public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ckermit] epel9: Add '-ansi -D_DEFAULT_SOURCE' to KFLAG variable to fix FTBFS (#2339971)
@ 2026-09-18 13:52 David Cantrell
0 siblings, 0 replies; only message in thread
From: David Cantrell @ 2026-09-18 13:52 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/ckermit
Branch : epel9
Commit : 2a4818dae7fdaa057fe668f2b3bef750093fdc92
Author : David Cantrell <dcantrell@burdell.org>
Date : 2025-01-22T14:25:26-05:00
Stats : +410640/-2 in 83 file(s)
URL : https://src.fedoraproject.org/rpms/ckermit/c/2a4818dae7fdaa057fe668f2b3bef750093fdc92?branch=epel9
Log:
Add '-ansi -D_DEFAULT_SOURCE' to KFLAG variable to fix FTBFS (#2339971)
Signed-off-by: David Cantrell <dcantrell@burdell.org>
---
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/COPYING.TXT b/ckermit-9.0.302-build/ckermit-9.0.302/COPYING.TXT
new file mode 100644
index 0000000..200f236
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/COPYING.TXT
@@ -0,0 +1,31 @@
+THE C-KERMIT 9.0 LICENSE
+
+Fri Jun 24 14:43:35 2011
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ + Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ + Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ + Neither the name of Columbia University nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/README.fedora b/ckermit-9.0.302-build/ckermit-9.0.302/README.fedora
new file mode 100644
index 0000000..bfa41ac
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/README.fedora
@@ -0,0 +1,22 @@
+If unprivileged users attempt to access a serial port, e.g.
+/dev/ttyS<n> or /dev/ttyUSB<n>, they will normally get an error
+message such as:
+
+ Sorry, write access to UUCP lockfile directory denied.
+
+This message is actually due to permissions on the device, not the
+lockfile directory.
+
+If it is desired to allow specific unprivileged users to use ckermit
+to access serial ports, add those users to the "dialout" group. One
+way to accomplish this is using a command line such as:
+
+ sudo usermod -a -G dialout <username>
+
+This will apply to future logins by that user.
+
+If you want to make the serial ports accessible to all users without
+adding them to the dialout group (not recommended), you can change the
+permissions of the serial device to 666, e.g.,
+
+ sudo chmod 666 /dev/ttyS<n>
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ck_crp.c b/ckermit-9.0.302-build/ckermit-9.0.302/ck_crp.c
new file mode 100644
index 0000000..593d0b4
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ck_crp.c
@@ -0,0 +1,5622 @@
+char *ckcrpv = "Encryption Engine, 9.0.117, 19 Mar 2010";
+/*
+ C K _ C R P . C - Cryptography for C-Kermit"
+
+ Copyright (C) 1998, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Author:
+ Jeffrey E Altman (jaltman@secure-endpoints.com)
+ Secure Endpoints Inc., New York City
+*/
+
+#define CK_CRP_C
+#ifdef CK_DES
+#ifdef CK_SSL
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+#endif /* CK_SSL */
+#endif /* CK_DES */
+
+#ifdef CRYPT_DLL
+#define CK_AUTHENTICATION
+#define CK_ENCRYPTION
+#define CK_DES
+#define CK_CAST
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+
+#define TELCMDS /* to define name array */
+#define TELOPTS /* to define name array */
+#define ENCRYPT_NAMES
+#endif /* CRYPT_DLL */
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcnet.h"
+
+#ifdef DEBUG
+#undef DEBUG
+#endif /* DEBUG */
+
+#ifdef CK_AUTHENTICATION
+#ifdef CK_ENCRYPTION
+#define ENCRYPTION
+#ifdef CK_DES
+#define DES_ENCRYPTION
+#endif /* CK_DES */
+#ifdef CK_CAST
+#define CAST_ENCRYPTION
+#endif /* CK_CAST */
+#ifdef COMMENT
+#define CAST_EXPORT_ENCRYPTION
+#endif /* COMMENT */
+#endif /* CK_ENCRYPTION */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_ENCRYPTION
+
+#include "ckucmd.h" /* For struct keytab definition */
+#include "ckuath.h"
+#include "ckuat2.h"
+#ifdef MIT_CURRENT
+#include <krb5.h>
+#endif /* MIT_CURRENT */
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef OS2
+#include <stdarg.h>
+#ifdef OS2ONLY
+#include <os2.h>
+#endif /* OS2ONLY */
+#include "ckosyn.h"
+#else /* OS2 */
+static char * tmpstring = NULL;
+#endif /* OS2 */
+
+#ifndef CAST_OR_EXPORT
+#ifdef CAST_ENCRYPTION
+#define CAST_OR_EXPORT
+#endif /* CAST_ENCRYPTION */
+#ifdef CAST_EXPORT_ENCRYPTION
+#define CAST_OR_EXPORT
+#endif /* CAST_EXPORT_ENCRYPTION */
+#endif /* CAST_OR_EXPORT */
+
+#ifdef MACOSX
+#undef LIBDES
+#endif /* MACOSX */
+
+#ifdef CRYPT_DLL
+int cmd_quoting = 0;
+
+#ifndef TELOPT_MACRO
+int
+telopt_index(opt) int opt; {
+ if ( opt >= 0 && opt <= TELOPT_SEND_URL )
+ return(opt);
+ else if ( opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT )
+ return(opt-89);
+ else
+ return(NTELOPTS);
+}
+
+int
+telopt_ok(opt) int opt; {
+ return((opt >= TELOPT_BINARY && opt <= TELOPT_SEND_URL) ||
+ (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT));
+}
+
+CHAR *
+telopt(opt) int opt; {
+ if ( telopt_ok(opt) )
+ return(telopts[telopt_index(opt)]);
+ else
+ return("UNKNOWN");
+}
+#endif /* TELOPT_MACRO */
+
+static int (*p_ttol)(char *,int)=NULL;
+static int (*p_dodebug)(int,char *,char *,CK_OFF_T)=NULL;
+static int (*p_dohexdump)(char *,char *,int)=NULL;
+static void (*p_tn_debug)(char *)=NULL;
+static int (*p_vscrnprintf)(char *, ...)=NULL;
+static void * p_k5_context=NULL;
+static unsigned long (*p_reqtelmutex)(unsigned long)=NULL;
+static unsigned long (*p_reltelmutex)(void)=NULL;
+
+unsigned long
+RequestTelnetMutex(unsigned long x)
+{
+ if ( p_reqtelmutex )
+ return p_reqtelmutex(x);
+ return 0;
+}
+
+unsigned long
+ReleaseTelnetMutex(void)
+{
+ if ( p_reltelmutex )
+ return p_reltelmutex();
+ return 0;
+}
+
+int
+ttol(char * s, int n)
+{
+ if ( p_ttol )
+ return(p_ttol(s,n));
+ else
+ return(-1);
+}
+
+int
+dodebug(int flag, char * s1, char * s2, CK_OFF_T n)
+{
+ if ( p_dodebug )
+ return(p_dodebug(flag,s1,s2,n));
+ else
+ return(-1);
+}
+
+int
+dohexdump( char * s1, char * s2, int n )
+{
+ if ( p_dohexdump )
+ p_dohexdump(s1,s2,n);
+ return(0);
+}
+
+void
+tn_debug( char * s )
+{
+ if ( p_tn_debug )
+ p_tn_debug(s);
+}
+
+static char myprtfstr[4096];
+int
+Vscrnprintf(const char * format, ...) {
+ int i, len, rc=0;
+ char *cp;
+ va_list ap;
+
+ va_start(ap, format);
+#ifdef NT
+ rc = _vsnprintf(myprtfstr, sizeof(myprtfstr)-1, format, ap);
+#else /* NT */
+ rc = vsprintf(myprtfstr, format, ap);
+#endif /* NT */
+ va_end(ap);
+
+ if ( p_vscrnprintf )
+ return(p_vscrnprintf(myprtfstr));
+ else
+ return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen)
+#else /* CK_ANSIC */
+tn_hex(buf, buflen, data, datalen)
+ CHAR * buf;
+ int buflen;
+ CHAR * data;
+ int datalen;
+#endif /* CK_ANSIC */
+{
+ int i = 0, j = 0, k = 0;
+ CHAR tmp[8];
+#ifdef COMMENT
+ int was_hex = 1;
+
+ for (k=0; k < datalen; k++) {
+ if (data[k] < 32 || data[k] >= 127) {
+ sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]);
+ was_hex = 1;
+ } else {
+ sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]);
+ was_hex = 0;
+ }
+ ckstrncat(buf,tmp,buflen);
+ }
+ if (!was_hex)
+ ckstrncat(buf,"\" ",buflen);
+#else /* COMMENT */
+ if (datalen <= 0 || data == NULL)
+ return(0);
+
+ for (i = 0; i < datalen; i++) {
+ ckstrncat(buf,"\r\n ",buflen);
+ for (j = 0 ; (j < 16); j++) {
+ if ((i + j) < datalen)
+ sprintf(tmp,
+ "%s%02x ",
+ (j == 8 ? "| " : ""),
+ (CHAR) data[i + j]
+ );
+ else
+ sprintf(tmp,
+ "%s ",
+ (j == 8 ? "| " : "")
+ );
+ ckstrncat(buf,tmp,buflen);
+ }
+ ckstrncat(buf," ",buflen);
+ for (k = 0; (k < 16) && ((i + k) < datalen); k++) {
+ sprintf(tmp,
+ "%s%c",
+ (k == 8 ? " " : ""),
+ isprint(data[i + k]) ? data[i + k] : '.'
+ );
+ ckstrncat(buf,tmp,buflen);
+ }
+ i += j - 1;
+ } /* end for */
+ ckstrncat(buf,"\r\n ",buflen);
+#endif /* COMMENT */
+ return(strlen(buf));
+}
+
+#ifdef COMMENT
+#define ttol dll_ttol
+#define dodebug dll_dodebug
+#define dohexdump dll_dohexdump
+#define tn_debug dll_tn_debug
+#define Vscrnprintf dll_vscrnprintf
+#endif /* COMMENT */
+
+char tn_msg[TN_MSG_LEN], hexbuf[TN_MSG_LEN]; /* from ckcnet.c */
+int deblog=1, debses=1, tn_deb=1;
+#else /* CRYPT_DLL */
+extern char tn_msg[], hexbuf[]; /* from ckcnet.c */
+extern int deblog, debses, tn_deb;
+#ifdef MIT_CURRENT
+extern krb5_context k5_context;
+#endif /* MIT_CURRENT */
+#endif /* CRYPT_DLL */
+
+#ifdef LIBDES
+#ifdef MACOSX
+#define des_new_random_key ck_des_new_random_key
+#define des_set_random_generator_seed ck_des_set_random_generator_seed
+#define des_key_sched ck_des_key_sched
+#define des_ecb_encrypt ck_des_ecb_encrypt
+#define des_string_to_key ck_des_string_to_key
+#define des_fixup_key_parity ck_des_fixup_key_parity
+#endif /* MACOSX */
+#ifndef UNIX
+#define des_new_random_key des_random_key
+#define des_set_random_generator_seed des_random_seed
+#endif /* UNIX */
+#define des_fixup_key_parity des_set_odd_parity
+#ifdef OPENSSL_097
+#define OPENSSL_ENABLE_OLD_DES_SUPPORT
+#include <openssl/des.h>
+#endif /* OPENSSL_097 */
+#else /* LIBDES */
+#ifdef UNIX
+#define des_set_random_generator_seed(x) des_init_random_number_generator(x)
+#endif /* UNIX */
+#ifdef OS2
+#define des_new_random_key ck_des_new_random_key
+#define des_set_random_generator_seed ck_des_set_random_generator_seed
+#define des_key_sched ck_des_key_sched
+#define des_ecb_encrypt ck_des_ecb_encrypt
+#define des_string_to_key ck_des_string_to_key
+#define des_fixup_key_parity ck_des_fixup_key_parity
+#endif /* OS2 */
+#endif /* LIBDES */
+
+#ifdef CK_DES
+/* This code comes from Eric Young's libdes package and is not part */
+/* of the standard MIT DES library that is part of Kerberos. However, */
+/* it is extremely useful. So we add it here. */
+
+
+/* Weak and semi week keys as take from
+ * %A D.W. Davies
+ * %A W.L. Price
+ * %T Security for Computer Networks
+ * %I John Wiley & Sons
+ * %D 1984
+ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
+ * (and actual cblock values).
+ */
+#define NUM_WEAK_KEY 16
+static Block weak_keys[NUM_WEAK_KEY]={
+ /* weak keys */
+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+ {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
+ {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
+ {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
+ /* semi-weak keys */
+ {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
+ {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
+ {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
+ {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
+ {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
+ {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
+ {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
+ {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
+ {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
+ {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+ {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};
+
+int
+ck_des_is_weak_key(key)
+Block key;
+{
+ int i;
+
+ for (i=0; i<NUM_WEAK_KEY; i++) {
+ /* Added == 0 to comparision, I obviously don't run
+ * this section very often :-(, thanks to
+ * engineering@MorningStar.Com for the fix
+ * eay 93/06/29
+ * Another problem, I was comparing only the first 4
+ * bytes, 97/03/18 */
+ if (memcmp(weak_keys[i],key,sizeof(Block)) == 0)
+ return(1);
+ }
+ return(0);
+}
+
+#ifdef UNIX
+#ifdef LIBDES
+#ifndef MACOSX
+/* These functions are not part of Eric Young's DES library */
+/* _unix_time_gmt_unixsec */
+/* _des_set_random_generator_seed */
+/* _des_fixup_key_parity (added in 0.9.5) */
+/* _des_new_random_key */
+#include <sys/time.h>
+
+unsigned long
+unix_time_gmt_unixsec (usecptr)
+ unsigned long *usecptr;
+{
+ struct timeval now;
+
+ (void) gettimeofday (&now, (struct timezone *)0);
+ if (usecptr)
+ *usecptr = now.tv_usec;
+ return now.tv_sec;
+}
+
+void
+des_set_random_generator_seed(Block B)
+{
+ des_random_seed(B);
+ return;
+}
+
+#ifdef COMMENT
+/* added to openssl in 0.9.5 */
+void
+des_fixup_key_parity(Block B)
+{
+ des_set_odd_parity(B);
+ return;
+}
+#endif /* COMMENT */
+int
+des_new_random_key(Block B)
+{
+ int rc=0;
+ /* WARNING:
+ This might need to have the "rc = " removed because this
+ is VOID in later, and maybe even all, versions.
+ */
+ rc = des_random_key(B);
+ return(rc);
+}
+
+#endif /* MACOSX */
+#endif /* LIBDES */
+#endif /* UNIX */
+#endif /* CK_DES */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)encrypt.c 8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+
+/*
+ * These function pointers point to the current routines
+ * for encrypting and decrypting data.
+ */
+/* NOTE: These next two might need to have the "static " removed */
+
+static VOID (*encrypt_output) P((unsigned char *, int));
+static int (*decrypt_input) P((int));
+
+#ifdef DEBUG
+static int encrypt_debug_mode = 1;
+static int encrypt_verbose = 1;
+#else
+static int encrypt_verbose = 1;
+static int encrypt_debug_mode = 0;
+#endif
+
+static char dbgbuf [16384];
+
+static int decrypt_mode = 0;
+static int encrypt_mode = 0;
+static int autoencrypt = 1;
+static int autodecrypt = 1;
+static int havesessionkey = 0;
+
+static kstream EncryptKSGlobalHack = NULL;
+static int EncryptType = ENCTYPE_ANY;
+
+#define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0)
+
+static long i_support_encrypt =
+ typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64);
+static long i_support_decrypt =
+ typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64);
+static long i_wont_support_encrypt = 0;
+static long i_wont_support_decrypt = 0;
+#define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt)
+#define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt)
+
+static long remote_supports_encrypt = 0;
+static long remote_supports_decrypt = 0;
+
+/* Make sure that this list is in order of algorithm strength */
+/* as it determines the search order for selecting specific */
+/* encryption choices. All CFB modes must come before OFB modes. */
+static Encryptions encryptions[] = {
+#ifdef DES_ENCRYPTION
+ { "DES3_CFB64",
+ ENCTYPE_DES3_CFB64,
+ des3_cfb64_encrypt,
+ des3_cfb64_decrypt,
+ des3_cfb64_init,
+ des3_cfb64_start,
+ des3_cfb64_is,
+ des3_cfb64_reply,
+ des3_cfb64_session,
+ des3_cfb64_keyid,
+ NULL },
+#endif /* DES_ENCRYPTION */
+#ifdef CAST_ENCRYPTION
+#ifndef CAST_EXPORT_ENCRYPTION
+ { "CAST128_CFB64", ENCTYPE_CAST128_CFB64,
+ cast_cfb64_encrypt,
+ cast_cfb64_decrypt,
+ cast_cfb64_init,
+ cast_cfb64_start,
+ cast_cfb64_is,
+ cast_cfb64_reply,
+ cast_cfb64_session,
+ cast_cfb64_keyid,
+ NULL },
+#endif
+#endif
+#ifdef DES_ENCRYPTION
+ { "DES_CFB64",
+ ENCTYPE_DES_CFB64,
+ cfb64_encrypt,
+ cfb64_decrypt,
+ cfb64_init,
+ cfb64_start,
+ cfb64_is,
+ cfb64_reply,
+ cfb64_session,
+ cfb64_keyid,
+ NULL },
+#endif /* DES_ENCRYPTION */
+#if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION)
+ { "CAST5_40_CFB64", ENCTYPE_CAST5_40_CFB64,
+ castexp_cfb64_encrypt,
+ castexp_cfb64_decrypt,
+ castexp_cfb64_init,
+ castexp_cfb64_start,
+ castexp_cfb64_is,
+ castexp_cfb64_reply,
+ castexp_cfb64_session,
+ castexp_cfb64_keyid,
+ NULL },
+#endif /* CAST_ENCRYPTION */
+#ifdef DES_ENCRYPTION
+ { "DES3_OFB64",
+ ENCTYPE_DES3_OFB64,
+ des3_ofb64_encrypt,
+ des3_ofb64_decrypt,
+ des3_ofb64_init,
+ des3_ofb64_start,
+ des3_ofb64_is,
+ des3_ofb64_reply,
+ des3_ofb64_session,
+ des3_ofb64_keyid,
+ NULL },
+#endif /* DES_ENCRYPTION */
+#ifdef CAST_ENCRYPTION
+#ifndef CAST_EXPORT_ENCRYPTION
+ { "CAST128_OFB64", ENCTYPE_CAST128_OFB64,
+ cast_ofb64_encrypt,
+ cast_ofb64_decrypt,
+ cast_ofb64_init,
+ cast_ofb64_start,
+ cast_ofb64_is,
+ cast_ofb64_reply,
+ cast_ofb64_session,
+ cast_ofb64_keyid,
+ NULL },
+#endif
+#endif
+#ifdef DES_ENCRYPTION
+ { "DES_OFB64",
+ ENCTYPE_DES_OFB64,
+ ofb64_encrypt,
+ ofb64_decrypt,
+ ofb64_init,
+ ofb64_start,
+ ofb64_is,
+ ofb64_reply,
+ ofb64_session,
+ ofb64_keyid,
+ NULL },
+#endif /* DES_ENCRYPTION */
+#if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION)
+ { "CAST5_40_OFB64", ENCTYPE_CAST5_40_OFB64,
+ castexp_ofb64_encrypt,
+ castexp_ofb64_decrypt,
+ castexp_ofb64_init,
+ castexp_ofb64_start,
+ castexp_ofb64_is,
+ castexp_ofb64_reply,
+ castexp_ofb64_session,
+ castexp_ofb64_keyid,
+ NULL },
+#endif /* CAST_ENCRYPTION */
+ { 0,0,0,0,0,0,0,0,0,0,0 }
+};
+
+int
+get_crypt_table( struct keytab ** pTable, int * pN )
+{
+ int i=0,n=0;
+
+ if ( *pTable )
+ {
+ for ( i=0 ; i < *pN ; i++ )
+ free( (*pTable)[i].kwd ) ;
+ free ( *pTable ) ;
+ }
+ *pTable = NULL;
+ *pN = 0;
+
+ /* How many encryption types do we have? */
+ while ( encryptions[n].name )
+ n++;
+
+ if ( n )
+ {
+ *pTable = malloc( sizeof(struct keytab) * (n+2) ) ;
+ if ( !(*pTable) )
+ return(0);
+
+#ifdef OS2
+ (*pTable)[0].kwd =strdup("automatic");
+#else /* OS2 */
+ makestr(&tmpstring,"automatic");
+ (*pTable)[0].kwd = tmpstring;
+ tmpstring = NULL;
+#endif /* OS2 */
+ (*pTable)[0].kwval = ENCTYPE_ANY;
+ (*pTable)[0].flgs = 0;
+#ifdef OS2
+ (*pTable)[1].kwd =strdup("none");
+#else /* OS2 */
+ makestr(&tmpstring,"none");
+ (*pTable)[1].kwd = tmpstring;
+ tmpstring = NULL;
+#endif /* OS2 */
+ (*pTable)[1].kwval = 999;
+ (*pTable)[1].flgs = 0;
+ (*pN) = 2;
+
+ for ( i=0 ; i < n ; i++ ) {
+ char * newstr = NULL, * p;
+ int newval = encryptions[i].type;
+ int j = 0, len = 0;
+
+#ifdef OS2
+ newstr = strdup(encryptions[i].name);
+ strlwr(newstr);
+#else /* OS2 */
+ makestr(&tmpstring,encryptions[i].name);
+ newstr = tmpstring;
+ tmpstring = NULL;
+ for (p = newstr; *p; p++) if (isupper(*p)) *p = tolower(*p);
+#endif /* OS2 */
+
+ for (j = 0; j < (*pN); j++) {
+ int tempval = 0;
+ char * tempstr = NULL;
+
+ if ( strcmp( (*pTable)[j].kwd, newstr ) > 0 )
+ {
+ tempval = (*pTable)[j].kwval;
+ tempstr = (*pTable)[j].kwd;
+ (*pTable)[j].kwd = newstr ;
+ (*pTable)[j].kwval = newval;
+ newval = tempval;
+ newstr = tempstr;
+ (*pTable)[j].flgs = 0;
+ }
+ }
+ (*pTable)[*pN].kwd = newstr ;
+ (*pTable)[*pN].kwval = newval;
+ (*pTable)[*pN].flgs = 0 ;
+ (*pN)++ ;
+ }
+ } else {
+ *pTable = malloc( sizeof(struct keytab) * 2 ) ;
+ if ( !(*pTable) )
+ return(0);
+
+#ifdef OS2
+ (*pTable)[0].kwd =strdup("automatic");
+#else /* OS2 */
+ makestr(&tmpstring,"automatic");
+ (*pTable)[0].kwd = tmpstring;
+ tmpstring = NULL;
+#endif /* OS2 */
+ (*pTable)[0].kwval = ENCTYPE_ANY;
+ (*pTable)[0].flgs = 0;
+#ifdef OS2
+ (*pTable)[1].kwd =strdup("none");
+#else /* OS2 */
+ makestr(&tmpstring,"none");
+ (*pTable)[1].kwd = tmpstring;
+ tmpstring = NULL;
+#endif /* OS2 */
+ (*pTable)[1].kwval = 999;
+ (*pTable)[1].flgs = 0;
+ (*pN) = 2;
+ }
+ return(*pN);
+}
+
+static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPTION,
+ ENCRYPT_SUPPORT };
+static unsigned char str_suplen = 0;
+static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPTION };
+static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPTION, 0, IAC, SE };
+
+_PROTOTYP(int encrypt_request_end, (VOID));
+_PROTOTYP(int encrypt_request_start, (VOID));
+_PROTOTYP(int encrypt_enc_keyid, (unsigned char *, int));
+_PROTOTYP(int encrypt_dec_keyid, (unsigned char *, int));
+_PROTOTYP(int encrypt_support, (unsigned char *, int));
+_PROTOTYP(int encrypt_start, (unsigned char *, int));
+_PROTOTYP(int encrypt_end, (VOID));
+
+_PROTOTYP(int encrypt_ks_stream,(struct kstream_data_block *, /* output */
+ struct kstream_data_block *)); /* input */
+
+_PROTOTYP(int decrypt_ks_stream,(struct kstream_data_block *, /* output */
+ struct kstream_data_block *)); /* input */
+
+int
+#ifdef CK_ANSIC
+encrypt_ks_stream(struct kstream_data_block *i,
+ struct kstream_data_block *o)
+#else
+encrypt_ks_stream(i,o)
+ struct kstream_data_block *i; struct kstream_data_block *o;
+#endif
+{
+ /*
+ * this is really quite bogus, since it does an in-place encryption...
+ */
+ if (encrypt_output) {
+ encrypt_output(i->ptr, i->length);
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+#ifdef CK_ANSIC
+decrypt_ks_stream(struct kstream_data_block *i,
+ struct kstream_data_block *o)
+#else
+decrypt_ks_stream(i,o)
+ struct kstream_data_block *i; struct kstream_data_block *o;
+#endif
+{
+ unsigned int len;
+ /*
+ * this is really quite bogus, since it does an in-place decryption...
+ */
+ if (decrypt_input) {
+ for (len = 0 ; len < i->length ; len++)
+ ((unsigned char *)i->ptr)[len]
+ = decrypt_input(((unsigned char *)i->ptr)[len]);
+ return 1;
+ }
+ return 0;
+}
+
+int
+#ifdef CK_ANSIC
+decrypt_ks_hack(unsigned char *buf, int cnt)
+#else
+decrypt_ks_hack(buf,cnt) unsigned char *buf; int cnt;
+#endif
+{
+ int len;
+ /*
+ * this is really quite bogus, since it does an in-place decryption...
+ */
+ for (len = 0 ; len < cnt ; len++)
+ buf[len] = decrypt_input(buf[len]);
+
+#ifdef DEBUG
+ ckhexdump("decrypt ks hack", buf, cnt);
+#endif
+ return 1;
+}
+
+
+/*
+ * parsedat[0] == the suboption we might be negotiating,
+ */
+int
+#ifdef CK_ANSIC
+encrypt_parse(unsigned char *parsedat, int end_sub)
+#else
+encrypt_parse(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+ int rc = 0;
+
+ switch(parsedat[1]) {
+ case ENCRYPT_START:
+ rc = encrypt_start(parsedat + 2, end_sub - 2);
+ break;
+ case ENCRYPT_END:
+ rc = encrypt_end();
+ break;
+ case ENCRYPT_SUPPORT:
+ rc = encrypt_support(parsedat + 2, end_sub - 2);
+ break;
+ case ENCRYPT_REQSTART:
+ rc = encrypt_request_start();
+ break;
+ case ENCRYPT_REQEND:
+ /*
+ * We can always send an REQEND so that we cannot
+ * get stuck encrypting. We should only get this
+ * if we have been able to get in the correct mode
+ * anyhow.
+ */
+ rc = encrypt_request_end();
+ break;
+ case ENCRYPT_IS:
+ rc = encrypt_is(parsedat + 2, end_sub - 2);
+ break;
+ case ENCRYPT_REPLY:
+ rc = encrypt_reply(parsedat + 2, end_sub - 2);
+ break;
+ case ENCRYPT_ENC_KEYID:
+ rc = encrypt_enc_keyid(parsedat + 2, end_sub - 2);
+ break;
+ case ENCRYPT_DEC_KEYID:
+ rc = encrypt_dec_keyid(parsedat + 2, end_sub - 2);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+ return(rc);
+}
+
+/* XXX */
+Encryptions *
+#ifdef CK_ANSIC
+findencryption(int type)
+#else
+findencryption(type) int type;
+#endif
+{
+ Encryptions *ep = encryptions;
+
+ if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type)))
+ return(0);
+ while (ep->type && ep->type != type)
+ ++ep;
+ return(ep->type ? ep : 0);
+}
+
+Encryptions *
+#ifdef CK_ANSIC
+finddecryption(int type)
+#else
+finddecryption(type) int type;
+#endif
+{
+ Encryptions *ep = encryptions;
+
+ if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type)))
+ return(0);
+ while (ep->type && ep->type != type)
+ ++ep;
+ return(ep->type ? ep : 0);
+}
+
+#define MAXKEYLEN 64
+
+static struct key_info {
+ unsigned char keyid[MAXKEYLEN];
+ int keylen;
+ int dir;
+ int *modep;
+ Encryptions *(*getcrypt)();
+} ki[2] = {
+ { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption },
+ { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption },
+};
+
+VOID
+#ifdef CK_ANSIC
+encrypt_init(kstream iks, int type)
+#else
+encrypt_init(iks, type) kstream iks; int type;
+#endif
+{
+ Encryptions *ep = encryptions;
+
+ i_support_encrypt = i_support_decrypt = 0;
+ remote_supports_encrypt = remote_supports_decrypt = 0;
+ i_wont_support_encrypt = i_wont_support_decrypt = 0;
+ encrypt_mode = 0;
+ decrypt_mode = 0;
+ encrypt_output = NULL;
+ decrypt_input = NULL;
+ ki[0].keylen = 0;
+ memset(ki[0].keyid,0,MAXKEYLEN);
+ ki[1].keylen = 0;
+ memset(ki[1].keyid,0,MAXKEYLEN);
+ havesessionkey = 0;
+ autoencrypt = 1;
+ autodecrypt = 1;
+
+ EncryptKSGlobalHack = iks;
+ EncryptType = type;
+
+ str_send[0] = IAC;
+ str_send[1] = SB;
+ str_send[2] = TELOPT_ENCRYPTION;
+ str_send[3] = ENCRYPT_SUPPORT;
+ str_suplen = 4;
+
+ while (ep->type) {
+ if ( EncryptType == ENCTYPE_ANY ||
+ EncryptType == ep->type ) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>I will support %s\n",
+ ENCTYPE_NAME(ep->type)); /* safe */
+ debug(F110,"encrypt_init",dbgbuf,0);
+ }
+#endif
+ i_support_encrypt |= typemask(ep->type);
+ i_support_decrypt |= typemask(ep->type);
+ if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
+ if ((str_send[str_suplen++] = ep->type) == IAC)
+ str_send[str_suplen++] = IAC;
+ }
+ if (ep->init)
+ (*ep->init)(0);
+ ++ep;
+ }
+ str_send[str_suplen++] = IAC;
+ str_send[str_suplen++] = SE;
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_support(VOID)
+#else
+encrypt_send_support()
+#endif
+{
+ Encryptions *ep = encryptions;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return;
+#endif /* CK_SSL */
+
+ str_send[0] = IAC;
+ str_send[1] = SB;
+ str_send[2] = TELOPT_ENCRYPTION;
+ str_send[3] = ENCRYPT_SUPPORT;
+ str_suplen = 4;
+
+ while (ep->type) {
+ if ( EncryptType == ENCTYPE_ANY ||
+ EncryptType == ep->type ) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>I will support %s\n",
+ ENCTYPE_NAME(ep->type)); /* safe */
+ debug(F110,"encrypt_send_support",dbgbuf,0);
+ }
+#endif
+ if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
+ if ((str_send[str_suplen++] = ep->type) == IAC)
+ str_send[str_suplen++] = IAC;
+ }
+ ++ep;
+ }
+ str_send[str_suplen++] = IAC;
+ str_send[str_suplen++] = SE;
+
+ /*
+ * If the user has requested that decryption start
+ * immediatly, then send a "REQUEST START" before
+ * we negotiate the type.
+ */
+ if (autodecrypt)
+ encrypt_send_request_start();
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,"TELNET SENT SB %s SUPPORT ",
+ TELOPT(TELOPT_ENCRYPTION)); /* safe */
+ for ( i=4;i<str_suplen-2;i++ ) {
+ if ( str_send[i] == IAC ) {
+ ckstrncat(tn_msg,"IAC ",TN_MSG_LEN);
+ i++;
+ }
+ ckstrncat(tn_msg,ENCTYPE_NAME(str_send[i]),TN_MSG_LEN);
+ ckstrncat(tn_msg," ",TN_MSG_LEN);
+ }
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(str_send, str_suplen);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ str_suplen = 0;
+}
+
+/*
+ * Called when ENCRYPT SUPPORT is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_support(unsigned char *_typelist, int _cnt)
+#else
+encrypt_support(_typelist, _cnt) unsigned char * _typelist; int _cnt;
+#endif
+{
+ register int type, use_type = 0;
+ unsigned char * typelist = _typelist;
+ int cnt = _cnt;
+ Encryptions *ep;
+
+ debug(F111,"encrypt_support","cnt",cnt);
+
+ /*
+ * Forget anything the other side has previously told us.
+ */
+ remote_supports_decrypt = 0;
+
+ while (cnt-- > 0) {
+ debug(F101,"XXX cnt","",cnt);
+ type = *typelist++;
+ debug(F101,"XXX type","",type);
+ debug(F101,"XXX ENCTYPE_ANY","",ENCTYPE_ANY);
+ if ( EncryptType == ENCTYPE_ANY ||
+ EncryptType == type ) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Remote supports %s (%d)\n",
+ ENCTYPE_NAME(type), type); /* safe */
+ debug(F110,"encrypt_support",dbgbuf,0);
+ }
+#endif
+ if ((type < ENCTYPE_CNT) &&
+ (I_SUPPORT_ENCRYPT & typemask(type))) {
+ remote_supports_decrypt |= typemask(type);
+ if (use_type == 0)
+ use_type = type;
+ }
+ }
+ }
+ debug(F101,"XXX use_type","",use_type);
+ if (use_type) {
+ ep = findencryption(use_type);
+ if (!ep) {
+ debug(F111,"encrypt_support","findencryption == NULL",use_type);
+ return(-1);
+ }
+ debug(F100,"XXX ep not NULL","",0);
+ type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0;
+ debug(F101,"XXX new type","",type);
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>(*ep->start)() %s returned %d (%s)\n",
+ ENCTYPE_NAME(use_type), type,
+ ENCRYPT_NAME(type)); /* safe */
+ debug(F110,"encrypt_support",dbgbuf,0);
+ }
+#endif
+ if (type < 0) {
+ debug(F111,"encrypt_support","type < 0",type);
+ return(-1);
+ }
+ encrypt_mode = use_type;
+ if (type == 0)
+ encrypt_start_output(use_type);
+ debug(F111,"encrypt_support","success",type);
+ return(0);
+ }
+ debug(F111,"encrypt_support","failed",use_type);
+ return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_is(unsigned char *data, int cnt)
+#else
+encrypt_is(data, cnt) unsigned char *data; int cnt;
+#endif /* CK_ANSIC */
+{
+ Encryptions *ep;
+ register int type, ret;
+
+ if (--cnt < 0)
+ return(-1);
+ type = *data++;
+ if (type < ENCTYPE_CNT)
+ remote_supports_encrypt |= typemask(type);
+ if (!(ep = finddecryption(type))) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>encrypt_is: "
+ "Can't find type %s (%d) for initial negotiation\n",
+ ENCTYPE_NAME_OK(type)
+ ? ENCTYPE_NAME(type) : "(unknown)",
+ type); /* safe */
+ debug(F110,"encrypt_is",dbgbuf,0);
+ }
+#endif
+ return(-1);
+ }
+ if (!ep->is) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>encrypt_is: "
+ "No initial negotiation needed for type %s (%d)\n",
+ ENCTYPE_NAME_OK(type)
+ ? ENCTYPE_NAME(type) : "(unknown)",
+ type); /* safe */
+ debug(F110,"encrypt_is",dbgbuf,0);
+ }
+#endif
+ ret = 0;
+ } else {
+ ret = (*ep->is)(data, cnt);
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, "encrypt_is: "
+ "(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt,
+ (ret < 0) ? "FAIL " :
+ (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */
+ debug(F110,"encrypt_is",dbgbuf,0);
+ }
+#endif
+ }
+ if (ret < 0) {
+ autodecrypt = 0;
+ return(-1);
+ } else {
+ decrypt_mode = type;
+ if (ret == 0 && autodecrypt) {
+ encrypt_send_request_start();
+ }
+ }
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_reply(unsigned char *data, int cnt)
+#else
+encrypt_reply(data, cnt) unsigned char *data; int cnt;
+#endif
+{
+ Encryptions *ep;
+ register int ret, type;
+
+ if (--cnt < 0)
+ return(-1);
+ type = *data++;
+ if (!(ep = findencryption(type))) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf,
+ ">>>Can't find type %s (%d) for initial negotiation\n",
+ ENCTYPE_NAME_OK(type)
+ ? ENCTYPE_NAME(type) : "(unknown)",
+ type); /* safe */
+ debug(F110,"encrypt_reply",dbgbuf,0);
+ }
+#endif
+ return(-1);
+ }
+ if (!ep->reply) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>No initial negotiation needed for type %s (%d)\n",
+ ENCTYPE_NAME_OK(type)
+ ? ENCTYPE_NAME(type) : "(unknown)",
+ type); /* safe */
+ debug(F110,"encrypt_reply",dbgbuf,0);
+ }
+#endif
+ ret = 0;
+ } else {
+ ret = (*ep->reply)(data, cnt);
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, "(*ep->reply)(%x, %d) returned %s(%d)\n",
+ data, cnt,
+ (ret < 0) ? "FAIL " :
+ (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */
+ debug(F110,"encrypt_reply",dbgbuf,0);
+ }
+#endif
+ }
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>encrypt_reply returned %d\n", ret); /* safe */
+ debug(F110,"encrypt_reply",dbgbuf,0);
+ }
+#endif
+ if (ret < 0) {
+ autoencrypt = 0;
+ return(-1);
+ } else {
+ encrypt_mode = type;
+ if (ret == 0 && autoencrypt)
+ encrypt_start_output(type);
+ }
+ return(0);
+}
+
+/*
+ * Called when a ENCRYPT START command is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_start(unsigned char *data, int cnt)
+#else
+encrypt_start(data, cnt) unsigned char *data; int cnt;
+#endif
+{
+ Encryptions *ep;
+
+ if (!decrypt_mode) {
+ /*
+ * Something is wrong. We should not get a START
+ * command without having already picked our
+ * decryption scheme. Send a REQUEST-END to
+ * attempt to clear the channel...
+ */
+ encrypt_send_request_end();
+ printf("Authentication error!\n%s\n",
+ "Warning, Cannot decrypt input stream!!!");
+ return(-1);
+ }
+
+ if (ep = finddecryption(decrypt_mode)) {
+ if ( decrypt_input != ep->input ) {
+ decrypt_input = ep->input;
+ EncryptKSGlobalHack->decrypt = decrypt_ks_stream;
+ EncryptKSGlobalHack->decrypt_type = ep->type;
+
+ if (encrypt_verbose) {
+ sprintf(dbgbuf, "Input is now decrypted with type %s",
+ ENCTYPE_NAME(decrypt_mode)); /* safe */
+ debug(F110,"encrypt_start",dbgbuf,0);
+ printf("%s\n",dbgbuf);
+ }
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Start to decrypt input with type %s",
+ ENCTYPE_NAME(decrypt_mode)); /* safe */
+ debug(F110,"ck_crp",dbgbuf,0);
+ }
+#endif
+ }
+ } else {
+ char buf[1024];
+ sprintf(buf, "Warning, Cannot decrypt type %s (%d)!!!",
+ ENCTYPE_NAME_OK(decrypt_mode)
+ ? ENCTYPE_NAME(decrypt_mode) : "(unknown)",
+ decrypt_mode); /* safe */
+ printf("Authentication error!\n%s\n",buf);
+ encrypt_send_request_end();
+ return(-1);
+ }
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_dont_support(int type)
+#else
+encrypt_dont_support(type) int type;
+#endif
+{
+ i_wont_support_encrypt |= typemask(type);
+ i_wont_support_decrypt |= typemask(type);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_session_key(Session_Key *key, int server)
+#else
+encrypt_session_key(key, server) Session_Key *key; int server;
+#endif
+{
+ Encryptions *ep = encryptions;
+
+ if (havesessionkey)
+ return(0);
+
+ havesessionkey = 1;
+
+ while (ep->type) {
+ debug(F111,"encrypt_session_key",ep->name,ep->type);
+ if (ep->session) {
+ if ((*ep->session)(key, server) < 0) {
+ i_wont_support_encrypt |= typemask(ep->type);
+ i_wont_support_decrypt |= typemask(ep->type);
+ }
+ }
+ ++ep;
+ }
+ debug(F111,"encrypt_session_key (done)",ep->name,ep->type);
+ return(0);
+}
+
+/*
+ * Called when ENCRYPT END is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_end(VOID)
+#else
+encrypt_end()
+#endif
+{
+ decrypt_input = NULL;
+ EncryptKSGlobalHack->decrypt = NULL;
+ EncryptKSGlobalHack->decrypt_type = ENCTYPE_ANY;
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Input is back to clear text"); /* safe */
+ debug(F110,"encrypt_end",dbgbuf,0);
+ }
+#endif
+ if (encrypt_verbose) {
+ sprintf(dbgbuf, "Input is now clear text"); /* safe */
+ debug(F110,"encrypt_end",dbgbuf,0);
+ printf("%s\n",dbgbuf);
+ }
+ return(0);
+}
+
+/*
+ * Called when ENCRYPT REQUEST-END is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_request_end(VOID)
+#else
+encrypt_request_end()
+#endif
+{
+ encrypt_send_end();
+ return(0);
+}
+
+/*
+ * Called when ENCRYPT REQUEST-START is received. If we receive
+ * this before a type is picked, then that indicates that the
+ * other side wants us to start encrypting data as soon as we
+ * can.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_request_start(VOID)
+#else
+encrypt_request_start()
+#endif
+{
+ if (encrypt_mode != 0)
+ encrypt_start_output(encrypt_mode);
+ return(0);
+}
+
+static unsigned char str_keyid[(MAXKEYLEN*2)+5] = {
+ IAC, SB, TELOPT_ENCRYPTION
+};
+_PROTOTYP(int encrypt_keyid,(struct key_info *,unsigned char *,int));
+
+int
+#ifdef CK_ANSIC
+encrypt_enc_keyid(unsigned char *keyid, int len)
+#else
+encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len;
+#endif
+{
+ return(encrypt_keyid(&ki[1], keyid, len));
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_dec_keyid(unsigned char *keyid, int len)
+#else
+encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len;
+#endif /* CK_ANSIC */
+{
+ return(encrypt_keyid(&ki[0], keyid, len));
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len)
+#else
+encrypt_keyid(kp, keyid, len)
+ struct key_info *kp; unsigned char *keyid; int len;
+#endif
+{
+ Encryptions *ep;
+ int dir = kp->dir;
+ register int ret = 0;
+
+ if (!(ep = (*kp->getcrypt)(*kp->modep))) {
+ if (len == 0)
+ return(-1);
+ kp->keylen = 0;
+ } else if (len == 0 || len > MAXKEYLEN) {
+ /*
+ * Empty option or Key too long, indicates a failure.
+ */
+ if (kp->keylen == 0)
+ return(-1);
+ kp->keylen = 0;
+ if (ep->keyid)
+ (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
+
+ } else if ((len != kp->keylen) || (memcmp(keyid, kp->keyid, len) != 0)) {
+ /*
+ * Length or contents are different
+ */
+ kp->keylen = len;
+ memcpy(kp->keyid, keyid, len); /* length < MAXKEYLEN */
+ if (ep->keyid)
+ (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
+ } else {
+ if (ep->keyid)
+ ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen);
+ if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt)
+ encrypt_start_output(*kp->modep);
+ return(0);
+ }
+
+ encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_send_keyid(int dir, unsigned char *keyid, int keylen, int saveit)
+#else
+encrypt_send_keyid(dir, keyid, keylen, saveit)
+ int dir; unsigned char *keyid; int keylen; int saveit;
+#endif
+{
+ unsigned char *strp;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return(0);
+#endif /* CK_SSL */
+
+ str_keyid[3] = (dir == DIR_ENCRYPT)
+ ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID;
+ if (saveit && keylen <= MAXKEYLEN) {
+ struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1];
+ memcpy(kp->keyid, keyid, keylen);
+ kp->keylen = keylen;
+ }
+
+ for (strp = &str_keyid[4]; keylen > 0; --keylen) {
+ if ((*strp++ = *keyid++) == IAC)
+ *strp++ = IAC;
+ }
+ *strp++ = IAC;
+ *strp++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,"TELNET SENT SB %s %s ",
+ TELOPT(TELOPT_ENCRYPTION),
+ (dir == DIR_ENCRYPT) ? "ENC-KEYID" : "DEC-KEYID"); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_keyid[4],strp-str_keyid-2-4);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(str_keyid, strp - str_keyid);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ return(0);
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_auto(int on)
+#else
+encrypt_auto(on) int on;
+#endif
+{
+ if (on < 0)
+ autoencrypt ^= 1;
+ else
+ autoencrypt = on ? 1 : 0;
+}
+
+VOID
+#ifdef CK_ANSIC
+decrypt_auto(int on)
+#else
+decrypt_auto(on) int on;
+#endif
+{
+ if (on < 0)
+ autodecrypt ^= 1;
+ else
+ autodecrypt = on ? 1 : 0;
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_start_output(int type)
+#else
+encrypt_start_output(type) int type;
+#endif
+{
+ Encryptions *ep;
+ register unsigned char *p;
+ register int i;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return;
+#endif /* CK_SSL */
+
+ if (!(ep = findencryption(type))) {
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Can't encrypt with type %s (%d)\n",
+ ENCTYPE_NAME_OK(type)
+ ? ENCTYPE_NAME(type) : "(unknown)",
+ type); /* safe */
+ debug(F110,"encrypt_start_output",dbgbuf,0);
+ }
+#endif
+ return;
+ }
+ if (ep->start) {
+ i = (*ep->start)(DIR_ENCRYPT, 0);
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Encrypt start: %s (%d) %s\n",
+ (i < 0) ? "failed" :
+ "initial negotiation in progress",
+ i, ENCTYPE_NAME(type)); /* safe */
+ debug(F110,"encrypt_start_output",dbgbuf,0);
+ }
+#endif
+ if (i)
+ return;
+ }
+
+ if ( encrypt_output != ep->output ) {
+ p = str_start;
+ *p++ = IAC;
+ *p++ = SB;
+ *p++ = TELOPT_ENCRYPTION;
+ *p++ = ENCRYPT_START;
+ for (i = 0; i < ki[0].keylen; ++i) {
+ if (( *p++ = ki[0].keyid[i]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,"TELNET SENT SB %s START ",
+ TELOPT(TELOPT_ENCRYPTION)); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(str_start, p - str_start);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ /*
+ * If we are already encrypting in some mode, then
+ * encrypt the ring (which includes our request) in
+ * the old mode, mark it all as "clear text" and then
+ * switch to the new mode.
+ */
+ encrypt_output = ep->output;
+ EncryptKSGlobalHack->encrypt = encrypt_ks_stream;
+ EncryptKSGlobalHack->encrypt_type = type;
+ encrypt_mode = type;
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Started to encrypt output with type %s",
+ ENCTYPE_NAME(type)); /* safe */
+ debug(F110,"encrypt_start_output",dbgbuf,0);
+ }
+#endif
+ if (encrypt_verbose) {
+ sprintf(dbgbuf, "Output is now encrypted with type %s",
+ ENCTYPE_NAME(type)); /* safe */
+ debug(F110,"encrypt_start_output",dbgbuf,0);
+ printf("%s\n",dbgbuf);
+ }
+ }
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_end(VOID)
+#else
+encrypt_send_end()
+#endif
+{
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return;
+#endif /* CK_SSL */
+
+ if (!encrypt_output)
+ return;
+
+ str_end[0] = IAC;
+ str_end[1] = SB;
+ str_end[2] = TELOPT_ENCRYPTION;
+ str_end[3] = ENCRYPT_END;
+ str_end[4] = IAC;
+ str_end[5] = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,"TELNET SENT SB %s END IAC SE",
+ TELOPT(TELOPT_ENCRYPTION)); /* safe */
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(str_end, sizeof(str_end));
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ encrypt_output = 0;
+ EncryptKSGlobalHack->encrypt = NULL;
+ EncryptKSGlobalHack->encrypt_type = ENCTYPE_ANY;
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Output is back to clear text"); /* safe */
+ debug(F110,"encrypt_send_end",dbgbuf,0);
+ }
+#endif
+ if (encrypt_verbose) {
+ sprintf(dbgbuf, "Output is now clear text"); /* safe */
+ debug(F110,"encrypt_send_end",dbgbuf,0);
+ printf("%s\n",dbgbuf);
+ }
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_request_start(VOID)
+#else
+encrypt_send_request_start()
+#endif
+{
+ register unsigned char *p;
+ register int i;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return;
+#endif /* CK_SSL */
+
+ p = str_start;
+ *p++ = IAC;
+ *p++ = SB;
+ *p++ = TELOPT_ENCRYPTION;
+ *p++ = ENCRYPT_REQSTART;
+ for (i = 0; i < ki[1].keylen; ++i) {
+ if (( *p++ = ki[1].keyid[i]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,"TELNET SENT SB %s REQUEST-START ",
+ TELOPT(TELOPT_ENCRYPTION)); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(str_start, p - str_start);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Request input to be encrypted\n"); /* safe */
+ debug(F110,"encrypt_send_request_start",dbgbuf,0);
+ }
+}
+
+VOID
+#ifdef CK_ANSIC
+encrypt_send_request_end(VOID)
+#else
+encrypt_send_request_end()
+#endif
+{
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return;
+#endif /* CK_SSL */
+
+ str_end[0] = IAC;
+ str_end[1] = SB;
+ str_end[2] = TELOPT_ENCRYPTION;
+ str_end[3] = ENCRYPT_REQEND;
+ str_end[4] = IAC;
+ str_end[5] = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,"TELNET SENT SB %s REQEND IAC SE",
+ TELOPT(TELOPT_ENCRYPTION)); /* safe */
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(str_end, sizeof(str_end));
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ if (encrypt_debug_mode) {
+ sprintf(dbgbuf, ">>>Request input to be clear text\n"); /* safe */
+ debug(F110,"encrypt_send_request_end",dbgbuf,0);
+ }
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_is_encrypting(VOID)
+#else
+encrypt_is_encrypting()
+#endif
+{
+ if (encrypt_output)
+ return 1;
+ return 0;
+}
+
+int
+#ifdef CK_ANSIC
+encrypt_is_decrypting(VOID)
+#else
+encrypt_is_decrypting()
+#endif
+{
+ if (decrypt_input)
+ return 1;
+ return 0;
+}
+
+#ifdef DEBUG
+void
+encrypt_debug(mode)
+ int mode;
+{
+ encrypt_debug_mode = mode;
+}
+#endif
+
+#ifdef CK_DES
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)enc_des.c 8.1 (Berkeley) 6/4/93 */
+
+#define CFB 0
+#define OFB 1
+
+#define NO_SEND_IV 1
+#define NO_RECV_IV 2
+#define NO_KEYID 4
+#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
+#define SUCCESS 0
+#define xFAILED -1
+
+Schedule test_sched;
+
+struct des_stinfo {
+ Block str_output;
+ Block str_feed;
+ Block str_iv;
+ Block str_ikey;
+#ifdef MIT_CURRENT
+ unsigned char str_keybytes[8];
+ krb5_keyblock str_key;
+#else /* MIT_CURRENT */
+ Schedule str_sched;
+ int str_index;
+#endif /* MIT_CURRENT */
+ int str_flagshift;
+};
+
+struct des_fb {
+#ifndef MIT_CURRENT
+ Block krbdes_key;
+ Schedule krbdes_sched;
+#endif /* MIT_CURRENT */
+ Block temp_feed;
+ unsigned char fb_feed[64];
+ int need_start;
+ int state[2];
+ int keyid[2];
+ int once;
+#ifdef MIT_CURRENT
+ int validkey;
+#endif /* MIT_CURRENT */
+ struct des_stinfo streams[2];
+};
+static struct des_fb des_fb[2];
+
+struct des3_stinfo {
+ Block str_output;
+ Block str_feed;
+ Block str_iv;
+ Block str_ikey[3];
+ Schedule str_sched[3];
+ int str_index;
+ int str_flagshift;
+};
+
+struct des3_fb {
+#ifndef MIT_CURRENT
+ Block krbdes_key[3];
+ Schedule krbdes_sched[3];
+#endif /* MIT_CURRENT */
+ Block temp_feed;
+ unsigned char fb_feed[64];
+ int need_start;
+ int state[2];
+ int keyid[2];
+ int once;
+#ifdef MIT_CURRENT
+ int validkey;
+#endif /* MIT_CURRENT */
+ struct des3_stinfo streams[2];
+};
+static struct des3_fb des3_fb[2];
+
+struct keyidlist {
+ char *keyid;
+ int keyidlen;
+ char *key;
+ int keylen;
+ int flags;
+} keyidlist [] = {
+ { "\0", 1, 0, 0, 0 }, /* default key of zero */
+ { 0, 0, 0, 0, 0 }
+};
+
+#define KEYFLAG_MASK 03
+
+#define KEYFLAG_NOINIT 00
+#define KEYFLAG_INIT 01
+#define KEYFLAG_OK 02
+#define KEYFLAG_BAD 03
+
+#define KEYFLAG_SHIFT 2
+
+#define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2)))
+
+#define FB64_IV 1
+#define FB64_IV_OK 2
+#define FB64_IV_BAD 3
+#define FB64_CHALLENGE 4
+#define FB64_RESPONSE 5
+
+void fb64_stream_iv P((Block, struct des_stinfo *));
+void fb64_init P((struct des_fb *));
+static int fb64_start P((struct des_fb *, int, int));
+int fb64_is P((unsigned char *, int, struct des_fb *));
+int fb64_reply P((unsigned char *, int, struct des_fb *));
+static int fb64_session P((Session_Key *, int, struct des_fb *));
+void fb64_stream_key P((Block, struct des_stinfo *));
+int fb64_keyid P((int, unsigned char *, int *, struct des_fb *));
+
+#ifdef MIT_CURRENT
+static void
+#ifdef CK_ANSIC
+ecb_encrypt(struct des_stinfo *stp, Block in, Block out)
+#else /* CKANSIC */
+ecb_encrypt(stp, in, out)
+ struct des_stinfo *stp;
+ Block in;
+ Block out;
+#endif /* CK_ANSIC */
+{
+ krb5_error_code code;
+ krb5_data din;
+ krb5_enc_data dout;
+
+ din.length = 8;
+ din.data = in;
+
+ dout.ciphertext.length = 8;
+ dout.ciphertext.data = out;
+ dout.enctype = ENCTYPE_UNKNOWN;
+
+#ifdef CRYPT_DLL
+ code = krb5_c_encrypt(*p_k5_context, &stp->str_key, 0, 0,
+ &din, &dout);
+#else /* CRYPT_DLL */
+ code = krb5_c_encrypt(k5_context, &stp->str_key, 0, 0,
+ &din, &dout);
+#endif /* CRYPT_DLL */
+ /* XXX I'm not sure what to do if this fails */
+ if (code)
+ com_err("libtelnet", code, "encrypting stream data");
+}
+#endif /* MIT_CURRENT */
+
+void
+cfb64_init(server)
+ int server;
+{
+ fb64_init(&des_fb[CFB]);
+ des_fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
+ des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+ des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+void
+ofb64_init(server)
+ int server;
+{
+ fb64_init(&des_fb[OFB]);
+ des_fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
+ des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+ des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+void
+fb64_init(fbp)
+ register struct des_fb *fbp;
+{
+ memset((void *)fbp, 0, sizeof(*fbp));
+ fbp->state[0] = fbp->state[1] = xFAILED;
+ fbp->fb_feed[0] = IAC;
+ fbp->fb_feed[1] = SB;
+ fbp->fb_feed[2] = TELOPT_ENCRYPTION;
+ fbp->fb_feed[3] = ENCRYPT_IS;
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ * 2: Not yet. Other things (like getting the key from
+ * Kerberos) have to happen before we can continue.
+ */
+int
+cfb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(fb64_start(&des_fb[CFB], dir, server));
+}
+int
+ofb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(fb64_start(&des_fb[OFB], dir, server));
+}
+
+static int
+fb64_start(fbp, dir, server)
+ struct des_fb *fbp;
+ int dir;
+ int server;
+{
+ int x;
+ unsigned char *p;
+ register int state;
+
+ switch (dir) {
+ case DIR_DECRYPT:
+ /*
+ * This is simply a request to have the other side
+ * start output (our input). He will negotiate an
+ * IV so we need not look for it.
+ */
+ state = fbp->state[dir-1];
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+ break;
+
+ case DIR_ENCRYPT:
+ state = fbp->state[dir-1];
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+ else if ((state & NO_SEND_IV) == 0)
+ break;
+
+#ifdef MIT_CURRENT
+ if (!fbp->validkey) {
+ fbp->need_start = 1;
+ break;
+ }
+#else /* MIT_CURRENT */
+ if (!VALIDKEY(fbp->krbdes_key)) {
+ fbp->need_start = 1;
+ break;
+ }
+#endif /* MIT_CURRENT */
+ state &= ~NO_SEND_IV;
+ state |= NO_RECV_IV;
+ /*
+ * Create a random feed and send it over.
+ */
+#ifdef MIT_CURRENT
+ {
+ krb5_data d;
+ krb5_error_code code;
+
+ d.data = fbp->temp_feed;
+ d.length = sizeof(fbp->temp_feed);
+
+#ifdef CRYPT_DLL
+ if (code = krb5_c_random_make_octets(*p_k5_context,&d))
+ return(xFAILED);
+#else /* CRYPT_DLL */
+ if (code = krb5_c_random_make_octets(k5_context,&d))
+ return(xFAILED);
+#endif /* CRYPT_DLL */
+ }
+
+#else /* MIT_CURRENT */
+ des_new_random_key(fbp->temp_feed);
+ des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+ fbp->krbdes_sched, 1);
+#endif /* MIT_CURRENT */
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_IS;
+ p++;
+ *p++ = FB64_IV;
+ for (x = 0; x < sizeof(Block); ++x) {
+ if (( *p++ = fbp->temp_feed[x]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,
+ "TELNET SENT SB %s IS %s FB64_IV ",
+ TELOPT(fbp->fb_feed[2]),
+ enctype_names[fbp->fb_feed[4]]); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],
+ (p-fbp->fb_feed)-2-6);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+ default:
+ return(xFAILED);
+ }
+ return(fbp->state[dir-1] = state);
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ */
+int
+cfb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(fb64_is(data, cnt, &des_fb[CFB]));
+}
+
+int
+ofb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(fb64_is(data, cnt, &des_fb[OFB]));
+}
+
+int
+fb64_is(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct des_fb *fbp;
+{
+ unsigned char *p;
+ register int state = fbp->state[DIR_DECRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+#ifdef CK_SSL
+ if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+#endif /* CK_SSL */
+ switch (*data++) {
+ case FB64_IV:
+ if (cnt != sizeof(Block)) {
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("CFB64: initial vector failed on size\r\n");
+#endif
+ state = xFAILED;
+ goto failure;
+ }
+
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ printf("CFB64: initial vector received\r\n");
+ printf("Initializing Decrypt stream\r\n");
+ }
+#endif
+ fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
+
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_OK;
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,
+ "TELNET SENT SB %s REPLY %s FB64_IV_OK ",
+ TELOPT(fbp->fb_feed[2]),
+ enctype_names[fbp->fb_feed[4]]); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],
+ (p-fbp->fb_feed)-2-6);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ state = IN_PROGRESS;
+ break;
+
+ default:
+#if 0
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", *(data-1));
+ printf("\r\n");
+ }
+#endif
+ /* FALL THROUGH */
+ failure:
+ /*
+ * We failed. Send an FB64_IV_BAD option
+ * to the other side so it will know that
+ * things failed.
+ */
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_BAD;
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,
+ "TELNET SENT SB %s REPLY %s FB64_IV_BAD ",
+ TELOPT(fbp->fb_feed[2]),
+ enctype_names[fbp->fb_feed[4]]); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],
+ (p-fbp->fb_feed)-2-6);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+ }
+ return(fbp->state[DIR_DECRYPT-1] = state);
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ */
+int
+cfb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(fb64_reply(data, cnt, &des_fb[CFB]));
+}
+int
+ofb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(fb64_reply(data, cnt, &des_fb[OFB]));
+}
+
+
+int
+fb64_reply(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct des_fb *fbp;
+{
+ register int state = fbp->state[DIR_ENCRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+ switch (*data++) {
+ case FB64_IV_OK:
+ fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+ state &= ~NO_RECV_IV;
+ encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
+ break;
+
+ case FB64_IV_BAD:
+ memset(fbp->temp_feed, 0, sizeof(Block));
+ fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ state = xFAILED;
+ break;
+
+ default:
+#if 0
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", data[-1]);
+ printf("\r\n");
+ }
+#endif
+ /* FALL THROUGH */
+ failure:
+ state = xFAILED;
+ break;
+ }
+ return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+int
+cfb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(fb64_session(key, server, &des_fb[CFB]));
+}
+
+int
+ofb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(fb64_session(key, server, &des_fb[OFB]));
+}
+
+static int
+fb64_session(key, server, fbp)
+ Session_Key *key;
+ int server;
+ struct des_fb *fbp;
+{
+ int rc=0;
+ int use2keys;
+ struct des_stinfo * s_stream;
+ struct des_stinfo * c_stream;
+
+ if(server) {
+ s_stream = &fbp->streams[DIR_ENCRYPT-1];
+ c_stream = &fbp->streams[DIR_DECRYPT-1];
+ }
+ else {
+ s_stream = &fbp->streams[DIR_DECRYPT-1];
+ c_stream = &fbp->streams[DIR_ENCRYPT-1];
+ }
+
+ if (!key || key->length < sizeof(Block)) {
+ CHAR buf[80];
+ sprintf((char *)buf,"Can't set DES session key (%d < %d)",
+ key ? key->length : 0, sizeof(Block)); /* safe */
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("%s\r\n",buf);
+#endif
+ debug(F110,"fb64_session",buf,0);
+ return(-1);
+ }
+ use2keys = (key->type == SK_DES ||
+ key->length < 2 * sizeof(Block)) ? 0 : 1;
+#ifdef MIT_CURRENT
+ if(use2keys) {
+ memcpy((void *) fbp->keybytes,
+ (void *) (key->data + sizeof(Block)), sizeof(Block));
+ des_fixup_key_parity(fbp->);
+ fb64_stream_key(fbp->krbdes_key, s_stream);
+ }
+
+ memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
+ if (key->type != SK_DES)
+ des_fixup_key_parity(fbp->krbdes_key);
+
+ if(!use2keys)
+ fb64_stream_key(fbp->krbdes_key, s_stream);
+ fb64_stream_key(fbp->krbdes_key, c_stream);
+ fbp->validkey = 1;
+
+ fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1]);
+ fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1]);
+#else /* MIT_CURRENT */
+ if(use2keys) {
+ memcpy((void *) fbp->krbdes_key,
+ (void *) (key->data + sizeof(Block)), sizeof(Block));
+ des_fixup_key_parity(fbp->krbdes_key);
+ fb64_stream_key(fbp->krbdes_key, s_stream);
+ }
+
+ memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
+ if (key->type != SK_DES)
+ des_fixup_key_parity(fbp->krbdes_key);
+
+ if(!use2keys)
+ fb64_stream_key(fbp->krbdes_key, s_stream);
+ fb64_stream_key(fbp->krbdes_key, c_stream);
+
+ if (fbp->once == 0) {
+ des_set_random_generator_seed(fbp->krbdes_key);
+ fbp->once = 1;
+ }
+
+ memset(fbp->krbdes_sched,0,sizeof(Schedule));
+ ckhexdump("fb64_session_key",fbp->krbdes_key,8);
+
+ rc = des_key_sched(fbp->krbdes_key, fbp->krbdes_sched);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified for encryption\n");
+ debug(F110,"fb64_session_key",
+ "invalid DES Key specified for encryption",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified for encryption\n");
+ debug(F110,"fb64_session_key",
+ "weak DES Key specified for encryption",0);
+ } else if ( rc != 0 ) {
+ printf("?Key Schedule not created by encryption\n");
+ debug(F110,"fb64_session_key",
+ "Key Schedule not created by encryption",0);
+ }
+
+ ckhexdump("fb64_session_key schedule",fbp->krbdes_sched,8*16);
+#endif /* MIT_CURRENT */
+ /*
+ * Now look to see if krbdes_start() was was waiting for
+ * the key to show up. If so, go ahead an call it now
+ * that we have the key.
+ */
+ if (fbp->need_start) {
+ fbp->need_start = 0;
+ fb64_start(fbp, DIR_ENCRYPT, server);
+ }
+ return(0);
+}
+
+/*
+ * We only accept a keyid of 0. If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+int
+cfb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(fb64_keyid(dir, kp, lenp, &des_fb[CFB]));
+}
+
+int
+ofb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(fb64_keyid(dir, kp, lenp, &des_fb[OFB]));
+}
+
+int
+fb64_keyid(dir, kp, lenp, fbp)
+ int dir, *lenp;
+ unsigned char *kp;
+ struct des_fb *fbp;
+{
+ register int state = fbp->state[dir-1];
+
+ if (*lenp != 1 || (*kp != '\0')) {
+ *lenp = 0;
+ return(state);
+ }
+
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+
+ state &= ~NO_KEYID;
+
+ return(fbp->state[dir-1] = state);
+}
+
+#if 0
+void
+fb64_printsub(data, cnt, buf, buflen, type)
+ unsigned char *data, *buf, *type;
+ int cnt, buflen;
+{
+ char lbuf[64];
+ register int i;
+ char *cp;
+
+ buf[buflen-1] = '\0'; /* make sure it's NULL terminated */
+ buflen -= 1;
+
+ switch(data[2]) {
+ case FB64_IV:
+ sprintf(lbuf, "%s_IV", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_OK:
+ sprintf(lbuf, "%s_IV_OK", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_BAD:
+ sprintf(lbuf, "%s_IV_BAD", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_CHALLENGE:
+ sprintf(lbuf, "%s_CHALLENGE", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_RESPONSE:
+ sprintf(lbuf, "%s_RESPONSE", type);
+ cp = lbuf;
+ goto common;
+
+ default:
+ sprintf(lbuf, " %d (unknown)", data[2]);
+ cp = lbuf;
+ common:
+ for (; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ for (i = 3; i < cnt; i++) {
+ sprintf(lbuf, " %d", data[i]);
+ for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ }
+ break;
+ }
+}
+
+void
+cfb64_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+ofb64_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+#endif
+
+void
+fb64_stream_iv(seed, stp)
+ Block seed;
+ register struct des_stinfo *stp;
+{
+ int rc=0;
+
+ memcpy(stp->str_iv, seed, sizeof(Block));
+ memcpy(stp->str_output, seed, sizeof(Block));
+
+ memset(stp->str_sched,0,sizeof(Schedule));
+
+ ckhexdump("fb64_stream_iv",stp->str_ikey,8);
+
+#ifndef MIT_CURRENT
+ rc = des_key_sched(stp->str_ikey, stp->str_sched);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified for encryption\r\n");
+ debug(F110,"fb64_stream_iv",
+ "invalid DES Key specified for encryption",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified for encryption\r\n");
+ debug(F110,"fb64_stream_iv",
+ "weak DES Key specified for encryption",0);
+ } else if ( rc != 0 ) {
+ printf("?Key Schedule not created by encryption\r\n");
+ debug(F110,"fb64_stream_iv",
+ "Key Schedule not created by encryption",0);
+ }
+ ckhexdump("fb64_stream_iv schedule",stp->str_sched,8*16);
+#endif /* MIT_CURRENT */
+
+ stp->str_index = sizeof(Block);
+}
+
+void
+fb64_stream_key(key, stp)
+ Block key;
+ register struct des_stinfo *stp;
+{
+ int rc = 0;
+
+#ifdef MIT_CURRENT
+ memcpy(stp->str_keybytes, key, sizeof(Block));
+ stp->str_key.length = 8;
+ stp->str_key.contents = stp->str_keybytes;
+ /* the original version of this code uses des ecb mode, but
+ it only ever does one block at a time. cbc with a zero iv
+ is identical */
+ stp->str_key.enctype = ENCTYPE_DES_CBC_RAW;
+#else /* MIT_CURRENT */
+ memcpy(stp->str_ikey, key, sizeof(Block));
+
+ memset(stp->str_sched,0,sizeof(Schedule));
+
+ ckhexdump("fb64_stream_key",key,8);
+
+ rc = des_key_sched(key, stp->str_sched);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified for encryption\r\n");
+ debug(F110,"fb64_stream_key",
+ "invalid DES Key specified for encryption",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified for encryption\r\n");
+ debug(F110,"fb64_stream_key",
+ "weak DES Key specified for encryption",0);
+ } else if ( rc != 0 ) {
+ printf("?Key Schedule not created by encryption\r\n");
+ debug(F110,"fb64_stream_key",
+ "Key Schedule not created by encryption",0);
+ }
+ ckhexdump("fb64_stream_key schedule",stp->str_sched,8*16);
+#endif /* MIT_CURRENT */
+
+ memcpy(stp->str_output, stp->str_iv, sizeof(Block));
+
+ stp->str_index = sizeof(Block);
+}
+
+/*
+ * DES 64 bit Cipher Feedback
+ *
+ * key --->+-----+
+ * +->| DES |--+
+ * | +-----+ |
+ * | v
+ * INPUT --(--------->(+)+---> DATA
+ * | |
+ * +-------------+
+ *
+ *
+ * Given:
+ * iV: Initial vector, 64 bits (8 bytes) long.
+ * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ * V0 = DES(iV, key)
+ * On = Dn ^ Vn
+ * V(n+1) = DES(On, key)
+ */
+
+void
+cfb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_ENCRYPT-1];
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef MIT_CURRENT
+ ecb_encrypt(stp, stp->str_output, b);
+#else /* MIT_CURRENT */
+ des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+ memcpy(stp->str_feed,b,sizeof(Block));
+ index = 0;
+ }
+
+ /* On encryption, we store (feed ^ data) which is cypher */
+ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
+ s++;
+ index++;
+ }
+ stp->str_index = index;
+}
+
+int
+cfb64_decrypt(data)
+ int data;
+{
+ register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_DECRYPT-1];
+ int index;
+
+ if (data == -1) {
+ /*
+ * Back up one byte. It is assumed that we will
+ * never back up more than one byte. If we do, this
+ * may or may not work.
+ */
+ if (stp->str_index)
+ --stp->str_index;
+ return(0);
+ }
+
+ index = stp->str_index++;
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef MIT_CURRENT
+ ecb_encrypt(stp, stp->str_output, b);
+#else /* MIT_CURRENT */
+ des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+ memcpy(stp->str_feed, b, sizeof(Block));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ /* On decryption we store (data) which is cypher. */
+ stp->str_output[index] = data;
+ return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * DES 64 bit Output Feedback
+ *
+ * key --->+-----+
+ * +->| DES |--+
+ * | +-----+ |
+ * +-----------+
+ * v
+ * INPUT -------->(+) ----> DATA
+ *
+ * Given:
+ * iV: Initial vector, 64 bits (8 bytes) long.
+ * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ * V0 = DES(iV, key)
+ * V(n+1) = DES(Vn, key)
+ * On = Dn ^ Vn
+ */
+void
+ofb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_ENCRYPT-1];
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef MIT_CURRENT
+ ecb_encrypt(stp, stp->str_feed, b);
+#else /* MIT_CURRENT */
+ des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+ memcpy(stp->str_feed,b,sizeof(Block));
+ index = 0;
+ }
+ *s++ ^= stp->str_feed[index];
+ index++;
+ }
+ stp->str_index = index;
+}
+
+int
+ofb64_decrypt(data)
+ int data;
+{
+ register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_DECRYPT-1];
+ int index;
+
+ if (data == -1) {
+ /*
+ * Back up one byte. It is assumed that we will
+ * never back up more than one byte. If we do, this
+ * may or may not work.
+ */
+ if (stp->str_index)
+ --stp->str_index;
+ return(0);
+ }
+
+ index = stp->str_index++;
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef MIT_CURRENT
+ ecb_encrypt(stp, stp->str_feed, b);
+#else /* MIT_CURRENT */
+ des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+#endif /* MIT_CURRENT */
+ memcpy(stp->str_feed, b, sizeof(Block));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ return(data ^ stp->str_feed[index]);
+}
+
+
+void des3_fb64_stream_iv P((Block, struct des3_stinfo *));
+void des3_fb64_init P((struct des3_fb *));
+static int des3_fb64_start P((struct des3_fb *, int, int));
+int des3_fb64_is P((unsigned char *, int, struct des3_fb *));
+int des3_fb64_reply P((unsigned char *, int, struct des3_fb *));
+static int des3_fb64_session P((Session_Key *, int, struct des3_fb *));
+void des3_fb64_stream_key P((Block *, struct des3_stinfo *));
+int des3_fb64_keyid P((int, unsigned char *, int *, struct des3_fb *));
+
+void
+des3_cfb64_init(server)
+ int server;
+{
+ des3_fb64_init(&des3_fb[CFB]);
+ des3_fb[CFB].fb_feed[4] = ENCTYPE_DES3_CFB64;
+ des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+ des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+void
+des3_ofb64_init(server)
+ int server;
+{
+ des3_fb64_init(&des3_fb[OFB]);
+ des3_fb[OFB].fb_feed[4] = ENCTYPE_DES3_OFB64;
+ des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+ des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+void
+des3_fb64_init(fbp)
+ register struct des3_fb *fbp;
+{
+ memset((void *)fbp, 0, sizeof(*fbp));
+ fbp->state[0] = fbp->state[1] = xFAILED;
+ fbp->fb_feed[0] = IAC;
+ fbp->fb_feed[1] = SB;
+ fbp->fb_feed[2] = TELOPT_ENCRYPTION;
+ fbp->fb_feed[3] = ENCRYPT_IS;
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ * 2: Not yet. Other things (like getting the key from
+ * Kerberos) have to happen before we can continue.
+ */
+int
+des3_cfb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(des3_fb64_start(&des3_fb[CFB], dir, server));
+}
+int
+des3_ofb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(des3_fb64_start(&des3_fb[OFB], dir, server));
+}
+
+static int
+des3_fb64_start(fbp, dir, server)
+ struct des3_fb *fbp;
+ int dir;
+ int server;
+{
+ int x;
+ unsigned char *p;
+ register int state;
+
+ switch (dir) {
+ case DIR_DECRYPT:
+ /*
+ * This is simply a request to have the other side
+ * start output (our input). He will negotiate an
+ * IV so we need not look for it.
+ */
+ state = fbp->state[dir-1];
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+ break;
+
+ case DIR_ENCRYPT:
+ state = fbp->state[dir-1];
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+ else if ((state & NO_SEND_IV) == 0)
+ break;
+
+ if (!VALIDKEY(fbp->krbdes_key[0]) ||
+ !VALIDKEY(fbp->krbdes_key[1]) ||
+ !VALIDKEY(fbp->krbdes_key[2]) ) {
+ fbp->need_start = 1;
+ break;
+ }
+ state &= ~NO_SEND_IV;
+ state |= NO_RECV_IV;
+ /*
+ * Create a random feed and send it over.
+ */
+ des_new_random_key(fbp->temp_feed);
+#ifdef LIBDES
+ des_ecb3_encrypt(fbp->temp_feed, fbp->temp_feed,
+ fbp->krbdes_sched[0],
+ fbp->krbdes_sched[1],
+ fbp->krbdes_sched[2],
+ 1);
+#else /* LIBDES */
+ des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+ fbp->krbdes_sched[0], 1);
+ des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+ fbp->krbdes_sched[1], 0);
+ des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+ fbp->krbdes_sched[2], 1);
+#endif /* LIBDES */
+
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_IS;
+ p++;
+ *p++ = FB64_IV;
+ for (x = 0; x < sizeof(Block); ++x) {
+ if (( *p++ = fbp->temp_feed[x]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,
+ "TELNET SENT SB %s IS %s FB64_IV ",
+ TELOPT(fbp->fb_feed[2]),
+ enctype_names[fbp->fb_feed[4]]); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],
+ (p-fbp->fb_feed)-2-6);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+ default:
+ return(xFAILED);
+ }
+ return(fbp->state[dir-1] = state);
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ */
+int
+des3_cfb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(des3_fb64_is(data, cnt, &des3_fb[CFB]));
+}
+
+int
+des3_ofb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(des3_fb64_is(data, cnt, &des3_fb[OFB]));
+}
+
+int
+des3_fb64_is(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct des3_fb *fbp;
+{
+ unsigned char *p;
+ register int state = fbp->state[DIR_DECRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+#ifdef CK_SSL
+ if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+#endif /* CK_SSL */
+ switch (*data++) {
+ case FB64_IV:
+ if (cnt != sizeof(Block)) {
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("DES3_FB64: initial vector failed on size\r\n");
+#endif
+ state = xFAILED;
+ goto failure;
+ }
+
+#ifdef DEBUG
+ if (encrypt_debug_mode) {
+ printf("DES3_FB64: initial vector received\r\n");
+ printf("Initializing Decrypt stream\r\n");
+ }
+#endif
+ des3_fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
+
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_OK;
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,
+ "TELNET SENT SB %s REPLY %s FB64_IV_OK ",
+ TELOPT(fbp->fb_feed[2]),
+ enctype_names[fbp->fb_feed[4]]); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],
+ (p-fbp->fb_feed)-2-6);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ state = IN_PROGRESS;
+ break;
+
+ default:
+#if 0
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", *(data-1));
+ printf("\r\n");
+ }
+#endif
+ /* FALL THROUGH */
+ failure:
+ /*
+ * We failed. Send an FB64_IV_BAD option
+ * to the other side so it will know that
+ * things failed.
+ */
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_BAD;
+ *p++ = IAC;
+ *p++ = SE;
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ sprintf(tn_msg,
+ "TELNET SENT SB %s REPLY %s FB64_IV_BAD ",
+ TELOPT(fbp->fb_feed[2]),
+ enctype_names[fbp->fb_feed[4]]); /* safe */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],
+ (p-fbp->fb_feed)-2-6);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+ }
+ return(fbp->state[DIR_DECRYPT-1] = state);
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ */
+int
+des3_cfb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(des3_fb64_reply(data, cnt, &des3_fb[CFB]));
+}
+int
+des3_ofb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(des3_fb64_reply(data, cnt, &des3_fb[OFB]));
+}
+
+
+int
+des3_fb64_reply(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct des3_fb *fbp;
+{
+ register int state = fbp->state[DIR_ENCRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+ switch (*data++) {
+ case FB64_IV_OK:
+ des3_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+ state &= ~NO_RECV_IV;
+ encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
+ break;
+
+ case FB64_IV_BAD:
+ memset(fbp->temp_feed, 0, sizeof(Block));
+ des3_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ state = xFAILED;
+ break;
+
+ default:
+#if 0
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", data[-1]);
+ printf("\r\n");
+ }
+#endif
+ /* FALL THROUGH */
+ failure:
+ state = xFAILED;
+ break;
+ }
+ return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+int
+des3_cfb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(des3_fb64_session(key, server, &des3_fb[CFB]));
+}
+
+int
+des3_ofb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(des3_fb64_session(key, server, &des3_fb[OFB]));
+}
+
+static int
+des3_fb64_session(key, server, fbp)
+ Session_Key *key;
+ int server;
+ struct des3_fb *fbp;
+{
+ int rc=0,i=0;
+ int keys2use=0;
+ struct des3_stinfo * s_stream;
+ struct des3_stinfo * c_stream;
+
+ if(server) {
+ s_stream = &fbp->streams[DIR_ENCRYPT-1];
+ c_stream = &fbp->streams[DIR_DECRYPT-1];
+ }
+ else {
+ s_stream = &fbp->streams[DIR_DECRYPT-1];
+ c_stream = &fbp->streams[DIR_ENCRYPT-1];
+ }
+
+ keys2use = key->length / sizeof(Block);
+ if (!key || (key->type == SK_DES) || (keys2use < 2)) {
+ CHAR buf[80];
+ sprintf((char *)buf,"Can't set 3DES session key (%d < %d)",
+ key ? key->length : 0, 2 * (int)sizeof(Block)); /* safe */
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("%s\r\n",buf);
+#endif
+ debug(F110,"des3_fb64_session",buf,0);
+ return(-1);
+ }
+
+ debug(F111,"des3_fb64_session","keys2use",keys2use);
+ /* Compute the first set of keys / key order */
+ switch ( keys2use ) {
+ case 2:
+ memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block));
+ break;
+ case 3:
+ default:
+ memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[2],
+ (void *) (key->data + 2*sizeof(Block)), sizeof(Block));
+ break;
+ }
+ ckhexdump("des3_session_key key->data",key->data,sizeof(Block));
+ ckhexdump("des3_session_key fbp->krbdes_key[0]",
+ fbp->krbdes_key[0],
+ sizeof(Block)
+ );
+ if (fbp->once == 0) {
+ des_set_random_generator_seed(fbp->krbdes_key[0]);
+ fbp->once = 1;
+ }
+
+ for ( i=0;i<3;i++ )
+ des_fixup_key_parity(fbp->krbdes_key[i]);
+ des3_fb64_stream_key(fbp->krbdes_key, s_stream);
+
+
+ /* Compute the second set of keys / key order */
+ switch ( keys2use ) {
+ case 2:
+ memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ memcpy((void *)fbp->krbdes_key[1], (void *)key->data, sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[2],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ break;
+ case 3:
+ memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[1],
+ (void *) (key->data + 2*sizeof(Block)), sizeof(Block));
+ memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block));
+ break;
+ case 4:
+ memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[1],
+ (void *) (key->data + 3*sizeof(Block)), sizeof(Block));
+ memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block));
+ break;
+ case 5:
+ memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)),
+ sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[1],
+ (void *) (key->data + 3*sizeof(Block)), sizeof(Block));
+ memcpy((void *)fbp->krbdes_key[2],
+ (void *)(key->data + 4*sizeof(Block)), sizeof(Block));
+ break;
+ case 6:
+ memcpy((void *) fbp->krbdes_key[0],
+ (void *) (key->data + 3*sizeof(Block)), sizeof(Block));
+ memcpy((void *)fbp->krbdes_key[1],
+ (void *)(key->data + 4*sizeof(Block)), sizeof(Block));
+ memcpy((void *) fbp->krbdes_key[2],
+ (void *) (key->data + 5 *sizeof(Block)), sizeof(Block));
+ break;
+ }
+
+ for ( i=0;i<3;i++ )
+ des_fixup_key_parity(fbp->krbdes_key[i]);
+ des3_fb64_stream_key(fbp->krbdes_key, c_stream);
+
+ /* now use the second set of keys to build the default Key Schedule */
+ /* which is used for generating the IV. */
+ for ( i=0;i<3;i++ ) {
+ memset(fbp->krbdes_sched[i],0,sizeof(Schedule));
+
+ rc = des_key_sched(fbp->krbdes_key[i], fbp->krbdes_sched[i]);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified for encryption [DES3,%s]\r\n",
+ server?"server":"client");
+ debug(F110,"des3_fb64_stream_iv",
+ "invalid DES Key specified for encryption",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified for encryption\r\n");
+ debug(F110,"des3_fb64_stream_iv",
+ "weak DES Key specified for encryption",0);
+ } else if ( rc != 0 ) {
+ printf("?Key Schedule not created by encryption\r\n");
+ debug(F110,"des3_fb64_stream_iv",
+ "Key Schedule not created by encryption",0);
+ }
+ ckhexdump("des3_fb64_session_key schedule",fbp->krbdes_sched[i],8*16);
+ }
+ /*
+ * Now look to see if krbdes_start() was was waiting for
+ * the key to show up. If so, go ahead an call it now
+ * that we have the key.
+ */
+ if (fbp->need_start) {
+ fbp->need_start = 0;
+ des3_fb64_start(fbp, DIR_ENCRYPT, server);
+ }
+ return(0);
+}
+
+/*
+ * We only accept a keyid of 0. If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+int
+des3_cfb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[CFB]));
+}
+
+int
+des3_ofb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[OFB]));
+}
+
+int
+des3_fb64_keyid(dir, kp, lenp, fbp)
+ int dir, *lenp;
+ unsigned char *kp;
+ struct des3_fb *fbp;
+{
+ register int state = fbp->state[dir-1];
+
+ if (*lenp != 1 || (*kp != '\0')) {
+ *lenp = 0;
+ return(state);
+ }
+
+ if (state == xFAILED)
+ state = IN_PROGRESS;
+
+ state &= ~NO_KEYID;
+
+ return(fbp->state[dir-1] = state);
+}
+
+#if 0
+void
+des3_fb64_printsub(data, cnt, buf, buflen, type)
+ unsigned char *data, *buf, *type;
+ int cnt, buflen;
+{
+ char lbuf[64];
+ register int i;
+ char *cp;
+
+ buf[buflen-1] = '\0'; /* make sure it's NULL terminated */
+ buflen -= 1;
+
+ switch(data[2]) {
+ case FB64_IV:
+ sprintf(lbuf, "%s_IV", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_OK:
+ sprintf(lbuf, "%s_IV_OK", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_BAD:
+ sprintf(lbuf, "%s_IV_BAD", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_CHALLENGE:
+ sprintf(lbuf, "%s_CHALLENGE", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_RESPONSE:
+ sprintf(lbuf, "%s_RESPONSE", type);
+ cp = lbuf;
+ goto common;
+
+ default:
+ sprintf(lbuf, " %d (unknown)", data[2]);
+ cp = lbuf;
+ common:
+ for (; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ for (i = 3; i < cnt; i++) {
+ sprintf(lbuf, " %d", data[i]);
+ for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ }
+ break;
+ }
+}
+
+void
+des3_cfb64_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ des3_fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+des3_ofb64_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ des3_fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+#endif
+
+void
+des3_fb64_stream_iv(seed, stp)
+ Block seed;
+ register struct des3_stinfo *stp;
+{
+ int rc=0, i = 0;;
+
+ memcpy(stp->str_iv, seed, sizeof(Block));
+ memcpy(stp->str_output, seed, sizeof(Block));
+ for ( i=0;i<3;i++ ) {
+ memset(stp->str_sched[i],0,sizeof(Schedule));
+
+ ckhexdump("des3_fb64_stream_iv",stp->str_ikey[i],8);
+
+ rc = des_key_sched(stp->str_ikey[i], stp->str_sched[i]);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified for encryption [DES3 iv]\r\n");
+ debug(F110,"des3_fb64_stream_iv",
+ "invalid DES Key specified for encryption",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified for encryption\r\n");
+ debug(F110,"des3_fb64_stream_iv",
+ "weak DES Key specified for encryption",0);
+ } else if ( rc != 0 ) {
+ printf("?Key Schedule not created by encryption\r\n");
+ debug(F110,"des3_fb64_stream_iv",
+ "Key Schedule not created by encryption",0);
+ }
+ ckhexdump("des3_fb64_stream_iv schedule",stp->str_sched[i],8*16);
+ }
+ stp->str_index = sizeof(Block);
+}
+
+void
+des3_fb64_stream_key(key, stp)
+ Block * key;
+ register struct des3_stinfo *stp;
+{
+ int rc = 0, i = 0;
+
+ for ( i=0;i<3;i++ ) {
+ memcpy(stp->str_ikey[i], key[i], sizeof(Block));
+
+ memset(stp->str_sched[i],0,sizeof(Schedule));
+
+ ckhexdump("des3_fb64_stream_key",key[i],8);
+
+ rc = des_key_sched(key[i], stp->str_sched[i]);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified for encryption [DES3 key]\r\n");
+ debug(F110,"des3_fb64_stream_key",
+ "invalid DES Key specified for encryption",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified for encryption\r\n");
+ debug(F110,"des3_fb64_stream_key",
+ "weak DES Key specified for encryption",0);
+ } else if ( rc != 0 ) {
+ printf("?Key Schedule not created by encryption\r\n");
+ debug(F110,"des3_fb64_stream_key",
+ "Key Schedule not created by encryption",0);
+ }
+ ckhexdump("des3_fb64_stream_key schedule",stp->str_sched[i],8*16);
+ }
+
+ memcpy(stp->str_output, stp->str_iv, sizeof(Block));
+ stp->str_index = sizeof(Block);
+}
+
+/*
+ * DES3 64 bit Cipher Feedback
+ *
+ * key1 key2 key3
+ * | | |
+ * v v v
+ * +-------+ +-------+ +-------+
+ * +->| DES-e |->| DES-d |->| DES-e |-- +
+ * | +-------+ +-------+ +-------+ |
+ * | v
+ * INPUT --(-------------------------------->(+)+---> DATA
+ * | |
+ * +------------------------------------+
+ *
+ *
+ * Given:
+ * iV: Initial vector, 64 bits (8 bytes) long.
+ * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ * V0 = DES-e(DES-d(DES-e(iV, key1),key2),key3)
+ * On = Dn ^ Vn
+ * V(n+1) = DES-e(DES-d(DES-e(On, key1),key2),key3)
+ */
+
+void
+des3_cfb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_ENCRYPT-1];
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef LIBDES
+ des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0],
+ stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[0], 1);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[1], 0);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[2], 1);
+#endif /* LIBDES */
+ memcpy(stp->str_feed,b,sizeof(Block));
+ index = 0;
+ }
+
+ /* On encryption, we store (feed ^ data) which is cypher */
+ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
+ s++;
+ index++;
+ }
+ stp->str_index = index;
+}
+
+int
+des3_cfb64_decrypt(data)
+ int data;
+{
+ register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_DECRYPT-1];
+ int index;
+
+ if (data == -1) {
+ /*
+ * Back up one byte. It is assumed that we will
+ * never back up more than one byte. If we do, this
+ * may or may not work.
+ */
+ if (stp->str_index)
+ --stp->str_index;
+ return(0);
+ }
+
+ index = stp->str_index++;
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef LIBDES
+ des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0],
+ stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[0], 1);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[1], 0);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[2], 1);
+#endif /* LIBDES */
+ memcpy(stp->str_feed, b, sizeof(Block));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ /* On decryption we store (data) which is cypher. */
+ stp->str_output[index] = data;
+ return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * DES3 64 bit Output Feedback
+ *
+ *
+ * key1 key2 key3
+ * | | |
+ * v v v
+ * +-------+ +-------+ +-------+
+ * +->| DES-e |->| DES-d |->| DES-e |-- +
+ * | +-------+ +-------+ +-------+ |
+ * +------------------------------------+
+ * v
+ * INPUT ------------------------------------->(+) ----> DATA
+ *
+ * Given:
+ * iV: Initial vector, 64 bits (8 bytes) long.
+ * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ * V0 = DES-e(DES-d(DES-e(iV, key1),key2),key3)
+ * V(n+1) = DES-e(DES-d(DES-e(Vn, key1),key2),key3)
+ * On = Dn ^ Vn
+ */
+void
+des3_ofb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_ENCRYPT-1];
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef LIBDES
+ des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0],
+ stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[0], 1);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[1], 0);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[2], 1);
+#endif /* LIBDES */
+ memcpy(stp->str_feed,b,sizeof(Block));
+ index = 0;
+ }
+ *s++ ^= stp->str_feed[index];
+ index++;
+ }
+ stp->str_index = index;
+}
+
+int
+des3_ofb64_decrypt(data)
+ int data;
+{
+ register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_DECRYPT-1];
+ int index;
+
+ if (data == -1) {
+ /*
+ * Back up one byte. It is assumed that we will
+ * never back up more than one byte. If we do, this
+ * may or may not work.
+ */
+ if (stp->str_index)
+ --stp->str_index;
+ return(0);
+ }
+
+ index = stp->str_index++;
+ if (index == sizeof(Block)) {
+ Block b;
+#ifdef LIBDES
+ des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0],
+ stp->str_sched[1], stp->str_sched[2], 1);
+#else /* LIBDES */
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[0], 1);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[1], 0);
+ des_ecb_encrypt(stp->str_output, b,
+ stp->str_sched[2], 1);
+#endif /* LIBDES */
+ memcpy(stp->str_feed, b, sizeof(Block));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ return(data ^ stp->str_feed[index]);
+}
+#endif /* CK_DES */
+
+#ifdef CK_CAST
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997 Stanford University
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+
+/*
+ * cast.h
+ * Author: Tom Wu
+ *
+ * Type and function declarations for CAST.
+ */
+
+#ifndef _CAST_H_
+#define _CAST_H_
+
+#ifndef P
+#ifdef __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif /* __STDC__ */
+#endif /* P */
+
+#ifndef LITTLE_ENDIAN
+#ifndef BIG_ENDIAN
+#ifndef WORDS_BIGENDIAN
+#define LITTLE_ENDIAN 1
+#endif /* WORDS_BIGENDIAN */
+#endif /* BIG_ENDIAN */
+#endif /* LITTLE_ENDIAN */
+
+typedef unsigned int uint32; /* Must be 32 bits */
+typedef uint32 * uint32p;
+typedef unsigned char uint8;
+typedef uint8 * uint8p;
+
+typedef struct {
+ struct CastSubkeyPair {
+ uint32 Km;
+ uint32 Kr;
+ } K[16];
+ int ksize;
+} CastKeySched;
+
+/*
+ * cast*_key_sched(schedule, key)
+ *
+ * Initializes the CAST key schedule "schedule" according to the given key.
+ * The different setup routines accept different length keys:
+ *
+ * ck_cast5_40_key_sched: 40-bit/5-byte (12 round) keys
+ * ck_cast5_64_key_sched: 64-bit/8-byte (12 round) keys
+ * ck_cast5_80_key_sched: 80-bit/10-byte (12 round) keys
+ * ck_cast128_key_sched: 128-bit/16-byte (16 round) keys
+ */
+
+extern void ck_cast5_40_key_sched P((CastKeySched *, uint8 *));
+extern void ck_cast5_64_key_sched P((CastKeySched *, uint8 *));
+extern void ck_cast5_80_key_sched P((CastKeySched *, uint8 *));
+extern void ck_cast128_key_sched P((CastKeySched *, uint8 *));
+
+/*
+ * ck_cast_ecb_encrypt(output, input, schedule, mode)
+ * ck_cast_ecb_crypt(data, schedule, mode)
+ *
+ * Encrypts the 64-bit "input" according to the CAST key schedule
+ * "schedule" and places the result in "output". If "mode" is 0,
+ * ck_cast_ecb_encrypt will encrypt, otherwise it will decrypt.
+ * "Output" and "input" can point to the same memory, in which case
+ * en/decryption will be performed in place.
+ *
+ * ck_cast_ecb_crypt accepts input in the form of an array of two
+ * 32-bit words and performs encryption/decryption in place.
+ */
+
+extern void ck_cast_ecb_encrypt P((uint8 *, uint8 *, CastKeySched *, int));
+extern void ck_cast_ecb_crypt P((uint32 *, CastKeySched *, int));
+
+#endif /* CAST_H */
+
+extern encrypt_debug_mode;
+
+#define CFB_40 0
+#define OFB_40 1
+#ifdef CAST_EXPORT_ENCRYPTION
+#define FB_CNT 2
+#else
+#define CFB_128 2
+#define OFB_128 3
+#define FB_CNT 4
+#endif
+
+#define NO_SEND_IV 1
+#define NO_RECV_IV 2
+#define NO_KEYID 4
+#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
+#define SUCCESS 0
+#define cFAILED -1
+
+
+struct cast_fb {
+ Block temp_feed;
+ unsigned char fb_feed[64];
+ int key_isset;
+ int need_start;
+ int state[2];
+ struct cast_stinfo {
+ Block str_output;
+ Block str_feed;
+ Block str_iv;
+ CastKeySched str_sched;
+ int str_index;
+ } streams[2];
+};
+
+static struct cast_fb cast_fb[FB_CNT];
+
+#define FB64_IV 1
+#define FB64_IV_OK 2
+#define FB64_IV_BAD 3
+
+
+static void cast_fb64_stream_iv P((Block, struct cast_stinfo *));
+static void cast_fb64_init P((struct cast_fb *));
+static int cast_fb64_start P((struct cast_fb *, int, int));
+static int cast_fb64_is P((unsigned char *, int, struct cast_fb *));
+static int cast_fb64_reply P((unsigned char *, int, struct cast_fb *));
+static int cast_fb64_session P((Session_Key *, int, struct cast_fb *, int));
+static void cast_fb64_stream_key P((Block, struct cast_stinfo *, int));
+static int cast_fb64_keyid P((int, unsigned char *, int *, struct cast_fb *));
+static void _cast_cfb64_encrypt P((unsigned char *,int, struct cast_stinfo *));
+static int _cast_cfb64_decrypt P((int, struct cast_stinfo *));
+static void _cast_ofb64_encrypt P((unsigned char *,int, struct cast_stinfo *));
+static int _cast_ofb64_decrypt P((int, struct cast_stinfo *));
+
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+cast_cfb64_init(server)
+ int server;
+{
+ cast_fb64_init(&cast_fb[CFB_128]);
+ cast_fb[CFB_128].fb_feed[4] = ENCTYPE_CAST128_CFB64;
+}
+
+void
+cast_ofb64_init(server)
+ int server;
+{
+ cast_fb64_init(&cast_fb[OFB_128]);
+ cast_fb[OFB_128].fb_feed[4] = ENCTYPE_CAST128_OFB64;
+}
+#endif
+
+void
+castexp_cfb64_init(server)
+ int server;
+{
+ cast_fb64_init(&cast_fb[CFB_40]);
+ cast_fb[CFB_40].fb_feed[4] = ENCTYPE_CAST5_40_CFB64;
+}
+
+void
+castexp_ofb64_init(server)
+ int server;
+{
+ cast_fb64_init(&cast_fb[OFB_40]);
+ cast_fb[OFB_40].fb_feed[4] = ENCTYPE_CAST5_40_OFB64;
+}
+
+static void
+cast_fb64_init(fbp)
+ register struct cast_fb *fbp;
+{
+ memset((void *)fbp, 0, sizeof(*fbp));
+ fbp->key_isset = 0;
+ fbp->state[0] = fbp->state[1] = cFAILED;
+ fbp->fb_feed[0] = IAC;
+ fbp->fb_feed[1] = SB;
+ fbp->fb_feed[2] = TELOPT_ENCRYPTION;
+ fbp->fb_feed[3] = ENCRYPT_IS;
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ * 2: Not yet. Other things (like getting the key from
+ * Kerberos) have to happen before we can continue.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(cast_fb64_start(&cast_fb[CFB_128], dir, server));
+}
+
+int
+cast_ofb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(cast_fb64_start(&cast_fb[OFB_128], dir, server));
+}
+#endif
+
+int
+castexp_cfb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(cast_fb64_start(&cast_fb[CFB_40], dir, server));
+}
+
+int
+castexp_ofb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(cast_fb64_start(&cast_fb[OFB_40], dir, server));
+}
+
+static int
+cast_fb64_start(fbp, dir, server)
+ struct cast_fb *fbp;
+ int dir;
+ int server;
+{
+ Block b;
+ int x;
+ unsigned char *p;
+ register int state;
+
+ switch (dir) {
+ case DIR_DECRYPT:
+ /*
+ * This is simply a request to have the other side
+ * start output (our input). He will negotiate an
+ * IV so we need not look for it.
+ */
+ state = fbp->state[dir-1];
+ if (state == cFAILED)
+ state = IN_PROGRESS;
+ break;
+
+ case DIR_ENCRYPT:
+ state = fbp->state[dir-1];
+ if (state == cFAILED)
+ state = IN_PROGRESS;
+ else if ((state & NO_SEND_IV) == 0)
+ break;
+
+ if (!fbp->key_isset) {
+ fbp->need_start = 1;
+ break;
+ }
+ state &= ~NO_SEND_IV;
+ state |= NO_RECV_IV;
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("Creating new feed\r\n");
+#endif
+ /*
+ * Create a random feed and send it over.
+ */
+ ck_cast_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
+ &fbp->streams[dir-1].str_sched, 0);
+
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_IS;
+ p++;
+ *p++ = FB64_IV;
+ for (x = 0; x < sizeof(Block); ++x) {
+ if ((*p++ = fbp->temp_feed[x]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+ break;
+ default:
+ return(cFAILED);
+ }
+ return(fbp->state[dir-1] = state);
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_is(data, cnt, &cast_fb[CFB_128]));
+}
+
+int
+cast_ofb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_is(data, cnt, &cast_fb[OFB_128]));
+}
+#endif
+
+int
+castexp_cfb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_is(data, cnt, &cast_fb[CFB_40]));
+}
+
+int
+castexp_ofb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_is(data, cnt, &cast_fb[OFB_40]));
+}
+
+static int
+cast_fb64_is(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct cast_fb *fbp;
+{
+ int x;
+ unsigned char *p;
+ Block b;
+ register int state = fbp->state[DIR_DECRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+#ifdef CK_SSL
+ if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+#endif /* CK_SSL */
+ switch (*data++) {
+ case FB64_IV:
+ if (cnt != sizeof(Block)) {
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("FB64: initial vector failed on size\r\n");
+#endif
+ state = cFAILED;
+ goto failure;
+ }
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("FB64: initial vector received\r\n");
+
+ if (encrypt_debug_mode)
+ printf("Initializing Decrypt stream\r\n");
+#endif
+ cast_fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
+
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_OK;
+ *p++ = IAC;
+ *p++ = SE;
+
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+ state = IN_PROGRESS;
+ break;
+
+ default:
+ /* unknown option type */
+ /* FALL THROUGH */
+ failure:
+ /*
+ * We failed. Send an FB64_IV_BAD option
+ * to the other side so it will know that
+ * things failed.
+ */
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_BAD;
+ *p++ = IAC;
+ *p++ = SE;
+
+ ttol(fbp->fb_feed, p - fbp->fb_feed);
+ break;
+ }
+ return(fbp->state[DIR_DECRYPT-1] = state);
+}
+
+/*
+ * Returns:
+ * -1: some error. Negotiation is done, encryption not ready.
+ * 0: Successful, initial negotiation all done.
+ * 1: successful, negotiation not done yet.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_reply(data, cnt, &cast_fb[CFB_128]));
+}
+
+int
+cast_ofb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_reply(data, cnt, &cast_fb[OFB_128]));
+}
+#endif
+
+int
+castexp_cfb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_reply(data, cnt, &cast_fb[CFB_40]));
+}
+
+int
+castexp_ofb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(cast_fb64_reply(data, cnt, &cast_fb[OFB_40]));
+}
+
+static int
+cast_fb64_reply(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct cast_fb *fbp;
+{
+ int x;
+ unsigned char *p;
+ Block b;
+ register int state = fbp->state[DIR_ENCRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+ switch (*data++) {
+ case FB64_IV_OK:
+ cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ if (state == cFAILED)
+ state = IN_PROGRESS;
+ state &= ~NO_RECV_IV;
+ encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
+ break;
+
+ case FB64_IV_BAD:
+ memset(fbp->temp_feed, 0, sizeof(Block));
+ cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ state = cFAILED;
+ break;
+
+ default:
+#if 0
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", data[-1]);
+ printd(data, cnt);
+ printf("\r\n");
+ }
+#endif
+ /* FALL THROUGH */
+ failure:
+ state = cFAILED;
+ break;
+ }
+ return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(cast_fb64_session(key, server, &cast_fb[CFB_128], 1));
+}
+
+int
+cast_ofb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(cast_fb64_session(key, server, &cast_fb[OFB_128], 1));
+}
+#endif
+
+int
+castexp_cfb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(cast_fb64_session(key, server, &cast_fb[CFB_40], 0));
+}
+
+int
+castexp_ofb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ return(cast_fb64_session(key, server, &cast_fb[OFB_40], 0));
+}
+
+#define CAST128_KEYLEN 16 /* 128 bits */
+#define CAST5_40_KEYLEN 5 /* 40 bits */
+
+static int
+cast_fb64_session(key, server, fbp, fs)
+ Session_Key *key;
+ int server;
+ struct cast_fb *fbp;
+ int fs;
+{
+ int klen;
+ unsigned char * kptr;
+
+ if(fs)
+ klen = CAST128_KEYLEN;
+ else
+ klen = CAST5_40_KEYLEN;
+
+ if (!key || key->length < klen) {
+ CHAR buf[80];
+ sprintf((char *)buf,"Can't set CAST session key (%d < %d)",
+ key ? key->length : 0, klen); /* safe */
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("%s\r\n",buf);
+#endif
+ debug(F110,"cast_fb64_session",buf,0);
+ return(cFAILED);
+ }
+ if(key->length < 2 * klen)
+ kptr = key->data;
+ else
+ kptr = key->data + klen;
+
+ if(server) {
+ cast_fb64_stream_key(kptr, &fbp->streams[DIR_ENCRYPT-1], fs);
+ cast_fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1], fs);
+ }
+ else {
+ cast_fb64_stream_key(kptr, &fbp->streams[DIR_DECRYPT-1], fs);
+ cast_fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1], fs);
+ }
+
+ /* Stuff leftovers into the feed */
+ if(key->length >= 2 * klen + sizeof(Block))
+ memcpy(fbp->temp_feed, key->data + 2 * klen, sizeof(Block));
+ else {
+#ifdef COMMENT
+ /* This is a better way of erasing the password */
+ /* but we do not want to link in libsrp */
+ t_random(fbp->temp_feed, sizeof(Block));
+#else
+ memset(fbp->temp_feed, 0, sizeof(Block));
+#endif
+ }
+
+ fbp->key_isset = 1;
+ /*
+ * Now look to see if cast_fb64_start() was was waiting for
+ * the key to show up. If so, go ahead an call it now
+ * that we have the key.
+ */
+ if (fbp->need_start) {
+ fbp->need_start = 0;
+ cast_fb64_start(fbp, DIR_ENCRYPT, server);
+ }
+ return(0);
+}
+
+/*
+ * We only accept a keyid of 0. If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_128]));
+}
+
+int
+cast_ofb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_128]));
+}
+#endif
+
+int
+castexp_cfb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_40]));
+}
+
+int
+castexp_ofb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_40]));
+}
+
+static int
+cast_fb64_keyid(dir, kp, lenp, fbp)
+ int dir, *lenp;
+ unsigned char *kp;
+ struct cast_fb *fbp;
+{
+ register int state = fbp->state[dir-1];
+
+ if (*lenp != 1 || (*kp != '\0')) {
+ *lenp = 0;
+ return(state);
+ }
+
+ if (state == cFAILED)
+ state = IN_PROGRESS;
+
+ state &= ~NO_KEYID;
+
+ return(fbp->state[dir-1] = state);
+}
+
+static void
+cast_fb64_printsub(data, cnt, buf, buflen, type)
+ unsigned char *data, *buf, *type;
+ int cnt, buflen;
+{
+ char lbuf[64];
+ register int i;
+ char *cp;
+
+ buf[buflen-1] = '\0'; /* make sure it's NULL terminated */
+ buflen -= 1;
+
+ switch(data[2]) {
+ case FB64_IV:
+ sprintf(lbuf, "%s_IV", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_OK:
+ sprintf(lbuf, "%s_IV_OK", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_BAD:
+ sprintf(lbuf, "%s_IV_BAD", type);
+ cp = lbuf;
+ goto common;
+
+ default:
+ sprintf(lbuf, " %d (unknown)", data[2]);
+ cp = lbuf;
+ common:
+ for (; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ for (i = 3; i < cnt; i++) {
+ sprintf(lbuf, " %d", data[i]);
+ for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ }
+ break;
+ }
+}
+
+void
+cast_cfb64_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ cast_fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void
+cast_ofb64_printsub(data, cnt, buf, buflen)
+ unsigned char *data, *buf;
+ int cnt, buflen;
+{
+ cast_fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+
+static void
+cast_fb64_stream_iv(seed, stp)
+ Block seed;
+ register struct cast_stinfo *stp;
+{
+ memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block));
+ memcpy((void *)stp->str_output, (void *)seed, sizeof(Block));
+
+ stp->str_index = sizeof(Block);
+}
+
+static void
+cast_fb64_stream_key(key, stp, fs)
+ unsigned char * key;
+ register struct cast_stinfo *stp;
+ int fs;
+{
+#ifndef CAST_EXPORT_ENCRYPTION
+ if(fs)
+ ck_cast128_key_sched(&stp->str_sched, key);
+ else
+#endif
+ ck_cast5_40_key_sched(&stp->str_sched, key);
+
+ memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
+
+ stp->str_index = sizeof(Block);
+}
+
+/*
+ * CAST 64 bit Cipher Feedback
+ *
+ * key --->+------+
+ * +->| CAST |--+
+ * | +------+ |
+ * | v
+ * INPUT --(---------->(+)+---> DATA
+ * | |
+ * +--------------+
+ *
+ *
+ * Given:
+ * iV: Initial vector, 64 bits (8 bytes) long.
+ * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ * V0 = CAST(iV, key)
+ * On = Dn ^ Vn
+ * V(n+1) = CAST(On, key)
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+cast_cfb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ _cast_cfb64_encrypt(s, c, &cast_fb[CFB_128].streams[DIR_ENCRYPT-1]);
+}
+#endif
+
+void
+castexp_cfb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ _cast_cfb64_encrypt(s, c, &cast_fb[CFB_40].streams[DIR_ENCRYPT-1]);
+}
+
+static void
+_cast_cfb64_encrypt(s, c, stp)
+ register unsigned char *s;
+ int c;
+ register struct cast_stinfo *stp;
+{
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+ ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0);
+ memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+ index = 0;
+ }
+
+ /* On encryption, we store (feed ^ data) which is cypher */
+ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
+ s++;
+ index++;
+ }
+ stp->str_index = index;
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_cfb64_decrypt(data)
+ int data;
+{
+ return _cast_cfb64_decrypt(data, &cast_fb[CFB_128].streams[DIR_DECRYPT-1]);
+}
+#endif
+
+int
+castexp_cfb64_decrypt(data)
+ int data;
+{
+ return _cast_cfb64_decrypt(data, &cast_fb[CFB_40].streams[DIR_DECRYPT-1]);
+}
+
+static int
+_cast_cfb64_decrypt(data, stp)
+ int data;
+ register struct cast_stinfo *stp;
+{
+ int index;
+
+ if (data == -1) {
+ /*
+ * Back up one byte. It is assumed that we will
+ * never back up more than one byte. If we do, this
+ * may or may not work.
+ */
+ if (stp->str_index)
+ --stp->str_index;
+ return(0);
+ }
+
+ index = stp->str_index++;
+ if (index == sizeof(Block)) {
+ Block b;
+ ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0);
+ memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ /* On decryption we store (data) which is cypher. */
+ stp->str_output[index] = data;
+ return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * CAST 64 bit Output Feedback
+ *
+ * key --->+------+
+ * +->| CAST |--+
+ * | +------+ |
+ * +------------+
+ * v
+ * INPUT --------->(+) ----> DATA
+ *
+ * Given:
+ * iV: Initial vector, 64 bits (8 bytes) long.
+ * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ * V0 = CAST(iV, key)
+ * V(n+1) = CAST(Vn, key)
+ * On = Dn ^ Vn
+ */
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+cast_ofb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ _cast_ofb64_encrypt(s, c, &cast_fb[OFB_128].streams[DIR_ENCRYPT-1]);
+}
+#endif
+
+void
+castexp_ofb64_encrypt(s, c)
+ register unsigned char *s;
+ int c;
+{
+ _cast_ofb64_encrypt(s, c, &cast_fb[OFB_40].streams[DIR_ENCRYPT-1]);
+}
+
+static void
+_cast_ofb64_encrypt(s, c, stp)
+ register unsigned char *s;
+ int c;
+ register struct cast_stinfo *stp;
+{
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+ ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0);
+ memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+ index = 0;
+ }
+ *s++ ^= stp->str_feed[index];
+ index++;
+ }
+ stp->str_index = index;
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+int
+cast_ofb64_decrypt(data)
+ int data;
+{
+ return _cast_ofb64_decrypt(data, &cast_fb[OFB_128].streams[DIR_DECRYPT-1]);
+}
+#endif
+
+int
+castexp_ofb64_decrypt(data)
+ int data;
+{
+ return _cast_ofb64_decrypt(data, &cast_fb[OFB_40].streams[DIR_DECRYPT-1]);
+}
+
+static int
+_cast_ofb64_decrypt(data, stp)
+ int data;
+ register struct cast_stinfo *stp;
+{
+ int index;
+
+ if (data == -1) {
+ /*
+ * Back up one byte. It is assumed that we will
+ * never back up more than one byte. If we do, this
+ * may or may not work.
+ */
+ if (stp->str_index)
+ --stp->str_index;
+ return(0);
+ }
+
+ index = stp->str_index++;
+ if (index == sizeof(Block)) {
+ Block b;
+ ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0);
+ memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ return(data ^ stp->str_feed[index]);
+}
+
+/*
+ * Copyright (c) 1997 Stanford University
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * cast.c
+ * Author: Tom Wu
+ *
+ * An implementation of the CAST-128 encryption algorithm, as
+ * specified in RFC 2144.
+ */
+
+/* The first four S-boxes are for encryption/decryption */
+
+static uint32 S1[] = {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3,
+ 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675,
+ 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059,
+ 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b,
+ 0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de,
+ 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159,
+ 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f,
+ 0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,
+ 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2, 0x0c6e4f38,
+ 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493,
+ 0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a,
+ 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb,
+ 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14,
+ 0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6,
+ 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8,
+ 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495,
+ 0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e,
+ 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426,
+ 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98,
+ 0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f,
+ 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,0x7b5a41f0, 0xd37cfbad,
+ 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464,
+ 0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,
+ 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,0x3f04442f, 0x6188b153,
+ 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274,
+ 0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755,
+ 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,0x580304f0, 0xca042cf1,
+ 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1,
+ 0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79,
+ 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,0x474d6ad7, 0x7c0c5e5c,
+ 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff,
+ 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d,
+ 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+};
+
+static uint32 S2[] = {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a,
+ 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba,
+ 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605,
+ 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b,
+ 0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4,
+ 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083,
+ 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f,
+ 0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d,
+ 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e,
+ 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366,
+ 0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4,
+ 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064,
+ 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6,
+ 0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709,
+ 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364,
+ 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b,
+ 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9,
+ 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c,
+ 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741,
+ 0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab,
+ 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b,
+ 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa,
+ 0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8,
+ 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028,
+ 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6,
+ 0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b,
+ 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1,
+ 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb,
+ 0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea,
+ 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d,
+ 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e,
+ 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef,
+ 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
+};
+
+static uint32 S3[] = {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b,
+ 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae,
+ 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9,
+ 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd,
+ 0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e,
+ 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264,
+ 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e,
+ 0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f,
+ 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e,
+ 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790,
+ 0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504,
+ 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e,
+ 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8,
+ 0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d,
+ 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240,
+ 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c,
+ 0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15,
+ 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788,
+ 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa,
+ 0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392,
+ 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f,
+ 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae,
+ 0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67,
+ 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9,
+ 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888,
+ 0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d,
+ 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2,
+ 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2,
+ 0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce,
+ 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d,
+ 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00,
+ 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5,
+ 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
+};
+
+static uint32 S4[] = {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57,
+ 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120,
+ 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd,
+ 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe,
+ 0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701,
+ 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801,
+ 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1,
+ 0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,
+ 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3,
+ 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c,
+ 0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c,
+ 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16,
+ 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7,
+ 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327,
+ 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002,
+ 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7,
+ 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031,
+ 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff,
+ 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035,
+ 0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69,
+ 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec,
+ 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e,
+ 0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3,
+ 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6,
+ 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f,
+ 0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091,
+ 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6,
+ 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2,
+ 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367,
+ 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda,
+ 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6,
+ 0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e,
+ 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+};
+
+/* Encrypt/decrypt one 64-bit block of data */
+
+void
+ck_cast_ecb_encrypt(out, in, sched, mode)
+ uint8p out;
+ uint8p in;
+ CastKeySched * sched;
+ int mode; /* zero means encrypt */
+{
+ uint32 t[2];
+
+#ifdef LITTLE_ENDIAN
+ t[0] = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
+ t[1] = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | in[7];
+#else
+ t[0] = *(uint32p) in;
+ t[1] = *(uint32p) (in + 4);
+#endif
+
+ ck_cast_ecb_crypt(t, sched, mode);
+
+#ifdef LITTLE_ENDIAN
+ out[0] = (t[0] >> 24) & 0xff;
+ out[1] = (t[0] >> 16) & 0xff;
+ out[2] = (t[0] >> 8) & 0xff;
+ out[3] = t[0] & 0xff;
+ out[4] = (t[1] >> 24) & 0xff;
+ out[5] = (t[1] >> 16) & 0xff;
+ out[6] = (t[1] >> 8) & 0xff;
+ out[7] = t[1] & 0xff;
+#else
+ *(uint32p) out = t[0];
+ *(uint32p) (out + 4) = t[1];
+#endif
+}
+
+void
+ck_cast_ecb_crypt(data, sched, mode)
+ uint32p data;
+ CastKeySched * sched;
+ int mode;
+{
+ register uint32 L, R, temp;
+ register struct CastSubkeyPair * kp;
+ register uint8p Ia, Ib, Ic, Id;
+ uint32 I;
+
+#ifdef LITTLE_ENDIAN
+ Id = (uint8p) &I;
+ Ic = Id + 1;
+ Ib = Ic + 1;
+ Ia = Ib + 1;
+#else
+ Ia = (uint8p) &I;
+ Ib = Ia + 1;
+ Ic = Ib + 1;
+ Id = Ic + 1;
+#endif
+
+ L = data[0];
+ R = data[1];
+
+#define type0(left,right) \
+ temp = kp->Km + right;\
+ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\
+ left ^= ((S1[*Ia] ^ S2[*Ib]) - S3[*Ic]) + S4[*Id];
+
+#define type1(left,right) \
+ temp = kp->Km ^ right;\
+ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\
+ left ^= ((S1[*Ia] - S2[*Ib]) + S3[*Ic]) ^ S4[*Id];
+
+#define type2(left,right) \
+ temp = kp->Km - right;\
+ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\
+ left ^= ((S1[*Ia] + S2[*Ib]) ^ S3[*Ic]) - S4[*Id];
+
+ if(mode) {
+#ifndef CAST_EXPORT_ENCRYPTION
+ if(sched->ksize > 10) {
+ kp = &sched->K[15];
+ type0(L, R); --kp;
+ type2(R, L); --kp;
+ type1(L, R); --kp;
+ type0(R, L); --kp;
+ }
+ else
+#endif
+ kp = &sched->K[11];
+ type2(L, R); --kp;
+ type1(R, L); --kp;
+ type0(L, R); --kp;
+ type2(R, L); --kp;
+ type1(L, R); --kp;
+ type0(R, L); --kp;
+ type2(L, R); --kp;
+ type1(R, L); --kp;
+ type0(L, R); --kp;
+ type2(R, L); --kp;
+ type1(L, R); --kp;
+ type0(R, L);
+ }
+ else {
+ kp = &sched->K[0];
+ type0(L, R); ++kp;
+ type1(R, L); ++kp;
+ type2(L, R); ++kp;
+ type0(R, L); ++kp;
+ type1(L, R); ++kp;
+ type2(R, L); ++kp;
+ type0(L, R); ++kp;
+ type1(R, L); ++kp;
+ type2(L, R); ++kp;
+ type0(R, L); ++kp;
+ type1(L, R); ++kp;
+ type2(R, L); ++kp;
+#ifndef CAST_EXPORT_ENCRYPTION
+ if(sched->ksize > 10) {
+ type0(L, R); ++kp;
+ type1(R, L); ++kp;
+ type2(L, R); ++kp;
+ type0(R, L);
+ }
+#endif
+ }
+
+ data[0] = R;
+ data[1] = L;
+}
+
+/* The last four S-boxes are for key schedule setup */
+
+static uint32 S5[] = {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5,
+ 0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00,
+ 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, 0xe6a2e77f, 0xf0c720cd,
+ 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb,
+ 0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725,
+ 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, 0xf2f3f763, 0x68af8040,
+ 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2,
+ 0x2261be02, 0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec,
+ 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900, 0xfe38d399,
+ 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966,
+ 0xdfdd55bc, 0x29de0655, 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468,
+ 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9,
+ 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616,
+ 0xf24766e3, 0x8eca36c1, 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4,
+ 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419,
+ 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9,
+ 0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6,
+ 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, 0x0ab378d5, 0xd951fb0c,
+ 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715,
+ 0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6,
+ 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, 0x76f0ae02, 0x083be84d,
+ 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba,
+ 0x9cad9010, 0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487,
+ 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382, 0x175683f4,
+ 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c,
+ 0x1ad2fff3, 0x8c25404e, 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78,
+ 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87,
+ 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110,
+ 0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58,
+ 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3,
+ 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d,
+ 0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55,
+ 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
+};
+
+static uint32 S6[] = {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4,
+ 0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9,
+ 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, 0x33f14961, 0xc01937bd,
+ 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f,
+ 0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c,
+ 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, 0xfd41197e, 0x9305a6b0,
+ 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941,
+ 0x2c0e636a, 0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d,
+ 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89, 0xaa928223,
+ 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6,
+ 0x9a69a02f, 0x68818a54, 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a,
+ 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7,
+ 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89,
+ 0xfd339fed, 0xb87834bf, 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be,
+ 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0,
+ 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4,
+ 0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853,
+ 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, 0x36f73523, 0x4cfb6e87,
+ 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585,
+ 0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751,
+ 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, 0xbf32679d, 0xd45b5b75,
+ 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283,
+ 0x3cc2acfb, 0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459,
+ 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e, 0x74719eef,
+ 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0,
+ 0xbc60b42a, 0x953498da, 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb,
+ 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200,
+ 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf,
+ 0x3a479c3a, 0x5302da25, 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b,
+ 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869,
+ 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb,
+ 0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454,
+ 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
+};
+
+static uint32 S7[] = {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912,
+ 0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82,
+ 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, 0xa05fbcf6, 0xcd4181e9,
+ 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4,
+ 0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9,
+ 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, 0x107789be, 0xb3b2e9ce,
+ 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7,
+ 0xd0d854c0, 0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e,
+ 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288, 0xe1a5c06e,
+ 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9,
+ 0xc6e6fa14, 0xbae8584a, 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b,
+ 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3,
+ 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c,
+ 0x16746233, 0x3c034c28, 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802,
+ 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778,
+ 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be,
+ 0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858,
+ 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, 0xf28ebfb0, 0xf5b9c310,
+ 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476,
+ 0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df,
+ 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, 0xf22b017d, 0xa4173f70,
+ 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a,
+ 0x058745b9, 0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07,
+ 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c, 0x7154c24c,
+ 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e,
+ 0xe4f2dfa6, 0x693ed285, 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378,
+ 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e,
+ 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301,
+ 0xcfd2a87f, 0x60aeb767, 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2,
+ 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4,
+ 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021,
+ 0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada,
+ 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
+};
+
+static uint32 S8[] = {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b,
+ 0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174,
+ 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, 0xde9adeb1, 0x0a0cc32c,
+ 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7,
+ 0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164,
+ 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, 0x12a8ddec, 0xfdaa335d,
+ 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8,
+ 0x57e8726e, 0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6,
+ 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049, 0x2998df04,
+ 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38,
+ 0x424f7618, 0x35856039, 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8,
+ 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354,
+ 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160,
+ 0x7895cda5, 0x859c15a5, 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab,
+ 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2,
+ 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98,
+ 0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441,
+ 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, 0xa842eedf, 0xfdba60b4,
+ 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5,
+ 0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c,
+ 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, 0x77853b53, 0x37effcb5,
+ 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b,
+ 0xc4248289, 0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4,
+ 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4, 0xe98ea084,
+ 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a,
+ 0xe0779695, 0xf9c17a8f, 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf,
+ 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77,
+ 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f,
+ 0xdf09822b, 0xbd691a6c, 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819,
+ 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3,
+ 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1,
+ 0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d,
+ 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
+};
+
+/* Initialize a key schedule from a 128-bit key */
+
+static void
+cast_key_sched(sched, key)
+ CastKeySched * sched;
+ uint8p key;
+{
+ uint8p x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF;
+ uint8p z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF;
+ uint32 X03, X47, X8B, XCF, Z03, Z47, Z8B, ZCF;
+
+#ifdef LITTLE_ENDIAN
+ x3 = (uint8p) &X03; x2 = x3 + 1; x1 = x2 + 1; x0 = x1 + 1;
+ x7 = (uint8p) &X47; x6 = x7 + 1; x5 = x6 + 1; x4 = x5 + 1;
+ xB = (uint8p) &X8B; xA = xB + 1; x9 = xA + 1; x8 = x9 + 1;
+ xF = (uint8p) &XCF; xE = xF + 1; xD = xE + 1; xC = xD + 1;
+ z3 = (uint8p) &Z03; z2 = z3 + 1; z1 = z2 + 1; z0 = z1 + 1;
+ z7 = (uint8p) &Z47; z6 = z7 + 1; z5 = z6 + 1; z4 = z5 + 1;
+ zB = (uint8p) &Z8B; zA = zB + 1; z9 = zA + 1; z8 = z9 + 1;
+ zF = (uint8p) &ZCF; zE = zF + 1; zD = zE + 1; zC = zD + 1;
+#else
+ x0 = (uint8p) &X03; x1 = x0 + 1; x2 = x1 + 1; x3 = x2 + 1;
+ x4 = (uint8p) &X47; x5 = x4 + 1; x6 = x5 + 1; x7 = x6 + 1;
+ x8 = (uint8p) &X8B; x9 = x8 + 1; xA = x9 + 1; xB = xA + 1;
+ xC = (uint8p) &XCF; xD = xC + 1; xE = xD + 1; xF = xE + 1;
+ z0 = (uint8p) &Z03; z1 = z0 + 1; z2 = z1 + 1; z3 = z2 + 1;
+ z4 = (uint8p) &Z47; z5 = z4 + 1; z6 = z5 + 1; z7 = z6 + 1;
+ z8 = (uint8p) &Z8B; z9 = z8 + 1; zA = z9 + 1; zB = zA + 1;
+ zC = (uint8p) &ZCF; zD = zC + 1; zE = zD + 1; zF = zE + 1;
+#endif
+
+#ifdef LITTLE_ENDIAN
+ *x0 = key[0];
+ *x1 = key[1];
+ *x2 = key[2];
+ *x3 = key[3];
+ *x4 = key[4];
+ *x5 = key[5];
+ *x6 = key[6];
+ *x7 = key[7];
+ *x8 = key[8];
+ *x9 = key[9];
+ *xA = key[10];
+ *xB = key[11];
+ *xC = key[12];
+ *xD = key[13];
+ *xE = key[14];
+ *xF = key[15];
+#else
+ X03 = *(uint32p) key;
+ X47 = *(uint32p) (key + 4);
+ X8B = *(uint32p) (key + 8);
+ XCF = *(uint32p) (key + 12);
+#endif
+
+ /* First half of key schedule */
+
+ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+ Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+ Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+ ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+ sched->K[0].Km = S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2];
+ sched->K[1].Km = S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6];
+ sched->K[2].Km = S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9];
+ sched->K[3].Km = S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC];
+
+ X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+ X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+ X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+ XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+ sched->K[4].Km = S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8];
+ sched->K[5].Km = S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD];
+ sched->K[6].Km = S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3];
+ sched->K[7].Km = S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7];
+
+ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+ Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+ Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+ ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+ sched->K[8].Km = S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9];
+ sched->K[9].Km = S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC];
+ sched->K[10].Km = S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2];
+ sched->K[11].Km = S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6];
+
+ X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+ X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+ X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+ XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+ sched->K[12].Km = S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3];
+ sched->K[13].Km = S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7];
+ sched->K[14].Km = S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8];
+ sched->K[15].Km = S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD];
+
+ /* Second half of key schedule - just like first half */
+
+ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+ Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+ Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+ ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+ sched->K[0].Kr = (S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2]) & 0x1f;
+ sched->K[1].Kr = (S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6]) & 0x1f;
+ sched->K[2].Kr = (S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9]) & 0x1f;
+ sched->K[3].Kr = (S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC]) & 0x1f;
+
+ X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+ X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+ X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+ XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+ sched->K[4].Kr = (S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8]) & 0x1f;
+ sched->K[5].Kr = (S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD]) & 0x1f;
+ sched->K[6].Kr = (S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3]) & 0x1f;
+ sched->K[7].Kr = (S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7]) & 0x1f;
+
+ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8];
+ Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA];
+ Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9];
+ ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB];
+
+ sched->K[8].Kr = (S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9]) & 0x1f;
+ sched->K[9].Kr = (S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC]) & 0x1f;
+ sched->K[10].Kr = (S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2]) & 0x1f;
+ sched->K[11].Kr = (S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6]) & 0x1f;
+
+ X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0];
+ X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2];
+ X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1];
+ XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3];
+
+ sched->K[12].Kr = (S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3]) & 0x1f;
+ sched->K[13].Kr = (S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7]) & 0x1f;
+ sched->K[14].Kr = (S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8]) & 0x1f;
+ sched->K[15].Kr = (S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD]) & 0x1f;
+}
+
+/* Initialize with a full-strength 128-bit key */
+
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+ck_cast128_key_sched(sched, key)
+ CastKeySched * sched;
+ uint8 * key;
+{
+ sched->ksize = 16;
+ cast_key_sched(sched, key);
+}
+#endif
+
+/* Handle reduced-keysize variants */
+
+static void
+cast5_key_sched(sched, key, sz)
+ CastKeySched * sched;
+ uint8 * key;
+ int sz;
+{
+ uint8 buf[16];
+
+ sched->ksize = sz;
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, key, sz);
+ cast_key_sched(sched, buf);
+}
+
+/* 40, 64, and 80-bit keys - all use 12 rounds */
+
+void
+ck_cast5_40_key_sched(sched, key)
+ CastKeySched * sched;
+ uint8 * key;
+{
+ cast5_key_sched(sched, key, 5);
+}
+
+#ifndef CAST_EXPORT_ENCRYPTION
+void
+ck_cast5_64_key_sched(sched, key)
+ CastKeySched * sched;
+ uint8 * key;
+{
+ cast5_key_sched(sched, key, 8);
+}
+
+void
+ck_cast5_80_key_sched(sched, key)
+ CastKeySched * sched;
+ uint8 * key;
+{
+ cast5_key_sched(sched, key, 10);
+}
+#endif /* CAST_EXPORT_ENCRYPTION */
+#endif /* CK_CAST */
+
+#ifdef CRYPT_DLL
+static char *
+ck_crypt_dll_version()
+{
+ return(ckcrpv);
+}
+
+int
+crypt_dll_init( struct _crypt_dll_init * init )
+{
+#ifdef LIBDES
+ extern int des_check_key;
+ extern void libdes_dll_init(struct _crypt_dll_init *);
+ des_check_key = 1;
+#endif /* LIBDES */
+
+ if ( init->version >= 1 ) {
+ p_ttol = init->p_ttol;
+ p_dodebug = init->p_dodebug;
+ p_dohexdump = init->p_dohexdump;
+ p_tn_debug = init->p_tn_debug;
+ p_vscrnprintf = init->p_vscrnprintf;
+ if ( init->version == 1 )
+ return(1);
+ }
+ if ( init->version >= 2 ) {
+ /* This is a k5_context but we don't want to include krb5.h */
+ p_k5_context = (void *) init->p_k5_context;
+ if ( init->version == 2 )
+ return(1);
+ }
+ if ( init->version >= 3 ) {
+ init->p_install_funcs("encrypt_parse",encrypt_parse);
+ init->p_install_funcs("encrypt_init",encrypt_init);
+ init->p_install_funcs("encrypt_session_key",encrypt_session_key);
+ init->p_install_funcs("encrypt_send_request_start",
+ encrypt_send_request_start
+ );
+ init->p_install_funcs("encrypt_request_start",encrypt_request_start);
+ init->p_install_funcs("encrypt_send_request_end",
+ encrypt_send_request_end
+ );
+ init->p_install_funcs("encrypt_request_end",encrypt_request_end);
+ init->p_install_funcs("encrypt_send_end",encrypt_send_end);
+ init->p_install_funcs("encrypt_send_support",encrypt_send_support);
+ init->p_install_funcs("encrypt_is_encrypting",encrypt_is_encrypting);
+ init->p_install_funcs("encrypt_is_decrypting",encrypt_is_decrypting);
+ init->p_install_funcs("get_crypt_table",get_crypt_table);
+ init->p_install_funcs("des_is_weak_key",ck_des_is_weak_key);
+ libdes_dll_init(init);
+ if (init->version == 3)
+ return(1);
+ }
+ if ( init->version >= 4 ) {
+ init->p_install_funcs("crypt_dll_version",ck_crypt_dll_version);
+ if (init->version == 4)
+ return(1);
+ }
+
+ if ( init->version >= 5 ) {
+ p_reqtelmutex = init->p_reqtelmutex;
+ p_reltelmutex = init->p_reltelmutex;
+ if (init->version == 5)
+ return(1);
+ }
+
+ if ( init->version >= 6 ) {
+ init->p_install_funcs("encrypt_dont_support",encrypt_dont_support);
+ if ( init->version == 6 )
+ return(1);
+ /* when adding new versions; migrate the next two lines */
+ init->version = 6;
+ return(1);
+ }
+ return(0);
+}
+
+#undef malloc
+#undef realloc
+#undef free
+#undef strdup
+
+static void
+fatal(char *msg) {
+ if (!msg) msg = "";
+
+ printf(msg);
+ exit(1); /* Exit indicating failure */
+}
+
+void *
+kmalloc(size_t size)
+{
+ void *ptr;
+
+ if (size == 0) {
+ fatal("kmalloc: zero size");
+ }
+ ptr = malloc(size);
+ if (ptr == NULL) {
+ fatal("kmalloc: out of memory");
+ }
+ return ptr;
+}
+
+void *
+krealloc(void *ptr, size_t new_size)
+{
+ void *new_ptr;
+
+ if (new_size == 0) {
+ fatal("krealloc: zero size");
+ }
+ if (ptr == NULL)
+ new_ptr = malloc(new_size);
+ else
+ new_ptr = realloc(ptr, new_size);
+ if (new_ptr == NULL) {
+ fatal("krealloc: out of memory");
+ }
+ return new_ptr;
+}
+
+void
+kfree(void *ptr)
+{
+ if (ptr == NULL) {
+ printf("kfree: NULL pointer given as argument");
+ return;
+ }
+ free(ptr);
+}
+
+char *
+kstrdup(const char *str)
+{
+ size_t len;
+ char *cp;
+
+ if (str == NULL) {
+ fatal("kstrdup: NULL pointer given as argument");
+ }
+ len = strlen(str) + 1;
+ cp = kmalloc(len);
+ if (cp)
+ memcpy(cp, str, len);
+ return cp;
+}
+#endif /* CRYPT_DLL */
+#endif /* CK_ENCRYPTION */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ck_des.c b/ckermit-9.0.302-build/ckermit-9.0.302/ck_des.c
new file mode 100644
index 0000000..c534652
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ck_des.c
@@ -0,0 +1,98 @@
+/*
+ C K _ D E S . C - libDES interface for Kermit 95"
+
+ Copyright (C) 1998, 2001, Trustees of Columbia University in the City of New
+ York. The C-Kermit software may not be, in whole or in part, licensed or
+ sold for profit as a software product itself, nor may it be included in or
+ distributed with commercial products or otherwise distributed by commercial
+ concerns to their clients or customers without written permission of the
+ Office of Kermit Development and Distribution, Columbia University. This
+ copyright notice must not be removed, altered, or obscured.
+
+ Author:
+ Jeffrey E Altman (jaltman@secure-endpoints.com)
+*/
+
+/*
+ This file contains wrappers so that the following functions will be imported
+ into the k95crypt.dll/k2crypt.dll files in such a form that they can be
+ re-exported to k95.exe/k2.exe. This subset of the DES library is needed to
+ provide DES based Kerberos authentication.
+*/
+
+
+#ifdef LIBDES
+/* The following is specific to my installation, but since I'm the only one */
+/* that uses this file ... */
+#include "ckcdeb.h"
+#include "ckuath.h"
+#define CK_DES_C
+#include "ckuat2.h"
+#ifdef NT
+#ifdef _M_ALPHA
+#include <c:\srp\des\des.h>
+#else
+#include <c:\src\srp\des\des.h>
+#endif
+#else
+#include <c:\srp\des\des.h>
+#endif
+
+int
+libdes_random_key(des_cblock B)
+{
+ des_random_key(B);
+ return(0);
+}
+
+void
+libdes_random_seed(des_cblock B)
+{
+ des_random_seed(B);
+}
+
+void
+libdes_key_sched(des_cblock * B, des_key_schedule S)
+{
+ des_key_sched(B,S);
+}
+
+void
+libdes_ecb_encrypt(des_cblock * B1, des_cblock * B2, des_key_schedule S, int n)
+{
+ des_ecb_encrypt(B1,B2,S,n);
+}
+
+int
+libdes_string_to_key(char * s, des_cblock * B)
+{
+ des_string_to_key(s,B);
+ return(0);
+}
+
+void
+libdes_fixup_key_parity(des_cblock * B)
+{
+ des_set_odd_parity(B);
+}
+
+void
+libdes_pcbc_encrypt(des_cblock *input, des_cblock *output, long length,
+ des_key_schedule schedule, des_cblock *ivec, int enc)
+{
+ des_pcbc_encrypt(input,output,length,schedule,ivec,enc);
+}
+
+void
+libdes_dll_init(struct _crypt_dll_init * init)
+{
+ init->p_install_funcs("libdes_random_key",libdes_random_key);
+ init->p_install_funcs("libdes_random_seed",libdes_random_seed);
+ init->p_install_funcs("libdes_key_sched",libdes_key_sched);
+ init->p_install_funcs("libdes_ecb_encrypt",libdes_ecb_encrypt);
+ init->p_install_funcs("libdes_string_to_key",libdes_string_to_key);
+ init->p_install_funcs("libdes_fixup_key_parity",libdes_fixup_key_parity);
+ init->p_install_funcs("libdes_pcbc_encrypt",libdes_pcbc_encrypt);
+
+}
+#endif /* LIBDES */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ck_ssl.c b/ckermit-9.0.302-build/ckermit-9.0.302/ck_ssl.c
new file mode 100644
index 0000000..428fb7c
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ck_ssl.c
@@ -0,0 +1,4358 @@
+char *cksslv = "SSL/TLS support, 9.0.227, 04 Aug 2010";
+/*
+ C K _ S S L . C -- OpenSSL Interface for C-Kermit
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Author: Jeffrey E Altman (jaltman@secure-endpoints.com)
+ Secure Endpoints Inc., New York City
+
+ Provides:
+
+ . Telnet Auth SSL option compatible with Tim Hudson's hack.
+ . Telnet START_TLS option
+ . Configuration of certificate and key files
+ . Certificate verification and revocation list checks
+ . Client certificate to user id routine
+
+ Note: This code is written to be compatible with OpenSSL 0.9.6[abcdefgh]
+ and 0.9.7 beta 5 (and, presumably, later).
+ It will also compile with version 0.9.5 although that is discouraged
+ due to security weaknesses in that release.
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+
+#ifdef CK_SSL
+#include "ckcnet.h"
+#include "ckuath.h"
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef UNIX
+#include <netinet/in.h>
+#ifndef FREEBSD4
+#include <arpa/inet.h>
+#endif /* FREEBSD4 */
+#endif /* UNIX */
+
+#ifdef DEC_TCPIP
+#include <time.h>
+#include <inet.h>
+#endif /* DEC_TCPIP */
+
+#ifdef OS2
+extern char exedir[];
+#ifdef NT
+char * GetAppData(int);
+#endif
+#endif /* OS2 */
+
+extern int quiet; /* fdc - Mon Nov 28 11:44:15 2005 */
+
+static int ssl_installed = 1;
+#endif /* CK_SSL */
+int
+ck_ssh_is_installed()
+{
+#ifdef SSHBUILTIN
+#ifdef SSLDLL
+#ifdef NT
+ extern HINSTANCE hCRYPTO;
+#else /* NT */
+ extern HMODULE hCRYPTO;
+#endif /* NT */
+ debug(F111,"ck_ssh_is_installed","hCRYPTO",hCRYPTO);
+ return(ssl_installed && (hCRYPTO != NULL));
+#else /* SSLDLL */
+ return(ssl_installed);
+#endif /* SSLDLL */
+#else
+ return 0;
+#endif
+}
+
+int
+#ifdef CK_ANSIC
+ck_ssleay_is_installed(void)
+#else
+ck_ssleay_is_installed()
+#endif
+{
+#ifdef CK_SSL
+#ifdef SSLDLL
+#ifdef NT
+ extern HINSTANCE hSSL, hCRYPTO;
+#else /* NT */
+ extern HMODULE hSSL, hCRYPTO;
+#endif /* NT */
+ debug(F111,"ck_ssleay_is_installed","hSSL",hSSL);
+ debug(F111,"ck_ssleay_is_installed","hCRYPTO",hCRYPTO);
+ return(ssl_installed && (hSSL != NULL) && (hCRYPTO != NULL));
+#else /* SSLDLL */
+ return(ssl_installed);
+#endif /* SSLDLL */
+#else /* CK_SSL */
+ return(0);
+#endif /* CK_SSL */
+}
+
+#ifdef CK_SSL
+#include "ckcker.h"
+#include "ckucmd.h" /* For struct keytab */
+#include "ckctel.h"
+#include "ck_ssl.h"
+#ifdef UNIX
+#include <pwd.h> /* Password file for home directory */
+#endif /* UNIX */
+#ifdef OS2
+#include <process.h>
+#endif /* OS2 */
+#ifdef OS2ONLY
+#include "ckotcp.h"
+#endif /* OS2ONLY */
+
+#ifdef SSLDLL
+int ssl_finished_messages = 0;
+#else /* SSLDLL */
+#ifdef OPENSSL_VERSION_NUMBER
+int ssl_finished_messages = (OPENSSL_VERSION_NUMBER >= 0x0090581fL);
+#else
+!ERROR This module requires OpenSSL 0.9.5a or higher
+#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* SSLDLL */
+
+static int auth_ssl_valid = 0;
+static char *auth_ssl_name = 0; /* this holds the oneline name */
+char ssl_err[SSL_ERR_BFSZ]="";
+
+BIO *bio_err=NULL;
+X509_STORE *crl_store = NULL;
+
+#ifndef NOFTP
+#ifndef SYSFTP
+SSL *ssl_ftp_con = NULL;
+SSL_CTX *ssl_ftp_ctx = NULL;
+SSL *ssl_ftp_data_con = NULL;
+int ssl_ftp_active_flag = 0;
+int ssl_ftp_data_active_flag = 0;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+#ifndef NOHTTP
+SSL *tls_http_con = NULL;
+SSL_CTX *tls_http_ctx = NULL;
+int tls_http_active_flag = 0;
+int ssl_http_initialized = 0;
+#endif /* NOHTTP */
+
+SSL_CTX *ssl_ctx = NULL;
+SSL *ssl_con = NULL;
+int ssl_debug_flag = 0;
+int ssl_verbose_flag = 0;
+int ssl_only_flag = 0;
+int ssl_raw_flag = 0;
+int ssl_active_flag = 0;
+int ssl_verify_flag = SSL_VERIFY_PEER;
+int ssl_certsok_flag = 0;
+char *ssl_rsa_cert_file = NULL;
+char *ssl_rsa_cert_chain_file = NULL;
+char *ssl_rsa_key_file = NULL;
+char *ssl_dsa_cert_file = NULL;
+char *ssl_dsa_cert_chain_file = NULL;
+char *ssl_dh_key_file = NULL;
+char *ssl_crl_file = NULL;
+char *ssl_crl_dir = NULL;
+char *ssl_verify_file = NULL;
+char *ssl_verify_dir = NULL;
+char *ssl_dh_param_file = NULL;
+char *ssl_cipher_list = NULL;
+char *ssl_rnd_file = NULL;
+
+SSL_CTX *tls_ctx = NULL;
+SSL *tls_con = NULL;
+int tls_only_flag = 0;
+int tls_raw_flag = 0;
+int tls_active_flag = 0;
+
+int ssl_initialized = 0;
+int ssl_verify_depth = -1; /* used to track depth in verify routines */
+
+/* compile this set to 1 to negotiate SSL/TLS but not actually start it */
+int ssl_dummy_flag=0;
+
+extern int inserver;
+extern int debses;
+extern int accept_complete;
+extern char szHostName[], szUserNameRequested[], szUserNameAuthenticated[];
+
+_PROTOTYP(int X509_to_user,(X509 *, char *, int));
+
+static int verbosity = 0; /* Message control */
+static VOID
+setverbosity() {
+ verbosity = ssl_verbose_flag;
+ if (quiet) verbosity = 0;
+}
+
+int
+#ifdef CK_ANSIC
+ssl_server_verify_callback(int ok, X509_STORE_CTX * ctx)
+#else /* CK_ANSIC */
+ssl_server_verify_callback(ok, ctx)
+int ok;
+X509_STORE_CTX *ctx;
+#endif /* CK_ANSIC */
+{
+ static char *saved_subject=NULL;
+ char *subject=NULL, *issuer=NULL;
+ int depth,error;
+ X509 *xs = NULL;
+
+ if ( ssl_certsok_flag )
+ return(1);
+
+ setverbosity();
+
+ error=X509_STORE_CTX_get_error(ctx);
+ depth=X509_STORE_CTX_get_error_depth(ctx);
+ xs=X509_STORE_CTX_get_current_cert(ctx);
+
+ if (depth==0) {
+ /* clear things */
+ if (saved_subject!=NULL) {
+ free(saved_subject);
+ saved_subject=NULL;
+ }
+ if (auth_ssl_name!=NULL) {
+ free(auth_ssl_name);
+ auth_ssl_name=NULL;
+ }
+ }
+
+
+ if (ssl_debug_flag && !inserver) {
+ printf("ssl:server_verify_callback:depth=%d ok=%d err=%d-%s\r\n",
+ depth,ok,error,X509_verify_cert_error_string(error));
+ }
+
+ /* first thing is to have a meaningful name for the current
+ * certificate that is being verified ... and if we cannot
+ * determine that then something is seriously wrong!
+ */
+ makestr(&subject,
+ (char *)X509_NAME_oneline(X509_get_subject_name(xs),NULL,0));
+ makestr(&issuer,
+ (char *)X509_NAME_oneline(X509_get_issuer_name(xs),NULL,0));
+ if (!subject || !subject[0] || !issuer || !issuer[0]) {
+ ok = 0;
+ goto return_time;
+ }
+
+ if (verbosity && !inserver && depth != ssl_verify_depth) {
+ printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject);
+ printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer);
+ ssl_verify_depth = depth;
+ }
+
+ /* make sure that the certificate that has been presented */
+ /* has not been revoked (if we have been given a CRL. */
+ ok = ssl_verify_crl(ok, ctx);
+
+ /* if we have any form of error in secure mode we reject the connection */
+ if (error!=X509_V_OK) {
+ if (inserver) {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ cksyslog(SYSLG_LI, 0,
+ "X.509 Certificate verify failure",
+ (char *) subject,
+ (char *)X509_verify_cert_error_string(error)
+ );
+ }
+#endif /* CKSYSLOG */
+
+ } else {
+ if ( ssl_verify_flag &
+ (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+ printf("Error: ");
+ else
+ printf("Warning: ");
+ switch (error) {
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ printf("Certificate is self signed.\r\n");
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ printf("Certificate has expired.\r\n");
+ break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ printf(
+ "Certificate issuer's certificate isn't available locally.\r\n");
+ break;
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ printf("Unable to verify leaf signature.\r\n");
+ break;
+ case X509_V_ERR_CERT_REVOKED:
+ printf("Certificate revoked.\r\n");
+ break;
+ default:
+ printf("Error %d while verifying certificate.\r\n",
+ ctx->error);
+ break;
+ }
+ }
+ ok = !(ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+ } else {
+ /* if we got all the way to the top of the tree then
+ * we *can* use this certificate for a username to
+ * match ... in all other cases we must not!
+ */
+ auth_ssl_name = saved_subject;
+ saved_subject = NULL;
+ }
+
+ return_time:
+
+ /* save the name if at least the first level is okay */
+ if (depth == 0 && ok)
+ makestr(&saved_subject,subject);
+
+ /* clean up things */
+ if (subject!=NULL)
+ free(subject);
+ if (issuer!=NULL)
+ free(issuer);
+
+ return ok;
+}
+
+int
+#ifdef CK_ANSIC
+ssl_client_verify_callback(int ok, X509_STORE_CTX * ctx)
+#else
+ssl_client_verify_callback(ok, ctx)
+int ok;
+X509_STORE_CTX *ctx;
+#endif
+{
+ char subject[256]="", issuer[256]="";
+ int depth, error, len;
+ X509 *xs;
+
+ setverbosity();
+
+ xs=X509_STORE_CTX_get_current_cert(ctx);
+ error=X509_STORE_CTX_get_error(ctx);
+ depth=X509_STORE_CTX_get_error_depth(ctx);
+
+ if ( ssl_debug_flag )
+ printf("ssl:client_verify_callback:depth=%d ok=%d err=%d-%s\r\n",
+ depth,ok,error,X509_verify_cert_error_string(error));
+
+ if ( ssl_certsok_flag ) {
+ ok = 1;
+ }
+
+ /* first thing is to have a meaningful name for the current
+ * certificate that is being verified ... and if we cannot
+ * determine that then something is seriously wrong!
+ */
+#ifdef XN_FLAG_SEP_MULTILINE
+ X509_NAME_print_ex(bio_err,X509_get_subject_name(xs),4,
+ XN_FLAG_SEP_MULTILINE);
+ len = BIO_read(bio_err,subject,256);
+ subject[len < 256 ? len : 255] = '\0';
+ if (!subject[0]) {
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0);
+ ok=0;
+ goto return_time;
+ }
+
+ X509_NAME_print_ex(bio_err,X509_get_issuer_name(xs),4,
+ XN_FLAG_SEP_MULTILINE);
+ len = BIO_read(bio_err,issuer,256);
+ issuer[len < 256 ? len : 255] = '\0';
+ if (!issuer[0]) {
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0);
+ ok=0;
+ goto return_time;
+ }
+#else /* XN_FLAG_SEP_MULTILINE */
+ X509_NAME_oneline(X509_get_subject_name(xs),subject,256);
+ if (!subject[0]) {
+ int len;
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0);
+ ok=0;
+ goto return_time;
+ }
+
+ X509_NAME_oneline(X509_get_issuer_name(xs),issuer,256);
+ if (!issuer[0]) {
+ int len;
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0);
+ ok=0;
+ goto return_time;
+ }
+#endif /* XN_FLAG_SEP_MULTILINE */
+
+ if (verbosity && depth != ssl_verify_depth) {
+ printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject);
+ printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer);
+ ssl_verify_depth = depth;
+ }
+
+ ok = ssl_verify_crl(ok, ctx);
+
+ if ( !ok ) {
+ char prefix[1024];
+ /* if the server is using a self signed certificate then
+ * we need to decide if that is good enough for us to
+ * accept ...
+ */
+
+ switch ( error ) {
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: {
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ /* make 100% sure that in secure more we drop the
+ * connection if the server does not have a
+ * real certificate!
+ */
+ ckmakxmsg(prefix,1024,
+ "Error: Server has a self-signed certificate\n",
+ "[",ckitoa(depth),"] Certificate Subject=\n",subject,
+ "\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer,
+ NULL,NULL,NULL);
+
+ uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+ /* sometimes it is really handy to be able to debug things
+ * and still get a connection!
+ */
+ if (ssl_debug_flag) {
+ printf("SSL: debug -> ignoring cert required!\r\n");
+ ok=1;
+ } else {
+ ok=0;
+ }
+ goto return_time;
+ } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+ ckmakxmsg(prefix,1024,
+ "Warning: Server has a self-signed certificate\n",
+ "[",ckitoa(depth),"] Certificate Subject=\n",subject,
+ "\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer,
+ NULL,NULL,NULL);
+
+ ok = uq_ok(prefix,
+ "Continue? (Y/N) ",
+ 3, NULL, 0);
+ if ( ok < 0 )
+ ok = 0;
+ goto return_time;
+ }
+ }
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ /* make 100% sure that in secure more we drop the
+ * connection if the server does not have a
+ * real certificate!
+ */
+ ckmakxmsg(prefix,1024,
+ "Error: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Issuer=\n",issuer,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+ /* sometimes it is really handy to be able to debug things
+ * and still get a connection!
+ */
+ if (ssl_debug_flag) {
+ printf("SSL: debug -> ignoring cert required!\r\n");
+ ok=1;
+ } else {
+ ok=0;
+ }
+ goto return_time;
+ } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+ ckmakxmsg(prefix,1024,
+ "Warning: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Issuer=\n",issuer,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+ goto return_time;
+ }
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ int len;
+ /* make 100% sure that in secure more we drop the
+ * connection if the server does not have a
+ * real certificate!
+ */
+ ASN1_TIME_print(bio_err,X509_get_notBefore(xs));
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ ckmakxmsg(prefix,1024,
+ "Error: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Subject=\n",subject,
+ "\nnotBefore=",ssl_err,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+ /* sometimes it is really handy to be able to debug things
+ * and still get a connection!
+ */
+ if (ssl_debug_flag) {
+ printf("SSL: debug -> ignoring cert required!\r\n");
+ ok=1;
+ } else {
+ ok=0;
+ }
+ goto return_time;
+ } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+ int len;
+ ASN1_TIME_print(bio_err,X509_get_notBefore(xs));
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ ckmakxmsg(prefix,1024,
+ "Warning: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Subject=\n",subject,
+ "\n notBefore=",ssl_err,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+ }
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ int len;
+ /* make 100% sure that in secure more we drop the
+ * connection if the server does not have a
+ * real certificate!
+ */
+ ASN1_TIME_print(bio_err,X509_get_notAfter(xs));
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+
+ ckmakxmsg(prefix,1024,
+ "Error: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Subject=\n",subject,
+ "\n notAfter=",ssl_err,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+ /* sometimes it is really handy to be able to debug things
+ * and still get a connection!
+ */
+ if (ssl_debug_flag) {
+ printf("SSL: debug -> ignoring cert required!\r\n");
+ ok=1;
+ } else {
+ ok=0;
+ }
+ goto return_time;
+ } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+ int len;
+ ASN1_TIME_print(bio_err,X509_get_notAfter(xs));
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ ckmakxmsg(prefix,1024,
+ "Warning: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Subject=\n",subject,
+ "\n notAfter=",ssl_err,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+ }
+ break;
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ /*
+ * When an SSL server sends its certificates to the client there
+ * are two" conventions": one is to send the complete certificate
+ * chain and the other is to send the whole chain apart from the
+ * root.
+ *
+ * You don't usually need the root because the root is normally
+ * stored and trusted locally.
+ *
+ * So if you get the whole chain it will complain about the self
+ * signed certificate whereas if the root is missing it says it
+ * can't find the issuer certificate.
+ */
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ /* make 100% sure that in secure more we drop the
+ * connection if the server does not have a
+ * real certificate!
+ */
+ ckmakxmsg(prefix,1024,
+ "Error: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Issuer=\n",issuer,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+ /* sometimes it is really handy to be able to debug things
+ * and still get a connection!
+ */
+ if (ssl_debug_flag) {
+ printf("SSL: debug -> ignoring cert required!\r\n");
+ ok=1;
+ } else {
+ ok=0;
+ }
+ goto return_time;
+ } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+ ckmakxmsg(prefix,1024,
+ "Warning: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Issuer=\n",issuer,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+#ifdef NT
+ if (ok) {
+ /* if the user decides to accept the certificate
+ * offer to store it for future connections in
+ * the user's private store
+ */
+ ok = uq_ok(
+ "Do you wish to store the certificate to verify future connections?",
+ "Continue (Y/N)", 3, NULL, 0);
+ if (ok)
+ ck_X509_save_cert_to_user_store(xs);
+ }
+#endif /* NT */
+ }
+ break;
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_CERT_REVOKED:
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ default:
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ /* make 100% sure that in secure mode we drop the
+ * connection if the server does not have a
+ * real certificate!
+ */
+ ckmakxmsg(prefix,1024,
+ "Error: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Subject=\n",subject,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
+
+ /* sometimes it is really handy to be able to debug things
+ * and still get a connection!
+ */
+ if (ssl_debug_flag) {
+ printf("SSL: debug -> ignoring cert required!\r\n");
+ ok=1;
+ } else {
+ ok=0;
+ }
+ goto return_time;
+ } else if (ssl_verify_flag != SSL_VERIFY_NONE) {
+ ckmakxmsg(prefix,1024,
+ "Warning: ",
+ (char *)X509_verify_cert_error_string(error),
+ "\nCertificate Subject=\n",subject,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
+ }
+ break;
+ }
+ }
+
+ return_time:
+ if ( ssl_debug_flag )
+ printf("ssl:client_verify_callback => ok: %d\r\n",ok);
+ return ok;
+}
+
+VOID
+#ifdef CK_ANSIC
+ssl_client_info_callback(const SSL *s, int where, int ret)
+#else
+ssl_client_info_callback(s,where,ret)
+const SSL *s;
+int where;
+int ret;
+#endif /* CK_ANSIC */
+{
+ if (inserver || !ssl_debug_flag)
+ return;
+
+ setverbosity();
+
+ switch ( where ) {
+ case SSL_CB_CONNECT_LOOP:
+ printf("SSL_connect:%s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ break;
+ case SSL_CB_CONNECT_EXIT:
+ if (ret == 0) {
+ printf("SSL_connect:failed in %s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ } else if (ret < 0) {
+ printf("SSL_connect:error in %s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ }
+ break;
+ case SSL_CB_ACCEPT_LOOP:
+ printf("SSL_accept:%s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ break;
+ case SSL_CB_ACCEPT_EXIT:
+ if (ret == 0) {
+ printf("SSL_accept:failed in %s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ } else if (ret < 0) {
+ printf("SSL_accept:error in %s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ }
+ break;
+ case SSL_CB_READ_ALERT:
+ printf("SSL_read_alert\r\n");
+ break;
+ case SSL_CB_WRITE_ALERT:
+ printf("SSL_write_alert\r\n");
+ break;
+ case SSL_CB_HANDSHAKE_START:
+ printf("SSL_handshake:%s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ break;
+ case SSL_CB_HANDSHAKE_DONE:
+ printf("SSL_handshake:%s %s\r\n",
+ SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
+ break;
+ }
+}
+
+#ifdef USE_CERT_CB
+/* Return 1, client cert is available */
+/* Return 0, no client cert is available */
+/* Return -1, callback must be called again. SSL_want_x509_lookup() == 1 */
+int
+#ifdef CK_ANSIC
+ssl_client_cert_callback(SSL * s, X509 ** x509, EVP_PKEY ** pkey)
+#else /* CK_ANSIC */
+ssl_client_cert_callback(s, x509, pkey)
+ SSL * s;
+ X509 ** x509;
+ EVP_PKEY ** pkey;
+#endif /* CK_ANSIC */
+{
+ setverbosity();
+
+ if ( ssl_debug_flag ) {
+ const char * cipher_list=SSL_get_cipher(s);
+ printf("ssl_client_cert_callback called (%s)\r\n",
+ cipher_list?cipher_list:"UNKNOWN");
+ }
+#ifdef COMMENT
+ if ( s == tls_con ) {
+ if (tls_load_certs(tls_cts,tls_con,0)) {
+ *x509 = SSL_get_certificate(s);
+ *pkey = SSL_get_privatekey(s);
+ return(1);
+ }
+ } else if ( s == ssl_con ) {
+ if (tls_load_certs(ssl_ctx,ssl_con,0)) {
+ *x509 = SSL_get_certificate(s);
+ *pkey = SSL_get_privatekey(s);
+ return(1);
+ }
+ }
+ return(0);
+#else /* COMMENT */
+ return(0);
+#endif /* COMMENT */
+}
+#endif /* USE_CERT_CB */
+
+#ifndef MS_CALLBACK
+#define MS_CALLBACK
+#endif /* MS_CALLBACK */
+
+static RSA MS_CALLBACK *
+#ifdef CK_ANSIC
+tmp_rsa_cb(SSL * s, int export, int keylength)
+#else /* CK_ANSIC */
+tmp_rsa_cb(s,export,keylength)
+SSL *s;
+int export;
+int keylength;
+#endif /* CK_ANSIC */
+{
+ static RSA *rsa_tmp=NULL;
+
+#ifndef NO_RSA
+ if (rsa_tmp == NULL)
+ {
+ if (ssl_debug_flag)
+ printf("Generating temporary (%d bit) RSA key...\r\n",keylength);
+
+ rsa_tmp=RSA_generate_key(keylength,RSA_F4,NULL,NULL);
+
+ if (ssl_debug_flag)
+ printf("\r\n");
+ }
+#else /* NO_RSA */
+ if (ssl_debug_flag)
+ printf("Unable to generate temporary RSA key...\r\n");
+#endif
+ return(rsa_tmp);
+}
+
+
+#ifndef NO_DH
+static unsigned char dh512_p[]={
+ 0xE9,0x4E,0x3A,0x64,0xFA,0x65,0x5F,0xA6,0x44,0xC7,0xFC,0xF1,
+ 0x16,0x8B,0x11,0x11,0x7A,0xF0,0xB2,0x49,0x80,0x56,0xA3,0xF8,
+ 0x0F,0x7D,0x01,0x68,0x5D,0xF6,0x8A,0xEA,0x8C,0xDD,0x01,0xDC,
+ 0x43,0x18,0xE0,0xC4,0x89,0x80,0xE6,0x2D,0x44,0x77,0x45,0xFD,
+ 0xBA,0xFC,0x43,0x35,0x12,0xC0,0xED,0x32,0xD3,0x16,0xEF,0x51,
+ 0x09,0x44,0xA2,0xDB,
+};
+static unsigned char dh512_g[]={
+ 0x05,
+};
+
+static unsigned char dh768_p[]={
+ 0x8B,0x2A,0x8C,0x6C,0x0F,0x87,0xC7,0x34,0xEE,0x2E,0xFB,0x60,
+ 0x94,0xB3,0xBF,0x95,0xBA,0x84,0x74,0x86,0xEA,0xE0,0xA4,0x33,
+ 0xE0,0x8F,0x7C,0x79,0x5C,0x62,0xE2,0x91,0xC5,0x6D,0x68,0xB9,
+ 0x6C,0x5E,0x4E,0x94,0x0C,0x8E,0x56,0x8E,0xEB,0x98,0x7C,0x6E,
+ 0x0E,0xF2,0xD5,0xAA,0x22,0x27,0x3F,0x0F,0xAF,0x10,0xB5,0x0B,
+ 0x16,0xCC,0x05,0x27,0xBB,0x58,0x6D,0x61,0x4B,0x2B,0xAB,0xDC,
+ 0x6A,0x15,0xBC,0x36,0x75,0x4D,0xEC,0xAB,0xFA,0xB6,0xE1,0xB1,
+ 0x13,0x70,0xD8,0x77,0xCD,0x5E,0x51,0x77,0x81,0x0D,0x77,0x43,
+};
+static unsigned char dh768_g[]={
+ 0x05,
+};
+
+static unsigned char dh1024_p[]={
+ 0xA4,0x75,0xCF,0x35,0x00,0xAF,0x3C,0x17,0xCE,0xB0,0xD0,0x52,
+ 0x43,0xA0,0x0E,0xFA,0xA2,0xC9,0xBE,0x0B,0x76,0x7A,0xD9,0x2E,
+ 0xF4,0x97,0xAC,0x02,0x24,0x69,0xF6,0x36,0x4F,0xAB,0xCC,0x43,
+ 0xC1,0x74,0xFF,0xA3,0xD4,0x04,0x0F,0x11,0x2B,0x6D,0x8C,0x47,
+ 0xC9,0xCF,0x40,0x93,0x9B,0x7D,0x1E,0x52,0x85,0xB2,0x17,0x55,
+ 0x9C,0xF2,0x41,0x02,0x2A,0x9D,0x5F,0x24,0x22,0xC6,0x04,0xC4,
+ 0xAB,0x92,0x6D,0xC7,0xC8,0xF3,0x41,0x58,0x6C,0x86,0xFD,0xB8,
+ 0x0F,0x2D,0xDD,0xBF,0xA8,0x40,0x0C,0x58,0xC8,0xF2,0x3F,0x18,
+ 0xEF,0xF1,0x93,0x3E,0xBA,0x16,0x41,0xBE,0x32,0x6C,0xC5,0x63,
+ 0xFF,0x8A,0x02,0x3D,0xAC,0xD5,0x5A,0x49,0x64,0x34,0x14,0x2E,
+ 0xFB,0x2E,0xE7,0x39,0x1A,0x0F,0x3C,0x33,
+};
+static unsigned char dh1024_g[]={
+ 0x05,
+};
+
+static unsigned char dh1536_p[]={
+ 0xA3,0x2B,0x75,0x0E,0x7B,0x31,0x82,0xCA,0xF2,0xFC,0xF3,0x3D,
+ 0xCE,0x5F,0xCD,0x5B,0x95,0xF6,0x2F,0xA4,0x5D,0x08,0x26,0xD2,
+ 0x5F,0xC0,0x3F,0xC5,0xD8,0xA2,0xFE,0x83,0x26,0xBC,0xEB,0x7D,
+ 0xF0,0x4E,0xD2,0xA6,0xBB,0x3C,0x88,0x63,0xCE,0x98,0xDE,0x08,
+ 0xE2,0xE1,0xAF,0xE2,0x38,0xA8,0xFA,0x68,0x76,0x8D,0xBF,0xDF,
+ 0xBB,0x30,0x15,0xFE,0xBD,0x22,0xCC,0x03,0x4E,0x5E,0x33,0xA3,
+ 0x6D,0xD6,0x68,0x12,0x97,0x17,0x4B,0xB5,0x84,0x5F,0x5F,0xA3,
+ 0x5C,0x2F,0xA4,0x10,0xC1,0xAD,0xBF,0xAC,0x30,0xCA,0x47,0x64,
+ 0x63,0xFE,0xEE,0xEE,0xA1,0x64,0x73,0x70,0xAA,0xF9,0xFE,0xC6,
+ 0xAD,0x5E,0xF6,0xF3,0x9C,0xDF,0x34,0x53,0x34,0x72,0xA6,0xA4,
+ 0xBB,0x81,0x5A,0x43,0x41,0xFD,0x41,0x05,0x5B,0x77,0x7B,0x84,
+ 0x03,0xFA,0x8A,0xFA,0xF7,0x8E,0x0F,0xCB,0x51,0xA2,0xB8,0x45,
+ 0xFF,0x59,0x42,0xEF,0xCF,0xF6,0x25,0x37,0xE2,0x6D,0xFF,0x69,
+ 0x11,0xF5,0x77,0x59,0x79,0x1C,0x5F,0x05,0xFC,0x7A,0x65,0x81,
+ 0x03,0x4A,0x78,0xC6,0xE9,0x48,0x73,0xF6,0x10,0xBC,0x99,0x1C,
+ 0xEE,0x44,0x2F,0x8B,0x70,0xCA,0xA8,0xB6,0x02,0x83,0x3E,0x0B,
+};
+static unsigned char dh1536_g[]={
+ 0x05,
+};
+
+static unsigned char dh2048_p[]={
+ 0xFA,0x4E,0xE4,0x3B,0xFA,0xC1,0x87,0xDD,0xE7,0xC6,0x8B,0xE6,
+ 0x13,0x85,0xBC,0x9B,0x2B,0x8B,0x5B,0x46,0xBB,0x8B,0x86,0x6D,
+ 0xD7,0xB6,0xD5,0x49,0xC5,0x54,0xF2,0x3E,0xD2,0x39,0x64,0x9B,
+ 0x0E,0x33,0x39,0x8F,0xFA,0xFA,0xD9,0x78,0xED,0x34,0x82,0x29,
+ 0x37,0x58,0x4D,0x5D,0x40,0xCB,0x69,0xE3,0x8A,0x9F,0x17,0x0C,
+ 0x01,0x23,0x6B,0x05,0x01,0xAF,0x33,0xDE,0xDF,0x1A,0xBB,0x7B,
+ 0x6A,0x9F,0xD8,0xED,0x8D,0x5E,0x44,0x19,0x5B,0xE0,0xB6,0x23,
+ 0xF9,0x7A,0x96,0x6E,0x94,0x33,0x31,0x49,0xBA,0x84,0xD5,0x12,
+ 0xD7,0x6D,0xDC,0x35,0x54,0x64,0xA3,0xD8,0x04,0x26,0xC5,0xAF,
+ 0x7F,0xE3,0xFE,0x6F,0xBE,0xD5,0x17,0x72,0x4B,0xA6,0xD0,0xA7,
+ 0x5F,0x18,0xF5,0xF0,0x2D,0x11,0x9A,0xF6,0xD5,0x3B,0x6C,0x61,
+ 0x3C,0x6F,0x8E,0x09,0x4F,0x2C,0xE1,0x26,0x06,0x51,0xB3,0x19,
+ 0x85,0x85,0x13,0xF9,0xC2,0x6E,0x80,0x28,0x9E,0x8A,0xA0,0x01,
+ 0x46,0xD1,0x85,0x44,0x8C,0xE6,0xEE,0x7E,0x1E,0x17,0x3D,0xBA,
+ 0x54,0xFF,0xE8,0x0E,0xDD,0x51,0xF3,0x74,0x7F,0x0D,0x0B,0xAB,
+ 0xCA,0x84,0x8D,0x24,0x5D,0x56,0xD4,0x47,0x02,0xFC,0x93,0x9F,
+ 0xAE,0x9B,0x5C,0xDB,0x63,0xEB,0x65,0x01,0x38,0xC2,0x7B,0x30,
+ 0x1E,0x17,0x1C,0x75,0xF5,0x16,0x3B,0x4F,0x5F,0x41,0x32,0xB5,
+ 0xFF,0x9E,0x61,0xFD,0xD2,0x62,0x6E,0xFD,0x8A,0x28,0x93,0x59,
+ 0x2D,0x70,0x14,0x4D,0xE1,0x86,0xD5,0x90,0xB4,0xDF,0x72,0x71,
+ 0xE0,0xB4,0xD0,0xD6,0x82,0x3A,0x4A,0x04,0x58,0x32,0x0B,0xD3,
+ 0x51,0x13,0x32,0x63,
+};
+static unsigned char dh2048_g[]={
+ 0x02,
+};
+
+static DH *
+get_dh512()
+{
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL)
+ return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+}
+
+static DH *
+get_dh768()
+{
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL)
+ return(NULL);
+ dh->p=BN_bin2bn(dh768_p,sizeof(dh768_p),NULL);
+ dh->g=BN_bin2bn(dh768_g,sizeof(dh768_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+}
+
+static DH *
+get_dh1024()
+{
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL)
+ return(NULL);
+ dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+ dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+}
+
+static DH *
+get_dh1536()
+{
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL)
+ return(NULL);
+ dh->p=BN_bin2bn(dh1536_p,sizeof(dh1536_p),NULL);
+ dh->g=BN_bin2bn(dh1536_g,sizeof(dh1536_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+}
+
+static DH *
+get_dh2048()
+{
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL)
+ return(NULL);
+ dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
+ dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+}
+#endif /* NO_DH */
+
+static DH MS_CALLBACK *
+#ifdef CK_ANSIC
+tmp_dh_cb(SSL * s, int export, int keylength)
+#else /* CK_ANSIC */
+tmp_dh_cb(s,export,keylength)
+SSL *s;
+int export;
+int keylength;
+#endif /* CK_ANSIC */
+{
+ static DH *dh_tmp=NULL;
+ BIO *bio=NULL;
+
+#ifndef NO_DH
+ if (dh_tmp == NULL)
+ {
+ if (ssl_dh_param_file &&
+ (bio=BIO_new_file(ssl_dh_param_file,"r")) != NULL)
+ dh_tmp=PEM_read_bio_DHparams(bio,NULL,NULL,NULL);
+ if (bio != NULL)
+ BIO_free(bio);
+
+ if ( dh_tmp == NULL ) {
+ if ( keylength < 768 )
+ dh_tmp = get_dh512();
+ else if ( keylength < 1024 )
+ dh_tmp = get_dh768();
+ else if ( keylength < 1536 )
+ dh_tmp = get_dh1024();
+ else if ( keylength < 2048 )
+ dh_tmp = get_dh1536();
+ else
+ dh_tmp = get_dh2048();
+ }
+ }
+#else /* NO_DH */
+ if (ssl_debug_flag)
+ printf("DH not supported...\r\n");
+#endif /* NO_DH */
+ return(dh_tmp);
+}
+
+static void
+ssl_display_comp(SSL * ssl)
+{
+ if ( quiet ) /* fdc - Mon Nov 28 11:44:15 2005 */
+ return;
+
+ if ( !ck_ssleay_is_installed() )
+ return;
+
+ if (ssl == NULL)
+ return;
+
+ if (ssl->expand == NULL || ssl->expand->meth == NULL)
+ printf("Compression: None\r\n");
+ else {
+ printf("Compression: %s\r\n",ssl->expand->meth->name);
+ }
+}
+
+int
+#ifdef CK_ANSIC
+ssl_display_connect_details(SSL * ssl_con, int server, int verbose)
+#else /* CK_ANSIC */
+ssl_display_connect_details(ssl_con,server,verbose)
+SSL *ssl_con;
+int server;
+int verbose;
+#endif /* CK_ANSIC */
+{
+ X509 *peer;
+ SSL_CIPHER * cipher;
+ const char *cipher_list;
+ char buf[512]="";
+
+ if ( quiet ) /* fdc - Mon Nov 28 11:44:15 2005 */
+ return(0);
+
+ if ( !ck_ssleay_is_installed() )
+ return(0);
+
+ if ( inserver && !tn_deb )
+ return(0);
+
+ /* the cipher list *can* be NULL ... useless but it happens! */
+ cipher = SSL_get_current_cipher(ssl_con);
+ cipher_list = SSL_CIPHER_get_name(cipher);
+ SSL_CIPHER_description(cipher,buf,sizeof(buf));
+ if (cipher_list==NULL)
+ cipher_list="<NULL>";
+ printf("[TLS - %s",buf);
+ ssl_display_comp(ssl_con);
+
+ if ( server ) {
+ cipher_list=SSL_get_shared_ciphers(ssl_con,buf,512);
+ if (cipher_list==NULL)
+ cipher_list="<NULL>";
+ printf("[TLS - shared ciphers=%s]\r\n",
+ cipher_list);
+ }
+ if ( server || tn_deb ) {
+ peer=SSL_get_peer_certificate(ssl_con);
+ if (peer != NULL) {
+ X509_NAME_oneline(X509_get_subject_name(peer),buf,512);
+ printf("[TLS - subject=%s]\r\n",buf);
+ X509_NAME_oneline(X509_get_issuer_name(peer),buf,512);
+ printf("[TLS - issuer=%s]\r\n",buf);
+ /* X509_free(peer); */
+ } else if (!tls_is_krb5(0)) {
+ if ( !sstelnet && !tcp_incoming ) {
+ printf("[TLS - No certificate provided.]\r\n");
+ printf(
+ "[TLS - The identity of the host could not be verified.]\r\n");
+ }
+ }
+ }
+ return(0);
+}
+
+/*
+ * Use SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void * userdata)
+ * to set the value of the userdata. We are going to use it to store the
+ * prompt.
+ */
+
+int
+#ifdef CK_ANSIC
+ssl_passwd_callback(char *buf, int len, int rwflag, VOID * userdata)
+#else /* CK_ANSIC */
+ssl_passwd_callback(buf,len,rwflag,userdata)
+ char * buf; int len; int rwflag; VOID *userdata;
+#endif /* CK_ANSIC */
+{
+ extern char pwbuf[];
+ extern int pwflg, pwcrypt;
+ int ok;
+ char *prompt=NULL;
+
+ if ( pwbuf[0] && pwflg ) {
+ int n;
+ n = ckstrncpy(buf,pwbuf,len);
+#ifdef OS2
+ if ( pwcrypt )
+ ck_encrypt((char *)buf);
+#endif /* OS2 */
+ return(n);
+ }
+
+ if ( userdata == NULL )
+ prompt="Enter certificate passphrase: ";
+ else
+ prompt=(char*)userdata;
+ ok = uq_txt(NULL,prompt,2,NULL,buf,len,NULL,DEFAULT_UQ_TIMEOUT);
+ return(ok > 0 ? strlen(buf) : 0);
+}
+
+
+/* Attempts to load certificate data into the TLS context structures */
+/* Returns 1 on success; 0 on failure */
+int
+tls_load_certs(SSL_CTX * ctx, SSL * con, int server)
+{
+ int rc = 1;
+
+ if ( !ck_ssleay_is_installed() )
+ return(0);
+
+ debug(F110,"tls_load_certs","SSL_CTX",0);
+ debug(F110,"tls_load_certs","SSL",0);
+ debug(F110,"tls_load_certs","server",0);
+
+ if ( con ) {
+ if (ssl_rsa_cert_file) {
+ if ( ssl_debug_flag )
+ printf("Loading RSA certificate into SSL\r\n");
+
+ rc = SSL_use_certificate_file(con, ssl_rsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ {
+ if ( !quiet || ssl_debug_flag )
+ printf("Error loading certificate from %s\r\n",
+ ssl_rsa_cert_file);
+ } else {
+ if (!ssl_rsa_key_file || !ssl_rsa_key_file[0])
+ makestr(&ssl_rsa_key_file,ssl_rsa_cert_file);
+
+ rc = SSL_use_PrivateKey_file(con, ssl_rsa_key_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ rc = SSL_use_PrivateKey_file(con, ssl_rsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ {
+ if ( !quiet || ssl_debug_flag )
+ printf("Error loading key from %s\r\n",
+ ssl_rsa_key_file);
+ } else {
+ rc = SSL_check_private_key(con);
+ if (!rc)
+ {
+ if ( ssl_debug_flag )
+ printf(
+ "Private key does not match the certificate public key\r\n");
+ }
+ }
+ }
+ }
+
+ if (ssl_dsa_cert_file) {
+ if ( ssl_debug_flag )
+ printf("Loading DSA certificate into SSL\r\n");
+
+ rc = SSL_use_certificate_file(con, ssl_dsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ {
+ if ( ssl_debug_flag ) {
+ printf("Error loading certificate from %s\r\n",
+ ssl_dsa_cert_file);
+ }
+ } else {
+ if (!ssl_dh_key_file || !ssl_dh_key_file[0])
+ makestr(&ssl_dh_key_file,ssl_dsa_cert_file);
+ rc = SSL_use_PrivateKey_file(con, ssl_dh_key_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ rc = SSL_use_PrivateKey_file(con, ssl_dsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ {
+ if ( !quiet || ssl_debug_flag ) {
+ printf("Error loading key from %s\r\n",
+ ssl_dh_key_file);
+ }
+ } else {
+ rc = SSL_check_private_key(con);
+ if (!rc)
+ {
+ if ( ssl_debug_flag )
+ printf(
+ "Private key does not match the certificate public key\n");
+ }
+ }
+ }
+ }
+ } else {
+ if (ssl_rsa_cert_file) {
+ if ( ssl_debug_flag )
+ printf("Loading RSA certificate into SSL\r\n");
+
+ rc = SSL_CTX_use_certificate_file(ctx, ssl_rsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ {
+ if ( !quiet || ssl_debug_flag )
+ printf("Error loading certificate from %s\r\n",
+ ssl_rsa_cert_file);
+ } else {
+ if (!ssl_rsa_key_file || !ssl_rsa_key_file[0])
+ makestr(&ssl_rsa_key_file,ssl_rsa_cert_file);
+
+ rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_key_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc) {
+ if ( ssl_debug_flag )
+ printf("Error loading key from %s\r\n",ssl_rsa_key_file);
+ } else {
+ rc = SSL_CTX_check_private_key(ctx);
+ if (!rc) {
+ if ( ssl_debug_flag )
+ printf(
+ "Private key does not match the certificate public key\r\n");
+ }
+ }
+ }
+ }
+ if (ssl_dsa_cert_file) {
+ if ( ssl_debug_flag )
+ printf("Loading DSA certificate into SSL\r\n");
+
+ rc = SSL_CTX_use_certificate_file(ctx, ssl_dsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc) {
+ if ( ssl_debug_flag ) {
+ printf("Error loading certificate from %s\r\n",
+ ssl_dsa_cert_file);
+ }
+ } else {
+ if (!ssl_dh_key_file || !ssl_dh_key_file[0])
+ makestr(&ssl_dh_key_file,ssl_dsa_cert_file);
+ rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dh_key_file,
+ X509_FILETYPE_PEM);
+ if (!rc)
+ rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dsa_cert_file,
+ X509_FILETYPE_PEM);
+ if (!rc) {
+ if ( ssl_debug_flag )
+ printf("Error loading key from %s\r\n",ssl_dh_key_file);
+ } else {
+ rc = SSL_CTX_check_private_key(ctx);
+ if (!rc) {
+ if ( ssl_debug_flag )
+ printf(
+ "Private key does not match the certificate public key\n");
+ }
+ }
+ }
+ }
+ }
+
+ if (ssl_rsa_cert_chain_file && server) {
+ int skip1st = 0;
+ if (ssl_debug_flag)
+ printf("Loading RSA Certificate Chain into SSL\r\n");
+ if (!ckstrcmp(ssl_rsa_cert_chain_file,ssl_rsa_cert_file,-1,
+#ifdef OS2
+ 0
+#else
+ 1
+#endif /* OS2 */
+ ))
+ skip1st = 1;
+ rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_rsa_cert_chain_file);
+ if (!rc && ssl_debug_flag)
+ printf("Error loading RSA Certificate Chain into SSL\r\n");
+ }
+ if (ssl_dsa_cert_chain_file && server) {
+ int skip1st = 0;
+ if (ssl_debug_flag)
+ printf("Loading DSA Certificate Chain into SSL\r\n");
+ if (!ckstrcmp(ssl_dsa_cert_chain_file,ssl_dsa_cert_file,-1,
+#ifdef OS2
+ 0
+#else
+ 1
+#endif /* OS2 */
+ ))
+ skip1st = 1;
+ rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_dsa_cert_chain_file);
+ if (!rc && ssl_debug_flag)
+ printf("Error loading DSA Certificate Chain into SSL\r\n");
+ }
+ return(rc);
+}
+
+VOID
+#ifdef CK_ANSIC
+ssl_once_init(void)
+#else
+ssl_once_init()
+#endif /* CK_ANSIC */
+{
+ COMP_METHOD * cm;
+ char * s;
+
+ if ( !ck_ssleay_is_installed() )
+ return;
+/*
+ OpenSSL does not provide for ABI compatibility between releases prior
+ to version 1.0.0. If the version does not match, it is not safe to
+ assume that any function you call takes the same parameters or does
+ the same thing with them. Removing this test prior to the OpenSSL 1.0.0
+ release will result in an increase in unexplained or incorrect behaviors.
+ The test should be revised once OpenSSL 1.0.0 is released and we see what
+ its claims are as to ABI compatibility.
+*/
+ debug(F111,"Kermit built for OpenSSL",OPENSSL_VERSION_TEXT,SSLEAY_VERSION_NUMBER);
+#ifndef OS2ONLY
+ debug(F111,"OpenSSL Library",SSLeay_version(SSLEAY_VERSION),
+ SSLeay());
+ debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_BUILT_ON),0);
+ debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_CFLAGS),0);
+ debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_PLATFORM),0);
+
+ /* The following test is suggested by Richard Levitte */
+ if (((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xffffff0f)
+#ifdef OS2
+ || ckstrcmp(OPENSSL_VERSION_TEXT,(char *)SSLeay_version(SSLEAY_VERSION),-1,1)
+#endif /* OS2 */
+ ) {
+ ssl_installed = 0;
+ debug(F111,"OpenSSL Version does not match. Built with",
+ SSLeay_version(SSLEAY_VERSION),SSLEAY_VERSION_NUMBER);
+ printf("?OpenSSL libraries do not match required version:\r\n");
+ printf(" . C-Kermit built with %s\r\n",OPENSSL_VERSION_TEXT);
+ printf(" . Version found %s\r\n",SSLeay_version(SSLEAY_VERSION));
+ printf(" OpenSSL versions prior to 1.0.0 must be the same.\r\n");
+
+ s = "R";
+#ifdef SOLARIS
+ printf(" Set CD_LIBRARY_PATH for %s.\r\n",OPENSSL_VERSION_TEXT);
+ s = " Or r";
+#endif /* SOLARIS */
+
+#ifdef HPUX
+ printf(" Set SHLIB_PATH for %s.\r\n",OPENSSL_VERSION_TEXT);
+ s = " Or r";
+#endif /* HPUX */
+
+#ifdef AIX
+ printf(" Set LIBPATH for %s.\r\n",OPENSSL_VERSION_TEXT);
+ s = " Or r";
+#endif /* AIX */
+
+#ifdef LINUX
+ printf(" Set LD_LIBRARY_PATH for %s.\r\n",OPENSSL_VERSION_TEXT);
+ s = " Or r";
+#endif /* LINUX */
+
+ printf(" %sebuild C-Kermit from source on this computer to make \
+versions agree.\r\n",s);
+
+#ifdef KTARGET
+ {
+ char * s;
+ s = KTARGET;
+ if (!s) s = "";
+ if (!*s) s = "(unknown)";
+ printf(" C-Kermit makefile target: %s\r\n",s);
+ }
+#endif /* KTARGET */
+ printf(" Or if that is what you did then try to find out why\r\n");
+ printf(" the program loader (image activator) is choosing a\r\n");
+ printf(" different OpenSSL library than the one specified in \
+the build.\r\n\r\n");
+ printf(" All SSL/TLS features disabled.\r\n\r\n");
+ bleep(BP_FAIL);
+#ifdef SSLDLL
+ ck_ssl_unloaddll();
+ ck_crypto_unloaddll();
+#endif /* SSLDLL */
+ return;
+ }
+#endif /* OS2ONLY */
+
+ /* init things so we will get meaningful error messages
+ * rather than numbers
+ */
+ SSL_load_error_strings();
+
+#ifdef SSHBUILTIN
+ OPENSSL_add_all_algorithms_noconf();
+#else
+ /* SSL_library_init() only loads those ciphers needs for SSL */
+ /* These happen to be a similar set to those required for SSH */
+ /* but they are not a complete set of ciphers provided by the */
+ /* crypto library. */
+ SSL_library_init();
+#endif /* SSHBUILTIN */
+
+#ifdef ZLIB
+ cm = COMP_zlib();
+ if (cm != NULL && cm->type != NID_undef) {
+ SSL_COMP_add_compression_method(0xe0, cm); /* EAY's ZLIB ID */
+ }
+#endif /* ZLIB */
+ cm = COMP_rle();
+ if (cm != NULL && cm->type != NID_undef)
+ SSL_COMP_add_compression_method(0xe1, cm); /* EAY's RLE ID */
+
+ /* Ensure the Random number generator has enough entropy */
+ if ( !RAND_status() ) {
+ char buffer[256]="";
+ char randombytes[256];
+ int rc1 = -1, rc2 = 1; /* assume failure and success */
+
+ debug(F110,"ssl_once_init","!RAND_status()",0);
+
+ if ( ssl_rnd_file == NULL ) {
+ debug(F110,"ssl_rnd_file","ssl_rnd_file is NULL",0);
+ RAND_file_name(buffer,256);
+ if ( buffer[0] )
+ makestr(&ssl_rnd_file, buffer);
+ else
+ makestr(&ssl_rnd_file,".rnd");
+ }
+ debug(F110,"ssl_rnd_file",ssl_rnd_file,0);
+
+ rc1 = RAND_egd(ssl_rnd_file);
+ debug(F111,"ssl_once_init","RAND_egd()",rc1);
+ if ( rc1 <= 0 ) {
+ rc2 = RAND_load_file(ssl_rnd_file, -1);
+ debug(F111,"ssl_once_init","RAND_load_file()",rc1);
+ }
+
+ if ( rc1 <= 0 && !rc2 )
+ {
+ time_t t = time(NULL);
+ int tlen = sizeof(time_t);
+ int pid = getpid();
+ int plen = sizeof(int);
+ int n;
+#ifndef RAND_MAX
+#define RAND_MAX 0x7FFF
+#endif
+ debug(F110,"ssl_once_init","calling RAND_seed()",0);
+
+ RAND_seed((unsigned char *)&t, tlen);
+ RAND_seed((unsigned char *)&pid, plen);
+
+ srand((unsigned int)t);
+ sprintf(buffer, "%.0f", (((double)(rand()%RAND_MAX)/RAND_MAX)*
+ (sizeof(randombytes)-128-1)));
+ n = (atoi(buffer)+1)%(sizeof(randombytes)-128-1);
+ RAND_seed(randombytes, 128);
+ }
+
+ if ( !RAND_status() ) {
+ debug(F110,"ssl_once_init","Unable to initialize PRNG",0);
+ printf(" Unable to load 'random state'\n");
+ printf(" SSL and TLS are unavailble.\n");
+ printf(" Use SET AUTH SSL RANDOM-FILE <file> command to provide random data.\n");
+ printf(" Specified file will be overwritten with new random data after use.\n");
+ return;
+ }
+
+ if ( ssl_rnd_file ) {
+ int rc = RAND_write_file(ssl_rnd_file);
+ debug(F111,"ssl_once_init","RAND_write_file()",rc);
+ }
+ }
+
+#ifdef NT
+ // Initialize additional OID types for use when saving certs to a file
+ OBJ_create("2.99999.3","SET.ex3","SET x509v3 extension 3");
+#endif /* NT */
+
+ /* make sure we have somewhere we can log errors to */
+ bio_err=BIO_new(BIO_s_mem());
+
+ debug(F100,"ssl_once_init() complete","",0);
+}
+
+int
+#ifdef CK_ANSIC
+ssl_tn_init(int mode)
+#else
+ssl_tn_init(mode) int mode;
+#endif /* CK_ANSIC */
+{
+#ifdef KRB5
+ extern char * k5_keytab;
+ extern char * krb5_d_srv;
+#endif /* KRB5 */
+ static int last_ssl_mode = -1;
+ SSL * ssl_conx=NULL, * tls_conx=NULL;
+
+ ssl_initialized = 0;
+
+ if ( !ck_ssleay_is_installed() )
+ return(0);
+
+ debug(F111,"ssl_tn_init","mode",mode);
+
+ if (ssl_debug_flag)
+ printf("SSL_DEBUG_FLAG on\r\n");
+
+ if (last_ssl_mode != mode) {
+ if (ssl_ctx) {
+ SSL_CTX_free(ssl_ctx);
+ ssl_ctx = NULL;
+ }
+ if (tls_ctx) {
+ SSL_CTX_free(tls_ctx);
+ tls_ctx = NULL;
+ }
+ }
+
+ if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) {
+ if ( mode == SSL_CLIENT ) {
+ ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+ /* This can fail because we do not have RSA available */
+ if ( !ssl_ctx ) {
+ debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
+ ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+ }
+ if ( !ssl_ctx ) {
+ debug(F110,"ssl_tn_init","SSLv3_client_method failed",0);
+ last_ssl_mode = -1;
+ return(0);
+ }
+#ifndef COMMENT
+ tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
+#else /* COMMENT */
+ tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+ /* This can fail because we do not have RSA available */
+ if ( !tls_ctx ) {
+ debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
+ tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+ }
+#endif /* COMMENT */
+ if ( !tls_ctx ) {
+ debug(F110,"ssl_tn_init","TLSv1_client_method failed",0);
+ last_ssl_mode = -1;
+ return(0);
+ }
+#ifdef USE_CERT_CB
+ SSL_CTX_set_client_cert_cb(ssl_ctx,ssl_client_cert_callback);
+ SSL_CTX_set_client_cert_cb(tls_ctx,ssl_client_cert_callback);
+#endif /* USE_CERT_CB */
+ } else if (mode == SSL_SERVER) {
+ /* We are a server */
+ ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method());
+ /* This can fail because we do not have RSA available */
+ if ( !ssl_ctx ) {
+ debug(F110,"ssl_tn_init","SSLv23_server_method failed",0);
+ ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_server_method());
+ }
+ if ( !ssl_ctx ) {
+ debug(F110,"ssl_tn_init","SSLv3_server_method failed",0);
+ last_ssl_mode = -1;
+ return(0);
+ }
+#ifdef COMMENT
+ tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
+#else /* COMMENT */
+ tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method());
+ /* This can fail because we do not have RSA available */
+ if ( !tls_ctx ) {
+ debug(F110,"ssl_tn_init","SSLv23_server_method failed",0);
+ tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
+ }
+#endif /* COMMENT */
+ if ( !tls_ctx ) {
+ debug(F110,"ssl_tn_init","TLSv1_server_method failed",0);
+ last_ssl_mode = -1;
+ return(0);
+ }
+ } else /* Unknown mode */
+ return(0);
+
+ if ( !inserver ) {
+ SSL_CTX_set_default_passwd_cb(ssl_ctx,
+ (pem_password_cb *)ssl_passwd_callback);
+ SSL_CTX_set_default_passwd_cb(tls_ctx,
+ (pem_password_cb *)ssl_passwd_callback);
+ }
+
+ /* for SSL switch on all the interoperability and bug
+ * workarounds so that we will communicate with people
+ * that cannot read poorly written specs :-)
+ * for TLS be sure to prevent use of SSLv2
+ */
+ SSL_CTX_set_options(ssl_ctx,SSL_OP_ALL|SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(tls_ctx,
+ SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA);
+
+ SSL_CTX_set_info_callback(ssl_ctx,ssl_client_info_callback);
+ SSL_CTX_set_info_callback(tls_ctx,ssl_client_info_callback);
+
+#ifndef COMMENT
+ /* Set the proper caching mode */
+ if ( mode == SSL_SERVER ) {
+ SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_SERVER);
+ SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_SERVER);
+ } else {
+ SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_CLIENT);
+ SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_CLIENT);
+ }
+ SSL_CTX_set_session_id_context(ssl_ctx,(CHAR *)"1",1);
+ SSL_CTX_set_session_id_context(tls_ctx,(CHAR *)"2",1);
+#else /* COMMENT */
+ SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_OFF);
+ SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_OFF);
+#endif /* COMMENT */
+ }
+
+ /* The server uses defaults for the certificate files. */
+ /* The client does not. */
+ if (mode == SSL_SERVER) {
+ char cert_filepath[1024];
+ const char * defdir = NULL;
+ DH * dh = NULL;
+
+ defdir = getenv("SSL_CERT_DIR");
+ if ( !defdir ) {
+#ifdef OS2
+ defdir = exedir;
+#else /* OS2 */
+ defdir = X509_get_default_cert_dir();
+#endif /* OS2 */
+ debug(F110,"ssl_tn_init - setting default directory to",defdir,0);
+ }
+ if ( !defdir )
+ defdir = "";
+
+ if (!ssl_rsa_cert_file) {
+ /* we need to know the fullpath to the location of the
+ * certificate that we will be running with as we cannot
+ * be sure of the cwd when we are launched
+ */
+ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa.pem");
+ if (zchki(cert_filepath) > 0)
+ makestr(&ssl_rsa_cert_file,cert_filepath);
+ }
+ if (ssl_rsa_cert_file && !ssl_rsa_key_file) {
+ /* we need to know the fullpath to the location of the
+ * certificate that we will be running with as we cannot
+ * be sure of the cwd when we are launched
+ */
+ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa-key.pem");
+ if (zchki(cert_filepath) > 0)
+ makestr(&ssl_rsa_key_file,cert_filepath);
+ }
+ if (!ssl_dsa_cert_file) {
+ /* we need to know the fullpath to the location of the
+ * certificate that we will be running with as we cannot
+ * be sure of the cwd when we are launched
+ */
+ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa.pem");
+ if (zchki(cert_filepath) > 0)
+ makestr(&ssl_dsa_cert_file,cert_filepath);
+ }
+ if (ssl_dsa_cert_file && !ssl_dh_key_file) {
+ /* we need to know the fullpath to the location of the
+ * certificate that we will be running with as we cannot
+ * be sure of the cwd when we are launched
+ */
+ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa-key.pem");
+ if (zchki(cert_filepath) > 0)
+ makestr(&ssl_dh_key_file,cert_filepath);
+ }
+ if (!ssl_crl_dir) {
+ /* we need to know the fullpath to the location of the
+ * certificate that we will be running with as we cannot
+ * be sure of the cwd when we are launched
+ */
+ sprintf(cert_filepath,"%s/crl",defdir);
+ if (zchki(cert_filepath) > 0)
+ makestr(&ssl_crl_dir,cert_filepath);
+ }
+
+ if (ssl_only_flag && !tls_load_certs(ssl_ctx,ssl_con,1)) {
+ debug(F110,"ssl_tn_init","Unable to load SSL certs",0);
+ last_ssl_mode = -1;
+ return(0);
+ }
+ if (tls_only_flag && !tls_load_certs(tls_ctx,tls_con,1)) {
+ debug(F110,"ssl_tn_init","Unable to load TLS certs",0);
+ last_ssl_mode = -1;
+ return(0);
+ }
+
+ if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) {
+ /* we may require a temp 512 bit RSA key because of the
+ * wonderful way export things work ... if so we generate
+ * one now!
+ */
+
+ SSL_CTX_set_tmp_rsa_callback(ssl_ctx, tmp_rsa_cb);
+ SSL_CTX_set_tmp_dh_callback( ssl_ctx, tmp_dh_cb);
+ SSL_CTX_set_tmp_rsa_callback(tls_ctx, tmp_rsa_cb);
+ SSL_CTX_set_tmp_dh_callback( tls_ctx, tmp_dh_cb);
+
+ dh = tmp_dh_cb(NULL,0,512);
+ SSL_CTX_set_tmp_dh(ssl_ctx,dh);
+ SSL_CTX_set_tmp_dh(tls_ctx,dh);
+
+ /* The following code is only called if we are using a
+ * certificate with an RSA public key and where the
+ * certificate has a key length less than 512 bits or is
+ * marked for signing only. This is so we can support
+ * the greatest legal privacy level with exportable clients.
+ */
+
+ if (SSL_CTX_need_tmp_RSA(ssl_ctx) ||
+ SSL_CTX_need_tmp_RSA(tls_ctx))
+ {
+ RSA *rsa;
+
+ if ( ssl_debug_flag )
+ printf("Generating temp (512 bit) RSA key ...\r\n");
+ rsa=RSA_generate_key(512,RSA_F4,NULL,NULL);
+ if ( ssl_debug_flag )
+ printf("Generation of temp (512 bit) RSA key done\r\n");
+
+ if (SSL_CTX_need_tmp_RSA(ssl_ctx)) {
+ if (!SSL_CTX_set_tmp_rsa(ssl_ctx,rsa)) {
+ if ( ssl_debug_flag )
+ printf(
+ "Failed to assign generated temp RSA key to SSL!\r\n");
+ }
+ }
+ if (SSL_CTX_need_tmp_RSA(tls_ctx)) {
+ if (!SSL_CTX_set_tmp_rsa(tls_ctx,rsa)) {
+ if ( ssl_debug_flag )
+ printf(
+ "Failed to assign generated temp RSA key to TLS!\r\n");
+ }
+ }
+ RSA_free(rsa);
+ if ( ssl_debug_flag )
+ printf("Assigned temp (512 bit) RSA key\r\n");
+ }
+ }
+ }
+
+ /* make sure we will find certificates in the standard
+ * location ... otherwise we don't look anywhere for
+ * these things which is going to make client certificate
+ * exchange rather useless :-)
+ * In OS2, default values for ssl_verify_file and ssl_verify_path.
+ */
+
+#ifdef OS2
+#ifdef NT
+ {
+ /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+ char path[CKMAXPATH];
+
+ ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+ if (isdir(path) &&
+ SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init certificate verify dir",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification Directory: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL);
+ if (isdir(path) &&
+ SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init certificate verify dir",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification Directory: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL);
+ if (isdir(path) &&
+ SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init certificate verify dir",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification Directory: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+ }
+ ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init certificate verify file",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification File: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init certificate verify file",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification File: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init certificate verify file",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification File: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+ }
+ }
+#else /* NT */
+ {
+ /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+ char path[CKMAXPATH];
+
+ ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+ if (isdir(path) &&
+ SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init certificate verify dir",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification Directory: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
+ }
+ ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init certificate verify file",path,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification File: %s\r\n",path);
+ SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
+ }
+ }
+#endif /* NT */
+#else /* OS2 */
+ SSL_CTX_set_default_verify_paths(ssl_ctx);
+ SSL_CTX_set_default_verify_paths(tls_ctx);
+#endif /* OS2 */
+
+ if (ssl_verify_file) {
+ if (zchki(ssl_verify_file) > 0 &&
+ SSL_CTX_load_verify_locations(tls_ctx,ssl_verify_file,NULL) == 1) {
+ debug(F110,"ssl_tn_init certificate verify file",ssl_verify_file,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification File: %s\r\n",ssl_verify_file);
+ SSL_CTX_load_verify_locations(ssl_ctx,ssl_verify_file,NULL);
+ }
+ }
+ if (ssl_verify_dir && isdir(ssl_verify_dir)) {
+ if (SSL_CTX_load_verify_locations(tls_ctx,NULL,ssl_verify_dir) == 1) {
+ debug(F110,"ssl_tn_init certificate verify dir",ssl_verify_dir,0);
+ if (ssl_debug_flag)
+ printf(" Certificate Verification Directory: %s\r\n",ssl_verify_dir);
+ SSL_CTX_load_verify_locations(ssl_ctx,NULL,ssl_verify_dir);
+ }
+ }
+ if (mode == SSL_SERVER) {
+ SSL_CTX_set_verify(ssl_ctx,
+ ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0,
+ ssl_server_verify_callback);
+ SSL_CTX_set_verify(tls_ctx,
+ ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0,
+ ssl_server_verify_callback);
+ } else {
+ SSL_CTX_set_verify(ssl_ctx,ssl_verify_flag,
+ ssl_client_verify_callback);
+ SSL_CTX_set_verify(tls_ctx,ssl_verify_flag,
+ ssl_client_verify_callback);
+ }
+
+ /* Free the existing CRL Store */
+ if (crl_store) {
+ X509_STORE_free(crl_store);
+ crl_store = NULL;
+ }
+
+ /* set up the new CRL Store */
+ crl_store = X509_STORE_new();
+ if (crl_store) {
+#ifdef OS2
+ char path[CKMAXPATH];
+
+ ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
+ if (isdir(path) &&
+ X509_STORE_load_locations(crl_store,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init crl dir",path,0);
+ if (ssl_debug_flag)
+ printf(" CRL Directory: %s\r\n",path);
+ }
+#ifdef NT
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL);
+ if (isdir(path) &&
+ X509_STORE_load_locations(crl_store,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init crl dir",path,0);
+ if (ssl_debug_flag)
+ printf(" CRL Directory: %s\r\n",path);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL);
+ if (isdir(path) &&
+ X509_STORE_load_locations(crl_store,NULL,path) == 1) {
+ debug(F110,"ssl_tn_init crl dir",path,0);
+ if (ssl_debug_flag)
+ printf(" CRL Directory: %s\r\n",path);
+ }
+#endif /* NT */
+
+ ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ X509_STORE_load_locations(crl_store,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init crl file",path,0);
+ if (ssl_debug_flag)
+ printf(" CRL File: %s\r\n",path);
+ }
+#ifdef NT
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ X509_STORE_load_locations(crl_store,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init crl file",path,0);
+ if (ssl_debug_flag)
+ printf(" CRL File: %s\r\n",path);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL);
+ if (zchki(path) > 0 &&
+ X509_STORE_load_locations(crl_store,path,NULL) == 1) {
+ debug(F110,"ssl_tn_init crl file",path,0);
+ if (ssl_debug_flag)
+ printf(" CRL File: %s\r\n",path);
+ }
+#endif /* NT */
+#endif /* OS2 */
+
+ if (ssl_crl_file || ssl_crl_dir) {
+ if (ssl_crl_file && zchki(ssl_crl_file) > 0 &&
+ X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 1) {
+ debug(F110,"ssl_tn_init crl file",ssl_crl_file,0);
+ if (ssl_debug_flag)
+ printf(" CRL File: %s\r\n",ssl_crl_file);
+ }
+ if (ssl_crl_dir && isdir(ssl_crl_dir) &&
+ X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 1) {
+ debug(F110,"ssl_tn_init crl dir",ssl_crl_dir,0);
+ if (ssl_debug_flag)
+ printf(" CRL Directory: %s\r\n",ssl_crl_dir);
+ }
+ }
+#ifndef OS2
+ else {
+ X509_STORE_set_default_paths(crl_store);
+ }
+#endif /* OS2 */
+ }
+
+#ifndef COMMENT
+ ssl_conx = ssl_con;
+ ssl_con=(SSL *)SSL_new(ssl_ctx);
+ if ( !ssl_con ) {
+ debug(F110,"ssl_tn_init","SSL_new(ssl_con) failed",0);
+ last_ssl_mode = -1;
+ ssl_con = ssl_conx;
+ return(0);
+ }
+ if (ssl_conx) {
+ if ( mode == SSL_CLIENT ) {
+ SSL_set_session(ssl_con, SSL_get_session(ssl_conx));
+ }
+#ifdef SSL_KRB5
+ if (ssl_conx->kssl_ctx) {
+ kssl_ctx_free(ssl_conx->kssl_ctx);
+ ssl_conx->kssl_ctx = NULL;
+ }
+#endif /* SSL_KRB5 */
+ SSL_free(ssl_conx);
+ ssl_conx = NULL;
+ }
+ tls_conx = tls_con;
+ tls_con=(SSL *)SSL_new(tls_ctx);
+ if ( !tls_con ) {
+ debug(F110,"ssl_tn_init","SSL_new(tls_con) failed",0);
+ last_ssl_mode = -1;
+ tls_con = tls_conx;
+ return(0);
+ }
+ if (tls_conx) {
+ if ( mode == SSL_CLIENT )
+ SSL_set_session(tls_con, SSL_get_session(tls_conx));
+#ifdef SSL_KRB5
+ if (tls_conx->kssl_ctx) {
+ kssl_ctx_free(tls_conx->kssl_ctx);
+ tls_conx->kssl_ctx = NULL;
+ }
+#endif /* SSL_KRB5 */
+ SSL_free(tls_conx);
+ tls_conx = NULL;
+ }
+#else /* COMMENT */
+ /* I don't know why this does not work to reuse the connection. */
+ if ( ssl_con ) {
+ SSL_clear(ssl_con);
+ SSL_set_session(ssl_con,NULL);
+ SSL_set_accept_state(ssl_con) ;
+ } else {
+ ssl_con=(SSL *)SSL_new(ssl_ctx);
+ if (!ssl_con) {
+ debug(F110,"ssl_tn_init","SSL_new(ssl_ctx) failed",0);
+ last_ssl_mode = -1;
+ ssl_con = ssl_conx;
+ return(0);
+ }
+ }
+
+ if ( tls_con ) {
+ SSL_clear(tls_con);
+ SSL_set_session(tls_con,NULL);
+ SSL_set_accept_state(tls_con) ;
+ } else {
+ tls_con=(SSL *)SSL_new(tls_ctx);
+ if ( !tls_con ) {
+ debug(F110,"ssl_tn_init","SSL_new(tls_ctx) failed",0);
+ last_ssl_mode = -1;
+ tls_con = tls_conx;
+ return(0);
+ }
+ }
+#endif /* COMMENT */
+
+#ifdef SSL_KRB5
+#ifndef KRB5_SERVICE_NAME
+#define KRB5_SERVICE_NAME "host"
+#endif
+
+ if (ssl_con->kssl_ctx == NULL)
+ ssl_con->kssl_ctx = kssl_ctx_new();
+ if (tls_con->kssl_ctx == NULL)
+ tls_con->kssl_ctx = kssl_ctx_new();
+ if (mode == SSL_SERVER) {
+ if (ssl_con->kssl_ctx != NULL)
+ kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_KEYTAB, k5_keytab);
+ if (tls_con->kssl_ctx != NULL)
+ kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_KEYTAB, k5_keytab);
+ } else {
+ if (ssl_con->kssl_ctx != NULL)
+ kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVER, szHostName);
+ if (tls_con->kssl_ctx != NULL)
+ kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVER, szHostName);
+ }
+ kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVICE,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
+ kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVICE,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
+#endif /* SSL_KRB5 */
+
+ if (ssl_cipher_list) {
+ SSL_set_cipher_list(ssl_con,ssl_cipher_list);
+ SSL_set_cipher_list(tls_con,ssl_cipher_list);
+ } else {
+ char * p;
+ if (p = getenv("SSL_CIPHER")) {
+ SSL_set_cipher_list(ssl_con,p);
+ SSL_set_cipher_list(tls_con,p);
+ } else {
+ SSL_set_cipher_list(ssl_con,DEFAULT_CIPHER_LIST);
+ SSL_set_cipher_list(tls_con,DEFAULT_CIPHER_LIST);
+ }
+ }
+
+ ssl_verify_depth = -1;
+
+ if ( ssl_debug_flag )
+ printf("SSL/TLS init done!\r\n");
+
+ ssl_initialized = 1;
+ last_ssl_mode = mode;
+ debug(F110,"ssl_tn_init","done",0);
+ return(1);
+}
+
+#ifndef NOHTTP
+int
+#ifdef CK_ANSIC
+ssl_http_init(char * hostname)
+#else
+ssl_http_init(hostname) char * hostname;
+#endif /* CK_ANSIC */
+{
+#ifdef KRB5
+ extern char * k5_keytab;
+ extern char * krb5_d_srv;
+#endif /* KRB5 */
+ SSL * tls_conx=NULL;
+
+ ssl_http_initialized = 0;
+
+ if ( !ck_ssleay_is_installed() )
+ return(0);
+ debug(F110,"ssl_http_init",hostname,0);
+
+ if (ssl_debug_flag)
+ printf("SSL_DEBUG_FLAG on\r\n");
+
+ if (!tls_http_ctx ) {
+#ifdef COMMENT
+ /* too many web servers still do not support TLSv1 */
+ tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
+#else /* COMMENT */
+ tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+ /* This can fail because we do not have RSA available */
+ if ( !tls_http_ctx ) {
+ debug(F110,"ssl_http_init","SSLv23_client_method failed",0);
+ tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+ }
+#endif /* COMMENT */
+ if ( !tls_http_ctx ) {
+ debug(F110,"ssl_http_init","TLSv1_client_method failed",0);
+ return(0);
+ }
+#ifdef USE_CERT_CB
+ SSL_CTX_set_client_cert_cb(tls_http_ctx,ssl_client_cert_callback);
+#endif /* USE_CERT_CB */
+ }
+
+ SSL_CTX_set_default_passwd_cb(tls_http_ctx,
+ (pem_password_cb *)ssl_passwd_callback);
+
+ /* for SSL switch on all the interoperability and bug
+ * workarounds so that we will communicate with people
+ * that cannot read poorly written specs :-)
+ * for TLS be sure to prevent use of SSLv2
+ */
+ SSL_CTX_set_options(tls_http_ctx,
+ SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA);
+
+ SSL_CTX_set_info_callback(tls_http_ctx,ssl_client_info_callback);
+
+#ifndef COMMENT
+ SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_CLIENT);
+ SSL_CTX_set_session_id_context(tls_http_ctx,(CHAR *)"3",1);
+#else /* COMMENT */
+ SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_OFF);
+#endif /* COMMENT */
+
+ /* make sure we will find certificates in the standard
+ * location ... otherwise we don't look anywhere for
+ * these things which is going to make client certificate
+ * exchange rather useless :-)
+ */
+
+#ifdef OS2
+#ifdef NT
+ {
+ /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+ char path[CKMAXPATH];
+
+ ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-dir: %s\r\n",path);
+ }
+
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-dir: %s\r\n",path);
+ }
+
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-dir: %s\r\n",path);
+ }
+
+ ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-file: %s\r\n",path);
+ }
+
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-file: %s\r\n",path);
+ }
+
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-file: %s\r\n",path);
+ }
+ }
+#else /* NT */
+ {
+ /* The defaults in the SSL crypto library are not appropriate for OS/2 */
+ char path[CKMAXPATH];
+
+ ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-dir: %s\r\n",path);
+ }
+ ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
+ if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load path",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-file: %s\r\n",path);
+ }
+ }
+#endif /* NT */
+#else /* OS2 */
+ SSL_CTX_set_default_verify_paths(tls_http_ctx);
+#endif /* OS2 */
+
+ if (ssl_verify_file &&
+ SSL_CTX_load_verify_locations(tls_http_ctx,ssl_verify_file,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load ssl_verify_file",ssl_verify_file,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
+ }
+ if (ssl_verify_dir &&
+ SSL_CTX_load_verify_locations(tls_http_ctx,NULL,ssl_verify_dir) == 0) {
+ debug(F110,"ssl_http_init unable to load ssl_verify_dir",ssl_verify_dir,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
+ }
+
+ SSL_CTX_set_verify(tls_http_ctx,ssl_verify_flag,
+ ssl_client_verify_callback);
+
+ /* Free the existing CRL Store */
+ if (crl_store) {
+ X509_STORE_free(crl_store);
+ crl_store = NULL;
+ }
+
+ /* set up the new CRL Store */
+ crl_store = X509_STORE_new();
+ if (crl_store) {
+#ifdef OS2
+ char path[CKMAXPATH];
+
+ ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
+ if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load dir",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-dir: %s\r\n",path);
+ }
+#ifdef NT
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL);
+ if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load dir",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-dir: %s\r\n",path);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL);
+ if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
+ debug(F110,"ssl_http_init unable to load dir",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-dir: %s\r\n",path);
+ }
+#endif /* NT */
+
+ ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
+ if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load file",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-file: %s\r\n",path);
+ }
+#ifdef NT
+ ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL);
+ if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load file",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-file: %s\r\n",path);
+ }
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL);
+ if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load file",path,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-file: %s\r\n",path);
+ }
+#endif /* NT */
+#endif /* OS2 */
+
+ if (ssl_crl_file || ssl_crl_dir) {
+ if (ssl_crl_file &&
+ X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
+ debug(F110,"ssl_http_init unable to load ssl_crl_file",ssl_crl_file,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
+ }
+ if (ssl_crl_dir &&
+ X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
+ debug(F110,"ssl_http_init unable to load ssl_crl_dir",ssl_crl_dir,0);
+ if (ssl_debug_flag)
+ printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
+ }
+ } else {
+ X509_STORE_set_default_paths(crl_store);
+ }
+ }
+
+#ifndef COMMENT
+ tls_conx = tls_http_con;
+ tls_http_con=(SSL *)SSL_new(tls_http_ctx);
+ if ( !tls_http_con ) {
+ debug(F110,"ssl_http_init","SSL_new(tls_http_con) failed",0);
+ tls_http_con = tls_conx;
+ return(0);
+ }
+ if (tls_conx) {
+ SSL_set_session(tls_http_con, SSL_get_session(tls_conx));
+#ifdef SSL_KRB5
+ if (tls_conx->kssl_ctx) {
+ kssl_ctx_free(tls_conx->kssl_ctx);
+ tls_conx->kssl_ctx = NULL;
+ }
+#endif /* SSL_KRB5 */
+ SSL_free(tls_conx);
+ tls_conx = NULL;
+ }
+#else /* COMMENT */
+ /* I don't know why this does not work to reuse the connection. */
+ if ( tls_http_con ) {
+ SSL_clear(tls_http_con);
+ SSL_set_session(tls_http_con,NULL);
+ SSL_set_accept_state(tls_http_con) ;
+ } else {
+ tls_http_con=(SSL *)SSL_new(tls_http_ctx);
+ if ( !tls_http_con ) {
+ debug(F110,"ssl_http_init","SSL_new(tls_http_ctx) failed",0);
+ tls_http_con = tls_conx;
+ return(0);
+ }
+ }
+#endif /* COMMENT */
+
+#ifdef SSL_KRB5
+#ifndef KRB5_SERVICE_NAME
+#define KRB5_SERVICE_NAME "host"
+#endif
+
+ if (tls_http_con->kssl_ctx == NULL)
+ tls_http_con->kssl_ctx = kssl_ctx_new();
+ if (tls_http_con->kssl_ctx != NULL)
+ kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVER, hostname);
+
+ kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVICE,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
+#endif /* SSL_KRB5 */
+
+ if (ssl_cipher_list)
+ SSL_set_cipher_list(tls_http_con,ssl_cipher_list);
+ else {
+ char * p;
+ if (p = getenv("SSL_CIPHER")) {
+ SSL_set_cipher_list(tls_http_con,p);
+ } else {
+ SSL_set_cipher_list(tls_http_con,DEFAULT_CIPHER_LIST);
+ }
+ }
+
+ ssl_verify_depth = -1;
+
+ if ( ssl_debug_flag )
+ printf("SSL/TLS init done!\r\n");
+
+ ssl_http_initialized = 1;
+ return(1);
+}
+#endif /* NOHTTP */
+
+char *
+ssl_get_dNSName(ssl) SSL * ssl;
+{
+ static char *dns = NULL;
+ X509 *server_cert = NULL;
+ int i;
+ X509_EXTENSION *ext = NULL;
+ STACK_OF(GENERAL_NAME) *ialt = NULL;
+ GENERAL_NAME *gen = NULL;
+
+ if ( dns ) {
+ free(dns);
+ dns = NULL;
+ }
+
+ if (server_cert = SSL_get_peer_certificate(ssl)) {
+ if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1))<0)
+ return NULL;
+ if (!(ext = X509_get_ext(server_cert, i)))
+ return NULL;
+ X509V3_add_standard_extensions();
+ if (!(ialt = X509V3_EXT_d2i(ext)))
+ return NULL;
+ for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) {
+ gen = sk_GENERAL_NAME_value(ialt, i);
+ if (gen->type == GEN_DNS) {
+ if (!gen->d.ia5 || !gen->d.ia5->length)
+ break;
+ if (strlen((char *)gen->d.ia5->data) != gen->d.ia5->length) {
+ /* Ignoring IA5String containing null character */
+ continue;
+ }
+ dns = malloc(gen->d.ia5->length + 1);
+ if (dns) {
+ memcpy(dns, gen->d.ia5->data, gen->d.ia5->length);
+ dns[gen->d.ia5->length] = 0;
+ }
+ break;
+ }
+ }
+ X509V3_EXT_cleanup();
+ }
+cleanup:
+ if (ialt) sk_GENERAL_NAME_free(ialt);
+ if (server_cert) X509_free(server_cert);
+ return dns;
+}
+
+char *
+ssl_get_commonName(ssl) SSL * ssl; {
+ static char name[256];
+ int name_text_len;
+ int err;
+ X509 *server_cert;
+
+ name_text_len = 0;
+ if (server_cert = SSL_get_peer_certificate(ssl)) {
+ name_text_len =
+ X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
+ NID_commonName, name, sizeof(name));
+ X509_free(server_cert);
+ }
+ if (name_text_len <= 0) {
+ /* Common Name was empty or not retrieved */
+ err = 0;
+ } else if (strlen(name) != name_text_len) {
+ /* Ignoring Common Name containing null character */
+ err = 0;
+ } else {
+ err = 1;
+ }
+ if (err > 0)
+ return name;
+ else
+ return NULL;
+}
+
+char *
+ssl_get_issuer_name(ssl) SSL * ssl;
+{
+ static char name[256];
+ X509 *server_cert;
+
+ name[0] = '\0';
+ if (server_cert = SSL_get_peer_certificate(ssl)) {
+ X509_NAME_oneline(X509_get_issuer_name(server_cert),name,sizeof(name));
+ X509_free(server_cert);
+ return name;
+ }
+ else {
+#ifdef COMMENT
+ fprintf(stderr, "Warning: No certificate from server!\r\n");
+#endif /* COMMENT */
+ return NULL;
+ }
+}
+
+char *
+ssl_get_subject_name(ssl) SSL * ssl;
+{
+ static char name[256];
+ X509 *server_cert;
+
+ name[0] = '\0';
+ if (server_cert = SSL_get_peer_certificate(ssl)) {
+ X509_NAME_oneline(X509_get_subject_name(server_cert),name,sizeof(name));
+ X509_free(server_cert);
+ return name;
+ }
+ else
+ return NULL;
+}
+
+#ifdef COMMENT
+#ifdef CK_SSL
+ && !(ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) &&
+ ssl_anonymous_cipher(tls_active_flag?tls_con:ssl_con))
+#endif /* CK_SSL */
+
+int
+ssl_anonymous_cipher(ssl) SSL * ssl;
+{
+ X509 * cert;
+
+ if (sstelnet)
+ cert = SSL_get_certificate(ssl);
+ else
+ cert = SSL_get_peer_certificate(ssl);
+
+ if ( cert ) {
+ X509_free(cert);
+ return 0;
+ }
+ return 1;
+}
+#endif /* COMMENT */
+
+/*
+ This one is (very much!) based on work by
+ Ralf S. Engelschall <rse@engelschall.com>.
+ Comments by Ralf.
+*/
+int
+ssl_verify_crl(int ok, X509_STORE_CTX *ctx)
+{
+ X509_OBJECT obj;
+ X509_NAME *subject = NULL;
+ X509_NAME *issuer = NULL;
+ X509 *xs = NULL;
+ X509_CRL *crl = NULL;
+ X509_REVOKED *revoked = NULL;
+ X509_STORE_CTX * store_ctx = NULL;
+ long serial;
+ BIO *bio = NULL;
+ int i, n, rc;
+ char *cp;
+ char *cp2;
+
+ /*
+ * Unless a revocation store for CRLs was created we
+ * cannot do any CRL-based verification, of course.
+ */
+ if (!crl_store)
+ return ok;
+
+ store_ctx = X509_STORE_CTX_new();
+ if ( !store_ctx )
+ return(ok);
+
+ /*
+ * Determine certificate ingredients in advance
+ */
+ xs = X509_STORE_CTX_get_current_cert(ctx);
+ subject = X509_get_subject_name(xs);
+ issuer = X509_get_issuer_name(xs);
+
+ /*
+ * OpenSSL provides the general mechanism to deal with CRLs but does not
+ * use them automatically when verifying certificates, so we do it
+ * explicitly here. We will check the CRL for the currently checked
+ * certificate, if there is such a CRL in the store.
+ *
+ * We come through this procedure for each certificate in the certificate
+ * chain, starting with the root-CA's certificate. At each step we've to
+ * both verify the signature on the CRL (to make sure it's a valid CRL)
+ * and it's revocation list (to make sure the current certificate isn't
+ * revoked). But because to check the signature on the CRL we need the
+ * public key of the issuing CA certificate (which was already processed
+ * one round before), we've a little problem. But we can both solve it and
+ * at the same time optimize the processing by using the following
+ * verification scheme (idea and code snippets borrowed from the GLOBUS
+ * project):
+ *
+ * 1. We'll check the signature of a CRL in each step when we find a CRL
+ * through the _subject_ name of the current certificate. This CRL
+ * itself will be needed the first time in the next round, of course.
+ * But we do the signature processing one round before this where the
+ * public key of the CA is available.
+ *
+ * 2. We'll check the revocation list of a CRL in each step when
+ * we find a CRL through the _issuer_ name of the current certificate.
+ * This CRLs signature was then already verified one round before.
+ *
+ * This verification scheme allows a CA to revoke its own certificate as
+ * well, of course.
+ */
+
+ /*
+ * Try to retrieve a CRL corresponding to the _subject_ of
+ * the current certificate in order to verify it's integrity.
+ */
+ memset((char *)&obj, 0, sizeof(obj));
+ X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
+ rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, subject, &obj);
+ X509_STORE_CTX_cleanup(store_ctx);
+ crl = obj.data.crl;
+ if (rc > 0 && crl != NULL) {
+ /*
+ * Verify the signature on this CRL
+ */
+ if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) {
+ fprintf(stderr, "Invalid signature on CRL!\n");
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
+ X509_OBJECT_free_contents(&obj);
+ X509_STORE_CTX_free(store_ctx);
+ return 0;
+ }
+
+ /*
+ * Check date of CRL to make sure it's not expired
+ */
+ i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+ if (i == 0) {
+ fprintf(stderr, "Found CRL has invalid nextUpdate field.\n");
+ X509_STORE_CTX_set_error(ctx,
+ X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+ X509_OBJECT_free_contents(&obj);
+ X509_STORE_CTX_free(store_ctx);
+ return 0;
+ }
+ if (i < 0) {
+ fprintf(stderr,
+"Found CRL is expired - revoking all certificates until you get updated CRL.\n"
+ );
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
+ X509_OBJECT_free_contents(&obj);
+ X509_STORE_CTX_free(store_ctx);
+ return 0;
+ }
+ X509_OBJECT_free_contents(&obj);
+ }
+
+ /*
+ * Try to retrieve a CRL corresponding to the _issuer_ of
+ * the current certificate in order to check for revocation.
+ */
+ memset((char *)&obj, 0, sizeof(obj));
+ X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
+ rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, issuer, &obj);
+ X509_STORE_CTX_free(store_ctx); /* calls X509_STORE_CTX_cleanup() */
+ crl = obj.data.crl;
+ if (rc > 0 && crl != NULL) {
+ /*
+ * Check if the current certificate is revoked by this CRL
+ */
+ n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+ for (i = 0; i < n; i++) {
+ revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+ if (ASN1_INTEGER_cmp(revoked->serialNumber,
+ X509_get_serialNumber(xs)) == 0) {
+
+ serial = ASN1_INTEGER_get(revoked->serialNumber);
+ cp = X509_NAME_oneline(issuer, NULL, 0);
+ free(cp);
+
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+ X509_OBJECT_free_contents(&obj);
+ return 0;
+ }
+ }
+ X509_OBJECT_free_contents(&obj);
+ }
+ return ok;
+}
+
+char *
+tls_userid_from_client_cert(ssl) SSL * ssl;
+{
+ static char cn[256];
+ static char *r = cn;
+ int err;
+ X509 *client_cert;
+
+ if (client_cert = SSL_get_peer_certificate(ssl)) {
+ /* call the custom function */
+ err = X509_to_user(client_cert, cn, sizeof(cn));
+ X509_free(client_cert);
+ if (err)
+ return r = NULL;
+ else
+ return r;
+ }
+ else
+ return r = NULL;
+}
+
+unsigned char **
+tls_get_SAN_objs(SSL * ssl, int type)
+/* returns NULL or an array of malloc'ed objects of type `type' from the server's
+ * subjectAltName, remember to free() them all!
+ */
+{
+#define NUM_SAN_OBJS 64
+ static unsigned char *objs[NUM_SAN_OBJS];
+ unsigned char **rv = NULL;
+ X509 *server_cert = NULL;
+ int i, j;
+ X509_EXTENSION *ext = NULL;
+ STACK_OF(GENERAL_NAME) *ialt = NULL;
+ GENERAL_NAME *gen = NULL;
+
+ memset(objs, 0, sizeof(objs));
+ if (server_cert = SSL_get_peer_certificate(ssl)) {
+ if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1)) < 0)
+ goto eject;
+ if (!(ext = X509_get_ext(server_cert, i)))
+ goto eject;
+ X509V3_add_standard_extensions();
+ if (!(ialt = X509V3_EXT_d2i(ext)))
+ goto eject;
+ rv = objs;
+ for (i = 0, j = 0; i < sk_GENERAL_NAME_num(ialt) && j < NUM_SAN_OBJS - 2; i++) {
+ gen = sk_GENERAL_NAME_value(ialt, i);
+ /* The use of V_ASN1_CONTEXT_SPECIFIC is because OpenSSL 0.9.6 defined its
+ * types | V_ASN1_CONTEXT_SPECIFIC. 0.9.7 does not. In case, we are built
+ * with one and linked to the other we use this hack.
+ */
+ if ((gen->type | V_ASN1_CONTEXT_SPECIFIC) == (type | V_ASN1_CONTEXT_SPECIFIC)) {
+ if (!gen->d.ia5 || !gen->d.ia5->length)
+ break;
+ if (strlen((char *)gen->d.ia5->data) != gen->d.ia5->length) {
+ /* Ignoring IA5String containing null character */
+ continue;
+ }
+ objs[j] = malloc(gen->d.ia5->length + 1);
+ if (objs[j]) {
+ memcpy(objs[j], gen->d.ia5->data, gen->d.ia5->length);
+ objs[j][gen->d.ia5->length] = 0;
+ j++;
+ }
+ }
+ }
+ X509V3_EXT_cleanup();
+ }
+eject:
+ if (ialt) sk_GENERAL_NAME_free(ialt);
+ if (server_cert) X509_free(server_cert);
+ return rv;
+}
+
+
+static int
+dNSName_cmp(const char *host, const char *dNSName)
+{
+ int c1 = 1, c2 = 1, num_comp, rv = -1;
+ char *p, *p1, *p2, *host_copy=NULL, *dNSName_copy=NULL;
+
+ /* first we count the number of domain name components in both parameters.
+ * they should be equal many, or it's not a match
+ */
+ p = (char *) host;
+ while (p = strstr(p, ".")) {
+ c1++;
+ p++;
+ }
+ p = (char *) dNSName;
+ while (p = strstr(p, ".")) {
+ c2++;
+ p++;
+ }
+ if (c1 != c2)
+ return -1;
+ num_comp = c1;
+
+ makestr(&host_copy,host);
+ makestr(&dNSName_copy,dNSName);
+ if (host_copy == NULL || dNSName_copy == NULL)
+ goto eject;
+ /* make substrings by replacing '.' with '\0' */
+ p = dNSName_copy;
+ while (p = strstr(p, ".")) {
+ *p = '\0';
+ p++;
+ }
+ p = host_copy;
+ while (p = strstr(p, ".")) {
+ *p = '\0';
+ p++;
+ }
+
+ /* compare each component */
+ p1 = host_copy;
+ p2 = dNSName_copy;
+ for (; num_comp; num_comp--) {
+ if (!ckmatch(p2, p1,0,1))
+ /* failed match */
+ goto eject;
+ p1 += strlen(p1) + 1;
+ p2 += strlen(p2) + 1;
+ }
+ /* match ok */
+ rv = 0;
+
+ eject:
+ if (dNSName_copy) free(dNSName_copy);
+ if (host_copy) free(host_copy);
+ return rv;
+}
+
+
+
+static int
+show_hostname_warning(char *s1, char *s2)
+{
+ char prefix[1024];
+ int ok = 1;
+ setverbosity();
+ ckmakxmsg(prefix,1024,
+ "Warning: Hostname (\"", s1,
+ "\") does not match server's certificate (\"", s2, "\")",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ if (ssl_verify_flag)
+ ok = uq_ok(prefix,
+ "Continue? (Y/N) ",
+ 3, NULL, 0);
+ else if (verbosity)
+ printf(prefix);
+ return(ok);
+}
+
+#ifndef OSF50
+#ifndef HPUX10
+#ifndef HPUX1100
+#ifndef SCO_OSR505
+#ifndef OpenBSD
+#ifndef FREEBSD4
+#ifndef NETBSD15
+#ifndef LINUX
+#ifndef AIX41
+#ifndef UW7
+#ifndef IRIX65
+#ifndef SOLARIS9
+#ifndef SOLARIS8
+#ifndef SOLARIS7
+#ifndef MACOSX
+#ifdef DEC_TCPIP
+#define inet_aton INET_ATON
+#endif /* DEC_TCPIP */
+
+#ifndef NO_DCL_INET_ATON
+static int
+inet_aton(char * ipaddress, struct in_addr * ia) {
+ struct stringarray * q;
+ union {
+ unsigned long l;
+ unsigned char b[4];
+ } dummy;
+
+ q = cksplit(1,0,ipaddress,".","0123456789abcdefACDEF",8,0,0);
+ if (q->a_size == 4) {
+ dummy.b[0] = atoi(q->a_head[1]);
+ dummy.b[1] = atoi(q->a_head[2]);
+ dummy.b[2] = atoi(q->a_head[3]);
+ dummy.b[3] = atoi(q->a_head[4]);
+ ia->s_addr = dummy.l;
+ return(ia->s_addr != 0);
+ }
+ return(0);
+}
+#endif /* NO_DCL_INET_ATON */
+
+#endif /* MACOSX */
+#endif /* SOLARIS7 */
+#endif /* SOLARIS8 */
+#endif /* SOLARIS9 */
+#endif /* IRIX65 */
+#endif /* UW7 */
+#endif /* AIX41 */
+#endif /* LINUX */
+#endif /* NETBSD15 */
+#endif /* FREEBSD4 */
+#endif /* OpenBSD */
+#endif /* SCO_OSR505 */
+#endif /* HPUX1100 */
+#endif /* HPUX10 */
+#endif /* OSF50 */
+
+int
+ssl_check_server_name(SSL * ssl, char * hostname)
+/* returns 0 if hostname and server's cert matches, else -1 */
+{
+ char * commonName;
+ unsigned char ** dNSName;
+ unsigned char ** ipAddress;
+ struct in_addr ia;
+ int rv;
+
+ setverbosity();
+ if (verbosity && !inserver) {
+ if (dNSName = tls_get_SAN_objs(ssl,GEN_DNS)) {
+ int i = 0;
+ for (i = 0; dNSName[i]; i++) {
+ printf("Certificate[0] altSubjectName DNS=%s\r\n",dNSName[i]);
+ free(dNSName[i]);
+ }
+ }
+ if (ipAddress = tls_get_SAN_objs(ssl,GEN_IPADD)) {
+ int i = 0;
+ char *server_ip;
+ struct in_addr ia;
+
+ for (i = 0; ipAddress[i]; i++) {
+ if (ipAddress[i]) {
+ ia.s_addr = *(unsigned long *)ipAddress[i];
+ server_ip = inet_ntoa(ia);
+ printf("Certificate[0] altSubjectName IPAddr=%s\r\n",server_ip);
+ }
+ free(ipAddress[i]);
+ }
+ /* ipAddress points to a static - don't free */
+ }
+ if (dNSName = tls_get_SAN_objs(ssl,GEN_EMAIL)) {
+ int i = 0;
+ for (i = 0; dNSName[i]; i++) {
+ printf("Certificate[0] altSubjectName Email=%s\r\n",dNSName[i]);
+ free(dNSName[i]);
+ }
+ }
+ if (dNSName = tls_get_SAN_objs(ssl,GEN_URI)) {
+ int i = 0;
+ for (i = 0; dNSName[i]; i++) {
+ printf("Certificate[0] altSubjectName URI=%s\r\n",dNSName[i]);
+ free(dNSName[i]);
+ }
+ }
+ if (dNSName = tls_get_SAN_objs(ssl,GEN_OTHERNAME)) {
+ int i = 0;
+ for (i = 0; dNSName[i]; i++) {
+ printf("Certificate[0] altSubjectName Other=%s\r\n",dNSName[i]);
+ free(dNSName[i]);
+ }
+ }
+ }
+
+ /* first we check if `hostname' is in fact an ip address */
+ if (inet_aton(hostname, &ia)) {
+ ipAddress = tls_get_SAN_objs(ssl,GEN_IPADD);
+ if (ipAddress) {
+ int i = 0;
+ char *server_ip = "UNKNOWN";
+
+ for (i = 0; ipAddress[i]; i++)
+ if (*(unsigned long *)ipAddress[i] == ia.s_addr)
+ return 0;
+
+ if (ipAddress[i - 1]) {
+ ia.s_addr = *(unsigned long *)ipAddress[i - 1];
+ server_ip = inet_ntoa(ia);
+ }
+ rv = show_hostname_warning(hostname, server_ip) ? 0 : -1;
+ for (i = 0; ipAddress[i]; i++)
+ free(ipAddress[i]);
+ } else {
+ rv = show_hostname_warning(hostname, "NO IP IN CERT") ? 0 : -1;
+ }
+ return(rv);
+ }
+
+ /* look for dNSName(s) in subjectAltName in the server's certificate */
+ dNSName = tls_get_SAN_objs(ssl,GEN_DNS);
+ if (dNSName) {
+ int i = 0;
+ for (i = 0; dNSName[i]; i++) {
+ if (!dNSName_cmp(hostname,(char *)dNSName[i]))
+ return 0;
+ }
+ rv = show_hostname_warning(hostname,
+ (char *)((dNSName[i - 1] == NULL) ?
+ (char *)"UNKNOWN" : (char *)dNSName[i - 1]))
+ ? 0 : -1;
+ for (i = 0; dNSName[i]; i++)
+ free(dNSName[i]);
+ return rv;
+ } else if ((commonName = ssl_get_commonName(ssl))) {
+ /* so the server didn't have any dNSName's, check the commonName */
+ if (!dNSName_cmp(hostname, commonName))
+ return 0;
+ else
+ return (show_hostname_warning(hostname, commonName) ? 0 : -1);
+ }
+ return -1;
+}
+
+/* Is 'user' authorized to access the system without a login */
+int
+tls_is_user_valid(SSL * ssl, const char *user)
+{
+ X509 *client_cert;
+ int r = 0;
+
+ if ( !ssl || !user || !user[0] )
+ return(0);
+
+ if (!(client_cert = SSL_get_peer_certificate(ssl)))
+ return 0;
+
+ /* Use user supplied function */
+ r = X509_userok(client_cert,user);
+
+ X509_free(client_cert);
+ return r;
+}
+
+int
+tls_is_anon(int x)
+{
+ char buf[128];
+ SSL_CIPHER * cipher;
+ SSL * ssl = NULL;
+
+ switch ( x ) {
+#ifndef NOFTP
+#ifndef SYSFTP
+ case 1: /* ftp command */
+ if ( ssl_ftp_active_flag )
+ ssl = ssl_ftp_con;
+ else
+ return(0);
+ break;
+ case 2: /* ftp data */
+ if ( ssl_ftp_data_active_flag )
+ ssl = ssl_ftp_data_con;
+ else
+ return(0);
+ break;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+ default:
+ if (tls_active_flag)
+ ssl = tls_con;
+ else if (ssl_active_flag)
+ ssl = ssl_con;
+ else
+ return(0);
+ }
+
+ cipher = SSL_get_current_cipher(ssl);
+ if (SSL_CIPHER_description(cipher,buf,sizeof(buf))) {
+ if (ckindex("Au=None",buf,0,0,0) != 0)
+ return(1); /* anonymous */
+ return(0); /* known */
+ } else {
+ /* could not get cipher description. Assume anonymous */
+ return(1);
+ }
+}
+
+int
+tls_is_krb5(int x)
+{
+ char buf[128];
+ SSL_CIPHER * cipher;
+ SSL * ssl = NULL;
+
+ switch ( x ) {
+#ifndef NOFTP
+#ifndef SYSFTP
+ case 1: /* ftp command */
+ if ( ssl_ftp_active_flag )
+ ssl = ssl_ftp_con;
+ else
+ return(0);
+ break;
+ case 2: /* ftp data */
+ if ( ssl_ftp_data_active_flag )
+ ssl = ssl_ftp_data_con;
+ else
+ return(0);
+ break;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+#ifndef NOHTTP
+ case 3:
+ if ( tls_http_active_flag )
+ ssl = tls_http_con;
+ break;
+#endif /* NOHTTP */
+ default:
+ if (tls_active_flag)
+ ssl = tls_con;
+ else if (ssl_active_flag)
+ ssl = ssl_con;
+ else
+ return(0);
+ }
+
+ cipher = SSL_get_current_cipher(ssl);
+ if (cipher && SSL_CIPHER_description(cipher,buf,sizeof(buf))) {
+ if (ckindex("Au=KRB5",buf,0,0,0) != 0)
+ return(1); /* krb5 */
+ }
+ return(0); /* not */
+}
+
+int
+ssl_get_client_finished(char *buf, int count)
+{
+#ifdef NO_GET_FINISHED
+ return(0);
+#else
+ if (sstelnet || tcp_incoming) {
+ return(SSL_get_peer_finished(ssl_active_flag?ssl_con:tls_con,
+ buf,count));
+ } else {
+ return(SSL_get_finished(ssl_active_flag?ssl_con:tls_con,
+ buf,count));
+ }
+#endif /* NO_GET_FINISHED */
+}
+
+int
+ssl_get_server_finished(char *buf, int count)
+{
+#ifdef NO_GET_FINISHED
+ return(0);
+#else
+ if (sstelnet || tcp_incoming) {
+ return(SSL_get_finished(ssl_active_flag?ssl_con:tls_con,
+ buf,count));
+ } else {
+ return(SSL_get_peer_finished(ssl_active_flag?ssl_con:tls_con,
+ buf,count));
+ }
+#endif /* NO_GET_FINISHED */
+}
+
+
+#ifdef CK_AUTHENTICATION
+int
+#ifdef CK_ANSIC
+ssl_reply(int how, unsigned char *data, int cnt)
+#else
+ssl_reply(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ char * str=NULL;
+
+ setverbosity();
+ data += 4; /* Point to status byte */
+ cnt -= 4;
+
+ if(cnt-- < 1) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ switch(*data++) {
+ case SSL_ACCEPT:
+ if (tn_deb || debses)
+ tn_debug("[SSL - handshake starting]");
+ else if ( verbosity )
+ printf("[SSL - handshake starting]\r\n");
+ debug(F110,"ssl_reply","[SSL - handshake starting]",0);
+
+ /* right ... now we drop into the SSL library */
+ if (!ssl_only_flag) {
+ if (ssl_dummy_flag) {
+ if (tn_deb || debses)
+ tn_debug("[SSL - Dummy Connected]");
+ else if ( verbosity ) {
+ printf("[SSL - Dummy Connected]\r\n");
+ }
+ debug(F110,"ssl_reply","[SSL - Dummy Connected]",0);
+ auth_finished(AUTH_UNKNOWN);
+ accept_complete = 1;
+ return AUTH_SUCCESS;
+ }
+
+ if (SSL_connect(ssl_con) <= 0) {
+ int len;
+ if (tn_deb || debses) {
+ tn_debug("[SSL - FAILED]");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ printf(ssl_err);
+ } else if ( verbosity ) {
+ printf("[SSL - FAILED]\r\n");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ printf(ssl_err);
+ }
+ debug(F110,"ssl_reply","[SSL - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ ttclos(0);
+ return AUTH_FAILURE;
+ } else {
+ if (tn_deb || debses)
+ tn_debug("[SSL - OK]");
+ else if ( verbosity ) {
+ printf("[SSL - OK]\r\n");
+ }
+ debug(F110,"ssl_reply","[SSL - OK]",0);
+
+ ssl_active_flag = 1;
+ ssl_display_connect_details(ssl_con,0,verbosity);
+ }
+ }
+ auth_finished(AUTH_UNKNOWN);
+ accept_complete = 1;
+ break;
+
+ case SSL_REJECT:
+ if (tn_deb || debses) {
+ tn_debug(
+ "[SSL - failed to switch on SSL - trying plaintext login]");
+ } else if ( verbosity ) {
+ printf("[SSL - failed to switch on SSL]\r\n");
+ printf("Trying plaintext login:\r\n");
+ }
+ debug(F110,"ssl_reply","[SSL - failed to switch on SSL]",0);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+
+ default:
+ return AUTH_FAILURE;
+ }
+ return AUTH_SUCCESS;
+}
+
+int
+#ifdef CK_ANSIC
+ssl_is(unsigned char *data, int cnt)
+#else
+ssl_is(data,cnt) unsigned char *data; int cnt;
+#endif
+{
+ if ((cnt -= 4) < 1)
+ return AUTH_FAILURE;
+
+ setverbosity();
+ data += 4;
+ switch(*data++) {
+ case SSL_START:
+ /* server starts the SSL stuff now ... */
+ if (!ssl_only_flag) {
+ if ( !tls_load_certs(ssl_ctx,ssl_con,1) ) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ if (tn_deb || debses)
+ tn_debug("[SSL - handshake starting]");
+ else if ( verbosity )
+ printf("[SSL - handshake starting]\r\n");
+ debug(F110,"ssl_is","[SSL - handshake starting]",0);
+
+ SendSSLAuthSB(SSL_ACCEPT, (void *)0, 0);
+
+ auth_ssl_valid = 1;
+
+ if (ssl_dummy_flag) {
+ if (tn_deb || debses)
+ tn_debug("[SSL - Dummy Connected]");
+ else if ( verbosity ) {
+ printf("[SSL - Dummy Connected]\r\n");
+ }
+ debug(F110,"ssl_is","[SSL - Dummy Connected]",0);
+ accept_complete = 1;
+ auth_finished(AUTH_UNKNOWN);
+ return AUTH_SUCCESS;
+ }
+
+ if (SSL_accept(ssl_con) <= 0) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[SSL - SSL_accept error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+
+ if (tn_deb || debses)
+ tn_debug(errbuf);
+ else if ( ssl_debug_flag )
+ printf("%s\r\n",errbuf);
+ else if ( verbosity )
+ printf("[SSL - SSL_accept error]\r\n");
+
+ debug(F110,"ssl_is",errbuf,0);
+
+ auth_finished(AUTH_REJECT);
+ ttclos(0);
+ return AUTH_FAILURE;
+ }
+
+ if (tn_deb || debses)
+ tn_debug("[SSL - OK]");
+ else if ( verbosity ) {
+ printf("[SSL - OK]\r\n");
+ }
+ debug(F110,"ssl_is","[SSL - OK]",0);
+ ssl_active_flag = 1;
+ ssl_display_connect_details(ssl_con,1,verbosity);
+
+ /* now check to see that we got exactly what we
+ * wanted from the caller ... if a certificate is
+ * required then we make 100% sure that we were
+ * given one during the handshake (as it is an optional
+ * part of SSL)
+ */
+
+#ifdef SSL_KRB5
+ if ( tls_is_krb5(0) ) {
+ if (ssl_con->kssl_ctx->client_princ)
+ debug(F110,"ssl_is KRB5",ssl_con->kssl_ctx->client_princ,0);
+ } else
+#endif /* SSL_KRB5 */
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ X509 * peer = SSL_get_peer_certificate(ssl_con);
+ if (peer == NULL) {
+ if (tn_deb || debses)
+ tn_debug("[SSL - peer check failed]");
+ else if (ssl_debug_flag)
+ printf("[SSL - peer check failed]\r\n");
+ debug(F110,"ssl_is","[SSL - peer check failed]",0);
+
+ /* LOGGING REQUIRED HERE! */
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ }
+ auth_finished(AUTH_UNKNOWN);
+ accept_complete = 1;
+ }
+ break;
+
+ default:
+ SendSSLAuthSB(SSL_REJECT, (void *) "Unknown option received", -1);
+ if (tn_deb || debses)
+ tn_debug("[SSL - Unknown option received]");
+ else
+ printf("Unknown SSL option %d\r\n", data[-1]);
+ debug(F111,"ssl_is","[SSL - Unknown option received]",data[-1]);
+ auth_ssl_valid = 0;
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+ return AUTH_SUCCESS;
+}
+
+#endif /* CK_AUTHENTICATION */
+
+int
+ck_tn_tls_negotiate(VOID)
+{
+ X509 * peer = NULL;
+ char str[256], *uid=NULL;
+ extern int sstelnet;
+
+ if ( !ck_ssleay_is_installed() )
+ return(-1);
+
+ setverbosity();
+ if (sstelnet) {
+ /* server starts the TLS stuff now ... */
+ if (!tls_only_flag) {
+ if ( !tls_load_certs(tls_ctx,tls_con,1) ) {
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+
+ if (tn_deb || debses)
+ tn_debug("[TLS - handshake starting]");
+ else if ( verbosity )
+ printf("[TLS - handshake starting]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[TLS - handshake starting]",0);
+
+ if (ssl_dummy_flag) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - Dummy Connected]");
+ else if ( verbosity ) {
+ printf("[TLS - Dummy Connected]\r\n");
+ }
+ debug(F110,"ck_tn_tls_negotiate","[TLS - Dummy Connected]",0);
+ accept_complete = 1;
+ auth_finished(AUTH_REJECT);
+ return 0;
+ }
+
+ if (SSL_accept(tls_con) <= 0) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[TLS - SSL_accept error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+
+ if (tn_deb || debses)
+ tn_debug(errbuf);
+ else if ( ssl_debug_flag )
+ printf("%s\r\n",errbuf);
+ else if ( verbosity )
+ printf("[TLS - SSL_accept error]\r\n");
+
+ debug(F110,"ck_tn_tls_negotiate",errbuf,0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+
+ if (tn_deb || debses)
+ tn_debug("[TLS - OK]");
+ else if ( verbosity ) {
+ printf("[TLS - OK]\r\n");
+ }
+
+ debug(F110,"ck_tn_tls_negotiate","[TLS - OK]",0);
+ tls_active_flag = 1;
+ ssl_display_connect_details(tls_con,1,verbosity);
+
+
+#ifdef SSL_KRB5
+ if ( tls_is_krb5(0) ) {
+ if (tls_con->kssl_ctx->client_princ) {
+ char *p;
+ ckstrncpy(szUserNameAuthenticated,
+ tls_con->kssl_ctx->client_princ,
+ UIDBUFLEN);
+ ckstrncpy(szUserNameRequested,
+ tls_con->kssl_ctx->client_princ,
+ UIDBUFLEN);
+ for ( p = szUserNameRequested; *p ; p++ ) {
+ if ( *p == '@' || *p == '/' ) {
+ *p = '\0';
+ break;
+ }
+ }
+ } else {
+ szUserNameRequested[0] = '\0';
+ szUserNameAuthenticated[0] = '\0';
+ }
+#ifdef CK_LOGIN
+ if (zvuser(szUserNameRequested))
+ auth_finished(AUTH_VALID);
+ else
+#endif /* CK_LOGIN */
+ auth_finished(AUTH_USER);
+ } else
+#endif /* SSL_KRB5 */
+ {
+ /* now check to see that we got exactly what we
+ * wanted from the caller ... if a certificate is
+ * required then we make 100% sure that we were
+ * given one during the handshake (as it is an optional
+ * part of TLS)
+ */
+ peer=SSL_get_peer_certificate(tls_con);
+ if (peer == NULL) {
+ debug(F100,"SSL_get_peer_certificate() == NULL","",0);
+ auth_finished(AUTH_REJECT);
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - peer check failed]");
+ else if (ssl_debug_flag) {
+ printf("[TLS - peer check failed]\r\n");
+ }
+ debug(F110,
+ "ck_tn_tls_negotiate",
+ "[TLS - peer check failed]",
+ 0
+ );
+ /* LOGGING REQUIRED HERE! */
+ return -1;
+ }
+ } else {
+ debug(F100,"SSL_get_peer_certificate() != NULL","",0);
+ X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+ NID_commonName,str,
+ 256
+ );
+ if ( verbosity )
+ printf("[TLS - commonName=%s]\r\n",str);
+
+ X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+#ifndef NID_x500UniqueIdentifier
+ NID_uniqueIdentifier,
+#else
+ NID_x500UniqueIdentifier,
+#endif
+ str,
+ 256
+ );
+ if ( verbosity )
+ printf("[TLS - uniqueIdentifier=%s]\r\n",str);
+
+ /* Try to determine user name */
+ uid = tls_userid_from_client_cert(tls_con);
+ if ( uid ) {
+ /* This code is very questionable.
+ * How should it behave?
+ * The client has presented a certificate that
+ * contains a username. We have validated the
+ * certificate but we do not automatically
+ * log the user in unless there is a .tlslogin
+ * file.
+ */
+
+ ckstrncpy(szUserNameRequested,uid,UIDBUFLEN);
+#ifdef CK_LOGIN
+ if (zvuser(uid))
+ auth_finished(AUTH_VALID);
+ else
+#endif /* CK_LOGIN */
+ auth_finished(AUTH_USER);
+ }
+ else {
+ szUserNameRequested[0] = '\0';
+ auth_finished(AUTH_REJECT);
+ }
+ }
+ }
+ }
+ } else {
+ char * str=NULL;
+
+ if (tn_deb || debses)
+ tn_debug("[TLS - handshake starting]");
+ else if ( verbosity )
+ printf("[TLS - handshake starting]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[TLS - handshake starting]",0);
+
+ /* right ... now we drop into the SSL library */
+ if (!tls_only_flag) {
+ char *subject=NULL, *issuer=NULL, *commonName=NULL, *dNSName=NULL;
+
+ if (ssl_dummy_flag) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - Dummy Connected]");
+ else if ( verbosity ) {
+ printf("[TLS - Dummy Connected]\r\n");
+ }
+ debug(F110,"ck_tn_tls_negotiate","[TLS - Dummy Connected]",0);
+ auth_finished(AUTH_REJECT);
+ accept_complete = 1;
+ return 0;
+ }
+
+#ifndef USE_CERT_CB
+ if (!tls_load_certs(tls_ctx,tls_con,0))
+ return(-1);
+#endif /* USE_CERT_CB */
+ if (SSL_connect(tls_con) <= 0) {
+ int len;
+ if (tn_deb || debses) {
+ tn_debug("[TLS - FAILED]");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ printf(ssl_err);
+ } else if ( verbosity ) {
+ printf("[TLS - FAILED]\r\n");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ printf(ssl_err);
+ }
+ debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+
+ tls_active_flag = 1;
+ if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER)
+ && !tls_is_krb5(0)) {
+ char prmpt[1024];
+ subject = ssl_get_subject_name(tls_con);
+
+ if (!subject) {
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+ {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ } else {
+ int ok;
+ ok = uq_ok("Warning: Server didn't provide a certificate",
+ "Continue? (Y/N)", 3, NULL, 0);
+ if (!ok) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+ }
+ } else if (ssl_check_server_name(tls_con, szHostName)) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+ }
+
+ if ( ssl_debug_flag && ssl_finished_messages) {
+ char msg[32];
+ int i, len=32;
+ extern char tn_msg[], hexbuf[];
+
+ tn_msg[0] = '\0';
+ len = ssl_get_client_finished(msg,len);
+ if ( len > 0 ) {
+ for ( i=0;i<len;i++ ) {
+ sprintf(hexbuf,"%02X ",msg[i]);
+ ckstrncat(tn_msg,hexbuf,TN_MSG_LEN);
+ }
+ printf("TLS client finished: %s\r\n",tn_msg);
+ }
+ tn_msg[0] = '\0';
+ len = ssl_get_server_finished(msg,len);
+ if ( len > 0 ) {
+ for ( i=0;i<len;i++ ) {
+ sprintf(hexbuf,"%02X ",msg[i]);
+ ckstrncat(tn_msg,hexbuf,TN_MSG_LEN);
+ }
+ printf("TLS server finished: %s\r\n",tn_msg);
+ }
+ }
+
+ if (tn_deb || debses)
+ tn_debug("[TLS - OK]");
+ else if ( verbosity )
+ printf("[TLS - OK]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[TLS - OK]",0);
+
+ ssl_display_connect_details(tls_con,0,verbosity);
+ }
+ auth_finished(AUTH_REJECT);
+ }
+ accept_complete = 1;
+ auth_ssl_valid = 1;
+ return(0);
+}
+
+int
+ck_ssl_incoming(fd) int fd;
+{
+ /* if we are not running in debug then any error
+ * stuff from SSL debug *must* not go down
+ * the socket (which 0,1,2 are all pointing to by
+ * default)
+ */
+
+ int timo = 2000;
+
+ setverbosity();
+ if ( !ck_ssleay_is_installed() )
+ return(-1);
+
+ /* do the SSL stuff now ... before we play with pty's */
+ SSL_set_fd(ssl_con,fd);
+ SSL_set_fd(tls_con,fd);
+
+ if (tls_only_flag) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - handshake starting]");
+ else if ( verbosity )
+ printf("[TLS - handshake starting]\r\n");
+ debug(F110,"ck_ssl_incoming","[TLS - handshake starting]",0);
+
+ /* hmm ... only when running talking to things like
+ * https servers should we hit this code and then
+ * we really don't care *who* we talk to :-)
+ */
+ if (SSL_accept(tls_con) <= 0) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[TLS - SSL_accept error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+
+ if (tn_deb || debses)
+ tn_debug(errbuf);
+ else if ( ssl_debug_flag )
+ printf("%s\r\n",errbuf);
+ else if ( verbosity )
+ printf("[TLS - SSL_accept error]\r\n");
+
+ debug(F110,"ck_ssl_incoming",errbuf,0);
+ return(-1);
+ } else {
+ if (tn_deb || debses)
+ tn_debug("[TLS - OK]");
+ else if ( verbosity )
+ printf("[TLS - OK]\r\n");
+ debug(F110,"ck_ssl_incoming","[TLS - OK]",0);
+ tls_active_flag = 1;
+ }
+ } else if (ssl_only_flag) {
+ if (tn_deb || debses)
+ tn_debug("[SSL - handshake starting]");
+ else if ( verbosity )
+ printf("[SSL - handshake starting]\r\n");
+ debug(F110,"ck_ssl_incoming","[SSL - handshake starting]",0);
+
+ /* hmm ... only when running talking to things like
+ * https servers should we hit this code and then
+ * we really don't care *who* we talk to :-)
+ */
+ if (SSL_accept(ssl_con) <= 0) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[SSL - SSL_accept error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+
+ if (tn_deb || debses)
+ tn_debug(errbuf);
+ else if ( ssl_debug_flag )
+ printf("%s\r\n",errbuf);
+ else if ( verbosity )
+ printf("[SSL - SSL_accept error]\r\n");
+
+ debug(F110,"ck_ssl_incoming",errbuf,0);
+ return(-1);
+ } else {
+ if (tn_deb || debses)
+ tn_debug("[SSL - OK]");
+ else if ( verbosity )
+ printf("[SSL - OK]\r\n");
+ debug(F110,"ssl_is","[SSL - OK]",0);
+ ssl_active_flag = 1;
+ }
+ }
+ if (ssl_active_flag || tls_active_flag) {
+ X509 *peer;
+ char str[256], *uid=NULL;
+
+ /* now check to see that we got exactly what we
+ * wanted from the caller ... if a certificate is
+ * required then we make 100% sure that we were
+ * given on during the handshake (as it is an optional
+ * part of SSL and TLS)
+ */
+
+ if ( tls_active_flag ) {
+ peer=SSL_get_peer_certificate(tls_con);
+ } else if ( ssl_active_flag ) {
+ peer=SSL_get_peer_certificate(ssl_con);
+ }
+
+ if (peer == NULL) {
+ debug(F100,"SSL_get_peer_certificate() == NULL","",0);
+ auth_finished(AUTH_REJECT);
+
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ if (tn_deb || debses)
+ tn_debug("[SSL/TLS - peer check failed]");
+ else if (ssl_debug_flag) {
+ printf("[SSL/TLS - peer check failed]\r\n");
+ }
+ debug(F110,
+ "ck_tn_tls_negotiate",
+ "[SSL/TLS - peer check failed]",
+ 0
+ );
+ /* LOGGING REQUIRED HERE! */
+ return -1;
+ }
+
+ } else {
+ debug(F100,"SSL_get_peer_certificate() != NULL","",0);
+ X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+ NID_commonName,str,
+ 256
+ );
+ printf("[TLS - commonName=%s]\r\n",str);
+
+ X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
+#ifndef NID_x500UniqueIdentifier
+ NID_uniqueIdentifier,
+#else
+ NID_x500UniqueIdentifier,
+#endif
+ str,256
+ );
+ printf("[TLS - uniqueIdentifier=%s]\r\n",str);
+
+ /* Try to determine user name */
+ uid = tls_userid_from_client_cert(tls_con);
+ if ( uid ) {
+ /* This code is very questionable.
+ * How should it behave?
+ * The client has presented a certificate that
+ * contains a username. We have validated the
+ * certificate but we do not automatically
+ * log the user in unless there is a .tlslogin
+ * file.
+ */
+
+ ckstrncpy(szUserNameRequested,uid,UIDBUFLEN);
+#ifdef CK_LOGIN
+ if (zvuser(uid))
+ auth_finished(AUTH_VALID);
+ else
+#endif /* CK_LOGIN */
+ auth_finished(AUTH_USER);
+ }
+ else {
+ szUserNameRequested[0] = '\0';
+ auth_finished(AUTH_REJECT);
+ }
+ }
+ }
+ return(0); /* success */
+}
+
+int
+ck_ssl_outgoing(fd) int fd;
+{
+ int timo = 2000;
+
+ setverbosity();
+ if ( !ck_ssleay_is_installed() )
+ return(-1);
+
+ /* bind in the network descriptor */
+ SSL_set_fd(ssl_con,fd);
+ SSL_set_fd(tls_con,fd);
+
+ /* If we are doing raw TLS then start it now ... */
+ if (tls_only_flag) {
+#ifndef USE_CERT_CB
+ if (!tls_load_certs(tls_ctx,tls_con,0)) {
+ debug(F110,"ck_ssl_outgoing","tls_load_certs() failed",0);
+ return(-1);
+ }
+#endif /* USE_CERT_CB */
+ if (tn_deb || debses)
+ tn_debug("[TLS - handshake starting]");
+ else if (verbosity)
+ printf("[TLS - handshake starting]\r\n");
+ debug(F110,"ck_ssl_outgoing","[TLS - handshake starting]",0);
+ if (SSL_connect(tls_con) <= 0) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[TLS - SSL_connect error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+
+ if (tn_deb || debses)
+ tn_debug(errbuf);
+ else if ( ssl_debug_flag )
+ printf("%s\r\n",errbuf);
+
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,"ck_ssl_outgoing","[TLS - FAILED]",0);
+ netclos();
+ return(-1);
+ } else {
+ tls_active_flag = 1;
+ if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+ !tls_is_krb5(0) ) {
+ char *subject = ssl_get_subject_name(tls_con);
+
+ if (!subject) {
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+ {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+
+ auth_finished(AUTH_REJECT);
+ return -1;
+ } else {
+ char prmpt[1024];
+ int ok;
+ ok = uq_ok("Warning: Server didn't provide a certificate",
+ "Continue? (Y/N)", 3, NULL, 0);
+ if (!ok) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+ }
+ } else if (ssl_check_server_name(tls_con, szHostName)) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+ }
+ if (tn_deb || debses)
+ tn_debug("[TLS - OK]");
+ else if (!quiet)
+ printf("[TLS - OK]\r\n");
+ debug(F110,"ck_ssl_outgoing","[TLS - OK]",0);
+ ssl_display_connect_details(tls_con,0,verbosity);
+ }
+ }
+ /* if we are doing raw SSL then start it now ... */
+ else if (ssl_only_flag) {
+#ifndef USE_CERT_CB
+ if (!tls_load_certs(ssl_ctx,ssl_con,0))
+ return(-1);
+#endif /* USE_CERT_CB */
+ if (tn_deb || debses)
+ tn_debug("[SSL - handshake starting]");
+ else if ( verbosity )
+ printf("[SSL - handshake starting]\r\n");
+ debug(F110,"ck_ssl_outgoing","[SSL - handshake starting]",0);
+ if (SSL_connect(ssl_con) <= 0) {
+ if ( ssl_debug_flag ) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[SSL - SSL_connect error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ printf("%s\r\n",errbuf);
+ }
+ if (tn_deb || debses)
+ tn_debug("[SSL - FAILED]");
+ else if ( verbosity )
+ printf("[SSL - FAILED]\r\n");
+ debug(F110,"ck_ssl_outgoing","[SSL - FAILED]",0);
+ return(-1);
+ } else {
+ ssl_active_flag = 1;
+
+ if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+ !tls_is_krb5(0)) {
+ char *subject = ssl_get_subject_name(ssl_con);
+
+ if (!subject) {
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+ {
+ if (tn_deb || debses)
+ tn_debug("[SSL - FAILED]");
+ else if ( verbosity )
+ printf("[SSL - FAILED]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[SSL - FAILED]",0);
+
+ auth_finished(AUTH_REJECT);
+ return -1;
+ } else {
+ char prmpt[1024];
+ int ok;
+ ok = uq_ok("Warning: Server didn't provide a certificate",
+ "Continue? (Y/N)", 3, NULL, 0);
+ if (!ok) {
+ if (tn_deb || debses)
+ tn_debug("[SSL - FAILED]");
+ else if ( verbosity )
+ printf("[SSL - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[SSL - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+ }
+ } else if (ssl_check_server_name(ssl_con, szHostName)) {
+ if (tn_deb || debses)
+ tn_debug("[SSL - FAILED]");
+ else if ( verbosity )
+ printf("[SSL - FAILED]\r\n");
+ debug(F110, "ck_tn_tls_negotiate","[SSL - FAILED]",0);
+ auth_finished(AUTH_REJECT);
+ return -1;
+ }
+ }
+ if (tn_deb || debses)
+ tn_debug("[SSL - OK]");
+ else if (!quiet)
+ printf("[SSL - OK]\r\n");
+ debug(F110,"ck_ssl_outgoing","[SSL - OK]",0);
+ ssl_display_connect_details(ssl_con,0,verbosity);
+ }
+ }
+ return(0); /* success */
+}
+
+#ifndef NOHTTP
+int
+ck_ssl_http_client(fd, hostname) int fd; char * hostname;
+{
+ int timo = 2000;
+
+ if ( !ck_ssleay_is_installed() )
+ return(-1);
+
+ setverbosity();
+
+ /* bind in the network descriptor */
+ SSL_set_fd(tls_http_con,fd);
+
+ /* If we are doing raw TLS then start it now ... */
+ if (1) {
+#ifndef USE_CERT_CB
+ if (!tls_load_certs(tls_http_ctx,tls_http_con,0)) {
+ debug(F110,"ck_ssl_http_client","tls_load_certs() failed",0);
+ return(-1);
+ }
+#endif /* USE_CERT_CB */
+ if (tn_deb || debses)
+ tn_debug("[TLS - handshake starting]");
+ else if (verbosity)
+ printf("[TLS - handshake starting]\r\n");
+ debug(F110,"ck_ssl_outgoing","[TLS - handshake starting]",0);
+ if (SSL_connect(tls_http_con) <= 0) {
+ char errbuf[1024];
+
+ sprintf(errbuf,"[TLS - SSL_connect error: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+
+ if (tn_deb || debses)
+ tn_debug(errbuf);
+ else if ( ssl_debug_flag )
+ printf("%s\r\n",errbuf);
+
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,"ck_ssl_http_client","[TLS - FAILED]",0);
+ http_close();
+ return(-1);
+ } else {
+ tls_http_active_flag = 1;
+ if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+ !tls_is_krb5(3) ) {
+ char *subject = ssl_get_subject_name(tls_http_con);
+
+ if (!subject) {
+ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+ {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ return -1;
+ } else {
+ char prmpt[1024];
+ int ok;
+ ok = uq_ok("Warning: Server didn't provide a certificate",
+ "Continue? (Y/N)", 3, NULL, 0);
+ if (!ok) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ return -1;
+ }
+ }
+ } else if (ssl_check_server_name(tls_http_con, hostname)) {
+ if (tn_deb || debses)
+ tn_debug("[TLS - FAILED]");
+ else if ( verbosity )
+ printf("[TLS - FAILED]\r\n");
+ debug(F110,
+ "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+ return -1;
+ }
+ }
+
+ printf("[TLS - OK]\r\n");
+ if (tn_deb || debses)
+ tn_debug("[TLS - OK]");
+ debug(F110,"ck_ssl_outgoing","[TLS - OK]",0);
+ ssl_display_connect_details(tls_http_con,0,verbosity);
+ }
+ }
+ return(0); /* success */
+}
+#endif /* NOHTTP */
+int
+ck_ssl_renegotiate_ciphers()
+{
+
+ if ( !ck_ssleay_is_installed() )
+ return(0);
+
+ if ( !sstelnet )
+ return(0);
+
+ if ( ssl_active_flag )
+ return SSL_renegotiate(ssl_con);
+ else if ( tls_active_flag )
+ return SSL_renegotiate(tls_con);
+ return(0);
+}
+
+#ifdef NT
+int
+ck_X509_save_cert_to_user_store(X509 *cert)
+{
+#ifdef X509V3_EXT_DUMP_UNKNOWN
+ char path[CKMAXPATH];
+ char hash[16];
+ char * GetAppData(int);
+ BIO * out=NULL;
+
+ if ( cert == NULL )
+ return(0);
+
+ sprintf(hash,"%08lx",X509_subject_name_hash(cert));
+ ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs/",
+ hash,".0");
+
+
+ out=BIO_new(BIO_s_file());
+ if (out == NULL)
+ {
+ ERR_print_errors(bio_err);
+ return(0);
+ }
+ if (BIO_write_filename(out,path) <= 0) {
+ perror(path);
+ return(0);
+ }
+
+ X509_print_ex(out, cert, XN_FLAG_SEP_MULTILINE, X509V3_EXT_DUMP_UNKNOWN);
+ if (!PEM_write_bio_X509(out,cert)) {
+ BIO_printf(bio_err,"unable to write certificate\n");
+ ERR_print_errors(bio_err);
+ BIO_free_all(out);
+ return(0);
+ }
+ BIO_free_all(out);
+ return(1);
+#else /* X509V3_EXT_DUMP_UNKNOWN */
+ return(0);
+#endif /* X509V3_EXT_DUMP_UNKNOWN */
+}
+#endif /* NT */
+
+#ifndef OS2
+/* The following function should be replaced by institution specific */
+/* code that will convert an X509 cert structure to a userid for the */
+/* purposes of client to host login. The example code included */
+/* simply returns the UID field of the Subject if it exists. */
+
+/* X509_to_user() returns 0 if valid userid in 'userid', else -1 */
+int
+X509_to_user(X509 *peer_cert, char *userid, int len)
+{
+#ifdef X509_UID_TO_USER
+ /* BEGIN EXAMPLE */
+ int err;
+
+ if (!(peer_cert && userid) || len <= 0)
+ return -1;
+
+ userid[0] = '\0';
+ debug(F110,"X509_to_user() subject",
+ X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0),0);
+
+ /* userid is in cert subject /UID */
+ err = X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
+#ifndef NID_x500UniqueIdentifier
+ NID_uniqueIdentifier,
+#else
+ NID_x500UniqueIdentifier,
+#endif
+ userid, len);
+
+ debug(F111,"X509_to_user() userid",userid,err);
+ if (err > 0)
+ return 0;
+
+ /* END EXAMPLE */
+#else /* X509_UID_TO_USER */
+#ifdef X509_SUBJECT_ALT_NAME_TO_USER
+ /* BEGIN EXAMPLE */
+ int i;
+ X509_EXTENSION *ext = NULL;
+ STACK_OF(GENERAL_NAME) *ialt = NULL;
+ GENERAL_NAME *gen = NULL;
+ char email[256];
+
+ if (!(peer_cert && userid) || len <= 0)
+ return -1;
+
+ userid[0] = '\0';
+ email[0] = '\0';
+ debug(F110,"X509_to_user() subject",
+ X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0),0);
+
+ if ((i = X509_get_ext_by_NID(peer_cert, NID_subject_alt_name, -1))<0)
+ return -1;
+ if (!(ext = X509_get_ext(peer_cert, i)))
+ return -1;
+ X509V3_add_standard_extensions();
+ if (!(ialt = X509V3_EXT_d2i(ext)))
+ return -1;
+ for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) {
+ gen = sk_GENERAL_NAME_value(ialt, i);
+ if (gen->type == GEN_DNS) {
+ if (!gen->d.ia5 || !gen->d.ia5->length)
+ break;
+ if (strlen(gen->d.ia5->data) != gen->d.ia5->length) {
+ /* Ignoring IA5String containing null character */
+ continue;
+ }
+ if ( gen->d.ia5->length + 1 > sizeof(email) ) {
+ goto cleanup;
+ }
+ memcpy(email, gen->d.ia5->data, gen->d.ia5->length);
+ email[gen->d.ia5->length] = 0;
+ break;
+ }
+ }
+ cleanup:
+ X509V3_EXT_cleanup();
+ if (ialt)
+ sk_GENERAL_NAME_free(ialt);
+
+ debug(F110,"X509_to_user() email",email,0);
+
+ if ( email[0] ) {
+ char * domain = NULL;
+
+ /* Find domain */
+ for ( i=0 ; email[i] ; i++ ) {
+ if ( email[i] == '@' ) {
+ email[i] = '\0';
+ domain = &email[i+1];
+ break;
+ }
+ }
+
+ if ( domain ) {
+ /* XXX - Put code to Verify domain here */
+
+ if ( /* domain is okay */ 1 )
+ ckstrncpy(userid,email,len);
+ }
+ }
+
+ return(userid[0] ? 0 : -1);
+ /* END EXAMPLE */
+#endif /* X509_SUBJECT_ALT_NAME_TO_USER */
+#endif /* X509_UID_TO_USER */
+ return -1;
+}
+
+/* The following function should be replaced by institution specific */
+/* code that will determine whether or not the combination of the */
+/* provided X509 certificate and username is valid for automatic */
+/* login. Whereas X509_to_user() is used to provide authentication */
+/* of the user, the X509_userok() function is used to provide */
+/* authorization. The certificate passed into X509_userok() does */
+/* need to map to a userid; nor would the userid it would map to */
+/* need to match the userid provided to the function. There are */
+/* numerous circumstances in which it is beneficial to have the ability */
+/* for multiple users to gain access to a common account such as */
+/* 'root' on Unix; or a class account on a web server. In Unix we */
+/* implement this capability with the ~userid/.tlslogin file which */
+/* a list of X509 certificates which may be used to access the */
+/* account 'userid'. */
+
+/* X509_to_user() returns 0 if access is denied; 1 is access is permitted */
+int
+X509_userok(X509 * peer_cert, const char * userid)
+{
+#ifndef VMS
+ /* check if clients cert is in "user"'s ~/.tlslogin file */
+ char buf[512];
+ int r = 0;
+ FILE *fp;
+ struct passwd *pwd;
+ X509 *file_cert;
+
+ if ( peer_cert == NULL )
+ return(0);
+
+ if (!(pwd = getpwnam(userid)))
+ return 0;
+ if (strlen(pwd->pw_dir) > 500)
+ return(0);
+ sprintf(buf, "%s/.tlslogin", pwd->pw_dir);
+
+ if (!(fp = fopen(buf, "r")))
+ return 0;
+ while (!r && (file_cert = PEM_read_X509(fp, NULL, NULL, NULL))) {
+ if (!ASN1_STRING_cmp(peer_cert->signature, file_cert->signature))
+ r = 1;
+ X509_free(file_cert);
+ }
+ fclose(fp);
+ return(r);
+#else /* VMS */
+ /* Need to implement an appropriate function for VMS */
+ return(0);
+#endif /* VMS */
+}
+#endif /* OS2 */
+#endif /* CK_SSL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ck_ssl.h b/ckermit-9.0.302-build/ckermit-9.0.302/ck_ssl.h
new file mode 100644
index 0000000..97b6544
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ck_ssl.h
@@ -0,0 +1,160 @@
+/*
+ C K _ S S L . H -- OpenSSL Interface Header for C-Kermit
+
+ Copyright (C) 1985, 2005,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Author: Jeffrey E Altman (jaltman@secure-endpoints.com)
+ Secure Endpoints Inc., New York City
+*/
+
+#ifdef CK_SSL
+#ifndef CK_ANSIC
+#define NOPROTO
+#endif /* CK_ANSIC */
+
+#ifdef COMMENT /* Not for C-Kermit 7.1 */
+#ifdef KRB5
+#ifndef NOSSLK5
+#ifndef SSL_KRB5
+#define SSL_KRB5
+#endif /* SSL_KRB5 */
+#endif /* NOSSLK5 */
+#endif /* KRB5 */
+#endif /* COMMENT */
+
+#ifdef OS2
+#ifndef ZLIB
+#define ZLIB
+#endif /* ZLIB */
+#endif /* OS2 */
+
+#ifdef ZLIB
+#include <openssl/comp.h>
+#endif /* ZLIB */
+/* We place the following to avoid loading openssl/mdc2.h since it
+ * relies on the OpenSSL des.h. Since we do not need the MDC2
+ * definitions there is no reason to have it included by openssl/evp.h
+ */
+#define OPENSSL_NO_MDC2
+#ifdef OPENSSL_100
+#define OPENSSL_098
+#endif /* OPENSSL_100 */
+#ifdef OPENSSL_098
+#define OPENSSL_097
+#endif /* OPENSSL_098 */
+#ifdef CK_DES
+#include <openssl/des.h>
+#endif /* CK_DES */
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/bn.h>
+#include <openssl/blowfish.h>
+#include <openssl/dh.h>
+#include <openssl/rc4.h>
+#include <openssl/cast.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#ifdef SSL_KRB5
+#include <openssl/kssl.h>
+#endif /* SSL_KRB5 */
+
+extern BIO *bio_err;
+extern SSL *ssl_con;
+extern SSL_CTX *ssl_ctx;
+extern int ssl_debug_flag;
+extern int ssl_only_flag;
+extern int ssl_active_flag;
+extern int ssl_verify_flag;
+extern int ssl_verbose_flag;
+extern int ssl_certsok_flag;
+extern int ssl_dummy_flag;
+extern int ssl_verify_depth;
+
+extern char *ssl_rsa_cert_file;
+extern char *ssl_rsa_cert_chain_file;
+extern char *ssl_rsa_key_file;
+extern char *ssl_dsa_cert_file;
+extern char *ssl_dsa_cert_chain_file;
+extern char *ssl_dh_key_file;
+extern char *ssl_cipher_list;
+extern char *ssl_crl_file;
+extern char *ssl_crl_dir;
+extern char *ssl_verify_file;
+extern char *ssl_verify_dir;
+extern char *ssl_dh_param_file;
+extern char *ssl_rnd_file;
+
+extern SSL_CTX *tls_ctx;
+extern SSL *tls_con;
+extern int tls_only_flag;
+extern int tls_active_flag;
+extern int x509_cert_valid;
+extern X509_STORE *crl_store;
+
+extern int ssl_raw_flag;
+extern int tls_raw_flag;
+
+#ifndef NOHTTP
+extern SSL_CTX *tls_http_ctx;
+extern SSL *tls_http_con;
+extern int tls_http_active_flag;
+#endif /* NOHTTP */
+
+extern int ssl_initialized;
+
+_PROTOTYP(VOID ssl_once_init,(void));
+_PROTOTYP(int ssl_tn_init,(int));
+_PROTOTYP(int ssl_http_init,(char *));
+_PROTOTYP(int ck_ssl_http_client,(int,char *));
+_PROTOTYP(int ssl_display_connect_details,(SSL *,int,int));
+_PROTOTYP(int ssl_server_verify_callback,(int, X509_STORE_CTX *));
+_PROTOTYP(int ssl_client_verify_callback,(int, X509_STORE_CTX *));
+_PROTOTYP(int ssl_reply,(int, unsigned char *, int));
+_PROTOTYP(int ssl_is,(unsigned char *, int));
+_PROTOTYP(int ck_ssl_incoming,(int));
+_PROTOTYP(int ck_ssl_outgoing,(int));
+_PROTOTYP(int tls_is_user_valid,(SSL *, const char *));
+_PROTOTYP(char * ssl_get_dnsName,(SSL *));
+_PROTOTYP(char * ssl_get_commonName,(SSL *));
+_PROTOTYP(char * ssl_get_issuer_name,(SSL *));
+_PROTOTYP(char * ssl_get_subject_name,(SSL *));
+_PROTOTYP(int ssl_get_client_finished,(char *, int));
+_PROTOTYP(int ssl_get_server_finished,(char *, int));
+_PROTOTYP(int ssl_passwd_callback,(char *, int, int, VOID *));
+_PROTOTYP(VOID ssl_client_info_callback,(const SSL *,int, int));
+_PROTOTYP(int ssl_anonymous_cipher,(SSL * ssl));
+_PROTOTYP(int tls_load_certs,(SSL_CTX * ctx, SSL * con, int server));
+_PROTOTYP(int ssl_verify_crl,(int, X509_STORE_CTX *));
+_PROTOTYP(int tls_is_krb5,(int));
+_PROTOTYP(int X509_userok,(X509 *,const char *));
+_PROTOTYP(int ck_X509_save_cert_to_user_store,(X509 *));
+/* SMS 2007/02/15 */
+_PROTOTYP(int ssl_check_server_name,(SSL * ssl, char * hostname));
+#ifdef OS2
+#include "ckosslc.h"
+#include "ckossl.h"
+#endif /* OS2 */
+
+#define SSL_CLIENT 0
+#define SSL_SERVER 1
+#define SSL_HTTP 2
+
+#define SSL_ERR_BFSZ 4096
+
+#ifdef SSL_KRB5
+#define DEFAULT_CIPHER_LIST "HIGH:MEDIUM:LOW:+KRB5:+ADH:+EXP"
+#else
+#define DEFAULT_CIPHER_LIST "HIGH:MEDIUM:LOW:+ADH:+EXP"
+#endif /* SSL_KRB5 */
+#endif /* CK_SSL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckaaaa.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckaaaa.txt
new file mode 100644
index 0000000..335ec7d
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckaaaa.txt
@@ -0,0 +1,380 @@
+ckaaaa.txt July 2011
+
+ C-KERMIT VERSION 9.0.301
+ OVERVIEW OF FILES
+
+ Communications software for UNIX and (Open)VMS.
+
+ And in former versions also for:
+ Stratus VOS, AOS/VS, QNX,
+ Plan 9, OS-9, Apollo Aegis, and the Commodore Amiga.
+ The Apple Macintosh, the Atari ST.
+
+ The Kermit Project - Columbia University
+
+ http://kermit.columbia.edu/ - kermit@columbia.edu
+
+
+ Copyright (C) 1985, 2011,
+ 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.
+ BRIEFLY: C-Kermit 9.0 has the OPEN SOURCE 3-clause MODIFIED BSD LICENSE.
+
+
+DOCUMENTATION
+
+ C-Kermit is documented in the book "Using C-Kermit", Second Edition, by
+ Frank da Cruz and Christine M. Gianone, Digital Press, ISBN 1-55558-164-1,
+ supplemented by Web-based updates for C-Kermit 7.0, 8.0, and 9.0.
+
+PLATFORMS
+ Security
+ Name Included Last Updated
+
+ Unix Yes 9.0.300 30 Jun 2011
+ (Open)VMS Yes 9.0.300 30 Jun 2011
+ Windows (K95) Yes 8.0.208 14 Mar 2003 (K95 2.1)
+ OS/2 (K95) Yes 8.0.208 14 Mar 2003 (K95 2.1)
+ DG AOS/VS No 7.0.196 1 Jan 2000
+ Stratus VOS No 7.0.196 1 Jan 2000
+ Bell Plan 9 No 7.0.196 1 Jan 2000
+ Microware OS-9 No 7.0.196 1 Jan 2000
+ Commodore Amiga No 7.0.196 1 Jan 2000
+ Macintosh No 5A(190) 16 Aug 1994 (Mac Kermit 0.991)
+ Atari ST No 5A(189) 30 Jun 1993
+
+QUICK START FOR FTP USERS
+
+ If you have a Web browser, go to:
+
+ http://www.columbia.edu/kermit/ckermit.html
+
+ And take it from there. Otherwise...
+
+ The definitive FTP source for Kermit software is kermit.columbia.edu.
+ Kermit software obtained from other FTP sites is not necessarily complete
+ or up to date, and may have been modified.
+
+C-Kermit for UNIX computers that have a C compiler and 'make' program:
+
+ Directory kermit/archives, binary mode, file cku211.tar.Z or cku211.tar.gz
+
+ This is a compressed tar archive of UNIX C-Kermit source code, makefile, and
+ other files. It unpacks into its current directory, so download it into a
+ fresh directory. Transfer in binary mode, uncompress (or gunzip), untar (tar
+ xvf cku211.tar), and then give the appropriate "make" command to build for
+ your UNIX system; read the comments in the makefile and ckuins.txt for
+ further info.
+
+C-Kermit for VMS:
+
+ If you have VMS UNZIP, get the file kermit/archives/ckv211.zip in binary
+ mode, unzip -aa, and build with CKVKER.COM (@ckvker.com). Read the comments
+ at the top of CKVKER.COM for details.
+
+Others: In the kermit/f or kermit/test directories under the appropriate
+prefixes, explained below.
+
+
+INSTALLATION
+
+Installation procedures depend on the operating system. Please read the
+CK?INS.TXT, if any, file for your operating system (?=U for UNIX, V for VMS,
+etc). Please note the naming and placement for the initialization files:
+
+ CKERMIT.INI
+ .kermrc in the user's home directory (UNIX).
+ CKERMIT.INI in the user's home directory (other OS's).
+
+
+ CKERMOD.INI
+ .mykermrc in the user's home directory (UNIX).
+ CKERMOD.INI elsewhere.
+
+ DIALING DIRECTORIES
+ Dialing directory files can be system-wide, per-group, or per-user, or
+ any combination. For example, there can be a corporate wide directory
+ shared by all users, a supplemental directory for each division or
+ department, and a personal directory for each user. Simply be sure the
+ dialing directory files are identified a SET DIAL DIRECTORY command in
+ the user's (or the system-wide) C-Kermit initialization file, or in the
+ environment variable (logical name, symbol) K_DIAL_DIRECTORY. (The
+ standard initialization file looks by default in the user's home or login
+ directory.) When installing C-Kermit on multiuser platforms from which
+ users will dial out, you can also set environment variables for area
+ code, country code, and the various dialing prefixes as described on page
+ 478 of "Using C-Kermit" (second edition), so users don't have to worry
+ about defining these items themselves. Network directories and service
+ directories can also be set up in a similar manner.
+
+ DOCUMENTATION
+ In UNIX, the general C-Kermit man page (or one of the versions tailored
+ for a specific platform, like HP-UX or Solaris) should be installed in
+ the appropriate place. In VMS, the VMS help topic (CKVKER.HLP) should
+ be installed as described in CKVINS.TXT. Plain-text documentation such
+ as CKERMIT2.TXT should be put in whatever place people are accustomed
+ to looking.
+
+FILES AND FILE NAMING CONVENTIONS
+
+C-Kermit is a family of Kermit programs for many different computer systems.
+The program shares a common set of system-independent file transfer protocol
+modules, written in the C language. System-dependent operations are collected
+into system-specific modules for each system.
+
+C-Kermit file names all start with the letters "CK", followed by a single
+letter indicating the subgroup. When referring to these files in the UNIX,
+AOS/VS, or VOS environments, use lowercase letters, rather than the uppercase
+letters shown here. Subgroups:
+
+ _: Security/Authentication/Encryption code, possibly regulated by law
+ a: General descriptive material and documentation
+ b: BOO file encoders and decoders (obsolete)
+ c: All platforms with C compilers
+ d: Data General AOS/VS
+ e: Reserved for "ckermit" files, like CKERMIT.INI, CKERMIT80.TXT
+ f: (reserved)
+ g: (reserved)
+ h: (reserved)
+ i: Commodore Amiga (Intuition)
+ j: (unused)
+ k: (unused)
+ l: Stratus VOS
+ m: Macintosh with Mac OS
+ n: Microsoft Windows NT
+ o: OS/2 and/or Microsoft Windows 95/98/ME/NT/2000/XP/...
+ p: Bell Labs Plan 9
+ q: (reserved)
+ r: DEC PDP-11 with RSTS/E (reserved)
+ s: Atari ST GEMDOS (last supported in version 5A(189))
+ t: DEC PDP-11 with RT-11 (reserved)
+ u: UNIX or environments with UNIX-like C libraries
+ v: VMS and OpenVMS
+ w: Wart (Lex-like preprocessor, used with all systems)
+ x: (reserved)
+ y: (reserved)
+ z: (reserved)
+ 0-3: (reserved)
+ 4: IBM AS/400 (reserved but probably never will be used)
+ 5-8: (reserved)
+ 9: Microware OS-9
+
+Examples:
+
+ ckaaaa.txt - This file
+ ckufio.c - File i/o for UNIX
+ ckstio.c - Communications i/o for the Atari ST
+ makefile - makefile for building UNIX C-Kermit
+ ckpker.mk - makefile for building Plan 9 C-Kermit
+ ckvker.com - build procedure for VMS C-Kermit
+
+IMPORTANT FILES (use lowercase names on UNIX, VOS, or AOS/VS):
+
+ ckaaaa.txt - This file (overview of the C-Kermit files).
+ For system-specific distributions, this will normally
+ be replaced by a system-specific READ.ME file.
+
+ ckermit70.txt - Updates: Supplement to "Using C-Kermit", 2nd Ed, for 7.0.
+ ckermit80.txt - Updates: Supplement to "Using C-Kermit", 2nd Ed, for 8.0.
+ ckututor.txt - C-Kermit Tutorial for Unix (plain text)
+ ckcbwr.txt - "Beware file" (limitations, known bugs, hints), general.
+ ckermit.ini - Standard initialization file (rename to .kermrc in UNIX, OS-9)
+ ckermod.ini - Sample customization file (rename to .mykermrc in UNIX, OS-9)
+
+The following can be found at the Kermit FTP site:
+
+ ckermit.kdd - Sample dialing directory file (rename to .kdd in UNIX, OS-9)
+ ckermit.knd - Sample dialing directory file (rename to .knd in UNIX, OS-9)
+ ckermit.ksd - Sample services directory file (rename to .ksd in UNIX, OS-9)
+ ckedemo.ksc - Demonstration macros from "Using C-Kermit"
+ ckepage.ksc - Ditto
+ ckevt.ksc - Ditto
+
+UNIX-specific files:
+
+ ckuins.txt - UNIX-specific installation instructions.
+ ckubwr.txt - UNIX-specific beware file.
+ ckuker.nr - "man page" for UNIX.
+
+VMS-specific files:
+
+ ckvins.txt - VMS-specific installation instructions.
+ ckvbwr.txt - VMS-specific beware file
+ ckvker.hlp - VMS C-Kermit HELP topic (needs updating).
+
+DG AOS/VS-specific files:
+
+ ckdins.txt - Data General AOS/VS C-Kermit installation instructions
+ ckdbwr.txt - AOS/VS "beware" file
+ ckd*.cli - Procedures for building AOS/VS C-Kermit
+
+The following files are of interest mainly to programmers and historians
+(find them at the Kermit ftp site in the kermit/f directory):
+
+ ckcker.ann - Release announcements.
+ ckccfg.txt - Configuration information (feature selection), general.
+ ckcplm.txt - Program logic manual (for programmers).
+ ckc300.txt - Program update history for edit 212-300 (C-Kermit 9.0).
+ ckc211.txt - Program update history for edit 201-211.
+ ckc200.txt - Program update history for edit 198-200 (big)
+ ckc197.txt - Program update history for edit 195-197 (big)
+ ckc190.txt - Program update history for edits 189-190 (big).
+ ckc188.txt - Program update history, edits 179-188 (big).
+ ckc178.txt - Program edit history, 5A edits through 178 (very big).
+ ckcv4f.txt - Program edit history, version 4F.
+ ckcv4e.txt - Program edit history, version 4E.
+
+BINARIES
+
+If you have FTP access to kermit.columbia.edu (also known as
+kermit.cc.columbia.edu, ftp.cc.columbia.edu), you can also retrieve various
+C-Kermit binaries from the directory kermit/bin/ck*.*, or more conveniently
+from the web page:
+
+ http://www.columbia.edu/kermit/ck80binaries.html
+
+Test versions would be in kermit/test/bin/ck*.*. Be sure to transfer these
+files in binary mode. The READ.ME file in that directory explains what's
+what.
+
+SOURCE FILES
+
+The source files for the UNIX version (all UNIX versions) are available in
+kermit/archives/ckuNNN.tar.Z, approximately 1MB in size. Transfer this file
+in binary mode. This is a compressed tar archive. There is also a gzip'd
+version, cku211.tar.gz. To get the binary tar archive:
+
+ mkdir kermit (at shell prompt, make a Kermit directory)
+ cd kermit (make it your current directory)
+
+ ftp kermit.columbia.edu (make an ftp connection)
+ user: anonymous (log in as user "anonymous", lower case!)
+ password: (use your email id as a password)
+ cd kermit/archives (go to the archives directory)
+ type binary (specify binary file transfer)
+ get cku300.tar.Z (get the tar archive) (or get cku192.tar.gz)
+ bye (disconnect and exit from ftp)
+
+ uncompress cku300.tar.Z (at the shell prompt, uncompress the archive)
+ tar xvf cku300.tar (extract the files from the tar archive)
+ make xxx (build C-Kermit for your system)
+
+(where "xxx" is the makefile entry appropriate for your system.)
+
+All C-Kermit source and other text files are also kept separately in the
+kermit/f directory. The files necessary to build a particular implementation
+of C-Kermit are listed in the appropriate makefile or equivalent:
+
+ UNIX: makefile (or rename ckuker.mak to makefile)
+ 2.11 BSD: ckubs2.mak (rename to makefile), ckustr.sed
+ Plan 9: ckpker.mk (rename to mkfile)
+ Macintosh: ckmker.mak (rename to kermit.make, use MPW C 3.2)
+ VMS: CKVKER.COM (DCL) (and optionally also CKVKER.MMS)
+ or CKVOLD.COM (for VMS 4.x)
+ Amiga: CKIKER.MAK (Aztec C) or CKISAS.MAK (SAS C)
+ Atari ST: CKSKER.MAK
+ OS-9: ck9ker.mak or ck9ker.gcc
+ AOS/VS: ckdmak.cli, ckdcc.cli, ckdlnk.cli
+Stratus VOS: cklmak.cm
+
+Minimal source files for building selected versions (these patterns get all
+the files you need, and in some cases maybe a few extra):
+
+ UNIX: ck[cuw]*.[cwh] (including QNX, Plan 9, and BeBox)
+ UNIX: ck[cuw_]*.[cwh] (Unix with security modules)
+ VMS: ck[cuwv]*.[cwh] VMS
+ VMS: ck[cuwv_]*.[cwh] VMS with SSL/TLS
+ Mac: ck[cuwm]*.[cwhr] Old Mac OS, not Mac OS X, which is UNIX.
+ AOS/VS: ck[cuwd]*.[cwh]
+ VOS: ck[cwhl]*.[cwh]
+ Amiga: ck[cuwi]*.[cwh]
+ Atari: ck[cuws]*.[cwh]
+ OS-9: ck[cuw9]*.[cwha]
+
+Finally, here is a more detailed description of the C-Kermit file naming
+conventions. A C-Kermit filename has the form:
+
+ CK<system><what>.<type>
+
+where:
+
+<system> is described earlier in this file;
+
+<type> is the file type (use lowercase on UNIX, VOS, or AOS/VS):
+
+ c: C language source
+ h: Header file for C language source
+ w: Wart preprocessor source, converted by Wart (or Lex) to a C program
+ r: Macintosh resource file (8-bit text)
+ a: Assembler source
+
+ txt: Plain text.
+ nr: Nroff/Troff text formatter source for UNIX "man page"
+ mss: Scribe text formatter source
+ ps: Typeset material to be printed on a PostScript printer
+ pdf: An Adobe PDF file
+ hlp: A VMS Help topic
+
+ ini: Initialization file
+ ksc: A Kermit Script to be executed by the TAKE command
+ kdd: A Kermit Dialing Directory
+ knd: A Kermit Network Directory
+ ksd: A Kermit Services Directory
+
+ mak: A Makefile or other build procedure (often needs renaming)
+ com: (VMS only) a DCL command procedure
+ cli: (AOS/VS only) a command procedure
+ cmd: (OS/2 only) a Rexx command procedure
+
+ boo: "boo"-encoded executable program, decode with CKBUNB program.
+ hex: "hex"-encoded executable program, decode with CKVDEH program (VMS only).
+ hqx: BinHex'd Macintosh Kermit program, decode with BinHex version 4.0.
+ uue: A uuencoded binary file, decode with uudecode or (DG only) CKDECO.
+
+ def: An OS/2 linker definitions file.
+ sh: A UNIX shell script.
+ sed: A UNIX sed (editor) script.
+ str: A file of character strings extracted from C-Kermit (BSD 2.1x only).
+
+<what> is mnemonic (up to 3 characters) for what's in the file:
+
+NOTE: After C-Kermit 6.0, text filetypes such as .DOC and .HLP were changed
+to .TXT to avoid confusion in Windows-based Web browsers, which would
+otherwise mistake them for Microsoft Word or Windows Help documents.
+
+ aaa: A "read-me" file, like this one
+ ins: Installation instructions or procedures
+ bwr: "Beware" file -- things to watch out for, hints and tips
+ plm: Program Logic Manual
+ ker: General C-Kermit definitions, information, documentation
+
+ nnn: Digits: C-Kermit edit number (e.g. cku300.tar.gz)
+ cmd: Command parsing
+ con: CONNECT command
+ cns: CONNECT command (UNIX only - version that uses select(), not fork())
+ deb: Debug/Transaction Log formats, Typedefs
+ dia: Modem/Dialer control
+ fio: System-dependent File I/O
+ fns: Protocol support functions
+ fn2: More protocol support functions (and FN3, ...)
+ lib: Common library routines module
+ mai: Main program
+ net: Network i/o module
+ pro: Protocol
+ scr: SCRIPT command
+ tel: Telnet protocol module
+ tio: System-dependent communications i/o & control and interrupt handing
+ sig: Signal handling module
+ usr: Interactive/script user interface
+ us2: More user interface (mainly help text)
+ us3: Still more user interface (and USR4, USR5, USR6, USR7)
+ usx: Common user interface functions
+ usy: Command-line parsing
+ xla: Character set translation module
+ uni: Unicode support
+ pty: Pseudoterminal support
+ mdb: Malloc-debugging module (not included in real builds)
+ str: Strings module (only for 2.xBSD)
+
+(End of ckaaaa.txt)
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckc302.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckc302.txt
new file mode 100644
index 0000000..13a661a
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckc302.txt
@@ -0,0 +1,7881 @@
+C-KERMIT 9.0 CHANGE LOG (Changes since 8.0.207 / K95 2.1.3 January 2003)
+
+ Chronological order.
+ Go to the bottom to find the newest edits.
+
+ F. da Cruz, The Kermit Project, Columbia University, NYC.
+ Last update: 28 June 2011.
+
+FTP USER, FTP ACCOUNT, plus the various prompts and switches for FTP username,
+password, and account all neglected to strip quotes, and in most cases quotes
+are necessary to specify a username that contains spaces. ckcftp.c,
+15 Jan 2003.
+
+FTP MPUT f1 f2 f3... gets a parse error if any of the fn's do not match an
+existing file. This is bad for scripts. In doftpput(), cmfdb() looks for
+keywords (switches) or CMIFI. When it hits CMIFI, it exits from the initial
+parse loop and then does additional cmifi()s in a loop until done. The most
+obvious fix is to parse each field with cmfdb(CMIFI,CMFLD), i.e. fall back to
+CMFLD if CMIFI doesn't match anything. Then if CMFLD was used, we don't add
+the filespec to the list. This is a rather big change but it seems to work.
+No error messages or failures happen for non-matching fields, but an error
+message is printed (and the MPUT command fails) if none of the fields match
+any files. This fix got in too late for 2.1.3; workaround: use C-Shell
+like wildcard list (ftp mput "{*.abc,foo.*}"). ckcftp.c, 16 Jan 2003.
+
+GREP did not pass its pattern through the expander, thus variables could
+not be used for patterns. This must have been an oversight -- I can't find
+anything in my notes about it. Fixed in dogrep(): ckuus6.c, 24 Jan 2003.
+
+New makefile target for HP-UX 11.xx with OpenSSL from Tapani Tarvainen.
+makefile, 31 Jan 2003.
+
+From Jeff:
+ . Avoid core dump when dereferencing tnc_get_signature(): ckuus4.c.
+ . Bump version numbers to 8.0.208, 2.1.4: ckcmai.c.
+
+Added /NOLOGIN to FTP [OPEN]. ckcftp.c, 10 Feb 2003.
+
+Don't dump core if FTP DEBUG is ON and FTP OPEN does not include a service.
+openftp(): ckcftp.c, 10 Feb 2003.
+
+HELP PATTERN text incorrectly identified commands and functions with
+floating and anchored patterns. The corrected lists are:
+Floating: GREP, TYPE /MATCH:, /EXCEPT: patterns, \farraylook(),
+Anchored: IF MATCH, file-matching wildcards, \fsearch(), \frsearch()
+ckuus2.c, 10 Feb 2003.
+
+INPUT n \fpattern(xxx) did not work for case-independent comparisons.
+Fixed in doinput(): ckuus4.c, 10 Feb 2003.
+
+It seems \fpattern() didn't work with MINPUT at all. There was no code to
+handle \fpattern() in the MINPUT parse loop, so it never worked. The code
+had to be totally rewritten to use cmfld() in a loop, rather than cmtxt()
+and then cksplit(). Furthermore, whenever any of the fields was an
+\fjoin(), this had to be split. ckuusr.c, 10 Feb 2003.
+
+Macro replacement via \m() and \fdefinition() does not work as advertised
+(i.e. case sensitively) for associative array elements; e.g. \m(xxx<abc>) is
+treated the same as \m(xxx<ABC>), contrary to section 7.10.10 of the C-Kermit
+7.0 update notes, and to the fact that the two really do exist separately.
+Fixed by adding a static function isaarray(s) which succeeds if s is an
+associative array reference and fails otherwise, and then having \m()
+and \fdef() call mxxlook() (case-sensitive lookup) if isaarray(), otherwise
+(as before) mxlook()). ckuus4.c, 11 Feb 2003.
+
+Fixed FTP OPEN to allow the /USER switch to override SET FTP AUTOLOGIN OFF,
+just as /NOLOGIN overrides SET FTP AUTOLOGIN ON. ckcftp.c, 11 Feb 2003.
+
+In K95, "set key \1234 \27H" (any SET KEY command in which the first char of
+the definition was backslash, and the ONLY character after the backslash
+quantity was an uppercase letter, that letter would be lowercased). Diagnosis:
+xlookup() poking its argument (see notes from July 2000). Jeff sent a fix.
+ckucmd.c, 15 Feb 2003.
+
+Ran my S-Expression torture test to make sure Sexps still worked. They do,
+except the bitwise & and | operators were broken, e.g. (& 7 2) and (| 1 2 4)
+get "Invalid operand" errors. Jeff's code had added an early failure return
+from the lookup loop when when a single-byte keyword matched a keyword that
+started with the same byte but was more than one byte long. So "&" would hit
+"&&" and fail instead of continuing its search (xlookup tables aren't sorted
+so there can be no early return). Fixed in xlookup(): ckucmd.c, 16 Feb 2003.
+
+Got rid of "krbmit" target from makefile. It's still there, but we don't
+use it any more. All secure targets now use "xermit", and produce a binary
+called wermit, just like the regular ones do (except the old ckucon.c ones).
+Non-secure targets, since they don't define any of the security symbols,
+wind up compiling and linking to (mostly) empty security modules. makefile,
+15 Feb 2003.
+
+Added \fcvtdate(xxx,3) to format its result in MDTM format (yyyymmddhhmmss,
+all numeric, no spaces or punctuation). Of course these numeric strings
+are too big to be 32-bit numbers and are useless for arithmetic, but they're
+useful for lexical comparison, etc. ckuus[24].c, 16 Feb 2003.
+
+The following FTP commands did not set FAILURE when they failed: RMDIR,
+CD, CDUP, Fixed in the corresponding doftpblah() routines. ckcftp.c,
+16 Feb 2003.
+
+RENAME would sometimes not print an error message when it failed, e.g. in K95
+when the destination file already existed. ckuus6.c, 17 Feb 2003.
+
+Fixed COPY error messages, which did not come out in standard format when
+/LIST was not included. ckuus6.c, 17 Feb 2003.
+
+Fixed #ifdefs in ck_crp.c to allow nonsecure builds on old platforms like
+System V/68 R3. 19 Feb 2003.
+
+Similar treatment for ck_ssl.c. 20 Feb 2003.
+
+From Jeff, 21 Feb 2003:
+ . AIX53 and AIX52 symbols for ckcdeb.h, makefile.
+ . New gcc targets for various AIX 4.x/5.x versions: makefile.
+ . Copyright date updates: ck_crp.c, ck_ssl.c.
+ . ENABLE/DISABLE QUERY broken because keyword table out of order: ckuusr.c.
+ . Fixed the use of HTTP proxies for HTTP [RE]OPEN for Unix: ckcnet.c.
+
+Also for K95 only: Allow file transfer when K95 is invoked on the remote end
+of a connection to a Pragma Systems Terminal Server connection; automatically
+SET EXIT HANGUP OFF when invoked with open port handle ("k95 -l nnnn").
+
+"cd a*" failed even when "a*" matched only one directory. Fixed in cmifi():
+ckucmd.c, 21 Feb 2003.
+
+In the Unix version, replace "extern int errno;" with "#include <errno.h>"
+if __GLIBC__ is defined, since glibc now defines a thread-specific errno.
+ckcdeb.h, 26 Feb 2003.
+
+Added #ifdefs to skip compilation of ckuath.c in nonsecure builds. Tested
+by building both secure and regular versions in Linux. ckuath.c, 26 Feb 2003.
+
+Ran the build-in-84-different-configurations script on Linux to make sure it
+still builds with all different combinations of feature selection options.
+All OK. 26 Feb 2003.
+
+Built on VMS. Needed to add a prototype for mxxlook*() to ckuusr.h; built
+OK otherwise. 26 Feb 2003.
+
+From Jeff: More #ifdef shuffling for nonsecure builds: ckuath.c, ck_ssl.c,
+27 Feb 2003.
+
+Added code to ensure \v(download) ends in a directory separator in Unix,
+Windows, and OS/2. ckuus7.c, 27 Feb 2003.
+
+Added code to K95 zfnqfp() to tack on directory separator when returning
+a directory name. ckofio.c, 27 Feb 2003.
+
+Somehow an old copy of ckuath.c popped to replace the new one. Put the new
+one back. 28 Feb 2003.
+
+From Jeff: Fix typo in my K95 zfnqfp() code from yesterday; fixes for handling
+UNCs uniformly, no matter which way their slashes are leaning. ckofio.c,
+28 Feb 2003.
+
+At Jeff Mezei's suggestion, separate text and binary mode open sequences
+for VMS session log. ckvfio.c, 28 Feb 2003.
+
+Added freebsd48 target for FreeBSD 4.8. makefile, 1 Mar 2003.
+
+Changed Mac OS X entries to include -DUSE_STRERROR. makefile, 2 Mar 2003.
+
+Fixed GETOK /GUI to evaluate its text argument. ckuus6.c, 3 Mar 2003.
+
+Jeff fixed the K95 Dialer QUICK dialog to (a) allow templates, and (b) have
+a Save-As option. 3 Mar 2003.
+
+Jeff fixed a problem with the Xmodem-CRC checksum being crunched whenever
+there was a retransmission. 7 Mar 2003.
+
+Added target/banner for Tru64 5.1B. makefile, ckuver.h, 5 Mar 2003.
+
+In Unix, the zcopy() routine (used by the COPY command) reset the user's umask
+to 0 for the remainder of the Kermit process lifetime. The bug was in
+ckufio.c 8.0.194, 24 Oct 2002, and is fixed in ckufio.c 8.0.195, 6 Mar 2003.
+Of course this happened after building 155 C-Kermit 8.0.208 binaries. (But
+before officially releasing 8.0.208.)
+
+In the VMS version, changed:
+
+ while ((n--) && xx_inc(2) > -1) ;
+to:
+ while ((n--) && xx_inc(2) >= 0) ;
+
+to suppress the "...is being compared with a relational operator to a constant
+whose value is not greater than zero" warning. ckvtio.c, 7 Mar 2002.
+
+Added a debug call to dologend in hopes of catching overzealous Locus
+switching, which seems to happen only in K95. ckuus3.c, 7 Mar 2002.
+
+Rebuilt binaries for some of the more current Unix releases: AIX 4.3.3-5.1,
+Solaris 7-9 , Red Hat 7.0-8.0, Slackware 8.1, Freebsd 4.7-4.8, NetBSD 1.6,
+OpenBSD 3.2, Unixware 7.1.3, Open Unix 8, OSR5.0.6a, etc. A Unix binary with
+COPY umask fix shows a 6 Mar 2003 date for "UNIX File support" in SHOW
+VERSIONS; a binary without the fix shows 24 Oct 2002.
+
+C-Kermit 8.0.208 dated 14 March 2003 released on 10 March 2003.
+
+---8.0.208---
+
+From Jeff 13 Mar 2003:
+ . Updated SSL module allows importation of tickets from host.
+ . freebsd50+openssl target: makefile.
+ . FTP PUT /PERMISSIONS error message for K95: ckcftp.c.
+
+Fixed MINPUT to strip quotes or braces from around targets (this was broken
+on Feb 10th). Thanks to Jason Heskett for discovering and reporting this
+(killer) bug. ckuusr.c, 14 Mar 2003.
+
+Changed version number to 209 Dev.00. ckcmai.c, 14 Mar 2003.
+
+While debugging the alphapage script, I found that the command "minput 8 \6\13
+\21\13 \13\27\4\13 \30\13" gets "?Not confirmed" in 8.0.208 and 8.0.209, but
+not in 206 and earlier. This problem too was introduced on Feb 10th by
+changing MINPUT parsing from cmtxt() followed by cksplit() to cmfld() in a
+loop. cmfld() uses setatm() to return its result and of course setatm()
+breaks on \13. Changing setatm() not to do this would break everything else.
+But cmfld() has no arguments that let us tell it to do anything different in
+this case. Changing the API would be a disaster. The only solution is to add
+an "MINPUT ACTIVE" (minputactive) global variable that tells cmfld() to tell
+setatm() not to break on CR. Now MINPUT with braced targets containing CR
+and/or LF works in 209, 206, and 201 (but not 208). ckucmd.c, ckuusr.c,
+ckuus5.c, 15 Mar 2003.
+
+MINPUT n \fjoin(&a) works OK if all the members of \&a[] are text strings, but
+if they are strings of control chars (as above), they don't get separated by
+the spaces. For example in:
+
+ dcl \&a[] = "\4\5" "\6\7" xxx
+ minput 10 \fjoin(&a)
+
+MINPUT gets two targets: "aaa" and "\4\5 \6\7 xxx". The bug was in the
+cksplit() call in the \fjoin() case of MINPUT: it needed to specify an
+include set consisting of all the control characters except NUL. ckuusr.c,
+16 Mar 2003.
+
+But there's still a problem:
+
+ dcl \&a[] = "\4\5\13\10" "\6\7" "xxx"
+
+creates an array whose first member is "^D^E (one doublequote included). But
+if braces are used instead, there's no problem. Same deal as MINPUT: cmfld()
+breaks on CR or LF, thus the end quote is lost. If I set minputactive for
+DECLARE initializers too, that fixes it. Is there any reason not to do this?
+Can't think of any (famous last words)... ckuusr.c, 16 Mar 2003.
+
+Since it has multiple applications, changed the flag's name from minputactive
+to keepallchars. ckucmd.c, ckuus[r5].c, 16 Mar 2003.
+
+\v(exedir) wasn't being set correctly (it included the program name as well
+as the directory). Fixed in getexedir(): ckuus4.c, 16 Mar 2003.
+
+SET CARRIER-WATCH <Esc> "auto matic" (spurious space in supplied keyword).
+Cosmetic only; it still worked. Fixed in setdcd(): ckuus3.c, 16 Mar 2003.
+
+"directory a b c" listed too many files -- all files whose names END WITH a,
+b, or c, rather than the files whose names WERE a, b, or c. Diagnosis: The
+filespec is changed into a pattern: {a,b,c}, which is the correct form. It is
+passed to nzxpand(), which goes through the directory getting filenames and
+sending each one to ckmatch() with the given pattern. ckmatch() receives the
+correct pattern but then prepends a "*" -- that's not right. It's not just
+in filename matching either. The following succeeds when it shouldn't:
+
+ if match xxxxc {{a,b,c}} <command>
+
+Changing ckmatch() to not prepend the "*" to each segment fixes the command
+above but breaks lots of others. Running through the "match" torture-test
+script shows the problem occurs only when the {a,b,c} list is the entire
+pattern, and not embedded within a larger pattern. Testing for this case
+fixed the problem. ckmatch(): ckclib.c, 16 Mar 2003.
+
+Fixed FTP MODTIME to not print anything if QUIET ON. ckcftp.c, 16 Mar 2003.
+
+Picked up a new ckuath.c from Jeff, not sure what the changes are. 16 Mar 2003.
+
+Did a few regular and secure builds to make sure I didn't wreck anything.
+
+Changed version number to 209 (final). ckcmai.c, 16 Mar 2003.
+
+Jason Heskett found another bug: if you define a macro FOO inside the
+definition of another macro BAR, and FOO's definition includes an odd number
+of doublequotes (such as 1), FOO's definition absorbs the rest of BAR's
+definition. Example:
+
+ def TEST {
+ .foo = {X"}
+ sho mac foo
+ }
+ do test
+ sho mac foo
+
+Results in:
+
+ foo = {X"}, sho mac foo
+
+Diagnosis: the TEST definition becomes:
+
+ def TEST .foo = {X"}, sho mac foo
+
+and the macro reader is erroneously treating the doublequote as an open
+quote, and then automatically closes the quote at the end of the definition.
+The error is that a doublequote should be significant only at the beginning of
+a field. But the macro reader isn't a command parser; it doesn't know what
+a field is -- it's just looking for commas and skipping over quoted ones.
+First we have to fix an oversight: SET COMMAND DOUBLEQUOTING OFF should have
+worked here, but it wasn't tested in this case. Fixed in getncm(): ckuus5.c,
+17 Mar 2003.
+
+There are only certain cases where it makes sense to treat doublequotes as
+significant:
+
+ . An open quote must be at the beginning or preceded by a space.
+ . A close quote is only at the end or else followed by a space.
+
+This too was fixed in getncm(): ckuus5.c, 17 Mar 2003.
+
+A fix from Jeff SSL/TLS FTP data decoding. ckcftp.c, 18 Mar 2003.
+
+Tried building C-Kermit on a Cray Y-MP with UNICOS 9.0. "int suspend",
+declared in ckcmai.c and used in many modules, conflicts with:
+
+ unistd.h:extern int suspend __((int _Category, int _Id));
+
+The "=Dsuspend=xsuspend" trick doesn't work for this; there is no way around
+the conflict other than to rename the variable: ckcmai.c, ckutio.c,
+ckuus[35xy].c. 26 Mar 2003. VMS and K95 not affected.
+
+OK that gets us past ckcmai.c... Then in ckutio.c I had to add a new #ifdef
+around the LFDEVNO setting, because the Cray didn't have mkdev.h. Could not
+find a Cray-specific manifest symbol, so I made a new makefile target (cray9)
+that sets this symbol. Having done this I have no idea what kind of lockfile
+would be created, but I also doubt if anybody dials out from a Cray. The
+binary should run a C90, J90, or Y-MP. makefile, 26 Mar 2003.
+
+Added a target for SCO OSR5.0.7. makefile, ckuver.h, 30 Mar 2003.
+
+Changed since 208:
+makefile ckuver.h ckcmai.c ckclib.c ckcftp.c ckucmd.c ckuus*.c ckutio.c.
+
+---8.0.209---
+
+From Mark Sapiro, a fix for the March 17th doublequote fix, getncm(): ckuus5.c,
+4 Apr 2003.
+
+From Jeff, 29 Apr 2003:
+ . Corrected target for HP-UX 11.00 + OpenSSL: makefile,
+ . Do not allow WILL AUTH before WONT START_TLS: ckctel.h ckctel.c
+ . Add hooks for SFTP and SET/SHOW SFTP: ckcdeb.h ckuusr.h ckuusr.c ckuus3.c
+ . Add SKERMIT ckuusr.h ckuusr.c
+ . Add ADM-5 terminal emulation: ckuus7.c, ckuus5.c
+ . Uncomment and update HELP SET SSH V2 AUTO-REKEY: ckuus2.c
+ . Enable IF TERMINAL-MACRO and IF STARTED-FROM-DIALER for C-Kermit: ckuus6.c
+ . Fix conflicting NOSCROLL keyword definition: ckuusr.h
+ . Set ttname when I_AM_SSH: ckuusy.c
+ . Add extended arg parsing for SSH, Rlogin, Telnet: ckuusy.c, ckuus4.c
+ . Security updates: ckuath.c, ck_ssl.c
+ . Change K95 version number to 2.2.0: ckcmai.c
+ . Save K95 term i/o state before executing keyboard macro: ckuus4.c
+ . Add tests for SSH Subsystem active during INPUT/OUTPUT/CONNECT: ckuus[45].c
+ . Enable K95 SET SSH V2 AUTO-REKEY: ckuus3.c
+
+SFTP and SET SFTP subcommands are implemented up to the case statements.
+
+Files of mine that Jeff hadn't picked up:
+ ckuver.h ckcftp.c ckutio.c ckuusx.c (just minor changes for last build-all)
+
+On 4 Jan 2003, SET RECEIVE MOVE-TO was changed to convert is argument to an
+absolute path, which made it impossible to specify a relative path, then
+move to different directories and have it apply relatively to each directory.
+Changed this as follows:
+
+ . Parser uses cmtxt() rather than cmdir() so it won't fail at parse time.
+ . If path is absolute, we fail at parse time if directory doesn't exist.
+ . In reof() we run the the path through xxstring (again, in case deferred
+ evaluation of variables is desired) and then, if not null, use it.
+ . If the directory doesn't exist, rename() fails and reof() returns -4,
+ resulting in a protocol error (this is not a change). We do NOT create
+ the directory on the fly.
+
+I also fixed SET SEND/RECEIVE RENAME-TO to parse with cmtxt() rather than
+cmdir(), since it's parsing a text template, not a directory name, e.g.
+"set receive rename-to file-\v(time)-v(date)-\v(pid)". This was totally
+broken, since when I don't know. We don't call xxstring() in this parse, so
+evaluation is always deferred -- I'd better not change this. ckuus7.c,
+ckcfns.c, 1 May 2003.
+
+From Jeff, Sat May 3 14:15:23 2003:
+ . Pick up the right isascii definition for K95: ckctel.c
+ . malloc... ckuath.c (new safe malloc routines for K95)
+ . Add author listing: ckuus5.c
+ . SSH Heartbeat support (K95 only): ckuus[23].c
+ . Prescan --height and --width to avoid window resizing at startup: ckuusy.c
+ . Add checks for fatal() or doexit() called from sysinit(): ckuusx.c
+ . Move some K95-specific definitions to ckoker.h: ckcdeb.h
+ . Add support for ON_CD macro in zchdir(): ckufio.c
+ . Add a command to let FTP client authenticate with SSLv2: ckcftp.c
+ . Fix parsing of FTP file facts like "UNIX.mode": ckcftp.c
+
+ON_CD will need some explaining (to be done). It's implemented for Unix,
+VMS, WIndows, and OS/2.
+
+The FTP file facts fix came from first exposure to the new OpenBSD FTP
+server: ftp://ftp7.usa.openbsd.org/pub/os/OpenBSD/3.3/i386/
+The period in "UNIX.mode" caused an erroneous word break, adding junk to
+the filename.
+
+About the malloc changes, Jeff says "K95 is not behaving well in low memory
+environments. I'm not sure that C-Kermit does much better. The program does
+not crash but it certainly does not behave the way the user expects it to.
+I'm beginning to think that any malloc() error should be treated as fatal."
+
+Not visible in these changes because it's in K95-specific modules: Jeff made
+SET ATTRIBUTES OFF and SET ATTRIBUTES DATE OFF apply to XYZMODEM transfers.
+
+From Jeff, 11 May 2003:
+ . Add support for SSH Keepalive to relevant SET command (K95): ckuus3.c
+ . Reduce max overlapped i/o requests from 30 to 7 (K95): ckuus7.c
+ . Don't call sysinit() in fatal(): ckuusx.c.
+ . Some new conditionalizations for SSL module: ck_ssl.c
+
+The doublequote-parsing fixes from March and April broke the SWITCH statement,
+which is implemented by internally defining, then executing, a macro. If I
+drop back to the old dumb handling of doublequotes, everything is fixed except
+the problem of March 17th. But can we really expect getncm() to pre-guess
+what the parser is going to do? getncm()'s only job is to find command
+boundaries, which are represented by commas. Commas, however, is needed IN
+commands too. We take a comma literally if it is quoted with \, or is inside
+a matched pair of braces, parens, or doublequotes. It is not unreasonable to
+require a doublequote in a macro definition to be prefixed by \ when it is to
+be taken literally. The proper response to Jason Heskett's complaint of March
+17th should have been to leave the code alone and recommand an appropriate
+form of quoting:
+
+ def TEST {
+ .foo = {X\"}
+ sho mac foo
+ }
+
+And this is what I have done. Another reason for sticking with the old method
+is that it's explainable. The "improved" method, even if it worked, would be
+be impossible to explain. Btw, in testing this I noticed that the switch-test
+script made 8.0.201 dump core. Today's version is fine. The problem with
+quoted strings inside of IF {...} clauses and FOR and WHILE loops is fixed
+too. Perhaps "unbroken" would be a better word. ckuus5.c, 11 May 2003.
+
+Vace discovered that FTP MGET /EXCEPT:{... (with an unterminated /EXCEPT list)
+could crash Kermit. Fixed in ckcftp.c, 11 May 2003.
+
+CONTINUE should not affect SUCCESS/FAILURE status. ckuusr.c, 11 May 2003.
+
+Fixed an oversight that goes back 15 years. While \{123} is allowed for
+decimal codes, \x{12} and \o{123} were never handled. ckucmd.c, 11 May 2003.
+
+Added support for Red Hat <baudboy.h> and /usr/sbin/lockdev. Supposedly this
+allows Kermit to be installed without setuid or setgid bits and still be able
+to lock and use the serial device. Compiles and starts, but not tested.
+ckcdeb.h, makefile, ckutio.c, ckuus5.c, 16 May 2003.
+
+From Jeff: FTP ASCII send data to host when FTP /SSL was in use was broken.
+ftp_dpl is set to Clear when FTP /SSL is in use. This was causing the data to
+be written to the socket with send() instead of the OpenSSL routines.
+ckcftp.c, ckuath.c, 21 May 2003.
+
+From Jeff: Stuff for Kerberos 524: ckcdeb.h. Fixes for FTP; "FTP ASCII send
+data did not properly compute the end of line translations. On Unix (and
+similar platforms) the end of line was correct for no character sets but
+incorrect when character sets were specified. On Windows/OS2, the end of line
+was correct when character sets were specified and incorrect when they were
+not. On MAC, both were broken. Also, FTP Send Byte counts were incorrect
+when character sets were specified." ckcftp.c. 17 Jun 2003.
+
+From Jeff: fixes to HTTP /AGENT: and /USER: switch action: ckcnet.c ckuus3.c
+ck_crp.c ckcftp.c ckuus2.c ckuusy.c ckuusr.c ckcnet.h, 21 Jun 2003.
+
+From Jeff: Fix SET DIALER BACKSPACE so it can override a previous SET KEY
+(e.g. from INI file): ckuus7.c. Some SSL/TLS updates: ck_ssl.c. HTTP support
+for VMS and other VMS improvements (e.g. a way to not have to hardwire the
+C-Kermit version number into the build script) from Martin Vorlaender:
+ckcnet.h, ckuus[r3].c, ckcdeb.h, ckvtio.c, ckcnet.c, ckvker.com. Built on
+Solaris (gcc/ansi) and SunOS (cc/k&r). The new VMS script tests the VMS
+version and includes HTTP support only for VMS 6.2 or later. 2 Jul 2003.
+
+Tried to build on our last VMS system but it seems to be dead. Looks like a
+head crash (makes really loud noises, boot says DKA0 not recognized) (fooey, I
+just paid good money to renew the VMS license). Tried building at another
+site with:
+
+ Process Software MultiNet V4.3 Rev A-X,
+ Compaq AlphaServer ES40, OpenVMS AXP V7.3
+ Compaq C V6.4-008 on OpenVMS Alpha V7.3
+
+Had to make a few corrections to ckvker.com. But still, compilation of
+ckcnet.c bombs, indicating that the SELECT definition somehow got lost
+somewhere since the 209 release (i.e. no SELECT type is defined so it falls
+thru to "SELECT is required for this code"). But I don't see anything in
+ckcdeb.h or ckcnet.[ch] that would explain this. Not ckvker.com either
+(putting the old one back gives the same result). OK, I give up, maybe it's
+just that I haven't tried building it on MultiNet recently. What about UCX?
+Aha, builds fine there except for warnings about mlook, dodo, and parser in
+ckvfio.c (because of ON_CD) -- I suppose I have #include <ckucmd.h>... (done)
+Anyhow it builds OK and the HTTP code is active and almost works (HTTP OPEN
+works; HTTP GET seems to succeed but creates an empty file every time). Tried
+building under MultiNet at another installation; same bad result.
+
+OK so why won't it build for MultiNet? Comparing ckcnet.c with the 209
+version, not a single #ifdef or #include is changed. Tried building with
+p3="NOHTTP" -- builds OK, aha. Where's the problem? Not ckcnet.h...
+Not ckcdeb.h... OK I give up, will revisit this next time I get time to
+do anything with the code.
+
+Later Jeff said "Martin did not implement VMS networking for the HTTP code.
+All he did was activate the #define HTTP which happens to work because his
+connections are using SSL/TLS connections. http_inc(), http_tol(), etc have
+no support for VMS networking regardless of whether it is UCX or MULTINET.
+The vast majority of HTTP connections are not secured by SSL/TLS. It makes no
+sense to support HTTP on VMS until someone is willing to either do the work or
+pay have the work done to implement VMS networking in that code base." So the
+fix is to not enable HTTP for VMS after all. Removed the CKHTTP definition
+for VMS from ckcdeb.h, 6 Jul 2003.
+
+Fixed ckvfio.c to #include <ckuusr.h> (instead of <ckucmd.h>) to pick up
+missing prototypes. 6 Jul 2003.
+
+From Arthur Marsh: solaris2xg+openssl+zlib+srp+pam+shadow and the corresponding
+Solaris 7 target. makefile, 6 Jul 2003.
+
+Remove duplicate #includes for <sys/stat.h>, <errno.h>, and <ctype.h> from
+ckcftp.c. 6 Jul 2003.
+
+Add -DUSE_MEMCPY to Motorola SV/68 targets because of shuffled #includes in
+ckcftp.c. 8 Jul 2003.
+
+From Jeff: Fix problems mixing SSL and SRP without Kerberos. Plus a few minor
+#define comment changes and a reshuffling of #defines in ckcdeb.h to allow me
+to build on X86 Windows without Kerberos. ckcdeb.h, ck_crp.c, ckuath.c,
+10 Jul 2003.
+
+From Jeff: updated ckuat2.h and ckuath.c, 29 Jul 2003.
+
+Mats Peterson noticed that a very small Latin-1 file would be incorrectly
+identified as UCS-2 by scanfile(). Fixed in ckuusx.c, 29 Jul 2003.
+
+Fixed ACCESS macro definition to account for the fact that FIND is now a
+built-in command. ckermit.ini, 30 Jul 2003.
+
+From Jeff: Fix for typo in urlparse() (svc/hos): ckuusy.c, 18 Aug 2003.
+
+From Jeff: Redhat9 makefile targets (needed for for OpenSSL 0.9.7):
+makefile, 19 Aug 2003.
+
+GREP /NOLIST and /COUNT did too much magic, with some undesirable fallout:
+"GREP /NOLIST /COUNT:x args" printed "file:count" for each file. "GREP
+/COUNT:x /NOLIST args" did not print "file:count", but neither did it set the
+count variable. Removed the magic. Also one of the GREP switches,
+/LINENUMBERS, was out of order. Fixed in ckuus6.c, 20 Aug 2003.
+
+From Jeff: "Reorganizing code to enable building with different subsets of
+options; a few typos corrected as well." ckcdeb.h, ckuver.h (for RH9),
+ckcnet.c, ckuus7.c, ckuus3.c: 24 Aug 2003.
+
+Scanfile misidentified a big PDF file as text because the first 800K of it
+*was* text (most other PDF files were correctly tagged as binary). Fixed
+by adding a check for the PDF signature at the beginning of the file.
+scanfile(): ckuusx.c, 25 Aug 2003.
+
+Ditto for PostScript files, but conservatively. Signature at beginning of
+file must begin with "%!PS-Ado". If it's just "%!" (or something nonstandard
+like "%%Creator: Windows PSCRIPT") we do a regular scan. Also added "*.ps"
+to all binary filename patterns. ckuusx.c, 4 Sep 2003.
+
+Ditto (but within #ifndef NOPCLSCAN) for PCL (<ESC>E) and PJL (<ESC>%) files,
+but no binpatterns (note: ".PCL" is the extension for TOPS-20 EXEC scripts).
+ckuusx.c, 4 Sep 2003.
+
+Added comments about OpenSSL 0.9.7 to all linux+openssl targets.
+makefile, 4 Sep 2003.
+
+From Jeff: Added - #define ALLOW_KRB_3DES_ENCRYPT. When this symbol is defined
+at compilation Kermit will allow non-DES session keys to be used during Telnet
+Auth. These session keys can then be used for Telnet Encrypt. The reason
+this is not compiled on by default is that the MIT Kerberos Telnet does not
+follow the RFC for constructing keys for ENCRYPT DES when the keys are longer
+than 8 bytes in length. ckuath.c, ckuus5.c, 4 Sep 2003.
+
+"ftp mget a b c" succeeded if one or more of the files did not exist, even
+with "set ftp error-action proceed". This is because the server's NLST file
+list does not include any files that don't exist, so the client never even
+tries to get them. Fortunately, the way the code is structured, this one was
+easy to fix. ckcftp.c, 14 Sep 2003.
+
+From Jeff: Corrected code in ckcnet.c to ensure that Reverse DNS Lookups are
+not performed if tcp_rdns is OFF. Fixed ck_krb5_getrealm() to actually return
+the realm of the credentials cache and not the default realm specified in the
+krb5.conf file. Previously krb5_cc_get_principal() was not being called.
+Fixed ck_krb5_is_tgt_valid() to test the TGT in the current ccache and not the
+TGT constructed from the default realm. ckcnet.c, ckuath.c, 14 Sep 2003.
+
+Marco Bernardi noticed that IF DIRECTORY could produce a false positive if
+the argument directory had previously been referenced but then removed. This
+is because of the clever isdir() cache that was added to speed up recursion
+through big directory trees. Changed IF DIRECTORY to make a second check
+(definitive but more expensive) if isdir() succeeds, and changed the
+directory-deleting routine, ckmkdir(), to flush the directory cache (UNIX
+only -- this also should be done in K95 but it's not critical). This was
+done by adding a routine, clrdircache() to ckufio.c, which sets prevstat
+to -1 and prevpath[0] to NUL. ckcfn3.c, ckuus6.c, ckufio.c, 18 Sep 2003.
+
+Marco reported the second fix still didn't work for him (even though it did
+for me). Rather than try to figure out why, I concluded that the directory
+cache is just not safe: a directory found a second ago might have been deleted
+or renamed not only by Kermit but by some other process. Why did I add this
+in the first place? The log says:
+
+ Some debug logs showed that isdir() is often called twice in a row on the
+ same file. Rather than try to sort out clients, I added a 1-element cache
+ to Unix isdir(). ckufio.c, 24 Apr 2000.
+
+Experimentation with DIR and DIR /RECURSIVE does not show this happening at
+all. So I #ifdef'd out the directory cache (see #ifdef ISDIRCACHE in ckufio.c;
+ISDIRCACHE is not defined) and backed off the previous changes: ckufio.c,
+ckcfn3.c, ckuus6.c, 28 Sep 2003.
+
+From Jeff: Replace the compile time ALLOW_KRB_3DES_ENCRYPT with a run-time
+command SET TELNET BUG AUTH-KRB5-DES which defaults to ON: ckctel.[ch],
+ckuus[234].c, ck_crp.c, ckuath.c. 4 Oct 2003.
+
+Allow DIAL RETRIES to be any positive number, and catch negative ones.
+Also added code to check for atoi() errors (e.g. truncation). At least on
+some platforms (e.g. Solaris) atoi() is supposed to set errno, but it
+doesn't. ckuus3.c, ckucmd.c, 4 Oct 2003.
+
+Added /DEFAULT: to ASK-class commands (ASK, ASKQ, GETOK):
+
+ . For popups: no way to send defaults to popup_readtext() or popup_readpass().
+ . For GUI ASK[Q], pass default to gui_txt_dialog().
+ . For GUI GETOK, convert "yes" "ok" or "no" default to number for uq_ok().
+ . For Text GETOK, add default to cmkey().
+ . For Text ASK[Q], add default to cmtxt().
+ . For GETC, GETKEY, and READ: no changes.
+
+GETOK, ASK, and ASKQ with /TIMEOUT: no longer fail when the timer goes off
+if a /DEFAULT was supplied. The GUI functions (uq_blah) don't seem to
+support timeouts. Only the text version has been tested. ckuus[26].c,
+4 Oct 2003.
+
+From Jeff: add /DEFAULT: for popups. ckuus6.c. 6 Oct 2003.
+
+Change SET DIAL INTERVAL to be like SET DIAL RETRIES. ckuus[34].c, 6 Oct 2003.
+
+Added target for HP-UX 10/11 + OpenSSL built with gcc, from Chris Cheney.
+Makefile, 12 Oct 2003.
+
+From Jeff, 6 Nov 2003:
+ . #ifdef adjustments: ckcftp.c, ckcdeb.h
+ . Fix spurious consumption of first byte(s) on Telnet connection: ckctel.c
+ . Another HP PJL test for scanfile: ckuusx.c.
+ . K95: Recognize DG4xx protected fields in DG2xx emulation: ckuus7.c.
+ . Add SSLeay version display to SHOW AUTH command: ckuus7.c
+ . Improved SET MOUSE CLEAR help text: ckuus2.c.
+ . Improved Kverbs help text: ckuus2.c (+ new IBM-3151 Kverbs).
+ . Some changes to ck_ssl.c, ckuath.c.
+
+From PeterE, 10 Nov 2003:
+ . Improved HP-UX 10/11 makefile targets for OpenSSL.
+ . #ifdef fix for OpenSSL on HP-UX: ck_ssl.c.
+
+Another new makefile from PeterE with improved and integrated HP-UX targets.
+12 Nov 2003.
+
+A couple fixes to the solaris9g+krb5+krb4+openssl+shadow+pam+zlib target
+from Jeff. Added a solaris9g+openssl+shadow+pam+zlib target. makefile,
+21 Nov 2003.
+
+From Jeff, 30 Nov 2003:
+ . Fix SEND /MOVE-TO: ckuusr.c.
+ . Fix K95 SET TITLE to allow quotes/braces around text: ckuus7.c.
+ . Improved "set term autodownload ?" response: ckuus5.c.
+ . Fix SHOW FEATURES to specify the protocol for encryption: ckuus5.c
+ . Make {SEND, RECEIVE} {MOVE-TO, RENAME-TO} work for XYZMODEM (K95 only).
+
+From Jeff: 7 Jan 2004:
+ . At one point Frank started to add a timer parameter to the
+ uq_txt() function but he only did it for the non-ANSI
+ compilers. I added it for the ANSI compilers, fixed the
+ prototypes and provided a default value easily changed
+ DEFAULT_UQ_TIMEOUT: ckcker.h, ckuus[36].c, ck_ssl.c, ckcftp.c, ckuath.c.
+ . Fixed SET TERMINAL DEBUG ON (typo in variable name): ckuus7.c.
+ . Fixed BEEP INFORMATION; previously it made no sound, now uses
+ MB_ICONQUESTION. ckuusx.c.
+
+From Ian Beckwith <ian@nessie.mcc.ac.uk> (Debianization), 7 Jan 2004:
+ . Search dir/ckermit for docs, as well as dir/kermit in cmdini(): ckuus5.c.
+ . New linux+krb5+krb4+openssl+shadow+pam target (kitchen sink minus SRP,
+ which Debian does not distribute): makefile.
+ ? Mangles the DESTDIR support in makefile to install into a staging area:
+ makefile (I didn't take this one yet).
+
+Updated copyright notices for 2004, all modules. 7 Jan 2004.
+
+Added INPUT /NOMATCH, allowing INPUT to be used for a fixed amount of time
+without attempting to match any text or patterns, so it's no longer
+necessary to "input 600 STRING_THAT_WILL_NEVER_COME". If /NOMATCH is
+included, INPUT succeeds if the timeout expires, with \v(instatus) = 1
+(meaning "timed out"); fails upon interruption or i/o error. ckuusr.h,
+ckuus[r24].c, 7 Jan 2004.
+
+Added SET INPUT SCALE-FACTOR <float>. This scales all INPUT timeouts by the
+given factor, allowing time-sensitive scripts to be adjusted to changing
+conditions such as congested networks or different-speed modems without
+having to change each INPUT-class command. This affects only those timeouts
+that are given in seconds, not as wall-clock times. Although the scale
+factor can have a fractional part, the INPUT timeout is still an integer.
+Added this to SHOW INPUT, and added a \v(inscale) variable for it.
+ckuusr.h, ckuus[r257].c, 7 Jan 2004.
+
+undef \%a, \fverify(abc,\%a) returns 0, which makes it look as if \%a is a
+string composed of a's, b's, and/or c's, when in fact it contains nothing.
+Changed \fverify() to return -1 in this case. ckuus4.c, 12 Jan 2004.
+
+\fcode(xxx) returned an empty string if its argument string was empty. This
+makes it unsafe to use in arithmetic or boolean expressions. Changed it to
+return 0 if its argument was missing, null, or empty. ckuus4.c, 12 Jan 2004.
+
+Updated \verify() and \fcode() help text. ckuus2.c, 12 Jan 2004.
+
+While setting up IKSD, Ian Beckwith noticed that including the --initfile:
+option caused Kermit to start parsing its own Copyright string as if it were
+the command line, and eventually crash. I couldn't reproduce on Solaris /
+Sparc but I could in Linux / i386 (what Ian is using) -- a change from Jeff
+on 28 Apr 2003 set the command-line arg pointer to a literal empty string in
+prescan() about line 1740 of of ckuus4.c; the pointer is incremented next
+time thru the loop, resulting in random memory being referenced. Fixed by
+setting the pointer to NULL instead of "". ckuus4.c, 12 Jan 2004.
+
+declare \&a[999999999999999] would dump core on some platforms. atoi()
+or whatever would truncate the dimension to maxint. When we add 1 to the
+result, we get a negative number, which is used as an index, loop test, etc.
+Fixed both dodcl() and dclarray() to check for (n+1 < 0). ckuus[r5].c,
+12 Jan 2004.
+
+Unix zchki() would fail on /dev/tty, which is unreasonable. This prevented
+FOPEN /READ from reading from the terminal. zchki() already allowed for
+/dev/null, so I added /dev/tty to the list of specials. Ditto for FOPEN
+/WRITE and zchko(). ckufio.c 13 Jan 2004.
+
+Added untabify() routine to ckclib.[ch], 13 Jan 2004.
+Added FREAD /TRIM and /UNTABIFY. ckuus[27].c, 13 Jan 2004.
+Added \funtabify(). ckuusr.h, ckuus[24].c, 13 Jan 2004.
+
+Dat Nguyen noticed that (setq u 'p') followed by (u) dumped core. This was
+caused by an over-clever optimization that skipped mallocs for short
+literals, but then went on later to try to free one that hadn't been
+malloc'd. Fixed in dosexp(): ckuus3.c, 14 Jan 2004.
+
+Catch another copyright date. ckuus5.c, 14 Jan 2004.
+
+Fixed SWITCH to work even when SET COMMAND DOUBLEQUOTE OFF (from Mark
+Sapiro). ckuus5.c, 15 Jan 2004.
+
+Changed version to 8.0.211 so scripts can test for recently added features.
+ckcmai.c, 15 Jan 2004.
+
+Fixed a glitch in K95 "help set port". ckuus2.c, 20 Jan 2004.
+
+Fix from Jeff: Connections to a TLS-aware protocol which require a reconnect
+upon certificate verification failure could not reconnect if the connection
+was initiated from the command line or via a URL. ckctel.c ckcmai.c
+ckuusr.c ckuus7.c ckuusy.c, 20 Jan 2004.
+
+From Alex Lewin: makefile target and #ifdef for Mac OS X 10.3 (Panther):
+makefile, ckcnet.c, 7 Feb 2004.
+
+Added KFLAGS to sco32v507 targets to make PTY and SSH commands work. The
+same flags could probably also be added to earlier OSR5 targets but they
+have not been tested there. makefile, 7 Feb 2004.
+
+Checked a complaint that "LOCAL &a" did not make array \&a[] local. Indeed
+it did not, and can not. You have to use the full syntax in the LOCAL
+command, "LOCAL \&a[]", or else it doesn't know it's not a macro named &a.
+7 Feb 2004.
+
+Fixed some confusion in creating IKSD database file and temp-file names.
+I was calling zfnqfp() without remembering that the path member of the
+returned struct included the filename, so to get just the directory name,
+I needed to strip the filename from the right. ckuusy.c, 2 Mar 2004.
+
+New ckuath.c, ck_ssl.c from Jeff. 2 Mar 2004.
+
+Updated Jeff's affiliation in VERSION command text. ckuusr.c, 2 Mar 2004.
+
+Designation changed from Dev.00 to Beta.01. ckcmai.c, 2 Mar 2004.
+
+Fixed zrename() syslogging -- it had success and failure reversed.
+Beta.02: ckufio.c, 4 Mar 2004.
+
+Problem: when accessing IKSD via a kermit:// or iksd:// URL, and a user ID
+is given but no password, doxarg() set the password to "" instead of leaving
+it NULL, but all the tests in dourl() are for NULL. Fixed in doxarg():
+ckuusy.c, 5 Mar 2004.
+
+The logic in dourl() about which macro to construct (login and connect,
+login and get directory listing, or login and fetch a file) was a bit off,
+so all three cases were not handled. ckcmai.c, 5 Mar 2004.
+
+Trial Beta builds:
+ . HP-UX B.11.11 PA-RISC
+ . HP-UX B.11.23 IA64
+ . Tru64 4.0G Alpha
+ . Tru64 5.1B Alpha
+ . Debian 3.0 i386
+ . Red Hat ES 2.1 i386
+ . Slackware 9.1 i386
+ . VMS 7.3-1 Alpha + UCX 5.3
+ . VMS 7.3-1 Alpha no TCP/IP
+ . VMS 7.3 Alpha MultiNet 4.3 A-X
+ . SCO UnixWare 7.1.4 i386
+ . SCO OSR5.0.7 i386
+ . Solaris 9 Sparc
+
+Fixed compiler warning in doxarg() caused by typo (NULL instead of NUL) in
+the 5 March doxarg() edit. ckuusy.c, 9 Mar 2004.
+
+IKSD (kermit://) command-line URLs did not work right if the client had
+already preauthenticated with Kerberos or somesuch because they tried to log
+in again with REMOTE LOGIN. The macros constructed in doxarg() needed to
+check \v(authstate) before attempting REMOTE LOGIN. ckcmai.c, 10 Mar 2004.
+
+Added ckuker.nr to x.sh (ckdaily upload) and updated ckuker.nr with current
+version number and dates. 10 Mar 2004.
+
+Replaced hardwired references to /usr/local in makefile with $(prefix)
+(which defaults to /usr/local, but can be overridden on the command line),
+suggested by Nelson Beebe for use with Configure. 10 Mar 2004.
+
+From Nelson Beebe: In the Kermit makefile in the install target commands,
+line 981 reads:
+
+ cp $(BINARY) $(DESTDIR)$(BINDIR)/kermit || exit 1;\
+
+Could you please add this line before it:
+
+ rm -f $(DESTDIR)$(BINDIR)/kermit;\
+
+Some sites (mine included) keep multiple versions of software around,
+with hard links between $(prefix)/progname and $(prefix)/progname-x.y.z.
+Failure to remove the $(prefix)/progname at "make install" time then
+replaces the old $(prefix)/progname-x.y.z with the new one, destroying
+an old version that the site wanted to be preserved. makefile, 10 Mar 2004.
+
+Minor syntax and typo fixes (mostly prototypes): ckcdeb.h, ckcfns.c,
+ckclib.c, ckufio.c, ckuusr.h, ckuusx.c, 10 Mar 2004. (I still have a few
+more to do.)
+
+Added CC=$(CC) CC2=$(CC2) to many (but not all) makefile targets that
+reference other makefile targets. On some platforms (notably AIX, Solaris,
+SunOS) there are specific targets for different compilers, so I skipped
+those. makefile, 10 Mar 2004.
+
+Added error checking to kermit:// URL macros, so they don't plow ahead
+after the connection is closed. ckcmai.c, 11 Mar 2004.
+
+Added FreeBSD 4.9 and 5.1 targets (only the herald is affected).
+makefile, ckuver.h, 11 Mar 2004.
+
+Added "LIBS=-lcrypt" to bsd44 targets since nowadays crypt is almost always
+unbundled from libc. Also added explanatory notes. makefile, 11 Mar 2004.
+
+Changed MANDIR to default to $(manroot)/man/man1, and manroot to default
+to $(prefix). More adding of CC=$(CC) clauses: {Free,Net,Open}BSD, 4.4BSD.
+makefile, 11 Mar 2004.
+
+Miscellaneous cleanups: ckuusx.c, ckcnet.c, ckufio.c, 11 Mar 2004.
+
+Corrected the check in the linux target to see if /usr/include/crypt.h
+exists, and if so to define HAVE_CRYPT_H, which is used in ckcdeb.h to
+#include <crypt.h> to get the prototype for crypt() and prevent bogus
+conversions on its return type on 64-bit platforms (the previous test wasn't
+quite right and the resulting symbol wasn't spelled right). makefile,
+12 Mar 2004.
+
+From Jeff, 14 Mar 2004:
+ . Initialize localuidbuf[] in tn_snenv(): ckctel.c.
+ . Remove remote-mode checks in hupok() for K95G only (why?): ckuus3.c.
+ . Add help text for new K95-only TYPE /GUI switches: ckuus2.c.
+ . TYPE /GUI parsing, ...: ckuusr.c.
+ . TYPE /GUI action, dotype(): ckuus6.c
+ . Change Jeff's affiliation: most modules.
+
+20 Mar 2004: Looked into adding long file support, i.e. handling files more
+than 2GB (or 4GB) long. Discovered very quickly this would be a major
+project. Each platform has a different API, or environment, or transition
+plan, or whatever -- a nightmare to handle in portable code. At the very
+least we'll need to convert a lot of Kermit variables from long or unsigned
+long to some new Kermit type, which in turn is #defined or typedef'd
+appropriately for each platform (to off_t or size_t or whatever). Then we
+have to worry about the details of open() vs fopen(); printf() formats (%lld
+vs %Ld vs %"PRId64"...), platforms like HP-UX where you might have to use
+different APIs for different file systems on the same computer, etc. We'll
+need to confront this soon, but let's get a good stable 8.0.211 release out
+first! Meanwhile, for future reference, here are a few articles:
+
+General: http://freshmeat.net/articles/view/709/
+Linux: http://www.ece.utexas.edu/~luo/linux_lfs.html
+HP-UX: http://devrsrc1.external.hp.com/STK/partner/lg_files.pdf
+Solaris: http://wwws.sun.com/software/whitepapers/wp-largefiles/largefiles.pdf
+
+Looked into FTP timeouts. It appears I can just call empty() (which is
+nothing more than a front end for select()) with the desired timeout before
+any kind of network read. If it returns <= 0, we have a timeout. This is
+not quite the same as using alarm() / signal() around a recv() (which could
+get stuck) but alarm() / signal() are not not used in the FTP module and are
+not naturally portable to Windows, but select() is already in use in the FTP
+module for both Unix and Windows. This form of timeout could be used
+portably for both command response and data reads. What about writes to the
+command or data socket? They can get stuck for hours and hours without
+returning too, but the select() approach won't help here -- we need the
+actual send() or recv() to time out, or be wrapped in an alarm()/signal()
+kind of mechanism. But if we can do that for sends, we can also do it for
+receives. Better check with Jeff before I start programming anything.
+20 Mar 2004.
+
+Later: Decided to postpone the above two projects (ditto IPv6) until after
+8.0.211 is released because both will have major impacts on portability.
+Grumble: all i/o APIs should have been designed from the beginning with a
+timeout parameter. To this day, hardly any have this feature.
+
+3-4 Apr 2004: More 8.0.211 Beta.02+ test builds:
+
+ . FreeBSD 3.3
+ . FreeBSD 4.4
+ . Linux Debian 2.1
+ . Linux RH 6.1
+ . Linux RH 7.1
+ . Linux RH 7.2
+ . Linux RH 9 (with 84 different combinations of feature selection)
+ . Linux SuSE 6.4
+ . Linux SuSE 7.0
+ . NetBSD 1.4.1
+ . NetBSD 1.5.2
+ . OpenBSD 2.5
+ . OpenBSD 3.0
+ . QNX 4.25
+ . SCO UnixWare 2.1.3
+ . SCO UnixWare 7.1.4
+ . SCO OpenServer 5.0.7
+ . SCO XENIX 2.3.4 (no TCP)
+
+Changes needed: None.
+
+Problem: SCO XENIX 2.3.4 network build failed in the FTP module with
+header-file syntax and conflicting-definitions trouble. I'm not going to
+try to fix it; 8.0.209 built OK with FTP, so we'll just keep that one
+available.
+
+Got access to VMS 8.1 on IA64. Building the nonet version of C-Kermit
+required minor modifications to ckvvms.h, ckv[ft]io.c, and ckvcon.c, to
+account for a third architecture. Also to SHOW FEATURES in ckuus5.c. Once
+that was done, the UCX 5.5 version built OK too. Starts OK, makes Telnet
+connection OK, sends files. Has some obvious glitches though -- "stat"
+after a file transfer reports 0 elapsed time (in fact it was 00:09:48) and
+1219174400 cps (when in fact it was 10364). This doesn't happen on the
+Alpha. Btw, the IA64 binary is twice as big as the Alpha one. Changed
+to Beta.03. 5 Apr 2004.
+
+Fixed the ckdaily script to include the makefile and man page in the Zip
+file (they were not included because the Zip file was intended mainly for
+VMS users, but some Unix users prefer Zip to tar.gz). 6 Apr 2004.
+
+Traced problems in VMS/IA64 statistics report to rftimer()/gftimer() in
+ckvtio.c, which use sys$ and lib$ calls to figure elapsed time. These work
+on VAX and Alpha but not IA64. Sent a report to the chief engineer of the
+IA64 VMS port; he says it's probably a bug in VMS 8.1 (which is not a real
+release); he'll make sure it's fixed in 8.2. As an experiment, tried
+swapping in the Unix versions of these routines (which call gettimeofday()
+etc). They seem work just fine (it hung a couple times but I think that's
+because the underlying system hung too; trying it later on a new connection,
+it was fine; however I noticed a BIG discrepancy in throughput between
+sending and receiving). Moved definitions for VMS64BIT and VMSI64 to
+ckcdeb.h so all modules can use them and added them to the SHOW FEATURES
+display. Added VMSV80 definition to build procedure. Beta.03+. ckcdeb.h,
+ckcuus5.c, ckcvvms.h, ckvtio.c, ckvker.com, 6 Apr 2004.
+
+While doing the build-all, I noticed the VMS version did not build with
+Multinet or older UCX versions, always with the same errors -- undeclared
+variables, undefined symbols, all TCP/IP related. This didn't happen a
+couple weeks ago... Somehow the order of #includes was messed up --
+ckuusr.h depended on symbols that are defined in ckcnet.h, but ckcnet.h
+was being included after ckuusr.h... this was compounded by two missing
+commas in ckvker.com. 11 Apr 2004.
+
+Removed Beta designation, released as 8.0.211, 10 Apr 2004.
+
+I had somehow lost the edit to ckutio.c that changed the UUCP lockfile for
+Mac OS X from /var/spool/uucp to /var/spool/lock. So I slipped it in and
+re-uploaded version 8.0.211. You can tell the difference because SHOW
+VERSIONS has 17 Apr 2004 for the Communications I/O module. Also the 10.3
+executable now has a designer banner: "Mac OS X 10.3". makefile, ckuver.h,
+ckutio.c, ckuus[45].c, 17 Apr 2004.
+
+---8.0.211---
+
+Removed "wermit" from "make clean" (how did it get there?). makefile.
+
+From Jeff, applied 10 May 2004.
+ . Rearrange #ifdefs that define OS/2-only features. ckcdeb.h.
+ . Fix two strncat()s that should have been ckstrncat()s. ckuus7.c.
+ . Fix two strncat()s that should have been ckstrncat()s. ckuus4.c.
+ . Fix one strncat(). ckcfns.c.
+ . SET FTP CHAR ON used backwards byte order when output to screen. ckcfns.c.
+ . Fix two strncat()s. ckuus3.c.
+ . Add SET NETWORK TYPE NAMED-PIPE for K95. ckuus3.c.
+ . Add "No active connections" message to hupok(). ckuus3.c.
+ . Fix many strncat()s. ckcnet.c.
+ . Fix some strncat()s. ckcftp.c
+ . Make FTP port unsigned short for 16383 < port < 65536. ckcftp.c.
+ . Improvements to FTP USER command. ckcftp.c.
+ . Fix FEAT parsing to allow for various forms of whitespace. ckcftp.c.
+
+S-Expression (AND FOO BAR) would not short-circuit if FOO's value was 0,
+even though short-circuiting code has been there since Day 1. Similarly for
+(OR BAR FOO). Turns out the first operand was a special case that bypassed
+the short-circuit check. Fixed in dosexp(): ckuus3.c, 10 May 2004.
+
+Red Hat 7.3 (and maybe others) <baudboy.h> referenced open() without first
+ensuring it was declared. The declaration is in <fcntl.h>, which is after
+<baudboy.h> in ckutio.c series of #includes. Made a special case for this.
+ckutio.c (see comments), 10 May 2004.
+
+If the local Kermit's parity is set to SPACE and then a file arrives via
+autodownload, automatic parity detection improperly switches it to NONE.
+Fixed in rpack() by switching parity automatically only if parchk() returns
+> 0 (rather than > -1), since NONE and SPACE are indistinguishable. A
+bigger problem still remains: autodownload does not work at all if the
+sender is using actual parity bits (even, odd, or mark) and the receiver's
+parity is NONE. ckcfn2.c, 10 May 2004.
+
+When a DIAL MACRO is defined and the phone number is comprised of more than
+one "word" (i.e. contains spaces), the dial macro loses the second and
+subsequent words after the first call. Fixed in xdial() by inserting quotes
+around phone number before passing it to xdial(). ckuus6.c, 10 May 2004.
+
+DIAL MACRO fix was not right; the quotes were kept as part of the phone
+number and sent to the modem. dodo() pokes its argument to separate the
+macro argument string into its component arguments. xdial() is called
+repeatedly on the same string, so after the first time, a NUL has been
+deposited after the first word of the telephone number. The fix is to have
+xdial() create a pokeable copy of its argument string before calling
+dodo(dial-macro,args...). It might seem odd that dodo pokes its argument,
+but making copies would be would be prohibitive in space and time.
+ckuus6.c, 23 May 2004.
+
+FTP CD did not strip braces or quotes from around its argument. Fixed in
+doftprmt(): ckcftp.c, 23 May 2004.
+
+Added client side of REMOTE MESSAGE/RMESSAGE/RMSG: ckuus[r27].c, 23 May 2004.
+
+Server side of REMOTE MESSAGE: ckcpro.w, 23 May 2004.
+
+From Dave Sneddon: an updated CKVKER.COM containing a fix where the
+COMPAQ_SSL symbol was not defined but later referenced which generated an
+undefined symbol error. ckvker.com, 5 Jan 2005.
+
+From Andy Tanenbaum (28 May 2005):
+ . Fix an errant prototype in ckcker.h and ckucmd.h - () instead of (void).
+ . Add support for MINIX 3.0. makefile, ckutio.c, ckufio.c, ckuver.h.
+
+Fixed messed-up sndhlp() call which apparently had been jiggered to
+compensate for the bad prototype which has now been fixed, ckcpro.w,
+12 Jun 2005.
+
+From Jeff (12 June 2005):
+ . Security updates. ck_ssl.c, ck_crp.c, ckuath.c.
+ . Fix bug in K95 SET PRINTER CHARACTER-SET. ckuus3.c.
+ . Add printer character-set to K95 SHOW PRINTER display. ckuus5,c
+ . Add SET MSKERMIT FILE-RENAMING to K95. ckuus7.c, ckuusr.h.
+ . Add help for K95 SET MSKERMIT. ckuus2.c.
+ . Add SET GUI CLOSE to K95. ckuusr.h, ckuus2.c, ckuus3.c
+ . Add help text for K95 SET GUI MENUBAR and TOOLBAR. ckuus2.c.
+ . Add --noclose command-line option for K95. ckuusy.c
+ . Add PAM support for Mac OS X. ckufio.c.
+ . Add GSSAPI support for Mac OS X. ckcftp.c.
+ . Pick up more URL options. ckcker.h, ckuusy.c.
+ . Fix bug in delta-time calculation across year boundary. ckucmd.c.
+ . Add Secure Endpoints to copyright notices. ckcmai.c.
+ . Fix FTP HELP to override unverbose setting. ckcftp.c.
+ . Fix assorted minor typos.
+
+From Matthias Kurz: automatic herald generation for NetBSD 2.0 and later,
+"make netbsd2". ckuver.h, makefile, 12 Jun 2005.
+
+Added SET TERMINAL LF-DISPLAY, like CR-DISPLAY but for linefeed rather than
+carriage return. ckuusr.h, ckuus[257x].c, 12 Jun 2005.
+
+Made a command-line option --unbuffered to do what the -DNONOSETBUF
+compile-time option does, i.e. force unbuffered console i/o. Unix only.
+ckuusr.h, ckuusy.c, ckutio.c, 12 Jun 2005.
+
+Fixed getiact() (which displays TERM IDLE-ACTION setting) to display
+space as \{32}. ckuus7.c, 12 Jun 2005.
+
+Added LMV as a synonym for LRENAME, which is itself a synonym for LOCAL
+RENAME. ckuusr.c, 12 Jun 2005.
+
+Put HELP SET TERMINAL DG-UNIX-MODE text where it belonged. ckuus2.c,
+12 Jun 2005.
+
+Added IF LINK (Unix only) to test if a filename is a symlink. Uses the most
+simpleminded possible method, calls readlink() to see if it succeeds or fails.
+No other method is dependable across different Unixes. This code should be
+portable because I already use readlink() elsewhere within exactly the same
+#ifdefs. ckufio.c, ckuus2.c, ckuus6.c, 12 Jun 2005.
+
+Fixed a bug in which \fdir() wouldn't work when its argument was the nonwild
+name of a directory file. zxpand(): ckufio.c, 12 Jun 2005.
+
+Made \fdirectory() a synonym for \fdirectories(). Made \fdir() an
+acceptable abbreviation for these, even though it clashes with \fdirname(),
+which still works as before. ckuus4.c, 12 Jun 2005.
+
+Added the long-needed \flopx() function, to return rightmost pieces of
+strings, such as file extensions. \fstripx() and \flopx() are the
+orthogonal functions we need to pick filenames apart from the right:
+\stripx(foo.tar.gz) = foo.tar; flopx(foo.tar.gz) = gz. ckuusr.h, ckuusr.c,
+ckuus2.c, 12 Jun 2005.
+
+Removed reference to defunct fax number, ckcmai.c, 12 Jun 2005.
+
+Added -DHAVE_PTMX to linux+krb5+openssl+zlib+shadow+pam. From Timothy Folks.
+makefile, 12 Jun 2005.
+
+Built on Solaris 9 and NetBSD 2.0.
+
+From Jeff: New build target for Mac OS X 10.3 with Kerberos 5 and SSL.
+makefile, 14 Jun 2005.
+
+Fixed error in ckuver.h NetBSD #ifdefs. 15 Jun 2005.
+
+Fixed SET TERMINAL IDLE-ACTION OUTPUT to work as documented, namely if the
+output string is empty, to send a NUL. Previously there was no way to make
+it send a NUL. ckuus7.c, 15 Jun 2005.
+
+Suppose (in Unix, for example) a filename contains wildcard characters, such
+as {abc}.txt. When referring to such a file (e.g. in a SEND command), these
+characters can be quoted, e.g. \{abc\}.txt. But if the file list has been
+obtained programmatically, e.g. stored in an array, there is no way, short
+of tedious, complicated, and error-prone string processing, to reference the
+file. For this we need a way to disable wildcard processing. I added { ON,
+OFF } choices for the SET WILD and SHOW FILE commands: ckuusr.h, ckuus[234].c.
+{ ON, OFF } turns wildcarding off and on without affecting the { KERMIT,
+SHELL } agent choice; it does this by setting a new and separate global
+variable, wildena. Added semantics to ckufio.c. Crude but effective. It
+might have been more Unixlike to add Yet Another form of quoting but we
+have enough of that already (later maybe I'll add a \function() for this).
+Needs to be propagated to Windows and VMS. 15 Jun 2005.
+
+Improved and fixed typos in HELP WILDCARD and HELP PATTERN. ckuus2.c,
+15 Jun 2005.
+
+The GREP command, and probably anything else that uses ckmatch() for pattern
+matching, failed on patterns like */[0-3]*.html. The [a-b] handler, when
+failing to match at the current position, neglected to back up the pattern
+and try again on the remainder of the string. I also fixed another case, in
+which matching a literal string a*b?c against the pattern a[*?]*[?*]c caused
+ckmatch() to recurse until it blew up. ckclib.c, 16 Jun 2005.
+
+Added builds and designer banner for Solaris 10. makefile, ckuver.h,
+27 Jun 2005.
+
+Defined CKHTTP for NetBSD, the HTTP code builds and works fine there.
+ckcdeb.h, 2 Jul 2005.
+
+Added #ifndef OSF40..#endif around definition of inet_aton() in ck_ssl()
+to allow building in Tru64. Added tru64-51b+openssl to makefile.
+15 Jul 2005.
+
+HTTP GET would fail if the URL contained any metacharacters, no matter how
+much you quoted them. Although it uses cmfld() to parse the (partial) URL,
+it then uses cmofi() to get the output filename, which by default is the
+"filename" from the URL, which might be something like "rankem.asp?id=1639".
+cmofi() refuses to accept unquoted metacharacters in "filenames" and that's
+what happens in this case if the output filename is not specified. Worked
+around this by disabling wildcard processing around HTTP GET using the new
+"wildena" variable from June 15th. ckuusr.c, 18 Jul 2005.
+
+Fixed the June 16th fix to the pattern matcher. I fixed a real problem, but
+I made an unrelated optimization that introduced new ones. ckclib.c,
+18 Jul 2005.
+
+Added missing help text for \fb64encode() and \fb64decode(). ckuus2.c,
+18 Jul 2005.
+
+Changed SET WILD OFF help text to warn that this setting prevents the
+creation of backup files (later I'll have to see if something more useful
+can be done about this). ckuus2.c, 18 Jul 2005.
+
+Built OK on Mac OS X 10.4.2 using macosx103 target (but with some
+"signedness" warnings in ckcnet.c and ckcftp.c). Built on Unixware 7.1.4
+with uw7 target. 27-28 Jul 2005.
+
+Added -DCKHTTP to Mac OS X 10.3-.4 KFLAGS. Makefile, 4 Aug 2005.
+
+Built on BSDI 4.3.1. Added -DCKHTTP.
+
+Compact substring notation extended to accept not only start:length but also
+start-end notation. Thus \s(foo[12:18]) means the substring of foo starting
+at position 12 of length 18, and tne new \s(foo[12-18]) means the substring
+of foo starting at position 12 and ending with position 18. Ditto for
+\:(\%a), etc. ckuus4.c, 9 Aug 2005.
+
+See correspondence with Mark Sapiro, Nov 2003 and Sep 2004, about certain
+variations on IF syntax having been broken by the introduction of "immediate
+macros" circa 1999. It seems the problem -- variables not being expanded --
+always occurs in the ELSE part when (a) the IF condition is false; (b) the
+ELSE command is "standalone", i.e. expressed as a separate command after the
+IF command (original C-Kermit 5A syntax), and (c) its command list is a block.
+This would suggest the problem is in the XXELS parser.
+
+Going back to 1999, I find this:
+ Fixed a problem Jim Whitby noticed with quoting in ELSE statements. This
+ problem was introduced when I unified IF and XIF, and occurs only when
+ ELSE begins on a line, followed by a { command list } rather than a single
+ command. The solution (gross) was to make a special version of pushcmd()
+ (called pushqcmd()) for this situation, which doubles backslashes while
+ copying, BUT ONLY IF it's a command list (i.e. starts with "{"); otherwise
+ we break lots of other stuff. Result passes Jim's test and still passes
+ ckedemo.ksc and iftest.ksc. ckucmd.c, ckuus6.c, 27 Sep 99.
+
+I undid this change and it made no difference to all the other IF
+constructions (in fact, it fixed an unrelated one that was broken, so now
+iftest scores 54 out of 54, instead of 53). However, it does not fix the
+ELSE problem; in fact it pushes it all the way in the other direction:
+
+ The opposite occurs any time you try to execute an immediate macro inside a
+ macro or any other { block }: not only is the variable evaluated, it is
+ evaluated into nothing. It looks like this happens only in immediate
+ macros, i.e. *commands* that start with '{'. So maybe we really have two
+ isolated problems, that can each be fixed.
+
+The situation is illustrated by this simple script:
+
+ def xx {
+ if false { echo \%1, echo \%2 }
+ else { echo \%3, echo \%4 }
+ }
+ xx one two three four
+
+With pushqcmd() it echoes the variable names literally; with pushcmd() it
+echoes empty lines. Since ELSE, when its argument is a block, dispatches
+to the immediate-macro handler, it seems we have unified the two problems,
+so fixing one should fix the other.
+
+The problem is that we define a new temporary macro and then call dodo() to
+execute it. But if the definition contains macro arguments, we have added a
+new level of macro invocation, thus wiping out the current level of args.
+The cure is to expand the variables in the immediate macro in the current
+context, before executing it. This means simply changing the cmtxt() call
+that reads the immediate macro to specify xxsting as its processing
+function, rather than NULL, which is used for real macros to defer their
+argument evaluation until after the macro entered. ckuusr.c, 11 Aug 2005.
+
+Added a new makefile target, macosx10.4, for Mac OS X 10.4. This one uses
+an undocumented trick to get the otherwise unavailable-except-by-clicking
+Mac OS X version number (in this case 10.4.2) and stuff it into the HERALD
+string. makefile, 11 Aug 2005.
+
+Built OK on Solaris 9, Solaris 10 (with a few implicit declaration warnings
+in ckuusx.c), Mac OS X 10.4.2 (with some warnings in ckcnet.c and ckcftp.c),
+Mac OS X 10.3.9 (also using the macos10.4 entry, which gets the right
+version number, and gets no warnings at all), RH Enterprise Linux AS4 on AMD
+x86_64, Tru64 Unix 4.0F, SCO UnixWare 7.1.4
+
+For docs and/or scriptlib: Unix C-Kermit can be a stdin/out filter. The
+trick is to use the ASK, ASKQ, or GETC command for input, specifying no
+prompt, and ECHO or XECHO for output, e.g.:
+
+while true {
+ ask line
+ if fail exit 0
+ echo \freverse(\m(line))
+}
+exit 0
+
+FOPEN didn't do anything with the channel number if the open failed, so any
+subsequent command that tried to reference it would get a parse error it was
+undefined or non-numeric, not very helpful. Changed FOPEN to set the
+channel number to -1 if the file can't be opened. Now subsequent operations
+on the channel fail with "Channel -1: File not open". I also added two
+magic channel numbers: -8 means that any FILE command (besides OPEN and
+STATUS) on that channel is a noop that succeeds silently; -9 is a noop that
+fails silently. So now it's possible to simply set a channel number to one
+of these values to disable i/o to certain file without getting lots of error
+messages. dofile(): ckuus7.c, 12 Aug 2005.
+
+Added automatic herald construction for UnixWare 7. makefile, 12 Aug 2005.
+
+Unix isdir() never allowed for arguments that started with tilde, so gave
+incorrect results for ~/tmp/ or ~fdc. The problem was mainly invisible
+since most commands that parsed file or directory names used cmifi(), cmdir(),
+etc, which did the conversions themselves. But IF DIRECTORY was an exception,
+since its operand had to be treated as just text, and then tested after it
+was parsed. ckufio.c, 13 Aug 2005.
+
+Fixed the following:
+"ckuusx.c", line 8959: warning: implicit function declaration: ckgetpeer
+"ckufio.c", line 1869: warning: implicit function declaration: ttwait
+"ckufio.c", line 2941: warning: implicit function declaration: mlook
+"ckufio.c", line 2943: warning: implicit function declaration: dodo
+"ckufio.c", line 2944: warning: implicit function declaration: parser
+"ckcftp.c", line 2625: warning: implicit function declaration: delta2sec
+"ckcftp.c", line 4071: warning: no explicit type given for parameter: prm
+"ckcftp.c", line 8389: warning: no explicit type given for parameter: brief
+ckuusx.c, ckufio.c, ckcftp.c, ckucmd.h. 13 Aug 2005.
+
+Unbuffered stdout code has never worked because the setbuf(stdout,NULL) call
+has to occur before the stdout has been used. The reason it's needed is
+that some Kermit code writes to stderr (which is unbuffered) and other code
+writes to stdout, and therefore typescripts can come out jumbled. Robert
+Simmons <robertls@nortel.com> provided the needed clue when he insisted it
+worked only when executed at the very beginning of main(). So I moved the
+code to that spot. But since now we also want to make unbuffered a runtime
+(command-line) option, I had to do a clunky by-hand pre-prescan inline in
+main() to look thru argv[], even before prescan() was called. ckcmai.c,
+ckutio.c, ckuusy.c, 13 Aug 2005. (Now that this works, it might be a good
+idea to remove all use of stderr from Kermit.)
+
+Managed, after some finagling, to build a 64-bit version on Solaris 10 at
+Utah Math with Sun cc. (Can't make any gcc builds at all, 32- or 64-bit,
+they all blow up in <sys/siginfo.h>.) New target: solaris10_64. makefile,
+15 Aug 2005.
+
+The 64-bit Solaris 10 version compiles and links OK and transfers files in
+remote mode. It can make FTP connections and use them, but Telnet connections
+always fail with "network unreachable". This is with all default libs and
+include files. Nelson has a separate set in /usr/local, which he references
+explicitly in all his 64-bit builds, but using these makes no difference.
+Some data type is wrong in ckcnet.c. But telnet works fine in 64-bit Linux
+and Tru64 builds. Debug logs trace the difference to netopen() (of course),
+the spot where we test the results of inet_addr(), which is already marked
+suspicious for 64-bit builds. It seems that inet_addr() is of type in_addr_t,
+which in turn is u_int32, i.e. an unsigned 32-bit int. Yet the man page says
+that failure is indicated by returning -1. I guess this doesn't matter in
+32-bit builds, but in the 64-bit world, the test for failure didn't work
+right. I made a Solaris-specific workaround, and checked that it works in
+both 32-bit and 64-builds. I really hate typedefs. ckcnet.c, 15 Aug 2005.
+
+Changed the plain-text version (as opposed to the popup or GUI version - the
+GUI version, at least, already does this) of ASKQ to echo keystrokes
+asterisks rather than simply not echo anything, so it's easier to see what
+you're doing, the effects of editing, etc. Experimental; for now, there's
+no way to disable this. Not sure if there needs to be. Anyway, to get this
+working required a fair amount of cleaning up of gtword(), which was echoing
+different ways in different places. ckuus6.c, ckucmd.c, 15 Aug 2005.
+
+Added a solaris9_64 target for building a 64-bit version on Solaris 9 with
+Sun cc. Verified, using the DIR command and \fsize() function on a 4.4GB
+file, that the Solaris 64-bit version of Kermit gets the size correctly, and
+that it can copy such a file (thus its fopen/fread/fwrite/fclose interface
+works right). Initiated a large-file transfer between here and Utah over
+SSH and verified that it puts the correct file size in the A packet when
+sending; the right quantities are shown on the file transfer display (file
+size CPS, percent done, etc). But even at 5Mb/sec, it takes a good while to
+transfer 4.4GB, more than 2 hours (not streaming; 30 window slots, 4K
+packets, maybe it would go faster with streaming)... After an hour or so,
+it filled up the partition and gave up (gracefully) before it reached the
+2GB frontier (drained its pending packets, closed the partial file).
+Restarted at 12:54, this time with streaming and 8K packets (the speed
+wasn't significantly different). This time it transferred 95% of the file
+(4187660288 bytes) before failing because the disk filled up. Went to Utah
+and started a transfer between two Solaris 10/Sparc hosts; this goes about 8
+times faster. The transfer completed successfully after 17m41s. All fields
+in the f.t. display looked right the whole time. Then I verified various
+other 64-bit combinations transferring the same 4.4GB file:
+
+ To................
+ From Sol Amd i64 Tru
+ Sol OK OK OK OK Sol = Solaris 10 / Sparc
+ Amd OK Amd = AMD x86_64 RH Enterprise Linux AS4
+ i64 OK i64 = Intel IA64, RH 2.1AS
+ Tru Tru = Tru64 Unix 4.0F Alpha
+
+(The other combinations are difficult to test for logistical reasons.)
+
+Tried sending the same long file with Kermit's FTP client. It chugged along
+for a while until I stopped it; it would have taken hours to complete.
+There is no indication that it wouldn't have worked, assuming the FTP server
+could also handle long files, which who knows. Anyway, Kermit showed all
+the right data on the display screen. 17 Aug 2005.
+
+On AMD x86_64 and IA64 native 64-bit Linux builds, the pty routines did not
+work at all. ptsname() dumped core. If I commented out ptsname(), then the
+next thing dumped core. The same code works on the other 64-bit builds.
+Poking around, I see that this version of Linux has an openpty() function,
+which I could try using instead of the current API -- grantpty(), etc. Then
+I see that openpty() is already coded into Kermit's pty module,
+conditionalized under HAVE_OPENPTY, which has never before been defined for
+any build. I added a test to the makefile linux target (look for the
+openpty() prototype in <pty.h>, if found define HAVE_OPENPTY as a CFLAG and
+also add -lutil to LNKFLAGS). Works fine on the problem builds, and also
+on previously working 32-bit builds. makefile, 17 Aug 2005.
+
+Fixed a bug in the ASKQ echo asterisks code, which made the VMS version of
+C-Kermit always echo asterisks. Turns out that some code in the main parse
+loop to reset command-specific flags was in the wrong place, which had other
+effects too, for example ASKQ temporarily turns off debug logging as a
+security measure, but the code to turn it back on was skipped in most cases.
+Some other side effects related to the DIRECTORY and CD commands might have
+been possible but I haven't seen them. ckuus[56].c, 23 Aug 2005.
+
+Problem reported when sending a file to VMS when the name in the F packet
+starts with a device specification and does not include a directory field,
+and PATHNAMES are RELATIVE. Example: dsk:foo.bar becomes f_oo.bar. The
+code assumes that if there is a device field, it is followed by a directory
+field, and it inserts a dot after the '[', which in this case is not there.
+Later the dot becomes '_' because of the only-one-dot rule. Solution: only
+insert the dot if there really is an opening bracket. nzrtol(): ckvfio.c,
+23 Aug 2005.
+
+A report on the newsgroup complains that C-Kermit and K95 servers were
+sending REMOTE DIR listings with only #J line terminators, rather than #M#J.
+Yet all the other REMOTE xxx responses arrived with #M#J. snddir() was
+neglecting to switch to text mode. ckcfns.c, 26 Aug 2005.
+
+Back to long files. What happens if 32-bit Kermit is sent a long file?
+It gets an A-packet that looks like this:
+
+ ^A_"A."U1""B8#120050815 18:28:03!'42920641*4395073536,#775-!7@ )CP
+
+The 32-bit receiver reacts like so:
+
+ gattr length[4395073536]=100106240
+
+the first number being the string from the A-packet, the second being the
+value of the long int it was converted to by atol(). Clearly not equal in
+this case. When this happens Kermit should reject the file instead of
+accepting it and then getting a horrible error a long time later. Added
+code to gattr() to convert the result of atol() back to a string and compare
+it with the original string; if they're not equal, reject the file on the
+assumption that the only reason this could happen is overflow. Also some
+other code in case the sender sends the only LENGTHK attribute. Now files
+whose lengths are too big for a long int are rejected right away, provided
+the sender sends the length in an A packet ahead of the file itself. If
+this new code should ever cause a problem, it can be bypassed with SET
+ATTRIBUTE LENGTH OFF. ckcfn3.c, 26 Aug 2005.
+
+As I recall from when I was testing this a few weeks ago, when the too-big
+length is not caught at A-packet time, the transfer fails more or less
+gracefully when the first attempt is made to write past the limit. I went
+to doublecheck this by sending a big file from the 64-bit Solaris10 version
+to a 32-bit Mac OS X version that does not have today's code. The Mac
+thinks the incoming file is 2GB long when it's really 4GB+. But in this
+case, something new happens! Although the percent done and transfer rate go
+negative, the file keeps coming. It would seem that Mac OS X lets us create
+long files without using any special APIs. The transfer runs to completion.
+Mac OS X Kermit says SUCCESS (but gets the byte count and cps wrong, of
+course). But then a STATUS command says FAILURE. The file was, however,
+transferred successfully; it is exactly the same length and compares byte
+for byte with the original. This tells me that in the Mac OS X version --
+and how many others like it??? -- today's rejection code should not be
+enabled. Meanwhile I put today's new code in #ifndef NOCHECKOVERFLOW..#endif,
+and defined this symbol in the Mac OS X 10.4 target. Over time, I'll have
+to find out what other platforms have this characteristic. And of course
+I'll also have to do something about file-transfer display, statistics, and
+status. makefile, ckcfn3.c, 26 Aug 2005.
+
+From now on I'm going to bump the Dev.xx number each time I upload a new
+ckdaily. This one will be Dev.02. ckckmai.c, 26 Aug 2005.
+
+Got rid of all the extraneous FreeBSD 4 and 5 build targets. Now there's
+one (freebsd) for all FreeBSD 4.1 and later. makefile, 27 Aug 2005.
+
+Mac OS X 10.4 (Tiger) is a 64-bit OS. Building C-Kermit 0n 10.4.2 without
+any special switches stilll gives a 32-bit executable. Ditto building with
+-mpowerpc64. Further investigation turned up a tip sheet on MySQL that says
+you have to include all of these: -mpowerpc64 -mcpu=G5 -mtune=G5 -arch
+ppc64. That did the trick. New makefile target: macosx10.4_64. But the
+10.4.2 system I tried did not have 64-bit [n]curses or resolv libs, so this
+build has no -DNOCURSES -DNO_DNS_SRV. makefile, 27 Aug 2005.
+
+Created a symbol CK_64BIT to indicate true 64-bit builds at compile time.
+Added 64-bit announcement to the startup herald and the VERSION text.
+ckcdeb.h, ckuus[r5].c, 27 Aug 2005.
+
+Added a built-in variable \v(bits) to indicate the size of the build
+(16, 32, 64, or whatever else sizeof() might report). ckuusr.h, ckuus4.c,
+27 Aug 2005.
+
+Got rid of all the warnings in 64-bit Mac OS X about args to getsockopt(),
+getsockname(), and getpeername(), and the comparisons on the return value
+of inet_addr(). ckcnet.[ch], 27 Aug 2005.
+
+Now to check the effects on other builds...
+ Linux on AMD64: ok.
+ Linux on IA64: ok.
+ Linux on i386: ok.
+ Mac OS X 10.3.9 32-bit: ok.
+ Solaris 10 64-bit: ok.
+ Solaris 9 32-bit: ok.
+ Tru64 4.0F: ok.
+ FreeBSD 4.11: ok.
+ FreeBSD 5.4 ia64 (64-bit): ok.
+ FreeBSD 5.4 i386 (32-bit): ok.
+
+The Tru64 5.1B build totally blew up because they have their own unique
+sockopt/etc length-argument data type (int!), so I had to roll back on using
+socklen_t for this in all 64-bit builds. Checked to make sure it still
+builds on Tru64 4.0F after this change (it does). ckcnet.h, 27 Aug 2005.
+
+The HP-UX 11i/ia64 build comes out to be 32-bit but thinks it's 64-bit.
+CK_64BIT is set because __ia64 is defined. So how do I actually make a
+64-bit HP-UX build? I tried adding +DD64 to CFLAGS, and this generates
+64-bit object files but linking fails to find the needed 64-bit libs
+(e.g. -lm). For now I added an exception for HPUX to the CK_64BIT
+definition section. ckcdeb.h, 27 Aug 2005.
+
+Took the time to verify my recollection about the "graceful failure" on a
+regular Pentium Linux system when receiving a too-big file... OK, it's not
+exactly graceful. It gets a "File size limit exceeded" error; the message
+is printed in the middle of the file-transfer display, apparently not by
+Kermit, and Kermit exits immediately. Looks like a trap... Yup. "File
+size limit exceeded" is SIGXFSZ (25). What happens if we set it to SIG_IGN?
+Just the right thing: The receiver gets "Error writing data" at 2147483647
+bytes, sends E-packet to sender with this message, and recovers with total
+grace (drains packet buffers, returns to prompt). ckutio.c, 27 Aug 2005.
+
+Backed off from rejecting a file because its announced size overflows a
+long. Now instead, I set the file size to -2 (a negative size means the
+size is unknown, but we have always used -1 for this; -2 means "unknown and
+probably too big"). In this case, the f-t display says:
+
+ File Size: POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT
+
+then the user can interrupt it with X or whatever, or can let it run and
+see if maybe (as in the case of Mac OS X) it will be accepted anyway. This
+way, we skip all the bogus calculations of percent done, time remaining, etc.
+ckcfn3.c, ckuusx.c, 27 Aug 2005.
+
+Discovered that VMS C-Kermit on Alpha and IA64 is a 32-bit application;
+sizeof(long) == sizeof(char *) == 4. Tried adding /POINTER_SIZE=64 to VMS
+DECC builds on Alpha and IA64, but the results aren't great. Tons of
+warnings about pointer size mismatches between Kermit pointers and RMS ones,
+and the executable doesn't run. It appears that access to long files
+would require a lot of hacking, similar to what's needed for 32-bit Linux.
+
+--- Dev.02: 27 Aug 2005 ---
+
+From Jeff, 28 Aug 2005.
+ . Fix SSH GLOBAL-KNOWN-HOSTS-FILE / USER-KNOWN-HOSTS-FILE parsing, ckuus3.c.
+ . Pick up K95STARTFLAGS from environment, ckuus4.c.
+ . Fix some typos in command-line processing (-q), ckuus4.c.
+ . Be sure to suppress herald if started with -q, ckuus7.c.
+ . Fix ssh command-line switches, ckuusy.c.
+
+Eric Smutz complained that HTTP POST was adding an extraneous blank line,
+which prevented his application from successfully posting. RFC 2616 states
+(in Section 4.1):
+
+ In the interest of robustness, servers SHOULD ignore any empty
+ line(s) received where a Request-Line is expected. In other words, if
+ the server is reading the protocol stream at the beginning of a
+ message and receives a CRLF first, it should ignore the CRLF.
+
+ Certain buggy HTTP/1.0 client implementations generate extra CRLF's
+ after a POST request. To restate what is explicitly forbidden by the
+ BNF, an HTTP/1.1 client MUST NOT preface or follow a request with an
+ extra CRLF.
+
+This seems pretty clear. One section of code in http_post() (just above the
+postopen: label) was appending a CRLF to a buffer whose last already was
+terminated by CRLF, and then appended a second CRLF; thus two empty lines.
+I removed the second one. ckcnet.c, 28 Aug 2005.
+
+I looked into the 64-bitness of NetBSD, it seems to be like Linux and
+FreeBSD on 64-bit hardware, i.e. you just build it there and it works, at
+least on Alpha and AMD64, going back to NetBSD 1.4 or 1.5. But I don't have
+access to any of these for verification and documentation on the Web is
+scanty.
+
+Checked PeterE's complaint again of warnings in ckutio.c about parameter
+list of get[ug]id() and gete[ug]id(). When I "make hpux1100o" on HP-UX
+11.11 (PA-RISC), there are definitely no warnings. He says the same thing
+happens on 10.xx, but I don't have access to that any more. I also did
+"make hpux1100o" on HP-UX 11.23 (11i v2) (PA-RISC), also no warnings.
+(Except in both cases, a warning about a comment within a comment in
+/usr/include/sys/ptyio.h). On HP-UX 11i v2 on Itanium, however, there are
+TONS of warnings, mostly of the "variable set but never used" kind. Also
+"dollar sign used in identifier". Tracking this last one down, I see it's
+complaining about code that's in #ifdefs for other platforms, such as
+Apollo Aegis. Is "aegis" defined in HP-UX 11i v2/IA64? No! (It would show
+up in SHOW FEATURES if it was.) Some phase of the compiler is complaining
+about code that it should be skipping (and that, in fact, it *is* skipping
+it because the build is successful). It's as if cc is running lint for me
+but not telling lint which macros are defined and which are not.
+
+Verified that 64-bit linking fails in the same way for HP-UX 11i v2 on both
+IA64 and PA-RISC. Sent a query to HP.
+
+Compiling ckcnet.c and ckcftp.c got the familiar sockopt-related warnings on
+HP-UX 11i v2; turns out it is just like Tru64 Unix in using an int for the
+length argument. Added another special case and the warnings went away.
+ckcnet.h, 28 Aug 2005.
+
+Added some stuff to SHOW FEATURES to see what kinds of macros are exposed
+(e.g. INT_MAX, LONG_MAX, LLONG_MAX, etc) and also show sizeof(long long) and
+sizeof(off_t). Building this code all over the place will give me an idea
+of how widespread these data types are, and to what extent I can tell
+whether they are available from clues in the header files. (At first
+glance, it appears that I'm not picking up <limits.h>, but adding an
+#include for it is just asking for trouble.) No complaints about long long
+or off_t from Solaris 9 or recent Linuxes. ckuus5.c, 28 Aug 2005.
+
+Fixed a warning in HP-UX 10 and 11 stemming from some old-style prototypes
+in ckutio.c for get[re][gu]id(). ckutio.c, 29 Aug 2005.
+
+Updated minix3 target from Andy Tanenbaum. makefile, 29 Aug 2005.
+
+PeterE confirms that "long long" and off_t are available in all HP-UX 10 and
+11, and in HP-UX 9 on PA-RISC but not Motorola. 30 Aug 2005.
+
+Got 64-bit builds to work on HP-UX. According to my notes, John Bigg of HP
+said (in 1999) that HP-UX 10.30 and later require PA-RISC 1.1, and do not
+work on PA-RISC 1.0. But is PA 1.0 64-bit or what? Today, Alex McKale of
+HP said "The 64-bit binaries will work on all machines that have the same or
+later release of HP-UX (excluding PA-RISC 1.1 machines)". Still need
+clarification... Maybe it's that all IA64 builds can be 64-bit but I need
+dual builds for PA-RISC. Meanwhile I started transfer of a 4GB+ file from
+Solaris to HP-UX 11i but it exceeded some quota on the HP long before it
+approached the 2G point. It failed cleanly and up until then it was working
+fine (numbers, stats, etc). 30 Aug 2005.
+
+Support of large files in 32-bit builds began in 10.20. 64-bit application
+support began in 11.00, but not all machines that run 11.00 support 64 bits.
+About long files, see HP /usr/share/doc/lg_files.txt.
+
+PeterE found that certain patterns can still make Kermit loop; example:
+
+ if match T01011-00856-21-632-073 *[abc] { echo GOOD } else { echo BAD }
+ if match T01011-00856-21-632-073 *[a-z] { echo GOOD } else { echo BAD }
+
+The minimum offending pattern is * followed immediately by an [xxx]
+construction, followed by anything else, including nothing. Previous
+versions of Kermit handled this one correctly, without looping (but failed
+certain matches that should have succeeded). The new section of code I
+added on 15 June, upon failure to match, advances the string pointer and
+backs up the pattern to the previous pattern, and starts again
+(recursively). However, there needed to be a corresponding check at entry
+for an empty target string. ckmatch(): ckclib.c, 12 Sep 2005.
+
+PeterE discovered that "kermit -y filethatdoesnotexit" gives an erroneous
+error message that names the user's customization, rather than the name
+given on the command line. doinit(): ckuus5.c, 12 Sep 2005.
+
+FREAD does not get an error if it tries to read a record or file or piece of
+file that is too big for its buffer. In particular, FREAD /SIZE:xxx seems
+to succeed even if less than xxx was read. It should fail unless, perhaps,
+it successfully read up to the end of the file. Furthermore, if xxx is
+bigger than the file buffer size, it should complain. The buffer is
+line[LINBUFSIZ], 32K. The lack of failure was due to code in dofile() that
+adjusted the given size silently if it was greater than the buffer size,
+which I removed, and also added a check when parsing the /SIZE: switch.
+dofile(): ckuus7.c, 12 Sep 2005.
+
+That still didn't help with FREAD /SIZE:n returning less than n bytes, even
+when they were available. That's because the underlying routine, z_in(),
+didn't check fread()'s return code, which is the number of bytes read.
+If fread() has smaller buffers, it needs to be called in a loop. z_in():
+ckuus7.c, 12 Sep 2005.
+
+Flen() fails on strings of length 8192 or more. The limitation is in the
+callers of zzstring, which seem to be specifying an 8K buffer, in this case
+fneval(). The operable symbols are FNVALL (max length of value returned by
+a function) and MAXARGLEN (maximum length of an argument to a function). I
+changed both of these for BIGBUFOK builds to be CMDBL. Buffers can never be
+infinite, there has to be a limit. It's important to make everything work
+consistently within that limit, and to make something useful happen when the
+limit is exceeded. At this point, I can probably also increase the limits
+for modern 32-bit systems, and certainly for 64-bit ones. Also there's no
+point in worrying about 16-bit platforms any more; earlier C-Kermit versions
+can still be used on them if necessary. ckuusr.h, 12 Sep 2005.
+
+Special #ifdefs for finding resolv.h and nameser.h in MINIX3 from Andy
+Tanenbaum. ckcnet.c, 20 Sep 2005.
+
+PeterE noticed that ckmatch(), even though it works pretty well now, does a
+lot of extra and unnecessary recursion after determining the string and
+pattern do not match, at least when the pattern is of the form *[abc].
+After several false starts I was able reduce this effect to a minor level
+(but not eliminate it all together) by changing a while loop into a do loop.
+ckmatch(): ckclib.c, 15 Oct 2005.
+
+Added -DNOLONGLONG to HP-UX 8.00 and earlier builds, and to Motorola-based
+HP-UX 9.00 builds. This is simply to inhibit the test for whether "long
+long" is supported by the compiler, since when it isn't, the module
+containing the test won't compile. makefile, ckuus5.c, 16 Oct 2005.
+
+Making ASKQ always echo asterisks is a bad idea, because when it doesn't
+echo, it's the perfect way to read silently from stdin, e.g. in a CGI script
+(INPUT can also be used for this but it's not as straightforward). So I put
+the default for ASKQ back to no echoing, then gave ASKQ its own switch
+table, which is the same as for ASK with the addition of an /ECHO:x switch,
+which tells what character to echo. ckucmd.c, ckuus[26].c, 17 Oct 2005.
+
+Fixed a bug in FTP GET /COMMAND filename commandname; it always dumped core
+dereferencing a null string (the nonexistent local asname). ckcftp.c,
+17 Oct 2005.
+
+For docs: if you don't like the funny business that happens when you type
+an IF command at the prompt, use XIF instead and it won't happen. Also note
+that commands like "if xxx { echo blah } else { echo blah blah }" don't
+work when typed at the prompt; you have to use XIF for this.
+
+Back to ckmatch()... Under certain conditions (e.g. patterns like *[abc])
+failure to match would not stop the recursion because the string and pattern
+arguments are on the stack, as they must be, so there was no way for level
+n-1 to know that level n had detected a definitive nonmatch and that no
+further attempts at matching were required. The right way to handle this is
+to recode the whole thing as coroutines, the cheap way out is with a global
+static flag. Works perfectly, in the sense that the match.ksc test results
+are identical to what they were before and the extra backing up and
+recursion are eliminated. (The Oct 15th fix wasn't really a fix, it broke
+a couple of cases.) ckclib.c, 20 Oct 2005.
+
+ckuus7.c(2987): warning #267: the format string requires additional arguments
+(in PURGE command); fixed 20 Oct 2005.
+
+From Andy Tanenbaum, final changes for MINIX3: #ifdef out the inline
+definitions for gettimeofday() and readlink(). ckutio.c, 23 Oct 2005.
+
+From Jeff: struct gss_trials initializers changed from gss_mech_krb5 to
+ck_gss_mech_krb5. ckcftp.c, 23 Oct 2005.
+
+From Jeff: some improvements to K95 GUI SHOW TERMINAL. ckuus5.c, 23 Oct 2005.
+
+Found and corrected some misplaced #ifdefs in shofeat(), ckuus5.c, 23 Oct 2005.
+
+--- Dev.03 ---
+
+Fixed a compiler warning in a debug() statement in zzstring() by adding
+parens. ckuus4.c, 24 Oct 2005.
+
+Added -DNOLONGLONG to sv68r3v6 target, makefile, 25 Oct 2005.
+
+New makefile targets for HP-UX from PeterE to handle the 'long long'
+situation. 26 Oct 2005.
+
+From Jeff: changes to support OpenSSL 0.9.8, ck_ssl.h. ckcasc.h has had
+short names defined for ASCII control characters for 20-some years but now
+they are causing conflicts, so EM becomes XEM (also for OpenSSL 0.9.8).
+Changed K95's default terminal type from VT320 to VT220 because VT320
+termcaps/terminfos are disappearing from Unix hosts: ckuus7.c. Reorganize
+the data-types section of SHOW FEATURES to add more macro tests for integral
+sizes and to provide for the proper printf formatting in order to allow the
+sizes to be output ("You are going to need to be careful because %llx is not
+supported on all platforms. On Windows, it is the same as %lx, 32 bits"):
+ckuus5.c, 26 Oct 2005.
+
+Defined NOLONGLONG ckcdeb.h for various old platforms where we know we are
+never going to need 64-bit ints (even if they support a long long datatype,
+chances are pretty slim they supported 64-bit file sizes). ckcdeb.h,
+26 Oct 2005.
+
+PeterE noticed that GOTO targets can only be 50 characters long. This was
+by design, a long time ago, on the assumption that nobody would make longer
+labels. But in SWITCH statements, case labels can be variables that expand
+to anything at all. If we chop them off at 50, we might execute the wrong
+case. Changed the maximum label size to be 8K, and added code to dogoto()
+to check when a label or target is too long and fail, to prevent spurious
+GOTO or SWITCH results. ckuusr.h, ckuus[r6].c, 26 Oct 2005.
+
+Testing revealed there was still a problem with SWITCH case labels that were
+variables that expanded into long strings. Turns out that I was being
+too clever when I decided that, if the SWITCH macro was n1 characters long
+and the case-label search target was n2 characters long, I only had to
+search the first n1-n2+1 characters of the macro definition. That was true
+before I allowed case labels to be variables, but not any more! Fixed in
+dogoto(): ckuus5.c, 26 Oct 2005.
+
+--- Dev.04 ---
+
+Dev.04 didn't actually contain Jeff's data-type changes to shofeat(),
+I think I saved the wrong buffer in EMACS... Fixed now. 27 Oct 2005.
+
+PeterE corrected a typo in the HP-UX 7.00 makefile target. 27 Oct 2005.
+
+PeterE had been reporting problems stress-testing the new SWITCH code, but
+only on HP-UX 9, primarily stack overrun. Turns out to be the HP-UX 9
+optimizing compiler's fault. No optimization, no problems.
+
+PeterE found that even when dogoto() detects a string that is too long
+and fails, this does not stop SWITCH from producing a result, which can not
+possibly be trusted. Changed the part of dogoto() that handles this to
+not just fail, but also to exit the script immediately and return to top
+level. ckuus6.c, 28 Oct 2005.
+
+An idea popped into my head after having typed too many commands like "dir
+ck[cuw]*.[cwh]" to check the list of matching files, and then having to
+retype the same filespec in a SEND command: Why not unleash some unused
+control character such as Ctrl-K to spit out the most recently entered input
+filespec? It was easy, just a few lines in cmifi2() and gtword(), plus a
+couple declarations. To see all the changes, search for "lastfile" (all the
+new code is protected by #ifndef NOLASTFILE). ckucmd.c, 28 Oct 2005.
+
+I added a new variable \v(lastfilespec) that expands to the same last
+filespec, for use in scripts. ckuusr.h, ckuus4.c, 28 Oct 2005.
+
+The Unix version of C-Kermit failed to put anything in the session log if
+SET TERMINAL DEBUG ON. Rearranged the pertinent clause so logging happens
+independent of TERMINAL DEBUG. For now, since the user who noticed this
+wanted debug format to go into the session log, that's what I do. The
+alternative would be to just log the raw incoming stream as usual, or to add
+Yet Another SET Command to choose. ckucns.c, 11 Nov 2005.
+
+Fixed HELP INTRO text. ckuus2.c, 11 Nov 2005.
+
+Added NOLONGLONG for SV68. ckcdeb.h, 11 Nov 2005.
+
+--- Dev.05 ---
+
+Added a debug() statement in FTP secure_getbyte() to see what's going on
+with Muhamad Taufiq Tajuddin's 205-byte-per-second FTP/SSL downloads.
+
+--- Dev.06 ---
+
+Result: nothing, SSL_get_error() does not report any errors. Suggested
+testing SSL_read()'s return code, if 0 don't update the screen.
+
+Created a new data type CK_OFF_T in ckcdeb.h that will eventually resolve
+to whatever each platform uses for file sizes and offsets. ckcdeb.h,
+17 Nov 2005.
+
+Made a new library routine ckfstoa() that converts a file size or offset to
+a string. This is to solve the problem with having to use different
+printf() formats for different representations of file size (int, long, long
+long, off_t, signed, unsigned, etc). Replaced a few printf("%l",size) with
+printf("%s",ckfstoa(size)) with the expected results. This is just a start,
+the definitions will need adjustment for many platforms, variables need to
+be redeclared, and all the offending printf's (and printw's) will have to
+hunted down and converted. ckclib.[ch], ckuus4.c, 17 Nov 2005.
+
+Built a minimal version on Linux with:
+make linux "KFLAGS=-DNOLOCAL -DNOICP -DNOCSETS -DNODEBUG"
+Worked fine, result was 260K on i686. 21 Nov 2005.
+
+Discovered that Kermit's date parser, contrary to the documentation, failed
+to handle strings like "Wed, 13 Feb 2002 17:43:02 -0800 (PST)", which are
+commonly found in email. This was because of an overzealous and misguided
+check in the code; once removed, all was well. ckucmd.c, 26 Nov 2005.
+
+Added a new format code 4 to \fcvtdate() to emit asctime() format, used in
+BSD-format email message envelopes (i.e. the "From " line). shuffledate(),
+ckucmd.c, ckuus[24].c, 26 Nov 2005.
+
+Added a new function \femailaddress(). Given a From: or Sender: header line
+from an RFC2822-format email address, extracts and returns the actual email
+address, such as kermit@columbia.edu. ckuusr.h, ckuus[42].c, 26 Nov 2005.
+
+Using the new functions, I wrote a script to fetch mail from a POP3 server
+over a TLS connection. But the line-at-a-time input (needed for changing
+line terminators and byte-stuffing text lines that start with "From ") is
+slow, 17 sec to read 29 messages totaling 175K.
+
+Added INPUT /CLEAR so INPUT can be started with a clean buffer without
+requiring a separate CLEAR INPUT command. ckuusr.h, ckuus[r24].c,
+27 Nov 2005.
+
+One thing that INPUT was never able to do well was read and save the
+complete incoming data stream. That's because, while waiting for its
+target, the buffer might overflow wrap around. Yet there was never a way to
+tell it to stop when its buffer fills up and let me save it. I added a
+/NOWRAP switch that does this. If the buffer fills up before any other
+completion criterion is met, INPUT returns failure, but with \v(instatus)
+set to 6 (the next available instatus value). Thus a program that wants to
+read and save (say) an email message from a POP server, which could be any
+length at all, and which terminates with <CRLF>.<CRLF> could do this:
+
+ set flag off
+ while open connection {
+ input /nowrap 10 \13\10.\13\10 # Wait for <CRLF>.<CRLF>
+ if success {
+ frwrite /string \%o {\freplace(\v(input),\13\10.\13\10,\13\10)}
+ set flag on
+ break
+ } else if ( == \v(instatus) 6 || == \v(instatus) 1 ) {
+ frwrite /string \%o {\v(input)}
+ continue
+ }
+ break
+ }
+ if flag (handle success)
+
+Note carefully the braces around the FWRITE text; without them, trailing
+spaces would be lost.
+
+Previously the only way to INPUT an entire data stream without losing
+anything (assuming it was ordinary lines of text that were not "too long"),
+was line-by-line:
+
+ while open connection {
+ input /clear 10 \13\10
+ if fail break
+ if eq "\v(input)" "$ \13\10" break
+ fwrite /string \%o {\freplace(\v(input),\13\10,\10)}
+ }
+
+The new code is 3 times faster using the default INPUT buffer length of 4K.
+Raising it to 16K makes it 3.6 times faster (not worth it). Changing the
+POP3 script to use INPUT /NOWRAP makes it about twice as fast (it does more;
+it has to do all the byte-stuffing and unstuffing). 27 Nov 2005.
+
+Changed ssl_display_xxx() to just return if SET QUIET ON. Otherwise there
+is no way to suppress the messages. Also protected a previously unprotected
+printf("[SSL - OK]\r\n"); by if ( ssl_verbose_flag ). ck_ssl.c,
+28 Nov 2005.
+
+Discovered that FOPEN /APPEND doesn't work if the file doesn't exist. It
+uses cmiofi() which is a super-hokey front end to cmifi2(). I had code to
+call it but for some reason it was commented out, with a note to the effect
+it didn't work. I uncommented it but that didn't help much. So I wrote an
+entirely new cmiofi() that works exactly as it should, using chained FDBs,
+_CMIFI to _CMOFI (I think the original cmiofi() predated chained FDBs).
+ckuus7.c, ckucmd.c, 29 Nov 2005.
+
+Getting rid of the awful hacks required to call cmiofi() meant I also had to
+change the EDIT command, which is the only other place where it's used.
+Unfortunately now it's no longer possible to give EDIT without a filename
+(to just start an empty editor) but I doubt anyone will notice. ckuusr.c,
+29 Nov 2005.
+
+IF KERBANG didn't always work right. If a kerbang script TAKEs another
+kerbang script, the second one should have IF KERBANG false, but it didn't.
+Added a check for \v(cmdlevel) == 1. Now you can write a wrapper that runs
+a kerbang script in a loop, and the latter can use IF KERBANG to know
+whether to EXIT (if called at top level) or END (if called by another
+script, thus allowing -- in this case -- the loop to continue). ckuus6.c,
+29 Nov 2005.
+
+Changed \flop() and flopx() functions to take a third argument, a number
+signifying at which occurrence of the break character to lop, so:
+
+ \flopx(sesame.cc.columbia.edu) = edu
+ \flopx(sesame.cc.columbia.edu,,2) = columbia.edu
+
+ckuus[24].c, 1 Dec 2005.
+
+Built OK on VMS 7.2-1 with MultiNet 4.4. Built with and without OpenSSL on
+Linux OK, ditto Solaris 9. Built OK on RH Linux AS4 on X86_64 (64-bit);
+"show var fsize" (using new ckfstoa()) works OK there. Also Mac OS X 10.3.9
+(32-bit), Tru64 UNIX 4.0F (64-bit), HP-UX 11iv2 (64-bit) (picky new compiler
+spews out tons of useless warnings), FreeBSD 6.0 on ia64 (64-bit).
+
+--- Dev.07 ---
+
+Changed "make netbsd" to be a synonym for "make netbsd2" because the
+original netbsd target was ancient. Renamed it to netbsd-old. makefile,
+3 Dec 2005.
+
+Updated INPUT and MINPUT help text. ckuus2.c, 3 Dec 2005.
+
+Discovered that on a SET PORT /SSL connection, Kermit treats incoming
+0xff data bytes (e.g. sent from the POP server) as IACs and goes into Telnet
+negotiations. Jeff says "You will need to implement NP_SSLRAW and NP_TLSRAW
+that do the same as NP_TCPRAW but negotiate SSL or TLS as appropriate."
+This was not as easy as it sounded, because apparently a lot of the Telnet
+code is used by SSL and TLS even when Telnet protocol is not being executed.
+I wound up doing this as follows: I added /SSL-RAW and /TLS-RAW to the
+switch table. Rather than disable Telnet, they do exactly what the /SSL and
+/TLS switches do, but also set a special flag. This flag is checked in only
+two place: netclos() (to prevent Kermit from sending TELNET LOGOUT when
+closing the connection), and tn_doop() (to prevent Kermit from reacting to
+incoming IACs; it makes tn_doop() return(3), which means "quoted IAC", which
+causes the caller to keep the IAC as data). ckcnet.h, ckctel.h, ckctel.c,
+ckuus7.c, 4 Dec 2005.
+
+The INPUT command did not account for tn_doop() returning 3. Fixed in
+doinput(), ckuus4.c, 4 Dec 2005.
+
+Added another debug() statement in FTP secure_getbyte() to see what's going on
+with Muhamad Taufiq Tajuddin's 205-byte-per-second FTP/SSL downloads, plus
+new code to test SSL_read()'s return code (byte count); if 0 don't update
+the screen. ckcftp.c, 4 Dec 2005.
+
+--- Dev.08 ---
+
+Fixed a typo in the non-ANSIC definition of ckfstoa(). ckclib.c, 7 Dec 2005.
+
+Our Ctrl-C trap (the ON_CTRLC macro) wasn't working for kerbang files.
+Rearranged some code to make it work. ckcmai.c, 8 Dec 2005.
+
+Started converting code to use CK_OFF_T for file sizes and offsets, and
+all [s]printf's to replace "%ld" or whatever with "%s", and the size
+variable with a call to ckfstoa(). Since I haven't actually changed the
+definition of CK_OFF_T from what all the size variables were to begin
+with (i.e. long), it shouldn't do any harm. So far just ckcfn3.c
+10 Dec 2005.
+
+An updated HP-UX 9.xx makefile target from PeterE to fix a core dump that
+happens on that platform due to insufficient resources. 14 Dec 2005.
+
+Added debug() statements to http_blah() routines to tell whether the
+connection is "chunked". There seems to be a bad performance problem.
+ckcnet.c, 14 Dec 2005.
+
+PeterE complained about ugly DIRECTORY error message, ?No files match -
+"{blah}". The braces are used internally in case the user typed more than
+one filespec. I changed the error message to remove them. Ditto DELETE.
+ckuus6.c, 15 Dec 2005.
+
+The problem with HTTP downloads is that Kermit always does single-character
+read() or socket_read() calls (or the SSL equivalent); see http_inc(). I
+added buffering code for non-SSL connections only but it's gross because it
+has to swap ttyfd and httpfd before calling nettchk(). I tried making a
+nettchk() clone that accepts a file descriptor as an argument but it didn't
+work because too many other routines that are invoked directly or implicitly
+by nettchk() (such as in_chk()) are still hardwired to use ttyfd. HTTP GETs
+are now 20 times faster on the local network (the improvement is less
+dramatic over a clogged Internet). ckcnet.[ch], 15 Dec 2005.
+
+--- Dev.09 ---
+
+HTTP file-descriptor swapping is not thread safe. Doing it right, of
+course, is a big deal, so for now I just don't define HTTP_BUFFERING for
+Windows. ckcnet.c, 15 Dec 2005.
+
+Noticed that HTTP not included in FreeBSD and OpenBSD builds. Fixed in
+ckcdeb.h, 22 Dec 2005.
+
+Fleshed out 32/64-bit data type definitions and changed struct zattr
+(file attribute structure) members length and lengthk to have the new
+CK_OFF_T type. Changed final arguments of debug() and tlog() to be the new
+LONGLONG type. ckcdeb.h, 22 Dec 2005.
+
+Changed ckfstoa() to return a signed number in string form, rather than an
+unsigned one. That's because off_t is signed (thank goodness). Added the
+inverse function, ckatofs() so we can convert file sizes and offsets back
+and forth between binary number and string. ckclib.c, 22 Dec 2005.
+
+Changed Attribute Packet reader to convert incoming file size attribute
+with ckatofs() rather than atol(). ckcfn3.c, 22 Dec 2005.
+
+Converted debug(), tlog(), ckscreen(), etc, to handle potentially "long long"
+arguments by making their "n" argument CK_OFF_T. ckuusx.c, ckcdeb.h,
+22 Dec 2005.
+
+Converted the rest of the source files to use CK_OFF_T for all file size
+and offset and byte-count related variables, and converted all references to
+these variables in printfs to go through ckfstoa(). Then I built it on
+Linux/i386 with:
+
+ make linux "KFLAGS=-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+
+which makes off_t be 64 bits and magically makes all the regular file APIs
+use 64-bit sizes and offsets without changing the API calls in the source
+code. It's going to be a lot of work to get through all the kinks but I was
+able to send a long file, do directory listings of long files, do
+\fsize(longfile), etc. When it sends a file, the length is shown correctly
+in the A packet. If the receiver does not support big numbers, it receives
+the file OK anyway, without showing the size, the thermometer, or percent
+done (and then will get an error when the file keeps coming after the 2G
+mark). Kermit 95 actually refuses long files for "Size", but only if the
+announced is less than 2^63 bytes. When today's Linux version receives a
+file, it shows the length correctly in the file-transfer display, as well as
+percent done, thermometer, etc. Also built this version on true 64-bit
+Linux, and it worked fine. Many files changed, 22 Dec 2005.
+
+For the record, this API is specified in X/Open's Single UNIX Specification
+Version 2, which is branded as UNIX 98. It is called Large File Support, or
+LFS, and was developed at the Large File Summit.
+
+It looks like the operative feature-test macro in glibc for transitional
+large file support is __USE_LARGEFILE64. So if this is defined, we can also
+supply _LARGEFILE_SOURCE and _FILE_OFFSET_BITS=64 automatically for 32-bit
+Linux builds. But there's a Catch-22, you don't know if this is defined
+until you read the header files, but you have to define _LARGEFILE_SOURCE
+and _FILE_OFFSET_BITS before you read the header files. Maybe it's good
+enough to grep through <features.h> for __USE_LARGEFILE64. makefile,
+23 Dec 2005.
+
+Checked this on true 64-bit Linux. The same symbols are defined in CFLAGS,
+but they do no harm; it builds without complaint and works fine. 24 Dec 2005.
+
+Built it on Red Hat Linux 6.1 from 1999. This picked up the long file
+support too. Guess 6.1 isn't old enough to not have it! Kermit seems to
+work OK on regular files but I don't have enough disk space to create a long
+file, and my bigfile.c program (which creates a long file containing only 1
+byte) doesn't work ("fseeko: invalid argument"). It looks like parts of
+this API were visible in Linux before they were actually working.
+24 Dec 2005.
+
+Converted all fseek() and ftell() to macros that expand to fseek() and ftell()
+or fseeko() and ftello() depending on whether _LARGEFILE_SOURCE is defined.
+ckufio.c, ckuus7.c, ckuusx.c, 24 Dec 2005.
+
+Made a CK_OFF_T version of cmnum(). It would be a very big deal to just
+change cmnum() to return a new type, so another idea is to rename cmnum() to
+something else, cmnumw(), change its result argument to CK_OFF_T, and then
+make a stub cmnum() to call it to get an int, then call cmnumw() explicitly
+any time we need a big number. ckucmd.c, 24 Dec 2005.
+
+Calling cmnumw() directly requires changes to each routine that uses it.
+The INCREMENT and DECREMENT commands, for example, required changes to
+doincr(), varval(), and incvar(), and all references to them. ckuusr.[ch],
+ckuus[56].c, 24 Dec 2005.
+
+Calling cmnumw() in chained FDBs required defining a new function code,
+_CMNUW, adding a new member to the OFDB struct for returning wide results,
+and adding a new case to cmfdb(). ckucmd.[ch], 24 Dec 2005.
+
+Changed FSEEK and FCOUNT to use the new chained FDB interface, now we can
+seek and look past 2GB. ckuus7.c, 24 Dec 2005.
+
+Next come switches, which store their results in a struct stringint. This
+struct was defined in each module where it was used (ckuus[r367].c, ckcftp.c).
+I moved the definition to ckuusr.h and added a wval member, which can be
+referenced by any switch-parsing code that calls cmnumw(). 24 Dec 2005.
+
+Changed SEND /CALIBRATE:n to allow big values of n. This makes it possible
+to test the protocol aspects of long-file transfer without actually having a
+long file handy. ckuusr.c, 24 Dec 2005.
+
+SEND /SMALLER-THAN:n, SEND /LARGER-THAN:n, and and SEND /START:n also now
+allow large values of n. ckuusr.c, 24 Dec 2005.
+
+Changed the algebraic expression evaluator to use wide values.
+ckuus5.c, 24 Dec 2005.
+
+Fixed ckfstoa() to handle the case when n is negative and (0 - n) is also
+negative, which happens for numbers 2^(n-1) or greater, where n is the
+number of bits in the word size we're dealing with, e.g. 64, in which case
+2^63 has its sign bit set so seems to be negative. In such cases, ckfstoa()
+returns "OVERFLOW" instead of a numeric string. We'll have to see how this
+plays out but I think it's better to cause a parse error and stop things
+dead than to return a spurious number. ckclib.c, 24 Dec 2005.
+
+Converted the S-Expression handler to use wide integers. ckuus3.c, 24 Dec 2005.
+
+Took all the LONGLONG stuff out of ckcdeb.h, we don't need it.
+
+All of these changes result in 64-bit arithmetic (more or less) on 32-bit
+Linux, as well as on true 64-bit platforms.
+
+Rebuilt today's code on Solaris 9 in the 32-bit and 64-bit worlds, on Red
+Hat 6.1, Red Hat AS4.2. I haven't bothered trying a 32/64 hybrid build for
+Solaris, since I can build a pure 64-bit version there. Quick tests show
+the large-number arithmetic works OK in all cases except, of course, on pure
+32-bit builds (unfortunately I can't find a running Linux system old enough
+to verify this for Linux, but it's true for other 32-bit platforms).
+24 Dec 2005.
+
+Tried building a hybrid version on Solaris 9 after all since the LFS API is
+ostensibly the same as for Linux:
+
+ make solaris9 "KFLAGS=-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+
+It built smoothly and the resulting binary is 2.5MB compared to 3.4MB for
+the 100% 64-bit version. Looks like a keeper. For now, added solaris9lfs
+and solaris10lfs entries to the makefile but if these work on PCs we can
+make these the regular entries for Solaris 9 and 10. 27 Dec 2005.
+
+Built on Mac OS X 10.4 with the regular target. It seems that in that case,
+off_t is 64 bits anyway. Noticed that a lot of stuff didn't work, like
+exponentiation in S-Expressions. Tried building it as above, which worked,
+and now CK_OFF_T is 64 bits instead of 32, but (^ 2 30) is still 2.0. In
+fact 2-to-the-any-power is 2.0. It seems that the Mac OS X version did not
+have FNFLOAT defined. It also seems that every test in dosexp() like:
+
+ if (result != fpresult) fpflag++;
+
+should have been protected by #ifdef FNFLOAT..#endif /* FNFLOAT */ -- a
+double-ended break, as they say in the nuclear power industry. ckuus3.c,
+27 Dec 2005.
+
+Added GREP /EXCEPT:pattern. ckuus[26].c, 27 Dec 2005.
+
+Fixed a problem with uninitialized pv[].wval (switch-parsing parameter-value)
+members that showed up on certain platforms or with certain compilers. Now
+the Mac OS X 10.4 version works. ckuus[r367].c, ckcftp.c, 28 Dec 2005.
+
+Built on Unixware 7.1.1, a pure 32-bit build, seems fine. Rebuilt on Red
+Hat AS 4.2 just to make sure I didn't break anything, it's OK. No testing
+on HP-UX, etc, because HP testdrive file system is full, can't upload
+anything. 29 Dec 2005.
+
+Commented out the SHOW FEATURES section that displays constants like
+INT_MAX, CHAR_MAX, etc, because printing each value in the appropriate
+format is too tricky, and we don't need them anyway. ckuus5.c, 29 Dec 2005.
+
+Updated ckvfio.c to use CK_OFF_T for the relevant variables. Built and
+tested on VMS/Alpha 7.2: file transfer in remote mode; making a Telnet
+connection and then local-mode file transfer; S-Expressions, all OK. Also
+built a no-net version OK. 29 Dec 2005.
+
+Built and tested on Red Hat AS4 AMD X86_64, used it to upload new sources to
+FreeBSD 4.11. Built on FreeBSD 4.11/i386. Here's another one where off_t
+is 64 bits, even though long is 32 bits. But it seems to work ok, not sure
+why, when CK_OFF_T is 32 bits. There is no _LARGEFILE_SOURCE stuff in the
+header files. 29 Dec 2005.
+
+Built on Mac OS X 10.3.9 using the new macosx10.4 target to pick up LFS.
+Works fine.
+
+Built on Red Hat Linux 4WS on IA64 (64-bit). Now this one is odd, stat()
+fails on big files. It happens also if I use the "linuxnolfs" target, which
+does not define _USE_LARGEFILE or _FILE_OFFSET_BITS=64. DIRECTORY BIGFILE
+shows the size as -1, but if "log debug", it says "no files match", i.e.
+different behavior, observer effect. I hate when that happens.
+
+Let's see if that's an anomaly... Built on Tru64 Unix 4.0F (64-bit Alpha).
+It sees long files just fine. Rebuilt and checked on x86_64 again... fine.
+OK, let's not worry about IA64 yet.
+
+Another small fix to the HP-UX 9.0 target from PeterE. makefile, 29 Dec 2005.
+
+---Dev.10---
+
+Code adjustments from Jeff, mainly to the SSL and TLS Raw mode code from
+several weeks ago, plus changing some data types in the security code to
+CK_OFF_T, plus a different data type for CK_OFF_T for K95 because Windows
+size_T isn't signed. This presumably will allow large-number arithmetic but
+it will not give large file access because that will require replacing all C
+library file i/o calls (esp. in ckofio.c) with native Windows APIs. Build
+on Solaris 9 with and without SSL and on Linux RH AS4.2 with and without
+SSL. ck_crp.c, ck_ssl.c, ck_ssl.h, ckcdeb.h, ckcftp.c, ckcmai.c, ckcnet.c,
+ckcnet.h, ckctel.c, ckuat2.h, ckuus4.c, ckuus7.c, ckuusr.c, 30 Dec 2005.
+
+It was reported that WRITE SESSION always returned a failure status, even
+when it succeeded. The problem was that Unix versions of zsout() and
+zsoutl(), for the session log only, were using write() and returning
+write()'s return code, which is different from what zsout() and zsoutl() are
+documented to return. Also plugged a couple potential holes in zsoutx()
+that I noticed while I was in the neighborhood. ckufio.c, 30 Dec 2005.
+
+Added FSEEK /FIND:pattern. This form of FSEEK accepts all the other
+switches and arguments and performs the desired seek. Then, if the seek was
+successful, it starts from that point and reads through the file, line by
+line, searching for the first line that contains the given string or matches
+the given (unanchored) pattern and, if found, sets the file pointer to the
+beginning of that line. Useful, e.g., for very long timestamped logs, where
+you want to start processing at a certain date or time; searching for a
+particular string is much faster than doing date comparisons on each line.
+ckuus[27].c, 30 Dec 2005.
+
+It was annoying me that FILE STATUS (FSTATUS) required a channel number to
+be given even if only one file was open, so I supplied the correct default
+in that case. ckuus7.c, 30 Dec 2005.
+
+INPUT /NOWRAP, added recently, is used for efficiently copying the INPUT
+stream intact, but it's not good for matching because if the INPUT target is
+broken between the end of the previous buffer and the beginning of the next
+one, the context is lost and the match does not occur. I thought of several
+ways around this, but they all involve saving a huge amount of context --
+old input buffers, the arrays of target strings and corresponding match
+positions, etc. The alternative is fairly simple but it's not transparent
+to the user. Here's what I did in a POP script:
+
+ .eom := "\13\10.\13\10"
+ set flag off # FLAG ON = success
+ while ( open connection && not flag ) {
+ .oldinput := \fright(\v(input),8) # Save tail of previous INPUT buffer
+ input /clear /nowrap 4 \m(eom) # Get new INPUT buffer
+ if success { # INPUT matched - good
+ .s := {\freplace(\v(input),\m(eom),\13\10)}
+ set flag on
+ } else { # No match
+ .s := \v(input) # Check if target crossed the border
+ .oldinput := \m(oldinput)\fsubstr(\v(input),1,8)
+ if \findex(\m(eom),\m(oldinput)) set flag on
+ }
+ ...
+ }
+
+I think this will be easier to explain than any dangerous and grotesque
+magic I might put into doinput() itself. For now, added a few words about
+this to HELP INPUT. ckuus2.c, 30 Dec 2005.
+
+Back to the pattern matcher. Noticed that "IF MATCH index.html [a-hj-z]*"
+succeeded when it should have failed. In ckmatch(), the clist section
+needed one more clause: it can't float the pattern if an asterisk does not
+occur in the pattern before the clist. This change fixes the problem
+without breaking any other cases that weren't already broken, most of which
+involve slists, i.e. {string,string,string,...}. ckclib.c, 30 Dec 2005.
+
+Tried FSEEK /FIND: on a largish file (over 100,000 lines), using it to seek
+to a line near the end. It took 0.756 seconds, compared with Unix grep,
+which did the same thing in 0.151 sec. That's because C-Kermit is using
+ckmatch(). But if the search target is not a pattern, it should be a bit
+faster to use ckindex(). Yup, 0.554 sec, a 36% improvement. Can't expect
+to compete with grep, though; it's highly tuned for its single purpose.
+ckclib.[ch], ckuus7.c, 1 Jan 2006.
+
+Updated visible copyright dates to 2006: ckcmai.c, ckuus2.c, ckuus5.c,
+1 Jan 2006.
+
+Noticed that NetBSD 2.0.3 has 64-bit off_t, and that _LARGEFILE_SOURCE is
+mentioned in <stdio.h>. Tried building Kermit with _LARGEFILE_SOURCE added
+to CFLAGS, it's good. Added it to the netbsd target. makefile, 1 Jan 2006.
+
+Fixed typo, #ifdef CK_NOLONGLONG in ckuus5.c should have been #ifndef
+CK_LONGLONG (which, it turns out, we don't use anyway). 2 Jan 2005.
+
+Observed that FreeBSD 4.x has a 64-bit off_t, but does not use the
+_LARGEFILE_SOURCE convention. Reasoning that all versions of FreeBSD have
+off_t (I was able to check back to FreeBSD 3.3), I simply #define CK_OFF_T
+to be off_t in ckcdeb.h within #ifdef __FreeBSD__ .. #endif. Another one
+down. This can be done for any platform that is guaranteed to have off_t.
+Turns out FreeBSD 3.3 has 64-bit off_t too. 2 Jan 2005.
+
+OpenBSD, same as FreeBSD. Also, added OS-version-getting thing to makefile
+target for the program herald, as in the other BSDs. Built on OpenBSD 2.5
+from 1998, it has 64-bit off_t too. ckcdeb.h, makefile, 2 Jan 2005.
+
+Dumping the command stack every time there's an error is really too much.
+I added SET COMMAND ERROR-DISPLAY {0,1,2,3} to set the verbosity level of
+error messages. Only level 3 dumps the stack. ckuus[235].c, 2 Jan 2005.
+
+Built on HP-UX 11.11 with _LARGEFILE_SOURCE and _FILE_OFFSET_BITS=64. The
+result works fine as far as I can tell. It sees big files, it can open
+them, seek to positions past the 2^31 boundary. It can send large files.
+It can do large-number arithmetic (^ 2 62). The only problem is that during
+compilation, every single modules warns:
+
+ cc: "/usr/include/sys/socket.h", line 504: warning 562: Redeclaration of
+ "sendfile" with a different storage class specifier: "sendfile" will have
+ internal linkage.
+ cc: "/usr/include/sys/socket.h", line 505: warning 562: Redeclaration of
+ "sendpath" with a different storage class specifier: "sendpath" will have
+ internal linkage.
+
+These warnings should be perfectly harmless since they are not coming from
+C-Kermit code, nor does C-Kermit use either one of those functions. These
+warnings don't come out in HP-UX 11i v2, but on that one we get tons and tons
+of picky compiler warnings (variables set but not used, defined but not
+referenced, etc). A couple, however, turned out to be valid; one case of
+"expression has no effect", and two of "string format incompatible with
+data type" (I missed a couple file-size printfs).
+
+There were also numerous warnings about signedness mismatch or sign
+conversion of constants like IAC (0xff). Does the HP-UX Optimizing Compiler
+have a compiler flag to make all chars unsigned? Yes, +uc, but the man page
+says "Be careful when using this option. Your application may have problems
+interfacing with HP-UX system libraries and other libraries that do not use
+this option". Sigh, better not use it.
+
+After reviewing "HP-UX Large Files White Paper Version 1.4" and HP's
+"Writing Portable Code" documents, I added -D_LARGEFILE_SOURCE
+-D_FILE_OFFSET_BITS=64 to the hpux1000 target, which is the basis for all
+HP-UX 10.00 and later builds. Large files are available in HP-UX 10.20 and
+later. 10.00 and 10.10 were not real releases, and anyway these flags
+should be harmless there unless the large-file implementation was only
+partly done. Built OK on both PA-RISC and IA64, optimized and plain.
+makefile, 4 Jan 2006.
+
+Built on FreeBSD 6.0 on IA64. All OK except I got a warning about the
+argument passed to time() in logwtmp() in ckufio.c. This section had
+already been partially fixed; thus I put the improved version into
+#ifdef CK_64BIT, which is our newly available symbol that should be
+automatically defined for any true 64-bit build. ckufio.c, 4 Jan 2006.
+
+Finally got around to testing Jeff's changes to SSL/TLS RAW mode from
+December 30th against our POP server. It didn't work, couldn't log in.
+Tried backing off the ckctel.c changes first; that allowed login and
+communication, but it did not suppress activation of Telnet protocol
+whenever a 0xff byte arrived. Backed off the rest of the changes and now
+all is OK again. ckctel.c, ckcnet.c, ckuus7.c, 9 Jan 2006.
+
+Built on NetBSD 1.4.1 (1999), found that it did not like the large file
+assumption -- fseeko() and ftello() do not exist; added a clause to the
+netbsd target to check for fseeko and not define _LARGEFILE_SOURCE if not
+found. Oddly enough, off_t is 64 bits anyway, but it doesn't look like the
+APIs are half-done. For example, stat() uses off_t (64 bits) for the file
+length, but fseek() uses long (32 bits) and there is no 64-bit analog.
+Anyway the new netbsd target works on both 1.4.1 and 1.5.2 (no large files)
+and on 2.0.3 (large files). makefile, 9 Jan 2006.
+
+Built on QNX-32 4.25, which has no large file support. Got a few strange
+compiler (WatCom) warnings, but it built and runs OK. Noticed that file
+transfers into QNX over a Telnet connection can't use streaming, but that's
+nothing new to this version; same thing happens with C-Kermit 7.0. 9 Jan 2006.
+
+Built on IRIX 6.5. I didn't bother with large files there because it does
+not support the _LARGEFILE_SOURCE interface; you have to change all the APIs
+at the source level from blah() to blah64(). Seems to work fine as a 32-bit
+app even though its off_t is 64 bits. Tried a pure 64-bit IRIX 6.5 build
+but it dies in ckcnet.c when it hits SOCKOPT_T and GSOCKNAME_T with "The
+identifier 'socklen_t' is undefined".
+
+Looks like I no longer have access to SCO OSR5.
+
+Made a pure 32-bit build on SCO UnixWare 7.1.4, all OK. Found that this
+version also supports LFS, added it to the uw7 target. makefile, 9 Jan 2006.
+
+--- Dev.11 ---
+
+Evidently the HP-UX bundled (non-ANSI non-optimizing) compiler doesn't like
+long integers in switch expressions. Changed three examples of these in the
+S-expression code. ckuus3.c, 10 Jan 2006.
+
+A section of tstats() where GFTIMER isn't defined (e.g. on Motorola
+sv68r3v6) was garbled. Fixed in ckcfn2.c, 10 Jan 2006.
+
+A fix for setting 921600 bps on Linux from Paul Fulghum, Microgate Systems Ltd.
+ttgspd(): ckutio.c, 11 Jan 2006.
+
+Noticed that when I changed the compact substring notation code back on
+August 9th, I broke the ability to use arithmetic expressions within the
+brackets, which explains some rather odd behavior I saw with some of my
+scripts. Looking more deeply into this, I also see that all the parsers I
+have been using up to now for this, as well as for array bounds pairs, have
+been inadequate because they never allowed for nested constructions, such as
+a member of a bounds pair that itself was an array element, possibly with
+another array element as a subscript. I wrote a new routine for this,
+called boundspair(), which is like arraybounds() except it accepts an extra
+argument, an array of characters that can serve as bounds-pair delimiters,
+and it returns the pair separator that was encountered in another new
+argument. For the alternative substring notation for [startpos-endpos] I
+had to change the delimiter from '-' to '_' because '-' can be used in
+arithmetic but '_' is not a recognized operator. This is so I can parse,
+e.g. [a:b] or [a_b] in the same context, and then find out which form was
+used, e.g. \s(line[9:12]) or \s(line[9_12]); the first string is 4 bytes
+long, the second is 12. Everything seems to be OK now. \s(line[10]) gives
+everything starting at 10, but \s(line[10:0]) gives the null string. Bad
+syntax in the bounds pairs results in a null string; missing pieces of the
+bounds pair result in defaults that should be compatible with previous
+behavior. ckuus[45].c, ckuusr.h, 13 Jan 2005.
+
+Changed arraybounds() to call boundspair(). This was a rather drastic
+change, not strictly necessary, but I think I got all the kinks out.
+ckuus5.c, 13 Jan 2005.
+
+Changes from PeterE to the makefile for HP-UX 6 and 7, to accommodate bigger
+symbol tables, etc. 19 Jan 2005.
+
+Determined that SCO OSR5.0.6 (and earlier) do(es) not support large files.
+Don't know about 5.0.7. 30 Jan 2005.
+
+Created a new build target for SCO OSR6.0.0. Gets the exact 6.x.x version
+dynamically. Supports large files and big-number arithmetic via CK_OFF_T.
+The sockopt() family of functions changed the data types of some of their
+arguments since OSR5. It was already possible to define SOCKOPT_T and
+GSOCKNAME_T from the command line but I had to add code to also allow this
+for GPEERNAME_T too. ckcnet.c, makefile, 30 Jan 2005.
+
+Apparently, ever since C-Kermit 7.0 was released, it has never been possible
+to use a variable for the as-name in a RECEIVE command in Kermit 95. This
+is because evaluation of the as-name field was deferred until after we could
+check whether it might be a directory name (which, in Windows, could start
+with a backslash). This little bit of magic was not a good idea, magic
+hardly ever is. I changed the code to evaluate both as-name fields in the
+normal way. If they want to receive to a directory called "\%1", they'll
+just have to spell it differently. The workaround is to turn the whole
+command into a macro and evaluate it before executing it, e.g.:
+
+ assign xx receive /as-name:\%1
+ do xx
+
+ckuus6.c, 1 Feb 2006.
+
+Built OK on FreeBSD 6.1 on AMD64. Adjusted some copyrights and date stamps.
+ckcmai.c, makefile, 8 Feb 2006.
+
+--- Dev.12 ---
+
+Fixed a signed/unsigned char warning in the new boundspair() calling code
+in the compact substring notation handler. ckuus4.c, 9 Feb 2006.
+
+Removed a spurious extra linux+openssl label from the makefile, added
+solaris10g_64 synonym. 9 Feb 2006.
+
+Satisfied myself that LFS is OK on Solaris 10 i386, and I'm going to assume
+it's also OK on Solaris 9. Made LFS standard for all Solaris 9 and 10
+builds (including the secure ones) except the explicitly 64-bit ones, and
+made the provisional solarisXXlfs targets into synonyms. makefile, 9 Feb 2006.
+
+--- Dev.13 ---
+
+Further attempts at SSL/TLS message suppression when QUIET is ON.
+ck_ssl.c, 16 Feb 2006.
+
+From J.Scott Kasten: (quote...) I just uploaded a patch to /kermit/incoming.
+The file name is "jsk-patch-for-cku211.diff". I have also included the
+patch as ASCII text in this email below. This patch may be applied to the
+cku211.tar.gz source code via:
+ cd cku211, patch -p1 <../jsk-patch-for-cku211.diff
+The patch adds 4 new build targets:
+ netbsdwoc - a stripped no curses target for iksd used.
+ netbsdse - security enhanced target with srp, ssl, and zlib.
+ irix65gcc - build on SGI Irix 6.5 platform using gcc.
+ irix65se - security enhanced target with srp, ssl, and zlib.
+The patch fixes one build target:
+ irix64gcc - The "-s" option is not supported by gcc under Irix.
+I thank all of you in the Kermit Project for such a fine utility. I
+recently had to get a 16 MB file overseas across a spotty communications
+link to repair a computer remotely. Kermit was the only thing that could do
+the job, so I wanted to contribute these patches back to the mainstream to
+say thanks. This digitally signed email is a binding contract that
+officially assigns the rights to the source code patch (shown below) that I
+developed to the Kermit Project at Columbia University. (...end quote)
+ck_ssl.c, makefile, 23 Feb 2006.
+
+Changed the new NetBSD target names to be consistent with the conventions
+used in most other targets:
+
+ netbsdwoc -> netbsdnc
+ netbsdse -> netbsd+ssl+srp+zlib
+ irix65se -> irix65+ssl+srp+zlib
+
+and removed old, now superfluous, NetBSD targets (old-netbsd, netbst15,
+netbst16), leaving synonym labels in their place. Also updated (crudely)
+the Linux target variations (curses instead of nocurses, no curses at all)
+to be (appropriately modified) copies of the current linux target. It would
+be nicer to combine them, but this gets the job done. makefile, 23 Feb 2006.
+
+--- Dev.14 ---
+
+Fixed the HELP command when used with tokens like @, ^, #, and ;. The first
+two had been omitted from the table. The second two required a new path
+into the guts of the parser, since comments are normally stripped at a very
+low level. ckuus[r2].c, ckucmd.c, 24 Feb 2006.
+
+Built on AIX 5.1 ("make aix51") without incident. Then I tried:
+
+ make aix51 "KFLAGS=-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+
+This had no effect. I found the relevant document ath the IBM website. It
+says to use -D_LARGE_FILES instead. I added this to the AIX 4.2 target
+since (a) IBM says large files are supported by AIX 4.2 and later, and (b)
+all Kermit AIX targets past 4.2 use the 4.2 one. Plus a clause to make
+sure CK_OFF_T is defined appropriately. ckcdeb.h, makefile, 6 Mar 2006.
+
+Added a 32-bit aix51+openssl target. Builds OK, works fine (tested against
+our SSL POP server). Tried I tried adding -D_LARGE_FILES. It seems to work
+fine, so we'll keep it. Cleaned up the other aix5blah entries a bit also.
+makefile, 6 Mar 2006.
+
+Fixes from J. Scott Kasten to the IRIX 6.4 and 6.5 makefile targets. They
+were badly wrong. makefile, 6 Mar 2006.
+
+The reason Kermit was looping on directories in IRIX was a classic
+"double-ended break". The makefile targets failed to define DIRENT so
+Kermit was open/read on directories rather than opendir()/readdir(). But
+then it was also failing to account for the fact that read() would return -1
+on error. The makefile fix adds -DDIRENT, and the read() case in traverse()
+now properly terminates its loop on error. ckufio.c, 6 Mar 2006.
+
+--- Dev.14 ---
+
+In response to a complaint that C-Kermit would not build on HP-UX 11 with
+OpenSSL, I tried it myself on both 11.11/PA-RISC and 11i v2/Itanium. It built
+OK on both but I had to add a new target (hpux1000o+openssl-nozlib) for no
+Zlib since these boxes did not have it installed. makefile, 9 Mar 2006.
+
+Added OpenSSL version number display to SHOW FEATURES. ckuus5.c, 9 Mar 2006.
+
+Gavin Graham noticed that FTP [M]GET /DELETE /MOVE-TO: was rejected with
+"?Sorry, /DELETE conflicts with /MOVE or /RENAME". This check belongs in the
+PUT code but not in the GET code. Commented it out and tested the result.
+The combination is now accepted but then Kermit refuses the incoming file as
+if it had been given a /SMALLER-THAN: or /LARGER-THAN: switch, which it didn't
+happen. Turns out there was one more place where I wasn't initializing the
+new "wide int" member of the switch-parsing pv[] struct. Once this was fixed,
+the /MOVE-TO part still didn't work. Turned out the /DELETE case was part of
+a long if-else-if-else- chain, which effectively made /DELETE and /MOVE-TO: or
+/RENAME-TO: mutually exclusive. Fixed this, now it works fine. ckcftp.c,
+13 Mar 2006.
+
+Got access to AIX 5.3, built there, all OK, including large files. 13 Mar 2006.
+
+--- Dev.16 ---
+
+Patches from Mark Sapiro to suppress getsockopt() and getsockname() warnings
+in Mac OS X. ckcnet.[ch], 18 Mar 2006.
+
+In response to a complaint from Clarence Dold, tried "make redhat9" (which
+is the rather dated target that tried to include all forms of security) on
+RH Linux AS4.3, it failed miserably. I made a new makefile target, removing
+Kerberos IV and got a lot farther. But then in ckcftp.c, the following
+struct definition:
+
+ struct {
+ CONST gss_OID_desc * CONST * mech_type;
+ char *service_name;
+ } gss_trials[] = {
+ { &ck_gss_mech_krb5, "ftp" },
+ { &ck_gss_mech_krb5, "host" },
+ };
+
+refers to a variable, ck_gss_mech_krb5, that is not defined anywhere. Up
+above, however, is a static definition for gss_mech_krb5, so I changed the
+struct definition to match. Next, in ckuath.c, the compiler could not find
+the com_err.h file. Turns out in Linux this is in a subdirectory, et, so we
+have to add a -I clause to the makefile target for this. Made a target for
+Linux+SSL only. Made a target for Linux+Krb5 only; this required moving an
+#ifdef in ckuus7.c to prevent an unguarded reference to SSLEAY_VERSION.
+New targets: linux+krb5+ssl, linux+krb5, linux+krb5. ckcftp.c, ckuus7.c,
+makefile, 27 Mar 2006.
+
+New targets of HP-UX 10/11 with OpenSSL from PeterE. makefile, 27 Mar 2006.
+
+Added large file/integer support to SHOW FEATURES. ckuus5.c, 27 Mar 2006.
+
+Built OK on Solaris 9 and 10 with gcc (someone was complaining that this
+didn't work, but that was 8.0.211).
+
+Started build on a Sun 3/80 mc68030 with NetBSD 2.0 and gcc 3.3.3. But it
+died with an assembler error in ckcfn2.c (compiler bug). 27 Mar 2006.
+
+--- Dev.17 ---
+
+NebBSD 2.0 build completed by turning off optimization on ckcfn2.c
+("KFLAGS=-O0"). Result supports 64-bit ints and, presumably, large files.
+uname -p = "m68k", -m = "sun3". 29 Mar 2006.
+
+Corrected an omission in applying PeterE's updates to the HP-UX targets.
+makefile, 28 Mar 2006.
+
+solaris2xg+krb5+krb4+openssl+shadow:
+
+Tried resurrecting the solaris2xg+krb5+krb4+openssl+shadow target. It asks
+to link with libdes but there is no libdes. Removed -ldes from the target,
+now at least it builds and runs wart. The compilation blows up in ckcftp.c
+for missing header files:
+
+ ckcftp.c:462: kerberosIV/krb.h: No such file or directory
+ ckcftp.c:500: gssapi/gssapi_generic.h: No such file or directory
+ ckcftp.c:501: gssapi/gssapi_krb5.h: No such file or directory
+
+Got a bit farther by adding appropriate -I's and -L's to KFLAGS but it still
+dies compiling (or linking?) ckcftp.c, but it doesn't say exactly why. OK,
+deferred.
+
+Added SET SEXPRESSION TRUNCATE-ALL-RESULTS { ON, OFF }. This can be used
+for force integer arithmetic in any kind of calculation that requires it,
+such as date calculations. This is a global setting, not on any kind of
+stack. Also, updated SHOW SEXP and added HELP SET SEXP which wasn't there
+before. ckuus[23].c, 30 Mar 2006.
+
+To make the RENAME command a bit more useful, need to add some switches.
+But it shares a switch table, qvswtab[], with some other commands. Broke
+this off into its own switch table. ckuus6.c, 17 Apr 2006.
+
+Added RENAME switch values that can be used in the same table with the DELETE
+switch values, which are shared by many commands. ckuusr.h, 17 Apr 2006.
+
+Discovered that the RENAME command could be entered without any arguments
+and it would still succeed. Fixed in dorenam(): ckuus6.c, 17 Apr 2006.
+
+Added parsing for RENAME /UPPER:option (to uppercase the file name(s)),
+/LOWER:option (to lowercase), and /REPLACE:{{s1}{s2}} (to do string
+replacement on the filename(s)), but not the semantics. When any of these
+switches is given, the target ("to") name is not parsed; they act on the
+source name. The /LOWER: switch takes keyword args to specify whether it
+should act only only files that have all UPPER case latters, or on ALL files
+(i.e., including files with mixed-case names); similarly for the /UPPER:
+switch. There is some creative parsing allowing these to be given with or
+without a colon and keyword argument, which works fine except if you include
+the colon but no argument, execute the command (which works fine), and then
+recall the command. I haven't yet decided about the interaction among these
+switches. Clearly if /UPPER is given after /LOWER, it overrides. But if
+/UPPER (or /LOWER) is given with /REPLACE, what should happen? ckuus6.c,
+17 Apr 2006.
+
+Filled in actions for RENAME /UPPER: and /LOWER: for the single file case,
+and tested all combinations of switch values and filename configurations.
+Once that was OK, moved the code out into a separate routine, renameone(),
+and then called it from both the single-file case and the multifile case.
+ckuus6.c, 19 Apr 2006.
+
+Added RENAME /SIMULATE. Filled in the code for string replacement, needs
+testing. ckuus6.c, 20 Apr 2006.
+
+Changed /REPLACE options to allow a negative number to specify an occurrence
+from the right, so -1 means the last occurrence, -2 means the next-to-last,
+etc. ckuus6.c, 24 Apr 2006.
+
+Added RENAME /COLLISION:{OVERWRITE,PROCEED,FAIL}. This is implemented but
+not tested. ckuus6.c, 24 Apr 2006.
+
+Worked on RENAME /COLLISION:FAIL. I decided it was less than useful to ...
+
+Added SET RENAME { COLLISION, LIST } to let user change default collision
+and listing actions. ckuusr.[ch], ckuus[36].c, 25 Apr 2006.
+
+Experimented with parsing for /CONVERT:cset1:cset2. The problem here is
+that there is no straightforward way for a switch to have multiple
+arguments. Or is there...? If I parse cset1 with cmswi() rather than
+cmkey(), it almost works; the only problem is that the character-set
+keywords don't have CM_ARG set, so they don't know to stop on, and ignore, a
+colon. If I make a copy of the table and set CM_ARG in the flags field for
+each keyword, it works fine: if I Tab in the first name, it fills itself
+out, supplies a colon, and waits for the second name. So in the code, the
+first time that RENAME /CONVERT is invoked, I put code to copy fcstab[] and
+set CM_ARG in each flags field. Works fine, and now we know how to make a
+switch that takes multiple arguments. ckuus6.c, 24 Apr 2006.
+
+I thought I had a function to convert the character set of a string but I
+don't, so actually implementing /CONVERT: will be difficult.
+
+Actually the parsing wasn't that easy either. It works OK interactively,
+but not in a TAKE file. To make a long story short, I had to change
+gtword() and cmkey2() to not require "/" at the beginning of a switch, and
+then to parse arguments-that-are-followed-by-other-arguments as if they were
+switches, so that they can end with colon rather than space. This might
+seem dangerous, but switches always have "/" at the beginning, so the check
+is superfluous. ckucmd.c, 26 Apr 2006.
+
+Back to /CONVERT... Once I was able to get the code to call cvtstring() I
+was able to debug it (at first it was skipping every second character). And
+now we have a general-purpose string-translating function we can call from
+anywhere. Requires that C-Kermit be built with Unicode support.
+ckuus6.c, 26 Apr 2006.
+
+Added SHOW RENAME. ckuusr.h, ckuus[r5].c, 26 Apr 2006.
+
+Conditionalized some Unix/Windows assumptions in renameone() so the code
+could work in VMS. ckuus6.c, 2 May 2006.
+
+Added RENAME /FIXSPACES to change all spaces in the filename(s) to
+underscore or any other character or string that is given. This is just a
+special case of RENAME /REPLACE:{{ }{x}} with easier syntax.
+ckuusr.h, ckuus6.c, 2 May 2006.
+
+Added an "all-but" control to the /REPLACE options:
+/REPLACE:{{.}{_}{~1}} means replace all but the first (this one works);
+/REPLACE:{{.}{_}{~-1}} means replace all but the last (this one not yet).
+ckuus6.c, 2 May 2006.
+
+Filled in the second one ("all but" the given occurrence). The algorithm is
+simply to reverse the three strings and then use the same code as we use in
+the left-right-case, and then unreverse the result. At first I used
+yystring() for this but yikes, what a bad design! So I made a better
+string-reversal routine, gnirts(), for this (luckily yystring() is only used
+in one place, for which its design is appropriate). ckuus6.c, 3-4 May 2006.
+
+Added code to handle the case where the file being renamed includes a path
+specification. In this case we separate the path, apply the renaming
+functions to the filename only, and then at the end rejoin the original
+filename with the path, and join the new name with same path or, if a
+destination directory was given, with that. ckuus6.c, 4 May 2006.
+
+Added HELP SET RENAME and updated HELP RENAME. ckuus2.c, 4 May 2006.
+
+"Tom Violin" (Tom Hansen) noticed that the first time you FOPEN a file,
+Kermit's memory consumption goes way up. In fact there's a warning to that
+effect in the code, where, upon first open, a potentially big array of
+potentially big structs is allocated. I rewrote the code to allocate each
+array member (struct ckz_file) as needed, i.e. when a file is opened, and to
+free it when the file is closed (or the open fails). This was actually
+quite a lot of work, which is why I didn't do it the first time around:
+every single "." had to be changed to "->". Every check for a valid
+channel first had to check if the channel's struct was allocated and every
+other reference to z_file[i]->anything had to be prechecked that z_file[i]
+was not a NULL pointer. Also I made some improvements to FILE STATUS, and I
+fixed FILE CLOSE to default the channel number if only one channel was open,
+as I did for FILE STATUS a while back. ckuus7.c, Cinco de mayo 2006.
+
+Ran my old BUILDS script that builds C-Kermit with about 100 different
+combinations of feature-selection switches. Fixed a few small glitches so
+now they all build OK (except can't do NOANSI builds any more on recent
+Linuxes because of varargs()). ckuus3.c, ckuus5.c, ckuus6.c, ckuus7.c,
+ckucmd.c, ckcfns.c, 6 May 2006.
+
+Fixed RENAME /LOWER and /UPPER, when given with no colon or argument, to
+default to ALL. ckuus6.c, 13 May 2006.
+
+Built on VMS 7.2-1, tested new RENAME command there; seems to be OK.
+13 May 2006.
+
+--- Dev.18 ---
+
+I wanted to test large files against RESEND but I don't have access to any
+system that can run C-Kermit and that also has enough space for a large
+file. I created a "fake" large file on Linux (3G hole plus 1 byte), and
+sent it over a localhost connection, and interrupted it repeatedly and then
+initiated a RESEND at the sender. In each case, it picked up where it left
+off. But before the 2G boundary was crossed the disk filled up.
+Inconclusive. 14 May 2006.
+
+PeterE got a warning in the new FILE OPEN code when building in HP-UX 9.
+I added a cast, built on HP-UX 11, no more complaint. However there
+are warnings about internal vs external bindings of sendpath and sendfile
+in every module. Too bad, these are not Kermit tokens, it's a conflict in
+HP's header files. Marc Sapiro doesn't see them; probably it's something
+on the HP testdrive site. ckuus7.c, 17 May 2006.
+
+Fixed the tru64-51b+openssl target -- the terminating doublequote of KFLAGS
+was missing -- and also the osf target, which failed to import the LIBS
+definition from whatever other target invoked it. Now the SSL build goes OK
+on Tru64 5.1B. Replaced x.tar.z in the download areas without declaring a
+new Dev number. The new one has a makefile with today's date. Software
+engineering at its best! makefile, 18 May 2006.
+
+Scott Kasten noted that the estimated-time-remaining calculation would go
+bonkers on LFS systems when RESENDing a large file. It looks like the
+shocps() and shoetl() functions escaped the CK_OFF_T conversion. I made
+what seemed to be the right adjustments, and then was lucky enough to find a
+computer that had enough free disk space for me to send a large file,
+interrupt it several times, resend it, all seems to be OK. 28 May 2006.
+Later Scott verified these changes independently for Linux, but the problems
+in IRIX remain.
+
+Patches from Scott Kasten for large files on IRIX 6.5: ckcdeb.h, makefile,
+12 Jun 2006.
+
+--- Dev.19 ---
+
+Added a new function for dealing with JPGs and GIFs:
+
+\fpicture(filename,&a)
+ returns 0 if file not recognized or can't be opened;
+ returns 1 if landscape, 2 if portrait or square.
+ If array given, element 1 is width, element 2 is height.
+
+ckuusr.h, ckuus4.c, 19 Jun 2006.
+
+Scott Kasten reports that the FTP client can transfer large files OK, at
+least in Linux, but has trouble with recovery:
+
+ . Kermit takes a very long time to start the transfer, sometimes over
+ 30 minutes. Suspect the ftp server is counting the bytes in a long file?
+ Or maybe it's a text-mode transfer and it's counting the lines? Probably
+ in response to Kermit's SIZE command.
+
+ . The size shown in the FT display is wrong by a random amount. And of
+ course so are the progress bar, percent done, and time remaining.
+
+ . The file, however, is transferred correctly. REGET works correctly too.
+
+I tried setting up a test scenario locally but our Solaris FTP server does
+not support large files:
+
+ FTP SENT [SIZE BIGFILE]
+ FTP RCVD [550 BIGFILE: not a plain file.]
+ FTP SENT [PASV]
+ FTP RCVD [227 Entering Passive Mode (128,59,48,24,246,37)]
+ FTP SENT [RETR BIGFILE]
+ FTP RCVD [550 BIGFILE: Value too large for defined data type.]
+
+Created the same 3GB on a Tru64 Unix system that allows FTP access. Made
+the connection from C-Kermit on Solaris (32-bit with LFS):
+
+ 16:46:12.908 FTP SENT [SIZE BIGFILE]
+ 16:46:12.947 FTP RCVD [213 3000000001]
+
+Note that it takes less than half a second to get the reply. Now I start
+the download and then interrupt it at about 2%:
+
+ 16:46:12.979 FTP SENT [TYPE I]
+ 16:46:13.174 FTP RCVD [200 Type set to I.]
+ 16:46:13.226 FTP SENT [PASV]
+ 16:46:13.262 FTP RCVD [227 Entering Passive Mode (15,170,178,171,11,37)]
+ 16:46:13.299 FTP SENT [RETR BIGFILE]
+ 16:46:13.337 FTP RCVD [150 Opening BINARY mode data connection for BIGFILE..]
+ 16:47:24.895 FTP RCVD [426 Transfer aborted. Data connection closed.]
+ 16:47:24.934 FTP RCVD [226 Abort successful]
+ 16:47:24.991 FTP SENT [MDTM BIGFILE]
+ 16:47:25.028 FTP RCVD [213 20060706204458]
+
+Now I do a REGET:
+
+ 16:51:55.321 FTP SENT [PASV]
+ 16:51:55.357 FTP RCVD [227 Entering Passive Mode (15,170,178,171,11,43)]
+ 16:51:55.394 FTP SENT [REST 122736640]
+ 16:51:55.430 FTP RCVD [350 Restarting at 122736640. Send STORE or RETRIEVE..]
+ 16:51:55.431 FTP SENT [RETR BIGFILE]
+ 16:51:55.469 FTP RCVD [150 Opening BINARY mode data connection for BIGFILE..]
+
+This worked perfectly, as far as I can tell; the FT display picked up in the
+right place; the thermometer, percent done, and estimated time remaining
+were the same as when we left off last time. I did the same thing several
+more times, everything was OK. It would have taken a really long time to
+let this run to completion, but I think this demonstrates that Scott's
+symptoms are server-dependent. No changes. 6 July 2006.
+
+Checked current code on VMS 8.2-1 on IA64 / UCX 5.5, builds fine.
+No changes. Updated listing at HP. 6 July 2006.
+
+Checked FTP GET of large file in ASCII mode against Tru64 FTP server. It
+was fine, and there was no delay in the server's response to our SIZE command
+(as there would be if it were scanning the entire file to count how many
+bytes would be required to send it in text mode). 7 Jul 2006.
+
+Tested FTP PUT big file against Tru64, OK. Ditto FTP RESEND big file:
+
+ C-Kermit>resend BIGFILE
+ PUT BIGFILE (binary) (3000000001 bytes)---> PASV
+ 227 Entering Passive Mode (15,170,178,171,13,186)
+ ---> SIZE BIGFILE
+ 213 343211280
+ ---> MDTM BIGFILE
+ 213 20060707141243
+ ---> APPE BIGFILE
+ 150 Opening BINARY mode data connection for BIGFILE (128.59.59.56,45470).
+
+Made REPUT a synonym for RESEND. ckuusr.c, 7 Jul 2006.
+
+Added FTP REPUT and FTP RESEND since previously there was no FTP-prefixed
+command for recovering uploads, only the regular RESEND command, which might
+not have been obvious to people. ckcftp.c, 7 Jul 2006.
+
+Added help text for FTP RESEND and REPUT and amended RESEND help text.
+ckcftp.c, ckuus2.c, 7 Jul 2006.
+
+Changed name of \fpicture() to \fpictureinfo() and added help text. By the
+way, ImageMagick can do this too: identify -format "%w %h" dscf0520.jpg.
+The advantage of having it in Kermit is that not everybody has ImageMagick.
+ckuus[24].c, 7 Jul 2006.
+
+Changed the numeric comparisons = < > <= >= != to allow long integers by
+changing the data type to CK_OFF_T, etc. ckuus6.c, 7 Jul 2006.
+
+Noticed that \fkeywordvalue(foo=this is a string) only kept the first word.
+Fixed it to keep the whole definition. Also added \fkwvalue() as a briefer
+synonym. ckuus4.c, 7 Jul 2006
+
+Sometimes we want to check if a file's status before we've FOPEN'd it, in
+which case the channel variable is likely to be empty and \f_status(\%c)
+would get an error. Making the obvious change didn't fix this, however. It
+turns out that the function evaluator failed to adjust argn (argument count)
+when trailing arguments were empty, and argn was being used in this case,
+and probably others, to test whether an argument existed. I added code to
+adjust argn to reflect the number of arguments up to and including the
+rightmost non-empty one. ckuus4.c, 7 Jul 2006.
+
+Fixed \fstripb() to not dump core if second argument is missing.
+ckuus4.c, 7 Jul 2006.
+
+Discovered that it was not obvious what pattern to use to match strings
+enclosed in square brackets. "if match [abc] \[*\]" didn't work. Neither
+did various other tricks like NCRs for the brackets. However, "if match
+[abc] \\[*\\]" does work. Trying to fix this would no doubt break 100 other
+things, so let's call it a feature. 7 Jul 2006.
+
+Added \fgetpidinfo(n) to return info about a process ID; for now it simply
+returns 1 if the process is alive and 0 if not (or -1 if the argument is
+bad or missing or on any kind of error). ckuusr.h, ckuus[24].c, 7 Jul 2006.
+
+The "where-did-my-file-go" message seemed to be ending with a LF rather
+than CRLF, probably because the terminal modes had not yet been restored,
+leaving the next prompt hanging below it, rather than on the left margin,
+if C-Kermit exited immediately after the transfer. Fixed by changing
+all \n's to \r\n's in wheremsg(): ckcpro.w, 8 Jul 2006.
+
+Added \v(lastkwval) so we can retrieve programmatically the keyword most
+recently processed by \fkeywordval(). ckuusr.h, ckuus4.c, 9 Jul 2006.
+
+--- Dev.20 ---
+
+Added #ifdef SV68, #include <unistd.h>, #endif because Unix System V/68 on
+Motorola choked on the SEEK_CUR reference without it. ckuus4.c, 10 Jul 2006.
+
+Make \fkeywordval(xxx) undefine xxx (i.e. when a keyword is given with no
+value). This way command-line keywords will always override preexisting
+default definitions, whether they have a value or not, which makes it easier
+to parse command lines like "foo=bar blah xx=yy". ckuus[24].c, 12 Jul 2006.
+
+On 29 Nov 2005 I changed IF KERBANG to solve a problem (see entry for that
+date), but introduced a new one; namely that you can't have (e.g.) a FATAL
+macro that uses IF KERBANG to decide whether to EXIT all the way or STOP
+back to the prompt. Changed it again, this time to require not that the
+command level be 1, but that the command *file* level be 0 (i.e. that we are
+in the top-level command file, irrespective of the command or macro level,
+but not in a subfile). ckuus6.c, 12 Jul 2006.
+
+It is unhelpful when Kermit gets a syntax error in the middle of a big
+compound statement block (e.g. FOR or WHILE loop) and dumps out the whole
+thing in an error message. I changed the two places where this can happen
+to call a new routine that, instead of dumping out the entire cmdbuf,
+checks its length first and if it's more than a line long, truncates it
+and adds an ellipsis. ckuus6.c, 12 Jul 2006.
+
+The new RENAME command didn't give very good error messages, e.g. if the
+filespec didn't match any files. Fixed in dorenam(): ckuus6.c, 12 Jul 2006.
+
+Fixed DIR /TOP to work if the /TOP:n argument was omitted, defaulting
+to 10. domydir(): ckuus6.c, 12 Jul 2006.
+
+Added DIR /COUNT:v to count the number of files that match the given
+criteria and store result in the variable v. ckuusr.h, ckuus[r26].c,
+24 Aug 2006.
+
+Added HDIRECTORY as an invisible synonym for DIR /SORT:SIZE /REVERSE.
+Can be used with other switches, of course, so (e.g.) HD /TOP shows the
+ten biggest files. ckuusr.h, ckuus[r26].c, 24 Aug 2006.
+
+DIR /FOLLOWLINKS and /NOFOLLOWLINKS always did the same thing; the switch
+was ignored, a symlink is always followed. Fixed in ckuus6.c, 24 Aug 2006.
+
+Added DIR /NOLINKS, which means don't show or count symlinks at all.
+ckuusr.h, ckuus[r26].c, 24 Aug 2006.
+
+Build on Solaris 9 and NetBSD 3.0, 24 Aug 2006.
+
+Added a missing definition for LOCK_DIR in the Linux HAVE_BAUDBOY case,
+suggested by Gerry Belanger. ckutio.c, 6 Oct 2006.
+
+Suggested by Jim Crapuchettes: \v(dialmessage) is the text string
+corresponding to \v(dialstatus). ckuusr.h, ckuus4.c, 6 Oct 2006.
+
+Soewono Effendi sent code for exit sequence to leave DTR on; this amounted
+to unsetting HPUCL in c_cflag. I did it a simpler way, hopefully portable
+to all Unixes, but who knows at this late date. The code is inside
+#ifndef CK_NOHUPCL..#endif in case it causes trouble. It is executed if
+SET EXIT HANGUP is OFF and a serial port was open at the time Kermit exits
+(or closes it explicitly). ttclos(): ckutio.c, 6 Oct 2006.
+
+Built on Solaris9/Sparc; FreeBSD 6.2/AMD64; NetBSD 3.0/i386; HP-UX 11i v2;
+SCO OSR6.00.
+
+--- Dev.21 ---
+
+Added netbsd+openssl target to makefile. Built OK (NetBSD 3.0, OpenSSL
+0.9.7d) except with some warnings in ck_crp.c. Connects and logs in OK to a
+secure site. 10 Oct 2006.
+
+Added a debug statement to ftp_hookup() to record the TCP port that was used.
+ckcftp.c, 11 Oct 2006.
+
+Built with OpenSSL 0.9.7l on Solaris 9. Built with OpenSSL 0.9.8d on
+Solaris 9; connects and logs in to a secure site. 11 Oct 2006.
+
+The new RENAME command didn't work if both the source and destination names
+included directory segments, e.g. "rename /tmp/foo ~/bar" (see notes of
+4 May 2006). This was fixed in renameone() by a special case in which
+the second argument is given but it is a filename, not a directory name.
+ckuus6.c, 11 Oct 2006.
+
+Fixed unguarded reference to dialmsg[] for \fdialmessage(), noticed by
+Gerry Belanger. ckuus4.c, 12 Oct 2006.
+
+Added a TOUCH command that does what UNIX touch does: creates the file if it
+does not exist, updates the timestamp if it does. If a wildcard is given,
+it operates only on existing files. It shares the DIRECTORY command parser,
+so all the same file selection switches can be given. ckuusr.[ch],
+ckuus[26].c, 12 Oct 2006.
+
+PeterE noticed that if you FOPEN a file, do some seeks or reads, then FCLOSE
+it, then FOPEN it again (or open a different one), some of the old
+information is still there (e.g. current line number). This is an artifact
+of the changes of May 4th. Now the file closing and opening routines are a
+bit more careful about scrubbing and initializing the file info struct.
+ckuus7.c, 12 Oct 2006.
+
+--- Dev.22 ---
+
+Built OK on Red Hat Linux AS4 with both "make linux" and "make linuxnc".
+15 Oct 2006.
+
+DIRECTORY /BRIEF ignored file selection switches and always listed all
+files. This was because of how I cleverly called filhelp() (the routine
+that lists matching files when ? is typed in a filename field) and, of
+course, filhelp() doesn't know anything about the DIRECTORY command's file
+selections. Changed filhelp() to accept all the args needed for passing
+along to fileselect(), renamed it to xfilhelp(), and made a filhelp() stub
+that chains to xfilhelp() with null selections. ckcker.h, ckucmd.[ch],
+ckuus6.c, 29 Nov 2006.
+
+SHOW CONNECTION for an SSH connection said the connection type was "NET"
+rather than "SSH". Fixed in dolognet(): ckuus3.c, 29 Nov 2006.
+
+SHOW CONNECTION didn't show the TCP port number. This command works by
+parsing the current connection log entry string, which doesn't have a field
+for this, but which sometimes shows the port number as part of the hostname
+(but more often not). Added code to dolognet() to log the TCP port number,
+if known. This involved adding a gettcpport() function to ckcnet.c.
+ckcnet.[ch], ckuus3.c, 29 Nov 2006.
+
+This was impossible: def \%1 upper, echo \f\%1(abc) -- i.e. to "compose" a
+function name. Fixed in zzstring(). But note that it's still not possible
+to do this: def \%1 \fupper, echo \%1(abc) -- because at the point where
+"\fupper" is encountered, which is automatically fed to fneval(), the
+argument list hasn't been read yet. ckuus4.c, 29 Nov 2006.
+
+The meaningless Lisp command (=) would cause Kermit to hang. Due to some
+idiosyncracy in the parser, it would see this as ((=) and would go into
+"wait for the closing paren" mode. There was already a hack in the code to
+compensate for this, but it didn't work. I fixed the hack but I don't
+understand the real problem. Anyway, comparing Kermit with real (Franz)
+Lisp I discovered that comparison operators do not require two arguments, as
+Kermit has been doing, although they do require at least one. I changed
+Kermit to not require two, so now all the comparison predicates behave
+exactly like Franz Lisp, including getting an error if there are no args).
+ckuus[r3].c, 29 Nov 2006.
+
+From to-do list: Make a way to inhibit pattern matching in SWITCH labels.
+It's already there; just quote the wildcard characters; the only trick is
+that for some reason (such as that SWITCH is really an internally defined
+macro), a double quote is needed:
+
+ switch \%1 {
+ :a\\*z, echo literally "a*z", break
+ :abcxyz, echo literally "abcxyz", break
+ :a*z, echo a...z, break
+ :default, echo NO MATCH
+ }
+
+In first case, the asterisk is taken literally; in the third it's a
+metacharacter and the label matches any string that starts with 'a' and
+ends with 'z'.
+
+Array initialization would quit early if any initializers were undefined,
+e.g. "decl \&a[] = \%a \%b \%c" would stop at the first element if \%b
+was not defined, even though \%c might be defined. Fixed in dodcl():
+ckuusr.c, 30 Nov 2006.
+
+DIR /ARRAY:a filespec, when the filespec does not match any files,
+terminates with the array undeclared. It would be better to return a
+declared but empty array (\&a[0] = 0). The code is already there to do
+that, but isn't working. And yet "declare \&a[0]" does indeed create a
+0-element array ("show array" shows a dimension of 0). Turns out there were
+two problems; one was the careless recycling of a local variable ("array"),
+resulting in failure to create \&a[] (but not any other array). Fixed in
+domydir(): ckuus6.c, 30 Nov 2006.
+
+The other problem was that dclarray(), when called with an array name and a
+dimension of zero, does two different things depending on whether the array
+already existed. There is still a fair amount of confusion about whether a
+dimension of 0 indicates an array with 1 element (as it should) or a
+nonexistent array. We call dclarray() with a size of 0 to undeclare an
+array but we also need to able able to declare an array with only element 0.
+I changed dclarray() to treat a negative dimension as a command to destroy
+the array, and 0 or positive as a command to create the array with the given
+dimension. ckuus[r56].c, 30 Nov 2006.
+
+Next problem: when chkarray() returns 0, this should not be interpreted to
+mean the array does not exist. Looks like the only place this happened was
+in \fcontents(); fixed in ckuus4.c, 30 Nov 2006.
+
+If we include file selectors with DIR /ARRAY:&a and some of the files that
+match the given filespec but don't fit the selectors, the array's dimension
+is bigger than its number of elements. Added code at the end of domydir()
+to resize the array so \fdim() returns the number of filenames in the array,
+and also made sure that element 0 contains that number too. ckuus6.c,
+30 Nov 2006.
+
+This would be a nice elegant way to loop over a bunch of files, if it worked:
+
+ for \%i 1 \ffiles(*) 1 { rename \fnextfile() xxx_\flpad(\%i,3,0) }
+
+But in this loop, Kermit skips every other file (beginning with the first)
+and then runs out of files halfway through the loop. Why? Because in
+commands like RENAME and DELETE, the filename parser is in a chained FDB
+with the switch parser. First the switch parser, cmswi(), gets its hands on
+\fnextfile(), passing it through the evaluator and thus getting the first
+filename, which it then sees is not a switch, so now the field is parsed by
+the next parser in the chain, cmifi(), which causes \fnextfile() to be
+executed again. In fact, the FOR loop has nothing to do with; the same
+thing happens like this:
+
+ void \ffiles(*)
+ delete \fnextfile()
+
+This deletes not the first file, but the second one. Obviously users can be
+told not to refer to \fnextfile() in chained-fdb fields:
+
+ for \%i 1 \ffiles(*) 1 { .f := \fnextfile(), delete \m(f) }
+
+but this is hardly intuitive. I had some clever ideas of how to make
+\fnextfile() work as expected in this context but it's way too much magic.
+Better to simply document that \fnextfile() is "deprecated" and the array
+format should be used:
+
+ for \%i 1 \ffiles(*,&a) 1 { delete \&a[\%i] }
+
+The difference is, an array element doesn't change every time it's referred to!
+
+Added a /PRESERVE switch to the COPY command to preserve the timestamp and
+permissions of the file. I did this using the Kermit APIs so it should work
+for any version of C-Kermit or K95. ckuus[26].c, 30 Nov 2006.
+
+Added COPY /OVERWRITE:{ALWAYS,NEVER,OLDER,NEWER} to control name collisions
+when copying across directories. ckuus[26].c, 1 Dec 2006.
+
+--- Dev.23 ---
+
+Fixed a bug in SET TELNET PROMPT-FOR-USERID, SET AUTH KERBEROS[45] PROMPT,
+and SET AUTH SRP PROMPT in which the user's string was compared with a
+literal (s == ""), reported by Pavol Rusnak. Worse, empty strings (if the
+test succeeded) were turned into null pointers, and then fed to strlen().
+Fixed in ckuus3.c, 5 Dec 2006.
+
+Added an optional 4th argument to \findex(), \frindex(), \fsearch(), and
+\frsearch(): the desired occurrence number of the searched-for string.
+\frsearch() was a bit tricky. ckuus[24].c, 7 Dec 2006.
+
+Added \fcount(s1,s2) to tell the number of occurrences of s1 in s2.
+ckuus[24].c, 8 Dec 2006.
+
+Added \ffunction(s1) to tell if a given built-in function is available.
+ckuus[24].c, 8 Dec 2006.
+
+Changed RENAME /COLLISION:PROCEED to be /COLLISION:SKIP, which is clearer.
+ckuus[26].c, 8 Dec 2006.
+
+For communication protocols: INPUT /COUNT:n to read exactly n characters
+without any matching. Can be used, for example, with CONTENT_LENGTH in CGI
+scripts; NUL characters are counted but not collected. ckuusr.[ch],
+ckuus4.c, 8 Dec 2006.
+
+There was a bad bug in the date-parsing routines; it's been there for years.
+If a date string includes a timezone, e.g. "Sat, 9 Dec 2006 19:26:23 EST",
+and converting to GMT changes the date, the variables for day, month, and
+year (which are used later) were not updated, and the final result was a day
+off. Fixed in cmcvtdate(): ckucmd.c, 10 Dec 2006.
+
+Built OK with SSL/TLS. Tested with the POP script, found that I broke INPUT
+when adding the /COUNT feature; there was a path through the code that could
+leave the "anychar" variable unset and therefore random. Fixed in
+doinput(). The POP script, which does not use /COUNT, works again and so
+does a new CGI script, which does use /COUNT. ckuus4.c, 10 Dec 2006.
+
+Supplied a missing comma in the help-text array for HELP SET TERMINAL, which
+resulted in bad formatting in K95 around SET SNI-FIRMWARE-VERSIONS.
+ckuus2.c, 10 Dec 2006.
+
+Made "help locus" a synonym for "help set locus". ckuusr.[ch], ckuus2.c,
+11 Dec 2006.
+
+This morning the Columbia FTP server was malfunctioning in a perfect way
+for me to implement and test an FTP timeout mechanism. The server would
+close the data connection after sending the file, but the client never saw
+the close and was stuck forever in a recv(). I added code to do a select()
+on the data connection prior to entering the recv(), with a timeout on the
+select() that the user can establish with SET FTP TIMEOUT. Built and tested
+on Solaris 9, clear-text FTP. Also built cleanly for FTPS and tested
+against a server that does not hang; I don't have access to an FTPS server
+that would tickle the timeout code. ckcftp.c, 11 Dec 2006.
+
+--- Dev.24 ---
+
+Fixed a bug in the INPUT /COUNT: parser: the array of search strings was
+never initialized, which didn't matter before, but with /COUNT:, if the
+first element was not a NULL pointer, we'd treat it as a search string, and
+then if it happened to match something in the input stream, the operation
+would stop before the count was exhausted. Fixed by (a) initializing the
+array, and (b) ignoring any search strings if /COUNT: was given. ckuusr.c,
+13 Dec 2006.
+
+Removed a debug() statement from zsattr() that suddenly started making some
+version of gcc complain, reported by Gerry Belanger. ckufio.c, 13 Dec 2006.
+
+--- Dev.25 ---
+
+Some casts for the 3 interior args of the new select() call in ckcftp.c
+for HP-UX 9. 14 Dec 2006.
+
+Changed \fkeywordvalue() to accept a string rather than a single word
+as its second argument, so that more than one separator could be specified,
+and to return -1 on error, 0 if it found nothing, 1 if given a keyword but
+no value, and 2 if there was a keyword and a value. dokwval(): ckuus[24].c,
+14 Dec 2006.
+
+Checked FTP timeout on command channel with FTP DIRECTORY of a big directory
+using a path into our ftp server that preserves the hanging behavior. The
+timeout was actually working, but the failure condition wasn't propagating
+back to the user, and there was no error message. Fixed in doftprecv2() and
+failftprecv2(): ckcftp.c, 15 Dec 2006.
+
+Added the obvious timeout checks for FTP uploads, but I have no way to test
+the code since our misbehaving FTP server does not hang when receiving
+files, only when sending them. But uploads work both with and without a
+timeout set, so at least no harm is done. ckcftp.c, 17 Dec 2006.
+
+When downloading with FILE DESTINATION NOWHERE (= /CALIBRATE), Kermit still
+checked the size of the incoming file and refused it if there wasn't enough
+free disk space, on platforms (such as VMS) where zchkspa()) actually works;
+reported by Bob Gezelter. ckcfn3.c, 18 Dec 2006.
+
+Built on Mac OS X 10.4.8 and NetBSD 3.1_RC3, all OK. 19 Dec 2006.
+
+--- Dev.26 ---
+
+Built on VMS 7.3-2/Alpha. Had to squelch a couple compiler warnings by
+changing some ints in the new \fpictureinfo() code from unsigned to signed,
+and fix a typo in the prototype for the new gettcpport() function.
+ckcnet.h, ckuus4.c, 22 Dec 2006.
+
+--- Dev.27 ---
+
+Parameterized pty routines and all references to them for file descriptor,
+rather than to use global ttyfd, thus allowing ptys to be created for
+different purposes. Tested on Solaris 9 and Mac OS X 10.4.8, with "set host
+/connect /pty emacs" (fine in both cases), and (more to the point) "set host
+/connect /pty kermit" -- here we make a connection from one Kermit process
+to another and transfer a file; works fine and wasn't especially slow either;
+a good sign. ckcdeb.h, ckutio.c, ckupty.c, 22 Dec 2006.
+
+Created a new version of ttruncmd() called ttyptycmd(), which works by
+calling do_pty() to get a pty to run the command on, and then in a loop,
+reads from the pty and writes to the net and reads from the net and writes
+to the pty, using select() to which of those it should do on each pass.
+First cut just uses single-byte reads and writes. Tested using Kermit
+itself as an external protocol. Works but slowly: 6000cps. Zmodem doesn't
+work at all. ckutio.c, 24 Dec 2006.
+
+Changed single-character read() and write() to buffered reads and writes,
+with ttxin() and ttol() used for network i/o. Using Kermit as the external
+protocol, this gives 450Kcps (about 1/3 normal on this connection).
+
+But now there's a problem: the loop doesn't know when to stop. How does it
+know when the process that is running on the pty has exited? With single
+character read()'s that are executed unconditionally when select() says the
+pty has data waiting, as in the first pass, I get EIO if there actually
+isn't any, and can exit the loop. But now, to avoid blocking, I call
+in_chk() to see how much data is waiting, and I don't try to read anything
+if it says nothing is waiting. If the process associated with the pty file
+descriptor has terminated, in_chk() would presumably get some kind of error,
+but it doesn't. I changed do_pty to return the pid of the fork where it
+execs its command so we can check the pid with kill(pid,0) when in_chk() of
+the pty says 0, but this doesn't help either; it seems like the process is
+not exiting, but of course it is.
+
+I could not find any legitimate way to test when the pty fork terminated.
+Select() always says the pty file descriptor was ready, no matter what.
+Select() never reports an exception on the pty file descriptor;
+in_chk(ptyfd) returns 0 and not an error. read(ptyfd,...) gets 0 but not an
+error. fcntl(ptyfd,...) doesn't get an error. Finally I tried
+write(ptyfd,c,0) and this indeed gets EIO (i/o error). With this, using
+Kermit as the external protocol works fine in Solaris but I tend to think
+this trick will not be very portable (it isn't). 24 Dec 2006.
+
+Made ttptycmd() use a more intelligent buffering scheme, fixed a few things
+about how I was setting up the select() call that should address some of
+yesterday's problems. Still doesn't work but it's progress. A: 25 Dec 2006.
+
+Debugging yesterday's code... Still, the error conditions are never set,
+we never detect when the pty closes. In Solaris, if select() says ptyfd is
+ready to read but in_chk() says there are no characters there, we can treat
+this as a loop-exit condition. But in NetBSD, in_chk() always says 0 when
+used on a pty (but works OK on a serial or net connection).
+
+Realized I could not use in_chk() on the pty because there is too much
+baggage with the communication path -- myread(), etc etc) -- so I replaced
+this with a simple ioctl(ptyfd,FIONREAD,&n). This works fine in Solaris but
+always returns 0 in NetBSD, despite what the man page says (i.e. that this
+function can be used on any file descriptor).
+
+OK, let's see.... select() does not return useful results. It says
+characters are waiting on ptyfd when they are not, and it never detects the
+closure of the pty..... Well of course not, because we are the ones who
+have to close it. Just because the process has stopped doesn't mean the pty
+is closed. So we're back to square one, how do we know when to close it?
+ckupty.c seems to keep the process ID in a global variable, pty_fork_pid
+(which is not the same as the pid now returned by do_pty(), which is
+useless, but I don't understand why). But it doesn't matter because when we
+kill(pty_fork_pid,0), we still get no error of any kind, even after we know
+the process has exited. I am completely flummoxed. select() lies, and even
+if it didn't, there is simply no completion criterion. In the loop,
+select() always says that the pty is ready to read. To be continued.
+26 Dec 2006.
+
+Back to Square One, single-byte reads and writes.
+
+ . This works for both ripple and Kermit.
+ . Doesn't work for Zmodem but we'll deal with that later.
+ . In this case FD_ISSET(ptyfd) is still true after pty closes.
+
+But the ensuing read() gets EIO so we know the pty is gone. That means the
+same thing should happen in the buffered version, no? Yes; I went back to
+the buffered version and replaced all the other nonworking tests by a
+blocking read of 1 byte on the pty and this detects the termination. Now:
+
+ . ripple works perfectly (of course it's only one-way).
+ . Kermit fails
+
+Let's call the remote, forked, redirected, external Kermit A and its
+local partner B. A sends its S-packet, B receives it OK and Acks.
+A apparently does not receive the ACK in time, so sends the S again, but OK.
+followed immediately by the F. B Acks the F. A sends the A, B Acks it.
+But now A sends a piece of the previous F packet and the the first piece
+of a D packet.
+
+Clearly the buffering is messed up. Sure enough, there was an extraneous
+statement incrementing a read pointer in a write section. Removing that
+cleared up the problems with Kermit, now we can send and receive substantial
+files efficiently in remote mode. Zmodem seems to work too, except that at
+the beginning a bunch of "**B0800000000022d"'s are stuffed into Kermit's
+command buffer, so after the transfer we get some error messages.
+
+In local mode, over a Telnet connection, Kermit works fine. Zmodem works
+OK too except it doesn't finish right, so at the very end rz on the far end
+is still waiting for something; if I cancel out of it with ^X^X^X^X^X, it
+deletes the file. So there still is something wrong with the termination
+test.
+
+Also you don't see anything on your screen when running Kermit or Zmodem
+this way. That's to be expected, since they are using stdio for the
+transfer, so they can't also be displaying progress or other messages.
+
+Built this on NetBSD again... Seems to work this time, but has trouble
+finishing, like Zmodem. Hmmm, on closer examination, it turns out that
+since in_chk() always returns 0 on the ptyfd, we fall into our new
+single-byte read code, so it's really slow, like 10K cps on a connection
+where 1M is the norm. 27 Dec 2006.
+
+Switched the pty from buffer peeking (FIONREAD) and blocking reads to to
+nonblocking reads (O_NONBLOCK / O_NDELAY). Works just fine on NetBSD except
+now we no longer get EIO at the end when trying to read from the pty process
+that has exited. In fact, we're back to square one again. not ioctl(), not
+fcntl(), not select(), not even read() gets an i/o error after the pty
+process exits. But in NetBSD, we have to use nonblocking reads because ...
+Hmmmm, maybe switch the fd between blocking and nonblocking for the test...
+Nope, NetBSD seems to be hopeless (later, Ed Ravin confirmed that similar
+problems have been observed with other applications that try to do this).
+
+Switching to Linux, I see that yesterday's Solaris code (blocking reads)
+works exactly the same way on Linux.
+
+Tried today's O_NDELAY method on Solaris. It works perfectly. And then I
+moved this one to Linux and it works perfectly there too. Except in both
+cases we have the weird thing with Zmodem at the end, but I think that's
+because rz/sz don't use standard i/o. On NetBSD, it still hangs at the end.
+
+Turns out that testing the pid works in NetBSD, even though it didn't in
+Solaris. Turns out read() gets an i/o error in Solaris and Linux but not
+in NetBSD. So checking the read result first, and then checking the pid
+if read() got zero bytes catches all three. 28 Dec 2006.
+
+Now the question of return code. In the original ttruncmd() function, we do
+a fork() and a wait(). When the external protocol program finishes, wait()
+gives us its return code and we can pass it on through \v(pexitstat) as well
+ttruncmd's own return code. But ttptycmd() has to interact with the pty
+continuously, so it can't just sit back and wait() for it. Instead we have
+to detect when the process has exited and then call waitpid() on the fork
+pid, before shutting down the pty. Tested on Solaris using Kermit as the
+external protocol and then inducing failure, or letting it run to
+completion. FAILURE and SUCCESS set appropriately in each case. Tested
+with Zmodem too, works OK except for the aforementioned cosmetic glitch at
+the end. Tested on NetBSD, all OK.
+
+To make K5 connection to Panix from Spam:
+
+ set telnet debug on
+ authenticate K5 init /realm:PANIX.COM /password:xxxxx
+ set host shell.panix.com 23 /k5login
+
+Good... Now I try to send a file from Spam to Panix over the K5 connection
+using Kermit itself as the external protocol. It fails. Inspection of the
+debug log on the far side shows that the S-Packet was received correctly,
+good! This means we are reading the clear-text S-Packet from the external
+Kermit program, and that ttol() is encrypting appropriately.
+
+The remote Kermit sends the Ack and goes to read the next packet: ttinl()
+calls myfillbuf() and:
+
+ SVORPOSIX myfillbuf calling read()
+ SVORPOSIX myfillbuf=0 <-- read returns 0
+ SVORPOSIX myfillbuf ttcarr=2
+ SVORPOSIX myfillbuf errno=0 <-- and reports no error
+ HEXDUMP: mygetbuf read (-3 bytes)
+ mygetbuf errno=0
+ ttinl myread failure, n=-3
+ ttinl myread errno=0
+ ttinl non-EINTR -3[closing]
+
+This happens because myfillbuf() deliberately returns -3 when read() gets 0
+bytes. I don't understand why this happens but the real problem is yet to
+come. The local Kermit (the one that has made the secure connection and is
+running the external protocol through ttptycmd()) eventually figures out
+that the transfer failed and when we reconnect, we get total garbage -- the
+encryption either stopped happening, or got out of sync.
+
+Looking at the local debug log, ttol() is doing its job, converting the
+initial "kermit -r\13" from plaintext to cyphertext, as shown by the
+hexdumps. Then it enters ttptycmd()... Hmmmm, wait, how can it send the
+"kermit -r" before it starts the external protocol? Never mind, worry about
+that later... Anyway, ttptycmd() says:
+
+ ttptycmd loop top have_pty=1
+ ttptycmd loop top have_net=1
+ ttptycmd FD_SET ptyfd in
+ ttptycmd FD_SET ttyfd in
+ ttptycmd nfds=5
+ ttptycmd select=1
+ ttptycmd FD_ISSET ttyfd in
+ ...
+ ttptycmd in_chk(ttyfd) n=11
+ ttptycmd ttxin n=11
+
+ttxin() asks for 11 bytes, myfillbuf() gets 11 bytes, and hexdump() shows
+the cyphertext, there doesn't seem to be any decrypting going on. Hmmm, it
+looks like the regular code calls ttinc() in a loop, rather than ttxin().
+Maybe ttxin() doesn't have decryption hooks. No, that's not it, the code is
+there, but the Kermit packet reader does not use ttxin(), it uses ttinl().
+But of course we can't use that for external protocols because it's designed
+only to read Kermit packets. Substituting a loop of ttinc()s for the ttxin()
+call fixes things (and strangely enough, it seems to be faster). And now we
+have our first external protocol transfer over a secure connection (external
+Kermit program, Linux over Kerberos 5 to NetBSD). Zmodem worked too for a
+short file but "something happens" with longer ones. 29 Dec 2006.
+
+New makefile target for Linux with Kerberos 5, linux+krb5, that doesn't
+include anything extra from SSL or other security methods (but apparently it
+is still necessary to include -DOPENSSL_097 in order to get the right names
+for the DES routines?). Ditto netbsd+krb5 for NetBSD, except in this case
+-DOPENSSL_097 is not necessary. makefile, 30 Dec 2006.
+
+Note to myself: On Panix:
+
+ export LD_LIBRARY_PATH=/usr/local/kerblib
+ make netbsd+krb5 "K5LIB=-L/usr/local/kerblib" "K5INC=-I/usr/local/include"
+
+Can't telnet-k5 from newly built Kermit on NetBSD; partway through the
+negotiations, just after "TELNET RCVD SB ENCRYPTION SUPPORT DES_CFB64
+DES_OFB64 IAC SE" it dumps core. The last two lines in debug.log after
+this are:
+
+ tn_sb[len]=5
+ encrypt_support[cnt]=2
+
+Rebuilding with -DOPENSSL_097 doesn't change anything. Ed Ravin said they
+have two different Kerberos installations, Heimdal and MIT; maybe some
+mixup between the two explains the problem (Jeff concurs). The core dump
+occurs in ck_crp: encrypt_support():
+
+ debug(F100,"XXX ep not NULL","",0);
+ type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0; <-- Here
+ debug(F101,"XXX new type","",type);
+
+Anyway, I can log in with Kerberos 5 to Panix OK from Columbia (sesame)
+using 8.0.201. So let's try to resurrect the Solaris version with everything:
+
+ solaris9g+krb5+krb4+openssl+shadow+pam+zlib
+
+I hunted around to find where the current library and header file
+directories were... Last time I tried this (March 2006) it bombed, not
+finding libdes. Instead we have /opt/kerberos5125/lib/libdes425.a. Made a
+new cu-specific target that includes this; now we get farther; it blows up
+in ckcftp.c with tons of errors and warnings, which we can worry about
+later. Building again with -DNOFTP, it gets to ckuath.c (the first security
+module) and:
+
+ ckuath.c:151:18: error: krb5.h: No such file or directory
+ ckuath.c:152:21: error: profile.h: No such file or directory
+ ckuath.c:153:21: error: com_err.h: No such file or directory
+ ckuath.c:176:28: error: kerberosIV/krb.h: No such file or directory
+ In file included from /opt/openssl-0.9.8d/include/openssl/des.h:101,
+ from ckuath.c:219:
+
+Found krb5.h in /opt/kerberos5125/include/krb5.h, added a -I for this
+directory ... Now we get lots of warnings in ckuath.c, but it completes OK,
+then we wind up bombing out in ck_crp.c; I don't know why -- there are all
+the same warnings (related to argument passing to DES functions), but no
+errors. I have no clue.
+
+Tried to resurrect the solaris2x+krb4 target; this required changing -lkrb
+to -lkrb4 and -ldes to -ldes425. Lots of warnings in ckutio.c, ckcnet.c,
+ckctel.c, then it bombs out in ckcftp.c because it can't find krb.h. I
+found it, adjusted the -I flags, but now it bombs because krb.h itself
+#includes <kerberosIV/des.h>, which of course it can't find because the
+brackets mean it's looking in /usr/include/kerberosIV/, which, of course,
+the sys folks have removed. Giving up on Solaris again. Later, Jeff said
+"Solaris does not publicly export the krb5 libraries. You need to build
+the MIT Kerberos libraries separately and link to them." 30 December 2006.
+
+Changed copyright date to 2007. ckcmai.c, 1 Jan 2007.
+
+With Ed Ravin's help, successfully built C-Kermit with Kerberos 5 and
+OpenSSL (netbsd+krb5+openssl+zlib), but it does not make K5 connections; it
+gets hung up in the Telnet negotiations. 3 Jan 2007.
+
+Downloaded MIT Kerberos 5 v1.4.4 to Solaris 9, 54MB worth. This is just so
+I can build a Kerberized C-Kermit for testing ttyptycmd(). Ran the
+configure program, got a few warnings but it didn't fail (should it?) Did
+"make install", specifying a private directory but it failed immediately
+with "cannot stat libkrb5support.so.0.0: No such file or directory".
+OK, I tried. 3 Jan 2007.
+
+Made a new makefile target for Mac OS X, macosx10.4+krb5+ssl, ran it on Mac
+OS X 10.4.8. It bombs out in ckcftp.c with: ckcftp.c:551: error: static
+declaration of 'gss_mech_krb5' follows non-static declaration
+/usr/include/gssapi/gssapi_krb5.h:76: error: previous declaration of
+'gss_mech_krb5' was here". Ditto for gss_mech_krb5_old, gss_nt_krb5_name,
+and gss_nt_krb5_principal. Tried again with -DNOFTP. We get lots of
+warnings in the network modules, but they complete. But ck_ssl.c bombed
+with a conflict between its own declarations of encrypt_output and
+decrypt_input and the ones in ckuat2.h; removed the prototypes from the
+latter (as Jeff advised) it built OK and it works OK too. Built with FTP
+too, but with link-time warnings about the aforementioned gss_* symbols.
+#ifdef'd them out (gss_mech_krb5, gss_mech_krb5_old, gss_mech_name, and
+gss_mech_principal) for MACOSX, where these symbols are exported by the
+library. Now it all compiles and links OK, and runs OK too. 3 Jan 2007.
+
+Spent a day hunting around for a version of Zmodem that would build and
+execute on Mac OS X, finally found one. Now at last I could try a Zmodem
+external-protocol transfer over a secure connection. But phooey, C-Kermit's
+pty support didn't work on this box. Kermit finds master /dev/ptypa OK,
+then in ptyint_void_association() tries to open /dev/tty but gets ERRNO=6
+"device not configured" (which is apparently OK, because the same thing
+happens on other platforms where this works), then tries to open slave
+/dev/ttypa and gets ERRNO=13 "permission denied" because, indeed, I don't
+have r/w permission on the device. Left a message. 4 Jan 2007.
+
+Changed TRANSMIT /BINARY output buffer size from 252 to 508 to avoid
+TCP fragmentation. Need to add a SET command for this later.
+ckuus4.c, 5 Jan 2007.
+
+Found another Mac where the ptys weren't protected against me, make a K5
+connection and transferred a largish file with Zmodem with zero glitches,
+except it was kind of slow, 84K cps. Well, we're doing single-character
+reads on the net (ttinc()'s instead of ttxin()). Hmmm, but then I did it
+again and got 2.2Mcps. Success was reported, but it actually didn't work;
+it only sent the first quarter of the file.... Oh well, at least now we
+have a testbed. 5 Jan 2007.
+
+Tried again, saw that the file is actually transferred instantly but then
+we're not picking up the protocol at the end. Theory: after the transfer
+finishes, we come back to the prompt on the remote host, which means we have
+something to read from the net and write to the pty, but the pty has already
+exited. AFTER THE PTY IS GONE, WE DO NOT WANT TO READ FROM THE NET ANY
+MORE. Adding this test makes Kermit succeed right away when sending the
+same largish file, with a transfer rate of 4M cps, that's better. But the
+rz program on the far end is evidently not receiving the goodbye handshake
+from the receiver, because it sits there foreever in its *B09002402009418
+mode until I ^X^X^X^X^X out of it, at which point it deletes the file it
+already received, not very helpful. In the code, I read from the pty if the
+pty is open and there is room in the buffer. This means that when we get to
+the end, either there is no room in the buffer (unlikely) or the last bit
+sent by sz before exiting was cut off when the fork closed. Why do we get
+in this fix only with Zmodem and not with Kermit?
+
+In Mac OS X, after sz exits, we get ERRNO=5 if we try to write to the pty,
+but we still get no errors after that if we try to read from it. Still,
+prior to this we did more than 20 unproductive nonblocking reads from the
+pty (no error, no bytes) without incident; there did not seem to be anything
+waiting. In fact, the last thing we read from the pty were the text
+messages that are issued at the end of the transfer: "rz 3.73 1-30-03
+finished." After which it pauses a second and spits out a message about
+UNREGISTERED COPY.
+
+Figured out how to build lrzsz, in hopes that the previous problems were
+with rzsz and crzsz's fiddling with file descriptors, but I get the same
+behavior. Which is good, I guess, because if I can fix one, I fix them all.
+Or not... Testing lrz by itself (not under C-Kermit), I see that it doesn't
+work at all with Kermit's own Zmodem implementation.
+
+OK, here's one problem: at the end of the transfer, the Omen Zmodems print
+stuff like "Please read the license agreement", Kermit dutifully reads this
+from the pty and sends it to the host, the host shell says "Please: command
+not found", issues its prompt again, which Kermit reads, feeds to the pty,
+and apparently the pty echoes it, so we send it back to the host, and there
+ensues an infinite loop of getty babble until the pty closes. Now, there
+ought to be a way to make the external protocol shut up, like Kermit's
+-q(uiet) flag, but these are unregistered versions so you can't shut up the
+messages. In fact, the transfer works, but the getty babble at the end
+ruins the experience. Now I'm beginning to wonder how any of these programs
+ever worked as external protocols. Hmmm, now that I try it, I see the
+same thing happens the old way, when using ttruncmd() rather than ttptycmd().
+
+Reading the crzsz documentation I see it says that messages come out on
+stderr. OK, that's progress. In ckupty.c I try redirecting 2 to /dev/null.
+Well good, this filters out the messages from csz, but we still get getty
+babble on the prompt. In the debug log, we read the last bunch of stuff
+from net, 618 bytes of Zmodem stuff... Now what happens?
+
+Zmodem on the remote exits, the host prints its prompt. Kermit, of course,
+reads the prompt from the net, now come to the bottom of the loop and we
+have 7 bytes to write to the pty, and no error condition, so we continue the
+loop. select() says that the pty is ready for writing. We write the 7
+bytes and and get no error. Loop again, this time select() says the pty has
+data waiting. Sure enough we get the prompt back, and send it to the net,
+and thus begins the getty babble. There are two causes for this:
+
+ 1. crzsz does not exit immediately; it sleeps for 10 seconds after
+ printing its nag message.
+
+ 2. During this interval the pty seems to be echoing what is sent to it.
+ csz is not echoing; I checked. Anyway, removing the pause doesn't
+ seem to make a difference.
+
+ttptycmd() needs to:
+
+ . TELL the pty module to redirect stderr to /dev/null
+ . SET PTY TO NOECHO (master or slave?)
+
+Tried setting the pty to noecho:
+
+ termbuf.c_lflag &= ~(ECHO|ECHOE|ECHOK);
+
+and this seemed to stop the getty babble. After the file transfer, I read
+back the prompt from the host shell, I write the prompt bytes to the pty;
+there is no error. And now select() simply hangs forever (or times out if
+a timeout is set). The question here is: why didn't writing to the pty
+produce an error? And, because we never detect the pty has exited, we can't
+set a good return code. 5 Jan 2007.
+
+Moved pty fork testing to a separate routine, pty_get_status(), and
+added a call to it from the place where we time out, in case the fork
+terminated; then we can get and return its status. 6 Jan 2007.
+
+Added calls to pty_get_status() to every place where we suspect a pty error,
+tried again with lrzsz, crzsz, and regular rzsz. All three work, but in
+each case waitpid() indicates that the sz program gave exit code 1 (failure).
+ckutio.c, 7 Jan 2007.
+
+Changing the subject... On my test system, every time I execute ttptycmd(),
+I get "permission denied" on /dev/ttyp3. Then I run it again and get to
+ttyp4 which is OK. I wanted to skip past any pty for which I lack
+permission and try the next without raising an error. Added debugging code:
+
+ 16:25:23.524 pty_getpty() pty master open error[/dev/ptyp0]=5
+ 16:25:23.524 pty_getpty() pty master open error[/dev/ptyp1]=5
+ 16:25:23.524 pty_getpty() pty master open error[/dev/ptyp2]=5
+ 16:25:23.524 pty_getpty() found pty master[/dev/ptyp3]
+ 16:25:23.524 pty_getpty() slavebuf [2][/dev/ttyp3]
+
+So it already was skipping past open errors; ttyp3 was opened successfully.
+The problem is that ptyp3 is rw-rw-rw-, but the corresponding master,
+ttyp3, is rw--r----. It seems the code assumes that if the master can be
+opened, then so can the corresponding slave. Unfortunately, the code is
+not structured to allow us to skip ahead to the next master if the slave
+can't be opened. 7 Jan 2007.
+
+Spent a couple hours trying to rearrange the code in the pty module to skip
+past inaccessible slaves but it was a rabbit hole, not worth it, backed off.
+8 Jan 2008.
+
+Tried an upload over a secure connection using lsz. Unexpectedly, this time
+it worked; not only was the file (about 0.5MB) transferred correctly, but
+Kermit detected the fork's termination and got the pid's exit status, and,
+for the first time, correctly reported a successful transfer. I have no
+idea why this works today and not yesterday. More tests; it works most of
+the time. It works with csz and with regular sz too.
+
+(days later...)
+
+ckucns.c seems to do the right thing; it recognize the ZSTART string,
+activates the Zmodem-Receive APC, and returns. doconect() sees the APC and
+begins to execute it. The RECEIVE command results in a call to the GET
+command parser, doxget() (IS THAT RIGHT?), then comes a ttflui(), which
+throws away a bunch of stuff. Finally we get to ttptycmd(), we get a pty
+and run lrz in it, select() says stuff is waiting from the pty, but read
+returns 0, errno 0. Skipping the ttflui() in doxget() if the protocol was
+not Kermit didn't seem to make difference. ckuus6.c, 8 Jan 2007.
+
+The problem is that in this case, reads from the pty never get anything (no
+data, no error), write always gets an error. It's as if the pty was not
+being set up right, or we're using the wrong file descriptor. And if we
+skip the autodownload? Same thing.
+
+OK, putting downloads aside for a moment, let's get uploads working as well
+as possible. At this point we have the odd situation (at least in this
+configuration) that the upload succeeds, but now for some reason we are
+unable to read the exit status from the process, even though this was
+working before, so ttptycmd() returns 0 (failure), yet Kermit reports
+success.
+
+Well, it turns out that kill(pty_fork_pid,0) was gumming up the works.
+If we use only waitpid() all is well, I think. waitpid() with WNOHANG
+returns -1 with status -1 errno 0 if the pid has not exited, and it returns
+the pid and status > -1 if the process has exited. Fixed pty_get_status()
+to do it this way. ckutio.c, 7 Jan 2007.
+
+Let's move this from Mac OS to NetBSD and see how it works. Well, the file
+transfer was just fine, but then I used some sexps to calculate the elapsed
+time and transfer rate, and Kermit hung in dosexp(). Fine, ignoring that...
+The debug log shows that ttptycmd() gets the pty OK, master and slave, the
+i/o goes smoothly, and waitpid() does its job perfectly. Solaris, same
+deal; ttruncmd() goes smoothly, but then the sexps afterward get "Arithmetic
+exception". Turns out there was a BAD bug in dosexp() that allowed an
+integer division by 0 to occur under certain circumstances; it's always been
+there. Fixed in dosexp(): ckuus3.c, 8 Jan 2007.
+
+After noticing a few problems running the pop.ksc script in production over
+the past year, rewrote \femailaddress() to be more reliable and a lot
+simpler. ckuus4.c, 9 Jan 2007.
+
+Back to ttptycmd()... When we left off, we could send but not receive. Set
+up a test case using Kermit as the external protocol for receiving a short
+file. If I SET STREAMING OFF and use short packets, it actually does work,
+so it's not a complete failure to function, but apparently a lack of flow
+control for the pty. Began by completing the parameterization of the pty
+module, so it can be called for interactive use (fc 0) or for running
+protocols (1). Confirmed that everything works at least as well as before
+(e.g. "set host /pty emacs" vs external protocols). ckcdeb.h, ckutio.c,
+ckupty.c, 9 Jan 2007.
+
+Found in HP-UX "man 7 pty" a description of ioctl(fd,TIOCTTY,fc) which is
+exactly what we want: fc 0 turns off all termio processing and guarantees an
+uninterrupted, unmolested, flow-controlled stream of bytes in both
+directions. This function also exists in Linux, but not in Solaris, NetBSD,
+or Mac OS X (TIOCNOTTY is not what we want, it does something else entirely).
+
+Another possibility is TIOCREMOTE, which "causes input to the pseudoterminal
+to be flow controlled and not input edited, regardless of the terminal
+mode". This one exists in at least HPUX, NetBSD, Solaris, and Mac OS X.
+
+Solaris: builds OK, but at runtime we get ENOTTY ("Inappropriate ioctl for
+device"). By the time this happens, it's hard to tell from the code whether
+the fd we're using is for the master or the slave; TIOCREMOTE can be used
+only on the master. Close inspection shows that I am indeed doing that;
+ptyfd as seen by ttptycmd() is truly the master, i.e. the /dev/ptyXX device,
+not the /dev/ttyXX device (the slave fd can't be seen at all, as it exists
+only in a separate fork). OK, so now we know that TIOCREMOTE can't be used
+on Solaris.
+
+NetBSD: Somehow, whether as a result of today's fiddling or the phase of the
+moon, the code in pty_open_slave() that tries to open /dev/tty started
+failing on NetBSD ("Device not configured"). Changing it to be run only if
+fc == 0 (which doesn't seem to hurt anything), once again I get ENOTTY on
+the TIOCREMOTE ioctl. Zmodem works but Kermit totally fails (the fork exits
+immediately with an exit code of 0, even though it didn't do anything).
+
+Mac OS X: Exactly the same sequence and results as NetBSD.
+
+Linux: It did not execute the new ioctl at all; apparently the TIOC symbols
+are hidden or not exported or something.
+
+Where we stand:
+ . Downloads don't work
+ . Uploads got slow again
+ . Kermit doesn't work at all as an external protocol
+
+Actually if I take the debugging out it goes fast, but it doesn't finish.
+
+All today's work on ttptycmd() looks like a dead end. To roll back to
+yesterday:
+
+ cp ckutio.c-20070108 ckutio.c
+ cp ckupty.c-20070108 ckupty.c
+ cp ckupty.h-20070108 ckupty.h
+
+or to continue with today's:
+
+ cp ckutio.c-20070109 ckutio.c
+ cp ckupty.c-20070109 ckupty.c
+ cp ckupty.h-20070109 ckupty.h
+
+Comparing Monday's and Tuesday's pty-related code, the differences are:
+ 1. Passing of function code to and among pty modules.
+ 2. Skipping the TIOCSCTTY ioctl and the open("/dev/tty") test.
+ 3. Attempting to put pty in TIOCTTY or TIOCREMOTE mode.
+
+Commenting out 2 and 3 should put us back where we were on Monday if the
+parameterization was done right. And with this, on Solaris, downloading
+with Kermit external protocol works but slowly, 8K cps, with or without
+debugging. Debug log does not show any obvious bottlenecks; select() takes
+anywhere between no time at all and 0.1 seconds to return. If I increase
+the pty-net buffer size from 1K to 4K, the rate goes up to 55K cps. If I
+make it 8K I get 136K cps. With 16K I get 346K cps. 32K: 395K cps -- this
+last one isn't worth the doubling. But at 24K I get 490K cps, sometimes
+twice that. Let's stick with 24K for now. Downloading with Zmodem (rzsz)
+works at the same rate, but now we're back to seeing the getty babble
+(Several "**B0800000000022d") at the end. 10 Jan 2007.
+
+Moving to Mac OS X, everything works the same as on Solaris, except I don't
+get the Zmodem getty babble there, not even with Omen rzsz. Tested sends
+in both remote and local mode, the latter over a secure Kerberos 5 Telnet
+connection, using C-Kermit, rzsz, lrzsz, and crzsz, all good. 10 Jan 2007.
+
+Now we're back where we were yesterday morning, but with better throughput.
+The big issue then was receiving files. But yikes, now it works! Not only
+that, I got a transfer rate of 2.1M cps. That's using Kermit protocol,
+streaming, and big (4K) packets. Which didn't work before. Not a fluke
+either, I uploaded bigger and bigger files up to 6MB, they all went
+smoothly, at rates between 1 and 2 MBps. 10 Jan 2007.
+
+Not so great in Zmodem land, however. If I start the external-protocol
+receiver on the far end, escape back and start a Zmodem send... nothing.
+If I leave the remote C-Kermit at its prompt (where it supposed to recognize
+the Zmodem start string), still nothing. On the other hand, if I do it
+with a script instead of by hand:
+
+ def xx output take blah\13, send /proto:zmodem \%1
+
+it works, at least intermittently. But that's in remote mode. We won't be
+using this in remote mode. In local mode, where we have a secure connection
+to another computer, it seems we can read from the pty and write to the net,
+but we time out waiting to read from the net; nothing arrives. Well, we
+know that i/o works both ways, so there is some kind of screwup with the
+Zmodem protocol start itself. Increasing the (still hardwired timeout) from
+5 to 22sec and driving the whole process with a script so as to avoid
+autodownload as well as manual dexterity effects... It just sits there
+forever, way longer than 22 sec. ^C'ing out, I see that sz was indeed
+started on the far end and the protocol was executing. But it looks like
+the receiver (the one running under ttptycmd()) is getting trashed packets,
+because (a) it seems to be sending the same thing over and over again, and
+(b) sometimes it waits as long as 10 seconds before anything arrives from
+the remote. Maybe I was too impatient; I interrupted it after 4 minutes but
+it seems to have been making some progress. Whenever there was data
+available to read from the net, it was always 65 bytes, and it was not
+actually the same data over and over. This is using lrz as the external
+protocol. crz gets a bit farther. In this case we read up to 24K at a
+gulp, but the amount varies a lot. It looks like we took in about 1.2MB of
+Zmodem protocol data, but were only able to output the first 20K of the
+file. Clearly there were lots of errors. In the end, the crz exits with
+status 1 (failure).
+
+Anyway it looks like we're back at needing to find a way to accomplish
+something like TIOCREMOTE on the pty, which is where we came in. 10 Jan 2007.
+
+Without any way to make the pty transparent and flow controlled, it would
+seem to make sense to write to the pty in smaller chunks than we do to the
+net. I left the read-from-pty-write-to-net buffer at 24K and changed the
+read-from-net-write-to-pty buffer to 48 bytes.
+
+Upload using lsz worked but took about 3 minutes. Actually it didn't work.
+On the local end it seemed to work, but the file did not appear on the
+remote end. Tried this several times, each time with different results,
+adding more debugging each time. The problem this time was that the pty
+read could get EWOULDBLOCK. Changed the code to not treat this as an error,
+now Zmodem uploads are solid again except I never got EWOULDBLOCK again
+either, even though I repeated the same upload about 1000 times (with
+throughput of over 2MBps even with debugging on), so the test for it has
+not been exercised.
+
+OK, uploads still work. Back to downloading... The very first pty read
+gets 0 bytes, followed by the fork test that shows that it exited with
+exit status 2.
+
+Next we try starting sz with some different options on the far end:
+
+ -q: quiet (no messages):
+ for some reason this gets totally stuck.
+ it looks as if this option is misdocumented;
+ sz seems to be sending the letter C (as in Xmodem 1K or whatever)
+
+ -e: escape (all control chars):
+ first attempt to read pty finds the process gone with exit status 2.
+
+ -k: send 1k blocks:
+ this one didn't stop immediately. It reads 48 bytes from net, writes
+ 48 to the pty with no error. Then reads 21 bytes from the pty, writes
+ them to the net OK. Then reads 48 bytes from net, writes them to pty OK,
+ reads 21 from pty, writes to net OK, etc etc... It appears to have
+ worked but (final read from pty returned 0, fork test showed lrz exited
+ with status 0), but only 754 bytes were received from the net when the
+ file is 420K...
+
+Well this only goes to show that the faster we shove stuff into the pty, the
+worse it gets. Zmodem downloads won't work unless we can make the pty
+transparent and flow-controlled. So to summarize today's developments:
+
+ . separated in/out buffer sizes
+ . handled EWOULDBLOCK
+ . found out that sz options don't help much
+
+11 Jan 2007.
+
+Next day. This has got to be the most delicate code ever, it's like
+Whack-A-Mole, fix A and B pops up. Even without touching it, something that
+worked perfectly a 2:00 doesn't work at all an hour later. Maybe I could
+have used pipes instead of ptys, but pipes have problems of their own.
+There has to be a way to do this. The telnet server, the SSH server, etc --
+they all run on ptys, and we can upload files to them with Kermit. Why?
+Because Kermit puts its terminal into all the right modes using the
+time-honored methods of ttpkt() and ttvt(). Perhaps all we need is a copy
+of ttpkt() that operates on the pty.
+
+On that theory, let's go back to Kermit as the external protocol.
+It's important to suppress all messages and displays. With that,
+uploads work fine, no hitches.
+
+Downloads: We fail right away. The debug log shows the Kermit program that
+we are starting in the pty says:
+
+ "" - Invalid command-line option, type "kermit -h" for help.
+
+But of course we are not giving it an invalid command-line option.
+Switching to gkermit for the external protocol, now we see that no matter
+command-line options we use, we read 0d 0d 0a from the pty and then the
+next time we go to read from the pty we get 0 bytes and waitpid() says the
+program has exited with status 1.
+
+Why should downloading be different from uploading? ttptycmd has no idea,
+it does everything the same. The only difference would seem to be which
+side sends first, but even that tends to get washed out by each program's
+startup messages.
+
+Downloading with Kermit worked 2 days ago, what's different now? The buffer
+sizes. Putting the net-to-pty back up to 24K (from 48 bytes)... Now it
+works again.
+
+Conclusion: Kermit conditions the pty correctly, Zmodem does not. Therefore
+ttruncmd() must duplicate what ttpkt() does.
+
+Or not. Because rz works fine on ssh/telnet ptys too. But not on our pty.
+lrz exits immediately with status code 2 = 01000 but there are no clues in
+the lrz.c source code, I don't even see this exit status set anywhere.
+Unredirecting stderr, I see that the error is "lrz: garbage on command line".
+
+Why do both Kermit and Zmodem sometimes think they are receiving an invalid
+command line? If I could capture the garbage...
+
+Side trip #1: ("pty.log",O_WRONLY) gives "no such file or directory".
+Changed this to ("pty.log",O_CREAT,0644) and now it doesn't get an error,
+and it creates the file, but not with 0644 permissions, and with nothing
+written in it. How come nothing works?
+
+Fine, the debug log shows that ttptycmd() receives the correct string
+(e.g. "lrz -v"). It passes it to do_pty() correctly, and do_pty() passes it
+to exec_cmd(), which runs cksplit() on it, coming up (in this case) with
+"lrz" and "-v", which is right, and then:
+
+ args = q->a_head + 1;
+ execvp(args[0],args);
+
+execvp() wants the args array to have a null element at the end. cksplit()
+does indeed do that, or at least the code is there. Added code to exec_cmd()
+to verify the argument list and that it is null-terminated. So far it is.
+
+Anyway, we have traffic between the Zmodem partners, but no joy.
+Commenting out the bit that redirects stderr, now I can see it on my screen
+in real time:
+
+ lrz waiting to receive.Retry 0: Bad CRC
+ Retry 0: Got ERROR
+ Retry 0: TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: TIMEOUT
+
+etc etc, forever. Trying sz -e on the far end, I get:
+
+ Retry 0: Bad CRC
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ ...
+ Retry 0: Got ERROR
+ Retry 0: Bad CRC
+ Retry 0: Got ERROR
+ Retry 0: Got ERROR
+ lrz: xxufio.c removed.
+
+So apparently it's not a matter of escaping. Trying some other stuff, I
+caught the command-line problem in the act:
+
+ lrz: garbage on commandline
+ Try `lrz --help' for more information.
+
+Debug log shows:
+
+ cksplit result[lrz]=1
+ cksplit result[-v]=2
+ exec_cmd arg[lrz]=0
+ exec_cmd arg[-v]=1
+ exec_cmd arg[]=2
+
+An empty string at the end instead of a null pointer. I really do not see
+any way that could happen, but rather than dig into cksplit() again after
+all these years I added a test for this in exec_cmd(), which, of course
+after adding it, never encountered this behavior again.
+
+Fiddled with pty buffer size again. Made it 512 bytes instead of 24K.
+Zmodem downloads are the same (Rety 0: TIMEOUT, over and over). But I don't
+see what the problem is -- every time we receive n bytes from the net, we
+write n bytes successfully to the pty and there are no errors. But it also
+looks like the remote sender is sending the file header over and over
+because it's not receiving an acknowledgment. If we're not losing data,
+then maybe it's a transparency problem.
+
+Tried uncommenting the TIOCblah stuff I commented out before. Now instead
+of only timeouts I get:
+
+ lrz waiting to receive.Retry 0: Bad CRC
+ Retry 0: Got ERROR
+ Retry 0: Bad CRC
+ Retry 0: Got ERROR
+ Retry 0: Bad CRC
+ Retry 0: Got ERROR
+ Retry 0: TIMEOUT
+
+which is odd because the TIOCREMOTE ioctl failed with errno 14, EFAULT,
+bad address, which should indicate it had no effect. We're still receiving
+data from the remote in tiny chunks (from 12 to 65 bytes), apparently the
+same stuff (file header), and writing them to the pty successfully but
+nothing...
+
+Looked at cloning ttpkt() for the pty, but these stupid routines use global
+tty mode structs so it's not going to be easy.
+
+Well, we got exactly nowhere today, but I think I'll leave stderr as it is
+so users will see some feedback; no reason not to.
+
+WHY DO KERMIT DOWNLOADS WORK AND ZMODEM NOT?
+
+Is it 8-bit transparency? Up til now I've been testing with text files.
+If I try to download a binary what happens? Fails after 99 seconds. Packet
+log from the far end shows that as soon as the first packet containing 8-bit
+data is sent, everything stops. At least I got one of these:
+
+ 17:23:56.475 exec_cmd arg[gkermit]=0
+ 17:23:56.475 exec_cmd arg[-qr]=1
+ 17:23:56.475 exec_cmd arg[]=2
+ 17:23:56.475 exec_cmd SUBSTITUTING NULL=2 <-- the code I just added
+
+Doing this again shows the same thing on the near end. All the 7-bit-only
+packets are sent and acknowledged OK. Three 8-bit data packets arrive and
+nothing else happens after that. This is with G-Kermit.
+
+The same thing happens with C-Kermit receiving. But if I change C-Kermit's
+.kermrc to turn off streaming and use a short packet length:
+
+The transfer works, even though it's sending 8-bit bytes. So the problem is
+not 8-bit data after all, per se. Facts:
+
+ . Kermit can receive streaming transfers of 7-bit files.
+ . Kermit can not receive streaming transfers of 8-bit files.
+ . Kermit can receive nonstreaming transfers of 8-bit files with short packets.
+ . Kermit can receive nonstreaming transfers of 8-bit files with 1K packets.
+ . Kermit can receive nonstreaming transfers of 8-bit files with 4K packets.
+
+So it's the combination of streaming and 8-bit data? 12 Jan 2007.
+
+As a test I made a new routine pty_make_raw() that does cfmakeraw() (a
+nonportable "POSIX-like" function known to be used on ptys in applications
+that do approximately what we're attempting). Results:
+
+ Solaris: errno 25 - inappropriate ioctl for device.
+
+This happens even when we try to get the terminal modes with tcgetattr(),
+which is completely nuts. We pass it the file descriptor of the pty master,
+which is supposed to work. But in Mac OS X, there are no errors. But
+downloads still don't work; lots of errors but the pattern is different.
+Using a very small buffer:
+
+ Retry 0: Bad CRC
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Got TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: Bad CRC
+ Retry 0: Bad CRC
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: TIMEOUT
+ Retry 0: Got ERROR
+ Retry 0: TIMEOUT
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Bad CRC
+
+Using a bigger buffer:
+
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ (several screensful)
+
+Various other combinations... Nothing seems to work.
+
+Insight: telnetd does exactly what we want to do, sort of.
+But it uses TIOCPKT, so every time it reads from pty, it receives
+one control byte and then the data bytes, which would complicate our
+buffering scheme considerably. Anyway the TIOCPKT ioctl() fails on
+Mac OS X with 14 "Bad address".
+
+Also see: snoopserver.c (found in Google). It seems to do things in a
+slightly different way -- it sets stdout to raw and then dups it to the
+slave side of the pty?
+
+Maybe it's a mistake to use the ckupty.c routines. They are designed for
+creating and accessing an interactive session. Maybe just copy one of the
+other programs.
+
+18 Jan 2007. Tried going back to blocking rather than nonblocking reads
+to see if it would make a difference, after all the other changes. Nope.
+OK, let's look at some of these other programs...
+
+snoopserver.c. I don't know exactly what this is or where it's from or what
+platform it runs on and there are no comments to speak of, but it does
+approximately what ttptycmd() does. To get a pty it uses openpty():
+
+ if (openpty(&pty, &tty, NULL, NULL, NULL) == -1)
+
+then creates a fork. In the fork, it closes the pty (master) and
+manipulates the modes of the tty (slave), dups tty to be stdio, and then
+doex execv() on the command. Meanwhile the upper fork closes the tty
+(slave), gets the attributes of stdin, using atexit() to have them
+automatically restored on exit. Then it sets stdin to raw mode and enters
+the select() loop on stdin, the pty master, and the net. It uses regular
+blocking reads. It does not use TIOCPKT or anything like it.
+
+openpty() is supported on: Linux, Mac OS X, NetBSD, FreeBSD, ...
+openpty() is NOT supported on: Solaris, HP-UX, ...
+
+ 1. Try copying the pty code, but keep everything else the same.
+
+I did this; it compiles and starts OK, upper fork (ttptycmd) debug log shows
+no errors, but nothing happens. Logs show that the Kermit program that is
+started in the subfork seems to die as soon as it reaches eof on its init
+file. The good news, at least, is that select() doesn't report report that
+the pty is ready to be read. Clearly the file descriptors aren't being
+assigned as expected, or as before.
+
+In ckupty.c getptyslave() dup2's the slave fd to 0 and 1. The new code
+does exactly the same thing. Debug log makes it look like the forked kermit
+is not receiving its command line. But now I'm not even sure that the
+forked kermit started at all. ps from another terminal doesn't show it.
+
+19 Jan 2007: Noticed that in snoopserver, the select() calls use standard
+input and output file descriptors, rather than the pty master. Made that
+change... In doing that I had to look at every file descriptor in every
+line of code and discovered a couple mistakes, fixed them, put back the
+original code but with the fixes, tried it, but no change; can upload OK but
+still can't download with Zmodem without lots of errors and ultimate
+failure. Going back to the alternative version and trying to get the the
+file descriptors sorted out, now it appears that the external Kermit program
+never even starts in the lower fork. After a bit more fiddling I sort that
+out, but now when the lower Kermit program goes to open "/dev/tty" it gets
+errno 6 "Device not configured". Forcing it to use stdio with "-l 0", it
+gets past this and actually sends its first packet. But the Kermit on top
+reads nothing from the pty.
+
+Next, I change the pty fd from STDIN_FILENO and STDOUT_FILENO to slavefd.
+No difference. Next I comment out the dup2() calls. This time I get some
+action. The transfer starts, but only one packet comes. Log shows that
+the lower Kermit sends its S packet. The upper Kermit receives the ACK
+but the lower Kermit never gets it. The write to the pty succeeds, no
+error. Different combinations give different results. If write to master
+and read from the slave, I get packets in both directions but tons of
+errors.... This happens only if I comment out the dup2()'s.
+
+25 Jan 2007: After leaving it sit for a while, and realizing that what I'm
+trying to do has to be possible because so much other software does the same
+thing (e.g. Telnet servers), I put things back to how they were originally
+-- the upper fork (Kermit) uses the master and the lower fork the slave.
+The upper fork puts the master in raw mode, the lower fork puts the slave in
+raw mode. The lower fork dup2's the slave fd to stdin/out. Send file in
+remote mode using external Kermit: works OK but select() times out at the
+end. This means that the self-contained pty code in ttptycmd() is sorted
+out -- all the file descriptors go to the right place, etc, and now we can
+use this routine as a testbed, rather than the original ckupty.c-based one.
+
+But send with lsz, csz, and regular rz: Nothing happens, times out after 0
+bytes of i/o. Once again, Kermit works, Zmodem doesn't. The reason for
+running Zmodem in a pty is so its i/o will work as it does on a terminal,
+no matter how it may fiddle the file descriptors. So why don't we see a
+single byte come out?
+
+Commenting out pty_make_raw(), I get a successful Zmodem send using lsz.
+csz manages to get the filename across, but then gets stuck. regular sz, on
+the other hand, works perfectly. Testing csz by itself (not under Kermit),
+I see it fails in exactly the same way ("Got phony ZEOF", etc). OK, forget
+crzsz.
+
+OK, let's move to local mode over a Kerberized Telnet connection...
+Uploading (sending) with external Kermit protocol... works.
+Downloading (receiving) with external Kermit protocol... works.
+Uploading with sz... works.
+Downloading with lrz... Gets tons of errors and fails.
+
+Running pty_make_raw() on the slave but not on the master: no difference.
+Running pty_make_raw() on the master but not on the slave: no difference.
+
+Back where we started... Either:
+
+ . Zmodem is overdriving the pty, no matter what modes we put it in.
+ . It's a transparency problem.
+
+Theoretically we should be able to test these by using different sz switches:
+ -q: quiet (should always use this)
+ -e: escape all control characters
+ -B n: Buffer n bytes (rather than whole file)
+ -L n: Packet length
+ -l n: Frame length (>= packet length)
+ -w n: Window size
+ -4: 4K blocksize (doesn't help)
+
+-q by itself doesn't help.
+-q -e, this one worked but still got about 100 errors and was very slow.
+-q -e -l 200 -L 100, failed fast and bad.
+-q -e -w 1. Failed quickly.
+-q -e -w 1 -B 100. Eventually failed.
+-q -w 1, Eventually failed.
+-q -l 1024, this gets much more errors, definitely need -e.
+-q -e -l 1024, got pretty far before failing.
+-q -e -w 1 -l 1024, also got pretty far before failing.
+-q -e, this one got farthest of all, about 48K, before getting errors.
+
+In the latter combinations that work somewhat better, we always get up to
+16K, or 32K, or 48K, before the errors start coming out and piling up.
+Sometimes the errors are recoverable and we receive as much as 300K
+successfully before giving up.
+
+Now that we have data flowing pretty well (but not well enough), tried
+reinstating pty_make_raw(), but it hurt more than helped.
+
+As a sanity check, I tried transferring from the same host over the same
+kind of connection (Kerberized Telnet) directly to K95's built-in Zmodem
+protocol, and that worked fine. So the problem is definitely in the pty.
+Or more precisely, where Kermit writes incoming net data to the pty master.
+
+26 Jan 2007: Tried changing the size of the net-to-pty buffer from 24K to
+1K. Result: total failure. Set both buffers to 1K. Still total failure.
+Set both to 4K: now we get about 45K of data, then failure. Put them both
+back to 24K, still fails totally -- the same code that worked pretty well
+yesterday. Actually, no downloads work, not even Kermit, not even of
+text files.
+
+27 Jan 2007: Since I have not been able to find a way to make ptys work for
+this, I made a third copy of this routine, this time using pipes instead of
+ptys. The disadvantage here is that if the external protocol does not use
+stdio, the pipes won't work, but one thing a time...
+
+Inferior Kermit starts in lower fork, but when it tries to send its first
+packet it gets errno=9 EBADF, Bad File Descriptor. Substituting G-Kermit as
+the external protocol, which is simpler, reveals that the problem is that
+the external protocol gets errors when it tries to manipulate the its stdio
+file descriptors with ioctls, etc; these are not valid for a pipe. The pipe
+mechanism itself works. If I take out the test for ttpkt() failing in
+gkermit, the file transfer works OK. Trying Zmodem... Sending works OK;
+receiving works a lot better than with ptys (it got 360K into the file
+before failing). Making the buffers smaller, doesn't help.
+
+I'm starting to wonder if the problem might be in my buffering code, rather
+than in the pty or pipe interface... Try making a version that does
+single-character reads and writes.
+
+This one reads the first packet from the lower Kermit and sends it. It is
+recognized by the other Kermit, which sends an ACK. We see the ^A of the
+ACK, but then select() times out on the next character -- OF COURSE: because
+at a lower level, it has already been read. We have to check the myread
+buffer, and then call select() only if it's empty. Making this change:
+
+ . SEND with G-Kermit works (but very slowly).
+ . SEND with lsz works but gets a lot of errors, eventually succeeds.
+
+Let's work our way back... With the same changes to the buffered pipe version:
+
+ . SEND with G-Kermit/streaming works (fast).
+ . SEND with lsz works too (fast), but we get gubbish at the end.
+ . RECEIVE with Kermit fails because "/dev/tty is not a terminal device".
+ . RECEIVE with rsz... lots of errors ("garbage count exceeded") but succeeded.
+
+But maybe now we're seeing pipe artifacts, so going back one more step to
+the version that gets its own pty and starts its own fork:
+
+ . SEND with G-Kermit/Streaming works (fast) but select() times out at the end.
+
+Another breakthrough: Moved the write pieces to below the read pieces. This
+is what was preventing the buffer reset code from working -- with the writes
+done before the reads, we never catch up and can never reset the buffers.
+
+ . SEND with G-Kermit/streaming works (fast) (but there's a pause at the end)
+ . SEND with lsz works (fast) (but there's a pause at the end)
+ . RECEIVE with rsz... lots of errors ("garbage count exceeded") and fails.
+ . RECEIVE with Kermit -- nothing happens (it thinks it succeeded), then we
+ reconnect, terminal sees S packet and goes into autodownload
+
+From the log it looks like ttpkt() fails in the lower Kermit. Switching
+this with the hacked G-Kermit... it gets "transmission error on reliable
+link". Tried again with real Kermit below, this time with "-l 0" and not
+streaming. This was actually working, but slowly, I don't see any NAKs in
+the packet log, but then select() timed out.
+
+28 Jan 2007: Restored both the calls to pty_make_raw():
+
+ . SEND with C-Kermit streaming works, but slow (54Kcps)
+ . Ditto, but with debugging off -- hangs forever.
+ . Ditto, but using G-Kermit instead of C-Kermit -- also hangs forever.
+
+Backed off on calling pty_make_raw(). Same thing.
+Reduced size of net-to-pty buffer. Same thing.
+
+15 Feb 2007... Decided to give up on this and publish it as is, in hopes
+that somebody with more experience with ptys can make it work, because I'm
+just going in circles. So today I just have to get the code into shape so
+people could choose among the three alternative routines. The second one,
+yttyptycmd(), is the one that uses openpty(), which is not portable, so it
+can be enabled only for Mac OS X, NetBSD, FreeBSD, and Linux, or by also
+defining HAVE_OPENPTY at compile time. Anyway, if you build Kermit in the
+normal way, you get the regular behavior -- ttruncmd() is used to execute
+external protocols. If you build it with -DXTTPTYCMD, you get the first
+version of ttptycmd(); with -DYTTPTYCMD the second, and with -DZTTPTYCMD the
+third.
+
+(Then some interruptions, then...)
+
+From Jeff, fix hostname comparison in X.509 certificate checking to work
+right in the case of names that contain no periods. dNSName_cmp(): cl_ssl.c,
+21 Feb 2007.
+
+John Dunlap noticed some strange behavior when transferring files between
+home base and the EM-APEX oceanographic floats via satellite... long story,
+but every so often the transfer would get stuck for a long time, and it
+happened only when C-Kermit was sending a file and received two or more
+packets (Ack or Nak) back to back from the float. Years ago I added some
+lookahead code to ttinl() to clear the input buffer of any interpacket junk
+so that, in the windowing case, we wouldn't be tricked next time around into
+thinking a packet was waiting to be read when there wasn't. The code, which
+has been there for a while, was a bit fractured; luckily, it would be
+executed only when the debug log was active so it didn't have much effect.
+The problem was that if the SOP came immediately after the EOP, it could be
+missed because the loop read the next character before checking the current
+one. Fixed by rearranging the loop. Also I changed it so it would execute
+in all cases, not only when the debug log was active. Also, cleaned up a
+bunch of confusing #ifdefs and removed some chunks that had been commented
+out for years, decades maybe. ttinl(): ckutio.c, 21-22 Feb 2007.
+
+Added NOW keyword info to HELP DATE, plus a tip about how to convert to UTC;
+suggested by Arthur Marsh. ckuus2.c, 22 Feb 2007.
+
+When an FTP client sends NLST to the server and no matching files are found,
+the server is supposed to respond with an error message on the control
+channel and nothing on the data channel. However it seems that at least one
+server sends the error message back on the data channel, as if it were a
+filename ("/bin/ls: blah: No such file or directory"), and on the control
+channel there is no error indication ("226 ASCII Transfer complete"). At
+this point remote_files() has a listfile and, if a match pattern was given,
+it looks through list to see if any of the lines match the given filename,
+e.g. "blah". This makes FTP CHECK give false positives. The problem
+(diagnosed by Jeff) is that the match pattern was not given in this case, so
+it takes some random default action, resulting in the spurious success
+return. Fixed by using the user's string as the pattern. Not tested,
+however, since I don't have access to a server that behaves this way.
+ckcftp.c, 22 Feb 2007.
+
+If an external-protocol file transfer fails, don't print Kermit-specific
+hints. ckuus5.c, 22 Feb 2007.
+
+One more time with ttinl(). Got rid of the "csave" junk, which never could
+have worked (which is no doubt why it was in a debugging section). The
+problem was that saving the beginning of the next packet locally did not
+synchronize with the buffer clearing (ttflui()) done at a higher level,
+between calls to ttinl(). So now, the lookahead code, if it finds the
+beginning an as-yet unread packet, puts it back at the head of the input
+queue. This way, if the protocol engine clears the input buffer, it will
+get the whole packet, not just the part after the SOH. ckutio.c, 24 Feb 2007.
+
+From Steven M Schweda, Saint Paul, MN: adaptation of large file support to
+VMS (it was already possible to transfer large files in VMS C-Kermit but the
+file-transfer display and statistics were wrong). And a minimal adaptation
+of the FTP client to VMS -- no RMS, no special VMS file stuff, Stream_LF and
+binary files only, developed and tested only with UCX. SSL/TLS is
+supported. The source-code changes are minimal; most have nothing to do
+with VMS, but with header files, prototypes, and data types (e.g. ftp_port
+int rather than short, various signed/unsigned conflicts) to shut up
+compiler warnings. Some of these could be dangerous in terms of
+portability; I've marked them with /* SMS 2007/02/15 */. ckcfns.c,
+ckcnet.h, ck_ssl.h, ckuus3.c, ckuus4.c, ckvfio.c, ckcftp.c, ckvker.mms
+(which was rewritten to actually reflect the source module dependencies),
+ckvker.com (also heavily modified). ckvker.com (the "makefile" for VMS
+C-Kermit) now includes "F" and "I" option flags for the large File and
+Internal ftp features, plus better handling of Vax/Alpha/IA64 distinction.
+26 Feb 2007.
+
+Changed NetBSD targets to include -DHAVE_OPENPTY and -lutil, so they
+can use openpty(). makefile, 26 Feb 2007.
+
+Built on Solaris without and with SSL OK.
+Built on NetBSD with Kerberos 5, OK.
+Built on Mac OS X 10.4, regular version, OK.
+Built on Mac OS X 10.4 with SSL and Kerberos 5, OK.
+
+On VMS 7.2-1/Alpha with MultiNet 4.4A-X...
+
+'CC' 'CCOPT' KSP:ckuus3
+%DCL-W-TKNOVF, command element is too long - shorten
+ \CKUUS4.OBJ "'CC' 'CCOPT' KSP:ckuus4" "KSP:ckuus4.c KSP:ckcsym.h KSP:ckcdeb.h
+ KSP:ckclib.h" "KSP:ckcasc.h KSP:ckcker.h KSP:ckcnet.h KSP:ckvioc.h"
+"KSP:ckctel.h KSP:ckuusr.h KSP:ckucmd.h KSP:ckuver.h" "KSP:ckcxla.h
+ KSP:ckuxla.h KSP:ckcuni.h KSP:ckuath.h"
+
+The new rule for ckuus4.c was too long. I removed one file from the
+dependency list (ckcxla.h, which will probably never change again) and that
+made it OK. Built Nonet and Net versions OK, but this is without the new
+stuff.
+
+"make f" (large-file support) on VMS 7.2-1...
+'CC' 'CCOPT' KSP:ckuus4
+ if (CKFSEEK(fp,(CK_OFF_T)j,SEEK_CUR) != 0) {
+........................^
+%CC-I-IMPLICITFUNC, In this statement, the identifier "fseeko" is implicitly
+declared as a function.
+
+Ditto for ftello and fseeko in various other places, and then fseeko and
+ftello come up up undefined at link time.
+
+The rule for ckcftp in "make i" (Internal FTP support) had the same problem.
+I removed ckcxla.h from its dependency list too, but "utime" comes up
+undeclared at compile time and undefined at link time.
+
+Verdict: neither one of the two new features can be used in VMS 7.2 or
+earlier, but the code still builds OK if you don't ask for them.
+
+VMS 8.3 on IA64... Can't build anything:
+%MMS-F-BADTARG, Specified target (WERMIT) does not exist in description file
+
+27 Feb 2007: Changed CKVKER.COM to keep all its dependencies but use a
+shorter logical name (Steven M Schweda). The problem on VMS 8.3 is that MMS
+now supports case-sensitive file systems, and so it can't find anything.
+Workaround: bypass MMS (include "m" in P1). With this, "@ckvker.com ifm"
+builds OK on HP Testdrive, but I can't test the new features since outbound
+connections are not allowed there. As for fseeko(), ftello(), and utime(),
+they simply are not available prior to VMS 7.3. It would probably be a good
+idea to test for this in CKVKER.COM, but actually it is possible to install
+newer C's and CRTLs on older VMS versions, so don't stand in their way.
+
+28 Feb 2007: With additional changes from SMS, and then some further
+adjustments, I was able to build the FTP version on VMS 7.2-1. First I
+tested it with GET of a binary file, but it transferred it in text mode.
+After a few more attempts with PUT and GET, it crashed with "floating/decimal
+divide by zero" in ckscreen, ckuusx.c line 27859. Of course, that's the
+listing line, not the source line, and I don't have a listing.
+
+To get a listing, I deleted CKUUSX.OBJ and then did:
+
+ $ make i "" "" "/LIST"
+
+Surprisingly, it recompiled everything.
+
+Anyway, the divide by zero happened in a section of code where the divisor
+was not checked, but it was a section of code we should not have been
+executing at all, since the file-transfer display was fullscreen, and this
+was in the "brief" section. Anyway, I added the needed check. Again, it
+recompiles everything. Maybe there's no MMS on grumpy -- right, there isn't.
+
+ANYWAY... Try to GET a binary file like this:
+
+ binary
+ ---> TYPE I
+ 200 Type set to I.
+ get gkermit
+ ---> TYPE A
+ 200 Type set to A.
+ ---> SIZE gkermit
+ 550 gkermit: file too large for SIZE.
+ GET gkermit (text) (-1 bytes)---> TYPE A
+
+Anyway... "get /binary gkermit" downloads it, seemingly correctly (the byte
+count is right).
+
+But "put /binary gkermit.;1" results in a 0-length GKERMIT file being sent.
+Here's the debug log:
+
+FTP PUT gnfile[DISK$MSA4:[C.FDC.NET]gkermit.;1]=1
+ftp putfile flg[DISK$MSA4:[C.FDC.NET]gkermit.;1]=0
+zltor fncnv[DISK$MSA4:[C.FDC.NET]gkermit.;1]=-1
+FTP PUT nzltor[GKERMIT]
+zfnqfp 1[DISK$MSA4:[C.FDC.NET]gkermit.;1]=675
+zfnqfp 2[DISK$MSA4:[C.FDC.NET]GKERMIT.;1]=31
+zfnqfp 3[DISK$MSA4:[C.FDC.NET]GKERMIT.;1]=31
+zrelnam result 2[gkermit.;1]
+ftp sendrequest restart[DISK$MSA4:[C.FDC.NET]gkermit.;1]=0
+openi name[DISK$MSA4:[C.FDC.NET]gkermit.;1]
+openi sndsrc=-1
+openi file number=2
+zopeni[DISK$MSA4:[C.FDC.NET]gkermit.;1]=2
+zopeni fp=0
+chkfn=2
+chkfn return=0
+zopeni fixed file format - using blk I/O
+zopeni binary flag at open=1
+zopeni ifile_bmode=1
+zopeni binary=1
+zopeni RMS operations completed ok
+openi zopeni 1[DISK$MSA4:[C.FDC.NET]gkermit.;1]=1
+ftpcmd cmd[PASV]
+FTP SENT [PASV]
+FTP RCVD [227 Entering Passive Mode (166,84,1,2,233,216)]
+initconn connect ok
+FTP SENT [STOR GKERMIT]
+FTP RCVD [150 Opening BINARY mode data connection for 'GKERMIT'.]
+doftpsend2 ftpcode[STOR]=150
+
+ Here is where the file is supposed to be read and sent but there is nothing
+ in the log between the "doftpsend2 ftpcode" line and the following line.
+
+rftimer status=1
+gftimer status 1=1
+gftimer status 2=1409025
+gftimer status 3=1409025
+gftimer s[0.000000]
+zclose n=2
+chkfn=2
+chkfn return=1
+zclose ZIFILE RMS operations completed ok
+ftp getreply lcs=0
+ftp getreply rcs=-1
+ftp getreply fc=0
+FTP RCVD [226 Transfer complete.]
+ftp getreply[226 Transfer complete.]=2
+doftpsend2 ok=0
+
+Everything is OK up until we go to send the file, then it behaves as if we
+got EOF immediately and so closes the data connection, and reports success;
+an empty copy of the file is left on the far end.
+
+Starting over with a text file.... PUT LOGIN.COM gets another divide by
+zero. But it happened in the code I just fixed, which is impossible. Swell.
+I recompiled everything and this time the upload worked, and downloading it
+again worked too.
+
+But a binary file still can't be uploaded. Trying to upload a text file
+after doing this seems to succeed (reports the right number of bytes sent)
+but nothing appears on the far side.
+
+SUMMARY:
+
+ To download a text file: GET /ASCII blah.txt (/ASCII is optional)
+ To download a binary file: GET /BINARY blah.bin (/BINARY is required)
+ To upload a text file: PUT blah.txt (/ASCII switch not needed)
+ To upload a binary file: PUT /BINARY blah.bin (doesn't work)
+
+Problems:
+ . Why doesn't BINARY "stick"?
+ . Why don't binary uploads work?
+
+The culprit seems to be the VMS version of zxin(). In the FTP module,
+zxin() is called only when sending binary files. In VMS, zxin() is just
+a front end for C-Library fread(). It probably needs to do just do
+zminchar() in a loop, like binary mode does, but calling zzout instead
+of xxout. Or something like that. FINISH THIS TOMORROW (debug on grumpy).
+
+2 Mar 2007: New logs from John Dunlap.
+
+ema-1636-log-0175.dbg: C-Kermit uploads a short file. It receives an Ack for
+the Z packet it just sent, tailgated by the beginning of a Nak for the next
+packet. When the second SOH is encountered, it is put back in the myread
+queue. Then the protocol engine, to which we return the Ack, says, "I have
+the packet I wanted so I'm clearing the buffer", and away go the first two
+bytes of the Nak from the myread buffer. Then, having just received the Ack
+of our Z packet, we send our B, and go to read the reply. in_chk finds 0 in
+the myread buffer (which we just cleared) and 6 waiting to be read from the
+comms channel, which it does, obtaining the remaining 6 bytes of the Nak,
+which it properly discards. (The reason this is proper is that, having
+already received the Ack for the last packet it sent, no Ack or Nak that
+arrives subsequently -- in the non-windowing case -- could possibly affect
+what it does next.) Since it hasn't yet found a good packet, it keeps
+reading, and now it finds the Ack to the B, as soon as it showed up. This
+is how it's supposed to work. No time was lost because of anything that
+C-Kermit did.
+
+ema-1636-log-0174.dbg: C-Kermit uploads a short file. It sends Data packet
+#3 and receives the Ack followed immediately by the first 3 bytes of a Nak
+for packet 4. When it gets to the SOH of the second packet, it pushes it
+back in the queue. Again, input() flushes the input buffer (myread queue
+and device buffer). C-Kermit detects EOF on the file it is sending, and
+sends the Z packet. Then it reads the remaining bytes of the Nak,
+which it discards, and then it finds the Ack for Z which comes in 23 seconds
+later, sends the B, gets a Nak for the B, sends the B again, gets the Ack
+for the B 4 seconds later, and done. Again, it's working right and losing
+no time.
+
+The question remains: what would happen if the protocol engine did not clear
+the buffer? Would ttinl() retrieve all packets in sequence even when they
+come back to back? To test this, I had C-Kermit send a file using 30 window
+slots and observed the stream of Acks in the reverse direction:
+
+ HEXDUMP: mygetbuf read (16 bytes)
+ 01 25 23 59 2f 52 39 0d | 01 25 24 59 2b 26 31 0d .%#Y/R9. .%$Y+&1.
+ ttinl lookahead my_count=9
+ ttinl lookahead removed=^M
+ ttinl lookahead pushback SOP=^A
+ HEXDUMP: ttinl got (7 bytes)
+ 01 25 23 59 2f 52 39 | .%#Y/R9
+ RECEIVE BUFFERS:
+ buffer inuse address length data type seq flag retries
+ 0 1 29212 9667 0 Y 3 0
+ [\x01%#Y]
+ ...
+ in_chk my_count=8
+ ...
+ ttinl lookahead my_count=1
+ ttinl lookahead removed=^M
+ HEXDUMP: ttinl got (7 bytes)
+ 01 25 24 59 2b 26 31 | .%$Y+&1
+ RECEIVE BUFFERS:
+ buffer inuse address length data type seq flag retries
+ 0 1 29212 9667 0 Y 4 0
+ [\x01%$Y]
+
+Here we can see that the pushed-back SOH was properly retrieved next time
+around, and the tailgating Ack was not lost. This scenario repeats itself
+212 times in the log, and there are no screwups.
+
+Back to VMS FTP... The problem with sending binary files is that zxin()
+uses C-Library fopen()/fread() instead of RMS, so it can't access the input
+file, which was opened by zopeni(), which is totally RMS-ified in VMS
+C-Kermit. For VMS only, I replaced the zxin() loop by a zminchar() loop
+like the one used in text mode, except without the character set or
+record-format conversion. Tested by PUT /BINARY of some binary files, which
+worked fine. ckcftp.c, 2 Mar 2007.
+
+Next problem... VMS C-Kermit ftp client sending binary files in text mode.
+Variation 1: We just send the file. zopeni() is supposed to detect that
+it's a binary file and automatically set the mode. And it does:
+
+ zopeni fixed file format - using blk I/O
+ zopeni binary flag at open=0
+ zopeni ifile_bmode=1
+ zopeni binary=0
+ zopeni autoswitch from TEXT to BINARY
+ zopeni RMS operations completed ok
+
+but then in gnfile():
+
+ if (!server || (server && ((whatru & WMI_FLAG) == 0)))
+ binary = gnf_binary; /* Restore prevailing transfer mode */
+
+Well, since VMS sets text/binary mode automatically when sending files,
+this code can (and should) be skipped in VMS. gnfile(): ckcfns.c, 2 Mar 2007.
+
+Variation 2: BINARY or SET FILE TYPE BINARY doesn't force binary mode. But
+SET FTP TYPE BINARY does. But BINARY does indeed call doftptyp() so what's
+the problem? We do indeed set ftp_typ to 1 but it gets reset somewhere
+before we call zopeni(). But then zopeni() puts it back to 1. Tracing
+through a transfer, it looks like all of this works right, it's only that
+the file transfer display says TEXT when the transfer is really in binary
+mode. This is because screen() is called before openi(). I wonder if we
+can call scrft() from the ftp module... No, that would be too easy. OK,
+sendrequest calls openi() and sets the file mode; putfile() calls
+screen(SCR_FN), which prints the transfer mode. But putfile calls
+sendrequest() after it puts up the screen that says the file type. So it
+looks like sendrequest() has to call screen(SCR_FN) again if it changes the
+file type. OK, that did it. ckuusx.c, ckcftp.c, 2 Mar 2007.
+
+The BINARY and TEXT (ASCII) commands do not inhibit automatic type switching
+in VMS. They don't in Unix either. They never have. Should they? I think
+so, otherwise what good are they? Plus we want the Kermit FTP client to
+behave like the others. I added code for this but it doesn't work, due to
+the layers and layers of text/binary detection and switching and
+if-this-but-then-if-that... Anyway, no harm done. The normal rule is:
+when you PUT a file, Kermit figures out on a per-file basis whether to use
+text or binary mode unless you include a /TEXT (/ASCII) or /BINARY switch
+in the PUT (or MPUT) command. ckuus[r3].c, ckcftp.c, 2 Mar 2007.
+
+Wed Mar 7 16:21:13 2007 WROTE SHORT TEST PROGRAM for ttruncmd (the openpty
+version) on Mac OS X. On dulce: ~/kermit/ttpty.c / ttpty.sh. It starts the
+external protocol in the lower fork. The command to run is a command-line
+argument. Sending and receiving files with Kermit works OK. But again, the
+standalone program totally fails when I use sz or lsz as the external
+protocol. So it looks like we can rule out any environmental effects of
+running the code inside C-Kermit.
+
+Mon Mar 12 16:52:20 2007: Put some effort into making ttpty.c more useful;
+added a debug log. Found that for some reason, at least on Mac OS X,
+select() always timed out at the the end. I added a SIGCHLD alarm and that
+seems to handle the fork exit condition very nicely. Now we can send (say)
+a 3MB file at good speed on Ethernet (1Mcps) considering the debugging, etc,
+and it terminates instantly. But when sending a file into ttptycmd (with
+"gkermit -r"), things go wrong at the end -- the Z packet is never
+acknowledged. This is reproducible. Maybe this is a good lead.... The log
+shows that select() timed out, even though the gkermit fork had not yet
+exited (or finished). It looks like gkermit sent the Ack, ttpty.c read it
+from the pty and sent it out the net:
+
+ 0003: read pty=8 <-- read Ack from pty
+ 0003: loop top have_pty=1
+ 0003: loop top have_net=1
+ 0003: FD_SET pty_in
+ 0003: FD_SET ttyfd in
+ 0003: FD_SET ttyfd out=8
+ 0003: nfds=5
+ 0003: select=1
+ 0003: FD_ISSET ttyfd out
+ 0003: write net=8 <-- send ack to net
+ 0003: loop top have_pty=1
+ 0003: loop top have_net=1
+ 0003: FD_SET pty_in
+ 0003: FD_SET ttyfd in
+ 0003: nfds=5
+ 0009: select=0
+ 0009: select timeout - have_pty=1
+
+But Ack never arrived. This is a streaming transfer. But nope, streaming
+is not the problem. If I disable streaming ("gkermit -Sr"), we hang in in
+the middle of sending the data. If I use small packets, we don't hang:
+1000 is OK, 2000 is not. In fact, the cutoff is 1024. OK, TBC...
+
+Wed 14 Mar 2007: Receiving a file thru ttpty "gkermit -e 1200 -Srd"
+produces a debug log that shows that gkermit gets a lot of EAGAIN errors
+when it tries to read from its stdin. In fact, it takes 6 tries (read()
+calls) to read the S packet (27 bytes). Then when the first data packet
+arrives (1200 bytes), read() never returns even one single byte. The
+timeout interval is 15 seconds and it times out repeatedly. Added a
+primitive hex dump to the ttpty debug log for each read/write (showing only
+the first 24 characters and the last character, so it fits on one line).
+Tried uploading a file. The S, F, and A packets (short) are received and
+Ack'd OK, but then ttpty select() times out, never receiving even one byte
+from the D packet. Clearly, when the pty driver receives a burst of > 1K
+bytes, stops working. As before, if I limit the packets to < 1K, it works
+fine.
+
+Can I send an 8-bit binary file? Nope. ttpty reads the binary data just
+fine from the net and writes it exactly as it was received to the pty, but
+the first time we write an 8-bit byte, we never hear back from the PTY
+again. But the log shows that when the initial 7-bit packets from the pty,
+it looks like the PTY is not in rawmode, because these packets end with ^J
+rather than ^M. Calling pty_make_raw() on the masterfd and slavefd
+explicitly, however, doesn't change anything. It doesn't matter if I do
+this in the lower fork or the upper fork. So maybe it's the actual
+semantics of pty_make_raw() that are wrong.
+
+Thu 15 Mar 2007: Went thru all the terminal mode flags in Mac OS X; didn't
+help. Changed hex dump to show whole packet. Put hex dump routine in a
+private copy of G-Kermit. Tried to transfer an 8-bit file, logging both
+ttpty and gkermit. Compared what ttpty received on stdin with what it sent
+to the pty (same) and what was received by G-Kermit (same). Then I realized
+that my little test program was not putting its controlling terminal into
+raw mode; when I did that, I could upload binary files (streaming, 2MB/sec).
+And with Zmodem too (with rz; lrz doesn't work for some reason). Looking
+back at the original in ckutio.c, I see that ttptycmd() never called
+ttpkt(). Maybe that was the trouble all along. (Yup, but maybe not the
+whole trouble.)
+
+Moving back to C-Kermit and the original ttptycmd() routine, adding the call
+to ttpkt(), and stripping out a lot of cruft, and moving the pty_make_raw()
+code to ckupty.c, Kermit uploads and downloads (streaming) work fine in
+Solaris. Zmodem sends a file, but then the transfer hangs at the very end,
+as if the signoff protocol were lost. This happens on Solaris. If I move
+back to Mac OS X, everything works just fine. Then, making a Kerberized
+connection from the Mac to NetBSD, I can send files from the Mac with both
+Zmodem and Kermit. Receiving... Kermit OK. Zmodem... Nope. "rz:
+Persistent CRC or other ERROR" (and created a 265MB debug.log!)
+
+Fri 16 Mar 2007: ttptycmd() was for sending files with Zmodem across
+encrypted connections. But it occurred to me that it's necessary for
+clear-text connections too; e.g. Telnet, where 0xff has to be doubled. Of
+course Zmodem doesn't do that itself, so there's no way Zmodem external
+protocol could work when executed over a Telnet connection, and in fact
+it doesn't. I wonder why I ever thought it did.
+
+Wed 21 Mar 2007: Back to where we left off a week ago. Trying C-Kermit's
+ttptycmd() on the Mac again, in remote mode:
+
+ . G-Kermit send txt (kst): OK 832Kcps
+ . G-Kermit recv txt (kr): OK 425Kcps
+ . G-Kermit send bin (ksb): OK 1000Kcps
+ . G-Kermit recv bin (kr): OK 188Kcps
+
+And Zmodem:
+
+ . sz txt (zst): OK 563Kcps
+ . sz bin (zsb): OK 714Kcps
+ . rz txt (zr): OK 863Kcps
+ . rz bin (zr): OK 198Kcps
+
+So in remote mode, everything works. Now let's try a clear-text Telnet
+connection...
+
+ . G-Kermit send txt (kst): OK 841Kcps
+ . G-Kermit recv txt (krt): OK 391Kcps
+ . G-Kermit send bin (ksb): OK 811Kcps
+ . G-Kermit recv bin (krb): OK 171Kcps
+
+And Zmodem over the same clear-text telnet connection:
+
+ . sz txt (zst): OK 91Kcps (*)
+
+Kermit is sending sz messages like "sz 3.73 1-30-03 finished." to the
+host, which tries to execute them, after the transfer is finished.
+Of course "sz" is a command, but:
+
+ sz: cannot open 3.73: No such file or directory
+ sz: cannot open 1-30-03: No such file or directory
+ sz: cannot open finished.: No such file or directory
+
+Did I lose that code that dis-redirects stderr when I went back to using the
+pty code from the ckupty module? No, it's there and it's being executed.
+Apparently the copy of sz I have is writing its "finished" message to stdout
+because "sz blah 2> /dev/null" does not suppress it. Starting again with
+lsz instead of sz:
+
+ . sz txt (lzst): OK 413Kcps
+ . sz bin (lzsb): OK FAILED (*)
+ . rz txt (lzrt): OK
+ . rz bin (lzrb): OK
+
+(*) Sigh. Using lsz, we get "garbage count exceeded" errors and eventual
+failure. But using regular sz, we get the extraneous message that starts
+sz on the far tend, and the resulting getty babble.
+
+But even without changing the code, it will work one minute, and then fail
+consistently the next. For example, I was able to send files with sz
+successfully over and over, but with the getty babble at the end. Then,
+after trying lsz and then going back to sz, every attempt at sending a file
+quits with "Got ZCAN". The difference has to be that Kermit always does at
+least some minimal encoding of C0/C1 control characters such NUL and DEL and
+IAC, and I doubt that Zmodem does.
+
+http://zssh.sourceforge.net/ says:
+
+ If file transfer is initiated but never completes (ie a line like :
+
+ Bytes Sent: 0/ 513 BPS:0 ETA 00:00 Retry 0: Got ZCAN
+
+ can be seen, but transfer never completes), chances are the pty/tty on one
+ of the systems are not 8-bit clean. (Linux is 8-bit clean, NetBSD is not).
+ Using the -e (escape) option of rz should solve this problem.
+
+It doesn't, at least not with lrz. And yes, the receiving end happens to be
+NetBSD. But it looks like the zssh people have been down this road too.
+
+But with rz and sz, it worked. Once. Twice. Three times. But of course,
+with the getty babble at the end. This can be taken care of by doing:
+
+ rz -eq ; cat > foo
+
+which puts "sz 3.73 1-30-03 finished" and any other messages in foo (but you
+have to type ^D to finish the cat). Using this method I was also able to
+send an 8K binary file that contained a test pattern of all 256 possible byte
+values. Then I tried a 3MB binary executable. All OK. So here we go again:
+
+ . sz txt (zst): OK
+ . sz bin (zsb): OK
+ . rz txt (zrt):
+ . rz bin (zrb):
+
+Downloading fails about halfway through a fairly large file. I tried an
+even bigger file, guaranteed to be 100% ASCII; same thing -- halfway
+through: "rz: Persistent CRC or other ERROR". But it worked with a smaller
+version of the same file (82K versus 2MB). Tried again with the bigger
+version, it failed in exactly the same way at exactly the same spot: byte
+number 1048320. But this is just ASCII text so it can't be a transparency
+problem. Substituting another plain ASCII file of the same size but totally
+different contents, it doesn't fail (2.36MB). Back to the previous file, it
+fails again, but in a different spot (832960). So it's not totally
+deterministic.
+
+To round things out, I tried downloading the binary test-pattern file; it's
+only 8K. This failed.
+
+ -4, --try-4k go up to 4K blocksize
+ -B, --bufsize N buffer N bytes (N==auto: buffer whole file)
+ -e, --escape escape all control characters (Z)
+ -E, --rename force receiver to rename files it already has
+ -L, --packetlen N limit subpacket length to N bytes (Z)
+ -l, --framelen N limit frame length to N bytes (l>=L) (Z)
+
+Tried again with "sz -L 256 -B 256 -4aeq". Doesn't change anything.
+
+NOTE: Mac OS X rz 3.73 1-30-03 does not support -e.
+NetBSD rz 0.12.20 does support -e.
+
+Thu 22 Mar 2007: It occurs to me that ttpkt() might still be a problem;
+maybe it's the network connection and not the pty that is not transparent
+enough. To test this theory I did "stty raw ; stty -a" and then copied all
+of the flag values into ttpkt in the BSD44ORPOSIX section:
+
+ . rz txt (zrt): OK (2.36MB file, worked 2 out of 3 times)
+ . rz bin (zrb): "rz: Persistent CRC or other ERROR"
+
+A little more fiddling with the flags and I got the 8K binary test pattern
+to SEEM to download OK (in the sense that rz gave a 0 return code) but the
+file itself was truncated, always at 224. If I changed the test pattern
+file to not include any bytes with value 224 (0xe0) or 255 (0xff), the
+download worked. So we have a transparency problem somewhere. The debug
+log shows that all byte values are being received from the network correctly
+so the problem has to occur when we try to feed them to the pty.
+
+But no amount of twiddling with the termios flags seems to let these
+characters pass through. Of course, since they are not in the C0 or C1
+control range, "sz -e" doesn't quote them (which it does by prefixing with
+Ctrl-X and then adding 0x40 to the byte value so (e.g.) NUL becomes ^X@.
+Note that 255 does not cause problems because it coincides with the IAC
+character; the remote Telnet server doubles outbound IACs, and Kermit's
+ttinc() undoubles them automatically (as the log shows).
+
+Trying to send a different file (a C-Kermit binary) shows that 255 is the
+real killer; the file is truncated where the first one appears (at about
+6K), even though some 224's precede it. Going back to the remote-mode test,
+I see the same thing happens with the binary test-pattern file, if I send it
+from K95 direct to rz-under-C-Kermit-in-remote-mode. So it has nothing to
+do with C-Kermit having a network connection. Yet if I send the same file
+direct from K95 to rz, it goes OK and the result is not truncated, so it's
+not Zmodem either. The data arrives to C-Kermit intact, so the failure is
+definitely in writing it to the rz process through the slave and master ptys.
+
+BUT if I send the same file from K95 to rz-under-ttpty, that works. What's
+the difference? Suppose I just transplant ttpty literally into C-Kermit...
+It makes no difference. When receiving the test-pattern, it truncates it
+in exactly the same place.
+
+Well, all this is on Mac OS X. What if I move it to a different platform?
+OK, building on Solaris and following the exact same procedure, ttptycmd()
+doesn't even use the network connection. I think that's because rzsz on
+Solaris is hardwired to use the controlling terminal and can't be
+redirected, even in a pty?
+
+Moved to NetBSD.
+
+ . sz txt (zst): Failed ("Got ZCAN")
+ . sz bin (zsb):
+ . rz txt (zrt): OK
+ . rz bin (zrb):
+
+Well, this is a big mess. Sending doesn't work (or sometimes it does but
+reports that it didn't). Receiving... well, actually it's the same thing;
+the file is completely transferred but then the final protocol handshake is
+lost. The local C-Kermit returns to its prompt, but rz is still running:
+
+ Retry 0: Got TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: Got TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: Got TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: Got TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: Got TIMEOUT
+ Retry 0: TIMEOUT
+ Retry 0: Got TIMEOUT
+
+I don't see how that is even possible. Even after I exit from Kermit the
+messages keep coming, even though ps doesn't show the rz process anywhere.
+Looking at the code, I see a place where end_pty() was still commented out
+from the ttpty.c episode, I uncommented it. But still:
+
+ . sz txt (zst): Fails ("Got ZCAN")
+ . sz bin (zsb): Fails instantly (but with no diagnostic)
+ . rz txt (zrt): OK
+ . rz bin (zrb): Fails with tons of "Bad CRC", "Garbage Count exceeded"
+
+Conclusion for the day: I think this is hopeless. Even if I can get it to
+work somewhere, the results depend on the exact Zmodem software, how it uses
+stdin/out vs stderr versus getting its own nonredirectable file descriptor,
+versus the Zmodem version on the other end and which options are available
+on each, versus the pty and select() quirks on each platform, and on and on.
+It will be so hard to explain and to set up that nobody would ever use it.
+It would be better to just implement Zmodem internally.
+
+Fri 23 Mar 2007: Went back to the small test program, ttpty.c. Tried
+setting both the master and the slave pty to rawmode, even though I have
+never seen any other software that did this. I had it receive the binary
+test pattern file; it worked. I made a bigger test-pattern file, 3MB,
+containing single, double, and triple copies of each byte in byte order and
+in random order, this one was accepted too.
+
+So it would seem that the ckupty.c module is something to avoid after all.
+It's full of stuff I don't understand and probably should not undo. So
+changing C-Kermit's ttptycmd() to manage its own pty again, using openpty()
+(which is not portable), I got it all to work in remote mode: Kermit
+text/binary up/down and Zmodem text/binary up/down. But in local mode on
+the client side of a Telnet connection...
+
+ zst: OK, but we still get the getty babble at the end that starts sz.
+ zsb: OK, ditto. This is with the 3MB test-pattern file.
+ zrt: Not OK -- "Persistent CRC or other ERROR"
+ zrb: Not OK -- got the cutoff at 224 again "Persistent CRC or other ERROR"
+
+It's close. But actually this was still with USE_CKUPTY_C defined. When I
+undefined it, it was back to being totally broken. Start over. (Check the
+new cfmakeraw() code.)
+
+Tue 27 Mar 2007: Starting over. Back to ttpty.c. Let's verify, VERY
+CAREFULLY, that it really does work, using the most stressful of the four
+tests: sending the big (3.2768MB) binary test pattern from K95 into rz
+through ttpty, logging everything. ttpty definitely receives the big file
+smoothly with no errors or hiccups when I have it set to use the master side
+of the pty for i/o. The application program (Zmodem in this case) runs on
+the slave, and the network and/or control program communicates with the
+master. This implies that Zmodem controls the terminal modes of the slave,
+and ttpty should be concerned with those of the master. Doing it this way
+in ttpty confirms this.
+
+Fine. But if I tell ttpty to SEND a file with sz, nothing happens. Ditto
+with lsz. Select times out waiting for input from the pty. But if I
+manually tell K95 to RECEIVE /PROTOCOL:ZMODEM it works OK. Somehow sz's
+initial B000000 string is being swallowed somewhere, and it's waiting for
+a reply from the receiver. sigh... But "ttpty gkermit -s filename" works
+fine. What's the difference? It has nothing to do with stdout vs stderr;
+sz is not writing to stderr at all. Is it some timing thing between the
+forks? Aha. It's that I change the modes of the pty master in one fork
+while sz is already starting in the other fork.
+
+OK, good, now for the first time we have Kermit and Zmodem both able to
+upload and download a large worst-case binary test-pattern file... in
+remote mode. Now taking today's lessons and fitting them back into
+C-Kermit so I can try it local mode...
+
+Using G-Kermit as the external protocol, first in remote mode... All good:
+text/binary up/down. The "halting problem" is solved by SIGCHLD, which
+catches fork termination instantly and lets ttptycmd() know there is no more
+pty. Zmodem:
+
+ zst: OK
+ zsb: OK
+ zrt: OK
+ zrb: OK
+
+That's a first. Next, repeat in local mode, in which C-Kermit is the client
+and has made a Telnet connection to another host over a secure (Kerberos V)
+connection:
+
+ kst: OK zst: ...
+ ksb: OK
+ krt: OK
+ krb: OK
+
+It seems we can never end a day on a high note. Somehow I seem to have
+broken regular internal Kermit protocol transfers over encrypted connections
+-- the en/decryption engine loses sync. But they still work OK over a
+clear-text Telnet connection.
+
+Today's code in ~/80/dulce.tar (27 Mar 2007).
+
+Added makefile target solaris10g+openssl. Gathered all the standard CFLAGS
+for Solaris into cdcdeb.h so they don't have to be included in every single
+makefile target for Solaris. On local Solaris 10 host OpenSSL is in
+/opt/openssl-0.9.8e/. Tried the new makefile target, works OK. Also made
+solaris10+openssl for Sun CC, but couldn't test it because I can't find any
+Solaris 10 host that has Sun CC. Built with gcc at another site that has
+OpenSSL 0.9.8f-dev, all OK. ckcdeb.h, makefile, 24 Jun 2007.
+
+It occurs to me that Kermit transfers on secure connections might have been
+broken by the changes I made back in February to ttinl() for John Dunlap.
+Here, for the first time, we invoke myunrd() to push a byte back into the
+input queue, and there is also some funny business with "csave", which
+changed, and which an old comment notes that it has to be treated specially
+when encrypting. So it could be that the broken Kermit transfer has nothing
+to do with the work on external protocols, and that putting back the
+previous ttinl() will fix it. But now I can't seem to make a Kerberized
+connection from Panix to Panix, even though I can make one from Columbia to
+Panix. This means I have to build a Kerberized binary from the current
+source code on either Solaris or Mac OS X. Trying Solaris
+first... [~/solaris9k5/mk5.sh] This didn't work the first time due to
+undefined krb5_init_ets, which is referenced if MIT_CURRENT is not defined
+(it should be for Kerberos 5 1.05 and later and we have 1.42 here), tried
+again with -DMIT_CURRENT=1... Nope, that one totally blew up in ck_crp.c.
+Later, Jeff says krb5_init_ets is a no-op in Kerberos 1.4.x and later,
+so I added an #ifdef (NO_KRB5_INIT_ETS) for skipping it; now it builds and
+runs OK. ckuath.c, makefile, 9 Jul 2007.
+
+Meanwhile, using C-Kermit on Mac OS X, which makes the Kerberized connection
+just fine, but still has the problem transferring files over it. Packet log
+shows:
+
+ s-00-01-^A9 Sz/ @-#Y3~Z! z0___F"U1@A^M
+ r-00-01-^A9 Y~/ @-#Y3~^>J)0___J"U1@I
+ s-01-01-^A(!Fx.x)(V^M
+ r-xx-08-<timeout>
+ S-01-08-^A(!Fx.x)(V^M
+ r-xx-08-<timeout>
+ S-01-08-^A(!Fx.x)(V^M
+ r-xx-16-<timeout>
+
+Note that S packet is sent, received, and Ack'd OK. The F packet is sent but
+is never Ack'd. Tried this several times and noticed that it's just
+receiving that is screwed up, not sending. After ^C'ing out of the
+transfer, I can still type commands, and they are executed on the far end,
+but the results coming back are gibberish. Mon Jul 9 16:08:22 2007 (come
+back to this later... substitute Dev.27 ttinl for current one and see if
+the problem goes away, and if so, conditionalize the new code for clear-text
+connections).
+
+Built C-Kermit with Kerberos 5 on Solaris with a version of ckutio.c that
+uses the old ttinl() and transferred a file OK over a Kerberized connection.
+So now it's just a matter of reconciling the old and new ttinl. The easiest
+way to do this is to have new ttinl() chain to old ttinl() if the connection
+is encrypted, which is what I did and it works fine. At some point the two
+versions of ttinl() should be reconciled. ckutio.c, 12 Aug 2007.
+
+There was a function, islink(), used in only one place (ckuus6.c) that had
+the same name as a commonly used scalar variable, and it was missing a
+prototype. Changed its name to isalink() and added the prototype (Unix
+only), ckuus6.c, ckufio.c, ckcdeb.h. 12 Aug 2007.
+
+Revisiting the ASCII and BINARY top-level commands, which are supposed to
+be like in other FTP clients, but don't seem to have any effect. I added a
+new routine to the FTP module, doftpglobaltype(), that sets the global,
+sticky, permanent transfer mode (ASCII or BINARY) (TENEX could be added to
+if anybody asks). These commands (now that they work) are different from
+SET FTP TYPE { ASCII, BINARY }, which set the *default* transfer mode when
+automatic switching fails for a given file. ckuusr.c, ckcftp.c, 12 Aug 2007.
+ (notify: Matt <mlist@cmcflex.com>)
+
+Even though the code hasn't changed, suddenly we're getting:
+
+ "ckuusx.c", line 5682: warning: implicit function declaration: tgetent
+ "ckuusx.c", line 6183: warning: implicit function declaration: tgetstr
+ "ckuusx.c", line 6262: warning: implicit function declaration: tputs
+ "ckuusx.c", line 6266: warning: implicit function declaration: tgoto
+
+in ckuusx.c on Solaris 9. <curses.h> is still in /usr/include, dated 2002.
+A quick search shows the missing functions are hiding in <term.h>, which
+until now was included only in Linux. Added a USE_TERM_H clause. No, that
+doesn't help, the prototypes are not selected at compile time; there are
+#ifdefs in that file that skip over these prototypes. I had to put them in
+the code under #ifdef BUG999..#endif (I could have used a longer name like
+#ifdef ADD_PROTOTYPES_FOR_CURSES_FUNCTIONS, but that would not be portable).
+ckuusx.c, 12 Aug 2007.
+
+Also:
+
+ "ckuusx.c", line 9232: warning: implicit function declaration: creat
+
+This is called in the IKSD database code, used for getting a lockfile.
+creat() is a Unixism in code that is supposed to be portable. But IKSD only
+runs on Unix and Windows, so I assume the Windows C library has a creat()
+function. Anyway, suddenly the Solaris header files seem to have blocked
+whatever path previously existed to the creat() prototype (which is in
+<fcntl.h>), so I added an #include in the appropriate spot. ckuusx.c,
+12 Aug 2007.
+
+Kermit functions for converting the number base -- \fradix(), \fhexify(),
+\unfhexify() -- did not work with big numbers; ckradix() was missed in the
+CK_OFF_T conversion. Fixed in ckclib.c, 12 Aug 2007.
+
+Updated the help text for ASCII, BINARY, and SET FTP TYPE to clarify the
+semantics. ckuus2.c, ckcftp.c, 12 Aug 2007.
+
+Error messages were printed upon failure to open any of the four log file,
+even with SET QUIET ON. Fixed in ckuus4.c, 12 Aug 2007.
+
+Built OK on NetBSD 1.3_RC3. Tried to build secure version but the libraries
+had disappeared. 13 Aug 2007.
+
+Built OK on Mac OS X 10.4.9. Tried the secure version, macosx10.4+krb5+ssl.
+Here we get the usual pile of "pointer targets in passing argument 1 of
+(function name) differ in signedness", regarding security functions, but it
+built OK. 13 Aug 2007.
+
+Reconciling the two ttinl's... On encrypted connections myread() returns
+encrypted bytes; ttinl() has to decrypt them; it wasn't doing this in the
+lookahead section so I fixed it. The new code works on both encrypted and
+clear-text connections. I removed the chaining to oldttinl(), and
+oldttinl() itself. ckutio.c, 13 Aug 2007.
+
+ (Wouldn't it make more sense and be more efficient and less confusing
+ for myfillbuf() to do the decrypting?)
+
+When C-Kermit uses Zmodem as an external protocol, it doesn't seem to scan
+files before sending them to set text or binary mode appropriately. It's
+that external protocols bypass Kermit's whole "get next file" mechanism; the
+(possibly wild) filespec is simply passed to the external protocol program.
+Changing this would be a very big deal. But if only one file is being sent
+(the filespec is not wild) it's easy enough to check. I added this to the
+external protocols section of the protocol module. It can be overridden in
+any of the regular ways (/TEXT or /BINARY switch on SEND command, SET
+PATTERNS OFF, SET TRANSFER MODE MANUAL, etc). ckcpro.w, 13 Aug 2007.
+
+[FTP SEND /RECURSIVE]
+Peter Crowley reported a problem with FTP recursive uploads getting the
+directory tree wrong when the previous pathname was a left substring of the
+new pathname (e.g. foo/bar/ and foo/bar2/). The logic did not handle this
+case and created the bar2 directory as a subdirectory of bar, rather than as
+a parallel directory. Fixed in syncdir() and tested with various edge cases.
+ckcftp.c 14 Aug 2007.
+
+ notify <peter.crowley@alumni.utexas.net>
+
+Added CD messages to FTP BRIEF display to track the ups and downs of
+recursive uploads. ckcftp.c, 14 Aug 2007.
+
+The OUTPUT command gave a misleading error message ("Connection to xxx not
+open") when used on a serial port that was, indeed, open but was not
+presenting the Carrier signal, when CARRIER-WATCH was not OFF. Added a new
+message for this, and some others. ckuus5.c, 14 Aug 2007.
+
+Sending from the command line, e.g. kermit -s foo, did not give an
+informative error message if the file could not be found or opened. Fixed
+in ckuusy.c, 14 Aug 2007.
+
+OK, back to ttptycmd.... It seems that back on March 27th, I got everything
+working but I thought that there was still something wrong with it because
+an unrelated problem so I put it aside. The version of ttpty.c from that
+date worked OK, and it looks like I updated ckutio.c from it, but that
+version of ckutio.c was put aside. Since then I have been working on the
+ckutio.c version that was NOT put aside and so now I have to reconcile the
+two:
+
+ ~/80/ttypty/20070327/ckutio.c
+ ~/80/ckutio.c
+
+As a first cut I did this simply by replacing the contents of the #ifdef
+CK_REDIR section of the latter with that of the former. Of course in
+Solaris this comes up with openpty() implicitly declared at compile time and
+unresolved at link time. So the first task is to get HAVE_OPENPTY defined
+for platforms that have it and have the others use the ttruncmd(). For
+starters I put an #ifdef block in ckcdeb.h that defines HAVE_OPENPTY for
+Linux, FreeBSD, NetBSD, OpenBSD, and Mac OS X. Ones that don't have
+openpty() include AIX, HP-UX, and Solaris. Others like SCO I don't know but
+I doubt it. The real solution is to get the ckupty.c module to work but one
+thing at a time... This version is supposed work with secure builds on the
+openpty() platforms, and on the others like Solaris, if an external protocol
+is attempted on a secure (encrypted) connection, an error message is
+printed and the command fails. ckutio.c, 14 Aug 2007.
+
+How to test? Apparently I did all my testing on Panix before, and that's
+where all my Zmodem builds are, but now when I build a Kerberized version
+(which works if I do it on the right pool host), it won't make a local
+connection, and there is no other place I can connect to that has a
+Kerberized Telnet server. I can, however, connect to Panix from here, using
+the same code, but on Mac OS X...
+
+Slight detour: Got access to AIX again (5.3.0.0). Picky compiler, some
+things needed fixing.... Also it says "1506-507 (W) No licenses available.
+Contact your program supplier to add additional users. Compilation will
+proceed shortly" and of course it goes kind of slow. For some reason, I
+can't do streaming transfers into AIX over a local network (to its SSH
+server), but windowed transfers are OK. Anyway, noting that we've been
+using the same basic makefile target since AIX 4.2, changing nothing but the
+version herald, I made a new target, simply "aix", that picks up the AIX
+version automatically and sets the herald from it. Ditto for aix+openssl,
+but on this host requires setting SSLINC and SSLLIB to /opt/ssl/include and
+/opt/ssl/lib. Also the make program here was extremely sensitive to spacing
+so I had to make some minor edits to get the link step to work for the SSL
+version. ckuusy.c, makefile, 14-15 Aug 2007.
+
+Got rid of the special Panix secure NetBSD target, replaced it with a
+regular one, which is invoked in the normal way by defining K5INC and K5LIB
+to point to to where the stuff is hidden. Cleaned up and modernized the
+comments in the makefile a bit. makefile 15 Aug 2007.
+
+Changed some data types and added some casts to ckctel.c to do away with
+tons of "pointer targets in passing argument 1 of 'xxx' differ in signedness"
+warnings. 15 Aug 2007.
+
+Set up Mac OS X as the testbed for ttptycmd(), with Panix as the remote
+partner over a Kerberos 5 connection. The first test is to send a 300K
+text file with gkermit as the external protocol. It worked fine, and the
+debug log showed all the right components were active (namely encryption and
+ttptycmd) [kermit/zmodem send/receive text/binary]:
+
+ Kermit Zmodem
+ kst OK zst OK
+ ksb OK zsb OK
+ krt OK zrt OK
+ krb OK zrb Failed "rz: Persistent CRC or other ERROR"
+
+We've seen this before. The problem is 0xff, Telnet IAC, as I proved to
+myself by constructing a 3MB file that contained every byte but 0xff in every
+mixture and order and transferring it successfully over the same connection.
+Presumably the Telnet server is doubling IACs, whereas of course rz is not
+undoubling, thus the CRC error. This is progress. 15 Aug 2007.
+
+Log shows that indeed every IAC in the source file arrives doubled. Adding
+code to remove the first IAC of every adjacent pair, a small test file with
+different-length runs of IACs transfers OK. The 3MB all.bin file does not.
+
+Starting over... I can receive a big text file with Zmodem OK. The 3.2MB
+binary test pattern that contains no IACs failed after 1.8MB, but the part
+that it transferred was OK. A second try, almost the whole thing arrived,
+it stopped just 584 bytes short of the end. Could be that file size is a
+separate problem. Making a new copy exactly 1MB long... Well, that's
+interesting, this one too stopped just short of the end. And again, the
+same thing. When connecting back to the host, the last Zmodem packet can
+be seen on the screen; it's as if the local Zmodem exited before reading
+the last packet... But OK, if I change the options on the remote sz
+sender to use small blocks, etc, then it works.
+
+Now, changing from the 1MB no-IAC-binary test pattern, to the 1MB all-values
+test pattern, we fail after 81K. But the part that was transferred is
+correct. Second try, same thing, but 57K. Third: 40K. Each time, upon
+connecting back, the session is completely dead.
+
+IF I HAVE TO undouble IACs for incoming files, don't I have to double them
+going out? To send a block to net we just call ttol(), but ttol() doesn't
+do any doubling (because Kermit protocol always quotes 0xff). To see what
+happens, I changed the ttol() call to ttoc() in a loop that doubles IACs. I
+tested this by sending the full 3.2MB test pattern, which worked fine.
+
+For receiving, it's slow but it works OK with files that don't contain IACs
+(my concern was that IACs might appear in outbound files or in Zmodem
+protocol messages). It receives the 1MB no-IAC test pattern, so there are
+no problems with protocol or timing. But the full test pattern always gets
+cut off, but at different points, as before, with the remote session dead.
+Changing the Zmodem receiver from rz to lrz on the local end (since the
+sender on the remote end is lsz) does not change the behavior.
+
+Anyway, I went back and replaced the byte loop with something more
+efficient, and it goes about 20 times faster. But this doesn't help either,
+it only makes it fail faster. But aha, what if a doubled IAC is broken
+across successive pty reads -- we have to make the "previous character"
+memory persistent. Well, that was a good insight, but it still didn't fix
+it. The log shows the IAC handling code is working fine.
+
+What does sz say? Capturing its stderr to a file... "Retry 1: Got ZCAN".
+Next time: "Retry 1: Got TIMEOUT". Next time: Got ZCAN.
+
+Trying different Zmodem options... apparently I don't need to use short
+blocks. But I do need to use -e, probably because of Telnet NVT treatment
+of carriage return; without -e, there is a "persistent CRC error". -O
+disables timeouts, but this makes no difference.
+
+OK, we still have two Big Problems:
+
+ 1. When a long file has no IACs, the final < 1K of the file is not received.
+ 2. When a long file has IACs, the transfer generally stops very early.
+
+Problem 1: the transfer consistently fails less than 1K from the end of the
+file. Upon CONNECT back to the host, a big Zmodem packet is sitting there
+waiting to be read, which means ttptycmd()'s copy of rz is terminating
+early. Can we catch it in the debug log? Doing this takes forever and
+writes a GB to the disk... And then the problem doesn't happen. Also, I
+can receive a HUGE text file almost instantly with no errors at all.
+
+Switching to lrz on the receiving end, now I see the error messages, about
+300 lines like this:
+
+ Retry 0: Garbage count exceeded
+ Bytes received: 872352/1000000 BPS:85464 ETA 00:01 Retry 0: Bad CRC
+ Bytes received: 892448/1000000 BPS:86690 ETA 00:01 Retry 0: Bad CRC
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Retry 0: Got ERROR
+ Bytes received: 898336/1000000 BPS:84293 ETA 00:01 Retry 0: Bad CRC
+ Retry 0: Garbage count exceeded
+ Retry 0: Garbage count exceeded
+ Bytes received: 900384/1000000 BPS:83751 ETA 00:01 Bad escape sequence
+ 2fRe
+ try 0: Bad data subpacket
+ Bytes received: 941472/1000000 BPS:86191 ETA 00:00 Retry 0: Bad CRC
+ Retry 0: Garbage count exceeded
+
+Even when it succeeds, it gets these. But if I receive a text file, no
+matter how big, no errors or retries or timeouts at all. So it appears that
+there is only one problem: a big-time lack of transparency regarding 8-bit
+and/or control characters. The odd thing is, it's not that the characters
+can't get through -- they all can -- but they seem to cause transitory
+blockages. 16 Aug 2007.
+
+Cleaned up the remaining pointer signedness warnings in ckutio.c, but this
+was a mistake, it broke Kerberos connections completely. Undid the changes.
+ckutio.c, 17 Aug 2007.
+
+Changed all return() in the fork()==0 section of ttptycmd() to exit().
+ckutio.c, 17 Aug 2007.
+
+Tried explicitly setting the slave pty to rawmode. Makes no difference.
+Tried using the Mac OS X (curses) raw() function, and also system("stty
+raw"); still no difference. Tried doing all of these in different
+combinations and orders. I found one combination that cuts the errors about
+in half, and the transfer of the no-IAC test pattern almost always succeeds
+(but it's slow). Anyway, it doesn't help much with the test pattern that
+contains IACs. Well, the code is more solid than it was before but
+functionally we have not advanced much if we can't download a binary file
+with Zmodem! On the other hand, we can upload them, and we can transfer
+text files in both directions, which is an improvement over the previous
+situation, in which the entire session would hang due to loss of
+synchronization of the encryption stream.
+
+Tried adding -funsigned-char to CFLAGS of Mac OS X target. It does not
+make the "signedness" warnings go away and it doesn't change the runtime
+symptoms.
+
+I tried a simpler version of pty_make_raw(), the one from Serg Iakovlev, but
+it was a total failure. That's encouraging though, because it indicates
+that pty_make_raw() is the right place to be working.
+
+Then I made pty_make_raw() set or unset every single terminal flag
+explicitly. This made no difference, but didn't hurt anything either.
+
+Then I made pty_make_raw() explicitly set all the c_cc[] characters to 0
+(but left c_cc[VMIN] as 1). This made no difference either.
+
+I checked pty_make_raw() against ttpkt() and the only difference I found in
+the terminal flags is that ttpkt() sets IGNPAR thinking it means "ignore
+parity errors" when really it means "discard any character that has a parity
+error" (at least according to Iakovlev) -- exactly the opposite. But I
+tried it both ways, no difference. 17 Aug 2007.
+
+I noticed that even Zmodem text receives can fail. They don't get any
+errors, they just get cut off shortly before the end. (But usually they
+succeed, and fast too, like 500K cps).
+
+What if I don't call pty_make_raw() at all on the slave pty?
+
+zrt: EESSSSSSSS: 80% good (E = stopped just before end but no other errors)
+
+zrb no-IAC test pattern, short blocks:
+ 1. S/5 (success with 5 screens of errors.
+ 2. S/7
+ 3. S/7
+ 4. S/6
+ 5. E/7 (failed just before end)
+ 6. S/7
+ 7. S/6
+ 8. S/6
+ 9. S/6
+10. S/4
+
+So, lots of errors, but it recovered 90% of the time.
+Next, same thing, but without requesting short blocks:
+
+ 1. E/5
+ 2. S/5
+ 3. E/4
+ 4. S/5
+ 5. S/5
+ 6. S/5
+ 7. X/0 (hard failure right away: "Got ZCAN"
+ 8. S/5
+ 9. S/5
+10. S/5
+
+So it doesn't look like short blocks make that much difference. Now what if
+I turn off prefixing? Bad CRC, fails immediately every time. Putting back
+pty_make_raw(slave), it still fails hard.
+
+Tried a new strategy with pty_make_raw(): rather than modify existing flags,
+I set all flags to 0, and then turn on only those few that we need like CS8.
+Now we get only 2.5 screens of errors instead 4-7 and the transfer rate is
+higher for binary files (all of the previous ones were under 100K CPS, while
+for text files it was 400-500K CPS):
+
+ 1. S/2 195669 CPS
+ 2. S/2 194720
+ 3. E/3
+ 4. S/2 192550
+ 5. S/3 192325
+ 6. S/3 145066
+ 7. S/2 200689
+ 8. S/3 188948
+ 9. S/2 209461
+10. S/3 181991
+
+I noticed that there was no TIOCSTTY ioctl in the pty/fork setup sequence,
+which is recommended somewhere, so I tried that and it was a disaster; the
+entire session hung. I took it back out. 18 Aug 2007.
+
+Tried some transfers over a clear-text (not encrypted) connection with the
+same results: smooth, fast transfer of a big text file (400K cps); rocky but
+successful transfer of the no-IAC binary pattern file (135K cps). Switching
+back to ttruncmd(), the same binary file is received at 1.5M cps, and the
+no-IAC binary file totally fails after too many "Bad CRC"s; and we already
+know that any file that contains IACs will fail. One might say that
+ttptycmd() is better in every respect than ttruncmd() except in speed
+(when it works).
+
+Let's see if ttyptycmd still works in remote mode (to local K95):
+ . sz / text works, but slowly.
+ . lsz / text works but some weird errors are reported.
+ . lsz / binary / no IAC doesn't work at all (CRC-32 mismatch for a header;
+ Unexpected control character ignored: 13, etc).
+ . sz / binary / no IAC works OK but slow.
+ . sz / binary / full test pattern with IAC works OK but slow.
+ . Sending text into rz fails completely.
+
+What about ttruncmd() in remote mode?
+ . send /text works, fast.
+ . send /binary works, fast.
+ . receive /text works, not so fast but not bad.
+ . receive /binary works, not so fast but not bad.
+
+So we use ttruncmd() for remote mode, and we use it for local mode
+serial-port and modem connections, and we use ttptycmd() on network
+connections because (a) they might be encrypted, and (b) even if they are
+not, they use some protocol that we have to handle, e.g. Telnet, Rlogin.
+19 Aug 2007.
+
+Discovered that Sending binary files no longer works. Text is OK, binary
+transfers don't even start. This happens on both encrypted and clear-text
+connections. ttptycmd() is being used in both cases. But oddly enough,
+receiving binary still works as before. What did I break, and when?
+Oh, it was just the script, when I changed it from using sz to lsz. Putting
+it back to sz makes it work, even with the full 3.2MB binary pattern with
+IACs.
+
+I backed off the changes I made to ckctel.c to suppress some warnings, in
+view of the fact that similar changes to ckutio.c broke things so badly.
+19 Aug 2007.
+
+If sz is not given the -e flag, it sends control characters bare, except ^P,
+^Q, ^S, and ^X. ^X is the control prefix, so ^A is sent ^X followed by A.
+With -e, all C0 control chars are prefixed, but with ^X, which is, of
+course, a control character. Interestingly, the C1 analogs of ^P, ^Q, ^S
+(but not ^X and, unfortunately, not IAC) are also prefixed. -e makes no
+difference for 8-bit characters.
+
+If we have a Telnet connection and the server is in ASCII (NVT) mode, CR is
+always followed by LF or NUL. Well, it seems the server is putting us
+(Kermit) in binary mode in this case, but staying in ASCII mode itself.
+Added code to handle NVT byte stuffing and unstuffing in each direction
+independently, according to the TRANSMIT_BINARY state in that direction. I
+made a file containing just the bytes 0-31 and 127 and 128-159 and 255 (66
+bytes all together) and sending it from the host to C-Kermit, the local log
+shows that every control character was received correctly and all TELNET
+conversions were done right -- NUL removed after CR (and only after CR); IAC
+removed after IAC (and only after an IAC meant as a quote). For the first
+time, I can receive the 1MB all-values test pattern, but there are still
+tons of (correctable) CRC errors, so the transfer rate is really awful, like
+about 5% of what we get with a text file (25Kcps instead of 500).
+
+Further experimentation shows that the fundamental transparency problem is
+fixed; we can receive short files (say, 1K or less) containing absolutely
+any byte values in any combination with no errors at all. But once the file
+size reaches (say) 10K, we get CRC errors, like one every 2 or 3K of data.
+These are not deterministic. In successive transfers of the same file, they
+come in different spots. It's tempting to blame pty buffer overruns, but
+then text files would show the same behavior. When a binary file size
+exceeds, say, 1MB, the chances of successful completion go way down,
+independent of whether my external protocol is rz or lrz. I like lrz better
+because the error reports come out on the screen as the transfer is going
+on. Trying to download a real-world binary file -- a 2.2MB C-Kermit
+executable -- I get 4500 error messages but the transfer eventually succeeds,
+with an effective throughput of 21Kcps.
+
+Actually it turns out that "sz -a somebigtextfile" (2.2MB) also gets a lot
+of CRC errors. The -e flag (escape all control characters) makes the same
+big text file transfer with few or no errors. It's not sure-fire.
+Sometimes no errors, sometimes one or two, and sometimes a fatal error that
+kills the transfer.
+
+With binary files... a 32K binary file seems to make it every time. 40K
+fails about 50% of the time. 48K fails 60% and every time it fails, it has
+created a partial file of exactly 32K (32768 bytes). 96K fails 9 out of 10
+times, when it fails, the partial file is always 0 bytes, or 32768, or
+65536, but that just means that rz's file output buffer is 32K.
+
+Why, then, do binary files cause trouble if it is not a solid transparency
+problem? If a certain file can get through once, why can't it get through
+every time? When a character arrives at the pty, the pty driver probably
+takes a different path through its code, checking the terminal flags that
+would affect that character. I tried making Kermit's network read buffers
+very small but, surprisingly, this made things worse. I also tried making
+them very much bigger, which didn't help either. 24K still seems to be the
+right size.
+
+So, is it that some characters take longer to process than others? So long
+that data is lost due to lack of flow control between TCP and the pty? One
+way to test this theory is to slow Zmodem down. I tried "-l 32" which,
+according to the man page, tells sz to "wait for the receiver to acknowledge
+correct data every N (32 <= N <= 1024) characters. This may be used to
+avoid network over-run when XOFF flow control is lacking." Makes no
+difference. I also tried the -w (Window) switch, ditto. In fact there are
+all sorts of options to set the "window size", "packet length", "block
+size", and "frame length", but with no explanation of what these mean or how
+they are related. If I crank everything down to minimum value:
+
+ lsz q -L 32 -l 32 -w 1
+
+I get 50% success with the 96K file instead of 10%. Adding -e, oddly
+enough, made it worse. I also tried setting the environment variable
+ZNULLS to different numbers like 512, no help there either.
+
+I tried making the read-from-net-write-to-pty buffer small (1K) but leaving
+the pty-to-net one big. This improves chances of success, but it's
+intolerably slow (3Kcps when the connection is capable of 500K).
+
+I also changed the write-to-pty operation from a single write() call of
+possibly many K characters to a byte loop, one write() per byte. Same
+result: success (but still about 300 recoverable errors), throughput 3Kcps.
+20 Aug 2007.
+
+With ttptycmd() configured to write to the pty in a byte loop, it is
+possible to delay each write. Adding a 10msec delay per character results
+in a transfer that runs at about 20 cps and (for the 96K test file) would
+take about 80 minutes to complete. And yet it still gets just as many
+errors. So it's not a matter of timing either. The errors come, on
+average, every file 388 bytes, but not at regular intervals.
+
+I tried the TIOCREMOTE ioctl on the pty master, as discussed somewhat
+obliquely in the Mac OS X "man pty" page; "This mode causes input to the
+pseudo terminal to be flow controlled and not input edited (regardless of
+the terminal mode)" -- sounds like just the ticket but it made no
+difference. Actually, looking at a man page on another OS (Solaris), it
+says this is only for lines of text, EOLs are supplied, so that would mess
+up the protocol. So remember: don't use this.
+
+Tried without O_NDELAY; the behavior was the same but the speed was much
+slower.
+
+Tried switching back to the ckupty.c routines on Mac OS X and found that it
+works now the same as with openpty(), except that I seem to get more getty
+babble at the end. But this means I can run some tests on Solaris. I moved
+the entire test environment from Mac OS X 10.4.9 to Solaris 9. But it
+doesn't work at all.
+
+Trying to figure out the ckupty.c modules again.
+ . do_pty() calls pty_getpty() which returns in arg1 the fd of the pty master.
+ . Then it creates a pipe as a way to tell when the child dies
+ . Then it creates a fork:
+ - The parent does a blocking read from the pipe
+ - The child calls getptyslave() to get the pty slave
+ and writes one byte to the pipe
+ and then execs the command it's supposed to run
+Note that the file descriptor of the slave is known only to the lower fork.
+Therefore the lower fork is the one that has to set all the tty modes, etc.
+I took care of all that but the ckupty.c method doesn't work at all on
+Solaris. But it works "fine" on Mac OS X (the 32K all-bytes test file
+transfers instantly with no errors, but the 96K one errors out).
+
+The problem on Solaris is that pty_make_raw() fails on the masterfd (but not
+on the slavefd) with errno 25 "ioctl inappropriate for device". It doesn't
+matter whether I do it in ckupty.c or ckutio.c. I found a web page on
+kde.org that says Solaris does not allow tcget/setattr() on a pty master.
+But the Sun "knowledge base" is not open to the public. Well, presumably
+changes made to the slave are reflected in the master (comments in Solaris
+telnetd seem to confirm this...) Let's come back to Solaris later.
+
+Moving to a Linux with lrzsz installed... Built a Kerberos 5 version with
+USE_CKUPTY_C. Like on Mac OS X, it transfers short files OK and chokes on
+longer ones. Switched to openpty(), it behaves the same. So the problems
+on Mac OS X are evidently not OS-specific, which is good I guess, since that
+means finding the way around them will apply to more than one platform.
+21 Aug 2007.
+
+Look into TIOCSCTTY again. On System V based OS's, opening a pty acquires a
+controlling terminal automatically. On BSD-based OS's, no; you have to use
+the TIOCSCTTY on the slave file descriptor to give it one. I'm not sure why
+a controlling terminal would be needed, except that without one, the virtual
+device "/dev/tty" does not exist for the process that runs on the pty, and
+maybe the application that runs there (e.g. rzsz) checks for it. On the
+downside, having a controlling terminal opens the process up to terminal
+interrupts like SIGINT and SIGQUIT. Until now I have not been using this
+ioctl(). Results (in Linux):
+
+ With TIOCSCTTY: 96K all-bytes test: 11 screens of errors, then success
+ Without TIOCSCTTY: exactly the same.
+
+Tried the same thing with TIOCNOTTY instead of TIOCSCTTY, with exactly the
+same results (no effect whatsoever).
+
+There has to be a way to make this work, because Zmodem works through
+telnetd, which basically the same thing as ttptycmd(): a relay between the
+network and a pty. ttptycmd() is like telnetd backwards. Modern telnetds
+are not much help; they don't access ptys or the network directly, they go
+through "mux" devices so I can't see what they're doing to get transparency
+and flow control. An old BSD telnetd uses packet mode but that would be a
+big deal...
+
+I tried ignoring various signals like SIGTTOU and SITSTP, since some Telnet
+clients do this. No effect, no difference. Anyway, in Linux the transfers
+almost always finish OK despite the many errors. There is just some trick
+I'm missing to make the pty accept a stream of arbitrary bytes without
+hiccuping.
+
+What about Solaris, which uses ckupty.c? In streams-based OS's, where line
+disciplines and whatnot are pushed on top of the pty, it looks like the pty
+module saves the file descriptor of the "bare" slave pty (as 'spty') before
+pushing things onto it, and then later uses spty rather than the regular
+slave pty file descriptor when getting/setting terminal modes. I'm not sure
+what this is all about but it's definitely SysVish... It happens if
+STREAMSPTY is defined, but I noticed that STREAMSPTY is never defined
+anywhere. I tried defining it so we take an entirely different path through
+the code. It made absolutely no difference.
+
+Then I noticed that HAVE_STREAMS is not defined for Solaris either. Tried
+defining it, but the session didn't work at all, no i/o. Removing the
+HAVE_STREAMS definition but keeping the STREAMSPTY defined, I rebuilt and
+tried "set host /connect /pty emacs". I got an EMACS screen but could not
+type anything into it, which means that STREAMSPTY should not be defined
+either. Removed the definition and "set host /pty" works again. So what's
+the problem with ttptycmd()?
+
+In fact, ttptycmd() works on Solaris with Kermit as the external protocol,
+but not with Zmodem, not even with text files. So again, there is no
+fundamental problem with the code or the logic, it's Just A Matter Of
+Transparency to control and/or 8-bit characters -- some trick I don't know
+about.
+
+Looking at the Solaris debug log... I see that ckupty.c is calling
+init_termbuf() to set the tty modes of the master, not the slave, and
+set_termbuf() to set them, but you can't do that in Solaris, error 25. This
+is in getptyslave(). Shouldn't getptyslave() be setting the tty modes of
+the slave, not the master? I changed it to do this, but like all other
+changes, it made no difference. I checked to make sure that after the change,
+"set host /pty /connect emacs" still worked and it did.
+
+And then what... I had some code to redirect stderr in ckupty.c that was
+not being executing due to a typo. When I fixed the typo, poof, Zmodem
+binary transfers started working, or working as well as they work in Linux
+and Mac OS X. It turns out that if I don't redirect stderr, sz and rz
+just don't work. But lsz and lrz do. But if I do redirect it, I don't see
+the progress messages from lsz/lrz. 22 Aug 2007.
+
+Built on HP-UX 11i v3 (B.11.31 U ia64) with optimizing compiler, got tons of
+picky warnings, but it finished and linked and runs OK. Many of the
+warnings were like this:
+
+ "ckucns.c", line 1606: warning #2068-D: integer conversion resulted in a
+ change of sign: tnopt[0] = (CHAR) IAC;
+
+IAC is defined as 255 in ckctel.h. If I define it as 0xff, I don't get the
+warnings. I changed the definitions of all the Telnet commands to be in hex
+notation rather than decimal. If cuts way down on the HP-UX warnings and
+doesn't seem to cause problems elsewhere. ckctel.h, 23 Aug 2007.
+
+Now it looks like Solaris is working but then it hangs at the end. It
+appears as if the ckupty.c module is blocking SIGCHLD. Debug log shows that
+when the transfer is complete, we received IAC DM (Telnet Data Mark) after
+sz's last gasp and before the shell prompt is printed. But calling
+tn_doop() in this case is a mistake because we are reading the number of
+bytes that we know are available in a counted loop, but tn_doop() would
+consume an unknown number of bytes and we would never know when to exit the
+loop. Anyway, C-Kermit doesn't do anything with DM. Skipping over
+tn_doop() (and not writing out the Telnet command bytes) fixes the hanging
+condition at the end, even though SIGCHLD is never raised. ckutio.c,
+23 Aug 2007.
+
+Some tests, Solaris to NetBSD over K5.
+zst sends ascii.txt, a 2.36MB ascii text file (Kcps / Errors).
+zrt receives the same file:
+
+ zst 587/0 526/0 542/0 434/0 423/0
+ zrt 827/0 800/0 847/0 FAIL 610/0
+
+So text is good. Binary not so good. Here we transfer the 1MB all-bytes
+pattern file. zrb receives it successfully, but with 1248 errors, at only
+15Kcps. Sending the same file out always fails:
+
+ Begin 20070823 16:32:07: SEND BINARY all2.bin [sz]
+ Sending: all2.bin
+ Bytes Sent: 5600/1000000 BPS:12446 ETA 01:19 FAILURE
+ End 20070823 16:32:13
+ Elapsed time: 6.617992999999842
+ cps = 151103.2121067556
+ lsz: caught signal 1; exiting
+
+Decided to move to Linux but found that something is screwed up in Linux
+C-Kermit with tilde expansion:
+
+ send ~/testfiles/all.bin
+
+doesn't expand at all (but it did yesterday!). The problem was in the
+ancient, ancient realuid/setuid handling code; real_uid() no longer works in
+Linux. I worked around this in whoami() by setting ruid to getuid() if
+real_uid() returned a negative number. Maybe dangerous, worry about it
+later. ckufio.c, 23 Aug 2007.
+
+ANYWAY... after fixing that, I tested zsb on Linux, and it's broken there
+too, using openpty(), so it's nothing to do with ckupty.c. After sending
+the first Zmodem data packet, it just hangs, nothing comes back. In text
+mode it gets farther, but then the same thing happens. Captured stderr from
+rz on the far end:
+
+ Bytes received: 608/1000000 BPS:21137 ETA 00:47 Retry 0: Bad CRC
+ Bytes received: 864/1000000 BPS:23540 ETA 00:42 Retry 0: Bad CRC
+ Bytes received: 1120/1000000 BPS:25003 ETA 00:39 Retry 0: Bad CRC
+ Bytes received: 5696/1000000 BPS:56988 ETA 00:17 Retry 0: Bad CRC
+ Bytes received: 9120/1000000 BPS:62227 ETA 00:15 Retry 0: Bad CRC
+ Bytes received: 9376/1000000 BPS:60766 ETA 00:16 Retry 0: Bad CRC
+ Bytes received: 9632/1000000 BPS:60361 ETA 00:16 Retry 0: Got TIMEOUT
+ Retry 0: Sender Canceled
+ Retry 0: Got ZCAN
+
+The local sz, however, doesn't give any error message. ZCAN means: "other
+end canceled session by sending 5 ^X's" (or user typed them). What actually
+happens is that ttptycmd()'s select() times out waiting for something from
+the Zmodem partner and ttptycmd() itself kills the sz fork with SIGHUP.
+When lsz receives SIGHUP it sends the ZCAN. So the real problem is that
+after some point we're not receiving anything.
+
+I changed the timeout from 4 seconds to 30 seconds and now I see it just
+stops for long periods of time and then resumes. The lrz log on the
+receiving end shows tons of timouts, CRC errors, and other errors. The
+local log shows that lsz wound up sending ZCAN (2 x (10 x ^H, 10 x ^X)).
+
+Moving on to another problem... Turns out Ctrl-C (SIGINT) is working right
+after all. Since I'm using my test scripts like kerbang scripts, Ctrl-C
+exits through trap(), as it should, closing the connection and cleaning up.
+If I start Kermit and tell it to TAKE the script, then Ctrl-C brings me back
+to the prompt with the connection still open (as it should). However, until
+now I haven't done anything about the fork or the ptys. Added code to
+trap() to kill the fork and close the master pty. ckuusx.c, 24 Aug 2007.
+
+Added code to try to break the deadlock. If select() times out, but we have
+stuff to write either to the pty or the net, try to do it anyway, even
+though select() did not say we could. But this doesn't help because when
+select() times out we don't have anything to write. The problem is that
+after receiving that last packet from the remote rz, the local lsz doesn't
+seem to do anything, as if the lower fork wasn't running (and to confirm
+this hypothesis, sometimes I noticed that when I Ctrl-C'd out of this, the
+transfer would take off again).
+
+Backing up and testing with gkermit rather than zmodem:
+
+ kst ripple.txt [824K] OK
+ kst ascii.txt [1359K] OK
+ krt ripple.txt -- FAILED
+
+It seems that we can't handle streaming. If I set up krt to disable
+streaming on receipt, it works OK.
+
+ krt ripple.txt [824K] OK
+ krb all2.bin [1000K] OK
+
+So here we have no trouble sending but big trouble receiving unless we
+disable streaming. Whereas with Zmodem we have trouble receiving.
+
+But this wasn't happening before, what changed? Using C-Kermit on the far
+end to receive the file with debug log on, I see that it is sending 4K data
+packet after 4K data packet, with the local gkermit silent, as expected.
+About midway through the transfer, the local Kermit sends an error packet
+"Transmission error on reliable link". Looking at G-Kermit's debug log...
+It receives the first five 4K data packets OK, but gets a CRC error on the
+fifth one, and sends the Error packet. So it has received a stream of
+20-some thousand bytes OK and then messes up. That number sounds a lot like
+ttptycmd()'s buffer size. I changed the buffer sizes to be different:
+
+ Read from pty and write to net: 4K
+ Read from net and write to pty: 1K
+
+This time it received the first 4K packet and failed on the second one.
+Then I increased the buffers to 98K each, expecting to receive lots more
+packets successfully but it bombed out on the 5th one. But that's good, it
+confirms there's no logic error in the buffer management. Just to make
+sure, though, let's set the buffer size smaller than the packet size and
+disable streaming. In this case we get 4 good data packets and a CRC error
+on the 5th one and so we request retransmission, and the next 8 times it
+arrives it gets a different CRC error, but the 9th copy is OK. Then the
+next packet comes and it gets a CRC error every time. And this is nothing
+but plain ASCII text.
+
+Switching to remote mode:
+
+ REMOTE=1 kk kst
+
+(after tricking myself because it was using ttruncmd() for this...) I see
+that nothing works at all. What did I break? 24 Aug 2007.
+
+Fixed ttptycmd() to restore console modes after a remote-mode transfer.
+ckutio.c, 25 Aug 2007.
+
+Noticed that error codes like ESRCH are not available in all modules.
+That's because of some complicated in #ifdefs in ckcdeb.h that wind up not
+always #including <errno.h>. But I notice that ckutio.c includes it
+unconditionally with no ill effects, and so does ckvfio.c. Does any version
+of Unix at all not have <errno.h>? Added a catch-all clause to ckcdeb.h to
+#include <errno.h> (in UNIX only) if, after the other clauses, ESRCH was
+still not defined. ckcdeb.h, 25 Aug 2007.
+
+Now back to debugging ttptycmd()... Remote-mode transfers with ttptycmd()
+were broken in two places, maybe as long as 2 weeks ago (this would have
+affected non-network transfers too, which I can't test any more).
+The logic was missing in a couple places for the non-network and/or
+non-Telnet and/or non-encrypting connections (if statements with no else
+parts). Fixed in ckutio.c, 25 Aug 2007.
+
+Testing remote mode:
+
+ kst OK zst OK
+ ksb OK zsb OK
+ krt OK zrt OK
+ krb OK zrb OK
+
+Functionally it all works but there are hitches with Zmodem as always.
+When sending to K95:
+
+ . If I send with lsz, there are hundreds of "Subpacket too long" errors,
+ and the transfer is very slow, but it succeeds.
+
+ . If I send with the 1994 Omen version of sz, transmission is instantaneous
+ and without errors, but then it hangs at the end.
+
+ . If I bypass C-Kermit and send direct from lsz or sz, both work fine.
+
+So clearly the ptys are getting in the way. The hanging at the end would be
+caused by the sz process closing before its last output reached the master
+pty. It would need to do some form of flushing and/or pausing at the end
+but there's nothing I can do about that; these programs were not designed to
+be used in this way. Anyway, it only seems to happen with files longer than
+100K.
+
+For local mode, testing in Solaris over our Kerberos 5 connection again:
+
+ gkermit lrzsz
+ kst OK zst FAIL
+ ksb OK zsb FAIL
+ krt OK zrt OK but with errors
+ krb OK zrb FAIL
+
+If I use Omen rzsz as the external protocol (e.g. with zst), it blocks
+redirection and it sends the file to my terminal, rather than over the
+connection. This would probably be because it finds out the device name of
+the job's controlling terminal and opens it, to prevent redirection. This
+is hard to prevent in Solaris because there is no TIOCSTTY ioctl().
+Supposedly the same thing is accomplished by closing and reopening the slave
+pty after doing setsid(). I added code to do this, but it made no
+difference. (If I use lsz instead of sz, it is indeed redirected, but jams
+up after about 15K.) ckupty.c, 27 Aug 2007.
+
+On Mac OS X with sz 3.73 1-30-03, however, the redirection works, so I
+assume it would also work in Linux, FreeBSD, NetBSD, etc, too. Doing the
+full test suite on Mac OS X:
+
+ gkermit lrzsz rzsz
+ kst OK zst FAIL (1) OK
+ ksb OK zsb FAIL (2) OK
+ krt OK zrt OK (3) OK for 100K file, fails for longer.
+ krb OK zrb FAIL (4) OK (1MB all-bytes test pattern)
+
+(1) 64K file OK every time; 100K file fails every time.
+(2) 10K file fails every time.
+(3) Succeeds with 800K file but gets a few recoverable errors.
+(4) Succeeds with 48K binary file with some errors, fails with longer ones.
+
+So actually it looks pretty good, it's just that lrzsz messes up. When
+sending with lsz if I include -L 512 it sends the 100K test file with no
+errors, but still chokes on longer ones.
+
+Testing on Mac OS X again, but this time over a clear-text Telnet connection:
+
+ gkermit lrzsz rzsz
+ kst OK zst FAIL(1) OK
+ ksb OK zsb FAIL(2) OK
+ krt OK zrt OK(3) OK
+ krb OK zrb FAIL(4) OK
+
+(1) Almost worked, finished 777K out of 824K without errors.
+(2) Got tons of errors, failed in first 30K out of 1000K.
+(3) OK for 100K file but fails for larger.
+(4) OK for 48K binary fail but fails for larger.
+
+Maybe see if we can do without the OPENPTY part.
+
+TOMORROW -- just clean up the code, add some SET / SHOW / HELP commands,
+document it, and move on.
+
+Note: In K95, SET WINDOW sets the Zmodem packet length, 32 - 1024, multiple
+of 64.
+
+SEE ~/80/external.txt
+
+Changed ftp port from int to unsigned int. ckcftp.c, 30 Aug 2007.
+
+Tried again to build KRB4/KRB5/SSL/TLS version for Solaris 9. Had to update
+the build procedure again, of course, because of new file and directory
+names, but ran into problems anyway because the
+cu-solaris9g+krb5+krb4+openssl+shadow+pam+zlib target was calling another
+target that did not know about the hardwired pathnames. Integrated the two
+targets and tried building again. It actually compiled ok (but with lots of
+warnings from the security modules), but failed at link time with
+krb5_init_ets not found; fixed that with an #ifdef NO_KRB5_INIT_ETS, now it
+builds OK but without the ftp client. Tried building it WITH the FTP and
+that was OK too, no changes needed except to the build procedure. 12 Feb
+2008, that is: C-Kermit 8.0.212 : 20080212.
+
+Tried to build with -DCK_SRP and -lsrp but:
+
+ hash_supported ckcftp.o
+ hash_getdescbyname ckcftp.o
+ hash_getdescbyid ckcftp.o
+ cipher_getdescbyname ckcftp.o
+ krypto_delete ckcftp.o
+ krypto_new ckcftp.o
+ cipher_supported ckcftp.o
+ krypto_msg_priv ckcftp.o
+ krypto_msg_safe ckcftp.o
+ hash_getlist ckcftp.o
+ cipher_getlist ckcftp.o
+ cipher_getdescbyid ckcftp.o
+
+Sent mail to Tom Wu and backed off for now. makefile, 14 Feb 2008.
+(Tom Wu never answered; seems like SRP is defunct.)
+
+The ".blah = xxx" form of variable assignment only worked for variables
+names of length 22 or less, noticed and fixed by Wolfram Sang. ckucmd.c,
+5 Mar 2008.
+
+In "set host /pty ssh ..." connections, the INPUT command suddenly stopped
+working. This is in Solaris 9. It happens with all 8.0.* versions of
+C-Kermit, so it's nothing to do with ttptycmd(). Added some debug()
+statements but they don't show anything. Turns out there wasn't a problem
+after all. Wed Mar 26 16:04:53 2008
+
+Changed cmifi() to not print "?No files match" (or whatever) if SET QUIET ON.
+ckucmd.c, 26 Mar 2008.
+
+Added \v(remoteip) for the IP address of the host we're connected to,
+and \v(inmessage) for INPUT status messages corresponding to \v(instatus).
+ckuusr.h, ckcmai.c, ckuus[24].c, 26 Mar 2008.
+
+Made \fkeywordval() strip braces/quotes from the right-hand side so we can
+handle things like:
+
+ password="stringwithspaceatend "
+
+ckuus4.c, 6 Aug 2008.
+
+Added invisible PUTENV command for UNIX only. Value should not be enclosed
+in doublequotes. Requires lge \v(buildid) 20080826. ckuusr.[ch], 26 Aug 2008.
+
+Added SET VARIABLE-EVALUATION { RECURSIVE, SIMPLE }. This is highly
+experimental, but also highly desirable if it works out. SIMPLE inhibits
+the default recursive method of evaluating \%x and \&x[] variables, which
+is, quite frankly, nuts and makes programming in Kermit at best
+counterintuitive. I made an exception in the case of array subscripts,
+because changing how they are evaluated could break a lot of scripts, and
+anyway there should never be any harm in evaluating them recursively because
+their final value is always (or should be) numeric, not some string that
+might contain backslashes. The SET VAR setting is on the stack, just like
+SET QUIET (it follows the quiet/xquiet code in ckuus[356].c), so macros or
+command files that change it can't break the script that invokes them.
+Added \frecurse() to force recursive evaluation of a \%x or \&x[] variable
+regardless of the VARIABLE-EVALUATION setting. Added \v(vareval) to allow
+programmatic setting to current setting. Tested on Solaris 9 but should be
+totally portable. ckuusr.[ch], ckuus[356].c, 11 Sep 2008.
+
+From G�nter Knauf: 64-bit builds were failing on SuSE Linux because
+libresolv and libcrypt were in lib64 rather than lib; updated the tests in
+the linux makefile target to find them. makefile, 12 Jan 2009.
+
+Tried building on Red Hat Enterprise Linux Server release 5.3 64-bit.
+There is no curses or ncurses. "make linuxnc" compiled OK but collapsed at
+link time looking for crypt(), res_search(), and dn_expand(). Turned out
+the linuxnc (and linuxc) targets needed the same treatment as the Linux one
+for 64-bit Linuxes. makefile, 3 Mar 2009.
+
+Consolidated the linux targets so we no longer need three separate ones for
+curses, ncurses, and no curses. "make linux" works ok on computers with and
+without (n)curses. "make linux+ssl", ditto. "linux+krb5+ssl builds OK but
+needs -DNO_KRB5_INIT_ETS". Makefile, 3 Mar 2009.
+
+Fixed copyright date announced in herald, ckuus5.c, 3 Mar 2009.
+
+Patch from Seth Theriault to avoid deprecation warning for utmp references
+in ckufio.c in Mac OS X 10.5 (later, this became a consolidated makefile
+target that works automatically for at least Mac OS X 10.3.9 through
+10.5.6). makefile, ckufio.c, 28 April 2009.
+
+zshcmd() (the function used by RUN and ! to run external commands) was not
+falling back as expected in Linux RHEL4/5 if SHELL was not defined in the
+environment. Also in all Unix versions, there was no indication if a RUN/!
+command failed (other than the return code) because the specified shell
+didn't exist or was not executable (e.g. the SHELL environment variable was
+misdefined). Now it prints the name of the offending shell and the reason
+it couldn't be executed (Not found, Permission denied, etc). ckufio.c,
+28 April 2009.
+
+There is no easy way to get the last field of string; for example, the
+extension from a filename, which might have any number of fields. In
+general we want to be able to get "word number n" counting from the right;
+\fword() lacks this ability. Now if you give it a negative word number,
+that says to count from the right; for example \fword(one two three four
+five, -2) returns "four". ckclib.c, ckuusr.c, 14 May 2009.
+
+Fixed a typo in the aix51+openssl (SSLLIBS should have been SSLLIB).
+From Jason Lehr. makefile, 27 May 2009.
+
+Updated the linux+openssl+zlib+shadow+pam target to chain to the new main
+Linux target. A bunch of other ones remain un-updated. makefile, 12 Jun 2009.
+
+Updates to the new Mac OS X 10.5 target from Seth Theriault (which is
+supposed to work on all Mac OS 10-point-anything) to avoid warnings
+that came up on on Mac OS 10.4.11/Intel. Once this one is proven we should
+be able to remove/consolidate lots of other ones. makefile, 12 Jun 2009.
+
+C-Kermit disables SSL with the message "?OpenSSL libraries do not match
+required version." if the version of OpenSSL that Kermit was built with is
+not exactly the same as the version that is loaded dynamically at runtime.
+This is actually the proper behavior, since APIs are not guaranteed not to
+change between OpenSSL versions prior to 1.0.0. Made the error message more
+informative. ck_ssl.c, 26 Aug 2009, and again 28 Aug 2009.
+
+AIX 6.1 is out, it is really just a new name for AIX 5.4. Added makefile
+targets, plus for the first I made AIX 4.2 and later figure out its version
+number in the makefile target so we don't have to keep adding new -DAIXnn
+sections to the code, and also get its hardware name (e.g. "powerpc") from
+uname at make time, rather than hardwiring "rs6000" as I did before.
+Consolidated all AIX 4.2 and later targets so now just "make aix" or "make
+aix+ssl" can be used. Except not the gcc ones as they have some quirks so
+I'd rather not disturb them. Tested this on AIX 5.3.
+makefile, 28 Aug 2009.
+
+From Kinjal Shah, a correction to the Linux makefile entry that allows it
+find the 64-bit curses or ncurses library. makefile, 29 Aug 2009.
+
+Renamed aix4[23]: to oldaix4[23]: in makefile to fix the warning messages
+I didn't notice before. I didn't want to remove them because they have
+some special things that might still be needed, if anybody still has these
+AIX versions. makefile, 29 Aug 2009.
+
+Built on RHEL 5.3 64-bit, regular and with OpenSSL 0.9.8e. 31 Aug 2009.
+
+Built on NetBSD 5.0.1/i386, regular and with OpenSSL 0.9.9-dev, 1 Sep 2009.
+
+Changed SSL message to mention LD_LIBRARY_PATH (Solaris), SHLIB_PATH (HP-UX),
+LIBPATH (AIX), or LD_LIBRARY_PATH (Linux). ck_ssl.c, 3 Sep 2009
+
+Noticed that "make linux+openssl" fails to include -lutil a link time, which
+it needs for openpty(). That's because this target is obsolete. I renamed
+it to be oldlinux+openssl and added linux+openssl as a synonym for
+linux+ssl. makefile, 3 Sep 2009.
+
+Tested linux+openssl+zlib+shadow+pam, it's OK. Also linux+krb5. Also
+linux+krb5+ssl. makefile, 3 Sep 2009.
+
+Tried building on Solaris 9 with OpenSSL 0.9.8k with
+solaris9g+openssl+shadow+pam+zlib, it failed like so:
+
+ ck_ssl.c:2875: error: conflicting types for 'inet_aton'
+ /usr/include/arpa/inet.h:52: previous declaration of 'inet_aton' was here
+ make[2]: [ck_ssl.o] Error 1
+ make[2]: Leaving directory hmt/sirius1/prv0/kd/fdc/solaris9ssl'
+ make[1]: [solaris2xg+openssl+zlib+pam+shadow] Error 2
+ make[1]: Leaving directory hmt/sirius1/prv0/kd/fdc/solaris9ssl'
+ make: [solaris9g+openssl+shadow+pam+zlib] Error 2
+
+The problem was caused by including an inet_aton() function ck_ssl.c for
+the benefit of platforms that don't have one in their libraries. This is
+defeated by including NO_DCL_INET_ATON in KFLAGS. I added this, but then
+I thought it would be a good idea to automatically sense the OpenSSL
+version so we can automatically set OPENSSL_097 or OPENSSL_098 rather than
+bombing out, so I added code to do that too, and also to set the Solaris
+version number: 9, 10, or 11. The new entry is solaris9g+openssl.
+ckcdeb.h, makefile, 3 Sep 2009.
+
+Fixed a complaint in ckufio.c about implicit declaration of initgroups.
+ckufio.c, 4 Sep 2009.
+
+Built on Solaris 10 with gcc and Sun CC using new solaris{9,10,11} target
+that is like the new solaris{9,10,11}g one but without the gccisms.
+makefile, 4 Sep 2009.
+
+Changed solaris{9,10,11}g+ssl target to set only the SSL-specific things and
+then chain to the main solaris{9,10,11}g target. Tested OK on Solaris 9 and
+10. makefile, 4 Sep 2009.
+
+Created solaris{9,10,11}+ssl target that is exactly like the
+solaris{9,10,11}g+ssl except it chains to the solaris{9,10,11} target
+instead of the solaris{9,10,11}g one. That is, it builds an SSL version of
+C-Kermit using Sun CC rather than gcc. makefile, 4 Sep 2009.
+
+Tried building on HP-UX 10.20, bundled (non-ANSI) compiler ("make
+hpux1000"). This failed until I:
+
+ . Moved a struct initialization out of setextern(), ckuus3.c.
+ . Removed an ANSIism from the declaration of sigchld_handler() in ckutio.c
+ . Added a cast to strcmp() in zvuser(), ckufio.c.
+
+Builds OK now. Built OK with "hpux1000o" (the ANSI compiler) too.
+And with "hpux1000gcc". Couldn't test "hpux1000o+openssl". 21 Sep 2009.
+
+The Sony Playstation 2 and 3 are 64-bit PowerPC platforms that can run Linux
+if it is installed as an "other OS" on its hard disk; and the Linux kernel
+since 2.6.21 supports the PS3 without any patching required. Pawel Rogocz
+reported that "make linuxppc" (one of the old targets that has not yet been
+integrated into the main "linux" target) compiles OK on 2.6.29-ydl61.3
+(Yellow Dog Linux release 6.2 'Pyxis'), but fails at link time because
+'openpty' isn't found, because -lutil was not included, because that part
+was added only to the main linux target. I asked him to try "make linux"
+and he sent back a transcript in which there were thousands of errors from
+the curses code ckuusx.c. Later I tried it myself and it built without a
+hitch. My theory is that between then and now, a missing piece of the
+ncurses library (/usr/include/ncursesw) was installed. 21 Sep 2009.
+
+HP-UX 9.05 on PA-RISC 9000/712 building with hpux0900 (bundled compiler):
+ . ckutio.c compilation failed with PENDIN and FLUSHO not defined in
+ pty_make_raw(). I dummied definitions for them to handle this situation
+ on this or any other platform where it might crop up.
+ ckutio.c, 24 Sep 2009.
+ . Ditto for the PTY module, + IMAXBEL. ckupty.c, 24 Sep 2009.
+ . References to endusershell() were fatal in the bundled compiler. Changed
+ the hpux0900 target to define NODCLENDUSERSHELL, and put a special case
+ in ckufio.c to not put a cast in front of the call if NODCLENDUSERSHELL
+ is defined. Now it builds and links OK. makefile, ckufio.c, 24 Sep 2009.
+
+HP-UX 9.05 on PA-RISC 9000/712 building with hpux0900o (optimizing compiler):
+ . Warnings in ckutio.c at line 14860 about arguments to select (pointers
+ are not assignment-compatible). "man select" says arguments are ints.
+ Defining INTSELECT fixes these warnings but results in fatal errors later
+ around line 14881 and others in the area involving FD_SET. This was too
+ involved so I put it back as it was. 24 Sep 2009.
+
+Built OK on Solaris 10 with Sun CC. A couple warnings about implicit
+function declarations for curses routines because apparently they aren't
+declared in curses.h. Tuff. 25 Sep 2009.
+
+Tried building on Solaris 10 with Sun CC and OpenSSL 0.9.8k, and this
+uncovered various loose ends in the solaris9+openssl target, which I fixed.
+makefile, 25 Sep 2005.
+
+Fixed four typos in printfs in ck_ssl.c, \% instead of just %. 25 Sep 2009.
+
+Squelched 20-some complaints about a character array being referred to
+directly instead of by a pointer, plus several other similar nits to get rid
+of all the compilation warnings on Solaris 10 with Sun C 5.8 Patch 121015-06
+2007/10/03. ckctel.c, ckctel.h, 25 Sep 2009.
+
+Built the result on the same Solaris 10 system with gcc 4.2.4 using the
+new solari10g+openssl target, working out a few kinks here too.
+makefile, 25 Sep 2009.
+
+Made consolidated Solaris 9/10/11 64-bit targets for gcc, solaris9g64,
+solaris10g64, solaris11g64, tested on Solaris 10 Sparc. makefile, 25 Sep 2009.
+
+Made consolidated Solaris 9/10/11 64-bit targets for Sun cc: solaris9_64,
+solaris10_64, solaris11_64. These simply set a couple flags and chain to
+the main solaris9 target. makefile, 25 Sep 2009.
+
+Removed a bunch of old superfluous Solaris 9 and 10 targets: oldsolaris9,
+oldsolaris9lfs, solaris9g64 solaris9g_64, oldsolaris10 old solaris10lfs,
+oldsolaris10+openssl, oldsolaris10g+openssl, solaris10_64, oldsolaris10g,
+solaris10g_64, solaris10g64. There are still plenty more to prune but it's
+a start. makefile, 25 Sep 2009.
+
+Added or fixed some missing prototypes in ckctel.h:
+fwdx_send_xauth_to_xserver(), fwdx_parse_displayname. 25 Sep 2009.
+
+Improved the instructions for building secure versions in the makefile,
+using this example:
+
+ make solaris9+openssl "SSLINC=-I/opt/openssl-0.9.8k/include" \
+ "SSLLIB=-L/opt/openssl-0.9.8k/lib"
+
+makefile, http://kermit.columbia.edu/security.html, 25 Sep 2009.
+
+Built on HP-UX 11.11, 26 Sep 2009:
+ . make hpux1100 (ok)
+ . make hpux1100gcc (ok)
+ . make hpux1100o (gets a lot of warnings about sendpath and sendfile,
+ because they are also declared in <sys/socket.h>, but builds OK)
+ . make hpux1000gcc+openssl \
+ SSLINC=-I/opt/openssl/include SSLLIB=-L/opt/openssl/lib
+
+Note: sendpath and sendfile are not Kermit symbols. The warnings are coming
+from socket.h: 'Redeclaration of "sendfile" with a different storage class
+specifier'. This is nothing new; see notes of 2-4 Jan 2005.
+
+From Peter Eichhorn:
+ . Update to makefile to make current code build OK on HP-UX 8.00.
+ . Changes to format of some hints to make them more copy-and-pastable.
+makefile, ckuu5.c, 28 Sep 2009.
+
+From Peter Eichhorn: Changes to HP-UX 7.0 target to increase the switch table
+stack size, which was overflowing. makefile, 30 Sep 2009
+
+HP-UX 6.5 (1989), "make hpux0650tcpc"... (8:19...) Needed to not include
+arpa/inet.h (which doesn't exist) and not use host address lists (add
+-DNOHADDRLIST), which gets us past ckcnet.c, but in ckcftp.c we bomb out on
+FD_SETSIZE undefined. Somehow we worked around this in ckcnet.c. Patched
+in a definition in ckcftp.c, and also added -DINTSELECT to compiler flags.
+Compiles ok, bombs at link time on bcopy, bzero, FD_ZERO, FD_SET, FD_ISSET.
+Now it compiles and links OK but dumps core when started. Added
+-DNOCKGETFQHOST, rebuilt from scratch (takes 35 minutes). It starts OK, but
+it dumps core when given a "telnet xxx" command, where xxx is a hostname.
+However, it works OK if an IP address is used: "telnet 123.45.6.78". It
+took all day to track this down, but now it's fixed (see the #ifdef HPUX6
+sections of ckcnet.c). So now (for the first time, I think) we have both
+telnet and ftp in HP-UX 6.x, if anyone cares. ckcnet.[ch], ckcftp.c,
+makefile, 2 Oct 2009.
+
+Changed default SET TERMINAL TYPE type for K95 from vt320 to vt220. This is
+because Unix OS's such as Solaris have dropped vt320 as a terminal type.
+settrmtyp(), ckuus7.c, 5 Oct 2009.
+
+I moved the PUTENV command code, which was inline, to a function, doputenv().
+ckuus[r7].c, ckuusr.h, 5 Oct 2009.
+
+Changed the UNIX version of SET TERMINAL TYPE to take a value and then do
+the equivalent of "export TERM=value" by calling doputenv(). This sets
+\$(TERM) correctly and passes its value along to inferior processes.
+However, to make this take effect within Kermit itself (for the fullscreen
+file transfer display and for the SCREEN command, Ctrl-L, etc) I also had to
+reinitialize the curses database, which is tricky because normally if you
+feed it an unknown terminal name, it just exits. ckuus7.c, 5 Oct 2009.
+
+Changed the little-known and little-used RESET command (which closes all
+open files) to also put command echoing back to normal in case it got
+messed up somehow (as in HP-UX 6.5, upon returning from PUSH).
+ckuusx.c, 5 Oct 2009.
+
+For Unix, increased string buffer sizes for wildcard expansion for all
+platforms that have BIGBUFOK defined from 500000 (0.5M) to 10000000 (10M)
+bytes, and for 64-bit builds to 2000000000 (2G) bytes. No point making
+it bigger than that because malloc's argument is a size_t, which is an int.
+ckufio.c, 5 Oct 2009.
+
+Built on Mac OS X 10.4.11, required one minor adjustment to the makefile
+(-DNODCLINITGROUPS). This was using the macosx10.5 target, which is
+supposed to be universal like the linux and netbsd targets, but not yet
+proven. Also built a 64-bit version (-mpowerpc64 -mcpu=G5 -mtune=G5
+-arch ppc64); it compiles and links OK but won't start: "Bad CPU Type
+in executable". Fix later... makefile, 5 Oct 2009.
+
+Changes from Seth Theriault to suppress signed vs unsigned char warnings in
+Mac OS 10.5.8 from gcc4, and a new makefile target for Mac OS X (presumably
+10.3.9 or later) + Kerberos 5 and OpenSSL. ckutio.c, ckuath.c, ckctel.c,
+ckcnet.c, ckcftp.c, ck_crp.c, makefile, 6 Oct 2009.
+
+ Later I had to back out of these, because although it made for a
+ clean build, in the resulting executable SSL connections didn't work.
+
+Tue Oct 6 17:23:27 2009
+FTP address resolution is broken, but ftp_hookup() hasn't changed.
+So... (see the #ifdef HPUX6 sections of ckcnet.c) (I did, and I rolled
+back some of the changes from the other day, but it made no difference.)
+Putting back the ckcftp.c from a few weeks ago makes no difference.
+Putting back the ckcnet.c from a few weeks ago makes no difference.
+
+Added patches from Seth Theriault so macosx10.5+krb5+openssl would build
+on Mac OS X 10.3.9. makefile, ckcftp.c, 7 Oct 2009.
+
+Built today's code on Linux RHEL4, NetBSD 5.0.1, Solaris 9, and Mac OS X
+10.4.11, both with and without SSL. The NetBSD system has OpenSSL 0.9.9-dev.
+7 Oct 2009.
+
+In Mac OS X 10.6, the following symbols are unresolved at link time:
+_des_key_sched, _des_new_random_key, _des_ecb_encrypt,
+_des_init_random_number_generator, _des_fixup_key_parity. This is
+with OpenSSL 0.9.8k. But it doesn't happen on other platforms that
+have 0.9.8k.
+
+Added SET SESSION-LOG NULL-TERMINATED-TEXT. This is for the benefit of a
+speech synthesizer that will speak a line of text only after receiving a
+NUL character. A more general solution would be to define a filter or
+whatever, but who has time. ckuus[23x].c, 7 Oct 2009.
+
+Consolidated Mac OS X targets, and removed experimental 64-bit ones, because
+they never could work in 10.5 and earlier because 64-bit libs are missing,
+and 10.6 and later are 64-bit automatically. makefile, 8 Oct 2009.
+
+Built on Mac OS X 10.6.1. It came out automatically as a 64-bit build
+because __LP64__ is defined somewhere that I can't find. But this explains
+why the 0.9.8k on 10.6 comes up with missing symbols when the 0.9.8k lib
+10.5 (or on Solaris or on Linux) does not: it's a different library: "Mach-O
+64-bit dynamically linked shared library x86_64", rather than "Mach-O
+dynamically linked shared library ppc". Probably the 64-bit version has
+some things #ifdef'd out. Added -m32 to the CFLAGS and LNKFLAGS for the
+macosx+krb5+openssl targets, and it built OK one time. But then the errors
+came back. makefile, 8 Oct 2009.
+
+Updated C-Kermit installation for Mac OS X in ckuwr.html on the website.
+8 Oct 2009.
+
+Tried some things to get around the problem with OpenSSL in Mac OS X 10.6,
+to no avail. Asked Jeff. He said, "MacOS X no longer includes DES anywhere
+on the system. Not for SSL, not for Kerberos, not for anything. This will
+increasingly become the situation on new operating systems. Windows 7 and
+2008 R2 will also ship with no DES." Sure enough, the Mac OS X Server
+Upgrading and Migrating document for 10.6 says, "Mac OS X Server v10.6 does
+not support single DES encryption. It supports AES 128 and 256 encryption
+types. However, during a migration or upgrade from v10.4 to v10.6, servers
+that were Kerberized by the v10.5 Open Directory server will not use the AES
+128 or 256 encryption types. To use the AES 128 or 256 encryption types you
+must re-Kerberize all servers." 12 Oct 2009.
+
+DES and 3DES encryption can be excluding removing the -DCK_DES flag. I
+removed this one and -DLIBDES (and -m32) and this makes a working 64-bit
+version. Then I added code to the macosx+krb5+openssl target to use these
+flags if the Mac OS X version was 10.5 or less and leave them out for 10.6
+or later. Tested on 10.4.11 and 10.6.1. A better way to do it might have
+been "nm -gj libssl.dylib | grep des_", but that gives the same results on
+10.4 and 10.6. Also, 10.6 still has /usr/include/ssl/des.h.
+makefile, 13 Oct 2009.
+
+Next issue:
+ In file included from ckutio.c:15674:
+ /usr/lib/gcc/i386-redhat-linux/3.4.6/include/varargs.h:4:2: #error "GCC no
+ longer implements <varargs.h>."
+ /usr/lib/gcc/i386-redhat-linux/3.4.6/include/varargs.h:5:2: #error "Revise
+ your code to use <stdarg.h>."
+
+The problem occurs when trying to force a non-ANSIC build with GCC.
+Changing the source file to include <stdarg.h> instead of <varargs.h>
+doesn't help because evidently <stdarg.h> requires an ANSI C compiler.
+Nothing can be done about this. 13 Oct 2009.
+
+Next issue: Can't compile ckcftp.c with -DNOCSETS or -DNOSPL; some
+#ifdef/#endif doesn't match up. Sigh, this is the hardest kind of thing to
+debug. There's 17,622 lines of code in this module and no tool that I know
+of.... Wait, I wrote one. But it shows all the #if/#ifdef/#ifndef's and
+#endifs matching up just fine. Backing off to ckcftp.c of a few days ago
+(before char / unsigned char casts were added), I see that it builds OK, so
+I backed off to that one, but put back the special case #ifdef for MACOSX103
+declaring CONST gss_OID_desc, and it builds OK (the other stuff was purely
+cosmetic, when will I learn?). ckcftp.c, 13 Oct 2009.
+
+Protected cvtstring() and related functions with #ifdef NOCSETS..#endif,
+and ditto for the character-set conversion code in dorename().
+ckuus6.c, 13 Oct 2009.
+
+Fixed an #endif /* TNCODE */ that was a line too low in ttptycmd(),
+causing -DNONET builds to fail. ckutio.c, 13 Oct 2009.
+
+There was a reference to doputenv() that wasn't guarded by #ifndef NOPUTENV,
+fixed in ckuus7.c, 13 Oct 2009.
+
+Moved doputenv() and settermtyp() out of an #ifdef NOLOCAL section because
+these are useful even when not making connections. ckuus7.c, 13 Oct 2009.
+
+Moved havelfs declaration outside of #ifdef NOXFER because it was also used
+for other things. ckcmai.c, 13 Oct 2009.
+
+COPY /PRESERVE depended on code from the Kermit protocol module, which
+is omitted in -DNOXFER builds. Disabled COPY /PRESERVE in -DNOXFER
+builds. ckuus6.c, 14 Oct 2009.
+
+SHOW PROTOCOL code for external protocols had to be #ifdef'd out for
+-DNOPUSH builds. ckuus4.c, 14 Oct 2009.
+
+There was some confusion between "No XYZMODEM" and "No external protocols";
+cleared up in ckuus3.c, 14 Oct 2009.
+
+After all that, 86 different combinations of feature selections built OK on
+Linux. And the Kerberized version (K5) works OK on Linux for Telnet and FTP.
+14 Oct 2009.
+
+Changed version number to 9.0. All modules, 16 Oct 2009.
+
+Need to make LOG SESSION log to a tty. Right now "log session
+/dev/ttyKeySerial1" says "Write permission denied" even though the device is
+crw-rw-rw-. This happens in zchko(), which is called by cmofi(). The
+problem is that /dev/ is not writeable. I added a Unix-only clause that
+attempts to open the file for write access using open(), in order to get a
+file descriptor, which then can be passed to isatty() to check if it's a
+tty, and if so, to allow access. And then close it. I tested this on Mac
+OS X as follows:
+
+ log session /dev/ttyKeySerial1
+ telnet somehost
+
+The Mac's serial port was connected to the serial port of another computer
+where Kermit displayed the incoming characters in CONNECT mode. Glitches:
+
+ 1. The port has to be set up as desired in advance, outside of Kermit.
+ 2. log session /dev/ttyKeySerial1 will hang if any required modem signals
+ are not present when the port is opened.
+ 3. Bypasses lockfile mechanism - so we do this only if -DNOUUCP.
+
+For (2), I tried setting O_NDELAY / O_NONBLOCK, and this allowed zchko() to
+continue, but then it freezes in the subsequent fopen(). So I changed
+zopeno() to also check if the device is a serial port, and if so, to open()
+it with O_NDELAY / O_NONBLOCK, and then convert the file descriptor into a
+file pointer with fdopen().
+
+Now for the speaking device that needs lines to be terminated by NUL...
+
+ set session-log binary <-- need to put these in SHOW LOG
+ set session-log null-padded (and in HELP SET LOG)
+ set line /dev/ttyKeySerial1
+
+This part works.
+
+This feature is enabled only for -DNOUUCP builds because serial ports aren't
+like other Unix files; we would have to create a lockfile, but we can't do
+that... actually, ttlock() takes a name as an argument, but ttunlck() does
+not, so there would be no way to remove the lock. Anyway, there is only one
+API for configuring the port (speed, flow control, etc) and it only works
+with the SET LINE device, not any random file. To fix this would require
+massive redesign and changes. ckuus[23].c, ckufio.c, 19-20 Oct 2009.
+
+I made -DNOUUCP the default for Mac OS X, since everybody winds up building
+it that way anyhow. To undo this, do "make macosx KFLAGS=-UNOUUCP".
+makefile, 21 Oct 2009.
+
+Changed SET SESSION-LOG TEXT to strip out ANSI escape sequences;
+previously there wasn't that much difference between TEXT and BINARY logs.
+It's still not perfect; for example it doesn't delete characters that the
+user erased. (Made sure this still builds with -DNOESCSEQ.)
+ckucns.c, 22 Oct 2009.
+
+Changed SHOW LOG to show the SET SESSION-LOG settings, as well as
+SET DEBUG, which was not shown before. ckuus5.c, 22 Oct 2009.
+
+If a series of PUTENV commands is given, each new one undoes the previous
+one, so only the last definition is seen by the new fork (or by Kermit
+itself). Turns out you can't feed automatic variables to putenv(); they
+have to be static, so to allow for multiple PUTENV commands Kermit has to
+maintain an array of static strings. ckuus7.c, 6 Nov 2009.
+
+From Seth Theriault, a better way for the makefile to determine the
+Mac OS X version number; there's a program for this, sw_ver. makefile,
+6 Nov 2009.
+
+Peter Eichhorn reported that file-transfer failure hints were not coming
+out since Dev.27. The only change I made since then was to skip them if
+the file-transfer protocol was not Kermit. I was using the wrong variable
+in the tests, 'proto' instead of 'protocol'. ckuus5.c, 6 Nov 2009.
+
+Changed Mac OS X targets to correctly extract the Mac OS major version
+from uname -r in order to choose correctly between utmp and utmpx; this
+wasn't working in 10.6.1. makefile, 6 Nov 2009.
+
+Fix from Seth T. for an oversight in the previous edit. Also add
+MACOSX103 to "show features" display. makefile, ckuus5.c, 10 Nov 2009.
+
+Added REJECT as a synonym for DISCARD in SET FILE COLLISION; it's more
+intuitive and more accurate. ckuus[27].c, 15 Nov 2009.
+
+\fsplit() and \fword() always break on 8-bit characters unless you explicitly
+put every single 8-bit value into the include set, e.g. (for a TSV file):
+
+ undef include
+ for \%i 128 255 1 {
+ if == \%i 9 continue
+ .include := \m(include)\fchar(\%i)
+ }
+ .\%n := \fsplit(\m(line),&a,\9,\m(include))
+
+I changed cksplit() to treat all 8-bit bytes 128-255 as non-break characters
+by default. It might have made more sense to do this for 160-255 (since
+128-159 are traditionally C1 control characters) but thanks to Microsoft
+tradition is out the window. To treat one or more 8-bit characters as break
+characters, put them in the break set. This might break some scripts, but I
+doubt it because this flaw was so awful that if anyone had come up against
+they would have let me know. ckclib.c, 16 Nov 2009.
+
+Changed the netbsd target to set -funsigned-char, since cc on NetBSD is
+actually gcc. makefile, 16 Nov 2009.
+
+Changed macosx targets to get the CPU type from the HOSTTYPE environment
+variable. Also added getenv("HOSTTYPE") as a last-resort method to set the
+\v(cpu) variable at runtime (maybe it should be the first resort?)...
+ckuus4.c, makefile, 16 Nov 2009.
+
+Made sure the solaris9_64 and solaris10 targets still work. 16 Nov 2009.
+
+Made sure the current source package builds OK on HP-UX 10.20... Got a lot
+of "warning 6062: Optdriver: Exceeding compiler resource limits in xxx; some
+optimizations skipped. Use +Onolimit if override desired" but it builds OK.
+Tested long file transfer; works OK. 17 Nov 2009.
+
+Built on FreeBSD 7.2 with and without OpenSSL, all OK. 17 Nov 2009.
+
+Built on NetBSD 5.0.1 with and without OpenSSL, all OK, but netbsd+krb5
+fails with "can't find -lgssapi_krb5"; worked around this with
+"K5LIB=-L/usr/local/kerblib" (where the lib actually is on this host) but
+then it failed with "ckcftp.c:13868: error: 'gss_nt_service_name' undeclared".
+17 Nov 2009.
+
+I found a VMS 6.2 system... Takes a loooong time to build there. In
+ckuusy.c, DEC C didn't like the prototypes and declarations of dorlgarg()
+and dotnarg() as static so I made them not static. But that didn't help,
+now it fails at the very end, saying the final #ifdef is an invalid
+statement. It looks like an #ifdef mismatch that affects only VMS. I ran
+my #ifdef matcher, it turned up nothing. I substituted a copy of ckuusy.c
+from 2007, it comes up with the same errors. Then I substituted the copy
+from 8.0.211 from 2004, and this one compiled OK and, miraculously, the
+whole mess even linked OK and runs OK. The Alpha binary is 2.84MB. Now I
+have 4500 lines of code to compare.... I went through the two files line by
+line and I can't see a single thing wrong. I gave up and tried building the
+TCP/IP version. It builds fine except for ckuusy.c, with the utterly
+useless error message:
+
+ #endif /* NOCMDL */
+ ...................^
+ %CC-E-BADSTMT, Invalid statement.
+
+Indicating the last line in the file. Just for the heck of it, I put
+another line after that one:
+
+ /* This is a test */
+
+and got:
+
+ /* This is a test */
+ ....................^
+ %CC-E-BADSTMT, Invalid statement.
+
+So it is not objecting to anything in the file. Trying the old LISP trick,
+I put an extraneous closing bracket after that. Success! Honestly, I don't
+see anything wrong with file. It's DEC C V5.3-006. I suspect a C bug.
+I'll leave it like this for now until I get access to some other VMS
+versions. Another clue is that when building the network version I get a
+horrible warning I never saw before from a module that hasn't been touched
+in a very long time (ckvrtl.c). Also, in the network version, I note that
+the FTP code is not compiled in. We have to try this again with some
+command-line switches, but it'll do for now. ckuusy.c, 18 Nov 2009.
+
+---C-Kermit 9.0 Alpha.01---
+
+From Steven Schweda (SMS), the real solution for the VMS closing brace
+problem, it wasn't a DECC bug, it was a me bug. ckuusy.c, 20 Nov 2009.
+
+Rediscovered the new VMS build options: f for Long Files, i for Internal
+FTP. "make mnf" doesn't work on VMS 6.2, it looks like the VMS definition
+for CK_OFF_T got lost. Same thing with "make mfi". Come back to this later.
+
+From Gerry Belanger, a fix to INPUT /COUNT:n. ckuus4.c, 26 Nov 2009.
+
+Added \fsqueeze(s), returns string s with leading and trailing whitespace
+removed, Tabs converted to Spaces, and multiple spaces converted to single
+spaces. For now, ASCII only, no options. ckuusr.h, ckuus[24].c, 27 Nov 2009.
+
+I wrote a Kermit script to read a big file of addresses on Solaris 9,
+\fsqueeze()ing each line. After about 14000 lines, there was a malloc
+failure in getnct() (the command-file reader). There's nothing wrong with
+\fsqueeze(), the failure is on a deeper level, because the same thing
+happens if I use \fupper() (which is structurally identical to \fsqueeze())
+in the same script. The problem is not in getnct() either, because every
+malloc() is freed (I checked). On the other hand, the same script (with
+\fupper() instead of \fsqueeze() completes OK in C-Kermit 8.0.201. If I
+remove the function call (\fsqueeze() or \fupper()) from the script, it also
+runs OK in 9.0. This seems to point the finger at fnevel(), which contains
+countless malloc's and free's. But comparing fneval() between 8.0.211 and
+9.0, I don't see any difference that would explain this behavior -- nothing
+at all that involves malloc(), makstr(), or free(). Nor any pertinent
+change in the caller (zzstring) of fneval(). 27 Nov 3009.
+
+Another problem is that when this happens, the error is not caught (e.g. by
+the IF FAIL statement after the command that contains the function call);
+instead, C-Kermit returns immediately to its prompt. 27 Nov 2009.
+
+It could simply be that some of the buffers we allocate are much bigger now.
+But again, I don't see much difference between 8.0.211 and 9.0; we were
+already allocating 32K command-related buffers (malloc() takes a size_t, and
+size_t is an int almost everywhere). I built the same source on NetBSD and
+ran the same script (with \fqueeze()), and it worked fine. Let's worry
+about this later, if it comes up. 27 Nov 2009.
+
+Built OK on Silicon Graphics IRIX 6.5 R10000; regular build OK, SSL and
+Kerberos builds failed. 30 Nov 3009.
+
+Tried to build on Digital Unix 4.0F but it blew up in ckutio.c, apparently
+not recognizing any of the terminal struct symbols from termios.h. Tried
+again with gcc, same thing. Tried explicitly #including <sys/termios.h>
+within #ifdef TRU64, same thing. What could have changed? 30 Nov 2009.
+
+Built OK on Linux RHEL5.4/Itanium-2, make linux. The secure build
+required "FLAGS=-DNO_KRB5_INIT_ETS" and built OK. 30 Nov 2009.
+
+Built OK on Digital Unix 4.0F using "make osf" instead of "make tru64-40f".
+I don't know why the specific target doesn't work, but it's not worth
+chasing down. 2 Dec 2009.
+
+Built OK on MirBSD 10, despite a lot of gratuitous compiler warnings. Built
+OK on MirBSD 10, OpenBSD 4.5, and Fedora 10. 3 Dec 2009.
+
+(Various other successful Unix builds in these weeks...)
+
+Built on VMS 7.2 and 8.3 with and without TCP/IP, no problems. 11 Jan 2010.
+
+Built on VMS 8.3 with "make fi" to include the FTP client and long-file
+support (mid Jan 2010).
+
+Built on VMS 8.3 with UXC 5.6 and HP SSL 1.3, which is OpenSSL 0.9.7e.
+It compiled and linked OK but when I tried to make an FTP SSL connection
+it crashed in SSL$LIBSSL_SHR, which is called from ssl_auth(), after having
+had TLS accepted as an authentication type, but before actually
+authenticating. In Unix:
+
+ 19. ftp open ftp.somecompany.com /user:pge.com/test_quota /password:xxxxxx
+Connected to ftp.somecompany.com.
+220-Somecompany FTP v6.0 for WinSock ready...
+220 Welcome to the online storage FTP server. Please check the main web
+site for system announcements and AUP. (O)
+---> AUTH TLS
+234 AUTH command OK. Initializing SSL connection.
+TLS accepted as authentication type
+SSL DEBUG ACTIVE
+=>START SSL/TLS connect on COMMAND
+
+In VMS:
+
+ 19. ftp open ftp.somecompany.com /user:pge.com/test_quota /password:xxxxxx
+Connected to ftp.somecompany.com.
+220 Somecompany FTP v6.0 for WinSock ready...
+---> AUTH TLS
+234 AUTH command OK. Initializing SSL connection.
+TLS accepted as authentication type
+SSL DEBUG ACTIVE
+%SYSTEM-F-ACCVIO, access violation, reason mask=04, virtual
+address=FFFFFFFF8001A120, PC=000000000068B118, PS=0000001B
+
+Note: The Unix version received the second 220 response, the VMS version did
+not. That's odd, it's the same code... 25 Jan 2010.
+
+Added some essential details to the HELP FSEEK text. ckuus2.c, 25 Jan 2010.
+
+Discovered that the result returned by \fsearch() is totally unreliable.
+This is probably too hard to fix.
+
+FSEEK did not pay attention to SET CASE, searches were always case sensitive.
+Fixed in ckuus7.c, 26 Jan 2010.
+
+FSEEK failed to find anything if the search pattern was matched in the first
+line of the file. Fixed in ckuus7.c, 26 Jan 2010.
+
+\fword() and \fsplit().... Another change, but not backwards-incompatible.
+One may now put the word ALL (just like that, all uppercase) as the include
+set (4th argument) to indicate that there will be no break characters other
+than those explicitly given in the break set, e.g. \fsplit(\m(xx),&a,:,ALL)
+breaks a line only on a colon (:), nothing else. The original rules for
+cksplit() were more than a little counterintuitive: the default break set is
+all non alphanums, and the default include set is all alphanums, so if you
+wanted to parse (say) a CSV file, breaking only on comma, you had to think
+of all the characters you wanted to keep. This way you just say ALL.
+ckclib.c, 26 Jan 2010.
+
+Speaking of CSV files... How can you put comma as a function argument when
+comma is the function-argument separator? Use one of these forms:
+
+ \fsplit(\m(xx),&a,",",ALL)
+ \fsplit(\m(xx),&a,{,},ALL)
+ \fsplit(\m(xx),&a,\44,ALL)
+ \fsplit(\m(xx),&a,\fchar(44),ALL)
+
+From John Dunlap, U. of Washington Applied Physics Lab: 'When "stty -a <
+/dev/ttyS0 | grep crtscts" shows "crtscts" (not "-crtscts") and when using a
+three wire serial interface and when asking kermit to not use flow control
+(set flow none) then "ckutio.c1" (see attachments) fails while "ckutio.c"
+works. The result of "diff -u ckutio.c1 ckutio.c" is attached as "diffs"'.
+ckutio.c, 26 Jan 2010.
+
+Changed the year from 2009 to 2010 in the modules I worked on today and in
+the heralds, etc. ckckmai.c, ckuus5.c, ckutio.c, ckclib.c, ckuus7.c,
+26 Jan 2010.
+
+Built on Linux Fedora Core 3, regular and with OpenSSL 0.9.7a. Built on
+Ubuntu 9.4 OK, but SSL and Kerberos builds failed due to not finding libs
+and/or header files. I'm sure this could be fixed... 27 Jan 2010.
+
+Added SSL, KRB4, and KRB5 to the startup herald for versions that were
+built with SSL, Kerberos 4, or Kerberos 5. Built OK on Fedora 3 with
+linux+krb5+ssl and new banner shows correctly. ckuus5.c, 27 Jan 2010.
+
+Set NO_KRB5_INIT_ETS by default in ckuath.h since krb5_init_ets() is a no-op
+in Kerberos 1.4.x and later and in some installations it can't be found,
+which clobbers the build. ckuath.h, 27 Jan 2010.
+
+Adapted to MINIX 3 1.5, the first version that has virtual memory according
+to Andy T, who should know. On earlier versions (e.g. MINIX 3 1.2) any
+attempt to build C-Kermit causes the compiler to crash. Now the compiler
+doesn't crash but it spews out countless warnings about old-fashioned
+function declarations that I don't get anywhere else. The real problems
+came in ckutio.c where numerous symbols were undefined at compile time and
+the POSIX function tcgetpgrp() was not found at link time, even though there
+is a prototype for it in the MINIX header files, and there is no alternative
+(since POSIX doesn't let us use ioctl()). Also note that there is some
+confusion over the compile-time symbols MINIX, MINIX2, MINIX3, and MINIX315.
+You would expect MINIX to mean "any version of MINIX" but in some parts of
+ckutio.c it means MINIX 1.0. I sincerely doubt that C-Kermit 9.0 can be
+built on any version of Minix before 3.1.5 so I removed the confusion and
+made MINIX mean "any Minix". It builds on 3.1.5 OK now, except for the FTP
+client. This can probably be fixed but... Modules changed: ckcdeb.h,
+ckuver.h, ckcmai.c, ckuus5.c, ckutio.c, 1 Feb 2010.
+
+Later.. Andy says MINIX does not support job control, so no program is ever
+in the background. That settles that! 1 Feb 2010.
+
+Built OK on Minix, Linux, Mac OS X, Solaris 9, NetBSD 5.0.1... 1 Feb 2010.
+
+---C-Kermit 9.0 Alpha.02---
+
+From Christian Corti at Uni-Stuttgart.de: fixes to allow building on SunOS
+4.1, which once was my main development platform but which is long-gone from
+here. ckupty.c, ckutio.c, 9 Feb 2010. (He says it is also necessary to
+comment out the "struct winsize" and "struct ttysize" in sys/ioctl.h;
+otherwise there will be a conflict with sys/ttycom.h (included by termios.h)
+which also declares these structs. But you need both includes.')
+
+From John Dunlap, a fix for Kermit protocol fixed packet-timeout interval
+going to a unexpected value (missing else clause in two places).
+ckcfn2.c, 9 Feb 2010.
+
+Added an aixg target to build on AIX with gcc when gcc is not installed as
+cc, and also added CC=$(CC) CC2=$(CC) clauses to the aix and aix+ssl
+targets. Wow, AIX really loses bigtime when receiving files through its ssh
+server. Streaming can't be used, sliding windows recover from errors but
+there are tons of them using the default 4K packets; 500 works much better.
+Built with IBM cc and gcc, and also tested (successfully) the new aix+ibmssl
+target, in which the OpenSSL headers and libs are in a standard place.
+makefile, 9 Feb 2010.
+
+In ckupty.h, make the #include <sys/ioctl.h> be #ifndef SUNOS41.
+From Christian Corti. 10 Feb 2010.
+
+Built on VMS E8.4. 12 Feb 2010.
+
+Tried to build on a real VAX-11/785 but the machine seems to be seriously
+wedged. 12-15 Feb 2010.
+
+Added note to CKVKER.COM to the effect the the 'f' option has no effect
+on VAX architecture. 15 Feb 2010.
+
+Moved the #include "ckvrtl.h" in the FTP module to below the include for
+utime.h, because building the VMS version with the 'i' option (meaning
+"include internal ftp client") results in "struct utimbuf tp" erroring out
+because struct utimbuf is not defined yet (at least in some version of VMS
+with some version of C). From Rob Brown, ckcftp.c, 20 Feb 2010.
+
+From Martin Vorlaender: new code in VMS C-Kermit build procedure to detect
+OpenSSL version automatically. ckvker.com, 22 Feb 2010.
+
+Added code to INPUT command to strip ANSI escape sequences. It's activated
+by SET SESSION-LOG TEXT. ckuusr.h: added prototype for chkaes();
+ckucon.c, ckucns.c: made inesc[] and oldesc[] global instead of static;
+ckuus4.c: doinput() code for skipping escape sequences. 1 Mar 2010.
+
+Peter Eichhorn complained that if you make an ssh connection with Kermit,
+then log out from the ssh host, and then use a "connect" command to
+make a new connection to the same host (which you can do with Telnet),
+Kermit says (e.g.):
+
+ DNS Lookup... Can't get address for ssh -e none somehostname
+ Sorry, can't open ssh -e none somehostname: Error 0
+
+I added code to detect and handle this case and it seems to work OK, even
+though it's kind of a hack. ckuusr.[ch], ckuus7.c, 1 Mar 2010.
+
+There has never been a clean way to put debugging messages (ECHO commands)
+in a script which are executed only if debugging is desired and ignored
+otherwise. You'd have to set a random variable and test it, or define a
+macro or whatever. To make this more straightforward, I added SET DEBUG
+MESSAGE ON/OFF/STDERR, and added a new MESSAGE (syn: MSG) command for printing
+debugging messages to stdout if SET DEBUG MESSAGE is ON or to stderr if SET
+DEBUG MESSAGE is STDERR. ckcmai.c, ckuus[r23].c, 12 Mar 2010.
+
+Also for debugging and error messages, I added \v(lastcommmand) so that
+the command that failed can be included in an IF FAIL or DEBUG error message.
+This works even for commands that have syntax errors.
+ckuusr.h, ckuus5.c, ckucmd.c, 12 Mar 2010.
+
+From SMS for VMS: 'Added/documented P3 options INTSELECT, OLDFIB, OLDIP.
+Disabled (commented out) automatic definition of NOSETTIME for VMS before
+V7.2 (vms_ver .lts. "VMS_V72").' ckcdeb.h, ckcftp.c, ckcnet.c, ckuus[2567].c,
+ckvfio.c, ckvker.com, ckvrtl.[ch], 15 Mar 2010.
+
+Exposed inesc[] and oldesc[] for VMS, so new INPUT command escape-sequence
+stripping can work (really, chkaes() and related global variables should be
+moved out of ck[uvd]con.c/ckucns.c and into a common module; do that later).
+ckuusr.h, ckvcon.c, 15 Mar 2010.
+
+Built OK on Solaris9, Mac OS X 10.4.11, RHEL4 (32-bit), RHEL5 (64-bit),
+AIX 5.3, SCO OpenServr 6.0.0... 15 Mar 2010.
+
+Not so good on VMS, turns out I made a typo in one of the VMS updates
+(#ifndef OLDIP instead of #ifdef...). ckcnet.c, 16 Mar 2010.
+
+More from SMS for VMS, 16 Mar 2010:
+ . Set MAXPATH correctly for VMS, ckcdeb.h.
+ . NAM -> NAML, QIO replaces system( "SET PROTECTION"), bugfixes in
+ cvtdir() and nzltor(), ... (See comments): ckvfio.c, new ckvrms.h.
+ (The RMS code in ckvfio.c was almost totally rewritten)
+ . Moved "NAMX$*" (and related) macros to ckvrms.h, and renamed to
+ "NAMX_*" (and similar "$" -> "_"), moved "FIB_*" macros from ckvrtl.c.
+
+These changes are mainly to accommodate the ODS5 file system, which has
+longer and mixed-case filenames, and also to execute certain commands
+(e.g. for setting file protection, deleting directories) directly instead
+of using a system() command.
+
+Built OK on VMS 8.3 (with and without network support). 16 Mar 2010.
+
+Failed to build on VMS 6.2. 16 Mar 2010.
+
+FreeBSD 8.0 <libutil.h> has a hexdump() prototype that conflicts with the
+hexdump macro defined in ckcdeb.h. Since the same thing is likely to happen
+elsewhere, I changed the Kermit macro to ckhexdump as well all references to
+it: ckcdeb.h, ckcftp.c, ckcnet.c, ckctel.c, ckuath.c, ckutio.c, 16 Mar 2010.
+
+Built OK on Digital Unix Tru-64 4.0E using "make osf", 16 Mar 2010.
+
+Tried again to build Digital Unix Tru64 4.0E using "make tru64-40e", but
+something prevents it from picking up the termios symbols and it blows up in
+ckutio.c, whereas this used to work in earlier C-Kermit versions. This is
+the only Tru64 system I still have access to, so I can't tell if it's a
+local peculiarity or what. Note that POSIX is not defined for this build.
+But if I define it, I get into trouble with "struct timeval". Tried again
+with "KFLAGS=-DPOSIX -DNOTIMEVAL" but that doesn't help. Tried "make
+dec-osf" and that worked OK but oddly enough it makes a Kermit with less
+features than "make osf". 16 Mar 2010.
+
+To go with MESSAGE and SET DEBUG MESSAGE, I added IF DEBUG, which is true
+if SET DEBUG MESSAGE is not OFF and false otherwise. ckuusr.h, ckuus6.c,
+16 Mar 2010.
+
+From SMS: Corrections to my merging of SMS's changes, ckcftp.c, ckvrtl.h.
+Builds OK on VMS 6.2 now. Also did an SSL build on VMS 8.3 with OpenSSL
+m0.9.7e and "OPENSSL_DISABLE_OLD_DES_SUPPORT" was included in P3
+automatically by Martin V's addition to ckvker.com. 17 Mar 2010.
+
+From SMS: #include <types.h> earlier for VMS in ckcdeb.h to pick up off_t
+before it is referenced. This allows C-Kermit to compile on VMS/Alpha 6.2
+but linking fails on fseeko() and ftello() (and yet, a functional executable
+is created, and FSEEK works right). Builds the same way with no problems at
+all on VMS 8.3 / Alpha. In this case we get the full 64-bit arithmetic...
+Well, 62 bits:
+
+ ATLAS::C-Kermit>( ^ 2 63)
+ 9223372036854775000.0
+ ATLAS::C-Kermit>( ^ 2 62)
+ 4611686018427387904
+
+whereas on VMS 6.2 we get integers only up to (^ 2 30). 17 Mar 2010.
+
+Changed the VMS build procedure to enable large file support automatically
+for non-VAX and VMS 7.3 or greater. No reason not to include this feature.
+Changed the sense of the F option to DISABLE large file support in the
+unlikely case that C-Kermit is being built on a suitable platform but the
+C library is older than VMS73_ACRTL-V0200, in which case fseeko() and
+ftello() will come up missing at link time. ckvker.com, 18 Mar 2010.
+
+Changed VMS build procedure to include the FTP client in any network build
+by default. Changed the sense of the I option to exclude the FTP client,
+in case anybody would want to do that. ckvker.com, 18 Mar 2010.
+
+From SMS: updated dependencies in CKVKER.COM, fix the "don't reinclude me"
+clause in CKVRTL.H. 19 Mar 2010.
+
+Built OK on VMS 6.2 and 8.3 with and without networking. Large file support
+included automatically in VMS 8.3 FTP client included automatically in both
+network builds. 19 Mar 2010.
+
+Changed hexdump() to ckhexdump() in ck_crp.c, which I missed before.
+19 Mar 2010.
+
+---C-Kermit 9.0 Alpha.03---
+
+In HP-UX with the bundled-non ANSI compiler, we get warnings about functions
+such as endusershell(), which are declared void in the header files. But in
+non-ANSI builds we defind VOID to be int rather than void, so our prototypes
+are wrong. I checked that HP-UX 9, 10, and 11 all have void datatype and
+changed the definition of VOID to void in those cases. ckcdeb.h, 29 Mar 2010.
+
+Fixed a typo in a debug() statement in cksplit() that was causing some
+warnings. ckclib.c, 29 Mar 2010.
+
+Ditto in tls_load_certs(). ck_ssl.c, 29 Mar 2010.
+
+"make hpux1000o+ssl" files with:
+/usr/ccs/bin/ld: Unsatisfied symbols:
+ __umoddi3 (code)
+ __udivdi3 (code)
+ __eprintf (code)
+
+It appears that OpenSSL (0.9.7c in this case) requires -lgcc.
+And indeed hpux1000gcc+ssl builds fine. 29 Mar 2010.
+
+There are various warnings in the SSL code in ckutio.c, ckcftp.c, and
+ckcnet.c about pointers not being assignment compatible, but I have learned
+from experience not to try to fix these (see notes from 6 Oct 2009).
+29 Mar 2010.
+
+connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)): In FTP,
+this doesn't work on RHEL5 / Mac OX X 6.1/2 64-bit. But the connect() in
+Telnet works. On Mac OS X 6.2 I tried changing the socket() call to be like
+the one in ckcnet.c for Telnet, but it made no difference. On a RHEL5.4
+system on i386, FTP works fine, so it's not the Red Hat version. On Digital
+Unix 4.0E 64-bit, same thing:
+
+ 11:23:10.722 ftp_hookup[kermit.columbia.edu]=21
+ 11:23:10.722 ftp hookup A[kermit.columbia.edu]
+ 11:23:10.722 ftp hookup C[kermit.columbia.edu]
+ 11:23:10.722 ftp hookup socket=4
+ 11:23:10.722 ftp hookup HADDRLIST
+ 11:23:10.723 ftp hookup connect failed=13
+ 11:23:10.723 ftp hookup bad
+
+13 = Permission denied:
+
+ [EACCESS] Search permission is denied for a component of the path prefix;
+ or write access to the named socket is denied.
+
+On Gentoo Linux, also on Alpha, the errno is 51: Network is unreachable.
+Clearly some data type in the sockets structs is out of whack.
+
+The third connect() argument is "address length". The address is a
+struct sockaddr. About the third argument, RHEL5 "man connect" says:
+
+ The third argument of connect() is in reality an int (and this is what
+ 4.x BSD and libc4 and libc5 have). Some POSIX confusion resulted in
+ the present socklen_t, also used by glibc. See also accept(2).
+
+Building on RHEL5 on x86_64, where size_t is 8 and socklen_t is 4, I get a
+warning:
+
+ ckcftp.c: In function 'ftp_hookup':
+ ckcftp.c:14667: warning:
+ comparison is always true due to limited range of data
+
+Referring to:
+
+ if (hisctladdr.sin_addr.s_addr != (unsigned long) -1)
+
+This seems to be the problem; if I remove the (unsigned long) cast (in two
+places), the problem goes away. Actually what I should be comparing it with
+is INADDR_NONE, which is defined appropriately in some header file, e.g. as
+0xffffffff. Also I define it explicitly as -1 if it is not defined in any
+header file (as is the case in Solaris 9). Tested OK on 64-bit RHEL5,
+32-bit RHEL5, Digital Unix 4.0E 64-bit, Solaris 9 32-bit, Mac OS X 10.4.11
+32-bit, Mac OS X 10.6.3 64-bit, AIX 5.3, Gentoo Linux 2.6.31 on Alpha
+64-bit, NetBSD 5.0.1 32-bit.... ckcftp.c, 29 Mar 2010.
+
+---C-Kermit 9.0 Alpha.04---
+
+Yesterday's VOID redefinition caused problems for HP-UX in ckuusx.c, in the
+curses section where VOID is undef'd and not used to avoid a conflict with
+curses.h. As a workaround I defined a new macro CKVOID with the same
+definition as VOID and used it in the offending section of ckuusx. The real
+solution is to replace all references to VOID with CKVOID (since VOID is
+increasingly likely to cause conflicts), but a mass search and replace is
+not without risks. ckcdeb.h, ckuusx.c, 30 Mar 2010.
+
+Changed VOID and CKVOID definition to be 'void' for all HP-UX (verified by
+PeterE back to HP-UX 6.5, 1989). Still need to check this on HP-UX 5.21;
+if that's an exception it can be done in the makefile. ckcdeb.h, 30 Mar 2010.
+
+The change I made to allow CONNECT to reestablish a previous SSH connection
+prevented a new SSH connection to a different host to be made. Fixed in
+ckuus7.c, 30 Mar 2010.
+
+Fixed mistaken extern declarations of krb4_errno and krb5_errno as strings
+in nvlook(); they are ints. Built OK on Mac OS X 10.6.3. ckuus4.c, 30 Mar 2010.
+
+A fix to Trusted HP-UX makefile target from PeterE, to account for the
+equivalence of +openssl and +ssl as target suffixes. 30 Mar 2010.
+
+Added a new function \fcvtcsets(string,cset1,cset1) that converts a string
+from one character set to another. The csets are File Character-Set names.
+ckuus4.c, 31 Mar 2010.
+
+Added a new function \fdecodehex(string,prefix) that decodes a string
+containing prefixed hex bytes. Default prefix is %%, but any prefix of
+one of two chars (such as % or 0x) can be specified. ckuusr.h, ckclib.h,
+ckclib.c, ckuusr.c, 31 Mar 2010.
+
+Richard Nolde reports that Kermit can't find -lpam on Fedora 12 because it's
+in /lib rather than /usr/lib. RHEL5 has symlinks, FC12 should too. Added a
+note to the makefile. 1 Apr 2010.
+
+Build on Solaris 11 for the first time. Had to adjust ckuver.h to get the
+version herald right. This was on a box that reported its architecture as
+i86pc. 1 Apr 2010.
+
+Added MIME character-set names as invisible synonyms in the file and
+terminal character-set tables, fcstab[] and tcstab[]. Note that not all the
+character sets known to Kermit are registered in MIME. But at least now
+MIME-registered character sets can be referred to by their MIME names, e.g.
+ISO-8859-1, ISO646-ES, IBM437, WINDOWS-1252. These are not listed if you
+type ? in a field that is parsing them, unless you type a letter first,
+e.g. "i?" lists ISO- and IBM set names. Later maybe I'll make parallel
+tables, or keyword attribute bit that says whether a name is MIME or not.
+The real benefit of this change is that now Kermit can take its
+character-set names from external sources like email headers or web logs.
+ckuxla.c, 1 Apr 2010.
+
+Changed the IF command to accept a bare macro name its condition. This will
+parse and execute correctly if the macro is defined and if it has a numeric
+value, or if it is not defined, in which case it evaluates to 0 (FALSE). If
+it is defined but has a non-numeric value, a parse error occurs. ckuus6.c,
+2 Apr 2010.
+
+Added \fstringtype() function. Given a string argument, it tells whether
+the string is 7bit, 8bit, utf8, binary, etc. ckuusr.h, ckuus[4x].c,
+2 Apr 2010.
+
+Did a few builds to make sure there were no booboos. Solaris 9, NetBSD
+5.01, Linux RHEL4, HP-UX 10.20 (non-ANSI compiler and ANSI optimizing
+compiler), Mac OS X 10.4.11, SCO OSR 6.00. 5 Apr 2010.
+
+---C-Kermit 9.0 Alpha.05---
+
+Increased maximum variable name length from 4K to 16K. Verified that
+too-long names are caught and recovered from correctly. ckuusr.h, 6 Apr 2010.
+
+Implemented a new \fsplit() option for parsing CSV files, which turns out to
+be a little complicated, because the separator is not just a comma, but a
+comma and all its surrounding spaces. Also there are special quoting rules
+for fields with embedded commas and fields with embedded quotes. ckclib.c,
+7 Apr 2010.
+
+---C-Kermit 9.0 Alpha.06---
+
+VMS changes from SMS. They build OK, Kermit file transfers are still OK,
+but FTP text-mode GETs always hang on the 10th 8K network read. Couldn't
+get a debug log this time. ckcmai.c, ckvfio.c, ckvrms.h, ckvker.com.
+8 Apr 2010.
+
+Changing VNAML from 4K to 16K broke the build on HP-UX 9. Put it back to
+4K. 9 Apr 2010.
+
+John Dunlap, running days-long stress tests between E-Kermit and C-Kermit,
+found a bug in the packet-reading and -decoding code: If a NAK packet
+arrives with its length field corrupted to indicate a bigger size, and there
+are enough bytes following in the pipeline, ttinl() will return a too-long
+packet (if there are not enough bytes waiting to be read, then ttinl() will
+properly time out). In the bad case rpack() trusts the packet length, uses
+it as the basis for computation of the block-check length, which is then
+used to access memory that might not be there, causing (at least on John's
+Linux system) a segmentation fault. John added the normal clause to check
+the result of the block-check calculation, and I changed ttinl() to always
+break on the eol character (normally carriage return), since this can never
+appear in a packet, even if we "set control unprefix all". Also added a
+check to ttinl() to protect against length fields corrupted into illegal
+values. ckcfn2.c, ckutio.c, 13 Apr 2010.
+
+From Lewis McCarthy:
+ Based on code inspection, C-Kermit appears to have an SSL-related security
+ vulnerability analogous to that identified as CVE-2009-3767 (see e.g.
+ http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3767).
+
+ I'm attaching a patch for this issue relative to the revision of ck_ssl.c
+ obtained from a copy of http://www.columbia.edu/kermit/ftp/test/tar/x.zip
+ downloaded on 2010/07/30, which I believe is the latest.
+
+ When this flaw was first widely publicized at last year's Black Hat
+ conference, it was claimed that some public certificate authorities had
+ indeed issued certificates that could be used to exploit this class of
+ vulnerability. As far as I know they have not revealed specifically which
+ public CA(s) had been found issuing such certificates.
+ Some references: http://www.mseclab.com/?p=180
+ http://www.theregister.co.uk/2009/07/30/universal_ssl_certificate/
+
+Patches added to ck_ssl.c, 4 Aug 2010.
+
+Peter Eichhorn reported that "RENAME ../x ." didn't work. This is a side
+effect of the changes of 2006 to the RENAME command, there was a little
+confusion in the renameone() routine; fixed in ckuus6.c, 4 Aug 2010.
+
+If only one file is FOPEN'd, FCLOSE given with no arguments would close it.
+Turns out to be a bad idea. Example: program with an input and output file,
+try to close the output file before it is opened by just typing FCLOSE; this
+can mess up the input file. For safety FCLOSE has to require a channel
+number or ALL. ckuus7.c, 4 Aug 2010.
+
+Added \fstrcmp(s1,s2,case,start,length), which has the advantage over IF
+EQU,LGT,LLT that case sensitivity can be specified as a function arg, and
+also substrings can be specified. ckuusr.h, ckuus[24].c, 5 Aug 2010.
+
+The CSV feature of Alpha.06 had a subtle flaw, namely that if the last item
+in a comma separated list was enclosed within doublequotes with a trailing
+space after the closing doublequote, a spurious empty final element would be
+created in the result array. Fixed in cksplit(), ckclib.c, 5 Aug 2010.
+
+---Alpha.07---
+
+The CSV feature of \fsplit() splits a comma-separated list into an array.
+To turn the array back into a comma separated list, \fjoin(&a,\44,1) almost
+works, except for elements contain literal doublequotes, such as:
+
+ Mohammad "The Greatest" Ali
+
+This calls for making a symbolic CSV argument for \fjoin() like the one that
+was made for \fsplit(): \fjoin(&a,CSV). Also \fjoin(&a,TSV) for
+Tab-separated list. Thus if Kermit reads a record in CSV format, splits it
+into an array, and then joins the array back into a CSV record, the result
+will be equivalent to the original, according to the CSV definition. It
+might not be identical, because if the result had extraneous spaces before
+or after the separating commas, these are discarded, but that does not
+affect the elements themselves. Furthermore it is now possible to convert
+a comma-separated list into a tab-separated list, and vice versa (which is
+not a simple matter of changing commas to tabs or vice versa). ckuus4.c,
+12 Aug 2010.
+
+From Joop Boonen 26 Juli 2010: "Added HAVE_LOCKDEV as openSuSE >= 11.3 uses
+lockdev but not baudboy. They use ttylock directly. The program code has
+been added so the the program works without a problem." makefile, ckcdeb.h,
+ckutio.c, ckuus5.c, 23 Aug 2010.
+
+---Alpha.08---
+
+From Gary Mills at the U of Manitoba: convert Solaris version from BSD ptys
+to streams ptys because there are only 48 BSD-style ptys and he was running
+out. No code changes needed, the only change necessary was to add the
+following flags to the makefile target:
+
+ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME
+ -DPUSH_PTEM -DPUSH_LDTERM -DPUSH_TTCOMPAT
+
+makefile, ckcmai.c, 21 Sep 2010.
+
+Testing this in Solaris 9 I see that the DES library disappeared. Added
+code to the solaris9 targets (also used by Solaris 10 and 11) to check for
+this. makefile, 21 Sep 2010.
+
+The Solaris target checked the OpenSSL version automatically to set the
+right flag, the Linux target didn't. Put the OpenSSL-version testing code
+in the Linux target too. makefile, 21 Sep 2010.
+
+A couple minor changes to the tru64-51b makefile targets from Steven Schweda
+but there still are some problems with the Tru64 Unix builds.
+makefile, 21 Sep 2010.
+
+---Alpha.09---
+
+\fcontents(\&a[3]) got an error if the array was declared but its dimension
+was less than 3, which is bad when dealing with (say) an array created
+dynamically by \fsplit(), which might or might not have a third element.
+In case it doesn't -- i.e. in case we are referring to an out of range
+element of any array that is declared -- we should just return a null
+string, as we do with other types of variables that are not defined.
+For that matter, ditto even if the array is not declared; what useful
+purpose is served by throwing an error in this case?
+ckuus4.c, 30 Dec 2010.
+
+cksplit() treats \ as a quoting character. If the source string contains
+backslashes, they are swallowed (or, if doubled, one is kept). That's not
+good for parsing external data, such as lines read from files, where there
+are no quoting rules. This came up when parsing CSV files; as a workaround,
+I made \fsplit() treat backslash as an ordinary character for CSV and TSV
+splitting (a better solution might be yet another argument that specifies
+a quote character). ckclib.c, 30 Dec 2010.
+
+Began converting C-Kermit to Open Source with the Simplified 3-Clause BSD
+license. Updated the text for the INTRO, LICENSE, NEWS, and SUPPORT
+commands. Fixed things so the copyright year to be displayed is defined in
+one place (ck_cryear in ckcmai.c), rather than hardwired into text strings
+all over the place. COPYING.TXT, ckcmai.c, ckuus[256].c, 2 Jun 2011.
+
+When I added MIME synonyms for Kermit character-set names, I left a bogus
+entry in the tables ("windows-1251") that was in the wrong place
+alphabetically, thus preventing most references to file character-set names
+from working right. Removed the bogus entry. ckuxla.c, 2 Jun 2011.
+
+Most combinations work OK, but not translating Cyrillic text from UTF-8
+to Latin/Cyrillic, and probably the same would be true for any case of
+converting from UTF-8 or UCS-2 to anything else. The problem was in
+xgnbyte(), which converts the input stream from the specified character to
+UCS2; it needed to make a special case for when the input file was already
+Unicode. Believe it or not, this problem occurred at least as far back as
+8.0.201 (9.5 years ago) and nobody noticed. So if the fix isn't perfect
+probably nobody will notice that either. ckcfns.c, 3 Jun 2011.
+
+The SET BLOCK CHECK command did not parse all the items in its keyword
+list. Fixed in ckuus3.c, 3 Jun 2011.
+
+For EM-APEX ocean floats project, where buoys in stormy waters have to
+transmit data through an earth satellite using non-error-correcting modems,
+John Dunlap ran exhaustive stress tests of Kermit protocol transfers through
+a simulated connection that injected errors and delays and identified a
+weakness in Kermit protocol when it is used under extremely bad conditions:
+If a data byte of the S packet (or its Ack) is corrupted and the 1-byte
+checksum is also corrupted in such a way that that the checksum matches the
+corrupted data, the two Kermit programs will disagree as to the negotiated
+parameters. For example, if file Sender's RPT field is changed from '~' to
+'^', the receiver will decode the packet incorrectly. Ditto for most of the
+other parameters. The result is that a corrupted file is received but
+reported correct. John suggested a new mode of operation in which the Type
+3 block check is used for all packets. Such a mode can not be negotiated
+because the negotiation packet itself is assumed by all Kermit programs to
+have a 1-byte checksum. Added SET BLOCK-CHECK 5 to the parser (with
+invisible synonym FORCE-3". ckuus3.c, 3 Jun 2011.
+
+Added supporting code for SET BLOCK 5: ckcfn[23].c, ckcpro.w, ckcmai.c,
+ckuus3.c, 3 Jun 2011.
+
+Added code to skip the heuristic that S and I packets always have block
+check type 1. File transfer OK between two C-Kermits with SET BLOCK 5.
+rpack(): ckcfn2.c, 5 Jun 2011.
+
+Made the file receiver put "5" in the block-check-type in its ACK to the
+S-Packet. spar(): ckcfns.c, 5 Jun 2011.
+
+Now the question is: Can we make the file receiver automatically and safely
+recognize a three-byte block check on an incoming S or I packet? It's
+tricky because the block check field is not self-identified, it's just the
+last "n" characters of string indicated by the length field, so correct
+decoding of the packet depends on stateful knowledge of "n". How about this:
+rpack() already knows what type of packet it is, so if it's an S or I packet
+and the 8th byte of the data field is "5" and last 3 bytes, when interpreted
+as the CRC, match the packet contents, then we accept the packet and switch
+to BLOCK 5 mode.
+
+On the other hand, if the "5" was put there by corruption, the CRC should
+catch the error. In that case we NAK the packet and presumably get a
+different version back. There would be no reason to try to re-read the same
+packet with a different block check, because the "5" could not possibly be
+there legitimately unless it had a 3-byte CRC. To be clear, this is
+cheating. We read the packet contents before we know the packet is correct,
+then we check that it *is* correct. I made the 4-line change to rpack()
+and it works OK in the absence of transmission errors. ckcfn2.c, 3 Jun 2011.
+
+So the various combinations should work as desired:
+
+ . Sender and receiver both support and are told to SET BLOCK 5 ("SB5").
+ . Sender SB5, but receiver doesn't support it (errors out).
+ . Sender SB5, receiver supports it but wasn't told (auto-recognizes it).
+ . Receiver SB5 but sender no (errors out).
+
+Note in the last case, the receiver should NOT automatically fall back to
+standard behavior because if the user said SET BLOCK 5 that means every
+packet MUST be protected by CRC to prevent the I/S packets from being
+corrupted.
+
+Installed new HELP SET BLOCK-CHECK text. ckuus2.c, 5 Jun 2011.
+
+Autodownload didn't work when the S or I packet had a 3-byte block check
+because kstart() checked it for a 1-byte checksum. Fixed in kstart(),
+ckcfn2.c, 6 Jun 2011. However, older Kermit versions and programs that
+claim to do "autodownload" will never recognize this type of packet. No
+big deal since even if they did, the transfer would fail anyway.
+
+Added 'FORCE 3' to E-Kermit, called it EK 1.7. The option is "-b 5". Works
+OK for sending and receiving, both with and without the new option. Also
+works with "-b 5" if you send an S packet to it with '5' in the BCT field.
+Changes were minimal, I have them all in ek17.diff.
+
+I could probably also make a new G-Kermit in about 10 minutes, but who cares
+about G-Kermit... We already have two useful Kermit programs that
+interoperate with the new protocol. 6 Jun 2011.
+
+Replaced the very inadequate help texts for functions \fword() and
+\fsplit() with new ones. ckuus2.c, 6 Jun 2011.
+
+There were a couple reports of file corruption that I was saving for later.
+Now that now is later I dug up the messages, files, and logs and it turns
+out that nobody had reported a reproducible case of Kermit corrupting a
+file. There have been non-reproducible cases though, almost certainly due
+to corruption of the S or I packet or its ACK, which is why we now have SET
+BLOCK 5. Even with BLOCK CHECK 5, there is no guarantee that the same thing
+won't happen, it is just far less likely. Even if we added a 32-bit CRC or
+even 64-bit one, there would still be a small chance it could happen.
+
+7 Jun 2011:
+
+Corrected various #ifdefs (or lack of them) when building C-Kermit with
+different combinations of feature-selection options such as NOCSETS, NOICP,
+NOLOCAL, NOSPL, NOUNICODE, etc. ckcfns.c ckcmai.c ckcxla.h ckuus2.c
+ckuus4.c ckuus5.c ckuus6.c ckuusr.c, 7 Jun 2011. After running the script
+that does all these builds (84 of them) I ran it again to make sure that
+none of the changes broke builds that succeeded before the changes were made.
+
+Built OK on Solaris9 ("make solaris9")
+Ditto with Krb5 and OpenSSL 0.9.8q ("make solaris9g+openssl+shadow+pam+zlib")
+
+Built OK on Mac OS X 10.4.11 ("make macosx").
+Also "make macosx+krb5+openssl.
+
+Built OK on Linux RHEL4 ("make linux").
+Built OK on Linux RHEL4 with OpenSSL 0.9.7a ("make linux+ssl").
+Built OK on Linux RHEL5 ("make linux").
+
+"make linux+ssl" fails on RHEL5 because of DES, even though the target
+tests for the presence or absence of the DES libraries. In this case the
+libraries are there but they lack the functions des_ecb3_encrypt,
+des_random_seed, and des_set_odd_parity. The build succeeds as:
+
+ make linux+ssl KFLAGS=-UCK_SSL
+
+Since DES is now considered harmful, Jeff Altman suggests that all OpenSSL
+builds, even for old versions, should omit it ("If you are building with
+openssl and no kerberos or srp, just disable DES. Disabling DES will impact
+telnet and rlogin but it won't matter if you have no ability to negotiate a
+session key").
+
+From Ian Beckwith, patches for Debian Linux:
+ . Change all '-' to '\(hy' in man page (new pedantry): ckuker.nr.
+ . Make IKSD authentication (using PAM) ask for a password when an invalid
+ username has been given, to avoid disclosing which account names are valid:
+ ckufio.c, ckuus7.c.
+ . Fix spelling errors: ckcftp.c, ckuus2.c, ckuker.nr, ckcpro.w, ckuusr.h.
+ . Patch makefile to support install to a staging area with DESTDIR.
+ . Some other patches (mainly for typos) were for plain-text documentation
+ files that were generated from Web pages; I updated the web pages.
+
+A big corporate C-Kermit user has an application where a local C-Kermit
+makes a connection to a remote one, uploads some files, and then if the
+server has any new patch files for the local, it sends the patches and
+does a REMOTE HOST command to run the patch program. This stopped working
+in C-Kermit 6.0 or 7.0 when I put a check to prevent it, because "it makes
+no sense to send REMOTE commands to the local end, because the results are
+sent back to the remote to be displayed on its screen but it has no screen".
+That may be true, but if the user needs to control the local from the
+remote, they should be able to. I removed the checks. This doesn't solve
+the problem of where the output goes; ideally it would go to the local
+screen but I don't see any elegant and simple way to make that change.
+However the output redirectors can still be used with the REMOTE command
+so the results can be captured to a remote file, which could then be sent.
+ckuus7.c, 7 Jun 2011.
+
+Changed SET VARIABLE-EVALUATION to SET COMMAND VARIABLE-EVALUATION, but left
+the former version available. ckuusr.c, 9 Jun 2011.
+
+Documented the SET COMMAND VARIABLE-EVALUATION command, which I added in
+2008. ck90.html, 9 Jun 2011.
+
+Renamed all old Mac OS X makefile targets to have the prefix "old" to avoid
+confusing them with the current targets, and made macosx10 a synonym for
+macosx, so those who used previous makefiles will get a current target
+without having to know the new name. makefile, 9 Jun 2011.
+
+Added XMESSAGE, which is to MESSAGE as XECHO is ECHO: prints the text
+without a line terminator, so it can be continued by subsequent [X]MESSAGE
+commands. ckuusr.[ch], 9 Jun 2011.
+
+Back to "make linux+ssl" on RHEL5... I took the coward's way out and added
+code to the makefile target to check whether the build worked (somebody let
+me know if there is a better way to check), and if not to give a message
+suggesting they "make clean ; make linux+ssl KFLAGS=-UCK_DES". makefile,
+9 Jun 2011.
+
+Noticed that \frecurse() would dump core if called with no arguments.
+Fixed in ckuus4.c, 9 Jun 2011.
+
+Added \q() as an alternative to the more verbose \fliteral() for quoting
+strings that contain characters (like \) that would otherwise be significant
+to Kermit. It's more efficient because it isn't a function call, and 'q'
+is an intuitive letter to mean 'quote'. It also works better than
+\fliteral() because functions treat commas and braces specially. ckuus4.c,
+10 Jun 2011.
+
+Built OK on VMS 8.3 on Alpha, no net. DEC C caught a couple glitches in the
+new code that gcc didn't catch, which I fixed. ckuus[25].c, 10 Jun 2011.
+
+Built OK on VMS 8.3 on Alpha with Multinet 5.3. The SSL build failed but
+I'm not going to worry about it. 10 Jun 2011.
+
+Built OK on NetBSD 5.1. 10 Jun 2011.
+
+Tried to resurrect my old "build-all" machine, an IBM Netfinity 3500 from
+1997 with 20-some mountable bootable hard disks with lots of 1990s OS's on
+them. No dice. I can see the BIOS but not the hard disks. The
+configuration is still correct because it tries to boot from the mountable
+hard disk, but it fails (I tried six different ones).
+
+Tried to resurrect my old Siemens Nixdorf RM 200 MIPS machine. Booted OK,
+headless even, but makes a hellish high-pitched whine, like a dentist drill.
+It's pretty slow too. "make sinix542" (for SINIX 5.4.2) bombed at link
+time on no rdchk(). Fixed by #including <sys/filio.h>. ckutio.c, 10 Jun 2011.
+
+Tried to resurrect my old SCO Xenix 2.3.4 machine, also headless. Amazingly
+it still works; it can't use a monitor but I can Telnet to it. Had to tweak
+some #ifdefs but I got a no-net version built successfully. According to my
+notes, it hasn't been possible to build with TCP/IP since C-Kermit 8.0,
+but how many people ever had SCO Xenix 2.3.4 with TCP/IP anyway? Anyway we
+still have the binaries for C-Kermit 7.0. ckuus4.c, 10 Jun 2011.
+
+Built OK on AIX 5.3. Built OK on Solaris 10. 11 Jun 2011.
+
+Tried harder to revive the build-all machine, now it sort of works, but not
+all of the bootable OS's work. Built C-Kermit 9.0 OK on OpenBSD 3.0. Built
+OK on QNX 4.25 but had to #ifdef references to IXANY in ckutio.c and ckupty.
+Built OK on NetBSD 1.5.1 (2000). Tried "make netbsd+ssl" on this one, it's
+OpenSSL 0.9.5a 1 Apr 2000, but it bombs out in ckuath.c, no big deal.
+Another problem in NetBSD 1.5.2 is that even though off_t is 8, CK_OFF_T
+is 4. Worth noting but not worth fixing unless someone else notices.
+13 Jun 2011.
+
+SuSE 7.0... boots OK but telnet server doesn't work. Can telnet out but
+it's too flaky, connection drops if I try to transfer a file.
+
+OpenBSD 2.5 [1999] OK. Red Hat 7.1 OK. Red Hat 7.1 with OpenSSL 0.9.6
+not OK, same error as with 0.9.5a:
+
+ckuath.c
+In file included from ck_ssl.h:48,
+ from ckuath.c:225:
+/usr/include/openssl/des.h:77: warning: redefinition of `Block'
+ckuat2.h:86: warning: `Block' previously declared here
+/usr/include/openssl/des.h:83: redefinition of `struct des_ks_struct'
+/usr/include/openssl/des.h:91: warning: redefinition of `Schedule'
+ckuat2.h:90: warning: `Schedule' previously declared here
+
+So it appears that OpenSSL support is broken for pre-0.9.7. Tried
+building it again with -UCK_SSL (since the errors are originating from
+from des.h)... But it still failed exactly the same way. I found
+#includes for des.h in ckuath.c and and ck_ssl.h and #ifdef'd them out,
+but it still fails:
+
+In file included from /usr/include/openssl/evp.h:89,
+ from /usr/include/openssl/x509.h:67,
+ from /usr/include/openssl/ssl.h:69,
+ from ck_ssl.h:51,
+ from ckuath.c:227:
+/usr/include/openssl/des.h:77: warning: redefinition of `Block'
+ckuat2.h:86: warning: `Block' previously declared here
+/usr/include/openssl/des.h:83: redefinition of `struct des_ks_struct'
+/usr/include/openssl/des.h:91: warning: redefinition of `Schedule'
+ckuat2.h:90: warning: `Schedule' previously declared here
+
+Built OK on Debian 2.1. 13 Jun 2011.
+
+On FreeBSD 4.4, it blows up with:
+ckufio.c: In function vpass':
+ckufio.c:8201: conflicting types for 'initgroups'
+/usr/include/unistd.h:154: previous declaration of 'initgroups'
+ckufio.c:8201: warning: extern declaration of 'initgroups' doesn't match global
+one. Fixed by defining NODCLINITGROUPS for FreeBSD in ckufio.c. It might not
+be the right fix, but I don't have a lot of other FreeBSD versions to
+compare with. Anyway now it builds OK on 4.4, and also on FreeBSD 3.3.
+ckufio.c, 13 Jun 2011.
+
+Tried to build on SCO Open Server 5.0.7 but it fails at link time because
+it can't find rdchk(). But it's supposed to be there! Come back to this
+later...
+
+Red Hat 6.1 i386 32/64 linux 2332545
+Red Hat 7.1 i386 32/64 linux 2368528
+Red Hat EL4 i386 32/74 linux 2363067
+Red Hat EL5.6 i386 64 linux 2371279
+Solaris9 sparc 32/64 solaris9 2849896
+Solaris9+ssl sparc 32/64 solaris9 5021764
+Solaris10 sparc 32/64 solaris10 2855776
+QNX i386 32 qnx32 2012323
+NetBSD 1.5.1 i386 32/64 netbsd 2198055
+NetBSD 5.1 i386 32/64 netbsd 2159863
+OpenBSD 2.5 i386 32/64 openbsd 2236036
+Mac OS X 10.6.7 x86_64 64 macosx 2.7M
+Mac OS X 10.4.11 ppc 32/64 macosx 2496304
+Debian 2.1 i386 32/64 linux 2213221
+FreeBSD 4.4 i386 32/64 freebsd 2291333
+FreeBSD 3.3 i386 32/64 freebsd 2147370
+SINIX 5.42 mips 32 sinix542 3319325 (1995)
+SCO Unixware 2.1.3 i386 32 uw213 2242176
+SCO OSR6.0.0 i386 32/64 sco_osr600 2368300
+
+More builds, 14 June 2011:
+
+VMS 6.2 alpha 32 make mn 2556928 No TCP/IP
+VMS 6.2 alpha 32 make m 3112960 UCX 4.0
+Solaris 11 i386 32/64 solaris11 2823860
+Solaris 11 i386 32/64 solaris11+ssl 2993660 OpenSSL 0.9.8l
+NetBSD 5.1 i386 32/64 netbsd+krb5 2307855 Kerberos 5
+Linux Slackware 12.1.0 i386 32/65 linux 2175754
+Linux Fedora 14 i386 32/64 linux 2256514
+Linux Fedora 14 i386 32/64 linux+ssl ....... OpenSSL 1.0.0d
+Linux Fedora 14 i386 32/64 linux+krb 2449614 (*)
+
+(*) make linux+krb5 "LIBS=$LIBS /lib/libk5crypto.so.3 /lib/libcom_err.so.2"
+
+Noticed that netbsd+ssl build on NetBSD 5.1 said "NetBSD 1.5" in its banner.
+Fixed by replacing the old hardwired target with the new "subroutinized"
+target a'la linux+ssl and adapting it to NetBSD. makefile, 15 Jun 2011.
+
+Same deal for Kerberos 5, make a new netbsd+krb5 target and it builds ok,
+at least once one figures out where the Kerberos headers and libs are.
+makefile, 15 Jun 2011.
+
+Same deal for the netbsdnc target, now it simply defined NOCURSES and
+chains to the main netbsd target. makefile, 15 Jun 2011.
+
+Tried to build with Kerberos 5 on Solaris, fails because the DES library
+no longer exists. This one is beyond me, sorry.
+
+Made new targets for MirBSD, mirbsd and mirbsd+ssl, makefile 15 Jun 2011.
+
+In OpenSUSE 11.2 with OpenSSL 0.9.8r we bomb on undefined references from
+various DES library routines. Builds OK without DES.
+
+Various linux+krb5 builds fail because can't find -lgssapi_krb5
+
+SSL builds with OpenSSL < 0.9.7 fail even though there is code to support
+the older SSL.
+
+Fixed some printf %ld vs int instances in the sizeofs section of SHOW FEATURES.
+ckuus5.c, 15 Jun 2011.
+
+Fixed the new linux+ssl target to actually use the SSLINC and SSLLIBS
+definitions, oops. makefile, 15 Jun 2011.
+
+15 June 2011 builds (Beta.01):
+
+AIX 5.3 ppc 32/64 aix+ssl 3283846 OpenSSL 0.9.8m
+NetBSD 5.1 i386 32/64 netbsd 2159863
+NetBSD 5.1 i386 32/64 netbsd+ssl 2350274 OpenSSL 0.9.9-dev
+NetBSD 5.1 i386 32/64 netbsd+krb5 2349627 MIT Krb5 1.6.3
+FreeBSD 8.2 i386 32/64 freebsd 2298414
+FreeBSD 8.2 i386 32/64 freebsd+ssl 2448961 OpenSSL 0.9.8q
+OpenBSD 4.7 i386 32/64 openbsd 2266132
+OpenBSD 4.7 i386 32/64 openbsd+ssl 2409263 OpenSSL 0.9.8k
+MirBSD 10 i386 32/64 mirbsd 2216601
+MirBSD 10 i386 32/64 mirbsd+ssl 2358318 OpenSSL 0.9.8r
+OpenSuse 11.2 x86_64 64 linux 2348468
+OpenSuse 11.2 x86_64 64 linux+ssl (*) 2546540 OpenSSL 0.9.8r
+RHEL 5.6 ia64 64 linux 4390687
+RHEL 5.6 ia64 64 linux+ssl (*) 4775007 OpenSSL 0.9.8e
+Ubuntu 9.10 i386 32/64 linux 2275523
+Ubuntu 9.10 i386 32/64 linux+ssl 2466708 OpenSSL 0.9.8r
+Gentoo 1.12.13 ppc 32/64 linux 2386597
+Gentoo 1.12.13 ppc64 64 linux 2749015
+Gentoo 1.12.13 ppc64 64 linux+ssl 3002150 OpenSSL 0.9.8r
+Gentoo 1.12.13 sparc 32/64 linux 2478382
+Gentoo 1.12.13 sparc 32/64 linux+ssl 2690499 OpenSSL 0.9.8r
+Solaris 9 sparc 32/64 solaris9 2849896
+Solaris 10 i386 32/64 solaris10 2837620
+IRIX 6.5 R10000 32/64 irix65 2869704
+
+* and KFLAGS=-UCK_DES
+
+Tried building on NetBSD 5.1 with Heimdal Kerberos using:
+
+make netbsd+krb5 \
+ "KFLAGS=-DHEIMDAL" \
+ "K5INC=-I/usr/include" \
+ "K5LIB=-L/usr/lib"
+
+It found all its headers OK, but it blew up in ckuath.c. Small wonder,
+ckccfg.html says:
+
+HEIMDAL
+ Should be defined if Kerberos V support is provided by HEIMDAL. Support
+ for this option is not complete in C-Kermit 8.0. Anyone interested in
+ working on this should contact kermit-support.
+
+'krb5-config --version' gives the MIT Kerberos 5 version number.
+
+Make a new netbsd+krb5+ssl target based on the combination of the new
+netbsd+ssl and netbsd+krb5 targets. There were lots of warnings in the
+compilation but no errors, but it produced an executable that starts and
+does normal things but I have no idea if the SSL or Kerberos functions work.
+makefile, 16 Jun 2011.
+
+Changed the cu-solaris9-krb5 target to test for the presence of DES because
+DES isn't there, to see if this would allow a Kerberos build to proceed.
+And it worked, amazing. At least the build completed, I have no way to test
+the Kerberos part. makefile, 16 Jun 2011.
+
+Updated the solaris9+ssl target to do the DES testing. makefile, 16 Jun 2011.
+
+Updated cu-solaris+krb5 target to test whether the GSSAPI library is called
+libgassapi or libgassapi_krb5. makefile, 16 Jun 2011.
+
+Added lots of tests to the Linux Kerberos 5 entries, linux+krb5 and
+linux+krb5+ssl, because some have libk5crypto and some don't; some have
+libcom_err and some don't; and some have libgssapi_krb5 (e.g. RHEL5,
+OpenSuse 11.2) whereas others have libgssapi (Gentoo).
+
+16 June 2011 builds (Beta.01):
+
+NetBSD 5.1 i386 32/64 netbsd+krb5+ssl 2451757 OpenSSL 0.9.9 MIT Krb5 1.6.3
+Solaris 9 sparc 32/64 solaris9+krb5 2543036 MIT Kerberos 5 1.7.1
+Solaris 9 sparc 32/64 solaris9+ssl 5021544 OpenSSL 0.9.8q (gcc)
+Gentoo... ppc 32/64 linux 2386597
+Gentoo... ppc 32/64 linux+ssl 2593561 OpenSSL 0.9.8r
+Gentoo... ppc64 64 linux 2749015
+Gentoo... ppc64 64 linux+ssl 3002150 OpenSSL 0.9.8r
+RHEL5 x86_64 64 linux+krb5 (*) 2563878 MIT Kerberos 5 1.6.1
+RHEL5 x86_64 64 linux+krb5+ssl(*) 2563878 MIT Kerberos 5 1.6.1
+Fedora 14 i386 32/64 linux+krb5+ssl 2539891 MIT Krb5 + OpenSSL 0.9.8r
+
+* KFLAGS=-UCK_DES
+
+--- C-Kermit 9.0.299 Beta.01 ---
+
+sizeof() can return a long or an int, so neither printf("%d",sizeof(blah));
+or printf("%ld",sizeof(blah)); can be used everywhere. Changed the
+"sizeofs" section of SHOW FEATURES in the dumbest (and therefore most
+portable) way to squelch the warnings. ckuus5.c, 17 Jun 2011.
+
+From John Dunlap: "Watching the server screen led me to offer a cosmetic
+patch for ckuusx.c. I noticed that the server screen said it was
+"RESENDING" when it really wasn't. The attached patch emits blanks to
+insure that old labels are completely erased." ckuusx.c, 17 Jun 2011.
+
+Nelson Beebe found two places where I had SSLLIBS in the makefile instead of
+SSLLIB. makefile, 18 Jun 2011.
+
+More important he knew how to force gcc to load the right header files for
+OpenSSL 1.0.0d (by using '-isystem' rather than '-I'). Previously it was
+using the 0.9.8r header files but linking with the 1.0.0d libraries. This
+is not in the sources or makefile; it's done when giving the 'make' command:
+
+ export PATH=/usr/bin:$PATH
+ export SSLINC=-isystem/usr/include
+ export "SSLLIB=-L/usr/lib -Wl,-rpath,/usr/lib"
+ make linux+ssl
+
+Folded the previous linux+openssl+zlib+shadow+pam and linux+openssl+shadow
+targets into linux+ssl. Checked the linuxso (scripting only) target, builds
+OK, 600K. Made new subroutinized linux+krb5+krb4 target but can't find
+anyplace to test it. Made new subroutinized linux+shadow+pam target, works
+fine on RHEL4. Revised comments and lists again. makefile, 18 Jun 2011.
+
+For the pluggable-disk OS's that boot OK but lack a working network, I
+rigged up a serial connection using a DB9-FF null modem cable, and then a
+DB9-MF modem cable to make it reach. I don't see any modem signals on
+either end, but the data goes through OK. COM1 on the desktop PC,
+/dev/ttyS1 or whatever on Lab. Since there are no modem signals, can't use
+RTS/CTS. At 57600bps with Xon/Xoff, 500-byte packets and sliding windows,
+transfers work OK at about 5000cps using 5 window slots; takes 8 minutes to
+transfer the gzipped C-Kermit tarball. Kermit to the rescue. 19 Jun 2011.
+
+Transferred the tarball over serial ports to SCO OSR5.0.5 at 38.4Kbps, the
+highest speed supported, 12 minutes, no errors, 3300cps. Unpack, make
+sco32v505udk, OK. Also built the TCP/IP version and it almost made an
+outbound connection, but only once (not a Kermit problem but something with
+the TCP/IP stack). 19 Jun 2011.
+
+Ditto for Solaris 2.6/i386, except 57.6Kbps, 4K-byte packets, no problem.
+Solaris 8/i386, ditto. 19 Jun 2011.
+
+SCO OpenServer 5.0.5 i386 32 sco32v505udk 1940964 No TCP/IP
+SCO OpenServer 5.0.5 i386 32 sco32v505udknet 2314668 With TCP/IP
+Sun Solaris 2.6 i386 32 solaris26g 4661368
+Sun Solaris 8 i386 32 solaris8g 4675432
+
+When using compact substring notation, \s(xx[4]) returns the whole string
+xx starting at position 4, but \s(xx[4:]) returns an empty string. Fixed
+the latter to be like the former. ckuus5.c, 20 Jun 2010.
+
+Really it would have been nicer if \s(xx[4]) returned a single character,
+the 4th character of xx, but it's too late now. Added another "separator"
+character '.' (period) for that: \s(xx[4.]) is the 4th character of xx.
+ckuus4.c, 20 Jun 2010.
+
+Back to SCO OSR5.0.7... This failed before because 'rdchk' came up unknown
+at link time, unlike all previous OSR5's, that used rdchk() in place of the
+FIONREAD ioctl. Added #ifdefs to make a special case for 5.0.7. I'm not
+sure this is the best way, but this is the minimal change to get it to work.
+If anybody cares, maybe the same can be done for previous OSR5 releases.
+ckutio.c, 20 Jun 2010 (search for SCO_OSR507).
+
+SCO OpenServer 5.0.7 i386 32 sco32v507 1895724 No TCP/IP
+SCO OpenServer 5.0.7 i386 32 sco32v507net 2246792 With TCP/IP
+
+Checked current code on RHEL4, found that my GSSAPI-lib finding makefile
+target didn't look in enough places; added some more. makefile, 21 Jun 2011.
+
+Got reports back on HPUX from Peter Eichhorn, almost all good on HP-UX 7, 8,
+9, 10, and 11. 21-22 Jun 2011.
+
+Got access to Debian 5.0 and 7-to-be ("Wheezy/Sid"). Regular 'make linux' is
+OK in Debian 5, but in 7 can't find crypt, res_search, or dn_expand; had
+to add more library search clauses to 'make linux'. makefile, 21 Jun 2011.
+
+In Debian 7.0, libk5crypto could not be found without adding another clause
+to 'make linux+krb5'. That done, the SSL build (1.0.0d) was OK, as well as
+the krb5+ssl one. makefile, 21 Jun 2011.
+
+I found a Linux box that had both Kerberos 4 and 5 installed and tried 'make
+linux+krb5+krb4', which failed because of missing DES functions. Tried
+'make linux+krb5+krb4 KFLAGS=-UCK_DES', but that fails too, even though it
+doesn't fail for Kerberos 5 alone, so probably some Krb4 code is making
+unguarded calls to the DES routines. What is really needed is a way to
+completely strip all DES references from any given build, code and makefile,
+a big deal. 21 Jun 2011.
+
+Fixed some typos in COPYING.TXT (noticed by Ian Beckwith). 24 Jun 2011.
+
+Got access to perhaps the last living 4.3BSD VAX system. It doesn't have
+SEEK_CUR so I had to #ifdef out the \fpicture() function. Aside from that,
+no problems. ckuus4.c, 24 Jun 2011.
+
+I had been wanting the S-Expression (ROUND x) to allow a second argument n,
+which, if given, tells where the rounding should occur. If n is positive,
+the number is rounded to n decimal places. If zero, it is rounded to the
+nearest integet. If positive, the number is rounded to the nearest power of
+10; e.g. -2 means "to the nearest hundred". If ROUND is used as before,
+with one argument, it works as before. ckclib.c, ckuus3.c, 25 Jun 2011.
+
+From Arthur Marsh, a few more directories to test for libresolv in Linux.
+makefile, 26 Jun 2011.
+
+From Martin Vorlaender, a fix for the VMS file-transfer display and
+statistics, a place where a file length wasn't being cast to CK_OFF_T
+in zchki(). ckvfio.c, 28 Jun 2011.
+
+Updated version to 9.0.300 and removed the Beta designation.
+ckcmai.c, makefile, 28 Jun 2011.
+
+Removed solaris9_64 target from makefile. It builds but it doesn't work
+at all. 30 Jun 2011.
+
+--- C-Kermit 9.0.300 ---
+
+On Solaris 10 and 11, DNS lookups don't work. It seems these Solaris
+versions have INADDRX and INADDRX_NONE defined, thus triggering the code in
+ckcnet.c, ckucns.c, and ckcftp.c #ifdef'd on these symbols, but that code
+doesn't work in this case. This happens building with gcc as well as with
+Sun cc. Put #ifdefs in ckcnet.h to undefine these symbols (if they are
+defined after including all the header files) for Solaris. I didn't bother
+trying to differentiate the Solaris versions because the symbols are not
+defined in Solaris 9 or earlier, and they should not be used in Solaris 10
+or 11. ckcnet.h, 6 July 2011.
+
+From SMS: To avoid the %CC-W-PTRMISMATCH1 complaints from ck_ssl.c, add
+two (harmless) type casts at lines 2460 and 2773, 6 July 2011.
+
+Built and tested on Solaris 9, Solaris 10, and RHEL5. 6 July 2011.
+
+--- C-Kermit 9.0.301 Beta.01 ---
+
+Updated version text and date. ckcmai.c, makefile, 11 July 2011.
+
+--- C-Kermit 9.0.301 ---
+
+After the initial release I made some small changes that affect only HP-UX
+5.x: added -DVOID=void and -DCKVOID=void to the hpux0500 makefile targets,
+and put #ifdefs around #include <errno.h>, which (in the WinTCP case) didn't
+protect itself against multiple inclusion (which is happening in other
+header files, not in Kermit). makefile, ckucmd.c, ckucon.c, ckutio.c,
+ckufio.c, ckcnet.c, ckcftp.c, 14 July 2011.
+
+In the new copyright notice, copied from the BSD license template,
+one instance of "the <ORGANIZATION>" was not replaced by "Columbia
+University". Fixed in ckcmai.c, 19 July 2011.
+
+Added another search term for lk5crypto in the linux+krb5 targets.
+makefile, 20 July 2011.
+
+Added and successfully used a new solaris9+krb5+ssl target.
+makefile, 8 Aug 2011.
+
+FreeBSD 9 switched from utmp to utmpx, which broke compilation of Kermit on
+that version. Furthermore, the UUCP lockfile convensions changed in FreeBSD
+8, which did not prevent C-Kermit from compiling, but any attempt to lock a
+terminal or pty device would fail. Thanks to Alexey Dokuchaev "danfe" for
+finding and patching the problems. I undid the patches and fixed the code
+so it didn't need to be patched, except for some declarations in the
+ck_crp.c module, which I felt had better not be changed without thoroughly
+testing the changes on dozens of different platforms, which I don't have
+time to do (in any case, it builds OK on FreeBSD 9 without the patch). In
+particular I made completely new makefile targets for FreeBSD 4.0 and later,
+which automatically detect FreeBSD 8 and FreeBSD 9 to enable the appropriate
+feature tests in the code, for a regular build and a build with OpenSSL.
+These changes should affect only FreeBSD. ckutio.c, ckufio.c, ck_crp.c,
+ckuus5.c, makefile, 20 Aug 2011.
+
+Changed the version to 9.0.302, ckcmai.c, 20 Aug 2011.
+
+Fixed freebsd+ssl and netbsd+ssl, netbsd+krb5, and netbsd+krb5+ssl targets
+to have CC=$(CC) instead of CC=gcc; ditto for CC2, and adjusted line breaks
+in freebsd and freebsd+ssl targets. makefile, 21 Aug 2011.
+
+--- 9.0.302 ---
+
+---------------------------------
+***************************
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcasc.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcasc.h
new file mode 100644
index 0000000..68cd2f7
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcasc.h
@@ -0,0 +1,69 @@
+/*
+ File CKCASC.H
+ Mnemonics for ASCII control characters (and Space) for use with C-Kermit.
+*/
+/*
+ Author: Frank da Cruz (fdc@columbia.edu).
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef CKCASC_H
+#define CKCASC_H
+
+#define NUL '\0' /* Null Ctrl-@*/
+#define SOH 1 /* Start of header Ctrl-A */
+#define STX 2 /* Ctrl-B */
+#define ETX 3 /* Ctrl-C */
+#define EOT 4 /* Ctrl-D */
+#define ENQ 5 /* ENQ Ctrl-E */
+#define ACK 6 /* Ctrl-F */
+#define BEL 7 /* Bell (Beep) Ctrl-G */
+#define BS 8 /* Backspace Ctrl-H */
+#define HT 9 /* Horizontal Tab Ctrl-I */
+#define LF 10 /* Linefeed Ctrl-J */
+#define VT 11 /* Vertical Tab Ctrl-K */
+#define NL '\n' /* Newline */
+#define FF 12 /* Formfeed Ctrl-L */
+#define CR 13 /* Carriage Return Ctrl-M */
+#define SO 14 /* Shift Out Ctrl-N */
+#define SI 15 /* Shift In Ctrl-O */
+#define DLE 16 /* Datalink Escape Ctrl-P */
+#define XON 17 /* XON Ctrl-Q */
+#define DC1 17
+#define DC2 18 /* Ctrl-R */
+#define XOFF 19 /* XOFF Ctrl-S */
+#define DC3 19
+#define DC4 20 /* Ctrl-T */
+#define NAK 21 /* Ctrl-U */
+#define SYN 22 /* SYN, Ctrl-V */
+#define ETB 23 /* Ctrl-W */
+#define CAN 24 /* CAN, Ctrl-X */
+#define XEM 25 /* Ctrl-Y (was EM but conflicts with OpenSSL) */
+#define SUB 26 /* SUB Ctrl-Z */
+#define ESC 27 /* Escape Ctrl-[ */
+#define XFS 28 /* Field Separator, Ctrl-Backslash */
+#define XGS 29 /* Group Separator, Ctrl-Rightbracket */
+#define XRS 30 /* Record Separator, Ctrl-Circumflex */
+#define US 31 /* Unit Separator, Ctrl-Underscore */
+#define SP 32 /* Space */
+#define DEL 127 /* Delete (Rubout) */
+#define RUB 127 /* Delete (Rubout) */
+
+#ifdef OS2
+/*
+ These are needed in OS/2, so let's not cause any unnecessary conflicts.
+*/
+#define _CSI 0233 /* 8-bit Control Sequence Introducer */
+#define _SS2 0216 /* 8-bit Single Shift 2 */
+#define _SS3 0217 /* 8-bit Single Shift 3 */
+#define _DCS 0220 /* 8-bit Device Control String Introducer */
+#define _ST8 0234 /* 8-bit String Terminator */
+#define _OSC 0235 /* 8-bit Operating System Command */
+#define _PM8 0236 /* 8-bit Privacy Message */
+#define _APC 0237 /* 8-bit Application Program Command */
+#endif /* OS2 */
+#endif /* CKCASC_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcbwr.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckcbwr.txt
new file mode 100644
index 0000000..533c946
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcbwr.txt
@@ -0,0 +1,1514 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+ As of: C-Kermit 9.0.300, 30 June 2011
+ This page last updated: Tue Jun 28 08:54:30 2011 (New York USA Time)
+
+ IF YOU ARE READING A PLAIN-TEXT version of this document, it is a
+ plain-text dump of a Web page. You can visit the original (and
+ possibly more up-to-date) Web page here:
+
+ [11]http://www.columbia.edu/kermit/ckcbwr.html
+
+ This document contains platform-independent C-Kermit hints and tips.
+ Also see the platform-specific C-Kermit hints and tips document for
+ your platform, for example:
+
+ [12]http://www.columbia.edu/kermit/ckubwr.html
+
+ for Unix. This document also applies to [13]Kermit 95 for Windows,
+ which is based on C-Kermit.
+
+ [ [14]C-Kermit ] [ [15]TUTORIAL ]
+
+CONTENTS
+
+ 0. [16]PATCHES
+ 1. [17]INCOMPATIBLE CHANGES
+ 2. [18]THE C-KERMIT COMMAND PARSER
+ 3. [19]MULTIPLE SESSIONS
+ 4. [20]NETWORK CONNECTIONS
+ 5. [21]MODEMS AND DIALING
+ 6. [22]DIALING HINTS AND TIPS
+ 7. [23]TERMINAL SERVERS
+ 8. [24]TERMINAL EMULATION
+ 9. [25]KEY MAPPING
+ 10. [26]FILE TRANSFER
+ 11. [27]SCRIPT PROGRAMMING
+
+0. PATCHES
+
+ [ [28]Top ] [ [29]Contents ] [ [30]Next ]
+
+ Source-level patches for C-Kermit 8.0.211:
+
+ (None)
+
+1. INCOMPATIBLE CHANGES
+
+ [ [31]Top ] [ [32]Contents ] [ [33]Next ]
+
+ These are not necessarily exhaustive lists.
+
+1.1. C-Kermit 6.0
+
+ C-Kermit 6.0 was released 6 September 1996 and is completely documented
+ in [34]Using C-Kermit, 2nd Edition. The following incompatible changes
+ were made in C-Kermit 6.0:
+
+ * Unless you tell C-Kermit otherwise, if a serial or network
+ connection seems to be open, and you attempt to EXIT or to open a
+ new connection, C-Kermit warns you that an active connection
+ appears to be open and asks you if you really want to close it. If
+ you do not want these warnings, add SET EXIT WARNING OFF to your
+ customization file or script, or give this command at the prompt.
+ * The default for SET { SEND, RECEIVE } PATHNAMES was changed from ON
+ to OFF, to prevent unexpected creation of directories and
+ depositing of incoming files in places you might not know to look.
+ * The default for SET FILE INCOMPLETE was changed from DISCARD to
+ KEEP to allow for file transfer recovery.
+ * The default file-transfer block-check is now 3, rather than 1. If
+ the other Kermit does not support this, the two will drop back to
+ type 1 automatically unless the other Kermit fails to follow the
+ protocol specification.
+ * The default flow-control is now "auto" ("do the right thing for
+ each type of connection"), not Xon/Xoff.
+ * Backslash (\) is no longer a command continuation character. Only -
+ (hyphen, dash) may be used for this in C-Kermit 6.0 and later.
+ * Negative INPUT timeout now results in infinite wait, rather than 1
+ second.
+
+1.2. C-Kermit 7.0
+
+ C-Kermit 7.0 was released 1 January 2000. Its new features are
+ documented in the C-Kermit 7.0 Supplement,
+ [35]http://www.columbia.edu/kermit/ckermit2.html. The following
+ incompatible changes were made in C-Kermit 7.0:
+ * The "multiline GET" command is gone. Now use either of the
+ following forms instead:
+ get remote-name local-name
+ get /as-name:local-name remote-name
+
+ If either name contains spaces, enclose it in braces (or, in
+ C-Kermit 8.0, doublequotes).
+ * To include multiple file specifications in a GET command, you must
+ now use MGET rather than GET:
+ mget file1 file2 file3 ...
+
+ * C-Kermit 7.0 and later use FAST Kermit protocol settings by
+ default. This includes "unprefixing" of certain control characters.
+ Because of this, file transfers that worked with previous releases
+ might not work in the new release especially against a
+ non-Kermit-Project Kermit protocol implementation (but it is more
+ likely that they will work, and much faster). If a transfer fails,
+ you'll get a context-sensitive hint suggesting possible causes and
+ cures. Usually SET PREFIXING ALL does the trick.
+ * By default C-Kermit 7.0 and later send files in text or binary mode
+ by looking at each file to see which is the appropriate mode. To
+ restore the previous behavior, put SET TRANSFER MODE MANUAL and the
+ desired SET FILE TYPE (TEXT or BINARY) in your C-Kermit
+ initialization file.
+ * The RESEND and REGET commands automatically switch to binary mode;
+ previously if RESEND or REGET were attempted when FILE TYPE was
+ TEXT, these commands would fail immediately, with a message telling
+ you they work only when the FILE TYPE is BINARY. Now they simply do
+ this for you.
+ * SET PREFIXING CAUTIOUS and MINIMAL now both prefix linefeed (10 and
+ 138) in case rlogin, ssh, or cu are "in the middle", since
+ otherwise <LF>~ might appear in Kermit packets, and this would
+ cause rlogin, ssh, or cu to disconnect, suspend,escape back, or
+ otherwise wreck the file transfer. Xon and Xoff are now always
+ prefixed too, even when Xon/Xoff flow control is not in effect,
+ since unprefixing them has proven dangerous on TCP/IP connections.
+ * In UNIX, VMS, Windows, and OS/2, the DIRECTORY command is built
+ into C-Kermit itself rather than implemented by running an external
+ command or program. The built-in command might not behave the way
+ the platform-specific external one did, but many options are
+ available for customization. Of course the underlying
+ platform-specific command can still be accessed with "!", "@", or
+ "RUN" wherever the installation does not forbid. In UNIX, the "ls"
+ command can be accessed directly as "ls" in C-Kermit.
+ * SEND ? prints a list of switches rather than a list of filenames.
+ If you want to see a list of filenames, use a (system-dependent)
+ construction such as SEND ./? (for UNIX, Windows, or OS/2), SEND
+ []? (VMS), etc.
+ * In UNIX, OS-9, and Kermit 95, the wildcard characters in previous
+ versions were * and ?. In C-Kermit 7.0 they are *, ?, [, ], {, and
+ }, with dash used inside []'s to denote ranges and comma used
+ inside {} to separate list elements. If you need to include any of
+ these characters literally in a filename, precede each one with
+ backslash (\).
+ * SET QUIET { ON, OFF } is now on the command stack, just like SET
+ INPUT CASE, SET COUNT, SET MACRO ERROR, etc, as described on p.458
+ of [36]Using C-Kermit, 2nd Edition. This allows any macro or
+ command file to SET QUIET ON or OFF without worrying about saving
+ and restoring the global QUIET value. For example, this lets you
+ write a script that tries SET LINE on lots of devices until it
+ finds one free without spewing out loads of error messages, and
+ also without disturbing the global QUIET setting, whatever it was.
+ * Because of the new "." operator (which introduces assignments),
+ macros whose names begin with "." can not be invoked "by name".
+ However, they still can be invoked with DO or \fexecute().
+ * The syntax of the EVALUATE command has changed. To restore the
+ previous syntax, use SET EVALUATE OLD.
+ * The \v(directory) variable now includes the trailing directory
+ separator; in previous releases it did not. This is to allow
+ constructions such as:
+ cd \v(dir)data.tmp
+
+ to work across platforms that might have different directory
+ notation, such as UNIX, Windows, and VMS.
+ * Prior to C-Kermit 7.0, the FLOW-CONTROL setting was global and
+ sticky. In C-Kermit 7.0, there is an array of default flow-control
+ values for each kind of connection, that are applied automatically
+ at SET LINE/PORT/HOST time. Thus a SET FLOW command given before
+ SET LINE/PORT/HOST is likely to be undone. Therefore SET FLOW can
+ be guaranteed to have the desired effect only if given after the
+ SET LINE/PORT/HOST command.
+ * Character-set translation works differently in the TRANSMIT command
+ when (a) the file character-set is not the same as the local end of
+ the terminal character-set, or (b) when the terminal character-set
+ is TRANSPARENT.
+
+1.3. C-Kermit 8.0
+
+ The following incompatible changes were made in C-Kermit 8.0:
+ * C-Kermit now accepts doublequotes in most contexts where you
+ previously had to use braces to group multiple words into a single
+ field, or to force inclusion of leading or trailing blanks. This
+ might cause problems in contexts where you wanted the doublequote
+ characters to be taken literally. Consult [37]Section 5 of the
+ [38]C-Kermit 8.0 Update Notes for further information.
+ * Using the SET HOST command to make HTTP connections is no longer
+ supported. Instead, use the new [39]HTTP OPEN command.
+
+1.4. C-Kermit 9.0
+
+ The [40]\fsplit() function is incredibly handy, it can do almost
+ anything, up to and including parsing a LISP program (the underlying
+ code is the basis of the [41]S-Expression interpreter). But did you
+ ever try to use it to parse (say) a Tab-Separated-List (TSV file) or
+ Comma-Separated-List (CSV)? It works as expected as long as the data
+ contains only 7-bit characters. But if your data contains (say) Spanish
+ or German or Russian text written in an 8-bit character set such as ISO
+ 8859-1, every 8-bit character (any value 128-255) is treated as a break
+ character. This is fixed in C-Kermit 9.0 by treating all 8-bit bytes as
+ "include" characters rather than break characters, a total reversal of
+ past behavior. I don't think it will affect anyone though, because if
+ this had happened to anyone, I would have heard about it!
+
+ Since most standard 8-bit character sets have control characters in
+ positions 128-160, it might have made sense to keep 128-160 in the
+ break set, but with the proliferation of Microsoft Windows code pages,
+ there is no telling which 8-bit character is likely to be some kind of
+ text, e.g. "smart quotes" or East European or Turkish accented letters.
+
+2. THE C-KERMIT COMMAND PARSER
+
+ [ [42]Top ] [ [43]Contents ] [ [44]Next ] [ [45]Previous ]
+
+ Various command-related limits are shown in the following table, in
+ which the sample values are for a "large memory model" build of
+ C-Kermit, typical for modern platforms (Linux, Solaris, AIX, VMS, etc).
+ You can see the values for your version of Kermit by giving the SHOW
+ FEATURES command. The maximum length for a Kermit command (CMDBL) also
+ determines the maximum length for a macro definition, since DEFINE is
+ itself a command. The maximum length for a variable name is between 256
+ and 4096 characters, depending on the platform; for array declarations
+ and references, that includes the subscript.
+
+ Item Symbol Sample
+ Value Definition
+ Number of characters in a command CMDBL 32763 ckucmd.h
+ Number of chars in a field of a command ATMBL 10238 ckucmd.h
+ Nesting level for command files MAXTAKE 54 ckuusr.h
+ Nesting level for macros MACLEVEL 128 ckuusr.h
+ Nesting level for FOR / WHILE loops FORDEPTH 32 ckuusr.h
+ Number of macros MAC_MAX 16384 ckuusr.h
+ Size of INPUT buffer INPBUFSIZ 4096 ckuusr.h
+ Maximum files to match a wildcard MAXWLD 102400 ckcdeb.h
+ Filespecs in MSEND command MSENDMAX 1024 ckuusr.h
+ Length for GOTO target label LBLSIZ 50 ckuusr.h
+ \fexecute() recursion depth limit CMDDEP 64 ckucmd.h
+
+ If you need to define a macro that is longer than CMDBL, you can break
+ the macro up into sub-macros or rewrite the macro as a command file. In
+ a pinch you can also redefine CMDBL and recompile C-Kermit. All of
+ these numbers represent tradeoffs: the bigger the number, the more
+ "powerful" Kermit in the corresponding area, but also the bigger the
+ program image and possibly disk footprint, and the longer it takes to
+ load and initialize.
+
+ In the interactive command parser:
+
+ * EMACS- or VI-style command line editing is not supported.
+ * Editing keys are hardwired (Ctrl-U, Ctrl-W, etc).
+
+ If you interrupt C-Kermit before it has issued its first prompt, it
+ will exit. This means that you cannot interrupt execution of the
+ initialization file, or of an "application file" (file whose name is
+ given as the first command-line argument), or of an alternative
+ initialization file ("-y filename"), and get to the prompt. There is,
+ however, one exception to this rule: you *can* interrupt commands --
+ including TAKE commands -- given in the '-C "command list"'
+ command-line argument and -- if there were no action commands among the
+ command-line arguments -- you will be returned to the C-Kermit prompt.
+ So, for example, if you want to start C-Kermit in such a way that it
+ executes a command file before issuing its first prompt, and you also
+ want to be able to interrupt the command file and get to the prompt,
+ include a TAKE command for the desired command in the -C argument, for
+ example:
+
+ kermit -C "take dial.scr"
+
+ At the command prompt, if you use the backslash (\) prefix to enter a
+ control character, space, or question mark into a command literally,
+ the backslash disappears and is replaced by the quoted character. If it
+ was a control character, it is shown as a circumflex (^). This allows
+ editing (backspace, delete, Ctrl-W) to work correctly even for control
+ characters.
+
+ Priot to C-Kermit 8.0, the only way to include a comma literally in a
+ macro definition -- as opposed to having it separate commands within
+ the definition -- is to enter its ASCII value (44) in backslash
+ notation, e.g.:
+
+ DEFINE ROWS RUN MODE CO80\{44}\%1
+
+ In C-Kermit 8.0 you can use constructions like this:
+
+ DEFINE ROWS RUN MODE "CO80,\%1"
+
+ If you quote special characters in a filename (e.g. in the SEND
+ command), filename completion may seem to work incorrectly. For
+ example, if you have a file whose name is a*b (the name really contains
+ an asterisk), and you type "send a\\*<ESC>", the "b" does not appear,
+ nor will Ctrl-R redisplay the completed name correctly. But internally
+ the file name is recognized anyway.
+
+ Question-mark help does not work during execution of an ASKQ command.
+ The question marks are simply accepted as text.
+
+ In OUTPUT commands only, \B sends a BREAK signal, \L sends a Long BREAK
+ signal, and \N sends a NUL (ASCII 0). BREAK and Long BREAK are special
+ signals, not characters, and NUL is a character that normally cannot be
+ included in a C string, since it is the C string terminator. If you
+ really want to output a backslash followed by a B, an L, or an N (as is
+ needed to configure certain modems, etc), double the backslash, e.g.
+ "output \\B". In C-Kermit 7.0 or later, you can disarm and re-arm the
+ special OUTPUT-command escapes (\B, \L, and \N) with SET OUTPUT
+ SPECIAL-ESCAPES { OFF, ON }.
+
+ When using the command-line processor ("kermit -l /dev/tty00 -b 19200",
+ etc), note that in some cases the order of the command-line options
+ makes a difference, contrary to the expectation that order of
+ command-line options should not matter. For example, the -b option must
+ be given after the -l option if it is to affect the device specified in
+ the -l option.
+
+3. MULTIPLE SESSIONS
+
+ [ [46]Top ] [ [47]Contents ] [ [48]Next ] [ [49]Previous ]
+
+ C-Kermit 7.0 and earlier do not support multiple sessions. When you SET
+ LINE (or SET PORT, same thing) to a new device, or SET HOST to a new
+ host, the previous SET LINE device or network host connection is
+ closed, resulting in hangup of the modem or termination of the network
+ connection. In windowing environments like HP-VUE, NeXTSTEP, Windows,
+ OS/2, etc, you can run separate copies of Kermit in different windows
+ to achieve multiple sessions.
+
+ To achieve multiple sessions through a single serial port (e.g. when
+ dialing up), you can install SLIP or PPP on your computer and then use
+ C-Kermit's TCP/IP support over the SLIP or PPP connection, assuming you
+ also have TCP/IP networking installed on your computer.
+
+ C-Kermit 8.0 has the same restriction on SET LINE and SET HOST
+ sessions: only one regular session (dialout, Telnet, etc) can be open
+ at a time. However, version 8.0 adds two new kinds of sessions: FTP and
+ HTTP; one or both of these can be open at the same as a regular
+ session.
+
+4. NETWORK CONNECTIONS
+
+ [ [50]Top ] [ [51]Contents ] [ [52]Next ] [ [53]Previous ]
+
+FTP Client Bugs
+
+ The Unix C-Kermit 8.0.206 FTP client had the following bugs at the time
+ most of the 8.0.206 binaries were built for the C-Kermit 8.0 CDROM:
+
+ 1. FTP MGET fails when directory segments contain wildcards, as in
+ "ftp mget */data/*.dat". Work around by doing a separate MGET for
+ each source directory.
+ 2. FTP MGET can fail or produce random side effects if you have a
+ TMPDIR or CK_TMP environment variable definition in effect, or a
+ SET TEMP-DIRECTORY value, longer than 7 characters. Work around by
+ giving a SET TEMP-DIRECTORY command with a short value, such as
+ "/tmp".
+
+ These two bugs are fixed in the source code that is included on the
+ CDROM, and also in Kermit 95 2.1.1. You can tell if a C-Kermit 8.0.206
+ binary has these fixes by typing SHOW VERSION; if it says "FTP Client,
+ 8.0.200, 24 Oct 2002" it has the fixes; if the edit number is less that
+ 200, it doesn't, in which case can build a new binary from the source
+ code (or contact us and we'll try to get get one for you).
+
+Making TCP/IP Connections Can Take a Long Time
+
+ The most frequently asked question in many newsgroups is "Why does it
+ take such a long time to make a Telnet connection to (or from) my
+ (e.g.) Linux PC?" (this applies to Kermit as well as to regular Telnet
+ clients):
+
+ 1. Most Telnet servers perform reverse DNS lookups on the client for
+ security and/or logging reasons. If the Telnet client's host cannot
+ be found by the server's local DNS server, the DNS request goes out
+ to the Internet at large, and this can take quite some time. The
+ solution to this problem is to make sure that both client and host
+ are registered in DNS.
+ 2. C-Kermit itself performs reverse DNS lookups unless you tell it not
+ to. This is to allow C-Kermit to let you know which host it is
+ actually connected to in case you have made a connection to a "host
+ pool" (multihomed host). You can disable C-Kermit's reverse DNS
+ lookup with SET TCP REVERSE-DNS-LOOKUP OFF.
+ 3. C-Kermit 7.0 and later strictly enforce Telnet protocol rules. One
+ such rule is that certain negotiations must be responded to. If
+ C-Kermit sends a such a negotiation and the host does not respond,
+ C-Kermit waits a long time for the reply (in case the network is
+ congested or the host is slow), but eventually will time out. To
+ eliminate the waits (and therefore risk possible protocol
+ mismatches -- or worse -- between Telnet client and server), tell
+ C-Kermit to SET TELNET WAIT OFF (or include the /NOWAIT switch with
+ the TELNET command).
+
+The Rlogin Client
+
+ In multiuser operating systems such as UNIX and VMS, TCP/IP Rlogin
+ connections are available only to privileged users, since "login" is a
+ privileged socket. Assuming you are allowed to use it in the first
+ place, it is likely to behave differently depending on what type of
+ host you are rlogging in to, due to technical reasons having to do with
+ conflicting interpretations of RFC793 (Out-Of-Band Data) and Rlogin
+ (RFC1122)... "Specifically, the TCP urgent pointer in BSD points to the
+ byte after the urgent data byte, and an RFC-compliant TCP urgent
+ pointer points to the urgent data byte. As a result, if an application
+ sends urgent data from a BSD-compatible implementation to an
+ [54]RFC-1122 compatible implementation then the receiver will read the
+ wrong urgent data byte (it will read the byte located after the correct
+ byte in the data stream as the urgent data byte)." Rlogin requires the
+ use of OOB data while Telnet does not. Therefore, it is possible for
+ Telnet to work between all systems while BSD and System V TCP/IP
+ implementations are almost always a bad mix.
+
+The Telnet Client
+
+ On a TCP/IP TELNET connection, you should normally have PARITY set to
+ NONE and (except in VMS C-Kermit) FLOW-CONTROL also set to NONE. If
+ file transfer does not work with these settings (for example, because
+ the remote TELNET server only gives a 7-bit data path), use SET PARITY
+ SPACE. Do not use SET PARITY MARK, EVEN, or ODD on a TELNET connection
+ -- it interferes with TELNET protocol.
+
+ If echoing does not work right after connecting to a network host or
+ after dialing through a TCP/IP modem server, it probably means that the
+ TELNET server on the far end of the connection is executing the TELNET
+ protocol incorrectly. After initially connecting and discovering
+ incorrect echoing (characters are echoed twice, or not at all), escape
+ back, give the appropriate SET DUPLEX command (FULL or HALF), and then
+ CONNECT again. For a consistently misbehaving connection, you can
+ automate this process in a macro or TAKE file.
+
+ TELNET sessions are treated just like serial communications sessions as
+ far as "terminal bytesize" and "command bytesize" are concerned. If you
+ need to view and/or enter 8-bit characters during a TELNET session, you
+ must tell C-Kermit to SET TERMINAL BYTESIZE 8, SET COMMAND BYTESIZE 8,
+ and SET PARITY NONE.
+
+ If you SET TELNET DEBUG ON prior to making a connection, protocol
+ negotiations will be displayed on your screen. You can also capture
+ them in the debug log (along with everything else) and then extract
+ them easily, since all Telnet negotiations lines begin with (uppercase)
+ "TELNET".
+
+The SSH Client
+
+ C-Kermit does not have its own built-in SSH client; instead, in the
+ Unix tradition, uses the external SSH client to do the SSH part, and
+ Kermit does its thing on top -- file transfer, scripting, etc. Under
+ certain circumstances that have not yet been identified, it sometimes
+ happens that after making an SSH connection from C-Kermit, logging out
+ from the remote host, and popping back to the local C-Kermit program,
+ subsequent SSH commands file with a message like "Network type not
+ supported". Starting a new copy of C-Kermit is the workaround.
+
+5. MODEMS AND DIALING
+
+ [ [55]Top ] [ [56]Contents ] [ [57]Next ] [ [58]Previous ]
+
+ External modems are recommended because:
+
+ * They don't need any special drivers.
+ * They are less likely to interfere with normal operation of your
+ computer.
+ * You can use the lights and speaker to troubleshoot dialing.
+ * You can share them among all types of computers.
+ * You can easily turn them off and on when power-cycling seems
+ warranted.
+ * They are more likely to have manuals.
+
+ Modems can be used by C-Kermit only when they are visible as or through
+ a regular serial port device. Certain modems can not be used in this
+ normal way on many kinds of computers: Winmodems, RPI modems,
+ Controllerless modems, the IBM Mwave, etc; all of these require special
+ drivers that perform some, most, or all of the modem's functions in
+ software. Such drivers are generally NOT available in UNIX or other
+ non-Windows (or non-OS/2, in the case of the Mwave) platforms.
+
+ In order to dial a modem, C-Kermit must know the modem's repertoire of
+ commands and responses. Each modem make and model is likely to have a
+ different repertoire. Since Kermit has no way of knowing which kind of
+ modem will be dialed, normally you have to tell it with a SET MODEM
+ TYPE command, e.g.:
+
+ set modem type usrobotics
+ set line /dev/cua0
+ set speed 57600
+ dial 7654321
+
+ In the early days, there was a wide variety of modems and command
+ languages. Nowadays, almost every modem uses the Hayes AT command set
+ (but with some differences in the details) and its startup
+ configuration includes error correction, data compression, and hardware
+ (RTS/CTS) flow control. As long as C-Kermit is capable of hardware flow
+ control (as it is on many, but not all, the platforms where it runs,
+ since some operating systems don't support it), the modem can be dialed
+ immediately, without lengthy configuration dialogs, and in fact this is
+ what SET MODEM TYPE GENERIC-HIGH-SPEED does. In C-Kermit 8.0,
+ GENERIC-HIGH-SPEED has become the default modem type, so now it is
+ usually possible to SET LINE, SET SPEED, and DIAL without having to
+ identify your modem. If this doesn't work, of course, then you might
+ have to fall back to the traditional method: Give a SET MODEM TYPE for
+ a specific modem first, then SET LINE, SET SPEED, and DIAL.
+
+ An important change in C-Kermit 6.0 is that when you give a SET MODEM
+ TYPE command to tell Kermit what kind of modem you have, Kermit also
+ sets a number of other modem-related parameters automatically from its
+ internal modem database. Thus, the order in which you give
+ modem-related commands is significant, whereas in prior releases they
+ could be given in any order.
+
+ In particular, MODEM SPEED-MATCHING is set according to whether the
+ modem is known to be capable of speed buffering. SET MODEM TYPE
+ HAYES-2400 automatically turns SPEED-MATCHING ON, because when the
+ Hayes 2400 reports a particular speed in its CONNECT message, that
+ means its interface speed has changed to that speed, and C-Kermit's
+ must change accordingly if it is to continue communicating. This might
+ cause some confusion if you use "set modem type hayes" for dialing a
+ more advanced type of modem.
+
+ The new default for flow control is "auto", meaning "do the right thing
+ for each type of connection". So (for example) if your version of
+ C-Kermit supports SET FLOW RTS/CTS and your modem also supports
+ RTS/CTS, then Kermit automatically sets its flow control to RTS/CTS and
+ set modem's flow control to RTS/CTS too before attempting to use the
+ modem.
+
+ For these reasons, don't assume that "set modem type hayes" should be
+ used for all modems that uses the Hayes AT command set. "set modem type
+ hayes" really does mean Hayes 1200 or 2400, which in turn means no
+ hardware flow control, and no speed buffering. This choice will rarely
+ work with a modern high-speed modem.
+
+6. DIALING HINTS AND TIPS
+
+ [ [59]Top ] [ [60]Contents ] [ [61]Next ] [ [62]Previous ]
+
+ If you have a high-speed, error-correcting, data-compressing,
+ speed-buffering modem, you should fix the modem's interface speed as
+ high as possible, preferably (at least) four times higher than its
+ maximum connection (modulation) speed to allow compression to work at
+ full advantage. In this type of setup, you must also have an effective
+ means of flow control enabled between C-Kermit and the modem,
+ preferably hardware (RTS/CTS) flow control. On platforms that do not
+ support hardware flow control, it is usually possible to select
+ software flow control (Xon/Xoff), and C-Kermit will do its best to set
+ the modem for local Xon/Xoff flow control too (but then, of course,
+ Ctrl-S and Ctrl-Q characters can not be transmitted on the connection).
+
+ If you are having trouble dialing your modem, SET DIAL DISPLAY ON to
+ watch the dialing interactions between C-Kermit and your modem. Consult
+ Chapters 3-4 of [63]Using C-Kermit (2nd Ed) for modem-dialing
+ troubleshooting instructions. The following sections offer some
+ additional hints and tips.
+
+6.1. Syntax
+
+ If you want to dial a number that starts with #, you'll need to quote
+ the "#" character (as \# or \{35}), since it is also a comment
+ introducer:
+
+ C-Kermit>dial #98765421-1-212-5551212 ; Looks like a comment
+ ?You must specify a number to dial
+ C-Kermit>dial \#98765421-1-212-5551212 ; Works OK
+ C-Kermit>dial =#98765421-1-212-5551212 ; This works too
+
+ When using a dialing directory, remember what happens if a name is not
+ found:
+
+ C-Kermit>dial xyzcorp
+ Lookup: "xyzcorp" - not found - dialing as given
+
+ This normally does no harm, but some modems might behave strangely when
+ given dial strings that contain certain letters. For example, a certain
+ German modem treats any dial string that contains the letter "s" as a
+ command to fetch a number from its internal list, and replies OK to the
+ ATD command, which is normally not a valid response except for partial
+ dialing. To avoid this situation, use:
+
+ lookup xyzcorp
+ if success dial
+
+6.2. The Carrier Signal
+
+ Remember: In many C-Kermit implementations (depending on the underlying
+ operating system -- mostly Windows, OS/2, and System-V-based UNIX
+ versions, and in C-Kermit 7.0, also VMS), you can't CONNECT to a modem
+ and type the modem's dialing command (like "ATDT7654321") manually,
+ unless you first tell C-Kermit to:
+
+ SET CARRIER-WATCH OFF
+
+ This is because (in these implementations), the CONNECT command
+ requires the modem's Carrier Detect (CD) signal to be on, but the CD
+ signal doesn't come on until after dialing is complete. This
+ requirement is what allows C-Kermit to pop back to its prompt
+ automatically when the connection is hung up. See the description of
+ SET CARRIER-WATCH in "Using C-Kermit".
+
+ Similarly, if your dialed connection drops when CARRIER-WATCH is set to
+ AUTO or ON, you can't CONNECT back to the (now disconnected) screen to
+ see what might have happened unless you first SET CARRIER-WATCH OFF.
+ But sometimes not even SET CARRIER-WATCH OFF will help in this
+ situation: certain platforms (for example Unixware 2.1), once carrier
+ drops, won't let the application do i/o with the device any more. In
+ that case, if you want to use the device again, you have to CLOSE it
+ and OPEN it again. Or you can have Kermit do this for you automatically
+ by telling it to SET CLOSE-ON-DISCONNECT ON.
+
+6.3. Dialing and Flow Control
+
+ Don't SET FLOW RTS/CTS if your modem is turned off, or if it is not
+ presenting the CTS signal. Otherwise, the serial device driver can get
+ stuck waiting for this signal to appear.
+
+ Most modern modems support RTS/CTS (if they support any hardware flow
+ control at all), but some computers use different RS-232 circuits for
+ the same purposes, e.g. DTR and CD, or DTR and CTS. In such cases, you
+ might be able to make your computer work with your modem by
+ appropriately cross-wiring the circuits in the cable connector, for
+ example the computer's DTR to the modem's RTS, and modem's CD to the
+ computer's CTS. HOWEVER, C-Kermit does not know you have done this. So
+ if you have (say) SET FLOW DTR/CD, C-Kermit will make no attempt to
+ tell the modem to use RTS/CTS. You probably did this yourself when you
+ configured the modem.
+
+6.4. The Dial Timeout
+
+ If it takes your call longer to be completed than the timeout interval
+ that C-Kermit calculates, you can use the SET DIAL TIMEOUT command to
+ override C-Kermit's value. But beware: the modem has its own timeout
+ for completing the call. If it is a Hayes-like modem, C-Kermit adjusts
+ the modem's value too by setting register S7. But the maximum value for
+ S7 might be smaller than the time you need! In that case, C-Kermit sets
+ S7 to 0, 255, or other (modem-specific) value to signify "no timeout".
+ If Kermit attempts to set register S7 to a value higher than your
+ modem's maximum, the modem will say "ERROR" and you will get a "Failure
+ to initialize modem" error. In that case, use SET DIAL TIMEOUT to
+ override C-Kermit's calculation of the timeout value with the highest
+ value that is legal for your modem, e.g. 60.
+
+6.5. Escape Sequence Guard Time
+
+ A "TIES" (Time-Independent Escape Sequence) modem does not require any
+ guard time around its escape sequence. The following text:
+
+ +++ATH0
+
+ if sent through a TIES modem, for example because you were uploading
+ this file through it, could pop the modem back into command mode and
+ make it hang up the connection. Later versions of the Telebit T1600 and
+ T3000 (version LA3.01E firmware and later), and all WorldBlazers, use
+ TIES.
+
+ Although the probability of "+++" appearing in a Kermit packet is
+ markedly lower than with most other protocols (see the [64]File
+ Transfer section below), it can still happen under certain
+ circumstances. It can also happen when using C-Kermit's TRANSMIT
+ command. If you are using a Telebit TIES modem, you can change the
+ modem's escape sequence to an otherwise little-used control character
+ such as Ctrl-_ (Control-Underscore):
+
+ AT S2=31
+
+ A sequence of three consecutive Ctrl-_ characters will not appear in a
+ Kermit packet unless you go to extraordinary lengths to defeat more
+ than a few of Kermit's built-in safety mechanisms. And if you do this,
+ then you should also turn off the modem's escape-sequence recognition
+ altogether:
+
+ AT S48=0 S2=255
+
+ But when escape sequence recognition is turned off, "modem hangup"
+ (<pause>+++<pause>ATH0<CR>) will not work, so you should also SET MODEM
+ HANGUP RS232-SIGNAL (rather then MODEM-COMMAND).
+
+6.6. Adaptive Dialing
+
+ Some modems have a feature called adaptive dialing. When they are told
+ to dial a number using Tone dialing, they check to make sure that
+ dialtone has gone away after dialing the first digit. If it has not,
+ the modem assumes the phone line does not accept Tone dialing and so
+ switches to Pulse. When dialing out from a PBX, there is almost always
+ a secondary dialtone. Typically you take the phone off-hook, get the
+ PBX dialtone, dial "9" to get an outside line, and then get the phone
+ company's dialtone. In a situation like this, you need to tell the
+ modem to expect the secondary dialtone. On Hayes and compatible modems,
+ this is done by putting a "W" in the dial string at the appropriate
+ place. For example, to dial 9 for an outside line, and then 7654321,
+ use ATDT9W7654321:
+
+ SET PBX-OUTSIDE-PREFIX 9W
+
+ (replace "9" with whatever your PBX's outside-line prefix is).
+
+6.7. The Busy Signal
+
+ Some phone companies are eliminating the busy signal. Instead, they
+ issue a voice message such as "press 1 to automatically redial until
+ the number answers, or...". Obviously this is a disaster for modem
+ calls. If your service has this feature, there's nothing Kermit can do
+ about it. Your modem will respond with NO CARRIER (after a long time)
+ rather than BUSY (immediately), and Kermit will declare the call a
+ failure, rather than trying to redial the same number.
+
+6.8. Hanging Up
+
+ There are two ways to hang up a modem: by turning off the serial port's
+ DTR signal (SET MODEM HANGUP-METHOD RS232-SIGNAL) or sending the modem
+ its escape sequence followed by its hangup command (SET MODEM
+ HANGUP-METHOD MODEM-COMMAND). If one doesn't work, try the other. If
+ the automatic hangup performed at the beginning of a DIAL command
+ causes trouble, then SET DIAL HANGUP OFF.
+
+ The HANGUP command has no effect when C-Kermit is in remote mode. This
+ is on purpose. If C-Kermit could hang up its own controlling terminal,
+ this would (a) most likely leave behind zombie processes, and (b) pose
+ a security risk.
+
+ If you DIAL a modem, disconnect, then SET HOST or TELNET, and then
+ HANGUP, Kermit sends the modem's hangup command, such as "+++ATHO".
+ There is no good way to avoid this, because this case can't reliably be
+ distinguished from the case in which the user does SET HOST
+ terminal-server, SET MODEM TYPE name, DIAL. In both cases we have a
+ valid modem type selected and we have a network connection. If you want
+ to DIAL and then later make a regular network connection, you will have
+ to SET MODEM TYPE NONE or SET DIAL HANGUP OFF to avoid this phenomenon.
+
+7. TERMINAL SERVERS
+
+ [ [65]Top ] [ [66]Contents ] [ [67]Next ] [ [68]Previous ]
+
+ Watch out for terminal server's escape character -- usually a control
+ character such as Ctrl-Circumflex (Ctrl-^). Don't unprefix it in
+ Kermit!
+
+ Ciscos -- must often be told to "terminal download"... Cisco ASM models
+ don't have hardware flow control in both directions.
+
+ Many terminal servers only give you a 7-bit connection, so if you can't
+ make it 8-bit, tell Kermit to "set parity space".
+
+ The following story, regarding trouble transferring 8-bit files through
+ a reverse terminal server, was contributed by an Annex terminal server
+ user:
+
+ Using C-Kermit on an HP 9000 712/80 running the HP-UX 10.00
+ operating system. The HP was connected to a Xylogics Annex
+ MICRO-ELS-UX R7.1 8 port terminal server via ethernet. On the second
+ port of the terminal server is an AT&T Paradyne 3810 modem, which is
+ connected to a telephone line. There is a program which runs on the
+ HP to establish a Telnet connection between a serial line on the
+ Annex and a character special file on the HP (/dev file). This is an
+ Annex specific program called rtelnet (reverse telnet) and is
+ provided with the terminal server software. The rtelnet utility runs
+ on top of the pseudo-terminal facility provided by UNIX. It creates
+ host-originated connections to devices attached ot Annex serial
+ ports. There are several command line arguments to be specified with
+ this program: the IP address of the terminal server, the number of
+ the port to attach to, and the name of the pseudo-device to create.
+ In addition to these there are options to tell rtelnet how to
+ operate on the connect: -b requests negotiation for Telnet binary
+ mode, -d turns on socket-leve debugging, -f enables "connect on the
+ fly" mode, -r removes the device-name if it already exists, etc. The
+ most important of these to be specified when using 8 data bits and
+ no parity, as we found out, was the -t option. This creates a
+ transparent TCP connection to the terminal server. Again, what we
+ assumed to be happening was that the rtelnet program encountered a
+ character sequence special to itself and then "eating" those kermit
+ packets. I think this is all of the information I can give you on
+ the configuration, short of the values associated with the port on
+ the terminal server.
+
+ How to DIAL from a TCP/IP reverse terminal server (modem server):
+
+ 1. (only if necessary) SET TELNET ECHO REMOTE
+ 2. SET HOST terminal-server-ip-name-or-address [ port ]
+ 3. SET MODEM TYPE modem-type
+ 4. (only if necessary) SET DIAL HANGUP OFF
+ 5. (for troubleshooting) SET DIAL DISPLAY ON
+ 6. DIAL phone-number
+
+ The order is important: SET HOST before SET MODEM TYPE. Since this is a
+ Telnet connection, serial-port related commands such as SET SPEED, SET
+ STOP-BITS, HANGUP (when MODEM HANGUP-METHOD is RS232), etc, have no
+ effect. However, in C-Kermit 8.0, if the modem server supports
+ [69]RFC-2217 Telnet Com-Port Control protocol, these commands do indeed
+ take effect at the server's serial port.
+
+8. TERMINAL EMULATION
+
+ [ [70]Top ] [ [71]Contents ] [ [72]Next ] [ [73]Previous ]
+
+ Except for the Windows, OS/2, and Macintosh versions, C-Kermit does not
+ emulate any kind of terminal. Rather, it acts as a "semitransparent
+ pipe", passing the characters you type during a CONNECT session to the
+ remote host, and sending the characters received from the remote host
+ to your screen. Whatever is controlling your keyboard and screen
+ provides the specific terminal emulation: a real terminal, a PC running
+ a terminal emulator, etc, or (in the case of a self-contained
+ workstation) your console driver, a terminal window, xterm, etc.
+
+ Kermit is semitransparent rather than fully transparent in the
+ following ways:
+
+ * During a TELNET ("set host") session, C-Kermit itself executes the
+ TELNET protocol and performs TELNET negotiations. (But it does not
+ perform TN3270 protocol or any other type of 3270 terminal
+ emulation.)
+ * If you have changed your keyboard mapping using SET KEY, C-Kermit
+ replaces the characters you type with the characters or strings
+ they are mapped to.
+ * If you SET your TERMINAL CHARACTER-SET to anything but TRANSPARENT,
+ C-Kermit translates your keystrokes (after applying any SET KEY
+ definitions) before transmitting them, and translates received
+ characters before showing them on your screen.
+ * If your remote and/or local TERMINAL CHARACTER-SET is an ISO 646
+ 7-bit national character set, such as German, French, Italian,
+ Swedish, etc, or Short KOI used for Cyrillic, C-Kermit's CONNECT
+ command automatically skips over ANSI escape sequences to avoid
+ translating their characters. Only ANSI/ISO standard
+ (VT100/200/300-like) 7-bit escape sequence formats are supported
+ for this purpose, no proprietary schemes like H-P, Televideo,
+ Tektronix, etc.
+ * If your version of C-Kermit includes SET TERMINAL APC command, then
+ C-Kermit's CONNECT command will handle APC escape sequences if
+ TERMINAL APC is not set to OFF (which is the default).
+
+ You can make C-Kermit fully transparent by starting it with the -0
+ (dash zero) command-line option.
+
+ If you are running C-Kermit under a console driver, or in a terminal
+ window, that emulates the VT100, and use C-Kermit to log in to a VMS
+ system, the console driver or terminal window (not Kermit) is supposed
+ to reply to the "what are you?" query (ESC Z) from the VAX. If it
+ doesn't, and you can't make it do so, then you can (a) live with the
+ "unknown terminal" problem; (b) tell VMS to SET TERMINAL/DEVICE=VT100;
+ (c) program a key using SET KEY to send the appropriate sequence and
+ then punch the key at the right time; or (d) use the VMSLOGIN macro
+ that is defined in CKERMIT.INI to do this for you automatically.
+
+ SET SESSION-LOG { TEXT, BINARY }, which is effective in UNIX and AOS/VS
+ but not other C-Kermit versions, removes CR, DEL, NUL, XON, and XOFF
+ characters (Using C-Kermit neglects to mention that XON and XOFF are
+ removed). The TEXT-mode setting is ineffective during SCRIPT command
+ execution, as well as on X.25 connections.
+
+9. KEY MAPPING
+
+ [ [74]Top ] [ [75]Contents ] [ [76]Next ] [ [77]Previous ]
+
+ Except in the terminal-emulating versions, C-Kermit's key mapping
+ facilities are limited to normal "ASCII" keys, and cannot be used with
+ function keys, arrow keys, arcane key combinations, etc. Since C-Kermit
+ runs on such a wide variety of hardware platforms (including, for
+ example, more than 360 different UNIX platforms), it is not possible
+ for C-Kermit to support every conceivable keyboard under every release
+ of every UNIX (or VMS, or ...) product on every different kind of
+ computer possibly under all manner of different console drivers, even
+ if it had the means to do so.
+
+ In technical terms, C-Kermit uses the read() function to read
+ keystrokes, and read() returns a single byte (value 0 through 255).
+ C-Kermit's SET KEY function applies to these single-byte codes.
+ "Extended function" keys, such as F-keys, arrow keys, etc, usually
+ return either a 2-byte "scan code" or else a character string (such as
+ an escape sequence like "<ESC> O p"). In both cases, C-Kermit has no
+ way to tell the difference between such multibyte key values, and the
+ corresponding series of single-byte key values. This could only be done
+ by accessing the keyboard at a much lower level in a highly
+ platform-dependent manner, probably requiring tens of thousands of
+ lines of code to support even a sampling of the most popular
+ workstation / OS combinations.
+
+ However, most workstation console drivers (terminal emulation windows,
+ etc) include their own key-mapping facility. For example in AIX, the
+ AIXterm program (in whose window you would run C-Kermit) allows
+ rebinding of the F1-F12 keys to arbitrary strings. The same is true of
+ Xterm and DECterm windows, etc. Consult the technical documentation for
+ your workstation or emulator. See sample Xterm (Xmodmap) mappings in
+ the [78]Unix C-Kermit Hints and Tips document.
+
+ The SET KEY command (except in Kermit 95) does not allow a key
+ definition to be (or contain) the NUL (\0) character.
+
+10. FILE TRANSFER
+
+ [ [79]Top ] [ [80]Contents ] [ [81]Next ] [ [82]Previous ]
+
+ C-Kermit 7.0 is the first release of C-Kermit to use fast (rather than
+ robust and therefore slow) protocol defaults: long packets, sliding
+ windows, control-character unprefixing, and streaming where possible.
+ This makes most transfers (partner willing) dramatically faster "out of
+ the box" but might break some combinations that worked before. If
+ transfers with C-Kermit 7.0 or later fail where transfers worked with
+ earlier C-Kermit versions, try the following (one at a time, in this
+ order):
+
+ 1. SET PREFIXING ALL: Disables control-character unprefixing.
+ 2. SET STREAMING OFF: Disables streaming.
+ 3. CAUTIOUS: Selects medium but cautious protocol settings.
+ 4. ROBUST: this command reverts to the most conservative protocol
+ settings.
+
+ Execution of multiple file transfers by C-Kermit from a command file
+ when in remote mode might exhibit long delays between each transfer. To
+ avoid this, just include the command "SET DELAY 0" in your command file
+ before any of the file-transfer commands.
+
+ File transfer failures can occur for all sorts of reasons, most of them
+ listed in Chapter 10 of [83]Using C-Kermit. The following sections
+ touch on some that aren't.
+
+ The [84]C-Kermit 7.0 Release Notes document SEND /COMMAND as taking an
+ argument, but it doesn't. Instead of SEND /COMMAND:{some command}, use:
+
+SEND /COMMAND [ other switches such as /AS-NAME: ] command [ arguments... ]
+
+10.1. Laptops
+
+ Watch out for laptops and their assorted power-saver features; for
+ example, a built-in modem's "auto timeout delay" hanging up the
+ connection in the middle of a file transfer. Most modems, even if they
+ have this feature, do not have it enabled by default. But if you
+ experience otherwise inexplicable disconnections in the midst of your
+ Kermit sessions, check the modem manual for such things as "idle
+ timeout", "auto timeout", etc, and add the command to disable this
+ feature to Kermit's init string for this modem.
+
+10.2. NFS
+
+ If uploading a large file to an NFS-mounted disk fails (or is painfully
+ slow), try uploading it to a local disk (e.g. /tmp on Unix) and then
+ copying to the NFS disk later.
+
+10.3. Modems
+
+ If you are dialing out and find that downloads work but uploads don't,
+ try again with a lower serial-port speed. Case in point: dialing out on
+ a certain PC from Linux at 115200 bps using a USR Courier 56K
+ "V.Everything" external modem and RTS/CTS flow control. Downloads
+ worked flawlessly, uploads stopped dead after the first few packets
+ were sent. The modem lights showed constant retraining (ARQ light
+ blinks slowly), and the CTS light was off 95% of the time, allowing
+ nothing to get through. Reducing the serial port speed to 57600 bps
+ made the problems go away. Evidently the PC in question has a very fast
+ serial port, since dialing the same modem with a different PC at 115200
+ bps works without incident.
+
+10.4. TCP/IP Connections
+
+ If you have trouble transferring files over a TCP/IP connection, tell
+ Kermit to SET PARITY SPACE and try again. If that doesn't work, also
+ try a shorter packet length or smaller window size (to compensate for
+ certain well-known broken Telnet servers), and/or SET RELIABLE OFF.
+
+10.5. Multihop Connections
+
+ If you have a multihop connection, with the interior nodes in CONNECT
+ mode (Kermit, Telnet, Rlogin, or any other), you can expect (a) file
+ transfer to be slower, and (b) the connection to be less transparent
+ (to control characters, perhaps to the 8th bit) than a more direct
+ connection. C-Kermit 7.0 and later have a "-0" (dash-zero) command-line
+ option to make it 100% transparent in cases where it is to be used in
+ the middle.
+
+10.6. Recovery
+
+ The recovery feature (RESEND command) that was added in version 5A(190)
+ works only for binary-mode transfers. In order for this feature to be
+ useful at all, the default for SET FILE INCOMPLETE was changed from
+ DISCARD to KEEP. Otherwise an interrupted transfer would leave no
+ partial file behind unless you had remembered to change the default.
+ But now you have to pay closer attention to Kermit's messages to know
+ whether a transfer succeeded or failed -- previously, if it failed, the
+ file would not show up on the receiving end at all; in 5A(190) and
+ later, you'll get a partial file which could easily be mistaken for the
+ complete file unless you change the default back to DISCARD or read the
+ screen messages, or keep a transaction log.
+
+10.7. Filename Collisions
+
+ SET FILE COLLISION BACKUP is the default. This means:
+
+ * If you send the same file lots of times, there will be many backup
+ files. There is no automatic mechanism within Kermit to delete
+ them, no notion of a "version retention count", etc, but you can
+ use the PURGE command to clean them up.
+ * If a file arrives that has the same name as a directory, the file
+ transfer fails because Kermit will not rename a directory. Send the
+ file with another name, or use SET FILE COLLISION RENAME.
+ * If the directory lacks write permission, the file transfer fails
+ even if you have write access to the file that is being backed up;
+ in that case, switch to SET FILE COLLISION OVERWRITE or APPEND, or
+ send to a different directory.
+
+ SET FILE COLLISION UPDATE depends on the date/time stamp in the
+ attribute packet. However, this is recorded in local time, not
+ Universal Time (GMT), and there is no indication of time zone. The time
+ is expressed to the precision of 1 second, but some file systems do not
+ record with this precision -- for example, MS-DOS records the file
+ date/time only to the nearest 2 seconds. This might cause update
+ operations to send more files than necessary.
+
+ (This paragraph does NOT apply to UNIX, where, as of C-Kermit 7.0,
+ C-Kermit pipes incoming mail and print material directly the mail or
+ print program): When C-Kermit is receiving files from another Kermit
+ program that has been given the MAIL or REMOTE PRINT command, C-Kermit
+ follows the current filename collision action. This can be
+ disconcerting if the action was (for example) BACKUP, because the
+ existing file will be renamed, and the new file will be mailed (or
+ printed) and then deleted. Kermit cannot temporarily change to RENAME
+ because the file collision action occurs when the filename packet is
+ received, and the PRINT or MAIL disposition only comes later, in the
+ Attribute packet.
+
+ Watch out for SET FILE COLLISION RENAME, especially when used in
+ conjunction with recovery. Recall that this option (which is NOT the
+ default) renames the incoming file if a file already exists with the
+ same name (the default is to rename the previously existing file, and
+ store the incoming file with its own name). It is strongly recommended
+ that you do not use SET FILE COLLISION RENAME if you ever intend to use
+ the recovery feature:
+
+ * When the file is first received by C-Kermit, its name is changed if
+ another file already has the same name. When you RESEND the same
+ file after a failure, C-Kermit will probably try to append the
+ re-sent portion to the wrong file.
+ * Assuming that you get RESEND to work with FILE COLLISION RENAME,
+ C-Kermit, when receiving the remainder of the file during a RESEND
+ operation, will report back the wrong name. Nothing can be done
+ about this because the name is reported back before the receiving
+ Kermit program finds out that it is a recovery operation.
+
+ Also watch out for DISABLE DELETE, since this implicitly sets FILE
+ COLLISION to RENAME. And note tht DELETE is DISABLEd automatically any
+ time you Kermit is in local mode (i.e. it makes a connection). Also
+ note that for purposes of DISABLE and ENABLE, "set host *" connections
+ do not count as local mode even though, strictly speaking, they are.
+
+10.8. DOS Pathnames
+
+ When referring to foreign MS-DOS, Windows, Atari ST, OS/2, or other
+ file specifications that contain backslash characters in a C-Kermit
+ command, you might have to double each backslash, for example:
+
+ C-Kermit>get c:\\directory\\foo.txt
+
+ This is because backslash is used in C-Kermit commands for introducing
+ special character codes, variables, functions, etc.
+
+10.9. Cancellation
+
+ If attempting to cancel local-mode file reception at a very early stage
+ (i.e. before data packets are exchanged) with X or Z does not work, use
+ E or Ctrl-C instead, or wait until the first data packets are sent.
+
+ If you cancel a transfer that is underway using X or Z, and a lot of
+ window slots are in use, it might take a while for the cancellation to
+ take effect, especially if you do this on the receiving end; that's
+ because a lot of packets might already be on their way to you. In that
+ case, just be patient and let Kermit "drain" them.
+
+ If C-Kermit is sending a file, remote-mode packet-mode breakout (three
+ consecutive Ctrl-C's by default) is not effective until after C-Kermit
+ sends its first packet. If C-Kermit is receiving a file or is in server
+ mode, it is effective right away. In the former case, the SET DELAY
+ value determines the earliest time at which you can break out of packet
+ mode.
+
+10.10. Partner Peculiarities
+
+ When one or both partners is on an SCO operating system such as OSR5,
+ you might issue the command:
+
+mapchan -n
+
+ to disable character-set conversion by the terminal driver. Similarly
+ for AIX:
+
+setmaps -t NOMAP
+
+ When using C-Kermit to transfer files with the HP48SX calculator, you
+ must SET FLOW NONE. The HP48SX does not support flow control, and
+ evidently also becomes confused if you attempt to use it. You might
+ also need to use SET SEND PAUSE 100 (or other number). For greater
+ detail about transferring files the HP-48, see:
+
+ [85]http://www.columbia.edu/kermit/hp48.html
+
+ Some communication programs have errors in their implementation of
+ Kermit attribute packets. If you get an error message from your
+ communication program like "Attribute error", tell C-Kermit to SET
+ ATTRIBUTES OFF. Better yet, switch to a real Kermit program.
+
+ Some communication software claims to implement Kermit sliding windows,
+ but does so incorrectly. If sliding window transfers fail, set
+ C-Kermit's window size to the smallest one that works, for example, SET
+ WINDOW 1.
+
+ For lots more detail about how to cope with defective Kermit partners,
+ see:
+
+ * [86]Coping with Faulty Kermit Implementations (C-Kermit 7.0 and
+ later).
+ * [87]Coping with Broken Kermit Partners (C-Kermit 8.0 and later).
+
+ The UNIX version of C-Kermit discards carriage returns when receiving
+ files in text mode. Thus, "bare" carriage returns (sometimes used to
+ achieve overstriking) are lost.
+
+11. SCRIPT PROGRAMMING
+
+ [ [88]Top ] [ [89]Contents ] [ [90]Previous ]
+
+11.1. Comments Versus the SCRIPT Command
+
+ Remember that ";" and "#" introduce comments when (a) they are the
+ first character on the line, or (b) they are preceded by at least one
+ blank or tab within a line. Thus constructions like:
+
+ INPUT 5 ;
+ SCRIPT ~0 #--#--#
+
+ must be coded using backslash notation to keep the data from being
+ ignored:
+
+ INPUT 5 \59 ; 59 is the decimal ASCII code for ";"
+ SCRIPT ~0 \35--#--# ; 43 is the decimal ASCII code for "#"
+
+ or, more simply:
+
+ INPUT 5 \; ; Just quote the semicolon
+ SCRIPT ~0 \#--#--# ; Just quote the "#"
+
+11.2. Alphabetic Case and the INPUT Command
+
+ INPUT and MINPUT caseless string comparisons do not work for non-ASCII
+ (international) characters. Workaround: SET INPUT CASE OBSERVE. Even
+ then, the "lexically less than" and "lexically greater than" operations
+ (IF LLT, IF LGT) probably won't work as expected. The same is true for
+ the case-conversion functions \Flower() and \Fupper(). C-Kermit does
+ not know the collating sequence for different character sets and
+ languages. (On the other hand, it might work depending on such items as
+ how Kermit was linked, whether your operating supports "locales", etc)
+
+11.3. NUL (0) Characters in C-Kermit Commands
+
+ You can't include a NUL character (\0) in C-Kermit command text without
+ terminating the character string in which it appears. For example:
+
+ echo In these brackets [\0] is a NUL
+
+ will echo "In these brackets [". This applies to ECHO, INPUT, OUTPUT,
+ and all other commands (but you can represent NUL by "\N" in an OUTPUT
+ string). This is because C-language strings are terminated internally
+ by the NUL character, and it allows all of C-Kermit's string comparison
+ and manipulation functions to work in the normal "C" way.
+
+ To illustrate:
+
+ INPUT 5 \0
+
+ is equivalent to:
+
+ INPUT 5
+
+ and:
+
+ INPUT 5 ABC\0DEF
+
+ is equivalent to:
+
+ INPUT 5 ABC
+
+ INPUT operations discard and ignore NUL characters that arrive from the
+ communication device, meaning that they do not figure into matching
+ operations (e.g. A<NUL>B matches AB); they are not deposited in the
+ INPUT buffer (\v(input)); and they are not counted in \v(incount), with
+ two exceptions:
+
+ 1. An arriving NUL character restarts the INPUT SILENCE timer.
+ 2. An arriving NUL character terminates the INPUT command with the
+ SUCCESS condition if the INPUT command was given an empty search
+ string. In this case \v(incount) is set to 1.
+
+ Also, the \v(inchar) variable is null (completely empty) if the last
+ INPUT character was NUL. That is, there is no way to tell only by
+ looking at \v(inchar) the difference between a NUL that was INPUT and
+ no INPUT at all. If the INPUT command succeeded but \v(inchar) is
+ empty, then a NUL character was input. Also, \v(incount) will be set to
+ 1.
+
+ Here's a sample script fragment to read characters, possibly including
+ NUL, from the communication connection and write them to a file:
+
+ while true {
+ input 1 ; read one byte
+ if fail break ; timed out or connection closed
+ fwrite /char \%c \v(inchar) ; record the byte
+ }
+
+ This works because when \v(inchar) is NUL, that's equivalent to FWRITE
+ /CHAR having no text argument at all, in which case it writes a NUL
+ character.
+
+ \v(incount) and \v(inchar) are NOT affected by the CLEAR command.
+
+11.4. \ffiles() and \fnextfile() Peculiarities
+
+ The following script program:
+
+ for \%i 1 \ffiles(oofa.*) 1 {
+ send \fnextfile()
+ }
+
+ did not work as expected in C-Kermit 6.0 and earlier but does work in
+ C-Kermit 7.0 and later.
+
+11.5. Commands That Have Only Local Effect
+
+ Certain settings are local to each command level, meaning that
+ subordinate command levels (macros or command files) can change them
+ without affecting their values at higher command levels. When a new
+ command level is invoked, the value is inherited from the previous
+ level. These settings are:
+
+ CASE
+ COUNT and \v(count)
+ INPUT CASE
+ INPUT TIMEOUT
+ MACRO ERROR
+ QUIET
+ TAKE ERROR
+
+ This arrangement allows CASE, TIMEOUT, and ERROR settings, which are
+ used to control automatic exit from a command file or macro upon error,
+ to be automatically restored when the command file or macro exits.
+
+ The COUNT variable follows this rule too, which permits nested SET
+ COUNT / IF COUNT loops, as in this example in which the inner loop
+ counts down from the current COUNT value of the outer loop (try it):
+
+ DEFINE INNER WHILE COUNT { WRITE SCREEN { Inner:}, SHOW COUNT }
+ SET COUNT 5
+ WHILE COUNT { WRITE SCREEN Outer:, SHOW COUNT, DO INNER }
+
+ Keep in mind that an inferior command level cannot manipulate the COUNT
+ value held by a higher level. For example:
+
+ DEFINE OOFA SHOW COUNT, IF COUNT GOTO LOOP
+ SET COUNT 5
+ :LOOP
+ OOFA
+ ECHO Done
+
+ results in an infinite loop; the COUNT value remains at 5 because it is
+ never decremented at the same level at which it was set.
+
+11.6. Literal Braces in Function Calls
+
+ Since braces are used in function calls to indicate grouping, there is
+ no way to pass literal braces to the function itself. Solution: Define
+ a variable containing the string that has braces. Example:
+
+ define \%a ab{cd
+ echo \fsubstring(\%a)
+ ab{cd
+
+ If the string is to start with a leading brace and end with a closing
+ brace, then double braces must appear around the string (which itself
+ is enclosed in braces):
+
+ define \%a {{{foo}}}
+ echo \fsubstring(\%a)
+ {foo}
+
+ This also works for any other kind of string:
+
+ define \%a {{ab{cd}}
+ echo \fsubstring(\%a)
+ ab{cd
+
+11.7. Defining Variables on the C-Kermit Command Line
+
+ To define variables on the C-Kermit command line, use the -C
+ command-line option with one or more DEFINE or ASSIGN commands. Note
+ that the C-Kermit command line must cope with the quoting rules of your
+ shell. Examples:
+
+ kermit -C "define \\%a foo, define phonenumber 7654321"
+
+ In this case we follow UNIX quoting rules by doubling the backslash.
+ Once C-Kermit starts, the \%a and \m(phonenumber) variables are defined
+ as indicated and can be used in the normal way.
+
+ In DOS or Windows or OS/2 the command would be:
+
+ kermit -C "define \%%a foo, define phonenumber 7654321"
+
+ Here we need to double the percent sign rather than the backslash
+ because of DOS shell quoting rules.
+
+11.8. Per-Character Echo Check with the OUTPUT Command
+
+ Sometimes the OUTPUT command must be used to send commands or data to a
+ device in "echoplex" mode, meaning that characters must be sent one at
+ a time, and the next character can not be sent until the echo from the
+ previous one has been received. For example, a certain PBX might have
+ this characteristic. Let's say a Kermit script is used to program the
+ PBX. If characters are sent too fast, they can be lost. It would seem
+ that the command:
+
+ SET OUTPUT PACING milliseconds
+
+ could be used to take care of this, but the pacing interval is constant
+ and must be set large enough to allow even the slowest echo to finish.
+ If the script is large (an actual example is 14,000 lines long), this
+ can cause it to take hours longer than it needs to.
+
+ Here is a macro you can use to OUTPUT a string in an Echoplex
+ environment:
+
+ define XOUTPUT {
+ local \%c \%i
+ set output pacing 0
+ for \%i 1 \flen(\%*) 1 {
+ asg \%c \fsubstr(\%*,\%i,1)
+ output \%c
+ input 2 \%c
+ }
+ }
+
+ C-Kermit 7.0 or later is required.
+
+ It sends one character at a time and then waits up to 2 seconds for the
+ character to be echoed back, but continues to the next character as
+ soon as the echo appears, so no time is wasted. You can add an IF FAIL
+ clause after the INPUT in case you want to do something special about
+ failure to detect an echo within the timeout period. Obviously you can
+ also change the 2-second limit, and adjust the script in any other
+ desired way.
+
+11.9. Scripted File Transfer
+
+ Sometimes a user complains that when she makes a connection by hand,
+ logs in, and transfers a file, there are no problems, but when she
+ scripts the the exact same sequence, the file transfer always fails
+ after a few packets. Here's a scenario where this can happen:
+
+ 1. Upon logging in to the remote computer, it sends a "What Are You?"
+ escape sequence.
+ 2. When you log in interactively, your terminal emulator sends the
+ response. This is invisible to you; you don't know it's happening.
+ 3. When you script the login, and begin a file transfer immediately
+ upon logging in, the host still sends the "What Are You?" sequence.
+ Kermit's INPUT ECHO setting is ON by default, so the escape
+ sequence passes through to the terminal, and the terminal sends its
+ response. But by this time Kermit has already started the file
+ transfer.
+ 4. By default, the local Kermit program examines the keyboard for
+ interruption characters between every packet. The "What Are You"
+ response is sitting in the keyboard buffer. Eventually Kermit will
+ read a character such as "c" that is a valid interruption
+ character, and the file transfer stops with "User canceled".
+
+ The right way to handle this situation is to have your look for the
+ "What Are You?" sequence and send the response itself, as described in
+ Using C-Kermit, pp.429-431. Or you can work around it by telling the
+ local Kermit to "set input echo off" and/or "set transfer interruption
+ off".
+
+11.10. Hexadecimal arithmetic...
+
+ C-Kermit can do both integer and floating-point arithmetic, in both
+ ordinary algebraic notation and in Lisp S-Expression notation. All
+ arithmetic operators and functions operate only on decimal numbers. It
+ is possible, however, to write scripts that operate on hexadecimal
+ numbers. This is done by converting them to decimal prior to any
+ arithmetic operations, and then converting them back to hexadecimal for
+ display. Example:
+
+; EVALUATE is a command that evaluates an arithmetic expression.
+; See HELP EVALUATE for details. This is just for demonstration.
+; Arithmetic expressions can be used in any context where a number
+; can be used. Also, the special notation:
+;
+; .\%a ::= expression
+;
+; evaluations the expression and assigns the result to the variable.
+;
+.\%a := fffe ; Set variable to hex value
+set eval old ; See HELP EVAL
+eval \fhex2n(\%a) ; Show value of variable
+eval \fhex2n(\%a) + 1 ; Show value of expression
+eval \fhex2n(\%a) + 2 ; Show value of expression
+.\%x ::= \fhex2n(\%a) + 1 ; Assign value of expression to variable
+echo \fn2hex(\%x) ; Display variable's value in hex
+.\%x ::= \fhex2n(\%a) + 2 : Ditto
+echo \fn2hex(\%x)
+.\%x ::= \fhex2n(\%a) | \fhex2n(ffff) ; Similarly for logical OR
+echo \fn2hex(\%x)
+.\%x ::= \fhex2n(\%a) & \fhex2n(ffff) ; and logical AND
+echo \fn2hex(\%x)
+
+ By the way, you might be tempted to use Kermit's \xnn notation to plug
+ hex numbers into arithmetic expressions but this doesn't work. That
+ notation is strictly for bytes (hex representation of character
+ values), not for numbers.
+
+11.11. Other...
+
+ Escape sequences (or any strings that contain control characters) can't
+ be used as labels, GOTO targets, or SWITCH cases.
+
+ [ [91]Top ] [ [92]Contents ] [ [93]C-Kermit Home ] [ [94]C-Kermit 8.0
+ Overview ] [ [95]Kermit Home ]
+ __________________________________________________________________
+
+ C-Kermit 8.0 Unix Hints and Tips / [96]The Kermit Project /
+ [97]kermit@columbia.edu / 30 June 2011
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/ckcbwr.html
+ 12. http://www.columbia.edu/kermit/ckubwr.html
+ 13. http://www.columbia.edu/kermit/k95.html
+ 14. http://www.columbia.edu/kermit/ckermit.html
+ 15. http://www.columbia.edu/kermit/ckututor.html
+ 16. http://www.columbia.edu/kermit/ckcbwr.html#x0
+ 17. http://www.columbia.edu/kermit/ckcbwr.html#x1
+ 18. http://www.columbia.edu/kermit/ckcbwr.html#x2
+ 19. http://www.columbia.edu/kermit/ckcbwr.html#x3
+ 20. http://www.columbia.edu/kermit/ckcbwr.html#x4
+ 21. http://www.columbia.edu/kermit/ckcbwr.html#x5
+ 22. http://www.columbia.edu/kermit/ckcbwr.html#x6
+ 23. http://www.columbia.edu/kermit/ckcbwr.html#x7
+ 24. http://www.columbia.edu/kermit/ckcbwr.html#x8
+ 25. http://www.columbia.edu/kermit/ckcbwr.html#x9
+ 26. http://www.columbia.edu/kermit/ckcbwr.html#x10
+ 27. http://www.columbia.edu/kermit/ckcbwr.html#x11
+ 28. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 29. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 30. http://www.columbia.edu/kermit/ckcbwr.html#x2
+ 31. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 32. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 33. http://www.columbia.edu/kermit/ckcbwr.html#x2
+ 34. http://www.columbia.edu/kermit/ck60manual.html
+ 35. http://www.columbia.edu/kermit/ckermit2.html
+ 36. http://www.columbia.edu/kermit/ck60manual.html
+ 37. http://www.columbia.edu/kermit/ckermit80.html#x5
+ 38. http://www.columbia.edu/kermit/ckermit80.html
+ 39. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+ 40. http://www.columbia.edu/kermit/ckermit80.html#x8.7.2
+ 41. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 42. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 43. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 44. http://www.columbia.edu/kermit/ckcbwr.html#x3
+ 45. http://www.columbia.edu/kermit/ckcbwr.html#x1
+ 46. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 47. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 48. http://www.columbia.edu/kermit/ckcbwr.html#x4
+ 49. http://www.columbia.edu/kermit/ckcbwr.html#x2
+ 50. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 51. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 52. http://www.columbia.edu/kermit/ckcbwr.html#x5
+ 53. http://www.columbia.edu/kermit/ckcbwr.html#x3
+ 54. ftp://ftp.isi.edu/in-notes/rfc1122.txt
+ 55. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 56. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 57. http://www.columbia.edu/kermit/ckcbwr.html#x6
+ 58. http://www.columbia.edu/kermit/ckcbwr.html#x4
+ 59. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 60. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 61. http://www.columbia.edu/kermit/ckcbwr.html#x7
+ 62. http://www.columbia.edu/kermit/ckcbwr.html#x5
+ 63. http://www.columbia.edu/kermit/ck60manual.html
+ 64. http://www.columbia.edu/kermit/ckcbwr.html#x10
+ 65. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 66. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 67. http://www.columbia.edu/kermit/ckcbwr.html#x8
+ 68. http://www.columbia.edu/kermit/ckcbwr.html#x6
+ 69. ftp://ftp.isi.edu/in-notes/rfc2217.txt
+ 70. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 71. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 72. http://www.columbia.edu/kermit/ckcbwr.html#x9
+ 73. http://www.columbia.edu/kermit/ckcbwr.html#x7
+ 74. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 75. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 76. http://www.columbia.edu/kermit/ckcbwr.html#x10
+ 77. http://www.columbia.edu/kermit/ckcbwr.html#x8
+ 78. http://www.columbia.edu/kermit/ckubwr.html
+ 79. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 80. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 81. http://www.columbia.edu/kermit/ckcbwr.html#x11
+ 82. http://www.columbia.edu/kermit/ckcbwr.html#x9
+ 83. http://www.columbia.edu/kermit/ck60manual.html
+ 84. http://www.columbia.edu/kermit/ckermi70.htm
+ 85. http://www.columbia.edu/kermit/hp48.html
+ 86. http://www.columbia.edu/kermit/ckermit70.html#x4.22
+ 87. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 88. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 89. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 90. http://www.columbia.edu/kermit/ckcbwr.html#x10
+ 91. http://www.columbia.edu/kermit/ckcbwr.html#top
+ 92. http://www.columbia.edu/kermit/ckcbwr.html#contents
+ 93. http://www.columbia.edu/kermit/ckermit.html
+ 94. http://www.columbia.edu/kermit/ck80.html
+ 95. http://www.columbia.edu/kermit/index.html
+ 96. http://www.columbia.edu/kermit/index.html
+ 97. mailto:kermit@columbia.edu
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckccfg.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckccfg.txt
new file mode 100644
index 0000000..0185c3d
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckccfg.txt
@@ -0,0 +1,1738 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+C-Kermit Configuration Options
+
+ As of: C-Kermit 9.0.300, 30 June 2011
+ This page last updated: Fri Jul 1 15:48:21 2011 (New York USA Time)
+
+ IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+ this file is a plain-text dump of a Web page. You can visit the
+ original (and possibly more up-to-date) Web page here:
+
+ [11]http://www.columbia.edu/kermit/ckccfg.html
+
+ [ [12]C-Kermit Home ] [ [13]Kermit Home ]
+
+ CONTENTS
+
+ 1. [14]FILE TRANSFER
+ 2. [15]SERIAL COMMUNICATION SPEEDS
+ 3. [16]FULLSCREEN FILE TRANSFER DISPLAY
+ 4. [17]CHARACTER SETS
+ 5. [18]APC EXECUTION
+ 6. [19]PROGRAM SIZE
+ 7. [20]MODEM DIALING
+ 8. [21]NETWORK SUPPORT
+ 9. [22]EXCEPTION HANDLING
+ 10. [23]SECURITY FEATURES
+ 11. [24]ENABLING SELECT()
+ 12. [25]I/O REDIRECTION
+ 13. [26]FLOATING-POINT NUMBERS, TIMERS, AND ARITHMETIC
+ 14. [27]SPECIAL CONFIGURATIONS
+ I. [28]SUMMARY OF COMPILE-TIME OPTIONS
+
+ OVERVIEW
+
+ This document describes configuration options for C-Kermit (5A and
+ later). The major topics covered include program size (and how to
+ reduce it), how to include or exclude particular features, notes on
+ serial-port, modem, and network support, and a list of C-Kermit's
+ compile-time options.
+
+ For details about your particular operating system, also see the
+ system-specific installation instructions file, such as the
+ [29]C-Kermit Installation Instructions for Unix.
+
+ [ [30]C-Kermit Home ] [ [31]Kermit Home ]
+
+ 1. FILE TRANSFER
+
+ [ [32]Top ] [ [33]Contents ] [ [34]Next ] [ [35]Previous ]
+
+ Prior to version 7.0, C-Kermit was always built with the most
+ conservative Kermit file-transfer protocol defaults on every platform:
+ no control-character prefixing, 94-byte packets, and a window size of
+ 1.
+
+ Starting in version 7.0, fast settings are the default. To override
+ these at compile time, include:
+
+ -DNOFAST
+
+ in the C compiler CFLAGS. Even with the fast defaults, C-Kermit
+ automatically drops down to whatever window and packet sizes requested
+ by the other Kermit, if these are smaller, when sending files (except
+ for control-character unprefixing, which is not negotiated, and which
+ is now set to CAUTIOUS rather than NONE at startup). C-Kermit's
+ settings prevail when it is receiving.
+
+ [ [36]C-Kermit Home ] [ [37]Kermit Home ]
+
+ 2. SERIAL COMMUNICATION SPEEDS
+
+ [ [38]Top ] [ [39]Contents ] [ [40]Next ] [ [41]Previous ]
+
+ As of 6 September 1997, a new simplified mechanism for obtaining the
+ list of legal serial interface speeds is in place:
+
+ * If the symbol TTSPDLIST is defined, the system-dependent routine
+ ttspdlist() is called at program initialization to obtain the list.
+ * This symbol should be defined only for C-Kermit implementations
+ that have implemented the ttspdlist() function, typically in the
+ ck?tio.c module. See [42]ckutio.c for an example.
+ * TTSPDLIST is automatically defined in [43]ckcdeb.h for UNIX. Add
+ the appropriate #ifdefs for other platforms when the corresponding
+ ttspdlist() functions are filled in.
+ * If TTSPDLIST is (or normally would be) defined, the old code
+ (described below) can still be selected by defining NOTTSPDLIST.
+
+ The ttspdlist() function can obtain the speeds in any way that works.
+ For example, based simply on #ifdef Bnnnn..#endif (in UNIX). Although
+ it might be better to actually check each speed against the currently
+ selected hardware interface before allowing it in the array, there is
+ usually no passive and/or reliable and safe way to do this, and so it's
+ better to let some speeds into the array that might not work, than it
+ is to erroneously exclude others. Speeds that don't work are caught
+ when the SET SPEED command is actually given.
+
+ Note that this scheme does not necessarily rule out split speed
+ operation, but effectively it does in C-Kermit as presently constituted
+ since there are no commands to set input and output speed separately
+ (except the special case "set speed 75/1200").
+
+ Note that some platforms, notably AIX 4.2 and 4.3, implement high
+ serial speeds transparently to the application, e.g. by mapping 50 bps
+ to 57600 bps, and so on.
+
+ That's the whole deal. When TTSPDLIST is not defined, the following
+ applies:
+
+ Speeds are defined in two places: the SET SPEED keyword list in the
+ command parser (as of this writing, in the [44]ckuus3.c source file),
+ and in the system- dependent communications i/o module, ck?tio.c,
+ functions ttsspd() (set speed) and ttgspd() (get speed). The following
+ speeds are assumed to be available in all versions:
+
+ 0, 110, 300, 600, 1200, 2400, 4800, 9600
+
+ If one or more of these speeds is not supported by your system, you'll
+ need to change the source code (this has never happened so far). Other
+ speeds that are not common to all systems have Kermit-specific symbols:
+
+ Symbol Symbol
+ Speed (bps) to enable to disable
+ 50 BPS_50 NOB_50
+ 75 BPS_75 NOB_75
+ 75/1200 BPS_7512 NOB_7512
+ 134.5 BPS_134 NOB_134
+ 150 BPS_150 NOB_150
+ 200 BPS_200 NOB_200
+ 1800 BPS_1800 NOB_1800
+ 3600 BPS_3600 NOB_3600
+ 7200 BPS_7200 NOB_7200
+ 14400 BPS_14K NOB_14K
+ 19200 BPS_19K NOB_19K
+ 28800 BPS_28K NOB_28K
+ 38400 BPS_38K NOB_38K
+ 57600 BPS_57K NOB_57K
+ 76800 BPS_76K NOB_76K
+ 115200 BPS_115K NOB_155K
+ 230400 BPS_230K NOB_230K
+ 460800 BPS_460K NOB_460K
+ 921600 BPS_921K NOB_921K
+
+ The [45]ckcdeb.h header file contains default speed configurations for
+ the many systems that C-Kermit supports. You can override these
+ defaults by (a) editing ckcdeb.h, or (b) defining the appropriate
+ enabling and/or disabling symbols on the CC command line, for example:
+
+ -DBPS_14400 -DNOB_115200
+
+ or the "make" command line, e.g.:
+
+ make blah "KFLAGS=-DBPS_14400 -DNOB_115200"
+
+ Note: some speeds have no symbols defined for them, because they have
+ never been needed: 12.5bps, 45.5bps, 20000bps, etc. These can easily be
+ added if required (but they will work only if the OS supports them).
+
+ IMPORTANT: Adding one of these flags at compile time does not
+ necessarily mean that you will be able to use that speed. A particular
+ speed is usable only if your underlying operating system supports it.
+ In particular, it needs to be defined in the appropriate system header
+ file (e.g. in UNIX, cd to /usr/include and grep for B9600 in *.h and
+ sys/*.h to find the header file that contains the definitions for the
+ supported speeds), and supported by the serial device driver, and of
+ course by the physical device itself.
+
+ ALSO IMPORTANT: The list of available speeds is independent of how they
+ are set. The many UNIXes, for example, offer a wide variety of APIs
+ that are BSD-based, SYSV-based, POSIX-based, and purely made up. See
+ the ttsspd(), ttgspd(), and ttspdlist() routines in [46]ckutio.c for
+ illustrations.
+
+ The latest entries in this horserace are the tcgetspeed() and
+ ttsetspeed() routines found in UnixWare 7. Unlike other methods, they
+ accept the entire range of integers (longs really) as speed values,
+ rather than certain codes, and return an error if the number is not, in
+ fact, a legal speed for the device/driver in question. In this case,
+ there is no way to build a list of legal speeds at compile time, since
+ no Bnnnn symbols are defined (except for "deprecated, legacy"
+ interfaces like ioctl()) and so the legal speed list must be enumerated
+ in the code -- see ttspdlist() in [47]ckutio.c.
+
+ [ [48]C-Kermit Home ] [ [49]Kermit Home ]
+
+ 3. FULLSCREEN FILE TRANSFER DISPLAY
+
+ [ [50]Top ] [ [51]Contents ] [ [52]Next ] [ [53]Previous ]
+
+ New to edit 180 is support for an MS-DOS-Kermit-like local-mode full
+ screen file transfer display, accomplished using the curses library, or
+ something equivalent (for example, the Screen Manager on DEC VMS). To
+ enable this feature, include the following in your CFLAGS:
+
+ -DCK_CURSES
+
+ and then change your build procedure (if necessary) to include the
+ necessary libraries. For example, in Unix these are usually "curses" or
+ "ncurses" (and more recently, "ncursesw" and "slang"), perhaps also
+ "termcap", "termlib", or "tinfo":
+
+ "LIBS= -lcurses -ltermcap"
+ "LIBS= -lcurses -ltermlib"
+ "LIBS= -lncurses"
+ "LIBS= -ltermlib"
+ "LIBS= -ltinfo"
+
+ "man curses" for further information, and search through the Unix
+ [54]makefile for "CK_CURSES" to see many examples, and also see the
+ relevant sections of the [55]Unix C-Kermit Installation Instructions,
+ particularly Sections [56]4 and [57]9.2.
+
+ There might still be a complication. Some implementations of curses
+ reserve the right to alter the buffering on the output file without
+ restoring it afterwards, which can leave Kermit's command processing in
+ a mess when the prompt comes back after a fullscreen file transfer
+ display. The typical symptom is that characters you type at the prompt
+ after a local-mode file transfer (i.e. after seeing the curses
+ file-transfer display) do not echo until you press the Return (Enter)
+ key. If this happens to you, try adding
+
+ -DCK_NEWTERM
+
+ to your makefile target (see comments in screenc() in [58]ckuusx.c for
+ an explanation).
+
+ If that doesn't fix the problem, then use a bigger hammer and replace
+ -DCK_NEWTERM with:
+
+ -DNONOSETBUF
+
+ which tells Kermit to force stdout to be unbuffered so CBREAK mode can
+ work.
+
+ In SCO Xenix and SCO UNIX, there are two separate curses libraries, one
+ based on termcap and the other based on terminfo. The default library,
+ usually terminfo, is established when the development system is
+ installed. To manually select terminfo (at compile time):
+
+ compile -DM_TERMINFO and link -ltinfo
+
+ and to manually select termcap:
+
+ compile -DM_TERMCAP and link -ltcap -ltermlib
+
+ <curses.h> looks at M_TERMINFO and M_TERMCAP to decide which header
+ files to use. /usr/lib/libcurses.a is a link to either libtinfo.a or
+ libtcap.a. The C-Kermit compilation options must agree with the version
+ of the curses library that is actually installed.
+
+ NOTE: If you are doing an ANSI-C compilation and you get compile time
+ warnings like the following:
+
+ Warning: function not declared in ckuusx.c: wmove, printw, wclrtoeol,
+ wclear, wrefresh, endwin, etc...
+
+ it means that your <curses.h> file does not contain prototypes for
+ these functions. The warnings should be harmless.
+
+ New to edit 190 is the ability to refresh a messed-up full-screen
+ display, e.g. after receiving a broadcast message. This depends on the
+ curses package including the wrefresh() and clearok() functions and the
+ curscr variable. If your version has these, or has code to simulate
+ them, then add:
+
+ -DCK_WREFRESH
+
+ The curses and termcap libraries add considerable size to the program
+ image (e.g. about 20K on a SUN-4, 40K on a 386). On some small systems,
+ such as the AT&T 6300 PLUS, curses can push Kermit over the edge...
+ even though it compiles, loads, and runs correctly, its increased size
+ apparently makes it swap constantly, slowing it down to a crawl, even
+ when the curses display is not in use. Some new makefile targets have
+ been added to take care of this (e.g. sys3upcshcc), but similar tricks
+ might be necessary in other cases too.
+
+ On the curses file-transfer display, just below the "thermometer", is a
+ running display of the transfer rate, as a flat quotient of file
+ characters per elapsed seconds so far. You can change this to an
+ average that gives greater weight to recent history (0.25 *
+ instantaneous cps + 0.75 * historical cps) by adding -DCPS_WEIGHTED to
+ your CFLAGS (sorry folks, this one is not worth a SET command). You can
+ choose a second type of weighted average in which the weighting smooths
+ out progressively as the transfer progresses by adding -DCPS_VINCE to
+ -DCPS_WEIGHTED.
+
+ An alternative to curses is also available at compile time, but should
+ be selected if your version of Kermit is to be run in local mode only
+ in an ANSI terminal environment, for example on a desktop workstation
+ that has an ANSI console driver. To select this option in place of
+ curses, define the symbol MYCURSES:
+
+ -DMYCURSES
+
+ instead of CK_CURSES. The MYCURSES option uses built-in ANSI (VT100)
+ escape sequences, and depends upon your terminal or console driver to
+ interpret them correctly.
+
+ In some C-Kermit builds, we replace printf() via #define printf...
+ However, this can cause conflicts with the [n]curses header files.
+ Various hacks are required to get around this -- see [59]ckutio.c,
+ [60]ckufio.c, [61]ckuusx.c, [62]ckucmd.c, etc.
+
+ [ [63]C-Kermit Home ] [ [64]Kermit Home ]
+
+ 4. CHARACTER SETS
+
+ [ [65]Top ] [ [66]Contents ] [ [67]Next ] [ [68]Previous ]
+
+ Since version 5A, C-Kermit has included support for conversion of
+ character sets for Western European languages (i.e. languages that
+ originated in Western Europe, but are now also spoken in the Western
+ Hemisphere and other parts of the world), via ISO 8859-1 Latin Alphabet
+ 1, for Eastern European languages (ISO Latin-2), Hebrew (and Yiddish),
+ Greek, and Cyrillic-alphabet languages (ISO Latin/Cyrillic). Many file
+ (local) character sets are supported: ISO 646 7-bit national sets, IBM
+ code pages, Apple, DEC, DG, NeXT, etc.
+
+ To build Kermit with no character-set translation at all, include
+ -DNOCSETS in the CFLAGS. To build with no Latin-2, add -DNOLATIN2. To
+ build with no Cyrillic, add -DNOCYRIL. To omit Hebrew, add -DNOHEBREW.
+ If -DNOCSETS is *not* included, you'll always get LATIN1. To build with
+ no KANJI include -DNOKANJI. There is presently no way to include
+ Latin-2, Cyrillic, Hebrew, or Kanji without also including Latin-1.
+
+ [69]Unicode support was added in C-Kermit 7.0, and it adds a fair
+ amount of tables and code (and this is only a "Level 1" implementation
+ -- a higher level would also require building in the entire Unicode
+ database). On a PC with RH 5.2 Linux, building C-Kermit 7.0, we get the
+ following sizes:
+
+ NOCSETS NOUNICODE NOKANJI Before After
+ [ ] [ ] [ ] 1329014 (Full)
+ [ ] [ ] [ X ] 1325686 (Unicode but no Kanji)
+ [ ] [ X ] [ ] 1158837 (All charsets except Unicode)
+ [ X ] [ x ] [ x ] 1090845 (NOCSETS implies the other two)
+
+ Note, by the way, that NOKANJI without NOUNICODE only removes the
+ non-Unicode Kanji sets (Shift-JIS, EUC-JP, JIS-7, etc). Kanji is still
+ representable in UCS-2 and UTF-8.
+
+ [ [70]C-Kermit Home ] [ [71]Kermit Home ]
+
+ 5. APC EXECUTION
+
+ [ [72]Top ] [ [73]Contents ] [ [74]Next ] [ [75]Previous ]
+
+ The Kermit CONNECT and INPUT commands are coded to execute Application
+ Program Command escape sequences from the host:
+
+ <ESC>_<text><ESC>\
+
+ where <text> is a C-Kermit command, or a list of C-Kermit commands
+ separated by commas, up to about 1K in length.
+
+ To date, this feature has been included in the OS/2, Windows, VMS,
+ OS-9, and Unix versions, for which the symbol:
+
+ CK_APC
+
+ is defined automatically in [76]ckuusr.h. For OS/2, APC is enabled at
+ runtime by default, for UNIX it is disabled. It is controlled by the
+ SET TERMINAL APC command. Configuring APC capability into a version
+ that gets it by default (because CK_APC is defined in [77]ckuusr.h) can
+ be overridden by including:
+
+ -DNOAPC
+
+ on the CC command line.
+
+ C-Kermit's autodownload feature depends on the APC feature, so
+ deconfiguring APC also disables autodownload (it doesn't use APC escape
+ sequences, but uses the APC switching mechanism internally).
+
+ [ [78]C-Kermit Home ] [ [79]Kermit Home ]
+
+ 6. PROGRAM SIZE
+
+ [ [80]Top ] [ [81]Contents ] [ [82]Next ] [ [83]Previous ]
+
+ SECTION CONTENTS
+
+ 6.1. [84]Feature Selection
+ 6.2. [85]Changing Buffer Sizes
+ 6.3. [86]Other Size-Related Items
+ 6.4. [87]Space/Time Tradeoffs
+
+ (Also see [88]Section 4)
+
+ Each release of C-Kermit is larger than the last. On some computers
+ (usually old ones) the size of the program prevents it from being
+ successfully linked and loaded. On some others (also usually old ones),
+ it occupies so much memory that it is constantly swapping or paging. In
+ such cases, you can reduce C-Kermit's size in various ways, outlined in
+ this section. The following options can cut down on the program's size
+ at compile time by removing features or changing the size of storage
+ areas.
+
+ If you are reading this section because all you want is a small, fast,
+ quick-to-load Kermit file-transfer application for the remote end of
+ your connection, and the remote end is Unix based, take a look at
+ G-Kermit:
+
+ [89]http://www.columbia.edu/kermit/gkermit.html
+
+ 6.1. Feature Selection
+
+ Features can be added or removed by defining symbols on the CC (C
+ compiler) command line. "-D" is the normal CC directive to define a
+ symbol so, for example, "-DNODEBUG" defines the symbol NODEBUG. Some C
+ compilers might use different syntax, e.g. "-d NODEBUG" or
+ "/DEFINE=NODEBUG". For C compilers that do not accept command-line
+ definitions, you can put the corresponding #define statements in the
+ file ckcsym.h, for example:
+
+ #define NODEBUG
+
+ The following table shows the savings achieved when building C-Kermit
+ 8.0 (Beta.04) with selected feature-deselection switches on an
+ Intel-based PC with Red Hat Linux 7.0 and gcc 2.96. The sizes are for
+ non-security builds. The fully configured non-security build is 2127408
+ bytes.
+
+ Option Size Savings Effect
+ NOICP 545330 74.4% No Interactive Command Parser (command-line only)
+ NOLOCAL 1539994 27.6% No making connections.
+ NOXFER 1551108 27.1% No file transfer.
+ IKSDONLY 1566608 26.4% Internet Kermit Server only.
+ NOCSETS 1750097 17.7% No character-set conversion.
+ NOSPL 1800293 15.4% No Script Programming Language.
+ NONET 1808575 15.0% No making network connections.
+ NOUNICODE 1834426 13.8% No Unicode character-set conversion.
+ NOHELP 1837877 13.6% No built-in help text.
+ NODEBUG 1891669 11.1% No debug log.
+ NOFRILLS 1918966 9.8% No "frills".
+ NOFTP 1972496 7.3% No FTP client.
+ NODIAL 1984488 6.7% No automatic modem dialing.
+ NOPUSH 2070184 2.7% No shell access, running external programs, etc.
+ NOIKSD 2074129 2.5% No Internet Kermit Server capability.
+ NOHTTP 2082610 2.1% No HTTP client.
+ NOFLOAT 2091332 1.7% No floating-point arithmetic.
+ NOCHANNELIO 2095978 1.5% No FOPEN/FREAD/FWRITE/FCLOSE, etc.
+ MINIDIAL 2098035 1.4% No built-in support for many kinds of modems.
+ NOSERVER 2098987 1.3% No server mode.
+ NOSEXP 2105898 1.0% No S-Expressions.
+ NOPTY 2117743 0.5% No pseudoterminal support.
+ NORLOGIN 2121089 0.3% No RLOGIN connections.
+ NOOLDMODEMS 2124038 0.2% No built-in support for old kinds of modems.
+ NOSSH 2125696 0.1% No SSH command.
+
+ And here are a few combinations
+
+ Options Size Savings Effect
+ NODEBUG NOICP NOCSETS NOLOCAL 281641 86.7% No debug log, parser,
+ character sets, or making connections.
+ NOICP NOCSETS NOLOCAL 376468 82.3% No parser, character sets, or making
+ connections.
+ NOICP NOCSETS NONET 427510 79.9% No parser, character sets, or network
+ connections.
+ NOSPL NOCSETS 1423784 33.1% No script language, or character sets.
+
+ -DNOFRILLS removes various command synonyms; the following top-level
+ commands: CLEAR, DELETE, DISABLE, ENABLE, GETOK, MAIL, RENAME, TYPE,
+ WHO; and the following REMOTE commands: KERMIT, LOGIN, LOGOUT, PRINT,
+ TYPE, WHO.
+
+ 6.2. Changing Buffer Sizes
+
+ Most modern computers have so much memory that (a) there is no need to
+ scrimp and save, and (b) C-Kermit, even when fully configured, is
+ relatively small by today's standards.
+
+ Two major factors affect Kermit's size: feature selection and buffer
+ sizes. Buffer sizes affect such things as the maximum length for a
+ Kermit packet, the maximum length for a command, for a macro, for the
+ name of a macro, etc. Big buffer sizes are used when the following
+ symbol is defined:
+
+ BIGBUFOK
+
+ as it is by default for most modern platforms (Linux, AIX 4 and 5,
+ HP-UX 10 and 11, Solaris, etc) in [90]ckuusr.h. If your build does not
+ get big buffers automatically (SHOW FEATURES tells you), you can
+ include them by rebuilding with BIGBUFOK defined; e.g. in Unix:
+
+ make xxxx KFLAGS=-DBIGBUFOK
+
+ where xxxx is the makefile target. On the other hand, if you want to
+ build without big buffers when they normally would be selected, use:
+
+ make xxxx KFLAGS=-DNOBIGBUF
+
+ There are options to control Kermit's packet buffer allocations. The
+ following symbols are defined in [91]ckcker.h in such a way that you
+ can override them by redefining them in CFLAGS:
+
+ -DMAXSP=xxxx - Maximum send-packet length.
+ -DMAXRP=xxxx - Maximum receive-packet length.
+ -DSBSIZ=xxxx - Total allocation for send-packet buffers.
+ -DRBSIZ=xxxx - Total allocation for receive-packet buffers.
+
+ The defaults depend on the platform.
+
+ Using dynamic allocation (-DDYNAMIC) reduces storage requirements for
+ the executable program on disk, and allows more and bigger packets at
+ runtime. This has proven safe over the years, and now most builds (e.g.
+ all Unix, VMS, Windows, and OS/2 ones) use dynamic memory allocation by
+ default. If it causes trouble, however, then omit the -DDYNAMIC option
+ from CFLAGS, or add -DNODYNAMIC.
+
+ 6.3. Other Size-Related Items
+
+ To make Kermit compile and load successfully, you might have to change
+ your build procedure to:
+
+ a. Request a larger ("large" or "huge") compilation / code-generation
+ model. This is needed for 16-bit PC-based UNIX versions (most or
+ all of which fail to build C-Kermit 7.0 and later anyway). This is
+ typically done with a -M and/or -F switch (see your cc manual or
+ man page for details).
+ b. Some development systems support overlays. If the program is too
+ big to be built as is, check your loader manual ("man ld") to see
+ if an overlay feature is available. See the 2.10/2.11 BSD example
+ in the UNIX makefile. (Actually, as of version 7.0, C-Kermit is too
+ big to build, period, even with overlays, on 2.xx BSD).
+ c. Similarly, some small and/or segment-based architectures support
+ "code mapping", which is similar to overlays (PDP11-based VENIX
+ 1.0, circa 1984, was an example). See the linker documentation on
+ the affected platform.
+
+ It is also possible to reduce the size of the executable program file
+ in several other ways:
+
+ a. Include the -O (optimize) compiler switch if it isn't already
+ included in your "make" entry (and if it works!). If your compiler
+ supports higher levels of optimization (e.g. -O2 or higher number,
+ -Onolimit (HP-UX), etc), try them; the greater the level of
+ optimization, the longer the compilation and more likely the
+ compiler will run out of memory. The latter eventuality, some
+ compilers also provide command-line options to allocate more memory
+ for the optimizer, like "-Olimit number" in Ultrix.
+ b. If your platform supports shared libraries, change the make entry
+ to take advantage of this feature. The way to do this is, of
+ course, platform dependent; see the NeXT makefile target for an
+ example. some platforms (like Solaris) do it automatically and give
+ you no choice. But watch out: executables linked with shared
+ libraries are less portable than statically linked executables.
+ c. Strip the program image after building ("man strip" for further
+ info), or add -s to the LNKFLAGS (UNIX only). This strips the
+ program of its symbol table and relocation information.
+ d. Move character strings into a separate file. See the 2.11 BSD
+ target for an example.
+
+ 6.4. Space/Time Tradeoffs
+
+ There are more than 6000 debug() statements in the program. If you want
+ to save both space (program size) and time (program execution time),
+ include -DNODEBUG in the compilation. If you want to include debugging
+ for tracking down problems, omit -DNODEBUG from the make entry. But
+ when you include debugging, you have two choices for how it's done. One
+ definition defines debug() to be a function call; this is cheap in
+ space but expensive in execution. The other defines debug as "if
+ (deblog)" and then the function call, to omit the function call
+ overhead when the debug log is not active. But this adds a lot of space
+ to the program. Both methods work, take your choice; IFDEBUG is
+ preferred if memory is not a constraint but the computer is likely to
+ be slow. The first method is the default, i.e. if nothing is done to
+ the CFLAGS or in [92]ckcdeb.h (but in some cases, e.g. VMS, it is). To
+ select the second method, include -DIFDEBUG in the compilation (and
+ don't include -DNODEBUG).
+
+ [ [93]C-Kermit Home ] [ [94]Kermit Home ]
+
+ 7. MODEM DIALING
+
+ [ [95]Top ] [ [96]Contents ] [ [97]Next ] [ [98]Previous ]
+
+ -DNODIAL removes automatic modem dialing completely, including the
+ entire [99]ckudia.c module, plus all commands that refer to dialing in
+ the various ckuus*.c modules.
+
+ -DMINIDIAL leaves the DIAL and related commands (SET/SHOW MODEM,
+ SET/SHOW DIAL) intact, but removes support for all types of modems
+ except CCITT, Hayes, Unknown, User-defined, Generic-high-speed, and
+ None (= Direct). The MINIDIAL option cuts the size of the dial module
+ approximately in half. Use this option if you have only Hayes or CCITT
+ modems and don't want to carry the baggage for the other types.
+
+ A compromise between full dialer support and MINIDIAL is obtained by
+ removing support for "old" modems -- all the strange non-Hayes
+ compatible 1200 and 2400 bps modems that C-Kermit has been carrying
+ around since 1985 or so. To remove support for these modems, add
+ -DNOOLDMODEMS to CFLAGS at compilation time.
+
+ Finally, if you keep support for old modems, you will notice that their
+ names appear on the "set modem ?" menu. That's because their names are,
+ by default, "visible". But the list is confusing to the younger
+ generation, who have only heard of modems from the V.32bis-and-later
+ era. If you want to be able to use old modems, but don't want their
+ names cluttering up menus, add this to CFLAGS:
+
+ -DM_OLD=1
+
+ [ [100]C-Kermit Home ] [ [101]Kermit Home ]
+
+ 8. NETWORK SUPPORT
+
+ [ [102]Top ] [ [103]Contents ] [ [104]Next ] [ [105]Previous ]
+
+ SECTION CONTENTS
+
+ 8.1. [106]TCP/IP
+ 8.2. [107]X.25
+ 8.3. [108]Other Networks
+
+ C-Kermit supports not only serial-port and modem connections, but also
+ TCP/IP and X.25 network connections. Some versions support other
+ network types too like DECnet, LAT, NETBIOS, etc. If you define the
+ following symbol:
+
+ NONET
+
+ then all network support is compiled away.
+
+ 8.1. TCP/IP
+
+ SUBSECTION CONTENTS
+
+ 8.1.1. [109]Firewalls
+ 8.1.2. [110]Compilation and Linking Problems
+ 8.1.3. [111]Enabling Host Address Lists
+ 8.1.4. [112]Enabling Telnet NAWS
+ 8.1.5. [113]Enabling Incoming TCP/IP Connections
+ 8.1.6. [114]Disabling SET TCP Options
+
+ C-Kermit's TCP/IP features require the Berkeley sockets library or
+ equivalent, generally available on any Unix system, as well as in
+ Windows 9x/NT, OS/2, VMS, AOS/VS, VOS, etc. The TCP/IP support includes
+ built-in TELNET, FTP, and HTTP protocol. To select TCP/IP support,
+ include -DTCPSOCKET in your makefile target's CFLAGS, or (in VMS) the
+ appropriate variant (e.g. -DWOLLONGONG, -DMULTINET, -DEXCELAN,
+ -DWINTCP, etc).
+
+ The VMS and/or early Unix third-party TCP/IP products are often
+ incompatible with each other, and sometimes with different versions of
+ themselves. For example, Wollongong reportedly put header files in
+ different directories for different UNIX versions:
+
+ * in.h can be in either /usr/include/sys or /user/include/netinet.
+ * telnet.h can be in either /usr/include/arpa or
+ /user/include/netinet.
+ * inet.h can be in either /usr/include/arpa or /user/include/sys.
+
+ In cases like this, use the -I cc command-line option when possible;
+ otherwise it's better to make links in the file system than it is to
+ hack up the C-Kermit source code. Suppose, for example, Kermit is
+ looking for telnet.h in /usr/include/arpa, but on your computer it is
+ in /usr/include/netinet. Do this (as root, or get the system
+ administrator to do it):
+
+ cd /usr/include/arpa
+ ln /usr/include/netinet/telnet.h telnet.h
+
+ ("man ln" for details about links.)
+
+ The network support for TCP/IP and X.25 is in the source files
+ [115]ckcnet.h, [116]ckctel.c, [117]ckctel.c, [118]ckctel.h,
+ [119]ckcftp.c, with miscellaneous SHOW commands, etc, in the various
+ ckuus*.c modules, plus code in the ck*con.c or ckucns.c (CONNECT
+ command) and several other modules to detect TELNET negotiations, etc.
+
+ Within the TCPSOCKET code, some socket-level controls are included if
+ TCPSOCKET is defined in the C-Kermit CFLAGS and SOL_SOCKET is defined
+ in in the system's TCP-related header files, such as <sys/socket.h>.
+ These are:
+
+ SET TCP KEEPALIVE
+ SET TCP LINGER
+ SET TCP RECVBUF
+ SET TCP SENDBUF
+
+ In addition, if TCP_NODELAY is defined, the following command is also
+ enabled:
+
+ SET TCP NODELAY (Nagle algorithm)
+
+ See the [120]C-Kermit user documentation for descriptions of these
+ commands.
+
+ 8.1.1. Firewalls
+
+ There exist various types of firewalls, set up to separate users of an
+ internal TCP/IP network ("Intranet") from the great wide Internet, but
+ then to let selected users or services get through after all.
+
+ One firewall method is called SOCKS, in which a proxy server allows
+ users inside a firewall to access the outside world, based on a
+ permission list generally stored in a file. SOCKS is enabled in one of
+ two ways. First, the standard sockets library is modified to handle the
+ firewall, and then all the client applications are relinked (if
+ necessary, i.e. if the libraries are not dynamically loaded) with the
+ modified sockets library. The APIs are all the same, so the
+ applications do not need to be recoded or recompiled.
+
+ In the other method, the applications must be modified to call
+ replacement routines, such as Raccept() instead of accept(), Rbind()
+ instead of bind(), etc, and then linked with a separate SOCKS library.
+ This second method is accomplished (for SOCKS4) in C-Kermit by
+ including -DCK_SOCKS in your CFLAGS, and also adding:
+
+ -lsocks
+
+ to LIBS, or replacing -lsockets with -lsocks (depending on whether the
+ socks library also includes all the sockets entry points).
+
+ For SOCKS5, use -DCK_SOCKS5.
+
+ Explicit firewall support can, in general, not be a standard feature or
+ a feature that is selected at runtime, because the SOCKS library tends
+ to be different at each site -- local modifications abound.
+
+ The ideal situation occurs when firewalls are supported by the first
+ method, using dynamically linked sockets-replacement libraries; in this
+ case, all your TCP/IP client applications negotiate the firewall
+ transparently.
+
+ 8.1.2. Compilation and Linking Problems
+
+ If you get a compilation error in [121]ckcnet.c, with a complaint like
+ "incompatible types in assignment", it probably has something to do
+ with the data type your system uses for the inet_addr() function, which
+ is declared (usually) in <arpa/inet.h>. Kermit uses "unsigned long"
+ unless the symbol INADDRX is defined, in which case "struct inaddr" is
+ used instead. Try adding -DINADDRX to CFLAGS in your make entry, and if
+ that fixes the problem, please send a report to kermit@columbia.edu.
+
+ Compilation errors might also have to do with the data type used for
+ getsockopt() and setsockopt() option-length field. This is normally an
+ int, but sometimes it's a short, a long, or an unsigned any of those,
+ or a size_t. To fix the compilation problem, add -DSOCKOPT_T=xxx to the
+ CFLAGS in your makefile target, where xxx is the appropriate type (use
+ "man getsockopt" or grep through your system/network header files to
+ find the needed type).
+
+ 8.1.3. Enabling Host Address Lists
+
+ When you give Kermit an IP host name, it calls the socket routine
+ gethostbyname() to resolve it. gethostbyname() returns a hostent
+ struct, which might or might not not include a list of addresses; if it
+ does, then if the first one fails, Kermit can try the second one, and
+ so on. However, this will only work if the symbol "h_addr" is a macro
+ defined as "h_addr_list[0]", usually in netdb.h. If it is, then you can
+ activate this feature by defining the following symbol in CFLAGS:
+
+ HADDRLIST
+
+ 8.1.4. Enabling Telnet NAWS
+
+ The Telnet Negotiation About Window Size (NAWS) option requires the
+ ability to find out the terminal screen's dimensions. E.g. in Unix, we
+ need something like ioctl(0, TIOCGWINSZ, ...). If your version of
+ Kermit was built with NAWS capability, SHOW VERSIONS includes CK_NAWS
+ among the compiler options. If it doesn't, you can add it by defining
+ CK_NAWS at compile time. Then, if the compiler or linker complain about
+ undefined or missing symbols, or there is no complaint but SHOW
+ TERMINAL fails to show reasonable "Rows =, Columns =" values, then take
+ a look at (or write) the appropriate ttgwsiz() routine. On the other
+ hand, if CK_NAWS is defined by default for your system (in
+ [122]ckcnet.h), but causes trouble, you can override this definition by
+ including the -DNONAWS switch on your CC command line, thus disabling
+ the NAWS feature.
+
+ This appears to be needed at least on the AT&T 3B2, where in
+ [123]ckutio.c, the routine ttgwsiz() finds that the TIOCGWINSZ symbol
+ is defined but lacks definitions for the corresponding winsize struct
+ and its members ws_col and ws_row.
+
+ The UNIX version of C-Kermit also traps SIGWINCH, so it can send a NAWS
+ to the Telnet server any time the local console terminal window size
+ changes, e.g. when you stretch it with a mouse. The SIGWINCH-trapping
+ code is enabled if SIGWINCH is defined (i.e. in signal.h). If this code
+ should cause problems, you can disable it without disabling the NAWS
+ feature altogether, by defining NOSIGWINCH at compile time.
+
+ 8.1.5. Enabling Incoming TCP/IP Connections
+
+ This feature lets you "set host * port" and wait for an incoming
+ connection on the given port. This feature is enabled automatically at
+ compile if TCPSOCKET is defined and SELECT is also defined. But watch
+ out, simply defining SELECT on the cc command line does not guarantee
+ successful compilation or linking (see [124]Section 11).
+
+ If you want to disable incoming TCP/IP connections, then build C-Kermit
+ with:
+
+ -DNOLISTEN
+
+ 8.1.6. Disabling SET TCP Options
+
+ The main reason for this is because of header file / prototype
+ conflicts at compile time regarding get- / setsockopt(). If you can't
+ fix them (without breaking other builds), add the following in CFLAGS:
+
+ -DNOTCPOPTS
+
+ 8.2. X.25
+
+ X.25 support requires (a) a Sun, (b) the SunLink product (libraries and
+ header files), and (c) an X.25 connection into your Sun. Similarly (in
+ C-Kermit 7.0 or later) Stratus VOS and IBM AIX.
+
+ In UNIX, special makefile targets sunos4x25 and sunos41x25 (for SUNOS
+ 4.0 and 4.1, respectively), or aix41x25, are provided to build in this
+ feature, but they only work if conditions (a)-(c) are met. To request
+ this feature, include -DSUNX25 (or -DIBMX25) in CFLAGS.
+
+ SUNX25 (or -DIBMX25) and TCPSOCKET can be freely mixed and matched, and
+ selected by the user at runtime with the SET NETWORK TYPE command or
+ SET HOST switches.
+
+ 8.3. Other Networks
+
+ Support for other networking methods -- NETBIOS, LAT, Named Pipes, etc
+ -- is included in ck*net.h and ck*net.c for implementations (such as
+ Windows or OS/2) where these methods are supported.
+
+ Provision is made in the organization of the modules, header files,
+ commands, etc, for addition of new network types such as DECnet, X.25
+ for other systems (HP-UX, VMS, etc), and so on. Send email to
+ [125]kermit@columbia.edu if you are willing and able to work on such a
+ project.
+
+ [ [126]C-Kermit Home ] [ [127]Kermit Home ]
+
+ 9. EXCEPTION HANDLING
+
+ [ [128]Top ] [ [129]Contents ] [ [130]Next ] [ [131]Previous ]
+
+ The C language setjmp/longjmp mechanism is used for handling
+ exceptions. The jump buffer is of type jmp_buf, which almost everywhere
+ is typedef'd as an array, in which case you should have no trouble
+ compiling the exception-handling code. However, if you are building
+ C-Kermit in/for an environment where jmp_buf is something other than an
+ array (e.g. a struct), then you'll have to define the following symbol:
+
+ JBNOTARRAY
+
+ [ [132]C-Kermit Home ] [ [133]Kermit Home ]
+
+ 10. SECURITY FEATURES
+
+ [ [134]Top ] [ [135]Contents ] [ [136]Next ] [ [137]Previous ]
+
+ Security, in the sense of secure authentication and strong encryption,
+ can be built into versionf of C-Kermit for which the appropriate
+ libraries and header files are available (Kerberos IV, Kerberos V,
+ OpenSSL, SRP), as explained in great detail in the Kermit Security
+ Reference
+ . The following symbols govern C-Kermit's security features at build
+ time:
+
+ NO_AUTHENTICATION
+ Means do not configure any TELNET AUTHENTICATION support. It
+ implies NO_ENCRYPTION and undefines any of the auth and encrypt
+ types. It does not undefine CK_SSL even though builds with
+ CK_SSL cannot succeed without CK_AUTHENTICATION. (This will be
+ supported in a future release. It will be needed to allow
+ C-Kermit to be built only as an FTP client.)
+
+ NO_KERBEROS
+ Means do not compile in any KERBEROS support when
+ CK_AUTHENTICATION has been defined.
+
+ NO_SRP
+ Do not compile in any SRP support when CK_AUTHENTICATION has
+ been defined.
+
+ NO_SSL
+ Do not compile in any SSL/TLS support
+
+ NO_ENCRYPTION
+ Do not compile in any Telnet encryption support. It does not
+ affect the use of SSL/TLS
+
+ NOSSH
+ Do not compile in any SSH support whether internal or external
+
+ CK_AUTHENTICATION
+ Telnet AUTHENTICATION support. (Also, required if SSL/TLS
+ support is desired.) On most platforms this does not autodefine
+ any authentication mechanisms such as Kerberos V, Kerberos IV,
+ SRP, ... Those need to be defined separately.
+
+ CK_KERBEROS
+ Defined automatically when KRB4, KRB5, or KRB524 are defined.
+ Implies that some version of Kerberos is in use.
+
+ KRB4
+ Should be defined when Kerberos IV support is desired.
+
+ KRB5
+ Should be defined when Kerberos V support is desired.
+
+ KRB524
+ Should be defined if both Kerberos V and Kerberos IV are used
+ and the Kerberos IV support is provided by the MIT Kerberos IV
+ compatibility library in the current Kerberos 5 distribution.
+
+ KRB5_U2U
+ Should be defined if KRB5 is defined and Kerberos 5 User to User
+ mode is desired.
+
+ HEIMDAL
+ Should be defined if Kerberos V support is provided by HEIMDAL.
+ Support for this option is not complete in C-Kermit 8.0. Anyone
+ interested in working on this should contact kermit-support.
+
+ CK_SRP
+ Should be defined if SRP support is desired.
+
+ CK_ENCRYPTION
+ Should be defined if TELNET ENCRYPTION option support is
+ desired. This option does not define any particular encryption
+ types. That should be done by defining CK_DES or CK_CAST.
+
+ CK_DES
+ Should be defined if either DES or 3DES Telnet Encryption option
+ support is desired.
+
+ LIBDES
+ If CK_DES is defined and DES support is being provided by either
+ Eric Young's libdes.a or OpenSSL 0.9.6x or earlier, this option
+ must be defined. If it is not defined, it will be assumed that
+ DES support is provided by the MIT Kerberos IV libraries.
+
+ CK_CAST
+ Should be defined if CAST Telnet Encryption option support is
+ desired
+
+ CK_SSL
+ Should be defined if SSL/TLS support (OpenSSL) is desired.
+
+ SSL_KRB5
+ If KRB5 is defined, and OpenSSL is built to support the Kerberos
+ 5 ciphers, then you should define SSL_KRB5
+
+ NOSSLKRB5
+ If you are using OpenSSL 0.9.7 or higher and do not wish to
+ build with support for Kerberos 5 TLS ciphers, this option must
+ be defined.
+
+ ZLIB
+ If you are using OpenSSL 0.9.6 or higher and it has been
+ compiled with support for ZLIB compression, this option should
+ be defined to enable Kermit to properly enable the use of
+ compression.
+
+ SSHCMD
+ Defined for C-Kermit to enable the use of external SSH clients
+ from the Kermit command language
+
+ SSHBUILTIN
+ Defined for Kermit implementations that have integrated SSH
+ support. Currently only Windows.
+
+ ANYSSH
+ Defined if either SSHCMD or SSHBUILTIN are defined.
+
+ CK_SNDLOC
+ Telnet Send Location support.
+
+ NOSNDLOC
+ Do not include Telnet Send Location support.
+
+ CK_XDISPLOC
+ Telnet X-Display Location support. Determines if the X-Display
+ location information is sent to the Telnet server either via
+ Telnet XDISPLOC or NEW-ENV options.
+
+ NOXDISPLOC
+ Do not include Telnet X-Display Location support.
+
+ CK_FORWARD_X
+ Telnet Forward X Windows Session Data option. Used to protect
+ the privacy and integrity of X Windows Sessions when secure
+ telnet sessions are in use.
+
+ NOFORWARDX
+ Do not include Telnet Forward X Windows Session Data option.
+
+ Besides the strong forms of security listed above, C-Kermit also
+ embodies various internal security features, including:
+
+ NOPUSH
+ Compiling with the NOPUSH symbol defined removes all the "shell
+ escape" features from the program, including the PUSH, RUN, and
+ SPAWN commands, the "!" and "@" command prefixes, OPEN !READ,
+ OPEN !WRITE, job control (including the SUSPEND command), the
+ REDIRECT command, shell/DCL escape from CONNECT mode, as well as
+ the server's execution of REMOTE HOST commands (and, of course,
+ the ENABLE HOST command). Add NODISPO to also prevent acceptance
+ of incoming MAIL or REMOTE PRINT files. For UNIX, also be sure
+ to read [138]Section 11 of the [139]Unix C-Kermit Installation
+ Instructions. about set[ug]id configuration. Additional
+ restrictions can be enforced when in server mode; read about the
+ DISABLE command in the user manual.
+
+ NOCCTRAP
+ Compiling with NOCCTRAP prevents the trapping of SIGINT by
+ Kermit. Thus if the user generates a SIGINT signal (e.g. by
+ typing the system's interrupt character), Kermit will exit
+ immediately, rather than returning to its prompt.
+
+ NOPUSH and NOCCTRAP together allow Kermit to be run from restricted
+ shells, preventing access to system functions.
+
+ [ [140]C-Kermit Home ] [ [141]Kermit Home ]
+
+ 11. ENABLING SELECT()
+
+ [ [142]Top ] [ [143]Contents ] [ [144]Next ] [ [145]Previous ]
+
+ Kermit works best if it can do nonblocking reads, nondestructive input
+ buffer checking, and millisecond sleeps. All of these functions can be
+ accomplished by the select() function, which, unfortunately, is not
+ universally available. Furthermore, select() is required if incoming
+ TCP/IP connections are to be supported.
+
+ select() was introduced with Berkeley UNIX, rejected by AT&T for System
+ V, but is gradually creeping in to all UNIX versions (and other
+ operating systems too) by virtue of its presence in the sockets
+ library, which is needed for TCP/IP. AT&T SVID for System V R4 includes
+ select(), but that does not mean that all SVR4 implementations have it.
+
+ Furthermore, even when select() is available, it might work only on
+ socket file descriptors, but not on others like serial ports, pipes,
+ etc. For example, in AOS/VS and BeOS, it works only with file
+ descriptors that were created by socket() and opened by connect() or
+ accept().
+
+ Other alternatives include poll() and rdchk(). Only one of these three
+ functions should be included. The following symbols govern this:
+
+ SELECT Use select() (BSD, or systems with sockets libraries)
+ CK_POLL Use poll() (System V)
+ RDCHK Use rdchk() (SCO XENIX and UNIX)
+
+ If your system supports the select() function, but your version of
+ C-Kermit does not, try adding:
+
+ -DSELECT
+
+ to the CFLAGS, and removing -DRDCHK or -DCK_POLL if it is there. If you
+ get compilation errors, some adjustments to ck*tio.c and/or ck*net.c
+ might be needed; search for SELECT (uppercase) in these files (note
+ that there are several variations on the calling conventions for
+ select()).
+
+ Various macros and data types need to be defined in order to use
+ select(). Usually these are picked up from <types.h> or <sys/types.h>.
+ But on some systems, they are in <sys/select.h>. In that case, add the
+ following:
+
+ -DSELECT_H
+
+ to the CFLAGS to tell C-Kermit to #include <sys/select.h>. A good
+ indication that you need to do this would be if you get compile-time
+ complaints about "fd_set" or "FD_SET" not being declared or defined.
+
+ In UNIX, the use of select() vs fork() in the CONNECT command is
+ independent of the above considerations, and is governed by choosing a
+ particular makefile target.
+
+ As of C-Kermit 7.0, select() is also the preferred control mechanism
+ for the CONNECT command. Unfortunately, the structures used by the
+ original UNIX CONNECT command, based on fork(), and those used by
+ select(), are so different, it was not practical to implement them both
+ in one module. So the select()-based CONNECT command module for UNIX is
+ [146]ckucns.c, and the fork-based one remains [147]ckucon.c. To choose
+ the fork-based one, which is more portable (but slower and more
+ fragile), use "wermit" as the make target. To choose the select-based
+ one, use "xermit". Only do this if you can verify that the CONNECT
+ command works on serial connections and PIPE connections as well as TCP
+ connections.
+
+ The select()-based Unix CONNECT module, ckucns.c, must be used if
+ encryption is to be done, since the fork() version (ckucon.c) loses
+ its ability to share vital state information between the two forks.
+ Also note that the select() version is superior in many other ways
+ too. For example, it recovers better from exterior killing, forced
+ disconnections, etc, plus it goes faster.
+
+ SHOW VERSIONS tells whether the CONNECT module uses fork() or select().
+
+ C-Kermit 8.0 adds learned script capability, which depends on select().
+ All the "wermit" based targets (as opposed to "xermit") had NOLEARN
+ added to them. Whenever changing a target over from wermit to xermit,
+ also remember to remove NOLEARN.
+
+ [ [148]C-Kermit Home ] [ [149]Kermit Home ]
+
+ 12. I/O REDIRECTION
+
+ [ [150]Top ] [ [151]Contents ] [ [152]Next ] [ [153]Previous ]
+
+ The REDIRECT command allows a local program to be run with its i/o
+ redirected over the communications connection. Your version of C-Kermit
+ has a REDIRECT command if it was built with the following CFLAG:
+
+ -DCK_REDIR
+
+ This, in turn, is possible only if the underlying API is there. In the
+ case of UNIX this is just the wait() system call, so all UNIX versions
+ get this feature as of 6.0.192 (earlier versions needed a <sys/wait.h>
+ header file defining the symbols WIFEXITED and WEXITSTATUS).
+
+ As of version 7.0, file transfer can be done using pipes and filters.
+ To enable this feature, #define PIPESEND (and fill in the code). To
+ disable on systems where it is normally enabled, define NOPIPESEND.
+ This feature is, of course, also disabled by building with NOPUSH (or
+ giving the "nopush" command at runtime).
+
+ C-Kermit 7.0 also adds the PIPE and SET HOST /COMMAND commands, which
+ provide another form of redirection. This feature is selected with
+ -DNETCMD. CK_RDIR must also be defined, since the same mechanisms are
+ used internally.
+
+ [ [154]C-Kermit Home ] [ [155]Kermit Home ]
+
+ 13. FLOATING-POINT NUMBERS, TIMERS, AND ARITHMETIC
+
+ [ [156]Top ] [ [157]Contents ] [ [158]Next ] [ [159]Previous ]
+
+ Floating-point support was added in C-Kermit 7.0.
+
+ Floating-point numbers are enabled internally, at least for use in
+ high-precision file-transfer timers and statistics, unless the
+ following symbol is defined at compile time:
+
+ -DNOFLOAT
+
+ This might be necessary on old PCs that do not have built-in
+ floating-point hardware.
+
+ When NOFLOAT is not defined, the following symbol tells which
+ floating-point type to use:
+
+ -DCKFLOAT=xxxx
+
+ The value is either "double" (normal for 32- and 16-bit architectures)
+ or "float" (normal for 64-bit architectures).
+
+ C-Kermit can be configured to use high-precision file-transfer timers
+ for more accurate statistics. This feature is enabled with:
+
+ -DGFTIMER
+
+ and disabled with:
+
+ -DNOGFTIMER
+
+ If you try to build with -DGFTIMER but you get compilation errors,
+ either fix them (and send email to kermit@columbia.edu telling what you
+ did), or else give up and use -DNOGFTIMER (or -DNOFLOAT) instead. Hint:
+ depending on your machine architecture, you might have better luck
+ using double than float as the data type for floating-point numbers, or
+ vice versa. Look in [160]ckcdeb.h for the CKFLOAT definition.
+
+ Floating-point arithmetic is also supported in the script programming
+ language. First via the \fpp...() functions, such as \fppadd(), which
+ adds two floating-point numbers, second in S-Expressions. Addition,
+ subtraction, multiplication, and division are always available. But
+ other functions such as logs, raising to powers, sines and cosines,
+ etc, require the C Math library. To include user-level floating-point
+ math you must put:
+
+ -DFNFLOAT
+
+ and in Unix you must link with the Math library:
+
+ LIBS=".... -lm"
+
+ In K95 and VMS, FNFLOAT is defined automatically if CKFLOAT is defined.
+ In Unix, however, FNFLOAT must be added to each makefile target
+ individually, because of the special linking instructions that must
+ also be added to each target.
+
+ Note: S-Expressions require FNFLOAT.
+
+ [ [161]C-Kermit Home ] [ [162]Kermit Home ]
+
+ 14. SPECIAL CONFIGURATIONS
+
+ [ [163]Top ] [ [164]Contents ] [ [165]Previous ]
+
+ As of C-Kermit 7.0, if you build C-Kermit normally, but with -DNOICP
+ (No Interactive Command Parser), you get a program capable of making
+ serial connections (but not dialing) and network connections (if
+ TCPSOCKET or other network option included), and can also transfer
+ files using Kermit protocol, but only via autodownload/upload.
+ Furthermore, if you call the executable "telnet", it will act like
+ Telnet -- using the command-line options. However, in this case there
+ is nothing to escape back to, so if you type Ctrl-\c, it just prints a
+ message to this effect.
+
+ You can also build C-Kermit with -DNOXFER, meaning omit all the
+ file-transfer features. This leaves you with a scriptable
+ communications program that is considerably smaller than the full
+ C-Kermit.
+
+ [ [166]C-Kermit Home ] [ [167]Kermit Home ]
+
+ APPENDIX I: SUMMARY OF COMPILE-TIME OPTIONS
+
+ [ [168]Top ] [ [169]Contents ]
+
+ These are the symbols that can be specified on the cc command line,
+ listed alphabetically. Others are used internally, including those
+ taken from header files, those defined by the compiler itself, and
+ those inferred from the ones given below. Kermit's SHOW VERSIONS
+ command attempts to display most of these. See [170]ckcdeb.h and
+ [171]ckcnet.h for inference rules. For example SVR3 implies ATTSV,
+ MULTINET implies TCPSOCKET, and so on.
+
+ Here is the complete list of the Kermit-specific compile-time switches:
+
+ ACUCNTRL Select BSD 4.3-style acucntrl() bidirectional tty control.
+ aegis Build for Apollo Aegis (predefined on Apollo systems).
+ AIX370 Build for IBM AIX/370 for IBM mainframes.
+ AIXESA Build for IBM AIX/ESA for IBM mainframes.
+ AIXPS2 Build for IBM AIX 3.0 for PS/2 series (never formally released).
+ AIXRS Build for IBM AIX 3.x on RS/6000.
+ AIX41 Build for IBM AIX 4.x on RS/6000.
+ AMIGA Build for Commodore Amiga with Intuition OS.
+ ATT6300 Build for AT&T 6300 PLUS.
+ ATT7300 Build for AT&T 7300 UNIX PC (3B1).
+ ATTSV Build for AT&T System III or V UNIX.
+ AUX Build for Apple A/UX for the Macintosh.
+ BIGBUFOK OK to use big buffers - "memory is not a problem"
+ BPS_xxxx Enable SET SPEED xxxx
+ BSD29 Build for BSD 2.9 or 2.10.
+ BSD4 Build for BSD 4.2.
+ BSD41 Build for BSD 4.1.
+ BSD43 Build for BSD 4.3.
+ BSD44 Build for BSD 4.4.
+ C70 Build for BBN C/70.
+ CIE Build for CIE Systems 680/20.
+ CKCONINTB4CB Work around prompt-disappears after escape back from
+ CONNECT.
+ CKLEARN Build with support for learned scripts.
+ CKLOGDIAL Enable connection log.
+ CKMAXPATH Maximum length for a fully qualified filename.
+ CKREGEX (misnomer) Include [...] or {xxx,xxx,xxx} matching in
+ ckmatch().
+ CKSYSLOG Enable syslogging.
+ CK_ANSIC Enable ANSI C constructs - prototypes, etc.
+ CK_ANSILIBS Use header files for ANSI C libraries.
+ CK_APC Enable APC execution by CONNECT module.
+ CK_CURSES Enable fullscreen file transfer display.
+ CK_DSYSINI Use system-wide init file, with name supplied by Kermit.
+ CK_DTRCD DTR/CD flow control is available.
+ CK_FAST Build with fast Kermit protocol defaults.
+ CK_FORK_SIG UNIX only: signal() number for CONNECT module forks.
+ CK_IFRO IF REMOTE command is available (and can run in remote mode).
+ CK_INI_A System-wide init file takes precedence over user's.
+ CK_INI_B User's init file takes precedence over the system-wide one.
+ CK_LABELED Include support for SET FILE TYPE LABELED.
+ CK_LBRK This version can send Long BREAK.
+ CK_LINGER Add code to turn of TCP socket "linger" parameter.
+ CK_MKDIR This version has a zmkdir() command to create directories.
+ CK_NAWS Include TELNET Negotiate About Window Size support.
+ CK_NEWTERM Use newterm() rather than initscr() to initialize curses.
+ CK_PAM Include PAM authentication (might also require -lpam).
+ CK_PCT_BAR Fullscreen file transfer display should include
+ "thermometer".
+ CK_POLL System-V or POSIX based UNIX has poll() function.
+ CK_POSIX_SIG Use POSIX signal handing: sigjmp_buf, sigsetjmp,
+ siglongjmp.
+ CK_READ0 read(fd,&x,0) can be used to test TCP/IP connections.
+ CK_REDIR Enable the REDIRECT command.
+ CK_RESEND Include the RESEND command (needs zfseek() + append).
+ CK_RTSCTS RTS/CTS flow control is available.
+ CK_SHADOW Include support for shadow passwords (e.g. for IKSD
+ authentication).
+ CK_SOCKBUF Enable TCP socket-buffer-size-increasing code.
+ CK_SOCKS UNIX only: Build with socks library rather than regular
+ sockets
+ CK_SOCKS5 UNIX only: Build with socks 5 lib rather than regular sockets
+ CK_SPEED Enable control-character unprefixing.
+ CK_SYSINI="xxxxx" Quoted string to be used as system-wide init file
+ name.
+ CK_TIMERS Build with support for dynamically calculated packet
+ timeouts.
+ CK_TMPDIR This version of Kermit has an isdir() function.
+ CK_TTYFD Defined on systems where the communications connection file
+ descriptor (ttyfd) can be passed to other processes as a command-line
+ argument via \v(ttyfd).
+ CK_URL Parse URLs as well as hostnames, etc.
+ CK_XONXOFF Xon/Xoff flow control available.
+ CK_XYZ Include support for XYZMODEM protocols.
+ CK_WREFRESH Curses package includes wrefresh(),clearok() for screen
+ refresh.
+ CKFLOAT=type Floating-point data type, "double" or "float".
+ CKTYP_H=xxx Force include of xxx as <types.h> file.
+ CLSOPN When hanging up a tty device, also close and reopen it.
+ CMDDEP Maximum recursion depth for self-referential user-defined fn's.
+ COHERENT Build for Mark Williams Coherent UNIX
+ CONGSPD Define if this version has congspd() routine in ck?tio.c
+ datageneral Build for Data General AOS/VS or AOS/VS II
+ DCLPOPEN popen() is available but needs to be declared
+ DEC_TCPIP Build with support for DEC TCP/IP (UCX) for (Open)VMS
+ DGUX430 Build for DG/UX 4.30
+ DGUX540 Build for DG/UX 5.40
+ DEFPAR=x Default parity, 0, 'e', 'o', 'm', or 's'.
+ DFTTY=xxx Default communications device name.
+ DIRENT UNIX directory structure to be taken from <dirent.h>.
+ DIRPWDRP Prompt for password in REMOTE CWD command.
+ DTILDE Include UNIX ~ notation for username/home-directory
+ DYNAMIC Allocate file transfer packet buffers dynamically with malloc.
+ ENCORE Build for Encore Multimax computers.
+ EXCELAN Build with excelan TCP/IP.
+ FNFLOAT Include floating-point math functions (logs, sin, cos, exp,
+ etc)
+ FT18 Build for Fortune For:Pro 1.8.
+ FT21 Build for Fortune For:Pro 2.1.
+ GEMDOS Build for Atari ST GEMDOS.
+ GFTIMER Use high-precision floating-point file-transfer timers.
+ GID_T=xxx Group IDs are of type xxx (usually int, short, or gid_t).
+ HADDRLIST If gethostbyname() hostent struct contains a list of
+ addresses.
+ HDBUUCP Build with support for Honey DanBer UUCP.
+ HPUX Build for Hewlett Packard HP-UX.
+ HPUX9 Build for Hewlett Packard HP-UX 9.x.
+ HPUX10 Build for Hewlett Packard HP-UX 10.x.
+ HWPARITY Define if this version can SET PARITY HARDWARE { EVEN, ODD...}
+ I386IX Build for Interactive System V R3.
+ IFDEBUG Add IF stmts "if (deblog)" before "debug()" calls.
+ INADDRX TCP/IP inet_addr() type is struct inaddr, not unsigned long.
+ INTERLAN Build with support for Racal/Interlan TCP/IP.
+ ISDIRBUG System defs of S_ISDIR and S_ISREG have bug, define ourselves.
+ ISIII Build for Interactive System III.
+ IX370 Build for IBM IX/370.
+ KANJI Build with Kanji character-set translation support.
+ LCKDIR UUCP lock directory is /usr/spool/uucp/LCK/.
+ LFDEVNO UUCP lockfile name uses device numbers, as in SVR4.
+ LINUXFSSTND For Linux, use FSSTND UUCP lockfile conventions (default).
+ LOCK_DIR=xxx UUCP lock directory is xxx (quoted string).
+ LOCKF Use lockf() (in addition to lockfiles) on serial lines
+ LONGFN BSD long filenames supported using <dir.h> and opendir().
+ LYNXOS Build for Lynx OS 2.2 or later (POSIX-based).
+ MAC Build for Apple Macintosh with Mac OS.
+ MATCHDOT Make wildcards match filenames that start with period (.)
+ MAXRP=number Maximum receive-packet length.
+ MAXSP=number Maximum send-packet length.
+ MDEBUG Malloc-debugging requested.
+ MINIDIAL Minimum modem dialer support: CCITT, Hayes, Unknown, and None.
+ MINIX Build for MINIX.
+ MIPS Build for MIPS workstation.
+ MULTINET Build with support for TGV MultiNet TCP/IP (VAX/VMS).
+ M_UNIX Defined by SCO.
+ NAP The nap() is available (conflicts with SELECT and USLEEP)
+ NAPHACK The nap() call is available but only as syscall(3112,...)
+ NDIR BSD long filenames supported using <ndir.h> and opendir().
+ NDGPWNAM Don't declare getpwnam().
+ NDSYSERRLIST Don't declare sys_errlist[].
+ NEEDSELECTDEFS select() is available but we need to define FD_blah
+ ourselves.
+ NETCMD Build with support for SET HOST /COMMAND and PIPE commands.
+ NEXT Build for NeXT Mach 1.x or 2.x or 3.0, 3.1, or 3.2.
+ NEXT33 Build for NeXT Mach 3.3.
+ NOANSI Disable ANSI C function prototyping.
+ NOAPC Do not include CK_APC code.
+ NOARROWKEYS Exclude code to parse ANSI arrow-key sequences.
+ NOB_xxxx Disable SET SPEED xxxx
+ NOBIGBUF Override BIGBUFOK when it is the default
+ NOBRKC Don't try to refer to t_brkc or t_eof tchars structure members.
+ NOCKFQHOSTNAME Exclude code to get fully qualified hostname in case it
+ causes core dumps.
+ NOCCTRAP Disable Control-C (SIGINT) trapping.
+ NOCKSPEED Disable control-prefix removal feature (SET CONTROL).
+ NOCKTIMERS Build without support for dynamic timers.
+ NOCKXYZ Overrides CK_XYZ.
+ NOCKREGEX Do not include [...] or {xxx,xxx,xxx} matching in ckmatch().
+ NOCMDL Build with no command-line option processing.
+ NOCOTFMC No Close(Open()) To Force Mode Change (UNIX version).
+ NOCSETS Build with no support for character set translation.
+ NOCYRIL Build with no support for Cyrillic character set translation.
+ NOCYRILLIC Ditto.
+ NODEBUG Build with no debug logging capability.
+ NODIAL Build with no DIAL or SET DIAL commands.
+ NODISPO Build to always refuse incoming MAIL or REMOTE PRINT files.
+ DNODISPLAY Build with no file-transfer display.
+ NOESCSEQ Build with no support for ANSI escape sequence recognition.
+ NOFAST Do not make FAST Kermit protocol settings the default.
+ NOFDZERO Do not use file descriptor 0 for remote-mode file transfer.
+ NOFILEH Do not #include <sys/file.h>.
+ NOFLOAT Don't include any floating-point data types or operations.
+ NOFRILLS Build with "no frills" (this should be phased out...)
+ NOFTRUNCATE Include this on UNIXes that don't have ftruncate().
+ NOGETUSERSHELL Include this on UNIXes that don't have getusershell().
+ NOGFTIMER Don't use high-precision floating-point file-transfer timers.
+ NOHEBREW Build with no support for Hebrew character sets.
+ NOHELP Build with no built-in help.
+ NOIKSD Build with IKSD support excluded.
+ NOINITGROUPS Include this on UNIXes that don't have initgroups().
+ NOICP Build with no interactive command parser.
+ NOJC Build with no support for job control (suspend).
+ NOKANJI Build with no support for Japanese Kanji character sets.
+ NOKVERBS Build with no support for keyboard verbs (\Kverbs).
+ NOLATIN2 Build with no ISO Latin-2 character-set translation support.
+ NOLEARN Build with no support for learned scripts.
+ NOLINKBITS Use of S_ISLNK and _IFLNK untrustworthy; use readlink()
+ instead.
+ NOLOCAL Build without any local-mode features: No Making Connections.
+ NOLOGDIAL Disable connection log.
+ NOLOGIN Build without IKSD (network login) support.
+ NOLSTAT Not OK to use lstat().
+ NOMDMHUP Build without "modem-specific hangup" (e.g. ATH0) feature.
+ NOMHHOST Exclude the multihomed-host TCP/IP code (if compilation
+ errors)
+ NOMINPUT Build without MINPUT command.
+ NOMSEND Build with no MSEND command.
+ NONAWS Do not include TELNET Negotiate About Window Size support.
+ NONET Do not include any network support.
+ NONOSETBUF (See NOSETBUF)
+ NOPARSEN Build without automatic parity detection.
+ NOPIPESEND Disable file transfer using pipes and filters.
+ NOPOLL Override CK_POLL definition.
+ NOPOPEN The popen() library call is not available.
+ NOPURGE Build with no PURGE command.
+ NOPUSH Build with no escapes to operating system.
+ NOREALPATH In UNIX, realpath() function is not available.
+ NORECALL Disable the command-recall feature.
+ NOREDIRECT Disable REDIRECT command.
+ NORENAME Don't use rename() system call, use link()/unlink() (UNIX).
+ NORESEND Build with no RESEND command.
+ NORETRY Build with no command-retry feature.
+ NOSCRIPT Build with no SCRIPT command.
+ NOSELECT Don't try to use select().
+ NOSERVER Build with no SERVER mode and no server-related commands.
+ NOSETBUF Don't make console writes unbuffered.
+ NONOSETBUF DO make console writes unbuffered.
+ NOSETREU setreuid() and/or setregid() not available.
+ NOSHOW Build with no SHOW command (not recommended!).
+ NOSIGWINCH Disable SIGWINCH signal trapping.
+ NOSPL Build with no script programming language.
+ NOSTAT Don't call stat() from mainline code.
+ NOSYMLINK Include this for UNIXes that don't have readlink().
+ NOSYSIOCTLH Do not #include <sys/ioctl.h>.
+ NOSYSTIMEH Co not include <sys/time.h>.
+ NOSYSLOG Disable syslogging code.
+ NOTCPOPTS Build with no SET TCP options or underlying support.
+ NOTLOG Build with no support for transaction logging.
+ NOTM_ISDST Struct tm has no tm_isdst member.
+ NOUNICODE Build with no support for Unicode character-set translation.
+ NOURL Don't parse URLs
+ NOUUCP Build with no UUCP lockfile support (dangerous!).
+ NOWARN Make EXIT WARNING be OFF by default (otherwise it's ON).
+ NOWREFRESH Override built-in definition of CK_WREFRESH (q.v.).
+ NOXFER Build with no Kermit or other file-transfer protocols.
+ NOXMIT Build with no TRANSMIT command.
+ NOXPRINT Disables transparent print code.
+ OLDMSG Use old "entering server mode" message (see [172]ckcmai.c).
+ OLINUXHISPEED Build in old Linux hi-serial-speed code (for Linux <=
+ 1.0).
+ OPENBSD Build for OpenBSD.
+ OS2 Build for OS/2.
+ OSF Build for OSF/1.
+ OSFPC Build for OSF/1 on a PC.
+ OSF32 Digital UNIX 3.2 or later.
+ OSF40 Build for Digital UNIX 4.0.
+ OSF50 Build for Digital UNIX 5.0.
+ OSK Build for OS-9.
+ OXOS Build for Olivetti X/OS 2.3.
+ PCIX Build for PC/IX
+ PID_T=xxx Type for pids is xxx (normally int or pid_t).
+ POSIX Build for POSIX: use POSIX header files, functions, etc.
+ _POSIX_SOURCE Disable non-POSIX features.
+ PROVX1 Build for Venix 1.0 on DEC Professional 3xx.
+ PTX Build for Dynix/PTX
+ PWID_T=xxx getpwid() type is xxx.
+ RBSIZ=xxx Define overall size of receive-packet buffer (with DYNAMIC).
+ RDCHK rdchk() system call is available.
+ RENAME rename() system call is available (UNIX).
+ RTAIX Build for AIX 2.2.1 on IBM RT PC.
+ RTU Build for Masscomp / Concurrent RTU.
+ SAVEDUID BSD or other non-AT&T UNIX has saved-setuid feature.
+ SBSIZ=xxx Define overall size of send-packet buffer (use with DYNAMIC).
+ SDIRENT Directory structure specified in <sys/dirent.h>.
+ SELECT select() function available (conflicts with RDCHK and CK_POLL)
+ SELECT_H Include <sys/select.h> for select()-related definitions.
+ SETEUID BSD 4.4-style seteXid() functions available.
+ SIG_V Type for signal() is void. Used to override normal assumption.
+ SIG_I Type for signal() is int. Used to override normal assumption.
+ SOCKOPT_T Override default data type for get/setsockopt() option
+ length.
+ SOLARIS Build for Solaris.
+ SOLARIS25 Build for Solaris 2.5 or later.
+ SONYNEWS Build for Sony NEWS-OS.
+ STERMIOX <sys/termiox.h> is available.
+ STRATUS Build for Stratus VOS.
+ STRATUSX25 Include Stratus VOS X.25 support.
+ SUN4S5 Build for SUNOS 4.x in the System V R3 environment.
+ SUNOS4 Build for SUNOS 4.0 in the BSD environment.
+ SUNOS41 Build for SUNOS 4.1 in the BSD environment.
+ SUNX25 Build with support for SunLink X.25.
+ SVR3 Build for AT&T System V Release 3.
+ SVR3JC Allow job control support on System V Release 3 UNIX versions.
+ SVR4 Build for AT&T System V Release 4.
+ SW_ACC_ID UNIX only -- swap real & effective ids around access() calls.
+ sxaE50 Build for PFU Compact A Series SX/A TISP.
+ SYSLOGLEVEL=n Force syslogging at given level.
+ SYSTIMEH Include <sys/time.h>.
+ SYSUTIMEH Include <sys/utime.h> for setting file dates (88OPEN)
+ TCPSOCKET Build with support for TCP/IP via Berkeley sockets library.
+ TERMIOX <termiox.h> header file is available (mostly SVR4).
+ TNCODE Include TELNET-specific code.
+ TOWER1 Build for NCR Tower 1632 with OS 1.02.
+ TRS16 Build for Tandy 16/6000.
+ UID_T=xxx Type for uids is xxx (normally int or uid_t).
+ UNIX Must be defined for all UNIX versions.
+ UNIX351M AT&T UNIX 3.51m on the AT&T 7300 UNIX PC.
+ USE_ARROWKEYS Include code to parse ANSI arrow-key sequences.
+ USE_LSTAT OK to use lstat().
+ USE_MEMCPY Define this if memcpy()/memset()/memmove() available.
+ USE_STRERROR Define this if strerror() is available.
+ USLEEP usleep() system call available (conflicts with NAP & SELECT).
+ UTEK Build for Tektronix workstations with UTEK OS.
+ UTIMEH Include <utime.h> for setting file dates (SVR4, POSIX)
+ UTS24 Build for Amdahl UTS 2.4.
+ V7 Build for Version 7 UNIX.
+ VMS Build for VAX/VMS.
+ VOID=xxx VOID type for functions (int or void).
+ VXVE Build for CDC VX/VE 5.2.1.
+ WAIT_T=xxx Type of argument passed to wait().
+ WINTCP Build with Wollongong VAX/VMS TCP/IP (implies TCPSOCKET)
+ WOLLONGONG Build with Wollongong UNIX TCP/IP (implies TCPSOCKET)
+ XENIX Build for Xenix (SCO, Tandy, others).
+ XNDIR Support for BSD long filenames via <sys/ndir.h>.
+ XYZ_INTERNAL Support for XYZMODEM protocols is internal, not external.
+ ZFCDAT Define this if zfcdat() function is available in Kermit.
+ ZILOG Build for Zilog ZEUS.
+ ZJDATE Has zjdate() function that converts date to Julian format.
+ XPRINT Transparent print code included in CONNECT module.
+
+ [ [173]Top ] [ [174]Contents ] [ [175]C-Kermit Home ] [ [176]Kermit
+ Home ]
+ __________________________________________________________________
+
+
+ C-Kermit Configuration Options / [177]The Kermit Project /
+ [178]kermit@columbia.edu / 30 June 2011
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/ckccfg.html
+ 12. http://www.columbia.edu/kermit/ckermit.html
+ 13. http://www.columbia.edu/kermit/index.html
+ 14. http://www.columbia.edu/kermit/ckccfg.html#x1
+ 15. http://www.columbia.edu/kermit/ckccfg.html#x2
+ 16. http://www.columbia.edu/kermit/ckccfg.html#x3
+ 17. http://www.columbia.edu/kermit/ckccfg.html#x4
+ 18. http://www.columbia.edu/kermit/ckccfg.html#x5
+ 19. http://www.columbia.edu/kermit/ckccfg.html#x6
+ 20. http://www.columbia.edu/kermit/ckccfg.html#x7
+ 21. http://www.columbia.edu/kermit/ckccfg.html#x8
+ 22. http://www.columbia.edu/kermit/ckccfg.html#x9
+ 23. http://www.columbia.edu/kermit/ckccfg.html#x10
+ 24. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 25. http://www.columbia.edu/kermit/ckccfg.html#x12
+ 26. http://www.columbia.edu/kermit/ckccfg.html#x13
+ 27. http://www.columbia.edu/kermit/ckccfg.html#x14
+ 28. http://www.columbia.edu/kermit/ckccfg.html#xa1
+ 29. http://www.columbia.edu/kermit/ckuins.html
+ 30. http://www.columbia.edu/kermit/ckermit.html
+ 31. http://www.columbia.edu/kermit/index.html
+ 32. http://www.columbia.edu/kermit/ckccfg.html#top
+ 33. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 34. http://www.columbia.edu/kermit/ckccfg.html#x2
+ 35. http://www.columbia.edu/kermit/ckccfg.html#x0
+ 36. http://www.columbia.edu/kermit/ckermit.html
+ 37. http://www.columbia.edu/kermit/index.html
+ 38. http://www.columbia.edu/kermit/ckccfg.html#top
+ 39. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 40. http://www.columbia.edu/kermit/ckccfg.html#x3
+ 41. http://www.columbia.edu/kermit/ckccfg.html#x1
+ 42. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 43. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 44. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+ 45. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 46. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 47. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 48. http://www.columbia.edu/kermit/ckermit.html
+ 49. http://www.columbia.edu/kermit/index.html
+ 50. http://www.columbia.edu/kermit/ckccfg.html#top
+ 51. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 52. http://www.columbia.edu/kermit/ckccfg.html#x4
+ 53. http://www.columbia.edu/kermit/ckccfg.html#x2
+ 54. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 55. http://www.columbia.edu/kermit/ckuins.html
+ 56. http://www.columbia.edu/kermit/ckuins.html#x4
+ 57. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 58. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+ 59. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 60. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 61. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+ 62. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c
+ 63. http://www.columbia.edu/kermit/ckermit.html
+ 64. http://www.columbia.edu/kermit/index.html
+ 65. http://www.columbia.edu/kermit/ckccfg.html#top
+ 66. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 67. http://www.columbia.edu/kermit/ckccfg.html#x5
+ 68. http://www.columbia.edu/kermit/ckccfg.html#x3
+ 69. http://www.columbia.edu/kermit/unicode.html
+ 70. http://www.columbia.edu/kermit/ckermit.html
+ 71. http://www.columbia.edu/kermit/index.html
+ 72. http://www.columbia.edu/kermit/ckccfg.html#top
+ 73. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 74. http://www.columbia.edu/kermit/ckccfg.html#x6
+ 75. http://www.columbia.edu/kermit/ckccfg.html#x4
+ 76. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+ 77. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+ 78. http://www.columbia.edu/kermit/ckermit.html
+ 79. http://www.columbia.edu/kermit/index.html
+ 80. http://www.columbia.edu/kermit/ckccfg.html#top
+ 81. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 82. http://www.columbia.edu/kermit/ckccfg.html#x7
+ 83. http://www.columbia.edu/kermit/ckccfg.html#x5
+ 84. http://www.columbia.edu/kermit/ckccfg.html#x6.1
+ 85. http://www.columbia.edu/kermit/ckccfg.html#x6.2
+ 86. http://www.columbia.edu/kermit/ckccfg.html#x6.3
+ 87. http://www.columbia.edu/kermit/ckccfg.html#x6.4
+ 88. http://www.columbia.edu/kermit/ckccfg.html#x4
+ 89. http://www.columbia.edu/kermit/gkermit.html
+ 90. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+ 91. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h
+ 92. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 93. http://www.columbia.edu/kermit/ckermit.html
+ 94. http://www.columbia.edu/kermit/index.html
+ 95. http://www.columbia.edu/kermit/ckccfg.html#top
+ 96. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 97. http://www.columbia.edu/kermit/ckccfg.html#x8
+ 98. http://www.columbia.edu/kermit/ckccfg.html#x6
+ 99. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c
+ 100. http://www.columbia.edu/kermit/ckermit.html
+ 101. http://www.columbia.edu/kermit/index.html
+ 102. http://www.columbia.edu/kermit/ckccfg.html#top
+ 103. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 104. http://www.columbia.edu/kermit/ckccfg.html#x9
+ 105. http://www.columbia.edu/kermit/ckccfg.html#x7
+ 106. http://www.columbia.edu/kermit/ckccfg.html#x8.1
+ 107. http://www.columbia.edu/kermit/ckccfg.html#x8.2
+ 108. http://www.columbia.edu/kermit/ckccfg.html#x8.3
+ 109. http://www.columbia.edu/kermit/ckccfg.html#x8.1.1
+ 110. http://www.columbia.edu/kermit/ckccfg.html#x8.1.2
+ 111. http://www.columbia.edu/kermit/ckccfg.html#x8.1.3
+ 112. http://www.columbia.edu/kermit/ckccfg.html#x8.1.4
+ 113. http://www.columbia.edu/kermit/ckccfg.html#x8.1.5
+ 114. http://www.columbia.edu/kermit/ckccfg.html#x8.1.6
+ 115. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 116. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 117. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 118. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h
+ 119. ftp://kermit.columbia.edu/kermit/c-kermit/ckcftp.c
+ 120. http://www.columbia.edu/kermit/ckermit.html
+ 121. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 122. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 123. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 124. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 125. mailto:kermit@columbia.edu
+ 126. http://www.columbia.edu/kermit/ckermit.html
+ 127. http://www.columbia.edu/kermit/index.html
+ 128. http://www.columbia.edu/kermit/ckccfg.html#top
+ 129. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 130. http://www.columbia.edu/kermit/ckccfg.html#x10
+ 131. http://www.columbia.edu/kermit/ckccfg.html#x8
+ 132. http://www.columbia.edu/kermit/ckermit.html
+ 133. http://www.columbia.edu/kermit/index.html
+ 134. http://www.columbia.edu/kermit/ckccfg.html#top
+ 135. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 136. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 137. http://www.columbia.edu/kermit/ckccfg.html#x9
+ 138. http://www.columbia.edu/kermit/ckuins.html#x11
+ 139. http://www.columbia.edu/kermit/ckuins.html
+ 140. http://www.columbia.edu/kermit/ckermit.html
+ 141. http://www.columbia.edu/kermit/index.html
+ 142. http://www.columbia.edu/kermit/ckccfg.html#top
+ 143. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 144. http://www.columbia.edu/kermit/ckccfg.html#x12
+ 145. http://www.columbia.edu/kermit/ckccfg.html#x10
+ 146. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c
+ 147. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c
+ 148. http://www.columbia.edu/kermit/ckermit.html
+ 149. http://www.columbia.edu/kermit/index.html
+ 150. http://www.columbia.edu/kermit/ckccfg.html#top
+ 151. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 152. http://www.columbia.edu/kermit/ckccfg.html#x13
+ 153. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 154. http://www.columbia.edu/kermit/ckermit.html
+ 155. http://www.columbia.edu/kermit/index.html
+ 156. http://www.columbia.edu/kermit/ckccfg.html#top
+ 157. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 158. http://www.columbia.edu/kermit/ckccfg.html#x14
+ 159. http://www.columbia.edu/kermit/ckccfg.html#x12
+ 160. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 161. http://www.columbia.edu/kermit/ckermit.html
+ 162. http://www.columbia.edu/kermit/index.html
+ 163. http://www.columbia.edu/kermit/ckccfg.html#top
+ 164. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 165. http://www.columbia.edu/kermit/ckccfg.html#x13
+ 166. http://www.columbia.edu/kermit/ckermit.html
+ 167. http://www.columbia.edu/kermit/index.html
+ 168. http://www.columbia.edu/kermit/ckccfg.html#top
+ 169. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 170. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 171. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 172. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 173. http://www.columbia.edu/kermit/ckccfg.html#top
+ 174. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 175. http://www.columbia.edu/kermit/ckermit.html
+ 176. http://www.columbia.edu/kermit/index.html
+ 177. http://www.columbia.edu/kermit/index.html
+ 178. mailto:kermit@columbia.edu
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcdeb.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcdeb.h
new file mode 100644
index 0000000..34ff008
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcdeb.h
@@ -0,0 +1,6607 @@
+/* C K C D E B . H */
+
+/*
+Mon Aug 23 09:22:05 2010
+
+ NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
+ compatible with C preprocessors that support only #ifdef, #else, #endif,
+ #define, and #undef. Please do not use #if, logical operators, or other
+ later-model preprocessor features in any of the portable C-Kermit modules.
+ You can, of course, use these constructions in platform-specific modules
+ when you know they are supported.
+*/
+
+/*
+ This file is included by all C-Kermit modules, including the modules
+ that aren't specific to Kermit (like the command parser and the ck?tio and
+ ck?fio modules). It should be included BEFORE any other C-Kermit header
+ files. It specifies format codes for debug(), tlog(), and similar
+ functions, and includes any necessary definitions to be used by all C-Kermit
+ modules, and also includes some feature selection compile-time switches, and
+ also system- or compiler-dependent definitions, plus #includes and prototypes
+ required by all C-Kermit modules.
+*/
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ Etymology: The name of this file means "C-Kermit Common-C-Language Debugging
+ Header", because originally it contained only the formats (F000-F111) for
+ the debug() and tlog() functions. Since then it has grown to include all
+ material required by all other C-Kermit modules, including the non-Kermit
+ specific ones. In other words, this is the one header file that is
+ guaranteed to be included by all C-Kermit source modules.
+*/
+
+#ifndef CKCDEB_H /* Don't include me more than once. */
+#define CKCDEB_H
+
+#ifdef OS2
+#include "ckoker.h"
+#else /* OS2 */
+/* Unsigned numbers */
+
+#ifndef USHORT
+#define USHORT unsigned short
+#endif /* USHORT */
+
+#ifndef UINT
+#define UINT unsigned int
+#endif /* UINT */
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif /* ULONG */
+#endif /* OS2 */
+
+#ifdef MACOSX10 /* Mac OS X 1.0 */
+#ifndef MACOSX /* implies Mac OS X */
+#define MACOSX
+#endif /* MACOSX */
+#endif /* MACOSX10 */
+
+#ifdef MACOSX /* Mac OS X */
+#ifndef BSD44 /* implies 4.4 BSD */
+#define BSD44
+#endif /* BSD44 */
+#endif /* MACOSX */
+
+#ifdef SCO_OSR505 /* SCO 3.2v5.0.5 */
+#ifndef SCO_OSR504 /* implies SCO 3.2v5.0.4 */
+#define SCO_OSR504
+#endif /* SCO_OSR504 */
+#endif /* SCO_OSR505 */
+
+#ifdef SCO_OSR504 /* SCO 3.2v5.0.4 */
+#ifndef CK_SCOV5 /* implies SCO 3.2v5.0 */
+#define CK_SCOV5
+#endif /* CK_SCOV5 */
+#include <sys/types.h> /* To sidestep header-file mess */
+#endif /* SCO_OSR504 */
+
+#ifdef CK_SCOV5
+#ifndef ANYSCO
+#define ANYSCO
+#endif /* ANYSCO */
+#endif /* CK_SCOV5 */
+
+#ifdef UNIXWARE
+#ifndef ANYSCO
+#define ANYSCO
+#endif /* ANYSCO */
+#endif /* UNIXWARE */
+
+#ifndef MINIX /* Minix versions */
+#ifdef MINIX315
+#define MINIX
+#else
+#ifdef MINIX3
+#define MINIX
+#else
+#ifdef MINIX2
+#define MINIX
+#endif /* MINIX2 */
+#endif /* MINIX3 */
+#endif /* MINIX315 */
+#endif /* MINIX */
+
+#ifdef CK_SCO32V4 /* SCO 3.2v4 */
+#ifndef ANYSCO
+#define ANYSCO
+#endif /* ANYSCO */
+#ifndef XENIX
+#define XENIX
+#endif /* XENIX */
+#ifndef SVR3
+#define SVR3
+#endif /* SVR3 */
+#ifndef DIRENT
+#define DIRENT
+#endif /* DIRENT */
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#ifndef SVR3JC
+#define SVR3JC
+#endif /* SVR3JC */
+#ifndef CK_RTSCTS
+#define CK_RTSCTS
+#endif /* CK_RTSCTS */
+#ifndef PID_T
+#define PID_T pid_t
+#endif /* PID_T */
+#ifndef PWID_T
+#define PWID_T int
+#endif /* PWID_T */
+#endif /* CK_SCO32V4 */
+
+#ifdef NOICP /* If no command parser */
+#ifndef NOSPL /* Then no script language either */
+#define NOSPL
+#endif /* NOSPL */
+#ifndef NOCSETS /* Or characer sets */
+#define NOCSETS
+#endif /* NOCSETS */
+#ifndef NOFTP /* Or FTP client */
+#define NOFTP
+#endif /* NOFTP */
+#endif /* NOICP */
+
+/* Built-in makefile entries */
+
+#ifdef SOLARIS11 /* Solaris 11 implies 10 */
+#ifndef SOLARIS10
+#define SOLARIS10
+#endif /* SOLARIS10 */
+#endif /* SOLARIS11 */
+
+#ifdef SOLARIS10 /* Solaris 10 implies 9 */
+#ifndef SOLARIS9
+#define SOLARIS9
+#endif /* SOLARIS9 */
+#endif /* SOLARIS10 */
+
+#ifdef SOLARIS9 /* Solaris 9 implies 8 */
+#ifndef SOLARIS8
+#define SOLARIS8
+#endif /* SOLARIS8 */
+#endif /* SOLARIS9 */
+
+#ifdef SOLARIS8 /* Solaris 8 implies 7 */
+#ifndef SOLARIS7
+#define SOLARIS7
+#endif /* SOLARIS7 */
+#endif /* SOLARIS8 */
+
+#ifdef SOLARIS7 /* Solaris 7 implies 2.6 */
+#ifndef SOLARIS26
+#define SOLARIS26
+#endif /* SOLARIS26 */
+#endif /* SOLARIS7 */
+
+#ifdef SOLARIS26 /* Solaris 2.6 implies 2.5 */
+#ifndef SOLARIS25
+#define SOLARIS25
+#endif /* SOLARIS25 */
+#endif /* SOLARIS26 */
+
+#ifdef SOLARIS25 /* Solaris 2.5 implies Solaris */
+#ifndef SOLARIS
+#define SOLARIS
+#endif /* SOLARIS */
+#ifndef POSIX /* And POSIX */
+#define POSIX
+#endif /* POSIX */
+#ifndef CK_WREFRESH /* And this (curses) */
+#define CK_WREFRESH
+#endif /* CK_WREFRESH */
+#endif /* SOLARIS25 */
+
+#ifdef SOLARIS24 /* Solaris 2.4 implies Solaris */
+#ifndef SOLARIS
+#define SOLARIS
+#endif /* SOLARIS */
+#endif /* SOLARIS24 */
+
+#ifdef SOLARIS /* Solaris gets "POSIX" RTS/CTS API */
+#ifdef POSIX
+#ifndef POSIX_CRTSCTS
+#define POSIX_CRTSCTS
+#endif /* POSIX_CRTSCTS */
+#endif /* POSIX */
+#ifndef SVR4
+#define SVR4
+#endif /* SVR4 */
+#ifndef STERMIOX
+#define STERMIOX
+#endif /* STERMIOX */
+#ifndef SELECT
+#define SELECT
+#endif /* SELECT */
+#ifndef FNFLOAT
+#define FNFLOAT
+#endif /* FNFLOAT */
+#ifndef DIRENT
+#define DIRENT
+#endif /* DIRENT */
+#ifndef BIGBUFOK
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#ifndef CK_NEWTERM
+#define CK_NEWTERM
+#endif /* CK_NEWTERM */
+#endif /* SOLARIS */
+
+#ifdef SUN4S5 /* Sun-4 System V environment */
+#ifndef SVR3 /* implies System V R3 or later */
+#define SVR3
+#endif /* SVR3 */
+#endif /* SUN4S5 */
+#ifdef SUNOS41 /* SUNOS41 implies SUNOS4 */
+#ifndef SUNOS4
+#define SUNOS4
+#endif /* SUNOS4 */
+#endif /* SUNOS41 */
+
+#ifdef SUN4S5 /* Sun-4 System V environment */
+#ifndef SVR3 /* implies System V R3 or later */
+#define SVR3
+#endif /* SVR3 */
+#endif /* SUN4S5 */
+
+#ifdef SUNOS41 /* SUNOS41 implies SUNOS4 */
+#ifndef SUNOS4
+#define SUNOS4
+#endif /* SUNOS4 */
+#endif /* SUNOS41 */
+
+#ifdef SUNOS4 /* Built-in SUNOS4 makefile entry */
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#ifndef BSD4
+#define BSD4
+#endif /* BSD4 */
+#ifndef NOSETBUF
+#define NOSETBUF
+#endif /* NOSETBUF */
+#ifndef DIRENT
+#define DIRENT
+#endif /* DIRENT */
+#ifndef NONET
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#endif /* NONET */
+#ifndef SAVEDUID
+#define SAVEDUID
+#endif /* SAVEDUID */
+#ifndef DYNAMIC
+#define DYNAMIC
+#endif /* DYNAMIC */
+#endif /* SUNOS4 */
+
+#ifdef SOLARIS /* Built in makefile entry */
+#ifndef NOSETBUF /* for Solaris 2.x */
+#define NOSETBUF
+#endif /* NOSETBUF */
+#ifndef NOCURSES
+#ifndef CK_CURSES
+#define CK_CURSES
+#endif /* CK_CURSES */
+#endif /* NOCURSES */
+#ifndef CK_NEWTERM
+#define CK_NEWTERM
+#endif /* CK_NEWTERM */
+#ifndef DIRENT
+#define DIRENT
+#endif /* DIRENT */
+#ifndef NONET
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#endif /* NONET */
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#ifndef SVR4
+#define SVR4
+#endif /* SVR4 */
+#ifndef HADDRLIST
+#define HADDRLIST
+#endif /* HADDRLIST */
+#ifndef STERMIOX
+#define STERMIOX
+#endif /* STERMIOX */
+#ifndef SELECT
+#define SELECT
+#endif /* SELECT */
+#ifndef DYNAMIC
+#define DYNAMIC
+#endif /* DYNAMIC */
+#ifndef NOUUCP
+#ifndef HDBUUCP
+#define HDBUUCP
+#endif /* HDBUUCP */
+#endif /* NOUUCP */
+#endif /* SOLARIS */
+
+/* Features that can be eliminated from a no-file-transfer version */
+
+#ifdef NOXFER
+#ifndef NOFTP
+#define NOFTP
+#endif /* NOFTP */
+#ifndef OS2
+#ifndef NOCURSES /* Fullscreen file-transfer display */
+#define NOCURSES
+#endif /* NOCURSES */
+#endif /* OS2 */
+#ifndef NOCKXYZ /* XYZMODEM support */
+#define NOCKXYZ
+#endif /* NOCKXYZ */
+#ifndef NOCKSPEED /* Ctrl-char unprefixing */
+#define NOCKSPEED
+#endif /* NOCKSPEED */
+#ifndef NOSERVER /* Server mode */
+#define NOSERVER
+#endif /* NOSERVER */
+#ifndef NOCKTIMERS /* Dynamic packet timers */
+#define NOCKTIMERS
+#endif /* NOCKTIMERS */
+#ifndef NOPATTERNS /* File-type patterns */
+#define NOPATTERNS
+#endif /* NOPATTERNS */
+#ifndef NOSTREAMING /* Streaming */
+#define NOSTREAMING
+#endif /* NOSTREAMING */
+#ifndef NOIKSD /* Internet Kermit Service */
+#define NOIKSD
+#endif /* NOIKSD */
+#ifndef NOPIPESEND /* Sending from pipes */
+#define NOPIPESEND
+#endif /* NOPIPESEND */
+#ifndef NOAUTODL /* Autodownload */
+#define NOAUTODL
+#endif /* NOAUTODL */
+#ifndef NOMSEND /* MSEND */
+#define NOMSEND
+#endif /* NOMSEND */
+#ifndef NOTLOG /* Transaction logging */
+#define NOTLOG
+#endif /* NOTLOG */
+#ifndef NOCKXXCHAR /* Packet character doubling */
+#define NOCKXXCHAR
+#endif /* NOCKXXCHAR */
+#endif /* NOXFER */
+
+#ifdef NOICP /* No Interactive Command Parser */
+#ifndef NODIAL /* Implies No DIAL command */
+#define NODIAL
+#endif /* NODIAL */
+#ifndef NOCKXYZ /* and no external protocols */
+#define NOCKXYZ
+#endif /* NOCKXYZ */
+#endif /* NOICP */
+
+#ifndef NOIKSD
+#ifdef IKSDONLY
+#ifndef IKSD
+#define IKSD
+#endif /* IKSD */
+#ifndef NOLOCAL
+#define NOLOCAL
+#endif /* NOLOCAL */
+#ifndef NOPUSH
+#define NOPUSH
+#endif /* NOPUSH */
+#ifndef TNCODE
+#define TNCODE
+#endif /* TNCODE */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef NETCONN
+#define NETCONN
+#endif /* NETCONN */
+#ifdef SUNX25
+#undef SUNX25
+#endif /* SUNX25 */
+#ifdef IBMX25
+#undef IBMX25
+#endif /* IBMX25 */
+#ifdef STRATUSX25
+#undef STRATUSX25
+#endif /* STRATUSX25 */
+#ifdef CK_NETBIOS
+#undef CK_NETBIOS
+#endif /* CK_NETBIOS */
+#ifdef SUPERLAT
+#undef SUPERLAT
+#endif /* SUPERLAT */
+#ifdef NPIPE
+#undef NPIPE
+#endif /* NPIPE */
+#ifdef NETFILE
+#undef NETFILE
+#endif /* NETFILE */
+#ifdef NETCMD
+#undef NETCMD
+#endif /* NETCMD */
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#ifdef RLOGCODE
+#undef RLOGCODE
+#endif /* RLOGCODE */
+#ifdef NETDLL
+#undef NETDLL
+#endif /* NETDLL */
+#ifndef NOSSH
+#undef NOSSH
+#endif /* NOSSH */
+#ifndef NOFORWARDX
+#define NOFORWARDX
+#endif /* NOFORWARDX */
+#ifndef NOBROWSER
+#define NOBROWSER
+#endif /* NOBROWSER */
+#ifndef NOHTTP
+#define NOHTTP
+#endif /* NOHTTP */
+#ifndef NOFTP
+#define NOFTP
+#endif /* NOFTP */
+#ifndef NO_COMPORT
+#define NO_COMPORT
+#endif /* NO_COMPORT */
+#endif /* IKSDONLY */
+#endif /* NOIKSD */
+
+/* Features that can be eliminated from a remote-only version */
+
+#ifdef NOLOCAL
+#ifndef NOFTP
+#define NOFTP
+#endif /* NOFTP */
+#ifndef NOHTTP
+#define NOHTTP
+#endif /* NOHTTP */
+#ifndef NOSSH
+#define NOSSH
+#endif /* NOSSH */
+#ifndef NOTERM
+#define NOTERM
+#endif /* NOTERM */
+#ifndef NOCURSES /* Fullscreen file-transfer display */
+#define NOCURSES
+#endif /* NOCURSES */
+#ifndef NODIAL
+#define NODIAL
+#endif /* NODIAL */
+#ifndef NOSCRIPT
+#define NOSCRIPT
+#endif /* NOSCRIPT */
+#ifndef NOSETKEY
+#define NOSETKEY
+#endif /* NOSETKEY */
+#ifndef NOKVERBS
+#define NOKVERBS
+#endif /* NOKVERBS */
+#ifndef NOXMIT
+#define NOXMIT
+#endif /* NOXMIT */
+#ifdef CK_CURSES
+#undef CK_CURSES
+#endif /* CK_CURSES */
+#ifndef IKSDONLY
+#ifndef NOAPC
+#define NOAPC
+#endif /* NOAPC */
+#ifndef NONET
+#define NONET
+#endif /* NONET */
+#endif /* IKSDONLY */
+#endif /* NOLOCAL */
+
+#ifdef NONET
+#ifdef NETCONN
+#undef NETCONN
+#endif /* NETCONN */
+#ifdef TCPSOCKET
+#undef TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef NOTCPOPTS
+#define NOTCPOPTS
+#endif /* NOTCPOPTS */
+#ifdef SUNX25
+#undef SUNX25
+#endif /* SUNX25 */
+#ifdef IBMX25
+#undef IBMX25
+#endif /* IBMX25 */
+#ifdef STRATUSX25
+#undef STRATUSX25
+#endif /* STRATUSX25 */
+#ifdef CK_NETBIOS
+#undef CK_NETBIOS
+#endif /* CK_NETBIOS */
+#ifdef SUPERLAT
+#undef SUPERLAT
+#endif /* SUPERLAT */
+#ifdef NPIPE
+#undef NPIPE
+#endif /* NPIPE */
+#ifdef NETFILE
+#undef NETFILE
+#endif /* NETFILE */
+#ifdef NETCMD
+#undef NETCMD
+#endif /* NETCMD */
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#ifdef RLOGCODE
+#undef RLOGCODE
+#endif /* RLOGCODE */
+#ifdef NETDLL
+#undef NETDLL
+#endif /* NETDLL */
+#ifndef NOSSH
+#define NOSSH
+#endif /* NOSSH */
+#ifndef NOFTP
+#define NOFTP
+#endif /* NOFTP */
+#ifndef NOHTTP
+#define NOHTTP
+#endif /* NOHTTP */
+#ifndef NOBROWSER
+#define NOBROWSER
+#endif /* NOBROWSER */
+#ifndef NOFORWARDX
+#define NOFORWARDX
+#endif /* NOFORWARDX */
+#endif /* NONET */
+
+#ifdef IKSDONLY
+#ifdef SUNX25
+#undef SUNX25
+#endif /* SUNX25 */
+#ifdef IBMX25
+#undef IBMX25
+#endif /* IBMX25 */
+#ifdef STRATUSX25
+#undef STRATUSX25
+#endif /* STRATUSX25 */
+#ifdef CK_NETBIOS
+#undef CK_NETBIOS
+#endif /* CK_NETBIOS */
+#ifdef SUPERLAT
+#undef SUPERLAT
+#endif /* SUPERLAT */
+#ifdef NPIPE
+#undef NPIPE
+#endif /* NPIPE */
+#ifdef NETFILE
+#undef NETFILE
+#endif /* NETFILE */
+#ifdef NETCMD
+#undef NETCMD
+#endif /* NETCMD */
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#ifdef RLOGCODE
+#undef RLOGCODE
+#endif /* RLOGCODE */
+#ifdef NETDLL
+#undef NETDLL
+#endif /* NETDLL */
+#ifndef NOSSH
+#define NOSSH
+#endif /* NOSSH */
+#ifndef NOHTTP
+#define NOHTTP
+#endif /* NOHTTP */
+#ifndef NOBROWSER
+#define NOBROWSER
+#endif /* NOBROWSER */
+#endif /* IKSDONLY */
+/*
+ Note that none of the above precludes TNCODE, which can be defined in
+ the absence of TCPSOCKET, etc, to enable server-side Telnet negotation.
+*/
+#ifndef TNCODE /* This is for the benefit of */
+#ifdef TCPSOCKET /* modules that might need TNCODE */
+#define TNCODE /* not all of ckcnet.h... */
+#endif /* TCPSOCKET */
+#endif /* TNCODE */
+
+#ifndef NETCONN
+#ifdef TCPSOCKET
+#define NETCONN
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+
+#ifndef DEFPAR /* Default parity */
+#define DEFPAR 0 /* Must be here because it is used */
+#endif /* DEFPAR */ /* by all classes of modules */
+
+#ifdef NT
+#ifndef OS2ORWIN32
+#define OS2ORWIN32
+#endif /* OS2ORWIN32 */
+#ifndef OS2
+#define WIN32ONLY
+#endif /* OS2 */
+#endif /* NT */
+
+#ifdef OS2 /* For OS/2 debugging */
+#ifndef OS2ORWIN32
+#define OS2ORWIN32
+#endif /* OS2ORWIN32 */
+#ifdef NT
+#define NOCRYPT
+#include <windows.h>
+#define NTSIG
+#else /* NT */
+#define OS2ONLY
+#include <os2def.h>
+#endif /* NT */
+#ifndef OS2ORUNIX
+#define OS2ORUNIX
+#endif /* OS2ORUNIX */
+#ifndef OS2ORVMS
+#define OS2ORVMS
+#endif /* OS2ORVMS */
+#endif /* OS2 */
+
+#include <stdio.h> /* Begin by including this. */
+#include <ctype.h> /* and this. */
+
+#ifdef VMS
+#include <types.h> /* Ensure off_t. */
+#include "ckvrms.h" /* Get NAMDEF NAMX_C_MAXRSS. */
+#endif /* def VMS */
+
+/* System-type compilation switches */
+
+#ifdef FT21 /* Fortune For:Pro 2.1 implies 1.8 */
+#ifndef FT18
+#define FT18
+#endif /* FT18 */
+#endif /* FT21 */
+
+#ifdef __bsdi__
+#ifndef BSDI
+#define BSDI
+#endif /* BSDI */
+#endif /* __bsdi__ */
+
+#ifdef AIXPS2 /* AIXPS2 implies AIX370 */
+#ifndef AIX370
+#define AIX370
+#endif /* AIX370 */
+#endif /* AIXPS2 */
+
+#ifdef AIX370 /* AIX PS/2 or 370 implies BSD4 */
+#ifndef BSD4
+#define BSD4
+#endif /* BSD4 */
+#endif /* AIX370 */
+
+#ifdef AIXESA /* AIX/ESA implies BSD4.4 */
+#ifndef BSD44
+#define BSD44
+#endif /* BSD44 */
+#endif /* AIXESA */
+
+#ifdef AIX53 /* AIX53 implies AIX52 */
+#ifndef AIX52
+#define AIX52
+#endif /* AIX52 */
+#endif /* AIX53 */
+
+#ifdef AIX52 /* AIX52 implies AIX51 */
+#ifndef AIX51
+#define AIX51
+#endif /* AIX51 */
+#endif /* AIX52 */
+
+#ifdef AIX51 /* AIX51 implies AIX50 */
+#ifndef AIX50
+#define AIX50
+#endif /* AIX50 */
+#endif /* AIX51 */
+
+#ifdef AIX50 /* AIX50 implies AIX45 */
+#ifndef AIX45
+#define AIX45
+#endif /* AIX45 */
+#endif /* AIX50 */
+
+#ifdef AIX45 /* AIX45 implies AIX44 */
+#ifndef AIX44
+#define AIX44
+#endif /* AIX44 */
+#endif /* AIX45 */
+
+#ifdef AIX44 /* AIX44 implies AIX43 */
+#ifndef AIX43
+#define AIX43
+#endif /* AIX43 */
+#endif /* AIX44 */
+
+#ifdef AIX43 /* AIX43 implies AIX42 */
+#ifndef AIX42
+#define AIX42
+#endif /* AIX42 */
+#endif /* AIX43 */
+
+#ifdef AIX42 /* AIX42 implies AIX41 */
+#ifndef AIX41
+#define AIX41
+#endif /* AIX41 */
+#endif /* AIX42 */
+
+#ifdef SV68R3V6 /* System V/68 R32V6 implies SVR3 */
+#ifndef SVR3
+#define SVR3
+#endif /* SVR3 */
+#endif /* SV68R3V6 */
+
+#ifdef SV88R32 /* System V/88 R32 implies SVR3 */
+#ifndef SVR3
+#define SVR3
+#endif /* SVR3 */
+#endif /* SV88R32 */
+
+#ifdef DGUX540 /* DG UX 5.40 implies Sys V R 4 */
+#ifndef SVR4
+#define SVR4
+#endif /* SVR4 */
+#endif /* DGUX540 */
+
+#ifndef DGUX
+#ifdef DGUX540 /* DG/UX 5.40 implies DGUX */
+#define DGUX
+#else
+#ifdef DGUX430 /* So does DG/UX 4.30 */
+#define DGUX
+#endif /* DGUX430 */
+#endif /* DGUX540 */
+#endif /* DGUX */
+
+#ifdef IRIX65 /* IRIX 6.5 implies IRIX 6.4 */
+#ifndef IRIX64
+#define IRIX64
+#endif /* IRIX64 */
+#endif /* IRIX65 */
+
+#ifdef IRIX64 /* IRIX 6.4 implies IRIX 6.2 */
+#ifndef BSD44ORPOSIX
+#define BSD44ORPOSIX /* for ckutio's benefit */
+#endif /* BSD44ORPOSIX */
+#ifndef IRIX62
+#define IRIX62
+#endif /* IRIX62 */
+#endif /* IRIX64 */
+
+#ifdef IRIX62 /* IRIX 6.2 implies IRIX 6.0 */
+#ifndef IRIX60
+#define IRIX60
+#endif /* IRIX60 */
+#endif /* IRIX62 */
+
+#ifdef IRIX60 /* IRIX 6.0 implies IRIX 5.1 */
+#ifndef IRIX51
+#define IRIX51
+#endif /* IRIX51 */
+#ifndef IRIX52 /* And IRIX 5.2 (for hwfc) */
+#define IRIX52
+#endif /* IRIX52 */
+#endif /* IRIX60 */
+
+#ifndef IRIX /* IRIX 4.0 or greater implies IRIX */
+#ifdef IRIX64
+#define IRIX
+#else
+#ifdef IRIX62
+#define IRIX
+#else
+#ifdef IRIX60
+#define IRIX
+#else
+#ifdef IRIX51
+#define IRIX
+#else
+#ifdef IRIX40
+#define IRIX
+#endif /* IRIX40 */
+#endif /* IRIX51 */
+#endif /* IRIX60 */
+#endif /* IRIX62 */
+#endif /* IRIX64 */
+#endif /* IRIX */
+
+#ifdef MIPS /* MIPS System V environment */
+#ifndef SVR3 /* implies System V R3 or later */
+#define SVR3
+#endif /* SVR3 */
+#endif /* MIPS */
+
+#ifdef HPUX9 /* HP-UX 9.x */
+#ifndef SVR3
+#define SVR3
+#endif /* SVR3 */
+#ifndef HPUX
+#define HPUX
+#endif /* HPUX */
+#ifndef HPUX9PLUS
+#define HPUX9PLUS
+#endif /* HPUX9PLUS */
+#endif /* HPUX9 */
+
+#ifdef HPUX10 /* HP-UX 10.x */
+#ifndef HPUX1010 /* If anything higher is defined */
+#ifdef HPUX1020 /* define HPUX1010 too. */
+#define HPUX1010
+#endif /* HPUX1020 */
+#ifdef HPUX1030
+#define HPUX1010
+#endif /* HPUX1030 */
+#endif /* HPUX1010 */
+
+#ifdef HPUX1100 /* HP-UX 11.00 implies 10.10 */
+#ifndef HPUX1010
+#define HPUX1010
+#endif /* HPUX1010 */
+#endif /* HPUX1100 */
+
+#ifndef SVR4
+#define SVR4
+#endif /* SVR4 */
+#ifndef HPUX
+#define HPUX
+#endif /* HPUX */
+#ifndef HPUX9PLUS
+#define HPUX9PLUS
+#endif /* HPUX9PLUS */
+#endif /* HPUX10 */
+
+#ifdef QNX /* QNX Software Systems Inc */
+#ifndef POSIX /* QNX 4.0 or later is POSIX */
+#define POSIX
+#endif /* POSIX */
+#ifndef __386__ /* Comes in 16-bit and 32-bit */
+#define __16BIT__
+#define CK_QNX16
+#else
+#define __32BIT__
+#define CK_QNX32
+#endif /* __386__ */
+#endif /* QNX */
+
+/*
+ 4.4BSD is a mixture of System V R4, POSIX, and 4.3BSD.
+*/
+#ifdef BSD44 /* 4.4 BSD */
+#ifndef SVR4 /* BSD44 implies SVR4 */
+#define SVR4
+#endif /* SVR4 */
+#ifndef NOSETBUF /* NOSETBUF is safe */
+#define NOSETBUF
+#endif /* NOSETBUF */
+#ifndef DIRENT /* Uses <dirent.h> */
+#define DIRENT
+#endif /* DIRENT */
+#endif /* BSD44 */
+
+#ifdef OPENBSD /* OpenBSD might or might not */
+#ifndef __OpenBSD__ /* have this defined... */
+#define __OpenBSD__
+#endif /* __OpenBSD__ */
+#endif /* OPENBSD */
+
+#ifdef SVR3 /* SVR3 implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* SVR3 */
+
+#ifdef SVR4 /* SVR4 implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#ifndef SVR3 /* ...as well as SVR3 */
+#define SVR3
+#endif /* SVR3 */
+#endif /* SVR4 */
+
+#ifdef OXOS
+#ifndef ATTSV
+#define ATTSV /* OXOS implies ATTSV */
+#endif /* ! ATTSV */
+#define SW_ACC_ID /* access() wants privs on */
+#define kill priv_kill /* kill() wants privs on */
+#ifndef NOSETBUF
+#define NOSETBUF /* NOSETBUF is safe */
+#endif /* ! NOSETBUF */
+#endif /* OXOS */
+
+#ifdef UTSV /* UTSV implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* UTSV */
+
+#ifdef XENIX /* XENIX implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* XENIX */
+
+#ifdef AUX /* AUX implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* AUX */
+
+#ifdef ATT7300 /* ATT7300 implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* ATT7300 */
+
+#ifdef ATT6300 /* ATT6300 implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* ATT6300 */
+
+#ifdef HPUX /* HPUX implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* HPUX */
+
+#ifdef ISIII /* ISIII implies ATTSV */
+#ifndef ATTSV
+#define ATTSV
+#endif /* ATTSV */
+#endif /* ISIII */
+
+#ifdef NEXT33 /* NEXT33 implies NEXT */
+#ifndef NEXT
+#define NEXT
+#endif /* NEXT */
+#endif /* NEXT33 */
+
+#ifdef NEXT /* NEXT implies BSD4 */
+#ifndef BSD4
+#define BSD4
+#endif /* BSD4 */
+#endif /* NEXT */
+
+#ifdef BSD41 /* BSD41 implies BSD4 */
+#ifndef BSD4
+#define BSD4
+#endif /* BSD4 */
+#endif /* BSD41 */
+
+#ifdef BSD43 /* BSD43 implies BSD4 */
+#ifndef BSD4
+#define BSD4
+#endif /* BSD4 */
+#endif /* BSD43 */
+
+#ifdef BSD4 /* BSD4 implies ANYBSD */
+#ifndef ANYBSD
+#define ANYBSD
+#endif /* ANYBSD */
+#endif /* BSD4 */
+
+#ifdef BSD29 /* BSD29 implies ANYBSD */
+#ifndef ANYBSD
+#define ANYBSD
+#endif /* ANYBSD */
+#endif /* BSD29 */
+
+#ifdef ATTSV /* ATTSV implies UNIX */
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#endif /* ATTSV */
+
+#ifdef ANYBSD /* ANYBSD implies UNIX */
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#endif /* ANYBSD */
+
+#ifdef POSIX /* POSIX implies UNIX */
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#ifndef DIRENT /* and DIRENT, i.e. <dirent.h> */
+#ifndef SDIRENT
+#define DIRENT
+#endif /* SDIRENT */
+#endif /* DIRENT */
+#ifndef NOFILEH /* POSIX doesn't use <sys/file.h> */
+#define NOFILEH
+#endif /* NOFILEH */
+#endif /* POSIX */
+
+#ifdef V7
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#endif /* V7 */
+
+#ifdef COHERENT
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#ifdef COMMENT
+#ifndef NOCURSES
+#define NOCURSES
+#endif /* NOCURSES */
+#endif /* COMMENT */
+#endif /* COHERENT */
+
+#ifdef MINIX
+#ifndef UNIX
+#define UNIX
+#endif /* UNIX */
+#endif /* MINIX */
+/*
+ The symbol SVORPOSIX is defined for both AT&T and POSIX compilations
+ to make it easier to select items that System V and POSIX have in common,
+ but which BSD, V7, etc, do not have.
+*/
+#ifdef ATTSV
+#ifndef SVORPOSIX
+#define SVORPOSIX
+#endif /* SVORPOSIX */
+#endif /* ATTSV */
+
+#ifdef POSIX
+#ifndef SVORPOSIX
+#define SVORPOSIX
+#endif /* SVORPOSIX */
+#endif /* POSIX */
+
+/*
+ The symbol SVR4ORPOSIX is defined for both AT&T System V R4 and POSIX
+ compilations to make it easier to select items that System V R4 and POSIX
+ have in common, but which BSD, V7, and System V R3 and earlier, etc, do
+ not have.
+*/
+#ifdef POSIX
+#ifndef SVR4ORPOSIX
+#define SVR4ORPOSIX
+#endif /* SVR4ORPOSIX */
+#endif /* POSIX */
+#ifdef SVR4
+#ifndef SVR4ORPOSIX
+#define SVR4ORPOSIX
+#endif /* SVR4ORPOSIX */
+#endif /* SVR4 */
+
+/*
+ The symbol BSD44ORPOSIX is defined for both 4.4BSD and POSIX compilations
+ to make it easier to select items that 4.4BSD and POSIX have in common,
+ but which System V, BSD, V7, etc, do not have.
+*/
+#ifdef BSD44
+#ifndef BSD44ORPOSIX
+#define BSD44ORPOSIX
+#endif /* BSD44ORPOSIX */
+#endif /* BSD44 */
+
+#ifdef POSIX
+#ifndef BSD44ORPOSIX
+#define BSD44ORPOSIX
+#endif /* BSD44ORPOSIX */
+#endif /* POSIX */
+
+#ifdef UNIX /* For items common to OS/2 and UNIX */
+#ifndef OS2ORUNIX
+#define OS2ORUNIX
+#endif /* OS2ORUNIX */
+#endif /* UNIX */
+
+#ifdef UNIX /* For items common to VMS and UNIX */
+#define VMSORUNIX
+#else
+#ifdef VMS
+#define VMSORUNIX
+#ifndef OS2ORVMS
+#define OS2ORVMS
+#endif /* OS2ORVMS */
+#endif /* VMS */
+#endif /* UNIX */
+
+#ifndef UNIXOROSK /* UNIX or OS-9 (or OS-9000) */
+#ifdef UNIX
+#define UNIXOROSK
+#else
+#ifdef OSK
+#define UNIXOROSK
+#endif /* OSK */
+#endif /* UNIX */
+#endif /* UNIXOROSK */
+
+#ifndef OSKORUNIX
+#ifdef UNIXOROSK
+#define OSKORUNIX
+#endif /* UNIXOROSK */
+#endif /* OSKORUNIX */
+
+#ifdef OS2
+#define CK_ANSIC /* OS/2 supports ANSIC and more extensions */
+#endif /* OS2 */
+
+#ifdef OSF50 /* Newer OSF/1 versions imply older ones */
+#ifndef OSF40
+#define OSF40
+#endif /* OSF40 */
+#endif /* OSF50 */
+
+#ifdef OSF40
+#ifndef OSF32
+#define OSF32
+#endif /* OSF32 */
+#endif /* OSF40 */
+
+#ifdef OSF32
+#ifndef OSF30
+#define OSF30
+#endif /* OSF30 */
+#endif /* OSF32 */
+
+#ifdef OSF30
+#ifndef OSF20
+#define OSF20
+#endif /* OSF20 */
+#endif /* OSF30 */
+
+#ifdef OSF20
+#ifndef OSF10
+#define OSF10
+#endif /* OSF10 */
+#endif /* OSF20 */
+
+#ifdef __DECC /* For DEC Alpha VMS or OSF/1 */
+#ifndef CK_ANSIC
+#define CK_ANSIC /* Even with /stand=vaxc, need ansi */
+#endif /* CKANSIC */
+#ifndef SIG_V
+#define SIG_V /* and signal type is VOID */
+#endif /* SIG_V */
+#ifndef CK_ANSILIBS
+#define CK_ANSILIBS /* (Martin Zinser, Feb 1995) */
+#endif /* CK_ANSILIBS */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 1
+#endif /* _POSIX_C_SOURCE */
+#endif /* __DECC */
+
+#ifdef VMS
+#ifdef __ia64 /* VMS on Itanium */
+#ifndef VMSI64
+#define VMSI64
+#endif /* VMSI64 */
+#endif /* __ia64 */
+#ifndef VMS64BIT /* 64-bit VMS on Itanium or Alpha */
+#ifdef __ia64
+#define VMS64BIT
+#else
+#ifdef __ALPHA
+#define VMS64BIT
+#endif /* __ia64 */
+#endif /* __ALPHA */
+#endif /* VMS64BIT */
+#endif /* VMS */
+
+#ifdef apollo /* May be ANSI-C, check further */
+#ifdef __STDCPP__
+#define CK_ANSIC /* Yes, this is real ANSI-C */
+#define SIG_V
+#else
+#define NOANSI /* Nope, not ANSI */
+#undef __STDC__ /* Even though it say it is! */
+#define SIG_I
+#endif /* __STDCPP__ */
+#endif /* apollo */
+
+#ifdef POSIX /* -DPOSIX on cc command line */
+#ifndef _POSIX_SOURCE /* Implies _POSIX_SOURCE */
+#define _POSIX_SOURCE
+#endif /* _POSIX_SOURCE */
+#endif /* POSIX */
+
+/*
+ ANSI C? That is, do we have function prototypes, new-style
+ function declarations, and parameter type checking and coercion?
+*/
+#ifdef MAC /* MPW C is ANSI */
+#ifndef NOANSI
+#ifndef CK_ANSIC
+#define CK_ANSIC
+#endif /* CK_ANSIC */
+#endif /* NOANSI */
+#endif /* MAC */
+
+#ifdef STRATUS /* Stratus VOS */
+#ifndef CK_ANSIC
+#define CK_ANSIC
+#endif /* CK_ANSIC */
+#ifndef NOSTAT
+#define NOSTAT
+#endif /* NOSTAT */
+#endif /* STRATUS */
+
+#ifndef NOANSI
+#ifdef __STDC__ /* __STDC__ means ANSI C */
+#ifndef CK_ANSIC
+#define CK_ANSIC
+#endif /* CK_ANSIC */
+#endif /* __STDC__ */
+#endif /* NOANSI */
+/*
+ _PROTOTYP() is used for forward declarations of functions so we can have
+ parameter and return value type checking if the compiler offers it.
+ __STDC__ should be defined by the compiler only if function prototypes are
+ allowed. Otherwise, we get old-style forward declarations. Our own private
+ CK_ANSIC symbol tells whether we use ANSI C prototypes. To force use of
+ ANSI prototypes, include -DCK_ANSIC on the cc command line. To disable the
+ use of ANSI prototypes, include -DNOANSI.
+*/
+#ifdef CK_ANSIC
+#define _PROTOTYP( func, parms ) func parms
+#else /* Not ANSI C */
+#define _PROTOTYP( func, parms ) func()
+#endif /* CK_ANSIC */
+
+#ifndef OS2
+#ifdef NOLOGIN /* NOLOGIN implies NOIKSD */
+#ifndef NOIKSD
+#define NOIKSD
+#endif /* NOIKSD */
+#endif /* NOLOGIN */
+#endif /* OS2 */
+
+#ifdef NOIKSD /* Internet Kermit Service Daemon */
+#ifndef OS2
+#ifndef NOPRINTFSUBST
+#define NOPRINTFSUBST
+#endif /* NOPRINTFSUBST */
+#endif /* OS2 */
+#ifndef NOLOGIN
+#define NOLOGIN
+#endif /* NOLOGIN */
+#ifndef NOSYSLOG
+#define NOSYSLOG
+#endif /* NOSYSLOG */
+#ifndef NOWTMP
+#define NOWTMP
+#endif /* NOWTMP */
+#else
+#ifndef IKSD
+#ifdef OS2ORUNIX /* Platforms where IKSD is supported */
+#define IKSD
+#endif /* OS2ORUNIX */
+#endif /* IKSD */
+#endif /* NOIKSD */
+
+#ifdef IKSD /* IKSD options... */
+#ifndef IKSDCONF /* IKSD configuration file */
+#ifdef UNIX
+#define IKSDCONF "/etc/iksd.conf"
+#else
+#ifdef OS2
+#define IKSDCONF "iksd.ksc"
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* IKSDCONF */
+#ifndef NOIKSDB
+#ifndef IKSDB /* IKSD database */
+#ifdef UNIX
+#define IKSDB
+#define IK_LCKTRIES 16 /* How many times to try to get lock */
+#define IK_LCKSLEEP 1 /* How long to sleep between tries */
+#define IK_LOCKFILE "iksd.lck" /* Database lockfilename */
+#define IK_DBASEDIR "/var/log/" /* Database directory */
+#define IK_DBASEFIL "iksd.db" /* Database filename */
+#else /* UNIX */
+#ifdef OS2
+#define IKSDB
+#ifndef NOFTRUNCATE /* ftruncate() not available */
+#define NOFTRUNCATE
+#endif /* NOFTRUNCATE */
+#define IK_LCKTRIES 16 /* How many times to try to get lock */
+#define IK_LCKSLEEP 1 /* How long to sleep between tries */
+#define IK_LOCKFILE "iksd.lck" /* DB lockfilename (in systemroot) */
+#define IK_DBASEFIL "iksd.db" /* Database filename */
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* IKSDB */
+#endif /* NOIKSDB */
+#endif /* IKSD */
+/*
+ Substitutes for printf() and friends used in IKS to compensate for
+ lack of a terminal driver, mainly to supply CR after LF.
+*/
+#ifndef NOPRINTFSUBST
+#ifdef MAC
+/*
+ * The MAC doesn't use standard stdio routines.
+ */
+#undef getchar
+#define getchar() mac_getchar()
+#undef putchar
+#define putchar(c) mac_putchar(c)
+#define printf mac_printf
+#define perror mac_perror
+#define puts mac_puts
+extern int mac_putchar (int c);
+extern int mac_puts (const char *string);
+extern int mac_printf(const char *, ...);
+extern int mac_getchar (void);
+#endif /* MAC */
+
+#ifdef OS2
+#define printf Vscrnprintf
+#define fprintf Vscrnfprintf
+extern int Vscrnprintf(const char *, ...);
+extern int Vscrnprintw(const char *, ...);
+extern int Vscrnfprintf(FILE *, const char *, ...);
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) Vscrnprintf("%c",x)
+#define perror(x) Vscrnperror(x)
+#endif /* OS2 */
+
+#ifndef CKWART_C
+#ifdef UNIX
+#ifndef pdp11
+#ifndef CKXPRINTF
+#define CKXPRINTF
+#endif /* CKXPRINTF */
+#endif /* pdp11 */
+#endif /* UNIX */
+#endif /* CKWART_C */
+#endif /* NOPRINTFSUBST */
+
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#define fprintf ckxfprintf
+#ifdef CK_ANSIC
+_PROTOTYP(int ckxprintf,(const char *, ...));
+#ifdef NEXT
+_PROTOTYP(void ckxperror,(const char *));
+#else
+#ifdef CK_SCOV5
+_PROTOTYP(void ckxperror,(const char *));
+#else
+_PROTOTYP(int ckxperror,(const char *));
+#endif /* CK_SCOV5 */
+#endif /* NEXT */
+_PROTOTYP(int ckxfprintf,(FILE *, const char *, ...));
+#endif /* CK_ANSIC */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) ckxprintf("%c",x)
+#ifdef putc
+#undef putc
+#endif /* putc */
+#define putc(a,b) ckxfprintf(b,"%c",a)
+#define perror(x) ckxperror(x)
+#endif /* CKXPRINTF */
+
+/*
+ Altos-specific items: 486, 586, 986 models...
+*/
+#ifdef A986
+#define M_VOID
+#define void int
+#define CHAR char
+#define SIG_I
+#endif /* A986 */
+
+/* Signal handling */
+
+#ifdef QNX
+#ifndef CK_POSIX_SIG
+#define CK_POSIX_SIG
+#endif /* CK_POSIX_SIG */
+#endif /* QNX */
+
+/*
+ void type, normally available only in ANSI compilers.
+ The HP-UX exception (for its "bundled" non-ANSI C compiler)
+ is known to be valid back to HP-UX 6.5.
+ Adjustments might be needed for earlier HP-UX versions.
+*/
+#ifndef VOID /* Used throughout all C-Kermit */
+#ifdef CK_ANSIC /* modules... */
+#define VOID void
+#else
+#ifdef HPUX
+#define VOID void
+#else
+#define VOID int
+#endif /* HPUX */
+#endif /* CK_ANSIC */
+#endif /* VOID */
+/*
+ Exactly the same as VOID but for use in contexts where the VOID symbol
+ conflicts some header-file definition. This is needed for the section
+ of ckuusx.c that provides C-Kermit's curses interface, roughly the
+ second half of ckuusx.c.
+*/
+#ifndef CKVOID
+#ifdef CK_ANSIC
+#define CKVOID void
+#else
+#ifdef HPUX
+#define CKVOID void
+#else
+#define CKVOID int
+#endif /* HPUX */
+#endif /* CK_ANSIC */
+#endif /* CKVOID */
+
+/* Const type */
+
+#ifndef CONST
+#ifdef OSK
+#ifdef _UCC
+#define CONST const
+#else
+#define CONST
+#endif /* _UCC */
+#else /* !OSK */
+#ifdef CK_SCO32V4
+#define CONST
+#else
+#ifdef CK_ANSIC
+#define CONST const
+#else
+#define CONST
+#endif /* CK_ANSIC */
+#endif /* CK_SCO32V4 */
+#endif /* OSK */
+#endif /* CONST */
+
+/* Signal type */
+
+#ifndef SIG_V /* signal() type, if not def'd yet */
+#ifndef SIG_I
+#ifdef OS2
+#define SIG_V
+#else
+#ifdef POSIX
+#define SIG_V
+#else
+#ifdef SVR3 /* System V R3 and later */
+#define SIG_V
+#else
+#ifdef SUNOS4 /* SUNOS V 4.0 and later */
+#ifndef sun386
+#define SIG_V
+#else
+#define SIG_I
+#endif /* sun386 */
+#else
+#ifdef NEXT /* NeXT */
+#define SIG_V
+#else
+#ifdef AIX370
+#include <signal.h>
+#define SIG_V
+#define SIGTYP __SIGVOID /* AIX370 */
+#else
+#ifdef STRATUS /* Stratus VOS */
+#define SIG_V
+#else
+#ifdef MAC
+#define SIGTYP long
+#define SIG_I
+#ifndef MPW33
+#define SIG_IGN 0
+#endif /* MPW33 */
+#define SIGALRM 1
+#ifndef MPW33
+#define SIGINT 2
+#endif /* MPW33 */
+#else /* Everything else */
+#define SIG_I
+#endif /* MAC */
+#endif /* STRATUS */
+#endif /* AIX370 */
+#endif /* NEXT */
+#endif /* SUNOS4 */
+#endif /* SVR3 */
+#endif /* POSIX */
+#endif /* OS2 */
+#endif /* SIG_I */
+#endif /* SIG_V */
+
+#ifdef SIG_I
+#define SIGRETURN return(0)
+#ifndef SIGTYP
+#define SIGTYP int
+#endif /* SIGTYP */
+#endif /* SIG_I */
+
+#ifdef SIG_V
+#define SIGRETURN return
+#ifndef SIGTYP
+#define SIGTYP void
+#endif /* SIGTYP */
+#endif /* SIG_V */
+
+#ifdef NT
+#ifndef SIGTYP
+#define SIGTYP void
+#endif /* SIGTYP */
+#endif /* NT */
+
+#ifndef SIGTYP
+#define SIGTYP int
+#endif /* SIGTYP */
+
+#ifndef SIGRETURN
+#define SIGRETURN return(0)
+#endif /* SIGRETURN */
+
+#ifdef CKNTSIG
+/* This does not work, so don't use it. */
+#define signal ckntsignal
+SIGTYP (*ckntsignal(int type, SIGTYP (*)(int)))(int);
+#endif /* CKNTSIG */
+
+/* We want all characters to be unsigned if the compiler supports it */
+
+#ifdef KUI
+#ifdef CHAR
+#undef CHAR
+#endif /* CHAR */
+#define CHAR unsigned char
+#else
+#ifdef PROVX1
+typedef char CHAR;
+/* typedef long LONG; */
+typedef int void;
+#else
+#ifdef MINIX
+typedef unsigned char CHAR;
+#else
+#ifdef V7
+typedef char CHAR;
+#else
+#ifdef C70
+typedef char CHAR;
+/* typedef long LONG; */
+#else
+#ifdef BSD29
+typedef char CHAR;
+/* typedef long LONG; */
+#else
+#ifdef datageneral
+#define CHAR unsigned char /* 3.22 compiler */
+#else
+#ifdef HPUX
+#define CHAR unsigned char
+#else
+#ifdef OS2
+#ifdef NT
+#define CHAR unsigned char
+#else /* NT */
+#ifdef CHAR
+#undef CHAR
+#endif /* CHAR */
+typedef unsigned char CHAR;
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+typedef unsigned char CHAR;
+#else
+#ifdef CHAR
+#undef CHAR
+#endif /* CHAR */
+typedef unsigned char CHAR;
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* HPUX */
+#endif /* datageneral */
+#endif /* BSD29 */
+#endif /* C70 */
+#endif /* V7 */
+#endif /* MINIX */
+#endif /* PROVX1 */
+#endif /* KUI */
+
+union ck_short { /* Mainly for Unicode */
+ USHORT x_short;
+ CHAR x_char[2];
+};
+
+#ifdef MAC /* Macintosh file routines */
+#ifndef CKWART_C /* But not in "wart"... */
+#ifdef feof
+#undef feof
+#endif /* feof */
+#define feof mac_feof
+#define rewind mac_rewind
+#define fgets mac_fgets
+#define fopen mac_fopen
+#define fclose mac_fclose
+int mac_feof();
+void mac_rewind();
+char *mac_fgets();
+FILE *mac_fopen();
+int mac_fclose();
+#endif /* CKCPRO_W */
+#endif /* MAC */
+/*
+ Systems whose mainline modules have access to the communication-line
+ file descriptor, ttyfd.
+*/
+#ifndef CK_TTYFD
+#ifdef UNIX
+#define CK_TTYFD
+#else
+#ifdef OS2
+#define CK_TTYFD
+#else
+#ifdef VMS
+#define CK_TTYFD
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* CK_TTYFD */
+
+/* Systems where we can get our own process ID */
+
+#ifndef CK_PID
+#ifdef UNIX
+#define CK_PID
+#endif /* UNIX */
+#ifdef OS2
+#define CK_PID
+#endif /* OS2 */
+#ifdef VMS
+#define CK_PID
+#endif /* VMS */
+#endif /* CK_PID */
+
+/* Systems that support the Microsoft Telephony API (TAPI) */
+
+#ifndef NODIAL
+#ifndef CK_TAPI
+#ifdef NT
+#define CK_TAPI
+#endif /* NT */
+#endif /* CK_TAPI */
+#endif /* NODIAL */
+
+#ifndef NONZXPAND
+#ifndef NZXPAND
+#ifdef OS2ORUNIX
+#define NZXPAND
+#else
+#ifdef VMS
+#define NZXPAND
+#else
+#ifdef datageneral
+#define NZXPAND
+#else
+#ifdef OSK
+#define NZXPAND
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#endif /* NZXPAND */
+#else
+#ifdef NZXPAND
+#undef NZXPAND
+#endif /* NZXPAND */
+#endif /* NONZXPAND */
+
+/* nzxpand() option flags */
+
+#define ZX_FILONLY 1 /* Match only regular files */
+#define ZX_DIRONLY 2 /* Match only directories */
+#define ZX_RECURSE 4 /* Descend through directory tree */
+#define ZX_MATCHDOT 8 /* Match "dot files" */
+#define ZX_NOBACKUP 16 /* Don't match "backup files" */
+#define ZX_NOLINKS 32 /* Don't follow symlinks */
+
+#ifndef NZXPAND
+#define nzxpand(a,b) zxpand(a)
+#endif /* NZXPAND */
+
+#ifndef NOZXREWIND
+#ifndef ZXREWIND /* Platforms that have zxrewind() */
+#ifdef OS2ORUNIX
+#define ZXREWIND
+#else
+#ifdef VMS
+#define ZXREWIND
+#else
+#ifdef datageneral
+#define ZXREWIND
+#else
+#ifdef OSK
+#define ZXREWIND
+#else
+#ifdef STRATUS
+#define ZXREWIND
+#endif /* STRATUS */
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#endif /* ZXREWIND */
+#else
+#ifdef ZXREWIND
+#undef ZXREWIND
+#endif /* ZXREWIND */
+#endif /* NOZXREWIND */
+
+/* Temporary-directory-for-RECEIVE feature ... */
+/* This says whether we have the isdir() function defined. */
+
+#ifdef UNIX /* UNIX has it */
+#ifndef CK_TMPDIR
+#ifndef pdp11
+#define CK_TMPDIR
+#define TMPDIRLEN 256
+#endif /* pdp11 */
+#endif /* CK_TMPDIR */
+#endif /* UNIX */
+
+#ifdef VMS /* VMS too */
+#ifndef CK_TMPDIR
+#define CK_TMPDIR
+#define TMPDIRLEN 256
+#endif /* CK_TMPDIR */
+#endif /* VMS */
+
+#ifdef OS2 /* OS two too */
+#ifndef CK_TMPDIR
+#define CK_TMPDIR
+#define TMPDIRLEN 129
+#endif /* CK_TMPDIR */
+#endif /* OS2 */
+
+#ifdef STRATUS /* Stratus VOS too. */
+#ifndef CK_TMPDIR
+#define CK_TMPDIR
+#define TMPDIRLEN 256
+#endif /* CK_TMPDIR */
+#endif /* STRATUS */
+
+#ifdef OSK /* OS-9 too */
+#ifndef CK_TMPDIR
+#define CK_TMPDIR
+#define TMPDIRLEN 256
+#endif /* CK_TMPDIR */
+#endif /* OSK */
+
+#ifdef datageneral /* AOS/VS too */
+#ifndef CK_TMPDIR
+#define CK_TMPDIR
+#define TMPDIRLEN 256
+#endif /* CK_TMPDIR */
+#endif /* datageneral */
+
+#ifdef CK_TMPDIR /* Needs command parser */
+#ifdef NOICP
+#undef CK_TMPDIR
+#endif /* NOICP */
+#endif /* CK_TMPDIR */
+
+/* Whether to include <sys/time.h> */
+
+#ifndef NOTIMEH /* <time.h> */
+#ifndef TIMEH
+#define TIMEH
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH /* <sys/time.h> */
+#ifndef SYSTIMEH
+#ifdef UNIX /* UNIX */
+#ifdef SVORPOSIX /* System V or POSIX... */
+#ifdef M_UNIX
+#define SYSTIMEH
+#else
+#ifdef SCO_32V4
+#define SYSTIMEH
+#else
+#ifdef OXOS
+#define SYSTIMEH
+#else
+#ifdef BSD44
+#define SYSTIMEH
+#else
+#ifdef __linux__
+#define SYSTIMEH
+#else
+#ifdef AIXRS
+#ifndef AIX41
+#define SYSTIMEH
+#endif /* AIX41 */
+#else
+#ifdef IRIX60
+#define SYSTIMEH
+#else
+#ifdef I386IX
+#define SYSTIMEH
+#else
+#ifdef SV68R3V6
+#define SYSTIMEH
+#endif /* SV68R3V6 */
+#endif /* I386IX */
+#endif /* IRIX60 */
+#endif /* AIXRS */
+#endif /* __linux__ */
+#endif /* BSD44 */
+#endif /* OXOS */
+#endif /* SCO_32V4 */
+#endif /* M_UNIX */
+
+#else /* Not SVORPOSIX */
+
+#ifndef BELLV10 /* All but these... */
+#ifndef PROVX1
+#ifndef V7
+#ifndef BSD41
+#ifndef COHERENT
+#define SYSTIMEH
+#endif /* COHERENT */
+#endif /* BSD41 */
+#endif /* V7 */
+#endif /* PROVX1 */
+#endif /* BELLV10 */
+#endif /* SVORPOSIX */
+#endif /* UNIX */
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+
+#ifndef NOSYSTIMEBH /* <sys/timeb.h> */
+#ifndef SYSTIMEBH
+#ifdef OSF
+#define SYSTIMEBH
+#else
+#ifdef COHERENT
+#define SYSTIMEBH
+#else
+#ifdef BSD41
+#define SYSTIMEBH
+#else
+#ifdef BSD29
+#define SYSTIMEBH
+#else
+#ifdef TOWER1
+#define SYSTIMEBH
+#else
+#ifdef FT21
+#define SYSTIMEBH
+#else
+#ifdef BELLV10
+#define SYSTIMEBH
+#endif /* BELLV10 */
+#endif /* FT21 */
+#endif /* TOWER1 */
+#endif /* BSD29 */
+#endif /* BSD41 */
+#endif /* COHERENT */
+#endif /* OSF */
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+
+/*
+ Debug and transaction logging is included automatically unless you define
+ NODEBUG or NOTLOG. Do this if you want to save the space and overhead.
+ (Note, in version 4F these definitions changed from "{}" to the null string
+ to avoid problems with semicolons after braces, as in: "if (x) tlog(this);
+ else tlog(that);"
+*/
+#ifndef NODEBUG
+#ifndef DEBUG
+#define DEBUG
+#endif /* DEBUG */
+#else
+#ifdef DEBUG
+#undef DEBUG
+#endif /* DEBUG */
+#endif /* NODEBUG */
+
+#ifdef NOTLOG
+#ifdef TLOG
+#undef TLOG
+#endif /* TLOG */
+#else /* NOTLOG */
+#ifndef TLOG
+#define TLOG
+#endif /* TLOG */
+#endif /* NOTLOG */
+
+/* debug() macro style selection. */
+
+#ifdef VMS
+#ifndef IFDEBUG
+#define IFDEBUG
+#endif /* IFDEBUG */
+#endif /* VMS */
+
+#ifdef MAC
+#ifndef IFDEBUG
+#define IFDEBUG
+#endif /* IFDEBUG */
+#endif /* MAC */
+
+#ifdef OS2
+#ifndef IFDEBUG
+#define IFDEBUG
+#endif /* IFDEBUG */
+#endif /* OS2 */
+
+#ifdef OXOS /* tst is faster than jsr */
+#ifndef IFDEBUG
+#define IFDEBUG
+#endif /* IFDEBUG */
+#endif /* OXOS */
+
+#ifndef CKCMAI
+extern int deblog;
+extern int debok;
+extern int debxlen;
+extern int matchdot;
+extern int tt_bell;
+#endif /* CKCMAI */
+
+#ifdef OS2
+_PROTOTYP( void bleep, (short) );
+#else /* OS2 */
+#define bleep(x) if(tt_bell)putchar('\07')
+#endif /* OS2 */
+
+#ifndef BEOSORBEBOX
+#ifdef BEBOX /* This was used only for DR7 */
+#define BEOSORBEBOX
+#else
+#ifdef BEOS /* This is used for BeOS 4.x */
+#define BEOSORBEBOX
+#endif /* BEOS */
+#endif /* BEBOX */
+#endif /* BEOSORBEBOX */
+
+#ifdef NOICP
+#ifdef TLOG
+#undef TLOG
+#endif /* TLOG */
+#endif /* NOICP */
+
+/* Formats for debug() and tlog() */
+
+#define F000 0
+#define F001 1
+#define F010 2
+#define F011 3
+#define F100 4
+#define F101 5
+#define F110 6
+#define F111 7
+
+#ifdef __linux__
+#ifndef LINUX
+#define LINUX
+#endif /* LINUX */
+#endif /* __linux__ */
+
+/* Platforms where small size is needed */
+
+#ifdef pdp11
+#define CK_SMALL
+#endif /* pdp11 */
+
+/* Can we use realpath()? */
+
+#ifndef NOREALPATH
+#ifdef pdp11
+#define NOREALPATH
+#endif /* pdp11 */
+#endif /* NOREALPATH */
+
+#ifndef NOREALPATH
+#ifdef UNIX
+#ifdef HPUX5
+#define NOREALPATH
+#else
+#ifdef HPUX6
+#define NOREALPATH
+#else
+#ifdef HPUX7
+#define NOREALPATH
+#else
+#ifdef HPUX8
+#define NOREALPATH
+#else
+#ifdef SV68R3V6
+#define NOREALPATH
+#else
+#ifdef XENIX
+#define NOREALPATH
+#else
+#ifdef CK_SCO32V4
+#define NOREALPATH
+#else
+#ifdef CK_SCOV5
+#define NOREALPATH
+#else
+#ifdef OSF32
+#define NOREALPATH
+#else
+#ifdef OSF30
+#define NOREALPATH
+#else
+#ifdef ultrix
+#define NOREALPATH
+#else
+#ifdef COHERENT
+#define NOREALPATH
+#endif /* COHERENT */
+#endif /* ultrix */
+#endif /* OSF30 */
+#endif /* OSF32 */
+#endif /* CK_SCOV5 */
+#endif /* CK_SCO32V4 */
+#endif /* XENIX */
+#endif /* SV68R3V6 */
+#endif /* HPUX8 */
+#endif /* HPUX7 */
+#endif /* HPUX6 */
+#endif /* HPUX5 */
+#endif /* NOREALPATH */
+
+#ifndef NOREALPATH
+#ifndef CKREALPATH
+#define CKREALPATH
+#endif /* NOREALPATH */
+#endif /* CKREALPATH */
+#endif /* UNIX */
+
+#ifdef CKREALPATH
+#ifdef OS2ORUNIX
+#ifndef CKROOT
+#define CKROOT
+#endif /* CKROOT */
+#endif /* OS2ORUNIX */
+#endif /* CKREALPATH */
+
+/* CKSYMLINK should be set only if we can use readlink() */
+
+#ifdef UNIX
+#ifndef NOSYMLINK
+#ifndef CKSYMLINK
+#define CKSYMLINK
+#endif /* NOSYMLINK */
+#endif /* CKSYMLINK */
+#endif /* UNIX */
+
+/* Platforms where we can use lstat() instead of stat() (for symlinks) */
+/* This should be set only if both lstat() and readlink() are available */
+
+#ifndef NOLSTAT
+#ifndef NOSYMLINK
+#ifndef USE_LSTAT
+#ifdef UNIX
+#ifdef CKSYMLINK
+#ifdef SVR4 /* SVR4 has lstat() */
+#define USE_LSTAT
+#else
+#ifdef BSD42 /* 4.2BSD and 4.3BSD have it */
+#define USE_LSTAT /* This should include old HPUXs */
+#else
+#ifdef BSD44 /* 4.4BSD has it */
+#define USE_LSTAT
+#else
+#ifdef LINUX /* LINUX has it */
+#define USE_LSTAT
+#else
+#ifdef SUNOS4 /* SunOS has it */
+#define USE_LSTAT
+#endif /* SUNOS4 */
+#endif /* LINUX */
+#endif /* BSD44 */
+#endif /* BSD42 */
+#endif /* SVR4 */
+#endif /* CKSYMLINK */
+#endif /* UNIX */
+#endif /* USE_LSTAT */
+#endif /* NOSYMLINK */
+#endif /* NOLSTAT */
+
+#ifdef NOLSTAT
+#ifdef USE_LSTAT
+#undef USE_LSTAT
+#endif /* USE_LSTAT */
+#endif /* NOLSTAT */
+
+#ifndef NOTTYLOCK /* UNIX systems that have ttylock() */
+#ifndef USETTYLOCK
+#ifdef AIXRS /* AIX 3.1 and later */
+#define USETTYLOCK
+#else
+#ifdef USE_UU_LOCK /* FreeBSD or other with uu_lock() */
+#define USETTYLOCK
+#else
+/*
+ Prior to 8.0.299 Alpha.08 this was HAVE_BAUDBOY which was added for
+ Red Hat 7.2 in May 2003 but which is no longer supported in Debian and
+ OpenSuse (at least).
+*/
+#ifdef HAVE_LOCKDEV
+#define USETTYLOCK
+#endif /* HAVE_LOCKDEV */
+#endif /* USE_UU_LOCK */
+#endif /* AIXRS */
+#endif /* USETTYLOCK */
+#endif /* NOTTYLOCK */
+
+#ifndef NO_OPENPTY /* Can use openpty() */
+#ifndef HAVE_OPENPTY
+#ifdef __linux__
+#define HAVE_OPENPTY
+#else
+#ifdef __FreeBSD__
+#define HAVE_OPENPTY
+#else
+#ifdef __OpenBSD__
+#define HAVE_OPENPTY
+#else
+#ifdef __NetBSD__
+#define HAVE_OPENPTY
+#else
+#ifdef MACOSX10
+#define HAVE_OPENPTY
+#endif /* MACOSX10 */
+#endif /* __NetBSD__ */
+#endif /* __OpenBSD__ */
+#endif /* __FreeBSD__ */
+#endif /* __linux__ */
+#endif /* HAVE_OPENPTY */
+#endif /* NO_OPENPTY */
+
+/* Kermit feature selection */
+
+#ifndef NOSPL
+#ifndef NOCHANNELIO /* Channel-based file i/o package */
+#ifndef CKCHANNELIO
+#ifdef UNIX
+#define CKCHANNELIO
+#else
+#ifdef OS2
+#define CKCHANNELIO
+#else
+#ifdef VMS
+#define CKCHANNELIO
+#else
+#ifdef STRATUS
+#define CKCHANNELIO
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* CKCHANNELIO */
+#endif /* NOCHANNELIO */
+#endif /* NOSPL */
+
+#ifndef NOCKEXEC /* EXEC command */
+#ifndef NOPUSH
+#ifndef CKEXEC
+#ifdef UNIX /* UNIX can do it */
+#define CKEXEC
+#endif /* UNIX */
+#endif /* CKEXEC */
+#endif /* NOPUSH */
+#endif /* NOCKEXEC */
+
+#ifndef NOFAST /* Fast Kermit protocol by default */
+#ifndef CK_FAST
+#ifdef UNIX
+#define CK_FAST
+#else
+#ifdef VMS
+#define CK_FAST
+#else
+#ifdef OS2
+#define CK_FAST
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* CK_FAST */
+#endif /* NOFAST */
+
+#ifdef UNIX /* Transparent print */
+#ifndef NOXPRINT
+#ifndef XPRINT
+#define XPRINT
+#endif /* XPRINT */
+#endif /* NOXPRINT */
+#endif /* UNIX */
+
+#ifndef NOHWPARITY /* Hardware parity */
+#ifndef HWPARITY
+#ifdef SVORPOSIX /* System V or POSIX can have it */
+#define HWPARITY
+#else
+#ifdef SUNOS41 /* SunOS 4.1 can have it */
+#define HWPARITY
+#else
+#ifdef OS2 /* K95 can have it */
+#define HWPARITY
+#endif /* OS2 */
+#endif /* SUNOS41 */
+#endif /* SVORPOSIX */
+#endif /* HWPARITY */
+#endif /* NOHWPARITY */
+
+#ifndef NOSTOPBITS /* Stop-bit selection */
+#ifndef STOPBITS
+#ifdef OS2ORUNIX
+/* In Unix really this should only be if CSTOPB is defined. */
+/* But we don't know that yet. */
+#define STOPBITS
+#else
+#ifdef TN_COMPORT
+#define STOPBITS
+#endif /* TN_COMPORT */
+#endif /* OS2ORUNIX */
+#endif /* STOPBITS */
+#endif /* NOSTOPBITS */
+
+#ifdef UNIX
+#ifndef NETCMD /* Can SET NETWORK TYPE COMMAND */
+#define NETCMD
+#endif /* NETCMD */
+#endif /* UNIX */
+
+/* Pty support, nonportable, available on a case-by-case basis */
+
+#ifndef NOPTY
+#ifdef NEXT /* NeXTSTEP (tested on 3.1)*/
+#define NETPTY
+#else
+#ifdef CK_SCOV5 /* SCO OSR5 (tested on 5.0.5)*/
+#define NETPTY
+#else
+#ifdef QNX /* QNX (tested on 4.25) */
+#define NETPTY
+#else
+#ifdef SINIX /* Sinix (tested on 5.42) */
+#define NETPTY
+#else
+#ifdef DGUX540 /* DG/UX 5.4++ (tested on 5.4R4.11) */
+#define NETPTY
+#else
+#ifdef OSF32 /* Digital Unix 3.2 */
+#define NETPTY
+#else
+#ifdef OSF40 /* Digital Unix 4.0 / Tru64 */
+#define NETPTY
+#else
+#ifdef IRIX60 /* IRIX 6.0 (not earlier) */
+#define NETPTY
+#else
+#ifdef HPUX10 /* HPUX 10.00 or later */
+#define NETPTY
+#ifndef HAVE_PTYTRAP
+#define HAVE_PTYTRAP
+#endif /* HAVE_PTYTRAP */
+#else
+#ifdef HPUX9 /* HPUX 9.00 (not earlier) */
+#define NETPTY
+#ifndef HAVE_PTYTRAP
+#define HAVE_PTYTRAP
+#endif /* HAVE_PTYTRAP */
+#else
+#ifdef BSD44 /* BSD44, {Net,Free,Open}BSD */
+#define NETPTY
+#else
+#ifdef BSDI /* BSDI/OS (tested in 4) */
+#define NETPTY
+#else
+#ifdef SOLARIS /* Solaris (tested in 2.5) */
+#define NETPTY
+#else
+#ifdef UW7 /* Unixware 7 */
+#define NETPTY
+#else
+#ifdef SUNOS41 /* SunOS (tested in 4.1.3) */
+#define NETPTY
+#else
+#ifdef AIX41 /* AIX 4.1 and later */
+#define NETPTY
+#else
+#ifdef LINUX /* Linux */
+#define NETPTY
+#endif /* LINUX */
+#endif /* AIX41 */
+#endif /* SUNOS41 */
+#endif /* UW7 */
+#endif /* SOLARIS */
+#endif /* BSDI */
+#endif /* BSD44 */
+#endif /* HPUX9 */
+#endif /* HPUX10 */
+#endif /* IRIX60 */
+#endif /* OSF40 */
+#endif /* OSF32 */
+#endif /* DGUX540 */
+#endif /* SINIX */
+#endif /* QNX */
+#endif /* CK_SCOV5 */
+#endif /* NEXT */
+
+#else /* NOPTY */
+
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#endif /* NOPTY */
+
+#ifdef NETPTY /* NETCMD required for NETPTY */
+#ifndef NETCMD
+#define NETCMD
+#endif /* NETCMD */
+#endif /* NETPTY */
+
+#ifndef CK_UTSNAME /* Can we call uname()? */
+#ifdef VMS
+#define CK_UTSNAME
+#else
+#ifdef OS2
+#define CK_UTSNAME
+#else
+#ifdef POSIX /* It's in POSIX.1 */
+#define CK_UTSNAME
+#else
+#ifdef SUNOS41 /* It's in SunOS 4.1 */
+#define CK_UTSNAME
+#else
+#ifdef AIXRS /* It's in AIX */
+#define CK_UTSNAME
+#else
+#ifdef SVR4 /* It's in SVR4 (but not SVR3) */
+#define CK_UTSNAME
+#else
+#ifdef HPUX /* It's in HP-UX 5.00 and later */
+#define CK_UTSNAME
+#else
+#ifdef OSF /* It's in OSF/1 / Digital UNIX */
+#define CK_UTSNAME
+#else
+#ifdef CK_SCOV5
+#define CK_UTSNAME
+#endif /* CK_SCOV5 */
+#endif /* OSF */
+#endif /* HPUX */
+#endif /* SVR4 */
+#endif /* AIXRS */
+#endif /* SUNOS41 */
+#endif /* POSIX */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* CK_UTSNAME */
+
+/* This section for anything that might use floating-point */
+
+/* If the following causes trouble use -DFLOAT=float on the command line */
+
+#ifdef NOSPL
+#ifdef FNFLOAT
+#undef FNFLOAT
+#endif /* FNFLOAT */
+#ifdef CKFLOAT
+#undef CKFLOAT
+#endif /* CKFLOAT */
+#endif /* NOSPL */
+
+#ifndef NOFLOAT
+
+#ifndef CKFLOAT
+#ifdef __alpha
+/* Don't use double on 64-bit platforms -- bad things happen */
+#define CKFLOAT float
+#define CKFLOAT_S "float"
+#else
+#define CKFLOAT double
+#define CKFLOAT_S "double"
+#endif /* __alpha */
+#endif /* CKFLOAT */
+
+#ifndef NOGFTIMER /* Floating-point timers */
+#ifndef GFTIMER
+#ifdef UNIX /* For UNIX */
+#define GFTIMER
+#endif /* UNIX */
+#ifdef VMS /* VMS */
+#ifndef OLD_VMS /* 5.0 and later */
+#define GFTIMER
+#endif /* OLD_VMS */
+#endif /* VMS */
+#ifdef OS2 /* And K95 */
+#define GFTIMER
+#endif /* OS2 */
+#ifdef STRATUS /* And Stratus VOS */
+#define GFTIMER
+#endif /* STRATUS */
+#endif /* GFTIMER */
+#endif /* NOGFTIMER */
+
+#ifndef NOSPL
+#ifndef FNFLOAT /* Floating-point math functions */
+#ifdef VMS /* defined by default in VMS */
+#define FNFLOAT
+#else
+#ifdef OS2 /* and K95 */
+#define FNFLOAT
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* FNFLOAT */
+#endif /* NOSPL */
+
+#else /* NOFLOAT is defined */
+
+#ifdef CKFLOAT
+#undef CKFLOAT
+#endif /* CKFLOAT */
+
+#ifdef GFTIMER
+#undef GFTIMER
+#endif /* GFTIMER */
+
+#ifdef FNFLOAT
+#undef FNFLOAT
+#endif /* FNFLOAT */
+
+#endif /* NOFLOAT */
+
+#ifdef GFTIMER /* Fraction of second to use when */
+#ifndef GFMINTIME /* elapsed time is <= 0 */
+#define GFMINTIME 0.005
+#endif /* GFMINTIME */
+#endif /* GFTIMER */
+
+#ifndef CKCMAI
+extern long ztmsec, ztusec; /* Fraction of sec of current time */
+#endif /* CKCMAI */
+
+#ifndef NOUNPREFIXZERO /* Allow unprefixing of NUL (0) */
+#ifndef UNPREFIXZERO /* in file-transfer packets */
+#define UNPREFIXZERO
+#endif /* UNPREFIXZERO */
+#endif /* NOUNPREFIXZERO */
+
+#ifdef CK_SMALL
+#define NOCAL /* Calibrate */
+#endif /* CK_SMALL */
+
+#ifndef NOPATTERNS /* Filetype matching patterns */
+#ifndef PATTERNS
+#ifndef VMS
+#ifndef CK_SMALL
+#define PATTERNS
+#endif /* CK_SMALL */
+#endif /* VMS */
+#endif /* PATTERNS */
+#endif /* NOPATTERNS */
+
+#ifndef NOCAL
+#ifndef CALIBRATE
+#define CALIBRATE
+#endif /* CALIBRATE */
+#else
+#ifdef CALIBRATE
+#undef CALIBRATE
+#endif /* CALIBRATE */
+#endif /* NOCAL */
+
+#ifndef NORECURSE /* Recursive directory traversal */
+#ifndef RECURSIVE
+#ifdef VMS
+#define RECURSIVE
+#else
+#ifdef OS2ORUNIX
+#ifndef CK_SMALL
+#define RECURSIVE
+#endif /* CK_SMALL */
+#else
+#ifdef STRATUS
+#define RECURSIVE
+#else
+#ifdef OSK
+#define RECURSIVE
+#endif /* OSK */
+#endif /* STRATUS */
+#endif /* OS2ORUNIX */
+#endif /* VMS */
+#endif /* RECURSIVE */
+#endif /* NORECURSE */
+
+#ifndef CK_SMALL /* Enable file-transfer tuning code */
+#ifndef CKTUNING /* in which more code is added */
+#ifndef NOTUNING /* to avoid function calls, etc */
+#define CKTUNING
+#endif /* NOTUNING */
+#endif /* CKTUNING */
+#endif /* CK_SMALL */
+
+#ifndef NOURL /* Parse URLs in SET HOST, etc */
+#define CK_URL
+#define NO_FTP_AUTH /* No auth "ftp" / "anonymous" */
+#endif /* NOURL */
+
+#ifndef NOTRIGGER
+#ifndef CK_TRIGGER /* Trigger string to exit CONNECT */
+#ifdef OS2ORUNIX /* OK for UNIX and K95 */
+#define CK_TRIGGER
+#else
+#ifdef VMS /* and VMS */
+#define CK_TRIGGER
+#else
+#ifdef datageneral /* and AOS/VS */
+#define CK_TRIGGER
+#endif /* datageneral */
+#endif /* OS2ORUNIX */
+#endif /* VMS */
+#endif /* CK_TRIGGER */
+#endif /* NOTRIGGER */
+
+#ifdef CK_TRIGGER
+#define TRIGGERS 8 /* How many triggers allowed */
+#endif /* CK_TRIGGER */
+
+#ifndef XLIMITS /* CONNECT limits */
+#ifdef OS2
+#define XLIMITS
+#endif /* OS2 */
+#endif /* XLIMITS */
+
+#ifdef NOFRILLS
+#ifndef NOBROWSER
+#define NOBROWSER
+#endif /* NOBROWSER */
+#ifndef NOFTP
+#define NOFTP
+#endif /* NOFTP */
+#endif /* NOFRILLS */
+
+#ifndef NOHTTP /* HTTP features need... */
+#ifdef NOICP /* an interactive command parser */
+#define NOHTTP
+#endif /* NOICP */
+#ifndef VMS
+#ifndef OS2ORUNIX /* K95 or UNIX (because of */
+#define NOHTTP /* time functions, time_t, etc) */
+#endif /* OS2ORUNIX */
+#endif /* VMS */
+#endif /* NOHTTP */
+
+
+#ifndef NONET
+#ifdef TCPSOCKET
+
+/* The HTTP code is not very portable, so it must be asked for with -DCKHTTP */
+
+#ifndef NOHTTP
+#ifndef CKHTTP
+#ifdef SUNOS4 /* We can use it in SunOS */
+#define CKHTTP
+#endif /* SUNOS4 */
+#ifdef SOLARIS /* And in Solaris */
+#define CKHTTP
+#endif /* SOLARIS */
+#ifdef LINUX /* And Linux */
+#define CKHTTP
+#endif /* LINUX */
+#ifdef HPUX10 /* And HP-UX 10 and above */
+#define CKHTTP
+#endif /* HPUX10 */
+#ifdef OS2 /* And in K-95 */
+#define CKHTTP
+#endif /* OS2 */
+#ifdef AIX41 /* In AIX 4.1 and higher */
+#define CKHTTP
+#endif /* AIX41 */
+#ifdef UNIXWARE /* In Unixware 2.1 and higher */
+#define CKHTTP /* and probably also in 1.x and 2.0 */
+#endif /* UNIXWARE */
+#ifdef CK_SCOV5
+#define CKHTTP
+#endif /* CK_SCOV5 */
+#ifdef OSF /* And in OSF Digital UNIX/True 64 */
+#define CKHTTP
+#endif /* OSF */
+#ifdef ultrix /* And in Ultrix Mips */
+#ifdef mips
+#define CKHTTP
+#endif /* mips */
+#endif /* ultrix */
+#ifdef __NetBSD__ /* NetBSD */
+#define CKHTTP
+#endif /* __NetBSD__ */
+#ifdef __FreeBSD__
+#define CKHTTP
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
+#define CKHTTP
+#endif /* __OpenBSD__ */
+/* Add more here... */
+#endif /* CKHTTP */
+#ifndef CKHTTP /* If CKHTTP not defined yet */
+#define NOHTTP /* then define NOHTTP */
+#endif /* CKHTTP */
+#endif /* NOHTTP */
+
+#ifdef NETCONN /* Special "network" types... */
+#ifndef NOLOCAL
+#ifdef OS2
+#ifndef NETFILE
+#define NETFILE
+#endif /* NETFILE */
+#ifndef NOPUSH
+#ifndef NETCMD
+#define NETCMD
+#endif /* NETCMD */
+#endif /* NOPUSH */
+#ifdef NT
+#ifndef NETDLL
+#define NETDLL
+#endif /* NETDLL */
+#endif /* NT */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#endif /* NETCONN */
+
+#ifndef NOFTP
+#ifndef SYSFTP
+#ifndef NEWFTP
+#ifdef OS2ORUNIX
+#define NEWFTP
+#endif /* OS2ORUNIX */
+#endif /* NEWFTP */
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+#ifndef NOFTP
+#ifdef NEWFTP
+#ifdef SYSFTP
+#undef SYSFTP
+#endif /* SYSFTP */
+#else /* NEWFTP */
+#ifndef SYSFTP
+#define SYSFTP
+#endif /* SYSFTP */
+#endif /* NEWFTP */
+#else /* NOFTP */
+#ifdef NEWFTP
+#undef NEWFTP
+#endif /* NEWFTP */
+#ifdef SYSFTP
+#undef SYSFTP
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+#ifndef NOBROWSER
+#ifdef UNIX
+#ifndef BROWSER
+#ifndef NOPUSH
+#define BROWSER
+#endif /* NOPUSH */
+#endif /* BROWSER */
+#endif /* UNIX */
+#ifdef OS2
+#ifndef BROWSER
+#ifndef NOPUSH
+#define BROWSER
+#endif /* NOPUSH */
+#endif /* BROWSER */
+#endif /* OS2 */
+#else
+#ifdef BROWSER
+#undef BROWSER
+#endif /* BROWSER */
+#endif /* NOBROWSER */
+
+#else /* TCPSOCKET */
+#ifndef NOHTTP /* HTTP requires TCPSOCKET */
+#define NOHTTP
+#endif /* NOHTTP */
+#endif /* TCPSOCKET */
+#endif /* NONET */
+
+#ifdef TCPSOCKET
+#ifndef NOCKGETFQHOST
+#ifdef __ia64__
+#define NOCKGETFQHOST
+#else /* __ia64__ */
+#ifdef SV68
+#define NOCKGETFQHOST
+#else
+#ifdef HPUXPRE65
+#define NOCKGETFQHOST
+#endif /* HPUXPRE65 */
+#endif /* SV68 */
+#endif /* __ia64 */
+#endif /* NOCKGETFQHOST */
+/*
+ Regarding System V/68 (SV68) (from Gerry Belanger, Oct 2002):
+
+ 1) The gethostbyname() appears to return the actual host IP
+ address in the hostent struct, instead of the expected pointer
+ to the address. Hence the bogus address in the bcopy/memcopy.
+ This is despite the header agreeing with our expectations.
+
+ 2) the expected argument swap between bcopy and memcopy
+ did not happen. What grief this might cause, I know not.
+*/
+#endif /* TCPSOCKET */
+
+#ifdef TCPSOCKET
+#ifdef OS2ONLY
+#ifndef NOSOCKS
+#define NOSOCKS
+#endif /* NOSOCKS */
+#endif /* OS2ONLY */
+#ifdef NOSOCKS
+#ifdef CK_SOCKS
+#undef CK_SOCKS
+#endif /* CK_SOCKS */
+#ifdef CK_SOCKS5
+#undef CK_SOCKS5
+#endif /* CK_SOCKS5 */
+#else /* NOSOCKS */
+#ifdef NT
+#ifndef CK_SOCKS
+#define CK_SOCKS
+#endif /* CK_SOCKS */
+#endif /* NT */
+#ifdef CK_SOCKS5 /* CK_SOCKS5 implies CK_SOCKS */
+#ifndef CK_SOCKS
+#define CK_SOCKS
+#endif /* CK_SOCKS */
+#endif /* CK_SOCKS5 */
+#endif /* NOSOCKS */
+#endif /* TCPSOCKET */
+
+#ifdef TNCODE
+#ifndef CK_AUTHENTICATION
+#ifdef OS2
+#ifdef _M_PPC
+#define NO_KERBEROS
+#define NO_SRP
+#else /* _M_PPC */
+#ifndef NO_SSL
+#define CK_SSL
+#define SSLDLL
+#endif /* NO_SSL */
+#endif /* _M_PPC */
+#ifndef NO_KERBEROS
+#define CK_KERBEROS
+#define KRB4
+#define KRB5
+#define KRB524
+#define KRB524_CONV
+#ifdef NT
+#ifndef _M_PPC
+#ifndef _M_ALPHA
+#ifndef NO_SSL_KRB5
+#define SSL_KRB5
+#endif /* NO_SSL_KRB5 */
+#endif /* _M_ALPHA */
+#endif /* _M_PPC */
+#endif /* NT */
+#endif /* NO_KERBEROS */
+#ifndef NO_SRP
+#define CK_SRP
+#endif /* NO_SRP */
+#define CK_AUTHENTICATION
+#endif /* OS2 */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_AUTHENTICATION /* Encryption must have Auth */
+#ifndef CK_ENCRYPTION
+#ifndef NO_ENCRYPTION
+#ifdef OS2
+#define CK_ENCRYPTION
+#define CK_DES
+#define CK_CAST
+#endif /* OS2 */
+#endif /* NO_ENCRYPTION */
+#endif /* CK_ENCRYPTION */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef NO_AUTHENTICATION /* Allow authentication to be */
+#ifdef CK_AUTHENTICATION /* disabled in NT and OS/2 */
+#undef CK_AUTHENTICATION
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_KERBEROS
+#undef CK_KERBEROS
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+#undef CK_SRP
+#endif /* CK_SRP */
+#ifdef CK_ENCRYPTION
+#undef CK_ENCRYPTION
+#endif /* CK_ENCRYPTION */
+#endif /* NO_AUTHENTICATION */
+
+#ifdef NO_ENCRYPTION /* Allow encryption to be */
+#ifdef CK_ENCRYPTION /* disabled in NT and OS/2 */
+#undef CK_ENCRYPTION
+#endif /* CK_ENCRYPTION */
+#endif /* NO_ENCRYPTION */
+
+#ifdef CK_KERBEROS /* Disable funcs not yet supported with Heimdal */
+#ifdef KRB5
+#ifndef HEIMDAL
+#define KRB5_U2U
+#endif /* HEIMDAL */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+/*
+ SSH section. NOSSH disables any form of SSH support.
+ If NOSSH is not defined (or implied by NONET, NOLOCAL, etc)
+ then SSHBUILTIN is defined for K95 and SSHCMD is defined for UNIX.
+ Then, if either SSHBUILTIN or SSHCMD is defined, ANYSSH is also defined.
+*/
+
+#ifndef NOSSH
+#ifndef NO_SSL
+#ifdef OS2ONLY
+#define NOSSH
+#endif /* OS2ONLY */
+#ifdef NT
+#ifndef CK_SSL
+#define NOSSH
+#endif /* CK_SSL */
+#endif /* NT */
+#else /* NO_SSL */
+#define NOSSH
+#endif /* NO_SSL */
+#endif /* NOSSH */
+
+#ifdef NOSSH /* NOSSH */
+#ifdef SSHBUILTIN /* undefines any SSH selctors */
+#undef SSHBUILTIN
+#endif /* SSHBUILTIN */
+#ifdef SFTP_BUILTIN
+#undef SFTP_BUILTIN
+#endif /* SFTP_BUILTIN */
+#ifdef SSHCMD
+#undef SSHCMD
+#endif /* SSHCMD */
+#ifdef ANYSSH
+#undef ANYSSH
+#endif /* ANYSSH */
+#else /* Not NOSSH */
+#ifndef NOLOCAL
+#ifdef OS2
+#ifndef SSHBUILTIN
+#define SSHBUILTIN
+#endif /* SSHBUILTIN */
+#else /* Not OS2 */
+#ifdef UNIX
+#ifndef SSHCMD
+#ifdef NETPTY
+#ifndef NOPUSH
+#define SSHCMD
+#endif /* NOPUSH */
+#endif /* NETPTY */
+#endif /* SSHCMD */
+#endif /* UNIX */
+#endif /* OS2 */
+#ifndef ANYSSH
+#ifdef SSHBUILTIN
+#define ANYSSH
+#ifdef SSHCMD
+#undef SSHCMD
+#endif /* SSHCMD */
+#else /* SSHBUILTIN */
+#ifdef SSHCMD
+#define ANYSSH
+#endif /* SSHCMD */
+#endif /* SSHBUILTIN */
+#endif /* ANYSSH */
+#endif /* NOLOCAL */
+#endif /* NOSSH */
+
+/* This is in case #ifdef SSH is used anywhere in the K95 modules */
+
+#ifdef OS2
+#ifdef SSHBUILTIN
+#ifndef SSH
+#define SSH
+#endif /* SSH */
+#endif /* SSHBUILTIN */
+#endif /* OS2 */
+
+#ifdef CK_AUTHENTICATION
+#define CK_SECURITY
+#else
+#ifdef CK_SSL
+#define CK_AUTHENTICATION
+#define CK_SECURITY
+#endif /* CK_SSL */
+#endif /* CK_AUTHENTICATION */
+
+/* Environment stuff */
+
+#ifndef OS2ORUNIX
+#ifndef NOPUTENV
+#define NOPUTENV
+#endif /* NOPUTENV */
+#endif /* OS2ORUNIX */
+
+#ifndef CK_ENVIRONMENT
+#ifdef OS2
+#define CK_ENVIRONMENT
+#else
+#ifdef UNIX
+#define CK_ENVIRONMENT
+#else
+#ifdef STRATUS
+#define CK_ENVIRONMENT
+#else
+#ifdef VMS
+#define CK_ENVIRONMENT
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* CK_ENVIRONMENT */
+#ifndef NOSNDLOC /* RFC 779 SEND LOCATION */
+#ifndef CK_SNDLOC
+#define CK_SNDLOC
+#endif /* CK_SNDLOC */
+#endif /* NOSNDLOC */
+#ifndef NOXDISPLOC /* RFC 1096 XDISPLOC */
+#ifndef CK_XDISPLOC
+#define CK_XDISPLOC
+#endif /* CK_XDISPLOC */
+#endif /* NOXDISPLOC */
+#ifndef NOFORWARDX
+#ifndef NOPUTENV
+#ifndef NOSELECT
+#ifndef CK_FORWARD_X
+#ifdef CK_AUTHENTICATION
+#ifndef OS2ONLY
+#define CK_FORWARD_X
+#endif /* OS2ONLY */
+#endif /* CK_AUTHENTICATION */
+#endif /* CK_FORWARD_X */
+#endif /* NOSELECT */
+#endif /* NOPUTENV */
+#endif /* NOFORWARDX */
+#ifndef NO_COMPORT
+#ifdef TCPSOCKET
+#ifndef TN_COMPORT
+#define TN_COMPORT
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+#endif /* NO_COMPORT */
+#endif /* TNCODE */
+
+#ifndef NOXFER
+#ifndef NOCTRLZ /* Allow SET FILE EOF CTRL-Z */
+#ifndef CK_CTRLZ
+#ifdef OS2ORUNIX
+#define CK_CTRLZ
+#endif /* OS2ORUNIX */
+#endif /* CK_CTRLZ */
+#endif /* NOCTRLZ */
+#endif /* NOXFER */
+
+#ifndef NOPERMS /* File permissions in A packets */
+#ifndef CK_PERMS
+#ifdef UNIX
+#define CK_PERMS
+#else
+#ifdef VMS
+#define CK_PERMS
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* CK_PERMS */
+#endif /* NOPERMS */
+#ifdef CK_PERMS
+#define CK_PERMLEN 24 /* Max length of sys-dependent perms */
+#endif /* CK_PERMS */
+
+#ifdef UNIX /* NOSETBUF for everybody */
+#ifndef NOSETBUF
+#ifndef USE_SETBUF /* This is the escape clause */
+#define NOSETBUF
+#endif /* USE_SETBUF */
+#endif /* NOSETBUF */
+#endif /* UNIX */
+
+#ifndef USE_STRERROR /* Whether to use strerror() */
+#ifdef pdp11
+#define USE_STRERROR
+#endif /* pdp11 */
+#endif /* USE_STRERROR */
+
+#ifdef VMS /* Features for all VMS builds */
+#ifndef NOJC
+#define NOJC
+#endif /* NOJC */
+#ifndef NOSETBUF
+#define NOSETBUF
+#endif /* NOSETBUF */
+#ifndef DYNAMIC
+#define DYNAMIC
+#endif /* DYNAMIC */
+#ifndef NOCURSES
+#ifndef CK_CURSES
+#define CK_CURSES
+#endif /* CK_CURSES */
+#endif /* NOCURSES */
+#endif /* VMS */
+
+#ifndef NOCKTIMERS /* Dynamic timeouts */
+#ifndef CK_TIMERS
+#define CK_TIMERS
+#endif /* CK_TIMERS */
+#endif /* NOCKTIMERS */
+
+#define CK_SPEED /* Control-prefix removal */
+#ifdef NOCKSPEED
+#undef CK_SPEED
+#endif /* NOCKSPEED */
+
+#ifndef NOCKXXCHAR
+#ifndef CKXXCHAR
+#ifdef UNIX
+#define CKXXCHAR
+#else
+#ifdef OS2
+#define CKXXCHAR
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* CKXXCHAR */
+#endif /* NOCKXXCHAR */
+
+#ifdef MAC /* For Macintosh, no escape */
+#define NOPUSH /* to operating system */
+#endif /* MAC */
+
+/* Systems where we can call zmkdir() to create directories. */
+
+#ifndef CK_MKDIR
+#ifndef NOMKDIR
+
+#ifdef UNIX
+#ifndef pdp11
+#define CK_MKDIR
+#endif /* pdp11 */
+#endif /* UNIX */
+
+#ifdef OS2
+#define CK_MKDIR
+#endif /* OS2 */
+
+#ifdef VMS
+#define CK_MKDIR
+#endif /* VMS */
+
+#ifdef STRATUS
+#define CK_MKDIR
+#endif /* STRATUS */
+
+#ifdef OSK
+#define CK_MKDIR
+#endif /* OSK */
+
+#ifdef datageneral
+#define CK_MKDIR
+#endif /* datageneral */
+
+#endif /* CK_MKDIR */
+#endif /* NOMKDIR */
+
+#ifdef NOMKDIR /* Allow for command-line override */
+#ifdef CK_MKDIR
+#undef CK_MKDIR
+#endif /* CK_MKDIR */
+#endif /* NOMKDIR */
+
+/* Systems for which we can enable the REDIRECT command automatically */
+/* As of 6.0.193, it should work for all UNIX... */
+
+#ifndef NOREDIRECT
+#ifndef CK_REDIR
+#ifdef UNIX
+#define CK_REDIR
+#endif /* UNIX */
+#ifdef OS2 /* As well as OS/2 and friends... */
+#define CK_REDIR
+#endif /* OS2 */
+#endif /* CK_REDIR */
+#endif /* NOREDIRECT */
+
+#ifdef NOPUSH /* But... REDIRECT command is not */
+#ifdef CK_REDIR /* allowed if NOPUSH is defined. */
+#undef CK_REDIR
+#endif /* CK_REDIR */
+#ifdef NETCMD /* Nor is SET NET COMMAND */
+#undef NETCMD
+#endif /* NETCMD */
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#endif /* NOPUSH */
+
+#ifndef PEXITSTAT /* \v(pexitstat) variable defined */
+#ifdef OS2ORUNIX
+#define PEXITSTAT
+#else
+#ifdef VMS
+#define PEXITSTAT
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#endif /* PEXITSTAT */
+
+/* The following allows automatic enabling of REDIRECT to be overridden... */
+
+#ifdef NOREDIRECT
+#ifdef NETCMD
+#undef NETCMD
+#endif /* NETCMD */
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#ifdef CK_REDIR
+#undef CK_REDIR
+#endif /* CK_REDIR */
+#endif /* NOREDIRECT */
+
+#ifdef NONETCMD
+#ifdef NETCMD
+#undef NETCMD
+#endif /* NETCMD */
+#ifdef NETPTY
+#undef NETPTY
+#endif /* NETPTY */
+#endif /* NONETCMD */
+
+#ifdef CK_REDIR
+_PROTOTYP( int ttruncmd, (char *) );
+#endif /* CK_REDIR */
+
+/* Use built-in DIRECTORY command */
+
+#ifndef NOMYDIR
+#ifndef DOMYDIR
+#ifdef UNIXOROSK
+#define DOMYDIR
+#else
+#ifdef OS2
+#define DOMYDIR
+#else
+#ifdef VMS
+#define DOMYDIR
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIXOROSK */
+#endif /* DOMYDIR */
+#endif /* NOMYDIR */
+
+/* Sending from and receiving to commands/pipes */
+
+#ifndef PIPESEND
+#ifdef UNIX
+#define PIPESEND
+#endif /* UNIX */
+#ifdef OS2
+#define PIPESEND
+#endif /* OS2 */
+#endif /* PIPESEND */
+
+#ifdef PIPESEND
+#ifdef NOPIPESEND
+#undef PIPESEND
+#endif /* NOPIPESEND */
+#ifdef NOPUSH
+#undef PIPESEND
+#endif /* NOPUSH */
+#endif /* PIPESEND */
+
+#ifdef NOPUSH
+#ifdef BROWSER
+#undef BROWSER
+#endif /* BROWSER */
+#endif /* NOPUSH */
+
+/* Versions where we support the RESEND command */
+
+#ifndef NOXFER
+#ifndef NORESEND
+#ifndef CK_RESEND
+#ifdef UNIX
+#ifndef pdp11
+#define CK_RESEND
+#endif /* pdp11 */
+#endif /* UNIX */
+
+#ifdef VMS
+#define CK_RESEND
+#endif /* VMS */
+
+#ifdef OS2
+#define CK_RESEND
+#endif /* OS2 */
+
+#ifdef AMIGA
+#define CK_RESEND
+#endif /* AMIGA */
+
+#ifdef datageneral
+#define CK_RESEND
+#endif /* datageneral */
+
+#ifdef STRATUS
+#define CK_RESEND
+#endif /* STRATUS */
+
+#ifdef OSK
+#define CK_RESEND
+#endif /* OSK */
+
+#endif /* CK_RESEND */
+#endif /* NORESEND */
+#endif /* NOXFER */
+
+/* Systems implementing "Doomsday Kermit" protocol ... */
+
+#ifndef DOOMSDAY
+#ifdef UNIX
+#define DOOMSDAY
+#else
+#ifdef VMS
+#define DOOMSDAY
+#else
+#ifdef OS2
+#define DOOMSDAY
+#else
+#ifdef STRATUS
+#define DOOMSDAY
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* DOOMSDAY */
+
+/* Systems where we want the Thermometer to be used for fullscreen */
+
+#ifdef OS2
+#ifndef CK_PCT_BAR
+#define CK_PCT_BAR
+#endif /* CK_PCT_BAR */
+#endif /* OS2 */
+
+/* Systems where we have a REXX command */
+
+#ifdef OS2
+#ifdef __32BIT__
+#ifndef NOREXX
+#define CK_REXX
+#endif /* NOREXX */
+#endif /* __32BIT__ */
+#endif /* OS2 */
+
+/* Platforms that have a ZCHKPID function */
+
+#ifdef OS2ORUNIX
+#define ZCHKPID
+#endif /* OS2ORUNIX */
+
+#ifndef ZCHKPID
+/* If we can't check pids then we have treat all pids as active & valid. */
+#define zchkpid(x) 1
+#endif /* ZCHKPID */
+
+/* Systems that have a ZRENAME function */
+
+#define ZRENAME /* They all do */
+
+/* Systems that have a ZCOPY function */
+
+#ifndef ZCOPY
+#ifdef VMS
+#define ZCOPY
+#else
+#ifdef OS2
+#define ZCOPY
+#else
+#ifdef UNIX
+#define ZCOPY
+#else
+#ifdef STRATUS
+#define ZCOPY
+#endif /* STRATUS */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* ZCOPY */
+
+/* Systems that have ttgwsiz() (they all should but they don't) */
+
+#ifndef NOTTGWSIZ
+#ifndef CK_TTGWSIZ
+#ifdef UNIX
+#define CK_TTGWSIZ
+#else
+#ifdef VMS
+#define CK_TTGWSIZ
+#else
+#ifdef OS2
+#define CK_TTGWSIZ
+#else
+#ifdef OSK
+#define CK_TTGWSIZ
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* CK_TTGWSIZ */
+#endif /* NOTTGWSIZ */
+
+#ifdef NOTTGWSIZ
+#ifdef CK_TTGWSIZ
+#undef CK_TTGWSIZ
+#endif /* CK_TTGWSIZ */
+#endif /* NOTTGWSIZ */
+
+#ifdef OS2
+/* OS/2 C-Kermit features not available in 16-bit version... */
+
+#ifdef OS2ONLY
+#ifndef __32BIT__
+#ifndef NOLOCAL
+#ifdef PCFONTS /* PC Font support */
+#undef PCFONTS
+#endif /* PCFONTS */
+#ifdef NPIPE /* Named Pipes communication */
+#undef NPIPE
+#endif /* NPIPE */
+#ifdef CK_NETBIOS /* NETBIOS communication */
+#undef CK_NETBIOS
+#endif /* CK_NETBIOS */
+#ifdef OS2MOUSE /* Mouse */
+#undef OS2MOUSE
+#endif /* OS2MOUSE */
+#ifdef OS2PM /* Presentation Manager */
+#undef OS2PM
+#endif /* OS2PM */
+#endif /* NOLOCAL */
+#ifdef CK_REXX /* Rexx */
+#undef CK_REXX
+#endif /* CK_REXX */
+#endif /* __32BIT__ */
+#endif /* OS2ONLY */
+
+/* OS/2 C-Kermit features not available in Windows NT version... */
+
+#ifdef NT
+#ifdef PCFONTS /* PC Font support */
+#undef PCFONTS
+#endif /* PCFONTS */
+#ifdef OS2PM /* Presentation Manager */
+#undef OS2PM
+#endif /* OS2PM */
+#ifdef CK_REXX /* Rexx */
+#undef CK_REXX
+#endif /* CK_REXX */
+#endif /* NT */
+#endif /* OS2 */
+
+/*
+ Systems that have select().
+ This is used for both msleep() and for read-buffer checking in in_chk().
+*/
+#define CK_SLEEPINT 250 /* milliseconds - set this to something that
+ divides evenly into 1000 */
+#ifndef SELECT
+#ifndef NOSELECT
+#ifdef __linux__
+#define SELECT
+#else
+#ifdef SUNOS4
+#define SELECT
+#else
+#ifdef NEXT
+#define SELECT
+#else
+#ifdef RTAIX
+#define SELECT
+#else
+#ifdef HPUX
+/*
+ Not really. I think it's only in HP-UX 7.0 and later, except it's also
+ in earlier versions that have TCP/IP installed. Override this default
+ in particular HP-UX makefile entries by adding -DNOSELECT, as in (e.g.)
+ the HP-UX 6.5 ones.
+*/
+#define SELECT
+#else
+#ifdef AIXRS
+#define SELECT
+#else
+#ifdef BSD44
+#define SELECT
+#else
+#ifdef BSD4
+#define SELECT
+#else
+#ifdef OXOS
+#define SELECT
+#else
+#ifdef OS2
+#define SELECT
+#else
+#ifdef BEBOX
+#define SELECT
+#endif /* BEBOX */
+#endif /* OS2 */
+#endif /* OXOS */
+#endif /* BSD4 */
+#endif /* BSD44 */
+#endif /* AIXRS */
+#endif /* HPUX */
+#endif /* RTAIX */
+#endif /* NEXT */
+#endif /* __linux__ */
+#endif /* SUNOS4 */
+#endif /* NOSELECT */
+#endif /* SELECT */
+
+/*
+ The following section moved here from ckcnet.h in 6.1 because select()
+ is now used for non-networking purposes.
+*/
+
+/* On HP-9000/500 HP-UX 5.21 this stuff is not defined in any header file */
+
+#ifdef hp9000s500
+#ifndef NEEDSELECTDEFS
+#define NEEDSELECTDEFS
+#endif /* NEEDSELECTDEFS */
+#endif /* hp9000s500 */
+
+#ifdef NEEDSELECTDEFS
+typedef long fd_mask;
+#ifndef NBBY
+#define NBBY 8
+#endif /* NBBY */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif /* FD_SETSIZE */
+#ifndef NFDBITS
+#define NFDBITS (sizeof(fd_mask) * NBBY)
+#endif /* NFDBITS */
+#ifndef howmany
+#define howmany(x,y) (((x)+((y)-1))/(y))
+#endif /* howmany */
+typedef struct fd_set {
+ fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+#ifndef FD_SET
+#define FD_SET(n,p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#endif /* FD_SET */
+#ifndef FD_CLR
+#define FD_CLR(n,p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#endif /* FD_CLR */
+#ifndef FD_ISSET
+#define FD_ISSET(n,p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* FD_ISSET */
+#ifndef FD_COPY
+#define FD_COPY(f,t) (bcopy(f,t,sizeof(*(f)))
+#endif /* FD_COPY */
+#ifndef FD_ZERO
+#define FD_ZERO(p) bzero((char *)(p),sizeof(*(p)))
+#endif /* FD_ZERO */
+#endif /* NEEDSELECTDEFS */
+
+/*
+ CK_NEED_SIG is defined if the system cannot check the console to
+ to see if characters are waiting. This is used during local-mode file
+ transfer to interrupt the transfer, refresh the screen display, etc.
+ If CK_NEED_SIG is defined, then file-transfer interruption characters
+ have to be preceded a special character, e.g. the SIGQUIT character.
+ CK_NEED_SIG should be defined if the conchk() function is not operational.
+*/
+#ifdef NOPOLL /* For overriding CK_POLL definition */
+#ifdef CK_POLL
+#undef CK_POLL
+#endif /* CK_POLL */
+#endif /* NOPOLL */
+
+#ifndef CK_POLL /* If we don't have poll() */
+#ifndef RDCHK /* And we don't have rdchk() */
+#ifndef SELECT /* And we don't have select() */
+#ifdef ATTSV
+#ifndef aegis
+#ifndef datageneral
+#ifndef OXOS
+#define CK_NEED_SIG
+#endif /* OXOS */
+#endif /* datageneral */
+#endif /* aegis */
+#endif /* ATTSV */
+#ifdef POSIX
+#ifndef CK_NEED_SIG
+#define CK_NEED_SIG
+#endif /* CK_NEED_SIG */
+#endif /* POSIX */
+#endif /* SELECT */
+#endif /* RDCHK */
+#endif /* CK_POLL */
+
+#ifdef HPUX /* HP-UX has select() */
+#ifdef CK_NEED_SIG
+#undef CK_NEED_SIG
+#endif /* CK_NEED_SIG */
+#endif /* HPUX */
+
+#ifdef AIXRS /* AIX has select() */
+#ifdef CK_NEED_SIG
+#undef CK_NEED_SIG
+#endif /* CK_NEED_SIG */
+#endif /* AIXRS */
+
+#ifdef BSD44 /* 4.4BSD has FIONREAD */
+#ifdef CK_NEED_SIG
+#undef CK_NEED_SIG
+#endif /* CK_NEED_SIG */
+#endif /* BSD44 */
+
+#ifdef QNX /* QNX has FIONREAD and select() */
+#ifdef CK_NEED_SIG
+#undef CK_NEED_SIG
+#endif /* CK_NEED_SIG */
+#endif /* QNX */
+
+#ifdef COHERENT
+#ifndef NOTIMEZONE
+#define NOTIMEZONE
+#endif /* NOTIMEZONE */
+#endif /* COHERENT */
+
+#ifdef UNIX
+#ifndef HAVE_TZ /* Can we use struct timezone? */
+#ifndef NOTIMEZONE
+#ifdef PTX
+#define NOTIMEZONE
+#else
+#ifndef SELECT
+#ifdef COHERENT
+#define NOTIMEZONE
+#else
+#ifdef BELLV10
+#define NOTIMEZONE
+#endif /* BELLV10 */
+#endif /* COHERENT */
+#endif /* SELECT */
+#endif /* PTX */
+#endif /* NOTIMEZONE */
+#endif /* HAVE_TZ */
+#ifndef NOTIMEVAL /* Can we use struct timeval? */
+#ifndef HAVE_TV
+#define HAVE_TV
+#endif /* HAVE_TV */
+#endif /* NOTIMEVAL */
+#ifndef NOTIMEZONE
+#ifndef HAVE_TZ
+#define HAVE_TZ
+#endif /* HAVE_TZ */
+#endif /* NOTIMEZONE */
+#endif /* UNIX */
+
+#ifdef SCO32
+#ifdef HAVE_TV
+#undef HAVE_TV
+#endif /* HAVE_TV */
+#ifdef HAVE_TZ
+#undef HAVE_TZ
+#endif /* HAVE_TZ */
+#ifndef NOTIMEVAL
+#define NOTIMEVAL
+#endif /* NOTIMEVAL */
+#ifndef NOTIMEZONE
+#define NOTIMEZONE
+#endif /* NOTIMEZONE */
+#endif /* SCO32 */
+
+#ifdef ATT7300
+#ifdef HAVE_TV
+#undef HAVE_TV
+#endif /* HAVE_TV */
+#ifdef HAVE_TZ
+#undef HAVE_TZ
+#endif /* HAVE_TZ */
+#ifndef NOTIMEVAL
+#define NOTIMEVAL
+#endif /* NOTIMEVAL */
+#ifndef NOTIMEZONE
+#define NOTIMEZONE
+#endif /* NOTIMEZONE */
+#endif /* ATT7300 */
+
+/*
+ Automatic parity detection.
+ This actually implies a lot more now: length-driven packet reading,
+ "Doomsday Kermit" IBM Mainframe file transfer through 3270 data streams, etc.
+*/
+#ifdef UNIX /* For Unix */
+#ifndef NOPARSEN
+#define PARSENSE
+#endif /* NOPARSEN */
+#endif /* UNIX */
+
+#ifdef VMS /* ... and VMS */
+#ifndef NOPARSEN
+#define PARSENSE
+#endif /* NOPARSEN */
+#ifdef __GNUC__
+#define VMSGCC
+#endif /* __GNUC__ */
+#endif /* VMS */
+
+#ifdef MAC /* and Macintosh */
+#ifndef NOPARSEN
+#define PARSENSE
+#endif /* NOPARSEN */
+#endif /* MAC */
+
+#ifdef STRATUS /* and Stratus VOS */
+#ifndef NOPARSEN
+#define PARSENSE
+#endif /* NOPARSEN */
+#endif /* STRATUS */
+
+#ifdef OS2 /* and OS/2, finally */
+#ifndef NOPARSEN
+#define PARSENSE
+#endif /* NOPARSEN */
+#endif /* OS2 */
+
+#ifndef NODYNAMIC /* DYNAMIC is default for UNIX */
+#ifndef DYNAMIC /* as of C-Kermit 7.0 */
+#ifdef UNIX
+#define DYNAMIC
+#endif /* UNIX */
+#endif /* DYNAMIC */
+#endif /* NODYNAMIC */
+
+#ifdef DYNAMIC /* If DYNAMIC is defined */
+#define DCMDBUF /* then also define this. */
+#endif /* DYNAMIC */
+
+#ifndef CK_LBRK /* Can send Long BREAK */
+
+#ifdef UNIX /* (everybody but OS-9) */
+#define CK_LBRK
+#endif /* UNIX */
+#ifdef VMS
+#define CK_LBRK
+#endif /* VMS */
+#ifdef datageneral
+#define CK_LBRK
+#endif /* datageneral */
+#ifdef GEMDOS
+#define CK_LBRK
+#endif /* GEMDOS */
+#ifdef OS2
+#define CK_LBRK
+#endif /* OS2 */
+#ifdef AMIGA
+#define CK_LBRK
+#endif /* AMIGA */
+#ifdef STRATUS
+#define CK_LBRK
+#endif /* STRATUS */
+
+#endif /* CK_LBRK */
+
+/* Carrier treatment */
+/* These are defined here because they are shared by the system dependent */
+/* and the system independent modules. */
+
+#define CAR_OFF 0 /* Off: ignore carrier always. */
+#define CAR_ON 1 /* On: heed carrier always, except during DIAL. */
+#define CAR_AUT 2 /* Auto: heed carrier, but only if line is declared */
+ /* to be a modem line, and only during CONNECT. */
+
+/* And more generically (for use with any ON/OFF/AUTO feature) */
+#define CK_OFF 0
+#define CK_ON 1
+#define CK_AUTO 2
+
+#ifndef NOLOCAL
+/*
+ Serial interface speeds available.
+
+ As of C-Kermit 6.1 there is a new method to get the supported
+ speeds, which obviates the need for all the craziness below. At runtime,
+ just call the new ttspdlist() routine to get a list of supported speeds.
+ Then the user interface module can build a keyword table or menu from it.
+*/
+#ifndef TTSPDLIST
+#ifdef UNIX /* For now, only for UNIX */
+#ifndef OLINUXHISPEED /* But not systems with hacks for */
+#ifndef MINIX /* high speeds, like 110 = 115200 */
+#define TTSPDLIST
+#endif /* MINIX */
+#endif /* OLINUXHISPEED */
+#else
+#ifdef VMS
+#define TTSPDLIST /* VMS gets it too */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* TTSPDLIST */
+
+#ifndef NODIAL /* Hangup by modem command */
+#ifndef NOMDMHUP
+#ifndef MDMHUP
+#define MDMHUP
+#endif /* MDMHUP */
+#endif /* NOMDMHUP */
+#endif /* NODIAL */
+
+#ifdef NOSPL
+#ifndef NOLOGDIAL /* Connection log needs mjd(), etc. */
+#define NOLOGDIAL
+#endif /* NOLOGDIAL */
+#endif /* NOSPL */
+
+#ifdef pdp11
+#define NOLOGDIAL
+#endif /* pdp11 */
+
+#ifndef NOLOGDIAL /* Connection log */
+#ifndef CXLOGFILE
+#define CXLOGFILE "CX.LOG" /* Default connection log file name */
+#endif /* CXLOGFILE */
+#ifndef CKLOGDIAL
+#ifndef CK_SMALL
+#define CKLOGDIAL
+#define CXLOGBUFL 1024 /* Connection log record buffer size */
+#endif /* CK_SMALL */
+#endif /* NOLOGDIAL */
+#endif /* CKLOGDIAL */
+
+#endif /* NOLOCAL */
+
+#ifdef NOTTSPDLIST /* Except if NOTTSPDLIST is defined */
+#ifdef TTSPDLIST
+#undef TTSPDLIST
+#endif /* TTSPDLIST */
+#endif /* NOTTSPDLIST */
+
+#ifdef TTSPDLIST
+
+_PROTOTYP( long * ttspdlist, (void) );
+
+#else /* TTSPDLIST not defined */
+/*
+ We must use a long and convoluted series of #ifdefs that have to be kept in
+ sync with the code in the ck?tio.c module.
+
+ We assume that everybody supports: 0, 110, 300, 600, 1200, 2400, 4800, and
+ 9600 bps. Symbols for other speeds are defined here. You can also add
+ definitions on the CC command lines. These definitions affect the SET SPEED
+ keyword table, and are not necessarily usable in the system-dependent
+ speed-setting code in the ck?tio.c modules, which depends on system-specific
+ symbols like (in UNIX) B19200. In other words, just defining it doesn't
+ mean it'll work -- you also have to supply the supporting code in ttsspd()
+ and ttgspd() in ck?tio.c.
+
+ The symbols have the form BPS_xxxx, where xxxx is the speed in bits per
+ second, or (for bps values larger than 9999) thousands of bps followed by K.
+ The total symbol length should be 8 characters or less. Some values are
+ enabled automatically below. You can disable a particular value by defining
+ NOB_xxxx on the CC command line.
+
+*/
+
+#ifndef NOB_50
+#define BPS_50 /* 50 bps */
+#endif
+
+#ifndef NOB_75
+#define BPS_75 /* 75 bps */
+#endif
+
+#ifndef NOB7512
+#ifdef ANYBSD
+#define BPS_7512 /* 75/1200 Split Speed */
+#endif /* ANYBSD */
+#endif /* NOB7512 */
+
+#ifndef NOB134
+#ifdef SOLARIS25
+#define BPS_134
+#else
+#undef BPS_134 /* 134.5 bps (IBM 2741) */
+#endif /* BPS_134 */
+#endif /* NOB134 */
+
+#ifndef NOB_150
+#define BPS_150 /* 150 bps */
+#endif
+
+#ifndef NOB_200
+#define BPS_200 /* 200 bps */
+#endif
+
+#ifndef NOB_1800
+#ifdef MAC
+#define BPS_1800 /* 1800 bps */
+#else
+#ifdef SOLARIS25
+#define BPS_1800
+#endif
+#endif
+#endif
+
+#ifndef NOB_3600
+#ifndef SOLARIS25
+#define BPS_3600 /* 3600 bps */
+#endif
+#endif
+
+#ifndef NOB_7200
+#ifndef SOLARIS25
+#define BPS_7200 /* 7200 bps */
+#endif /* SOLARIS25 */
+#endif
+
+#ifndef NOB_14K
+#ifdef BSD44
+#define BPS_14K /* 14400 bps */
+#else
+#ifdef OS2
+#define BPS_14K
+#else
+#ifdef NEXT
+#define BPS_14K
+#else
+#ifdef MAC
+#define BPS_14K
+#else
+#ifdef AMIGA
+#define BPS_14K
+#endif /* AMIGA */
+#endif /* MAC */
+#endif /* NEXT */
+#endif /* OS2 */
+#endif /* BSD44 */
+#endif /* NOB_14K */
+
+#ifndef NOB_19K
+#define BPS_19K /* 19200 bps */
+#endif
+
+#ifndef NOB_28K
+#ifdef BSD44
+#define BPS_28K
+#else
+#ifdef OS2
+#define BPS_28K
+#else
+#ifdef NEXT
+#define BPS_28K /* 28800 bps */
+#else
+#ifdef MAC
+#define BPS_28K /* 28800 bps */
+#endif /* MAC */
+#endif /* NEXT */
+#endif /* OS2 */
+#endif /* BSD44 */
+#endif /* NOB_28K */
+
+#ifndef NOB_38K
+#define BPS_38K /* 38400 bps */
+#endif
+
+#ifndef NOB_57K
+#ifdef Plan9
+#define BPS_57K
+#else
+#ifdef SOLARIS25
+#define BPS_57K
+#else
+#ifdef VMS
+#define BPS_57K /* 57600 bps */
+#else
+#ifdef OS2
+#define BPS_57K
+#else
+#ifdef __linux__
+#define BPS_57K
+#else
+#ifdef HPUX
+#define BPS_57K
+#else
+#ifdef NEXT
+#define BPS_57K
+#else
+#ifdef __386BSD__
+#define BPS_57K
+#else
+#ifdef __FreeBSD__
+#define BPS_57K
+#else
+#ifdef __NetBSD__
+#define BPS_57K
+#else
+#ifdef MAC
+#define BPS_57K
+#else
+#ifdef QNX
+#define BPS_57K
+#else
+#ifdef BEOSORBEBOX
+#define BPS_57K
+#else
+#ifdef IRIX62
+#define BPS_57K
+#else
+#ifdef SCO_OSR504
+#define BPS_57K
+#else
+#ifdef BSDI2
+#define BPS_57K
+#endif /* BSDI2 */
+#endif /* SCO_OSR504 */
+#endif /* IRIX62 */
+#endif /* BEOSORBEBOX */
+#endif /* QNX */
+#endif /* MAC */
+#endif /* __NetBSD__ */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#endif /* NEXT */
+#endif /* HPUX */
+#endif /* __linux__ */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* SOLARIS25 */
+#endif /* Plan9 */
+#endif /* NOB_57K */
+
+#ifndef NOB_76K
+#ifdef BSDI2
+#define BPS_76K
+#endif /* BSDI2 */
+#ifdef Plan9
+#define BPS_76K
+#endif /* Plan9 */
+#ifdef SOLARIS25
+#define BPS_76K
+#endif /* SOLARIS25 */
+#ifdef VMS
+#define BPS_76K /* 76800 bps */
+#endif /* VMS */
+#ifdef OS2
+#ifdef __32BIT__
+#define BPS_76K
+#endif /* __32BIT__ */
+#endif /* OS2 */
+#ifdef QNX
+#define BPS_76K
+#endif /* QNX */
+#ifdef IRIX62
+#define BPS_76K
+#endif /* IRIX62 */
+#ifdef SCO_OSR504
+#define BPS_76K
+#endif /* SCO_OSR504 */
+#endif /* NOB_76K */
+
+#ifndef NOB_115K
+#ifdef BSDI2
+#define BPS_115K
+#endif /* BSDI2 */
+#ifdef Plan9
+#define BPS_115K
+#endif /* Plan9 */
+#ifdef SOLARIS25
+#define BPS_115K
+#endif /* SOLARIS25 */
+#ifdef VMS
+#define BPS_115K /* 115200 bps */
+#else
+#ifdef QNX
+#define BPS_115K
+#else
+#ifdef HPUX
+#define BPS_115K
+#else
+#ifdef __linux__
+#define BPS_115K
+#else
+#ifdef __386BSD__
+#define BPS_115K
+#else
+#ifdef __FreeBSD__
+#define BPS_115K
+#else
+#ifdef __NetBSD__
+#define BPS_115K
+#else
+#ifdef OS2
+#ifdef __32BIT__
+#define BPS_115K
+#endif /* __32BIT__ */
+#else
+#ifdef BEOSORBEBOX
+#define BPS_115K
+#else
+#ifdef IRIX62
+#define BPS_115K
+#else
+#ifdef SCO_OSR504
+#define BPS_115K
+#endif /* SCO_OSR504 */
+#endif /* IRIX62 */
+#endif /* BEOSORBEBOX */
+#endif /* OS2 */
+#endif /* __NetBSD__ */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#endif /* __linux__ */
+#endif /* HPUX */
+#endif /* QNX */
+#endif /* VMS */
+#endif /* NOB_115K */
+
+#ifndef NOB_230K /* 230400 bps */
+#ifdef BSDI2
+#define BPS_230K
+#else
+#ifdef SCO_OSR504
+#define BPS_230K
+#else
+#ifdef __linux__
+#define BPS_230K
+#else
+#ifdef SOLARIS25
+#define BPS_230K
+#else
+#ifdef OS2
+#ifdef __32BIT__
+#define BPS_230K
+#endif /* __32BIT__ */
+#else
+#undef BPS_230K
+#endif /* OS2 */
+#endif /* SOLARIS25 */
+#endif /* __linux__ */
+#endif /* SCO_OSR504 */
+#endif /* BSDI2 */
+#endif /* NOB_230K */
+
+#ifndef NOB_460K /* 460800 bps */
+#ifdef SCO_OSR504
+#define BPS_460K
+#else
+#ifdef __linux__
+#define BPS_460K
+#else
+#ifdef OS2
+#ifdef __32BIT__
+#define BPS_460K
+#endif /* __32BIT__ */
+#else
+#undef BPS_460K
+#endif /* __linux__ */
+#endif /* SCO_OSR504 */
+#endif /* OS2 */
+#endif /* NOB_460K */
+
+#ifndef NOB_921K /* 921600 bps */
+#ifdef SCO_OSR504
+#define BPS_921K
+#endif /* SCO_OSR504 */
+#endif /* NOB_921K */
+
+#ifdef BPS_921K /* Maximum speed defined */
+#define MAX_SPD 921600L
+#else
+#ifdef BPS_460K
+#define MAX_SPD 460800L
+#else
+#ifdef BPS_230K
+#define MAX_SPD 230400L
+#else
+#ifdef BPS_115K
+#define MAX_SPD 115200L
+#else
+#ifdef BPS_76K
+#define MAX_SPD 76800L
+#else
+#ifdef BPS_57K
+#define MAX_SPD 57600L
+#else
+#ifdef BPS_38K
+#define MAX_SPD 38400L
+#else
+#ifdef BPS_28K
+#define MAX_SPD 28800L
+#else
+#ifdef BPS_19K
+#define MAX_SPD 19200L
+#else
+#ifdef BPS_14K
+#define MAX_SPD 14400L
+#else
+#define MAX_SPD 9600L
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif /* TTSPDLIST */
+
+#ifndef CONGSPD /* Systems that can call congspd() */
+#ifdef UNIX
+#define CONGSPD
+#endif /* UNIX */
+#ifdef VMS
+#define CONGSPD
+#endif /* VMS */
+#ifdef STRATUS
+#define CONGSPD
+#endif /* STRATUS */
+#endif /* CONGSPD */
+
+/* Types of flow control available */
+
+#define CK_XONXOFF /* Everybody can do this, right? */
+
+#ifdef AMIGA /* Commodore Amiga */
+#define CK_RTSCTS /* has RTS/CTS */
+#endif /* AMIGA */
+
+#ifdef SUN4S5 /* SunOS in System V environment */
+#define CK_RTSCTS
+#else /* SunOS 4.0/4.1 in BSD environment */
+#ifdef SUNOS4 /* SunOS 4.0+later supports RTS/CTS */
+#ifdef SUNOS41 /* Easy in 4.1 and later */
+#define CK_RTSCTS
+#else /* Harder in 4.0 */
+#ifndef __GNUC__ /* (see tthflow() in ckutio.c) */
+#ifndef GNUC
+#define CK_RTSCTS /* Only if not using GNU gcc */
+#endif /* __GNUC__ */
+#endif /* GNUC */
+#endif /* SUNOS41 */
+#endif /* SUNOS4 */
+#endif /* SUN4S5 */
+
+#ifdef BSD44 /* And in 4.4 BSD, including BSDI */
+#define CK_RTSCTS
+#endif /* BSD44 */
+
+#ifdef TERMIOX /* Sys V R4 <termiox.h> */
+#ifndef CK_RTSCTS
+#define CK_RTSCTS
+#endif /* CK_RTSCTS */
+#ifndef CK_DTRCD
+#define CK_DTRCD
+#endif /* CK_DTRCD */
+#else
+#ifdef STERMIOX /* Sys V R4 <sys/termiox.h> */
+#ifndef CK_RTSCTS
+#define CK_RTSCTS
+#endif /* CK_RTSCTS */
+#ifndef CK_DTRCD
+#define CK_DTRCD
+#endif /* CK_DTRCD */
+#endif /* STERMIOX */
+#endif /* TERMIOX */
+
+#ifdef OXOS /* Olivetti X/OS R2 struct termios */
+#define CK_RTSCTS /* Ditto. */
+#define CK_DTRCD
+#endif /* OXOS */
+
+#ifdef AIXRS /* RS/6000 with AIX 3.x */
+#define CK_RTSCTS /* Has its own peculiar method... */
+#endif /* AIXRS */
+
+#ifdef __linux__ /* Linux */
+#define CK_RTSCTS
+#endif /* __linux__ */
+/*
+ Hardware flow control is not defined in POSIX.1. Nevertheless, a certain
+ style API for hardware flow control, using tcsetattr() and the CRTSCTS
+ bit(s), seems to be gaining currency on POSIX-based UNIX systems. The
+ following code defines the symbol POSIX_CRTSCTS for such systems.
+*/
+#ifdef CK_RTSCTS
+#ifdef __bsdi__ /* BSDI, a.k.a. BSD/386 */
+#define POSIX_CRTSCTS
+#endif /* __bsdi__ */
+#ifdef __linux__ /* Linux */
+#define POSIX_CRTSCTS
+#endif /* __linux__ */
+#ifdef __NetBSD__ /* NetBSD */
+#define POSIX_CRTSCTS
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+#define POSIX_CRTSCTS
+#endif /* __OpenBSD__ */
+#ifdef BEOSORBEBOX /* BeBOX */
+#define POSIX_CRTSCTS
+/* BEBOX defines CRTSFL as (CTSFLOW & RTSFLOW) */
+#define CRTSCTS CRTSFL
+#endif /* BEOSORBEBOX */
+#ifdef IRIX52 /* IRIX 5.2 and later */
+#define POSIX_CRTSCTS
+#define CRTSCTS CNEW_RTSCTS /* See <sys/termios.h> */
+#endif /* IRIX52 */
+#endif /* CK_RTSCTS */
+
+/* Implementations that have implemented the ttsetflow() function. */
+
+#ifndef CK_TTSETFLOW
+#ifdef UNIX
+#define CK_TTSETFLOW
+#endif /* UNIX */
+#ifdef OS2
+#define CK_TTSETFLOW
+#endif /* OS2 */
+#endif /* CK_TTSETFLOW */
+
+#ifdef CK_TTSETFLOW
+_PROTOTYP( int ttsetflow, (int) );
+#endif /* CK_TTSETFLOW */
+/*
+ Systems where we can expand tilde at the beginning of file or directory names
+*/
+#ifdef POSIX
+#ifndef DTILDE
+#define DTILDE
+#endif /* DTILDE */
+#endif /* POSIX */
+#ifdef BSD4
+#ifndef DTILDE
+#define DTILDE
+#endif /* DTILDE */
+#endif /* BSD4 */
+#ifdef ATTSV
+#ifndef DTILDE
+#define DTILDE
+#endif /* DTILDE */
+#endif /* ATTSV */
+#ifdef OSK
+#ifndef DTILDE
+#define DTILDE
+#endif /* DTILDE */
+#endif /* OSK */
+#ifdef HPUX /* I don't know why this is */
+#ifndef DTILDE /* necessary, since -DHPUX */
+#define DTILDE /* automatically defines ATTSV */
+#endif /* DTILDE */ /* (see above) ... */
+#endif /* HPUX */
+
+/*
+ This is mainly for the benefit of ckufio.c (UNIX and OS/2 file support).
+ Systems that have an atomic rename() function, so we don't have to use
+ link() and unlink().
+*/
+#ifdef POSIX
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* POSIX */
+
+#ifdef OS2
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* OS2 */
+
+#ifdef SUNOS41
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* SUNOS41 */
+
+#ifdef SVR4
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* SVR4 */
+
+#ifdef AIXRS
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* AIXRS */
+
+#ifdef BSD44
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* BSD44 */
+
+#ifdef NORENAME /* Allow for compile-time override */
+#ifdef RENAME
+#undef RENAME
+#endif /* RENAME */
+#endif /* NORENAME */
+
+#ifdef STRATUS /* Stratus VOS */
+#ifndef RENAME
+#define RENAME
+#endif /* RENAME */
+#endif /* STRATUS */
+
+/* Line delimiter for text files */
+
+/*
+ If the system uses a single character for text file line delimitation,
+ define NLCHAR to the value of that character. For text files, that
+ character will be converted to CRLF upon output, and CRLF will be converted
+ to that character on input during text-mode (default) packet operations.
+*/
+#ifdef MAC /* Macintosh */
+#define NLCHAR 015
+#else
+#ifdef OSK /* OS-9/68K */
+#define NLCHAR 015
+#else /* All Unix-like systems */
+#define NLCHAR 012
+#endif /* OSK */
+#endif /* MAC */
+
+/*
+ At this point, if there's a system that uses ordinary CRLF line
+ delimitation AND the C compiler actually returns both the CR and
+ the LF when doing input from a file, then #undef NLCHAR.
+*/
+#ifdef OS2 /* OS/2 */
+#undef NLCHAR
+#endif /* OS2 */
+
+#ifdef GEMDOS /* Atari ST */
+#undef NLCHAR
+#endif /* GEMDOS */
+
+/*
+ VMS file formats are so complicated we need to do all the conversion
+ work in the CKVFIO module, so we tell the rest of C-Kermit not to fiddle
+ with the bytes.
+*/
+
+#ifdef vms
+#undef NLCHAR
+#endif /* vms */
+
+/* The device name of a job's controlling terminal */
+/* Special for VMS, same for all Unixes (?), not used by Macintosh */
+
+#ifdef BEOS
+#define CTTNAM dftty
+#else
+#ifdef vms
+#define CTTNAM "SYS$INPUT:" /* (4 Jan 2002) Was TT: */
+#else
+#ifdef datageneral
+#define CTTNAM "@output"
+#else
+#ifdef OSK
+extern char myttystr[];
+#define CTTNAM myttystr
+#else
+#ifdef OS2
+#define CTTNAM "con"
+#else
+#ifdef UNIX
+#define CTTNAM "/dev/tty"
+#else
+#ifdef GEMDOS
+#define CTTNAM "aux:"
+#else
+#ifdef STRATUS
+extern char myttystr[];
+#define CTTNAM myttystr
+#else /* Anyone else... */
+#define CTTNAM "stdout" /* This is a kludge used by Mac */
+#endif /* STRATUS */
+#endif /* GEMDOS */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* vms */
+#endif /* BEOS */
+
+#ifndef HAVECTTNAM
+#ifdef UNIX
+#define HAVECTTNAM
+#else
+#ifdef VMS
+#define HAVECTTNAM
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* HAVECTTNAM */
+
+#ifndef ZFCDAT /* zfcdat() function available? */
+#ifdef UNIX
+#define ZFCDAT
+#else
+#ifdef STRATUS
+#define ZFCDAT
+#else
+#ifdef GEMDOS
+#define ZFCDAT
+#else
+#ifdef AMIGA
+#define ZFCDAT
+#else
+#ifdef OS2
+#define ZFCDAT
+#else
+#ifdef datageneral
+#define ZFCDAT
+#else
+#ifdef VMS
+#define ZFCDAT
+#endif /* VMS */
+#endif /* datageneral */
+#endif /* OS2 */
+#endif /* AMIGA */
+#endif /* GEMDOS */
+#endif /* STRATUS */
+#endif /* UNIX */
+#endif /* ZFCDAT */
+
+#ifdef SUNS4S5
+#define tolower _tolower
+#define toupper _toupper
+#endif /* SUNS4S5 */
+
+/* Error number */
+
+#ifdef _CRAY
+#ifdef _CRAYCOM /* Cray Computer Corp. */
+extern int errno;
+#else /* _CRAYCOM */
+#include <errno.h> /* Cray Research UNICOS defines */
+ /* errno as a function. */
+#endif /* _CRAYCOM */ /* OK for UNICOS 6.1 and 7.0. */
+#else /* _CRAY */
+#ifdef STRATUS /* Stratus VOS */
+#include <errno.h>
+#else /* not STRATUS */
+#ifndef VMS
+#ifndef OS2
+#ifdef __GLIBC__
+/*
+ "glibc uses threads, kermit uses glibc; errno access is in Thread Local
+ Storage (TLS) from glibc-3.2.2. ...a thread specific errno is being run in
+ thread local storage relative to the %gs segment register, so some means to
+ revector gets/puts needs to be done." - Jeff Johnson, Red Hat, Feb 2003.
+*/
+#include <errno.h>
+#else
+/*
+ The following declaration would cause problems for VMS and OS/2, in which
+ errno is an "extern volatile int noshare"... NOTE: by now (2007) the
+ following is an anachronism and should be the execption rather than the
+ rule.
+*/
+extern int errno;
+#endif /* __GLIBC__ */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* _CRAY */
+
+#ifdef UNIX /* Catch-all so we can have */
+#ifndef ESRCH /* access to error mnemonics */
+#include <errno.h> /* in all modules - 2007/08/25 */
+#endif /* ESRCH */
+#endif /* UNIX */
+
+#ifdef pdp11 /* Try to make some space on PDP-11 */
+#ifndef NODIAL
+#define NODIAL
+#endif /* NODIAL */
+#ifndef NOCURSES
+#define NOCURSES
+#endif /* NOCURSES */
+#ifndef NOBIGBUF
+#define NOBIGBUF
+#endif /* NOBIGBUF */
+#endif /* pdp11 */
+
+#ifndef NOBIGBUF
+#ifndef BIGBUFOK /* Platforms with lots of memory */
+
+#ifdef QNX /* QNX */
+#ifndef QNX16 /* But not 16-bit versions */
+#define BIGBUFOK
+#endif /* QNX16 */
+#endif /* QNX */
+
+#ifdef BSD44
+#define BIGBUFOK
+#endif /* BSD44 */
+
+#ifdef STRATUS /* Stratus VOS */
+#define BIGBUFOK
+#endif /* STRATUS */
+
+#ifdef sparc /* SPARC processors */
+#define BIGBUFOK
+#endif /* sparc */
+
+#ifdef mips /* MIPS processors */
+#define BIGBUFOK
+#endif /* mips */
+
+#ifdef HPUX9 /* HP-UX 9.x */
+#define BIGBUFOK
+#endif /* HPUX9 */
+
+#ifdef HPUX10 /* HP-UX 10.0 PA-RISC */
+#define BIGBUFOK
+#endif /* HPUX10 */
+
+#ifdef NEXT /* NeXTSTEP */
+#ifdef mc68000 /* on NEXT platforms... */
+#define BIGBUFOK
+#endif /* mc68000 */
+#endif /* NEXT */
+
+#ifdef LINUX /* Linux in 1998 should be OK */
+#ifndef BIGBUFOK
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* LINUX */
+
+#ifdef OS2 /* 32-bit OS/2 2.x and above */
+#ifdef __32BIT__
+#define BIGBUFOK
+#endif /* __32BIT__ */
+#ifdef NT
+#define BIGBUFOK
+#endif /* NT */
+#endif /* OS2 */
+
+#ifdef Plan9 /* Plan 9 is OK */
+#define BIGBUFOK
+#endif /* Plan9 */
+
+#ifdef VMS /* Any VMS is OK */
+#ifndef BIGBUFOK
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* VMS */
+
+#ifdef __alpha /* DEC 64-bit Alpha, e.g. OSF/1 */
+#ifndef BIGBUFOK /* Might already be defined for VMS */
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* __alpha */
+
+#ifdef sgi /* SGI with IRIX 4.0 or later */
+#ifndef BIGBUFOK
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* sgi */
+
+#ifdef AIXRS /* AIX on RISC */
+#define BIGBUFOK
+#endif /* AIXRS */
+
+#ifdef CK_SCOV5 /* SCO OSR5 */
+#ifndef BIGBUFOK
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* CK_SCOV5 */
+
+#ifdef SOLARIS /* Solaris x86 */
+#ifndef BIGBUFOK
+#define BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* SOLARIS */
+
+#endif /* BIGBUFOK */
+#endif /* NOBIGBUF */
+
+#ifdef CK_SMALL
+#ifdef BIGBUFOK
+#undef BIGBUFOK
+#endif /* BIGBUFOK */
+#endif /* CK_SMALL */
+
+/* If "memory is no problem" then this improves performance */
+
+#ifdef DEBUG
+#ifdef BIGBUFOK
+#ifndef IFDEBUG
+#define IFDEBUG
+#endif /* IFDEBUG */
+#endif /* BIGBUFOK */
+#endif /* DEBUG */
+
+/* File System Defaults */
+
+#ifndef UIDBUFLEN /* Length of User ID */
+#ifdef OS2
+#define UIDBUFLEN 256
+#else /* OS2 */
+#ifdef BIGBUFOK
+#define UIDBUFLEN 256
+#else
+#define UIDBUFLEN 64
+#endif /* BIGBUFOK */
+#endif /* OS2 */
+#endif /* UIDBUFLEN */
+
+#ifdef UNIX
+#ifdef PROVX1
+#define MAXWLD 50
+#else
+#ifdef pdp11
+#define MAXWLD 50
+#else
+#ifdef BIGBUFOK
+#define MAXWLD 102400
+#else
+#define MAXWLD 1024
+#endif /* BIGBUFOK */
+#endif /* pdp11 */
+#endif /* PROVX1 */
+#else
+#ifdef VMS
+#define MAXWLD 102400 /* Maximum wildcard filenames */
+#else
+#ifdef datageneral
+#define MAXWLD 500
+#else
+#ifdef STRATUS
+#define MAXWLD 5000
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIX */
+
+#ifdef VMS
+#define DBLKSIZ 512
+#define DLRECL 512
+#else
+#define DBLKSIZ 0
+#define DLRECL 0
+#endif /* VMS */
+
+/* Communication device / network host name length */
+
+#ifdef BIGBUFOK
+#define TTNAMLEN 512
+#else
+#ifdef MAC
+#define TTNAMLEN 256
+#else
+#ifndef CK_SMALL
+#define TTNAMLEN 128
+#else
+#define TTNAMLEN 80
+#endif /* CK_SMALL */
+#endif /* MAC */
+#endif /* BIGBUFOK */
+
+/* Program return codes for DECUS C and UNIX (VMS uses UNIX codes) */
+
+#ifdef decus
+#define GOOD_EXIT IO_NORMAL
+#define BAD_EXIT IO_ERROR
+#else
+#define GOOD_EXIT 0
+#define BAD_EXIT 1
+#endif /* decus */
+
+/* Special hack for Fortune, which doesn't have <sys/file.h>... */
+
+#ifdef FT18
+#define FREAD 0x01
+#define FWRITE 0x10
+#endif /* FT18 */
+
+/* Special hack for OS-9/68k */
+#ifdef OSK
+#ifndef _UCC
+#define SIGALRM 30 /* May always cancel I/O */
+#endif /* _UCC */
+#define SIGARB 1234 /* Arbitrary for I/O */
+SIGTYP (*signal())();
+#endif /* OSK */
+
+#ifdef MINIX
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(c) (putc(c,stdout)!=EOF)&&fflush(stdout)
+#endif /* MINIX */
+
+#ifdef datageneral /* Data General AOS/VS */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(c) conoc(c)
+#endif /* datageneral */
+
+/* Escape/quote character used by the command parser */
+
+#define CMDQ '\\'
+
+/* Symbols for RS-232 modem signals */
+
+#define KM_FG 1 /* Frame ground */
+#define KM_TXD 2 /* Transmit */
+#define KM_RXD 3 /* Receive */
+#define KM_RTS 4 /* Request to Send */
+#define KM_CTS 5 /* Clear to Send */
+#define KM_DSR 6 /* Data Set Ready */
+#define KM_SG 7 /* Signal ground */
+#define KM_DCD 8 /* Carrier Detect */
+#define KM_DTR 20 /* Data Terminal Ready */
+#define KM_RI 22 /* Ring Indication */
+
+/* Bit mask values for modem signals */
+
+#define BM_CTS 0001 /* Clear to send (From DCE) */
+#define BM_DSR 0002 /* Dataset ready (From DCE) */
+#define BM_DCD 0004 /* Carrier (From DCE) */
+#define BM_RNG 0010 /* Ring Indicator (From DCE) */
+#define BM_DTR 0020 /* Data Terminal Ready (From DTE) */
+#define BM_RTS 0040 /* Request to Send (From DTE) */
+
+/* Codes for full duplex flow control */
+
+#define FLO_NONE 0 /* None */
+#define FLO_XONX 1 /* Xon/Xoff (soft) */
+#define FLO_RTSC 2 /* RTS/CTS (hard) */
+#define FLO_DTRC 3 /* DTR/CD (hard) */
+#define FLO_ETXA 4 /* ETX/ACK (soft) */
+#define FLO_STRG 5 /* String-based (soft) */
+#define FLO_DIAL 6 /* DIALing kludge */
+#define FLO_DIAX 7 /* Cancel dialing kludge */
+#define FLO_DTRT 8 /* DTR/CTS (hard) */
+#define FLO_KEEP 9 /* Keep, i.e. don't touch or change */
+#define FLO_AUTO 10 /* Figure out automatically */
+
+/* Types of connections */
+
+#define CXT_REMOTE 0 /* Remote mode - no connection */
+#define CXT_DIRECT 1 /* Direct serial connection */
+#define CXT_MODEM 2 /* Modem dialout */
+#define CXT_TCPIP 3 /* TCP/IP - Telnet, Rlogin, etc */
+#define CXT_X25 4 /* X.25 peer-to-peer */
+#define CXT_DECNET 5 /* DECnet (CTERM, etc) */
+#define CXT_LAT 6 /* LAT */
+#define CXT_NETBIOS 7 /* NETBIOS */
+#define CXT_NPIPE 8 /* Named Pipe */
+#define CXT_PIPE 9 /* Pipe, Command, PTY, DLL, etc */
+#define CXT_SSH 10 /* SSH */
+#define CXT_MAX 10 /* Highest connection type */
+
+/* Autodownload Detection Options */
+
+#define ADL_PACK 0 /* Auto-Download detect packet */
+#define ADL_STR 1 /* Auto-Download detect string */
+
+/* And finally... */
+
+#ifdef COMMENT /* Make sure this is NOT defined! */
+#undef COMMENT
+#endif /* COMMENT */
+
+/* zstr zattr filinfo were here (moved to top for DECC 5 Jun 2000) */
+
+#ifndef ZFNQFP /* Versions that have zfnqfp() */
+#ifdef UNIX
+#define ZFNQFP
+#else
+#ifdef VMS
+#define ZFNQFP
+#else
+#ifdef OS2
+#define ZFNQFP
+#else
+#ifdef datageneral
+#define ZFNQFP
+#else
+#ifdef STRATUS
+#define ZFNQFP
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* UNIX */
+struct zfnfp {
+ int len; /* Length of full pathname */
+ char * fpath; /* Pointer to full pathname */
+ char * fname; /* Pointer to name part */
+};
+#endif /* ZFNQFP */
+
+/* Systems that support FILE TYPE LABELED */
+
+#ifdef VMS
+#define CK_LABELED
+#else
+#ifdef OS2
+#ifdef __32BIT__
+#ifndef NT
+#define CK_LABELED
+#endif /* NT */
+#endif /* __32BIT__ */
+#endif /* OS2 */
+#endif /* VMS */
+
+/* LABELED FILE options bitmask */
+
+#ifdef VMS /* For VMS */
+#define LBL_NAM 1 /* Ignore incoming name if set */
+#define LBL_PTH 2 /* Use complete path if set */
+#define LBL_ACL 4 /* Preserve ACLs if set */
+#define LBL_BCK 8 /* Preserve backup date if set */
+#define LBL_OWN 16 /* Preserve ownership if set */
+
+#else
+
+#ifdef OS2 /* Ditto for OS/2 */
+#define LBL_NOR 0x0000 /* Normal file */
+#define LBL_ARC 0x0020 /* Archive */
+#define LBL_DIR 0x0010 /* Directory */
+#define LBL_HID 0x0002 /* Hidden file */
+#define LBL_RO 0x0001 /* Read only file */
+#define LBL_SYS 0x0004 /* System file */
+#define LBL_EXT 0x0040 /* Extended */
+#endif /* OS2 */
+#endif /* VMS */
+
+/*
+ Data types. First the header file for data types so we can pick up the
+ types used for pids, uids, and gids. Override this section by putting
+ -DCKTYP_H=xxx on the command line to specify the header file where your
+ system defines these types.
+*/
+#ifndef STRATUS
+#ifdef __ALPHA
+#ifdef MULTINET
+#define CK_TGV_AXP
+#endif /* MULTINET */
+#endif /* __ALPHA */
+
+#ifdef CK_TGV_AXP /* Alpha, VMS, MultiNet */
+/*
+ Starting in DECC 5.0, <stdlib.h> no longer includes <types.h>.
+ But before that an elaborate workaround is required, which results in
+ including <types.h> sometimes but not others, evidently depending on whether
+ <types.h> protects itself against multiple inclusion, which in turn probably
+ differentiates between DECC <types.h> and TGV <types.h>. Unfortunately I
+ don't remember the details. (fdc, 25 Oct 96)
+*/
+#ifdef COMMENT
+/*
+ Previously the test here was for DEC version prior to 4.0, but since the
+ test involved an "#if" statement, it was not portable and broke some non-VMS
+ builds. In any case, condition was never satisfied, so the result of
+ commenting this section out is the same as the previous "#if" condition.
+*/
+#ifndef __TYPES_LOADED
+#define __TYPES_LOADED /* Work around bug in .h files */
+#endif /* __TYPES_LOADED */
+#endif /* COMMENT */
+#include <sys/types.h>
+#ifdef IF_DOT_H
+#ifndef MULTINET
+#include <if.h> /* Needed to put up u_int typedef */
+#endif /* MULTINET */
+#else /* IF_DOT_H */
+#ifdef NEEDUINT
+typedef unsigned int u_int;
+#endif /* NEEDUINT */
+#endif /* IF_DOT_H */
+#else /* !CK_TGV_AXP */
+#ifdef OSK /* OS-9 */
+#include <types.h>
+#else /* General case, not OS-9 */
+#ifndef CKTYP_H
+#ifndef VMS
+#ifndef MAC
+#ifndef AMIGA
+#define CKTYP_H <sys/types.h>
+#endif /* AMIGA */
+#endif /* MAC */
+#endif /* VMS */
+#endif /* CKTYP_H */
+
+#ifdef GEMDOS
+#undef CKTYP_H
+#include <types.h>
+#endif /* GEMDOS */
+
+#ifdef OS2
+#undef CKTYP_H
+#include <sys/types.h>
+#endif /* OS2 */
+
+#ifdef CKTYP_H /* Include it. */
+#ifdef COHERENT /* Except for COHERENT */
+#include <unistd.h>
+#include <sys/types.h>
+#else
+#ifdef datageneral /* AOS/VS */
+#include <sys/types.h>
+#else /* All others */
+#ifdef __bsdi__ /* BSDI */
+#ifdef POSIX
+#undef _POSIX_SOURCE
+#endif /* POSIX */
+#endif /* __bsdi__ */
+#include CKTYP_H
+#ifdef __bsdi__
+#ifdef POSIX
+#define _POSIX_SOURCE
+#endif /* POSIX */
+#endif /* __bsdi__ */
+#endif /* datageneral */
+#endif /* COHERENT */
+#endif /* CKTYP_H */
+
+#endif /* OSK */
+#endif /* CK_TGV_AXP */
+#endif /* STRATUS */ /* End of types.h section */
+
+/*
+ File lengths and offsets. This section is expected to grow as we
+ support long files on 32-bit platforms. We want this data type to be
+ signed because so many functions return either a file size or a negative
+ value to indicate an error.
+*/
+#ifndef CK_OFF_T
+#ifdef OS2
+#ifdef NT
+#define CK_OFF_T __int64
+#else
+#define CK_OFF_T long
+#endif /* NT */
+#endif /* OS2 */
+#endif /* CK_OFF_T */
+
+/* FreeBSD and OpenBSD set off_t to the appropriate size unconditionally */
+
+#ifndef CK_OFF_T
+#ifdef __FreeBSD__
+#define CK_OFF_T off_t
+#else
+#ifdef __OpenBSD__
+#define CK_OFF_T off_t
+#endif /* __OpenBSD__ */
+#endif /* __FreeBSD__ */
+#endif /* CK_OFF_T */
+
+/* 32-bit platforms that support long files thru "transitional interface" */
+/* These include Linux, Solaris, NetBSD... */
+
+#ifdef AIXRS
+#ifdef _LARGE_FILES
+#ifndef CK_OFF_T
+#define CK_OFF_T off_t
+#endif /* CK_OFF_T */
+#endif /* _LARGE_FILES */
+#endif /* AIXRS */
+
+#ifdef _LARGEFILE_SOURCE
+#ifndef CK_OFF_T
+#define CK_OFF_T off_t
+#endif /* CK_OFF_T */
+#ifdef IRIX
+#define CKFSEEK(a,b,c) fseek64(a,b,c)
+#define CKFTELL(a) ftell64(a)
+#else /* IRIX */
+#define CKFSEEK(a,b,c) fseeko(a,b,c)
+#define CKFTELL(a) ftello(a)
+#endif /* IRIX */
+#else /* Not _LARGEFILE_SOURCE */
+#define CKFSEEK(a,b,c) fseek(a,b,c)
+#define CKFTELL(a) ftell(a)
+/* See below the next section for the catch-all case */
+#endif /* _LARGEFILE_SOURCE */
+
+/* 32-bit or 64-bit platforms */
+
+/* CK_64BIT is a compile-time symbol indicating a true 64-bit build */
+/* meaning that longs and pointers are 64 bits */
+
+#ifndef VMS /* VMS Alpha and IA64 are 32-bit! */
+#ifndef CK_64BIT
+#ifdef _LP64 /* Solaris */
+#define CK_64BIT
+#else
+#ifdef __LP64__ /* MacOS X 10.4 (or _LP64,__ppc64__) */
+#define CK_64BIT
+#else
+#ifdef __arch64__ /* gcc alpha, sparc */
+#define CK_64BIT
+#else
+#ifdef __alpha /* Alpha decc (or __ALPHA) */
+#define CK_64BIT
+#else
+#ifdef __amd64 /* AMD x86_64 (or __x86_64) */
+#define CK_64BIT
+#else
+#ifdef __ia64 /* Intel IA64 */
+#ifndef HPUX
+#define CK_64BIT
+#endif /* HPUX */
+#endif /* __ia64 */
+#endif /* __amd64 */
+#endif /* __alpha */
+#endif /* __arch64__ */
+#endif /* __LP64__ */
+#endif /* _LP64 */
+#endif /* CK_64BIT */
+#endif /* VMS */
+
+#ifndef CK_OFF_T
+#ifdef CK_64BIT
+#define CK_OFF_T off_t /* This has to be signed */
+#else /* CK_64BIT */
+#define CK_OFF_T long /* Signed */
+#endif /* CK_64BIT */
+#endif /* CK_OFF_T */
+
+#ifndef TLOG
+#define tlog(a,b,c,d)
+#else
+#ifndef CKCMAI
+/* Debugging included. Declare debug log flag in main program only. */
+extern int tralog, tlogfmt;
+#endif /* CKCMAI */
+_PROTOTYP(VOID dotlog,(int, char *, char *, CK_OFF_T));
+#define tlog(a,b,c,d) if (tralog && tlogfmt) dotlog(a,b,c,(CK_OFF_T)d)
+_PROTOTYP(VOID doxlog,(int, char *, CK_OFF_T, int, int, char *));
+#endif /* TLOG */
+
+#ifndef DEBUG
+/* Compile all the debug() statements away. Saves a lot of space and time. */
+#define debug(a,b,c,d)
+#define ckhexdump(a,b,c)
+/* Now define the debug() macro. */
+#else /* DEBUG */
+_PROTOTYP(int dodebug,(int,char *,char *,CK_OFF_T));
+_PROTOTYP(int dohexdump,(CHAR *,CHAR *,int));
+#ifdef IFDEBUG
+/* Use this form to avoid function calls: */
+#ifdef COMMENT
+#define debug(a,b,c,d) if (deblog) dodebug(a,b,(char *)(c),(CK_OFF_T)(d))
+#define ckhexdump(a,b,c) if (deblog) dohexdump((CHAR *)(a),(CHAR *)(b),c)
+#else
+#ifdef CK_ANSIC
+#define debug(a,b,c,d) \
+((void)(deblog?dodebug(a,b,(char *)(c),(CK_OFF_T)(d)):0))
+#define ckhexdump(a,b,c) \
+((void)(deblog?dohexdump((CHAR *)(a),(CHAR *)(b),c):0))
+#else
+#define debug(a,b,c,d) (deblog?dodebug(a,b,(char *)(c),(CK_OFF_T)(d)):0)
+#define ckhexdump(a,b,c) (deblog?dohexdump((CHAR *)(a),(CHAR *)(b),c):0)
+#endif /* CK_ANSIC */
+#endif /* COMMENT */
+#else /* IFDEBUG */
+/* Use this form to save space: */
+#define debug(a,b,c,d) dodebug(a,b,(char *)(c),(CK_OFF_T)(d))
+#define ckhexdump(a,b,c) dohexdump((CHAR *)(a),(CHAR *)(b),c)
+#endif /* IFDEBUG */
+#endif /* DEBUG */
+
+
+/* Structure definitions for Kermit file attributes */
+/* All strings come as pointer and length combinations */
+/* Empty string (or for numeric variables, -1) = unused attribute. */
+
+struct zstr { /* string format */
+ int len; /* length */
+ char *val; /* value */
+};
+
+struct zattr { /* Kermit File Attribute structure */
+ CK_OFF_T lengthk; /* (!) file length in K */
+ struct zstr type; /* (") file type (text or binary) */
+ struct zstr date; /* (#) file creation date yyyymmdd[ hh:mm[:ss]] */
+ struct zstr creator; /* ($) file creator id */
+ struct zstr account; /* (%) file account */
+ struct zstr area; /* (&) area (e.g. directory) for file */
+ struct zstr password; /* (') password for area */
+ long blksize; /* (() file blocksize */
+ struct zstr xaccess; /* ()) file access: new, supersede, append, warn */
+ struct zstr encoding; /* (*) encoding (transfer syntax) */
+ struct zstr disp; /* (+) disposition (mail, message, print, etc) */
+ struct zstr lprotect; /* (,) protection (local syntax) */
+ struct zstr gprotect; /* (-) protection (generic syntax) */
+ struct zstr systemid; /* (.) ID for system of origin */
+ struct zstr recfm; /* (/) record format */
+ struct zstr sysparam; /* (0) system-dependent parameter string */
+ CK_OFF_T length; /* (1) exact length on system of origin */
+ struct zstr charset; /* (2) transfer syntax character set */
+#ifdef OS2
+ struct zstr longname; /* OS/2 longname if applicable */
+#endif /* OS2 */
+ struct zstr reply; /* This goes last, used for attribute reply */
+};
+
+/* Kermit file information structure */
+
+struct filinfo {
+ int bs; /* Blocksize */
+ int cs; /* Character set */
+ long rl; /* Record length */
+ int org; /* Organization */
+ int fmt; /* Record format */
+ int cc; /* Carriage control */
+ int typ; /* Type (text/binary) */
+ int dsp; /* Disposition */
+ char *os_specific; /* OS-specific attributes */
+#ifdef OS2
+ unsigned long int lblopts; /* LABELED FILE options bitmask */
+#else
+ int lblopts;
+#endif /* OS2 */
+};
+
+
+/*
+ Data type for pids. If your system uses a different type, put something
+ like -DPID_T=pid_t on command line, or override here.
+*/
+#ifndef PID_T
+#define PID_T int
+#endif /* PID_T */
+/*
+ Data types for uids and gids. Same deal as for pids.
+ Wouldn't be nice if there was a preprocessor test to find out if a
+ typedef existed?
+*/
+#ifdef VMS
+/* Not used in VMS so who cares */
+#define UID_T int
+#define GID_T int
+#endif /* VMS */
+
+#ifdef POSIX
+/* Or would it be better (or worse?) to use _POSIX_SOURCE here? */
+#ifndef UID_T
+#define UID_T uid_t
+#endif /* UID_T */
+#ifndef GID_T
+#define GID_T gid_t
+#endif /* GID_T */
+#else /* Not POSIX */
+#ifdef SVR4
+/* SVR4 and later have uid_t and gid_t. */
+/* SVR3 and earlier use int, or unsigned short, or.... */
+#ifndef UID_T
+#define UID_T uid_t
+#endif /* UID_T */
+#ifndef GID_T
+#define GID_T gid_t
+#endif /* GID_T */
+#else /* Not SVR4 */
+#ifdef BSD43
+#ifndef UID_T
+#define UID_T uid_t
+#endif /* UID_T */
+#ifndef GID_T
+#define GID_T gid_t
+#endif /* GID_T */
+#else /* Not BSD43 */
+/* Default these to int for older UNIX versions */
+#ifndef UID_T
+#define UID_T int
+#endif /* UID_T */
+#ifndef GID_T
+#define GID_T int
+#endif /* GID_T */
+#endif /* BSD43 */
+#endif /* SVR4 */
+#endif /* POSIX */
+
+/*
+ getpwuid() arg type, which is not necessarily the same as UID_T,
+ e.g. in SCO UNIX SVR3, it's int.
+*/
+#ifndef PWID_T
+#define PWID_T UID_T
+#endif /* PWID_T */
+
+#ifdef CK_REDIR
+#ifdef NEXT
+#define MACHWAIT
+#else
+#ifdef MACH
+#define MACHWAIT
+#endif /* MACH */
+#endif /* NEXT */
+
+#ifdef MACHWAIT /* WAIT_T argument for wait() */
+#include <sys/wait.h>
+#define CK_WAIT_H
+typedef union wait WAIT_T;
+#else
+#ifdef POSIX
+#ifdef OSF
+/* OSF wait.h defines BSD wait if _BSD is defined so hide _BSD from wait.h */
+#ifdef _BSD
+#define CK_OSF_BSD
+#undef _BSD
+#endif /* _BSD */
+#endif /* OSF */
+#include <sys/wait.h>
+#define CK_WAIT_H
+#ifndef WAIT_T
+typedef int WAIT_T;
+#endif /* WAIT_T */
+#ifdef CK_OSF_BSD /* OSF/1: Restore _BSD definition */
+#define _BSD
+#undef CK_OSF_BSD
+#endif /* CK_OSF_BSD */
+#else /* !POSIX */
+typedef int WAIT_T;
+#endif /* POSIX */
+#endif /* MACHWAIT */
+#else
+typedef int WAIT_T;
+#endif /* CK_REDIR */
+
+/* Assorted other blah_t's handled here... */
+
+#ifndef SIZE_T
+#define SIZE_T size_t
+#endif /* SIZE_T */
+
+/* Forward declarations of system-dependent functions callable from all */
+/* C-Kermit modules. */
+
+/* File-related functions from system-dependent file i/o module */
+
+#ifndef CKVFIO_C
+/* For some reason, this does not agree with DEC C */
+_PROTOTYP( int zkself, (void) );
+#endif /* CKVFIO_C */
+_PROTOTYP( int zopeni, (int, char *) );
+_PROTOTYP( int zopeno, (int, char *, struct zattr *, struct filinfo *) );
+_PROTOTYP( int zclose, (int) );
+#ifndef MAC
+_PROTOTYP( int zchin, (int, int *) );
+#endif /* MAC */
+_PROTOTYP( int zxin, (int, char *, int) );
+_PROTOTYP( int zsinl, (int, char *, int) );
+_PROTOTYP( int zinfill, (void) );
+_PROTOTYP( int zsout, (int, char*) );
+_PROTOTYP( int zsoutl, (int, char*) );
+_PROTOTYP( int zsoutx, (int, char*, int) );
+_PROTOTYP( int zchout, (int, char) );
+_PROTOTYP( int zoutdump, (void) );
+_PROTOTYP( int zsyscmd, (char *) );
+_PROTOTYP( int zshcmd, (char *) );
+#ifdef UNIX
+_PROTOTYP( int zsetfil, (int, int) );
+_PROTOTYP( int zchkpid, (unsigned long) );
+#endif /* UNIX */
+#ifdef CKEXEC
+_PROTOTYP( VOID z_exec, (char *, char **, int) );
+#endif /* CKEXEC */
+_PROTOTYP( int chkfn, (int) );
+_PROTOTYP( CK_OFF_T zchki, (char *) );
+#ifdef VMSORUNIX
+_PROTOTYP( CK_OFF_T zgetfs, (char *) );
+#else
+#ifdef OS2
+_PROTOTYP( CK_OFF_T zgetfs, (char *) );
+#else
+#define zgetfs(a) zchki(a)
+#endif /* OS2 */
+#endif /* VMSORUNIX */
+_PROTOTYP( int iswild, (char *) );
+_PROTOTYP( int isdir, (char *) );
+_PROTOTYP( int zchko, (char *) );
+_PROTOTYP( int zdelet, (char *) );
+_PROTOTYP( VOID zrtol, (char *,char *) );
+_PROTOTYP( VOID zltor, (char *,char *) );
+_PROTOTYP( VOID zstrip, (char *,char **) );
+#ifdef VMS
+_PROTOTYP( char * zrelname, (char *, char *) );
+#endif /* VMS */
+_PROTOTYP( int zchdir, (char *) );
+_PROTOTYP( char * zhome, (void) );
+_PROTOTYP( char * zgtdir, (void) );
+_PROTOTYP( int zxcmd, (int, char *) );
+#ifndef MAC
+_PROTOTYP( int zclosf, (int) );
+#endif /* MAC */
+#ifdef NZXPAND
+_PROTOTYP( int nzxpand, (char *, int) );
+#else /* NZXPAND */
+_PROTOTYP( int zxpand, (char *) );
+#endif /* NZXPAND */
+_PROTOTYP( int znext, (char *) );
+#ifdef ZXREWIND
+_PROTOTYP( int zxrewind, (void) );
+#endif /* ZXREWIND */
+_PROTOTYP( int zchkspa, (char *, CK_OFF_T) );
+_PROTOTYP( VOID znewn, (char *, char **) );
+_PROTOTYP( int zrename, (char *, char *) );
+_PROTOTYP( int zcopy, (char *, char *) );
+_PROTOTYP( int zsattr, (struct zattr *) );
+_PROTOTYP( int zfree, (char *) );
+_PROTOTYP( char * zfcdat, (char *) );
+_PROTOTYP( int zstime, (char *, struct zattr *, int) );
+#ifdef CK_PERMS
+_PROTOTYP( char * zgperm, (char *) );
+_PROTOTYP( char * ziperm, (char *) );
+#endif /* CK_PERMS */
+_PROTOTYP( int zmail, (char *, char *) );
+_PROTOTYP( int zprint, (char *, char *) );
+_PROTOTYP( char * tilde_expand, (char *) );
+_PROTOTYP( int zmkdir, (char *) ) ;
+_PROTOTYP( int zfseek, (CK_OFF_T) ) ;
+#ifdef ZFNQFP
+_PROTOTYP( struct zfnfp * zfnqfp, (char *, int, char * ) ) ;
+#else
+#define zfnqfp(a,b,c) ckstrncpy(c,a,b)
+#endif /* ZFNQFP */
+_PROTOTYP( int zvuser, (char *) ) ;
+_PROTOTYP( int zvpass, (char *) ) ;
+_PROTOTYP( VOID zvlogout, (void) ) ;
+#ifdef OS2
+_PROTOTYP( int os2setlongname, ( char * fn, char * ln ) ) ;
+_PROTOTYP( int os2getlongname, ( char * fn, char ** ln ) ) ;
+_PROTOTYP( int os2rexx, ( char *, char *, int ) ) ;
+_PROTOTYP( int os2rexxfile, ( char *, char *, char *, int) ) ;
+_PROTOTYP( int os2geteas, (char *) ) ;
+_PROTOTYP( int os2seteas, (char *) ) ;
+_PROTOTYP( char * get_os2_vers, (void) ) ;
+_PROTOTYP( int do_label_send, (char *) ) ;
+_PROTOTYP( int do_label_recv, (void) ) ;
+#ifdef OS2MOUSE
+_PROTOTYP( unsigned long os2_mouseon, (void) );
+_PROTOTYP( unsigned long os2_mousehide, (void) );
+_PROTOTYP( unsigned long os2_mouseshow, (void) );
+_PROTOTYP( unsigned long os2_mouseoff, (void) );
+_PROTOTYP( void os2_mouseevt, (void *) );
+_PROTOTYP( int mousebuttoncount, (void));
+#endif /* OS2MOUSE */
+#endif /* OS2 */
+
+/* Functions from system-dependent terminal i/o module */
+
+_PROTOTYP( int ttopen, (char *, int *, int, int) ); /* tty functions */
+#ifndef MAC
+_PROTOTYP( int ttclos, (int) );
+#endif /* MAC */
+_PROTOTYP( int tthang, (void) );
+_PROTOTYP( int ttres, (void) );
+_PROTOTYP( int ttpkt, (long, int, int) );
+#ifndef MAC
+_PROTOTYP( int ttvt, (long, int) );
+#endif /* MAC */
+_PROTOTYP( int ttsspd, (int) );
+_PROTOTYP( long ttgspd, (void) );
+_PROTOTYP( int ttflui, (void) );
+_PROTOTYP( int ttfluo, (void) );
+_PROTOTYP( int ttpushback, (CHAR *, int) );
+_PROTOTYP( int ttpeek, (void) );
+_PROTOTYP( int ttgwsiz, (void) );
+_PROTOTYP( int ttchk, (void) );
+_PROTOTYP( int ttxin, (int, CHAR *) );
+_PROTOTYP( int ttxout, (CHAR *, int) );
+_PROTOTYP( int ttol, (CHAR *, int) );
+_PROTOTYP( int ttoc, (char) );
+_PROTOTYP( int ttinc, (int) );
+_PROTOTYP( int ttscarr, (int) );
+_PROTOTYP( int ttgmdm, (void) );
+_PROTOTYP( int ttsndb, (void) );
+_PROTOTYP( int ttsndlb, (void) );
+#ifdef UNIX
+_PROTOTYP( char * ttglckdir, (void) );
+#endif /* UNIX */
+#ifdef PARSENSE
+#ifdef UNIX
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) );
+#else
+#ifdef VMS
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) );
+#else
+#ifdef STRATUS
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) );
+#else
+#ifdef OS2
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) );
+#else
+#ifdef OSK
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) );
+#else
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR) );
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* UNIX */
+#else /* ! PARSENSE */
+_PROTOTYP( int ttinl, (CHAR *, int, int, CHAR) );
+#endif /* PARSENSE */
+
+/* XYZMODEM support */
+
+/*
+ CK_XYZ enables the various commands and data structures.
+ XYZ_INTERNAL means these protocols are built-in; if not defined,
+ then they are external. XYZ_DLL is used to indicate a separate
+ loadable library containing the XYZmodem protocol code.
+*/
+#ifdef pdp11 /* No room for this in PDP-11 */
+#define NOCKXYZ
+#endif /* pdp11 */
+
+#ifndef NOCKXYZ /* Alternative protocols */
+#ifndef CK_XYZ
+#ifdef UNIX
+#define CK_XYZ
+#else
+#ifdef OS2
+#define CK_XYZ
+#ifndef NOXYZDLL
+#define XYZ_INTERNAL /* Internal and DLL */
+#define XYZ_DLL
+#endif /* NOXYZDLL */
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* CK_XYZ */
+#endif /* NOCKXYZ */
+
+#ifdef XYZ_INTERNAL /* This ensures that XYZ_INTERNAL */
+#ifndef CK_XYZ /* is defined only if CK_XYZ is too */
+#undef XYZ_INTERNAL
+#endif /* CK_XYZ */
+#endif /* XYZ_INTERNAL */
+#ifdef XYZ_DLL /* This ensures XYZ_DLL is defined */
+#ifndef XYZ_INTERNAL /* only if XYZ_INTERNAL is too */
+#undef XYZ_DLL
+#endif /* XYZ_INTERNAL */
+#endif /* XYZ_DLL */
+
+/* Console functions */
+
+_PROTOTYP( int congm, (void) );
+#ifdef COMMENT
+_PROTOTYP( VOID conint, (SIGTYP (*)(int, int), SIGTYP (*)(int, int)) );
+#else
+_PROTOTYP( VOID conint, (SIGTYP (*)(int), SIGTYP (*)(int)) );
+#endif /* COMMENT */
+_PROTOTYP( VOID connoi, (void) );
+_PROTOTYP( int concb, (char) );
+#ifdef CONGSPD
+_PROTOTYP( long congspd, (void) );
+#endif /* CONGSPD */
+_PROTOTYP( int conbin, (char) );
+_PROTOTYP( int conres, (void) );
+_PROTOTYP( int conoc, (char) );
+_PROTOTYP( int conxo, (int, char *) );
+_PROTOTYP( int conol, (char *) );
+_PROTOTYP( int conola, (char *[]) );
+_PROTOTYP( int conoll, (char *) );
+_PROTOTYP( int conchk, (void) );
+_PROTOTYP( int coninc, (int) );
+_PROTOTYP( char * conkbg, (void) );
+_PROTOTYP( int psuspend, (int) );
+_PROTOTYP( int priv_ini, (void) );
+_PROTOTYP( int priv_on, (void) );
+_PROTOTYP( int priv_off, (void) );
+_PROTOTYP( int priv_can, (void) );
+_PROTOTYP( int priv_chk, (void) );
+_PROTOTYP( int priv_opn, (char *, int) );
+
+_PROTOTYP( int sysinit, (void) ); /* Misc Kermit functions */
+_PROTOTYP( int syscleanup, (void) );
+_PROTOTYP( int msleep, (int) );
+_PROTOTYP( VOID rtimer, (void) );
+_PROTOTYP( int gtimer, (void) );
+#ifdef GFTIMER
+_PROTOTYP( VOID rftimer, (void) );
+_PROTOTYP( CKFLOAT gftimer, (void) );
+#endif /* GFTIMER */
+_PROTOTYP( VOID ttimoff, (void) );
+_PROTOTYP( VOID ztime, (char **) );
+_PROTOTYP( int parchk, (CHAR *, CHAR, int) );
+_PROTOTYP( VOID doexit, (int, int) );
+_PROTOTYP( int askmore, (void) );
+_PROTOTYP( VOID fatal, (char *) );
+_PROTOTYP( VOID fatal2, (char *, char *) );
+#ifdef VMS
+_PROTOTYP( int ck_cancio, (void) );
+#endif /* VMS */
+
+/* Key mapping support */
+
+#ifdef NOICP
+#ifndef NOSETKEY
+#define NOSETKEY
+#endif /* NOSETKEY */
+#endif /* NOICP */
+
+#ifdef MAC
+#ifndef NOSETKEY
+#define NOSETKEY
+#endif /* NOSETKEY */
+#endif /* MAC */
+
+_PROTOTYP( int congks, (int) );
+#ifdef OS2
+/* OS2 requires these definitions even if SET KEY is not being supported */
+#define KMSIZE 8916
+typedef ULONG KEY;
+typedef CHAR *MACRO;
+extern int wideresult;
+#else /* Not OS2 */
+#ifndef NOSETKEY
+/*
+ Catch-all for systems where we don't know how to read keyboard scan
+ codes > 255.
+*/
+#define KMSIZE 256
+/* Note: CHAR (i.e. unsigned char) is very important here. */
+typedef CHAR KEY;
+typedef CHAR * MACRO;
+#define congks coninc
+#endif /* NOSETKEY */
+#endif /* OS2 */
+
+#ifndef OS2
+#ifndef NOKVERBS /* No \Kverbs unless... */
+#define NOKVERBS
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+#ifndef NOKVERBS
+#ifdef OS2
+/*
+ Note: this value chosen to be bigger than PC BIOS key modifier bits,
+ but still fit in 16 bits without affecting sign.
+
+ As of K95 1.1.5, this no longer fits in 16 bits, good thing we are 32 bit.
+*/
+#define F_MACRO 0x2000 /* Bit indicating a macro indice */
+#define IS_MACRO(x) (x & F_MACRO)
+#define F_KVERB 0x4000 /* Bit indicating a keyboard verb */
+#define IS_KVERB(x) (x & F_KVERB) /* Test this bit */
+#endif /* OS2 */
+#endif /* NOKVERBS */
+
+#define F_ESC 0x8000 /* Bit indicating ESC char combination */
+#define IS_ESC(x) (x & F_ESC)
+#define F_CSI 0x10000 /* Bit indicating CSI char combination */
+#define IS_CSI(x) (x & F_CSI)
+
+#ifdef NOSPL /* This might be overkill.. */
+#ifndef NOKVERBS /* Not all \Kverbs require */
+#define NOKVERBS /* the script programming language. */
+#endif /* NOKVERBS */
+#ifndef NOTAKEARGS
+#define NOTAKEARGS
+#endif /* NOTAKEARGS */
+#endif /* NOSPL */
+
+/*
+ Function prototypes for system and library functions.
+*/
+#ifdef _POSIX_SOURCE
+#ifndef VMS
+#ifndef MAC
+#define CK_ANSILIBS
+#endif /* MAC */
+#endif /* VMS */
+#endif /* _POSIX_SOURCE */
+
+#ifdef NEXT
+#define CK_ANSILIBS
+#endif /* NEXT */
+
+#ifdef SVR4
+#define CK_ANSILIBS
+#endif /* SVR4 */
+
+#ifdef STRATUS /* Stratus VOS uses ANSI libraries */
+#define CK_ANSILIBS
+#endif /* STRATUS */
+
+#ifdef OS2
+#define CK_ANSILIBS
+#ifndef NOCURSES
+#define MYCURSES
+#endif /* NOCURSES */
+#define CK_RTSCTS
+#ifdef __IBMC__
+#define S_IFMT 0xF000
+#define timezone _timezone
+#endif /* __IBMC__ */
+#include <fcntl.h>
+#include <io.h>
+#ifdef __EMX__
+#ifndef __32BIT__
+#define __32BIT__
+#endif /* __32BIT__ */
+#include <sys/timeb.h>
+#else /* __EMX__ */
+#include <direct.h>
+#undef SIGALRM
+#ifndef SIGUSR1
+#define SIGUSR1 7
+#endif /* SIGUSR1 */
+#define SIGALRM SIGUSR1
+_PROTOTYP( unsigned alarm, (unsigned) );
+_PROTOTYP( unsigned sleep, (unsigned) );
+#endif /* __EMX__ */
+_PROTOTYP( unsigned long zdskspace, (int) );
+_PROTOTYP( int zchdsk, (int) );
+_PROTOTYP( int conincraw, (int) );
+_PROTOTYP( int ttiscom, (int f) );
+_PROTOTYP( int IsFileNameValid, (char *) );
+_PROTOTYP( void ChangeNameForFAT, (char *) );
+_PROTOTYP( char *GetLoadPath, (void) );
+#endif /* OS2 */
+
+/* Fullscreen file transfer display items... */
+
+#ifndef NOCURSES
+#ifdef CK_NCURSES /* CK_NCURSES implies CK_CURSES */
+#ifndef CK_CURSES
+#define CK_CURSES
+#endif /* CK_CURSES */
+#endif /* CK_NCURSES */
+
+#ifdef MYCURSES /* MYCURSES implies CK_CURSES */
+#ifndef CK_CURSES
+#define CK_CURSES
+#endif /* CK_CURSES */
+#endif /* MYCURSES */
+#endif /* NOCURSES */
+
+#ifdef NOCURSES
+#ifdef CK_CURSES
+#undef CK_CURSES
+#endif /* CK_CURSES */
+#ifndef NODISPLAY
+#define NODISPLAY
+#endif /* NODISPLAY */
+#endif /* NOCURSES */
+
+#ifdef CK_CURSES
+/*
+ The CK_WREFRESH symbol is defined if the curses library provides
+ clearok() and wrefresh() functions, which are used in repainting
+ the screen.
+*/
+#ifdef NOWREFRESH /* Override CK_WREFRESH */
+
+#ifdef CK_WREFRESH /* If this is defined, */
+#undef CK_WREFRESH /* undefine it. */
+#endif /* CK_WREFRESH */
+
+#else /* !NOWREFRESH */ /* No override... */
+
+#ifndef CK_WREFRESH /* If CK_WREFRESH not defined */
+/*
+ Automatically define it for systems known to have it ...
+*/
+#ifdef VMS /* DEC (Open)VMS has it */
+#define CK_WREFRESH
+#else
+#ifdef ultrix /* DEC ULTRIX has it */
+#else
+#ifdef SVR3 /* System V has it */
+#define CK_WREFRESH
+#else
+#ifdef BSD44 /* 4.4 BSD has it */
+#define CK_WREFRESH
+#else
+#ifdef NEXT /* Define it for NeXTSTEP */
+#define CK_WREFRESH
+#else
+#ifdef SUNOS4 /* SunOS 4.x... */
+#define CK_WREFRESH
+#else
+#ifdef SOLARIS25 /* Solaris 2.5 and later */
+#define CK_WREFRESH
+#else
+#ifdef AIXRS /* RS/6000 AIX ... */
+#define CK_WREFRESH
+#else
+#ifdef RTAIX /* RT PC AIX ... */
+#define CK_WREFRESH
+#else
+#ifdef OSF /* DEC OSF/1 ... */
+#define CK_WREFRESH
+
+/* Add more here, or just define CK_WREFRESH on the CC command line... */
+
+#endif /* OSF */
+#endif /* RTAIX */
+#endif /* AIXRS */
+#endif /* SOLARIS25 */
+#endif /* SUNOS4 */
+#endif /* NEXT */
+#endif /* BSD44 */
+#endif /* SVR3 */
+#endif /* ultrix */
+#endif /* VMS */
+
+#else /* CK_WREFRESH is defined */
+
+/* This is within an ifdef CK_CURSES block. The following is not needed */
+
+#ifndef CK_CURSES /* CK_WREFRESH implies CK_CURSES */
+#define CK_CURSES
+#endif /* CK_CURSES */
+
+#endif /* CK_WREFRESH */
+#endif /* NOWREFRESH */
+
+#ifndef TRMBUFL
+#ifdef BIGBUFOK
+#define TRMBUFL 16384
+#else
+#ifdef DYNAMIC
+#define TRMBUFL 8192
+#else
+#define TRMBUFL 1024
+#endif /* BIGBUFOK */
+#endif /* DYNAMIC */
+#endif /* TRMBUFL */
+#endif /* CK_CURSES */
+
+/*
+ Whether to use ckmatch() in all its glory for C-Shell-like patterns.
+ If CKREGEX is NOT defined, all but * and ? matching are removed from
+ ckmatch(). NOTE: Defining CKREGEX does not necessarily mean that ckmatch()
+ regexes are used for filename matching. That depends on whether zxpand()
+ in ck?fio.c calls ckmatch(). NOTE 2: REGEX is a misnomer -- these are not
+ regular expressions in the computer-science sense (in which, e.g. "a*b"
+ matches 0 or more 'a' characters followed by 'b') but patterns (in which
+ "a*b" matches 'a' followed by 0 or more non-b characters, followed by b).
+*/
+#ifndef NOCKREGEX
+#ifndef CKREGEX
+#define CKREGEX
+#endif /* CKREGEX */
+#endif /* NOCKREGEX */
+
+/* Learned-script feature */
+
+#ifndef NOLEARN
+#ifdef NOSPL
+#define NOLEARN
+#else
+#ifdef NOLOCAL
+#define NOLEARN
+#endif /* NOLOCAL */
+#endif /* NOSPL */
+#endif /* NOLEARN */
+
+#ifdef NOLEARN
+#ifdef CKLEARN
+#undef CKLEARN
+#endif /* CKLEARN */
+#else /* !NOLEARN */
+#ifndef CKLEARN
+#ifdef OS2ORUNIX
+/* In UNIX this can work only with ckucns.c builds */
+#define CKLEARN
+#else
+#ifdef VMS
+#define CKLEARN
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#endif /* CKLEARN */
+#endif /* NOLEARN */
+
+#ifdef CKLEARN
+#ifndef LEARNBUFSIZ
+#define LEARNBUFSIZ 128
+#endif /* LEARNBUFSIZ */
+#endif /* CKLEARN */
+
+#ifndef IKSDONLY
+#ifndef CKTIDLE /* Pseudo-keepalive in CONNECT */
+#ifdef OS2 /* In K95 */
+#define CKTIDLE
+#else
+#ifdef UNIX /* In UNIX but only ckucns versions */
+#ifndef NOLEARN
+#ifndef NOSELECT
+#define CKTIDLE
+#endif /* NOSELECT */
+#endif /* NOLEARN */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* CKTIDLE */
+#endif /* IKSDONLY */
+
+#ifdef CK_ANSILIBS
+/*
+ String library functions.
+ For ANSI C, get prototypes from <string.h>.
+ Otherwise, skip the prototypes.
+*/
+#include <string.h>
+
+/*
+ Prototypes for other commonly used library functions, such as
+ malloc, free, getenv, atol, atoi, and exit. Otherwise, no prototypes.
+*/
+#include <stdlib.h>
+#ifdef DIAB /* DIAB DS90 */
+/* #include <commonC.h> */
+#include <sys/wait.h>
+#define CK_WAIT_H
+#ifdef COMMENT
+extern void exit(int status);
+extern void _exit(int status);
+extern int uname(struct utsname *name);
+#endif /* COMMENT */
+extern int chmod(char *path, int mode);
+extern int ioctl(int fildes, int request, ...);
+extern int rdchk(int ttyfd);
+extern int nap(int m);
+#ifdef COMMENT
+extern int getppid(void);
+#endif /* COMMENT */
+extern int _filbuf(FILE *stream);
+extern int _flsbuf(char c,FILE *stream);
+#endif /* DIAB */
+
+/*
+ Prototypes for UNIX functions like access, alarm, chdir, sleep, fork,
+ and pause. Otherwise, no prototypes.
+*/
+#ifdef VMS
+#include <signal.h> /* SMS: sleep() for old (V4.0-000) DEC C. */
+#include <unixio.h>
+#include <unixlib.h> /* SMS: getpid() for old (V4.0-000) DEC C. */
+#endif /* VMS */
+
+#ifdef NEXT
+#ifndef NEXT33
+#include <libc.h>
+#endif /* NEXT33 */
+#else /* NoT NeXT */
+#ifndef AMIGA
+#ifndef OS2
+#ifdef STRATUS
+#include <c_utilities.h>
+#else /* !STRATUS */
+#ifndef OSKXXC
+#include <unistd.h>
+#endif /* OSKXXC */
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif /* HAVE_CRYPT_H */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* AMIGA */
+#endif /* NEXT */
+
+#else /* Not ANSI libs... */
+
+#ifdef MAC
+#include <String.h>
+#include <StdLib.h>
+#endif /* MAC */
+
+#ifdef HPUX
+#ifndef HPUXPRE65
+#include <unistd.h>
+#endif /* HPUXPRE65 */
+#endif /* HPUX */
+
+#ifdef SUNOS41
+#include <unistd.h>
+#include <stdlib.h>
+#else
+#ifndef MAC
+/*
+ It is essential that these are declared correctly!
+ Which is not always easy. Take malloc() for instance ...
+*/
+#ifdef PYRAMID
+#ifdef SVR4
+#ifdef __STDC__
+#define SIZE_T_MALLOC
+#endif /* __STDC__ */
+#endif /* SVR4 */
+#endif /* PYRAMID */
+/*
+ Maybe some other environments need the same treatment for malloc.
+ If so, define SIZE_T_MALLOC for them here or in compiler CFLAGS.
+*/
+#ifdef SIZE_T_MALLOC
+_PROTOTYP( void * malloc, (size_t) );
+#else
+_PROTOTYP( char * malloc, (unsigned int) );
+#endif /* SIZE_T_MALLOC */
+
+_PROTOTYP( char * getenv, (char *) );
+_PROTOTYP( long atol, (char *) );
+#endif /* !MAC */
+#endif /* SUNOS41 */
+#endif /* CK_ANSILIBS */
+
+/*
+ <sys/param.h> generally picks up NULL, MAXPATHLEN, and MAXNAMLEN
+ and seems to present on all Unixes going back at least to SCO Xenix
+ with the exception(s) noted.
+*/
+#ifndef NO_PARAM_H /* 2001-11-03 */
+#ifndef UNIX /* Non-Unixes don't have it */
+#define NO_PARAM_H
+#else
+#ifdef TRS16 /* Tandy Xenix doesn't have it */
+#define NO_PARAM_H
+#endif /* TRS16 */
+#endif /* UNIX */
+#endif /* NO_PARAM_H */
+
+#ifndef NO_PARAM_H
+#ifndef INCL_PARAM_H
+#define INCL_PARAM_H
+#endif /* INCL_PARAM_H */
+#include <sys/param.h>
+#endif /* NO_PARAM_H */
+
+#ifndef NULL /* In case NULL is still not defined */
+#define NULL 0L
+/* or #define NULL 0 */
+/* or #define NULL ((char *) 0) */
+/* or #define NULL ((void *) 0) */
+#endif /* NULL */
+
+/* Macro to differentiate "" from NULL (to avoid comparisons with literals) */
+
+#ifndef isemptystring
+#define isemptystring(s) ((s?(*s?0:1):0))
+#endif /* isemptystring */
+
+/* Maximum length for a fully qualified filename, not counting \0 at end. */
+/*
+ This is a rough cut, and errs on the side of being too big. We don't
+ want to pull in hundreds of header files looking for many and varied
+ symbols, for fear of introducing unnecessary conflicts.
+*/
+#ifndef CKMAXPATH
+#ifdef VMS /* VMS may have bad (small, ODS2) */
+#define CKMAXPATH NAMX_C_MAXRSS /* PATH_MAX, so use NAMX_C_MAXRSS. */
+#else /* def VMS */
+#ifdef MAXPATHLEN /* (it probably isn't) */
+#define CKMAXPATH MAXPATHLEN
+#else
+#ifdef PATH_MAX /* POSIX */
+#define CKMAXPATH PATH_MAX
+#else /* def PATH_MAX */
+#ifdef MAC
+#define CKMAXPATH 63
+#else /* def MAC */
+#ifdef pdp11
+#define CKMAXPATH 255
+#else /* def pdp11 */
+#ifdef UNIX /* Even though some are way less... */
+#define CKMAXPATH 1024
+#else /* def UNIX */
+#ifdef STRATUS
+#define CKMAXPATH 256 /* == $MXPL from PARU.H */
+#else /* def STRATUS */
+#ifdef datageneral
+#define CKMAXPATH 256 /* == $MXPL from PARU.H */
+#else /* def datageneral */
+#define CKMAXPATH 255
+#endif /* def STRATUS [else] */
+#endif /* def datageneral [else] */
+#endif /* def UNIX [else] */
+#endif /* def pdp11 [else] */
+#endif /* def MAC [else] */
+#endif /* def PATH_MAX [else] */
+#endif /* def MAXPATHLEN [else] */
+#endif /* def VMS [else] */
+#endif /* ndef CKMAXPATH */
+
+/* Maximum length for the name of a tty device */
+
+#ifndef DEVNAMLEN
+#define DEVNAMLEN CKMAXPATH
+#endif /* DEVNAMLEN */
+
+/* Directory (path segment) separator */
+/* Not fully general - Tricky for VMS, Amiga, ... */
+
+#ifndef DIRSEP
+#ifdef UNIX
+#define DIRSEP '/'
+#define ISDIRSEP(c) ((c)=='/')
+#else
+#ifdef OS2
+#define DIRSEP '/'
+#define ISDIRSEP(c) ((c)=='/'||(c)=='\\')
+#else
+#ifdef datageneral
+#define DIRSEP ':'
+#define ISDIRSEP(c) (((c)==':')||((c)=='^')||((c)=='='))
+#else
+#ifdef STRATUS
+#define DIRSEP '>'
+#define ISDIRSEP(c) ((c)=='>')
+#else
+#ifdef VMS
+#define DIRSEP ']' /* (not really) */
+#define ISDIRSEP(c) ((c)==']'||(c)==':')
+#else
+#ifdef MAC
+#define DIRSEP ':'
+#define ISDIRSEP(c) ((c)==':')
+#else
+#ifdef AMIGA
+#define DIRSEP '/'
+#define ISDIRSEP(c) ((c)=='/'||(c)==':')
+#else
+#ifdef GEMDOS
+#define DIRSEP '\\'
+#define ISDIRSEP(c) ((c)=='\\'||(c)==':')
+#else
+#define DIRSEP '/'
+#define ISDIRSEP(c) ((c)=='/')
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* MAC */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* DIRSEP */
+
+/* FILE package parameters */
+
+#ifdef pdp11
+#define NOCHANNELIO
+#else
+
+#ifndef CKMAXOPEN
+#ifdef QNX
+#define CKMAXOPEN 390
+#else
+#ifdef VMS
+#define CKMAXOPEN 64
+#else
+#ifdef OPEN_MAX
+#define CKMAXOPEN OPEN_MAX
+#else
+#ifdef FOPEN_MAX
+#define CKMAXOPEN FOPEN_MAX
+#else
+#define CKMAXOPEN 64
+#endif /* FOPEN_MAX */
+#endif /* OPEN_MAX */
+#endif /* VMS */
+#endif /* QNX */
+#endif /* CKMAXOPEN */
+
+/* Maximum channels for FOPEN = CKMAXOPEN minus logs, stdio, etc */
+
+#ifndef Z_MINCHAN
+#define Z_MINCHAN 16
+#endif /* Z_MINCHAN */
+
+#ifndef Z_MAXCHAN
+#define Z_MAXCHAN (CKMAXOPEN-ZNFILS-5)
+#endif /* Z_MAXCHAN */
+#endif /* pdp11 */
+
+/* New-format nzltor() and nzrtol() functions that handle pathnames */
+
+#ifndef NZLTOR
+#ifdef UNIX
+#define NZLTOR
+#else
+#ifdef VMS
+#define NZLTOR
+#else
+#ifdef OS2
+#define NZLTOR
+#else
+#ifdef STRATUS
+#define NZLTOR
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* NZLTOR */
+
+#ifdef NZLTOR
+_PROTOTYP( VOID nzltor, (char *, char *, int, int, int) );
+_PROTOTYP( VOID nzrtol, (char *, char *, int, int, int) );
+#endif /* NZLTOR */
+
+/* Implementations with a zrmdir() function */
+
+#ifndef ZRMDIR
+#ifdef OS2
+#define ZRMDIR
+#else /* OS2 */
+#ifdef UNIX
+#define ZRMDIR
+#else
+#ifdef VMS
+#define ZRMDIR
+#else /* VMS */
+#ifdef STRATUS
+#define ZRMDIR
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* ZRMDIR */
+
+#ifdef ZRMDIR
+_PROTOTYP( int zrmdir, (char *) );
+#endif /* ZRMDIR */
+
+#ifndef FILECASE
+#ifdef UNIXOROSK
+#define FILECASE 1
+#else
+#define FILECASE 0
+#endif /* UNIXOROSK */
+#ifndef CKCMAI
+extern int filecase;
+#endif /* CKCMAI */
+#endif /* FILECASE */
+
+/* Funny names for library functions department... */
+
+#ifdef ZILOG
+#define setjmp setret
+#define longjmp longret
+#define jmp_buf ret_buf
+#define getcwd curdir
+#endif /* ZILOG */
+
+#ifdef STRATUS
+/* The C-runtime conflicts with things we do in Stratus VOS ckltio.c ... */
+#define printf vosprtf
+_PROTOTYP( int vosprtf, (char *fmt, ...) );
+#define perror(txt) printf("%s\n", txt)
+/* char_varying is a string type from PL/I that VOS uses extensively */
+#define CV char_varying
+#endif /* STRATUS */
+
+#ifdef NT
+extern int OSVer;
+#define isWin95() (OSVer==VER_PLATFORM_WIN32_WINDOWS)
+#else
+#define isWin95() (0)
+#endif /* NT */
+
+#ifndef BPRINT
+#ifdef OS2
+#define BPRINT
+#endif /* OS2 */
+#endif /* BPRINT */
+
+#ifndef SESLIMIT
+#ifdef OS2
+#define SESLIMIT
+#endif /* OS2 */
+#endif /* SESLIMIT */
+
+#ifndef NOTERM
+#ifndef PCTERM
+#ifdef NT
+#define PCTERM
+#endif /* NT */
+#endif /* PCTERM */
+#endif /* NOTERM */
+
+#ifdef BEOSORBEBOX
+#define query ckquery
+#endif /* BEOSORBEBOX */
+
+#ifndef PTYORPIPE /* NETCMD and/or NETPTY defined */
+#ifdef NETCMD
+#define PTYORPIPE
+#else
+#ifdef NETPTY
+#define PTYORPIPE
+#endif /* NETPTY */
+#endif /* NETCMD */
+#endif /* PTYORPIPE */
+
+/* mktemp() and mkstemp() */
+
+#ifndef NOMKTEMP
+#ifndef MKTEMP
+#ifdef OS2ORUNIX
+#define MKTEMP
+#endif /* OS2ORUNIX */
+#endif /* MKTEMP */
+
+#ifdef MKTEMP
+#ifndef NOMKSTEMP
+#ifndef MKSTEMP
+#ifdef BSD44
+#define MKSTEMP
+#else
+#ifdef __linux__
+#define MKSTEMP
+#endif /* __linux__ */
+#endif /* BSD44 */
+#endif /* MKSTEMP */
+#endif /* NOMKSTEMP */
+#endif /* MKTEMP */
+#endif /* NOMKTEMP */
+
+/* Platforms that have memcpy() -- only after all headers included */
+
+#ifndef USE_MEMCPY
+#ifdef VMS
+#define USE_MEMCPY
+#else
+#ifdef NEXT
+#define USE_MEMCPY
+#else
+#ifdef OS2
+#define USE_MEMCPY
+#else
+#ifdef __linux__
+#define USE_MEMCPY
+#else
+#ifdef SOLARIS
+#define USE_MEMCPY
+#else
+#ifdef SUNOS4
+#define USE_MEMCPY
+#else
+#ifdef AIXRS
+#define USE_MEMCPY
+#else
+#ifdef HPUX
+#define USE_MEMCPY
+#else
+#ifdef POSIX
+#define USE_MEMCPY
+#else
+#ifdef SVR4
+#define USE_MEMCPY
+#else
+#ifdef OSF
+#define USE_MEMCPY
+#else
+#ifdef datageneral
+#define USE_MEMCPY
+#else
+#ifdef STRATUS
+#define USE_MEMCPY
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* OSF */
+#endif /* SVR4 */
+#endif /* POSIX */
+#endif /* HPUX */
+#endif /* AIXRS */
+#endif /* SUNOS4 */
+#endif /* SOLARIS */
+#endif /* __linux__ */
+#endif /* OS2 */
+#endif /* NEXT */
+#endif /* VMS */
+#endif /* USE_MEMCPY */
+
+#ifndef USE_MEMCPY
+#define memcpy(a,b,c) ckmemcpy((a),(b),(c))
+#else
+#ifdef CK_SCO32V4
+/* Because the prototype isn't picked up in the normal header files */
+_PROTOTYP( void *memcpy, (void *, const void *, size_t));
+#endif /* CK_SCO32V4 */
+#endif /* USE_MEMCPY */
+
+/* User authentication for IKS -- So far K95 and UNIX only */
+
+#ifdef NOICP
+#ifndef NOLOGIN
+#define NOLOGIN
+#endif /* NOLOGIN */
+#endif /* NOICP */
+
+#ifndef NOLOGIN
+#ifdef OS2ORUNIX
+#ifndef CK_LOGIN
+#define CK_LOGIN
+#ifndef NOSHADOW
+#ifdef CK_SCOV5
+#define CK_SHADOW
+#endif /* CK_SCOV5 */
+#endif /* NOSHADOW */
+#endif /* CK_LOGIN */
+#ifdef NT
+#define NTCREATETOKEN
+#endif /* NT */
+#endif /* OS2ORUNIX */
+#else /* NOLOGIN */
+#ifdef CK_LOGIN
+#undef CK_LOGIN
+#endif /* CK_LOGIN */
+#endif /* NOLOGIN */
+
+#ifdef OS2
+#define CKSPINNER
+#endif /* OS2 */
+
+#ifdef CK_LOGIN /* Telnet protocol required */
+#ifndef TNCODE /* for login to IKSD. */
+#define TNCODE
+#endif /* TNCODE */
+#endif /* CK_LOGIN */
+
+#ifdef CK_AUTHENTICATION
+#ifdef NOSENDUID
+#undef NOSENDUID
+#endif /* NOSENDUID */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef TNCODE /* Should TELNET send user ID? */
+#ifndef NOSENDUID
+#ifndef CKSENDUID
+#define CKSENDUID
+#endif /* CKSENDUID */
+#endif /* NOSENDUID */
+#endif /* TNCODE */
+
+/* UNIX platforms that don't have getusershell() */
+
+#ifdef UNIX
+#ifndef NOGETUSERSHELL
+#ifdef IRIX
+#define NOGETUSERSHELL
+#else
+#ifdef PTX
+#define NOGETUSERSHELL
+#else
+#ifdef AIXRS
+#define NOGETUSERSHELL
+#else
+#ifdef SINIX
+#define NOGETUSERSHELL
+#else
+#ifdef UNIXWARE
+#define NOGETUSERSHELL
+#else
+#ifdef COHERENT
+#define NOGETUSERSHELL
+#endif /* COHERENT */
+#endif /* UNIXWARE */
+#endif /* SINIX */
+#endif /* AIXRS */
+#endif /* PTX */
+#endif /* IRIX */
+#endif /* NOGETUSERSHELL */
+#endif /* UNIX */
+
+#ifdef CK_LOGIN
+#ifdef NT
+#ifndef NOSYSLOG
+#ifndef CKSYSLOG
+#define CKSYSLOG
+#endif /* CKSYSLOG */
+#endif /* NOSYSLOG */
+#endif /* NT */
+#ifdef UNIX
+#ifndef NOSYSLOG
+#ifndef CKSYSLOG
+#define CKSYSLOG
+#endif /* CKSYSLOG */
+#endif /* NOSYSLOG */
+#ifndef NOWTMP
+#ifndef CKWTMP
+#define CKWTMP
+#endif /* CKWTMP */
+#endif /* NOWTMP */
+#ifndef NOGETUSERSHELL
+#ifndef GETUSERSHELL
+#define GETUSERSHELL
+#endif /* GETUSERSHELL */
+#endif /* NOGETUSERSHELL */
+#endif /* UNIX */
+_PROTOTYP( int ckxlogin, (CHAR *, CHAR *, CHAR *, int));
+_PROTOTYP( int ckxlogout, (VOID));
+#endif /* CK_LOGIN */
+
+#ifndef NOZLOCALTIME /* zlocaltime() available. */
+#ifdef OS2ORUNIX
+#define ZLOCALTIME
+_PROTOTYP( char * zlocaltime, (char *) );
+#endif /* OS2ORUNIX */
+#endif /* NOZLOCALTIME */
+
+#ifdef CKSYSLOG /* Syslogging levels */
+#define SYSLG_NO 0 /* No logging */
+#define SYSLG_LI 1 /* Login/out */
+#define SYSLG_DI 2 /* Dialing out */
+#define SYSLG_AC 3 /* Making any kind of connection */
+#define SYSLG_PR 4 /* Protocol Operations */
+#define SYSLG_FC 5 /* File creation */
+#define SYSLG_FA 6 /* File reading */
+#define SYSLG_CM 7 /* Top-level commands */
+#define SYSLG_CX 8 /* All commands */
+#define SYSLG_DB 9 /* Debug */
+#define SYSLGMAX 9 /* Highest level */
+#define SYSLG_DF SYSLG_FA /* Default level */
+/* Logging function */
+_PROTOTYP(VOID cksyslog,(int, int, char *, char *, char *));
+#endif /* CKSYSLOG */
+#ifndef CKCMAI
+extern int ckxlogging, ckxsyslog, ikdbopen;
+#endif /* CKCMAI */
+
+#ifndef CK_KEYTAB
+#define CK_KEYTAB
+/* Keyword Table Template */
+
+/* Note: formerly defined in ckucmd.h but now more widely used */
+
+struct keytab { /* Keyword table */
+ char *kwd; /* Pointer to keyword string */
+ int kwval; /* Associated value */
+ int flgs; /* Flags (as defined above) */
+};
+#endif /* CK_KEYTAB */
+
+#ifdef UNIX
+_PROTOTYP( int isalink, (char *));
+#endif /* UNIX */
+
+#ifdef NETPTY
+_PROTOTYP( int do_pty, (int *, char *, int));
+_PROTOTYP( VOID end_pty, (void));
+#endif /* NETPTY */
+
+#ifdef CKROOT
+_PROTOTYP( int zsetroot, (char *) );
+_PROTOTYP( char * zgetroot, (void) );
+_PROTOTYP( int zinroot, (char *) );
+#endif /* CKROOT */
+
+/* Local Echo Buffer prototypes */
+_PROTOTYP( VOID le_init, (void) );
+_PROTOTYP( VOID le_clean, (void));
+_PROTOTYP( int le_inbuf, (void));
+_PROTOTYP( int le_putstr, (CHAR *));
+_PROTOTYP( int le_puts, (CHAR *, int));
+_PROTOTYP( int le_putchar, (CHAR));
+_PROTOTYP( int le_getchar, (CHAR *));
+
+/* #ifndef NOHTTP */
+#ifndef NOCMDATE2TM
+#ifndef CMDATE2TM
+#ifdef OS2ORUNIX
+#define CMDATE2TM
+#endif /* OS2ORUNIX */
+#ifdef VMS
+#define CMDATE2TM
+#endif /* VMS */
+#endif /* CMDATE2TM */
+#endif /* NOCMDATE2TM */
+
+#ifdef CMDATE2TM
+_PROTOTYP( struct tm * cmdate2tm, (char *,int));
+#endif /* CMDATE2TM */
+/* #endif */ /* NOHTTP */
+
+#ifndef NOSETTIME /* This would be set in CFLAGS */
+#ifdef SVR4ORPOSIX /* Defined in IEEE 1003.1-1996 */
+#ifndef UTIMEH /* and in SVID for SVR4 */
+#define UTIMEH
+#endif /* UTIMEH */
+#else /* SVR4ORPOSIX */
+#ifdef OSF /* Verified by Lucas Hart */
+#ifndef UTIMEH
+#define UTIMEH
+#endif /* UTIMEH */
+#else /* OSF */
+#ifdef SUNOS41 /* Verified by Lucas Hart */
+#ifndef UTIMEH
+#define UTIMEH
+#endif /* UTIMEH */
+#else /* SUNOS41 */
+#ifdef OS2
+#ifndef SYSUTIMEH
+#define SYSUTIMEH
+#endif /* SYSUTIMEH */
+#else /* OS2 */
+#ifdef VMS
+#ifndef UTIMEH
+#define UTIMEH
+#endif /* UTIMEH */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* SUNOS41 */
+#endif /* OSF */
+#endif /* SVR4ORPOSIX */
+#endif /* NOSETTIME */
+
+#ifdef NEWFTP
+_PROTOTYP( int ftpisconnected, (void));
+_PROTOTYP( int ftpisloggedin, (void));
+_PROTOTYP( int ftpissecure, (void));
+#endif /* NEWFTP */
+
+_PROTOTYP( int readpass, (char *, char *, int));
+_PROTOTYP( int readtext, (char *, char *, int));
+
+#ifdef OS2
+_PROTOTYP(int ck_auth_loaddll, (VOID));
+_PROTOTYP(int ck_auth_unloaddll, (VOID));
+#endif /* OS2 */
+
+#ifdef NT
+_PROTOTYP(DWORD ckGetLongPathname,(LPCSTR lpFileName,
+ LPSTR lpBuffer, DWORD cchBuffer));
+#endif /* NT */
+
+
+#include "ckclib.h"
+
+/* End of ckcdeb.h */
+#endif /* CKCDEB_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcfn2.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcfn2.c
new file mode 100644
index 0000000..5fa0507
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcfn2.c
@@ -0,0 +1,3350 @@
+/* C K C F N 2 -- System-independent Kermit protocol support functions... */
+
+/* ...Part 2 (continued from ckcfns.c) */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+/*
+ Note -- if you change this file, please amend the version number and date at
+ the top of ckcfns.c accordingly.
+*/
+
+#include "ckcsym.h" /* Compilation options */
+#include "ckcdeb.h" /* Debugging and other symbols */
+#include "ckcasc.h" /* ASCII symbols */
+#include "ckcker.h" /* Kermit symbols */
+#include "ckcxla.h" /* Translation */
+#include "ckcnet.h" /* IKS and VMS #define TCPSOCKET */
+#ifdef TCPSOCKET /* For TELNET business in spack() */
+extern int tn_nlm, ttnproto, tn_b_nlm;
+#endif /* TCPSOCKET */
+
+extern int parity, network, local, interrupted, fatalio, wasclosed;
+
+int kstartactive = 0; /* Flag for kstart() in a packet */
+
+static CHAR p_tbl[] = { /* Even parity table for dopar(). */
+ (CHAR) '\000', /* ANSI C casts '\ooo' constants */
+ (CHAR) '\201', /* to signed char, so we have to */
+ (CHAR) '\202', /* cast back to unsigned char... */
+ (CHAR) '\003',
+ (CHAR) '\204',
+ (CHAR) '\005',
+ (CHAR) '\006',
+ (CHAR) '\207',
+ (CHAR) '\210',
+ (CHAR) '\011',
+ (CHAR) '\012',
+ (CHAR) '\213',
+ (CHAR) '\014',
+ (CHAR) '\215',
+ (CHAR) '\216',
+ (CHAR) '\017',
+ (CHAR) '\220',
+ (CHAR) '\021',
+ (CHAR) '\022',
+ (CHAR) '\223',
+ (CHAR) '\024',
+ (CHAR) '\225',
+ (CHAR) '\226',
+ (CHAR) '\027',
+ (CHAR) '\030',
+ (CHAR) '\231',
+ (CHAR) '\232',
+ (CHAR) '\033',
+ (CHAR) '\234',
+ (CHAR) '\035',
+ (CHAR) '\036',
+ (CHAR) '\237',
+ (CHAR) '\240',
+ (CHAR) '\041',
+ (CHAR) '\042',
+ (CHAR) '\243',
+ (CHAR) '\044',
+ (CHAR) '\245',
+ (CHAR) '\246',
+ (CHAR) '\047',
+ (CHAR) '\050',
+ (CHAR) '\251',
+ (CHAR) '\252',
+ (CHAR) '\053',
+ (CHAR) '\254',
+ (CHAR) '\055',
+ (CHAR) '\056',
+ (CHAR) '\257',
+ (CHAR) '\060',
+ (CHAR) '\261',
+ (CHAR) '\262',
+ (CHAR) '\063',
+ (CHAR) '\264',
+ (CHAR) '\065',
+ (CHAR) '\066',
+ (CHAR) '\267',
+ (CHAR) '\270',
+ (CHAR) '\071',
+ (CHAR) '\072',
+ (CHAR) '\273',
+ (CHAR) '\074',
+ (CHAR) '\275',
+ (CHAR) '\276',
+ (CHAR) '\077',
+ (CHAR) '\300',
+ (CHAR) '\101',
+ (CHAR) '\102',
+ (CHAR) '\303',
+ (CHAR) '\104',
+ (CHAR) '\305',
+ (CHAR) '\306',
+ (CHAR) '\107',
+ (CHAR) '\110',
+ (CHAR) '\311',
+ (CHAR) '\312',
+ (CHAR) '\113',
+ (CHAR) '\314',
+ (CHAR) '\115',
+ (CHAR) '\116',
+ (CHAR) '\317',
+ (CHAR) '\120',
+ (CHAR) '\321',
+ (CHAR) '\322',
+ (CHAR) '\123',
+ (CHAR) '\324',
+ (CHAR) '\125',
+ (CHAR) '\126',
+ (CHAR) '\327',
+ (CHAR) '\330',
+ (CHAR) '\131',
+ (CHAR) '\132',
+ (CHAR) '\333',
+ (CHAR) '\134',
+ (CHAR) '\335',
+ (CHAR) '\336',
+ (CHAR) '\137',
+ (CHAR) '\140',
+ (CHAR) '\341',
+ (CHAR) '\342',
+ (CHAR) '\143',
+ (CHAR) '\344',
+ (CHAR) '\145',
+ (CHAR) '\146',
+ (CHAR) '\347',
+ (CHAR) '\350',
+ (CHAR) '\151',
+ (CHAR) '\152',
+ (CHAR) '\353',
+ (CHAR) '\154',
+ (CHAR) '\355',
+ (CHAR) '\356',
+ (CHAR) '\157',
+ (CHAR) '\360',
+ (CHAR) '\161',
+ (CHAR) '\162',
+ (CHAR) '\363',
+ (CHAR) '\164',
+ (CHAR) '\365',
+ (CHAR) '\366',
+ (CHAR) '\167',
+ (CHAR) '\170',
+ (CHAR) '\371',
+ (CHAR) '\372',
+ (CHAR) '\173',
+ (CHAR) '\374',
+ (CHAR) '\175',
+ (CHAR) '\176',
+ (CHAR) '\377'
+};
+
+/* D O P A R -- Add an appropriate parity bit to a character */
+
+CHAR
+#ifdef CK_ANSIC
+dopar(register CHAR ch)
+#else
+dopar(ch) register CHAR ch;
+#endif /* CK_ANSIC */
+ {
+ register unsigned int a;
+ if (!parity
+#ifdef TCPSOCKET
+ || (network && (ttnproto == NP_TELNET) && (TELOPT_ME(TELOPT_BINARY)))
+#ifndef NOXFER
+ || (!local && sstelnet) /* TELNET BINARY MODE */
+#endif /* NOXFER */
+#endif /* TCPSOCKET */
+ ) return((CHAR) (ch & 255)); else a = ch & 127;
+ switch (parity) {
+ case 'e': return(p_tbl[a]); /* Even */
+ case 'm': return((CHAR) (a | 128)); /* Mark */
+ case 'o': return((CHAR) (p_tbl[a] ^ 128)); /* Odd */
+ case 's': return((CHAR) a); /* Space */
+ default: return((CHAR) a); /* Something illegal */
+ }
+}
+
+#ifndef NOXFER /* Rest of this file... */
+
+#define NEWDPL /* New dynamic packet length method */
+
+#ifdef VMS
+extern int batch;
+#else
+extern int backgrd;
+#endif /* VMS */
+
+#ifdef DYNAMIC
+extern struct pktinfo *s_pkt; /* array of pktinfo structures */
+extern struct pktinfo *r_pkt; /* array of pktinfo structures */
+#else
+extern struct pktinfo s_pkt[]; /* array of pktinfo structures */
+extern struct pktinfo r_pkt[]; /* array of pktinfo structures */
+#endif /* DYNAMIC */
+
+extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, wslotn,
+ sbufnum, rbufnum, pktpaus, reliable;
+
+#ifdef STREAMING
+static int dontsend = 0;
+extern int streaming;
+#endif /* STREAMING */
+
+extern int ttprty; /* from ck*tio.c */
+extern int autopar;
+
+extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend;
+extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, flow;
+extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctf, bctl, rsn, rln, maxtry;
+extern int size, osize, maxsize, spktl, rpktl, nfils, stdouf, fsecs;
+extern int turn, turnch, displa, pktlog, seslog, xflg, mypadn;
+extern int hcflg, server, cxseen, czseen, discard, slostart;
+extern int nakstate, quiet, success, xitsta, what, filestatus;
+extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
+extern int carrier, fdispla, srvidl;
+
+#ifdef GFTIMER
+extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
+#endif /* GFTIMER */
+
+extern long filcnt, filrej, speed, filcps, tfcps;
+extern CK_OFF_T ffc, flci, flco, tlci, tlco, tfc;
+
+extern char *cmarg, filnam[];
+
+extern CHAR padch, mypadc, eol, seol, ctlq, sstate;
+extern CHAR *recpkt, *data, myinit[];
+extern CHAR *srvptr, stchr, mystch, *rdatap;
+extern CHAR padbuf[];
+extern CHAR * epktmsg;
+extern int epktrcvd, epktsent;
+
+#ifdef OS2 /* AUTODOWNLOAD parameters */
+extern int adl_kmode, adl_zmode; /* Match Packet to signal download */
+extern char * adl_kstr; /* KERMIT Download String */
+extern char * adl_zstr; /* ZMODEM Download String */
+#endif /* OS2 */
+
+#ifdef CK_AUTODL
+CHAR ksbuf[96] = { NUL, NUL }; /* Autodownload "Kermit Start" buf */
+#endif /* CK_AUTODL */
+
+int numerrs = 0; /* Number of packet errors so far */
+int rcvtimo = 0; /* Timeout for receiving a packet */
+int idletmo = 0; /* Flag for idle timeout */
+
+long filcps = 0L; /* CPS most recent file transferred */
+long tfcps = 0L; /* CPS most recent transaction */
+long xfsecs = 0L; /* Elapsed time for most recent file */
+#ifdef GFTIMER
+CKFLOAT fpxfsecs = 0.0; /* Ditto, but floating point */
+#endif /* GFTIMER */
+
+#ifdef CK_TIMERS
+int rrttbl[64], srttbl[64]; /* Packet timestamp tables */
+extern int rttflg;
+#define RTT_SCALE 1000
+long
+ rttsamples, /* Round trip time samples */
+ rttdelay, /* RTT delay */
+ pktintvl, /* Interpacket arrival time */
+ rttvariance, /* RTT variance */
+ rttstddev; /* RTT standard deviation */
+#endif /* CK_TIMERS */
+
+/* CRC generation tables */
+
+long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
+ 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
+ 0153215L, 0163416L, 0173617L
+};
+
+long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L,
+ 053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L,
+ 0155745L, 0164576L, 0174367L
+};
+
+#ifdef CK_TIMERS
+/*
+ Round-trip timer calculations adapted from Tim Kientzle's article,
+ "Improving Kermit Performance", Dr Dobb's Journal, February 1996.
+*/
+
+
+/* R T T I N I T -- Initialize timers at start of transaction */
+
+VOID
+rttinit() { /* Initialize round-trip timing */
+ int i;
+
+ if (timint == 0)
+ return;
+
+ rttsamples = 0L; /* Samples (packets) */
+ rttvariance = 0L; /* Variance in delay */
+ rttdelay = (long) timint * RTT_SCALE; /* Delay */
+ pktintvl = (long) timint * RTT_SCALE; /* Delay */
+ rttstddev = (long) timint * RTT_SCALE; /* Standard deviation of delay */
+
+ /* Tables of timestamps indexed by packet sequence number */
+
+ for (i = 0; i < 64; i++) {
+ rrttbl[i] = -1; /* Time each packet was received */
+ srttbl[i] = -1; /* Time each packet was sent */
+ }
+ rcvtimo = timint; /* Initial timeout is what user said */
+}
+
+/* G E T R T T -- Get packet round trip time */
+/*
+ Call with nakstate == 0 if file sender, nonzero if receiver,
+ and n == packet sequence number of the packet we just received.
+
+ Returns:
+ -1 on failure with rcvtimo set to timint (what the user said), or:
+ 0 on success with rcvtimo set to dynamically calculated value:
+ 1 <= rcvtimo <= timint * 3.
+*/
+int
+getrtt(nakstate, n) int nakstate, n; {
+ extern int mintime, maxtime;
+ static int prevz = 0, prevr = 0;
+ int x, y, yy, z = 0, zz = 0; /* How long did it take to get here? */
+
+ rcvtimo = timint; /* Default timeout is what user said */
+
+ if (timint == 0) /* We're not timing out. */
+ return(0);
+
+ if (!rttflg) /* Not supposed to be doing this? */
+ return(-1); /* So don't */
+
+ if (!RTT_SCALE) /* Paranoia... */
+ return(-1);
+
+ /* rtimer() (reset timer) is not called until 1st data packet */
+#ifdef GFTIMER
+ /* rftimer(); */
+#endif /* GFTIMER */
+ /* S (F [ A ] D* Z)* B */
+
+ /* NOTE: we calculate both the round-trip time AND the packet */
+ /* arrival rate. We don't use the RTT for anything, we just display it. */
+ /* Timeouts are based on the packet arrival rate. */
+
+ if (spackets > 3) { /* Don't start till 4th packet */
+ if (nakstate) { /* File receiver */
+ x = rrttbl[n]; /* Time when I got packet n */
+ y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */
+ yy = srttbl[n > 0 ? n - 1 : 63]; /* Time when I sent ACK(n-1) */
+ if (x > -1 && y > -1) { /* Be careful */
+ z = x - y; /* Packet rate */
+ zz = x - yy; /* Round trip time */
+ z++; /* So sender & receiver differ */
+ debug(F101,"RTT RECV","",z);
+ } else { /* This shouldn't happen */
+ debug(F101,"RTT RECV ERROR spackets","",spackets);
+ debug(F101,"RTT RECV ERROR sequence","",n);
+ return(-1);
+ }
+ } else { /* File sender */
+ x = rrttbl[n]; /* Time when I got ACK(n) */
+ y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */
+ yy = srttbl[n]; /* Time when I sent n */
+ if (x > -1 && y > -1) {
+ z = x - y; /* Packet rate */
+ zz = x - yy; /* Round trip time */
+ debug(F101,"RTT SEND","",z);
+ } else {
+ debug(F100,"RTT SEND ERROR","",0);
+ return(-1);
+ }
+ }
+ if (z < 1) /* For fast connections */
+ z = RTT_SCALE / 2; /* Convert to scale... */
+ else
+ z *= RTT_SCALE;
+ debug(F101,"RTT z scaled","",z);
+
+ if (zz < 1) /* For fast connections */
+ zz = RTT_SCALE / 2; /* Convert to scale... */
+ else
+ zz *= RTT_SCALE;
+
+ rttdelay = zz; /* Round trip time of this packet */
+#ifdef COMMENT
+/*
+ This was used in C-Kermit 7.0 (and 6.0?) but not only is it overkill,
+ it also can produce ridiculously long timeouts under certain conditions.
+ Replaced in 8.0 by a far simpler and more aggressive strategy.
+*/
+ if (rttsamples++ == 0L) { /* First sample */
+ pktintvl = z;
+ } else { /* Subsequent samples */
+ long oldavg = pktintvl;
+ long rttdiffsq;
+
+ if (rttsamples > 30) /* Use real average for first 30 */
+ rttsamples = 30; /* then decaying average. */
+
+ /* Average delay, difference squared, variance, std deviation */
+
+ pktintvl += (z - pktintvl) / rttsamples;
+ rttdiffsq = (z - oldavg) * (z - oldavg);
+ rttvariance += (rttdiffsq - rttvariance) / rttsamples;
+ debug(F101,"RTT stddev1","",rttstddev);
+ if (rttstddev < 1L) /* It can be zero, in which case */
+ rttstddev = RTT_SCALE / 3; /* set it to something small... */
+ rttstddev = (rttstddev + rttvariance / rttstddev) / 2;
+ }
+ debug(F101,"RTT stddev2","",rttstddev);
+ debug(F101,"RTT delay ","",pktintvl);
+ rcvtimo = (pktintvl + (3L * rttstddev)) / RTT_SCALE + 1;
+ if (rpackets < 32) /* Allow for slow start */
+ rcvtimo += rcvtimo + 2;
+ else if (rpackets < 64)
+ rcvtimo += rcvtimo / 2 + 1;
+ /* On a reliable link, don't try too hard to time out. */
+ /* Especially on fast local network connections. */
+ if (server && what == W_NOTHING) /* Server command wait */
+ rcvtimo = rcvtimo; /* == srvtim */
+ else if (reliable == SET_ON && rcvtimo > 0) /* Reliable */
+ rcvtimo = rcvtimo +15; /* and not server command wait */
+ else /* Not reliable or server cmd wait */
+ rcvtimo = rcvtimo;
+ if (rcvtimo < mintime) /* Lower bound */
+ rcvtimo = mintime;
+ if (maxtime > 0) { /* User specified an upper bound */
+ if (rcvtimo > maxtime)
+ rcvtimo = maxtime;
+ } else if (maxtime == 0) { /* User didn't specify */
+ if (rcvtimo > timint * 6)
+ rcvtimo = timint * 6;
+ }
+#else /* COMMENT */
+#ifdef CKFLOAT
+ {
+ CKFLOAT x;
+ x = (CKFLOAT)(prevz + z + z) / 3.0;
+ rcvtimo = (int)((((CKFLOAT)x * 2.66) / RTT_SCALE) + 0.5);
+ debug(F101,"RTT rcvtimo (float)","",rcvtimo);
+ }
+#else
+ rcvtimo = (prevz + z + z) / RTT_SCALE;
+ debug(F101,"RTT rcvtimo (int)","",rcvtimo);
+#endif /* CKFLOAT */
+#endif /* COMMENT */
+
+ zz = (rttdelay + 500) / 1000;
+ if (rcvtimo > (zz * 3))
+ rcvtimo = zz * 3;
+
+ if (rcvtimo < 1)
+ rcvtimo = 1;
+ if (mintime > 0) {
+ if (rcvtimo < mintime) /* Lower bound */
+ rcvtimo = mintime;
+ }
+ if (maxtime > 0) { /* Upper bound */
+ if (rcvtimo > maxtime)
+ rcvtimo = maxtime;
+ }
+ if (rcvtimo == (prevr - 1))
+ rcvtimo++;
+
+ debug(F101,"RTT final rcvtimo","",rcvtimo);
+ }
+ prevz = z;
+ prevr = rcvtimo;
+ return(0);
+}
+#endif /* CK_TIMERS */
+
+/* I N P U T -- Attempt to read packet number 'pktnum'. */
+
+/*
+ This is the function that feeds input to Kermit's finite state machine,
+ in the form of a character in the range 32-126, normally a packet type
+ (uppercase letter) or pseudo-packet-type (lowercase letter).
+
+ If a special start state is in effect, that state is returned as if it were
+ the type of an incoming packet.
+*/
+int
+input() {
+ int type = 0, acktype; /* Received packet type */
+ int x, y, k; /* Workers */
+ int z, pi, nf; /* Worker, packet index, NAK flag */
+ int nak2ack = 0;
+
+ debug(F000,"input sstate","",sstate);
+ debug(F101,"input nakstate","",nakstate);
+ debug(F000,"input sndtyp","",sndtyp);
+ debug(F101,"input xitsta","",xitsta);
+ debug(F101,"input what","",what);
+
+ while (1) { /* Big loop... */
+/*
+ It is ttchk()'s responsibility to tell us if the connection is broken,
+ and to do so instantly and nondestructively -- no blocking, etc, that would
+ slow down file transfer.
+*/
+ if (ttchk() < 0) {
+ debug(F100,"input CONNECTION BROKEN","",0);
+ fatalio = 1;
+ return('q');
+ }
+ if (sstate != 0) { /* If a start state is in effect, */
+ type = sstate; /* return it like a packet type, */
+ sstate = 0; /* and then nullify it. */
+ numerrs = 0; /* (PWP) no errors so far */
+ return(type);
+ }
+ if (nakstate) { /* This section for file receiver. */
+ if (wslots > 1) { /* If we're doing windows, */
+ x = rseqtbl[winlo]; /* see if desired packet already in. */
+ debug(F101,"input winlo","",winlo);
+ debug(F101,"input rseqtbl[winlo]","",rseqtbl[winlo]);
+ if (x > -1) { /* Already there? */
+ if (r_pkt[x].pk_seq == winlo) { /* (double check) */
+ rsn = winlo; /* Yes, return its info */
+ debug(F101,"input return pre-stashed packet","",rsn);
+ dumprbuf();
+ rdatap = r_pkt[x].pk_adr; /* like rpack would do. */
+ rln = (int)strlen((char *) rdatap);
+ type = r_pkt[x].pk_typ;
+ break;
+ }
+ }
+ }
+ type = rpack(); /* Try to read a packet. */
+ debug(F101,"input rpack","",type);
+
+ while (type == 'e') { /* Handle echoes */
+ debug(F101,"input echo discarded","",type);
+ type = rpack();
+ }
+#ifdef DEBUG
+ if (deblog) {
+ if (type == 'D')
+ debug(F011,"input type D=",(char *)rdatap,39);
+ else
+ debug(F000,"input type",(char *)rdatap,type);
+ }
+#endif /* DEBUG */
+#ifndef OLDCHKINT
+ if (type == 'z') {
+ epktrcvd = 1;
+ errpkt((CHAR *)"User cancelled.");
+ type = 'E';
+ break;
+ }
+#endif /* OLDCHKINT */
+ if (type < -1) {
+ char * s;
+ s = (type == -2) ?
+ "FAILED - Interrupted" :
+ "FAILED - Connection lost";
+
+ xxscreen(SCR_PT,'q',0L,s);
+ dologend();
+ return('q'); /* Ctrl-C or connection lost */
+ }
+ if (type < 0) { /* Receive window full */
+ /* Another thing to do here would be to delete */
+ /* the highest packet and NAK winlo. But that */
+ /* shouldn't be necessary since the other Kermit */
+ /* should not have sent a packet outside the window. */
+#ifdef COMMENT
+ char foo[256];
+ ckmakxmsg(foo,256,"Receive window full (rpack): wslots=",
+ ckitoa(wslots)," winlo=",ckitoa(winlo)," pktnum=",
+ ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
+ errpkt((CHAR *)foo);
+ debug(F100,foo,"",0);
+#else
+ errpkt((CHAR *)"Receive window full");
+ debug(F101,"rpack receive window full","",0);
+ debug(F101," wslots","",wslots);
+ debug(F101," winlo","",winlo);
+ debug(F101," pktnum","",pktnum);
+#endif
+ dumprbuf();
+ type = 'E';
+ break;
+ }
+ dumprbuf();
+
+#ifdef OLDCHKINT
+ if (chkint() < 0) { /* Check for console interrupts. */
+ errpkt((CHAR *)"User cancelled."); /* (old way) */
+ type = 'E';
+ break;
+ }
+#endif /* OLDCHKINT */
+
+#ifdef STREAMING
+ if (streaming) { /* Streaming */
+ if (type == 'Q' || type == 'T') { /* Errors are fatal. */
+ crunched++; /* For statistics */
+ errpkt((CHAR *)"Transmission error on reliable link.");
+ type = 'E';
+ }
+ }
+#endif /* STREAMING */
+ if (type == 'E') {
+ debug(F101,"input got E, nakstate","",nakstate);
+ break; /* Error packet */
+ }
+ if (type == 'Q') { /* Crunched packet. */
+ crunched++;
+ numerrs++;
+/*
+ Packet arrived damaged. It was most likely the packet we were expecting
+ next, so we send a NAK for that packet. Prior to 5A(189), we always
+ NAK'd winlo here, but that was bad because if two (or more) different
+ packets were damaged, we would keep NAKing the first one and never NAK the
+ other ones, which could result in a lengthy series of timeouts. Now we
+ NAK the oldest as-yet-unNAK'd missing packet.
+*/
+#ifdef CK_TIMERS
+ rcvtimo++; /* Stretch the timeout a little */
+#endif /* CK_TIMERS */
+ z = (winlo + wslots) % 64; /* Search from winlo to z */
+ debug(F101,"ZZZ crunched z","",z);
+ nf = 0; /* NAK flag not set yet */
+ for (x = winlo; x != z; x = (x + 1) % 64) {
+ debug(F101,"ZZZ x","",x);
+ if (rseqtbl[x] > -1) /* Have I received packet x? */
+ continue; /* Yes, go on. */
+ debug(F101,"ZZZ x not recd yet","",x);
+ pi = sseqtbl[x]; /* No, have I NAK'd it yet? */
+ if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
+ debug(F101,"ZZZ x not NAK'd yet","",x);
+ nack(x); /* No, NAK it now. */
+ nf = 1; /* Flag that I did. */
+ break;
+ }
+ }
+ if (!nf) { /* If we didn't NAK anything above, */
+ debug(F101,"ZZZ NAKing winlo","",winlo);
+ if (nack(winlo) < 0) { /* we have to NAK winlo (again) */
+ errpkt((CHAR *)"Too many retries."); /* Too many */
+ type = 'E';
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (type == 'T') { /* Timeout */
+#ifndef OS2
+ /* K95 does this its own way */
+ if (server && srvidl) {
+ idletmo = 1;
+ debug(F101,"SERVER IDLE TIMEOUT","",srvidl);
+ return('q');
+ }
+#endif /* OS2 */
+#ifdef CK_TIMERS
+ rcvtimo++; /* Stretch the timeout a little */
+#endif /* CK_TIMERS */
+ timeouts++;
+ debug(F101,"input receive-state timeout, winlo","",winlo);
+ /* NAK only the packet at window-low */
+ debug(F101,"input sending NAK for winlo","",winlo);
+ x = ttchk();
+ if (x > 0) /* Don't give up if there is still */
+ continue; /* something to read. */
+ else if (x < 0) {
+ dologend();
+ fatalio = 1;
+ return('q'); /* Connection Lost */
+ }
+ if (nack(winlo) < 0) {
+ debug(F101,"input sent too many naks","",winlo);
+ errpkt((CHAR *)"Too many retries.");
+ type = 'E';
+ break;
+ } else continue;
+ }
+ if (rsn == winlo) { /* Got the packet we want, done. */
+#ifdef CK_TIMERS
+ if (rttflg && timint) /* Dynamic round trip timers? */
+ getrtt(nakstate, rsn); /* yes, do it. */
+ else /* JHD 20100208 */
+ rcvtimo = timint; /* JHD 20100208 */
+#endif /* CK_TIMERS */
+ debug(F101,"input rsn=winlo","",rsn);
+ break;
+ }
+
+ /* Got a packet out of order. */
+
+ debug(F101,"input out of sequence, rsn","",rsn);
+ k = rseqtbl[rsn]; /* Get window slot of this packet. */
+ debug(F101,"input rseqtbl[rsn]","",k);
+ if (k < 0) {
+ debug(F101,"input recv can't find index for rcvd pkt","",rsn);
+ /* Was "Internal error 21" */
+ /* This should not happen */
+ errpkt((CHAR *)"Sliding windows protocol error.");
+ type = 'E';
+ break;
+ }
+ y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
+ debug(F101,"input recv chkwin","",y);
+ if (y == 1) { /* From previous window. */
+#ifdef STREAMING
+ if (!streaming) /* NO RESEND IF STREAMING! */
+#endif /* STREAMING */
+ resend(rsn); /* Resend the ACK (might have data) */
+ freerpkt(rsn); /* Get rid of received packet */
+ continue; /* Back to wait for another packet */
+ } else { /* In this window or out of range */
+ if (y < 0) /* If out of range entirely, */
+ freerpkt(rsn); /* release its buffer */
+
+#ifdef STREAMING
+ if (streaming) { /* Streaming (this shouldn't happen) */
+ errpkt((CHAR *)"Sequence error on reliable link.");
+ type = 'E';
+ break;
+ }
+#endif /* STREAMING */
+
+/* If our receive window is full, NAK window-low */
+
+ if (rbufnum < 1) { /* Receive window full? */
+ if (nack(winlo) < 0) { /* No choice, must NAK winlo. */
+ errpkt((CHAR *)"Too many retries."); /* Too many */
+ type = 'E';
+ break;
+ } else continue;
+ }
+/*
+ Receive window not full. This is a packet in the current window but it is
+ not the desired packet at winlo. So therefore there are gaps before this
+ packet. So we find the "lowest" unNAK'd missing packet, if any, between
+ winlo and this one, and NAK it. If there are no as-yet-unNAK'd missing
+ packets in the window, then we send nothing and go wait for another packet.
+ In theory, this could result in a timeout, but in practice it is likely that
+ the already-NAK'd missing packets are already on their way. Note, we do not
+ NAK ahead of ourselves, as that only creates unnecessary retransmissions.
+*/
+ for (x = winlo; x != rsn; x = (x + 1) % 64) {
+ if (rseqtbl[x] > -1) /* Have I received packet x? */
+ continue; /* Yes, check next sequence number. */
+ pi = sseqtbl[x]; /* No, have I NAK'd it yet? */
+ if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
+ nack(x); /* No, NAK it now. */
+ break;
+ }
+ }
+ }
+/*!!!*/
+ } else { /* Otherwise file sender... */
+
+#ifdef STREAMING
+ if (streaming && sndtyp == 'D') {
+ debug(F101,"STREAMING input streaming","",streaming);
+ debug(F000,"STREAMING input sndtyp","",sndtyp);
+ rsn = winlo;
+ type = 'Y'; /* Pretend we got an ACK */
+ }
+#endif /* STREAMING */
+ if (!nak2ack) { /* NAK(n+1) = ACK(n) */
+ if (wslots > 1) { /* Packet at winlo already ACK'd? */
+ if (sacktbl[winlo]) { /* If so, */
+ sacktbl[winlo] = 0; /* Turn off the ACK'd flag */
+ winlo = (winlo + 1) % 64; /* Rotate the window */
+ type = 'Y'; /* And return ACK */
+ debug(F101,
+ "input send returning pre-stashed ACK","",
+ winlo-1);
+ break;
+ }
+ }
+#ifdef STREAMING
+ if (!(streaming && sndtyp == 'D')) { /* Not streaming | data */
+ type = rpack(); /* Try to read an acknowledgement */
+ } else { /* Streaming and in Data phase */
+ type = 'Y'; /* Assume all is normal */
+ if (chkint() < 0) /* Check for console interrupts. */
+ type = 'z';
+ else if (ttchk() > 4 + bctu) /* Check for return traffic */
+ type = rpack();
+ debug(F000,"input streaming type","",type);
+ }
+#endif /* STREAMING */
+ debug(F111,"input send",(char *) rdatap,(int) type);
+ while (type == 'e') { /* Handle echoes */
+ debug(F000,"echo discarded","",type);
+ type = rpack();
+ }
+#ifndef OLDCHKINT
+ if (type == 'z') {
+ epktrcvd = 1;
+ errpkt((CHAR *)"User cancelled.");
+ type = 'E';
+ break;
+ }
+#endif /* OLDCHKINT */
+ if (type < -1) {
+ xxscreen(SCR_PT,'q',0L,
+ ((char *)((type == -2) ?
+ "Interrupted" :
+ "Connection lost"))
+ );
+ if (type != -2)
+ dologend();
+ return('q'); /* Ctrl-C or connection lost */
+ }
+ if (type == -1) {
+#ifdef COMMENT
+ char foo[256];
+ ckmakxmsg(foo,256,
+ "Receive window full (error 18): wslots=",
+ ckitoa(wslots),
+ " winlo=",ckitoa(winlo)," pktnum=",
+ ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
+ errpkt((CHAR *)foo);
+ debug(F100,foo,"",0);
+#else
+ errpkt((CHAR *)"Receive window full"); /* was "internal */
+ debug(F101," wslots","",wslots); /* error 18" */
+ debug(F101," winlo","",winlo);
+ debug(F101," pktnum","",pktnum);
+#endif /* COMMENT */
+ dumprbuf();
+ type = 'E';
+ break;
+ }
+ dumprbuf(); /* Debugging */
+
+#ifdef OLDCHKINT
+ if (chkint() < 0) { /* Check for console interrupts. */
+ errpkt((CHAR *)"User cancelled.");
+ return(type = 'E');
+ }
+#endif /* OLDCHKINT */
+
+ /* Got a packet */
+
+#ifdef STREAMING
+ if (streaming) { /* Streaming */
+ if (type == 'Q' || type == 'T') { /* Errors are fatal. */
+ crunched++; /* For statistics */
+ errpkt((CHAR *)"Transmission error on reliable link.");
+ type = 'E';
+ }
+ }
+#endif /* STREAMING */
+ if (type == 'E') {
+ debug(F101,"input send got E, nakstate","",nakstate);
+ break; /* Error packet */
+ }
+ if (type == 'Q') { /* Crunched packet */
+ crunched++; /* For statistics */
+ numerrs++; /* For packet resizing */
+ x = resend(winlo); /* Resend window-low */
+ if (x < 0) {
+ type = 'E';
+ errpkt((CHAR *)"Too many retries");
+ break;
+ }
+ continue;
+ }
+ if (type == 'T') { /* Timeout waiting for ACKs. */
+ timeouts++; /* Count it */
+ numerrs++; /* Count an error too */
+ debug(F101,"input send state timeout, winlo","",winlo);
+
+ /* Retransmit the oldest un-ACK'd packet. */
+
+ debug(F101,"input send resending winlo","",winlo);
+ if (resend(winlo) < 0) { /* Check retries */
+ debug(F101,"input send too many resends","",maxtry);
+ errpkt((CHAR *)"Too many retries");
+ return(type = 'E');
+ }
+#ifdef NEWDPL
+ /* Reduce prevailing packet length */
+ x = sseqtbl[winlo]; /* Get length of packet we want ACKd */
+ if (x > -1) { /* Only if we have a valid index */
+ if (s_pkt[x].pk_typ == 'D') { /* only for D packets */
+ spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */
+ if (spsiz < 20) spsiz = 20; /* within reason */
+ debug(F101,"input T cut packet length","",spsiz);
+ }
+ }
+#endif /* NEWDPL */
+ continue;
+ }
+ }
+ /* Got an actual normal packet */
+
+ nak2ack = 0; /* Unset this flag. */
+ y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
+ debug(F101,"input send rsn","",rsn);
+ debug(F101,"input send winlo","",winlo);
+ debug(F101,"input send chkwin","",y);
+
+ if (type == 'Y') { /* Got an ACK */
+ if (y == 0) { /* In current window */
+ if (spackets < 4) /* Error counter doesn't count */
+ numerrs = 0; /* until data phase. */
+ sacktbl[rsn]++; /* Mark the packet as ACK'd */
+ x = sseqtbl[rsn]; /* Get ACK'd packet's buffer index */
+ debug(F101,"bestlen ack x","",x);
+#ifdef NEWDPL
+ if (x > -1) {
+ acktype = s_pkt[x].pk_typ; /* Get type */
+ debug(F000,"bestlen ack type","",acktype);
+
+ if (acktype == 'D') { /* Adjust data packet length */
+ if (spsiz > bestlen) {
+ bestlen = spsiz;
+ debug(F101,"bestlen B","",bestlen);
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"bestlen retry","",s_pkt[x].pk_rtr);
+ debug(F101,"bestlen len","",s_pkt[x].pk_len);
+ debug(F101,"bestlen spackets","",spackets);
+ }
+#endif /* DEBUG */
+ /* Set new best length */
+ if (s_pkt[x].pk_rtr == 0 &&
+ s_pkt[x].pk_len + 8 > bestlen) {
+ bestlen = s_pkt[x].pk_len + 8;
+ if (bestlen > spmax)
+ bestlen = spmax;
+ debug(F101,"bestlen A","",bestlen);
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"bestlen wslots","",wslots);
+ debug(F101,"bestlen maxsend","",maxsend);
+ }
+#endif /* DEBUG */
+ /* Slow start */
+ if (slostart &&
+ (maxsend <= spmax) &&
+ (rpackets < 11) &&
+ (numerrs == 0)) {
+ spsiz = spsiz << 1;
+ debug(F101,"bestlen spsiz A","",spsiz);
+
+ /* Creep up to best length */
+ } else if ((spackets > 5) &&
+ (spsiz < bestlen - 8)) {
+ spsiz += (bestlen - spsiz) / 3;
+ debug(F101,"bestlen spsiz B","",spsiz);
+
+ /* Push the envelope */
+ } else if ((spackets % (wslots + 1) == 0) &&
+ (spackets > 6) &&
+ (bestlen < spmax - 8) &&
+ (spsiz < spmax)) {
+ spsiz += (spmax - bestlen) / 3;
+ debug(F101,"bestlen spsiz C","",spsiz);
+ }
+ /* But not too far */
+ if (spsiz > spmax) {
+ spsiz = spmax;
+ debug(F101,"bestlen spsiz D","",spsiz);
+ }
+ }
+ }
+#endif /* NEWDPL */
+
+#ifdef CK_TIMERS
+ if (rttflg && timint) /* If doing dynamic timers */
+ getrtt(nakstate, rsn); /* call routine to set it. */
+ else /* JHD 20100208 */
+ rcvtimo = timint; /* JHD 20100208 */
+#endif /* CK_TIMERS */
+/*
+ NOTE: The following statement frees the buffer of the ACK we just got.
+ But the upper layers still need the data, like if it's the ACK to an I,
+ S, F, D, Z, or just about any kind of packet. So for now, freerbuf()
+ deallocates the buffer, but does not erase the data or destroy the pointer
+ to it. There's no other single place where these receive buffers can be
+ correctly freed (?) ...
+*/
+ freerpkt(rsn); /* Free the ACK's buffer */
+ freesbuf(rsn); /* *** Free the sent packet's buffer */
+ if (rsn == winlo) { /* Got the one we want */
+ sacktbl[winlo] = 0;
+ winlo = (winlo + 1) % 64;
+ debug(F101,"input send rotated send window","",winlo);
+ break; /* Return the ACK */
+ } else {
+ debug(F101,"input send mark pkt","",rsn);
+ continue; /* Otherwise go read another packet */
+ }
+ } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */
+ numerrs++; /* == NAK for current, count error */
+ debug(F101,"input send ACK for previous","",rsn);
+ freerpkt(rsn); /* Free NAK's buffer */
+ x = resend(winlo); /* Resend current packet */
+ if (x < 0) {
+ type = 'E';
+ errpkt((CHAR *)"Too many retries");
+ break;
+ } else continue; /* Resend ok, go read another packet */
+ } else { /* Other cases, just ignore */
+ debug(F101,"input send ACK out of window","",rsn);
+ freerpkt(rsn);
+ continue;
+ }
+ }
+ if (type == 'N') { /* NAK */
+ numerrs++; /* Count an error */
+#ifdef STREAMING
+ if (streaming) { /* Streaming */
+ errpkt((CHAR *)"NAK received on reliable link.");
+ type = 'E';
+ break;
+ }
+#endif /* STREAMING */
+
+ debug(F101,"input send NAK","",rsn);
+#ifdef NEWDPL
+ /* Reduce prevailing packet length */
+ x = sseqtbl[rsn]; /* Length of packet that was NAK'd */
+ if (x > -1) { /* If it's a Data packet we've sent */
+ if (s_pkt[x].pk_typ == 'D') {
+ spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */
+#ifdef COMMENT
+ /* This might be a good idea -- haven't tried it ... */
+ if (bestlen > 0 && spsiz > bestlen)
+ spsiz = bestlen;
+#endif /* COMMENT */
+ if (spsiz < 20) spsiz = 20;
+ debug(F101,"input N cut packet length","",spsiz);
+ }
+ }
+#endif /* NEWDPL */
+ freerpkt(rsn); /* Free buffer where NAK lies. */
+ if (y == 0) { /* In current window */
+ debug(F100," in window","",0);
+ k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */
+ if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
+ x = resend(winlo); /* Packet we haven't sent yet. */
+ } else {
+ x = resend(rsn); /* Resend requested packet. */
+ }
+ if (x < 0) { /* Resend error is fatal. */
+ type = 'E';
+ errpkt((CHAR *)"Too many retries");
+ break;
+ } else continue; /* Resend ok, go read another packet */
+ } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
+ if (wslots > 1) {
+ debug( F101,"NAK for next packet, windowing","",rsn);
+ x = resend(winlo); /* Resend window-low */
+ if (x < 0) {
+ type = 'E';
+ errpkt((CHAR *)"Too many retries");
+ break;
+ }
+ continue; /* Go back and read another pkt */
+ }
+ debug(F101,"NAK for next packet, no windowing","",rsn);
+ x = (rsn == 0) ? 63 : rsn - 1;
+ if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
+ resend(0); /* ACK for S or I packet missing */
+ continue; /* so resend the S or I */
+ }
+ rsn = x; /* Else, treat NAK(n+1) as ACK(n) */
+ nak2ack = 1; /* Go back and process the ACK */
+ continue;
+ } else if (y > 0) { /* NAK for pkt we can't resend */
+ debug(F101," NAK out of window","",rsn); /* bad... */
+ type = 'E';
+ errpkt((CHAR *)"NAK out of window");
+ break;
+ } else continue; /* Ignore other NAKs */
+ } /* End of file-sender NAK handler */
+
+ if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */
+ debug(F000,"input send unexpected type","",type);
+ break;
+ }
+ } /* End of file-sender section */
+ } /* End of input() while() loop */
+/*
+ When the window size is 1 and we have the packet we want, there can not
+ possibly be anything waiting for us on the connection that is useful to us.
+ However, there might be redundant copies of a packet we already got, which
+ would cause needless cycles of repeated packets. Therefore we flush the
+ communications input buffer now to try to get rid of undesired and unneeded
+ packets that we have not read yet.
+
+ Actually, the first sentence above is not entirely true: there could be an
+ Error packet waiting to be read. Flushing an E packet is bad because it
+ will not be resent, and we'll go into a cycle of timing out and
+ retransmitting up to the retry limit. - fdc 2007/03/02
+*/
+ if (wslotn == 1 /* (not wslots!) */
+#ifdef STREAMING
+ && !streaming /* But not when streaming */
+#endif /* STREAMING */
+ ) {
+ debug(F100,"input about to flush","",0);
+ ttflui(); /* Got what we want, clear input buffer. */
+ }
+#ifndef NEWDPL
+ if (!nakstate) /* When sending */
+ rcalcpsz(); /* recalculate size every packet */
+#endif /* NEWDPL */
+ if (type == 'E')
+ xitsta |= (what ? what : 1); /* Remember what failed. */
+ debug(F101,"input winlo","",winlo);
+ debug(F101,"input rsn","",rsn);
+ debug(F000,"input returning type","",type);
+ return(rcvtyp = type); /* Success, return packet type. */
+}
+
+#ifdef PARSENSE
+/* P A R C H K -- Check if Kermit packet has parity */
+
+/*
+ Call with s = pointer to packet, start = packet start character, n = length.
+ Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
+ 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed.
+ So a return value of 0 really means either space or none.
+ Returns -2 if parity has already been checked during this protocol operation.
+*/
+int
+#ifdef CK_ANSIC
+parchk(CHAR *s, CHAR start, int n)
+#else
+parchk(s,start,n) CHAR *s, start; int n;
+#endif /* CK_ANSIC */
+/* parchk */ {
+ CHAR s0, s1, s2, s3;
+
+ debug(F101,"parchk n","",n);
+ debug(F101,"parchk start","",start);
+
+ s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */
+
+ if (s0 != start || n < 5) return(-1); /* Not a valid packet */
+
+/* Look at packet control fields, which never have 8th bit set */
+/* First check for no parity, most common case. */
+
+ if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
+ return(0); /* No parity or space parity */
+
+/* Check for mark parity */
+
+ if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
+ return('m'); /* Mark parity */
+
+/* Packet has some kind of parity */
+/* Make 7-bit copies of control fields */
+
+ s1 = s[1] & 0x7f; /* LEN */
+ s2 = s[2] & 0x7f; /* SEQ */
+ s3 = s[3] & 0x7f; /* TYPE */
+
+/* Check for even parity */
+
+ if ((s[0] == p_tbl[s0]) &&
+ (s[1] == p_tbl[s1]) &&
+ (s[2] == p_tbl[s2]) &&
+ (s[3] == p_tbl[s3]))
+ return('e');
+
+/* Check for odd parity */
+
+ if ((s[0] != p_tbl[s0]) &&
+ (s[1] != p_tbl[s1]) &&
+ (s[2] != p_tbl[s2]) &&
+ (s[3] != p_tbl[s3]))
+ return('o');
+
+/* Otherwise it's probably line noise. Let checksum calculation catch it. */
+
+ return(-1);
+}
+#endif /* PARSENSE */
+\f
+/*
+ Check to make sure timeout intervals are long enough to allow maximum
+ length packets to get through before the timer goes off. If not, the
+ timeout interval is adjusted upwards.
+
+ This routine is called at the beginning of a transaction, before we
+ know anything about the delay characteristics of the line. It works
+ only for serial communication devices; it trusts the speed reported by
+ the operating system.
+
+ Call with a timout interval. Returns it, adjusted if necessary.
+*/
+int
+chktimo(timo,flag) int timo, flag; {
+ long cps, z; int x, y;
+#ifdef STREAMING
+ debug(F101,"chktimo streaming","",streaming);
+ if (streaming)
+ return(0);
+#endif /* STREAMING */
+
+ debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
+ debug(F101,"chktimo flag","",flag);
+
+ if (flag) /* Don't change timeout if user */
+ return(timo); /* gave SET SEND TIMEOUT command. */
+ debug(F101,"chktimo spmax","",spmax);
+ debug(F101,"chktimo urpsiz","",urpsiz);
+
+ if (!network) { /* On serial connections... */
+ speed = ttgspd(); /* Get current speed. */
+ if (speed > 0L) {
+ cps = speed / 10L; /* Convert to chars per second */
+ if (cps > 0L) {
+ long plen; /* Maximum of send and rcv pkt size */
+ z = cps * (long) timo; /* Chars per timeout interval */
+ z -= z / 10L; /* Less 10 percent */
+ plen = spmax;
+ if (urpsiz > spmax) plen = urpsiz;
+ debug(F101,"chktimo plen","",plen);
+ if (z < plen) { /* Compare with packet size */
+ x = (int) ((long) plen / cps); /* Adjust if necessary */
+ y = x / 10; /* Add 10 percent for safety */
+ if (y < 2) y = 2; /* Or 2 seconds, whichever is more */
+ x += y;
+ if (x > timo) /* If this is greater than current */
+ timo = x; /* timeout, change the timeout */
+ debug(F101,"chktimo new timo","",timo);
+ }
+ }
+ }
+ }
+ return(timo);
+}
+\f
+/* S P A C K -- Construct and send a packet */
+
+/*
+ spack() sends a packet of the given type, sequence number n, with len data
+ characters pointed to by d, in either a regular or extended- length packet,
+ depending on len. Returns the number of bytes actually sent, or else -1
+ upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet
+ fully built and null-terminated for later retransmission by resend().
+ Updates global sndpktl (send-packet length).
+
+ NOTE: The global pointer "data" is assumed to point into the 7th position
+ of a character array (presumably in packet buffer for the current packet).
+ It was used by getpkt() to build the packet data field. spack() fills in
+ the header to the left of the data pointer (the data pointer is defined
+ in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then
+ the packet's data field has been built "in place" and need not be copied.
+*/
+int
+#ifdef CK_ANSIC
+spack(char pkttyp, int n, int len, CHAR *d)
+#else
+spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
+#endif /* CK_ANSIC */
+/* spack */ {
+ register int i;
+ int ix, j, k, x, lp, longpkt, copy, loglen;
+
+#ifdef GFTIMER
+ CKFLOAT t1 = 0.0, t2 = 0.0;
+#endif /* GFTIMER */
+
+ register CHAR *cp, *mydata;
+ unsigned crc;
+
+ copy = (d != data); /* Flag whether data must be copied */
+
+#ifdef DEBUG
+ if (deblog) { /* Save lots of function calls! */
+ debug(F101,"spack n","",n);
+#ifdef COMMENT
+ if (pkttyp != 'D') { /* Data packets would be too long */
+ debug(F111,"spack data",data,data);
+ debug(F111,"spack d",d,d);
+ }
+#endif /* COMMENT */
+ debug(F101,"spack len","",len);
+ debug(F101,"spack copy","",copy);
+ }
+#endif /* DEBUG */
+
+ longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */
+ mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
+ k = sseqtbl[n]; /* Packet structure info for pkt n */
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) { /* Save 2 more function calls... */
+ debug(F101,"spack mydata","",mydata);
+ debug(F101,"spack sseqtbl[n]","",k);
+ if (k < 0) {
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ debug(F101,"spack sending packet out of window","",n);
+ }
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ if (k > -1) {
+ s_pkt[k].pk_adr = mydata; /* Remember address of packet. */
+ s_pkt[k].pk_seq = n; /* Record sequence number */
+ s_pkt[k].pk_typ = pkttyp; /* Record packet type */
+ }
+ spktl = 0; /* Initialize length of this packet */
+ i = 0; /* and position in packet. */
+
+/* Now fill the packet */
+
+ mydata[i++] = mystch; /* MARK */
+ lp = i++; /* Position of LEN, fill in later */
+
+ mydata[i++] = tochar(n); /* SEQ field */
+ mydata[i++] = pkttyp; /* TYPE field */
+ j = len + bctl; /* Length of data + block check */
+ if (longpkt) { /* Long packet? */
+ int x; /* Yes, work around SCO Xenix/286 */
+#ifdef CKTUNING
+ unsigned int chk;
+#endif /* CKTUNING */
+ x = j / 95; /* compiler bug... */
+ mydata[lp] = tochar(0); /* Set LEN to zero */
+ mydata[i++] = tochar(x); /* Extended length, high byte */
+ mydata[i++] = tochar(j % 95); /* Extended length, low byte */
+#ifdef CKTUNING
+ /* Header checksum - skip the function calls and loops */
+ chk = (unsigned) mydata[lp] +
+ (unsigned) mydata[lp+1] +
+ (unsigned) mydata[lp+2] +
+ (unsigned) mydata[lp+3] +
+ (unsigned) mydata[lp+4] ;
+ mydata[i++] = tochar((CHAR) ((((chk & 0300) >> 6) + chk) & 077));
+#else
+ mydata[i] = '\0'; /* Terminate for header checksum */
+ mydata[i++] = tochar(chk1(mydata+lp,5));
+#endif /* CKTUNING */
+ } else mydata[lp] = tochar(j+2); /* Normal LEN */
+/*
+ When sending a file, the data is already in the right place. If it weren't,
+ it might make sense to optimize this section by using memcpy or bcopy
+ (neither of which are portable), but only if our packets were rather long.
+ When receiving, we're only sending ACKs so it doesn't matter. So count the
+ following loop as a sleeping dog.
+*/
+ if (copy) /* Data field built in place? */
+ for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
+ else /* Otherwise, */
+ i += len; /* Just skip past data field. */
+ mydata[i] = '\0'; /* Null-terminate for checksum calc. */
+
+ switch (bctu) { /* Block check */
+ case 1: /* 1 = 6-bit chksum */
+ ix = i - lp; /* Avoid "order of operation" error */
+ mydata[i++] = tochar(chk1(mydata+lp,ix));
+ break;
+ case 2: /* 2 = 12-bit chksum */
+ j = chk2(mydata+lp,i-lp);
+ mydata[i++] = (unsigned)tochar((j >> 6) & 077);
+ mydata[i++] = (unsigned)tochar(j & 077);
+ break;
+ case 3: /* 3 = 16-bit CRC */
+ crc = chk3(mydata+lp,i-lp);
+ mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
+ mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
+ mydata[i++] = (unsigned)tochar(crc & 077);
+ break;
+ case 4: /* 2 = 12-bit chksum, blank-free */
+ j = chk2(mydata+lp,i-lp);
+ mydata[i++] =
+ (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
+ mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
+ break;
+ }
+ loglen = i;
+ mydata[i++] = seol; /* End of line (packet terminator) */
+#ifdef TCPSOCKET
+/*
+ If TELNET connection and packet terminator is carriage return,
+ we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
+ (tn_nlm), to meet the TELNET NVT specification, unless user said RAW.
+
+ If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL
+ on a NVT connection and CR on a binary connection.
+*/
+ if (
+#ifdef STREAMING
+ !dontsend &&
+#endif /* STREAMING */
+ ((network && ttnproto == NP_TELNET) || (!local && sstelnet))
+ && seol == CR) {
+ switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
+ case TNL_CR: /* NVT or BINARY */
+ break;
+ case TNL_CRNUL:
+ mydata[i++] = NUL;
+ break;
+ case TNL_CRLF:
+ mydata[i++] = LF;
+ break;
+ }
+ }
+#endif /* TCPSOCKET */
+ mydata[i] = '\0'; /* Terminate string */
+ if (
+#ifdef STREAMING
+ !dontsend &&
+#endif /* STREAMING */
+ pktlog
+ ) /* Save a function call! */
+ logpkt('s',n,mydata,loglen); /* Log the packet */
+
+ /* (PWP) add the parity quickly at the end */
+ if (parity) {
+ switch (parity) {
+ case 'e': /* Even */
+ for (cp = &mydata[i-1]; cp >= mydata; cp--)
+ *cp = p_tbl[*cp];
+ break;
+ case 'm': /* Mark */
+ for (cp = &mydata[i-1]; cp >= mydata; cp--)
+ *cp |= 128;
+ break;
+ case 'o': /* Odd */
+ for (cp = &mydata[i-1]; cp >= mydata; cp--)
+ *cp = p_tbl[*cp] ^ 128;
+ break;
+ case 's': /* Space */
+ for (cp = &mydata[i-1]; cp >= mydata; cp--)
+ *cp &= 127;
+ break;
+ }
+ }
+ if (pktpaus) msleep(pktpaus); /* Pause if requested */
+ x = 0;
+
+ if (npad) {
+#ifdef STREAMING
+ if (dontsend)
+ x = 0;
+ else
+#endif /* STREAMING */
+ x = ttol(padbuf,npad); /* Send any padding */
+ }
+ if (x > -1) {
+#ifdef CK_TIMERS
+ if (timint > 0) {
+ if (pkttyp == 'N')
+ srttbl[n > 0 ? n-1 : 63] = gtimer();
+ else
+ srttbl[n] = gtimer();
+ }
+#endif /* CK_TIMERS */
+ spktl = i; /* Remember packet length */
+ if (k > -1)
+ s_pkt[k].pk_len = spktl; /* also in packet info structure */
+
+#ifdef DEBUG
+#ifdef GFTIMER
+/*
+ This code shows (in the debug log) how long it takes write() to execute.
+ Sometimes on a congested TCP connection, it can surprise you -- 90 seconds
+ or more...
+*/
+ if (
+#ifdef STREAMING
+ !dontsend &&
+#endif /* STREAMING */
+ deblog
+ )
+ t1 = gftimer();
+#endif /* GFTIMER */
+#endif /* DEBUG */
+
+#ifdef STREAMING
+ if (dontsend) {
+ debug(F000,"STREAMING spack skipping","",pkttyp);
+ x = 0;
+ } else
+#endif /* STREAMING */
+ x = ttol(mydata,spktl); /* Send the packet */
+ }
+#ifdef STREAMING
+ if (!dontsend) {
+#endif /* STREAMING */
+ debug(F101,"spack spktl","",spktl);
+ debug(F101,"spack ttol returns","",x);
+ if (x < 0) { /* Failed. */
+ if (local && x < -1) {
+ xxscreen(SCR_ST,ST_ERR,0L,"FAILED: Connection lost");
+ /* We can't send an E packet because the connection is lost. */
+ epktsent = 1; /* So pretend we sent one. */
+ fatalio = 1; /* Remember we got a fatal i/o error */
+ dologend();
+ ckstrncpy((char *)epktmsg,"Connection lost",PKTMSGLEN);
+ }
+ return(x);
+ }
+ if (spktl > maxsend) /* Keep track of longest packet sent */
+ maxsend = spktl;
+#ifdef DEBUG
+#ifdef GFTIMER
+ if (deblog) { /* Log elapsed time for write() */
+ t2 = gftimer();
+ debug(F101,"spack ttol msec","",(long)((t2-t1)*1000.0));
+ }
+#endif /* GFTIMER */
+#endif /* DEBUG */
+#ifdef STREAMING
+ }
+#endif /* STREAMING */
+
+ sndtyp = pkttyp; /* Remember packet type for echos */
+#ifdef STREAMING
+ if (!dontsend) { /* If really sent, */
+ spackets++; /* count it. */
+ flco += spktl; /* Count the characters */
+ tlco += spktl; /* for statistics... */
+#ifdef DEBUG
+ if (deblog) { /* Save two function calls! */
+ dumpsbuf(); /* Dump send buffers to debug log */
+ debug(F111,"spack calling screen, mydata=",mydata,n);
+ }
+#endif /* DEBUG */
+ }
+#endif /* STREAMING */
+ if (local) {
+ int x = 0;
+ if (fdispla != XYFD_N) x = 1;
+ if ((fdispla == XYFD_B) && (pkttyp == 'D' || pkttyp == 'Y')) x = 0;
+ if (x)
+ xxscreen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
+ }
+ return(spktl); /* Return length */
+}
+
+/* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
+
+int
+chk1(pkt,len) register CHAR *pkt; register int len; {
+ register unsigned int chk;
+#ifdef CKTUNING
+#ifdef COMMENT
+ register unsigned int m; /* Avoid function call */
+ m = (parity) ? 0177 : 0377;
+ for (chk = 0; len-- > 0; pkt++)
+ chk += *pkt & m;
+#else
+ chk = 0;
+ while (len-- > 0) chk += (unsigned) *pkt++;
+#endif /* COMMENT */
+#else
+ chk = chk2(pkt,len);
+#endif /* CKTUNING */
+ chk = (((chk & 0300) >> 6) + chk) & 077;
+ debug(F101,"chk1","",chk);
+ return((int) chk);
+}
+
+/* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */
+
+unsigned int
+chk2(pkt,len) register CHAR *pkt; register int len; {
+ register long chk;
+#ifdef COMMENT
+ register unsigned int m;
+ m = (parity) ? 0177 : 0377;
+ for (chk = 0; len-- > 0; pkt++)
+ chk += *pkt & m;
+#else
+ /* Parity has already been stripped */
+ chk = 0L;
+ while (len-- > 0) chk += (unsigned) *pkt++;
+#endif /* COMMENT */
+ debug(F101,"chk2","",(unsigned int) (chk & 07777));
+ return((unsigned int) (chk & 07777));
+}
+
+/* C H K 3 -- Compute a type-3 Kermit block check. */
+/*
+ Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
+ table. Assumes the argument string contains no embedded nulls.
+*/
+#ifdef COMMENT
+unsigned int
+chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; {
+ register long c, crc;
+ register unsigned int m;
+ m = (parity) ? 0177 : 0377;
+ for (crc = 0; len-- > 0; pkt++) {
+ c = crc ^ (long)(*pkt & m);
+ crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
+ }
+ return((unsigned int) (crc & 0xFFFF));
+}
+#else
+unsigned int
+chk3(pkt,len) register CHAR *pkt; register int len; {
+ register long c, crc;
+ for (crc = 0; len-- > 0; pkt++) {
+ c = crc ^ (long)(*pkt);
+ crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
+ }
+ debug(F101,"chk3","",(unsigned int) (crc & 0xFFFF));
+ return((unsigned int) (crc & 0xFFFF));
+}
+#endif /* COMMENT */
+
+/* N X T P K T -- Next Packet */
+/*
+ Get packet number of next packet to send and allocate a buffer for it.
+ Returns:
+ 0 on success, with global pktnum set to the packet number;
+ -1 on failure to allocate buffer (fatal);
+ -2 if resulting packet number is outside the current window.
+*/
+int
+nxtpkt() { /* Called by file sender */
+ int j, n, x;
+
+ debug(F101,"nxtpkt pktnum","",pktnum);
+ debug(F101,"nxtpkt winlo ","",winlo);
+ n = (pktnum + 1) % 64; /* Increment packet number mod 64 */
+ debug(F101,"nxtpkt n","",n);
+#ifdef STREAMING
+ if (!streaming) {
+ x = chkwin(n,winlo,wslots); /* Don't exceed window boundary */
+ debug(F101,"nxtpkt chkwin","",x);
+ if (x)
+ return(-2);
+ j = getsbuf(n); /* Get a buffer for packet n */
+ if (j < 0) {
+ debug(F101,"nxtpkt getsbuf failure","",j);
+ return(-1);
+ }
+ }
+#endif /* STREAMING */
+ pktnum = n;
+ return(0);
+}
+
+/* Functions for sending ACKs and NAKs */
+
+/* Note, we should only ACK the packet at window-low (winlo) */
+/* However, if an old packet arrives again (e.g. because the ACK we sent */
+/* earlier was lost), we ACK it again. */
+
+int
+ack() { /* Acknowledge the current packet. */
+ return(ackns(winlo,(CHAR *)""));
+}
+
+#ifdef STREAMING
+int
+fastack() { /* Acknowledge packet n */
+ int j, k, n, x;
+ n = winlo;
+
+ k = rseqtbl[n]; /* First find received packet n. */
+ debug(F101,"STREAMING fastack k","",k);
+ freesbuf(n); /* Free current send-buffer, if any */
+ if ((j = getsbuf(n)) < 0) {
+ /* This can happen if we have to re-ACK an old packet that has */
+ /* already left the window. It does no harm. */
+ debug(F101,"STREAMING fastack can't getsbuf","",n);
+ }
+ dontsend = 1;
+ x = spack('Y',n,0,(CHAR *)""); /* Now send it (but not really) */
+ dontsend = 0;
+ if (x < 0) return(x);
+ debug(F101,"STREAMING fastack x","",x);
+ if (k > -1)
+ freerbuf(k); /* don't need it any more */
+ if (j > -1)
+ freesbuf(j); /* and don't need to keep ACK either */
+ winlo = (winlo + 1) % 64;
+ return(0);
+}
+#endif /* STREAMING */
+
+int
+ackns(n,s) int n; CHAR *s; { /* Acknowledge packet n */
+ int j, k, x;
+ debug(F111,"ackns",s,n);
+
+ k = rseqtbl[n]; /* First find received packet n. */
+ debug(F101,"ackns k","",k);
+ freesbuf(n); /* Free current send-buffer, if any */
+ if ((j = getsbuf(n)) < 0) {
+ /* This can happen if we have to re-ACK an old packet that has */
+ /* already left the window. It does no harm. */
+ debug(F101,"ackns can't getsbuf","",n);
+ }
+ x = spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
+ if (x < 0) return(x);
+ debug(F101,"ackns winlo","",winlo);
+ debug(F101,"ackns n","",n);
+ if (n == winlo) { /* If we're acking winlo */
+ if (k > -1)
+ freerbuf(k); /* don't need it any more */
+ if (j > -1)
+ freesbuf(j); /* and don't need to keep ACK either */
+ winlo = (winlo + 1) % 64;
+ }
+ return(0);
+}
+
+int
+ackn(n) int n; { /* Send ACK for packet number n */
+ return(ackns(n,(CHAR *)""));
+}
+
+int
+ack1(s) CHAR *s; { /* Send an ACK with data. */
+ if (!s) s = (CHAR *)"";
+ debug(F110,"ack1",(char *)s,0);
+ return(ackns(winlo,s));
+}
+
+/* N A C K -- Send a Negative ACKnowledgment. */
+/*
+ Call with the packet number, n, to be NAK'd.
+ Returns -1 if that packet has been NAK'd too many times, otherwise 0.
+ Btw, it is not right to return 0 under error conditions. This is
+ done because the -1 code is used for cancelling the file transfer.
+ More work is needed here.
+*/
+int
+nack(n) int n; {
+ int i, x;
+
+ if (n < 0 || n > 63) {
+ debug(F101,"nack bad pkt num","",n);
+ return(0);
+ } else debug(F101,"nack","",n);
+ if ((i = sseqtbl[n]) < 0) { /* If necessary */
+ if (getsbuf(n) < 0) { /* get a buffer for this NAK */
+ debug(F101,"nack can't getsbuf","",n);
+ return(0);
+ } else i = sseqtbl[n]; /* New slot number */
+ }
+ if (maxtry > 0 && s_pkt[i].pk_rtr++ > maxtry) /* How many? */
+ return(-1); /* Too many... */
+
+/* Note, don't free this buffer. Eventually an ACK will come, and that */
+/* will set it free. If not, well, it's back to ground zero anyway... */
+
+ x = spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */
+ return(x);
+}
+
+#ifndef NEWDPL /* This routine no longer used */
+/*
+ * (PWP) recalculate the optimal packet length in the face of errors.
+ * This is a modified version of the algorithm by John Chandler in Kermit/370,
+ * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
+ *
+ * This implementation minimizes the total overhead equation, which is
+ *
+ * Total chars = file_chars + (header_len * num_packs)
+ * + (errors * (header_len + packet_len))
+ *
+ * Differentiate with respect to number of chars, solve for packet_len, get:
+ *
+ * packet_len = sqrt (file_chars * header_len / errors)
+ */
+
+/*
+ (FDC) New super-simple algorithm. If there was an error in the most recent
+ packet exchange, cut the send-packet size in half, down to a minimum of 20.
+ If there was no error, increase the size by 5/4, up to the maximum negotiated
+ length. Seems to be much more responsive than previous algorithm, which took
+ forever to recover the original packet length, and it also went crazy under
+ certain conditions.
+
+ Here's another idea for packet length resizing that keeps a history of the
+ last n packets. Push a 1 into the left end of an n-bit shift register if the
+ current packet is good, otherwise push a zero. The current n-bit value, w, of
+ this register is a weighted sum of the noise hits for the last n packets, with
+ the most recent weighing the most. The current packet length is some function
+ of w and the negotiated packet length, like:
+
+ (2^n - w) / (2^n) * (negotiated length)
+
+ If the present resizing method causes problems, think about this one a little
+ more.
+*/
+VOID
+rcalcpsz() {
+
+#ifdef COMMENT
+/* Old way */
+ register long x, q;
+ if (numerrs == 0) return; /* bounds check just in case */
+
+ /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
+ /* an ACK is 5+bctr */
+
+ /* first set x = per packet overhead */
+ if (wslots > 1) /* Sliding windows */
+ x = (long) (npad+5+bctr); /* packet only, don't count ack */
+ else /* Stop-n-wait */
+ x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */
+
+ /* then set x = packet length ** 2 */
+ x = x * ( ffc / (CK_OFF_T) numerrs); /* careful of overflow */
+
+ /* calculate the long integer sqrt(x) quickly */
+ q = 500;
+ q = (q + x/q) >> 1;
+ q = (q + x/q) >> 1;
+ q = (q + x/q) >> 1;
+ q = (q + x/q) >> 1; /* should converge in about 4 steps */
+ if ((q > 94) && (q < 130)) /* break-even point for long packets */
+ q = 94;
+ if (q > spmax) q = spmax; /* maximum bounds */
+ if (q < 10) q = 10; /* minimum bounds */
+ spsiz = q; /* set new send packet size */
+ debug(F101,"rcalcpsiz","",q);
+#else
+/* New way */
+ debug(F101,"rcalcpsiz numerrs","",numerrs);
+ debug(F101,"rcalcpsiz spsiz","",spsiz);
+ if (spackets < 3) {
+ numerrs = 0;
+ return;
+ }
+ if (numerrs)
+ spsiz = spsiz / 2;
+ else
+ spsiz = (spsiz / 4) * 5;
+ if (spsiz < 20) spsiz = 20;
+ if (spsiz > spmax) spsiz = spmax;
+ debug(F101,"rcalcpsiz new spsiz","",spsiz);
+ numerrs = 0;
+#endif /* COMMENT */
+}
+#endif /* NEWDPL */
+
+/* R E S E N D -- Retransmit packet n. */
+
+/*
+ Returns 0 or positive on success (the number of retries for packet n).
+ On failure, returns a negative number, and an error message is placed
+ in recpkt.
+*/
+int
+resend(n) int n; { /* Send packet n again. */
+ int j, k, x;
+#ifdef GFTIMER
+ CKFLOAT t1 = 0.0, t2 = 0.0;
+#endif /* GFTIMER */
+
+ debug(F101,"resend seq","",n);
+
+ k = chkwin(n,winlo,wslots); /* See if packet in current window */
+ j = -1; /* Assume it's lost */
+ if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */
+ if (k != 0 || j < 0) { /* If not.... */
+ if (nakstate && k == 1) {
+/*
+ Packet n is in the previous window and we are the file receiver.
+ We already sent the ACK and deallocated its buffer so we can't just
+ retransmit the ACK. Rather than give up, we try some tricks...
+*/
+ if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
+/*
+ If the packet number is 0, and we're at the beginning of a protocol
+ operation (spackets < 63), then we have to resend the ACK to an I or S
+ packet, complete with parameters in the data field. So we take a chance and
+ send a copy of the parameters in an ACK packet with block check type 1.
+ (Or 3 if SET BLOCK 5.)
+*/
+ if (bctf) { /* Force Type 3 on all packets? */
+ x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
+ if (x < 0) return(x);
+ logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
+ } else { /* Regular Kermit protocol */
+ int bctlsav; /* Temporary storage */
+ int bctusav;
+ bctlsav = bctl; /* Save current block check length */
+ bctusav = bctu; /* and type */
+ bctu = bctl = 1; /* Set block check to 1 */
+ x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
+ if (x < 0) return(x);
+ logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
+ bctu = bctusav; /* Restore block check type */
+ bctl = bctlsav; /* and length */
+ }
+ } else { /* Not the first packet */
+/*
+ It's not the first packet of the protocol operation. It's some other packet
+ that we have already ACK'd and forgotten about. So we take a chance and
+ send an empty ACK using the current block-check type. Usually this will
+ work out OK (like when acking Data packets), and no great harm will be done
+ if it was some other kind of packet (F, etc). If we are requesting an
+ interruption of the file transfer, the flags are still set, so we'll catch
+ up on the next packet.
+*/
+ x = spack('Y',n,0,(CHAR *) "");
+ if (x < 0) return(x);
+ }
+ retrans++;
+ xxscreen(SCR_PT,'%',(long)pktnum,"Retransmission");
+ return(0);
+ } else {
+/*
+ Packet number is not in current or previous window. We seem to hit this
+ code occasionally at the beginning of a transaction, for apparently no good
+ reason. Let's just log it for debugging, send nothing, and try to proceed
+ with the protocol rather than killing it.
+*/
+ debug(F101,"resend PKT NOT IN WINDOW","",n);
+ debug(F101,"resend k","",k);
+ return(0);
+ }
+ }
+
+/* OK, it's in the window and it's not lost. */
+
+ debug(F101,"resend pktinfo index","",k);
+
+ if (maxtry > 0 && s_pkt[j].pk_rtr++ > maxtry) { /* Over retry limit */
+ xitsta |= what;
+ return(-1);
+ }
+ debug(F101,"resend retry","",s_pkt[j].pk_rtr); /* OK so far */
+ dumpsbuf(); /* (debugging) */
+ if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */
+ if (nakstate) { /* (This shouldn't happen any more) */
+ nack(n);
+ retrans++;
+ xxscreen(SCR_PT,'%',(long)pktnum,"(resend)");
+ return(s_pkt[j].pk_rtr);
+ } else { /* No packet to resend! */
+#ifdef COMMENT
+/*
+ This happened (once) while sending a file with 2 window slots and typing
+ X to the sender to cancel the file. But since we're cancelling anyway,
+ there's no need to give a scary message.
+*/
+ sprintf((char *)epktmsg,
+ "resend logic error: NPS, n=%d, j=%d.",n,j);
+ return(-2);
+#else
+/* Just ignore it. */
+ return(0);
+#endif /* COMMENT */
+ }
+ }
+#ifdef DEBUG
+#ifdef GFTIMER
+ if (deblog) t1 = gftimer();
+#endif /* GFTIMER */
+#endif /* DEBUG */
+
+ /* Everything ok, send the packet */
+#ifdef CK_TIMERS
+ if (timint > 0)
+ srttbl[n] = gtimer(); /* Update the timer */
+#endif /* CK_TIMERS */
+ x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len);
+
+#ifdef DEBUG
+#ifdef GFTIMER
+ if (deblog) {
+ t2 = gftimer();
+ debug(F101,"resend ttol msec","",(long)((t2-t1)*1000.0));
+ }
+#endif /* GFTIMER */
+#endif /* DEBUG */
+ debug(F101,"resend ttol returns","",x);
+
+ retrans++; /* Count a retransmission */
+ xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */
+ logpkt('S',n,s_pkt[j].pk_adr, s_pkt[j].pk_len); /* Log the resent packet */
+ return(s_pkt[j].pk_rtr); /* Return the number of retries. */
+}
+
+/* E R R P K T -- Send an Error Packet */
+
+int
+errpkt(reason) CHAR *reason; { /* ...containing the reason given */
+ extern int rtimo, state, justone;
+ int x, y;
+ czseen = 1; /* Also cancels batch */
+ state = 0; /* Reset protocol state */
+ debug(F110,"errpkt",reason,0);
+ tlog(F110,"Protocol Error:",(char *)reason,0L);
+ xxscreen(SCR_EM,0,0L,reason);
+ encstr(reason);
+ x = spack('E',pktnum,size,data);
+ ckstrncpy((char *)epktmsg,(char *)reason,PKTMSGLEN);
+ y = quiet; quiet = 1; epktsent = 1; /* Close files silently. */
+ clsif(); clsof(1);
+ quiet = y;
+/*
+ I just sent an E-packet. I'm in local mode, I was receiving a file,
+ I'm not a server, and sliding windows are in use. Therefore, there are
+ likely to be a bunch of packets already "in the pipe" on their way to me
+ by the time the remote sender gets the E-packet. So the next time I
+ CONNECT or try to start another protocol operation, I am likely to become
+ terribly confused by torrents of incoming material. To prevent this,
+ the following code soaks up packets from the connection until there is an
+ error or timeout, without wasting too much time waiting.
+
+ Exactly the same problem occurs when I am in remote mode or if I am
+ in server mode with the justone flag set. In remote mode not only
+ does the packet data potentially get echo'd back to the sender which
+ is confusing to the user in CONNECT mode, but it also may result in the
+ host performing bizarre actions such as suspending the process if ^Z is
+ unprefixed, etc.
+
+ Furthermore, thousands of packets bytes in the data stream prevent the
+ client from being able to process Telnet Kermit Option negotiations
+ properly.
+*/
+#ifdef STREAMING
+ /* Because streaming sets the timeout to 0... */
+ if (streaming) {
+ timint = rcvtimo = rtimo;
+ streaming = 0;
+ }
+#endif /* STREAMING */
+ if (what & W_RECV &&
+ (!server || (server && justone)) &&
+ (wslots > 1
+#ifdef STREAMING
+ || streaming
+#endif /* STREAMING */
+ )) {
+#ifdef GFTIMER
+ CKFLOAT oldsec, sec = (CKFLOAT) 0.0;
+#else
+ int oldsec, sec = 0;
+#endif /* GFTIMER */
+ debug(F101,"errpkt draining","",wslots);
+ xxscreen(SCR_ST,ST_MSG,0l,"Draining incoming packets, wait...");
+ while (x > -1) { /* Don't bother if no connection */
+ oldsec = sec;
+#ifdef GFTIMER
+ sec = gftimer();
+ if (oldsec != (CKFLOAT) 0.0)
+ timint = rcvtimo = (int) (sec - oldsec + 0.5);
+#else
+ sec = gtimer();
+ if (oldsec != 0)
+ timint = rcvtimo = sec - oldsec + 1;
+#endif /* GFTIMER */
+ if (timint < 1)
+ timint = rcvtimo = 1;
+ msleep(50); /* Allow a bit of slop */
+ x = rpack(); /* Read a packet */
+ if (x == 'T' || x == 'z') /* Timed out means we're done */
+ break;
+ xxscreen(SCR_PT,x,rsn,""); /* Let user know */
+ }
+ xxscreen(SCR_ST,ST_MSG,0l,"Drain complete.");
+ }
+ if ((x = (what & W_KERMIT)))
+ xitsta |= x; /* Remember what failed. */
+ success = 0;
+ return(y);
+}
+
+/* scmd() -- Send a packet of the given type */
+
+int
+#ifdef CK_ANSIC
+scmd(char t, CHAR *dat)
+#else
+scmd(t,dat) char t; CHAR *dat;
+#endif /* CK_ANSIC */
+/* scmd */ {
+ int x;
+ extern char * srimsg;
+ debug(F000,"scmd",dat,t);
+ if (encstr(dat) < 0) { /* Encode the command string */
+ srimsg = "String too long";
+ return(-1);
+ }
+ x = spack(t,pktnum,size,data);
+ debug(F101,"scmd spack","",x);
+ return(x);
+}
+
+/* Compose and Send GET packet */
+
+struct opktparm { /* O-Packet item list */
+ CHAR * opktitem;
+ struct opktparm * opktnext;
+};
+
+struct opktparm * opkthead = NULL; /* Linked list of O-packet fields */
+int opktcnt = 0; /* O-Packet counter */
+char * srimsg = NULL; /* GET-Packet error message */
+
+/* S O P K T -- Send O-Packet */
+/*
+ Sends one O-Packet each time called, using first-fit method of filling
+ the packet from linked list of parameters pointed to by opkthead.
+ To be called repeatedly until list is empty or there is an error.
+ Returns:
+ -1 on failure.
+ 0 on success and no more fields left to send.
+ 1 on success but with more fields left to be sent.
+*/
+
+int
+sopkt() {
+ int n = 0; /* Field number in this packet */
+ int rc = 0; /* Return code */
+ int len = 0; /* Data field length */
+ char c = NUL;
+ struct opktparm * o = NULL;
+ struct opktparm * t = NULL;
+ struct opktparm * prev = NULL;
+ CHAR * dsave = data;
+ int x, ssave = spsiz;
+
+ srimsg = NULL; /* Error message */
+ o = opkthead; /* Point to head of list */
+ if (!o) { /* Oops, no list... */
+ srimsg = "GET Packet Internal Error 1";
+ debug(F100,"sopkt NULL list","",0);
+ return(-1);
+ }
+ while (o) { /* Go thru linked list... */
+ c = *(o->opktitem); /* Parameter code */
+ debug(F000,"sopkt",o->opktitem,c);
+ x = encstr((CHAR *)o->opktitem);
+ debug(F111,"sopkt encstr",dsave,x);
+ if (x < 0) { /* Encode this item */
+ if (n == 0) { /* Failure, first field in packet */
+ debug(F100,"sopkt overflow","",0);
+ spsiz = ssave; /* Restore these */
+ data = dsave;
+ o = opkthead; /* Free linked list */
+ while (o) {
+ if (o->opktitem) free(o->opktitem);
+ t = o->opktnext;
+ free((char *)o);
+ o = t;
+ }
+ opkthead = NULL;
+ srimsg = "GET Packet Too Long for Server";
+ return(-1); /* Fail */
+ } else { /* Not first field in packet */
+ debug(F110,"sopkt leftover",o->opktitem,0);
+ prev = o; /* Make this one the new previous */
+ o = o->opktnext; /* Get next */
+ c = NUL; /* So we know we're not done */
+ *data = NUL; /* Erase any partial encoding */
+ continue; /* We can try this one again later */
+ }
+ }
+ n++; /* Encoding was successful */
+ debug(F111,"sopkt field",data,x);
+ len += x; /* Total data field length */
+ data += x; /* Set up for next field... */
+ spsiz -= x;
+ free(o->opktitem); /* Free item just encoded */
+ if (o == opkthead) { /* If head */
+ opkthead = o->opktnext; /* Move head to next */
+ free((char *)o); /* Free this list node */
+ o = opkthead;
+ } else { /* If not head */
+ o = o->opktnext; /* Get next */
+ prev->opktnext = o; /* Link previous to next */
+ }
+ if (c == '@') /* Loop exit */
+ break;
+ if (!o && !opkthead) { /* Set up End Of Parameters Field */
+ o = (struct opktparm *)malloc(sizeof(struct opktparm));
+ if (o) {
+ opkthead = o;
+ if (!(o->opktitem = (CHAR *)malloc(3))) {
+ free((char *)o);
+ srimsg = "GET Packet Internal Error 8";
+ return(-1);
+ }
+ ckstrncpy((char *)(o->opktitem), "@ ", 3);
+ debug(F111,"sopkt o->opktitem",o->opktitem,
+ strlen((char *)(o->opktitem)));
+ o->opktnext = NULL;
+ }
+ }
+ }
+ data = dsave; /* Restore globals */
+ spsiz = ssave;
+ debug(F110,"sopkt data",data,0);
+ debug(F101,"sopkt opktcnt","",opktcnt);
+ if (opktcnt++ > 0) {
+ if (nxtpkt() < 0) { /* Get next packet number and buffer */
+ srimsg = "GET Packet Internal Error 9";
+ return(-1);
+ }
+ }
+ debug(F101,"sopkt pktnum","",pktnum);
+ rc = spack((char)'O',pktnum,len,data); /* Send O-Packet */
+ debug(F101,"sopkt spack","",rc);
+ if (rc < 0) /* Failed */
+ srimsg = "Send Packet Failure"; /* Set message */
+ else /* Succeeded */
+ rc = (c == '@') ? 0 : 1; /* 1 = come back for more, 0 = done */
+ debug(F101,"sopkt rc","",rc);
+ return(rc);
+}
+
+/* S R I N I T -- Send GET packet */
+/*
+ Sends the appropriate GET-Class packet.
+ Returns:
+ -1 on error
+ 0 if packet sent successfully and we can move on to the next state
+ 1 if an O-packet was sent OK but more O packets still need to be sent.
+*/
+int
+srinit(reget, retrieve, opkt) int reget, retrieve, opkt; {
+ int x = 0, left = 0;
+ extern int oopts, omode;
+ CHAR * p = NULL;
+#ifdef RECURSIVE
+ extern int recursive;
+ debug(F101,"srinit recursive","",recursive);
+#endif /* RECURSIVE */
+ debug(F101,"srinit reget","",reget);
+ debug(F101,"srinit retrieve","",retrieve);
+ debug(F101,"srinit opkt","",opkt);
+ debug(F101,"srinit oopts","",oopts);
+ debug(F101,"srinit omode","",omode);
+ debug(F110,"srinit cmarg",cmarg,0);
+ srimsg = NULL;
+
+ opktcnt = 0;
+ if (!cmarg) cmarg = "";
+ if (!*cmarg) {
+ srimsg = "GET with no filename";
+ debug(F100,"srinit null cmarg","",0);
+ return(-1);
+ }
+ if (opkt) { /* Extended GET is totally different */
+ char buf[16];
+ struct opktparm * o = NULL;
+ struct opktparm * prev = NULL;
+
+ buf[0] = NUL;
+
+ /* Build O-Packet fields and send (perhaps first) O-Packet */
+
+ if (oopts > -1) { /* Write Option flags */
+ o = (struct opktparm *)malloc(sizeof(struct opktparm));
+ if (!o) {
+ srimsg = "GET Packet Internal Error 2";
+ debug(F100,"srinit malloc fail O1","",0);
+ return(-1);
+ }
+ sprintf(buf,"Ox%d",oopts); /* safe */
+ x = (int) strlen(buf+2);
+ buf[1] = tochar(x);
+ o->opktitem = (CHAR *)malloc(x + 3);
+ if (!o->opktitem) {
+ srimsg = "GET Packet Internal Error 3";
+ debug(F100,"srinit malloc fail O2","",0);
+ return(-1);
+ }
+ ckstrncpy((char *)(o->opktitem),buf,x+3);
+ o->opktnext = NULL;
+ if (!opkthead)
+ opkthead = o;
+ prev = o;
+ }
+ if (omode > -1) { /* If Xfer Mode specified, write it */
+ o = (struct opktparm *)malloc(sizeof(struct opktparm));
+ if (!o) {
+ srimsg = "GET Packet Internal Error 4";
+ debug(F100,"srinit malloc fail M1","",0);
+ return(-1);
+ }
+ sprintf(buf,"Mx%d",omode); /* safe */
+ x = (int) strlen(buf+2);
+ buf[1] = tochar(x);
+ o->opktitem = (CHAR *)malloc(x + 3);
+ if (!o->opktitem) {
+ srimsg = "GET Packet Internal Error 5";
+ debug(F100,"srinit malloc fail O2","",0);
+ return(-1);
+ }
+ ckstrncpy((char *)(o->opktitem),buf,x+3);
+ o->opktnext = NULL;
+ if (!opkthead)
+ opkthead = o;
+ else
+ prev->opktnext = o;
+ prev = o;
+ }
+
+ /* Same deal for oname and opath eventually but not needed now... */
+
+ x = strlen(cmarg); /* Now do filename */
+ if (x > spsiz - 4) {
+ srimsg = "GET Packet Too Long for Server";
+ return(-1);
+ }
+ o = (struct opktparm *)malloc(sizeof(struct opktparm));
+ if (!o) {
+ srimsg = "GET Packet Internal Error 6";
+ debug(F100,"srinit malloc fail F1","",0);
+ return(-1);
+ }
+ left = x + 6;
+ o->opktitem = (CHAR *)malloc(left + 1);
+ if (!o->opktitem) {
+ srimsg = "GET Packet Internal Error 7";
+ debug(F100,"srinit malloc fail F2","",0);
+ return(-1);
+ }
+ p = o->opktitem;
+ *p++ = 'F';
+ left--;
+ if (x > 94) { /* Too long for normal length */
+ *p++ = SYN; /* Escape length with Ctrl-V */
+ *p++ = tochar(x / 95);
+ *p++ = tochar(x % 95);
+ left -= 3;
+ } else { /* Normal encoding for 94 or less */
+ *p++ = tochar(x);
+ left--;
+ }
+ ckstrncpy((char *)p,cmarg,left); /* Copy the filename */
+ o->opktnext = NULL;
+ if (!opkthead)
+ opkthead = o;
+ else
+ prev->opktnext = o;
+ prev = o;
+
+ /* End of Parameters */
+
+ prev->opktnext = NULL; /* End of list. */
+ return(sopkt());
+ }
+
+ /* Not Extended GET */
+
+ if (encstr((CHAR *)cmarg) < 0) { /* Encode the filename. */
+ srimsg = "GET Packet Too Long for Server";
+ return(-1);
+ }
+ if (retrieve) { /* Send the packet. */
+#ifdef RECURSIVE
+ if (recursive)
+ x = spack((char)'W',pktnum,size,data); /* GET /DELETE /RECURSIVE */
+ else
+#endif /* RECURSIVE */
+ x = spack((char)'H',pktnum,size,data); /* GET /DELETE */
+ }
+#ifdef RECURSIVE
+ else if (recursive)
+ x = spack((char)'V',pktnum,size,data); /* GET /RECURSIVE */
+#endif /* RECURSIVE */
+ else
+ x = spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* GET */
+ if (x < 0)
+ srimsg = "Send Packet Failure";
+ return(x < 0 ? x : 0);
+}
+
+
+/* K S T A R T -- Checks for a Kermit packet while in terminal mode. */
+
+/* (or command mode...) */
+
+#ifdef CK_AUTODL
+int
+#ifdef CK_ANSIC
+kstart(CHAR ch)
+#else
+kstart(ch) CHAR ch;
+#endif /* CK_ANSIC */
+/* kstart */ {
+ static CHAR * p = NULL;
+
+#ifdef OS2
+ static CHAR * pk = NULL;
+#endif /* OS2 */
+ ch &= 0177; /* Strip 8th bit */
+
+ /* Because we're in cooked mode at the command prompt... */
+
+ if (ch == LF) {
+ debug(F110,"kstart","ch == LF",0);
+ if ((what == W_COMMAND || what == W_INIT || what == W_NOTHING)) {
+ if (eol == CR) {
+ ch = eol;
+ debug(F110,"kstart","ch = CR",0);
+ }
+ }
+ }
+
+#ifdef OS2
+ if (adl_kmode == ADL_STR) {
+ if (!ch)
+ return(0);
+ if (!pk)
+ pk = adl_kstr;
+
+ if (ch == *pk) {
+ pk++;
+ if (*pk == '\0') {
+ pk = adl_kstr;
+ debug(F100, "kstart Kermit Start String","",0);
+ return(PROTO_K + 1);
+ }
+ } else
+ pk = adl_kstr;
+ }
+#endif /* OS2 */
+
+ if (ch == stchr) { /* Start of packet */
+ kstartactive = 1;
+ p = ksbuf;
+ *p = ch;
+ debug(F101,"kstart SOP","",ch);
+ } else if (ch == eol) { /* End of packet */
+ kstartactive = 0;
+ if (p) {
+ debug(F101,"kstart EOL","",ch);
+ p++;
+ if (p - ksbuf < 94 ) {
+ int rc = 0;
+ *p++ = ch;
+ *p = NUL;
+ rc = chkspkt((char *)ksbuf);
+ debug(F111,"kstart EOP chkspkt", ksbuf, rc);
+ p = NULL;
+ if (!rc) return(0);
+ if (rc == 2) rc = -1;
+ debug(F111,"kstart ksbuf",ksbuf,rc);
+ return(rc);
+ } else {
+ debug(F110,"kstart","p - ksbuf >= 94",0);
+ p = NULL;
+ }
+ }
+ } else if (p) {
+ if (ch < SP)
+ kstartactive = 0;
+ p++;
+ if (p - ksbuf < 94) {
+ *p = ch;
+ } else {
+ p = NULL;
+ debug(F110,"kstart","p - ksbuf >= 94",0);
+ }
+ }
+ return(0);
+}
+
+#ifdef CK_XYZ
+
+/* Z S T A R T -- Checks for a ZMODEM packet while in terminal mode. */
+
+int
+#ifdef CK_ANSIC
+zstart(CHAR ch)
+#else
+zstart(ch) CHAR ch;
+#endif /* CK_ANSIC */
+/* zstart */ {
+ static CHAR * matchstr = (CHAR *) "\030B00";
+ /* "rz\r**\030B00000000000000\r\033J\021"; */
+ static CHAR * p = NULL;
+ extern int inserver;
+
+ if (inserver)
+ return(0);
+
+ if (!ch)
+ return(0);
+ if (!p) {
+#ifdef OS2
+ p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
+#else
+ p = matchstr;
+#endif /* OS2 */
+ }
+ if (ch == *p) {
+ p++;
+ if (*p == '\0') {
+#ifdef OS2
+ if (adl_zmode == ADL_PACK) {
+ p = matchstr;
+ debug(F100, "zstart Zmodem SOP","",0);
+ } else {
+ p = adl_zstr;
+ debug(F100, "zstart Zmodem Start String","",0);
+ }
+#else
+ p = matchstr;
+ debug(F100, "zstart Zmodem SOP","",0);
+#endif /* OS2 */
+ return(PROTO_Z + 1);
+ }
+ } else {
+#ifdef OS2
+ p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
+#else
+ p = matchstr;
+#endif /* OS2 */
+ }
+ return(0);
+}
+#endif /* CK_XYZ */
+
+#ifndef NOICP
+#ifdef CK_APC
+/* A U T O D O W N */
+
+#ifdef CK_ANSIC
+VOID
+autodown(int ch)
+#else
+VOID
+autodown(ch) int ch;
+#endif /* CK_ANSIC */
+/* autodown */ {
+
+/* The Kermit and Zmodem Auto-download calls go here */
+
+ extern int justone; /* From protocol module */
+ extern int debses, protocol, apcactive, autodl, inautodl;
+#ifdef DCMDBUF
+ extern char *apcbuf;
+#else
+ extern char apcbuf[];
+#endif /* DCMDBUF */
+#ifdef OS2
+ extern int apclength, term_io;
+#endif /* OS2 */
+ int k = 0;
+
+ if ((autodl || inautodl
+#ifdef IKS_OPTION
+ || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+#endif /* IKS_OPTION */
+ ) && !debses) {
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+ extern int p_avail;
+#else
+ int p_avail = 1;
+#endif /* XYZ_INTERNAL */
+ if (p_avail && zstart((CHAR) ch)) {
+ debug(F100, "Zmodem download","",0);
+#ifdef OS2
+#ifndef NOTERM
+ apc_command(APC_LOCAL,"receive /protocol:zmodem");
+#endif /* NOTERM */
+#else /* OS2 */
+ ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
+ apcactive = APC_LOCAL;
+#endif /* OS2 */
+ return;
+ }
+#endif /* CK_XYZ */
+
+ /* First try... */
+ k = kstart((CHAR) ch);
+ if (
+#ifdef NOSERVER
+ k > 0
+#else /* NOSERVER */
+ k
+#endif /* NOSERVER */
+ ) { /* We saw a valid S or I packet */
+ if (k < 0) { /* Stuff RECEIVE into APC buffer */
+ justone = 1;
+ switch (protocol) {
+#ifdef CK_XYZ
+ case PROTO_G:
+ ckstrncpy(apcbuf,
+ "set proto kermit, server, set protocol g",
+ APCBUFLEN
+ );
+ break;
+ case PROTO_X:
+ ckstrncpy(apcbuf,
+ "set proto kermit,server,set proto xmodem",
+ APCBUFLEN
+ );
+ break;
+ case PROTO_XC:
+ ckstrncpy(apcbuf,
+ "set proto kermit,server,set proto xmodem-crc",
+ APCBUFLEN
+ );
+ break;
+ case PROTO_Y:
+ ckstrncpy(apcbuf,
+ "set proto kermit,server, set protocol y",
+ APCBUFLEN
+ );
+ break;
+ case PROTO_Z:
+ ckstrncpy(apcbuf,
+ "set proto kermit,server,set proto zmodem",
+ APCBUFLEN
+ );
+ break;
+#endif /* CK_XYZ */
+ case PROTO_K:
+ ckstrncpy(apcbuf,"server",APCBUFLEN);
+ break;
+ }
+ } else {
+ justone = 0;
+ ckstrncpy(apcbuf,"receive /protocol:kermit",APCBUFLEN);
+ }
+#ifdef OS2
+#ifndef NOTERM
+ apc_command(APC_LOCAL,apcbuf);
+#endif /* NOTERM */
+#else /* OS2 */
+ ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
+ apcactive = APC_LOCAL;
+#endif /* OS2 */
+ return;
+ }
+ }
+}
+#endif /* CK_APC */
+#endif /* NOICP */
+
+/* C H K S P K T -- Check if buf contains a valid S or I packet */
+
+int
+chkspkt(packet) char *packet; {
+ int i;
+ int buflen;
+ int len = -1;
+ CHAR chk;
+ char type = 0;
+ char *s = NULL;
+ char *buf = NULL;
+ char tmpbuf[100]; /* Longest S/I packet is about 30 */
+
+ if (!packet) return(0);
+ buflen = ckstrncpy(tmpbuf,packet,100); /* Make a pokeable copy */
+ if (buflen < 5) return(0); /* Too short */
+ if (buflen > 100) return(0); /* Too long to be an S or I packet */
+ s = buf = tmpbuf; /* Point to beginning of copy */
+
+ if (*s++ != stchr) return(0); /* SOH */
+ len = xunchar(*s++); /* Length */
+ if (len < 0) return(0);
+ if (*s++ != SP) return(0); /* Sequence number */
+ type = *s++; /* Type */
+ if (type != 'S' && type != 'I')
+ return(0);
+ if (buflen < len + 2) return(0);
+ s += (len - 3); /* Position of checksum */
+ chk = (CHAR) (*s); /* Checksum */
+ *s = NUL; /* Temporarily null-terminate data field */
+ if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) { /* Check it */
+ /*
+ In C-Kermit 9.0 and later, an S or I packet can have a
+ Type 3 Block check ("help set block-check" for details).
+ */
+ unsigned crc; /* Failed... Try Type 3 block check */
+ *s = chk; /* Replace last byte */
+ s -= 2; /* Back up two bytes */
+ crc = (xunchar(s[0]) << 12) /* Convert 3 bytes to numeric CRC */
+ | (xunchar(s[1]) << 6)
+ | (xunchar(s[2]));
+ chk = (CHAR)(*s); /* Copy 1st byte of 3-byte CRC */
+ *s = NUL; /* Null-terminate data field */
+ if (crc != chk3((CHAR *)(buf+1),strlen(buf+1)))
+ return(0);
+ }
+ return(type == 'S' ? 1 : 2);
+}
+#endif /* CK_AUTODL */
+
+/* R P A C K -- Read a Packet */
+
+/*
+ rpack reads a packet and returns the packet type, or else Q if the
+ packet was invalid, or T if a timeout occurred. Upon successful return,
+ sets the values of global rsn (received sequence number), rln (received
+ data length), and rdatap (pointer to null-terminated data field), and
+ returns the packet type. NOTE: This is an inner-loop function so must be
+ efficient. Protect function calls by if-tests where possible, e.g.
+ "if (pktlog) logpkt(...);".
+*/
+int
+rpack() {
+ register int i, j, x, lp; /* Local variables */
+#ifdef CKTUNING
+ unsigned int chk;
+#endif /* CKTUNING */
+ int k, type, chklen;
+ unsigned crc;
+ CHAR pbc[5]; /* Packet block check */
+ CHAR *sohp; /* Pointer to SOH */
+ CHAR e; /* Packet end character */
+
+#ifdef GFTIMER
+ CKFLOAT t1 = 0.0, t2 = 0.0;
+#endif /* GFTIMER */
+
+ debug(F101,"rpack pktnum","",pktnum);
+
+#ifndef OLDCHKINT
+ if (chkint() < 0) /* Check for console interrupts. */
+ return('z');
+#endif /* OLDCHKINT */
+
+ k = getrbuf(); /* Get a new packet input buffer. */
+ debug(F101,"rpack getrbuf","",k);
+ if (k < 0) { /* Return like this if none free. */
+ return(-1);
+ }
+ recpkt = r_pkt[k].bf_adr;
+ *recpkt = '\0'; /* Clear receive buffer. */
+ sohp = recpkt; /* Initialize pointers to it. */
+ rdatap = recpkt;
+ rsn = rln = -1; /* In case of failure. */
+ e = (turn) ? turnch : eol; /* Use any handshake char for eol */
+
+/* Try to get a "line". */
+
+#ifdef CK_AUTODL
+ debug(F110,"rpack ksbuf",ksbuf,0);
+ if (ksbuf[0]) { /* Kermit packet already */
+ int x; /* collected for us in CONNECT mode */
+ CHAR *s1 = recpkt, *s2 = ksbuf;
+ j = 0;
+ while (*s2) { /* Copy and get length */
+ *s1++ = *s2++; /* No point optimizing this since */
+ j++; /* it's never more than ~20 chars */
+ }
+ *s1 = NUL;
+#ifdef PARSENSE
+ x = parchk(recpkt, stchr, j); /* Check parity */
+ debug(F000,"autodownload parity","",parity);
+ debug(F000,"autodownload parchk","",x);
+ if (x > 0 && parity != x) {
+ autopar = 1;
+ parity = x;
+ }
+#endif /* PARSENSE */
+ ksbuf[0] = NUL; /* Don't do this next time! */
+
+ } else { /* Normally go read a packet */
+#endif /* CK_AUTODL */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"rpack timint","",timint);
+ debug(F101,"rpack rcvtimo","",rcvtimo);
+#ifdef STREAMING
+ debug(F101,"rpack streaming","",streaming);
+#endif /* STREAMING */
+#ifdef GFTIMER
+ /* Measure how long it takes to read a packet */
+ t1 = gftimer();
+#endif /* GFTIMER */
+ }
+#endif /* DEBUG */
+
+/* JUST IN CASE (otherwise this could clobber streaming) */
+
+ if ((timint == 0
+#ifdef STREAMING
+ || streaming
+#endif /* STREAMING */
+ ) && (rcvtimo != 0)) {
+ debug(F101,"rpack timint 0 || streaming but rcvtimo","",rcvtimo);
+ rcvtimo = 0;
+ }
+
+#ifdef PARSENSE
+#ifdef UNIX
+/*
+ So far the final turn argument is only for ck[uvdl]tio.c. Should be added
+ to the others too. (turn == handshake character.)
+*/
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
+#else
+#ifdef VMS
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
+#else
+#ifdef datageneral
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
+#else
+#ifdef STRATUS
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
+#else
+#ifdef OS2
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
+#else
+#ifdef OSK
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
+#else
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr);
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIX */
+ if (parity != 0 && parity != 's' && ttprty != 0) {
+ if (parity != ttprty) autopar = 1;
+ parity = ttprty;
+ }
+#else /* !PARSENSE */
+ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e);
+#endif /* PARSENSE */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"rpack ttinl len","",j);
+#ifdef GFTIMER
+ t2 = gftimer();
+ debug(F101,"rpack ttinl msec","",(long)((t2-t1)*1000.0));
+#endif /* GFTIMER */
+ }
+#endif /* DEBUG */
+
+#ifdef STREAMING
+ if (streaming && sndtyp == 'D' && j == 0)
+ return('Y');
+#endif /* STREAMING */
+
+ if (j < 0) {
+ /* -1 == timeout, -2 == ^C, -3 == connection lost or fatal i/o */
+ debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
+ freerbuf(k); /* Free this buffer */
+ if (j < -1) { /* Bail out if ^C^C typed. */
+ if (j == -2) {
+ interrupted = 1;
+ debug(F101,"rpack ^C server","",server);
+ debug(F101,"rpack ^C en_fin","",en_fin);
+ } else if (j == -3) {
+ fatalio = 1;
+ debug(F101,"rpack fatalio","",en_fin);
+ }
+ return(j);
+ }
+ if (nakstate) /* j == -1 is a read timeout */
+ xxscreen(SCR_PT,'T',(long)winlo,"");
+ else
+ xxscreen(SCR_PT,'T',(long)pktnum,"");
+ logpkt('r',-1,(CHAR *)"<timeout>",0);
+ if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */
+ return('T');
+ }
+#ifdef CK_AUTODL
+ }
+#endif /* CK_AUTODL */
+
+ rpktl = j;
+ tlci += j; /* All OK, Count the characters. */
+ flci += j;
+
+/* Find start of packet */
+
+#ifndef PARSENSE
+ for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
+ sohp++; /* Find mark */
+ if (i++ >= j) { /* Didn't find it. */
+ logpkt('r',-1,"<timeout>",0);
+ freerbuf(k);
+ return('T');
+ }
+#else
+ i = 1; /* ttinl does this for us */
+#endif /* PARSENSE */
+
+ rpackets++; /* Count received packet. */
+ lp = i; /* Remember LEN position. */
+ if ((j = xunchar(recpkt[i++])) == 0) { /* Get packet length. */
+ if ((j = lp+5) > MAXRP) { /* Long packet */
+ return('Q'); /* Too long */
+ }
+
+#ifdef CKTUNING
+ /* Save some function-call and loop overhead... */
+#ifdef COMMENT
+ /* ttinl() already removed parity */
+ if (parity)
+#endif /* COMMENT */
+ chk = (unsigned) ((unsigned) recpkt[i-1] +
+ (unsigned) recpkt[i] +
+ (unsigned) recpkt[i+1] +
+ (unsigned) recpkt[i+2] +
+ (unsigned) recpkt[i+3]
+ );
+#ifdef COMMENT
+ else
+ chk = (unsigned) ((unsigned) (recpkt[i-1] & 077) +
+ (unsigned) (recpkt[i] & 077) +
+ (unsigned) (recpkt[i+1] & 077) +
+ (unsigned) (recpkt[i+2] & 077) +
+ (unsigned) (recpkt[i+3] & 077)
+ );
+#endif /* COMMENT */
+ if (xunchar(recpkt[j]) != ((((chk & 0300) >> 6) + chk) & 077))
+#else
+ x = recpkt[j]; /* Header checksum. */
+ recpkt[j] = '\0'; /* Calculate & compare. */
+ if (xunchar(x) != chk1(recpkt+lp,5))
+#endif /* CKTUNING */
+ {
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:hdr>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet header");
+ return('Q');
+ }
+#ifndef CKTUNING
+ recpkt[j] = x; /* Checksum ok, put it back. */
+#endif /* CKTUNING */
+ rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
+ j = 3; /* Data offset. */
+ } else if (j < 3) {
+ debug(F101,"rpack packet length less than 3","",j);
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:len>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet length");
+ return('Q');
+ } else {
+ rln = j - bctl - 2; /* Regular packet */
+ j = 0; /* No extended header */
+ }
+ rsn = xunchar(recpkt[i++]); /* Sequence number */
+ if (pktlog) /* Save a function call! */
+ logpkt('r',rsn,sohp,rln+bctl+j+4);
+ if (rsn < 0 || rsn > 63) {
+ debug(F101,"rpack bad sequence number","",rsn);
+ freerbuf(k);
+ if (pktlog)
+ logpkt('r',rsn,(CHAR *)"<crunched:seq>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"Bad sequence number");
+ return('Q');
+ }
+/*
+ If this packet has the same type as the packet just sent, assume it is
+ an echo and ignore it. Don't even bother with the block check calculation:
+ even if the packet is corrupted, we don't want to NAK an echoed packet.
+ Nor must we NAK an ACK or NAK.
+*/
+ type = recpkt[i++]; /* Get packet's TYPE field */
+ if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
+ debug(F000,"rpack echo","",type); /* If it's an echo */
+ freerbuf(k); /* Free this buffer */
+ logpkt('#',rsn,(CHAR *)"<echo:ignored>",0);
+ return('e'); /* Return special (lowercase) code */
+ }
+/*
+ Separate the data from the block check, accounting for the case where
+ a packet was retransmitted after the block check switched. The "Type 3
+ Forced" business is new to C-Kermit 9.0.
+*/
+ if (bctf) { /* Type 3 forced on all packets */
+ bctl = chklen = 3;
+ } else if ((type == 'I' || type == 'S')) { /* Otherwise... */
+ if (recpkt[11] == '5') { /* Sender is forcing Type 3 */
+ bctf = 1; /* So we will too */
+ bctl = chklen = 3;
+ debug(F100,"RECOGNIZE BLOCK CHECK TYPE 5","",0);
+ } else { /* Normal case */
+ /* I & S packets always have type 1 */
+ chklen = 1;
+ rln = rln + bctl - 1;
+ }
+ } else if (type == 'N') { /* A NAK packet never has data */
+ chklen = xunchar(recpkt[lp]) - 2;
+ if (chklen < 1 || chklen > 3) { /* JHD 13 Apr 2010 */
+ debug(F101,"rpack bad nak chklen","",chklen);
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:chklen>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"(bad nak)");
+ return('Q');
+ }
+ rln = rln + bctl - chklen;
+ } else chklen = bctl;
+#ifdef DEBUG
+ if (deblog) { /* Save 2 function calls */
+ debug(F101,"rpack bctl","",bctl);
+ debug(F101,"rpack chklen","",chklen);
+ }
+#endif /* DEBUG */
+ i += j; /* Buffer index of DATA field */
+ rdatap = recpkt+i; /* Pointer to DATA field */
+ if ((j = rln + i) > r_pkt[k].bf_len) { /* Make sure it fits */
+ debug(F101,"packet too long","",j);
+ freerbuf(k);
+ logpkt('r',rsn,(CHAR *)"<overflow>",0);
+ return('Q');
+ }
+ for (x = 0; x < chklen; x++) /* Copy the block check */
+ pbc[x] = recpkt[j+x]; /* 3 bytes at most. */
+ pbc[x] = '\0'; /* Null-terminate block check string */
+ recpkt[j] = '\0'; /* and the packet Data field. */
+
+ if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */
+ chklen = 4; /* (chklen is now a misnomer...) */
+ debug(F100,"rpack block check B","",0);
+ }
+ switch (chklen) { /* Check the block check */
+ case 1: /* Type 1, 6-bit checksum */
+ if (xunchar(*pbc) != chk1(recpkt+lp,j-lp)) {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"checked chars",recpkt+lp,0);
+ debug(F101,"block check (1)","",(int) xunchar(*pbc));
+ debug(F101,"should be (1)","",chk1(recpkt+lp,j-lp));
+ }
+#endif /* DEBUG */
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:chk1>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
+ return('Q');
+ }
+ break;
+ case 2: /* Type 2, 12-bit checksum */
+ x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
+ if (x != chk2(recpkt+lp,j-lp)) { /* No match */
+ if (type == 'E') { /* Allow E packets to have type 1 */
+ recpkt[j++] = pbc[0];
+ recpkt[j] = '\0';
+ if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
+ break;
+ else
+ recpkt[--j] = '\0';
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"checked chars",recpkt+lp,0);
+ debug(F101,"block check (2)","", x);
+ debug(F101,"should be (2)","", (int) chk2(recpkt+lp,j-lp));
+ }
+#endif /* DEBUG */
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:chk2>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
+ return('Q');
+ }
+ break;
+ case 3: /* Type 3, 16-bit CRC */
+ crc = (xunchar(pbc[0]) << 12)
+ | (xunchar(pbc[1]) << 6)
+ | (xunchar(pbc[2]));
+ if (crc != chk3(recpkt+lp,j-lp)) {
+ if (type == 'E') { /* Allow E packets to have type 1 */
+ recpkt[j++] = pbc[0];
+ recpkt[j++] = pbc[1];
+ recpkt[j] = '\0';
+ if (xunchar(pbc[2]) == chk1(recpkt+lp,j-lp))
+ break;
+ else { j -=2; recpkt[j] = '\0'; }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"checked chars",recpkt+lp,0);
+ debug(F101,"block check (3)","",crc);
+ debug(F101,"should be (3)","",(int) chk3(recpkt+lp,j-lp));
+ }
+#endif /* DEBUG */
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:chk3>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"CRC error");
+ return('Q');
+ }
+ break;
+ case 4: /* Type 4 = Type 2, no blanks. */
+ x = (unsigned)((xunchar(*pbc) - 1) << 6) |
+ (unsigned)(xunchar(pbc[1]) - 1);
+ if (x != chk2(recpkt+lp,j-lp)) {
+ if (type == 'E') { /* Allow E packets to have type 1 */
+ recpkt[j++] = pbc[0];
+ recpkt[j] = '\0';
+ if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
+ break;
+ else
+ recpkt[--j] = '\0';
+ }
+ debug(F101,"bad type B block check","",x);
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:chkb>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
+ return('Q');
+ }
+ break;
+ default: /* Shouldn't happen... */
+ freerbuf(k);
+ logpkt('r',-1,(CHAR *)"<crunched:chkx>",0);
+ xxscreen(SCR_PT,'%',(long)pktnum,"(crunched)");
+ return('Q');
+ }
+ debug(F101,"rpack block check OK","",rsn);
+
+/* Now we can believe the sequence number, and other fields. */
+/* Here we violate strict principles of layering, etc, and look at the */
+/* packet sequence number. If there's already a packet with the same */
+/* number in the window, we remove this one so that the window will not */
+/* fill up. */
+
+ if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */
+ retrans++; /* Count it for statistics */
+ debug(F101,"rpack got dup","",rsn);
+ logpkt('r',rsn,(CHAR *)"<duplicate>",0);
+ freerbuf(x); /* Free old buffer, keep new packet. */
+ r_pkt[k].pk_rtr++; /* Count this as a retransmission. */
+ }
+
+/* New packet, not seen before, enter it into the receive window. */
+
+#ifdef CK_TIMERS
+ if (timint > 0)
+ rrttbl[rsn] = gtimer(); /* Timestamp */
+#endif /* CK_TIMERS */
+
+ rseqtbl[rsn] = k; /* Make back pointer */
+ r_pkt[k].pk_seq = rsn; /* Record in packet info structure */
+ r_pkt[k].pk_typ = type; /* Sequence, type,... */
+ r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */
+ if (local) { /* Save a function call! */
+ int x = 0;
+ if (fdispla != XYFD_N) x = 1;
+ if (fdispla == XYFD_B && (type == 'D' || sndtyp == 'D')) x = 0;
+ if (x) /* Update screen */
+ xxscreen(SCR_PT,(char)type,(long)rsn,(char *)sohp);
+ }
+ return(type); /* Return packet type */
+}
+
+/* L O G P K T -- Log packet number n, pointed to by s. */
+
+/* c = 's' (send) or 'r' (receive) */
+
+VOID
+#ifdef CK_ANSIC
+logpkt(char c,int n, CHAR *s, int len)
+#else
+logpkt(c,n,s,len) char c; int n; CHAR *s; int len;
+#endif /* CK_ANSIC */
+/* logpkt */ {
+ char plog[20];
+ if (!s) s = (CHAR *)"";
+ if (pktlog) if (chkfn(ZPFILE) > 0) {
+ if (n < 0) /* Construct entry header */
+ sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); /* safe */
+ else
+ sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); /* safe */
+ if (zsoutx(ZPFILE,plog,(int)strlen(plog)) < 0) {
+ pktlog = 0;
+ return;
+ } else {
+ if (len == 0)
+ len = strlen((char *)s);
+ if (len > 0) {
+ char * p; /* Make SOP printable */
+ int x; /* so we can look at logs without */
+ p = dbchr(*s); /* triggering autodownload. */
+ x = strlen(dbchr(*s));
+ if (*s < 32 || (*s > 127 && *s < 160)) {
+ if (zsoutx(ZPFILE,p,x) < 0) {
+ pktlog = 0;
+ return;
+ } else {
+ len--;
+ s++;
+ }
+ }
+ }
+ if (zsoutx(ZPFILE,(char *)s,len) < 0) {
+ pktlog = 0;
+ return;
+ } else if (zsoutx(ZPFILE,
+#ifdef UNIX
+ "\n", 1
+#else
+#ifdef datageneral
+ "\n", 1
+#else
+#ifdef OSK
+ "\r", 1
+#else
+#ifdef MAC
+ "\r", 1
+#else
+ "\015\012", 2
+#endif /* MAC */
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* UNIX */
+ ) < 0) {
+ pktlog = 0;
+ }
+ }
+ }
+}
+
+/* T S T A T S -- Record statistics in transaction log */
+
+VOID
+tstats() {
+ char *tp = NULL;
+#ifdef GFTIMER
+ CKFLOAT xx; /* Elapsed time divisor */
+#endif /* GFTIMER */
+
+ debug(F101,"tstats xfsecs","",xfsecs);
+ debug(F101,"tstats filcnt","",filcnt);
+ if (filcnt == 1) { /* Get timing for statistics */
+ tsecs = xfsecs; /* Single file, we already have it */
+#ifdef GFTIMER
+ debug(F101,"tstats fpxfsecs","",(int)fpxfsecs);
+ fptsecs = fpxfsecs;
+#endif /* GFTIMER */
+ } else { /* Multiple files */
+ tsecs = gtimer(); /* Get current time */
+#ifdef GFTIMER
+ fptsecs = gftimer();
+#endif /* GFTIMER */
+ }
+#ifdef GFTIMER
+ if (fptsecs <= GFMINTIME) /* Calculate CPS */
+ fptsecs = (CKFLOAT) GFMINTIME;
+ debug(F101,"tstats fptsecs","",(int)fptsecs);
+ xx = (CKFLOAT) tfc / fptsecs;
+ if (sizeof(long) <= 4) { /* doesn't account for 16-bit longs */
+ if (xx > 2147483647.0)
+ tfcps = 2147483647L; /* 31 bits */
+ else
+ tfcps = (long) xx;
+ } else
+ tfcps = (long) xx;
+#else
+ if (tsecs < 2L)
+ tsecs = 1L;
+ debug(F101,"tstats tsecs","",tsecs);
+ tfcps = tfc / tsecs;
+#endif /* GFTIMER */
+
+ ztime(&tp); /* Get time stamp */
+ tlog(F100,"","",0L); /* Leave a blank line */
+ tlog(F110,"Transaction complete",tp,0L); /* Record it */
+
+ if (filcnt < 1) return; /* If no files, done. */
+
+/* If multiple files, record character totals for all files */
+
+ if (filcnt > 1) {
+ tlog(F101," files transferred ","",filcnt - filrej);
+ tlog(F101," total file characters ","",tfc);
+ tlog(F101," communication line in ","",tlci);
+ tlog(F101," communication line out ","",tlco);
+ }
+
+/* Record timing info for one or more files */
+
+#ifdef GFTIMER
+ if (filcnt - filrej == 1) {
+ tlog(F101," elapsed time (seconds) ","",(long) fpxfsecs);
+ tlog(F101," effective data rate ","",filcps);
+ } else {
+ tlog(F101," elapsed time (seconds) ","",(long) fptsecs);
+ tlog(F101," effective data rate ","",(long) xx);
+ }
+#else
+ tlog(F101," elapsed time (seconds) ","",tsecs);
+ if (tsecs > 0)
+ tlog(F101," effective data rate ","",(tfc / tsecs));
+#endif /* GFTIMER */
+
+ tlog(F100,"","",0L); /* Leave a blank line */
+}
+
+/* F S T A T S -- Record file statistics in transaction log */
+
+VOID
+fcps() {
+#ifdef GFTIMER
+ double xx;
+ fpxfsecs = gftimer() - fpfsecs;
+ if (fpxfsecs <= GFMINTIME)
+ fpxfsecs = (CKFLOAT) GFMINTIME;
+ xx = (CKFLOAT) ffc / fpxfsecs;
+ if (sizeof(long) <= 4) {
+ if (xx > 2147483647.0)
+ tfcps = 2147483647L; /* 31 bits */
+ else
+ filcps = (long) xx;
+ } else
+ filcps = (long) xx;
+ if (sizeof(int) >= 4)
+ xfsecs = (int) fpxfsecs;
+ else if (fpxfsecs < 32768.0)
+ xfsecs = (int) fpxfsecs;
+ else
+ xfsecs = 32767;
+#else /* GFTIMER */
+ xfsecs = gtimer() - fsecs;
+ if (xfsecs < 1L) xfsecs = 1L;
+ filcps = ffc / xfsecs;
+#endif /* GFTIMER */
+}
+
+VOID
+fstats() {
+ tfc += ffc;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"fstats tfc","",tfc);
+ debug(F101,"fstats what","",what);
+ debug(F110,"fstats epktmsg",epktmsg,0);
+ }
+#endif /* DEBUG */
+#ifdef TLOG
+ if (!discard && !cxseen && !czseen && what != W_NOTHING && !*epktmsg)
+ tlog(F101," complete, size","",ffc);
+#endif /* TLOG */
+}
+
+#endif /* NOXFER */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcfn3.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcfn3.c
new file mode 100644
index 0000000..2d58a56
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcfn3.c
@@ -0,0 +1,2606 @@
+/* C K C F N 3 -- Packet buffer management for C-Kermit */
+
+/* (plus assorted functions tacked on at the end) */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+/*
+ Note -- if you change this file, please amend the version number and date at
+ the top of ckcfns.c accordingly.
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckcxla.h"
+
+/* C K M K D I R -- Create a directory */
+/*
+ Call with:
+ int fc = 0 to create, nonzero to remove, a directory.
+ char * s = pointer to name of directory to create or remove.
+ char ** r = address of pointer to return name or message.
+ int m = 1 to print error messages, 0 to be silent.
+ int cvt = 1 means convert s from standard format to local format;
+ 0 means use s as is.
+ Returns:
+ 0 on success (directory was created or removed).
+ -1 when attempt to create the directory failed.
+ -2 on internal error (e.g. no code for creating directories).
+ On success, the name is pointed to by p.
+ On failure, the reason is pointed to by p.
+*/
+#ifdef CK_MKDIR
+static char ckmkdbuf[CKMAXPATH+1];
+#else
+#ifdef datageneral
+static char ckmkdbuf[CKMAXPATH+1];
+#endif /* datageneral */
+#endif /* CK_MKDIR */
+
+#ifdef CK_MKDIR
+int
+ckmkdir(fc,s,r,m,cvt) int fc; char * s; char ** r; int m; int cvt; {
+ int x, rc = -2;
+ char tmpbuf[CKMAXPATH+1];
+ char buf2[CKMAXPATH+1];
+ if (!s) s = "";
+ debug(F110,"ckmkdir 1 fc",s,fc);
+ if (!*s) {
+ ckmakmsg(ckmkdbuf,
+ CKMAXPATH+1,
+ (fc == 0) ? "mkdir" : "rmdir",
+ ": no name given",
+ NULL,
+ NULL
+ );
+ *r = ckmkdbuf;
+ return(-2);
+ }
+#ifdef datageneral
+/* Come back and make this nicer later if anybody notices */
+ if (fc == 0) { /* mkdir */
+ rc = createdir(s,0);
+ } else { /* rmdir */
+ /* AOS/VS rmdir() is a no-op. */
+ ckmakmsg(tmpbuf,CKMAXPATH+1,"delete ",s,NULL,NULL);
+ debug(F110,"ckmkdir 2",tmpbuf,0);
+ rc = system(tmpbuf);
+ }
+ *r = NULL;
+#else /* not datageneral */
+
+/* First make sure the name has an acceptable directory-name format */
+
+#ifdef VMS
+ {
+ char *p = s;
+ int lb = 0, rb = 0, sl = 0;
+ while (*p) {
+ if (*p == '[' || *p == '<') lb++; /* Count brackets */
+ else if (*p == ']' || *p == '>') rb++;
+ else if (*p == '/') sl++; /* and slashes */
+ p++;
+ }
+ if (lb != 1 && rb != 1 && sl == 0 && p > s && *(p-1) != ':') {
+ /* Probably just a word - convert to VMS format */
+ ckmakmsg(buf2,
+ CKMAXPATH+1,
+ "[",
+ (*s == '.') ? "" : ".",
+ s,
+ "]"
+ );
+ s = buf2;
+ } else if (lb == 0 && rb == 0 && sl != 0 && p > s && *(p-1) != ':') {
+ int flag = 0;
+ /* Seems to be in UNIX format */
+ x = strlen(s);
+ if (x > 0 && s[x-1] != '/')
+ flag = 1;
+ ckmakmsg(buf2,CKMAXPATH+1,s,flag ? "/" : "",NULL,NULL);
+ s = buf2;
+ }
+ if (s == buf2) {
+ ckstrncpy(tmpbuf,s,CKMAXPATH+1);
+ s = tmpbuf;
+ }
+ debug(F110,"ckmkdir 2+VMS",s,0);
+ }
+#else
+#ifdef UNIXOROSK
+#ifdef DTILDE
+ s = tilde_expand(s);
+#endif /* DTILDE */
+ ckstrncpy(tmpbuf,s,CKMAXPATH+1);
+ s = tmpbuf;
+ x = strlen(s);
+ if (x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */
+ s[x] = '/';
+ s[x+1] = NUL;
+ debug(F110,"ckmkdir 2+UNIXOROSK",s,0);
+ }
+#else /* UNIXOROSK */
+#ifdef OS2
+ ckstrncpy(tmpbuf,s,CKMAXPATH+1);
+ s = tmpbuf;
+ x = strlen(s);
+ if (fc == 0 && x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */
+ s[x] = '/';
+ s[x+1] = NUL;
+ debug(F110,"ckmkdir 2+OS2",s,0);
+ }
+#endif /* OS2 */
+#endif /* UNIXOROSK */
+#endif /* VMS */
+#ifdef NZLTOR
+ /* Server is calling us, so convert to local format if necessary */
+ if (cvt) {
+ nzrtol(s,(char *)buf2,1,PATH_ABS,CKMAXPATH);
+ s = buf2;
+ debug(F110,"ckmkdir 3",s,0);
+ }
+#endif /* NZLTOR */
+ debug(F110,"ckmkdir 4",s,0);
+ if (fc == 0) { /* Making */
+#ifdef CK_MKDIR
+ rc = zmkdir(s);
+#else
+#ifdef NT
+ rc = _mkdir(s);
+#else
+ rc = mkdir(s,0777);
+#endif /* NT */
+#endif /* CK_MKDIR */
+ } else { /* Removing */
+#ifdef ZRMDIR
+ rc = zrmdir(s);
+#else
+#ifdef NT
+ rc = _rmdir(s);
+#else
+#ifdef OSK
+ rc = -2;
+#else
+ rc = rmdir(s);
+#endif /* OSK */
+#endif /* NT */
+#endif /* ZRMDIR */
+ }
+#endif /* datageneral */
+ debug(F101,"ckmkdir rc","",rc);
+ if (rc == -2) {
+ ckmakmsg(ckmkdbuf,
+ CKMAXPATH,
+ "Directory ",
+ (fc == 0) ? "creation" : "removal",
+ "not implemented in this version of C-Kermit",
+ NULL
+ );
+ *r = ckmkdbuf;
+ if (m) printf("%s\n",*r);
+ } else if (rc < 0) {
+ if (m) perror(s);
+ ckmakmsg(ckmkdbuf,CKMAXPATH,s,": ",ck_errstr(),NULL);
+ *r = ckmkdbuf;
+ } else if (fc == 0 && zfnqfp(s,CKMAXPATH,ckmkdbuf)) {
+ *r = ckmkdbuf;
+ } else if (fc != 0) {
+ ckmakmsg(ckmkdbuf,CKMAXPATH,s,": removed",NULL,NULL);
+ *r = ckmkdbuf;
+ }
+ return(rc);
+}
+#endif /* CK_MKDIR */
+
+#ifndef NOXFER /* Rest of this file... */
+
+#ifndef NODISPO
+#ifdef pdp11
+#define NODISPO
+#endif /* pdpd11 */
+#endif /* NODISPO */
+
+extern int pipesend;
+#ifdef PIPESEND
+extern char ** sndfilter;
+#endif /* PIPESEND */
+
+extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what,
+ sendmode, opnerr, dest, epktrcvd, epktsent, filestatus, eofmethod, dispos,
+ fncnv, fnrpath;
+
+extern char * ofn2;
+extern char * rfspec, * sfspec, * prfspec, * psfspec, * rrfspec, * prrfspec;
+extern char ofn1[];
+extern int ofn1x;
+extern char * ofperms;
+
+#ifdef VMS
+extern int batch;
+#else
+extern int backgrd;
+#endif /* VMS */
+
+extern int xflg, remfile, remappd;
+extern CHAR *data;
+extern char filnam[];
+#ifndef NOFRILLS
+extern int rprintf, rmailf; /* REMOTE MAIL, PRINT */
+char optbuf[OPTBUFLEN]; /* Options for MAIL or REMOTE PRINT */
+#endif /* NOFRILLS */
+extern int wslots;
+extern int fblksiz, frecl, forg, frecfm, fncact, fncsav, fcctrl, lf_opts;
+extern CHAR * srvcmd;
+extern int srvcmdlen;
+
+extern int binary, spsiz;
+extern int pktnum, cxseen, czseen, nfils, stdinf;
+extern int memstr, stdouf, keep, sndsrc, hcflg;
+extern int server, en_cwd, en_mai, en_pri;
+
+/* Attributes in/out enabled flags */
+
+extern int
+ atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
+ attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
+
+#ifdef CK_PERMS
+extern int atlpri, atlpro, atgpri, atgpro;
+#endif /* CK_PERMS */
+
+#ifdef STRATUS
+extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
+#endif /* STRATUS */
+
+#ifdef datageneral
+extern int quiet;
+#endif /* datageneral */
+
+extern long filcnt;
+extern CK_OFF_T fsize, ffc, tfc, sendstart, calibrate;
+CK_OFF_T rs_len;
+
+#ifndef NOCSETS
+_PROTOTYP (VOID setxlate, (void));
+extern int tcharset, fcharset;
+extern int ntcsets, xlatype, xfrxla;
+extern struct csinfo tcsinfo[], fcsinfo[];
+#endif /* NOCSETS */
+
+/* Variables global to Kermit that are defined in this module */
+
+#ifdef CKXXCHAR /* DOUBLE / IGNORE char table */
+int dblflag = 0;
+int ignflag = 0;
+short dblt[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+#endif /* CKXXCHAR */
+
+int winlo; /* packet number at low window edge */
+
+int sbufnum; /* number of free buffers */
+int dum001 = 1234; /* protection... */
+int sbufuse[MAXWS]; /* buffer in-use flag */
+int dum003 = 1111;
+int rbufnum; /* number of free buffers */
+int dum002 = 4321; /* more protection */
+int rbufuse[MAXWS]; /* buffer in-use flag */
+int sseqtbl[64]; /* sequence # to buffer # table */
+int rseqtbl[64]; /* sequence # to buffer # table */
+int sacktbl[64]; /* sequence # ack table */
+
+int o_isopen = 0, i_isopen = 0; /* Input & output files are open */
+
+#ifdef DYNAMIC
+struct pktinfo *s_pkt = NULL; /* array of pktinfo structures */
+struct pktinfo *r_pkt = NULL; /* array of pktinfo structures */
+#else
+struct pktinfo s_pkt[MAXWS]; /* array of pktinfo structures */
+struct pktinfo r_pkt[MAXWS]; /* array of pktinfo structures */
+#endif /* DYNAMIC */
+
+#ifdef DEBUG
+char xbuf[200]; /* For debug logging */
+#endif /* DEBUG */
+
+#ifdef DYNAMIC
+CHAR *bigsbuf = NULL, *bigrbuf = NULL;
+#else
+char bigsbt[8]; /* Protection (shouldn't need this). */
+ /* BUT DON'T REMOVE IT! */
+CHAR bigsbuf[SBSIZ + 5]; /* Send-packet buffer area */
+char bigrbt[8]; /* Safety padding */
+CHAR bigrbuf[RBSIZ + 5]; /* Receive-packet area */
+#endif
+int bigsbsiz = SBSIZ; /* Sizes of big send & rcv buffers. */
+int bigrbsiz = RBSIZ;
+
+#ifdef VMS
+int zchkpath(char *s);
+#endif /* VMS */
+
+/* FUNCTIONS */
+
+VOID
+dofast() {
+ long maxbufsiz = RBSIZ; /* Configuration parameters */
+ int maxpktsiz = MAXSP;
+ extern int spsizf, /* For bug in IRIX Telnet server */
+ rpsiz, urpsiz, spsizr, spmax, wslotr;
+ extern struct ck_p ptab[];
+
+ if (maxpktsiz < 40) /* Long packet length */
+ maxpktsiz = 40;
+ else if (maxpktsiz > 4000)
+ maxpktsiz = 4000;
+ wslotr = maxbufsiz / maxpktsiz;
+ if (wslotr > MAXWS) /* Window slots */
+ wslotr = MAXWS;
+ if (wslotr > 30)
+ wslotr = 30;
+ else if (wslotr < 1)
+ wslotr = 1;
+ urpsiz = adjpkl(maxpktsiz,wslotr,maxbufsiz);
+ ptab[PROTO_K].rpktlen = urpsiz;
+ rpsiz = (urpsiz > 94) ? 94 : urpsiz; /* Max non-long packet length */
+ debug(F111,"dofast","uprsiz",urpsiz);
+#ifdef IRIX
+#ifndef IRIX65
+ /* IRIX Telnet server chops off writes longer than 4K */
+ spsiz = spmax = spsizr = urpsiz;
+ debug(F101,"doarg Q IRIX spsiz","",spsiz);
+ spsizf = 1;
+#endif /* IRIX65 */
+#endif /* IRIX */
+#ifdef CK_SPEED
+ setprefix(PX_CAU); /* Cautious unprefixing */
+#endif /* CK_SPEED */
+}
+
+
+/* For sanity, use "i" for buffer slots, "n" for packet numbers. */
+
+/* I N I B U F S */
+
+/*
+ Allocates the big send and receive buffers.
+ Call with size for big send buffer (s) and receive buffer (r).
+ These sizes can be different.
+ Attempts to allocate buffers of the requested size, but if it can't,
+ it will allocate smaller ones.
+ Sets global variables bigsbsiz and bigrbsiz to the actual sizes,
+ and bigsbuf and bigrbuf pointing to the actual buffers.
+ Designed to be called more than once.
+ Returns 0 on success, -1 on failure.
+*/
+
+CHAR *bigbufp = NULL;
+
+int
+inibufs(s,r) int s, r; {
+#ifdef DYNAMIC
+ unsigned
+ int size;
+#ifdef OS2
+ unsigned /* Don't you wish everybody had unsigned long... */
+#endif /* OS2 */
+ long z;
+ int x;
+
+ debug(F101,"inibufs s","",s);
+ debug(F101,"inibufs r","",r);
+
+ if (s < 80 || r < 80) return(-1); /* Validate arguments. */
+
+ if (!s_pkt) { /* Allocate packet info structures */
+ if (!(s_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
+ fatal("ini_pkts: no memory for s_pkt");
+ }
+ for (x = 0; x < MAXWS; x++)
+ s_pkt[x].pk_adr = NULL; /* Initialize addresses */
+
+ if (!r_pkt) {
+ if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
+ fatal("ini_pkts: no memory for s_pkt");
+ }
+ for (x = 0; x < MAXWS; x++)
+ r_pkt[x].pk_adr = NULL; /* Initialize addresses */
+
+ if (!srvcmd) { /* Allocate srvcmd buffer */
+ srvcmd = (CHAR *) malloc(r + 100);
+ if (!srvcmd) return(-1);
+ srvcmdlen = r + 99;
+ *srvcmd = NUL;
+ }
+ if (bigbufp) { /* Free previous buffers, if any. */
+ free(bigbufp);
+ bigbufp = NULL;
+ }
+ size = s + r + 40; /* Combined requested size + padding */
+ z = (unsigned) s + (unsigned) r + 40;
+ debug(F101,"inibufs size 1","",size);
+ debug(F101,"inibufs size z","",z);
+ if ((long) size != z) {
+ debug(F100,"inibufs overflow","",0);
+ size = 65535;
+ }
+
+ /* Try to get the space. If malloc fails, try to get a little less. */
+ /* (Obviously, this algorithm can be refined.) */
+
+ while (!(bigbufp = (CHAR *) malloc(size))) {
+ debug(F101,"inibufs bigbuf malloc failed","",size);
+ size = (size * 2) / 3; /* Failed, cut size by 1/3. */
+ if (size < 200) /* Try again until too small. */
+ return(-1);
+ }
+ debug(F101,"inibufs size 2","",size); /* OK, we got some space. */
+
+/*
+ Now divide the allocated space between the send and receive buffers in the
+ requested proportion. The natural formula would be (s / (s + r)) * size
+ (for the send buffer), but that doesn't work with integer arithmetic and we
+ can't use floating point because some machines don't have it. This can be
+ rearranged as (s * size) / (s + r). But (s * size) can be VERY large, too
+ large for 32 bits. So let's do it this way. This arithmetic works for
+ buffer sizes up to about 5,000,000.
+*/
+#define FACTOR 20L
+ z = ( (long) s * FACTOR ) / ( (long) s + (long) r );
+ x = ( z * ( (long) size / FACTOR ) );
+ if (x < 0) return(-1); /* Catch overflow */
+
+ bigsbsiz = x - 5; /* Size of send buffer */
+ bigsbuf = bigbufp; /* Address of send buffer */
+ debug(F101,"inibufs bigsbsiz","",bigsbsiz);
+
+ bigrbsiz = size - x - 5; /* Size of receive buffer */
+ bigrbuf = bigbufp + x; /* Addresss of receive buffer */
+ debug(F101,"inibufs bigrbsiz","",bigrbsiz);
+
+ return(0); /* Success */
+#else /* No dynamic allocation */
+ bigsbsiz = SBSIZ; /* Just use the symbols */
+ bigrbsiz = RBSIZ; /* ... */
+ return(0); /* Success. */
+#endif /* DYNAMIC */
+}
+
+
+/* M A K E B U F -- Makes and clears a new buffers. */
+
+/* Call with: */
+/* slots: number of buffer slots to make, 1 to 32 */
+/* bufsiz: size of the big buffer */
+/* buf: address of the big buffer */
+/* xx: pointer to array of pktinfo structures for these buffers */
+
+/* Subdivides the big buffer into "slots" buffers. */
+
+/* Returns: */
+/* -1 if too many or too few slots requested, */
+/* -2 if slots would be too small. */
+/* n (positive) on success = size of one buffer. */
+/* with pktinfo structure initialized for this set of buffers. */
+
+int
+makebuf(slots,bufsiz,buf,xx)
+/* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
+
+ CHAR *a;
+ int i, size;
+
+ debug(F101,"makebuf","",slots);
+ debug(F101,"makebuf bufsiz","",bufsiz);
+ debug(F101,"makebuf MAXWS","",MAXWS);
+
+ if (slots > MAXWS || slots < 1) return(-1);
+ if (bufsiz < slots * 10 ) return(-2);
+
+ size = bufsiz / slots; /* Divide up the big buffer. */
+ a = buf; /* Address of first piece. */
+
+ for (i = 0; i < slots; i++) {
+ struct pktinfo *x = &xx[i];
+ x->bf_adr = a; /* Address of this buffer */
+ x->bf_len = size; /* Length of this buffer */
+ x->pk_len = 0; /* Length of data field */
+ x->pk_typ = ' '; /* packet type */
+ x->pk_seq = -1; /* packet sequence number */
+ x->pk_rtr = 0; /* retransmissions */
+ *a = '\0'; /* Clear the buffer */
+ a += size; /* Position to next buffer slot */
+ }
+ return(size);
+}
+
+/* M A K S B U F -- Makes the send-packet buffer */
+
+int
+mksbuf(slots) int slots; {
+ int i, x;
+ sbufnum = 0;
+ if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) {
+ debug(F101,"mksbuf makebuf return","",x);
+ return(x);
+ }
+ debug(F101,"mksbuf makebuf return","",x);
+ for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
+ sseqtbl[i] = -1; /* to-buffer-number table. */
+ sacktbl[i] = 0;
+ }
+ for (i = 0; i < MAXWS; i++)
+ sbufuse[i] = 0; /* Mark each buffer as free */
+ sbufnum = slots;
+ wcur = 0;
+ return(x);
+}
+
+/* M A K R B U F -- Makes the receive-packet buffer */
+
+int
+mkrbuf(slots) int slots; {
+ int i, x;
+ rbufnum = 0;
+ if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) {
+ debug(F101,"mkrbuf makebuf return","",x);
+ return(x);
+ }
+ debug(F101,"mkrbuf makebuf return","",x);
+ for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
+ rseqtbl[i] = -1; /* to-buffer-number table. */
+ }
+ for (i = 0; i < MAXWS; i++)
+ rbufuse[i] = 0; /* Mark each buffer as free */
+ rbufnum = slots;
+ wcur = 0;
+ return(x);
+}
+
+/* W I N D O W -- Resize the window to n */
+
+int
+window(n) int n; {
+ debug(F101,"window","",n);
+ if (n < 1 || n > MAXWS) return(-1);
+ if (mksbuf(n) < 0) return(-1);
+ if (mkrbuf(n) < 0) return(-1);
+ wslots = n;
+#ifdef DEBUG
+ if (deblog) dumpsbuf();
+ if (deblog) dumprbuf();
+#endif /* DEBUG */
+ return(0);
+}
+
+/* G E T S B U F -- Allocate a send-buffer. */
+
+/* Call with packet sequence number to allocate buffer for. */
+/* Returns: */
+/* -4 if argument is invalid (negative, or greater than 63) */
+/* -3 if buffers were thought to be available but really weren't (bug!) */
+/* -2 if the number of free buffers is negative (bug!) */
+/* -1 if no free buffers. */
+/* 0 or positive, packet sequence number, with buffer allocated for it. */
+
+int
+getsbuf(n) int n; { /* Allocate a send-buffer */
+ int i;
+ CHAR * p = NULL;
+ if (n < 0 || n > 63) {
+ debug(F101,"getsbuf bad arg","",n);
+ return(-4); /* Bad argument */
+ }
+ debug(F101,"getsbuf packet","",n);
+ /* debug(F101,"getsbuf, sbufnum","",sbufnum); */
+ if (sbufnum == 0) return(-1); /* No free buffers. */
+ if (sbufnum < 0) return(-2); /* Shouldn't happen. */
+ for (i = 0; i < wslots; i++) /* Find the first one not in use. */
+ if (sbufuse[i] == 0) { /* Got one? */
+ sbufuse[i] = 1; /* Mark it as in use. */
+ sbufnum--; /* One less free buffer. */
+ *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
+ s_pkt[i].pk_seq = n; /* Put in the sequence number */
+ sseqtbl[n] = i; /* Back pointer from sequence number */
+ sacktbl[n] = 0; /* ACK flag */
+ s_pkt[i].pk_len = 0; /* Data field length now zero. */
+ s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
+ s_pkt[i].pk_rtr = 0; /* Zero the retransmission count */
+ p = s_pkt[i].bf_adr + 7; /* Set global "data" address. */
+ debug(F101,"getsbuf p","",0);
+ data = p;
+ if (!data) {
+ debug(F100,"getsbuf data == NULL","",0);
+ return(-3);
+ }
+ if ((what & (W_SEND|W_REMO)) && (++wcur > wmax))
+ wmax = wcur; /* For statistics. */
+ /* debug(F101,"getsbuf wcur","",wcur); */
+ return(n); /* Return its index. */
+ }
+ sbufnum = 0; /* Didn't find one. */
+ return(-3); /* Shouldn't happen! */
+}
+
+int
+getrbuf() { /* Allocate a receive buffer */
+ int i;
+#ifdef COMMENT
+ /* This code is pretty stable by now... */
+ /* Looks like we might need this after all */
+ debug(F101,"getrbuf rbufnum","",rbufnum);
+ debug(F101,"getrbuf wslots","",wslots);
+ debug(F101,"getrbuf dum002","",dum002);
+ debug(F101,"getrbuf dum003","",dum003);
+#endif /* COMMENT */
+ if (rbufnum == 0) return(-1); /* No free buffers. */
+ if (rbufnum < 0) return(-2); /* Shouldn't happen. */
+ for (i = 0; i < wslots; i++) /* Find the first one not in use. */
+ if (rbufuse[i] == 0) { /* Got one? */
+ rbufuse[i] = 1; /* Mark it as in use. */
+ *r_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
+ rbufnum--; /* One less free buffer. */
+ debug(F101,"getrbuf new rbufnum","",rbufnum);
+ if ((what & W_RECV) && (++wcur > wmax))
+ wmax = wcur; /* For statistics. */
+ /* debug(F101,"getrbuf wcur","",wcur); */
+ return(i); /* Return its index. */
+ }
+ /* debug(F101,"getrbuf foulup","",i); */
+ rbufnum = 0; /* Didn't find one. */
+ return(-3); /* Shouldn't happen! */
+}
+
+/* F R E E S B U F -- Free send-buffer for given packet sequence number */
+
+/* Returns: */
+/* 1 upon success */
+/* -1 if specified buffer does not exist */
+
+int
+freesbuf(n) int n; { /* Release send-buffer for packet n. */
+ int i;
+
+ debug(F101,"freesbuf","",n);
+ if (n < 0 || n > 63) /* No such packet. */
+ return(-1);
+ i = sseqtbl[n]; /* Get the window slot number. */
+ if (i > -1 && i <= wslots) {
+ sseqtbl[n] = -1; /* If valid, remove from seqtbl */
+ sbufnum++; /* and count one more free buffer */
+ sbufuse[i] = 0; /* and mark it as free, */
+ if (what & (W_SEND|W_REMO)) /* decrement active slots */
+ wcur--; /* for statistics and display. */
+ } else {
+ debug(F101," sseqtbl[n]","",sseqtbl[n]);
+ return(-1);
+ }
+
+/* The following is done only so dumped buffers will look right. */
+
+ if (1) {
+ *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
+ s_pkt[i].pk_seq = -1; /* Invalidate the sequence number */
+ s_pkt[i].pk_len = 0; /* Data field length now zero. */
+ s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
+ s_pkt[i].pk_rtr = 0; /* And the retries field. */
+ }
+ return(1);
+}
+
+int
+freerbuf(i) int i; { /* Release receive-buffer slot "i". */
+ int n;
+
+/* NOTE !! Currently, this function frees the indicated buffer, but */
+/* does NOT erase the data. The program counts on this. Will find a */
+/* better way later.... */
+
+ /* debug(F101,"freerbuf, slot","",i); */
+ if (i < 0 || i >= wslots) { /* No such slot. */
+ debug(F101,"freerbuf no such slot","",i);
+ return(-1);
+ }
+ n = r_pkt[i].pk_seq; /* Get the packet sequence number */
+ debug(F101,"freerbuf packet","",n);
+ if (n > -1 && n < 64) /* If valid, remove from seqtbl */
+ rseqtbl[n] = -1;
+ if (rbufuse[i] != 0) { /* If really allocated, */
+ rbufuse[i] = 0; /* mark it as free, */
+ rbufnum++; /* and count one more free buffer. */
+ if (what & W_RECV) /* Keep track of current slots */
+ wcur--; /* for statistics and display */
+ debug(F101,"freerbuf rbufnum","",rbufnum);
+ }
+
+/* The following is done only so dumped buffers will look right. */
+
+ if (1) {
+ /* *r_pkt[i].bf_adr = '\0'; */ /* Zero the buffer data field */
+ r_pkt[i].pk_seq = -1; /* And from packet list */
+ r_pkt[i].pk_len = 0; /* Data field length now zero. */
+ r_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
+ r_pkt[i].pk_rtr = 0; /* And the retries field. */
+ }
+ return(1);
+}
+
+/* This is like freerbuf, except it's called with a packet sequence number */
+/* rather than a packet buffer index. */
+
+VOID
+freerpkt(seq) int seq; {
+ int k;
+ debug(F101,"freerpkt seq","",seq);
+ k = rseqtbl[seq];
+ /* debug(F101,"freerpkt k","",k); */
+ if (k > -1) {
+ k = freerbuf(k);
+ /* debug(F101,"freerpkt freerbuf","",k); */
+ }
+}
+
+
+/* C H K W I N -- Check if packet n is in window. */
+
+/* Returns: */
+/* 0 if it is in the current window, */
+/* +1 if it would have been in previous window (e.g. if ack was lost), */
+/* -1 if it is outside any window (protocol error), */
+/* -2 if either of the argument packet numbers is out of range. */
+
+/* Call with packet number to check (n), lowest packet number in window */
+/* (bottom), and number of slots in window (slots). */
+
+int
+chkwin(n,bottom,slots) int n, bottom, slots; {
+ int top, prev;
+
+ debug(F101,"chkwin packet","",n);
+ debug(F101,"chkwin winlo","",bottom);
+ debug(F101,"chkwin slots","",slots);
+
+/* First do the easy and common cases, where the windows are not split. */
+
+ if (n < 0 || n > 63 || bottom < 0 || bottom > 63)
+ return(-2);
+
+ if (n == bottom) return(0); /* In a perfect world... */
+
+ top = bottom + slots; /* Calculate window top. */
+ if (top < 64 && n < top && n >= bottom)
+ return(0); /* In current window. */
+
+ prev = bottom - slots; /* Bottom of previous window. */
+ if (prev > -1 && n < bottom && n > prev)
+ return(1); /* In previous. */
+
+/* Now consider the case where the current window is split. */
+
+ if (top > 63) { /* Wraparound... */
+ top -= 64; /* Get modulo-64 sequence number */
+ if (n < top || n >= bottom) {
+ return(0); /* In current window. */
+ } else { /* Not in current window. */
+ if (n < bottom && n >= prev) /* Previous window can't be split. */
+ return(1); /* In previous window. */
+ else
+ return(-1); /* Not in previous window. */
+ }
+ }
+
+/* Now the case where current window not split, but previous window is. */
+
+ if (prev < 0) { /* Is previous window split? */
+ prev += 64; /* Yes. */
+ if (n < bottom || n >= prev)
+ return(1); /* In previous window. */
+ } else { /* Previous window not split. */
+ if (n < bottom && n >= prev)
+ return(1); /* In previous window. */
+ }
+
+/* It's not in the current window, and not in the previous window... */
+
+ return(-1); /* So it's not in any window. */
+}
+
+int
+dumpsbuf() { /* Dump send-buffers */
+#ifdef DEBUG
+ int j, x, z; /* to debug log. */
+
+ if (! deblog) return(0);
+ x = zsoutl(ZDFILE,"SEND BUFFERS:");
+ if (x < 0) {
+ deblog = 0;
+ return(0);
+ }
+ x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
+ if (x < 0) {
+ deblog = 0;
+ return(0);
+ }
+ for (j = 0; j < wslots; j++) {
+ if (!sbufuse[j])
+ continue;
+ z = ((unsigned long)(s_pkt[j].bf_adr)) & 0xffff;
+
+ sprintf(xbuf, /* safe (200) */
+ "%4d%6d%10d%5d%6d%4c%5d%6d\n",
+ j,
+ sbufuse[j],
+ /* Avoid warnings when addresses are bigger than ints */
+ z,
+ s_pkt[j].bf_len,
+ s_pkt[j].pk_len,
+ s_pkt[j].pk_typ,
+ s_pkt[j].pk_seq,
+ s_pkt[j].pk_rtr
+ );
+ if (zsout(ZDFILE,xbuf) < 0) {
+ deblog = 0;
+ return(0);
+ }
+ if (s_pkt[j].pk_adr) {
+ x = (int)strlen((char *) s_pkt[j].pk_adr);
+ if (x)
+ sprintf(xbuf, /* safe (checked) */
+ "[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : "");
+ else
+ sprintf(xbuf,"[(empty string)]\n"); /* safe (200) */
+ } else {
+ sprintf(xbuf,"[(null pointer)]\n"); /* safe (200) */
+ }
+ if (zsout(ZDFILE,xbuf) < 0) {
+ deblog = 0;
+ return(0);
+ }
+ }
+ sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo); /* safe (200) */
+ if (zsout(ZDFILE,xbuf) < 0) {
+ deblog = 0;
+ return(0);
+ }
+#endif /* DEBUG */
+ return(0);
+}
+int
+dumprbuf() { /* Dump receive-buffers */
+#ifdef DEBUG
+ int j, x, z;
+ if (! deblog) return(0);
+ if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) {
+ deblog = 0;
+ return(0);
+ }
+ x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
+ if (x < 0) {
+ deblog = 0;
+ return(0);
+ }
+ for ( j = 0; j < wslots; j++ ) {
+ if (!rbufuse[j])
+ continue;
+ z = ((unsigned long)(r_pkt[j].bf_adr)) & 0xffff;
+ sprintf(xbuf, /* 200, safe */
+ "%4d%6d%10d%5d%6d%4c%5d%6d\n",
+ j,
+ rbufuse[j],
+ /* Avoid warnings when addresses are bigger than ints */
+ z,
+ r_pkt[j].bf_len,
+ r_pkt[j].pk_len,
+ r_pkt[j].pk_typ,
+ r_pkt[j].pk_seq,
+ r_pkt[j].pk_rtr
+ );
+ if (zsout(ZDFILE,xbuf) < 0) {
+ deblog = 0;
+ return(0);
+ }
+ x = (int)strlen((char *)r_pkt[j].bf_adr);
+ sprintf(xbuf, /* safe (checked) */
+ "[%.72s%s]\n",r_pkt[j].bf_adr, x > 72 ? "..." : "");
+ if (zsout(ZDFILE,xbuf) < 0) {
+ deblog = 0;
+ return(0);
+ }
+ }
+ sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo); /* safe (200) */
+ if (zsout(ZDFILE,xbuf) < 0) {
+ deblog = 0;
+ return(0);
+ }
+#endif /* DEBUG */
+ return(0);
+}
+
+/* S A T T R -- Send an Attribute Packet */
+
+/*
+ Sends attribute packet(s) for the current file. If the info will not
+ fit into one packet, it can be called repeatedly until all the fields
+ that will fit are sent.
+
+ Call with:
+ xp == 0 if we're sending a real file (F packet), or:
+ xp != 0 for screen data (X packet).
+ And:
+ flag == 1 for first A packet
+ flag == 0 for subsequent A packets.
+ Returns:
+ 1 or greater if an A packet was sent, or:
+ 0 if an S-packet was not sent because there was no data to send or
+ there was no data left that was short enough to send, or:
+ -1 on any kind of error.
+*/
+
+/* (don't) #define TSOFORMAT */
+/* which was only for making C-Kermit send TSO-Kermit-like A packets */
+/* to try to track down a problem somebody reported... */
+
+int
+sattr(xp, flag) int xp, flag; { /* Send Attributes */
+
+ static int max; /* Maximum length for Attributes */
+ static short done[95]; /* Field-complete array */
+ static struct zattr x; /* File attribute struct */
+ static char xdate[24];
+
+ extern char * cksysid;
+
+ /* Some extra flags are used because the "done" array is sparse */
+
+ int i, j, rc, aln, left = 0, numset = 0, xbin = 0; /* Workers */
+ int notafile = 0;
+ char *tp, c;
+
+ notafile = sndarray || pipesend ||
+#ifdef PIPESEND
+ sndfilter ||
+#endif /* PIPESEND */
+ calibrate;
+
+ debug(F101,"sattr flag","",flag);
+ if (!flag) /* No more attributes to send */
+ if (done[xunchar('@')])
+ return(0);
+
+ /* Initialize Attribute mechanism */
+
+ if (flag) { /* First time here for this file? */
+ initattr(&x); /* Blank out all the fields. */
+ for (j = 0; j < 95; j++) /* Init array of completed fields */
+ done[j] = 0;
+ max = maxdata(); /* Get maximum data field length */
+ if (notafile || xp == 1) { /* Is it not a real file? */
+ extern char * zzndate();
+ char * p;
+ int i;
+#ifdef CALIBRATE
+ if (calibrate) { /* Calibration run... */
+ x.lengthk = calibrate / 1024L; /* We know the length */
+ x.length = calibrate;
+ }
+#endif /* CALIBRATE */
+ x.systemid.val = cksysid; /* System ID */
+ x.systemid.len = (int)strlen(cksysid);
+ ckstrncpy(xdate,zzndate(),24);
+ xdate[8] = SP;
+ ztime(&p);
+ for (i = 11; i < 19; i++) /* copy hh:mm:ss */
+ xdate[i - 2] = p[i]; /* to xdate */
+ xdate[17] = NUL; /* terminate */
+ x.date.val = xdate;
+ x.date.len = 17;
+ debug(F111,"sattr notafile date",x.date.val,x.date.len);
+ } else { /* Real file */
+ rc = zsattr(&x); /* Get attributes for this file */
+ debug(F101,"sattr zsattr","",rc);
+ if (rc < 0) /* Can't get 'em so don't send 'em */
+ return(0);
+ debug(F101,"sattr init max","",max);
+ }
+ }
+ if (nxtpkt() < 0) /* Got 'em, get next packet number */
+ return(-1); /* Bad news if we can't */
+
+ i = 0; /* Init data field character number */
+
+ /* Do each attribute using first-fit method, marking as we go */
+ /* This is rather long and repititious - could be done more cleverly */
+
+ if (atsido && !done[xunchar(c = '.')]) { /* System type */
+ if (max - i >= x.systemid.len + 2) { /* Enough space ? */
+ data[i++] = c; /* Yes, add parameter */
+ data[i++] = tochar(x.systemid.len); /* Add length */
+ for (j = 0; j < x.systemid.len; j++) /* Add data */
+ data[i++] = x.systemid.val[j];
+ numset++; /* Count that we did at least one */
+ done[xunchar(c)] = 1; /* Mark this attribute as done */
+ } else /* No */
+ left++; /* so mark this one left to do */
+ }
+#ifdef STRATUS
+ if (atcreo && !done[xunchar(c = '$')]) { /* Creator */
+ if (max - i >= x.creator.len + 2) { /* Enough space ? */
+ data[i++] = c;
+ data[i++] = tochar(x.creator.len);
+ for (j = 0; j < x.creator.len; j++)
+ data[i++] = x.creator.val[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+ if (atacto && !done[xunchar(c = '%')]) { /* File account */
+ if (max - i >= x.account.len + 2) {
+ data[i++] = c;
+ data[i++] = tochar(x.account.len);
+ for (j = 0; j < x.account.len; j++)
+ data[i++] = x.account.val[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+ if (atfrmo && !done[xunchar(c = '/')]) { /* Packet data format */
+ if (max - i >= x.recfm.len + 2) {
+ data[i++] = c;
+ data[i++] = tochar(x.recfm.len); /* Copy from attr structure */
+ for (j = 0; j < x.recfm.len; j++)
+ data[i++] = x.recfm.val[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+#endif /* STRATUS */
+
+ xbin = /* Is the transfer in binary mode? */
+#ifdef VMS
+ binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */
+ !strncmp(x.recfm.val,"F",1) /* or RECFM=Fxxxxxx */
+#else
+ binary /* User said SET FILE TYPE BINARY */
+#endif /* VMS */
+ ;
+
+ if (attypo && !done[xunchar(c = '"')]) { /* File type */
+ if (max - i >= 5) { /* Max length for this field */
+ data[i++] = c;
+ if (xbin) { /* Binary */
+ data[i++] = tochar(2); /* Two characters */
+ data[i++] = 'B'; /* B for Binary */
+ data[i++] = '8'; /* 8-bit bytes (note assumption...) */
+#ifdef CK_LABELED
+ if (binary != XYFT_L
+#ifdef VMS
+ && binary != XYFT_I
+#endif /* VMS */
+ )
+ binary = XYFT_B;
+#endif /* CK_LABELED */
+ } else { /* Text */
+#ifdef TSOFORMAT
+ data[i++] = tochar(1); /* One character */
+ data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
+#else
+ data[i++] = tochar(3); /* Three characters */
+ data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
+ data[i++] = 'M'; /* M for carriage return */
+ data[i++] = 'J'; /* J for linefeed */
+#endif /* TSOFORMAT */
+
+#ifdef VMS
+ binary = XYFT_T; /* We automatically detected text */
+#endif /* VMS */
+ }
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+
+#ifdef TSOFORMAT
+ if (attypo && !xbin && !done[xunchar(c = '/')]) { /* Record format */
+ if (max - i >= 5) {
+ data[i++] = c;
+ data[i++] = tochar(3); /* Three characters */
+ data[i++] = 'A'; /* A = variable with CRLFs */
+ data[i++] = 'M'; /* M for carriage return */
+ data[i++] = 'J'; /* J for linefeed */
+ }
+ }
+#endif /* TSOFORMAT */
+
+ if (attypo && !xbin && !done[xunchar(c = '*')]) { /* Text encoding */
+#ifdef NOCSETS
+ if (max - i >= 3) {
+ data[i++] = c;
+ data[i++] = tochar(1); /* Length of value is 1 */
+ data[i++] = 'A'; /* A for ASCII */
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+#else
+ if (tcharset == TC_TRANSP || !xfrxla) { /* Transfer character set */
+ if (max - i >= 3) {
+ data[i++] = c; /* Encoding */
+ data[i++] = tochar(1); /* Length of value is 1 */
+ data[i++] = 'A'; /* A for ASCII (i.e. text) */
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ } else {
+ tp = tcsinfo[tcharset].designator;
+ if (!tp) tp = "";
+ aln = strlen(tp);
+ if (aln > 0) {
+ if (max - i >= aln + 2) {
+ data[i++] = c; /* Encoding */
+ data[i++] = tochar(aln+1); /* Length of designator. */
+ data[i++] = 'C'; /* Text in specified charset. */
+ for (j = 0; j < aln; j++) /* Copy designator */
+ data[i++] = *tp++; /* Example: *&I6/100 */
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ } else
+ done[xunchar(c)] = 1;
+ }
+#endif /* NOCSETS */
+ }
+ if (atdato && !done[xunchar(c = '#')] && /* Creation date, if any */
+ (aln = x.date.len) > 0) {
+ if (max - i >= aln + 2) {
+ data[i++] = c;
+ data[i++] = tochar(aln);
+ for (j = 0; j < aln; j++)
+ data[i++] = x.date.val[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+ /* File length in K */
+ if (atleno && !done[xunchar(c = '!')] && x.lengthk > (CK_OFF_T)-1) {
+#ifdef COMMENT
+ sprintf((char *) &data[i+2],"%ld",x.lengthk); /* safe */
+#else
+ ckstrncpy((char *)&data[i+2],ckfstoa(x.lengthk),32);
+#endif /* COMMENT */
+ aln = (int)strlen((char *)(data+i+2));
+ if (max - i >= aln + 2) {
+ data[i] = c;
+ data[i+1] = tochar(aln);
+ i += aln + 2;
+ numset++;
+ done[xunchar(c)] = 1;
+ } else {
+ data[i] = NUL;
+ left++;
+ }
+ }
+ /* File length in bytes */
+ if (atleno && !done[xunchar(c = '1')] && x.length > (CK_OFF_T)-1) {
+#ifdef COMMENT
+ sprintf((char *) &data[i+2],"%ld",x.length); /* safe */
+#else
+ ckstrncpy((char *)&data[i+2],ckfstoa(x.length),32);
+#endif /* COMMENT */
+ aln = (int)strlen((char *)(data+i+2));
+ if (max - i >= aln + 2) {
+ data[i] = c;
+ data[i+1] = tochar(aln);
+ i += aln + 2;
+ numset++;
+ done[xunchar(c)] = 1;
+ } else {
+ data[i] = NUL;
+ left++;
+ }
+ }
+#ifdef CK_PERMS
+ if (atlpro && !done[xunchar(c = ',')] && /* Local protection */
+ (aln = x.lprotect.len) > 0 && !notafile && xp == 0) {
+ if (max - i >= aln + 2) {
+ data[i++] = c;
+ data[i++] = tochar(aln);
+ for (j = 0; j < aln; j++)
+ data[i++] = x.lprotect.val[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+ if (atgpro && !done[xunchar(c = '-')] && /* Generic protection */
+ (aln = x.gprotect.len) > 0 && !notafile && xp == 0) {
+ if (max - i >= aln + 2) {
+ data[i++] = c;
+ data[i++] = tochar(aln);
+ for (j = 0; j < aln; j++)
+ data[i++] = x.gprotect.val[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+#endif /* CK_PERMS */
+ if (atblko && fblksiz && !done[xunchar(c = '(')] &&
+ !notafile && xp == 0) { /* Blocksize */
+ sprintf((char *) &data[i+2],"%d",fblksiz); /* safe */
+ aln = (int)strlen((char *)(data+i+2));
+ if (max - i >= aln + 2) {
+ data[i] = c;
+ data[i+1] = tochar(aln);
+ i += aln + 2;
+ numset++;
+ done[xunchar(c)] = 1;
+ } else {
+ data[i] = NUL;
+ left++;
+ }
+ }
+#ifndef NOFRILLS
+ if ((rprintf || rmailf) && atdiso && /* MAIL, or REMOTE PRINT? */
+ !done[xunchar(c = '+')]) {
+ aln = (int) strlen(optbuf) + 1; /* Options, if any */
+ if (max - i >= aln + 2) {
+ data[i++] = c; /* Disposition */
+ data[i++] = tochar(aln); /* Options, if any */
+ if (rprintf)
+ data[i++] = 'P'; /* P for Print */
+ else
+ data[i++] = 'M'; /* M for Mail */
+ for (j = 0; optbuf[j]; j++) /* Copy any options */
+ data[i++] = optbuf[j];
+ numset++;
+ done[xunchar(c)] = 1;
+ } else {
+ data[i] = NUL;
+ left++;
+ }
+ }
+#endif /* NOFRILLS */
+#ifdef CK_RESEND
+ if (sendmode == SM_RESEND && !done[xunchar(c = '+')]) {
+ if (max - i >= 3) {
+ data[i++] = c; /* Disposition */
+ data[i++] = tochar(1);
+ data[i++] = 'R'; /* is RESEND */
+ numset++;
+ done[xunchar(c)] = 1;
+ } else
+ left++;
+ }
+#endif /* CK_RESEND */
+
+ /* End of Attributes -- to be sent only after sending all others */
+
+ debug(F111,"sattr","@",i);
+ debug(F101,"sattr numset","",numset);
+ debug(F101,"sattr left","",left);
+
+ if ((left == 0 || numset == 0) && !done[xunchar(c = '@')]) {
+ if (max - i >= 3) {
+ data[i++] = c; /* End of Attributes */
+ data[i++] = SP; /* Length 0 */
+ data[i] = NUL; /* Make sure it's null-terminated */
+ numset++;
+ done[xunchar(c)] = 1;
+ }
+ }
+
+ /* Finished - send the packet off if we have anything in it */
+
+ if (numset) {
+ data[i] = NUL; /* Terminate last good field */
+ debug(F111,"sattr sending",data,left);
+ aln = (int)strlen((char *)data); /* Get overall length of attributes */
+ return(spack('A',pktnum,aln,data)); /* Send it */
+ } else
+ return(0);
+}
+
+static char *refused = "";
+
+static char *reason[] = {
+ "size", "type", "date", "creator", "account", "area", "password",
+ "blocksize", "access", "encoding", "disposition", "protection",
+ "protection", "origin", "format",
+ "sys-dependent", /* 0 */
+ "size", /* 1 */
+ "2", /* 2 */
+ "3", /* 3 */
+ "4", /* 4 */
+ "5", /* 5 */
+ "6", /* 6 */
+ "7", /* 7 */
+ "8", /* 8 */
+ "9", /* 9 */
+ ":", /* : */
+ ";", /* ; */
+ "<", /* < */
+ "=", /* = */
+ ">", /* > */
+ "name", /* ? */
+ "@"
+};
+static int nreason = sizeof(reason) / sizeof(char *);
+int rejection = -1;
+
+char *
+getreason(s) char *s; { /* Decode attribute refusal reason */
+ char c, *p;
+ if (rejection == 1) /* Kludge for SET FIL COLL DISCARD */
+ return("name"); /* when other Kermit doesn't... */
+ p = s;
+ if (*p++ != 'N') return(""); /* Should start with N */
+ else if ((c = *p) > SP) { /* get reason, */
+ rejection = c; /* remember it, */
+ c -= '!'; /* get offset */
+ p = ((unsigned int) ((CHAR) c) <= (unsigned int) nreason) ?
+ reason[c] :
+ "unknown";
+ }
+ return(p);
+}
+
+int
+rsattr(s) CHAR *s; { /* Read response to attribute packet */
+ debug(F111,"rsattr",s,*s);
+ if (*s == 'N') { /* If it's 'N' followed by anything, */
+ refused = getreason((char *)s); /* they are refusing, get reason. */
+ debug(F110,"rsattr refused",refused,0);
+ tlog(F110," refused:",refused,0L);
+ return(-1);
+ }
+#ifdef CK_RESEND
+ if (sendmode == SM_RESEND && *s == '1') { /* RESEND length */
+ int n; CK_OFF_T z; CHAR *p;
+ p = s + 1;
+ n = xunchar(*p++);
+ debug(F101,"rsattr RESEND n","",n);
+ z = (CK_OFF_T)0;
+ while (n-- > 0) /* We assume the format is good. */
+ z = (CK_OFF_T)10 * z + (CK_OFF_T)(*p++ - '0');
+ debug(F101,"rsattr RESEND z","",z);
+ if (z > (CK_OFF_T)0) sendstart = z;
+ debug(F101,"rsattr RESEND sendstart","",sendstart);
+ if (sendstart > (CK_OFF_T)0)
+ if (zfseek(sendstart) < 0) /* Input file is already open. */
+ return(0);
+#ifdef CK_CURSES
+ if (fdispla == XYFD_C)
+ xxscreen(SCR_FS,0,fsize,""); /* Refresh file transfer display */
+#endif /* CK_CURSES */
+ }
+#endif /* CK_RESEND */
+ refused = "";
+ return(0);
+}
+
+/*
+ Get attributes from incoming A packet. Returns:
+ 0 on success, file is to be accepted
+ -1 on failure, file is to be refused
+*/
+int
+gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */
+ char c, d;
+ char *ff;
+ int aln, i, overflow = 0;
+
+#ifndef NOCSETS
+ extern int r_cset, axcset[];
+#endif /* NOCSETS */
+
+#define ABUFL 40 /* Temporary buffer for conversions */
+ char abuf[ABUFL+1];
+#define RFBUFL 10 /* Record-format buffer */
+ static char rfbuf[RFBUFL+1];
+#define FTBUFL 10 /* File type buffer */
+ static char ftbuf[FTBUFL+1];
+#define DTBUFL 40 /* File creation date */
+ static char dtbuf[DTBUFL+1];
+#define TSBUFL 10 /* Transfer syntax */
+ static char tsbuf[TSBUFL+1];
+#define IDBUFL 10 /* System ID */
+ static char idbuf[IDBUFL+1];
+#ifndef DYNAMIC
+#define DSBUFL 100 /* Disposition */
+ static char dsbuf[DSBUFL+1];
+#define SPBUFL 512 /* System-dependent parameters */
+ static char spbuf[SPBUFL+1];
+#else
+#define DSBUFL 100 /* Disposition */
+ static char *dsbuf = NULL;
+#define SPBUFL 512 /* System-dependent parameters */
+ static char *spbuf = NULL;
+#endif /* DYNAMIC */
+#define RPBUFL 20 /* Attribute reply */
+ static char rpbuf[RPBUFL+1];
+
+#ifdef CK_PERMS
+ static char lprmbuf[CK_PERMLEN+1];
+ static char gprmbuf[2];
+#endif /* CK_PERMS */
+
+ char *rp; /* Pointer to reply buffer */
+ int retcode; /* Return code */
+
+ d = SP; /* Initialize disposition */
+ ff = filnam; /* Filename returned by rcvfil */
+ if (fncact == XYFX_R && ofn1x && ofn1[0]) /* But watch out for FC=RENAME */
+ ff = ofn1; /* because we haven't renamed it yet */
+
+/* Fill in the attributes we have received */
+
+ rp = rpbuf; /* Initialize reply buffer */
+ *rp++ = 'N'; /* for negative reply. */
+ *rp = NUL;
+ retcode = 0; /* Initialize return code. */
+
+ if (dest == DEST_P) { /* SET DESTINATION PRINTER */
+#ifdef DYNAMIC
+ if (!dsbuf)
+ if ((dsbuf = malloc(DSBUFL+1)) == NULL)
+ fatal("gtattr: no memory for dsbuf");
+#endif /* DYNAMIC */
+ dsbuf[0] = 'P';
+ dsbuf[1] = '\0';
+ yy->disp.val = dsbuf;
+ yy->disp.len = 1;
+ }
+ while (c = *s++) { /* Get attribute tag */
+ aln = xunchar(*s++); /* Length of attribute string */
+ switch (c) {
+#ifdef COMMENT /* This case combined with '1' below */
+ case '!': /* File length in K */
+ for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
+ abuf[i] = *s++;
+ abuf[i] = '\0'; /* Terminate with null */
+ if (i < aln) s += (aln - i); /* If field was too long for buffer */
+ yy->lengthk = ckatofs(abuf); /* Convert to number */
+ break;
+#endif /* COMMENT */
+
+ case '/': /* Record format */
+ rfbuf[1] = NUL;
+ rfbuf[2] = NUL;
+ for (i = 0; (i < aln) && (i < RFBUFL); i++) /* Copy it */
+ rfbuf[i] = *s++;
+ rfbuf[i] = NUL; /* Terminate with null */
+ yy->recfm.val = rfbuf; /* Pointer to string */
+ yy->recfm.len = i; /* Length of string */
+ if ((rfbuf[0] != 'A') ||
+ (rfbuf[1] && rfbuf[1] != 'M') ||
+ (rfbuf[2] && rfbuf[2] != 'J')) {
+ debug(F110,"gattr bad recfm",rfbuf,0);
+ *rp++ = c;
+ retcode = -1;
+ }
+ break;
+
+ case '"': /* File type (text, binary, ...) */
+ for (i = 0; (i < aln) && (i < FTBUFL); i++)
+ ftbuf[i] = *s++; /* Copy it into a static string */
+ ftbuf[i] = '\0';
+ if (i < aln) s += (aln - i);
+ /* TYPE attribute is enabled? */
+ if (attypi) {
+ yy->type.val = ftbuf; /* Pointer to string */
+ yy->type.len = i; /* Length of string */
+ debug(F111,"gattr file type", ftbuf, i);
+ debug(F101,"gattr binary 1","",binary);
+ /* Unknown type? */
+ if ((*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I')
+#ifdef CK_LABELED
+/* ... Or our FILE TYPE is LABELED and the incoming file is text... */
+ || (binary == XYFT_L && *ftbuf == 'A' && !xflg)
+#endif /* CK_LABELED */
+ ) {
+ retcode = -1; /* Reject the file */
+ *rp++ = c;
+ if (!opnerr) tlog(F100," refused: type","",0);
+ break;
+ }
+/*
+ The following code moved here from opena() so we set binary mode
+ as soon as requested by the attribute packet. That way when the first
+ data packet comes, the mode of transfer can be displayed correctly
+ before opena() is called.
+*/
+ if (yy->type.val[0] == 'A') { /* Check received attributes. */
+#ifdef VMS
+ if (binary != XYFT_I) /* VMS IMAGE overrides this */
+#endif /* VMS */
+ binary = XYFT_T; /* Set current type to Text. */
+ debug(F101,"gattr binary 2","",binary);
+ } else if (yy->type.val[0] == 'B') {
+#ifdef CK_LABELED
+ if (binary != XYFT_L
+#ifdef VMS
+ && binary != XYFT_U /* VMS special case */
+#endif /* VMS */
+ )
+#endif /* CK_LABELED */
+#ifdef MAC
+ if (binary != XYFT_M) /* If not MacBinary... */
+#endif /* MAC */
+ binary = XYFT_B;
+ debug(F101,"gattr binary 3","",binary);
+ }
+ }
+ break;
+
+ case '#': /* File creation date */
+ for (i = 0; (i < aln) && (i < DTBUFL); i++)
+ dtbuf[i] = *s++; /* Copy it into a static string */
+ if (i < aln) s += (aln - i);
+ dtbuf[i] = '\0';
+ if (atdati && !xflg) { /* Real file and dates enabled */
+ yy->date.val = dtbuf; /* Pointer to string */
+ yy->date.len = i; /* Length of string */
+ if (fncact == XYFX_U) { /* Receiving in update mode? */
+ if (zstime(ff,yy,1) > 0) { /* Compare dates */
+ *rp++ = c; /* Discard if older, reason = date. */
+ if (!opnerr) tlog(F100," refused: date","",0);
+ retcode = -1; /* Rejection notice. */
+ }
+ }
+ }
+ break;
+
+ case '(': /* File Block Size */
+ for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
+ abuf[i] = *s++;
+ abuf[i] = '\0'; /* Terminate with null */
+ if (i < aln) s += (aln - i);
+ if (atblki)
+ yy->blksize = atol(abuf); /* Convert to number */
+ break;
+
+ case '*': /* Encoding (transfer syntax) */
+ for (i = 0; (i < aln) && (i < TSBUFL); i++)
+ tsbuf[i] = *s++; /* Copy it into a static string */
+ if (i < aln) s += (aln - i);
+ tsbuf[i] = '\0';
+#ifndef NOCSETS
+ xlatype = XLA_NONE; /* Assume no translation */
+#endif /* NOCSETS */
+ if (atenci) {
+ char * ss;
+ yy->encoding.val = tsbuf; /* Pointer to string */
+ yy->encoding.len = i; /* Length of string */
+ debug(F101,"gattr encoding",tsbuf,i);
+ ss = tsbuf+1;
+ switch (*tsbuf) {
+#ifndef NOCSETS
+ case 'A': /* Normal, nothing special */
+ tcharset = TC_TRANSP; /* Transparent chars untranslated */
+ debug(F110,"gattr sets tcharset TC_TRANSP","A",0);
+ break;
+ case 'C': /* Specified character set */
+ if (!xfrxla) { /* But translation disabled */
+ tcharset = TC_TRANSP;
+ debug(F110,"gattr sets tcharset TC_TRANSP","C",0);
+ break;
+ }
+#ifdef UNICODE
+ if (!strcmp("I196",ss)) /* Treat I196 (UTF-8 no level) */
+ ss = "I190"; /* as I190 (UTF-8 Level 1) */
+#endif /* UNICODE */
+ if (!strcmp("I6/204",ss)) /* Treat "Latin-1 + Euro" */
+ ss = "I6/100"; /* as I6/100 (regular Latin-1) */
+ for (i = 0; i < ntcsets; i++) {
+ if (!strcmp(tcsinfo[i].designator,ss))
+ break;
+ }
+ debug(F101,"gattr xfer charset lookup","",i);
+ if (i == ntcsets) { /* If unknown character set, */
+ debug(F110,"gattr: xfer charset unknown",ss,0);
+ if (!unkcs) { /* and SET UNKNOWN DISCARD, */
+ retcode = -1; /* reject the file. */
+ *rp++ = c;
+ if (!opnerr)
+ tlog(F100," refused: character set","",0);
+ }
+ } else {
+ tcharset = tcsinfo[i].code; /* it's known, use it */
+ debug(F101,"gattr switch tcharset","",tcharset);
+ debug(F101,"gattr fcharset","",fcharset);
+ if (r_cset == XMODE_A) { /* Automatic switching? */
+ if (tcharset > -1 && tcharset <= MAXTCSETS) {
+ int x;
+ x = axcset[tcharset];
+ if (x > 0 && x <= MAXFCSETS) {
+ fcharset = x;
+ debug(F101,"gattr switch fcharset","",x);
+ }
+ }
+ }
+ /* Set up translation type and function */
+ setxlatype(tcharset,fcharset);
+ }
+ break;
+#endif /* NOCSETS */
+ default: /* Something else. */
+ debug(F110,"gattr unk encoding attribute",tsbuf,0);
+ if (!unkcs) { /* If SET UNK DISC */
+ retcode = -1;
+ *rp++ = c;
+ if (!opnerr) tlog(F100," refused: encoding","",0);
+ }
+ break;
+ }
+ }
+ break;
+
+ case '+': /* Disposition */
+#ifdef DYNAMIC
+ if (!dsbuf)
+ if ((dsbuf = malloc(DSBUFL+1)) == NULL)
+ fatal("gtattr: no memory for dsbuf");
+#endif /* DYNAMIC */
+ for (i = 0; (i < aln) && (i < DSBUFL); i++)
+ dsbuf[i] = *s++; /* Copy it into a separate string */
+ dsbuf[i] = '\0';
+ if (i < aln) s += (aln - i);
+ rs_len = (CK_OFF_T)0;
+ if (atdisi) { /* We are doing this attribute */
+ /* Copy it into the attribute structure */
+ yy->disp.val = dsbuf; /* Pointer to string */
+ yy->disp.len = i; /* Length of string */
+ d = *dsbuf;
+#ifndef NODISPO
+/*
+ Define NODISPO to disable receipt of mail or print files and of RESEND.
+*/
+ if (
+#ifndef datageneral /* MAIL supported only for */
+#ifndef OS2 /* UNIX, VMS, and OS-9 */
+#ifndef MAC
+#ifndef GEMDOS
+#ifndef AMIGA
+ d != 'M' && /* MAIL */
+#endif /* AMIGA */
+#endif /* GEMDOS */
+#endif /* MAC */
+#endif /* OS/2 */
+#endif /* datageneral */
+#ifdef CK_RESEND
+ d != 'R' && /* RESEND */
+#endif /* CK_RESEND */
+ d != 'P') { /* PRINT */
+ retcode = -1; /* Unknown/unsupported disposition */
+ *rp++ = c;
+ if (!opnerr) tlog(F101," refused: bad disposition","",d);
+ }
+ dispos = d;
+ debug(F000,"gattr dispos","",dispos);
+ switch (d) {
+#ifndef NOFRILLS
+ case 'M':
+ if (!en_mai) {
+ retcode = -1;
+ *rp++ = c;
+ if (!opnerr) tlog(F100," refused: mail disabled","",0);
+ dispos = 0;
+ }
+ break;
+#endif /* NOFRILLS */
+ case 'P':
+ if (!en_pri) {
+ retcode = -1;
+ *rp++ = c;
+ if (!opnerr)
+ tlog(F100," refused: print disabled","",0);
+ dispos = 0;
+ }
+ break;
+
+ case 'R':
+ dispos = 0;
+#ifdef CK_RESEND
+ rs_len = zgetfs(ff); /* Get length of file */
+ debug(F111,"gattr RESEND",ff,rs_len);
+#ifdef VMS
+ rs_len &= (long) -512; /* Ensure block boundary if VMS */
+ rs_len -= 512; /* In case last block not complete */
+ debug(F111,"gattr rs_len",ff,rs_len);
+#endif /* VMS */
+#ifdef COMMENT
+ if (rs_len < 0L) /* Local file doesn't exist */
+ rs_len = 0L;
+#endif /* COMMENT */
+/*
+ Another possibility here (or later, really) would be to check if the two
+ file lengths are the same, and if so, keep the prevailing collision action
+ as is (note: rs_len == length of existing file; yy->length == fsize ==
+ length of incoming file). This could be complicated, though, since
+ (a) we might not have received the length attribute yet, and in fact it
+ might even be in a subsequent A-packet, yet (b) we have to accept or reject
+ the Recover attribute now. So better to leave as-is. Anyway, it's probably
+ more useful this way.
+*/
+ if (rs_len > (CK_OFF_T)0) {
+ fncsav = fncact; /* Save collision action */
+ fncact = XYFX_A; /* Switch to APPEND */
+ }
+#else
+ retcode = -1; /* This shouldn't happen */
+ *rp++ = c; /* 'cause it wasn't negotiated. */
+ if (!opnerr) tlog(F100," refused: resend","",0);
+#endif /* CK_RESEND */
+ }
+#else /* NODISPO */
+ retcode = -1;
+ *rp++ = c;
+ if (!opnerr) tlog(F100," refused: NODISPO","",0);
+#endif /* NODISPO */
+ }
+ break;
+
+ case '.': /* Sender's system ID */
+ for (i = 0; (i < aln) && (i < IDBUFL); i++)
+ idbuf[i] = *s++; /* Copy it into a static string */
+ idbuf[i] = '\0';
+ if (i < aln) s += (aln - i);
+ if (atsidi) {
+ yy->systemid.val = idbuf; /* Pointer to string */
+ yy->systemid.len = i; /* Length of string */
+ }
+ break;
+
+ case '0': /* System-dependent parameters */
+#ifdef DYNAMIC
+ if (!spbuf && !(spbuf = malloc(SPBUFL)))
+ fatal("gattr: no memory for spbuf");
+#endif /* DYNAMIC */
+ for (i = 0; (i < aln) && (i < SPBUFL); i++)
+ spbuf[i] = *s++; /* Copy it into a static string */
+ spbuf[i] = '\0';
+ if (i < aln) s += (aln - i);
+ if (atsysi) {
+ yy->sysparam.val = spbuf; /* Pointer to string */
+ yy->sysparam.len = i; /* Length of string */
+ }
+ break;
+
+ case '!': /* File length in K */
+ case '1': { /* File length in bytes */
+ char * l2;
+ CK_OFF_T xlen;
+ for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
+ abuf[i] = *s++;
+ abuf[i] = '\0'; /* Terminate with null */
+ if (i < aln) s += (aln - i);
+ if (rdigits(abuf)) { /* Make sure string is all digits */
+ xlen = ckatofs(abuf); /* Convert to number */
+ l2 = ckfstoa(xlen); /* Convert number back to string */
+ if (c == '1')
+ debug(F111,"gattr length",abuf,xlen);
+ else
+ debug(F111,"gattr lengthk",abuf,xlen);
+ if (ckstrcmp(abuf,l2,-1,1)) { /* This is how we check... */
+ xlen = (CK_OFF_T)-2; /* -2 = unk, possibly too long */
+ overflow++;
+ debug(F111,"gattr overflow",
+ (c == '1') ? "length" : "lengthk",
+ xlen);
+ }
+ if (c == '1') {
+ yy->length = xlen;
+ debug(F101,"gattr length","",xlen);
+ } else {
+ yy->lengthk = xlen;
+ debug(F101,"gattr lengthk","",xlen);
+ }
+ }
+ /* If the length field is not numeric accept the file */
+ /* anyway but with an unknown length */
+ break;
+ }
+
+#ifdef CK_PERMS
+ case ',': /* System-dependent protection code */
+ for (i = 0; (i < aln) && (i < CK_PERMLEN); i++)
+ lprmbuf[i] = *s++; /* Just copy it - decode later */
+ lprmbuf[i] = '\0'; /* Terminate with null */
+ if (i < aln) s += (aln - i);
+ if (atlpri) {
+ yy->lprotect.val = (char *)lprmbuf;
+ yy->lprotect.len = i;
+ } else
+ lprmbuf[0] = NUL;
+ break;
+
+ case '-': /* Generic "world" protection code */
+ gprmbuf[0] = NUL; /* Just 1 byte by definition */
+ for (i = 0; i < aln; i++) /* But allow for more... */
+ if (i == 0) gprmbuf[0] = *s++;
+ gprmbuf[1] = NUL;
+ if (atgpri) {
+ yy->gprotect.val = (char *)gprmbuf;
+ yy->gprotect.len = gprmbuf[0] ? 1 : 0;
+ } else
+ gprmbuf[0] = NUL;
+ break;
+#endif /* CK_PERMS */
+
+ default: /* Unknown attribute */
+ s += aln; /* Just skip past it */
+ break;
+ }
+ }
+
+ /* Check space now, because we also need to know the file type */
+ /* in case zchkspa() differentiates text and binary (VMS version does) */
+
+ if (atleni && !calibrate) { /* Length attribute enabled? */
+ if (yy->length > (CK_OFF_T)-1) { /* Length-in-bytes attribute rec'd? */
+ if (!zchkspa(ff,(yy->length))) { /* Check space */
+ retcode = -1; /* Not enuf */
+ *rp++ = '1';
+ if (!opnerr) tlog(F100," refused: length bytes","",0);
+ }
+ } else if (yy->lengthk > (CK_OFF_T)-1) { /* Length in K received? */
+ long xlen;
+ xlen = yy->lengthk * 1024;
+ if (!zchkspa(ff,xlen)) {
+ retcode = -1; /* Check space */
+ *rp++ = '!';
+ if (!opnerr) tlog(F100," refused: length K","",0);
+ }
+ }
+ }
+ if (retcode > -1L) { /* Remember the file size */
+ if (yy->length > (CK_OFF_T)-1) {
+ fsize = yy->length;
+ } else if (yy->lengthk > (CK_OFF_T)-1 && !overflow) {
+ fsize = yy->lengthk * 1024L;
+ } else fsize = yy->length; /* (e.g. -2L) */
+ }
+
+#ifdef DEBUG
+ if (deblog) {
+#ifdef COMMENT
+ sprintf(abuf,"%ld",fsize); /* safe */
+#else
+ ckstrncpy(abuf,ckfstoa(fsize),ABUFL);
+#endif /* COMMENT */
+debug(F110,"gattr fsize",abuf,0);
+ }
+#endif /* DEBUG */
+
+ if (retcode == 0) rp = rpbuf; /* Null reply string if accepted */
+ *rp = '\0'; /* End of reply string */
+
+#ifdef CK_RESEND
+ if (d == 'R') { /* Receiving a RESEND? */
+ debug(F101,"gattr RESEND","",retcode);
+ /* We ignore retcodes because this overrides */
+ if (binary != XYFT_B) { /* Reject if not binary */
+ retcode = -1; /* in case type field came */
+ ckstrncpy(rpbuf,"N+",RPBUFL); /* after the disposition field */
+ debug(F111,"gattr RESEND not binary",rpbuf,binary);
+ } else { /* Binary mode */
+ retcode = 0; /* Accept the file */
+ discard = 0; /* If SET FILE COLLISION DISCARD */
+#ifdef COMMENT
+ sprintf(rpbuf+2,"%ld",rs_len); /* Reply with length of file */
+#else
+ ckstrncpy(rpbuf+2,ckfstoa(rs_len),RPBUFL-2);
+#endif /* COMMENT */
+ rpbuf[0] = '1'; /* '1' means Length in Bytes */
+ rpbuf[1] = tochar((int)strlen(rpbuf+2)); /* Length of length */
+ debug(F111,"gattr RESEND OK",rpbuf,retcode);
+ }
+ }
+#endif /* CK_RESEND */
+ if (retcode == 0 && discard != 0) { /* Do we still have a discard flag? */
+ ckstrncpy(rpbuf,"N?",RPBUFL); /* Yes, must be filename collision */
+ retcode = -1; /* "?" = name (reply-only code) */
+ }
+ yy->reply.val = rpbuf; /* Add it to attribute structure */
+ yy->reply.len = (int)strlen(rpbuf);
+ if (retcode < 0) { /* If we are rejecting */
+ discard = 1; /* remember to discard the file */
+ rejection = rpbuf[1]; /* and use the first reason given. */
+ if (fncsav != -1) {
+ fncact = fncsav;
+ fncsav = -1;
+ }
+ }
+ debug(F111,"gattr return",rpbuf,retcode);
+ return(retcode);
+}
+
+/* I N I T A T T R -- Initialize file attribute structure */
+
+int
+initattr(yy) struct zattr *yy; {
+ yy->lengthk = yy->length = (CK_OFF_T)-1;
+ yy->type.val = "";
+ yy->type.len = 0;
+ yy->date.val = "";
+ yy->date.len = 0;
+ yy->encoding.val = "";
+ yy->encoding.len = 0;
+ yy->disp.val = "";
+ yy->disp.len = 0;
+ yy->systemid.val = "";
+ yy->systemid.len = 0;
+ yy->sysparam.val = "";
+ yy->sysparam.len = 0;
+ yy->creator.val = "";
+ yy->creator.len = 0;
+ yy->account.val = "";
+ yy->account.len = 0;
+ yy->area.val = "";
+ yy->area.len = 0;
+ yy->password.val = "";
+ yy->password.len = 0;
+ yy->blksize = -1L;
+ yy->xaccess.val = "";
+ yy->xaccess.len = 0;
+#ifdef CK_PERMS
+ if (!ofperms) ofperms = "";
+ debug(F110,"initattr ofperms",ofperms,0);
+ yy->lprotect.val = ofperms;
+ yy->lprotect.len = 0 - strlen(ofperms); /* <-- NOTE! */
+ /*
+ A negative length indicates that we have a permissions string but it has
+ been inherited from a previously existing file rather than picked up
+ from an incoming A-packet.
+ */
+#else
+ yy->lprotect.val = "";
+ yy->lprotect.len = 0;
+#endif /* CK_PERMS */
+ yy->gprotect.val = "";
+ yy->gprotect.len = 0;
+ yy->recfm.val = "";
+ yy->recfm.len = 0;
+ yy->reply.val = "";
+ yy->reply.len = 0;
+#ifdef OS2
+ yy->longname.len = 0 ;
+ yy->longname.val = "" ;
+#endif /* OS2 */
+ return(0);
+}
+
+/* A D E B U -- Write attribute packet info to debug log */
+
+int
+adebu(f,zz) char *f; struct zattr *zz; {
+#ifdef DEBUG
+ if (deblog == 0) return(0);
+ debug(F110,"Attributes for incoming file ",f,0);
+ debug(F101," length in K","",(int) zz->lengthk);
+ debug(F111," file type",zz->type.val,zz->type.len);
+ debug(F111," creation date",zz->date.val,zz->date.len);
+ debug(F111," creator",zz->creator.val,zz->creator.len);
+ debug(F111," account",zz->account.val,zz->account.len);
+ debug(F111," area",zz->area.val,zz->area.len);
+ debug(F111," password",zz->password.val,zz->password.len);
+ debug(F101," blksize","",(int) zz->blksize);
+ debug(F111," access",zz->xaccess.val,zz->xaccess.len);
+ debug(F111," encoding",zz->encoding.val,zz->encoding.len);
+ debug(F111," disposition",zz->disp.val,zz->disp.len);
+ debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len);
+ debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len);
+ debug(F111," systemid",zz->systemid.val,zz->systemid.len);
+ debug(F111," recfm",zz->recfm.val,zz->recfm.len);
+ debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len);
+ debug(F101," length","",(int) zz->length);
+ debug(F110," reply",zz->reply.val,0);
+#endif /* DEBUG */
+ return(0);
+}
+
+/* O P E N A -- Open a file, with attributes. */
+/*
+ This function tries to open a new file to put the arriving data in. The
+ filename is the one in the srvcmd buffer. File collision actions are:
+ OVERWRITE (the existing file is overwritten), RENAME (the new file is
+ renamed), BACKUP (the existing file is renamed), DISCARD (the new file is
+ refused), UPDATE (the incoming file replaces the existing file only if the
+ incoming file has a newer creation date).
+
+ Returns 0 on failure, nonzero on success.
+*/
+extern char *rf_err;
+
+int
+opena(f,zz) char *f; struct zattr *zz; {
+ int x, dispos = 0;
+ static struct filinfo fcb; /* Must be static! */
+
+ debug(F110,"opena f",f,0);
+ debug(F101,"opena discard","",discard);
+
+ adebu(f,zz); /* Write attributes to debug log */
+
+ ffc = (CK_OFF_T)0; /* Init file-character counter */
+
+#ifdef PIPESEND
+ if (pipesend) /* Receiving to a pipe - easy. */
+ return(openo(f,zz,&fcb)); /* Just open the pipe. */
+#endif /* PIPESEND */
+
+ /* Receiving to a file - set up file control structure */
+
+ fcb.bs = fblksiz; /* Blocksize */
+#ifndef NOCSETS
+ fcb.cs = fcharset; /* Character set */
+#else
+ fcb.cs = 0; /* Character set */
+#endif /* NOCSETS */
+ fcb.rl = frecl; /* Record Length */
+ fcb.fmt = frecfm; /* Record Format */
+ fcb.org = forg; /* Organization */
+ fcb.cc = fcctrl; /* Carriage control */
+ fcb.typ = binary; /* Type */
+ debug(F101,"opena xflg","",xflg);
+ debug(F101,"opena remfile","",remfile);
+ debug(F101,"opena remappd","",remappd);
+ if (xflg && remfile && remappd) /* REMOTE output redirected with >> */
+ fcb.dsp = XYFZ_A;
+ else
+ fcb.dsp = (fncact == XYFX_A) ? XYFZ_A : XYFZ_N; /* Disposition */
+ debug(F101,"opena disp","",fcb.dsp);
+ fcb.os_specific = ""; /* OS-specific info */
+#ifdef CK_LABELED
+ fcb.lblopts = lf_opts; /* Labeled file options */
+#else
+ fcb.lblopts = 0;
+#endif /* CK_LABELED */
+
+ if (zz->disp.len > 0) { /* Incoming file has a disposition? */
+ debug(F111,"open disposition",zz->disp.val,zz->disp.len);
+ dispos = (int) (*(zz->disp.val));
+ }
+ if (!dispos && xflg && remfile && remappd) /* REMOTE redirect append ? */
+ dispos = fcb.dsp;
+
+ debug(F101,"opena dispos","",dispos);
+
+ if (!dispos) { /* No special disposition? */
+ if (fncact == XYFX_B && ofn1x && ofn2) { /* File collision = BACKUP? */
+ if (zrename(ofn1,ofn2) < 0) { /* Rename existing file. */
+ debug(F110,"opena rename fails",ofn1,0);
+ rf_err = "Can't create backup file";
+ return(0);
+ } else debug(F110,"opena rename ok",ofn2,0);
+ }
+ } else if (dispos == 'R') { /* Receiving a RESEND */
+ debug(F101,"opena remote len","",zz->length);
+ debug(F101,"opena local len","",rs_len);
+#ifdef COMMENT
+ if (fncact == XYFX_R) /* and file collision = RENAME */
+ if (ofn1x)
+#endif /* COMMENT */
+ if (ofn1[0])
+ f = ofn1; /* use original name. */
+ if (fncact == XYFX_R) /* if file collision is RENAME */
+ ckstrncpy(filnam,ofn1,CKMAXPATH+1); /* restore the real name */
+ xxscreen(SCR_AN,0,0L,f); /* update name on screen */
+ if (zz->length == rs_len) /* Local and remote lengths equal? */
+ return(-17); /* Secret code */
+ }
+ debug(F111,"opena [file]=mode: ",f,fcb.dsp);
+ if (x = openo(f,zz,&fcb)) { /* Try to open the file. */
+#ifdef pdp11
+ tlog(F110," local name:",f,0L); /* OK, open, record local name. */
+ makestr(&prfspec,f); /* New preliminary name */
+#else
+#ifndef ZFNQFP
+ tlog(F110," local name:",f,0L);
+ makestr(&prfspec,f);
+#else
+ { /* Log full local pathname */
+ char *p = NULL, *q = f;
+ if ((p = malloc(CKMAXPATH+1)))
+ if (zfnqfp(filnam, CKMAXPATH, p))
+ q = p;
+ tlog(F110," local name:",q,0L);
+ makestr(&prfspec,q);
+ if (p) free(p);
+ }
+#endif /* ZFNQFP */
+#endif /* pdp11 */
+
+ if (binary) { /* Log file mode in transaction log */
+ tlog(F101," mode: binary","",(long) binary);
+ } else { /* If text mode, check character set */
+ tlog(F100," mode: text","",0L);
+#ifndef NOCSETS
+ if (xfrxla) {
+ if (fcharset > -1 && fcharset <= MAXFCSETS)
+ tlog(F110," file character-set:",fcsinfo[fcharset].name,0L);
+ if (tcharset > -1 && tcharset <= MAXTCSETS)
+ tlog(F110," xfer character-set:",tcsinfo[tcharset].name,0L);
+ } else {
+ tlog(F110," character-set:","transparent",0L);
+ }
+#endif /* NOCSETS */
+ debug(F111,"opena charset",zz->encoding.val,zz->encoding.len);
+ }
+ debug(F101,"opena binary","",binary);
+
+#ifdef COMMENT
+ if (fsize >= 0)
+#endif /* COMMENT */
+ xxscreen(SCR_FS,0,fsize,"");
+
+#ifdef datageneral
+/*
+ Need to turn on multi-tasking console interrupt task here, since multiple
+ files may be received (huh?) ...
+*/
+ if ((local) && (!quiet)) /* Only do this if local & not quiet */
+ consta_mt(); /* Start the async read task */
+#endif /* datageneral */
+
+ } else { /* Did not open file OK. */
+
+ rf_err = ck_errstr(); /* Get system error message */
+ if (*rf_err)
+ xxscreen(SCR_EM,0,0l,rf_err);
+ else
+ xxscreen(SCR_EM,0,0l,"Can't open output file");
+ tlog(F110,"Failure to open",f,0L);
+ tlog(F110,"Error:",rf_err,0L);
+ debug(F110,"opena error",rf_err,0);
+ }
+ return(x); /* Pass on return code from openo */
+}
+
+/* O P E N C -- Open a command (in place of a file) for output */
+
+int
+openc(n,s) int n; char * s; {
+ int x;
+#ifndef NOPUSH
+ x = zxcmd(n,s);
+#else
+ x = 0;
+#endif /* NOPUSH */
+ debug(F111,"openc zxcmd",s,x);
+ o_isopen = (x > 0) ? 1 : 0;
+ return(x);
+}
+
+/* C A N N E D -- Check if current file transfer cancelled */
+
+int
+canned(buf) CHAR *buf; {
+ extern int interrupted;
+ if (*buf == 'X') cxseen = 1;
+ if (*buf == 'Z') czseen = 1;
+ if (czseen || cxseen)
+ interrupted = 1;
+ debug(F101,"canned: cxseen","",cxseen);
+ debug(F101," czseen","",czseen);
+ return((czseen || cxseen) ? 1 : 0);
+}
+
+
+/* O P E N I -- Open an existing file for input */
+
+int
+openi(name) char *name; {
+#ifndef NOSERVER
+ extern int fromgetpath;
+#endif /* NOSERVER */
+ int x, filno;
+ char *name2;
+ extern CHAR *epktmsg;
+
+ epktmsg[0] = NUL; /* Initialize error message */
+ if (memstr || sndarray) { /* Just return if "file" is memory. */
+ i_isopen = 1;
+ return(1);
+ }
+ debug(F110,"openi name",name,0);
+ debug(F101,"openi sndsrc","",sndsrc);
+
+ filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */
+ debug(F101,"openi file number","",filno);
+
+#ifndef NOSERVER
+ /* If I'm a server and CWD is disabled and name is not from GET-PATH... */
+
+ if (server && !en_cwd && !fromgetpath) {
+ zstrip(name,&name2);
+ if ( /* ... check if pathname included. */
+#ifdef VMS
+ zchkpath(name)
+#else
+ strcmp(name,name2)
+#endif /* VMS */
+ ) {
+ tlog(F110,name,"access denied",0L);
+ debug(F110,"openi CD disabled",name,0);
+ ckstrncpy((char *)epktmsg,"Access denied",PKTMSGLEN);
+ return(0);
+ } else name = name2;
+ }
+#endif /* NOSERVER */
+
+#ifdef PIPESEND
+ debug(F101,"openi pipesend","",pipesend);
+ if (pipesend) {
+ int x;
+#ifndef NOPUSH
+ x = zxcmd(ZIFILE,name);
+#else
+ x = 0;
+#endif /* NOPUSH */
+ i_isopen = (x > 0) ? 1 : 0;
+ if (!i_isopen)
+ ckstrncpy((char *)epktmsg,"Command or pipe failure",PKTMSGLEN);
+ debug(F111,"openi pipesend zxcmd",name,x);
+ return(i_isopen);
+ }
+#endif /* PIPESEND */
+
+#ifdef CALIBRATE
+ if (calibrate) {
+ i_isopen = 1;
+ return(1);
+ }
+#endif /* CALIBRATE */
+
+ x = zopeni(filno,name); /* Otherwise, try to open it. */
+ debug(F111,"openi zopeni 1",name,x);
+ if (x) {
+ i_isopen = 1;
+ return(1);
+ } else { /* If not found, */
+ char xname[CKMAXPATH]; /* convert the name */
+#ifdef NZLTOR
+ nzrtol(name,xname,fncnv,fnrpath,CKMAXPATH);
+#else
+ zrtol(name,xname); /* to local form and then */
+#endif /* NZLTOR */
+ x = zopeni(filno,xname); /* try opening it again. */
+ debug(F111,"openi zopeni 2",xname,x);
+ if (x) {
+ i_isopen = 1;
+ return(1); /* It worked. */
+ } else {
+ char * s;
+ s = ck_errstr();
+ if (s) if (!s) s = NULL;
+ if (!s) s = "Can't open file";
+ ckstrncpy((char *)epktmsg,s,PKTMSGLEN);
+ tlog(F110,xname,s,0L);
+ debug(F110,"openi failed",xname,0);
+ debug(F110,"openi message",s,0);
+ i_isopen = 0;
+ return(0);
+ }
+ }
+}
+
+/* O P E N O -- Open a new file for output. */
+
+int
+openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; {
+ char *name2;
+#ifdef DTILDE
+ char *dirp;
+#endif /* DTILDE */
+
+ int channel, x;
+
+ if (stdouf) { /* Receiving to stdout? */
+ x = zopeno(ZSTDIO,"",zz,NULL);
+ o_isopen = (x > 0);
+ debug(F101,"openo stdouf zopeno","",x);
+ return(x);
+ }
+ debug(F110,"openo: name",name,0);
+
+ if (cxseen || czseen || discard) { /* If interrupted, get out before */
+ debug(F100," open cancelled","",0); /* destroying existing file. */
+ return(1); /* Pretend to succeed. */
+ }
+ channel = ZOFILE; /* SET DESTINATION DISK or PRINTER */
+
+#ifdef PIPESEND
+ debug(F101,"openo pipesend","",pipesend);
+ if (pipesend) {
+ int x;
+#ifndef NOPUSH
+ x = zxcmd(ZOFILE,(char *)srvcmd);
+#else
+ x = 0;
+#endif /* NOPUSH */
+ o_isopen = x > 0;
+ debug(F101,"openo zxcmd","",x);
+ return(x);
+ }
+#endif /* PIPESEND */
+
+ if (dest == DEST_S) { /* SET DEST SCREEN... */
+ channel = ZCTERM;
+ fcb = NULL;
+ }
+#ifdef DTILDE
+ if (*name == '~') {
+ dirp = tilde_expand(name);
+ if (*dirp) ckstrncpy(name,dirp,CKMAXPATH+1);
+ }
+#endif /* DTILDE */
+ if (server && !en_cwd) { /* If running as server */
+ zstrip(name,&name2); /* and CWD is disabled, */
+ if (strcmp(name,name2)) { /* check if pathname was included. */
+ tlog(F110,name,"authorization failure",0L);
+ debug(F110,"openo CD disabled",name,0);
+ return(0);
+ } else name = name2;
+ }
+ if (zopeno(channel,name,zz,fcb) <= 0) { /* Try to open the file */
+ o_isopen = 0;
+ debug(F110,"openo failed",name,0);
+ /* tlog(F110,"Failure to open",name,0L); */
+ return(0);
+ } else {
+ o_isopen = 1;
+ debug(F110,"openo ok, name",name,0);
+ return(1);
+ }
+}
+
+/* O P E N T -- Open the terminal for output, in place of a file */
+
+int
+opent(zz) struct zattr *zz; {
+ int x;
+ ffc = tfc = (CK_OFF_T)0;
+ x = zopeno(ZCTERM,"",zz,NULL);
+ debug(F101,"opent zopeno","",x);
+ if (x >= 0) {
+ o_isopen = 1;
+ binary = XYFT_T;
+ } else
+ return(0);
+ return(x);
+}
+
+/* O P E N X -- Open nothing (incoming file to be accepted but ignored) */
+
+int
+ckopenx(zz) struct zattr *zz; {
+ ffc = tfc = (CK_OFF_T)0; /* Reset counters */
+ o_isopen = 1;
+ debug(F101,"ckopenx fsize","",fsize);
+ xxscreen(SCR_FS,0,fsize,""); /* Let screen display know the size */
+ return(1);
+}
+
+/* C L S I F -- Close the current input file. */
+
+int
+clsif() {
+ extern int xferstat, success;
+ int x = 0;
+
+ fcps(); /* Calculate CPS quickly */
+
+#ifdef datageneral
+ if ((local) && (!quiet)) /* Only do this if local & not quiet */
+ if (nfils < 1) /* More files to send ... leave it on! */
+ connoi_mt();
+#endif /* datageneral */
+
+ debug(F101,"clsif i_isopen","",i_isopen);
+ if (i_isopen) { /* If input file is open... */
+ if (memstr) { /* If input was memory string, */
+ memstr = 0; /* indicate no more. */
+ } else {
+ x = zclose(ZIFILE); /* else close input file. */
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"clsif zclose","",x);
+ debug(F101,"clsif success","",success);
+ debug(F101,"clsif xferstat","",xferstat);
+ debug(F101,"clsif fsize","",fsize);
+ debug(F101,"clsif ffc","",ffc);
+ debug(F101,"clsif cxseen","",cxseen);
+ debug(F101,"clsif czseen","",czseen);
+ debug(F101,"clsif discard","",czseen);
+ }
+#endif /* DEBUG */
+ if ((cxseen || czseen) && !epktsent) { /* If interrupted */
+ xxscreen(SCR_ST,ST_INT,0l,""); /* say so */
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,psfspec,fsize,binary,1,"Interrupted");
+#endif /* TLOG */
+ } else if (discard && !epktsent) { /* If I'm refusing */
+ xxscreen(SCR_ST,ST_REFU,0l,refused); /* say why */
+#ifdef TLOG
+ if (tralog && !tlogfmt) {
+ char buf[128];
+ ckmakmsg(buf,128,"Refused: ",refused,NULL,NULL);
+ doxlog(what,psfspec,fsize,binary,1,buf);
+ }
+#endif /* TLOG */
+ } else if (!epktrcvd && !epktsent && !cxseen && !czseen) {
+ CK_OFF_T zz;
+ zz = ffc;
+#ifdef CK_RESEND
+ if (sendmode == SM_RESEND || sendmode == SM_PSEND)
+ zz += sendstart;
+#endif /* CK_RESEND */
+ debug(F101,"clsif fstats","",zz);
+ fstats(); /* Update statistics */
+ if ( /* Was the whole file sent? */
+#ifdef VMS
+ 0 /* Not a reliable check in VMS */
+#else
+#ifdef STRATUS
+ 0 /* Probably not for VOS either */
+#else
+ zz < fsize
+#ifdef CK_CTRLZ
+ && ((eofmethod != XYEOF_Z && !binary) || binary)
+#endif /* CK_CTRLZ */
+#endif /* STRATUS */
+#endif /* VMS */
+ ) {
+ xxscreen(SCR_ST,ST_INT,0l,"");
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,psfspec,fsize,binary,1,"Incomplete");
+#endif /* TLOG */
+ } else {
+#ifdef COMMENT
+ /* Not yet -- we don't have confirmation from the receiver */
+ xxscreen(SCR_ST,ST_OK,0l,"");
+#endif /* COMMENT */
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,psfspec,fsize,binary,0,"");
+#endif /* TLOG */
+ }
+ }
+ }
+ i_isopen = 0;
+ hcflg = 0; /* Reset flags */
+ sendstart = (CK_OFF_T)0; /* Don't do this again! */
+#ifdef COMMENT
+/*
+ This prevents a subsequent call to clsof() from deleting the file
+ when given the discard flag.
+*/
+ *filnam = '\0'; /* and current file name */
+#endif /* COMMENT */
+ return(x);
+}
+
+
+/* C L S O F -- Close an output file. */
+
+/* Call with disp != 0 if file is to be discarded. */
+/* Returns -1 upon failure to close, 0 or greater on success. */
+
+int
+clsof(disp) int disp; {
+ int x = 0;
+ extern int success;
+
+ fcps(); /* Calculate CPS quickly */
+
+ debug(F101,"clsof disp","",disp);
+ debug(F101,"clsof cxseen","",cxseen);
+ debug(F101,"clsof success","",success);
+
+ debug(F101,"clsof o_isopen","",o_isopen);
+ if (fncsav != -1) { /* Saved file collision action... */
+ fncact = fncsav; /* Restore it. */
+ fncsav = -1; /* Unsave it. */
+ }
+#ifdef datageneral
+ if ((local) && (!quiet)) /* Only do this if local & not quiet */
+ connoi_mt();
+#endif /* datageneral */
+ if (o_isopen && !calibrate) {
+ if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */
+ tlog(F100,"Failure to close",filnam,0L);
+ xxscreen(SCR_ST,ST_ERR,0l,"Can't close file");
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,prfspec,fsize,binary,1,"Can't close file");
+#endif /* TLOG */
+ } else if (disp) { /* Interrupted or refused */
+ if (keep == 0 || /* If not keeping incomplete files */
+ (keep == SET_AUTO && binary == XYFT_T)
+ ) {
+ if (*filnam && (what & W_RECV)) /* AND we're receiving */
+ zdelet(filnam); /* ONLY THEN, delete it */
+ if (what & W_KERMIT) {
+ debug(F100,"clsof incomplete discarded","",0);
+ tlog(F100," incomplete: discarded","",0L);
+ if (!epktrcvd && !epktsent) {
+ xxscreen(SCR_ST,ST_DISC,0l,"");
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,prfspec,fsize,binary,1,"Discarded");
+#endif /* TLOG */
+ }
+ }
+ } else { /* Keep incomplete copy */
+ debug(F100,"clsof fstats 1","",0);
+ fstats();
+ if (!discard) { /* Unless discarding for other reason... */
+ if (what & W_KERMIT) {
+ debug(F100,"closf incomplete kept","",0);
+ tlog(F100," incomplete: kept","",0L);
+ }
+ }
+ if (what & W_KERMIT) {
+ if (!epktrcvd && !epktsent) {
+ xxscreen(SCR_ST,ST_INC,0l,"");
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,prfspec,fsize,binary,1,"Incomplete");
+#endif /* TLOG */
+ }
+ }
+ }
+ }
+ }
+ if (o_isopen && x > -1 && !disp) {
+ debug(F110,"clsof OK",rfspec,0);
+ makestr(&rfspec,prfspec);
+ makestr(&rrfspec,prrfspec);
+ fstats();
+ if (!epktrcvd && !epktsent && !cxseen && !czseen) {
+ xxscreen(SCR_ST,ST_OK,0L,"");
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,rfspec,fsize,binary,0,"");
+#endif /* TLOG */
+ }
+ }
+ rs_len = (CK_OFF_T)0;
+ o_isopen = 0; /* The file is not open any more. */
+ cxseen = 0; /* Reset per-file interruption flag */
+ return(x); /* Send back zclose() return code. */
+}
+
+#ifdef SUNOS4S5
+tolower(c) char c; { return((c)-'A'+'a'); }
+toupper(c) char c; { return((c)-'a'+'A'); }
+#endif /* SUNOS4S5 */
+#endif /* NOXFER */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcfns.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcfns.c
new file mode 100644
index 0000000..0f2bd86
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcfns.c
@@ -0,0 +1,7165 @@
+char *fnsv = "C-Kermit functions, 9.0.233, 3 Jun 2011";
+
+char *nm[] = { "Disabled", "Local only", "Remote only", "Enabled" };
+
+/* C K C F N S -- System-independent Kermit protocol support functions. */
+
+/* ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+/*
+ System-dependent primitives defined in:
+
+ ck?tio.c -- terminal (communications) i/o
+ cx?fio.c -- file i/o, directory structure
+*/
+#include "ckcsym.h" /* Needed for Stratus VOS */
+#include "ckcasc.h" /* ASCII symbols */
+#include "ckcdeb.h" /* Debug formats, typedefs, etc. */
+#include "ckcker.h" /* Symbol definitions for Kermit */
+#include "ckcxla.h" /* Character set symbols */
+#include "ckcnet.h" /* VMS definition of TCPSOCKET */
+#ifdef OS2
+#ifdef OS2ONLY
+#include <os2.h>
+#endif /* OS2ONLY */
+#include "ckocon.h"
+#endif /* OS2 */
+
+int docrc = 0; /* Accumulate CRC for \v(crc16) */
+long crc16 = 0L; /* File CRC = \v(crc16) */
+int gnferror = 0; /* gnfile() failure reason */
+
+extern CHAR feol;
+extern int byteorder, xflg, what, fmask, cxseen, czseen, nscanfile, sysindex;
+extern int xcmdsrc, dispos, matchfifo;
+extern int inserver;
+
+extern int nolinks;
+#ifdef VMSORUNIX
+extern int zgfs_dir;
+#ifdef CKSYMLINK
+extern int zgfs_link;
+#endif /* CKSYMLINK */
+#endif /* VMSORUNIX */
+
+#ifndef NOXFER
+
+#ifndef NOICP
+#ifndef NOSPL
+extern char * clcmds;
+extern int haveurl;
+#ifdef CK_APC
+extern int apcactive, adl_ask;
+#endif /* CK_APC */
+#endif /* NOSPL */
+#endif /* NOICP */
+
+extern int remfile;
+
+/* (move these prototypes to the appropriate .h files...) */
+
+#ifdef COMMENT
+/* Not used */
+#ifdef VMS
+_PROTOTYP( int getvnum, (char *) );
+#endif /* VMS */
+#endif /* COMMENT */
+
+_PROTOTYP( static int bgetpkt, (int) );
+#ifndef NOCSETS
+_PROTOTYP( int lookup, (struct keytab[], char *, int, int *) );
+#endif /* NOCSETS */
+#ifndef NOSPL
+_PROTOTYP( int zzstring, (char *, char **, int *) );
+#endif /* NOSPL */
+
+#ifdef OS2
+#include <io.h>
+#ifdef OS2ONLY
+#include <os2.h>
+#endif /* OS2ONLY */
+#endif /* OS2 */
+
+#ifdef VMS
+#include <errno.h>
+#endif /* VMS */
+
+/* Externals from ckcmai.c */
+
+extern int srvcdmsg, srvidl, idletmo;
+extern char * cdmsgfile[];
+extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
+ rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
+extern int pktnum, bctr, bctu, bctf, bctl, clfils, sbufnum, protocol,
+ size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success;
+extern int parity, turn, network, whatru, fsecs, justone, slostart,
+ ckdelay, displa, mypadn, moving, recursive, nettype;
+extern long filcnt;
+extern CK_OFF_T
+ tfc, fsize, sendstart, rs_len, flci, flco, tlci, tlco, calibrate;
+extern long filrej, oldcps, cps, peakcps, ccu, ccp, filestatus;
+extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup;
+extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
+extern int hcflg, binary, fncnv, b_save, f_save, server;
+extern int nakstate, discard, rejection, local, xfermode, interrupted;
+extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
+extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike;
+extern int atcapr, atcapb, atcapu;
+extern int lpcapr, lpcapb, lpcapu;
+extern int swcapr, swcapb, swcapu;
+extern int lscapr, lscapb, lscapu;
+extern int rscapr, rscapb, rscapu;
+extern int rptena, rptmin;
+extern int sseqtbl[];
+extern int numerrs, nzxopts;
+extern long rptn;
+extern int maxtry;
+extern int stdouf;
+extern int sendmode;
+extern int carrier, ttprty;
+extern int g_fnrpath;
+#ifdef TCPSOCKET
+extern int ttnproto;
+#endif /* TCPSOCKET */
+
+#ifndef NOSPL
+extern int sndxin, sndxhi, sndxlo;
+#endif /* NOSPL */
+
+extern int g_binary, g_fncnv;
+
+#ifdef GFTIMER
+extern CKFLOAT fpfsecs;
+#endif /* GFTIMER */
+
+#ifdef OS2
+extern struct zattr iattr;
+#endif /* OS2 */
+
+#ifdef PIPESEND
+extern int usepipes;
+#endif /* PIPESEND */
+extern int pipesend;
+
+#ifdef STREAMING
+extern int streamrq, streaming, streamed, streamok;
+#endif /* STREAMING */
+extern int reliable, clearrq, cleared, urclear;
+
+extern int
+ atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
+ attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
+
+extern int bigsbsiz, bigrbsiz;
+extern char *versio;
+extern char *filefile;
+extern char whoareu[], * cksysid;
+
+#ifndef NOSERVER
+extern int ngetpath;
+extern char * getpath[];
+extern int fromgetpath;
+#endif /* NOSERVER */
+
+#ifdef CK_LOGIN
+extern int isguest;
+#endif /* CK_LOGIN */
+
+extern int srvcmdlen;
+extern CHAR *srvcmd, * epktmsg;
+extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq;
+extern CHAR *data, padbuf[], stchr, mystch;
+extern CHAR *srvptr;
+extern CHAR *rdatap;
+extern char *cmarg, *cmarg2, **cmlist, filnam[], ofilnam[];
+extern char *rfspec, *prfspec, *rrfspec, *prrfspec, *sfspec, *psfspec, *rfspec;
+extern char fspec[];
+extern int fspeclen;
+
+#ifndef NOMSEND
+extern struct filelist * filehead, * filenext;
+extern int addlist;
+#endif /* NOMSEND */
+
+_PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
+_PROTOTYP( int szeof, (CHAR *s) );
+_PROTOTYP( VOID fnlist, (void) );
+#endif /* NOXFER */
+
+extern CK_OFF_T ffc;
+
+/* Character set Translation */
+
+#ifndef NOCSETS
+extern int tcharset, fcharset, dcset7, dcset8;
+extern int fcs_save, tcs_save;
+extern int ntcsets, xlatype, cseqtab[];
+extern struct csinfo tcsinfo[], fcsinfo[];
+extern int r_cset, s_cset, afcset[];
+#ifdef UNICODE
+extern int ucsorder, fileorder;
+#endif /* UNICODE */
+
+_PROTOTYP( CHAR ident, (CHAR) ); /* Identity translation function */
+
+/* Arrays of and pointers to character translation functions */
+
+#ifdef CK_ANSIC
+extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */
+extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Send */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Recv */
+#ifdef UNICODE
+extern int (*xut)(USHORT); /* Translation function UCS to TCS */
+extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
+extern USHORT (*xtu)(CHAR); /* Translation function TCS to UCS */
+extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
+#endif /* UNICODE */
+
+#else /* The same declarations again for non-ANSI comilers... */
+
+extern CHAR (*rx)();
+extern CHAR (*sx)();
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();
+#ifdef UNICODE
+extern int (*xut)();
+extern int (*xuf)();
+extern USHORT (*xtu)();
+extern USHORT (*xfu)();
+#endif /* UNICODE */
+#endif /* CK_ANSIC */
+#endif /* NOCSETS */
+
+/* (PWP) external def. of things used in buffered file input and output */
+
+#ifdef DYNAMIC
+extern char *zinbuffer, *zoutbuffer;
+#else
+extern char zinbuffer[], zoutbuffer[];
+#endif /* DYNAMIC */
+extern char *zinptr, *zoutptr;
+extern int zincnt, zoutcnt, zobufsize, xfrxla;
+
+extern long crcta[], crctb[]; /* CRC-16 generation tables */
+extern int rseqtbl[]; /* Rec'd-packet sequence # table */
+
+#ifndef NOXFER
+
+/* Criteria used by gnfile()... */
+
+char sndafter[19] = { NUL, NUL };
+char sndbefore[19] = { NUL, NUL };
+char sndnafter[19] = { NUL, NUL };
+char sndnbefore[19] = { NUL, NUL };
+char *sndexcept[NSNDEXCEPT] = { NULL, NULL };
+char *rcvexcept[NSNDEXCEPT] = { NULL, NULL };
+CK_OFF_T sndsmaller = (CK_OFF_T)-1;
+CK_OFF_T sndlarger = (CK_OFF_T)-1;
+
+/* Variables defined in this module but shared by other modules. */
+
+int xfrbel = 1;
+char * ofperms = ""; /* Output file permissions */
+int autopath = 0; /* SET RECEIVE PATHNAMES AUTO flag */
+
+#ifdef CALIBRATE
+#define CAL_O 3
+#define CAL_M 253
+
+int cal_j = 0;
+
+CHAR
+cal_a[] = {
+ 16, 45, 98, 3, 52, 41, 14, 7, 76,165,122, 11,104, 77,166, 15,
+160, 93, 18, 19,112, 85, 54, 23,232,213, 90, 27, 12, 81,126, 31,
+ 4,205, 34, 35,144, 73,110, 39, 28,133,218, 43,156, 65,102, 47,
+ 84, 61, 50, 51,208,117, 86, 55, 8,245, 74, 59, 44,125,222, 63,
+ 80, 1,162, 67,116,105,206, 71,120, 9,250, 75, 88, 97, 6, 79,
+100,221, 82, 83, 36, 89, 94, 87, 40, 21,106, 91,236,145,150, 95,
+228, 33,130, 99,148,137,198,103,108,169, 42,107,184,129, 78,111,
+ 0, 49,114,115, 32,121,254,119,172, 57,138,123,152,177, 22,127,
+240,193, 2,131,176, 5, 38,135,204,229, 10,139,200,161,174,143,
+128, 17,146,147, 68,153, 30,151, 72,217,170,155, 24,209, 62,159,
+ 64,225,194,163,244,201, 70,167,216,197,234,171,188,109,230,175,
+212,113,178,179,132,185,190,183,136,249,202,187, 92,241,118,191,
+ 48,237, 66,195, 96,233,142,199,248, 37, 58,203, 60, 13,134,207,
+ 20, 29,210,211,164,149,182,215,220, 25, 26,219,124,157,246,223,
+180,141,226,227,192,101,238,231, 56, 69,154,235,252,173, 46,239,
+224,253,242,243,196, 53,214,247,168,181,186,251,140,189,158,255
+};
+#endif /* CALIBRATE */
+
+char * rf_err = "Error receiving file"; /* rcvfil() error message */
+
+#ifdef CK_SPEED
+short ctlp[256] = { /* Control-Prefix table */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G0 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* DEL */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C1 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G1 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 255 */
+};
+#endif /* CK_SPEED */
+
+int sndsrc; /* Flag for where to get names of files to send: */
+ /* -1: znext() function */
+ /* 0: stdin */
+ /* >0: list in cmlist or other list */
+ /* -9: calibrate */
+
+int memstr; /* Flag for input from memory string */
+int funcstr; /* Flag for input from function */
+int bestlen = 0;
+int maxsend = 0;
+
+int gnf_binary = 0; /* Prevailing xfer mode for gnfile */
+
+#ifdef pdp11
+#define MYINITLEN 32
+#else
+#define MYINITLEN 100
+#endif /* pdp11 */
+CHAR myinit[MYINITLEN]; /* Copy of my Send-Init data */
+
+/* Variables local to this module */
+
+#ifdef TLOG
+#ifndef XYZ_INTERNAL
+static
+#endif /* XYZ_INTERNAL */
+char *fncnam[] = {
+ "rename", "replace", "backup", "append", "discard", "ask",
+ "update", "dates-differ", ""
+};
+#endif /* TLOG */
+
+static char *memptr; /* Pointer for memory strings */
+
+#ifdef VMS
+extern int batch;
+#else
+extern int backgrd;
+#endif /* VMS */
+
+#ifdef CK_CTRLZ
+static int lastchar = 0;
+#endif /* CK_CTRLZ */
+
+#ifdef CK_ANSIC
+static int (*funcptr)(void); /* Pointer for function strings */
+#else
+static int (*funcptr)();
+#endif /* CK_ANSIC */
+
+#ifdef pdp11
+#define CMDSTRL 50
+static char cmdstr[50]; /* System command string. */
+#else
+#ifdef BIGBUFOK
+#define CMDSTRL 1024
+#else
+#define CMDSTRL 256
+#endif /* BIGBUFOK */
+static char cmdstr[CMDSTRL+1];
+#endif /* pdp11 */
+
+static int drain; /* For draining stacked-up ACKs. */
+
+static int first; /* Flag for first char from input */
+static CHAR t; /* Current character */
+#ifdef COMMENT
+static CHAR next; /* Next character */
+#endif /* COMMENT */
+
+static int ebqsent = 0; /* 8th-bit prefix bid that I sent */
+static int lsstate = 0; /* Locking shift state */
+static int lsquote = 0; /* Locking shift quote */
+
+extern int quiet;
+
+/* E N C S T R -- Encode a string from memory. */
+
+/*
+ Call this instead of getpkt() if source is a string, rather than a file.
+ Note: Character set translation is never done in this case.
+*/
+
+#ifdef COMMENT
+#define ENCBUFL 200
+#ifndef pdp11
+CHAR encbuf[ENCBUFL];
+#else
+/* This is gross, but the pdp11 root segment is out of space */
+/* Will allocate it in ckuusr.c. */
+extern CHAR encbuf[];
+#endif /* pdp11 */
+#endif /* COMMENT */
+
+/*
+ Encode packet data from a string in memory rather than from a file.
+ Returns the length of the encoded string on success, -1 if the string
+ could not be completely encoded into the currently negotiated data
+ field length.
+*/
+int
+#ifdef CK_ANSIC
+encstr(CHAR *s)
+#else /* CK_ANSIC */
+encstr(s) CHAR* s;
+#endif /* CK_ANSIC */
+{
+/*
+ Recoded 30 Jul 94 to use the regular data buffer and the negotiated
+ maximum packet size. Previously we were limited to the length of encbuf[].
+ Also, to return a failure code if the entire encoded string would not fit.
+ Modified 14 Jul 98 to return length of encoded string.
+*/
+ int m, rc, slen; char *p;
+ if (!data) { /* Watch out for null pointers. */
+ debug(F100,"SERIOUS ERROR: encstr data == NULL","",0);
+ return(-1);
+ }
+ if (!s) s = (CHAR *)""; /* Ditto. */
+ slen = strlen((char *)s); /* Length of source string. */
+ debug(F111,"encstr",s,slen);
+ rc = 0; /* Return code. */
+ m = memstr; p = memptr; /* Save these. */
+ memptr = (char *)s; /* Point to the string. */
+ /* debug(F101,"encstr memptr 1","",memptr); */
+ memstr = 1; /* Flag memory string as source. */
+ first = 1; /* Initialize character lookahead. */
+ *data = NUL; /* In case s is empty */
+ debug(F101,"encstr spsiz","",spsiz);
+ rc = getpkt(spsiz,0); /* Fill a packet from the string. */
+ debug(F101,"encstr getpkt rc","",rc);
+ if (rc > -1 && memptr < (char *)(s + slen)) { /* Means we didn't encode */
+ rc = -1; /* the whole string. */
+ debug(F101,"encstr string too big","",size);
+ }
+ debug(F101,"encstr getpkt rc","",rc);
+ memstr = m; /* Restore memory string flag */
+ memptr = p; /* and pointer */
+ first = 1; /* Put this back as we found it. */
+ return(rc);
+}
+
+/* Output functions passed to 'decode': */
+
+int /* Put character in server command buffer */
+#ifdef CK_ANSIC
+putsrv(char c)
+#else
+putsrv(c) register char c;
+#endif /* CK_ANSIC */
+/* putsrv */ {
+ *srvptr++ = c;
+ *srvptr = '\0'; /* Make sure buffer is null-terminated */
+ return(0);
+}
+
+int /* Output character to console. */
+#ifdef CK_ANSIC
+puttrm(char c)
+#else
+puttrm(c) register char c;
+#endif /* CK_ANSIC */
+/* puttrm */ {
+ extern int rcdactive;
+#ifndef NOSPL
+ extern char * qbufp; /* If REMOTE QUERY active, */
+ extern int query, qbufn; /* also store response in */
+ if (query && qbufn++ < 1024) { /* query buffer. */
+ *qbufp++ = c;
+ *qbufp = NUL;
+ }
+ if (!query || !xcmdsrc)
+#endif /* NOSPL */
+/*
+ This routine is used (among other things) for printing the server's answer
+ to a REMOTE command. But REMOTE CD is special because it isn't really
+ asking for an answer from the server. Thus some people want to suppress
+ the confirmation message (e.g. when the server sends back the actual path
+ of the directory CD'd to), and expect to be able to do this with SET QUIET
+ ON. But they would not want SET QUIET ON to suppress the other server
+ replies, which are pointless without their answers. Thus the "rcdactive"
+ flag (REMOTE CD command is active). Thu Oct 10 16:38:21 2002
+*/
+ if (!(quiet && rcdactive)) /* gross, yuk */
+ conoc(c);
+ return(0);
+}
+#endif /* NOXFER */
+
+int /* Output char to file. */
+#ifdef CK_ANSIC
+putmfil(char c) /* Just like putfil but to ZMFILE */
+#else /* rather than ZOFILE... */
+putmfil(c) register char c;
+#endif /* CK_ANSIC */
+/* putmfil */ {
+ debug(F000,"putfil","",c);
+ if (zchout(ZMFILE, (char) (c & fmask)) < 0) {
+ czseen = 1;
+ debug(F101,"putfil zchout write error, setting czseen","",1);
+ return(-1);
+ }
+ return(0);
+}
+
+int /* Output char to nowhere. */
+#ifdef CK_ANSIC
+putnowhere(char c)
+#else
+putnowhere(c) register char c;
+#endif /* CK_ANSIC */
+/* putnowhere */ {
+ return(0);
+}
+
+
+int /* Output char to file. */
+#ifdef CK_ANSIC
+putfil(char c)
+#else
+putfil(c) register char c;
+#endif /* CK_ANSIC */
+/* putfil */ {
+ debug(F000,"putfil","",c);
+ if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
+ czseen = 1; /* If write error... */
+ debug(F101,"putfil zchout write error, setting czseen","",1);
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ The following function is a wrapper for putfil(). The only reason for its
+ existence is to be passed as a function pointer to decode(), which treats
+ putfil() itself specially -- bypassing it and using an internal macro
+ instead to speed things up. Use zputfil() instead of putfil() in cases where
+ we do not want this to happen, e.g. when we need to send output to the file
+ with a mixture of zchout() and zsout()/zsoutl() calls (as is the case with
+ incoming short-form REMOTE command replies redirected to a file), which would
+ otherwise result in data written to the file out of order.
+*/
+int
+#ifdef CK_ANSIC
+zputfil(char c)
+#else
+zputfil(c) register char c;
+#endif /* CK_ANSIC */
+/* zputfil */ {
+ return(putfil(c));
+}
+
+#ifndef NOXFER
+
+/* D E C O D E -- Kermit packet decoding procedure */
+
+/*
+ Call with string to be decoded and an output function.
+ Returns 0 on success, -1 on failure (e.g. disk full).
+
+ This is the "inner loop" when receiving files, and must be coded as
+ efficiently as possible. Note some potential problems: if a packet
+ is badly formed, having a prefixed sequence ending prematurely, this
+ function, as coded, could read past the end of the packet. This has
+ never happened, thus the additional (time-consuming) tests have not
+ been added.
+*/
+
+static CHAR *xdbuf; /* Global version of decode()'s buffer pointer */
+ /* for use by translation functions. */
+
+/* Function for pushing a character onto decode()'s input stream. */
+
+VOID
+#ifdef CK_ANSIC
+zdstuff(CHAR c)
+#else
+zdstuff(c) CHAR c;
+#endif /* CK_ANSIC */
+/* zdstuff */ {
+ xdbuf--; /* Back up the pointer. */
+ *xdbuf = c; /* Stuff the character. */
+}
+
+#ifdef CKTUNING
+/*
+ Trimmed-down packet decoder for binary-mode no-parity transfers.
+ decode() is the full version.
+*/
+int
+#ifdef CK_ANSIC
+bdecode(CHAR *buf, int (*fn)(char))
+#else
+bdecode(buf,fn) register CHAR *buf; register int (*fn)();
+#endif /* CK_ANSIC */
+/* bdecode */ {
+ register unsigned int a, a7; /* Various copies of current char */
+ int ccpflg; /* For Ctrl-unprefixing stats */
+ int t; /* Int version of character */
+ int len;
+ long z; /* For CRC calculation */
+ CHAR c; /* Current character */
+
+ if (!binary || parity || fn != putfil) /* JUST IN CASE */
+ return(decode(buf,fn,1));
+ debug(F100,"BDECODE","",0);
+
+ xdbuf = buf; /* Global copy of source pointer. */
+
+ len = rln; /* Number of bytes in data field */
+ while (len > 0) {
+ a = *xdbuf++ & 0xff; /* Get next character */
+ len--;
+ rpt = 0; /* Initialize repeat count. */
+ if (a == rptq && rptflg) { /* Got a repeat prefix? */
+ rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
+ rptn += rpt;
+ a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
+ len -= 2;
+ }
+ ccpflg = 0; /* Control prefix flag. */
+ if (a == ctlq) { /* If control prefix, */
+ a = *xdbuf++ & 0xFF; /* get its operand */
+ len--;
+ a7 = a & 0x7F; /* and its low 7 bits. */
+ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
+ a = ctl(a); /* if in control range. */
+ a7 = a & 0x7F;
+ ccpflg = 1; /* Note that we did this */
+ ccp++; /* Count for stats */
+ }
+ } else a7 = a & 0x7f; /* Not control quote */
+ if (a7 < 32 || a7 == 127) /* A bare control character? */
+ if (!ccpflg) ccu++; /* Count it */
+ if (!rpt) rpt = 1;
+ for (; rpt > 0; rpt--) { /* Output the char RPT times */
+#ifdef CALIBRATE
+ if (calibrate) {
+ ffc++;
+ continue;
+ }
+#endif /* CALIBRATE */
+#ifdef OS2
+ if (xflg && !remfile) { /* Write to virtual screen */
+ char _a;
+ _a = a & fmask;
+ t = conoc(_a);
+ if (t < 1)
+ t = -1;
+ } else
+#endif /* OS2 */
+ t = zmchout(a & fmask); /* zmchout is a macro */
+ if (t < 0) {
+ debug(F101,"bdecode write error - errno","",errno);
+ return(-1);
+ }
+ ffc++; /* Count the character */
+ if (docrc && !remfile) { /* Update file CRC */
+ c = a; /* Force conversion to unsigned char */
+ z = crc16 ^ (long)c;
+ crc16 = (crc16 >> 8) ^
+ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
+ }
+ }
+#ifdef CK_CTRLZ
+ lastchar = a;
+#endif /* CK_CTRLZ */
+ }
+ return(0);
+}
+#endif /* CKTUNING */
+#endif /* NOXFER */
+
+/* P N B Y T E -- Output next byte to file or other destination */
+
+static CK_OFF_T offc = 0L;
+
+static int
+#ifdef CK_ANSIC
+pnbyte(CHAR c, int (*fn)(char))
+#else
+pnbyte(c,fn) CHAR c; int (*fn)();
+#endif /* CK_ANSIC */
+/* pnbyte */ {
+ int rc;
+ long z;
+
+#ifdef OS2
+#ifndef NOXFER
+ if (xflg && !remfile) { /* Write to virtual screen */
+ char _a;
+ _a = c & fmask;
+ rc = conoc(_a);
+ if (rc < 1)
+ return(-1);
+ } else
+#endif /* NOXFER */
+#endif /* OS2 */
+ {
+ if (fn == putfil) { /* Execute output function */
+ rc = zmchout(c); /* to-file macro (fast) */
+ } else if (!fn) {
+ rc = putchar(c); /* to-screen macro (fast) */
+ } else {
+ rc = (*fn)(c); /* function call (not as fast) */
+ }
+ if (rc < 0)
+ return(rc);
+ }
+/*
+ Both xgnbyte() and xpnbyte() increment ffc (the file byte counter).
+ During file transfer, only one of these functions is called. However,
+ the TRANSLATE command is likely to call them both. offc, therefore,
+ contains the output byte count, necessary for handling the UCS-2 BOM.
+ NOTE: It might be safe to just test for W_SEND, FTP or not.
+*/
+ if ((what & (W_FTP|W_SEND)) != (W_FTP|W_SEND)) {
+ offc++; /* Count the byte */
+ ffc++; /* Count the byte */
+ }
+#ifndef NOXFER
+ if (docrc && !xflg && !remfile) { /* Update file CRC */
+ z = crc16 ^ (long)c;
+ crc16 = (crc16 >> 8) ^
+ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
+ }
+#endif /* NOXFER */
+ return(1);
+}
+
+/*
+ X P N B Y T E -- Translate and put next byte to file.
+
+ Only for Unicode. Call with next untranslated byte from incoming
+ byte stream, which can be in any Transfer Character Set: UCS-2, UTF-8,
+ Latin-1, Latin-Hebrew, etc. Translates to the file character set and
+ writes bytes to the output file. Call with character to translate
+ as an int, plus the transfer character set (to translate from) and the
+ file character set (to translate to), or -1,0,0 to reset the UCS-2 byte
+ number (which should be done at the beginning of a file). If the transfer
+ (source) character-set is UCS-2, bytes MUST arrive in Big-Endian order.
+ Returns:
+ -1: On error
+ 0: Nothing to write (mid-sequence)
+ >0: Number of bytes written.
+*/
+#ifdef KANJI
+static int jstate = 0, jx = 0; /* For outputting JIS-7 */
+static char jbuf[16] = { NUL, NUL };
+#endif /* KANJI */
+
+int
+#ifdef CK_ANSIC
+xpnbyte(int a, int tcs, int fcs, int (*fn)(char))
+#else
+xpnbyte(a,tcs,fcs,fn) int a, tcs, fcs; int (*fn)();
+#endif /* CK_ANSIC */
+/* xpnbyte */ {
+#ifdef UNICODE
+ extern int ucsbom; /* Byte order */
+#endif /* UNICODE */
+ /* CHAR c; */ /* Unsigned char worker */
+ static union ck_short uc, eu, sj; /* UCS-2, EUC, and Shift-JIS workers */
+ USHORT ch; /* ditto... */
+ USHORT * us = NULL; /* ditto... */
+ int c7, rc, haveuc = 0; /* Return code and UCS-2 flag */
+ int utferror = 0; /* UTF-8 error */
+ static int bn = 0; /* UCS-2 byte number */
+ int swapping = 0; /* Swapping UCS bytes to output? */
+ /* swapping must be 0 or 1 */
+ if (a == -1 && (tcs | fcs) == 0) { /* Reset in case previous run */
+ bn = 0; /* left bn at 1... */
+ offc = (CK_OFF_T)0;
+ debug(F101,"xpnbyte RESET","",bn);
+ return(0);
+ }
+ debug(F001,"xpnbyte a","",a);
+
+#ifdef UNICODE
+
+/*
+ byteorder = hardware byte order of this machine.
+ ucsorder = override by SET FILE UCS BYTE-ORDER command.
+ fileorder = byte order of UCS-2 input file detected from BOM.
+ swapping applies only when output charset is UCS-2.
+*/
+ if (ucsorder != 1 && ucsorder != 0) /* Also just in case... */
+ ucsorder = byteorder;
+ if ((byteorder && !ucsorder) || (!byteorder && fileorder))
+ swapping = 1; /* Swapping bytes to output */
+
+#ifdef COMMENT
+ debug(F101,"xpnbyte ucsorder","",ucsorder);
+ debug(F101,"xpnbyte swapping","",swapping);
+#endif /* COMMENT */
+
+ if (tcs == TC_UTF8) { /* 'a' is from a UTF-8 stream */
+ ch = a;
+ if (fcs == TC_UTF8) /* Output is UTF-8 too */
+ return(pnbyte(ch,fn)); /* so just copy. */
+ rc = utf8_to_ucs2(ch,&us); /* Otherwise convert to UCS-2 */
+ if (rc == 0) { /* Done with this sequence */
+ uc.x_short = *us; /* We have a Unicode */
+ haveuc = 1;
+ } else if (rc < 0) { /* Error */
+ debug(F101,"xpnbyte UTF-8 conversion error","",rc);
+ haveuc = 1; /* Replace by U+FFFD */
+ uc.x_short = *us;
+ utferror = 1;
+ } else /* Sequence incomplete */
+ return(0);
+ } else if (tcs == TC_UCS2) { /* 'a' is UCS-2 */
+ /* Here we have incoming UCS-2 in guaranteed Big Endian order */
+ /* so we must exchange bytes if local machine is Little Endian. */
+ switch (bn) { /* Which byte? */
+ case 0: /* High... */
+ uc.x_char[byteorder] = (unsigned)a & 0xff;
+ bn++;
+ return(0); /* Wait for next */
+ case 1: /* Low... */
+ uc.x_char[1-byteorder] = (unsigned)a & 0xff;
+ bn = 0; /* Done with sequence */
+ haveuc = 1; /* Have a Unicode */
+ }
+ } else
+#endif /* UNICODE */
+
+#ifdef KANJI /* Whether UNICODE is defined or not */
+ if (tcs == TC_JEUC) { /* Incoming Japanese EUC */
+ int bad = 0;
+ static int kanji = 0; /* Flags set in case 0 for case 1 */
+ static int kana = 0;
+ switch (bn) { /* Byte number */
+ case 0: /* Byte 0 */
+ eu.x_short = 0;
+ if ((a & 0x80) == 0) {
+ sj.x_short = (unsigned)a & 0xff; /* Single byte */
+ kanji = kana = 0;
+ } else { /* Double byte */
+ c7 = a & 0x7f;
+ if (c7 > 0x20 && c7 < 0x7f) { /* Kanji */
+ eu.x_char[byteorder] = (CHAR) a; /* Store first byte */
+ bn++; /* Set up for second byte */
+ kanji = 1;
+ kana = 0;
+ return(0);
+ } else if (a == 0x8e) { /* SS2 -- Katakana prefix */
+ eu.x_char[byteorder] = (CHAR) a; /* Save it */
+ bn++;
+ kana = 1;
+ kanji = 0;
+ return(0);
+ } else {
+ bad++;
+ }
+ }
+ break;
+ case 1: /* Byte 1 */
+ bn = 0;
+ if (kanji) {
+ eu.x_char[1-byteorder] = (CHAR) a;
+ sj.x_short = eu_to_sj(eu.x_short);
+ break;
+ } else if (kana) {
+ sj.x_short = (CHAR) (a | 0x80);
+ break;
+ } else { /* (shouldn't happen) */
+ bad++;
+ }
+ }
+ /* Come here with one Shift-JIS character */
+
+#ifdef UNICODE
+ if (bad) {
+ uc.x_short = 0xfffd;
+ } else {
+ uc.x_short = sj_to_un(sj.x_short); /* Convert to Unicode */
+ }
+ haveuc = 1;
+#endif /* UNICODE */
+ } else
+#endif /* KANJI */
+
+#ifdef UNICODE
+ uc.x_short = (unsigned)a & 0xff; /* Latin-1 or whatever... */
+
+ /* Come here with uc = the character to be translated. */
+ /* If (haveuc) it's UCS-2 in native order, otherwise it's a byte. */
+
+ debug(F101,"xpnbyte haveuc","",haveuc);
+
+ if (haveuc) { /* If we have a Unicode... */
+ debug(F001,"xpnbyte uc.x_short","[A]",uc.x_short);
+ debug(F101,"xpnbyte feol","",feol);
+ if (what & W_XFER) { /* If transferring a file */
+ if (feol && uc.x_short == CR) { /* handle eol conversion. */
+ return(0);
+ } else if (feol && uc.x_short == LF) {
+ uc.x_short = feol;
+ }
+ }
+ debug(F001,"xpnbyte uc.x_short","[B]",uc.x_short);
+ if (fcs == FC_UCS2) { /* And FCS is UCS-2 */
+ /* Write out the bytes in the appropriate byte order */
+ int count = 0;
+#ifndef IKSDONLY
+#ifdef OS2
+ extern int k95stdout,wherex[],wherey[];
+ extern unsigned char colorcmd;
+ union {
+ USHORT ucs2;
+ UCHAR bytes[2];
+ } output;
+#endif /* OS2 */
+#endif /* IKSDONLY */
+ if (!offc && ucsbom) { /* Beginning of file? */
+
+#ifndef IKSDONLY
+#ifdef OS2
+ if (fn == NULL && !k95stdout && !inserver) {
+ offc++;
+#ifdef COMMENT
+ /* Don't print the BOM to the display */
+ output.bytes[0] = (!ucsorder ? 0xff : 0xfe);
+ output.bytes[1] = (!ucsorder ? 0xfe : 0xff);
+
+ VscrnWrtUCS2StrAtt(VCMD,
+ &output.ucs2,
+ 1,
+ wherey[VCMD],
+ wherex[VCMD],
+ &colorcmd
+ );
+#endif /* COMMENT */
+ } else
+#endif /* OS2 */
+#endif /* IKSDONLY */
+ {
+ if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0)
+ return(rc); /* BOM */
+ if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
+ return(rc);
+ }
+ count += 2;
+ }
+ if (utferror) {
+#ifndef IKSDONLY
+#ifdef OS2
+ if (fn == NULL && !k95stdout && !inserver) {
+ offc++;
+ output.bytes[0] = (!ucsorder ? 0xfd : 0xff);
+ output.bytes[1] = (!ucsorder ? 0xff : 0xfd);
+
+ VscrnWrtUCS2StrAtt(VCMD,
+ &output.ucs2,
+ 1,
+ wherey[VCMD],
+ wherex[VCMD],
+ &colorcmd
+ );
+ } else
+#endif /* OS2 */
+#endif /* IKSDONLY */
+ {
+ if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
+ return(rc);
+ }
+ count += 2;
+ }
+#ifndef IKSDONLY
+#ifdef OS2
+ if (fn == NULL && !k95stdout && !inserver) {
+ offc++;
+ output.bytes[0] = uc.x_char[swapping];
+ output.bytes[1] = uc.x_char[1-swapping];
+
+ VscrnWrtUCS2StrAtt(VCMD,
+ &output.ucs2,
+ 1,
+ wherey[VCMD],
+ wherex[VCMD],
+ &colorcmd
+ );
+ } else
+#endif /* OS2 */
+#endif /* IKSDONLY */
+ {
+ if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
+ return(rc);
+ }
+ count += 2;
+ return(count);
+ } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */
+ CHAR * buf = NULL;
+ int i, count;
+ if (utferror) {
+ if ((rc = pnbyte((ucsorder ? 0xbd : 0xff),fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte((ucsorder ? 0xff : 0xbd),fn)) < 0)
+ return(rc);
+ }
+ if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
+ return(-1);
+ debug(F011,"xpnbyte buf",buf,count);
+ for (i = 0; i < count; i++)
+ if ((rc = pnbyte(buf[i],fn)) < 0)
+ return(rc);
+ if (utferror)
+ count += 2;
+ return(count);
+ } else { /* Translate UCS-2 to byte */
+ if (uc.x_short == 0x2028 || uc.x_short == 0x2029) {
+ if (utferror)
+ pnbyte(UNK,fn);
+ if (feol)
+ return(pnbyte((CHAR)feol,fn));
+ if ((rc = pnbyte((CHAR)CR,fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte((CHAR)LF,fn)) < 0)
+ return(rc);
+ else
+ return(utferror ? 3 : 2);
+ } else if (xuf) { /* UCS-to-FCS function */
+ int x = 0;
+ if (utferror)
+ pnbyte(UNK,fn);
+ if ((rc = (*xuf)(uc.x_short)) < 0) /* These can fail... */
+ ch = UNK;
+ else
+ ch = (unsigned)((unsigned)rc & 0xffff);
+ x = pnbyte(ch,fn);
+ if (x < 0)
+ return(x);
+ else if (utferror)
+ x++;
+ return(x);
+#ifdef KANJI
+
+/* Also see the non-Unicode Kanji section further down in this function. */
+
+ } else if (fcsinfo[fcs].alphabet == AL_JAPAN) {
+
+ /* Translate UCS-2 to Japanese set */
+ debug(F001,"xpnbyte uc","",uc.x_short);
+ sj.x_short = un_to_sj(uc.x_short); /* First to Shift-JIS */
+ debug(F001,"xpnbyte sj","",sj.x_short);
+
+ switch (fcs) { /* File character set */
+ case FC_SHJIS: /* Shift-JIS -- just output it */
+ if (sj.x_char[byteorder]) /* But not high byte if zero */
+ if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
+ return(rc);
+ return(2);
+ case FC_JEUC: /* EUC-JP */
+ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
+ debug(F001,"xpnbyte eu","",eu.x_short);
+ if (eu.x_short == 0xffff) { /* Bad */
+ if ((rc = pnbyte(UNK,fn)) < 0)
+ return(rc);
+ return(1);
+ } else { /* Good */
+ int count = 0; /* Write high byte if not zero */
+ if (eu.x_char[byteorder]) {
+ if ((rc=pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
+ return(rc);
+ count++;
+ }
+ /* Always write low byte */
+ if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
+ return(rc);
+ count++;
+ return(count);
+ }
+ break;
+
+ case FC_JIS7: /* JIS-7 */
+ case FC_JDEC: /* DEC Kanji */
+ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
+ if (eu.x_short == 0xffff) { /* Bad */
+ debug(F001,"xpnbyte bad eu","",eu.x_short);
+ if ((rc = pnbyte(UNK,fn)) < 0)
+ return(rc);
+ return(1);
+ } else { /* Good */
+ int i;
+ /* Use another name - 'a' hides parameter */
+ /* It's OK as is but causes compiler warnings */
+ char a = eu.x_char[1-byteorder]; /* Low byte */
+ debug(F001,"xpnbyte eu","",eu.x_short);
+ if (eu.x_char[byteorder] == 0) { /* Roman */
+ switch (jstate) {
+ case 1: /* Current state is Katakana */
+ jbuf[0] = 0x0f; /* SI */
+ jbuf[1] = a;
+ jx = 2;
+ break;
+ case 2: /* Current state is Kanji */
+ jbuf[0] = 0x1b; /* ESC */
+ jbuf[1] = 0x28; /* ( */
+ jbuf[2] = 0x4a; /* J */
+ jbuf[3] = a;
+ jx = 4;
+ break;
+ default: /* Current state is Roman */
+ jbuf[0] = a;
+ jx = 1;
+ break;
+ }
+ jstate = 0; /* New state is Roman */
+ } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
+ jx = 0;
+ switch (jstate) {
+ case 2: /* from Kanji */
+ jbuf[jx++] = 0x1b; /* ESC */
+ jbuf[jx++] = 0x28; /* ( */
+ jbuf[jx++] = 0x4a; /* J */
+ case 0: /* from Roman */
+ jbuf[jx++] = 0x0e; /* SO */
+ default: /* State is already Kana*/
+ jbuf[jx++] = (a & 0x7f); /* and the char */
+ break;
+ }
+ jstate = 1; /* New state is Katakana */
+ } else { /* Kanji */
+ jx = 0;
+ switch (jstate) {
+ case 1: /* Current state is Katakana */
+ jbuf[jx++] = 0x0f; /* SI */
+ case 0: /* Current state is Roman */
+ jbuf[jx++] = 0x1b; /* ESC */
+ jbuf[jx++] = 0x24; /* $ */
+ jbuf[jx++] = 0x42; /* B */
+ default: /* Current state is already Kanji */
+ jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
+ jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
+ break;
+ }
+ jstate = 2; /* Set state to Kanji */
+ }
+ for (i = 0; i < jx; i++) /* Output the result */
+ if ((rc = pnbyte(jbuf[i],fn)) < 0)
+ return(rc);
+ return(jx); /* Return its length */
+ }
+ }
+#endif /* KANJI */
+ } else { /* No translation function */
+ int count = 0;
+ if (utferror) {
+ if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0)
+ return(rc);
+ count += 2;
+ }
+ if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
+ return(rc);
+ count += 2;
+ return(count);
+ }
+ }
+ } else { /* Byte to Unicode */
+ if (xtu) { /* TCS-to-UCS function */
+ if (((tcsinfo[tcs].size > 128) && (uc.x_short & 0x80)) ||
+ tcsinfo[tcs].size <= 128)
+ uc.x_short = (*xtu)(uc.x_short);
+ }
+ if (fcs == FC_UCS2) { /* And FCS is UCS-2 */
+ /* Write out the bytes in the appropriate byte order */
+ if (!offc && ucsbom) { /* Beginning of file? */
+ if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) /* BOM */
+ return(rc);
+ if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0)
+ return(rc);
+ }
+ if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0)
+ return(rc);
+ if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0)
+ return(rc);
+ return(2);
+ } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */
+ CHAR * buf = NULL;
+ int i, count;
+ if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1)
+ return(-1);
+ for (i = 0; i < count; i++)
+ if ((rc = pnbyte(buf[i],fn)) < 0)
+ return(rc);
+ return(count);
+ } else {
+ debug(F100,"xpnbyte impossible combination","",0);
+ return(-1);
+ }
+ }
+#else
+#ifdef KANJI
+/*
+ This almost, but not quite, duplicates the Kanji section above.
+ There is no doubt a way to combine the sections more elegantly,
+ but probably only at the expense of additional execution overhead.
+ As matters stand, be careful to reflect any changes in this section
+ to the other Kanji section above.
+*/
+ if (tcs == TC_JEUC) { /* Incoming Japanese EUC */
+ int count = 0;
+ switch (fcs) { /* File character set */
+ case FC_SHJIS: /* Shift-JIS -- just output it */
+ if (sj.x_char[byteorder]) /* But not high byte if zero */
+ if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0)
+ return(rc);
+ count++;
+ if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0)
+ return(rc);
+ count++;
+ return(count);
+ case FC_JEUC: /* EUC-JP */
+ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
+ debug(F001,"xpnbyte FC_JEUC eu","",eu.x_short);
+ if (eu.x_short == 0xffff) { /* Bad */
+ if ((rc = pnbyte(UNK,fn)) < 0)
+ return(rc);
+ return(1);
+ } else { /* Good */
+ int count = 0; /* Write high byte if not zero */
+ if (eu.x_char[byteorder]) {
+ if ((rc = pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0)
+ return(rc);
+ count++;
+ }
+ /* Always write low byte */
+ if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0)
+ return(rc);
+ count++;
+ return(count);
+ }
+ break;
+
+ case FC_JIS7: /* JIS-7 */
+ case FC_JDEC: /* DEC Kanji */
+ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */
+ if (eu.x_short == 0xffff) { /* Bad */
+ debug(F001,"xpnbyte FC_JIS7 bad eu","",eu.x_short);
+ if ((rc = pnbyte(UNK,fn)) < 0)
+ return(rc);
+ return(1);
+ } else { /* Good */
+ int i;
+ char a = eu.x_char[1-byteorder]; /* Low byte */
+ debug(F001,"xpnbyte FC_JIS7 eu","",eu.x_short);
+ if (eu.x_char[byteorder] == 0) { /* Roman */
+ switch (jstate) {
+ case 1: /* Current state is Katakana */
+ jbuf[0] = 0x0f; /* SI */
+ jbuf[1] = a;
+ jx = 2;
+ break;
+ case 2: /* Current state is Kanji */
+ jbuf[0] = 0x1b; /* ESC */
+ jbuf[1] = 0x28; /* ( */
+ jbuf[2] = 0x4a; /* J */
+ jbuf[3] = a;
+ jx = 4;
+ break;
+ default: /* Current state is Roman */
+ jbuf[0] = a;
+ jx = 1;
+ break;
+ }
+ jstate = 0; /* New state is Roman */
+ } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */
+ jx = 0;
+ switch (jstate) {
+ case 2: /* from Kanji */
+ jbuf[jx++] = 0x1b; /* ESC */
+ jbuf[jx++] = 0x28; /* ( */
+ jbuf[jx++] = 0x4a; /* J */
+ case 0: /* from Roman */
+ jbuf[jx++] = 0x0e; /* SO */
+ default: /* State is already Kana*/
+ jbuf[jx++] = (a & 0x7f); /* and the char */
+ break;
+ }
+ jstate = 1; /* New state is Katakana */
+ } else { /* Kanji */
+ jx = 0;
+ switch (jstate) {
+ case 1: /* Current state is Katakana */
+ jbuf[jx++] = 0x0f; /* SI */
+ case 0: /* Current state is Roman */
+ jbuf[jx++] = 0x1b; /* ESC */
+ jbuf[jx++] = 0x24; /* $ */
+ jbuf[jx++] = 0x42; /* B */
+ default: /* Current state is already Kanji */
+ jbuf[jx++] = eu.x_char[byteorder] & 0x7f;
+ jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f;
+ break;
+ }
+ jstate = 2; /* Set state to Kanji */
+ }
+ for (i = 0; i < jx; i++) /* Output the result */
+ if ((rc = pnbyte(jbuf[i],fn)) < 0)
+ return(rc);
+ return(jx); /* Return its length */
+ }
+ default:
+ if (sj.x_short < 0x80)
+ return(sj.x_short);
+ else
+ return('?');
+ }
+ }
+#endif /* KANJI */
+#endif /* UNICODE */
+ debug(F100,"xpnbyte BAD FALLTHRU","",0);
+ return(-1);
+}
+
+#ifndef NOXFER
+
+/* D E C O D E -- Kermit Data-packet decoder */
+
+int
+#ifdef CK_ANSIC
+decode(CHAR *buf, int (*fn)(char), int xlate)
+#else
+decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
+#endif /* CK_ANSIC */
+/* decode */ {
+ register unsigned int a, a7, a8, b8; /* Various copies of current char */
+ int t; /* Int version of character */
+ int ssflg; /* Character was single-shifted */
+ int ccpflg; /* For Ctrl-unprefixing stats */
+ int len;
+ long z;
+ CHAR c;
+/*
+ Catch the case in which we are asked to decode into a file that is not open,
+ for example, if the user interrupted the transfer, but the other Kermit
+ keeps sending.
+*/
+ if ((cxseen || czseen || discard) && (fn == putfil))
+ return(0);
+
+#ifdef COMMENT
+#ifdef CKTUNING
+ if (binary && !parity)
+ return(bdecode(buf,fn));
+#endif /* CKTUNING */
+#endif /* COMMENT */
+ debug(F100,"DECODE","",0);
+
+ xdbuf = buf; /* Make global copy of pointer. */
+ rpt = 0; /* Initialize repeat count. */
+
+ len = rln; /* Number of bytes in data field */
+ while (len > 0) { /* Loop for each byte */
+ a = *xdbuf++ & 0xff; /* Get next character */
+ len--;
+ if (a == rptq && rptflg) { /* Got a repeat prefix? */
+ rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
+ rptn += rpt;
+ a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
+ len -= 2;
+ }
+ b8 = lsstate ? 0200 : 0; /* 8th-bit value from SHIFT-STATE */
+ if (ebqflg && a == ebq) { /* Have 8th-bit prefix? */
+ b8 ^= 0200; /* Yes, invert the 8th bit's value, */
+ ssflg = 1; /* remember we did this, */
+ a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
+ len--;
+ } else ssflg = 0;
+ ccpflg = 0;
+ if (a == ctlq) { /* If control prefix, */
+ a = *xdbuf++ & 0xFF; /* get its operand */
+ len--;
+ a7 = a & 0x7F; /* and its low 7 bits. */
+ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
+ a = ctl(a); /* if in control range. */
+ a7 = a & 0x7F;
+ ccpflg = 1; /* Note that we did this */
+ ccp++; /* Count for stats */
+ }
+ } else a7 = a & 0x7f; /* Not control quote */
+ if (a7 < 32 || a7 == 127) { /* Control character? */
+ if (!ccpflg) ccu++; /* A bare one, count it */
+ if (lscapu) { /* If doing locking shifts... */
+ if (lsstate) /* If SHIFTED */
+ a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
+ else /* otherwise */
+ a8 = a | b8; /* OR in 8th bit */
+ /* If we're not in a quoted sequence */
+ if (!lsquote && (!lsstate || !ssflg)) {
+ if (a8 == DLE) { /* Check for DLE quote */
+ lsquote = 1; /* prefixed by single shift! */
+ continue;
+ } else if (a8 == SO) { /* Check for Shift-Out */
+ lsstate = 1; /* SHIFT-STATE = SHIFTED */
+ continue;
+ } else if (a8 == SI) { /* or Shift-In */
+ lsstate = 0; /* SHIFT-STATE = UNSHIFTED */
+ continue;
+ }
+ } else lsquote = 0;
+ }
+ }
+ a |= b8; /* OR in the 8th bit */
+ if (rpt == 0) rpt = 1; /* If no repeats, then one */
+#ifndef NOCSETS
+ if (!binary) { /* If in text mode, */
+ if (tcharset != TC_UCS2) {
+ if (feol && a == CR) /* Convert CRLF to newline char */
+ continue;
+ if (feol && a == LF)
+ a = feol;
+ }
+ if (xlatype == XLA_BYTE) /* Byte-for-byte - do it now */
+ if (xlate && rx) a = (*rx)((CHAR) a);
+ }
+#endif /* NOCSETS */
+ /* (PWP) Decoding speedup via buffered output and a macro... */
+ if (fn == putfil) {
+ for (; rpt > 0; rpt--) { /* Output the char RPT times */
+#ifdef CALIBRATE
+ if (calibrate) {
+ ffc++;
+ continue;
+ }
+#endif /* CALIBRATE */
+
+/* Note: The Unicode and Kanji sections can probably be combined now; */
+/* the Unicode method (xpnbyte()) covers Kanji too. */
+
+#ifdef UNICODE
+ if (!binary && xlatype == XLA_UNICODE)
+ t = xpnbyte((unsigned)((unsigned)a & 0xff),
+ tcharset,
+ fcharset,
+ fn
+ );
+ else
+#endif /* UNICODE */
+#ifdef KANJI
+ if (!binary && tcharset == TC_JEUC &&
+ fcharset != FC_JEUC) { /* Translating from J-EUC */
+ if (!ffc) xkanjf();
+ if (xkanji(a,fn) < 0) /* to something else? */
+ return(-1);
+ else t = 1;
+ } else
+#endif /* KANJI */
+ {
+#ifdef OS2
+ if (xflg && !remfile) { /* Write to virtual screen */
+ char _a;
+ _a = a & fmask;
+ t = conoc(_a);
+ if (t < 1)
+ t = -1;
+ } else
+#endif /* OS2 */
+ t = zmchout(a & fmask); /* zmchout is a macro */
+ }
+ if (t < 0) {
+ debug(F101,"decode write errno","",errno);
+ return(-1);
+ }
+#ifdef UNICODE
+ if (xlatype != XLA_UNICODE || binary) {
+ ffc++; /* Count the character */
+ if (docrc && !xflg && !remfile) { /* Update file CRC */
+ c = a; /* Force conversion to unsigned char */
+ z = crc16 ^ (long)c;
+ crc16 = (crc16 >> 8) ^
+ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
+ }
+ }
+#endif /* UNICODE */
+ }
+ } else { /* Output to something else. */
+ a &= fmask; /* Apply file mask */
+ for (; rpt > 0; rpt--) { /* Output the char RPT times */
+#ifdef CALIBRATE
+ if (calibrate) {
+ ffc++;
+ continue;
+ }
+#endif /* CALIBRATE */
+ if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
+ }
+ }
+#ifdef CK_CTRLZ
+ lastchar = a;
+#endif /* CK_CTRLZ */
+ }
+ return(0);
+}
+
+/* G E T P K T -- Fill a packet data field */
+
+/*
+ Gets characters from the current source -- file or memory string.
+ Encodes the data into the packet, filling the packet optimally.
+ Set first = 1 when calling for the first time on a given input stream
+ (string or file).
+
+ Call with:
+ bufmax -- current send-packet size
+ xlate -- flag: 0 to skip character-set translation, 1 to translate
+
+ Uses global variables:
+ t -- current character.
+ first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
+ next -- next character (not used any more).
+ data -- pointer to the packet data buffer.
+ size -- number of characters in the data buffer.
+ memstr - flag that input is coming from a memory string instead of a file.
+ memptr - pointer to string in memory.
+ (*sx)() character set translation function
+
+ Returns:
+ The size as value of the function, and also sets global "size",
+ and fills (and null-terminates) the global data array.
+ Returns:
+ 0 on EOF.
+ -1 on fatal (internal) error.
+ -3 on timeout (e.g. when reading data from a pipe).
+
+ Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
+ Incorporates old getchx() and encode() inline to reduce function calls,
+ uses buffered input for much-improved efficiency, and clears up some
+ confusion with line termination (CRLF vs LF vs CR).
+
+ Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
+ May 1991. And again in 1998 for efficiency, etc, with a separate
+ bgetpkt() split out for binary-mode no-parity transfers.
+*/
+
+/*
+ Note: Separate Kanji support dates from circa 1991 and now (1999) can most
+ likely be combined with the the Unicode support: the xgnbyte()/xpnbyte()
+ mechanism works for both Unicode and Kanji.
+*/
+#ifdef KANJI
+int
+kgetf(
+#ifdef CK_ANSIC
+ VOID
+#endif /* CK_ANSIC */
+ ) {
+ if (funcstr)
+ return((*funcptr)());
+ else
+ return(zminchar());
+}
+
+int
+kgetm(
+#ifdef CK_ANSIC
+ VOID
+#endif /* CK_ANSIC */
+ ) {
+ int x;
+ if ((x = *memptr++)) return(x);
+ else return(-1);
+}
+#endif /* KANJI */
+
+/*
+ Lookahead function to decide whether locking shift is worth it. Looks at
+ the next four input characters to see if all of their 8th bits match the
+ argument. Call with 0 or 0200. Returns 1 on match, 0 if they don't match.
+ If we don't happen to have at least 4 more characters waiting in the input
+ buffer, returns 1. Note that zinptr points two characters ahead of the
+ current character because of repeat-count lookahead.
+*/
+int
+lslook(b) unsigned int b; { /* Locking Shift Lookahead */
+ int i;
+ if (zincnt < 3) /* If not enough chars in buffer, */
+ return(1); /* force shift-state switch. */
+ b &= 0200; /* Force argument to proper form. */
+ for (i = -1; i < 3; i++) /* Look at next 5 characters to */
+ if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match. */
+ return(0); /* They don't. */
+ return(1); /* They do. */
+}
+
+/* Routine to compute maximum data length for packet to be filled */
+
+int
+maxdata() { /* Get maximum data length */
+ int n, len;
+ debug(F101,"maxdata spsiz 1","",spsiz);
+ if (spsiz < 0) /* How could this happen? */
+ spsiz = DSPSIZ;
+ debug(F101,"maxdata spsiz 2","",spsiz);
+ n = spsiz - 5; /* Space for Data and Checksum */
+ if (n > 92 && n < 96) n = 92; /* "Short" Long packets don't pay */
+ if (n > 92 && lpcapu == 0) /* If long packets needed, */
+ n = 92; /* make sure they've been negotiated */
+ len = n - bctl; /* Space for data */
+ if (n > 92) len -= 3; /* Long packet needs header chksum */
+ debug(F101,"maxdata len 1","",len);
+ if (len < 0) len = 10;
+ debug(F101,"maxdata len 2","",len);
+ return(len);
+}
+
+static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
+static int nleft = 0;
+
+#ifdef CKTUNING
+/*
+ When CKTUNING is defined we use this special trimmed-down version of getpkt
+ to speed up binary-mode no-parity transfers. When CKTUNING is not defined,
+ or for text-mode or parity transfers, we use the regular getpkt() function.
+ Call just like getpkt() but test first for transfer mode and parity. NOTE:
+ This routine is only to be called when sending a real file -- not for
+ filenames, server responses, etc, because it only reads from the input file.
+ See getpkt() for more detailed commentary.
+*/
+static int
+bgetpkt(bufmax) int bufmax; {
+ register CHAR rt = t, rnext;
+ register CHAR *dp, *odp, *p1, *p2;
+ register int x = 0, a7;
+
+ CHAR xxrc, xxcq; /* Pieces of prefixed sequence */
+
+ long z; /* A long worker (for CRC) */
+
+ if (!binary || parity || memstr) /* JUST IN CASE caller didn't test */
+ return(getpkt(bufmax,!binary));
+
+ if (!data) {
+ debug(F100,"SERIOUS ERROR: bgetpkt data == NULL","",0);
+ return(-1);
+ }
+ dp = data; /* Point to packet data buffer */
+ size = 0; /* And initialize its size */
+ bufmax = maxdata(); /* Get maximum data length */
+
+#ifdef DEBUG
+ if (deblog)
+ debug(F101,"bgetpkt bufmax","",bufmax);
+#endif /* DEBUG */
+
+ if (first == 1) { /* If first character of this file.. */
+ ffc = (CK_OFF_T)0; /* reset file character counter */
+#ifdef COMMENT
+/* Moved to below */
+ first = 0; /* Next character won't be first */
+#endif /* COMMENT */
+ *leftover = '\0'; /* Discard any interrupted leftovers */
+ nleft = 0;
+
+ /* Get first character of file into rt, watching out for null file */
+
+#ifdef CALIBRATE
+ if (calibrate) {
+#ifdef NORANDOM
+ rt = 17;
+#else
+ rt = cal_a[rand() & 0xff];
+#endif /* NORANDOM */
+ first = 0;
+ } else
+#endif /* CALIBRATE */
+
+ if ((x = zminchar()) < 0) { /* EOF or error */
+ if (x == -3) { /* Timeout. */
+ size = (dp - data);
+ debug(F101,"bgetpkt timeout size","",size);
+ return((size == 0) ? x : size);
+ }
+ first = -1;
+ size = 0;
+ if (x == -2) { /* Error */
+ debug(F100,"bgetpkt: input error","",0);
+ cxseen = 1; /* Interrupt the file transfer */
+ } else {
+ debug(F100,"bgetpkt empty file","",0);
+ }
+ return(0);
+ }
+ first = 0; /* Next char will not be the first */
+ ffc++; /* Count a file character */
+ rt = (CHAR) x; /* Convert int to char */
+ if (docrc && (what & W_SEND)) { /* Accumulate file crc */
+ z = crc16 ^ (long)rt;
+ crc16 = (crc16 >> 8) ^
+ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
+ }
+ rt &= fmask; /* Apply SET FILE BYTESIZE mask */
+
+ } else if (first == -1 && nleft == 0) { /* EOF from last time */
+
+ return(size = 0);
+ }
+/*
+ Here we handle characters that were encoded for the last packet but
+ did not fit, and so were saved in the "leftover" array.
+*/
+ if (nleft) {
+ for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
+ *dp++ = *p1++;
+ *leftover = '\0'; /* Delete leftovers */
+ nleft = 0;
+ }
+ if (first == -1) /* Handle EOF */
+ return(size = (dp - data));
+
+/* Now fill up the rest of the packet. */
+
+ rpt = 0; /* Initialize character repeat count */
+
+ while (first > -1) { /* Until EOF... */
+#ifdef CALIBRATE
+ if (calibrate) { /* We generate our own "file" */
+ if (ffc >= calibrate) { /* EOF */
+ first = -1;
+ ffc--;
+ } else { /* Generate next character */
+ if (cal_j > CAL_M * ffc)
+ cal_j = cal_a[ffc & 0xff];
+ x = (unsigned)cal_a[(cal_j & 0xff)];
+ if (x == rt) x ^= 2;
+ }
+ ffc++;
+ cal_j += (unsigned int)(ffc + CAL_O);
+ } else
+#endif /* CALIBRATE */
+ if ((x = zminchar()) < 0) { /* Check for EOF */
+ if (x == -3) { /* Timeout. */
+ t = rt;
+ size = (dp-data);
+ debug(F101,"bgetpkt timeout size","",size);
+ return((size == 0) ? x : size);
+ }
+ first = -1; /* Flag eof for next time. */
+ if (x == -2) cxseen = 1; /* If error, cancel this file. */
+ } else {
+ ffc++; /* Count the character */
+ if (docrc && (what & W_SEND)) { /* Accumulate file crc */
+ z = crc16 ^ (long)((CHAR)x & 0xff);
+ crc16 = (crc16 >> 8) ^
+ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
+ }
+ }
+ rnext = (CHAR) (x & fmask); /* Apply file mask */
+/*
+ At this point, the character we just read is in rnext,
+ and the character we are about to encode into the packet is in rt.
+*/
+ odp = dp; /* Remember where we started. */
+ xxrc = xxcq = NUL; /* Clear these. */
+/*
+ Now encode the character according to the options that are in effect:
+ ctlp[]: whether this control character needs prefixing.
+ rptflg: repeat counts enabled.
+ Other options don't apply in this routine.
+*/
+ if (rptflg && (rt == rnext) && (first == 0)) { /* Got a run... */
+ if (++rpt < 94) { /* Below max, just count */
+ continue; /* go back and get another */
+ } else if (rpt == 94) { /* Reached max, must dump */
+ xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
+ rptn += rpt; /* Accumulate it for statistics */
+ rpt = 0; /* And reset it */
+ }
+ } else if (rpt > 0) { /* End of run */
+ xxrc = (CHAR)tochar(++rpt); /* The count */
+ rptn += rpt; /* For stats */
+ rpt = 0; /* Reset repeat count */
+ }
+ a7 = rt & 0177; /* Get low 7 bits of character */
+ if (
+#ifdef CK_SPEED
+ ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
+#else
+ (a7 < SP) || (a7 == DEL)
+#endif /* CK_SPEED */
+ ) { /* Do control prefixing if necessary */
+ xxcq = myctlq; /* The prefix */
+ ccp++; /* Count it */
+ rt = (CHAR) ctl(rt); /* Uncontrollify the character */
+ }
+#ifdef CK_SPEED
+ else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
+ ccu++;
+#endif /* CK_SPEED */
+
+ if (a7 == myctlq) /* Always prefix the control prefix */
+ xxcq = myctlq;
+
+ if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
+ xxcq = myctlq; /* prefix it if doing repeat counts */
+
+/* Now construct the prefixed sequence */
+
+ if (xxrc) { /* Repeat count */
+#ifdef COMMENT
+ if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
+ *dp++ = rt; /* So just do this */
+ } else { /* More than two or prefixed */
+ *dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */
+ }
+#else /* CHECK THIS */
+ if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */
+ if (dp == data) {
+ *dp++ = rt; /* So just do this */
+ } else if (*(dp-1) == rt) {
+ *dp++ = (CHAR) rptq;
+ *dp++ = xxrc; /* Emit repeat sequence */
+ } else {
+ *dp++ = rt; /* So just do this */
+ }
+ } else { /* More than two or prefixed */
+ *dp++ = (CHAR) rptq;
+ *dp++ = xxrc; /* Emit repeat sequence */
+ }
+#endif /* COMMENT */
+ }
+ if (xxcq) { *dp++ = myctlq; } /* Control prefix */
+ *dp++ = rt; /* Finally, the character itself */
+ rt = rnext; /* Next character is now current. */
+
+/* Done encoding the character. Now take care of packet buffer overflow. */
+
+ size = dp - data; /* How many bytes we put in buffer. */
+ if (size >= bufmax) { /* If too big, save some for next. */
+ *dp = '\0'; /* Mark the end. */
+ if (size > bufmax) { /* if packet is overfull */
+ /* Copy the part that doesn't fit into the leftover buffer, */
+ /* taking care not to split a prefixed sequence. */
+ int i;
+ nleft = dp - odp;
+ p1 = leftover;
+ p2 = odp;
+ for (i = 0; i < nleft; i++)
+ *p1++ = *p2++;
+ size = odp - data; /* Return truncated packet. */
+ *odp = '\0'; /* Mark the new end */
+ }
+ t = rt; /* Save for next time */
+ return(size);
+ }
+ } /* Otherwise, keep filling. */
+ size = dp - data; /* End of file */
+ *dp = '\0'; /* Mark the end of the data. */
+ return(size); /* Return partially filled last packet. */
+}
+#endif /* CKTUNING */
+
+VOID
+dofilcrc(c) int c; { /* Accumulate file crc */
+ long z;
+ z = crc16 ^ (long)c;
+ crc16 = (crc16 >> 8) ^
+ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
+}
+
+/* For SENDing from an array... */
+
+int
+agnbyte() { /* Get next byte from array */
+#ifndef NOSPL
+ char c;
+ static int save = 0; /* For CRLF */
+ static char ** ap = NULL; /* Array pointer */
+ static char * p = NULL; /* Character pointer */
+ static int i = 0, n = 0; /* Array index and limit */
+ extern int a_dim[]; /* Array dimension */
+
+ if (!ap) { /* First time thru */
+ ap = sndarray; /* Set up array pointers */
+ if (!ap || (i = sndxlo) > a_dim[sndxin]) {
+ sndarray = NULL;
+ ap = NULL;
+ return(-1);
+ }
+ p = ap[i]; /* Point to first element in range */
+ n = sndxhi; /* Index of last element in range */
+ if (sndxhi > a_dim[sndxin]) /* Adjust if necessary */
+ n = a_dim[sndxin];
+ }
+ if (save) { /* If anything saved */
+ c = save; /* unsave it */
+ save = 0; /* and return it */
+ return(c & 0xff);
+ }
+ if (i > n) { /* No more elements */
+ sndarray = NULL;
+ ap = NULL;
+ return(-1);
+ }
+ if (!p) /* Source pointer is NULL */
+ c = NUL; /* this means an empty line */
+ else /* Source pointer not NULL */
+ c = *p++; /* Next char */
+ if (!c) { /* Char is empty? */
+ if (!binary) { /* Text: end of line. */
+ if (feol) { /* Supply NL */
+ c = feol;
+ } else { /* or CRLF */
+ save = LF;
+ c = CR;
+ }
+ p = ap[++i];
+ return(c & 0xff);
+ }
+ while (i++ < n) { /* Binary - get next element */
+ p = ap[i];
+ if (!p) /* Empty line? */
+ continue; /* Ignore it and get another */
+ c = *p++; /* Get next char */
+ if (!c) /* Emtpy char? */
+ continue; /* Ignore it and get another */
+ return(c & 0xff); /* Not empty - return it */
+ }
+ sndarray = NULL;
+ ap = NULL;
+ return(-1); /* Done */
+ }
+ return(c & 0xff); /* Char is not empty */
+#else
+ sndarray = NULL;
+ return(-1);
+#endif /* NOSPL */
+}
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+static CHAR xlabuf[32] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+static int xlacount = 0;
+static int xlaptr = 0;
+/* static USHORT lastucs2 = 0; */
+
+/*
+ X G N B Y T E -- Get next translated byte from the input file.
+
+ Returns the next byte that is to be put into the packet, already translated.
+ This isolates getpkt() from having to know anything about translation,
+ single- vs multibyte character sets, one-to-many vs many-to-one, etc, but it
+ has rather high overhead, so don't call it unless you know translation is
+ needed to or from Unicode, Japanese, or other multibyte character set.
+
+ Call with:
+ fcs: File character set (source, file we are reading from)
+ tcs: Target character set (use an FC_xxx code, not a TC_xxx code)
+ Returns:
+ >= 0: A translated byte suitable for writing.
+ < 0: Fatal error (such as EOF on input source).
+ As of Sat Sep 7 18:37:41 2002:
+ When the output character-set is UCS-2, bytes are ALWAYS returned in
+ big-endian order (previously they could also be returned in LE order
+ under certain conditions, which was just way too confusing).
+*/
+int
+#ifdef CK_ANSIC
+xgnbyte(int tcs, int fcs, int (*fn)(void))
+#else /* CK_ANSIC */
+xgnbyte(tcs,fcs,fn) int tcs, fcs, (*fn)();
+#endif /* CK_ANSIC */
+/* xgnbyte */ {
+ _PROTOTYP( int (*xx), (USHORT) ) = NULL;
+ int haveuc = 0; /* Flag for have Unicode character */
+#ifdef KANJI
+ int havesj = 0; /* Have Shift-JIS character */
+ int haveeu = 0; /* Have EUC-JP character */
+#endif /* KANJI */
+ int rc = -1, x = 0, flag = 0;
+ int utferror = 0;
+ int eolflag = 0;
+ unsigned int xc, thischar;
+ static int swapping = 0;
+ CHAR rt;
+ /* USHORT ch; */
+#ifdef UNICODE
+ union ck_short uc;
+#endif /* UNICODE */
+#ifdef KANJI
+ union ck_short sj, eu; /* Shift-JIS character */
+#endif /* KANJI */
+
+#ifdef KANJI
+ sj.x_short = 0;
+#endif /* KANJI */
+
+#ifdef DEBUG
+ if (deblog && !ffc) {
+ debug(F101,"xgnbyte initial swap","",swapping);
+ }
+#endif /* DEBUG */
+
+ if (xlacount-- > 0) { /* We already have some */
+ x = xlabuf[xlaptr++];
+ debug(F001,"xgnbyte from buf","",x);
+ return(x);
+ }
+ if (xlatype != XLA_NONE) { /* Not not translating... */
+ haveuc = 0;
+#ifdef UNICODE
+ if (fcs == FC_UCS2) { /* UCS-2: Read two bytes */
+ if (!ffc) /* Beginning of file? */
+ swapping = 0; /* Reset byte-swapping flag */
+ uc.x_short = 0;
+ bomskip:
+ x = fn ? (*fn)() : zminchar(); /* Get first byte */
+ debug(F001,"zminchar swapping","",swapping);
+ debug(F001,"zminchar C0","",x);
+ flag = 1; /* Remember we called zminchar() */
+ if (x > -1) { /* Didn't fail */
+ ffc++; /* Count a file byte */
+ uc.x_char[swapping] = x & 0xff;
+#ifndef NOXFER
+ if (docrc && (what & W_SEND))
+ dofilcrc(x);
+#endif /* NOXFER */
+ x = fn ? (*fn)() : zminchar(); /* Get second byte */
+ if (x > -1) { /* If didn't fail */
+ debug(F001,"zminchar C1","",x);
+ ffc++; /* count another file byte */
+ uc.x_char[1-swapping] = x & 0xff;
+ haveuc = 1; /* And remember we have Unicode */
+#ifndef NOXFER
+ if (docrc && (what & W_SEND))
+ dofilcrc(x);
+#endif /* NOXFER */
+ if (ffc == (CK_OFF_T)2) { /* Second char of file */
+ debug(F001,"xgnbyte 1st UCS2","",uc.x_short);
+ debug(F111,"xgnbyte fileorder","A",fileorder);
+ if (fileorder < 0) /* Byte order of this file */
+ fileorder = ucsorder; /* Default is ucsorder */
+ if (fileorder > 1)
+ fileorder = 1;
+ debug(F111,"xgnbyte fileorder","B",fileorder);
+ if (uc.x_short == (USHORT)0xfeff) {
+ swapping = 0;
+ debug(F101,
+ "xgnbyte UCS2 goodbom swap","",swapping);
+ fileorder = byteorder; /* Note: NOT 0 */
+ goto bomskip;
+ } else if (uc.x_short == (USHORT)0xfffe) {
+ swapping = 1;
+ debug(F101,
+ "xgnbyte UCS2 badbom swap","",swapping);
+ fileorder = (1 - byteorder); /* Note: NOT 1 */
+ goto bomskip;
+ } else if ((byteorder && !fileorder) || /* No BOM */
+ (!byteorder && fileorder > 0)) {
+ /* fileorder might have been set by scanfile() */
+ CHAR c;
+ c = uc.x_char[0];
+ uc.x_char[0] = uc.x_char[1];
+ uc.x_char[1] = c;
+ swapping = 1;
+ debug(F111,"xgnbyte UCS2 noBOM swap","A",swapping);
+ } else {
+ swapping = 0;
+ debug(F111,"xgnbyte UCS2 noBOM swap","B",swapping);
+ }
+ debug(F111,"xgnbyte fileorder","C",fileorder);
+ }
+ } else
+ return(x);
+ } else
+ return(x);
+ debug(F001,"xgnbyte UCS2","",uc.x_short);
+
+ } else if (fcs == FC_UTF8) { /* File is UTF-8 */
+ CHAR ch = 0; /* Data types needed for API... */
+ USHORT * us = NULL;
+ uc.x_short = 0;
+ flag = 1; /* We (will) have called zminchar() */
+ /* Read source bytes */
+ while ((x = fn ? (*fn)() : zminchar()) > -1) {
+ ffc++; /* Got a byte - count it */
+#ifndef NOXFER
+ if (docrc && (what & W_SEND))
+ dofilcrc(x);
+#endif /* NOXFER */
+ ch = x;
+ rc = utf8_to_ucs2(ch,&us); /* Convert to UCS-2 */
+ if (rc == 0) { /* Done */
+ uc.x_short = *us;
+ haveuc = 1;
+ break;
+ } else if (rc < 0) { /* Error */
+ utferror = 1;
+ debug(F101,"xgnbyte UTF-8 input error","",rc);
+ haveuc = 1;
+ uc.x_short = *us;
+ break;
+ }
+ }
+ if (x < 0)
+ return(x);
+ debug(F001,"xgnbyte UTF8->UCS2","",uc.x_short);
+ }
+#endif /* UNICODE */
+
+#ifdef KANJI
+#ifdef UNICODE
+ else
+#endif /* UNICODE */
+ if (fcsinfo[fcs].alphabet == AL_JAPAN) { /* Japanese source file */
+ int c7, x, y;
+ if (fcs == FC_JIS7) { /* If file charset is JIS-7 */
+ if (!ffc) /* If first byte of file */
+ j7init(); /* Initialize JIS-7 parser */
+ x = getj7(); /* Get a JIS-7 byte */
+ } else /* Otherwise */
+ x = fn ? (*fn)() : zminchar(); /* Just get byte */
+ if (x < 0) { /* Propogate EOF or error */
+ debug(F100,"XGNBYTE EOF","",0);
+ return(x);
+ }
+ debug(F001,"XGNBYTE x","",x);
+ ffc++; /* Count */
+#ifndef NOXFER
+ if (docrc && (what & W_SEND)) dofilcrc(x); /* Do CRC */
+#endif /* NOXFER */
+ switch (fcs) { /* What next depends on charset */
+ case FC_SHJIS: /* Shift-JIS */
+ if ((x <= 0x80) || /* Any 7-bit char... */
+ (x >= 0xa0 && x <= 0xdf)) { /* or halfwidth Katakana */
+ sj.x_short = (USHORT) x; /* we read one byte. */
+ } else { /* Anything else */
+ if ((y = fn ? (*fn)() : zminchar()) < 0) /* get another */
+ return(y);
+#ifndef NOXFER
+ if (docrc && (what & W_SEND)) dofilcrc(y);
+#endif /* NOXFER */
+ ffc++;
+ sj.x_char[byteorder] = (CHAR) x;
+ sj.x_char[1-byteorder] = (CHAR) y;
+ }
+ break;
+
+ case FC_JIS7: /* JIS-7 */
+ case FC_JDEC: /* DEC Kanji */
+ case FC_JEUC: /* EUC-JP */
+ if ((x & 0x80) == 0) { /* Convert to Shift-JIS */
+ sj.x_short = (USHORT) x; /* C0 or G0: one byte */
+ eu.x_short = (USHORT) x;
+ haveeu = 1;
+ } else {
+ c7 = x & 0x7f;
+ if (c7 > 0x20 && c7 < 0x7f) { /* Kanji: two bytes */
+ if ((y = (fcs == FC_JEUC) ?
+ (fn ? (*fn)() : zminchar()) :
+ getj7() /* ^^^ */
+ ) < 0)
+ return(y);
+ ffc++;
+#ifndef NOXFER
+ if (docrc && (what & W_SEND)) dofilcrc(y);
+#endif /* NOXFER */
+ eu.x_char[byteorder] = (CHAR) x;
+ eu.x_char[1-byteorder] = (CHAR) y;
+ sj.x_short = eu_to_sj(eu.x_short);
+ haveeu = 1;
+ } else if (x == 0x8e) { /* SS2 Katakana prefix: 2 bytes */
+ if ((y = (fcs == FC_JIS7) ?
+ getj7() : /* ^^^ */
+ (fn ? (*fn)() : zminchar())
+ ) < 0)
+ return(y);
+ ffc++;
+#ifndef NOXFER
+ if (docrc && (what & W_SEND)) dofilcrc(y);
+#endif /* NOXFER */
+ sj.x_short = y | 0x80;
+ debug(F001,"XGNBYTE KANA SJ","",sj.x_short);
+ } else {
+ /* Something that translates to U+FFFD */
+ sj.x_short = UNKSJIS;
+ }
+ }
+ break;
+ }
+ havesj = 1; /* Have Shift-JIS */
+#ifdef UNICODE
+ uc.x_short = sj_to_un(sj.x_short); /* Translate to UCS-2 */
+ haveuc = 1; /* Have Unicode */
+#endif /* UNICODE */
+ flag = 1; /* Have a char */
+ }
+#endif /* KANJI */
+ }
+ if (!flag) { /* If no character was read yet... */
+ if ((x = (fn ? (*fn)() : zminchar())) > -1) /* read one now */
+ ffc++;
+ debug(F101,"xgnbyte zminchar 1","",x);
+ if (x < 0)
+ return(x);
+ haveuc = 0;
+ }
+#ifdef UNICODE
+ if (haveuc) {
+ thischar = uc.x_short;
+ /* lastucs2 = uc.x_short; */
+ } else
+#endif /* UNICODE */
+ thischar = x;
+ debug(F001,"xgnbyte thischar",haveuc ? "[UNICODE]" : "[other]",thischar);
+
+#ifdef CK_CTRLZ /* SET EOF CTRLZ */
+ if (eofmethod == XYEOF_Z && !binary && thischar == 26) {
+ debug(F100,"xgnbyte EOF on Ctrl-Z 1","",0);
+ return(-1);
+ }
+#endif /* CK_CTRLZ */
+
+#ifdef UNICODE
+ if (!haveuc) /* If not Unicode... */
+#endif /* UNICODE */
+ x &= fmask; /* Apply SET FILE BYTESIZE mask */
+
+ switch (xlatype) { /* Translation type... */
+#ifdef UNICODE
+ case XLA_UNICODE: { /* Unicode is involved */
+ xc = 0;
+/*
+ Here we must choose the appropriate translation function. If we are being
+ called by getpkt() (i.e. when transferring a file), we are translating from
+ Unicode to the Transfer Character Set and therefore must use the function
+ pointed to by xut. Otherwise, e.g. during TRANSLATE, CONNECT, TRANSMIT, etc,
+ we are translating from Unicode to the File Character Set and so must call
+ the function pointed to by xuf. There might be a cleaner way to set this
+ up but I don't think so. For example, setxlatype() might have been called
+ too soon and so might not have known whether it was a file transfer or a
+ local operation.
+*/
+/*
+ (Many years later...) In testing this code I noticed that TRANSLATE'ing
+ Russian text from UTF-8 to ISO Latin/Cyrillic produced all question marks.
+ Rereading the previous paragraph it seems to me we are (I am) overloading
+ this function with responsibilites, satisfying the needs of file transfer
+ (local file charset -> transfer charset for outbound packet) and local file
+ conversion. In the case of TRANSLATE, we call (xgnbyte(), xpnbyte()) in a
+ loop, expecting the xgnbyte() will feed UCS2 to xpnbyte(). But the
+ following code does what xpnbyte() is going to do, returning (in this case)
+ an ISO Latin/Cyrillic byte stream, which xpnbyte() believes to be UCS2, and
+ comes up with nonsense. Not wanting to rip the whole thing apart and start
+ over, I made the following change that should do no harm, upon observing
+ that if the input character set is UTF-8 or UCS-2, then when we get here it
+ has already been converted to UCS2, so if we are not transferring a file, we
+ don't need to do anything else except put the bytes in the right place to be
+ returned, which is done further along.
+*/
+#ifdef COMMENT
+ /* Previous code */
+ xx = (what & W_SEND) ? xut : xuf;
+#else
+ /* New code 2011-06-03 */
+ if (what & W_SEND) {
+ xx = xut;
+ } else {
+ if (fcs == FC_UCS2 || fcs == FC_UTF8)
+ xx = NULL;
+ else
+ xx = xuf;
+ }
+#endif /* COMMENT */
+
+ eolflag = 0;
+ if (haveuc) { /* File is Unicode */
+ /* See Unicode TR13, "Converting to Other Character Sets" */
+ if (uc.x_short == 0x2028 || /* Line Separator? */
+ uc.x_short == 0x2029 || /* Paragraph Separator */
+ (feol && (uc.x_short == (USHORT)feol))
+ ) {
+ debug(F001,"xgnbyte uc eol","",uc.x_short);
+ rc = 0;
+ eolflag = 1; /* Don't translate and handle later */
+ }
+ if (xx && !eolflag) { /* UCS-to-TCS function (UCS->byte) */
+ rc = (*xx)(uc.x_short); /* These can fail... */
+ debug(F101,"xgnbyte xx rc","",rc);
+ if (rc < 0) /* If it can't be translated */
+ uc.x_short = UNK; /* Put unknown-character symbol */
+ else
+ uc.x_short = (unsigned)((unsigned)rc & 0xffff);
+ debug(F101,"xgnbyte xx uc","",uc.x_short);
+ }
+#ifdef KANJI
+ if (tcs == FC_JEUC) { /* Translating to EUC-JP */
+ USHORT sj = 0;
+ union ck_short eu;
+ debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short);
+ if (!havesj) /* If we don't already have it */
+ sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */
+ eu.x_short = sj_to_eu(sj);
+ debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short);
+ xlaptr = 0;
+ xlacount = 0;
+ if (eolflag) {
+ if (what & W_SEND) {
+ xlabuf[xlacount++] = LF;
+ return(CR);
+ } else {
+ return(feol);
+ }
+ }
+ if (eu.x_char[byteorder]) { /* Two bytes */
+ rc = eu.x_char[byteorder];
+ xlabuf[xlacount++] = eu.x_char[1-byteorder];
+ debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]);
+ } else { /* One byte */
+ rc = eu.x_char[1-byteorder];
+ }
+ debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount);
+ debug(F001,"xgnbyte UCS->EUC rc","",rc);
+ return(rc);
+ } else
+#endif /* KANJI */
+ if (tcs != FC_UCS2 && tcs != FC_UTF8) {
+ if (uc.x_short & 0xff00) { /* Decoding error */
+ debug(F001,"xgnbyte decoding error","",uc.x_short);
+ return(-2);
+ } else
+ return((unsigned int)(uc.x_short & 0xff));
+ }
+ xc = uc.x_short;
+
+ } else { /* File is not Unicode */
+ USHORT ch;
+ /* Translate from single FCS byte to UCS-2 */
+/*
+ This is a bit nonobvious... The blah_u() (Blah-to-Unicode) routines are
+ called only with pieces of character sets, in the ISO 2022 sense. So,
+ for example, if ch is a Latin-1 character, we call the translation
+ routine only if it is in the right half; if it's in the left half, it
+ isn't translated, and in fact will give the wrong result if sent to the
+ translation function. That's because those functions were designed for
+ use with the ISO 2022 G0..G3 sets, not for file transfer. On the other
+ hand, if it's a 7-bit character set, we *do* call the translation
+ function. (To put it another way, the left half of any 8-bit character
+ set is ASCII and therefore doesn't need to be translated but 7-bit sets
+ such as ISO 646 German do need translation).
+*/
+ ch = (unsigned)(thischar & 0xff);
+ if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) ||
+ fcsinfo[fcs].size <= 128) {
+ if (xfu) { /* FCS-to-UCS function */
+ ch = (*xfu)(ch);
+ }
+ }
+ xc = ch;
+ }
+ /* At this point we have a UCS-2 character in native format */
+ /* (Big Endian or Little Endian) in xc, which is an unsigned int. */
+
+ debug(F001,"xgnbyte xc","",xc);
+
+ if (tcs == FC_UTF8) { /* Now convert to UTF-8 */
+ USHORT c; /* NOTE: this is FC_UTF8 on purpose! */
+ CHAR * buf = NULL;
+ int i, k = 0, x;
+
+ xlaptr = 0;
+ if (utferror) {
+ xlabuf[k++] = 0xff;
+ xlabuf[k++] = 0xbd;
+ }
+ if (eolflag) { /* We detected EOL in source file */
+ if (what & W_SEND) { /* Convert to CRLF */
+ xlabuf[k++] = LF;
+ xlacount = k;
+ return((unsigned int)CR);
+#ifdef COMMENT
+ } else { /* Or to local line-end */
+ xlacount = k;
+ return((unsigned int)feol);
+#endif /* COMMENT */
+ }
+ }
+ c = xc;
+ if ((x = ucs2_to_utf8(c,&buf)) < 1) {
+ debug(F101,"xgnbyte ucs2_to_utf8 error","",c);
+ return(-2);
+ }
+ debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]);
+ for (i = 1; i < x; i++) {
+ xlabuf[k+i-1] = buf[i];
+ debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]);
+ }
+ xlaptr = 0;
+ xlacount = x - 1;
+ debug(F101,"xgnbyte UTF8 xlacount","",xlacount);
+ return((unsigned int)buf[0]);
+ } else { /* Or keep it as UCS-2 */
+ int k = 0;
+ CHAR c;
+ xlaptr = 0;
+ if (utferror) {
+ xlabuf[k++] = 0xff;
+ xlabuf[k++] = 0xfd;
+ debug(F101,"xgnbyte error","",k);
+ }
+ if (eolflag) { /* We detected EOL in source file */
+ if (what & W_SEND) { /* Convert to CRLF */
+ xlabuf[k++] = CR;
+ xlabuf[k++] = NUL;
+ xlabuf[k++] = LF;
+ xlacount = k;
+ debug(F101,"xgnbyte send CRLF","",k);
+ return(0); /* Return NUL */
+ } else { /* Or to local line-end */
+#ifdef COMMENT
+ /* This bypasses byte swapping that we might need */
+ xlabuf[k++] = (CHAR)feol;
+ xlacount = k;
+ debug(F101,"xgnbyte send feol","",k);
+ return(0); /* Return NUL */
+#else
+ xc = (CHAR)feol;
+#endif /* COMMENT */
+ }
+ }
+ /* In which order should we return the bytes? */
+#ifdef COMMENT
+ if ( (what & W_SEND) || (what & W_FTP) || (fileorder == 0)) {
+#endif /* COMMENT */
+ /* ALWAYS RETURN IN BIG ENDIAN ORDER... 7 Sep 2002 */
+ /* xgnbyte() is almost always used to feed xpnbyte() */
+ /* which requires bytes in BE order. In cases where */
+ /* xgnbyte is used in isolation, the caller can swap */
+ /* bytes itself afterwards. */
+ xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */
+ xlabuf[k++] = xc & 0xff;
+ debug(F001,"xgnbyte->UCS2BE",
+ ckitox((int)xlabuf[0]),xlabuf[1]);
+#ifdef COMMENT
+ } else { /* Little Endian */
+ xlabuf[k++] = xc & 0xff;
+ xlabuf[k++] = (xc >> 8) & 0xff;
+ debug(F001,"xgnbyte->UCS2LE",
+ ckitox((int)xlabuf[0]),xlabuf[1]);
+ }
+#endif /* COMMENT */
+ c = xlabuf[0];
+ xlaptr = 1;
+ xlacount = k-1;
+ debug(F101,"xgnbyte c","",c);
+ debug(F101,"xgnbyte xlaptr","",xlaptr);
+ debug(F011,"xgnbyte xlabuf",xlabuf,xlacount);
+ return((unsigned int)c);
+ }
+ }
+#endif /* UNICODE */
+ case XLA_NONE:
+ return((fn ? (*fn)() : zminchar()));
+ case XLA_BYTE: /* Byte-for-Byte translation */
+ rt = x;
+ if (sx)
+ rt = (*sx)(rt);
+#ifdef UNICODE
+ if (utferror) {
+ xlaptr = 0;
+ xlacount = 1;
+ xlabuf[0] = rt;
+ return(UNK);
+ } else
+#endif /* UNICODE */
+ return((unsigned int)rt);
+
+#ifdef KANJI
+ case XLA_JAPAN: /* Come here with Shift-JIS */
+ if (tcs == FC_JEUC) { /* It better be... */
+ xlaptr = 0;
+ xlacount = 0;
+ if (!havesj) {
+ printf("BAD BAD\n");
+ return(-2);
+ }
+ if (!haveeu) /* We might already have EUC too */
+ eu.x_short = sj_to_eu(sj.x_short);
+ if (eu.x_char[byteorder]) {
+ xlabuf[xlacount++] = eu.x_char[1-byteorder];
+ return(eu.x_char[byteorder]);
+ } else {
+ return(eu.x_char[1-byteorder]);
+ }
+ break;
+ }
+#endif /* KANJI */
+
+ default:
+ debug(F101,"xgnbyte bad xlatype","",xlatype);
+ return(-2);
+ }
+#ifdef COMMENT
+/*
+ If there is a return() statement here, some compilers complain
+ about "statement not reached". If there is no return() statement,
+ other compilers complain that "Non-void function should return a value".
+ There is no path through this function that falls through to here.
+*/
+ debug(F100,"xgnbyte switch failure","",0);
+ return(-2);
+#endif /* COMMENT */
+}
+#endif /* NOCSETS */
+
+#ifndef NOXFER
+
+/* G E T P K T -- Fill a packet data field from the indicated source. */
+
+/*
+ Parameters:
+ bufmax: Maximum length of entire packet.
+ xlate: Flag for whether to translate charsets when in text mode.
+ Returns: Number of characters written to packet data field, 0 or more,
+ Or -1 on failure (internal error),
+ or -3 on timeout (e.g. when reading from a pipe).
+
+ This is the full version allowing for parity and text-mode conversions;
+ i.e. it works in all cases. Also see bgetpkt(), a special lean/mean/fast
+ packet encoder that works only for binary-mode no-parity transfers.
+*/
+static int uflag = 0;
+
+int
+getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
+ register CHAR rt = t, rnext = NUL; /* Register shadows of the globals */
+ register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
+ register int x; /* Loop index. */
+ register int a7; /* Low 7 bits of character */
+
+ CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */
+
+ if (binary) xlate = 0; /* We don't translate if binary */
+
+ if (!data) {
+ debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0);
+ return(-1);
+ }
+ dp = data; /* Point to packet data buffer */
+ size = 0; /* And initialize its size */
+/*
+ Assume bufmax is the receiver's total receive-packet buffer length.
+ Our whole packet has to fit into it, so we adjust the data field length.
+ We also decide optimally whether it is better to use a short-format or
+ long-format packet when we're near the borderline.
+*/
+ bufmax = maxdata(); /* Get maximum data length */
+
+ if (first == 1) { /* If first character of this file.. */
+#ifdef UNICODE
+ /* Special end-of-line handling for Unicode */
+ if (tcharset == TC_UCS2 || tcharset == TC_UTF8)
+ uflag = 1;
+#endif /* UNICODE */
+ debug(F101,"getpkt first uflag","",uflag);
+ debug(F101,"getpkt first rt","",rt);
+ if (!memstr && !funcstr) /* and real file... */
+ ffc = (CK_OFF_T)0; /* reset file character counter */
+#ifdef COMMENT
+ /* Moved to below... */
+ first = 0; /* Next character won't be first */
+#endif /* COMMENT */
+ *leftover = '\0'; /* Discard any interrupted leftovers */
+ nleft = 0;
+#ifndef NOCSETS
+ setxlatype(tcharset,fcharset); /* Set up charset translations */
+#endif /* NOCSETS */
+
+ /* Get first character of file into rt, watching out for null file */
+
+#ifdef CALIBRATE
+ if (calibrate && !memstr) {
+#ifdef NORANDOM
+ x = rt = 53;
+#else
+ x = rt = cal_a[rand() & 0xff];
+#endif /* NORANDOM */
+ first = 0;
+ ffc++;
+ } else
+#endif /* CALIBRATE */
+#ifdef KANJI
+ if (xlate && tcharset == TC_JEUC) { /* Kanji text */
+ x = zkanjf();
+ if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
+ first = -1;
+ size = 0;
+ if (x == -2) {
+ debug(F100,"getpkt zkanji: input error","",0);
+ cxseen = 1;
+ } else debug(F100,"getpkt zkanji: empty string/file","",0);
+ return(0);
+ }
+ rt = x;
+ first = 0;
+ if (!memstr) {
+ ffc++;
+ if (docrc && (what & W_SEND)) /* Accumulate file crc */
+ dofilcrc((int)rt);
+ }
+ } else { /* Not Kanji text */
+#endif /* KANJI */
+ if (memstr) { /* Reading data from memory string */
+ /* This will not be Unicode */
+ if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
+ first = -1;
+ size = 0;
+ debug(F100,"getpkt: empty string","",0);
+ return(0);
+ }
+ first = 0;
+ } else if (funcstr) { /* Reading data from a function */
+ /* This will not be Unicode */
+ if ((x = (*funcptr)()) < 0) { /* End of input */
+ first = -1;
+ size = 0; /* Empty */
+ return(0);
+ }
+ ffc++; /* Count a file character */
+ rt = (CHAR) x; /* Convert int to char */
+ first = 0;
+ debug(F000,"getpkt funcstr","",rt);
+
+ } else { /* Reading data from a file */
+#ifndef NOCSETS
+ if (xlate && !binary) { /* Could be Unicode */
+ if (xlatype == XLA_UNICODE) {
+ /* Get next translated byte */
+ x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
+ debug(F101,"getpkt xgnbyte","",x);
+ } else { /* Not Unicode */
+ x = zminchar(); /* Get next byte, translate below */
+ debug(F101,"getpkt zminchar A","",x);
+ }
+ } else { /* Just get next byte */
+#endif /* NOCSETS */
+ x = zminchar();
+ debug(F101,"getpkt zminchar B","",x);
+#ifndef NOCSETS
+ }
+#endif /* NOCSETS */
+ if (x < 0) { /* End of file or input error */
+ if (x == -3) { /* Timeout. */
+ size = (dp-data);
+ debug(F101,"getpkt timeout size","",size);
+ return((size == 0) ? x : size);
+ }
+ first = -1;
+ size = 0;
+ if (x == -2) { /* Error */
+ debug(F100,"getpkt: input error","",0);
+ cxseen = 1; /* Interrupt the file transfer */
+ } else {
+ debug(F100,"getpkt empty file","",0);
+ }
+ return(0);
+ }
+ first = 0; /* Next character won't be first */
+ rt = (CHAR) x; /* Convert int to char */
+#ifndef NOCSETS
+ if (xlatype != XLA_UNICODE || binary) {
+ ffc++;
+ if (sx)
+ rt = (*sx)(rt);
+ if (docrc && (what & W_SEND))
+ dofilcrc(x);
+ }
+#endif /* NOCSETS */
+#ifdef DEBUG
+ if (deblog)
+ debug(F101,"getpkt 1st char","",rt);
+#endif /* DEBUG */
+ if (/* !haveuc && */ docrc && (what & W_SEND)) /* File CRC */
+ dofilcrc(x);
+ }
+#ifdef KANJI
+ }
+#endif /* KANJI */
+ /* PWP: handling of feol is done later (in the while loop)... */
+
+ } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"getpkt eof crc16","",crc16);
+ debug(F101,"getpkt eof ffc","",ffc);
+ }
+#endif /* DEBUG */
+ return(size = 0);
+ }
+/*
+ Here we handle characters that were encoded for the last packet but
+ did not fit, and so were saved in the "leftover" array.
+*/
+ debug(F101,"getpkt nleft","",nleft);
+ if (nleft) {
+ for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */
+ *dp++ = *p1++;
+ *leftover = '\0'; /* Delete leftovers */
+ nleft = 0;
+ }
+ if (first == -1) /* Handle EOF */
+ return(size = (dp - data));
+
+/* Now fill up the rest of the packet. */
+
+ rpt = 0; /* Initialize character repeat count */
+
+ while (first > -1) { /* Until EOF... */
+#ifdef CALIBRATE
+ if (calibrate && !memstr) { /* We generate our own "file" */
+ if (ffc >= calibrate) { /* EOF */
+ first = -1;
+ ffc--;
+ } else { /* Generate next character */
+ if (cal_j > CAL_M * ffc)
+ cal_j = cal_a[ffc & 0xff];
+ x = (unsigned)cal_a[(cal_j & 0xff)];
+ if (x == rt) x ^= 2;
+ }
+ cal_j += (unsigned int)(ffc + CAL_O);
+ ffc++;
+ } else
+#endif /* CALIBRATE */
+#ifdef KANJI
+ if (xlate && tcharset == TC_JEUC) {
+ if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
+ first = -1;
+ if (x == -2) cxseen = 1;
+ } else if (!memstr) ffc++;
+ rnext = (CHAR) (x & fmask);
+ } else {
+#endif /* KANJI */
+ if (memstr) { /* Get next char from memory string */
+ if ((x = *memptr++) == '\0') /* End of string means EOF */
+ first = -1; /* Flag EOF for next time. */
+ rnext = (CHAR) (x & fmask); /* Apply file mask */
+ } else if (funcstr) { /* Get next char from function */
+ if ((x = (*funcptr)()) < 0) /* End of string means EOF */
+ first = -1; /* Flag EOF for next time. */
+ rnext = (CHAR) (x & fmask); /* Apply file mask */
+ } else { /* From file... */
+#ifndef NOCSETS
+ if (xlate && !binary) { /* Could be Unicode */
+ if (xlatype == XLA_UNICODE) {
+ /* Get next translated byte */
+ x = xgnbyte(cseqtab[tcharset],fcharset,NULL);
+ } else { /* Not Unicode */
+ x = zminchar(); /* Get next byte, translate below */
+ /* debug(F101,"xgnbyte B zminchar","",x); */
+ }
+ } else { /* Just get next byte */
+#endif /* NOCSETS */
+ x = zminchar();
+ /* debug(F101,"xgnbyte C zminchar","",x); */
+#ifndef NOCSETS
+ }
+#endif /* NOCSETS */
+ if (x < 0) { /* Check for EOF */
+ if (x == -3) { /* Timeout reading from pipe */
+ t = rt;
+ size = (dp-data);
+ debug(F101,"getpkt timeout size","",size);
+ return((size == 0) ? x : size);
+ }
+ first = -1; /* Flag eof for next time. */
+ if (x == -2) cxseen = 1; /* If error, cancel this file. */
+ }
+ rnext = (CHAR) (x & fmask); /* Apply file mask */
+#ifndef NOCSETS
+ if (xlatype != XLA_UNICODE) {
+#endif /* NOCSETS */
+ ffc++;
+#ifndef NOCSETS
+ if (sx)
+ rt = (*sx)(rt);
+#endif /* NOCSETS */
+ if (docrc && (what & W_SEND))
+ dofilcrc(x);
+
+#ifndef NOCSETS
+ }
+#endif /* NOCSETS */
+ }
+#ifdef KANJI
+ }
+#endif /* KANJI */
+/*
+ At this point, the character we just read is in rnext,
+ and the character we are about to encode into the packet is in rt.
+*/
+ odp = dp; /* Remember where we started. */
+ xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
+/*
+ Now encode the character according to the options that are in effect:
+ ctlp[]: whether this control character needs prefixing.
+ binary: text or binary mode.
+ rptflg: repeat counts enabled.
+ ebqflg: 8th-bit prefixing enabled.
+ lscapu: locking shifts enabled.
+*/
+ if (rptflg) { /* Repeat processing is on? */
+ if (!uflag &&
+ /*
+ * If the next char is really CRLF, then we cannot
+ * be doing a repeat (unless CR,CR,LF which becomes
+ * "~ <n-1> CR CR LF", which is OK but not most efficient).
+ * I just plain don't worry about this case. The actual
+ * conversion from NL to CRLF is done after the rptflg if...
+ */
+ (!feol || binary || (feol && (rnext != feol))) &&
+ (rt == rnext) && (first == 0)) { /* Got a run... */
+ if (++rpt < 94) { /* Below max, just count */
+ continue; /* go back and get another */
+ } else if (rpt == 94) { /* Reached max, must dump */
+ xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
+ rptn += rpt; /* Accumulate it for statistics */
+ rpt = 0; /* And reset it */
+ }
+ } else if (rpt > 1) { /* More than two */
+ xxrc = (CHAR) tochar(++rpt); /* and count. */
+ rptn += rpt;
+ rpt = 0; /* Reset repeat counter. */
+ }
+ /*
+ If (rpt == 1) we must encode exactly two characters.
+ This is done later, after the first character is encoded.
+ */
+ }
+ /* If it's the newline character... */
+ if (!uflag && !binary && feol && (rt == feol)) {
+ if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */
+ if (ebqflg) { /* If single shifts enabled, */
+ *dp++ = (CHAR) ebq; /* insert a single shift. */
+ } else { /* Otherwise must shift in. */
+ *dp++ = myctlq; /* Insert shift-out code */
+ *dp++ = 'O';
+ lsstate = 0; /* Change shift state */
+ }
+ }
+#ifdef CK_SPEED
+ if (ctlp[CR]) {
+ *dp++ = myctlq; /* Insert carriage return directly */
+ *dp++ = 'M';
+ ccp++;
+ } else {
+ *dp++ = CR; /* Perhaps literally */
+ ccu++;
+ }
+#else /* !CK_SPEED */
+ *dp++ = myctlq; /* Insert carriage return directly */
+ *dp++ = 'M';
+ ccp++;
+#endif /* CK_SPEED */
+ rt = LF; /* Now make next char be linefeed. */
+ }
+/*
+ Now handle the 8th bit of the file character. If we have an 8-bit
+ connection, we preserve the 8th bit. If we have a 7-bit connection,
+ we employ either single or locking shifts (if they are enabled).
+*/
+ a7 = rt & 0177; /* Get low 7 bits of character */
+ if (rt & 0200) { /* 8-bit character? */
+ if (lscapu) { /* Locking shifts enabled? */
+ if (!lsstate) { /* Not currently shifted? */
+ x = lslook(0200); /* Look ahead */
+ if (x != 0 || ebqflg == 0) { /* Locking shift decision */
+ xxls = 'N'; /* Need locking shift-out */
+ lsstate = 1; /* and change to shifted state */
+ } else if (ebqflg) { /* Not worth it */
+ xxss = (CHAR) ebq; /* Use single shift */
+ }
+ }
+ rt = (CHAR) a7; /* Replace character by 7-bit value */
+ } else if (ebqflg) { /* 8th bit prefixing is on? */
+ xxss = (CHAR) ebq; /* Insert single shift */
+ rt = (CHAR) a7; /* Replace character by 7-bit value */
+ }
+/*
+ In case we have a 7-bit connection and this is an 8-bit character, AND
+ neither locking shifts nor single shifts are enabled, then the character's
+ 8th bit will be destroyed in transmission, and a block check error will
+ occur.
+*/
+ } else if (lscapu) { /* 7-bit character */
+
+ if (lsstate) { /* Comes while shifted out? */
+ x = lslook(0); /* Yes, look ahead */
+ if (x || ebqflg == 0) { /* Time to shift in. */
+ xxls = 'O'; /* Set shift-in code */
+ lsstate = 0; /* Exit shifted state */
+ } else if (ebqflg) { /* Not worth it, stay shifted out */
+ xxss = (CHAR) ebq; /* Insert single shift */
+ }
+ }
+ }
+ /* If data character is significant to locking shift protocol... */
+ if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
+ xxdl = 'P'; /* Insert datalink escape */
+
+ if (
+#ifdef CK_SPEED
+ /*
+ Thwart YET ANOTHER unwanted, unneeded, and unloved sign
+ extension. This one was particularly nasty because it prevented
+ 255 (Telnet IAC) from being prefixed on some platforms -- e.g.
+ VMS with VAX C -- but not others, thus causing file transfers to
+ fail on Telnet connections by sending bare IACs. Not to mention
+ the stray memory reference. Signed chars are a BAD idea.
+ */
+ ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */
+#else
+ (a7 < SP) || (a7 == DEL)
+#endif /* CK_SPEED */
+ ) { /* Do control prefixing if necessary */
+ xxcq = myctlq; /* The prefix */
+ ccp++; /* Count it */
+ rt = (CHAR) ctl(rt); /* Uncontrollify the character */
+ }
+#ifdef CK_SPEED
+ else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
+ ccu++;
+#endif /* CK_SPEED */
+
+ if (a7 == myctlq) /* Always prefix the control prefix */
+ xxcq = myctlq;
+
+ if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
+ xxcq = myctlq; /* prefix it if doing repeat counts */
+
+ if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */
+ xxcq = myctlq; /* if doing 8th-bit prefixes */
+
+/* Now construct the entire sequence */
+
+ if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
+ odp2 = dp; /* (Save this place) */
+ if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
+ if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
+ if (xxss) { *dp++ = (CHAR) ebq; } /* Single shift */
+ if (xxcq) { *dp++ = myctlq; } /* Control prefix */
+ *dp++ = rt; /* Finally, the character itself */
+
+ if (rpt == 1) { /* Exactly two copies? */
+ rpt = 0;
+ p2 = dp; /* Save place temporarily */
+ for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
+ *dp++ = *p1;
+ if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
+ if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */
+ }
+ rt = rnext; /* Next character is now current. */
+
+/* Done encoding the character. Now take care of packet buffer overflow. */
+
+ if ((dp-data) >= bufmax) { /* If too big, save some for next. */
+
+ debug(F000,"getpkt EOP","",rt);
+
+ size = (dp-data); /* Calculate the size. */
+ *dp = '\0'; /* Mark the end. */
+ if (memstr) { /* No leftovers for memory strings */
+ if (rt) /* Char we didn't encode yet */
+ memptr--; /* (for encstr()) */
+ return(size);
+ }
+ if ((dp-data) > bufmax) { /* if packet is overfull */
+ /* copy the part that doesn't fit into the leftover buffer, */
+ /* taking care not to split a prefixed sequence. */
+ int i;
+ nleft = dp - odp;
+ for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) {
+ *p1++ = *p2++;
+ if (memstr) memptr--; /* (for encstr) */
+ }
+ debug(F111,"getpkt leftover",leftover,size);
+ debug(F101,"getpkt osize","",(odp-data));
+ size = (odp-data); /* Return truncated packet. */
+ *odp = '\0'; /* Mark the new end */
+ }
+ t = rt; /* Save for next time */
+ return(size);
+ }
+ } /* Otherwise, keep filling. */
+ size = (dp-data); /* End of file */
+ *dp = '\0'; /* Mark the end of the data. */
+ debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
+ return(size); /* return partially filled last packet. */
+}
+
+/* T I N I T -- Initialize a transaction */
+
+int epktrcvd = 0, epktsent = 0;
+
+/*
+ Call with 1 to reset everything before S/I/Y negotiation, or 0 to
+ reset only the things that are not set in the S/I/Y negotiation.
+ Returns -1 on failure (e.g. to create packet buffers), 0 on success.
+*/
+int
+tinit(flag) int flag; {
+ int x;
+#ifdef CK_TIMERS
+ extern int rttflg;
+#endif /* CK_TIMERS */
+ extern int rcvtimo;
+ extern int fatalio;
+
+ debug(F101,"tinit flag","",flag);
+
+ *epktmsg = NUL;
+ epktrcvd = 0;
+ epktsent = 0;
+ ofperms = "";
+ diractive = 0; /* DIR / REMOTE DIR not active */
+ interrupted = 0; /* Not interrupted */
+ fatalio = 0; /* No fatal i/o error */
+ if (server) {
+ moving = 0;
+ pipesend = 0; /* This takes care of multiple GETs sent to a server. */
+ }
+ bestlen = 0; /* For packet length optimization */
+ maxsend = 0; /* Biggest data field we can send */
+#ifdef STREAMING
+ streamok = 0; /* Streaming negotiated */
+ streaming = 0; /* Streaming being done now */
+#endif /* STREAMING */
+
+ binary = b_save; /* ... */
+ gnf_binary = binary; /* Per-file transfer mode */
+ retrans = 0; /* Packet retransmission count */
+ sndtyp = 0; /* No previous packet */
+ xflg = 0; /* Reset x-packet flag */
+ memstr = 0; /* Reset memory-string flag */
+ memptr = NULL; /* and buffer pointer */
+ funcstr = 0; /* Reset "read from function" flag */
+ funcptr = NULL; /* and function pointer */
+ autopar = 0; /* Automatic parity detection flag */
+
+ /* This stuff is only for BEFORE S/I/Y negotiation, not after */
+
+ if (flag) {
+ if (bctf) { /* Force Block Check 3 on all packets */
+ bctu = bctl = 3; /* Set block check type to 3 */
+ } else {
+ bctu = bctl = 1; /* Reset block check type to 1 */
+ }
+ myinit[0] = '\0'; /* Haven't sent init string yet */
+ rqf = -1; /* Reset 8th-bit-quote request flag */
+ ebq = MYEBQ; /* Reset 8th-bit quoting stuff */
+ ebqflg = 0; /* 8th bit quoting not enabled */
+ ebqsent = 0; /* No 8th-bit prefix bid sent yet */
+ sq = 'Y'; /* 8th-bit prefix bid I usually send */
+ spsiz = spsizr; /* Initial send-packet size */
+ debug(F101,"tinit spsiz","",spsiz);
+ wslots = 1; /* One window slot */
+ wslotn = 1; /* No window negotiated yet */
+ justone = 0; /* (should this be zero'd here?) */
+ whoareu[0] = NUL; /* Partner's system type */
+ sysindex = -1;
+ wearealike = 0;
+ what = W_INIT; /* Doing nothing so far... */
+ }
+ fncnv = f_save; /* Back to what user last said */
+ pktnum = 0; /* Initial packet number to send */
+ cxseen = czseen = discard = 0; /* Reset interrupt flags */
+ *filnam = '\0'; /* Clear file name */
+ spktl = 0; /* And its length */
+ nakstate = 0; /* Assume we're not in a NAK state */
+ numerrs = 0; /* Transmission error counter */
+ idletmo = 0; /* No idle timeout yet */
+ if (server) { /* If acting as server, */
+ if (srvidl > 0) /* If an idle timeout is given */
+ timint = srvidl;
+ else
+ timint = srvtim; /* use server timeout interval. */
+ } else { /* Otherwise */
+ timint = chktimo(rtimo,timef); /* and use local timeout value */
+ }
+ debug(F101,"tinit timint","",timint);
+
+#ifdef CK_TIMERS
+ if (rttflg && timint > 0) /* Using round-trip timers? */
+ rttinit();
+ else
+#endif /* CK_TIMERS */
+ rcvtimo = timint;
+
+ winlo = 0; /* Packet 0 is at window-low */
+ debug(F101,"tinit winlo","",winlo);
+ x = mksbuf(1); /* Make a 1-slot send-packet buffer */
+ if (x < 0) return(x);
+ x = getsbuf(0); /* Allocate first send-buffer. */
+ debug(F101,"tinit getsbuf","",x);
+ if (x < 0) return(x);
+ dumpsbuf();
+ x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */
+ if (x < 0) return(x);
+ lsstate = 0; /* Initialize locking shift state */
+ if (autopath) { /* SET RECEIVE PATHNAMES AUTO fixup */
+ fnrpath = PATH_AUTO;
+ autopath = 0;
+ }
+ return(0);
+}
+
+VOID
+pktinit() { /* Initialize packet sequence */
+ pktnum = 0; /* number & window low. */
+ winlo = 0;
+ debug(F101,"pktinit winlo","",winlo);
+}
+
+/* R I N I T -- Respond to S or I packet */
+
+VOID
+rinit(d) CHAR *d; {
+ char *tp = NULL;
+ ztime(&tp);
+ tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
+ tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
+ tlog(F110,"Collision action:", fncnam[fncact],0);
+ tlog(F100,"","",0);
+ debug(F101,"rinit fncact","",fncact);
+ filcnt = filrej = 0; /* Init file counters */
+ spar(d);
+ ack1(rpar());
+#ifdef datageneral
+ if ((local) && (!quiet)) /* Only do this if local & not quiet */
+ consta_mt(); /* Start the asynch read task */
+#endif /* datageneral */
+}
+
+
+/* R E S E T C -- Reset per-transaction character counters */
+
+VOID
+resetc() {
+ rptn = 0; /* Repeat counts */
+ fsecs = flci = flco = (CK_OFF_T)0; /* File chars in and out */
+#ifdef GFTIMER
+ fpfsecs = 0.0;
+#endif /* GFTIMER */
+ tfc = tlci = tlco = (CK_OFF_T)0; /* Total file, line chars in & out */
+ ccu = ccp = 0L; /* Control-char statistics */
+#ifdef COMMENT
+ fsize = (CK_OFF_T)-1; /* File size */
+#else
+ if (!(what & W_SEND))
+ fsize = (CK_OFF_T)-1;
+ debug(F101,"resetc fsize","",fsize);
+#endif /* COMMENT */
+ timeouts = retrans = 0; /* Timeouts, retransmissions */
+ spackets = rpackets = 0; /* Packet counts out & in */
+ crunched = 0; /* Crunched packets */
+ wcur = 0; /* Current window size */
+ wmax = 0; /* Maximum window size used */
+ peakcps = 0; /* Peak chars per second */
+}
+
+/* S I N I T -- Get & verify first file name, then send Send-Init packet */
+/*
+ Returns:
+ 1 if send operation begins successfully
+ 0 if send operation fails
+*/
+#ifdef DYNAMIC
+char *cmargbuf = NULL;
+#else
+char cmargbuf[CKMAXPATH+1];
+#endif /* DYNAMIC */
+char *cmargp[2];
+
+VOID
+fnlist() {
+ if (!calibrate)
+ sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */
+#ifdef DYNAMIC
+ if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1)))
+ fatal("fnlist: no memory for cmargbuf");
+#endif /* DYNAMIC */
+ cmargbuf[0] = NUL; /* Initialize name buffer */
+
+ debug(F101,"fnlist nfils","",nfils);
+ debug(F110,"fnlist cmarg",cmarg,0);
+ debug(F110,"fnlist cmarg2",cmarg2,0);
+ if (!cmarg2) cmarg2 = "";
+ if (nfils == 0) { /* Sending from stdin or memory. */
+ if ((cmarg2 != NULL) && (*cmarg2)) {
+ cmarg = cmarg2; /* If F packet, "as-name" is used */
+ cmarg2 = ""; /* if provided */
+ } else
+ cmarg = "stdin"; /* otherwise just use "stdin" */
+ ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1);
+ cmargp[0] = cmargbuf;
+ cmargp[1] = "";
+ cmlist = cmargp;
+ nfils = 1;
+ }
+}
+
+int
+sinit() {
+ int x; /* Worker int */
+ char *tp, *xp, *m; /* Worker string pointers */
+
+ filcnt = filrej = 0; /* Initialize file counters */
+
+ fnlist();
+
+ xp = "";
+ if (nfils < 0) {
+#ifdef PIPESEND
+ if (usepipes && protocol == PROTO_K && *cmarg == '!') {
+ pipesend = 1;
+ cmarg++;
+ }
+#endif /* PIPESEND */
+ xp = cmarg;
+ } else {
+#ifndef NOMSEND
+ if (addlist)
+ xp = filehead->fl_name;
+ else
+#endif /* NOMSEND */
+ if (filefile)
+ xp = filefile;
+ else if (calibrate)
+ xp = "Calibration";
+ else
+ xp = *cmlist;
+ }
+ debug(F110,"sinit xp",xp,0);
+ x = gnfile(); /* Get first filename. */
+ debug(F111,"sinit gnfile",ckitoa(gnferror),x);
+ if (x == 0) x = gnferror; /* If none, get error reason */
+ m = NULL; /* Error message pointer */
+ debug(F101,"sinit gnfil","",x);
+ switch (x) {
+ case -6: m = "No files meet selection criteria"; break;
+ case -5: m = "Too many files match wildcard"; break;
+ case -4: m = "Cancelled"; break;
+ case -3: m = "Read access denied"; break;
+ case -2: m = "File is not readable"; break;
+#ifdef COMMENT
+ case -1: m = iswild(filnam) ? "No files match" : "File not found";
+ break;
+ case 0: m = "No filespec given!"; break;
+#else
+ case 0:
+ case -1: m = iswild(filnam) ? "No files match" : "File not found";
+ break;
+#endif /* COMMENT */
+ default:
+ break;
+ }
+ debug(F101,"sinit nfils","",nfils);
+ debug(F110,"sinit filnam",filnam,0);
+ if (x < 1) { /* Didn't get a file. */
+ debug(F111,"sinit msg",m,x);
+ if (server) { /* Doing GET command */
+ errpkt((CHAR *)m); /* so send Error packet. */
+ } else if (!local) { /* Doing SEND command */
+ interrupted = 1; /* (To suppress hint) */
+ printf("?%s\r\n",m);
+ } else {
+ xxscreen(SCR_EM,0,0l,m); /* so print message. */
+ }
+ tlog(F110,xp,m,0L); /* Make transaction log entry. */
+ freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
+ return(0); /* Return failure code */
+ }
+ if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */
+ sleep(ckdelay); /* Delay if requested */
+#ifdef datageneral
+ if ((local) && (!quiet)) /* Only do this if local & not quiet */
+ consta_mt(); /* Start the async read task */
+#endif /* datageneral */
+ freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
+ sipkt('S'); /* Send the Send-Init packet. */
+ ztime(&tp); /* Get current date/time */
+ tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
+ tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
+ tlog(F100,"","",0);
+ debug(F111,"sinit ok",filnam,0);
+ return(1);
+}
+
+int
+#ifdef CK_ANSIC
+sipkt(char c) /* Send S or I packet. */
+#else
+sipkt(c) char c;
+#endif
+/* sipkt */ {
+ CHAR *rp; int k, x;
+ extern int sendipkts;
+ debug(F101,"sipkt pktnum","",pktnum); /* (better be 0...) */
+ ttflui(); /* Flush pending input. */
+ /*
+ If this is an I packet and SET SEND I-PACKETS is OFF, don't send it;
+ set sstate to 'Y' which makes the next input() call return 'Y' as if we
+ had received an ACK to the I packet we didn't send. This is to work
+ around buggy Kermit servers that can't handle I packets.
+ */
+ if ((sendipkts == 0) && (c == 'I')) { /* I packet but don't send I pkts? */
+ sstate = 'Y'; /* Yikes! */
+ return(0); /* (see input()..)*/
+ }
+ k = sseqtbl[pktnum]; /* Find slot for this packet */
+ if (k < 0) { /* No slot? */
+ k = getsbuf(winlo = pktnum); /* Make one. */
+ debug(F101,"sipkt getsbuf","",k);
+ }
+ rp = rpar(); /* Get protocol parameters. */
+ if (!rp) rp = (CHAR *)"";
+ x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */
+ return(x);
+}
+
+/* X S I N I T -- Retransmit S-packet */
+/*
+ For use in the GET-SEND sequence, when we start to send, but receive another
+ copy of the GET command because the receiver didn't get our S packet.
+ This retransmits the S packet and frees the receive buffer for the ACK.
+ This special case is necessary because packet number zero is being re-used.
+*/
+VOID
+xsinit() {
+ int k;
+ k = rseqtbl[0];
+ debug(F101,"xsinit k","",k);
+ if (k > -1)
+ freerbuf(k);
+ resend(0);
+}
+
+/* R C V F I L -- Receive a file */
+
+/*
+ Incoming filename is in data field of F packet.
+ This function decodes it into the srvcmd buffer, substituting an
+ alternate "as-name", if one was given.
+ Then it does any requested transformations (like converting to
+ lowercase), and finally if a file of the same name already exists,
+ takes the desired collision action.
+ Returns:
+ 1 on success.
+ 0 on failure.
+*/
+char ofn1[CKMAXPATH+4]; /* Buffer for output file name */
+char * ofn2; /* Pointer to backup file name */
+int ofn1x; /* Flag output file already exists */
+CK_OFF_T ofn1len = (CK_OFF_T)0;
+int opnerr; /* Flag for open error */
+
+int /* Returns success ? 1 : 0 */
+rcvfil(n) char *n; {
+ extern int en_cwd;
+ int i, skipthis;
+ char * n2;
+ char * dispo;
+#ifdef OS2ONLY
+ char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
+#endif /* OS2ONLY */
+#ifdef DTILDE
+ char *dirp;
+#endif /* DTILDE */
+ int dirflg, x, y;
+#ifdef PIPESEND
+ extern char * rcvfilter;
+#endif /* PIPESEND */
+#ifdef CALIBRATE
+ extern int dest;
+ CK_OFF_T csave;
+ csave = calibrate; /* So we can decode filename */
+ calibrate = (CK_OFF_T)0;
+#endif /* CALIBRATE */
+
+ ofperms = ""; /* Reset old-file permissions */
+ opnerr = 0; /* No open error (yet) */
+ ofn2 = NULL; /* No new name (yet) */
+ lsstate = 0; /* Cancel locking-shift state */
+ srvptr = srvcmd; /* Decode file name from packet. */
+
+#ifdef UNICODE
+ xpnbyte(-1,0,0,NULL); /* Reset UCS-2 byte counter. */
+#endif /* UNICODE */
+
+ debug(F110,"rcvfil rdatap",rdatap,0);
+ decode(rdatap,putsrv,0); /* Don't xlate charsets. */
+#ifdef CALIBRATE
+ calibrate = csave;
+ if (dest == DEST_N) {
+ calibrate = 1;
+ cmarg2 = "CALIBRATE";
+ }
+#endif /* CALIBRATE */
+ if (*srvcmd == '\0') /* Watch out for null F packet. */
+ ckstrncpy((char *)srvcmd,"NONAME",srvcmdlen);
+ makestr(&prrfspec,(char *)srvcmd); /* New preliminary filename */
+#ifdef DTILDE
+ if (*srvcmd == '~') {
+ dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
+ if (*dirp != '\0')
+ ckstrncpy((char *)srvcmd,dirp,srvcmdlen);
+ }
+#else
+#ifdef OS2
+ if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
+ ckstrncat((char *)srvcmd,"NONAME",srvcmdlen);
+#endif /* OS2 */
+#endif /* DTILDE */
+
+#ifndef NOICP
+#ifndef NOSPL
+/* File dialog when downloading... */
+ if (
+#ifdef CK_APC
+ (apcactive == APC_LOCAL && adl_ask) || /* Autodownload with ASK */
+#endif /* CK_APC */
+ (clcmds && haveurl) /* Or "kermit:" or "iksd:" URL */
+ ) {
+ int x;
+ char fnbuf[CKMAXPATH+1]; /* Result buffer */
+ char * preface;
+
+ if (clcmds && haveurl)
+ preface = "\r\nIncoming file from Kermit server...\r\n\
+Please confirm output file specification or supply an alternative:";
+ else
+ preface = "\r\nIncoming file from remote Kermit...\r\n\
+Please confirm output file specification or supply an alternative:";
+
+ x = uq_file(preface, /* Preface */
+ NULL, /* Prompt (let uq_file() built it) */
+ 3, /* Output file */
+ NULL, /* Help text */
+ (char *)srvcmd, /* Default */
+ fnbuf, /* Result buffer */
+ CKMAXPATH+1 /* Size of result buffer */
+ );
+ if (x < 1) { /* Refused */
+ rf_err = "Refused by user";
+ return(0);
+ }
+ ckstrncpy((char *)srvcmd,fnbuf,CKMAXPATH+1);
+ if (isabsolute((char *)srvcmd)) { /* User gave an absolute path */
+ g_fnrpath = fnrpath; /* Save current RECEIVE PATHNAMES */
+ fnrpath = PATH_ABS; /* switch to ABSOLUTE */
+ }
+ }
+#endif /* NOSPL */
+#endif /* NOICP */
+
+ if (!ENABLED(en_cwd)) { /* CD is disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
+ rf_err = "Access denied";
+ return(0);
+ }
+ }
+#ifdef COMMENT
+ /* Wrong place for this -- handle cmarg2 first -- see below... */
+
+ if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
+ debug(F110,"rcvfil access denied",srvcmd,0);
+ rf_err = "Write access denied";
+ discard = opnerr = 1;
+ return(0);
+ }
+ xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
+ debug(F110,"rcvfil srvcmd 1",srvcmd,0);
+ tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
+#endif /* COMMENT */
+
+ skipthis = 0; /* This file in our exception list? */
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ if (!rcvexcept[i]) {
+ break;
+ }
+ if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) {
+ skipthis = 1;
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (deblog && skipthis) {
+ debug(F111,"rcvfil rcvexcept",rcvexcept[i],i);
+ debug(F110,"rcvfil skipping",srvcmd,0);
+ }
+#endif /* DEBUG */
+
+ if (skipthis) { /* Skipping this file */
+ discard = 1;
+ rejection = 1;
+ rf_err = "Exception list";
+ debug(F101,"rcvfil discard","",discard);
+ tlog(F100," refused: exception list","",0);
+ return(1);
+ }
+
+ /* File is not in exception list */
+
+ if (!cmarg2) /* No core dumps please */
+ cmarg2 = "";
+ debug(F110,"rcvfil cmarg2",cmarg2,0);
+
+ if (*cmarg2) { /* Check for alternate name */
+#ifndef NOSPL
+ int y; char *s; /* Pass it thru the evaluator */
+ extern int cmd_quoting;
+ if (cmd_quoting) {
+ y = MAXRP;
+ ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for \v(filename) */
+ s = (char *)srvcmd;
+ zzstring(cmarg2,&s,&y);
+ } else
+ *srvcmd = NUL;
+ if (!*srvcmd) /* If we got something */
+#endif /* NOSPL */
+ ckstrncpy((char *)srvcmd,cmarg2,srvcmdlen);
+ }
+ debug(F110,"rcvfil srvcmd 2",srvcmd,0);
+
+#ifdef PIPESEND
+ /* If it starts with "bang", it's a pipe, not a file. */
+ if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) {
+ CHAR *s;
+ s = srvcmd+1; /* srvcmd[] is not a pointer. */
+ while (*s) { /* So we have to slide the contents */
+ *(s-1) = *s; /* over 1 space to the left. */
+ s++;
+ }
+ *(s-1) = NUL;
+ pipesend = 1;
+ }
+#endif /* PIPESEND */
+
+#ifdef COMMENT
+/*
+ This is commented out because we need to know whether the name we are
+ using was specified by the local user as an override, or came from the
+ incoming packet. In the former case, we don't do stuff to it (like
+ strip the pathname) that we might do to it in the latter.
+*/
+ cmarg2 = ""; /* Done with alternate name */
+#endif /* COMMENT */
+
+ if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
+ *(srvcmd + CKMAXPATH - 1) = NUL;
+
+ /* At this point, srvcmd[] contains the incoming filename or as-name. */
+ /* So NOW we check for write access. */
+
+ if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */
+ debug(F110,"rcvfil access denied",srvcmd,0);
+ rf_err = "Write access denied";
+ discard = opnerr = 1;
+ return(0);
+ }
+ xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
+ debug(F110,"rcvfil srvcmd 1",srvcmd,0);
+ tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
+
+#ifdef CK_LABELED
+#ifdef VMS
+/*
+ If we have an as-name, this overrides the internal name if we are doing
+ a labeled-mode transfer.
+*/
+ if (*cmarg2) {
+ extern int lf_opts;
+ lf_opts &= ~LBL_NAM;
+ }
+#endif /* VMS */
+#endif /* CK_LABELED */
+
+ debug(F111,"rcvfil pipesend",srvcmd,pipesend);
+
+#ifdef PIPESEND
+ /* Skip all the filename manipulation and collision actions */
+ if (pipesend) {
+ dirflg = 0;
+ ofn1[0] = '!';
+ ckstrncpy(&ofn1[1],(char *)srvcmd,CKMAXPATH+1);
+ ckstrncpy(n,ofn1,CKMAXPATH+1);
+ ckstrncpy(fspec,ofn1,CKMAXPATH+1);
+ makestr(&prfspec,fspec); /* New preliminary filename */
+ debug(F110,"rcvfil pipesend",ofn1,0);
+ goto rcvfilx;
+ }
+#endif /* PIPESEND */
+/*
+ This is to avoid passing email subjects through nzrtol().
+ We haven't yet received the A packet so we don't yet know it's e-mail,
+ so in fact we go ahead and convert it anyway, but later we get the
+ original back from ofilnam[].
+*/
+ dispos = 0;
+ ckstrncpy(ofilnam,(char *)srvcmd,CKMAXPATH+1);
+
+#ifdef NZLTOR
+ if (*cmarg2)
+ ckstrncpy((char *)ofn1,(char *)srvcmd,CKMAXPATH+1);
+ else
+ nzrtol((char *)srvcmd, /* Filename from packet */
+ (char *)ofn1, /* Where to put result */
+ fncnv, /* Filename conversion */
+ fnrpath, /* Pathname handling */
+ CKMAXPATH /* Size of result buffer */
+ );
+#else
+ debug(F101,"rcvfil fnrpath","",fnrpath); /* Handle pathnames */
+ if (fnrpath == PATH_OFF && !*cmarg2) { /* RECEIVE PATHNAMES OFF? */
+ char *t; /* Yes. */
+ zstrip((char *)srvcmd,&t); /* If there is a pathname, strip it */
+ debug(F110,"rcvfil PATH_OFF zstrip",t,0);
+ if (!t) /* Be sure we didn't strip too much */
+ sprintf(ofn1,"FILE%02ld",filcnt);
+ else if (*t == '\0')
+ sprintf(ofn1,"FILE%02ld",filcnt);
+ else
+ ckstrncpy(ofn1,t,CKMAXPATH+1);
+ ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); /* Now copy it back. */
+ }
+/*
+ SET RECEIVE PATHNAMES RELATIVE...
+ The following doesn't belong here but doing it right would require
+ defining and implementing a new file routine for all ck?fio.c modules.
+ So for now...
+*/
+#ifdef UNIXOROSK
+ else if (fnrpath == PATH_REL && !*cmarg2) {
+ if (isabsolute((char *)srvcmd)) {
+ ofn1[0] = '.';
+ ckstrncpy(&of1n[1],(char *)srvcmd,CKMAXPATH+1);
+ ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
+ debug(F110,"rcvfil PATH_REL",ofn1,0);
+ }
+ }
+#else
+#ifdef OS2
+ else if (fnrpath == PATH_REL && !*cmarg2) {
+ if (isabsolute((char *)srvcmd)) {
+ char *p = (char *)srvcmd;
+ if (isalpha(*p) && *(p+1) == ':')
+ p += 2;
+ if (*p == '\\' || *p == '/')
+ p++;
+ ckstrncpy(ofn1,p,CKMAXPATH+1);
+ ckstrncpy((char *)srvcmd,ofn1,srvcmdlen);
+ debug(F110,"rcvfil OS2 PATH_REL",ofn1,0);
+ }
+ }
+#endif /* OS2 */
+#endif /* UNIXOROSK */
+
+ /* Now srvcmd contains incoming filename with path possibly stripped */
+
+ if (fncnv) /* FILE NAMES CONVERTED? */
+ zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
+ else
+ ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* No, copy literally. */
+#endif /* NZLTOR */
+
+#ifdef PIPESEND
+ if (rcvfilter) {
+ char * p = NULL, * q;
+ int nn = MAXRP;
+ pipesend = 1;
+ debug(F110,"rcvfil rcvfilter ",rcvfilter,0);
+#ifndef NOSPL
+ if ((p = (char *) malloc(nn + 1))) {
+ q = p;
+#ifdef COMMENT
+ /* We have already processed srvcmd and placed it into ofn1 */
+ ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* For \v(filename) */
+#endif /* COMMENT */
+ debug(F110,"rcvfile pipesend filter",rcvfilter,0);
+ zzstring(rcvfilter,&p,&nn);
+ debug(F111,"rcvfil pipename",q,nn);
+ if (nn <= 0) {
+ printf(
+ "?Sorry, receive filter + filename too long, %d max.\n",
+ CKMAXPATH
+ );
+ rf_err = "Name too long";
+ free(q);
+ return(0);
+ }
+ ckstrncpy((char *)srvcmd,q,MAXRP);
+ free(q);
+ }
+#endif /* NOSPL */
+ }
+#endif /* PIPESEND */
+
+ /* Now the incoming filename, possibly converted, is in ofn1[]. */
+
+#ifdef OS2
+ /* Don't refuse the file just because the name is illegal. */
+ if (!IsFileNameValid(ofn1)) { /* Name is OK for OS/2? */
+#ifdef OS2ONLY
+ char *zs = NULL;
+ zstrip(ofn1, &zs); /* Not valid, strip unconditionally */
+ if (zs) {
+ if (iattr.longname.len && /* Free previous longname, if any */
+ iattr.longname.val)
+ free(iattr.longname.val);
+ iattr.longname.len = strlen(zs); /* Store in attribute structure */
+ iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
+ if (iattr.longname.val) /* Remember this (illegal) name */
+ strcpy(iattr.longname.val, zs); /* safe */
+ }
+#endif /* OS2ONLY */
+ debug(F110,"rcvfil: invalid file name",ofn1,0);
+ ChangeNameForFAT(ofn1); /* Change to an acceptable name */
+ debug(F110,"rcvfil: FAT file name",ofn1,0);
+
+ } else { /* Name is OK. */
+
+ debug(F110,"rcvfil: valid file name",ofn1,0);
+#ifdef OS2ONLY
+ if (iattr.longname.len &&
+ iattr.longname.val) /* Free previous longname, if any */
+ free(iattr.longname.val);
+ iattr.longname.len = 0;
+ iattr.longname.val = NULL; /* This file doesn't need a longname */
+#endif /* OS2ONLY */
+ }
+#endif /* OS2 */
+ debug(F110,"rcvfil as",ofn1,0);
+
+/* Filename collision action section. */
+
+ dirflg = /* Is it a directory name? */
+#ifdef CK_TMPDIR
+ isdir(ofn1)
+#else
+ 0
+#endif /* CK_TMPDIR */
+ ;
+ debug(F101,"rcvfil dirflg","",dirflg);
+ ofn1len = zchki(ofn1); /* File already exists? */
+ debug(F111,"rcvfil ofn1len",ofn1,ofn1len);
+ ofn1x = (ofn1len != (CK_OFF_T)-1);
+
+ if ( (
+#ifdef UNIX
+ strcmp(ofn1,"/dev/null") && /* It's not the null device? */
+#else
+#ifdef OSK
+ strcmp(ofn1,"/nil") &&
+#endif /* OSK */
+#endif /* UNIX */
+ !stdouf ) && /* Not copying to standard output? */
+ ofn1x || /* File of same name exists? */
+ dirflg ) { /* Or file is a directory? */
+ debug(F111,"rcvfil exists",ofn1,fncact);
+#ifdef CK_PERMS
+ ofperms = zgperm((char *)ofn1); /* Get old file's permissions */
+ debug(F110,"rcvfil perms",ofperms,0);
+#endif /* CK_PERMS */
+
+ debug(F101,"rcvfil fncact","",fncact);
+ switch (fncact) { /* Yes, do what user said. */
+ case XYFX_A: /* Append */
+ ofperms = "";
+ debug(F100,"rcvfil append","",0);
+ if (dirflg) {
+ rf_err = "Can't append to a directory";
+ tlog(F100," error - can't append to directory","",0);
+ discard = opnerr = 1;
+ return(0);
+ }
+ tlog(F110," appending to",ofn1,0);
+ break;
+#ifdef COMMENT
+ case XYFX_Q: /* Query (Ask) */
+ break; /* not implemented */
+#endif /* COMMENT */
+ case XYFX_B: /* Backup (rename old file) */
+ if (dirflg) {
+ rf_err = "Can't rename existing directory";
+ tlog(F100," error - can't rename directory","",0);
+ discard = opnerr = 1;
+ return(0);
+ }
+ znewn(ofn1,&ofn2); /* Get new unique name */
+ tlog(F110," backup:",ofn2,0);
+ debug(F110,"rcvfil backup ofn1",ofn1,0);
+ debug(F110,"rcvfil backup ofn2",ofn2,0);
+#ifdef CK_LABELED
+#ifdef OS2ONLY
+/*
+ In case this is a FAT file system, we can't change only the FAT name, we
+ also have to change the longname from the extended attributes block.
+ Otherwise, we'll have many files with the same longname and if we copy them
+ to an HPFS volume, only one will survive.
+*/
+ if (os2getlongname(ofn1, &longname) > -1) {
+ if (strlen(longname)) {
+ char tmp[10];
+ extern int ck_znewn;
+ sprintf(tmp,".~%d~",ck_znewn);
+ newlongname =
+ (char *) malloc(strlen(longname) + strlen(tmp) + 1);
+ if (newlongname) {
+ strcpy(newlongname, longname); /* safe (prechecked) */
+ strcat(newlongname, tmp); /* safe (prechecked) */
+ os2setlongname(ofn1, newlongname);
+ free(newlongname);
+ newlongname = NULL;
+ }
+ }
+ } else debug(F100,"rcvfil os2getlongname failed","",0);
+#endif /* OS2ONLY */
+#endif /* CK_LABELED */
+
+#ifdef COMMENT
+ /* Do this later, in opena()... */
+ if (zrename(ofn1,ofn2) < 0) {
+ rf_err = "Can't transform filename";
+ debug(F110,"rcvfil rename fails",ofn1,0);
+ discard = opnerr = 1;
+ return(0);
+ }
+#endif /* COMMENT */
+ break;
+
+ case XYFX_D: /* Discard (refuse new file) */
+ ofperms = "";
+ discard = 1;
+ rejection = 1; /* Horrible hack: reason = name */
+ debug(F101,"rcvfil discard","",discard);
+ tlog(F100," refused: name","",0);
+ break;
+
+ case XYFX_R: /* Rename incoming file */
+ znewn(ofn1,&ofn2); /* Make new name for it */
+#ifdef OS2ONLY
+ if (iattr.longname.len) {
+ char tmp[10];
+ extern int ck_znewn;
+ sprintf(tmp,".~%d~",ck_znewn);
+ newlongname =
+ (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
+ if (newlongname) {
+ strcpy(newlongname, iattr.longname.val); /* safe */
+ strcat(newlongname, tmp); /* safe */
+ debug(F110,
+ "Rename Incoming: newlongname",newlongname,0);
+ if (iattr.longname.len &&
+ iattr.longname.val)
+ free(iattr.longname.val);
+ iattr.longname.len = strlen(newlongname);
+ iattr.longname.val = newlongname;
+ /* free(newlongname) here ? */
+ }
+ }
+#endif /* OS2ONLY */
+ break;
+ case XYFX_X: /* Replace old file */
+ debug(F100,"rcvfil overwrite","",0);
+ if (dirflg) {
+ rf_err = "Can't overwrite existing directory";
+ tlog(F100," error - can't overwrite directory","",0);
+ discard = opnerr = 1;
+#ifdef COMMENT
+ return(0);
+#else
+ break;
+#endif /* COMMENT */
+ }
+ tlog(F110,"overwriting",ofn1,0);
+ break;
+ case XYFX_U: /* Refuse if older */
+ debug(F110,"rcvfil update",ofn1,0);
+ if (dirflg) {
+ rf_err = "File has same name as existing directory";
+ tlog(F110," error - directory exists:",ofn1,0);
+ discard = opnerr = 1;
+#ifdef COMMENT
+ /* Don't send an error packet, just refuse the file */
+ return(0);
+#endif /* COMMENT */
+ }
+ break; /* Not here, we don't have */
+ /* the attribute packet yet. */
+ default:
+ ofperms = "";
+ debug(F101,"rcvfil bad collision action","",fncact);
+ break;
+ }
+ }
+ debug(F110,"rcvfil ofn1",ofn1,0);
+ debug(F110,"rcvfil ofn2",ofn2,0);
+ debug(F110,"rcvfil ofperms",ofperms,0);
+ if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
+ xxscreen(SCR_AN,0,0l,ofn2); /* Display renamed name */
+ ckstrncpy(n, ofn2, CKMAXPATH+1); /* Return it */
+ } else { /* No */
+ xxscreen(SCR_AN,0,0l,ofn1); /* Display regular name */
+ ckstrncpy(n, ofn1, CKMAXPATH+1); /* and return it. */
+ }
+
+#ifdef CK_MKDIR
+/* Create directory(s) if necessary. */
+ if (!discard && fnrpath != PATH_OFF) { /* RECEIVE PATHAMES ON? */
+ int x;
+ debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
+ if ((x = zmkdir(ofn1)) < 0) {
+ debug(F100,"zmkdir fails","",0);
+ tlog(F110," error - directory creation failure:",ofn1,0);
+ rf_err = "Directory creation failure.";
+ discard = 1;
+ return(0);
+ }
+#ifdef TLOG
+ else if (x > 0)
+ tlog(F110," path created:",ofn1,0);
+#endif /* TLOG */
+ }
+#else
+ debug(F110,"rcvfil CK_MKDIR not defined",ofn1,0);
+#endif /* CK_MKDIR */
+
+ if (calibrate)
+ ckstrncpy(fspec,ofn1,CKMAXPATH+1);
+ else
+ zfnqfp(ofn1,fspeclen,fspec);
+ debug(F110,"rcvfil fspec",fspec,0);
+
+#ifdef COMMENT
+ /* See comments with VMS zfnqfp()... */
+#ifdef VMS
+ /* zfnqfp() does not return the version number */
+ if (!calibrate) {
+ int x, v;
+ x = strlen(ofn1);
+ if (x > 0) {
+ if (ofn1[x-1] == ';') {
+ v = getvnum(ofn1);
+ ckstrncpy(&ofn1[x],ckitoa(v),CKMAXPATH-x);
+ }
+ }
+ }
+#endif /* VMS */
+#endif /* COMMENT */
+ fspec[fspeclen] = NUL;
+ makestr(&prfspec,fspec); /* New preliminary filename */
+
+#ifdef PIPESEND
+ rcvfilx:
+#endif /* PIPESEND */
+
+ debug(F110,"rcvfilx: n",n,0);
+ debug(F110,"rcvfilx: ofn1",ofn1,0);
+ ffc = (CK_OFF_T)0; /* Init per-file counters */
+ cps = oldcps = 0L;
+ rs_len = (CK_OFF_T)0;
+ rejection = -1;
+ fsecs = gtimer(); /* Time this file started */
+#ifdef GFTIMER
+ fpfsecs = gftimer();
+ debug(F101,"rcvfil fpfsecs","",fpfsecs);
+#endif /* GFTIMER */
+ filcnt++;
+ intmsg(filcnt);
+ return(1); /* Successful return */
+}
+
+
+/* R E O F -- Receive End Of File packet for incoming file */
+
+/*
+ Closes the received file.
+ Returns:
+ 0 on success.
+ -1 if file could not be closed.
+ 2 if disposition was mail, mail was sent, but temp file not deleted.
+ 3 if disposition was print, file was printed, but not deleted.
+ -2 if disposition was mail and mail could not be sent
+ -3 if disposition was print and file could not be printed
+ -4 if MOVE-TO: failed
+ -5 if RENAME-TO: failed
+*/
+int
+reof(f,yy) char *f; struct zattr *yy; {
+ extern char * rcv_move, * rcv_rename;
+ extern int o_isopen;
+ int rc = 0; /* Return code */
+ char *p;
+ char c;
+
+ debug(F111,"reof fncact",f,fncact);
+ debug(F101,"reof discard","",discard);
+ success = 1; /* Assume status is OK */
+ lsstate = 0; /* Cancel locking-shift state */
+ if (discard) { /* Handle attribute refusals, etc. */
+ debug(F101,"reof discarding","",0);
+ success = 0; /* Status = failed. */
+ if (rejection == '#' || /* Unless rejection reason is */
+ rejection == 1 || /* date or name (SET FILE COLLISION */
+ rejection == '?') /* UPDATE or DISCARD) */
+ success = 1;
+ debug(F101,"reof success","",success);
+ filrej++; /* Count this rejection. */
+ discard = 0; /* We never opened the file, */
+ return(0); /* so we don't close it. */
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"reof cxseen","",cxseen);
+ debug(F101,"reof czseen","",czseen);
+ debug(F110,"reof rdatap",rdatap,0);
+ }
+#endif /* DEBUG */
+
+ if (cxseen == 0) /* Got cancel directive? */
+ cxseen = (*rdatap == 'D');
+ if (cxseen || czseen) /* (for hints) */
+ interrupted = 1;
+ success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
+ if (!success) /* "Uncount" this file */
+ filrej++;
+ debug(F101,"reof o_isopen","",o_isopen);
+
+ if (o_isopen) { /* If an output file was open... */
+
+#ifdef CK_CTRLZ
+ if (success) {
+ debug(F101,"reof lastchar","",lastchar);
+ if (!binary && eofmethod == XYEOF_Z && lastchar != 26 &&
+ (!xflg || (xflg && remfile)))
+ pnbyte((char)26,putfil);
+ }
+#endif /* CK_CTRLZ */
+
+ rc = clsof(cxseen || czseen); /* Close the file (resets cxseen) */
+ debug(F101,"reof closf","",rc);
+ if (rc < 0) { /* If failure to close, FAIL */
+ if (success) filrej++;
+ success = 0;
+ }
+ if (!calibrate) {
+ /* Set file modification date and/or permissions */
+ if (success)
+ zstime(f,yy,0);
+#ifdef OS2ONLY
+#ifdef CK_LABELED
+ if (success && yy->longname.len)
+ os2setlongname(f, yy->longname.val);
+#endif /* CK_LABELED */
+#endif /* OS2ONLY */
+ }
+ if (success == 0) { /* And program return code */
+ xitsta |= W_RECV;
+ } else if (success == 1) { /* File rec'd successfully */
+ makestr(&rrfspec,prrfspec); /* Record it for wheremsg */
+ makestr(&rfspec,prfspec);
+ }
+
+/* Handle dispositions from attribute packet... */
+
+ c = NUL;
+#ifndef NOFRILLS
+ if (!calibrate && yy->disp.len != 0) {
+ p = yy->disp.val;
+ c = *p++;
+#ifndef UNIX
+/*
+ See ckcpro.w. In UNIX we don't use temp files any more -- we pipe the
+ stuff right into mail or lpr.
+*/
+ if (c == 'M') { /* Mail to user. */
+ rc = zmail(p,filnam); /* Do the system's mail command */
+ if (rc < 0) success = 0; /* Remember status */
+ tlog(F110,"mailed",filnam,0L);
+ tlog(F110," to",p,0L);
+ zdelet(filnam); /* Delete the file */
+ } else if (c == 'P') { /* Print the file. */
+ rc = zprint(p,filnam); /* Do the system's print command */
+ if (rc < 0) success = 0; /* Remember status */
+ tlog(F110,"printed",filnam,0L);
+ tlog(F110," with options",p,0L);
+#ifndef VMS
+#ifndef STRATUS
+ /* spooler deletes file after print complete in VOS & VMS */
+ if (zdelet(filnam) && rc == 0) rc = 3; /* Delete the file */
+#endif /* STRATUS */
+#endif /* VMS */
+ }
+#endif /* UNIX */
+ }
+#endif /* NOFRILLS */
+
+ if (success &&
+ !pipesend &&
+ !calibrate && c != 'M' && c != 'P') {
+ if (rcv_move) { /* If /MOVE-TO was given... */
+ char * p = rcv_move;
+#ifdef COMMENT
+/* No need for this - it's a directory name */
+ char tmpbuf[CKMAXPATH+1];
+ extern int cmd_quoting; /* for \v(filename) */
+ if (cmd_quoting) { /* But only if cmd_quoting is on */
+ int n;
+ n = CKMAXPATH;
+ p = tmpbuf;
+ debug(F111,"reof /move-to",rcv_move,0);
+ zzstring(rcv_move,&p,&n);
+ p = tmpbuf;
+ }
+#endif /* COMMENT */
+/*
+ Here we could create the directory if it didn't exist (and it was relative)
+ but there would have to be a user-settable option to say whether to do this.
+*/
+ rc = zrename(filnam,p);
+ debug(F111,"reof MOVE zrename",rcv_move,rc);
+ if (rc > -1) {
+ tlog(F110," moving received file to",rcv_move,0);
+ } else {
+ rc = -4;
+ tlog(F110," FAILED to move received file to",rcv_move,0);
+ }
+ } else if (rcv_rename) { /* Or /RENAME-TO: */
+ char *s = rcv_rename; /* This is the renaming string */
+#ifndef NOSPL
+ char tmpnam[CKMAXPATH+16];
+ extern int cmd_quoting; /* for \v(filename) */
+ if (cmd_quoting) { /* But only if cmd_quoting is on */
+ int n; /* Pass it thru the evaluator */
+ n = CKMAXPATH;
+ s = (char *)tmpnam;
+ zzstring(rcv_rename,&s,&n);
+ s = (char *)tmpnam;
+ }
+#endif /* NOSPL */
+ if (s) if (*s) {
+ rc = zrename(filnam,s);
+ debug(F111,"reof RENAME zrename",s,rc);
+ if (rc > -1) {
+ tlog(F110," renaming received file to",s,0);
+ } else {
+ rc = -5;
+ tlog(F110," FAILED to rename received file to",s,0);
+ }
+ }
+ }
+ }
+ }
+ debug(F101,"reof success","",success);
+ debug(F101,"reof returns","",rc);
+
+ filnam[0] = NUL; /* Erase the filename */
+ return(rc);
+}
+
+/* R E O T -- Receive End Of Transaction */
+
+VOID
+reot() {
+ cxseen = czseen = discard = 0; /* Reset interruption flags */
+ tstats(); /* Finalize transfer statistics */
+}
+
+/* S F I L E -- Send File header or teXt header packet */
+
+/*
+ Call with x nonzero for X packet, zero for F packet.
+ If X == 0, filename to send is in filnam[], and if cmarg2 is not null
+ or empty, the file should be sent under this name rather than filnam[].
+ If sndfilter not NULL, it is the name of a send filter.
+ Returns 1 on success, 0 on failure.
+*/
+int
+sfile(x) int x; {
+#ifdef pdp11
+#define PKTNL 64
+#else
+#define PKTNL 256
+#endif /* pdp11 */
+ char pktnam[PKTNL+1]; /* Local copy of name */
+ char *s;
+ int rc;
+ int notafile = 0;
+ extern int filepeek;
+#ifdef PIPESEND
+ extern char * sndfilter;
+
+ if (sndfilter) {
+ pipesend = 1;
+ debug(F110,"sfile send filter ",sndfilter,0);
+ }
+#endif /* PIPESEND */
+
+ notafile = calibrate || sndarray || pipesend || x;
+ debug(F101,"sfile x","",x);
+ debug(F101,"sfile notafile","",notafile);
+
+#ifndef NOCSETS
+ if (tcs_save > -1) { /* Character sets */
+ tcharset = tcs_save;
+ tcs_save = -1;
+ debug(F101,"sfile restored tcharset","",tcharset);
+ }
+ if (fcs_save > -1) {
+ fcharset = fcs_save;
+ fcs_save = -1;
+ debug(F101,"sfile restored fcharset","",fcharset);
+ }
+ setxlatype(tcharset,fcharset); /* Translation type */
+#endif /* NOCSETS */
+
+ /* cmarg2 or filnam (with that precedence) have the file's name */
+
+ lsstate = 0; /* Cancel locking-shift state */
+#ifdef COMMENT
+ /* Do this after making sure we can open the file */
+ if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
+#endif /* COMMENT */
+ pktnam[0] = NUL; /* Buffer for name we will send */
+ if (x == 0) { /* F-Packet setup */
+ if (!cmarg2) cmarg2 = "";
+#ifdef DEBUG
+ if (deblog) {
+ /* debug(F111,"sfile cmarg2",cmarg2,cmarg2); */
+ debug(F101,"sfile binary 1","",binary);
+ debug(F101,"sfile wearealike","",wearealike);
+ debug(F101,"sfile xfermode","",xfermode);
+ debug(F101,"sfile filepeek","",filepeek);
+#ifndef NOCSETS
+ debug(F101,"sfile s_cset","",s_cset);
+ debug(F101,"sfile tcharset","",tcharset);
+ debug(F101,"sfile xfrxla","",xfrxla);
+#endif /* NOCSETS */
+ }
+#endif /* DEBUG */
+ if (xfermode == XMODE_A /* TRANSFER MODE AUTOMATIC */
+#ifndef NOMSEND
+ && !addlist /* And not working from a SEND-LIST */
+#endif /* NOMSEND */
+ ) {
+ /* Other Kermit is on a like system and no charset translation */
+ if (wearealike
+#ifndef NOCSETS
+ && (tcharset == TC_TRANSP || xfrxla == 0)
+#endif /* NOCSETS */
+ ) {
+#ifdef VMS
+ if (binary != XYFT_I)
+#endif /* VMS */
+#ifdef CK_LABELED
+ if (binary != XYFT_L)
+#endif /* CK_LABELED */
+ binary = XYFT_B; /* Send all files in binary mode */
+ }
+
+ /* Otherwise select transfer mode based on file info */
+
+ else if (!notafile /* but not if sending from pipe */
+#ifdef CK_LABELED
+ && binary != XYFT_L /* and not if FILE TYPE LABELED */
+#endif /* CK_LABELED */
+#ifdef VMS
+ && binary != XYFT_I /* or FILE TYPE IMAGE */
+#endif /* VMS */
+ ) {
+#ifdef UNICODE
+ fileorder = -1; /* File byte order */
+#endif /* UNICODE */
+ if (filepeek && !notafile) { /* Real file, FILE SCAN is ON */
+ int k, x;
+ k = scanfile(filnam,&x,nscanfile); /* Scan the file */
+ debug(F101,"sfile scanfile","",k);
+ switch (k) {
+ case FT_TEXT: /* Unspecified text */
+ debug(F100,"sfile scanfile text","",0);
+ binary = XYFT_T; /* SET FILE TYPE TEXT */
+ break;
+#ifndef NOCSETS
+ case FT_7BIT: /* 7-bit text */
+ binary = XYFT_T; /* SET FILE TYPE TEXT */
+ /* If SEND CHARSET-SELECTION AUTO */
+ /* and SET TRANSFER TRANSLATION is ON */
+ debug(F100,"sfile scanfile text7","",0);
+ if (s_cset == XMODE_A && xfrxla) {
+ if (fcsinfo[fcharset].size != 128) {
+ fcs_save = fcharset; /* Current FCS not 7bit */
+ fcharset = dcset7; /* Use default 7bit set */
+ debug(F101,"sfile scanfile 7 fcharset",
+ "",fcharset);
+ }
+ /* And also switch to appropriate TCS */
+ if (afcset[fcharset] > -1 &&
+ afcset[fcharset] <= MAXTCSETS) {
+ tcs_save = tcharset;
+ tcharset = afcset[fcharset];
+ debug(F101,"sfile scanfile 7 tcharset","",
+ tcharset);
+ }
+ setxlatype(tcharset,fcharset);
+ }
+ break;
+
+ case FT_8BIT: /* 8-bit text */
+ binary = XYFT_T; /* SET FILE TYPE TEXT */
+ /* If SEND CHARSET-SELEC AUTO */
+ /* and SET TRANSFER TRANSLATION is ON */
+ debug(F100,"sfile scanfile text8","",0);
+ if (s_cset == XMODE_A && xfrxla) {
+ if (fcsinfo[fcharset].size != 256) {
+ fcs_save = fcharset; /* Current FCS not 8bit */
+ fcharset = dcset8; /* Use default 8bit set */
+ debug(F101,"sfile scanfile 8 fcharset",
+ "",fcharset);
+ }
+ /* Switch to corresponding transfer charset */
+ if (afcset[fcharset] > -1 &&
+ afcset[fcharset] <= MAXTCSETS) {
+ tcs_save = tcharset;
+ tcharset = afcset[fcharset];
+ debug(F101,"sfile scanfile 8 tcharset","",
+ tcharset);
+ }
+ setxlatype(tcharset,fcharset);
+ }
+ break;
+#ifdef UNICODE
+ case FT_UTF8: /* UTF-8 text */
+ case FT_UCS2: /* UCS-2 text */
+ debug(F101,"sfile scanfile Unicode","",k);
+ binary = XYFT_T;
+ /* If SEND CHARSET-SELEC AUTO */
+ /* and SET TRANSFER TRANSLATION is ON */
+ if (s_cset == XMODE_A && xfrxla) {
+ fcs_save = fcharset;
+ tcs_save = tcharset;
+ fcharset = (k == FT_UCS2) ? FC_UCS2 : FC_UTF8;
+ if (k == FT_UCS2 && x > -1)
+ fileorder = x;
+ }
+ /* Switch to associated transfer charset if any */
+ if (afcset[fcharset] > -1 &&
+ afcset[fcharset] <= MAXTCSETS)
+ tcharset = afcset[fcharset];
+ if (tcharset == TC_TRANSP) /* If none */
+ tcharset = TC_UTF8; /* use UTF-8 */
+ setxlatype(tcharset,fcharset);
+ debug(F101,"sfile Unicode tcharset","",tcharset);
+ break;
+#endif /* UNICODE */
+#endif /* NOCSETS */
+ case FT_BIN:
+ debug(F101,"sfile scanfile binary","",k);
+ binary = XYFT_B;
+ break;
+ /* Default: Don't change anything */
+ }
+ }
+ }
+ debug(F101,"sfile binary 2","",binary);
+ debug(F101,"sfile sendmode","",sendmode);
+ }
+ if (*cmarg2) { /* If we have a send-as name... */
+ int y; char *s;
+#ifndef NOSPL /* and a script programming language */
+ extern int cmd_quoting;
+ if (cmd_quoting) { /* and it's not turned off */
+ y = PKTNL; /* pass as-name thru the evaluator */
+ s = pktnam;
+ zzstring(cmarg2,&s,&y);
+#ifdef COMMENT
+/* This ruins macros like BSEND */
+ if (!pktnam[0]) /* and make sure result is not empty */
+ sprintf(pktnam,"FILE%02ld",filcnt);
+#endif /* COMMENT */
+ } else
+#endif /* NOSPL */
+ ckstrncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
+
+ debug(F110,"sfile pktnam",pktnam,0);
+#ifdef COMMENT
+/* We don't do this any more because now we have filename templates */
+ cmarg2 = ""; /* and blank it out for next time. */
+#endif /* COMMENT */
+ }
+ if (!*pktnam) { /* No as-name... */
+#ifdef NZLTOR
+ int xfncnv, xpath;
+ debug(F101,"sfile fnspath","",fnspath);
+ debug(F101,"sfile fncnv","",fncnv);
+ xfncnv = fncnv;
+ xpath = fnspath;
+ if (notafile) { /* If not an actual file */
+ xfncnv = 0; /* Don't convert name */
+ xpath = PATH_OFF; /* Leave path off */
+ } else if (xfncnv &&
+ (!strcmp(whoareu,"U1") || !strcmp(whoareu,"UN"))
+ ) {
+ /* Less-strict conversion if partner is UNIX or Win32 */
+ xfncnv = -1;
+ }
+ debug(F101,"sfile xpath","",xpath);
+ debug(F101,"sfile xfncnv","",xfncnv);
+ nzltor(filnam,pktnam,xfncnv,xpath,PKTNL);
+
+#else /* Not NZLTOR */
+
+ debug(F101,"sfile fnspath","",fnspath);
+ if (fnspath == PATH_OFF /* Stripping path names? */
+ && (!notafile) /* (of actual files) */
+ ) {
+ char *t; /* Yes. */
+ zstrip(filnam,&t); /* Strip off the path. */
+ debug(F110,"sfile zstrip",t,0);
+ if (!t) t = "UNKNOWN"; /* Be cautious... */
+ else if (*t == '\0')
+ t = "UNKNOWN";
+ ckstrncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
+ } else if (fnspath == PATH_ABS && !notafile) {
+ /* Converting to absolute form */
+ zfnqfp(filnam,PKTNL,pktnam);
+ } else
+ ckstrncpy(pktnam,filnam,PKTNL);
+
+ /* pktnam[] has the packet name, filnam[] has the original name. */
+ /* But we still need to convert pktnam if FILE NAMES CONVERTED. */
+
+ debug(F101,"sfile fncnv","",fncnv);
+ if (fncnv && !notafile) { /* If converting names of files */
+ zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
+ ckstrncpy(pktnam,(char *)srvcmd,PKTNL);
+ *srvcmd = NUL;
+ }
+#endif /* NZLTOR */
+ }
+ if (!*pktnam) /* Failsafe... */
+ sprintf(pktnam,"FILE%02ld",filcnt);
+ debug(F110,"sfile filnam 1",filnam,0);
+ debug(F110,"sfile pktnam 1",pktnam,0);
+#ifdef PIPESEND
+/* If we have a send filter, substitute the current filename into it */
+
+ if (sndfilter) {
+ char * p = NULL, * q;
+ int n = CKMAXPATH;
+#ifndef NOSPL
+ if ((p = (char *) malloc(n + 1))) {
+ q = p;
+ debug(F110,"sfile pipesend filter",sndfilter,0);
+ zzstring(sndfilter,&p,&n);
+ debug(F111,"sfile pipename",q,n);
+ if (n <= 0) {
+ printf(
+ "?Sorry, send filter + filename too long, %d max.\n",
+ CKMAXPATH
+ );
+ free(q);
+ return(0);
+ }
+ ckstrncpy(filnam,q,CKMAXPATH+1);
+ free(q);
+ }
+#endif /* NOSPL */
+ }
+#endif /* PIPESEND */
+
+ debug(F110,"sfile filnam 2",filnam,0); /* Log debugging info */
+ debug(F110,"sfile pktnam 2",pktnam,0);
+ if (openi(filnam) == 0) /* Try to open the input file */
+ return(0);
+
+#ifdef CK_RESEND
+/*
+ The following check is done after openi() is called, since openi() itself
+ can change the transfer mode (as in VMS).
+*/
+ if ((binary == XYFT_T
+#ifdef VMS
+ || binary == XYFT_L
+#endif /* VMS */
+ ) && sendmode == SM_RESEND) {
+ /* Trying to RESEND/REGET a file first sent in TEXT mode. */
+ debug(F111,"sfile error - Recover vs Text",filnam,binary);
+ /* Set appropriate error messages and make log entries here */
+#ifdef VMS
+ if (binary == XYFT_L)
+ ckmakmsg((char *)epktmsg,
+ PKTMSGLEN,
+ "Recovery attempted in LABELED mode: ",
+ filnam,
+ NULL,
+ NULL
+ );
+ else
+#endif /* VMS */
+ ckmakmsg((char *)epktmsg,
+ PKTMSGLEN,
+ "Recovery attempted in TEXT mode: ",
+ filnam,
+ NULL,
+ NULL
+ );
+ return(0);
+ }
+ if (sendmode == SM_PSEND) /* PSENDing? */
+ if (sendstart > (CK_OFF_T)0) /* Starting position */
+ if (zfseek(sendstart) < 0) /* seek to it... */
+ return(0);
+#endif /* CK_RESEND */
+ s = pktnam; /* Name for packet data field */
+#ifdef OS2
+ /* Never send a disk letter. */
+ if (isalpha(*s) && (*(s+1) == ':'))
+ s += 2;
+#endif /* OS2 */
+
+ } else { /* X-packet setup, not F-packet. */
+ binary = XYFT_T; /* Text always */
+ debug(F110,"sfile X packet",cmdstr,0); /* Log debugging info */
+ s = cmdstr; /* Name for data field */
+ }
+
+ /* Now s points to the string that goes in the packet data field. */
+
+ debug(F101,"sfile binary","",binary); /* Log debugging info */
+ encstr((CHAR *)s); /* Encode the name. */
+ /* Send the F or X packet */
+ /* If the encoded string did not fit into the packet, it was truncated. */
+
+ if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
+
+ rc = spack((char) (x ? 'X' : 'F'), pktnum, size, data);
+ if (rc < 0)
+ return(rc);
+
+#ifndef NOCSETS
+ setxlatype(tcharset,fcharset); /* Set up charset translations */
+#endif /* NOCSETS */
+
+ if (x == 0) { /* Display for F packet */
+ if (displa) { /* Screen */
+ xxscreen(SCR_FN,'F',(long)pktnum,filnam);
+ xxscreen(SCR_AN,0,0L,pktnam);
+ xxscreen(SCR_FS,0,calibrate ? calibrate : fsize,"");
+ }
+#ifdef pdp11
+ tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
+ makestr(&psfspec,filnam); /* New filename */
+#else
+#ifndef ZFNQFP
+ tlog(F110,"Sending",filnam,0L);
+ makestr(&psfspec,filnam); /* New filename */
+#else
+ if (notafile) { /* If not a file log simple name */
+ tlog(F110,"Sending", filnam, 0L);
+ } else { /* Log fully qualified filename */
+#ifdef COMMENT
+ /* This section generates bad code in SCO 3.2v5.0.5's cc */
+ char *p = NULL, *q = filnam;
+ debug(F101,"sfile CKMAXPATH","",CKMAXPATH);
+ if ((p = malloc(CKMAXPATH+1))) {
+ debug(F111,"sfile calling zfnqfp",filnam,strlen(filnam));
+ if (zfnqfp(filnam, CKMAXPATH, p)) {
+ debug(F111,"sfile zfnqfp ok",p,strlen(p));
+ q = p;
+ }
+ }
+#else
+ char tmpbuf[CKMAXPATH+1];
+ char *p = tmpbuf, *q = filnam;
+ if (zfnqfp(filnam, CKMAXPATH, p))
+ q = p;
+#endif /* COMMENT */
+ debug(F111,"sfile q",q,strlen(q));
+ tlog(F110,"Sending",q,0L);
+ makestr(&psfspec,q); /* New preliminary filename */
+#ifdef COMMENT
+ if (p) free(p);
+#endif /* COMMENT */
+ }
+#endif /* ZFNQFP */
+#endif /* pdp11 */
+ tlog(F110," as",pktnam,0L);
+ if (binary) { /* Log file mode in transaction log */
+ tlog(F101," mode: binary","",(long) binary);
+ } else { /* If text mode, check character set */
+ tlog(F100," mode: text","",0L);
+#ifndef NOCSETS
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ tlog(F110," character set","transparent",0L);
+ } else {
+ tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
+ tlog(F110," file character set",fcsinfo[fcharset].name,0L);
+ }
+#endif /* NOCSETS */
+ }
+ } else { /* Display for X-packet */
+
+ xxscreen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
+ tlog(F110,"Sending from:",cmdstr,0L); /* Transaction log */
+ }
+ intmsg(++filcnt); /* Count file, give interrupt msg */
+ first = 1; /* Init file character lookahead. */
+ ffc = (CK_OFF_T)0; /* Init file character counter. */
+ cps = oldcps = 0L; /* Init cps statistics */
+ rejection = -1;
+ fsecs = gtimer(); /* Time this file started */
+#ifdef GFTIMER
+ fpfsecs = gftimer();
+ debug(F101,"SFILE fpfsecs","",fpfsecs);
+#endif /* GFTIMER */
+ debug(F101,"SFILE fsecs","",fsecs);
+ return(1);
+}
+
+/* S D A T A -- Send a data packet */
+
+/*
+ Returns -1 if no data to send (end of file), -2 if connection is broken.
+ If there is data, a data packet is sent, and sdata() returns 1.
+
+ In the streaming case, the window is regarded as infinite and we keep
+ sending data packets until EOF or there appears to be a Kermit packet on the
+ reverse channel. When not streaming and the window size is greater than 1,
+ we keep sending data packets until window is full or characters start to
+ appear from the other Kermit.
+
+ In the windowing or streaming case, when there is no more data left to send
+ (or when sending has been interrupted), sdata() does nothing and returns 0
+ each time it is called until the acknowledgement sequence number catches up
+ to the last data packet that was sent.
+*/
+int
+sdata() {
+ int i, x, len;
+ char * s;
+
+ debug(F101,"sdata entry, first","",first);
+ debug(F101,"sdata drain","",drain);
+/*
+ The "drain" flag is used with window size > 1. It means we have sent
+ our last data packet. If called and drain is not zero, then we return
+ 0 as if we had sent an empty data packet, until all data packets have
+ been ACK'd, then then we can finally return -1 indicating EOF, so that
+ the protocol can switch to seof state. This is a kludge, but at least
+ it's localized...
+*/
+ if (first == 1) drain = 0; /* Start of file, init drain flag. */
+
+ if (drain) { /* If draining... */
+ debug(F101,"sdata draining, winlo","",winlo);
+ if (winlo == pktnum) /* If all data packets are ACK'd */
+ return(-1); /* return EOF indication */
+ else /* otherwise */
+ return(0); /* pretend we sent a data packet. */
+ }
+ debug(F101,"sdata sbufnum","",sbufnum);
+ for (i = sbufnum;
+ i > 0
+#ifdef STREAMING
+ || streaming
+#endif /* STREAMING */
+ ;
+ i--) {
+ if (i < 0)
+ break;
+ debug(F101,"sdata countdown","",i);
+#ifdef STREAMING
+ if (streaming) {
+ pktnum = (pktnum + 1) % 64;
+ winlo = pktnum;
+ debug(F101,"sdata streaming pktnum","",pktnum);
+ } else {
+#endif /* STREAMING */
+ x = nxtpkt(); /* Get next pkt number and buffer */
+ debug(F101,"sdata nxtpkt pktnum","",pktnum);
+ if (x < 0) return(0);
+#ifdef STREAMING
+ }
+#endif /* STREAMING */
+ debug(F101,"sdata packet","",pktnum);
+ if (chkint() < 0) /* Especially important if streaming */
+ return(-9);
+ if (cxseen || czseen) { /* If interrupted, done. */
+ if (wslots > 1) {
+ drain = 1;
+ debug(F100,"sdata cx/zseen windowing","",0);
+ return(0);
+ } else {
+ debug(F100,"sdata cx/zseen nonwindowing","",0);
+ return(-1);
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"sdata spsiz","",spsiz);
+ debug(F101,"sdata binary","",binary);
+ debug(F101,"sdata parity","",parity);
+ }
+#endif /* DEBUG */
+#ifdef CKTUNING
+ if (binary && !parity && !memstr && !funcstr)
+ len = bgetpkt(spsiz);
+ else
+ len = getpkt(spsiz,1);
+#else
+ len = getpkt(spsiz,1);
+#endif /* CKTUNING */
+ s = (char *)data;
+ if (len == -3) { /* Timed out (e.g.reading from pipe) */
+ s = ""; /* Send an empty data packet. */
+ len = 0;
+ } else if (len == 0) { /* Done if no data. */
+ if (pktnum == winlo)
+ return(-1);
+ drain = 1; /* But can't return -1 until all */
+ debug(F101,"sdata eof, drain","",drain);
+ return(0); /* ACKs are drained. */
+ }
+ debug(F101,"sdata pktnum","",pktnum);
+ debug(F101,"sdata len","",len);
+ debug(F011,"sdata data",data,52);
+
+ x = spack('D',pktnum,len,(CHAR *)s); /* Send the data packet. */
+ debug(F101,"sdata spack","",x);
+ if (x < 0) { /* Error */
+ ttchk(); /* See if connection is still there */
+ return(-2);
+ }
+#ifdef STREAMING
+ if (streaming) /* What an ACK would do. */
+ winlo = pktnum;
+#endif /* STREAMING */
+ x = ttchk(); /* Peek at input buffer. */
+ debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe? */
+ if (x < 0) /* Or connection broken? */
+ return(-2);
+/*
+ Here we check to see if any ACKs or NAKs have arrived, in which case we
+ break out of the D-packet-sending loop and return to the state switcher
+ to process them. This is what makes our windows slide instead of lurch.
+*/
+ if (
+#ifdef GEMDOS
+/*
+ In the Atari ST version, ttchk() can only return 0 or 1. But note: x will
+ probably always be > 0, since the as-yet-unread packet terminator from the
+ last packet is probably still in the buffer, so sliding windows will
+ probably never happen when the Atari ST is the file sender. The alternative
+ is to say "if (0)", in which case the ST will always send a window full of
+ packets before reading any ACKs or NAKs.
+*/
+ x > 0
+
+#else /* !GEMDOS */
+/*
+ In most other versions, ttchk() returns the actual count.
+ It can't be a Kermit packet if it's less than five bytes long.
+*/
+ x > 4 + bctu
+
+#endif /* GEMDOS */
+ )
+ return(1); /* Yes, stop sending data packets */
+ } /* and go try to read the ACKs. */
+ return(1);
+}
+
+
+/* S E O F -- Send an End-Of-File packet */
+
+/* Call with a string pointer to character to put in the data field, */
+/* or else a null pointer or "" for no data. */
+
+/*
+ There are two "send-eof" functions. seof() is used to send the normal eof
+ packet at the end of a file's data (even if the file has no data), or when
+ a file transfer is interrupted. sxeof() is used to send an EOF packet that
+ occurs because of attribute refusal or interruption prior to entering data
+ state. The difference is purely a matter of buffer allocation and packet
+ sequence number management. Both functions act as "front ends" to the
+ common send-eof function, szeof().
+*/
+
+/* Code common to both seof() and sxeof() */
+
+int
+szeof(s) CHAR *s; {
+ int x;
+ lsstate = 0; /* Cancel locking-shift state */
+ if (!s) s = (CHAR *)"";
+ debug(F111,"szeof",s,pktnum);
+ if (*s) {
+ x = spack('Z',pktnum,1,s);
+ xitsta |= W_SEND;
+#ifdef COMMENT
+ tlog(F100," *** interrupted, sending discard request","",0L);
+#endif /* COMMENT */
+ filrej++;
+ } else {
+ x = spack('Z',pktnum,0,(CHAR *)"");
+ }
+ if (x < 0)
+ return(x);
+
+#ifdef COMMENT
+ /* No, too soon */
+ discard = 0; /* Turn off per-file discard flag */
+#endif /* COMMENT */
+
+/* If we were sending from a pipe, we're not any more... */
+ pipesend = 0;
+ return(0);
+}
+
+int
+seof(x) int x; {
+ char * s;
+/*
+ ckcpro.w, before calling seof(), sets window size back to 1 and then calls
+ window(), which clears out the old buffers. This is OK because the final
+ data packet for the file has been ACK'd. However, sdata() has already
+ called nxtpkt(), which set the new value of pktnum which seof() will use.
+ So all we need to do here is is allocate a new send-buffer.
+*/
+ s = x ? "D" : "";
+ debug(F111,"seof",s,pktnum);
+ if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */
+ debug(F101,"seof can't get s-buffer","",pktnum);
+ return(-1);
+ }
+ return(szeof((CHAR *)s));
+}
+
+/*
+ Version of seof() to be called when sdata() has not been called before. The
+ difference is that this version calls nxtpkt() to allocate a send-buffer and
+ get the next packet number.
+*/
+int
+sxeof(x) int x; {
+ char * s;
+ s = x ? "D" : "";
+ if (nxtpkt() < 0) /* Get next pkt number and buffer */
+ debug(F101,"sxeof nxtpkt fails","",pktnum);
+ else
+ debug(F101,"sxeof packet","",pktnum);
+ return(szeof((CHAR *)s));
+}
+
+/* S E O T -- Send an End-Of-Transaction packet */
+
+int
+seot() {
+ int x;
+ x = nxtpkt();
+ debug(F101,"seot nxtpkt","",x);
+ if (x < 0) return(-1); /* Bump packet number, get buffer */
+ x = spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */
+ if (x < 0)
+ return(x);
+ cxseen = czseen = discard = 0; /* Reset interruption flags */
+ tstats(); /* Log timing info */
+ return(0);
+}
+
+
+/* R P A R -- Fill the data array with my send-init parameters */
+
+int q8flag = 0;
+
+CHAR dada[32]; /* Use this instead of data[]. */
+ /* To avoid some kind of wierd */
+ /* addressing foulup in spack()... */
+ /* (which might be fixed now...) */
+
+CHAR *
+rpar() {
+ char *p;
+ int i, x, max;
+ extern int sprmlen;
+
+ max = maxdata(); /* Biggest data field I can send */
+ debug(F101, "rpar max 1","",max);
+ debug(F101, "rpar sprmlen","",sprmlen);
+ if (sprmlen > 1 && sprmlen < max) /* User override */
+ max = sprmlen;
+ debug(F101, "rpar max 2","",max);
+
+ if (rpsiz > MAXPACK) /* Biggest normal packet I want. */
+ dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */
+ else /* extended packet length below... */
+ dada[0] = (char) tochar(rpsiz); /* else use what the user said. */
+ dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
+ dada[2] = (char) tochar(mypadn); /* How much padding I need (none) */
+ dada[3] = (char) ctl(mypadc); /* Padding character I want */
+ dada[4] = (char) tochar(eol); /* End-Of-Line character I want */
+ dada[5] = myctlq; /* Control-Quote character I send */
+
+ if (max < 6) { dada[6] = NUL; rqf = 0; ebq = sq = NUL; return(dada); }
+
+ switch (rqf) { /* 8th-bit prefix (single-shift) */
+ case -1: /* I'm opening the bids */
+ case 1: /* Other Kermit already bid 'Y' */
+ if (parity) ebq = sq = MYEBQ; /* So I reply with '&' if parity */
+ break; /* otherwise with 'Y'. */
+ case 2: /* Other Kermit sent a valid prefix */
+ if (q8flag)
+ sq = ebq; /* Fall through on purpose */
+ case 0: /* Other Kermit bid nothing */
+ break; /* So I reply with 'Y'. */
+ }
+ debug(F000,"rpar 8bq sq","",sq);
+ debug(F000,"rpar 8bq ebq","",ebq);
+ if (lscapu == 2) /* LOCKING-SHIFT FORCED */
+ dada[6] = 'N'; /* requires no single-shift */
+ else /* otherwise send prefix or 'Y' */
+ dada[6] = (char) sq;
+ ebqsent = dada[6]; /* And remember what I really sent */
+
+ if (max < 7) { dada[7] = NUL; bctr = 1; return(dada); }
+
+ dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
+
+ if (max < 8) { dada[8] = NUL; rptflg = 0; return(dada); }
+
+ if (rptena) {
+ if (rptflg) /* Run length encoding */
+ dada[8] = (char) rptq; /* If receiving, agree */
+ else /* by replying with same character. */
+ dada[8] = (char) (rptq = myrptq); /* When sending use this. */
+ } else dada[8] = SP; /* Not enabled, put a space here. */
+
+ /* CAPAS mask */
+
+ if (max < 9) {
+ dada[9] = NUL;
+ atcapr = 0;
+ lpcapr = 0;
+ swcapr = 0;
+ rscapr = 0;
+ return(dada);
+ }
+ dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
+ (atcapr ? atcapb : 0) | /* Attribute packets */
+ (lpcapr ? lpcapb : 0) | /* Long packets */
+ (swcapr ? swcapb : 0) | /* Sliding windows */
+ (rscapr ? rscapb : 0)); /* RESEND */
+ if (max < 10) { wslotr = 1; return(dada); }
+ dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
+
+ if (max < 12) { rpsiz = 80; return(dada); }
+ if (urpsiz > 94)
+ rpsiz = urpsiz - 1; /* Long packets ... */
+ dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
+ dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
+
+ if (max < 16) return(dada);
+ dada[13] = '0'; /* CAPAS+4 = WONT CHKPNT */
+ dada[14] = '_'; /* CAPAS+5 = CHKINT (reserved) */
+ dada[15] = '_'; /* CAPAS+6 = CHKINT (reserved) */
+ dada[16] = '_'; /* CAPAS+7 = CHKINT (reserved) */
+ if (max < 17) return(dada);
+#ifndef WHATAMI
+ dada[17] = ' ';
+#else
+ x = 0;
+ if (server) x |= WMI_SERVE; /* Whether I am a server */
+ if (binary) x |= WMI_FMODE; /* My file transfer mode is ... */
+ if (fncnv) x |= WMI_FNAME; /* My filename conversion is ... */
+#ifdef STREAMING
+ if (streamrq == SET_ON)
+ x |= WMI_STREAM;
+ else if (streamrq == SET_AUTO && reliable == SET_ON)
+ x |= WMI_STREAM;
+ /*
+ Always offer to stream when in remote mode and STREAMING is AUTO
+ and RELIABLE is not OFF (i.e. is ON or AUTO).
+ */
+ else if (!local && streamrq == SET_AUTO && reliable != SET_OFF)
+ x |= WMI_STREAM;
+#endif /* STREAMING */
+#ifdef TCPSOCKET
+ if (clearrq == SET_ON)
+ x |= WMI_CLEAR;
+ else if (clearrq == SET_AUTO && /* SET CLEAR-CHANNEL AUTO */
+ ((network && nettype == NET_TCPB /* TCP/IP */
+#ifdef RLOGCODE
+ && ttnproto != NP_RLOGIN/* Rlogin is not clear */
+ && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
+#endif /* RLOGCODE */
+ )
+#ifdef SSHBUILTIN
+ || (network && nettype == NET_SSH)
+#endif /* SSHBUILTIN */
+#ifdef IKSD
+ || inserver /* We are IKSD */
+#endif /* IKSD */
+ ))
+ x |= WMI_CLEAR;
+#endif /* TCPSOCKET */
+ x |= WMI_FLAG;
+ dada[17] = (char) tochar(x);
+#endif /* WHATAMI */
+ i = 18; /* Position of next field */
+ p = cksysid; /* WHOAMI (my system ID) */
+ x = strlen(p);
+ if (max - i < x + 1) return(dada);
+ if (x > 0) {
+ dada[i++] = (char) tochar(x);
+ while (*p)
+ dada[i++] = *p++;
+ }
+
+ if (max < i+1) return(dada);
+#ifndef WHATAMI /* WHATAMI2 */
+ dada[i++] = ' ';
+#else
+ debug(F101,"rpar xfermode","",xfermode);
+ x = WMI2_FLAG; /* Is-Valid flag */
+ if (xfermode != XMODE_A) /* If TRANSFER MODE is MANUAL */
+ x |= WMI2_XMODE; /* set the XFERMODE bit */
+ if (recursive > 0) /* If this is a recursive transfer */
+ x |= WMI2_RECU; /* set the RECURSIVE bit */
+ dada[i++] = tochar(x);
+ debug(F101,"rpar whatami2","",x);
+#endif /* WHATAMI */
+
+ dada[i] = '\0'; /* Terminate the init string */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"rpar",dada,0);
+ rdebu(dada,(int)strlen((char *)dada));
+ }
+#endif /* DEBUG */
+ ckstrncpy((char *)myinit,(char *)dada,MYINITLEN);
+ return(dada); /* Return pointer to string. */
+}
+
+int
+spar(s) CHAR *s; { /* Set parameters */
+ int x, y, lpsiz, biggest;
+ extern int rprmlen, lastspmax;
+ extern struct sysdata sysidlist[];
+
+ whatru = 0;
+ whoareu[0] = NUL;
+#ifdef STREAMING
+ streamok = 0;
+ streaming = 0;
+#endif /* STREAMING */
+ biggest = rln;
+
+ debug(F101, "spar biggest 1","",biggest);
+ debug(F101, "spar rprmlen","",rprmlen);
+ if (rprmlen > 1 && rprmlen < biggest)
+ biggest = rprmlen;
+ debug(F101, "rpar biggest 2","",biggest);
+ debug(F110,"spar packet",s,0);
+
+ s--; /* Line up with field numbers. */
+
+/* Limit on size of outbound packets */
+ x = (biggest >= 1) ? xunchar(s[1]) : 80;
+ lpsiz = spsizr; /* Remember what they SET. */
+ if (spsizf) { /* SET-command override? */
+ if (x < spsizr) spsiz = x; /* Ignore LEN unless smaller */
+ } else { /* otherwise */
+ spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */
+ }
+ spmax = spsiz; /* Remember maximum size */
+
+/* Timeout on inbound packets */
+ if (timef) {
+ timint = rtimo; /* SET SEND TIMEOUT value overrides */
+ } else { /* Otherwise use requested value, */
+ x = (biggest >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
+ timint = (x < 0) ? rtimo : x;
+ }
+ timint = chktimo(timint,timef); /* Adjust if necessary */
+
+/* Outbound Padding */
+ npad = 0; padch = '\0';
+ if (biggest >= 3) {
+ npad = xunchar(s[3]);
+ if (biggest >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
+ }
+ if (npad) {
+ int i;
+ for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
+ }
+
+/* Outbound Packet Terminator */
+ seol = (CHAR) (biggest >= 5) ? xunchar(s[5]) : CR;
+ if ((seol < 1) || (seol > 31)) seol = CR;
+
+/* Control prefix that the other Kermit is sending */
+ x = (biggest >= 6) ? s[6] : '#';
+ ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
+
+/* 8th-bit prefix */
+/*
+ NOTE: Maybe this could be simplified using rcvtyp.
+ If rcvtyp == 'Y' then we're reading the ACK,
+ otherwise we're reading the other Kermit's initial bid.
+ But his horrendous code has been working OK for years, so...
+*/
+ rq = (biggest >= 7) ? s[7] : 0;
+ if (rq == 'Y') rqf = 1;
+ else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
+ else rqf = 0;
+ debug(F000,"spar 8bq rq","",rq);
+ debug(F000,"spar 8bq sq","",sq);
+ debug(F000,"spar 8bq ebq","",ebq);
+ debug(F101,"spar 8bq rqf","",rqf);
+ switch (rqf) {
+ case 0: /* Field is missing from packet. */
+ ebqflg = 0; /* So no 8th-bit prefixing. */
+ break;
+ case 1: /* Other Kermit sent 'Y' = Will Do. */
+ /*
+ When I am the file receiver, ebqsent is 0 because I didn't send a
+ negotiation yet. If my parity is set to anything other than NONE,
+ either because my user SET PARITY or because I detected parity bits
+ on this packet, I reply with '&', otherwise 'Y'.
+
+ When I am the file sender, ebqsent is what I just sent in rpar(),
+ which can be 'Y', 'N', or '&'. If I sent '&', then this 'Y' means
+ the other Kermit agrees to do 8th-bit prefixing.
+
+ If I sent 'Y' or 'N', but then detected parity on the ACK packet
+ that came back, then it's too late: there is no longer any way for
+ me to tell the other Kermit that I want to do 8th-bit prefixing, so
+ I must not do it, and in that case, if there is any 8-bit data in
+ the file to be transferred, the transfer will fail because of block
+ check errors.
+
+ The following clause covers all of these situations:
+ */
+ if (parity && (ebqsent == 0 || ebqsent == '&')) {
+ ebqflg = 1;
+ ebq = MYEBQ;
+ }
+ break;
+ case 2: /* Other Kermit sent a valid prefix */
+ ebqflg = (ebq == sq || sq == 'Y');
+ if (ebqflg) {
+ ebq = rq;
+ debug(F101,"spar setting parity to space","",ebq);
+ if (!parity) parity = ttprty = 's';
+ }
+ }
+ if (lscapu == 2) { /* But no single-shifts if LOCKING-SHIFT FORCED */
+ ebqflg = 0;
+ ebq = 'N';
+ }
+
+/* Block check */
+ x = 1;
+ if (biggest >= 8) {
+ if (s[8] == 'B') x = 4;
+ else x = s[8] - '0';
+ if ((x < 1) || (x > 5)) x = 1; /* "5" 20110605 */
+ }
+ bctr = x;
+
+/* Repeat prefix */
+
+ rptflg = 0; /* Assume no repeat-counts */
+ if (biggest >= 9) { /* Is there a repeat-count field? */
+ char t; /* Yes. */
+ t = s[9]; /* Get its contents. */
+/*
+ If I'm sending files, then I'm reading these parameters from an ACK, and so
+ this character must agree with what I sent.
+*/
+ if (rptena) { /* If enabled ... */
+ if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */
+ if (t == myrptq) rptflg = 1;
+ } else { /* I'm receiving files */
+ if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
+ rptflg = 1;
+ rptq = t;
+ }
+ }
+ } else rptflg = 0;
+ }
+
+/* Capabilities */
+
+ atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
+ if (lscapu != 2) lscapu = 0; /* Assume no LS unless forced. */
+ y = 11; /* Position of next field, if any */
+ if (biggest >= 10) {
+ x = xunchar(s[10]);
+ debug(F101,"spar capas","",x);
+ atcapu = (x & atcapb) && atcapr; /* Attributes */
+ lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
+ swcapu = (x & swcapb) && swcapr; /* Sliding windows */
+ rscapu = (x & rscapb) && rscapr; /* RESEND */
+ debug(F101,"spar lscapu","",lscapu);
+ debug(F101,"spar lscapr","",lscapr);
+ debug(F101,"spar ebqflg","",ebqflg);
+ if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
+ debug(F101,"spar swcapr","",swcapr);
+ debug(F101,"spar swcapu","",swcapu);
+ debug(F101,"spar lscapu","",lscapu);
+ for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++);
+ debug(F101,"spar y","",y);
+ }
+
+/* Long Packets */
+ debug(F101,"spar lpcapu","",lpcapu);
+ if (lpcapu) {
+ if (biggest > y+1) {
+ x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
+ debug(F101,"spar lp len","",x);
+ if (spsizf) { /* If overriding negotiations */
+ spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
+ } else { /* otherwise */
+ spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
+ }
+ if (spsiz < 10) spsiz = 80; /* Be defensive... */
+ }
+ }
+ /* (PWP) save current send packet size for optimal packet size calcs */
+ spmax = spsiz; /* Maximum negotiated length */
+ lastspmax = spsiz; /* For stats */
+ if (slostart && spsiz > 499) /* Slow start length */
+ spsiz = 244;
+ debug(F101,"spar slow-start spsiz","",spsiz);
+ debug(F101,"spar lp spmax","",spmax);
+ timint = chktimo(timint,timef); /* Recalculate the packet timeout */
+
+/* Sliding Windows... */
+
+ if (swcapr) { /* Only if requested... */
+ if (biggest > y) { /* See what other Kermit says */
+ x = xunchar(s[y+1]);
+ debug(F101,"spar window","",x);
+ wslotn = (x > MAXWS) ? MAXWS : x;
+/*
+ wslotn = negotiated size (from other Kermit's S or I packet).
+ wslotr = requested window size (from this Kermit's SET WINDOW command).
+*/
+ if (wslotn > wslotr) /* Use the smaller of the two */
+ wslotn = wslotr;
+ if (wslotn < 1) /* Watch out for bad negotiation */
+ wslotn = 1;
+ if (wslotn > 1) {
+ swcapu = 1; /* We do windows... */
+ if (wslotn > maxtry) /* Retry limit must be greater */
+ maxtry = wslotn + 1; /* than window size. */
+ }
+ debug(F101,"spar window after adjustment","",x);
+ } else { /* No window size specified. */
+ wslotn = 1; /* We don't do windows... */
+ debug(F101,"spar window","",x);
+ swcapu = 0;
+ debug(F101,"spar no windows","",wslotn);
+ }
+ }
+
+/* Now recalculate packet length based on number of windows. */
+/* The nogotiated number of window slots will be allocated, */
+/* and the maximum packet length will be reduced if necessary, */
+/* so that a windowful of packets can fit in the big buffer. */
+
+ if (wslotn > 1) { /* Shrink to fit... */
+ x = adjpkl(spmax,wslotn,bigsbsiz);
+ if (x < spmax) {
+ spmax = x;
+ lastspmax = spsiz;
+ if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
+ debug(F101,"spar sending, redefine spmax","",spmax);
+ }
+ }
+#ifdef WHATAMI
+ debug(F101,"spar biggest","",biggest);
+ if (biggest > y+7) { /* Get WHATAMI info if any */
+ whatru = xunchar(s[y+8]);
+ debug(F101,"spar whatru","",whatru);
+ }
+ if (whatru & WMI_FLAG) { /* Only valid if this bit is set */
+#ifdef STREAMING
+ if (whatru & WMI_STREAM) {
+ if (streamrq == SET_ON ||
+ (streamrq == SET_AUTO &&
+ (reliable == SET_ON || (reliable == SET_AUTO && !local)
+#ifdef TN_COMPORT
+ && !istncomport()
+#endif /* TN_COMPORT */
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ))) {
+ streamok = 1; /* Streaming negotiated */
+ slostart = 0; /* Undo slow-start machinations */
+ spsiz = lastspmax;
+ }
+ }
+ streamed = streamok;
+ debug(F101,"spar streamok","",streamok);
+ debug(F101,"spar clearrq","",clearrq);
+ if (clearrq == SET_ON ||
+ (clearrq == SET_AUTO &&
+ ((network && nettype == NET_TCPB
+#ifdef RLOGCODE
+ && ttnproto != NP_RLOGIN/* Rlogin is not clear */
+ && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN)
+#endif /* RLOGCODE */
+#ifdef TN_COMPORT
+ && !istncomport()
+#endif /* TN_COMPORT */
+ )
+#ifdef SSHBUILTIN
+ || (network && nettype == NET_SSH)
+#endif /* SSHBUILTIN */
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ )))
+ urclear = (whatru & WMI_CLEAR);
+ debug(F101,"spar urclear","",urclear);
+#ifdef CK_SPEED
+ if (urclear)
+ setprefix(PX_NON);
+#endif /* CK_SPEED */
+ cleared = urclear;
+#endif /* STREAMING */
+ }
+#endif /* WHATAMI */
+
+ if (biggest > y+8) { /* Get WHOAREYOU info if any */
+ int x, z;
+ x = xunchar(s[y+9]); /* Length of it */
+ z = y;
+ y += (9 + x);
+ debug(F101,"spar sysindex x","",x);
+ debug(F101,"spar sysindex y","",y);
+ debug(F101,"spar sysindex biggest","",biggest);
+
+ if (x > 0 && x < 16 && biggest >= y) {
+ strncpy(whoareu,(char *)s+z+10,x); /* Other Kermit's system ID */
+ debug(F111,"spar whoareyou",whoareu,whoareu[0]);
+ if (whoareu[0]) { /* Got one? */
+ sysindex = getsysix((char *)whoareu);
+ debug(F101,"spar sysindex",whoareu,sysindex);
+ }
+ }
+ } else
+ goto xspar;
+
+#ifdef WHATAMI
+ y++; /* Advance pointer */
+ if (biggest >= y) {
+ whatru2 = xunchar(s[y]); /* Next field is WHATAMI2 */
+ debug(F101,"spar whatru2","",whatru2);
+ if (whatru2 & WMI2_FLAG) { /* Valid only if this bit is set */
+ if (server) { /* Server obeys client's xfer mode */
+ xfermode = (whatru2 & WMI2_XMODE) ? XMODE_M : XMODE_A;
+ debug(F101,"spar whatru2 xfermode","",xfermode);
+ }
+ if (whatru2 & WMI2_RECU) { /* RECURSIVE transfer */
+ if (fnrpath == PATH_AUTO) { /* If REC PATH AUTO */
+ fnrpath = PATH_REL; /* Set it to RELATIVE */
+ autopath = 1; /* and remember we did this */
+ }
+ }
+ }
+ }
+#endif /* WHATAMI */
+
+ xspar:
+ if (sysindex > -1) {
+ char * p;
+ p = sysidlist[sysindex].sid_name;
+ tlog(F110,"Remote system type: ",p,0L);
+ if (sysindex > 0) { /* If partnet's system type known */
+ whoarewe(); /* see if we are a match. */
+#ifdef CK_SPEED
+/* Never unprefix XON and XOFF when sending to VMS */
+ debug(F111,"proto whoareu",whoareu,sysindex);
+ if (!strcmp((char *)whoareu,"D7")) {
+ debug(F111,"proto special VMS prefixing","",0);
+ ctlp[XON] = ctlp[XOFF] = 1;
+ ctlp[XON+128] = ctlp[XOFF+128] = 1;
+ ctlp[3] = 1; /* Ctrl-C might be dangerous too */
+ ctlp[14] = ctlp[15] = 1; /* And SO/SI */
+ ctlp[24] = ctlp[25] = 1; /* And ^X/^Y */
+ ctlp[141] = 1; /* And CR+128 */
+ }
+#endif /* CK_SPEED */
+ }
+ }
+
+/* Record parameters in debug log */
+#ifdef DEBUG
+ if (deblog) sdebu(biggest);
+#endif /* DEBUG */
+ numerrs = 0; /* Start counting errors here. */
+ return(0);
+}
+
+/* G N F I L E -- Get name of next file to send */
+/*
+ Expects global sndsrc to be:
+ -9: if we are generating a file internally for calibration.
+ -1: next filename to be obtained by calling znext().
+ 0: no next file name
+ 1: (or greater) next filename to be obtained from **cmlist,
+ or if addlist != 0, from the "filehead" linked list,
+ or if filefile pointer not null from that file (which is already open).
+ Returns:
+ 1, with name of next file in filnam.
+ 0, no more files, with filnam set to empty string.
+ -1, file not found
+ -2, file is not readable (but then we just skip to the next one if any)
+ -3, read access denied
+ -4, cancelled
+ -5, too many files match wildcard
+ -6, no files selected
+ NOTE:
+ If gnfile() returns 0, then the global variable gnferror should be checked
+ to find out the most recent gnfile() error, and use that instead of the
+ return code (for reasons to hard to explain).
+*/
+int
+gnfile() {
+ int i = 0, x = 0;
+ CK_OFF_T filesize = 0;
+ int dodirstoo = 0;
+ int retcode = 0;
+
+ char fullname[CKMAXPATH+1];
+
+ dodirstoo = ((what & (W_FTP|W_SEND)) == (W_FTP|W_SEND)) && recursive;
+
+ debug(F101,"gnfile sndsrc","",sndsrc);
+ debug(F101,"gnfile filcnt","",filcnt);
+ debug(F101,"gnfile what","",what);
+ debug(F101,"gnfile recursive","",recursive);
+ debug(F101,"gnfile dodirstoo","",dodirstoo);
+ gnferror = 0;
+ fsize = (CK_OFF_T)-1; /* Initialize file size */
+ fullname[0] = NUL;
+
+#ifdef VMS
+ /*
+ In VMS, zopeni() sets binary 0/1 automatically from the file
+ attributes. Don't undo it here.
+ */
+ debug(F101,"gnfile VMS binary","",binary);
+#else /* VMS */
+ if (!(what & W_REMO) && (xfermode == XMODE_A)
+#ifndef NOMSEND
+ && !addlist
+#endif /* NOMSEND */
+ ) {
+ extern int stdinf;
+ if (!stdinf) /* Not if sending from stdin */
+#ifdef WHATAMI
+ /* We don't do this in server mode because it undoes WHATAMI */
+ if (!server || (server && ((whatru & WMI_FLAG) == 0)))
+#endif /* WHATAMI */
+ binary = gnf_binary; /* Restore prevailing transfer mode */
+ debug(F101,"gnfile binary = gnf_binary","",gnf_binary);
+ }
+#endif /* VMS */
+
+#ifdef PIPESEND
+ debug(F101,"gnfile pipesend","",pipesend);
+ if (pipesend) { /* First one */
+ if (filcnt == 0) {
+ ckstrncpy(filnam,cmarg,CKMAXPATH+1);
+ return(1);
+ } else { /* There's only one... */
+ *filnam = NUL;
+ pipesend = 0;
+ return(0);
+ }
+ }
+#endif /* PIPESEND */
+
+#ifdef CALIBRATE
+ if (sndsrc == -9) {
+ debug(F100,"gnfile calibrate","",0);
+ ckstrncpy(filnam,"CALIBRATION",CKMAXPATH);
+ nfils = 0;
+ cal_j = 0;
+ fsize = calibrate;
+ sndsrc = 0; /* For next time */
+ nfils = 0;
+ return(1);
+ }
+#endif /* CALIBRATE */
+
+#ifndef NOSPL
+ if (sndarray) { /* Sending from an array */
+ extern char sndxnam[]; /* Pseudo filename */
+ debug(F100,"gnfile array","",0);
+ nfils = 0;
+ fsize = (CK_OFF_T)-1; /* Size unknown */
+ sndsrc = 0;
+ ckstrncpy(filnam,sndxnam,CKMAXPATH);
+ return(1);
+ }
+#endif /* NOSPL */
+
+ if (sndsrc == 0) { /* It's not really a file */
+ if (nfils > 0) { /* It's a pipe, or stdin */
+ ckstrncpy(filnam,*cmlist,CKMAXPATH+1); /* Copy its "name" */
+ nfils = 0; /* There is no next file */
+ return(1); /* OK this time */
+ } else return(0); /* but not next time */
+ }
+
+/* If file group interruption (C-Z) occurred, fail. */
+
+ if (czseen) {
+ tlog(F100,"Transaction cancelled","",0L);
+ debug(F100,"gnfile czseen","",0);
+ return(-4);
+ }
+
+/* Loop through file list till we find a readable, sendable file */
+
+ filesize = (CK_OFF_T)-1; /* Loop exit (file size) variable */
+ while (filesize < 0) { /* Keep trying till we get one... */
+ retcode = 0;
+ if (sndsrc > 0) { /* File list in cmlist or file */
+ if (filefile) { /* Reading list from file... */
+ if (zsinl(ZMFILE,filnam,CKMAXPATH) < 0) { /* Read a line */
+ zclose(ZMFILE); /* Failed */
+ debug(F110,"gnfile filefile EOF",filefile,0);
+ makestr(&filefile,NULL);
+ return(0);
+ }
+ debug(F110,"gnfile filefile filnam",filnam,0);
+ }
+ debug(F101,"gnfile nfils","",nfils);
+ if (nfils-- > 0 || filefile) { /* Still some left? */
+#ifndef NOMSEND
+ if (addlist) {
+ if (filenext && filenext->fl_name) {
+ ckstrncpy(filnam,filenext->fl_name,CKMAXPATH+1);
+ cmarg2 =
+ filenext->fl_alias ?
+ filenext->fl_alias :
+ "";
+ binary = filenext->fl_mode;
+ } else {
+ printf("?Internal error expanding ADD list\n");
+ return(-5);
+ }
+ filenext = filenext->fl_next;
+ debug(F111,"gnfile addlist filnam",filnam,nfils);
+ } else if (sndsrc > 0 && !filefile) {
+#endif /* NOMSEND */
+ ckstrncpy(filnam,*cmlist++,CKMAXPATH+1);
+ debug(F111,"gnfile cmlist filnam",filnam,nfils);
+#ifndef NOMSEND
+ }
+#endif /* NOMSEND */
+ i = 0;
+#ifndef NOSERVER
+ debug(F101,"gnfile ngetpath","",ngetpath);
+#endif /* NOSERVER */
+nextinpath:
+#ifndef NOSERVER
+ fromgetpath = 0;
+ if (server && !isabsolute(filnam) && (ngetpath > i)) {
+ ckstrncpy(fullname,getpath[i],CKMAXPATH+1);
+ ckstrncat(fullname,filnam,CKMAXPATH);
+ debug(F111,"gnfile getpath",fullname,i);
+ fromgetpath = 1;
+ i++;
+ } else {
+ i = ngetpath + 1;
+#else
+ i = 1; /* ? */
+#endif /* NOSERVER */
+ ckstrncpy(fullname,filnam,CKMAXPATH+1);
+ debug(F110,"gnfile absolute",fullname,0);
+#ifndef NOSERVER
+ }
+#endif /* NOSERVER */
+ if (iswild(fullname)
+#ifdef RECURSIVE
+ || recursive > 0 || !strcmp(fullname,".")
+#endif /* RECURSIVE */
+ ) { /* It looks wild... */
+ /* First check if a file with this name exists */
+ debug(F110,"gnfile wild",fullname,0);
+ if (zchki(fullname) >= 0) {
+ /*
+ Here we have a file whose name actually
+ contains wildcard characters.
+ */
+ goto gotnam;
+ }
+#ifdef COMMENT
+ nzxopts = ZX_FILONLY; /* (was 0: 25 Jul 2001 fdc) */
+#else
+ nzxopts = recursive ? 0 : ZX_FILONLY; /* 30 Jul 2001 */
+#endif /* COMMENT */
+ if (nolinks) nzxopts |= ZX_NOLINKS; /* (26 Jul 2001 fdc) */
+#ifdef UNIXOROSK
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+#endif /* UNIXOROSK */
+ if (recursive) nzxopts |= ZX_RECURSE;
+ x = nzxpand(fullname,nzxopts); /* Expand wildcards */
+ debug(F101,"gnfile nzxpand","",x);
+ if (x == 1) {
+ int xx;
+ xx = znext(fullname);
+ debug(F111,"gnfile znext A",fullname,xx);
+ goto gotnam;
+ }
+ if (x == 0) { /* None match */
+#ifndef NOSERVER
+ if (server && ngetpath > i)
+ goto nextinpath;
+#endif /* NOSERVER */
+ retcode = -1;
+ debug(F101,"gnfile gnferror A","",gnferror);
+ gnferror = -1;
+ continue;
+ }
+ if (x < 0) { /* Too many to expand */
+ debug(F101,"gnfile gnferror B","",gnferror);
+ gnferror = -5;
+ return(-5);
+ }
+ sndsrc = -1; /* Change send-source to znext() */
+ }
+ } else { /* We're out of files. */
+ debug(F111,"gnfile done",ckitoa(gnferror),nfils);
+ *filnam = '\0';
+ return(0);
+ }
+ }
+
+/* Otherwise, step to next element of internal wildcard expansion list. */
+
+ if (sndsrc == -1) {
+ int xx = 0;
+ while (1) {
+ debug(F111,"gnfile znext X",filnam,xx);
+ xx = znext(filnam);
+ debug(F111,"gnfile znext B",filnam,xx);
+ if (!filnam[0])
+ break;
+ if (dodirstoo) {
+ debug(F111,"gnfile FTP MPUT /RECURSIVE",filnam,xx);
+ break;
+ }
+ if (!isdir(filnam))
+ break;
+ }
+ debug(F111,"gnfile znext C",filnam,x);
+ if (!filnam[0]) { /* If no more, */
+ sndsrc = 1; /* go back to previous list */
+ debug(F101,"gnfile setting sndsrc back","",sndsrc);
+ continue;
+ } else
+ ckstrncpy(fullname,filnam,CKMAXPATH+1);
+ }
+
+/* Get here with a filename. */
+
+gotnam:
+ debug(F110,"gnfile fullname",fullname,0);
+ if (fullname[0]) {
+#ifdef DTILDE
+ char * dirp = "";
+ if (fullname[0] == '~') {
+ dirp = tilde_expand((char *)fullname);
+ if (*dirp) ckstrncpy(fullname,dirp,CKMAXPATH+1);
+ }
+#endif /* DTILDE */
+ filesize = zchki(fullname); /* Check if file readable */
+ debug(F111,"gnfile zchki",fullname,filesize);
+ retcode = filesize; /* Possible return code */
+ if (filesize == (CK_OFF_T)-2 && dodirstoo) {
+ filesize = 0;
+ }
+ if (filesize < 0) {
+ gnferror = (int)filesize;
+ debug(F101,"gnfile gnferror C","",gnferror);
+ }
+ if (filesize == (CK_OFF_T)-1) { /* If not found */
+ debug(F100,"gnfile -1","",0);
+#ifndef NOSERVER
+ if (server && ngetpath > i)
+ goto nextinpath;
+#endif /* NOSERVER */
+ debug(F110,"gnfile skipping:",fullname,0);
+ tlog(F110,fullname,": open failure - skipped",0);
+ xxscreen(SCR_FN,0,0l,fullname);
+ xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname);
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,fullname,fsize,binary,1,"Skipped");
+#endif /* TLOG */
+ continue;
+ } else if (filesize < 0) {
+ if (filesize == (CK_OFF_T)-3) { /* Exists but not readable */
+ debug(F100,"gnfile -3","",0);
+ filrej++; /* Count this one as not sent */
+ tlog(F110,"Read access denied",fullname,0); /* Log this */
+ xxscreen(SCR_FN,0,0l,fullname);
+ xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); /* Display it */
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,fullname,fsize,binary,1,"Skipped");
+#endif /* TLOG */
+ }
+ continue;
+ } else {
+ int xx;
+ fsize = filesize;
+/* +++ */
+ debug(F111,"gnfile sndsmaller",ckfstoa(sndsmaller),sndsmaller);
+ debug(F111,"gnfile sndlarger",ckfstoa(sndlarger),sndlarger);
+ debug(F111,"gnfile (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
+
+ xx = fileselect(fullname,
+ sndafter, sndbefore,
+ sndnafter,sndnbefore,
+ sndsmaller,sndlarger,
+ skipbup,
+ NSNDEXCEPT,sndexcept);
+ debug(F111,"gnfile fileselect",fullname,xx);
+ if (!xx) {
+ filesize = (CK_OFF_T)-1;
+ gnferror = -6;
+ debug(F101,"gnfile gnferror D","",gnferror);
+ continue;
+ }
+ ckstrncpy(filnam,fullname,CKMAXPATH+1);
+ return(1);
+ }
+#ifdef COMMENT
+ /* This can't be right! */
+ } else { /* sndsrc is 0... */
+ if (!fileselect(fullname,
+ sndafter, sndbefore,
+ sndnafter,sndnbefore,
+ sndsmaller,sndlarger,
+ skipbup,
+ NSNDEXCEPT,sndexcept)) {
+ gnferror = -6;
+ debug(F111,"gnfile fileselect",fullname,gnferror);
+ filesize = (CK_OFF_T)-1;
+ continue;
+ }
+ ckstrncpy(filnam,fullname,CKMAXPATH+1);
+ return(1);
+#endif /* COMMENT */
+ }
+ }
+ debug(F101,"gnfile result","",retcode);
+ *filnam = '\0';
+ return(0);
+}
+
+/*
+ The following bunch of routines feed internally generated data to the server
+ to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
+ and so on. We have to write these lines in the format appropriate to our
+ platform, so they can be converted to generic (CRLF) text format by the
+ packetizer.
+*/
+#ifdef UNIX
+char * endline = "\12";
+#else
+#ifdef datageneral
+char * endline = "\12";
+#else
+#ifdef MAC
+char * endline = "\15";
+#else
+#ifdef OSK
+char * endline = "\15";
+#else
+char * endline = "\15\12";
+#endif /* OSK */
+#endif /* MAC */
+#endif /* datageneral */
+#endif /* UNIX */
+
+#ifdef MAC
+#define FNCBUFL 256
+#else
+#ifdef CKSYMLINK
+#define FNCBUFL (CKMAXPATH + CKMAXPATH + 64)
+#else
+#define FNCBUFL (CKMAXPATH + 64)
+#endif /* CKSYMLINK */
+#endif /* MAC */
+
+/* NB: The minimum FNCBUFL is 255 */
+
+static CHAR funcbuf[FNCBUFL];
+static int funcnxt = 0;
+static int funclen = 0;
+static int nxpnd = -1;
+static long ndirs = 0;
+static long nfiles = 0;
+static CK_OFF_T nbytes = 0;
+
+int
+sndstring(p) char * p; {
+#ifndef NOSERVER
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ ckstrncpy(cmdstr,versio,CMDSTRL); /* Data for X packet. */
+ first = 1; /* Init getchx lookahead */
+ memstr = 1; /* Just set the flag. */
+ memptr = p; /* And the pointer. */
+ binary = XYFT_T; /* Text mode for this. */
+ return(sinit());
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+
+/* S N D H L P -- Routine to send builtin help */
+
+static int srvhlpnum = 0;
+
+#ifdef IKSD
+static char *nmx[] = { "Disabled", "Disabled", "Enabled", "Enabled" };
+#endif /* IKSD */
+
+static char *
+xnm(x) int x; {
+#ifdef IKSD
+ if (inserver)
+ return(nmx[x]);
+ else
+#endif /* IKSD */
+ return(nm[x]);
+}
+
+static int
+nxthlp(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ ) {
+ int x = 0;
+ extern int
+ en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai,
+ en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who,
+ /* en_ret, */ en_mkd, en_rmd, en_asg, en_que, en_xit, x_login, x_logged,
+ xfinish;
+ extern char * ckxsys;
+
+ if (funcnxt < funclen)
+ return (funcbuf[funcnxt++]);
+
+ switch (srvhlpnum++) {
+ case 0:
+ x = ckstrncpy((char *)funcbuf,
+ "Client Command Status Description\n",
+ FNCBUFL
+ );
+ if (x_login && !x_logged) {
+ x += ckstrncat((char *)funcbuf,
+ " REMOTE LOGIN required\n",
+ FNCBUFL
+ );
+ }
+ if (FNCBUFL - x > 74)
+ sprintf((char *)(funcbuf+x)," GET %-14s%s\n",
+ xnm(en_get),
+ "Transfer file(s) from server to client."
+ );
+ break;
+
+/* NOTE: The minimum funcbuf[] size is 255; all of the following are safe. */
+
+ case 1:
+ sprintf((char *)funcbuf," SEND %-14s%s\n",
+ xnm(en_sen),
+ "Transfer file(s) from client to server."
+ );
+ break;
+
+ case 2:
+ sprintf((char *)funcbuf," MAIL %-14s%s\n",
+ xnm(inserver ? 0 : en_mai),
+ "Send file(s) as e-mail."
+ );
+ break;
+
+ case 3:
+#ifndef NOSPL
+ sprintf((char *)funcbuf," REMOTE ASSIGN %-14s%s\n",
+ xnm(en_asg),
+ "Assign value to server variable or macro."
+ );
+#else
+ sprintf((char *)funcbuf," REMOTE ASSIGN not configured\n");
+#endif /* NOSPL */
+
+ break;
+ case 4:
+ sprintf((char *)funcbuf," REMOTE CD %-14s%s\n",
+ xnm(en_cwd),
+ "Change server's directory."
+ );
+ break;
+
+ case 5:
+#ifdef ZCOPY
+ sprintf((char *)funcbuf," REMOTE COPY %-14s%s\n",
+ xnm(en_cpy),
+ "Copy a file on the server."
+ );
+#else
+ sprintf((char *)funcbuf," REMOTE COPY not configured\n");
+#endif /* ZCOPY */
+
+ break;
+ case 6:
+ sprintf((char *)funcbuf," REMOTE DELETE %-14s%s\n",
+ xnm(en_del),
+ "Delete a file on the server."
+ );
+ break;
+
+ case 7:
+ sprintf((char *)funcbuf," REMOTE DIRECTORY %-14s%s\n",
+ xnm(en_dir),
+ "List files on the server."
+ );
+ break;
+
+ case 8:
+ sprintf((char *)funcbuf," REMOTE EXIT %-14s%s\n",
+ xnm(en_xit),
+ "Exit from Kermit server program."
+ );
+ break;
+
+ case 9:
+ sprintf((char *)funcbuf," REMOTE HOST %-14s%s\n",
+ xnm(inserver ? 0 : en_hos),
+#ifdef datageneral
+ "Execute a CLI command on the server."
+#else
+#ifdef VMS
+ "Execute a DCL command on the server."
+#else
+ "Execute a shell command on the server."
+#endif /* VMS */
+#endif /* datageneral */
+ );
+ break;
+
+ case 10:
+ sprintf((char *)funcbuf," REMOTE PRINT %-14s%s\n",
+ xnm(inserver ? 0 : en_pri),
+ "Send a file to the server for printing."
+ );
+ break;
+
+ case 11:
+#ifndef NOSPL
+ sprintf((char *)funcbuf," REMOTE QUERY %-14s%s\n",
+ xnm(en_que),
+ "Get value of server variable or macro."
+ );
+
+#else
+ sprintf((char *)funcbuf," REMOTE QUERY not configured\n");
+#endif /* NOSPL */
+
+ break;
+ case 12:
+ sprintf((char *)funcbuf," REMOTE MKDIR %-14s%s\n",
+ xnm(en_mkd),
+ "Create a directory on the server."
+ );
+ break;
+
+ case 13:
+ sprintf((char *)funcbuf," REMOTE RMDIR %-14s%s\n",
+ xnm(en_rmd),
+ "Remove a directory on the server."
+ );
+ break;
+
+ case 14:
+ sprintf((char *)funcbuf," REMOTE RENAME %-14s%s\n",
+ xnm(en_ren),
+ "Rename a file on the server."
+ );
+ break;
+
+ case 15:
+ sprintf((char *)funcbuf," REMOTE SET %-14s%s\n",
+ xnm(en_set),
+ "Set a parameter on the server"
+ );
+ break;
+
+ case 16:
+ sprintf((char *)funcbuf," REMOTE SPACE %-14s%s\n",
+ xnm(en_spa),
+ "Inquire about disk space on the server."
+ );
+ break;
+
+ case 17:
+ sprintf((char *)funcbuf," REMOTE TYPE %-14s%s\n",
+ xnm(en_typ),
+ "Display a server file on your screen."
+ );
+ break;
+
+ case 18:
+ sprintf((char *)funcbuf," REMOTE WHO %-14s%s\n",
+ xnm(inserver ? 0 : en_who),
+ "List who is logged in to the server."
+ );
+ break;
+
+ case 19:
+ sprintf((char *)funcbuf," FINISH %-14s%s\n",
+ xnm(en_fin),
+ xfinish ?
+ "Exit from Kermit server program." :
+ "Return the server to its command prompt."
+ );
+ break;
+
+ case 20:
+ sprintf((char *)funcbuf," BYE %-14s%s\n\n",
+ xnm(en_bye),
+ "Log the server out and disconnect."
+ );
+ break;
+
+ default:
+ return(-1);
+ }
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ return(funcbuf[funcnxt++]);
+}
+
+int
+sndhlp() {
+#ifndef NOSERVER
+ extern char * ckxsys;
+
+ first = 1; /* Init getchx lookahead */
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ ckstrncpy(cmdstr,"REMOTE HELP",CMDSTRL); /* Data for X packet. */
+ sprintf((char *)funcbuf, "C-Kermit %s,%s\n\n", versio, ckxsys);
+ funclen = strlen((char *)funcbuf);
+#ifdef IKSD
+ if (inserver) {
+ sprintf((char *)(funcbuf+funclen),
+ "Internet Kermit Service (EXPERIMENTAL)\n\n");
+ funclen = strlen((char *)funcbuf);
+ }
+#endif /* IKSD */
+ funcnxt = 0;
+ funcptr = nxthlp;
+ funcstr = 1;
+ srvhlpnum = 0;
+ binary = XYFT_T; /* Text mode for this. */
+ return(sinit());
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+
+/*
+ Returns the next available character,
+ -1 if no more data.
+*/
+static int
+nxttype(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ ) {
+ int c;
+ if (zchin(ZIFILE,&c) < 0) {
+ zclose(ZIFILE);
+ return(-1);
+ } else {
+ return((unsigned)c);
+ }
+}
+
+/* S N D T Y P -- TYPE a file to remote client */
+
+int
+sndtype(file) char * file; {
+#ifndef NOSERVER
+ char name[CKMAXPATH+1];
+
+#ifdef OS2
+ char * p = NULL;
+
+ if (*file) {
+ ckstrncpy(name, file, CKMAXPATH+1);
+ /* change / to \. */
+ p = name;
+ while (*p) { /* Change them back to \ */
+ if (*p == '/') *p = '\\';
+ p++;
+ }
+ } else
+ return(0);
+#else
+ ckstrncpy(name, file, CKMAXPATH+1);
+#endif /* OS2 */
+
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ if (zchki(name) == -2) {
+ /* Found a directory */
+ return(0);
+ }
+ if (!zopeni(ZIFILE,name))
+ return(0);
+
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ ckstrncpy(cmdstr,"type",CMDSTRL); /* Data for X packet. */
+ first = 1; /* Init getchx lookahead */
+ funcstr = 1; /* Just set the flag. */
+ funcptr = nxttype; /* And the pointer. */
+ binary = XYFT_T; /* Text mode for this */
+ return(sinit());
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+
+/*
+ N X T D I R -- Provide data for senddir()
+
+ Returns the next available character or -1 if no more data.
+*/
+#ifndef NOICP
+/* Directory listing parameters set by the user interface, if any. */
+extern int dir_head, dir_dots, dir_back;
+#endif /* NOICP */
+static int sd_hdg, sd_bkp, sd_dot; /* Local listing parameters */
+
+static int
+nxtdir(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ ) {
+ char name[CKMAXPATH+1], dbuf[24], *p = NULL;
+ char *dstr = NULL, * lnk = "";
+ CHAR c, * linebuf = funcbuf;
+#ifdef OSK
+ /* Work around bugs in OSK compiler */
+ char *dirtag = "directories";
+ char *filetag = "files";
+ char *bytetag = "bytes";
+#endif /* OSK */
+ CK_OFF_T len = 0;
+ int x, itsadir = 0, gotone = 0;
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"nxtdir funcnxt","",funcnxt);
+ debug(F101,"nxtdir funclen","",funclen);
+ debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
+ }
+#endif /* DEBUG */
+ if (funcnxt < funclen) { /* Return next character from buffer */
+ c = funcbuf[funcnxt++];
+ debug(F000,"nxtdir return 1","",(unsigned)(c & 0xff));
+ return((unsigned)(c & 0xff));
+ }
+ while (nxpnd > 0) { /* Buffer needs refill */
+ nxpnd--;
+ znext(name); /* Get next filename */
+ if (!name[0]) { /* None left - done */
+ nxpnd = 0;
+ return(nxtdir());
+ }
+ if (sd_bkp) { /* Showing backup files? */
+ gotone = 1; /* Yes, no need to check. */
+ break;
+ }
+ x = ckmatch( /* No - see if this is one */
+#ifdef CKREGEX
+ "*.~[0-9]*~" /* Not perfect but close enough. */
+#else
+ "*.~*~" /* Less close. */
+#endif /* CKREGEX */
+ ,name,filecase,1);
+ debug(F111,"nxtdir ckmatch",name,x);
+ if (x) {
+ continue; /* It's a backup file - skip it */
+ } else {
+ gotone = 1; /* It's not, break from loop. */
+ break;
+ }
+ }
+ if (gotone) {
+ len = zgetfs(name); /* Get file size */
+ debug(F111,"nxtdir zgetfs",name,len);
+#ifdef VMSORUNIX
+ itsadir = zgfs_dir; /* See if it's a directory */
+#else
+ itsadir = (len == -2 || isdir(name));
+#endif /* VMSORUNIX */
+ dstr = zfcdat(name);
+ debug(F111,"nxtdir zcfdat",dstr,0);
+ if (!dstr)
+ dstr = "0000-00-00 00:00:00";
+ if (!*dstr) {
+ dstr = "0000-00-00 00:00:00";
+ } else {
+ dbuf[0] = dstr[0];
+ dbuf[1] = dstr[1];
+ dbuf[2] = dstr[2];
+ dbuf[3] = dstr[3];
+ dbuf[4] = '-';
+ dbuf[5] = dstr[4];
+ dbuf[6] = dstr[5];
+ dbuf[7] = '-';
+ dbuf[8] = dstr[6];
+ dbuf[9] = dstr[7];
+ strcpy(dbuf+10,dstr+8);
+ dstr = dbuf;
+ }
+#ifdef CK_PERMS
+#ifdef VMSORUNIX
+ p = ziperm(name); /* Get permissions */
+#else
+ p = zgperm(name);
+#endif /* VMSORUNIX */
+#else
+ p = NULL;
+#endif /* CK_PERMS */
+ debug(F110,"domydir perms",p,0);
+
+#ifdef VMS
+ /* Make name relative */
+ ckstrncpy(name,zrelname(name,zgtdir()),CKMAXPATH+1);
+#endif /* VMS */
+
+ if (itsadir) {
+ ndirs++;
+ } else {
+ nfiles++;
+ nbytes += len;
+ }
+ lnk = "";
+#ifdef UNIX
+#ifdef CKSYMLINK
+ if (zgfs_link) {
+ extern char linkname[];
+ lnk = linkname;
+ }
+ debug(F111,"nxtdir linkname",lnk,zgfs_link);
+#endif /* CKSYMLINK */
+#endif /* UNIX */
+
+/*
+ The following sprintf's are safe; linebuf is a pointer to funcbuf,
+ which is 64 bytes larger than CKMAXPATH (or double CKMAXPATH when
+ symlinks are possible). 64 allows for the fixed-field portions of
+ the file listing line: permissions, size, and date. CKMAXPATH allows
+ for the longest possible pathname.
+*/
+ if (itsadir && len < 0) { /* Directory */
+#ifdef VMS
+ sprintf((char *)linebuf,
+ "%-22s%-10s %s %s\n",p,"<DIR>",dstr,name);
+#else
+ if (p)
+ sprintf((char *)linebuf,
+ "%10s%-10s %s %s\n",p,"<DIR>",dstr,name);
+ else
+ sprintf((char *)linebuf,
+ "%-10s %s %s\n", "<DIR>", dstr, name);
+#endif /* VMS */
+ } else { /* Regular file */
+#ifdef VMS
+ sprintf((char *)linebuf,
+ "%-22s%10s %s %s\n", p, ckfstoa(len), dstr, name);
+#else
+ if (p)
+ sprintf((char *)linebuf,
+ "%10s%10s %s %s%s%s\n",
+ p, ckfstoa(len), dstr, name,
+ *lnk ? " -> " : "",
+ lnk
+ );
+ else
+ sprintf((char *)linebuf,
+ "%10s %s %s%s%s\n",
+ ckfstoa(len), dstr, name,
+ *lnk ? " -> " : "",
+ lnk
+ );
+#endif /* VMS */
+ }
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ } else if (sd_hdg && nxpnd == 0) { /* Done, send summary */
+ char *blankline = ""; /* At beginning of summary */
+/*
+ The idea is to prevent (a) unnecessary multiple blanklines, and (b)
+ prompt-stomping. Preventing (b) is practically impossible, because it
+ depends on the client so for now always include that final CRLF.
+*/
+ if (!ndirs || !nbytes || !nfiles)
+ blankline = endline;
+#ifdef OSK
+/* Workaround bugs in OS-9 compiler... */
+ if (ndirs == 1)
+ dirtag = "directory";
+ if (nfiles == 1)
+ filetag = "file";
+ if (nbytes == (CK_OFF_T)1)
+ bytetag = "byte";
+ sprintf((char *)funcbuf,
+ "%sSummary: %ld %s, %ld %s, %s %s%s",
+ blankline,
+ ndirs,
+ dirtag,
+ nfiles,
+ filetag,
+ ckfstoa(nbytes),
+ bytetag,
+ endline);
+#else
+ sprintf((char *)funcbuf,
+ "%sSummary: %ld director%s, %ld file%s, %s byte%s%s",
+ blankline,
+ ndirs,
+ (ndirs == 1) ? "y" : "ies",
+ nfiles,
+ (nfiles == 1) ? "" : "s",
+ ckfstoa(nbytes),
+ (nbytes == (CK_OFF_T)1) ? "" : "s",
+ endline
+ );
+#endif /* OSK */
+ nxpnd--;
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ } else {
+ funcbuf[0] = '\0';
+ funcnxt = 0;
+ funclen = 0;
+ }
+ debug(F101,"nxtdir funclen","",funclen);
+
+ if (funcnxt < funclen) { /* If we have data to send... */
+ c = funcbuf[funcnxt++];
+ debug(F000,"nxtdir return 2","",(unsigned)(c & 0xff));
+ return((unsigned)(c & 0xff));
+ } else
+ return(-1); /* Nothing left, done. */
+}
+
+/* S N D D I R -- send directory listing */
+
+int
+snddir(spec) char * spec; {
+#ifndef NOSERVER
+ char * p = NULL, name[CKMAXPATH+1];
+ int t = 0, rc = 0;
+ char fnbuf[CKMAXPATH+1];
+
+ debug(F111,"snddir matchdot",spec,matchdot);
+
+#ifndef NOICP
+ debug(F111,"snddir dir_dots",spec,dir_dots);
+ sd_hdg = dir_head > 0; /* Import listing parameters if any */
+ sd_bkp = dir_back > 0;
+ if (dir_dots > -1)
+ sd_dot = dir_dots;
+ else
+ sd_dot = matchdot;
+#else
+ sd_hdg = 1; /* Or use hardwired defaults */
+ sd_bkp = 1;
+ sd_dot = matchdot;
+#endif /* NOICP */
+
+ if (!spec) spec = "";
+ debug(F111,"snddir sd_dot",spec,sd_dot);
+ if (*spec) {
+#ifdef COMMENT
+ zfnqfp(spec,CKMAXPATH,name);
+ debug(F110,"snddir zfnqfp",name,0);
+#else
+ ckstrncpy(name,spec,CKMAXPATH+1);
+ debug(F110,"snddir name",name,0);
+#endif /* COMMENT */
+ } else {
+#ifdef OS2
+ strcpy(name, "*");
+#else
+#ifdef UNIXOROSK
+ strcpy(name, "./*");
+#else
+#ifdef VMS
+ strcpy(name, "*.*");
+#else
+#ifdef datageneral
+ strcpy(name, "+");
+#else
+ debug(F101,"snddir quit (no filespec)","",0);
+ return(0);
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OS2 */
+ }
+ debug(F110,"snddir name 1",name,0);
+ ndirs = 0L;
+ nfiles = 0L;
+ nbytes = (CK_OFF_T)0;
+
+ if (zfnqfp(name,CKMAXPATH,fnbuf))
+
+ debug(F110,"snddir name 2",name,0);
+ p = name + strlen(name); /* Move it to end of list */
+
+ /* sprintf safe because funcbuf size >= max path len + 64 */
+
+ if (sd_hdg) {
+ sprintf((char *)funcbuf,"Listing files: %s%s%s",fnbuf,endline,endline);
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ }
+ diractive = 1;
+
+#ifdef OS2
+ if (zchki(name) == -2) { /* Found a directory */
+ p--;
+ if (*p == '\\' || *p == '/')
+ ckstrncat(name, "*", CKMAXPATH);
+ else if (*p == ':')
+ ckstrncat(name, ".", CKMAXPATH);
+ else
+ ckstrncat(name, "\\*", CKMAXPATH);
+ debug(F110,"snddir directory",name,0);
+ }
+#else
+ if (!iswild(name) && isdir(name)) {
+ char * s = name;
+ p--;
+#ifdef UNIXOROSK
+ if (*p == '/') /* So append wildcard to it */
+ ckstrncat(s, "*", CKMAXPATH);
+ else
+ ckstrncat(s, "/*", CKMAXPATH);
+#else
+#ifdef VMS
+ if (*p == ']' || *p == '>' || *p == ':')
+ ckstrncat(s, "*.*", CKMAXPATH);
+#else
+#ifdef datageneral
+ if (*p == ':')
+ ckstrncat(s, "+", CKMAXPATH);
+ else
+ ckstrncat(s, ":+", CKMAXPATH);
+#else
+#ifdef VOS
+ if (*p == '>')
+ ckstrncat(s, "*", CKMAXPATH);
+ else
+ ckstrncat(s, ">*", CKMAXPATH);
+#endif /* VOS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIXOROSK */
+ debug(F110,"snddir directory",name,0);
+ }
+#endif /* OS2 */
+
+ nzxopts = 0;
+#ifdef UNIX
+ {
+ extern char ** mtchs;
+ debug(F111,"snddir sd_dot",spec,sd_dot);
+ if (sd_dot > 0)
+ nzxopts |= ZX_MATCHDOT;
+ if (recursive)
+ nzxopts |= ZX_RECURSE;
+ debug(F111,"snddir nzxopts",spec,nzxopts);
+ nxpnd = nzxpand(name,nzxopts); /* Get the array of names */
+ sh_sort(mtchs,NULL,nxpnd,0,0,1); /* Sort the array */
+ }
+#else
+ if (recursive) nzxopts |= ZX_RECURSE;
+ nxpnd = nzxpand(name,nzxopts);
+#endif /* UNIX */
+
+ debug(F101,"snddir nzxpand nxpnd","",nxpnd);
+ if (nxpnd < 1)
+ return(-1);
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */
+ sprintf(cmdstr,"DIRECTORY %s",name); /* safe */
+ else
+ ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL);
+ first = 1; /* Init getchx lookahead */
+ funcstr = 1; /* Just set the flag. */
+ funcptr = nxtdir; /* And the pointer. */
+ binary = XYFT_T; /* Text mode for this */
+ rc = sinit(); /* 26 Aug 2005 */
+ debug(F111,"snddir","sinit()",rc);
+ return(rc);
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+
+/* N X T D E L -- provide data for delete */
+
+/* Returns the next available character or -1 if no more data */
+
+static int
+nxtdel(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ ) {
+ char name[257], *p = NULL;
+ int len = 0;
+
+ if (funcnxt < funclen)
+ return ((unsigned)funcbuf[funcnxt++]);
+
+ if (nxpnd > 0) {
+ nxpnd--;
+ znext(name);
+ if (!name[0]) {
+ nxpnd = 0;
+ return(nxtdel());
+ }
+ len = zchki(name);
+
+ /* Find just the name of the file */
+
+ for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
+ if (*p == '/') p++;
+
+ /* sprintf's safe because size of funcbuf >= 64 + maxpathlen */
+
+ if (len > -1L) {
+ if (zdelet(name)) {
+ sprintf((char *)funcbuf," %10s: %s%s","skipping",p,endline);
+ } else {
+ nfiles++;
+ nbytes += len;
+ sprintf((char *)funcbuf," %10s: %s%s","deleted",p,endline);
+ }
+ } else
+ sprintf((char *)funcbuf," directory: %s%s", p, endline);
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ } else
+
+ /* If done processing the expanded entries send a summary statement */
+
+ if (nxpnd == 0) {
+ sprintf((char *)funcbuf,
+ "%s%ld file%s deleted, %s byte%s freed%s",
+ endline,
+ nfiles,
+ (nfiles == 1) ? "" : "s",
+ ckfstoa(nbytes),
+ (nbytes == (CK_OFF_T)1) ? "" : "s",
+ endline
+ );
+ nxpnd--;
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+ } else {
+ funcbuf[0] = '\0';
+ funcnxt = 0;
+ funclen = 0;
+ }
+
+ /* If we have data to send */
+
+ if (funcnxt < funclen)
+ return ((unsigned)funcbuf[funcnxt++]); /* Return a character */
+ else
+ return(-1); /* No more input */
+}
+
+/* S N D D E L -- Send delete message */
+
+int
+snddel(spec) char * spec; {
+#ifndef NOSERVER
+ char name[CKMAXPATH+1];
+#ifdef OS2
+ char * p = NULL;
+#endif /* #ifdef OS2 */
+
+ if (!*spec)
+ return(0);
+
+ ckstrncpy(name, spec, CKMAXPATH+1);
+
+#ifdef OS2
+ /* change / to \. */
+ p = name;
+ while (*p) { /* Change them back to \ */
+ if (*p == '/') *p = '\\';
+ p++;
+ }
+#endif /* OS2 */
+
+ nfiles = 0L;
+ nbytes = (CK_OFF_T)0;
+ sprintf((char *)funcbuf,"Deleting \"%s\"%s",name,endline);
+ funcnxt = 0;
+ funclen = strlen((char *)funcbuf);
+
+ nzxopts = ZX_FILONLY; /* Files only */
+#ifdef UNIXOROSK
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+#endif /* UNIXOROSK */
+#ifdef COMMENT
+ /* Recursive deleting not supported yet */
+ if (recursive) nzxopts |= ZX_RECURSE;
+#endif /* COMMENT */
+ nxpnd = nzxpand(name,nzxopts);
+ if (nxpnd < 1)
+ return(-1);
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ ckstrncpy(cmdstr,"REMOTE DELETE",CMDSTRL); /* Data for X packet. */
+ first = 1; /* Init getchx lookahead */
+ funcstr = 1; /* Just set the flag. */
+ funcptr = nxtdel; /* And the pointer. */
+ binary = XYFT_T; /* Use text mode for this, */
+ return(sinit());
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+
+#ifdef OS2
+/* S N D S P A C E -- send disk space message */
+int
+sndspace(drive) int drive; {
+#ifndef NOSERVER
+ static char spctext[64];
+ unsigned long space;
+
+ if (drive) {
+ space = zdskspace(drive - 'A' + 1);
+ if (space > 0 && space < 1024)
+ sprintf(spctext,
+ " Drive %c: unknown%s",
+ drive,
+ endline
+ );
+ else
+ sprintf(spctext,
+ " Drive %c: %ldK free%s",
+ drive,
+ space / 1024L,
+ endline
+ );
+ } else {
+ space = zdskspace(0);
+ if (space > 0 && space < 1024)
+ sprintf(spctext, " Free space: unknown%s", endline);
+ else
+ sprintf(spctext, " Free space: %ldK%s", space / 1024L, endline);
+ }
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ ckstrncpy(cmdstr,"free space",CMDSTRL); /* Data for X packet. */
+ first = 1; /* Init getchx lookahead */
+ memstr = 1; /* Just set the flag. */
+ memptr = spctext; /* And the pointer. */
+ binary = XYFT_T; /* Text mode for this. */
+ return(sinit());
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+
+/* S N D W H O -- send who message */
+int
+sndwho(who) char * who; {
+#ifndef NOSERVER
+ nfils = 0; /* No files, no lists. */
+ xflg = 1; /* Flag we must send X packet. */
+ ckstrncpy(cmdstr,"who",CMDSTRL); /* Data for X packet. */
+ first = 1; /* Init getchx lookahead */
+ memstr = 1; /* Just set the flag. */
+#ifdef NT
+ memptr = "\15\12K95 SERVER\15\12"; /* And the pointer. */
+#else
+ memptr = "\15\12K/2 SERVER\15\12";
+#endif /* NT */
+ binary = XYFT_T; /* Use text mode */
+ return(sinit());
+#else
+ return(0);
+#endif /* NOSERVER */
+}
+#endif /* OS2 */
+
+/* C W D -- Change server's working directory */
+
+/*
+ String passed has first byte as length of directory name, rest of string
+ is name. Returns:
+ 0 on failure.
+ 1 on success after sending short-form response (ACK with name).
+ 2 on success if a CD Message file is to be sent.
+*/
+int
+cwd(vdir) char *vdir; {
+ char *cdd, *dirp;
+
+ vdir[xunchar(*vdir) + 1] = '\0'; /* Terminate string with a null */
+ dirp = vdir+1;
+ tlog(F110,"Directory requested: ",dirp,0L);
+ if (zchdir(dirp)) { /* Try to change */
+ cdd = zgtdir(); /* Get new working directory. */
+ debug(F110,"cwd",cdd,0);
+ if (srvcdmsg) { /* Send orientation file? */
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (zchki(cdmsgfile[i]) > -1) {
+ xxscreen(SCR_CD,0,0l,cdd);
+ tlog(F110,"Changed directory to",cdd,0L);
+ return(2);
+ }
+ }
+ }
+ encstr((CHAR *)cdd); /* Send short-form reply */
+ ack1(data); /* containing directory name. */
+ xxscreen(SCR_CD,0,0l,cdd);
+ tlog(F110,"Changed directory to",cdd,0L);
+ return(1);
+ } else {
+ debug(F110,"cwd failed",dirp,0);
+ tlog(F110,"Failed to change directory to",dirp,0L);
+ return(0);
+ }
+}
+
+
+/* S Y S C M D -- Do a system command */
+
+/* Command string is formed by concatenating the two arguments. */
+
+int
+syscmd(prefix,suffix) char *prefix, *suffix; {
+ extern int i_isopen;
+#ifndef NOPUSH
+ char *cp;
+
+ i_isopen = 0;
+ if (!prefix)
+ return(0);
+ if (!*prefix)
+ return(0);
+ for (cp = cmdstr; *prefix != '\0'; (*cp++ = *prefix++));
+ while ((*cp++ = *suffix++))
+#ifdef OS2
+ /* This takes away more than we gain in convenience
+ if (*(cp-1) == '/') *(cp-1) = '\\' */
+#endif /* OS2 */
+ ; /* Copy suffix */
+
+ debug(F110,"syscmd",cmdstr,0);
+
+ if (zxcmd(ZIFILE,cmdstr) > 0) {
+ debug(F110,"syscmd zxcmd ok",cmdstr,0);
+ nfils = sndsrc = 0; /* Flag that input is from stdin */
+ xflg = hcflg = 1; /* And special flags for pipe */
+ binary = XYFT_T; /* Go to text mode */
+ i_isopen = 1;
+ return (sinit()); /* Send S packet */
+ } else {
+ debug(F100,"syscmd zxcmd failed",cmdstr,0);
+ i_isopen = 0;
+ return(0);
+ }
+#else
+ debug(F100,"syscmd zxcmd NOPUSH",cmdstr,0);
+ i_isopen = 0;
+ return(0);
+#endif /* NOPUSH */
+}
+
+/* R E M S E T -- Remote Set */
+/* Called by server to set variables as commanded in REMOTE SET packets. */
+/* Returns 1 on success, 0 on failure. */
+
+int
+remset(s) char *s; {
+ extern int c_save, en_del;
+ int len, i, x, y;
+ char *p;
+
+ len = xunchar(*s++); /* Length of first field */
+ p = s + len; /* Pointer to second length field */
+ *p++ = '\0'; /* Zero out second length field */
+ x = atoi(s); /* Value of first field */
+ debug(F111,"remset",s,x);
+ debug(F110,"remset",p,0);
+ switch (x) { /* Do the right thing */
+ case 132: /* Attributes (all, in) */
+ atcapr = atoi(p);
+ return(1);
+ case 133: /* File length attributes */
+ case 233: /* IN/OUT combined */
+ case 148: /* Both kinds of lengths */
+ case 248:
+ atleni = atleno = atoi(p);
+ return(1);
+ case 134: /* File Type (text/binary) */
+ case 234:
+ attypi = attypo = atoi(p);
+ return(1);
+ case 135: /* File creation date */
+ case 235:
+ atdati = atdato = atoi(p);
+ return(1);
+ case 139: /* File Blocksize */
+ case 239:
+ atblki = atblko = atoi(p);
+ return(1);
+ case 141: /* Encoding / Character Set */
+ case 241:
+ atenci = atenco = atoi(p);
+ return(1);
+ case 142: /* Disposition */
+ case 242:
+ atdisi = atdiso = atoi(p);
+ return(1);
+ case 145: /* System ID */
+ case 245:
+ atsidi = atsido = atoi(p);
+ return(1);
+ case 147: /* System-Dependent Info */
+ case 247:
+ atsysi = atsyso = atoi(p);
+ return(1);
+ case 232: /* Attributes (all, out) */
+ atcapr = atoi(p);
+ return(1);
+ case 300: /* File type (text, binary) */
+ binary = atoi(p);
+ b_save = binary;
+#ifndef NOICP
+ g_binary = -1;
+#endif /* NOICP */
+ return(1);
+ case 301: /* File name conversion */
+ fncnv = 1 - atoi(p); /* (oops) */
+ f_save = fncnv;
+#ifndef NOICP
+ g_fncnv = -1;
+#endif /* NOICP */
+ return(1);
+ case 302: /* File name collision */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest) /* May not be changed by guest */
+ return(0);
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ x = atoi(p);
+ if (!ENABLED(en_del) && (x == XYFX_X || x == XYFX_U))
+ return(0);
+ if (x == XYFX_R) ckwarn = 1; /* Rename */
+ if (x == XYFX_X) ckwarn = 0; /* Replace */
+ fncact = x;
+ return(1);
+ case 310: /* Incomplete File Disposition */
+ keep = atoi(p); /* Keep, Discard, Auto */
+ return(1);
+ case 311: /* Blocksize */
+ fblksiz = atoi(p);
+ return(1);
+ case 312: /* Record Length */
+ frecl = atoi(p);
+ return(1);
+ case 313: /* Record format */
+ frecfm = atoi(p);
+ return(1);
+ case 314: /* File organization */
+ forg = atoi(p);
+ return(1);
+ case 315: /* File carriage control */
+ fcctrl = atoi(p);
+ return(1);
+ case 330: /* Match dotfiles */
+#ifndef NOICP
+ dir_dots = -1; /* This undoes DIR /DOT option */
+#endif /* NOICP */
+ matchdot = atoi(p);
+ return(1);
+ case 331: /* Match FIFOs */
+ matchfifo = atoi(p);
+ return(1);
+ case 400: /* Block check */
+ y = atoi(p);
+ if (y < 5 && y > 0) {
+ bctr = y;
+ c_save = -1;
+ return(1);
+ } else if (*p == 'B') {
+ bctr = 4;
+ c_save = -1;
+ return(1);
+ } else if (*p == '5') {
+ bctr = 3;
+ c_save = -1;
+ return(1);
+ }
+ return(0);
+ case 401: /* Receive packet-length */
+ rpsiz = urpsiz = atoi(p);
+ if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
+ if (rpsiz > 94) rpsiz = 94; /* Max short-packet length */
+ urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
+ return(1);
+ case 402: /* Receive timeout */
+ y = atoi(p); /* Client is telling us */
+ if (y > -1 && y < 999) { /* the timeout that it wants */
+ pkttim = chktimo(y,timef); /* us to tell it to use. */
+ return(1);
+ } else return(0);
+ case 403: /* Retry limit */
+ y = atoi(p);
+ if (y > -1 && y < 95) {
+ maxtry = y;
+ return(1);
+ } else return(0);
+ case 404: /* Server timeout */
+ y = atoi(p);
+ if (y < 0) return(0);
+ srvtim = y;
+ return(1);
+
+#ifndef NOCSETS
+ case 405: { /* Transfer character set */
+ extern int s_cset, axcset[];
+ int i;
+ for (i = 0; i < ntcsets; i++) {
+ if (!strcmp(tcsinfo[i].designator,p)) break;
+ }
+ debug(F101,"remset tcharset lookup","",i);
+ if (i == ntcsets) return(0);
+ tcharset = tcsinfo[i].code; /* If known, use it */
+ debug(F101,"remset tcharset","",tcharset);
+ if (s_cset == XMODE_A)
+ if (axcset[tcharset] > -1 && axcset[tcharset] > MAXFCSETS)
+ fcharset = axcset[tcharset]; /* Auto-pick file charset */
+ debug(F101,"remset tcharset fcharset","",fcharset);
+ setxlatype(tcharset,fcharset); /* Set up charset translations */
+ debug(F101,"remset xlatype","",xlatype);
+ debug(F101,"remset tcharset after setxlatype","",tcharset);
+ tcs_save = -1;
+ return(1);
+ }
+ case 320: { /* File character set */
+ extern struct keytab fcstab[];
+ extern int nfilc, s_cset, r_cset;
+ x = lookup(fcstab,p,nfilc,&y);
+ debug(F111,"RSET FILE CHAR name",p,x);
+ if (x < 0)
+ return(0);
+ s_cset = XMODE_M; /* No automatic charset switching */
+ r_cset = XMODE_M;
+ fcharset = x; /* Set file charset */
+ setxlatype(tcharset,fcharset); /* and translation type */
+ fcs_save = -1;
+ return(1);
+ }
+#endif /* NOCSETS */
+
+ case 406: /* Window slots */
+ y = atoi(p);
+ if (y == 0) y = 1;
+ if (y < 1 || y > MAXWS) return(0);
+ wslotr = y;
+ swcapr = 1;
+ urpsiz = adjpkl(urpsiz,wslotr,bigrbsiz);
+ return(1);
+
+ case 410: /* Transfer mode */
+ y = atoi(p); /* 0 = automatic, nonzero = manual */
+ if (y != 0) y = 1;
+ xfermode = y;
+ debug(F101,"REMOTE SET xfermode","",xfermode);
+ return(1);
+
+ case 420: /* SERVER CD-MESSAGE { ON, OFF } */
+ y = atoi(p); /* 0 = automatic, nonzero = manual */
+ srvcdmsg = y;
+ return(1);
+
+ default: /* Anything else... */
+ return(0);
+ }
+}
+
+/* Adjust packet length based on number of window slots and buffer size */
+
+int
+adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
+ if (protocol != PROTO_K) return(pktlen);
+ debug(F101,"adjpkl len","",pktlen);
+ debug(F101,"adjpkl slots","",slots);
+ debug(F101,"adjpkl bufsiz","",bufsiz);
+ if (((pktlen + 6) * slots) > bufsiz)
+ pktlen = (bufsiz / slots) - 6;
+ debug(F101,"adjpkl new len","",pktlen);
+ return(pktlen);
+}
+
+/* Set transfer mode and file naming based on comparison of system types */
+
+
+VOID
+whoarewe() {
+#ifndef NOICP
+ extern int g_xfermode;
+#endif /* NOICP */
+
+ wearealike = 0;
+
+ debug(F101,"whoarewe xfermode","",xfermode);
+#ifndef NOICP
+ debug(F101,"whoarewe g_xfermode","",g_xfermode);
+#endif /* NOICP */
+ if (whoareu[0]) { /* If we know partner's system type */
+ char * p = (char *)whoareu;
+ debug(F110,"whoarewe remote sysid",whoareu,0);
+ if (!strcmp(p,cksysid)) /* Other system same as us */
+ wearealike = 1;
+
+#ifdef UNIX
+ else if (!strcmp(p,"L3")) /* UNIX is sort of like AmigaDOS */
+ wearealike = 1; /* (same directory separator) */
+ else if (!strcmp(p,"N3")) /* UNIX like Aegis */
+ wearealike = 1;
+#else
+#ifdef AMIGA
+/* Like UNIX, but case distinctions are ignored and can begin with device:. */
+ else if (!strcmp(p,"U1")) /* Amiga is sort of like UNIX */
+ wearealike = 1;
+ else if (!strcmp(p,"N3")) /* Amiga is sort of like Aegis */
+ wearealike = 1;
+#else
+#ifdef OS2 /* (Includes Windows 95/NT) */
+
+ /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
+ /* All "the same" for FAT partitions but all bets off otherwise */
+ /* so this part needs some refinement ... */
+
+ else if (!strcmp(p,"U8")) /* MS-DOS */
+ wearealike = 1;
+ else if (!strcmp(p,"UO")) /* OS/2 */
+ wearealike = 1;
+ else if (!strcmp(p,"UN")) /* Windows NT or 95 */
+ wearealike = 1;
+ else if (!strcmp(p,"K2")) /* GEMDOS */
+ wearealike = 1;
+#else
+#ifdef GEMDOS
+ else if (!strcmp(p,"U8"))
+ wearealike = 1;
+ else if (!strcmp(p,"UO"))
+ wearealike = 1;
+ else if (!strcmp(p,"UN"))
+ wearealike = 1;
+ else if (!strcmp(p,"K2"))
+ wearealike = 1;
+#endif /* GEMDOS */
+#endif /* OS2 */
+#endif /* AMIGA */
+#endif /* UNIX */
+
+ /* Get here with wearealike == 1 if system types match */
+
+ debug(F101,"whoarewe wearealike","",wearealike);
+ if (!wearealike) /* Not alike */
+ return;
+
+ fncnv = XYFN_L; /* Alike, so literal filenames */
+ debug(F101,"whoarewe setting fncnv","",fncnv);
+
+ if (xfermode == XMODE_A) { /* Current xfer mode is auto */
+#ifdef VMS
+ binary = XYFT_L; /* For VMS-to-VMS, use labeled */
+#else
+#ifdef OS2
+ /* OS/2 but not Windows */
+ if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
+ binary = XYFT_L; /* For OS/2-to-OS/2, use labeled */
+#else
+ binary = XYFT_B; /* For all others use binary */
+#endif /* OS2 */
+#endif /* VMS */
+ gnf_binary = binary; /* Prevailing type for gnfile() */
+ debug(F101,"whoarewe setting binary","",binary);
+ }
+ }
+}
+#endif /* NOXFER */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcftp.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcftp.c
new file mode 100644
index 0000000..66c7940
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcftp.c
@@ -0,0 +1,17654 @@
+#define FTP_TIMEOUT
+
+/* C K C F T P -- FTP Client for C-Kermit */
+
+char *ckftpv = "FTP Client, 9.0.260, 14 Jul 2011";
+
+/*
+ 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, 2011,
+ 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"
+#ifdef VMS
+/* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
+#include <stat.h>
+#else /* def VMS */
+#include <sys/stat.h>
+#endif /* def VMS [else] */
+#include <ctype.h>
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#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"
+
+#ifdef CK_SSL
+#include "ckuath.h" /* SMS 2007/02/15 */
+#endif /* def CK_SSL */
+
+/*
+ How to get the struct timeval definition so we can call select(). The
+ xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
+ targets. The problem is: maybe we have already included some header file
+ that defined struct timeval, and maybe we didn't. If we did, we don't want
+ to include another header file that defines it again or the compilation will
+ fail. If we didn't, we have to include the header file where it's defined.
+ But in some cases even that won't work because of strict POSIX constraints
+ or somesuch, or because this introduces other conflicts (e.g. struct tm
+ multiply defined), in which case we have to define it ourselves, but this
+ can work only if we didn't already encounter a definition.
+*/
+#ifndef DCLTIMEVAL
+#ifdef SV68R3V6
+#define DCLTIMEVAL
+#else
+#ifdef SCO234
+#define DCLTIMEVAL
+#endif /* SCO234 */
+#endif /* SV68R3V6 */
+#endif /* DCLTIMEVAL */
+
+#ifdef DCLTIMEVAL
+/* Also maybe in some places the elements must be unsigned... */
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#ifdef COMMENT
+/* Currently we don't use this... */
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif /* COMMENT */
+#else /* !DCLTIMEVAL */
+#ifndef NOSYSTIMEH
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+#endif /* DCLTIMEVAL */
+
+/* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
+#ifdef VMS
+#include <types.h>
+#else /* def VMS */
+#include <sys/types.h>
+#endif /* def VMS [else] */
+#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 VMS /* SMS 2007/02/15 */
+#include "ckvrtl.h" /* for utime() */
+#else /* def VMS */
+#ifdef SYSUTIMEH
+#include <sys/utime.h>
+#else
+#ifdef UTIMEH
+#include <utime.h>
+#define SYSUTIMEH
+#endif /* UTIMEH */
+#endif /* SYSUTIMEH */
+#endif /* def VMS */
+#endif /* NOSETTIME */
+
+#ifndef SCO_OSR504
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* SCO_OSR504 */
+
+#ifndef INADDR_NONE /* 2010-03-29 */
+#define INADDR_NONE -1
+#endif /* INADDR_NONE */
+
+/* select() dialects... */
+
+#ifdef UNIX
+#define BSDSELECT /* BSD select() syntax/semantics */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 128
+#endif /* FD_SETSIZE */
+#ifdef HPUX6 /* For HP-UX 6.5 circa 1989 */
+typedef long fd_mask;
+#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif /* howmany */
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_COPY(f, t) bcopy(f, t, sizeof(*(f)))
+#define FD_ZERO(p) bzero(p, sizeof(*(p)))
+#endif /* HPUX6 */
+
+#else
+#ifdef OS2 /* OS/2 or Win32 */
+#ifdef NT
+#define BSDSELECT
+#else /* NT */
+#define IBMSELECT
+#endif /* NT */
+#endif /* OS2 */
+#endif /* UNIX */
+
+#ifdef VMS
+#define BSDSELECT /* SMS 2007/02/15 */
+#endif /* def VMS */
+
+/* Other select() peculiarities */
+
+#ifdef HPUX
+#ifndef HPUX10 /* HP-UX 9.xx and earlier */
+#ifndef HPUX1100
+/* The three interior args to select() are (int *) rather than (fd_set *) */
+#ifndef INTSELECT
+#define INTSELECT
+#endif /* INTSELECT */
+#endif /* HPUX1100 */
+#endif /* HPUX10 */
+#endif /* HPUX */
+
+#ifdef CK_SOCKS /* SOCKS Internet relay package */
+#ifdef CK_SOCKS5 /* SOCKS 5 */
+#define accept SOCKSaccept
+#define bind SOCKSbind
+#define connect SOCKSconnect
+#define getsockname SOCKSgetsockname
+#define listen SOCKSlisten
+#else /* Not SOCKS 5 */
+#define accept Raccept
+#define bind Rbind
+#define connect Rconnect
+#define getsockname Rgetsockname
+#define listen Rlisten
+#endif /* CK_SOCKS5 */
+#endif /* CK_SOCKS */
+
+#ifndef NOHTTP
+extern char * tcp_http_proxy; /* Name[:port] of http proxy server */
+extern int tcp_http_proxy_errno;
+extern char * tcp_http_proxy_user;
+extern char * tcp_http_proxy_pwd;
+extern char * tcp_http_proxy_agent;
+#define HTTPCPYL 1024
+static char proxyhost[HTTPCPYL];
+#endif /* NOHTTP */
+int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
+
+/* Feature selection */
+
+#ifndef USE_SHUTDOWN
+/*
+ We don't use shutdown() because (a) we always call it just before close()
+ so it's redundant and unnecessary, and (b) it introduces a long pause on
+ some platforms like SV/68 R3.
+*/
+/* #define USE_SHUTDOWN */
+#endif /* USE_SHUTDOWN */
+
+#ifndef NORESEND
+#ifndef NORESTART /* Restart / recover */
+#ifndef FTP_RESTART
+#define FTP_RESTART
+#endif /* FTP_RESTART */
+#endif /* NORESTART */
+#endif /* NORESEND */
+
+#ifndef NOUPDATE /* Update mode */
+#ifndef DOUPDATE
+#define DOUPDATE
+#endif /* DOUPDATE */
+#endif /* NOUPDATE */
+
+#ifndef UNICODE /* Unicode required */
+#ifndef NOCSETS /* for charset translation */
+#define NOCSETS
+#endif /* NOCSETS */
+#endif /* UNICODE */
+
+#ifndef OS2
+#ifndef HAVE_MSECS /* Millisecond timer */
+#ifdef UNIX
+#ifdef GFTIMER
+#define HAVE_MSECS
+#endif /* GFTIMER */
+#endif /* UNIX */
+#endif /* HAVE_MSECS */
+#endif /* OS2 */
+
+#ifdef PIPESEND /* PUT from pipe */
+#ifndef PUTPIPE
+#define PUTPIPE
+#endif /* PUTPIPE */
+#endif /* PIPESEND */
+
+#ifndef NOSPL /* PUT from array */
+#ifndef PUTARRAY
+#define PUTARRAY
+#endif /* PUTARRAY */
+#endif /* NOSPL */
+
+/* Security... */
+
+#ifdef CK_SRP
+#define FTP_SRP
+#endif /* CK_SRP */
+
+#ifdef CK_KERBEROS
+#ifdef KRB4
+/*
+ There is a conflict between the Key Schedule formats used internally
+ within the standalone MIT KRB4 library and that used by Eric Young
+ in OpenSSL and his standalone DES library. Therefore, KRB4 FTP AUTH
+ cannot be supported when either of those two packages are used.
+*/
+#ifdef KRB524
+#define FTP_KRB4
+#else /* KRB524 */
+#ifndef CK_SSL
+#ifndef LIBDES
+#define FTP_KRB4
+#endif /* LIBDES */
+#endif /* CK_SSL */
+#endif /* KRB524 */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifndef HEIMDAL
+#ifndef NOFTP_GSSAPI /* 299 */
+#define FTP_GSSAPI
+#endif /* NOFTP_GSSAPI */
+#endif /* HEIMDAL */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+/* FTP_SECURITY is defined if any of the above is selected */
+#ifndef FTP_SECURITY
+#ifdef FTP_GSSAPI
+#define FTP_SECURITY
+#else
+#ifdef FTP_KRB4
+#define FTP_SECURITY
+#else
+#ifdef FTP_SRP
+#define FTP_SECURITY
+#else
+#ifdef CK_SSL
+#define FTP_SECURITY
+#endif /* CK_SSL */
+#endif /* FTP_SRP */
+#endif /* FTP_KRB4 */
+#endif /* FTP_GSSAPI */
+#endif /* FTP_SECURITY */
+
+#ifdef CK_DES
+#ifdef CK_SSL
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+#endif /* CK_SSL */
+#endif /* CK_DES */
+
+#ifdef CRYPT_DLL
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+#endif /* CRYPT_DLL */
+
+#ifdef FTP_KRB4
+#define des_cblock Block
+#define des_key_schedule Schedule
+#ifdef KRB524
+#ifdef NT
+#define _WINDOWS
+#endif /* NT */
+#include "kerberosIV/krb.h"
+#else /* KRB524 */
+#ifdef SOLARIS
+#ifndef sun
+/* For some reason lost in history the Makefile Solaris targets have -Usun */
+#define sun
+#endif /* sun */
+#endif /* SOLARIS */
+#include "krb.h"
+#define krb_get_err_text_entry krb_get_err_text
+#endif /* KRB524 */
+#endif /* FTP_KRB4 */
+
+#ifdef CK_SSL
+#ifdef FTP_KRB4
+#ifndef HEADER_DES_H
+#define HEADER_DES_H
+#endif /* HEADER_DES_H */
+#endif /* FTP_KRB4 */
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifdef FTP_SRP
+#ifdef HAVE_PWD_H
+#include "pwd.h"
+#endif /* HAVE_PWD_H */
+#include "t_pwd.h"
+#include "t_client.h"
+#include "krypto.h"
+#endif /* FTP_SRP */
+
+#ifdef FTP_GSSAPI
+#include <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;
+
+#ifdef MACOSX
+/** exported constants defined in gssapi_krb5{,_nx}.h **/
+
+/* these are bogus, but will compile */
+
+/*
+ * The OID of the draft krb5 mechanism, assigned by IETF, is:
+ * iso(1) org(3) dod(5) internet(1) security(5)
+ * kerberosv5(2) = 1.3.5.1.5.2
+ * The OID of the krb5_name type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
+ * The OID of the krb5_principal type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
+ * The OID of the proposed standard krb5 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) = 1.2.840.113554.1.2.2
+ * The OID of the proposed standard krb5 v2 mechanism is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * krb5v2(3) = 1.2.840.113554.1.2.3
+ *
+ */
+
+/*
+ * Encoding rules: The first two values are encoded in one byte as 40
+ * * value1 + value2. Subsequent values are encoded base 128, most
+ * significant digit first, with the high bit (\200) set on all octets
+ * except the last in each value's encoding.
+ */
+
+static CONST gss_OID_desc
+ck_krb5_gss_oid_array[] = {
+ /* this is the official, rfc-specified OID */
+ {9, "\052\206\110\206\367\022\001\002\002"},
+ /* this is the unofficial, wrong OID */
+ {5, "\053\005\001\005\002"},
+ /* this is the v2 assigned OID */
+ {9, "\052\206\110\206\367\022\001\002\003"},
+ /* these two are name type OID's */
+ {10, "\052\206\110\206\367\022\001\002\002\001"},
+ {10, "\052\206\110\206\367\022\001\002\002\002"},
+ { 0, 0 }
+};
+
+static
+CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
+
+#ifdef MACOSX103
+static
+CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
+#endif /* MACOSX103 */
+
+#ifndef MACOSX
+static
+CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
+static
+CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
+static
+CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
+static
+CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
+#endif /* MACOSX */
+
+/*
+ * See krb5/gssapi_krb5.c for a description of the algorithm for
+ * encoding an object identifier.
+ */
+
+/*
+ * The OID of user_name is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1) = 1.2.840.113554.1.2.1.1
+ * machine_uid_name:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2
+ * string_uid_name:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3
+ * service_name:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4) = 1.2.840.113554.1.2.1.4
+ * exported_name:
+ * 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes),
+ * 4(gss-api-exported-name)
+ * host_based_service_name (v2):
+ * iso (1) org (3), dod (6), internet (1), security (5), nametypes(6),
+ * gss-host-based-services(2)
+ */
+
+static gss_OID_desc ck_oids[] = {
+ {10, "\052\206\110\206\367\022\001\002\001\001"},
+ {10, "\052\206\110\206\367\022\001\002\001\002"},
+ {10, "\052\206\110\206\367\022\001\002\001\003"},
+ {10, "\052\206\110\206\367\022\001\002\001\004"},
+ { 6, "\053\006\001\005\006\004"},
+ { 6, "\053\006\001\005\006\002"},
+};
+
+static gss_OID ck_gss_nt_user_name = ck_oids+0;
+static gss_OID ck_gss_nt_machine_uid_name = ck_oids+1;
+static gss_OID ck_gss_nt_string_uid_name = ck_oids+2;
+static gss_OID ck_gss_nt_service_name = ck_oids+3;
+static gss_OID ck_gss_nt_exported_name = ck_oids+4;
+static gss_OID ck_gss_nt_service_name_v2 = ck_oids+5;
+#endif /* MACOSX */
+#endif /* FTP_GSSAPI */
+
+#ifdef OS2
+#ifdef FTP_SRP
+#define MAP_KRYPTO
+#ifdef SRPDLL
+#define MAP_SRP
+#endif /* SRPDLL */
+#endif /* FTP_SRP */
+#ifdef FTP_KRB4
+#define MAP_KRB4
+#ifdef CK_ENCRYPTION
+#define MAP_DES
+#endif /* CK_ENCRYPTION */
+#endif /* FTP_KRB4 */
+#ifdef FTP_GSSAPI
+#define MAP_GSSAPI
+#define GSS_OIDS
+#endif /* FTP_GSSAPI */
+#include "ckoath.h"
+
+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 CK_OFF_T fsize, ffc, tfc, sendstart, sndsmaller, sndlarger, rs_len;
+extern long filcnt, xfsecs, tfcps, cps, oldcps;
+
+#ifdef FTP_TIMEOUT
+int ftp_timed_out = 0;
+long ftp_timeout = 0;
+#endif /* FTP_TIMEOUT */
+
+#ifdef GFTIMER
+extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
+#else
+extern long xfsecs;
+#endif /* GFTIMER */
+
+extern char filnam[], * filefile, myhost[];
+extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
+extern int g_skipbup, skipbup, sendmode;
+extern int g_displa, fdispla, displa;
+
+#ifdef LOCUS
+extern int locus, autolocus;
+#endif /* LOCUS */
+
+#ifndef NOCSETS
+extern int nfilc, dcset7, dcset8, fileorder;
+extern struct csinfo fcsinfo[];
+extern struct keytab fcstab[];
+extern int fcharset;
+#endif /* NOCSETS */
+
+extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
+extern char sndnbefore[], sndnafter[], *rcvexcept[];
+extern CHAR feol;
+
+extern char * remdest;
+extern int remfile, remappd, rempipe;
+
+#ifndef NOSPL
+extern int cmd_quoting;
+#ifdef PUTARRAY
+extern int sndxlo, sndxhi, sndxin;
+extern char sndxnam[];
+extern char **a_ptr[]; /* Array pointers */
+extern int a_dim[]; /* Array dimensions */
+#endif /* PUTARRAY */
+#endif /* NOSPL */
+
+#ifndef NOMSEND /* MPUT and ADD SEND-LIST lists */
+extern char *msfiles[];
+extern int filesinlist;
+extern struct filelist * filehead;
+extern struct filelist * filetail;
+extern struct filelist * filenext;
+extern int addlist;
+extern char fspec[]; /* Most recent filespec */
+extern int fspeclen; /* Length of fspec[] buffer */
+#endif /* NOMSEND */
+
+extern int pipesend;
+#ifdef PIPESEND
+extern char * sndfilter, * rcvfilter;
+#endif /* PIPESEND */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+#ifdef KRB4
+extern int krb4_autoget;
+_PROTOTYP(char * ck_krb4_realmofhost,(char *));
+#endif /* KRB4 */
+
+#ifdef KRB5
+extern int krb5_autoget;
+extern int krb5_d_no_addresses;
+_PROTOTYP(char * ck_krb5_realmofhost,(char *));
+#endif /* KRB5 */
+
+#ifdef DCMDBUF
+extern char *atmbuf; /* Atom buffer (malloc'd) */
+extern char *cmdbuf; /* Command buffer (malloc'd) */
+extern char *line; /* Big string buffer #1 */
+extern char *tmpbuf; /* Big string buffer #2 */
+#else
+extern char atmbuf[]; /* The same, but static */
+extern char cmdbuf[];
+extern char line[];
+extern char tmpbuf[];
+#endif /* DCMDBUF */
+
+extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
+
+/* Public variables declared here */
+
+#ifdef NOXFER
+int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
+#else
+int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
+#endif /* NOXFER */
+int ftpcode = -1; /* Last FTP response code */
+int ftp_cmdlin = 0; /* FTP invoked from command line */
+int ftp_fai = 0; /* FTP failure count */
+int ftp_deb = 0; /* FTP debugging */
+int ftp_dis = -1; /* FTP display style */
+int ftp_log = 1; /* FTP Auto-login */
+int sav_log = -1;
+int ftp_action = 0; /* FTP action from command line */
+int ftp_dates = 1; /* Set file dates from server */
+int ftp_xfermode = XMODE_A; /* FTP-specific transfer mode */
+
+char ftp_reply_str[FTP_BUFSIZ] = ""; /* Last line of previous reply */
+char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
+char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
+char * ftp_host = NULL; /* FTP hostname */
+char * ftp_logname = NULL; /* FTP username */
+char * ftp_rdir = NULL; /* Remote directory from cmdline */
+char * ftp_apw = NULL; /* Anonymous password */
+
+/* Definitions and typedefs needed for prototypes */
+
+#define sig_t my_sig_t
+#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 CK_OFF_T havesize = (CK_OFF_T)-1;
+static char * havemdtm = NULL;
+static int mgetmethod = 0; /* NLST or MLSD */
+static int mgetforced = 0;
+
+static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
+static int c0, c1; /* Temp variables for characters */
+
+static char putpath[CKMAXPATH+1] = { NUL, NUL };
+static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
+
+#define RFNBUFSIZ 4096 /* Remote filename buffer size */
+
+static unsigned int maxbuf = 0, actualbuf = 0;
+static CHAR *ucbuf = NULL;
+static int ucbufsiz = 0;
+static unsigned int nout = 0; /* Number of chars in ucbuf */
+
+static jmp_buf recvcancel;
+static jmp_buf sendcancel;
+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 unsigned short ftp_port = 0; */ /* FTP port */
+/* static int ftp_port = 0; */ /* SMS 2007/02/15 */
+static int ftp_port = 0; /* fdc 2007/08/30 */
+#ifdef FTPHOST
+static int hostcmd = 0; /* Has HOST command been sent */
+#endif /* FTPHOST */
+static int form, mode, stru, bytesize, curtype = FTT_ASC;
+static char bytename[8];
+
+/* For parsing replies to FTP server command */
+static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
+
+#ifdef FTP_PROXY
+static int proxy, unix_proxy
+#endif /* FTP_PROXY */
+
+static char pasv[64]; /* Passive-mode port */
+static int passivemode = 0;
+static int sendport = 0;
+static int servertype = 0; /* FTP server's OS type */
+
+static int testing = 0;
+static char ftpcmdbuf[FTP_BUFSIZ];
+
+/* Macro definitions */
+
+#define UC(b) ckitoa(((int)b)&0xff)
+#define nz(x) ((x) == 0 ? 1 : (x))
+
+/* Command tables and definitions */
+
+#define FTP_ACC 1 /* FTP command keyword codes */
+#define FTP_APP 2
+#define FTP_CWD 3
+#define FTP_CHM 4
+#define FTP_CLS 5
+#define FTP_DEL 6
+#define FTP_DIR 7
+#define FTP_GET 8
+#define FTP_IDL 9
+#define FTP_MDE 10
+#define FTP_MDI 11
+#define FTP_MGE 12
+#define FTP_MKD 13
+#define FTP_MOD 14
+#define FTP_MPU 15
+#define FTP_OPN 16
+#define FTP_PUT 17
+#define FTP_PWD 18
+#define FTP_RGE 19
+#define FTP_REN 20
+#define FTP_RES 21
+#define FTP_HLP 22
+#define FTP_RMD 23
+#define FTP_STA 24
+#define FTP_SIT 25
+#define FTP_SIZ 26
+#define FTP_SYS 27
+#define FTP_UMA 28
+#define FTP_GUP 29
+#define FTP_USR 30
+#define FTP_QUO 31
+#define FTP_TYP 32
+#define FTP_FEA 33
+#define FTP_OPT 34
+#define FTP_CHK 35
+#define FTP_VDI 36
+#define FTP_ENA 37
+#define FTP_DIS 38
+#define FTP_REP 39
+
+struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
+ { "auto", 2, 0 },
+ { "ftp", 1, 0 },
+ { "kermit", 0, 0 }
+};
+
+static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
+ { "proceed", 0, 0 }, /* 0 = proceed */
+ { "quit", 1, 0 } /* 1 = quit */
+};
+
+static struct keytab ftpcmdtab[] = { /* FTP command table */
+ { "account", FTP_ACC, 0 },
+ { "append", FTP_APP, 0 },
+ { "bye", FTP_CLS, 0 },
+ { "cd", FTP_CWD, 0 },
+ { "cdup", FTP_GUP, 0 },
+ { "check", FTP_CHK, 0 },
+ { "chmod", FTP_CHM, 0 },
+ { "close", FTP_CLS, 0 },
+ { "cwd", FTP_CWD, CM_INV },
+ { "delete", FTP_MDE, 0 },
+ { "directory", FTP_DIR, 0 },
+ { "disable", FTP_DIS, 0 },
+ { "enable", FTP_ENA, 0 },
+ { "features", FTP_FEA, 0 },
+ { "get", FTP_GET, 0 },
+ { "help", FTP_HLP, 0 },
+ { "idle", FTP_IDL, 0 },
+ { "login", FTP_USR, CM_INV },
+ { "mdelete", FTP_MDE, CM_INV },
+ { "mget", FTP_MGE, 0 },
+ { "mkdir", FTP_MKD, 0 },
+ { "modtime", FTP_MOD, 0 },
+ { "mput", FTP_MPU, 0 },
+ { "open", FTP_OPN, 0 },
+ { "opt", FTP_OPT, CM_INV|CM_ABR },
+ { "opts", FTP_OPT, CM_INV },
+ { "options", FTP_OPT, 0 },
+ { "put", FTP_PUT, 0 },
+ { "pwd", FTP_PWD, 0 },
+ { "quit", FTP_CLS, CM_INV },
+ { "quote", FTP_QUO, 0 },
+ { "reget", FTP_RGE, 0 },
+ { "rename", FTP_REN, 0 },
+ { "reput", FTP_REP, 0 },
+ { "resend", FTP_REP, CM_INV },
+ { "reset", FTP_RES, 0 },
+ { "rmdir", FTP_RMD, 0 },
+ { "send", FTP_PUT, CM_INV },
+ { "site", FTP_SIT, 0 },
+ { "size", FTP_SIZ, 0 },
+ { "status", FTP_STA, 0 },
+ { "system", FTP_SYS, 0 },
+ { "type", FTP_TYP, 0 },
+ { "umask", FTP_UMA, 0 },
+ { "up", FTP_GUP, CM_INV },
+ { "user", FTP_USR, 0 },
+ { "vdirectory",FTP_VDI, 0 },
+ { "", 0, 0 }
+};
+static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
+
+#define OPN_ANO 1 /* FTP OPEN switch codes */
+#define OPN_PSW 2
+#define OPN_USR 3
+#define OPN_ACC 4
+#define OPN_ACT 5
+#define OPN_PSV 6
+#define OPN_TLS 7
+#define OPN_NIN 8
+#define OPN_NOL 9
+
+#ifdef FTP_SECURITY
+#ifdef CK_SSL
+#define USETLSTAB
+static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
+ { "/ssl", OPN_TLS, 0 },
+ { "/tls", OPN_TLS, 0 },
+ { "", 0, 0 }
+};
+static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
+#endif /* CK_SSL */
+#endif /* FTP_SECURITY */
+
+static struct keytab ftpswitab[] = { /* FTP command switches */
+ { "/account", OPN_ACC, CM_ARG },
+ { "/active", OPN_ACT, 0 },
+ { "/anonymous", OPN_ANO, 0 },
+ { "/noinit", OPN_NIN, 0 },
+ { "/nologin", OPN_NOL, 0 },
+ { "/passive", OPN_PSV, 0 },
+ { "/password", OPN_PSW, CM_ARG },
+ { "/user", OPN_USR, CM_ARG },
+ { "", 0, 0 }
+};
+static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
+
+/* FTP { ENABLE, DISABLE } items */
+
+#define ENA_FEAT 1
+#define ENA_MDTM 2
+#define ENA_MLST 3
+#define ENA_SIZE 4
+#define ENA_AUTH 5
+
+static struct keytab ftpenatab[] = {
+ { "AUTH", ENA_AUTH, 0 },
+ { "FEAT", ENA_FEAT, 0 },
+ { "MDTM", ENA_MDTM, 0 },
+ { "ML", ENA_MLST, CM_INV|CM_ABR },
+ { "MLS", ENA_MLST, CM_INV|CM_ABR },
+ { "MLSD", ENA_MLST, CM_INV },
+ { "MLST", ENA_MLST, 0 },
+ { "SIZE", ENA_SIZE, 0 },
+ { "", 0, 0 }
+};
+static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
+
+/* SET FTP command keyword indices */
+
+#define FTS_AUT 1 /* Autoauthentication */
+#define FTS_CRY 2 /* Encryption */
+#define FTS_LOG 3 /* Autologin */
+#define FTS_CPL 4 /* Command protection level */
+#define FTS_CFW 5 /* Credentials forwarding */
+#define FTS_DPL 6 /* Data protection level */
+#define FTS_DBG 7 /* Debugging */
+#define FTS_PSV 8 /* Passive mode */
+#define FTS_SPC 9 /* Send port commands */
+#define FTS_TYP 10 /* (file) Type */
+#define FTS_USN 11 /* Unique server names (for files) */
+#define FTS_VBM 12 /* Verbose mode */
+#define FTS_ATP 13 /* Authentication type */
+#define FTS_CNV 14 /* Filename conversion */
+#define FTS_TST 15 /* Test (progress) messages */
+#define FTS_PRM 16 /* (file) Permissions */
+#define FTS_XLA 17 /* Charset translation */
+#define FTS_CSR 18 /* Server charset */
+#define FTS_ERR 19 /* Error action */
+#define FTS_FNC 20 /* Collision */
+#define FTS_SRP 21 /* SRP options */
+#define FTS_GFT 22 /* GET automatic file-type switching */
+#define FTS_DAT 23 /* Set file dates */
+#define FTS_STO 24 /* Server time offset */
+#define FTS_APW 25 /* Anonymous password */
+#define FTS_DIS 26 /* File-transfer display style */
+#define FTS_BUG 27 /* Bug(s) */
+#define FTS_TMO 28 /* Timeout */
+
+/* FTP BUGS */
+
+#define FTB_SV2 1 /* use SSLv2 */
+
+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 */
+#ifdef FTP_TIMEOUT
+ { "timeout", FTS_TMO, 0 },
+#endif /* FTP_TIMEOUT */
+ { "type", FTS_TYP, 0 },
+ { "unique-server-names", FTS_USN, 0 },
+ { "verbose-mode", FTS_VBM, 0 },
+ { "", 0, 0 }
+};
+static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
+
+/*
+ GET and PUT switches are approximately the same as Kermit GET and SEND,
+ and use the same SND_xxx definitions, but hijack a couple for FTP use.
+ Don't just make up new ones, since the number of SND_xxx options must be
+ known in advance for the switch-parsing arrays.
+*/
+#define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
+#define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
+#define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
+
+static struct keytab putswi[] = { /* FTP PUT switch table */
+ { "/after", SND_AFT, CM_ARG },
+#ifdef PUTARRAY
+ { "/array", SND_ARR, CM_ARG },
+#endif /* PUTARRAY */
+ { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
+ { "/as-name", SND_ASN, CM_ARG },
+ { "/ascii", SND_TXT, CM_INV },
+ { "/b", SND_BIN, CM_INV|CM_ABR },
+ { "/before", SND_BEF, CM_ARG },
+ { "/binary", SND_BIN, 0 },
+#ifdef PUTPIPE
+ { "/command", SND_CMD, CM_PSH },
+#endif /* PUTPIPE */
+#ifdef COMMENT
+/* This works but it's dangerous */
+#ifdef DOUPDATE
+ { "/dates-differ", SND_DIF, CM_INV },
+#endif /* DOUPDATE */
+#endif /* COMMENT */
+ { "/delete", SND_DEL, 0 },
+#ifdef UNIXOROSK
+ { "/dotfiles", SND_DOT, 0 },
+#endif /* UNIXOROSK */
+ { "/error-action", SND_ERR, CM_ARG },
+ { "/except", SND_EXC, CM_ARG },
+ { "/filenames", SND_NAM, CM_ARG },
+#ifdef PIPESEND
+#ifndef NOSPL
+ { "/filter", SND_FLT, CM_ARG|CM_PSH },
+#endif /* NOSPL */
+#endif /* PIPESEND */
+#ifdef CKSYMLINK
+ { "/followlinks", SND_LNK, 0 },
+#endif /* CKSYMLINK */
+#ifdef VMS
+ { "/image", SND_IMG, 0 },
+#else
+ { "/image", SND_BIN, CM_INV },
+#endif /* VMS */
+ { "/larger-than", SND_LAR, CM_ARG },
+ { "/listfile", SND_FIL, CM_ARG },
+#ifndef NOCSETS
+ { "/local-character-set", SND_CSL, CM_ARG },
+#endif /* NOCSETS */
+#ifdef CK_TMPDIR
+ { "/move-to", SND_MOV, CM_ARG },
+#endif /* CK_TMPDIR */
+ { "/nobackupfiles", SND_NOB, 0 },
+#ifdef UNIXOROSK
+ { "/nodotfiles", SND_NOD, 0 },
+#endif /* UNIXOROSK */
+#ifdef CKSYMLINK
+ { "/nofollowlinks", SND_NLK, 0 },
+#endif /* CKSYMLINK */
+
+ { "/not-after", SND_NAF, CM_ARG },
+ { "/not-before", SND_NBE, CM_ARG },
+#ifdef UNIX
+ { "/permissions", SND_PRM, CM_ARG },
+#else
+ { "/permissions", SND_PRM, CM_ARG|CM_INV },
+#endif /* UNIX */
+ { "/quiet", SND_SHH, 0 },
+#ifdef FTP_RESTART
+ { "/recover", SND_RES, 0 },
+#endif /* FTP_RESTART */
+#ifdef RECURSIVE
+ { "/recursive", SND_REC, 0 },
+#endif /* RECURSIVE */
+ { "/rename-to", SND_REN, CM_ARG },
+#ifdef FTP_RESTART
+ { "/restart", SND_RES, CM_INV },
+#endif /* FTP_RESTART */
+#ifndef NOCSETS
+ { "/server-character-set", SND_CSR, CM_ARG },
+#endif /* NOCSETS */
+ { "/server-rename-to", SND_SRN, CM_ARG },
+ { "/simulate", SND_SIM, 0 },
+ { "/since", SND_AFT, CM_INV|CM_ARG },
+ { "/smaller-than", SND_SMA, CM_ARG },
+#ifdef COMMENT
+ { "/starting-at", SND_STA, CM_ARG },
+#endif /* COMMENT */
+#ifdef RECURSIVE
+ { "/subdirectories", SND_REC, CM_INV },
+#endif /* RECURSIVE */
+ { "/tenex", SND_TEN, 0 },
+ { "/text", SND_TXT, 0 },
+#ifndef NOCSETS
+ { "/transparent", SND_XPA, 0 },
+#endif /* NOCSETS */
+ { "/type", SND_TYP, CM_ARG },
+#ifdef DOUPDATE
+ { "/update", SND_UPD, 0 },
+#endif /* DOUPDATE */
+ { "/unique-server-names", SND_USN, 0 },
+ { "", 0, 0 }
+};
+static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
+
+static struct keytab getswi[] = { /* FTP [M]GET switch table */
+ { "/after", SND_AFT, CM_INV },
+ { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
+ { "/as-name", SND_ASN, CM_ARG },
+ { "/ascii", SND_TXT, CM_INV },
+ { "/before", SND_BEF, CM_INV },
+ { "/binary", SND_BIN, 0 },
+ { "/collision", SND_COL, CM_ARG },
+#ifdef PUTPIPE
+ { "/command", SND_CMD, CM_PSH },
+#endif /* PUTPIPE */
+ { "/delete", SND_DEL, 0 },
+ { "/error-action", SND_ERR, CM_ARG },
+ { "/except", SND_EXC, CM_ARG },
+ { "/filenames", SND_NAM, CM_ARG },
+#ifdef PIPESEND
+#ifndef NOSPL
+ { "/filter", SND_FLT, CM_ARG|CM_PSH },
+#endif /* NOSPL */
+#endif /* PIPESEND */
+#ifdef VMS
+ { "/image", SND_IMG, 0 },
+#else
+ { "/image", SND_BIN, CM_INV },
+#endif /* VMS */
+ { "/larger-than", SND_LAR, CM_ARG },
+ { "/listfile", SND_FIL, CM_ARG },
+#ifndef NOCSETS
+ { "/local-character-set", SND_CSL, CM_ARG },
+#endif /* NOCSETS */
+ { "/match", SND_PAT, CM_ARG },
+ { "/ml", SND_MLS, CM_INV|CM_ABR },
+ { "/mls", SND_MLS, CM_INV|CM_ABR },
+ { "/mlsd", SND_MLS, 0 },
+ { "/mlst", SND_MLS, CM_INV },
+#ifdef CK_TMPDIR
+ { "/move-to", SND_MOV, CM_ARG },
+#endif /* CK_TMPDIR */
+ { "/namelist", SND_NML, CM_ARG },
+ { "/nlst", SND_NLS, 0 },
+ { "/nobackupfiles", SND_NOB, 0 },
+ { "/nodotfiles", SND_NOD, 0 },
+#ifdef DOUPDATE
+ { "/dates-differ", SND_DIF, CM_INV },
+#endif /* DOUPDATE */
+ { "/not-after", SND_NAF, CM_INV },
+ { "/not-before", SND_NBE, CM_INV },
+ { "/permissions", SND_PRM, CM_INV },
+ { "/quiet", SND_SHH, 0 },
+#ifdef FTP_RESTART
+ { "/recover", SND_RES, 0 },
+#endif /* FTP_RESTART */
+#ifdef RECURSIVE
+ { "/recursive", SND_REC, 0 },
+#endif /* RECURSIVE */
+ { "/rename-to", SND_REN, CM_ARG },
+#ifdef FTP_RESTART
+ { "/restart", SND_RES, CM_INV },
+#endif /* FTP_RESTART */
+#ifndef NOCSETS
+ { "/server-character-set", SND_CSR, CM_ARG },
+#endif /* NOCSETS */
+ { "/server-rename-to", SND_SRN, CM_ARG },
+ { "/smaller-than", SND_SMA, CM_ARG },
+#ifdef RECURSIVE
+ { "/subdirectories", SND_REC, CM_INV },
+#endif /* RECURSIVE */
+ { "/text", SND_TXT, 0 },
+ { "/tenex", SND_TEN, 0 },
+#ifndef NOCSETS
+ { "/transparent", SND_XPA, 0 },
+#endif /* NOCSETS */
+ { "/to-screen", SND_MAI, 0 },
+#ifdef DOUPDATE
+ { "/update", SND_UPD, CM_INV },
+#endif /* DOUPDATE */
+ { "", 0, 0 }
+};
+static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
+
+static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
+ { "/error-action", SND_ERR, CM_ARG },
+ { "/except", SND_EXC, CM_ARG },
+ { "/filenames", SND_NAM, CM_ARG },
+ { "/larger-than", SND_LAR, CM_ARG },
+ { "/nobackupfiles", SND_NOB, 0 },
+#ifdef UNIXOROSK
+ { "/nodotfiles", SND_NOD, 0 },
+#endif /* UNIXOROSK */
+ { "/quiet", SND_SHH, 0 },
+#ifdef RECURSIVE
+ { "/recursive", SND_REC, 0 },
+#endif /* RECURSIVE */
+ { "/smaller-than", SND_SMA, CM_ARG },
+#ifdef RECURSIVE
+ { "/subdirectories", SND_REC, CM_INV },
+#endif /* RECURSIVE */
+ { "", 0, 0 }
+};
+static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
+
+static struct keytab fntab[] = { /* Filename conversion keyword table */
+ { "automatic", 2, CNV_AUTO },
+ { "converted", 1, CNV_CNV },
+ { "literal", 0, CNV_LIT }
+};
+static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
+
+static struct keytab ftptyp[] = { /* SET FTP TYPE table */
+ { "ascii", FTT_ASC, 0 },
+ { "binary", FTT_BIN, 0 },
+ { "tenex", FTT_TEN, 0 },
+ { "text", FTT_ASC, CM_INV },
+ { "", 0, 0 }
+};
+static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
+
+#ifdef FTP_SECURITY
+static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
+ { "clear", FPL_CLR, 0 },
+ { "confidential", FPL_CON, 0 },
+ { "private", FPL_PRV, 0 },
+ { "safe", FPL_SAF, 0 },
+ { "", 0, 0 }
+};
+static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
+#endif /* FTP_SECURITY */
+
+/* Definitions for FTP from RFC765. */
+
+/* Reply codes */
+
+#define REPLY_PRELIM 1 /* Positive preliminary */
+#define REPLY_COMPLETE 2 /* Positive completion */
+#define REPLY_CONTINUE 3 /* Positive intermediate */
+#define REPLY_TRANSIENT 4 /* Transient negative completion */
+#define REPLY_ERROR 5 /* Permanent negative completion */
+#define REPLY_SECURE 6 /* Security encoded message */
+
+/* Form codes and names */
+
+#define FORM_N 1 /* Non-print */
+#define FORM_T 2 /* Telnet format effectors */
+#define FORM_C 3 /* Carriage control (ASA) */
+
+/* Structure codes and names */
+
+#define STRU_F 1 /* File (no record structure) */
+#define STRU_R 2 /* Record structure */
+#define STRU_P 3 /* Page structure */
+
+/* Mode types and names */
+
+#define MODE_S 1 /* Stream */
+#define MODE_B 2 /* Block */
+#define MODE_C 3 /* Compressed */
+
+/* Protection levels and names */
+
+#define PROT_C 1 /* Clear */
+#define PROT_S 2 /* Safe */
+#define PROT_P 3 /* Private */
+#define PROT_E 4 /* Confidential */
+
+#ifdef COMMENT /* Not used */
+#ifdef FTP_NAMES
+char *strunames[] = {"0", "File", "Record", "Page" };
+char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
+char *modenames[] = {"0", "Stream", "Block", "Compressed" };
+char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
+#endif /* FTP_NAMES */
+
+/* Record Tokens */
+
+#define REC_ESC '\377' /* Record-mode Escape */
+#define REC_EOR '\001' /* Record-mode End-of-Record */
+#define REC_EOF '\002' /* Record-mode End-of-File */
+
+/* Block Header */
+
+#define BLK_EOR 0x80 /* Block is End-of-Record */
+#define BLK_EOF 0x40 /* Block is End-of-File */
+#define BLK_REPLY_ERRORS 0x20 /* Block might have errors */
+#define BLK_RESTART 0x10 /* Block is Restart Marker */
+#define BLK_BYTECOUNT 2 /* Bytes in this block */
+#endif /* COMMENT */
+
+#define RADIX_ENCODE 0 /* radix_encode() function codes */
+#define RADIX_DECODE 1
+
+/*
+ The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
+ results in a serious performance degradation due to the increased number
+ of page faults and the inability to overlap encrypt/decrypt, file i/o, and
+ network i/o. So instead we set the value to 1<<13 (8K), about half the size
+ of the typical TCP window. Maybe we should add a command to allow the value
+ to be changed.
+*/
+#define DEFAULT_PBSZ 1<<13
+
+/* Prototypes */
+
+_PROTOTYP(int remtxt, (char **) );
+_PROTOTYP(char * gskreason, (int) );
+_PROTOTYP(static int ftpclose,(void));
+_PROTOTYP(static int zzsend, (int, CHAR));
+_PROTOTYP(static int getreply,(int,int,int,int,int));
+_PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
+_PROTOTYP(static int setpbsz,(unsigned int));
+_PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
+ int,int,char *,int,int,int));
+_PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
+_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);
+ ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
+ ckstrncat(ftplogbuf,p,CXLOGBUFL);
+ } else
+ ftplogprev = 0L;
+ debug(F101,"ftp cx log dialog","",dialog);
+ if (dialog) { /* If logging */
+ int x;
+ x = diaopn(diafil,1,1); /* Open log in append mode */
+ if (x > 0) {
+ debug(F101,"ftp cx log open","",x);
+ x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
+ debug(F101,"ftp cx log write","",x);
+ x = zclose(ZDIFIL); /* Close the log */
+ debug(F101,"ftp cx log close","",x);
+ }
+ }
+}
+
+VOID
+dologftp() {
+ ftplogend(); /* Previous session not closed out? */
+ ftplogprev = 0L;
+ ftplogactive = 1; /* Record is active */
+
+ ckmakxmsg(ftplogbuf,CXLOGBUFL,
+ ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
+ " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
+ " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
+ debug(F110,"ftp cx log begin",ftplogbuf,0);
+}
+#endif /* CKLOGDIAL */
+
+static char * dummy[2] = { NULL, NULL };
+
+static struct keytab modetab[] = {
+ { "active", 0, 0 },
+ { "passive", 1, 0 }
+};
+
+#ifndef NOCMDL
+int /* Called from ckuusy.c */
+#ifdef CK_ANSIC
+doftparg(char c)
+#else
+doftparg(c) char c;
+#endif /* CK_ANSIC */
+/* doftparg */ {
+ 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;
+ ftp_xfermode = XMODE_M;
+ filepeek = 0;
+ patterns = 0;
+ break;
+
+ case 'g': /* Get */
+ case 'p': /* Put */
+ case 's': { /* Send (= Put) */
+ int havefiles, rc;
+ if (ftp_action) {
+ fatal("Only one FTP action at a time please");
+ }
+ if (*(xp+1)) {
+ fatal("invalid argument bundling after -s");
+ }
+ nfils = 0; /* Initialize file counter */
+ havefiles = 0; /* Assume nothing to send */
+ cmlist = xargv + 1; /* Remember this pointer */
+
+ while (++xargv, --xargc > 0) { /* Traverse the list */
+ if (c == 'g') {
+ havefiles++;
+ nfils++;
+ continue;
+ }
+#ifdef RECURSIVE
+ if (!strcmp(*xargv,".")) {
+ havefiles = 1;
+ nfils++;
+ recursive = 1;
+ } else
+#endif /* RECURSIVE */
+ if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
+ if (rc != -2)
+ havefiles = 1;
+ nfils++;
+ } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
+ havefiles = 1;
+ nfils++;
+ }
+ }
+ xargc++, xargv--; /* Adjust argv/argc */
+ if (!havefiles) {
+ if (c == 'g') {
+ fatal("No files to put");
+ } else {
+ fatal("No files to get");
+ }
+ }
+ ftp_action = c;
+ break;
+ }
+ case 'D': /* Directory */
+ makestr(&ftp_rdir,*xargv);
+ break;
+
+ case 'm': /* Mode (Active/Passive */
+ ftp_psv = lookup(modetab,*xargv,2,NULL);
+ if (ftp_psv < 0) fatal("Invalid mode");
+ break;
+
+ case 'P':
+ makestr(&ftp_tmp,*xargv); /* You-Know-What */
+ break;
+
+ case 'Y': /* No initialization file */
+ break; /* (already done in prescan) */
+
+#ifdef CK_URL
+ case 'U': { /* URL */
+ /* These are set by urlparse() - any not set are NULL */
+ if (g_url.hos) {
+/*
+ Kermit has accepted host:port notation since many years before URLs were
+ invented. Unfortunately, URLs conflict with this notation. Thus "ftp
+ host:449" looks like a URL and results in service = host and host = 449.
+ Here we try to catch this situation transparently to the user.
+*/
+ if (ckstrcmp(g_url.svc,"ftp",-1,0)
+#ifdef CK_SSL
+ && ckstrcmp(g_url.svc,"ftps",-1,0)
+#endif /* CK_SSL */
+ ) {
+ if (!g_url.usr &&
+ !g_url.psw &&
+ !g_url.por &&
+ !g_url.pth) {
+ g_url.por = g_url.hos;
+ g_url.hos = g_url.svc;
+ g_url.svc = "ftp";
+ } else {
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
+ g_url.svc," host=",g_url.hos);
+ fatal(tmpbuf);
+ }
+ }
+ makestr(&ftp_host,g_url.hos);
+ if (g_url.usr) {
+ haveftpuid = 1;
+ ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
+ makestr(&ftp_logname,uidbuf);
+ }
+ if (g_url.psw) {
+ makestr(&ftp_tmp,g_url.psw);
+ }
+ if (g_url.pth) {
+ if (!g_url.usr) {
+ haveftpuid = 1;
+ ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
+ makestr(&ftp_logname,uidbuf);
+ }
+ if (ftp_action) {
+ fatal("Only one FTP action at a time please");
+ }
+ if (!stayflg)
+ quiet = 1;
+ nfils = 1;
+ dummy[0] = g_url.pth;
+ cmlist = dummy;
+ ftp_action = 'g';
+ }
+ xp = NULL;
+ haveurl = 1;
+ }
+ break;
+ }
+#endif /* CK_URL */
+
+#ifdef FTP_SECURITY
+ case 'k': { /* K4 Realm */
+#ifdef FTP_KRB4
+ ckstrncpy(ftp_realm,*xargv, REALM_SZ);
+#endif /* FTP_KRB4 */
+ if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
+ break;
+ }
+ case 'f': {
+#ifdef FTP_GSSAPI
+ ftp_cfw = 1;
+ if (ftp_deb) printf("K5 Credentials Forwarding\n");
+#else /* FTP_GSSAPI */
+ printf("K5 Credentials Forwarding not supported\n");
+#endif /* FTP_GSSAPI */
+ break;
+ }
+ case 'x': {
+ ftp_cry = 1;
+ if (ftp_deb) printf("Autoencryption\n");
+ break;
+ }
+ case 'c': { /* Cipher */
+#ifdef FTP_SRP
+ if (!srp_selcipher(*xargv)) {
+ if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
+ } else
+ printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
+#else /* FTP_SRP */
+ printf("?SRP not supported\n");
+#endif /* FTP_SRP */
+ break;
+ }
+ case 'H': {
+#ifdef FTP_SRP
+ if (!srp_selhash(*xargv)) {
+ if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
+ } else
+ printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
+#else /* FTP_SRP */
+ printf("?SRP not supported\n");
+#endif /* FTP_SRP */
+ break;
+ }
+ case 'z': {
+ /* *xargv contains a value of the form tag=value */
+ /* we need to lookup the tag and save the value */
+ char * p = NULL, * q = NULL;
+ 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; CK_OFF_T z; char * s; {
+ if (displa && fdispla && !backgrd && !quiet && !out2screen) {
+ if (!dpyactive) {
+ ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
+ dpyactive = 1;
+ }
+ ckscreen(n,c,z,s);
+ }
+}
+
+#ifndef OS2
+/* g m s t i m e r -- Millisecond timer */
+
+long
+gmstimer() {
+#ifdef HAVE_MSECS
+ /* For those versions of ztime() that also set global ztmsec. */
+ char *p = NULL;
+ long z;
+ ztime(&p);
+ if (!p) return(0L);
+ if (!*p) return(0L);
+ z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ return(z * 1000 + ztmsec);
+#else
+ return((long)time(NULL) * 1000L);
+#endif /* HAVE_MSECS */
+}
+#endif /* OS2 */
+
+/* d o s e t f t p -- The SET FTP command */
+
+int
+dosetftp() {
+ int cx;
+ if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
+ return(cx);
+ switch (cx) {
+
+ case FTS_FNC: /* Filename collision action */
+ if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ftp_fnc = x;
+ return(1);
+
+ case FTS_CNV: /* Filename conversion */
+ if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ftp_cnv = x;
+ return(1);
+
+ case FTS_DBG: /* Debug messages */
+ return(seton(&ftp_deb));
+
+ case FTS_LOG: /* Auto-login */
+ return(seton(&ftp_log));
+
+ case FTS_PSV: /* Passive mode */
+ return(dosetftppsv());
+
+ case FTS_SPC: /* Send port commands */
+ x = seton(&ftp_spc);
+ if (x > 0) sendport = ftp_spc;
+ return(x);
+
+ case FTS_TYP: /* Type */
+ if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ ftp_typ = x;
+ g_ftp_typ = x;
+ tenex = (ftp_typ == FTT_TEN);
+ return(1);
+
+ case FTS_USN: /* Unique server names */
+ return(seton(&ftp_usn));
+
+ case FTS_VBM: /* Verbose mode */
+ if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
+ return(x);
+ ftp_vbx = ftp_vbm; /* Global sticky copy */
+ return(x);
+
+ case FTS_TST: /* "if (testing)" messages */
+ return(seton(&testing));
+
+ case FTS_PRM: /* Send permissions */
+ return(setonaut(&ftp_prm));
+
+ case FTS_AUT: /* Auto-authentication */
+ return(seton(&ftp_aut));
+
+ case FTS_ERR: /* Error action */
+ if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ftp_err = x;
+ return(success = 1);
+
+#ifndef NOCSETS
+ case FTS_XLA: /* Translation */
+ return(seton(&ftp_xla));
+
+ case FTS_CSR: /* Server charset */
+ if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ftp_csr = x;
+ ftp_xla = 1; /* Also enable translation */
+ return(success = 1);
+#endif /* NOCSETS */
+
+ case FTS_GFT:
+ return(seton(&get_auto)); /* GET-filetype-switching */
+
+ case FTS_DAT:
+ return(seton(&ftp_dates)); /* Set file dates */
+
+#ifdef FTP_TIMEOUT
+ case FTS_TMO: /* Timeout */
+ if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ftp_timeout = z;
+ return(success = 1);
+#endif /* FTP_TIMEOUT */
+
+ case FTS_STO: { /* Server time offset */
+ char * s, * p = NULL;
+ long k;
+ if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
+ return(x);
+ if (!strcmp(s,"+0")) {
+ s = NULL;
+ } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
+ printf("?Invalid time offset\n");
+ return(-9);
+ }
+ makestr(&p,s); /* Make a safe copy the string */
+ if ((x = cmcfm()) < 0) { /* Get confirmation */
+ if (p)
+ makestr(&p,NULL);
+ return(x);
+ }
+ fts_sto = p; /* Confirmed - set the string. */
+ return(success = 1);
+ }
+ case FTS_APW: {
+ char * s;
+ if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
+ return(x);
+ makestr(&ftp_apw, *s ? s : NULL);
+ return(success = 1);
+ }
+
+ case FTS_BUG: {
+ if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+#ifdef CK_SSL
+ case FTB_SV2:
+ return seton(&ftp_bug_use_ssl_v2);
+#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);
+}
+
+VOID /* 12 Aug 2007 */
+doftpglobaltype(x) int x; {
+ ftp_xfermode = XMODE_M; /* Set manual FTP transfer mode */
+ ftp_typ = x; /* Used by top-level BINARY and */
+ g_ftp_typ = x; /* ASCII commands. */
+ get_auto = 0;
+ forcetype = 1;
+}
+
+int
+doftpacct() {
+ int x;
+ char * s;
+ if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ makestr(&ftp_acc,brstrip(s));
+ if (testing)
+ printf(" ftp account: \"%s\"\n",ftp_acc);
+ success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
+ return(success);
+}
+
+int
+doftpusr() { /* Log in as USER */
+ extern char uidbuf[];
+ extern char pwbuf[];
+ extern int pwflg, pwcrypt;
+ int x;
+ char *s, * acct = "";
+
+ debok = 0; /* Don't log */
+
+ if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
+ if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
+ if (x == -3) { /* no input */
+ if ( pwbuf[0] && pwflg ) {
+ ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
+#ifdef OS2
+ if ( pwcrypt )
+ ck_encrypt((char *)tmpbuf);
+#endif /* OS2 */
+ }
+ } else {
+ return(x);
+ }
+ } else {
+ ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+ }
+ if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
+ "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ if (*s) {
+ x = strlen(tmpbuf);
+ if (x > 0) {
+ acct = &tmpbuf[x+2];
+ ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
+ }
+ }
+ if (testing)
+ printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
+ success = ftp_user(line,tmpbuf,acct);
+#ifdef CKLOGDIAL
+ dologftp();
+#endif /* CKLOGDIAL */
+ return(success);
+}
+
+/* DO (various FTP commands)... */
+
+int
+doftptyp(type) int type; { /* TYPE */
+ CHECKCONN();
+ ftp_typ = type;
+ changetype(ftp_typ,ftp_vbm);
+ debug(F101,"doftptyp changed type","",type);
+ 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 */
+
+/*
+ Call with:
+ local = pointer to pathname of local file to be sent.
+ sim = 1 for simulation, 0 for real uploading.
+ Returns 0 on failure, 1 on success.
+
+ The 'local' argument is relative to the initial directory of the MPUT,
+ i.e. the root of the tree being uploaded. If the directory of the
+ argument file is different from the directory of the previous file
+ (which is stored in global putpath[]), this routine does the appropriate
+ CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
+*/
+static int cdlevel = 0, cdsimlvl = 0; /* Tree-level trackers */
+
+static int
+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, * psep, * ssep;
+ int i, k = 0, done = 0, itsadir = 0, saveq;
+
+ debug(F110,"ftp syncdir local (new)",local,0);
+ debug(F110,"ftp syncdir putpath (old)",putpath,0);
+
+ itsadir = isdir(local); /* Is the local file a directory? */
+ saveq = quiet;
+
+ while ((*s = *p)) { /* Copy the argument filename */
+ if (++k == CKMAXPATH) /* so we can poke it. */
+ return(-1);
+ if (*s == '/') /* Pointer to rightmost dirsep */
+ q = s;
+ s++;
+ p++;
+ }
+ if (!itsadir) /* If it's a regular file */
+ *q = NUL; /* keep just the path part */
+
+ debug(F110,"ftp syncdir buf",buf,0);
+ if (!strcmp(buf,putpath)) { /* Same path as previous file? */
+ if (itsadir) { /* This file is a directory? */
+ if (doftpcwd(local,0)) { /* Try to CD to it */
+ doftpcdup(); /* Worked - CD back up */
+ } else if (sim) { /* Simulating... */
+ if (fdispla == XYFD_B) {
+ printf("WOULD CREATE DIRECTORY %s\n",local);
+ } else if (fdispla) {
+ ckmakmsg(msgbuf,CKMAXPATH,
+ "WOULD CREATE DIRECTORY",local,NULL,NULL);
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
+ }
+ /* See note above */
+ return(0);
+ } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
+ return(0);
+ } else { /* Remote directory created OK */
+ if (fdispla == XYFD_B) {
+ printf("CREATED DIRECTORY %s\n",local);
+ } else if (fdispla) {
+ ckmakmsg(msgbuf,CKMAXPATH+64,
+ "CREATED DIRECTORY ",local,NULL,NULL);
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
+ }
+ }
+ }
+ debug(F110,"ftp syncdir no change",buf,0);
+ return(1); /* Yes, done. */
+ }
+ ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */
+ debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
+
+ p = buf; /* New */
+ s = putpath; /* Old */
+
+ debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
+ debug(F110,"ftp syncdir A (new) p",p,0); /* New */
+
+ psep = buf;
+ ssep = putpath;
+ while (*p != NUL && *s != NUL && *p == *s) {
+ if (*p == '/') { psep = p+1; ssep = s+1; }
+ p++,s++;
+ }
+ /*
+ psep and ssep point to the first path segment that differs.
+ We have to do as many CDUPs as there are path segments in ssep.
+ then we have to do as many MKDs and CWDs as there are segments in psep.
+ */
+ s = ssep;
+ p = psep;
+
+ debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
+ debug(F110,"ftp syncdir B (new) p",p,0); /* New */
+
+ /* p and s now point to the leftmost spot where the paths differ */
+
+ if (*s) { /* We have to back up */
+ k = 1; /* How many levels counting this one */
+ while ((c = *s++)) { /* Count dirseps remaining in prev */
+ if (c == '/' && *s)
+ k++;
+ }
+ debug(F101,"ftp syncdir levels up","",k);
+
+ for (i = 1; i <= k; i++) { /* Do that many CDUPs */
+ debug(F111,"ftp syncdir CDUP A",p,i);
+ if (fdispla == XYFD_B)
+ printf(" CDUP\n");
+ if (sim && cdsimlvl) {
+ cdsimlvl--;
+ } else {
+ if (!doftpcdup()) {
+ quiet = saveq;
+ return(0);
+ }
+ }
+ cdlevel--;
+ }
+ if (!*p) /* If we don't have to go down */
+ goto xcwd; /* we're done. */
+ }
+#ifdef COMMENT
+ while (p > buf && *p && *p != '/') /* If in middle of segment */
+ p--; /* back up to beginning */
+ if (*p == '/') /* and terminate there */
+ p++;
+#endif /* COMMENT */
+
+ debug(F110,"ftp syncdir NEW PATH",p,0);
+
+ s = p; /* Point to start of new down path. */
+ while (1) { /* Loop through characters. */
+ if (*s == '/' || !*s) { /* Have a segment. */
+ if (!*s) /* If end of string, */
+ done++; /* after this segment we're done. */
+ else
+ *s = NUL; /* NUL out the separator. */
+ if (*p) { /* If segment is not empty */
+ debug(F110,"ftp syncdir down segment",p,0);
+ if (!doftpcwd(p,0)) { /* Try to CD to it */
+ if (sim) {
+ if (fdispla == XYFD_B) {
+ printf(" WOULD CREATE DIRECTORY %s\n",local);
+ } else if (fdispla) {
+ ckmakmsg(msgbuf,CKMAXPATH,
+ "WOULD CREATE DIRECTORY",
+ local,NULL,NULL);
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
+ }
+ cdsimlvl++;
+ } else {
+ if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
+ debug(F110,"ftp syncdir mkdir failed",p,0);
+/*
+ Suppose we are executing SEND /RECURSIVE. Locally we have a directory
+ FOO but the remote has a regular file with the same name. We can't CD
+ to it, can't MKDIR it either. There's no way out but to fail and let
+ the user handle the problem.
+*/
+ quiet = saveq;
+ return(0);
+ }
+ debug(F110,"ftp syncdir mkdir OK",p,0);
+ if (fdispla == XYFD_B) {
+ printf(" CREATED DIRECTORY %s\n",p);
+ } else if (fdispla) {
+ ckmakmsg(msgbuf,CKMAXPATH,
+ "CREATED DIRECTORY ",p,NULL,NULL);
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
+ }
+ if (!doftpcwd(p,0)) { /* Try again to CD */
+ debug(F110,"ftp syncdir CD failed",p,0);
+ quiet = saveq;
+ return(0);
+ }
+ if (fdispla == XYFD_B) printf(" CWD %s\n",p);
+ debug(F110,"ftp syncdir CD OK",p,0);
+ }
+ }
+ cdlevel++;
+ }
+ if (done) /* Quit if no next segment */
+ break;
+ p = s+1; /* Point to next segment */
+ }
+ s++; /* Point to next source char */
+ }
+
+ xcwd:
+ ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
+ quiet = saveq;
+ return(1);
+}
+
+#ifdef DOUPDATE
+#ifdef DEBUG
+static VOID
+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 /* def BSD44 */
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2];
+ } tp;
+#else /* def V7 */
+#ifdef SYSUTIMEH
+#ifdef NT
+ struct _utimbuf tp;
+#else /* NT */
+ struct utimbuf tp;
+#endif /* NT */
+#else /* def SYSUTIMEH */
+#ifdef VMS
+ struct utimbuf tp;
+#define SYSUTIMEH /* Our utimbuf matches this one. */
+#else /* def VMS */
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* def VMS [else] */
+#endif /* def SYSUTIMEH [else] */
+#endif /* def V7 [else] */
+#endif /* def BSD44 [else] */
+
+ if (stat(f,&sb) < 0) {
+ debug(F111,"setmodtime stat failure",f,errno);
+ return(-1);
+ }
+#ifdef BSD44
+ tp[0].tv_sec = sb.st_atime; /* Access time first */
+ tp[1].tv_sec = t; /* Update time second */
+ debug(F111,"setmodtime BSD44",f,t);
+#else
+#ifdef V7
+ tp.timep[0] = t; /* Set modif. time to creation date */
+ tp.timep[1] = sb.st_atime; /* Don't change the access time */
+ debug(F111,"setmodtime V7",f,t);
+#else
+#ifdef SYSUTIMEH
+ tp.modtime = t; /* Set modif. time to creation date */
+ tp.actime = sb.st_atime; /* Don't change the access time */
+ debug(F111,"setmodtime SYSUTIMEH",f,t);
+#else
+ tp.mtime = t; /* Set modif. time to creation date */
+ tp.atime = sb.st_atime; /* Don't change the access time */
+ debug(F111,"setmodtime (other)",f,t);
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+ /* Try to set the file date */
+
+#ifdef BSD44
+ x = utimes(f,tp);
+ debug(F111,"setmodtime utimes()","BSD44",x);
+#else
+#ifdef IRIX65
+ {
+ /*
+ The following produces the nonsensical warning:
+ Argument of type "const struct utimbuf *" is incompatible with
+ parameter of type "const struct utimbuf *". If you can make it
+ go away, be my guest.
+ */
+ const struct utimbuf * t2 = &tp;
+ x = utime(f,t2);
+ }
+#else
+ x = utime(f,&tp);
+ debug(F111,"setmodtime utime()","other",x);
+#endif /* IRIX65 */
+#endif /* BSD44 */
+ if (x)
+ rc = -1;
+
+ debug(F101,"setmodtime result","",rc);
+ return(rc);
+}
+
+
+/*
+ c h k m o d t i m e -- Check/Set file modification time.
+
+ fc = function code:
+ 0 = Check; returns:
+ -1 on error,
+ 0 if local older than remote,
+ 1 if modtimes are equal,
+ 2 if local newer than remote.
+ 1 = Set (local file's modtime from remote's); returns:
+ -1 on error,
+ 0 on success.
+*/
+static int
+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 */
+ /* Convert to struct tm */
+ tmlocal = gmtime((time_t *)&statbuf.st_mtime);
+#ifdef DEBUG
+ if (tmlocal) {
+ dbtime(local,tmlocal);
+ }
+#endif /* DEBUG */
+ }
+ }
+ /* Get remote file's mod time as yyyymmddhhmmss */
+
+ if (havemdtm) { /* Already got it from MLSD? */
+ s = havemdtm;
+ flag++;
+ } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
+ char c;
+ bzero((char *)&tmremote, sizeof(struct tm));
+ s = ftp_reply_str;
+ while ((c = *s++)) { /* Skip past response code */
+ if (c == SP) {
+ flag++;
+ break;
+ }
+ }
+ }
+ if (flag) {
+ debug(F111,"ftp chkmodtime string",s,flag);
+ if (fts_sto) { /* User gave server time offset? */
+ char * p;
+ debug(F110,"ftp chkmodtime offset",fts_sto,0);
+ ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
+ if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
+ ckstrncpy(timebuf,p,64); /* Convert to MDTM format */
+ timebuf[8] = timebuf[9]; /* h */
+ timebuf[9] = timebuf[10]; /* h */
+ timebuf[10] = timebuf[12]; /* m */
+ timebuf[11] = timebuf[13]; /* m */
+ timebuf[12] = timebuf[12]; /* s */
+ timebuf[13] = timebuf[13]; /* s */
+ timebuf[14] = NUL;
+ s = timebuf;
+ debug(F110,"ftp chkmodtime adjust",s,0);
+ }
+ }
+ if (flag) { /* Convert to struct tm */
+ char * pat;
+ int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */
+ if (!ckstrcmp(s,"191",3,0)) {
+ pat = "%05d%02d%02d%02d%02d%02d";
+ y2kbug++;
+ debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
+ } else {
+ pat = "%04d%02d%02d%02d%02d%02d";
+ }
+ if (sscanf(s, /* Parse into struct tm */
+ pat,
+ &(tmremote.tm_year),
+ &(tmremote.tm_mon),
+ &(tmremote.tm_mday),
+ &(tmremote.tm_hour),
+ &(tmremote.tm_min),
+ &(tmremote.tm_sec)
+ ) == 6) {
+ tmremote.tm_year -= (y2kbug ? 19000 : 1900);
+ debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
+ tmremote.tm_mon--;
+
+#ifdef DEBUG
+ debug(F100,"SERVER TIME FOLLOWS:","",0);
+ dbtime(remote,&tmremote);
+#endif /* DEBUG */
+
+ if (havedate > -1)
+ havedate = 1;
+ }
+ }
+ } else { /* Failed */
+ debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
+ if (ftpcode == 500 || /* Command unrecognized */
+ ftpcode == 502 || /* Command not implemented */
+ ftpcode == 202) /* Command superfluous */
+ mdtmok = 0; /* Don't ask this server again */
+ return(-1);
+ }
+ if (fc == 0) { /* Compare */
+ if (havedate == 1) { /* Only if we have both file dates */
+ /*
+ Compare with local file's time. We don't use
+ clock time (time_t) here in case of signed/unsigned
+ confusion, etc.
+ */
+ int xx;
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ dbtime("LOCAL",tmlocal);
+ dbtime("REMOT",&tmremote);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ xx = tmcompare(tmlocal,&tmremote);
+ debug(F101,"chkmodtime tmcompare","",xx);
+ return(xx + 1);
+ }
+ } else if (ftp_dates) { /* Set */
+ /*
+ Here we must convert struct tm to time_t
+ without applying timezone conversion, for which
+ there is no portable API. The method is hidden
+ in mkutime(), defined above.
+ */
+ time_t utc;
+ utc = mkutime(&tmremote);
+ debug(F111,"ftp chkmodtime mkutime",remote,utc);
+ if (utc != (time_t)-1)
+ return(setmodtime(local,utc));
+ }
+ return(-1);
+}
+
+/* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
+
+static int
+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 (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
+ int x;
+ x = matchname(remote,0,servertype);
+ debug(F111,"ftp getfile matchname",remote,x);
+ switch (x) {
+ case 0: ftp_typ = FTT_ASC; break;
+ case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
+ default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
+ }
+ changetype(ftp_typ,ftp_vbm);
+ binary = ftp_typ; /* For file-transfer display */
+ }
+#endif /* PATTERNS */
+
+#ifndef NOCSETS
+ ftp_csx = -1; /* For file-transfer display */
+ ftp_csl = -1; /* ... */
+
+ if (rcs > -1) /* -1 means no translation */
+ if (ftp_typ == FTT_ASC) /* File type is "ascii"? */
+ if (fcs < 0) /* File charset not forced? */
+ fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
+ if (fcs > -1 && rcs > -1) { /* Set up translation functions */
+ debug(F110,"ftp getfile","initxlate",0);
+ initxlate(rcs,fcs); /* NB: opposite order of PUT */
+ ftp_csx = rcs;
+ ftp_csl = fcs;
+ } else
+ xlate = 0;
+#endif /* NOCSETS */
+
+ if (!local) local = "";
+ if (!pipename && !*local)
+ local = remote;
+
+ out2screen = !strcmp(local,"-");
+
+ fullname[0] = NUL;
+ if (pipename) {
+ ckstrncpy(fullname,pipename,CKMAXPATH+1);
+ } else {
+ zfnqfp(local,CKMAXPATH,fullname);
+ if (!fullname[0])
+ ckstrncpy(fullname,local,CKMAXPATH+1);
+ }
+ if (!out2screen && displa && fdispla) { /* Screen */
+ ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
+ ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
+ ftscreen(SCR_FS,0,fsize,"");
+ }
+ tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
+ tlog(F110," as",fullname,0);
+ debug(F111,"ftp getfile size",remote,fsize);
+ debug(F111,"ftp getfile local",local,out2screen);
+
+ ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
+
+ t0 = gmstimer(); /* Start time */
+ debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
+ rc = recvrequest("RETR",
+ local,
+ remote,
+ append ? "ab" : "wb",
+ 0,
+ recover,
+ pipename,
+ xlate,
+ fcs,
+ rcs
+ );
+ t1 = gmstimer(); /* End time */
+ debug(F111,"ftp getfile t1",remote,t1);
+ debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
+#ifdef GFTIMER
+ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
+ fpxfsecs = sec; /* (for doxlog()) */
+#else
+ sec = (t1 - t0) / 1000;
+ xfsecs = (int)sec;
+#endif /* GFTIMER */
+
+#ifdef FTP_TIMEOUT
+ if (ftp_timed_out)
+ rc = -4;
+#endif /* FTP_TIMEOUT */
+
+ debug(F111,"ftp recvrequest rc",remote,rc);
+ if (cancelfile || cancelgroup) {
+ debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
+ ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
+ } else if (rc > 0) {
+ debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
+ } else if (rc < 0) {
+ switch (ftpcode) {
+ case -4: /* Network error */
+ case -2: /* File error */
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
+ break;
+ case -3:
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
+ "Failure to make data connection");
+ break;
+ case -1: /* (should be covered above) */
+ ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
+ break;
+ default:
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
+ }
+ } else { /* Tudo bem */
+ ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
+ if (rc == 0) {
+ ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
+ makestr(&rrfspec,remote); /* For WHERE command */
+ makestr(&rfspec,fullname);
+ }
+ }
+ if (rc > -1) {
+ if (ftp_dates) /* If FTP DATES ON... */
+ if (!pipename && !out2screen) /* and it's a real file */
+ if (rc < 1 && rc != -3) /* and it wasn't skipped */
+ if (connected) /* and we still have a connection */
+ if (zchki(local) > -1) { /* and the file wasn't discarded */
+ chkmodtime(local,remote,1); /* set local file date */
+ debug(F110,"ftp get set date",local,0);
+ }
+ filcnt++; /* Used by \v(filenum) */
+ }
+#ifdef TLOG
+ if (tralog) {
+ if (rc > 0) {
+ tlog(F100," recovery skipped","",0);
+ } else if (rc == 0) {
+ tlog(F101," complete, size", "", fsize);
+ } else if (cancelfile) {
+ tlog(F100," canceled by user","",0);
+#ifdef FTP_TIMEOUT
+ } else if (ftp_timed_out) {
+ tlog(F100," timed out","",0);
+#endif /* FTP_TIMEOUT */
+ } else {
+ tlog(F110," failed:",ftp_reply_str,0);
+ }
+ if (!tlogfmt)
+ doxlog(what,local,fsize,ftp_typ,rc,"");
+ }
+#endif /* TLOG */
+ return(rc);
+}
+
+/* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
+/* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
+
+static int
+putfile(cx,
+ local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
+ char * local, * remote, * mvto, *rnto, *srvrn;
+ int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
+
+/* 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 = (CK_OFF_T)0;
+ restart = flg & PUT_RES;
+ if (!remote)
+ remote = "";
+
+ /* FTP protocol command to send to server */
+ cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
+
+ if (x_cnv == SET_AUTO) { /* Name conversion is auto */
+ if (alike) { /* If server & client are alike */
+ nc = 0; /* no conversion */
+ } else { /* If they are different */
+ if (servertype == SYS_UNIX || servertype == SYS_WIN32)
+ nc = -1; /* only minimal conversions needed */
+ else /* otherwise */
+ nc = 1; /* full conversion */
+ }
+ } else /* Not auto - do what user said */
+ nc = x_cnv;
+
+ /* If Transfer Mode is Automatic, determine file type */
+ if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
+ if (isdir(local)) { /* If it's a directory */
+ k = FT_BIN; /* skip the file scan */
+ } else {
+ debug(F110,"FTP PUT calling scanfile",local,0);
+ k = scanfile(local,&o,nscanfile); /* Scan the file */
+ }
+ debug(F111,"FTP PUT scanfile",local,k);
+ if (k > -1 && !forcetype) {
+ ftp_typ = (k == FT_BIN) ? 1 : 0;
+ if (xft > -1 && ftp_typ != xft) {
+ if (flg & PUT_SIM)
+ tlog(F110,"ftp put SKIP (Type):", local, 0);
+ return(SKP_TYP);
+ }
+ if (ftp_typ == 1 && tenex) /* User said TENEX? */
+ ftp_typ = FTT_TEN;
+ }
+ }
+#ifndef NOCSETS
+ ftp_csx = -1; /* For file-transfer display */
+ ftp_csl = -1; /* ... */
+
+ if (rcs > -1) { /* -1 means no translation */
+ if (ftp_typ == 0) { /* File type is "ascii"? */
+ if (fcs < 0) { /* File charset not forced? */
+ if (k < 0) { /* If we didn't scan */
+ fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
+ } else { /* If we did scan, use scan result */
+ switch (k) {
+ case FT_TEXT: /* Unknown text */
+ fcs = fcharset;
+ break;
+ case FT_7BIT: /* 7-bit text */
+ fcs = dcset7;
+ break;
+ case FT_8BIT: /* 8-bit text */
+ fcs = dcset8;
+ break;
+ case FT_UTF8: /* UTF-8 */
+ fcs = FC_UTF8;
+ break;
+ case FT_UCS2: /* UCS-2 */
+ fcs = FC_UCS2;
+ if (o > -1) /* Input file byte order */
+ fileorder = o;
+ break;
+ default:
+ rcs = -1;
+ }
+ }
+ }
+ }
+ }
+ if (fcs > -1 && rcs > -1) { /* Set up translation functions */
+ debug(F110,"ftp putfile","initxlate",0);
+ initxlate(fcs,rcs);
+ debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
+ xlate = 1;
+ ftp_csx = rcs;
+ ftp_csl = fcs;
+ }
+#endif /* NOCSETS */
+
+ binary = ftp_typ; /* For file-transfer display */
+ asname[0] = NUL;
+
+ if (recursive) { /* If sending recursively, */
+ if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
+ return(-1); /* Don't PUT if it fails. */
+ else if (isdir(local)) /* It's a directory */
+ return(0); /* Don't send it! */
+ }
+ if (*remote) { /* If an as-name template was given */
+#ifndef NOSPL
+ if (cmd_quoting) { /* and COMMAND QUOTING is ON */
+ y = CKMAXPATH; /* evaluate it for this file */
+ s = asname;
+ zzstring(remote,&s,&y);
+ } else
+#endif /* NOSPL */
+ ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */
+ } else { /* No as-name */
+ nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */
+ debug(F110,"FTP PUT nzltor",asname,0);
+ }
+ /* Preliminary messages and log entries */
+
+ fullname[0] = NUL;
+ zfnqfp(local,CKMAXPATH,fullname);
+ if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
+ fullname[CKMAXPATH] = NUL;
+
+ if (displa && fdispla) { /* Screen */
+ ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
+ ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
+ ftscreen(SCR_FS,0,fsize,"");
+ }
+#ifdef DOUPDATE
+ if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */
+ mt = chkmodtime(fullname,asname,0);
+ debug(F111,"ftp putfile chkmodtime",asname,mt);
+ if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
+ tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
+ /* Skip this one */
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
+ filcnt++;
+ return(SKP_DAT);
+ } else if (mt == 1) { /* Times are equal */
+ tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
+ filcnt++;
+ return(SKP_DAT);
+ }
+ /* Local file is newer */
+ tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
+ "ftp put /update TEXT:", fullname, 0);
+ } else if (flg & PUT_RES) {
+ tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
+ "ftp put /recover TEXT:", fullname, 0);
+ } else {
+ tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
+ }
+#else
+ tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
+#endif /* DOUPDATE */
+ tlog(F110," as",asname,0);
+
+#ifndef NOCSETS
+ if (xlate) {
+ debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
+ tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
+ tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
+ } else if (!ftp_typ) {
+ tlog(F110," character sets:","no conversion",0);
+ fcs = ofcs; /* Binary file but we still must */
+ rcs = orcs; /* translate its name */
+ }
+#endif /* NOCSETS */
+
+ /* PUT THE FILE */
+
+ t0 = gmstimer(); /* Start time */
+ if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */
+ if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */
+ rc = (mt < 0) ? /* Update mode... */
+ SKP_XNX : /* Remote file doesn't exist */
+ SKP_XUP; /* Remote file is older */
+ } else {
+ rc = SKP_SIM; /* "Would be sent", period. */
+ }
+ } else {
+ rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
+ }
+ t1 = gmstimer(); /* End time */
+ filcnt++; /* File number */
+
+#ifdef GFTIMER
+ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
+ fpxfsecs = sec; /* (for doxlog()) */
+#else
+ sec = (t1 - t0) / 1000;
+ xfsecs = (int)sec;
+#endif /* GFTIMER */
+
+ debug(F111,"ftp sendrequest rc",local,rc);
+
+ if (cancelfile || cancelgroup) {
+ debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
+ ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
+ } else if (rc > 0) {
+ debug(F101,"ftp put skipped",local,rc);
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
+ } else if (rc < 0) {
+ debug(F111,"ftp put error",local,ftpcode);
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
+ } else {
+ debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
+ ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
+ debug(F111,"ftp put ST_OK",local,rc);
+ ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
+ debug(F110,"ftp put old sfspec",sfspec,0);
+ makestr(&sfspec,fullname); /* For WHERE command */
+ debug(F110,"ftp put new sfspec",sfspec,0);
+ debug(F110,"ftp put old srfspec",srfspec,0);
+ makestr(&srfspec,asname);
+ debug(F110,"ftp put new srfspec",srfspec,0);
+ }
+
+ /* Final log entries */
+
+#ifdef TLOG
+ if (tralog) {
+ if (rc > 0) {
+ 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,(CK_OFF_T)0,mvto); */
+
+ } else if (rnto) {
+ char * s = rnto;
+#ifndef NOSPL
+ int y; /* Pass it thru the evaluator */
+ extern int cmd_quoting; /* for \v(filename) */
+ if (cmd_quoting) { /* But only if cmd_quoting is on */
+ y = CKMAXPATH;
+ s = (char *)asname;
+ zzstring(rnto,&s,&y);
+ s = (char *)asname;
+ }
+#endif /* NOSPL */
+ if (s) if (*s) {
+ int x;
+ x = zrename(local,s);
+ tlog(F110, (x > -1) ?
+ " renamed source file to" :
+ " failed to rename source file to",
+ s,
+ 0
+ );
+ if (x < 0)
+ return(-1);
+ /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
+ }
+ }
+
+ /* Disposition of destination file */
+
+ if (srvrn) { /* /SERVER-RENAME: */
+ char * s = srvrn;
+#ifndef NOSPL
+ int y; /* Pass it thru the evaluator */
+ extern int cmd_quoting; /* for \v(filename) */
+ debug(F111,"ftp putfile srvrn",s,1);
+
+ if (cmd_quoting) { /* But only if cmd_quoting is on */
+ y = CKMAXPATH;
+ s = (char *)fullname; /* We can recycle this buffer now */
+ zzstring(srvrn,&s,&y);
+ s = (char *)fullname;
+ }
+#endif /* NOSPL */
+ debug(F111,"ftp putfile srvrn",s,2);
+ if (s) if (*s) {
+ int x;
+ x = ftp_rename(asname,s);
+ debug(F111,"ftp putfile ftp_rename",asname,x);
+ tlog(F110, (x > 0) ?
+ " renamed destination file to" :
+ " failed to rename destination file to",
+ s,
+ 0
+ );
+ if (x < 1)
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+/* xxout must only be used for ASCII transfers */
+static int
+#ifdef CK_ANSIC
+xxout(char c)
+#else
+xxout(c) char c;
+#endif /* CK_ANSIC */
+{
+#ifndef OS2
+#ifndef VMS
+#ifndef MAC
+#ifndef OSK
+ /* For Unix, DG, Stratus, Amiga, Gemdos, other */
+ if (c == '\012') {
+ if (zzout(dout,(CHAR)'\015') < 0)
+ return(-1);
+ ftpsnd.bytes++;
+ }
+#else /* OSK */
+ if (c == '\015') {
+ c = '\012';
+ if (zzout(dout,(CHAR)'\015') < 0)
+ return(-1);
+ ftpsnd.bytes++;
+ }
+#endif /* OSK */
+#else /* MAC */
+ if (c == '\015') {
+ c = '\012';
+ if (zzout(dout,(CHAR)'\015') < 0)
+ return(-1);
+ ftpsnd.bytes++;
+ }
+#endif /* MAC */
+#endif /* VMS */
+#endif /* OS2 */
+ if (zzout(dout,(CHAR)c) < 0)
+ return(-1);
+ ftpsnd.bytes++;
+ return(0);
+}
+
+static int
+#ifdef CK_ANSIC
+scrnout(char c)
+#else
+scrnout(c) char c;
+#endif /* CK_ANSIC */
+{
+ return(putchar(c));
+}
+
+static int
+#ifdef CK_ANSIC
+pipeout(char c)
+#else
+pipeout(c) char c;
+#endif /* CK_ANSIC */
+{
+ return(zmchout(c));
+}
+
+static int
+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);
+}
+
+#ifdef FTP_TIMEOUT
+/* fc = 0 for read; 1 for write */
+static int
+check_data_connection(fd,fc) int fd, fc; {
+ int x;
+ struct timeval tv;
+ fd_set in, out, err;
+
+ if (ftp_timeout < 1L)
+ return(0);
+
+ FD_ZERO(&in);
+ FD_ZERO(&out);
+ FD_ZERO(&err);
+ FD_SET(fd,fc ? &out : &in);
+ tv.tv_sec = ftp_timeout; /* Time limit */
+ tv.tv_usec = 0L;
+
+#ifdef INTSELECT
+ x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
+#else
+ x = select(FD_SETSIZE,&in,&out,&err,&tv);
+#endif /* INTSELECT */
+
+ if (x == 0) {
+#ifdef EWOULDBLOCK
+ errno = EWOULDBLOCK;
+#else
+#ifdef EAGAIN
+ errno = EAGAIN;
+#else
+ errno = 11;
+#endif /* EAGAIN */
+#endif /* EWOULDBLOCK */
+ debug(F100,"ftp check_data_connection TIMOUT","",0);
+ return(-3);
+ }
+ return(0);
+}
+#endif /* FTP_TIMEOUT */
+
+/* zzsend - used by buffered output macros. */
+
+static int
+#ifdef CK_ANSIC
+zzsend(int fd, CHAR c)
+#else
+zzsend(fd,c) int fd; CHAR c;
+#endif /* CK_ANSIC */
+{
+ int rc;
+
+ debug(F101,"zzsend ucbufsiz","",ucbufsiz);
+ debug(F101,"zzsend nout","",nout);
+ debug(F111,"zzsend","secure?",ftpissecure());
+
+ if (iscanceled()) /* Check for cancellation */
+ return(-9);
+
+#ifdef FTP_TIMEOUT
+ ftp_timed_out = 0;
+ if (check_data_connection(fd,1) < 0) {
+ ftp_timed_out = 1;
+ return(-3);
+ }
+#endif /* FTP_TIMEOUT */
+
+ rc = (!ftpissecure()) ?
+ send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
+ secure_putbuf(fd, ucbuf, nout);
+ ucbuf[nout] = NUL;
+ nout = 0;
+ ucbuf[nout++] = c;
+ spackets++;
+ pktnum++;
+ if (rc > -1 && fdispla != XYFD_B) {
+ spktl = nout;
+ ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
+ }
+ return(rc);
+}
+
+/* c m d l i n p u t -- Command-line PUT */
+
+int
+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(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
+ if (!stay)
+ doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
+ return(success);
+}
+
+
+/* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */
+
+int
+#ifdef CK_ANSIC
+doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */
+#else
+doftpput(cx,who) int cx, who;
+#endif /* CK_ANSIC */
+{
+ struct FDB sf, fl, sw, cm;
+ int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
+ int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
+ char * s, * s2;
+
+ int x_csl, x_csr = -1; /* Local and remote charsets */
+ int x_xla = 0;
+ int x_recurse = 0;
+ char c, * p; /* Workers */
+#ifdef PUTARRAY
+ int range[2]; /* Array range */
+ char ** ap = NULL; /* Array pointer */
+ int arrayx = -1; /* Array index */
+#endif /* PUTARRAY */
+ ULONG t0 = 0L, t1 = 0L; /* Times for stats */
+#ifdef GFTIMER
+ CKFLOAT sec;
+#else
+ int sec = 0;
+#endif /* GFTIMER */
+
+ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
+ success = 0; /* Assume failure */
+ forcetype = 0; /* No /TEXT or /BINARY given yet */
+ out2screen = 0; /* Not outputting file to screen */
+ putflags = 0; /* PUT options */
+ x_cnv = ftp_cnv; /* Filename conversion */
+ x_usn = ftp_usn; /* Unique server names */
+ x_prm = ftp_prm; /* Permissions */
+ if (x_prm == SET_AUTO) /* Permissions AUTO */
+ x_prm = alike;
+
+#ifndef NOCSETS
+ x_csr = ftp_csr; /* Inherit global server charset */
+ x_csl = ftp_csl;
+ if (x_csl < 0)
+ x_csl = fcharset;
+ x_xla = ftp_xla;
+#endif /* NOCSETS */
+
+ makestr(&filefile,NULL); /* No filename list file yet. */
+ makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */
+ makestr(&snd_rename,NULL); /* PUT /RENAME */
+ makestr(&snd_move,NULL); /* PUT /MOVE */
+ putpath[0] = NUL; /* Initialize for syncdir(). */
+ puterror = ftp_err; /* Inherit global error action. */
+ what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */
+ asnambuf[0] = NUL; /* Clear as-name buffer */
+
+ if (g_ftp_typ > -1) { /* Restore TYPE if saved */
+ ftp_typ = g_ftp_typ;
+ /* g_ftp_typ = -1; */
+ }
+ for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = -1; /* and -1 int values */
+ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
+ }
+ if (who == 0) { /* Called with unprefixed command */
+ switch (cx) {
+ case XXRSEN: pv[SND_RES].ival = 1; break;
+ case XXCSEN: pv[SND_CMD].ival = 1; break;
+ case XXMOVE: pv[SND_DEL].ival = 1; break;
+ case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
+ case XXMSE: mput++; break;
+ }
+ } else {
+ if (cx == FTP_REP)
+ pv[SND_RES].ival = 1;
+ if (cx == FTP_MPU)
+ mput++;
+ }
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nputswi, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ putswi, /* Keyword table */
+ &sf /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 3rd FDB - local filespec */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* 4th FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ again:
+ cmfdbi(&sf, /* 2nd FDB - file to send */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
+ nolinks | x_recurse, /* addtl numeric data 1 */
+ 0, /* dirflg 0 means "not dirs only" */
+ xxstring,
+ NULL,
+#ifdef COMMENT
+ mput ? &cm : &fl
+#else
+ &fl
+#endif /* COMMENT */
+ );
+
+ while (1) { /* Parse zero or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"ftp put cmfdb A","",x);
+ debug(F101,"ftp put fcode A","",cmresult.fcode);
+ if (x < 0) /* Error */
+ goto xputx; /* or reparse needed */
+ if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
+ break;
+ c = cmgbrk(); /* Get break character */
+ getval = (c == ':' || c == '='); /* to see how they ended the switch */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ x = -9;
+ goto xputx;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ x = -9;
+ goto xputx;
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"ftp put switch","",n);
+
+ switch (n) { /* Process the switch */
+ case SND_AFT: /* Send /AFTER:date-time */
+ case SND_BEF: /* Send /BEFORE:date-time */
+ case SND_NAF: /* Send /NOT-AFTER:date-time */
+ case SND_NBE: /* Send /NOT-BEFORE:date-time */
+ if (!getval) break;
+ if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Date-time required\n");
+ x = -9;
+ }
+ goto xputx;
+ }
+ pv[n].ival = 1;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case SND_ASN: /* /AS-NAME: */
+ debug(F101,"ftp put /as-name getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
+ if (x == -3) {
+ printf("?name required\n");
+ x = -9;
+ }
+ goto xputx;
+ }
+ makestr(&(pv[n].sval),brstrip(s));
+ debug(F110,"ftp put /as-name 1",pv[n].sval,0);
+ if (pv[n].sval) pv[n].ival = 1;
+ break;
+
+#ifdef PUTARRAY
+ case SND_ARR: /* /ARRAY */
+ if (!getval) break;
+ ap = NULL;
+ if ((x = cmfld("Array name (a single letter will do)",
+ "",
+ &s,
+ NULL
+ )) < 0) {
+ if (x == -3)
+ break;
+ else
+ return(x);
+ }
+ if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
+ printf("?Bad array: %s\n",s);
+ return(-9);
+ }
+ if (!(ap = a_ptr[x])) {
+ printf("?No such array: %s\n",s);
+ return(-9);
+ }
+ pv[n].ival = 1;
+ pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
+ pv[SND_RES].ival = 0;
+ pv[SND_FIL].ival = 0;
+ arrayx = x;
+ break;
+#endif /* PUTARRAY */
+
+ case SND_BIN: /* /BINARY */
+ case SND_TXT: /* /TEXT or /ASCII */
+ case SND_TEN: /* /TENEX */
+ pv[SND_BIN].ival = 0;
+ pv[SND_TXT].ival = 0;
+ pv[SND_TEN].ival = 0;
+ pv[n].ival = 1;
+ break;
+
+#ifdef PUTPIPE
+ case SND_CMD: /* These take no args */
+ if (nopush) {
+ printf("?Sorry, system command access is disabled\n");
+ x = -9;
+ goto xputx;
+ }
+#ifdef PIPESEND
+ else if (sndfilter) {
+ printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
+ x = -9;
+ goto xputx;
+ }
+#endif /* PIPESEND */
+ sw.hlpmsg = "Command, or switch"; /* Change help message */
+ pv[n].ival = 1; /* Just set the flag */
+ pv[SND_ARR].ival = 0;
+ break;
+#endif /* PUTPIPE */
+
+#ifdef CKSYMLINK
+ case SND_LNK:
+ nolinks = 0;
+ goto again; /* Because CMIFI params changed... */
+ case SND_NLK:
+ nolinks = 2;
+ goto again;
+#endif /* CKSYMLINK */
+
+#ifdef FTP_RESTART
+ case SND_RES: /* /RECOVER (resend) */
+ pv[SND_ARR].ival = 0; /* fall thru on purpose... */
+#endif /* FTP_RESTART */
+
+ case SND_NOB:
+ case SND_DEL: /* /DELETE */
+ case SND_SHH: /* /QUIET */
+ case SND_UPD: /* /UPDATE */
+ case SND_SIM: /* /UPDATE */
+ case SND_USN: /* /UNIQUE */
+ pv[n].ival = 1; /* Just set the flag */
+ break;
+
+ case SND_REC: /* /RECURSIVE */
+ recursive = 2; /* Must be set before cmifi() */
+ x_recurse = 1;
+ goto again; /* Because CMIFI params changed... */
+ break;
+
+#ifdef UNIXOROSK
+ case SND_DOT: /* /DOTFILES */
+ matchdot = 1;
+ break;
+ case SND_NOD: /* /NODOTFILES */
+ matchdot = 0;
+ break;
+#endif /* UNIXOROSK */
+
+ case SND_ERR: /* /ERROR-ACTION */
+ if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
+ goto xputx;
+ pv[n].ival = x;
+ break;
+
+ case SND_EXC: /* Excludes */
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ x = -9;
+ }
+ goto xputx;
+ }
+ if (s) if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s);
+ if (pv[n].sval)
+ pv[n].ival = 1;
+ break;
+
+ case SND_PRM: /* /PERMISSIONS */
+ if (!getval)
+ x = 1;
+ else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ goto xputx;
+ pv[SND_PRM].ival = x;
+ break;
+
+#ifdef PIPESEND
+ case SND_FLT: /* /FILTER */
+ debug(F101,"ftp put /filter getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
+ if (x == -3)
+ s = "";
+ else
+ goto xputx;
+ }
+ if (*s) s = brstrip(s);
+ y = strlen(s);
+ for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
+ if (s[x] != '\\') continue;
+ if (s[x+1] == 'v') break;
+ }
+ if (x == y) {
+ printf(
+ "?Filter must contain a replacement variable for filename.\n"
+ );
+ x = -9;
+ goto xputx;
+ }
+ if (s) if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s);
+ if (pv[n].sval)
+ pv[n].ival = 1;
+ break;
+#endif /* PIPESEND */
+
+ case SND_NAM: /* /FILENAMES */
+ if (!getval) break;
+ if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
+ goto xputx;
+ debug(F101,"ftp put /filenames","",x);
+ pv[n].ival = x;
+ break;
+
+ case SND_SMA: /* Smaller / larger than */
+ case SND_LAR: {
+ CK_OFF_T y;
+ if (!getval) break;
+ if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
+ goto xputx;
+ pv[n].wval = y;
+ break;
+ }
+ case SND_FIL: /* Name of file containing filenames */
+ if (!getval) break;
+ if ((x = cmifi("Name of file containing list of filenames",
+ "",&s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Filename required\n");
+ x = -9;
+ }
+ goto xputx;
+ } else if (y && iswild(s)) {
+ printf("?Wildcards not allowed\n");
+ x = -9;
+ goto xputx;
+ }
+ if (s) if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s);
+ if (pv[n].sval) {
+ pv[n].ival = 1;
+ pv[SND_ARR].ival = 0;
+ } else {
+ pv[n].ival = 0;
+ }
+ mput = 0;
+ break;
+
+ case SND_MOV: /* MOVE after */
+ case SND_REN: /* RENAME after */
+ case SND_SRN: { /* SERVER-RENAME after */
+ char * m = "";
+ switch (n) {
+ case SND_MOV:
+ m = "device and/or directory for source file after sending";
+ break;
+ case SND_REN:
+ m = "new name for source file after sending";
+ break;
+ case SND_SRN:
+ m = "new name for destination file after sending";
+ break;
+ }
+ if (!getval) break;
+ if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
+ if (x == -3) {
+ printf("%s\n", n == SND_MOV ?
+ "?Destination required" :
+ "?New name required"
+ );
+ x = -9;
+ }
+ goto xputx;
+ }
+ if (s) if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
+ pv[n].ival = (pv[n].sval) ? 1 : 0;
+ break;
+ }
+ case SND_STA: /* Starting position (= PSEND) */
+ if (!getval) break;
+ if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
+ goto xputx;
+ pv[n].ival = y;
+ break;
+
+ case SND_TYP: /* /TYPE */
+ if (!getval) break;
+ if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
+ goto xputx;
+ pv[n].ival = (x == 2) ? -1 : x;
+ break;
+
+#ifndef NOCSETS
+ case SND_CSL: /* Local character set */
+ case SND_CSR: /* Remote (server) charset */
+ if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
+ return((x == -3) ? -2 : x);
+ }
+ if (n == SND_CSL)
+ x_csl = x;
+ else
+ x_csr = x;
+ x_xla = 1; /* Overrides global OFF setting */
+ break;
+
+ case SND_XPA: /* Transparent */
+ x_xla = 0;
+ x_csr = -1;
+ x_csl = -1;
+ break;
+#endif /* NOCSETS */
+ }
+ }
+#ifdef PIPESEND
+ if (pv[SND_RES].ival > 0) { /* /RECOVER */
+ if (sndfilter || pv[SND_FLT].ival > 0) {
+ printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
+ x = -9;
+ goto xputx;
+ }
+ if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
+ printf("WARNING: Server says it doesn't support REST.\n");
+ }
+#endif /* PIPESEND */
+
+ cmarg = "";
+ cmarg2 = asnambuf;
+ line[0] = NUL;
+ s = line;
+ wild = 0;
+
+ switch (cmresult.fcode) { /* How did we get out of switch loop */
+ case _CMIFI: /* Input filename */
+ if (pv[SND_FIL].ival > 0) {
+ printf("?You may not give a PUT filespec and a /LISTFILE\n");
+ x = -9;
+ goto xputx;
+ }
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
+ if (pv[SND_ARR].ival > 0)
+ ckstrncpy(asnambuf,line,CKMAXPATH);
+ else
+ wild = cmresult.nresult; /* Wild flag */
+ debug(F111,"ftp put wild",line,wild);
+ if (!wild && !recursive && !mput)
+ nolinks = 0;
+ break;
+ case _CMFLD: /* Field */
+ /* Only allowed with /COMMAND and /ARRAY */
+ if (pv[SND_FIL].ival > 0) {
+ printf("?You may not give a PUT filespec and a /LISTFILE\n");
+ x = -9;
+ goto xputx;
+ }
+ /* For MPUT it's OK to have filespecs that don't match any files */
+ if (mput)
+ break;
+ if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off limits: %s\n",cmresult.sresult);
+ else
+#endif /* CKROOT */
+ printf("?%s - \"%s\"\n",
+ iswild(cmresult.sresult) ?
+ "No files match" : "File not found",
+ cmresult.sresult
+ );
+ x = -9;
+ goto xputx;
+ }
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ if (pv[SND_ARR].ival > 0)
+ ckstrncpy(asnambuf,line,CKMAXPATH);
+ break;
+ case _CMCFM: /* Confirmation */
+ confirmed = 1;
+ break;
+ default:
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ x = -9;
+ goto xputx;
+ }
+ debug(F110,"ftp put string",s,0);
+ debug(F101,"ftp put confirmed","",confirmed);
+
+ /* Save and change protocol and transfer mode */
+ /* Global values are restored in main parse loop */
+
+ g_displa = fdispla;
+ if (ftp_dis > -1)
+ fdispla = ftp_dis;
+ g_skipbup = skipbup;
+
+ if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
+ g_skipbup = skipbup;
+ skipbup = 1;
+ }
+ if (pv[SND_TYP].ival > -1) { /* /TYPE */
+ xfiletype = pv[SND_TYP].ival;
+ if (xfiletype == 2)
+ xfiletype = -1;
+ }
+ if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
+ forcetype = 1; /* So skip file scan */
+ ftp_typ = FTT_BIN; /* Set binary */
+ } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
+ forcetype = 1;
+ ftp_typ = FTT_ASC;
+ } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
+ forcetype = 1;
+ ftp_typ = FTT_TEN;
+ } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
+ forcetype = 1;
+ ftp_typ = binary;
+ g_ftp_typ = binary;
+ }
+
+#ifdef PIPESEND
+ if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
+ debug(F110,"PUT /COMMAND before stripping",s,0);
+ s = brstrip(s);
+ debug(F110,"PUT /COMMAND after stripping",s,0);
+ if (!*s) {
+ printf("?Sorry, a command to send from is required\n");
+ x = -9;
+ goto xputx;
+ }
+ cmarg = s;
+ }
+#endif /* PIPESEND */
+
+/* Set up /MOVE and /RENAME */
+
+ if (pv[SND_DEL].ival > 0 &&
+ (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
+ printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
+ x = -9;
+ goto xputx;
+ }
+#ifdef CK_TMPDIR
+ if (pv[SND_MOV].ival > 0) {
+ int len;
+ char * p = pv[SND_MOV].sval;
+ len = strlen(p);
+ if (!isdir(p)) { /* Check directory */
+#ifdef CK_MKDIR
+ char * s = NULL;
+ s = (char *)malloc(len + 4);
+ if (s) {
+ strcpy(s,p); /* safe */
+#ifdef datageneral
+ if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
+#else
+ if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
+#endif /* datageneral */
+ s[len++] = 'X';
+ s[len] = NUL;
+#ifdef NOMKDIR
+ x = -1;
+#else
+ x = zmkdir(s);
+#endif /* NOMKDIR */
+ free(s);
+ if (x < 0) {
+ printf("?Can't create \"%s\"\n",p);
+ x = -9;
+ goto xputx;
+ }
+ }
+#else
+ printf("?Directory \"%s\" not found\n",p);
+ x = -9;
+ goto xputx;
+#endif /* CK_MKDIR */
+ }
+ makestr(&snd_move,p);
+ }
+#endif /* CK_TMPDIR */
+
+ if (pv[SND_REN].ival > 0) { /* /RENAME */
+ char * p = pv[SND_REN].sval;
+ if (!p) p = "";
+ if (!*p) {
+ printf("?New name required for /RENAME\n");
+ x = -9;
+ goto xputx;
+ }
+ p = brstrip(p);
+#ifndef NOSPL
+ /* If name given is wild, rename string must contain variables */
+ if (wild) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(p,&s,&x);
+ if (!strcmp(tmpbuf,p)) {
+ printf(
+ "?/RENAME for file group must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xputx;
+ }
+ }
+#endif /* NOSPL */
+ makestr(&snd_rename,p);
+ debug(F110,"FTP snd_rename",snd_rename,0);
+ }
+ if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */
+ char * p = pv[SND_SRN].sval;
+ if (!p) p = "";
+ if (!*p) {
+ printf("?New name required for /SERVER-RENAME\n");
+ x = -9;
+ goto xputx;
+ }
+ p = brstrip(p);
+#ifndef NOSPL
+ if (wild) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(p,&s,&x);
+ if (!strcmp(tmpbuf,p)) {
+ printf(
+"?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xputx;
+ }
+ }
+#endif /* NOSPL */
+ makestr(&srv_renam,p);
+ debug(F110,"ftp put srv_renam",srv_renam,0);
+ }
+ if (!confirmed) { /* CR not typed yet, get more fields */
+ char * lp;
+ if (mput) { /* MPUT or MMOVE */
+ nfils = 0; /* We already have the first one */
+#ifndef NOMSEND
+ if (cmresult.fcode == _CMIFI) {
+ /* First filespec is valid */
+ msfiles[nfils++] = line; /* Store pointer */
+ lp = line + (int)strlen(line) + 1; /* Point past it */
+ debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
+ } else {
+ /* First filespec matches no files */
+ debug(F110,"ftp put mput skipping first filespec",
+ cmresult.sresult,
+ 0
+ );
+ lp = line;
+ }
+ /* Parse a filespec, a "field", or confirmation */
+
+ cmfdbi(&sf, /* 1st FDB - file to send */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nolinks | x_recurse, /* addtl numeric data 1 */
+ 0, /* dirflg 0 means "not dirs only" */
+ xxstring,
+ NULL,
+ &fl
+ );
+ cmfdbi(&fl, /* 2nd FDB - local filespec */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* 3rd FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "",
+ "",
+ "",
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ while (!confirmed) { /* Get more filenames */
+ x = cmfdb(&sf); /* Parse something */
+ debug(F101,"ftp put cmfdb B","",x);
+ debug(F101,"ftp put fcode B","",cmresult.fcode);
+ if (x < 0) /* Error */
+ goto xputx; /* or reparse needed */
+ switch (cmresult.fcode) {
+ case _CMCFM: /* End of command */
+ confirmed++;
+ if (nfils < 1) {
+ debug(F100,"ftp put mput no files match","",0);
+ printf("?No files match MPUT list\n");
+ x = -9;
+ goto xputx;
+ }
+ break;
+ case _CMFLD: /* No match */
+ debug(F110,"ftp put mput skipping",cmresult.sresult,0);
+ continue;
+ case _CMIFI: /* Good match */
+ s = cmresult.sresult;
+ msfiles[nfils++] = lp; /* Got one, count, point to it, */
+ p = lp; /* remember pointer, */
+ while ((*lp++ = *s++)) /* and copy it into buffer */
+ if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
+ printf("?MPUT list too long\n");
+ line[0] = NUL;
+ x = -9;
+ goto xputx;
+ }
+ debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
+ if (nfils == 1) /* Take care of \v(filespec) */
+ fspec[0] = NUL;
+#ifdef ZFNQFP
+ zfnqfp(p,TMPBUFSIZ,tmpbuf);
+ p = tmpbuf;
+#endif /* ZFNQFP */
+ if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
+ strcat(fspec,p); /* safe */
+ strcat(fspec," "); /* safe */
+ } else {
+#ifdef COMMENT
+ printf("WARNING - \\v(filespec) buffer overflow\n");
+#else
+ debug(F101,"doxput filespec buffer overflow","",0);
+#endif /* COMMENT */
+ }
+ }
+ }
+#endif /* NOMSEND */
+ } else { /* Regular PUT */
+ nfils = -1;
+ if ((x = cmtxt(wild ?
+"\nOptional as-name template containing replacement variables \
+like \\v(filename)" :
+ "Optional name to send it with",
+ "",&p,NULL)) < 0)
+ goto xputx;
+
+ if (p) if (!*p) p = NULL;
+ p = brstrip(p);
+
+ if (p && *p) {
+ makestr(&(pv[SND_ASN].sval),p);
+ if (pv[SND_ASN].sval)
+ pv[SND_ASN].ival = 1;
+ debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
+ }
+ }
+ }
+ /* Set cmarg2 from as-name, however we got it. */
+
+ CHECKCONN();
+ if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
+ char * p;
+ p = brstrip(pv[SND_ASN].sval);
+ ckstrncpy(asnambuf,p,CKMAXPATH+1);
+ }
+ debug(F110,"ftp put asnambuf",asnambuf,0);
+
+ if (pv[SND_FIL].ival > 0) {
+ if (confirmed) {
+ if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
+ debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
+ printf("?Failure to open %s\n",pv[SND_FIL].sval);
+ x = -9;
+ goto xputx;
+ }
+ makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
+ debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
+ wild = 1;
+ }
+ }
+ if (confirmed && !line[0] && !filefile) {
+#ifndef NOMSEND
+ if (filehead) { /* OK if we have a SEND-LIST */
+ nfils = filesinlist;
+ sndsrc = nfils; /* Like MSEND */
+ addlist = 1; /* But using a different list... */
+ filenext = filehead;
+ goto doput;
+ }
+#endif /* NOMSEND */
+ printf("?Filename required but not given\n");
+ x = -9;
+ goto xputx;
+ }
+#ifndef NOMSEND
+ addlist = 0; /* Don't use SEND-LIST. */
+#endif /* NOMSEND */
+
+ if (mput) { /* MPUT (rather than PUT) */
+#ifndef NOMSEND
+ cmlist = msfiles; /* List of filespecs */
+ sndsrc = nfils; /* rather filespec and as-name */
+#endif /* NOMSEND */
+ pipesend = 0;
+ } else if (filefile) { /* File contains list of filenames */
+ s = "";
+ cmarg = "";
+ line[0] = NUL;
+ nfils = 1;
+ sndsrc = 1;
+
+ } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
+
+ /* Not MSEND, MMOVE, /LIST, or /ARRAY */
+ nfils = sndsrc = -1;
+ if (!wild) {
+ if (zchki(s) < 0) {
+ printf("?Read access denied - \"%s\"\n", s);
+ x = -9;
+ goto xputx;
+ }
+ }
+ if (s != line) /* We might already have done this. */
+ ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
+#ifdef DEBUG
+ else
+ debug(F110,"doxput line=s",line,0);
+#endif /* DEBUG */
+ cmarg = line; /* File to send */
+ }
+#ifndef NOMSEND
+ zfnqfp(cmarg,fspeclen,fspec); /* Get full name */
+#endif /* NOMSEND */
+
+ if (!mput) { /* For all but MPUT... */
+#ifdef PIPESEND
+ if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
+ pipesend = 1;
+ debug(F101,"ftp put /COMMAND pipesend","",pipesend);
+ if (pipesend && filefile) {
+ printf("?Invalid switch combination\n");
+ x = -9;
+ goto xputx;
+ }
+#endif /* PIPESEND */
+
+#ifndef NOSPL
+ /* If as-name given and filespec is wild, as-name must contain variables */
+ if ((wild || mput) && asnambuf[0]) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(asnambuf,&s,&x);
+ if (!strcmp(tmpbuf,asnambuf)) {
+ printf(
+ "?As-name for file group must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xputx;
+ }
+ }
+#endif /* NOSPL */
+ }
+
+ doput:
+
+ if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
+ fdispla = 0;
+ debug(F101,"ftp put display","",fdispla);
+ } else {
+ displa = 1;
+ if (ftp_deb)
+ fdispla = XYFD_B;
+ }
+
+#ifdef PUTARRAY /* SEND /ARRAY... */
+ if (pv[SND_ARR].ival > 0) {
+ if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
+ if (range[0] == -1) /* If low end of range not specified */
+ range[0] = 1; /* default to 1 */
+ if (range[1] == -1) /* If high not specified */
+ range[1] = a_dim[arrayx]; /* default to size of array */
+ if ((range[0] < 0) || /* Check range */
+ (range[0] > a_dim[arrayx]) ||
+ (range[1] < range[0]) ||
+ (range[1] > a_dim[arrayx])) {
+ printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
+ x = -9;
+ goto xputx;
+ }
+ sndarray = ap; /* Array pointer */
+ sndxin = arrayx; /* Array index */
+ sndxlo = range[0]; /* Array range */
+ sndxhi = range[1];
+ sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
+ if (!asnambuf[0])
+ ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
+ cmarg = "";
+ }
+#endif /* PUTARRAY */
+
+ moving = 0;
+
+ if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
+ if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
+ moving = 1;
+ if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
+ ckstrncpy(sndafter,pv[SND_AFT].sval,19);
+ if (pv[SND_BEF].ival > 0)
+ ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
+ if (pv[SND_NAF].ival > 0)
+ ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
+ if (pv[SND_NBE].ival > 0)
+ ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
+ if (pv[SND_EXC].ival > 0)
+ makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
+ if (pv[SND_SMA].ival > -1)
+ sndsmaller = pv[SND_SMA].wval;
+ if (pv[SND_LAR].ival > -1)
+ sndlarger = pv[SND_LAR].wval;
+ if (pv[SND_NAM].ival > -1)
+ x_cnv = pv[SND_NAM].ival;
+ if (pv[SND_USN].ival > -1)
+ x_usn = pv[SND_USN].ival;
+ if (pv[SND_ERR].ival > -1)
+ puterror = pv[SND_ERR].ival;
+
+#ifdef DOUPDATE
+ if (pv[SND_UPD].ival > 0) {
+ if (x_usn) {
+ printf("?Conflicting switches: /UPDATE /UNIQUE\n");
+ x = -9;
+ goto xputx;
+ }
+ putflags |= PUT_UPD;
+ ftp_dates |= 2;
+ }
+#ifdef COMMENT
+ /* This works but it's useless, maybe dangerous */
+ if (pv[SND_DIF].ival > 0) {
+ if (x_usn) {
+ printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
+ x = -9;
+ goto xputx;
+ }
+ putflags |= PUT_DIF;
+ ftp_dates |= 2;
+ }
+#endif /* COMMENT */
+#endif /* DOUPDATE */
+
+ if (pv[SND_SIM].ival > 0)
+ putflags |= PUT_SIM;
+
+ if (pv[SND_PRM].ival > -1) {
+#ifdef UNIX
+ if (x_usn) {
+ printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
+ x = -9;
+ goto xputx;
+ }
+ x_prm = pv[SND_PRM].ival;
+#else /* UNIX */
+ printf("?/PERMISSIONS switch is not supported\n");
+#endif /* UNIX */
+ }
+#ifdef FTP_RESTART
+ if (pv[SND_RES].ival > 0) {
+ if (!sizeok) {
+ printf("?PUT /RESTART can't be used because SIZE disabled.\n");
+ x = -9;
+ goto xputx;
+ }
+ if (x_usn || putflags) {
+ printf("?Conflicting switches: /RECOVER %s\n",
+ x_usn && putflags ? "/UNIQUE /UPDATE" :
+ (x_usn ? "/UNIQUE" : "/UPDATE")
+ );
+ x = -9;
+ goto xputx;
+ }
+#ifndef NOCSETS
+ if (x_xla &&
+ (x_csl == FC_UCS2 ||
+ x_csl == FC_UTF8 ||
+ x_csr == FC_UCS2 ||
+ x_csr == FC_UTF8)) {
+ printf("?/RECOVER can not be used with Unicode translation\n");
+ x = -9;
+ goto xputx;
+ }
+#endif /* NOCSETS */
+ putflags = PUT_RES;
+ }
+#endif /* FTP_RESTART */
+ }
+ debug(F101,"ftp PUT restart","",putflags & PUT_RES);
+ debug(F101,"ftp PUT update","",putflags & PUT_UPD);
+
+#ifdef PIPESEND
+ if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
+ if (!pv[SND_FLT].sval) {
+ sndfilter = NULL;
+ } else {
+ sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
+ if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
+ }
+ debug(F110,"ftp put /FILTER", sndfilter, 0);
+ }
+ if (sndfilter || pipesend) /* No /UPDATE or /RESTART */
+ if (putflags) /* with pipes or filters */
+ putflags = 0;
+#endif /* PIPESEND */
+
+ tfc = (CK_OFF_T)0; /* Initialize stats and counters */
+ filcnt = 0;
+ pktnum = 0;
+ spackets = 0L;
+
+ if (wild) /* (is this necessary?) */
+ cx = FTP_MPU;
+
+ t0 = gmstimer(); /* Record starting time */
+
+ done = 0; /* Loop control */
+ cancelgroup = 0;
+
+ cdlevel = 0;
+ cdsimlvl = 0;
+ while (!done && !cancelgroup) { /* Loop for all files */
+ /* or until canceled. */
+#ifdef FTP_PROXY
+ /*
+ If we are using a proxy, we don't use the local file list;
+ instead we use the list on the remote machine which we want
+ sent to someone else, and we use remglob() to get the names.
+ But in that case we shouldn't even be executing this routine;
+ see ftp_mput().
+ */
+#endif /* FTP_PROXY */
+
+ cancelfile = 0;
+ x = gnfile(); /* Get next file from list(s) */
+
+ if (x == 0) /* (see gnfile() comments...) */
+ x = gnferror;
+ debug(F111,"FTP PUT gnfile",filnam,x);
+ debug(F111,"FTP PUT binary",filnam,binary);
+
+ switch (x) {
+ case 1: /* File to send */
+ s2 = asnambuf;
+#ifndef NOSPL
+ if (asnambuf[0]) { /* As-name */
+ int n; char *p; /* to be evaluated... */
+ n = TMPBUFSIZ;
+ p = tmpbuf;
+ zzstring(asnambuf,&p,&n);
+ s2 = tmpbuf;
+ debug(F110,"ftp put asname",s2,0);
+ }
+#endif /* NOSPL */
+ rc = putfile(cx, /* Function (PUT, APPEND) */
+ filnam, s2, /* Name to send, as-name */
+ forcetype, moving, /* Parameters from switches... */
+ snd_move, snd_rename, srv_renam,
+ x_cnv, x_usn, xfiletype, x_prm,
+#ifndef NOCSETS
+ x_csl, (!x_xla ? -1 : x_csr),
+#else
+ -1, -1,
+#endif /* NOCSETS */
+ putflags
+ );
+ debug(F111,"ftp put putfile rc",filnam,rc);
+ debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
+ debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
+ if (rc > -1) {
+ good++;
+ status = 1;
+ }
+ if (cancelfile)
+ continue;
+ if (rc < 0) {
+ ftp_fai++;
+ if (puterror) {
+ status = 0;
+ printf("?Fatal upload error: %s\n",filnam);
+ done++;
+ }
+ }
+ continue;
+ case 0: /* No more files, done */
+ done++;
+ continue;
+ case -1:
+ printf("?%s: file not found - \"%s\"\n",
+ puterror ? "Fatal" : "Warning",
+ filnam
+ );
+ if (puterror) {
+ status = 0;
+ done++;
+ break;
+ }
+ continue;
+ case -2:
+ if (puterror) {
+ printf("?Fatal: file not found - \"%s\"\n", filnam);
+ status = 0;
+ done++;
+ break;
+ }
+ continue; /* Not readable, keep going */
+ case -3:
+ if (puterror) {
+ printf("?Fatal: Read access denied - \"%s\"\n", filnam);
+ status = 0;
+ done++;
+ break;
+ }
+ printf("?Warning access denied - \"%s\"\n", filnam);
+ continue;
+#ifdef COMMENT
+ case -4: /* Canceled */
+ done++;
+ break;
+#endif /* COMMENT */
+ case -5:
+ printf("?Too many files match\n");
+ done++;
+ break;
+ case -6:
+ if (good < 1)
+ printf("?No files selected\n");
+ done++;
+ break;
+ default:
+ printf("?getnextfile() - unknown failure\n");
+ done++;
+ }
+ }
+ if (cdlevel > 0) {
+ while (cdlevel--) {
+ if (cdsimlvl) {
+ cdsimlvl--;
+ } else if (!doftpcdup())
+ break;
+ }
+ }
+ if (status > 0) {
+ if (cancelgroup)
+ status = 0;
+ else if (cancelfile && good < 1)
+ status = 0;
+ }
+ success = status;
+ x = success;
+
+ xputx:
+ if (x > -1) {
+#ifdef GFTIMER
+ t1 = gmstimer(); /* End time */
+ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
+ if (!sec) sec = 0.001;
+ fptsecs = sec;
+#else
+ sec = (t1 - t0) / 1000;
+ if (!sec) sec = 1;
+#endif /* GFTIMER */
+ tfcps = (long) (tfc / sec);
+ tsecs = (int)sec;
+ lastxfer = W_FTP|W_SEND;
+ xferstat = success;
+ if (dpyactive)
+ ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
+ }
+ for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ }
+ ftreset(); /* Undo switch effects */
+ dpyactive = 0;
+ return(x);
+}
+
+
+static char ** mgetlist = NULL; /* For MGET */
+static int mgetn = 0, mgetx = 0;
+static char xtmpbuf[4096];
+
+/*
+ c m d l i n g e t
+
+ Get files specified by -g command-line option.
+ File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
+*/
+int
+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 = (CK_OFF_T)-1;
+ makestr(&havemdtm,NULL);
+
+ if (ftp_fnc < 0)
+ ftp_fnc = fncact;
+
+#ifndef NOSPL
+ cmd_quoting = 0;
+#endif /* NOSPL */
+ debug(F101,"ftp cmdlinget nfils","",nfils);
+
+ if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */
+ if (alike) { /* If server & client are alike */
+ nc = 0; /* no conversion */
+ } else { /* If they are different */
+ if (servertype == SYS_UNIX || servertype == SYS_WIN32)
+ nc = -1; /* only minimal conversions needed */
+ else /* otherwise */
+ nc = 1; /* full conversion */
+ }
+ } else /* Not auto - do what user said */
+ nc = ftp_cnv;
+
+ if (nfils < 1)
+ doexit(BAD_EXIT,-1);
+
+ t0 = gmstimer(); /* Starting time for this batch */
+
+#ifndef NOCSETS
+ if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
+ lcs = ftp_csl; /* Local charset */
+ if (lcs < 0) lcs = fcharset;
+ if (lcs < 0) xlate = 0;
+ }
+ if (xlate) { /* Still ON? */
+ rcs = ftp_csx; /* Remote (Server) charset */
+ if (rcs < 0) rcs = ftp_csr;
+ if (rcs < 0) xlate = 0;
+ }
+#endif /* NOCSETS */
+ /*
+ If we have only one file and it is a directory, then we ask for a
+ listing of its contents, rather than retrieving the directory file
+ itself. This is what (e.g.) Netscape does.
+ */
+ if (nfils == 1) {
+ if (doftpcwd((char *)cmlist[mgetx],-1)) {
+ /* If we can CD to it, it must be a directory */
+ if (recursive) {
+ cmlist[mgetx] = "*";
+ } else {
+ status =
+ (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
+ done = 1;
+ }
+ }
+ }
+/*
+ The following is to work around UNIX servers which, when given a command
+ like "NLST path/blah" (not wild) returns the basename without the path.
+*/
+ if (!done && servertype == SYS_UNIX && nfils == 1) {
+ mget = iswild(cmlist[mgetx]);
+ }
+ if (!mget && !done) { /* Invoked by command-line FTP URL */
+ if (ftp_deb)
+ printf("DOING GET...\n");
+ done++;
+ cancelfile = 0; /* This file not canceled yet */
+ s = cmlist[mgetx];
+ rc = 0; /* Initial return code */
+ fsize = (CK_OFF_T)-1;
+ if (sizeok) {
+ x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
+ if (x == REPLY_COMPLETE)
+ fsize = ckatofs(&ftp_reply_str[4]);
+ }
+ ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
+ debug(F111,"ftp cmdlinget filnam",filnam,fsize);
+
+ nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
+ s2 = tmpbuf;
+
+ /* If local file already exists, take collision action */
+
+ if (zchki(s2) > -1) {
+ switch (ftp_fnc) {
+ case XYFX_A: /* Append */
+ append = 1;
+ break;
+ case XYFX_R: /* Rename */
+ case XYFX_B: { /* Backup */
+ char * p = NULL;
+ int x = -1;
+ znewn(s2,&p); /* Make unique name */
+ debug(F110,"ftp cmdlinget znewn",p,0);
+ if (ftp_fnc == XYFX_B) { /* Backup existing file */
+ x = zrename(s2,p);
+ debug(F111,"ftp cmdlinget backup zrename",p,x);
+ } else { /* Rename incoming file */
+ x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
+ s2 = tmpbuf;
+ debug(F111,"ftp cmdlinget rename incoming",p,x);
+ }
+ if (x < 0) {
+ printf("?Backup/Rename failed\n");
+ return(success = 0);
+ }
+ break;
+ }
+ case XYFX_D: /* Discard */
+ ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
+ tlog(F100," refused: name","",0);
+ debug(F110,"ftp cmdlinget skip name",s2,0);
+ goto xclget;
+
+ case XYFX_X: /* Overwrite */
+ case XYFX_U: /* Update (already handled above) */
+ case XYFX_M: /* ditto */
+ break;
+ }
+ }
+ rc = getfile(s, /* Remote name */
+ s2, /* Local name */
+ 0, /* Recover/Restart */
+ append, /* Append */
+ NULL, /* Pipename */
+ 0, /* Translate charsets */
+ -1, /* File charset (none) */
+ -1 /* Server charset (none) */
+ );
+ debug(F111,"ftp cmdlinget rc",s,rc);
+ debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
+ debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
+
+ if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
+ rc = getfile(&s[1], /* Remote name without leading '/' */
+ s2, /* Local name */
+ 0, /* Recover/Restart */
+ append, /* Append */
+ NULL, /* Pipename */
+ 0, /* Translate charsets */
+ -1, /* File charset (none) */
+ -1 /* Server charset (none) */
+ );
+ if (rc > -1) {
+ good++;
+ status = 1;
+ }
+ if (cancelfile)
+ goto xclget;
+ if (rc < 0) {
+ ftp_fai++;
+#ifdef FTP_TIMEOUT
+ if (ftp_timed_out)
+ status = 0;
+#endif /* FTP_TIMEOUT */
+ if (geterror) {
+ status = 0;
+ done++;
+ }
+ }
+ }
+ if (ftp_deb && !done)
+ printf("DOING MGET...\n");
+ while (!done && !cancelgroup) {
+ cancelfile = 0; /* This file not canceled yet */
+ s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
+ if (!s) s = "";
+ if (!*s) {
+ first = 1;
+ mgetx++;
+ if (mgetx < nfils)
+ s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
+ else
+ s = NULL;
+ debug(F111,"ftp cmdlinget remote_files B",s,0);
+ if (!s) {
+ done = 1;
+ break;
+ }
+ }
+ /*
+ The semantics of NLST are ill-defined. Suppose we have just sent
+ NLST /path/[a-z]*. Most servers send back names like /path/foo,
+ /path/bar, etc. But some send back only foo and bar, and subsequent
+ RETR commands based on the pathless names are not going to work.
+ */
+ if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
+ if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
+ int len, left = 4096;
+ char * tmp = xtmpbuf;
+ len = s3 - cmlist[mgetx] + 1;
+ ckstrncpy(tmp,cmlist[mgetx],left);
+ tmp += len;
+ left -= len;
+ ckstrncpy(tmp,s,left);
+ s = xtmpbuf;
+ debug(F111,"ftp cmdlinget remote_files X",s,0);
+ }
+ }
+ first = 0; /* Not first any more */
+
+ debug(F111,"ftp cmdlinget havetype",s,havetype);
+ if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
+ debug(F110,"ftp cmdlinget not-a-file",s,0);
+ continue;
+ }
+ rc = 0; /* Initial return code */
+ if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
+ fsize = havesize;
+ } else { /* No - must ask server */
+ /*
+ Prior to sending the NLST command we necessarily put the
+ server into ASCII mode. We must now put it back into the
+ the requested mode so the upcoming SIZE command returns
+ right kind of size; this is especially important for
+ GET /RECOVER; otherwise the server returns the "ASCII" size
+ of the file, rather than its true size.
+ */
+ changetype(ftp_typ,0); /* Change to requested type */
+ fsize = (CK_OFF_T)-1;
+ if (sizeok) {
+ x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
+ if (x == REPLY_COMPLETE)
+ fsize = ckatofs(&ftp_reply_str[4]);
+ }
+ }
+ ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
+ debug(F111,"ftp cmdlinget filnam",filnam,fsize);
+
+ nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
+ s2 = tmpbuf;
+
+ /* If local file already exists, take collision action */
+
+ if (zchki(s2) > -1) {
+ switch (ftp_fnc) {
+ case XYFX_A: /* Append */
+ append = 1;
+ break;
+ case XYFX_R: /* Rename */
+ case XYFX_B: { /* Backup */
+ char * p = NULL;
+ int x = -1;
+ znewn(s2,&p); /* Make unique name */
+ debug(F110,"ftp cmdlinget znewn",p,0);
+ if (ftp_fnc == XYFX_B) { /* Backup existing file */
+ x = zrename(s2,p);
+ debug(F111,"ftp cmdlinget backup zrename",p,x);
+ } else { /* Rename incoming file */
+ x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
+ s2 = tmpbuf;
+ debug(F111,"ftp cmdlinget rename incoming",p,x);
+ }
+ if (x < 0) {
+ printf("?Backup/Rename failed\n");
+ return(success = 0);
+ }
+ break;
+ }
+ case XYFX_D: /* Discard */
+ ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
+ tlog(F100," refused: name","",0);
+ debug(F110,"ftp cmdlinget skip name",s2,0);
+ continue;
+ case XYFX_X: /* Overwrite */
+ case XYFX_U: /* Update (already handled above) */
+ case XYFX_M: /* ditto */
+ break;
+ }
+ }
+ /* ^^^ ADD CHARSET STUFF HERE ^^^ */
+ rc = getfile(s, /* Remote name */
+ s2, /* Local name */
+ 0, /* Recover/Restart */
+ append, /* Append */
+ NULL, /* Pipename */
+ 0, /* Translate charsets */
+ -1, /* File charset (none) */
+ -1 /* Server charset (none) */
+ );
+ debug(F111,"ftp cmdlinget rc",s,rc);
+ debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
+ debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
+
+ if (rc > -1) {
+ good++;
+ status = 1;
+ }
+ if (cancelfile)
+ continue;
+ if (rc < 0) {
+ ftp_fai++;
+#ifdef FTP_TIMEOUT
+ if (ftp_timed_out)
+ status = 0;
+#endif /* FTP_TIMEOUT */
+ if (geterror) {
+ status = 0;
+ done++;
+ }
+ }
+ }
+
+ xclget:
+ if (cancelgroup)
+ mlsreset();
+ if (status > 0) {
+ if (cancelgroup)
+ status = 0;
+ else if (cancelfile && good < 1)
+ status = 0;
+ }
+ success = status;
+
+#ifdef GFTIMER
+ t1 = gmstimer(); /* End time */
+ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
+ if (!sec) sec = 0.001;
+ fptsecs = sec;
+#else
+ sec = (t1 - t0) / 1000;
+ if (!sec) sec = 1;
+#endif /* GFTIMER */
+
+ tfcps = (long) (tfc / sec);
+ tsecs = (int)sec;
+ lastxfer = W_FTP|W_RECV;
+ xferstat = success;
+ if (dpyactive)
+ ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
+ if (!stay)
+ doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
+ return(success);
+}
+
+/* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */
+
+/*
+ Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
+ zstrdat() to convert to UTC-based time_t. But it doesn't make sense from
+ the user-interface perspective, since the server's directory listings show
+ its own local times and since we don't know what timezone it's in, there's
+ no way to reconcile our local times with the server's.
+*/
+int
+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;
+ CK_OFF_T getlarger = (CK_OFF_T)-1;
+ CK_OFF_T getsmaller = (CK_OFF_T)-1;
+ char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
+ char * src = "", * local = "";
+ 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 pv[SND_MAX+1]; /* Temporary array for switch values */
+
+ success = 0; /* Assume failure */
+ forcetype = 0; /* No /TEXT or /BINARY given yet */
+ restart = 0; /* No restart yet */
+ out2screen = 0; /* No TO-SCREEN switch given yet */
+ mgetmethod = 0; /* No NLST or MLSD switch yet */
+ mgetforced = 0;
+
+ g_displa = fdispla;
+ if (ftp_dis > -1)
+ fdispla = ftp_dis;
+
+ x_cnv = ftp_cnv; /* Filename conversion */
+ if (x_cnv == CNV_AUTO) { /* Name conversion is auto */
+ if (alike) { /* If server & client are alike */
+ x_cnv = 0; /* no conversion */
+ } else { /* If they are different */
+ if (servertype == SYS_UNIX || servertype == SYS_WIN32)
+ x_cnv = -1; /* only minimal conversions needed */
+ else /* otherwise */
+ x_cnv = 1; /* full conversion */
+ }
+ } else /* Not auto - do what user said */
+ x_cnv = ftp_cnv;
+
+ x_prm = ftp_prm; /* Permissions */
+ if (x_prm == SET_AUTO) /* Permissions AUTO */
+ x_prm = alike;
+
+#ifndef NOCSETS
+ x_csr = ftp_csr; /* Inherit global server charset */
+ x_csl = ftp_csl; /* Inherit global local charset */
+ if (x_csl < 0) /* If none, use current */
+ x_csl = fcharset; /* file character-set. */
+ x_xla = ftp_xla; /* Translation On/Off */
+#endif /* NOCSETS */
+
+ geterror = ftp_err; /* Inherit global error action. */
+ asnambuf[0] = NUL; /* No as-name yet. */
+ pipesave = pipesend;
+ pipesend = 0;
+
+ havetype = 0;
+ havesize = (CK_OFF_T)-1;
+ makestr(&havemdtm,NULL);
+
+ if (g_ftp_typ > -1) { /* Restore TYPE if saved */
+ ftp_typ = g_ftp_typ;
+ /* g_ftp_typ = -1; */
+ }
+ for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = -1; /* and -1 int values */
+ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
+ }
+ zclose(ZMFILE); /* In case it was left open */
+
+ x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
+
+ if (fp_nml) { /* Reset /NAMELIST */
+ if (fp_nml != stdout)
+ fclose(fp_nml);
+ fp_nml = NULL;
+ }
+ makestr(&ftp_nml,NULL);
+
+ /* Initialize list of remote filespecs */
+
+ if (!mgetlist) {
+ mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
+ if (!mgetlist) {
+ printf("?Memory allocation failure - MGET list\n");
+ return(-9);
+ }
+ for (i = 0; i < MGETMAX; i++)
+ mgetlist[i] = NULL;
+ }
+ mgetn = 0; /* Number of mget arguments */
+ mgetx = 0; /* Current arg */
+
+ if (who == 0) { /* Called with unprefixed command */
+ if (cx == XXGET || cx == XXREGET || cx == XXRETR)
+ getone++;
+ switch (cx) {
+ case XXREGET: pv[SND_RES].ival = 1; break;
+ case XXRETR: pv[SND_DEL].ival = 1; break;
+ case XXGET:
+ case XXMGET: mget++; break;
+ }
+ } else { /* FTP command */
+ if (cx == FTP_GET || cx == FTP_RGE)
+ getone++;
+ switch (cx) {
+ case FTP_DEL: /* (fall thru on purpose) */
+ case FTP_MDE: mdel++; /* (ditto) */
+ case FTP_GET: /* (ditto) */
+ case FTP_MGE: mget++; break;
+ case FTP_RGE: pv[SND_RES].ival = 1; break;
+ }
+ }
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Remote filename;\n or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ mdel ? delswi : getswi, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 2nd FDB - remote filename */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* 3rd FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"ftp get cmfdb","",x);
+ if (x < 0) /* Error */
+ goto xgetx; /* or reparse needed */
+ if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
+ break;
+ c = cmgbrk(); /* Get break character */
+ getval = (c == ':' || c == '='); /* to see how they ended the switch */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ x = -9;
+ goto xgetx;
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"ftp get switch","",n);
+
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ x = -9;
+ goto xgetx;
+ }
+ switch (n) { /* Process the switch */
+ case SND_ASN: /* /AS-NAME: */
+ debug(F101,"ftp get /as-name getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
+ if (x == -3) {
+ printf("?name required\n");
+ x = -9;
+ }
+ goto xgetx;
+ }
+ s = brstrip(s);
+ if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s);
+ pv[n].ival = 1;
+ break;
+
+ case SND_BIN: /* /BINARY */
+ case SND_TXT: /* /TEXT or /ASCII */
+ case SND_TEN: /* /TENEX */
+ pv[SND_BIN].ival = 0;
+ pv[SND_TXT].ival = 0;
+ pv[SND_TEN].ival = 0;
+ pv[n].ival = 1;
+ break;
+
+#ifdef PUTPIPE
+ case SND_CMD: /* These take no args */
+ if (nopush) {
+ printf("?Sorry, system command access is disabled\n");
+ x = -9;
+ goto xgetx;
+ }
+#ifdef PIPESEND
+ else if (rcvfilter) {
+ printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
+ x = -9;
+ goto xgetx;
+ }
+#endif /* PIPESEND */
+ sw.hlpmsg = "Command, or switch"; /* Change help message */
+ pv[n].ival = 1; /* Just set the flag */
+ pv[SND_ARR].ival = 0;
+ break;
+#endif /* PUTPIPE */
+
+ case SND_SHH: /* /QUIET */
+ case SND_RES: /* /RECOVER (reget) */
+ case SND_NOB: /* /NOBACKUPFILES */
+ case SND_DEL: /* /DELETE */
+ case SND_UPD: /* /UPDATE */
+ case SND_USN: /* /UNIQUE */
+ case SND_NOD: /* /NODOTFILES */
+ case SND_REC: /* /RECOVER */
+ case SND_MAI: /* /TO-SCREEN */
+ pv[n].ival = 1; /* Just set the flag */
+ break;
+
+ case SND_DIF: /* /DATES-DIFFER */
+ pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */
+ pv[n].ival = 1;
+ break;
+
+ case SND_COL: /* /COLLISION: */
+ if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
+ goto xgetx;
+ if (x == XYFX_M)
+ pv[SND_DIF].ival = 1; /* (phase this out) */
+ pv[n].ival = x; /* this should be sufficient */
+ break;
+
+ case SND_ERR: /* /ERROR-ACTION */
+ if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
+ goto xgetx;
+ pv[n].ival = x;
+ break;
+
+ case SND_EXC: /* Exception list */
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ x = -9;
+ }
+ goto xgetx;
+ }
+ if (s) if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s);
+ if (pv[n].sval)
+ pv[n].ival = 1;
+ break;
+
+#ifdef PIPESEND
+ case SND_FLT:
+ debug(F101,"ftp get /filter getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
+ if (x == -3)
+ s = "";
+ else
+ goto xgetx;
+ }
+ s = brstrip(s);
+ if (pv[SND_MAI].ival < 1) {
+ y = strlen(s);
+ /* Make sure they included "\v(...)" */
+ for (x = 0; x < y; x++) {
+ if (s[x] != '\\') continue;
+ if (s[x+1] == 'v') break;
+ }
+ if (x == y) {
+ printf(
+ "?Filter must contain a replacement variable for filename.\n"
+ );
+ x = -9;
+ goto xgetx;
+ }
+ }
+ if (*s) {
+ pv[n].ival = 1;
+ makestr(&(pv[n].sval),s);
+ } else {
+ pv[n].ival = 0;
+ makestr(&(pv[n].sval),NULL);
+ }
+ break;
+#endif /* PIPESEND */
+
+ case SND_NAM:
+ if (!getval) break;
+ if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
+ goto xgetx;
+ debug(F101,"ftp get /filenames","",x);
+ pv[n].ival = x;
+ break;
+
+ case SND_SMA: /* Smaller / larger than */
+ case SND_LAR: {
+ CK_OFF_T y;
+ if (!getval) break;
+ if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
+ goto xgetx;
+ pv[n].wval = y;
+ break;
+ }
+ case SND_FIL: /* Name of file containing filnames */
+ if (!getval) break;
+ if ((x = cmifi("Name of file containing list of filenames",
+ "",&s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Filename required\n");
+ x = -9;
+ }
+ goto xgetx;
+ } else if (y && iswild(s)) {
+ printf("?Wildcards not allowed BBB\n");
+ x = -9;
+ goto xgetx;
+ }
+ if (s) if (!*s) s = NULL;
+ makestr(&(pv[n].sval),s);
+ if (pv[n].sval)
+ pv[n].ival = 1;
+ break;
+
+ case SND_MOV: /* MOVE after */
+ case SND_REN: /* RENAME after */
+ case SND_SRN: { /* SERVER-RENAME */
+ char * m = "";
+ switch (n) {
+ case SND_MOV:
+ m =
+ "Device and/or directory for incoming file after reception";
+ break;
+ case SND_REN:
+ m = "New name for incoming file after reception";
+ break;
+ case SND_SRN:
+ m = "New name for source file on server after reception";
+ break;
+ }
+ if (!getval) break;
+ if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
+ if (x == -3) {
+ printf("%s\n", n == SND_MOV ?
+ "?Destination required" :
+ "?New name required"
+ );
+ x = -9;
+ }
+ goto xgetx;
+ }
+ makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
+ pv[n].ival = (pv[n].sval) ? 1 : 0;
+ break;
+ }
+#ifndef NOCSETS
+ case SND_CSL: /* Local character set */
+ case SND_CSR: /* Remote (server) charset */
+ if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
+ return((x == -3) ? -2 : x);
+ if (n == SND_CSL)
+ x_csl = x;
+ else
+ x_csr = x;
+ x_xla = 1; /* Overrides global OFF setting */
+ break;
+
+ case SND_XPA: /* Transparent */
+ x_xla = 0;
+ x_csr = -1;
+ x_csl = -1;
+ break;
+#endif /* NOCSETS */
+
+ case SND_NML:
+ if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
+ goto xgetx;
+ makestr(&ftp_nml,s);
+ break;
+
+ case SND_PAT: /* /PATTERN: */
+ if (!getval) break;
+ if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
+ goto xgetx;
+ makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
+ pv[n].ival = (pv[n].sval) ? 1 : 0;
+ break;
+
+ case SND_NLS: /* /NLST */
+ pv[n].ival = 1; /* Use NLST */
+ pv[SND_MLS].ival = 0; /* Don't use MLSD */
+ break;
+
+ case SND_MLS: /* /MLSD */
+ pv[n].ival = 1; /* Use MLSD */
+ pv[SND_NLS].ival = 0; /* Don't use NLST */
+ break;
+
+ default: /* /AFTER, /PERMISSIONS, etc... */
+ printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
+ x = -9;
+ goto xgetx;
+ }
+ }
+ line[0] = NUL;
+ cmarg = line;
+ cmarg2 = asnambuf;
+ s = line;
+/*
+ For GET, we want to parse an optional as-name, like with PUT.
+ For MGET, we must parse a list of names, and then send NLST or MLSD
+ commands for each name separately.
+*/
+ switch (cmresult.fcode) { /* How did we get out of switch loop */
+ case _CMFLD: /* Field */
+ if (!getone) {
+ s = brstrip(cmresult.sresult);
+ makestr(&(mgetlist[mgetn++]),s);
+ while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
+ if (x < 0)
+ goto xgetx;
+ makestr(&(mgetlist[mgetn++]),brstrip(s));
+ if (mgetn >= MGETMAX) {
+ printf("?Too many items in MGET list\n");
+ goto xgetx;
+ }
+ }
+ if ((x = cmcfm()) < 0)
+ goto xgetx;
+ } else {
+ s = brstrip(cmresult.sresult);
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
+ if (x != -3)
+ goto xgetx;
+ s = brstrip(s);
+ ckstrncpy(asnambuf,s,CKMAXPATH+1);
+ if ((x = cmcfm()) < 0)
+ goto xgetx;
+ }
+ break;
+ case _CMCFM: /* Confirmation */
+ break;
+ default:
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ x = -9;
+ goto xgetx;
+ }
+ if (pv[SND_REC].ival > 0) /* /RECURSIVE */
+ recursive = 2;
+
+ if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
+ forcetype = 1; /* So skip the name-pattern match */
+ ftp_typ = XYFT_B; /* Set binary */
+ } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
+ forcetype = 1;
+ ftp_typ = XYFT_T;
+ } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
+ forcetype = 1;
+ ftp_typ = FTT_TEN;
+ } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
+ forcetype = 1;
+ ftp_typ = binary;
+ g_ftp_typ = binary;
+ }
+ if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
+ char * p;
+ p = brstrip(pv[SND_ASN].sval); /* As-name */
+ ckstrncpy(asnambuf,p,CKMAXPATH+1);
+ }
+ debug(F110,"ftp get asnambuf",asnambuf,0);
+
+#ifdef PIPESEND
+ if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
+ char * p;
+ p = asnambuf;
+ debug(F110,"GET /COMMAND before stripping",p,0);
+ p = brstrip(p);
+ debug(F110,"GET /COMMAND after stripping",p,0);
+ if (!*p) {
+ printf("?Sorry, a command to write to is required\n");
+ x = -9;
+ goto xgetx;
+ }
+ pipename = p;
+ pipesend = 1;
+ }
+#endif /* PIPESEND */
+
+/* Set up /MOVE and /RENAME */
+
+#ifdef COMMENT
+ /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
+ if (pv[SND_DEL].ival > 0 &&
+ (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
+ printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
+ x = -9;
+ goto xgetx;
+ }
+#endif /* COMMENT */
+#ifdef CK_TMPDIR
+ if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
+ int len;
+ char * p = pv[SND_MOV].sval;
+ len = strlen(p);
+ if (!isdir(p)) { /* Check directory */
+#ifdef CK_MKDIR
+ char * s = NULL;
+ s = (char *)malloc(len + 4);
+ if (s) {
+ strcpy(s,p); /* safe */
+#ifdef datageneral
+ if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
+#else
+ if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
+#endif /* datageneral */
+ s[len++] = 'X';
+ s[len] = NUL;
+#ifdef NOMKDIR
+ x = -1;
+#else
+ x = zmkdir(s);
+#endif /* NOMKDIR */
+ free(s);
+ if (x < 0) {
+ printf("?Can't create \"%s\"\n",p);
+ x = -9;
+ goto xgetx;
+ }
+ }
+#else
+ printf("?Directory \"%s\" not found\n",p);
+ x = -9;
+ goto xgetx;
+#endif /* CK_MKDIR */
+ }
+ makestr(&rcv_move,p);
+ moving = 1;
+ }
+#endif /* CK_TMPDIR */
+
+ if (pv[SND_REN].ival > 0) { /* /RENAME */
+ char * p = pv[SND_REN].sval;
+ if (!p) p = "";
+ if (!*p) {
+ printf("?New name required for /RENAME\n");
+ x = -9;
+ goto xgetx;
+ }
+ p = brstrip(p);
+#ifndef NOSPL
+ /* If name given is wild, rename string must contain variables */
+ if (mget && !getone) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(p,&s,&x);
+ if (!strcmp(tmpbuf,p)) {
+ printf(
+ "?/RENAME for file group must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xgetx;
+ }
+ }
+#endif /* NOSPL */
+ renaming = 1;
+ makestr(&rcv_rename,p);
+ debug(F110,"FTP rcv_rename",rcv_rename,0);
+ }
+ if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
+ printf("?Filename required but not given\n");
+ x = -9;
+ goto xgetx;
+ } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
+ printf("?You can't give both /LISTFILE and a remote filename\n");
+ x = -9;
+ goto xgetx;
+ }
+ CHECKCONN(); /* Check connection */
+
+ if (pv[SND_COL].ival > -1)
+ x_fnc = pv[SND_COL].ival;
+
+#ifndef NOSPL
+ /* If as-name given for MGET, as-name must contain variables */
+ if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(asnambuf,&s,&x);
+ if (!strcmp(tmpbuf,asnambuf)) {
+ printf(
+ "?As-name for MGET must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xgetx;
+ }
+ }
+#endif /* NOSPL */
+
+/* doget: */
+
+ if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
+ fdispla = 0;
+ } else {
+ displa = 1;
+ if (mdel || ftp_deb)
+ fdispla = XYFD_B;
+ }
+ deleting = 0;
+ if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
+ deleting = 1;
+ if (pv[SND_EXC].ival > 0)
+ makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
+ if (pv[SND_SMA].wval > -1)
+ getsmaller = pv[SND_SMA].wval;
+ if (pv[SND_LAR].wval > -1)
+ getlarger = pv[SND_LAR].wval;
+ if (pv[SND_NAM].ival > -1)
+ x_cnv = pv[SND_NAM].ival;
+ if (pv[SND_ERR].ival > -1)
+ geterror = pv[SND_ERR].ival;
+ if (pv[SND_MAI].ival > -1)
+ toscreen = 1;
+
+ if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */
+ mgetmethod = SND_NLS;
+ mgetforced = 1;
+ } else if (pv[SND_MLS].ival > 0) {
+ mgetmethod = SND_MLS;
+ mgetforced = 1;
+ }
+
+#ifdef FTP_RESTART
+ if (pv[SND_RES].ival > 0) {
+ if (!ftp_typ) {
+ printf("?Sorry, GET /RECOVER requires binary mode\n");
+ x = -9;
+ goto xgetx;
+#ifdef COMMENT
+ /* Not true - the fact that the initial REST fails does not mean */
+ /* it will fail here. */
+ } else if (!okrestart) {
+ printf("WARNING: Server might not support restart...\n");
+#endif /* COMMENT */
+ }
+ restart = 1;
+ }
+#endif /* FTP_RESTART */
+
+#ifdef PIPESEND
+ if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
+ if (pipesend) {
+ printf("?Switch conflict: /FILTER and /COMMAND\n");
+ x = -9;
+ goto xgetx;
+ }
+ makestr(&rcvfilter,pv[SND_FLT].sval);
+ debug(F110,"ftp get /FILTER", rcvfilter, 0);
+ }
+ if (rcvfilter || pipesend) { /* /RESTART */
+#ifdef FTP_RESTART
+ if (restart) { /* with pipes or filters */
+ printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
+ x = -9;
+ goto xgetx;
+ }
+#endif /* FTP_RESTART */
+ if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
+ printf(
+ "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
+ x = -9;
+ goto xgetx;
+ }
+ }
+#endif /* PIPESEND */
+
+ tfc = (CK_OFF_T)0; /* Initialize stats and counters */
+ filcnt = 0;
+ pktnum = 0;
+ rpackets = 0L;
+
+ if (pv[SND_FIL].ival > 0) {
+ if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
+ debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
+ printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
+ x = -9;
+ goto xgetx;
+ }
+ if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
+ zclose(ZMFILE); /* Failed */
+ debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
+ printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
+ x = -9;
+ goto xgetx;
+ }
+ listfile = 1;
+ debug(F110,"ftp get listfile first",tmpbuf,0);
+ makestr(&(mgetlist[0]),tmpbuf);
+ }
+ t0 = gmstimer(); /* Record starting time */
+
+ updating = 0; /* Checking dates? */
+ if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
+ updating = 1;
+ if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
+ updating = 2;
+ if (updating) /* These switches force FTP DATES ON */
+ ftp_dates |= 2;
+
+ what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
+
+ cancelgroup = 0; /* Group not canceled yet */
+ if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
+ changetype(ftp_typ,0); /* Change to requested type */
+ binary = ftp_typ; /* For file-transfer display */
+ first = 1; /* For MGET list */
+ done = 0; /* Loop control */
+
+#ifdef CK_TMPDIR
+ if (dldir && !f_tmpdir) { /* If they have a download directory */
+ if ((s = zgtdir())) { /* Get current directory */
+ if (zchdir(dldir)) { /* Change to download directory */
+ ckstrncpy(savdir,s,TMPDIRLEN);
+ f_tmpdir = 1; /* Remember that we did this */
+ }
+ }
+ }
+#endif /* CK_TMPDIR */
+
+ if (ftp_nml) { /* /NAMELIST */
+ debug(F110,"ftp GET ftp_nml",ftp_nml,0);
+ if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
+ fp_nml = stdout;
+ else
+ fp_nml = fopen(ftp_nml, "wb");
+ if (!fp_nml) {
+ printf("?%s: %s\n",ftp_nml,ck_errstr());
+ goto xgetx;
+ }
+ }
+ while (!done && !cancelgroup) { /* Loop for all files */
+ /* or until canceled. */
+#ifdef FTP_PROXY
+ /* do something here if proxy */
+#endif /* FTP_PROXY */
+
+ rs_len = (CK_OFF_T)0; /* REGET position */
+ cancelfile = 0; /* This file not canceled yet */
+ haspath = 0; /* Recalculate this each time thru */
+
+ if (getone) { /* GET */
+ 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',(CK_OFF_T)0,s);
+ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
+ tlog(F110,"ftp get file not found:",s,0);
+ goto again;
+ }
+ } else { /* Names from command line */
+ mgetx++;
+ if (mgetx < mgetn)
+ s = (char *)remote_files(first,
+ (CHAR *)mgetlist[mgetx],
+ (CHAR *)pv[SND_PAT].sval,
+ 0
+ );
+ else
+ s = NULL;
+ if (!s) mgetx++;
+ debug(F111,"ftp mget remote_files D",s,mgetx);
+ }
+ if (!s) {
+ if (!first || mgetx >= mgetn) {
+ done = 1;
+ break;
+ } else if (geterror) {
+ status = 0;
+ done = 1;
+ break;
+ } else {
+ continue;
+ }
+ }
+ }
+ }
+ debug(F111,"ftp mget remote_files E",s,0);
+ /*
+ The semantics of NLST are ill-defined. Suppose we have just sent
+ NLST /path/[a-z]*. Most servers send back names like /path/foo,
+ /path/bar, etc. But some send back only foo and bar, and subsequent
+ RETR commands based on the pathless names are not going to work.
+ */
+ if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
+ char * s3;
+ if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
+ int len, left = 4096;
+ char * tmp = xtmpbuf;
+ len = s3 - mgetlist[mgetx] + 1;
+ ckstrncpy(tmp,mgetlist[mgetx],left);
+ tmp += len;
+ left -= len;
+ ckstrncpy(tmp,s,left);
+ s = xtmpbuf;
+ debug(F111,"ftp mget remote_files F",s,0);
+ }
+ }
+ first = 0;
+ skipthis = 0; /* File selection... */
+ msg = "";
+ nam = s; /* Filename (without path) */
+ rc = 0; /* Initial return code */
+ s2 = "";
+
+ if (!getone && !skipthis) { /* For MGET and MDELETE... */
+ char c, * p = s;
+ int srvpath = 0;
+ int usrpath = 0;
+ int i, k = 0;
+
+ debug(F111,"ftp mget havetype",s,havetype);
+ if (havetype > 0 && havetype != FTYP_FILE) {
+ /* Server says it's not file... */
+ debug(F110,"ftp mget not-a-file",s,0);
+ continue;
+ }
+/*
+ Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
+ But if the client did not ask for a recursive list, we have to ignore any
+ server files that include a pathname that extends beyond any path that
+ was included in the user's request.
+
+ User's filespec is blah or path/blah (or other non-UNIX syntax). We need to
+ get the user's path segment. Then, for each incoming file, if it begins
+ with the same path segment, we must strip it (point past it).
+*/
+ src = mgetlist[mgetx]; /* In case it moved! */
+ if (src) {
+ for (i = 0; src[i]; i++) { /* Find rightmost path separator */
+ if (ispathsep(src[i])) /* in user's pathname */
+ k = i + 1;
+ }
+ } else {
+ src = "";
+ }
+ usrpath = k; /* User path segment length */
+ debug(F111,"ftp get usrpath",src,usrpath);
+
+ p = s; /* Server filename */
+ while ((c = *p++)) { /* Look for path in server filename */
+ if (ispathsep(c)) {
+ /* haspath++; */
+ nam = p; /* Pathless name (for ckmatch) */
+ srvpath = p - s; /* Server path segment length */
+ }
+ }
+ debug(F111,"ftp get srvpath",s,srvpath);
+
+ if (usrpath == 0) {
+/*
+ Here we handle the case where the user said "mget foo" where foo is a
+ directory name, and the server is sending back names like "foo/file1",
+ "foo/file2", etc. This is a nasty trick but it's necessary because the
+ user can't compensate by typing "mget foo/" because then the server is
+ likely to send back "foo//file1, foo//file2" etc, and we still won't
+ get a match...
+*/
+ int srclen = 0, srvlen = 0;
+ if (src) srclen = strlen(src);
+ if (s) srvlen = strlen(s);
+ if (src && (srvlen > srclen)) {
+ if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
+ char * tmpsrc = NULL;
+ tmpsrc = (char *)malloc(srclen + 2);
+ strncpy(tmpsrc,src,srclen);
+ tmpsrc[srclen] = s[srclen];
+ tmpsrc[srclen+1] = NUL;
+ free(mgetlist[mgetx]);
+ mgetlist[mgetx] = tmpsrc;
+ tmpsrc = NULL;
+ src = mgetlist[mgetx];
+ usrpath = srclen+1;
+ }
+ }
+ }
+/*
+ If as-name not given and server filename includes path that matches
+ the pathname from the user's file specification, we must trim the common
+ path prefix from the server's name when constructing the local name.
+*/
+ if (src && /* Wed Sep 25 17:27:48 2002 */
+ !asnambuf[0] &&
+ !recursive && /* Thu Sep 19 16:11:59 2002 */
+ (srvpath > 0) &&
+ !strncmp(src,s,usrpath)) {
+ s2 = s + usrpath; /* Local name skips past remote path */
+ }
+#ifdef COMMENT
+ /* This doesn't work if the path prefix contains wildcards! */
+ haspath = (srvpath > usrpath);
+#else
+ { /* Count path segments instead */
+ int x1 = 0, x2 = 0;
+ char *p;
+ for (p = s; *p; p++)
+ if (ispathsep(*p)) x1++;
+ for (p = src; *p; p++) {
+ if (ispathsep(*p)) x2++;
+ }
+ haspath = recursive ? x1 || x2 : x1 > x2;
+ debug(F111,"ftp get server path segments",s,x1);
+ debug(F111,"ftp get user path segments",src,x2);
+ }
+
+#endif /* COMMENT */
+ debug(F111,"ftp get haspath",s+usrpath,haspath);
+
+ if (haspath) { /* Server file has path segments? */
+ if (!recursive) { /* [M]GET /RECURSIVE? */
+/*
+ We did not ask for a recursive listing, but the server is sending us one
+ anyway (as wu-ftpd is wont to do). We get here if the current filename
+ includes a path segment beyond any path segment we asked for in our
+ non-recursive [M]GET command. We MUST skip this file.
+*/
+ debug(F111,"ftp get skipping because of path",s,0);
+ continue;
+ }
+ }
+ } else if (getone && !skipthis) { /* GET (not MGET) */
+ char * p = nam;
+ while ((c = *p++)) { /* Handle path in local name */
+ if (ispathsep(c)) {
+ if (recursive) { /* If recursive, keep it */
+ haspath = 1;
+ break;
+ } else { /* Otherwise lose it. */
+ nam = p;
+ }
+ }
+ }
+ s2 = nam;
+ }
+ if (!*nam) /* Name without path */
+ nam = s;
+
+ if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
+ if (nam[0] == '.')
+ continue;
+ }
+ if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
+ int xx;
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ if (!rcvexcept[i]) {
+ break;
+ }
+ xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
+ debug(F111,"ftp mget /except match",rcvexcept[i],xx);
+ if (xx) {
+ tlog(F100," refused: exception list","",0);
+ msg = "Refused: Exception List";
+ skipthis++;
+ break;
+ }
+ }
+ }
+ if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
+ if (ckmatch(
+#ifdef CKREGEX
+ "*.~[0-9]*~"
+#else
+ "*.~*~"
+#endif /* CKREGEX */
+ ,nam,0,1) > 0)
+ continue;
+ }
+ if (!x_xla) { /* If translation is off */
+ x_csl = -2; /* unset the charsets */
+ x_csr = -2;
+ }
+ ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
+ if (!*s2) /* Local name */
+ s2 = asnambuf; /* As-name */
+
+ if (!*s2) /* Sat Nov 16 19:19:39 2002 */
+ s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */
+
+ debug(F110,"ftp get filnam ",s,0);
+ debug(F110,"ftp get asname A",s2,0);
+
+ /* Receiving to real file */
+ if (!pipesend &&
+#ifdef PIPESEND
+ !rcvfilter &&
+#endif /* PIPESEND */
+ !toscreen) {
+#ifndef NOSPL
+ /* Do this here so we can decide whether to skip */
+ if (cmd_quoting && !skipthis && asnambuf[0]) {
+ int n; char *p;
+ n = TMPBUFSIZ;
+ p = tmpbuf;
+ zzstring(asnambuf,&p,&n);
+ s2 = tmpbuf;
+ debug(F111,"ftp get asname B",s2,updating);
+ }
+#endif /* NOSPL */
+
+ local = *s2 ? s2 : s;
+
+ if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
+ CK_OFF_T x;
+ x = zchki(local);
+ debug(F111,"ftp get DISCARD zchki",local,x);
+ if (x > -1) {
+ skipthis++;
+ debug(F110,"ftp get skip name",local,0);
+ tlog(F100," refused: name","",0);
+ msg = "Refused: Name";
+ }
+ }
+
+#ifdef DOUPDATE
+ if (!skipthis && updating) { /* If updating and not yet skipping */
+ if (zchki(local) > -1) {
+ x = chkmodtime(local,s,0);
+#ifdef DEBUG
+ if (deblog) {
+ if (updating == 2)
+ debug(F111,"ftp get /dates-diff chkmodtime",local,x);
+ else
+ debug(F111,"ftp get /update chkmodtime",local,x);
+ }
+#endif /* DEBUG */
+ if ((updating == 1 && x > 0) || /* /UPDATE */
+ (updating == 2 && x == 1)) { /* /DATES-DIFFER */
+ skipthis++;
+ tlog(F100," refused: date","",0);
+ msg = "Refused: Date";
+ debug(F110,"ftp get skip date",local,0);
+ }
+ }
+ }
+#endif /* DOUPDATE */
+ }
+ /* Initialize file size to -1 in case server doesn't understand */
+ /* SIZE command, so xxscreen() will know we don't know the size */
+
+ fsize = (CK_OFF_T)-1;
+
+ /* Ask for size now only if we need it for selection */
+ /* because if you're going thru a list 100,000 files to select */
+ /* a small subset, 100,000 SIZE commands can take hours... */
+
+ gotsize = 0;
+ if (!mdel && !skipthis && /* Don't need size for DELE... */
+ (getsmaller >= (CK_OFF_T)0 || getlarger >= (CK_OFF_T)0)) {
+ if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
+ fsize = havesize;
+ gotsize = 1;
+ } else { /* No - must ask server */
+ /*
+ Prior to sending the NLST command we necessarily put the
+ server into ASCII mode. We must now put it back into the
+ the requested mode so the upcoming SIZE command returns
+ right kind of size; this is especially important for
+ GET /RECOVER; otherwise the server returns the "ASCII" size
+ of the file, rather than its true size.
+ */
+ changetype(ftp_typ,0); /* Change to requested type */
+ fsize = (CK_OFF_T)-1;
+ if (sizeok) {
+ x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
+ if (x == REPLY_COMPLETE) {
+ fsize = ckatofs(&ftp_reply_str[4]);
+ gotsize = 1;
+ }
+ }
+ }
+ if (gotsize) {
+ if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
+ skipthis++;
+ if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
+ skipthis++;
+ if (skipthis) {
+ debug(F111,"ftp get skip size",s,fsize);
+ tlog(F100," refused: size","",0);
+ msg = "Refused: Size";
+ }
+#ifdef COMMENT
+ } else if (getone) {
+ /* SIZE can fail for many reasons. Does the file exist? */
+ x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
+ if (x != REPLY_COMPLETE) {
+ printf(">>> FILE NOT FOUND: %s\n",s);
+ break;
+ }
+#endif /* COMMENT */
+ }
+ }
+ if (skipthis) { /* Skipping this file? */
+ ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
+ if (msg)
+ ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
+ else
+ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
+ continue;
+ }
+ if (fp_nml) { /* /NAMELIST only - no transfer */
+ fprintf(fp_nml,"%s\n",s);
+ continue;
+ }
+ if (recursive && haspath && !pipesend
+#ifdef PIPESEND
+ && !rcvfilter
+#endif /* PIPESEND */
+ ) {
+ int x;
+
+#ifdef NOMKDIR
+ x = -1;
+#else
+ x = zmkdir(s); /* Try to make the directory */
+#endif /* NOMKDIR */
+
+ if (x < 0) {
+ rc = -1; /* Failure is fatal */
+ if (geterror) {
+ status = 0;
+ ftscreen(SCR_EM,0,(CK_OFF_T)0,
+ "Directory creation failure");
+ break;
+ }
+ }
+ }
+
+ /* Not skipping */
+
+ selected++; /* Count this file as selected */
+ pn = NULL;
+
+ if (!gotsize && !mdel) { /* Didn't get size yet */
+ if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
+ fsize = havesize;
+ gotsize = 1;
+ } else { /* No - must ask server */
+ fsize = (CK_OFF_T)-1;
+ if (sizeok) {
+ x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
+ if (x == REPLY_COMPLETE) {
+ fsize = ckatofs(&ftp_reply_str[4]);
+ gotsize = 1;
+ }
+ }
+ }
+ }
+ if (mdel) { /* [M]DELETE */
+ if (displa && !ftp_vbm)
+ printf(" %s...",s);
+ rc =
+ (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
+ if (rc > -1) {
+ tlog(F110,"ftp mdelete",s,0);
+ if (displa && !ftp_vbm)
+ printf("OK\n");
+ } else {
+ tlog(F110,"ftp mdelete failed:",s,0);
+ if (displa)
+ printf("Failed\n");
+ }
+#ifndef NOSPL
+#ifdef PIPESEND
+ } else if (rcvfilter) { /* [M]GET with filter */
+ int n; char * p;
+ n = CKMAXPATH;
+ p = tmpbuf; /* Safe - no asname with filter */
+ zzstring(rcvfilter,&p,&n);
+ if (n > -1)
+ pn = tmpbuf;
+ debug(F111,"ftp get rcvfilter",pn,n);
+#endif /* PIPESEND */
+#endif /* NOSPL */
+ if (toscreen) s2 = "-";
+ } else if (pipesend) { /* [M]GET /COMMAND */
+ int n; char * p;
+ n = CKMAXPATH;
+ p = tmpbuf; /* Safe - no asname with filter */
+ zzstring(pipename,&p,&n);
+ if (n > -1)
+ pn = tmpbuf;
+ debug(F111,"ftp get pipename",pipename,n);
+ if (toscreen) s2 = "-";
+ } else { /* [M]GET with no pipes or filters */
+ debug(F111,"ftp get s2 A",s2,x_cnv);
+ if (toscreen) {
+ s2 = "-"; /* (hokey convention for stdout) */
+ } else if (!*s2) { /* No asname? */
+ if (x_cnv) { /* If converting */
+ nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
+ s2 = tmpbuf;
+ debug(F110,"ftp get nzrtol",s2,0);
+ } else /* otherwise */
+ s2 = s; /* use incoming file's name */
+ }
+ debug(F110,"ftp get s2 B",s2,0);
+
+ /* If local file already exists, take collision action */
+
+ if (!pipesend &&
+#ifdef PIPESEND
+ !rcvfilter &&
+#endif /* PIPESEND */
+ !toscreen) {
+ CK_OFF_T x;
+ x = zchki(s2);
+ debug(F111,"ftp get zchki",s2,x);
+ debug(F111,"ftp get x_fnc",s2,x_fnc);
+
+ if (x > (CK_OFF_T)-1 && !restart) {
+ int x = -1;
+ char * newname = NULL;
+
+ switch (x_fnc) {
+ case XYFX_A: /* Append */
+ append = 1;
+ break;
+ case XYFX_R: /* Rename */
+ case XYFX_B: /* Backup */
+ znewn(s2,&newname); /* Make unique name */
+ debug(F110,"ftp get znewn",newname,0);
+ if (x_fnc == XYFX_B) { /* Backup existing file */
+ x = zrename(s2,newname);
+ debug(F111,"ftp get backup zrename",newname,x);
+ } else { /* Rename incoming file */
+ x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
+ s2 = tmpbuf;
+ debug(F111,"ftp get rename incoming",newname,x);
+ }
+ if (x < 0) {
+ ftscreen(SCR_EM,0,(CK_OFF_T)0,
+ "Backup/Rename failed");
+ x = 0;
+ goto xgetx;
+ }
+ break;
+ case XYFX_D: /* Discard (already handled above) */
+ case XYFX_U: /* Update (ditto) */
+ case XYFX_M: /* Update (ditto) */
+ case XYFX_X: /* Overwrite */
+ break;
+ }
+ }
+ }
+ }
+ if (!mdel) {
+#ifdef PIPESEND
+ debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
+#endif /* PIPESEND */
+ if (pipesend && !toscreen)
+ s2 = NULL;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"ftp get x_xla","",x_xla);
+ debug(F101,"ftp get x_csl","",x_csl);
+ debug(F101,"ftp get x_csr","",x_csr);
+ debug(F101,"ftp get append","",append);
+ }
+#endif /* DEBUG */
+
+ rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"ftp get rc",s,rc);
+ debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
+ debug(F111,"ftp get cancelfile",s,cancelfile);
+ debug(F111,"ftp get cancelgroup",s,cancelgroup);
+ debug(F111,"ftp get renaming",s,renaming);
+ debug(F111,"ftp get moving",s,moving);
+ }
+#endif /* DEBUG */
+ }
+ if (rc > -1) {
+ good++;
+ status = 1;
+ if (!cancelfile) {
+ if (deleting) { /* GET /DELETE (source file) */
+ rc =
+ (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
+ ? 1 : -1;
+ tlog(F110, (rc > -1) ?
+ " deleted" : " failed to delete", s, 0);
+ }
+ if (renaming && rcv_rename && !toscreen) {
+ char *p; /* Rename downloaded file */
+#ifndef NOSPL
+ char tmpbuf[CKMAXPATH+1];
+ int n;
+ n = CKMAXPATH;
+ p = tmpbuf;
+ debug(F111,"ftp get /rename",rcv_rename,0);
+ zzstring(rcv_rename,&p,&n);
+ debug(F111,"ftp get /rename",rcv_rename,0);
+ p = tmpbuf;
+#else
+ p = rcv_rename;
+#endif /* NOSPL */
+ rc = (zrename(s2,p) < 0) ? -1 : 1;
+ debug(F111,"doftpget /RENAME zrename",p,rc);
+ tlog(F110, (rc > -1) ?
+ " renamed to" :
+ " failed to rename to",
+ p,
+ 0
+ );
+ } else if (moving && rcv_move && !toscreen) {
+ char *p; /* Move downloaded file */
+#ifndef NOSPL
+ char tmpbuf[CKMAXPATH+1];
+ int n;
+ n = TMPBUFSIZ;
+ p = tmpbuf;
+ debug(F111,"ftp get /move-to",rcv_move,0);
+ zzstring(rcv_move,&p,&n);
+ p = tmpbuf;
+#else
+ p = rcv_move;
+#endif /* NOSPL */
+ debug(F111,"ftp get /move-to",p,0);
+ rc = (zrename(s2,p) < 0) ? -1 : 1;
+ debug(F111,"doftpget /MOVE zrename",p,rc);
+ tlog(F110, (rc > -1) ?
+ " moved to" : " failed to move to", p, 0);
+ }
+ if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
+ char * s = pv[SND_SRN].sval;
+ char * srvrn = pv[SND_SRN].sval;
+ char tmpbuf[CKMAXPATH+1];
+#ifndef NOSPL
+ int y; /* Pass it thru the evaluator */
+ extern int cmd_quoting; /* for \v(filename) */
+ debug(F111,"ftp get srv_renam",s,1);
+
+ if (cmd_quoting) {
+ y = CKMAXPATH;
+ s = (char *)tmpbuf;
+ zzstring(srvrn,&s,&y);
+ s = (char *)tmpbuf;
+ }
+#endif /* NOSPL */
+ debug(F111,"ftp get srv_renam",s,1);
+ if (s) if (*s) {
+ int x;
+ x = ftp_rename(s2,s);
+ debug(F111,"ftp get ftp_rename",s2,x);
+ tlog(F110, (x > 0) ?
+ " renamed source file to" :
+ " failed to rename source file to",
+ s,
+ 0
+ );
+ if (x < 1)
+ return(-1);
+ }
+ }
+ }
+ }
+ if (cancelfile)
+ continue;
+ if (rc < 0) {
+ ftp_fai++;
+#ifdef FTP_TIMEOUT
+ debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
+ if (ftp_timed_out) {
+ status = 0;
+ ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
+ }
+#endif /* FTP_TIMEOUT */
+ if (geterror) {
+ status = 0;
+ ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
+ done++;
+ }
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"ftp get status","",status);
+ debug(F101,"ftp get cancelgroup","",cancelgroup);
+ debug(F101,"ftp get cancelfile","",cancelfile);
+ debug(F101,"ftp get selected","",selected);
+ debug(F101,"ftp get good","",good);
+ }
+#endif /* DEBUG */
+
+ if (selected == 0) { /* No files met selection criteria */
+ status = 1; /* which is a kind of success. */
+ } else if (status > 0) { /* Some files were selected */
+ if (cancelgroup) /* but MGET was canceled */
+ status = 0; /* so MGET failed */
+ else if (cancelfile && good < 1) /* If file was canceled */
+ status = 0; /* MGET failed if it got no files */
+ }
+ success = status;
+ x = success;
+ debug(F101,"ftp get success","",success);
+
+ xgetx:
+ pipesend = pipesave; /* Restore global pipe selection */
+ if (fp_nml) { /* Close /NAMELIST */
+ if (fp_nml != stdout)
+ fclose(fp_nml);
+ fp_nml = NULL;
+ }
+ if (
+#ifdef COMMENT
+ x > -1
+#else
+ success
+#endif /* COMMENT */
+ ) { /* Download successful */
+#ifdef GFTIMER
+ t1 = gmstimer(); /* End time */
+ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
+ if (!sec) sec = 0.001;
+ fptsecs = sec;
+#else
+ sec = (t1 - t0) / 1000;
+ if (!sec) sec = 1;
+#endif /* GFTIMER */
+ tfcps = (long) (tfc / sec);
+ tsecs = (int)sec;
+ lastxfer = W_FTP|W_RECV;
+ xferstat = success;
+ }
+ if (dpyactive)
+ ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
+#ifdef CK_TMPDIR
+ if (f_tmpdir) { /* If we changed to download dir */
+ zchdir((char *) savdir); /* Go back where we came from */
+ f_tmpdir = 0;
+ }
+#endif /* CK_TMPDIR */
+
+ for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ }
+ for (i = 0; i < mgetn; i++) /* MGET list too */
+ makestr(&(mgetlist[i]),NULL);
+
+ if (cancelgroup) /* Clear temp-file stack */
+ mlsreset();
+
+ ftreset(); /* Undo switch effects */
+ dpyactive = 0;
+ return(x);
+}
+
+static struct keytab ftprmt[] = {
+ { "cd", XZCWD, 0 },
+ { "cdup", XZCDU, 0 },
+ { "cwd", XZCWD, CM_INV },
+ { "delete", XZDEL, 0 },
+ { "directory", XZDIR, 0 },
+ { "exit", XZXIT, 0 },
+ { "help", XZHLP, 0 },
+ { "login", XZLGI, 0 },
+ { "logout", XZLGO, 0 },
+ { "mkdir", XZMKD, 0 },
+ { "pwd", XZPWD, 0 },
+ { "rename", XZREN, 0 },
+ { "rmdir", XZRMD, 0 },
+ { "type", XZTYP, 0 },
+ { "", 0, 0 }
+};
+static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
+
+int
+doftpsite() { /* Send a SITE command */
+ int reply;
+ char * s;
+ int lcs = -1, rcs = -1;
+ int save_vbm = ftp_vbm;
+
+#ifndef NOCSETS
+ if (ftp_xla) {
+ lcs = ftp_csl;
+ if (lcs < 0) lcs = fcharset;
+ rcs = ftp_csx;
+ if (rcs < 0) rcs = ftp_csr;
+ }
+#endif /* NOCSETS */
+ if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ ckstrncpy(line,s,LINBUFSIZ);
+ if (testing) printf(" ftp site \"%s\"...\n",line);
+ if (!ftp_vbm)
+ ftp_vbm = !ckstrcmp("HELP",line,4,0);
+ if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
+ do {
+ reply = getreply(0,lcs,rcs,ftp_vbm,0);
+ } while (reply == REPLY_PRELIM);
+ }
+ ftp_vbm = save_vbm;
+ return(success = (reply == REPLY_COMPLETE));
+}
+
+
+int
+dosetftppsv() { /* Passive mode */
+ x = seton(&ftp_psv);
+ if (x > 0) passivemode = ftp_psv;
+ return(x);
+}
+
+/* d o f t p r m t -- Parse and execute REMOTE commands */
+
+int
+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);
+ s = brstrip(line);
+ return(doftpcwd(s,1));
+ case XZPWD: /* RPWD */
+ return(doftppwd());
+ case XZDEL: /* RDEL */
+ return(doftpget(FTP_MDE,1));
+ case XZDIR: /* RDIR */
+ return(doftpdir(FTP_DIR));
+ case XZHLP: /* RHELP */
+ return(doftpxhlp());
+ case XZMKD: /* RMKDIR */
+ return(doftpmkd());
+ case XZREN: /* RRENAME */
+ return(doftpren());
+ case XZRMD: /* RRMDIR */
+ return(doftprmd());
+ case XZLGO: /* LOGOUT */
+ return(doftpres());
+ case XZXIT: /* EXIT */
+ return(ftpbye());
+ }
+ printf("?Not usable with FTP - \"%s\"\n", atmbuf);
+ return(-9);
+}
+
+int
+doxftp() { /* Command parser for built-in FTP */
+ int cx, 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 */
+ case FTP_REP: /* REPUT */
+ return(doftpput(cx,1));
+
+ case FTP_PWD: /* PWD */
+ x = doftppwd();
+ if (x > -1) success = x;
+ return(x);
+
+ case FTP_REN: /* RENAME */
+ return(doftpren());
+
+ case FTP_RES: /* RESET */
+ return(doftpres());
+
+ case FTP_HLP: /* (remote) HELP */
+ return(doftpxhlp());
+
+ case FTP_RMD: /* RMDIR */
+ return(doftprmd());
+
+ case FTP_STA: /* STATUS */
+ if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ ckstrncpy(line,s,LINBUFSIZ);
+ if (testing) printf(" ftp status \"%s\"...\n",line);
+ success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
+ return(success);
+
+ case FTP_SIT: { /* SITE */
+ return(doftpsite());
+ }
+
+ case FTP_SIZ: /* (ask for) SIZE */
+ if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ ckstrncpy(line,s,LINBUFSIZ);
+ if (testing)
+ printf(" ftp size \"%s\"...\n",line);
+ success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
+ if (success)
+ sizeok = 1;
+ return(success);
+
+ case FTP_SYS: /* Ask for server's SYSTEM type */
+ if ((x = cmcfm()) < 0) return(x);
+ CHECKCONN();
+ if (testing)
+ printf(" ftp system...\n");
+ success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
+ return(success);
+
+ case FTP_UMA: /* Set/query UMASK */
+ if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
+ if (x != -3)
+ return(x);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = cmcfm()) < 0) return(x);
+ CHECKCONN();
+ if (testing) {
+ if (tmpbuf[0])
+ printf(" ftp umask \"%s\"...\n",tmpbuf);
+ else
+ printf(" ftp query umask...\n");
+ }
+ success = ftp_umask(tmpbuf);
+ return(success);
+
+ case FTP_USR:
+ return(doftpusr());
+
+ case FTP_QUO:
+ if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
+ return(success);
+
+ case FTP_TYP: /* Type */
+ if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ CHECKCONN();
+ ftp_typ = x;
+ g_ftp_typ = x;
+ tenex = (ftp_typ == FTT_TEN);
+ changetype(ftp_typ,ftp_vbm);
+ return(1);
+
+ case FTP_CHK: /* Check if remote file(s) exist(s) */
+ if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
+ return(success);
+
+ case FTP_FEA: /* RFC2389 */
+ if ((y = cmcfm()) < 0)
+ return(y);
+ CHECKCONN();
+ success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
+ if (success) {
+ if (sfttab[0] > 0) {
+ ftp_aut = sfttab[SFT_AUTH];
+ sizeok = sfttab[SFT_SIZE];
+ mdtmok = sfttab[SFT_MDTM];
+ mlstok = sfttab[SFT_MLST];
+ }
+ }
+ return(success);
+
+ case FTP_OPT: /* RFC2389 */
+ /* Perhaps this should be a keyword list... */
+ if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
+ return(x);
+ CHECKCONN();
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
+ return(x);
+ success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
+ return(success);
+
+ case FTP_ENA: /* FTP ENABLE */
+ case FTP_DIS: /* FTP DISABLE */
+ if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ switch (x) {
+ case ENA_AUTH: /* OK to use autoauthentication */
+ ftp_aut = (cx == FTP_ENA) ? 1 : 0;
+ sfttab[SFT_AUTH] = ftp_aut;
+ break;
+ case ENA_FEAT: /* OK to send FEAT command */
+ featok = (cx == FTP_ENA) ? 1 : 0;
+ break;
+ case ENA_MLST: /* OK to use MLST/MLSD */
+ mlstok = (cx == FTP_ENA) ? 1 : 0;
+ sfttab[SFT_MLST] = mlstok;
+ break;
+ case ENA_MDTM: /* OK to use MDTM */
+ mdtmok = (cx == FTP_ENA) ? 1 : 0;
+ sfttab[SFT_MDTM] = mdtmok;
+ break;
+ case ENA_SIZE: /* OK to use SIZE */
+ sizeok = (cx == FTP_ENA) ? 1 : 0;
+ sfttab[SFT_SIZE] = sizeok;
+ break;
+ }
+ return(success = 1);
+ }
+ return(-2);
+}
+
+#ifndef NOSHOW
+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) int 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;
+ }
+#ifdef FTP_TIMEOUT
+ printf(" ftp timeout: %ld\n",ftp_timeout);
+#endif /* FTP_TIMEOUT */
+ printf(" ftp type: %s\n",s);
+ printf(" ftp get-filetype-switching: %s\n",showoff(get_auto));
+ printf(" ftp dates: %s\n",showoff(ftp_dates));
+ printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed");
+ printf(" ftp filenames: %s\n",
+ ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
+ );
+ printf(" ftp debug %s\n",showoff(ftp_deb));
+
+ printf(" ftp passive-mode: %s\n",showoff(ftp_psv));
+ printf(" ftp permissions: %s\n",showooa(ftp_prm));
+ printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx));
+ printf(" ftp send-port-commands: %s\n",showoff(ftp_psv));
+ printf(" ftp unique-server-names: %s\n",showoff(ftp_usn));
+#ifdef COMMENT
+ /* See note in doxftp() */
+ if (ftp_fnc < 0)
+ ftp_fnc = fncact;
+#endif /* COMMENT */
+ printf(" ftp collision: %s\n",
+ fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
+ printf(" ftp server-time-offset: %s\n",
+ fts_sto ? fts_sto : "(none)");
+ n += 15;
+
+#ifndef NOCSETS
+ printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+
+ printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword);
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+
+ printf(" file character-set: %s\n",fcsinfo[fcharset].keyword);
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+#endif /* NOCSETS */
+
+ x = ftp_dis;
+ if (x < 0)
+ x = fdispla;
+ switch (x) {
+ case XYFD_N: s = "none"; break;
+ case XYFD_R: s = "serial"; break;
+ case XYFD_C: s = "fullscreen"; break;
+ case XYFD_S: s = "crt"; break;
+ case XYFD_B: s = "brief"; break;
+ }
+ printf(" ftp display: %s\n",s);
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+
+ if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
+ printf(" enabled: ");
+ if (ftp_aut) printf(" AUTH");
+ if (featok) printf(" FEAT");
+ if (mdtmok) printf(" MDTM");
+ if (mlstok) printf(" MLST");
+ if (sizeok) printf(" SIZE");
+ printf("\n");
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ }
+ if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
+ printf(" disabled: ");
+ if (!ftp_aut) printf(" AUTH");
+ if (!featok) printf(" FEAT");
+ if (!mdtmok) printf(" MDTM");
+ if (!mlstok) printf(" MLST");
+ if (!sizeok) printf(" SIZE");
+ printf("\n");
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ }
+ switch (ftpget) {
+ case 0: s = "kermit"; break;
+ case 1: s = "ftp"; break;
+ case 2: s = "auto"; break;
+ default: s = "?";
+ }
+ printf(" get-put-remote: %s\n",s);
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+
+ printf("\n");
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+
+#ifdef FTP_SECURITY
+ printf("Available security methods: ");
+#ifdef FTP_GSSAPI
+ printf("GSSAPI ");
+#endif /* FTP_GSSAPI */
+#ifdef FTP_KRB4
+ printf("Kerberos4 ");
+#endif /* FTP_KRB4 */
+#ifdef FTP_SRP
+ printf("SRP ");
+#endif /* FTP_SRP */
+#ifdef FTP_SSL
+ printf("SSL ");
+#endif /* FTP_SSL */
+
+ n++;
+ printf("\n\n");
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ printf(" ftp authtype: %s\n",strval(auth_type,NULL));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ printf(" ftp auto-encryption: %s\n",showoff(ftp_cry));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+ printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy));
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+#else
+ printf("Available security methods: (none)\n");
+ if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
+#endif /* FTP_SECURITY */
+
+ if (n <= cmd_rows - 3)
+ printf("\n");
+ return(0);
+}
+#endif /* NOSHOW */
+
+#ifndef NOHELP
+/* FTP HELP text strings */
+
+static char * fhs_ftp[] = {
+ "Syntax: FTP subcommand [ operands ]",
+ " Makes an FTP connection, or sends a command to the FTP server.",
+ " To see a list of available FTP subcommands, type \"ftp ?\".",
+ " and then use HELP FTP xxx to get help about subcommand xxx.",
+ " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
+ ""
+};
+
+static char * fhs_acc[] = { /* ACCOUNT */
+ "Syntax: FTP ACCOUNT text",
+ " Sends an account designator to an FTP server that needs one.",
+ " Most FTP servers do not use accounts; some use them for other",
+ " other purposes, such as disk-access passwords.",
+ ""
+};
+static char * fhs_app[] = { /* APPEND */
+ "Syntax: FTP APPEND filname",
+ " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.",
+ ""
+};
+static char * fhs_cls[] = { /* BYE, CLOSE */
+ "Syntax: [ FTP ] BYE",
+ " Logs out from the FTP server and closes the FTP connection.",
+ " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.",
+ ""
+};
+static char * fhs_cwd[] = { /* CD, CWD */
+ "Syntax: [ FTP ] CD directory",
+ " Asks the FTP server to change to the given directory.",
+ " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.",
+ ""
+};
+static char * fhs_gup[] = { /* CDUP, UP */
+ "Syntax: FTP CDUP",
+ " Asks the FTP server to change to the parent directory of its current",
+ " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.",
+ ""
+};
+static char * fhs_chm[] = { /* CHMOD */
+ "Syntax: FTP CHMOD filename permissions",
+ " Asks the FTP server to change the permissions, protection, or mode of",
+ " the given file. The given permissions must be in the syntax of the",
+ " the server's file system, e.g. an octal number for UNIX. Also see",
+ " FTP PUT /PERMISSIONS",
+ ""
+};
+static char * fhs_mde[] = { /* DELETE */
+ "Syntax: FTP DELETE [ switches ] filespec",
+ " Asks the FTP server to delete the given file or files.",
+ " Synonym: MDELETE (Kermit makes no distinction between single and",
+ " multiple file deletion). Optional switches:",
+ " ",
+ " /ERROR-ACTION:{PROCEED,QUIT}",
+ " /EXCEPT:pattern",
+ " /FILENAMES:{AUTO,CONVERTED,LITERAL}",
+ " /LARGER-THAN:number",
+#ifdef UNIXOROSK
+ " /NODOTFILES",
+#endif /* UNIXOROSK */
+ " /QUIET",
+#ifdef RECURSIVE
+ " /RECURSIVE (depends on server)",
+ " /SUBDIRECTORIES",
+#endif /* RECURSIVE */
+ " /SMALLER-THAN:number",
+ ""
+};
+static char * fhs_dir[] = { /* DIRECTORY */
+ "Syntax: FTP DIRECTORY [ filespec ]",
+ " Asks the server to send a directory listing of the files that match",
+ " the given filespec, or if none is given, all the files in its current",
+ " directory. The filespec, including any wildcards, must be in the",
+ " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.",
+ " Synonym: RDIRECTORY.",
+ ""
+};
+static char * fhs_vdi[] = { /* VDIRECTORY */
+ "Syntax: FTP VDIRECTORY [ filespec ]",
+ " Asks the server to send a directory listing of the files that match",
+ " the given filespec, or if none is given, all the files in its current",
+ " directory. VDIRECTORY is needed for getting verbose directory",
+ " listings from certain FTP servers, such as on TOPS-20. Try it if",
+ " FTP DIRECTORY lists only filenames without details.",
+ ""
+};
+static char * fhs_fea[] = { /* FEATURES */
+ "Syntax: FTP FEATURES",
+ " Asks the FTP server to list its special features. Most FTP servers",
+ " do not recognize this command.",
+ ""
+};
+static char * fhs_mge[] = { /* MGET */
+ "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
+ " Download a single file or multiple files. Asks the FTP server to send",
+ " the given file or files. Also see FTP GET. Optional switches:",
+ " ",
+ " /AS-NAME:text",
+ " Name under which to store incoming file.",
+ " Pattern required for for multiple files.",
+ " /BINARY", /* /IMAGE */
+ " Force binary mode. Synonym: /IMAGE.",
+ " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
+ " What to do if an incoming file has the same name as an existing file.",
+
+#ifdef PUTPIPE
+ " /COMMAND",
+ " Specifies that the as-name is a command to which the incoming file",
+ " is to be piped as standard input.",
+#endif /* PUTPIPE */
+
+#ifdef DOUPDATE
+ " /DATES-DIFFER",
+ " Download only those files whose modification date-times differ from",
+ " those of the corresponding local files, or that do not already",
+ " exist on the local computer.",
+#endif /* DOUPDATE */
+
+ " /DELETE",
+ " Specifies that each file is to be deleted from the server after,",
+ " and only if, it is successfully downloaded.",
+ " /ERROR-ACTION:{PROCEED,QUIT}",
+ " When downloading a group of files, what to do upon failure to",
+ " transfer a file: quit or proceed to the next one.",
+ " /EXCEPT:pattern",
+ " Exception list: don't download any files that match this pattern.",
+ " See HELP WILDCARD for pattern syntax.",
+ " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
+ " Whether to convert incoming filenames to local syntax.",
+#ifdef PIPESEND
+#ifndef NOSPL
+ " /FILTER:command",
+ " Pass incoming files through the given command.",
+#endif /* NOSPL */
+#endif /* PIPESEND */
+ " /LARGER-THAN:number",
+ " Only download files that are larger than the given number of bytes.",
+ " /LISTFILE:filename",
+ " Obtain the list of files to download from the given file.",
+#ifndef NOCSETS
+ " /LOCAL-CHARACTER-SET:name",
+ " When downloading in text mode and character-set conversion is",
+ " desired, this specifies the target set.",
+#endif /* NOCSETS */
+ " /MATCH:pattern",
+ " Specifies a pattern to be used to select filenames locally from the",
+ " server's list.",
+ " /MLSD",
+ " Forces sending of MLSD (rather than NLST) to get the file list.",
+#ifdef CK_TMPDIR
+ " /MOVE-TO:directory",
+ " Each file that is downloaded is to be moved to the given local",
+ " directory immediately after, and only if, it has been received",
+ " successfully.",
+#endif /* CK_TMPDIR */
+ " /NAMELIST:filename",
+ " Instead of downloading the files, stores the list of files that",
+ " would be downloaded in the given local file, one filename per line.",
+ " /NLST",
+ " Forces sending of NLST (rather than MLSD) to get the file list.",
+ " /NOBACKUPFILES",
+ " Don't download any files whose names end with .~<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 successfully.",
+ " /SMALLER-THAN:number",
+ " Download only those files smaller than the given number of bytes.",
+ " /TEXT", /* /ASCII */
+ " Force text mode. Synonym: /ASCII.",
+ " /TENEX",
+ " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
+#ifndef NOCSETS
+ " /TRANSPARENT",
+ " When downloading in text mode, do not convert chracter-sets.",
+#endif /* NOCSETS */
+ " /TO-SCREEN",
+ " The downloaded file is to be displayed on the screen.",
+#ifdef DOUPDATE
+ " /UPDATE",
+ " Equivalent to /COLLISION:UPDATE. Download only those files that are",
+ " newer than than their local counterparts, or that do not exist on",
+ " the local computer.",
+#endif /* DOUPDATE */
+ ""
+};
+static char * fhs_hlp[] = { /* HELP */
+ "Syntax: FTP HELP [ command [ subcommand... ] ]",
+ " Asks the FTP server for help about the given command. First use",
+ " FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
+ " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.",
+ ""
+};
+static char * fhs_idl[] = { /* IDLE */
+ "Syntax: FTP IDLE [ number ]",
+ " If given without a number, this asks the FTP server to tell its",
+ " current idle-time limit. If given with a number, it asks the server",
+ " to change its idle-time limit to the given number of seconds.",
+ ""
+};
+static char * fhs_usr[] = { /* USER, LOGIN */
+ "Syntax: FTP USER username [ password [ account ] ]",
+ " Log in to the FTP server. To be used when connected but not yet",
+ " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
+ " If you omit the password, and one is required by the server, you are",
+ " prompted for it. If you omit the account, no account is sent.",
+ " Synonym: FTP LOGIN.",
+ ""
+};
+static char * fhs_get[] = { /* GET */
+ "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
+ " Download a single file. Asks the FTP server to send the given file.",
+ " The optional as-name is the name to store it under when it arrives;",
+ " if omitted, the file is stored with the name it arrived with, as",
+ " modified according to the FTP FILENAMES setting or /FILENAMES: switch",
+ " value. Aside from the file list and as-name, syntax and options are",
+ " the same as for FTP MGET, which is used for downloading multiple files."
+, ""
+};
+static char * fhs_mkd[] = { /* MKDIR */
+ "Syntax: FTP MKDIR directory",
+ " Asks the FTP server to create a directory with the given name,",
+ " which must be in the syntax of the server's file system. Synonyms:",
+ " REMOTE MKDIR, RMKDIR.",
+ ""
+};
+static char * fhs_mod[] = { /* MODTIME */
+ "Syntax: FTP MODTIME filename",
+ " Asks the FTP server to send the modification time of the given file,",
+ " to be displayed on the screen. The date-time format is all numeric:",
+ " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
+ " fractions of seconds).",
+ ""
+};
+static char * fhs_mpu[] = { /* MPUT */
+ "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
+ " Uploads files. Sends the given file or files to the FTP server.",
+ " Also see FTP PUT. Optional switches are:",
+ " ",
+ " /AFTER:date-time",
+ " Uploads only those files newer than the given date-time.",
+ " HELP DATE for info about date-time formats. Synonym: /SINCE.",
+#ifdef PUTARRAY
+ " /ARRAY:array-designator",
+ " Tells Kermit to upload the contents of the given array, rather than",
+ " a file.",
+#endif /* PUTARRAY */
+ " /AS-NAME:text",
+ " Name under which to send files.",
+ " Pattern required for for multiple files.",
+ " /BEFORE:date-time",
+ " Upload only those files older than the given date-time.",
+ " /BINARY",
+ " Force binary mode. Synonym: /IMAGE.",
+#ifdef PUTPIPE
+ " /COMMAND",
+ " Specifies that the filespec is a command whose standard output is",
+ " to be sent.",
+#endif /* PUTPIPE */
+
+#ifdef COMMENT
+#ifdef DOUPDATE
+ " /DATES-DIFFER",
+ " Upload only those files whose modification date-times differ from",
+ " those on the server, or that don't exist on the server at all.",
+#endif /* DOUPDATE */
+#endif /* COMMENT */
+
+ " /DELETE",
+ " Specifies that each source file is to be deleted after, and only if,",
+ " it is successfully uploaded.",
+ " /DOTFILES",
+ " Include files whose names begin with period (.).",
+ " /ERROR-ACTION:{PROCEED,QUIT}",
+ " When uploading a group of files, what to do upon failure to",
+ " transfer a file: quit or proceed to the next one.",
+ " /EXCEPT:pattern",
+ " Exception list: don't upload any files that match this pattern.",
+ " See HELP WILDCARD for pattern syntax.",
+ " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
+ " Whether to convert outbound filenames to common syntax.",
+#ifdef PIPESEND
+#ifndef NOSPL
+ " /FILTER:command",
+ " Pass outbound files through the given command.",
+#endif /* NOSPL */
+#endif /* PIPESEND */
+#ifdef CKSYMLINK
+ " /FOLLOWINKS",
+ " Send files that are pointed to by symbolic links.",
+ " /NOFOLLOWINKS",
+ " Skip over symbolic links (default).",
+#endif /* CKSYMLINK */
+ " /LARGER-THAN:number",
+ " Only upload files that are larger than the given number of bytes.",
+ " /LISTFILE:filename",
+ " Obtain the list of files to upload from the given file.",
+#ifndef NOCSETS
+ " /LOCAL-CHARACTER-SET:name",
+ " When uploading in text mode and character-set conversion is",
+ " desired, this specifies the source-file character set.",
+#endif /* NOCSETS */
+#ifdef CK_TMPDIR
+ " /MOVE-TO:directory",
+ " Each source file that is uploaded is to be moved to the given local",
+ " directory when, and only if, the transfer is successful.",
+#endif /* CK_TMPDIR */
+ " /NOBACKUPFILES",
+ " Don't upload any files whose names end with .~<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_reput[] = { /* REPUT, RESEND */
+ "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
+ " Synonym for FTP PUT /RECOVER. Recovers an interrupted binary-mode",
+ " upload from the point of failure if the FTP server supports recovery.",
+ " Synonym: [ FTP ] RESEND. For details see HELP FTP MPUT.",
+ ""
+};
+static char * fhs_pwd[] = { /* PWD */
+ "Syntax: FTP PWD",
+ " Asks the FTP server to reveal its current working directory.",
+ " Synonyms: REMOTE PWD, RPWD.",
+ ""
+};
+static char * fhs_quo[] = { /* QUOTE */
+ "Syntax: FTP QUOTE text",
+ " Sends an FTP protocol command to the FTP server. Use this command",
+ " for sending commands that Kermit might not support.",
+ ""
+};
+static char * fhs_rge[] = { /* REGET */
+ "Syntax: FTP REGET",
+ " Synonym for FTP GET /RECOVER.",
+ ""
+};
+static char * fhs_ren[] = { /* RENAME */
+ "Syntax: FTP RENAME name1 name1",
+ " Asks the FTP server to change the name of the file whose name is name1",
+ " and which resides in the FTP server's file system, to name2. Works",
+ " only for single files; wildcards are not accepted.",
+ ""
+};
+static char * fhs_res[] = { /* RESET */
+ "Syntax: FTP RESET",
+ " Asks the server to log out your session, terminating your access",
+ " rights, without closing the connection.",
+ ""
+};
+static char * fhs_rmd[] = { /* RMDIR */
+ "Syntax: FTP RMDIR directory",
+ " Asks the FTP server to remove the directory whose name is given.",
+ " This usually requires the directory to be empty. Synonyms: REMOTE",
+ " RMDIR, RRMDIR.",
+ ""
+};
+static char * fhs_sit[] = { /* SITE */
+ "Syntax: FTP SITE text",
+ " Sends a site-specific command to the FTP server.",
+ ""
+};
+static char * fhs_siz[] = { /* SIZE */
+ "Syntax: FTP SIZE filename",
+ " Asks the FTP server to send a numeric string representing the size",
+ " of the given file.",
+ ""
+};
+static char * fhs_sta[] = { /* STATUS */
+ "Syntax: FTP STATUS [ filename ]",
+ " Asks the FTP server to report its status. If a filename is given,",
+ " the FTP server should report details about the file.",
+ ""
+};
+static char * fhs_sys[] = { /* SYSTEM */
+ "Syntax: FTP SYSTEM",
+ " Asks the FTP server to report its operating system type.",
+ ""
+};
+static char * fhs_typ[] = { /* TYPE */
+ "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
+ " Puts the client and server in the indicated transfer mode.",
+ " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit",
+ " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
+ " downloading files from TENEX or TOPS-20 that have been uploaded in",
+ " TENEX mode.",
+ ""
+};
+static char * fhs_uma[] = { /* UMASK */
+ "Syntax: FTP UMASK number",
+ " Asks the FTP server to set its file creation mode mask. Applies",
+ " only (or mainly) to UNIX-based FTP servers.",
+ ""
+};
+static char * fhs_chk[] = { /* CHECK */
+ "Syntax: FTP CHECK remote-filespec",
+ " Asks the FTP server if the given file or files exist. If the",
+ " remote-filespec contains wildcards, this command fails if no server",
+ " files match, and succeeds if at least one file matches. If the",
+ " remote-filespec does not contain wildcards, this command succeeds if",
+ " the given file exists and fails if it does not.",
+ ""
+};
+static char * fhs_ena[] = { /* ENABLE */
+ "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
+ " Enables the use of the given FTP protocol command in case it has been",
+ " disabled (but this is no guarantee that the FTP server understands it)."
+,
+ " Use SHOW FTP to see which of these commands is enabled and disabled.",
+ " Also see FTP DISABLE.",
+ ""
+};
+static char * fhs_dis[] = { /* DISABLE */
+ "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
+ " Disables the use of the given FTP protocol command.",
+ " Also see FTP ENABLE.",
+ ""
+};
+
+#endif /* NOHELP */
+
+int
+doftphlp() {
+ int cx;
+ if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
+ if (cx != -3)
+ return(cx);
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#ifdef NOHELP
+ printf("Sorry, no help available\n");
+#else
+ switch (cx) {
+ case -3:
+ return(hmsga(fhs_ftp));
+ case FTP_ACC: /* ACCOUNT */
+ return(hmsga(fhs_acc));
+ case FTP_APP: /* APPEND */
+ return(hmsga(fhs_app));
+ case FTP_CLS: /* BYE, CLOSE */
+ return(hmsga(fhs_cls));
+ case FTP_CWD: /* CD, CWD */
+ return(hmsga(fhs_cwd));
+ case FTP_GUP: /* CDUP, UP */
+ return(hmsga(fhs_gup));
+ case FTP_CHM: /* CHMOD */
+ return(hmsga(fhs_chm));
+ case FTP_MDE: /* DELETE, MDELETE */
+ return(hmsga(fhs_mde));
+ case FTP_DIR: /* DIRECTORY */
+ return(hmsga(fhs_dir));
+ case FTP_VDI: /* VDIRECTORY */
+ return(hmsga(fhs_vdi));
+ case FTP_FEA: /* FEATURES */
+ return(hmsga(fhs_fea));
+ case FTP_GET: /* GET */
+ return(hmsga(fhs_get));
+ case FTP_HLP: /* HELP */
+ return(hmsga(fhs_hlp));
+ case FTP_IDL: /* IDLE */
+ return(hmsga(fhs_idl));
+ case FTP_USR: /* USER, LOGIN */
+ return(hmsga(fhs_usr));
+ case FTP_MGE: /* MGET */
+ return(hmsga(fhs_mge));
+ case FTP_MKD: /* MKDIR */
+ return(hmsga(fhs_mkd));
+ case FTP_MOD: /* MODTIME */
+ return(hmsga(fhs_mod));
+ case FTP_MPU: /* MPUT */
+ return(hmsga(fhs_mpu));
+ case FTP_OPN: /* OPEN */
+ return(hmsga(fhs_opn));
+ case FTP_OPT: /* OPTS, OPTIONS */
+ return(hmsga(fhs_opt));
+ case FTP_PUT: /* PUT, SEND */
+ return(hmsga(fhs_put));
+ case FTP_REP: /* REPUT, RESEND */
+ return(hmsga(fhs_reput));
+ case FTP_PWD: /* PWD */
+ return(hmsga(fhs_pwd));
+ case FTP_QUO: /* QUOTE */
+ return(hmsga(fhs_quo));
+ case FTP_RGE: /* REGET */
+ return(hmsga(fhs_rge));
+ case FTP_REN: /* RENAME */
+ return(hmsga(fhs_ren));
+ case FTP_RES: /* RESET */
+ return(hmsga(fhs_res));
+ case FTP_RMD: /* RMDIR */
+ return(hmsga(fhs_rmd));
+ case FTP_SIT: /* SITE */
+ return(hmsga(fhs_sit));
+ case FTP_SIZ: /* SIZE */
+ return(hmsga(fhs_siz));
+ case FTP_STA: /* STATUS */
+ return(hmsga(fhs_sta));
+ case FTP_SYS: /* SYSTEM */
+ return(hmsga(fhs_sys));
+ case FTP_TYP: /* TYPE */
+ return(hmsga(fhs_typ));
+ case FTP_UMA: /* UMASK */
+ return(hmsga(fhs_uma));
+ case FTP_CHK: /* CHECK */
+ return(hmsga(fhs_chk));
+ case FTP_ENA:
+ return(hmsga(fhs_ena));
+ case FTP_DIS:
+ return(hmsga(fhs_dis));
+ default:
+ printf("Sorry, help available for this command.\n");
+ break;
+ }
+#endif /* NOHELP */
+ return(success = 0);
+}
+
+int
+dosetftphlp() {
+ int cx;
+ if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
+ if (cx != -3)
+ return(cx);
+ if (cx != -3)
+ ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#ifdef NOHELP
+ printf("Sorry, no help available\n");
+#else
+ switch (cx) {
+ case -3:
+ printf("\nSyntax: SET FTP parameter value\n");
+ printf(" Type \"help set ftp ?\" for a list of parameters.\n");
+ printf(" Type \"help set ftp xxx\" for information about setting\n");
+ printf(" parameter xxx. Type \"show ftp\" for current values.\n\n");
+ return(0);
+
+ case FTS_BUG:
+ printf("\nSyntax: SET FTP BUG <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. ASCII is a synonym for TEXT. Normally each\n");
+ printf(" file's type is determined automatically from its contents\n"
+ );
+ printf(" or its name; SET FTP TYPE does not prevent that, it only\n");
+ printf(" tells which mode to use when the type can't be determined\n"
+ );
+ printf(" automatically. To completely disable automatic transfer-\n"
+ );
+ printf(" mode switching and force either text or binary mode, give\n"
+ );
+ printf(" the top-level command ASCII or BINARY, as in traditional\n");
+ printf(" FTP clients.\n\n");
+ return(0);
+
+#ifdef FTP_TIMEOUT
+ case FTS_TMO:
+ printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
+ printf(" Establishes a timeout for FTP transfers.\n");
+ printf(" The timeout applies per network read or write on the data\n");
+ printf(" connection, not to the whole transfer. By default the\n");
+ printf(" timeout value is 0, meaning no timeout. Use a positive\n");
+ printf(" number to escape gracefully from hung data connections or\n");
+ printf(" directory listings.\n\n");
+ return(0);
+#endif /* FTP_TIMEOUT */
+
+#ifdef PATTERNS
+ case FTS_GFT:
+ printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
+ printf(" Tells whether GET and MGET should automatically switch\n");
+ printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n");
+ printf(" matching the name of each incoming file with its list of\n");
+ printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n");
+ printf(" default. SHOW PATTERNS displays the current pattern\n");
+ printf(" list. HELP SET FILE to see how to change it.\n");
+ break;
+#endif /* PATTERNS */
+
+ case FTS_USN: /* "unique-server-names" */
+ printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
+ printf(" Tells whether to ask the server to create unique names\n");
+ printf(" for any uploaded file that has the same name as an\n");
+ printf(" existing file. Default is OFF.\n\n");
+ return(0);
+
+ case FTS_VBM: /* "verbose-mode" */
+ printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
+ printf(" Whether to display all responses from the FTP server.\n");
+ printf(" OFF by default.\n\n");
+ return(0);
+
+ case FTS_DAT:
+ printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
+ printf(" Whether to set date of incoming files from the file date\n");
+ printf(" on the server. ON by default. Note: there is no way to\n")
+ ;
+ printf(" set the date on files uploaded to the server. Also note\n");
+ printf(" that not all servers support this feature.\n\n");
+ return(0);
+
+ case FTS_APW:
+ printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
+ printf(" Password to supply automatically on anonymous FTP\n");
+ printf(" connections instead of the default user@host.\n");
+ printf(" Omit optional text to restore default.\n\n");
+ return(0);
+
+ default:
+ printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
+ }
+#endif /* NOHELP */
+ return(0);
+}
+
+#ifndef L_SET
+#define L_SET 0
+#endif /* L_SET */
+#ifndef L_INCR
+#define L_INCR 1
+#endif /* L_INCR */
+
+#ifdef FTP_SRP
+char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */
+char *srp_pass;
+char *srp_acct;
+#endif /* FTP_SRP */
+
+static int kerror; /* Needed for all auth types */
+
+static struct sockaddr_in hisctladdr;
+static struct sockaddr_in hisdataaddr;
+static struct sockaddr_in data_addr;
+static int data = -1;
+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);
+ ftp_xfermode = xfermode;
+ if (!ftp_vbm && !quiet)
+ printlines = 1;
+ ftpcmd("QUIT",NULL,0,0,ftp_vbm);
+ if (csocket) {
+#ifdef CK_SSL
+ if (ssl_ftp_active_flag) {
+ SSL_shutdown(ssl_ftp_con);
+ SSL_free(ssl_ftp_con);
+ ssl_ftp_proxy = 0;
+ ssl_ftp_active_flag = 0;
+ ssl_ftp_con = NULL;
+ }
+#endif /* CK_SSL */
+#ifdef TCPIPLIB
+ socket_close(csocket);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(csocket, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(csocket);
+#endif /* TCPIPLIB */
+ }
+ csocket = -1;
+ connected = 0;
+ anonymous = 0;
+ loggedin = 0;
+ mdtmok = 1;
+ sizeok = 1;
+ featok = 1;
+ stouarg = 1;
+ typesent = 0;
+ data = -1;
+ globaldin = -1;
+#ifdef FTP_PROXY
+ if (!proxy)
+ macnum = 0;
+#endif /* FTP_PROXY */
+ auth_type = NULL;
+ ftp_dpl = FPL_CLR;
+#ifdef CKLOGDIAL
+ ftplogend();
+#endif /* CKLOGDIAL */
+#ifdef LOCUS
+ /* Unprefixed file management commands are executed locally */
+ if (autolocus && !ftp_cmdlin && !quitting) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+#ifdef OS2
+ DialerSend(OPT_KERMIT_HANGUP, 0);
+#endif /* OS2 */
+ return(0);
+}
+
+int
+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((unsigned short)ftp_port); /* SMS 2007/02/15 */
+ }
+ } else
+ ftp_port = atoi(service);
+ if (ftp_port <= 0) {
+ printf("?Bad port name - \"%s\"\n", service);
+ ftpcode = -1;
+ return(0);
+ }
+ host = ftp_hookup(remote, ftp_port, use_tls);
+ if (host) {
+ ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
+ connected = 1; /* Set FTP defaults */
+ ftp_cpl = ftp_dpl = FPL_CLR;
+ curtype = FTT_ASC; /* Server uses ASCII mode */
+ form = FORM_N;
+ mode = MODE_S;
+ stru = STRU_F;
+ strcpy(bytename, "8");
+ bytesize = 8;
+
+#ifdef FTP_SECURITY
+ if (ftp_aut) {
+ if (ftp_auth()) {
+ if (ftp_cry
+#ifdef OS2
+ && ck_crypt_is_installed()
+#endif /* OS2 */
+ ) {
+ if (!quiet)
+ printf("FTP Command channel is Private (encrypted)\n");
+ ftp_cpl = FPL_PRV;
+ if (setpbsz(DEFAULT_PBSZ) < 0) {
+ /* a failure here is most likely caused by a mixup */
+ /* in the session key used by client and server */
+ printf("?Protection buffer size negotiation failed\n");
+ return(0);
+ }
+ if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
+ if (!quiet)
+ printf("FTP Data channel is Private (encrypted)\n");
+ ftp_dpl = FPL_PRV;
+ } else
+ printf("?Unable to enable encryption on data channel\n");
+ } else {
+ ftp_cpl = FPL_SAF;
+ }
+ }
+ if (!connected)
+ goto fail;
+ }
+#endif /* FTP_SECURITY */
+ if (ftp_log) /* ^^^ */
+ ftp_login(remote);
+
+ if (!connected)
+ goto fail;
+
+ ftp_xfermode = xfermode;
+
+#ifdef CKLOGDIAL
+ dologftp();
+#endif /* CKLOGDIAL */
+#ifdef OS2
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+#endif /* OS2 */
+ passivemode = ftp_psv;
+ sendport = ftp_spc;
+ mdtmok = 1;
+ sizeok = 1;
+ stouarg = 1;
+ typesent = 0;
+
+ if (ucbuf == NULL) {
+ actualbuf = DEFAULT_PBSZ;
+ while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
+ actualbuf >>= 2;
+ }
+ if (!maxbuf)
+ ucbufsiz = actualbuf - FUDGE_FACTOR;
+ debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
+ return(1);
+ }
+ fail:
+ printf("?Can't FTP connect to %s:%s\n",remote,service);
+ ftpcode = -1;
+ return(0);
+}
+
+#ifdef CK_SSL
+int
+ssl_auth() {
+ int i;
+ char* p;
+
+ 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 && s[i] != CR && s[i] != LF)
+ return;
+ kwbuf[i] = NUL;
+ /* xlookup requires a full (but case independent) match */
+ i = xlookup(feattab,kwbuf,nfeattab,&x);
+ debug(F111,"ftp parsefeat",s,i);
+ if (i < 0 || i > 15)
+ return;
+
+ switch (i) {
+ case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
+ sfttab[i] = mdtmok;
+ if (mdtmok) sfttab[0]++;
+ break;
+ case SFT_MLST: /* ditto */
+ sfttab[i] = mlstok;
+ if (mlstok) sfttab[0]++;
+ break;
+ case SFT_SIZE: /* ditto */
+ sfttab[i] = sizeok;
+ if (sizeok) sfttab[0]++;
+ break;
+ case SFT_AUTH: /* ditto */
+ sfttab[i] = ftp_aut;
+ if (ftp_aut) sfttab[0]++;
+ break;
+ default: /* Others */
+ sfttab[0]++;
+ sfttab[i]++;
+ }
+}
+
+static char *
+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 = ckatofs(s);
+ debug(F101,"ftp parsefact size","",havesize);
+ break;
+ case FACT_TYPE: /* Type */
+ j = xlookup(ftyptab,s,nftyptab,NULL);
+ debug(F111,"ftp parsefact type",s,j);
+ havetype = (j < 1) ? 0 : j;
+ break;
+ }
+ *p = ';';
+ s = p+1; /* s points next fact or name */
+ }
+ while (*s == SP) /* Skip past spaces. */
+ s++;
+ if (!*s) /* Make sure we still have a name */
+ s = NULL;
+ debug(F110,"ftp parsefact name",s,0);
+ return(s);
+}
+
+/* g e t r e p l y -- (to an FTP command sent to server) */
+
+/* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
+
+static int
+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 = (CK_OFF_T)0;
+ } else if (sendstart > fsize) { /* Remote file bigger than local */
+ debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
+ sendstart = (CK_OFF_T)0;
+ }
+ /* Local is newer */
+ debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
+ if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
+ debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
+ sendstart = (CK_OFF_T)0; /* Send the whole file */
+ }
+ }
+ changetype(ftp_typ,0); /* Change back to appropriate type */
+ if (sendstart > (CK_OFF_T)0) { /* Still restarting? */
+ if (sendstart == fsize) { /* Same size - no need to send */
+ debug(F111,"doftpsend2 /restart SKIP",
+ ckfstoa(fsize),sendstart);
+ zclose(ZIFILE);
+ ftpsndret = SKP_RES;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ errno = 0; /* Restart needed, seek to the spot */
+ if (zfseek((long)sendstart) < 0) {
+ debug(F111,"doftpsend2 zfseek fails",
+ ftpsnd.local,sendstart);
+ fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
+ sendstart = 0;
+ zclose(ZIFILE);
+ ftpsndret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+#ifdef COMMENT
+ debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
+ x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
+ if (x != REPLY_CONTINUE) {
+ sendstart = 0;
+ zclose(ZIFILE);
+ ftpsndret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ } else {
+ ftpsnd.cmd = "STOR";
+ }
+#else
+ sendmode = SM_RESEND;
+ ftpsnd.cmd = "APPE";
+#endif /* COMMENT */
+ /* sendstart = (CK_OFF_T)0; */
+ }
+ }
+#endif /* FTP_RESTART */
+
+ if (unique && !stouarg) /* If we know STOU accepts no arg */
+ ftpsnd.remote = NULL; /* don't include one. */
+
+ x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
+ debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
+ debug(F101,"doftpsend2 ftpcmd","",x);
+
+ if (x != REPLY_PRELIM && unique) {
+ /*
+ RFC959 says STOU does not take an argument. But every FTP server
+ I've encountered but one accepts the arg and constructs the unique
+ name from it, which is better than making up a totally random name
+ for the file, which is what RFC959 calls for. Especially because
+ there is no way for the client to find out the name chosen by the
+ server. So we try STOU with the argument first, which works with
+ most servers, and if it fails we retry it without the arg, for
+ the benefit of the one picky server that is not "liberal in what
+ it accepts" UNLESS the first STOU got a 502 code ("not implemented")
+ which means STOU is not accepted, period.
+ */
+ if ((x == 5) && stouarg && (ftpcode != 502)) {
+ x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
+ if (x == REPLY_PRELIM) /* If accepted */
+ stouarg = 0; /* flag no STOU arg for this server */
+ }
+ }
+ if (x != REPLY_PRELIM) {
+ signal(SIGINT, ftpsnd.oldintr);
+#ifdef SIGPIPE
+ if (ftpsnd.oldintp)
+ signal(SIGPIPE, ftpsnd.oldintp);
+#endif /* SIGPIPE */
+ debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
+ zclose(ZIFILE);
+#ifdef PIPESEND
+ if (sndfilter)
+ pipesend = 0;
+#endif /* PIPESEND */
+ ftpsndret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ debug(F100,"doftpsend2 getting data connection...","",0);
+ dout = dataconn(ftpsnd.lmode); /* Get data connection */
+ debug(F101,"doftpsend2 dataconn","",dout);
+ if (dout == -1) {
+ failftpsend2(threadinfo);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ /* Initialize per-file stats */
+ ffc = (CK_OFF_T)0; /* Character counter */
+ cps = oldcps = 0L; /* Thruput */
+ n = 0;
+#ifdef GFTIMER
+ rftimer(); /* reset f.p. timer */
+#endif /* GFTIMER */
+
+#ifdef SIGPIPE
+ ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
+#endif /* SIGPIPE */
+ debug(F101,"doftpsend2 curtype","",curtype);
+ switch (curtype) {
+ case FTT_BIN: /* Binary mode */
+ case FTT_TEN:
+ errno = d = 0;
+#ifdef VMS
+ /*
+ This is because VMS zxin() is C-Library fread()
+ but the file was opened with zopeni(), which is RMS.
+ */
+ while (((c = zminchar()) > -1) && !cancelfile) {
+ ffc++;
+ if (zzout(dout,c) < 0)
+ break;
+ }
+#else /* VMS */
+ while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
+ ftpsnd.bytes += n;
+ ffc += n;
+ debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
+ ckhexdump("doftpsend2 zxin",buf,16);
+#ifdef CK_SSL
+ if (ssl_ftp_data_active_flag) {
+ for (bufp = buf; n > 0; n -= d, bufp += d) {
+ if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
+ break;
+ spackets++;
+ pktnum++;
+ if (fdispla != XYFD_B) {
+ spktl = d;
+ ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
+ }
+ }
+ } else {
+#endif /* CK_SSL */
+ for (bufp = buf; n > 0; n -= d, bufp += d) {
+ if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
+ || iscanceled())
+ break;
+ spackets++;
+ pktnum++;
+ if (fdispla != XYFD_B) {
+ spktl = d;
+ ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
+ }
+ }
+#ifdef CK_SSL
+ }
+#endif /* CK_SSL */
+ if (d <= 0)
+ break;
+ }
+#endif /* VMS */
+
+ debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
+ if (n < 0)
+ fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
+ if (d < 0 || (d = secure_flush(dout)) < 0) {
+ if (d == -1 && errno && errno != EPIPE)
+ perror("netout");
+ ftpsnd.bytes = -1;
+ }
+ break;
+
+ case FTT_ASC: /* Text mode */
+#ifndef NOCSETS
+ if (ftpsnd.xlate) { /* With translation */
+ initxlate(ftpsnd.incs,ftpsnd.outcs);
+ while (!cancelfile) {
+ if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
+ if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
+ }
+ } else {
+#endif /* NOCSETS */
+ /* Text mode, no translation */
+ while (((c = zminchar()) > -1) && !cancelfile) {
+ ffc++;
+ if (xxout(c) < 0)
+ break;
+ }
+ d = 0;
+#ifndef NOCSETS
+ }
+#endif /* NOCSETS */
+ if (dout == -1 || (d = secure_flush(dout)) < 0) {
+ if (d == -1 && errno && errno != EPIPE)
+ perror("netout");
+ ftpsnd.bytes = -1;
+ }
+ break;
+ }
+ tfc += ffc; /* Total file chars */
+#ifdef GFTIMER
+ fpfsecs = gftimer();
+#endif /* GFTIMER */
+ zclose(ZIFILE); /* Close input file */
+#ifdef PIPESEND
+ if (sndfilter) /* Undo this (it's per file) */
+ pipesend = 0;
+#endif /* PIPESEND */
+
+#ifdef CK_SSL
+ if (ssl_ftp_data_active_flag) {
+ SSL_shutdown(ssl_ftp_data_con);
+ SSL_free(ssl_ftp_data_con);
+ ssl_ftp_data_active_flag = 0;
+ ssl_ftp_data_con = NULL;
+ }
+#endif /* CK_SSL */
+
+#ifdef TCPIPLIB
+ socket_close(dout); /* Close data connection */
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(dout, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(dout);
+#endif /* TCPIPLIB */
+ ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
+ signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
+#ifdef SIGPIPE
+ if (ftpsnd.oldintp)
+ signal(SIGPIPE, ftpsnd.oldintp);
+#endif /* SIGPIPE */
+ if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
+ debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
+ ftpsndret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ } else if (cancelfile) {
+ debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
+ ftpsndret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
+ ftpsndret = 0;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+}
+
+static int
+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 */
+
+#ifdef VMS
+ debug(F101,"XXX before openi binary","",binary);
+ debug(F101,"XXX before openi ftp_typ","",ftp_typ);
+#endif /* VMS */
+
+ if (openi(local) == 0) /* Try to open the input file */
+ return(-1);
+
+#ifdef VMS
+ debug(F101,"XXX after openi binary","",binary);
+ debug(F101,"XXX after openi ftp_typ","",ftp_typ);
+ if (!forcetype) {
+ if (binary != ftp_typ) { /* VMS zopeni() sets binary */
+ debug(F101,"XXX changing type","",binary);
+ doftptyp(binary);
+ debug(F101,"XXX after doftptyp","",ftp_typ);
+
+ /* **** */
+ if (displa && fdispla) { /* Update file type display */
+ ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
+ }
+ }
+ }
+#endif /* VMS */
+ ftpsndret = 0;
+ ftpsnd.incs = incs;
+ ftpsnd.outcs = outcs;
+ ftpsnd.cmd = cmd;
+ ftpsnd.local = local;
+ ftpsnd.remote = remote;
+ ftpsnd.oldintr = signal(SIGINT, cancelsend);
+ havesigint = 0;
+
+ if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
+ return(-1);
+ if (ftpsndret < 0)
+ return(-1);
+ if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
+ return(-1);
+
+ return(ftpsndret);
+}
+
+static sigtype
+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;
+ CK_OFF_T localsize;
+};
+static struct xx_ftprecv ftprecv;
+
+static int ftprecvret = 0;
+
+static VOID
+#ifdef CK_ANSIC
+failftprecv(VOID * threadinfo)
+#else
+failftprecv(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef NTSIG
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "docmdfile called with threadinfo block","", 0);
+ } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+
+#ifdef CK_LOGIN
+#ifdef IKSD
+#ifdef NT
+ if (inserver)
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+
+ while (cpend) {
+ ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
+ }
+ if (data >= 0) {
+#ifdef CK_SSL
+ if (ssl_ftp_data_active_flag) {
+ SSL_shutdown(ssl_ftp_data_con);
+ SSL_free(ssl_ftp_data_con);
+ ssl_ftp_data_active_flag = 0;
+ ssl_ftp_data_con = NULL;
+ }
+#endif /* CK_SSL */
+#ifdef TCPIPLIB
+ socket_close(data);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(data, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(data);
+#endif /* TCPIPLIB */
+ data = -1;
+ globaldin = -1;
+ }
+ if (ftprecv.oldintr)
+ signal(SIGINT, ftprecv.oldintr);
+ ftpcode = -1;
+ ftprecvret = -1;
+
+#ifndef OS2
+ /* TEST ME IN K95 */
+ if (havesigint) {
+ havesigint = 0;
+ debug(F100,"ftp failftprecv chain to trap()...","",0);
+ if (ftprecv.oldintr != SIG_IGN)
+ (*ftprecv.oldintr)(SIGINT);
+ /* NOTREACHED (I hope!) */
+ debug(F100,"ftp failftprecv return from trap()...","",0);
+ }
+#endif /* OS2 */
+ return;
+}
+
+static VOID
+#ifdef CK_ANSIC
+doftprecv(VOID * threadinfo)
+#else
+doftprecv(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef NTSIG
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "docmdfile called with threadinfo block","", 0);
+ } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef IKSD
+#ifdef NT
+ if (inserver)
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+
+#ifndef COMMENT
+ if (!out2screen && !ftprecv.pipename) {
+ int x;
+ char * local;
+ local = ftprecv.local;
+ x = zchko(local);
+ if (x < 0) {
+ if ((!dpyactive || ftp_deb))
+ fprintf(stderr,
+ "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
+ signal(SIGINT, ftprecv.oldintr);
+ ftpcode = -2;
+ ftprecvret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ }
+#endif /* COMMENT */
+ changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
+ if (initconn()) { /* Initialize the data connection */
+ signal(SIGINT, ftprecv.oldintr);
+ ftpcode = -1;
+ ftprecvret = -3;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ secure_getc(0,1); /* Initialize net input buffers */
+ ftprecvret = 0;
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+}
+
+static VOID
+#ifdef CK_ANSIC
+failftprecv2(VOID * threadinfo)
+#else
+failftprecv2(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef NTSIG
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "docmdfile called with threadinfo block","", 0);
+ } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef IKSD
+#ifdef NT
+ if (inserver)
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+
+ /* Cancel using RFC959 recommended IP,SYNC sequence */
+
+ debug(F100,"ftp recvrequest CANCEL","",0);
+#ifdef GFTIMER
+ fpfsecs = gftimer();
+#endif /* GFTIMER */
+#ifdef SIGPIPE
+ if (ftprecv.oldintp)
+ signal(SIGPIPE, ftprecv.oldintr);
+#endif /* SIGPIPE */
+ signal(SIGINT, SIG_IGN);
+ if (!cpend) {
+ ftpcode = -1;
+ signal(SIGINT, ftprecv.oldintr);
+ ftprecvret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ cancel_remote(ftprecv.din);
+
+#ifdef FTP_TIMEOUT
+ if (ftp_timed_out && out2screen && !quiet)
+ printf("\n?Timed out.\n");
+#endif /* FTP_TIMEOUT */
+
+ if (ftpcode > -1)
+ ftpcode = -1;
+ if (data >= 0) {
+#ifdef CK_SSL
+ if (ssl_ftp_data_active_flag) {
+ SSL_shutdown(ssl_ftp_data_con);
+ SSL_free(ssl_ftp_data_con);
+ ssl_ftp_data_active_flag = 0;
+ ssl_ftp_data_con = NULL;
+ }
+#endif /* CK_SSL */
+#ifdef TCPIPLIB
+ socket_close(data);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(data, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(data);
+#endif /* TCPIPLIB */
+ data = -1;
+ globaldin = -1;
+ }
+ if (!out2screen) {
+ int x = 0;
+ debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
+ zclose(ZOFILE);
+ switch (keep) { /* which is... */
+ case SET_AUTO: /* AUTO */
+ if (curtype == FTT_ASC) /* Delete file if TYPE A. */
+ x = 1;
+ break;
+ case SET_OFF: /* DISCARD */
+ x = 1; /* Delete file, period. */
+ break;
+ default: /* KEEP */
+ break;
+ }
+ if (x) {
+ x = zdelet(ftprecv.local);
+ debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
+ }
+ }
+ if (ftprecv.din) {
+#ifdef TCPIPLIB
+ socket_close(ftprecv.din);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(ftprecv.din, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(ftprecv.din);
+#endif /* TCPIPLIB */
+ }
+ signal(SIGINT, ftprecv.oldintr);
+ ftprecvret = -1;
+
+ if (havesigint) {
+ havesigint = 0;
+ debug(F100,"FTP failftprecv2 chain to trap()...","",0);
+#ifdef OS2
+ debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
+ PostCtrlCSem();
+#else /* OS2 */
+ if (ftprecv.oldintr != SIG_IGN)
+ (*ftprecv.oldintr)(SIGINT);
+ /* NOTREACHED (I hope!) */
+ debug(F100,"ftp failftprecv2 return from trap()...","",0);
+#endif /* OS2 */
+ }
+}
+
+static VOID
+#ifdef CK_ANSIC
+doftprecv2(VOID * threadinfo)
+#else
+doftprecv2(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+ register int c, d;
+ CK_OFF_T bytes = (CK_OFF_T)0;
+ int bare_lfs = 0;
+ int blksize = 0;
+ ULONG start = 0L, stop;
+ 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;
+
+#ifdef FTP_TIMEOUT
+ ftp_timed_out = 0;
+#endif /* FTP_TIMEOUT */
+
+ ftprecv.din = -1;
+#ifdef NTSIG
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "docmdfile called with threadinfo block","", 0);
+ } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef IKSD
+#ifdef NT
+ if (inserver)
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+
+ if (ftprecv.recover) { /* Initiate recovery */
+ x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
+ debug(F111,"ftp reply","REST",x);
+ if (x == REPLY_CONTINUE) {
+ ftprecv.lmode = "ab";
+ rs_len = ftprecv.localsize;
+ } else {
+ ftprecv.recover = 0;
+ }
+ }
+ /* IMPORTANT: No FTP commands can come between REST and RETR! */
+
+ debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
+
+ /* Send the command and get reply */
+ debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
+ debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
+
+ if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
+ != REPLY_PRELIM) {
+ signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
+ ftprecvret = -1; /* ftpcode is set by ftpcmd() */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ ftprecv.din = dataconn("r"); /* Good reply, open data connection */
+ globaldin = ftprecv.din; /* Global copy of file descriptor */
+ if (ftprecv.din == -1) { /* Check for failure */
+ ftpcode = -3; /* Code for no data connection */
+ ftprecvret = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+#ifdef CK_URL
+ /* In K95 GUI put up a file box */
+ if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
+ int x;
+ char * preface =
+"\r\nIncoming file from FTP server...\r\n\
+Please confirm output file specification or supply an alternative:";
+
+ x = uq_file(preface, /* K95 GUI: Put up file box. */
+ NULL,
+ 4,
+ NULL,
+ ftprecv.local ? ftprecv.local : ftprecv.remote,
+ newname,
+ CKMAXPATH+1
+ );
+ if (x > 0) {
+ ftprecv.local = newname; /* Substitute user's file name */
+ if (x == 2) /* And append if user said to */
+ ftprecv.lmode = "ab";
+ }
+ }
+#endif /* CK_URL */
+ x = 1; /* Output file open OK? */
+ if (ftprecv.pipename) { /* Command */
+ x = zxcmd(ZOFILE,ftprecv.pipename);
+ debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
+ } else if (!out2screen) { /* File */
+ struct filinfo xx;
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.os_specific = 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 = (CK_OFF_T)0; /* Character counter */
+ cps = oldcps = 0L; /* Thruput */
+ start = gmstimer(); /* Start time (msecs) */
+#ifdef GFTIMER
+ rftimer(); /* Start time (float) */
+#endif /* GFTIMER */
+
+ debug(F111,"ftp get type",ftprecv.local,curtype);
+ debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
+ switch (curtype) {
+ case FTT_BIN: /* Binary mode */
+ case FTT_TEN: /* TENEX mode */
+ d = 0;
+ while (1) {
+ errno = 0;
+ c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
+ if (cancelfile) {
+ failftprecv2(threadinfo);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ if (c < 1)
+ break;
+#ifdef printf /* (What if it isn't?) */
+ if (out2screen && !ftprecv.pipename) {
+ int i;
+ for (i = 0; i < c; i++)
+ printf("%c",rcvbuf[i]);
+ } else
+#endif /* printf */
+ {
+ register int i;
+ i = 0;
+ errno = 0;
+ while (i < c) {
+ if (zmchout(rcvbuf[i++]) < 0) {
+ d = i;
+ break;
+ }
+ }
+ }
+ bytes += c;
+ ffc += c;
+ }
+#ifdef FTP_TIMEOUT
+ if (c == -3) {
+ debug(F100,"ftp recvrequest timeout","",0);
+ bytes = (CK_OFF_T)-1;
+ ftp_timed_out = 1;
+ ftpcode = -3;
+ } else
+#endif /* FTP_TIMEOUT */
+ if (c < 0) {
+ debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
+ if (c == -1 && errno != EPIPE)
+ if ((!dpyactive || ftp_deb))
+ perror("netin");
+ bytes = (CK_OFF_T)-1;
+ ftpcode = -4;
+ }
+ if (d < c) {
+ ftpcode = -2;
+ if ((!dpyactive || ftp_deb)) {
+ char * p;
+ p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
+ if (d < 0)
+ fprintf(stderr,
+ "local(3): %s: %s\n", ftprecv.local, ck_errstr());
+ else
+ fprintf(stderr,
+ "%s: short write\n", ftprecv.local);
+ }
+ }
+ break;
+
+ case FTT_ASC: /* Text mode */
+ debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
+#ifndef NOCSETS
+ if (ftprecv.xlate) {
+ 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
+#ifdef FTP_TIMEOUT
+ || ftp_timed_out
+#endif /* FTP_TIMEOUT */
+ ) {
+ failftprecv2(threadinfo);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ if (c < 0 || c == EOF)
+ break;
+#ifdef UNIX
+ /* Record format conversion for Unix */
+ /* SKIP THIS FOR WINDOWS! */
+ if (c == '\n')
+ bare_lfs++;
+ while (c == '\r') {
+ bytes++;
+ if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
+ ftprecv.tcrflag) {
+ if (cancelfile) {
+ failftprecv2(threadinfo);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+ }
+ if (c < 0 || c == EOF)
+ 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 = (CK_OFF_T)-1;
+ }
+ if (c == -2)
+ bytes = (CK_OFF_T)-1;
+ break;
+#ifndef NOCSETS
+ }
+#endif /* NOCSETS */
+ }
+ if (ftprecv.pipename || !out2screen) {
+ zclose(ZOFILE); /* Close the file */
+ debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
+ if (ftpcode < 0) { /* If download failed */
+ int x = 0;
+ switch (keep) { /* which is... */
+ case SET_AUTO: /* AUTO */
+ if (curtype == FTT_ASC) /* Delete file if TYPE A. */
+ x = 1;
+ break;
+ case SET_OFF: /* DISCARD */
+ x = 1; /* Delete file, period. */
+ break;
+ default: /* KEEP */
+ break;
+ }
+ if (x) {
+ x = zdelet(ftprecv.local);
+ debug(F111,"ftp get delete incomplete",ftprecv.local,x);
+ }
+ }
+ }
+ signal(SIGINT, ftprecv.oldintr);
+#ifdef SIGPIPE
+ if (ftprecv.oldintp)
+ signal(SIGPIPE, ftprecv.oldintp);
+#endif /* SIGPIPE */
+ stop = gmstimer();
+#ifdef GFTIMER
+ fpfsecs = gftimer();
+#endif /* GFTIMER */
+ tfc += ffc;
+
+#ifdef TCPIPLIB
+ socket_close(ftprecv.din);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(ftprecv.din, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(ftprecv.din);
+#endif /* TCPIPLIB */
+ ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
+ ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
+ ftprecv.reply == REPLY_ERROR) ? -1 : 0);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+}
+
+static int
+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 = (CK_OFF_T)0;
+
+ if (remfile) { /* See remcfm(), remtxt() */
+ if (rempipe) {
+ pipename = remdest;
+ } else {
+ local = remdest;
+ if (remappd) lmode = "ab";
+ }
+ }
+ out2screen = 0;
+ if (!cmd) cmd = ""; /* Core dump prevention */
+ if (!remote) remote = "";
+ if (!lmode) lmode = "";
+
+ if (pipename) { /* No recovery for pipes. */
+ recover = 0;
+ if (!local)
+ local = pipename;
+ } else {
+ if (!local) /* Output to screen? */
+ local = "-";
+ out2screen = !strcmp(local,"-");
+ }
+ debug(F101,"ftp recvrequest out2screen","",out2screen);
+
+#ifdef OS2
+ if ( ftp_xla && out2screen && !k95stdout && !inserver )
+ fcs = FC_UCS2;
+#endif /* OS2 */
+
+ if (out2screen) /* No recovery to screen */
+ recover = 0;
+ if (!ftp_typ) /* No recovery in text mode */
+ recover = 0;
+ ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
+
+ if (!ftprecv.is_retr) /* No recovery except for RETRieve */
+ recover = 0;
+
+#ifdef COMMENT
+ if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
+ if (recursive && ckstrchr(local,'/')) {
+
+ }
+ }
+#endif /* COMMENT */
+
+ ftprecv.localsize = (CK_OFF_T)0; /* Local file size */
+ rs_len = (CK_OFF_T)0; /* Recovery point */
+
+ debug(F101,"ftp recvrequest recover","",recover);
+ if (recover) { /* Recovering... */
+ if (stat(local, &stbuf) < 0) { /* Can't stat local file */
+ debug(F101,"ftp recvrequest recover stat failed","",errno);
+ recover = 0; /* So cancel recovery */
+ } else { /* Have local file info */
+ ftprecv.localsize = stbuf.st_size; /* Get size */
+ /* Remote file smaller than local */
+ if (fsize < ftprecv.localsize) {
+ debug(F101,"ftp recvrequest recover remote smaller","",fsize);
+ recover = 0; /* Recovery can't work */
+ } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
+ debug(F111,"ftp recvrequest recover equal size",
+ remote,ftprecv.localsize);
+ return(1);
+ }
+#ifdef COMMENT
+/*
+ The problem here is that the original partial file never got its date
+ set, either because FTP DATES was OFF, or because the partial file was
+ downloaded by some other program that doesn't set local file dates, or
+ because Kermit only sets the file's date when the download was complete
+ and successful. In all these cases, the local file has a later time
+ than the remote.
+*/
+ if (recover) { /* Remote is bigger */
+ x = chkmodtime(local,remote,0); /* Check file dates */
+ debug(F111,"ftp recvrequest chkmodtime",remote,x);
+ if (x != 1) /* Dates must be equal! */
+ recover = 0; /* If not, get whole file */
+ }
+#endif /* COMMENT */
+ }
+ debug(F111,"ftp recvrequest recover",remote,recover);
+ }
+
+#ifdef FTP_PROXY
+ if (proxy && ftprecv.is_retr)
+ return(proxtrans(cmd, local ? local : remote, remote));
+#endif /* FTP_PROXY */
+
+ ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
+
+ ftprecv.reply = 0;
+ ftprecv.fcs = fcs;
+ ftprecv.rcs = rcs;
+ ftprecv.recover = recover;
+ ftprecv.xlate = xlate;
+ ftprecv.cmd = cmd;
+ ftprecv.local = local;
+ ftprecv.remote = remote;
+ ftprecv.lmode = lmode;
+ ftprecv.pipename = pipename;
+ ftprecv.oldintp = NULL;
+ ftpcode = 0;
+
+ havesigint = 0;
+ ftprecv.oldintr = signal(SIGINT, cancelrecv);
+ if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
+ return -1;
+
+#ifdef FTP_TIMEOUT
+ debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
+ debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
+ if (ftp_timed_out)
+ ftprecvret = -1;
+#endif /* FTP_TIMEOUT */
+
+ if (ftprecvret < 0)
+ return -1;
+
+ if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
+ return -1;
+ return ftprecvret;
+}
+
+/*
+ * Need to start a listen on the data channel before we send the command,
+ * otherwise the server's connect may fail.
+ */
+static int
+initconn() {
+ register char *p, *a;
+ int result, tmpno = 0;
+ int on = 1;
+ GSOCKNAME_T len;
+
+#ifndef NO_PASSIVE_MODE
+ int a1,a2,a3,a4,p1,p2;
+
+ if (passivemode) {
+ data = socket(AF_INET, SOCK_STREAM, 0);
+ globaldin = data;
+ if (data < 0) {
+ perror("ftp: socket");
+ return(-1);
+ }
+ if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
+ printf("Passive mode refused\n");
+ passivemode = 0;
+ return(initconn());
+ }
+/*
+ Now we have a string of comma-separated one-byte unsigned integer values,
+ The first four are the an IP address. The fifth is the MSB of the port
+ number, the sixth is the LSB. From that we can make a sockaddr_in.
+*/
+ if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
+ printf("Passive mode address scan failure\n");
+ return(-1);
+ };
+#ifndef NOHTTP
+ if (tcp_http_proxy) {
+#ifdef OS2
+ char * agent = "Kermit 95"; /* Default user agent */
+#else
+ char * agent = "C-Kermit";
+#endif /* OS2 */
+ register struct hostent *hp = 0;
+ struct servent *destsp;
+ char host[512], *p, *q;
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+ int tos;
+#endif /* IPTOS_THROUGHPUT */
+#endif /* IP_TOS */
+ 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 != INADDR_NONE) /* 2010-03-29 */
+ {
+ debug(F110,"initconn A",host,0);
+ hisctladdr.sin_family = AF_INET;
+ } else {
+ debug(F110,"initconn B",host,0);
+ hp = gethostbyname(host);
+#ifdef HADDRLIST
+ hp = ck_copyhostent(hp); /* make safe copy that won't change */
+#endif /* HADDRLIST */
+ if (hp == NULL) {
+ fprintf(stderr, "ftp: %s: Unknown host\n", host);
+ ftpcode = -1;
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ return(0);
+ }
+ hisctladdr.sin_family = hp->h_addrtype;
+#ifdef HADDRLIST
+ memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
+ sizeof(hisctladdr.sin_addr));
+#else /* HADDRLIST */
+ memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
+ sizeof(hisctladdr.sin_addr));
+#endif /* HADDRLIST */
+ }
+ data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+ debug(F101,"initconn socket","",data);
+ if (data < 0) {
+ perror("ftp: socket");
+ ftpcode = -1;
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ return(0);
+ }
+ if (*p == ':')
+ p++;
+ else
+ p = "http";
+
+ destsp = getservbyname(p,"tcp");
+ if (destsp)
+ hisctladdr.sin_port = destsp->s_port;
+ else if (p)
+ hisctladdr.sin_port = htons(atoi(p));
+ else
+ hisctladdr.sin_port = htons(80);
+ errno = 0;
+#ifdef HADDRLIST
+ debug(F100,"initconn HADDRLIST","",0);
+ while
+#else
+ debug(F100,"initconn no HADDRLIST","",0);
+ if
+#endif /* HADDRLIST */
+ (connect(data, (struct sockaddr *)&hisctladdr,
+ sizeof (hisctladdr)) < 0) {
+ debug(F101,"initconn connect failed","",errno);
+#ifdef HADDRLIST
+ if (hp && hp->h_addr_list[1]) {
+ int oerrno = errno;
+
+ fprintf(stderr,
+ "ftp: connect to address %s: ",
+ inet_ntoa(hisctladdr.sin_addr)
+ );
+ errno = oerrno;
+ perror((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,(CK_OFF_T)0,"Display canceled");
+ /* fdispla = XYFD_B; */
+ }
+
+ if (uq_ok(
+ "Warning: Server didn't provide a certificate on data connection\n",
+ "Continue with file transfer? (Y/N)",
+ 3,NULL,0) <= 0) {
+ debug(F110, "dataconn","[SSL - FAILED]",0);
+ ssl_ftp_data_active_flag = 0;
+#ifdef TCPIPLIB
+ socket_close(data);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(data, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(data);
+#endif /* TCPIPLIB */
+ data = -1;
+ globaldin = data;
+ return(-1);
+ }
+ }
+ } else {
+ if (!out2screen && displa && fdispla == XYFD_C) {
+ ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
+ /* fdispla = XYFD_B; */
+ }
+
+ if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
+ debug(F110,"dataconn","[SSL - FAILED]",0);
+ ssl_ftp_data_active_flag = 0;
+#ifdef TCPIPLIB
+ socket_close(data);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(data, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(data);
+#endif /* TCPIPLIB */
+ data = -1;
+ globaldin = data;
+ return(-1);
+ }
+ }
+ }
+ debug(F110,"dataconn","[SSL - OK]",0);
+#ifdef COMMENT
+ /* This messes up the full screen file transfer display */
+ ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
+#endif /* COMMENT */
+ }
+ if (ssl_debug_flag) {
+ fprintf(stderr,"=>DONE SSL connect on DATA\n");
+ fflush(stderr);
+ }
+ return(data);
+}
+#endif /* CK_SSL */
+
+static int
+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
+
+#ifdef COMMENT
+/* ck_gss_mech_krb5 is not declared anywhere */
+struct {
+ CONST gss_OID_desc * CONST * mech_type;
+ char *service_name;
+} gss_trials[] = {
+ { &ck_gss_mech_krb5, "ftp" },
+ { &ck_gss_mech_krb5, "host" },
+};
+#else
+/* This matches what is declared above */
+struct {
+ CONST gss_OID_desc * CONST * mech_type;
+ char *service_name;
+} gss_trials[] = {
+ { &gss_mech_krb5, "ftp" },
+ { &gss_mech_krb5, "host" },
+};
+#endif /* COMMENT */
+
+
+int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
+#endif /* FTP_GSSAPI */
+
+static int
+ftp_auth() {
+ extern int setsafe();
+ int j = 0, n;
+#ifdef FTP_KRB4
+ char *service, inst[INST_SZ];
+ ULONG cksum;
+ ULONG checksum = (ULONG) getpid();
+ CHAR out_buf[FTP_BUFSIZ];
+ int i;
+#else /* FTP_KRB4 */
+#ifdef FTP_GSSAPI
+ CHAR out_buf[FTP_BUFSIZ];
+ int i;
+#endif /* FTP_GSSAPI */
+#endif /* FTP_KRB4 */
+
+ if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
+ return(0);
+
+ if (auth_type)
+ return(1); /* auth already succeeded */
+
+ /* Try each auth type as specified by the end user */
+ for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
+#ifdef FTP_GSSAPI
+ if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
+ n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
+ if (n == REPLY_CONTINUE) {
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t target_name;
+ gss_buffer_desc send_tok, recv_tok, *token_ptr;
+ char stbuf[FTP_BUFSIZ];
+ int comcode, trial;
+ struct gss_channel_bindings_struct chan;
+ char * realm = NULL;
+ char tgt[256];
+
+ chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+ chan.initiator_address.length = 4;
+ chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
+ chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+ chan.acceptor_address.length = 4;
+ chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
+ chan.application_data.length = 0;
+ chan.application_data.value = 0;
+
+ if (!quiet)
+ printf("GSSAPI accepted as authentication type\n");
+
+ realm = ck_krb5_realmofhost(ftp_user_host);
+ if (realm) {
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
+ debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
+ if ( krb5_autoget &&
+ !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
+ (ck_krb5_is_tgt_valid() > 0)) )
+ ck_krb5_autoget_TGT(realm);
+ }
+
+ /* Blob from gss-client */
+ for (trial = 0; trial < n_gss_trials; trial++) {
+ /* ftp@hostname first, the host@hostname */
+ /* the V5 GSSAPI binding canonicalizes this for us... */
+ ckmakmsg(stbuf,FTP_BUFSIZ,
+ gss_trials[trial].service_name,
+ "@",
+ ftp_user_host,
+ NULL
+ );
+ if (ftp_deb)
+ fprintf(stderr,
+ "Authenticating to <%s>...\n", stbuf);
+ send_tok.value = stbuf;
+ send_tok.length = strlen(stbuf);
+ maj_stat = gss_import_name(&min_stat, &send_tok,
+ gss_nt_service_name,
+ &target_name
+ );
+ if (maj_stat != GSS_S_COMPLETE) {
+ user_gss_error(maj_stat, min_stat, "parsing name");
+ secure_error("name parsed <%s>\n", stbuf);
+ continue;
+ }
+ token_ptr = GSS_C_NO_BUFFER;
+ gcontext = GSS_C_NO_CONTEXT; /* structure copy */
+
+ do {
+ if (ftp_deb)
+ fprintf(stderr, "calling gss_init_sec_context\n");
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &gcontext,
+ target_name,
+ (gss_OID) *
+ gss_trials[trial].mech_type,
+ GSS_C_MUTUAL_FLAG |
+ GSS_C_REPLAY_FLAG |
+ (ftp_cfw ?
+ GSS_C_DELEG_FLAG : 0),
+ 0,
+ /* channel bindings */
+ (krb5_d_no_addresses ?
+ GSS_C_NO_CHANNEL_BINDINGS :
+ &chan),
+ token_ptr,
+ NULL, /* ignore mech type */
+ &send_tok,
+ NULL, /* ignore ret_flags */
+ NULL
+ ); /* ignore time_rec */
+
+ if (maj_stat != GSS_S_COMPLETE &&
+ maj_stat != GSS_S_CONTINUE_NEEDED) {
+ if (trial == n_gss_trials-1)
+ user_gss_error(maj_stat,
+ min_stat,
+ "initializing context"
+ );
+ gss_release_name(&min_stat, &target_name);
+ /* maybe we missed on the service name */
+ goto outer_loop;
+ }
+ if (send_tok.length != 0) {
+ int len;
+ reply_parse = "ADAT="; /* for ftpcmd() later */
+ len = FTP_BUFSIZ;
+ kerror =
+ radix_encode(send_tok.value,
+ out_buf,
+ send_tok.length,
+ &len,
+ RADIX_ENCODE
+ );
+ if (kerror) {
+ fprintf(stderr,
+ "Base 64 encoding failed: %s\n",
+ radix_error(kerror)
+ );
+ goto gss_complete_loop;
+ }
+ comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
+ if (comcode != REPLY_COMPLETE
+ && comcode != REPLY_CONTINUE /* (335) */
+ ) {
+ if (trial == n_gss_trials-1) {
+ fprintf(stderr, "GSSAPI ADAT failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ }
+ /*
+ Backoff to the v1 gssapi is still possible.
+ Send a new AUTH command. If that fails,
+ terminate the loop.
+ */
+ if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
+ != REPLY_CONTINUE) {
+ fprintf(stderr,
+ "GSSAPI ADAT failed, AUTH restart failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ }
+ goto outer_loop;
+ }
+ if (!reply_parse) {
+ fprintf(stderr,
+ "No authentication data received from server\n");
+ if (maj_stat == GSS_S_COMPLETE) {
+ fprintf(stderr,
+ "...but no more was needed\n");
+ goto gss_complete_loop;
+ } else {
+ user_gss_error(maj_stat,
+ min_stat,
+ "no reply, huh?"
+ );
+ goto gss_complete_loop;
+ }
+ }
+ len = FTP_BUFSIZ;
+ kerror = radix_encode(reply_parse,out_buf,i,&len,
+ RADIX_DECODE);
+ if (kerror) {
+ fprintf(stderr,
+ "Base 64 decoding failed: %s\n",
+ radix_error(kerror));
+ goto gss_complete_loop;
+ }
+
+ /* everything worked */
+ token_ptr = &recv_tok;
+ recv_tok.value = out_buf;
+ recv_tok.length = len;
+ continue;
+
+ /* get out of loop clean */
+ gss_complete_loop:
+ trial = n_gss_trials-1;
+ gss_release_buffer(&min_stat, &send_tok);
+ gss_release_name(&min_stat, &target_name);
+ goto outer_loop;
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ outer_loop:
+ if (maj_stat == GSS_S_COMPLETE)
+ break;
+ }
+ if (maj_stat == GSS_S_COMPLETE) {
+ printf("GSSAPI authentication succeeded\n");
+ reply_parse = NULL;
+ auth_type = "GSSAPI";
+ return(1);
+ } else {
+ fprintf(stderr, "GSSAPI authentication failed\n");
+ reply_parse = NULL;
+ }
+ } else {
+ if (ftp_deb)
+ fprintf(stderr, "GSSAPI rejected as an authentication type\n");
+ if (ftpcode == 500 || ftpcode == 502)
+ return(0);
+ }
+ }
+#endif /* FTP_GSSAPI */
+#ifdef FTP_SRP
+ if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
+ if (srp_ftp_auth(ftp_user_host,NULL,NULL))
+ return(1);
+ else if (ftpcode == 500 || ftpcode == 502)
+ return(0);
+ }
+#endif /* FTP_SRP */
+#ifdef FTP_KRB4
+ if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
+ n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
+ if (n == REPLY_CONTINUE) {
+ char tgt[4*REALM_SZ+1];
+ int rc;
+
+ if (!quiet)
+ printf("KERBEROS_V4 accepted as authentication type\n");
+ ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
+ ckstrncpy(ftp_realm,
+ (char *)ck_krb4_realmofhost(ftp_user_host),
+ REALM_SZ
+ );
+
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
+ rc = ck_krb4_tkt_isvalid(tgt);
+
+ if (rc <= 0 && krb4_autoget)
+ ck_krb4_autoget_TGT(ftp_realm);
+
+ service = "ftp";
+ kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
+ if (kerror == KDC_PR_UNKNOWN) {
+ service = "rcmd";
+ kerror = krb_mk_req(&ftp_tkt,
+ service,
+ inst,
+ ftp_realm,
+ checksum
+ );
+ }
+ if (kerror)
+ fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
+ krb_get_err_text(kerror));
+ if (!kerror) {
+ kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
+ if (kerror)
+ fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
+ krb_get_err_text(kerror));
+ }
+ if (!kerror) {
+ int rc;
+ rc = des_key_sched(ftp_cred.session, ftp_sched);
+ if (rc == -1) {
+ printf("?Invalid DES key specified in credentials\r\n");
+ debug(F110,"ftp_auth",
+ "invalid DES Key specified in credentials",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified in credentials\r\n");
+ debug(F110,"ftp_auth",
+ "weak DES Key specified in credentials",0);
+ } else if ( rc != 0 ) {
+ printf("?DES Key Schedule not set by credentials\r\n");
+ debug(F110,"ftp_auth",
+ "DES Key Schedule not set by credentials",0);
+ }
+ reply_parse = "ADAT=";
+ i = FTP_BUFSIZ;
+ kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
+ &i, RADIX_ENCODE);
+ if (kerror) {
+ fprintf(stderr, "Base 64 encoding failed: %s\n",
+ radix_error(kerror));
+ goto krb4_err;
+ }
+ if (i > FTP_BUFSIZ - 6)
+ printf("?ADAT data too long\n");
+ if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
+ REPLY_COMPLETE) {
+ fprintf(stderr, "Kerberos V4 authentication failed\n");
+ goto krb4_err;
+ }
+ if (!reply_parse) {
+ fprintf(stderr,
+ "No authentication data received from server\n");
+ goto krb4_err;
+ }
+ i = sizeof(out_buf);
+ kerror =
+ radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
+ if (kerror) {
+ fprintf(stderr, "Base 64 decoding failed: %s\n",
+ radix_error(kerror));
+ goto krb4_err;
+ }
+ kerror = krb_rd_safe(out_buf, i,
+#ifdef KRB524
+ ftp_cred.session,
+#else /* KRB524 */
+ &ftp_cred.session,
+#endif /* KRB524 */
+ &hisctladdr,
+ &myctladdr,
+ &ftp_msg_data
+ );
+ if (kerror) {
+ fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
+ krb_get_err_text(kerror));
+ goto krb4_err;
+ }
+
+ /* fetch the (modified) checksum */
+ memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
+ if (ntohl(cksum) == checksum + 1) {
+ if (ftp_vbm)
+ printf("Kerberos V4 authentication succeeded\n");
+ reply_parse = NULL;
+ auth_type = "KERBEROS_V4";
+ return(1);
+ } else
+ fprintf(stderr,
+ "Kerberos V4 mutual authentication failed\n");
+ krb4_err:
+ reply_parse = NULL;
+ }
+ } else {
+ if (ftp_deb)
+ fprintf(stderr,
+ "KERBEROS_V4 rejected as an authentication type\n");
+ if (ftpcode == 500 || ftpcode == 502)
+ return(0);
+ }
+ }
+#endif /* FTP_KRB4 */
+#ifdef CK_SSL
+ if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
+#ifdef FTPHOST
+ if (!hostcmd) {
+ ftpcmd("HOST",ftp_user_host,0,0,0);
+ hostcmd = 1;
+ }
+#endif /* FTPHOST */
+ n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
+ if (n != REPLY_COMPLETE)
+ n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
+ if (n == REPLY_COMPLETE) {
+ if (!quiet)
+ printf("TLS accepted as authentication type\n");
+
+ auth_type = "TLS";
+ ssl_auth();
+ if (ssl_ftp_active_flag ) {
+ ftp_dpl = FPL_CLR;
+ ftp_cpl = FPL_PRV;
+ return(1);
+ } else {
+ fprintf(stderr,"TLS authentication failed\n");
+ auth_type = NULL;
+#ifdef TCPIPLIB
+ socket_close(csocket);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(csocket, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(csocket);
+#endif /* TCPIPLIB */
+ csocket = -1;
+ if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
+ return(0);
+ }
+ } else {
+ if (ftp_deb)
+ fprintf(stderr,"TLS rejected as an authentication type\n");
+ if (ftpcode == 500 || ftpcode == 502)
+ return(0);
+ }
+ }
+ if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
+#ifdef FTPHOST
+ if (!hostcmd) {
+ ftpcmd("HOST",ftp_user_host,0,0,0);
+ hostcmd = 1;
+ }
+#endif /* FTPHOST */
+ n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
+ if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
+ if (!quiet)
+ printf("SSL accepted as authentication type\n");
+ auth_type = "SSL";
+ ssl_auth();
+ if (ssl_ftp_active_flag) {
+ ftp_dpl = FPL_PRV;
+ ftp_cpl = FPL_PRV;
+ setprotbuf(1<<20);
+ return(1);
+ } else {
+ fprintf(stderr,"SSL authentication failed\n");
+ auth_type = NULL;
+#ifdef TCPIPLIB
+ socket_close(csocket);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(csocket, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(csocket);
+#endif /* TCPIPLIB */
+ csocket = -1;
+ if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
+ return(0);
+ }
+ } else {
+ if (ftp_deb)
+ fprintf(stderr, "SSL rejected as an authentication type\n");
+ if (ftpcode == 500 || ftpcode == 502)
+ return(0);
+ }
+ }
+#endif /* CK_SSL */
+ /* Other auth types go here ... */
+ } /* for (j;;) */
+ return(0);
+}
+#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 */
+
+ debug(F111,"ftp_hookup",host,port);
+
+#ifndef NOHTTP
+ if (tcp_http_proxy) {
+ struct servent *destsp;
+ char *p, *q;
+
+ ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
+ for (p = tcp_http_proxy, q = hostname;
+ *p != '\0' && *p != ':';
+ p++, q++
+ )
+ *q = *p;
+ *q = '\0';
+
+ if (*p == ':')
+ p++;
+ else
+ p = "http";
+
+ destsp = getservbyname(p,"tcp");
+ if (destsp)
+ cport = ntohs(destsp->s_port);
+ else if (p) {
+ cport = atoi(p);
+ } else
+ cport = 80;
+ } else
+#endif /* NOHTTP */
+ {
+ ckstrncpy(hostname,host,MAXHOSTNAMELEN);
+ cport = port;
+ }
+ memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
+ hisctladdr.sin_addr.s_addr = inet_addr(host);
+ if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
+ {
+ debug(F110,"ftp hookup A",hostname,0);
+ hisctladdr.sin_family = AF_INET;
+ ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
+ } else {
+ debug(F110,"ftp hookup B",hostname,0);
+ hp = gethostbyname(hostname);
+#ifdef HADDRLIST
+ hp = ck_copyhostent(hp); /* make safe copy that won't change */
+#endif /* HADDRLIST */
+ if (hp == NULL) {
+ fprintf(stderr, "ftp: %s: Unknown host\n", host);
+ ftpcode = -1;
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ return((char *) 0);
+ }
+ hisctladdr.sin_family = hp->h_addrtype;
+#ifdef HADDRLIST
+ memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
+ sizeof(hisctladdr.sin_addr));
+#else /* HADDRLIST */
+ memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
+ sizeof(hisctladdr.sin_addr));
+#endif /* HADDRLIST */
+ ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
+ }
+ debug(F110,"ftp hookup C",hostnamebuf,0);
+ ftp_host = hostnamebuf;
+ s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+ debug(F101,"ftp hookup socket","",s);
+ if (s < 0) {
+ perror("ftp: socket");
+ ftpcode = -1;
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ return(0);
+ }
+ hisctladdr.sin_port = htons(cport);
+ errno = 0;
+
+#ifdef COMMENT
+ printf("hisctladdr=%d\n",sizeof(hisctladdr));
+ printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
+ printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
+ printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
+#endif /* COMMENT */
+
+#ifdef HADDRLIST
+ debug(F100,"ftp hookup HADDRLIST","",0);
+ while
+#else
+ debug(F100,"ftp hookup no HADDRLIST","",0);
+ if
+#endif /* HADDRLIST */
+ (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
+ debug(F101,"ftp hookup connect failed","",errno);
+#ifdef HADDRLIST
+ if (hp && hp->h_addr_list[1]) {
+ int oerrno = errno;
+
+ fprintf(stderr, "ftp: connect to address %s: ",
+ inet_ntoa(hisctladdr.sin_addr));
+ errno = oerrno;
+ perror((char *) 0);
+ hp->h_addr_list++;
+ memcpy((char *)&hisctladdr.sin_addr,
+ hp->h_addr_list[0],
+ sizeof(hisctladdr.sin_addr));
+ fprintf(stdout, "Trying %s...\n",
+ inet_ntoa(hisctladdr.sin_addr));
+#ifdef TCPIPLIB
+ socket_close(s);
+#else /* TCPIPLIB */
+ close(s);
+#endif /* TCPIPLIB */
+ s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("ftp: socket");
+ ftpcode = -1;
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ return(0);
+ }
+ continue;
+ }
+#endif /* HADDRLIST */
+ perror("ftp: connect");
+ ftpcode = -1;
+ goto bad;
+ }
+ debug(F100,"ftp hookup connect ok","",0);
+
+ len = sizeof (myctladdr);
+ errno = 0;
+ if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
+ debug(F101,"ftp hookup getsockname failed","",errno);
+ perror("ftp: getsockname");
+ ftpcode = -1;
+ goto bad;
+ }
+ debug(F100,"ftp hookup getsockname ok","",0);
+
+#ifndef NOHTTP
+ if (tcp_http_proxy) {
+#ifdef OS2
+ char * agent = "Kermit 95"; /* Default user agent */
+#else
+ char * agent = "C-Kermit";
+#endif /* OS2 */
+
+ if (http_connect(s,agent,NULL,
+ tcp_http_proxy_user,
+ tcp_http_proxy_pwd,
+ 0,
+ proxyhost
+ ) < 0) {
+ char * foo = NULL;
+#ifdef TCPIPLIB
+ socket_close(s);
+#else /* TCPIPLIB */
+ close(s);
+#endif /* TCPIPLIB */
+
+ while (foo == NULL && tcp_http_proxy != NULL ) {
+
+ if (tcp_http_proxy_errno == 401 ||
+ tcp_http_proxy_errno == 407 ) {
+ char uid[UIDBUFLEN];
+ char pwd[PWDSIZ];
+ struct txtbox tb[2];
+ int ok;
+
+ tb[0].t_buf = uid;
+ tb[0].t_len = UIDBUFLEN;
+ tb[0].t_lbl = "Proxy Userid: ";
+ tb[0].t_dflt = NULL;
+ tb[0].t_echo = 1;
+ tb[1].t_buf = pwd;
+ tb[1].t_len = 256;
+ tb[1].t_lbl = "Proxy Passphrase: ";
+ tb[1].t_dflt = NULL;
+ tb[1].t_echo = 2;
+
+ ok = uq_mtxt("Proxy Server Authentication Required\n",
+ NULL, 2, tb);
+
+ if (ok && uid[0]) {
+ char * proxy_user, * proxy_pwd;
+
+ proxy_user = tcp_http_proxy_user;
+ proxy_pwd = tcp_http_proxy_pwd;
+
+ tcp_http_proxy_user = uid;
+ tcp_http_proxy_pwd = pwd;
+
+ foo = ftp_hookup(host, port, 0);
+
+ debug(F110,"ftp_hookup()",foo,0);
+ memset(pwd,0,PWDSIZ);
+ tcp_http_proxy_user = proxy_user;
+ tcp_http_proxy_pwd = proxy_pwd;
+ } else
+ break;
+ } else
+ break;
+ }
+ if (foo != NULL)
+ return(foo);
+ perror("ftp: connect");
+ ftpcode = -1;
+ goto bad;
+ }
+ ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
+ }
+#endif /* NOHTTP */
+
+ csocket = s;
+
+#ifdef CK_SSL
+ if (tls) {
+ /* FTP over SSL
+ * If the connection is over an SSL proxy then the
+ * auth_type will be NULL. However, I'm not sure
+ * whether we should protect the data channel in
+ * that case or not.
+ */
+
+ debug(F100,"ftp hookup use_tls","",0);
+ if (!ssl_auth()) {
+ debug(F100,"ftp hookup ssl_auth failed","",0);
+ auth_type = NULL;
+ ftpcode = -1;
+ csocket = -1;
+ goto bad;
+ }
+ ssl_ftp_proxy = 1;
+ }
+#endif /* CK_SSL */
+
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+ tos = IPTOS_LOWDELAY;
+ if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+ perror("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+ if (!quiet)
+ printf("Connected to %s.\n", host);
+
+ /* Read greeting from server */
+ if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
+ debug(F100,"ftp hookup bad reply","",0);
+#ifdef TCPIPLIB
+ socket_close(csocket);
+#else /* TCPIPLIB */
+ close(csocket);
+#endif /* TCPIPLIB */
+ ftpcode = -1;
+ goto bad;
+ }
+#ifdef SO_OOBINLINE
+ {
+ int on = 1;
+ errno = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
+ sizeof(on)) < 0) {
+ perror("ftp: setsockopt");
+ debug(F101,"ftp hookup setsockopt failed","",errno);
+ }
+#ifdef DEBUG
+ else
+ debug(F100,"ftp hookup setsockopt ok","",0);
+#endif /* DEBUG */
+ }
+#endif /* SO_OOBINLINE */
+
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ return(ftp_host);
+
+ bad:
+ debug(F100,"ftp hookup bad","",0);
+#ifdef TCPIPLIB
+ socket_close(s);
+#else /* TCPIPLIB */
+ close(s);
+#endif /* TCPIPLIB */
+#ifdef DEBUG
+ debtim = xdebtim;
+#endif /* DEBUG */
+ csocket = -1;
+ return((char *)0);
+}
+
+static VOID
+ftp_init() {
+ int i, n;
+
+ /* The purpose of the initial REST 0 is not clear, but other FTP */
+ /* clients do it. In any case, failure of this command is not a */
+ /* reliable indication that the server does not support Restart. */
+
+ okrestart = 0;
+ if (!noinit) {
+ n = ftpcmd("REST 0",NULL,0,0,0);
+ if (n == REPLY_COMPLETE)
+ okrestart = 1;
+#ifdef COMMENT
+ else if (ftp_deb)
+ printf("WARNING: Unable to restore file pointer.\n");
+#endif /* COMMENT */
+ }
+ n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
+ if (n == REPLY_COMPLETE) {
+ register char *cp, c = NUL;
+ cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
+ if (cp == NULL)
+ cp = ckstrchr(ftp_reply_str+4,'\r');
+ if (cp) {
+ if (cp[-1] == '.')
+ cp--;
+ c = *cp; /* Save this char */
+ *cp = '\0'; /* Replace it with NUL */
+ }
+ if (!quiet)
+ printf("Remote system type is %s.\n",ftp_reply_str+4);
+ ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
+ if (cp) /* Put back saved char */
+ *cp = c;
+ }
+ alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
+
+ if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
+ else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
+ else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
+ else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
+ else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
+ else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
+ else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
+
+#ifdef FTP_PROXY
+ unix_proxy = 0;
+ if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
+#endif /* FTP_PROXY */
+
+ if (ftp_cmdlin && ftp_xfermode == XMODE_M)
+ ftp_typ = binary; /* Type given on command line */
+ else /* Otherwise set it automatically */
+ ftp_typ = alike ? FTT_BIN : FTT_ASC;
+ changetype(ftp_typ,0); /* Change to this type */
+ g_ftp_typ = ftp_typ; /* Make it the global type */
+ if (!quiet)
+ printf("Default transfer mode is %s\n",
+ ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
+ );
+ for (i = 0; i < 16; i++) /* Init server FEATure table */
+ sfttab[i] = 0;
+ if (!noinit) {
+ n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
+#ifdef COMMENT
+ if (n != REPLY_COMPLETE)
+ printf("WARNING: Server does not accept MODE S(TREAM)\n");
+#endif /* COMMENT */
+ n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
+#ifdef COMMENT
+ if (n != REPLY_COMPLETE)
+ printf("WARNING: Server does not accept STRU F(ILE)\n");
+#endif /* COMMENT */
+ if (featok) {
+ n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
+ if (n == REPLY_COMPLETE) {
+ debug(F101,"ftp_init FEAT","",sfttab[0]);
+ if (deblog || ftp_deb) {
+ int i;
+ for (i = 1; i < 16 && i < nfeattab; i++) {
+ debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
+ if (ftp_deb)
+ printf(" Server %s %s\n",
+ sfttab[i] ? "supports" : "does not support",
+ feattab[i].kwd
+ );
+ }
+ /* Deal with disabled MLST opts here if necessary */
+ /* But why would it be? */
+ }
+ }
+ }
+ }
+}
+
+static int
+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 = (CK_OFF_T)-1; /* Initialize file facts... */
+ havetype = 0;
+ makestr(&havemdtm,NULL);
+ p = (char *)buf;
+
+ if (mgetmethod == SND_NLS) { /* NLST... */
+ if (pattern) {
+ if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
+ goto again;
+ }
+ } else { /* MLSD... */
+ p = parsefacts((char *)buf);
+ switch (havetype) {
+ case FTYP_FILE: /* File: Get it if it matches */
+ if (pattern) {
+ if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
+ goto again;
+ }
+ break;
+ case FTYP_CDIR: /* Current directory */
+ case FTYP_PDIR: /* Parent directory */
+ goto again; /* Skip */
+ case FTYP_DIR: /* (Sub)Directory */
+ if (!recursive) /* If not /RECURSIVE */
+ goto again; /* Skip */
+ if (mlsdepth < MLSDEPTH) {
+ char * p2 = NULL;
+ mlsdepth++;
+ printf("RECURSING [%s](%d)...\n",p,mlsdepth);
+ if (doftpcwd(p,0) > 0) {
+ int x;
+ if (!ckstrchr(p,'/')) {
+ /* zmkdir() needs dirsep */
+ if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
+ strcpy(p2,p); /* SAFE */
+ strcat(p2,"/"); /* SAFE */
+ p = p2;
+ }
+ }
+#ifdef NOMKDIR
+ x = -1;
+#else
+ x = zmkdir(p);
+#endif /* NOMKDIR */
+ if (x > -1) {
+ zchdir(p);
+ p = (char *)remote_files(1,arg,pattern,0);
+ if (p2) free(p2);
+ } else {
+ printf("?mkdir failed: [%s] Depth=%d\n",
+ p,
+ mlsdepth
+ );
+ mlsreset();
+ if (p2) free(p2);
+ return(NULL);
+ }
+ } else {
+ printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
+ mlsreset();
+ return(NULL);
+ }
+ } else {
+ printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
+ mlsdepth
+ );
+ mlsreset();
+ return(NULL);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"remote_files havesize","",havesize);
+ debug(F101,"remote_files havetype","",havetype);
+ debug(F110,"remote_files havemdtm",havemdtm,0);
+ debug(F110,"remote_files name",p,0);
+ }
+#endif /* DEBUG */
+ return((CHAR *)p);
+}
+
+/* N O T P O R T A B L E !!! */
+
+#if (SIZEOF_SHORT == 4)
+typedef unsigned short ftp_uint32;
+typedef short ftp_int32;
+#else
+#if (SIZEOF_INT == 4)
+typedef unsigned int ftp_uint32;
+typedef int ftp_int32;
+#else
+#if (SIZEOF_LONG == 4)
+typedef ULONG ftp_uint32;
+typedef long ftp_int32;
+#endif
+#endif
+#endif
+
+/* Perhaps use these in general, certainly use them for GSSAPI */
+
+#ifndef looping_write
+#define ftp_int32 int
+#define ftp_uint32 unsigned int
+static int
+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',(CK_OFF_T)spackets,NULL);
+ }
+ return(rc);
+}
+
+#ifdef COMMENT /* (not used) */
+/* returns:
+ * c>=0 on success
+ * -1 on error
+ * -2 on security error
+ */
+static int
+#ifdef CK_ANSIC
+secure_putc(char c, int fd)
+#else
+secure_putc(c, fd) char c; int fd;
+#endif /* CK_ANSIC */
+/* secure_putc */ {
+ return(secure_putbyte(fd, (CHAR) c));
+}
+#endif /* COMMENT */
+
+/* returns:
+ * nbyte on success
+ * -1 on error (errno set)
+ * -2 on security error
+ */
+static int
+#ifdef CK_ANSIC
+secure_write(int fd, CHAR * buf, unsigned int nbyte)
+#else
+secure_write(fd, buf, nbyte)
+ int fd;
+ CHAR * buf;
+ unsigned int nbyte;
+#endif /* CK_ANSIC */
+{
+ int ret;
+
+#ifdef FTP_TIMEOUT
+ ftp_timed_out = 0;
+ if (check_data_connection(fd,1) < 0) {
+ ftp_timed_out = 1;
+ return(-3);
+ }
+#endif /* FTP_TIMEOUT */
+
+ if (!ftpissecure()) {
+ if (nout > 0) {
+ if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
+ return(ret);
+ nout = 0;
+ }
+ return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
+ } else {
+ int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
+ int bsent = 0;
+
+ while (bsent < nbyte) {
+ int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
+ (ucbuflen - nout) : (nbyte - bsent));
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"secure_write ucbuflen","",ucbuflen);
+ debug(F101,"secure_write ucbufsiz","",ucbufsiz);
+ debug(F101,"secure_write bsent","",bsent);
+ debug(F101,"secure_write b2cp","",b2cp);
+ }
+#endif /* DEBUG */
+ memcpy(&ucbuf[nout],&buf[bsent],b2cp);
+ nout += b2cp;
+ bsent += b2cp;
+
+ if (nout == ucbuflen) {
+ nout = 0;
+ ret = secure_putbuf(fd, ucbuf, ucbuflen);
+ if (ret < 0)
+ return(ret);
+ }
+ }
+ return(bsent);
+ }
+}
+
+/* returns:
+ * 0 on success
+ * -1 on error (errno set)
+ * -2 on security error
+ */
+static int
+#ifdef CK_ANSIC
+secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
+#else
+secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
+#endif /* CK_ANSIC */
+{
+ static char *outbuf = NULL; /* output ciphertext */
+#ifdef FTP_SECURITY
+ static unsigned int bufsize = 0; /* size of outbuf */
+#endif /* FTP_SECURITY */
+ ftp_int32 length = 0;
+ ftp_uint32 net_len = 0;
+
+ /* Other auth types go here ... */
+#ifdef CK_SSL
+ if (ssl_ftp_data_active_flag) {
+ int count, error;
+
+ /* there is no need to send an empty buffer when using SSL/TLS */
+ if ( nbyte == 0 )
+ return(0);
+
+ count = SSL_write(ssl_ftp_data_con, buf, nbyte);
+ error = SSL_get_error(ssl_ftp_data_con,count);
+ switch (error) {
+ case SSL_ERROR_NONE:
+ return(0);
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_SYSCALL:
+#ifdef NT
+ {
+ int gle = GetLastError();
+ if (gle == 0)
+ return(0);
+ debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
+ }
+#endif /* NT */
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ SSL_shutdown(ssl_ftp_data_con);
+ SSL_free(ssl_ftp_data_con);
+ ssl_ftp_data_active_flag = 0;
+ ssl_ftp_data_con = NULL;
+#ifdef TCPIPLIB
+ socket_close(data);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(data, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(data);
+#endif /* TCPIPLIB */
+ data = -1;
+ globaldin = data;
+ return(-1);
+ }
+ return(-1);
+ }
+#endif /* CK_SSL */
+
+#ifdef FTP_SRP
+ if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
+ if (bufsize < nbyte + FUDGE_FACTOR) {
+ if (outbuf?
+ (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
+ (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
+ bufsize = nbyte + FUDGE_FACTOR;
+ } else {
+ bufsize = 0;
+ secure_error("%s (in malloc of PROT buffer)", ck_errstr());
+ return(ERR);
+ }
+ }
+ if ((length =
+ srp_encode(ftp_dpl == FPL_PRV,
+ (CHAR *) buf,
+ (CHAR *) outbuf,
+ nbyte
+ )
+ ) < 0) {
+ secure_error ("srp_encode failed");
+ return ERR;
+ }
+ }
+#endif /* FTP_SRP */
+#ifdef FTP_KRB4
+ if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
+ struct sockaddr_in myaddr, hisaddr;
+ GSOCKNAME_T len;
+ len = sizeof(myaddr);
+ if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
+ secure_error("secure_putbuf: getsockname failed");
+ return(ERR);
+ }
+ len = sizeof(hisaddr);
+ if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
+ secure_error("secure_putbuf: getpeername failed");
+ return(ERR);
+ }
+ if (bufsize < nbyte + FUDGE_FACTOR) {
+ if (outbuf ?
+ (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
+ (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
+ bufsize = nbyte + FUDGE_FACTOR;
+ } else {
+ bufsize = 0;
+ secure_error("%s (in malloc of PROT buffer)", ck_errstr());
+ return(ERR);
+ }
+ }
+ if (ftp_dpl == FPL_PRV) {
+ length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
+ ftp_sched,
+#ifdef KRB524
+ ftp_cred.session,
+#else /* KRB524 */
+ &ftp_cred.session,
+#endif /* KRB524 */
+ &myaddr,
+ &hisaddr
+ );
+ } else {
+ length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
+#ifdef KRB524
+ ftp_cred.session,
+#else /* KRB524 */
+ &ftp_cred.session,
+#endif /* KRB524 */
+ &myaddr,
+ &hisaddr
+ );
+ }
+ if (length == -1) {
+ secure_error("krb_mk_%s failed for KERBEROS_V4",
+ ftp_dpl == FPL_PRV ? "priv" : "safe");
+ return(ERR);
+ }
+ }
+#endif /* FTP_KRB4 */
+#ifdef FTP_GSSAPI
+ if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
+ gss_buffer_desc in_buf, out_buf;
+ OM_uint32 maj_stat, min_stat;
+ int conf_state;
+
+ in_buf.value = buf;
+ in_buf.length = nbyte;
+ maj_stat = gss_seal(&min_stat, gcontext,
+ (ftp_dpl == FPL_PRV), /* confidential */
+ GSS_C_QOP_DEFAULT,
+ &in_buf,
+ &conf_state,
+ &out_buf
+ );
+ if (maj_stat != GSS_S_COMPLETE) {
+ /* generally need to deal */
+ /* ie. should loop, but for now just fail */
+ user_gss_error(maj_stat, min_stat,
+ ftp_dpl == FPL_PRV?
+ "GSSAPI seal failed":
+ "GSSAPI sign failed");
+ return(ERR);
+ }
+ if (bufsize < out_buf.length) {
+ if (outbuf ?
+ (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
+ (outbuf = malloc((unsigned) out_buf.length))) {
+ bufsize = out_buf.length;
+ } else {
+ bufsize = 0;
+ secure_error("%s (in malloc of PROT buffer)",
+ ck_errstr());
+ return(ERR);
+ }
+ }
+ memcpy(outbuf, out_buf.value, length=out_buf.length);
+ gss_release_buffer(&min_stat, &out_buf);
+ }
+#endif /* FTP_GSSAPI */
+ net_len = htonl((ULONG) length);
+ if (looping_write(fd, (char *)&net_len, 4) == -1)
+ return(-1);
+ if (looping_write(fd, outbuf, length) != length)
+ return(-1);
+ return(0);
+}
+
+
+/* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
+
+static int
+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 FTP_TIMEOUT
+ if (check_data_connection(fd,0) < 0)
+ return(-3);
+#endif /* FTP_TIMEOUT */
+
+#ifdef CK_SSL
+ if (ssl_ftp_data_active_flag) {
+ int count, error;
+ count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
+ error = SSL_get_error(ssl_ftp_data_con,count);
+#ifdef DEBUG
+ if (error != SSL_ERROR_NONE)
+ debug(F101,"ftp secure_getbyte error","",error);
+ if (count == 0)
+ debug(F101,"ftp secure_getbyte count","",count);
+#endif /* DEBUG */
+ switch (error) {
+ case SSL_ERROR_NONE:
+ if (count > 0) {
+ nin = bufp = count;
+ rpackets++;
+ pktnum++;
+ if (fdispla != XYFD_B) {
+ rpktl = count;
+ ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
+ }
+ break;
+ }
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_SYSCALL:
+#ifdef NT
+ {
+ int gle = GetLastError();
+ }
+#endif /* NT */
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ nin = bufp = count = 0;
+ SSL_shutdown(ssl_ftp_data_con);
+ SSL_free(ssl_ftp_data_con);
+ ssl_ftp_data_active_flag = 0;
+ ssl_ftp_data_con = NULL;
+#ifdef TCPIPLIB
+ socket_close(data);
+#else /* TCPIPLIB */
+#ifdef USE_SHUTDOWN
+ shutdown(data, 1+1);
+#endif /* USE_SHUTDOWN */
+ close(data);
+#endif /* TCPIPLIB */
+ data = -1;
+ globaldin = data;
+ break;
+ }
+ } else
+#endif /* CK_SSL */
+ {
+ kerror = looping_read(fd, (char *)&length, sizeof(length));
+ if (kerror != sizeof(length)) {
+ secure_error("Couldn't read PROT buffer length: %d/%s",
+ kerror,
+ kerror == -1 ? ck_errstr()
+ : "premature EOF"
+ );
+ return(ERR);
+ }
+ debug(F101,"secure_getbyte length","",length);
+ debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
+
+ length = (ULONG) ntohl(length);
+ if (length > maxbuf) {
+ secure_error("Length (%d) of PROT buffer > PBSZ=%u",
+ length,
+ maxbuf
+ );
+ return(ERR);
+ }
+ if ((kerror = looping_read(fd, ucbuf, length)) != length) {
+ secure_error("Couldn't read %u byte PROT buffer: %s",
+ length,
+ kerror == -1 ? ck_errstr() : "premature EOF"
+ );
+ return(ERR);
+ }
+
+ /* Other auth types go here ... */
+#ifdef FTP_SRP
+ if (strcmp(auth_type, "SRP") == 0) {
+ if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
+ (CHAR *) ucbuf,
+ ucbuf,
+ length
+ )
+ ) == -1) {
+ secure_error ("srp_encode failed" );
+ return ERR;
+ }
+ }
+#endif /* FTP_SRP */
+#ifdef FTP_KRB4
+ if (strcmp(auth_type, "KERBEROS_V4") == 0) {
+ struct sockaddr_in myaddr, hisaddr;
+ GSOCKNAME_T len;
+ len = sizeof(myaddr);
+ if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
+ secure_error("secure_putbuf: getsockname failed");
+ return(ERR);
+ }
+ len = sizeof(hisaddr);
+ if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
+ secure_error("secure_putbuf: getpeername failed");
+ return(ERR);
+ }
+ if (ftp_dpl) {
+ kerror = krb_rd_priv(ucbuf, length, ftp_sched,
+#ifdef KRB524
+ ftp_cred.session,
+#else /* KRB524 */
+ &ftp_cred.session,
+#endif /* KRB524 */
+ &hisaddr, &myaddr, &ftp_msg_data);
+ } else {
+ kerror = krb_rd_safe(ucbuf, length,
+#ifdef KRB524
+ ftp_cred.session,
+#else /* KRB524 */
+ &ftp_cred.session,
+#endif /* KRB524 */
+ &hisaddr, &myaddr, &ftp_msg_data);
+ }
+ if (kerror) {
+ secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
+ ftp_dpl == FPL_PRV ? "priv" : "safe",
+ krb_get_err_text(kerror));
+ return(ERR);
+ }
+ memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
+ nin = bufp = ftp_msg_data.app_length;
+ }
+#endif /* FTP_KRB4 */
+#ifdef FTP_GSSAPI
+ if (strcmp(auth_type, "GSSAPI") == 0) {
+ gss_buffer_desc xmit_buf, msg_buf;
+ OM_uint32 maj_stat, min_stat;
+ int conf_state;
+
+ xmit_buf.value = ucbuf;
+ xmit_buf.length = length;
+ conf_state = (ftp_dpl == FPL_PRV);
+ /* decrypt/verify the message */
+ maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
+ &msg_buf, &conf_state, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ user_gss_error(maj_stat, min_stat,
+ (ftp_dpl == FPL_PRV)?
+ "failed unsealing ENC message":
+ "failed unsealing MIC message");
+ return ERR;
+ }
+ memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
+ gss_release_buffer(&min_stat, &msg_buf);
+ }
+#endif /* FTP_GSSAPI */
+ /* Other auth types go here ... */
+
+ /* Update file transfer display */
+ rpackets++;
+ pktnum++;
+ if (fdispla != XYFD_B) {
+ rpktl = nin;
+ ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
+ }
+ }
+ }
+ if (nin == 0)
+ return(EOF);
+ else
+ return(ucbuf[bufp - nin--]);
+}
+
+/* secure_getc(fd,fc)
+ * Call with:
+ * fd = file descriptor for connection.
+ * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
+ * Returns:
+ * c>=0 on success (character value)
+ * -1 on EOF
+ * -2 on security error
+ * -3 on timeout (if built with FTP_TIMEOUT defined)
+ */
+static int
+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);
+
+#ifdef FTP_TIMEOUT
+ if (check_data_connection(fd,0) < 0) {
+ debug(F100,"secure_getc TIMEOUT","",0);
+ nin = bufp = 0;
+ ftp_timed_out = 1;
+ return(-3);
+ }
+#endif /* FTP_TIMEOUT */
+
+ nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
+ if ((nin == 0) || (nin == (unsigned int)-1)) {
+ debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
+ debug(F101,"secure_getc returns EOF","",EOF);
+ nin = bufp = 0;
+ return(EOF);
+ }
+ debug(F101,"ftp secure_getc recv","",nin);
+ ckhexdump("ftp secure_getc recv",ucbuf,16);
+ rpackets++;
+ pktnum++;
+ if (fdispla != XYFD_B) {
+ rpktl = nin;
+ ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
+ }
+ }
+ return(ucbuf[bufp - nin--]);
+ } else
+ return(secure_getbyte(fd,fc));
+}
+
+/* returns:
+ * n>0 on success (n == # of bytes read)
+ * 0 on EOF
+ * -1 on error (errno set), only for FPL_CLR
+ * -2 on security error
+ */
+static int
+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);
+#ifdef FTP_TIMEOUT
+ case -3:
+ debug(F101,"ftp secure_read timeout","",c);
+ return(c);
+#endif /* FTP_TIMEOUT */
+ default:
+ buf[i++] = c;
+ }
+ }
+ return(i);
+}
+
+#ifdef USE_RUSERPASS
+/* BEGIN_RUSERPASS
+ *
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
+#endif /* not lint */
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+char * renvlook();
+static FILE * cfile;
+
+#define DEFAULT 1
+#define LOGIN 2
+#define PASSWD 3
+#define ACCOUNT 4
+#define MACDEF 5
+#define ID 10
+#define MACH 11
+
+static char tokval[100];
+
+static struct toktab {
+ char *tokstr;
+ int tval;
+} toktab[]= {
+ "default", DEFAULT,
+ "login", LOGIN,
+ "password", PASSWD,
+ "passwd", PASSWD,
+ "account", ACCOUNT,
+ "machine", MACH,
+ "macdef", MACDEF,
+ 0, 0
+};
+
+static int
+token() {
+ char *cp;
+ int c;
+ struct toktab *t;
+
+ if (feof(cfile))
+ return(0);
+ while ((c = getc(cfile)) != EOF &&
+ (c == '\n' || c == '\t' || c == ' ' || c == ','))
+ continue;
+ if (c == EOF)
+ return(0);
+ cp = tokval;
+ if (c == '"') {
+ while ((c = getc(cfile)) != EOF && c != '"') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ } else {
+ *cp++ = c;
+ while ((c = getc(cfile)) != EOF
+ && c != '\n' && c != '\t' && c != ' ' && c != ',') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ }
+ *cp = 0;
+ if (tokval[0] == 0)
+ return(0);
+ for (t = toktab; t->tokstr; t++)
+ if (!strcmp(t->tokstr, tokval))
+ return(t->tval);
+ return(ID);
+}
+
+ruserpass(host, aname, apass, aacct)
+ char *host, **aname, **apass, **aacct;
+{
+ char *hdir, buf[FTP_BUFSIZ], *tmp;
+ char myname[MAXHOSTNAMELEN], *mydomain;
+ int t, i, c, usedefault = 0;
+#ifdef NT
+ struct _stat stb;
+#else /* NT */
+ struct stat stb;
+#endif /* NT */
+
+ hdir = getenv("HOME");
+ if (hdir == NULL)
+ hdir = ".";
+ ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
+ cfile = fopen(buf, "r");
+ if (cfile == NULL) {
+ if (errno != ENOENT)
+ perror(buf);
+ return(0);
+ }
+ if (gethostname(myname, MAXHOSTNAMELEN) < 0)
+ myname[0] = '\0';
+ if ((mydomain = ckstrchr(myname, '.')) == NULL)
+ mydomain = "";
+
+ next:
+ while ((t = token())) switch(t) {
+
+ case DEFAULT:
+ usedefault = 1;
+ /* FALL THROUGH */
+
+ case MACH:
+ if (!usedefault) {
+ if (token() != ID)
+ continue;
+ /*
+ * Allow match either for user's input host name
+ * or official hostname. Also allow match of
+ * incompletely-specified host in local domain.
+ */
+ if (ckstrcmp(host, tokval,-1,1) == 0)
+ goto match;
+ if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
+ goto match;
+ if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
+ ckstrcmp(tmp, mydomain,-1,1) == 0 &&
+ ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
+ tokval[tmp - ftp_host] == '\0')
+ goto match;
+ if ((tmp = ckstrchr(host, '.')) != NULL &&
+ ckstrcmp(tmp, mydomain,-1,1) == 0 &&
+ ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
+ tokval[tmp - host] == '\0')
+ goto match;
+ continue;
+ }
+
+ match:
+ while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
+
+ case LOGIN:
+ if (token())
+ if (*aname == 0) {
+ *aname = malloc((unsigned) strlen(tokval) + 1);
+ strcpy(*aname, tokval); /* safe */
+ } else {
+ if (strcmp(*aname, tokval))
+ goto next;
+ }
+ break;
+ case PASSWD:
+ if (strcmp(*aname, "anonymous") &&
+ fstat(fileno(cfile), &stb) >= 0 &&
+ (stb.st_mode & 077) != 0) {
+ fprintf(stderr, "Error - .netrc file not correct mode.\n");
+ fprintf(stderr, "Remove password or correct mode.\n");
+ goto bad;
+ }
+ if (token() && *apass == 0) {
+ *apass = malloc((unsigned) strlen(tokval) + 1);
+ strcpy(*apass, tokval); /* safe */
+ }
+ break;
+ case ACCOUNT:
+ if (fstat(fileno(cfile), &stb) >= 0
+ && (stb.st_mode & 077) != 0) {
+ fprintf(stderr, "Error - .netrc file not correct mode.\n");
+ fprintf(stderr, "Remove account or correct mode.\n");
+ goto bad;
+ }
+ if (token() && *aacct == 0) {
+ *aacct = malloc((unsigned) strlen(tokval) + 1);
+ strcpy(*aacct, tokval); /* safe */
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
+ break;
+ }
+ goto done;
+ }
+
+ done:
+ fclose(cfile);
+ return(0);
+
+ bad:
+ fclose(cfile);
+ return(-1);
+}
+#endif /* USE_RUSERPASS */
+
+static char *radixN =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static char pad = '=';
+
+static int
+radix_encode(inbuf, outbuf, inlen, outlen, decode)
+ CHAR inbuf[], outbuf[];
+ int inlen, *outlen, decode;
+{
+ int i, j, D = 0;
+ char *p;
+ CHAR c = NUL;
+
+ if (decode) {
+ for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
+ if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
+ return(1);
+ D = p - radixN;
+ switch (i&3) {
+ case 0:
+ outbuf[j] = D<<2;
+ break;
+ case 1:
+ outbuf[j++] |= D>>4;
+ outbuf[j] = (D&15)<<4;
+ break;
+ case 2:
+ outbuf[j++] |= D>>2;
+ outbuf[j] = (D&3)<<6;
+ break;
+ case 3:
+ outbuf[j++] |= D;
+ }
+ if (j == *outlen)
+ return(4);
+ }
+ switch (i&3) {
+ case 1: return(3);
+ case 2: if (D&15) return(3);
+ if (strcmp((char *)&inbuf[i], "==")) return(2);
+ break;
+ case 3: if (D&3) return(3);
+ if (strcmp((char *)&inbuf[i], "=")) return(2);
+ }
+ *outlen = j;
+ } else {
+ for (i = 0, j = 0; i < inlen; i++) {
+ switch (i%3) {
+ case 0:
+ outbuf[j++] = radixN[inbuf[i]>>2];
+ c = (inbuf[i]&3)<<4;
+ break;
+ case 1:
+ outbuf[j++] = radixN[c|inbuf[i]>>4];
+ c = (inbuf[i]&15)<<2;
+ break;
+ case 2:
+ outbuf[j++] = radixN[c|inbuf[i]>>6];
+ outbuf[j++] = radixN[inbuf[i]&63];
+ c = 0;
+ }
+ if (j == *outlen)
+ return(4);
+ }
+ if (i%3) outbuf[j++] = radixN[c];
+ switch (i%3) {
+ case 1: outbuf[j++] = pad;
+ case 2: outbuf[j++] = pad;
+ }
+ outbuf[*outlen = j] = '\0';
+ }
+ return(0);
+}
+
+static char *
+radix_error(e) int e;
+{
+ switch (e) {
+ case 0: return("Success");
+ case 1: return("Bad character in encoding");
+ case 2: return("Encoding not properly padded");
+ case 3: return("Decoded # of bits not a multiple of 8");
+ case 4: return("Output buffer too small");
+ default: return("Unknown error");
+ }
+}
+/* END_RUSERPASS */
+
+#ifdef FTP_SRP
+/*---------------------------------------------------------------------------+
+ | |
+ | Package: srpftp |
+ | Author: Eugene Jhong |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*
+ * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ * must display the following acknowlegment:
+ * "This product uses the 'Secure Remote Password' cryptographic
+ * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ * itself must also display the following acknowledgment:
+ * "This product includes software developed by Tom Wu and Eugene
+ * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice and list of conditions.
+ */
+
+#define SRP_PROT_VERSION 1
+
+#ifdef CK_ENCRYPTION
+#define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
+#else
+#define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
+#endif /* CK_ENCRYPTION */
+
+#define SRP_DEFAULT_HASH HASH_ID_SHA
+
+CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
+CHAR srp_pref_hash = HASH_ID_SHA;
+
+static struct t_client *tc = NULL;
+static CHAR *skey = NULL;
+static krypto_context *incrypt = NULL;
+static krypto_context *outcrypt = NULL;
+
+typedef unsigned int srp_uint32;
+
+/*--------------------------------------------------------------+
+ | srp_selcipher: select cipher |
+ +--------------------------------------------------------------*/
+static int
+srp_selcipher (cname) char *cname; {
+ cipher_desc *cd;
+
+ if (!(cd = cipher_getdescbyname (cname))) {
+ int i;
+ CHAR *list = cipher_getlist ();
+
+ fprintf (stderr, "ftp: supported ciphers:\n\n");
+ for (i = 0; i < strlen (list); i++)
+ fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
+ fprintf (stderr, "\n");
+ return -1;
+ }
+ srp_pref_cipher = cd->id;
+ return 0;
+}
+
+/*--------------------------------------------------------------+
+ | srp_selhash: select hash |
+ +--------------------------------------------------------------*/
+static int
+srp_selhash (hname) char *hname; {
+ hash_desc *hd;
+
+ if (!(hd = hash_getdescbyname (hname))) {
+ int i;
+ CHAR *list = hash_getlist ();
+
+ fprintf (stderr, "ftp: supported hash functions:\n\n");
+ for (i = 0; i < strlen (list); i++)
+ fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
+ fprintf (stderr, "\n");
+ return -1;
+ }
+ srp_pref_hash = hd->id;
+ return 0;
+}
+
+/*--------------------------------------------------------------+
+ | srp_userpass: get username and password |
+ +--------------------------------------------------------------*/
+static int
+srp_userpass (host) char *host; {
+ char tmp[BUFSIZ], prompt[PROMPTSIZ];
+ char *user;
+
+ user = NULL;
+#ifdef USE_RUSERPASS
+ ruserpass (host, &user, &srp_pass, &srp_acct);
+#endif /* USE_RUSERPASS */
+
+ while (user == NULL) {
+ char *myname;
+ int ok;
+
+ myname = whoami();
+ if (!myname) myname = "";
+ if (myname[0])
+ ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ else
+ ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
+ tmp[0] = '\0';
+ ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if (!ok || *tmp == '\0')
+ user = myname;
+ else
+ user = brstrip(tmp);
+ }
+ ckstrncpy (srp_user, user,BUFSIZ);
+ return(0);
+}
+
+/*--------------------------------------------------------------+
+ | srp_reset: reset srp information |
+ +--------------------------------------------------------------*/
+static int
+srp_reset () {
+ if (tc) { t_clientclose (tc); tc = NULL; }
+ if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
+ if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
+ return(0);
+}
+
+/*--------------------------------------------------------------+
+ | srp_ftp_auth: perform srp authentication |
+ +--------------------------------------------------------------*/
+static int
+srp_ftp_auth(host, user, pass)
+ char *host;
+ char *user;
+ char *pass;
+{
+ struct t_num *wp;
+ struct t_num N;
+ struct t_num g;
+ struct t_num s;
+ struct t_num yp;
+ CHAR buf[FTP_BUFSIZ];
+ CHAR tmp[FTP_BUFSIZ];
+ CHAR *bp, *cp;
+ int n, e, clen, blen, len, i;
+ CHAR cid = 0;
+ CHAR hid = 0;
+
+ srp_pass = srp_acct = 0;
+
+ n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
+ if (n != REPLY_CONTINUE) {
+ if (ftp_deb)
+ fprintf(stderr, "SRP rejected as an authentication type\n");
+ return(0);
+ } else { /* Send protocol version */
+ CHAR vers[4];
+ memset (vers, 0, 4);
+ vers[3] = SRP_PROT_VERSION;
+ if (!quiet)
+ printf ("SRP accepted as authentication type.\n");
+ bp = tmp; blen = 0;
+ srp_put (vers, &bp, 4, &blen);
+ len = FTP_BUFSIZ;
+ if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
+ goto encode_error;
+ reply_parse = "ADAT=";
+ n = ftpcmd("ADAT",buf,-1,-1,0);
+ }
+ if (n == REPLY_CONTINUE) { /* Get protocol version */
+ bp = buf;
+ if (!reply_parse)
+ goto data_error;
+ blen = FTP_BUFSIZ;
+ if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
+ goto decode_error;
+ if (srp_get (&bp, &cp, &blen, &clen) != 4)
+ goto data_error;
+
+ if (host) { /* Get username/password if needed */
+ srp_userpass (host);
+ } else {
+ ckstrncpy (srp_user, user, BUFSIZ);
+ srp_pass = pass;
+ }
+ bp = tmp; blen = 0; /* Send username */
+ srp_put (srp_user, &bp, strlen (srp_user), &blen);
+ len = FTP_BUFSIZ;
+ if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
+ goto encode_error;
+ reply_parse = "ADAT=";
+ n = ftpcmd("ADAT",buf,-1,-1,0);
+ }
+ if (n == REPLY_CONTINUE) { /* Get N, g and s */
+ bp = buf;
+ if (!reply_parse)
+ goto data_error;
+ blen = FTP_BUFSIZ;
+ if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
+ goto decode_error;
+ if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
+ goto data_error;
+ if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
+ goto data_error;
+ if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
+ goto data_error;
+ if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
+ fprintf (stderr, "Unable to open SRP client structure.\n");
+ goto bad;
+ }
+ wp = t_clientgenexp (tc); /* Send wp */
+ bp = tmp; blen = 0;
+ srp_put (wp->data, &bp, wp->len, &blen);
+ len = FTP_BUFSIZ;
+ if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
+ goto encode_error;
+ reply_parse = "ADAT=";
+ n = ftpcmd("ADAT",buf,-1,-1,0);
+ }
+ if (n == REPLY_CONTINUE) { /* Get yp */
+ bp = buf;
+ if (!reply_parse)
+ goto data_error;
+ blen = FTP_BUFSIZ;
+ if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
+ goto decode_error;
+ if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
+ goto data_error;
+ if (!srp_pass) {
+ static char ftppass[PASSBUFSIZ];
+ int ok;
+ setint();
+ ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if (ok)
+ srp_pass = brstrip(ftppass);
+ }
+ t_clientpasswd (tc, srp_pass);
+ memset (srp_pass, 0, strlen (srp_pass));
+ skey = t_clientgetkey (tc, &yp); /* Send response */
+ bp = tmp; blen = 0;
+ srp_put (t_clientresponse (tc), &bp, 20, &blen);
+ len = FTP_BUFSIZ;
+ if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
+ goto encode_error;
+ reply_parse = "ADAT=";
+ n = ftpcmd("ADAT",buf,-1,-1,0);
+ }
+ if (n == REPLY_CONTINUE) { /* Get response */
+ bp = buf;
+ if (!reply_parse)
+ goto data_error;
+ blen = FTP_BUFSIZ;
+ if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
+ goto encode_error;
+ if (srp_get (&bp, &cp, &blen, &clen) != 20)
+ goto data_error;
+ if (t_clientverify (tc, cp)) {
+ fprintf (stderr, "WARNING: bad response to client challenge.\n");
+ goto bad;
+ }
+ bp = tmp; blen = 0; /* Send nothing */
+ srp_put ("\0", &bp, 1, &blen);
+ len = FTP_BUFSIZ;
+ if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
+ goto encode_error;
+ reply_parse = "ADAT=";
+ n = ftpcmd("ADAT",buf,-1,-1,0);
+ }
+ if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
+ CHAR seqnum[4];
+ CHAR *clist;
+ CHAR *hlist;
+ CHAR *p1;
+ int clist_len, hlist_len;
+ bp = buf;
+ if (!reply_parse)
+ goto data_error;
+ blen = FTP_BUFSIZ;
+ if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
+ goto encode_error;
+ if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
+ goto data_error;
+ if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
+ goto data_error;
+ if (srp_get (&bp, &cp, &blen, &clen) != 4)
+ goto data_error;
+ memcpy (seqnum, cp, 4);
+ if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
+ cid = srp_pref_cipher;
+ if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
+ cid = SRP_DEFAULT_CIPHER;
+ if (!cid) {
+ CHAR *loclist = cipher_getlist ();
+ for (i = 0; i < strlen (loclist); i++)
+ if (cipher_supported (clist, loclist[i])) {
+ cid = loclist[i];
+ break;
+ }
+ }
+ if (!cid) {
+ fprintf (stderr, "Unable to agree on cipher.\n");
+ goto bad;
+ }
+ /* Choose hash */
+
+ if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
+ hid = srp_pref_hash;
+
+ if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
+ hid = SRP_DEFAULT_HASH;
+
+ if (!hid) {
+ CHAR *loclist = hash_getlist ();
+ for (i = 0; i < strlen (loclist); i++)
+ if (hash_supported (hlist, loclist[i])) {
+ hid = loclist[i];
+ break;
+ }
+ }
+ if (!hid) {
+ fprintf (stderr, "Unable to agree on hash.\n");
+ goto bad;
+ }
+ /* Set incrypt */
+
+ if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
+ KRYPTO_DECODE)))
+ goto bad;
+
+ /* Generate random number for outkey and outseqnum */
+
+ t_random (seqnum, 4);
+
+ /* Send cid, hid, outkey, outseqnum */
+
+ bp = tmp; blen = 0;
+ srp_put (&cid, &bp, 1, &blen);
+ srp_put (&hid, &bp, 1, &blen);
+ srp_put (seqnum, &bp, 4, &blen);
+ len = FTP_BUFSIZ;
+ if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
+ goto encode_error;
+ reply_parse = "ADAT=";
+ n = ftpcmd("ADAT",buf,-1,-1,0);
+
+ /* Set outcrypt */
+
+ if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
+ KRYPTO_ENCODE)))
+ goto bad;
+
+ t_clientclose (tc);
+ tc = NULL;
+ }
+ if (n != REPLY_COMPLETE)
+ goto bad;
+
+ if (ftp_vbm) {
+ if (ftp_deb)
+ printf("\n");
+ printf ("SRP authentication succeeded.\n");
+ printf ("Using cipher %s and hash function %s.\n",
+ (cipher_getdescbyid(cid))->name,
+ (hash_getdescbyid(hid))->name
+ );
+ }
+ reply_parse = NULL;
+ auth_type = "SRP";
+ return(1);
+
+ encode_error:
+ fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
+ goto bad;
+
+ decode_error:
+ fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
+ goto bad;
+
+ data_error:
+ fprintf (stderr, "Unable to unmarshal authentication data.\n");
+ goto bad;
+
+ bad:
+ fprintf (stderr, "SRP authentication failed, trying regular login.\n");
+ reply_parse = NULL;
+ return(0);
+}
+
+/*--------------------------------------------------------------+
+ | srp_put: put item to send buffer |
+ +--------------------------------------------------------------*/
+static int
+srp_put (in, out, inlen, outlen)
+ CHAR *in;
+ CHAR **out;
+ int inlen;
+ int *outlen;
+{
+ srp_uint32 net_len;
+
+ net_len = htonl (inlen);
+ memcpy (*out, &net_len, 4);
+
+ *out += 4; *outlen += 4;
+
+ memcpy (*out, in, inlen);
+
+ *out += inlen; *outlen += inlen;
+ return(0);
+}
+
+/*--------------------------------------------------------------+
+ | srp_get: get item from receive buffer |
+ +--------------------------------------------------------------*/
+static int
+srp_get (in, out, inlen, outlen)
+ CHAR **in;
+ CHAR **out;
+ int *inlen;
+ int *outlen;
+{
+ srp_uint32 net_len;
+
+ if (*inlen < 4) return -1;
+
+ memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
+ *outlen = ntohl (net_len);
+
+ if (*inlen < *outlen) return -1;
+
+ *out = *in; *inlen -= *outlen; *in += *outlen;
+
+ return *outlen;
+}
+
+/*--------------------------------------------------------------+
+ | srp_encode: encode control message |
+ +--------------------------------------------------------------*/
+static int
+srp_encode (private, in, out, len)
+ int private;
+ CHAR *in;
+ CHAR *out;
+ unsigned len;
+{
+ if (private)
+ return krypto_msg_priv (outcrypt, in, out, len);
+ else
+ return krypto_msg_safe (outcrypt, in, out, len);
+}
+
+/*--------------------------------------------------------------+
+ | srp_decode: decode control message |
+ +--------------------------------------------------------------*/
+static int
+srp_decode (private, in, out, len)
+ int private;
+ CHAR *in;
+ CHAR *out;
+ unsigned len;
+{
+ if (private)
+ return krypto_msg_priv (incrypt, in, out, len);
+ else
+ return krypto_msg_safe (incrypt, in, out, len);
+}
+
+#endif /* FTP_SRP */
+
+
+
+#ifdef NOT_USED
+/*
+ The following code is from the Unix FTP client. Be sure to
+ make sure that the functionality is not lost. Especially
+ the Proxy stuff even though we have not yet implemented it.
+*/
+
+/* Send multiple files */
+
+static int
+ftp_mput(argc, argv) int argc; char **argv; {
+ register int i;
+ sig_t oldintr;
+ int ointer;
+ char *tp;
+ sigtype mcancel();
+
+ if (argc < 2 && !another(&argc, &argv, "local-files")) {
+ printf("usage: %s local-files\n", argv[0]);
+ ftpcode = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT, mcancel);
+
+ /* Replace with calls to cc_execute() */
+ setjmp(jcancel);
+#ifdef FTP_PROXY
+ if (proxy) {
+ char *cp, *tp2, tmpbuf[CKMAXPATH];
+
+ while ((cp = remglob(argv,0)) != NULL) {
+ if (*cp == 0) {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ tp = cp;
+ if (mcase) {
+ while (*tp && !islower(*tp)) {
+ tp++;
+ }
+ if (!*tp) {
+ tp = cp;
+ tp2 = tmpbuf;
+ while ((*tp2 = *tp) != 0) {
+ if (isupper(*tp2)) {
+ *tp2 = 'a' + *tp2 - 'A';
+ }
+ tp++;
+ tp2++;
+ }
+ }
+ tp = tmpbuf;
+ }
+ if (ntflag) {
+ tp = dotrans(tp);
+ }
+ if (mapflag) {
+ tp = domap(tp);
+ }
+ sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ signal(SIGINT, oldintr);
+ mflag = 0;
+ return;
+ }
+#endif /* FTP_PROXY */
+ for (i = 1; i < argc; i++) {
+ register char **cpp, **gargs;
+
+ if (mflag && confirm(argv[0], argv[i])) {
+ tp = argv[i];
+ sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ continue;
+
+ gargs = ftpglob(argv[i]);
+ if (globerr != NULL) {
+ printf("%s\n", globerr);
+ if (gargs) {
+ blkfree(gargs);
+ free((char *)gargs);
+ }
+ continue;
+ }
+ for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
+ if (mflag && confirm(argv[0], *cpp)) {
+ tp = *cpp;
+ sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ if (gargs != NULL) {
+ blkfree(gargs);
+ free((char *)gargs);
+ }
+ }
+ signal(SIGINT, oldintr);
+ mflag = 0;
+}
+
+/* Get multiple files */
+
+static int
+ftp_mget(argc, argv) int argc; char **argv; {
+ int rc = -1;
+ sig_t oldintr;
+ int ointer;
+ char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
+ sigtype mcancel();
+
+ if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+ printf("usage: %s remote-files\n", argv[0]);
+ ftpcode = -1;
+ return(-1);
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT,mcancel);
+ /* Replace with calls to cc_execute() */
+ setjmp(jcancel);
+ while ((cp = remglob(argv,proxy)) != NULL) {
+ if (*cp == '\0') {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ tp = cp;
+ if (mcase) {
+ while (*tp && !islower(*tp)) {
+ tp++;
+ }
+ if (!*tp) {
+ tp = cp;
+ tp2 = tmpbuf;
+ while ((*tp2 = *tp) != 0) {
+ if (isupper(*tp2)) {
+ *tp2 = 'a' + *tp2 - 'A';
+ }
+ tp++;
+ tp2++;
+ }
+ }
+ tp = tmpbuf;
+ }
+ rc = (recvrequest("RETR", tp, cp, "wb",
+ tp != cp || !interactive) == 0,0,NULL,0,0,0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mget")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ signal(SIGINT,oldintr);
+ mflag = 0;
+ return(rc);
+}
+
+/* Delete multiple files */
+
+static int
+mdelete(argc, argv) int argc; char **argv; {
+ sig_t oldintr;
+ int ointer;
+ char *cp;
+ sigtype mcancel();
+
+ if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+ printf("usage: %s remote-files\n", argv[0]);
+ ftpcode = -1;
+ return(-1);
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT, mcancel);
+ /* Replace with calls to cc_execute() */
+ setjmp(jcancel);
+ while ((cp = remglob(argv,0)) != NULL) {
+ if (*cp == '\0') {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mdelete")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ signal(SIGINT, oldintr);
+ mflag = 0;
+ return(rc);
+}
+
+/* Get a directory listing of multiple remote files */
+
+static int
+mls(argc, argv) int argc; char **argv; {
+ sig_t oldintr;
+ int ointer, i;
+ char *cmd, mode[1], *dest;
+ sigtype mcancel();
+ int rc = -1;
+
+ if (argc < 2 && !another(&argc, &argv, "remote-files"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "local-file")) {
+ usage:
+ printf("usage: %s remote-files local-file\n", argv[0]);
+ ftpcode = -1;
+ return(-1);
+ }
+ dest = argv[argc - 1];
+ argv[argc - 1] = NULL;
+ if (strcmp(dest, "-") && *dest != '|')
+ if (!globulize(&dest) ||
+ !confirm("output to local-file:", dest)) {
+ ftpcode = -1;
+ return(-1);
+ }
+ cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT, mcancel);
+ /* Replace with calls to cc_execute() */
+ setjmp(jcancel);
+ for (i = 1; mflag && i < argc-1; ++i) {
+ *mode = (i == 1) ? 'w' : 'a';
+ rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", argv[0])) {
+ mflag ++;
+ }
+ interactive = ointer;
+ }
+ }
+ signal(SIGINT, oldintr);
+ mflag = 0;
+ return(rc);
+}
+
+static char *
+remglob(argv,doswitch) char *argv[]; int doswitch; {
+ char temp[16];
+ static char buf[CKMAXPATH];
+ static FILE *ftemp = NULL;
+ static char **args;
+ int oldhash;
+ char *cp, *mode;
+
+ if (!mflag) {
+ if (!doglob) {
+ args = NULL;
+ } else {
+ if (ftemp) {
+ (void) fclose(ftemp);
+ ftemp = NULL;
+ }
+ }
+ return(NULL);
+ }
+ if (!doglob) {
+ if (args == NULL)
+ args = argv;
+ if ((cp = *++args) == NULL)
+ args = NULL;
+ return(cp);
+ }
+ if (ftemp == NULL) {
+ (void) strcpy(temp, _PATH_TMP);
+#ifdef MKTEMP
+#ifndef MKSTEMP
+ (void) mktemp(temp);
+#endif /* MKSTEMP */
+#endif /* MKTEMP */
+ verbose = 0;
+ oldhash = hash, hash = 0;
+#ifdef FTP_PROXY
+ if (doswitch) {
+ pswitch(!proxy);
+ }
+#endif /* FTP_PROXY */
+ for (mode = "wb"; *++argv != NULL; mode = "ab")
+ recvrequest ("NLST", temp, *argv, mode, 0);
+#ifdef FTP_PROXY
+ if (doswitch) {
+ pswitch(!proxy);
+ }
+#endif /* FTP_PROXY */
+ hash = oldhash;
+ ftemp = fopen(temp, "r");
+ unlink(temp);
+ if (ftemp == NULL && (!dpyactive || ftp_deb)) {
+ printf("Can't find list of remote files, oops\n");
+ return(NULL);
+ }
+ }
+ if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
+ fclose(ftemp), ftemp = NULL;
+ return(NULL);
+ }
+ if ((cp = ckstrchr(buf,'\n')) != NULL)
+ *cp = '\0';
+ return(buf);
+}
+#endif /* NOT_USED */
+#endif /* TCPSOCKET (top of file) */
+#endif /* SYSFTP (top of file) */
+#endif /* NOFTP (top of file) */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcker.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcker.h
new file mode 100644
index 0000000..890f666
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcker.h
@@ -0,0 +1,1425 @@
+/* ckcker.h -- Symbol and macro definitions for C-Kermit */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+#ifndef CKCKER_H
+#define CKCKER_H
+
+#define I_AM_KERMIT 0 /* Personalities */
+#define I_AM_TELNET 1
+#define I_AM_RLOGIN 2
+#define I_AM_IKSD 3
+#define I_AM_FTP 4
+#define I_AM_HTTP 5
+#define I_AM_SSHSUB 6
+#define I_AM_SSH 7
+
+#ifndef NOSTREAMING
+#ifndef STREAMING
+#define STREAMING
+#endif /* STREAMING */
+#endif /* NOSTREAMING */
+/*
+ If NEWDEFAULTS is defined then:
+ - RECEIVE PACKET-LENGTH is 4095 rather than 90
+ - WINDOW is 30 rather than 1
+ - BLOCK-CHECK is 3 rather than 1
+ - FILE TYPE is BINARY rather than TEXT
+*/
+#ifdef BIGBUFOK /* (was OS2) */
+#ifndef NEWDEFAULTS
+#define NEWDEFAULTS
+#endif /* NEWDEFAULTS */
+#endif /* BIGBUFOK */
+
+#ifdef NOICP /* No Interactive Command Parser */
+#ifndef NOSPL /* implies... */
+#define NOSPL /* No Script Programming Language */
+#endif /* NOSPL */
+#ifndef NOCSETS /* No character-set translation */
+#define NOCSETS /* because the only way to set it up */
+#endif /* NOCSETS */ /* is with interactive commands */
+#endif /* NOICP */
+
+#ifdef pdp11 /* There is a maximum number of */
+#ifndef NOCKSPEED /* of -D's allowed on the CC */
+#define NOCKSPEED /* command line, so some of them */
+#endif /* NOCKSPEED */ /* have to go here... */
+#ifndef NOREDIRECT
+#define NOREDIRECT
+#endif /* NOREDIRECT */
+#ifdef WHATAMI
+#undef WHATAMI
+#endif /* WHATAMI */
+#endif /* pdp11 */
+
+#ifdef UIDBUFLEN
+#define LOGINLEN UIDBUFLEN
+#else
+#define LOGINLEN 32 /* Length of server login field */
+#endif /* UIDBUFLEN */
+
+/* Bell values */
+
+#define XYB_NONE 0 /* No bell */
+#define XYB_AUD 1 /* Audible bell */
+#define XYB_VIS 2 /* Visible bell */
+#define XYB_BEEP 0 /* Audible Beep */
+#define XYB_SYS 4 /* Audible System Sounds */
+
+/* File status bits */
+
+#define FS_OK 1 /* File transferred OK */
+#define FS_REFU 2 /* File was refused */
+#define FS_DISC 4 /* File was discarded */
+#define FS_INTR 8 /* Transfer was interrupted by user */
+#define FS_ERR 16 /* Fatal error during transfer */
+
+/* Control-character (un)prefixing options */
+
+#define PX_ALL 0 /* Prefix all control chars */
+#define PX_CAU 1 /* Unprefix cautiously */
+#define PX_WIL 2 /* Unprefix with wild abandon */
+#define PX_NON 3 /* Unprefix all (= prefix none) */
+
+/* Destination codes */
+
+#define DEST_D 0 /* DISK */
+#define DEST_S 1 /* SCREEN */
+#define DEST_P 2 /* PRINTER */
+#define DEST_N 3 /* NOWHERE (calibration run) */
+
+/* File transfer protocols */
+
+#define PROTO_K 0 /* Kermit */
+#ifdef CK_XYZ
+#define PROTO_X 1 /* XMODEM */
+#define PROTO_XC 2 /* XMODEM-CRC */
+#define PROTO_Y 3 /* YMODEM */
+#define PROTO_G 4 /* YMODEM-g */
+#define PROTO_Z 5 /* ZMODEM */
+#define PROTO_O 6 /* OTHER */
+#define NPROTOS 7 /* How many */
+#else
+#define NPROTOS 1 /* How many */
+#endif /* CK_XYZ */
+
+struct ck_p { /* C-Kermit Protocol info structure */
+ char * p_name; /* Protocol name */
+ int rpktlen; /* Packet length - receive */
+ int spktlen; /* Packet length - send */
+ int spktflg; /* ... */
+ int winsize; /* Window size */
+ int prefix; /* Control-char prefixing options */
+ int fnca; /* Filename collision action */
+ int fncn; /* Filename conversion */
+ int fnsp; /* Send filename path stripping */
+ int fnrp; /* Receive filename path stripping */
+ char * h_b_init; /* Host receive initiation string - text */
+ char * h_t_init; /* Host receive initiation string - binary */
+ char * h_x_init; /* Host server string */
+ char * p_b_scmd; /* SEND cmd for external protocol - text */
+ char * p_t_scmd; /* SEND cmd for external protocol - binary */
+ char * p_b_rcmd; /* RECV cmd for external protocol - text */
+ char * p_t_rcmd; /* RECV cmd for external protocol - binary */
+};
+
+struct filelist { /* Send-file list element */
+ char * fl_name; /* Filename */
+ int fl_mode; /* Transfer mode */
+ char * fl_alias; /* Name to send the file under */
+ struct filelist * fl_next; /* Pointer to next element */
+};
+
+/* Kermit system IDs and associated properties... */
+
+struct sysdata {
+ char *sid_code; /* Kermit system ID code */
+ char *sid_name; /* Descriptive name */
+ short sid_unixlike; /* Tree-structured directory with separators */
+ char sid_dirsep; /* Directory separator character if unixlike */
+ short sid_dev; /* Can start with dev: */
+ short sid_case; /* Bit mapped: 1 = case matters, 2 = case preserved */
+ short sid_recfm; /* Text record separator */
+/*
+ 0 = unknown or nonstream
+ 1 = cr
+ 2 = lf
+ 3 = crlf
+*/
+};
+
+struct ssh_pf { /* SSH port forwarding */
+ int p1; /* port to be forwarded */
+ char * host; /* host */
+ int p2; /* port */
+};
+
+#define SET_ON 1 /* General values for settings that can be ON */
+#define SET_OFF 0 /* OFF, */
+#define SET_AUTO 2 /* or AUTO */
+
+#define PATH_OFF 0 /* Pathnames off (to be stripped) */
+#define PATH_REL 1 /* Pathnames on, left relative if possible */
+#define PATH_ABS 2 /* Pathnames absolute always */
+#define PATH_AUTO 4 /* Pathnames handled automatically */
+
+/* GET Options */
+
+#define GOPT_DEL 1 /* Delete source file */
+#define GOPT_REC 2 /* Recursive */
+#define GOPT_RES 4 /* Recover (Resend) */
+#define GOPT_CMD 8 /* Filename is a Command */
+
+/* GET Transfer Modes */
+
+#define GMOD_TXT 0 /* Text */
+#define GMOD_BIN 1 /* Binary */
+#define GMOD_AUT 2 /* Auto */
+#define GMOD_LBL 3 /* Labeled */
+
+/* GET Filename Options */
+
+#define GNAM_LIT 0 /* Literal */
+#define GNAM_CNV 1 /* Converted */
+
+/* GET Pathname Options */
+
+#define GPTH_OFF 0 /* Pathnames Off */
+#define GPTH_REL 1 /* Pathnames Relative */
+#define GPTH_ABX 2 /* Pathnames Absolute */
+
+#ifndef NOSPL
+/*
+ The IF REMOTE-ONLY command is available only in versions
+ that actually can be used in remote mode, and only if we have
+ an interactive command parser.
+*/
+#define CK_IFRO
+#ifdef MAC
+#undef CK_IFRO
+#else
+#ifdef GEMDOS
+#undef CK_IFRO
+#endif /* GEMDOS */
+#endif /* MAC */
+#endif /* NOSPL */
+
+/* Systems whose CONNECT modules can execute Application Program Commands */
+
+#ifdef NOSPL /* Script programming language */
+#ifdef CK_APC /* is required for APC. */
+#undef CK_APC
+#endif /* CK_APC */
+#ifndef NOAPC
+#define NOAPC
+#endif /* NOAPC */
+#ifndef NOAUTODL
+#define NOAUTODL
+#endif /* NOAUTODL */
+#endif /* NOSPL */
+
+#ifndef NOAPC /* Unless they said NO APC */
+#ifndef CK_APC /* And they didn't already define it */
+#ifdef OS2 /* OS/2 gets it */
+#define CK_APC
+#endif /* OS2 */
+#ifdef UNIX /* UNIX gets it */
+#define CK_APC
+#endif /* UNIX */
+#ifdef VMS /* VMS too */
+#define CK_APC
+#endif /* VMS */
+#endif /* CK_APC */
+#endif /* NOAPC */
+
+#ifdef CK_APC /* APC buffer length */
+#ifndef APCBUFLEN /* Should be no bigger than */
+#ifdef NOSPL /* command buffer length */
+#define APCBUFLEN 608 /* (see ckucmd.h) but we can't */
+#else /* reference ckucmd.h symbols here */
+#define APCBUFLEN 4096
+#endif /* NOSPL */
+#endif /* APCBUFLEN */
+#define APC_OFF 0 /* APC OFF (disabled) */
+#define APC_ON 1 /* APC ON (enabled for non-dangerous commands) */
+#define APC_UNCH 2 /* APC UNCHECKED (enabled for ALL commands) bitmask */
+#define APC_NOINP 4 /* APC (enabled with no input allowed - bitmask) */
+#define APC_INACTIVE 0 /* APC not in use */
+#define APC_REMOTE 1 /* APC in use from Remote */
+#define APC_LOCAL 2 /* APC being used from within Kermit */
+#ifndef NOAUTODL
+#ifndef CK_AUTODL /* Autodownload */
+#ifdef OS2
+#define CK_AUTODL
+#else
+#ifdef UNIX
+#define CK_AUTODL
+#else
+#ifdef VMS
+#define CK_AUTODL
+#else
+#ifdef CK_AUTODL
+#undef CK_AUTODL
+#endif /* CK_AUTODL */
+#endif /* NOAUTODL */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* CK_AUTODL */
+
+#else /* CK_APC not defined */
+
+#ifdef NOICP
+#ifdef UNIX
+#ifndef CK_AUTODL
+#define CK_AUTODL
+#endif /* CK_AUTODL */
+#endif /* UNIX */
+#else /* Not NOICP... */
+#ifdef CK_AUTODL
+#undef CK_AUTODL
+#endif /* CK_AUTODL */
+#endif /* NOICP */
+#endif /* CK_APC */
+
+#ifdef NOAUTODL
+#ifdef CK_AUTODL
+#undef CK_AUTODL
+#endif /* CK_AUTODL */
+#endif /* NOAUTODL */
+
+/* Codes for what we are doing now - bit mask values */
+
+#define W_NOTHING 0 /* Nothing */
+#define W_INIT 1 /* Initializing protocol */
+#define W_SEND 2 /* SENDing or MAILing */
+#define W_RECV 4 /* RECEIVEing or GETting */
+#define W_REMO 8 /* Doing a REMOTE command */
+#define W_CONNECT 16 /* CONNECT mode */
+#define W_COMMAND 32 /* Command mode */
+#define W_DIALING 64 /* Dialing a modem */
+#define W_FTP 128 /* FTP */
+#define W_FT_DELE 64 /* FTP MDELETE */
+#define W_KERMIT (W_INIT|W_SEND|W_RECV|W_REMO) /* Kermit protocol */
+#define W_XFER (W_INIT|W_SEND|W_RECV|W_REMO|W_FTP) /* File xfer any protocol */
+
+#ifndef NOWHATAMI
+#ifndef WHATAMI
+#define WHATAMI
+#endif /* WHATAMI */
+#endif /* NOWHATAMI */
+
+#ifdef WHATAMI /* Bit mask positions for WHATAMI */
+#define WMI_SERVE 1 /* Server mode */
+#define WMI_FMODE 2 /* File transfer mode */
+#define WMI_FNAME 4 /* File name conversion */
+#define WMI_STREAM 8 /* I have a reliable transport */
+#define WMI_CLEAR 16 /* I have a clear channel */
+#define WMI_FLAG 32 /* Flag that WHATAMI field is valid */
+/* WHATAMI2 bits... */
+#define WMI2_XMODE 1 /* Transfer mode auto(0)/manual(1) */
+#define WMI2_RECU 2 /* Transfer is recursive */
+#define WMI2_FLAG 32 /* Flag that WHATAMI2 field is valid */
+#endif /* WHATAMI */
+
+/* Terminal types */
+#define VT100 0 /* Also for VT52 mode */
+#define TEKTRONIX 1
+
+/* Normal packet and window size */
+
+#define MAXPACK 94 /* Maximum unextended packet size */
+ /* Can't be more than 94. */
+#ifdef pdp11 /* Maximum sliding window slots */
+#define MAXWS 8
+#else
+#define MAXWS 32 /* Can't be more than 32. */
+#endif /* pdp11 */
+
+/* Maximum long packet size for sending packets */
+/* Override these from cc command line via -DMAXSP=nnn */
+
+#ifdef IRIX /* Irix 6.4 and earlier has */
+#ifndef MAXSP /* Telnet server bug */
+#ifdef IRIX65
+#define MAXSP 9024
+#else
+#define MAXSP 4000
+#endif /* IRIX65 */
+#endif /* MAXSP */
+#endif /* IRIX */
+
+#ifdef DYNAMIC
+#ifndef MAXSP
+#define MAXSP 9024
+#endif /* MAXSP */
+#else /* not DYNAMIC */
+#ifndef MAXSP
+#ifdef pdp11
+#define MAXSP 1024
+#else
+#define MAXSP 2048
+#endif /* pdp11 */
+#endif /* MAXSP */
+#endif /* DYNAMIC */
+
+/* Maximum long packet size for receiving packets */
+/* Override these from cc command line via -DMAXRP=nnn */
+
+#ifdef DYNAMIC
+#ifndef MAXRP
+#define MAXRP 9024
+#endif /* MAXRP */
+#else /* not DYNAMIC */
+#ifndef MAXRP
+#ifdef pdp11
+#define MAXRP 1024
+#else
+#define MAXRP 2048
+#endif /* pdp11 */
+#endif /* MAXRP */
+#endif /* DYNAMIC */
+/*
+ Default sizes for windowed packet buffers.
+ Override these from cc command line via -DSBSIZ=nnn, -DRBSIZ=nnn.
+ Or just -DBIGBUFOK.
+*/
+#ifndef MAXGETPATH /* Maximum number of directories */
+#ifdef BIGBUFOK /* for GET path... */
+#define MAXGETPATH 128
+#else
+#define MAXGETPATH 16
+#endif /* BIGBUFOK */
+#endif /* MAXGETPATH */
+
+#ifndef NOSPL /* Query buffer length */
+#ifdef OS2
+#define QBUFL 4095
+#else
+#ifdef BIGBUFOK
+#define QBUFL 4095
+#else
+#define QBUFL 1023
+#endif /* BIGBUFOK */
+#endif /* OS2 */
+#endif /* NOSPL */
+
+#ifdef DYNAMIC
+#ifndef SBSIZ
+#ifdef BIGBUFOK /* If big buffers are safe... */
+#define SBSIZ 290000 /* Allow for 10 x 9024 or 20 x 4096 */
+#else /* Otherwise... */
+#ifdef pdp11
+#define SBSIZ 3020
+#else
+#define SBSIZ 9050 /* Allow for 3 x 3000, etc. */
+#endif /* pdp11 */
+#endif /* BIGBUFOK */
+#endif /* SBSIZ */
+
+#ifndef RBSIZ
+#ifdef BIGBUFOK
+#define RBSIZ 290000
+#else
+#ifdef pdp11
+#define RBSIZ 3020
+#else
+#define RBSIZ 9050
+#endif /* pdp11 */
+#endif /* BIGBUFOK */
+#endif /* RBSIZ */
+#else /* not DYNAMIC */
+#ifdef pdp11
+#define SBSIZ 3020
+#define RBSIZ 3020
+#else
+#ifndef SBSIZ
+#define SBSIZ (MAXSP * (MAXWS + 1))
+#endif /* SBSIZ */
+#ifndef RBSIZ
+#define RBSIZ (MAXRP * (MAXWS + 1))
+#endif /* RBSIZ */
+#endif /* pdp11 */
+#endif /* DYNAMIC */
+
+#ifdef BIGBUFOK
+#define PKTMSGLEN 1023
+#else
+#define PKTMSGLEN 80
+#endif /* BIGBUFOK */
+
+/* Kermit parameters and defaults */
+
+#define CTLQ '#' /* Control char prefix I will use */
+#define MYEBQ '&' /* 8th-Bit prefix char I will use */
+#define MYRPTQ '~' /* Repeat count prefix I will use */
+
+#define MAXTRY 10 /* Times to retry a packet */
+#define MYPADN 0 /* How many padding chars I need */
+#define MYPADC '\0' /* Which padding character I need */
+
+#define DMYTIM 8 /* Initial timeout interval to use. */
+#define URTIME 15 /* Timeout interval to use on me. */
+#define DSRVTIM 0 /* Default server cmd wait timeout. */
+
+#define DEFTRN 0 /* Default line turnaround handshake */
+
+#define MYEOL CR /* Incoming packet terminator. */
+
+#ifdef NEWDEFAULTS
+#define DRPSIZ 4095 /* Default incoming packet size. */
+#define DFWSIZ 30 /* Default window size */
+#define DFBCT 3 /* Default block-check type */
+#else
+#define DRPSIZ 90 /* Default incoming packet size. */
+#define DFWSIZ 1 /* Default window size */
+#define DFBCT 3 /* Default block-check type */
+#endif /* NEWDEFAULTS */
+
+/* The HP-UX 5 and 6 Telnet servers can only swallow 513 bytes at once */
+
+#ifdef HPUX5
+#ifdef DRPSIZ
+#undef DRPSIZ
+#endif /* DRPSIZ */
+#define DRPSIZ 500
+#else
+#ifdef HPUX6
+#ifdef DRPSIZ
+#undef DRPSIZ
+#endif /* DRPSIZ */
+#define DRPSIZ 500
+#endif /* HPUX6 */
+#endif /* HPUX5 */
+
+#define DSPSIZ 90 /* Default outbound packet size. */
+#define DDELAY 1 /* Default delay. */
+#define DSPEED 9600 /* Default line speed. */
+
+#ifdef OS2 /* Default CONNECT-mode */
+#define DFESC 29 /* escape character */
+#else
+#ifdef NEXT /* Ctrl-] for PC and NeXT */
+#define DFESC 29
+#else
+#ifdef GEMDOS /* And Atari ST */
+#define DFESC 29
+#else
+#define DFESC 28 /* Ctrl-backslash for others */
+#endif /* GEMDOS */
+#endif /* NEXT */
+#endif /* OS2 */
+
+#ifdef NOPUSH /* NOPUSH implies NOJC */
+#ifndef NOJC /* (no job control) */
+#define NOJC
+#endif /* NOJC */
+#endif /* NOPUSH */
+
+#ifdef UNIX /* Default for SET SUSPEND */
+#ifdef NOJC /* UNIX but job control disabled */
+#define DFSUSP 0
+#else /* UNIX, job control enabled. */
+#define DFSUSP 1
+#endif /* NOJC */
+#else
+#define DFSUSP 0
+#endif /* UNIX */
+
+#ifndef DFCDMSG
+#ifdef UNIXOROSK
+#define DFCDMSG "{{./.readme}{README.TXT}{READ.ME}}"
+#else
+#define DFCDMSG "{{README.TXT}{READ.ME}}"
+#endif /* UNIXOROSK */
+#endif /* DFCDMSG */
+
+#define NSNDEXCEPT 64 /* Max patterns for /EXCEPT: list */
+
+/* Files */
+
+#define ZCTERM 0 /* Console terminal */
+#define ZSTDIO 1 /* Standard input/output */
+#define ZIFILE 2 /* Current input file (SEND, etc) (in) */
+#define ZOFILE 3 /* Current output file (RECEIVE, GET) (out) */
+#define ZDFILE 4 /* Current debugging log file (out) */
+#define ZTFILE 5 /* Current transaction log file (out) */
+#define ZPFILE 6 /* Current packet log file (out) */
+#define ZSFILE 7 /* Current session log file (out) */
+#define ZSYSFN 8 /* Input/Output from a system function */
+#define ZRFILE 9 /* Local file for READ (in) */
+#define ZWFILE 10 /* Local file for WRITE (out) */
+#define ZMFILE 11 /* Miscellaneous file, e.g. for XLATE */
+#define ZDIFIL 12 /* DIAL log */
+#define ZNFILS 13 /* How many defined file numbers */
+
+#ifdef CKCHANNELIO
+
+/* File modes */
+
+#define FM_REA 1 /* Read */
+#define FM_WRI 2 /* Write */
+#define FM_APP 4 /* Append */
+#define FM_RWA 7 /* Read/Write/Append mask */
+#define FM_BIN 8 /* Binary */
+#define FM_RWB 15 /* Read/Write/Append/Binary mask */
+#define FM_CMD 16 /* Command */
+#define FM_EOF 64 /* (status) At EOF */
+
+/* File errors */
+
+#define FX_NER 0 /* No error */
+#define FX_SYS -1 /* System error */
+#define FX_EOF -2 /* End of file */
+#define FX_NOP -3 /* Channel not open */
+#define FX_CHN -4 /* Channel out of range */
+#define FX_RNG -5 /* Argument range error */
+#define FX_FNF -6 /* File not found */
+#define FX_BFN -7 /* Bad or missing filename */
+#define FX_NMF -8 /* No more files */
+#define FX_FOP -9 /* Forbidden operation */
+#define FX_ACC -10 /* Access denied */
+#define FX_BOM -11 /* Bad combination of open modes */
+#define FX_OFL -12 /* Buffer overflow */
+#define FX_LNU -13 /* Current line number unknown */
+#define FX_ROO -14 /* Set Root violation */
+#define FX_NYI -99 /* Feature not implemented yet */
+#define FX_UNK -999 /* Unknown error */
+
+_PROTOTYP( int z_open, (char *, int) );
+_PROTOTYP( int z_close, (int) );
+_PROTOTYP( int z_out, (int, char *, int, int) );
+_PROTOTYP( int z_in, (int, char *, int, int, int) );
+_PROTOTYP( int z_flush, (int) );
+_PROTOTYP( int z_seek, (int, CK_OFF_T) );
+_PROTOTYP( int z_line, (int, CK_OFF_T) );
+_PROTOTYP( int z_getmode, (int) );
+_PROTOTYP( int z_getfnum, (int) );
+_PROTOTYP( CK_OFF_T z_getpos, (int) );
+_PROTOTYP( CK_OFF_T z_getline, (int) );
+_PROTOTYP( CK_OFF_T z_count, (int, int) );
+_PROTOTYP( char * z_getname, (int) );
+_PROTOTYP( char * ckferror, (int) );
+#endif /* CKCHANNELIO */
+
+_PROTOTYP( int scanfile, (char *, int *, int) );
+_PROTOTYP( int scanstring, (char *) );
+
+/* Buffered file i/o ... */
+#ifdef OS2 /* K-95 */
+#define INBUFSIZE 32768
+#define OBUFSIZE 32768
+#else
+#ifdef pdp11
+#define INBUFSIZE 512
+#define OBUFSIZE 512
+#else
+/* In VMS, allow for longest possible RMS record */
+#ifdef VMS
+#define INBUFSIZE 32768 /* File input buffer size */
+#define OBUFSIZE 32768 /* File output buffer size */
+#else /* Not VMS */
+#ifdef STRATUS
+#ifdef DYNAMIC
+#define INBUFSIZE 32767 /* File input buffer size */
+#define OBUFSIZE 32767 /* File output buffer size */
+#else /* STRATUS, not DYNAMIC */
+#define INBUFSIZE 4096 /* File input buffer size */
+#define OBUFSIZE 4096 /* File output buffer size */
+#endif /* DYNAMIC */
+#else /* not STRATUS */
+#ifdef BIGBUFOK /* Systems where memory is */
+#define INBUFSIZE 32768 /* not a problem... */
+#define OBUFSIZE 32768
+#else /* Not BIGBUFOK */
+#define INBUFSIZE 1024
+#define OBUFSIZE 1024
+#endif /* BIGBUFOK */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* pdp11 */
+#endif /* OS2 */
+
+/* File-transfer character in/out macros for buffered i/o */
+
+/* Get the next file byte */
+#ifndef CKCMAI
+#ifndef NOXFER
+extern char ** sndarray;
+#endif /* NOXFER */
+#endif /* CKCMAI */
+#ifdef NOSPL
+#define zminchar() (((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill())
+#else
+#ifdef NOXFER
+#define zminchar() (((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill())
+#else
+#define zminchar() \
+(sndarray?agnbyte():(((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill()))
+#endif /* NOXFER */
+#endif /* NOSPL */
+
+/* Stuff a character into the input buffer */
+#define zmstuff(c) zinptr--, *zinptr = c, zincnt++
+
+/* Put a character to a file */
+#define zmchout(c) \
+((*zoutptr++=(char)(c)),(((++zoutcnt)>=zobufsize)?zoutdump():0))
+
+/* Screen functions */
+
+#define XYFD_N 0 /* File transfer display: None, Off */
+#define XYFD_R 1 /* Regular, Dots */
+#define XYFD_C 2 /* Cursor-positioning (e.g. curses) */
+#define XYFD_S 3 /* CRT Screen */
+#define XYFD_B 4 /* Brief */
+#define XYFD_G 5 /* GUI */
+
+#ifdef NODISPLAY
+#define xxscreen(a,b,c,d)
+#define ckscreen(a,b,c,d)
+#else
+_PROTOTYP( VOID ckscreen, (int, char, CK_OFF_T, char *) );
+#ifdef VMS
+#define xxscreen(a,b,c,d) \
+if (local && fdispla != XYFD_N) \
+ckscreen((int)a,(char)b,(CK_OFF_T)c,(char *)d)
+#else
+#define xxscreen(a,b,c,d) \
+if (local && !backgrd && fdispla != XYFD_N) \
+ckscreen((int)a,(char)b,(CK_OFF_T)c,(char *)d)
+#endif /* VMS */
+#endif /* NODISPLAY */
+
+#define SCR_FN 1 /* filename */
+#define SCR_AN 2 /* as-name */
+#define SCR_FS 3 /* file-size */
+#define SCR_XD 4 /* x-packet data */
+#define SCR_ST 5 /* File status: */
+#define ST_OK 0 /* Transferred OK */
+#define ST_DISC 1 /* Discarded */
+#define ST_INT 2 /* Interrupted */
+#define ST_SKIP 3 /* Skipped */
+#define ST_ERR 4 /* Fatal Error */
+#define ST_REFU 5 /* Refused (use Attribute codes for reason) */
+#define ST_INC 6 /* Incompletely received */
+#define ST_MSG 7 /* Informational message */
+#define ST_SIM 8 /* Transfer simulated (e.g. would be sent) */
+#define SCR_PN 6 /* packet number */
+#define SCR_PT 7 /* packet type or pseudotype */
+#define SCR_TC 8 /* transaction complete */
+#define SCR_EM 9 /* error message */
+#define SCR_WM 10 /* warning message */
+#define SCR_TU 11 /* arbitrary undelimited text */
+#define SCR_TN 12 /* arbitrary new text, delimited at beginning */
+#define SCR_TZ 13 /* arbitrary text, delimited at end */
+#define SCR_QE 14 /* quantity equals (e.g. "foo: 7") */
+#define SCR_CW 15 /* close screen window */
+#define SCR_CD 16 /* display current directory */
+#define SCR_MS 17 /* message from client */
+
+/* Skip reasons */
+
+#define SKP_DAT 1 /* Date-Time (Older) */
+#define SKP_EQU 2 /* Date-Time (Equal) */
+#define SKP_TYP 3 /* Type */
+#define SKP_SIZ 4 /* Size */
+#define SKP_NAM 5 /* Name collision */
+#define SKP_EXL 6 /* Exception list */
+#define SKP_DOT 7 /* Dot file */
+#define SKP_BKU 8 /* Backup file */
+#define SKP_RES 9 /* Recovery not needed */
+#define SKP_ACC 10 /* Access denied */
+#define SKP_NRF 11 /* Not a regular file */
+#define SKP_SIM 12 /* Simulation (WOULD BE SENT) */
+#define SKP_XUP 13 /* Simulation: Would be sent because remote file older */
+#define SKP_XNX 14 /* Simulation: ditto, because remote file does not exist */
+
+/* Macros */
+
+#ifndef CKCMAI
+extern int tcp_incoming; /* Used by ENABLE macro */
+#endif /* CKCMAI */
+
+#ifndef TCPSOCKET
+/*
+ ENABLED tells whether a server-side service is enabled.
+ 0 = disabled, 1 = local, 2 = remote.
+ A "set host *" connection is technically local but logically remote
+*/
+#define ENABLED(x) ((local && (x & 1)) || (!local && (x & 2)))
+#else
+#define ENABLED(x) (((local && !tcp_incoming) && (x & 1)) || \
+((!local || tcp_incoming) && (x&2)))
+#endif /* TCPSOCKET */
+
+/* These are from the book */
+
+#define tochar(ch) (((ch) + SP ) & 0xFF ) /* Number to character */
+#define xunchar(ch) (((ch) - SP ) & 0xFF ) /* Character to number */
+#define ctl(ch) (((ch) ^ 64 ) & 0xFF ) /* Control/Uncontrol toggle */
+#define unpar(ch) (((ch) & 127) & 0xFF ) /* Clear parity bit */
+
+#ifndef NOLOCAL /* CONNECT return status codes */
+
+/* Users will see the numbers so they can't be changed */
+/* Numbers >= 100 indicate connection loss */
+
+#define CSX_NONE 0 /* No CONNECT yet so no status */
+#define CSX_ESCAPE 1 /* User Escaped back */
+#define CSX_TRIGGER 2 /* Trigger was encountered */
+#define CSX_IKSD 3 /* IKSD autosynchronization */
+#define CSX_APC 4 /* Application Program Command */
+#define CSX_IDLE 5 /* Idle limit exceeded */
+#define CSX_TN_ERR 6 /* Telnet Error */
+#define CSX_MACRO 7 /* Macro bound to keystroke */
+#define CSX_TIME 8 /* Time Limit exceeded */
+#define CSX_INTERNAL 100 /* Internal error */
+#define CSX_CARRIER 101 /* Carrier required but not detected */
+#define CSX_IOERROR 102 /* I/O error on connection */
+#define CSX_HOSTDISC 103 /* Disconnected by host */
+#define CSX_USERDISC 104 /* Disconnected by user */
+#define CSX_SESSION 105 /* Session Limit exceeded */
+#define CSX_TN_POL 106 /* Rejected due to Telnet Policy */
+#define CSX_KILL_SIG 107 /* Received Kill Signal */
+
+/* SET TERMINAL IDLE-ACTION values */
+
+#define IDLE_RET 0 /* Return to prompt */
+#define IDLE_EXIT 1 /* Exit from Kermit */
+#define IDLE_HANG 2 /* Hangup the connection */
+#define IDLE_OUT 3 /* OUTPUT a string */
+#define IDLE_TNOP 4 /* TELNET NOP */
+#define IDLE_TAYT 5 /* TELNET AYT */
+#endif /* NOLOCAL */
+
+/* Modem and dialing definitions */
+
+#ifndef NODIAL
+
+/* Modem capabilities (bit values) */
+#define CKD_AT 1 /* Hayes AT commands and responses */
+#define CKD_V25 2 /* V.25bis commands and responses */
+#define CKD_SB 4 /* Speed buffering */
+#define CKD_EC 8 /* Error correction */
+#define CKD_DC 16 /* Data compression */
+#define CKD_HW 32 /* Hardware flow control */
+#define CKD_SW 64 /* (Local) software flow control */
+#define CKD_KS 128 /* Kermit spoofing */
+#define CKD_TB 256 /* Made by Telebit */
+#define CKD_ID 512 /* Has Caller ID */
+
+/* DIAL command result codes */
+#define DIA_UNK -1 /* No DIAL command given yet */
+#define DIA_OK 0 /* DIAL succeeded */
+#define DIA_NOMO 1 /* Modem type not specified */
+#define DIA_NOLI 2 /* Communication line not spec'd */
+#define DIA_OPEN 3 /* Line can't be opened */
+#define DIA_NOSP 4 /* Speed not specified */
+#define DIA_HANG 5 /* Hangup failure */
+#define DIA_IE 6 /* Internal error (malloc, etc) */
+#define DIA_IO 7 /* I/O error */
+#define DIA_TIMO 8 /* Dial timeout expired */
+#define DIA_INTR 9 /* Dialing interrupted by user */
+#define DIA_NRDY 10 /* Modem not ready */
+#define DIA_PART 11 /* Partial dial command OK */
+#define DIA_DIR 12 /* Dialing directory error */
+#define DIA_HUP 13 /* Modem was hung up OK */
+#define DIA_NRSP 19 /* No response from modem */
+#define DIA_ERR 20 /* Modem command error */
+#define DIA_NOIN 21 /* Failure to initialize modem */
+#define DIA_BUSY 22 /* Phone busy */
+#define DIA_NOCA 23 /* No carrier */
+#define DIA_NODT 24 /* No dialtone */
+#define DIA_RING 25 /* Ring, incoming call */
+#define DIA_NOAN 26 /* No answer */
+#define DIA_DISC 27 /* Disconnected */
+#define DIA_VOIC 28 /* Answered by voice */
+#define DIA_NOAC 29 /* Access denied, forbidden call */
+#define DIA_BLCK 30 /* Blacklisted */
+#define DIA_DELA 31 /* Delayed */
+#define DIA_FAX 32 /* Fax */
+#define DIA_DIGI 33 /* Digital Line */
+#define DIA_TAPI 34 /* TAPI dialing failure */
+#define DIA_UERR 98 /* Unknown error */
+#define DIA_UNSP 99 /* Unspecified failure detected by modem */
+
+#define MDMINF struct mdminf
+
+MDMINF { /* Structure for modem-specific information */
+
+ char * name; /* Descriptive name */
+ char * pulse; /* Command to force pulse dialing */
+ char * tone; /* Command to force tone dialing */
+ int dial_time; /* Time modem allows for dialing (secs) */
+ char * pause_chars; /* Character(s) to tell modem to pause */
+ int pause_time; /* Time associated with pause chars (secs) */
+ char * wake_str; /* String to wakeup modem & put in cmd mode */
+ int wake_rate; /* Delay between wake_str characters (msecs) */
+ char * wake_prompt; /* String prompt after wake_str */
+ char * dmode_str; /* String to put modem in dialing mode */
+ char * dmode_prompt; /* String prompt for dialing mode */
+ char * dial_str; /* Dialing string, with "%s" for number */
+ int dial_rate; /* Interchar delay to modem (msec) */
+ int esc_time; /* Escape sequence guard time (msec) */
+ int esc_char; /* Escape character */
+ char * hup_str; /* Hangup string */
+ char * hwfc_str; /* Hardware flow control string */
+ char * swfc_str; /* Software flow control string */
+ char * nofc_str; /* No flow control string */
+ char * ec_on_str; /* Error correction on string */
+ char * ec_off_str; /* Error correction off string */
+ char * dc_on_str; /* Data compression on string */
+ char * dc_off_str; /* Data compression off string */
+ char * aa_on_str; /* Autoanswer on string */
+ char * aa_off_str; /* Autoanswer off string */
+ char * sb_on_str; /* Speed buffering on string */
+ char * sb_off_str; /* Speed buffering off string */
+ char * sp_on_str; /* Speaker on string */
+ char * sp_off_str; /* Speaker off string */
+ char * vol1_str; /* Volume low string */
+ char * vol2_str; /* Volume med string */
+ char * vol3_str; /* Volume high string */
+ char * ignoredt; /* Ignore dialtone string */
+ char * ini2; /* Last-minute init string */
+ long max_speed; /* Maximum interface speed */
+ long capas; /* Capability bits */
+ /* function to read modem's response string to a non-dialing command */
+ _PROTOTYP( int (*ok_fn), (int,int) );
+};
+#endif /* NODIAL */
+
+/* Symbols for File Attributes */
+
+#define AT_XALL 0 /* All of them */
+#define AT_ALLY 1 /* All of them on (Yes) */
+#define AT_ALLN 2 /* All of them off (no) */
+#define AT_LENK 3 /* Length in K */
+#define AT_FTYP 4 /* File Type */
+#define AT_DATE 5 /* Creation date */
+#define AT_CREA 6 /* Creator */
+#define AT_ACCT 7 /* Account */
+#define AT_AREA 8 /* Area */
+#define AT_PSWD 9 /* Password for area */
+#define AT_BLKS 10 /* Blocksize */
+#define AT_ACCE 11 /* Access */
+#define AT_ENCO 12 /* Encoding */
+#define AT_DISP 13 /* Disposition */
+#define AT_LPRO 14 /* Local Protection */
+#define AT_GPRO 15 /* Generic Protection */
+#define AT_SYSI 16 /* System ID */
+#define AT_RECF 17 /* Record Format */
+#define AT_SYSP 18 /* System-Dependent Parameters */
+#define AT_LENB 19 /* Length in Bytes */
+#define AT_EOA 20 /* End of Attributes */
+
+/* Kermit packet information structure */
+
+struct pktinfo { /* Packet information structure */
+ CHAR *bf_adr; /* buffer address */
+ int bf_len; /* buffer length */
+ CHAR *pk_adr; /* Packet address within buffer */
+ int pk_len; /* length of data within buffer */
+ int pk_typ; /* packet type */
+ int pk_seq; /* packet sequence number */
+ int pk_rtr; /* retransmission count */
+};
+
+/* Send Modes (indicating which type of SEND command was used) */
+
+#define SM_SEND 0
+#define SM_MSEND 1
+#define SM_RESEND 2
+#define SM_PSEND 3
+#define SM_MAIL 4
+#define SM_PRINT 5
+
+#define OPTBUFLEN 256
+
+/* File-related symbols and structures */
+/* Used by SET FILE command but also by protocol and i/o modules */
+
+#define XMODE_A 0 /* Transfer mode Automatic */
+#define XMODE_M 1 /* Transfer mode Manual */
+
+#define XYFILN 0 /* Naming */
+#define XYFN_L 0 /* Literal */
+#define XYFN_C 1 /* Converted */
+#define XYFILT 1 /* Type */
+#define XYFT_T 0 /* Text */
+#define XYFT_B 1 /* Binary */
+#define XYFT_I 2 /* Image or Block (VMS) */
+#define XYFT_L 3 /* Labeled (tagged binary) (VMS or OS/2) */
+#define XYFT_U 4 /* Binary Undefined (VMS) */
+#define XYFT_M 5 /* MacBinary (Macintosh) */
+#define XYFT_X 6 /* TENEX (FTP TYPE L 8) */
+#define XYFT_D 99 /* Debug (for session logs) */
+#define XYFILW 2 /* Warning */
+#define XYFILD 3 /* Display */
+#define XYFILC 4 /* Character set */
+#define XYFILF 5 /* Record Format */
+#define XYFF_S 0 /* Stream */
+#define XYFF_V 1 /* Variable */
+#define XYFF_VB 2 /* Variable with RCW's */
+#define XYFF_F 3 /* Fixed length */
+#define XYFF_U 4 /* Undefined */
+#define XYFILR 6 /* Record length */
+#define XYFILO 7 /* Organization */
+#define XYFO_S 0 /* Sequential */
+#define XYFO_I 1 /* Indexed */
+#define XYFO_R 2 /* Relative */
+#define XYFILP 8 /* Printer carriage control */
+#define XYFP_N 0 /* Newline (imbedded control characters) */
+#define XYFP_F 1 /* FORTRAN (space, 1, +, etc, in column 1 */
+#define XYFP_P 2 /* Special printer carriage controls */
+#define XYFP_X 4 /* None */
+#define XYFILX 9 /* Collision Action */
+#define XYFX_A 3 /* Append */
+#define XYFX_Q 5 /* Ask */
+#define XYFX_B 2 /* Backup */
+#define XYFX_D 4 /* Discard */
+#define XYFX_R 0 /* Rename */
+#define XYFX_X 1 /* Replace */
+#define XYFX_U 6 /* Update */
+#define XYFX_M 7 /* Modtimes differ */
+#define XYFILB 10 /* Blocksize */
+#define XYFILZ 11 /* Disposition */
+#define XYFZ_N 0 /* New, Create */
+#define XYFZ_A 1 /* New, append if file exists, else create */
+#define XYFZ_O 2 /* Old, file must exist */
+#define XYFILS 12 /* File Byte Size */
+#define XYFILL 13 /* File Label (VMS) */
+#define XYFILI 14 /* File Incomplete */
+#define XYFILQ 15 /* File path action (strip or not) */
+#define XYFILG 16 /* File download directory */
+#define XYFILA 17 /* Line terminator for local text files */
+#define XYFA_L 012 /* LF (as in UNIX) */
+#define XYFA_C 015 /* CR (as in OS-9 or Mac OS) */
+#define XYFA_2 000 /* CRLF -- Note: this must be defined as 0 */
+#define XYFILY 18 /* Destination */
+#define XYFILV 19 /* EOF Detection Method */
+#define XYEOF_L 0 /* File length */
+#define XYEOF_Z 1 /* Ctrl-Z in file */
+#define XYFILH 20 /* OUTPUT parameters - buffered, blocking, etc */
+#define XYFIBP 21 /* BINARY-PATTERN */
+#define XYFITP 22 /* TEXT-PATTERN */
+#define XYFIPA 23 /* PATTERNS ON/OFF */
+#define XYFILU 24 /* UCS ... */
+#define XYF_PRM 25 /* PERMISSIONS, PROTECTION */
+#define XYF_INSP 26 /* INSPECTION (SCAN) */
+#define XYF_DFLT 27 /* DEFAULT (character sets) */
+#define XYF_SSPA 28 /* STRINGSPACE */
+#define XYF_LSIZ 29 /* LISTSIZE */
+
+/* File Type (return code) definitions and corresponding name strings */
+
+#define FT_7BIT 0 /* 7-bit text */
+#define FT_8BIT 1 /* 8-bit text */
+#define FT_UTF8 2 /* UTF8 */
+#define FT_UCS2 3 /* UCS2 */
+#define FT_TEXT 4 /* Unknown text */
+#define FT_BIN 5 /* Binary */
+#define SCANFILEBUF 49152 /* Size of file scan (48K) */
+
+/* Connection closed reasons */
+
+#define WC_REMO 0 /* Closed by remote */
+#define WC_CLOS 1 /* Closed from our end */
+#define WC_TELOPT 2 /* Telnet negotiation failure */
+
+#ifdef BIGBUFOK
+#define FTPATTERNS 256
+#else
+#define FTPATTERNS 64
+#endif /* BIGBUFOK */
+
+#define SYS_UNK 0 /* Selected server system types */
+#define SYS_UNIX 1
+#define SYS_WIN32 2
+#define SYS_VMS 3
+#define SYS_OS2 4
+#define SYS_DOS 5
+#define SYS_TOPS10 6
+#define SYS_TOPS20 7
+#define SYS_VOS 8
+#define SYS_DG 9
+#define SYS_OSK 10
+#define SYS_MAX 11
+
+#ifdef CK_SMALL
+#define PWBUFL 63
+#else
+#define PWBUFL 255
+#endif /* CK_SMALL */
+
+#ifdef OS2
+struct tt_info_rec { /* Terminal emulation info */
+ char *x_name;
+ char *x_aliases[4];
+ char *x_id;
+};
+#endif /* OS2 */
+
+/* BEEP TYPES */
+#define BP_BEL 0 /* Terminal bell */
+#define BP_NOTE 1 /* Info */
+#define BP_WARN 2 /* Warning */
+#define BP_FAIL 3 /* Error */
+
+#ifndef NOIKSD
+#ifdef IKSDB /* IKSD Database definitions */
+
+/* Field values */
+
+#define DBF_INUSE 1 /* Flag bits... In use */
+#define DBF_USER 2 /* Real user (versus anonymous) */
+#define DBF_LOGGED 4 /* Logged in (versus not) */
+
+/* Data Definitions... */
+
+/* Numeric fields, hex, right justified, 0-filled on left */
+
+#define db_FLAGS 0 /* Field 0: Flags */
+#define DB_FLAGS 0 /* Offset: 0 */
+#define dB_FLAGS 4 /* Length: 4 (hex digits) */
+
+#define db_ATYPE 1 /* Field 1: Authentication type */
+#define DB_ATYPE 4 /* 4 hex digits */
+#define dB_ATYPE 4
+
+#define db_AMODE 2 /* Field 2: Authentication mode */
+#define DB_AMODE 8 /* 4 hex digits */
+#define dB_AMODE 4
+
+#define db_STATE 3 /* Field 3: State - 4 hex digits*/
+#define DB_STATE 12 /* 4 hex digits */
+#define dB_STATE 4
+
+#define db_MYPID 4 /* Field 4: My PID */
+#define DB_MYPID 16 /* 16 hex digits left padded with 0 */
+#define dB_MYPID 16
+
+#define db_SADDR 5 /* Field 5: Server (my) IP address */
+#define DB_SADDR 32 /* 16 hex digits left padded with 0 */
+#define dB_SADDR 16
+
+#define db_CADDR 6 /* Field 6: Client IP address */
+#define DB_CADDR 48 /* 16 hex digits left padded with 0 */
+#define dB_CADDR 16
+
+/* Date-time fields (17 right-adjusted in 18 for Y10K readiness) */
+
+#define db_START 7 /* Field 7: Session start date-time */
+#define DB_START 65 /* 64 is leading space for Y10K */
+#define dB_START 17
+
+#define db_LASTU 8 /* Field 8: Last lastu date-time */
+#define DB_LASTU 83 /* 82 is leading space for Y10K */
+#define dB_LASTU 17
+
+#define db_ULEN 9 /* Field 9: Length of Username */
+#define DB_ULEN 100 /* 4 hex digits */
+#define dB_ULEN 4
+
+#define db_DLEN 10 /* Field 10: Length of Directory */
+#define DB_DLEN 104 /* 4 hex digits */
+#define dB_DLEN 4
+
+#define db_ILEN 11 /* Field 11: Length of Info */
+#define DB_ILEN 108 /* 4 hex digits */
+#define dB_ILEN 4
+
+#define db_PAD1 12 /* Field 12: (Reserved) */
+#define DB_PAD1 112 /* filled with spaces */
+#define dB_PAD1 912
+
+/* String fields, all right-padded with blanks */
+
+#define db_USER 13 /* Field 13: Username */
+#define DB_USER 1024 /* right-padded with spaces */
+#define dB_USER 1024
+
+#define db_DIR 14 /* Field 14: Current directory */
+#define DB_DIR 2048 /* right-padded with spaces */
+#define dB_DIR 1024
+
+#define db_INFO 15 /* Field 15: State-specific info */
+#define DB_INFO 3072 /* right-padded with spaces */
+#define dB_INFO 1024
+
+#define DB_RECL 4096 /* Database record length */
+
+/* Offset, length, and type of each field thru its db_XXX symbol */
+
+#define DBT_HEX 1 /* Hexadecimal number */
+#define DBT_STR 2 /* String */
+#define DBT_DAT 3 /* Date-Time yyyymmdd hh:mm:ss */
+#define DBT_UND 9 /* Undefined and blank */
+
+struct iksdbfld {
+ int off; /* Position (offset) */
+ int len; /* Length (bytes) */
+ int typ; /* Data type */
+};
+_PROTOTYP(int dbinit, (void));
+_PROTOTYP(int initslot, (int));
+_PROTOTYP(int getslot, (void));
+_PROTOTYP(int freeslot, (int));
+_PROTOTYP(int updslot, (int));
+_PROTOTYP(int slotstate, (int, char *, char *, char *));
+_PROTOTYP(int slotdir, (char *, char *));
+#endif /* IKSDB */
+#endif /* NOIKSD */
+
+/* ANSI forward declarations for protocol-related functions. */
+
+_PROTOTYP( int input, (void) );
+_PROTOTYP( int inibufs, (int, int) );
+_PROTOTYP( int makebuf, (int, int, CHAR [], struct pktinfo *) );
+_PROTOTYP( int mksbuf, (int) );
+_PROTOTYP( int mkrbuf, (int) );
+_PROTOTYP( int spack, (char, int, int, CHAR *) );
+_PROTOTYP( VOID proto, (void) );
+_PROTOTYP( int rpack, (void) );
+_PROTOTYP( int ack, (void) );
+_PROTOTYP( int nack, (int) );
+_PROTOTYP( int ackn, (int) );
+_PROTOTYP( int ack1, (CHAR *) );
+_PROTOTYP( int ackns, (int, CHAR *) );
+#ifdef STREAMING
+_PROTOTYP( int fastack, (void) );
+#endif /* STREAMING */
+_PROTOTYP( int resend, (int) );
+_PROTOTYP( int errpkt, (CHAR *) );
+_PROTOTYP( VOID logpkt, (char, int, CHAR *, int) );
+_PROTOTYP( CHAR dopar, (CHAR) );
+_PROTOTYP( int chk1, (CHAR *, int) );
+_PROTOTYP( unsigned int chk2, (CHAR *, int) );
+_PROTOTYP( unsigned int chk3, (CHAR *, int) );
+_PROTOTYP( int sipkt, (char) );
+_PROTOTYP( int sopkt, (void) );
+_PROTOTYP( int sinit, (void) );
+_PROTOTYP( VOID rinit, (CHAR *) );
+_PROTOTYP( int spar, (CHAR *) );
+_PROTOTYP( int rcvfil, (char *) );
+_PROTOTYP( CHAR * rpar, (void) );
+_PROTOTYP( int gnfile, (void) );
+_PROTOTYP( int getsbuf, (int) );
+_PROTOTYP( int getrbuf, (void) );
+_PROTOTYP( int freesbuf, (int) );
+_PROTOTYP( int freerbuf, (int) );
+_PROTOTYP( int dumpsbuf, (void) );
+_PROTOTYP( int dumprbuf, (void) );
+_PROTOTYP( VOID freerpkt, (int) );
+_PROTOTYP( int chkwin, (int, int, int) );
+_PROTOTYP( int rsattr, (CHAR *) );
+_PROTOTYP( char *getreason, (char *) );
+_PROTOTYP( int scmd, (char, CHAR *) );
+_PROTOTYP( int encstr, (CHAR *) );
+_PROTOTYP( int decode, (CHAR *, int (*)(char), int) );
+_PROTOTYP( int bdecode, (CHAR *, int (*)(char)) );
+_PROTOTYP( int fnparse, (char *) );
+_PROTOTYP( int syscmd, (char *, char *) );
+_PROTOTYP( int cwd, (char *) );
+_PROTOTYP( int remset, (char *) );
+_PROTOTYP( int initattr, (struct zattr *) );
+_PROTOTYP( int gattr, (CHAR *, struct zattr *) );
+_PROTOTYP( int adebu, (char *, struct zattr *) );
+_PROTOTYP( int canned, (CHAR *) );
+_PROTOTYP( int opent, (struct zattr *) );
+_PROTOTYP( int ckopenx, (struct zattr *) );
+_PROTOTYP( int opena, (char *, struct zattr *) );
+_PROTOTYP( int openi, (char *) );
+_PROTOTYP( int openo, (char *, struct zattr *, struct filinfo *) );
+_PROTOTYP( int openc, (int, char *) );
+_PROTOTYP( int reof, (char *, struct zattr *) );
+_PROTOTYP( VOID reot, (void) );
+_PROTOTYP( int sfile, (int) );
+_PROTOTYP( int sattr, (int, int) );
+_PROTOTYP( int sdata, (void) );
+_PROTOTYP( int seof, (int) );
+_PROTOTYP( int sxeof, (int) );
+_PROTOTYP( int seot, (void) );
+_PROTOTYP( int window, (int) );
+_PROTOTYP( int clsif, (void) );
+_PROTOTYP( int clsof, (int) );
+_PROTOTYP( CHAR setgen, (char, char *, char *, char *) );
+_PROTOTYP( int getpkt, (int, int) );
+_PROTOTYP( int maxdata, (void) );
+_PROTOTYP( int putsrv, (char) );
+_PROTOTYP( int puttrm, (char) );
+_PROTOTYP( int putque, (char) );
+_PROTOTYP( int putfil, (char) );
+_PROTOTYP( int putmfil, (char) );
+_PROTOTYP( int zputfil, (char) );
+_PROTOTYP( VOID zdstuff, (CHAR) );
+_PROTOTYP( int tinit, (int) );
+_PROTOTYP( VOID pktinit, (void) );
+_PROTOTYP( VOID resetc, (void) );
+_PROTOTYP( VOID xsinit, (void) );
+_PROTOTYP( int adjpkl, (int,int,int) );
+_PROTOTYP( int chktimo, (int,int) );
+_PROTOTYP( int nxtpkt, (void) );
+_PROTOTYP( VOID rcalcpsz, (void) );
+_PROTOTYP( int srinit, (int, int, int) );
+_PROTOTYP( VOID tstats, (void) );
+_PROTOTYP( VOID fstats, (void) );
+_PROTOTYP( VOID intmsg, (long) );
+_PROTOTYP( VOID ermsg, (char *) );
+_PROTOTYP( int chkint, (void) );
+_PROTOTYP( VOID sdebu, (int) );
+_PROTOTYP( VOID rdebu, (CHAR *, int) );
+_PROTOTYP( char * dbchr, ( int ) );
+#ifdef COMMENT
+_PROTOTYP( SIGTYP stptrap, (int, int) );
+_PROTOTYP( SIGTYP trap, (int, int) );
+#else
+_PROTOTYP( SIGTYP stptrap, (int) );
+_PROTOTYP( SIGTYP trap, (int) );
+#endif /* COMMENT */
+_PROTOTYP( char * ck_errstr, (void) );
+#ifndef NOXFER
+_PROTOTYP( int agnbyte, (void) );
+#endif /* NOXFER */
+_PROTOTYP( int xgnbyte, (int, int, int (*)(void)) );
+_PROTOTYP( int xpnbyte, (int, int, int, int (*)(char)) );
+
+/* User interface functions needed by main program, etc. */
+
+_PROTOTYP( int doconect, (int,int) );
+_PROTOTYP( VOID setflow, (void) );
+_PROTOTYP( VOID prescan, (int) );
+_PROTOTYP( VOID setint, (void) );
+_PROTOTYP( VOID doinit, (void) );
+_PROTOTYP( VOID dofast, (void) );
+_PROTOTYP( VOID cmdini, (void) );
+_PROTOTYP( int dotake, (char *) );
+_PROTOTYP( int cmdlin, (void) );
+#ifdef OS2
+_PROTOTYP( int conect, (int) );
+#else /* OS2 */
+_PROTOTYP( int conect, (void) );
+#endif /* OS2 */
+_PROTOTYP( int ckcgetc, (int) );
+_PROTOTYP( int ckcputc, (int) );
+_PROTOTYP (int mdmhup, (void) );
+_PROTOTYP( VOID herald, (void) );
+_PROTOTYP( VOID fixcmd, (void) );
+_PROTOTYP( int doarg, (char) );
+_PROTOTYP( int doxarg, (char **, int) );
+_PROTOTYP( VOID usage, (void) );
+_PROTOTYP( VOID doclean, (int) );
+_PROTOTYP( int sndhlp, (void) );
+_PROTOTYP( int sndstring, (char *) );
+_PROTOTYP( VOID ckhost, (char *, int) );
+_PROTOTYP( int gettcs, (int, int) );
+_PROTOTYP( VOID getdialenv, (void) );
+_PROTOTYP( VOID setprefix, (int) );
+_PROTOTYP(VOID initproto,(int,char *,char *,char *,char *,char *,char*,char*));
+_PROTOTYP( VOID initpat, (void) );
+_PROTOTYP( VOID initcsets, (void) );
+_PROTOTYP( char * getsysid, (char *) );
+_PROTOTYP( int getsysix, (char *) );
+#ifdef CK_TIMERS
+_PROTOTYP( VOID rttinit, (void) );
+_PROTOTYP( int getrtt, (int, int) );
+#endif /* CK_TIMERS */
+
+_PROTOTYP( int is_a_tty, (int) );
+_PROTOTYP( int snddir, (char *) );
+_PROTOTYP( int snddel, (char *) );
+_PROTOTYP( int sndtype, (char *) );
+_PROTOTYP( int dooutput, (char *, int) );
+_PROTOTYP( int isabsolute, (char *) );
+_PROTOTYP( VOID whoarewe, (void) );
+_PROTOTYP( int ckmkdir, (int, char *, char **, int, int) );
+_PROTOTYP( int autoexitchk, (CHAR) );
+_PROTOTYP( VOID fcps, (void) );
+#ifdef OS2
+_PROTOTYP( VOID logchar, (unsigned short) );
+#else /* OS2 */
+_PROTOTYP( VOID logchar, (char) );
+#endif /* OS2 */
+_PROTOTYP( VOID logstr, (char *, int) );
+
+_PROTOTYP( VOID dologend, (void) );
+#ifdef NOLOCAL
+#define dologshow()
+#else
+_PROTOTYP( long dologshow, (int) );
+#endif /* NOLOCAL */
+
+#ifdef NODISPLAY
+#define fxdinit(a)
+#else
+_PROTOTYP( VOID fxdinit, (int) );
+#endif /* NODISPLAY */
+
+_PROTOTYP( int fileselect, (char *,
+ char *, char *, char *, char *,
+ CK_OFF_T, CK_OFF_T,
+ int, int,
+ char **) );
+_PROTOTYP( char * whoami, (void) );
+_PROTOTYP( int shoesc, (int) );
+
+#ifdef CK_APC
+_PROTOTYP( int chkspkt, (char *) );
+_PROTOTYP( int kstart, (CHAR) );
+_PROTOTYP( VOID autodown, (int));
+#ifdef CK_XYZ
+_PROTOTYP( int zstart, (CHAR) );
+#endif /* CK_XYZ */
+#ifdef OS2
+_PROTOTYP(void apc_command, (int, char*));
+#endif /* OS2 */
+#endif /* CK_APC */
+
+/* User Query data structures and functions */
+
+struct txtbox {
+ char * t_buf; /* Destination buffer address */
+ int t_len; /* Destination buffer length */
+ char * t_lbl; /* Label for this field */
+ char * t_dflt; /* Default response for this field */
+ int t_echo; /* 0 = no, 1 = yes, 2 = asterisks */
+};
+
+#define DEFAULT_UQ_TIMEOUT 0
+_PROTOTYP(int uq_ok, (char *,char *,int,char **,int) );
+_PROTOTYP(int uq_txt, (char *,char *,int,char **,char *,int,char *,int));
+_PROTOTYP(int uq_mtxt, (char *,char **,int,struct txtbox[]) );
+_PROTOTYP(int uq_file, (char *,char *,int,char **,char *,char *,int));
+
+#ifdef CK_URL
+struct urlopt {
+ char * nam;
+ char * val;
+};
+#define MAX_URL_OPTS 16
+struct urldata {
+ char * sav; /* The URL itself */
+ char * svc; /* Service */
+ char * usr; /* User */
+ char * psw; /* Password */
+ char * hos; /* Host */
+ char * por; /* Port */
+ char * pth; /* Path */
+ int nopts; /* number of options */
+ struct urlopt opt[MAX_URL_OPTS]; /* options */
+};
+_PROTOTYP(int urlparse, (char *, struct urldata *));
+#endif /* CK_URL */
+
+#endif /* CKCKER_H */
+
+/* End of ckcker.h */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckclib.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckclib.c
new file mode 100644
index 0000000..51b9f06
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckclib.c
@@ -0,0 +1,3319 @@
+char * cklibv = "C-Kermit library, 9.0.052, 29 Jun 2011";
+
+#define CKCLIB_C
+
+/* C K C L I B . C -- C-Kermit Library routines. */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1999, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ General-purpose, system/platform/compiler-independent routines for use
+ by all modules. Many are replacements for commonly used C library
+ functions that are not found on every platform, and/or that lack needed
+ functionality (e.g. caseless string search/compare) or safety features.
+
+ ckstrncpy() - Similar to strncpy() but different (see comments).
+ ckstrncat() - Similar to strncat() but different (see comments).
+ chartostr() - Converts a char to a string (self or ctrl char name).
+ ckstrchr() - Portable strchr().
+ ckstrpbrk() - Portable strpbrk().
+ cklower() - Lowercase a string (in place).
+ ckupper() - Uppercase a string (in place).
+ ckindex() - Left or right index.
+ ckstrstr() - Portable strstr().
+ ckitoa() - Converts int to string.
+ ckuitoa() - Converts unsigned int to string.
+ ckltoa() - Converts long to string.
+ ckultoa() - Converts unsigned long to string.
+ ckfstoa() - Converts off_t-type integer (long or long long) to string.
+ ckatofs() - Converts a numeric string to an off_t-type integer.
+ ckctoa() - Converts char to string.
+ ckmakmsg() - Constructs a message from 4 source strings.
+ ckmakxmsg() - Constructs a message from 12 source strings.
+ ckmatch() - Pattern matching.
+ ckmemcpy() - Portable memcpy().
+ ckrchar() - Rightmost character of a string.
+ ckstrcmp() - Possibly caseless string comparison.
+ ckstrpre() - Caseless string prefix comparison.
+ sh_sort() - Sorts an array of strings, many options.
+ brstrip() - Strips enclosing braces (and doublequotes).
+ makelist() - Splits "{{item}{item}...}" into an array.
+ makestr() - Careful malloc() front end.
+ xmakestr() - ditto (see comments).
+ ckradix() - Convert number radix (2-36).
+ b8tob64() - Convert data to base 64.
+ b64tob8() - Convert base 64 to data.
+ chknum() - Checks if string is a (possibly signed) integer.
+ rdigits() - Checks if string is composed only of decimal digits.
+ isfloat() - Checks if string is a valid floating-point number.
+ ckround() - Rounds a floating-point number to desired precision.
+ parnam() - Returns parity name string.
+ hhmmss() - Converts seconds to hh:mm:ss string.
+ lset() - Write fixed-length field left-adjusted into a record.
+ rset() - Write fixed-length field right-adjusted into a record.
+ ulongtohex() - Converts an unsigned long to a hex string.
+ hextoulong() - Converts a hex string to an unsigned long.
+ cksplit() - Splits a string into an array of words.
+ ispattern() - Tells if argument string is a pattern.
+
+ Prototypes are in ckclib.h.
+
+ Note: This module should not contain any extern declarations.
+*/
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+
+/* Public variables */
+
+int dblquo = 1; /* Nonzero if doublequotes can be used for grouping */
+
+char *
+ccntab[] = { /* Names of ASCII (C0) control characters 0-31 */
+ "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+ "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
+ "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+ "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
+};
+
+char *
+c1tab[] = { /* Names of ISO 6429 (C1) control characters 0-32 */
+ "XXX", "XXX", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
+ "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
+ "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
+ "SOS", "XXX", "SCI", "CSI", "ST", "OSC", "PM", "APC", "NBS"
+};
+
+#define RXRESULT 127
+static char rxdigits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static char rxresult[RXRESULT+1];
+
+/* C K S T R N C P Y */
+
+/*
+ Copies a NUL-terminated string into a buffer whose total length is given,
+ ensuring that the result is NUL-terminated even if it has to be truncated.
+
+ Call with:
+ dest = pointer to destination buffer
+ src = pointer to source string
+ len = length of destination buffer (the actual length, not one less).
+
+ Returns:
+ int, The number of bytes copied, 0 or more.
+
+ NOTE: This is NOT a replacement for strncpy():
+ . strncpy() does not require its source string to be NUL-terminated.
+ . strncpy() does not necessarily NUL-terminate its result.
+ . strncpy() right-pads dest with NULs if it is longer than src.
+ . strncpy() treats the length argument as the number of bytes to copy.
+ . ckstrncpy() treats the length argument as the size of the dest buffer.
+ . ckstrncpy() doesn't dump core if given NULL string pointers.
+ . ckstrncpy() returns a number.
+
+ Use ckstrncpy() when you want to:
+ . Copy an entire string into a buffer without overrun.
+ . Get the length of the string back.
+
+ Use strncpy() when you want to:
+ . Copy a piece of a string.
+*/
+int
+#ifdef CK_ANSIC
+ckstrncpy(char * dest, const char * src, int len)
+#else
+ckstrncpy(dest,src,len) char * dest, * src; int len;
+#endif /* CK_ANSIC */
+{
+ int i;
+ if (len < 1 || !src || !dest) { /* Nothing or nowhere to copy */
+ if (dest) *dest = NUL;
+ return(0);
+ }
+#ifndef NOCKSTRNCPY
+ for (i = 0; src[i] && (i < len-1); i++) /* Args OK, copy */
+ dest[i] = src[i];
+ dest[i] = NUL;
+#else
+ i = strlen(src);
+ if (i > len) i = len;
+ strncpy(dest,src,i);
+ dest[len] = NUL;
+#endif /* NOCKSTRNCPY */
+ return(i);
+}
+
+/* C K S T R N C A T */
+
+/*
+ Appends a NUL-terminated string to a buffer whose total length is given,
+ ensuring that the result is NUL-terminated even if it had to be truncated.
+
+ Call with:
+ dest = pointer to destination buffer containing a null-terminated string
+ src = pointer to null-terminated source string
+ len = length of destination buffer (the actual length, not one less).
+
+ Returns:
+ int, The number of bytes copied, 0 or more.
+*/
+int
+#ifdef CK_ANSIC
+ckstrncat(char * dest, const char * src, int len)
+#else
+ckstrncat(dest,src,len) char * dest, * src; int len;
+#endif /* CK_ANSIC */
+{
+ register int i, j;
+#ifdef NOCKSTRNCPY
+ register char * s1, * s2;
+#endif /* NOCKSTRNCPY */
+ if (len < 1 || !src || !dest) { /* Nothing or nowhere to copy */
+ if (dest) *dest = NUL;
+ return(0);
+ }
+#ifndef NOCKSTRNCPY
+ /* Args OK, copy */
+ for (i = 0, j = strlen(dest); src[i] && (i < len-j-1); i++)
+ dest[i+j] = src[i];
+ dest[i+j] = NUL;
+#else
+ j = 0;
+ s1 = dest;
+ while (*s1++) j++; /* j = strlen(dest); */
+ s1--; /* (back up over NUL) */
+
+ i = 0;
+ s2 = (char *)src;
+ while (*s2++) i++; /* i = strlen(src); */
+
+ if (i > (len-j))
+ i = len - j;
+ if (i <= 0)
+ return(0);
+
+#ifdef COMMENT
+ strncpy(&dest[j],src,i);
+#else
+ j = i; /* This should be a bit faster... */
+ s2 = (char *)src; /* depends on strcpy implementation; */
+ while ((*s1++ = *s2++) && j--) /* at least it shouldn't be slower. */
+ ;
+ dest[len-1] = NUL; /* In case of early exit. */
+#endif /* COMMENT */
+
+#endif /* NOCKSTRNCPY */
+ return(i);
+}
+
+/* C K M A K M S G */
+
+/*
+ Constructs a message from up to 4 pieces with length checking.
+ Result is always NUL terminated. Call with:
+ buf: Pointer to buffer for constructing message.
+ len: Length of buffer.
+ s1-s4: String pointers (can be NULL).
+ Returns:
+ 0: Nothing was copied.
+ n: (positive number) n bytes copied, all args copied successfully.
+ -n: n bytes were copied, destination buffer not big enough for all.
+ Also see:
+ ckmakxmsg() -- accepts 12 string args.
+ ckitoa(), ckltoa(), ckctoa(), ckitox(), etc.
+ Use ckmak[x]msg() plus ck?to?() as a safe replacement for sprintf().
+*/
+int
+#ifdef CK_ANSIC
+ckmakmsg(char * buf, int len, char *s1, char *s2, char *s3, char *s4)
+#else /* CK_ANSIC */
+ckmakmsg(buf,len,s1,s2,s3,s4) char *buf, *s1, *s2, *s3, *s4; int len;
+#endif /* CK_ANSIC */
+{
+ int i, n = 0, m = 0;
+ char *s;
+ char *p, *a[4];
+
+ if (!buf) return(n); /* No destination */
+ if (len < 1) return(n); /* No size */
+
+ s = buf; /* Point to destination */
+ a[0] = s1; a[1] = s2; a[2] = s3; a[3] = s4; /* Array of source strings */
+ for (i = 0; i < 4; i++) { /* Loop thru array */
+ p = a[i]; /* Point to this element */
+ if (p) { /* If pointer not null */
+ n = ckstrncpy(s,p,len); /* Copy safely */
+ m += n; /* Accumulate total */
+ if (p[n]) /* Didn't get whole thing? */
+ return(-m); /* return indicating buffer full */
+ len -= n; /* Deduct from space left */
+ s += n; /* Otherwise advance dest pointer */
+ }
+ }
+ return(m); /* Return total bytes copied */
+}
+
+
+/* C K M A K X M S G */
+
+/* Exactly like ckmakmsg(), but accepts 12 string arguments. */
+
+int
+#ifdef CK_ANSIC
+ckmakxmsg(char * buf, int len,
+ char *s1, char *s2, char *s3, char *s4, char *s5, char *s6,
+ char *s7, char *s8, char *s9, char *s10, char *s11, char *s12)
+#else /* CK_ANSIC */
+ckmakxmsg(buf,len,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12)
+ char *buf, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9, *s10, *s11, *s12;
+ int len;
+#endif /* CK_ANSIC */
+{
+ int i, n = 0, m = 0;
+ char *s;
+ char *p, *a[12];
+
+
+ if (!buf) return(n); /* No destination */
+ if (len < 1) return(n); /* No size */
+
+ s = buf; /* Point to destination */
+ a[0] = s1; a[1] = s2; a[2] = s3; a[3] = s4; /* Source-string array */
+ a[4] = s5; a[5] = s6; a[6] = s7; a[7] = s8;
+ a[8] = s9; a[9] = s10; a[10] = s11; a[11] = s12;
+ for (i = 0; i < 12; i++) { /* Loop thru array */
+ p = a[i]; /* Point to this element */
+ if (p) { /* If pointer not null */
+ n = ckstrncpy(s,p,len); /* Copy safely */
+ m += n; /* Accumulate total */
+ if (p[n]) /* Didn't get whole thing? */
+ return(-m); /* return indicating buffer full */
+ len -= n; /* Deduct from space left */
+ s += n; /* Otherwise advance dest pointer */
+ }
+ }
+ return(m); /* Return total bytes copied */
+}
+
+/* C H A R T O S T R */
+
+/* Converts a character to a string, interpreting controls. */
+
+char *
+chartostr(x) int x; { /* Call with char x */
+ static char buf[2]; /* Returns string pointer. */
+ if (x < 32)
+ return(ccntab[x]);
+ if (x == 127)
+ return("DEL");
+ if (x > 127 && x < 161)
+ return(c1tab[x - 128]);
+ if (x == 0xAD)
+ return("SHY");
+ buf[1] = NUL;
+ buf[0] = (unsigned)(x & 0xff);
+ return((char *)buf);
+}
+
+/* C K R C H A R */
+
+/* Returns the rightmost character of the given null-terminated string */
+
+int
+ckrchar(s) char * s; {
+ register CHAR c = '\0', *p;
+ p = (CHAR *)s;
+ if (!p) p = (CHAR *)""; /* Null pointer == empty string */
+ if (!*p) return(0);
+ while (*p) /* Crawl to end of string */
+ c = *p++;
+ return((unsigned)(c & 0xff)); /* Return final character */
+}
+
+/* C K S T R C H R */
+
+/* Replacement for strchr(), which is not universal. */
+/* Call with:
+ s = pointer to string to look in.
+ c = character to look for.
+ Returns:
+ NULL if c not found in s or upon any kind of error, or:
+ pointer to first occurrence of c in s, searching from left to right.
+*/
+char *
+#ifdef CK_ANSIC
+ckstrchr(char * s, char c)
+#else
+ckstrchr(s,c) char *s, c;
+#endif /* CK_ANSIC */
+/* ckstrchr */ {
+ if (!s)
+ return(NULL);
+ while (*s && *s != c)
+ s++;
+ return((*s == c) ? s : NULL);
+}
+
+/* C K S T R R C H R */
+
+/* Replacement for strrchr(), which is not universal. */
+/* Call with:
+ s = pointer to string to look in.
+ c = character to look for.
+ Returns:
+ NULL if c not found in s or upon any kind of error, or:
+ pointer to first occurrence of c in s, searching from right to left.
+*/
+char *
+#ifdef CK_ANSIC
+ckstrrchr(char * s, char c)
+#else
+ckstrrchr(s,c) char *s, c;
+#endif /* CK_ANSIC */
+/* ckstrchr */ {
+ char * s2 = NULL;
+ if (!s)
+ return(NULL);
+ while (*s) {
+ if (*s == c)
+ s2 = s;
+ s++;
+ }
+ return(s2);
+}
+
+
+/* C K S T R P B R K -- Portable replacement for strpbrk() */
+
+/* Returns pointer to first char in s1 that is also in s2, or NULL */
+
+char *
+ckstrpbrk(s1, s2) char * s1, * s2; {
+ char c1, c2, * s3;
+ if (!s1 || !s2) return(NULL);
+ if (!*s1 || !*s2) return(NULL);
+ while ((c1 = *s1++)) {
+ s3 = s2;
+ while ((c2 = *s3++)) {
+ if (c2 == c1)
+ return(s1-1);
+ }
+ }
+ return(NULL);
+}
+
+/* C K L O W E R -- Lowercase a string IN PLACE */
+
+/* Returns the length of the string */
+
+int
+cklower(s) char *s; {
+ int n = 0;
+ if (!s) return(0);
+ while (*s) {
+ if (isupper(*s)) *s = (char) tolower(*s);
+ s++, n++;
+ }
+ return(n);
+}
+
+/* C K U P P E R -- Uppercase a string IN PLACE */
+
+/* Returns the length of the string */
+
+int
+ckupper(s) char *s; {
+ int n = 0;
+ if (!s) return(0);
+ while (*s) {
+ if (islower(*s)) *s = (char) toupper(*s);
+ s++, n++;
+ }
+ return(n);
+}
+
+/* C K L T O A -- Long to string -- FOR DISCIPLINED USE ONLY */
+
+#define NUMBUF 1024
+static char numbuf[NUMBUF+32] = { NUL, NUL };
+static int numbp = 0;
+/*
+ ckltoa() and ckitoa() are like atol() and atoi() in the reverse direction,
+ returning a pointer to the string representation of the given number without
+ the caller having to worry about allocating or defining a buffer first.
+ They manage their own internal buffer, so successive calls return different
+ pointers. However, to keep memory consumption from growing without bound,
+ the buffer recycles itself. So after several hundred calls (depending on
+ the size of the numbers), some of the earlier pointers might well find
+ themselves referencing something different. Moral: You can't win in C.
+ Therefore, these routines are intended mainly for generating numeric strings
+ for short-term use, e.g. for passing numbers in string form as parameters to
+ functions. For long-term use, the result must be copied to a safe place.
+*/
+char *
+#ifdef CK_ANSIC
+ckltoa(long n)
+#else
+ckltoa(n) long n;
+#endif /* CK_ANSIC */
+/* ckltoa */ {
+ char buf[32]; /* Internal working buffer */
+ char * p, * s, * q;
+ int k, x, len = 0, sign = 0;
+ if (n < 0L) { /* Sign */
+ n = 0L - n;
+ sign = 1;
+ }
+ buf[31] = NUL;
+ for (k = 30; k > 0; k--) { /* Convert number to string */
+ x = n % 10L;
+ buf[k] = x + '0';
+ n = n / 10L;
+ if (!n)
+ break;
+ }
+ if (sign) buf[--k] = '-'; /* Add sign if necessary */
+ len = 31 - k;
+ if (len + numbp > NUMBUF)
+ numbp = 0;
+ p = numbuf + numbp;
+ q = p;
+ s = buf + k;
+ while ((*p++ = *s++)) ; /* Copy */
+ *p++ = NUL;
+ numbp += len+1;
+ return(q); /* Return pointer */
+}
+
+/* C K U L T O A -- Unsigned long to string */
+
+char *
+#ifdef CK_ANSIC
+ckultoa(unsigned long n)
+#else
+ckultoa(n) unsigned long n;
+#endif /* CK_ANSIC */
+/* ckultoa */ {
+ char buf[32]; /* Internal working buffer */
+ char * p, * s, * q;
+ int k, x, len = 0;
+ buf[31] = NUL;
+ for (k = 30; k > 0; k--) { /* Convert number to string */
+ x = n % 10L;
+ buf[k] = x + '0';
+ n = n / 10L;
+ if (!n)
+ break;
+ }
+ len = 31 - k;
+ if (len + numbp > NUMBUF)
+ numbp = 0;
+ p = numbuf + numbp;
+ q = p;
+ s = buf + k;
+ while ((*p++ = *s++)) ; /* Copy */
+ numbp += len+1;
+ return(q); /* Return pointer */
+}
+
+char *
+#ifdef CK_ANSIC
+ckltox(long n) /* Long int to "0x.." hex string */
+#else
+ckltox(n) long n;
+#endif /* CK_ANSIC */
+/* ckltox */ {
+ char buf[32]; /* Internal working buffer */
+ char *p, *q, *s, *bp = buf + 2;
+ int k;
+ buf[0] = '0';
+ buf[1] = 'x';
+ sprintf(bp, "%lx", n);
+ k = strlen(bp);
+ if (k&1) {
+ sprintf(bp, "0%lx", n);
+ k++;
+ }
+ k += 2; /* "0x" */
+ if (numbp + k >= NUMBUF)
+ numbp = 0;
+ p = numbuf + numbp;
+ q = p;
+ s = buf;
+ while ((*p++ = *s++)) ; /* Copy */
+ *p++ = NUL;
+ numbp += k+1;
+ return(q); /* Return pointer */
+}
+
+
+/* C K F S T O A -- File Size (or offset) to string */
+
+/* This is just like ckltoa() except for the data type of the argument. */
+/* It's mainly for printing file sizes without having to know their data */
+/* type, so we don't have to hardware "%ld" or "%lld" into printf()s. */
+/* Works for 32 or 64 bits, according to CK_OFF_T definition. */
+
+char *
+#ifdef CK_ANSIC
+ckfstoa(CK_OFF_T n)
+#else
+ckfstoa(n) CK_OFF_T n;
+#endif /* CK_ANSIC */
+/* ckfstoa */ {
+ char buf[32]; /* Internal working buffer */
+ char * p, * s, * q;
+ int k, x, len = 0, sign = 0;
+
+ if (n < (CK_OFF_T)0) { /* Sign */
+ n = (CK_OFF_T)0 - n;
+ sign = 1;
+ }
+ buf[31] = NUL; /* 2^63-1 is about 20 decimal digits */
+ for (k = 30; k > 0; k--) { /* Convert number to string */
+ x = n % (CK_OFF_T)10;
+ if (x < 0) {
+ /* x += 10; */
+ ckstrncpy(&buf[23],"OVERFLOW",32);
+ sign = 0;
+ k = 23;
+ break;
+ }
+ buf[k] = x + '0';
+ n = n / (CK_OFF_T)10;
+ if (!n)
+ break;
+ }
+ if (sign) buf[--k] = '-'; /* Add sign if necessary */
+ len = 31 - k;
+ if (len + numbp > NUMBUF)
+ numbp = 0;
+ p = numbuf + numbp;
+ q = p;
+ s = buf + k;
+ while ((*p++ = *s++)) ; /* Copy */
+ *p++ = NUL;
+ numbp += len+1;
+ return(q); /* Return pointer */
+}
+
+/* C K A T O F S -- String to File Size (or offset) */
+
+/* This is the inverse of ckfstoa(), a replacement for atol() that works */
+/* for either 32-bit or 64-bit arguments, according to CK_OFF_T definition. */
+/* Like atol(), there is no error indication. */
+
+CK_OFF_T
+#ifdef CK_ANSIC
+ckatofs(char * s)
+#else
+ckatofs(s) char * s;
+#endif /* CK_ANSIC */
+/* ckatofs */ {
+ CK_OFF_T result = (CK_OFF_T)0;
+ int minus = 0;
+ while (*s && (*s == SP || *s == HT)) s++;
+ if (*s == '+') s++;
+ if (*s == '-') {
+ minus = 1;
+ s++;
+ }
+ while (isdigit(*s)) {
+ result = (result * (CK_OFF_T)10) + (CK_OFF_T)(*s - '0');
+ s++;
+ }
+ return(minus ? -result : result);
+}
+
+/* C K I T O A -- Int to string -- FOR DISCIPLINED USE ONLY */
+
+char *
+ckitoa(n) int n; { /* See comments with ckltoa(). */
+ long nn;
+ nn = n;
+ return(ckltoa(nn));
+}
+
+
+char * /* Unsigned int to string */
+ckuitoa(n) unsigned int n; {
+ unsigned long nn;
+ nn = n;
+ return(ckultoa(nn));
+}
+
+char *
+ckitox(n) int n; { /* Int to hex */
+ long nn;
+ nn = n;
+ return(ckltox(nn));
+}
+
+char *
+#ifdef CK_ANSIC
+ckctoa(char c) /* Char to string */
+#else
+ckctoa(c) char c;
+#endif
+/* ckctoa */ {
+ static char buf[32];
+ static int current = 0;
+ if (current >= 30)
+ current = 0;
+ buf[current++] = c;
+ buf[current++] = '\0';
+ return((char *)(buf + current - 2));
+}
+
+char *
+#ifdef CK_ANSIC
+ckctox(CHAR c, int flag) /* Unsigned char to hex */
+#else
+ckctox(c, flag) CHAR c; int flag;
+#endif
+/* ckctox */ {
+ static char buf[48];
+ static int current = 0;
+ int x;
+ char h;
+ if (current > 45)
+ current = 0;
+ x = (c >> 4) & 0x0f;
+ h = rxdigits[x];
+ if (!flag && isupper(rxdigits[x]))
+ h = tolower(rxdigits[x]);
+ buf[current++] = h;
+ x = c & 0x0f;
+ h = rxdigits[x];
+ if (!flag && isupper(rxdigits[x]))
+ h = tolower(rxdigits[x]);
+ buf[current++] = h;
+ buf[current++] = '\0';
+ return((char *)(buf + current - 3));
+}
+
+/* C K I N D E X -- C-Kermit's index function */
+/*
+ We can't depend on C libraries to have one, so here is our own.
+ Call with:
+ s1 - String to look for.
+ s2 - String to look in.
+ t - Offset from right or left of s2, 0 based; -1 for rightmost char in s2.
+ r - 0 for left-to-right search, non-0 for right-to-left.
+ icase 0 for case independence, non-0 if alphabetic case matters.
+ Returns 0 if string not found, otherwise a 1-based result.
+ Also returns 0 on any kind of error, e.g. junk parameters.
+*/
+int
+ckindex(s1,s2,t,r,icase) char *s1, *s2; int t, r, icase; {
+ int len1 = 0, len2 = 0, i, j, x, ot = t; /* ot = original t */
+ char * s;
+
+ if (!s1 || !s2) return(0);
+ s = s1;
+ while (*s++) len1++; /* length of string to look for */
+ s = s2;
+ while (*s++) len2++; /* length of string to look in */
+ s = s2;
+ if (t < 0) t = len2 - 1;
+
+ j = len2 - len1; /* length difference */
+
+ if (j < 0 || (r == 0 && t > j)) /* search string is longer */
+ return(0);
+ if (r == 0) { /* Index */
+ s = s2 + t; /* Point to beginning of target */
+ for (i = 0; i <= (j - t); i++) { /* Now compare */
+ x = ckstrcmp(s1,s++,len1,icase);
+ if (!x)
+ return(i+1+t);
+ }
+ } else { /* Reverse Index */
+ i = len2 - len1; /* Where to start looking */
+ if (ot > 0) /* Figure in offset if any */
+ i -= t;
+ for (j = i; j > -1; j--) {
+ if (!ckstrcmp(s1,&s2[j],len1,icase))
+ return(j+1);
+ }
+ }
+ return(0);
+}
+
+/* C K S T R S T R -- Portable replacement for strstr() */
+
+/* Returns pointer to first occurrence of s1 in s2, or NULL */
+
+char *
+ckstrstr(s1, s2) char * s1, * s2; {
+ int k;
+ k = ckindex(s2,s1,0,0,1);
+ return((k < 1) ? NULL : &s1[k-1]);
+}
+
+
+/* B R S T R I P -- Strip enclosing braces from arg string, in place. */
+/*
+ Call with:
+ Pointer to string that can be poked.
+ Returns:
+ Pointer to string without enclosing braces.
+ If original string was not braced, this is the arg pointer;
+ otherwise it is 1 + the arg pointer, with the matching closing
+ brace zero'd out. If the string starts with a brace but does
+ not end with a matching brace, the original pointer to the original
+ string is returned. If the arg pointer is NULL, a pointer to an
+ empty string is returned.
+*/
+#ifdef COMMENT
+
+/* This is the original version, handling only braces */
+
+char *
+brstrip(p) char *p; {
+ if (!p) return("");
+ if (*p == '{') {
+ int x;
+ x = (int)strlen(p) - 1;
+ if (p[x] == '}') {
+ p[x] = NUL;
+ p++;
+ }
+ }
+ return(p);
+}
+
+#else
+/* New version handles braces and doublequotes */
+/* WARNING: this function writes into its argument, it always has. */
+
+char *
+brstrip(p) char *p; {
+ if (!p) return("");
+ if (*p == '{' || (*p == '"' && dblquo)) {
+ int x;
+ x = (int)strlen(p) - 1;
+ if (x > 0) {
+ if ((*p == '{' && p[x] == '}') ||
+ (*p == '"' && p[x] == '"')) {
+ if (x > 0 && p[x-1] != CMDQ) {
+ p[x] = NUL;
+ p++;
+ }
+ }
+ }
+ }
+ return(p);
+}
+#endif /* COMMENT */
+
+#ifdef COMMENT
+
+/* Even newer experimental version -- breaks many things */
+
+char *
+fnstrip(p) char *p; {
+ int i, j, k, n, len;
+ extern int cmd_quoting; /* Bad - no externs allowed! */
+
+ if (!p)
+ return("");
+
+ if (*p == '{') {
+ len = strlen(p);
+ n = 0;
+
+ for (j = 0; j < len; j++ ) {
+ if (p[j] == '{' &&
+ (!cmd_quoting || j == 0 || p[j-1] != CMDQ)) {
+ for (n = 1, i = j+1; i < len; i++ ) {
+ if (p[i] == '{' && (!cmd_quoting || p[i-1] != CMDQ))
+ n++;
+ else if (p[i] == '}' && (!cmd_quoting || p[i-1] != CMDQ)) {
+ if (--n == 0) {
+ for (k = j; k < i - 1; k++)
+ p[k] = p[k+1];
+ for (; i < len; i++ )
+ p[i-1] = p[i+1];
+ len -= 2;
+ j = i - 1;
+ }
+ }
+ }
+ }
+ }
+ if (n == 1) { /* Implied right brace at end of field */
+ for (k = j; k < len; k++)
+ p[k] = p[k+1];
+ len -= 1;
+ }
+ } else if (*p == '"') {
+ len = strlen(p);
+ n = 0;
+
+ for (j = 0; j < len; j++) {
+ if (p[j] == '"' &&
+ (!cmd_quoting || j == 0 || p[j-1] != CMDQ)) {
+ n++;
+
+ for (i = j + 1; i < len; i++) {
+ if (p[i] == '"' && (!cmd_quoting || p[i-1] != CMDQ)) {
+ n--;
+
+ for (k = j; k < i - 1; k++)
+ p[k] = p[k+1];
+ for (; i < len; i++)
+ p[i-1] = p[i+1];
+ len -= 2;
+ j = i - 1;
+ }
+ }
+ }
+ }
+ if (n == 1) { /* Implied double quote at end of field */
+ for (k = j; k < len; k++ )
+ p[k] = p[k+1];
+ len -= 1;
+ }
+ }
+ return(p);
+}
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/*
+ Not used -- Note: these not only write into their arg, but write past
+ past the end.
+*/
+char *
+brace(fn) char *fn; {
+ int spaces = 0;
+ char * p, ch, ch2;
+ for (p = fn; *p; p++) {
+ if (*p == SP) {
+ spaces = 1;
+ break;
+ }
+ }
+ if (spaces) {
+ p = fn;
+ ch = *p;
+ *p = '{';
+ p++;
+
+ while (*p) {
+ ch2 = *p;
+ *p = ch;
+ ch = ch2;
+ p++;
+ }
+ *p = ch;
+ p++;
+ *p = '}';
+ p++;
+ *p = '\0';
+ }
+ return(fn);
+}
+#endif /* COMMENT */
+
+/* d q u o t e -- Puts doublequotes around arg in place. */
+/*
+ Call with:
+ Pointer to buffer and its total length and flag = 0 to use
+ doublequotes, 1 to use braces.
+ Returns:
+ Number: length of result.
+*/
+int
+dquote(fn, len, flag) char *fn; int len; int flag; {
+ int spaces = 0, k = 0;
+ char * p, ch, ch2;
+ if (!fn)
+ return(0);
+
+ k = strlen(fn);
+ for (p = fn; *p; p++) {
+ if (*p == SP) {
+ spaces = 1;
+ break;
+ }
+ }
+ if (spaces) {
+ if (k + 2 >= len)
+ return(k);
+ p = fn;
+ ch = *p;
+ *p = flag ? '{' : '"';
+ p++;
+
+ while (*p) {
+ ch2 = *p;
+ *p = ch;
+ ch = ch2;
+ p++;
+ }
+ *p = ch;
+ p++;
+ *p = flag ? '}' : '"';
+ p++;
+ *p = '\0';
+ }
+ return(k+2);
+}
+
+
+/* U N T A B I F Y --- Untabify s1 into s2, assuming tabs every 8 space */
+
+int
+untabify(s1,s2,max) char * s1, * s2; int max; {
+ int i, j, k, x, z;
+ x = strlen(s1);
+ for (i = 0, k = 0; k < x; k++) {
+ if (s1[k] != '\t') {
+ if (i >= max-1) {
+ s2[max-1] = '\0';
+ return(-1);
+ }
+ s2[i++] = s1[k];
+ continue;
+ }
+ z = 8 - i%8;
+ if (z == 0) z = 8;
+ for (j = 0; j < z && i < max; j++)
+ s2[i++] = ' ';
+ }
+ s2[i] = '\0';
+ return(0);
+}
+
+
+/* M A K E L I S T --- Breaks {{s1}{s2}..{sn}} into an array of strings */
+/*
+ Call with:
+ s = pointer to string to break up.
+ list = array of string pointers.
+ len = number of elements in array.
+ NOTE: The array must be preinitialized to all NULL pointers.
+ If any array element is not NULL, it is assumed to have been malloc'd
+ and is therefore freed. Do NOT call this function with an uninitialized
+ array, or with an array that has had any static elements assigned to it.
+*/
+VOID
+makelist(s,list,len) char * s; char *list[]; int len; {
+ int i, n, q, bc = 0;
+ char *p = NULL, *s2 = NULL;
+ debug(F110,"makelist s",s,0);
+ if (!s) { /* Check for null or empty string */
+ list[0] = NULL;
+ return;
+ }
+ n = strlen(s);
+ if (n == 0) {
+ list[0] = NULL;
+ return;
+ }
+ if ((s2 = (char *)malloc(n+1))) { /* Safe copy for poking */
+ strcpy(s2,s); /* (no need for ckstrncpy here) */
+ s = s2;
+ }
+ s = brstrip(s); /* Strip braces */
+ n = strlen(s); /* Get length */
+ if (*s != '{') { /* Outer braces only */
+ if ((p = (char *)malloc(n+1))) { /* So just one pattern */
+ strcpy(p,s); /* (no need for ckstrncpy here) */
+ if (list[0])
+ free(list[0]);
+ list[0] = p;
+ }
+ if (s2) free(s2);
+ return;
+ }
+ q = 0; /* Inner ones too */
+ i = 0; /* so a list of patterns. */
+ n = 0;
+ while (*s && i < len) {
+ if (*s == CMDQ) { /* Quote... */
+ q = 1;
+ s++;
+ n++;
+ continue;
+ }
+ if (*s == '{' && !q) { /* Opening brace */
+ if (bc++ == 0) { /* Beginning of a group */
+ p = ++s;
+ n = 0;
+ } else { /* It's a brace inside the group */
+ n++;
+ s++;
+ }
+ continue;
+ } else if (*s == '}' && !q) { /* Closing brace */
+ if (--bc == 0) { /* End of a group */
+ *s++ = NUL;
+ debug(F111,"makelist element",p,i);
+ if (list[i])
+ free(list[i]);
+ if ((list[i] = (char *)malloc(n+1))) {
+ ckstrncpy(list[i],p,n+1); /* Note: n+1 */
+ i++;
+ }
+ while (*s == SP) s++;
+ p = s;
+ n = 0;
+ continue;
+ } else { /* Within a group */
+ n++;
+ s++;
+ }
+ } else { /* Regular character */
+ q = 0;
+ s++;
+ n++;
+ }
+ }
+ if (*p && i < len) { /* Last one */
+ if (list[i])
+ free(list[i]);
+ if ((list[i] = (char *)malloc(n+1))) {
+ ckstrncpy(list[i],p,n+1);
+ debug(F111,"makelist last element",p,i);
+ }
+ }
+ i++; /* Clear out the rest of the list */
+ for ( ; i < len; i++) {
+ if (list[i])
+ free (list[i]);
+ list[i] = NULL;
+ }
+ if (s2) free(s2);
+}
+
+/*
+ M A K E S T R -- Creates a dynamically allocated string.
+
+ Makes a new copy of string s and sets pointer p to its address.
+ Handles degenerate cases, like when buffers overlap or are the same,
+ one or both arguments are NULL, etc.
+
+ The source string is assumed to be NUL-terminated. Therefore it can not
+ be a UCS-2 string or arbitrary binary data.
+
+ The target pointer must be either NULL or else a pointer to a previously
+ malloc'ed buffer. If not, expect a core dump or segmentation fault.
+
+ Note: The caller can tell whether this routine failed as follows:
+
+ malloc(&p,q);
+ if (q & !p) { makestr() failed };
+
+ Really this routine should have returned a length, but since it doesn't
+ we set the global variable makestrlen to the length of the result string.
+*/
+int makestrlen = 0;
+
+VOID
+#ifdef CK_ANSIC
+makestr(char **p, const char *s)
+#else
+makestr(p,s) char **p, *s;
+#endif
+/* makestr */ {
+ int x = 0;
+ char *q = NULL;
+#ifdef CK_ANSIC
+ register const char * s2;
+#else
+ register char * s2;
+#endif /* CK_ANSIC */
+ register char * q2;
+
+ if (*p == s) /* The two pointers are the same. */
+ return; /* Don't do anything. */
+
+ if (!s) { /* New definition is null? */
+ if (*p) /* Free old storage. */
+ free(*p);
+ *p = NULL; /* Return null pointer. */
+ makestrlen = 0;
+ return;
+ }
+ s2 = s; /* Maybe new string will fit */
+
+#ifdef COMMENT
+/*
+ This is a fairly big win, allowing us to skip the malloc() and free if the
+ destination string already exists and is not shorter than the source string.
+ But it doesn't allow for possible overlap of source and destination.
+*/
+ if (*p) { /* into old storage... */
+ char * p2 = *p;
+ char c;
+ while (c = *p2) {
+ if (!(*p2++ = *s2++))
+ break;
+ x++;
+ }
+ makestrlen = x;
+ if (c) return;
+ }
+#endif /* COMMENT */
+
+/* Didn't fit */
+
+ x = 0;
+ while (*s2++) x++; /* Get (rest of) length of s. */
+
+ if (x >= 0) { /* Get length, even of empty string. */
+ q = malloc(x+1); /* Get and point to temp storage. */
+ if (q) {
+ makestrlen = x; /* Remember length for stats */
+ s2 = s; /* Point back to beginning of source */
+ q2 = q; /* Copy dest pointer to increment... */
+ while ((*q2++ = *s2++)) ; /* Instead of calling strcpy(). */
+/*
+ Note: HP flexelint says that the above loop can result in creation (++) and
+ access (*) of out-of-bounds pointers. I really don't see it.
+*/
+ }
+#ifdef DEBUG
+ else { /* This would be a really bad error */
+ char tmp[24]; /* So get a good record of it. */
+ if (x > 23) {
+ ckstrncpy(tmp,s,20);
+ strcpy(tmp+20,"...");
+ tmp[23] = NUL;
+ } else {
+ strcpy(tmp,s); /* We already checked the length */
+ }
+ debug(F110,"MAKESTR MALLOC FAILURE ",tmp,0);
+ }
+#endif /* DEBUG */
+ } else
+ q = NULL; /* Length of string is zero */
+
+ if (*p) /* Now free the original storage. */
+ free(*p);
+ *p = q;
+}
+
+/* X M A K E S T R -- Non-destructive makestr() if s is NULL. */
+
+VOID
+#ifdef CK_ANSIC
+xmakestr(char **p, const char *s)
+#else
+xmakestr(p,s) char **p, *s;
+#endif
+/* xmakestr */ {
+ if (s) makestr(p,s);
+}
+
+#ifndef USE_MEMCPY
+/* C K M E M C P Y -- Portable (but slow) memcpy() */
+
+/* Copies n bytes from s to p, allowing for overlap. */
+/* For use when real memcpy() not available. */
+
+VOID
+ckmemcpy(p,s,n) char *p, *s; int n; {
+ char * q = NULL;
+ register int i;
+ int x;
+
+ if (!s || !p || n <= 0 || p == s) /* Verify args */
+ return;
+ x = p - s; /* Check for overlap */
+ if (x < 0)
+ x = 0 - x;
+ if (x < n) { /* They overlap */
+ q = p;
+ if (!(p = (char *)malloc(n))) /* So use a temporary buffer */
+ return;
+ }
+ for (i = 0; i < n; i++) /* Copy n bytes */
+ p[i] = s[i];
+ if (q) { /* If we used a temporary buffer */
+ for (i = 0; i < n; i++) /* copy from it to destination */
+ q[i] = p[i];
+ if (p) free(p); /* and free the temporary buffer */
+ }
+}
+#endif /* USE_MEMCPY */
+
+
+/* C K S T R C M P -- String comparison with case-matters selection */
+/*
+ Call with pointers to the two strings, s1 and s2, a length, n,
+ and c == 0 for caseless comparison, nonzero for case matters.
+ Call with n == -1 to compare without a length limit.
+ Compares up to n characters of the two strings and returns:
+ 1 if s1 > s2
+ 0 if s1 = s2
+ -1 if s1 < s2
+ Note: case handling is only as good as isupper() and tolower().
+*/
+int
+ckstrcmp(s1,s2,n,c) char *s1, *s2; register int n, c; {
+ register CHAR t1, t2;
+ if (n == 0) return(0);
+ if (!s1) s1 = ""; /* Watch out for null pointers. */
+ if (!s2) s2 = "";
+ if (!*s1) return(*s2 ? -1 : 0);
+ if (!*s2) return(1);
+ while (n--) {
+ t1 = (CHAR) *s1++; /* Get next character from each. */
+ t2 = (CHAR) *s2++;
+ if (!t1) return(t2 ? -1 : 0);
+ if (!t2) return(1);
+ if (!c) { /* If case doesn't matter */
+ if (isupper(t1)) t1 = tolower(t1); /* Convert case. */
+ if (isupper(t2)) t2 = tolower(t2);
+ }
+ if (t1 < t2) return(-1); /* s1 < s2 */
+ if (t1 > t2) return(1); /* s1 > s2 */
+ }
+ return(0); /* They're equal */
+}
+
+/* C K S T R P R E -- Caseless string prefix comparison */
+
+/* Returns position of the first char in the 2 strings that doesn't match */
+
+int
+ckstrpre(s1,s2) char *s1, *s2; {
+ CHAR t1, t2;
+ int n = 0;
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ while (1) {
+ t1 = (CHAR) *s1++;
+ t2 = (CHAR) *s2++;
+ if (!t1 || !t2) return(n);
+ if (isupper(t1)) t1 = tolower(t1);
+ if (isupper(t2)) t2 = tolower(t2);
+ if (t1 != t2)
+ return(n);
+ n++;
+ }
+}
+
+#define GLOBBING
+
+/* C K M A T C H -- Match a string against a pattern */
+/*
+ Call with:
+ pattern to be matched.
+ string to look for the pattern in.
+ icase is 1 if case-sensitive, 0 otherwise.
+ opts is a bitmask:
+ Bit 0 (=1):
+ 1 = Match strings starting with '.'
+ 0 = Don't match them (used with UNIX filenames).
+ Bit 1 (=2):
+ 1 = File globbing (dirseps are fences);
+ 0 = Dirseps are not fences.
+ Bit 2 (=4):
+ 1 = Allow ^ and $ anchors at beginning and end of pattern.
+ 0 = Don't allow them (normal case for filename matching).
+ Bit 3 (and beyond): Undefined.
+ Works only with NUL-terminated strings.
+ Pattern may contain any number of ? and/or *.
+ If CKREGEX is defined, also [abc], [a-z], and/or {string,string,...}.
+ (Note: REGEX is a misnomer, see below.)
+
+ Returns:
+ 0 if string does not match pattern,
+ >= 1, the 1-based position in the string where the match was found.
+
+ To be done:
+ Find a way to identify the piece of the string that matched the pattern,
+ as in Snobol "LINE (PAT . RESULT)". This is now partially done by
+ setting matchpos and matchend (except matchend needs some tuning). But
+ these are useless unless a copy of the string is kept, or a copy of the
+ matching part is made. But that would be too costly in performance --
+ this routine has to be fast because it's used for wildcard expansion.
+
+ Note:
+ Patterns are not the same as regular expressions, in which '*' means
+ 0 or more repetitions of the preceding item. For example "a*b" as a
+ pattern matches any string that starts with 'a' and ends with 'b'; as a
+ regular expression it matches any string of zero or more a's followed by
+ one b. Regular expressions are especially useful in matching strings of
+ (say) digits, or letters, e.g. "[0-9]*" matches any string of digits.
+ So far, Kermit doesn't do this.
+*/
+static char * mypat = NULL; /* For rewriting pattern */
+static int matchpos = 0;
+int matchend = 0;
+static int matchdepth = 0;
+static int stringpos = 0;
+static char * ostring = NULL;
+
+#define MATCHRETURN(x,y) { rc=y; where=x; goto xckmatch; }
+static char * lastpat = NULL;
+
+static int xxflag = 0; /* Global bailout flag for ckmatch() */
+
+int
+ispattern(s) char * s; {
+ int quote = 0, sbflag = 0, sb = 0, cbflag = 0, cb = 0;
+
+ char c = 0;
+ if (*s == '^') return(1);
+ while ((c = *s++)) {
+ if (quote) {
+ quote = 0;
+ continue;
+ }
+ if (c == '\\') {
+ quote = 1;
+ continue;
+ }
+ if (c == '*') return(1);
+ if (c == '?') return(1);
+ /* Unquoted brackets or braces must match */
+ if (c == '[') { sbflag++; sb++; continue; }
+ if (c == ']') { sb--; continue; }
+ if (c == '{') { cbflag++; cb++; continue; }
+ if (c == '}') { cb--; continue; }
+ if (!*s && c == '$') return(1);
+ }
+ return(sbflag || cbflag);
+}
+
+int
+ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; {
+ int q = 0, i = 0, k = -1, x, flag = 0;
+ int rc = 0; /* Return code */
+ int havestar = 0;
+ int where = -1;
+ CHAR cp; /* Current character from pattern */
+ CHAR cs; /* Current character from string */
+ char * patstart; /* Start of pattern */
+ int plen, dot, globbing, xstar = 0;
+ int bronly = 0; /* Whole pattern is {a,b,c,...} */
+
+ debug(F111,"CKMATCH ENTRY pat opt",pattern,opts);
+ debug(F111,"CKMATCH ENTRY str dep",string,matchdepth);
+ /* debug(F101,"CKMATCH ENTRY icase","",icase); */
+
+ globbing = opts & 2;
+
+ if (!string) string = "";
+ if (!pattern) pattern = "";
+
+ if (!*pattern) { /* Empty pattern matches anything */
+ matchdepth++; /* (it wasn't incremented yet) */
+ MATCHRETURN(0,1);
+ } else if (!*string) {
+ MATCHRETURN(0,0);
+ }
+ patstart = pattern; /* Remember beginning of pattern */
+
+ if (matchdepth == 0) { /* Top-level call? */
+ xxflag = 0;
+ stringpos = 0; /* Reset indices etc. */
+ matchpos = 0;
+ matchend = 0;
+ ostring = string;
+ lastpat = pattern;
+ if (*pattern == '{') /* Entire pattern is {a,b.c} */
+ bronly = 1; /* Maybe */
+ dot = (opts & 1) || /* Match leading dot (if file) */
+ ((opts & 2) == 0) || /* always if not file */
+ (pattern[0] == '.'); /* or if pattern starts with '.' */
+
+ plen = strlen(pattern); /* Length of pattern */
+/* This would be used in calculating length of matching segment */
+ if (plen > 0) /* User's pattern ends with '*' */
+ if (pattern[plen - 1] == '*')
+ xstar = 1;
+ if (pattern[0] == '*') { /* User's pattern starts with '*' */
+ matchpos = 1;
+ debug(F111,"CKMATCH 1",string, matchpos);
+ }
+ if (opts & 4) { /* ^..$ allowed (top level only) */
+ /* Rewrite pattern to account for ^..$ anchoring... */
+
+ if (mypat) free(mypat); /* Get space for "*pattern*" */
+ mypat = (char *)malloc(plen + 4);
+ if (mypat) { /* Got space? */
+ char * s = pattern, * p = mypat; /* Set working pointers */
+ if (*s == '^') { /* First source char is ^ */
+ s++; /* so skip past it */
+ } else if (*s != '*') { /* otherwise */
+ *p++ = '*'; /* prepend '*' to pattern */
+ }
+ while (*s) { /* Copy rest of pattern */
+ if (!*(s+1)) { /* Final pattern character? */
+ if (*s != '$') { /* If it's not '$' */
+ *p++ = *s; /* Copy it into the pattern */
+ if (*s++ != '*') /* And if it's also not '*' */
+ *p++ = '*'; /* append '*'. */
+ }
+ break; /* Done */
+ } else /* Not final character */
+ *p++ = *s++; /* Just copy it */
+ }
+ *p = NUL; /* Terminate the new pattern */
+ pattern = mypat; /* Make the switch */
+ }
+ debug(F110,"CKMATCH INIT pat",pattern,0);
+ }
+ }
+ matchdepth++; /* Now increment call depth */
+
+#ifdef UNIX
+ if (!dot) { /* For UNIX file globbing */
+ if (*string == '.' && *pattern != '.' && !matchdot) {
+ if (
+#ifdef CKREGEX
+ *pattern != '{' && *pattern != '['
+#else
+ 1
+#endif /* CKREGEX */
+ ) {
+ debug(F110,"ckmatch skip",string,0);
+ MATCHRETURN(1,0);
+ }
+ }
+ }
+#endif /* UNIX */
+ while (1) {
+ k++;
+ cp = *pattern; /* Character from pattern */
+ cs = *string; /* Character from string */
+
+#ifdef COMMENT
+ debug(F000,"CKMATCH pat cp",pattern,cp);
+ debug(F000,"CKMATCH str cs",string,cs);
+#endif /* COMMENT */
+
+ if (!cs) { /* End of string - done. */
+ x = (!cp || (cp == '*' && !*(pattern+1))) ? 1 : 0;
+ if (x) {
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH A",string, matchpos);
+ }
+ matchend = stringpos;
+ MATCHRETURN(2,matchpos);
+ }
+ debug(F111,"CKMATCH ZERO d",string, matchpos);
+ matchpos = 0;
+ MATCHRETURN(16,matchpos);
+ }
+ if (!icase) { /* If ignoring case */
+ if (isupper(cp)) /* convert both to lowercase. */
+ cp = tolower(cp);
+ if (isupper(cs))
+ cs = tolower(cs);
+ }
+ if (q) { /* This character was quoted */
+ debug(F000,"CKMATCH QUOTED",pattern,cp);
+ q = 0; /* Turn off quote flag */
+
+ if (cs == cp) { /* Compare directly */
+ if (!matchpos) { /* Matches */
+ matchpos = stringpos;
+ debug(F111,"CKMATCH \\ new match",string, matchpos);
+ }
+ pattern++;
+ } else { /* Doesn't match */
+ pattern = lastpat; /* Back up the pattern */
+ matchpos = 0;
+ debug(F111,"CKMATCH \\ no match",pattern, matchpos);
+ }
+ string++;
+ stringpos++;
+ continue;
+ }
+ if (cp == CMDQ && !q) { /* Quote in pattern */
+ debug(F000,"CKMATCH QUOTE",pattern,cp);
+ q = 1; /* Set flag */
+ pattern++; /* Advance to next pattern character */
+ continue; /* and continue. */
+ }
+ if (cs && cp == '?') { /* '?' matches any char */
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH D",string, matchpos);
+ }
+ debug(F110,"CKMATCH ? pat",pattern,0);
+ debug(F110,"CKMATCH ? str",string,0);
+ pattern++;
+ string++;
+ stringpos++;
+ continue;
+#ifdef CKREGEX
+ } else if (cp == '[') { /* Have bracket */
+ int q = 0; /* My own private q */
+ char * psave = NULL; /* and backup pointer */
+ CHAR clist[256]; /* Character list from brackets */
+ CHAR c, c1, c2;
+
+ for (i = 0; i < 256; i++) /* memset() etc not portable */
+ clist[i] = NUL;
+ psave = ++pattern; /* Where pattern starts */
+ debug(F111,"CKMATCH [] ",pattern-1, matchpos);
+ for (flag = 0; !flag; pattern++) { /* Loop thru pattern */
+ c = (CHAR)*pattern; /* Current char */
+ debug(F000,">>> pattern char","",c);
+ if (q) { /* Quote within brackets */
+ q = 0;
+ clist[c] = 1;
+ continue;
+ }
+ if (!icase) /* Case conversion */
+ if (isupper(c))
+ c = tolower(c);
+ switch (c) { /* Handle unquoted character */
+ case NUL: /* End of string */
+ MATCHRETURN(4,0); /* No matching ']' so fail */
+ case CMDQ: /* Next char is quoted */
+ q = 1; /* Set flag */
+ continue; /* and continue. */
+ case '-': /* A range is specified */
+ c1 = (pattern > psave) ? (CHAR)*(pattern-1) : NUL;
+ c2 = (CHAR)*(pattern+1); /* IGNORE OUT-OF-BOUNDS WARNING */
+ if (c2 == ']') c2 = NUL; /* (it can't happen) */
+ if (c1 == NUL) c1 = c2;
+ for (c = c1; c <= c2; c++) {
+ clist[c] = 1;
+ if (!icase) {
+ if (islower(c)) {
+ clist[toupper(c)] = 1;
+ } else if (isupper(c)) {
+ clist[tolower(c)] = 1;
+ }
+ }
+ }
+ continue;
+ case ']': /* End of bracketed sequence */
+ flag = 1; /* Done with FOR loop */
+ break; /* Compare what we have */
+ default: /* Just a char */
+ clist[c] = 1; /* Record it */
+ if (!icase) {
+ if (islower(c)) {
+ clist[toupper(c)] = 1;
+ } else if (isupper(c)) {
+ clist[tolower(c)] = 1;
+ }
+ }
+ continue;
+ }
+ }
+ debug(F000,">>> cs","",cs);
+ debug(F101,">>> clist[cs]","",clist[cs]);
+ debug(F000,">>> string",string,*string);
+
+ if (!clist[(unsigned)cs]) { /* No match? */
+ if (!*string) { /* This clause 16 Jun 2005 */
+ MATCHRETURN(5,0); /* Nope, done. */
+ }
+/*
+ We need to fail here if the [clist] is not allowed to float.
+ The [clist] is not allowed to float if it is not preceded
+ by an asterisk, right? 30 Dec 2005.
+*/
+ if (!havestar) {
+ MATCHRETURN(500,0);
+ }
+ string++; /* From here to end added 2005/6/15 */
+ stringpos++;
+ pattern = lastpat; /* Back up pattern */
+ k = ckmatch(pattern,string,icase,opts);
+ if (xxflag) MATCHRETURN(0,0);
+ if (!matchpos && k > 0)
+ matchpos = stringpos;
+ MATCHRETURN(5, (*string) ? matchpos : 0);
+ }
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH [] match",string, matchpos);
+ }
+ string++; /* Yes, advance string pointer */
+ stringpos++;
+ continue; /* and go on. */
+ } else if (cp == '{') { /* Braces enclosing list of strings */
+ char * p, * s, * s2, * buf = NULL;
+ int n, bc = 0;
+ int len = 0;
+ debug(F111,"CKMATCH {} ",string, matchpos);
+ for (p = pattern++; *p; p++) {
+ if (*p == '{') bc++;
+ if (*p == '}') bc--;
+ if (bc < 1) break;
+ }
+ if (bc != 0) { /* Braces don't match */
+ MATCHRETURN(6,0); /* Fail */
+ } else { /* Braces do match */
+ int q = 0, done = 0;
+ len = *p ? strlen(p+1) : 0; /* Length of rest of pattern */
+ if (len)
+ bronly = 0;
+ if (bronly && (matchdepth != 1))
+ bronly = 0;
+ n = p - pattern; /* Size of list in braces */
+ if ((buf = (char *)malloc(n+1))) { /* Copy so we can poke it */
+ char * tp = NULL;
+ int k, sofar;
+ ckstrncpy(buf,pattern,n+1);
+ sofar = string - ostring - matchpos + 1;
+ if (sofar < 0) sofar = 0;
+ debug(F111,"CKMATCH .. string",string,sofar);
+ debug(F111,"CKMATCH .. ostring",ostring,sofar);
+ n = 0;
+ for (s = s2 = buf; 1; s++) { /* Loop through segments */
+ n++;
+ if (q) { /* This char is quoted */
+ q = 0;
+ if (!*s)
+ done = 1;
+ continue;
+ }
+ if (*s == CMDQ && !q) { /* Quote next char */
+ q = 1;
+ continue;
+ }
+ if (!*s || *s == ',') { /* End of this segment */
+ int tplen = 0;
+ if (!*s) /* If end of buffer */
+ done = 1; /* then end of last segment */
+ *s = NUL; /* Overwrite comma with NUL */
+ debug(F111,"CKMATCH {} segment",s2,done);
+ tplen = n + len + sofar + 2;
+ if (!*s2) { /* Empty segment, no advancement */
+ k = 0;
+ } else if ((tp = (char *)malloc(tplen))) {
+ int savpos, opts2;
+ char * pp;
+ pp = matchpos > 0 ?
+ &ostring[matchpos-1] :
+ ostring;
+ if (bronly) {
+ if (matchpos > 0)
+ ckstrncpy(tp,pp,sofar+1);
+ else
+ ckstrncpy(tp,pp,sofar);
+ } else {
+ tp[0] = '*';
+ tp[1] = NUL;
+ if (matchpos > 0)
+ ckstrncpy(&tp[1],pp,sofar+1);
+ else
+ ckstrncpy(&tp[1],pp,sofar);
+ }
+ ckstrncat(tp,s2,tplen); /* Current segment */
+ ckstrncat(tp,p+1,tplen); /* rest of pattern */
+
+ debug(F101,"CKMATCH {} matchpos","",matchpos);
+ savpos = matchpos;
+ matchpos = 0;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"CKMATCH {} tp",tp,matchpos);
+ debug(F111,"CKMATCH {} string",
+ string,matchpos);
+ debug(F111,"CKMATCH {} ostring",
+ ostring,savpos);
+ }
+#endif /* DEBUG */
+ /* If segment starts with dot */
+ /* then set matchdot option.. */
+ opts2 = opts;
+ if (*s2 == '.') opts2 |= 1;
+ debug(F111,"CKMATCH {} recursing",s2,opts2);
+ k = ckmatch(tp,
+ (string > ostring) ?
+ &ostring[savpos-1] : string,
+ icase,opts2);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"CKMATCH {} k","",k);
+ debug(F101,"CKMATCH {} savpos","",savpos);
+ }
+#endif /* DEBUG */
+ free(tp);
+ tp = NULL;
+ if (xxflag) MATCHRETURN(0,0);
+ if (k == 0) {
+ matchpos = savpos;
+ }
+ if (k > 0) { /* If it matched we're done */
+ MATCHRETURN(7,k);
+ }
+ } else { /* Malloc failure */
+ MATCHRETURN(14,0);
+ }
+ if (k) { /* Successful comparison */
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH {} match",
+ string, matchpos);
+ }
+ string += n-1; /* Advance pointers */
+ pattern = p+1;
+ break;
+ }
+ if (done) /* If no more segments */
+ break; /* break out of segment loop. */
+ s2 = s+1; /* Otherwise, on to next segment */
+ n = 0;
+ }
+ }
+ free(buf);
+ }
+ }
+#endif /* CKREGEX */
+ } else if (cp == '*') { /* Pattern char is asterisk */
+ char * psave;
+ char * p, * s = NULL; /* meaning match anything */
+ int k, n, q = 0;
+ havestar++; /* The rest can float */
+ while (*pattern == '*') /* Collapse successive asterisks */
+ pattern++;
+ psave = pattern; /* First non-asterisk after asterisk */
+ lastpat = pattern - 1; /* Ditto, global */
+ debug(F111,"CKMATCH * ",string,matchpos);
+ for (n = 0, p = psave; *p; p++,n++) { /* Find next meta char */
+ if (!q) {
+ if (*p == '?' || *p == '*' || *p == CMDQ
+#ifdef CKREGEX
+ || *p == '[' || *p == '{'
+#endif /* CKREGEX */
+ )
+ break;
+#ifdef GLOBBING
+ if (globbing
+#ifdef UNIXOROSK
+ && *p == '/'
+#else
+#ifdef VMS
+ && (*p == '.' || *p == ']' ||
+ *p == '<' || *p == '>' ||
+ *p == ':' || *p == ';')
+#else
+#ifdef datageneral
+ && *p == ':'
+#else
+#ifdef STRATUS
+ && *p == '>'
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIXOROSK */
+ )
+ break;
+#endif /* GLOBBING */
+ }
+ }
+ debug(F111,"CKMATCH * n string",string,n);
+ debug(F111,"CKMATCH * n pattrn",pattern,n);
+ debug(F111,"CKMATCH * n p",p,n);
+ if (n > 0) { /* Literal string to match */
+ s = (char *)malloc(n+1);
+ if (s) {
+ ckstrncpy(s,psave,n+1); /* Copy cuz no poking original */
+ if (*p) {
+ k = ckindex(s,string,0,0,icase); /* 1-based index() */
+ debug(F110,"CKMATCH * Index() string",string,0);
+ debug(F110,"CKMATCH * Index() pattrn",s,0);
+ debug(F101,"CKMATCH * Index() result","",k);
+ } else { /* String is right-anchored */
+ k = ckindex(s,string,-1,1,icase); /* rindex() */
+ debug(F111,"CKMATCH * Rindex()",string,k);
+ debug(F110,"CKMATCH * Rindex() pattrn",s,0);
+ debug(F101,"CKMATCH * Rindex() result","",k);
+ }
+ free(s);
+ if (k < 1) {
+ MATCHRETURN(8,0);
+ }
+ debug(F111,"CKMATCH * stringpos matchpos",
+ ckitoa(stringpos), matchpos);
+ if (!matchpos) {
+ matchpos = string - ostring + k;
+ debug(F111,"CKMATCH * new match ", string, matchpos);
+ }
+ string += k + n - 1;
+ stringpos += k + n - 1;
+ pattern += n;
+ debug(F111,"CKMATCH * new string", string, stringpos);
+ debug(F110,"CKMATCH * new pattrn", pattern, 0);
+ continue;
+ }
+ } else if (!*p) { /* Asterisk at end matches the rest */
+ if (!globbing) { /* (if not filename globbing) */
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH *$ ",string, matchpos);
+ }
+ matchend = stringpos;
+ MATCHRETURN(9,matchpos);
+ }
+#ifdef GLOBBING
+ while (*string) {
+ if (globbing /* Filespec so don't cross fields */
+#ifdef OS2
+ && *string == '/' || *string == '\\' ||
+ *string == ':'
+#else
+#ifdef UNIXOROSK
+ && *string == '/'
+#else
+#ifdef VMS
+ && (*string == '.' || *string == ']' ||
+ *string == '<' || *string == '>' ||
+ *string == ':' || *string == ';')
+#else
+#ifdef datageneral
+ && *string == ':'
+#else
+#ifdef STRATUS
+ && *string == '>'
+#else
+ && *string == '/' /* (catch-all) */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIXOROSK */
+#endif /* OS2 */
+ ) {
+ matchend = stringpos;
+ MATCHRETURN(10,0);
+ }
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH *$ match",string, matchpos);
+ }
+ string++;
+ stringpos++;
+ }
+#endif /* GLOBBING */
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH ** match",string, matchpos);
+ }
+ matchend = stringpos;
+ MATCHRETURN(11,matchpos);
+
+ } else { /* A meta char follows asterisk */
+ if (!*string)
+ MATCHRETURN(17, matchpos = 0);
+#ifdef COMMENT
+ /* This is more elegant but it doesn't work. */
+ p--;
+ string++;
+ stringpos++;
+ k = ckmatch(p,string,icase,opts);
+#else
+ while (*string && ((k = ckmatch(p,string,icase,opts)) < 1)) {
+ if (xxflag) MATCHRETURN(0,0);
+ string++;
+ stringpos++;
+ }
+ if (!*string && k < 1) {
+/*
+ Definitely no match so we set a global flag to inibit further backing up
+ and retrying by previous incarnations, since they don't see that the string
+ and/or pattern, which are on the stack, have been exhausted at this level.
+*/
+ xxflag++;
+ debug(F111,"CKMATCH DEFINITELY NO MATCH",p,k);
+ MATCHRETURN(91,0);
+ }
+#endif /* COMMENT */
+ debug(F111,"CKMATCH *<meta> k",string, k);
+ if (!matchpos && k > 0) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH *<meta> matchpos",string, matchpos);
+ }
+ MATCHRETURN(12, (*string) ? matchpos : 0);
+ }
+ } else if (cs == cp) {
+ pattern++;
+ string++;
+ stringpos++;
+ if (!matchpos) {
+ matchpos = stringpos;
+ debug(F111,"CKMATCH cs=cp",string, matchpos);
+ }
+ continue;
+ } else {
+ MATCHRETURN(13,0);
+ }
+ }
+ xckmatch:
+ {
+#ifdef DEBUG
+ char msgbuf[256];
+#endif /* DEBUG */
+ if (matchdepth > 0)
+ matchdepth--;
+ matchpos = rc;
+#ifdef DEBUG
+ ckmakxmsg(msgbuf,256,
+ "CKMATCH RETURN[",
+ ckitoa(where),
+ "] matchpos=",
+ ckitoa(matchpos),
+ " matchdepth=",
+ ckitoa(matchdepth),
+ " pat=",pattern,
+ " string=",string,NULL,NULL
+ );
+ debug(F110,msgbuf,string,0);
+#endif /* DEBUG */
+ return(rc);
+ }
+}
+
+
+#ifdef CKFLOAT
+/* I S F L O A T -- Verify that arg represents a floating-point number */
+
+/*
+ Portable replacement for atof(), strtod(), scanf(), etc.
+
+ Call with:
+ s = pointer to string
+ flag == 0 means entire string must be a (floating-pointing) number.
+ flag != 0 means to terminate scan on first character that is not legal.
+
+ Returns:
+ 1 if result is a legal number;
+ 2 if result has a fractional part;
+ 0 if not or if string empty.
+
+ Side effect:
+ Sets global floatval to floating-point value if successful.
+
+ Number need not contain a decimal point -- integer is subcase of float.
+ Scientific notation not supported.
+*/
+CKFLOAT floatval = 0.0; /* For returning value */
+
+int
+isfloat(s,flag) char *s; int flag; {
+ int state = 0;
+ int sign = 0;
+ char c;
+ CKFLOAT d = 0.0, f = 0.0;
+
+ if (!s) return(0);
+ if (!*s) return(0);
+
+ while (isspace(*s)) s++;
+
+ if (*s == '-') { /* Handle optional sign */
+ sign = 1;
+ s++;
+ } else if (*s == '+')
+ s++;
+ while ((c = *s++)) { /* Handle numeric part */
+ switch (state) {
+ case 0: /* Mantissa... */
+ if (isdigit(c)) {
+ f = f * 10.0 + (CKFLOAT)(c - '0');
+ continue;
+ } else if (c == '.') {
+ state = 1;
+ d = 1.0;
+ continue;
+ }
+ if (flag) /* Not digit or period */
+ goto done; /* break if flag != 0 */
+ return(0); /* otherwise fail. */
+ case 1: /* Fraction... */
+ if (isdigit(c)) {
+ d *= 10.0;
+ f += (CKFLOAT)(c - '0') / d;
+ continue;
+ }
+ default:
+ if (flag) /* Illegal character */
+ goto done; /* Break */
+ return(0); /* or fail, depending on flag */
+ }
+ }
+ done:
+ if (sign) f = 0.0 - f; /* Apply sign to result */
+ floatval = f; /* Set result */
+ return(d ? 2 : 1); /* Succeed */
+}
+
+/*
+ c k r o u n d -- Rounds a floating point number or an integer.
+
+ fpnum:
+ Floating-point number to round.
+ places:
+ Positive...To how many decimal places.
+ Zero.......Round to integer.
+ Negative...-1 = nearest ten, -2 = nearest 100, -3 = nearest thousand, etc.
+ obuf
+ Output buffer for string result if desired.
+ obuflen
+ Length of output buffer.
+ Returns:
+ Result as CKFLOAT (which is not going to be as exact as the string result)
+ And the exact result in the string output buffer, if one was specified.
+*/
+CKFLOAT
+#ifdef CK_ANSIC
+ckround(CKFLOAT fpnum, int places, char *obuf, int obuflen)
+#else
+ckround(fpnum,places,obuf,obuflen)
+ CKFLOAT fpnum; int places, obuflen; char *obuf;
+#endif /* CK_ANSIC */
+/* ckround */ {
+ char *s, *s2, *d;
+ int i, p, len, x, n, digits;
+ int carry = 0;
+ int minus = 0;
+ char buf[200];
+ char * number;
+ CKFLOAT value;
+ extern int fp_digits;
+
+ sprintf(buf,"%200.100f",fpnum); /* Make string version to work with */
+ number = (char *) buf; /* Make pointer to it */
+
+ p = places; /* Precision */
+ d = (char *)0; /* Pointer to decimal or string end */
+
+ s = number; /* Fix number... */
+ while (*s == ' ' || *s == '\011') s++; /* Strip leading whitespace */
+ if (*s == '+') s++; /* Skip leading plus sign*/
+ number = s; /* Start of number */
+ if (*s == '-') { minus++; number++; s++; } /* Remember if negative */
+
+ s = number; /* Don't allow false precision */
+ n = 0;
+ while (*s && *s != '.') s++, n++; /* Find decimal */
+
+ if (p + n > fp_digits) /* Too many digits */
+ p = fp_digits - n; /* Don't ask for bogus precision */
+ if (p < 0) p = 0; /* But don't ask for less than zero */
+ if (n > fp_digits) /* Integer part has too many digits */
+ *s = 0; /* but we can't truncate it */
+ else /* Magnitude is OK */
+ number[fp_digits+1] = 0; /* Truncate fractional part. */
+
+ len = (int)strlen(number); /* Length of non-bogus number */
+ d = s; /* Pointer to decimal point */
+ if (p > 0) { /* Rounding the fractional part */
+ if (n + p < len) { /* If it's not already shorter */
+ if (*s == '.') s++; /* Skip past decimal */
+ s += p; /* Go to desired spot */
+ if (*s > '4' && *s <= '9') /* Check value of digit */
+ carry = 1;
+ *s = 0; /* And end the string */
+ s--; /* Point to last digit */
+ }
+ } else if (p == 0) { /* Rounding to integer */
+ if (*s == '.') {
+ *s = 0; /* erase the decimal point */
+ if (*(s+1)) { /* and there is a factional part */
+ if (*(s+1) > '4' && *(s+1) <= '9') /* Check for carry */
+ carry = 1;
+ }
+ s--; /* Point to last digit */
+ }
+ } else { /* Rounding the integer part */
+ if (s + p > number) { /* as in "the nearest hundred" */
+ s += p; /* Go left to desired digit */
+ *d = 0; /* Discard fraction */
+ carry = 0;
+ if (*s > '4') /* Check first digit of fraction */
+ carry = 1; /* and set carry flag */
+ s2 = s;
+ while (s2 < d) /* Fill in the rest with zeros */
+ *s2++ = '0';
+ s--; /* Point to last digit */
+ }
+ }
+ if (carry) { /* Handle carry, if any */
+ while (s >= number) {
+ if (*s == '.') { /* Skip backwards over decimal */
+ s--;
+ continue;
+ }
+ *s += 1; /* Add 1 to current digit */
+ carry = 0;
+ if (*s <= '9') /* If result is 9 or less */
+ break; /* we're done */
+ *s = '0'; /* Otherwise put 0 */
+ carry = 1; /* carry the 1 */
+ s--; /* and back up to next digit */
+ }
+ }
+#ifdef __alpha
+ sscanf(number,"%f",&value); /* Convert back to floating point */
+#else
+ sscanf(number,"%lf",&value); /* Convert back to floating point */
+#endif
+ if (obuf) strncpy(obuf,number,obuflen); /* Set string result */
+ return(value); /* Return floating-point result */
+}
+
+#endif /* CKFLOAT */
+
+/* Sorting routines... */
+
+/* S H _ S O R T -- Shell sort -- sorts string array s in place. */
+
+/*
+ Highly defensive and relatively quick.
+ Uses shell sort algorithm.
+
+ Args:
+ s = pointer to array of strings.
+ p = pointer to a second array to sort in parallel s, or NULL for none.
+ n = number of elements in s.
+ k = position of key.
+ r = ascending lexical order if zero, reverse lexical order if nonzero.
+ c = 0 for case independence, 1 for case matters, 2 for numeric.
+
+ If k is past the right end of a string, the string is considered empty
+ for comparison purposes.
+
+ Hint:
+ To sort a piece of an array, call with s pointing to the first element
+ and n the number of elements to sort.
+
+ Return value:
+ None. Always succeeds, unless any of s[0]..s[n-1] are bad pointers,
+ in which case memory violations are possible, but C offers no defense
+ against this, so no way to gracefully return an error code.
+*/
+VOID
+sh_sort(s,p,n,k,r,c) char **s, **p; int n, k, r, c; {
+ int m, i, j, x;
+ char *t, *t1, *t2, *u = NULL;
+#ifdef CKFLOAT
+ CKFLOAT f1, f2;
+#else
+ long n1, n2;
+#endif /* CKFLOAT */
+
+ if (!s) return; /* Nothing to sort? */
+ if (n < 2) return; /* Not enough elements to sort? */
+ if (k < 0) k = 0; /* Key */
+
+ m = n; /* Initial group size is whole array */
+ while (1) {
+ m = m / 2; /* Divide group size in half */
+ if (m < 1) /* Small as can be, so done */
+ break;
+ for (j = 0; j < n-m; j++) { /* Sort each group */
+ t = t2 = s[j+m]; /* Compare this one... */
+ if (!t) /* But if it's NULL */
+ t2 = ""; /* make it the empty string */
+ if (p) /* Handle parallel array, if any */
+ u = p[j+m];
+ if (k > 0 && *t2) {
+ if ((int)strlen(t2) < k) /* If key too big */
+ t2 = ""; /* make key the empty string */
+ else /* Key is in string */
+ t2 = t + k; /* so point to key position */
+ }
+ for (i = j; i >= 0; i -= m) { /* Loop thru comparands s[i..]*/
+ t1 = s[i];
+ if (!t1) /* Same deal */
+ t1 = "";
+ if (k > 0 && *t1) {
+ if ((int)strlen(t1) < k)
+ t1 = "";
+ else
+ t1 = s[i]+k;
+ }
+ if (c == 2) { /* Numeric comparison */
+ x = 0;
+#ifdef CKFLOAT
+ f2 = 0.0;
+ f1 = 0.0;
+ if (isfloat(t1,1)) {
+ f1 = floatval;
+ if (isfloat(t2,1))
+ f2 = floatval;
+ else
+ f1 = 0.0;
+ }
+ if (f2 < f1)
+ x = 1;
+ else
+ x = -1;
+#else
+ n2 = 0L;
+ n1 = 0L;
+ if (rdigits(t1)) {
+ n1 = atol(t1);
+ if (rdigits(t2))
+ n2 = atol(t2);
+ else
+ n1 = 0L;
+ }
+ if (n2 < n1)
+ x = 1;
+ else
+ x = -1;
+#endif /* CKFLOAT */
+ } else {
+ x = ckstrcmp(t1,t2,-1,c); /* Compare */
+ }
+ if (r == 0 && x < 0)
+ break;
+ if (r != 0 && x > 0)
+ break;
+ s[i+m] = s[i];
+ if (p) p[i+m] = p[i];
+ }
+ s[i+m] = t;
+ if (p) p[i+m] = u;
+ }
+ }
+}
+
+
+/* C K R A D I X -- Radix converter */
+/*
+ Call with:
+ s: a number in string format.
+ in: int, specifying the radix of s, 2-36.
+ out: int, specifying the radix to convert to, 2-36.
+ Returns:
+ NULL on error (illegal radix, illegal number, etc.).
+ "-1" on overflow (number too big for unsigned long).
+ Otherwise: Pointer to result.
+*/
+char *
+ckradix(s,in,out) char * s; int in, out; {
+ char c, *r = rxresult;
+ int d, minus = 0;
+#ifdef COMMENT
+ unsigned long zz = 0L;
+ long z = 0L;
+#else
+ /*
+ To get 64 bits on 32-bit hardware we use off_t, but there
+ is no unsigned version of off_t, so we lose the ability to
+ detect overflow.
+ */
+ CK_OFF_T zz = (CK_OFF_T)0;
+ CK_OFF_T z = (CK_OFF_T)0;
+#endif /* COMMENT */
+
+ if (in < 2 || in > 36) /* Verify legal input radix */
+ return(NULL);
+ if (out < 2 || out > 36) /* and output radix. */
+ return(NULL);
+ if (*s == '+') { /* Get sign if any */
+ s++;
+ } else if (*s == '-') {
+ minus++;
+ s++;
+ }
+ while (*s == SP || *s == '0') /* Trim leading blanks or 0's */
+ s++;
+/*
+ For detecting overflow, we use a signed copy of the unsigned long
+ accumulator. If it goes negative, we know we'll overflow NEXT time
+ through the loop.
+*/
+ for (; *s; s++) { /* Convert from input radix to */
+ c = *s; /* unsigned long */
+ if (islower(c)) c = toupper(c);
+ if (c >= '0' && c <= '9')
+ d = c - '0';
+ else if (c >= 'A' && c <= 'Z')
+ d = c - 'A' + 10;
+ else
+ return(NULL);
+ if (d >= in) /* Check for illegal digit */
+ return(NULL);
+ zz = zz * in + d;
+ if (z < 0L) /* Clever(?) overflow detector */
+ return("-1");
+ z = zz;
+ }
+ if (!zz) return("0");
+ r = &rxresult[RXRESULT]; /* Convert from unsigned long */
+ *r-- = NUL; /* to output radix. */
+ while (zz > 0 && r > rxresult) {
+ d = zz % (unsigned)out;
+ *r-- = rxdigits[d];
+ zz = zz / (unsigned)out;
+ }
+ if (minus) *r-- = '-'; /* Replace original sign */
+ return((char *)(r+1));
+}
+
+#ifndef NOB64
+/* Base-64 conversion routines */
+
+static char b64[] = { /* Encoding vector */
+#ifdef pdp11
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+#else
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
+ 'T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l',
+ 'm','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4',
+ '5','6','7','8','9','+','/','=','\0'
+#endif /* pdp11 */
+};
+static int b64tbl[] = { /* Decoding vector */
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+/*
+ B 8 T O B 6 4 -- Converts 8-bit data to Base64 encoding.
+
+ Call with:
+ s = Pointer to 8-bit data;
+ n = Number of source bytes to encode (SEE NOTE).
+ If it's a null-terminated string, you can use -1 here.
+ out = Address of output buffer.
+ len = Length of output buffer (should > 4/3 longer than input).
+
+ Returns:
+ >= 0 if OK, number of bytes placed in output buffer,
+ with the subsequent byte set to NUL if space permits.
+ -1 on error (output buffer space exhausted).
+
+ NOTE:
+ If this function is to be called repeatedly, e.g. to encode a data
+ stream a chunk at a time, the source length must be a multiple of 3
+ in all calls but the final one to avoid the generation of extraneous
+ pad characters that would throw the decoder out of sync. When encoding
+ only a single string, this is not a consideration. No internal state
+ is kept, so there is no reset function.
+*/
+int
+b8tob64(s,n,out,len) char * s,* out; int n, len; {
+ int b3, b4, i, x = 0;
+ unsigned int t;
+
+ if (n < 0) n = strlen(s);
+
+ for (i = 0; i < n; i += 3,x += 4) { /* Loop through source bytes */
+ b3 = b4 = 0;
+ t = (unsigned)((unsigned)((unsigned int)s[i] & 0xff) << 8);
+ if (n - 1 > i) { /* Do we have another after this? */
+ t |= (unsigned)(s[i+1] & 0xff); /* Yes, OR it in */
+ b3 = 1; /* And remember */
+ }
+ t <<= 8; /* Move over */
+ if (n - 2 > i) { /* Another one after that? */
+ t |= (unsigned)(s[i+2] & 0xff); /* Yes, OR it in */
+ b4 = 1; /* and remember */
+ }
+ if (x + 4 > len) /* Check output space */
+ return(-1);
+ out[x+3] = b64[b4 ? (t & 0x3f) : 64]; /* 64 = code for '=' */
+ t >>= 6;
+ out[x+2] = b64[b3 ? (t & 0x3f) : 64];
+ t >>= 6;
+ out[x+1] = b64[t & 0x3f];
+ t >>= 6;
+ out[x] = b64[t & 0x3f];
+ }
+ if (x < len) out[x] = NUL; /* Null-terminate the string */
+ return(x);
+}
+
+
+/*
+ B 6 4 T O B 8 -- Converts Base64 string to 8-bit data.
+
+ Call with:
+ s = pointer to Base64 string (whitespace ignored).
+ n = length of string, or -1 if null terminated, or 0 to reset.
+ out = address of output buffer.
+ len = length of output buffer.
+
+ Returns:
+ >= 0 if OK, number of bytes placed in output buffer,
+ with the subsequent byte set to NUL if space permits.
+ < 0 on error:
+ -1 = output buffer too small for input.
+ -2 = input contains illegal characters.
+ -3 = internal coding error.
+
+ NOTE:
+ Can be called repeatedly to decode a Base64 stream, one chunk at a
+ time. However, if it is to be called for multiple streams in
+ succession, its internal state must be reset at the beginning of
+ the new stream.
+*/
+int
+b64tob8(s,n,out,len) char * s,* out; int n, len; { /* Decode */
+ static int bits = 0;
+ static unsigned int r = 0;
+ int i, k = 0, x, t;
+ unsigned char c;
+
+ if (n == 0) { /* Reset state */
+ bits = 0;
+ r = 0;
+ return(0);
+ }
+ x = (n < 0) ? strlen(s) : n; /* Source length */
+
+ n = ((x + 3) / 4) * 3; /* Compute destination length */
+ if (x > 0 && s[x-1] == '=') n--; /* Account for padding */
+ if (x > 1 && s[x-2] == '=') n--;
+ if (n > len) /* Destination not big enough */
+ return(-1); /* Fail */
+
+ for (i = 0; i < x; i++) { /* Loop thru source */
+ c = (CHAR)s[i]; /* Next char */
+ t = b64tbl[c]; /* Code for this char */
+ if (t == -2) { /* Whitespace or Ctrl */
+ n--; /* Ignore */
+ continue;
+ } else if (t == -1) { /* Illegal code */
+ return(-2); /* Fail. */
+ } else if (t > 63 || t < 0) /* Illegal value */
+ return(-3); /* fail. */
+ bits += 6; /* Count bits */
+ r <<= 6; /* Make space */
+ r |= (unsigned) t; /* OR in new code */
+ if (bits >= 8) { /* Have a byte yet? */
+ bits -= 8; /* Output it */
+ c = (unsigned) ((r >> bits) & 0xff);
+ out[k++] = c;
+ }
+ }
+ if (k < len) out[k] = NUL; /* Null-terminate in case it's */
+ return(k); /* a text string */
+}
+#endif /* NOB64 */
+
+/* C H K N U M -- See if argument string is an integer */
+
+/* Returns 1 if OK, zero if not OK */
+/* If OK, string should be acceptable to atoi() or atol() or ckatofs() */
+/* Allows leading space, sign */
+
+int
+chknum(s) char *s; { /* Check Numeric String */
+ int x = 0; /* Flag for past leading space */
+ int y = 0; /* Flag for digit seen */
+ char c;
+ debug(F110,"chknum",s,0);
+ if (!s) return(0);
+ if (!*s) return(0);
+ while ((c = *s++)) { /* For each character in the string */
+ switch (c) {
+ case SP: /* Allow leading spaces */
+ case HT:
+ if (x == 0) continue;
+ else return(0);
+ case '+': /* Allow leading sign */
+ case '-':
+ if (x == 0) x = 1;
+ else return(0);
+ break;
+ default: /* After that, only decimal digits */
+ if (c >= '0' && c <= '9') {
+ x = y = 1;
+ continue;
+ } else return(0);
+ }
+ }
+ return(y);
+}
+
+
+/* R D I G I T S -- Verify that all characters in arg ARE DIGITS */
+
+/* Returns 1 if so, 0 if not or if string is empty */
+
+int
+rdigits(s) char *s; {
+ if (!s) return(0);
+ do {
+ if (!isdigit(*s)) return(0);
+ s++;
+ } while (*s);
+ return(1);
+}
+
+/* P A R N A M -- Return parity name */
+
+char *
+#ifdef CK_ANSIC
+parnam(char c)
+#else
+parnam(c) char c;
+#endif /* CK_ANSIC */
+/* parnam */ {
+ switch (c) {
+ case 'e': return("even");
+ case 'o': return("odd");
+ case 'm': return("mark");
+ case 's': return("space");
+ case 0: return("none");
+ default: return("invalid");
+ }
+}
+
+char * /* Convert seconds to hh:mm:ss */
+#ifdef CK_ANSIC
+hhmmss(long x)
+#else
+hhmmss(x) long x;
+#endif /* CK_ANSIC */
+/* hhmmss(x) */ {
+ static char buf[10];
+ long s, h, m;
+ h = x / 3600L; /* Hours */
+ x = x % 3600L;
+ m = x / 60L; /* Minutes */
+ s = x % 60L; /* Seconds */
+ if (x > -1L)
+ sprintf(buf,"%02ld:%02ld:%02ld",h,m,s);
+ else
+ buf[0] = NUL;
+ return((char *)buf);
+}
+
+/* L S E T -- Set s into p, right padding to length n with char c; */
+/*
+ s is a NUL-terminated string.
+ If length(s) > n, only n bytes are moved.
+ The result is NOT NUL terminated unless c == NUL and length(s) < n.
+ The intended of this routine is for filling in fixed-length record fields.
+*/
+VOID
+lset(p,s,n,c) char *s; char *p; int n; int c; {
+ int x;
+#ifndef USE_MEMCPY
+ int i;
+#endif /* USE_MEMCPY */
+ if (!s) s = "";
+ x = strlen(s);
+ if (x > n) x = n;
+#ifdef USE_MEMCPY
+ memcpy(p,s,x);
+ if (n > x)
+ memset(p+x,c,n-x);
+#else
+ for (i = 0; i < x; i++)
+ *p++ = *s++;
+ for (; i < n; i++)
+ *p++ = c;
+#endif /* USE_MEMCPY */
+}
+
+/* R S E T -- Right-adjust s in p, left padding to length n with char c */
+
+VOID
+rset(p,s,n,c) char *s; char *p; int n; int c; {
+ int x;
+#ifndef USE_MEMCPY
+ int i;
+#endif /* USE_MEMCPY */
+ if (!s) s = "";
+ x = strlen(s);
+ if (x > n) x = n;
+#ifdef USE_MEMCPY
+ memset(p,c,n-x);
+ memcpy(p+n-x,s,x);
+#else
+ for (i = 0; i < (n - x); i++)
+ *p++ = c;
+ for (; i < n; i++)
+ *p++ = *s++;
+#endif /* USE_MEMCPY */
+}
+
+/* U L O N G T O H E X -- Unsigned long to hex */
+
+/*
+ Converts unsigned long arg to hex and returns string pointer to
+ rightmost n hex digits left padded with 0's. Allows for longs
+ up to 64 bits. Returns pointer to result.
+*/
+char *
+#ifdef CK_ANSIC
+ulongtohex( unsigned long z, int n )
+#else
+ulongtohex(z,n) unsigned long z; int n;
+#endif /* CK_ANSIC */
+/* ulongtohex */ {
+ static char hexbuf[17];
+ int i = 16, x, k = 0;
+ hexbuf[16] = '\0';
+ if (n > 16) n = 16;
+ k = 2 * (sizeof(long));
+ for (i = 0; i < n; i++) {
+ if (i > k || z == 0) {
+ hexbuf[15-i] = '0';
+ } else {
+ x = z & 0x0f;
+ z = z >> 4;
+ hexbuf[15-i] = x + ((x < 10) ? '0' : 0x37);
+ }
+ }
+ return((char *)(&hexbuf[16-i]));
+}
+
+/* H E X T O U L O N G -- Hex string to unsigned long */
+
+/*
+ Converts n chars from s from hex to unsigned long.
+ Returns:
+ 0L or positive, good result (0L is returned if arg is NULL or empty).
+ -1L on error: non-hex arg or overflow.
+*/
+long
+hextoulong(s,n) char *s; int n; {
+ char buf[64];
+ unsigned long result = 0L;
+ int d, count = 0;
+ int flag = 0;
+ if (!s) s = "";
+ if (!*s) {
+ return(0L);
+ }
+ if (n < 1)
+ return(0L);
+ if (n > 63) n = 63;
+ strncpy(buf,s,n);
+ buf[n] = '\0';
+ s = buf;
+ while (*s) {
+ d = *s++;
+ if ((d == '0' || d == ' ')) {
+ if (!flag)
+ continue;
+ } else {
+ flag = 1;
+ }
+ if (islower(d))
+ d = toupper(d);
+ if (d >= '0' && d <= '9') {
+ d -= 0x30;
+ } else if (d >= 'A' && d <= 'F') {
+ d -= 0x37;
+ } else {
+ return(-1L);
+ }
+ if (++count > (sizeof(long) * 2))
+ return(-1L);
+ result = (result << 4) | (d & 0x0f);
+ }
+ return(result);
+}
+
+/*
+ c k s p l i t -- Splits a string into words, or:
+ extracts a given word from a string.
+
+ Allows for grouping.
+ Operates on a copy of the string; does not alter the original string.
+ All strings NUL-terminated.
+
+ Call with:
+ fc = function code:
+ 1 = split, 0 = word.
+ n1 = desired word number if fc == 0.
+ s1 = source string.
+ s2 = break string (NULL to accept default = all non-alphanum).
+ s3 = include string (NULL to accept default = all alphanum).
+ n2 = grouping mask (OR desired ones together):
+ 1 = doublequotes, 2 = braces, 4 = apostrophes,
+ 8 = parens, 16 = brackets, 32 = angle brackets,
+ -1 = 63 = all of these.
+ n3 = group quote character, ASCII value, used and tested only for
+ LISP quote, e.g. (a 'b c '(d e f)).
+ n4 = 0 to collapse adjacent separators;
+ nonzero not to collapse them.
+
+ Returns:
+ Pointer to struct stringarray, with size:
+ -1 = memory allocation error.
+ -2 = too many words in string.
+ n = number of words (0 or more).
+
+ With:
+ wordarray = array of pointers to n words (n == 1 if fc == 0), 1-based.
+ Each pointer is to a malloc'd string. This array is recycled upon each
+ call; if you need to keep the strings, make copies of them. This routine
+ must have control of allocation and deallocation.
+
+ If a given character is included in the include list, it is not treated
+ as a separator or as a grouping character.
+
+ Groups may be nested only if they are formed with braces, parens, or
+ brackets, but not with quotes or apostrophes since ASCII quotes have no
+ intrinsic handedness. Group-start and end characters are treated as
+ separators even in the absence of other separators, so a string such as
+ "a{b}c" results in three words, not one.
+
+ Sample call to split a string into an array:
+ struct stringarray * q;
+ q = cksplit(1,0,s1,s2,s3,-1,0);
+ q->a_size = size (>=0) or failure code (<0)
+ q->a_head = pointer to array (elements 0 thru q->asize - 1).
+
+ Sample call to extract word n from a string:
+ struct stringarray * q;
+ q = cksplit(0,n,s1,s2,s3,-1,0);
+ q->a_size = size (1) or failure code (<0)
+ q->a_head = pointer to array (element 1 is the desired word).
+*/
+
+/* States */
+
+#define ST_BW 0 /* Between Words */
+#define ST_IW 1 /* In Word */
+#define ST_IG 2 /* Start Group */
+
+/* Character Classes (bitmap) */
+
+#define CL_SEP 1 /* Separator */
+#define CL_OPN 2 /* Group Open */
+#define CL_CLS 4 /* Group Close */
+#define CL_DAT 8 /* Data */
+#define CL_QUO 16 /* Group quote */
+
+#ifdef BIGBUFOK
+#ifndef MAXWORDS
+#define MAXWORDS 4096 /* Max number of words */
+#endif /* MAXWORDS */
+#ifndef NESTMAX
+#define NESTMAX 64 /* Maximum nesting level */
+#endif /* NESTMAX */
+#else
+#ifndef MAXWORDS
+#define MAXWORDS 128 /* Max number of words */
+#endif /* MAXWORDS */
+#ifndef NESTMAX
+#define NESTMAX 16 /* Maximum nesting level */
+#endif /* NESTMAX */
+#endif /* BIGBUFOK */
+
+/* static */ char ** wordarray = NULL; /* Result array of word pointers */
+
+static struct stringarray ck_sval = { /* Return value structure */
+ NULL, /* Pointer to array */
+ 0 /* Size */
+};
+static int * wordsize = NULL;
+
+static VOID
+setword(n,s,len) int n, len; char * s; {
+ register char * p;
+ register int i, k;
+
+ if (!s) s = "";
+
+ if (!wordarray) { /* Allocate result array (only once) */
+ if (!(wordarray = (char **)malloc((MAXWORDS+1) * sizeof(char *))))
+ return;
+ if (!(wordsize = (int *)malloc((MAXWORDS+1) * sizeof(int))))
+ return;
+ for (i = 0; i <= MAXWORDS; i++) { /* Initialize result array */
+ wordarray[i] = NULL;
+ wordsize[i] = 0;
+ }
+ }
+ if (wordsize[n] < len /* || !wordarray[n] */ ) {
+ k = (len < 16) ? 16 : len + (len / 4);
+ wordarray[n] = (char *) malloc(k+1);
+ wordsize[n] = (wordarray[n]) ? k : 0;
+ if (wordarray[n]) {
+ p = wordarray[n];
+ while ((*p++ = *s++) && k-- > 0) ;
+ }
+ } else if (len > 0) {
+ k = wordsize[n]; /* (In case len arg is a lie) */
+ p = wordarray[n];
+ while ((*p++ = *s++) && k-- > 0) {
+#ifdef COMMENT
+ if ((*(s-1) == CMDQ) && *s != CMDQ) {
+ k++;
+ p--;
+ }
+#endif /* COMMENT */
+ }
+ } else if (wordarray[n]) {
+ wordarray[n][0] = NUL;
+ }
+}
+
+static char * splitbuf = NULL;
+static int nsplitbuf = 0;
+
+/* n4 = 1 to NOT collapse adjacent separators */
+
+
+struct stringarray *
+cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; {
+ int splitting = 0; /* What I was asked to do */
+ int i, k, ko = 0, n, x, max = MAXWORDS; /* Workers */
+ char * s = NULL, * ss, * p; /* Workers */
+ char * sep = ""; /* Default break set */
+ char * notsep = ""; /* Default include set */
+ int grouping = 0; /* Grouping option */
+ char * gr_opn = "\"{'([<"; /* Group open brackets */
+ char * gr_cls = "\"}')]>"; /* Group close brackets */
+ int gr_stk[NESTMAX]; /* Nesting bracket stack */
+ int gr_lvl = 0; /* Nesting level */
+ int wordnum = 0; /* Current word number */
+ CHAR c = 'A'; /* Current char (dummy start value) */
+ int class = 0; /* Current character class */
+ int state = ST_BW; /* Current FSA state */
+ int len = 0; /* Length of current word */
+ int slen = 0; /* Length of s1 */
+ int gquote = 0; /* Quoted group */
+ int cquote = 0; /* Quoted character */
+ int collapse = 1; /* Collapse adjacent separators */
+ int all = 0; /* s3 == ALL */
+ int csv = 0; /* s3 == CSV */
+ int tsv = 0; /* s3 == TSV */
+ int prevstate = -1;
+
+ unsigned int hex80 = 128;
+ unsigned int hexff = 255;
+ CHAR notsepbuf[256];
+
+ notsepbuf[0] = NUL; /* Keep set for "ALL" */
+ if (n4) collapse = 0; /* Don't collapse */
+
+ for (i = 0; i < NESTMAX; i++) /* Initialize nesting stack */
+ gr_stk[i] = 0;
+
+ setword(1,NULL,0);
+ ck_sval.a_head = wordarray; /* Initialize return value struct */
+ ck_sval.a_size = 0;
+
+ if (!s1) s1 = ""; /* s1 = source string */
+ if (!*s1) { /* If none, nothing to do */
+ return(&ck_sval);
+ }
+ splitting = fc; /* Our job */
+ if (splitting) { /* If splitting n = word count */
+ n = 0; /* Initialize it */
+ } else { /* Otherwise */
+#ifdef COMMENT
+ if (n1 < 1) { /* If 0 (or less) */
+ ck_sval.a_size = 0; /* nothing to do. */
+ return(&ck_sval);
+ }
+#else
+ if (n1 == 0) { /* If 0 */
+ ck_sval.a_size = 0; /* nothing to do. */
+ return(&ck_sval);
+ }
+#endif /* COMMENT */
+ n = n1; /* n = desired word number. */
+ }
+ slen = 0; /* Get length of s1 */
+ debug(F111,"cksplit",s1,n);
+
+ p = s1;
+
+#ifdef COMMENT
+ while (*p++) slen++; /* Make pokeable copy of s1 */
+ if (!splitbuf || slen > nsplitbuf) { /* Allocate buffer if needed */
+ int xx;
+ if (splitbuf)
+ free(splitbuf);
+ xx = (slen < 255) ? 255 : xx + (xx / 4);
+ debug(F101,"cksplit splitbuf","",xx);
+ splitbuf = (char *)malloc(xx+1);
+ if (!splitbuf) { /* Memory allocation failure... */
+ ck_sval.a_size = -1;
+ return(&ck_sval);
+ }
+ nsplitbuf = xx; /* Remember size of buffer */
+ }
+#else
+/*
+ The idea is to just copy the string into splitbuf (if it exists). This
+ gives us both the copy and the length so we only need to grovel through the
+ string once in most cases. Only when splitbuf doesn't exist or is too short
+ do we re-malloc(), which should be very infrequent so who cares if we have
+ to go through the string again in that case.
+*/
+ p = s1;
+ s = splitbuf;
+ if (splitbuf) { /* Make pokeable copy of s1 */
+ while ((*s++ = *p++) && (slen++ < nsplitbuf)) /* Try to copy */
+ ;
+ }
+ if (!splitbuf || slen >= nsplitbuf) { /* Need to do more... */
+ int xx;
+ if (splitbuf) /* Free previous buf if any */
+ free(splitbuf);
+ while (*p++) slen++; /* Get (rest of) length */
+ xx = (slen < 255) ? 255 : slen + (slen / 4); /* Size of new buffer */
+ splitbuf = (char *)malloc(xx+1); /* Allocate it */
+ if (!splitbuf) { /* Memory allocation failure... */
+ ck_sval.a_size = -1;
+ return(&ck_sval);
+ }
+ nsplitbuf = xx; /* Remember (new) buffer size */
+ s = splitbuf;
+ p = s1;
+ while ((*s++ = *p++)) ;
+ }
+
+#endif /* COMMENT */
+ s = splitbuf;
+ sep = s2; /* s2 = break set */
+ if (!sep) sep = "";
+ notsep = s3; /* s3 = include set */
+ if (!notsep) {
+ notsep = "";
+ } else if ((all = !ckstrcmp(notsep,"ALL",3,1)) ||
+ (csv = !ckstrcmp(notsep,"CSV",3,1)) ||
+ (tsv = !ckstrcmp(notsep,"TSV",3,1))) {
+ int i, flag; CHAR c;
+ int n = 0;
+ char * ss;
+ if (!all && (csv || tsv)) {
+ all = 1;
+ collapse = 0;
+ }
+ if (csv || tsv) {
+ all = 1;
+ collapse = 0;
+ }
+ for (i = 1; i < 256; i++) {
+ flag = 0;
+ ss = sep;
+ while (c = *ss++ && !flag) {
+ if (c == i) flag++;
+ }
+ if (!flag) notsepbuf[n++] = c;
+ }
+ notsepbuf[n] = NUL;
+ notsep = (char *)notsepbuf;
+ debug(F110,"CKMATCH NOTSEPBUF ALL",notsep,0);
+ }
+ if (*s && csv) { /* For CSV skip leading whitespace */
+ while (*s == SP || *s == HT)
+ s++;
+ c = *s;
+ }
+ if (n2 == 0 && csv) n2 = 1; /* CSV implies doublequote grouping */
+ if (n2 < 0) n2 = 63; /* n2 = grouping mask */
+ grouping = n2;
+ p = ""; /* Pointer to current word */
+ while (c) { /* Loop through string */
+ c = *s;
+ class = 0;
+ if (!csv && !tsv) { /* fdc 2010-12-30 */
+ /* In CSV and TSV splitting, backslash is not special */
+ if (!cquote && c == CMDQ) { /* If CMDQ */
+ cquote++; /* next one is quoted */
+ goto nextc; /* go get it */
+ }
+
+ }
+ if (cquote && c == CMDQ) { /* Quoted CMDQ is special */
+ if (state != ST_BW) { /* because it can still separate */
+ char * s2 = s-1;
+ while (s2 > p) { *s2 = *(s2-1); s2--; }
+ p++;
+ }
+ cquote = 0;
+ }
+ if (cquote) { /* Other quoted character */
+ if (state != ST_BW) { /* can't separate or group */
+ char * s2 = s-1;
+ while (s2 > p) { *s2 = *(s2-1); s2--; }
+ p++;
+ }
+ class = CL_DAT; /* so treat it as data */
+ cquote = 0;
+ x = 1;
+ } else { /* Character is not quoted */
+ if (!all && c < SP) { /* Get its class */
+ x = 0; /* x == 0 means "is separator" */
+ } else if (*sep) { /* Break set given */
+ ss = sep;
+ while (*ss && *ss != c) ss++; /* (instead of ckstrchr()) */
+ x = (*ss != c);
+ } else { /* Default break set is */
+ x = ((c >= 'a' && c <= 'z') || /* all but alphanumerics */
+ (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ ((unsigned int)c >= hex80 && (unsigned int)c <= hexff)
+ );
+ }
+ if (x == 0 && *notsep && c) { /* Include set if given */
+ ss = notsep;
+ while (*ss && *ss != c) ss++; /* (instead of ckstrchr()) */
+ x = (*ss == c);
+ }
+ if (c == n3 && grouping && state == ST_BW) { /* Group quote? */
+ class = CL_QUO;
+ } else {
+ class = x ? CL_DAT : CL_SEP; /* Class = data or separator */
+ }
+ if (grouping) { /* Grouping? */
+ int j; /* Look for group start */
+ for (k = 0; k < 6; k++) { /* Group-start char? */
+ j = 1 << k; /* Get its mask bit value */
+ if (grouping & j) {
+ if (c == gr_opn[k]) { /* Selected group opener? */
+ ko = k;
+ class |= CL_OPN;
+ if (c == '"' || c == '\'') { /* These can also */
+ class |= CL_CLS; /* be closers */
+ break;
+ }
+ } else if (c == gr_cls[k]) { /* Group closer? */
+ class |= CL_CLS;
+ break;
+ }
+ }
+ }
+ }
+ }
+ debug(F000,"cksplit char",s,c);
+ debug(F101,"cksplit state","",state);
+ debug(F101,"cksplit class","",class);
+
+ switch (state) { /* State switcher... */
+ case ST_BW: /* BETWEENWORDS */
+ if (class & CL_OPN) { /* Group opener */
+ if (gr_lvl == 0 && !gquote) { /* If not in group */
+ p = s; /* point to beginning of word */
+ }
+ gr_lvl++; /* Push closer on nesting stack */
+ if (gr_lvl >= NESTMAX)
+ goto xxsplit;
+ gr_stk[gr_lvl] = gr_cls[ko];
+ prevstate = state;
+ state = ST_IG; /* Switch to INGROUP state */
+ } else if (class & CL_DAT) { /* Data character */
+ gr_lvl = 0; /* Clear group nesting stack */
+ gr_stk[gr_lvl] = 0;
+ len = 0;
+ p = s; /* Point to beginning of word */
+ if (gquote) { /* Adjust for quote */
+ len++;
+ p--;
+ gquote = 0;
+ }
+ prevstate = state;
+ state = ST_IW; /* Switch to INWORD state */
+ } else if (class & CL_QUO) { /* Group quote */
+ gquote = gr_lvl+1; /* Remember quoted level */
+ p = s - 1;
+ len = 1;
+ }
+ if (collapse)
+ break;
+
+ case ST_IW: /* INWORD (but not in a group) */
+ if (class & CL_SEP) { /* Ends on any kind of separator */
+ *s = NUL; /* Terminate this word */
+ if (csv) { /* If comma-separated list */
+ char * s2 = s; /* discard surrounding spaces */
+ while (s2 > splitbuf) { /* first backwards... */
+ s2--;
+ if (*s2 == SP || *s2 == HT)
+ *s2 = NUL;
+ else
+ break;
+ }
+ s2 = s+1; /* Then forwards... */
+ while (*s2 && (*s2 == SP || *s2 == HT))
+ *s2++;
+ s = s2-1;
+ }
+ if (!csv || prevstate != ST_IG) {
+ wordnum++; /* Count it */
+ if (splitting || n < 0) { /* Dispose of it appropriately */
+ if (wordnum > max) { /* Add to array if splitting */
+ ck_sval.a_size = -2;
+ return(&ck_sval);
+ }
+ /* This inelegant bit corrects an edge condition */
+ if (csv && !*p && (!c || !*(s+1))) {
+ wordnum--;
+ } else {
+ setword(wordnum,p,len);
+ }
+ } else if (wordnum == n) { /* Searching for word n */
+ setword(1,p,len);
+ ck_sval.a_size = 1;
+ return(&ck_sval);
+ }
+ }
+ prevstate = state;
+ state = ST_BW; /* Switch to BETWEENWORDS state */
+ len = 0;
+ }
+ break;
+
+ case ST_IG: /* INGROUP */
+ if (class & CL_CLS) { /* Have group closer? */
+ if (csv) {
+ if (*(s+1) == c) {
+ char *s2 = s;
+ while ((*s2 = *(s2+1))) s2++;
+ s++;
+ c = *s;
+ }
+ }
+ if (c == gr_stk[gr_lvl]) { /* Does it match current opener? */
+ gr_lvl--; /* Yes, pop stack */
+ if (gr_lvl < 0) /* Don't pop it too much */
+ gr_lvl = 0;
+ if (gr_lvl == 0) { /* If at top of stack */
+ if (gquote)
+ s++;
+ c = *s;
+ *s = NUL; /* we have word. */
+ wordnum++; /* Count and dispose of it. */
+ len--;
+ if (splitting || n < 0) {
+ if (wordnum > max) {
+ ck_sval.a_size = -2;
+ return(&ck_sval);
+ }
+ setword(wordnum,p+1,len);
+ } else if (wordnum == n) {
+ setword(1,p+1,len);
+ ck_sval.a_size = 1;
+ return(&ck_sval);
+ }
+ prevstate = state;
+ state = ST_BW; /* Switch to BETWEENWORDS state */
+ len = 0;
+ }
+ if (gr_lvl < gquote)
+ gquote = 0;
+ }
+ } else if (class & CL_OPN) { /* Have group opener */
+ gr_lvl++; /* Push on nesting stack */
+ if (gr_lvl >= NESTMAX) goto xxsplit;
+ gr_stk[gr_lvl] = gr_cls[ko];
+ }
+ } /* switch */
+
+ nextc:
+ s++; /* Next char */
+ if (state)
+ len++;
+ } /* while (c) */
+
+ if (gr_lvl > 0) { /* In case of an unclosed group */
+ if (splitting || n < 0) { /* make it the last word. */
+ if (++wordnum > max) {
+ ck_sval.a_size = -2;
+ return(&ck_sval);
+ }
+ setword(wordnum,p+1,len);
+ } else if (wordnum == n) { /* Counting from left */
+ setword(1,p+1,len);
+ ck_sval.a_size = 1;
+ return(&ck_sval);
+ } else if (n < 0 && (wordnum + n > -1)) { /* Counting from right */
+ char * s = wordarray[wordnum + n + 1];
+ if (!s) s = "";
+ setword(1,s,strlen(s));
+ ck_sval.a_size = 1;
+ return(&ck_sval);
+ }
+ }
+ if (!splitting) { /* Fword... */
+ if (n < 0 && (wordnum + n > -1)) { /* Counting from right */
+ char * s = wordarray[wordnum + n + 1];
+ if (!s) s = "";
+ setword(1,s,strlen(s));
+ ck_sval.a_size = 1;
+ return(&ck_sval);
+ }
+ setword(1,NULL,0); /* From left... */
+ ck_sval.a_size = 0; /* but there weren't n words */
+ return(&ck_sval);
+ } else { /* Succeed otherwise */
+ ck_sval.a_size = wordnum;
+/*
+ Always put a null element at the end of the array. It does no harm in
+ the normal case, and it's required if we're making an argv[] array to
+ pass to execvp(). This element is not included in the count.
+*/
+ if (wordnum < MAXWORDS)
+ setword(wordnum+1,NULL,0);
+ }
+#ifdef DEBUG
+ if (deblog) {
+ for (i = 1; i <= wordnum; i++)
+ debug(F111,"cksplit result",wordarray[i],i);
+ }
+#endif /* DEBUG */
+ return(&ck_sval);
+
+ xxsplit: /* Error return */
+ ck_sval.a_size = -2;
+ return(&ck_sval);
+}
+
+/*
+ ckhexbytetoint() expects a string of two hex characters,
+ returns the int equivalent or -1 on error.
+*/
+int
+#ifdef CK_ANSIC
+ckhexbytetoint( char * s )
+#else
+ckhexbytetoint(s) char * s;
+#endif /* CK_ANSIC */
+{
+ int i, c[2];
+ if (!s) return(-1);
+ if ((int)strlen(s) != 2) return(-1);
+ for (i = 0; i < 2; i++) {
+ c[i] = *s++;
+ if (!c[i]) return(-1);
+ if (islower(c[i])) c[i] = toupper(c[i]);
+ if (c[i] >= '0' && c[i] <= '9') {
+ c[i] -= 0x30;
+ } else if (c[i] >= 'A' && c[i] <= 'F') {
+ c[i] -= 0x37;
+ } else {
+ return(-1);
+ }
+ }
+ return(c[0] * 16 + c[1]);
+}
+
+
+/* End of ckclib.c */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckclib.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckclib.h
new file mode 100644
index 0000000..af09c0e
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckclib.h
@@ -0,0 +1,104 @@
+/* ckclib.h -- C-Kermit library routine prototypes */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 2002, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef CKCLIB_H
+#define CKCLIB_H
+
+struct stringarray {
+ char ** a_head;
+ int a_size;
+};
+
+#ifdef CK_ANSIC
+_PROTOTYP( int ckstrncpy, (char *, const char *, int) );
+_PROTOTYP( int ckstrncat, (char *, const char *, int) );
+#else
+_PROTOTYP( int ckstrncpy, (char *, char *, int) );
+_PROTOTYP( int ckstrncat, (char *, char *, int) );
+#endif /* CK_ANSIC */
+
+_PROTOTYP( int ckmakmsg, (char *, int, char *, char *, char *, char *) );
+_PROTOTYP( int ckmakxmsg, (char *, int,
+ char *, char *, char *, char *, char *, char *,
+ char *, char *, char *, char *, char *, char *) );
+
+_PROTOTYP( char * ckstrpbrk, (char *, char *) );
+_PROTOTYP( char * ckstrstr, (char *, char *) );
+_PROTOTYP( char * chartostr, (int) );
+_PROTOTYP( int cklower, (char *) );
+_PROTOTYP( int ckupper, (char *) );
+_PROTOTYP( int ckindex, (char *, char *, int, int, int) );
+_PROTOTYP( char * ckctoa, (char) );
+_PROTOTYP( char * ckctox, (CHAR, int) );
+_PROTOTYP( char * ckitoa, (int) );
+_PROTOTYP( char * ckuitoa, (unsigned int) );
+_PROTOTYP( char * ckltoa, (long) );
+_PROTOTYP( char * ckultoa, (unsigned long) );
+_PROTOTYP( char * ckfstoa, (CK_OFF_T) );
+_PROTOTYP( CK_OFF_T ckatofs, (char *) );
+_PROTOTYP( char * ckitox, (int) );
+_PROTOTYP( char * ckltox, (long) );
+_PROTOTYP( int ispattern, (char *) );
+_PROTOTYP( int ckmatch, (char *, char *, int, int ) );
+_PROTOTYP( VOID ckmemcpy, (char *, char *, int) );
+_PROTOTYP( char * ckstrchr, (char *, char) );
+_PROTOTYP( char * ckstrrchr, (char *, char) );
+_PROTOTYP( int ckrchar, (char *) );
+_PROTOTYP( int ckstrcmp, (char *, char *, int, int) );
+#define xxstrcmp(a,b,c) ckstrcmp(a,b,c,0)
+_PROTOTYP( int ckstrpre, (char *, char *) );
+_PROTOTYP( VOID sh_sort, (char **, char **, int, int, int, int) );
+_PROTOTYP( char * brstrip, (char *) );
+_PROTOTYP( char * fnstrip, (char *) );
+#ifdef COMMENT
+_PROTOTYP( char * brace, (char *) );
+#endif /* COMMENT */
+_PROTOTYP( int dquote, (char *, int, int) );
+_PROTOTYP( int untabify, (char *, char *, int) );
+_PROTOTYP( VOID makelist, (char *, char *[], int) );
+#ifndef CK_ANSIC
+_PROTOTYP( VOID makestr, (char **, char *) );
+_PROTOTYP( VOID xmakestr, (char **, char *) );
+#else /* CK_ANSIC */
+_PROTOTYP( VOID makestr, (char **, const char *) );
+_PROTOTYP( VOID xmakestr, (char **, const char *) );
+#endif /* CK_ANSIC */
+_PROTOTYP( int chknum, (char *) );
+_PROTOTYP( int rdigits, (char *) );
+_PROTOTYP( char * ckradix, (char *,int,int) );
+
+/* Base-64 conversion needed for script programming and HTTP */
+
+#ifndef NOB64
+_PROTOTYP( int b8tob64, (char *,int,char *,int));
+_PROTOTYP( int b64tob8, (char *,int,char *,int));
+#endif /* NOB64 */
+
+#ifdef CKFLOAT
+_PROTOTYP( int isfloat, (char *,int) );
+#ifndef CKCLIB_C
+#ifndef CKWART_C
+extern CKFLOAT floatval;
+#endif /* CKWART_C */
+#endif /* CKCLIB_C */
+#endif /* CKFLOAT */
+
+_PROTOTYP( char * parnam, (char) );
+_PROTOTYP( char *hhmmss, (long) );
+
+_PROTOTYP( VOID lset, (char *, char *, int, int) );
+_PROTOTYP( VOID rset, (char *, char *, int, int) );
+_PROTOTYP( char * ulongtohex, (unsigned long, int) );
+_PROTOTYP( long hextoulong, (char *, int) );
+_PROTOTYP( struct stringarray * cksplit, (int,int,
+ char *,char *,char *,int,int,int) );
+
+_PROTOTYP( int ckhexbytetoint, (char *) );
+#endif /* CKCLIB_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcmai.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcmai.c
new file mode 100644
index 0000000..f65d0a0
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcmai.c
@@ -0,0 +1,3580 @@
+#define EDITDATE "20 Aug 2011" /* Last edit date dd mmm yyyy */
+#define EDITNDATE "20110820" /* Keep them in sync */
+/* Sat Aug 20 17:20:17 2011 */
+
+/* ckcmai.c - Main program for C-Kermit plus some miscellaneous functions */
+
+/*
+ ckcsym.h is used for for defining symbols that normally would be defined
+ using -D or -d on the cc command line, for use with compilers that don't
+ support this feature. Must come before any tests for preprocessor symbols.
+*/
+#include "ckcsym.h"
+/*
+ Consolidated program C-Kermit version information for all platforms
+ (but for UNIX also see ckuver.h). See makever() below for how they are used.
+*/
+#ifdef COMMENT /* Uncomment this for real K95 version */
+#ifndef OS2 /* OS2 actually means Kermit 95. */
+#ifndef BETATEST /* It's because Kermit 95 started */
+#define BETATEST /* out as C-Kermit for OS/2. */
+#endif /* BETATEST */
+#endif /* OS2 */
+#endif /* COMMENT */
+
+#ifdef BETATEST
+#ifdef OS2
+#ifdef __DATE__
+#define BETADATE
+#endif /* __DATE__ */
+#endif /* OS2 */
+#endif /* BETATEST */
+
+char * ck_cryear = "2011"; /* C-Kermit copyright year */
+
+#ifndef MAC /* MAC = Kermit for MAC OS 6, 7, ... */
+/*
+ Note: initialize ck_s_test to "" if this is not a test version.
+ Use (*ck_s_test != '\0') to decide whether to print test-related messages.
+*/
+
+#ifndef BETATEST
+#ifndef OS2 /* UNIX, VMS, etc... (i.e. C-Kermit) */
+char *ck_s_test = ""; /* "Dev","Alpha","Beta","RC", or "" */
+char *ck_s_tver = ""; /* Test version number or "" */
+#else /* OS2 */
+char *ck_s_test = ""; /* (i.e. K95) */
+char *ck_s_tver = "";
+#endif /* OS2 */
+#else
+char *ck_s_test = ""; /* Development */
+char *ck_s_tver = "";
+#endif /* BETATEST */
+#else /* MAC */
+char *ck_s_test = "Pre-Alpha"; /* Mac Kermit is always a test... */
+char *ck_s_tver = ""; /* (pre Mac OS X 10, that is!) */
+#endif /* MAC */
+
+#ifdef BETADATE /* Date of this version or edit */
+char *ck_s_date = __DATE__; /* Compilation date */
+#else
+char *ck_s_date = EDITDATE; /* See top */
+
+#endif /* BETADATE */
+char *buildid = EDITNDATE; /* See top */
+
+#ifdef UNIX
+static char sccsid[] = "@(#)C-Kermit 9.0.302";
+#endif /* UNIX */
+
+/*
+ The C-Kermit Version number is major.minor.edit (integers).
+ Major version always goes up.
+ Minor version is historical, hasn't been used since C-Kermit 7.1.
+ Edit is sequential, always goes up, but there can be gaps.
+ For example there might be many edits between releases.
+ If the major goes to 10, some version-number-based feature tests
+ could fail. It might be better to use the minor version field
+ for future releases.
+*/
+
+char *ck_s_ver = "9.0.302"; /* C-Kermit version string */
+long ck_l_ver = 900302L; /* C-Kermit version number */
+
+#ifdef OS2
+char *ck_s_xver = "3.0.0"; /* Product-specific version string */
+long ck_l_xver = 3000L; /* Product-specific version number */
+#else
+#ifdef MAC
+char *ck_s_xver = "0.995"; /* Product-specific version string */
+long ck_l_xver = 995L; /* Product-specific version number */
+#else
+char *ck_s_xver = ""; /* Don't touch these... */
+long ck_l_xver = 0L; /* they are computed at runtime */
+#endif /* MAC */
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef IKSDONLY
+#ifdef NT
+char *ck_s_name = "IKS-NT";
+#else /* NT */
+char *ck_s_name = "IKS-OS/2";
+#endif /* NT */
+#else /* IKSDONLY */
+char *ck_s_name = "Kermit 95"; /* Program name */
+#endif /* IKSDONLY */
+#else
+#ifdef MAC
+char *ck_s_name = "Mac Kermit";
+#else
+char *ck_s_name = "C-Kermit";
+#endif /* MAC */
+#endif /* OS2 */
+
+char *ck_s_who = ""; /* Where customized, "" = not. */
+char *ck_patch = ""; /* Patch info, if any. */
+
+#define CKVERLEN 128
+char versiox[CKVERLEN]; /* Version string buffer */
+char *versio = versiox; /* These are filled in at */
+long vernum, xvernum; /* runtime from above. */
+
+#define CKCMAI
+
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckcdeb.h" /* Debug & other symbols */
+
+char * myname = NULL; /* The name I am called by */
+#ifndef OS2
+char * exedir = NULL; /* Directory I was executed from */
+#endif /* OS2 */
+char * myhome = NULL; /* Home directory override */
+
+/* C K C M A I -- C-Kermit Main program */
+
+/*
+ Author: Frank da Cruz (fdc@columbia.edu),
+ Columbia University in the city of New York,
+ Computer Center / Center for Computing Activities / Information Technology.
+ I am no longer at Columbia U as of 1 July 2011, but the email address
+ should still work. The Kermit website http://kermit.columbia.edu should
+ still be available and under my control, as well as the Kermit FTP site,
+ ftp://kermit.columbia.edu/kermit/.
+
+COPYRIGHT NOTICE:
+*/
+
+char *copyright[] = {
+
+#ifdef pdp11
+"Copyright (C) 1985, %s, Trustees of Columbia University, NYC.",
+"All rights reserved.",
+" ",
+#else
+"Copyright (C) 1985, %s,",
+" The Trustees of Columbia University in the City of New York.",
+" All rights reserved.",
+" ",
+"Redistribution and use in source and binary forms, with or without",
+"modification, are permitted provided that the following conditions",
+"are met:",
+" ",
+" + Redistributions of source code must retain the above copyright",
+" notice, this list of conditions and the following disclaimer.",
+" ",
+" + Redistributions in binary form must reproduce the above copyright",
+" notice, this list of conditions and the following disclaimer in",
+" the documentation and/or other materials provided with the",
+" distribution.",
+" ",
+" + Neither the name of Columbia University nor the names of its",
+" contributors may be used to endorse or promote products derived",
+" from this software without specific prior written permission.",
+" ",
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS",
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT",
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR",
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT",
+"HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,",
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT",
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,",
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY",
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT",
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE",
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
+#endif /* pdp11 */
+
+#ifdef OS2
+"Portions Copyright (C) 2002-2005, Secure Endpoints Inc, New York NY USA.",
+"Portions Copyright (C) 1995, Oy Online Solutions Ltd., Jyvaskyla, Finland.",
+#endif /* OS2 */
+
+#ifdef CK_AUTHENTICATION
+"Portions Copyright (C) 1990, Massachusetts Institute of Technology.",
+#ifdef CK_ENCRYPTION
+"Portions Copyright (C) 1991, 1993 Regents of the University of California.",
+"Portions Copyright (C) 1991, 1992, 1993, 1994, 1995 by AT&T.",
+"Portions Copyright (C) 1995, 1997, Eric Young <eay@cryptosoft.com>.",
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SRP
+"Portions Copyright (C) 1997, Stanford University.",
+#endif /* CK_SRP */
+#endif /* CK_AUTHENTICATION */
+
+#ifndef pdp11
+" ",
+"For further information, visit the Kermit Project website:",
+"http://www.columbia.edu/kermit/ .",
+#endif /* pdp11 */
+""};
+
+/* Windows IKSD copyright used to be separate */
+char *wiksdcpr = (char *) copyright;
+
+
+/*
+DOCUMENTATION:
+
+ "Using C-Kermit" by Frank da Cruz and Christine M. Gianone,
+ Digital Press / Butterworth-Heinemann, Woburn MA, USA.
+ Second edition (1997), ISBN 1-55558-164-1.
+ Order from Digital Press: +1 (800) 366-2665
+ Or from Columbia University: +1 (212) 854-3703
+
+For Kermit 95, also:
+
+ "Kermit 95" by Christine M. Gianone and Frank da Cruz,
+ Manning Publications, Greenwich CT, USA (1998) - Online.
+
+ACKNOWLEDGMENTS:
+
+ The Kermit file transfer protocol was developed at the Columbia University
+ Center for Computing Activities (CUCCA), which was since renamed to Columbia
+ University Academic Information Systems (AcIS) and after that Columbia
+ University Information Technology (CUIT). Kermit is named after Kermit the
+ Frog, star of the television series THE MUPPET SHOW; the name is used by
+ permission of Henson Associates, Inc.
+
+ Thanks to at least the following people for their contributions to this
+ program over the years, and apologies to anyone who was inadvertantly
+ omitted:
+
+ Chris Adie, Edinburgh U, Scotland (OS/2)
+ Robert Adsett, University of Waterloo, Canada
+ Larry Afrin, Clemson U
+ Russ Allbery, Stanford U
+ Jeffrey Altman, Columbia University
+ Greg Andrews, Telebit Corp
+ Barry Archer, U of Missouri
+ Robert Andersson, International Systems A/S, Oslo, Norway
+ Chris Armstrong, Brookhaven National Lab (OS/2)
+ William Bader, Software Consulting Services, Nazareth, PA
+ Fuat Baran, Columbia U
+ Stan Barber, Rice U
+ Jim Barbour, U of Colorado
+ Donn Baumgartner, Dell
+ Ian Beckwith, Debian Project
+ Nelson Beebe, U of Utah
+ Gerry Belanger, Cognitronics
+ Karl Berry, UMB
+ Mark Berryman, SAIC
+ Dean W Bettinger, SUNY
+ Gary Bilkus
+ Peter Binderup, Denmark
+ David Bolen, Advanced Networks and Services, Inc.
+ Joop Bonen
+ Marc Boucher, U of Montreal
+ Charles Brooks, EDN
+ Bob Brown
+ Mike Brown, Purdue U
+ Rob Brown
+ Jack Bryans, California State U at Long Beach
+ Mark Buda, DEC (VMS)
+ Fernando Cabral, Padrao iX, Brasilia
+ Bjorn Carlsson, Stockholm University Computer Centre QZ, Sweden
+ Bill Catchings, (formerly of) Columbia U
+ Bob Cattani, Columbia U CS Dept
+ Davide Cervone, Rochester U
+ Seth Chaiklin, Denmark
+ John Chandler, Harvard U / Smithsonian Astronomical Observatory
+ Bernard Chen, UCLA
+ Andrew A Chernov, RELCOM Team, Moscow
+ John L Chmielewski, AT&T, Lisle, IL
+ Howard Chu, U of Michigan
+ Bill Coalson, McDonnell Douglas
+ Bertie Coopersmith, London
+ Christian Corti
+ Chet Creider, U of Western Ontario
+ Alan Crosswell, Columbia U
+ Jeff Damens, (formerly of) Columbia U
+ Mark Davies, Bath U, UK
+ Sin-itirou Dezawa, Fujifilm, Japan
+ Joe R. Doupnik, Utah State U
+ Frank Dreano, Honeywell
+ John Dunlap, U of Washington
+ Alex Dupuy, SMART.COM
+ David Dyck, John Fluke Mfg Co.
+ Stefaan A. Eeckels, Eurokom, Luxembourg
+ Nick Efthymiou
+ Paul Eggert, Twin Sun, Inc., El Segundo, CA
+ Bernie Eiben, DEC
+ Peter Eichhorn, Assyst International
+ Kristoffer Eriksson, Peridot Konsult AB, Oerebro, Sweden
+ John R. Evans, IRS, Kansas City
+ Glenn Everhart, RCA Labs
+ Charlie Finan, Cray Research
+ Herm Fischer, Encino, CA (extensive contributions to version 4.0)
+ Carl Fongheiser, CWRU
+ Mike Freeman, Bonneville Power Authority
+ Carl Friedberg
+ Marcello Frutig, Catholic University, Sao Paulo, Brazil (X.25 support)
+ Hirofumi Fujii, Japan Nat'l Lab for High Energy Physics, Tokyo (Kanji)
+ Chuck Fuller, Westinghouse Corporate Computer Services
+ Andy Fyfe, Caltech
+ Christine M. Gianone, Columbia U
+ John Gilmore, UC Berkeley
+ Madhusudan Giyyarpuram, HP
+ Rainer Glaschick, Siemens AG, Paderborn
+ William H. Glass
+ German Goldszmidt, IBM
+ Chuck Goodhart, NASA
+ Alistair Gorman, New Zealand
+ Richard Gration, ADFA, Australia
+ Chris Green, Essex U, UK
+ Alan Grieg, Dundee Tech, Scotland
+ Yekta Gursel, MIT
+ Jim Guyton, Rand Corp
+ Michael Haertel
+ Bruno Haible
+ Bob Hain, UMN
+ Marion Hakanson, ORST
+ Richard Hamilton
+ John Hamilston, Iowa State U
+ Simon Hania, Netherlands
+ Stan Hanks, Rice U.
+ Ken Harrenstein, SRI
+ Eugenia Harris, Data General (AOS/VS)
+ David Harrison, Kingston Warren Corp
+ Lucas Hart, Oregon State University
+ James Harvey, Indiana/Purdue U (VMS)
+ Rob Healey
+ Chuck Hedrick, Rutgers U
+ Ron Heiby, Technical Systems Division, Motorola Computer Group
+ Steve Hemminger, Tektronix
+ Christian Hemsing, RWTH Aachen, Germany (OS-9)
+ Randolph Herber, US DOE,
+ Andrew Herbert, Monash Univ, Australia
+ Marcus Herbert, Germany
+ Mike Hickey, ITI
+ Dan Hildebrand, QNX Software Systems Inc, Kanata, ON (QNX)
+ R E Hill
+ Stephan Hoffman-Emden
+ Sven Holmstrom, ABB Utilities AB, Sweden
+ Bill Homer, Cray Research
+ Ray Hunter, The Wollongong Group
+ Randy Huntziger, National Library of Medicine
+ Larry Jacobs, Transarc
+ Steve Jenkins, Lancaster University, UK
+ Dave Johnson, Gradient Technologies
+ Mark B Johnson, Apple Computer
+ Jyke Jokinen, Tampere University of Technology, Finland (QNX)
+ Eric F Jones, AT&T
+ Luke Jones, AT&T
+ Peter Jones, U of Quebec Montreal
+ Phil Julian, SAS Institute
+ Peter Kabal, U of Quebec
+ Mic Kaczmarczik, U of Texas at Austin
+ Sergey Kartashoff, Inst. of Precise Mechanics & Computer Equipment, Moscow
+ Howie Kaye, Columbia U
+ Rob Kedoin, Linotype Co, Hauppauge, NY (OS/2)
+ Phil Keegstra
+ Mark Kennedy, IBM
+ Terry Kennedy, St Peter's College, Jersey City, NJ (VMS and more)
+ "Carlo Kid", Technical University of Delft, Netherlands
+ Tim Kientzle
+ Paul Kimoto, Cornell U
+ Douglas Kingston, morgan.com
+ Lawrence Kirby, Wiltshire, UK
+ Tom Kloos, Sequent Computer Systems
+ Guenter Knauf
+ Jim Knutson, U of Texas at Austin
+ John T. Kohl (BSDI)
+ Scott Kramer, SRI International, Menlo Park, CA
+ John Kraynack, US Postal Service
+ David Kricker, Encore Computer
+ Thomas Krueger, UWM
+ Bo Kullmar, ABC Klubben, Stockholm, and Central Bank of Sweden, Kista
+ R. Brad Kummer, AT&T Bell Labs, Atlanta, GA
+ John Kunze, UC Berkeley
+ David Lane, BSSI / BellSouth (Stratus VOS, X.25)
+ Bob Larson, USC (OS-9)
+ Bert Laverman, Groningen U, Netherlands
+ Steve Layton
+ David Lawyer, UC Irvine
+ Jason Lehr
+ David LeVine, National Semiconductor Corporation
+ Daniel S. Lewart, UIUC
+ S.O. Lidie, Lehigh U
+ Tor Lillqvist, Helsinki U, Finland
+ David-Michael Lincke, U of St Gallen, Switzerland
+ Robert Lipe (for SCO makefile entries & advice)
+ Dean Long
+ Mike Long, Analog Devices, Norwood MA
+ Kevin Lowey, U of Saskatchewan (OS/2)
+ Andy Lowry, Columbia U
+ James Lummel, Caprica Telecomputing Resources (QNX)
+ Lewis McCarthy
+ David MacKenzie, Environmental Defense Fund, U of Maryland
+ John Mackin, University of Sidney, Australia
+ Martin Maclaren, Bath U, UK
+ Chris Maio, Columbia U CS Dept
+ Montserrat Mane, HP, Grenoble, France
+ Fulvio Marino, Olivetti, Ivrea, Italy
+ Arthur Marsh, dircsa.org.au
+ Peter Mauzey, Lucent Technologies
+ Tye McQueen, Utah State U
+ Ted Medin
+ Hellmuth Michaelis, Hanseatischer Computerservice GmbH, Hamburg, Germany
+ Leslie Mikesell, American Farm Bureau
+ Todd Miller, Courtesan Consulting
+ Gary Mills
+ Martin Minow, DEC (VMS)
+ Pawan Misra, Bellcore
+ Ken Mizialko, IBM, Manassas, VA
+ Wolfgang Moeller, DECUS Germany
+ Ray Moody, Purdue U
+ Bruce J Moore, Allen-Bradley Co, Highland Heights, OH (Atari ST)
+ Steve Morley, Convex
+ Peter Mossel, Columbia U
+ Tony Movshon, NYU
+ Lou Muccioli, Swanson Analysis Systems
+ Dan Murphy
+ Neal P. Murphy, Harsof Systems, Wonder Lake IL
+ Gary Mussar
+ John Nall, FSU
+ Jack Nelson, U of Pittsburgh
+ Jim Noble, Planning Research Corporation (Macintosh)
+ Ian O'Brien, Bath U, UK
+ Melissa O'Neill, SFU
+ John Owens
+ Thomas Pinkl, Health Business Systems Inc.
+ Michael Pins, Iowa Computer Aided Engineering Network
+ Andre' Pirard, University of Liege, Belgium
+ Paul Placeway, Ohio State U
+ Piet W. Plomp, ICCE, Groningen University, Netherlands
+ Ken Poulton, HP Labs
+ Manfred Prange, Oakland U
+ Christopher Pratt, APV Baker, UK
+ Frank Prindle, NADC
+ Tony Querubin, U of Hawaii
+ Jean-Pierre Radley
+ Anton Rang
+ Mike Rechtman
+ Scott Ribe
+ Alan Robiette, Oxford University, UK
+ Michel Robitaille, U of Montreal (Mac)
+ Huw Rogers, Schweizerische Kreditanstalt, Zuerich
+ Nigel Roles, Cambridge, England
+ Kai Uwe Rommel, Technische Universitaet Muenchen (OS/2)
+ Larry Rosenman (Amiga)
+ Jay Rouman, U of Michigan
+ Jack Rouse, SAS Institute (Data General and/or Apollo)
+ Stew Rubenstein, Harvard U (VMS)
+ Gerhard Rueckle, FH Darmstadt, Fb. E/Automatisierungstechnik
+ John Santos, EG&H
+ Bill Schilit, Columbia U
+ Ulli Schlueter, RWTH Aachen, Germany (OS-9, etc)
+ Michael Schmidt, U of Paderborn, Germany
+ Eric Schnoebelen, Convex
+ Benn Schreiber, DEC
+ Dan Schullman, DEC (modems, DIAL command, etc)
+ John Schultz, 3M
+ Steven Schultz, Contel (PDP-11)
+ Steven Schweda
+ APPP Scorer, Leeds Polytechnic, UK
+ Gordon Scott, Micro Focus, Newbury UK
+ Gisbert W. Selke, WIdO, Bonn, Germany
+ Kijal Shah
+ David Singer, IBM Almaden Research Labs
+ David Sizeland, U of London Medical School
+ Fridrik Skulason, Iceland
+ Rick Sladkey (Linux)
+ Dave Slate
+ Bradley Smith, UCLA
+ Fred Smith, Merk / Computrition
+ Richard S Smith, Cal State
+ Ryan Stanisfer, UNT
+ Bertil Stenstroem, Stockholm University Computer Centre (QZ), Sweden
+ James Sturdevant, CAP GEMENI AMERICA, Minneapolis
+ Peter Svanberg, Royal Techn. HS, Sweden
+ James R. Swenson, Accu-Weather, Inc.
+ Ted T'so, MIT (Linux)
+ Andy Tanenbaum, Vrije U, Amsterdam, Netherlands
+ Seth Theriault, Columbia U
+ Glen Thobe
+ Markku Toijala, Helsinki U of Technology
+ Teemu Torma, Helsinki U of Technology
+ Linus Torvalds, Helsinki
+ Rick Troxel, NIH
+ Warren Tucker, Tridom Corp, Mountain Park, GA
+ Dave Tweten, AMES-NAS
+ G Uddeborg, Sweden
+ Walter Underwood, Ford Aerospace
+ Pieter Van Der Linden, Centre Mondial, Paris
+ Ge van Geldorp, Netherlands
+ Fred van Kempen, MINIX User Group, Voorhout, Netherlands
+ Wayne Van Pelt, GE/CRD
+ Mark Vasoll, Oklahoma State U (V7 UNIX)
+ Konstantin Vinogradov, ICSTI, Moscow
+ Paul Vixie, DEC
+ Bernie Volz, Process Software
+ Eduard Vopicka, Prague University of Economics, Czech Republic
+ Martin Vorlaender
+ Dimitri Vulis, CUNY
+ Roger Wallace, Raytheon
+ Stephen Walton, Calif State U, Northridge (Amiga)
+ Jamie Watson, Adasoft, Switzerland (AIX)
+ Rick Watson, U of Texas (Macintosh)
+ Eric Weaver, Columbia U
+ Scott Weikart (Association for Progressive Communications)
+ Robert Weiner, Programming Plus, New York City
+ Lauren Weinstein, Vortex Technlogy
+ David Wexelblat, AT&T
+ Clark Wierda, Illuminati Online
+ Joachim Wiesel, U of Karlsruhe
+ Lon Willett, U of Utah
+ Michael Williams, UCLA
+ Nate Williams, U of Montana
+ David Wilson
+ Joellen Windsor, U of Arizona
+ Patrick Wolfe, Kuck & Associates, Inc.
+ Gregg Wonderly, Oklahoma State U (V7 UNIX)
+ Farrell Woods, Concurrent (formerly Masscomp)
+ Dave Woolley, CAP Communication Systems, London
+ Jack Woolley, SCT Corp
+ Frank Wortner
+ Ken Yap, formerly of U of Rochester
+ John Zeeff, Ann Arbor, MI
+*/
+
+#include "ckcker.h" /* Kermit symbols */
+#include "ckcnet.h" /* Network symbols */
+
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifndef NOSPL
+#include "ckuusr.h"
+#endif /* NOSPL */
+
+#ifdef OS2ONLY
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#endif /* OS2ONLY */
+
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#endif /* NT */
+
+#ifndef NOSERVER
+/* Text message definitions.. each should be 256 chars long, or less. */
+#ifdef MINIX
+char *srvtxt = "\r\n\
+Entering server mode.\r\n\0";
+#else
+#ifdef OLDMSG
+/*
+ It seems there was a large installation that was using C-Kermit 5A(165)
+ or thereabouts, which had deployed thousands of MS-DOS Kermit scripts in
+ scattered locations that looked for strings in the old server message,
+ which changed in 5A(183), August 1992.
+*/
+char *srvtxt = "\r\n\
+C-Kermit server starting. Return to your local machine by typing\r\n\
+its escape sequence for closing the connection, and issue further\r\n\
+commands from there. To shut down the C-Kermit server, issue the\r\n\
+FINISH or BYE command and then reconnect.\n\
+\r\n\0";
+#else
+#ifdef OSK
+char *srvtxt = "\r\012\
+Entering server mode. If your local Kermit software is menu driven, use\r\012\
+the menus to send commands to the server. Otherwise, enter the escape\r\012\
+sequence to return to your local Kermit prompt and issue commands from\r\012\
+there. Use SEND and GET for file transfer. Use REMOTE HELP for a list of\r\012\
+other available services. Use BYE or FINISH to end server mode.\r\012\0";
+#else /* UNIX, VMS, AOS/VS, and all others */
+char *srvtxt = "\r\n\
+Entering server mode. If your local Kermit software is menu driven, use\r\n\
+the menus to send commands to the server. Otherwise, enter the escape\r\n\
+sequence to return to your local Kermit prompt and issue commands from\r\n\
+there. Use SEND and GET for file transfer. Use REMOTE HELP for a list of\r\n\
+other available services. Use BYE or FINISH to end server mode.\r\n\0";
+#endif /* OSK */
+#endif /* OLDMSG */
+#endif /* MINIX */
+#else /* server mode disabled */
+char *srvtxt = "";
+#endif /* NOSERVER */
+
+int initflg = 0; /* sysinit() has executed... */
+int howcalled = I_AM_KERMIT; /* How I was called */
+int hmtopline = 0;
+int quitting = 0; /* I'm in the act of quitting */
+
+#ifdef IKSDCONF
+char * iksdconf = IKSDCONF; /* IKSD configuration file */
+int iksdcf = 0; /* Has IKSD c.f. been processed? */
+#endif /* IKSDCONF */
+
+int srvcdmsg = 0; /* [Server] CD message */
+char * cdmsgfile[8] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
+char * cdmsgstr = NULL;
+char * ckcdpath = NULL;
+
+#ifdef NLCHAR /* Text-file line terminator */
+CHAR feol = NLCHAR;
+#else
+CHAR feol = 0;
+#endif /* NLCHAR */
+
+int fblksiz = DBLKSIZ; /* File blocksize */
+int frecl = DLRECL; /* File record length */
+int frecfm = XYFF_S; /* File record format (default = stream) */
+int forg = XYFO_S; /* File organization (sequential) */
+int fcctrl = XYFP_N; /* File carriage control (ctrl chars) */
+int filecase = FILECASE; /* Case matters in filenames */
+int stathack = 1; /* Fast directory lookups by default */
+
+char uidbuf[UIDBUFLEN] = { NUL, NUL }; /* User ID buffer */
+int cfilef = 0; /* Application ("kerbang") file flag */
+char cmdfil[CKMAXPATH + 1] = { NUL, NUL }; /* Application file name */
+int haveurl = 0; /* URL given on command line */
+
+#ifndef NOXFER
+/* Multi-protocol support */
+
+struct ck_p ptab[NPROTOS] = { /* Initialize the Kermit part ... */
+ { "Kermit",
+ DRPSIZ, /* Receive packet size */
+ DSPSIZ, /* Send packet size */
+ 0, /* Send-packet-size-set flag */
+ DFWSIZ, /* Window size */
+
+#ifdef NEWDEFAULTS
+ PX_CAU, /* Control char unprefixing... */
+#else
+ PX_ALL,
+#endif /* NEWDEFAULTS */
+
+#ifdef VMS /* Default filename collision action */
+ XYFX_X, /* REPLACE for VAX/VMS */
+#else
+ XYFX_B, /* BACKUP for everybody else */
+#endif /* VMS */
+
+#ifdef OS2 /* Flag for file name conversion */
+ XYFN_L, /* Literal for OS2 */
+#else
+ XYFN_C, /* Converted for others */
+#endif /* OS2 */
+
+ PATH_OFF, /* Send pathnames OFF */
+ PATH_AUTO, /* Receive pathnames AUTO */
+ NULL, /* Host receive initiation string (binary) */
+ NULL, /* Host receive initiation string (text) */
+ NULL, /* Host server string */
+ NULL, /* External protocol send command (binary) */
+ NULL, /* External protocol send command (text) */
+ NULL, /* External protocol receive command (bin) */
+ NULL } /* External protocol receive command (txt) */
+#ifdef CK_XYZ
+,
+{"XMODEM", 128,128,-1,-1, 1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"XMODEM-CRC",128,128,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"YMODEM", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"YMODEM-g", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"ZMODEM", -1, -1,-1,-1,PX_WIL,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"Other", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+#endif /* CK_XYZ */
+};
+
+/* Declarations for Send-Init Parameters */
+
+int spsiz = DSPSIZ, /* Current packet size to send */
+ spmax = DSPSIZ, /* Biggest packet size we can send */
+ lastspmax = DSPSIZ, /* Send-packet size last used */
+ spsizr = DSPSIZ, /* Send-packet size requested */
+ spsizf = 0, /* Flag to override size negotiation */
+ rpsiz = DRPSIZ, /* Biggest we want to receive */
+ urpsiz = DRPSIZ, /* User-requested receive pkt size */
+ maxrps = MAXRP, /* Maximum incoming long packet size */
+ maxsps = MAXSP, /* Maximum outbound l.p. size */
+ maxtry = MAXTRY, /* Maximum retries per packet */
+ wslots = 1, /* Window size currently in use */
+ wslotr = DFWSIZ, /* Window size from SET WINDOW */
+ wslotn = 1, /* Window size negotiated in S-pkt */
+ timeouts = 0, /* For statistics reporting */
+ spackets = 0, /* ... */
+ rpackets = 0, /* ... */
+ retrans = 0, /* ... */
+ crunched = 0, /* ... */
+ wmax = 0, /* ... */
+ wcur = 0, /* ... */
+ srvidl = 0, /* Server idle timeout */
+ srvdis = 1, /* Server file xfer display */
+ srvtim = DSRVTIM, /* Server command wait timeout */
+ srvping = 1, /* Server keepalive */
+/*
+ timint is the timeout interval I use when waiting for a packet.
+ pkttim is the SET RECEIVE TIMEOUT value, sent to the other Kermit.
+ rtimo is the SET SEND TIMEOUT value. rtimo is the initial value of
+ timint. timint is changed by the value in the incoming negotiation
+ packet unless a SET SEND TIMEOUT command was given.
+*/
+ timint = DMYTIM, /* Timeout interval I use */
+ pkttim = URTIME, /* Timeout I want you to use */
+ rtimo = DMYTIM, /* Normal packet wait timeout */
+ timef = 0, /* Flag to override what you ask */
+#ifdef CK_TIMERS
+ rttflg = 1, /* Use dynamic round-trip timers */
+#else
+ rttflg = 0, /* Use fixed timer */
+#endif /* CK_TIMERS */
+ mintime = 1, /* Minimum timeout */
+ maxtime = 0, /* Maximum timeout */
+
+ npad = MYPADN, /* How much padding to send */
+ mypadn = MYPADN, /* How much padding to ask for */
+ bctr = DFBCT, /* Block check type requested */
+ bctu = 1, /* Block check type used */
+ bctl = 1, /* Block check length */
+ bctf = 0, /* Block check type 3 forced on all */
+ c_save = -1, /* Block check saving and restoring */
+ ss_save = -1, /* Slow-start saving and restoring */
+ ebq = MYEBQ, /* 8th bit prefix */
+ ebqflg = 0, /* 8th-bit quoting flag */
+ rqf = -1, /* Flag used in 8bq negotiation */
+ rq = 0, /* Received 8bq bid */
+ sq = 'Y', /* Sent 8bq bid */
+ rpt = 0, /* Repeat count */
+ rptq = MYRPTQ, /* Repeat prefix */
+ rptflg = 0, /* Repeat processing flag */
+ rptena = 1, /* Repeat processing enabled */
+ xfrcan = 1, /* Transfer cancellation enabled */
+ xfrint = 1, /* Transfer interruption enabled */
+ xfrchr = 3, /* Transfer cancel char = Ctrl-C */
+ xfrnum = 3, /* Need three of them by default */
+ g_xfrxla = -1;
+ char * xfrmsg = NULL; /* Message for f.t. display screen */
+#endif /* NOXFER */
+
+#ifdef NOCSETS
+int xfrxla = 0; /* Character-set translation */
+#else
+int xfrxla = 1; /* enabled or disabled */
+#endif /* NOCSETS */
+
+int havelfs = 0; /* Large file support available */
+
+#ifndef NOXFER
+int epktflg = 0; /* E-PACKET command active */
+
+int capas = 9, /* Position of Capabilities */
+ lpcapb = 2, /* Long Packet capability */
+ lpcapr = 1, /* requested */
+ lpcapu = 0, /* used */
+ swcapb = 4, /* Sliding Window capability */
+ swcapr = 1, /* requested (allowed) */
+ swcapu = 0, /* used */
+ atcapb = 8, /* Attribute capability */
+ atcapr = 1, /* requested */
+ atcapu = 0, /* used */
+ rscapb = 16, /* RESEND capability */
+ rscapr = 1, /* requested by default */
+ rscapu = 0, /* used */
+ lscapb = 32, /* Locking Shift capability */
+ lscapr = 1, /* requested by default */
+ lscapu = 0; /* used */
+
+/* Flags for whether to use particular attributes */
+
+int atenci = 1, /* Encoding in */
+ atenco = 1, /* Encoding out */
+ atdati = 1, /* Date in */
+ atdato = 1, /* Date out */
+ atdisi = 1, /* Disposition in/out */
+ atdiso = 1,
+ atleni = 1, /* Length in/out (both kinds) */
+ atleno = 1,
+ atblki = 1, /* Blocksize in/out */
+ atblko = 1,
+ attypi = 1, /* File type in/out */
+ attypo = 1,
+ atsidi = 1, /* System ID in/out */
+ atsido = 1,
+ atsysi = 1, /* System-dependent parameters in/out */
+ atsyso = 1;
+
+int dispos = 0; /* Disposition */
+
+#ifdef CK_PERMS
+int atlpri = 1,
+ atlpro = 1,
+ atgpri = 1,
+ atgpro = 1;
+#endif /* CK_PERMS */
+
+int atfrmi = 1, /* Record Format in/out */
+ atfrmo = 1;
+
+#ifdef STRATUS
+int atcrei = 1, /* Creator ID in/out */
+ atcreo = 1,
+ atacti = 1, /* Account in/out */
+ atacto = 1;
+#endif /* STRATUS */
+
+int sprmlen = -1; /* Send/Receive protocol parameter */
+int rprmlen = -1; /* string length limits */
+int sendipkts = 1; /* Send I packets */
+
+CHAR padch = MYPADC, /* Padding character to send */
+ mypadc = MYPADC, /* Padding character to ask for */
+ seol = MYEOL, /* End-Of-Line character to send */
+ eol = MYEOL, /* End-Of-Line character to look for */
+ ctlq = CTLQ, /* Control prefix in incoming data */
+ myctlq = CTLQ, /* Outbound control character prefix */
+ myrptq = MYRPTQ; /* Repeat prefix I want to use */
+
+int rptmin = 3; /* Repeat-count minimum */
+
+int usepipes = 0, /* Used for xfer to/from pipes */
+ g_usepipes = -1;
+
+char * filefile = NULL; /* File containing list of filenames */
+/* CD message filename list */
+
+char whoareu[16] = { NUL, NUL }; /* System ID of other Kermit */
+int sysindex = -1; /* and index to its system ID struct */
+int myindex = -1;
+int wearealike = 0; /* 2 Kermits have compatible sysids */
+char * cksysid = /* My system ID */
+#ifdef UNIX
+ "U1"
+#else
+#ifdef VMS
+ "D7"
+#else
+#ifdef OSK
+ "UD"
+#else
+#ifdef AMIGA
+ "L3"
+#else
+#ifdef MAC
+ "A3"
+#else
+#ifdef OS2
+#ifdef NT
+ "UN"
+#else /* NT */
+ "UO"
+#endif /* NT */
+#else /* OS2 */
+#ifdef datageneral
+ "F3"
+#else
+#ifdef GEMDOS
+ "K2"
+#else
+#ifdef STRATUS
+ "MV"
+#else
+ ""
+#endif /* STRATUS */
+#endif /* GEMDOS */
+#endif /* datageneral */
+#endif /* OS2 */
+#endif /* MAC */
+#endif /* AMIGA */
+#endif /* OSK */
+#endif /* VMS */
+#endif /* UNIX */
+ ;
+
+int oopts = -1; /* O-Packet Options */
+int omode = -1; /* O-Packet Transfer Mode */
+int oname = -1; /* O-Packet Filename Options */
+int opath = -1; /* O-Packet Pathname Options */
+
+struct zattr iattr; /* Incoming file attributes */
+
+#ifdef VMS
+/* VMS labeled file default options - name only. */
+int lf_opts = LBL_NAM;
+#else
+#ifdef OS2
+/* OS/2 labeled file default options, all attributes but archived. */
+unsigned long int lf_opts = LBL_EXT|LBL_HID|LBL_RO|LBL_SYS;
+#else
+int lf_opts = 0;
+#endif /* OS2 */
+#endif /* VMS */
+
+/* Packet-related variables */
+
+int pktnum = 0, /* Current packet number */
+ sndtyp = 0, /* Type of packet just sent */
+ rcvtyp = 0, /* Type of packet just received */
+ rsn, /* Received packet sequence number */
+ rln, /* Received packet length */
+ size, /* Current size of output pkt data */
+ osize, /* Previous output packet data size */
+ maxsize, /* Max size for building data field */
+ spktl = 0, /* Length packet being sent */
+ rpktl = 0, /* Length of packet just received */
+ pktpaus = 0, /* Interpacket pause interval, msec */
+ rprintf, /* REMOTE PRINT flag */
+ rmailf, /* MAIL flag */
+ xferstat = -1, /* Status of last transaction */
+ filestatus = 0; /* Status of last file transfer */
+
+CHAR pktmsgbuf[PKTMSGLEN+1];
+CHAR *epktmsg = pktmsgbuf;
+
+#ifdef pdp11
+int srvcmdlen = MAXRP; /* srvcmd buffer length */
+#else
+#ifdef DYNAMIC
+int srvcmdlen = MAXRP;
+#else
+int srvcmdlen = 0;
+#endif /* DYNAMIC */
+#endif /* pdp11 */
+
+CHAR
+#ifdef pdp11
+ srvcmdbuf[MAXRP+4],
+ *srvcmd = srvcmdbuf,
+#else
+#ifdef DYNAMIC
+ *srvcmd = (CHAR *)0, /* Where to decode server command */
+#else
+ srvcmdbuf[MAXRP+4],
+ *srvcmd = srvcmdbuf,
+#endif /* DYNAMIC */
+#endif /* pdp11 */
+ padbuf[96], /* Buffer for send-padding */
+ *recpkt,
+ *rdatap, /* Pointer to received packet data */
+ *data = (CHAR *)0, /* Pointer to send-packet data */
+ *srvptr, /* Pointer to srvcmd */
+ mystch = SOH, /* Outbound packet-start character */
+ stchr = SOH; /* Incoming packet-start character */
+
+/* File-related variables */
+
+#ifndef NOMSEND /* Multiple SEND */
+struct filelist * filehead = NULL; /* SEND list */
+struct filelist * filetail = NULL;
+struct filelist * filenext = NULL;
+int addlist = 0;
+#endif /* NOMSEND */
+
+char filnam[CKMAXPATH + 1]; /* Name of current file. */
+char ofilnam[CKMAXPATH + 1]; /* Original name. */
+
+int pipesend = 0; /* Nonzero if sending from pipe */
+#ifdef PIPESEND
+char * sndfilter = NULL; /* Send and receive filters */
+char * rcvfilter = NULL;
+#endif /* PIPESEND */
+
+char ** sndarray = NULL; /* SEND /ARRAY pointer and range */
+#ifndef NOSPL
+int sndxlo = -1, sndxhi = -1, sndxin = -1;
+#endif /* NOSPL */
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+int ngetpath = 0; /* GET search path */
+int fromgetpath = 0;
+char * getpath[MAXGETPATH];
+char * x_user = NULL; /* Server login information */
+char * x_passwd = NULL;
+char * x_acct = NULL;
+#endif /* NOSERVER */
+
+int x_login = 0; /* Login required */
+int x_logged = 0; /* User is logged in */
+
+extern int timelimit;
+
+#ifdef CK_LOGIN
+int logintimo = 300; /* Login timeout */
+char * userfile = NULL; /* Forbidden user file */
+#endif /* CK_LOGIN */
+#ifdef IKSD
+char * anonfile = NULL; /* Anonymous login init file */
+char * anonroot = NULL; /* Anonymous file-system root */
+int iks_timo = 300; /* 5 minutes idle timo */
+int iks_retry = 3; /* 3 attempts at login */
+#endif /* IKSD */
+
+#ifdef CKSYSLOG
+extern VOID zsyslog();
+extern int ckxlogging, ckxsyslog;
+#endif /* CKSYSLOG */
+
+CK_OFF_T fsize = (CK_OFF_T)0, /* Size of current file */
+ sendstart = (CK_OFF_T)0, /* SEND start position */
+ calibrate = (CK_OFF_T)0; /* Nonzero if calibration run */
+
+int nzxopts = 0; /* Options for nzxpand() */
+int nfils = 0; /* Number of files in file group */
+int wildena = 1; /* Wildcard expansion enabled */
+#ifdef UNIX
+int wildxpand = 0; /* Who expands wildcards, 0=Kermit.. */
+#else /* UNIX */
+#ifdef STRATUS
+int wildxpand = 1; /* 1=Shell. */
+#endif /* STRATUS */
+#endif /* UNIX */
+#ifdef UNIXOROSK
+int matchdot = 0; /* Whether to match dot files */
+#else
+int matchdot = 1;
+#endif /* UNIXOROSK */
+int matchfifo = 0; /* Whether to match FIFO "files" */
+int clfils = 0; /* Flag for command-line files */
+int stayflg = 0; /* Flag for "stay", i.e. "-S" */
+int xfinish = 0; /* Flag for FINISH = EXIT */
+long ztusec = -1L; /* Used with ztime() */
+long ztmsec = -1L; /* Ditto */
+
+/* Communication device / connection variables */
+
+char ttname[TTNAMLEN+1]; /* Name of communication device */
+
+#ifdef MAC
+int connected = 0; /* True if connected */
+int startconnected; /* initial state of connected */
+#endif /* MAC */
+
+long speed = -1L; /* Communication device speed */
+int wasclosed = 0; /* Connection was just closed */
+int whyclosed = WC_REMO; /* why it was closed */
+int qnxportlock = 0; /* QNX port locking on/off */
+
+#ifndef CLSONDISC
+#define CLSONDISC 0
+#endif /* CLSONDISC */
+
+int cxflow[CXT_MAX+1]; /* See initflow() */
+
+#ifndef NOSHOW
+char * floname[] = { /* Flow control names */
+ "none", "xon/xoff", "rts/cts", "dtr/cd", "etx/ack", "string",
+ "xxx1", "xxx2", "dtr/cts", "keep", "auto"
+};
+int nfloname = (sizeof(floname) / sizeof(char *));
+
+char * cxname[] = { /* Connection type names */
+ "remote", "direct-serial", "modem", "tcp/ip", "x.25", "decnet",
+ "lat", "netbios", "named-pipe", "ssh", "pipe"
+};
+int ncxname = (sizeof(cxname) / sizeof(char *));
+#endif /* NOSHOW */
+
+int parity = DEFPAR, /* Parity specified, 0,'e','o',etc */
+ hwparity = 0, /* Hardware parity for serial port */
+ stopbits = -1, /* Stop bits for serial port */
+ clsondisc = CLSONDISC, /* Serial port close on disconnect */
+ autopar = 0, /* Automatic parity change flag */
+ sosi = 0, /* Shift-In/Out flag */
+ flow = 0, /* Flow control (see initflow()) */
+ autoflow = 1, /* Automatic flow control */
+ turn = 0, /* Line turnaround handshake flag */
+ turnch = XON, /* Line turnaround character */
+ duplex = 0, /* Duplex, full by default */
+ escape = DFESC, /* Escape character for connect */
+ ckdelay = DDELAY, /* Initial delay before sending */
+ tnlm = 0; /* Terminal newline mode */
+
+/* Networks for SET HOST */
+
+#ifdef BIGBUFOK
+#define MYHOSTL 1024
+#else
+#define MYHOSTL 100
+#endif /* BIGBUFOK */
+
+char myhost[MYHOSTL]; /* Local host name */
+int network = 0; /* Network vs serial connection */
+int inserver = 0; /* Running as an Internet server */
+int isguest = 0; /* User is anonymous */
+char * clienthost = NULL; /* Peer host name or address */
+int tcp_incoming = 0; /* Incoming TCP connection? */
+
+#ifdef NETCONN
+#ifdef TCPSOCKET
+int nettype = NET_TCPB; /* Default network type */
+#else
+#ifdef SUNX25
+int nettype = NET_SX25;
+#else
+#ifdef IBMX25
+int nettype = NET_IX25;
+#else
+#ifdef HPX25
+int nettype = NET_HX25;
+#else
+#ifdef STRATUSX25
+int nettype = NET_VX25;
+#else
+#ifdef DECNET
+int nettype = NET_DEC;
+#else
+#ifdef SUPERLAT
+int nettype = NET_SLAT;
+#else
+int nettype = NET_NONE;
+#endif /* SUPERLAT */
+#endif /* DECNET */
+#endif /* STRATUSX25 */
+#endif /* HPX25 */
+#endif /* IBMX25 */
+#endif /* SUNX25 */
+#endif /* TCPSOCKET */
+#else /* NETCONN */
+int nettype = NET_NONE;
+#endif /* NETCONN */
+
+#ifdef ANYX25
+int revcall = 0; /* X.25 reverse call not selected */
+int closgr = -1; /* X.25 closed user group */
+int cudata = 0; /* X.25 call user data not specified */
+char udata[MAXCUDATA]; /* X.25 call user data */
+
+#ifdef IBMX25
+/*
+ I was unable to find any pre-defined MAX values for x25 addresses - the
+ addresses that I've seen have been around 10-12 characters 32 is probably
+ enough, 64 is hopefully safe for everyone.
+*/
+ x25addr_t local_nua = {'\0'}; /* local x.25 address */
+ x25addr_t remote_nua = {'\0'}; /* remote x.25 address */
+ char x25name[32] = {'\0'}; /* x25 device name, sx25a0 or sx25a1 */
+ char x25dev[64] = "/dev/x25pkt"; /* x25 device in /dev */
+ int x25port = 0; /* port used for X.25 - AIX only */
+#endif /* IBMX25 */
+
+#ifndef IBMX25
+/*
+ This condition is unrelated to the above IBMX25 condition.
+ IBM X.25 doesn't have PAD support.
+*/
+ CHAR padparms[MAXPADPARMS+1]; /* X.3 parameters */
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+/* Other items */
+
+int isinterrupted = 0; /* Used in exception handling */
+int what = W_INIT; /* What I am doing */
+int lastxfer = 0; /* Last transfer (send or receive) */
+
+extern int mdmtyp; /* Modem (/network) type */
+
+#ifdef NT
+extern int StartedFromDialer;
+#ifdef NTSIG
+extern int TlsIndex;
+#endif /* NTSIG */
+#ifdef NTASM
+unsigned long ESPToRestore; /* Ditto */
+#endif /* NTASM */
+#endif /* NT */
+
+#ifdef OS2PM
+int os2pm = 0; /* OS/2 Presentation Manager flag */
+#endif /* OS2PM */
+
+/* Terminal screen size, if known, -1 means unknown. */
+
+#ifdef OS2
+#include "ckocon.h"
+#ifdef KUI
+int tt_rows[VNUM] = {24,24,25,1}; /* Rows (height) */
+int tt_cols[VNUM] = {80,80,80,80}; /* Columns (width) */
+int cmd_rows = 24, cmd_cols = 80; /* Command/console screen dimensions */
+#else /* KUI */
+int tt_rows[VNUM] = {-1,24,25,1}; /* Rows (height) */
+int tt_cols[VNUM] = {-1,80,80,80}; /* Columns (width) */
+int cmd_rows = -1, cmd_cols = -1; /* Command/console screen dimensions */
+#endif /* KUI */
+int k95stdio = 0; /* Stdio threads */
+int tt_bell = XYB_AUD | XYB_SYS; /* BELL AUDIBLE (system sounds) */
+#else /* OS2 */
+int tt_rows = -1; /* Rows (height) */
+int tt_cols = -1; /* Columns (width) */
+int cmd_rows = 24, cmd_cols = 80; /* Command/console screen dimensions */
+int tt_bell = XYB_AUD; /* BELL ON */
+#endif /* OS2 */
+
+int tt_print = 0; /* Transparent print disabled */
+int tt_escape = 1; /* Escaping back is enabled */
+int tt_scroll = 1; /* Scrolling operations are enabled */
+
+int tn_exit = 0; /* Exit on disconnect */
+
+int exitonclose = 0; /* Exit on close */
+int exithangup = 1; /* Hangup on exit */
+int haveline = 0; /* SET LINE or SET HOST in effect */
+int tlevel = -1; /* Take-file command level */
+int hints = 1; /* Whether to give hints */
+
+#ifdef NOLOCAL
+int remonly = 1; /* Remote-mode-only advisory (-R) */
+int nolocal = 1; /* Remote-only strictly enforced */
+#else
+int remonly = 0;
+int nolocal = 0;
+int cx_status = 0; /* CONNECT return status */
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+extern int cmdlvl; /* Command level */
+extern int maclvl; /* Macro invocation level */
+#endif /* NOSPL */
+
+int protocol = PROTO_K; /* File transfer protocol = Kermit */
+
+#ifdef NEWDEFAULTS
+int prefixing = PX_CAU;
+#else
+int prefixing = PX_ALL;
+#endif /* NEWDEFAULTS */
+
+extern short ctlp[]; /* Control-prefix table */
+
+int carrier = CAR_AUT; /* Pay attention to carrier signal */
+int cdtimo = 0; /* Carrier wait timeout */
+int xitsta = GOOD_EXIT; /* Program exit status */
+
+#ifdef VMS /* Default filename collision action */
+int fncact = XYFX_X; /* REPLACE for VMS */
+#else
+int fncact = XYFX_B; /* BACKUP for everybody else */
+#endif /* VMS */
+
+int fncsav = -1; /* For saving & restoring the above */
+int bgset = -1; /* BACKGROUND mode set explicitly */
+
+int cmdint = 1; /* Interrupts are allowed */
+#ifdef UNIX
+int xsuspend = DFSUSP; /* Whether SUSPEND command, etc, */
+#else /* is to be allowed. */
+int xsuspend = 0;
+#endif /* UNIX */
+
+/* Statistics variables */
+
+CK_OFF_T
+ flci, /* Characters from line, current file */
+ flco, /* Chars to line, current file */
+ tlci, /* Chars from line in transaction */
+ tlco, /* Chars to line in transaction */
+ ffc, /* Chars to/from current file */
+ tfc; /* Chars to/from files in transaction */
+
+long filcnt, /* Number of files in transaction */
+ filrej, /* Number of files rejected in transaction */
+ cps = 0L, /* Chars/sec last transfer */
+ peakcps = 0L, /* Peak chars/sec last transfer */
+ ccu, /* Control chars unprefixed in transaction */
+ ccp, /* Control chars prefixed in transaction */
+ rptn; /* Repeated characters compressed */
+
+int tsecs = 0; /* Seconds for transaction */
+int fsecs = 0; /* Per-file timer */
+
+#ifdef GFTIMER
+CKFLOAT
+ fpfsecs = 0.0, /* Floating point per-file timer */
+ fptsecs = 0.0; /* and per-transaction timer */
+#endif /* GFTIMER */
+
+/* Flags */
+
+int deblog = 0, /* Debug log is open */
+ debok = 1, /* Debug log is not disabled */
+ debxlen = 54, /* Default length for debug strings */
+ debses = 0, /* Flag for DEBUG SESSION */
+ debtim = 0, /* Include timestamp in debug log */
+ debmsg = 0, /* Debug messages on/off */
+ pktlog = 0, /* Flag for packet logging */
+ seslog = 0, /* Session logging */
+ dialog = 0, /* DIAL logging */
+ tralog = 0, /* Transaction logging */
+ tlogfmt = 1, /* Transaction log format (verbose) */
+ tlogsep = (int)',', /* Transaction log field separator */
+ displa = 0, /* File transfer display on/off */
+ stdouf = 0, /* Flag for output to stdout */
+ stdinf = 0, /* Flag for input from stdin */
+ xflg = 0, /* Flag for X instead of F packet */
+ hcflg = 0, /* Doing Host command */
+ dest = DEST_D, /* Destination for packet data */
+ zchkod = 0, /* zchko() should work for dirs too? */
+ zchkid = 0, /* zchki() should work for dirs too? */
+
+/* If you change this, also see struct ptab above... */
+
+#ifdef OS2 /* Flag for file name conversion */
+ fncnv = XYFN_L, /* Default is Literal in OS/2, */
+ f_save = XYFN_L, /* (saved copy of same) */
+#else
+ fncnv = XYFN_C, /* elsewhere Convert them */
+ f_save = XYFN_C, /* (ditto) */
+#endif /* OS2 */
+
+ fnspath = PATH_OFF, /* Send file path */
+ fnrpath = PATH_AUTO, /* Receive file path */
+ fackpath = 1, /* Send back path in ACK to F */
+ binary = XYFT_B, /* Default file transfer mode */
+ b_save = XYFT_B, /* Saved file mode */
+ eofmethod = 0, /* EOF detection method (length) */
+
+#ifdef OS2
+ cursor_save = -1, /* Cursor state */
+#endif /* OS2 */
+
+ xfermode = XMODE_A, /* Transfer mode, manual or auto */
+ xfiletype = -1, /* Transfer only text (or binary) */
+ recursive = 0, /* Recursive directory traversal */
+ nolinks = 2, /* Don't follow symbolic links */
+ skipbup = 0, /* Skip backup files when sending */
+ sendmode = SM_SEND, /* Which type of SEND operation */
+ slostart = 1, /* Slow start (grow packet lengths) */
+ cmask = 0377, /* CONNECT (terminal) byte mask */
+ fmask = 0377, /* File byte mask */
+ ckwarn = 0, /* Flag for file warning */
+ quiet = 0, /* Be quiet during file transfer */
+ local = 0, /* 1 = local mode, 0 = remote mode */
+ cxtype = CXT_REMOTE, /* Connection type */
+ server = 0, /* Flag for I Am Server */
+ query = 0, /* Flag for Query active */
+ justone = 0, /* Server should do Just One command */
+ urserver = 0, /* Flag for You Are Server */
+ bye_active = 0, /* Flag for BYE command active */
+ diractive = 0, /* Flag for DIRECTORY command active */
+ cdactive = 0, /* Flag for CD command active */
+ cflg = 0, /* Connect before transaction */
+ cnflg = 0, /* Connect after transaction */
+ cxseen = 0, /* Flag for cancelling a file */
+ czseen = 0, /* Flag for cancelling file group */
+ fatalio = 0, /* Flag for fatal i/o error */
+ discard = 0, /* Flag for file to be discarded */
+ keep = SET_AUTO, /* Keep incomplete files = AUTO */
+ unkcs = 1, /* Keep file w/unknown character set */
+#ifdef VMS
+ filepeek = 0, /* Inspection of files */
+#else
+#ifdef datgeneral
+ filepeek = 0,
+#else
+ filepeek = 1,
+#endif /* datageneral */
+#endif /* VMS */
+ nakstate = 0, /* In a state where we can send NAKs */
+ dblchar = -1, /* Character to double when sending */
+ moving = 0, /* MOVE = send, then delete */
+ reliable = SET_AUTO, /* Nonzero if transport is reliable */
+ xreliable = -1,
+ setreliable = 0,
+ urclear = 0, /* Nonzero for clear channel to you */
+ clearrq = SET_AUTO, /* SET CLEARCHANEL value */
+ cleared = 0,
+ streaming = 0, /* Nonzero if streaming is active */
+ streamok = 0, /* Nonzero if streaming negotiated */
+ streamrq = SET_AUTO, /* SET STREAMING value */
+ streamed = -1; /* Whether we streamed last time */
+
+char * snd_move = NULL; /* Move file after sending it */
+char * snd_rename = NULL; /* Rename file after sending it */
+char * rcv_move = NULL; /* Move file after receiving it */
+char * rcv_rename = NULL; /* Rename file after receiving it */
+
+char * g_snd_move = NULL;
+char * g_snd_rename = NULL;
+char * g_rcv_move = NULL;
+char * g_rcv_rename = NULL;
+
+#ifdef CK_TRIGGER
+char *tt_trigger[TRIGGERS] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
+CHAR *tt_trmatch[TRIGGERS] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
+char *triggerval = NULL;
+#endif /* CK_TRIGGER */
+
+int ckxlogging = 0; /* Flag for syslogging active */
+int ikdbopen = 0; /* Flag for IKSD database active */
+int dbinited = 0; /* Flag for IKSDB record init'd */
+#ifndef CKSYSLOG
+int ckxsyslog = 0; /* Logging level 0 */
+#else
+#ifdef SYSLOGLEVEL
+int ckxsyslog = SYSLOGLEVEL; /* Logging level specified */
+#else
+int ckxsyslog = SYSLG_DF; /* Default logging level */
+#endif /* SYSLOGLEVEL */
+#endif /* CKSYSLOG */
+
+#ifndef NOHELP
+#ifndef NOCMDL
+_PROTOTYP( VOID iniopthlp, (void) ); /* Command-line help initializer */
+#endif /* NOCMDL */
+#endif /* NOHELP */
+
+_PROTOTYP( VOID getexedir, (void) );
+_PROTOTYP( int putnothing, (char) );
+
+#ifdef IKSD
+_PROTOTYP( VOID doiksdinit, (void) );
+_PROTOTYP( VOID iksdinit, (void) );
+_PROTOTYP( VOID doiklog, (void) );
+_PROTOTYP( int dbinit, (void) );
+#endif /* IKSD */
+
+/* Variables passed from command parser to protocol module */
+
+#ifndef NOSPL
+#ifndef NOICP
+#ifdef CK_APC
+_PROTOTYP( VOID apconect, (void) );
+#endif /* CK_APC */
+#ifdef OS2
+extern int initvik;
+#endif /* OS2 */
+#endif /* NOICP */
+#endif /* NOSPL */
+char *clcmds = NULL; /* Pointer to command-line commands */
+
+#ifndef NOSETKEY
+extern KEY *keymap;
+extern MACRO *macrotab;
+#endif /* NOSETKEY */
+
+#ifndef NOPUSH
+int nopush = 0; /* PUSH enabled */
+#else
+int nopush = 1; /* PUSH disabled */
+#endif /* NOPUSH */
+
+CHAR sstate = (CHAR) 0; /* Starting state for automaton */
+CHAR zstate = (CHAR) 0; /* For remembering sstate */
+char * printername = NULL; /* NULL if printer not redirected */
+int printpipe = 0; /* For SET PRINTER */
+int noprinter = 0;
+
+#ifndef NOXFER
+char *cmarg = ""; /* Pointer to command data */
+char *cmarg2 = ""; /* Pointer to 2nd command data */
+char **cmlist; /* Pointer to file list in argv */
+
+#ifdef CK_AUTODL /* Autodownload */
+int autodl = 1; /* Enabled by default */
+#else
+int autodl = 0; /* (or if not implemented). */
+#endif /* CK_AUTODL */
+int adl_err = 1; /* 1 = stop on error */
+#ifdef KUI
+int adl_ask = 1; /* 1 = file dialog on autodownload */
+#else
+int adl_ask = 0; /* 0 = no file dialog */
+#endif /* KUI */
+#ifdef OS2 /* AUTODOWNLOAD parameters */
+int adl_kmode = ADL_PACK, /* Match Packet to signal download */
+ adl_zmode = ADL_PACK;
+char * adl_kstr = NULL; /* KERMIT Download String */
+char * adl_zstr = NULL; /* ZMODEM Download String */
+#endif /* OS2 */
+
+int remfile = 0, rempipe = 0, remappd = 0; /* REMOTE output redirection */
+char * remdest = NULL;
+
+#ifndef NOSERVER
+/*
+ Server services:
+ 0 = disabled
+ 1 = enabled in local mode
+ 2 = enabled in remote mode
+ 3 = enabled in both local and remote modes
+ only as initial (default) values.
+*/
+int en_xit = 2; /* EXIT */
+int en_cwd = 3; /* CD/CWD */
+int en_cpy = 3; /* COPY */
+int en_del = 2; /* DELETE */
+int en_mkd = 3; /* MKDIR */
+int en_rmd = 2; /* RMDIR */
+int en_dir = 3; /* DIRECTORY */
+int en_fin = 3; /* FINISH */
+int en_get = 3; /* GET */
+#ifndef NOPUSH
+int en_hos = 2; /* HOST enabled */
+#else
+int en_hos = 0; /* HOST disabled */
+#endif /* NOPUSH */
+int en_ren = 3; /* RENAME */
+int en_sen = 3; /* SEND */
+int en_set = 3; /* SET */
+int en_spa = 3; /* SPACE */
+int en_typ = 3; /* TYPE */
+int en_who = 3; /* WHO */
+#ifdef datageneral
+/* Data General AOS/VS can't do this */
+int en_bye = 0; /* BYE */
+#else
+int en_bye = 2; /* PCs in local mode... */
+#endif /* datageneral */
+int en_asg = 3; /* ASSIGN */
+int en_que = 3; /* QUERY */
+int en_ret = 2; /* RETRIEVE */
+int en_mai = 3; /* MAIL */
+int en_pri = 3; /* PRINT */
+int en_ena = 3; /* ENABLE */
+#else
+int en_xit = 0, en_cwd = 0, en_cpy = 0, en_del = 0, en_mkd = 0, en_rmd = 0,
+ en_dir = 0, en_fin = 0, en_get = 0, en_hos = 0, en_ren = 0, en_sen = 0,
+ en_set = 0, en_spa = 0, en_typ = 0, en_who = 0, en_bye = 0, en_asg = 0,
+ en_que = 0, en_ret = 0, en_mai = 0, en_pri = 0, en_ena = 0;
+#endif /* NOSERVER */
+#endif /* NOXFER */
+
+/* Miscellaneous */
+
+char **xargv; /* Global copies of argv */
+int xargc; /* and argc */
+int xargs; /* an immutable copy of argc */
+char *xarg0; /* and of argv[0] */
+char *pipedata; /* Pointer to -P (pipe) data */
+
+extern char *dftty; /* Default tty name from ck?tio.c */
+extern int dfloc; /* Default location: remote/local */
+extern int dfprty; /* Default parity */
+extern int dfflow; /* Default flow control */
+
+#ifdef TNCODE
+extern int tn_deb;
+#endif /* TNCODE */
+/*
+ Buffered file input and output buffers. See getpkt() in ckcfns.c
+ and zoutdump() in the system-dependent file i/o module (usually ck?fio.c).
+*/
+#ifndef DYNAMIC
+/* Now we allocate them dynamically, see getiobs() below. */
+char zinbuffer[INBUFSIZE], zoutbuffer[OBUFSIZE];
+#endif /* DYNAMIC */
+char *zinptr, *zoutptr;
+int zincnt, zoutcnt;
+int zobufsize = OBUFSIZE;
+int zofbuffer = 1;
+int zofblock = 1;
+
+#ifdef SESLIMIT
+int seslimit = 0;
+#endif /* SESLIMIT */
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+
+_PROTOTYP( int getiobs, (VOID) );
+
+/* M A I N -- C-Kermit main program */
+
+#include <signal.h>
+
+#ifndef VMS
+#include <time.h>
+#endif
+
+#ifndef NOCCTRAP
+#include <setjmp.h>
+#include "ckcsig.h"
+ckjmpbuf cmjbuf;
+#ifdef GEMDOS /* Special for Atari ST */
+cc_clean(); /* This can't be right? */
+#endif /* GEMDOS */
+#endif /* NOCCTRAP */
+
+#ifndef NOXFER
+/* Info associated with a system ID */
+
+struct sysdata sysidlist[] = { /* Add others as needed... */
+ { "0", "anonymous", 0, NUL, 0, 0, 0 },
+ { "A1", "Apple II", 0, NUL, 0, 0, 3 }, /* fix this */
+ { "A3", "Macintosh", 1, ':', 0, 2, 1 },
+ { "D7", "VMS", 0, ']', 1, 0, 0 },
+ { "DA", "RSTS/E", 0, ']', 1, 0, 3 }, /* (i think...) */
+ { "DB", "RT11", 0, NUL, 1, 0, 3 }, /* (maybe...) */
+ { "F3", "AOS/VS", 1, ':', 0, 0, 2 },
+ { "I1", "VM/CMS", 0, NUL, 0, 0, 0 },
+ { "I2", "MVS/TSO", 0, NUL, 0, 0, 0 },
+ { "I4", "MUSIC", 0, NUL, 0, 0, 0 },
+ { "I7", "CICS", 0, NUL, 0, 0, 0 },
+ { "I9", "MVS/ROSCOE", 0, NUL, 0, 0, 0 },
+ { "K2", "Atari ST", 1, '\\', 1, 0, 3 },
+ { "L3", "Amiga", 1, '/', 1, 0, 2 },
+ { "MV", "Stratus VOS", 1, '>', 0, 1, 0 },
+ { "N3", "Apollo Aegis", 1, '/', 0, 3, 2 },
+ { "U1", "UNIX", 1, '/', 0, 3, 2 },
+ { "U8", "MS-DOS", 1, '\\', 1, 0, 3 },
+ { "UD", "OS-9", 1, '/', 0, 3, 2 },
+ { "UN", "Windows-32", 1, '\\', 1, 2, 3 },
+ { "UO", "OS/2", 1, '\\', 1, 2, 3 }
+};
+static int nxxsysids = (sizeof(sysidlist) / sizeof(struct sysdata));
+
+/* Given a Kermit system ID code, return the associated name string */
+/* and some properties of the filenames... */
+
+char *
+getsysid(s) char * s; { /* Get system-type name */
+ int i;
+ if (!s) return("");
+ for (i = 0; i < nxxsysids; i++)
+ if (!strcmp(sysidlist[i].sid_code,s))
+ return(sysidlist[i].sid_name);
+ return(s);
+}
+
+int
+getsysix(s) char *s; { /* Get system-type index */
+ int i;
+ if (!s) return(-1);
+ for (i = 0; i < nxxsysids; i++)
+ if (!strcmp(sysidlist[i].sid_code,s))
+ return(i);
+ return(-1);
+}
+#endif /* NOXFER */
+
+/* Tell if a pathname is absolute (versus relative) */
+/* This should be parceled out to each of the ck*fio.c modules... */
+/* VMS isabsolute() is now in ckvfio.c. */
+#ifndef VMS
+int
+isabsolute(path) char * path; {
+ int rc = 0;
+ int x;
+ if (!path)
+ return(0);
+ if (!*path)
+ return(0);
+ x = (int) strlen(path);
+ debug(F111,"isabsolute",path,x);
+#ifdef UNIX
+ if (*path == '/'
+#ifdef DTILDE
+ || *path == '~'
+#endif /* DTILDE */
+ )
+ rc = 1;
+#else /* def UNIX */
+#ifdef OS2
+ if (*path == '/' || *path == '\\')
+ rc = 1;
+ else if (isalpha(*path) && x > 2)
+ if (*(path+1) == ':' && (*(path +2) == '/' || *(path+2) == '\\'))
+ rc = 1;
+#else /* def OS2 */
+#ifdef AMIGA
+ if (*path == '/'
+#ifdef DTILDE
+ || *path == '~'
+#endif /* DTILDE */
+ )
+ rc = 1;
+#else /* def AMIGA */
+#ifdef OSK
+ if (*path == '/'
+#ifdef DTILDE
+ || *path == '~'
+#endif /* DTILDE */
+ )
+ rc = 1;
+#else /* def OSK */
+#ifdef datageneral
+ if (*path == ':')
+ rc = 1;
+#else /* def datageneral */
+#ifdef MAC
+ rc = 0; /* Fill in later... */
+#else /* def MAC */
+#ifdef STRATUS
+ rc = 0; /* Fill in later... */
+#else /* def STRATUS */
+#ifdef GEMDOS
+ if (*path == '/' || *path == '\\')
+ rc = 1;
+ else if (isalpha(*path) && x > 1)
+ if (*(path+1) == ':')
+ rc = 1;
+#endif /* GEMDOS */
+#endif /* STRATUS */
+#endif /* MAC */
+#endif /* datageneral */
+#endif /* OSK */
+#endif /* AMIGA */
+#endif /* OS2 */
+#endif /* UNIX */
+ debug(F101,"isabsolute rc","",rc);
+ return(rc);
+}
+#endif /* ndef VMS */
+
+/* See if I have direct access to the keyboard */
+
+int
+is_a_tty(n) int n; {
+#ifdef UNIX
+ extern int ttfdflg;
+ if (ttfdflg > 0)
+ return(1);
+#endif /* UNIX */
+#ifdef KUI
+ return 1;
+#else /* KUI */
+#ifdef NT
+ if (isWin95())
+ return(1);
+ else
+ return(_isatty(n));
+#else
+#ifdef IKSD
+ if (inserver)
+ return(1);
+ else
+#endif /* IKSD */
+ return(isatty(n));
+#endif /* NT */
+#endif /* KUI */
+}
+
+#ifndef NOXFER
+VOID
+initxlist() {
+ extern char * sndexcept[], * rcvexcept[];
+ int i;
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ sndexcept[i] = NULL;
+ rcvexcept[i] = NULL;
+ }
+}
+#endif /* NOXFER */
+
+/* Initialize flow control table */
+
+VOID
+initflow() { /* Default values for flow control */
+#ifdef VMS /* for each kind of connection. */
+ /* The VMS telnet terminal driver treats "none" as request to lose chars */
+ cxflow[CXT_REMOTE] = FLO_XONX; /* Remote mode... */
+#else
+#ifdef HPUX
+ /* Ditto for HP-UX */
+ cxflow[CXT_REMOTE] = FLO_XONX; /* Remote mode... */
+#else
+ /* The temptation is to make this one FLO_KEEP but don't!!! */
+ /* It totally wrecks binary-file transfer when coming in via Telnet. */
+ /* In UNIX at least... */
+ cxflow[CXT_REMOTE] = FLO_NONE;
+#endif /* HPUX */
+#endif /* VMS */
+
+#ifdef VMS
+ cxflow[CXT_DIRECT] = FLO_XONX; /* Direct serial connections... */
+#else
+ cxflow[CXT_DIRECT] = FLO_NONE;
+#endif /* VMS */
+
+#ifdef CK_RTSCTS
+ cxflow[CXT_MODEM] = FLO_RTSC; /* Modem connections... */
+#else
+#ifdef VMS
+ cxflow[CXT_MODEM] = FLO_XONX;
+#else
+ cxflow[CXT_MODEM] = FLO_NONE;
+#endif /* VMS */
+#endif /* CK_RTSCTS */
+
+#ifdef VMS
+ cxflow[CXT_TCPIP] = FLO_XONX; /* TCP/IP connections... */
+#else
+ cxflow[CXT_TCPIP] = FLO_NONE;
+#endif /* VMS */
+
+ cxflow[CXT_SSH] = FLO_NONE;
+ cxflow[CXT_X25] = FLO_NONE; /* Other kinds of networks... */
+ cxflow[CXT_DECNET] = FLO_XONX;
+ cxflow[CXT_LAT] = FLO_XONX;
+ cxflow[CXT_NETBIOS] = FLO_NONE;
+ cxflow[CXT_NPIPE] = FLO_NONE;
+ cxflow[CXT_PIPE] = FLO_NONE;
+ flow = cxflow[cxtype]; /* Initial flow setting. */
+ debug(F101,"initflow","",flow);
+}
+
+#ifndef NOXFER
+/* Initialize file transfer protocols */
+
+VOID
+initproto(y, upbstr, uptstr, srvstr, sndbstr, sndtstr, rcvbstr, rcvtstr)
+ int y;
+ char * upbstr, * uptstr, * srvstr, * sndbstr, * sndtstr, * rcvbstr,
+ * rcvtstr;
+/* initproto */ {
+
+ if (upbstr) /* Convert null strings */
+ if (!*upbstr) /* to null pointers */
+ upbstr = NULL;
+
+ if (uptstr) /* Convert null strings */
+ if (!*uptstr) /* to null pointers */
+ uptstr = NULL;
+
+ if (sndbstr)
+ if (!*sndbstr)
+ sndbstr = NULL;
+
+ if (sndtstr)
+ if (!*sndtstr)
+ sndtstr = NULL;
+
+ if (rcvbstr)
+ if (!*rcvbstr)
+ rcvbstr = NULL;
+
+ if (rcvtstr)
+ if (!*rcvtstr)
+ rcvtstr = NULL;
+
+ if (srvstr)
+ if (!*srvstr)
+ srvstr = NULL;
+
+ protocol = y; /* Set protocol */
+
+ if (ptab[protocol].rpktlen > -1)
+ urpsiz = ptab[protocol].rpktlen;
+ if (ptab[protocol].spktflg > -1)
+ spsizf = ptab[protocol].spktflg;
+ if (ptab[protocol].spktlen > -1) {
+ spsiz = ptab[protocol].spktlen;
+ debug(F101,"initproto spsiz","",spsiz);
+ if (spsizf) {
+ spsizr = spmax = spsiz;
+ debug(F101,"initproto spsizr","",spsizr);
+ }
+ }
+ if (ptab[protocol].winsize > -1)
+ wslotr = ptab[protocol].winsize;
+ if (ptab[protocol].prefix > -1)
+ prefixing = ptab[protocol].prefix;
+ if (ptab[protocol].fnca > -1)
+ fncact = ptab[protocol].fnca;
+ if (ptab[protocol].fncn > -1)
+ fncnv = ptab[protocol].fncn;
+ if (ptab[protocol].fnsp > -1)
+ fnspath = ptab[protocol].fnsp;
+ if (ptab[protocol].fnrp > -1)
+ fnrpath = ptab[protocol].fnrp;
+
+ makestr(&(ptab[protocol].h_b_init),upbstr);
+ makestr(&(ptab[protocol].h_t_init),uptstr);
+ makestr(&(ptab[protocol].h_x_init),srvstr);
+ makestr(&(ptab[protocol].p_b_scmd),sndbstr);
+ makestr(&(ptab[protocol].p_t_scmd),sndtstr);
+ makestr(&(ptab[protocol].p_b_rcmd),rcvbstr);
+ makestr(&(ptab[protocol].p_t_rcmd),rcvtstr);
+}
+#endif /* NOXFER */
+
+#ifndef NOCMDL
+VOID
+#ifdef CK_ANSIC
+docmdline(void * threadinfo)
+#else /* CK_ANSIC */
+docmdline(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug( F100, "docmdline called with threadinfo block", "", 0 );
+ } else
+ debug( F100, "docmdline threadinfo is NULL","",0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+ proto(); /* Take any requested action, then */
+ if (!quiet) /* put cursor back at left margin, */
+ conoll("");
+#ifndef NOLOCAL
+ if (cnflg) { /* Re-connect if requested */
+ cnflg = 0;
+ doconect(0,0);
+ if (ttchk() < 0)
+ dologend();
+ }
+#endif /* NOLOCAL */
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+}
+
+void
+ikslogin() {
+ if (sstelnet
+#ifdef IKSD
+ || inserver /* Internet server */
+#endif /* IKSD */
+ ) {
+ char *s;
+ extern int fdispla; /* File-transfer display format */
+ extern char * ikprompt; /* IKSD prompt */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver) {
+ x_login = 1; /* Login required */
+ x_logged = 0; /* Not logged in yet */
+ cmsetp(ikprompt); /* Set up IKSD's prompt */
+#ifndef NOSERVER
+ en_mai = 0; /* MAIL is disabled */
+ en_who = 0; /* REMOTE WHO is disabled */
+ en_hos = 0; /* REMOTE HOST is disabled */
+ en_pri = 0; /* PRINT is disabled */
+#endif /* NOSERVER */
+ } else {
+ x_login = 0; /* Login not required */
+ x_logged = 1; /* Already logged in */
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ nolocal = 1; /* SET LINE/HOST not allowed */
+ fdispla = XYFD_N; /* No file-transfer display */
+#ifdef NETCONN
+ clienthost = ckgetpeer(); /* Get client's hostname */
+ debug(F110,"ikslogin clienthost",clienthost,0);
+#endif /* NETCONN */
+ ztime(&s); /* Get current date and time */
+
+#ifdef CK_LOGIN
+#ifdef CK_AUTHENTICATION
+ if (x_login) {
+ x_logged = ck_tn_auth_valid(); /* Did Telnet Auth succeed? */
+ debug(F111,"ikslogin","x_logged",x_logged);
+
+#ifdef NT
+ /* On Windows 9x, we do not have the ability in */
+ /* zvuser() at present to determine if the name */
+ /* approved in a Kerberos principal is really a */
+ /* an account in the Windows Access Control List */
+ if (isWin95() && x_logged == AUTH_VALID
+ && (ck_tn_authenticated() != AUTHTYPE_NTLM)
+#ifdef CK_SRP
+ && (ck_tn_authenticated() != AUTHTYPE_SRP)
+#endif /* CK_SRP */
+ ) {
+ auth_finished(AUTH_USER);
+ x_logged = AUTH_USER;
+ printf("WARNING:\r\n");
+ printf(
+" The Telnet authentication method used cannot provide for automated\r\n");
+ printf(
+" login to Windows 95 or Windows 98. A password must be entered\r\n");
+ printf(
+" locally to validate your userid. Telnet authentication (and encryption)\r\n"
+ );
+ printf(
+" can be used to validate the host (and protect the privacy of your password.)\
+\r\n"
+ );
+ }
+#endif /* NT */
+
+ if (x_logged == AUTH_VALID) {
+#ifdef CK_SSL
+ if ((ssl_active_flag || tls_active_flag) &&
+ (!TELOPT_U(TELOPT_AUTHENTICATION) ||
+ ck_tn_authenticated() == AUTHTYPE_NULL ||
+ ck_tn_authenticated() == AUTHTYPE_AUTO)
+ ) {
+#ifdef SSL_KRB5
+ if (tls_is_krb5(0)) {
+ printf("Authenticated using Kerberos 5\r\n");
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_VALID",
+ "Kerberos 5",
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ } else
+#endif /* SSL_KRB5 */
+ {
+ printf("Authenticated using X.509 certificate\r\n");
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_VALID",
+ "X.509 certificate",
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ }
+ } else
+#endif /* CK_SSL */
+ {
+ printf("Authenticated using %s\r\n",
+ AUTHTYPE_NAME(ck_tn_authenticated()));
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_VALID",
+ AUTHTYPE_NAME(ck_tn_authenticated()),
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ }
+ zvuser(uidbuf);
+ if (zvpass("") == 0)
+ x_logged = 0;
+ } else if (x_logged == AUTH_USER && !strcmp(uidbuf,"anonymous")) {
+ extern char szUserNameAuthenticated[];
+ zvuser(uidbuf);
+ debug(F110,"szUserNameAuthenticated",
+ szUserNameAuthenticated,0);
+ if (zvpass(szUserNameAuthenticated) == 0) {
+ /* Anonymous login failed. Force a username prompt. */
+ x_logged = 0;
+ uidbuf[0] = '\0';
+ } else {
+#ifdef CK_SSL
+ if ((ssl_active_flag || tls_active_flag) &&
+ (!TELOPT_U(TELOPT_AUTHENTICATION) ||
+ ck_tn_authenticated() == AUTHTYPE_NULL ||
+ ck_tn_authenticated() == AUTHTYPE_AUTO)) {
+ printf("Authenticated using X.509 certificate\r\n");
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_USER",
+ "X.509 certificate",
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ } else
+#endif /* CK_SSL */
+ {
+ printf("Authenticated using %s\r\n",
+ AUTHTYPE_NAME(ck_tn_authenticated())
+ );
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ cksyslog(SYSLG_LI, 1, "AUTH_USER",
+ AUTHTYPE_NAME(ck_tn_authenticated()),
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ }
+ }
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging &&
+ x_logged == AUTH_USER) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_USER",
+ AUTHTYPE_NAME(ck_tn_authenticated()),
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ x_logged = 0;
+ if (!strcmp("(unknown)",uidbuf)
+#ifdef NT
+ || !stricmp("administrator",uidbuf)
+#ifdef UNIX
+ || !strcmp("root",uidbuf)
+#else
+#ifdef Plan9
+ || !strcmp("root",uidbuf)
+#else
+#ifdef OSK
+ || !strcmp("root",uidbuf)
+#endif /* OSK */
+#endif /* Plan9 */
+#endif /* UNIX */
+#endif /* NT */
+ )
+ uidbuf[0] = '\0';
+ }
+ }
+#endif /* CK_AUTHENTICATION */
+#endif /* CK_LOGIN */
+
+#ifdef IKSD
+ if (inserver)
+ printf("\r\nInternet Kermit Service ready at %s%s\r\n",s,versio);
+ else
+#endif /* IKSD */
+ printf("\r\nC-Kermit ready at %s%s\r\n",s,versio);
+ if (*myhost)
+ printf("%s\r\n", myhost);
+ printf("\r\n");
+ }
+#ifdef CK_LOGIN
+#ifdef IKSD
+ if (inserver) {
+ int i;
+ extern int arg_x; /* Flag for '-x' on command line */
+#ifndef NOSPL
+ extern struct mtab *mactab; /* For ON_LOGIN macro. */
+ extern int nmac;
+#endif /* NOSPL */
+
+ debug(F110,"MAIN clienthost",clienthost,0);
+ srvidl = timelimit = logintimo; /* For interactive login */
+ rtimer(); /* Reset timer */
+ for (i = 0; i < iks_retry && !x_logged; i++) { /* Count retries */
+ if (gtimer() > logintimo)
+ break;
+#ifdef TNCODE
+ tn_wait("login loop");
+ tn_push();
+#endif /* TNCODE */
+ debug(F101,"MAIN LOGIN try","",i);
+ what = W_NOTHING; /* Because proto() changes this */
+
+#ifdef IKS_OPTION
+ debug(F111,"MAIN LOGIN",
+ "TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+ /* Kermit server negotiated */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ debug(F101,"IKSD starting in server mode","",0);
+ arg_x = 1; /* Enter server mode */
+ sstate = 'x';
+#ifdef IKSDPOPBACK
+ justone = 1; /* Execute one command at a time. */
+#endif /* IKSDPOPBACK */
+ proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ if (x_logged) /* Logged in */
+ break;
+ } else { /* Not in client/server mode */
+#endif /* IKS_OPTION */
+ debug(F101,"IKSD starting with Username prompt","",0);
+ x_logged = ckxlogin((CHAR *)uidbuf,NULL,NULL,1);
+ if (sstate) { /* Received a packet at prompt */
+#ifdef IKSDPOPBACK
+ justone = 1; /* Go handle it */
+#endif /* IKSDPOPBACK */
+ proto();
+ }
+ if (!x_logged) { /* In case we are at the prompt... */
+ printf("Access denied.\n");
+ uidbuf[0] = '\0'; /* Forget the name if we have one */
+ }
+#ifdef IKS_OPTION
+ }
+#endif /* IKS_OPTION */
+ }
+ srvidl = timelimit = iks_timo; /* Reset command timelimit */
+ debug(F101,"MAIN LOGIN","",x_logged);
+ if (!x_logged) { /* Logins failed. */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ errpkt((CHAR *)"Login Timeout");
+ msleep(500);
+ doexit(BAD_EXIT,0);
+ }
+ what = W_NOTHING; /* Stay in known state */
+#ifndef NOSERVER
+ if (isguest) {
+ en_pri = 0; /* No printing for anonymous users */
+ en_mai = 0; /* No email for anonymous users */
+ en_mkd = 0; /* Or directory creation */
+ en_rmd = 0; /* Or directory removal */
+ en_ena = 0; /* Or ENABLing DISABLEd items */
+ }
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+/*
+ If a macro named "on_login" is defined, execute it. Also remove it from the
+ macro table so the user cannot see what it does. Execute it as part of the
+ iksd.conf file.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_login"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_login" */
+ if (k >= 0) { /* If found, */
+#ifdef IKSDCONF
+ int saved = iksdcf;
+ iksdcf = 0;
+#endif /* IKSDCONF */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* execute it */
+#ifdef IKSDCONF
+ iksdcf = saved;
+#endif /* IKSDCONF */
+ delmac(cmd,1); /* and delete it */
+ }
+ }
+#endif /* NOSPL */
+ } /* if (inserver) */
+#else /* CK_LOGIN */
+ if (inserver)
+ srvidl = timelimit = iks_timo; /* Set idle limits for IKS */
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+}
+
+VOID
+#ifdef CK_ANSIC
+failcmdline(void * foo)
+#else /* CK_ANSIC */
+failcmdline(foo) VOID * foo;
+#endif /* CK_ANSIC */
+{
+#ifdef GEMDOS
+ cc_clean();
+#endif /* GEMDOS */
+#ifndef NOLOCAL
+ if (cnflg) doconect(0,0); /* connect again if requested. */
+ if (ttchk() < 0)
+ dologend();
+#endif /* NOLOCAL */
+}
+#endif /* NOCMDL */
+
+#ifndef NOICP
+VOID
+#ifdef CK_ANSIC
+dotakeini(void * threadinfo) /* Execute init file. */
+#else /* CK_ANSIC */
+dotakeini(threadinfo) VOID * threadinfo; /* Execute init file. */
+#endif /* CK_ANSIC */
+/* dotakeini */ {
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "dotakeini called with threadinfo block","", 0);
+ } else
+ debug(F100, "dotakeini - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+ cmdini(); /* Sets tlevel */
+
+ debug(F111,"dotakeini","inserver",inserver);
+ debug(F111,"dotakeini","sstelnet",sstelnet);
+
+#ifdef COMMENT
+/* Wrong place for this... */
+#ifndef NOXFER
+#ifdef CK_FAST
+ dofast(); /* By now FAST defaults should be OK */
+#endif /* CK_FAST */
+#endif /* NOXFER */
+#endif /* COMMENT */
+
+ doinit(); /* Now do the initialization file */
+ debug(F101,"main executing init file","",tlevel);
+ while (tlevel > -1) {
+ sstate = (CHAR) parser(1); /* Execute one command at a time. */
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+ debug(F101,"main exits init file","",tlevel);
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+}
+
+VOID
+#ifdef CK_ANSIC
+failtakeini(void * threadinfo)
+#else /* CK_ANSIC */
+failtakeini(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failtakeini */ {
+#ifdef GEMDOS
+ cc_clean(); /* Atari: Clean up after ^C-trap. */
+#endif /* GEMDOS */
+ fixcmd();
+ if (!cfilef) {
+ conoll("Interrupted during initialization or \
+command-line processing.");
+ conoll("C-Kermit quitting...");
+ }
+ doexit(BAD_EXIT,-1); /* Exit with bad status. */
+}
+
+VOID
+#ifdef CK_ANSIC
+doicp(void * threadinfo)
+#else /* CK_ANSIC */
+doicp(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* doicp */ {
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ if (!TlsSetValue(TlsIndex,threadinfo))
+ debug(F101,"doicp TlsSetValue failed","",GetLastError());
+ debug(F101, "doicp a threadinfo block - TlsIndex", "", TlsIndex);
+ } else {
+ debug(F100, "doicp received a null threadinfo", "", 0);
+ }
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+#ifdef MAC
+ while (1) {
+ extern char *lfiles; /* Fake pointer cast */
+
+ if (connected) {
+ debug(F100, "doicp: calling macparser", "", 0);
+ sstate = newparser(1, 1, 0L);
+
+ /* ignore null command state */
+ if (sstate == 'n')
+ sstate = '\0';
+
+ if (sstate)
+ proto();
+ } else {
+ /*
+ * process take files the finder gave us.
+ */
+ if ((tlevel == -1) && lfiles)
+ startlfile();
+
+ debug(F100, "doicp: calling parser", "", 0);
+ sstate = (CHAR) parser(0);
+ if (sstate == 'c') /* if MAC connect */
+ sstate = 0;
+ if (sstate)
+ proto();
+ }
+ }
+#else /* Not MAC */
+
+#ifndef NOSPL
+/*
+ If interactive commands were given on the command line (using the
+ -C "command, command, ..." option), assign them to a macro called
+ "cl_commands", then execute the macro and leave it defined for
+ subsequent re-execution if desired.
+*/
+ if (clcmds) { /* Check for -C commands */
+ int x;
+ x = addmac("cl_commands",clcmds); /* Put macro in table */
+ if (x > -1) { /* If successful, */
+ dodo(x,NULL,CF_CMDL); /* set up for macro execution */
+ while (maclvl > -1) { /* Loop getting macro commands. */
+ sstate = (CHAR) parser(1);
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+ }
+ debug(F100,"doicp calling herald","",0);
+ herald();
+ }
+#endif /* NOSPL */
+ while(1) { /* Loop getting commands. */
+ sstate = (CHAR) parser(0);
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+#endif /* MAC */
+}
+
+VOID
+#ifdef CK_ANSIC
+failicp(void * threadinfo)
+#else /* CK_ANSIC */
+failicp(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef GEMDOS
+ cc_clean();
+#endif /* GEMDOS */
+ fixcmd(); /* Pop command stacks, etc. */
+ clcmds = NULL;
+ debug(F100,"ckcmai got interrupt","",0);
+}
+#endif /* NOICP */
+
+#ifndef NOICP
+VOID
+#ifdef CK_ANSIC
+docmdfile(void * threadinfo) /* Execute application file */
+#else /* CK_ANSIC */
+docmdfile(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* docmdfile */ {
+#ifdef NTSIG
+ concb((char)escape);
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "docmdfile called with threadinfo block","", 0);
+ } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef IKSD
+#ifdef NT
+ if (inserver)
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+ debug(F110,"main cmdfil",cmdfil,0);
+#ifndef NOSPL
+ addmac("\\%0",cmdfil);
+#endif /* NOSPL */
+ dotake(cmdfil); /* Set up the command file */
+ if (tlevel > -1) /* Remember we did this */
+ cfilef = 1;
+ while (tlevel > -1) { /* Execute it until it runs out. */
+ sstate = parser(1); /* Loop getting commands. */
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+}
+
+VOID
+#ifdef CK_ANSIC
+failcmdfile(void * threadinfo)
+#else /* CK_ANSIC */
+failcmdfile(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failcmdfile */ {
+#ifdef GEMDOS
+ cc_clean(); /* Atari: Clean up after ^C-trap. */
+#endif /* GEMDOS */
+ fixcmd();
+ if (!cfilef) {
+ conoll("Interrupted during initialization or \
+command-line processing.");
+ conoll("C-Kermit quitting...");
+ }
+ doexit(BAD_EXIT,-1); /* Exit with bad status. */
+}
+#endif /* NOICP */
+
+#ifndef NOXFER
+VOID
+setprefix(z) int z; { /* Initial control-char prefixing */
+#ifdef CK_SPEED
+ int i, val;
+
+ prefixing = z;
+ ptab[protocol].prefix = prefixing;
+ debug(F101,"setprefix","",prefixing);
+ switch (z) {
+ case PX_ALL: /* All */
+#ifdef COMMENT
+ /* Don't let Clear-Channel be dependent on prefixing */
+ clearrq = 0; /* Turn off clearchannel, fall thru */
+#endif /* COMMENT */
+ case PX_NON: /* None */
+ val = (z == PX_ALL) ? 1 : 0;
+ for (i =
+#ifdef UNPREFIXZERO
+ 0
+#else
+ 1
+#endif /* UNPREFIXZERO */
+ ; i < 32; i++)
+ ctlp[i] = val;
+ for (i = 127; i < 160; i++) ctlp[i] = val;
+ ctlp[(unsigned)255] = val;
+ if (z == PX_NON) { /* These are never safe */
+ if (network) { /* Assume network = telnet or rlogin */
+ ctlp[CR] = 1; /* Prefix CR because of NVT rules */
+ ctlp[XON] = ctlp[XOFF] = 1; /* Because of Telnet server */
+ ctlp[127] = ctlp[255] = 1; /* Telnet IAC */
+ ctlp[mystch] = ctlp[mystch+128] = 1; /* Kermit packet start */
+ } else {
+ ctlp[CR] = ctlp[255] = ctlp[mystch] = ctlp[mystch+128] = 1;
+ if (flow == FLO_XONX) /* Xon/Xoff forces prefixing */
+ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1;
+ }
+ }
+ break;
+
+ case PX_CAU: /* Cautious or Minimal */
+#ifdef COMMENT
+ /* Don't let CLEAR-CHANNEL be dependent on Prefixing */
+ clearrq = 0; /* Turn off clearchannel */
+#endif /* COMMENT */
+ case PX_WIL: /* Minimal ("wild") */
+ ctlp[0] = 1; /* Does not include 0 */
+ for (i = 1; i < 32; i++)
+ ctlp[i] = 0;
+ for (i = 127; i < 160; i++)
+ ctlp[i] = 0;
+ ctlp[mystch] = ctlp[mystch+128] = 1; /* Kermit start of packet */
+ if (seol != 13)
+ ctlp[seol] = ctlp[seol+128] = 1; /* Kermit end */
+ ctlp[13] = ctlp[141] = 1; /* In case of TELNET (NVT rules) */
+ ctlp[(unsigned)255] = 1; /* Ditto */
+
+ /* ^D, ^J, ^M, or ^U followed by tilde trigger Rlogin escape */
+
+ ctlp[4] = ctlp[4+128] = 1; /* In case of RLOGIN */
+ ctlp[10] = ctlp[10+128] = 1; /* In case of RLOGIN */
+ ctlp[21] = ctlp[21+128] = 1; /* In case of RLOGIN */
+
+ if (flow == FLO_XONX || /* Xon/Xoff forces prefixing these */
+ prefixing == PX_CAU || /* So does CAUTIOUS */
+ network) /* Networks too... */
+ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1;
+ if (prefixing == PX_CAU) { /* Cautious - add some more */
+#ifdef UNPREFIXZERO
+ ctlp[0] = 1;
+#endif /* UNPREFIXZERO */
+ ctlp[3] = ctlp[16] = 1; /* ^C, DLE */
+ ctlp[14] = ctlp[15] = 1; /* SO/SI */
+ ctlp[24] = ctlp[25] = 1; /* VMS might need these */
+ ctlp[26] = ctlp[26+128] = 1; /* UNIX suspend */
+ ctlp[28] = ctlp[29] = ctlp[30] = 1; /* Assorted esc chars */
+ ctlp[131] = ctlp[141] = ctlp[144] = 1; /* and 8-bit versions */
+ ctlp[(unsigned)255] = ctlp[156] = ctlp[157] = ctlp[158] = 1;
+ }
+ break;
+ }
+#endif /* CK_SPEED */
+}
+#endif /* NOXFER */
+
+VOID
+makever() { /* Make version string from pieces */
+ int x, y;
+ char * s;
+#ifndef OS2
+#ifndef MAC
+ ck_s_xver = ck_s_ver; /* Fill in C-Kermit version number */
+ ck_l_xver = ck_l_ver; /* for UNIX, VMS, etc. */
+#endif /* MAC */
+#endif /* OS2 */
+ x = strlen(ck_s_name);
+ y = strlen(ck_s_xver);
+ if (y + x + 1 < CKVERLEN) {
+ ckmakmsg(versio,CKVERLEN,ck_s_name," ",ck_s_xver,NULL);
+ } else {
+ ckstrncpy(versio,"C-Kermit",CKVERLEN);
+ return;
+ }
+ x += y + 1;
+
+ s = " OPEN SOURCE:"; /* C-Kermit 9.0 and later */
+ y = strlen(s);
+ if (CKVERLEN < x + y + 1)
+ return;
+ ckstrncat(versio,s,CKVERLEN);
+
+ x += y + 1;
+ if (*ck_s_who) {
+ y = strlen(ck_s_who);
+ if (CKVERLEN < x + y + 1)
+ return;
+ ckstrncat(versio,"-",CKVERLEN);
+ ckstrncat(versio,ck_s_who,CKVERLEN);
+ }
+ x += y + 1;
+ y = strlen(ck_s_test);
+ if (y > 0 && y + x + 1 < CKVERLEN) {
+ ckstrncat(versio," ",CKVERLEN);
+ ckstrncat(versio,ck_s_test,CKVERLEN);
+ x += y + 1;
+ y = strlen(ck_s_tver);
+ if (y > 0 && y + x + 1 < CKVERLEN) {
+ ckstrncat(versio,".",CKVERLEN);
+ ckstrncat(versio,ck_s_tver,CKVERLEN);
+ x += y + 1;
+ }
+ }
+ y = strlen(ck_s_date);
+ if (y > 0 && y + x + 2 < CKVERLEN) {
+ ckstrncat(versio,", ",CKVERLEN);
+ ckstrncat(versio,ck_s_date,CKVERLEN);
+ }
+ vernum = ck_l_ver;
+ xvernum = ck_l_xver;
+ debug(F110,"Kermit version",versio,0);
+}
+
+union ck_short shortbytes; /* For determining byte order */
+int byteorder = 0; /* 0 = Big Endian; 1 = Little Endian */
+int bigendian = 1;
+/* NOTE: MUST BE 0 or 1 - nothing else */
+
+#ifndef NOSPL
+#define SCRIPTLEN 10240
+#endif /* NOSPL */
+
+#ifdef NETCONN
+#ifndef NOCMDL
+#ifndef NOURL
+VOID
+dourl() {
+ int rc = 0;
+ char * port = NULL;
+ extern int ttnproto;
+ extern struct urldata g_url;
+
+#ifdef COMMENT
+ /* NOTE: debug() doesn't work yet - must use printf's */
+ printf("URL: %s\n",g_url.sav ? g_url.sav : "(none)");
+ printf("Type: %s\n",g_url.svc ? g_url.svc : "(none)");
+ printf("User: %s\n",g_url.usr ? g_url.usr : "(none)");
+ printf("Pass: %s\n",g_url.psw ? g_url.psw : "(none)");
+ printf("Host: %s\n",g_url.hos ? g_url.hos : "(none)");
+/* printf("Port: %s\n",g_url.por ? g_url.por : "(none)"); */
+ printf("Path: %s\n",g_url.pth ? g_url.pth : "(none)");
+#endif /* COMMENT */
+
+ if (!ckstrcmp(g_url.svc,"iksd",-1,0) ||
+ !ckstrcmp(g_url.svc,"kermit",-1,0)) {
+ extern char pwbuf[];
+ extern int pwflg;
+#ifdef OS2
+ extern int pwcrypt;
+#endif /* OS2 */
+
+ if (!g_url.hos) {
+ printf("?Incomplete IKSD URL\n");
+ doexit(BAD_EXIT,1);
+ }
+ if (!g_url.usr)
+ makestr(&g_url.usr,"anonymous");
+ if (!g_url.psw) {
+ char * tmpbuf = NULL;
+ if (!(tmpbuf = (char *)malloc(1024)))
+ fatal("dourl: out of memory");
+ if (!ckstrcmp(g_url.usr,"anonymous",-1,0)) {
+ ckmakmsg(tmpbuf,1024,uidbuf,"@",myhost,NULL);
+ makestr(&g_url.psw,tmpbuf);
+ } else {
+ readpass(" Password:",tmpbuf,1024);
+ makestr(&g_url.psw,tmpbuf);
+ }
+ free(tmpbuf);
+ }
+ port = "kermit";
+ ttnproto = NP_TELNET;
+ nettype = NET_TCPB;
+ mdmtyp = -nettype;
+ local = -1;
+ ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
+ if (g_url.psw) {
+ ckstrncpy(pwbuf,g_url.psw,PWBUFL);
+ pwflg = 1;
+#ifdef OS2
+ pwcrypt = 0;
+#endif /* OS2 */
+ }
+ ckmakmsg(ttname,
+ TTNAMLEN,
+ g_url.hos,
+ ":",
+ g_url.por ? g_url.por : port,
+ NULL
+ );
+ rc = ttopen(ttname,&local,mdmtyp,0);
+ if (rc > -1) {
+ network = 1;
+ exitonclose = 1;
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+ } else {
+ printf("?Connection failed: %s\n",g_url.sav);
+ doexit(BAD_EXIT,1);
+ }
+ /* Also need to check here for secure authentication already done */
+
+#ifdef NOSPL
+ cflg = 1;
+#else
+ {
+ char * script = NULL;
+ if (!(script = (char *)malloc(SCRIPTLEN)))
+ fatal("dourl: out of memory");
+ if (!g_url.pth) { /* Write the appropriate script */
+ cflg = 1;
+ ckmakxmsg(script,SCRIPTLEN,
+ "if not eq {\\v(authstate)} {user} ",
+ "if not eq {\\v(authstate)} {valid} { ",
+ "remote login ", /* No path */
+ g_url.usr, /* Just log in and CONNECT */
+ " ",
+ g_url.psw,
+ ", if fail exit 1 {IKSD login failed} }",
+ ", connect",
+ NULL,NULL,NULL,NULL);
+ /* printf("CLCMDS 1: %s\n",script); */
+ } else {
+ /* does the path specify a file or a directory? */
+ int len = strlen(g_url.pth);
+ if (ISDIRSEP(g_url.pth[len-1])) {
+ ckmakxmsg(script,SCRIPTLEN, /* Directory name given */
+ "if not eq {\\v(authstate)} {user} \
+if not eq {\\v(authstate)} {valid} { remote login ",
+ g_url.usr,
+ " ",
+ g_url.psw,
+ ", if fail exit 1 {IKSD login failed} }",
+ ", set macro error on",
+ ", set xfer displ brief",
+ ", set xfer bell off",
+ ", remote cd ",
+ g_url.pth,
+ ", lineout directory",
+ ", connect"
+ );
+ /* printf("CLCMDS 2: %s\n",script); */
+ } else {
+ ckmakxmsg(script,SCRIPTLEN, /* Path given, try to GET */
+ "if not eq {\\v(authstate)} {user} \
+if not eq {\\v(authstate)} {valid} { remote login ",
+ g_url.usr,
+ " ",
+ g_url.psw,
+ ", if fail exit 1 {IKSD login failed} }",
+ ", set xfer displ brief",
+ ", set xfer bell off",
+ ", get ",
+ g_url.pth,
+ ", .rc := \\v(status)",
+ ", if open connection bye",
+ ", exit \\m(rc)"
+ );
+ /* printf("CLCMDS 2: %s\n",script); */
+ }
+ }
+ clcmds = script; /* Make this our -C cmdline macro */
+ /* printf("HAVEURL=%d\n",haveurl); */
+ }
+#endif /* NOSPL */
+ } else {
+ if (ckstrcmp(g_url.svc,"telnet",-1,0) &&
+#ifdef SSHBUILTIN
+ ckstrcmp(g_url.svc,"ssh",-1,0) &&
+#endif /* SSHBUILTIN */
+ ckstrcmp(g_url.svc,"ftp",-1,0)) {
+ printf("?Sorry, %s URLs not supported\n",
+ g_url.svc ? g_url.svc : "");
+ doexit(BAD_EXIT,1);
+ }
+ }
+}
+#endif /* NOCMDL */
+#endif /* NETCONN */
+#endif /* NOURL */
+
+/*
+ main()...
+
+ If you get complaints about "main: return type is not blah",
+ define MAINTYPE on the CC command line, e.g. "CFLAGS=-DMAINTYPE=blah"
+ (where "blah" is int, long, or whatever).
+
+ If the complaint is "Attempt to return a value from a function of type void"
+ then add -DMAINISVOID.
+*/
+#ifndef MAINTYPE
+#ifndef MAINISVOID
+#define MAINTYPE int
+#endif /* MAINISVOID */
+#endif /* MAINTYPE */
+
+#ifdef MAINISVOID
+#ifndef MAINTYPE
+#define MAINTYPE void
+#endif /* MAINTYPE */
+#endif /* MAINISVOID */
+
+#ifdef aegis
+/* On the Apollo, intercept main to insert a cleanup handler */
+int
+ckcmai(argc,argv) int argc; char **argv;
+#else
+#ifdef MAC /* Macintosh */
+int
+main (void)
+#else
+#ifdef __GNUC__ /* GCC compiler */
+int
+main(argc,argv) int argc; char **argv;
+#else
+#ifdef __DECC /* DEC Alpha with DEC C compiler */
+#ifdef __ALPHA
+int
+main(argc,argv) int argc; char **argv;
+#else /* DEC C compiler, not Alpha */
+#define MAINISVOID
+VOID
+main(argc,argv) int argc; char **argv;
+#endif /* __ALPHA */
+#else
+#ifdef STRATUS /* Stratus VOS */
+int
+main(argc,argv) int argc; char **argv;
+#else /* K-95 */
+#ifdef OS2
+#ifdef KUI
+#define MAINISVOID
+void
+Main( int argc, char ** argv )
+#else /* KUI */
+#define MAINISVOID
+VOID
+main(argc,argv) int argc; char **argv;
+#endif /* KUI */
+#else /* Not K95 */
+MAINTYPE /* All others... */
+main(argc,argv) int argc; char **argv;
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* __DECC */
+#endif /* __GNUC__ */
+#endif /* MAC */
+#endif /* aegis */
+
+/* main */ {
+
+ char *p;
+
+#ifndef NOSETKEY
+ int i;
+#endif /* NOSETKEY */
+
+#ifdef datageneral
+ short *pfha = 016000000036; /* Get around LANG_RT problem */
+ *pfha = (short) 0; /* No user protection fault handler */
+#endif /* datageneral */
+
+ int unbuf = 0; /* nonzero for unbuffered stdout */
+
+/* setbuf has to be called on the file descriptor before it is used */
+
+#ifdef UNIX
+#ifdef NONOSETBUF /* Unbuffered console i/o */
+ unbuf++; /* as a compile-time option */
+#endif /* NONOSETBUF */
+ if (!unbuf) { /* Or as a command-line selection */
+ int i, n; /* We have to pre-pre-scan for */
+ char * s; /* this one. */
+ for (i = 1; i < argc; i++) {
+ s = argv[i];
+ if (!s) n = 0; else n = (int)strlen(s);
+ if (n > 4) {
+ if (!ckstrcmp("--unbuffered",s,n,0)) {
+ unbuf++;
+ break;
+ }
+ }
+ }
+ }
+ if (unbuf)
+ setbuf(stdout,NULL);
+#endif /* UNIX */
+
+/* Do some initialization */
+
+#ifdef VMS
+#ifdef __DECC
+ /* Get some RMS default settings. */
+ get_rms_defaults();
+#endif /* def __DECC */
+#endif /* def VMS */
+
+#ifndef MAC
+ xargc = xargs = argc; /* Make global copies of argc */
+ xargv = argv; /* ...and argv. */
+ xarg0 = argv[0];
+#ifdef NT
+ setOSVer();
+#endif /* NT */
+ zstrip(argv[0],&p); /* Get name we were invoked with */
+ makestr(&myname,p);
+ if (!ckstrcmp(myname,"telnet",-1,0)) howcalled = I_AM_TELNET;
+#ifdef CK_KERBEROS
+ else if (!ckstrcmp(myname,"ktelnet",-1,0)) howcalled = I_AM_TELNET;
+#endif /* CK_KERBEROS */
+ else if (!ckstrcmp(myname,"rlogin",-1,0)) howcalled = I_AM_RLOGIN;
+ else if (!ckstrcmp(myname,"iksd",-1,0)) howcalled = I_AM_IKSD;
+#ifdef NEWFTP
+ else if (!ckstrcmp(myname,"ftp",-1,0)) howcalled = I_AM_FTP;
+#endif /* NEWFTP */
+#ifndef NOHTTP
+ else if (!ckstrcmp(myname,"http",-1,0)) howcalled = I_AM_HTTP;
+#endif /* NOHTTP */
+#ifdef OS2
+ else if (!ckstrcmp(myname,"telnet.exe",-1,0)) howcalled = I_AM_TELNET;
+#ifdef SSHBUILTIN
+ else if (!ckstrcmp(myname,"ssh",-1,0)) howcalled = I_AM_SSH;
+ else if (!ckstrcmp(myname,"ssh.exe",-1,0)) howcalled = I_AM_SSH;
+#endif /* SSHBUILTIN */
+#ifdef CK_KERBEROS
+ else if (!ckstrcmp(myname,"ktelnet.exe",-1,0)) howcalled = I_AM_TELNET;
+#endif /* CK_KERBEROS */
+ else if (!ckstrcmp(myname,"rlogin.exe",-1,0)) howcalled = I_AM_RLOGIN;
+#ifdef NT
+ else if (!ckstrcmp(myname,"iksdnt",-1,0)) howcalled = I_AM_IKSD;
+ else if (!ckstrcmp(myname,"iksdnt.exe",-1,0)) howcalled = I_AM_IKSD;
+#endif /* NT */
+#ifdef NEWFTP
+ else if (!ckstrcmp(myname,"ftp.exe",-1,0)) howcalled = I_AM_FTP;
+#endif /* NEWFTP */
+#ifndef NOHTTP
+ else if (!ckstrcmp(myname,"http.exe",-1,0)) howcalled = I_AM_HTTP;
+#endif /* NOHTTP */
+#endif /* OS2 */
+ else if (!ckstrcmp(myname,"kermit-sshsub",-1,0)) howcalled = I_AM_SSHSUB;
+
+#ifndef NOICP
+ cmdini(); /* Must come before prescan */
+ debug(F100,"main cmdini() done","",0);
+#endif /* NOICP */
+ prescan(0); /* Pre-Check for debugging, etc */
+#endif /* MAC */
+ debug(F101,"MAIN feol","",feol);
+ makever(); /* Put together version strings */
+#ifndef NOSETKEY /* Allocate & initialize the keymap */
+ /* This code has been moved to before sysinit() for K95G */
+ if (!(keymap = (KEY *) malloc(sizeof(KEY)*KMSIZE)))
+ fatal("main: no memory for keymap");
+ if (!(macrotab = (MACRO *) malloc(sizeof(MACRO)*KMSIZE)))
+ fatal("main: no memory for macrotab");
+ for (i = 0; i < KMSIZE; i++) {
+ keymap[i] = (KEY) i;
+ macrotab[i] = NULL;
+ }
+#endif /* NOSETKEY */
+
+ shortbytes.x_short = 0xABCD; /* Get Endianness */
+ if (shortbytes.x_char[0] == 0xCD) { /* 0 = Big Endian */
+ byteorder = 1; /* 1 = Little Endian */
+ bigendian = 0; /* (for clarity in programming) */
+ } else {
+ byteorder = 0; /* Big Endian */
+ bigendian = 1;
+ }
+ if (sizeof(CK_OFF_T) == 8) /* Large files and ints? */
+ havelfs = 1;
+
+ if (sysinit() < 0) /* System-dependent initialization. */
+ fatal("Can't initialize!");
+ else
+ initflg = 1; /* Remember we did. */
+ debug(F111,"ckcmai myname",myname,howcalled);
+
+#ifdef UNIX
+ getexedir(); /* Compute exedir variable */
+#endif /* UNIX */
+
+#ifdef CKSYSLOG
+#ifdef SYSLOGLEVEL
+/*
+ If built with -DSYSLOGLEVEL on cc command line, this means we always
+ do syslogging at the indicated level.
+*/
+ zsyslog(); /* Open syslog */
+#else /* SYSLOGLEVEL */
+#ifdef IKSD
+ if (inserver)
+ zsyslog(); /* Open syslog */
+#endif /* IKSD */
+#endif /* SYSLOGLEVEL */
+#endif /* CKSYSLOG */
+
+#ifdef CK_KERBEROS
+ ini_kerb(); /* Initialize Kerberos data */
+#endif /* CK_KERBEROS */
+#ifdef CK_SSL
+ ssl_once_init();
+#endif /* CK_SSL */
+#ifdef TNCODE
+ tn_set_modes(); /* Init Telnet Option tables */
+#endif /* TNCODE */
+
+#ifdef CK_TTGWSIZ /* Initialize screen dimensions */
+#ifdef OS2
+ ttgcwsz();
+#else /* OS2 */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+#ifndef OS2
+#ifdef TCPSOCKET
+#ifdef CK_SOCKS
+ SOCKSinit(argv[0]); /* Internet relay package... */
+#endif /* CK_SOCKS */
+#endif /* TCPSOCKET */
+#endif /* OS2 */
+
+ initflow(); /* Initialize flow-control table */
+
+#ifndef NOICP
+#ifdef CKFLOAT
+ initfloat(); /* Deduce floating-point precision */
+#endif /* CKFLOAT */
+#endif /* NOICP */
+
+#ifndef NOXFER
+ initxlist(); /* Init exception lists */
+
+#ifdef CK_XYZ /* Initialize protocols... */
+
+#ifdef XYZ_INTERNAL /* XYZMODEM are internal ... */
+
+#ifdef COMMENT
+ /* Can't do this for XMODEM because if filename contains a "C" etc... */
+ initproto(PROTO_X, "rx %s","rx %s", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_XC,"rc %s","rc %s", NULL, NULL, NULL, NULL, NULL);
+#else /* COMMENT */
+ initproto(PROTO_X, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_XC,NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+#endif /* COMMENT */
+ initproto(PROTO_Y, "rb","rb", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_G, "rb","rb", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_Z, "rz","rz", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_K,"kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL);
+ /* Kermit Must be last */
+
+#else /* XYZMODEM are external protocols ... */
+
+ /* s1 s2 s3 s4 s5 s6 s7 */
+ initproto(PROTO_X, "rx %s","rx %s",NULL,"sx %s","sx -a %s","rx %s", "rx %s");
+ initproto(PROTO_XC,"rc %s","rc %s",NULL,"sx %s","sx -a %s","rc %s", "rc %s");
+ initproto(PROTO_Y, "rb", "rb", NULL,"sb %s","sb -a %s","rb", "rb" );
+ initproto(PROTO_G, "rb", "rb", NULL,"sb %s","sb -a %s","rb", "rb" );
+ initproto(PROTO_Z, "rz", "rz", NULL,"sz %s","sz -a %s","rz", "rz" );
+ initproto(PROTO_K, "kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL);
+ /* Kermit must be last */
+
+#endif /* XYZ_INTERNAL */
+
+#else /* No XYZMODEM support */
+
+ initproto(PROTO_K,"kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL);
+
+#endif /* CK_XYZ */
+#endif /* NOXFER */
+
+ connoi(); /* Console interrupts off */
+
+#ifndef NOXFER
+#ifdef OS2
+ /* Initialize Kermit and Zmodem Auto-Download Strings */
+ adl_kstr = strdup("KERMIT READY TO SEND...");
+ adl_zstr = strdup("rz\r");
+#endif /* OS2 */
+
+#ifdef PATTERNS
+ initpat(); /* Initialize filename patterns */
+#endif /* PATTERNS */
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+ initcsets(); /* Initialize character sets */
+#endif /* NOCSETS */
+
+#ifndef NOICP
+#ifdef DFCDMSG
+ makestr(&cdmsgstr,DFCDMSG);
+ makelist(cdmsgstr,cdmsgfile,8); /* Initialize CD message filenames */
+#endif /* DFCDMSG */
+#endif /* NOICP */
+
+ sstate = 0; /* No default start state. */
+#ifdef DYNAMIC
+ if (getiobs() < 0)
+ fatal("Can't allocate i/o buffers!");
+#endif /* DYNAMIC */
+
+#ifndef NOSPL
+#ifndef NORANDOM
+ {
+ char stackdata[256];
+ unsigned int c = 1234, n;
+ /* try to make a random unsigned int to feed srand() */
+#ifndef VMS
+ /* time.h and MultiNet do not get along */
+ c = time(NULL);
+#endif /* VMS */
+ c *= getpid();
+ /* Referenced before set... DELIBERATELY */
+ for (n = 0; n < sizeof(stackdata); n++) /* IGNORE WARNING */
+ c += stackdata[n]; /* DELIBERATELY USED BEFORE SET */
+ srand((unsigned int)c);
+ }
+#endif /* NORANDOM */
+#endif /* NOSPL */
+
+ ckhost(myhost,MYHOSTL); /* Name of local host */
+ debug(F110,"main ckhost",myhost,0);
+#ifdef IKSD
+ if (!inserver) {
+#endif /* IKSD */
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Set up default tty name. */
+ local = nolocal ? 0 : dfloc; /* And whether it's local or remote. */
+ parity = dfprty; /* Set initial parity, */
+#ifndef NOXFER
+ myindex = getsysix(cksysid); /* System index */
+#endif /* NOXFER */
+ if (local) if (ttopen(ttname,&local,0,0) < 0) {
+#ifndef OS2
+ conol("Can't open device: ");
+ conoll(ttname);
+#endif /* OS2 */
+ local = 0;
+ ckstrncpy(ttname,CTTNAM,TTNAMLEN);
+ }
+ setflow(); /* Set appropriate flow control */
+ speed = ttgspd(); /* Get transmission speed. */
+#ifdef IKSD
+ }
+#endif /* IKSD */
+
+#ifdef ANYX25 /* All X.25 implementations */
+#ifndef IBMX25 /* except IBM have PAD support */
+ initpad(); /* Initialize X.25 PAD */
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOXFER
+ if (inibufs(SBSIZ,RBSIZ) < 0) /* Allocate packet buffers */
+ fatal("Can't allocate packet buffers!");
+#ifndef NOCKSPEED
+ setprefix(prefixing); /* Set up control char prefixing */
+#endif /* NOCKSPEED */
+#endif /* NOXFER */
+
+#ifndef NOICP
+ if (sstelnet
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) {
+ int on = 1, x = 0;
+ extern int ckxech, ttnet, ttnproto, cmdmsk;
+#ifdef SO_SNDBUF
+ extern int tcp_sendbuf;
+#endif
+#ifdef SO_RCVBUF
+ extern int tcp_recvbuf;
+#endif
+#ifdef SO_KEEPALIVE
+ extern int tcp_keepalive;
+#endif
+#ifdef SO_LINGER
+ extern int tcp_linger, tcp_linger_tmo;
+#endif /* SO_LINGER */
+#ifdef SO_DONTROUTE
+ extern int tcp_dontroute;
+#endif /* SO_DONTROUTE */
+#ifdef TCP_NODELAY
+ extern int tcp_nodelay;
+#endif /* TCP_NODELAY */
+#ifdef IKSD
+ extern int iklogopen;
+#endif /* IKSD */
+ extern int ttmdm;
+
+#ifdef UNIX
+ if (isatty(0))
+ fatal("Internet Kermit Service cannot be started at a terminal.");
+#endif /* UNIX */
+
+ reliable = xreliable = SET_ON; /* IKSD has reliable connection */
+#ifndef VMS
+ flow = 0; /* No flow control needed */
+#endif /* VMS */
+ bgset = 0; /* Not in background */
+ nopush = 1; /* No external processes */
+ parity = 0; /* 8 bits ... */
+ cmdmsk = 0xff; /* all the way */
+ cmask = 0xff;
+
+#ifdef IKSD
+ if (inserver) { /* If IKSD */
+ doiksdinit(); /* Execute IKSD configuration file */
+ while (tlevel > -1)
+ parser(1); /* (Ignore any file-xfer commands) */
+ iksdcf = 1; /* IKSD c.f. has been processed */
+ }
+ if (!iklogopen) (VOID) doiklog(); /* Open Kermit-specific log */
+#endif /* IKSD */
+
+#ifdef UNIX
+ setbuf(stdout,NULL); /* Don't buffer the output */
+ ckstrncpy(ttname,"0",TTNAMLEN); /* not "/dev/tty"... */
+#endif /* UNIX */
+ local = 0; /* We are in remote mode */
+ ckxech = 1; /* We will echo */
+#ifdef OS2
+ nettype = NET_TCPB; /* So ttopen() treats the connection */
+ mdmtyp = -nettype; /* as a network */
+#endif /* OS2 */
+ debug(F100,"main about to call ttopen() inserver","",0);
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) { /* Open comm channel */
+ fatal("can't initialize i/o");
+ }
+#ifdef OS2
+ local = 0;
+ network = 1; /* Does use networking code */
+#else /* OS2 */
+ network = 0; /* Does not use networking code */
+#endif /* OS2 */
+ ttmdm = -1; /* Does not use a modem */
+ sstelnet = 1; /* Do server-side Telnet negotations */
+ debug(F111,"MAIN","sstelnet",sstelnet);
+ ttnet = NET_TCPB; /* Network type is TCP sockets */
+ ttnproto = NP_TELNET; /* Netword protocol is Telnet */
+#ifdef IKSDB
+ dbinit(); /* Initialize database record */
+#endif /* IKSDB */
+#ifndef OS2
+#ifdef CK_AUTHENTICATION
+ /* Before initializating Telnet/Rlogin negotiations, init Kerberos */
+ ck_auth_init(ckgetpeer(),"","",0);
+#endif /* CK_AUTHENTICATION */
+
+#ifdef NON_BLOCK_IO
+ on = 1;
+ x = socket_ioctl(0,FIONBIO,&on);
+ debug(F101,"main FIONBIO","",x);
+#endif /* NON_BLOCK_IO */
+#ifdef SO_OOBINLINE
+ on = 1;
+ x = setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on));
+ debug(F101,"main SO_OOBINLINE","",x);
+#endif /* SO_OOBINLINE */
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+ no_delay(0,tcp_nodelay);
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+ keepalive(0,tcp_keepalive);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ ck_linger(0,tcp_linger, tcp_linger_tmo);
+#endif /* SO_LINGER */
+#ifdef SO_DONTROUTE
+ dontroute(0,tcp_dontroute);
+#endif /* SO_DONTROUTE */
+#ifdef SO_SNDBUF
+ sendbuf(0,tcp_sendbuf);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ recvbuf(0,tcp_recvbuf);
+#endif /* SO_RCVBUF */
+#endif /* SOL_SOCKET */
+#endif /* datageneral */
+#endif /* NOTCPOPTS */
+
+#ifdef CK_SSL
+ if (ck_ssleay_is_installed()) {
+ if (!ssl_tn_init(SSL_SERVER)) {
+ if (bio_err != NULL) {
+ BIO_printf(bio_err,"do_ssleay_init() failed\r\n");
+ ERR_print_errors(bio_err);
+ } else {
+ fflush(stderr);
+ fprintf(stderr,"do_ssleay_init() failed\r\n");
+ ERR_print_errors_fp(stderr);
+ }
+ switch (ttnproto) {
+ case NP_SSL:
+ case NP_TLS:
+ case NP_SSL_RAW:
+ case NP_TLS_RAW:
+ case NP_SSL_TELNET:
+ case NP_TLS_TELNET:
+ doexit(BAD_EXIT,1);
+ }
+ /* otherwise we will continue to accept the connection */
+ /* without SSL or TLS support unless required. */
+ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ } else {
+ if ( ck_ssl_incoming(0) < 0 ) {
+ doexit(BAD_EXIT,1);
+ }
+ }
+ }
+#endif /* CK_SSL */
+
+#ifdef TNCODE
+ tn_ini(); /* Start Telnet negotiation now */
+#endif /* TNCODE */
+#endif /* OS2 */
+ }
+ debug(F101,"main argc after prescan()","",argc);
+
+ /* Now process any relevant environment variables */
+
+#ifndef NODIAL
+ getdialenv(); /* Dialing */
+#ifdef NETCONN
+ ndinit(); /* Initialize network directory info */
+ getnetenv(); /* Network directories */
+#endif /* NETCONN */
+#endif /* NODIAL */
+
+#ifndef NOXFER
+#ifdef CK_FAST
+ dofast(); /* By now FAST defaults should be OK */
+#endif /* CK_FAST */
+#endif /* NOXFER */
+
+#ifndef NOCMDL
+ ikslogin(); /* IKSD Login and other stuff */
+#ifdef IKSD
+#ifdef NT
+ if ( inserver )
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* NOCMDL */
+
+ if (howcalled == I_AM_SSHSUB) {
+ reliable = 1; /* We say the connection is reliable */
+ xreliable = 1; /* And that we said it was */
+ setreliable = 1; /* And pretend the "user" did too */
+ xfinish = 1; /* For REMOTE HELP response */
+ mdmtyp = 0; /* For ttopen() */
+ ckstrncpy(ttname,"0",TTNAMLEN+1); /* Use file descriptor 0 */
+ local = 0; /* And force remote mode */
+ ttopen(ttname,&local,mdmtyp,0); /* Open the "connection" */
+ sstate = 'x'; /* Initial state is Server */
+ proto(); /* Enter protocol */
+ doexit(GOOD_EXIT,xitsta); /* Exit when done */
+ }
+ debug(F111,"howcalled",myname,howcalled);
+
+#ifdef NOCCTRAP
+ dotakeini(0);
+#else /* NOCCTRAP */
+ debug(F100,"main about to cc_execute","",0);
+ setint();
+ cc_execute( ckjaddr(cmjbuf), dotakeini, failtakeini );
+#endif /* NOCCTRAP */
+
+ debug(F111,"main 2 cfilef",cmdfil,cfilef);
+ if (cmdfil[0]) { /* If we got one (see prescan())... */
+#ifdef NOCCTRAP
+ docmdfile(0); /* execute it. */
+#else /* NOCCTRAP */
+ setint();
+ cc_execute( ckjaddr(cmjbuf), docmdfile, failcmdfile );
+#endif /* NOCCTRAP */
+ }
+#ifndef OS2 /* Preserve name so we can delete it */
+ *cmdfil = '\0'; /* Done, nullify the file name */
+#endif /* OS2 */
+#endif /* NOICP */
+
+#ifndef NOCMDL
+/* Look for a UNIX-style command line... */
+
+ what = W_NOTHING;
+
+ debug(F101,"main argc","",argc);
+#ifndef NOHELP
+ iniopthlp(); /* Initialize cmdline arg help */
+#endif /* NOHELP */
+ if (
+#ifdef COMMENT
+ !cfilef &&
+#endif /* COMMENT */
+ argc > 1) { /* Command line arguments? */
+ sstate = (CHAR) cmdlin(); /* Yes, parse. */
+#ifdef NETCONN
+#ifndef NOURL
+ if (haveurl) { /* Was a URL given? */
+ dourl(); /* if so, do it. */
+ }
+#endif /* NOURL */
+#endif /* NETCONN */
+#ifndef NOXFER
+ zstate = sstate; /* Remember sstate around protocol */
+ debug(F101,"main zstate","",zstate);
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ if (cflg) { /* Connect first if requested */
+ doconect(0,0);
+ if (ttchk() < 0)
+ dologend();
+ cflg = 0;
+ }
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+ if (sstate) {
+#ifndef NOLOCAL
+ if (displa) concb((char)escape); /* (for console "interrupts") */
+#endif /* NOLOCAL */
+#ifdef NOCCTRAP
+ docmdline(1);
+#else /* NOCCTRAP */
+ setint();
+ cc_execute( ckjaddr(cmjbuf), docmdline, failcmdline );
+#endif /* NOCCTRAP */
+ }
+#endif /* NOXFER */
+
+#ifndef NOICP
+/*
+ If a command-line action argument was given and -S ("stay") was not given,
+ exit now.
+*/
+ if ((cflg || cnflg || zstate) && !stayflg)
+#endif /* NOICP */
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+
+#ifndef NOLOCAL
+#ifndef NOICP
+ if (local) {
+#ifdef NETCONN
+ if ((cflg || cnflg) && tn_exit && ttchk() < 0)
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+#endif /* NETCONN */
+ if (exitonclose && !network &&
+ (carrier != CAR_OFF && (ttgmdm() & BM_DCD) == 0))
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+ if (exitonclose && network && ttchk() < 0)
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+ }
+#endif /* NOICP */
+#endif /* NOLOCAL */
+ }
+#endif /* NOCMDL */
+
+#ifdef NOICP /* No interactive command parser */
+#ifndef NOCMDL
+ else {
+
+ /* Command-line-only version */
+ fatal("?No command-line options given - type 'kermit -h' for help");
+ }
+#else /* Neither one! */
+ sstate = 'x';
+ justone = 0;
+ proto(); /* So go into server mode */
+ doexit(GOOD_EXIT,xitsta); /* exit with good status */
+
+#endif /* NOCMDL */
+#else /* not NOICP */
+/*
+ If no action requested on command line, or if -S ("stay") was included,
+ enter the interactive command parser.
+*/
+ if (!clcmds)
+ herald(); /* Display program herald. */
+
+#ifdef NOCCTRAP
+ debug(F100,"main NOCCTRAP setting interrupt trap","",0);
+ setint(); /* Set up command interrupt traps */
+ doicp(NULL);
+#else /* NOCCTRAP */
+ while (1) {
+ debug(F100,"main setting interrupt trap","",0);
+ setint(); /* Set up command interrupt traps */
+ if (!cc_execute(ckjaddr(cmjbuf), doicp, failicp))
+ break;
+ }
+#endif /* NOCCTRAP */
+#endif /* NOICP */
+#ifndef MAINISVOID
+ return(1);
+#endif /* MAINISVOID */
+}
+
+#ifdef DYNAMIC
+/* Allocate file i/o buffers */
+
+char *zinbuffer = NULL, *zoutbuffer = NULL;
+
+int
+getiobs() {
+ zinbuffer = (char *)malloc(INBUFSIZE);
+ if (!zinbuffer) return(-1);
+ zoutbuffer = (char *)malloc(zobufsize);
+ debug(F101,"zoutbuffer malloc","",zobufsize);
+ if (!zoutbuffer) return(-1);
+ debug(F100,"getiobs ok","",0);
+ return(0);
+}
+#endif /* DYNAMIC */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcmai.c.c99 b/ckermit-9.0.302-build/ckermit-9.0.302/ckcmai.c.c99
new file mode 100644
index 0000000..a5640e5
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcmai.c.c99
@@ -0,0 +1,3576 @@
+#define EDITDATE "20 Aug 2011" /* Last edit date dd mmm yyyy */
+#define EDITNDATE "20110820" /* Keep them in sync */
+/* Sat Aug 20 17:20:17 2011 */
+
+/* ckcmai.c - Main program for C-Kermit plus some miscellaneous functions */
+
+/*
+ ckcsym.h is used for for defining symbols that normally would be defined
+ using -D or -d on the cc command line, for use with compilers that don't
+ support this feature. Must come before any tests for preprocessor symbols.
+*/
+#include "ckcsym.h"
+/*
+ Consolidated program C-Kermit version information for all platforms
+ (but for UNIX also see ckuver.h). See makever() below for how they are used.
+*/
+#ifdef COMMENT /* Uncomment this for real K95 version */
+#ifndef OS2 /* OS2 actually means Kermit 95. */
+#ifndef BETATEST /* It's because Kermit 95 started */
+#define BETATEST /* out as C-Kermit for OS/2. */
+#endif /* BETATEST */
+#endif /* OS2 */
+#endif /* COMMENT */
+
+#ifdef BETATEST
+#ifdef OS2
+#ifdef __DATE__
+#define BETADATE
+#endif /* __DATE__ */
+#endif /* OS2 */
+#endif /* BETATEST */
+
+char * ck_cryear = "2011"; /* C-Kermit copyright year */
+
+#ifndef MAC /* MAC = Kermit for MAC OS 6, 7, ... */
+/*
+ Note: initialize ck_s_test to "" if this is not a test version.
+ Use (*ck_s_test != '\0') to decide whether to print test-related messages.
+*/
+
+#ifndef BETATEST
+#ifndef OS2 /* UNIX, VMS, etc... (i.e. C-Kermit) */
+char *ck_s_test = ""; /* "Dev","Alpha","Beta","RC", or "" */
+char *ck_s_tver = ""; /* Test version number or "" */
+#else /* OS2 */
+char *ck_s_test = ""; /* (i.e. K95) */
+char *ck_s_tver = "";
+#endif /* OS2 */
+#else
+char *ck_s_test = ""; /* Development */
+char *ck_s_tver = "";
+#endif /* BETATEST */
+#else /* MAC */
+char *ck_s_test = "Pre-Alpha"; /* Mac Kermit is always a test... */
+char *ck_s_tver = ""; /* (pre Mac OS X 10, that is!) */
+#endif /* MAC */
+
+#ifdef BETADATE /* Date of this version or edit */
+char *ck_s_date = __DATE__; /* Compilation date */
+#else
+char *ck_s_date = EDITDATE; /* See top */
+
+#endif /* BETADATE */
+char *buildid = EDITNDATE; /* See top */
+
+#ifdef UNIX
+static char sccsid[] = "@(#)C-Kermit 9.0.302";
+#endif /* UNIX */
+
+/*
+ The C-Kermit Version number is major.minor.edit (integers).
+ Major version always goes up.
+ Minor version is historical, hasn't been used since C-Kermit 7.1.
+ Edit is sequential, always goes up, but there can be gaps.
+ For example there might be many edits between releases.
+ If the major goes to 10, some version-number-based feature tests
+ could fail. It might be better to use the minor version field
+ for future releases.
+*/
+
+char *ck_s_ver = "9.0.302"; /* C-Kermit version string */
+long ck_l_ver = 900302L; /* C-Kermit version number */
+
+#ifdef OS2
+char *ck_s_xver = "3.0.0"; /* Product-specific version string */
+long ck_l_xver = 3000L; /* Product-specific version number */
+#else
+#ifdef MAC
+char *ck_s_xver = "0.995"; /* Product-specific version string */
+long ck_l_xver = 995L; /* Product-specific version number */
+#else
+char *ck_s_xver = ""; /* Don't touch these... */
+long ck_l_xver = 0L; /* they are computed at runtime */
+#endif /* MAC */
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef IKSDONLY
+#ifdef NT
+char *ck_s_name = "IKS-NT";
+#else /* NT */
+char *ck_s_name = "IKS-OS/2";
+#endif /* NT */
+#else /* IKSDONLY */
+char *ck_s_name = "Kermit 95"; /* Program name */
+#endif /* IKSDONLY */
+#else
+#ifdef MAC
+char *ck_s_name = "Mac Kermit";
+#else
+char *ck_s_name = "C-Kermit";
+#endif /* MAC */
+#endif /* OS2 */
+
+char *ck_s_who = ""; /* Where customized, "" = not. */
+char *ck_patch = ""; /* Patch info, if any. */
+
+#define CKVERLEN 128
+char versiox[CKVERLEN]; /* Version string buffer */
+char *versio = versiox; /* These are filled in at */
+long vernum, xvernum; /* runtime from above. */
+
+#define CKCMAI
+
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckcdeb.h" /* Debug & other symbols */
+
+char * myname = NULL; /* The name I am called by */
+#ifndef OS2
+char * exedir = NULL; /* Directory I was executed from */
+#endif /* OS2 */
+char * myhome = NULL; /* Home directory override */
+
+/* C K C M A I -- C-Kermit Main program */
+
+/*
+ Author: Frank da Cruz (fdc@columbia.edu),
+ Columbia University in the city of New York,
+ Computer Center / Center for Computing Activities / Information Technology.
+ I am no longer at Columbia U as of 1 July 2011, but the email address
+ should still work. The Kermit website http://kermit.columbia.edu should
+ still be available and under my control, as well as the Kermit FTP site,
+ ftp://kermit.columbia.edu/kermit/.
+
+COPYRIGHT NOTICE:
+*/
+
+char *copyright[] = {
+
+#ifdef pdp11
+"Copyright (C) 1985, %s, Trustees of Columbia University, NYC.",
+"All rights reserved.",
+" ",
+#else
+"Copyright (C) 1985, %s,",
+" The Trustees of Columbia University in the City of New York.",
+" All rights reserved.",
+" ",
+"Redistribution and use in source and binary forms, with or without",
+"modification, are permitted provided that the following conditions",
+"are met:",
+" ",
+" + Redistributions of source code must retain the above copyright",
+" notice, this list of conditions and the following disclaimer.",
+" ",
+" + Redistributions in binary form must reproduce the above copyright",
+" notice, this list of conditions and the following disclaimer in",
+" the documentation and/or other materials provided with the",
+" distribution.",
+" ",
+" + Neither the name of Columbia University nor the names of its",
+" contributors may be used to endorse or promote products derived",
+" from this software without specific prior written permission.",
+" ",
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS",
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT",
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR",
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT",
+"HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,",
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT",
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,",
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY",
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT",
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE",
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
+#endif /* pdp11 */
+
+#ifdef OS2
+"Portions Copyright (C) 2002-2005, Secure Endpoints Inc, New York NY USA.",
+"Portions Copyright (C) 1995, Oy Online Solutions Ltd., Jyvaskyla, Finland.",
+#endif /* OS2 */
+
+#ifdef CK_AUTHENTICATION
+"Portions Copyright (C) 1990, Massachusetts Institute of Technology.",
+#ifdef CK_ENCRYPTION
+"Portions Copyright (C) 1991, 1993 Regents of the University of California.",
+"Portions Copyright (C) 1991, 1992, 1993, 1994, 1995 by AT&T.",
+"Portions Copyright (C) 1995, 1997, Eric Young <eay@cryptosoft.com>.",
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SRP
+"Portions Copyright (C) 1997, Stanford University.",
+#endif /* CK_SRP */
+#endif /* CK_AUTHENTICATION */
+
+#ifndef pdp11
+" ",
+"For further information, visit the Kermit Project website:",
+"http://www.columbia.edu/kermit/ .",
+#endif /* pdp11 */
+""};
+
+/* Windows IKSD copyright used to be separate */
+char *wiksdcpr = (char *) copyright;
+
+
+/*
+DOCUMENTATION:
+
+ "Using C-Kermit" by Frank da Cruz and Christine M. Gianone,
+ Digital Press / Butterworth-Heinemann, Woburn MA, USA.
+ Second edition (1997), ISBN 1-55558-164-1.
+ Order from Digital Press: +1 (800) 366-2665
+ Or from Columbia University: +1 (212) 854-3703
+
+For Kermit 95, also:
+
+ "Kermit 95" by Christine M. Gianone and Frank da Cruz,
+ Manning Publications, Greenwich CT, USA (1998) - Online.
+
+ACKNOWLEDGMENTS:
+
+ The Kermit file transfer protocol was developed at the Columbia University
+ Center for Computing Activities (CUCCA), which was since renamed to Columbia
+ University Academic Information Systems (AcIS) and after that Columbia
+ University Information Technology (CUIT). Kermit is named after Kermit the
+ Frog, star of the television series THE MUPPET SHOW; the name is used by
+ permission of Henson Associates, Inc.
+
+ Thanks to at least the following people for their contributions to this
+ program over the years, and apologies to anyone who was inadvertantly
+ omitted:
+
+ Chris Adie, Edinburgh U, Scotland (OS/2)
+ Robert Adsett, University of Waterloo, Canada
+ Larry Afrin, Clemson U
+ Russ Allbery, Stanford U
+ Jeffrey Altman, Columbia University
+ Greg Andrews, Telebit Corp
+ Barry Archer, U of Missouri
+ Robert Andersson, International Systems A/S, Oslo, Norway
+ Chris Armstrong, Brookhaven National Lab (OS/2)
+ William Bader, Software Consulting Services, Nazareth, PA
+ Fuat Baran, Columbia U
+ Stan Barber, Rice U
+ Jim Barbour, U of Colorado
+ Donn Baumgartner, Dell
+ Ian Beckwith, Debian Project
+ Nelson Beebe, U of Utah
+ Gerry Belanger, Cognitronics
+ Karl Berry, UMB
+ Mark Berryman, SAIC
+ Dean W Bettinger, SUNY
+ Gary Bilkus
+ Peter Binderup, Denmark
+ David Bolen, Advanced Networks and Services, Inc.
+ Joop Bonen
+ Marc Boucher, U of Montreal
+ Charles Brooks, EDN
+ Bob Brown
+ Mike Brown, Purdue U
+ Rob Brown
+ Jack Bryans, California State U at Long Beach
+ Mark Buda, DEC (VMS)
+ Fernando Cabral, Padrao iX, Brasilia
+ Bjorn Carlsson, Stockholm University Computer Centre QZ, Sweden
+ Bill Catchings, (formerly of) Columbia U
+ Bob Cattani, Columbia U CS Dept
+ Davide Cervone, Rochester U
+ Seth Chaiklin, Denmark
+ John Chandler, Harvard U / Smithsonian Astronomical Observatory
+ Bernard Chen, UCLA
+ Andrew A Chernov, RELCOM Team, Moscow
+ John L Chmielewski, AT&T, Lisle, IL
+ Howard Chu, U of Michigan
+ Bill Coalson, McDonnell Douglas
+ Bertie Coopersmith, London
+ Christian Corti
+ Chet Creider, U of Western Ontario
+ Alan Crosswell, Columbia U
+ Jeff Damens, (formerly of) Columbia U
+ Mark Davies, Bath U, UK
+ Sin-itirou Dezawa, Fujifilm, Japan
+ Joe R. Doupnik, Utah State U
+ Frank Dreano, Honeywell
+ John Dunlap, U of Washington
+ Alex Dupuy, SMART.COM
+ David Dyck, John Fluke Mfg Co.
+ Stefaan A. Eeckels, Eurokom, Luxembourg
+ Nick Efthymiou
+ Paul Eggert, Twin Sun, Inc., El Segundo, CA
+ Bernie Eiben, DEC
+ Peter Eichhorn, Assyst International
+ Kristoffer Eriksson, Peridot Konsult AB, Oerebro, Sweden
+ John R. Evans, IRS, Kansas City
+ Glenn Everhart, RCA Labs
+ Charlie Finan, Cray Research
+ Herm Fischer, Encino, CA (extensive contributions to version 4.0)
+ Carl Fongheiser, CWRU
+ Mike Freeman, Bonneville Power Authority
+ Carl Friedberg
+ Marcello Frutig, Catholic University, Sao Paulo, Brazil (X.25 support)
+ Hirofumi Fujii, Japan Nat'l Lab for High Energy Physics, Tokyo (Kanji)
+ Chuck Fuller, Westinghouse Corporate Computer Services
+ Andy Fyfe, Caltech
+ Christine M. Gianone, Columbia U
+ John Gilmore, UC Berkeley
+ Madhusudan Giyyarpuram, HP
+ Rainer Glaschick, Siemens AG, Paderborn
+ William H. Glass
+ German Goldszmidt, IBM
+ Chuck Goodhart, NASA
+ Alistair Gorman, New Zealand
+ Richard Gration, ADFA, Australia
+ Chris Green, Essex U, UK
+ Alan Grieg, Dundee Tech, Scotland
+ Yekta Gursel, MIT
+ Jim Guyton, Rand Corp
+ Michael Haertel
+ Bruno Haible
+ Bob Hain, UMN
+ Marion Hakanson, ORST
+ Richard Hamilton
+ John Hamilston, Iowa State U
+ Simon Hania, Netherlands
+ Stan Hanks, Rice U.
+ Ken Harrenstein, SRI
+ Eugenia Harris, Data General (AOS/VS)
+ David Harrison, Kingston Warren Corp
+ Lucas Hart, Oregon State University
+ James Harvey, Indiana/Purdue U (VMS)
+ Rob Healey
+ Chuck Hedrick, Rutgers U
+ Ron Heiby, Technical Systems Division, Motorola Computer Group
+ Steve Hemminger, Tektronix
+ Christian Hemsing, RWTH Aachen, Germany (OS-9)
+ Randolph Herber, US DOE,
+ Andrew Herbert, Monash Univ, Australia
+ Marcus Herbert, Germany
+ Mike Hickey, ITI
+ Dan Hildebrand, QNX Software Systems Inc, Kanata, ON (QNX)
+ R E Hill
+ Stephan Hoffman-Emden
+ Sven Holmstrom, ABB Utilities AB, Sweden
+ Bill Homer, Cray Research
+ Ray Hunter, The Wollongong Group
+ Randy Huntziger, National Library of Medicine
+ Larry Jacobs, Transarc
+ Steve Jenkins, Lancaster University, UK
+ Dave Johnson, Gradient Technologies
+ Mark B Johnson, Apple Computer
+ Jyke Jokinen, Tampere University of Technology, Finland (QNX)
+ Eric F Jones, AT&T
+ Luke Jones, AT&T
+ Peter Jones, U of Quebec Montreal
+ Phil Julian, SAS Institute
+ Peter Kabal, U of Quebec
+ Mic Kaczmarczik, U of Texas at Austin
+ Sergey Kartashoff, Inst. of Precise Mechanics & Computer Equipment, Moscow
+ Howie Kaye, Columbia U
+ Rob Kedoin, Linotype Co, Hauppauge, NY (OS/2)
+ Phil Keegstra
+ Mark Kennedy, IBM
+ Terry Kennedy, St Peter's College, Jersey City, NJ (VMS and more)
+ "Carlo Kid", Technical University of Delft, Netherlands
+ Tim Kientzle
+ Paul Kimoto, Cornell U
+ Douglas Kingston, morgan.com
+ Lawrence Kirby, Wiltshire, UK
+ Tom Kloos, Sequent Computer Systems
+ Guenter Knauf
+ Jim Knutson, U of Texas at Austin
+ John T. Kohl (BSDI)
+ Scott Kramer, SRI International, Menlo Park, CA
+ John Kraynack, US Postal Service
+ David Kricker, Encore Computer
+ Thomas Krueger, UWM
+ Bo Kullmar, ABC Klubben, Stockholm, and Central Bank of Sweden, Kista
+ R. Brad Kummer, AT&T Bell Labs, Atlanta, GA
+ John Kunze, UC Berkeley
+ David Lane, BSSI / BellSouth (Stratus VOS, X.25)
+ Bob Larson, USC (OS-9)
+ Bert Laverman, Groningen U, Netherlands
+ Steve Layton
+ David Lawyer, UC Irvine
+ Jason Lehr
+ David LeVine, National Semiconductor Corporation
+ Daniel S. Lewart, UIUC
+ S.O. Lidie, Lehigh U
+ Tor Lillqvist, Helsinki U, Finland
+ David-Michael Lincke, U of St Gallen, Switzerland
+ Robert Lipe (for SCO makefile entries & advice)
+ Dean Long
+ Mike Long, Analog Devices, Norwood MA
+ Kevin Lowey, U of Saskatchewan (OS/2)
+ Andy Lowry, Columbia U
+ James Lummel, Caprica Telecomputing Resources (QNX)
+ Lewis McCarthy
+ David MacKenzie, Environmental Defense Fund, U of Maryland
+ John Mackin, University of Sidney, Australia
+ Martin Maclaren, Bath U, UK
+ Chris Maio, Columbia U CS Dept
+ Montserrat Mane, HP, Grenoble, France
+ Fulvio Marino, Olivetti, Ivrea, Italy
+ Arthur Marsh, dircsa.org.au
+ Peter Mauzey, Lucent Technologies
+ Tye McQueen, Utah State U
+ Ted Medin
+ Hellmuth Michaelis, Hanseatischer Computerservice GmbH, Hamburg, Germany
+ Leslie Mikesell, American Farm Bureau
+ Todd Miller, Courtesan Consulting
+ Gary Mills
+ Martin Minow, DEC (VMS)
+ Pawan Misra, Bellcore
+ Ken Mizialko, IBM, Manassas, VA
+ Wolfgang Moeller, DECUS Germany
+ Ray Moody, Purdue U
+ Bruce J Moore, Allen-Bradley Co, Highland Heights, OH (Atari ST)
+ Steve Morley, Convex
+ Peter Mossel, Columbia U
+ Tony Movshon, NYU
+ Lou Muccioli, Swanson Analysis Systems
+ Dan Murphy
+ Neal P. Murphy, Harsof Systems, Wonder Lake IL
+ Gary Mussar
+ John Nall, FSU
+ Jack Nelson, U of Pittsburgh
+ Jim Noble, Planning Research Corporation (Macintosh)
+ Ian O'Brien, Bath U, UK
+ Melissa O'Neill, SFU
+ John Owens
+ Thomas Pinkl, Health Business Systems Inc.
+ Michael Pins, Iowa Computer Aided Engineering Network
+ Andre' Pirard, University of Liege, Belgium
+ Paul Placeway, Ohio State U
+ Piet W. Plomp, ICCE, Groningen University, Netherlands
+ Ken Poulton, HP Labs
+ Manfred Prange, Oakland U
+ Christopher Pratt, APV Baker, UK
+ Frank Prindle, NADC
+ Tony Querubin, U of Hawaii
+ Jean-Pierre Radley
+ Anton Rang
+ Mike Rechtman
+ Scott Ribe
+ Alan Robiette, Oxford University, UK
+ Michel Robitaille, U of Montreal (Mac)
+ Huw Rogers, Schweizerische Kreditanstalt, Zuerich
+ Nigel Roles, Cambridge, England
+ Kai Uwe Rommel, Technische Universitaet Muenchen (OS/2)
+ Larry Rosenman (Amiga)
+ Jay Rouman, U of Michigan
+ Jack Rouse, SAS Institute (Data General and/or Apollo)
+ Stew Rubenstein, Harvard U (VMS)
+ Gerhard Rueckle, FH Darmstadt, Fb. E/Automatisierungstechnik
+ John Santos, EG&H
+ Bill Schilit, Columbia U
+ Ulli Schlueter, RWTH Aachen, Germany (OS-9, etc)
+ Michael Schmidt, U of Paderborn, Germany
+ Eric Schnoebelen, Convex
+ Benn Schreiber, DEC
+ Dan Schullman, DEC (modems, DIAL command, etc)
+ John Schultz, 3M
+ Steven Schultz, Contel (PDP-11)
+ Steven Schweda
+ APPP Scorer, Leeds Polytechnic, UK
+ Gordon Scott, Micro Focus, Newbury UK
+ Gisbert W. Selke, WIdO, Bonn, Germany
+ Kijal Shah
+ David Singer, IBM Almaden Research Labs
+ David Sizeland, U of London Medical School
+ Fridrik Skulason, Iceland
+ Rick Sladkey (Linux)
+ Dave Slate
+ Bradley Smith, UCLA
+ Fred Smith, Merk / Computrition
+ Richard S Smith, Cal State
+ Ryan Stanisfer, UNT
+ Bertil Stenstroem, Stockholm University Computer Centre (QZ), Sweden
+ James Sturdevant, CAP GEMENI AMERICA, Minneapolis
+ Peter Svanberg, Royal Techn. HS, Sweden
+ James R. Swenson, Accu-Weather, Inc.
+ Ted T'so, MIT (Linux)
+ Andy Tanenbaum, Vrije U, Amsterdam, Netherlands
+ Seth Theriault, Columbia U
+ Glen Thobe
+ Markku Toijala, Helsinki U of Technology
+ Teemu Torma, Helsinki U of Technology
+ Linus Torvalds, Helsinki
+ Rick Troxel, NIH
+ Warren Tucker, Tridom Corp, Mountain Park, GA
+ Dave Tweten, AMES-NAS
+ G Uddeborg, Sweden
+ Walter Underwood, Ford Aerospace
+ Pieter Van Der Linden, Centre Mondial, Paris
+ Ge van Geldorp, Netherlands
+ Fred van Kempen, MINIX User Group, Voorhout, Netherlands
+ Wayne Van Pelt, GE/CRD
+ Mark Vasoll, Oklahoma State U (V7 UNIX)
+ Konstantin Vinogradov, ICSTI, Moscow
+ Paul Vixie, DEC
+ Bernie Volz, Process Software
+ Eduard Vopicka, Prague University of Economics, Czech Republic
+ Martin Vorlaender
+ Dimitri Vulis, CUNY
+ Roger Wallace, Raytheon
+ Stephen Walton, Calif State U, Northridge (Amiga)
+ Jamie Watson, Adasoft, Switzerland (AIX)
+ Rick Watson, U of Texas (Macintosh)
+ Eric Weaver, Columbia U
+ Scott Weikart (Association for Progressive Communications)
+ Robert Weiner, Programming Plus, New York City
+ Lauren Weinstein, Vortex Technlogy
+ David Wexelblat, AT&T
+ Clark Wierda, Illuminati Online
+ Joachim Wiesel, U of Karlsruhe
+ Lon Willett, U of Utah
+ Michael Williams, UCLA
+ Nate Williams, U of Montana
+ David Wilson
+ Joellen Windsor, U of Arizona
+ Patrick Wolfe, Kuck & Associates, Inc.
+ Gregg Wonderly, Oklahoma State U (V7 UNIX)
+ Farrell Woods, Concurrent (formerly Masscomp)
+ Dave Woolley, CAP Communication Systems, London
+ Jack Woolley, SCT Corp
+ Frank Wortner
+ Ken Yap, formerly of U of Rochester
+ John Zeeff, Ann Arbor, MI
+*/
+
+#include "ckcker.h" /* Kermit symbols */
+#include "ckcnet.h" /* Network symbols */
+
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifndef NOSPL
+#include "ckuusr.h"
+#endif /* NOSPL */
+
+#ifdef OS2ONLY
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#endif /* OS2ONLY */
+
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#endif /* NT */
+
+#ifndef NOSERVER
+/* Text message definitions.. each should be 256 chars long, or less. */
+#ifdef MINIX
+char *srvtxt = "\r\n\
+Entering server mode.\r\n\0";
+#else
+#ifdef OLDMSG
+/*
+ It seems there was a large installation that was using C-Kermit 5A(165)
+ or thereabouts, which had deployed thousands of MS-DOS Kermit scripts in
+ scattered locations that looked for strings in the old server message,
+ which changed in 5A(183), August 1992.
+*/
+char *srvtxt = "\r\n\
+C-Kermit server starting. Return to your local machine by typing\r\n\
+its escape sequence for closing the connection, and issue further\r\n\
+commands from there. To shut down the C-Kermit server, issue the\r\n\
+FINISH or BYE command and then reconnect.\n\
+\r\n\0";
+#else
+#ifdef OSK
+char *srvtxt = "\r\012\
+Entering server mode. If your local Kermit software is menu driven, use\r\012\
+the menus to send commands to the server. Otherwise, enter the escape\r\012\
+sequence to return to your local Kermit prompt and issue commands from\r\012\
+there. Use SEND and GET for file transfer. Use REMOTE HELP for a list of\r\012\
+other available services. Use BYE or FINISH to end server mode.\r\012\0";
+#else /* UNIX, VMS, AOS/VS, and all others */
+char *srvtxt = "\r\n\
+Entering server mode. If your local Kermit software is menu driven, use\r\n\
+the menus to send commands to the server. Otherwise, enter the escape\r\n\
+sequence to return to your local Kermit prompt and issue commands from\r\n\
+there. Use SEND and GET for file transfer. Use REMOTE HELP for a list of\r\n\
+other available services. Use BYE or FINISH to end server mode.\r\n\0";
+#endif /* OSK */
+#endif /* OLDMSG */
+#endif /* MINIX */
+#else /* server mode disabled */
+char *srvtxt = "";
+#endif /* NOSERVER */
+
+int initflg = 0; /* sysinit() has executed... */
+int howcalled = I_AM_KERMIT; /* How I was called */
+int hmtopline = 0;
+int quitting = 0; /* I'm in the act of quitting */
+
+#ifdef IKSDCONF
+char * iksdconf = IKSDCONF; /* IKSD configuration file */
+int iksdcf = 0; /* Has IKSD c.f. been processed? */
+#endif /* IKSDCONF */
+
+int srvcdmsg = 0; /* [Server] CD message */
+char * cdmsgfile[8] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
+char * cdmsgstr = NULL;
+char * ckcdpath = NULL;
+
+#ifdef NLCHAR /* Text-file line terminator */
+CHAR feol = NLCHAR;
+#else
+CHAR feol = 0;
+#endif /* NLCHAR */
+
+int fblksiz = DBLKSIZ; /* File blocksize */
+int frecl = DLRECL; /* File record length */
+int frecfm = XYFF_S; /* File record format (default = stream) */
+int forg = XYFO_S; /* File organization (sequential) */
+int fcctrl = XYFP_N; /* File carriage control (ctrl chars) */
+int filecase = FILECASE; /* Case matters in filenames */
+int stathack = 1; /* Fast directory lookups by default */
+
+char uidbuf[UIDBUFLEN] = { NUL, NUL }; /* User ID buffer */
+int cfilef = 0; /* Application ("kerbang") file flag */
+char cmdfil[CKMAXPATH + 1] = { NUL, NUL }; /* Application file name */
+int haveurl = 0; /* URL given on command line */
+
+#ifndef NOXFER
+/* Multi-protocol support */
+
+struct ck_p ptab[NPROTOS] = { /* Initialize the Kermit part ... */
+ { "Kermit",
+ DRPSIZ, /* Receive packet size */
+ DSPSIZ, /* Send packet size */
+ 0, /* Send-packet-size-set flag */
+ DFWSIZ, /* Window size */
+
+#ifdef NEWDEFAULTS
+ PX_CAU, /* Control char unprefixing... */
+#else
+ PX_ALL,
+#endif /* NEWDEFAULTS */
+
+#ifdef VMS /* Default filename collision action */
+ XYFX_X, /* REPLACE for VAX/VMS */
+#else
+ XYFX_B, /* BACKUP for everybody else */
+#endif /* VMS */
+
+#ifdef OS2 /* Flag for file name conversion */
+ XYFN_L, /* Literal for OS2 */
+#else
+ XYFN_C, /* Converted for others */
+#endif /* OS2 */
+
+ PATH_OFF, /* Send pathnames OFF */
+ PATH_AUTO, /* Receive pathnames AUTO */
+ NULL, /* Host receive initiation string (binary) */
+ NULL, /* Host receive initiation string (text) */
+ NULL, /* Host server string */
+ NULL, /* External protocol send command (binary) */
+ NULL, /* External protocol send command (text) */
+ NULL, /* External protocol receive command (bin) */
+ NULL } /* External protocol receive command (txt) */
+#ifdef CK_XYZ
+,
+{"XMODEM", 128,128,-1,-1, 1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"XMODEM-CRC",128,128,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"YMODEM", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"YMODEM-g", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"ZMODEM", -1, -1,-1,-1,PX_WIL,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
+{"Other", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+#endif /* CK_XYZ */
+};
+
+/* Declarations for Send-Init Parameters */
+
+int spsiz = DSPSIZ, /* Current packet size to send */
+ spmax = DSPSIZ, /* Biggest packet size we can send */
+ lastspmax = DSPSIZ, /* Send-packet size last used */
+ spsizr = DSPSIZ, /* Send-packet size requested */
+ spsizf = 0, /* Flag to override size negotiation */
+ rpsiz = DRPSIZ, /* Biggest we want to receive */
+ urpsiz = DRPSIZ, /* User-requested receive pkt size */
+ maxrps = MAXRP, /* Maximum incoming long packet size */
+ maxsps = MAXSP, /* Maximum outbound l.p. size */
+ maxtry = MAXTRY, /* Maximum retries per packet */
+ wslots = 1, /* Window size currently in use */
+ wslotr = DFWSIZ, /* Window size from SET WINDOW */
+ wslotn = 1, /* Window size negotiated in S-pkt */
+ timeouts = 0, /* For statistics reporting */
+ spackets = 0, /* ... */
+ rpackets = 0, /* ... */
+ retrans = 0, /* ... */
+ crunched = 0, /* ... */
+ wmax = 0, /* ... */
+ wcur = 0, /* ... */
+ srvidl = 0, /* Server idle timeout */
+ srvdis = 1, /* Server file xfer display */
+ srvtim = DSRVTIM, /* Server command wait timeout */
+ srvping = 1, /* Server keepalive */
+/*
+ timint is the timeout interval I use when waiting for a packet.
+ pkttim is the SET RECEIVE TIMEOUT value, sent to the other Kermit.
+ rtimo is the SET SEND TIMEOUT value. rtimo is the initial value of
+ timint. timint is changed by the value in the incoming negotiation
+ packet unless a SET SEND TIMEOUT command was given.
+*/
+ timint = DMYTIM, /* Timeout interval I use */
+ pkttim = URTIME, /* Timeout I want you to use */
+ rtimo = DMYTIM, /* Normal packet wait timeout */
+ timef = 0, /* Flag to override what you ask */
+#ifdef CK_TIMERS
+ rttflg = 1, /* Use dynamic round-trip timers */
+#else
+ rttflg = 0, /* Use fixed timer */
+#endif /* CK_TIMERS */
+ mintime = 1, /* Minimum timeout */
+ maxtime = 0, /* Maximum timeout */
+
+ npad = MYPADN, /* How much padding to send */
+ mypadn = MYPADN, /* How much padding to ask for */
+ bctr = DFBCT, /* Block check type requested */
+ bctu = 1, /* Block check type used */
+ bctl = 1, /* Block check length */
+ bctf = 0, /* Block check type 3 forced on all */
+ c_save = -1, /* Block check saving and restoring */
+ ss_save = -1, /* Slow-start saving and restoring */
+ ebq = MYEBQ, /* 8th bit prefix */
+ ebqflg = 0, /* 8th-bit quoting flag */
+ rqf = -1, /* Flag used in 8bq negotiation */
+ rq = 0, /* Received 8bq bid */
+ sq = 'Y', /* Sent 8bq bid */
+ rpt = 0, /* Repeat count */
+ rptq = MYRPTQ, /* Repeat prefix */
+ rptflg = 0, /* Repeat processing flag */
+ rptena = 1, /* Repeat processing enabled */
+ xfrcan = 1, /* Transfer cancellation enabled */
+ xfrint = 1, /* Transfer interruption enabled */
+ xfrchr = 3, /* Transfer cancel char = Ctrl-C */
+ xfrnum = 3, /* Need three of them by default */
+ g_xfrxla = -1;
+ char * xfrmsg = NULL; /* Message for f.t. display screen */
+#endif /* NOXFER */
+
+#ifdef NOCSETS
+int xfrxla = 0; /* Character-set translation */
+#else
+int xfrxla = 1; /* enabled or disabled */
+#endif /* NOCSETS */
+
+int havelfs = 0; /* Large file support available */
+
+#ifndef NOXFER
+int epktflg = 0; /* E-PACKET command active */
+
+int capas = 9, /* Position of Capabilities */
+ lpcapb = 2, /* Long Packet capability */
+ lpcapr = 1, /* requested */
+ lpcapu = 0, /* used */
+ swcapb = 4, /* Sliding Window capability */
+ swcapr = 1, /* requested (allowed) */
+ swcapu = 0, /* used */
+ atcapb = 8, /* Attribute capability */
+ atcapr = 1, /* requested */
+ atcapu = 0, /* used */
+ rscapb = 16, /* RESEND capability */
+ rscapr = 1, /* requested by default */
+ rscapu = 0, /* used */
+ lscapb = 32, /* Locking Shift capability */
+ lscapr = 1, /* requested by default */
+ lscapu = 0; /* used */
+
+/* Flags for whether to use particular attributes */
+
+int atenci = 1, /* Encoding in */
+ atenco = 1, /* Encoding out */
+ atdati = 1, /* Date in */
+ atdato = 1, /* Date out */
+ atdisi = 1, /* Disposition in/out */
+ atdiso = 1,
+ atleni = 1, /* Length in/out (both kinds) */
+ atleno = 1,
+ atblki = 1, /* Blocksize in/out */
+ atblko = 1,
+ attypi = 1, /* File type in/out */
+ attypo = 1,
+ atsidi = 1, /* System ID in/out */
+ atsido = 1,
+ atsysi = 1, /* System-dependent parameters in/out */
+ atsyso = 1;
+
+int dispos = 0; /* Disposition */
+
+#ifdef CK_PERMS
+int atlpri = 1,
+ atlpro = 1,
+ atgpri = 1,
+ atgpro = 1;
+#endif /* CK_PERMS */
+
+int atfrmi = 1, /* Record Format in/out */
+ atfrmo = 1;
+
+#ifdef STRATUS
+int atcrei = 1, /* Creator ID in/out */
+ atcreo = 1,
+ atacti = 1, /* Account in/out */
+ atacto = 1;
+#endif /* STRATUS */
+
+int sprmlen = -1; /* Send/Receive protocol parameter */
+int rprmlen = -1; /* string length limits */
+int sendipkts = 1; /* Send I packets */
+
+CHAR padch = MYPADC, /* Padding character to send */
+ mypadc = MYPADC, /* Padding character to ask for */
+ seol = MYEOL, /* End-Of-Line character to send */
+ eol = MYEOL, /* End-Of-Line character to look for */
+ ctlq = CTLQ, /* Control prefix in incoming data */
+ myctlq = CTLQ, /* Outbound control character prefix */
+ myrptq = MYRPTQ; /* Repeat prefix I want to use */
+
+int rptmin = 3; /* Repeat-count minimum */
+
+int usepipes = 0, /* Used for xfer to/from pipes */
+ g_usepipes = -1;
+
+char * filefile = NULL; /* File containing list of filenames */
+/* CD message filename list */
+
+char whoareu[16] = { NUL, NUL }; /* System ID of other Kermit */
+int sysindex = -1; /* and index to its system ID struct */
+int myindex = -1;
+int wearealike = 0; /* 2 Kermits have compatible sysids */
+char * cksysid = /* My system ID */
+#ifdef UNIX
+ "U1"
+#else
+#ifdef VMS
+ "D7"
+#else
+#ifdef OSK
+ "UD"
+#else
+#ifdef AMIGA
+ "L3"
+#else
+#ifdef MAC
+ "A3"
+#else
+#ifdef OS2
+#ifdef NT
+ "UN"
+#else /* NT */
+ "UO"
+#endif /* NT */
+#else /* OS2 */
+#ifdef datageneral
+ "F3"
+#else
+#ifdef GEMDOS
+ "K2"
+#else
+#ifdef STRATUS
+ "MV"
+#else
+ ""
+#endif /* STRATUS */
+#endif /* GEMDOS */
+#endif /* datageneral */
+#endif /* OS2 */
+#endif /* MAC */
+#endif /* AMIGA */
+#endif /* OSK */
+#endif /* VMS */
+#endif /* UNIX */
+ ;
+
+int oopts = -1; /* O-Packet Options */
+int omode = -1; /* O-Packet Transfer Mode */
+int oname = -1; /* O-Packet Filename Options */
+int opath = -1; /* O-Packet Pathname Options */
+
+struct zattr iattr; /* Incoming file attributes */
+
+#ifdef VMS
+/* VMS labeled file default options - name only. */
+int lf_opts = LBL_NAM;
+#else
+#ifdef OS2
+/* OS/2 labeled file default options, all attributes but archived. */
+unsigned long int lf_opts = LBL_EXT|LBL_HID|LBL_RO|LBL_SYS;
+#else
+int lf_opts = 0;
+#endif /* OS2 */
+#endif /* VMS */
+
+/* Packet-related variables */
+
+int pktnum = 0, /* Current packet number */
+ sndtyp = 0, /* Type of packet just sent */
+ rcvtyp = 0, /* Type of packet just received */
+ rsn, /* Received packet sequence number */
+ rln, /* Received packet length */
+ size, /* Current size of output pkt data */
+ osize, /* Previous output packet data size */
+ maxsize, /* Max size for building data field */
+ spktl = 0, /* Length packet being sent */
+ rpktl = 0, /* Length of packet just received */
+ pktpaus = 0, /* Interpacket pause interval, msec */
+ rprintf, /* REMOTE PRINT flag */
+ rmailf, /* MAIL flag */
+ xferstat = -1, /* Status of last transaction */
+ filestatus = 0; /* Status of last file transfer */
+
+CHAR pktmsgbuf[PKTMSGLEN+1];
+CHAR *epktmsg = pktmsgbuf;
+
+#ifdef pdp11
+int srvcmdlen = MAXRP; /* srvcmd buffer length */
+#else
+#ifdef DYNAMIC
+int srvcmdlen = MAXRP;
+#else
+int srvcmdlen = 0;
+#endif /* DYNAMIC */
+#endif /* pdp11 */
+
+CHAR
+#ifdef pdp11
+ srvcmdbuf[MAXRP+4],
+ *srvcmd = srvcmdbuf,
+#else
+#ifdef DYNAMIC
+ *srvcmd = (CHAR *)0, /* Where to decode server command */
+#else
+ srvcmdbuf[MAXRP+4],
+ *srvcmd = srvcmdbuf,
+#endif /* DYNAMIC */
+#endif /* pdp11 */
+ padbuf[96], /* Buffer for send-padding */
+ *recpkt,
+ *rdatap, /* Pointer to received packet data */
+ *data = (CHAR *)0, /* Pointer to send-packet data */
+ *srvptr, /* Pointer to srvcmd */
+ mystch = SOH, /* Outbound packet-start character */
+ stchr = SOH; /* Incoming packet-start character */
+
+/* File-related variables */
+
+#ifndef NOMSEND /* Multiple SEND */
+struct filelist * filehead = NULL; /* SEND list */
+struct filelist * filetail = NULL;
+struct filelist * filenext = NULL;
+int addlist = 0;
+#endif /* NOMSEND */
+
+char filnam[CKMAXPATH + 1]; /* Name of current file. */
+char ofilnam[CKMAXPATH + 1]; /* Original name. */
+
+int pipesend = 0; /* Nonzero if sending from pipe */
+#ifdef PIPESEND
+char * sndfilter = NULL; /* Send and receive filters */
+char * rcvfilter = NULL;
+#endif /* PIPESEND */
+
+char ** sndarray = NULL; /* SEND /ARRAY pointer and range */
+#ifndef NOSPL
+int sndxlo = -1, sndxhi = -1, sndxin = -1;
+#endif /* NOSPL */
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+int ngetpath = 0; /* GET search path */
+int fromgetpath = 0;
+char * getpath[MAXGETPATH];
+char * x_user = NULL; /* Server login information */
+char * x_passwd = NULL;
+char * x_acct = NULL;
+#endif /* NOSERVER */
+
+int x_login = 0; /* Login required */
+int x_logged = 0; /* User is logged in */
+
+extern int timelimit;
+
+#ifdef CK_LOGIN
+int logintimo = 300; /* Login timeout */
+char * userfile = NULL; /* Forbidden user file */
+#endif /* CK_LOGIN */
+#ifdef IKSD
+char * anonfile = NULL; /* Anonymous login init file */
+char * anonroot = NULL; /* Anonymous file-system root */
+int iks_timo = 300; /* 5 minutes idle timo */
+int iks_retry = 3; /* 3 attempts at login */
+#endif /* IKSD */
+
+#ifdef CKSYSLOG
+extern VOID zsyslog();
+extern int ckxlogging, ckxsyslog;
+#endif /* CKSYSLOG */
+
+CK_OFF_T fsize = (CK_OFF_T)0, /* Size of current file */
+ sendstart = (CK_OFF_T)0, /* SEND start position */
+ calibrate = (CK_OFF_T)0; /* Nonzero if calibration run */
+
+int nzxopts = 0; /* Options for nzxpand() */
+int nfils = 0; /* Number of files in file group */
+int wildena = 1; /* Wildcard expansion enabled */
+#ifdef UNIX
+int wildxpand = 0; /* Who expands wildcards, 0=Kermit.. */
+#else /* UNIX */
+#ifdef STRATUS
+int wildxpand = 1; /* 1=Shell. */
+#endif /* STRATUS */
+#endif /* UNIX */
+#ifdef UNIXOROSK
+int matchdot = 0; /* Whether to match dot files */
+#else
+int matchdot = 1;
+#endif /* UNIXOROSK */
+int matchfifo = 0; /* Whether to match FIFO "files" */
+int clfils = 0; /* Flag for command-line files */
+int stayflg = 0; /* Flag for "stay", i.e. "-S" */
+int xfinish = 0; /* Flag for FINISH = EXIT */
+long ztusec = -1L; /* Used with ztime() */
+long ztmsec = -1L; /* Ditto */
+
+/* Communication device / connection variables */
+
+char ttname[TTNAMLEN+1]; /* Name of communication device */
+
+#ifdef MAC
+int connected = 0; /* True if connected */
+int startconnected; /* initial state of connected */
+#endif /* MAC */
+
+long speed = -1L; /* Communication device speed */
+int wasclosed = 0; /* Connection was just closed */
+int whyclosed = WC_REMO; /* why it was closed */
+int qnxportlock = 0; /* QNX port locking on/off */
+
+#ifndef CLSONDISC
+#define CLSONDISC 0
+#endif /* CLSONDISC */
+
+int cxflow[CXT_MAX+1]; /* See initflow() */
+
+#ifndef NOSHOW
+char * floname[] = { /* Flow control names */
+ "none", "xon/xoff", "rts/cts", "dtr/cd", "etx/ack", "string",
+ "xxx1", "xxx2", "dtr/cts", "keep", "auto"
+};
+int nfloname = (sizeof(floname) / sizeof(char *));
+
+char * cxname[] = { /* Connection type names */
+ "remote", "direct-serial", "modem", "tcp/ip", "x.25", "decnet",
+ "lat", "netbios", "named-pipe", "ssh", "pipe"
+};
+int ncxname = (sizeof(cxname) / sizeof(char *));
+#endif /* NOSHOW */
+
+int parity = DEFPAR, /* Parity specified, 0,'e','o',etc */
+ hwparity = 0, /* Hardware parity for serial port */
+ stopbits = -1, /* Stop bits for serial port */
+ clsondisc = CLSONDISC, /* Serial port close on disconnect */
+ autopar = 0, /* Automatic parity change flag */
+ sosi = 0, /* Shift-In/Out flag */
+ flow = 0, /* Flow control (see initflow()) */
+ autoflow = 1, /* Automatic flow control */
+ turn = 0, /* Line turnaround handshake flag */
+ turnch = XON, /* Line turnaround character */
+ duplex = 0, /* Duplex, full by default */
+ escape = DFESC, /* Escape character for connect */
+ ckdelay = DDELAY, /* Initial delay before sending */
+ tnlm = 0; /* Terminal newline mode */
+
+/* Networks for SET HOST */
+
+#ifdef BIGBUFOK
+#define MYHOSTL 1024
+#else
+#define MYHOSTL 100
+#endif /* BIGBUFOK */
+
+char myhost[MYHOSTL]; /* Local host name */
+int network = 0; /* Network vs serial connection */
+int inserver = 0; /* Running as an Internet server */
+int isguest = 0; /* User is anonymous */
+char * clienthost = NULL; /* Peer host name or address */
+int tcp_incoming = 0; /* Incoming TCP connection? */
+
+#ifdef NETCONN
+#ifdef TCPSOCKET
+int nettype = NET_TCPB; /* Default network type */
+#else
+#ifdef SUNX25
+int nettype = NET_SX25;
+#else
+#ifdef IBMX25
+int nettype = NET_IX25;
+#else
+#ifdef HPX25
+int nettype = NET_HX25;
+#else
+#ifdef STRATUSX25
+int nettype = NET_VX25;
+#else
+#ifdef DECNET
+int nettype = NET_DEC;
+#else
+#ifdef SUPERLAT
+int nettype = NET_SLAT;
+#else
+int nettype = NET_NONE;
+#endif /* SUPERLAT */
+#endif /* DECNET */
+#endif /* STRATUSX25 */
+#endif /* HPX25 */
+#endif /* IBMX25 */
+#endif /* SUNX25 */
+#endif /* TCPSOCKET */
+#else /* NETCONN */
+int nettype = NET_NONE;
+#endif /* NETCONN */
+
+#ifdef ANYX25
+int revcall = 0; /* X.25 reverse call not selected */
+int closgr = -1; /* X.25 closed user group */
+int cudata = 0; /* X.25 call user data not specified */
+char udata[MAXCUDATA]; /* X.25 call user data */
+
+#ifdef IBMX25
+/*
+ I was unable to find any pre-defined MAX values for x25 addresses - the
+ addresses that I've seen have been around 10-12 characters 32 is probably
+ enough, 64 is hopefully safe for everyone.
+*/
+ x25addr_t local_nua = {'\0'}; /* local x.25 address */
+ x25addr_t remote_nua = {'\0'}; /* remote x.25 address */
+ char x25name[32] = {'\0'}; /* x25 device name, sx25a0 or sx25a1 */
+ char x25dev[64] = "/dev/x25pkt"; /* x25 device in /dev */
+ int x25port = 0; /* port used for X.25 - AIX only */
+#endif /* IBMX25 */
+
+#ifndef IBMX25
+/*
+ This condition is unrelated to the above IBMX25 condition.
+ IBM X.25 doesn't have PAD support.
+*/
+ CHAR padparms[MAXPADPARMS+1]; /* X.3 parameters */
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+/* Other items */
+
+int isinterrupted = 0; /* Used in exception handling */
+int what = W_INIT; /* What I am doing */
+int lastxfer = 0; /* Last transfer (send or receive) */
+
+extern int mdmtyp; /* Modem (/network) type */
+
+#ifdef NT
+extern int StartedFromDialer;
+#ifdef NTSIG
+extern int TlsIndex;
+#endif /* NTSIG */
+#ifdef NTASM
+unsigned long ESPToRestore; /* Ditto */
+#endif /* NTASM */
+#endif /* NT */
+
+#ifdef OS2PM
+int os2pm = 0; /* OS/2 Presentation Manager flag */
+#endif /* OS2PM */
+
+/* Terminal screen size, if known, -1 means unknown. */
+
+#ifdef OS2
+#include "ckocon.h"
+#ifdef KUI
+int tt_rows[VNUM] = {24,24,25,1}; /* Rows (height) */
+int tt_cols[VNUM] = {80,80,80,80}; /* Columns (width) */
+int cmd_rows = 24, cmd_cols = 80; /* Command/console screen dimensions */
+#else /* KUI */
+int tt_rows[VNUM] = {-1,24,25,1}; /* Rows (height) */
+int tt_cols[VNUM] = {-1,80,80,80}; /* Columns (width) */
+int cmd_rows = -1, cmd_cols = -1; /* Command/console screen dimensions */
+#endif /* KUI */
+int k95stdio = 0; /* Stdio threads */
+int tt_bell = XYB_AUD | XYB_SYS; /* BELL AUDIBLE (system sounds) */
+#else /* OS2 */
+int tt_rows = -1; /* Rows (height) */
+int tt_cols = -1; /* Columns (width) */
+int cmd_rows = 24, cmd_cols = 80; /* Command/console screen dimensions */
+int tt_bell = XYB_AUD; /* BELL ON */
+#endif /* OS2 */
+
+int tt_print = 0; /* Transparent print disabled */
+int tt_escape = 1; /* Escaping back is enabled */
+int tt_scroll = 1; /* Scrolling operations are enabled */
+
+int tn_exit = 0; /* Exit on disconnect */
+
+int exitonclose = 0; /* Exit on close */
+int exithangup = 1; /* Hangup on exit */
+int haveline = 0; /* SET LINE or SET HOST in effect */
+int tlevel = -1; /* Take-file command level */
+int hints = 1; /* Whether to give hints */
+
+#ifdef NOLOCAL
+int remonly = 1; /* Remote-mode-only advisory (-R) */
+int nolocal = 1; /* Remote-only strictly enforced */
+#else
+int remonly = 0;
+int nolocal = 0;
+int cx_status = 0; /* CONNECT return status */
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+extern int cmdlvl; /* Command level */
+extern int maclvl; /* Macro invocation level */
+#endif /* NOSPL */
+
+int protocol = PROTO_K; /* File transfer protocol = Kermit */
+
+#ifdef NEWDEFAULTS
+int prefixing = PX_CAU;
+#else
+int prefixing = PX_ALL;
+#endif /* NEWDEFAULTS */
+
+extern short ctlp[]; /* Control-prefix table */
+
+int carrier = CAR_AUT; /* Pay attention to carrier signal */
+int cdtimo = 0; /* Carrier wait timeout */
+int xitsta = GOOD_EXIT; /* Program exit status */
+
+#ifdef VMS /* Default filename collision action */
+int fncact = XYFX_X; /* REPLACE for VMS */
+#else
+int fncact = XYFX_B; /* BACKUP for everybody else */
+#endif /* VMS */
+
+int fncsav = -1; /* For saving & restoring the above */
+int bgset = -1; /* BACKGROUND mode set explicitly */
+
+int cmdint = 1; /* Interrupts are allowed */
+#ifdef UNIX
+int xsuspend = DFSUSP; /* Whether SUSPEND command, etc, */
+#else /* is to be allowed. */
+int xsuspend = 0;
+#endif /* UNIX */
+
+/* Statistics variables */
+
+CK_OFF_T
+ flci, /* Characters from line, current file */
+ flco, /* Chars to line, current file */
+ tlci, /* Chars from line in transaction */
+ tlco, /* Chars to line in transaction */
+ ffc, /* Chars to/from current file */
+ tfc; /* Chars to/from files in transaction */
+
+long filcnt, /* Number of files in transaction */
+ filrej, /* Number of files rejected in transaction */
+ cps = 0L, /* Chars/sec last transfer */
+ peakcps = 0L, /* Peak chars/sec last transfer */
+ ccu, /* Control chars unprefixed in transaction */
+ ccp, /* Control chars prefixed in transaction */
+ rptn; /* Repeated characters compressed */
+
+int tsecs = 0; /* Seconds for transaction */
+int fsecs = 0; /* Per-file timer */
+
+#ifdef GFTIMER
+CKFLOAT
+ fpfsecs = 0.0, /* Floating point per-file timer */
+ fptsecs = 0.0; /* and per-transaction timer */
+#endif /* GFTIMER */
+
+/* Flags */
+
+int deblog = 0, /* Debug log is open */
+ debok = 1, /* Debug log is not disabled */
+ debxlen = 54, /* Default length for debug strings */
+ debses = 0, /* Flag for DEBUG SESSION */
+ debtim = 0, /* Include timestamp in debug log */
+ debmsg = 0, /* Debug messages on/off */
+ pktlog = 0, /* Flag for packet logging */
+ seslog = 0, /* Session logging */
+ dialog = 0, /* DIAL logging */
+ tralog = 0, /* Transaction logging */
+ tlogfmt = 1, /* Transaction log format (verbose) */
+ tlogsep = (int)',', /* Transaction log field separator */
+ displa = 0, /* File transfer display on/off */
+ stdouf = 0, /* Flag for output to stdout */
+ stdinf = 0, /* Flag for input from stdin */
+ xflg = 0, /* Flag for X instead of F packet */
+ hcflg = 0, /* Doing Host command */
+ dest = DEST_D, /* Destination for packet data */
+ zchkod = 0, /* zchko() should work for dirs too? */
+ zchkid = 0, /* zchki() should work for dirs too? */
+
+/* If you change this, also see struct ptab above... */
+
+#ifdef OS2 /* Flag for file name conversion */
+ fncnv = XYFN_L, /* Default is Literal in OS/2, */
+ f_save = XYFN_L, /* (saved copy of same) */
+#else
+ fncnv = XYFN_C, /* elsewhere Convert them */
+ f_save = XYFN_C, /* (ditto) */
+#endif /* OS2 */
+
+ fnspath = PATH_OFF, /* Send file path */
+ fnrpath = PATH_AUTO, /* Receive file path */
+ fackpath = 1, /* Send back path in ACK to F */
+ binary = XYFT_B, /* Default file transfer mode */
+ b_save = XYFT_B, /* Saved file mode */
+ eofmethod = 0, /* EOF detection method (length) */
+
+#ifdef OS2
+ cursor_save = -1, /* Cursor state */
+#endif /* OS2 */
+
+ xfermode = XMODE_A, /* Transfer mode, manual or auto */
+ xfiletype = -1, /* Transfer only text (or binary) */
+ recursive = 0, /* Recursive directory traversal */
+ nolinks = 2, /* Don't follow symbolic links */
+ skipbup = 0, /* Skip backup files when sending */
+ sendmode = SM_SEND, /* Which type of SEND operation */
+ slostart = 1, /* Slow start (grow packet lengths) */
+ cmask = 0377, /* CONNECT (terminal) byte mask */
+ fmask = 0377, /* File byte mask */
+ ckwarn = 0, /* Flag for file warning */
+ quiet = 0, /* Be quiet during file transfer */
+ local = 0, /* 1 = local mode, 0 = remote mode */
+ cxtype = CXT_REMOTE, /* Connection type */
+ server = 0, /* Flag for I Am Server */
+ query = 0, /* Flag for Query active */
+ justone = 0, /* Server should do Just One command */
+ urserver = 0, /* Flag for You Are Server */
+ bye_active = 0, /* Flag for BYE command active */
+ diractive = 0, /* Flag for DIRECTORY command active */
+ cdactive = 0, /* Flag for CD command active */
+ cflg = 0, /* Connect before transaction */
+ cnflg = 0, /* Connect after transaction */
+ cxseen = 0, /* Flag for cancelling a file */
+ czseen = 0, /* Flag for cancelling file group */
+ fatalio = 0, /* Flag for fatal i/o error */
+ discard = 0, /* Flag for file to be discarded */
+ keep = SET_AUTO, /* Keep incomplete files = AUTO */
+ unkcs = 1, /* Keep file w/unknown character set */
+#ifdef VMS
+ filepeek = 0, /* Inspection of files */
+#else
+#ifdef datgeneral
+ filepeek = 0,
+#else
+ filepeek = 1,
+#endif /* datageneral */
+#endif /* VMS */
+ nakstate = 0, /* In a state where we can send NAKs */
+ dblchar = -1, /* Character to double when sending */
+ moving = 0, /* MOVE = send, then delete */
+ reliable = SET_AUTO, /* Nonzero if transport is reliable */
+ xreliable = -1,
+ setreliable = 0,
+ urclear = 0, /* Nonzero for clear channel to you */
+ clearrq = SET_AUTO, /* SET CLEARCHANEL value */
+ cleared = 0,
+ streaming = 0, /* Nonzero if streaming is active */
+ streamok = 0, /* Nonzero if streaming negotiated */
+ streamrq = SET_AUTO, /* SET STREAMING value */
+ streamed = -1; /* Whether we streamed last time */
+
+char * snd_move = NULL; /* Move file after sending it */
+char * snd_rename = NULL; /* Rename file after sending it */
+char * rcv_move = NULL; /* Move file after receiving it */
+char * rcv_rename = NULL; /* Rename file after receiving it */
+
+char * g_snd_move = NULL;
+char * g_snd_rename = NULL;
+char * g_rcv_move = NULL;
+char * g_rcv_rename = NULL;
+
+#ifdef CK_TRIGGER
+char *tt_trigger[TRIGGERS] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
+CHAR *tt_trmatch[TRIGGERS] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
+char *triggerval = NULL;
+#endif /* CK_TRIGGER */
+
+int ckxlogging = 0; /* Flag for syslogging active */
+int ikdbopen = 0; /* Flag for IKSD database active */
+int dbinited = 0; /* Flag for IKSDB record init'd */
+#ifndef CKSYSLOG
+int ckxsyslog = 0; /* Logging level 0 */
+#else
+#ifdef SYSLOGLEVEL
+int ckxsyslog = SYSLOGLEVEL; /* Logging level specified */
+#else
+int ckxsyslog = SYSLG_DF; /* Default logging level */
+#endif /* SYSLOGLEVEL */
+#endif /* CKSYSLOG */
+
+#ifndef NOHELP
+#ifndef NOCMDL
+_PROTOTYP( VOID iniopthlp, (void) ); /* Command-line help initializer */
+#endif /* NOCMDL */
+#endif /* NOHELP */
+
+_PROTOTYP( VOID getexedir, (void) );
+_PROTOTYP( int putnothing, (char) );
+
+#ifdef IKSD
+_PROTOTYP( VOID doiksdinit, (void) );
+_PROTOTYP( VOID iksdinit, (void) );
+_PROTOTYP( VOID doiklog, (void) );
+_PROTOTYP( int dbinit, (void) );
+#endif /* IKSD */
+
+/* Variables passed from command parser to protocol module */
+
+#ifndef NOSPL
+#ifndef NOICP
+#ifdef CK_APC
+_PROTOTYP( VOID apconect, (void) );
+#endif /* CK_APC */
+#ifdef OS2
+extern int initvik;
+#endif /* OS2 */
+#endif /* NOICP */
+#endif /* NOSPL */
+char *clcmds = NULL; /* Pointer to command-line commands */
+
+#ifndef NOSETKEY
+extern KEY *keymap;
+extern MACRO *macrotab;
+#endif /* NOSETKEY */
+
+#ifndef NOPUSH
+int nopush = 0; /* PUSH enabled */
+#else
+int nopush = 1; /* PUSH disabled */
+#endif /* NOPUSH */
+
+CHAR sstate = (CHAR) 0; /* Starting state for automaton */
+CHAR zstate = (CHAR) 0; /* For remembering sstate */
+char * printername = NULL; /* NULL if printer not redirected */
+int printpipe = 0; /* For SET PRINTER */
+int noprinter = 0;
+
+#ifndef NOXFER
+char *cmarg = ""; /* Pointer to command data */
+char *cmarg2 = ""; /* Pointer to 2nd command data */
+char **cmlist; /* Pointer to file list in argv */
+
+#ifdef CK_AUTODL /* Autodownload */
+int autodl = 1; /* Enabled by default */
+#else
+int autodl = 0; /* (or if not implemented). */
+#endif /* CK_AUTODL */
+int adl_err = 1; /* 1 = stop on error */
+#ifdef KUI
+int adl_ask = 1; /* 1 = file dialog on autodownload */
+#else
+int adl_ask = 0; /* 0 = no file dialog */
+#endif /* KUI */
+#ifdef OS2 /* AUTODOWNLOAD parameters */
+int adl_kmode = ADL_PACK, /* Match Packet to signal download */
+ adl_zmode = ADL_PACK;
+char * adl_kstr = NULL; /* KERMIT Download String */
+char * adl_zstr = NULL; /* ZMODEM Download String */
+#endif /* OS2 */
+
+int remfile = 0, rempipe = 0, remappd = 0; /* REMOTE output redirection */
+char * remdest = NULL;
+
+#ifndef NOSERVER
+/*
+ Server services:
+ 0 = disabled
+ 1 = enabled in local mode
+ 2 = enabled in remote mode
+ 3 = enabled in both local and remote modes
+ only as initial (default) values.
+*/
+int en_xit = 2; /* EXIT */
+int en_cwd = 3; /* CD/CWD */
+int en_cpy = 3; /* COPY */
+int en_del = 2; /* DELETE */
+int en_mkd = 3; /* MKDIR */
+int en_rmd = 2; /* RMDIR */
+int en_dir = 3; /* DIRECTORY */
+int en_fin = 3; /* FINISH */
+int en_get = 3; /* GET */
+#ifndef NOPUSH
+int en_hos = 2; /* HOST enabled */
+#else
+int en_hos = 0; /* HOST disabled */
+#endif /* NOPUSH */
+int en_ren = 3; /* RENAME */
+int en_sen = 3; /* SEND */
+int en_set = 3; /* SET */
+int en_spa = 3; /* SPACE */
+int en_typ = 3; /* TYPE */
+int en_who = 3; /* WHO */
+#ifdef datageneral
+/* Data General AOS/VS can't do this */
+int en_bye = 0; /* BYE */
+#else
+int en_bye = 2; /* PCs in local mode... */
+#endif /* datageneral */
+int en_asg = 3; /* ASSIGN */
+int en_que = 3; /* QUERY */
+int en_ret = 2; /* RETRIEVE */
+int en_mai = 3; /* MAIL */
+int en_pri = 3; /* PRINT */
+int en_ena = 3; /* ENABLE */
+#else
+int en_xit = 0, en_cwd = 0, en_cpy = 0, en_del = 0, en_mkd = 0, en_rmd = 0,
+ en_dir = 0, en_fin = 0, en_get = 0, en_hos = 0, en_ren = 0, en_sen = 0,
+ en_set = 0, en_spa = 0, en_typ = 0, en_who = 0, en_bye = 0, en_asg = 0,
+ en_que = 0, en_ret = 0, en_mai = 0, en_pri = 0, en_ena = 0;
+#endif /* NOSERVER */
+#endif /* NOXFER */
+
+/* Miscellaneous */
+
+char **xargv; /* Global copies of argv */
+int xargc; /* and argc */
+int xargs; /* an immutable copy of argc */
+char *xarg0; /* and of argv[0] */
+char *pipedata; /* Pointer to -P (pipe) data */
+
+extern char *dftty; /* Default tty name from ck?tio.c */
+extern int dfloc; /* Default location: remote/local */
+extern int dfprty; /* Default parity */
+extern int dfflow; /* Default flow control */
+
+#ifdef TNCODE
+extern int tn_deb;
+#endif /* TNCODE */
+/*
+ Buffered file input and output buffers. See getpkt() in ckcfns.c
+ and zoutdump() in the system-dependent file i/o module (usually ck?fio.c).
+*/
+#ifndef DYNAMIC
+/* Now we allocate them dynamically, see getiobs() below. */
+char zinbuffer[INBUFSIZE], zoutbuffer[OBUFSIZE];
+#endif /* DYNAMIC */
+char *zinptr, *zoutptr;
+int zincnt, zoutcnt;
+int zobufsize = OBUFSIZE;
+int zofbuffer = 1;
+int zofblock = 1;
+
+#ifdef SESLIMIT
+int seslimit = 0;
+#endif /* SESLIMIT */
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+
+_PROTOTYP( int getiobs, (VOID) );
+
+/* M A I N -- C-Kermit main program */
+
+#include <signal.h>
+
+#ifndef NOCCTRAP
+#include <setjmp.h>
+#include "ckcsig.h"
+ckjmpbuf cmjbuf;
+#ifdef GEMDOS /* Special for Atari ST */
+cc_clean(); /* This can't be right? */
+#endif /* GEMDOS */
+#endif /* NOCCTRAP */
+
+#ifndef NOXFER
+/* Info associated with a system ID */
+
+struct sysdata sysidlist[] = { /* Add others as needed... */
+ { "0", "anonymous", 0, NUL, 0, 0, 0 },
+ { "A1", "Apple II", 0, NUL, 0, 0, 3 }, /* fix this */
+ { "A3", "Macintosh", 1, ':', 0, 2, 1 },
+ { "D7", "VMS", 0, ']', 1, 0, 0 },
+ { "DA", "RSTS/E", 0, ']', 1, 0, 3 }, /* (i think...) */
+ { "DB", "RT11", 0, NUL, 1, 0, 3 }, /* (maybe...) */
+ { "F3", "AOS/VS", 1, ':', 0, 0, 2 },
+ { "I1", "VM/CMS", 0, NUL, 0, 0, 0 },
+ { "I2", "MVS/TSO", 0, NUL, 0, 0, 0 },
+ { "I4", "MUSIC", 0, NUL, 0, 0, 0 },
+ { "I7", "CICS", 0, NUL, 0, 0, 0 },
+ { "I9", "MVS/ROSCOE", 0, NUL, 0, 0, 0 },
+ { "K2", "Atari ST", 1, '\\', 1, 0, 3 },
+ { "L3", "Amiga", 1, '/', 1, 0, 2 },
+ { "MV", "Stratus VOS", 1, '>', 0, 1, 0 },
+ { "N3", "Apollo Aegis", 1, '/', 0, 3, 2 },
+ { "U1", "UNIX", 1, '/', 0, 3, 2 },
+ { "U8", "MS-DOS", 1, '\\', 1, 0, 3 },
+ { "UD", "OS-9", 1, '/', 0, 3, 2 },
+ { "UN", "Windows-32", 1, '\\', 1, 2, 3 },
+ { "UO", "OS/2", 1, '\\', 1, 2, 3 }
+};
+static int nxxsysids = (sizeof(sysidlist) / sizeof(struct sysdata));
+
+/* Given a Kermit system ID code, return the associated name string */
+/* and some properties of the filenames... */
+
+char *
+getsysid(s) char * s; { /* Get system-type name */
+ int i;
+ if (!s) return("");
+ for (i = 0; i < nxxsysids; i++)
+ if (!strcmp(sysidlist[i].sid_code,s))
+ return(sysidlist[i].sid_name);
+ return(s);
+}
+
+int
+getsysix(s) char *s; { /* Get system-type index */
+ int i;
+ if (!s) return(-1);
+ for (i = 0; i < nxxsysids; i++)
+ if (!strcmp(sysidlist[i].sid_code,s))
+ return(i);
+ return(-1);
+}
+#endif /* NOXFER */
+
+/* Tell if a pathname is absolute (versus relative) */
+/* This should be parceled out to each of the ck*fio.c modules... */
+/* VMS isabsolute() is now in ckvfio.c. */
+#ifndef VMS
+int
+isabsolute(path) char * path; {
+ int rc = 0;
+ int x;
+ if (!path)
+ return(0);
+ if (!*path)
+ return(0);
+ x = (int) strlen(path);
+ debug(F111,"isabsolute",path,x);
+#ifdef UNIX
+ if (*path == '/'
+#ifdef DTILDE
+ || *path == '~'
+#endif /* DTILDE */
+ )
+ rc = 1;
+#else /* def UNIX */
+#ifdef OS2
+ if (*path == '/' || *path == '\\')
+ rc = 1;
+ else if (isalpha(*path) && x > 2)
+ if (*(path+1) == ':' && (*(path +2) == '/' || *(path+2) == '\\'))
+ rc = 1;
+#else /* def OS2 */
+#ifdef AMIGA
+ if (*path == '/'
+#ifdef DTILDE
+ || *path == '~'
+#endif /* DTILDE */
+ )
+ rc = 1;
+#else /* def AMIGA */
+#ifdef OSK
+ if (*path == '/'
+#ifdef DTILDE
+ || *path == '~'
+#endif /* DTILDE */
+ )
+ rc = 1;
+#else /* def OSK */
+#ifdef datageneral
+ if (*path == ':')
+ rc = 1;
+#else /* def datageneral */
+#ifdef MAC
+ rc = 0; /* Fill in later... */
+#else /* def MAC */
+#ifdef STRATUS
+ rc = 0; /* Fill in later... */
+#else /* def STRATUS */
+#ifdef GEMDOS
+ if (*path == '/' || *path == '\\')
+ rc = 1;
+ else if (isalpha(*path) && x > 1)
+ if (*(path+1) == ':')
+ rc = 1;
+#endif /* GEMDOS */
+#endif /* STRATUS */
+#endif /* MAC */
+#endif /* datageneral */
+#endif /* OSK */
+#endif /* AMIGA */
+#endif /* OS2 */
+#endif /* UNIX */
+ debug(F101,"isabsolute rc","",rc);
+ return(rc);
+}
+#endif /* ndef VMS */
+
+/* See if I have direct access to the keyboard */
+
+int
+is_a_tty(n) int n; {
+#ifdef UNIX
+ extern int ttfdflg;
+ if (ttfdflg > 0)
+ return(1);
+#endif /* UNIX */
+#ifdef KUI
+ return 1;
+#else /* KUI */
+#ifdef NT
+ if (isWin95())
+ return(1);
+ else
+ return(_isatty(n));
+#else
+#ifdef IKSD
+ if (inserver)
+ return(1);
+ else
+#endif /* IKSD */
+ return(isatty(n));
+#endif /* NT */
+#endif /* KUI */
+}
+
+#ifndef NOXFER
+VOID
+initxlist() {
+ extern char * sndexcept[], * rcvexcept[];
+ int i;
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ sndexcept[i] = NULL;
+ rcvexcept[i] = NULL;
+ }
+}
+#endif /* NOXFER */
+
+/* Initialize flow control table */
+
+VOID
+initflow() { /* Default values for flow control */
+#ifdef VMS /* for each kind of connection. */
+ /* The VMS telnet terminal driver treats "none" as request to lose chars */
+ cxflow[CXT_REMOTE] = FLO_XONX; /* Remote mode... */
+#else
+#ifdef HPUX
+ /* Ditto for HP-UX */
+ cxflow[CXT_REMOTE] = FLO_XONX; /* Remote mode... */
+#else
+ /* The temptation is to make this one FLO_KEEP but don't!!! */
+ /* It totally wrecks binary-file transfer when coming in via Telnet. */
+ /* In UNIX at least... */
+ cxflow[CXT_REMOTE] = FLO_NONE;
+#endif /* HPUX */
+#endif /* VMS */
+
+#ifdef VMS
+ cxflow[CXT_DIRECT] = FLO_XONX; /* Direct serial connections... */
+#else
+ cxflow[CXT_DIRECT] = FLO_NONE;
+#endif /* VMS */
+
+#ifdef CK_RTSCTS
+ cxflow[CXT_MODEM] = FLO_RTSC; /* Modem connections... */
+#else
+#ifdef VMS
+ cxflow[CXT_MODEM] = FLO_XONX;
+#else
+ cxflow[CXT_MODEM] = FLO_NONE;
+#endif /* VMS */
+#endif /* CK_RTSCTS */
+
+#ifdef VMS
+ cxflow[CXT_TCPIP] = FLO_XONX; /* TCP/IP connections... */
+#else
+ cxflow[CXT_TCPIP] = FLO_NONE;
+#endif /* VMS */
+
+ cxflow[CXT_SSH] = FLO_NONE;
+ cxflow[CXT_X25] = FLO_NONE; /* Other kinds of networks... */
+ cxflow[CXT_DECNET] = FLO_XONX;
+ cxflow[CXT_LAT] = FLO_XONX;
+ cxflow[CXT_NETBIOS] = FLO_NONE;
+ cxflow[CXT_NPIPE] = FLO_NONE;
+ cxflow[CXT_PIPE] = FLO_NONE;
+ flow = cxflow[cxtype]; /* Initial flow setting. */
+ debug(F101,"initflow","",flow);
+}
+
+#ifndef NOXFER
+/* Initialize file transfer protocols */
+
+VOID
+initproto(y, upbstr, uptstr, srvstr, sndbstr, sndtstr, rcvbstr, rcvtstr)
+ int y;
+ char * upbstr, * uptstr, * srvstr, * sndbstr, * sndtstr, * rcvbstr,
+ * rcvtstr;
+/* initproto */ {
+
+ if (upbstr) /* Convert null strings */
+ if (!*upbstr) /* to null pointers */
+ upbstr = NULL;
+
+ if (uptstr) /* Convert null strings */
+ if (!*uptstr) /* to null pointers */
+ uptstr = NULL;
+
+ if (sndbstr)
+ if (!*sndbstr)
+ sndbstr = NULL;
+
+ if (sndtstr)
+ if (!*sndtstr)
+ sndtstr = NULL;
+
+ if (rcvbstr)
+ if (!*rcvbstr)
+ rcvbstr = NULL;
+
+ if (rcvtstr)
+ if (!*rcvtstr)
+ rcvtstr = NULL;
+
+ if (srvstr)
+ if (!*srvstr)
+ srvstr = NULL;
+
+ protocol = y; /* Set protocol */
+
+ if (ptab[protocol].rpktlen > -1)
+ urpsiz = ptab[protocol].rpktlen;
+ if (ptab[protocol].spktflg > -1)
+ spsizf = ptab[protocol].spktflg;
+ if (ptab[protocol].spktlen > -1) {
+ spsiz = ptab[protocol].spktlen;
+ debug(F101,"initproto spsiz","",spsiz);
+ if (spsizf) {
+ spsizr = spmax = spsiz;
+ debug(F101,"initproto spsizr","",spsizr);
+ }
+ }
+ if (ptab[protocol].winsize > -1)
+ wslotr = ptab[protocol].winsize;
+ if (ptab[protocol].prefix > -1)
+ prefixing = ptab[protocol].prefix;
+ if (ptab[protocol].fnca > -1)
+ fncact = ptab[protocol].fnca;
+ if (ptab[protocol].fncn > -1)
+ fncnv = ptab[protocol].fncn;
+ if (ptab[protocol].fnsp > -1)
+ fnspath = ptab[protocol].fnsp;
+ if (ptab[protocol].fnrp > -1)
+ fnrpath = ptab[protocol].fnrp;
+
+ makestr(&(ptab[protocol].h_b_init),upbstr);
+ makestr(&(ptab[protocol].h_t_init),uptstr);
+ makestr(&(ptab[protocol].h_x_init),srvstr);
+ makestr(&(ptab[protocol].p_b_scmd),sndbstr);
+ makestr(&(ptab[protocol].p_t_scmd),sndtstr);
+ makestr(&(ptab[protocol].p_b_rcmd),rcvbstr);
+ makestr(&(ptab[protocol].p_t_rcmd),rcvtstr);
+}
+#endif /* NOXFER */
+
+#ifndef NOCMDL
+VOID
+#ifdef CK_ANSIC
+docmdline(void * threadinfo)
+#else /* CK_ANSIC */
+docmdline(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug( F100, "docmdline called with threadinfo block", "", 0 );
+ } else
+ debug( F100, "docmdline threadinfo is NULL","",0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+ proto(); /* Take any requested action, then */
+ if (!quiet) /* put cursor back at left margin, */
+ conoll("");
+#ifndef NOLOCAL
+ if (cnflg) { /* Re-connect if requested */
+ cnflg = 0;
+ doconect(0,0);
+ if (ttchk() < 0)
+ dologend();
+ }
+#endif /* NOLOCAL */
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+}
+
+void
+ikslogin() {
+ if (sstelnet
+#ifdef IKSD
+ || inserver /* Internet server */
+#endif /* IKSD */
+ ) {
+ char *s;
+ extern int fdispla; /* File-transfer display format */
+ extern char * ikprompt; /* IKSD prompt */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver) {
+ x_login = 1; /* Login required */
+ x_logged = 0; /* Not logged in yet */
+ cmsetp(ikprompt); /* Set up IKSD's prompt */
+#ifndef NOSERVER
+ en_mai = 0; /* MAIL is disabled */
+ en_who = 0; /* REMOTE WHO is disabled */
+ en_hos = 0; /* REMOTE HOST is disabled */
+ en_pri = 0; /* PRINT is disabled */
+#endif /* NOSERVER */
+ } else {
+ x_login = 0; /* Login not required */
+ x_logged = 1; /* Already logged in */
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ nolocal = 1; /* SET LINE/HOST not allowed */
+ fdispla = XYFD_N; /* No file-transfer display */
+#ifdef NETCONN
+ clienthost = ckgetpeer(); /* Get client's hostname */
+ debug(F110,"ikslogin clienthost",clienthost,0);
+#endif /* NETCONN */
+ ztime(&s); /* Get current date and time */
+
+#ifdef CK_LOGIN
+#ifdef CK_AUTHENTICATION
+ if (x_login) {
+ x_logged = ck_tn_auth_valid(); /* Did Telnet Auth succeed? */
+ debug(F111,"ikslogin","x_logged",x_logged);
+
+#ifdef NT
+ /* On Windows 9x, we do not have the ability in */
+ /* zvuser() at present to determine if the name */
+ /* approved in a Kerberos principal is really a */
+ /* an account in the Windows Access Control List */
+ if (isWin95() && x_logged == AUTH_VALID
+ && (ck_tn_authenticated() != AUTHTYPE_NTLM)
+#ifdef CK_SRP
+ && (ck_tn_authenticated() != AUTHTYPE_SRP)
+#endif /* CK_SRP */
+ ) {
+ auth_finished(AUTH_USER);
+ x_logged = AUTH_USER;
+ printf("WARNING:\r\n");
+ printf(
+" The Telnet authentication method used cannot provide for automated\r\n");
+ printf(
+" login to Windows 95 or Windows 98. A password must be entered\r\n");
+ printf(
+" locally to validate your userid. Telnet authentication (and encryption)\r\n"
+ );
+ printf(
+" can be used to validate the host (and protect the privacy of your password.)\
+\r\n"
+ );
+ }
+#endif /* NT */
+
+ if (x_logged == AUTH_VALID) {
+#ifdef CK_SSL
+ if ((ssl_active_flag || tls_active_flag) &&
+ (!TELOPT_U(TELOPT_AUTHENTICATION) ||
+ ck_tn_authenticated() == AUTHTYPE_NULL ||
+ ck_tn_authenticated() == AUTHTYPE_AUTO)
+ ) {
+#ifdef SSL_KRB5
+ if (tls_is_krb5(0)) {
+ printf("Authenticated using Kerberos 5\r\n");
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_VALID",
+ "Kerberos 5",
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ } else
+#endif /* SSL_KRB5 */
+ {
+ printf("Authenticated using X.509 certificate\r\n");
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_VALID",
+ "X.509 certificate",
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ }
+ } else
+#endif /* CK_SSL */
+ {
+ printf("Authenticated using %s\r\n",
+ AUTHTYPE_NAME(ck_tn_authenticated()));
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_VALID",
+ AUTHTYPE_NAME(ck_tn_authenticated()),
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ }
+ zvuser(uidbuf);
+ if (zvpass("") == 0)
+ x_logged = 0;
+ } else if (x_logged == AUTH_USER && !strcmp(uidbuf,"anonymous")) {
+ extern char szUserNameAuthenticated[];
+ zvuser(uidbuf);
+ debug(F110,"szUserNameAuthenticated",
+ szUserNameAuthenticated,0);
+ if (zvpass(szUserNameAuthenticated) == 0) {
+ /* Anonymous login failed. Force a username prompt. */
+ x_logged = 0;
+ uidbuf[0] = '\0';
+ } else {
+#ifdef CK_SSL
+ if ((ssl_active_flag || tls_active_flag) &&
+ (!TELOPT_U(TELOPT_AUTHENTICATION) ||
+ ck_tn_authenticated() == AUTHTYPE_NULL ||
+ ck_tn_authenticated() == AUTHTYPE_AUTO)) {
+ printf("Authenticated using X.509 certificate\r\n");
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_USER",
+ "X.509 certificate",
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ } else
+#endif /* CK_SSL */
+ {
+ printf("Authenticated using %s\r\n",
+ AUTHTYPE_NAME(ck_tn_authenticated())
+ );
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ cksyslog(SYSLG_LI, 1, "AUTH_USER",
+ AUTHTYPE_NAME(ck_tn_authenticated()),
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ }
+ }
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging &&
+ x_logged == AUTH_USER) {
+ extern char szUserNameAuthenticated[];
+ cksyslog(SYSLG_LI, 1, "AUTH_USER",
+ AUTHTYPE_NAME(ck_tn_authenticated()),
+ szUserNameAuthenticated
+ );
+ }
+#endif /* CKSYSLOG */
+ x_logged = 0;
+ if (!strcmp("(unknown)",uidbuf)
+#ifdef NT
+ || !stricmp("administrator",uidbuf)
+#ifdef UNIX
+ || !strcmp("root",uidbuf)
+#else
+#ifdef Plan9
+ || !strcmp("root",uidbuf)
+#else
+#ifdef OSK
+ || !strcmp("root",uidbuf)
+#endif /* OSK */
+#endif /* Plan9 */
+#endif /* UNIX */
+#endif /* NT */
+ )
+ uidbuf[0] = '\0';
+ }
+ }
+#endif /* CK_AUTHENTICATION */
+#endif /* CK_LOGIN */
+
+#ifdef IKSD
+ if (inserver)
+ printf("\r\nInternet Kermit Service ready at %s%s\r\n",s,versio);
+ else
+#endif /* IKSD */
+ printf("\r\nC-Kermit ready at %s%s\r\n",s,versio);
+ if (*myhost)
+ printf("%s\r\n", myhost);
+ printf("\r\n");
+ }
+#ifdef CK_LOGIN
+#ifdef IKSD
+ if (inserver) {
+ int i;
+ extern int arg_x; /* Flag for '-x' on command line */
+#ifndef NOSPL
+ extern struct mtab *mactab; /* For ON_LOGIN macro. */
+ extern int nmac;
+#endif /* NOSPL */
+
+ debug(F110,"MAIN clienthost",clienthost,0);
+ srvidl = timelimit = logintimo; /* For interactive login */
+ rtimer(); /* Reset timer */
+ for (i = 0; i < iks_retry && !x_logged; i++) { /* Count retries */
+ if (gtimer() > logintimo)
+ break;
+#ifdef TNCODE
+ tn_wait("login loop");
+ tn_push();
+#endif /* TNCODE */
+ debug(F101,"MAIN LOGIN try","",i);
+ what = W_NOTHING; /* Because proto() changes this */
+
+#ifdef IKS_OPTION
+ debug(F111,"MAIN LOGIN",
+ "TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+ /* Kermit server negotiated */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ debug(F101,"IKSD starting in server mode","",0);
+ arg_x = 1; /* Enter server mode */
+ sstate = 'x';
+#ifdef IKSDPOPBACK
+ justone = 1; /* Execute one command at a time. */
+#endif /* IKSDPOPBACK */
+ proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ if (x_logged) /* Logged in */
+ break;
+ } else { /* Not in client/server mode */
+#endif /* IKS_OPTION */
+ debug(F101,"IKSD starting with Username prompt","",0);
+ x_logged = ckxlogin((CHAR *)uidbuf,NULL,NULL,1);
+ if (sstate) { /* Received a packet at prompt */
+#ifdef IKSDPOPBACK
+ justone = 1; /* Go handle it */
+#endif /* IKSDPOPBACK */
+ proto();
+ }
+ if (!x_logged) { /* In case we are at the prompt... */
+ printf("Access denied.\n");
+ uidbuf[0] = '\0'; /* Forget the name if we have one */
+ }
+#ifdef IKS_OPTION
+ }
+#endif /* IKS_OPTION */
+ }
+ srvidl = timelimit = iks_timo; /* Reset command timelimit */
+ debug(F101,"MAIN LOGIN","",x_logged);
+ if (!x_logged) { /* Logins failed. */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ errpkt((CHAR *)"Login Timeout");
+ msleep(500);
+ doexit(BAD_EXIT,0);
+ }
+ what = W_NOTHING; /* Stay in known state */
+#ifndef NOSERVER
+ if (isguest) {
+ en_pri = 0; /* No printing for anonymous users */
+ en_mai = 0; /* No email for anonymous users */
+ en_mkd = 0; /* Or directory creation */
+ en_rmd = 0; /* Or directory removal */
+ en_ena = 0; /* Or ENABLing DISABLEd items */
+ }
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+/*
+ If a macro named "on_login" is defined, execute it. Also remove it from the
+ macro table so the user cannot see what it does. Execute it as part of the
+ iksd.conf file.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_login"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_login" */
+ if (k >= 0) { /* If found, */
+#ifdef IKSDCONF
+ int saved = iksdcf;
+ iksdcf = 0;
+#endif /* IKSDCONF */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* execute it */
+#ifdef IKSDCONF
+ iksdcf = saved;
+#endif /* IKSDCONF */
+ delmac(cmd,1); /* and delete it */
+ }
+ }
+#endif /* NOSPL */
+ } /* if (inserver) */
+#else /* CK_LOGIN */
+ if (inserver)
+ srvidl = timelimit = iks_timo; /* Set idle limits for IKS */
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+}
+
+VOID
+#ifdef CK_ANSIC
+failcmdline(void * foo)
+#else /* CK_ANSIC */
+failcmdline(foo) VOID * foo;
+#endif /* CK_ANSIC */
+{
+#ifdef GEMDOS
+ cc_clean();
+#endif /* GEMDOS */
+#ifndef NOLOCAL
+ if (cnflg) doconect(0,0); /* connect again if requested. */
+ if (ttchk() < 0)
+ dologend();
+#endif /* NOLOCAL */
+}
+#endif /* NOCMDL */
+
+#ifndef NOICP
+VOID
+#ifdef CK_ANSIC
+dotakeini(void * threadinfo) /* Execute init file. */
+#else /* CK_ANSIC */
+dotakeini(threadinfo) VOID * threadinfo; /* Execute init file. */
+#endif /* CK_ANSIC */
+/* dotakeini */ {
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "dotakeini called with threadinfo block","", 0);
+ } else
+ debug(F100, "dotakeini - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+ cmdini(); /* Sets tlevel */
+
+ debug(F111,"dotakeini","inserver",inserver);
+ debug(F111,"dotakeini","sstelnet",sstelnet);
+
+#ifdef COMMENT
+/* Wrong place for this... */
+#ifndef NOXFER
+#ifdef CK_FAST
+ dofast(); /* By now FAST defaults should be OK */
+#endif /* CK_FAST */
+#endif /* NOXFER */
+#endif /* COMMENT */
+
+ doinit(); /* Now do the initialization file */
+ debug(F101,"main executing init file","",tlevel);
+ while (tlevel > -1) {
+ sstate = (CHAR) parser(1); /* Execute one command at a time. */
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+ debug(F101,"main exits init file","",tlevel);
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+}
+
+VOID
+#ifdef CK_ANSIC
+failtakeini(void * threadinfo)
+#else /* CK_ANSIC */
+failtakeini(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failtakeini */ {
+#ifdef GEMDOS
+ cc_clean(); /* Atari: Clean up after ^C-trap. */
+#endif /* GEMDOS */
+ fixcmd();
+ if (!cfilef) {
+ conoll("Interrupted during initialization or \
+command-line processing.");
+ conoll("C-Kermit quitting...");
+ }
+ doexit(BAD_EXIT,-1); /* Exit with bad status. */
+}
+
+VOID
+#ifdef CK_ANSIC
+doicp(void * threadinfo)
+#else /* CK_ANSIC */
+doicp(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* doicp */ {
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ if (!TlsSetValue(TlsIndex,threadinfo))
+ debug(F101,"doicp TlsSetValue failed","",GetLastError());
+ debug(F101, "doicp a threadinfo block - TlsIndex", "", TlsIndex);
+ } else {
+ debug(F100, "doicp received a null threadinfo", "", 0);
+ }
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+#ifdef MAC
+ while (1) {
+ extern char *lfiles; /* Fake pointer cast */
+
+ if (connected) {
+ debug(F100, "doicp: calling macparser", "", 0);
+ sstate = newparser(1, 1, 0L);
+
+ /* ignore null command state */
+ if (sstate == 'n')
+ sstate = '\0';
+
+ if (sstate)
+ proto();
+ } else {
+ /*
+ * process take files the finder gave us.
+ */
+ if ((tlevel == -1) && lfiles)
+ startlfile();
+
+ debug(F100, "doicp: calling parser", "", 0);
+ sstate = (CHAR) parser(0);
+ if (sstate == 'c') /* if MAC connect */
+ sstate = 0;
+ if (sstate)
+ proto();
+ }
+ }
+#else /* Not MAC */
+
+#ifndef NOSPL
+/*
+ If interactive commands were given on the command line (using the
+ -C "command, command, ..." option), assign them to a macro called
+ "cl_commands", then execute the macro and leave it defined for
+ subsequent re-execution if desired.
+*/
+ if (clcmds) { /* Check for -C commands */
+ int x;
+ x = addmac("cl_commands",clcmds); /* Put macro in table */
+ if (x > -1) { /* If successful, */
+ dodo(x,NULL,CF_CMDL); /* set up for macro execution */
+ while (maclvl > -1) { /* Loop getting macro commands. */
+ sstate = (CHAR) parser(1);
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+ }
+ debug(F100,"doicp calling herald","",0);
+ herald();
+ }
+#endif /* NOSPL */
+ while(1) { /* Loop getting commands. */
+ sstate = (CHAR) parser(0);
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+#endif /* MAC */
+}
+
+VOID
+#ifdef CK_ANSIC
+failicp(void * threadinfo)
+#else /* CK_ANSIC */
+failicp(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+#ifdef GEMDOS
+ cc_clean();
+#endif /* GEMDOS */
+ fixcmd(); /* Pop command stacks, etc. */
+ clcmds = NULL;
+ debug(F100,"ckcmai got interrupt","",0);
+}
+#endif /* NOICP */
+
+#ifndef NOICP
+VOID
+#ifdef CK_ANSIC
+docmdfile(void * threadinfo) /* Execute application file */
+#else /* CK_ANSIC */
+docmdfile(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* docmdfile */ {
+#ifdef NTSIG
+ concb((char)escape);
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ debug(F100, "docmdfile called with threadinfo block","", 0);
+ } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef IKSD
+#ifdef NT
+ if (inserver)
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+ debug(F110,"main cmdfil",cmdfil,0);
+#ifndef NOSPL
+ addmac("\\%0",cmdfil);
+#endif /* NOSPL */
+ dotake(cmdfil); /* Set up the command file */
+ if (tlevel > -1) /* Remember we did this */
+ cfilef = 1;
+ while (tlevel > -1) { /* Execute it until it runs out. */
+ sstate = parser(1); /* Loop getting commands. */
+ if (sstate) proto(); /* Enter protocol if requested. */
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ }
+
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ return;
+}
+
+VOID
+#ifdef CK_ANSIC
+failcmdfile(void * threadinfo)
+#else /* CK_ANSIC */
+failcmdfile(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failcmdfile */ {
+#ifdef GEMDOS
+ cc_clean(); /* Atari: Clean up after ^C-trap. */
+#endif /* GEMDOS */
+ fixcmd();
+ if (!cfilef) {
+ conoll("Interrupted during initialization or \
+command-line processing.");
+ conoll("C-Kermit quitting...");
+ }
+ doexit(BAD_EXIT,-1); /* Exit with bad status. */
+}
+#endif /* NOICP */
+
+#ifndef NOXFER
+VOID
+setprefix(z) int z; { /* Initial control-char prefixing */
+#ifdef CK_SPEED
+ int i, val;
+
+ prefixing = z;
+ ptab[protocol].prefix = prefixing;
+ debug(F101,"setprefix","",prefixing);
+ switch (z) {
+ case PX_ALL: /* All */
+#ifdef COMMENT
+ /* Don't let Clear-Channel be dependent on prefixing */
+ clearrq = 0; /* Turn off clearchannel, fall thru */
+#endif /* COMMENT */
+ case PX_NON: /* None */
+ val = (z == PX_ALL) ? 1 : 0;
+ for (i =
+#ifdef UNPREFIXZERO
+ 0
+#else
+ 1
+#endif /* UNPREFIXZERO */
+ ; i < 32; i++)
+ ctlp[i] = val;
+ for (i = 127; i < 160; i++) ctlp[i] = val;
+ ctlp[(unsigned)255] = val;
+ if (z == PX_NON) { /* These are never safe */
+ if (network) { /* Assume network = telnet or rlogin */
+ ctlp[CR] = 1; /* Prefix CR because of NVT rules */
+ ctlp[XON] = ctlp[XOFF] = 1; /* Because of Telnet server */
+ ctlp[127] = ctlp[255] = 1; /* Telnet IAC */
+ ctlp[mystch] = ctlp[mystch+128] = 1; /* Kermit packet start */
+ } else {
+ ctlp[CR] = ctlp[255] = ctlp[mystch] = ctlp[mystch+128] = 1;
+ if (flow == FLO_XONX) /* Xon/Xoff forces prefixing */
+ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1;
+ }
+ }
+ break;
+
+ case PX_CAU: /* Cautious or Minimal */
+#ifdef COMMENT
+ /* Don't let CLEAR-CHANNEL be dependent on Prefixing */
+ clearrq = 0; /* Turn off clearchannel */
+#endif /* COMMENT */
+ case PX_WIL: /* Minimal ("wild") */
+ ctlp[0] = 1; /* Does not include 0 */
+ for (i = 1; i < 32; i++)
+ ctlp[i] = 0;
+ for (i = 127; i < 160; i++)
+ ctlp[i] = 0;
+ ctlp[mystch] = ctlp[mystch+128] = 1; /* Kermit start of packet */
+ if (seol != 13)
+ ctlp[seol] = ctlp[seol+128] = 1; /* Kermit end */
+ ctlp[13] = ctlp[141] = 1; /* In case of TELNET (NVT rules) */
+ ctlp[(unsigned)255] = 1; /* Ditto */
+
+ /* ^D, ^J, ^M, or ^U followed by tilde trigger Rlogin escape */
+
+ ctlp[4] = ctlp[4+128] = 1; /* In case of RLOGIN */
+ ctlp[10] = ctlp[10+128] = 1; /* In case of RLOGIN */
+ ctlp[21] = ctlp[21+128] = 1; /* In case of RLOGIN */
+
+ if (flow == FLO_XONX || /* Xon/Xoff forces prefixing these */
+ prefixing == PX_CAU || /* So does CAUTIOUS */
+ network) /* Networks too... */
+ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1;
+ if (prefixing == PX_CAU) { /* Cautious - add some more */
+#ifdef UNPREFIXZERO
+ ctlp[0] = 1;
+#endif /* UNPREFIXZERO */
+ ctlp[3] = ctlp[16] = 1; /* ^C, DLE */
+ ctlp[14] = ctlp[15] = 1; /* SO/SI */
+ ctlp[24] = ctlp[25] = 1; /* VMS might need these */
+ ctlp[26] = ctlp[26+128] = 1; /* UNIX suspend */
+ ctlp[28] = ctlp[29] = ctlp[30] = 1; /* Assorted esc chars */
+ ctlp[131] = ctlp[141] = ctlp[144] = 1; /* and 8-bit versions */
+ ctlp[(unsigned)255] = ctlp[156] = ctlp[157] = ctlp[158] = 1;
+ }
+ break;
+ }
+#endif /* CK_SPEED */
+}
+#endif /* NOXFER */
+
+VOID
+makever() { /* Make version string from pieces */
+ int x, y;
+ char * s;
+#ifndef OS2
+#ifndef MAC
+ ck_s_xver = ck_s_ver; /* Fill in C-Kermit version number */
+ ck_l_xver = ck_l_ver; /* for UNIX, VMS, etc. */
+#endif /* MAC */
+#endif /* OS2 */
+ x = strlen(ck_s_name);
+ y = strlen(ck_s_xver);
+ if (y + x + 1 < CKVERLEN) {
+ ckmakmsg(versio,CKVERLEN,ck_s_name," ",ck_s_xver,NULL);
+ } else {
+ ckstrncpy(versio,"C-Kermit",CKVERLEN);
+ return;
+ }
+ x += y + 1;
+
+ s = " OPEN SOURCE:"; /* C-Kermit 9.0 and later */
+ y = strlen(s);
+ if (CKVERLEN < x + y + 1)
+ return;
+ ckstrncat(versio,s,CKVERLEN);
+
+ x += y + 1;
+ if (*ck_s_who) {
+ y = strlen(ck_s_who);
+ if (CKVERLEN < x + y + 1)
+ return;
+ ckstrncat(versio,"-",CKVERLEN);
+ ckstrncat(versio,ck_s_who,CKVERLEN);
+ }
+ x += y + 1;
+ y = strlen(ck_s_test);
+ if (y > 0 && y + x + 1 < CKVERLEN) {
+ ckstrncat(versio," ",CKVERLEN);
+ ckstrncat(versio,ck_s_test,CKVERLEN);
+ x += y + 1;
+ y = strlen(ck_s_tver);
+ if (y > 0 && y + x + 1 < CKVERLEN) {
+ ckstrncat(versio,".",CKVERLEN);
+ ckstrncat(versio,ck_s_tver,CKVERLEN);
+ x += y + 1;
+ }
+ }
+ y = strlen(ck_s_date);
+ if (y > 0 && y + x + 2 < CKVERLEN) {
+ ckstrncat(versio,", ",CKVERLEN);
+ ckstrncat(versio,ck_s_date,CKVERLEN);
+ }
+ vernum = ck_l_ver;
+ xvernum = ck_l_xver;
+ debug(F110,"Kermit version",versio,0);
+}
+
+union ck_short shortbytes; /* For determining byte order */
+int byteorder = 0; /* 0 = Big Endian; 1 = Little Endian */
+int bigendian = 1;
+/* NOTE: MUST BE 0 or 1 - nothing else */
+
+#ifndef NOSPL
+#define SCRIPTLEN 10240
+#endif /* NOSPL */
+
+#ifdef NETCONN
+#ifndef NOCMDL
+#ifndef NOURL
+VOID
+dourl() {
+ int rc = 0;
+ char * port = NULL;
+ extern int ttnproto;
+ extern struct urldata g_url;
+
+#ifdef COMMENT
+ /* NOTE: debug() doesn't work yet - must use printf's */
+ printf("URL: %s\n",g_url.sav ? g_url.sav : "(none)");
+ printf("Type: %s\n",g_url.svc ? g_url.svc : "(none)");
+ printf("User: %s\n",g_url.usr ? g_url.usr : "(none)");
+ printf("Pass: %s\n",g_url.psw ? g_url.psw : "(none)");
+ printf("Host: %s\n",g_url.hos ? g_url.hos : "(none)");
+/* printf("Port: %s\n",g_url.por ? g_url.por : "(none)"); */
+ printf("Path: %s\n",g_url.pth ? g_url.pth : "(none)");
+#endif /* COMMENT */
+
+ if (!ckstrcmp(g_url.svc,"iksd",-1,0) ||
+ !ckstrcmp(g_url.svc,"kermit",-1,0)) {
+ extern char pwbuf[];
+ extern int pwflg;
+#ifdef OS2
+ extern int pwcrypt;
+#endif /* OS2 */
+
+ if (!g_url.hos) {
+ printf("?Incomplete IKSD URL\n");
+ doexit(BAD_EXIT,1);
+ }
+ if (!g_url.usr)
+ makestr(&g_url.usr,"anonymous");
+ if (!g_url.psw) {
+ char * tmpbuf = NULL;
+ if (!(tmpbuf = (char *)malloc(1024)))
+ fatal("dourl: out of memory");
+ if (!ckstrcmp(g_url.usr,"anonymous",-1,0)) {
+ ckmakmsg(tmpbuf,1024,uidbuf,"@",myhost,NULL);
+ makestr(&g_url.psw,tmpbuf);
+ } else {
+ readpass(" Password:",tmpbuf,1024);
+ makestr(&g_url.psw,tmpbuf);
+ }
+ free(tmpbuf);
+ }
+ port = "kermit";
+ ttnproto = NP_TELNET;
+ nettype = NET_TCPB;
+ mdmtyp = -nettype;
+ local = -1;
+ ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
+ if (g_url.psw) {
+ ckstrncpy(pwbuf,g_url.psw,PWBUFL);
+ pwflg = 1;
+#ifdef OS2
+ pwcrypt = 0;
+#endif /* OS2 */
+ }
+ ckmakmsg(ttname,
+ TTNAMLEN,
+ g_url.hos,
+ ":",
+ g_url.por ? g_url.por : port,
+ NULL
+ );
+ rc = ttopen(ttname,&local,mdmtyp,0);
+ if (rc > -1) {
+ network = 1;
+ exitonclose = 1;
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+ } else {
+ printf("?Connection failed: %s\n",g_url.sav);
+ doexit(BAD_EXIT,1);
+ }
+ /* Also need to check here for secure authentication already done */
+
+#ifdef NOSPL
+ cflg = 1;
+#else
+ {
+ char * script = NULL;
+ if (!(script = (char *)malloc(SCRIPTLEN)))
+ fatal("dourl: out of memory");
+ if (!g_url.pth) { /* Write the appropriate script */
+ cflg = 1;
+ ckmakxmsg(script,SCRIPTLEN,
+ "if not eq {\\v(authstate)} {user} ",
+ "if not eq {\\v(authstate)} {valid} { ",
+ "remote login ", /* No path */
+ g_url.usr, /* Just log in and CONNECT */
+ " ",
+ g_url.psw,
+ ", if fail exit 1 {IKSD login failed} }",
+ ", connect",
+ NULL,NULL,NULL,NULL);
+ /* printf("CLCMDS 1: %s\n",script); */
+ } else {
+ /* does the path specify a file or a directory? */
+ int len = strlen(g_url.pth);
+ if (ISDIRSEP(g_url.pth[len-1])) {
+ ckmakxmsg(script,SCRIPTLEN, /* Directory name given */
+ "if not eq {\\v(authstate)} {user} \
+if not eq {\\v(authstate)} {valid} { remote login ",
+ g_url.usr,
+ " ",
+ g_url.psw,
+ ", if fail exit 1 {IKSD login failed} }",
+ ", set macro error on",
+ ", set xfer displ brief",
+ ", set xfer bell off",
+ ", remote cd ",
+ g_url.pth,
+ ", lineout directory",
+ ", connect"
+ );
+ /* printf("CLCMDS 2: %s\n",script); */
+ } else {
+ ckmakxmsg(script,SCRIPTLEN, /* Path given, try to GET */
+ "if not eq {\\v(authstate)} {user} \
+if not eq {\\v(authstate)} {valid} { remote login ",
+ g_url.usr,
+ " ",
+ g_url.psw,
+ ", if fail exit 1 {IKSD login failed} }",
+ ", set xfer displ brief",
+ ", set xfer bell off",
+ ", get ",
+ g_url.pth,
+ ", .rc := \\v(status)",
+ ", if open connection bye",
+ ", exit \\m(rc)"
+ );
+ /* printf("CLCMDS 2: %s\n",script); */
+ }
+ }
+ clcmds = script; /* Make this our -C cmdline macro */
+ /* printf("HAVEURL=%d\n",haveurl); */
+ }
+#endif /* NOSPL */
+ } else {
+ if (ckstrcmp(g_url.svc,"telnet",-1,0) &&
+#ifdef SSHBUILTIN
+ ckstrcmp(g_url.svc,"ssh",-1,0) &&
+#endif /* SSHBUILTIN */
+ ckstrcmp(g_url.svc,"ftp",-1,0)) {
+ printf("?Sorry, %s URLs not supported\n",
+ g_url.svc ? g_url.svc : "");
+ doexit(BAD_EXIT,1);
+ }
+ }
+}
+#endif /* NOCMDL */
+#endif /* NETCONN */
+#endif /* NOURL */
+
+/*
+ main()...
+
+ If you get complaints about "main: return type is not blah",
+ define MAINTYPE on the CC command line, e.g. "CFLAGS=-DMAINTYPE=blah"
+ (where "blah" is int, long, or whatever).
+
+ If the complaint is "Attempt to return a value from a function of type void"
+ then add -DMAINISVOID.
+*/
+#ifndef MAINTYPE
+#ifndef MAINISVOID
+#define MAINTYPE int
+#endif /* MAINISVOID */
+#endif /* MAINTYPE */
+
+#ifdef MAINISVOID
+#ifndef MAINTYPE
+#define MAINTYPE void
+#endif /* MAINTYPE */
+#endif /* MAINISVOID */
+
+#ifdef aegis
+/* On the Apollo, intercept main to insert a cleanup handler */
+int
+ckcmai(argc,argv) int argc; char **argv;
+#else
+#ifdef MAC /* Macintosh */
+int
+main (void)
+#else
+#ifdef __GNUC__ /* GCC compiler */
+int
+main(argc,argv) int argc; char **argv;
+#else
+#ifdef __DECC /* DEC Alpha with DEC C compiler */
+#ifdef __ALPHA
+int
+main(argc,argv) int argc; char **argv;
+#else /* DEC C compiler, not Alpha */
+#define MAINISVOID
+VOID
+main(argc,argv) int argc; char **argv;
+#endif /* __ALPHA */
+#else
+#ifdef STRATUS /* Stratus VOS */
+int
+main(argc,argv) int argc; char **argv;
+#else /* K-95 */
+#ifdef OS2
+#ifdef KUI
+#define MAINISVOID
+void
+Main( int argc, char ** argv )
+#else /* KUI */
+#define MAINISVOID
+VOID
+main(argc,argv) int argc; char **argv;
+#endif /* KUI */
+#else /* Not K95 */
+MAINTYPE /* All others... */
+main(argc,argv) int argc; char **argv;
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* __DECC */
+#endif /* __GNUC__ */
+#endif /* MAC */
+#endif /* aegis */
+
+/* main */ {
+
+ char *p;
+
+#ifndef NOSETKEY
+ int i;
+#endif /* NOSETKEY */
+
+#ifdef datageneral
+ short *pfha = 016000000036; /* Get around LANG_RT problem */
+ *pfha = (short) 0; /* No user protection fault handler */
+#endif /* datageneral */
+
+ int unbuf = 0; /* nonzero for unbuffered stdout */
+
+/* setbuf has to be called on the file descriptor before it is used */
+
+#ifdef UNIX
+#ifdef NONOSETBUF /* Unbuffered console i/o */
+ unbuf++; /* as a compile-time option */
+#endif /* NONOSETBUF */
+ if (!unbuf) { /* Or as a command-line selection */
+ int i, n; /* We have to pre-pre-scan for */
+ char * s; /* this one. */
+ for (i = 1; i < argc; i++) {
+ s = argv[i];
+ if (!s) n = 0; else n = (int)strlen(s);
+ if (n > 4) {
+ if (!ckstrcmp("--unbuffered",s,n,0)) {
+ unbuf++;
+ break;
+ }
+ }
+ }
+ }
+ if (unbuf)
+ setbuf(stdout,NULL);
+#endif /* UNIX */
+
+/* Do some initialization */
+
+#ifdef VMS
+#ifdef __DECC
+ /* Get some RMS default settings. */
+ get_rms_defaults();
+#endif /* def __DECC */
+#endif /* def VMS */
+
+#ifndef MAC
+ xargc = xargs = argc; /* Make global copies of argc */
+ xargv = argv; /* ...and argv. */
+ xarg0 = argv[0];
+#ifdef NT
+ setOSVer();
+#endif /* NT */
+ zstrip(argv[0],&p); /* Get name we were invoked with */
+ makestr(&myname,p);
+ if (!ckstrcmp(myname,"telnet",-1,0)) howcalled = I_AM_TELNET;
+#ifdef CK_KERBEROS
+ else if (!ckstrcmp(myname,"ktelnet",-1,0)) howcalled = I_AM_TELNET;
+#endif /* CK_KERBEROS */
+ else if (!ckstrcmp(myname,"rlogin",-1,0)) howcalled = I_AM_RLOGIN;
+ else if (!ckstrcmp(myname,"iksd",-1,0)) howcalled = I_AM_IKSD;
+#ifdef NEWFTP
+ else if (!ckstrcmp(myname,"ftp",-1,0)) howcalled = I_AM_FTP;
+#endif /* NEWFTP */
+#ifndef NOHTTP
+ else if (!ckstrcmp(myname,"http",-1,0)) howcalled = I_AM_HTTP;
+#endif /* NOHTTP */
+#ifdef OS2
+ else if (!ckstrcmp(myname,"telnet.exe",-1,0)) howcalled = I_AM_TELNET;
+#ifdef SSHBUILTIN
+ else if (!ckstrcmp(myname,"ssh",-1,0)) howcalled = I_AM_SSH;
+ else if (!ckstrcmp(myname,"ssh.exe",-1,0)) howcalled = I_AM_SSH;
+#endif /* SSHBUILTIN */
+#ifdef CK_KERBEROS
+ else if (!ckstrcmp(myname,"ktelnet.exe",-1,0)) howcalled = I_AM_TELNET;
+#endif /* CK_KERBEROS */
+ else if (!ckstrcmp(myname,"rlogin.exe",-1,0)) howcalled = I_AM_RLOGIN;
+#ifdef NT
+ else if (!ckstrcmp(myname,"iksdnt",-1,0)) howcalled = I_AM_IKSD;
+ else if (!ckstrcmp(myname,"iksdnt.exe",-1,0)) howcalled = I_AM_IKSD;
+#endif /* NT */
+#ifdef NEWFTP
+ else if (!ckstrcmp(myname,"ftp.exe",-1,0)) howcalled = I_AM_FTP;
+#endif /* NEWFTP */
+#ifndef NOHTTP
+ else if (!ckstrcmp(myname,"http.exe",-1,0)) howcalled = I_AM_HTTP;
+#endif /* NOHTTP */
+#endif /* OS2 */
+ else if (!ckstrcmp(myname,"kermit-sshsub",-1,0)) howcalled = I_AM_SSHSUB;
+
+#ifndef NOICP
+ cmdini(); /* Must come before prescan */
+ debug(F100,"main cmdini() done","",0);
+#endif /* NOICP */
+ prescan(0); /* Pre-Check for debugging, etc */
+#endif /* MAC */
+ debug(F101,"MAIN feol","",feol);
+ makever(); /* Put together version strings */
+#ifndef NOSETKEY /* Allocate & initialize the keymap */
+ /* This code has been moved to before sysinit() for K95G */
+ if (!(keymap = (KEY *) malloc(sizeof(KEY)*KMSIZE)))
+ fatal("main: no memory for keymap");
+ if (!(macrotab = (MACRO *) malloc(sizeof(MACRO)*KMSIZE)))
+ fatal("main: no memory for macrotab");
+ for (i = 0; i < KMSIZE; i++) {
+ keymap[i] = (KEY) i;
+ macrotab[i] = NULL;
+ }
+#endif /* NOSETKEY */
+
+ shortbytes.x_short = 0xABCD; /* Get Endianness */
+ if (shortbytes.x_char[0] == 0xCD) { /* 0 = Big Endian */
+ byteorder = 1; /* 1 = Little Endian */
+ bigendian = 0; /* (for clarity in programming) */
+ } else {
+ byteorder = 0; /* Big Endian */
+ bigendian = 1;
+ }
+ if (sizeof(CK_OFF_T) == 8) /* Large files and ints? */
+ havelfs = 1;
+
+ if (sysinit() < 0) /* System-dependent initialization. */
+ fatal("Can't initialize!");
+ else
+ initflg = 1; /* Remember we did. */
+ debug(F111,"ckcmai myname",myname,howcalled);
+
+#ifdef UNIX
+ getexedir(); /* Compute exedir variable */
+#endif /* UNIX */
+
+#ifdef CKSYSLOG
+#ifdef SYSLOGLEVEL
+/*
+ If built with -DSYSLOGLEVEL on cc command line, this means we always
+ do syslogging at the indicated level.
+*/
+ zsyslog(); /* Open syslog */
+#else /* SYSLOGLEVEL */
+#ifdef IKSD
+ if (inserver)
+ zsyslog(); /* Open syslog */
+#endif /* IKSD */
+#endif /* SYSLOGLEVEL */
+#endif /* CKSYSLOG */
+
+#ifdef CK_KERBEROS
+ ini_kerb(); /* Initialize Kerberos data */
+#endif /* CK_KERBEROS */
+#ifdef CK_SSL
+ ssl_once_init();
+#endif /* CK_SSL */
+#ifdef TNCODE
+ tn_set_modes(); /* Init Telnet Option tables */
+#endif /* TNCODE */
+
+#ifdef CK_TTGWSIZ /* Initialize screen dimensions */
+#ifdef OS2
+ ttgcwsz();
+#else /* OS2 */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+#ifndef OS2
+#ifdef TCPSOCKET
+#ifdef CK_SOCKS
+ SOCKSinit(argv[0]); /* Internet relay package... */
+#endif /* CK_SOCKS */
+#endif /* TCPSOCKET */
+#endif /* OS2 */
+
+ initflow(); /* Initialize flow-control table */
+
+#ifndef NOICP
+#ifdef CKFLOAT
+ initfloat(); /* Deduce floating-point precision */
+#endif /* CKFLOAT */
+#endif /* NOICP */
+
+#ifndef NOXFER
+ initxlist(); /* Init exception lists */
+
+#ifdef CK_XYZ /* Initialize protocols... */
+
+#ifdef XYZ_INTERNAL /* XYZMODEM are internal ... */
+
+#ifdef COMMENT
+ /* Can't do this for XMODEM because if filename contains a "C" etc... */
+ initproto(PROTO_X, "rx %s","rx %s", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_XC,"rc %s","rc %s", NULL, NULL, NULL, NULL, NULL);
+#else /* COMMENT */
+ initproto(PROTO_X, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_XC,NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+#endif /* COMMENT */
+ initproto(PROTO_Y, "rb","rb", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_G, "rb","rb", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_Z, "rz","rz", NULL, NULL, NULL, NULL, NULL);
+ initproto(PROTO_K,"kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL);
+ /* Kermit Must be last */
+
+#else /* XYZMODEM are external protocols ... */
+
+ /* s1 s2 s3 s4 s5 s6 s7 */
+ initproto(PROTO_X, "rx %s","rx %s",NULL,"sx %s","sx -a %s","rx %s", "rx %s");
+ initproto(PROTO_XC,"rc %s","rc %s",NULL,"sx %s","sx -a %s","rc %s", "rc %s");
+ initproto(PROTO_Y, "rb", "rb", NULL,"sb %s","sb -a %s","rb", "rb" );
+ initproto(PROTO_G, "rb", "rb", NULL,"sb %s","sb -a %s","rb", "rb" );
+ initproto(PROTO_Z, "rz", "rz", NULL,"sz %s","sz -a %s","rz", "rz" );
+ initproto(PROTO_K, "kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL);
+ /* Kermit must be last */
+
+#endif /* XYZ_INTERNAL */
+
+#else /* No XYZMODEM support */
+
+ initproto(PROTO_K,"kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL);
+
+#endif /* CK_XYZ */
+#endif /* NOXFER */
+
+ connoi(); /* Console interrupts off */
+
+#ifndef NOXFER
+#ifdef OS2
+ /* Initialize Kermit and Zmodem Auto-Download Strings */
+ adl_kstr = strdup("KERMIT READY TO SEND...");
+ adl_zstr = strdup("rz\r");
+#endif /* OS2 */
+
+#ifdef PATTERNS
+ initpat(); /* Initialize filename patterns */
+#endif /* PATTERNS */
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+ initcsets(); /* Initialize character sets */
+#endif /* NOCSETS */
+
+#ifndef NOICP
+#ifdef DFCDMSG
+ makestr(&cdmsgstr,DFCDMSG);
+ makelist(cdmsgstr,cdmsgfile,8); /* Initialize CD message filenames */
+#endif /* DFCDMSG */
+#endif /* NOICP */
+
+ sstate = 0; /* No default start state. */
+#ifdef DYNAMIC
+ if (getiobs() < 0)
+ fatal("Can't allocate i/o buffers!");
+#endif /* DYNAMIC */
+
+#ifndef NOSPL
+#ifndef NORANDOM
+ {
+ char stackdata[256];
+ unsigned int c = 1234, n;
+ /* try to make a random unsigned int to feed srand() */
+#ifndef VMS
+ /* time.h and MultiNet do not get along */
+ c = time(NULL);
+#endif /* VMS */
+ c *= getpid();
+ /* Referenced before set... DELIBERATELY */
+ for (n = 0; n < sizeof(stackdata); n++) /* IGNORE WARNING */
+ c += stackdata[n]; /* DELIBERATELY USED BEFORE SET */
+ srand((unsigned int)c);
+ }
+#endif /* NORANDOM */
+#endif /* NOSPL */
+
+ ckhost(myhost,MYHOSTL); /* Name of local host */
+ debug(F110,"main ckhost",myhost,0);
+#ifdef IKSD
+ if (!inserver) {
+#endif /* IKSD */
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Set up default tty name. */
+ local = nolocal ? 0 : dfloc; /* And whether it's local or remote. */
+ parity = dfprty; /* Set initial parity, */
+#ifndef NOXFER
+ myindex = getsysix(cksysid); /* System index */
+#endif /* NOXFER */
+ if (local) if (ttopen(ttname,&local,0,0) < 0) {
+#ifndef OS2
+ conol("Can't open device: ");
+ conoll(ttname);
+#endif /* OS2 */
+ local = 0;
+ ckstrncpy(ttname,CTTNAM,TTNAMLEN);
+ }
+ setflow(); /* Set appropriate flow control */
+ speed = ttgspd(); /* Get transmission speed. */
+#ifdef IKSD
+ }
+#endif /* IKSD */
+
+#ifdef ANYX25 /* All X.25 implementations */
+#ifndef IBMX25 /* except IBM have PAD support */
+ initpad(); /* Initialize X.25 PAD */
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOXFER
+ if (inibufs(SBSIZ,RBSIZ) < 0) /* Allocate packet buffers */
+ fatal("Can't allocate packet buffers!");
+#ifndef NOCKSPEED
+ setprefix(prefixing); /* Set up control char prefixing */
+#endif /* NOCKSPEED */
+#endif /* NOXFER */
+
+#ifndef NOICP
+ if (sstelnet
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) {
+ int on = 1, x = 0;
+ extern int ckxech, ttnet, ttnproto, cmdmsk;
+#ifdef SO_SNDBUF
+ extern int tcp_sendbuf;
+#endif
+#ifdef SO_RCVBUF
+ extern int tcp_recvbuf;
+#endif
+#ifdef SO_KEEPALIVE
+ extern int tcp_keepalive;
+#endif
+#ifdef SO_LINGER
+ extern int tcp_linger, tcp_linger_tmo;
+#endif /* SO_LINGER */
+#ifdef SO_DONTROUTE
+ extern int tcp_dontroute;
+#endif /* SO_DONTROUTE */
+#ifdef TCP_NODELAY
+ extern int tcp_nodelay;
+#endif /* TCP_NODELAY */
+#ifdef IKSD
+ extern int iklogopen;
+#endif /* IKSD */
+ extern int ttmdm;
+
+#ifdef UNIX
+ if (isatty(0))
+ fatal("Internet Kermit Service cannot be started at a terminal.");
+#endif /* UNIX */
+
+ reliable = xreliable = SET_ON; /* IKSD has reliable connection */
+#ifndef VMS
+ flow = 0; /* No flow control needed */
+#endif /* VMS */
+ bgset = 0; /* Not in background */
+ nopush = 1; /* No external processes */
+ parity = 0; /* 8 bits ... */
+ cmdmsk = 0xff; /* all the way */
+ cmask = 0xff;
+
+#ifdef IKSD
+ if (inserver) { /* If IKSD */
+ doiksdinit(); /* Execute IKSD configuration file */
+ while (tlevel > -1)
+ parser(1); /* (Ignore any file-xfer commands) */
+ iksdcf = 1; /* IKSD c.f. has been processed */
+ }
+ if (!iklogopen) (VOID) doiklog(); /* Open Kermit-specific log */
+#endif /* IKSD */
+
+#ifdef UNIX
+ setbuf(stdout,NULL); /* Don't buffer the output */
+ ckstrncpy(ttname,"0",TTNAMLEN); /* not "/dev/tty"... */
+#endif /* UNIX */
+ local = 0; /* We are in remote mode */
+ ckxech = 1; /* We will echo */
+#ifdef OS2
+ nettype = NET_TCPB; /* So ttopen() treats the connection */
+ mdmtyp = -nettype; /* as a network */
+#endif /* OS2 */
+ debug(F100,"main about to call ttopen() inserver","",0);
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) { /* Open comm channel */
+ fatal("can't initialize i/o");
+ }
+#ifdef OS2
+ local = 0;
+ network = 1; /* Does use networking code */
+#else /* OS2 */
+ network = 0; /* Does not use networking code */
+#endif /* OS2 */
+ ttmdm = -1; /* Does not use a modem */
+ sstelnet = 1; /* Do server-side Telnet negotations */
+ debug(F111,"MAIN","sstelnet",sstelnet);
+ ttnet = NET_TCPB; /* Network type is TCP sockets */
+ ttnproto = NP_TELNET; /* Netword protocol is Telnet */
+#ifdef IKSDB
+ dbinit(); /* Initialize database record */
+#endif /* IKSDB */
+#ifndef OS2
+#ifdef CK_AUTHENTICATION
+ /* Before initializating Telnet/Rlogin negotiations, init Kerberos */
+ ck_auth_init(ckgetpeer(),"","",0);
+#endif /* CK_AUTHENTICATION */
+
+#ifdef NON_BLOCK_IO
+ on = 1;
+ x = socket_ioctl(0,FIONBIO,&on);
+ debug(F101,"main FIONBIO","",x);
+#endif /* NON_BLOCK_IO */
+#ifdef SO_OOBINLINE
+ on = 1;
+ x = setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on));
+ debug(F101,"main SO_OOBINLINE","",x);
+#endif /* SO_OOBINLINE */
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+ no_delay(0,tcp_nodelay);
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+ keepalive(0,tcp_keepalive);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ ck_linger(0,tcp_linger, tcp_linger_tmo);
+#endif /* SO_LINGER */
+#ifdef SO_DONTROUTE
+ dontroute(0,tcp_dontroute);
+#endif /* SO_DONTROUTE */
+#ifdef SO_SNDBUF
+ sendbuf(0,tcp_sendbuf);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ recvbuf(0,tcp_recvbuf);
+#endif /* SO_RCVBUF */
+#endif /* SOL_SOCKET */
+#endif /* datageneral */
+#endif /* NOTCPOPTS */
+
+#ifdef CK_SSL
+ if (ck_ssleay_is_installed()) {
+ if (!ssl_tn_init(SSL_SERVER)) {
+ if (bio_err != NULL) {
+ BIO_printf(bio_err,"do_ssleay_init() failed\r\n");
+ ERR_print_errors(bio_err);
+ } else {
+ fflush(stderr);
+ fprintf(stderr,"do_ssleay_init() failed\r\n");
+ ERR_print_errors_fp(stderr);
+ }
+ switch (ttnproto) {
+ case NP_SSL:
+ case NP_TLS:
+ case NP_SSL_RAW:
+ case NP_TLS_RAW:
+ case NP_SSL_TELNET:
+ case NP_TLS_TELNET:
+ doexit(BAD_EXIT,1);
+ }
+ /* otherwise we will continue to accept the connection */
+ /* without SSL or TLS support unless required. */
+ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ } else {
+ if ( ck_ssl_incoming(0) < 0 ) {
+ doexit(BAD_EXIT,1);
+ }
+ }
+ }
+#endif /* CK_SSL */
+
+#ifdef TNCODE
+ tn_ini(); /* Start Telnet negotiation now */
+#endif /* TNCODE */
+#endif /* OS2 */
+ }
+ debug(F101,"main argc after prescan()","",argc);
+
+ /* Now process any relevant environment variables */
+
+#ifndef NODIAL
+ getdialenv(); /* Dialing */
+#ifdef NETCONN
+ ndinit(); /* Initialize network directory info */
+ getnetenv(); /* Network directories */
+#endif /* NETCONN */
+#endif /* NODIAL */
+
+#ifndef NOXFER
+#ifdef CK_FAST
+ dofast(); /* By now FAST defaults should be OK */
+#endif /* CK_FAST */
+#endif /* NOXFER */
+
+#ifndef NOCMDL
+ ikslogin(); /* IKSD Login and other stuff */
+#ifdef IKSD
+#ifdef NT
+ if ( inserver )
+ setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#endif /* NOCMDL */
+
+ if (howcalled == I_AM_SSHSUB) {
+ reliable = 1; /* We say the connection is reliable */
+ xreliable = 1; /* And that we said it was */
+ setreliable = 1; /* And pretend the "user" did too */
+ xfinish = 1; /* For REMOTE HELP response */
+ mdmtyp = 0; /* For ttopen() */
+ ckstrncpy(ttname,"0",TTNAMLEN+1); /* Use file descriptor 0 */
+ local = 0; /* And force remote mode */
+ ttopen(ttname,&local,mdmtyp,0); /* Open the "connection" */
+ sstate = 'x'; /* Initial state is Server */
+ proto(); /* Enter protocol */
+ doexit(GOOD_EXIT,xitsta); /* Exit when done */
+ }
+ debug(F111,"howcalled",myname,howcalled);
+
+#ifdef NOCCTRAP
+ dotakeini(0);
+#else /* NOCCTRAP */
+ debug(F100,"main about to cc_execute","",0);
+ setint();
+ cc_execute( ckjaddr(cmjbuf), dotakeini, failtakeini );
+#endif /* NOCCTRAP */
+
+ debug(F111,"main 2 cfilef",cmdfil,cfilef);
+ if (cmdfil[0]) { /* If we got one (see prescan())... */
+#ifdef NOCCTRAP
+ docmdfile(0); /* execute it. */
+#else /* NOCCTRAP */
+ setint();
+ cc_execute( ckjaddr(cmjbuf), docmdfile, failcmdfile );
+#endif /* NOCCTRAP */
+ }
+#ifndef OS2 /* Preserve name so we can delete it */
+ *cmdfil = '\0'; /* Done, nullify the file name */
+#endif /* OS2 */
+#endif /* NOICP */
+
+#ifndef NOCMDL
+/* Look for a UNIX-style command line... */
+
+ what = W_NOTHING;
+
+ debug(F101,"main argc","",argc);
+#ifndef NOHELP
+ iniopthlp(); /* Initialize cmdline arg help */
+#endif /* NOHELP */
+ if (
+#ifdef COMMENT
+ !cfilef &&
+#endif /* COMMENT */
+ argc > 1) { /* Command line arguments? */
+ sstate = (CHAR) cmdlin(); /* Yes, parse. */
+#ifdef NETCONN
+#ifndef NOURL
+ if (haveurl) { /* Was a URL given? */
+ dourl(); /* if so, do it. */
+ }
+#endif /* NOURL */
+#endif /* NETCONN */
+#ifndef NOXFER
+ zstate = sstate; /* Remember sstate around protocol */
+ debug(F101,"main zstate","",zstate);
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ if (cflg) { /* Connect first if requested */
+ doconect(0,0);
+ if (ttchk() < 0)
+ dologend();
+ cflg = 0;
+ }
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+ if (sstate) {
+#ifndef NOLOCAL
+ if (displa) concb((char)escape); /* (for console "interrupts") */
+#endif /* NOLOCAL */
+#ifdef NOCCTRAP
+ docmdline(1);
+#else /* NOCCTRAP */
+ setint();
+ cc_execute( ckjaddr(cmjbuf), docmdline, failcmdline );
+#endif /* NOCCTRAP */
+ }
+#endif /* NOXFER */
+
+#ifndef NOICP
+/*
+ If a command-line action argument was given and -S ("stay") was not given,
+ exit now.
+*/
+ if ((cflg || cnflg || zstate) && !stayflg)
+#endif /* NOICP */
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+
+#ifndef NOLOCAL
+#ifndef NOICP
+ if (local) {
+#ifdef NETCONN
+ if ((cflg || cnflg) && tn_exit && ttchk() < 0)
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+#endif /* NETCONN */
+ if (exitonclose && !network &&
+ (carrier != CAR_OFF && (ttgmdm() & BM_DCD) == 0))
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+ if (exitonclose && network && ttchk() < 0)
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+ }
+#endif /* NOICP */
+#endif /* NOLOCAL */
+ }
+#endif /* NOCMDL */
+
+#ifdef NOICP /* No interactive command parser */
+#ifndef NOCMDL
+ else {
+
+ /* Command-line-only version */
+ fatal("?No command-line options given - type 'kermit -h' for help");
+ }
+#else /* Neither one! */
+ sstate = 'x';
+ justone = 0;
+ proto(); /* So go into server mode */
+ doexit(GOOD_EXIT,xitsta); /* exit with good status */
+
+#endif /* NOCMDL */
+#else /* not NOICP */
+/*
+ If no action requested on command line, or if -S ("stay") was included,
+ enter the interactive command parser.
+*/
+ if (!clcmds)
+ herald(); /* Display program herald. */
+
+#ifdef NOCCTRAP
+ debug(F100,"main NOCCTRAP setting interrupt trap","",0);
+ setint(); /* Set up command interrupt traps */
+ doicp(NULL);
+#else /* NOCCTRAP */
+ while (1) {
+ debug(F100,"main setting interrupt trap","",0);
+ setint(); /* Set up command interrupt traps */
+ if (!cc_execute(ckjaddr(cmjbuf), doicp, failicp))
+ break;
+ }
+#endif /* NOCCTRAP */
+#endif /* NOICP */
+#ifndef MAINISVOID
+ return(1);
+#endif /* MAINISVOID */
+}
+
+#ifdef DYNAMIC
+/* Allocate file i/o buffers */
+
+char *zinbuffer = NULL, *zoutbuffer = NULL;
+
+int
+getiobs() {
+ zinbuffer = (char *)malloc(INBUFSIZE);
+ if (!zinbuffer) return(-1);
+ zoutbuffer = (char *)malloc(zobufsize);
+ debug(F101,"zoutbuffer malloc","",zobufsize);
+ if (!zoutbuffer) return(-1);
+ debug(F100,"getiobs ok","",0);
+ return(0);
+}
+#endif /* DYNAMIC */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcmdb.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcmdb.c
new file mode 100644
index 0000000..de5cebc
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcmdb.c
@@ -0,0 +1,387 @@
+/*
+ C K C M D B . C -- malloc debugger.
+*/
+
+/*
+ Author: Howie Kaye, Columbia University Center for Computing Activities.
+
+ Copyright (C) 1985, 1999,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+/* Use the real ones in this module! */
+#ifdef malloc
+#undef malloc
+#endif /* malloc */
+#ifdef calloc
+#undef calloc
+#endif /* calloc */
+#ifdef realloc
+#undef realloc
+#endif /* realloc */
+#ifdef free
+#undef free
+#endif /* free */
+
+#include "ckcsym.h"
+#include <stdio.h>
+#include "ckcdeb.h"
+
+#ifdef COHERENT
+_PROTOTYP ( FILE * fdopen, (int, char *) );
+#endif /* COHERENT */
+
+/*
+ memdebug:
+ variable to control memory debugging.
+ if memdebug == 1, then action is always taken.
+ if memdebug == 0, then no action is taken.
+ if memdebug == -1, then the user is asked (works well with gdb).
+*/
+int memdebug = -1;
+int disabled = 0;
+int inited = 0;
+/*
+ To use this package, compile your program with:
+ -Dmalloc=dmalloc -Dfree=dfree =Dcalloc=dcalloc ... -DMDEBUG
+ and then link it with ckcmdb.c.
+*/
+#ifdef MDEBUG
+
+#ifndef M_SIZE_T
+#ifdef NEXT
+#define M_SIZE_T size_t
+#else
+#ifdef SUNOS41
+#define M_SIZE_T unsigned
+#else
+#define M_SIZE_T int
+#endif /* SUNOS41 */
+#endif /* NEXT */
+#endif /* M_SIZE_T */
+
+#ifdef CK_ANSIC
+_PROTOTYP( void free, (void *) );
+_PROTOTYP( void * malloc, (size_t) );
+_PROTOTYP( void * realloc, (void *, size_t) );
+#else
+_PROTOTYP( VOID free, (char *) );
+_PROTOTYP( char * malloc, (M_SIZE_T) );
+_PROTOTYP( char * realloc, (char *, M_SIZE_T) );
+#endif /* NEXT */
+
+_PROTOTYP( VOID m_insert, (char *) );
+_PROTOTYP( int m_delete, (char *) );
+
+_PROTOTYP( char * dmalloc, (int) );
+_PROTOTYP( char * dcalloc, (int, int) );
+_PROTOTYP( char * drealloc, (char *, int) );
+
+_PROTOTYP( char *set_range_check, (char *, int) );
+_PROTOTYP( char *check_range, (char *) );
+_PROTOTYP( static char *maybe_check_range, (char *) );
+
+_PROTOTYP( static VOID maybe_quit, (char *) );
+_PROTOTYP( static int ask, (char *) );
+
+#ifndef min
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#endif /* min */
+#define RANGE "ABCDEFGHIJKLMNOP"
+#define INTSIZE sizeof(int)
+#define LONGSIZE sizeof(long)
+#define RSIZE sizeof(RANGE)
+#define RFRONT min((RSIZE/2),LONGSIZE)
+#define RBACK min((RSIZE-RFRONT),LONGSIZE)
+
+char *
+dmalloc(size) int size; {
+ char *cp;
+
+ cp = malloc(size + RSIZE + INTSIZE);
+ if (cp) {
+ cp = set_range_check(cp, size);
+ m_insert(cp);
+ }
+ return(cp);
+}
+
+char *
+dcalloc(nelem, elsize) int nelem, elsize; {
+ char *cp;
+
+ cp = dmalloc(nelem * elsize);
+ if (cp)
+ memset(cp, 0, nelem * elsize);
+ return(cp);
+}
+
+char *
+drealloc(bp,size) char *bp; int size; {
+ char *cp;
+
+ if (bp == NULL) {
+ maybe_quit("Freeing NULL pointer");
+ } else {
+ m_delete(bp);
+ cp = check_range(bp);
+ }
+ cp = realloc(cp, size + RSIZE + INTSIZE);
+ if (cp) {
+ cp = set_range_check(cp, size);
+ m_insert(cp);
+ }
+ return(cp);
+}
+
+VOID
+dfree(cp) char *cp; {
+ if (cp == NULL)
+ maybe_quit("Freeing NULL pointer");
+ else {
+ switch(m_delete(cp)) {
+ case 0:
+ cp = maybe_check_range(cp);
+ break;
+ case 1:
+ cp = check_range(cp);
+ break;
+ case 2:
+ break;
+ }
+ }
+#ifndef CK_ANSIC
+ return(free(cp));
+#endif /* CK_ANSIC */
+}
+
+char *
+set_range_check(cp,size) char *cp; int size; {
+ register int i;
+ int tmp = size;
+
+ for(i = 0; i < INTSIZE; i++) { /* set the size in the string */
+ cp[i] = tmp & 0xff;
+ tmp >>= 8;
+ }
+ cp += INTSIZE; /* skip the size */
+
+ for(i = 0; i < RFRONT; i++) /* set the front of the range check */
+ cp[i] = RANGE[i]; /* string */
+
+ cp += RFRONT; /* skip the front range check */
+
+ for(i = 0; i < RBACK; i++) /* set the back odf the range check */
+ cp[i+size] = RANGE[i+RFRONT];
+
+ return(cp);
+}
+
+/*
+ Put calls to this routine in your code any place where you want to
+ check whether you've copied too many characters into a malloc'd space.
+*/
+char *
+check_range(cp) char *cp; {
+ register char *bp = cp - RFRONT - INTSIZE;
+ char *xp = bp;
+ register int i;
+ int size = 0;
+
+ for(i = 0 ; i < INTSIZE; i++) { /* get the size out of the string */
+ size <<= 8;
+ size |= bp[INTSIZE-i-1] & 0xff;
+ }
+ bp += INTSIZE;
+
+ for(i = 0; i < RFRONT; i++) /* check front range check */
+ if (bp[i] != RANGE[i]) {
+ maybe_quit("leftside malloc buffer overrun");
+ break;
+ }
+ bp += RFRONT; /* skip front range check */
+
+ for(i = 0; i < RBACK; i++) /* check back range check */
+ if (bp[i+size] != RANGE[i+RFRONT]) {
+ maybe_quit("rightside malloc buffer overrun");
+ break;
+ }
+ return(xp);
+}
+
+static char *
+maybe_check_range(cp) char *cp; {
+ register char *bp = cp - RFRONT - INTSIZE;
+ char *xp = bp;
+ register int i;
+ int size = 0;
+
+ for(i = 0 ; i < INTSIZE; i++) { /* get the size out of the string */
+ size <<= 8;
+ size |= bp[INTSIZE-i-1] & 0xff;
+ }
+ bp += INTSIZE;
+
+ for(i = 0; i < RFRONT; i++) /* check front range check */
+ if (bp[i] != RANGE[i]) {
+ return(cp);
+ }
+ bp += RFRONT; /* skip front range check */
+
+ for(i = 0; i < RBACK; i++) /* check back range check */
+ if (bp[i+size] != RANGE[i+RFRONT]) {
+ fprintf(stderr,"rightside malloc buffer overrun\n");
+ abort();
+ break;
+ }
+ return(xp);
+}
+
+#define BUCKETS 10000
+char *m_used[BUCKETS];
+char *m_used2[BUCKETS];
+
+VOID
+m_insert(cp) register char *cp; {
+ register int i;
+
+ if (disabled)
+ return;
+
+ for(i = 0; i < BUCKETS; i++)
+ if (m_used[i] == 0) {
+ m_used[i] = cp;
+ return;
+ }
+ disabled ++;
+}
+
+static VOID
+m_insert2(cp) register char *cp; {
+ register int i;
+
+ if (disabled)
+ return;
+ for(i = 0; i < BUCKETS; i++)
+ if (m_used2[i] == 0) {
+ m_used2[i] = cp;
+ return;
+ }
+ disabled ++;
+}
+
+int
+m_delete(cp) register char *cp; {
+ register int i;
+
+ for(i = 0; i < BUCKETS; i++)
+ if (m_used[i] == cp) {
+ m_used[i] = 0;
+ return(1);
+ }
+ for(i = 0; i < BUCKETS; i++)
+ if (m_used2[i] == cp) {
+ m_used2[i] = 0;
+ return(2);
+ }
+ if (disabled)
+ return(0);
+
+ maybe_quit("Freeing unmalloc'ed pointer");
+ return(0);
+}
+
+VOID
+m_init() {
+ register int i;
+
+ inited = 1;
+ disabled = 0;
+#ifdef NEXT
+ malloc_debug(2+4+8+16);
+#endif /* NEXT */
+
+ for(i = 0; i < BUCKETS; i++)
+ m_used[i] = 0;
+}
+
+VOID
+m_done() {
+ register int i,j=0;
+
+ if (disabled)
+ return;
+ for(i = 0; i < BUCKETS; i++)
+ if (m_used[i] != 0) {
+ if (memdebug) {
+ if (j == 0)
+ fprintf(stderr,"unfree'ed buffers, indices: ");
+ fprintf(stderr,"%d, ", i);
+ j++;
+ }
+ }
+ if (j)
+ fprintf(stderr,"\n");
+ for(i = 0; i < BUCKETS; i++)
+ if (m_used2[i] != 0) {
+ if (memdebug) {
+ if (j == 0)
+ fprintf(stderr,"unfree'ed registered buffers, indices: ");
+ fprintf(stderr,"%d, ", i);
+ j++;
+ }
+ }
+ if (j)
+ fprintf(stderr,"\n");
+ if (j)
+ maybe_quit("Unfree'ed malloc buffers");
+}
+
+VOID
+m_checkranges() {
+ int i;
+
+ for ( i = 0; i < BUCKETS; i++)
+ if (m_used[i])
+ check_range(m_used[i]);
+}
+
+static VOID
+maybe_quit(str) char *str; {
+ debug(F100,"mdebug maybe_quit","",0);
+ if (memdebug == 0)
+ return;
+ fprintf(stderr,"%s\n",str);
+ if (memdebug == 1)
+ abort();
+ if (memdebug == -1)
+ if (ask("Quit? "))
+ abort();
+}
+
+static int
+ask(str) char *str; {
+ char buf[100];
+ FILE *in;
+ int fd;
+
+ fd = dup(fileno(stdin));
+ in = fdopen(fd, "r");
+ while(1) {
+ fprintf(stderr,str);
+ fflush(stderr);
+ if (fgets(buf, 99, in) == NULL) /* EOF? */
+ return(0);
+ if (buf[0] == 'n' || buf[0] == 'N') {
+ fclose(in);
+ return(0);
+ }
+ if (buf[0] == 'y' || buf[0] == 'Y') {
+ fclose(in);
+ return(1);
+ }
+ fprintf(stderr,"please answer y/n.\n");
+ }
+}
+#endif /* MDEBUG */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcnet.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcnet.c
new file mode 100644
index 0000000..2bb01a6
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcnet.c
@@ -0,0 +1,14447 @@
+char *cknetv = "Network support, 9.0.297, 14 Jul 2011";
+
+/* C K C N E T -- Network support */
+
+/*
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ REMINDER: Any changes made to this file that other modules depend must
+ also be made to cklnet.c (for VOS) until such time as cklnet.c and this
+ module are merged back together.
+
+ NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
+ C-Kermit source files, must be compatible with C preprocessors that support
+ only #ifdef, #else, #endif, #define, and #undef. Please do not use #if,
+ logical operators, or other preprocessor features in this module. Also,
+ don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
+
+ Authors:
+
+ Frank da Cruz (fdc@columbia.edu),
+ Columbia University Academic Information Systems, New York City.
+ Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary
+ maintainer/developer since about 1996.
+ netopen() routine for TCP/IP originally by Ken Yap, Rochester University
+ (ken@cs.rochester.edu) (no longer at that address).
+ Missing pieces for Excelan sockets library from William Bader.
+ Telnet protocol by Frank da Cruz and Jeffrey Altman.
+ Rlogin protocol by Jeffrey E Altman.
+ SSL support adapted by Jeffrey E Altman from work done by
+ Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
+ TLS support by Jeffrey E Altman.
+ HTTP support by Jeffrey E Altman.
+ TGV MultiNet code by Frank da Cruz.
+ MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
+ MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
+ TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
+ CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
+ X.25 support by Marcello Frutig, Catholic University,
+ Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
+ Stefaan Eeckels, Eurokom, Luxembourg.
+ David Lane added support for Stratus VOS X.25 1996.
+ Stephen Riehm added support for IBM AIX X.25 in April 1998.
+ Other contributions as indicated in the code.
+*/
+#define CKCNET_C
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcker.h"
+#include "ckcasc.h"
+#ifdef I386IX /* Has to come before ckcnet.h in */
+#include <errno.h> /* this version, but after in others */
+#endif /* I386IX */
+#include "ckcnet.h" /* which includes ckctel.h */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifdef CK_DNS_SRV
+#ifdef OS2
+#ifdef NT
+#include <wshelper.h>
+#else /* NT */
+/* !Error OS/2 does not support DNS Service Records. */
+#endif /* NT */
+#else /* OS2 */
+#include <arpa/inet.h>
+#ifdef USE_NAMESER_COMPAT
+#include <arpa/nameser_compat.h>
+#endif /* USE_NAMESER_COMPAT */
+
+#ifdef MINIX3
+#include <net/gen/resolv.h>
+#include <net/gen/nameser.h>
+#else
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif /* MINIX 3 */
+
+#ifndef PS2AIX10
+#ifndef BSD4
+#ifndef I386IX
+#ifndef RTAIX
+#include <netdb.h>
+#endif /* RTAIX */
+#endif /* I386IX */
+#endif /* BSD4 */
+#endif /* PS2AIX10 */
+#endif /* OS2 */
+#ifndef T_SRV
+#define T_SRV 33
+#endif /* T_SRV */
+#ifndef T_TXT
+#define T_TXT 16
+#endif /* T_TXT */
+
+/* for old Unixes and friends ... */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif /* MAXHOSTNAMELEN */
+
+#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
+#endif /* CK_DNS_SRV */
+
+#ifdef NONET
+#ifdef TCPIPLIB
+#undef TCPIPLIB
+#endif /* TCPIPLIB */
+#endif /* NONET */
+
+#ifndef NOMHHOST
+#ifdef datageneral
+#define NOMHHOST
+#else
+#ifdef HPUX5WINTCP
+#define NOMHHOST
+#endif /* HPUX5WINTCP */
+#endif /* datageneral */
+#endif /* NOMHHOST */
+
+#ifdef INADDRX
+ struct in_addr inaddrx;
+#endif /* INADDRX */
+
+int ttnet = NET_NONE; /* Network type */
+int ttnproto = NP_DEFAULT; /* Network virtual terminal protocol */
+
+/* 0 = don't lowercase username for Rlogin/Telnet protocol */
+/* nonzero = do lowercase it. Add a SET command if necessary... */
+#ifdef VMS
+int ck_lcname = 1;
+#else
+int ck_lcname = 0;
+#endif /* VMS */
+
+extern int /* External variables */
+ duplex, debses, seslog, sessft, wasclosed,
+ ttyfd, quiet, msgflg, what, nettype, ttmdm;
+#ifdef IKSD
+extern int inserver;
+#endif /* IKSD */
+
+char myipaddr[20] = { '\0' }; /* Global copy of my IP address */
+char hostipaddr[64] = { '\0' }; /* Global copy of remote IP address */
+
+#ifdef NETCONN
+/* Don't need any of this if there is no network support. */
+
+#ifndef OS2
+/* Current fd-swapping hack is not thread-safe */
+#define HTTP_BUFFERING
+#endif /* OS2 */
+
+#ifdef HTTP_BUFFERING
+#define HTTP_INBUFLEN 8192
+static char http_inbuf[HTTP_INBUFLEN];
+static int http_bufp = 0, http_count;
+#endif /* HTTP_BUFFERING */
+
+/*
+ NETLEBUF is (must be) defined for those platforms that call this
+ module to do network i/o (e.g. netinc(), nettchk(), etc) rather
+ than doing it themselves (ttinc(), ttchk(), etc). In this case
+ the Telnet local-echo buffers and routines are defined and referenced
+ here, rather than in the ck?tio.c module.
+*/
+#ifdef NETLEBUF
+#define LEBUFSIZ 4096
+int ttpush = -1, le_data = 0; /* These are seen from outside */
+static CHAR le_buf[LEBUFSIZ]; /* These are used internally */
+static int le_start = 0, le_end = 0;
+int tt_push_inited = 0;
+#endif /* NETLEBUF */
+
+#ifdef CK_SOCKS /* SOCKS Internet relay package */
+#ifdef CK_SOCKS5 /* SOCKS 5 */
+#define accept SOCKSaccept
+#define bind SOCKSbind
+#define connect SOCKSconnect
+#define getsockname SOCKSgetsockname
+#define listen SOCKSlisten
+#else /* Not SOCKS 5 */
+#define accept Raccept
+#define bind Rbind
+#define connect Rconnect
+#define getsockname Rgetsockname
+#define listen Rlisten
+#endif /* CK_SOCKS5 */
+#endif /* CK_SOCKS */
+
+#ifdef DEC_TCPIP
+#include <time.h>
+#include <inet.h>
+#endif /* DEC_TCPIP */
+
+/* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
+
+#ifdef HPUX
+#ifndef HPUX7 /* HPUX 7.00 doesn't have it */
+#ifndef HPUX6 /* HPUX 6.00 doesn't have it */
+#include <arpa/inet.h> /* For inet_ntoa() prototype */
+#endif /* HPUX6 */
+#endif /* HPUX7 */
+#endif /* HPUX */
+
+#ifdef CMU_TCPIP
+#include <time.h>
+#endif /* CMU_TCPIP */
+
+#ifndef NODCLTIMEVAL
+#ifdef DCLTIMEVAL /* UnixWare 7 */
+struct timeval { /* And define these ourselves. */
+ long tv_sec; /* (see comments in ckutio.c) */
+ long tv_usec;
+};
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif /* DCLTIMEVAL */
+#endif /* NODCLTIMEVAL */
+
+#ifdef WINTCP
+
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+/*
+ The WIN/TCP code path is the same as that for MultiNet.
+ Only the routine names have changed ...
+*/
+#define socket_read netread
+#define socket_ioctl ioctl
+#define socket_write netwrite
+#define socket_close netclose
+
+#ifdef OLD_TWG /* some routines have evolved */
+ extern int vmserrno, uerrno;
+#define socket_errno uerrno
+#define socket_perror perror /* which uses errno, not uerrno! */
+#else
+#define socket_errno errno
+#define socket_perror win$perror
+#endif /* OLD_TWG */
+
+#else /* Not WINTCP */
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#ifndef I386IX
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+#endif /* I386IX */
+
+#include <signal.h> /* Everybody needs this */
+
+#ifdef ZILOG /* Zilog has different name for this */
+#include <setret.h>
+#else
+#include <setjmp.h>
+#endif /* ZILOG */
+
+#endif /* WINTCP */
+
+#ifdef datageneral /* Data General AOS/VS */
+#include <:usr:include:vs_tcp_errno.h>
+#include <:usr:include:sys:vs_tcp_types.h>
+#ifdef SELECT
+/*
+ NOTE: This can be compiled and linked OK with SELECT defined
+ but it doesn't work at all. Anybody who cares and knows how
+ to fix it, feel free.
+*/
+#include <:usr:include:sys:vs_tcp_time.h>
+#endif /* SELECT */
+#include <:usr:include:sys:socket.h>
+#include <:usr:include:netinet:in.h>
+#include <:usr:include:netdb.h>
+#endif /* datageneral */
+
+#ifndef socket_errno
+#define socket_errno errno
+#endif /* socket_errno */
+
+#ifdef TNCODE
+extern int tn_deb;
+#endif /* TNCODE */
+
+int tcp_rdns = /* Reverse DNS lookup */
+#ifdef DEC_TCPIP_OLD
+ SET_OFF /* Doesn't seem to work in UCX */
+#else
+ SET_AUTO
+#endif /* DEC_TCPIP */
+ ;
+#ifdef CK_DNS_SRV
+int tcp_dns_srv = SET_OFF;
+#endif /* CK_DNS_SRV */
+
+_PROTOTYP( char * cmcvtdate, (char *, int) );
+
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_ctrl, (CHAR *, int) );
+_PROTOTYP( static int rlog_oob, (CHAR *, int) );
+#ifndef TCPIPLIB
+_PROTOTYP( static SIGTYP rlogoobh, ( int ) );
+#endif /* TCPIPLIB */
+_PROTOTYP( static int rlog_ini, (CHAR *, int,
+ struct sockaddr_in *,
+ struct sockaddr_in *) );
+int rlog_mode = RL_COOKED;
+int rlog_stopped = 0;
+int rlog_inband = 0;
+#endif /* RLOGCODE */
+
+#ifndef NOICP
+extern int doconx; /* CONNECT-class command active */
+#endif /* NOICP */
+
+#ifdef IBMX25
+/* This variable should probably be generalised for true client/server
+ * support - ie: the fd of the listening server, accepted calls should
+ * be forked or at least handled via a second fd (for IBM's X.25 -
+ * ttyfd always holds the active fd - ie the server becomes inactive
+ * as long as a client is connected, and becomes active again when the
+ * connection is closed)
+ */
+int x25serverfd = 0; /* extern in ckcnet.h */
+int x25seqno = 0; /* Connection sequence number */
+int x25lastmsg = -1; /* A cheapskate's state table */
+
+#define X25_CLOSED 0 /* Default state: no connection, no STREAM */
+#define X25_SETUP 1 /* X.25 has been set up (no connection) */
+#define X25_CONNECTED 2 /* X.25 connection has been established */
+int x25_state = X25_CLOSED; /* Default state */
+#endif /* IBMX25 */
+
+#ifndef DEBUG
+#define deblog 0
+#endif /* DEBUG */
+
+#ifdef CK_NAWS /* Negotiate About Window Size */
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_naws, (void) );
+#endif /* RLOGCODE */
+#endif /* CK_NAWS */
+
+#ifdef OS2 /* For terminal type name string */
+#include "ckuusr.h"
+#ifndef NT
+#include <os2.h>
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+extern int tt_type, max_tt;
+extern struct tt_info_rec tt_info[];
+extern char ttname[];
+#else
+#ifdef CK_AUTHENTICATION
+#include "ckuusr.h"
+#endif /* CK_AUTHENTICATION */
+#endif /* OS2 */
+
+#ifdef NT
+extern int winsock_version;
+#endif /* NT */
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+
+#include "ckcsig.h"
+
+#ifndef OS2 /* For timeout longjumps */
+static ckjmpbuf njbuf;
+#endif /* OS2 */
+
+#define NAMECPYL 1024 /* Local copy of hostname */
+char namecopy[NAMECPYL]; /* Referenced by ckctel.c */
+char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */
+#ifndef NOHTTP
+char http_host_port[NAMECPYL]; /* orig host/port necessary for http */
+char http_ip[20] = { '\0' }; /* ip address of host */
+char http_port = 0;
+int http_ssl = 0;
+char * http_agent = 0;
+int httpfd = -1; /* socket for http connections */
+int http_code = 0;
+#define HTTPBUFLEN 1024
+char http_reply_str[HTTPBUFLEN] = "";
+#endif /* NOHTTP */
+
+char ipaddr[20] = { '\0' }; /* Global copy of IP address */
+unsigned long myxipaddr = 0L; /* Ditto as a number */
+#endif /* NETCONN */
+
+char *tcp_address = NULL; /* Preferred IP Address */
+extern char uidbuf[]; /* User ID buffer */
+extern char pwbuf[]; /* Password buffer */
+
+#ifndef NOHTTP
+char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */
+int tcp_http_proxy_errno = 0;
+char * tcp_http_proxy_user = NULL;
+char * tcp_http_proxy_pwd = NULL;
+char * tcp_http_proxy_agent = NULL;
+#define HTTPCPYL 1024
+static char proxycopy[HTTPCPYL];
+#endif /* NOHTTP */
+
+#ifdef OS2
+extern int tt_rows[], tt_cols[];
+extern int tt_status[VNUM];
+#else /* OS2 */
+extern int tt_rows, tt_cols; /* Everybody has this */
+#endif /* OS2 */
+
+extern int cmd_cols, cmd_rows;
+
+#ifdef STREAMING /* Use blocking writes for streaming */
+extern int streaming;
+#endif /* STREAMING */
+
+#ifdef NT
+extern int WSASafeToCancel;
+int win95selectbug = 0; /* For TCP/IP stacks whose select() */
+/* always fails on write requests such as Cisco and Quarterdeck */
+#define stricmp _stricmp
+#endif /* NT */
+
+#ifndef NOTCPOPTS
+
+/* Skip all this if NOTCPOPTS specified. */
+
+#ifdef SOL_SOCKET
+
+#ifdef TCP_NODELAY
+int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */
+#endif /* TCP_NODELAY */
+
+#ifdef SO_DONTROUTE
+int tcp_dontroute = 0;
+#endif /* SO_DONTROUTE */
+
+#ifdef SO_LINGER
+int tcp_linger = 0; /* SO_LINGER */
+int tcp_linger_tmo = 0; /* SO_LINGER timeout */
+#endif /* SO_LINGER */
+
+#ifdef HPUX /* But the data structures */
+#ifndef HPUX8 /* needed for linger are not */
+#ifndef HPUX9 /* defined in HP-UX versions */
+#ifndef HPUX10 /* prior to 8.00. */
+#ifdef SO_LINGER
+#undef SO_LINGER
+#endif /* SO_LINGER */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* HPUX8 */
+#endif /* HPUX */
+
+#ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */
+#define SO_OOBINLINE 0x0100
+#endif /* SO_OOBINLINE */
+
+#ifndef TCPSNDBUFSIZ
+#ifdef VMS
+#ifdef __alpha
+#define TCPSNDBUFSIZ 16384
+#endif /* __alpha */
+#endif /* VMS */
+#endif /* TCPSNDBUFSIZ */
+
+#ifndef TCPSNDBUFSIZ
+#define TCPSNDBUFSIZ -1
+#endif /* TCPSNDBUFSIZ */
+
+#ifdef SO_SNDBUF
+int tcp_sendbuf = TCPSNDBUFSIZ;
+#endif /* SO_SNDBUF */
+
+#ifdef SO_RCVBUF
+int tcp_recvbuf = -1;
+#endif /* SO_RCVBUF */
+
+#ifdef SO_KEEPALIVE
+int tcp_keepalive = 1;
+#endif /* SO_KEEPALIVE */
+
+#endif /* SOL_SOCKET */
+#endif /* NOTCPOPTS */
+
+#ifndef NETCONN
+/*
+ Network support not defined.
+ Dummy functions here in case #ifdef's forgotten elsewhere.
+*/
+int /* Open network connection */
+netopen(name, lcl, nett) char *name; int *lcl, nett; {
+ return(-1);
+}
+int /* Close network connection */
+netclos() {
+ return(-1);
+}
+int /* Check network input buffer */
+nettchk() {
+ return(-1);
+}
+int /* Flush network input buffer */
+netflui() {
+ return(-1);
+}
+int /* Send network BREAK */
+netbreak() {
+ return(-1);
+}
+int /* Input character from network */
+netinc(timo) int timo; {
+ return(-1);
+}
+int /* Output character to network */
+#ifdef CK_ANSIC
+nettoc(CHAR c)
+#else
+nettoc(c) CHAR c;
+#endif /* CK_ANSIC */
+/* nettoc */ {
+ return(-1);
+}
+int
+nettol(s,n) CHAR *s; int n; {
+ return(-1);
+}
+
+#else /* NETCONN is defined (much of this module...) */
+
+#ifdef NETLEBUF
+VOID
+le_init() { /* LocalEchoInit() */
+ int i;
+ for (i = 0; i < LEBUFSIZ; i++)
+ le_buf[i] = '\0';
+ le_start = 0;
+ le_end = 0;
+ le_data = 0;
+ tt_push_inited = 1;
+}
+
+VOID
+le_clean() { /* LocalEchoCleanup() */
+ le_init();
+ return;
+}
+
+int
+le_inbuf() {
+ int rc = 0;
+ if (le_start != le_end) {
+ rc = (le_end -
+ le_start +
+ LEBUFSIZ) % LEBUFSIZ;
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_putchar(CHAR ch)
+#else
+le_putchar(ch) CHAR ch;
+#endif /* CK_ANSIC */
+/* le_putchar */ {
+ if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
+ debug(F110,"le_putchar","buffer is full",0);
+ return(-1);
+ }
+ le_buf[le_end++] = ch;
+ if (le_end == LEBUFSIZ)
+ le_end = 0;
+ le_data = 1;
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+le_puts(CHAR * s, int n)
+#else
+le_puts(s,n) CHAR * s; int n;
+#endif /* CK_ANSIC */
+/* le_puts */ {
+ int rc = 0;
+ int i = 0;
+ CHAR * p = (CHAR *)"le_puts";
+ ckhexdump(p,s,n);
+ for (i = 0; i < n; i++)
+ rc = le_putchar((char)s[i]);
+ debug(F101,"le_puts","",rc);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_putstr(CHAR * s)
+#else
+le_putstr(s) CHAR * s;
+#endif /* CK_ANSIC */
+/* le_puts */ {
+ CHAR * p;
+ int rc = 0;
+ p = (CHAR *)"le_putstr";
+ ckhexdump(p,s,(int)strlen((char *)s));
+ for (p = s; *p && !rc; p++)
+ rc = le_putchar(*p);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_getchar(CHAR * pch)
+#else /* CK_ANSIC */
+le_getchar(pch) CHAR * pch;
+#endif /* CK_ANSIC */
+/* le_gatchar */ {
+ int rc = 0;
+ if (le_start != le_end) {
+ *pch = le_buf[le_start];
+ le_buf[le_start] = 0;
+ le_start++;
+
+ if (le_start == LEBUFSIZ)
+ le_start = 0;
+
+ if (le_start == le_end) {
+ le_data = 0;
+ }
+ rc++;
+ } else {
+ *pch = 0;
+ }
+ return(rc);
+}
+#endif /* NETLEBUF */
+
+#ifdef VMS
+/*
+ In edit 190, we moved tn_ini() to be called from within netopen().
+ But tn_ini() calls ttol(), and ttol() checks to see if it's a net
+ connection, but the flag for that isn't set until after netopen()
+ is finished. Since, in this module, we are always doing network
+ output anyway, we just call nettol() directly, instead of going thru
+ ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
+ net connections just like regular connections in ttol(), and OS/2
+ has a special routine for this.
+*/
+#define ttol nettol
+#endif /* VMS */
+
+int tcpsrfd = -1;
+
+#ifdef CK_KERBEROS
+
+char * krb5_d_principal = NULL; /* Default principal */
+char * krb5_d_instance = NULL; /* Default instance */
+char * krb5_d_realm = NULL; /* Default realm */
+char * krb5_d_cc = NULL; /* Default credentials cache */
+char * krb5_d_srv = NULL; /* Default Service */
+int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */
+int krb5_d_forwardable = 0; /* creds not forwardable */
+int krb5_d_proxiable = 0; /* creds not proxiable */
+int krb5_d_renewable = 0; /* creds not renewable (0 min) */
+int krb5_autoget = 1; /* Autoget TGTs */
+int krb5_autodel = 0; /* Auto delete TGTs */
+int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */
+int krb5_checkaddrs = 1; /* Check TGT Addrs */
+int krb5_d_no_addresses = 0; /* Do not include IP Addresses */
+char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
+int krb5_errno = 0; /* Last K5 errno */
+char * krb5_errmsg = NULL; /* Last K5 errmsg */
+char * k5_keytab = NULL;
+
+char * krb4_d_principal = NULL; /* Default principal */
+char * krb4_d_realm = NULL; /* Default realm */
+char * krb4_d_srv = NULL; /* Default Service */
+int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */
+int krb4_d_preauth = 1; /* Use preauth requests */
+char * krb4_d_instance = NULL; /* Default instance */
+int krb4_autoget = 1; /* Autoget TGTs */
+int krb4_autodel = 0; /* Auto delete TGTs */
+int krb4_checkaddrs = 1; /* Check TGT Addrs */
+char * k4_keytab = NULL;
+
+int krb4_errno = 0; /* Last K4 errno */
+char * krb4_errmsg = NULL; /* Last K4 errmsg */
+
+struct krb_op_data krb_op = { /* Operational data structure */
+ 0, NULL /* (version, cachefile) */
+};
+
+struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */
+ 0, NULL, NULL, NULL, NULL
+};
+
+struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */
+ 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ 0
+};
+
+struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */
+ 0, 0, 0
+};
+
+int krb_action = -1; /* Kerberos action to perform */
+
+#ifndef CK_AUTHENTICATION
+char *
+ck_krb4_getrealm() {
+ return("");
+}
+char *
+ck_krb5_getrealm(cc) char * cc; {
+ return("");
+}
+char *
+ck_krb4_getprincipal() {
+ return("");
+}
+char *
+ck_krb5_getprincipal(cc) char * cc; {
+ return("");
+}
+#endif /* CK_AUTHENTICATION */
+
+/* I N I _ K E R B -- Initialize Kerberos data */
+
+VOID
+ini_kerb() {
+ int i;
+
+ krb_action = -1; /* No action specified */
+
+ krb_op.version = 0; /* Kerberos version (none) */
+ krb_op.cache = NULL; /* Cache file (none) */
+
+/* Kerberos 5 */
+
+ krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
+ krb5_init.proxiable = krb5_d_proxiable;
+ krb5_init.lifetime = krb5_d_lifetime;
+ krb5_init.renew = 0;
+ krb5_init.renewable = krb5_d_renewable;
+ krb5_init.validate = 0;
+ krb5_init.no_addresses = krb5_d_no_addresses;
+ krb5_init.getk4 = krb5_d_getk4;
+ if (krb5_init.postdate) {
+ free(krb5_init.postdate);
+ krb5_init.postdate = NULL;
+ }
+ if (krb5_init.service) {
+ free(krb5_init.service);
+ krb5_init.service = NULL;
+ }
+ if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */
+ char * p;
+ p = ck_krb5_get_cc_name();
+ makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
+ }
+ if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
+ char * p;
+ p = ck_krb5_getrealm(krb5_d_cc);
+ makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
+ }
+ makestr(&krb5_init.instance,krb5_d_instance);
+ makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
+ if (krb5_init.password) {
+ memset(krb5_init.password,0xFF,strlen(krb5_init.password));
+ free(krb5_init.password);
+ krb5_init.password = NULL;
+ }
+ if (!krb5_d_principal) { /* Default principal */
+ /* a Null principal indicates the user should be prompted */
+ char * p = ck_krb5_getprincipal(krb5_d_cc);
+ if (!p || !(*p))
+ p = (char *)uidbuf; /* Principal = user */
+ makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
+ }
+ makestr(&krb5_init.principal,krb5_d_principal);
+ for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
+ if (krb5_init.addrs[i])
+ free(krb5_init.addrs[i]);
+ krb5_init.addrs[i] = NULL;
+ }
+ for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
+ makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
+ }
+
+ /* Kerberos 4 */
+
+ krb4_init.lifetime = krb4_d_lifetime;
+ krb4_init.preauth = krb4_d_preauth;
+ makestr(&krb4_init.instance,krb4_d_instance);
+ if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
+ char * p;
+ p = ck_krb4_getrealm();
+ makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
+ }
+ makestr(&krb4_init.realm,krb4_d_realm);
+ if (krb4_init.password) {
+ memset(krb4_init.password,0xFF,strlen(krb4_init.password));
+ free(krb4_init.password);
+ krb4_init.password = NULL;
+ }
+ if (!krb4_d_principal) { /* Default principal */
+ /* a Null principal indicates the user should be prompted */
+ char * p = ck_krb4_getprincipal();
+ if (!p || !(*p))
+ p = (char *)uidbuf; /* Principal = user */
+ makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
+ }
+ makestr(&(krb4_init.principal),krb4_d_principal);
+}
+
+/* D O A U T H -- AUTHENTICATE action routine */
+
+int
+doauth(cx) int cx; { /* AUTHENTICATE action routine */
+ int rc = 0; /* Return code */
+
+#ifdef CK_AUTHENTICATION
+#ifdef OS2
+ if (!ck_security_loaddll()) /* Load various DLLs */
+ return(rc);
+#endif /* OS2 */
+ if (krb_op.version == 4) { /* Version = 4 */
+#ifdef COMMENT
+ sho_auth(AUTHTYPE_KERBEROS_V4);
+#endif /* COMMENT */
+ if (!ck_krb4_is_installed()) {
+ printf("?Kerberos 4 is not installed\n");
+ return(0);
+ }
+ switch (krb_action) { /* Perform V4 functions */
+ case KRB_A_IN: /* INIT */
+ rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
+ break;
+ case KRB_A_DE: /* DESTROY */
+ rc |= !(ck_krb4_destroy(&krb_op) < 0);
+ break;
+ case KRB_A_LC: /* LIST-CREDENTIALS */
+ rc |= !(ck_krb4_list_creds(&krb_op) < 0);
+ break;
+ }
+ }
+ if (krb_op.version == 5) { /* V5 functions */
+#ifdef COMMENT
+ sho_auth(AUTHTYPE_KERBEROS_V5);
+#endif /* COMMENT */
+ if (!ck_krb5_is_installed()) {
+ printf("?Kerberos 5 is not installed\n");
+ return(0);
+ }
+ switch (krb_action) {
+ case KRB_A_IN: /* INIT */
+ rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
+ krb5_init.getk4 ? &krb4_init : 0) < 0);
+ break;
+ case KRB_A_DE: /* DESTROY */
+ rc |= !(ck_krb5_destroy(&krb_op) < 0);
+ break;
+ case KRB_A_LC: /* LIST-CREDENTIALS */
+ if (krb_op.version == 0)
+ printf("\n");
+ rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
+ break;
+ }
+ }
+#else
+#ifndef NOICP
+#ifndef NOSHOW
+ rc = sho_auth(0); /* Show all */
+#endif /* NOSHOW */
+#endif /* NOICP */
+#endif /* CK_AUTHENTICATION */
+ return(rc);
+}
+#endif /* CK_KERBEROS */
+
+#ifdef TCPSOCKET
+#ifndef OS2
+#ifndef NOLISTEN /* For incoming connections */
+
+#ifndef INADDR_ANY
+#define INADDR_ANY 0
+#endif /* INADDR_ANY */
+
+_PROTOTYP( int ttbufr, ( VOID ) );
+_PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
+
+static unsigned short tcpsrv_port = 0;
+
+#endif /* NOLISTEN */
+#endif /* OS2 */
+
+static char svcbuf[80]; /* TCP service string */
+static int svcnum = 0; /* TCP port number */
+
+#endif /* TCPSOCKET */
+
+/*
+ TCPIPLIB means use separate socket calls for i/o, while on UNIX the
+ normal file system calls are used for TCP/IP sockets too.
+ Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
+*/
+
+#ifdef TCPIPLIB
+
+/* For buffered network reads... */
+/*
+ If the buffering code is written right, it shouldn't matter
+ how long this buffer is.
+*/
+#ifdef OS2
+#ifdef NT
+#define TTIBUFL 64240 /* 44 * 1460 (MSS) */
+#else
+#define TTIBUFL 32120 /* 22 * 1460 (MSS) */
+#endif /* NT */
+#else /* OS2 */
+#define TTIBUFL 8191 /* Let's use 8K. */
+#endif /* OS2 */
+
+CHAR ttibuf[TTIBUFL+1];
+
+/*
+ select() is used in preference to alarm()/signal(), but different systems
+ use different forms of select()...
+*/
+#ifndef NOSELECT /* Option to override BSDSELECT */
+#ifdef BELLV10
+/*
+ Note: Although BELLV10 does have TCP/IP support, and does use the unique
+ form of select() that is evident in this module (and in ckutio.c), it does
+ not have a sockets library and so we can't build Kermit TCP/IP support for
+ it. For this, somebody would have to write TCP/IP streams code.
+*/
+#define BELLSELECT
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 128
+#endif /* FD_SETSIZE */
+#else
+#ifdef WINTCP /* VMS with Wollongong WIN/TCP */
+#ifndef OLD_TWG /* TWG 3.2 has only select(read) */
+#define BSDSELECT
+#endif /* OLD_TWG */
+#else
+#ifdef CMU_TCPIP /* LIBCMU can do select */
+#define BSDSELECT
+#else
+#ifdef DEC_TCPIP
+#define BSDSELECT
+#else
+#ifdef OS2 /* OS/2 with TCP/IP */
+#ifdef NT
+#define BSDSELECT
+#else /* NT */
+#define IBMSELECT
+#endif /* NT */
+#endif /* OS2 */
+#endif /* DEC_TCPIP */
+#endif /* CMU_TCPIP */
+#endif /* WINTCP */
+#endif /* BELLV10 */
+#endif /* NOSELECT */
+/*
+ Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not
+ compile at all; the IBMSELECT case compiles and links but crashes at runtime.
+ NOTE: If any of these can be converted to select(), they should be for two
+ reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
+ their socket_read() calls to be interrupted; subsequent socket_read()'s tend
+ to fail with EBUSY. This happened in the UCX case before it was converted
+ to use select().
+*/
+#ifndef OS2
+#ifndef VMS
+static /* These are used in CKVTIO.C */
+#endif /* VMS */ /* And in CKONET.C */
+#endif /* OS2 */
+int
+ ttibp = 0,
+ ttibn = 0;
+/*
+ Read bytes from network into internal buffer ttibuf[].
+ To be called when input buffer is empty, i.e. when ttibn == 0.
+
+ Other network reading routines, like ttinc, ttinl, ttxin, should check the
+ internal buffer first, and call this routine for a refill if necessary.
+
+ Returns -1 on error, 0 if nothing happens. When data is read successfully,
+ returns number of bytes read, and sets global ttibn to that number and
+ ttibp (the buffer pointer) to zero.
+*/
+_PROTOTYP( int ttbufr, ( VOID ) );
+int
+ttbufr() { /* TT Buffer Read */
+ int count;
+
+ if (ttnet != NET_TCPB) /* First make sure current net is */
+ return(-1); /* TCP/IP; if not, do nothing. */
+
+#ifdef OS2
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+#endif /* OS2 */
+
+ if (ttibn > 0) { /* Our internal buffer is not empty, */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(ttibn); /* so keep using it. */
+ }
+
+ if (ttyfd == -1) { /* No connection, error */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+
+ ttibp = 0; /* Else reset pointer to beginning */
+
+#ifdef WINTCP
+ count = 512; /* This works for WIN/TCP */
+#else
+#ifdef DEC_TCPIP
+ count = 512; /* UCX */
+#else
+#ifdef OS2
+ count = TTIBUFL;
+#else /* Multinet, etc. */
+ count = ttchk(); /* Check network input buffer, */
+ if (ttibn > 0) { /* which can put a char there! */
+ debug(F111,"ttbufr","ttchk() returns",count);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(ttibn);
+ }
+ if (count < 0) { /* Read error - connection closed */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ else if (count > TTIBUFL) /* Too many to read */
+ count = TTIBUFL;
+ else if (count == 0) /* None, so force blocking read */
+ count = 1;
+#endif /* OS2 */
+#endif /* DEC_TCPIP */
+#endif /* WINTCP */
+ debug(F101,"ttbufr count 1","",count);
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error;
+ ssl_read:
+ if (ssl_active_flag)
+ count = SSL_read(ssl_con, ttibuf, count);
+ else
+ count = SSL_read(tls_con, ttibuf, count);
+ error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
+ switch (error) {
+ case SSL_ERROR_NONE:
+ debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
+ if (count > 0) {
+ ttibp = 0; /* Reset buffer pointer. */
+ ttibn = count;
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(ttibn); /* Return buffer count. */
+ } else if (count < 0) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ } else {
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ case SSL_ERROR_WANT_WRITE:
+ debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ case SSL_ERROR_WANT_READ:
+ debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if ( count == 0 ) { /* EOF */
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ } else {
+ int rc = -1;
+#ifdef NT
+ int gle = GetLastError();
+ debug(F111,"ttbufr SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ rc = -1;
+#endif /* NT */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(rc);
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ case SSL_ERROR_SSL:
+ if (bio_err!=NULL) {
+ int len;
+ extern char ssl_err[];
+ BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
+ if (ssl_debug_flag)
+ printf(ssl_err);
+ } else if (ssl_debug_flag) {
+ debug(F100,"ttbufr SSL_ERROR_SSL","",0);
+ fflush(stderr);
+ fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
+ ERR_print_errors_fp(stderr);
+ }
+#ifdef COMMENT
+ netclos();
+#endif /* COMMENT */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ case SSL_ERROR_ZERO_RETURN:
+ debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ default:
+ debug(F100,"ttbufr SSL_ERROR_?????","",0);
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ }
+#endif /* CK_SSL */
+
+#ifdef COMMENT
+/*
+ This is for nonblocking reads, which we don't do any more. This code didn't
+ work anyway, in the sense that a broken connection was never sensed.
+*/
+ if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
+ if (count == -1 && socket_errno == EWOULDBLOCK) {
+ debug(F100,"ttbufr finds nothing","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(0);
+ } else {
+ debug(F101,"ttbufr socket_read error","",socket_errno);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ }
+
+ } else if (count == 0) {
+ debug(F100,"ttbufr socket eof","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ }
+#else /* COMMENT */
+
+/* This is for blocking reads */
+
+#ifndef VMS
+#ifdef SO_OOBINLINE
+ {
+ int outofband = 0;
+#ifdef BELLSELECT
+ if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
+ outofband = 1;
+#else
+#ifdef BSDSELECT
+ fd_set efds;
+ struct timeval tv;
+ FD_ZERO(&efds);
+ FD_SET(ttyfd, &efds);
+ tv.tv_sec = tv.tv_usec = 0L;
+ debug(F100,"Out-of-Band BSDSELECT","",0);
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+ if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
+ FD_ISSET(ttyfd, &efds))
+ outofband = 1;
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#else /* !BSDSELECT */
+#ifdef IBMSELECT
+/* Is used by OS/2 ... */
+/* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */
+/* and timeval stuff since this is the only place where it is used. */
+ int socket = ttyfd;
+ debug(F100,"Out-of-Band IBMSELECT","",0);
+ if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
+ outofband = 1;
+#else /* !IBMSELECT */
+/*
+ If we can't use select(), then we use the regular alarm()/signal()
+ timeout mechanism.
+*/
+ debug(F101,"Out-of-Band data not supported","",0);
+ outofband = 0;
+
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+#endif /* BELLSELECT */
+ if (outofband) {
+ /* Get the Urgent Data */
+ /* if OOBINLINE is disabled this should be only a single byte */
+ /* MS Winsock has a bug in Windows 95. Extra bytes are delivered */
+ /* That were never sent. */
+#ifdef OS2
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+#endif /* OS2 */
+ count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ if (count <= 0) {
+ int s_errno = socket_errno;
+ debug(F101, "ttbufr socket_recv MSG_OOB","",count);
+ debug(F101, "ttbufr socket_errno","",s_errno);
+#ifdef OS2ONLY
+ if (count < 0 && (s_errno == 0 || s_errno == 23)) {
+ /* These appear in OS/2 - don't know why */
+ /* ignore it and read as normal data */
+ /* and break, then we will attempt to read */
+ /* the port using normal read() techniques */
+ debug(F100,"ttbufr handing as in-band data","",0);
+ count = 1;
+ } else {
+ netclos(); /* *** *** */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+#else /* OS2ONLY */
+ netclos(); /* *** *** */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+#endif /* OS2ONLY */
+ } else { /* we got out-of-band data */
+ ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
+#ifdef BETADEBUG
+ bleep(BP_NOTE);
+#endif /* BETADEBUG */
+#ifdef RLOGCODE /* blah */
+ if (ttnproto == NP_RLOGIN ||
+ ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
+ ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) &&
+ !rlog_inband)
+ )
+ {
+ /*
+ When urgent data is read with MSG_OOB and not OOBINLINE
+ then urgent data and normal data are not mixed. So
+ treat the entire buffer as urgent data.
+ */
+ rlog_oob(&ttibuf[ttibp+ttibn], count);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return ttbufr();
+ } else
+#endif /* RLOGCODE */ /* blah */
+#ifdef COMMENT
+ /*
+ I haven't written this yet, nor do I know what it should do
+ */
+ if (ttnproto == NP_TELNET) {
+ tn_oob();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return 0;
+ } else
+#endif /* COMMENT */
+ {
+ /* For any protocols we don't have a special out-of-band */
+ /* handler for, just put the bytes in the normal buffer */
+ /* and return */
+
+ ttibp += 0; /* Reset buffer pointer. */
+ ttibn += count;
+#ifdef DEBUG
+ /* Got some bytes. */
+ debug(F101,"ttbufr count 2","",count);
+ if (count > 0)
+ ttibuf[ttibp+ttibn] = '\0';
+ debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
+#endif /* DEBUG */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(ttibn); /* Return buffer count. */
+ }
+ }
+ }
+ }
+#endif /* SO_OOBINLINE */
+#endif /* VMS */
+
+ count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
+ if (count <= 0) {
+ int s_errno = socket_errno;
+ debug(F101,"ttbufr socket_read","",count);
+ debug(F101,"ttbufr socket_errno","",s_errno);
+#ifdef OS2
+ if (count == 0 || os2socketerror(s_errno) < 0) {
+ netclos();
+ ReleaseTCPIPMutex();
+ return(-2);
+ }
+ ReleaseTCPIPMutex();
+ return(-1);
+#else /* OS2 */
+ netclos(); /* *** *** */
+ return(-2);
+#endif /* OS2 */
+ }
+#endif /* COMMENT */ /* (blocking vs nonblock reads...) */
+ else {
+ ttibp = 0; /* Reset buffer pointer. */
+ ttibn += count;
+#ifdef DEBUG
+ debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
+ if (count > 0)
+ ttibuf[ttibp+ttibn] = '\0';
+ debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
+#endif /* DEBUG */
+
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(ttibn); /* Return buffer count. */
+ }
+}
+#endif /* TCPIPLIB */
+
+#ifndef IBMSELECT
+#ifndef BELLSELECT
+#ifndef BSDSELECT /* Non-TCPIPLIB case */
+#ifdef SELECT
+#define BSDSELECT
+#endif /* SELECT */
+#endif /* BSDSELECT */
+#endif /* BELLSELECT */
+#endif /* IBMSELECT */
+
+#define TELNET_PORT 23 /* Should do lookup, but it won't change */
+#define RLOGIN_PORT 513
+#define KERMIT_PORT 1649
+#define KLOGIN_PORT 543
+#define EKLOGIN_PORT 2105
+
+#ifndef NONET
+/*
+ C-Kermit network open/close functions for BSD-sockets.
+ Much of this code shared by SunLink X.25, which also uses the socket library.
+*/
+
+/* N E T O P N -- Open a network connection. */
+/*
+ Call with:
+ name of host (or host:service),
+ lcl - local-mode flag to be set if this function succeeds,
+ network type - value defined in ckunet.h.
+*/
+#ifdef TCPSOCKET
+struct hostent *
+#ifdef CK_ANSIC
+ck_copyhostent(struct hostent * h)
+#else /* CK_ANSIC */
+ck_copyhostent(h) struct hostent * h;
+#endif /* CK_ANSIC */
+{
+ /*
+ * The hostent structure is dynamic in nature.
+ * struct hostent {
+ * char * h_name;
+ * char * * h_aliases;
+ * short h_addrtype;
+ * short h_length;
+ * char * * h_addr_list;
+ * #define h_addr h_addr_list[0]
+ */
+#define HOSTENTCNT 5
+ static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
+ {NULL,NULL,0,0,NULL},
+ {NULL,NULL,0,0,NULL},
+ {NULL,NULL,0,0,NULL},
+ {NULL,NULL,0,0,NULL}};
+ static int next = 0;
+ int i,cnt;
+ char ** pp;
+
+ if ( h == NULL )
+ return(NULL);
+
+ if (next == HOSTENTCNT)
+ next = 0;
+
+ if ( hosts[next].h_name ) {
+ free(hosts[next].h_name);
+ hosts[next].h_name = NULL;
+ }
+ if ( hosts[next].h_aliases ) {
+ pp = hosts[next].h_aliases;
+ while ( *pp ) {
+ free(*pp);
+ pp++;
+ }
+ free(hosts[next].h_aliases);
+ }
+#ifdef HADDRLIST
+ if ( hosts[next].h_addr_list ) {
+ pp = hosts[next].h_addr_list;
+ while ( *pp ) {
+ free(*pp);
+ pp++;
+ }
+ free(hosts[next].h_addr_list);
+ }
+#endif /* HADDRLIST */
+
+ makestr(&hosts[next].h_name,h->h_name);
+ if (h->h_aliases) {
+ for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
+ /* The following can give warnings in non-ANSI builds */
+ hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
+ for ( i=0; i<cnt; i++) {
+ hosts[next].h_aliases[i] = NULL;
+ makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
+ }
+ hosts[next].h_aliases[i] = NULL;
+ } else
+ hosts[next].h_aliases = NULL;
+
+ hosts[next].h_addrtype = h->h_addrtype;
+ hosts[next].h_length = h->h_length;
+
+#ifdef HADDRLIST
+#ifdef h_addr
+ if (h->h_addr_list) {
+ for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
+ /* The following can give warnings non-ANSI builds */
+ hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
+ for ( i=0; i<cnt; i++) {
+ hosts[next].h_addr_list[i] = malloc(h->h_length);
+ bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
+ }
+ hosts[next].h_addr_list[i] = NULL;
+ } else
+ hosts[next].h_addr_list = NULL;
+#else
+ bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
+#endif /* h_addr */
+#else /* HADDRLIST */
+ bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
+#endif /* HADDRLIST */
+
+ return(&hosts[next++]);
+}
+
+#ifdef EXCELAN
+/*
+ Most other BSD sockets implementations define these in header files
+ and libraries.
+*/
+struct servent {
+ unsigned short s_port;
+};
+
+struct hostent {
+ short h_addrtype;
+ struct in_addr h_addr;
+ int h_length;
+};
+
+struct servent *
+getservbyname(service, connection) char *service,*connection; {
+ static struct servent servrec;
+ int port;
+
+ port = 0;
+ if (strcmp(service, "telnet") == 0) port = 23;
+ else if (strcmp(service, "smtp") == 0) port = 25;
+ else port = atoi(service);
+
+ debug(F101,"getservbyname return port ","",port);
+
+ if (port > 0) {
+ servrec.s_port = htons(port);
+ return(&servrec);
+ }
+ return((struct servent *) NULL);
+}
+
+struct hostent *
+gethostbyname(hostname) char *hostname; {
+ return((struct hostent *) NULL);
+}
+
+unsigned long
+inet_addr(name) char *name; {
+ unsigned long addr;
+
+ addr = rhost(&name);
+ debug(F111,"inet_addr ",name,(int)addr);
+ return(addr);
+}
+
+char *
+inet_ntoa(in) struct in_addr in; {
+ static char name[80];
+ ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
+ ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
+ return(name);
+}
+#else
+#ifdef DEC_TCPIP /* UCX */
+
+int ucx_port_bug = 0; /* Explained below */
+
+#ifdef OLDIP /* Very old VAXC or GCC */
+/*
+ Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP,
+ hence the "Very old" in the comment - SMS, 2010/03/15.
+*/
+#define getservbyname my_getservbyname
+
+#ifdef CK_ANSIC
+globalref int (*C$$GA_UCX_GETSERVBYNAME)();
+extern void C$$TRANSLATE();
+extern void C$$SOCK_TRANSLATE();
+#else
+globalref int (*C$$GA_UCX_GETSERVBYNAME)();
+extern VOID C$$TRANSLATE();
+extern VOID C$$SOCK_TRANSLATE();
+#endif /* CK_ANSIC */
+
+struct servent *
+my_getservbyname (service, proto) char *service, *proto; {
+ static struct servent sent;
+ struct iosb {
+ union {
+ unsigned long status;
+ unsigned short st[2];
+ } sb;
+ unsigned long spare;
+ } s;
+ struct {
+ struct iosb *s;
+ char *serv;
+ char *prot;
+ } par;
+ unsigned long e;
+ char sbuf[30], pbuf[30];
+ char *p;
+
+ debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
+
+ p = sbuf;
+ ckstrncpy(p, service, 29);
+ while (*p = toupper(*p), *p++) {}
+ p = pbuf;
+ ckstrncpy(p, proto, 29);
+ while (*p = toupper(*p), *p++) {}
+
+ par.s = &s;
+
+ par.serv = "";
+ par.prot = "";
+ /* reset file pointer or something like that!?!? */
+ e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
+ par.serv = sbuf;
+ par.prot = pbuf; /* that is don't care */
+ e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
+ if ((long)e == -1L)
+ return NULL;
+ if ((e & 1) == 0L) {
+ C$$TRANSLATE(e);
+ return NULL;
+ }
+ if ((s.sb.st[0] & 1) == 0) {
+ C$$SOCK_TRANSLATE(&s.sb.st[0]);
+ return NULL;
+ }
+/*
+ sent.s_port is supposed to be returned by UCX in network byte order.
+ However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
+ But there is no way of knowing which UCX version, so we have a user-settable
+ runtime variable. Note: UCX 2.0 was only for the VAX.
+*/
+ debug(F101,"UCX getservbyname port","",sent.s_port);
+ debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
+ if (ucx_port_bug) {
+ sent.s_port = htons(sent.s_port);
+ debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
+ debug(F101,"UCX swapped port","",sent.s_port);
+ debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
+ }
+ return &sent;
+}
+#endif /* def OLDIP */
+#endif /* DEC_TCPIP */
+#endif /* EXCELAN */
+
+int
+gettcpport() {
+ return(svcnum);
+}
+
+#endif /* TCPSOCKET */
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+int
+ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
+/*
+ The following, from William Bader, turns off the socket linger parameter,
+ which makes a close() block until all data is sent. "I don't think that
+ disabling linger can ever cause kermit to lose data, but you telnet to a
+ flaky server (or to our modem server when the modem is in use), disabling
+ linger prevents kermit from hanging on the close if you try to exit."
+
+ Modified by Jeff Altman to be generally useful.
+*/
+#ifdef SOL_SOCKET
+#ifdef SO_LINGER
+ struct linger set_linger_opt;
+ struct linger get_linger_opt;
+ SOCKOPT_T x;
+
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ if (sock == -1 ||
+ nettype != NET_TCPA && nettype != NET_TCPB &&
+ nettype != NET_SSH || ttmdm >= 0) {
+ tcp_linger = onoff;
+ tcp_linger_tmo = timo;
+ return(1);
+ }
+ x = sizeof(get_linger_opt);
+ if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
+ (char *)&get_linger_opt, &x)) {
+ debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
+ } else if (x != sizeof(get_linger_opt)) {
+#ifdef OS2
+ struct _linger16 {
+ short s_linger;
+ short s_onoff;
+ } get_linger_opt16, set_linger_opt16;
+ if ( x == sizeof(get_linger_opt16) ) {
+ debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_LINGER,
+ (char *)&get_linger_opt16, &x)
+ ) {
+ debug(F111,
+ "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
+ } else if (get_linger_opt16.s_onoff != onoff ||
+ get_linger_opt16.s_linger != timo)
+ {
+ set_linger_opt16.s_onoff = onoff;
+ set_linger_opt16.s_linger = timo;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_LINGER,
+ (char *)&set_linger_opt16,
+ sizeof(set_linger_opt16))
+ ) {
+ debug(F111,
+ "TCP ck_linger can't set SO_LINGER",
+ ck_errstr(),
+ errno
+ );
+ tcp_linger = get_linger_opt16.s_onoff;
+ tcp_linger_tmo = get_linger_opt16.s_linger;
+ } else {
+ debug(F101,
+ "TCP ck_linger new SO_LINGER","",
+ set_linger_opt16.s_onoff);
+ tcp_linger = set_linger_opt16.s_onoff;
+ tcp_linger_tmo = set_linger_opt16.s_linger;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP ck_linger SO_LINGER unchanged","",
+ get_linger_opt16.s_onoff);
+ tcp_linger = get_linger_opt16.s_onoff;
+ tcp_linger_tmo = get_linger_opt16.s_linger;
+ return 1;
+ }
+ return(0);
+ }
+#endif /* OS2 */
+ debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
+ debug(F111,"TCP ck_linger SO_LINGER",
+ "expected len",sizeof(get_linger_opt));
+ debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
+ get_linger_opt.l_onoff);
+ debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
+ get_linger_opt.l_linger);
+ } else if (get_linger_opt.l_onoff != onoff ||
+ get_linger_opt.l_linger != timo) {
+ set_linger_opt.l_onoff = onoff;
+ set_linger_opt.l_linger = timo;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_LINGER,
+ (char *)&set_linger_opt,
+ sizeof(set_linger_opt))) {
+ debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
+ tcp_linger = get_linger_opt.l_onoff;
+ tcp_linger_tmo = get_linger_opt.l_linger;
+ } else {
+ debug(F101,
+ "TCP ck_linger new SO_LINGER",
+ "",
+ set_linger_opt.l_onoff
+ );
+ tcp_linger = set_linger_opt.l_onoff;
+ tcp_linger_tmo = set_linger_opt.l_linger;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP ck_linger SO_LINGER unchanged","",
+ get_linger_opt.l_onoff);
+ tcp_linger = get_linger_opt.l_onoff;
+ tcp_linger_tmo = get_linger_opt.l_linger;
+ return 1;
+ }
+#else
+ debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
+#endif /* SO_LINGER */
+#else
+ debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
+#endif /* SOL_SOCKET */
+ return(0);
+}
+
+int
+sendbuf(sock,size) int sock; int size; {
+/*
+ The following, from William Bader, allows changing of socket buffer sizes,
+ in case that might affect performance.
+
+ Modified by Jeff Altman to be generally useful.
+*/
+#ifdef SOL_SOCKET
+#ifdef SO_SNDBUF
+ int i, j;
+ SOCKOPT_T x;
+
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ if (sock == -1 ||
+ nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
+ || ttmdm >= 0) {
+ tcp_sendbuf = size;
+ return 1;
+ }
+ x = sizeof(i);
+ if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
+ debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
+ } else if (x != sizeof(i)) {
+#ifdef OS2
+ short i16,j16;
+ if (x == sizeof(i16)) {
+ debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_SNDBUF,
+ (char *)&i16, &x)
+ ) {
+ debug(F111,"TCP sendbuf can't get SO_SNDBUF",
+ ck_errstr(),errno);
+ } else if (size <= 0) {
+ tcp_sendbuf = i16;
+ debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
+ return 1;
+ } else if (i16 != size) {
+ j16 = size;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ (char *)&j16,
+ sizeof(j16))
+ ) {
+ debug(F111,"TCP sendbuf can't set SO_SNDBUF",
+ ck_errstr(),errno);
+ } else {
+ debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
+ debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
+ tcp_sendbuf = size;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
+ tcp_sendbuf = size;
+ return 1;
+ }
+ return(0);
+ }
+#endif /* OS2 */
+ debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
+ debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
+ debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
+ } else if (size <= 0) {
+ tcp_sendbuf = i;
+ debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
+ return 1;
+ } else if (i != size) {
+ j = size;
+ if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
+ debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
+ tcp_sendbuf = i;
+ } else {
+ debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
+ debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
+ tcp_sendbuf = size;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
+ tcp_sendbuf = size;
+ return 1;
+ }
+#else
+ debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
+#endif /* SO_SNDBUF */
+#else
+ debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
+#endif /* SOL_SOCKET */
+ return(0);
+}
+
+int
+recvbuf(sock,size) int sock; int size; {
+/*
+ The following, from William Bader, allows changing of socket buffer sizes,
+ in case that might affect performance.
+
+ Modified by Jeff Altman to be generally useful.
+*/
+#ifdef SOL_SOCKET
+#ifdef SO_RCVBUF
+ int i, j;
+ SOCKOPT_T x;
+
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ if (sock == -1 ||
+ nettype != NET_TCPA && nettype != NET_TCPB &&
+ nettype != NET_SSH || ttmdm >= 0) {
+ tcp_recvbuf = size;
+ return(1);
+ }
+ x = sizeof(i);
+ if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
+ debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
+ } else if (x != sizeof(i)) {
+#ifdef OS2
+ short i16,j16;
+ if ( x == sizeof(i16) ) {
+ debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_RCVBUF,
+ (char *)&i16, &x)
+ ) {
+ debug(F111,"TCP recvbuf can't get SO_RCVBUF",
+ ck_errstr(),errno);
+ } else if (size <= 0) {
+ tcp_recvbuf = i16;
+ debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
+ return 1;
+ } else if (i16 != size) {
+ j16 = size;
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
+ sizeof(j16))) {
+ debug(F111,"TCP recvbuf can' set SO_RCVBUF",
+ ck_errstr(),errno);
+ } else {
+ debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
+ debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
+ tcp_recvbuf = size;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
+ tcp_recvbuf = size;
+ return 1;
+ }
+ return(0);
+ }
+#endif /* OS2 */
+ debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
+ debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
+ debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
+ } else if (size <= 0) {
+ tcp_recvbuf = i;
+ debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
+ return 1;
+ } else if (i != size) {
+ j = size;
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
+ debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
+ tcp_recvbuf = i;
+ } else {
+ debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
+ debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
+ tcp_recvbuf = size;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
+ tcp_recvbuf = size;
+ return 1;
+ }
+#else
+ debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
+#endif /* SO_RCVBUF */
+#else
+ debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
+#endif /* SOL_SOCKET */
+ return 0;
+}
+
+int
+keepalive(sock,onoff) int sock; int onoff; {
+#ifdef SOL_SOCKET
+#ifdef SO_KEEPALIVE
+ int get_keepalive_opt;
+ int set_keepalive_opt;
+ SOCKOPT_T x;
+
+ debug(F111,"TCP keepalive","sock",sock);
+ debug(F111,"TCP keepalive","nettype",nettype);
+ debug(F111,"TCP keepalive","ttmdm",ttmdm);
+
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ if (sock == -1 ||
+ nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
+ || ttmdm >= 0) {
+ tcp_keepalive = onoff;
+ return 1;
+ }
+ x = sizeof(get_keepalive_opt);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
+ debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
+ } else if (x != sizeof(get_keepalive_opt)) {
+#ifdef OS2
+ short get_keepalive_opt16;
+ short set_keepalive_opt16;
+ if (x == sizeof(get_keepalive_opt16)) {
+ debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
+ "len is 16-bit",x);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&get_keepalive_opt16, &x)
+ ) {
+ debug(F111,
+ "TCP keepalive can't get SO_KEEPALIVE",
+ ck_errstr(),
+ errno
+ );
+ } else if (get_keepalive_opt16 != onoff) {
+ set_keepalive_opt16 = onoff;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (char *)&set_keepalive_opt16,
+ sizeof(set_keepalive_opt16))
+ ) {
+ debug(F111,
+ "TCP keepalive can't clear SO_KEEPALIVE",
+ ck_errstr(),
+ errno
+ );
+ tcp_keepalive = get_keepalive_opt16;
+ } else {
+ debug(F101,
+ "TCP keepalive new SO_KEEPALIVE","",
+ set_keepalive_opt16);
+ tcp_keepalive = set_keepalive_opt16;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
+ get_keepalive_opt16);
+ tcp_keepalive = onoff;
+ return 1;
+ }
+ return(0);
+ }
+#endif /* OS2 */
+ debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
+ debug(F111,
+ "TCP keepalive SO_KEEPALIVE",
+ "expected len",
+ sizeof(get_keepalive_opt)
+ );
+ debug(F111,
+ "TCP keepalive SO_KEEPALIVE",
+ "keepalive_opt",
+ get_keepalive_opt
+ );
+ } else if (get_keepalive_opt != onoff) {
+ set_keepalive_opt = onoff;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (char *)&set_keepalive_opt,
+ sizeof(set_keepalive_opt))
+ ) {
+ debug(F111,
+ "TCP keepalive can't clear SO_KEEPALIVE",
+ ck_errstr(),
+ errno
+ );
+ tcp_keepalive = get_keepalive_opt;
+ } else {
+ debug(F101,
+ "TCP keepalive new SO_KEEPALIVE",
+ "",
+ set_keepalive_opt
+ );
+ tcp_keepalive = onoff;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
+ "",
+ get_keepalive_opt
+ );
+ tcp_keepalive = onoff;
+ return 1;
+ }
+#else
+ debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
+#endif /* SO_KEEPALIVE */
+#else
+ debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
+#endif /* SOL_SOCKET */
+ return(0);
+}
+
+int
+dontroute(sock,onoff) int sock; int onoff; {
+#ifdef SOL_SOCKET
+#ifdef SO_DONTROUTE
+ int get_dontroute_opt;
+ int set_dontroute_opt;
+ SOCKOPT_T x;
+
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ if (sock == -1 ||
+ nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
+ || ttmdm >= 0) {
+ tcp_dontroute = onoff;
+ return 1;
+ }
+ x = sizeof(get_dontroute_opt);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
+ debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
+ } else if (x != sizeof(get_dontroute_opt)) {
+#ifdef OS2
+ short get_dontroute_opt16;
+ short set_dontroute_opt16;
+ if (x == sizeof(get_dontroute_opt16)) {
+ debug(F111,"TCP dontroute warning: SO_DONTROUTE",
+ "len is 16-bit",x);
+ if (getsockopt(sock,
+ SOL_SOCKET, SO_DONTROUTE,
+ (char *)&get_dontroute_opt16, &x)
+ ) {
+ debug(F111,
+ "TCP dontroute can't get SO_DONTROUTE",
+ ck_errstr(),
+ errno
+ );
+ } else if (get_dontroute_opt16 != onoff) {
+ set_dontroute_opt16 = onoff;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_DONTROUTE,
+ (char *)&set_dontroute_opt16,
+ sizeof(set_dontroute_opt16))
+ ) {
+ debug(F111,
+ "TCP dontroute can't clear SO_DONTROUTE",
+ ck_errstr(),
+ errno
+ );
+ tcp_dontroute = get_dontroute_opt16;
+ } else {
+ debug(F101,
+ "TCP dontroute new SO_DONTROUTE","",
+ set_dontroute_opt16);
+ tcp_dontroute = set_dontroute_opt16;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
+ get_dontroute_opt16);
+ tcp_dontroute = onoff;
+ return 1;
+ }
+ return(0);
+ }
+#endif /* OS2 */
+ debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
+ debug(F111,
+ "TCP dontroute SO_DONTROUTE",
+ "expected len",
+ sizeof(get_dontroute_opt)
+ );
+ debug(F111,
+ "TCP dontroute SO_DONTROUTE",
+ "dontroute_opt",
+ get_dontroute_opt
+ );
+ } else if (get_dontroute_opt != onoff) {
+ set_dontroute_opt = onoff;
+ if (setsockopt(sock,
+ SOL_SOCKET,
+ SO_DONTROUTE,
+ (char *)&set_dontroute_opt,
+ sizeof(set_dontroute_opt))
+ ) {
+ debug(F111,
+ "TCP dontroute can't clear SO_DONTROUTE",
+ ck_errstr(),
+ errno
+ );
+ tcp_dontroute = get_dontroute_opt;
+ } else {
+ debug(F101,
+ "TCP dontroute new SO_DONTROUTE",
+ "",
+ set_dontroute_opt
+ );
+ tcp_dontroute = onoff;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
+ "",
+ get_dontroute_opt
+ );
+ tcp_dontroute = onoff;
+ return 1;
+ }
+#else
+ debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
+#endif /* SO_DONTROUTE */
+#else
+ debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
+#endif /* SOL_SOCKET */
+ return(0);
+}
+
+int
+no_delay(sock,onoff) int sock; int onoff; {
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+ int get_nodelay_opt;
+ int set_nodelay_opt;
+ SOCKOPT_T x;
+
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ if (sock == -1 ||
+ nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
+ || ttmdm >= 0) {
+ tcp_nodelay = onoff;
+ return(1);
+ }
+ x = sizeof(get_nodelay_opt);
+ if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
+ (char *)&get_nodelay_opt,&x)) {
+ debug(F111,
+ "TCP no_delay can't get TCP_NODELAY",
+ ck_errstr(),
+ errno);
+ } else if (x != sizeof(get_nodelay_opt)) {
+#ifdef OS2
+ short get_nodelay_opt16;
+ short set_nodelay_opt16;
+ if (x == sizeof(get_nodelay_opt16)) {
+ debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
+ if (getsockopt(sock,
+ IPPROTO_TCP, TCP_NODELAY,
+ (char *)&get_nodelay_opt16, &x)
+ ) {
+ debug(F111,
+ "TCP no_delay can't get TCP_NODELAY",
+ ck_errstr(),
+ errno);
+ } else if (get_nodelay_opt16 != onoff) {
+ set_nodelay_opt16 = onoff;
+ if (setsockopt(sock,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (char *)&set_nodelay_opt16,
+ sizeof(set_nodelay_opt16))
+ ) {
+ debug(F111,
+ "TCP no_delay can't clear TCP_NODELAY",
+ ck_errstr(),
+ errno);
+ tcp_nodelay = get_nodelay_opt16;
+ } else {
+ debug(F101,
+ "TCP no_delay new TCP_NODELAY",
+ "",
+ set_nodelay_opt16);
+ tcp_nodelay = onoff;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
+ get_nodelay_opt16);
+ tcp_nodelay = onoff;
+ return 1;
+ }
+ return(0);
+ }
+#endif /* OS2 */
+ debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
+ debug(F111,"TCP no_delay TCP_NODELAY","expected len",
+ sizeof(get_nodelay_opt));
+ debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
+ } else if (get_nodelay_opt != onoff) {
+ set_nodelay_opt = onoff;
+ if (setsockopt(sock,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (char *)&set_nodelay_opt,
+ sizeof(set_nodelay_opt))) {
+ debug(F111,
+ "TCP no_delay can't clear TCP_NODELAY",
+ ck_errstr(),
+ errno
+ );
+ tcp_nodelay = get_nodelay_opt;
+ } else {
+ debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
+ tcp_nodelay = onoff;
+ return 1;
+ }
+ } else {
+ debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
+ tcp_nodelay = onoff;
+ return(1);
+ }
+#else
+ debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
+#endif /* TCP_NODELAY */
+#else
+ debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
+#endif /* SOL_SOCKET */
+ return 0;
+}
+#endif /* datageneral */
+#endif /* NOTCPOPTS */
+
+#ifdef SUNX25
+#ifndef X25_WR_FACILITY
+/* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
+void
+bzero(s,n) char *s; int n; {
+ memset(s,0,n);
+}
+#endif /* X25_WR_FACILITY */
+#endif /* SUNX25 */
+
+#ifdef TCPSOCKET
+#ifndef OS2
+#ifndef NOLISTEN
+
+#ifdef BSDSELECT
+#ifndef VMS
+#ifndef BELLV10
+#ifndef datageneral
+#ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */
+#include <time.h>
+#else
+
+/****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
+* ------------------------------------------------------
+*
+* Due to OS9's Lack of a select() call, the following seems to be
+* enough to fool the rest of the code into compiling. The only
+* effect that I can see is using control L to refresh the status
+* display gets qued up until some network packets arrive.
+*
+* This solution is by no means elegant but works enough to be
+* a (the) solution.
+*
+* Also with the defines I had specified in my makefile I had to
+* have an #endif right at the end of the file when compiling.
+* I did not bother speding time to find out why.
+*
+* COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
+* -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
+* -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
+* -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
+* -l=termlib.l -l=math.l -l=sys_clib.l
+*
+* stever@ozemail.com.au
+*/
+
+#ifdef OSK
+#define BSDSELECT /* switch on BSD select code */
+#define FD_SETSIZE 32 /* Max # of paths in OS9 */
+#define FD_ZERO(p) ((*p)=0)
+#define FD_SET(n,b) ((*b)|=(1<<(n)))
+#define FD_ISSET(n,b) 1 /* always say data is ready */
+#define select(a,b,c,d,e) 1 /* always say 1 path has data */
+typedef int fd_set; /* keep BSD Code Happy */
+struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */
+
+/****** END OF OS9 MODS FROM STEVE RANCE **************************/
+#endif /* OSK */
+
+#include <sys/time.h>
+#endif /* hp9000s500 */
+#endif /* datageneral */
+#endif /* BELLV10 */
+#endif /* VMS */
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* BSDSELECT */
+
+#ifdef SELECT
+#ifdef CK_SCOV5
+#include <sys/select.h>
+#endif /* CK_SCOV5 */
+#endif /* SELECT */
+
+#ifdef NOTUSED
+/* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
+
+int
+tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
+ int on = 1;
+ static struct servent *service, servrec;
+ static struct hostent *host;
+ static struct sockaddr_in saddr;
+ static
+#ifdef UCX50
+ unsigned
+#endif /* UCX50 */
+ int saddrlen;
+#ifdef BSDSELECT
+ fd_set rfds;
+ struct timeval tv;
+#else
+#ifdef BELLSELECT
+ fd_set rfds;
+#else
+ fd_set rfds;
+ fd_set rfds;
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+ } tv;
+#endif /* BELLSELECT */
+#endif /* BSDSELECT */
+
+ debug(F101,"tcpsocket_open nett","",nett);
+ *ipaddr = '\0';
+
+ if (nett != NET_TCPB)
+ return(-1); /* BSD socket support */
+
+ netclos(); /* Close any previous connection. */
+ ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
+#ifdef COMMENT
+ /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */
+ if (ttnproto != NP_TCPRAW &&
+ ttnproto != NP_SSL_RAW &&
+ ttnproto != NP_TLS_RAW)
+ ttnproto = NP_NONE; /* No protocol selected yet. */
+#else
+ /* fdc's version from 4 Dec 2005 works ok */
+ if (ttnproto != NP_TCPRAW)
+ ttnproto = NP_NONE; /* No protocol selected yet. */
+#endif /* COMMENT */
+ debug(F110,"tcpsocket_open namecopy",namecopy,0);
+
+ /* Assign the socket number to ttyfd and then fill in tcp structures */
+ ttyfd = atoi(&name[1]);
+ debug(F111,"tcpsocket_open","ttyfd",ttyfd);
+
+#ifndef NOTCPOPTS
+#ifdef SOL_SOCKET
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+
+#ifndef datageneral
+#ifdef TCP_NODELAY
+ no_delay(ttyfd,tcp_nodelay);
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+ keepalive(ttyfd,tcp_keepalive);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
+#endif /* SO_LINGER */
+#ifdef SO_SNDBUF
+ sendbuf(ttyfd,tcp_sendbuf);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ recvbuf(ttyfd,tcp_recvbuf);
+#endif /* SO_RCVBUF */
+#endif /* datageneral */
+#endif /* SOL_SOCKET */
+#endif /* NOTCPOPTS */
+
+#ifdef NT_TCP_OVERLAPPED
+ OverlappedWriteInit();
+ OverlappedReadInit();
+#endif /* NT_TCP_OVERLAPPED */
+
+
+ /* Get the name of the host we are connected to */
+
+ saddrlen = sizeof(saddr);
+ getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
+
+ ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
+
+ if (tcp_rdns == SET_ON
+#ifdef CK_KERBEROS
+ || tcp_rdns == SET_AUTO &&
+ (ck_krb5_is_installed() || ck_krb4_is_installed())
+#endif /* CK_KERBEROS */
+#ifndef NOHTTP
+ && (tcp_http_proxy == NULL)
+#endif /* NOHTTP */
+#ifdef CK_SSL
+ && !(ssl_only_flag || tls_only_flag)
+#endif /* CK_SSL */
+ ) { /* Reverse DNS */
+ if (!quiet) {
+ printf(" Reverse DNS Lookup... ");
+ fflush(stdout);
+ }
+ host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
+ debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
+ if (host) {
+ host = ck_copyhostent(host);
+ debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
+ if (!quiet) {
+ printf("(OK)\n");
+ fflush(stdout);
+ }
+ ckstrncpy(name, host->h_name, 80);
+ ckstrncat(name, ":", 80);
+ ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
+ if (!quiet
+#ifndef NOICP
+ && !doconx
+#endif /* NOICP */
+ )
+ printf("%s connected on port %d\n",
+ host->h_name,
+ ntohs(saddr.sin_port)
+ );
+ } else if (!quiet)
+ printf("Failed\n");
+ } else if (!quiet)
+ printf("(OK)\n");
+
+ if (tcp_rdns != SET_ON || !host) {
+ ckstrncpy(name,ipaddr,80);
+ ckstrncat(name,":",80);
+ ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
+ if (!quiet
+#ifdef NOICP
+ && !doconx
+#endif /* NOICP */
+ )
+ printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
+ }
+ if (!quiet) fflush(stdout);
+ ttnet = nett; /* TCP/IP (sockets) network */
+
+#ifdef RLOGCODE
+ if (ntohs(saddr.sin_port) == 513)
+ ttnproto = NP_LOGIN;
+ else
+#endif /* RLOGCODE */
+ /* Assume the service is TELNET. */
+#ifdef COMMENT
+ /* Jeff's code from 2005/12/30 */
+ if (ttnproto != NP_TCP_RAW &&
+ ttnproto != NP_SSL_RAW &&
+ ttnproto != NP_TLS_RAW)
+#else
+ /* fdc's code from 2005/12/04 */
+ if (ttnproto != NP_TCPRAW)
+#endif /* COMMENT */
+ ttnproto = NP_TELNET; /* Yes, set global flag. */
+#ifdef CK_SECURITY
+ /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
+ ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
+ host->h_name : ipaddr,
+ ipaddr,
+ uidbuf,
+ ttyfd
+ );
+#endif /* CK_SECURITY */
+ if (tn_ini() < 0) /* Start/Reset TELNET negotiations */
+ if (ttchk() < 0) /* Did it fail due to connect loss? */
+ return(-1);
+
+ if (*lcl < 0) *lcl = 1; /* Local mode. */
+
+ return(0); /* Done. */
+}
+#endif /* NOTUSED */
+
+/* T C P S R V _ O P E N -- Open a TCP/IP Server connection */
+/*
+ Calling conventions same as ttopen(), except third argument is network
+ type rather than modem type.
+*/
+int
+tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
+ char *p;
+ int i, x;
+ SOCKOPT_T on = 1;
+ int ready_to_accept = 0;
+ static struct servent *service, *service2, servrec;
+ static struct hostent *host;
+ static struct sockaddr_in saddr;
+ struct sockaddr_in l_addr;
+ GSOCKNAME_T l_slen;
+#ifdef UCX50
+ static u_int saddrlen;
+#else
+ static SOCKOPT_T saddrlen;
+#endif /* UCX50 */
+
+#ifdef BSDSELECT
+ fd_set rfds;
+ struct timeval tv;
+#else
+#ifdef BELLSELCT
+ fd_set rfds;
+#else
+ fd_set rfds;
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+ } tv;
+#endif /* BELLSELECT */
+#endif /* BSDSELECT */
+#ifdef CK_SSL
+ int ssl_failed = 0;
+#endif /* CK_SSL */
+
+ debug(F101,"tcpsrv_open nett","",nett);
+ *ipaddr = '\0';
+
+ if (nett != NET_TCPB)
+ return(-1); /* BSD socket support */
+
+ netclos(); /* Close any previous connection. */
+ ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
+ /* Don't do this. */
+#ifdef COMMENT
+ /* fdc */
+ if (ttnproto != NP_TCPRAW)
+ ttnproto = NP_NONE; /* No protocol selected yet. */
+#endif /* COMMENT */
+#ifdef COMMENT
+ /* Jeff */
+ if (ttnproto != NP_TCP_RAW &&
+ ttnproto != NP_SSL_RAW &&
+ ttnproto != NP_TLS_RAW)
+ ttnproto = NP_NONE; /* No protocol selected yet. */
+#endif /* COMMENT */
+ debug(F110,"tcpsrv_open namecopy",namecopy,0);
+
+ p = namecopy; /* Was a service requested? */
+ while (*p != '\0' && *p != ':')
+ p++; /* Look for colon */
+ if (*p == ':') { /* Have a colon */
+ *p++ = '\0'; /* Get service name or number */
+ } else { /* Otherwise use kermit */
+ p = "kermit";
+ }
+ debug(F110,"tcpsrv_open service requested",p,0);
+ if (isdigit(*p)) { /* Use socket number without lookup */
+ service = &servrec;
+ service->s_port = htons((unsigned short)atoi(p));
+ } else { /* Otherwise lookup the service name */
+ service = getservbyname(p, "tcp");
+ }
+ if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
+ service = &servrec;
+ service->s_port = htons(1649);
+ }
+#ifdef RLOGCODE
+ if (service && !strcmp("login",p) && service->s_port != htons(513)) {
+ fprintf(stderr,
+ " Warning: login service on port %d instead of port 513\n",
+ ntohs(service->s_port));
+ fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
+ debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
+ }
+#endif /* RLOGCODE */
+ if (!service) {
+ fprintf(stderr, "Cannot find port for service: %s\n", p);
+ debug(F111,"tcpsrv_open can't get service",p,errno);
+ errno = 0; /* rather than mislead */
+ return(-1);
+ }
+
+ /* If we currently have a listen active but port has changed then close */
+
+ debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
+ debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
+ if (tcpsrfd != -1 &&
+ tcpsrv_port != ntohs((unsigned short)service->s_port)) {
+ debug(F100,"tcpsrv_open closing previous connection","",0);
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ tcpsrfd = -1;
+ }
+ debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
+ if (tcpsrfd == -1) {
+
+ /* Set up socket structure and get host address */
+
+ bzero((char *)&saddr, sizeof(saddr));
+ debug(F100,"tcpsrv_open bzero ok","",0);
+ saddr.sin_family = AF_INET;
+ if (tcp_address) {
+#ifdef INADDRX
+ inaddrx = inet_addr(tcp_address);
+ saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
+#else
+ saddr.sin_addr.s_addr = inet_addr(tcp_address);
+#endif /* INADDRX */
+ } else
+ saddr.sin_addr.s_addr = INADDR_ANY;
+
+ /* Get a file descriptor for the connection. */
+
+ saddr.sin_port = service->s_port;
+ ipaddr[0] = '\0';
+
+ debug(F100,"tcpsrv_open calling socket","",0);
+ if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("TCP socket error");
+ debug(F101,"tcpsrv_open socket error","",errno);
+ return (-1);
+ }
+ errno = 0;
+
+ /* Specify the Port may be reused */
+
+ debug(F100,"tcpsrv_open calling setsockopt","",0);
+ x = setsockopt(tcpsrfd,
+ SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
+ debug(F101,"tcpsrv_open setsockopt","",x);
+
+ /* Now bind to the socket */
+ printf("\nBinding socket to port %d ...\n",
+ ntohs((unsigned short)service->s_port));
+ if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ i = errno; /* Save error code */
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ ttyfd = -1;
+ wasclosed = 1;
+ errno = i; /* and report this error */
+ debug(F101,"tcpsrv_open bind errno","",errno);
+ printf("?Unable to bind to socket (errno = %d)\n",errno);
+ return(-1);
+ }
+ debug(F100,"tcpsrv_open bind OK","",0);
+ printf("Listening ...\n");
+ if (listen(tcpsrfd, 15) < 0) {
+ i = errno; /* Save error code */
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ ttyfd = -1;
+ wasclosed = 1;
+ errno = i; /* And report this error */
+ debug(F101,"tcpsrv_open listen errno","",errno);
+ return(-1);
+ }
+ debug(F100,"tcpsrv_open listen OK","",0);
+ tcpsrv_port = ntohs((unsigned short)service->s_port);
+ }
+
+#ifdef CK_SSL
+ if (ck_ssleay_is_installed()) {
+ if (!ssl_tn_init(SSL_SERVER)) {
+ ssl_failed = 1;
+ if (bio_err!=NULL) {
+ BIO_printf(bio_err,"do_ssleay_init() failed\n");
+ ERR_print_errors(bio_err);
+ } else {
+ fflush(stderr);
+ fprintf(stderr,"do_ssleay_init() failed\n");
+ ERR_print_errors_fp(stderr);
+ }
+ if (tls_only_flag || ssl_only_flag) {
+#ifdef TCPIPLIB
+ socket_close(ttyfd);
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(ttyfd);
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ return(-1);
+ }
+ /* we will continue to accept the connection */
+ /* without SSL or TLS support unless required. */
+ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ }
+ }
+#endif /* CK_SSL */
+
+ printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
+ ntohs((unsigned short)service->s_port));
+ saddrlen = sizeof(saddr);
+
+#ifdef BSDSELECT
+ tv.tv_sec = tv.tv_usec = 0L;
+ if (timo < 0)
+ tv.tv_usec = (long) -timo * 10000L;
+ else
+ tv.tv_sec = timo;
+ debug(F101,"tcpsrv_open BSDSELECT","",timo);
+#else
+ debug(F101,"tcpsrv_open not BSDSELECT","",timo);
+#endif /* BSDSELECT */
+
+ if (timo) {
+ while (!ready_to_accept) {
+#ifdef BSDSELECT
+ FD_ZERO(&rfds);
+ FD_SET(tcpsrfd, &rfds);
+ ready_to_accept =
+ ((select(FD_SETSIZE,
+#ifdef HPUX
+#ifdef HPUX1010
+ (fd_set *)
+#else
+
+ (int *)
+#endif /* HPUX1010 */
+#else
+#ifdef __DECC
+#ifdef INTSELECT
+ (int *)
+#else /* def INTSELECT */
+ (fd_set *)
+#endif /* def INTSELECT [else] */
+#endif /* __DECC */
+#endif /* HPUX */
+ &rfds, NULL, NULL, &tv) > 0) &&
+ FD_ISSET(tcpsrfd, &rfds));
+#else /* BSDSELECT */
+#ifdef IBMSELECT
+#define ck_sleepint 250
+ ready_to_accept =
+ (select(&tcpsrfd, 1, 0, 0,
+ timo < 0 ? -timo :
+ (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
+ );
+#else
+#ifdef BELLSELECT
+ FD_ZERO(rfds);
+ FD_SET(tcpsrfd, rfds);
+ ready_to_accept =
+ ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
+ (timo > 0 ? timo * 1000L)) > 0) &&
+ FD_ISSET(tcpsrfd, rfds));
+#else
+/* Try this - what's the worst that can happen... */
+
+ FD_ZERO(&rfds);
+ FD_SET(tcpsrfd, &rfds);
+ ready_to_accept =
+ ((select(FD_SETSIZE,
+ (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
+ FD_ISSET(tcpsrfd, &rfds));
+
+#endif /* BELLSELECT */
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+ }
+ }
+ if (ready_to_accept || timo == 0) {
+ if ((ttyfd = accept(tcpsrfd,
+ (struct sockaddr *)&saddr,&saddrlen)) < 0) {
+ i = errno; /* save error code */
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ errno = i; /* and report this error */
+ debug(F101,"tcpsrv_open accept errno","",errno);
+ return(-1);
+ }
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+ no_delay(ttyfd,tcp_nodelay);
+ debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+ keepalive(ttyfd,tcp_keepalive);
+ debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
+ debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
+#endif /* SO_LINGER */
+#ifdef SO_SNDBUF
+ sendbuf(ttyfd,tcp_sendbuf);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ recvbuf(ttyfd,tcp_recvbuf);
+#endif /* SO_RCVBUF */
+#endif /* SOL_SOCKET */
+#endif /* datageneral */
+#endif /* NOTCPOPTS */
+
+ ttnet = nett; /* TCP/IP (sockets) network */
+ tcp_incoming = 1; /* This is an incoming connection */
+ sstelnet = 1; /* Do server-side Telnet protocol */
+
+ /* See if the service is TELNET. */
+ x = (unsigned short)service->s_port;
+ service2 = getservbyname("telnet", "tcp");
+ if (service2 && x == service2->s_port) {
+#ifdef COMMENT
+ /* Jeff 2005/12/30 */
+ if (ttnproto != NP_TCPRAW && /* Yes... */
+ ttnproto != NP_SSL_RAW &&
+ ttnproto != NP_TLS_RAW) /* and if raw port not requested */
+#else
+ /* fdc 2005/12/04 */
+ if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */
+#endif /* */
+ ttnproto = NP_TELNET; /* set protocol to TELNET. */
+ }
+ ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
+ if (tcp_rdns) {
+ if (!quiet) {
+ printf(" Reverse DNS Lookup... ");
+ fflush(stdout);
+ }
+ if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
+ host = ck_copyhostent(host);
+ debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
+ if (!quiet) {
+ printf("(OK)\n");
+ fflush(stdout);
+ }
+ name[0] = '*';
+ ckstrncpy(&name[1],host->h_name,78);
+ ckstrncat(name,":",80-strlen(name));
+ ckstrncat(name,p,80-strlen(name));
+ if (!quiet
+#ifndef NOICP
+ && !doconx
+#endif /* NOICP */
+ )
+ printf("%s connected on port %s\n",host->h_name,p);
+ } else {
+ if (!quiet) printf("Failed.\n");
+ }
+ } else if (!quiet) printf("(OK)\n");
+
+ if (!tcp_rdns || !host) {
+ ckstrncpy(name,ipaddr,80);
+ ckstrncat(name,":",80);
+ ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
+ if (!quiet
+#ifndef NOICP
+ && !doconx
+#endif /* NOICP */
+ )
+ printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
+ }
+ if (!quiet) fflush(stdout);
+
+#ifdef CK_SECURITY
+ /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
+ ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
+ (char *)host->h_name : ipaddr,
+ ipaddr,
+ uidbuf,
+ ttyfd
+ );
+#endif /* CK_SECURITY */
+
+#ifdef CK_SSL
+ if (ck_ssleay_is_installed() && !ssl_failed) {
+ if (ck_ssl_incoming(ttyfd) < 0) {
+#ifdef TCPIPLIB
+ socket_close(ttyfd);
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(ttyfd);
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ return(-1);
+ }
+ }
+#endif /* CK_SSL */
+
+#ifndef datageneral
+ /* Find out our own IP address. */
+ l_slen = sizeof(l_addr);
+ bzero((char *)&l_addr, l_slen);
+#ifndef EXCELAN
+ if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
+ char * s = (char *)inet_ntoa(l_addr.sin_addr);
+ ckstrncpy(myipaddr, s,20);
+ debug(F110,"getsockname",myipaddr,0);
+ }
+#endif /* EXCELAN */
+#endif /* datageneral */
+
+ if (tn_ini() < 0) /* Start TELNET negotiations. */
+ if (ttchk() < 0) { /* Disconnected? */
+ i = errno; /* save error code */
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ errno = i; /* and report this error */
+ debug(F101,"tcpsrv_open accept errno","",errno);
+ return(-1);
+ }
+ debug(F101,"tcpsrv_open service","",x);
+ if (*lcl < 0) /* Set local mode. */
+ *lcl = 1;
+
+#ifdef CK_KERBEROS
+#ifdef KRB5_U2U
+ if ( ttnproto == NP_K5U2U ) {
+ if (k5_user_to_user_server_auth() != 0) {
+ i = errno; /* save error code */
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ errno = i; /* and report this error */
+ debug(F101,"tcpsrv_open accept errno","",errno);
+ return(-1);
+ }
+ }
+#endif /* KRB5_U2U */
+#endif /* CK_KERBEROS */
+ return(0); /* Done. */
+ } else {
+ i = errno; /* save error code */
+#ifdef TCPIPLIB
+ socket_close(tcpsrfd);
+#else /* TCPIPLIB */
+ close(tcpsrfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ tcpsrfd = -1;
+ tcpsrv_port = 0;
+ errno = i; /* and report this error */
+ debug(F101,"tcpsrv_open accept errno","",errno);
+ return(-1);
+ }
+}
+#endif /* NOLISTEN */
+#endif /* OS2 */
+#endif /* TCPSOCKET */
+#endif /* NONET */
+
+#ifdef TCPSOCKET
+char *
+ckname2addr(name) char * name;
+{
+#ifdef HPUX5
+ return("");
+#else
+ struct hostent *host;
+
+ if (name == NULL || *name == '\0')
+ return("");
+
+ host = gethostbyname(name);
+ if ( host ) {
+ host = ck_copyhostent(host);
+ return(inet_ntoa(*((struct in_addr *) host->h_addr)));
+ }
+ return("");
+#endif /* HPUX5 */
+}
+
+char *
+ckaddr2name(addr) char * addr;
+{
+#ifdef HPUX5
+ return("");
+#else
+ struct hostent *host;
+ struct in_addr sin_addr;
+
+ if (addr == NULL || *addr == '\0')
+ return("");
+
+ sin_addr.s_addr = inet_addr(addr);
+ host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
+ if (host) {
+ host = ck_copyhostent(host);
+ return((char *)host->h_name);
+ }
+ return("");
+#endif /* HPUX5 */
+}
+#endif /* TCPSOCKET */
+
+unsigned long peerxipaddr = 0L;
+
+char *
+ckgetpeer() {
+#ifdef TCPSOCKET
+ static char namebuf[256];
+ static struct hostent *host;
+ static struct sockaddr_in saddr;
+#ifdef GPEERNAME_T
+ static GPEERNAME_T saddrlen;
+#else
+#ifdef PTX
+ static size_t saddrlen;
+#else
+#ifdef AIX42
+ /* It's size_t in 4.2 but int in 4.1 and earlier. */
+ /* Note: the 4.2 man page lies; believe socket.h. */
+ static size_t saddrlen;
+#else
+#ifdef UNIXWARE
+ static size_t saddrlen;
+#else /* UNIXWARE */
+#ifdef DEC_TCPIP
+/* 2010-03-08 SMS.
+ * Coincidentally, the condition for integer arguments in select(),
+ * which is actually "defined( _DECC_V4_SOURCE)", works for an integer
+ * argument in getpeername(). Sadly, due to a lack of foresight,
+ * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the
+ * user-specified INTSELECT is used instead. Most likely, "size_t"
+ * should be used instead of "unsigned int", but I'm a coward.
+ */
+#ifdef INTSELECT
+ static int saddrlen;
+#else /* def INTSELECT */
+ static unsigned int saddrlen;
+#endif /* def INTSELECT [else] */
+#else
+#ifdef MACOSX10
+ static unsigned int saddrlen;
+#else
+#ifdef CK_64BIT
+ static socklen_t saddrlen;
+#else
+ static int saddrlen;
+#endif /* CK_64BIT */
+#endif /* MACOSX10 */
+#endif /* DEC_TCPIP */
+#endif /* UNIXWARE */
+#endif /* AIX42 */
+#endif /* PTX */
+#endif /* GPEERNAME_T */
+ saddrlen = sizeof(saddr);
+ if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
+ debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
+ return(NULL);
+ }
+ host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
+ if (host) {
+ host = ck_copyhostent(host);
+ ckstrncpy(namebuf,(char *)host->h_name,80);
+ } else {
+ ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
+ }
+ peerxipaddr = ntohl(saddr.sin_addr.s_addr);
+ debug(F111,"ckgetpeer",namebuf,peerxipaddr);
+ return(namebuf);
+#else
+ return(NULL);
+#endif /* TCPSOCKET */
+}
+
+/* Get fully qualified IP hostname */
+
+#ifndef NONET
+char *
+#ifdef CK_ANSIC
+ckgetfqhostname(char * name)
+#else
+ckgetfqhostname(name) char * name;
+#endif /* CK_ANSIC */
+{
+#ifdef NOCKGETFQHOST
+
+ return(name);
+
+#else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
+
+ static char namebuf[256];
+ struct hostent *host=NULL;
+ struct sockaddr_in r_addr;
+ int i;
+
+ debug(F110,"ckgetfqhn()",name,0);
+
+ ckstrncpy(namebuf,name,256);
+ namebuf[255] = '\0';
+ i = ckindex(":",namebuf,0,0,0);
+ if (i)
+ namebuf[i-1] = '\0';
+
+ bzero((char *)&r_addr, sizeof(r_addr));
+
+ host = gethostbyname(namebuf);
+ if (host) {
+ host = ck_copyhostent(host);
+ debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
+ r_addr.sin_family = host->h_addrtype;
+#ifdef HADDRLIST
+#ifdef h_addr
+ /* This is for trying multiple IP addresses - see <netdb.h> */
+ if (!(host->h_addr_list))
+ goto exit_func;
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&r_addr.sin_addr,
+ host->h_length
+ );
+#else
+ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
+#endif /* h_addr */
+#else /* HADDRLIST */
+ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
+#endif /* HADDRLIST */
+#ifdef COMMENT
+#ifndef EXCELAN
+ debug(F111,"BCOPY","host->h_addr",host->h_addr);
+#endif /* EXCELAN */
+ debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
+ (caddr_t)&r_addr.sin_addr);
+#endif /* COMMENT */
+ debug(F111,"BCOPY","host->h_length",host->h_length);
+
+#ifdef NT
+ /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
+ /* provided DNS functions. Otherwise, the TTL of the DNS response */
+ /* is ignored. */
+ if (isWin95())
+ sleep(1);
+#endif /* NT */
+ host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
+ if (host) {
+ host = ck_copyhostent(host);
+ debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
+ ckstrncpy(namebuf, host->h_name, 256);
+ }
+ }
+
+#ifdef HADDRLIST
+#ifdef h_addr
+ exit_func:
+#endif /* h_addr */
+#endif /* HADDRLIST */
+
+ if (i > 0)
+ ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
+ debug(F110,"ckgetfqhn()",namebuf,0);
+ return(namebuf);
+#endif /* NOCKGETFQHOST */
+}
+
+VOID
+#ifdef CK_ANSIC
+setnproto(char * p)
+#else
+setnproto(p) char * p;
+#endif /* CK_ANSIC */
+{
+ if (!isdigit(*p)) {
+ if (!strcmp("kermit",p))
+ ttnproto = NP_KERMIT;
+ else if (!strcmp("telnet",p))
+ ttnproto = NP_TELNET;
+ else if (!strcmp("http",p))
+ ttnproto = NP_TCPRAW;
+#ifdef RLOGCODE
+ else if (!strcmp("login",p))
+ ttnproto = NP_RLOGIN;
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ /* Commonly used SSL ports (might not be in services file) */
+ else if (!strcmp("https",p)) {
+ ttnproto = NP_SSL_RAW;
+ ssl_only_flag = 1;
+ } else if (!strcmp("ssl-telnet",p)) {
+ ttnproto = NP_TELNET;
+ ssl_only_flag = 1;
+ } else if (!strcmp("telnets",p)) {
+ ttnproto = NP_TELNET;
+ ssl_only_flag = 1;
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+ else if (!strcmp("klogin",p)) {
+ if (ck_krb5_is_installed())
+ ttnproto = NP_K5LOGIN;
+ else if (ck_krb4_is_installed())
+ ttnproto = NP_K4LOGIN;
+ else
+ ttnproto = NP_RLOGIN;
+ } else if (!strcmp("eklogin",p)) {
+ if (ck_krb5_is_installed())
+ ttnproto = NP_EK5LOGIN;
+ else if (ck_krb4_is_installed())
+ ttnproto = NP_EK4LOGIN;
+ else
+ ttnproto = NP_RLOGIN;
+ }
+#endif /* RLOGCODE */
+#endif /* CK_KERBEROS */
+ else
+ ttnproto = NP_NONE;
+ } else {
+ switch (atoi(p)) {
+ case 23: /* Telnet */
+ ttnproto = NP_TELNET;
+ break;
+ case 513:
+ ttnproto = NP_RLOGIN;
+ break;
+ case 1649:
+ ttnproto = NP_KERMIT;
+ break;
+#ifdef CK_SSL
+ case 443:
+#ifdef COMMENT
+ /* Jeff 2005/12/30 */
+ ttnproto = NP_SSL_RAW;
+#else
+ /* fdc 2005/12/04 */
+ ttnproto = NP_SSL;
+#endif /* COMMENT */
+ ssl_only_flag = 1;
+ break;
+ case 151:
+ case 992:
+ ttnproto = NP_TELNET;
+ ssl_only_flag = 1;
+ break;
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+ case 543:
+ if (ck_krb5_is_installed())
+ ttnproto = NP_K5LOGIN;
+ else if (ck_krb4_is_installed())
+ ttnproto = NP_K4LOGIN;
+ else
+ ttnproto = NP_RLOGIN;
+ break;
+ case 2105:
+ if (ck_krb5_is_installed())
+ ttnproto = NP_EK5LOGIN;
+ else if (ck_krb4_is_installed())
+ ttnproto = NP_EK4LOGIN;
+ else
+ ttnproto = NP_RLOGIN;
+ break;
+#endif /* CK_KERBEROS */
+ case 80: /* HTTP */
+ ttnproto = NP_TCPRAW;
+ break;
+ default:
+ ttnproto = NP_NONE;
+ break;
+ }
+ }
+}
+
+/* ckgetservice() is used to determine the port number for a given */
+/* service taking into account the use of DNS SRV records. */
+
+static struct servent servrec;
+static struct servent *
+ckgetservice(hostname, servicename, ip, iplen)
+ char *hostname; char * servicename; char * ip; int iplen;
+{
+ struct servent * service = NULL;
+#ifdef CK_DNS_SRV
+ struct sockaddr * dns_addrs = NULL;
+ int dns_naddrs = 0;
+#endif /* CK_DNS_SRV */
+
+ if (isdigit(*servicename)) { /* Use socket number without lookup */
+ service = &servrec;
+ service->s_port = htons((unsigned short)atoi(servicename));
+ } else { /* Otherwise lookup the service name */
+#ifdef CK_DNS_SRV
+ if (tcp_dns_srv && !quiet) {
+ printf(" DNS SRV Lookup... ");
+ fflush(stdout);
+ }
+ if (tcp_dns_srv &&
+ locate_srv_dns(hostname,
+ servicename,
+ "tcp",
+ &dns_addrs,
+ &dns_naddrs
+ )
+ ) {
+ /* Use the first one. Eventually we should cycle through all */
+ /* the returned IP addresses and port numbers. */
+ struct sockaddr_in *sin = NULL;
+#ifdef BETADEBUG
+ int i;
+ printf("\r\n");
+ for ( i=0;i<dns_naddrs;i++ ) {
+ sin = (struct sockaddr_in *) &dns_addrs[i];
+ printf("dns_addrs[%d] = %s %d\r\n", i,
+ (char *)inet_ntoa(sin->sin_addr),
+ ntohs(sin->sin_port));
+ }
+#endif /* BETADEBUG */
+ sin = (struct sockaddr_in *) &dns_addrs[0];
+ if ( ip && iplen > 0 )
+ ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
+ service = &servrec;
+ service->s_port = sin->sin_port;
+
+ free(dns_addrs);
+ dns_addrs = NULL;
+ dns_naddrs = 0;
+ } else
+#endif /* CK_DNS_SRV */
+ service = getservbyname(servicename, "tcp");
+ }
+ if (!service) {
+ if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
+ service = &servrec;
+ service->s_port = htons(1649);
+ } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
+ service = &servrec;
+ service->s_port = htons(23);
+ } else if (!ckstrcmp("http",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(80);
+ }
+#ifdef RLOGCODE
+ else if (!ckstrcmp("login",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(513);
+ }
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ /* Commonly used SSL ports (might not be in services file) */
+ else if (!ckstrcmp("https",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(443);
+ } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(151);
+ } else if (!ckstrcmp("telnets",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(992);
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+ else if (!ckstrcmp("klogin",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(543);
+ } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
+ service = &servrec;
+ service->s_port = htons(2105);
+ }
+#endif /* RLOGCODE */
+#endif /* CK_KERBEROS */
+ }
+ return(service);
+}
+
+/* N E T O P E N -- Open a network connection */
+/*
+ Calling conventions same as ttopen(), except third argument is network
+ type rather than modem type. Designed to be called from within ttopen.
+*/
+
+#define XXNAMELEN 256
+static char xxname[XXNAMELEN];
+
+int
+netopen(name, lcl, nett) char *name; int *lcl, nett; {
+ char *p;
+ int i, x, rc_inet_addr = 0, dns = 0;
+#ifdef TCPSOCKET
+ int isconnect = 0;
+#ifdef SO_OOBINLINE
+ int on = 1;
+#endif /* SO_OOBINLINE */
+ struct servent *service=NULL;
+ struct hostent *host=NULL;
+ struct sockaddr_in r_addr;
+ struct sockaddr_in sin;
+ struct sockaddr_in l_addr;
+ GSOCKNAME_T l_slen;
+#ifdef EXCELAN
+ struct sockaddr_in send_socket;
+#endif /* EXCELAN */
+
+#ifdef INADDRX
+/* inet_addr() is of type struct in_addr */
+#ifdef datageneral
+ extern struct in_addr inet_addr();
+#else
+#ifdef HPUX5WINTCP
+ extern struct in_addr inet_addr();
+#endif /* HPUX5WINTCP */
+#endif /* datageneral */
+ struct in_addr iax;
+#else
+#ifdef INADDR_NONE
+ struct in_addr iax;
+#else /* INADDR_NONE */
+ long iax;
+#endif /* INADDR_NONE */
+#endif /* INADDRX */
+#endif /* TCPSOCKET */
+
+#ifdef COMMENT
+/* This causes big trouble */
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif /* INADDR_NONE */
+#endif /* COMMENT */
+
+#ifdef SUNX25 /* Code for SunLink X.25 support */
+#define X29PID 1 /* X.29 Protocol ID */
+_PROTOTYP(SIGTYP x25oobh, (int) );
+ CONN_DB x25host;
+#ifndef X25_WR_FACILITY
+ FACILITY x25facil;
+#else
+ FACILITY_DB x25facil;
+#endif /* X25_WR_FACILITY */
+ static int needh = 1;
+ PID_T pid;
+ extern int linkid, lcn, x25ver;
+#endif /* SUNX25 */
+#ifdef ANYX25
+ extern int revcall, closgr, cudata;
+ extern char udata[];
+#endif /* ANYX25 */
+
+#ifdef IBMX25 /* Variables for IBM X25 */
+ extern int x25port; /* Logical port to use */
+ extern x25addr_t local_nua; /* Local X.25 address */
+ extern x25addr_t remote_nua; /* Remote X.25 address */
+ extern char x25name[]; /* X25 device name (sx25a0) */
+ extern char x25dev[]; /* X25 device file /dev/x25pkt */
+ ulong bind_flags = 0; /* Flags for binding the X25 stream */
+ ulong token = 0; /* Temporary return code */
+#endif /* IBMX25 */
+
+ debug(F101,"netopen nett","",nett);
+ *ipaddr = '\0'; /* Initialize IP address string */
+
+#ifdef SUNX25
+ if (nett == NET_SX25) { /* If network type is X.25 */
+ netclos(); /* Close any previous net connection */
+ ttnproto = NP_NONE; /* No protocol selected yet */
+
+ /* Set up host structure */
+ bzero((char *)&x25host,sizeof(x25host));
+ if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
+ fprintf (stderr,"Invalid X.121 host address %s\n",name);
+ errno = 0;
+ return (-1);
+ }
+ x25host.datalen = X29PIDLEN;
+ x25host.data[0] = X29PID;
+
+ /* Set call user data if specified */
+ if (cudata) {
+ ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
+ x25host.datalen += (int)strlen(udata);
+ }
+
+ /* Open SunLink X.25 socket */
+ if (!quiet && *name) {
+ printf(" Trying %s... ", name);
+ fflush(stdout);
+ }
+ if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
+ debug(F101,"netopen socket error","",errno);
+ perror ("X.25 socket error");
+ return (-1);
+ }
+
+ /* Setting X.25 out-of-band data handler */
+ pid = getpid();
+ if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
+ perror("X.25 set process group id error");
+ return(-1);
+ }
+ (VOID) signal(SIGURG,x25oobh);
+
+ /* Set reverse charge call and closed user group if requested */
+ bzero ((char *)&x25facil,sizeof(x25facil));
+
+#ifndef X25_WR_FACILITY
+/* New SunLink (7.0 or 8.0, not sure which)... */
+ x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
+ x25facil.f_reverse_charge = revcall ? 1 : 0;
+ if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
+ perror ("Setting X.25 reverse charge");
+ return (-1);
+ }
+ if (closgr > -1) { /* Closed User Group (Outgoing) */
+ bzero ((char *)&x25facil,sizeof(x25facil));
+ x25facil.type = T_CUG;
+ x25facil.f_cug_req = CUG_REQ_ACS;
+ x25facil.f_cug_index = closgr;
+ if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
+ perror ("Setting X.25 closed user group");
+ return (-1);
+ }
+ }
+#else
+/* Old SunLink 6.0 (or 7.0?)... */
+ if (revcall) x25facil.reverse_charge = revcall;
+ if (closgr > -1) {
+ x25facil.cug_req = 1;
+ x25facil.cug_index = closgr;
+ }
+ if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
+ perror ("Setting X.25 facilities");
+ return (-1);
+ }
+#endif /* X25_WR_FACILITY */
+
+ /* Need X.25 header with bits Q and M */
+ if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
+ perror ("Setting X.25 header");
+ return (-1);
+ }
+
+ /* Connects to remote host via SunLink X.25 */
+ if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
+ i = errno;
+ debug(F101,"netopen connect errno","",i);
+ if (i) {
+ perror("netopen x25 connect");
+ x25diag();
+ }
+ (VOID) netclos();
+ ttyfd = -1;
+ wasclosed = 1;
+ ttnproto = NP_NONE;
+ errno = i;
+ return (-1);
+ }
+
+ /* Get X.25 link identification used for the connection */
+ if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
+ perror ("Getting X.25 link id");
+ return (-1);
+ }
+
+ /* Get X.25 logical channel number used for the connection */
+ if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
+ perror ("Getting X.25 lcn");
+ return (-1);
+ }
+
+ /* Get SunLink X.25 version */
+ if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
+ perror ("Getting SunLink X.25 version");
+ return (-1);
+ }
+ ttnet = nett; /* Sunlink X.25 network */
+ ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */
+ if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
+ return(0);
+ } else /* Note that SUNX25 support can coexist with TCP/IP support. */
+#endif /* SUNX25 */
+
+#ifdef IBMX25
+ /* riehm */
+ if (nett == NET_IX25) { /* IBM AIX X.25 */
+ netclos(); /* Close any previous net connection */
+ ttnproto = NP_NONE; /* No protocol selected yet */
+
+ /* find out who we are - this is not so easy on AIX */
+ /* riehm: need to write the code that finds this out
+ * automatically, or at least allow it to be configured
+ * somehow
+ */
+ if (!local_nua[0] && !x25local_nua(local_nua)) {
+ return(-1);
+ }
+
+ /* Initialise the X25 API (once per process? once per connection?) */
+
+ debug(F110, "Opening ", x25dev, 0 );
+ /* set O_NDELAY to allow polling? */
+ if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
+ perror ("X.25 device open error");
+ debug(F101,"netopen: device open error","",errno);
+ return (-1);
+ }
+
+ /* push the NPI onto the STREAM */
+ if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
+ close(ttyfd);
+ ttyfd = -1;
+ wasclosed = 1;
+ perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
+ debug(F101,"netopen: can't push npi on the X25 stream","",errno);
+ return (-1);
+ }
+
+ /* set up server mode - bind the x25 port and wait for
+ * incoming connections
+ */
+ if (name[0] == '*') { /* Server */
+ /* set up a server - see the warning in x25bind() */
+ bind_flags |= TOKEN_REQUEST;
+
+ /* bind kermit to the local X25 address */
+ token = x25bind(ttyfd,
+ local_nua,
+ udata,
+ (int)strlen( udata ),
+ 1,
+ x25port,
+ bind_flags
+ );
+ if (token < 0) {
+ debug(F100,"netopen: couldn't bind to local X25 address","",0);
+ netclos();
+ return(-1);
+ }
+ /* Currently not connected to a remote host */
+
+ remote_nua[0] = '\0';
+
+ /* store the fd so that incoming calls can have their own fd
+ * This is almost support for a true server (ie: a'la ftpd)
+ * but we're not quite there yet.
+ * used in netclos()
+ */
+ x25serverfd = ttyfd;
+ /*
+ * wait for an incoming call
+ * this should happen in the "server" command and not in
+ * the "set host *" command.
+ */
+ if ((ttyfd = x25getcall(ttyfd)) < 0) {
+ netclos();
+ return(-1);
+ }
+ } else { /* Client */
+ /* Bind kermit to the local X25 address */
+ token = x25bind(
+ ttyfd,
+ local_nua,
+ (char *)NULL,
+ 0,
+ 0,
+ x25port,
+ bind_flags
+ );
+ if (token < 0) {
+ debug(F100,"netopen: couldn't bind to local X25 address","",0);
+ netclos();
+ return(-1);
+ }
+/* riehm: this should be done via the CONNECT command, not HOST! */
+ {
+ x25serverfd = 0;
+ /* call the remote host */
+ /* name == address of remote host as char* */
+ if (x25call(ttyfd, name, udata) < 0 ) {
+ debug(F100,
+ "netopen: couldn't connect to remote X25 address",
+ "", 0);
+ netclos();
+ return(-1);
+ }
+ strcpy(remote_nua, name);
+ }
+ }
+ ttnet = nett; /* AIX X.25 network */
+ if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
+ return(0);
+
+ } else /* Note that IBMX25 support can coexist with TCP/IP support. */
+#endif /* IBMX25 */
+
+/* Add support for other networks here. */
+
+ if (nett != NET_TCPB) return(-1); /* BSD socket support */
+
+#ifdef TCPSOCKET
+ netclos(); /* Close any previous connection. */
+ ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
+ debug(F110,"netopen namecopy",namecopy,0);
+
+#ifndef NOLISTEN
+ if (name[0] == '*')
+ return(tcpsrv_open(name, lcl, nett, 0));
+#endif /* NOLISTEN */
+
+ p = namecopy; /* Was a service requested? */
+ while (*p != '\0' && *p != ':') p++; /* Look for colon */
+ if (*p == ':') { /* Have a colon */
+ debug(F110,"netopen name has colon",namecopy,0);
+ *p++ = '\0'; /* Get service name or number */
+#ifdef CK_URL
+ /*
+ Here we have to check for various popular syntaxes:
+ host:port (our original syntax)
+ URL such as telnet:host or telnet://host/
+ Or even telnet://user:password@host:port/path/
+ Or a malformed URL such as generated by Netscape 4.0 like:
+ telnet:telnet or telnet::host.
+ */
+
+ /*
+ * REPLACE THIS CODE WITH urlparse() but not on the day of the
+ * C-Kermit 8.0 RELEASE.
+ */
+
+ if (*p == ':') /* a second colon */
+ *p++ = '\0'; /* get rid of that one too */
+ while (*p == '/') *p++ = '\0'; /* and slashes */
+ x = strlen(p); /* Length of remainder */
+ if (p[x-1] == '/') /* If there is a trailing slash */
+ p[x-1] = '\0'; /* remove it. */
+ debug(F110,"netopen namecopy after stripping",namecopy,0);
+ debug(F110,"netopen p after stripping",p,0);
+ service = getservbyname(namecopy,"tcp");
+ if (service ||
+#ifdef RLOGCODE
+ !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
+#endif /* CK_SSL */
+ !ckstrcmp("iksd",namecopy,NAMECPYL,0)
+ ) {
+ char temphost[256], tempservice[80], temppath[256];
+ char * q = p, *r = p, *w = p;
+ int uidfound=0;
+ extern char pwbuf[];
+ extern int pwflg, pwcrypt;
+
+ if (ttnproto == NP_DEFAULT)
+ setnproto(namecopy);
+
+ /* Check for userid and possibly password */
+ while (*p != '\0' && *p != '@')
+ p++; /* look for @ */
+ if (*p == '@') {
+ /* found username and perhaps password */
+ debug(F110,"netopen namecopy found @","",0);
+ *p = '\0';
+ p++;
+ while (*w != '\0' && *w != ':')
+ w++;
+ if (*w == ':')
+ *w++ = '\0';
+ /* r now points to username, save it and the password */
+ debug(F110,"netopen namecopy username",r,0);
+ debug(F110,"netopen namecopy password",w,0);
+ uidfound=1;
+ if ( strcmp(uidbuf,r) || *w )
+ ckstrncpy(pwbuf,w,PWBUFL+1);
+ ckstrncpy(uidbuf,r,UIDBUFLEN);
+ pwflg = 1;
+ pwcrypt = 0;
+ q = p; /* Host after user and pwd */
+ } else {
+ p = q; /* No username or password */
+ }
+ /* Now we must look for the optional port. */
+ debug(F110,"netopen x p",p,0);
+ debug(F110,"netopen x q",q,0);
+
+ /* Look for the port/service or a file/directory path */
+ while (*p != '\0' && *p != ':' && *p != '/')
+ p++;
+ if (*p == ':') {
+ debug(F110,"netopen found port",q,0);
+ *p++ = '\0'; /* Found a port name or number */
+ r = p;
+
+ /* Look for the end of port/service or a file/directory path */
+ while (*p != '\0' && *p != '/')
+ p++;
+ if (*p == '/')
+ *p++ = '\0';
+
+ debug(F110,"netopen port",r,0);
+ ckstrncpy(tempservice,r,80);
+ ckstrncpy(temphost,q,256);
+ ckstrncpy(temppath,p,256);
+ ckstrncpy(namecopy,temphost,NAMECPYL);
+ debug(F110,"netopen tempservice",tempservice,0);
+ debug(F110,"netopen temphost",temphost,0);
+ debug(F110,"netopen temppath",temppath,0);
+
+ /* move port/service to a buffer that won't go away */
+ x = strlen(namecopy);
+ p = namecopy + x + 1;
+ ckstrncpy(p, tempservice, NAMECPYL - x);
+ } else {
+ /* Handle a path if we found one */
+ if (*p == '/')
+ *p++ = '\0';
+ ckstrncpy(temppath,p,256);
+
+ /* We didn't find another port, but if q is a service */
+ /* then assume that namecopy is actually a host. */
+ if (getservbyname(q,"tcp")) {
+ p = q;
+ } else {
+#ifdef RLOGCODE
+ /* rlogin is not a valid service */
+ if (!ckstrcmp("rlogin",namecopy,6,0)) {
+ ckstrncpy(namecopy,"login",NAMECPYL);
+ }
+#endif /* RLOGCODE */
+ /* iksd is not a valid service */
+ if (!ckstrcmp("iksd",namecopy,6,0)) {
+ ckstrncpy(namecopy,"kermit",NAMECPYL);
+ }
+ /* Reconstruct namecopy */
+ ckstrncpy(tempservice,namecopy,80);
+ ckstrncpy(temphost,q,256);
+ ckstrncpy(namecopy,temphost,NAMECPYL);
+ debug(F110,"netopen tempservice",tempservice,0);
+ debug(F110,"netopen temphost",temphost,0);
+ debug(F110,"netopen temppath",temppath,0);
+
+ /* move port/service to a buffer that won't go away */
+ x = strlen(namecopy);
+ p = namecopy + x + 1;
+ ckstrncpy(p, tempservice, NAMECPYL - x - 1);
+ }
+ }
+ debug(F110,"netopen URL result: host",namecopy,0);
+ debug(F110,"netopen URL result: service",p,0);
+ debug(F110,"netopen URL result: path",temppath,0);
+
+#ifdef IKS_GET
+ /* If we have set a path specified, we need to try to GET it */
+ /* But we have another problem, we have to login first. How */
+ /* do we specify that a login must be done before the GET? */
+ /* The user's name if specified is in 'userid' and the */
+ /* password if any is in 'pwbuf'. */
+ if ( temppath[0] ) {
+ extern int action;
+ extern char * cmarg;
+
+ if ( !uidfound ) {
+ /* If no userid was specified as part of the URL but
+ * a path was specified, then we
+ * set the user name to anonymous and the password
+ * to the current userid.
+ */
+ ckstrncpy(pwbuf,uidbuf,PWBUFL);
+ ckstrncat(pwbuf,"@",PWBUFL);
+ pwflg = 1;
+ pwcrypt = 0;
+ ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
+ }
+
+ /*
+ * If a file path was specified we perform the GET
+ * operation and then terminate the connection.
+ *
+ * If a directory was given instead of a file, then
+ * we should REMOTE CD to the directory and list its
+ * contents. But how do we tell the difference?
+ */
+ makestr(&cmarg,temppath);
+ action = 'r';
+ }
+#endif /* IKS_GET */
+ }
+#endif /* CK_URL */
+ } else { /* Otherwise use telnet */
+ p = "telnet";
+ }
+/*
+ By the time we get here, namecopy[] should hold the null-terminated
+ hostname or address, and p should point to the service name or number.
+*/
+ debug(F110,"netopen host",namecopy,0);
+ debug(F110,"netopen service requested",p,0);
+
+ /* Use the service port to set the default protocol type if necessary */
+ if (ttnproto == NP_DEFAULT)
+ setnproto(p);
+
+ ckstrncpy(namecopy2,namecopy,NAMECPYL);
+ service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
+ if (!service) {
+ fprintf(stderr, "Can't find port for service %s\n", p);
+#ifdef TGVORWIN
+ debug(F101,"netopen can't get service","",socket_errno);
+#else
+ debug(F101,"netopen can't get service","",errno);
+#endif /* TGVORWIN */
+ errno = 0; /* (rather than mislead) */
+ return(-1);
+ } else {
+ if (!ckstrcmp(namecopy,namecopy2,-1,0))
+ namecopy2[0] = '\0';
+ ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
+ debug(F110,"netopen service ok",svcbuf,0);
+ }
+
+#ifdef RLOGCODE
+ if (service && !strcmp("login",p) && service->s_port != htons(513)) {
+ fprintf(stderr,
+ " Warning: login service on port %d instead of port 513\n",
+ ntohs(service->s_port)
+ );
+ fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
+ debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
+ }
+#endif /* RLOGCODE */
+
+#ifndef NOHTTP
+ /* For HTTP connections we must preserve the original hostname and */
+ /* service requested so we can include them in the Host header. */
+ ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
+ ckitoa(ntohs(service->s_port)),NULL);
+
+ /* 'namecopy' contains the name of the host to which we want to connect */
+ /* 'svcbuf' contains the service name */
+ /* 'service->s_port' contains the port number in network byte order */
+
+ /* If we are using an http proxy, we need to create a buffer containing */
+ /* hostname:port-number */
+ /* to pass to the http_connect() function. Then we need to replace */
+ /* 'namecopy' with the name of the proxy server and the service->s_port */
+ /* with the port number of the proxy (default port 80). */
+
+ if ( tcp_http_proxy ) {
+ ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
+ ckuitoa(ntohs(service->s_port)),NULL);
+ ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
+
+ p = namecopy; /* Was a service requested? */
+ while (*p != '\0' && *p != ':') p++; /* Look for colon */
+ if (*p == ':') { /* Have a colon */
+ debug(F110,"netopen name has colon",namecopy,0);
+ *p++ = '\0'; /* Get service name or number */
+ } else {
+ strcpy(++p,"http");
+ }
+
+ service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
+ if (!service) {
+ fprintf(stderr, "Can't find port for service %s\n", p);
+#ifdef TGVORWIN
+ debug(F101,"netopen can't get service for proxy","",socket_errno);
+#else
+ debug(F101,"netopen can't get service for proxy","",errno);
+#endif /* TGVORWIN */
+ errno = 0; /* (rather than mislead) */
+ return(-1);
+ }
+ ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
+
+ }
+#endif /* NOHTTP */
+
+ /* Set up socket structure and get host address */
+
+ bzero((char *)&r_addr, sizeof(r_addr));
+ debug(F100,"netopen bzero ok","",0);
+/*
+ NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
+ all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
+ address without going through the multihomed host sequence and winding up
+ at a different place than the one requested.
+*/
+#ifdef INADDR_NONE
+ debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
+#else /* INADDR_NONE */
+ debug(F100,"netopen INADDR_NONE not defined","",0);
+#endif /* INADDR_NONE */
+#ifdef INADDRX
+ debug(F100,"netopen INADDRX defined","",0);
+#else /* INADDRX */
+ debug(F100,"netopen INADDRX not defined","",0);
+#endif /* INADDRX */
+
+#ifndef NOMHHOST
+#ifdef INADDRX
+ iax = inet_addr(namecopy);
+ debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
+#else /* INADDRX */
+#ifdef INADDR_NONE
+ iax.s_addr = inet_addr(namecopy);
+ debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
+#else /* INADDR_NONE */
+#ifdef SOLARIS
+ /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */
+ /* (unsigned) yet it returns -1 (signed) on failure. */
+ /* It makes a difference in 64-bit builds. */
+ rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */
+ iax = (unsigned) rc_inet_addr; /* and from there to whatever.. */
+#else
+#ifndef datageneral
+ iax = (unsigned int) inet_addr(namecopy);
+#else
+ iax = -1L;
+#endif /* datageneral */
+#endif /* SOLARIS */
+ debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr);
+ debug(F111,"netopen inet_addr",namecopy,iax);
+#endif /* INADDR_NONE */
+#endif /* INADDRX */
+
+ dns = 0;
+ if (
+/* This might give warnings on 64-bit platforms but they should be harmless */
+/* because INADDR_NONE should be all 1's anyway, thus the OR part is */
+/* probably superfluous -- not sure why it's even there, maybe it should be */
+/* removed. */
+#ifdef SOLARIS
+ rc_inet_addr == -1
+#else
+#ifdef INADDR_NONE
+ iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
+#else /* INADDR_NONE */
+ iax < 0
+#endif /* INADDR_NONE */
+#endif /* SOLARIS */
+ ) {
+ if (!quiet) {
+ printf(" DNS Lookup... ");
+ fflush(stdout);
+ }
+ if ((host = gethostbyname(namecopy)) != NULL) {
+ debug(F110,"netopen gethostbyname != NULL",namecopy,0);
+ host = ck_copyhostent(host);
+ dns = 1; /* Remember we performed dns lookup */
+ r_addr.sin_family = host->h_addrtype;
+ if (tcp_rdns && host->h_name && host->h_name[0]
+#ifndef NOHTTP
+ && (tcp_http_proxy == NULL)
+#endif /* NOHTTP */
+ ) {
+#ifdef COMMENT
+ ckstrncpy(xxname,host->h_name,XXNAMELEN);
+ debug(F110,"netopen xxname[1]",xxname,0);
+ if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){
+ ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname));
+ ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname));
+ debug(F110,"netopen xxname[2]",xxname,0);
+ }
+ name = (char *)xxname;
+#else
+ ckstrncpy(name,host->h_name,80); /* Bad Bad Bad */
+ if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
+ ckstrncat(name,":",80-strlen(name));
+ ckstrncat(name,svcbuf,80-strlen(name));
+ }
+#endif /* COMMENT */
+ }
+ debug(F110,"netopen name after lookup",name,0);
+
+#ifdef HADDRLIST
+#ifdef h_addr
+ /* This is for trying multiple IP addresses - see <netdb.h> */
+ if (!(host->h_addr_list))
+ return(-1);
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&r_addr.sin_addr,
+ host->h_length
+ );
+#else
+ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
+#endif /* h_addr */
+#else /* HADDRLIST */
+#ifdef HPUX6
+ r_addr.sin_addr.s_addr = (u_long)host->h_addr;
+#else /* HPUX6 */
+ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
+#endif /* HPUX6 */
+#endif /* HADDRLIST */
+
+#ifndef HPUX6
+ debug(F111,"BCOPY","host->h_length",host->h_length);
+#endif /* HPUX6 */
+ }
+ }
+#endif /* NOMHHOST */
+
+ debug(F101,"netopen dns","",dns);
+
+ if (!dns) {
+#ifdef INADDRX
+/* inet_addr() is of type struct in_addr */
+ struct in_addr ina;
+ unsigned long uu;
+ debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
+ ina = inet_addr(namecopy);
+ uu = *(unsigned int *)&ina;
+#else /* Not INADDRX */
+/* inet_addr() is unsigned long */
+ unsigned long uu;
+ debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
+ uu = inet_addr(namecopy);
+#endif /* INADDRX */
+ debug(F101,"netopen uu","",uu);
+ if (
+#ifdef INADDR_NONE
+ !(uu == INADDR_NONE || uu == (unsigned int) -1L)
+#else /* INADDR_NONE */
+ uu != ((unsigned long)-1)
+#endif /* INADDR_NONE */
+ ) {
+ r_addr.sin_addr.s_addr = uu;
+ r_addr.sin_family = AF_INET;
+ } else {
+#ifdef VMS
+ fprintf(stdout, "\r\n"); /* complete any previous message */
+#endif /* VMS */
+ fprintf(stderr, "Can't get address for %s\n", namecopy);
+#ifdef TGVORWIN
+ debug(F101,"netopen can't get address","",socket_errno);
+#else
+ debug(F101,"netopen can't get address","",errno);
+#endif /* TGVORWIN */
+ errno = 0; /* Rather than mislead */
+ return(-1);
+ }
+ }
+
+ /* Get a file descriptor for the connection. */
+
+ r_addr.sin_port = service->s_port;
+ ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
+ debug(F110,"netopen trying",ipaddr,0);
+ if (!quiet && *ipaddr) {
+ printf(" Trying %s... ", ipaddr);
+ fflush(stdout);
+ }
+
+ /* Loop to try additional IP addresses, if any. */
+
+ do {
+#ifdef EXCELAN
+ send_socket.sin_family = AF_INET;
+ send_socket.sin_addr.s_addr = 0;
+ send_socket.sin_port = 0;
+ if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
+ &send_socket, SO_REUSEADDR)) < 0)
+#else /* EXCELAN */
+#ifdef NT
+#ifdef COMMENT_X
+ /*
+ Must make sure that all sockets are opened in
+ Non-overlapped mode since we use the standard
+ C RTL functions to read and write data.
+ But it doesn't seem to work as planned.
+ */
+ {
+ int optionValue = SO_SYNCHRONOUS_NONALERT;
+ if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
+ (char *) &optionValue, sizeof(optionValue))
+ != NO_ERROR)
+ return(-1);
+ }
+#endif /* COMMENT */
+#endif /* NT */
+
+ if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+#endif /* EXCELAN */
+ {
+#ifdef EXCELAN
+ experror("TCP socket error");
+#else
+#ifdef VMS
+ fprintf(stdout, "\r\n"); /* complete any previous stdout */
+#endif /* VMS */
+#ifdef TGVORWIN
+#ifdef OLD_TWG
+ errno = socket_errno;
+#endif /* OLD_TWG */
+ socket_perror("TCP socket error");
+ debug(F101,"netopen socket error","",socket_errno);
+#else
+ perror("TCP socket error");
+ debug(F101,"netopen socket error","",errno);
+#endif /* TGVORWIN */
+#endif /* EXCELAN */
+ return (-1);
+ }
+ errno = 0;
+
+#ifdef RLOGCODE
+ /* Not part of the RLOGIN RFC, but the BSD implementation */
+ /* requires that the client port be a priviliged port (<1024) */
+ /* on a Unix system this would require SuperUser permissions */
+ /* thereby saying that the root of the Unix system has given */
+ /* permission for this connection to be created */
+ if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
+ static unsigned short lport = 1024; /* max reserved port */
+#ifdef OS2
+ int s_errno;
+#endif /* OS2 */
+
+ lport--; /* Make sure we do not reuse a port */
+ if (lport == 512)
+ lport = 1023;
+
+ sin.sin_family = AF_INET;
+ if (tcp_address) {
+#ifdef INADDRX
+ inaddrx = inet_addr(tcp_address);
+ sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
+#else
+ sin.sin_addr.s_addr = inet_addr(tcp_address);
+#endif /* INADDRX */
+ } else
+ sin.sin_addr.s_addr = INADDR_ANY;
+ while (1) {
+ sin.sin_port = htons(lport);
+ if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ break;
+#ifdef OS2
+ s_errno = socket_errno;
+ if (s_errno && /* OS2 bind fails with 0, if already in use */
+#ifdef NT
+ s_errno != WSAEADDRINUSE
+#else
+ s_errno != SOCEADDRINUSE &&
+ s_errno != (SOCEADDRINUSE - SOCBASEERR)
+#endif /* NT */
+ )
+#else /* OS2 */
+#ifdef TGVORWIN
+ if (socket_errno != EADDRINUSE)
+#else
+ if (errno != EADDRINUSE)
+#endif /* TGVORWIN */
+#endif /* OS2 */
+ {
+#ifdef COMMENT
+ printf("\nBind failed with errno %d for port %d.\n",
+#ifdef OS2
+ s_errno
+#else
+#ifdef TGVORWIN
+ socket_errno
+#else
+ errno
+#endif /* TGVORWIN */
+#endif /* OS2 */
+ , lport
+ );
+#ifdef OS2
+ debug(F101,"rlogin bind failed","",s_errno);
+#else
+#ifdef TGVORWIN
+ debug(F101,"rlogin bind failed","",socket_errno);
+#ifdef OLD_TWG
+ errno = socket_errno;
+#endif /* OLD_TWG */
+ socket_perror("rlogin bind");
+#else
+ debug(F101,"rlogin bind failed","",errno);
+ perror("rlogin bind");
+#endif /* TGVORWIN */
+#endif /* OS2 */
+#else /* COMMENT */
+#ifdef OS2
+ debug(F101,"rlogin bind s_errno","",s_errno);
+ perror("rlogin bind");
+#else
+#ifdef VMS
+ printf("\r\n"); /* complete any previous message */
+#endif /* VMS */
+#ifdef TGVORWIN
+ debug(F101,"rlogin bind socket_errno","",socket_errno);
+#ifdef OLD_TWG
+ errno = socket_errno;
+#endif /* OLD_TWG */
+ socket_perror("rlogin bind");
+#else
+ debug(F101,"rlogin bind errno","",errno);
+ perror("rlogin bind");
+#endif /* TGVORWIN */
+#endif /* OS2 */
+ debug(F101,"rlogin local port","",lport);
+#endif /* COMMENT */
+ netclos();
+ return -1;
+ }
+ lport--;
+ if (lport == 512 /* lowest reserved port to use */ ) {
+ printf("\nNo reserved ports available.\n");
+ netclos();
+ return -1;
+ }
+ }
+ debug(F101,"rlogin lport","",lport);
+ ttnproto = NP_RLOGIN;
+ } else
+#endif /* RLOGCODE */
+
+ /* If a specific TCP address on the local host is desired we */
+ /* must bind it to the socket. */
+#ifndef datageneral
+ if (tcp_address) {
+ int s_errno;
+
+ debug(F110,"netopen binding socket to",tcp_address,0);
+ bzero((char *)&sin,sizeof(sin));
+ sin.sin_family = AF_INET;
+#ifdef INADDRX
+ inaddrx = inet_addr(tcp_address);
+ sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
+#else
+ sin.sin_addr.s_addr = inet_addr(tcp_address);
+#endif /* INADDRX */
+ sin.sin_port = 0;
+ if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ s_errno = socket_errno; /* Save error code */
+#ifdef TCPIPLIB
+ socket_close(ttyfd);
+#else /* TCPIPLIB */
+ close(ttyfd);
+#endif /* TCPIPLIB */
+ ttyfd = -1;
+ wasclosed = 1;
+ errno = s_errno; /* and report this error */
+ debug(F101,"netopen bind errno","",errno);
+ return(-1);
+ }
+ }
+#endif /* datageneral */
+
+/* Now connect to the socket on the other end. */
+
+#ifdef EXCELAN
+ if (connect(ttyfd, &r_addr) < 0)
+#else
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+ if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
+#endif /* EXCELAN */
+ {
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#ifdef OS2
+ i = socket_errno;
+#else /* OS2 */
+#ifdef TGVORWIN
+ i = socket_errno;
+#else
+ i = errno; /* Save error code */
+#endif /* TGVORWIN */
+#endif /* OS2 */
+#ifdef RLOGCODE
+ if (
+#ifdef OS2
+ i && /* OS2 bind fails with 0, if already in use */
+#ifdef NT
+ i == WSAEADDRINUSE
+#else
+ (i == SOCEADDRINUSE ||
+ i == (SOCEADDRINUSE - SOCBASEERR))
+#endif /* NT */
+#else /* OS2 */
+#ifdef TGVORWIN
+ socket_errno == EADDRINUSE
+#else
+ errno == EADDRINUSE
+#endif /* TGVORWIN */
+#endif /* OS2 */
+ && ttnproto == NP_RLOGIN) {
+#ifdef TCPIPLIB
+ socket_close(ttyfd); /* Close it. */
+#else
+ close(ttyfd);
+#endif /* TCPIPLIB */
+ continue; /* Try a different lport */
+ }
+#endif /* RLOGCODE */
+#ifdef HADDRLIST
+#ifdef h_addr
+ if (host && host->h_addr_list && host->h_addr_list[1]) {
+ perror("");
+ host->h_addr_list++;
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&r_addr.sin_addr,
+ host->h_length);
+
+ ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
+ debug(F110,"netopen h_addr_list",ipaddr,0);
+ if (!quiet && *ipaddr) {
+ printf(" Trying %s... ", ipaddr);
+ fflush(stdout);
+ }
+#ifdef TCPIPLIB
+ socket_close(ttyfd); /* Close it. */
+#else
+ close(ttyfd);
+#endif /* TCPIPLIB */
+ continue;
+ }
+#endif /* h_addr */
+#endif /* HADDRLIST */
+ netclos();
+ ttyfd = -1;
+ wasclosed = 1;
+ ttnproto = NP_NONE;
+ errno = i; /* And report this error */
+#ifdef EXCELAN
+ if (errno) experror("netopen connect");
+#else
+#ifdef TGVORWIN
+ debug(F101,"netopen connect error","",socket_errno);
+ /* if (errno) socket_perror("netopen connect"); */
+#ifdef OLD_TWG
+ errno = socket_errno;
+#endif /* OLD_TWG */
+ if (!quiet)
+ socket_perror("netopen connect");
+#else /* TGVORWIN */
+ debug(F101,"netopen connect errno","",errno);
+#ifdef VMS
+ if (!quiet)
+ perror("\r\nFailed");
+#else
+ if (!quiet)
+ perror("Failed");
+#endif /* VMS */
+#ifdef DEC_TCPIP
+ if (!quiet)
+ perror("netopen connect");
+#endif /* DEC_TCPIP */
+#ifdef CMU_TCPIP
+ if (!quiet)
+ perror("netopen connect");
+#endif /* CMU_TCPIP */
+#endif /* TGVORWIN */
+#endif /* EXCELAN */
+ return(-1);
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+ isconnect = 1;
+ } while (!isconnect);
+
+#ifdef NON_BLOCK_IO
+ on = 1;
+ x = socket_ioctl(ttyfd,FIONBIO,&on);
+ debug(F101,"netopen FIONBIO","",x);
+#endif /* NON_BLOCK_IO */
+
+#ifdef NT_TCP_OVERLAPPED
+ OverlappedWriteInit();
+ OverlappedReadInit();
+#endif /* NT_TCP_OVERLAPPED */
+
+ ttnet = nett; /* TCP/IP (sockets) network */
+
+#ifndef NOHTTP
+ /* We have succeeded in connecting to the HTTP PROXY. So now we */
+ /* need to attempt to connect through the proxy to the actual host */
+ /* If that is successful, we have to pretend that we made a direct */
+ /* connection to the actual host. */
+
+ if ( tcp_http_proxy ) {
+#ifdef OS2
+ char * agent = "Kermit 95"; /* Default user agent */
+#else
+ char * agent = "C-Kermit";
+#endif /* OS2 */
+
+ if (http_connect(ttyfd,
+ tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
+ NULL,
+ tcp_http_proxy_user,
+ tcp_http_proxy_pwd,
+ 0,
+ proxycopy
+ ) < 0) {
+ netclos();
+ return(-1);
+ }
+
+ ckstrncpy(namecopy,proxycopy,NAMECPYL);
+ p = namecopy; /* Was a service requested? */
+ while (*p != '\0' && *p != ':') p++; /* Look for colon */
+ *p = '\0';
+ }
+#endif /* NOHTTP */
+
+ /* Jeff - Does this next block of code that set's the protocol */
+ /* need to be here anymore? 5/10/2000 */
+
+ /* There are certain magic port numbers that when used require */
+ /* the use of specific protocols. Check this now before we */
+ /* set the SO_OOBINLINE state or we might get it wrong. */
+ x = ntohs((unsigned short)service->s_port);
+ svcnum = x;
+ /* See if the service is TELNET. */
+ if (x == TELNET_PORT) {
+ /* Yes, so if raw port not requested */
+#ifdef COMMENT
+ /* Jeff 2005/12/30 */
+ if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW &&
+ ttnproto != NP_TLS_RAW && ttnproto != NP_NONE)
+#else
+ /* fdc 2005/12/04 */
+ if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
+#endif /* COMMENT */
+ ttnproto = NP_TELNET; /* Select TELNET protocol. */
+ }
+#ifdef RLOGCODE
+ else if (x == RLOGIN_PORT) {
+ ttnproto = NP_RLOGIN;
+ }
+#ifdef CK_KERBEROS
+ /* There is no good way to do this. If the user didn't tell */
+ /* which one to use up front. We may guess wrong if the user */
+ /* has both Kerberos versions installed and valid TGTs for each */
+ else if (x == KLOGIN_PORT &&
+ ttnproto != NP_K4LOGIN &&
+ ttnproto != NP_K5LOGIN) {
+ if (ck_krb5_is_installed() &&
+ ck_krb5_is_tgt_valid())
+ ttnproto = NP_K5LOGIN;
+ else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
+ ttnproto = NP_K4LOGIN;
+ else
+ ttnproto = NP_K4LOGIN;
+ } else if (x == EKLOGIN_PORT &&
+ ttnproto != NP_EK4LOGIN &&
+ ttnproto != NP_EK5LOGIN) {
+ if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
+ ttnproto = NP_EK5LOGIN;
+ else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
+ ttnproto = NP_EK4LOGIN;
+ else
+ ttnproto = NP_EK4LOGIN;
+ }
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+#ifdef IKS_OPTION
+ else if (x == KERMIT_PORT) { /* IKS uses Telnet protocol */
+ if (ttnproto == NP_NONE)
+ ttnproto = NP_KERMIT;
+ }
+#endif /* IKS_OPTION */
+
+#ifdef SO_OOBINLINE
+/*
+ The symbol SO_OOBINLINE is not known to Ultrix 2.0.
+ It means "leave out of band data inline". The normal value is 0x0100,
+ but don't try this on systems where the symbol is undefined.
+*/
+/*
+ Note from Jeff Altman: 12/13/95
+ In implementing rlogin protocol I have come to the conclusion that it is
+ a really bad idea to read out-of-band data inline.
+ At least Windows and OS/2 does not handle this well.
+ And if you need to know that data is out-of-band, then it becomes
+ absolutely pointless.
+
+ Therefore, at least on OS2 and Windows (NT) I have changed the value of
+ on to 0, so that out-of-band data stays out-of-band.
+
+ 12/18/95
+ Actually, OOB data should be read inline when possible. Especially with
+ protocols that don't care about the Urgent flag. This is true with Telnet.
+ With Rlogin, you need to be able to catch OOB data. However, the best
+ way to do this is to set a signal handler on SIGURG. This isn't possible
+ on OS/2 and Windows. But it is in UNIX. We will also need OOB data for
+ FTP so better create a general mechanism.
+
+ The reason for making OOB data be inline is that the standard ttinc/ttoc
+ calls can be used for reading that data on UNIX systems. If we didn't
+ have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
+ to read it.
+*/
+#ifdef RLOGCODE
+#ifdef TCPIPLIB
+ if (ttnproto == NP_RLOGIN
+#ifdef CK_KERBEROS
+ || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
+ || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_KERBEROS */
+ )
+ on = 0;
+#else /* TCPIPLIB */
+ if (ttnproto == NP_RLOGIN
+#ifdef CK_KERBEROS
+ || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
+ || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_KERBEROS */
+ ) {
+ debug(F100,"Installing rlogoobh on SIGURG","",0);
+ signal(SIGURG, rlogoobh);
+ on = 0;
+ } else {
+ debug(F100,"Ignoring SIGURG","",0);
+ signal(SIGURG, SIG_DFL);
+ }
+#endif /* TCPIPLIB */
+#endif /* RLOGCODE */
+
+#ifdef datageneral
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef BSD43
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef OSF1
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef POSIX
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef MOTSV88R4
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef SOLARIS
+/*
+ Maybe this applies to all SVR4 versions, but the other (else) way has been
+ compiling and working fine on all the others, so best not to change it.
+*/
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef OSK
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef OS2
+ {
+ int rc;
+ rc = setsockopt(ttyfd,
+ SOL_SOCKET,
+ SO_OOBINLINE,
+ (char *) &on,
+ sizeof on
+ );
+ debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
+ }
+#else
+#ifdef VMS /* or, at least, VMS with gcc */
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef CLIX
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
+#endif /* CLIX */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* OSK */
+#endif /* SOLARIS */
+#endif /* MOTSV88R4 */
+#endif /* POSIX */
+#endif /* BSD43 */
+#endif /* OSF1 */
+#endif /* datageneral */
+#endif /* SO_OOBINLINE */
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+ no_delay(ttyfd,tcp_nodelay);
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+ keepalive(ttyfd,tcp_keepalive);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
+#endif /* SO_LINGER */
+#ifdef SO_SNDBUF
+ sendbuf(ttyfd,tcp_sendbuf);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ recvbuf(ttyfd,tcp_recvbuf);
+#endif /* SO_RCVBUF */
+#endif /* SOL_SOCKET */
+#endif /* datageneral */
+#endif /* NOTCPOPTS */
+
+#ifndef datageneral
+ /* Find out our own IP address. */
+ /* We need the l_addr structure for [E]KLOGIN. */
+ l_slen = sizeof(l_addr);
+ bzero((char *)&l_addr, l_slen);
+#ifndef EXCELAN
+ if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
+ char * s = (char *)inet_ntoa(l_addr.sin_addr);
+ ckstrncpy(myipaddr, s, 20);
+ debug(F110,"getsockname",myipaddr,0);
+ }
+#endif /* EXCELAN */
+#endif /* datageneral */
+
+/*
+ This is really only needed for Kerberos IV but is useful information in any
+ case. If we connect to a name that is really a pool, we need to get the
+ name of the machine we are actually connecting to for K4 to authenticate
+ properly. This way we also update the names properly.
+
+ However, it is a security hole when used with insecure DNS.
+
+ Note: This does not work on Windows 95 or Windows NT 3.5x. This is because
+ of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
+ and Winsock 2.0 on those platforms. Their algorithm is:
+
+ 1. Check the HOSTENT cache.
+ 2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
+ 3. Do a DNS query if the DNS server is configured for name resolution.
+ 4. Do an additional NetBIOS remote adapter status to an IP address for its
+ NetBIOS name table. This step is specific only to the Windows NT version
+ 3.51 implementation.
+
+ The problem is the use of the HOSTENT cache. It means that gethostbyaddr()
+ can not be used to resolve the real name of machine if it was originally
+ accessed by an alias used to represent a cluster.
+*/
+ if ((tcp_rdns && dns || tcp_rdns == SET_ON
+#ifdef CK_KERBEROS
+ || tcp_rdns == SET_AUTO &&
+ (ck_krb5_is_installed() || ck_krb4_is_installed())
+#endif /* CK_KERBEROS */
+ )
+#ifndef NOHTTP
+ && (tcp_http_proxy == NULL)
+#endif /* NOHTTP */
+#ifdef CK_SSL
+ && !(ssl_only_flag || tls_only_flag)
+#endif /* CK_SSL */
+ ) {
+#ifdef NT
+ if (isWin95())
+ sleep(1);
+#endif /* NT */
+ if (!quiet) {
+ printf(" Reverse DNS Lookup... ");
+ fflush(stdout);
+ }
+ if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
+ char * s;
+ host = ck_copyhostent(host);
+ debug(F100,"netopen gethostbyname != NULL","",0);
+ if (!quiet) {
+ printf("(OK)\n");
+ fflush(stdout);
+ }
+ s = host->h_name;
+ if (!s) { /* This can happen... */
+ debug(F100,"netopen host->h_name is NULL","",0);
+ s = "";
+ }
+ /* Something is wrong with inet_ntoa() on HPUX 10.xx */
+ /* The compiler says "Integral value implicitly converted to */
+ /* pointer in assignment." The prototype is right there */
+ /* in <arpa/inet.h> so what's the problem? */
+ /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
+ if (!*s) { /* No name so substitute the address */
+ debug(F100,"netopen host->h_name is empty","",0);
+ s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
+ if (!s) /* Trust No 1 */
+ s = "";
+ if (*s) { /* If it worked, use this string */
+ ckstrncpy(ipaddr,s,20);
+ }
+ s = ipaddr; /* Otherwise stick with the IP */
+ if (!*s) /* or failing that */
+ s = namecopy; /* the name we were called with. */
+ }
+ if (*s) { /* Copying into our argument? */
+ ckstrncpy(name,s,80); /* Bad Bad Bad */
+ if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
+ ckstrncat(name,":",80-strlen(name));
+ ckstrncat(name,svcbuf,80-strlen(name));
+ }
+ }
+ if (!quiet && *s
+#ifndef NOICP
+ && !doconx
+#endif /* NOICP */
+ ) {
+ printf(" %s connected on port %s\n",s,p);
+#ifdef BETADEBUG
+ /* This is simply for testing the DNS entries */
+ if (host->h_aliases) {
+ char ** a = host->h_aliases;
+ while (*a) {
+ printf(" alias => %s\n",*a);
+ a++;
+ }
+ }
+#endif /* BETADEBUG */
+ }
+ } else {
+ if (!quiet) printf("Failed.\n");
+ }
+ } else if (!quiet) printf("(OK)\n");
+ if (!quiet) fflush(stdout);
+
+ /* This should already have been done but just in case */
+ ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
+
+#ifdef CK_SECURITY
+
+ /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
+#ifndef NOHTTP
+ if (tcp_http_proxy) {
+ for (i=strlen(proxycopy); i >= 0 ; i--)
+ if ( proxycopy[i] == ':' )
+ proxycopy[i] = '\0';
+ }
+#endif /* NOHTTP */
+ ck_auth_init(
+#ifndef NOHTTP
+ tcp_http_proxy ? proxycopy :
+#endif /* NOHTTP */
+ (tcp_rdns && host && host->h_name && host->h_name[0]) ?
+ (char *)host->h_name : (namecopy2[0] ? namecopy2 :
+ (namecopy[0] ? namecopy : ipaddr)),
+ ipaddr,
+ uidbuf,
+ ttyfd
+ );
+#endif /* CK_SECURITY */
+#ifdef CK_SSL
+ if (ck_ssleay_is_installed()) {
+ if (!ssl_tn_init(SSL_CLIENT)) {
+ debug(F100,"netopen ssl_tn_init() failed","",0);
+ if (bio_err!=NULL) {
+ BIO_printf(bio_err,"ssl_tn_init() failed\n");
+ ERR_print_errors(bio_err);
+ } else {
+ fflush(stderr);
+ fprintf(stderr,"ssl_tn_init() failed\n");
+ ERR_print_errors_fp(stderr);
+ }
+ if (tls_only_flag || ssl_only_flag) {
+ debug(F100,"netopen ssl/tls required","",0);
+ netclos();
+ return(-1);
+ }
+
+ /* we will continue to accept the connection */
+ /* without SSL or TLS support unless required. */
+ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
+ debug(F100,"ck_ssl_outgoing() failed","",0);
+ netclos();
+ return(-1);
+ }
+ }
+#endif /* CK_SSL */
+
+#ifdef RLOGCODE
+ if (ttnproto == NP_RLOGIN
+#ifdef CK_KERBEROS
+ || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
+ || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_KERBEROS */
+ ) { /* Similar deal for rlogin */
+ if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
+ (CHAR *)host->h_name : (CHAR *)ipaddr),
+ service->s_port,
+ &l_addr,&r_addr
+ ) < 0) {
+ debug(F100,"rlogin initialization failed","",0);
+ netclos();
+ return(-1);
+ }
+ } else
+#endif /* RLOGCODE */
+ if (tn_ini() < 0) { /* Start Telnet negotiations. */
+ netclos();
+ return(-1); /* Gone, so open failed. */
+ }
+ if (ttchk() < 0) {
+ netclos();
+ return(-1);
+ }
+#ifdef CK_KERBEROS
+#ifdef KRB5_U2U
+ if ( ttnproto == NP_K5U2U ) {
+ if (k5_user_to_user_client_auth()) {
+ netclos();
+ return(-1);
+ }
+ }
+#endif /* KRB5_U2U */
+#endif /* CK_KERBEROS */
+
+ debug(F101,"netopen service","",svcnum);
+ debug(F110,"netopen name",name,0);
+ debug(F110,"netopen ipaddr",ipaddr,0);
+ ckstrncpy(hostipaddr,ipaddr,63);
+
+ if (lcl) if (*lcl < 0) /* Local mode. */
+ *lcl = 1;
+#endif /* TCPSOCKET */
+ return(0); /* Done. */
+}
+
+/* N E T C L O S -- Close current network connection. */
+
+#ifndef NOLOCAL
+_PROTOTYP(VOID slrestor,(VOID));
+#ifdef CK_SSL
+int tls_norestore = 0;
+#endif /* CK_SSL */
+#endif /* NOLOCAL */
+
+int
+netclos() {
+ static int close_in_progress = 0;
+ int x = 0, y, z;
+ debug(F101,"netclos","",ttyfd);
+
+#ifdef NETLEBUF
+ if (!tt_push_inited)
+ le_init();
+#endif /* NETLEBUF */
+
+ if (ttyfd == -1) /* Was open? */
+ return(0); /* Wasn't. */
+
+ if (close_in_progress)
+ return(0);
+ close_in_progress = 1; /* Remember */
+
+#ifndef NOLOCAL
+ /* This function call should not be here since this is a direct call */
+ /* from an I/O routine to a user interface level function. However, */
+ /* the reality is that we do not have pure interfaces. If we ever */
+ /* decide to clean this up the UI level should assign this function */
+ /* via a pointer assignment. - Jeff 9/10/1999 */
+#ifdef CK_SSL
+ if (!tls_norestore)
+#endif /* CK_SSL */
+ slrestor();
+#endif /* NOLOCAL */
+#ifdef OS2
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+#else /* OS2 */
+ if (ttyfd > -1) /* Was. */
+#endif /* OS2 */
+ {
+#ifdef VMS
+ y = 1; /* Turn on nonblocking reads */
+ z = socket_ioctl(ttyfd,FIONBIO,&y);
+ debug(F111,"netclos FIONBIO","on",z);
+#endif /* VMS */
+#ifdef TNCODE
+ if (ttnproto == NP_TELNET) {
+ if (!TELOPT_ME(TELOPT_LOGOUT)
+#ifdef COMMENT
+/* Jeff 2005/12/30 */
+#ifdef CK_SSL
+ && !ssl_raw_flag && !tls_raw_flag
+#endif /* CK_SSL */
+#endif /* COMMENT */
+ ) {
+ /* Send LOGOUT option before close */
+ if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
+ TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
+ /* It would be nice to call tn_wait but we can't */
+ }
+ }
+ tn_push(); /* Place any waiting data into input*/
+ }
+#endif /* TNCODE */
+#ifdef CK_SSL
+ if (ssl_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown\n");
+ SSL_shutdown(ssl_con);
+ ssl_active_flag = 0;
+ }
+ if (tls_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown\n");
+ SSL_shutdown(tls_con);
+ tls_active_flag = 0;
+ }
+#endif /* CK_SSL */
+#ifdef VMS
+ ck_cancio(); /* Cancel any outstanding reads. */
+#endif /* VMS */
+#ifdef TCPIPLIB
+ x = socket_close(ttyfd); /* Close it. */
+#else
+#ifndef OS2
+#ifdef IBMX25
+ if (ttnet == NET_IX25) {
+ /* riehm: should send a disc_req - but only if link is still OK */
+ x = x25clear();
+ close(ttyfd);
+ if (x25serverfd) {
+ /* we were the passive client of a server, now we
+ * go back to being the normal client.
+ * I hope that kermit can cope with the logic that
+ * there can still be a connection after netclos
+ * has been called.
+ */
+ ttyfd = x25serverfd;
+ x25serverfd = 0;
+ /*
+ * need to close the server connection too - because
+ * all file descriptors connected to the NPI have the
+ * same status.
+ *
+ * The problem is that any waiting connections get
+ * lost, the client doesn't realise, and hangs.
+ */
+ netclos();
+ }
+ x25_state = X25_CLOSED; /* riehm: dead code? */
+ } else
+#endif /* IBMX25 */
+ x = close(ttyfd);
+#endif /* OS2 */
+#endif /* TCPIPLIB */
+ }
+ ttyfd = -1; /* Mark it as closed. */
+ wasclosed = 1;
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+#ifdef TNCODE
+#ifdef CK_FORWARD_X
+ fwdx_close_all(); /* Shut down any Forward X sockets */
+#endif /* CK_FORWARD_X */
+ tn_reset(); /* The Reset Telnet Option table. */
+ debug(F100,"netclose setting tn_init = 0","",0);
+ tn_init = 0; /* Remember about telnet protocol... */
+ sstelnet = 0; /* Client-side Telnet */
+#endif /* TNCODE */
+ *ipaddr = '\0'; /* Zero the IP address string */
+ tcp_incoming = 0; /* No longer incoming */
+ /* Don't reset ttnproto so that we can remember which protocol is in use */
+
+#ifdef TCPIPLIB
+/*
+ Empty the internal buffers so they won't be used as invalid input on
+ the next connect attempt (rlogin).
+*/
+ ttibp = 0;
+ ttibn = 0;
+#endif /* TCPIPLIB */
+#ifdef CK_KERBEROS
+ /* If we are automatically destroying Kerberos credentials on Close */
+ /* do it now. */
+#ifdef KRB4
+ if (krb4_autodel == KRB_DEL_CL) {
+ extern struct krb_op_data krb_op;
+ krb_op.version = 4;
+ krb_op.cache = NULL;
+ ck_krb4_destroy(&krb_op);
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (krb5_autodel == KRB_DEL_CL) {
+ extern struct krb_op_data krb_op;
+ extern char * krb5_d_cc;
+ krb_op.version = 5;
+ krb_op.cache = krb5_d_cc;
+ ck_krb5_destroy(&krb_op);
+ }
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+ close_in_progress = 0; /* Remember we are done. */
+ return(x);
+}
+
+#ifdef OS2
+int
+os2socketerror( int s_errno ) {
+#ifdef OS2ONLY
+ if (s_errno > 0 && s_errno <= SOCBASEERR) {
+ /* in OS/2, there is a problem with threading in that
+ * the value of errno is not thread safe. It can be
+ * set to a value from a previous library call and if
+ * it was not cleared it will appear here. Only treat
+ * valid socket error codes as errors in this function.
+ */
+ debug(F100,"os2socketerror errno.h","",0);
+ socket_errno = 0;
+ return(0);
+ }
+#endif /* OS2ONLY */
+
+ switch (s_errno) {
+ case 0: /* NO ERROR */
+ debug(F100,"os2socketerror NOERROR","",0);
+ return(0);
+#ifdef NT
+ case WSAECONNRESET:
+#else /* NT */
+ case SOCECONNRESET:
+ case SOCECONNRESET - SOCBASEERR:
+#endif /* NT */
+ debug(F100,"os2socketerror ECONRESET","",0);
+ tn_debug("ECONRESET");
+ netclos(); /* *** *** */
+ return(-1); /* Connection is broken. */
+#ifdef NT
+ case WSAECONNABORTED:
+#else /* NT */
+ case SOCECONNABORTED:
+ case SOCECONNABORTED - SOCBASEERR:
+#endif /* NT */
+ debug(F100,"os2socketerror ECONNABORTED","",0);
+ tn_debug("ECONNABORTED");
+ netclos(); /* *** *** */
+ return(-1); /* Connection is broken. */
+#ifdef NT
+ case WSAENETRESET:
+#else /* NT */
+ case SOCENETRESET:
+ case SOCENETRESET - SOCBASEERR:
+#endif /* NT */
+ debug(F100,"os2socketerror ENETRESET","",0);
+ tn_debug("ENETRESET");
+ netclos(); /* *** *** */
+ return(-1); /* Connection is broken. */
+#ifdef NT
+ case WSAENOTCONN:
+#else /* NT */
+ case SOCENOTCONN:
+ case SOCENOTCONN - SOCBASEERR:
+#endif /* NT */
+ debug(F100,"os2socketerror ENOTCONN","",0);
+ tn_debug("ENOTCONN");
+ netclos(); /* *** *** */
+ return(-1); /* Connection is broken. */
+#ifdef NT
+ case WSAESHUTDOWN:
+ debug(F100,"os2socketerror ESHUTDOWN","",0);
+ tn_debug("ESHUTDOWN");
+ netclos(); /* *** *** */
+ return(-1); /* Connection is broken. */
+#endif /* NT */
+#ifdef NT
+ case WSAEWOULDBLOCK:
+#else
+ case SOCEWOULDBLOCK:
+ case SOCEWOULDBLOCK - SOCBASEERR:
+#endif /* NT */
+ debug(F100,"os2socketerror EWOULDBLOCK","",0);
+ return(0);
+#ifdef NT
+ case ERROR_IO_INCOMPLETE:
+ case ERROR_IO_PENDING:
+ case ERROR_OPERATION_ABORTED:
+ return(0);
+#endif /* NT */
+ default:
+ return(-2);
+ }
+ return(0);
+}
+#endif /* OS2 */
+
+/* N E T T C H K -- Check if network up, and how many bytes can be read */
+/*
+ Returns number of bytes waiting, or -1 if connection has been dropped.
+*/
+int /* Check how many bytes are ready */
+nettchk() { /* for reading from network */
+#ifdef TCPIPLIB
+ long count = 0;
+ int x = 0, z;
+ long y;
+ char c;
+ int rc;
+#ifdef NT
+ extern int ionoblock; /* For Overlapped I/O */
+#endif /* NT */
+
+ debug(F101,"nettchk entry ttibn","",ttibn);
+ debug(F101,"nettchk entry ttibp","",ttibp);
+
+#ifdef NETLEBUF
+ {
+ int n = 0;
+ if (ttpush >= 0)
+ n++;
+ n += le_inbuf();
+ if (n > 0)
+ return(n);
+ }
+#endif /* NETLEBUF */
+
+#ifndef OS2
+#ifndef BEBOX
+ socket_errno = 0; /* This is a function call in NT, and BeOS */
+#endif /* BEBOX */
+#endif /* OS2 */
+
+ if (ttyfd == -1) {
+ debug(F100,"nettchk socket is closed","",0);
+ return(-1);
+ }
+/*
+ Note: this socket_ioctl() call does NOT return an error if the
+ connection has been broken. (At least not in MultiNet.)
+*/
+#ifdef COMMENT
+/* Another trick that can be tried here is something like this: */
+
+ if (ttnet == NET_TCPB) {
+ char dummy;
+ x = read(ttyfd,&dummy,0); /* Try to read nothing */
+ if (x < 0) { /* "Connection reset by peer" */
+ perror("TCP/IP"); /* or somesuch... */
+ ttclos(0); /* Close our end too. */
+ return(-1);
+ }
+ }
+#endif /* COMMENT */
+
+
+#ifdef CK_SSL
+ if (ssl_active_flag) {
+#ifndef IKSDONLY
+#ifdef OS2
+ if ( IsConnectMode() ) {
+ debug(F101,"nettchk (ssl_active_flag) returns","",count);
+ return(0);
+ }
+#endif /* OS2 */
+#endif /* IKSDONLY */
+ count = SSL_pending(ssl_con);
+ if (count < 0) {
+ debug(F111,"nettchk","SSL_pending error",count);
+ netclos();
+ return(-1);
+ }
+ if ( count > 0 )
+ return(count); /* Don't perform a read */
+ } else if (tls_active_flag) {
+#ifndef IKSDONLY
+#ifdef OS2
+ if ( IsConnectMode() ) {
+ debug(F101,"nettchk (tls_active_flag) returns","",count);
+ return(0);
+ }
+#endif /* OS2 */
+#endif /* IKSDONLY */
+ count = SSL_pending(tls_con);
+ if (count < 0) {
+ debug(F111,"nettchk","TLS_pending error",count);
+ netclos();
+ return(-1);
+ }
+ if ( count > 0 )
+ return(count); /* Don't perform a read */
+ } else
+#endif /* CK_SSL */
+
+ if (socket_ioctl(ttyfd,FIONREAD,
+#ifdef COMMENT
+ /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
+#ifdef __DECC
+ /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
+ /* Cast needed for DECC 4.1 & later? */
+ /* Maybe, but __DECC_VER only exists in 5.0 and later */
+ (char *)
+#endif /* __DECC */
+#endif /* COMMENT */
+ &count
+ ) < 0) {
+ debug(F101,"nettchk socket_ioctl error","",socket_errno);
+ /* If the connection is gone, the connection is gone. */
+ netclos();
+#ifdef NT_TCP_OVERLAPPED
+ /* Is there anything in the overlapped I/O buffers? */
+ count += OverlappedDataWaiting();
+#endif /* NT_TCP_OVERLAPPED */
+ count += ttibn;
+ return(count>0?count:-1);
+ }
+ debug(F101,"nettchk count","",count);
+#ifdef NT_TCP_OVERLAPPED
+ /* Is there anything in the overlapped I/O buffers? */
+ count += OverlappedDataWaiting();
+ debug(F101,"nettchk count w/overlapped","",count);
+#endif /* NT_TCP_OVERLAPPED */
+
+#ifdef OS2
+#ifndef IKSDONLY
+ if ( IsConnectMode() ) {
+ debug(F101,"nettchk (FIONREAD) returns","",count);
+ return(count);
+ }
+#endif /* IKSDONLY */
+#endif /* OS2 */
+
+/* For the sake of efficiency, if there is still data in the ttibuf */
+/* do not go to the bother of checking to see of the connection is */
+/* still valid. The handle is still good, so just return the count */
+/* of the bytes that we already have left to process. */
+#ifdef OS2
+ if ( count > 0 || ttibn > 0 ) {
+ count+=ttibn;
+ debug(F101,"nettchk (count+ttibn > 0) returns","",count);
+ return(count);
+ } else {
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+ if ( ttibn == 0 )
+ ttibp = 0; /* reset for next read */
+ }
+#else /* OS2 */
+ if ( count > 0 || ttibn > 0 ) {
+ debug(F101,"nettchk returns","",count+ttibn);
+ return(count+ttibn);
+ }
+ ttibn = ttibp = 0;
+#endif /* OS2 */
+
+/*
+ The following code works well in most settings, but messes things up in
+ others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
+ make it impossible to ever make a new connection to the same host again with
+ CONNECT, once it has been logged out from the first time. Not even if you
+ HANGUP first, or SET HOST<CR>, or SET LINE<CR>. Reportedly, however, it
+ does work OK in later releases of UCX. But there is no way we can
+ accommodate both old and new -- we might have static linking or dynamic
+ linking, etc etc. If we have static, I only have access to 2.0, where this
+ doesn't work, etc etc blah blah.
+
+ In the following lines, we define a symbol NOCOUNT for builds where we want
+ to omit this code. By default, it is omitted for CMU/Tek. You can force
+ omission of it for other combinations by defining NOCOUNT in CFLAGS. You
+ can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
+ in CFLAGS.
+*/
+#ifdef NONOCOUNT
+#ifdef NOCOUNT
+#undef NOCOUNT
+#endif /* NOCOUNT */
+#else
+#ifndef NOCOUNT
+#ifdef CMU_TCPIP
+#define NOCOUNT
+#endif /* CMU_TCPIP */
+#endif /* NOCOUNT */
+#endif /* NONOCOUNT */
+
+
+ /* From this point forward we have a possible race condition in K95
+ * due to its use of multiple threads. Therefore, we must ensure
+ * that only one thread attempt to read/write from the socket at a
+ * time. Otherwise, it is possible for a buffer to be overwritten.
+ */
+ /* we know now that count >= 0 and that ttibn == 0 */
+
+ if (count == 0
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+ && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ int s_errno = 0;
+#ifndef NOCOUNT
+/*
+ Here we need to tell the difference between a 0 count on an active
+ connection, and a 0 count because the remote end of the socket broke the
+ connection. There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
+ the status of the connection, so we have to do a read. -1 means there was
+ no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
+ down. But if, by chance, we actually get a character, we have to put it
+ where it won't be lost.
+*/
+#ifndef NON_BLOCK_IO
+#ifdef OS2
+#ifdef CK_SSL
+ RequestSSLMutex(SEM_INDEFINITE_WAIT);
+#endif /* CK_SSL */
+#endif /* OS2 */
+ y = 1; /* Turn on nonblocking reads */
+ z = socket_ioctl(ttyfd,FIONBIO,&y);
+ debug(F111,"nettchk FIONBIO","on",z);
+#ifdef OS2
+#ifdef CK_SSL
+ ReleaseSSLMutex();
+#endif /* CK_SSL */
+#endif /* OS2 */
+#endif /* NON_BLOCK_IO */
+#ifdef NT_TCP_OVERLAPPED
+ ionoblock = 1; /* For Overlapped I/O */
+#endif /* NT_TCP_OVERLAPPED */
+#ifdef CK_SSL
+ if ( ssl_active_flag || tls_active_flag ) {
+#ifdef OS2
+ ssl_read:
+ x = SSL_read( ssl_active_flag?ssl_con:tls_con,
+ &ttibuf[ttibp+ttibn],
+ TTIBUFL-ttibp-ttibn );
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
+ case SSL_ERROR_NONE:
+ debug(F111,"nettchk SSL_ERROR_NONE","x",x);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
+ x = -1;
+ break;
+ case SSL_ERROR_WANT_READ:
+ debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
+ x = -1;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if ( x == 0 ) { /* EOF */
+ netclos();
+ rc = -1;
+ goto nettchk_return;
+ } else {
+#ifdef NT
+ int gle = GetLastError();
+#endif /* NT */
+#ifndef NON_BLOCK_IO
+#ifdef OS2
+#ifdef CK_SSL
+ RequestSSLMutex(SEM_INDEFINITE_WAIT);
+#endif /* CK_SSL */
+#endif /* OS2 */
+ y = 0; /* Turn off nonblocking reads */
+ z = socket_ioctl(ttyfd,FIONBIO,&y);
+ debug(F111,"nettchk FIONBIO","off",z);
+#ifdef OS2
+#ifdef CK_SSL
+ ReleaseSSLMutex();
+#endif /* CK_SSL */
+#endif /* OS2 */
+#endif /* NON_BLOCK_IO */
+#ifdef NT_TCP_OVERLAPPED
+ ionoblock = 0; /* For Overlapped I/O */
+#endif /* NT_TCP_OVERLAPPED */
+#ifdef NT
+ debug(F111,"nettchk SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ rc = -1;
+ goto nettchk_return;
+#endif /* NT */
+ break;
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
+ break;
+ case SSL_ERROR_SSL:
+ if (bio_err!=NULL) {
+ int len;
+ extern char ssl_err[];
+ BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
+ if (ssl_debug_flag)
+ printf(ssl_err);
+ } else if (ssl_debug_flag) {
+ debug(F100,"nettchk SSL_ERROR_SSL","",0);
+ fflush(stderr);
+ fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
+ ERR_print_errors_fp(stderr);
+ }
+#ifdef COMMENT
+ netclos();
+ rc = -1;
+ goto nettchk_return;
+#else
+ x = -1;
+ break;
+#endif
+ case SSL_ERROR_ZERO_RETURN:
+ debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
+ netclos();
+ rc = -1;
+ goto nettchk_return;
+ default:
+ debug(F100,"nettchk SSL_ERROR_?????","",0);
+ netclos();
+ rc = -1;
+ goto nettchk_return;
+ }
+#else /* OS2 */
+ /* Do not block */
+ x = -1;
+#endif /* OS2 */
+ } else
+#endif /* CK_SSL */
+ {
+#ifdef OS2
+ x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
+ TTIBUFL-ttibp-ttibn); /* Returns -1 if no data */
+#else /* OS2 */
+ x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
+#endif /* OS2 */
+ }
+ s_errno = socket_errno; /* socket_errno may be a function */
+ debug(F101,"nettchk socket_read","",x);
+
+#ifndef NON_BLOCK_IO
+#ifdef OS2
+#ifdef CK_SSL
+ RequestSSLMutex(SEM_INDEFINITE_WAIT);
+#endif /* CK_SSL */
+#endif /* OS2 */
+ y = 0; /* Turn off nonblocking reads */
+ z = socket_ioctl(ttyfd,FIONBIO,&y);
+ debug(F111,"nettchk FIONBIO","off",z);
+#ifdef OS2
+#ifdef CK_SSL
+ ReleaseSSLMutex();
+#endif /* CK_SSL */
+#endif /* OS2 */
+#endif /* NON_BLOCK_IO */
+#ifdef NT_TCP_OVERLAPPED
+ ionoblock = 0; /* For Overlapped I/O */
+#endif /* NT_TCP_OVERLAPPED */
+
+ if (x == -1) {
+ debug(F101,"nettchk socket_read errno","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0) {
+ rc = -1;
+ goto nettchk_return;
+ }
+#endif /* OS2 */
+ } else if (x == 0) {
+ debug(F100,"nettchk connection closed","",0);
+ netclos(); /* *** *** */
+ rc = -1;
+ goto nettchk_return;
+ }
+ if (x >= 1) { /* Oops, actually got a byte? */
+#ifdef OS2
+ /* In OS/2 we read directly into ttibuf[] */
+ ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
+ ttibn += x;
+#else /* OS2 */
+#ifdef CK_SSL
+ if ( ssl_active_flag || tls_active_flag ) {
+ ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
+ ttibn += x;
+ } else
+#endif /* CK_SSL */
+ {
+ debug(F101,"nettchk socket_read char","",c);
+ debug(F101,"nettchk ttibp","",ttibp);
+ debug(F101,"nettchk ttibn","",ttibn);
+/*
+ In the case of Overlapped I/O the character would have come from
+ the beginning of the buffer, so put it back.
+*/
+ if (ttibp > 0) {
+ ttibp--;
+ ttibuf[ttibp] = c;
+ ttibn++;
+ } else {
+ ttibuf[ttibp+ttibn] = c;
+ ttibn++;
+ }
+ }
+#endif /* OS2 */
+ }
+#else /* NOCOUNT */
+ if (ttnet == NET_TCPB) {
+ char dummy;
+ x = read(ttyfd,&dummy,0); /* Try to read nothing */
+ if (x < 0) { /* "Connection reset by peer" */
+ perror("TCP/IP"); /* or somesuch... */
+ ttclos(0); /* Close our end too. */
+ rc = -1;
+ goto nettchk_return;
+ }
+ }
+#endif /* NOCOUNT */
+ }
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN)
+ count += krb4_des_avail(ttyfd);
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN)
+ count += krb5_des_avail(ttyfd);
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U)
+ count += krb5_u2u_avail(ttyfd);
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+ debug(F101,"nettchk returns","",count+ttibn);
+ rc = count + ttibn;
+
+ nettchk_return:
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(rc);
+
+#else /* Not TCPIPLIB */
+/*
+ UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
+ seem to work OK.
+*/
+ return(ttchk());
+#endif /* TCPIPLIB */
+/*
+ But what about X.25?
+*/
+}
+
+#ifndef OS2
+VOID
+nettout(i) int i; { /* Catch the alarm interrupts */
+ debug(F100,"nettout caught timeout","",0);
+ ttimoff();
+ cklongjmp(njbuf, -1);
+}
+#endif /* !OS2 */
+
+#ifdef TCPIPLIB
+
+VOID
+#ifdef CK_ANSIC
+donetinc(void * threadinfo)
+#else /* CK_ANSIC */
+donetinc(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* donetinc */ {
+#ifdef NTSIG
+ extern int TlsIndex;
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ }
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+ while (1) {
+ if (ttbufr() < 0) /* Keep trying to refill it. */
+ break; /* Till we get an error. */
+ if (ttibn > 0) /* Or we get a character. */
+ break;
+ }
+}
+#endif /* TCPIPLIB */
+
+VOID
+#ifdef CK_ANSIC
+failnetinc(void * threadinfo)
+#else /* CK_ANSIC */
+failnetinc(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failnetinc */ {
+ ; /* Nothing to do on an error */
+}
+
+/* N E T X I N -- Input block of characters from network */
+
+int
+netxin(n,buf) int n; CHAR * buf; {
+ int len, i, j;
+#ifdef TCPIPLIB
+ int rc;
+#endif /* TCPIPLIB */
+
+ if (ttyfd == -1) {
+ debug(F100,"netxin socket is closed","",0);
+ return(-2);
+ }
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef TCPIPLIB
+#ifdef OS2
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+#endif /* OS2 */
+ if (ttibn == 0)
+ if ((rc = ttbufr()) <= 0) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(rc);
+ }
+
+ if (ttibn <= n) {
+ len = ttibn;
+ memcpy(buf,&ttibuf[ttibp],len); /* safe */
+ ttibp += len;
+ ttibn = 0;
+ } else {
+ memcpy(buf,&ttibuf[ttibp],n); /* safe */
+ ttibp += n;
+ ttibn -= n;
+ len = n;
+ }
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+#else /* TCPIPLIB */
+ for (i = 0; i < n; i++) {
+ if ((j = netinc(0)) < 0) {
+ if (j < -1)
+ return(j);
+ else
+ break;
+ }
+ buf[i] = j;
+ }
+ len = i;
+#endif /* TCPIPLIB */
+
+#ifdef COMMENT
+#ifdef CK_ENCRYPTION
+ /* This would be great if it worked. But what if the buffer we read */
+ /* contains a telnet negotiation that changes the state of the */
+ /* encryption. If so, we would be either decrypting unencrypted text */
+ /* or not decrypting encrypted text. So we must move this call to */
+ /* all functions that call ttxin(). In OS2 that means os2_netxin() */
+ /* where the Telnet Negotiations are handled. */
+ if (u_encrypt)
+ ck_tn_decrypt(buf,len);
+#endif /* CK_ENCRYPTION */
+#endif /* COMMENT */
+
+ return(len);
+}
+
+/* N E T I N C -- Input character from network */
+
+#ifdef NETLEBUF
+#define LEBUF
+#endif /* NETLEBUF */
+#ifdef TTLEBUF
+#define LEBUF
+#endif /* TTLEBUF */
+#ifndef LEBUF
+#ifdef OS2
+#define LEBUF
+#endif /* OS2 */
+#endif /* LEBUF */
+
+int
+netinc(timo) int timo; {
+#ifdef TCPIPLIB
+ int x; unsigned char c; /* The locals. */
+
+#ifdef NETLEBUF
+ if (ttpush >= 0) {
+ debug(F111,"netinc","ttpush",ttpush);
+ c = ttpush;
+ ttpush = -1;
+ return(c);
+ }
+ if (le_data) {
+ if (le_getchar((CHAR *)&c) > 0) {
+ debug(F111,"netinc le_getchar","c",c);
+ return(c);
+ }
+ }
+#endif /* NETLEBUF */
+
+ if (ttyfd == -1) {
+ debug(F100,"netinc socket is closed","",0);
+ return(-2);
+ }
+
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
+ return(-1);
+ else if (x < 0)
+ return(-2);
+ else
+ return(c);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
+ return(-1);
+ else if (x < 0)
+ return(-2);
+ else
+ return(c);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
+ return(-1);
+ else if (x < 0)
+ return(-2);
+ else
+ return(c);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef OS2
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+#endif /* OS2 */
+ if (ttibn > 0) { /* Something in internal buffer? */
+#ifdef COMMENT
+ debug(F100,"netinc char in buf","",0); /* Yes. */
+#endif /* COMMENT */
+ x = 0; /* Success. */
+ } else { /* Else must read from network. */
+ x = -1; /* Assume failure. */
+#ifdef DEBUG
+ debug(F101,"netinc goes to net, timo","",timo);
+#endif /* DEBUG */
+#ifdef CK_SSL
+ /*
+ * In the case of OpenSSL, it is possible that there is still
+ * data waiting in the SSL session buffers that has not yet
+ * been read by Kermit. If this is the case we must process
+ * it without calling select() because select() will not return
+ * with an indication that there is data to be read from the
+ * socket. If there is no data pending in the SSL session
+ * buffers then fall through to the select() code and wait for
+ * some data to arrive.
+ */
+ if (ssl_active_flag) {
+ x = SSL_pending(ssl_con);
+ if (x < 0) {
+ debug(F111,"netinc","SSL_pending error",x);
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ } else if ( x > 0 ) {
+ if ( ttbufr() >= 0 ) {
+ x = netinc(timo);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(x);
+ }
+ }
+ x = -1;
+ } else if (tls_active_flag) {
+ x = SSL_pending(tls_con);
+ if (x < 0) {
+ debug(F111,"netinc","TLS_pending error",x);
+ netclos();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ } else if ( x > 0 ) {
+ if ( ttbufr() >= 0 ) {
+ x = netinc(timo);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(x);
+ }
+ }
+ x = -1;
+ }
+#endif /* CK_SSL */
+#ifndef LEBUF
+ if (timo == 0) { /* Untimed case. */
+ while (1) { /* Wait forever if necessary. */
+ if (ttbufr() < 0) /* Refill buffer. */
+ break; /* Error, fail. */
+ if (ttibn > 0) { /* Success. */
+ x = 0;
+ break;
+ }
+ }
+ } else /* Timed case... */
+#endif /* LEBUF */
+ {
+#ifdef NT_TCP_OVERLAPPED
+ /* This code is for use on NT when we are using */
+ /* Overlapped I/O to handle reads. In the case */
+ /* of outstanding reads select() doesn't work */
+
+ if (WaitForOverlappedReadData(timo)) {
+ while (1) {
+ if (ttbufr() < 0) /* Keep trying to refill it. */
+ break; /* Till we get an error. */
+ if (ttibn > 0) { /* Or we get a character. */
+ x = 0;
+ break;
+ }
+ }
+ }
+#else /* NT_TCP_OVERLAPPED */
+#ifdef BSDSELECT
+ fd_set rfds;
+ struct timeval tv;
+ int timeout = timo < 0 ? -timo : 1000 * timo;
+ debug(F101,"netinc BSDSELECT","",timo);
+
+ for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
+ int rc;
+ debug(F111,"netinc","timeout",timeout);
+ /* Don't move select() initialization out of the loop. */
+ FD_ZERO(&rfds);
+ FD_SET(ttyfd, &rfds);
+ tv.tv_sec = tv.tv_usec = 0L;
+ if (timo)
+ tv.tv_usec = (long) 100000L;
+ else
+ tv.tv_sec = 30;
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+ rc = select(FD_SETSIZE,
+#ifdef __DECC
+#ifdef INTSELECT
+ (int *)
+#else /* def INTSELECT */
+ (fd_set *)
+#endif /* def INTSELECT [else] */
+#else /* def __DECC */
+ (fd_set *)
+#endif /* def __DECC [else] */
+ &rfds, NULL, NULL, &tv);
+ if (rc < 0) {
+ int s_errno = socket_errno;
+ debug(F111,"netinc","select",rc);
+ debug(F111,"netinc","socket_errno",s_errno);
+ if (s_errno) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ }
+ }
+ debug(F111,"netinc","select",rc);
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+ if (!FD_ISSET(ttyfd, &rfds)) {
+#ifdef LEBUF
+ if (le_inbuf() > 0) {
+ timeout = -1;
+ break;
+ }
+#endif /* LEBUF */
+ /* If waiting forever we have no way of knowing if the */
+ /* socket closed so try writing a 0-length TCP packet */
+ /* which should force an error if the socket is closed */
+ if (!timo) {
+ if ((rc = socket_write(ttyfd,"",0)) < 0) {
+ int s_errno = socket_errno;
+ debug(F101,"netinc socket_write error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0) {
+ ReleaseTCPIPMutex();
+ return(-2);
+ }
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1); /* Call it an i/o error */
+ }
+ }
+ continue;
+ }
+ while (1) {
+ if (ttbufr() < 0) { /* Keep trying to refill it. */
+ timeout = -1;
+ break; /* Till we get an error. */
+ }
+ if (ttibn > 0) { /* Or we get a character. */
+ x = 0;
+ timeout = -1;
+ break;
+ }
+ }
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#else /* !BSDSELECT */
+#ifdef IBMSELECT
+/*
+ Was used by OS/2, currently not used, but might come in handy some day...
+ ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
+ and timeval stuff since this is the only place where it is used.
+*/
+ int socket = ttyfd;
+ int timeout = timo < 0 ? -timo : 1000 * timo;
+
+ debug(F101,"netinc IBMSELECT","",timo);
+ for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
+ if (select(&socket, 1, 0, 0, 100L) == 1) {
+ while (1) {
+ if (ttbufr() < 0) { /* Keep trying to refill it. */
+ timeout = -1;
+ break; /* Till we get an error. */
+ }
+ if (ttibn > 0) { /* Or we get a character. */
+ x = 0;
+ timeout = -1;
+ break;
+ }
+ }
+ }
+#ifdef LEBUF
+ else if (le_inbuf() > 0) {
+ timeout = -1;
+ break;
+ }
+#endif /* LEBUF */
+ }
+#else /* !IBMSELECT */
+#ifdef WINSOCK
+ /* Actually, under WinSock we have a better mechanism than select() */
+ /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
+ SOCKET socket = ttyfd;
+ debug(F101,"netinc NTSELECT","",timo);
+ if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
+ sizeof(timo)) == NO_ERROR)
+ while (1) {
+ if (ttbufr() < 0) /* Keep trying to refill it. */
+ break; /* Till we get an error. */
+ if (ttibn > 0) { /* Or we get a character. */
+ x = 0;
+ break;
+ }
+ }
+#else /* WINSOCK */
+/*
+ If we can't use select(), then we use the regular alarm()/signal()
+ timeout mechanism.
+*/
+ debug(F101,"netinc alarm","",timo);
+ x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
+ ttimoff(); /* Timer off. */
+#endif /* WINSOCK */
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+#endif /* NT_TCP_OVERLAPPED */
+ }
+ }
+
+#ifdef LEBUF
+ if (le_inbuf() > 0) { /* If data was inserted into the */
+ if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the */
+#ifdef OS2 /* was taking place do not mix */
+ ReleaseTCPIPMutex(); /* the le data with the net data */
+#endif /* OS2 */
+ return(c);
+ }
+ }
+#endif /* LEBUF */
+ if (x < 0) { /* Return -1 if we failed. */
+ debug(F100,"netinc timed out","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ } else { /* Otherwise */
+ c = ttibuf[ttibp]; /* Return the first char in ttibuf[] */
+ if (deblog) {
+#ifndef COMMENT
+ debug(F101,"netinc returning","",c);
+#endif /* COMMENT */
+ if (c == 0) {
+ debug(F101,"netinc 0 ttibn","",ttibn);
+ debug(F101,"netinc 0 ttibp","",ttibp);
+#ifdef BETADEBUG
+ {
+#ifdef OS2
+ extern int tt_type_mode;
+ if ( !ISVTNT(tt_type_mode) )
+#endif /* OS2 */
+ ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
+ }
+#endif /* BETADEBUG */
+ }
+ }
+ ttibp++;
+ ttibn--;
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt(&c,1);
+#endif /* CK_ENCRYPTION */
+ return(c);
+ }
+#else /* Not using TCPIPLIB */
+ return(-1);
+#endif /* TCPIPLIB */
+}
+
+/* N E T T O L -- Output a string of bytes to the network */
+/*
+ Call with s = pointer to string, n = length.
+ Returns number of bytes actually written on success, or
+ -1 on i/o error, -2 if called improperly.
+*/
+
+int
+nettol(s,n) CHAR *s; int n; {
+#ifdef TCPIPLIB
+ int count = 0;
+ int len = n;
+ int try = 0;
+
+ if (ttyfd == -1) {
+ debug(F100,"nettol socket is closed","",0);
+ return -1;
+ }
+ debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
+#ifdef COMMENT
+ ckhexdump("nettol",s,n);
+#endif /* COMMENT */
+
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ return(krb4_des_write(ttyfd,s,n));
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ return(krb5_des_write(ttyfd,s,n,0));
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ return(krb5_u2u_write(ttyfd,s,n));
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef CK_ENCRYPTION
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(s,n);
+#endif /* CK_ENCRYPTION */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, r;
+ /* Write using SSL */
+ ssl_retry:
+ if (ssl_active_flag)
+ r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
+ else
+ r = SSL_write(tls_con, s, len /* >1024?1024:len */);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
+ case SSL_ERROR_NONE:
+ debug(F111,"nettol","SSL_write",r);
+ if ( r == len )
+ return(n);
+ s += r;
+ len -= r;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
+ return(-1);
+ case SSL_ERROR_WANT_READ:
+ debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if ( r == 0 ) { /* EOF */
+ netclos();
+ return(-2);
+ } else {
+ int rc = -1;
+#ifdef NT
+ int gle = GetLastError();
+ debug(F111,"nettol SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ rc = -1;
+#endif /* NT */
+ return(rc);
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
+ netclos();
+ return(-2);
+ case SSL_ERROR_SSL:
+ debug(F100,"nettol SSL_ERROR_SSL","",0);
+ if (bio_err!=NULL) {
+ int len;
+ extern char ssl_err[];
+ BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
+ if (ssl_debug_flag)
+ printf(ssl_err);
+ } else if (ssl_debug_flag) {
+ debug(F100,"nettol SSL_ERROR_SSL","",0);
+ fflush(stderr);
+ fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
+ ERR_print_errors_fp(stderr);
+ }
+#ifdef COMMENT
+ netclos();
+ return(-2);
+#else
+ return(-1);
+#endif
+ case SSL_ERROR_ZERO_RETURN:
+ debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
+ netclos();
+ return(-2);
+ default:
+ debug(F100,"nettol SSL_ERROR_?????","",0);
+ netclos();
+ return(-2);
+ }
+ }
+#endif /* CK_SSL */
+
+ nettol_retry:
+ try++; /* Increase the try counter */
+
+ if (ttnet == NET_TCPB) {
+#ifdef BSDSELECT
+ fd_set wfds;
+ struct timeval tv;
+
+ debug(F101,"nettol BSDSELECT","",0);
+ tv.tv_usec = 0L;
+ tv.tv_sec=30;
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+#ifdef STREAMING
+ do_select:
+#endif /* STREAMING */
+ FD_ZERO(&wfds);
+ FD_SET(ttyfd, &wfds);
+ if (select(FD_SETSIZE, NULL,
+#ifdef __DECC
+#ifndef __DECC_VER
+ (int *)
+#endif /* __DECC_VER */
+#endif /* __DECC */
+ &wfds, NULL, &tv) < 0) {
+ int s_errno = socket_errno;
+ debug(F101,"nettol select failed","",s_errno);
+#ifdef BETADEBUG
+ printf("nettol select failed: %d\n", s_errno);
+#endif /* BETADEBUG */
+#ifdef NT
+ WSASafeToCancel = 0;
+ if (!win95selectbug)
+#endif /* NT */
+ return(-1);
+ }
+ if (!FD_ISSET(ttyfd, &wfds)) {
+#ifdef STREAMING
+ if (streaming)
+ goto do_select;
+#endif /* STREAMING */
+ debug(F111,"nettol","!FD_ISSET",ttyfd);
+#ifdef NT
+ WSASafeToCancel = 0;
+ if (!win95selectbug)
+#endif /* NT */
+ return(-1);
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#else /* BSDSELECT */
+#ifdef IBMSELECT
+ {
+ int tries = 0;
+ debug(F101,"nettol IBMSELECT","",0);
+ while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
+ int count;
+ if (tries++ >= 60) {
+ /* if after 60 seconds we can't get permission to write */
+ debug(F101,"nettol select failed","",socket_errno);
+ return(-1);
+ }
+ if ((count = nettchk()) < 0) {
+ debug(F111,"nettol","nettchk()",count);
+ return(count);
+ }
+ }
+ }
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+ if ((count = socket_write(ttyfd,s,n)) < 0) {
+ int s_errno = socket_errno; /* maybe a function */
+ debug(F101,"nettol socket_write error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-2);
+#endif /* OS2 */
+ return(-1); /* Call it an i/o error */
+ }
+ if (count < n) {
+ debug(F111,"nettol socket_write",s,count);
+ if (try > 25) {
+ /* don't try more than 25 times */
+ debug(F100,"nettol tried more than 25 times","",0);
+ return(-1);
+ }
+ if (count > 0) {
+ s += count;
+ n -= count;
+ }
+ debug(F111,"nettol retry",s,n);
+ goto nettol_retry;
+ } else {
+ debug(F111,"nettol socket_write",s,count);
+ return(len); /* success - return total length */
+ }
+ } else
+ return(-2);
+#else
+ debug(F100,"nettol TCPIPLIB not defined","",0);
+ return(-2);
+#endif /* TCPIPLIB */
+}
+
+/* N E T T O C -- Output character to network */
+/*
+ Call with character to be transmitted.
+ Returns 0 if transmission was successful, or
+ -1 upon i/o error, or -2 if called improperly.
+*/
+int
+#ifdef CK_ANSIC
+nettoc(CHAR c)
+#else
+nettoc(c) CHAR c;
+#endif /* CK_ANSIC */
+/* nettoc */ {
+#ifdef UNIX
+ return(ttoc(c));
+#else
+#ifdef TCPIPLIB
+ unsigned char cc;
+ if (ttyfd == -1) {
+ debug(F100,"nettoc socket is closed","",0);
+ return -1;
+ }
+ cc = c;
+ debug(F101,"nettoc cc","",cc);
+
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef CK_ENCRYPTION
+ if ( TELOPT_ME(TELOPT_ENCRYPTION) )
+ ck_tn_encrypt(&cc,1);
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int len, error;
+ /* Write using SSL */
+ ssl_retry:
+ if (ssl_active_flag)
+ len = SSL_write(ssl_con, &cc, 1);
+ else
+ len = SSL_write(tls_con, &cc, 1);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
+ case SSL_ERROR_NONE:
+ debug(F111,"nettoc","SSL_write",len);
+ return(len == 1 ? 0 : -1);
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if ( len == 0 ) { /* EOF */
+ netclos();
+ return(-2);
+ } else {
+ int rc = -1;
+#ifdef NT
+ int gle = GetLastError();
+ debug(F111,"nettoc SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ rc = -1;
+#endif /* NT */
+ return(rc);
+ }
+ case SSL_ERROR_SSL:
+ if (bio_err!=NULL) {
+ int len;
+ extern char ssl_err[];
+ BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
+ ERR_print_errors(bio_err);
+ len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
+ ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
+ debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
+ if (ssl_debug_flag)
+ printf(ssl_err);
+ } else if (ssl_debug_flag) {
+ debug(F100,"nettoc SSL_ERROR_SSL","",0);
+ fflush(stderr);
+ fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
+ ERR_print_errors_fp(stderr);
+ }
+ return(-1);
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ netclos();
+ return(-2);
+ }
+ }
+#endif /* CK_SSL */
+ if (ttnet == NET_TCPB) {
+#ifdef BSDSELECT
+ fd_set wfds;
+ struct timeval tv;
+
+ debug(F101,"nettoc BSDSELECT","",0);
+ tv.tv_usec = 0L;
+ tv.tv_sec = 30;
+
+#ifdef STREAMING
+ do_select:
+#endif /* STREAMING */
+
+ FD_ZERO(&wfds);
+ FD_SET(ttyfd, &wfds);
+ if (select(FD_SETSIZE, NULL,
+#ifdef __DECC
+#ifndef __DECC_VER
+ (int *)
+#endif /* __DECC_VER */
+#endif /* __DECC */
+ &wfds, NULL, &tv) < 0) {
+ int s_errno = socket_errno;
+ debug(F101,"nettoc select failed","",s_errno);
+#ifdef BETADEBUG
+ printf("nettoc select failed: %d\n", s_errno);
+#endif /* BETADEBUG */
+#ifdef NT
+ WSASafeToCancel = 0;
+ if (!win95selectbug)
+#endif /* NT */
+ return(-1);
+ }
+ if (!FD_ISSET(ttyfd, &wfds)) {
+#ifdef STREAMING
+ if (streaming)
+ goto do_select;
+#endif /* STREAMING */
+ debug(F111,"nettoc","!FD_ISSET",ttyfd);
+#ifdef NT
+ WSASafeToCancel = 0;
+ if (!win95selectbug)
+#endif /* NT */
+ return(-1);
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#else /* BSDSELECT */
+#ifdef IBMSELECT
+ {
+ int tries = 0;
+ while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
+ int count;
+ if (tries++ >= 60) {
+ /* if after 60 seconds we can't get permission to write */
+ debug(F101,"nettoc select failed","",socket_errno);
+ return(-1);
+ }
+ if ((count = nettchk()) < 0) {
+ debug(F111,"nettoc","nettchk()",count);
+ return(count);
+ }
+ }
+ }
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+ if (socket_write(ttyfd,&cc,1) < 1) {
+ int s_errno = socket_errno; /* maybe a function */
+ debug(F101,"nettoc socket_write error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-2);
+#endif /* OS2 */
+ return(-1);
+ }
+ debug(F101,"nettoc socket_write","", cc);
+ return(0);
+ } else return(-2);
+#else
+ return(-2);
+#endif /* TCPIPLIB */
+#endif /* UNIX */
+}
+
+/* N E T F L U I -- Flush network input buffer */
+
+#ifdef TNCODE
+static int
+#ifdef CK_ANSIC
+netgetc(int timo) /* Input function to point to... */
+#else /* CK_ANSIC */
+netgetc(timo) int timo;
+#endif /* CK_ANSIC */
+{ /* ...in the tn_doop() call */
+#ifdef TCPIPLIB
+ return netinc(timo);
+#else /* TCPIPLIB */
+ return ttinc(timo);
+#endif /* TCPIPLIB */
+}
+#endif /* TNCODE */
+
+int
+netflui() {
+ int n;
+ int ch;
+#ifdef NETLEBUF
+ ttpush = -1; /* Clear the peek-ahead char */
+ while (le_data && (le_inbuf() > 0)) {
+ CHAR ch = '\0';
+ if (le_getchar(&ch) > 0) {
+ debug(F101,"ttflui le_inbuf ch","",ch);
+ }
+ }
+#endif /* NETLEBUF */
+
+#ifdef TCPIPLIB
+#ifdef OS2
+ RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
+#endif /* OS2 */
+#ifdef TNCODE
+ if (ttnproto == NP_TELNET) {
+ /* Netflui must process Telnet negotiations or get out of sync */
+ if ((n = nettchk()) <= 0)
+ goto exit_flui;
+ while (n-- > 0) {
+ ch = netinc(1);
+ if (ch == IAC) {
+ extern int duplex; /* this really shouldn't be here but ... */
+ int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
+ if (tx == 1) duplex = 1;
+ else if (tx == 2) duplex = 0;
+ n = nettchk();
+ }
+ }
+ } else
+#endif /* TNCODE */
+ {
+ ttibuf[ttibp+ttibn] = '\0';
+ debug(F111,"netflui 1",ttibuf,ttibn);
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ ck_tn_decrypt(&ttibuf[ttibp],ttibn);
+ }
+#endif /* CK_ENCRYPTION */
+ ttibn = ttibp = 0; /* Flush internal buffer *FIRST* */
+ if (ttyfd < 1)
+ goto exit_flui;
+ if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */
+ if (n > TTIBUFL) n = TTIBUFL; /* and sponge it up */
+ debug(F101,"netflui 2","",n); /* ... */
+ n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
+ if (n >= 0) ttibuf[n] = '\0';
+ debug(F111,"netflui 3",ttibuf,n);
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ ck_tn_decrypt(&ttibuf[ttibp],n);
+ }
+#endif /* CK_ENCRYPTION */
+ ttibuf[0] = '\0';
+ }
+ }
+#else /* !TCPIPLIB */
+ if (ttyfd < 1)
+ goto exit_flui;
+#ifdef TNCODE
+ if (ttnproto == NP_TELNET) {
+ if ((n = ttchk()) <= 0)
+ goto exit_flui;
+ while (n-- >= 0) {
+ /* Netflui must process Telnet negotiations or get out of sync */
+ ch = ttinc(1);
+ if (ch == IAC) {
+ extern int duplex; /* this really shouldn't be here but ... */
+ int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
+ if (tx == 1) duplex = 1;
+ else if (tx == 2) duplex = 0;
+ n = ttchk();
+ }
+ };
+ } else
+#endif /* TNCODE */
+ if ((n = ttchk()) > 0) {
+ debug(F101,"netflui non-TCPIPLIB","",n);
+ while ((n--) && ttinc(1) > -1) /* Don't worry, ttinc() is buffered */
+ ; /* and it handles the decryption... */
+ }
+#endif /* TCPIPLIB */
+ exit_flui:
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(0);
+}
+
+#ifdef CK_KERBEROS
+/* The following two functions are required for encrypted rlogin */
+/* They are called with nettoc() or nettol() are transmitting */
+/* encrypted data. They call a function to encrypt the data */
+/* and that function needs to be able to write to/read from the */
+/* network in an unimpeded manner. Hence, these two simple fns. */
+int
+net_write(fd, buf, len)
+ int fd;
+ register const char *buf;
+ int len;
+{
+ int cc;
+ register int wrlen = len;
+ do {
+#ifdef TCPIPLIB
+ cc = socket_write(fd, buf, wrlen);
+#else
+ cc = write(fd,buf,wrlen);
+#endif /* TCPIPLIB */
+ if (cc < 0) {
+ int s_errno = socket_errno;
+ debug(F101,"net_write error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-1);
+ else
+ continue;
+#else /* OS2 */
+ if (errno == EINTR)
+ continue;
+ return(-1);
+#endif /* OS2 */
+ }
+ else {
+ buf += cc;
+ wrlen -= cc;
+ }
+ } while (wrlen > 0);
+ return(len);
+}
+int
+net_read(fd, buf, len)
+ int fd;
+ register char *buf;
+ register int len;
+{
+ int cc, len2 = 0;
+
+ do {
+#ifdef TCPIPLIB
+ cc = socket_read(fd, buf, len);
+#else
+ cc = read(fd,buf,len);
+#endif
+ if (cc < 0) {
+ int s_errno = socket_errno;
+ debug(F101,"net_read error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-1);
+#endif /* OS2 */
+ return(cc); /* errno is already set */
+ }
+ else if (cc == 0) {
+ netclos();
+ return(len2);
+ } else {
+ buf += cc;
+ len2 += cc;
+ len -= cc;
+ }
+ } while (len > 0);
+ return(len2);
+}
+#endif /* CK_KERBEROS */
+#endif /* NONET */
+
+/* getlocalipaddr() attempts to resolve an IP Address for the local machine.
+ * If the host is multi-homed it returns only one address.
+ *
+ * Two techniques are used.
+ * (1) get the local host name and perform a DNS lookup, then take
+ * the first entry;
+ * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
+ * no data is sent), then retrieve the local address from the socket.
+ * Note: the second technique won't work on Microsoft systems. See
+ * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
+ */
+
+/* Technique number one cannot work reliably if the machine is a laptop
+ * and the hostname is associated with a physical adapter which is not
+ * installed and a PPP connection is being used instead. This is because
+ * the hostname DNS lookup will succeed for the physical adapter even though
+ * it would be impossible to use it. In NT4 SP4, the gethostbyname()
+ * when given the result of gethostname() returns not the real DNS entries
+ * for that name+domain. Instead it returns all of the static and dynamic
+ * IP addresses assigned to any physical or virtual adapter defined in the
+ * system regardless of whether or not it is installed. The order of the
+ * addresses is fixed according to the binding order in the NT registry.
+ */
+
+/*
+ * It appears that calling gethostbyname(NULL) is more reliable than
+ * calling gethostbyname(gethostname()) on Windows. So on Windows we will
+ * only call gethostbyname(NULL).
+ */
+
+int
+getlocalipaddr() {
+#ifndef datageneral
+ struct sockaddr_in l_sa;
+ struct sockaddr_in r_sa;
+ GSOCKNAME_T slen = sizeof(struct sockaddr_in);
+ int sock;
+ int rc;
+ struct in_addr laddr;
+
+ /* if still not resolved, then try second strategy */
+ /* This second strategy does not work on Windows */
+
+ debug(F100,"getlocalipaddr","",0);
+ memset(&l_sa,0,slen);
+ memset(&r_sa,0,slen);
+
+ /* get a UDP socket */
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock != -1) {
+ /* connect to arbirary port and address (NOT loopback) */
+ r_sa.sin_family = AF_INET;
+ r_sa.sin_port = htons(IPPORT_ECHO);
+
+ /* The following is an "illegal conversion" in AOS/VS */
+ /* (and who knows where else) */
+
+#ifdef INADDRX
+ inaddrx = inet_addr("128.127.50.1");
+ r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
+#else
+ r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
+#endif /* INADDRX */
+ rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
+ if (!rc) { /* get local address */
+ getsockname(sock,(struct sockaddr *)&l_sa,&slen);
+#ifdef TCPIPLIB
+ socket_close(sock); /* We're done with the socket */
+#else
+ close(sock);
+#endif /* TCPIPLIB */
+ if (l_sa.sin_addr.s_addr != INADDR_ANY) {
+ myxipaddr = ntohl(l_sa.sin_addr.s_addr);
+ ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
+ debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
+ return(0);
+ }
+ }
+ }
+ return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
+#else /* datageneral */
+ return(-1);
+#endif /* datageneral */
+}
+
+int
+getlocalipaddrs(buf,bufsz,index)
+ char * buf;
+ int bufsz;
+ int index;
+/* getlocalipaddrs */ {
+#ifndef datageneral
+ char localhost[256];
+ struct hostent * host=NULL;
+ struct sockaddr_in l_sa;
+ struct sockaddr_in r_sa;
+ GSOCKNAME_T slen = sizeof(struct sockaddr_in);
+ int rc;
+#ifdef COMMENT
+ int sock;
+ char messageBuf[60];
+ struct in_addr laddr;
+#endif /* COMMENT */
+
+ debug(F100,"getlocalipaddrs","",0);
+ memset(&l_sa,0,slen);
+ memset(&r_sa,0,slen);
+
+ /* init local address (to zero) */
+ l_sa.sin_addr.s_addr = INADDR_ANY;
+
+#ifdef CKGHNLHOST
+ rc = gethostname(localhost, 256);
+ debug(F110,"getlocalipaddrs localhost",localhost,0);
+#else
+ /* This doesn't work on some platforms, e.g. Solaris */
+ rc = 0;
+ localhost[0] = '\0';
+#ifdef NT
+ if ( winsock_version < 20 ) {
+ rc = gethostname(localhost, 256);
+ debug(F110,"getlocalipaddrs localhost",localhost,0);
+ }
+#endif /* NT */
+#endif /* CKGHNLHOST */
+ if (!rc) {
+ /* resolve host name for local address */
+ debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
+ host = gethostbyname(localhost);
+ /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */
+ if (host) {
+#ifdef HADDRLIST
+ host = ck_copyhostent(host);
+ if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
+ buf[0] = '\0';
+ return(-1);
+ }
+ l_sa.sin_addr.s_addr =
+ *((unsigned long *) (host->h_addr_list[index]));
+ ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
+ debug(F110,"getlocalipaddrs setting buf to",buf,0);
+
+#ifdef COMMENT
+ /* This is for reporting multiple IP Address */
+ while (host->h_addr_list && host->h_addr_list[0]) {
+ l_sa.sin_addr.s_addr =
+ *((unsigned long *) (host->h_addr_list[0]));
+ ckstrncpy(messageBuf,
+ (char *)inet_ntoa(l_sa.sin_addr),60);
+ if (tcp_address) {
+ if (!strcmp(messageBuf,tcp_address))
+ ckstrncpy(myipaddr,tcp_address,20);
+ }
+ debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
+ host->h_addr_list++;
+ }
+#endif /* COMMENT */
+#else /* HADDRLIST */
+ if (index != 0) {
+ buf[0] = '\0';
+ return(-1);
+ }
+ l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
+ ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
+ debug(F110,"getlocalipaddrs setting buf to",buf,0);
+#endif /* HADDRLIST */
+ return(0);
+ } else debug(F110,
+ "getlocalipaddrs: gethostbyname() failed",
+ localhost,
+ 0
+ );
+ }
+#endif /* datageneral */
+ return(-1);
+}
+
+#ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */
+int
+rlog_naws() {
+ struct rlog_naws {
+ unsigned char id[4];
+ unsigned short rows, cols, ypix, xpix;
+ } nawsbuf;
+
+ if (ttnet != NET_TCPB)
+ return 0;
+ if (ttnproto != NP_RLOGIN
+#ifdef CK_KERBEROS
+ && ttnproto != NP_K4LOGIN
+ && ttnproto != NP_EK4LOGIN
+ && ttnproto != NP_K5LOGIN
+ && ttnproto != NP_EK5LOGIN
+#endif /* CK_KERBEROS */
+ )
+ return 0;
+ if (!TELOPT_ME(TELOPT_NAWS))
+ return 0;
+
+ debug(F100,"rlogin Window Size sent","",0);
+
+ nawsbuf.id[0] = nawsbuf.id[1] = 0377;
+ nawsbuf.id[2] = nawsbuf.id[3] = 's';
+#ifdef OS2
+ nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
+ -(tt_status[VTERM]?1:0)));
+ nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
+#else /* OS2 */
+ nawsbuf.rows = htons((unsigned short) tt_rows);
+ nawsbuf.cols = htons((unsigned short) tt_cols);
+#endif /* OS2 */
+ nawsbuf.ypix = htons(0); /* y pixels */
+
+ nawsbuf.xpix = htons(0); /* x pixels */
+ if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
+ return(-1);
+ return(0);
+}
+
+#ifdef OS2ORUNIX
+#define RLOGOUTBUF
+#endif /* OS2 */
+static int
+#ifdef CK_ANSIC
+rlog_ini(CHAR * hostname, int port,
+ struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
+#else /* CK_ANSIC */
+rlog_ini(hostname, port, l_addr, r_addr)
+ CHAR * hostname;
+ int port;
+ struct sockaddr_in * l_addr;
+ struct sockaddr_in * r_addr;
+#endif /* CK_ANSIC */
+/* rlog_ini */ {
+
+#ifdef RLOGOUTBUF
+ char outbuf[512];
+ int outbytes=0;
+#endif /* RLOGOUTBUF */
+ int flag = 0;
+#define TERMLEN 16
+#define CONSPDLEN 16
+ CHAR localuser[UIDBUFLEN+1];
+ CHAR remoteuser[UIDBUFLEN+1];
+ int userlen = 0;
+ CHAR term_speed[TERMLEN+CONSPDLEN+1];
+#ifdef CONGSPD
+ long conspd = -1L;
+#endif /* CONGSPD */
+#ifdef OS2
+ extern int tt_type, max_tt;
+ extern struct tt_info_rec tt_info[];
+#endif /* OS2 */
+ int i, n;
+
+ int rc = 0;
+ tn_reset(); /* This call will reset all of the Telnet */
+ /* options and then quit. We need to do */
+ /* this since we use the Telnet options */
+ /* to hold various state information */
+ duplex = 0; /* Rlogin is always remote echo */
+ rlog_inband = 0;
+
+#ifdef CK_TTGWSIZ
+/*
+ But compute the values anyway before the first read since the out-
+ of-band NAWS request would arrive before the first data byte (NULL).
+*/
+#ifdef OS2
+ /* Console terminal screen rows and columns */
+ debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
+ -(tt_status[VTERM]?1:0));
+ debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
+ /* Not known yet */
+ if (VscrnGetWidth(VTERM) < 0 ||
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
+ ttgwsiz(); /* Try to get screen dimensions */
+ }
+ debug(F101,
+ "rlog_ini tt_rows 2",
+ "",
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
+ );
+ debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
+#else /* OS2 */
+ debug(F101,"rlog_ini tt_rows 1","",tt_rows);
+ debug(F101,"rlog_ini tt_cols 1","",tt_cols);
+ if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
+ ttgwsiz(); /* Try to find out */
+ }
+ debug(F101,"rlog_ini tt_rows 2","",tt_rows);
+ debug(F101,"rlog_ini tt_cols 2","",tt_cols);
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ ttflui(); /* Start by flushing the buffers */
+
+ rlog_mode = RL_COOKED;
+
+ /* Determine the user's local username ... */
+
+ localuser[0] = '\0';
+#ifdef NT
+ {
+ char localuid[UIDBUFLEN+1];
+ ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
+ }
+
+ if ( !localuser[0] )
+#endif /* NT */
+ {
+ char * user = getenv("USER");
+ if (!user)
+ user = "";
+ userlen = strlen(user);
+ debug(F111,"rlogin getenv(USER)",user,userlen);
+ ckstrncpy((char *)localuser,user,UIDBUFLEN);
+ debug(F110,"rlog_ini localuser 1",localuser,0);
+ }
+ if ( !localuser[0] )
+ strcpy((char *)localuser,"unknown");
+ else if (ck_lcname) {
+ cklower((char *)localuser);
+ debug(F110,"rlog_ini localuser 2",localuser,0);
+ }
+
+ /* And the username to login with */
+ if (uidbuf[0]) {
+ ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
+ debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
+ } else if (localuser[0]) {
+ ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
+ debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
+ } else {
+ remoteuser[0] = '\0';
+ debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
+ }
+ if (ck_lcname)
+ cklower((char *)remoteuser);
+ debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
+
+ /* The command to issue is the terminal type and speed */
+ term_speed[0] = '\0';
+ if (tn_term) { /* SET TELNET TERMINAL-TYPE value */
+ if (*tn_term) { /* (if any) takes precedence. */
+ ckstrncpy((char *)term_speed, tn_term, TERMLEN);
+ flag = 1;
+ }
+ } else { /* Otherwise the local terminal type */
+#ifdef OS2
+ /* In terminal-emulating versions, it's the SET TERM TYPE value */
+ ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
+ tt_info[tt_type].x_name : "network", TERMLEN);
+#else
+ /* In the others, we just look at the TERM environment variable */
+ {
+ char *p = getenv("TERM");
+ if (p)
+ ckstrncpy((char *)term_speed,p,TERMLEN);
+ else
+ term_speed[0] = '\0';
+#ifdef VMS
+ for (p = (char *) term_speed; *p; p++) {
+ if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
+ break;
+ else if (isupper(*p))
+ *p = tolower(*p);
+ }
+ *p = '\0';
+#endif /* VMS */
+ }
+#endif /* OS2 */
+ }
+ n = strlen((char *)term_speed);
+ if (n > 0) { /* We have a terminal type */
+ if (!flag) { /* If not user-specified */
+ for (i = 0; i < n; i++) /* then lowercase it. */
+ if (isupper(term_speed[i]))
+ term_speed[i] = tolower(term_speed[i]);
+ }
+ debug(F110,"rlog_ini term_speed 1",term_speed,0);
+
+#ifdef CONGSPD
+ /* conspd() is not yet defined in all ck*tio.c modules */
+ conspd = congspd();
+ if (conspd > 0L) {
+ ckstrncat((char *)term_speed,"/",sizeof(term_speed));
+ ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
+ } else
+#endif /* CONGSPD */
+ ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
+ debug(F110,"rlog_ini term_speed 2",term_speed,0);
+ } else {
+ term_speed[0] = '\0';
+ debug(F110,"rlog_ini term_speed 3",term_speed,0);
+ }
+
+#ifdef CK_KERBEROS
+ if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
+ ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
+ int kver, encrypt, rc;
+ switch (ttnproto) {
+ case NP_K4LOGIN:
+ kver = 4;
+ encrypt = 0;
+ break;
+ case NP_EK4LOGIN:
+ kver = 4;
+ encrypt = 1;
+ break;
+ case NP_K5LOGIN:
+ kver = 5;
+ encrypt = 0;
+ break;
+ case NP_EK5LOGIN:
+ kver = 5;
+ encrypt = 1;
+ break;
+ default:
+ kver = 0;
+ encrypt = 0;
+ }
+ rc = ck_krb_rlogin(hostname, port,
+ localuser, remoteuser, term_speed,
+ l_addr, r_addr, kver, encrypt);
+ if (!rc) { /* success */
+ TELOPT_ME(TELOPT_NAWS) = 1;
+ rc = rlog_naws();
+ }
+ return(rc);
+ } else
+#endif /* CK_KERBEROS */
+ if (ttnproto == NP_RLOGIN) {
+#ifdef RLOGOUTBUF
+ /*
+ * The rcmds start the connection with a series of init data:
+ *
+ * a port number upon which client is listening for stderr data
+ * the user's name on the client machine
+ * the user's name on the server machine
+ * the terminal_type/speed or command to execute
+ */
+ outbuf[outbytes++] = 0;
+ strcpy((char *)outbuf+outbytes,(char *)localuser);
+ outbytes += strlen((char *)localuser) + 1;
+ strcpy((char *)outbuf+outbytes,(char *)remoteuser);
+ outbytes += strlen((char *)remoteuser) + 1;
+ strcpy((char *)outbuf+outbytes,(char *)term_speed);
+ outbytes += strlen((char *)term_speed) + 1;
+ rc = ttol((CHAR *)outbuf,outbytes);
+#else /* RLOGOUTBUF */
+ ttoc(0); /* Send an initial NUL as wake-up */
+ /* Send each variable with the trailing NUL */
+ rc = ttol(localuser,strlen((char *)localuser)+1);
+ if (rc > 0)
+ rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
+ if (rc > 0)
+ rc = ttol(term_speed,strlen((char *)term_speed)+1);
+#endif /* RLOGOUTBUF */
+
+ /* Now we are supposed to get back a single NUL as confirmation */
+ errno = 0;
+ rc = ttinc(60);
+ debug(F101,"rlogin first ttinc","",rc);
+ if (rc > 0) {
+ debug(F101,"rlogin ttinc 1","",rc);
+ printf(
+ "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
+ return(-1);
+ } else if (rc < 0) {
+ debug(F101,"rlogin ttinc errno","",errno);
+ /* printf("Network error: %d\n", errno); */
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+/* two control messages are defined:
+
+ a double flag byte of 'o' indicates a one-byte message which is
+ identical to what was once carried out of band.
+
+ a double flag byte of 'q' indicates a zero-byte message. This
+ message is interpreted as two \377 data bytes. This is just a
+ quote rule so that binary data from the server does not confuse the
+ client. */
+
+int
+rlog_ctrl(cp, n)
+ unsigned char *cp;
+ int n;
+{
+ if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
+ if (rlog_oob(&cp[4],1))
+ return(-5);
+ return(5);
+ } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
+ /* this is somewhat of a hack */
+ cp[2] = '\377';
+ cp[3] = '\377';
+ return(2);
+ }
+ return(0);
+}
+
+static int
+rlog_oob(oobdata, count) CHAR * oobdata; int count; {
+ int i;
+ int flush = 0;
+
+ debug(F111,"rlogin out_of_band","count",count);
+
+ for (i = 0; i<count; i++) {
+ debug(F101,"rlogin out_of_band","",oobdata[i]);
+ if (oobdata[i] & 0x01)
+ continue;
+
+ if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
+ debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
+
+ /* Only flush the data if in fact we are in a mode that won't */
+ /* get out of sync. Ie, not when we are in protocol mode. */
+ switch ( what ) {
+ case W_NOTHING:
+ case W_CONNECT:
+ case W_COMMAND:
+ if ( rlog_inband )
+ flush = 1;
+ else
+ ttflui();
+ break;
+ }
+ }
+ if (oobdata[i] & 0x10) { /* Switch to RAW mode */
+ debug(F101,"rlogin Raw Mode command","",oobdata[i]);
+ rlog_mode = RL_RAW;
+ }
+
+ if (oobdata[i] & 0x20) { /* Switch to COOKED mode */
+ debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
+ rlog_mode = RL_COOKED;
+ }
+ if (oobdata[i] & 0x80)
+ { /* Send Window Size Info */
+ debug(F101,"rlogin Window Size command","",oobdata[i]);
+ /* Remember to send WS Info when Window Size changes */
+ if ( !TELOPT_ME(TELOPT_NAWS) ) {
+ TELOPT_ME(TELOPT_NAWS) = 1;
+ rlog_naws();
+ }
+ }
+ }
+ return(flush);
+}
+#ifndef TCPIPLIB
+static SIGTYP
+rlogoobh(sig) int sig; {
+#ifdef SOLARIS
+ char /* Or should it be char for all? */
+#else
+ CHAR
+#endif /* SOLARIS */
+ oobdata;
+
+ /* int count = 0; */ /* (not used) */
+
+ while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
+ /*
+ * We need to do some special processing here.
+ * Just in case the socket is blocked for input
+ *
+ */
+ switch (errno) {
+ case EWOULDBLOCK:
+ break;
+ default:
+ return;
+ }
+ }
+ debug(F101,"rlogin out_of_band","",oobdata);
+ if (oobdata == 0x02) { /* Flush Buffered Data not yet displayed */
+ debug(F101,"rlogin Flush Buffered Data command","",oobdata);
+ netflui();
+ }
+ if (oobdata & 0x10) { /* Switch to raw mode */
+ debug(F101,"rlogin Raw Mode command","",oobdata);
+ rlog_mode = RL_RAW;
+ }
+ if (oobdata & 0x20) { /* Switch to cooked mode */
+ debug(F101,"rlogin Cooked Mode command","",oobdata);
+ rlog_mode = RL_COOKED;
+ }
+ if (oobdata & 0x80) { /* Send Window Size Info */
+ debug(F101,"rlogin Window Size command","",oobdata);
+ /* Remember to send WS Info when Window Size changes */
+ if ( !TELOPT_ME(TELOPT_NAWS) ) {
+ TELOPT_ME(TELOPT_NAWS) = 1;
+ rlog_naws();
+ }
+ }
+}
+#endif /* TCPIPLIB */
+#endif /* RLOGCODE */
+
+/* Send network BREAK */
+/*
+ Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
+*/
+int
+netbreak() {
+ CHAR buf[3];
+ if (ttnet == NET_TCPB) {
+ if (ttnproto == NP_TELNET) {
+#ifdef TNCODE
+ buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
+ if (
+#ifdef OS2
+ nettol((char *) buf, 2)
+#else
+ ttol(buf, 2)
+#endif /* OS2 */
+ < 2)
+ return(-1);
+ if (tn_deb || debses || deblog) {
+ extern char tn_msg[];
+ ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
+ NULL,NULL);
+ debug(F101,tn_msg,"",BREAK);
+ if (debses || tn_deb) tn_debug(tn_msg);
+ }
+ return(1);
+#else
+ debug(F100,"netbreak no TNCODE","",0);
+ return(0);
+#endif /* TNCODE */
+ }
+ /* Insert other TCP/IP protocols here */
+ }
+ /* Insert other networks here */
+ return(0);
+}
+#endif /* NETCONN */
+
+
+#ifdef NETCONN
+#ifdef SUNX25
+/*
+ SunLink X.25 support by Marcello Frutig, Catholic University,
+ Rio de Janeiro, Brazil, 1990.
+*/
+
+/* PAD X.3, X.28 and X.29 support */
+
+static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
+
+/* Initialize PAD */
+
+extern CHAR padparms[];
+
+VOID
+initpad() {
+ padparms[PAD_BREAK_CHARACTER] = 0; /* Break character */
+ padparms[PAD_ESCAPE] = 1; /* Escape permitted */
+ padparms[PAD_ECHO] = 1; /* Kermit PAD does echo */
+ padparms[PAD_DATA_FORWARD_CHAR] = 2; /* forward character CR */
+ padparms[PAD_DATA_FORWARD_TIMEOUT] = 0; /* no timeout forward condition */
+ padparms[PAD_FLOW_CONTROL_BY_PAD] = 0; /* not used */
+ padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1; /* allow PAD service signals */
+ padparms[PAD_BREAK_ACTION] = 21; /* brk action: INT pk + brk ind*/
+ padparms[PAD_SUPPRESSION_OF_DATA] = 0; /* no supression of user data */
+ padparms[PAD_PADDING_AFTER_CR] = 0; /* no padding after CR */
+ padparms[PAD_LINE_FOLDING] = 0; /* no line fold */
+ padparms[PAD_LINE_SPEED] = 0; /* line speed - don't care */
+ padparms[PAD_FLOW_CONTROL_BY_USER] = 0; /* flow cont of PAD - not used */
+ padparms[PAD_LF_AFTER_CR] = 0; /* no LF insertion after CR */
+ padparms[PAD_PADDING_AFTER_LF] = 0; /* no padding after LF */
+ padparms[PAD_EDITING] = 1; /* can edit */
+ padparms[PAD_CHAR_DELETE_CHAR] = 8; /* character delete character */
+ padparms[PAD_BUFFER_DELETE_CHAR] = 21; /* buffer delete character */
+ padparms[PAD_BUFFER_DISPLAY_CHAR] = 18; /* buffer display character */
+}
+
+/* Set PAD parameters */
+
+VOID
+setpad(s,n) CHAR *s; int n; {
+ int i;
+ CHAR *ps = s;
+
+ if (n < 1) {
+ initpad();
+ } else {
+ for (i = 0; i < n; i++) {
+ if (*ps > MAXPADPARMS)
+ x29err[i+2] = *ps;
+ else
+ padparms[*ps] = *(ps+1);
+ ps += 2;
+ }
+ }
+}
+
+/* Read PAD parameters */
+
+VOID
+readpad(s,n,r) CHAR *s; int n; CHAR *r; {
+ int i;
+ CHAR *ps = s;
+ CHAR *pr = r;
+
+ *pr++ = X29_PARAMETER_INDICATION;
+ if (n > 0) {
+ for (i = 0; i < n; i++, ps++) {
+ if (*ps > MAXPADPARMS) {
+ x29err[i+2] = *ps++;
+ } else {
+ *pr++ = *ps;
+ *pr++ = padparms[*ps++];
+ }
+ }
+ } else {
+ for (i = 1; i < MAXPADPARMS; i++) {
+ *pr++ = i;
+ *pr++ = padparms[i];
+ }
+ }
+}
+
+int
+qbitpkt(s,n) CHAR *s; int n; {
+ CHAR *ps = s;
+ int x29cmd = *ps;
+ CHAR *psa = s+1;
+ CHAR x29resp[(MAXPADPARMS*2)+1];
+
+ switch (x29cmd) {
+
+ case X29_SET_PARMS:
+ setpad (ps+1,n/2);
+ if ((int)strlen((char *)x29err) > 2) {
+ ttol(x29err,(int)strlen((char *)x29err));
+ x29err[2] = '\0';
+ }
+ return (-2);
+ case X29_READ_PARMS:
+ readpad (ps+1,n/2,x29resp);
+ setqbit ();
+ ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
+ if ((int)strlen((char *)x29err) > 2) {
+ ttol(x29err,(int)strlen((char *)x29err));
+ x29err[2] = '\0';
+ }
+ resetqbit();
+ break;
+ case X29_SET_AND_READ_PARMS:
+ setpad (ps+1,n/2);
+ readpad (ps+1,n/2,x29resp);
+ setqbit();
+ ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
+ if ((int)strlen((char *)x29err) > 2) {
+ ttol (x29err,(int)strlen((char *)x29err));
+ x29err [2] = '\0';
+ }
+ resetqbit();
+ return (-2);
+ case X29_INVITATION_TO_CLEAR:
+ (VOID) x25clear();
+ return (-1);
+ case X29_INDICATION_OF_BREAK:
+ break;
+ }
+ return (0);
+}
+
+/* PAD break action processor */
+
+VOID
+breakact() {
+ extern char x25obuf[MAXOX25];
+ extern int obufl;
+ extern int active;
+ extern unsigned char tosend;
+ static CHAR indbrk[3] = {
+ X29_INDICATION_OF_BREAK,
+ PAD_SUPPRESSION_OF_DATA,
+ 1
+ };
+ CHAR intudat, cause, diag;
+
+ if (x25stat() < 0) return; /* Ignore if no virtual call established */
+
+ if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
+ if (ttol((CHAR *)x25obuf,obufl) < 0) {
+ perror ("\r\nCan't send characters");
+ active = 0;
+ } else {
+ bzero (x25obuf,sizeof(x25obuf));
+ obufl = 0;
+ tosend = 0;
+ };
+
+ switch (padparms[PAD_BREAK_ACTION]) {
+
+ case 0 : break; /* do nothing */
+ case 1 : /* send interrupt packet with interrupt user data field = 1 */
+ intudat = 1;
+ x25intr (intudat);
+ break;
+ case 2 : /* send reset packet with cause and diag = 0 */
+ cause = diag = 0;
+ x25reset (cause,diag);
+ break;
+ case 5 : /* send interrupt packet with interrupt user data field = 0 */
+ intudat = 0;
+ x25intr (intudat);
+ setqbit ();
+ /* send indication of break without a parameter field */
+ ttoc(X29_INDICATION_OF_BREAK);
+ resetqbit ();
+ break;
+ case 8 : active = 0; /* leave data transfer */
+ conol ("\r\n");
+ break;
+ case 21: /* send interrupt packet with interrupt user data field = 0 */
+ intudat = 0;
+ x25intr (intudat);
+ setpad (indbrk+1,2); /* set pad to discard input */
+ setqbit ();
+ /* send indication of break with parameter field */
+ ttol (indbrk,sizeof(indbrk));
+ resetqbit ();
+ break;
+ }
+}
+
+/* X.25 support functions */
+
+X25_CAUSE_DIAG diag;
+
+/*
+ Convert a null-terminated string representing an X.121 address
+ to a packed BCD form.
+*/
+int
+pkx121(str,bcd) char *str; CHAR *bcd; {
+ int i, j;
+ u_char c;
+
+ i = j = 0;
+ while (str[i]) {
+ if (i >= 15 || str [i] < '0' || str [i] > '9')
+ return (-1);
+ c = str [i] - '0';
+ if (i & 1)
+ bcd [j++] |= c;
+ else
+ bcd [j] = c << 4;
+ i++;
+ }
+ return (i);
+}
+
+/* Reads and prints X.25 diagnostic */
+
+int
+x25diag () {
+ int i;
+
+ bzero ((char *)&diag,sizeof(diag));
+ if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
+ perror ("Reading X.25 diagnostic");
+ return(-1);
+ }
+ if (diag.datalen > 0) {
+ printf ("X.25 Diagnostic :");
+ for (i = 0; i < (int)diag.datalen; i++)
+ printf(" %02h",diag.data[i])+
+ printf ("\r\n");
+ }
+ return(0);
+}
+
+/* X.25 Out-of-Band Signal Handler */
+
+SIGTYP
+x25oobh(foo) int foo; {
+ int oobtype;
+ u_char oobdata;
+ int t;
+
+ (VOID) signal(SIGURG,x25oobh);
+ do {
+ if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
+ perror ("Getting signal type");
+ return;
+ }
+ switch (oobtype) {
+ case INT_DATA:
+ if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
+ perror ("Receiving X.25 interrupt data");
+ return;
+ }
+ t = oobdata;
+ printf ("\r\nInterrupt received, data = %d\r\n", t);
+ break;
+ case VC_RESET:
+ printf ("\r\nVirtual circuit reset\r\n");
+ x25diag ();
+ break;
+ case N_RESETS:
+ printf ("\r\nReset timeout\r\n");
+ break;
+ case N_CLEARS:
+ printf ("\r\nClear timeout\r\n");
+ break;
+ case MSG_TOO_LONG:
+ printf ("\r\nMessage discarded, too long\r\n");
+ break;
+ default:
+ if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
+ break;
+ }
+ } while (oobtype);
+}
+
+/* Send a X.25 interrupt packet */
+
+int
+#ifdef CK_ANSIC
+x25intr(char intr)
+#else
+x25intr(intr) char intr;
+#endif /* CK_ANSIC */
+/* x25intr */ {
+ if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
+ debug(F100,"X.25 intr","",0);
+ return(0);
+}
+
+/* Reset X.25 virtual circuit */
+int
+#ifdef CK_ANSIC
+x25reset(char cause, char diagn)
+#else
+x25reset(cause, diagn) char cause; char diagn;
+#endif /* CK_ANSIC */
+/* x25reset */ {
+ bzero ((char *)&diag,sizeof(diag));
+ diag.flags = 0;
+ diag.datalen = 2;
+ diag.data[0] = cause;
+ diag.data[1] = diagn;
+ if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
+ return(-1);
+ debug(F100,"X.25 reset","",0);
+ return(0);
+}
+
+/* Clear X.25 virtual circuit */
+int
+x25clear() {
+ int i;
+ debug(F100,"X.25 clear","",0);
+ bzero ((char *)&diag,sizeof(diag));
+ diag.flags = (1 << DIAG_TYPE);
+ diag.datalen = 2;
+ diag.data[0] = 0;
+ diag.data[1] = 0;
+ ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
+ return(ttclos(0)); /* Close socket */
+}
+
+/* X.25 status */
+int
+x25stat() {
+ if (ttyfd == -1) return (-1);
+ return(0);
+}
+
+/* Set Q_BIT on */
+VOID
+setqbit() {
+ static int qbiton = 1 << Q_BIT;
+ ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
+}
+
+/* Set Q_BIT off */
+VOID
+resetqbit() {
+ static int qbitoff = 0;
+ ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
+}
+
+/* Read n characters from X.25 circuit into buf */
+
+int
+x25xin(n,buf) int n; CHAR *buf; {
+ register int x, c;
+ int qpkt;
+
+ do {
+ x = read(ttyfd,buf,n);
+ if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
+ /* If return -1 : invitation to clear; -2 : PAD changes */
+ if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
+ qpkt = 1;
+ } else qpkt = 0;
+ } while (qpkt);
+
+#ifdef COMMENT /* Disabled by Stephen Riehm 19.12.97 */
+ /* BUG!
+ * if buf[] is full, then this null lands in nirvana!
+ * I was unable to find any code which needs a trailing null in buf[]
+ */
+ if (x > 0) buf[x] = '\0';
+#endif /* COMMENT */
+ if (x < 1) x = -1;
+ debug(F101,"x25xin x","",x);
+
+ return(x);
+}
+
+#ifdef COMMENT /* NO LONGER NEEDED! */
+/* X.25 read a line */
+
+int
+#ifdef PARSENSE
+#ifdef CK_ANSIC
+x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
+#else
+x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
+#endif /* CK_ANSIC */
+#else /* not PARSENSE */
+#ifdef CK_ANSIC
+x25inl(CHAR *dest, int max,int timo, CHAR eol)
+#else
+x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
+#endif /* __SDTC__ */
+#endif /*PARSENSE */
+ /* x25inl */ {
+ CHAR *pdest;
+ int pktype, goteol, rest, n;
+ int i, flag = 0;
+ extern int ttprty, ttpflg;
+ int ttpmsk;
+
+ ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */
+
+ debug(F101,"x25inl max","",max);
+ debug(F101,"x25inl eol","",eol);
+ pdest = dest;
+ rest = max;
+ goteol = 0;
+ do {
+ n = read(ttyfd,pdest,rest);
+ n--;
+ pktype = *pdest & 0x7f;
+ switch (pktype) {
+ case 1 << Q_BIT:
+ if (qbitpkt(pdest+1,--n) < 0) return(-2);
+ break;
+ default:
+ if (flag == 0) { /* if not in packet, search start */
+ for (i = 1; (i < n) &&
+ !(flag = ((dest[i] & 0x7f) == start));
+ i++);
+ if (flag == 0) { /* not found, discard junk */
+ debug(F101,"x25inl skipping","",n);
+ continue;
+ } else { /* found, discard junk before start */
+ int k;
+ n = n - i + 1;
+ for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
+ }
+ }
+ for (i = 0; (i < n) && /* search for eol */
+ !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
+ i++,pdest++);
+ *pdest = '\0';
+ rest -= n;
+ }
+ } while ((rest > 0) && (!goteol));
+
+ if (goteol) {
+ n = max - rest;
+ debug (F111,"x25inl X.25 got",(char *) dest,n);
+ if (timo) ttimoff();
+ if (ttpflg++ == 0 && ttprty == 0) {
+ if ((ttprty = parchk(dest,start,n)) > 0) {
+ int j;
+ debug(F101,"x25inl senses parity","",ttprty);
+ debug(F110,"x25inl packet before",(char *)dest,0);
+ ttpmsk = 0x7f;
+ for (j = 0; j < n; j++)
+ dest[j] &= 0x7f; /* Strip parity from packet */
+ debug(F110,"x25inl packet after ",dest,0);
+ } else {
+ debug(F101,"parchk","",ttprty);
+ if (ttprty < 0) { ttprty = 0; n = -1; }
+ }
+ }
+ ttimoff();
+ return(n);
+ }
+ ttimoff();
+ return(-1);
+}
+#endif /* COMMENT */
+#endif /* SUNX25 */
+
+#ifdef IBMX25
+/*
+ * IBM X25 support - using the NPI streams interface
+ * written by Stephen Riehm, pc-plus, Munich Germany
+ */
+
+/* riehm: missing functions / TODO list */
+
+/*
+ x25intr() - Send an interrupt packet
+*/
+
+/* return an error message depending on packet type */
+char *
+x25err(n) int n; {
+ static char buf[30];
+ switch (n) {
+ case NBADADDR: return "invalid address";
+ case NBADOPT: return "invalid options";
+ case NACCESS: return "no permission";
+ case NNOADDR: return "unable to allocate address";
+ case NOUTSTATE: return "invalid state";
+ case NBADSEQ: return "invalid sequence number";
+ case NSYSERR: return "system error";
+ case NBADDATA: return "invalid data size";
+ case NBADFLAG: return "invalid flag";
+ case NNOTSUPPORT: return "unsupported primitive";
+ case NBOUND: return "address in use";
+ case NBADQOSPARAM: return "bad QOS parameters";
+ case NBADQOSTYPE: return "bad QOS type";
+ case NBADTOKEN: return "bad token value";
+ case NNOPROTOID: return "protocol id could not be allocated";
+ case NODDCUD: return "odd length call user data";
+ default:
+ ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
+ return buf;
+ }
+}
+
+/* turn a meaningless primitive number into a meaningful primitive name */
+char *
+x25prim(n) int n; {
+ static char buf[30];
+ switch(n) {
+ case N_BIND_ACK: return "N_BIND_ACK";
+ case N_BIND_REQ: return "N_BIND_REQ";
+ case N_CONN_CON: return "N_CONN_CON";
+ case N_CONN_IND: return "N_CONN_IND";
+ case N_CONN_REQ: return "N_CONN_REQ";
+ case N_CONN_RES: return "N_CONN_RES";
+ case N_DATACK_IND: return "N_DATAACK_IND";
+ case N_DATACK_REQ: return "N_DATAACK_REQ";
+ case N_DATA_IND: return "N_DATA_IND";
+ case N_DATA_REQ: return "N_DATA_REQ";
+ case N_DISCON_IND: return "N_DISCON_IND";
+ case N_DISCON_REQ: return "N_DISCON_REQ";
+ case N_ERROR_ACK: return "N_ERROR_ACK";
+ case N_EXDATA_IND: return "N_EXDATA_IND";
+ case N_EXDATA_REQ: return "N_EXDATA_REQ";
+ case N_INFO_ACK: return "N_INFO_ACK";
+ case N_INFO_REQ: return "N_INFO_REQ";
+ case N_OK_ACK: return "N_OK_ACK";
+ case N_OPTMGMT_REQ: return "N_OPTMGMT_REQ";
+ case N_RESET_CON: return "N_RESET_CON";
+ case N_RESET_IND: return "N_RESET_IND";
+ case N_RESET_REQ: return "N_RESET_REQ";
+ case N_RESET_RES: return "N_RESET_RES";
+ case N_UDERROR_IND: return "N_UDERROR_IND";
+ case N_UNBIND_REQ: return "N_UNBIND_REQ";
+ case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
+ case N_UNITDATA_IND: return "N_UNITDATA_IND";
+ default:
+ ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
+ return buf;
+ }
+}
+
+/*****************************************************************************
+ * Function: x25getmsg()
+ * Description: get a STREAMS message, and check it for errors
+ *
+ * Parameters:
+ * fd - file descriptor to x25 device (opened)
+ * control - control buffer (pre-allocated)
+ * ctl_size - size of control buffer
+ * data - data buffer (pre-allocated)
+ * data_size - size of data buffer
+ * flags - flags for getmsg()
+ * expected - expected Primitive type
+ *
+ * Return Value:
+ * >= 0 OK (size of data returned)
+ * -1 error
+ *
+ */
+int
+x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
+ int fd; /* X25 device (opened) */
+ N_npi_ctl_t *control; /* control buffer (pre-allocated) */
+ int ctl_size; /* size of control buffer */
+ N_npi_data_t *data; /* data buffer (pre-allocated) */
+ int data_size; /* size of data buffer */
+ int *get_flags; /* getmsg() flags */
+ int expected; /* expected primitive type */
+/* x25getmsg */ {
+ int rc = 0; /* return code */
+ struct strbuf *get_ctl=NULL; /* getmsg control */
+ struct strbuf *get_data=NULL; /* getmsg data */
+ int more = 0; /* flag for more data etc */
+ int file_status = -1; /* file async status */
+ N_npi_ctl_t * result; /* pointer to simplify switch() */
+ int packet_type = -1; /* unknown packet thus far */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25getmsg\n" );
+#endif /* TRACE */
+
+ debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
+ /* prepare the control structures for getmsg */
+ if (control) {
+ if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
+ {
+ perror("kermit x25getmsg(): get_ctl malloc failed\n");
+ debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
+ return(-1);
+ }
+ /* allow getmsg to return an unexpected packet type (which may be
+ * larger than the expected one)
+ */
+ get_ctl->maxlen = NPI_MAX_CTL;
+ get_ctl->len = 0;
+ get_ctl->buf = (char *)control;
+ } else {
+ printf(
+ "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
+ );
+ debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
+ return( -1 );
+ }
+ if (data) {
+ if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
+ {
+ perror("kermit x25getmsg(): get_data malloc failed\n");
+ debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
+ return(-1);
+ }
+ get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
+ NPI_MAX_DATA :
+ data_size;
+ get_data->len = 0;
+ get_data->buf = (char *)data;
+ }
+
+ /* get an X.25 packet -
+ * it may be any kind of packet, so check for special cases
+ * it may be split into multiple parts - so loop if necessary
+ */
+ do {
+#ifdef DEBUG
+ printf( "kermit: x25getmsg(): getting a message\n" );
+#endif /* DEBUG */
+ errno = 0;
+ if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
+#ifdef DEBUG
+ printf( "kermit: x25getmsg(): getmsg returned an error\n" );
+ perror( "getmsg error was" );
+#endif /* DEBUG */
+ debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
+ if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
+ /* was in non-blocking mode, nothing to get, but we're
+ * already waiting for the rest of the packet -
+ * switch to blocking mode for the next read.
+ * file_status used to reset file status before returning
+ */
+ if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
+ || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
+ {
+ perror("x25getmsg(): couldn't change x25 blocking mode");
+ debug(F101,
+ "x25getmsg fcntl returned an error\n", "", errno);
+ /* netclos(); */
+ rc = -1;
+ break;
+ } else {
+ /* loop again into a blocking getmsg() */
+ continue;
+ }
+ } else {
+ /* no data to get in non-blocking mode - return empty handed */
+ perror( "x25getmsg(): getmsg failed" );
+ debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
+ rc = -1;
+ break;
+ }
+ } else if (more & MORECTL) {
+ /* panic - the control information was larger than the
+ * maximum control buffer size!
+ */
+ /* riehm: close connection? */
+#ifdef DEBUG
+ printf("x25getmsg(): received partial control packet - panic\n");
+#endif /* DEBUG */
+ debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
+ rc = -1;
+ break;
+ }
+
+ if (result = (N_npi_ctl_t *)control) {
+ packet_type = result->bind_ack.PRIM_type;
+ if (packet_type != N_OK_ACK) {
+ x25lastmsg = packet_type;
+ }
+ }
+#ifdef DEBUG
+ /* printf( "kermit: x25getmsg(): getting " ); */
+ if (get_ctl->len > 0) {
+ x25dump_prim(result);
+ }
+ debug(F110,
+ "x25getmsg got packet ",
+ x25prim( result->bind_ack.PRIM_type ),
+ 0
+ );
+#endif /* DEBUG */
+
+ if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
+ /* not as pretty as a switch(), but switch can't handle
+ * runtime variable values :-(
+ */
+ if (packet_type == expected ) {
+ /* got what we wanted, special case for DATA_IND
+ * packets though */
+ /* riehm: check Q-bit ? */
+#ifdef DEBUG
+ printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
+#endif /* DEBUG */
+ if (packet_type == N_DATA_IND ) {
+ /* data received. May be incomplete, even though
+ * getmsg returned OK
+ */
+ if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
+ more |= MOREDATA;
+ if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
+ printf( "x25getmsg(): data packet wants ack\n" );
+ }
+ } else if( packet_type == N_DISCON_IND) {
+ printf( "X25 diconnected\n" );
+ /* riehm: need to acknowledge a disconnection? */
+ x25clear();
+ /* x25unbind( ttyfd ); */
+ rc = -1;
+ } else if( packet_type == N_ERROR_ACK) {
+ errno = result->error_ack.UNIX_error;
+ perror( "X25 error received" );
+ rc = -1;
+ } else {
+ printf("x25getmsg(): failed %s\n", x25err(packet_type));
+ rc = -1;
+ }
+ }
+#ifdef COMMENT
+ else {
+ /* Panic - no control data */
+ printf( "kermit: x25getmsg(): no control data with packet\n" );
+ rc = -1;
+ }
+#endif /* COMMENT */
+
+ if (get_data && (get_data->len >= 0)) {
+ get_data->buf += get_data->len;
+ get_data->maxlen -= get_data->len;
+ }
+ } while ((rc == 0)
+ && (get_data && (get_data->maxlen > 0))
+ && (more & MOREDATA)
+ );
+
+ /* return the file status to its original value, unless its still
+ * set to -1, or one of the fcntl's failed */
+ if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
+ rc = -1;
+
+ /*
+ * Verify that we received an expected primitive
+ * there is apparantly an error case where the primitive is set
+ * correctly, but there is not enough data in the control structure
+ */
+ if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
+ fprintf(stderr,
+ "x25getmsg(): %s NOT received. Primitive received was %s\n",
+ x25prim( expected ), x25prim( packet_type ));
+ debug(F110, "x25getmsg got an unexpected packet ",
+ x25prim(packet_type),
+ 0
+ );
+ rc = -1;
+ }
+
+ if (rc == 0) {
+ if (get_data && ( get_data->len >= 0)) {
+ rc = get_data->len;
+ }
+ }
+
+ if (get_ctl) { free(get_ctl); get_ctl = NULL; }
+ if (get_data) { free(get_data); get_data = NULL; }
+
+#ifdef COMMENT
+#ifdef DEBUG
+ printf( "kermit x25getmsg(): returning %d\n", rc );
+#endif /* DEBUG */
+#endif /* COMMENT */
+ debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25getmsg\n" );
+#endif /* TRACE */
+ return(rc);
+}
+
+/*****************************************************************************
+ * Function: x25putmsg()
+ *
+ * Description:
+ * send a message to a X25 STREAM
+ *
+ * Parameters:
+ * fd - file descriptor to x25 device (opened)
+ * control - control buffer (pre-allocated)
+ * data - data buffer (pre-allocated)
+ * data_len - length of data to be transmitted
+ * put_flags - flags for putmsg()
+ *
+ * Return Value:
+ * >= 0 number of bytes transmitted
+ * -1 error
+ */
+int
+x25putmsg(fd, control, data, data_len, put_flags)
+ int fd; /* X25 device (opened) */
+ N_npi_ctl_t *control; /* control buffer (pre-allocated) */
+ N_npi_data_t *data; /* data buffer (pre-allocated) */
+ int data_len; /* length of data (not the size of
+ the buffer) */
+ int *put_flags; /* putmsg() flags */
+/* x25putmsg */ {
+ int rc = 0; /* return code */
+ ulong type; /* primitive type */
+ struct strbuf *put_ctl = NULL; /* putmsg control */
+ struct strbuf *put_data = NULL; /* putmsg data */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25putmsg\n" );
+#endif /* TRACE */
+
+#ifdef DEBUG
+ printf( "kermit: x25putmsg(): putting " );
+ x25dump_prim( control );
+ printf( "\tdata:\t\t" );
+ x25dump_data( data, 0, data_len );
+ debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
+#endif /* DEBUG */
+
+ if (control) {
+ put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
+ if (put_ctl == NULL) {
+ perror("kermit x25putmsg(): put_ctl malloc failed\n");
+ return(-1);
+ }
+ put_ctl->maxlen = 0; /* unused by putmsg */
+ put_ctl->len = NPI_MAX_CTL;
+ put_ctl->buf = (char *)control;
+ }
+ if (data && ( data_len > 0)) {
+ put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
+ if( put_data == NULL) {
+ perror("kermit x25putmsg(): put_data malloc failed\n");
+ return(-1);
+ }
+ put_data->maxlen = 0; /* unused by putmsg */
+ put_data->len = data_len;
+ put_data->buf = (char *)data;
+ }
+
+ errno = 0;
+ rc = putmsg (fd, put_ctl, put_data, 0);
+ if (rc < 0) {
+ printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
+ perror("kermit: x25putmsg(): putmsg failed");
+ return(-1);
+ }
+
+ /* riehm: this should perhaps be discounted! */
+ x25lastmsg = control->PRIM_type;
+
+#ifdef COMMENT
+#ifdef DEBUG
+ printf( "kermit debug: x25putmsg() returning %d\n", data_len );
+#endif /* DEBUG */
+#endif /* COMMENT */
+ debug( F101, "x25putmsg block size put ", "", data_len);
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25putmsg\n" );
+#endif /* TRACE */
+
+ return( data_len );
+}
+
+/*****************************************************************************
+* Function: x25bind
+* Description: The bind submitted to NPI provides the information required
+* by the packet layer for it to listen for suitable incoming
+* calls.
+*
+* WARNING:
+*
+* This routine needs to be called in a completely different manner for
+* the client and server side. When starting a client, the
+* num_waiting_calls and CUD information should all be set to 0! The
+* client's CUD must be inserted in the CONN_REQ data block.
+* When starting a server, the CUD must be set to a CUD pattern, and
+* the number of waiting calls should be set to a number other than 0.
+* (num waiting calls is the number of incomming calls which are to be
+* put on hold while the server is servicing another client.)
+*
+* Who invented this crap?
+*
+* Parameters:
+* fd - X25 device (opened)
+* addr - local address
+* cud - User Data (null terminated)
+* cud_len - User Data length
+* num_waiting_calls - number of outstanding calls allowed on this stream
+* line - logical port number (1)
+* flags - 0, DEFAULT_LISTENER or TOKEN_REQUEST
+*
+* Return Value:
+* if binding is successful, 0 is returned for a client, and a token is
+* returned for a server
+*
+* Return code: 0 if successful
+* -1 if unsuccessful
+*****************************************************************************/
+
+ulong
+x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
+ int fd; /* X25 device (opened) */
+ char * addr; /* local address */
+ char * cud; /* Call User Data (null terminated) */
+ int cud_len; /* User Data length */
+ int num_waiting_calls; /* Outstanding calls allowed */
+ int line; /* logical port number */
+ ulong bind_flags; /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
+/* x25bind */ {
+ ulong rc; /* return code */
+ int get_flags; /* priority flag passed to getmsg */
+ int put_flags = 0; /* output flags for putmsg, always 0 */
+ ulong type; /* primitive type */
+ N_bind_req_t *bind_req; /* pointer to N_BIND_REQ primitive */
+ N_bind_ack_t *bind_ack; /* pointer to N_BIND_ACK primitive */
+ char *addtl_info; /* pointer to info in addition to
+ * the N_BIND_REQ primitive that is
+ * passed in the control structure
+ * to putmsg */
+ int addr_len = 0; /* length of address string */
+ ulong bind_req_t_size; /* for debugging only */
+
+#ifdef TRACE
+ printf("TRACE: entering x25bind\n" );
+#endif /* TRACE */
+
+#ifdef DEBUG
+ printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
+ fd, addr, cud, line, bind_flags
+ );
+#endif /* DEBUG */
+
+ /*
+ * Allocate and zero out space to hold the control portion of the
+ * message passed to putmsg. This will contain the N_BIND_REQ
+ * primitive and any additional info required for that.
+ *
+ * Note: allocated space is the size of the union typedef
+ * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
+ */
+ bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
+ if (bind_req == NULL) {
+ perror("kermit: x25bind(): bind_req malloc failed");
+ debug(F100, "x25bind bind_req malloc failed", "", 0);
+ return(-1);
+ }
+ bzero((char *)bind_req, sizeof(N_npi_ctl_t));
+
+ /* Build the Bind Request Primitive */
+ bind_req->PRIM_type = (ulong) N_BIND_REQ;
+
+ /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
+ * the actual address in an N_BIND_REQ. The first byte contains the
+ * line number being used with this address, and the second byte is the
+ * X.121 address prefix, which must be zero.
+ */
+ addr_len = strlen(addr);
+ bind_req->ADDR_length = (ulong) (addr_len + 2);
+ bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
+ bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
+ bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
+ bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
+ if (cud_len == 0) {
+ bind_req->PROTOID_offset = (ulong) 0;
+ } else {
+ /* need to remember the trailing NULL in the address - not
+ * counted in the address length
+ */
+ bind_req->PROTOID_offset
+ = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
+ }
+
+ /*
+ * Now fill in the additional information required with this primitive
+ * (address and protocol information (Call User Data))
+ */
+ addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
+ /*
+ * The bitwise "&" ensures that the line number is only one byte long
+ */
+ *addtl_info++ = (char) line & 0xff;
+ *addtl_info++ = (char) 0; /* X.121 format */
+ bcopy( addr, addtl_info, addr_len ); /* include trailing null */
+ addtl_info += addr_len;
+ if (cud_len > 0)
+ bcopy( cud, addtl_info, cud_len );
+ /*
+ * Call putmsg() to put the bind request message on the stream
+ */
+ if (x25putmsg(fd,
+ (N_npi_ctl_t*)bind_req,
+ (N_npi_data_t *)NULL,
+ 0,
+ &put_flags
+ ) < 0) {
+ printf( "kermit: x25bind(): x25putmsg failed\n" );
+ return(-1);
+ }
+
+ /*
+ * Allocate and zero out space for the N_BIND_ACK primitive
+ */
+ bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
+ if (bind_ack == NULL){
+ perror("kermit: x25bind(): bind_ack malloc failed");
+ return(-1);
+ }
+ bzero(bind_ack, sizeof(N_npi_ctl_t));
+ /*
+ * Initialize the control structure and flag variable sent to getmsg
+ */
+ get_flags=0;
+
+ /* get the ACK for the bind */
+#ifdef DEBUG
+ printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
+#endif /* DEBUG */
+ rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
+ (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
+ N_BIND_ACK );
+
+ /* turn quantitive return code into a qualitative one */
+ if (rc > 0) rc = 0;
+
+ /* if all went well, get the token from the acknowledgement packet */
+ if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
+ rc = bind_ack->TOKEN_value;
+ }
+
+ /* free up the memory we allocated earlier */
+ free(bind_req);
+ free(bind_ack);
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25bind\n" );
+#endif /* TRACE */
+
+ return( rc );
+}
+
+/*****************************************************************************
+* Function: x25call
+* Description: This routine builds and sends an N_CONN_REQ primitive, then
+* checks for an N_CONN_CON primitive in return.
+*
+* Parameters:
+* fd - file descriptor of stream
+* caddr - called address (remote address)
+*
+* Functions Referenced:
+* malloc()
+* bzero()
+* getmsg()
+* putmsg()
+*
+* Return code:
+* 0 - if successful
+* -1 if not successful
+*****************************************************************************/
+int
+x25call(fd, remote_nua, cud)
+ int fd; /* X25 device (opened) */
+ char * remote_nua; /* remote address to call */
+ char * cud; /* call user data */
+/* x25call */ {
+ int rc; /* return code */
+ int flags; /* Connection flags */
+ int get_flags; /* priority flags for getmsg */
+ ulong type; /* primitive type */
+ N_conn_req_t *connreq_ctl; /* pointer to N_CONN_REQ primitive */
+ N_npi_data_t *connreq_data; /* pointer to N_CONN_REQ data (CUD) */
+ int connreq_data_len; /* length of filled data buffer */
+ N_conn_con_t *conncon_ctl; /* pointer to N_CONN_CON primitive */
+ N_npi_data_t *conncon_data; /* pointer to any data associated with
+ * the N_CONN_CON primitive */
+ char *addtl_info; /* pointer to additional info needed
+ * for N_CONN_REQ primitive */
+ int addr_len; /* length of address */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25call\n" );
+#endif /* TRACE */
+
+#ifdef DEBUG
+ printf( "x25call( %d, %s )\n", fd, remote_nua );
+ printf( "connecting to %s on fd %d\n", remote_nua, fd );
+#endif /* DEBUG */
+
+ /*
+ * Allocate and zero out space for the N_CONN_REQ primitive
+ * use the size of the generic NPI primitive control buffer
+ */
+ connreq_ctl = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
+ if (connreq_ctl == NULL){
+ perror("kermit: x25call(): connreq_ctl malloc failed");
+ return(-1);
+ }
+ bzero(connreq_ctl,sizeof(N_npi_ctl_t));
+ /*
+ * Build the Connection Request Primitive
+ */
+ flags = 0;
+ connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
+
+ /* Note that the address length is nchai+1 and not n+2. The line number
+ * is only passed with the address for the bind. The first byte of
+ * the address for the N_CONN primitives contains the X.121
+ * address prefix, which must be zero. The remaining bytes are the
+ * address itself.
+ */
+ addr_len = strlen( remote_nua );
+ connreq_ctl->DEST_length = (ulong) (addr_len + 1);
+ connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
+ /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
+ connreq_ctl->CONN_flags = (ulong) 0;
+ connreq_ctl->QOS_length = (ulong) 0; /* unsupported in AIX 4.1 */
+ connreq_ctl->QOS_offset = (ulong) 0; /* unsupported in AIX 4.1 */
+
+ addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
+ *addtl_info++ = (char) 0; /* X.121 format */
+ bcopy( remote_nua, addtl_info, addr_len );
+
+ /*
+ * setup the data buffer for the connection request
+ */
+ connreq_data = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
+ if (connreq_data == NULL){
+ perror("kermit: x25call(): connreq_data malloc failed");
+ return(-1);
+ }
+ bzero(connreq_data,sizeof(N_npi_data_t));
+
+ /* facility selection needs to be put in the front of connreq_data */
+ connreq_data_len = 0;
+ connreq_data_len += x25facilities( (char *)connreq_data );
+ if (cud && *cud) {
+ bcopy(cud,
+ (char *)((char *)connreq_data + connreq_data_len),
+ strlen(cud)
+ );
+ connreq_data_len += strlen( cud );
+ }
+
+ /*
+ * Call putmsg() to put the connection request message on the stream
+ */
+ rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
+ connreq_data_len, &flags );
+ if (rc < 0) {
+ return(-1);
+ }
+
+ /*
+ * Allocate and zero out space for the N_CONN_CON primitive
+ */
+ if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
+ perror("kermit: x25call(): conncon_ctl malloc failed");
+ return(-1);
+ }
+ bzero(conncon_ctl, sizeof(N_npi_ctl_t));
+
+ /*
+ * Allocate and zero out space for any data associated with N_CONN_CON
+ */
+ if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
+ perror("kermit: x25call(): conncon_data malloc failed");
+ return(-1);
+ }
+ bzero(conncon_data, NPI_MAX_DATA);
+
+ /* Initialize and build the structures for getmsg */
+ get_flags=0;
+
+ rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
+ conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
+
+ /* turn quantitive return code into a qualitative one */
+ if (rc > 0) rc = 0;
+
+ /* Free the space that we no longer need */
+ if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
+ if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
+ if (conncon_data) { free(conncon_data); conncon_data = NULL; }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25call\n" );
+#endif /* TRACE */
+
+ return(rc);
+}
+
+/*****************************************************************************
+ * Function: x25getcall
+ *
+ * Description: This routine checks for an incomming call, verified
+ * that it is a CONNIND (connection indication) message, and then
+ * accepts the call and returns the file descriptor of the new stream
+ *
+ * Parameters:
+ * fd - file descriptor of listening stream
+ *
+ * Return Codes:
+ * callfd - file descriptor of connected incomming call.
+ * - set to -1 if an error occured
+ *
+ *****************************************************************************/
+int
+x25getcall(fd) int fd; {
+ int x25callfd; /* fd of incomming call */
+ N_conn_ind_t *connind_ctl; /* connind controll buffer */
+ N_npi_data_t *connind_data; /* connind data buffer */
+ int get_flags; /* flags for getmsg */
+ ulong flags; /* connection flags */
+ int rc; /* return code */
+
+ extern x25addr_t remote_nua; /* remote X.25 addr global var */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25getcall\n" );
+#endif /* TRACE */
+
+ /* allocate space for connection indication buffers */
+ if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
+ perror("kermit: x25getcall(): connind_ctl malloc failed");
+ return (-1);
+ }
+ bzero(connind_ctl, sizeof(N_npi_ctl_t));
+
+ if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
+ perror("kermit: x25getcall(): connind_data malloc failed");
+ return (-1);
+ }
+ bzero(connind_data, NPI_MAX_DATA);
+
+ /* initialise control structures */
+ get_flags = 0;
+
+ /* call getmsg to check for a connection indication */
+ if (x25getmsg(fd,
+ (N_npi_ctl_t*)connind_ctl,
+ (int)sizeof(N_conn_ind_t),
+ connind_data,
+ NPI_MAX_DATA,
+ &get_flags,
+ N_CONN_IND
+ ) < 0) {
+#ifdef DEBUG
+ printf( "x25getcall(): errno is: %d\n", errno );
+#endif /* DEBUG */
+ perror ("x25getcall(): getmsg failed");
+ return(-1);
+ }
+
+ /* a connection indication was received
+ * - pull it to bits and answer the call
+ */
+ x25seqno = connind_ctl->SEQ_number;
+ flags = connind_ctl->CONN_flags;
+#ifdef DEBUG
+ printf( "setting remote_nua to a new value due to incomming call\n" );
+#endif /* DEBUG */
+ /*
+ * no guarantee that the address is null terminated, ensure that
+ * after copying that it is (assumption: remote_nua is longer than
+ * the address + 1)
+ */
+ bzero(remote_nua, sizeof(remote_nua));
+ /* note: connind_ctl contains a x121 address, which has a null as
+ * the FIRST character - strip it off!
+ */
+ ckstrncpy(remote_nua,
+ (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
+ connind_ctl->SRC_length - 1
+ );
+#ifdef DEBUG
+ printf( "remote_nua set to new value of %s\n", remote_nua );
+#endif /* DEBUG */
+
+ /* errors handled by callee */
+ x25callfd = x25accept(x25seqno, flags);
+
+ /* free the malloc'd buffers */
+ if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
+ if (connind_data) { free(connind_data); connind_data = NULL; }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25getcall\n" );
+#endif /* TRACE */
+
+ /* return the file descriptor (or error if < 0) */
+ return( x25callfd );
+}
+
+/*****************************************************************************
+ * Function: x25accept
+ *
+ * Description: accept an incomming call
+ * This essentially means opening a new STREAM and sending
+ * an acknowledge back to the caller.
+ *
+ * Parameters:
+ * seqno - sequence number for acknowledgement
+ * flags - flags passed to us by the caller
+ *
+ * Return Codes:
+ * fd - file descriptor of new STREAM
+ * set to -1 if an error occured
+ *
+ *****************************************************************************/
+int
+x25accept(seqno,flags)
+ ulong seqno; /* connection sequence number */
+ ulong flags; /* connection flags */
+/* x25accept */ {
+ int x25callfd; /* fd for incomming call */
+ int get_flags; /* priority flags for getmsg */
+ int put_flags = 0; /* flags for putmsg, always 0 */
+ int addr_len; /* length of local address */
+ ulong token; /* connection token */
+ N_conn_res_t *conn_res; /* N_CONN_RES primitive */
+ N_ok_ack_t *ok_ack; /* N_OK_ACK primitive */
+ char *addtl_info; /* temp pointer */
+ int rc; /* temporary return code */
+
+/* global variables from ckcmai.c */
+ extern int revcall, closgr, cudata;
+ extern char udata[];
+ extern x25addr_t local_nua; /* local X.25 address */
+ extern char x25name[]; /* x25 device name (sx25a0) */
+ extern char x25dev[]; /* x25 device file /dev/x25pkt */
+ extern int x25port; /* logical port to use */
+ ulong bind_flags = 0; /* flags for binding the X25 stream */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25accept\n" );
+#endif /* TRACE */
+
+ /* open a new packet level stream */
+ if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
+ perror ("kermit: x25accept(): X.25 device open error");
+ debug(F101,"x25accept() device open error","",errno);
+ return(-1);
+ }
+
+ /* push the NPI onto the STREAM */
+ if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
+ perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
+ debug(F101,"x25accept can't push npi on the X25 stream","",errno);
+ return (-1);
+ }
+
+ /* bind kermit server to the local X25 address */
+ /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
+ bind_flags |= TOKEN_REQUEST;
+ token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
+ if (token < 0) {
+ printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
+ netclos();
+ return(-1);
+ }
+
+ /* allocate connection response primitive */
+ if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
+ perror("kermit: x25accept(): conn_res malloc failed");
+ return (-1);
+ }
+ bzero((char *)conn_res, NPI_MAX_CTL);
+
+ /* setup connection response primitive */
+ addr_len = strlen( local_nua );
+ conn_res->PRIM_type = (ulong)N_CONN_RES;
+ conn_res->TOKEN_value = token;
+ /* note address length is n+1 to accomodate the X.121 address prefix */
+ conn_res->RES_length = (ulong)(addr_len + 1);
+ conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
+ conn_res->SEQ_number = seqno;
+ conn_res->CONN_flags = 0;
+ conn_res->QOS_length = 0; /* unsupported - must be 0 (!?) */
+ conn_res->QOS_offset = 0;
+
+ addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
+ *addtl_info++ = (char)0; /* X.121 address prefix */
+ bcopy( local_nua, addtl_info, addr_len );
+
+ /*
+ * send off the connect response
+ */
+ if (x25putmsg(x25callfd,
+ (N_npi_ctl_t*)conn_res,
+ (N_npi_data_t *)NULL,
+ 0,
+ &put_flags
+ ) < 0 ) {
+ perror("kermit: x25accept(): putmsg connect response failed");
+ return(-1);
+ }
+
+ /*
+ * Allocate and zero out space for the OK_ACK primitive
+ */
+ if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
+ perror("kermit: x25call(): ok_ack malloc failed");
+ return(-1);
+ }
+ bzero(ok_ack, sizeof(N_npi_ctl_t));
+
+ /* Initialize and build the structures for getmsg */
+ get_flags=0;
+
+ rc = (int)x25getmsg(x25callfd,
+ (N_npi_ctl_t*)ok_ack,
+ (int)sizeof(N_ok_ack_t),
+ (N_npi_data_t*)NULL,
+ 0,
+ &get_flags,
+ N_OK_ACK
+ );
+ if (rc == 0) {
+ /* sequence number is only for disconnecting when not connected !? */
+ x25seqno = 0;
+ }
+
+ /* free up malloc'ed buffer space */
+ if (conn_res) { free(conn_res); conn_res = NULL; }
+ if (ok_ack) { free(ok_ack); ok_ack = NULL; }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25accept\n" );
+#endif /* TRACE */
+
+ return( ( rc >= 0 ) ? x25callfd : -1 );
+}
+
+/*****************************************************************************
+ * Function: x25unbind
+ *
+ * Description: This subroutine builds and sends an unbind request and gets
+ * the acknowledgement for it.
+ *
+ * Parameters:
+ * fd - File descriptor of the stream
+ *
+ * Functions Referenced:
+ * getmsg()
+ * putmsg()
+ * malloc()
+ * bzero()
+ *
+ * Return code:
+ * 0 - if successful
+ * -1 - if not successful
+ *****************************************************************************/
+int
+x25unbind(fd) int fd; { /* X25 device (opened) */
+ int rc; /* return code */
+ int flags; /* bind flags */
+ int get_flags; /* priority flag for getmsg */
+ ulong type; /* primitive type */
+ N_unbind_req_t *unbind_req; /* pointer to N_UNBIND_REQ */
+ N_ok_ack_t *ok_ack; /* pointer to N_OK_ACK */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25unbind\n" );
+#endif /* TRACE */
+
+#ifdef DEBUG
+ /* printf( "x25unbind( %d )\n", fd ); */
+#endif /* DEBUG */
+ debug(F101,"x25unbind closing x25 connection #","",fd);
+
+ /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
+ unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
+ if (unbind_req == NULL) {
+ perror("kermit: x25unbind(): unbind_req malloc failed");
+ return(-1);
+ }
+ bzero(unbind_req, sizeof(N_npi_ctl_t));
+
+ /*
+ * Build the Unbind Request Primitive
+ */
+ flags = 0;
+ unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
+
+ /*
+ * Call putmsg() to put the bind request message on the stream
+ */
+ if (x25putmsg(fd,
+ (N_npi_ctl_t*)unbind_req,
+ (N_npi_data_t *)NULL,
+ 0,
+ &flags
+ ) < 0) {
+ perror ("kermit: x25unbind(): putmsg failed");
+ return(-1);
+ }
+
+ /* Allocate and Zero out space for the N_OK_ACK primitive */
+ ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
+ if (ok_ack == NULL) {
+ perror("kermit x25unbind(): ok_ack malloc failed\n");
+ return(-1);
+ }
+ bzero(ok_ack, sizeof(N_npi_ctl_t));
+
+ /* Initialize and build the control structure for getmsg */
+ get_flags=0;
+
+ /* Call getmsg() to check for an acknowledgement */
+ rc = x25getmsg(fd,
+ (N_npi_ctl_t*)ok_ack,
+ (int)sizeof(N_ok_ack_t),
+ (N_npi_data_t*)NULL,
+ 0,
+ &get_flags,
+ N_OK_ACK
+ );
+ if (rc < 0) {
+ perror ("kermit: x25unbind: getmsg failed");
+ return(-1);
+ }
+
+ /* Free up the space that we no longer need */
+ if (unbind_req) { free(unbind_req); unbind_req = NULL; }
+ if (ok_ack) { free(ok_ack); ok_ack = NULL; }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25unbind\n" );
+#endif /* TRACE */
+
+ return(0);
+}
+
+/*****************************************************************************
+ * Function: x25xin
+ *
+ * Description:
+ * Read n characters from X.25 circuit into buf (AIX only)
+ *
+ * Parameters:
+ * data_buf_len maximum size of data buffer
+ * data_buf pointer to pre-allocated buffer space
+ *
+ * Return Value:
+ * the number of characters actually read
+ */
+int
+x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
+ struct strbuf getmsg_ctl; /* streams control structure */
+ struct strbuf getmsg_data; /* streams data structure */
+ int rc = 0; /* return code */
+ int getmsg_flags; /* packet priority flags */
+ char * ctl_buf; /* npi control buffer */
+ N_npi_ctl_t * result; /* pointer to simplify switch() */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25xin\n" );
+#endif /* TRACE */
+
+ /* ensure that no maximum's are overridden */
+ data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
+
+ /* allocate space for packet control info */
+ if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
+ perror( "kermit: x25xin(): ctl_buf malloc" );
+ return(-1);
+ }
+#ifdef COMMENT
+ /* riehm: need zeroed buffer for getmsg? */
+ bzero( ctl_buf, NPI_MAX_CTL );
+ /* clear data buffer */
+ bzero( data_buf, data_buf_len );
+#endif /* COMMENT */
+
+ getmsg_flags = 0; /* get the first packet available */
+
+ rc = x25getmsg(ttyfd,
+ ctl_buf,
+ NPI_MAX_CTL,
+ data_buf,
+ data_buf_len,
+ &getmsg_flags,
+ N_DATA_IND
+ );
+#ifdef COMMENT
+#ifdef DEBUG
+ if (rc >= 0) {
+ printf( "kermit: x25xin(): got " );
+ x25dump_data( data_buf, 0, rc );
+ } else {
+ printf( "x25xin(): attempt to get data resulted in an error\n" );
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+
+ /* free buffers */
+ if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25xi\n" );
+#endif /* TRACE */
+
+ return(rc);
+}
+
+/*****************************************************************************
+ * Function: x25write
+ *
+ * Description:
+ * write a block of characters to the X25 STREAM (AIX)
+ *
+ * Parameters:
+ * fd file descriptor to write to
+ * databuf buffer containing data to write
+ * databufsize size of the buffer to write
+ *
+ * Return Value:
+ * size the number of bytes actually transmitted
+ */
+int
+x25write(fd, databuf, databufsize)
+ int fd; /* X25 STREAMS file descriptor (ttyfd) */
+ char *databuf; /* buffer to write */
+ int databufsize; /* buffer size */
+/* x25write */ {
+ N_data_req_t *data_req_ctl;
+ int rc; /* return code (size transmitted) */
+ int write_flags = 0; /* always 0 !? */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25write\n" );
+#endif /* TRACE */
+
+ if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
+ perror( "kermit: x25write(): data_req_ctl malloc" );
+ return(-1);
+ }
+ data_req_ctl->PRIM_type = N_DATA_REQ;
+ data_req_ctl->DATA_xfer_flags = 0;
+
+ /* riehm: possible extension
+ * possibly need to think about splitting up the data buffer
+ * into multiple parts if databufsize > NPI_MAX_DATA
+ */
+
+#ifdef COMMENT
+#ifdef DEBUG
+ printf( "kermit: x25write(): writing data to x25 stream\n" );
+ printf( "\tdata:\t" );
+ x25dump_data(databuf, 0, databufsize);
+#endif /* DEBUG */
+#endif /* COMMENT */
+ rc = x25putmsg(fd,
+ (N_npi_ctl_t*)data_req_ctl,
+ (N_npi_data_t*)databuf,
+ databufsize,
+ &write_flags
+ );
+ if (data_req) { free(data_req_ctl); data_req = NULL; }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25write\n" );
+#endif /* TRACE */
+
+ return(rc);
+}
+
+/*****************************************************************************
+ * Function: x25local_nua
+ *
+ * Description:
+ * This routine is only interesting for IBM computers. In order
+ * to set up a connection (see x25bind()) you need to know the
+ * local NUA (x25 address). Unfortunately, you need all this code
+ * to find that out, I just hope this works for everyone else!
+ *
+ * Parameters:
+ * a pre-allocated character buffer, long enough to hold an X.25 address
+ * and the tailing null.
+ *
+ * Return Value:
+ * the length of the address string.
+ * 0 = error
+ */
+int
+x25local_nua(char *buf) {
+ struct CuAt *response; /* structure to fill with info from ODM */
+ CLASS_SYMBOL retClass; /* ODM class */
+ char query[64]; /* odm database query */
+ int rc = 0; /* return value (length of local NUA) */
+ extern char x25name[]; /* x25 device name (sx25a0) */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25local_nua\n" );
+#endif /* TRACE */
+
+ /* set up query string */
+ if (x25name[0] == '\0') {
+#ifdef DEBUG
+ printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
+#endif /* DEBUG */
+ strcpy( x25name, "sx25a0" );
+ }
+ ckmakmsg(query, sizeof(query), "name like ",x25name,
+ " and attribute like local_nua");
+
+ /* initialise ODM database */
+ odmerrno = 0;
+ if (odm_initialize() == -1) {
+ printf( "x25local_nua(): can't initialize ODM database");
+ switch (odmerrno) {
+ case ODMI_INVALID_PATH:
+ printf( "invalid path\n" );
+ break;
+ case ODMI_MALLOC_ERR:
+ printf( "malloc failed\n" );
+ break;
+ default:
+ printf( "unknown error %d\nPlease call IBM\n", odmerrno );
+ }
+ return(rc);
+ }
+
+ /* open the CuAt class */
+ retClass = odm_open_class(CuAt_CLASS);
+ if (((int)retClass) == -1) {
+ printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
+ switch (odmerrno) {
+ case ODMI_CLASS_DNE:
+ printf( "CuAt class doesn't exist\n" );
+ break;
+ case ODMI_CLASS_PERMS:
+ printf( "permission to CuAt class file denied\n" );
+ break;
+ case ODMI_MAGICNO_ERR:
+ printf( "CuAt is an invalid ODM object class\n" );
+ break;
+ case ODMI_OPEN_ERR:
+ printf( "cannot open CuAt class - and don't know why!\n" );
+ break;
+ case ODMI_INVALID_PATH:
+ printf( "invalid path\n" );
+ break;
+ case ODMI_TOOMANYCLASSES:
+ printf( "too many object classes have been opened\n" );
+ break;
+ default:
+ printf( "unknown error %d\nPlease call IBM\n", odmerrno );
+ }
+ return(rc);
+ }
+
+#ifdef DEBUG
+ printf("retClass= %d\n", retClass);
+#endif /* DEBUG */
+
+ response = (struct CuAt *)odm_get_first( retClass, query, NULL );
+ if (((int)response) == -1) {
+ printf( "kermit: x25local_nua(): odm query failed " );
+ switch (odmerrno) {
+ case ODMI_BAD_CRIT: /* Programming error */
+ printf( "bad search criteria\n" );
+ break;
+ case ODMI_CLASS_DNE:
+ printf( "CuAt class doesn't exist\n" );
+ break;
+ case ODMI_CLASS_PERMS:
+ printf( "permission to CuAt class file denied\n" );
+ break;
+ case ODMI_INTERNAL_ERR:
+ printf("odm internal error\nPlease contact your administrator\n" );
+ break;
+ case ODMI_INVALID_CLXN:
+ printf("CuAt is invalid or inconsistent odm class collection\n");
+ break;
+ case ODMI_INVALID_PATH:
+ printf( "invalid path\n" );
+ break;
+ case ODMI_MAGICNO_ERR:
+ printf( "CuAt is an invalid ODM object class\n" );
+ break;
+ case ODMI_MALLOC_ERR:
+ printf( "malloc failed\n" );
+ break;
+ case ODMI_OPEN_ERR:
+ printf( "cannot open CuAt class - and don't know why!\n" );
+ break;
+ case ODMI_TOOMANYCLASSES:
+ printf( "too many object classes have been opened\n" );
+ break;
+ default:
+ printf( "unknown error %d\nPlease call IBM\n", odmerrno );
+ }
+ return(rc);
+ }
+
+ /* check for a meaningfull response */
+ if (response != NULL) {
+ if (response->value != NULL) {
+ strcpy(buf, response->value);
+ rc = strlen( buf );
+#ifdef DEBUG
+/*
+ printf( "attribute name is: %s\n", (char *)response->attribute );
+ printf( "I think my address is %s\n", (char*)response->value );
+*/
+#endif /* DEBUG */
+ } else {
+ printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
+ }
+ } else {
+ switch (odmerrno) {
+ case ODMI_BAD_CRIT:
+ printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
+ break;
+ case ODMI_CLASS_DNE:
+ printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
+ break;
+ case ODMI_CLASS_PERMS:
+ printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
+ break;
+ case ODMI_INTERNAL_ERR:
+ printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
+ break;
+ case ODMI_INVALID_CLXN:
+ printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
+ break;
+ case ODMI_INVALID_PATH:
+ printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
+ break;
+ case ODMI_MAGICNO_ERR:
+ printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
+ break;
+ case ODMI_MALLOC_ERR:
+ printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
+ break;
+ case ODMI_OPEN_ERR:
+ printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
+ break;
+ case ODMI_TOOMANYCLASSES:
+ printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
+ break;
+ default:
+ printf( "Unknown error!\n" );
+ }
+ return(rc);
+ }
+
+ /* close the database again */
+ odm_close_class( retClass );
+
+ /* forget about ODM all together */
+ odm_terminate();
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25local_nua\n" );
+#endif /* TRACE */
+
+ debug(F110, "x25local_nua local address is ", buf, 0);
+ return(rc);
+}
+
+/*****************************************************************************
+ * Function: x25facilities
+ *
+ * Description:
+ * build up the facilities data packet for a connection request
+ *
+ * Parameters:
+ * a pre-allocated char buffer, normally NPI_MAX_DATA big.
+ *
+ * Return Value:
+ * the number of characters inserted into the buffer
+ */
+int
+x25facilities(buffer) char *buffer; {
+ extern int revcall;
+ extern int closgr;
+ char *p; /* temp pointer */
+ char *start; /* temp pointer */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25facilities\n" );
+#endif /* TRACE */
+
+ p = buffer + 1;
+ start = p;
+
+#ifdef DEBUG
+ printf( "kermit: x25facilities(): getting X25 facilities\n" );
+#endif /* DEBUG */
+
+ if (revcall != 0) {
+#ifdef DEBUG
+ printf("reverse charge: %d\n", revcall );
+#endif /* DEBUG */
+ *++p = 0x01;
+ *++p = revcall;
+ }
+ if (closgr > 0) {
+#ifdef DEBUG
+ printf("closed user group: %d\n", closgr );
+#endif /* DEBUG */
+ *++p = 0x03;
+ *++p = closgr;
+ }
+
+#ifdef DEBUG
+ if (p == start) {
+ printf( "no facilities\n" );
+ }
+#endif /* DEBUG */
+
+ /* set the size of the facilities buffer */
+ *buffer = (char)( p - start ) & 0xff;
+
+#ifdef DEBUG
+ printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer) );
+#endif /* DEBUG */
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25facilities\n" );
+#endif /* TRACE */
+
+ /* return the size of the facilities with size byte */
+ /* 1 == no facilities, 0 byte returned as facilities size */
+ return( (int)(p - buffer) );
+}
+
+/*
+ * reset the connection
+ */
+int
+x25reset(cause, diagn) char cause; char diagn; {
+ /* not implemented */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25reset\n" );
+#endif /* TRACE */
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25reset\n" );
+#endif /* TRACE */
+
+ return(0);
+}
+
+/*
+ * clear the x25 connection - ie: hang up
+ */
+int
+x25clear() {
+ int get_flags = 0; /* priority flag for getmsg */
+ int put_flags = 0; /* send flags, always 0 */
+ ulong type; /* primitive type */
+ N_discon_req_t *discon_req; /* pointer to N_DISCON_REQ */
+ N_discon_ind_t *discon_ind; /* pointer to N_DISCON_IND */
+ N_npi_data_t *discon_data; /* pointer to N_DISCON_IND data */
+ int rc = 0; /* return code */
+
+#ifdef TRACE
+ printf( "TRACE: entering x25clear\n" );
+#endif /* TRACE */
+
+#ifdef DEBUG
+ /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
+#endif /* DEBUG */
+
+ /*
+ * The following checks are used to ensure that we don't disconnect
+ * or unbind twice - this seems to throw the NPI interface right out of
+ * kilter.
+ */
+ switch(x25lastmsg) {
+ case N_BIND_ACK:
+ case N_CONN_CON:
+ case N_CONN_REQ:
+ case N_DATA_REQ:
+ case N_DATA_IND:
+ {
+#ifdef DEBUG
+ /* printf("x25clear(): actively disconnecting\n"); */
+#endif /* DEBUG */
+
+ discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
+ if (discon_req == NULL) {
+ perror("kermit x25clear(): discon_req malloc failed\n");
+ /* fallthrough, try to unbind the NPI anyway */
+ } else {
+ discon_req->PRIM_type = N_DISCON_REQ;
+ discon_req->DISCON_reason = 0; /* not used by AIX */
+ discon_req->RES_length = 0;
+ discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
+ discon_req->SEQ_number = x25seqno; /* global */
+
+ if (x25putmsg(ttyfd,
+ (N_npi_ctl_t*)discon_req,
+ (N_npi_data_t*)NULL,
+ 0,
+ &put_flags
+ ) < 0) {
+ perror("x25putmsg failed in x25clear()");
+ }
+ discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
+ discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
+ if((discon_ind == NULL) || (discon_data == NULL)) {
+ perror("x25clear(): discon_ind malloc failed\n");
+ /* fallthrough, try to unbind the NPI anyway */
+ } else {
+ if(x25getmsg(ttyfd,
+ (N_npi_ctl_t*)discon_ind,
+ NPI_MAX_CTL,
+ (N_npi_data_t*)discon_data,
+ NPI_MAX_DATA,
+ &get_flags,
+ N_OK_ACK
+ ) < 0 ) {
+ perror("x25getmsg failed in x25clear()");
+ /* fallthrough, try to unbind the NPI anyway */
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (x25lastmsg != N_UNBIND_REQ) {
+ rc = x25unbind(ttyfd);
+ }
+
+#ifdef TRACE
+ printf( "TRACE: leaving x25clear\n" );
+#endif /* TRACE */
+
+ return(rc);
+}
+
+#ifdef DEBUG
+/*
+ * only for debugging
+ *
+ * turn the internal representation of a datablock into something
+ * half-way readable. Because the length is known, we can print
+ * the string including null's etc (important, because the first(!)
+ * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
+ */
+x25dump_data(char *addr, ulong offset, ulong length) {
+ char *ptr = addr + offset;
+ ulong i = length;
+ /* allocate enough memory for all unprintable chars */
+ char *buf = (char *)malloc( length * 4 );
+ char *bptr = buf; /* pointer to current place in the print buffer */
+
+ while (i > 0) {
+ if (isprint(*ptr)) {
+ *bptr++ = *ptr;
+ } else {
+ *bptr++ = '[';
+ strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
+ *bptr++ = ']';
+ }
+ ptr++;
+ i--;
+ }
+ if (length > 0) {
+ *bptr = '\0';
+ printf( "%s", buf );
+ }
+ printf( " (%d+%d)\n", offset, length );
+
+ if (buf) { free(buf); buf = NULL; }
+ return;
+}
+
+/*
+ * only for debugging
+ * print as much useful information about a packet as possible
+ */
+x25dump_prim(primitive) N_npi_ctl_t *primitive; {
+ printf("Primitive");
+ switch (primitive->PRIM_type) {
+ case N_BIND_ACK:
+ printf( "\tN_BIND_ACK\n\taddress:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->bind_ack.ADDR_offset,
+ primitive->bind_ack.ADDR_length );
+ printf( "\tproto id:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->bind_ack.PROTOID_offset,
+ primitive->bind_ack.PROTOID_length );
+ printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
+ primitive->bind_ack.CONIND_number,
+ primitive->bind_ack.TOKEN_value );
+ break;
+
+ case N_BIND_REQ:
+ printf( "\tN_BIND_REQ\n\taddress:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->bind_req.ADDR_offset,
+ primitive->bind_req.ADDR_length );
+ printf( "\tproto id:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->bind_req.PROTOID_offset,
+ primitive->bind_req.PROTOID_length );
+ printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
+ primitive->bind_req.CONIND_number,
+ primitive->bind_req.BIND_flags );
+ break;
+
+ case N_CONN_CON:
+ printf( "\tN_CONN_CON\n" );
+ printf( "\tRES\t\t" );
+ x25dump_data( (char *)primitive,
+ primitive->conn_con.RES_offset,
+ primitive->conn_con.RES_length );
+ printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
+ break;
+
+ case N_CONN_IND:
+ printf( "\tN_CONN_IND\n" );
+ printf( "\tsource:\t\t" );
+ x25dump_data( (char *)primitive,
+ primitive->conn_ind.SRC_offset,
+ primitive->conn_ind.SRC_length );
+ printf( "\tdestination:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->conn_ind.DEST_offset,
+ primitive->conn_ind.DEST_length );
+ printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
+ printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
+ break;
+
+ case N_CONN_REQ:
+ printf( "\tN_CONN_REQ\n\tdestination:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->conn_req.DEST_offset,
+ primitive->conn_req.DEST_length );
+ printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
+ break;
+
+ case N_CONN_RES:
+ printf( "\tN_CONN_RES\n" );
+ printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
+ printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
+ printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
+ printf( "\tRES\t\t" );
+ x25dump_data( (char *)primitive,
+ primitive->conn_res.RES_offset,
+ primitive->conn_res.RES_length );
+ break;
+
+ case N_DATACK_IND:
+ printf( "\tN_DATACK_IND\n" );
+ break;
+
+ case N_DATACK_REQ:
+ printf( "\tN_DATACK_REQ\n" );
+ printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
+ break;
+
+ case N_DATA_IND:
+ printf( "\tN_DATA_IND\n" );
+ printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
+ break;
+
+ case N_DATA_REQ:
+ printf( "\tN_DATA_REQ\n" );
+ break;
+
+ case N_DISCON_IND:
+ printf( "\tN_DISCON_IND\n" );
+ printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
+ printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
+ printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
+ printf( "\tRES:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->discon_ind.RES_offset,
+ primitive->discon_ind.RES_length );
+ break;
+
+ case N_DISCON_REQ:
+ printf( "\tN_DISCON_REQ\n" );
+ printf( "\tDISCON_reason:\t%d\n",
+ primitive->discon_req.DISCON_reason );
+ printf( "\tRES:\t" );
+ x25dump_data( (char *)primitive,
+ primitive->discon_req.RES_offset,
+ primitive->discon_req.RES_length );
+ printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
+ break;
+
+ case N_ERROR_ACK:
+ printf( "\tN_ERROR_ACK\n" );
+ printf( "\tCaused by:\t%s\n",
+ x25prim( primitive->error_ack.ERROR_prim ) );
+ printf( "\tNPI error:\t%s\n",
+ x25err( primitive->error_ack.NPI_error ));
+ errno = primitive->error_ack.UNIX_error;
+ perror( "\t" );
+ break;
+
+ case N_EXDATA_IND:
+ printf( "\tN_EXDATA_ACK\n" );
+ break;
+
+ case N_EXDATA_REQ:
+ printf( "\tN_EXDATA_REQ\n" );
+ break;
+
+ case N_INFO_ACK:
+ printf( "\tN_INFO_ACK\n" );
+ printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
+ printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
+ printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
+ printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
+ printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
+ printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
+ break;
+
+ case N_INFO_REQ:
+ printf( "\tN_INFO_REQ\n" );
+ break;
+
+ case N_OK_ACK:
+ printf( "\tN_OK_ACK\n" );
+ break;
+
+ case N_OPTMGMT_REQ:
+ printf( "\tN_OPTMGMT_REQ\n" );
+ break;
+
+ case N_RESET_CON:
+ printf( "\tN_RESET_CON\n" );
+ break;
+
+ case N_RESET_IND:
+ printf( "\tN_RESET_IND\n" );
+ printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
+ printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
+ break;
+
+ case N_RESET_REQ:
+ printf( "\tN_RESET_REQ\n" );
+ printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
+ break;
+
+ case N_RESET_RES:
+ printf( "\tN_RESET_RES\n" );
+ break;
+
+ case N_UDERROR_IND:
+ printf( "\tN_UDERROR_IND\n" );
+ break;
+
+ case N_UNBIND_REQ:
+ printf( "\tN_UNBIND_REQ\n" );
+ break;
+
+ case N_UNITDATA_REQ:
+ printf( "\tN_UNITDATA_REQ\n" );
+ break;
+
+ case N_UNITDATA_IND:
+ printf( "\tN_UNITDATA_IND\n" );
+ break;
+
+ default:
+ (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
+ return 0;
+ }
+}
+#endif /* DEBUG */
+
+/* it looks like signal handling is not needed with streams! */
+/* x25oobh() - handle SIGURG signals - take from isode ? */
+
+#endif /* IBMX25 */
+
+#ifndef NOHTTP
+/*
+ Which time.h files to include... See ckcdeb.h for defaults.
+ Note that 0, 1, 2, or all 3 of these can be included according to
+ the symbol definitions.
+*/
+#ifndef NOTIMEH
+#ifdef TIMEH
+#include <time.h>
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+
+#ifndef TIMEH
+#ifndef SYSTIMEH
+#ifndef SYSTIMEBH
+#ifdef Plan9
+#include <sys/time.h>
+#else
+#ifdef AIX41
+#include <time.h>
+#else
+#ifdef SUNOS4
+#include <sys/time.h>
+#else
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#else
+#ifdef POSIX
+#include <posix/time.h>
+#else
+#ifdef CLIX
+#include <sys/time.h>
+#else
+#ifdef OS2
+#include <time.h>
+#else
+#include <time.h>
+/* #include <utime.h> */
+#endif /* OS2 */
+#endif /* CLIX */
+#endif /* POSIX */
+#endif /* SYSTIMEH */
+#endif /* SUNOS4 */
+#endif /* AIX41 */
+#endif /* Plan9 */
+#endif
+#endif
+#endif
+
+#ifdef OS2
+#include <sys/utime.h>
+#ifdef NT
+#define utimbuf _utimbuf
+#endif /* NT */
+#define utime _utime
+#else
+#ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
+#include <sys/utime.h> /* for extra fields required by */
+#else /* 88Open spec. */
+#ifdef UTIMEH /* or <utime.h> if requested */
+#include <utime.h> /* (SVR4, POSIX) */
+#define SYSUTIMEH /* Use this for both cases. */
+#endif /* UTIMEH */
+#endif /* SYSUTIMEH */
+#endif /* OS2 */
+
+#ifdef VMS /* SMS 2007/02/15 */
+#include "ckvrtl.h"
+#endif /* def VMS */
+
+#ifndef HTTP_VERSION
+#define HTTP_VERSION "HTTP/1.1"
+#endif /* HTTP_VERSION */
+
+#ifdef CMDATE2TM
+time_t
+#ifdef CK_ANSIC
+http_date(char * date)
+#else
+http_date(date) char * date;
+#endif /* CK_ANSIC */
+/* http_date */ {
+ /* HTTP dates are of the form: "Sun, 06 Oct 1997 20:11:47 GMT" */
+ /* There are two older formats which we are required to parse
+ * that we currently do not:
+ *
+ * RFC 850: "Sunday, 06-Oct-97 20:11:47 GMT"
+ * asctime(): "Sun Nov 6 20:11:47 1997"
+ *
+ * However, it is required that all dates be sent in the form we
+ * do accept. The other two formats are for compatibility with
+ * really old servers.
+ */
+ extern char cmdatebuf[18];
+ struct tm t_tm;
+ time_t t;
+ char ldate[32];
+ int j;
+
+ j = ckindex(",",date,0,0,0);
+ ckstrncpy(ldate,&date[j+1],25);
+
+ { /*
+ cmcvtate() date changed to return a string pointer.
+ fdc, 12 Aug 2001.
+ */
+ char * dp;
+ dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
+ if (!dp)
+ return(0);
+ t_tm = *cmdate2tm(dp,1);
+ }
+/*
+ From Lucas Hart, 5 Dec 2001:
+ "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
+ setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
+ the specified (GMT) time if the buffer size is 21, or the contemporaneous
+ localtime if the buffer size is 25. Perhaps tm_isdst should be set in
+ cmdate2tm(), rather than only in http_date."
+*/
+#ifndef NOTM_ISDST /* For platforms where */
+ t_tm.tm_isdst = -1; /* tm_isdst doesn't exist. */
+#endif /* NOTM_ISDST */
+
+ t = mktime(&t_tm); /* NOT PORTABLE */
+
+#ifdef XX_TIMEZONE
+ t -= _timezone;
+#endif /* XX_TIMEZONE */
+
+ return(t);
+}
+#endif /* CMDATE2TM */
+
+char *
+http_now() {
+ static char nowstr[32];
+#ifdef CMDATE2TM
+ struct tm *gmt;
+ time_t ltime; /* NOT PORTABLE */
+
+ time(<ime);
+
+ gmt = gmtime(<ime); /* PROBABLY NOT PORTABLE */
+ strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
+ /* not only is it not portable but it's locale-dependent */
+#else
+/*
+ This is hopeless. First of all, it seems that HTTP wants Day and Month
+ NAMES? In English? Whose idea was that? Even worse, the date/time must be
+ expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
+ nightmare. Every platform does it differently, if at all -- even if we
+ restrict ourselves to UNIX. For example (quoting from recent C-Kermit edit
+ history), "Fixed a longstanding bug in the BSDI version, in which incoming
+ file dates were set in GMT rather than local time. It seems in 4.4BSD,
+ localtime() does not return the local time, but rather Zero Meridian (Zulu)
+ time (GMT), and must be adjusted by the tm_gmtoff value." Swell. For
+ greater appreciation of the scope of the problem, just take a look at the
+ time-related #ifdefs in ckutio.c. The only right way to do this is to add
+ our own portable API for converting between local time and GMT/UTC/Zulu
+ that shields us not only from UNIXisms like time_t and struct tm, but also
+ the unbelievable amount of differences in time-related APIs -- e.g. is
+ "timezone" an external variable or a function; which header file(s) do we
+ include, etc etc etc. It's a major project.
+*/
+ int x;
+ x = cmcvtdate("",1);
+
+Evidently this code is not used -- if it is, it must be fixed to use
+new (aug 2001) cmcvtdate() calling conventions.
+
+ if (x < 0)
+ return("");
+/* yyyymmdd hh:mm:ss */
+/* 01234567890123456 */
+ nowstr[0] = 'X'; /* 1st letter of day */
+ nowstr[1] = 'x'; /* 2nd letter of day */
+ nowstr[2] = 'x'; /* 3rd letter of day */
+ nowstr[3] = ',';
+ nowstr[4] = ' ';
+ nowstr[5] = cmdate[6];
+ nowstr[6] = cmdate[7];
+ nowstr[7] = ' ';
+ nowstr[8] = ' '; /* first letter of month */
+ nowstr[9] = ' '; /* second letter of month */
+ nowstr[10] = ' '; /* third letter of month */
+ nowstr[11] = ' ';
+ nowstr[12] = cmdate[0];
+ nowstr[13] = cmdate[1];
+ nowstr[14] = cmdate[2];
+ nowstr[15] = cmdate[3];
+ nowstr[16] = ' ';
+ nowstr[17] = cmdate[9];
+ nowstr[18] = cmdate[10];
+ nowstr[19] = cmdate[11];
+ nowstr[20] = cmdate[12];
+ nowstr[21] = cmdate[13];
+ nowstr[22] = cmdate[14];
+ nowstr[23] = cmdate[15];
+ nowstr[24] = cmdate[16];
+ nowstr[25] = ' ';
+ nowstr[26] = 'G';
+ nowstr[27] = 'M';
+ nowstr[28] = 'T';
+ nowstr[29] = '\0';
+#endif /* CMDATE2TM */
+ return(nowstr);
+}
+
+#ifndef OS2
+#ifndef CK_AUTHENTICATION
+/* from ckuusr.h, which this module normally doesn't include */
+_PROTOTYP( int dclarray, (char, int) );
+#endif /* CK_AUTHENTICATION */
+#endif /* OS2 */
+/*
+ Assign http response pairs to given array.
+ For best results, response pairs should contain no spaces.
+
+ Call with:
+ resp = pointer to response list.
+ n = size of response list.
+ array = array letter.
+ Returns:
+ 0 on failure.
+ >= 1, size of array, on success.
+*/
+static int
+#ifdef CK_ANSIC
+http_mkarray(char ** resp, int n, char array)
+#else
+http_mkarray(resp, n, array) char ** resp; int n; char array;
+#endif /* CK_ANSIC */
+{
+#ifndef NOSPL
+ int i, x;
+ char ** ap;
+ extern char ** a_ptr[];
+ extern int a_dim[];
+
+ if (!array || n <= 0)
+ return(0);
+ if ((x = dclarray(array,n)) < 0) {
+ printf("?Array declaration failure\n");
+ return(-9);
+ }
+ /* Note: argument array is 0-based but Kermit array is 1-based */
+ ap = a_ptr[x];
+ ap[0] = NULL; /* 0th element is empty */
+ for (i = 1; i <= n; i++) {
+ ap[i] = resp[i-1]; /* If resp elements were malloc'd */
+ resp[i-1] = NULL;
+ }
+ a_dim[x] = n;
+ return(n);
+#else
+ return(0);
+#endif /* NOSPL */
+}
+
+#define HTTPHEADCNT 64
+int
+http_get_chunk_len()
+{
+ int len = 0;
+ int i = 0, j = -1;
+ char buf[24];
+ int ch;
+
+ while ((ch = http_inc(0)) >= 0 && i < 24) {
+ buf[i] = ch;
+ if ( buf[i] == ';' ) /* Find chunk-extension (if any) */
+ j = i;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ buf[i] = '\0';
+ break;
+ }
+ i++;
+ }
+ if ( i < 24 ) { /* buf now contains len in Hex */
+ len = hextoulong(buf, j == -1 ? i : j-1);
+ }
+
+ return(len);
+}
+
+int
+http_isconnected()
+{
+ return(httpfd != -1);
+}
+
+char *
+http_host()
+{
+ return(httpfd != -1 ? http_host_port : "");
+}
+
+char *
+http_security()
+{
+ if ( httpfd == -1 )
+ return("NULL");
+#ifdef CK_SSL
+ if (tls_http_active_flag) {
+ SSL_CIPHER * cipher;
+ const char *cipher_list;
+ static char buf[128];
+ buf[0] = NUL;
+ cipher = SSL_get_current_cipher(tls_http_con);
+ cipher_list = SSL_CIPHER_get_name(cipher);
+ SSL_CIPHER_description(cipher,buf,sizeof(buf));
+ return(buf);
+ }
+#endif /* CK_SSL */
+ return("NULL");
+}
+
+int
+http_reopen()
+{
+ int rc = 0;
+ char * s = NULL; /* strdup is not portable */
+ if ( tcp_http_proxy ) {
+ char * p;
+ makestr(&s,(char *)http_host_port);
+ p = s;
+ while (*p != '\0' && *p != ':') p++; /* Look for colon */
+ if (*p == ':') { /* Have a colon */
+ *p++ = '\0'; /* Get service name or number */
+ } else {
+ p="http";
+ }
+ rc = http_open(s,p,http_ssl,NULL,0,http_agent);
+ } else {
+ makestr(&s,(char *)http_ip);
+ rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
+ }
+ free(s);
+ return(rc);
+}
+
+
+int
+#ifdef CK_ANSIC
+http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
+ int rdns_len, char * agent)
+#else /* CK_ANSIC */
+http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
+ char * hostname;
+ char * svcname;
+ int use_ssl;
+ char * rdns_name;
+ int rdns_len;
+ char * agent;
+#endif /* CK_ANSIC */
+{
+ char namecopy[NAMECPYL];
+ char *p;
+ int i, x, dns = 0;
+#ifdef TCPSOCKET
+ int isconnect = 0;
+#ifdef SO_OOBINLINE
+ int on = 1;
+#endif /* SO_OOBINLINE */
+ struct servent *service=NULL;
+ struct hostent *host=NULL;
+ struct sockaddr_in r_addr;
+ struct sockaddr_in sin;
+ struct sockaddr_in l_addr;
+ GSOCKNAME_T l_slen;
+#ifdef EXCELAN
+ struct sockaddr_in send_socket;
+#endif /* EXCELAN */
+
+#ifdef INADDRX
+/* inet_addr() is of type struct in_addr */
+#ifdef datageneral
+ extern struct in_addr inet_addr();
+#else
+#ifdef HPUX5WINTCP
+ extern struct in_addr inet_addr();
+#endif /* HPUX5WINTCP */
+#endif /* datageneral */
+ struct in_addr iax;
+#else
+#ifdef INADDR_NONE
+ struct in_addr iax;
+#else /* INADDR_NONE */
+ long iax;
+#endif /* INADDR_NONE */
+#endif /* INADDRX */
+
+ if ( rdns_name == NULL || rdns_len < 0 )
+ rdns_len = 0;
+
+ *http_ip = '\0'; /* Initialize IP address string */
+ namecopy[0] = '\0';
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"http_open hostname",hostname,0);
+ debug(F110,"http_open svcname",svcname,0);
+ }
+#endif /* DEBUG */
+ if (!hostname) hostname = "";
+ if (!svcname) svcname = "";
+ if (!*hostname || !*svcname) return(-1);
+
+
+ service = ckgetservice(hostname,svcname,http_ip,20);
+
+ if (service == NULL) {
+ if ( !quiet )
+ printf("?Invalid service: %s\r\n",svcname);
+ return(-1);
+ }
+
+ /* For HTTP connections we must preserve the original hostname and */
+ /* service requested so we can include them in the Host header. */
+ ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
+ ckuitoa(ntohs(service->s_port)),NULL);
+ http_port = ntohs(service->s_port);
+ http_ssl = use_ssl;
+ debug(F111,"http_open",http_host_port,http_port);
+
+ /* 'http_ip' contains the IP address to which we want to connect */
+ /* 'svcnam' contains the service name */
+ /* 'service->s_port' contains the port number in network byte order */
+
+ /* If we are using an http proxy, we need to create a buffer containing */
+ /* hostname:port-number */
+ /* to pass to the http_connect() function. Then we need to replace */
+ /* 'namecopy' with the name of the proxy server and the service->s_port */
+ /* with the port number of the proxy (default port 80). */
+
+ if ( tcp_http_proxy ) {
+
+ ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
+ ckuitoa(ntohs(service->s_port)),NULL);
+ ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
+
+ p = namecopy; /* Was a service requested? */
+ while (*p != '\0' && *p != ':') p++; /* Look for colon */
+ if (*p == ':') { /* Have a colon */
+ debug(F110,"http_open name has colon",namecopy,0);
+ *p++ = '\0'; /* Get service name or number */
+ } else {
+ strcpy(++p,"http");
+ }
+
+ service = ckgetservice(namecopy,p,http_ip,20);
+ if (!service) {
+ fprintf(stderr, "Can't find port for service %s\n", p);
+#ifdef TGVORWIN
+ debug(F101,"http_open can't get service for proxy","",socket_errno);
+#else
+ debug(F101,"http_open can't get service for proxy","",errno);
+#endif /* TGVORWIN */
+ errno = 0; /* (rather than mislead) */
+ return(-1);
+ }
+
+ /* copy the proxyname and remove the service if any so we can use
+ * it as the hostname
+ */
+ ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
+ p = namecopy; /* Was a service requested? */
+ while (*p != '\0' && *p != ':') p++; /* Look for colon */
+ if (*p == ':') { /* Have a colon */
+ *p = '\0'; /* terminate string */
+ }
+ hostname = namecopy; /* use proxy as hostname */
+ }
+
+ /* Set up socket structure and get host address */
+ bzero((char *)&r_addr, sizeof(r_addr));
+ debug(F100,"http_open bzero ok","",0);
+
+#ifdef INADDR_NONE
+ debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
+#else /* INADDR_NONE */
+ debug(F100,"http_open INADDR_NONE not defined","",0);
+#endif /* INADDR_NONE */
+#ifdef INADDRX
+ debug(F100,"http_open INADDRX defined","",0);
+#else /* INADDRX */
+ debug(F100,"http_open INADDRX not defined","",0);
+#endif /* INADDRX */
+
+#ifndef NOMHHOST
+#ifdef INADDRX
+ iax = inet_addr(http_ip[0]?http_ip:hostname);
+ debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
+#else /* INADDRX */
+#ifdef INADDR_NONE
+ iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
+ debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
+#else /* INADDR_NONE */
+#ifndef datageneral
+ iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
+#else
+ iax = -1L;
+#endif /* datageneral */
+ debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
+#endif /* INADDR_NONE */
+#endif /* INADDRX */
+
+ dns = 0;
+ if (
+#ifdef INADDR_NONE
+/* This might give warnings on 64-bit platforms but they should be harmless */
+/* because INADDR_NONE should be all 1's anyway, thus the OR part is */
+/* probably superfluous -- not sure why it's even there, maybe it should be */
+/* removed. */
+ iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
+#else /* INADDR_NONE */
+ iax == -1
+#endif /* INADDR_NONE */
+ ) {
+ if (!quiet) {
+ printf(" DNS Lookup... ");
+ fflush(stdout);
+ }
+ if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
+ debug(F100,"http_open gethostbyname != NULL","",0);
+ host = ck_copyhostent(host);
+ dns = 1; /* Remember we performed dns lookup */
+ r_addr.sin_family = host->h_addrtype;
+ if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
+ && (tcp_http_proxy == NULL)
+ )
+ ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
+
+#ifdef HADDRLIST
+#ifdef h_addr
+ /* This is for trying multiple IP addresses - see <netdb.h> */
+ if (!(host->h_addr_list))
+ return(-1);
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&r_addr.sin_addr,
+ host->h_length
+ );
+#else
+ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
+#endif /* h_addr */
+#else /* HADDRLIST */
+ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
+#endif /* HADDRLIST */
+#ifdef COMMENT
+#ifndef EXCELAN
+ debug(F111,"BCOPY","host->h_addr",host->h_addr);
+#endif /* EXCELAN */
+ debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
+ (caddr_t)&r_addr.sin_addr);
+ debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
+ r_addr.sin_addr.s_addr);
+#endif /* COMMENT */
+ debug(F111,"BCOPY","host->h_length",host->h_length);
+ }
+ }
+#endif /* NOMHHOST */
+
+ if (!dns) {
+#ifdef INADDRX
+/* inet_addr() is of type struct in_addr */
+ struct in_addr ina;
+ unsigned long uu;
+ debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
+ ina = inet_addr(http_ip[0]?http_ip:hostname);
+ uu = *(unsigned int *)&ina;
+#else /* Not INADDRX */
+/* inet_addr() is unsigned long */
+ unsigned long uu;
+ debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
+ uu = inet_addr(http_ip[0]?http_ip:hostname);
+#endif /* INADDRX */
+ debug(F101,"http_open uu","",uu);
+ if (
+#ifdef INADDR_NONE
+ !(uu == INADDR_NONE || uu == (unsigned int) -1L)
+#else /* INADDR_NONE */
+ uu != ((unsigned long)-1)
+#endif /* INADDR_NONE */
+ ) {
+ r_addr.sin_addr.s_addr = uu;
+ r_addr.sin_family = AF_INET;
+ } else {
+#ifdef VMS
+ fprintf(stdout, "\r\n"); /* complete any previous message */
+#endif /* VMS */
+ fprintf(stderr, "Can't get address for %s\n",
+ http_ip[0]?http_ip:hostname);
+#ifdef TGVORWIN
+ debug(F101,"http_open can't get address","",socket_errno);
+#else
+ debug(F101,"http_open can't get address","",errno);
+#endif /* TGVORWIN */
+ errno = 0; /* Rather than mislead */
+ return(-1);
+ }
+ }
+
+ /* Get a file descriptor for the connection. */
+
+ r_addr.sin_port = service->s_port;
+ ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
+ debug(F110,"http_open trying",http_ip,0);
+ if (!quiet && *http_ip) {
+ printf(" Trying %s... ", http_ip);
+ fflush(stdout);
+ }
+
+ /* Loop to try additional IP addresses, if any. */
+
+ do {
+#ifdef EXCELAN
+ send_socket.sin_family = AF_INET;
+ send_socket.sin_addr.s_addr = 0;
+ send_socket.sin_port = 0;
+ if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
+ &send_socket, SO_REUSEADDR)) < 0)
+#else /* EXCELAN */
+ if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+#endif /* EXCELAN */
+ {
+#ifdef EXCELAN
+ experror("TCP socket error");
+#else
+#ifdef TGVORWIN
+#ifdef OLD_TWG
+ errno = socket_errno;
+#endif /* OLD_TWG */
+ socket_perror("TCP socket error");
+ debug(F101,"http_open socket error","",socket_errno);
+#else
+ perror("TCP socket error");
+ debug(F101,"http_open socket error","",errno);
+#endif /* TGVORWIN */
+#endif /* EXCELAN */
+ return (-1);
+ }
+ errno = 0;
+
+ /* If a specific TCP address on the local host is desired we */
+ /* must bind it to the socket. */
+#ifndef datageneral
+ if (tcp_address) {
+ int s_errno;
+
+ debug(F110,"http_open binding socket to",tcp_address,0);
+ bzero((char *)&sin,sizeof(sin));
+ sin.sin_family = AF_INET;
+#ifdef INADDRX
+ inaddrx = inet_addr(tcp_address);
+ sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
+#else
+ sin.sin_addr.s_addr = inet_addr(tcp_address);
+#endif /* INADDRX */
+ sin.sin_port = 0;
+ if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ s_errno = socket_errno; /* Save error code */
+#ifdef TCPIPLIB
+ socket_close(httpfd);
+#else /* TCPIPLIB */
+ close(httpfd);
+#endif /* TCPIPLIB */
+ httpfd = -1;
+ errno = s_errno; /* and report this error */
+ debug(F101,"http_open bind errno","",errno);
+ return(-1);
+ }
+ }
+#endif /* datageneral */
+
+/* Now connect to the socket on the other end. */
+
+#ifdef EXCELAN
+ if (connect(httpfd, &r_addr) < 0)
+#else
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+ if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
+#endif /* EXCELAN */
+ {
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#ifdef OS2
+ i = socket_errno;
+#else /* OS2 */
+#ifdef TGVORWIN
+ i = socket_errno;
+#else
+ i = errno; /* Save error code */
+#endif /* TGVORWIN */
+#endif /* OS2 */
+#ifdef HADDRLIST
+#ifdef h_addr
+ if (host && host->h_addr_list && host->h_addr_list[1]) {
+ perror("");
+ host->h_addr_list++;
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&r_addr.sin_addr,
+ host->h_length);
+
+ ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
+ debug(F110,"http_open h_addr_list",http_ip,0);
+ if (!quiet && *http_ip) {
+ printf(" Trying %s... ", http_ip);
+ fflush(stdout);
+ }
+#ifdef TCPIPLIB
+ socket_close(httpfd); /* Close it. */
+#else
+ close(httpfd);
+#endif /* TCPIPLIB */
+ continue;
+ }
+#endif /* h_addr */
+#endif /* HADDRLIST */
+ http_close();
+ httpfd = -1;
+ errno = i; /* And report this error */
+#ifdef EXCELAN
+ if (errno) experror("http_open connect");
+#else
+#ifdef TGVORWIN
+ debug(F101,"http_open connect error","",socket_errno);
+ /* if (errno) socket_perror("http_open connect"); */
+#ifdef OLD_TWG
+ errno = socket_errno;
+#endif /* OLD_TWG */
+ if (!quiet)
+ socket_perror("http_open connect");
+#else /* TGVORWIN */
+ debug(F101,"http_open connect errno","",errno);
+#ifdef VMS
+ if (!quiet)
+ perror("\r\nFailed");
+#else
+ if (!quiet)
+ perror("Failed");
+#endif /* VMS */
+#ifdef DEC_TCPIP
+ if (!quiet)
+ perror("http_open connect");
+#endif /* DEC_TCPIP */
+#ifdef CMU_TCPIP
+ if (!quiet)
+ perror("http_open connect");
+#endif /* CMU_TCPIP */
+#endif /* TGVORWIN */
+#endif /* EXCELAN */
+ return(-1);
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+ isconnect = 1;
+ } while (!isconnect);
+
+#ifdef NON_BLOCK_IO
+ on = 1;
+ x = socket_ioctl(httpfd,FIONBIO,&on);
+ debug(F101,"http_open FIONBIO","",x);
+#endif /* NON_BLOCK_IO */
+
+ /* We have succeeded in connecting to the HTTP PROXY. So now we */
+ /* need to attempt to connect through the proxy to the actual host */
+ /* If that is successful, we have to pretend that we made a direct */
+ /* connection to the actual host. */
+
+ if ( tcp_http_proxy ) {
+#ifdef OS2
+ if (!agent)
+ agent = "Kermit 95"; /* Default user agent */
+#else
+ if (!agent)
+ agent = "C-Kermit";
+#endif /* OS2 */
+
+ if (http_connect(httpfd,
+ tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
+ NULL,
+ tcp_http_proxy_user,
+ tcp_http_proxy_pwd,
+ 0,
+ proxycopy
+ ) < 0) {
+ http_close();
+ return(-1);
+ }
+ }
+
+#ifdef SO_OOBINLINE
+ /* See note on SO_OOBINLINE in netopen() */
+#ifdef datageneral
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef BSD43
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef OSF1
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef POSIX
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef MOTSV88R4
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef SOLARIS
+/*
+ Maybe this applies to all SVR4 versions, but the other (else) way has been
+ compiling and working fine on all the others, so best not to change it.
+*/
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef OSK
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef OS2
+ {
+ int rc;
+ rc = setsockopt(httpfd,
+ SOL_SOCKET,
+ SO_OOBINLINE,
+ (char *) &on,
+ sizeof on
+ );
+ debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
+ }
+#else
+#ifdef VMS /* or, at least, VMS with gcc */
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+#ifdef CLIX
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
+#else
+ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
+#endif /* CLIX */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* OSK */
+#endif /* SOLARIS */
+#endif /* MOTSV88R4 */
+#endif /* POSIX */
+#endif /* BSD43 */
+#endif /* OSF1 */
+#endif /* datageneral */
+#endif /* SO_OOBINLINE */
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+ no_delay(ttyfd,tcp_nodelay);
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+ keepalive(ttyfd,tcp_keepalive);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
+#endif /* SO_LINGER */
+#ifdef SO_SNDBUF
+ sendbuf(ttyfd,tcp_sendbuf);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ recvbuf(ttyfd,tcp_recvbuf);
+#endif /* SO_RCVBUF */
+#endif /* SOL_SOCKET */
+#endif /* datageneral */
+#endif /* NOTCPOPTS */
+
+#ifndef datageneral
+ /* Find out our own IP address. */
+ /* We need the l_addr structure for [E]KLOGIN. */
+ l_slen = sizeof(l_addr);
+ bzero((char *)&l_addr, l_slen);
+#ifndef EXCELAN
+ if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
+ char * s = (char *)inet_ntoa(l_addr.sin_addr);
+ ckstrncpy(myipaddr, s, 20);
+ debug(F110,"getsockname",myipaddr,0);
+ }
+#endif /* EXCELAN */
+#endif /* datageneral */
+
+/* See note in netopen() on Reverse DNS lookups */
+ if (tcp_rdns == SET_ON) {
+#ifdef NT
+ if (isWin95())
+ sleep(1);
+#endif /* NT */
+ if (!quiet) {
+ printf(" Reverse DNS Lookup... ");
+ fflush(stdout);
+ }
+ if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
+ char * s;
+ host = ck_copyhostent(host);
+ debug(F100,"http_open gethostbyname != NULL","",0);
+ if (!quiet) {
+ printf("(OK)\n");
+ fflush(stdout);
+ }
+ s = host->h_name;
+ if (!s) { /* This can happen... */
+ debug(F100,"http_open host->h_name is NULL","",0);
+ s = "";
+ }
+ /* Something is wrong with inet_ntoa() on HPUX 10.xx */
+ /* The compiler says "Integral value implicitly converted to */
+ /* pointer in assignment." The prototype is right there */
+ /* in <arpa/inet.h> so what's the problem? */
+ /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
+ if (!*s) { /* No name so substitute the address */
+ debug(F100,"http_open host->h_name is empty","",0);
+ s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
+ if (!s) /* Trust No 1 */
+ s = "";
+ if (*s) { /* If it worked, use this string */
+ ckstrncpy(http_ip,s,20);
+ }
+ s = http_ip; /* Otherwise stick with the IP */
+ if (!*s) /* or failing that */
+ s = http_host_port; /* the name we were called with. */
+ }
+ if (*s) /* return the rdns name */
+ ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
+
+ if (!quiet && *s
+#ifndef NOICP
+ && !doconx
+#endif /* NOICP */
+ ) {
+ printf(" %s connected on port %s\n",s,
+ ckuitoa(ntohs(service->s_port)));
+#ifdef BETADEBUG
+ /* This is simply for testing the DNS entries */
+ if (host->h_aliases) {
+ char ** a = host->h_aliases;
+ while (*a) {
+ printf(" alias => %s\n",*a);
+ a++;
+ }
+ }
+#endif /* BETADEBUG */
+ }
+ } else {
+ if (!quiet) printf("Failed.\n");
+ }
+ } else if (!quiet) printf("(OK)\n");
+ if (!quiet) fflush(stdout);
+
+
+ if ( tcp_http_proxy ) {
+ /* Erase the IP address since we cannot reuse it */
+ http_ip[0] = '\0';
+ } else {
+ /* This should already have been done but just in case */
+ ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
+ }
+ makestr(&http_agent,agent);
+
+#ifdef CK_SSL
+ if (use_ssl && ck_ssleay_is_installed()) {
+ if (!ssl_http_init(hostname)) {
+ if (bio_err!=NULL) {
+ BIO_printf(bio_err,"ssl_tn_init() failed\n");
+ ERR_print_errors(bio_err);
+ } else {
+ fflush(stderr);
+ fprintf(stderr,"ssl_tn_init() failed\n");
+ ERR_print_errors_fp(stderr);
+ }
+ http_close();
+ return(-1);
+ } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
+ http_close();
+ return(-1);
+ }
+ }
+#endif /* CK_SSL */
+#endif /* TCPSOCKET */
+
+ return(0); /* Done. */
+}
+
+int
+#ifdef CK_ANSIC
+http_close(VOID)
+#else /* CK_ANSIC */
+http_close()
+#endif /* CK_ANSIC */
+{
+ int x = 0;
+ debug(F101,"http_close","",httpfd);
+
+#ifdef HTTP_BUFFERING
+ http_count = 0;
+ http_bufp = 0;
+#endif /* HTTP_BUFFERING */
+
+ if (httpfd == -1) /* Was open? */
+ return(0); /* Wasn't. */
+
+#ifndef OS2
+ if (httpfd > -1) /* Was. */
+#endif /* OS2 */
+ {
+#ifdef CK_SSL
+ if (tls_http_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown\n");
+ SSL_shutdown(tls_http_con);
+ tls_http_active_flag = 0;
+ }
+#endif /* CK_SSL */
+#ifdef TCPIPLIB
+ x = socket_close(httpfd); /* Close it. */
+#else
+#ifndef OS2
+ x = close(httpfd);
+#endif /* OS2 */
+#endif /* TCPIPLIB */
+ }
+ httpfd = -1; /* Mark it as closed. */
+ /* do not erase http_host_port, http_ip, http_port so they */
+ /* can be used by http_reopen() */
+ return(x);
+}
+
+
+/* http_tol()
+ * Call with s = pointer to string, n = length.
+ * Returns number of bytes actually written on success, or
+ * -1 on i/o error, -2 if called improperly.
+ */
+
+int
+http_tol(s,n) CHAR *s; int n; {
+ int count = 0;
+ int len = n;
+ int try = 0;
+
+ if (httpfd == -1) {
+ debug(F100,"http_tol socket is closed","",0);
+ return -1;
+ }
+ debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
+#ifdef COMMENT
+ ckhexdump("http_tol",s,n);
+#endif /* COMMENT */
+
+#ifdef CK_SSL
+ if (tls_http_active_flag) {
+ int error, r;
+ /* Write using SSL */
+ ssl_retry:
+ r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
+ switch (SSL_get_error(tls_http_con,r)) {
+ case SSL_ERROR_NONE:
+ debug(F111,"http_tol","SSL_write",r);
+ if ( r == len )
+ return(n);
+ s += r;
+ len -= r;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
+ return(-1);
+ case SSL_ERROR_WANT_READ:
+ debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if ( r == 0 ) { /* EOF */
+ http_close();
+ return(-2);
+ } else {
+ int rc = -1;
+#ifdef NT
+ int gle = GetLastError();
+ debug(F111,"http_tol SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ return -1;
+#endif /* NT */
+ return(rc);
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
+ http_close();
+ return(-2);
+ case SSL_ERROR_SSL:
+ debug(F100,"http_tol SSL_ERROR_SSL","",0);
+ http_close();
+ return(-2);
+ case SSL_ERROR_ZERO_RETURN:
+ debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
+ http_close();
+ return(-2);
+ default:
+ debug(F100,"http_tol SSL_ERROR_?????","",0);
+ http_close();
+ return(-2);
+ }
+ }
+#endif /* CK_SSL */
+
+ http_tol_retry:
+ try++; /* Increase the try counter */
+
+ {
+#ifdef BSDSELECT
+ fd_set wfds;
+ struct timeval tv;
+
+ debug(F101,"http_tol BSDSELECT","",0);
+ tv.tv_usec = 0L;
+ tv.tv_sec=30;
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+#ifdef STREAMING
+ do_select:
+#endif /* STREAMING */
+ FD_ZERO(&wfds);
+ FD_SET(httpfd, &wfds);
+ if (select(FD_SETSIZE, NULL,
+#ifdef __DECC
+#ifndef __DECC_VER
+ (int *)
+#endif /* __DECC_VER */
+#endif /* __DECC */
+ &wfds, NULL, &tv) < 0) {
+ int s_errno = socket_errno;
+ debug(F101,"http_tol select failed","",s_errno);
+#ifdef BETADEBUG
+ printf("http_tol select failed: %d\n", s_errno);
+#endif /* BETADEBUG */
+#ifdef NT
+ WSASafeToCancel = 0;
+ if (!win95selectbug)
+#endif /* NT */
+ return(-1);
+ }
+ if (!FD_ISSET(httpfd, &wfds)) {
+#ifdef STREAMING
+ if (streaming)
+ goto do_select;
+#endif /* STREAMING */
+ debug(F111,"http_tol","!FD_ISSET",ttyfd);
+#ifdef NT
+ WSASafeToCancel = 0;
+ if (!win95selectbug)
+#endif /* NT */
+ return(-1);
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#else /* BSDSELECT */
+#ifdef IBMSELECT
+ {
+ int tries = 0;
+ debug(F101,"http_tol IBMSELECT","",0);
+ while (select(&httpfd, 0, 1, 0, 1000) != 1) {
+ int count;
+ if (tries++ >= 60) {
+ /* if after 60 seconds we can't get permission to write */
+ debug(F101,"http_tol select failed","",socket_errno);
+ return(-1);
+ }
+#ifdef COMMENT
+ if ((count = http_tchk()) < 0) {
+ debug(F111,"http_tol","http_tchk()",count);
+ return(count);
+ }
+#endif /* COMMENT */
+ }
+ }
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+#ifdef TCPIPLIB
+ if ((count = socket_write(httpfd,s,n)) < 0) {
+ int s_errno = socket_errno; /* maybe a function */
+ debug(F101,"http_tol socket_write error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-2);
+#endif /* OS2 */
+ return(-1); /* Call it an i/o error */
+ }
+#else /* TCPIPLIB */
+ if ((count = write(httpfd,s,n)) < 0) {
+ debug(F101,"http_tol socket_write error","",errno);
+ return(-1); /* Call it an i/o error */
+ }
+#endif /* TCPIPLIB */
+ if (count < n) {
+ debug(F111,"http_tol socket_write",s,count);
+ if (try > 25) {
+ /* don't try more than 25 times */
+ debug(F100,"http_tol tried more than 25 times","",0);
+ return(-1);
+ }
+ if (count > 0) {
+ s += count;
+ n -= count;
+ }
+ debug(F111,"http_tol retry",s,n);
+ goto http_tol_retry;
+ } else {
+ debug(F111,"http_tol socket_write",s,count);
+ return(len); /* success - return total length */
+ }
+ }
+}
+
+int
+http_inc(timo) int timo; {
+ int x=-1; unsigned char c; /* The locals. */
+
+ if (httpfd == -1) {
+#ifdef HTTP_BUFFERING
+ http_count = 0;
+ http_bufp = 0;
+#endif /* HTTP_BUFFERING */
+ debug(F100,"http_inc socket is closed","",0);
+ return(-2);
+ }
+
+#ifdef CK_SSL
+ /*
+ * In the case of OpenSSL, it is possible that there is still
+ * data waiting in the SSL session buffers that has not yet
+ * been read by Kermit. If this is the case we must process
+ * it without calling select() because select() will not return
+ * with an indication that there is data to be read from the
+ * socket. If there is no data pending in the SSL session
+ * buffers then fall through to the select() code and wait for
+ * some data to arrive.
+ */
+ if (tls_http_active_flag) {
+ int error;
+
+ x = SSL_pending(tls_http_con);
+ if (x < 0) {
+ debug(F111,"http_inc","SSL_pending error",x);
+ http_close();
+ return(-1);
+ } else if ( x > 0 ) {
+ ssl_read:
+ x = SSL_read(tls_http_con, &c, 1);
+ error = SSL_get_error(tls_http_con,x);
+ switch (error) {
+ case SSL_ERROR_NONE:
+ debug(F111,"http_inc SSL_ERROR_NONE","x",x);
+ if (x > 0) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(c); /* Return character. */
+ } else if (x < 0) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ } else {
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ case SSL_ERROR_WANT_WRITE:
+ debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ case SSL_ERROR_WANT_READ:
+ debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if ( x == 0 ) { /* EOF */
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ } else {
+ int rc = -1;
+#ifdef NT
+ int gle = GetLastError();
+ debug(F111,"http_inc SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ rc = -1;
+#endif /* NT */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(rc);
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ case SSL_ERROR_SSL:
+ debug(F100,"http_inc SSL_ERROR_SSL","",0);
+#ifdef COMMENT
+ http_close();
+#endif /* COMMENT */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ case SSL_ERROR_ZERO_RETURN:
+ debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ default:
+ debug(F100,"http_inc SSL_ERROR_?????","",0);
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ }
+ }
+#endif /* CK_SSL */
+
+#ifdef HTTP_BUFFERING
+ /* Skip all the select() stuff if we have bytes buffered locally */
+ if (http_count > 0)
+ goto getfrombuffer;
+#endif /* HTTP_BUFFERING */
+
+ {
+#ifdef BSDSELECT
+ fd_set rfds;
+ struct timeval tv;
+ int timeout = timo < 0 ? -timo : 1000 * timo;
+ debug(F101,"http_inc BSDSELECT","",timo);
+
+ for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
+ int rc;
+ debug(F111,"http_inc","timeout",timeout);
+ /* Don't move select() initialization out of the loop. */
+ FD_ZERO(&rfds);
+ FD_SET(httpfd, &rfds);
+ tv.tv_sec = tv.tv_usec = 0L;
+ if (timo)
+ tv.tv_usec = (long) 100000L;
+ else
+ tv.tv_sec = 30;
+#ifdef NT
+ WSASafeToCancel = 1;
+#endif /* NT */
+ rc = select(FD_SETSIZE,
+#ifndef __DECC
+ (fd_set *)
+#endif /* __DECC */
+ &rfds, NULL, NULL, &tv);
+ if (rc < 0) {
+ int s_errno = socket_errno;
+ debug(F111,"http_inc","select",rc);
+ debug(F111,"http_inc","socket_errno",s_errno);
+#ifdef HTTP_BUFFERING
+ http_count = 0;
+ http_bufp = 0;
+#endif /* HTTP_BUFFERING */
+ if (s_errno)
+ return(-1);
+ }
+ debug(F111,"http_inc","select",rc);
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+ if (FD_ISSET(httpfd, &rfds)) {
+ x = 0;
+ break;
+ } else {
+ /* If waiting forever we have no way of knowing if the */
+ /* socket closed so try writing a 0-length TCP packet */
+ /* which should force an error if the socket is closed */
+ if (!timo) {
+#ifdef TCPIPLIB
+ if ((rc = socket_write(httpfd,"",0)) < 0) {
+#ifdef HTTP_BUFFERING
+ http_count = 0;
+ http_bufp = 0;
+#endif /* HTTP_BUFFERING */
+ int s_errno = socket_errno;
+ debug(F101,"http_inc socket_write error","",s_errno);
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-2);
+#endif /* OS2 */
+ return(-1); /* Call it an i/o error */
+ }
+#else /* TCPIPLIB */
+ if ((rc = write(httpfd,"",0)) < 0) {
+#ifdef HTTP_BUFFERING
+ http_count = 0;
+ http_bufp = 0;
+#endif /* HTTP_BUFFERING */
+ debug(F101,"http_inc socket_write error","",errno);
+ return(-1); /* Call it an i/o error */
+ }
+#endif /* TCPIPLIB */
+ }
+ continue;
+ }
+ }
+#ifdef NT
+ WSASafeToCancel = 0;
+#endif /* NT */
+#else /* !BSDSELECT */
+#ifdef IBMSELECT
+ /*
+ Was used by OS/2, currently not used, but might come in handy some day...
+ ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
+ and timeval stuff since this is the only place where it is used.
+ */
+ int socket = httpfd;
+ int timeout = timo < 0 ? -timo : 1000 * timo;
+
+ debug(F101,"http_inc IBMSELECT","",timo);
+ for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
+ if (select(&socket, 1, 0, 0, 100L) == 1) {
+ x = 0;
+ break;
+ }
+ }
+#else /* !IBMSELECT */
+ SELECT is required for this code
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+ }
+
+ if (timo && x < 0) { /* select() timed out */
+#ifdef HTTP_BUFFERING
+ http_count = 0;
+ http_bufp = 0;
+#endif /* HTTP_BUFFERING */
+ debug(F100,"http_inc select() timed out","",0);
+ return(-1); /* Call it an i/o error */
+ }
+
+#ifdef CK_SSL
+ if ( tls_http_active_flag ) {
+ int error;
+ ssl_read2:
+ x = SSL_read(tls_http_con, &c, 1);
+ error = SSL_get_error(tls_http_con,x);
+ switch (error) {
+ case SSL_ERROR_NONE:
+ debug(F111,"http_inc SSL_ERROR_NONE","x",x);
+ if (x > 0) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(c); /* Return character. */
+ } else if (x < 0) {
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ } else {
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ case SSL_ERROR_WANT_WRITE:
+ debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ case SSL_ERROR_WANT_READ:
+ debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if ( x == 0 ) { /* EOF */
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ } else {
+ int rc = -1;
+#ifdef NT
+ int gle = GetLastError();
+ debug(F111,"http_inc SSL_ERROR_SYSCALL",
+ "GetLastError()",gle);
+ rc = os2socketerror(gle);
+ if (rc == -1)
+ rc = -2;
+ else if ( rc == -2 )
+ rc = -1;
+#endif /* NT */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(rc);
+ }
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ case SSL_ERROR_SSL:
+ debug(F100,"http_inc SSL_ERROR_SSL","",0);
+#ifdef COMMENT
+ http_close();
+#endif /* COMMENT */
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ case SSL_ERROR_ZERO_RETURN:
+ debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ default:
+ debug(F100,"http_inc SSL_ERROR_?????","",0);
+ http_close();
+#ifdef OS2
+ ReleaseTCPIPMutex();
+#endif /* OS2 */
+ return(-2);
+ }
+ }
+#endif /* CK_SSL */
+
+#ifdef HTTP_BUFFERING
+/*
+ Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP
+ GETs were orders of magnitude too slow due to the single-byte read()s. The
+ file-descriptor swapping is pretty gross, but the more elegant solution
+ (calling a nettchk() like routine with the fd as a parameter) doesn't work,
+ because nettchk() relies on too many other routines that, like itself, are
+ hardwired for ttyfd.
+*/
+ getfrombuffer:
+ if (--http_count >= 0) {
+ c = http_inbuf[http_bufp++];
+ x = 1;
+ } else {
+ int savefd;
+ savefd = ttyfd;
+ ttyfd = httpfd;
+ x = nettchk();
+ ttyfd = savefd;
+ debug(F101,"http_inc nettchk","",x);
+ if (x > HTTP_INBUFLEN)
+ x = HTTP_INBUFLEN;
+#ifdef TCPIPLIB
+ x = socket_read(httpfd,http_inbuf,x);
+#else /* Not TCPIPLIB */
+ x = read(httpfd,http_inbuf,x);
+#endif /* TCPIPLIB */
+ http_count = 0;
+ http_bufp = 0;
+ if (x > 0) {
+ c = http_inbuf[http_bufp++];
+ http_count = x - 1;
+ }
+ }
+#else /* Not HTTP_BUFFERING */
+#ifdef TCPIPLIB
+ x = socket_read(httpfd,&c,1);
+#else /* Not TCPIPLIB */
+ x = read(httpfd,&c,1);
+#endif /* TCPIPLIB */
+#endif /* HTTP_BUFFERING */
+
+ if (x <= 0) {
+ int s_errno = socket_errno;
+ debug(F101,"ttbufr socket_read","",x);
+ debug(F101,"ttbufr socket_errno","",s_errno);
+#ifdef OS2
+ if (x == 0 || os2socketerror(s_errno) < 0) {
+ http_close();
+ ReleaseTCPIPMutex();
+ return(-2);
+ }
+ ReleaseTCPIPMutex();
+ return(-1);
+#else /* OS2 */
+ http_close(); /* *** *** */
+ return(-2);
+#endif /* OS2 */
+ }
+ return(c);
+}
+
+void
+#ifdef CK_ANSIC
+http_set_code_reply(char * msg)
+#else
+http_set_code_reply(msg)
+ char * msg;
+#endif /* CK_ANSIC */
+{
+ char * p = msg;
+ char buf[16];
+ int i=0;
+
+ while ( *p != SP && *p != NUL ) {
+ buf[i] = *p;
+ p++;
+ i++;
+ }
+
+ http_code = atoi(buf);
+
+ while ( *p == SP )
+ p++;
+
+ ckstrncpy(http_reply_str,p,HTTPBUFLEN);
+}
+
+int
+#ifdef CK_ANSIC
+http_get(char * agent, char ** hdrlist, char * user,
+ char * pwd, char array, char * local, char * remote,
+ int stdio)
+#else
+http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
+ char * agent; char ** hdrlist; char * user;
+ char * pwd; char array; char * local; char * remote;
+ int stdio;
+#endif /* CK_ANSIC */
+{
+ char * request = NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int ch;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p;
+ int nullline;
+#ifdef OS2
+ struct utimbuf u_t;
+#else /* OS2 */
+#ifdef SYSUTIMEH
+ struct utimbuf u_t;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } u_t;
+#endif /* SYSUTIMH */
+#endif /* OS2 */
+ time_t mod_t = 0;
+ time_t srv_t = 0;
+ time_t local_t = 0;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ char * headers[HTTPHEADCNT];
+ int closecon = 0;
+ int chunked = 0;
+ int zfile = 0;
+ int first = 1;
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"http_get httpfd","",httpfd);
+ debug(F110,"http_agent",agent,0);
+ debug(F110,"http_user",user,0);
+ debug(F110,"http_local",local,0);
+ debug(F110,"http_remote",remote,0);
+ }
+#endif /* DEBUG */
+ if (!remote) remote = "";
+
+ if (httpfd == -1)
+ return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+ len = 8; /* GET */
+ len += strlen(HTTP_VERSION);
+ len += strlen(remote);
+ len += 16;
+
+ if (hdrlist) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ len += (int) strlen(http_host_port) + 8;
+
+ if (agent)
+ len += 13 + strlen(agent);
+ if (user) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 24;
+ }
+#ifdef HTTP_CLOSE
+ len += 19; /* Connection: close */
+#endif
+ len += 3; /* blank line + null */
+
+ request = malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION); /* safe */
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user) {
+ ckstrncat(request,"Authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+#ifdef HTTP_CLOSE
+ ckstrncat(request,"Connection: close\r\n",len);
+#endif
+ ckstrncat(request,"\r\n",len);
+
+ getreq:
+ if (http_tol((CHAR *)request,strlen(request)) < 0)
+ {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto getreq;
+ }
+ rc = -1;
+ goto getexit;
+ }
+
+ /* Process the headers */
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ len = -1;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while ( isspace(*p) )
+ p++;
+ switch ( p[0] ) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ local = NULL;
+ }
+ http_set_code_reply(p);
+#ifdef CMDATE2TM
+ } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
+ mod_t = http_date(&buf[15]);
+ } else if (!ckstrcmp(buf,"Date",4,0)) {
+ srv_t = http_date(&buf[4]);
+#endif /* CMDATE2TM */
+ } else if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
+ len = atoi(&buf[16]);
+ } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
+ if ( ckindex("chunked",buf,18,0,0) != 0 )
+ chunked = 1;
+ debug(F101,"http_get chunked","",chunked);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ if (ch < 0 && first) {
+ first--;
+ http_close();
+ http_reopen();
+ goto getreq;
+ }
+ if (http_fnd == 0) {
+ rc = -1;
+ closecon = 1;
+ goto getexit;
+ }
+
+ /* Now we have the contents of the file */
+ if ( local && local[0] ) {
+ if (zopeno(ZOFILE,local,NULL,NULL))
+ zfile = 1;
+ else
+ rc = -1;
+ }
+
+ if ( chunked ) {
+ while ((len = http_get_chunk_len()) > 0) {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ if ((ch = http_inc(0)) != CR)
+ break;
+ if ((ch = http_inc(0)) != LF)
+ break;
+ }
+ } else {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ }
+
+ if ( zfile )
+ zclose(ZOFILE);
+
+ if ( chunked ) { /* Parse Trailing Headers */
+ nullline = 0;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+#ifdef CMDATE2TM
+ if (!ckstrcmp(buf,"Last-Modified",13,0)) {
+ mod_t = http_date(&buf[15]);
+ } else if (!ckstrcmp(buf,"Date",4,0)) {
+ srv_t = http_date(&buf[4]);
+ }
+#endif /* CMDATE2TM */
+ else if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ }
+
+ if ( zfile ) { /* Set timestamp */
+#ifndef NOSETTIME
+#ifdef OS2
+ u_t.actime = srv_t ? srv_t : local_t;
+ u_t.modtime = mod_t ? mod_t : local_t;
+#else /* OS2 */
+#ifdef SYSUTIMEH
+ u_t.actime = srv_t ? srv_t : local_t;
+ u_t.modtime = mod_t ? mod_t : local_t;
+#else
+#ifdef BSD44
+ u_t[0].tv_sec = srv_t ? srv_t : local_t;
+ u_t[1].tv_sec = mod_t ? mod_t : local_t;
+#else
+ u_t.mtime = srv_t ? srv_t : local_t;
+ u_t.atime = mod_t ? mod_t : local_t;
+#endif /* BSD44 */
+#endif /* SYSUTIMEH */
+#endif /* OS2 */
+ utime(local,&u_t);
+#endif /* NOSETTIME */
+ }
+
+ getexit:
+ if (array)
+ http_mkarray(headers,hdcnt,array);
+
+ if ( closecon )
+ http_close();
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+http_head(char * agent, char ** hdrlist, char * user,
+ char * pwd, char array, char * local, char * remote,
+ int stdio)
+#else
+http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
+ char * agent; char ** hdrlist; char * user;
+ char * pwd; char array; char * local; char * remote;
+ int stdio;
+#endif /* CK_ANSIC */
+{
+ char * request = NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int ch;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p;
+ int nullline;
+ time_t mod_t;
+ time_t srv_t;
+ time_t local_t;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ char * headers[HTTPHEADCNT];
+ int closecon = 0;
+ int first = 1;
+
+ if (httpfd == -1)
+ return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+ len = 9; /* HEAD */
+ len += strlen(HTTP_VERSION);
+ len += strlen(remote);
+ len += 16;
+
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ len += strlen(http_host_port) + 8;
+
+ if (agent)
+ len += 13 + strlen(agent);
+ if (user) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 24;
+ }
+#ifdef HTTP_CLOSE
+ len += 19; /* Connection: close */
+#endif
+ len += 3; /* blank line + null */
+
+ request = (char *)malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user) {
+ ckstrncat(request,"Authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+#ifdef HTTP_CLOSE
+ ckstrncat(request,"Connection: close\r\n",len);
+#endif
+ ckstrncat(request,"\r\n",len);
+
+ if ( local && local[0] ) {
+ if (!zopeno(ZOFILE,local,NULL,NULL)) {
+ free(request);
+ return(-1);
+ }
+ }
+
+ headreq:
+ if (http_tol((CHAR *)request,strlen(request)) < 0)
+ {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto headreq;
+ }
+ rc = -1;
+ goto headexit;
+ }
+
+ /* Process the headers */
+
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if (buf[i] == 10) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while (isspace(*p))
+ p++;
+ switch (p[0]) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ }
+ http_set_code_reply(p);
+ } else {
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ }
+ if ( local && local[0] ) {
+ zsout(ZOFILE,buf);
+ zsout(ZOFILE,"\r\n");
+ }
+ if (stdio)
+ printf("%s\r\n",buf);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ if (ch < 0 && first) {
+ first--;
+ http_close();
+ http_reopen();
+ goto headreq;
+ }
+ if ( http_fnd == 0 )
+ rc = -1;
+
+ if (array)
+ http_mkarray(headers,hdcnt,array);
+
+ headexit:
+ if ( local && local[0] )
+ zclose(ZOFILE);
+ if (closecon)
+ http_close();
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+http_index(char * agent, char ** hdrlist, char * user, char * pwd,
+ char array, char * local, char * remote, int stdio)
+#else
+http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
+ char * agent; char ** hdrlist; char * user; char * pwd;
+ char array; char * local; char * remote; int stdio;
+#endif /* CK_ANSIC */
+{
+ char * request = NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int ch;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p;
+ int nullline;
+ time_t mod_t;
+ time_t srv_t;
+ time_t local_t;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ char * headers[HTTPHEADCNT];
+ int closecon = 0;
+ int chunked = 0;
+ int zfile = 0;
+ int first = 1;
+
+ if (httpfd == -1)
+ return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+ len = 10; /* INDEX */
+ len += strlen(HTTP_VERSION);
+ len += strlen(remote);
+ len += 16;
+
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ len += strlen(http_host_port) + 8;
+
+ if (agent)
+ len += 13 + strlen(agent);
+ if (user) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd));
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 24;
+ }
+#ifdef HTTP_CLOSE
+ len += 19; /* Connection: close */
+#endif
+ len += 3; /* blank line + null */
+
+ request = malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user) {
+ ckstrncat(request,"Authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+#ifdef HTTP_CLOSE
+ ckstrncat(request,"Connection: close\r\n",len);
+#endif
+ ckstrncat(request,"\r\n",len);
+ indexreq:
+ if (http_tol((CHAR *)request,strlen(request)) < 0)
+ {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto indexreq;
+ }
+ rc = -1;
+ goto indexexit;
+ }
+
+ /* Process the headers */
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ len = -1;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if (buf[i] == 10) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while (isspace(*p))
+ p++;
+ switch ( p[0] ) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ }
+ http_set_code_reply(p);
+ } else if ( !nullline ) {
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
+ len = atoi(&buf[16]);
+ } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
+ if ( ckindex("chunked",buf,18,0,0) != 0 )
+ chunked = 1;
+ debug(F101,"http_index chunked","",chunked);
+ }
+ printf("%s\n",buf);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+
+ if (ch < 0 && first) {
+ first--;
+ http_close();
+ http_reopen();
+ goto indexreq;
+ }
+ if ( http_fnd == 0 ) {
+ rc = -1;
+ closecon = 1;
+ goto indexexit;
+ }
+
+ /* Now we have the contents of the file */
+ if ( local && local[0] ) {
+ if (zopeno(ZOFILE,local,NULL,NULL))
+ zfile = 1;
+ else
+ rc = -1;
+ }
+
+ if ( chunked ) {
+ while ((len = http_get_chunk_len()) > 0) {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ if ((ch = http_inc(0)) != CR)
+ break;
+ if ((ch = http_inc(0)) != LF)
+ break;
+ }
+ } else {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ }
+
+ if ( zfile )
+ zclose(ZOFILE);
+
+ if ( chunked ) { /* Parse Trailing Headers */
+ nullline = 0;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ }
+ rc = 0;
+
+ indexexit:
+ if (array)
+ http_mkarray(headers,hdcnt,array);
+
+ if (closecon)
+ http_close();
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+http_put(char * agent, char ** hdrlist, char * mime, char * user,
+ char * pwd, char array, char * local, char * remote,
+ char * dest, int stdio)
+#else
+http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
+ char * agent; char ** hdrlist; char * mime; char * user;
+ char * pwd; char array; char * local; char * remote; char * dest;
+ int stdio;
+#endif /* CK_ANSIC */
+{
+ char * request=NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int ch;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p;
+ int nullline;
+ time_t mod_t;
+ time_t srv_t;
+ time_t local_t;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ int filelen;
+ char * headers[HTTPHEADCNT];
+ int closecon = 0;
+ int chunked = 0;
+ int first = 1;
+ int zfile = 0;
+
+ if (httpfd == -1)
+ return(-1);
+ if (!mime) mime = "";
+ if (!remote) remote = "";
+ if (!local) local = "";
+ if (!*local) return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+ filelen = zchki(local);
+ if (filelen < 0)
+ return(-1);
+
+ /* Compute length of request header */
+ len = 8; /* PUT */
+ len += strlen(HTTP_VERSION);
+ len += strlen(remote);
+ len += 16;
+
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ len += strlen(http_host_port) + 8;
+
+ if (agent)
+ len += 13 + strlen(agent);
+ if (user) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd));
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 24;
+ }
+ len += 16 + strlen(mime); /* Content-type: */
+ len += 32; /* Content-length: */
+ len += 32; /* Date: */
+#ifdef HTTP_CLOSE
+ len += 19; /* Connection: close */
+#endif
+ len += 3; /* blank line + null */
+
+ request = malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
+ ckstrncat(request,"Date: ",len);
+#ifdef CMDATE2TM
+ ckstrncat(request,http_now(),len);
+#else
+ ckstrncat(request,...,len);
+#endif /* CMDATE2TM */
+ ckstrncat(request,"\r\n",len);
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user) {
+ ckstrncat(request,"Authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+ ckstrncat(request,"Content-type: ",len);
+ ckstrncat(request,mime,len);
+ ckstrncat(request,"\r\n",len);
+ sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
+ ckstrncat(request,buf,len);
+#ifdef HTTP_CLOSE
+ ckstrncat(request,"Connection: close\r\n",len);
+#endif
+ ckstrncat(request,"\r\n",len);
+
+ /* Now we have the contents of the file */
+ if (zopeni(ZIFILE,local)) {
+
+ putreq: /* Send request */
+ if (http_tol((CHAR *)request,strlen(request)) <= 0) {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto putreq;
+ }
+ zclose(ZIFILE);
+ rc = -1;
+ goto putexit;
+ }
+ /* Request headers have been sent */
+
+ i = 0;
+ while (zchin(ZIFILE,&ch) == 0) {
+ buf[i++] = ch;
+ if (i == HTTPBUFLEN) {
+ if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto putreq;
+ }
+ }
+ i = 0;
+ }
+ }
+ if (i > 0) {
+ if (http_tol((CHAR *)buf,i) < 0) {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto putreq;
+ }
+ }
+ }
+ zclose(ZIFILE);
+
+ /* Process the response headers */
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ len = -1;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if (buf[i] == 10) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while (isspace(*p))
+ p++;
+ switch (p[0]) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ }
+ http_set_code_reply(p);
+ } else {
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
+ len = atoi(&buf[16]);
+ } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
+ if ( ckindex("chunked",buf,18,0,0) != 0 )
+ chunked = 1;
+ debug(F101,"http_put chunked","",chunked);
+ }
+ if ( stdio )
+ printf("%s\n",buf);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ if (ch < 0 && first) {
+ first--;
+ http_close();
+ http_reopen();
+ goto putreq;
+ }
+ if ( http_fnd == 0 ) {
+ closecon = 1;
+ rc = -1;
+ goto putexit;
+ }
+
+ /* Any response data? */
+ if ( dest && dest[0] ) {
+ if (zopeno(ZOFILE,dest,NULL,NULL))
+ zfile = 1;
+ else
+ rc = -1;
+ }
+
+ if ( chunked ) {
+ while ((len = http_get_chunk_len()) > 0) {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ if ((ch = http_inc(0)) != CR)
+ break;
+ if ((ch = http_inc(0)) != LF)
+ break;
+ }
+ } else {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ }
+
+ if ( zfile )
+ zclose(ZOFILE);
+
+ if ( chunked ) { /* Parse Trailing Headers */
+ nullline = 0;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ }
+ } else {
+ rc = -1;
+ }
+
+ putexit:
+ if ( array )
+ http_mkarray(headers,hdcnt,array);
+
+ if (closecon)
+ http_close();
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+http_delete(char * agent, char ** hdrlist, char * user,
+ char * pwd, char array, char * remote)
+#else
+http_delete(agent, hdrlist, user, pwd, array, remote)
+ char * agent; char ** hdrlist; char * user;
+ char * pwd; char array; char * remote;
+#endif /* CK_ANSIC */
+{
+ char * request=NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int ch;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p;
+ int nullline;
+ time_t mod_t;
+ time_t srv_t;
+ time_t local_t;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ char * headers[HTTPHEADCNT];
+ int closecon = 0;
+ int chunked = 0;
+ int first = 1;
+
+ if (httpfd == -1)
+ return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+
+ /* Compute length of request header */
+ len = 11; /* DELETE */
+ len += strlen(HTTP_VERSION);
+ len += strlen(remote);
+ len += 16;
+
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ len += strlen(http_host_port) + 8;
+
+ if (agent)
+ len += 13 + strlen(agent);
+ if (user) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd));
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 24;
+ }
+ len += 32; /* Date: */
+#ifdef HTTP_CLOSE
+ len += 19; /* Connection: close */
+#endif
+ len += 3; /* blank line + null */
+
+ request = malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
+ ckstrncat(request,"Date: ",len);
+#ifdef CMDATE2TM
+ ckstrncat(request,http_now(),len);
+#else
+ ckstrncat(request,...,len);
+#endif /* CMDATE2TM */
+ ckstrncat(request,"\r\n",len);
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user) {
+ ckstrncat(request,"Authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+#ifdef HTTP_CLOSE
+ ckstrncat(request,"Connection: close\r\n",len);
+#endif
+ ckstrncat(request,"\r\n",len);
+ delreq:
+ if (http_tol((CHAR *)request,strlen(request)) < 0)
+ {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto delreq;
+ }
+ rc = -1;
+ goto delexit;
+ }
+
+ /* Process the response headers */
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ len = -1;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if (buf[i] == 10) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while (isspace(*p))
+ p++;
+ switch (p[0]) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ }
+ http_set_code_reply(p);
+ } else {
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
+ len = atoi(&buf[16]);
+ } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
+ if ( ckindex("chunked",buf,18,0,0) != 0 )
+ chunked = 1;
+ debug(F101,"http_delete chunked","",chunked);
+ }
+ printf("%s\n",buf);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ if (ch < 0 && first) {
+ first--;
+ http_close();
+ http_reopen();
+ goto delreq;
+ }
+ if ( http_fnd == 0 ) {
+ rc = -1;
+ closecon = 1;
+ goto delexit;
+ }
+
+ /* Any response data? */
+ if ( chunked ) {
+ while ((len = http_get_chunk_len()) > 0) {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ conoc((CHAR)ch);
+ }
+ if ((ch = http_inc(0)) != CR)
+ break;
+ if ((ch = http_inc(0)) != LF)
+ break;
+ }
+ } else {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ conoc((CHAR)ch);
+ }
+ }
+
+ if ( chunked ) { /* Parse Trailing Headers */
+ nullline = 0;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ }
+
+ delexit:
+ if (array)
+ http_mkarray(headers,hdcnt,array);
+
+ if (closecon)
+ http_close();
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+http_post(char * agent, char ** hdrlist, char * mime, char * user,
+ char * pwd, char array, char * local, char * remote,
+ char * dest, int stdio)
+#else
+http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
+ stdio)
+ char * agent; char ** hdrlist; char * mime; char * user;
+ char * pwd; char array; char * local; char * remote; char * dest;
+ int stdio;
+#endif /* CK_ANSIC */
+{
+ char * request=NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int ch;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p;
+ int nullline;
+ time_t mod_t;
+ time_t srv_t;
+ time_t local_t;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ int filelen;
+ char * headers[HTTPHEADCNT];
+ int closecon = 0;
+ int chunked = 0;
+ int zfile = 0;
+ int first = 1;
+
+ if (httpfd == -1)
+ return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+ filelen = zchki(local);
+ if (filelen < 0)
+ return(-1);
+
+ /* Compute length of request header */
+ len = 9; /* POST */
+ len += strlen(HTTP_VERSION);
+ len += strlen(remote);
+ len += 16;
+
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ len += strlen(http_host_port) + 8;
+
+ if (agent)
+ len += 13 + strlen(agent);
+ if (user) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd));
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 24;
+ }
+ len += 16 + strlen(mime); /* Content-type: */
+ len += 32; /* Content-length: */
+ len += 32; /* Date: */
+#ifdef HTTP_CLOSE
+ len += 19; /* Connection: close */
+#endif
+ len += 3; /* blank line + null */
+
+ request = malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
+ ckstrncat(request,"Date: ",len);
+ ckstrncat(request,http_now(),len);
+ ckstrncat(request,"\r\n",len);
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user) {
+ ckstrncat(request,"Authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+ ckstrncat(request,"Content-type: ",len);
+ ckstrncat(request,mime,len);
+ ckstrncat(request,"\r\n",len);
+#ifdef HTTP_CLOSE
+ ckstrncat(request,"Connection: close\r\n",len);
+#endif
+ sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
+ ckstrncat(request,buf,len);
+ ckstrncat(request,"\r\n",len);
+#ifdef COMMENT
+ /* This is apparently a mistake - the previous ckstrncat() already */
+ /* appended a blank line to the request. There should only be one. */
+ /* Servers are not required by RFC 2616 to ignore extraneous empty */
+ /* lines. -fdc, 28 Aug 2005. */
+ ckstrncat(request,"\r\n",len);
+#endif /* COMMENT */
+
+ /* Now we have the contents of the file */
+ postopen:
+ if (zopeni(ZIFILE,local)) {
+ postreq:
+ if (http_tol((CHAR *)request,strlen(request)) < 0)
+ {
+ http_close();
+ if ( first ) {
+ first--;
+ http_reopen();
+ goto postreq;
+ }
+ rc = -1;
+ zclose(ZIFILE);
+ goto postexit;
+ }
+
+ i = 0;
+ while (zchin(ZIFILE,&ch) == 0) {
+ buf[i++] = ch;
+ if (i == HTTPBUFLEN) {
+ http_tol((CHAR *)buf,HTTPBUFLEN);
+ i = 0;
+ }
+ }
+ if (i > 0)
+ http_tol((CHAR *)buf,HTTPBUFLEN);
+ zclose(ZIFILE);
+
+ /* Process the response headers */
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ len = -1;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if (buf[i] == 10) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while (isspace(*p))
+ p++;
+ switch (p[0]) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ }
+ http_set_code_reply(p);
+ } else {
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
+ len = atoi(&buf[16]);
+ } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
+ if ( ckindex("chunked",buf,18,0,0) != 0 )
+ chunked = 1;
+ debug(F101,"http_post chunked","",chunked);
+ }
+ if (stdio)
+ printf("%s\n",buf);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ if (ch < 0 && first) {
+ first--;
+ http_close();
+ http_reopen();
+ goto postopen;
+ }
+ if (http_fnd == 0) {
+ rc = -1;
+ closecon = 1;
+ goto postexit;
+ }
+
+ /* Any response data? */
+ if ( dest && dest[0] ) {
+ if (zopeno(ZOFILE,dest,NULL,NULL))
+ zfile = 1;
+ else
+ rc = -1;
+ }
+
+ if ( chunked ) {
+ while ((len = http_get_chunk_len()) > 0) {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ if ((ch = http_inc(0)) != CR)
+ break;
+ if ((ch = http_inc(0)) != LF)
+ break;
+ }
+ } else {
+ while (len && (ch = http_inc(0)) >= 0) {
+ len--;
+ if ( zfile )
+ zchout(ZOFILE,(CHAR)ch);
+ if ( stdio )
+ conoc((CHAR)ch);
+ }
+ }
+
+ if ( zfile )
+ zclose(ZOFILE);
+
+ if ( chunked ) { /* Parse Trailing Headers */
+ nullline = 0;
+ while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if ( buf[i] == 10 ) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"Connection:",11,0)) {
+ if ( ckindex("close",buf,11,0,0) != 0 )
+ closecon = 1;
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ }
+ } else {
+ rc = -1;
+ }
+
+ postexit:
+ if (array)
+ http_mkarray(headers,hdcnt,array);
+ if (closecon)
+ http_close();
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+http_connect(int socket, char * agent, char ** hdrlist, char * user,
+ char * pwd, char array, char * host_port)
+#else
+http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
+ int socket;
+ char * agent; char ** hdrlist; char * user;
+ char * pwd; char array; char * host_port;
+#endif /* CK_ANSIC */
+{
+ char * request=NULL;
+ int i, j, len = 0, hdcnt = 0, rc = 0;
+ int http_fnd = 0;
+ char buf[HTTPBUFLEN], *p, ch;
+ int nullline;
+ time_t mod_t;
+ time_t srv_t;
+ time_t local_t;
+ char passwd[64];
+ char b64in[128];
+ char b64out[256];
+ char * headers[HTTPHEADCNT];
+ int connected = 0;
+
+ tcp_http_proxy_errno = 0;
+
+ if (socket == -1)
+ return(-1);
+
+ if (array) {
+ for (i = 0; i < HTTPHEADCNT; i++)
+ headers[i] = NULL;
+ }
+
+ /* Compute length of request header */
+ len = 12; /* CONNECT */
+ len += strlen(HTTP_VERSION);
+ len += strlen(host_port);
+ len += (int) strlen(http_host_port) + 8;
+ len += 16;
+ len += strlen("Proxy-Connection: Keep-Alive\r\n");
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++)
+ len += strlen(hdrlist[i]) + 2;
+ }
+ if (agent && agent[0])
+ len += 13 + strlen(agent);
+ if (user && user[0]) {
+ if (!pwd) {
+ readpass("Password: ",passwd,64);
+ pwd = passwd;
+ }
+ ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
+ j = b8tob64(b64in,strlen(b64in),b64out,256);
+ memset(pwd,0,strlen(pwd));
+ if (j < 0)
+ return(-1);
+ b64out[j] = '\0';
+ len += j + 72;
+ }
+ len += 32; /* Date: */
+ len += 3; /* blank line + null */
+
+ request = malloc(len);
+ if (!request)
+ return(-1);
+
+ sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
+ ckstrncat(request,"Date: ",len);
+#ifdef CMDATE2TM
+ ckstrncat(request,http_now(),len);
+#else
+ strcat(request,...);
+#endif /* CMDATE2TM */
+ ckstrncat(request,"\r\n",len);
+ ckstrncat(request,"Host: ", len);
+ ckstrncat(request,http_host_port, len);
+ ckstrncat(request,"\r\n",len);
+ if (agent && agent[0]) {
+ ckstrncat(request,"User-agent: ",len);
+ ckstrncat(request,agent,len);
+ ckstrncat(request,"\r\n",len);
+ }
+ if (user && user[0]) {
+ ckstrncat(request,"Proxy-authorization: Basic ",len);
+ ckstrncat(request,b64out,len);
+ ckstrncat(request,"\r\n",len);
+ ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
+ }
+ ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
+ if ( hdrlist ) {
+ for (i = 0; hdrlist[i]; i++) {
+ ckstrncat(request,hdrlist[i],len);
+ ckstrncat(request,"\r\n",len);
+ }
+ }
+ ckstrncat(request,"\r\n",len);
+ len = strlen(request);
+
+#ifdef TCPIPLIB
+ /* Send request */
+ if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
+ rc = -1;
+ goto connexit;
+ }
+#else
+ if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
+ rc = -1;
+ goto connexit;
+ }
+#endif /* TCPIPLIB */
+
+ /* Process the response headers */
+ local_t = time(NULL);
+ nullline = 0;
+ i = 0;
+ while (!nullline &&
+#ifdef TCPIPLIB
+ (socket_read(socket,&ch,1) == 1) &&
+#else
+ (read(socket,&ch,1) == 1) &&
+#endif /* TCPIPLIB */
+ i < HTTPBUFLEN) {
+ buf[i] = ch;
+ if (buf[i] == 10) { /* found end of line */
+ if (i > 0 && buf[i-1] == 13)
+ i--;
+ if (i < 1)
+ nullline = 1;
+ buf[i] = '\0';
+
+ if (array && !nullline && hdcnt < HTTPHEADCNT)
+ makestr(&headers[hdcnt++],buf);
+ if (!ckstrcmp(buf,"HTTP",4,0)) {
+ http_fnd = 1;
+ j = ckindex(" ",buf,0,0,0);
+ p = &buf[j];
+ while (isspace(*p))
+ p++;
+ tcp_http_proxy_errno = atoi(p);
+ switch (p[0]) {
+ case '1': /* Informational message */
+ break;
+ case '2': /* Success */
+ connected = 1;
+ break;
+ case '3': /* Redirection */
+ case '4': /* Client failure */
+ case '5': /* Server failure */
+ default: /* Unknown */
+ if (!quiet)
+ printf("Failure: Server reports %s\n",p);
+ rc = -1;
+ }
+ http_set_code_reply(p);
+ } else {
+ printf("%s\n",buf);
+ }
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ if ( http_fnd == 0 )
+ rc = -1;
+
+ if (array)
+ http_mkarray(headers,hdcnt,array);
+
+ connexit:
+ if ( !connected ) {
+ if ( socket == ttyfd ) {
+ ttclos(0);
+ }
+ else if ( socket == httpfd ) {
+ http_close();
+ }
+ }
+
+ free(request);
+ for (i = 0; i < hdcnt; i++) {
+ if (headers[i])
+ free(headers[i]);
+ }
+ return(rc);
+}
+#endif /* NOHTTP */
+
+#ifdef CK_DNS_SRV
+
+#define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
+#define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
+#define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
+
+#ifndef CKQUERYTYPE
+#ifdef UNIXWARE
+#ifndef UW7
+#define CKQUERYTYPE CHAR
+#endif /* UW7 */
+#endif /* UNIXWARE */
+#endif /* CKQUERYTYPE */
+
+#ifndef CKQUERYTYPE
+#define CKQUERYTYPE char
+#endif /* CKQUERYTYPE */
+
+/* 1 is success, 0 is failure */
+int
+locate_srv_dns(host, service, protocol, addr_pp, naddrs)
+ char *host;
+ char *service;
+ char *protocol;
+ struct sockaddr **addr_pp;
+ int *naddrs;
+{
+ int nout, j, count;
+ union {
+ unsigned char bytes[2048];
+ HEADER hdr;
+ } answer;
+ unsigned char *p=NULL;
+ CKQUERYTYPE query[MAX_DNS_NAMELEN];
+#ifdef CK_ANSIC
+ const char * h;
+#else
+ char * h;
+#endif /* CK_ANSIC */
+ struct sockaddr *addr = NULL;
+ struct sockaddr_in *sin = NULL;
+ struct hostent *hp = NULL;
+ int type, class;
+ int priority, weight, size, len, numanswers, numqueries, rdlen;
+ unsigned short port;
+#ifdef CK_ANSIC
+ const
+#endif /* CK_ANSIC */
+ int hdrsize = sizeof(HEADER);
+ struct srv_dns_entry {
+ struct srv_dns_entry *next;
+ int priority;
+ int weight;
+ unsigned short port;
+ char *host;
+ };
+ struct srv_dns_entry *head = NULL;
+ struct srv_dns_entry *srv = NULL, *entry = NULL;
+ char * s = NULL;
+
+ nout = 0;
+ addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
+ if (addr == NULL)
+ return 0;
+
+ count = 1;
+
+ /*
+ * First build a query of the form:
+ *
+ * service.protocol.host
+ *
+ * which will most likely be something like:
+ *
+ * _telnet._tcp.host
+ *
+ */
+ if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
+ > MAX_DNS_NAMELEN
+ )
+ goto dnsout;
+
+ /* Realm names don't (normally) end with ".", but if the query
+ doesn't end with "." and doesn't get an answer as is, the
+ resolv code will try appending the local domain. Since the
+ realm names are absolutes, let's stop that.
+
+ But only if a name has been specified. If we are performing
+ a search on the prefix alone then the intention is to allow
+ the local domain or domain search lists to be expanded.
+ */
+ h = host + strlen (host);
+ ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
+ ((h > host) && (h[-1] != '.')?".":NULL),
+ NULL,NULL,NULL,NULL,NULL);
+
+ size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
+
+ if (size < hdrsize)
+ goto dnsout;
+
+ /* We got a reply - See how many answers it contains. */
+
+ p = answer.bytes;
+
+ numqueries = ntohs(answer.hdr.qdcount);
+ numanswers = ntohs(answer.hdr.ancount);
+
+ p += sizeof(HEADER);
+
+ /*
+ * We need to skip over all of the questions, so we have to iterate
+ * over every query record. dn_expand() is able to tell us the size
+ * of compressed DNS names, so we use it.
+ */
+ while (numqueries--) {
+ len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
+ if (len < 0)
+ goto dnsout;
+ INCR_CHECK(p, len + 4);
+ }
+
+ /*
+ * We're now pointing at the answer records. Only process them if
+ * they're actually T_SRV records (they might be CNAME records,
+ * for instance).
+ *
+ * But in a DNS reply, if you get a CNAME you always get the associated
+ * "real" RR for that CNAME. RFC 1034, 3.6.2:
+ *
+ * CNAME RRs cause special action in DNS software. When a name server
+ * fails to find a desired RR in the resource set associated with the
+ * domain name, it checks to see if the resource set consists of a CNAME
+ * record with a matching class. If so, the name server includes the CNAME
+ * record in the response and restarts the query at the domain name
+ * specified in the data field of the CNAME record. The one exception to
+ * this rule is that queries which match the CNAME type are not restarted.
+ *
+ * In other words, CNAMEs do not need to be expanded by the client.
+ */
+ while (numanswers--) {
+
+ /* First is the name; use dn_expand() to get the compressed size. */
+ len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
+ if (len < 0)
+ goto dnsout;
+ INCR_CHECK(p, len);
+
+ CHECK(p,2); /* Query type */
+ type = NTOHSP(p,2);
+
+ CHECK(p, 6); /* Query class */
+ class = NTOHSP(p,6); /* Also skip over 4-byte TTL */
+
+ CHECK(p,2); /* Record data length */
+ rdlen = NTOHSP(p,2);
+ /*
+ * If this is an SRV record, process it. Record format is:
+ *
+ * Priority
+ * Weight
+ * Port
+ * Server name
+ */
+ if (class == C_IN && type == T_SRV) {
+ CHECK(p,2);
+ priority = NTOHSP(p,2);
+ CHECK(p, 2);
+ weight = NTOHSP(p,2);
+ CHECK(p, 2);
+ port = NTOHSP(p,2);
+ len = dn_expand(answer.
+ bytes,
+ answer.bytes + size,
+ p,
+ query,
+ sizeof(query)
+ );
+ if (len < 0)
+ goto dnsout;
+ INCR_CHECK(p, len);
+ /*
+ * We got everything. Insert it into our list, but make sure
+ * it's in the right order. Right now we don't do anything
+ * with the weight field
+ */
+ srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
+ if (srv == NULL)
+ goto dnsout;
+
+ srv->priority = priority;
+ srv->weight = weight;
+ srv->port = port;
+ makestr(&s,(char *)query); /* strdup() is not portable */
+ srv->host = s;
+
+ if (head == NULL || head->priority > srv->priority) {
+ srv->next = head;
+ head = srv;
+ } else
+ /*
+ * Confusing. Insert an entry into this spot only if:
+ * . The next person has a higher priority (lower
+ * priorities are preferred), or:
+ * . There is no next entry (we're at the end)
+ */
+ for (entry = head; entry != NULL; entry = entry->next)
+ if ((entry->next &&
+ entry->next->priority > srv->priority) ||
+ entry->next == NULL) {
+ srv->next = entry->next;
+ entry->next = srv;
+ break;
+ }
+ } else
+ INCR_CHECK(p, rdlen);
+ }
+
+ /*
+ * Now we've got a linked list of entries sorted by priority.
+ * Start looking up A records and returning addresses.
+ */
+ if (head == NULL)
+ goto dnsout;
+
+ for (entry = head; entry != NULL; entry = entry->next) {
+ hp = gethostbyname(entry->host);
+ if (hp != 0) {
+
+ /* Watch out - memset() and memcpy() are not portable... */
+
+ switch (hp->h_addrtype) {
+ case AF_INET:
+ for (j = 0; hp->h_addr_list[j]; j++) {
+ sin = (struct sockaddr_in *) &addr[nout++];
+ memset ((char *) sin, 0, sizeof (struct sockaddr));
+ sin->sin_family = hp->h_addrtype;
+ sin->sin_port = htons(entry->port);
+ memcpy((char *) &sin->sin_addr,
+ (char *) hp->h_addr_list[j],
+ sizeof(struct in_addr)); /* safe */
+ if (nout + 1 >= count) {
+ count += 5;
+ addr = (struct sockaddr *)
+ realloc((char *) addr,
+ sizeof(struct sockaddr) * count);
+ if (!addr)
+ goto dnsout;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ for (entry = head; entry != NULL;) {
+ free(entry->host);
+ entry->host = NULL;
+ srv = entry;
+ entry = entry->next;
+ free(srv);
+ srv = NULL;
+ }
+
+ dnsout:
+ if (srv)
+ free(srv);
+
+ if (nout == 0) { /* No good servers */
+ if (addr)
+ free(addr);
+ return 0;
+ }
+ *addr_pp = addr;
+ *naddrs = nout;
+ return 1;
+}
+#undef INCR_CHECK
+#undef CHECK
+#undef NTOHSP
+
+#define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
+ return 0
+#define CHECK(x, y) if (x + y > size + answer.bytes) \
+ return 0
+#define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
+
+int
+locate_txt_rr(prefix, name, retstr)
+ char *prefix, *name;
+ char **retstr;
+{
+ union {
+ unsigned char bytes[2048];
+ HEADER hdr;
+ } answer;
+ unsigned char *p;
+ char host[MAX_DNS_NAMELEN], *h;
+ int size;
+ int type, class, numanswers, numqueries, rdlen, len;
+
+ /*
+ * Form our query, and send it via DNS
+ */
+
+ if (name == NULL || name[0] == '\0') {
+ strcpy(host,prefix);
+ } else {
+ if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
+ return 0;
+
+ /* Realm names don't (normally) end with ".", but if the query
+ doesn't end with "." and doesn't get an answer as is, the
+ resolv code will try appending the local domain. Since the
+ realm names are absolutes, let's stop that.
+
+ But only if a name has been specified. If we are performing
+ a search on the prefix alone then the intention is to allow
+ the local domain or domain search lists to be expanded.
+ */
+ h = host + strlen (host);
+ ckmakmsg(host,sizeof(host),prefix, ".", name,
+ ((h > host) && (h[-1] != '.'))?".":NULL);
+
+ }
+ size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
+
+ if (size < 0)
+ return 0;
+
+ p = answer.bytes;
+
+ numqueries = ntohs(answer.hdr.qdcount);
+ numanswers = ntohs(answer.hdr.ancount);
+
+ p += sizeof(HEADER);
+
+ /*
+ * We need to skip over the questions before we can get to the answers,
+ * which means we have to iterate over every query record. We use
+ * dn_expand to tell us how long each compressed name is.
+ */
+
+ while (numqueries--) {
+ len = dn_expand(answer.bytes, answer.bytes + size, p, host,
+ sizeof(host));
+ if (len < 0)
+ return 0;
+ INCR_CHECK(p, len + 4); /* Name plus type plus class */
+ }
+
+ /*
+ * We're now pointing at the answer records. Process the first
+ * TXT record we find.
+ */
+
+ while (numanswers--) {
+
+ /* First the name; use dn_expand to get the compressed size */
+ len = dn_expand(answer.bytes, answer.bytes + size, p,
+ host, sizeof(host));
+ if (len < 0)
+ return 0;
+ INCR_CHECK(p, len);
+
+ /* Next is the query type */
+ CHECK(p, 2);
+ type = NTOHSP(p,2);
+
+ /* Next is the query class; also skip over 4 byte TTL */
+ CHECK(p,6);
+ class = NTOHSP(p,6);
+
+ /* Record data length - make sure we aren't truncated */
+
+ CHECK(p,2);
+ rdlen = NTOHSP(p,2);
+
+ if (p + rdlen > answer.bytes + size)
+ return 0;
+
+ /*
+ * If this is a TXT record, return the string. Note that the
+ * string has a 1-byte length in the front
+ */
+ /* XXX What about flagging multiple TXT records as an error? */
+
+ if (class == C_IN && type == T_TXT) {
+ len = *p++;
+ if (p + len > answer.bytes + size)
+ return 0;
+ *retstr = malloc(len + 1);
+ if (*retstr == NULL)
+ return ENOMEM;
+ strncpy(*retstr, (char *) p, len);
+ (*retstr)[len] = '\0';
+ /* Avoid a common error. */
+ if ( (*retstr)[len-1] == '.' )
+ (*retstr)[len-1] = '\0';
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#undef INCR_CHECK
+#undef CHECK
+#undef NTOHSP
+#endif /* CK_DNS_SRV */
+
+#ifdef TNCODE
+#ifdef CK_FORWARD_X
+#ifdef UNIX
+#include <sys/un.h>
+#define FWDX_UNIX_SOCK
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+#ifndef PF_LOCAL
+#define PF_LOCAL PF_UNIX
+#endif
+#ifndef SUN_LEN
+/* Evaluate to actual length of the `sockaddr_un' structure. */
+#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+#endif
+#endif /* UNIX */
+int
+fwdx_create_listen_socket(screen) int screen; {
+#ifdef NOPUTENV
+ return(-1);
+#else /* NOPUTENV */
+ struct sockaddr_in saddr;
+ int display, port, sock=-1, i;
+ static char env[512];
+
+ /*
+ * X Windows Servers support multiple displays by listening on
+ * one socket per display. Display 0 is port 6000; Display 1 is
+ * port 6001; etc.
+ *
+ * We start by trying to open port 6001 so that display 0 is
+ * reserved for the local X Windows Server.
+ */
+
+ for ( display=1; display < 1000 ; display++ ) {
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
+ return(-1);
+ }
+
+ port = 6000 + display;
+ bzero((char *)&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = inet_addr(myipaddr);
+ saddr.sin_port = htons(port);
+
+ if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ i = errno; /* Save error code */
+#ifdef TCPIPLIB
+ socket_close(sock);
+#else /* TCPIPLIB */
+ close(sock);
+#endif /* TCPIPLIB */
+ sock = -1;
+ debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
+ continue;
+ }
+
+ debug(F100,"fdwx_create_listen_socket() bind OK","",0);
+ break;
+ }
+
+ if ( display > 1000 ) {
+ debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
+ return(-1);
+ }
+
+ if (listen(sock, 5) < 0) {
+ i = errno; /* Save error code */
+#ifdef TCPIPLIB
+ socket_close(sock);
+#else /* TCPIPLIB */
+ close(sock);
+#endif /* TCPIPLIB */
+ debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
+ return(-1);
+ }
+ debug(F100,"fwdx_create_listen_socket() listen OK","",0);
+
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
+ if (!myipaddr[0])
+ getlocalipaddr();
+ if ( myipaddr[0] )
+ ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
+ ckuitoa(display),":",ckuitoa(screen),
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ else
+ ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
+ ckuitoa(screen));
+ putenv(env);
+ return(0);
+#endif /* NOPUTENV */
+}
+
+
+int
+fwdx_open_client_channel(channel) int channel; {
+ char * env;
+ struct sockaddr_in saddr;
+#ifdef FWDX_UNIX_SOCK
+ struct sockaddr_un saddr_un = { AF_LOCAL };
+#endif /* FWDX_UNIX_SOCK */
+ int colon, dot, display, port, sock, i, screen;
+ int family;
+ char buf[256], * host=NULL, * rest=NULL;
+#ifdef TCP_NODELAY
+ int on=1;
+#endif /* TCP_NODELAY */
+
+ debug(F111,"fwdx_create_client_channel()","channel",channel);
+
+ for ( i=0; i<MAXFWDX ; i++ ) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
+ /* Already open */
+ debug(F110,"fwdx_create_client_channel()","already open",0);
+ return(0);
+ }
+ }
+
+ env = getenv("DISPLAY");
+ if ( !env )
+ env = (char *)tn_get_display();
+ if ( env )
+ ckstrncpy(buf,env,256);
+ else
+ ckstrncpy(buf,"127.0.0.1:0.0",256);
+
+ bzero((char *)&saddr,sizeof(saddr));
+ saddr.sin_family = AF_INET;
+
+ if (!fwdx_parse_displayname(buf,
+ &family,
+ &host,
+ &display,
+ &screen,
+ &rest
+ )
+ ) {
+ if ( host ) free(host);
+ if ( rest ) free(rest);
+ return(0);
+ }
+ if (rest) free(rest);
+
+#ifndef FWDX_UNIX_SOCK
+ /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
+ * we change things to use inet sockets on the ip loopback interface instead,
+ * and hope that it works.
+ */
+ if (family == FamilyLocal) {
+ debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
+ family = FamilyInternet;
+ if (host) free(host);
+ if (host = malloc(strlen("localhost") + 1))
+ strcpy(host, "localhost");
+ else {
+ return(-1);
+ }
+ }
+#else /* FWDX_UNIX_SOCK */
+ if (family == FamilyLocal) {
+ if (host) free(host);
+ sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ return(-1);
+
+ ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
+ strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
+ if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
+ return(-1);
+ } else
+#endif /* FWDX_UNIX_SOCK */
+ {
+ /* Otherwise, we are assuming FamilyInternet */
+ if (host) {
+ ckstrncpy(buf,host,sizeof(buf));
+ free(host);
+ } else
+ ckstrncpy(buf,myipaddr,sizeof(buf));
+
+ debug(F111,"fwdx_create_client_channel()","display",display);
+
+ port = 6000 + display;
+ saddr.sin_port = htons(port);
+
+ debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
+ saddr.sin_addr.s_addr = inet_addr(buf);
+ if ( saddr.sin_addr.s_addr == (unsigned long) -1
+#ifdef INADDR_NONE
+ || saddr.sin_addr.s_addr == INADDR_NONE
+#endif /* INADDR_NONE */
+ )
+ {
+ struct hostent *host;
+ host = gethostbyname(buf);
+ if ( host == NULL )
+ return(-1);
+ host = ck_copyhostent(host);
+#ifdef HADDRLIST
+#ifdef h_addr
+ /* This is for trying multiple IP addresses - see <netdb.h> */
+ if (!(host->h_addr_list))
+ return(-1);
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&saddr.sin_addr,
+ host->h_length
+ );
+#else
+ bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
+#endif /* h_addr */
+#else /* HADDRLIST */
+ bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
+#endif /* HADDRLIST */
+ }
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
+ return(-1);
+ }
+
+ if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ debug(F110,"fwdx_create_client_channel()","connect() failed",0);
+#ifdef TCPIPLIB
+ socket_close(sock);
+#else /* TCPIPLIB */
+ close(sock);
+#endif /* TCPIPLIB */
+ return(-1);
+ }
+
+#ifdef TCP_NODELAY
+ setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
+#endif /* TCP_NODELAY */
+ }
+
+ for (i = 0; i < MAXFWDX; i++) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
+ debug(F111,"fwdx_create_client_channel()","socket",sock);
+ return(0);
+ }
+ }
+ return(-1);
+}
+
+int
+fwdx_server_avail() {
+ char * env;
+ struct sockaddr_in saddr;
+#ifdef FWDX_UNIX_SOCK
+ struct sockaddr_un saddr_un = { AF_LOCAL };
+#endif /* FWDX_UNIX_SOCK */
+ int colon, dot, display, port, sock, i, screen;
+ char buf[256], *host=NULL, *rest=NULL;
+#ifdef TCP_NODELAY
+ int on=1;
+#endif /* TCP_NODELAY */
+ int family;
+
+ env = getenv("DISPLAY");
+ if ( !env )
+ env = (char *)tn_get_display();
+ if ( env )
+ ckstrncpy(buf,env,256);
+ else
+ ckstrncpy(buf,"127.0.0.1:0.0",256);
+
+ bzero((char *)&saddr,sizeof(saddr));
+ saddr.sin_family = AF_INET;
+
+ if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
+ if ( host ) free(host);
+ if ( rest ) free(rest);
+ return(0);
+ }
+ if (rest) free(rest);
+
+#ifndef FWDX_UNIX_SOCK
+ /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
+ * we change things to use inet sockets on the ip loopback interface instead,
+ * and hope that it works.
+ */
+ if (family == FamilyLocal) {
+ family = FamilyInternet;
+ if (host) free(host);
+ if (host = malloc(strlen("localhost") + 1))
+ strcpy(host, "localhost");
+ else {
+ return(-1);
+ }
+ }
+#else /* FWDX_UNIX_SOCK */
+ if (family == FamilyLocal) {
+ debug(F100,"fwdx_server_avail() FamilyLocal","",0);
+ if (host) free(host);
+ sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ return(0);
+
+ ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
+ strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
+ if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
+ return(0);
+ close(sock);
+ return(1);
+ }
+#endif /* FWDX_UNIX_SOCK */
+
+ /* Otherwise, we are assuming FamilyInternet */
+ if (host) {
+ ckstrncpy(buf,host,sizeof(buf));
+ free(host);
+ } else
+ ckstrncpy(buf,myipaddr,sizeof(buf));
+
+ debug(F111,"fwdx_server_avail()","display",display);
+
+ port = 6000 + display;
+ saddr.sin_port = htons(port);
+
+ debug(F110,"fwdx_server_avail() ip-address",buf,0);
+ saddr.sin_addr.s_addr = inet_addr(buf);
+ if ( saddr.sin_addr.s_addr == (unsigned long) -1
+#ifdef INADDR_NONE
+ || saddr.sin_addr.s_addr == INADDR_NONE
+#endif /* INADDR_NONE */
+ )
+ {
+ struct hostent *host;
+ host = gethostbyname(buf);
+ if ( host == NULL ) {
+ debug(F110,"fwdx_server_avail() gethostbyname() failed",
+ myipaddr,0);
+ return(-1);
+ }
+ host = ck_copyhostent(host);
+#ifdef HADDRLIST
+#ifdef h_addr
+ /* This is for trying multiple IP addresses - see <netdb.h> */
+ if (!(host->h_addr_list))
+ return(-1);
+ bcopy(host->h_addr_list[0],
+ (caddr_t)&saddr.sin_addr,
+ host->h_length
+ );
+#else
+ bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
+#endif /* h_addr */
+#else /* HADDRLIST */
+ bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
+#endif /* HADDRLIST */
+ }
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ debug(F111,"fwdx_server_avail()","socket() < 0",sock);
+ return(0);
+ }
+
+ if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ debug(F110,"fwdx_server_avail()","connect() failed",0);
+#ifdef TCPIPLIB
+ socket_close(sock);
+#else /* TCPIPLIB */
+ close(sock);
+#endif /* TCPIPLIB */
+ return(0);
+ }
+
+#ifdef TCPIPLIB
+ socket_close(sock);
+#else /* TCPIPLIB */
+ close(sock);
+#endif /* TCPIPLIB */
+ return(1);
+}
+
+int
+fwdx_open_server_channel() {
+ int sock, ready_to_accept, sock2,channel,i;
+#ifdef TCP_NODELAY
+ int on=1;
+#endif /* TCP_NODELAY */
+#ifdef UCX50
+ static u_int saddrlen;
+#else
+ static SOCKOPT_T saddrlen;
+#endif /* UCX50 */
+ struct sockaddr_in saddr;
+ char sb[8];
+ extern char tn_msg[];
+#ifdef BSDSELECT
+ fd_set rfds;
+ struct timeval tv;
+#else
+#ifdef BELLSELCT
+ fd_set rfds;
+#else
+ fd_set rfds;
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+ } tv;
+#endif /* BELLSELECT */
+#endif /* BSDSELECT */
+ unsigned short nchannel;
+ unsigned char * p;
+
+ sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
+
+ try_again:
+
+#ifdef BSDSELECT
+ tv.tv_sec = tv.tv_usec = 0L;
+ tv.tv_usec = 50;
+ FD_ZERO(&rfds);
+ FD_SET(sock, &rfds);
+ ready_to_accept =
+ ((select(FD_SETSIZE,
+#ifdef HPUX
+#ifdef HPUX1010
+ (fd_set *)
+#else
+
+ (int *)
+#endif /* HPUX1010 */
+#else
+#ifdef __DECC
+ (fd_set *)
+#endif /* __DECC */
+#endif /* HPUX */
+ &rfds, NULL, NULL, &tv) > 0) &&
+ FD_ISSET(sock, &rfds));
+#else /* BSDSELECT */
+#ifdef IBMSELECT
+ ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
+#else
+#ifdef BELLSELECT
+ FD_ZERO(rfds);
+ FD_SET(sock, rfds);
+ ready_to_accept =
+ ((select(128, rfds, NULL, NULL, 50) > 0) &&
+ FD_ISSET(sock, rfds));
+#else
+/* Try this - what's the worst that can happen... */
+
+ tv.tv_sec = tv.tv_usec = 0L;
+ tv.tv_usec = 50;
+ FD_ZERO(&rfds);
+ FD_SET(sock, &rfds);
+ ready_to_accept =
+ ((select(FD_SETSIZE,
+ (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
+ FD_ISSET(sock, &rfds));
+#endif /* BELLSELECT */
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+
+ if ( !ready_to_accept )
+ return(0);
+
+ if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
+ int i = errno; /* save error code */
+ debug(F101,"tcpsrv_open accept errno","",i);
+ return(-1);
+ }
+
+ /*
+ * Now we have the open socket. We must now find a channel to store
+ * it in, and then notify the client.
+ */
+
+ for ( channel=0;channel<MAXFWDX;channel++ ) {
+ if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
+ break;
+ }
+
+ if ( channel == MAXFWDX ) {
+#ifdef TCPIPLIB
+ socket_close(sock2);
+#else /* TCPIPLIB */
+ close(sock2);
+#endif /* TCPIPLIB */
+ return(-1);
+ }
+
+ if ( fwdx_send_open(channel) < 0 ) {
+#ifdef TCPIPLIB
+ socket_close(sock2);
+#else /* TCPIPLIB */
+ close(sock2);
+#endif /* TCPIPLIB */
+ }
+
+#ifdef TCP_NODELAY
+ setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
+#endif /* TCP_NODELAY */
+
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
+ goto try_again;
+
+ return(0); /* never reached */
+}
+
+int
+fwdx_close_channel(channel) int channel; {
+ int i,fd;
+
+ for ( i=0; i<MAXFWDX ; i++ ) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
+ break;
+ }
+ if ( i == MAXFWDX )
+ return(-1);
+
+ fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+
+#ifdef TCPIPLIB
+ socket_close(fd);
+#else /* TCPIPLIB */
+ close(fd);
+#endif /* TCPIPLIB */
+ return(0);
+}
+
+int
+fwdx_close_all() {
+ int x,fd;
+
+ debug(F111,"fwdx_close_all()",
+ "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
+
+ if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
+#ifdef TCPIPLIB
+ socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
+#else /* TCPIPLIB */
+ close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
+#endif /* TCPIPLIB */
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
+ }
+
+ for (x = 0; x < MAXFWDX; x++) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
+ fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
+#ifdef TCPIPLIB
+ socket_close(fd);
+#else /* TCPIPLIB */
+ close(fd);
+#endif /* TCPIPLIB */
+ }
+ }
+ return(0);
+}
+
+/* The following definitions are for Unix */
+#ifndef socket_write
+#define socket_write(f,s,n) write(f,s,n)
+#endif /* socket_write */
+#ifndef socket_read
+#define socket_read(f,s,n) read(f,s,n)
+#endif /* socket_read */
+
+int
+fwdx_write_data_to_channel(channel, data, len)
+ int channel; char * data; int len;
+{
+ int sock, count, try=0, length = len, i;
+
+ if ( len <= 0 )
+ return(0);
+
+ for ( i=0; i<MAXFWDX ; i++ ) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
+ break;
+ }
+ if ( i == MAXFWDX ) {
+ debug(F110,"fwdx_write_data_to_channel",
+ "attempting to write to closed channel",0);
+ return(-1);
+ }
+
+ sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
+ debug(F111,"fwdx_write_data_to_channel","socket",sock);
+ ckhexdump("fwdx_write_data_to_channel",data,len);
+
+ fwdx_write_data_to_channel_retry:
+
+ if ((count = socket_write(sock,data,len)) < 0) {
+ int s_errno = socket_errno; /* maybe a function */
+ debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
+#ifdef BETATEST
+ printf("fwdx_write_data_to_channel error\r\n");
+#endif /* BETATEST */
+#ifdef OS2
+ if (os2socketerror(s_errno) < 0)
+ return(-2);
+#endif /* OS2 */
+ return(-1); /* Call it an i/o error */
+ }
+ if (count < len) {
+ debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
+ if (count > 0) {
+ data += count;
+ len -= count;
+ }
+ debug(F111,"fwdx_write_data_to_channel retry",data,len);
+ if ( len > 0 )
+ goto fwdx_write_data_to_channel_retry;
+ }
+
+ debug(F111,"fwdx_write_data_to_channel complete",data,length);
+ return(length); /* success - return total length */
+}
+
+VOID
+fwdx_check_sockets(fd_set *ibits)
+{
+ int x, sock, channel, bytes;
+ static char buffer[32000];
+
+ debug(F100,"fwdx_check_sockets()","",0);
+ if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
+ !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
+ debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
+ return;
+ }
+
+ for (x = 0; x < MAXFWDX; x++) {
+ if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
+ continue;
+
+ sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
+ if (FD_ISSET(sock, ibits))
+ {
+ channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
+ debug(F111,"fwdx_check_sockets()","channel set",channel);
+
+ bytes = socket_read(sock, buffer, sizeof(buffer));
+ if (bytes > 0)
+ fwdx_send_data_from_channel(channel, buffer, bytes);
+ else if (bytes == 0) {
+ fwdx_close_channel(channel);
+ fwdx_send_close(channel);
+ }
+ }
+ }
+}
+
+int
+fwdx_init_fd_set(fd_set *ibits)
+{
+ int x,set=0,cnt=0;
+
+ if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
+ !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
+ debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
+ return(0);
+ }
+
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
+ set++;
+ FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
+ }
+ for (x = 0; x < MAXFWDX; x++) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
+ cnt++;
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
+ continue;
+ set++;
+ FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
+ }
+ }
+ if (set + cnt == 0) {
+ return(-1);
+ } else {
+ return(set);
+ }
+}
+
+#ifdef NT
+VOID
+fwdx_thread( VOID * dummy )
+{
+ fd_set ifds;
+ struct timeval tv;
+ extern int priority;
+ int n;
+
+ setint();
+ SetThreadPrty(priority,isWin95() ? 3 : 11);
+
+ while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
+ sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
+ {
+ FD_ZERO(&ifds);
+ n = fwdx_init_fd_set(&ifds);
+ if (n > 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 2500;
+ if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
+ fwdx_check_sockets(&ifds);
+
+ } else if (n < 0) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
+ ckThreadEnd(NULL);
+ } else {
+ sleep(1);
+ }
+ }
+}
+#endif /* NT */
+#endif /* CK_FORWARD_X */
+#endif /* TNCODE */
+#endif /* NETCONN */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcnet.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcnet.h
new file mode 100644
index 0000000..040bc74
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcnet.h
@@ -0,0 +1,1509 @@
+/* ckcnet.h -- Symbol and macro definitions for C-Kermit network support */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef CKCNET_H
+#define CKCNET_H
+
+/* Network types */
+
+#define NET_NONE 0 /* None */
+#define NET_TCPB 1 /* TCP/IP Berkeley (socket) */
+#define NET_TCPA 2 /* TCP/IP AT&T (streams) */
+#define NET_SX25 3 /* SUNOS SunLink X.25 */
+#define NET_DEC 4 /* DECnet */
+#define NET_VPSI 5 /* VAX PSI */
+#define NET_PIPE 6 /* LAN Manager Named Pipe */
+#define NET_VX25 7 /* Stratus VOS X.25 */
+#define NET_BIOS 8 /* IBM NetBios */
+#define NET_SLAT 9 /* Meridian Technologies' SuperLAT */
+#define NET_FILE 10 /* Read from a file */
+#define NET_CMD 11 /* Read from a sub-process */
+#define NET_DLL 12 /* Load a DLL for use as comm channel*/
+#define NET_IX25 13 /* IBM AIX 4.1 X.25 */
+#define NET_HX25 14 /* HP-UX 10 X.25 */
+#define NET_PTY 15 /* Pseudoterminal */
+#define NET_SSH 16 /* SSH */
+
+#ifdef OS2 /* In OS/2, only the 32-bit */
+#ifndef __32BIT__ /* version gets NETBIOS */
+#ifdef CK_NETBIOS
+#undef CK_NETBIOS
+#endif /* CK_NETBIOS */
+#endif /* __32BIT__ */
+#endif /* OS2 */
+
+#ifdef _M_PPC
+#ifdef SUPERLAT
+#undef SUPERLAT
+#endif /* SUPERLAT */
+#endif /* _M_PPC */
+
+#ifdef NPIPE /* For items in common to */
+#define NPIPEORBIOS /* Named Pipes and NETBIOS */
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+#ifndef NPIPEORBIOS
+#define NPIPEORBIOS
+#endif /* NPIPEORBIOS */
+#endif /* CK_NETBIOS */
+
+/* Network virtual terminal protocols (for SET HOST connections) */
+/* FTP, HTTP and SSH have their own stacks */
+
+#define NP_DEFAULT 255
+#define NP_NONE 0 /* None (async) */
+#define NP_TELNET 1 /* TCP/IP telnet */
+#define NP_VTP 2 /* ISO Virtual Terminal Protocol */
+#define NP_X3 3 /* CCITT X.3 */
+#define NP_X28 4 /* CCITT X.28 */
+#define NP_X29 5 /* CCITT X.29 */
+#define NP_RLOGIN 6 /* TCP/IP Remote login */
+#define NP_KERMIT 7 /* TCP/IP Kermit */
+#define NP_TCPRAW 8 /* TCP/IP Raw socket */
+#define NP_TCPUNK 9 /* TCP/IP Unknown */
+#define NP_SSL 10 /* TCP/IP SSLv23 */
+#define NP_TLS 11 /* TCP/IP TLSv1 */
+#define NP_SSL_TELNET 12 /* TCP/IP Telnet over SSLv23 */
+#define NP_TLS_TELNET 13 /* TCP/IP Telnet over TLSv1 */
+#define NP_K4LOGIN 14 /* TCP/IP Kerberized remote login */
+#define NP_EK4LOGIN 15 /* TCP/IP Encrypted Kerberized ... */
+#define NP_K5LOGIN 16 /* TCP/IP Kerberized remote login */
+#define NP_EK5LOGIN 17 /* TCP/IP Encrypted Kerberized ... */
+#define NP_K5U2U 18 /* TCP/IP Kerberos 5 User to User */
+#define NP_CTERM 19 /* DEC CTERM */
+#define NP_LAT 20 /* DEC LAT */
+#define NP_SSL_RAW 21 /* SSL with no Telnet permitted */
+#define NP_TLS_RAW 22 /* TLS with no Telnet permitted */
+
+/* others here... */
+
+#ifdef CK_SSL
+#define IS_TELNET() (nettype == NET_TCPB && (ttnproto == NP_TELNET \
+ || ttnproto == NP_SSL_TELNET \
+ || ttnproto == NP_TLS_TELNET \
+ || ttnproto == NP_KERMIT))
+#else /* CK_SSL */
+#define IS_TELNET() (nettype == NET_TCPB && (ttnproto == NP_TELNET \
+ || ttnproto == NP_KERMIT))
+#endif /* CK_SSL */
+
+#ifdef CK_KERBEROS
+#ifdef KRB5
+#ifdef KRB4
+#define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN \
+ || ttnproto == NP_K5LOGIN \
+ || ttnproto == NP_EK5LOGIN \
+ || ttnproto == NP_K4LOGIN \
+ || ttnproto == NP_EK4LOGIN \
+ ))
+#else /* KRB4 */
+#define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN \
+ || ttnproto == NP_K5LOGIN \
+ || ttnproto == NP_EK5LOGIN \
+ ))
+#endif /* KRB4 */
+#else /* KRB5 */
+#ifdef KRB4
+#define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN \
+ || ttnproto == NP_K4LOGIN \
+ || ttnproto == NP_EK4LOGIN \
+ ))
+#else /* KRB4 */
+KERBEROS defined without either KRB4 or KRB5
+#endif /* KRB4 */
+#endif /* KRB5 */
+#else /* CK_KERBEROS */
+#define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN))
+#endif /* CK_KERBEROS */
+
+#define IS_SSH() (nettype == NET_SSH)
+
+/* RLOGIN Modes */
+#define RL_RAW 0 /* Do Not Process XON/XOFF */
+#define RL_COOKED 1 /* Do Process XON/XOFF */
+
+/* Encryption types */
+
+#define CX_NONE 999
+
+#ifdef ENCTYPE_ANY
+#define CX_AUTO ENCTYPE_ANY
+#else
+#define CX_AUTO 0
+#endif /* ENCTYPE_ANY */
+
+#ifdef ENCTYPE_DES_CFB64
+#define CX_DESC64 ENCTYPE_DES_CFB64
+#else
+#define CX_DESC64 1
+#endif /* ENCTYPE_DES_CFB64 */
+
+#ifdef ENCTYPE_DES_OFB64
+#define CX_DESO64 ENCTYPE_DES_OFB64
+#else
+#define CX_DESO64 2
+#endif /* ENCTYPE_DES_OFB64 */
+
+#ifdef ENCTYPE_DES3_CFB64
+#define CX_DES3C64 ENCTYPE_DES3_CFB64
+#else
+#define CX_DES3C64 3
+#endif /* ENCTYPE_DES_CFB64 */
+
+#ifdef ENCTYPE_DES3_OFB64
+#define CX_DESO64 ENCTYPE_DES3_OFB64
+#else
+#define CX_DES3O64 4
+#endif /* ENCTYPE_DES_OFB64 */
+
+#ifdef ENCTYPE_CAST5_40_CFB64
+#define CX_C540C64 ENCTYPE_CAST5_40_CFB64
+#else
+#define CX_C540C64 8
+#endif /* ENCTYPE_CAST5_40_CFB64 */
+
+#ifdef ENCTYPE_CAST5_40_OFB64
+#define CX_C540O64 ENCTYPE_CAST5_40_OFB64
+#else
+#define CX_C540O64 9
+#endif /* ENCTYPE_CAST5_40_OFB64 */
+
+#ifdef ENCTYPE_CAST128_CFB64
+#define CX_C128C64 ENCTYPE_CAST128_CFB64
+#else
+#define CX_C128C64 10
+#endif /* ENCTYPE_CAST128_CFB64 */
+
+#ifdef ENCTYPE_CAST128_OFB64
+#define CX_C128O64 ENCTYPE_CAST128_OFB64
+#else
+#define CX_C128O64 11
+#endif /* ENCTYPE_CAST128_OFB64 */
+
+/* Basic network function prototypes, common to all. */
+
+_PROTOTYP( int netopen, (char *, int *, int) );
+_PROTOTYP( int netclos, (void) );
+_PROTOTYP( int netflui, (void) );
+_PROTOTYP( int nettchk, (void) );
+_PROTOTYP( int netxchk, (int) );
+_PROTOTYP( int netbreak, (void) );
+_PROTOTYP( int netinc, (int) );
+_PROTOTYP( int netxin, (int, CHAR *) );
+_PROTOTYP( int nettol, (CHAR *, int) );
+_PROTOTYP( int nettoc, (CHAR) );
+#ifdef TCPSOCKET
+_PROTOTYP( int gettcpport, (void) );
+_PROTOTYP( int gettcpport, (void) );
+#endif /* TCPSOCKET */
+
+/*
+ SunLink X.25 support by Marcello Frutig, Catholic University,
+ Rio de Janeiro, Brazil, 1990.
+
+ Maybe this can be adapted to VAX PSI and other X.25 products too.
+*/
+#ifndef SUNOS4 /* Only valid for SUNOS4 */
+#ifndef SOLARIS
+#ifdef SUNX25
+#undef SUNX25
+#endif /* SUNX25 */
+#endif /* SOLARIS */
+#endif /* SUNOS4 */
+
+#ifdef STRATUSX25
+#define ANYX25
+#define MAX_USER_DATA 128 /* SUN defines this in a header file, I believe. */
+#endif /* STRATUSX25 */
+
+#ifdef SUNX25
+#define ANYX25
+#endif /* SUNX25 */
+
+#ifdef IBMX25 /* AIX 4.1 X.25 */
+#ifndef AIX41
+#undef IBMX25
+#else /* AIX41 */
+#define ANYX25
+#define MAX_USER_DATA NPI_MAX_DATA /* used for buffer sizes */
+#endif /* AIX41 */
+#endif /* IBMX25 */
+
+#ifdef HPX25 /* HP-UX 10.* X.25 */
+#ifndef HPUX10
+#undef HPX25
+#else /* HPUX10 */
+#define ANYX25
+#endif /* HPUX10 */
+#endif /* HPX25 */
+
+#ifdef ANYX25
+#ifndef NETCONN /* ANYX25 implies NETCONN */
+#define NETCONN
+#endif /* NETCONN */
+
+#define MAXPADPARMS 22 /* Number of PAD parameters */
+#define MAXCUDATA 12 /* Max length of X.25 call user data */
+#define X29PID 1 /* X.29 protocol ID */
+#define X29PIDLEN 4 /* X.29 protocol ID length */
+
+#define X29_SET_PARMS 2
+#define X29_READ_PARMS 4
+#define X29_SET_AND_READ_PARMS 6
+#define X29_INVITATION_TO_CLEAR 1
+#define X29_PARAMETER_INDICATION 0
+#define X29_INDICATION_OF_BREAK 3
+#define X29_ERROR 5
+
+#define INVALID_PAD_PARM 1
+
+#define PAD_BREAK_CHARACTER 0
+
+#define PAD_ESCAPE 1
+#define PAD_ECHO 2
+#define PAD_DATA_FORWARD_CHAR 3
+#define PAD_DATA_FORWARD_TIMEOUT 4
+#define PAD_FLOW_CONTROL_BY_PAD 5
+#define PAD_SUPPRESSION_OF_SIGNALS 6
+#define PAD_BREAK_ACTION 7
+#define PAD_SUPPRESSION_OF_DATA 8
+#define PAD_PADDING_AFTER_CR 9
+#define PAD_LINE_FOLDING 10
+#define PAD_LINE_SPEED 11
+#define PAD_FLOW_CONTROL_BY_USER 12
+#define PAD_LF_AFTER_CR 13
+#define PAD_PADDING_AFTER_LF 14
+#define PAD_EDITING 15
+#define PAD_CHAR_DELETE_CHAR 16
+#define PAD_BUFFER_DELETE_CHAR 17
+#define PAD_BUFFER_DISPLAY_CHAR 18
+
+#define MAXIX25 MAX_USER_DATA*7
+#define MAXOX25 MAX_USER_DATA
+#endif /* ANYX25 */
+
+#ifdef SUNX25
+#ifdef SOLARIS25 /* and presumably SunLink 9.xx */
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioccom.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sundev/syncstat.h>
+#include <netx25/x25_pk.h>
+#include <netx25/x25_ctl.h>
+#include <netx25/x25_ioctl.h>
+#else
+#include <sys/ioctl.h> /* X.25 includes, Sun only */
+#include <sys/systm.h>
+#ifndef SOLARIS
+#include <sys/mbuf.h>
+#endif /* SOLARIS */
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#ifdef SOLARIS
+#include <sys/sockio.h>
+#else
+#include <sys/domain.h>
+#endif /* SOLARIS */
+#include <sys/socketvar.h>
+#include <net/if.h>
+#include <sundev/syncstat.h>
+#include <netx25/x25_pk.h>
+#include <netx25/x25_ctl.h>
+#include <netx25/x25_ioctl.h>
+#endif /* SOLARIS25 */
+#endif /* SUNX25 */
+
+#ifdef ANYX25
+
+#ifdef IBMX25 /* X.25 includes, AIX only */
+#include <fcntl.h>
+#include <sys/twtypes.h>
+#include <sys/twlib.h>
+
+#include <sys/stream.h>
+#include <stropts.h>
+
+#define NPI_20 /* required to include the whole NPI */
+#include <sys/npi_20.h>
+#include <sys/npiapi.h>
+#include <sys/pktintf.h>
+
+#include <odmi.h> /* required for access to the ODM */
+#include <sys/cfgodm.h> /* database, needed to find out the */
+ /* local NUA. see x25local_nua() */
+
+
+/* IBM X25 NPI generic primitive type */
+typedef union N_npi_ctl_t {
+ ulong PRIM_type; /* generic primitive type */
+ char buffer[NPI_MAX_CTL]; /* maximum primitive size */
+ N_bind_ack_t bind_ack;
+ N_bind_req_t bind_req;
+ N_conn_con_t conn_con;
+ N_conn_ind_t conn_ind;
+ N_conn_req_t conn_req;
+ N_conn_res_t conn_res;
+ N_data_req_t data_req;
+ N_data_ind_t data_ind;
+ N_discon_ind_t discon_ind;
+ N_discon_req_t discon_req;
+ N_error_ack_t error_ack;
+ N_exdata_ind_t exdata_ind;
+ N_info_ack_t info_ack;
+ N_ok_ack_t ok_ack;
+ N_reset_con_t reset_con;
+ N_reset_req_t reset_req;
+ N_reset_ind_t reset_ind;
+} N_npi_ctl_t;
+
+/* some extra definitions to help out */
+typedef char x25addr_t[45]; /* max 40 defined by CCITT */
+typedef char N_npi_data_t[NPI_MAX_DATA];
+
+/* fd or server waiting for connections, used by netclos and netopen */
+extern int x25serverfd;
+
+#endif /* IBMX25 */
+
+#ifdef HPX25 /* X.25 includes, HP-UX only */
+#include <x25/ccittproto.h>
+#include <x25/x25.h>
+#include <x25/x25addrstr.h>
+#include <x25/x25codes.h>
+#include <x25/x25hd_ioctl.h>
+#include <x25/x25ioctls.h>
+#include <x25/x25str.h>
+#include <sys/ioctl.h>
+#endif /* HPX25 */
+
+/* C-Kermit X.3 / X.25 / X.29 / X.121 support functions */
+
+/* (riehm: this list of functions isn't quite right for AIX) */
+
+_PROTOTYP( int shopad, (int) );
+_PROTOTYP( int shox25, (int) );
+_PROTOTYP( VOID initpad, (void) );
+_PROTOTYP( VOID setpad, (CHAR *, int) );
+_PROTOTYP( VOID readpad, (CHAR *, int, CHAR *) );
+_PROTOTYP( int qbitpkt, (CHAR *, int) );
+_PROTOTYP( VOID setqbit, (void) );
+_PROTOTYP( VOID resetqbit, (void) );
+_PROTOTYP( VOID breakact, (void) );
+_PROTOTYP( int pkx121, (char *, CHAR *) );
+_PROTOTYP( SIGTYP x25oobh, (int) );
+_PROTOTYP( int x25diag, (void) );
+_PROTOTYP( int x25intr, (char) );
+_PROTOTYP( int x25reset, (char, char) );
+_PROTOTYP( int x25clear, (void) );
+_PROTOTYP( int x25stat, (void) );
+_PROTOTYP( int x25in, (int, CHAR *) );
+_PROTOTYP( int setpadp, (void) );
+_PROTOTYP( int setx25, (void) );
+_PROTOTYP( int x25xin, (int, CHAR *) );
+_PROTOTYP( int x25inl, (CHAR *, int, int, CHAR) );
+
+#ifdef IBMX25
+ /* setup x25 */
+_PROTOTYP( ulong x25bind, (int, char *, char *, int, int, int, ulong) );
+_PROTOTYP( int x25call, (int, char *, char *) ); /* connect to remote */
+_PROTOTYP( int x25unbind, (int) ); /* disconnect */
+_PROTOTYP( char *x25prim, (int) ); /* display primitives */
+_PROTOTYP( int x25local_nua, (char *) ); /* find local NUA */
+#endif /* IBMX25 */
+
+#endif /* ANYX25 */
+
+/* CMU-OpenVMS/IP */
+
+#ifdef CMU_TCPIP /* CMU_TCPIP implies TCPSOCKET */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef TCPIPLIB
+#define TCPIPLIB
+#endif /* TCPIPLIB */
+#endif /* CMU_TCPIP */
+
+/* DEC TCP/IP for (Open)VMS, previously known as UCX */
+
+#ifdef DEC_TCPIP /* DEC_TCPIP implies TCPSOCKET */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef TCPIPLIB
+#define TCPIPLIB
+#endif /* TCPIPLIB */
+#endif /* DEC_TCPIP */
+
+/* SRI/TGV/Cisco/Process MultiNet, TCP/IP for VAX/VMS */
+
+#ifdef MULTINET /* MULTINET implies TCPSOCKET */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef TCPIPLIB
+#define TCPIPLIB
+#endif /* TCPIPLIB */
+#ifndef TGVORWIN /* MULTINET and WINTCP */
+#define TGVORWIN /* share a lot of code... */
+#endif /* TGVORWIN */
+#endif /* MULTINET */
+
+/* Wollongong TCP/IP for VAX/VMS */
+
+#ifdef WINTCP /* WINTCP implies TCPSOCKET */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef TCPIPLIB
+#define TCPIPLIB
+#endif /* TCPIPLIB */
+#ifndef TGVORWIN /* WINTCP and MULTINET */
+#define TGVORWIN /* share a lot of code... */
+#endif /* TGVORWIN */
+#endif /* WINTCP */
+
+/* Wollongong TCP/IP for AT&T Sys V */
+
+#ifdef WOLLONGONG /* WOLLONGONG implies TCPSOCKET */
+#ifndef TCPSOCKET /* Don't confuse WOLLONGONG */
+#define TCPSOCKET /* (which is for UNIX) with */
+#endif /* TCPSOCKET */ /* WINTCP, which is for VMS! */
+#endif /* WOLLONGONG */
+
+#ifdef EXCELAN /* EXCELAN implies TCPSOCKET */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#endif /* EXCELAN */
+
+#ifdef INTERLAN /* INTERLAN implies TCPSOCKET */
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#endif /* INTERLAN */
+
+#ifdef BEBOX
+#ifndef TCPSOCKET
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#ifndef TCPIPLIB
+#define TCPIPLIB
+#endif /* TCPIPLIB */
+#define socket_errno h_errno
+#define socket_read(x,y,z) recv(x,y,sizeof(char),z)
+#define socket_write(x,y,z) send(x,y,sizeof(char),z)
+#define socket_ioctl ioctl
+#define socket_close(x) closesocket(x)
+#ifndef FIONBIO
+#define FIONBIO 2
+#endif /* FIONBIO */
+#ifndef FIONREAD
+#define FIONREAD 1
+#endif /* FIONREAD */
+#ifndef SIOCATMARK
+#define SIOCATMARK 3
+#endif /* SIOCATMARK */
+#endif /* BEBOX */
+
+#ifdef COMMENT /* no longer used but might come in handy again later... */
+/*
+ CK_READ0 can (and should) be defined if and only if:
+ (a) read(fd,&x,0) can be used harmlessly on a TCP/IP socket connection.
+ (b) read(fd,&x,0) returns 0 if the connection is up, -1 if it is down.
+*/
+#ifndef CK_READ0
+#ifdef TCPSOCKET
+#ifdef SUNOS41 /* It works in SunOS 4.1 */
+#define CK_READ0
+#else
+#ifdef NEXT /* and NeXTSTEP */
+#define CK_READ0
+#endif /* NEXT */
+#endif /* SUNOS41 */
+#endif /* TCPSOCKET */
+#endif /* CK_READ0 */
+#endif /* COMMENT */
+
+/* Telnet protocol */
+
+#ifdef TCPSOCKET /* TCPSOCKET implies TNCODE */
+#ifndef TNCODE /* Which means... */
+#define TNCODE /* Compile in telnet code */
+#endif /* TNCODE */
+
+/*
+ Platforms where we must call gethostname(buf,len) and then
+ gethostbyname(buf) to get local IP address, rather than calling
+ gethostbyname("").
+*/
+#ifndef CKGHNLHOST
+#ifdef datageneral
+#define CKGHNLHOST
+#else
+#ifdef SOLARIS
+#define CKGHNLHOST
+#else
+#ifdef SUNOS4
+#define CKGHNLHOST
+#else
+#ifdef UNIXWARE
+#define CKGHNLHOST
+#else
+#ifdef SINIX
+#define CKGHNLHOST
+#endif /* SINIX */
+#endif /* UNIXWARE */
+#endif /* SUNOS4 */
+#endif /* SOLARIS */
+#endif /* datageneral */
+#endif /* CKGHNLHOST */
+
+#ifndef RLOGCODE /* What about Rlogin? */
+#ifndef NORLOGIN
+/*
+ Rlogin can be enabled only for UNIX versions that have both SIGURG
+ (SCO doesn't) and CK_TTGWSIZ (OSF/1 doesn't), so we don't assume that
+ any others have these without verifying first. Not that it really makes
+ much difference since you can only use Rlogin if you are root...
+*/
+#ifdef SUNOS41
+#define RLOGCODE
+#else
+#ifdef SOLARIS
+#define RLOGCODE
+#else
+#ifdef HPUX9
+#define RLOGCODE
+#else
+#ifdef HPUX10
+#define RLOGCODE
+#else
+#ifdef OSF40
+#define RLOGCODE
+#else
+#ifdef NEXT
+#define RLOGCODE
+#else
+#ifdef AIX41
+#define RLOGCODE
+#else
+#ifdef UNIXWARE
+#define RLOGCODE
+#else
+#ifdef IRIX51
+#define RLOGCODE
+#else
+#ifdef IRIX60
+#define RLOGCODE
+#else
+#ifdef QNX
+#define RLOGCODE
+#else
+#ifdef __linux__
+#define RLOGCODE
+#else
+#ifdef BSD44
+#define RLOGCODE
+#endif /* BSD44 */
+#endif /* __linux__ */
+#endif /* QNX */
+#endif /* IRIX60 */
+#endif /* IRIX51 */
+#endif /* UNIXWARE */
+#endif /* AIX41 */
+#endif /* NEXT */
+#endif /* OSF40 */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* SOLARIS */
+#endif /* SUNOS41 */
+#endif /* NORLOGIN */
+#ifdef VMS /* VMS */
+#define RLOGCODE
+#endif /* VMS */
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+
+#ifdef TNCODE
+/*
+ Telnet local-echo buffer, used for saving up user data that can't be
+ properly displayed and/or evaluated until pending Telnet negotiations are
+ complete. TTLEBUF is defined for platforms (like UNIX) where net i/o is
+ done by the same routines that do serial i/o (in which case the relevant
+ code goes into the ck?tio.c module, in the ttinc(), ttchk(), etc, routines);
+ NETLETBUF is defined for platforms (like VMS) that use different APIs for
+ network and serial i/o, and enables the copies of the same routines that
+ are in ckcnet.c.
+*/
+#ifndef TTLEBUF
+#ifdef UNIX
+#define TTLEBUF
+#else
+#ifdef datageneral
+#define TTLEBUF
+#endif /* datageneral */
+#endif /* UNIX */
+#endif /* TTLEBUF */
+
+#ifndef NETLEBUF
+#ifdef VMS
+#define NETLEBUF
+#endif /* VMS */
+#endif /* NETLEBUF */
+#endif /* TNCODE */
+
+#ifdef SUNX25 /* SUNX25 implies TCPSOCKET */
+#ifndef TCPSOCKET /* But doesn't imply TNCODE */
+#define TCPSOCKET
+#endif /* TCPSOCKET */
+#endif /* SUNX25 */
+
+#ifndef TCPSOCKET
+#ifndef NO_DNS_SRV
+#define NO_DNS_SRV
+#endif /* NO_DNS_SRV */
+#endif /* TCPSOCKET */
+
+/* This is another TCPSOCKET section... */
+
+#ifdef TCPSOCKET
+#ifndef NETCONN /* TCPSOCKET implies NETCONN */
+#define NETCONN
+#endif /* NETCONN */
+
+#ifndef NO_DNS_SRV
+#ifdef NOLOCAL
+#define NO_DNS_SRV
+#endif /* NOLOCAL */
+#ifdef OS2ONLY
+#define NO_DNS_SRV
+#endif /* OS2ONLY */
+#ifdef NT
+#ifdef _M_PPC
+#define NO_DNS_SRV
+#endif /* _M_DNS */
+#endif /* NO_DNS_SRV */
+#ifdef VMS
+#define NO_DNS_SRV
+#endif /* VMS */
+#ifdef STRATUS
+#define NO_DNS_SRV
+#endif /* STRATUS */
+#ifdef datageneral
+#define NO_DNS_SRV
+#endif /* datageneral */
+#ifdef ultrix
+#define NO_DNS_SRV
+#endif /* ultrix */
+#ifdef NEXT
+#define NO_DNS_SRV
+#endif /* NEXT */
+#endif /* NO_DNS_SRV */
+
+#ifndef CK_DNS_SRV /* Use DNS SRV records to determine */
+#ifndef NO_DNS_SRV /* host and ports */
+#define CK_DNS_SRV
+#endif /* NO_DNS_SRV */
+#endif /* CK_DNS_SRV */
+
+#ifndef NOLISTEN /* select() is required to support */
+#ifndef SELECT /* incoming connections. */
+#ifndef VMS
+#ifndef OS2
+#define NOLISTEN
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* SELECT */
+#endif /* NOLISTEN */
+
+/* BSD sockets library header files */
+
+#ifdef VMS
+/*
+ Because bzero() and bcopy() are not portable among VMS versions,
+ or compilers, or TCP/IP products, etc.
+*/
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif /* bzero */
+#ifndef bcopy
+#define bcopy(h,a,l) memcpy(a,h,l)
+#endif /* bcopy */
+#endif /* VMS */
+
+#ifdef HPUX6
+/* These are missing in HP-UX 6.xx */
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif /* bzero */
+#ifndef bcopy
+#define bcopy(h,a,l) memcpy(a,h,l)
+#endif /* bcopy */
+#endif /* HPUX6 */
+
+#ifdef UNIX /* UNIX section */
+
+#ifdef SVR4
+/*
+ These suggested by Rob Healey, rhealey@kas.helios.mn.org, to avoid
+ bugs in Berkeley compatibility library on Sys V R4 systems, but untested
+ by me (fdc). Remove this bit if it gives you trouble.
+ (Later corrected by Marc Boucher <mboucher@iro.umontreal.ca> because
+ bzero/bcopy are not argument-compatible with memset/memcpy|memmove.)
+*/
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif
+#ifdef SOLARIS
+#ifdef SUNX25
+#undef bzero
+/*
+ WOULD YOU BELIEVE... That the Solaris X.25 /opt/SUNWcomm/lib/libsockx25
+ library references bzero, even though the use of bzero is forbidden in
+ Solaris? Look for the function definition in ckcnet.c.
+*/
+_PROTOTYP( void bzero, (char *, int) );
+#endif /* SUNX25 */
+#ifndef bcopy
+#define bcopy(h,a,l) memcpy(a,h,l)
+#endif
+#else
+#ifndef bcopy
+#define bcopy(h,a,l) memmove(a,h,l)
+#endif
+#endif /* SOLARIS */
+#else /* !SVR4 */
+#ifdef PTX /* Sequent DYNIX PTX 1.3 */
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif
+#ifndef bcopy
+#define bcopy(h,a,l) memcpy(a,h,l)
+#endif
+#endif /* PTX */
+#endif /* SVR4 */
+
+#ifdef INTERLAN /* Racal-Interlan TCP/IP */
+#include <interlan/socket.h>
+#include <interlan/il_types.h>
+#include <interlan/telnet.h>
+#include <interlan/il_errno.h>
+#include <interlan/in.h>
+#include <interlan/telnet.h> /* Why twice ? ? ? */
+#else /* Not Interlan */
+#ifdef BEBOX
+#include <socket.h>
+#else /* Not BEBOX */ /* Normal BSD TCP/IP library */
+#ifdef COMMENT
+#ifndef HPUX
+#include <arpa/telnet.h>
+#endif /* HPUX */
+#endif /* COMMENT */
+#ifdef SCO234
+#include <sys/errno.tcp.h>
+#include <sys/types.tcp.h>
+#endif /* SCO234 */
+#include <sys/socket.h>
+#ifdef WOLLONGONG
+#include <sys/in.h>
+#else
+#include <netinet/in.h>
+#ifndef SV68R3V6 /* (maybe this should be SVR3 in general) */
+#include <netinet/tcp.h> /* Added June 2001 */
+#endif /* SV68R3V6 */
+#endif /* WOLLONGONG */
+#endif /* BEBOX */
+#endif /* INTERLAN */
+
+#ifndef EXCELAN
+#include <netdb.h>
+#ifndef INTERLAN
+#ifdef WOLLONGONG
+#define minor /* Do not include <sys/macros.h> */
+#include <sys/inet.h>
+#else
+#ifndef OXOS
+#ifndef HPUX
+#ifndef BEBOX
+#include <arpa/inet.h>
+#endif /* BEBOX */
+#endif /* HPUX */
+#else /* OXOS */
+/* In too many releases of X/OS, <arpa/inet.h> declares inet_addr() as
+ * ``struct in_addr''. This is definitively wrong, and could cause
+ * core dumps. Instead of including that bad file, inet_addr() is
+ * correctly declared here. Of course, all the declarations done there
+ * has been copied here.
+ */
+unsigned long inet_addr();
+char *inet_ntoa();
+struct in_addr inet_makeaddr();
+unsigned long inet_network();
+#endif /* OXOS */
+#endif /* WOLLONGONG */
+#endif /* INTERLAN */
+#endif /* EXCELAN */
+
+#ifdef EXCELAN /* Excelan TCP/IP */
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif /* bzero */
+#ifndef bcopy
+#define bcopy(h,a,l) memcpy(a,h,l)
+#endif /* bcopy */
+#include <ex_errno.h>
+#endif /* EXCELAN */
+
+#ifdef I386IX /* Interactive Sys V R3 network. */
+/* #define TELOPTS */ /* This might need defining. */
+#define ORG_NLONG ENAMETOOLONG /* Resolve conflicting symbols */
+#undef ENAMETOOLONG /* in <errno.h> and <net/errno.h> */
+#define ORG_NEMPTY ENOTEMPTY
+#undef ENOTEMPTY
+#include <net/errno.h>
+#undef ENAMETOOLONG
+#define ENAMETOOLONG ORG_NLONG
+#undef ENOTEMPTY
+#define ENOTEMPTY ORG_NEMPTY
+#include <netinet/tcp.h> /* for inet_addr() */
+#endif /* I386IX */
+/*
+ Data type of the inet_addr() function...
+ We define INADDRX if it is of type struct inaddr.
+ If it is undefined, unsigned long is assumed.
+ Look at <arpa/inet.h> to find out. The following known cases are
+ handled here. Other systems that need it can be added here, or else
+ -DINADDRX can be included in the CFLAGS on the cc command line.
+*/
+#ifndef NOINADDRX
+#ifdef DU2 /* DEC Ultrix 2.0 */
+#define INADDRX
+#endif /* DU2 */
+#endif /* NOINADDRX */
+
+#else /* Not UNIX */
+
+#ifdef VMS /* (Open)VMS section */
+
+#ifdef MULTINET /* TGV MultiNet */
+/*
+ In C-Kermit 7.0 Beta.08 we started getting scads of compile time warnings
+ in Multinet builds: "blah" is implicitly declared as a function, where blah
+ is socket_read/write/close, ntohs, htons, getpeername, accept, select, etc.
+ I have no idea why -- these routines are declared in the header files below,
+ and the includes haven't changed. The executable still seems to work OK.
+ Messing with the order of the following includes is disastrous.
+*/
+#ifdef MULTINET_NO_PROTOTYPES
+#undef MULTINET_NO_PROTOTYPES
+#endif /* MULTINET_NO_PROTOTYPES */
+
+#ifdef __cplusplus
+#undef __cplusplus
+#endif /* __cplusplus */
+
+#include "multinet_root:[multinet.include]errno.h"
+#include "multinet_root:[multinet.include.sys]types.h"
+#include "multinet_root:[multinet.include.sys]socket.h"
+#include "multinet_root:[multinet.include]netdb.h"
+#include "multinet_root:[multinet.include.netinet]in.h"
+#include "multinet_root:[multinet.include.arpa]inet.h"
+#include "multinet_root:[multinet.include.sys]ioctl.h"
+
+#ifdef COMMENT
+/*
+ No longer needed because now bzero/bcopy are macros defined as
+ memset/memmove in all VMS builds.
+*/
+/*
+ We should be able to pick these up from <strings.h> but it's
+ not portable between VAXC and DECC. And even with DECC 5.x we have a
+ difference between VAX and Alpha. We get warnings here on the VAX
+ with DECC 5.6-003 but they are not fatal.
+*/
+#ifndef __DECC_VER
+#ifndef bzero
+_PROTOTYP( void bzero, (char *, int) );
+#endif /* bzero */
+#ifndef bcopy
+_PROTOTYP( void bcopy, (char *, char *, int) );
+#endif /* bcopy */
+#endif /* __DECC_VER */
+#endif /* COMMENT */
+
+#ifdef __DECC
+/*
+ If compiling under DEC C the socket calls must not be prefixed with
+ DECC$. This is done by using the compiler switch /Prefix=Ansi_C89.
+ However, this causes some calls that should be prefixed to not be
+ (which I think is a bug in the compiler - I've been told these calls
+ are present in ANSI compilers). At any rate, such calls are fixed
+ here by explicitly prefixing them.
+*/
+#ifdef COMMENT
+/*
+ But this causes errors with VMS 6.2 / DEC C 5.3-006 / MultiNet 4.0A on
+ a VAX (but not on an Alpha). So now what happens if we skip doing this?
+*/
+#define close decc$close
+#define alarm decc$alarm
+#endif /* COMMENT */
+#endif /* __DECC */
+
+#else /* Not MULTINET */
+
+#ifdef WINTCP /* WIN/TCP = PathWay for VMS */
+#ifdef OLD_TWG
+#include "twg$tcp:[netdist.include.sys]errno.h"
+#include "twg$tcp:[netdist.include.sys]types2.h" /* avoid some duplicates */
+#else
+#include "twg$tcp:[netdist.include]socket_aliases.h"
+#include <errno.h>
+#include "twg$tcp:[netdist.include.sys]types.h"
+#endif /* OLD_TWG */
+#include "twg$tcp:[netdist.include.sys]socket.h"
+#include "twg$tcp:[netdist.include]netdb.h"
+#include "twg$tcp:[netdist.include.sys]domain.h"
+#include "twg$tcp:[netdist.include.sys]protosw.h"
+#include "twg$tcp:[netdist.include.netinet]in.h"
+#include "twg$tcp:[netdist.include.arpa]inet.h"
+#include "twg$tcp:[netdist.include.sys]ioctl.h"
+
+#else /* Not WINTCP */
+
+#ifdef DEC_TCPIP
+#ifdef UCX50
+#ifndef IF_DOT_H
+#define IF_DOT_H
+#endif /* IF_DOT_H */
+#endif /* UCX50 */
+
+#ifdef IF_DOT_H
+#include <if.h> /* Needed to put up u_int typedef */
+#else
+#ifdef NEEDUINT
+typedef unsigned int u_int;
+#endif /* NEEDUINT */
+#endif /* IF_DOT_H */
+
+#include <in.h>
+#ifdef VMS
+#include <inet.h> /* (SMS 2007/02/15) */
+#endif /* VMS */
+#include <netdb.h>
+#include <socket.h>
+#include "ckvioc.h"
+#define socket_errno errno
+
+#ifdef COMMENT
+/*
+ No longer needed because now bzero/bcopy are macros defined as
+ memset/memmove in all VMS builds.
+*/
+/*
+ Translation: In <strings.h>, which exists only for DECC >= 5.2, bzero()
+ and bcopy() are declared only for OpenVMS >= 7.0. This still might need
+ adjustment for DECC 5.0 and higher.
+*/
+#ifdef __DECC_VER
+#ifdef VMSV70
+/*
+ Note: you can't use "#if (__VMS_VER>=70000000)" because that is not
+ portable and kills non-VMS builds.
+*/
+#include <strings.h>
+#else
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif
+#ifndef bcopy
+#define bcopy(h,a,l) memmove(a,h,l)
+#endif
+#endif /* VMSV70 */
+#else
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif
+#ifndef bcopy
+#define bcopy(h,a,l) memmove(a,h,l)
+#endif
+#endif /* __DECC_VER */
+#endif /* COMMENT */
+
+#define socket_read read
+#define socket_write write
+#define socket_ioctl ioctl
+#define socket_close close
+
+#ifdef __DECC
+int ioctl (int d, int request, void *argp);
+#else
+int ioctl (int d, int request, char *argp);
+#endif /* DECC */
+/*
+ UCX supports select(), but does not provide the needed symbol and
+ structure definitions in any header file, so ...
+*/
+#include <types.h>
+#ifndef NBBY
+/*-
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)types.h 8.1 (Berkeley) 6/2/93
+ */
+
+#define NBBY 8 /* number of bits in a byte */
+
+/*
+ * Select uses bit masks of file descriptors in longs. These macros
+ * manipulate such bit fields (the filesystem macros use chars).
+ * FD_SETSIZE may be defined by the user, but the default here should
+ * be enough for most uses.
+ */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 256
+#endif
+
+typedef long fd_mask;
+#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+
+typedef struct fd_set {
+ fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_COPY(f, t) bcopy(f, t, sizeof(*(f)))
+#define FD_ZERO(p) bzero(p, sizeof(*(p)))
+#endif /* !NBBY */
+
+#else /* Not DEC_TCPIP */
+
+#ifdef CMU_TCPIP
+#include <types.h>
+#include <in.h>
+#include <netdb.h>
+#include <socket.h>
+#include <inet.h>
+#include <ioctl.h>
+#include "ckvioc.h"
+#define socket_errno errno
+
+/*
+ * Routines supplied in LIBCMU.OLB
+ */
+#define socket_ioctl ioctl
+#define socket_read cmu_read
+#define socket_write cmu_write
+#define socket_close cmu_close
+
+#endif /* CMU_TCPIP */
+#endif /* DEC_TCPIP */
+#endif /* WINTCP */
+#endif /* MULTINET */
+
+#else /* Not VMS */
+
+#ifdef OS2
+#include "ckonet.h"
+#ifndef NT
+#include <nerrno.h>
+#endif
+#endif /* OS2 */
+
+#ifdef STRATUS /* Stratus VOS using OS TCP/IP products S235, S236, S237 */
+#include <tcp_socket.h>
+/* This gets used some places when TCPSOCKET is defined. */
+/* OS TCP provides bzero(), but not bcopy()... go figure. */
+#define bcopy(s,d,z) memcpy(d,s,z)
+#endif /* STRATUS */
+
+#ifdef OSK
+#ifndef OSKXXC
+#include <inet/in.h>
+#include <inet/netdb.h>
+#include <inet/socket.h>
+#else
+#include <INET/in.h>
+#include <INET/netdb.h>
+#include <INET/socket.h>
+#endif /* OSKXXC */
+#ifndef bzero
+#define bzero(s,n) memset(s,0,n)
+#endif
+#ifndef bcopy
+#define bcopy(h,a,l) memcpy(a,h,l)
+#endif
+typedef char * caddr_t; /* core address type */
+#endif /* OSK */
+
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* TCPSOCKET */
+
+#ifndef NOINADDRX /* 301 - Needed for Solaris 10 and 11 */
+#ifdef SOLARIS
+#define NOINADDRX
+#ifdef INADDR_NONE
+#undef INADDR_NONE
+#endif /* INADDR_NONE */
+#endif /* SOLARIS */
+#endif /* NOINADDRX */
+
+#ifdef NOINADDRX
+#ifdef INADDRX
+#undef INADDRX
+#endif /* INADDRX */
+#endif /* NOINADDRX */
+
+#ifdef TCPSOCKET
+#ifndef NOHADDRLIST
+#ifndef HADDRLIST
+#ifdef SUNOS41
+#define HADDRLIST
+#endif /* SUNOS41 */
+#ifdef SOLARIS
+#define HADDRLIST
+#endif /* SOLARIS */
+#ifdef LINUX
+#define HADDRLIST
+#endif /* LINUX */
+#ifdef AIXRS
+#define HADDRLIST
+#endif /* AIXRS */
+#ifdef HPUX
+#define HADDRLIST
+#endif /* HPUX */
+#ifdef IRIX
+#define HADDRLIST
+#endif /* IRIX */
+#ifdef I386IX
+#define HADDRLIST
+#endif /* I386IX */
+#endif /* HADDRLIST */
+/* A system that defines h_addr as h_addr_list[0] should be HADDRLIST */
+#ifndef HADDRLIST
+#ifdef h_addr
+#define HADDRLIST
+#endif /* h_addr */
+#endif /* HADDRLIST */
+#endif /* NOHADDRLIST */
+#endif /* TCPSOCKET */
+
+#ifdef TNCODE /* If we're compiling telnet code... */
+#ifndef IKS_OPTION
+#ifndef STRATUS
+#define IKS_OPTION
+#endif /* STRATUS */
+#endif /* IKS_OPTION */
+#include "ckctel.h"
+#else
+extern int sstelnet;
+#ifdef IKSD
+#undef IKSD
+#endif /* IKSD */
+#ifndef NOIKSD
+#define NOIKSD
+#endif /* NOIKSD */
+#ifdef IKS_OPTION
+#undef IKS_OPTION
+#endif /* IKS_OPTION */
+#endif /* TNCODE */
+
+#ifndef NOTCPOPTS
+/*
+ Automatically define NOTCPOPTS for configurations where they can't be
+ used at runtime or cause too much trouble at compile time.
+*/
+#ifdef CMU_TCPIP /* CMU/Tek */
+#define NOTCPOPTS
+#endif /* CMU_TCPIP */
+#ifdef MULTINET /* Multinet on Alpha */
+#ifdef __alpha
+#define NOTCPOPTS
+#endif /* __alpha */
+#endif /* MULTINET */
+#endif /* NOTCPOPTS */
+
+#ifdef NOTCPOPTS
+#ifdef TCP_NODELAY
+#undef TCP_NODELAY
+#endif /* TCP_NODELAY */
+#ifdef SO_LINGER
+#undef SO_LINGER
+#endif /* SO_LINGER */
+#ifdef SO_KEEPALIVE
+#undef SO_KEEPALIVE
+#endif /* SO_KEEPALIVE */
+#ifdef SO_SNDBUF
+#undef SO_SNDBUF
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+#undef SO_RCVBUF
+#endif /* SO_RCVBUF */
+#endif /* NOTCPOPTS */
+
+/* This function is declared even when TCPSOCKET is not available */
+_PROTOTYP( char * ckgetpeer, (VOID));
+
+#ifdef TCPSOCKET
+#ifdef SOL_SOCKET
+#ifdef TCP_NODELAY
+_PROTOTYP( int no_delay, (int, int) );
+#endif /* TCP_NODELAY */
+#ifdef SO_KEEPALIVE
+_PROTOTYP( int keepalive, (int, int) ) ;
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+_PROTOTYP( int ck_linger, (int, int, int) ) ;
+#endif /* SO_LINGER */
+#ifdef SO_SNDBUF
+_PROTOTYP( int sendbuf,(int, int) ) ;
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+_PROTOTYP( int recvbuf, (int, int) ) ;
+#endif /* SO_RCVBUF */
+#ifdef SO_DONTROUTE
+_PROTOTYP(int dontroute, (int, int));
+#endif /* SO_DONTROUTE */
+#endif /* SOL_SOCKET */
+_PROTOTYP( int getlocalipaddr, (VOID));
+_PROTOTYP( int getlocalipaddrs, (char *,int,int));
+_PROTOTYP( char * ckgetfqhostname,(char *));
+_PROTOTYP( struct hostent * ck_copyhostent,(struct hostent *));
+_PROTOTYP( char * ckname2addr, (char *));
+_PROTOTYP( char * ckaddr2name, (char *));
+
+/* AIX */
+
+#ifdef AIXRS
+#ifndef TCP_NODELAY
+#define TCP_NODELAY 0x1
+#endif /* TCP_NODELAY */
+#ifndef TCP_MAXSEG
+#define TCP_MAXSEG 0x2
+#endif /* TCP_MAXSEG */
+#ifndef TCP_KEEPALIVE
+#define TCP_KEEPALIVE 0x8
+#endif /* TCP_KEEPALIVE */
+#endif /* AIXRS */
+#endif /* TCPSOCKET */
+
+#ifdef RLOGCODE
+#ifndef CK_TTGWSIZ
+SORRY_RLOGIN_REQUIRES_TTGWSIZ_see_ckcplm.doc
+#endif /* CK_TTGWSIZ */
+#endif /* RLOGCODE */
+
+#ifdef CK_NAWS
+#ifndef CK_TTGWSIZ
+SORRY_CK_NAWS_REQUIRES_TTGWSIZ_see_ckcplm.doc
+#endif /* CK_TTGWSIZ */
+#endif /* CK_NAWS */
+
+#ifndef PF_INET
+#ifdef AF_INET
+#define PF_INET AF_INET
+#endif /* AF_INET */
+#endif /* PF_INET */
+
+#ifndef IPPORT_ECHO
+#define IPPORT_ECHO 7
+#endif /* IPPORT_ECHO */
+
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+_PROTOTYP(int ck_krb_rlogin,(CHAR *, int, CHAR *, CHAR *, CHAR *,
+ struct sockaddr_in *,
+ struct sockaddr_in *, int, int));
+#endif /* RLOGCODE */
+#endif /* CK_KERBEROS */
+
+_PROTOTYP( VOID ini_kerb, ( void ) ); /* Kerberos initialization routine */
+_PROTOTYP( int doauth, (int) ); /* AUTHENTICATE action routine */
+
+#ifdef CK_DNS_SRV
+_PROTOTYP(int locate_srv_dns,(char *host, char *service,
+ char *protocol, struct sockaddr **addr_pp,
+ int *naddrs));
+#endif /* CK_DNS_SRV */
+
+#ifndef NOHTTP
+_PROTOTYP(int http_open, (char *, char *, int, char *, int, char *));
+_PROTOTYP(int http_reopen, (VOID));
+_PROTOTYP(int http_close, (VOID));
+_PROTOTYP(int http_get, (char *,char **,char *,char *,char,char *,char *,
+ int));
+_PROTOTYP(int http_head, (char *,char **,char *,char *,char,char *,char *,
+ int));
+_PROTOTYP(int http_put, (char *,char **,char *,char *,char *,char,char *,
+ char *, char *, int));
+_PROTOTYP(int http_delete, (char *,char **,char *,char *,char,char *));
+_PROTOTYP(int http_connect, (int, char *,char **,char *,char *,char,char *));
+_PROTOTYP(int http_post, (char *,char **,char *,char *,char *,char,char *,
+ char *,char *, int));
+_PROTOTYP(int http_index, (char *,char **,char *,char *,char,char *,char *,
+ int));
+_PROTOTYP(int http_inc, (int));
+_PROTOTYP(int http_isconnected, (void));
+
+extern char * tcp_http_proxy; /* Name[:port] of http proxy server */
+extern int tcp_http_proxy_errno; /* Return value from server */
+extern char * tcp_http_proxy_user; /* Name of user for authentication */
+extern char * tcp_http_proxy_pwd; /* Password of user */
+#endif /* NOHTTP */
+
+#ifdef TCPSOCKET
+
+/* Type needed as 5th argument (length) to get/setsockopt() */
+
+#ifdef TRU64
+/* They say it themselves - this does not conform to standards */
+#define socklen_t int
+#else
+#ifdef HPUX
+#define socklen_t int
+#endif /* HPUX */
+#endif /* TRU64 */
+
+#ifndef SOCKOPT_T
+#ifdef CK_64BIT
+#define SOCKOPT_T socklen_t
+#endif /* CK_64BIT */
+#endif /* SOCKOPT_T */
+
+#ifndef SOCKOPT_T
+#define SOCKOPT_T int
+#ifdef MACOSX10
+#undef SOCKOPT_T
+#define SOCKOPT_T unsigned int
+#else
+#ifdef AIX42
+#undef SOCKOPT_T
+#define SOCKOPT_T unsigned long
+#else
+#ifdef PTX
+#undef SOCKOPT_T
+#define SOCKOPT_T size_t
+#else
+#ifdef NT
+#undef SOCKOPT_T
+#define SOCKOPT_T int
+#else /* NT */
+#ifdef UNIXWARE
+#undef SOCKOPT_T
+#define SOCKOPT_T size_t
+#else /* UNIXWARE */
+#ifdef VMS
+#ifdef DEC_TCPIP
+#ifdef __DECC_VER
+#undef SOCKOPT_T
+#define SOCKOPT_T size_t
+#endif /* __DECC_VER */
+#endif /* DEC_TCPIP */
+#endif /* VMS */
+#endif /* UNIXWARE */
+#endif /* NT */
+#endif /* PTX */
+#endif /* AIX42 */
+#endif /* MACOSX10 */
+#endif /* SOCKOPT_T */
+
+/* Ditto for getsockname() */
+
+#ifndef GSOCKNAME_T
+#ifdef CK_64BIT
+#define GSOCKNAME_T socklen_t
+#endif /* CK_64BIT */
+#endif /* GSOCKNAME_T */
+
+#ifndef GSOCKNAME_T
+#define GSOCKNAME_T int
+#ifdef MACOSX10
+#undef GSOCKNAME_T
+#define GSOCKNAME_T unsigned int
+#else
+#ifdef PTX
+#undef GSOCKNAME_T
+#define GSOCKNAME_T size_t
+#else
+#ifdef AIX42 /* size_t in 4.2++, int in 4.1-- */
+#undef GSOCKNAME_T
+#define GSOCKNAME_T size_t
+#else
+#ifdef UNIXWARE
+#undef GSOCKNAME_T
+#define GSOCKNAME_T size_t
+#else
+#ifdef VMS
+#ifdef DEC_TCPIP
+#ifdef __DECC_VER
+#undef GSOCKNAME_T
+#define GSOCKNAME_T size_t
+#endif /* __DECC_VER */
+#endif /* DEC_TCPIP */
+#endif /* VMS */
+#endif /* UNIXWARE */
+#endif /* AIX41 */
+#endif /* PTX */
+#endif /* MACOSX10 */
+#endif /* GSOCKNAME_T */
+
+#endif /* TCPSOCKET */
+
+#ifdef MACOSX10
+#ifdef bcopy
+#undef bcopy
+#endif
+#ifdef bzero
+#undef bzero
+#endif
+#endif /* MACOSX10 */
+
+#endif /* CKCNET_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcplm.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckcplm.txt
new file mode 100644
index 0000000..e00edde
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcplm.txt
@@ -0,0 +1,3113 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+C-Kermit Program Logic Manual
+
+ Frank da Cruz
+ [11]The Kermit Project
+
+ As of: C-Kermit 9.0.300, 30 June 2011
+ Last update: Fri Jul 1 15:47:34 2011
+
+ IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+ this file is a plain-text dump of a Web page. You can visit the
+ original (and possibly more up-to-date) Web page here:
+
+ [12]http://www.columbia.edu/kermit/ckcplm.html
+
+CONTENTS
+
+ 1. [13]INTRODUCTION
+ 2. [14]FILES
+ 3. [15]SOURCE CODE PORTABILITY AND STYLE
+ 4. [16]MODULES
+ 4.A. [17]Group A: Library Routines
+ 4.B. [18]Group B: Kermit File Transfer
+ 4.C. [19]Group C: Character-Set Conversion
+ 4.D. [20]Group D: User Interface
+ 4.E. [21]Group E: Platform-Dependent I/O
+ 4.F. [22]Group F: Network Support
+ 4.G. [23]Group G: Formatted Screen Support
+ 4.H. [24]Group H: Pseudoterminal Support
+ 4.I. [25]Group I: Security
+ I. [26]APPENDIX I: FILE PERMISSIONS
+
+1. INTRODUCTION
+
+ The Kermit Protocol is specified in the book [27]Kermit, A File
+ Transfer Protocol by Frank da Cruz, Digital Press / Butterworth
+ Heinemann, Newton, MA, USA (1987), 379 pages, ISBN 0-932376-88-6. It is
+ assumed the reader is familiar with the Kermit protocol specification.
+
+ This file describes the relationship among the modules and functions of
+ C-Kermit 5A and later, and other programming considerations. C-Kermit
+ is designed to be portable to any kind of computer that has a C
+ compiler. The source code is broken into many files that are grouped
+ according to their function, as shown in the [28]Contents.
+
+ C-Kermit has seen constant development since 1985. Throughout its
+ history, there has been a neverending tug-of-war among:
+
+ a. Functionality: adding new features, fixing bugs, improving
+ performance.
+ b. Adding support for new platforms or communication methods.
+ c. "Buzzword 1.0 compliance".
+
+ The latter category is the most frustrating, since it generally
+ involves massive changes just to keep the software doing what it did
+ before in some new setting: e.g. the K&R-to-ANSIC conversion (which had
+ to be done, of course, without breaking K&R); Y2K (not a big deal in
+ our case); the many and varied UNIX and other API "standards" with
+ which to "comply".
+
+ Upon first glance at the source code, you will probably be appalled.
+ Many will be tempted to clean it up and modernize it. But as soon as
+ you do, you are sure to break something. Remember that above all else,
+ the C-Kermit code is portable to every Unix platform that ever existed,
+ going back Unix V7 (1979)*, and to several other completely different
+ and unrelated operating-system families such as DEC/HP VMS, DG AOS/VS,
+ and Stratus VOS, as well as to some Unix offshoots like OS-9 and Plan 9
+ (from Outer Space). Every release of Kermit has been checked on every
+ platform available -- the older the better! -- to make sure it still
+ builds and runs. Even today (2011), there are modern Unix systems that
+ have non-ANSI C compilers, foremost among them HP-UX (where an ANSI
+ optimizing C compiler is available, but only as an expensive add-on).
+ In a way, portability is the most important feature of C-Kermit and
+ every effort should be made to preserve it through future releases.
+
+ Voluminous edit histories are available going back to May 1985. The
+ first versions of C-Kermit were done on our [29]DEC VAX-11/750 with
+ Ultrix 1.0 and 2.0 (as well as departmental 750s with 4.2BSD**), DEC
+ Pro-380 workstations (desktop PDP-11s) running 2.9BSD, which was
+ [30]ported to the 380 by us. Later (1988 or so) on a big VAX 8650 with
+ Ultrix, which became an 8700 (these no doubt weighed several tons), and
+ finally a succession of non-DEC equipment: an Encore Multimax, 25 years
+ worth of Suns, and now Linux on [31]HP Blades. We also had our own VMS
+ development systems for some years. All this plus a generous assortment
+ of departmental and offsite guest accounts on a multitude of platforms.
+ Anyway, the edit histories:
+
+ [32]ckc04e.txt C-Kermit 4.2(030) May 1985 to 4E(072) Jan 1989.
+ [33]ckc04f.txt C-Kermit 4F(077) Arp 1989 to 4F(095) Aug 1989.
+ [34]ckc168.txt Updates to C-Kermit 5A(168) for VMS Nov 1991
+ [35]ckc178.txt C-Kermit 5A(100) Jul 1989 to 5A(178) Jan 1992
+ [36]ckc188.txt C-Kermit 5A(188) development, 1992
+ [37]ckc189.txt C-Kermit 5A(189) development, 1993
+ [38]ckc192.txt C-Kermit 6.0(192) development, 1998
+ [39]ckc197.txt C-Kermit 7.0(197) development, 2000
+ [40]ckc200.txt C-Kermit 8.0.200 development, 2001
+ [41]ckc211.txt C-Kermit 8.0.201 through 8.0.209 2001-2004
+ [42]ckc300.txt C-Kermit 9.0.300 June 2011
+
+ _________________________________
+ * C-Kermit 6.0 was the last one to be built on V7, as I recall. The
+ code should still be good for V7 but it probably has outgrown the
+ 16-bit address space. In any case there is still a V7 makefile target
+ and a V7 path through the forest of #ifdefs in the code if anybody is
+ running V7 on an emulator and would like to try building C-Kermit.
+ There is no support for V6 but that is only because no V6 system was
+ ever found for development. Notice that some other 16-bit Unixes are
+ supported in the code, including 2.9BSD and Tandy Xenix 3.0, but have
+ not been tried since C-Kermit 6.0
+
+ ** C-Kermit 9.0.300 was built successfully on 4.2BSD about 25 years
+ later, in June 2011.
+
+ [ [43]Contents ] [ [44]C-Kermit ] [ [45]Kermit Home ]
+
+2. FILES
+
+ C-Kermit source files begin with the two letters "ck", for example
+ ckutio.c. Filenames are kept short (6.3) for maximum portability and
+ (obviously I hope) do not contain spaces or more than one period. The
+ third character in the name denotes something about the function group
+ and the expected level of portability:
+
+ a General descriptive material and documentation (text)
+ b BOO file encoders and decoders (obsolete)
+ c All platforms with C compilers (*)
+ d Data General AOS/VS
+ e Reserved for "ckermit" files, like ckermit.ini, ckermit2.txt
+ f (reserved)
+ g (reserved)
+ h (reserved)
+ i Commodore Amiga (Intuition)
+ j (unused)
+ k (unused)
+ l Stratus VOS
+ m Macintosh with Mac OS 1-9
+ n (unused)
+ o OS/2 and Microsoft Windows 9x/ME/NT/2000/XP/Vista/etc
+ p Plan 9 from Bell Labs
+ q (reserved)
+ r DEC PDP-11 with RSTS/E (never used, open for reassignment)
+ s Atari ST GEMDOS (last supported in version 5A(189))
+ t DEC PDP-11 with RT-11 (never used, open for reassignment)
+ u Unix-based operating systems (*)
+ v VMS and OpenVMS
+ w Wart (Lex-like preprocessor, platform independent)
+ x (reserved)
+ y (reserved)
+ z (reserved)
+ 0-3 (reserved)
+ 4 IBM AS/400
+ 5-8 (reserved)
+ 9 Microware OS-9
+ _ (underscore) Encryption modules
+
+ (*) In fact there is little distinction between the ckc*.* and cku*.*
+ categories. It would make more sense for all cku*.* modules to be
+ ckc*.* ones, except ckufio.c, ckutio.c, ckucon.c, ckucns.c, and
+ ckupty.c, which truly are specific to Unix. The rest (ckuus*.c,
+ ckucmd.c, etc) are quite portable.
+
+ One hint before proceeding: functions are scattered all over the ckc*.c
+ and cku*.c modules, where function size has begun to take precedence
+ over the desirability of grouping related functions together, the aim
+ being to keep any particular module from growing disproportionately
+ large. The easiest way (in UNIX) to find out in what source file a
+ given function is defined is like this (where the desired function is
+ foo()...):
+
+ grep ^foo\( ck*.c
+
+ This works because the coding convention has been to make function
+ names always start on the left margin with their contents indented, for
+ example:
+
+static char *
+foo(x,y) int x, y; {
+ ...
+}
+
+ Also note the style for bracket placement. This allows bracket-matching
+ text editors (such as EMACS) to help you make sure you know which
+ opening bracket a closing bracket matches, particularly when the
+ opening bracket is above the visible screen, and it also makes it easy
+ to find the end of a function (search for '}' on the left margin).
+
+ Of course EMACS tags work nicely with this format too:
+
+ $ cd kermit-source-directory
+ $ etags ck[cu]*.c
+ $ emacs
+ Esc-X Visit-Tags-Table<CR><CR>
+
+ (but remember that the source file for ckcpro.c is [46]ckcpro.w!)
+
+ Also:
+
+ * Tabs should be set every 8 spaces, as on a VT100.
+ * All lines must no more than 79 characters wide after tab expansion.
+ * Note the distinction between physical tabs (ASCII 9) and the
+ indentation conventions, which are: 4 for block contents, 2 for
+ most other stuff (obviously this is not a portability issue, just
+ style).
+
+ [ [47]Contents ] [ [48]C-Kermit ] [ [49]Kermit Home ]
+
+3. SOURCE CODE PORTABILITY AND STYLE
+
+ C-Kermit was designed in 1985 as a platform-independent replacement for
+ the earlier Unix Kermit. C-Kermit's design was expected to promote
+ portability, and judging from the number of platforms to which it has
+ been adapted since then, the model is effective, if not ideal
+ (obviously if we had it all to do over, we'd change a few things). To
+ answer the oft-repeated question: "Why are there so many #ifdefs?",
+ it's because:
+
+ * Many of them are related to feature selection and program size, and
+ so need to be there anyway.
+ * Those that treat compiler, library, platform, header-file, and
+ similar differences have built up over time as hundreds of people
+ all over the world adapted C-Kermit to their particular
+ environments and sent back their changes. There might be more
+ politically-correct ways to achieve portability, but this one is
+ natural and proven. The basic idea is to introduce changes that can
+ be selected by defining a symbol, which, if not defined, leaves the
+ program exactly as it was before the changes.
+ * Although it might be possible to "clean up" the "#ifdef mess",
+ nobody has access to all the hundreds of platforms served by the
+ #ifdefs to check the results.
+
+ And to answer the second-most-oft-repeated question: "Why don't you
+ just use GNU autoconfig / automake / autowhatever instead of
+ hard-coding all those #ifdefs?" Answers:
+
+ * The GNU tools are not available on all the platforms where C-Kermit
+ must be built and I wouldn't necessarily trust them if they were.
+ * Each platform is a moving target, so the tools themselves would
+ need to updated before Kermit could be updated.
+ * It would only add another layer of complexity to an already complex
+ process.
+ * Conversion at this point would not be practical unless there was a
+ way to test the results on all the hundreds of platforms where
+ C-Kermit is supposed to build.
+
+ When writing code for the system-independent C-Kermit modules, please
+ stick to the following coding conventions to ensure portability to the
+ widest possible variety of C preprocessors, compilers, and linkers, as
+ well as certain network and/or email transports. The same holds true
+ for many of the "system dependent" modules too; particularly the Unix
+ ones, since they must be buildable by a wide variety of compilers and
+ linkers, new and old.
+
+ This list does not purport to be comprehensive, and although some items
+ on it might seem far-fetched, they would not be listed unless I had
+ encountered them somewhere, some time. I wish I had kept better records
+ so I could cite specific platforms and compilers.
+
+ * Try to keep variable and function names unique within 6 characters,
+ especially if they are used across modules, since 6 is the maximum
+ for some old linkers (actually, this goes back to TOPS-10 and -20
+ and other old DEC OS's where C-Kermit never ran anyway; a more
+ realistic maximum is probably somewhere between 8 and 16). We know
+ for certain that VAX C has a 31-character max because it complains
+ -- others might not complain, but just silently truncate, thus
+ folding two or more routines/variables into one.
+ * Keep preprocessor symbols unique within 8 characters; that's the
+ max for some preprocessors (sorry, I can't give a specific example,
+ but in 1988 or thereabouts, I had to change character-set symbols
+ like TC_LATIN1 and TC_LATIN2 to TC_1LATIN and TC_2LATIN because the
+ digits were being truncated and ignored on a platform where I
+ actually had to build C-Kermit 5A; unfortunately I didn't note
+ which platform -- maybe some early Ultrix version?)
+ * Don't create preprocessor symbols, or variable or function names,
+ that start with underscore (_). These are usually reserved for
+ internal use by the compiler and header files.
+ * Don't put #include directives inside functions or { blocks }.
+ * Don't use the #if or #elif preprocessor constructions, only use
+ #ifdef, #ifndef, #define, #undef, and #endif.
+ * Put tokens after #endif in comment brackets, e.g. #endif /* FOO */.
+ * Don't indent preprocessor statements - # must always be first char
+ on line.
+ * Don't put whitespace after # in preprocessor statements.
+ * Don't use #pragma, even within #ifdefs -- it makes some
+ preprocessors give up.
+ * Same goes for #module, #if, etc - #ifdefs do NOT protect them.
+ * Don't use logical operators in preprocessor constructions.
+ * Avoid #ifdefs inside argument list to function calls (I can't
+ remember why this one is here, but probably needn't be; we do this
+ all the time).
+ * Always cast strlen() in expressions to int:
+ if ((int)strlen(foo) < x)...
+ * Avoid typedefs; they might be portable but they are very confusing
+ and there's no way to test for their presence or absence at compile
+ time. Use preprocessor symbols instead if possible; at least you
+ can test their definitions.
+ * Unsigned long is not portable; use a preprocessor symbol (Kermit
+ uses ULONG for this).
+ * Long long is not portable. If you really need it, be creative.
+ * Similarly 1234LL is not portable, nor almost any other constant
+ modifier other than L.
+ * Unsigned char is not portable, use CHAR (a preprocessor symbol
+ defined in the Kermit header files) and always take precautions
+ against character signage (more about this [50]below).
+ * Don't use initializers with automatic arrays or structs: it's not
+ portable.
+ * Don't use big automatic arrays or structs in functions that might
+ be called recursively; some platforms have fixed-size stacks (e.g.
+ Windows 9x: 256K) and recursive functions crash with stack
+ overflow. Even when there is not a compiler limitation, this causes
+ memory to be consumed without bound, and can end up filling swap
+ space.
+ * Don't assume that struct assignment performs a copy, or that it
+ even exists.
+ * Don't use sizeof to get the size of an array; someone might come
+ along later and and change it from static to malloc'd. Always use a
+ symbol to refer to the array's size.
+ * Don't put prototypes for static functions into header files that
+ are used by modules that don't contain that function; the link step
+ can fail with unresolved references (e.g. on AOS/VS).
+ * Avoid the construction *++p (the order of evaluation varies; it
+ shouldn't but at least one compiler had a bug that made me include
+ this item).
+ * Don't use triple assignments, like a = b = c = 0; (or quadruple,
+ etc). Some compilers generate bad code for these, or crash, etc
+ (some version of DEC C as I recall).
+ * Some compilers don't allow structure members to have the same names
+ as other identifiers. Try to give structure members unique names.
+ * Don't assume anything about order of evaluation in boolean
+ expressions, or that they will stop early if a required condition
+ is not true, e.g.:
+ if (i > 0 && p[i-1] == blah)
+
+ can still dump core if i == 0 (hopefully this is not true of any
+ modern compiler, but I would not have said this if it did not
+ actually happen somewhere).
+ * Don't have a switch() statement with no cases (e.g. because of
+ #ifdefs); this is a fatal error in some compilers.
+ * Don't put lots of code in a switch case; move it out to a separate
+ function; some compilers run out of memory when presented with a
+ huge switch() statement -- it's not the number of cases that
+ matters; it's the overall amount of code.
+ * Some compilers might also limit the number of switch() cases, e.g.
+ to 254.
+ * Don't put anything between "switch() {" and "case:" -- switch
+ blocks are not like other blocks.
+ * Don't jump into or out of switches.
+ * Don't make character-string constants longer than about 250 bytes.
+ Longer strings should be broken up into arrays of strings.
+ * Don't write into character-string constants (obviously). Even when
+ you know you are not writing past the end; the compiler or linker
+ might have put them into read-only and/or shared memory, and/or
+ coalesced multiple equal constants so if you change one you change
+ them all.
+ * Don't depend on '\r' being carriage return.
+ * Don't depend on '\n' being linefeed or for that matter any SINGLE
+ character.
+ * Don't depend on '\r' and '\n' being different (e.g. as separate
+ switch() cases).
+ * In other words, don't use \n or \r to stand for specific
+ characters; use \012 and \015 instead.
+ * Don't code for "buzzword 1.0 compliance", unless "buzzword" is K&R
+ and "1.0" is the first edition.
+ * Don't use or depend on anything_t (size_t, pid_t, etc), except
+ time_t, without #ifdef protection (time_t is the only one I've
+ found that is accepted everywhere). This is a tough one because the
+ same function might require (say) a size_t arg on one platform,
+ whereas size_t is unheard of on another; or worse, it might require
+ a totally different data type, like int or long or some other
+ typedef'd thing. It has often proved necessary to define a symbol
+ to stand for the type of a particular argument to a particular
+ library or system function to get around this problem.
+ * Don't use or depend on internationalization ("i18n") features,
+ wchar_t, locales, etc, in portable code; they are not portable.
+ Anyway, locales are not the right model for Kermit's
+ multi-character-set support. Kermit does all character-set
+ conversion itself and does not use any external libraries or
+ functions.
+ * In particular, don't use any library functions that deal with wide
+ characters or Unicode in any form. These are not only nonportable,
+ but a constantly shifting target (e.g. the ones in glibc).
+ * Don't make any assumption about signal handler type. It can be
+ void, int, long, or anything else. Always declare signal handlers
+ as SIGTYP (see definition in ckcdeb.h and augment it if necessary)
+ and always use SIGRETURN at exit points from signal handlers.
+ * Signals should always be re-armed to be used again (this barely
+ scratches the surface -- the differences between BSD/V7 and System
+ V and POSIX signal handling are numerous, and some platforms do not
+ even support signals, alarms, or longjmps correctly or at all --
+ avoid all of this if you can).
+ * On the other hand, don't assume that signals are disarmed after
+ being raised. In some platforms you have to re-arm them, in others
+ they stay armed.
+ * Don't call malloc() and friends from a signal handler; don't do
+ anything but setting integer global variables in a signal handler.
+ * malloc() does not initialize allocated memory -- it never said it
+ did. Don't expect it to be all 0's.
+ * Did You Know: malloc() can succeed and the program can still dump
+ core later when it attempts to use the malloc'd memory? (This
+ happens when allocation is deferred until use and swap space is
+ full.)
+ * memset(), memmove(), and memcpy() are not portable, don't use them
+ without protecting them in ifdefs (we have USE_MEMCPY for this).
+ bzero()/bcopy() too, except we're guaranteed to have
+ bzero()/bcopy() when using the sockets library (not really). See
+ examples in the source.
+ * Don't assume that strncpy() stops on the first null byte -- most
+ versions always copy the number of bytes given in arg 3, padding
+ out with 0's and overwriting whatever was there before. Use
+ C-Kermit ckstrncpy() if you want predictable non-padding behavior,
+ guaranteed NUL-termination, and a useful return code.
+ * DID YOU KNOW.. that some versions of inet_blah() routines return IP
+ addresses in network byte order, while others return them local
+ machine byte order? So passing them to ntohs() or whatever is not
+ always the right thing to do.
+ * Don't use ANSI-format function declarations without #ifdef
+ CK_ANSIC, and always provide an #else for the non-ANSI case.
+ * Use the Kermit _PROTOTYP() macro for declaring function prototypes;
+ it works in both the ANSI and non-ANSI cases.
+ * Don't depend on any other ANSI preprocessor features like "pasting"
+ -- they are often missing or nonoperational.
+ * Don't assume any C++ syntax or semantics.
+ * Don't use // as a comment introducer. C is not C++.
+ * Don't declare a string as "char foo[]" in one module and "extern
+ char * foo" in another, or vice-versa: this causes core dumps.
+ * With compiler makers falling all over themselves trying to outdo
+ each other in ANSI strictness, it has become increasingly necessary
+ to cast EVERYTHING. Especially char vs unsigned char. We need to
+ use unsigned chars if we want to deal with 8-bit character sets,
+ but most character- and string-oriented APIs want (signed) char
+ arguments, so explicit casts are necessary. It would be nice if
+ every compiler had a -funsigned-char option (as gcc does), but they
+ don't.
+ * a[x], where x is an unsigned char, can produce a wild memory
+ reference if x, when promoted to an int, becomes negative. Cast it
+ to (unsigned), even though it ALREADY IS unsigned.
+ * Be careful how you declare functions that have char or long
+ arguments; for ANSI compilers you MUST use ANSI declarations to
+ avoid promotion problems, but you can't use ANSI declarations with
+ non-ANSI compilers. Thus declarations of such functions must be
+ hideously entwined in #ifdefs. Example:
+ int /* Put character in server command buffer */
+ #ifdef CK_ANSIC
+ putsrv(char c)
+ #else
+ putsrv(c) char c;
+ #endif /* CK_ANSIC */
+ /* putsrv */ {
+ *srvptr++ = c;
+ *srvptr = '\0'; /* Make sure buffer is null-terminated */
+ return(0);
+ }
+
+ * Be careful how you return characters from functions that return int
+ values -- "getc-like functions" -- in the ANSI world. Unless you
+ explicitly cast the return value to (unsigned), it is likely to be
+ "promoted" to an int and have its sign extended.
+ * At least one compiler (the one on DEC OSF/1 1.3) treats "/*" and
+ "*/" within string constants as comment begin and end. No amount of
+ #ifdefs will get around this one. You simply can't put these
+ sequences in a string constant, e.g. "/usr/local/doc/*.*".
+ * Avoid putting multiple macro references on a single line, e.g.:
+ putchar(BS); putchar(SP); putchar(BS)
+
+ This overflows the CPP output buffer of more than a few C preprocessors
+ (this happened, for example, with SunOS 4.1 cc, which evidently has a
+ 1K macro expansion buffer).
+
+ C-Kermit needs constant adjustment to new OS and compiler releases.
+ Every new OS release shuffles header files or their contents, or
+ prototypes, or data types, or levels of ANSI strictness, etc. Every
+ time you make an adjustment to remove a new compilation error, BE VERY
+ CAREFUL to #ifdef it on a symbol unique to the new configuration so
+ that the previous configuration (and all other configurations on all
+ other platforms) remain as before.
+
+ Assume nothing. Don't assume header files are where they are supposed
+ to be, that they contain what you think they contain, that they define
+ specific symbols to have certain values -- or define them at all! Don't
+ assume system header files protect themselves against multiple
+ inclusion. Don't assume that particular system or library calls are
+ available, or that the arguments are what you think they are -- order,
+ data type, passed by reference vs value, etc. Be conservative when
+ attempting to write portable code. Avoid all advanced features.
+
+ If you see something that does not make sense, don't assume it's a
+ mistake -- it might be there for a reason, and changing it or removing
+ is likely to cause compilation, linking, or runtime failures sometime,
+ somewhere. Some huge percentage of the code, especially in the
+ platform-dependent modules, is workarounds for compiler, linker, or API
+ bugs.
+
+ But finally... feel free to violate any or all of these rules in
+ platform-specific modules for environments in which the rules are
+ certain not to apply. For example, in VMS-specific code, it is OK to
+ use #if, because VAX C, DEC C, and VMS GCC all support it.
+
+ [ [51]Contents ] [ [52]C-Kermit ] [ [53]Kermit Home ]
+
+3.1. Memory Leaks
+
+ The C language and standard C library are notoriously inadequate and
+ unsafe. Strings are arrays of characters, usually referenced through
+ pointers. There is no native string datatype. Buffers are fixed size,
+ and C provides no runtime bounds checking, thus allowing overwriting of
+ other data or even program code. With the popularization of the
+ Internet, the "buffer exploit" has become a preferred method for
+ hackers to hijack privileged programs; long data strings are fed to a
+ program in hopes that it uses unsafe C library calls such as strcpy()
+ or sprintf() to copy strings into automatic arrays, thus overwriting
+ the call stack, and therefore the routine's return address. When such a
+ hole is discovered, a "string" can be constructed that contains machine
+ code to hijack the program's privileges and penetrate the system.
+
+ This problem is partially addressed by the strn...() routines, which
+ should always be used in preference to their str...() equivalents
+ (except when the copy operation has already been prechecked, or there
+ is a good reason for not using them, e.g. the sometimes undesirable
+ side effect of strncpy() zeroing the remainder of the buffer). The most
+ gaping whole, however, is sprintf(), which performs no length checking
+ on its destination buffer, and is not easy to replace. Although
+ snprintf() routines are starting to appear, they are not yet
+ widespread, and certainly not universal, nor are they especially
+ portable, or even full-featured.
+
+ For these reasons, we have started to build up our own little library
+ of C Library replacements, ckclib.[ch]. These are safe and highly
+ portable primitives for memory management and string manipulation, such
+ as:
+
+ ckstrncpy()
+ Like strncpy but returns a useful value, doesn't zero buffer.
+
+ ckitoa()
+ Opposite of atoi()
+
+ ckltoa()
+ Opposite of atol()
+
+ ckctoa()
+ Returns character as string
+
+ ckmakmsg()
+ Used with ck?to?() as a safe sprintf() replacement for up to 4
+ items
+
+ ckmakxmsg()
+ Like ckmakmsg() but accepts up to 12 items
+
+ More about library functions in [54]Section 4.A.
+
+ [ [55]Contents ] [ [56]C-Kermit ] [ [57]Kermit Home ]
+
+3.2. The "char" vs "unsigned char" Dilemma
+
+ This is one of the most aggravating and vexing characteristics of the C
+ language. By design, chars (and char *'s) are SIGNED. But in the modern
+ era, however, we need to process characters that can have (or include)
+ 8-bit values, as in the ISO Latin-1, IBM CP 850, or UTF-8 character
+ sets, so this data must be treated as unsigned. But some C compilers
+ (such as those based on the Bell UNIX V7 compiler) do not support
+ "unsigned char" as a data type. Therefore we have the macro or typedef
+ CHAR, which we use when we need chars to be unsigned, but which,
+ unfortunately, resolves itself to "char" on those compilers that don't
+ support "unsigned char". AND SO... We have to do a lot of fiddling at
+ runtime to avoid sign extension and so forth.
+
+ Some modern compilers (e.g. IBM, DEC, Microsoft) have options that say
+ "make all chars be unsigned" (e.g. GCC "-funsigned-char") and we use
+ them when they are available. Other compilers don't have this option,
+ and at the same time, are becoming increasingly strict about type
+ mismatches, and spew out torrents of warnings when we use a CHAR where
+ a char is expected, or vice versa. We fix these one by one using casts,
+ and the code becomes increasingly ugly. But there remains a serious
+ problem, namely that certain library and kernel functions have
+ arguments that are declared as signed chars (or pointers to them),
+ whereas our character data is unsigned. Fine, we can can use casts here
+ too -- but who knows what happens inside these routines.
+
+ [ [58]Contents ] [ [59]C-Kermit ] [ [60]Kermit Home ]
+
+4. MODULES
+
+ When C-Kermit is on the far end of a connection, it is said to be in
+ remote mode. When C-Kermit has made a connection to another computer,
+ it is in local mode. (If C-Kermit is "in the middle" of a multihop
+ connection, it is still in local mode.)
+
+ On another axis, C-Kermit can be in any of several major states:
+
+ Command State
+ Reading and writing from the job's controlling terminal or
+ "console". In this mode, all i/o is handled by the Group E
+ conxxx() (console i/o) routines.
+
+ Protocol State
+ Reading and writing from the communications device. In this
+ mode, all i/o is handled by the Group E ttxxx() (terminal i/o)
+ routines.
+
+ Terminal State
+ Reading from the keyboard with conxxx() routines and writing to
+ the communications device with ttxxx() routines AND vice-versa.
+
+ When in local mode, the console and communications device are distinct.
+ During file transfer, Kermit may put up a file-transfer display on the
+ console and sample the console for interruption signals.
+
+ When in remote mode, the console and communications device are the
+ same, and therefore there can be no file-transfer display on the
+ console or interruptions from it (except for "in-band" interruptions
+ such as ^C^C^C).
+
+ [ [61]Contents ] [ [62]C-Kermit ] [ [63]Kermit Home ]
+
+4.A. Group A: Library Functions
+
+ Library functions, strictly portable, can be used by all modules on all
+ platforms: [64]ckclib.h, [65]ckclib.c.
+
+ (To be filled in... For now, see [66]Section 3.1 and the comments in
+ ckclib.c.)
+
+ [ [67]Contents ] [ [68]C-Kermit ] [ [69]Kermit Home ]
+
+4.B. Group B: Kermit File Transfer
+
+ The Kermit protocol kernel. These files, whose names start with "ckc
+ are supposed to be totally portable C, and are expected to compile
+ correctly on any platform with any C compiler. "Portable" does not mean
+ the same as as "ANSI" -- these modules must compile on 10- and 20-year
+ old computers, with C preprocessors, compilers, and/or linkers that
+ have all sorts of restrictions. The Group B modules do not include any
+ header files other than those that come with Kermit itself. They do not
+ contain any library calls except from the standard C library (e.g.
+ printf()). They most certainly do not contain any system calls. Files:
+
+ [70]ckcsym.h
+ For use by C compilers that don't allow -D on the command line.
+
+ [71]ckcasc.h
+ ASCII character symbol definitions.
+
+ [72]ckcsig.h
+ System-independent signal-handling definitions and prototypes.
+
+ [73]ckcdeb.h
+ Originally, debugging definitions. Now this file also contains
+ all definitions and prototypes that are shared by all modules in
+ all groups.
+
+ [74]ckcker.h
+ Kermit protocol symbol definitions.
+
+ [75]ckcxla.h
+ Character-set-related symbol definitions (see next section).
+
+ [76]ckcmai.c
+ The main program. This module contains the declarations of all
+ the protocol-related global variables that are shared among the
+ other modules.
+
+ [77]ckcpro.w
+ The protocol module itself, written in "wart", a lex-like
+ preprocessor that is distributed with Kermit under the name
+ CKWART.C.
+
+ [78]ckcfns.c, [79]ckcfn2.c, [80]ckcfn3.c
+ The protocol support functions used by the protocol module.
+
+ [81]Group B modules may call upon functions from [82]Group E, but not
+ from [83]Group D modules (with the single exception that the main
+ program invokes the user interface, which is in Group D). (This last
+ assertion is really only a conjecture.)
+
+ [ [84]Contents ] [ [85]C-Kermit ] [ [86]Kermit Home ]
+
+4.C. Group C: Character-Set Conversion
+
+ Character set translation tables and functions. Used by the [87]Group
+ B, protocol modules, but may be specific to different computers. (So
+ far, all character character sets supported by C-Kermit are supported
+ in [88]ckuxla.c and [89]ckuxla.h, including Macintosh and IBM character
+ sets). These modules should be completely portable, and not rely on any
+ kind of system or library services.
+
+ [90]ckcxla.h
+ Character-set definitions usable by all versions of C-Kermit.
+
+ ck?xla.h
+ Character-set definitions for computer "?", e.g. [91]ckuxla.h
+ for UNIX, [92]ckmxla.h for Macintosh.
+
+ [93]ck?xla
+ Character-set translation tables and functions for computer "?",
+ For example, CKUXLA.C for UNIX, CKMXLA.C for Macintosh. So far,
+ these are the only two such modules. The UNIX module is used for
+ all versions of C-Kermit except the Macintosh version.
+
+ [94]ckcuni.h
+ Unicode definitions
+
+ [95]ckcuni.c
+ Unicode module
+
+ Here's how to add a new file character set in the original (non-Unicode
+ modules). Assuming it is based on the Roman (Latin) alphabet. Let's
+ call it "Barbarian". First, in ck?xla.h, add a definition for FC_BARBA
+ (8 chars maximum length) and increase MAXFCSETS by 1. Then, in
+ ck?xla.c:
+
+ * Add a barbarian entry into the fcsinfo array.
+ * Add a "barbarian" entry to file character set keyword table,
+ fcstab.
+ * Add a "barbarian" entry to terminal character set keyword table,
+ ttcstab.
+ * Add a translation table from Latin-1 to barbarian: yl1ba[].
+ * Add a translation table from barbarian to Latin-1: ybal1[].
+ * Add a translation function from Barbarian to ASCII: xbaas().
+ * Add a translation function from Barbarian to Latin-1: xbal1().
+ * Add a translation function from Latin-1 to Barbarian: xl1ba().
+ * etc etc for each transfer character set...
+ * Add translation function pointers to the xls and xlr tables.
+
+ Other translations involving Barbarian (e.g. from Barbarian to
+ Latin-Cyrillic) are performed through these tables and functions. See
+ ckuxla.h and ckuxla.c for extensive examples.
+
+ To add a new Transfer Character Set, e.g. Latin Alphabet 9 (for the
+ Euro symbol), again in the "old" character-set modules:
+
+ In ckcxla.h:
+
+ + Add a TC_xxxx definition and increase MAXTCSETS accordingly.
+
+ In ck?xla.h (since any transfer charset is also a file charset):
+
+ + Add an FC_xxxx definition and increase MAXFCSETS accordingly.
+
+ In ck?xla.c:
+
+ + Add a tcsinfo[] entry.
+ + Make a tcstab[] keyword table entry.
+ + Make an fcsinfo[] table entry.
+ + Make an fcstab[] keyword table entry.
+ + Make a tcstab[] keyword table entry.
+ + If necessary, make a langinfo[] table entry.
+ + Make entries in the function pointer arrays.
+ + Provide any needed functions.
+
+ As of C-Kermit 7.0, character sets are also handled in parallel by the
+ new (and very large) Unicode module, ckcuni.[ch]. Eventually we should
+ phase out the old way, described just above, and operate entirely in
+ (and through) Unicode. The advantages are many. The disadvantages are
+ size and performance. To add a character to the Unicode modules:
+
+ In ckcuni.h:
+
+ + (To be filled in...)
+
+ In ckcuni.c:
+
+ + (To be filled in...)
+
+ [ [96]Contents ] [ [97]C-Kermit ] [ [98]Kermit Home ]
+
+4.D. Group D: User Interface
+
+ This is the code that communicates with the user, gets her commands,
+ informs her of the results. It may be command-line oriented,
+ interactive prompting dialog, menus and arrow keys, windows and mice,
+ speech recognition, telepathy, etc. The one provided is command-and
+ prompt, with the ability to read commands from various sources: the
+ console keyboard, a file, or a macro definition. The user interface has
+ three major functions:
+
+ 1. Sets the parameters for the file transfer and then starts it. This
+ is done by setting certain (many) global variables, such as the
+ protocol machine start state, the file specification, file type,
+ communication parameters, packet length, window size, character
+ set, etc.
+ 2. Displays messages on the user's screen during the file transfer,
+ using the screen() function, which is called by the group-1
+ modules.
+ 3. Executes any commands directly that do not require Kermit protocol,
+ such as the CONNECT command, local file management commands,
+ parameter-setting commands, FTP client commands, etc.
+
+ If you plan to embed the [99]Group B, files into a program with a
+ different user interface, your interface must supply an appropriate
+ screen() function, plus a couple related ones like chkint() and
+ intmsg() for handling keyboard (or mouse, etc) interruptions during
+ file transfer. The best way to find out about this is to link all the
+ C-Kermit modules together except the ckuu*.o and ckucon.o modules, and
+ see which missing symbols turn up.
+
+ C-Kermit's character-oriented user interface (as opposed to the
+ Macintosh version's graphical user interface) consists of the following
+ modules. C-Kermit can be built with an interactive command parser, a
+ command-line-option-only parser, a graphical user interface, or any
+ combination, and it can even be built with no user interface at all (in
+ which case it runs as a remote-mode Kermit server).
+
+ [100]ckucmd.h
+ [101]ckucmd.c
+ The command parsing primitives used by the interactive command
+ parser to parse keywords, numbers, filenames, etc, and to give
+ help, complete fields, supply defaults, allow abbreviations and
+ editing, etc. This package is totally independent of Kermit, but
+ does depend on the [102]Group E functions.
+
+ [103]ckuusr.h
+ Definitions of symbols used in Kermit's commands.
+
+ ckuus*.c
+ Kermit's interactive command parser, including the script
+ programming language: [104]ckuusr.c (includes top-level keyword
+ tables); [105]ckuus2.c (HELP command text); [106]ckuus3.c (most
+ of the SET command); [107]ckuus4.c (includes variables and
+ functions); ckuus[567].c (miscellaneous);
+
+ [108]ckuusy.c
+ The command-line-option parser.
+
+ [109]ckuusx.c
+ User interface functions common to both the interactive and
+ command-line parsers.
+
+ [110]ckuver.h
+ Version heralds for different implementations.
+
+ [111]ckuscr.c
+ The (old, uucp-like) SCRIPT command
+
+ [112]ckudia.c
+ The DIAL command. Includes specific knowledge of many types of
+ modems.
+
+ Note that none of the above files is actually Unix-specific. Over time
+ they have proven to be portable among all platforms where C-Kermit is
+ built: Unix, VMS, AOS/VS, Amiga, OS-9, VOS, etc etc. Thus the third
+ letter should more properly be "c", but changing it would be too
+ confusing.
+
+ ck?con.c, ckucns.c
+ The CONNECT command. Terminal connection, and in some cases
+ (Macintosh, Windows) also terminal emulation. NOTE: As of
+ C-Kermit 7.0, there are two different CONNECT modules for UNIX:
+ [113]ckucon.c -- the traditional, portable, fork()-based version
+ -- and [114]ckucns.c, a new version that uses select() rather
+ than forks so it can handle encryption. ckucns.c is the
+ preferred version for Unix; ckucon.c is not likely to keep pace
+ with it in terms of upgrades, etc. However, since select() is
+ not portable to every platform, ckucon.c will be kept
+ indefinitely for those platforms that can't use ckucns.c. NOTE:
+ SunLink X.25 support is available only in ckucon.c.
+
+ ck_*.*, ckuat*.*
+ Modules having to do with authentication and encryption. Since
+ the relaxation of USA export laws, they are included with the
+ general source-code distribution. Secure C-Kermit binaries can
+ be built using special targets in the standard makefile.
+ However, secure prebuilt binaries may not be distributed.
+
+ For other implementations, the files may, and probably do, have
+ different names. For example, the Macintosh graphical user interface
+ filenames start with "ckm". Kermit 95 uses the ckucmd and ckuus*
+ modules, but has its own CONNECT command modules. And so on.
+
+ Here is a brief description of C-Kermit's "user interface interface",
+ from ckuusr.c. It is nowhere near complete; in particular, hundreds of
+ global variables are shared among the many modules. These should, some
+ day, be collected into classes or structures that can be passed around
+ as needed; not only for purity's sake, but also to allow for multiple
+ simultaneous communication sessions and or user interfaces. Our list of
+ things to do is endless, and reorganizing the source is almost always
+ at the bottom.
+
+ The ckuus*.c modules (like many of the ckc*.c modules) depend on the
+ existence of C library features like fopen, fgets, feof, (f)printf,
+ argv/argc, etc. Other functions that are likely to vary among operating
+ systems -- like setting terminal modes or interrupts -- are invoked via
+ calls to functions that are defined in the [115]Group E
+ platform-dependent modules, ck?[ft]io.c. The command line parser
+ processes any arguments found on the command line, as passed to main()
+ via argv/argc. The interactive parser uses the facilities of the cmd
+ package (developed for this program, but, in theory, usable by any
+ program). Any command parser may be substituted for this one. The only
+ requirements for the Kermit command parser are these:
+
+ 1. Set parameters via global variables like duplex, speed, ttname,
+ etc. See [116]ckcmai.c for the declarations and descriptions of
+ these variables.
+ 2. If a command can be executed without the use of Kermit protocol,
+ then execute the command directly and set the sstate (start state)
+ variable to 0. Examples include SET commands, local directory
+ listings, the CONNECT command.
+ 3. If a command requires the Kermit protocol, set the following
+ variables:
+ sstate string data
+ 'x' (enter server mode) (none)
+ 'r' (send a 'get' command) cmarg, cmarg2
+ 'v' (enter receive mode) cmarg2
+ 'g' (send a generic command) cmarg
+ 's' (send files) nfils, cmarg & cmarg2 OR cmlist
+ 'c' (send a remote host command) cmarg
+
+
+ cmlist is an array of pointers to strings.
+ cmarg, cmarg2 are pointers to strings.
+ nfils is an integer (hmmm, probably should be an unsigned long).
+
+ cmarg can be:
+ A filename string (possibly wild), or:
+ a pointer to a prefabricated generic command string, or:
+ a pointer to a host command string.
+
+ cmarg2 is:
+ The name to send a single file under, or:
+ the name under which to store an incoming file; must not
+ be wild.
+ If it's the name for receiving, a null value means to
+ store the file under the name it arrives with.
+
+ cmlist is:
+ A list of nonwild filenames, such as passed via argv.
+
+ nfils is an integer, interpreted as follows:
+ -1: filespec (possibly wild) in cmarg, must be expanded
+ internally.
+ 0: send from stdin (standard input).
+ >0: number of files to send, from cmlist.
+
+ The screen() function is used to update the screen during file
+ transfer. The tlog() function writes to a transaction log (if TLOG is
+ defined). The debug() function writes to a debugging log (if DEBUG is
+ defined). The intmsg() and chkint() functions provide the user i/o for
+ interrupting file transfers.
+
+ [ [117]Contents ] [ [118]C-Kermit ] [ [119]Kermit Home ]
+
+4.E. Group E: Platform-Dependent I/O
+
+ Platform-dependent function definitions. All the Kermit modules,
+ including the command package, call upon these functions, which are
+ designed to provide system-independent primitives for controlling and
+ manipulating devices and files. For Unix, these functions are defined
+ in the files [120]ckufio.c (files), [121]ckutio.c (communications), and
+ [122]ckusig.c (signal handling).
+
+ For VMS, the files are [123]ckvfio.c, ckvtio.c, and [124]ckusig.c (VMS
+ can use the same signal handling routines as Unix). It doesn't really
+ matter what the files are called, except for Kermit distribution
+ purposes (grouping related files together alphabetically), only that
+ each function is provided with the name indicated, observes the same
+ calling and return conventions, and has the same type.
+
+ The Group E modules contain both functions and global variables that
+ are accessed by modules in the other groups. These are now described.
+
+ (By the way, I got this list by linking all the C-Kermit modules
+ together except ckutio and ckufio. These are the symbols that ld
+ reported as undefined. But that was a long time ago, probably circa
+ Version 6.)
+
+4.E.1. Global Variables
+
+ char *DELCMD;
+ Pointer to string containing command for deleting files.
+ Example: char *DELCMD = "rm -f "; (UNIX)
+ Example: char *DELCMD = "delete "; (VMS)
+ Note trailing space. Filename is concatenated to end of this
+ string. NOTE: DELCMD is used only in versions that do not
+ provide their own built-in DELETE command.
+
+ char *DIRCMD;
+ Pointer to string containing command for listing files when a
+ filespec is given.
+ Example: char *DIRCMD = "/bin/ls -l "; (UNIX)
+ Example: char *DIRCMD = "directory "; (VMS)
+ Note trailing space. Filename is concatenated to end of this
+ string. NOTE: DIRCMD is used only in versions that do not
+ provide their own built-in DIRECTORY command.
+
+ char *DIRCM2;
+ Pointer to string containing command for listing files when a
+ filespec is not given. (currently not used, handled in another
+ way.)
+ Example: char *DIRCMD2 = "/bin/ls -ld *";
+ NOTE: DIRCMD2 is used only in versions that do not provide their
+ own built-in DIRECTORY command.
+
+ char *PWDCMD;
+ Pointer to string containing command to display current
+ directory.
+ Example: char *PWDCMD = "pwd ";
+ NOTE: PWDCMD is used only in versions that do not provide their
+ own built-in PWD command.
+
+ char *SPACMD;
+ Pointer to command to display free disk space in current
+ device/directory.
+ Example: char *SPACMD = "df .";
+ NOTE: SPACMD is used only in versions that do not provide their
+ own built-in SPACE command.
+
+ char *SPACM2;
+ Pointer to command to display free disk space in another
+ device/directory.
+ Example: char *SPACM2 = "df ";
+ Note trailing space. Device or directory name is added to this
+ string. NOTE: SPACMD2 is used only in versions that do not
+ provide their own built-in SPACE command.
+
+ char *TYPCMD;
+ Pointer to command for displaying the contents of a file.
+ Example: char *TYPCMD = "cat ";
+ Note trailing space. Device or directory name is added to this
+ string. NOTE: TYPCMD is used only in versions that do not
+ provide their own built-in TYPE command.
+
+ char *WHOCMD;
+ Pointer to command for displaying logged-in users.
+ Example: char *WHOCMD = "who ";
+ Note trailing space. Specific user name may be added to this
+ string.
+
+ int backgrd = 0;
+ Flag for whether program is running in foreground (0) or
+ background (nonzero). Background operation implies that screen
+ output should not be done and that all errors should be fatal.
+
+ int ckxech;
+ Flag for who is to echo console typein:
+ 1: The program (system is not echoing).
+ 0: The OS, front end, terminal, etc (not this program).
+
+ char *ckxsys;
+ Pointer to string that names the computer and operating system.
+ Example: char *ckxsys = " NeXT Mach 1.0";
+ Tells what computer system ckxv applies to. In UNIX Kermit, this
+ variable is also used to print the program herald, and in the
+ SHOW VERSION command.
+
+ char *ckxv;
+ Pointer to version/edit info of ck?tio.c module.
+ Example: char *ckxv = "UNIX Communications Support, 6.0.169, 6
+ Sep 96";
+ Used by SHOW VERSION command.
+
+ char *ckzsys;
+ Like ckxsys, but briefer.
+ Example: char *ckzsys = " 4.3 BSD";
+ Tells what platform ckzv applies to. Used by the SHOW VERSION
+ command.
+
+ char *ckzv;
+ Pointer to version/edit info of ck?fio.c module.
+ Example: char *ckzv = "UNIX File support, 6.0.113, 6 Sep 96";
+ Used by SHOW VERSION command.
+
+ int dfflow;
+ Default flow control. 0 = none, 1 = Xon/Xoff, ... (see FLO_xxx
+ symbols in ckcdeb.h)
+ Set by Group E module. Used by [125]ckcmai.c to initialize flow
+ control variable.
+
+ int dfloc;
+ Default location. 0 = remote, 1 = local. Set by Group E module.
+ Used by ckcmai.c to initialize local variable. Used in various
+ places in the user interface.
+
+ int dfprty;
+ Default parity. 0 = none, 'e' = even, 'o' = odd, 'm' = mark, 's'
+ = space. Set by Group E module. Used by ckcmai.c to initialize
+ parity variable.
+
+ char *dftty;
+ Default communication device. Set by Group E module. Used in
+ many places. This variable should be initialized the symbol
+ CTTNAM, which is defined in ckcdeb.h, e.g. as "/dev/tty" for
+ UNIX, "TT:" for VMS, etc. Example: char *dftty = CTTNAM;
+
+ char *mtchs[];
+ Array of string pointers to filenames that matched the most
+ recent wildcard match, i.e. the most recent call to zxpand().
+ Used (at least) by command parsing package for partial filename
+ completion.
+
+ int tilde_expand;
+ Flag for whether to attempt to expand leading tildes in
+ directory names (used in UNIX only, and then only when the
+ symbol DTILDE is defined.
+
+ int ttnproto;
+ The protocol being used to communicate over a network device.
+ Values are defined in ckcnet.h. Example: NP_TELNET is network
+ protocol "telnet".
+
+ int maxnam;
+ The maximum length for a filename, exclusive of any device or
+ directory information, in the format of the host operating
+ system.
+
+ int maxpath;
+ The maximum length for a fully specified filename, including
+ device designator, directory name, network node name, etc, in
+ the format of the host operating system, and including all
+ punctuation.
+
+ int ttyfd;
+ File descriptor of the communication device. -1 if there is no
+ open or usable connection, including when C-Kermit is in remote
+ mode. Since this is not implemented everywhere, references to it
+ are in #ifdef CK_TTYFD..#endif.
+
+ [ [126]Contents ] [ [127]C-Kermit ] [ [128]Kermit Home ]
+
+4.E.2. Functions
+
+ These are divided into three categories: file-related functions (B.1),
+ communication functions (B.2), and miscellaneous functions (B.3).
+
+4.E.2.1. File-Related Functions
+
+ In most implementations, these are collected together into a module
+ called ck?fio.c, where ? = "u" ([129]ckutio.c for Unix), "v"
+ ([130]ckvtio.c for VMS), [131]etc. To be totally platform-independent,
+ C-Kermit maintains its own file numbers, and provides the functions
+ described in this section to deal with the files associated with them.
+ The file numbers are referred to symbolically, and are defined as
+ follows in ckcker.h:
+
+ #define ZCTERM 0 /* Console terminal */
+ #define ZSTDIO 1 /* Standard input/output */
+ #define ZIFILE 2 /* Current input file for SEND command */
+ #define ZOFILE 3 /* Current output file for RECEIVE command */
+ #define ZDFILE 4 /* Current debugging log file */
+ #define ZTFILE 5 /* Current transaction log file */
+ #define ZPFILE 6 /* Current packet log file */
+ #define ZSFILE 7 /* Current session log file */
+ #define ZSYSFN 8 /* Input from a system function (pipe) */
+ #define ZRFILE 9 /* Local file for READ command */ (NEW)
+ #define ZWFILE 10 /* Local file for WRITE command */ (NEW)
+ #define ZMFILE 11 /* Auxiliary file for internal use */ (NEW)
+ #define ZNFILS 12 /* How many defined file numbers */
+
+ In the descriptions below, fn refers to a filename, and n refers to one
+ of these file numbers. Functions are of type int unless otherwise
+ noted, and are listed mostly alphabetically.
+
+ int
+ chkfn(n) int n;
+ Checks the file number n. Returns:
+ -1: File number n is out of range
+ 0: n is in range, but file is not open
+ 1: n in range and file is open
+
+ int
+ iswild(filspec) char *filespec;
+ Checks if the file specification is "wild", i.e. contains
+ metacharacters or other notations intended to match multiple
+ filenames. Returns:
+ 0: not wild
+ 1: wild.
+
+ int
+ isdir(string) char *string;
+ Checks if the string is the name of an existing directory. The
+ idea is to check whether the string can be "cd'd" to, so in some
+ cases (e.g. DOS) it might also indicate any file structured
+ device, such as a disk drive (like A:). Other nonzero returns
+ indicate system-dependent information; e.g. in VMS
+ isdir("[.FOO]") returns 1 but isdir("FOO.DIR;1") returns 2 to
+ indicate the directory-file name is in a format that needs
+ conversion before it can be combined with a filename. Returns:
+ 0: not a directory (including any kind of error)
+ 1: it is an existing directory
+
+ char *
+ zfcdat(name) char *name;
+ Returns modification (preferably, otherwise creation) date/time
+ of file whose name is given in the argument string. Return value
+ is a pointer to a string of the form yyyymmdd hh:mm:ss, for
+ example 19931231 23:59:59, which represents the local time (no
+ timezone or daylight savings time finagling required). Returns
+ the null string ("") on failure. The text pointed to by the
+ string pointer might be in a static buffer, and so should be
+ copied to a safe place by the caller before any subsequent calls
+ to this function.
+
+ struct zfnfp *
+ zfnqfp(fn, buflen, buf) char * fn; int buflen; char * buf;
+ Given the filename fn, the corresponding fully qualified,
+ absolute filename is placed into the buffer buf, whose length is
+ buflen. On failure returns a NULL pointer. On success returns a
+ pointer to a struct zfnfp containing pointers to the full
+ pathname and to just the filename, and an int giving the length
+ of the full pathname. All references to this function in
+ mainline code must be protected by #ifdef ZFNQFP..#endif,
+ because it is not present in all of the ck*fio.c modules. So if
+ you implement this function in a version that did not have it
+ before, be sure to add #define ZFNQFP in the appropriate spot in
+ ckcdeb.h or in the build-procedure CFLAGS.
+
+ int
+ zcmpfn(s1,s2) char * s2, * s2;
+ Compares two filenames to see if they refer to the same.
+ Internally, the arguments can be converted to fully qualified
+ pathnames, e.g. with zfnqfp(), realpath(), or somesuch. In Unix
+ or other systems where symbolic links exist, the link should be
+ resolved before making the comparison or looking at the inodes.
+ Returns:
+ 0: Files are not identical.
+ 1: Files are identical.
+
+ int
+ zfseek(pos) long pos;
+ Positions the input pointer on the current input file to the
+ given position. The pos argument is 0-based, the offset
+ (distance in bytes) from beginning of the file. Needed for
+ RESEND, PSEND, and other recovery operations. This function is
+ not necessarily possible on all systems, e.g. record-oriented
+ systems. It should only be used on binary files (i.e. files we
+ are sending in binary mode) and stream-oriented file systems.
+ Returns:
+ -1: on failure.
+ 0: On success.
+
+ int
+ zchdir(dirnam) char *dirnam;
+ Changes current or default directory to the one given in dirnam.
+ Returns:
+ 0: On failure.
+ 1: on success.
+
+ long
+ zchki(fn) char *fn;
+ Check to see if file with name fn is a regular, readable,
+ existing file, suitable for Kermit to send -- not a directory,
+ not a symbolic link, etc. Returns:
+ -3: if file exists but is not accessible (e.g. read-protected);
+ -2: if file exists but is not of a readable type (e.g. a
+ directory);
+ -1: on error (e.g. file does not exist, or fn is garbage);
+ >=0: (length of file) if file exists and is readable.
+ Also see isdir(), zgetfs().
+
+ int
+ zchkpid(pid) unsigned long pid;
+ Returns:
+ 1: If the given process ID (e.g. pid in UNIX) is valid and
+ active
+ 0: otherwise.
+
+ long
+ zgetfs(fn) char *fn;
+ Gets the size of the given file, regardless of accessibility.
+ Used for directory listings. Unlike zchki(), should return the
+ size of any kind of file, even a directory. zgetfs() also should
+ serve as a mini "get file info" function that can be used until
+ we design a better one, by also setting some global variables:
+ int zgfs_link = 1/0 = file is (not) a symbolic link.
+ int zgfs_dir = 1/0 = file is (not) a directory.
+ char linkname[] = if zgfs_link != 0, name of file link points
+ to.
+ Returns:
+ -1: on error (e.g. file does not exist, or fn is garbage);
+ >=0: (length of file) if file exists and is readable.
+
+ int
+ zchko(fn) char *fn;
+ Checks to see if a file of the given name can be created.
+ Returns:
+ -1: if file cannot be created, or on any kind of error.
+ 0: if file can be created.
+
+ int
+ zchkspa(fn,len) char *f; long len;
+ Checks to see if there is sufficient space to store the file
+ named fn, which is len bytes long. If you can't write a function
+ to do this, then just make a dummy that always returns 1; higher
+ level code will recover from disk-full errors. The receiving
+ Kermit uses this function to refuse an incoming file based on
+ its size, via the attribute mechanism. Returns:
+ -1: on error.
+ 0: if there is not enough space.
+ 1: if there is enough space.
+
+ int
+ zchin(n,c) int n; int *c;
+ Gets a character from file number n, return it in c (call with
+ &c). Returns:
+ -1: on failure, including EOF.
+ 0: on success with character in c.
+
+ int
+ zchout(n,c) int n; char c;
+ Writes the character c to file number n. Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ zclose(n) int n;
+ Closes file number n. Returns:
+ -1: on error.
+ 1: on success.
+
+ int
+ zdelet(fn) char *name;
+ Attempts to delete (remove, erase) the named file. Returns:
+ -1: on error.
+ 1: if file was deleted successfully.
+
+ char *
+ zgperm(char * f)
+ Returns a pointer to the system-dependent numeric
+ permissions/protection string for file f, or NULL upon failure.
+ Used if CK_PERMS is defined.
+
+ char *
+ ziperm(char * f)
+ Returns a pointer to the system-dependent symbolic
+ permissions/protection string for file f, or NULL upon failure.
+ Used if CK_PERMS is defined. Example: In UNIX zgperm(f) might
+ return "100770", but ziperm() might return "-rwxrwx---". In VMS,
+ zgperm() would return a hexadecimal string, but ziperm() would
+ return something like "(RWED,RWED,RE,)".
+
+ char *
+ zgtdir()
+ Returns a pointer to the name of the current directory, folder,
+ etc, or a NULL pointer if the current directory cannot be
+ determined. If possible, the directory specification should be
+ (a) fully specified, e.g. as a complete pathname, and (b) be
+ suitable for appending a filename. Thus, for example, Unix
+ directory names should end with '/'. VMS directory names should
+ look like DEV:[NAME] (rather than, say, NAME.DIR;1).
+
+ char *
+ zhome()
+ Returns a pointer to a string containing the user's home
+ directory, or NULL upon error. Should be formatted like zgtdir()
+ (q.v.).
+
+ int
+ zinfill()
+ Fill buffer from input file. This function is used by the macro
+ zminchar(), which is defined in ckcker.h. zminchar() manages its
+ own buffer, and calls zinfill() to fill it whenever it becomes
+ empty. It is used only for sending files, and reads characters
+ only from file number ZIFILE. zinfill() returns -1 upon end of
+ file, -2 upon fatal error, and -3 upon timeout (e.g. when
+ reading from a pipe); otherwise it returns the first character
+ from the buffer it just read.
+
+ int
+ zkself()
+ Kills the current job, session, process, etc, logs out,
+ disappears. Used by the Kermit server when it receives a BYE
+ command. On failure, returns -1. On success, does not return at
+ all! This function should not be called until all other steps
+ have been taken to close files, etc.
+
+ VOID
+ zstrip(fn,&fn2) char *fn1, **fn2;
+ Strips device and directory, etc, from file specification fn,
+ leaving only the filename (including "extension" or "filetype"
+ -- the part after the dot). For example DUA0:[PROGRAMS]OOFA.C;3
+ becomes OOFA.C, or /usr/fdc/oofa.c becomes oofa.c. Returns a
+ pointer to result in fn2.
+
+ int
+ zsetperm(char * file, unsigned int code)
+ Set permissions of file to given system-dependent code. 0: On
+ failure.
+ 1: on success.
+
+ int
+ zsetroot(char * dir)
+ Sets the root for the user's file access, like Unix chroot(),
+ but does not require privilege. In Unix, this must be
+ implemented entirely by Kermit's own file access routines.
+ Returns:
+ 1: Success
+ -1: Invalid argument
+ -2:
+ -3: Internal error
+ -4: Access to given directory denied
+ -5: New root not within old root
+
+ int
+ zinroot(char * file)
+ If no root is set (zsetroot()), returns 1.
+ Otherwise, if given file is in the root, returns 1.
+ Otherwise, returns 0.
+
+ VOID
+ zltor(fn,fn2) char *fn1, *fn2;
+ Local-To-Remote filename translation. OBSOLETE: replaced by
+ nzltor() (q.v.). Translates the local filename fn into a format
+ suitable for transmission to an arbitrary type of computer, and
+ copies the result into the buffer pointed to by fn2. Translation
+ may involve (a) stripping the device and/or directory/path name,
+ (b) converting lowercase to uppercase, (c) removing spaces and
+ strange characters, or converting them to some innocuous
+ alphabetic character like X, (d) discarding or converting extra
+ periods (there should not be more than one). Does its best.
+ Returns no value. name2 is a pointer to a buffer, furnished by
+ the caller, into which zltor() writes the resulting name. No
+ length checking is done.
+
+ #ifdef NZLTOR
+ VOID
+ nzltor(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int
+ convert,pathnames,max;
+ Replaces zltor(). This new version handles pathnames and checks
+ length. fn1 and fn2 are as in zltor(). This version is called
+ unconditionally for each file, rather than only when filename
+ conversion is enabled. Pathnames can have the following values:
+
+ PATH_OFF: Pathname, if any, is to be stripped
+ PATH_REL: The relative pathname is to be included
+ PATH_ABS: The full pathname is to be included
+
+ After handling pathnames, conversion is done to the result as in
+ the zltor() description if convert != 0; if relative or absolute
+ pathnames are included, they are converted to UNIX format, i.e.
+ with slash (/) as the directory separator. The max parameter
+ specifies the maximum size of fn2. If convert > 0, the regular
+ conversions are done; if convert < 0, minimal conversions are
+ done (we skip uppercasing the letters, we allow more than one
+ period, etc; this can be used when we know our partner is UNIX
+ or similar).
+
+ #endif /* NZLTOR */
+
+ int
+ nzxpand(fn,flags) char *fn; int flags;
+ Replaces zxpand(), which is obsolete as of C-Kermit 7.0.
+ Call with:
+ fn = Pointer to filename or pattern.
+ flags = option bits:
+ flags & ZX_FILONLY Match regular files
+ flags & ZX_DIRONLY Match directories
+ flags & ZX_RECURSE Descend through directory tree
+ flags & ZX_MATCHDOT Match "dot files"
+ flags & ZX_NOBACKUP Don't match "backup files"
+ flags & ZX_NOLINKS Don't follow symlinks.
+
+ Returns the number of files that match fn, with data structures
+ set up so the first file (if any) will be returned by the next
+ znext() call. If ZX_FILONLY and ZX_DIRONLY are both set, or
+ neither one is set, files and directories are matched. Notes:
+
+ 1. It is essential that the number returned by nzxpand() reflect
+ the actual number of filenames that will be returned by
+ znext() calls. In other words:
+ for (n = nzxpand(string,flags); n > 0; n--) {
+ znext(buf);
+ printf("%s\n", buf);
+ }
+
+ should print all the file names; no more, no less.
+ 2. In UNIX, DOS, OS-9, etc, where directories contain entries for
+ themselves (.) and the superior directory (..), these should
+ NOT be included in the list under any circumstances, including
+ when ZX_MATCHDOT is set.
+ 3. Additional option bits might be added in the future, e.g. for
+ sorting (sort by date/name/size, reverse/ascending, etc).
+ Currently this is done only in higher level code (through a
+ hack in which the nzxpand() exports its filename array, which
+ is not portable because not all OS's can use this mechanism).
+
+ int
+ zmail(addr,fn) char *addr, fn;
+ Send the local, existing file fn as e-mail to the address addr.
+ Returns:
+ 0: on success
+ 2: if mail delivered but temp file can't be deleted
+ -2: if mail can't be delivered
+
+ int
+ zmkdir(path) char *path;
+ The path can be a file specification that might contain
+ directory information, in which the filename is expected to be
+ included, or an unambiguous directory specification (e.g. in
+ UNIX it must end with "/"). This routine attempts to create any
+ directories in the given path that don't already exist. Returns
+ 0 or greater success: no directories needed creation, or else
+ all directories that needed creation were created successfully;
+ the return code is the number of directories that were created.
+ Returns -1 on failure to create any of the needed directories.
+
+ int
+ zrmdir(path) char *path;
+ Attempts to remove the given directory. Returns 0 on success, -1
+ on failure. The detailed semantics are open -- should it fail if
+ the directory contains any files or subdirectories, etc. It is
+ probably best for this routine to behave in whatever manner is
+ customary on the underlying platform; e.g. in UNIX, VMS, DOS,
+ etc, where directories can not be removed unless they are empty.
+
+ VOID
+ znewn(fn,s) char *fn, **s;
+ Transforms the name fn into a filename that is guaranteed to be
+ unique. If the file fn does not exist, then the new name is the
+ same as fn; Otherwise, it's different. this function does its
+ best, returns no value. New name is created in caller's space.
+ Call like this: znewn(old,&new);. The second parameter is a
+ pointer to the new name. This pointer is set by znewn() to point
+ to a static string in its own space, so be sure to the result to
+ a safe place before calling this function again.
+
+ int
+ znext(fn) char *fn;
+ Copies the next file name from a file list created by zxpand()
+ into the string pointed to by fn (see zxpand). If no more files,
+ then the null string is placed there. Returns 0 if there are no
+ more filenames, with 0th element the array pointed to by fn set
+ to NUL. If there is a filename, it is stored in the array
+ pointed to by fn and a positive number is returned. NOTE: This
+ is a change from earlier definitions of this function
+ (pre-1999), which returned the number of files remaining; thus 0
+ was the return value when returning the final file. However, no
+ mainline code ever depended on the return value, so this change
+ should be safe.
+
+ int
+ zopeni(n,fn) int n; char *fn;
+ Opens the file named fn for input as file number n. Returns:
+ 0: on failure.
+ 1: on success.
+
+ int
+ zopeno(n,fn,zz,fcb) int n; char *name; struct zattr *zz; struct
+ filinfo *fcb;
+ Attempts to open the named file for output as file number n. zz
+ is a Kermit file attribute structure as defined in ckcdeb.h,
+ containing various information about the file, including its
+ size, creation date, and so forth. This function should attempt
+ to honor as many of these as possible. fcb is a "file control
+ block" in the traditional sense, defined in ckcdeb.h, containing
+ information relevant to complicated file systems like VMS (RMS),
+ IBM MVS, etc, like blocksize, record length, organization,
+ record format, carriage control, etc. Returns:
+ 0: on failure.
+ 1: on success.
+
+ int
+ zoutdump()
+ Dumps a file output buffer. Used with the macro zmchout()
+ defined in ckcker.h. Used only with file number ZOFILE, i.e. the
+ file that is being received by Kermit during file transfer.
+ Returns:
+ -1: on failure.
+ 0: on success.
+
+ int
+ zprint(p,fn) char *p, *f;
+ Prints the file with name fn on a local printer, with options p.
+ Returns:
+ 0: on success
+ 3: if file sent to printer but can't be deleted
+ -3: if file can't be printed
+
+ int
+ zrename(fn,fn2) char *fn, *fn2;
+ Changes the name of file fn to fn2. If fn2 is the name of an
+ existing directory, or a file-structured device, then file fn is
+ moved to that directory or device, keeping its original name. If
+ fn2 lacks a directory separator when passed to this function, an
+ appropriate one is supplied. Returns:
+ -1: on failure.
+ 0: on success.
+
+ int
+ zcopy(source,dest) char * source, * dest;
+ Copies the source file to the destination. One file only. No
+ wildcards. The destination string may be a filename or a
+ directory name. Returns:
+ 0: on success.
+ <0: on failure:
+ -2: source file is not a regular file.
+ -3: source file not found.
+ -4: permission denied.
+ -5: source and destination are the same file.
+ -6: i/o error.
+ -1: other error.
+
+ char *
+ zlocaltime(char *)
+ Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time. Returns
+ pointer to local date-time string "yyyymmdd hh:mm:ss" on
+ success, NULL on failure.
+
+ VOID
+ zrtol(fn,fn2) char *fn, *fn2;
+ Remote-To-Local filename translation. OBSOLETE: replaced by
+ nzrtol(). Translates a "standard" filename to a local filename.
+ For example, in Unix this function might convert an
+ all-uppercase name to lowercase, but leave lower- or mix-case
+ names alone. Does its best, returns no value. New name is in
+ string pointed to by fn2. No length checking is done.
+
+ #ifdef NZLTOR
+ int
+ nzrtol(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int
+ convert,pathnames,max;
+ Replaces zrtol. Like zrtol but handles pathnames and checks
+ length. See nzltor for detailed description of parameters.
+
+ #endif /* NZLTOR */
+
+ int
+ zsattr(xx) struct zattr *xx;
+ Fills in a Kermit file attribute structure for the file which is
+ to be sent, namely the currently open ZIFILE. Note that this is
+ not a very good design, but we're stuck with it. Callers must
+ ensure that zsattr() is called only on real files, not on pipes,
+ internally generated file-like objects such as server REMOTE
+ command responses, etc. Returns:
+ -1: on failure.
+ 0: on success with the structure filled in.
+ If any string member is null, it should be ignored by the
+ caller.
+ If any numeric member is -1, it should be ignored by the caller.
+
+ int
+ zshcmd(s) char *s;
+ s contains to pointer to a command to be executed by the host
+ computer's shell, command parser, or operating system. If the
+ system allows the user to choose from a variety of command
+ processors (shells), then this function should employ the user's
+ preferred shell. If possible, the user's job (environment,
+ process, etc) should be set up to catch keyboard interruption
+ signals to allow the user to halt the system command and return
+ to Kermit. The command must run in ordinary, unprivileged user
+ mode. If possible, this function should return -1 on failure to
+ start the command, or else it should return 1 if the command
+ succeeded and 0 if it failed.
+
+ int
+ pexitstatus
+ zshcmd() and zsyscmd() should set this to the command's actual
+ exit status code if possible.
+
+ int
+ zsyscmd(s) char *s;
+ s contains to pointer to a command to be executed by the host
+ computer's shell, command parser, or operating system. If the
+ system allows the user to choose from a variety of command
+ processors (shells), then this function should employ the system
+ standard shell (e.g. /bin/sh for Unix), so that the results will
+ always be the same for everybody. If possible, the user's job
+ (environment, process, etc) should be set up to catch keyboard
+ interruption signals to allow the user to halt the system
+ command and return to Kermit. The command must run in ordinary,
+ unprivileged user mode. If possible, this function should return
+ -1 on failure to start the command, or else it should return 1
+ if the command succeeded and 0 if it failed.
+
+ VOID
+ z_exec(s,args) char * s; char * args[];
+ This one executes the command s (which is searched for using the
+ system's normal searching mechanism, such as PATH in UNIX), with
+ the given argument vector, which follows the conventions of UNIX
+ argv[]: the name of the command pointed to by element 0, the
+ first arg by element 1, and so on. A null args[] pointer
+ indicates the end of the argument list. All open files must
+ remain open so the exec'd process can use them. Returns only if
+ unsuccessful.
+
+ int
+ zsinl(n,s,x) int n, x; char *s;
+ Reads a line from file number n. Writes the line into the
+ address s provided by the caller. Writing terminates when
+ newline is read, but with newline discarded. Writing also
+ terminates upon EOF or if length x is exhausted. Returns:
+ -1: on EOF or error.
+ 0: on success.
+
+ int
+ zsout(n,s) int n; char *s;
+ Writes the string s out to file number n. Returns:
+ -1: on failure.
+ 0: on success.
+
+ int
+ zsoutl(n,s) int n; char *s;
+ Writes the string s out to file number n and adds a line
+ (record) terminator (boundary) appropriate for the system and
+ the file format. Returns:
+ -1: on failure.
+ 0: on success.
+
+ int
+ zsoutx(n,s,x) int n, x; char *s;
+ Writes exactly x characters from string s to file number n. If s
+ has fewer than x characters, then the entire string s is
+ written. Returns:
+ -1: on failure.
+ >= 0: on success, the number of characters actually written.
+
+ int
+ zstime(fn,yy,x) char *fn; struct zattr *yy; int x;
+ Sets the creation date (and other attributes) of an existing
+ file, or compares a file's creation date with a given date. Call
+ with:
+
+ fn: pointer to name of existing file.
+ yy: Pointer to a Kermit file attribute structure in which yy->date.val
+ is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00, which
+ is to be used for setting or comparing the file date. Other attributes
+ in the struct can also be set, such as the protection/permission (See
+ [132]Appendix I), when it makes sense (e.g. "yy->lprotect.val" can be
+ set if the remote system ID matches the local one).
+ x: A function code: 0 means to set the file's creation date as given.
+ 1 means compare the date from the yy struct with the file's date.
+
+ Returns:
+ -1: on any kind of error.
+ 0: if x is 0 and the file date was set successfully.
+ 0: if x is 1 and date from attribute structure > file creation
+ date.
+ 1: if x is 1 and date from attribute structure <= file
+ creation date.
+
+ VOID
+ zstrip(name,name2) char *name, **name2;
+ Strips pathname from filename "name". Constructs the resulting
+ string in a static buffer in its own space and returns a pointer
+ to it in name2. Also strips device name, file version numbers,
+ and other "non-name" material.
+
+ int
+ zxcmd(n,s) char *s;
+ Runs a system command so its output can be accessed as if it
+ were file n. The command is run in ordinary, unprivileged user
+ mode.
+ If n is ZSTDIO or ZCTERM, returns -1.
+ If n is ZIFILE or ZRFILE, then Kermit reads from the command,
+ otherwise Kermit writes to the command.
+ Returns 0 on error, 1 on success.
+
+ int
+ zxpand(fn) char *fn;
+ OBSOLETE: Replaced by nzxpand(), q.v.
+
+ #ifdef ZXREWIND
+ int
+ zxrewind()
+ Returns the number of files returned by the most recent
+ nzxpand() call, and resets the list to the beginning so the next
+ znext() call returns the first file. Returns -1 if zxpand has
+ not yet been called. If this function is available, ZXREWIND
+ should be defined; otherwise it should not be referenced.
+
+ #endif /* ZXREWIND */
+
+ int
+ xsystem(cmd) char *cmd;
+ Executes the system command without redirecting any of its i/o,
+ similar (well, identical) to system() in Unix. But before
+ passing the command to the system, xsystem() ensures that all
+ privileges are turned off, so that the system command executes
+ in ordinary unprivileged user mode. If possible, xsystem()
+ returns the return code of the command that was executed.
+
+4.E.2.2. IKSD Variables and Functions
+
+ These must be implemented in any C-Kermit version that is to be
+ installed as an Internet Kermit Service Daemon (IKSD). IKSD is expected
+ to be started by the Internet Daemon (e.g. inetd) with its standard i/o
+ redirected to the incoming connection.
+
+ int ckxanon;
+ Nonzero if anonymous logins allowed.
+
+ extern int inserver;
+ Nonzero if started in IKSD mode.
+
+ extern int isguest;
+ Nonzero if IKSD and user logged in anonymously.
+
+ extern char * homdir;
+ Pointer to user's home directory.
+
+ extern char * anonroot;
+ Pointer to file-system root for anonymous users.
+
+ Existing functions must make "if (inserver && isguest)" checks for
+ actions that would not be legal for guests: zdelete(), zrmdir(),
+ zprint(), zmail(), etc.
+
+ int
+ zvuser(name) char * name;
+ Verifies that user "name" exists and is allowed to log in. If
+ the name is "ftp" or "anonymous" and ckxanon != 0, a guest login
+ is set up. Returns 0 if user not allowed to log in, nonzero if
+ user may log in.
+
+ int
+ zvpass(string) char * string;
+ Verifies password of the user from the most recent zvuser()
+ call. Returns nonzero if password is valid for user, 0 if it
+ isn't. Makes any appropriate system log entries (IKSD logins,
+ failed login attempts, etc). If password is valid, logs the user
+ in as herself (if real user), or sets up restricted anonymous
+ access if user is guest (e.g. changes file-system root to
+ anonroot and sets isguest = 1).
+
+ VOID
+ zsyslog()
+ Begins any desired system logging of an IKSD session.
+
+ VOID
+ zvlogout()
+ Terminates an IKSD session. In most cases this is simply a
+ wrapper for exit() or doexit(), with some system logging added.
+
+4.E.2.3. Privilege Functions
+
+ These functions are used by C-Kermit to adapt itself to operating
+ systems where the program can be made to run in a "privileged" mode,
+ e.g. setuid or setgid in Unix. C-Kermit should NOT read and write files
+ or start subprocesses as a privileged program. This would present a
+ serious threat to system security. The security package has been
+ installed to prevent such security breaches by turning off the
+ program's special privileges at all times except when they are needed.
+
+ In UNIX, the only need Kermit has for privileged status is access to
+ the UUCP lockfile directory, in order to read, create, and destroy
+ lockfiles, and to open communication devices that are normally
+ protected against the user (see the [133]Unix C-Kermit Installation
+ Instructions for discussion). Therefore, privileges should only be
+ enabled for these operations and disabled at all other times. This
+ relieves the programmer of the responsibility of putting expensive and
+ unreliable access checks around every file access and subprocess
+ creation.
+
+ Strictly speaking, these functions are not required in all C-Kermit
+ implementations, because their use (so far, at least) is internal to
+ the Group E modules. However, they should be included in all C-Kermit
+ implementations for operating systems that support the notion of a
+ privileged program (UNIX, RSTS/E, what others?).
+
+ int
+ priv_ini()
+ Determine whether the program is running in privileged status.
+ If so, turn off the privileges, in such a way that they can be
+ turned on again when needed. Called from sysinit() at program
+ startup time. Returns:
+ 0 on success
+ nonzero on failure, in which case the program should halt
+ immediately.
+
+ int
+ priv_on()
+ If the program is not privileged, this function does nothing. If
+ the program is privileged, this function returns it to
+ privileged status. priv_ini() must have been called first.
+ Returns:
+ 0 on success
+ nonzero on failure
+
+ int
+ priv_off()
+ Turns privileges off (if they are on) in such a way that they
+ can be turned back on again. Returns:
+ 0 on success
+ nonzero on failure
+
+ int
+ priv_can()
+ Turns privileges off in such a way that they cannot be turned
+ back on. Returns:
+ 0 on success
+ nonzero on failure
+
+ int
+ priv_chk()
+ Attempts to turns privileges off in such a way that they can be
+ turned on again later. Then checks to make sure that they were
+ really turned off. If they were not really turned off, then they
+ are canceled permanently. Returns:
+ 0 on success
+ nonzero on failure
+
+4.E.2.4. Console-Related Functions
+
+ These relate to the program's "console", or controlling terminal, i.e.
+ the terminal that the user is logged in on and types commands at, or on
+ a PC or workstation, the actual keyboard and screen.
+
+ int
+ conbin(esc) char esc;
+ Puts the console into "binary" mode, so that Kermit's command
+ parser can control echoing and other treatment of characters
+ that the user types. esc is the character that will be used to
+ get Kermit's attention during packet mode; puts this in a global
+ place. Sets the ckxech variable. Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ concb(esc) char esc;
+ Put console in "cbreak" (single-character wakeup) mode. That is,
+ ensure that each console character is available to the program
+ immediately when the user types it. Otherwise just like
+ conbin(). Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ conchk()
+ Returns a number, 0 or greater, the number of characters waiting
+ to be read from the console, i.e. the number of characters that
+ the user has typed that have not been read yet by Kermit.
+
+ long
+ congspd();
+ Returns the speed ("baud rate") of the controlling terminal, if
+ known, otherwise -1L.
+
+ int
+ congks(timo) int timo;
+ Get Keyboard Scancode. Reads a keyboard scan code from the
+ physical console keyboard. If the timo parameter is greater than
+ zero, then times out and returns -2 if no character appears
+ within the given number of seconds. Upon any other kind of
+ error, returns -1. Upon success returns a scan code, which may
+ be any positive integer. For situations where scan codes cannot
+ be read (for example, when an ASCII terminal is used as the
+ job's controlling terminal), this function is identical to
+ coninc(), i.e. it returns an 8-bit character value. congks() is
+ for use with workstations whose keyboards have Alternate,
+ Command, Option, and similar modifier keys, and Function keys
+ that generate codes greater than 255.
+
+ int
+ congm()
+ Console get modes. Gets the current console terminal modes and
+ saves them so that conres() can restore them later. Returns 1 if
+ it got the modes OK, 0 if it did nothing (e.g. because Kermit is
+ not connected with any terminal), -1 on error.
+
+ int
+ coninc(timo) int timo;
+ Console Input Character. Reads a character from the console. If
+ the timo parameter is greater than zero, then coninc() times out
+ and returns -2 if no character appears within the given number
+ of seconds. Upon any other kind of error, returns -1. Upon
+ success, returns the character itself, with a value in the range
+ 0-255 decimal.
+
+ VOID
+ conint(f,s) SIGTYP (*f)(), (*s)();
+ Sets the console to generate an interrupt if the user types a
+ keyboard interrupt character, and to transfer control the
+ signal-handling function f. For systems with job control, s is
+ the address of the function that suspends the job. Sets the
+ global variable "backgrd" to zero if Kermit is running in the
+ foreground, and to nonzero if Kermit is running in the
+ background. See ckcdeb.h for the definition of SIGTYP. No return
+ value.
+
+ VOID
+ connoi()
+ Console no interrupts. Disable keyboard interrupts on the
+ console. No return value.
+
+ int
+ conoc(c) char c;
+ Writes character c to the console terminal. Returns:
+ 0 on failure, 1 on success.
+
+ int
+ conol(s) char *s;
+ Writes string s to the console. Returns -1 on error, 0 or
+ greater on success.
+
+ int
+ conola(s) char *s[]; {
+ Writes an array of strings to the console. Returns -1 on error,
+ 0 or greater on success.
+
+ int
+ conoll(s) char *s;
+ Writes string s to the console, followed by the necessary line
+ termination characters to put the console cursor at the
+ beginning of the next line. Returns -1 on error, 0 or greater on
+ success.
+
+ int
+ conres()
+ Restores the console terminal to the modes obtained by congm().
+ Returns: -1 on error, 0 on success.
+
+ int
+ conxo(x,s) int x; char *s;
+ Write x characters from string s to the console. Returns 0 or
+ greater on success, -1 on error.
+
+ char *
+ conkbg();
+ Returns a pointer to the designator of the console keyboard
+ type. For example, on a PC, this function would return "88",
+ "101", etc. Upon failure, returns a pointer to the empty string.
+
+4.E.2.5. Communications Functions
+
+ The communication device is the device used for terminal emulation and
+ file transfer. It may or may not be the same device as the console, and
+ it may or may not be a terminal (serial-port) device; it could also be
+ a network connection. For brevity, the communication device is referred
+ to here as the "tty". When the communication device is the same as the
+ console device, Kermit is said to be in remote mode. When the two
+ devices are different, Kermit is in local mode.
+
+ int
+ ttchk()
+ Returns the number of characters that have arrived at the
+ communication device but have not yet been read by ttinc(),
+ ttinl(), and friends. If communication input is buffered (and it
+ should be), this is the sum of the number of unread characters
+ in Kermit's buffer PLUS the number of unread characters in the
+ operating system's internal buffer. The call must be
+ nondestructive and nonblocking, and as inexpensive as possible.
+ Returns:
+ 0: or greater on success,
+ 0: in case of internal error,
+ -1: or less when it determines the connection has been broken,
+ or there is no connection.
+
+ That is, a negative return from ttchk() should reliably indicate
+ that there is no usable connection. Furthermore, ttchk() should
+ be callable at any time to see if the connection is open. When
+ the connection is open, every effort must be made to ensure that
+ ttchk returns an accurate number of characters waiting to be
+ read, rather than just 0 (no characters) or 1 (1 or more
+ characters), as would be the case when we use select(). This
+ aspect of ttchk's operation is critical to successful operation
+ of sliding windows and streaming, but "nondestructive buffer
+ peeking" is an obscure operating system feature, and so when it
+ is not available, we have to do it ourselves by managing our own
+ internal buffer at a level below ttinc(), ttinl(), etc, as in
+ the UNIX version (non-FIONREAD case).
+
+ An external global variable, clsondisc, if nonzero, means that
+ if a serial connection drops (carrier on-to-off transition
+ detected by ttchk()), the device should be closed and released
+ automatically.
+
+ int
+ ttclos()
+ Closes the communication device (tty or network). If there were
+ any kind of exclusive access locks connected with the tty, these
+ are released. If the tty has a modem connection, it is hung up.
+ For true tty devices, the original tty device modes are
+ restored. Returns:
+ -1: on failure.
+ 0: on success.
+
+ int
+ ttflui()
+ Flush communications input buffer. If any characters have
+ arrived but have not yet been read, discard these characters. If
+ communications input is buffered by Kermit (and it should be),
+ this function flushes Kermit's buffer as well as the operating
+ system's internal input buffer. Returns:
+ -1: on failure.
+ 0: on success.
+
+ int
+ ttfluo()
+ Flush tty output buffer. If any characters have been written but
+ not actually transmitted (e.g. because the system has been
+ flow-controlled), remove them from the system's output buffer.
+ (Note, this function is not actually used, but it is recommended
+ that all C-Kermit programmers add it for future use, even if it
+ is only a dummy function that returns 0 always.)
+
+ int
+ ttgmdm()
+ Looks for the modem signals CTS, DSR, and CTS, and returns those
+ that are on in as its return value, in a bit mask as described
+ for ttwmdm, in which a bit is on (1) or off (0) according to
+ whether the corresponding signal is on (asserted) or off (not
+ asserted). Return values:
+ -3: Not implemented
+ -2: if the line does not have modem control
+ -1: on error
+ >=0: on success, with bit mask containing the modem signals.
+
+ long
+ ttgspd()
+ Returns the current tty speed in BITS (not CHARACTERS) per
+ second, or -1 if it is not known or if the tty is really a
+ network, or upon any kind of error. On success, the speed
+ returned is the actual number of bits per second, like 1200,
+ 9600, 19200, etc.
+
+ int
+ ttgwsiz()
+ Get terminal window size. Returns -1 on error, 0 if the window
+ size can't be obtained, 1 if the window size has been
+ successfully obtained. Upon success, the external global
+ variables tt_rows and tt_cols are set to the number of screen
+ rows and number of screen columns, respectively. As this
+ function is not implemented in all ck*tio.c modules, calls to it
+ must be wrapped in #ifdef CK_TTGWSIZ..#endif. NOTE: This
+ function must be available to use the TELNET NAWS feature
+ (Negotiate About Window Size) as well as Rlogin.
+
+ int
+ tthang()
+ Hang up the current tty device. For real tty devices, turn off
+ DTR for about 1/3-1/2 second (or other length of time, depending
+ on the system). If the tty is really a network connection, close
+ it. Returns:
+ -1: on failure.
+ 0: if it does not even try to hang up.
+ 1: if it believes it hung up successfully.
+
+ VOID
+ ttimoff()
+ Turns off all pending timer interrupts.
+
+ int
+ ttinc(timo) int timo; (function is old, return codes are new)
+ Reads one character from the communication device. If timo is
+ greater than zero, wait the given number of seconds and then
+ time out if no character arrives, otherwise wait forever for a
+ character. Returns:
+ -3: internal error (e.g. tty modes set wrong)
+ -2: communications disconnect
+ -1: timeout or other error
+ >=0: the character that was read.
+ It is HIGHLY RECOMMENDED that ttinc() be internally buffered so
+ that calls to it are relatively inexpensive. If it is possible
+ to to implement ttinc() as a macro, all the better, for example
+ something like:
+
+ #define ttinc(t) ( (--txbufn >= 0) ? txbuf[ttbufp++] : txbufr(t) )
+
+ (see description of txbufr() below)
+
+ int
+ ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR
+ *dest, eol, start;
+ ttinl() is Kermit's packet reader. Reads a packet from the
+ communications device, or up to max characters, whichever occurs
+ first. A line is a string of characters starting with the start
+ character up to and including the character given in eol or
+ until the length is exhausted, or, if turn != 0, until the line
+ turnaround character (turn) is read. If turn is 0, ttinl()
+ *should* use the packet length field to detect the end, to allow
+ for the possibility that the eol character appears unprefixed in
+ the packet data. (The turnaround character is for half-duplex
+ linemode connections.)
+
+ If timo is greater than zero, ttinl() times out if the eol
+ character is not encountered within the given number of seconds
+ and returns -1.
+
+ The characters that were input are copied into "dest" with their
+ parity bits stripped if parity is not none. The first character
+ copied into dest should be the start character, and the last
+ should be the final character of the packet (the last block
+ check character). ttinl() should also absorb and discard the eol
+ and turn characters, and any other characters that are waiting
+ to be read, up until the next start character, so that
+ subsequent calls to ttchk() will not succeed simply because
+ there are some terminators still sitting in the buffer that
+ ttinl() didn't read. This operation, if performed, MUST NOT
+ BLOCK (so if it can't be performed in a guaranteed nonblocking
+ way, don't do it).
+
+ On success, ttinl() returns the number of characters read.
+ Optionally, ttinl() can sense the parity of incoming packets. If
+ it does this, then it should set the global variable ttprty
+ accordingly. ttinl() should be coded to be as efficient as
+ possible, since it is at the "inner loop" of packet reception.
+ ttinl() returns:
+ -1: Timeout or other possibly correctable error.
+ -2: Interrupted from keyboard.
+ -3: Uncorrectable i/o error -- connection lost, configuration
+ problem, etc.
+ >=0: on success, the number of characters that were actually
+ read and placed in the dest buffer, not counting the trailing
+ null.
+
+ int
+ ttoc(c) char c;
+ Outputs the character c to the communication line. If the
+ operation fails to complete within two seconds, this function
+ returns -1. Otherwise it returns the number of characters
+ actually written to the tty (0 or 1). This function should only
+ be used for interactive, character-mode operations, like
+ terminal connection, script execution, dialer i/o, where the
+ overhead of the signals and alarms does not create a bottleneck.
+ (THIS DESCRIPTION NEEDS IMPROVEMENT -- If the operation fails
+ within a "certain amount of time"... which might be dependent on
+ the communication method, speed, etc. In particular,
+ flow-control deadlocks must be accounted for and broken out of
+ to prevent the program from hanging indefinitely, etc.)
+
+ int
+ ttol(s,n) int n; char *s;
+ Kermit's packet writer. Writes the n characters of the string
+ pointed to to by s. NOTE: It is ttol's responsibility to write
+ ALL of the characters, not just some of them. Returns:
+ -1: on a possibly correctable error (so it can be retried).
+ -3: on a fatal error, e.g. connection lost.
+ >=0: on success, the actual number of characters written (the
+ specific number is not actually used for anything).
+
+ int
+ ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem,
+ timo;
+ Opens a tty device, if it is not already open. ttopen must check
+ to make sure the SAME device is not already open; if it is,
+ ttopen returns successfully without doing anything. If a
+ DIFFERENT device is currently open, ttopen() must call ttclos()
+ to close it before opening the new one.
+
+ Parameters:
+
+ ttname:
+ character string - device name or network host name.
+
+ lcl:
+ If called with lcl < 0, sets value of lcl as
+ follows:
+ 0: the terminal named by ttname is the job's
+ controlling terminal.
+ 1: the terminal named by ttname is not the job's
+ controlling terminal.
+ If the device is already open, or if the requested
+ device can't be opened, then lcl remains (and is
+ returned as) -1.
+
+ modem:
+ Less than zero: this is the negative of the network
+ type, and ttname is a network host name. Network
+ types (from [134]ckcnet.h:
+
+ NET_TCPB 1 TCP/IP Berkeley (socket) (implemented in [135]ckutio.c)
+ NET_TCPA 2 TCP/IP AT&T (streams) (not yet implemented)
+ NET_DEC 3 DECnet (not yet implemented)
+
+ Zero or greater: ttname is a terminal device name.
+ Zero means a direct connection (don't use modem
+ signals). Positive means use modem signals depending
+ on the current setting of ttcarr (see ttscarr()).
+
+ timo:
+ > 0: number of seconds to wait for open() to return
+ before timing out.
+ <=0: no timer, wait forever (e.g. for incoming
+ call).
+ For real tty devices, ttopen() attempts to gain
+ exclusive access to the tty device, for example in
+ UNIX by creating a "lockfile" (in other operating
+ systems, like VMS, exclusive access probably
+ requires no special action).
+
+ Side effects:
+ Copies its arguments and the tty file descriptor to global
+ variables that are available to the other tty-related
+ functions, with the lcl value altered as described above.
+ Gets all parameters and settings associated with the line
+ and puts them in a global area, so that they can be
+ restored by ttres(), e.g. when the device is closed.
+
+ Returns:
+ 0: on success
+ -5: if device is in use
+ -4: if access to device is denied
+ -3: if access to lock mechanism denied
+ -2: upon timeout waiting for device to open
+ -1: on other error
+
+ int
+ ttpkt(speed,flow,parity) long speed; int flow, parity;
+ Puts the currently open tty device into the appropriate modes
+ for transmitting and receiving Kermit packets.
+
+ Arguments:
+
+ speed:
+ if speed > -1, and the device is a true tty device,
+ and Kermit is in local mode, ttpkt also sets the
+ speed.
+
+ flow:
+ if in the range 0-3, ttpkt selects the corresponding
+ type of flow control. Currently 0 is defined as no
+ flow control, 1 is Xon/Xoff, and no other types are
+ defined. If (and this is a horrible hack, but it
+ goes back many years and will be hard to eradicate)
+ flow is 4, then the appropriate tty modes are set
+ for modem dialing, a special case in which we talk
+ to a modem-controlled line without requiring
+ carrier. If flow is 5, then we require carrier.
+
+ parity:
+ This is simply copied into a global variable so that
+ other functions (like ttinl, ttinc, etc) can use it.
+
+ Side effects:
+ Copies its arguments to global variables, flushes the
+ terminal device input buffer.
+
+ Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ ttsetflow(int)
+ Enables the given type of flow control on the open serial
+ communications device immediately. Arguments are the FLO_xxx
+ values from ckcdeb.h, except FLO_DIAL, FLO_DIAX, or FLO_AUTO,
+ which are not actual flow-control types. Returns 0 on success,
+ -1 on failure.
+
+ #ifdef TTSPDLIST
+ long *
+ ttspdlist()
+ Returns a pointer to an array of longs, or NULL on failure. On
+ success, element 0 of the array contains number, n, indicating
+ how many follow. Elements 1-n are serial speeds, expressed in
+ bits per second, that are legal on this platform. The user
+ interface may use this list to construct a menu, keyword table,
+ etc.
+
+ #endif /* TTSPDLIST */
+
+ int
+ ttres()
+ Restores the tty device to the modes and settings that were in
+ effect at the time it was opened (see ttopen). Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ ttruncmd(string) char * string;
+ Runs the given command on the local system, but redirects its
+ input and output to the communication (SET LINE, SET PORT, or
+ SET HOST) device. Returns:
+ 0: on failure.
+ 1: on success.
+
+ int
+ ttscarr(carrier) int carrier;
+ Copies its argument to a variable that is global to the other
+ tty-related functions, and then returns it. The values for
+ carrier are defined in ckcdeb.h: CAR_ON, CAR_OFF, CAR_AUTO.
+ ttopen(), ttpkt(), and ttvt() use this variable when deciding
+ how to open the tty device and what modes to select. The
+ meanings are these:
+
+ CAR_OFF: Ignore carrier at all times.
+ CAR_ON: Require carrier at all times, except when dialing. This means,
+ for example, that ttopen() could hang forever waiting for carrier if it
+ is not present.
+ CAR_AUTO: If the modem type is zero (i.e. the connection is direct),
+ this is the same as CAR_OFF. If the modem type is positive, then heed
+ carrier during CONNECT (ttvt mode), but ignore it at other times
+ (packet mode, during SET LINE, etc). Compatible with pre-5A versions of
+ C-Kermit. This should be the default carrier mode.
+
+ Kermit's DIAL command ignores the carrier setting, but ttopen(),
+ ttvt(), and ttpkt() all honor the carrier option in effect at
+ the time they are called. None of this applies to remote mode
+ (the tty device is the job's controlling terminal) or to network
+ host connections (modem type is negative).
+
+ int
+ ttsndb()
+ Sends a BREAK signal on the tty device. On a real tty device,
+ send a real BREAK lasting approximately 275 milliseconds. If
+ this is not possible, simulate a BREAK by (for example) dropping
+ down some very low baud rate, like 50, and sending a bunch of
+ null characters. On a network connection, do the appropriate
+ network protocol for BREAK. Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ ttsndlb()
+ Like ttsndb(), but sends a "Long BREAK" (approx 1.5 seconds).
+ For network connections, it is identical to ttsndb(). Currently,
+ this function is used only if CK_LBRK is defined (as it is for
+ UNIX and VMS).
+
+ int
+ ttsspd(cps) int cps;
+ For serial devices only, set the device transmission speed to
+ (note carefully) TEN TIMES the argument. The argument is in
+ characters per second, but transmission speeds are in bits per
+ second. cps are used rather than bps because high speeds like
+ 38400 are not expressible in a 16-bit int but longs cannot be
+ used because keyword-table values are ints and not longs. If the
+ argument is 7, then the bps is 75, not 70. If the argument is
+ 888, this is a special code for 75/1200 split-speed operation
+ (75 bps out, 1200 bps in). Returns:
+ -1: on error, meaning the requested speed is not valid or
+ available.
+ >=0: on success (don't try to use this value for anything).
+
+ int
+ ttvt(speed,flow) long speed; int flow;
+ Puts the currently open tty device into the appropriate modes
+ for terminal emulation. The arguments are interpreted as in
+ ttpkt(). Side effects: ttvt() stores its arguments in global
+ variables, and sets a flag that it has been called so that
+ subsequent calls can be ignored so long as the arguments are the
+ same as in the last effective call. Other functions, such as
+ ttopen(), ttclose(), ttres(), ttvt(), etc, that change the tty
+ device in any way must unset this flag. In UNIX Kermit, this
+ flag is called tvtflg.
+
+ int
+ ttwmdm(mdmsig,timo) int mdmsig, timo;
+ Waits up to timo seconds for all of the given modem signals to
+ appear. mdmsig is a bit mask, in which a bit is on (1) or off
+ (0) according to whether the corresponding signal is to be
+ waited for. These symbols are defined in ckcdeb.h:
+ BM_CTS (bit 0) means wait for Clear To Send
+ BM_DSR (bit 1) means wait for Data Set Ready
+ BM_DCD (bit 2) means wait for Carrier Detect
+ Returns:
+ -3: Not implemented.
+ -2: This line does not have modem control.
+ -1: Timeout: time limit exceeded before all signals were
+ detected.
+ 1: Success.
+
+ int
+ ttxin(n,buf) int n; CHAR *buf;
+ Reads x characters from the tty device into the specified buf,
+ stripping parity if parity is not none. This call waits forever,
+ there is no timeout. This function is designed to be called only
+ when you know that at least x characters are waiting to be read
+ (as determined, for example, by ttchk()). This function should
+ use the same buffer as ttinc().
+
+ int
+ txbufr(timo) int timo;
+ Reads characters into the internal communications input buffer.
+ timo is a timeout interval, in seconds. 0 means no timeout, wait
+ forever. Called by ttinc() (and possibly ttxin() and ttinl())
+ when the communications input buffer is empty. The buffer should
+ be called ttxbuf[], its length is defined by the symbol TXBUFL.
+ The global variable txbufn is the number of characters available
+ to be read from ttxbuf[], and txbufp is the index of the next
+ character to be read. Should not be called if txbufn > 0, in
+ which case the buffer does not need refilling. This routine
+ returns:
+ -2: Communications disconnect
+ -1: Timeout
+ >=0: A character (0 - 255) On success, the first character that
+ was read, with the variables txbufn and txbufp set appropriately
+ for any remaining characters.
+ NOTE: Currently this routine is used internally only by the UNIX
+ and VMS versions. The aim is to make it available to all
+ versions so there is one single coherent and efficient way of
+ reading from the communications device or network.
+
+4.E.2.6. Miscellaneous system-dependent functions
+
+ VOID
+ ztime(s) char **s;
+ Returns a pointer, s, to the current date-and-time string in s.
+ This string must be in the fixed-field format associated with
+ the C runtime asctime() function, like: "Sun Sep 16 13:23:45
+ 1973\n" so that callers of this function can extract the
+ different fields. The pointer value is filled in by ztime, and
+ the data it points to is not safe, so should be copied to a safe
+ place before use. ztime() has no return value. As a side effect,
+ this routine can also fill in the following two external
+ variables (which must be defined in the system-dependent modules
+ for each platform):
+ long ztusec: Fraction of seconds of clock time, microseconds.
+ long ztmsec: Fraction of seconds of clock time, milliseconds.
+ If these variables are not set by zstime(), they remain at their
+ initial value of -1L.
+
+ int
+ gtimer()
+ Returns the current value of the elapsed time counter in seconds
+ (see rtimer), or 0 on any kind of error.
+
+ #ifdef GFTIMER
+ CKFLOAT
+ gftimer()
+ Returns the current value of the elapsed time counter in
+ seconds, as a floating point number, capable of representing not
+ only whole seconds, but also the fractional part, to the
+ millisecond or microsecond level, whatever precision is
+ available. Requires a function to get times at subsecond
+ precision, as well as floating-point support. That's why it's
+ #ifdef'd.
+
+ #endif /* GFTIMER */
+
+ int
+ msleep(m) int m;
+ Sleeps (pauses, does nothing) for m milliseconds (a millisecond
+ is one thousandth of a second). Returns:
+ -1: on failure.
+ 0: on success.
+
+ VOID
+ rtimer()
+ Sets the elapsed time counter to zero. If you want to time how
+ long an operation takes, call rtimer() when it starts and gtimer
+ when it ends. rtimer() has no return value.
+
+ #ifdef GFTIMER
+ VOID
+ rftimer()
+ Sets the elapsed time counter to zero. If you want to time how
+ long an operation takes, call rftimer() when it starts and
+ gftimer when it ends. rftimer() has no return value. Note:
+ rftimer() is to be used with gftimer() and rtimer() is to be
+ used with gtimer(). See the rftimer() description.
+
+ #endif /* GFTIMER */
+
+ int
+ sysinit()
+ Does whatever needs doing upon program start. In particular, if
+ the program is running in any kind of privileged mode, turns off
+ the privileges (see priv_ini()). Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ syscleanup()
+ Does whatever needs doing upon program exit. Returns:
+ -1: on error.
+ 0: on success.
+
+ int
+ psuspend()
+ Suspends the Kermit process, puts it in the background so it can
+ be continued ("foregrounded") later. Returns:
+ -1: if this function is not supported.
+ 0: on success.
+
+ [ [136]Contents ] [ [137]C-Kermit ] [ [138]Kermit Home ]
+
+4.F. Group F: Network Support
+
+ As of version 5A, C-Kermit includes support for several networks.
+ Originally, this was just worked into the ttopen(), ttclos(), ttinc(),
+ ttinl(), and similar routines in [139]ckutio.c. But this made it
+ impossible to share this code with non-UNIX versions, like VMS, AOS/VS,
+ OS/2, etc. So as of edit 168, network code has been separated out into
+ its own module and header file, ckcnet.c and ckcnet.h:
+
+ [140]ckcnet.h: Network-related symbol definitions.
+ [141]ckcnet.c: Network i/o (TCP/IP, X.25, etc), shared by most
+ platforms.
+ [142]cklnet.c: Network i/o (TCP/IP, X.25, etc) specific to Stratus
+ VOS.
+
+ The routines and variables in these modules fall into two categories:
+
+ 1. Support for specific network packages like SunLink X.25 and TGV
+ MultiNet, and:
+ 2. support for specific network virtual terminal protocols like CCITT
+ X.3 and TCP/IP Telnet.
+
+ Category (1) functions are analogs to the tt*() functions, and have
+ names like netopen, netclos, nettinc, etc. Group A-D modules do not
+ (and must not) know anything about these functions -- they continue to
+ call the old Group E functions (ttopen, ttinc, etc). Category (2)
+ functions are protocol specific and have names prefixed by a protocol
+ identifier, like tn for telnet x25 for X.25.
+
+ ckcnet.h contains prototypes for all these functions, as well as symbol
+ definitions for network types, protocols, and network- and protocol-
+ specific symbols, as well as #includes for the header files necessary
+ for each network and protocol.
+
+ The following functions are to be provided for networks that do not use
+ normal system i/o (open, read, write, close):
+
+ int
+ netopen()
+ To be called from within ttopen() when a network connection is
+ requested. Calling conventions and purpose same as Group E
+ ttopen().
+
+ int
+ netclos()
+ To be called from within ttclos() when a network connection is
+ being closed. Calling conventions and purpose same as Group E
+ ttclos().
+
+ int
+ nettchk()
+ To be called from within ttchk(). Calling conventions and
+ purpose same as Group E ttchk().
+
+ int
+ netflui()
+ To be called from within ttflui(). Calling conventions and
+ purpose same as Group E ttflui().
+
+ int
+ netbreak()
+ To send a network break (attention) signal. Calling conventions
+ and purpose same as Group E ttsndbrk().
+
+ int
+ netinc()
+ To get a character from the network. Calling conventions same as
+ Group E ttsndbrk().
+
+ int
+ nettoc()
+ Send a "character" (byte) to the network. Calling conventions
+ same as Group E ttoc().
+
+ int
+ nettol()
+ Send a "line" (sequence of bytes) to the network. Calling
+ conventions same as Group E ttol().
+
+ Conceivably, some systems support network connections simply by letting
+ you open a device of a certain name and letting you do i/o to it.
+ Others (like the Berkeley sockets TCP/IP library on UNIX) require you
+ to open the connection in a special way, but then do normal i/o (read,
+ write). In such a case, you would use netopen(), but you would not use
+ nettinc, nettoc, etc.
+
+ VMS TCP/IP products have their own set of functions for all network
+ operations, so in that case the full range of netxxx() functions is
+ used.
+
+ The technique is to put a test in each corresponding ttxxx() function
+ to see if a network connection is active (or is being requested), test
+ for which kind of network it is, and if necessary route the call to the
+ corresponding netxxx() function. The netxxx() function must also
+ contain code to test for the network type, which is available via the
+ global variable ttnet.
+
+ [ [143]Contents ] [ [144]C-Kermit ] [ [145]Kermit Home ]
+
+4.F.1. Telnet Protocol
+
+ (This section needs a great deal of updating...)
+
+ As of edit 195, Telnet protocol is split out into its own files, since
+ it can be implemented in remote mode, which does not have a network
+ connection:
+
+ [146]ckctel.h: Telnet protocol symbol definitions.
+ [147]ckctel.c: Telnet protocol.
+
+ The Telnet protocol is supported by the following variables and
+ routines:
+
+ int tn_init
+ Nonzero if telnet protocol initialized, zero otherwise.
+
+ int
+ tn_init()
+ Initialize the telnet protocol (send initial options).
+
+ int
+ tn_sopt()
+ Send a telnet option.
+
+ int
+ tn_doop()
+ Receive and act on a telnet option from the remote.
+
+ int
+ tn_sttyp()
+ Send terminal type using telnet protocol.
+
+4.F.2. FTP Protocol
+
+ (To be filled in...) See the [148]source file
+
+4.F.3. HTTP Protocol
+
+ (To be filled in...)
+
+4.F.4. X.25 Networks
+
+ These routines were written SunLink X.25 and have since been adapted to
+ at least on one other: IBM AIXLink/X.25.
+
+ int
+ x25diag()
+ Reads and prints X.25 diagnostics
+
+ int
+ x25oobh()
+ X.25 out of band signal handler
+
+ int
+ x25intr()
+ Sends X.25 interrupt packet
+
+ int
+ x25reset()
+ Resets X.25 virtual circuit
+
+ int
+ x25clear()
+ Clear X.25 virtual circuit
+
+ int
+ x25stat()
+ X.25 status
+
+ int
+ setqbit()
+ Sets X.25 Q-bit
+
+ int
+ resetqbit()
+ Resets X.25 Q-bit
+
+ int
+ x25xin()
+ Reads n characters from X.25 circuit.
+
+ int
+ x25inl()
+ Read a Kermit packet from X.25 circuit.
+
+ [ [149]Contents ] [ [150]C-Kermit ] [ [151]Kermit Home ]
+
+4.F.5. Adding New Network Types
+
+ Example: Adding support for IBM X.25 and Hewlett Packard X.25. First,
+ add new network type symbols for each one. There are already some
+ network types defined for other X.25 packages:
+
+ NET_SX25 is the network-type ID for SunLink X.25.
+ NET_VX25 is the network-type ID for VOS X.25.
+
+ So first you should new symbols for the new network types, giving them
+ the next numbers in the sequence, e.g.:
+
+#define NET_HX25 11 /* Hewlett-Packard X.25 */
+#define NET_IX25 12 /* IBM X.25 */
+
+ This is in ckcnet.h.
+
+ Then we need symbols to say that we are actually compiling in the code
+ for these platforms. These would be defined on the cc command line:
+
+ -DIBMX25 (for IBM)
+ -DHPX25 (for HP)
+
+ So we can build C-Kermit versions for AIX and HP-UX both with and
+ without X.25 support (since not all AIX and IBM systems have the needed
+ libraries, and so an executable that was linked with them might no
+ load).
+
+ Then in ckcnet.h:
+
+#ifdef IBMX25
+#define ANYX25
+#endif /* IBMX25 */
+
+#ifdef HPX25
+#define ANYX25
+#endif /* HPX25 */
+
+ And then use ANYX25 for code that is common to all of them, and IBMX25
+ or HPX25 for code specific to IBM or HP.
+
+ It might also happen that some code can be shared between two or more
+ of these, but not the others. Suppose, for example, that you write code
+ that applies to both IBM and HP, but not Sun or VOS X.25. Then you add
+ the following definition to ckcnet.h:
+
+#ifndef HPORIBMX25
+#ifdef HPX25
+#define HPORIBMX25
+#else
+#ifdef IBMX25
+#define HPORIBMX25
+#endif /* IBMX25 */
+#endif /* HPX25 */
+#endif /* HPORIBMX25 */
+
+ You can NOT use constructions like "#if defined (HPX25 || IBMX25)";
+ they are not portable.
+
+ [ [152]Contents ] [ [153]C-Kermit ] [ [154]Kermit Home ]
+
+4.G. Group G: Formatted Screen Support
+
+ So far, this is used only for the fullscreen local-mode file transfer
+ display. In the future, it might be extended to other uses. The
+ fullscreen display code is in and around the routine screenc() in
+ [155]ckuusx.c.
+
+ In the UNIX version, we use the curses library, plus one call from the
+ termcap library. In other versions (OS/2, VMS, etc) we insert dummy
+ routines that have the same names as curses routines. So far, there are
+ two methods for simulating curses routines:
+
+ 1. In VMS, we use the Screen Management Library (SMG), and insert
+ stubs to convert curses calls into SMG calls.
+ 2. In OS/2, we use the MYCURSES code, in which the stub routines
+ actually emit the appropriate escape sequences themselves.
+
+ Here are the stub routines:
+
+ int
+ tgetent(char *buf, char *term)
+ Arguments are ignored. Returns 1 if the user has a supported
+ terminal type, 0 otherwise. Sets a global variable (for example,
+ "isvt52" or "isdasher") to indicate the terminal type.
+
+ VOID
+ move(int row, int col)
+ Sends the escape sequence to position the cursor at the
+ indicated row and column. The numbers are 0-based, e.g. the home
+ position is 0,0.
+
+ int
+ clear()
+ Sends the escape sequence to clear the screen.
+
+ int
+ clrtoeol()
+ Sends the escape sequence to clear from the current cursor
+ position to the end of the line.
+
+ In the MYCURSES case, code must be added to each of the last three
+ routines to emit the appropriate escape sequences for a new terminal
+ type.
+
+ clearok(curscr), wrefresh()
+ In real curses, these two calls are required to refresh the
+ screen, for example after it was fractured by a broadcast
+ message. These are useful only if the underlying screen
+ management service keeps a copy of the entire screen, as curses
+ and SMG do. C-Kermit does not do this itself.
+
+ [ [156]Contents ] [ [157]C-Kermit ] [ [158]Kermit Home ]
+
+4.H. Group H: Pseudoterminal Support
+
+ (To be filled in...) But see: [159]these comments, and the source files
+ [160]ckupty.h and [161]ckupty.c.
+
+4.I. Group I: Security
+
+ (To be filled in...) Meanwhile, see [162]security.html.
+
+ [ [163]Contents ] [ [164]C-Kermit ] [ [165]Kermit Home ]
+
+APPENDIX I. FILE PERMISSIONS
+
+I.1. Format of System-Dependent File Permissions in A-Packets
+
+ The format of this field (the "," attribute) is interpreted according
+ to the System ID ("." Attribute).
+
+ For UNIX (System ID = U1), it's the familiar 3-digit octal number, the
+ low-order 9 bits of the filemode: Owner, Group, World, e.g. 660 =
+ read/write access for owner and group, none for world, recorded as a
+ 3-digit octal string. High-order UNIX permission bits are not
+ transmitted.
+
+ For VMS (System ID = D7), it's a 4-digit hex string, representing the
+ 16-bit file protection WGOS fields (World,Group,Owner,System), in that
+ order (which is the reverse of how they're shown in a directory
+ listing); in each field, Bit 0 = Read, 1 = Write, 2 = Execute, 3 =
+ Delete. A bit value of 0 means permission is granted, 1 means
+ permission is denied. Sample:
+
+ r-01-00-^A/!FWERMIT.EXE'"
+ s-01-00-^AE!Y/amd/watsun/w/fdc/new/wermit.exe.DV
+ r-02-01-^A]"A."D7""B8#119980101 18:14:05!#8531&872960,$A20B-!7(#512@ #.Y
+ s-02-01-^A%"Y.5!
+
+ A VMS directory listing shows the file's protection as (E,RWED,RED,RE)
+ which really means (S=E,O=RWED,G=RED,W=RE), which is reverse order from
+ the internal storage, so (RE,RED,RWED,E). Now translate each letter to
+ its corresponding bit:
+
+ RE=0101, RED=1101, RWED=1111, E=0010
+
+ Now reverse the bits:
+
+ RE=1010, RED=0010, RWED=0000, E=1101
+
+ This gives the 16-bit quantity:
+
+ 1010001000001101
+
+ This is the internal representation of the VMS file permission; in hex:
+
+ A20B
+
+ as shown in the sample packet above.
+
+ The VMS format probably would also apply to RSX or any other FILES-11
+ system.
+
+I.2. Handling of Generic Protection
+
+ To be used when the two systems are different (and/or do not recognize
+ or understand each other's local protection codes).
+
+ First of all, the book is wrong. This should not be the World
+ protection, but the Owner protection. The other fields should be set
+ according to system defaults (e.g. UNIX umask, VMS default protection,
+ etc), except that no non-Owner field should give more permissions than
+ the Owner field.
+
+ [ [166]Top ] [ [167]Contents ] [ [168]C-Kermit Home ] [ [169]Kermit
+ Home ]
+ __________________________________________________________________
+
+
+ C-Kermit Program Logic Manual / [170]The Kermit Project /
+ [171]kermit@columbia.edu / 30 June 2011
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/ckfaq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/
+ 12. http://www.columbia.edu/kermit/ckcplm.html
+ 13. http://www.columbia.edu/kermit/ckcplm.html#x1
+ 14. http://www.columbia.edu/kermit/ckcplm.html#x2
+ 15. http://www.columbia.edu/kermit/ckcplm.html#x3
+ 16. http://www.columbia.edu/kermit/ckcplm.html#x4
+ 17. http://www.columbia.edu/kermit/ckcplm.html#x4.A
+ 18. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+ 19. http://www.columbia.edu/kermit/ckcplm.html#x4.C
+ 20. http://www.columbia.edu/kermit/ckcplm.html#x4.D
+ 21. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+ 22. http://www.columbia.edu/kermit/ckcplm.html#x4.F
+ 23. http://www.columbia.edu/kermit/ckcplm.html#x4.G
+ 24. http://www.columbia.edu/kermit/ckcplm.html#x4.H
+ 25. http://www.columbia.edu/kermit/ckcplm.html#x4.I
+ 26. http://www.columbia.edu/kermit/ckcplm.html#xa1
+ 27. http://www.amazon.com/gp/product/0932376886?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0932376886
+ 28. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 29. http://www.columbia.edu/kermit/vax_11-750.jpg
+ 30. http://www.columbia.edu/cu/computinghistory/hermit.html
+ 31. http://www.columbia.edu/kermit/cudocs/ilosetup.html
+ 32. ftp://kermit.columbia.edu/kermit/f/ckc04e.txt
+ 33. ftp://kermit.columbia.edu/kermit/f/ckc04f.txt
+ 34. ftp://kermit.columbia.edu/kermit/f/ckc168.txt
+ 35. ftp://kermit.columbia.edu/kermit/f/ckc178.txt
+ 36. ftp://kermit.columbia.edu/kermit/f/ckc188.txt
+ 37. ftp://kermit.columbia.edu/kermit/f/ckc189.txt
+ 38. ftp://kermit.columbia.edu/kermit/f/ckc192.txt
+ 39. ftp://kermit.columbia.edu/kermit/f/ckc197.txt
+ 40. ftp://kermit.columbia.edu/kermit/f/ckc200.txt
+ 41. ftp://kermit.columbia.edu/kermit/f/ckc211.txt
+ 42. ftp://kermit.columbia.edu/kermit/f/ckc300.txt
+ 43. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 44. http://www.columbia.edu/kermit/ckermit.html
+ 45. http://www.columbia.edu/kermit/index.html
+ 46. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+ 47. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 48. http://www.columbia.edu/kermit/ckermit.html
+ 49. http://www.columbia.edu/kermit/index.html
+ 50. http://www.columbia.edu/kermit/ckcplm.html#x3.2
+ 51. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 52. http://www.columbia.edu/kermit/ckermit.html
+ 53. http://www.columbia.edu/kermit/index.html
+ 54. http://www.columbia.edu/kermit/ckcplm.html#x4.A
+ 55. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 56. http://www.columbia.edu/kermit/ckermit.html
+ 57. http://www.columbia.edu/kermit/index.html
+ 58. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 59. http://www.columbia.edu/kermit/ckermit.html
+ 60. http://www.columbia.edu/kermit/index.html
+ 61. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 62. http://www.columbia.edu/kermit/ckermit.html
+ 63. http://www.columbia.edu/kermit/index.html
+ 64. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.h
+ 65. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.c
+ 66. http://www.columbia.edu/kermit/ckcplm.html#x3.1
+ 67. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 68. http://www.columbia.edu/kermit/ckermit.html
+ 69. http://www.columbia.edu/kermit/index.html
+ 70. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsym.h
+ 71. ftp://kermit.columbia.edu/kermit/c-kermit/ckcasc.h
+ 72. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsig.h
+ 73. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 74. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h
+ 75. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
+ 76. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 77. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+ 78. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfns.c
+ 79. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn2.c
+ 80. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn3.c
+ 81. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+ 82. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+ 83. http://www.columbia.edu/kermit/ckcplm.html#x4.D
+ 84. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 85. http://www.columbia.edu/kermit/ckermit.html
+ 86. http://www.columbia.edu/kermit/index.html
+ 87. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+ 88. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.c
+ 89. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
+ 90. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
+ 91. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
+ 92. ftp://kermit.columbia.edu/kermit/c-kermit/ckmxla.h
+ 93. ftp://kermit.columbia.edu/kermit/c-kermit/ck?xla
+ 94. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.h
+ 95. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c
+ 96. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 97. http://www.columbia.edu/kermit/ckermit.html
+ 98. http://www.columbia.edu/kermit/index.html
+ 99. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+ 100. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.h
+ 101. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c
+ 102. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+ 103. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+ 104. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.c
+ 105. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus2.c
+ 106. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+ 107. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus4.c
+ 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusy.c
+ 109. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+ 110. ftp://kermit.columbia.edu/kermit/c-kermit/ckuver.h
+ 111. ftp://kermit.columbia.edu/kermit/c-kermit/ckuscr.c
+ 112. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c
+ 113. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c
+ 114. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c
+ 115. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+ 116. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 117. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 118. http://www.columbia.edu/kermit/ckermit.html
+ 119. http://www.columbia.edu/kermit/index.html
+ 120. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 121. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 122. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
+ 123. ftp://kermit.columbia.edu/kermit/c-kermit/ckvfio.c
+ 124. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
+ 125. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 126. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 127. http://www.columbia.edu/kermit/ckermit.html
+ 128. http://www.columbia.edu/kermit/index.html
+ 129. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 130. ftp://kermit.columbia.edu/kermit/c-kermit/ckvtio.c
+ 131. http://www.columbia.edu/kermit/ckcplm.html#x2
+ 132. http://www.columbia.edu/kermit/ckcplm.html#xa1
+ 133. http://www.columbia.edu/kermit/ckuins.html
+ 134. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 135. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 136. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 137. http://www.columbia.edu/kermit/ckermit.html
+ 138. http://www.columbia.edu/kermit/index.html
+ 139. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 140. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 141. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 142. ftp://kermit.columbia.edu/kermit/c-kermit/cklnet.c
+ 143. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 144. http://www.columbia.edu/kermit/ckermit.html
+ 145. http://www.columbia.edu/kermit/index.html
+ 146. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h
+ 147. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 148. ftp://kermit.columbia.edu/kermit/c-kermit/ckcftp.c
+ 149. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 150. http://www.columbia.edu/kermit/ckermit.html
+ 151. http://www.columbia.edu/kermit/index.html
+ 152. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 153. http://www.columbia.edu/kermit/ckermit.html
+ 154. http://www.columbia.edu/kermit/index.html
+ 155. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+ 156. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 157. http://www.columbia.edu/kermit/ckermit.html
+ 158. http://www.columbia.edu/kermit/index.html
+ 159. http://www.columbia.edu/kermit/ckermit90.html#LooseEnd
+ 160. ftp://kermit.columbia.edu/kermit/f/ckupty.h
+ 161. ftp://kermit.columbia.edu/kermit/f/ckupty.c
+ 162. http://www.columbia.edu/kermit/security.html
+ 163. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 164. http://www.columbia.edu/kermit/ckermit.html
+ 165. http://www.columbia.edu/kermit/index.html
+ 166. http://www.columbia.edu/kermit/ckcplm.html#top
+ 167. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 168. http://www.columbia.edu/kermit/ckermit.html
+ 169. http://www.columbia.edu/kermit/index.html
+ 170. http://www.columbia.edu/kermit/index.html
+ 171. mailto:kermit@columbia.edu
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcpro.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcpro.c
new file mode 100644
index 0000000..3c51b6b
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcpro.c
@@ -0,0 +1,3814 @@
+
+/* WARNING -- This C source program generated by Wart preprocessor. */
+/* Do not edit this file; edit the Wart-format source file instead, */
+/* and then run it through Wart to produce a new C source file. */
+
+/* Wart Version Info: */
+char *wartv = "Wart Version 2.14, 10 Nov 1999";
+
+char *protv = /* -*-C-*- */
+"C-Kermit Protocol Module 8.0.160, 12 Aug 2007";
+
+int kactive = 0; /* Kermit protocol is active */
+
+#define PKTZEROHACK
+
+/* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2007,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef NOXFER
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+#endif /* OS2 */
+
+/*
+ Note -- This file may also be preprocessed by the UNIX Lex program, but
+ you must indent the above #include statements before using Lex, and then
+ restore them to the left margin in the resulting C program before compilation.
+ Also, the invocation of the "wart()" function below must be replaced by an
+ invocation of the "yylex()" function. It might also be necessary to remove
+ comments in the (%)(%)...(%)(%) section.
+*/
+
+/* State definitions for Wart (or Lex) */
+#define ipkt 1
+#define rfile 2
+#define rattr 3
+#define rdpkt 4
+#define ssinit 5
+#define ssfile 6
+#define ssattr 7
+#define ssdata 8
+#define sseof 9
+#define sseot 10
+#define serve 11
+#define generic 12
+#define get 13
+#define rgen 14
+#define ssopkt 15
+#define ropkt 16
+
+_PROTOTYP(static VOID xxproto,(void));
+_PROTOTYP(static VOID wheremsg,(void));
+_PROTOTYP(int wart,(void));
+_PROTOTYP(static int sgetinit,(int,int));
+_PROTOTYP(int sndspace,(int));
+
+/* External C-Kermit variable declarations */
+ extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist, *rf_err;
+ extern char * rfspec, * sfspec, * srfspec, * rrfspec;
+ extern char * prfspec, * psfspec, * psrfspec, * prrfspec;
+ extern char *cdmsgfile[];
+ extern char * snd_move, * snd_rename, * srimsg;
+ extern char filnam[], ofilnam[], fspec[], ttname[], ofn1[];
+ extern CHAR sstate, *srvptr, *data;
+ extern int timint, rtimo, nfils, hcflg, xflg, flow, mdmtyp, network;
+ extern int oopts, omode, oname, opath, nopush, isguest, xcmdsrc, rcdactive;
+ extern int rejection, moving, fncact, bye_active, urserver, fatalio;
+ extern int protocol, prefixing, filcnt, carrier, fnspath, interrupted;
+ extern int recursive, inserver, nzxopts, idletmo, srvidl, xfrint;
+ extern struct ck_p ptab[];
+ extern int remfile, rempipe, xferstat, filestatus, wearealike, fackpath;
+ extern int patterns, filepeek, gnferror;
+ extern char * remdest;
+
+#ifdef PKTZEROHACK
+#define PKTZEROLEN 32
+static char ipktack[PKTZEROLEN];
+static int ipktlen = 0;
+#endif /* PKTZEROHACK */
+
+static int s_timint = -1; /* For saving timeout value */
+static int myjob = 0;
+static int havefs = 0;
+#ifdef CK_LOGIN
+static int logtries = 0;
+#endif /* CK_LOGIN */
+
+static int cancel = 0;
+int fackbug = 0;
+
+#ifdef STREAMING
+extern int streaming, streamok;
+
+static VOID
+streamon() {
+ if (streamok) {
+ debug(F100,"streamon","",0);
+ streaming = 1;
+ timint = 0; /* No timeouts while streaming. */
+ }
+}
+
+#ifdef COMMENT /* (not used) */
+static VOID
+streamoff() {
+ if (streaming) {
+ debug(F100,"streamoff","",0);
+ streaming = 0;
+ timint = s_timint; /* Restore timeout */
+ }
+}
+#endif /* COMMENT */
+#else /* STREAMING */
+#define streamon()
+#define streamoff()
+#endif /* STREAMING */
+
+#ifndef NOSPL
+_PROTOTYP( int addmac, (char *, char *) );
+_PROTOTYP( int zzstring, (char *, char **, int *) );
+#endif /* NOSPL */
+#ifndef NOICP
+_PROTOTYP( int cmdsrc, (void) );
+#endif /* NOICP */
+
+#ifndef NOSERVER
+ extern char * x_user, * x_passwd, * x_acct;
+ extern int x_login, x_logged;
+#endif /* NOSERVER */
+
+#include "ckcnet.h"
+
+#ifdef TNCODE
+ extern int ttnproto; /* Network protocol */
+#endif /* TNCODE */
+
+#ifdef CK_SPEED
+ extern short ctlp[]; /* Control-character prefix table */
+#endif /* CK_SPEED */
+
+#ifdef TNCODE
+ extern int tn_b_nlm, tn_b_xfer, tn_nlm;
+#ifdef CK_ENCRYPTION
+ extern int tn_no_encrypt_xfer;
+#endif /* CK_ENCRYPTION */
+#endif /* TNCODE */
+
+#ifdef TCPSOCKET
+#ifndef NOLISTEN
+ extern int tcpsrfd;
+#endif /* NOLISTEN */
+#endif /* TCPSOCKET */
+
+ extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl;
+ extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
+ extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
+ extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent;
+ extern int binary, fncnv;
+ extern long speed, ffc, crc16, calibrate, dest;
+#ifdef COMMENT
+ extern char *TYPCMD, *DIRCMD, *DIRCM2;
+#endif /* COMMENT */
+#ifndef OS2
+ extern char *SPACMD, *SPACM2, *WHOCMD;
+#endif /* OS2 */
+ extern CHAR *rdatap;
+ extern struct zattr iattr;
+
+#ifdef VMS
+ extern int batch;
+#endif /* VMS */
+
+#ifdef GFTIMER
+ extern CKFLOAT fptsecs;
+#endif /* GFTIMER */
+
+ extern CHAR *srvcmd;
+ extern CHAR *epktmsg;
+
+#ifdef CK_TMPDIR
+extern int f_tmpdir; /* Directory changed temporarily */
+extern char savdir[]; /* For saving current directory */
+extern char * dldir;
+#endif /* CK_TMPDIR */
+
+ extern int query; /* Query-active flag */
+#ifndef NOSPL
+ extern int cmdlvl;
+ char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
+ char *qbufp = querybuf; /* Pointer to it */
+ int qbufn = 0; /* Length of data in it */
+#else
+ extern int tlevel;
+#endif /* NOSPL */
+
+#ifndef NOICP
+ extern int escape;
+#endif /* NOICP */
+/*
+ If the following flag is nonzero when the protocol module is entered,
+ then server mode persists for exactly one transaction, rather than
+ looping until BYE or FINISH is received.
+*/
+extern int justone;
+
+static int r_save = -1;
+static int p_save = -1;
+
+/* Function to let remote-mode user know where their file(s) went */
+
+int whereflg = 1; /* Unset with SET XFER REPORT */
+
+static VOID
+wheremsg() {
+ extern int quiet, filrej;
+ int n;
+ n = filcnt - filrej;
+ debug(F101,"wheremsg n","",n);
+
+ debug(F110,"wheremsg prfspec",prfspec,0);
+ debug(F110,"wheremsg rfspec",rfspec,0);
+ debug(F110,"wheremsg psfspec",psfspec,0);
+ debug(F110,"wheremsg sfspec",sfspec,0);
+
+ debug(F110,"wheremsg prrfspec",prrfspec,0);
+ debug(F110,"wheremsg rrfspec",rrfspec,0);
+ debug(F110,"wheremsg psrfspec",psrfspec,0);
+ debug(F110,"wheremsg srfspec",srfspec,0);
+
+ if (!quiet && !local) {
+ if (n == 1) {
+ switch (myjob) {
+ case 's':
+ if (sfspec) {
+ printf(" SENT: [%s]",sfspec);
+ if (srfspec)
+ printf(" To: [%s]",srfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ break;
+ case 'r':
+ case 'v':
+ if (rrfspec) {
+ printf(" RCVD: [%s]",rrfspec);
+ if (rfspec)
+ printf(" To: [%s]",rfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ }
+ } else if (n > 1) {
+ switch (myjob) {
+ case 's':
+ if (sfspec) {
+ printf(" SENT: (%d files)",n);
+ if (srfspec)
+ printf(" Last: [%s]",srfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ break;
+ case 'r':
+ case 'v':
+ if (rrfspec) {
+ printf(" RCVD: (%d files)",n);
+ if (rfspec)
+ printf(" Last: [%s]",rfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ }
+ } else if (n == 0) {
+ if (myjob == 's')
+ printf(" SENT: (0 files) \r\n");
+ else if (myjob == 'r' || myjob == 'v')
+ printf(" RCVD: (0 files) \r\n");
+ }
+ }
+}
+
+static VOID
+rdebug() {
+ if (server)
+ debug(F111,"RESUME","server=1",justone);
+ else
+ debug(F111,"RESUME","server=0",justone);
+}
+
+/* Flags for the ENABLE and DISABLE commands */
+extern int
+ en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
+ en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
+ en_mkd, en_rmd;
+#ifndef NOSPL
+extern int en_asg, en_que;
+#endif /* NOSPL */
+extern int what, lastxfer;
+
+/* Global variables declared here */
+
+ int whatru = 0; /* What are you. */
+ int whatru2 = 0; /* What are you, cont'd. */
+
+/* Local variables */
+
+ static char vstate = 0; /* Saved State */
+ static char vcmd = 0; /* Saved Command */
+ static int reget = 0; /* Flag for executing REGET */
+ static int retrieve = 0; /* Flag for executing RETRIEVE */
+ static int opkt = 0; /* Send Extended GET packet */
+
+ static int x; /* General-purpose integer */
+ static char *s; /* General-purpose string pointer */
+
+/* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
+/* BEGIN is NOT a GOTO! */
+#define TINIT if (tinit(1) < 0) return(-9)
+#define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \
+sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; }
+#define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \
+if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } }
+
+#ifdef GFTIMER
+#define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \
+ fptsecs=gftimer(); quiet=x; return(success)
+#else
+#define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
+ return(success)
+#endif /* GFTIMER */
+
+/*
+ By late 1999, the big switch() statement generated from the following state
+ table began choking even gcc, so here we extract the code from the larger
+ states into static routines to reduce the size of the cases and the
+ switch() overall. The routines follow the state table; the prototypes are
+ here. Each of these routines simply contains the text from the
+ corresponding case, but with return(-1) added in appropriate places; see
+ instructions after the state table switcher.
+*/
+static int rc; /* Return code for these routines */
+static int rcv_s_pkt(); /* Received an S packet */
+static int rcv_firstdata(); /* Received first Data packet */
+static int rcv_shortreply(); /* Short reply to a REMOTE command */
+static int srv_query(); /* Server answers an query */
+static int srv_copy(); /* Server executes REMOTE COPY */
+static int srv_rename(); /* Server executes REMOTE RENAME */
+static int srv_login(); /* Server executes REMOTE LOGIN */
+static int srv_timeout(); /* Server times out */
+
+
+#define BEGIN state =
+
+int state = 0;
+
+int
+wart()
+{
+ int c,actno;
+ extern char tbl[];
+ while (1) {
+ c = input() - 32;
+ debug(F000,"PROTO input",ckitoa(state),c+32);
+ if (c < 0 || c > 95) c = 0;
+ if ((actno = tbl[c + state*96]) != -1)
+ switch(actno) {
+case 1:
+ { TINIT; /* Send file(s) */
+ if (sinit() > 0) BEGIN ssinit;
+ else RESUME; }
+ break;
+case 2:
+ { TINIT; nakstate = 1; BEGIN get; }
+ break;
+case 3:
+ { /* Client sends a GET command */
+ TINIT;
+ vstate = get;
+ reget = 0;
+ retrieve = 0;
+ opkt = 0;
+ vcmd = 0;
+#ifdef PKTZEROHACK
+ ipktack[0] = NUL;
+#endif /* PKTZEROHACK */
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 4:
+ { /* Client sends a RETRIEVE command */
+ TINIT;
+ vstate = get;
+ reget = 0;
+ retrieve = 1;
+ opkt = 0;
+ vcmd = 0;
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 5:
+ { /* Client sends a REGET command */
+ TINIT;
+ vstate = get;
+ reget = 1;
+ retrieve = 0;
+ opkt = 0;
+ vcmd = 0;
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 6:
+ { /* Client sends Extended GET Packet */
+ TINIT;
+ vstate = get;
+ reget = oopts & GOPT_RES;
+ retrieve = oopts & GOPT_DEL;
+ opkt = 1;
+ vcmd = 0;
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 7:
+ { /* Client sends a Host command */
+ TINIT;
+ vstate = rgen;
+ vcmd = 'C';
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 8:
+ { TINIT; /* Client sends a Kermit command */
+ vstate = rgen;
+ vcmd = 'K';
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 9:
+ { /* Client sends a REMOTE command */
+ TINIT;
+ vstate = rgen;
+ vcmd = 'G';
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+ break;
+case 10:
+ { /* Enter server mode */
+ int x;
+ x = justone;
+ if (!ENABLED(en_del)) { /* If DELETE is disabled */
+ if (fncact == XYFX_B || /* undo any file collision action */
+ fncact == XYFX_U || /* that could result in deletion or */
+ fncact == XYFX_A || /* modification of existing files. */
+ fncact == XYFX_X) {
+#ifndef NOICP
+ extern int g_fncact;
+ g_fncact = fncact; /* Save current setting */
+#endif /* NOICP */
+ fncact = XYFX_R; /* Change to RENAME */
+ debug(F101,"server DELETE disabled so fncact RENAME","",fncact);
+ }
+ }
+ SERVE; /* tinit() clears justone... */
+ justone = x;
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what, "SERVER", "", "");
+#endif /* IKSDB */
+}
+ break;
+case 11:
+ {
+ int b1 = 0, b2 = 0;
+ if (!data) TINIT; /* "ABEND" -- Tell other side. */
+#ifndef pdp11
+ if (epktflg) { /* If because of E-PACKET command */
+ b1 = bctl; b2 = bctu; /* Save block check type */
+ bctl = bctu = 1; /* set it to 1 */
+ }
+#endif /* pdp11 */
+ errpkt((CHAR *)"User cancelled"); /* Send the packet */
+#ifndef pdp11
+ if (epktflg) { /* Restore the block check */
+ epktflg = 0;
+ bctl = b1; bctu = b2;
+ }
+#endif /* pdp11 */
+ success = 0;
+ return(0); /* Return from protocol. */
+}
+ break;
+case 12:
+ { /* Receive Send-Init packet. */
+ rc = rcv_s_pkt();
+ cancel = 0; /* Reset cancellation counter */
+ debug(F101,"rcv_s_pkt","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+ break;
+case 13:
+ { /* Get ack for I-packet */
+ int x = 0;
+#ifdef PKTZEROHACK
+ ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */
+ ipktlen = strlen(ipktack);
+#endif /* PKTZEROHACK */
+ spar(rdatap); /* Set parameters */
+ cancel = 0;
+ winlo = 0; /* Set window-low back to zero */
+ debug(F101,"<ipkt>Y winlo","",winlo);
+ urserver = 1; /* So I know I'm talking to a server */
+ if (vcmd) { /* If sending a generic command */
+ if (tinit(0) < 0) return(-9); /* Initialize many things */
+ x = scmd(vcmd,(CHAR *)cmarg); /* Do that */
+ if (x >= 0) x = 0; /* (because of O-Packet) */
+ debug(F101,"proto G packet scmd","",x);
+ vcmd = 0; /* and then un-remember it. */
+ } else if (vstate == get) {
+ debug(F101,"REGET sstate","",sstate);
+ x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */
+ }
+ if (x < 0) { /* If command was too long */
+ if (!srimsg)
+ srimsg = "Error sending string";
+ errpkt((CHAR *)srimsg); /* cancel both sides. */
+ success = 0;
+ RESUME;
+ } else if (x > 0) { /* Need to send more O-Packets */
+ BEGIN ssopkt;
+ } else {
+ rtimer(); /* Reset the elapsed seconds timer. */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ winlo = 0; /* Window back to 0, again. */
+ debug(F101,"<ipkt>Y vstate","",vstate);
+ nakstate = 1; /* Can send NAKs from here. */
+ BEGIN vstate; /* Switch to desired state */
+ }
+}
+ break;
+case 14:
+ { /* Got ACK to O-Packet */
+ debug(F100,"CPCPRO <ssopkt>Y","",0);
+ x = sopkt();
+ debug(F101,"CPCPRO <ssopkt>Y x","",x);
+ if (x < 0) { /* If error */
+ errpkt((CHAR *)srimsg); /* cancel both sides. */
+ success = 0;
+ RESUME;
+ } else if (x == 0) { /* This was the last O-Packet */
+ rtimer(); /* Reset the elapsed seconds timer. */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ winlo = 0; /* Window back to 0, again. */
+ debug(F101,"<ssopkt>Y winlo","",winlo);
+ nakstate = 1; /* Can send NAKs from here. */
+ BEGIN vstate; /* Switch to desired state */
+ }
+ debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
+}
+ break;
+case 15:
+ { /* Ignore Error reply to I packet */
+ int x = 0;
+ winlo = 0; /* Set window-low back to zero */
+ debug(F101,"<ipkt>E winlo","",winlo);
+ if (vcmd) { /* In case other Kermit doesn't */
+ if (tinit(0) < 0) return(-9);
+ x = scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */
+ if (x >= 0) x = 0; /* (because of O-Packet) */
+ vcmd = 0; /* Otherwise act as above... */
+ } else if (vstate == get) x = srinit(reget, retrieve, opkt);
+ if (x < 0) { /* If command was too long */
+ errpkt((CHAR *)srimsg); /* cancel both sides. */
+ success = 0;
+ RESUME;
+ } else if (x > 0) { /* Need to send more O-Packets */
+ BEGIN ssopkt;
+ } else {
+ freerpkt(winlo); /* Discard the Error packet. */
+ debug(F101,"<ipkt>E winlo","",winlo);
+ winlo = 0; /* Back to packet 0 again. */
+ nakstate = 1; /* Can send NAKs from here. */
+ BEGIN vstate;
+ }
+}
+ break;
+case 16:
+ { /* Resend of previous I-pkt ACK, same seq number */
+ freerpkt(0); /* Free the ACK's receive buffer */
+ resend(0); /* Send the GET packet again. */
+}
+ break;
+case 17:
+ { /* Get I-packet */
+#ifndef NOSERVER
+ spar(rdatap); /* Set parameters from it */
+ ack1(rpar()); /* Respond with our own parameters */
+#ifdef COMMENT
+ pktinit(); /* Reinitialize packet numbers */
+#else
+#ifdef COMMENT
+ /* This can't be right - it undoes the stuff we just negotiated */
+ x = justone;
+ tinit(1); /* Reinitialize EVERYTHING */
+ justone = x; /* But this... */
+#else
+ tinit(0); /* Initialize most things */
+#endif /* COMMENT */
+#endif /* COMMENT */
+#endif /* NOSERVER */
+ cancel = 0; /* Reset cancellation counter */
+}
+ break;
+case 18:
+ { /* GET */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 19:
+ { /* GET /DELETE (RETRIEVE) */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ RESUME;
+ } else if (!ENABLED(en_del)) {
+ errpkt((CHAR *)"Deleting files is disabled");
+ RESUME;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+ moving = 1;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 20:
+ { /* GET /RECURSIVE */
+#ifndef NOSERVER
+ recursive = 1; /* Set these before sgetinit() */
+ if (fnspath == PATH_OFF)
+ fnspath = PATH_REL; /* Don't worry, they will be */
+ if (x_login && !x_logged) { /* reset next time through. */
+ errpkt((CHAR *)"Login required");
+ RESUME;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 21:
+ { /* GET /RECURSIVE /DELETE */
+#ifndef NOSERVER
+ recursive = 1; /* Set these before sgetinit() */
+ if (fnspath == PATH_OFF)
+ fnspath = PATH_REL; /* Don't worry, they will be */
+ moving = 1; /* reset next time through. */
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ RESUME;
+ } else if (!ENABLED(en_del)) {
+ errpkt((CHAR *)"Deleting files is disabled");
+ RESUME;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR,1,"server",
+ "GET /RECURSIVE /DELETE",(char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 22:
+ { /* GET /RECOVER (REGET) */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if (sgetinit(1,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 23:
+ { /* Extended GET */
+#ifndef NOSERVER
+ if (x_login && !x_logged) { /* (any combination of options) */
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if ((x = sgetinit(0,1)) < 0) {
+ debug(F101,"CKCPRO <serve>O sgetinit fail","",x);
+ RESUME;
+ } else if (x == 0) {
+ debug(F101,"CKCPRO <serve>O sgetinit done","",x);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ } else { /* Otherwise stay in this state */
+ debug(F101,"CKCPRO <serve>O sgetinit TBC","",x);
+ ack();
+ BEGIN ropkt;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 24:
+ {
+#ifndef NOSERVER
+ if (x_login && !x_logged) { /* (any combination of options) */
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if ((x = sgetinit(0,1)) < 0) {
+ debug(F101,"CKCPRO <ropkt>O sgetinit fail","",x);
+ RESUME;
+ } else if (x == 0) {
+ debug(F101,"CKCPRO <ropkt>O sgetinit done","",x);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ } else { /* Otherwise stay in this state */
+ debug(F101,"CKCPRO <ropkt>O sgetinit TBC","",x);
+ ack();
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 25:
+ { /* Generic server command */
+#ifndef NOSERVER
+ srvptr = srvcmd; /* Point to command buffer */
+ decode(rdatap,putsrv,0); /* Decode packet data into it */
+ putsrv(NUL); /* Insert a couple nulls */
+ putsrv(NUL); /* for termination */
+ if (srvcmd[0]) {
+ sstate = srvcmd[0]; /* Set requested start state */
+ if (x_login && !x_logged && /* Login required? */
+ /* Login, Logout, and Help are allowed when not logged in */
+ sstate != 'I' && sstate != 'L' && sstate != 'H') {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else {
+ nakstate = 0; /* Now I'm the sender. */
+ what = W_REMO; /* Doing a REMOTE command. */
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ if (timint < 1)
+ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
+ binary = XYFT_T; /* Switch to text mode */
+ BEGIN generic; /* Switch to generic command state */
+ }
+ } else {
+ errpkt((CHAR *)"Badly formed server command"); /* report error */
+ RESUME; /* & go back to server command wait */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 26:
+ { /* Receive Host command */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if (!ENABLED(en_hos)) {
+ errpkt((CHAR *)"REMOTE HOST disabled");
+ RESUME;
+ } else if (nopush) {
+ errpkt((CHAR *)"HOST commands not available");
+ RESUME;
+ } else {
+ srvptr = srvcmd; /* Point to command buffer */
+ decode(rdatap,putsrv,0); /* Decode command packet into it */
+ putsrv(NUL); /* Null-terminate */
+ nakstate = 0; /* Now sending, not receiving */
+ binary = XYFT_T; /* Switch to text mode */
+ if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
+ what = W_REMO; /* Doing a REMOTE command. */
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ if (timint < 1)
+ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit; /* If OK, send back its output */
+ } else { /* Otherwise */
+ errpkt((CHAR *)"Can't do system command"); /* report error */
+ RESUME; /* & go back to server command wait */
+ }
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 27:
+ { /* Interrupted or connection lost */
+ rc = srv_timeout();
+ debug(F101,"srv_timeout","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+ break;
+case 28:
+ { /* Server got a NAK in command-wait */
+#ifndef NOSERVER
+ errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
+ RESUME;
+#endif /* NOSERVER */
+}
+ break;
+case 29:
+ { /* Any other command in this state */
+#ifndef NOSERVER
+ if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
+ errpkt((CHAR *)"Unimplemented server function");
+ /* If we answer an E with an E, we get an infinite loop. */
+ /* A Y (ACK) can show up here if we sent back a short-form reply to */
+ /* a G packet and it was echoed. ACKs can be safely ignored here. */
+ RESUME; /* Go back to server command wait. */
+#endif /* NOSERVER */
+}
+ break;
+case 30:
+ { /* Login/Out */
+ rc = srv_login();
+ debug(F101,"<generic>I srv_login","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+ break;
+case 31:
+ { /* Got REMOTE CD command */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_cwd)) {
+ errpkt((CHAR *)"REMOTE CD disabled");
+ RESUME;
+ } else {
+ char * p = NULL;
+ x = cwd((char *)(srvcmd+1)); /* Try to change directory */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!x) { /* Failed */
+ errpkt((CHAR *)"Can't change directory");
+ RESUME; /* Back to server command wait */
+ } else if (x == 2) { /* User wants message */
+ if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */
+ errpkt((CHAR *)"REMOTE TYPE disabled");
+ RESUME;
+ } else { /* TYPE is enabled */
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (zchki(cdmsgfile[i]) > -1) {
+ break;
+ }
+ }
+ binary = XYFT_T; /* Use text mode for this. */
+ if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */
+ BEGIN ssinit; /* OK */
+ } else { /* not OK */
+ p = zgtdir();
+ if (!p) p = "";
+ success = (*p) ? 1 : 0;
+ ack1((CHAR *)p); /* ACK with new directory name */
+ success = 1;
+ RESUME; /* wait for next server command */
+ }
+ }
+ } else { /* User doesn't want message */
+ p =zgtdir();
+ if (!p) p = "";
+ success = (*p) ? 1 : 0;
+ ack1((CHAR *)p);
+ success = 1;
+ RESUME; /* Wait for next server command */
+ }
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 32:
+ { /* Got REMOTE PWD command */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_cwd)) {
+ errpkt((CHAR *)"REMOTE CD disabled");
+ RESUME;
+ } else {
+ if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */
+ ack1(data); /* If it fits, send it back in ACK */
+ success = 1;
+ } else { /* Failed */
+ ack(); /* Send empty ACK */
+ success = 0; /* and indicate failure locally */
+ }
+ RESUME; /* Back to server command wait */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 33:
+ { /* REMOTE DIRECTORY command */
+#ifndef NOSERVER
+ char *n2;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_dir)) { /* If DIR is disabled, */
+ errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
+ RESUME;
+ } else { /* DIR is enabled. */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* But CWD is disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+#ifdef COMMENT
+ n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
+ if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */
+#else
+ int x;
+ if ((x = snddir((char*)(srvcmd+2))) > 0)
+#endif /* COMMENT */
+ {
+ BEGIN ssinit; /* send the results back; */
+ } else { /* otherwise */
+ if (x < 0)
+ errpkt((CHAR *)"No files match");
+ else
+ errpkt((CHAR *)"Can't list directory");
+ RESUME; /* return to server command wait */
+ }
+ }
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 34:
+ { /* REMOTE DELETE (Erase) */
+#ifndef NOSERVER
+ char *n2;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_del)) {
+ errpkt((CHAR *)"REMOTE DELETE disabled");
+ RESUME;
+ } else { /* DELETE is enabled */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* but CWD is disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */
+ errpkt((CHAR *)"It's a directory");
+ RESUME;
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ int x;
+ if ((x = snddel((char*)(srvcmd+2))) > 0) {
+ BEGIN ssinit; /* If OK send results back */
+ } else { /* otherwise */
+ if (x < 0)
+ errpkt((CHAR *)"File not found"); /* report failure */
+ else
+ errpkt((CHAR *)"DELETE failed");
+ RESUME; /* & return to server command wait */
+ }
+ }
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 35:
+ { /* FINISH */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"SERVER FINISH", "", "");
+#endif /* IKSDB */
+ if (!ENABLED(en_fin)) {
+ errpkt((CHAR *)"FINISH disabled");
+ RESUME;
+ } else {
+ ack(); /* Acknowledge */
+ xxscreen(SCR_TC,0,0L,""); /* Display */
+ success = 1;
+ return(0); /* Done */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 36:
+ { /* EXIT */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE EXIT", "", "");
+#endif /* IKSDB */
+ if (!ENABLED(en_xit)) {
+ errpkt((CHAR *)"EXIT disabled");
+ RESUME;
+ } else {
+ ack(); /* Acknowledge */
+ xxscreen(SCR_TC,0,0L,""); /* Display */
+ doexit(GOOD_EXIT,xitsta);
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 37:
+ { /* BYE (Logout) */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "BYE", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"SERVER BYE", "", "");
+#endif /* IKSDB */
+ if (!ENABLED(en_bye)) {
+ errpkt((CHAR *)"BYE disabled");
+ RESUME;
+ } else {
+ ack(); /* Acknowledge */
+ success = 1;
+ msleep(750); /* Give the ACK time to get out */
+ if (local)
+ ttres(); /* Reset the terminal */
+ xxscreen(SCR_TC,0,0L,""); /* Display */
+ doclean(1); /* Clean up files, etc */
+#ifdef DEBUG
+ debug(F100,"C-Kermit BYE - Loggin out...","",0);
+ zclose(ZDFILE);
+#endif /* DEBUG */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver)
+ ckxlogout();
+ else
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+#ifdef TCPSOCKET
+#ifndef NOLISTEN
+ if (network && tcpsrfd > 0 && !inserver)
+ doexit(GOOD_EXIT,xitsta);
+ else
+#endif /* NOLISTEN */
+#endif /* TCPSOCKET */
+ return(zkself()); /* Try to log self out */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 38:
+ { /* REMOTE HELP */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE HELP", "", "");
+#endif /* IKSDB */
+#ifndef NOSERVER
+ if (sndhlp()) {
+ BEGIN ssinit; /* try to send it */
+ } else { /* If not ok, */
+ errpkt((CHAR *)"Can't send help"); /* send error message instead */
+ RESUME; /* and return to server command wait */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 39:
+ { /* REMOTE RENAME */
+ rc = srv_rename();
+ debug(F101,"srv_rename","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+ break;
+case 40:
+ { /* REMOTE COPY */
+ rc = srv_copy();
+ debug(F101,"srv_copy","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+ break;
+case 41:
+ { /* REMOTE SET */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifndef NOSERVER
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_set)) {
+ errpkt((CHAR *)"REMOTE SET disabled");
+ RESUME;
+ } else {
+ if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */
+ success = 1;
+ ack(); /* If OK, then acknowledge */
+ } else /* Otherwise */
+ errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
+ RESUME; /* Return to server command wait */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 42:
+ { /* REMOTE TYPE */
+#ifndef NOSERVER
+ char *n2;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_typ)) {
+ errpkt((CHAR *)"REMOTE TYPE disabled");
+ RESUME;
+ } else {
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* If CWD disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ binary = XYFT_T; /* Use text mode for this. */
+ if ( /* (RESUME didn't change state) */
+#ifdef COMMENT
+ syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
+#else
+ sndtype((char *)(srvcmd+2)) /* New way */
+#endif /* COMMENT */
+ )
+ BEGIN ssinit; /* OK */
+ else { /* not OK */
+ errpkt((CHAR *)"Can't type file"); /* give error message */
+ RESUME; /* wait for next server command */
+ }
+ }
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 43:
+ { /* REMOTE MKDIR */
+#ifndef NOSERVER
+#ifdef CK_MKDIR
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_mkd)) {
+ errpkt((CHAR *)"REMOTE MKDIR disabled");
+ RESUME;
+ } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
+ errpkt((CHAR *)"Directory access restricted");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ if (state == generic) { /* OK to go ahead. */
+ char *p = NULL;
+ x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */
+ if (!p) p = "";
+ if (x > -1) {
+ encstr((CHAR *)p); /* OK - encode the name */
+ ack1(data); /* Send short-form response */
+ success = 1;
+ RESUME;
+ } else { /* not OK */
+ if (!*p) p = "Directory creation failure";
+ errpkt((CHAR *)p); /* give error message */
+ RESUME; /* Wait for next server command */
+ }
+ }
+#else
+ errpkt((CHAR *)"REMOTE MKDIR not available");
+ RESUME;
+#endif /* CK_MKDIR */
+#endif /* NOSERVER */
+}
+ break;
+case 44:
+ { /* REMOTE RMDIR */
+#ifndef NOSERVER
+#ifdef CK_MKDIR
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_rmd)) {
+ errpkt((CHAR *)"REMOTE RMDIR disabled");
+ RESUME;
+ } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
+ errpkt((CHAR *)"Directory access restricted");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ if (state == generic) { /* OK to go ahead. */
+ char *p = NULL;
+ x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1);
+ if (!p) p = "";
+ if (x > -1) {
+ encstr((CHAR *)p); /* OK - encode the name */
+ ack1(data); /* Send short-form response */
+ success = 1;
+ RESUME;
+ } else { /* not OK */
+ if (!*p) p = "Directory removal failure";
+ errpkt((CHAR *)p); /* give error message */
+ RESUME; /* Wait for next server command */
+ }
+ }
+#else
+ errpkt((CHAR *)"REMOTE RMDIR not available");
+ RESUME;
+#endif /* CK_MKDIR */
+#endif /* NOSERVER */
+}
+ break;
+case 45:
+ { /* REMOTE SPACE */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_spa)) {
+ errpkt((CHAR *)"REMOTE SPACE disabled");
+ RESUME;
+ } else {
+ x = srvcmd[1]; /* Get area to check */
+ x = ((x == NUL) || (x == SP)
+#ifdef OS2
+ || (x == '!') || (srvcmd[3] == ':')
+#endif /* OS2 */
+ );
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ "REMOTE SPACE",
+ (x ? "" : (char *)srvcmd),
+ ""
+ );
+#endif /* IKSDB */
+ if (!x && !ENABLED(en_cwd)) { /* CWD disabled */
+ errpkt((CHAR *)"Access denied"); /* and non-default area given, */
+ RESUME; /* refuse. */
+ } else {
+#ifdef OS2
+_PROTOTYP(int sndspace,(int));
+ if (sndspace(x ? toupper(srvcmd[2]) : 0)) {
+ BEGIN ssinit; /* send the report. */
+ } else { /* If not ok, */
+ errpkt((CHAR *)"Can't send space"); /* send error message */
+ RESUME; /* and return to server command wait */
+ }
+#else
+ if (nopush)
+ x = 0;
+ else
+ x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
+ if (x) { /* If we got the info */
+ BEGIN ssinit; /* send it */
+ } else { /* otherwise */
+ errpkt((CHAR *)"Can't check space"); /* send error message */
+ RESUME; /* and await next server command */
+ }
+#endif /* OS2 */
+ }
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 46:
+ { /* REMOTE WHO */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_who)) {
+ errpkt((CHAR *)"REMOTE WHO disabled");
+ RESUME;
+ } else {
+#ifdef OS2
+_PROTOTYP(int sndwho,(char *));
+ if (sndwho((char *)(srvcmd+2))) {
+ BEGIN ssinit; /* try to send it */
+ } else { /* If not ok, */
+ errpkt((CHAR *)"Can't do who command"); /* send error msg */
+ RESUME; /* and return to server command wait */
+ }
+#else
+ if (syscmd(WHOCMD,(char *)(srvcmd+2))) {
+ BEGIN ssinit;
+ } else {
+ errpkt((CHAR *)"Can't do who command");
+ RESUME;
+ }
+#endif /* OS2 */
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 47:
+ { /* Variable query or set */
+ rc = srv_query();
+ debug(F101,"srv_query","",rc);
+ if (rc > -1) return(rc);
+}
+ break;
+case 48:
+ { /* REMOTE MESSAGE command */
+#ifndef NOSERVER
+ debug(F110,"RMSG",(char *)srvcmd+2,0);
+ xxscreen(SCR_MS,0,0L,(char *)(srvcmd+2));
+ ack();
+ RESUME;
+#endif /* NOSERVER */
+}
+ break;
+case 49:
+ { /* Interrupted or connection lost */
+#ifndef NOSERVER
+ if (fatalio) { /* Connection lost */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
+#endif /* CKSYSLOG */
+ success = 0;
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ } else if (interrupted) {
+ if (!ENABLED(en_fin)) { /* Ctrl-C typed */
+ errpkt((CHAR *)"QUIT disabled");
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
+#endif /* CKSYSLOG */
+ success = 0;
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ }
+ } else { /* Shouldn't happen */
+ debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0);
+ QUIT;
+ }
+#endif /* NOSERVER */
+}
+ break;
+case 50:
+ { /* Anything else in this state... */
+#ifndef NOSERVER
+ errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
+ RESUME; /* and return to server command wait */
+#endif /* NOSERVER */
+}
+ break;
+case 51:
+ { /* Sent BYE and connection broken */
+ if (bye_active && ttchk() < 0) {
+ msleep(500);
+ bye_active = 0;
+ ttclos(0); /* Close our end of the connection */
+ clsof(0);
+ return(success = 1);
+ } else { /* Other generic command */
+ return(success = 0); /* or connection not broken */
+ }
+}
+ break;
+case 52:
+ { /* Short-Form reply */
+ rc = rcv_shortreply();
+ debug(F101,"<rgen>Y rcv_shortreply","",rc);
+ if (rc > -1) return(rc);
+}
+ break;
+case 53:
+ { /* File header */
+ /* char *n2; */
+ extern int rsn;
+ debug(F101,"<rfile>F winlo 1","",winlo);
+ xflg = 0; /* Not screen data */
+ if (!czseen)
+ cancel = 0; /* Reset cancellation counter */
+#ifdef CALIBRATE
+ if (dest == DEST_N)
+ calibrate = 1;
+#endif /* CALIBRATE */
+ if (!rcvfil(filnam)) { /* Figure out local filename */
+ errpkt((CHAR *)rf_err); /* Trouble */
+ RESUME;
+ } else { /* Real file, OK to receive */
+ char * fnp;
+ debug(F111,"<rfile>F winlo 2",fspec,winlo);
+ if (filcnt == 1) /* rcvfil set this to 1 for 1st file */
+ crc16 = 0L; /* Clear file CRC */
+ fnp = fspec; /* This is the full path */
+ if (server && !ENABLED(en_cwd) || /* if DISABLE CD */
+ !fackpath /* or F-ACK-PATH OFF */
+ ) {
+ zstrip(fspec,&fnp); /* don't send back full path */
+ }
+ encstr((CHAR *)fnp);
+ if (fackbug)
+ ack();
+ else
+ ack1(data); /* Send it back in ACK */
+ initattr(&iattr); /* Clear file attribute structure */
+ streamon();
+ if (window(wslotn) < 0) { /* Allocate negotiated window slots */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ }
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ server ? "SERVER" : "",
+ "RECEIVE",
+ fspec
+ );
+#endif /* IKSDB */
+ BEGIN rattr; /* Now expect Attribute packets */
+ }
+}
+ break;
+case 54:
+ { /* X-packet instead of file header */
+ xflg = 1; /* Screen data */
+ if (!czseen)
+ cancel = 0; /* Reset cancellation counter */
+ ack(); /* Acknowledge the X-packet */
+ initattr(&iattr); /* Initialize attribute structure */
+ streamon();
+ if (window(wslotn) < 0) { /* allocate negotiated window slots */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ }
+#ifndef NOSPL
+ if (query) { /* If this is the response to */
+ qbufp = querybuf; /* a query that we sent, initialize */
+ qbufn = 0; /* the response buffer */
+ querybuf[0] = NUL;
+ }
+#endif /* NOSPL */
+ what = W_REMO; /* we're doing a REMOTE command */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ server ? "SERVER" : "",
+ "RECEIVE",
+ fspec
+ );
+#endif /* IKSDB */
+ BEGIN rattr; /* Expect Attribute packets */
+}
+ break;
+case 55:
+ { /* Attribute packet */
+ if (gattr(rdatap,&iattr) == 0) { /* Read into attribute structure */
+#ifdef CK_RESEND
+ ack1((CHAR *)iattr.reply.val); /* Reply with data */
+#else
+ ack(); /* If OK, acknowledge */
+#endif /* CK_RESEND */
+ } else { /* Otherwise */
+ extern long fsize;
+ char *r;
+ r = getreason(iattr.reply.val);
+ ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */
+ xxscreen(SCR_ST,ST_REFU,0L,r); /* reason */
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,filnam,fsize,binary,1,r);
+#endif /* TLOG */
+ }
+}
+ break;
+case 56:
+ { /* First data packet */
+ debug(F100,"<rattr> D firstdata","",0);
+ rc = rcv_firstdata();
+ debug(F101,"rcv_firstdata rc","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+ break;
+case 57:
+ { /* EOT, no more files */
+ ack(); /* Acknowledge the B packet */
+ reot(); /* Do EOT things */
+#ifdef CK_TMPDIR
+/* If we were cd'd temporarily to another device or directory ... */
+ if (f_tmpdir) {
+ int x;
+ x = zchdir((char *) savdir); /* ... restore previous directory */
+ f_tmpdir = 0; /* and remember we did it. */
+ debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
+ }
+#endif /* CK_TMPDIR */
+ RESUME; /* and quit */
+}
+ break;
+case 58:
+ { /* Got Data packet */
+ debug(F101,"<rdpkt>D cxseen","",cxseen);
+ debug(F101,"<rdpkt>D czseen","",czseen);
+ if (cxseen || czseen || discard) { /* If file or group interruption */
+ CHAR * msg;
+ msg = czseen ? (CHAR *)"Z" : (CHAR *)"X";
+#ifdef STREAMING
+ if (streaming) { /* Need to cancel */
+ debug(F111,"<rdpkt>D streaming cancel",msg,cancel);
+ if (cancel++ == 0) { /* Only do this once */
+ ack1(msg); /* Put "X" or "Z" in ACK */
+ } else if (czseen) {
+ errpkt((CHAR *)"User canceled");
+ RESUME;
+ } else {
+ fastack();
+ }
+ } else
+#endif /* STREAMING */
+ ack1(msg);
+ } else { /* No interruption */
+ int rc, qf;
+#ifndef NOSPL
+ qf = query;
+#else
+ qf = 0;
+#endif /* NOSPL */
+#ifdef CKTUNING
+ rc = (binary && !parity) ?
+ bdecode(rdatap,putfil):
+ decode(rdatap, qf ? puttrm : putfil, 1);
+#else
+ rc = decode(rdatap, qf ? puttrm : putfil, 1);
+#endif /* CKTUNING */
+ if (rc < 0) {
+ discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T));
+ errpkt((CHAR *)"Error writing data"); /* If failure, */
+ RESUME;
+ } else /* Data written OK, send ACK */
+#ifdef STREAMING
+ if (streaming)
+ fastack();
+ else
+#endif /* STREAMING */
+ ack();
+ }
+}
+ break;
+case 59:
+ { /* EOF immediately after A-Packet. */
+ rf_err = "Can't create file";
+ timint = s_timint;
+ if (discard) { /* Discarding a real file... */
+ x = 1;
+ } else if (xflg) { /* If screen data */
+ if (remfile) { /* redirected to file */
+ if (rempipe) /* or pipe */
+ x = openc(ZOFILE,remdest); /* Pipe: start command */
+ else
+ x = opena(remdest,&iattr); /* File: open with attributes */
+ } else { /* otherwise */
+ x = opent(&iattr); /* "open" the screen */
+ }
+#ifdef CALIBRATE
+ } else if (calibrate) { /* If calibration run */
+ x = ckopenx(&iattr); /* do this */
+#endif /* CALIBRATE */
+ } else { /* otherwise */
+ x = opena(filnam,&iattr); /* open the file, with attributes */
+ if (x == -17) { /* REGET skipped because same size */
+ discard = 1;
+ rejection = 1;
+ }
+ }
+ if (!x || reof(filnam, &iattr) < 0) { /* Close output file */
+ errpkt((CHAR *) rf_err); /* If problem, send error msg */
+ RESUME; /* and quit */
+ } else { /* otherwise */
+ if (x == -17)
+ xxscreen(SCR_ST,ST_SKIP,SKP_RES,"");
+ ack(); /* acknowledge the EOF packet */
+ BEGIN rfile; /* and await another file */
+ }
+}
+ break;
+case 60:
+ { /* Ctrl-C or connection loss. */
+ timint = s_timint;
+ window(1); /* Set window size back to 1... */
+ cxseen = 1;
+ x = clsof(1); /* Close file */
+ return(success = 0); /* Failed */
+}
+ break;
+case 61:
+ { /* End Of File (EOF) Packet */
+/* wslots = 1; */ /* (don't set) Window size back to 1 */
+#ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */
+ x = reof(filnam, &iattr); /* Handle the EOF packet */
+ switch (x) { /* reof() sets the success flag */
+ case -5: /* Handle problems */
+ errpkt((CHAR *)"RENAME failed"); /* Fatal */
+ RESUME;
+ break;
+ case -4:
+ errpkt((CHAR *)"MOVE failed"); /* Fatal */
+ RESUME;
+ break;
+ case -3: /* If problem, send error msg */
+ errpkt((CHAR *)"Can't print file"); /* Fatal */
+ RESUME;
+ break;
+ case -2:
+ errpkt((CHAR *)"Can't mail file"); /* Fatal */
+ RESUME;
+ break;
+ case 2: /* Not fatal */
+ case 3:
+ xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file");
+ RESUME;
+ break;
+ default:
+ if (x < 0) { /* Fatal */
+ errpkt((CHAR *)"Can't close file");
+ RESUME;
+ } else { /* Success */
+#ifndef NOSPL
+ if (query) /* Query reponses generally */
+ conoll(""); /* don't have line terminators */
+#endif /* NOSPL */
+ if (czseen) { /* Batch canceled? */
+ if (cancel++ == 0) { /* If we haven't tried this yet */
+ ack1((CHAR *)"Z"); /* Try it once */
+ } else { /* Otherwise */
+ errpkt((CHAR *)"User canceled"); /* quite with Error */
+ RESUME;
+ }
+ } else
+ ack(); /* Acknowledge the EOF packet */
+ BEGIN rfile; /* and await another file */
+ }
+ }
+#else
+ if (reof(filnam, &iattr) < 0) { /* Close the file */
+ errpkt((CHAR *)"Error at end of file");
+ RESUME;
+ } else { /* reof() sets success flag */
+ ack();
+ BEGIN rfile;
+ }
+#endif /* COHERENT */
+}
+ break;
+case 62:
+ { /* ACK for Send-Init */
+ spar(rdatap); /* set parameters from it */
+ cancel = 0;
+ bctu = bctr; /* switch to agreed-upon block check */
+ bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
+#ifdef CK_RESEND
+ if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
+ errpkt((CHAR *) "RESEND capabilities not negotiated");
+ RESUME;
+ } else {
+#endif /* CK_RESEND */
+ what = W_SEND; /* Remember we're sending */
+ lastxfer = W_SEND;
+ x = sfile(xflg); /* Send X or F header packet */
+ cancel = 0; /* Reset cancellation counter */
+ if (x) { /* If the packet was sent OK */
+ if (!xflg && filcnt == 1) /* and it's a real file */
+ crc16 = 0L; /* Clear the file CRC */
+ resetc(); /* reset per-transaction counters */
+ rtimer(); /* reset timers */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ streamon(); /* turn on streaming */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ (server ? "SERVER" : ""),
+ "SEND",
+ filnam
+ );
+#endif /* IKSDB */
+ BEGIN ssfile; /* and switch to receive-file state */
+ } else { /* otherwise send error msg & quit */
+ s = xflg ? "Can't execute command" : (char *)epktmsg;
+ if (!*s) s = "Can't open file";
+ errpkt((CHAR *)s);
+ RESUME;
+ }
+#ifdef CK_RESEND
+ }
+#endif /* CK_RESEND */
+}
+ break;
+case 63:
+ { /* R packet was retransmitted. */
+ xsinit(); /* Resend packet 0 */
+}
+ break;
+case 64:
+ { /* Same deal if G packet comes again */
+ xsinit();
+}
+ break;
+case 65:
+ { /* Same deal if C packet comes again */
+ xsinit();
+}
+ break;
+case 66:
+ { /* ACK for F or X packet */
+ srvptr = srvcmd; /* Point to string buffer */
+ decode(rdatap,putsrv,0); /* Decode data field, if any */
+ putsrv(NUL); /* Terminate with null */
+ ffc = 0L; /* Reset file byte counter */
+ debug(F101,"<ssfile>Y cxseen","",cxseen);
+ if (*srvcmd) { /* If remote name was recorded */
+ if (sendmode != SM_RESEND) {
+ if (fdispla == XYFD_C || fdispla == XYFD_S)
+ xxscreen(SCR_AN,0,0L,(char *)srvcmd);
+ tlog(F110," remote name:",(char *) srvcmd,0L);
+ makestr(&psrfspec,(char *)srvcmd);
+ }
+ }
+ if (cxseen||czseen) { /* Interrupted? */
+ debug(F101,"<ssfile>Y canceling","",0);
+ x = clsif(); /* Close input file */
+ sxeof(1); /* Send EOF(D) */
+ BEGIN sseof; /* and switch to EOF state. */
+ } else if (atcapu) { /* If attributes are to be used */
+ if (sattr(xflg | stdinf, 1) < 0) { /* send them */
+ errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
+ RESUME; /* and quit */
+ } else BEGIN ssattr; /* if ok, switch to attribute state */
+ } else { /* Attributes not negotiated */
+ if (window(wslotn) < 0) { /* Open window */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ } else if ((x = sdata()) == -2) { /* Send first data packet data */
+ window(1); /* Connection lost, reset window */
+ x = clsif(); /* Close input file */
+ return(success = 0); /* Return failure */
+ } else if (x == -9) { /* User interrupted */
+ errpkt((CHAR *)"User cancelled"); /* Send Error packet */
+ window(1); /* Set window size back to 1... */
+ timint = s_timint; /* Restore timeout */
+ return(success = 0); /* Failed */
+ } else if (x < 0) { /* EOF (empty file) or interrupted */
+ window(1); /* put window size back to 1, */
+ debug(F101,"<ssfile>Y cxseen","",cxseen);
+ x = clsif(); /* If not ok, close input file, */
+ if (x < 0) /* treating failure as interruption */
+ cxseen = 1; /* Send EOF packet */
+ seof(cxseen||czseen);
+ BEGIN sseof; /* and switch to EOF state. */
+ } else { /* First data sent OK */
+ BEGIN ssdata; /* All ok, switch to send-data state */
+ }
+ }
+}
+ break;
+case 67:
+ { /* Got ACK to A packet */
+ ffc = 0L; /* Reset file byte counter */
+ debug(F101,"<ssattr>Y cxseen","",cxseen);
+ if (cxseen||czseen) { /* Interrupted? */
+ debug(F101,"<sattr>Y canceling","",0);
+ x = clsif(); /* Close input file */
+ sxeof(1); /* Send EOF(D) */
+ BEGIN sseof; /* and switch to EOF state. */
+ } else if (rsattr(rdatap) < 0) { /* Was the file refused? */
+ discard = 1; /* Set the discard flag */
+ clsif(); /* Close the file */
+ sxeof(1); /* send EOF with "discard" code */
+ BEGIN sseof; /* switch to send-EOF state */
+ } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */
+ errpkt((CHAR *)"Can't send attributes"); /* Trouble... */
+ RESUME;
+ } else if (x == 0) { /* No more to send so now the data */
+ if (window(wslotn) < 0) { /* Allocate negotiated window slots */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ }
+ if ((x = sdata()) == -2) { /* File accepted, send first data */
+ window(1); /* Connection broken */
+ x = clsif(); /* Close file */
+ return(success = 0); /* Return failure */
+ } else if (x == -9) { /* User interrupted */
+ errpkt((CHAR *)"User cancelled"); /* Send Error packet */
+ window(1); /* Set window size back to 1... */
+ timint = s_timint; /* Restore timeout */
+ return(success = 0); /* Failed */
+ } else if (x < 0) { /* If data was not sent */
+ window(1); /* put window size back to 1, */
+ debug(F101,"<ssattr>Y cxseen","",cxseen);
+ if (clsif() < 0) /* Close input file */
+ cxseen = 1; /* Send EOF packet */
+ seof(cxseen||czseen);
+ BEGIN sseof; /* and switch to EOF state. */
+ } else {
+ BEGIN ssdata; /* All ok, switch to send-data state */
+ }
+ }
+}
+ break;
+case 68:
+ { /* Ctrl-C or connection loss. */
+ window(1); /* Set window size back to 1... */
+ cxseen = 1; /* To indicate interruption */
+ x = clsif(); /* Close file */
+ return(success = 0); /* Failed */
+}
+ break;
+case 69:
+ { /* Got ACK to Data packet */
+ canned(rdatap); /* Check if file transfer cancelled */
+ debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
+ debug(F111,"<ssdata>Y czseen",rdatap,czseen);
+ if ((x = sdata()) == -2) { /* Try to send next data */
+ window(1); /* Connection lost, reset window */
+ x = clsif(); /* Close file */
+ return(success = 0); /* Failed */
+ } else if (x == -9) { /* User interrupted */
+ errpkt((CHAR *)"User cancelled"); /* Send Error packet */
+ window(1); /* Set window size back to 1... */
+ timint = s_timint; /* Restore original timeout */
+ return(success = 0); /* Failed */
+ } else if (x < 0) { /* EOF - finished sending data */
+ debug(F101,"<ssdata>Y cxseen","",cxseen);
+ window(1); /* Set window size back to 1... */
+ if (clsif() < 0) /* Close input file */
+ cxseen = 1; /* Send EOF packet */
+ debug(F101,"<ssdata>Y CALLING SEOF()","",cxseen);
+ seof(cxseen||czseen);
+ BEGIN sseof; /* and enter send-eof state */
+ }
+ /* NOTE: If x == 0 it means we're draining: see sdata()! */
+}
+ break;
+case 70:
+ { /* Got ACK to EOF */
+ int g, xdiscard;
+ canned(rdatap); /* Check if file transfer cancelled */
+ debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
+ debug(F111,"<sseof>Y czseen",rdatap,czseen);
+ debug(F111,"<sseof>Y discard",rdatap,discard);
+ xdiscard = discard;
+ discard = 0;
+ success = (cxseen == 0 && czseen == 0); /* Transfer status... */
+ debug(F101,"<sseof>Y success","",success);
+ if (success && rejection > 0) /* If rejected, succeed if */
+ if (rejection != '#' && /* reason was date */
+ rejection != 1 && rejection != '?') /* or name; */
+ success = 0; /* fail otherwise. */
+ cxseen = 0; /* This goes back to zero. */
+ if (success) { /* Only if transfer succeeded... */
+ xxscreen(SCR_ST,ST_OK,0L,"");
+ if (!xdiscard) {
+ makestr(&sfspec,psfspec); /* Record filenames for WHERE */
+ makestr(&srfspec,psrfspec);
+ }
+ if (moving) { /* If MOVE'ing */
+ x = zdelet(filnam); /* Try to delete the source file */
+#ifdef TLOG
+ if (tralog) {
+ if (x > -1) {
+ tlog(F110," deleted",filnam,0);
+ } else {
+ tlog(F110," delete failed:",ck_errstr(),0);
+ }
+ }
+#endif /* TLOG */
+ } else if (snd_move) { /* Or move it */
+ int x;
+ x = zrename(filnam,snd_move);
+#ifdef TLOG
+ if (tralog) {
+ if (x > -1) {
+ tlog(F110," moved to ",snd_move,0);
+ } else {
+ tlog(F110," move failed:",ck_errstr(),0);
+ }
+ }
+#endif /* TLOG */
+ } else if (snd_rename) { /* Or rename it */
+ char *s = snd_rename; /* Renaming string */
+#ifndef NOSPL
+ int y; /* Pass it thru the evaluator */
+ extern int cmd_quoting; /* for \v(filename) */
+ if (cmd_quoting) { /* But only if cmd_quoting is on */
+ y = MAXRP;
+ s = (char *)srvcmd;
+ zzstring(snd_rename,&s,&y);
+ s = (char *)srvcmd;
+ }
+#endif /* NOSPL */
+ if (s) if (*s) {
+ int x;
+ x = zrename(filnam,s);
+#ifdef TLOG
+ if (tralog) {
+ if (x > -1) {
+ tlog(F110," renamed to",s,0);
+ } else {
+ tlog(F110," rename failed:",ck_errstr(),0);
+ }
+ }
+#endif /* TLOG */
+#ifdef COMMENT
+ *s = NUL;
+#endif /* COMMENT */
+ }
+ }
+ }
+ if (czseen) { /* Check group interruption flag */
+ g = 0; /* No more files if interrupted */
+ } else { /* Otherwise... */
+#ifdef COMMENT
+ /* This code makes any open error fatal to a file-group transfer. */
+ g = gnfile();
+ debug(F111,"<sseof>Y gnfile",filnam,g);
+ if (g > 0) { /* Any more files to send? */
+ if (sfile(xflg)) /* Yes, try to send next file header */
+ BEGIN ssfile; /* if ok, enter send-file state */
+ else { /* otherwise */
+ s = xflg ? "Can't execute command" : (char *)epktmsg;
+ if (!*s) s = "Can't open file";
+ errpkt((CHAR *)s); /* send error message */
+ RESUME; /* and quit */
+ }
+ } else { /* No next file */
+ tsecs = gtimer(); /* get statistics timers */
+#ifdef GFTIMER
+ fptsecs = gftimer();
+#endif /* GFTIMER */
+ seot(); /* send EOT packet */
+ BEGIN sseot; /* enter send-eot state */
+ }
+#else /* COMMENT */
+ while (1) { /* Keep trying... */
+ g = gnfile(); /* Get next file */
+ debug(F111,"<sseof>Y gnfile",filnam,g);
+ if (g == 0 && gnferror == 0) /* No more, stop trying */
+ break;
+ if (g > 0) { /* Have one */
+ if (sfile(xflg)) { /* Try to open and send F packet */
+ BEGIN ssfile; /* If OK, enter send-file state */
+ break; /* and break out of loop. */
+ }
+ } /* Otherwise keep trying to get one we can send... */
+ }
+ }
+ if (g == 0) {
+ debug(F101,"<sseof>Y no more files","",czseen);
+ tsecs = gtimer(); /* Get statistics timers */
+#ifdef GFTIMER
+ fptsecs = gftimer();
+#endif /* GFTIMER */
+ seot(); /* Send EOT packet */
+ BEGIN sseot; /* Enter send-eot state */
+ }
+#endif /* COMMENT */
+}
+ break;
+case 71:
+ { /* Got ACK to EOT */
+ debug(F101,"sseot justone","",justone);
+ RESUME; /* All done, just quit */
+}
+ break;
+case 72:
+ { /* Got Error packet, in any state */
+ char *s = "";
+ window(1); /* Close window */
+ timint = s_timint; /* Restore original timeout */
+ if (*epktmsg) /* Message from Error packet */
+ s = (char *)epktmsg;
+ if (!*s) { /* If not there then maybe here */
+ s = (char *)rdatap;
+ ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN);
+ }
+ if (!*s) /* Hopefully we'll never see this. */
+ s = "Unknown error";
+ success = 0; /* For IF SUCCESS/FAIL. */
+ debug(F101,"ckcpro.w justone at E pkt","",justone);
+
+ success = 0; /* Transfer failed */
+ xferstat = success; /* Remember transfer status */
+ if (!epktsent) {
+ x = quiet; quiet = 1; /* Close files silently, */
+ epktrcvd = 1; /* Prevent messages from clsof() */
+ clsif();
+ clsof(1); /* discarding any output file. */
+ ermsg(s); /* Issue the message (calls screen). */
+ quiet = x; /* Restore quiet state */
+ }
+ tstats(); /* Get stats */
+/*
+ If we are executing commands from a command file or macro, let the command
+ file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
+*/
+ if (
+#ifndef NOICP
+ !xcmdsrc &&
+#endif /* NOICP */
+ backgrd && !server)
+ fatal("Protocol error");
+ xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
+#ifdef CK_TMPDIR
+/* If we were cd'd temporarily to another device or directory ... */
+ if (f_tmpdir) {
+ int x;
+ x = zchdir((char *) savdir); /* ... restore previous directory */
+ f_tmpdir = 0; /* and remember we did it. */
+ debug(F111,"ckcpro.w E tmpdir restored",savdir,x);
+ }
+#endif /* CK_TMPDIR */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, "");
+#endif /* IKSDB */
+ RESUME;
+}
+ break;
+case 73:
+ { success = 0; QUIT; }
+ break;
+case 74:
+ { /* Anything not accounted for above */
+ errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
+ window(1);
+ xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
+ RESUME; /* and quit */
+}
+ break;
+
+ }
+ }
+}
+
+char tbl[] = {
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 15, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 13, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 57, 74, 74, 72, 53, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 54, 74, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 55, 74, 74, 56, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 59, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 58, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 61, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 60, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 65, 74, 72, 74, 64, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 63, 74, 74, 74, 74, 74, 74, 62, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 66, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 67, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 69, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 68, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 70, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 71, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 26, 29, 29, 29, 25, 19, 17, 22, 29, 29, 29, 28, 23,
+ 29, 29, 18, 12, 29, 29, 20, 21, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 11, 29, 7, 29, 29, 29, 9, 4, 29, 5, 8, 29, 29, 29, 6,
+ 29, 27, 3, 1, 29, 29, 2, 29, 10, 29, 29, 29, 29, 29, 29, 29,
+ -1, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 32, 50, 31, 33, 34, 35, 50, 38, 30, 50, 40, 37, 48, 50, 50,
+ 50, 50, 39, 41, 42, 45, 47, 46, 36, 50, 50, 50, 50, 50, 50, 50,
+ 50, 11, 50, 7, 44, 50, 50, 9, 4, 50, 5, 8, 50, 43, 50, 6,
+ 50, 49, 3, 1, 50, 50, 2, 50, 10, 50, 50, 50, 50, 50, 50, 50,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 17, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 12, 74, 74, 74, 74, 74, 16, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 53, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 12, 74, 74, 74, 74, 54, 52, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 51, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ -1, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 14, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74, 74,
+ 0, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 72, 74, 74, 74, 74, 74, 74, 74, 74, 74, 24,
+ 74, 74, 74, 12, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 11, 74, 7, 74, 74, 74, 9, 4, 74, 5, 8, 74, 74, 74, 6,
+ 74, 73, 3, 1, 74, 74, 2, 74, 10, 74, 74, 74, 74, 74, 74,74
+};
+
+
+/*
+ From here down to proto() are routines that were moved out of the state
+ table switcher because the resulting switch() had become too large.
+ To move the contents of a state-table case to a routine:
+ 1. Add a prototype to the list above the state table switcher.
+ 2. Make a routine with an appropriate name, returning int.
+ 3. Move the code into it.
+ 4. Put a call to the new routine in the former spot:
+ rc = name_of_routine();
+ if (rc > -1) return(rc);
+ 5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and
+ at the end if the code is open-ended.
+*/
+static int
+rcv_firstdata() {
+ extern int dispos;
+ debug(F101,"rcv_firstdata","",dispos);
+
+ if (discard) { /* if we're discarding the file */
+ ack1((CHAR *)"X"); /* just ack the data like this. */
+ cancel++; /* and count it */
+ BEGIN rdpkt; /* and wait for more data packets. */
+ return(-1);
+ } else { /* Not discarding. */
+ rf_err = "Can't open file";
+ if (xflg) { /* If screen data */
+ if (remfile) { /* redirected to file */
+ if (rempipe) /* or pipe */
+ x = openc(ZOFILE,remdest); /* Pipe: start command */
+ else
+ x = opena(remdest,&iattr); /* File: open with attributes */
+ } else { /* otherwise */
+ x = opent(&iattr); /* "open" the screen */
+ }
+ } else { /* otherwise */
+#ifdef CALIBRATE
+ if (calibrate) { /* If calibration run */
+ x = ckopenx(&iattr); /* open nothing */
+#ifdef STREAMING
+ if (streaming) /* Streaming */
+ fastack(); /* ACK without ACKing. */
+ else
+#endif /* STREAMING */
+ ack(); /* Send real ACK */
+ BEGIN rdpkt; /* Proceed to next state */
+ return(-1);
+ } else
+#endif /* CALIBRATE */
+#ifdef UNIX
+/*
+ In UNIX we can pipe the file data into the mail program, which is to be
+ preferred to writing it out to a temp file and then mailing it afterwards.
+ This depends rather heavily on all UNIXes having a mail command that
+ accepts '-s "subject"' on the command line. MAILCMD (e.g. mail, Mail, mailx)
+ is defined in ckufio.c.
+*/
+ if (dispos == 'M') { /* Mail... */
+ char *s;
+ char * tmp = NULL;
+ int n = 0;
+ extern char *MAILCMD;
+ s = iattr.disp.val + 1;
+ n = (int)strlen(MAILCMD) + /* Mail command */
+ (int)strlen(s) + /* address */
+ (int)strlen(ofilnam) + 32; /* subject */
+ if (tmp = (char *)malloc(n)) {
+ ckmakxmsg(tmp,n,
+ MAILCMD," -s \"",ofilnam,"\" ",s,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp));
+ x = openc(ZOFILE,(char *)tmp);
+ free(tmp);
+ } else
+ x = 0;
+ } else if (dispos == 'P') { /* Ditto for print */
+ char * tmp = NULL;
+ int n;
+ extern char *PRINTCMD;
+ n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4;
+ if (tmp = (char *)malloc(n)) {
+ sprintf(tmp, /* safe (prechecked) */
+ "%s %s", PRINTCMD, iattr.disp.val + 1);
+ x = openc(ZOFILE,(char *)tmp);
+ free(tmp);
+ } else
+ x = 0;
+ } else
+#endif /* UNIX */
+ x = opena(filnam,&iattr); /* open the file, with attributes */
+ }
+ if (x) { /* If file was opened ok */
+ int rc, qf;
+#ifndef NOSPL
+ qf = query;
+#else
+ qf = 0;
+#endif /* NOSPL */
+
+#ifdef CKTUNING
+ rc = (binary && !parity) ?
+ bdecode(rdatap,putfil):
+ decode(rdatap, qf ? puttrm : putfil, 1);
+#else
+ rc = decode(rdatap, qf ? puttrm : putfil, 1);
+#endif /* CKTUNING */
+ if (rc < 0) {
+ errpkt((CHAR *)"Error writing data");
+ RESUME;
+ return(-1);
+ }
+#ifdef STREAMING
+ if (streaming) /* Streaming was negotiated */
+ fastack(); /* ACK without ACKing. */
+ else
+#endif /* STREAMING */
+ ack(); /* acknowledge it */
+ BEGIN rdpkt; /* and switch to receive-data state */
+ return(-1);
+ } else { /* otherwise */
+ errpkt((CHAR *) rf_err); /* send error packet */
+ RESUME; /* and quit. */
+ return(-1);
+ }
+ }
+}
+
+static int
+rcv_shortreply() {
+#ifdef PKTZEROHACK
+ success = 0;
+ debug(F111,"rcv_shortreply",rdatap,ipktlen);
+ if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) {
+ /* No it's the ACK to the I packet again */
+ x = scmd(vcmd,(CHAR *)cmarg); /* So send the REMOTE command again */
+ /* Maybe this should be resend() */
+ debug(F110,"IPKTZEROHACK",ipktack,x);
+ if (x < 0) {
+ errpkt((CHAR *)srimsg);
+ RESUME;
+ return(-1);
+ }
+ } else {
+ ipktack[0] = NUL;
+#endif /* PKTZEROHACK */
+ urserver = 1;
+#ifndef NOSERVER
+#ifndef NOSPL
+ if (query) { /* If to query, */
+ qbufp = querybuf; /* initialize query response buffer */
+ qbufn = 0;
+ querybuf[0] = NUL;
+ }
+#endif /* NOSPL */
+ x = 1;
+ if (remfile) { /* Response redirected to file */
+ rf_err = "Can't open file";
+ if (rempipe) /* or pipe */
+ x =
+#ifndef NOPUSH
+ zxcmd(ZOFILE,remdest) /* Pipe: Start command */
+#else
+ 0
+#endif /* NOPUSH */
+ ;
+ else
+ x = opena(remdest,&iattr); /* File: Open with attributes */
+ debug(F111,"rcv_shortreply remfile",remdest,x);
+ } else {
+ x = opent(&iattr); /* "open" the screen */
+ }
+ if (x) { /* If file was opened ok */
+ if (decode(rdatap,
+#ifndef NOSPL
+ (query || !remfile) ? puttrm :
+#else
+ !remfile ? puttrm :
+#endif /* NOSPL */
+ zputfil, 1) < 0) { /* Note: zputfil, not putfil. */
+ errpkt((CHAR *)"Error writing data");
+ RESUME;
+ return(-1);
+ } else {
+ if (rdatap) /* If we had data */
+ if (*rdatap) /* add a line terminator */
+ if (remfile) { /* to file */
+ zsoutl(ZOFILE,"");
+ } else { /* or to screen. */
+#ifndef NOICP
+ if (!query || !xcmdsrc)
+#endif /* NOICP */
+ if (!(quiet && rcdactive))
+ conoll("");
+ }
+ if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */
+ msleep(500); /* command and got the ACK... */
+ bye_active = 0;
+ ttclos(0);
+ }
+ clsof(0);
+ if (!epktsent && !epktrcvd) /* If no error packet... */
+ success = 1; /* success. */
+ RESUME;
+ return(-1);
+ }
+ } else { /* File not opened OK */
+ errpkt((CHAR *) rf_err); /* send error message */
+ RESUME; /* and quit. */
+ return(-1);
+ }
+#endif /* NOSERVER */
+#ifdef PKTZEROHACK
+ }
+#endif /* PKTZEROHACK */
+ debug(F101,"rcv_shortreply fallthru","",success);
+ return(-1);
+}
+
+
+static int
+srv_query() {
+#ifndef NOSERVER
+#ifndef NOSPL
+ char c;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ c = *(srvcmd+2); /* Q = Query, S = Set */
+ if (c == 'Q') { /* Query */
+ if (!ENABLED(en_que)) { /* Security */
+ errpkt((CHAR *)"REMOTE QUERY disabled");
+ RESUME;
+ return(-1);
+ } else { /* Query allowed */
+ int n; char *p, *q;
+ qbufp = querybuf; /* Wipe out old stuff */
+ qbufn = 0;
+ querybuf[0] = NUL;
+ p = (char *) srvcmd + 3; /* Pointer for making wrapper */
+ n = strlen((char *)srvcmd); /* Position of end */
+ c = *(srvcmd+4); /* Which type of variable */
+
+ if (*(srvcmd+6) == CMDQ) { /* Starts with command quote? */
+ p = (char *) srvcmd + 6; /* Take it literally */
+ if (*p == CMDQ) p++;
+ } else { /* They played by the rules */
+ if (c == 'K') { /* Kermit variable */
+ int k;
+ k = (int) strlen(p);
+ if (k > 0 && p[k-1] == ')') {
+ p = (char *)(srvcmd + 4);
+ *(srvcmd+4) = CMDQ;
+ *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
+ } else {
+ *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
+ *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
+ *(srvcmd+5) = '('; /* around variable name */
+ *(srvcmd+n) = ')';
+ *(srvcmd+n+1) = NUL;
+ }
+ } else {
+ *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
+ *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
+ *(srvcmd+5) = '('; /* around variable name */
+ *(srvcmd+n) = ')';
+ *(srvcmd+n+1) = NUL;
+ if (c == 'S') { /* System variable */
+ *(srvcmd+4) = '$'; /* so it's \$(...) */
+ } else if (c == 'G') { /* Non-\ Global variable */
+ *(srvcmd+4) = 'm'; /* so wrap it in \m(...) */
+ }
+ }
+ } /* Now evaluate it */
+ n = QBUFL; /* Max length */
+ q = querybuf; /* Where to put it */
+ if (zzstring(p,&q,&n) < 0) {
+ errpkt((n > 0) ? (CHAR *)"Can't get value"
+ : (CHAR *)"Value too long"
+ );
+ RESUME;
+ return(-1);
+ } else {
+ if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
+ ack1(data); /* If it fits, send it back in ACK */
+ success = 1;
+ RESUME;
+ return(-1);
+ } else if (sndstring(querybuf)) { /* Long form response */
+ BEGIN ssinit;
+ return(-1);
+ } else { /* sndhlp() fails */
+ errpkt((CHAR *)"Can't send value");
+ RESUME;
+ return(-1);
+ }
+ }
+ }
+ } else if (c == 'S') { /* Set (assign) */
+ if (!ENABLED(en_asg)) { /* Security */
+ errpkt((CHAR *)"REMOTE ASSIGN disabled");
+ RESUME;
+ return(-1);
+ } else { /* OK */
+ int n;
+ n = xunchar(*(srvcmd+3)); /* Length of name */
+ n = 3 + n + 1; /* Position of length of value */
+ *(srvcmd+n) = NUL; /* Don't need it */
+ if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
+ errpkt((CHAR *)"REMOTE ASSIGN failed");
+ else {
+ ack();
+ success = 1;
+ }
+ RESUME;
+ return(-1);
+ }
+ } else {
+ errpkt((CHAR *)"Badly formed server command");
+ RESUME;
+ return(-1);
+ }
+#else
+ errpkt((CHAR *)"Variable query/set not available");
+ RESUME;
+ return(-1);
+#endif /* NOSPL */
+#endif /* NOSERVER */
+}
+
+static int
+srv_copy() {
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef ZCOPY
+ if (!ENABLED(en_cpy)) {
+ errpkt((CHAR *)"REMOTE COPY disabled");
+ RESUME;
+ return(-1);
+ } else {
+ char *str1, *str2, f1[256], f2[256];
+ int len1, len2;
+ len1 = xunchar(srvcmd[1]); /* Separate the parameters */
+ len2 = xunchar(srvcmd[2+len1]);
+ strncpy(f1,(char *)(srvcmd+2),len1);
+ f1[len1] = NUL;
+ strncpy(f2,(char *)(srvcmd+3+len1),len2);
+ f2[len2] = NUL;
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2);
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* If CWD is disabled */
+ zstrip(f1,&str1); /* and they included a pathname, */
+ zstrip(f2,&str2);
+ if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ return(-1);
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ if (zcopy(f1,f2)) { /* Try */
+ errpkt((CHAR *)"Can't copy file"); /* give error message */
+ } else {
+ success = 1;
+ ack();
+ }
+ RESUME; /* wait for next server command */
+ return(-1);
+ }
+ }
+ return(-1);
+#else /* no ZCOPY */
+ errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
+ RESUME; /* wait for next server command */
+ return(-1);
+#endif /* ZCOPY */
+#endif /* NOSERVER */
+}
+
+static int
+srv_rename() {
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef ZRENAME
+ if (!ENABLED(en_ren)) {
+ errpkt((CHAR *)"REMOTE RENAME disabled");
+ RESUME;
+ return(-1);
+ } else { /* RENAME is enabled */
+ char *str1, *str2, f1[256], f2[256];
+ int len1, len2;
+ len1 = xunchar(srvcmd[1]); /* Separate the parameters */
+ len2 = xunchar(srvcmd[2+len1]);
+ strncpy(f1,(char *)(srvcmd+2),len1);
+ f1[len1] = NUL;
+ strncpy(f2,(char *)(srvcmd+3+len1),len2);
+ f2[len2] = NUL;
+ len2 = xunchar(srvcmd[2+len1]);
+ strncpy(f1,(char *)(srvcmd+2),len1);
+ f1[len1] = NUL;
+ strncpy(f2,(char *)(srvcmd+3+len1),len2);
+ f2[len2] = NUL;
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2);
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* If CWD is disabled */
+ zstrip(f1,&str1); /* and they included a pathname, */
+ zstrip(f2,&str2);
+ if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ return(-1);
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ if (zrename(f1,f2)) { /* Try */
+ errpkt((CHAR *)"Can't rename file"); /* Give error msg */
+ } else {
+ success = 1;
+ ack();
+ }
+ RESUME; /* Wait for next server command */
+ return(-1);
+ }
+ }
+ return(-1);
+#else /* no ZRENAME */
+ /* Give error message */
+ errpkt((CHAR *)"REMOTE RENAME not available");
+ RESUME; /* Wait for next server command */
+ return(-1);
+#endif /* ZRENAME */
+#endif /* NOSERVER */
+}
+
+static int
+srv_login() {
+#ifndef NOSERVER
+ char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
+ CHAR *p;
+ int len, i;
+
+ debug(F101,"REMOTE LOGIN x_login","",x_login);
+ debug(F101,"REMOTE LOGIN x_logged","",x_logged);
+
+ f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
+ len = 0;
+ if (srvcmd[1]) /* First length field */
+ len = xunchar(srvcmd[1]); /* Separate the parameters */
+
+ if (x_login) { /* Login required */
+ if (x_logged) { /* And already logged in */
+ if (len > 0) { /* Logging in again */
+ errpkt((CHAR *)"Already logged in.");
+ } else { /* Logging out */
+ debug(F101,"REMOTE LOGOUT","",x_logged);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", "");
+#endif /* IKSDB */
+ tlog(F110,"Logged out",x_user,0);
+ ack1((CHAR *)"Logged out");
+ success = 1;
+ msleep(500);
+#ifdef CK_LOGIN
+ x_logged = 0;
+#ifdef IKSD
+ if (inserver)
+ ckxlogout();
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+ }
+ } else { /* Not logged in yet */
+ debug(F101,"REMOTE LOGIN len","",len);
+ if (len > 0) { /* Have username */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL);
+#endif /* CKSYSLOG */
+ if (len > LOGINLEN) {
+ errpkt((CHAR *)"Username too long");
+ }
+ p = srvcmd + 2; /* Point to it */
+ for (i = 0; i < len; i++) /* Copy it */
+ f1[i] = p[i];
+ f1[len] = NUL; /* Terminate it */
+ p += len; /* Point to next length field */
+ if (*p) { /* If we have one */
+ len = xunchar(*p++); /* decode it */
+ if (len > 0 && len <= LOGINLEN) {
+ for (i = 0; i < len; i++) /* Same deal for password */
+ f2[i] = p[i];
+ f2[len] = NUL;
+ p += len; /* And account */
+ if (*p) {
+ len = xunchar(*p++);
+ if (len > 0 && len <= LOGINLEN) {
+ for (i = 0; i < len; i++)
+ f3[i] = p[i]; /* Set but never used */
+ f3[len] = NUL; /* (because account not used) */
+ }
+ }
+ }
+ }
+ debug(F101,"REMOTE LOGIN 1","",x_logged);
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver) { /* Log in to system for real */
+ x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
+ debug(F101,"REMOTE LOGIN 2","",x_logged);
+ if (x_logged) { /* Count attempts */
+ logtries = 0;
+ justone = 1;
+ } else {
+ logtries++;
+ sleep(logtries);
+ }
+ } else
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ if (x_user && x_passwd) { /* User and password must match */
+ if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */
+ if (!strcmp(x_passwd,f2))
+ x_logged = 1;
+ debug(F101,"REMOTE LOGIN 3","",x_logged);
+ } else if (x_user) { /* Only username given, no password */
+ if (!strcmp(x_user,f1)) /* so only username must match */
+ x_logged = 1;
+ debug(F101,"REMOTE LOGIN 4","",x_logged);
+ }
+#ifdef CK_LOGIN
+ else {
+ x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
+ debug(F101,"REMOTE LOGIN 5","",x_logged);
+ }
+#endif /* CK_LOGIN */
+ if (x_logged) { /* Logged in? */
+ tlog(F110,"Logged in", x_user, 0);
+ if (isguest)
+ ack1((CHAR *)"Logged in as guest - restrictions apply");
+ else
+ ack1((CHAR *)"Logged in");
+ success = 1;
+ } else {
+ tlog(F110,"Login failed", f1, 0);
+ errpkt((CHAR *)"Access denied.");
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && logtries > 2)
+ ckxlogout();
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ }
+ } else { /* LOGOUT */
+ errpkt((CHAR *)"Logout ignored");
+ }
+ }
+ } else { /* Login not required */
+ if (len > 0)
+ errpkt((CHAR *)"Login ignored.");
+ else
+ errpkt((CHAR *)"Logout ignored.");
+ }
+#endif /* NOSERVER */
+ RESUME;
+ return(-1);
+}
+
+static int
+srv_timeout() {
+ /* K95 does this its own way */
+ if (idletmo) {
+#ifdef IKSD
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl);
+ doexit(GOOD_EXIT,xitsta);
+ }
+#endif /* IKSD */
+ idletmo = 0;
+ printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl);
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ }
+#ifndef NOSERVER
+ else if (fatalio) { /* Connection lost */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, "");
+#endif /* IKSDB */
+ xitsta |= what;
+ QUIT;
+ } else if (interrupted) { /* Interrupted by hand */
+ if (!ENABLED(en_fin)) {
+ errpkt((CHAR *)"QUIT disabled");
+ RESUME;
+ return(-1);
+ } else {
+ if (what == W_SEND || what == W_RECV || what == W_REMO) {
+ success = 0;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
+#endif /* CKSYSLOG */
+ } else if (what == W_NOTHING && filcnt == 0) {
+ success = 1;
+ } /* Otherwise leave success alone */
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ }
+ } else { /* Shouldn't happen */
+ debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0);
+ QUIT;
+ }
+#endif /* NOSERVER */
+}
+
+static int
+rcv_s_pkt() {
+#ifndef NOSERVER
+ if (state == rgen)
+ urserver = 1;
+ if (/* state == serve && */ x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else
+#endif /* NOSERVER */
+ if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
+ errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
+ RESUME;
+ return(-1);
+ } else { /* OK to go ahead. */
+#ifdef CK_TMPDIR
+ if (dldir && !f_tmpdir) { /* If they have a download directory */
+ debug(F110,"receive download dir",dldir,0);
+ if (s = zgtdir()) { /* Get current directory */
+ debug(F110,"receive current dir",s,0);
+ if (zchdir(dldir)) { /* Change to download directory */
+ debug(F100,"receive zchdir ok","",0);
+ ckstrncpy(savdir,s,TMPDIRLEN);
+ f_tmpdir = 1; /* Remember that we did this */
+ } else
+ debug(F100,"receive zchdir failed","",0);
+ }
+ }
+#endif /* CK_TMPDIR */
+ nakstate = 1; /* Can send NAKs from here. */
+ rinit(rdatap); /* Set parameters */
+ bctu = bctr; /* Switch to agreed-upon block check */
+ bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
+ what = W_RECV; /* Remember we're receiving */
+ lastxfer = W_RECV;
+ resetc(); /* Reset counters */
+ rtimer(); /* Reset timer */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ streamon();
+ BEGIN rfile; /* Go into receive-file state */
+ }
+ return(-1);
+}
+
+
+/* END OF ROUTINES MOVED OUT OF STATE MACHINE */
+
+
+/* P R O T O -- Protocol entry function */
+
+static int is_tn = 0; /* It's a Telnet connection */
+
+#ifdef CK_SPEED
+int f_ctlp = 0; /* Control-character prefix table */
+#ifdef COMMENT
+short s_ctlp[256];
+#endif /* COMMENT */
+#endif /* CK_SPEED */
+
+/*
+ This is simply a wrapper for the real protocol function just below,
+ that saves any items that might be changed automatically by protocol
+ negotiations and then restores them upon exit from protocol mode.
+*/
+VOID
+proto() {
+ extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear;
+#ifndef NOCSETS
+ extern int fcharset, fcs_save, tcharset, tcs_save;
+#endif /* NOCSETS */
+
+#ifdef PIPESEND
+ extern int pipesend;
+#endif /* PIPESEND */
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int cursorena[], cursor_save, term_io;
+ extern BYTE vmode;
+ extern int display_demo;
+ int term_io_save;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef TNCODE
+ int _u_bin=0, _me_bin = 0;
+#ifdef IKS_OPTION
+ int /* _u_start=0, */ _me_start = 0;
+#endif /* IKS_OPTION */
+#endif /* TNCODE */
+#ifdef PATTERNS
+ int pa_save;
+ int i;
+#endif /* PATTERNS */
+ int scan_save;
+
+#ifdef PATTERNS
+ pa_save = patterns;
+#endif /* PATTERNS */
+ scan_save = filepeek;
+
+ myjob = sstate;
+
+#ifdef CK_LOGIN
+ if (isguest) { /* If user is anonymous */
+ en_pri = 0; /* disable printing */
+ en_mai = 0; /* and disable email */
+ en_del = 0; /* and file deletion */
+ }
+#endif /* CK_LOGIN */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ cursor_save = cursorena[vmode];
+ cursorena[vmode] = 0;
+ term_io_save = term_io;
+ term_io = 0;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ b_save = binary; /* SET FILE TYPE */
+ f_save = fncnv; /* SET FILE NAMES */
+ c_save = bctr;
+ p_save = fnspath;
+ r_save = recursive;
+ s_timint = timint;
+ ss_save = slostart;
+#ifndef NOCSETS
+ fcs_save = fcharset;
+ tcs_save = tcharset;
+#endif /* NOCSETS */
+
+#ifdef COMMENT
+/* Don't do this because then user can never find out what happened. */
+#ifdef CK_SPEED
+ for (i = 0; i < 256; i++)
+ s_ctlp[i] = ctlp[i];
+ f_ctlp = 1;
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+ if (reliable == SET_ON)
+ slostart = 0;
+ is_tn = (!local && sstelnet)
+#ifdef TNCODE
+ || (local && network && ttnproto == NP_TELNET)
+#endif /* TNCODE */
+ ;
+#ifdef TNCODE
+ if (is_tn) {
+ if (tn_b_xfer && !(sstelnet || inserver)) {
+ /* Save the current state of Telnet Binary */
+ _u_bin = TELOPT_U(TELOPT_BINARY);
+ _me_bin = TELOPT_ME(TELOPT_BINARY);
+
+ /* If either direction is not Binary attempt to negotiate it */
+ if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) {
+ tn_sopt(DO,TELOPT_BINARY);
+ TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
+ }
+ if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) {
+ tn_sopt(WILL,TELOPT_BINARY);
+ TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
+ }
+ if (!(_me_bin && _u_bin))
+ tn_wait("proto set binary mode");
+ }
+#ifdef IKS_OPTION
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
+ /* _u_start = 1; */
+ }
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_STOP); /* I'm not servering */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ _me_start = 1;
+ }
+ } else
+#endif /* CK_XYZ */
+ if (sstate == 'x' || sstate == 'v') { /* Responding to a request */
+ if (!inserver && TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
+ /* _u_start = 1; */
+ }
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_START); /* Send Kermit-Server Start */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
+ }
+ } else { /* Initiating a request */
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_STOP); /* I'm not servering */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ _me_start = 1;
+ }
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ /* Send Req-Server-Start */
+ if (!iks_wait(KERMIT_REQ_START,0)) {
+ if (sstate != 's') {
+ success = 0; /* Other Kermit refused to serve */
+ if (local)
+ printf("A Kermit Server is not available\r\n");
+ debug(F110,"proto()",
+ "A Kermit Server is not available",0);
+ tlog(F110,"IKS client/server failure",
+ "A Kermit Server is not available",0);
+ goto xxprotox;
+ }
+ }
+ }
+ }
+#endif /* IKS_OPTION */
+#ifdef CK_ENCRYPTION
+ if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
+ ck_tn_enc_stop();
+ }
+#endif /* CK_ENCRYPTION */
+ }
+#endif /* TNCODE */
+
+ if (!xfrint) connoi();
+ xxproto(); /* Call the real protocol function */
+
+#ifdef IKS_OPTION
+ xxprotox:
+#endif /* IKS_OPTION */
+ xferstat = success; /* Remember transfer status */
+ kactive = 0;
+
+#ifdef TNCODE
+#ifdef CK_ENCRYPTION
+ if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
+ ck_tn_enc_start();
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) {
+ tn_siks(KERMIT_STOP); /* Server is stopped */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ }
+#endif /* IKS_OPTION */
+ if (is_tn && tn_b_xfer && !(sstelnet || inserver)) {
+ /* if we negotiated Binary mode try to reset it */
+ if (!_u_bin) {
+ /* Check to see if the state changed during the transfer */
+ if (TELOPT_U(TELOPT_BINARY)) {
+ tn_sopt(DONT,TELOPT_BINARY);
+ TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1;
+ } else
+ _u_bin = 1; /* So we don't call tn_wait() */
+ }
+ if (!_me_bin) {
+ /* Check to see if the state changed during the transfer */
+ if (TELOPT_ME(TELOPT_BINARY)) {
+ tn_sopt(WONT,TELOPT_BINARY);
+ TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1;
+ } else
+ _me_bin = 1; /* So we don't call tn_wait() */
+ }
+ if (!(_me_bin && _u_bin))
+ tn_wait("proto reset binary mode");
+ }
+#endif /* TNCODE */
+
+#ifdef PATTERNS
+ patterns = pa_save;
+#endif /* PATTERNS */
+ filepeek = scan_save;
+
+#ifdef STREAMING
+ streaming = 0;
+ /* streamok = 0; */
+#endif /* STREAMING */
+#ifdef COMMENT
+#ifdef CK_SPEED
+ for (i = 0; i < 256; i++)
+ ctlp[i] = s_ctlp[i];
+ f_ctlp = 0;
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+ urclear = 0;
+ if (!success) {
+ xitsta |= (what & W_KERMIT);
+ tlog(F110," failed:",(char *)epktmsg,0);
+ }
+ debug(F111,"proto xferstat",epktmsg,xferstat);
+ slostart = ss_save;
+ if (s_timint > -1) { /* Because of REMOTE SET */
+ timint = s_timint;
+ s_timint = -1;
+ }
+ recursive = r_save;
+ fnspath = p_save;
+ if (c_save > -1) { /* Because of REMOTE SET */
+ bctr = c_save;
+ c_save = -1;
+ }
+ fncnv = f_save;
+ binary = b_save;
+#ifdef PIPESEND
+ pipesend = 0; /* Next time might not be pipesend */
+#endif /* PIPESEND */
+#ifndef NOLOCAL
+#ifdef OS2
+ cursorena[vmode] = cursor_save;
+ term_io = term_io_save;
+ display_demo = 1;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+}
+
+static VOID
+xxproto() {
+ int x;
+ long lx;
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+_PROTOTYP( int pxyz, (int) );
+#endif /* XYZ_INTERNAL */
+#endif /* CK_XYZ */
+
+ char xss[2]; /* String representation of sstate */
+ xss[0] = sstate;
+ xss[1] = NUL;
+ s_timint = timint;
+
+ debug(F101,"xxproto entry justone","",justone);
+ success = 0;
+
+ retrieve = 0; /* Reset these ... */
+ reget = 0;
+ opkt = 0;
+
+ if (local && ttchk() < 0) { /* Giving BYE or FIN */
+ if (bye_active) { /* but there is no connection */
+ ttclos(0);
+ success = 1;
+ return;
+ }
+ /* Ditto for any REMOTE command */
+ if (sstate == 'g' && cmarg ) {
+ if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X')
+ success = 1;
+ else
+ printf("?No connection\r\n");
+ return;
+ }
+ }
+
+/* Set up the communication line for file transfer. */
+/* NOTE: All of the xxscreen() calls prior to the wart() invocation */
+/* could just as easily be printf's or, for that matter, hints. */
+
+ if (local && (speed < 0L) && (network == 0)) {
+ xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
+ return;
+ }
+ x = -1;
+ if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
+ debug(F111,"failed: proto ttopen local",ttname,local);
+ xxscreen(SCR_EM,0,0L,"Can't open line");
+ return;
+ }
+ if (x > -1) local = x;
+ debug(F111,"proto ttopen local",ttname,local);
+
+ lx = (local && !network) ? speed : -1;
+#ifdef NETCONN
+#ifdef CK_SPEED
+ if (is_tn) {
+ ctlp[(unsigned)255] = ctlp[CR] = 1;
+ if (parity == 'e' || parity == 'm') ctlp[127] = 1;
+ if (flow == FLO_XONX) { /* Also watch out for Xon/Xoff */
+ ctlp[17] = ctlp[19] = 1;
+ ctlp[17+128] = ctlp[19+128] = 1;
+ }
+ }
+#endif /* CK_SPEED */
+#endif /* NETCONN */
+ if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */
+ xxscreen(SCR_EM,0,0L,"Can't condition line");
+ return;
+ }
+ if (local && !network && carrier != CAR_OFF) {
+ int x; /* Serial connection */
+ x = ttgmdm(); /* with carrier checking */
+ if (x > -1) {
+ if (!(x & BM_DCD)) {
+ debug(F101,"proto ttgmdm","",0);
+ xxscreen(SCR_EM,0,0L,"Carrier required but not detected");
+ return;
+ }
+ }
+ }
+ /* Send remote side's "receive" or "server" startup string, if any */
+ if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) {
+ char *s = NULL;
+ if (
+#ifdef IKS_OPTION
+ /* Don't send auto-blah string if we know other side is serving */
+ !TELOPT_U(TELOPT_KERMIT) ||
+ !TELOPT_SB(TELOPT_KERMIT).kermit.u_start
+#else
+ 1
+#endif /* IKS_OPTION */
+ ) {
+ if (sstate == 's') { /* Sending file(s) */
+ s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
+ } else if (protocol == PROTO_K) { /* Command for server */
+ s = ptab[protocol].h_x_init;
+ }
+ }
+#ifdef CK_SPEED
+#ifndef UNPREFIXZERO
+ if (protocol == PROTO_K) /* Because of C-strings... */
+ ctlp[0] = 1;
+#endif /* UNPREFIXZERO */
+#endif /* CK_SPEED */
+ if (s) if (*s) { /* If we have a command to send... */
+ char tmpbuf[356];
+ int tmpbufsiz = 356;
+ int stuff = -1, stuff2 = -1, len = 0;
+ extern int tnlm;
+ if (sstate == 's') { /* Sending file(s) */
+#ifdef CK_XYZ
+ if (protocol == PROTO_X) {
+ char * s2;
+ s2 = cmarg2[0] ? cmarg2 : cmarg;
+ if ((int)strlen(s) + (int)strlen(s2) + 4 < 356)
+ sprintf(tmpbuf, s, s2);
+ else
+ tmpbuf[0] = NUL;
+ } else {
+#endif /* CK_XYZ */
+ ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL);
+#ifdef CK_XYZ
+ }
+#endif /* CK_XYZ */
+ } else { /* Command for server */
+ ckstrncpy(tmpbuf,s,356);
+ }
+ ckstrncat(tmpbuf, "\015",sizeof(tmpbuf));
+ if (tnlm) /* TERMINAL NEWLINE ON */
+ stuff = LF; /* Stuff LF */
+#ifdef TNCODE
+ /* TELNET NEWLINE MODE */
+ if (is_tn) {
+ switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
+ case TNL_CR:
+ break;
+ case TNL_CRNUL:
+ break;
+ case TNL_CRLF:
+ stuff2 = stuff;
+ stuff = LF;
+ break;
+ }
+ }
+#endif /* TNCODE */
+
+#ifdef NETCONN
+#ifdef TCPSOCKET
+#ifdef RLOGCODE
+ if (network && ttnproto == NP_RLOGIN) {
+ switch (tn_b_nlm) { /* Always BINARY */
+ case TNL_CR:
+ break;
+ case TNL_CRNUL:
+ stuff2 = stuff;
+ stuff = NUL;
+ break;
+ case TNL_CRLF:
+ stuff2 = stuff;
+ stuff = LF;
+ break;
+ }
+ }
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+
+ len = strlen(tmpbuf);
+ if (stuff >= 0 && len < tmpbufsiz - 1) {
+ tmpbuf[len++] = stuff;
+ if (stuff2 >= 0 && len < tmpbufsiz - 1)
+ tmpbuf[len++] = stuff2;
+ tmpbuf[len] = NUL;
+ }
+ ttol((CHAR *)tmpbuf,len);
+ if (protocol == PROTO_K) /* Give remote Kermit time to start */
+ msleep(400);
+ }
+ }
+
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
+ char tmpbuf[356];
+ int tmpbufsiz = 356;
+ char * s = "";
+
+#ifdef CK_TMPDIR
+ if (sstate == 'v') { /* If receiving and... */
+ if (dldir && !f_tmpdir) { /* if they have a download directory */
+ if (s = zgtdir()) { /* Get current directory */
+ if (zchdir(dldir)) { /* Change to download directory */
+ ckstrncpy(savdir,s,TMPDIRLEN);
+ f_tmpdir = 1; /* Remember that we did this */
+ }
+ }
+ }
+ }
+#endif /* CK_TMPDIR */
+
+#ifdef XYZ_INTERNAL /* Internal */
+ success = !pxyz(sstate);
+#else
+#ifdef CK_REDIR /* External */
+ switch (sstate) {
+ case 's': /* 'Tis better to SEND... */
+ s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
+ break;
+ case 'v': /* ... than RECEIVE */
+ s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
+ break;
+ }
+ if (!s) s = "";
+ if (*s) {
+ if (sstate == 's') { /* Sending */
+ extern int xfermode;
+ int k = 0, x = 0, b = binary;
+ /*
+ If just one file we can scan it to set the xfer mode.
+ Otherwise it's up to the external protocol program.
+ */
+ if (patterns && xfermode == XMODE_A && !iswild(fspec)) {
+ extern int nscanfile;
+ k = scanfile(fspec,&x,nscanfile);
+ if (k > -1) {
+ b = (k == FT_BIN) ? XYFT_B : XYFT_T;
+ s = b ?
+ ptab[protocol].p_b_scmd :
+ ptab[protocol].p_t_scmd;
+ }
+ }
+ if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
+ sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
+ tlog(F110,"Sending",fspec,0L);
+ }
+ } else { /* Receiving */
+ if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) {
+ sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */
+ tlog(F110,"Receiving",cmarg2,0L);
+ }
+ }
+ tlog(F110," via external protocol:",tmpbuf,0);
+ debug(F110,"ckcpro ttruncmd",tmpbuf,0);
+ success = ttruncmd(tmpbuf);
+ tlog(F110," status:",success ? "OK" : "FAILED", 0);
+ } else {
+ printf("?Sorry, no external protocol defined for %s\r\n",
+ ptab[protocol].p_name
+ );
+ }
+#else
+ printf(
+"Sorry, only Kermit protocol is supported in this version of Kermit\n"
+ );
+#endif /* CK_REDIR */
+#endif /* XYZ_INTERNAL */
+ return;
+ }
+#endif /* CK_XYZ */
+
+#ifdef NTSIGX
+ conraw();
+ connoi();
+#else
+ if (!local)
+ connoi(); /* No console interrupts if remote */
+#endif /* NTSIG */
+
+ kactive = 1;
+ if (sstate == 'x') { /* If entering server mode, */
+ extern int howcalled;
+ server = 1; /* set flag, */
+ debug(F101,"server backgrd","",backgrd);
+ debug(F101,"server quiet","",quiet);
+ debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
+ if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */
+ ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
+ } else if (!local) {
+ if (!quiet && !backgrd
+#ifdef IKS_OPTION
+ && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */
+#endif /* IKS_OPTION */
+ ) {
+ conoll(srvtxt);
+ conoll("KERMIT READY TO SERVE...");
+ }
+ } else {
+ conol("Entering server mode on ");
+ conoll(ttname);
+ conoll("Type Ctrl-C to quit.");
+ if (srvdis) intmsg(-1L);
+#ifdef TCPSOCKET
+#ifndef NOLISTEN
+ if (network && tcpsrfd > 0)
+ ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
+#endif /* NOLISTEN */
+#endif /* TCPSOCKET */
+ }
+ } else
+ server = 0;
+#ifdef VMS
+ if (!quiet && !backgrd) /* So message doesn't overwrite prompt */
+ conoll("");
+ if (local) conres(); /* So Ctrl-C will work */
+#endif /* VMS */
+/*
+ If in remote mode, not shushed, not in background, and at top command level,
+ issue a helpful message telling what to do...
+*/
+ if (!local && !quiet && !backgrd) {
+ if (sstate == 'v') {
+ conoll("Return to your local Kermit and give a SEND command.");
+ conoll("");
+ conoll("KERMIT READY TO RECEIVE...");
+ } else if (sstate == 's') {
+ conoll("Return to your local Kermit and give a RECEIVE command.");
+ conoll("");
+ conoll("KERMIT READY TO SEND...");
+ } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
+ sstate == 'j' || sstate == 'c' ) {
+ conoll("Return to your local Kermit and give a SERVER command.");
+ conoll("");
+ conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
+ "KERMIT READY TO GET..." :
+ "KERMIT READY TO SEND SERVER COMMAND...");
+ }
+ }
+#ifdef COMMENT
+ if (!local) sleep(1);
+#endif /* COMMENT */
+/*
+ The 'wart()' function is generated by the wart program. It gets a
+ character from the input() routine and then based on that character and
+ the current state, selects the appropriate action, according to the state
+ table above, which is transformed by the wart program into a big case
+ statement. The function is active for one transaction.
+*/
+ rtimer(); /* Reset elapsed-time timer */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ resetc(); /* & other per-transaction counters. */
+
+ debug(F101,"proto calling wart, justone","",justone);
+
+ wart(); /* Enter the state table switcher. */
+/*
+ Note: the following is necessary in case we have just done a remote-mode
+ file transfer, in which case the controlling terminal modes have been
+ changed by ttpkt(). In particular, special characters like Ctrl-C and
+ Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is
+ essential. IMPORTANT: restore interrupt handlers first, otherwise any
+ terminal interrupts that occur before this is done in the normal place
+ later will cause a crash.
+*/
+#ifdef OS2
+ ttres(); /* Reset the communication device */
+#else
+ if (!local) {
+ setint(); /* Arm interrupt handlers FIRST */
+ msleep(500);
+ ttres(); /* Then restore terminal. */
+ }
+#endif /* OS2 */
+ xxscreen(SCR_TC,0,0L,""); /* Transaction complete */
+ x = quiet;
+ quiet=1;
+ clsif(); /* Failsafe in case we missed */
+ clsof(1); /* a case in the state machine. */
+ quiet = x;
+
+ if (server) { /* Back from packet protocol. */
+ if (!quiet && !backgrd
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) { /* Give appropriate message */
+ conoll("");
+ conoll("C-Kermit server done");
+ }
+ server = 0; /* Not a server any more */
+ }
+}
+
+/* S G E T I N I T -- Handle incoming GET-Class packets */
+
+/*
+ Returns:
+ -1: On error
+ 0: GET packet processed OK - ready to Send.
+ 1: Extended GET processed OK - wait for another.
+*/
+static int
+sgetinit(reget,xget) int reget, xget; { /* Server end of GET command */
+ char * fs = NULL; /* Pointer to filespec */
+ int i, n, done = 0;
+#ifdef PIPESEND
+ extern int usepipes, pipesend;
+#endif /* PIPESEND */
+ extern int nolinks;
+
+ if (!ENABLED(en_get)) { /* Only if not disabled! */
+ errpkt((CHAR *)"GET disabled");
+ return(-1);
+ }
+
+ /* OK to proceed */
+
+ nolinks = recursive;
+ filcnt = 0;
+
+#ifdef WHATAMI
+ /* If they are alike this was already done in whoarewe() */
+ debug(F101,"sgetinit whatru","",whatru);
+ if (whatru & WMI_FLAG) { /* Did we get WHATAMI info? */
+ debug(F101,"sgetinit binary (1)","",binary);
+#ifdef VMS
+ if (binary != XYFT_I && binary != XYFT_L)
+#else
+#ifdef OS2
+ if (binary != XYFT_L)
+#endif /* OS2 */
+#endif /* VMS */
+ binary = (whatru & WMI_FMODE) ? /* Yes, set file type */
+ XYFT_B : XYFT_T; /* automatically */
+ debug(F101,"sgetinit binary (2)","",binary);
+ if (!wearealike)
+ fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */
+ }
+#endif /* WHATAMI */
+
+ fs = (char *)srvcmd;
+ srvptr = srvcmd; /* Point to server command buffer */
+ decode(rdatap,putsrv,0); /* Decode the GET command into it */
+ /* Accept multiple filespecs */
+ cmarg2 = ""; /* Don't use cmarg2 */
+ cmarg = ""; /* Don't use cmarg */
+
+ done = 1; /* Only 1 packet needed... */
+ if (xget) { /* Special decoding for Extended GET */
+ char L, next, c; /* PLV items */
+ int len, val; /* More PLV items */
+ char * p = (char *)srvcmd; /* String to decode */
+
+ done = 0; /* Maybe more packets needed */
+ fs = NULL; /* We don't know the filespec yet */
+ c = *p++; /* Get first parameter */
+
+ while (c) { /* For all parameters... */
+ debug(F000,"sgetinit c","",c);
+ L = *p++; /* Get length */
+ if (L >= SP) /* Decode length */
+ len = xunchar(L);
+ else if (c == '@') { /* Allow missing EOP length field */
+ len = 0;
+ } else {
+ len = (xunchar(*p++) * 95);
+ len += xunchar(*p++);
+ }
+ debug(F101,"sgetinit len","",len);
+ next = *(p+len); /* Get next parameter */
+ *(p+len) = NUL; /* Zero it out to terminal value */
+ debug(F110,"sgetinit p",p,0);
+ switch (c) { /* Do the parameter */
+ case 'O': /* GET Options */
+ val = atoi(p); /* Convert to int */
+ debug(F101,"sgetinit O val","",val);
+ if (val & GOPT_DEL) moving = 1;
+ if (val & GOPT_RES) reget = 1;
+ if (val & GOPT_REC) {
+ recursive = 1;
+ nolinks = 2;
+ if (fnspath == PATH_OFF)
+ fnspath = PATH_REL;
+ }
+ break;
+ case 'M': /* Transfer Mode */
+ val = atoi(p);
+ debug(F101,"sgetinit M val","",val);
+ if (val < 1)
+ break;
+ patterns = 0; /* Takes precedence over patterns */
+ filepeek = 0; /* and FILE SCAN */
+ if (val == GMOD_TXT) binary = XYFT_T; /* Text */
+ if (val == GMOD_BIN) binary = XYFT_B; /* Binary */
+ if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */
+ break;
+ case 'F': /* Filename */
+ fs = p;
+ debug(F110,"sgetinit filename",fs,0);
+ break;
+ case '@': /* End Of Parameters */
+ done = 1;
+ debug(F100,"sgetinit EOP","",0);
+ break;
+ default:
+ errpkt((CHAR *)"Unknown GET Parameter");
+ debug(F100,"sgetinit unknown parameter","",0);
+ return(-1);
+ }
+ p += (len + 1);
+ c = next;
+ }
+ }
+ if (!fs) fs = ""; /* A filename is required */
+ if (*fs) {
+ havefs = 1;
+ n = 0; /* Check for quoted name */
+ if ((n = strlen(fs)) > 1) {
+ /* Note: this does not allow for multiple quoted names */
+ if ((fs[0] == '{' && fs[n-1] == '}') ||
+ (fs[0] == '"' && fs[n-1] == '"')) {
+ fs[n-1] = '\0';
+ fs++;
+ debug(F111,"sgetinit unquoted filename",fs,n);
+ } else
+ n = 0; /* This means no quoting */
+ }
+
+#ifdef PIPESEND
+ debug(F111,"sgetinit",fs,usepipes);
+ if (usepipes && ENABLED(en_hos) && *fs == '!') {
+ cmarg = fs + 1; /* Point past the bang */
+ *fs = NUL;
+ nfils = -1;
+ pipesend = 1;
+ debug(F111,"sgetinit pipesend",cmarg,pipesend);
+ }
+ if (!pipesend) { /* If it's not a pipe */
+#endif /* PIPESEND */
+ if (n == 0) { /* If the name was not quoted */
+#ifndef NOMSEND
+ nfils = fnparse(fs); /* Allow it to be a list of names */
+ debug(F111,"sgetinit A",fs,nfils);
+#ifdef COMMENT
+/* This doesn't work if a GET-PATH is set. */
+ if (nfils == 1 && !iswild(fs)) { /* Single file */
+ char * m;
+ if ((x = zchki(fs)) < 0) { /* Check if it's sendable */
+ switch (x) {
+ case -1: m = "File not found"; break;
+ case -2: m = "Not a regular file"; break;
+ case -3: m = "Read access denied"; break;
+ }
+ errpkt((CHAR *)m);
+ return(-1);
+ }
+ }
+#endif /* COMMENT */
+ } else { /* If it was quoted */
+#endif /* NOMSEND */
+ nzxopts = 0;
+#ifdef UNIXOROSK
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+#endif /* UNIXOROSK */
+ if (recursive) nzxopts |= ZX_RECURSE;
+ /* Treat as a single filespec */
+ nfils = 0 - nzxpand(fs,nzxopts);
+ debug(F111,"sgetinit B",fs,nfils);
+ cmarg = fs;
+ }
+#ifdef PIPESEND
+ }
+#endif /* PIPESEND */
+ }
+ if (!done) { /* Need more O packets... */
+ debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */
+ return(1);
+ }
+ debug(F100,"sgetinit O-Packet done - havefs","",havefs);
+ if (!havefs) { /* Done - make sure we have filename */
+ errpkt((CHAR *)"GET without filename");
+ return(-1);
+ }
+ freerpkt(winlo);
+ winlo = 0; /* Back to packet 0 again. */
+ debug(F101,"sgetinit winlo","",winlo);
+ nakstate = 0; /* Now I'm the sender! */
+ if (reget) sendmode = SM_RESEND;
+ if (sinit() > 0) { /* Send Send-Init */
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
+ return(0); /* If successful, switch state */
+ } else return(-1); /* Else back to server command wait */
+}
+
+#else /* NOXFER */
+
+#include "ckcdeb.h"
+
+VOID
+proto() {
+ extern int success;
+ success = 0;
+}
+#endif /* NOXFER */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcpro.w b/ckermit-9.0.302-build/ckermit-9.0.302/ckcpro.w
new file mode 100644
index 0000000..a6b5f48
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcpro.w
@@ -0,0 +1,3633 @@
+char *protv = /* -*-C-*- */
+"C-Kermit Protocol Module 9.0.160, 16 Oct 2009";
+
+int kactive = 0; /* Kermit protocol is active */
+
+#define PKTZEROHACK
+
+/* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef NOXFER
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+#endif /* OS2 */
+
+/*
+ Note -- This file may also be preprocessed by the UNIX Lex program, but
+ you must indent the above #include statements before using Lex, and then
+ restore them to the left margin in the resulting C program before compilation.
+ Also, the invocation of the "wart()" function below must be replaced by an
+ invocation of the "yylex()" function. It might also be necessary to remove
+ comments in the (%)(%)...(%)(%) section.
+*/
+
+/* State definitions for Wart (or Lex) */
+%states ipkt rfile rattr rdpkt ssinit ssfile ssattr ssdata sseof sseot
+%states serve generic get rgen ssopkt ropkt
+
+_PROTOTYP(static VOID xxproto,(void));
+_PROTOTYP(static VOID wheremsg,(void));
+_PROTOTYP(int wart,(void));
+_PROTOTYP(static int sgetinit,(int,int));
+_PROTOTYP(int sndspace,(int));
+
+/* External C-Kermit variable declarations */
+ extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist, *rf_err;
+ extern char * rfspec, * sfspec, * srfspec, * rrfspec;
+ extern char * prfspec, * psfspec, * psrfspec, * prrfspec;
+ extern char *cdmsgfile[];
+ extern char * snd_move, * snd_rename, * srimsg;
+ extern char filnam[], ofilnam[], fspec[], ttname[], ofn1[];
+ extern CHAR sstate, *srvptr, *data;
+ extern int timint, rtimo, nfils, hcflg, xflg, flow, mdmtyp, network;
+ extern int oopts, omode, oname, opath, nopush, isguest, xcmdsrc, rcdactive;
+ extern int rejection, moving, fncact, bye_active, urserver, fatalio;
+ extern int protocol, prefixing, filcnt, carrier, fnspath, interrupted;
+ extern int recursive, inserver, nzxopts, idletmo, srvidl, xfrint;
+ extern struct ck_p ptab[];
+ extern int remfile, rempipe, xferstat, filestatus, wearealike, fackpath;
+ extern int patterns, filepeek, gnferror;
+ extern char * remdest;
+
+#ifdef PKTZEROHACK
+#define PKTZEROLEN 32
+static char ipktack[PKTZEROLEN];
+static int ipktlen = 0;
+#endif /* PKTZEROHACK */
+
+static int s_timint = -1; /* For saving timeout value */
+static int myjob = 0;
+static int havefs = 0;
+#ifdef CK_LOGIN
+static int logtries = 0;
+#endif /* CK_LOGIN */
+
+static int cancel = 0;
+int fackbug = 0;
+
+#ifdef STREAMING
+extern int streaming, streamok;
+
+static VOID
+streamon() {
+ if (streamok) {
+ debug(F100,"streamon","",0);
+ streaming = 1;
+ timint = 0; /* No timeouts while streaming. */
+ }
+}
+
+#ifdef COMMENT /* (not used) */
+static VOID
+streamoff() {
+ if (streaming) {
+ debug(F100,"streamoff","",0);
+ streaming = 0;
+ timint = s_timint; /* Restore timeout */
+ }
+}
+#endif /* COMMENT */
+#else /* STREAMING */
+#define streamon()
+#define streamoff()
+#endif /* STREAMING */
+
+#ifndef NOSPL
+_PROTOTYP( int addmac, (char *, char *) );
+_PROTOTYP( int zzstring, (char *, char **, int *) );
+#endif /* NOSPL */
+#ifndef NOICP
+_PROTOTYP( int cmdsrc, (void) );
+#endif /* NOICP */
+
+#ifndef NOSERVER
+ extern char * x_user, * x_passwd, * x_acct;
+ extern int x_login, x_logged;
+#endif /* NOSERVER */
+
+#include "ckcnet.h"
+
+#ifdef TNCODE
+ extern int ttnproto; /* Network protocol */
+#endif /* TNCODE */
+
+#ifdef CK_SPEED
+ extern short ctlp[]; /* Control-character prefix table */
+#endif /* CK_SPEED */
+
+#ifdef TNCODE
+ extern int tn_b_nlm, tn_b_xfer, tn_nlm;
+#ifdef CK_ENCRYPTION
+ extern int tn_no_encrypt_xfer;
+#endif /* CK_ENCRYPTION */
+#endif /* TNCODE */
+
+#ifdef TCPSOCKET
+#ifndef NOLISTEN
+ extern int tcpsrfd;
+#endif /* NOLISTEN */
+#endif /* TCPSOCKET */
+
+ extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl;
+ extern int bctf;
+ extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo;
+ extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla;
+ extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent;
+ extern int binary, fncnv;
+ extern long speed, ffc, crc16, calibrate, dest;
+#ifdef COMMENT
+ extern char *TYPCMD, *DIRCMD, *DIRCM2;
+#endif /* COMMENT */
+#ifndef OS2
+ extern char *SPACMD, *SPACM2, *WHOCMD;
+#endif /* OS2 */
+ extern CHAR *rdatap;
+ extern struct zattr iattr;
+
+#ifdef VMS
+ extern int batch;
+#endif /* VMS */
+
+#ifdef GFTIMER
+ extern CKFLOAT fptsecs;
+#endif /* GFTIMER */
+
+ extern CHAR *srvcmd;
+ extern CHAR *epktmsg;
+
+#ifdef CK_TMPDIR
+extern int f_tmpdir; /* Directory changed temporarily */
+extern char savdir[]; /* For saving current directory */
+extern char * dldir;
+#endif /* CK_TMPDIR */
+
+ extern int query; /* Query-active flag */
+#ifndef NOSPL
+ extern int cmdlvl;
+ char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */
+ char *qbufp = querybuf; /* Pointer to it */
+ int qbufn = 0; /* Length of data in it */
+#else
+ extern int tlevel;
+#endif /* NOSPL */
+
+#ifndef NOICP
+ extern int escape;
+#endif /* NOICP */
+/*
+ If the following flag is nonzero when the protocol module is entered,
+ then server mode persists for exactly one transaction, rather than
+ looping until BYE or FINISH is received.
+*/
+extern int justone;
+
+static int r_save = -1;
+static int p_save = -1;
+
+/* Function to let remote-mode user know where their file(s) went */
+
+int whereflg = 1; /* Unset with SET XFER REPORT */
+
+static VOID
+wheremsg() {
+ extern int quiet, filrej;
+ int n;
+ n = filcnt - filrej;
+ debug(F101,"wheremsg n","",n);
+
+ debug(F110,"wheremsg prfspec",prfspec,0);
+ debug(F110,"wheremsg rfspec",rfspec,0);
+ debug(F110,"wheremsg psfspec",psfspec,0);
+ debug(F110,"wheremsg sfspec",sfspec,0);
+
+ debug(F110,"wheremsg prrfspec",prrfspec,0);
+ debug(F110,"wheremsg rrfspec",rrfspec,0);
+ debug(F110,"wheremsg psrfspec",psrfspec,0);
+ debug(F110,"wheremsg srfspec",srfspec,0);
+
+ if (!quiet && !local) {
+ if (n == 1) {
+ switch (myjob) {
+ case 's':
+ if (sfspec) {
+ printf(" SENT: [%s]",sfspec);
+ if (srfspec)
+ printf(" To: [%s]",srfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ break;
+ case 'r':
+ case 'v':
+ if (rrfspec) {
+ printf(" RCVD: [%s]",rrfspec);
+ if (rfspec)
+ printf(" To: [%s]",rfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ }
+ } else if (n > 1) {
+ switch (myjob) {
+ case 's':
+ if (sfspec) {
+ printf(" SENT: (%d files)",n);
+ if (srfspec)
+ printf(" Last: [%s]",srfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ break;
+ case 'r':
+ case 'v':
+ if (rrfspec) {
+ printf(" RCVD: (%d files)",n);
+ if (rfspec)
+ printf(" Last: [%s]",rfspec);
+ printf(" (%s)\r\n", success ? "OK" : "FAILED");
+ }
+ }
+ } else if (n == 0) {
+ if (myjob == 's')
+ printf(" SENT: (0 files) \r\n");
+ else if (myjob == 'r' || myjob == 'v')
+ printf(" RCVD: (0 files) \r\n");
+ }
+ }
+}
+
+static VOID
+rdebug() {
+ if (server)
+ debug(F111,"RESUME","server=1",justone);
+ else
+ debug(F111,"RESUME","server=0",justone);
+}
+
+/* Flags for the ENABLE and DISABLE commands */
+extern int
+ en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
+ en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
+ en_mkd, en_rmd;
+#ifndef NOSPL
+extern int en_asg, en_que;
+#endif /* NOSPL */
+extern int what, lastxfer;
+
+/* Global variables declared here */
+
+ int whatru = 0; /* What are you. */
+ int whatru2 = 0; /* What are you, cont'd. */
+
+/* Local variables */
+
+ static char vstate = 0; /* Saved State */
+ static char vcmd = 0; /* Saved Command */
+ static int reget = 0; /* Flag for executing REGET */
+ static int retrieve = 0; /* Flag for executing RETRIEVE */
+ static int opkt = 0; /* Send Extended GET packet */
+
+ static int x; /* General-purpose integer */
+ static char *s; /* General-purpose string pointer */
+
+/* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */
+/* BEGIN is NOT a GOTO! */
+#define TINIT if (tinit(1) < 0) return(-9)
+#define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \
+sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; }
+#define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \
+if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } }
+
+#ifdef GFTIMER
+#define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \
+ fptsecs=gftimer(); quiet=x; return(success)
+#else
+#define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \
+ return(success)
+#endif /* GFTIMER */
+
+/*
+ By late 1999, the big switch() statement generated from the following state
+ table began choking even gcc, so here we extract the code from the larger
+ states into static routines to reduce the size of the cases and the
+ switch() overall. The routines follow the state table; the prototypes are
+ here. Each of these routines simply contains the text from the
+ corresponding case, but with return(-1) added in appropriate places; see
+ instructions after the state table switcher.
+*/
+static int rc; /* Return code for these routines */
+static int rcv_s_pkt(); /* Received an S packet */
+static int rcv_firstdata(); /* Received first Data packet */
+static int rcv_shortreply(); /* Short reply to a REMOTE command */
+static int srv_query(); /* Server answers an query */
+static int srv_copy(); /* Server executes REMOTE COPY */
+static int srv_rename(); /* Server executes REMOTE RENAME */
+static int srv_login(); /* Server executes REMOTE LOGIN */
+static int srv_timeout(); /* Server times out */
+
+%%
+
+/*
+ Protocol entry points, one for each start state (sstate).
+ The lowercase letters are internal "inputs" from the user interface.
+ NOTE: The start state letters that appear on the left margin immediately
+ below can NOT be used as packet types OR as G-packet subcodes.
+*/
+
+s { TINIT; /* Send file(s) */
+ if (sinit() > 0) BEGIN ssinit;
+ else RESUME; }
+
+v { TINIT; nakstate = 1; BEGIN get; } /* Receive file(s) */
+
+r { /* Client sends a GET command */
+ TINIT;
+ vstate = get;
+ reget = 0;
+ retrieve = 0;
+ opkt = 0;
+ vcmd = 0;
+#ifdef PKTZEROHACK
+ ipktack[0] = NUL;
+#endif /* PKTZEROHACK */
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+
+h { /* Client sends a RETRIEVE command */
+ TINIT;
+ vstate = get;
+ reget = 0;
+ retrieve = 1;
+ opkt = 0;
+ vcmd = 0;
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+j { /* Client sends a REGET command */
+ TINIT;
+ vstate = get;
+ reget = 1;
+ retrieve = 0;
+ opkt = 0;
+ vcmd = 0;
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+o { /* Client sends Extended GET Packet */
+ TINIT;
+ vstate = get;
+ reget = oopts & GOPT_RES;
+ retrieve = oopts & GOPT_DEL;
+ opkt = 1;
+ vcmd = 0;
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+c { /* Client sends a Host command */
+ TINIT;
+ vstate = rgen;
+ vcmd = 'C';
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+k { TINIT; /* Client sends a Kermit command */
+ vstate = rgen;
+ vcmd = 'K';
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+g { /* Client sends a REMOTE command */
+ TINIT;
+ vstate = rgen;
+ vcmd = 'G';
+ if (sipkt('I') >= 0)
+ BEGIN ipkt;
+ else
+ RESUME;
+}
+x { /* Enter server mode */
+ int x;
+ x = justone;
+ if (!ENABLED(en_del)) { /* If DELETE is disabled */
+ if (fncact == XYFX_B || /* undo any file collision action */
+ fncact == XYFX_U || /* that could result in deletion or */
+ fncact == XYFX_A || /* modification of existing files. */
+ fncact == XYFX_X) {
+#ifndef NOICP
+ extern int g_fncact;
+ g_fncact = fncact; /* Save current setting */
+#endif /* NOICP */
+ fncact = XYFX_R; /* Change to RENAME */
+ debug(F101,"server DELETE disabled so fncact RENAME","",fncact);
+ }
+ }
+ SERVE; /* tinit() clears justone... */
+ justone = x;
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what, "SERVER", "", "");
+#endif /* IKSDB */
+}
+
+a {
+ int b1 = 0, b2 = 0;
+ if (!data) TINIT; /* "ABEND" -- Tell other side. */
+
+ if (!bctf) { /* Block check 3 forced on all packets */
+#ifndef pdp11
+ if (epktflg) { /* If because of E-PACKET command */
+ b1 = bctl; b2 = bctu; /* Save block check type */
+ bctl = bctu = 1; /* set it to 1 */
+ }
+#endif /* pdp11 */
+ }
+ errpkt((CHAR *)"User cancelled"); /* Send the packet */
+ if (!bctf) { /* Block check 3 forced on all packets */
+#ifndef pdp11
+ if (epktflg) { /* Restore the block check */
+ epktflg = 0;
+ bctl = b1; bctu = b2;
+ }
+ }
+#endif /* pdp11 */
+ success = 0;
+ return(0); /* Return from protocol. */
+}
+
+/*
+ Dynamic states: <current-states>input-character { action }
+ nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
+*/
+
+<rgen,get,serve,ropkt>S { /* Receive Send-Init packet. */
+ rc = rcv_s_pkt();
+ cancel = 0; /* Reset cancellation counter */
+ debug(F101,"rcv_s_pkt","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+
+/* States in which we get replies back from commands sent to a server. */
+/* Complicated because direction of protocol changes, packet number */
+/* stays at zero through I-G-S sequence, and complicated even more by */
+/* sliding windows buffer allocation. */
+
+<ipkt>Y { /* Get ack for I-packet */
+ int x = 0;
+#ifdef PKTZEROHACK
+ ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */
+ ipktlen = strlen(ipktack);
+#endif /* PKTZEROHACK */
+ spar(rdatap); /* Set parameters */
+ cancel = 0;
+ winlo = 0; /* Set window-low back to zero */
+ debug(F101,"<ipkt>Y winlo","",winlo);
+ urserver = 1; /* So I know I'm talking to a server */
+ if (vcmd) { /* If sending a generic command */
+ if (tinit(0) < 0) return(-9); /* Initialize many things */
+ x = scmd(vcmd,(CHAR *)cmarg); /* Do that */
+ if (x >= 0) x = 0; /* (because of O-Packet) */
+ debug(F101,"proto G packet scmd","",x);
+ vcmd = 0; /* and then un-remember it. */
+ } else if (vstate == get) {
+ debug(F101,"REGET sstate","",sstate);
+ x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */
+ }
+ if (x < 0) { /* If command was too long */
+ if (!srimsg)
+ srimsg = "Error sending string";
+ errpkt((CHAR *)srimsg); /* cancel both sides. */
+ success = 0;
+ RESUME;
+ } else if (x > 0) { /* Need to send more O-Packets */
+ BEGIN ssopkt;
+ } else {
+ rtimer(); /* Reset the elapsed seconds timer. */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ winlo = 0; /* Window back to 0, again. */
+ debug(F101,"<ipkt>Y vstate","",vstate);
+ nakstate = 1; /* Can send NAKs from here. */
+ BEGIN vstate; /* Switch to desired state */
+ }
+}
+
+<ssopkt>Y { /* Got ACK to O-Packet */
+ debug(F100,"CPCPRO <ssopkt>Y","",0);
+ x = sopkt();
+ debug(F101,"CPCPRO <ssopkt>Y x","",x);
+ if (x < 0) { /* If error */
+ errpkt((CHAR *)srimsg); /* cancel both sides. */
+ success = 0;
+ RESUME;
+ } else if (x == 0) { /* This was the last O-Packet */
+ rtimer(); /* Reset the elapsed seconds timer. */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ winlo = 0; /* Window back to 0, again. */
+ debug(F101,"<ssopkt>Y winlo","",winlo);
+ nakstate = 1; /* Can send NAKs from here. */
+ BEGIN vstate; /* Switch to desired state */
+ }
+ debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
+}
+
+<ipkt>E { /* Ignore Error reply to I packet */
+ int x = 0;
+ winlo = 0; /* Set window-low back to zero */
+ debug(F101,"<ipkt>E winlo","",winlo);
+ if (vcmd) { /* In case other Kermit doesn't */
+ if (tinit(0) < 0) return(-9);
+ x = scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */
+ if (x >= 0) x = 0; /* (because of O-Packet) */
+ vcmd = 0; /* Otherwise act as above... */
+ } else if (vstate == get) x = srinit(reget, retrieve, opkt);
+ if (x < 0) { /* If command was too long */
+ errpkt((CHAR *)srimsg); /* cancel both sides. */
+ success = 0;
+ RESUME;
+ } else if (x > 0) { /* Need to send more O-Packets */
+ BEGIN ssopkt;
+ } else {
+ freerpkt(winlo); /* Discard the Error packet. */
+ debug(F101,"<ipkt>E winlo","",winlo);
+ winlo = 0; /* Back to packet 0 again. */
+ nakstate = 1; /* Can send NAKs from here. */
+ BEGIN vstate;
+ }
+}
+
+<get>Y { /* Resend of previous I-pkt ACK, same seq number */
+ freerpkt(0); /* Free the ACK's receive buffer */
+ resend(0); /* Send the GET packet again. */
+}
+
+/* States in which we're being a server */
+
+<serve,get>I { /* Get I-packet */
+#ifndef NOSERVER
+ spar(rdatap); /* Set parameters from it */
+ ack1(rpar()); /* Respond with our own parameters */
+#ifdef COMMENT
+ pktinit(); /* Reinitialize packet numbers */
+#else
+#ifdef COMMENT
+ /* This can't be right - it undoes the stuff we just negotiated */
+ x = justone;
+ tinit(1); /* Reinitialize EVERYTHING */
+ justone = x; /* But this... */
+#else
+ tinit(0); /* Initialize most things */
+#endif /* COMMENT */
+#endif /* COMMENT */
+#endif /* NOSERVER */
+ cancel = 0; /* Reset cancellation counter */
+}
+
+<serve>R { /* GET */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+
+<serve>H { /* GET /DELETE (RETRIEVE) */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ RESUME;
+ } else if (!ENABLED(en_del)) {
+ errpkt((CHAR *)"Deleting files is disabled");
+ RESUME;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+ moving = 1;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+
+<serve>V { /* GET /RECURSIVE */
+#ifndef NOSERVER
+ recursive = 1; /* Set these before sgetinit() */
+ if (fnspath == PATH_OFF)
+ fnspath = PATH_REL; /* Don't worry, they will be */
+ if (x_login && !x_logged) { /* reset next time through. */
+ errpkt((CHAR *)"Login required");
+ RESUME;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+
+<serve>W { /* GET /RECURSIVE /DELETE */
+#ifndef NOSERVER
+ recursive = 1; /* Set these before sgetinit() */
+ if (fnspath == PATH_OFF)
+ fnspath = PATH_REL; /* Don't worry, they will be */
+ moving = 1; /* reset next time through. */
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ RESUME;
+ } else if (!ENABLED(en_del)) {
+ errpkt((CHAR *)"Deleting files is disabled");
+ RESUME;
+ } else if (sgetinit(0,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR,1,"server",
+ "GET /RECURSIVE /DELETE",(char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+
+<serve>J { /* GET /RECOVER (REGET) */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if (sgetinit(1,0) < 0) {
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ }
+#endif /* NOSERVER */
+}
+
+<serve>O { /* Extended GET */
+#ifndef NOSERVER
+ if (x_login && !x_logged) { /* (any combination of options) */
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if ((x = sgetinit(0,1)) < 0) {
+ debug(F101,"CKCPRO <serve>O sgetinit fail","",x);
+ RESUME;
+ } else if (x == 0) {
+ debug(F101,"CKCPRO <serve>O sgetinit done","",x);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ } else { /* Otherwise stay in this state */
+ debug(F101,"CKCPRO <serve>O sgetinit TBC","",x);
+ ack();
+ BEGIN ropkt;
+ }
+#endif /* NOSERVER */
+}
+
+<ropkt>O {
+#ifndef NOSERVER
+ if (x_login && !x_logged) { /* (any combination of options) */
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if ((x = sgetinit(0,1)) < 0) {
+ debug(F101,"CKCPRO <ropkt>O sgetinit fail","",x);
+ RESUME;
+ } else if (x == 0) {
+ debug(F101,"CKCPRO <ropkt>O sgetinit done","",x);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit;
+ } else { /* Otherwise stay in this state */
+ debug(F101,"CKCPRO <ropkt>O sgetinit TBC","",x);
+ ack();
+ }
+#endif /* NOSERVER */
+}
+
+<serve>G { /* Generic server command */
+#ifndef NOSERVER
+ srvptr = srvcmd; /* Point to command buffer */
+ decode(rdatap,putsrv,0); /* Decode packet data into it */
+ putsrv(NUL); /* Insert a couple nulls */
+ putsrv(NUL); /* for termination */
+ if (srvcmd[0]) {
+ sstate = srvcmd[0]; /* Set requested start state */
+ if (x_login && !x_logged && /* Login required? */
+ /* Login, Logout, and Help are allowed when not logged in */
+ sstate != 'I' && sstate != 'L' && sstate != 'H') {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else {
+ nakstate = 0; /* Now I'm the sender. */
+ what = W_REMO; /* Doing a REMOTE command. */
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ if (timint < 1)
+ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
+ binary = XYFT_T; /* Switch to text mode */
+ BEGIN generic; /* Switch to generic command state */
+ }
+ } else {
+ errpkt((CHAR *)"Badly formed server command"); /* report error */
+ RESUME; /* & go back to server command wait */
+ }
+#endif /* NOSERVER */
+}
+
+<serve>C { /* Receive Host command */
+#ifndef NOSERVER
+ if (x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else if (!ENABLED(en_hos)) {
+ errpkt((CHAR *)"REMOTE HOST disabled");
+ RESUME;
+ } else if (nopush) {
+ errpkt((CHAR *)"HOST commands not available");
+ RESUME;
+ } else {
+ srvptr = srvcmd; /* Point to command buffer */
+ decode(rdatap,putsrv,0); /* Decode command packet into it */
+ putsrv(NUL); /* Null-terminate */
+ nakstate = 0; /* Now sending, not receiving */
+ binary = XYFT_T; /* Switch to text mode */
+ if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */
+ what = W_REMO; /* Doing a REMOTE command. */
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ if (timint < 1)
+ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ BEGIN ssinit; /* If OK, send back its output */
+ } else { /* Otherwise */
+ errpkt((CHAR *)"Can't do system command"); /* report error */
+ RESUME; /* & go back to server command wait */
+ }
+ }
+#endif /* NOSERVER */
+}
+
+<serve>q { /* Interrupted or connection lost */
+ rc = srv_timeout();
+ debug(F101,"srv_timeout","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+
+<serve>N { /* Server got a NAK in command-wait */
+#ifndef NOSERVER
+ errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
+ RESUME;
+#endif /* NOSERVER */
+}
+
+<serve>. { /* Any other command in this state */
+#ifndef NOSERVER
+ if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */
+ errpkt((CHAR *)"Unimplemented server function");
+ /* If we answer an E with an E, we get an infinite loop. */
+ /* A Y (ACK) can show up here if we sent back a short-form reply to */
+ /* a G packet and it was echoed. ACKs can be safely ignored here. */
+ RESUME; /* Go back to server command wait. */
+#endif /* NOSERVER */
+}
+
+<generic>I { /* Login/Out */
+ rc = srv_login();
+ debug(F101,"<generic>I srv_login","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+
+<generic>C { /* Got REMOTE CD command */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_cwd)) {
+ errpkt((CHAR *)"REMOTE CD disabled");
+ RESUME;
+ } else {
+ char * p = NULL;
+ x = cwd((char *)(srvcmd+1)); /* Try to change directory */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!x) { /* Failed */
+ errpkt((CHAR *)"Can't change directory");
+ RESUME; /* Back to server command wait */
+ } else if (x == 2) { /* User wants message */
+ if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */
+ errpkt((CHAR *)"REMOTE TYPE disabled");
+ RESUME;
+ } else { /* TYPE is enabled */
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (zchki(cdmsgfile[i]) > -1) {
+ break;
+ }
+ }
+ binary = XYFT_T; /* Use text mode for this. */
+ if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */
+ BEGIN ssinit; /* OK */
+ } else { /* not OK */
+ p = zgtdir();
+ if (!p) p = "";
+ success = (*p) ? 1 : 0;
+ ack1((CHAR *)p); /* ACK with new directory name */
+ success = 1;
+ RESUME; /* wait for next server command */
+ }
+ }
+ } else { /* User doesn't want message */
+ p = zgtdir();
+ if (!p) p = "";
+ success = (*p) ? 1 : 0;
+ ack1((CHAR *)p);
+ success = 1;
+ RESUME; /* Wait for next server command */
+ }
+ }
+#endif /* NOSERVER */
+}
+
+<generic>A { /* Got REMOTE PWD command */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_cwd)) {
+ errpkt((CHAR *)"REMOTE CD disabled");
+ RESUME;
+ } else {
+ if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */
+ ack1(data); /* If it fits, send it back in ACK */
+ success = 1;
+ } else { /* Failed */
+ ack(); /* Send empty ACK */
+ success = 0; /* and indicate failure locally */
+ }
+ RESUME; /* Back to server command wait */
+ }
+#endif /* NOSERVER */
+}
+
+<generic>D { /* REMOTE DIRECTORY command */
+#ifndef NOSERVER
+ char *n2;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_dir)) { /* If DIR is disabled, */
+ errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */
+ RESUME;
+ } else { /* DIR is enabled. */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* But CWD is disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+#ifdef COMMENT
+ n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2;
+ if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */
+#else
+ int x;
+ if ((x = snddir((char*)(srvcmd+2))) > 0)
+#endif /* COMMENT */
+ {
+ BEGIN ssinit; /* send the results back; */
+ } else { /* otherwise */
+ if (x < 0)
+ errpkt((CHAR *)"No files match");
+ else
+ errpkt((CHAR *)"Can't list directory");
+ RESUME; /* return to server command wait */
+ }
+ }
+ }
+#endif /* NOSERVER */
+}
+
+<generic>E { /* REMOTE DELETE (Erase) */
+#ifndef NOSERVER
+ char *n2;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_del)) {
+ errpkt((CHAR *)"REMOTE DELETE disabled");
+ RESUME;
+ } else { /* DELETE is enabled */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* but CWD is disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */
+ errpkt((CHAR *)"It's a directory");
+ RESUME;
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ int x;
+ if ((x = snddel((char*)(srvcmd+2))) > 0) {
+ BEGIN ssinit; /* If OK send results back */
+ } else { /* otherwise */
+ if (x < 0)
+ errpkt((CHAR *)"File not found"); /* report failure */
+ else
+ errpkt((CHAR *)"DELETE failed");
+ RESUME; /* & return to server command wait */
+ }
+ }
+ }
+#endif /* NOSERVER */
+}
+
+<generic>F { /* FINISH */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"SERVER FINISH", "", "");
+#endif /* IKSDB */
+ if (!ENABLED(en_fin)) {
+ errpkt((CHAR *)"FINISH disabled");
+ RESUME;
+ } else {
+ ack(); /* Acknowledge */
+ xxscreen(SCR_TC,0,0L,""); /* Display */
+ success = 1;
+ return(0); /* Done */
+ }
+#endif /* NOSERVER */
+}
+
+<generic>X { /* EXIT */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE EXIT", "", "");
+#endif /* IKSDB */
+ if (!ENABLED(en_xit)) {
+ errpkt((CHAR *)"EXIT disabled");
+ RESUME;
+ } else {
+ ack(); /* Acknowledge */
+ xxscreen(SCR_TC,0,0L,""); /* Display */
+ doexit(GOOD_EXIT,xitsta);
+ }
+#endif /* NOSERVER */
+}
+
+<generic>L { /* BYE (Logout) */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "BYE", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"SERVER BYE", "", "");
+#endif /* IKSDB */
+ if (!ENABLED(en_bye)) {
+ errpkt((CHAR *)"BYE disabled");
+ RESUME;
+ } else {
+ ack(); /* Acknowledge */
+ success = 1;
+ msleep(750); /* Give the ACK time to get out */
+ if (local)
+ ttres(); /* Reset the terminal */
+ xxscreen(SCR_TC,0,0L,""); /* Display */
+ doclean(1); /* Clean up files, etc */
+#ifdef DEBUG
+ debug(F100,"C-Kermit BYE - Logging out...","",0);
+ zclose(ZDFILE);
+#endif /* DEBUG */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver)
+ ckxlogout();
+ else
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+#ifdef TCPSOCKET
+#ifndef NOLISTEN
+ if (network && tcpsrfd > 0 && !inserver)
+ doexit(GOOD_EXIT,xitsta);
+ else
+#endif /* NOLISTEN */
+#endif /* TCPSOCKET */
+ return(zkself()); /* Try to log self out */
+ }
+#endif /* NOSERVER */
+}
+
+<generic>H { /* REMOTE HELP */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE HELP", "", "");
+#endif /* IKSDB */
+#ifndef NOSERVER
+ if (sndhlp()) {
+ BEGIN ssinit; /* try to send it */
+ } else { /* If not ok, */
+ errpkt((CHAR *)"Can't send help"); /* send error message instead */
+ RESUME; /* and return to server command wait */
+ }
+#endif /* NOSERVER */
+}
+
+<generic>R { /* REMOTE RENAME */
+ rc = srv_rename();
+ debug(F101,"srv_rename","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+
+<generic>K { /* REMOTE COPY */
+ rc = srv_copy();
+ debug(F101,"srv_copy","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+
+<generic>S { /* REMOTE SET */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifndef NOSERVER
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_set)) {
+ errpkt((CHAR *)"REMOTE SET disabled");
+ RESUME;
+ } else {
+ if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */
+ success = 1;
+ ack(); /* If OK, then acknowledge */
+ } else /* Otherwise */
+ errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */
+ RESUME; /* Return to server command wait */
+ }
+#endif /* NOSERVER */
+}
+
+<generic>T { /* REMOTE TYPE */
+#ifndef NOSERVER
+ char *n2;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_typ)) {
+ errpkt((CHAR *)"REMOTE TYPE disabled");
+ RESUME;
+ } else {
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* If CWD disabled */
+ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */
+ if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ binary = XYFT_T; /* Use text mode for this. */
+ if ( /* (RESUME didn't change state) */
+#ifdef COMMENT
+ syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */
+#else
+ sndtype((char *)(srvcmd+2)) /* New way */
+#endif /* COMMENT */
+ )
+ BEGIN ssinit; /* OK */
+ else { /* not OK */
+ errpkt((CHAR *)"Can't type file"); /* give error message */
+ RESUME; /* wait for next server command */
+ }
+ }
+ }
+#endif /* NOSERVER */
+}
+
+<generic>m { /* REMOTE MKDIR */
+#ifndef NOSERVER
+#ifdef CK_MKDIR
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_mkd)) {
+ errpkt((CHAR *)"REMOTE MKDIR disabled");
+ RESUME;
+ } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
+ errpkt((CHAR *)"Directory access restricted");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ if (state == generic) { /* OK to go ahead. */
+ char *p = NULL;
+ x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */
+ if (!p) p = "";
+ if (x > -1) {
+ encstr((CHAR *)p); /* OK - encode the name */
+ ack1(data); /* Send short-form response */
+ success = 1;
+ RESUME;
+ } else { /* not OK */
+ if (!*p) p = "Directory creation failure";
+ errpkt((CHAR *)p); /* give error message */
+ RESUME; /* Wait for next server command */
+ }
+ }
+#else
+ errpkt((CHAR *)"REMOTE MKDIR not available");
+ RESUME;
+#endif /* CK_MKDIR */
+#endif /* NOSERVER */
+}
+
+<generic>d { /* REMOTE RMDIR */
+#ifndef NOSERVER
+#ifdef CK_MKDIR
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_rmd)) {
+ errpkt((CHAR *)"REMOTE RMDIR disabled");
+ RESUME;
+ } else if (!ENABLED(en_cwd)) { /* If CWD disabled */
+ errpkt((CHAR *)"Directory access restricted");
+ RESUME; /* Remember, this is not a goto! */
+ }
+ if (state == generic) { /* OK to go ahead. */
+ char *p = NULL;
+ x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1);
+ if (!p) p = "";
+ if (x > -1) {
+ encstr((CHAR *)p); /* OK - encode the name */
+ ack1(data); /* Send short-form response */
+ success = 1;
+ RESUME;
+ } else { /* not OK */
+ if (!*p) p = "Directory removal failure";
+ errpkt((CHAR *)p); /* give error message */
+ RESUME; /* Wait for next server command */
+ }
+ }
+#else
+ errpkt((CHAR *)"REMOTE RMDIR not available");
+ RESUME;
+#endif /* CK_MKDIR */
+#endif /* NOSERVER */
+}
+
+<generic>U { /* REMOTE SPACE */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd);
+#endif /* CKSYSLOG */
+ if (!ENABLED(en_spa)) {
+ errpkt((CHAR *)"REMOTE SPACE disabled");
+ RESUME;
+ } else {
+ x = srvcmd[1]; /* Get area to check */
+ x = ((x == NUL) || (x == SP)
+#ifdef OS2
+ || (x == '!') || (srvcmd[3] == ':')
+#endif /* OS2 */
+ );
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ "REMOTE SPACE",
+ (x ? "" : (char *)srvcmd),
+ ""
+ );
+#endif /* IKSDB */
+ if (!x && !ENABLED(en_cwd)) { /* CWD disabled */
+ errpkt((CHAR *)"Access denied"); /* and non-default area given, */
+ RESUME; /* refuse. */
+ } else {
+#ifdef OS2
+_PROTOTYP(int sndspace,(int));
+ if (sndspace(x ? toupper(srvcmd[2]) : 0)) {
+ BEGIN ssinit; /* send the report. */
+ } else { /* If not ok, */
+ errpkt((CHAR *)"Can't send space"); /* send error message */
+ RESUME; /* and return to server command wait */
+ }
+#else
+ if (nopush)
+ x = 0;
+ else
+ x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2)));
+ if (x) { /* If we got the info */
+ BEGIN ssinit; /* send it */
+ } else { /* otherwise */
+ errpkt((CHAR *)"Can't check space"); /* send error message */
+ RESUME; /* and await next server command */
+ }
+#endif /* OS2 */
+ }
+ }
+#endif /* NOSERVER */
+}
+
+<generic>W { /* REMOTE WHO */
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ if (!ENABLED(en_who)) {
+ errpkt((CHAR *)"REMOTE WHO disabled");
+ RESUME;
+ } else {
+#ifdef OS2
+_PROTOTYP(int sndwho,(char *));
+ if (sndwho((char *)(srvcmd+2))) {
+ BEGIN ssinit; /* try to send it */
+ } else { /* If not ok, */
+ errpkt((CHAR *)"Can't do who command"); /* send error msg */
+ RESUME; /* and return to server command wait */
+ }
+#else
+ if (syscmd(WHOCMD,(char *)(srvcmd+2))) {
+ BEGIN ssinit;
+ } else {
+ errpkt((CHAR *)"Can't do who command");
+ RESUME;
+ }
+#endif /* OS2 */
+ }
+#endif /* NOSERVER */
+}
+
+<generic>V { /* Variable query or set */
+ rc = srv_query();
+ debug(F101,"srv_query","",rc);
+ if (rc > -1) return(rc);
+}
+
+<generic>M { /* REMOTE MESSAGE command */
+#ifndef NOSERVER
+ debug(F110,"RMSG",(char *)srvcmd+2,0);
+ xxscreen(SCR_MS,0,0L,(char *)(srvcmd+2));
+ ack();
+ RESUME;
+#endif /* NOSERVER */
+}
+
+<generic>q { /* Interrupted or connection lost */
+#ifndef NOSERVER
+ if (fatalio) { /* Connection lost */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
+#endif /* CKSYSLOG */
+ success = 0;
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ } else if (interrupted) {
+ if (!ENABLED(en_fin)) { /* Ctrl-C typed */
+ errpkt((CHAR *)"QUIT disabled");
+ RESUME;
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
+#endif /* CKSYSLOG */
+ success = 0;
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ }
+ } else { /* Shouldn't happen */
+ debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0);
+ QUIT;
+ }
+#endif /* NOSERVER */
+}
+
+<generic>. { /* Anything else in this state... */
+#ifndef NOSERVER
+ errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
+ RESUME; /* and return to server command wait */
+#endif /* NOSERVER */
+}
+
+<rgen>q { /* Sent BYE and connection broken */
+ if (bye_active && ttchk() < 0) {
+ msleep(500);
+ bye_active = 0;
+ ttclos(0); /* Close our end of the connection */
+ clsof(0);
+ return(success = 1);
+ } else { /* Other generic command */
+ return(success = 0); /* or connection not broken */
+ }
+}
+
+<rgen>Y { /* Short-Form reply */
+ rc = rcv_shortreply();
+ debug(F101,"<rgen>Y rcv_shortreply","",rc);
+ if (rc > -1) return(rc);
+}
+
+<rgen,rfile>F { /* File header */
+ /* char *n2; */
+ extern int rsn;
+ debug(F101,"<rfile>F winlo 1","",winlo);
+ xflg = 0; /* Not screen data */
+ if (!czseen)
+ cancel = 0; /* Reset cancellation counter */
+#ifdef CALIBRATE
+ if (dest == DEST_N)
+ calibrate = 1;
+#endif /* CALIBRATE */
+ if (!rcvfil(filnam)) { /* Figure out local filename */
+ errpkt((CHAR *)rf_err); /* Trouble */
+ RESUME;
+ } else { /* Real file, OK to receive */
+ char * fnp;
+ debug(F111,"<rfile>F winlo 2",fspec,winlo);
+ if (filcnt == 1) /* rcvfil set this to 1 for 1st file */
+ crc16 = 0L; /* Clear file CRC */
+ fnp = fspec; /* This is the full path */
+ if (server && !ENABLED(en_cwd) || /* if DISABLE CD */
+ !fackpath /* or F-ACK-PATH OFF */
+ ) {
+ zstrip(fspec,&fnp); /* don't send back full path */
+ }
+ encstr((CHAR *)fnp);
+ if (fackbug)
+ ack();
+ else
+ ack1(data); /* Send it back in ACK */
+ initattr(&iattr); /* Clear file attribute structure */
+ streamon();
+ if (window(wslotn) < 0) { /* Allocate negotiated window slots */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ }
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ server ? "SERVER" : "",
+ "RECEIVE",
+ fspec
+ );
+#endif /* IKSDB */
+ BEGIN rattr; /* Now expect Attribute packets */
+ }
+}
+
+<rgen,rfile>X { /* X-packet instead of file header */
+ xflg = 1; /* Screen data */
+ if (!czseen)
+ cancel = 0; /* Reset cancellation counter */
+ ack(); /* Acknowledge the X-packet */
+ initattr(&iattr); /* Initialize attribute structure */
+ streamon();
+ if (window(wslotn) < 0) { /* allocate negotiated window slots */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ }
+#ifndef NOSPL
+ if (query) { /* If this is the response to */
+ qbufp = querybuf; /* a query that we sent, initialize */
+ qbufn = 0; /* the response buffer */
+ querybuf[0] = NUL;
+ }
+#endif /* NOSPL */
+ what = W_REMO; /* we're doing a REMOTE command */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ server ? "SERVER" : "",
+ "RECEIVE",
+ fspec
+ );
+#endif /* IKSDB */
+ BEGIN rattr; /* Expect Attribute packets */
+}
+
+<rattr>A { /* Attribute packet */
+ if (gattr(rdatap,&iattr) == 0) { /* Read into attribute structure */
+#ifdef CK_RESEND
+ ack1((CHAR *)iattr.reply.val); /* Reply with data */
+#else
+ ack(); /* If OK, acknowledge */
+#endif /* CK_RESEND */
+ } else { /* Otherwise */
+ extern long fsize;
+ char *r;
+ r = getreason(iattr.reply.val);
+ ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */
+ xxscreen(SCR_ST,ST_REFU,0L,r); /* reason */
+#ifdef TLOG
+ if (tralog && !tlogfmt)
+ doxlog(what,filnam,fsize,binary,1,r);
+#endif /* TLOG */
+ }
+}
+
+<rattr>D { /* First data packet */
+ debug(F100,"<rattr> D firstdata","",0);
+ rc = rcv_firstdata();
+ debug(F101,"rcv_firstdata rc","",rc);
+ if (rc > -1) return(rc); /* (see below) */
+}
+
+<rfile>B { /* EOT, no more files */
+ ack(); /* Acknowledge the B packet */
+ reot(); /* Do EOT things */
+#ifdef CK_TMPDIR
+/* If we were cd'd temporarily to another device or directory ... */
+ if (f_tmpdir) {
+ int x;
+ x = zchdir((char *) savdir); /* ... restore previous directory */
+ f_tmpdir = 0; /* and remember we did it. */
+ debug(F111,"ckcpro.w B tmpdir restoring",savdir,x);
+ }
+#endif /* CK_TMPDIR */
+ RESUME; /* and quit */
+}
+
+<rdpkt>D { /* Got Data packet */
+ debug(F101,"<rdpkt>D cxseen","",cxseen);
+ debug(F101,"<rdpkt>D czseen","",czseen);
+ if (cxseen || czseen || discard) { /* If file or group interruption */
+ CHAR * msg;
+ msg = czseen ? (CHAR *)"Z" : (CHAR *)"X";
+#ifdef STREAMING
+ if (streaming) { /* Need to cancel */
+ debug(F111,"<rdpkt>D streaming cancel",msg,cancel);
+ if (cancel++ == 0) { /* Only do this once */
+ ack1(msg); /* Put "X" or "Z" in ACK */
+ } else if (czseen) {
+ errpkt((CHAR *)"User canceled");
+ RESUME;
+ } else {
+ fastack();
+ }
+ } else
+#endif /* STREAMING */
+ ack1(msg);
+ } else { /* No interruption */
+ int rc, qf;
+#ifndef NOSPL
+ qf = query;
+#else
+ qf = 0;
+#endif /* NOSPL */
+#ifdef CKTUNING
+ rc = (binary && !parity) ?
+ bdecode(rdatap,putfil):
+ decode(rdatap, qf ? puttrm : putfil, 1);
+#else
+ rc = decode(rdatap, qf ? puttrm : putfil, 1);
+#endif /* CKTUNING */
+ if (rc < 0) {
+ discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T));
+ errpkt((CHAR *)"Error writing data"); /* If failure, */
+ RESUME;
+ } else /* Data written OK, send ACK */
+#ifdef STREAMING
+ if (streaming)
+ fastack();
+ else
+#endif /* STREAMING */
+ ack();
+ }
+}
+
+<rattr>Z { /* EOF immediately after A-Packet. */
+ rf_err = "Can't create file";
+ timint = s_timint;
+ if (discard) { /* Discarding a real file... */
+ x = 1;
+ } else if (xflg) { /* If screen data */
+ if (remfile) { /* redirected to file */
+ if (rempipe) /* or pipe */
+ x = openc(ZOFILE,remdest); /* Pipe: start command */
+ else
+ x = opena(remdest,&iattr); /* File: open with attributes */
+ } else { /* otherwise */
+ x = opent(&iattr); /* "open" the screen */
+ }
+#ifdef CALIBRATE
+ } else if (calibrate) { /* If calibration run */
+ x = ckopenx(&iattr); /* do this */
+#endif /* CALIBRATE */
+ } else { /* otherwise */
+ x = opena(filnam,&iattr); /* open the file, with attributes */
+ if (x == -17) { /* REGET skipped because same size */
+ discard = 1;
+ rejection = 1;
+ }
+ }
+ if (!x || reof(filnam, &iattr) < 0) { /* Close output file */
+ errpkt((CHAR *) rf_err); /* If problem, send error msg */
+ RESUME; /* and quit */
+ } else { /* otherwise */
+ if (x == -17)
+ xxscreen(SCR_ST,ST_SKIP,SKP_RES,"");
+ ack(); /* acknowledge the EOF packet */
+ BEGIN rfile; /* and await another file */
+ }
+}
+
+<rdpkt>q { /* Ctrl-C or connection loss. */
+ timint = s_timint;
+ window(1); /* Set window size back to 1... */
+ cxseen = 1;
+ x = clsof(1); /* Close file */
+ return(success = 0); /* Failed */
+}
+
+<rdpkt>Z { /* End Of File (EOF) Packet */
+/* wslots = 1; */ /* (don't set) Window size back to 1 */
+#ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */
+ x = reof(filnam, &iattr); /* Handle the EOF packet */
+ switch (x) { /* reof() sets the success flag */
+ case -5: /* Handle problems */
+ errpkt((CHAR *)"RENAME failed"); /* Fatal */
+ RESUME;
+ break;
+ case -4:
+ errpkt((CHAR *)"MOVE failed"); /* Fatal */
+ RESUME;
+ break;
+ case -3: /* If problem, send error msg */
+ errpkt((CHAR *)"Can't print file"); /* Fatal */
+ RESUME;
+ break;
+ case -2:
+ errpkt((CHAR *)"Can't mail file"); /* Fatal */
+ RESUME;
+ break;
+ case 2: /* Not fatal */
+ case 3:
+ xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file");
+ RESUME;
+ break;
+ default:
+ if (x < 0) { /* Fatal */
+ errpkt((CHAR *)"Can't close file");
+ RESUME;
+ } else { /* Success */
+#ifndef NOSPL
+ if (query) /* Query reponses generally */
+ conoll(""); /* don't have line terminators */
+#endif /* NOSPL */
+ if (czseen) { /* Batch canceled? */
+ if (cancel++ == 0) { /* If we haven't tried this yet */
+ ack1((CHAR *)"Z"); /* Try it once */
+ } else { /* Otherwise */
+ errpkt((CHAR *)"User canceled"); /* quite with Error */
+ RESUME;
+ }
+ } else
+ ack(); /* Acknowledge the EOF packet */
+ BEGIN rfile; /* and await another file */
+ }
+ }
+#else
+ if (reof(filnam, &iattr) < 0) { /* Close the file */
+ errpkt((CHAR *)"Error at end of file");
+ RESUME;
+ } else { /* reof() sets success flag */
+ ack();
+ BEGIN rfile;
+ }
+#endif /* COHERENT */
+}
+
+<ssinit>Y { /* ACK for Send-Init */
+ spar(rdatap); /* set parameters from it */
+ cancel = 0;
+ if (bctf) {
+ bctu = 3;
+ bctl = 3;
+ } else {
+ bctu = bctr; /* switch to agreed-upon block check */
+ bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
+ }
+
+#ifdef CK_RESEND
+ if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */
+ errpkt((CHAR *) "RESEND capabilities not negotiated");
+ RESUME;
+ } else {
+#endif /* CK_RESEND */
+ what = W_SEND; /* Remember we're sending */
+ lastxfer = W_SEND;
+ x = sfile(xflg); /* Send X or F header packet */
+ cancel = 0; /* Reset cancellation counter */
+ if (x) { /* If the packet was sent OK */
+ if (!xflg && filcnt == 1) /* and it's a real file */
+ crc16 = 0L; /* Clear the file CRC */
+ resetc(); /* reset per-transaction counters */
+ rtimer(); /* reset timers */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ streamon(); /* turn on streaming */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,
+ (server ? "SERVER" : ""),
+ "SEND",
+ filnam
+ );
+#endif /* IKSDB */
+ BEGIN ssfile; /* and switch to receive-file state */
+ } else { /* otherwise send error msg & quit */
+ s = xflg ? "Can't execute command" : (char *)epktmsg;
+ if (!*s) s = "Can't open file";
+ errpkt((CHAR *)s);
+ RESUME;
+ }
+#ifdef CK_RESEND
+ }
+#endif /* CK_RESEND */
+}
+
+/*
+ These states are necessary to handle the case where we get a server command
+ packet (R, G, or C) reply with an S packet, but the client retransmits the
+ command packet. The input() function doesn't catch this because the packet
+ number is still zero.
+*/
+<ssinit>R { /* R packet was retransmitted. */
+ xsinit(); /* Resend packet 0 */
+}
+
+<ssinit>G { /* Same deal if G packet comes again */
+ xsinit();
+}
+
+/* should probably add cases for O, W, V, H, J, ... */
+
+<ssinit>C { /* Same deal if C packet comes again */
+ xsinit();
+}
+
+<ssfile>Y { /* ACK for F or X packet */
+ srvptr = srvcmd; /* Point to string buffer */
+ decode(rdatap,putsrv,0); /* Decode data field, if any */
+ putsrv(NUL); /* Terminate with null */
+ ffc = 0L; /* Reset file byte counter */
+ debug(F101,"<ssfile>Y cxseen","",cxseen);
+ if (*srvcmd) { /* If remote name was recorded */
+ if (sendmode != SM_RESEND) {
+ if (fdispla == XYFD_C || fdispla == XYFD_S)
+ xxscreen(SCR_AN,0,0L,(char *)srvcmd);
+ tlog(F110," remote name:",(char *) srvcmd,0L);
+ makestr(&psrfspec,(char *)srvcmd);
+ }
+ }
+ if (cxseen||czseen) { /* Interrupted? */
+ debug(F101,"<ssfile>Y canceling","",0);
+ x = clsif(); /* Close input file */
+ sxeof(1); /* Send EOF(D) */
+ BEGIN sseof; /* and switch to EOF state. */
+ } else if (atcapu) { /* If attributes are to be used */
+ if (sattr(xflg | stdinf, 1) < 0) { /* send them */
+ errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */
+ RESUME; /* and quit */
+ } else BEGIN ssattr; /* if ok, switch to attribute state */
+ } else { /* Attributes not negotiated */
+ if (window(wslotn) < 0) { /* Open window */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ } else if ((x = sdata()) == -2) { /* Send first data packet data */
+ window(1); /* Connection lost, reset window */
+ x = clsif(); /* Close input file */
+ return(success = 0); /* Return failure */
+ } else if (x == -9) { /* User interrupted */
+ errpkt((CHAR *)"User cancelled"); /* Send Error packet */
+ window(1); /* Set window size back to 1... */
+ timint = s_timint; /* Restore timeout */
+ return(success = 0); /* Failed */
+ } else if (x < 0) { /* EOF (empty file) or interrupted */
+ window(1); /* put window size back to 1, */
+ debug(F101,"<ssfile>Y cxseen","",cxseen);
+ x = clsif(); /* If not ok, close input file, */
+ if (x < 0) /* treating failure as interruption */
+ cxseen = 1; /* Send EOF packet */
+ seof(cxseen||czseen);
+ BEGIN sseof; /* and switch to EOF state. */
+ } else { /* First data sent OK */
+ BEGIN ssdata; /* All ok, switch to send-data state */
+ }
+ }
+}
+
+<ssattr>Y { /* Got ACK to A packet */
+ ffc = 0L; /* Reset file byte counter */
+ debug(F101,"<ssattr>Y cxseen","",cxseen);
+ if (cxseen||czseen) { /* Interrupted? */
+ debug(F101,"<sattr>Y canceling","",0);
+ x = clsif(); /* Close input file */
+ sxeof(1); /* Send EOF(D) */
+ BEGIN sseof; /* and switch to EOF state. */
+ } else if (rsattr(rdatap) < 0) { /* Was the file refused? */
+ discard = 1; /* Set the discard flag */
+ clsif(); /* Close the file */
+ sxeof(1); /* send EOF with "discard" code */
+ BEGIN sseof; /* switch to send-EOF state */
+ } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */
+ errpkt((CHAR *)"Can't send attributes"); /* Trouble... */
+ RESUME;
+ } else if (x == 0) { /* No more to send so now the data */
+ if (window(wslotn) < 0) { /* Allocate negotiated window slots */
+ errpkt((CHAR *)"Can't open window");
+ RESUME;
+ }
+ if ((x = sdata()) == -2) { /* File accepted, send first data */
+ window(1); /* Connection broken */
+ x = clsif(); /* Close file */
+ return(success = 0); /* Return failure */
+ } else if (x == -9) { /* User interrupted */
+ errpkt((CHAR *)"User cancelled"); /* Send Error packet */
+ window(1); /* Set window size back to 1... */
+ timint = s_timint; /* Restore timeout */
+ return(success = 0); /* Failed */
+ } else if (x < 0) { /* If data was not sent */
+ window(1); /* put window size back to 1, */
+ debug(F101,"<ssattr>Y cxseen","",cxseen);
+ if (clsif() < 0) /* Close input file */
+ cxseen = 1; /* Send EOF packet */
+ seof(cxseen||czseen);
+ BEGIN sseof; /* and switch to EOF state. */
+ } else {
+ BEGIN ssdata; /* All ok, switch to send-data state */
+ }
+ }
+}
+
+<ssdata>q { /* Ctrl-C or connection loss. */
+ window(1); /* Set window size back to 1... */
+ cxseen = 1; /* To indicate interruption */
+ x = clsif(); /* Close file */
+ return(success = 0); /* Failed */
+}
+
+<ssdata>Y { /* Got ACK to Data packet */
+ canned(rdatap); /* Check if file transfer cancelled */
+ debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
+ debug(F111,"<ssdata>Y czseen",rdatap,czseen);
+ if ((x = sdata()) == -2) { /* Try to send next data */
+ window(1); /* Connection lost, reset window */
+ x = clsif(); /* Close file */
+ return(success = 0); /* Failed */
+ } else if (x == -9) { /* User interrupted */
+ errpkt((CHAR *)"User cancelled"); /* Send Error packet */
+ window(1); /* Set window size back to 1... */
+ timint = s_timint; /* Restore original timeout */
+ return(success = 0); /* Failed */
+ } else if (x < 0) { /* EOF - finished sending data */
+ debug(F101,"<ssdata>Y cxseen","",cxseen);
+ window(1); /* Set window size back to 1... */
+ if (clsif() < 0) /* Close input file */
+ cxseen = 1; /* Send EOF packet */
+ debug(F101,"<ssdata>Y CALLING SEOF()","",cxseen);
+ seof(cxseen||czseen);
+ BEGIN sseof; /* and enter send-eof state */
+ }
+ /* NOTE: If x == 0 it means we're draining: see sdata()! */
+}
+
+<sseof>Y { /* Got ACK to EOF */
+ int g, xdiscard;
+ canned(rdatap); /* Check if file transfer cancelled */
+ debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
+ debug(F111,"<sseof>Y czseen",rdatap,czseen);
+ debug(F111,"<sseof>Y discard",rdatap,discard);
+ xdiscard = discard;
+ discard = 0;
+ success = (cxseen == 0 && czseen == 0); /* Transfer status... */
+ debug(F101,"<sseof>Y success","",success);
+ if (success && rejection > 0) /* If rejected, succeed if */
+ if (rejection != '#' && /* reason was date */
+ rejection != 1 && rejection != '?') /* or name; */
+ success = 0; /* fail otherwise. */
+ cxseen = 0; /* This goes back to zero. */
+ if (success) { /* Only if transfer succeeded... */
+ xxscreen(SCR_ST,ST_OK,0L,"");
+ if (!xdiscard) {
+ makestr(&sfspec,psfspec); /* Record filenames for WHERE */
+ makestr(&srfspec,psrfspec);
+ }
+ if (moving) { /* If MOVE'ing */
+ x = zdelet(filnam); /* Try to delete the source file */
+#ifdef TLOG
+ if (tralog) {
+ if (x > -1) {
+ tlog(F110," deleted",filnam,0);
+ } else {
+ tlog(F110," delete failed:",ck_errstr(),0);
+ }
+ }
+#endif /* TLOG */
+ } else if (snd_move) { /* Or move it */
+ int x;
+ x = zrename(filnam,snd_move);
+#ifdef TLOG
+ if (tralog) {
+ if (x > -1) {
+ tlog(F110," moved to ",snd_move,0);
+ } else {
+ tlog(F110," move failed:",ck_errstr(),0);
+ }
+ }
+#endif /* TLOG */
+ } else if (snd_rename) { /* Or rename it */
+ char *s = snd_rename; /* Renaming string */
+#ifndef NOSPL
+ int y; /* Pass it thru the evaluator */
+ extern int cmd_quoting; /* for \v(filename) */
+ if (cmd_quoting) { /* But only if cmd_quoting is on */
+ y = MAXRP;
+ s = (char *)srvcmd;
+ zzstring(snd_rename,&s,&y);
+ s = (char *)srvcmd;
+ }
+#endif /* NOSPL */
+ if (s) if (*s) {
+ int x;
+ x = zrename(filnam,s);
+#ifdef TLOG
+ if (tralog) {
+ if (x > -1) {
+ tlog(F110," renamed to",s,0);
+ } else {
+ tlog(F110," rename failed:",ck_errstr(),0);
+ }
+ }
+#endif /* TLOG */
+#ifdef COMMENT
+ *s = NUL;
+#endif /* COMMENT */
+ }
+ }
+ }
+ if (czseen) { /* Check group interruption flag */
+ g = 0; /* No more files if interrupted */
+ } else { /* Otherwise... */
+#ifdef COMMENT
+ /* This code makes any open error fatal to a file-group transfer. */
+ g = gnfile();
+ debug(F111,"<sseof>Y gnfile",filnam,g);
+ if (g > 0) { /* Any more files to send? */
+ if (sfile(xflg)) /* Yes, try to send next file header */
+ BEGIN ssfile; /* if ok, enter send-file state */
+ else { /* otherwise */
+ s = xflg ? "Can't execute command" : (char *)epktmsg;
+ if (!*s) s = "Can't open file";
+ errpkt((CHAR *)s); /* send error message */
+ RESUME; /* and quit */
+ }
+ } else { /* No next file */
+ tsecs = gtimer(); /* get statistics timers */
+#ifdef GFTIMER
+ fptsecs = gftimer();
+#endif /* GFTIMER */
+ seot(); /* send EOT packet */
+ BEGIN sseot; /* enter send-eot state */
+ }
+#else /* COMMENT */
+ while (1) { /* Keep trying... */
+ g = gnfile(); /* Get next file */
+ debug(F111,"<sseof>Y gnfile",filnam,g);
+ if (g == 0 && gnferror == 0) /* No more, stop trying */
+ break;
+ if (g > 0) { /* Have one */
+ if (sfile(xflg)) { /* Try to open and send F packet */
+ BEGIN ssfile; /* If OK, enter send-file state */
+ break; /* and break out of loop. */
+ }
+ } /* Otherwise keep trying to get one we can send... */
+ }
+ }
+ if (g == 0) {
+ debug(F101,"<sseof>Y no more files","",czseen);
+ tsecs = gtimer(); /* Get statistics timers */
+#ifdef GFTIMER
+ fptsecs = gftimer();
+#endif /* GFTIMER */
+ seot(); /* Send EOT packet */
+ BEGIN sseot; /* Enter send-eot state */
+ }
+#endif /* COMMENT */
+}
+
+<sseot>Y { /* Got ACK to EOT */
+ debug(F101,"sseot justone","",justone);
+ RESUME; /* All done, just quit */
+}
+
+E { /* Got Error packet, in any state */
+ char *s = "";
+ window(1); /* Close window */
+ timint = s_timint; /* Restore original timeout */
+ if (*epktmsg) /* Message from Error packet */
+ s = (char *)epktmsg;
+ if (!*s) { /* If not there then maybe here */
+ s = (char *)rdatap;
+ ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN);
+ }
+ if (!*s) /* Hopefully we'll never see this. */
+ s = "Unknown error";
+ success = 0; /* For IF SUCCESS/FAIL. */
+ debug(F101,"ckcpro.w justone at E pkt","",justone);
+
+ success = 0; /* Transfer failed */
+ xferstat = success; /* Remember transfer status */
+ if (!epktsent) {
+ x = quiet; quiet = 1; /* Close files silently, */
+ epktrcvd = 1; /* Prevent messages from clsof() */
+ clsif();
+ clsof(1); /* discarding any output file. */
+ ermsg(s); /* Issue the message (calls screen). */
+ quiet = x; /* Restore quiet state */
+ }
+ tstats(); /* Get stats */
+/*
+ If we are executing commands from a command file or macro, let the command
+ file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR.
+*/
+ if (
+#ifndef NOICP
+ !xcmdsrc &&
+#endif /* NOICP */
+ backgrd && !server)
+ fatal("Protocol error");
+ xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
+#ifdef CK_TMPDIR
+/* If we were cd'd temporarily to another device or directory ... */
+ if (f_tmpdir) {
+ int x;
+ x = zchdir((char *) savdir); /* ... restore previous directory */
+ f_tmpdir = 0; /* and remember we did it. */
+ debug(F111,"ckcpro.w E tmpdir restored",savdir,x);
+ }
+#endif /* CK_TMPDIR */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, "");
+#endif /* IKSDB */
+ RESUME;
+}
+
+q { success = 0; QUIT; } /* Ctrl-C or connection loss. */
+
+. { /* Anything not accounted for above */
+ errpkt((CHAR *)"Unexpected packet type"); /* Give error message */
+ window(1);
+ xitsta |= (what & W_KERMIT); /* Save this for doexit(). */
+ RESUME; /* and quit */
+}
+
+%%
+
+/*
+ From here down to proto() are routines that were moved out of the state
+ table switcher because the resulting switch() had become too large.
+ To move the contents of a state-table case to a routine:
+ 1. Add a prototype to the list above the state table switcher.
+ 2. Make a routine with an appropriate name, returning int.
+ 3. Move the code into it.
+ 4. Put a call to the new routine in the former spot:
+ rc = name_of_routine();
+ if (rc > -1) return(rc);
+ 5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and
+ at the end if the code is open-ended.
+*/
+static int
+rcv_firstdata() {
+ extern int dispos;
+ debug(F101,"rcv_firstdata","",dispos);
+
+ if (discard) { /* if we're discarding the file */
+ ack1((CHAR *)"X"); /* just ack the data like this. */
+ cancel++; /* and count it */
+ BEGIN rdpkt; /* and wait for more data packets. */
+ return(-1);
+ } else { /* Not discarding. */
+ rf_err = "Can't open file";
+ if (xflg) { /* If screen data */
+ if (remfile) { /* redirected to file */
+ if (rempipe) /* or pipe */
+ x = openc(ZOFILE,remdest); /* Pipe: start command */
+ else
+ x = opena(remdest,&iattr); /* File: open with attributes */
+ } else { /* otherwise */
+ x = opent(&iattr); /* "open" the screen */
+ }
+ } else { /* otherwise */
+#ifdef CALIBRATE
+ if (calibrate) { /* If calibration run */
+ x = ckopenx(&iattr); /* open nothing */
+#ifdef STREAMING
+ if (streaming) /* Streaming */
+ fastack(); /* ACK without ACKing. */
+ else
+#endif /* STREAMING */
+ ack(); /* Send real ACK */
+ BEGIN rdpkt; /* Proceed to next state */
+ return(-1);
+ } else
+#endif /* CALIBRATE */
+#ifdef UNIX
+/*
+ In UNIX we can pipe the file data into the mail program, which is to be
+ preferred to writing it out to a temp file and then mailing it afterwards.
+ This depends rather heavily on all UNIXes having a mail command that
+ accepts '-s "subject"' on the command line. MAILCMD (e.g. mail, Mail, mailx)
+ is defined in ckufio.c.
+*/
+ if (dispos == 'M') { /* Mail... */
+ char *s;
+ char * tmp = NULL;
+ int n = 0;
+ extern char *MAILCMD;
+ s = iattr.disp.val + 1;
+ n = (int)strlen(MAILCMD) + /* Mail command */
+ (int)strlen(s) + /* address */
+ (int)strlen(ofilnam) + 32; /* subject */
+ if (tmp = (char *)malloc(n)) {
+ ckmakxmsg(tmp,n,
+ MAILCMD," -s \"",ofilnam,"\" ",s,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp));
+ x = openc(ZOFILE,(char *)tmp);
+ free(tmp);
+ } else
+ x = 0;
+ } else if (dispos == 'P') { /* Ditto for print */
+ char * tmp = NULL;
+ int n;
+ extern char *PRINTCMD;
+ n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4;
+ if (tmp = (char *)malloc(n)) {
+ sprintf(tmp, /* safe (prechecked) */
+ "%s %s", PRINTCMD, iattr.disp.val + 1);
+ x = openc(ZOFILE,(char *)tmp);
+ free(tmp);
+ } else
+ x = 0;
+ } else
+#endif /* UNIX */
+ x = opena(filnam,&iattr); /* open the file, with attributes */
+ }
+ if (x) { /* If file was opened ok */
+ int rc, qf;
+#ifndef NOSPL
+ qf = query;
+#else
+ qf = 0;
+#endif /* NOSPL */
+
+#ifdef CKTUNING
+ rc = (binary && !parity) ?
+ bdecode(rdatap,putfil):
+ decode(rdatap, qf ? puttrm : putfil, 1);
+#else
+ rc = decode(rdatap, qf ? puttrm : putfil, 1);
+#endif /* CKTUNING */
+ if (rc < 0) {
+ errpkt((CHAR *)"Error writing data");
+ RESUME;
+ return(-1);
+ }
+#ifdef STREAMING
+ if (streaming) /* Streaming was negotiated */
+ fastack(); /* ACK without ACKing. */
+ else
+#endif /* STREAMING */
+ ack(); /* acknowledge it */
+ BEGIN rdpkt; /* and switch to receive-data state */
+ return(-1);
+ } else { /* otherwise */
+ errpkt((CHAR *) rf_err); /* send error packet */
+ RESUME; /* and quit. */
+ return(-1);
+ }
+ }
+}
+
+static int
+rcv_shortreply() {
+#ifdef PKTZEROHACK
+ success = 0;
+ debug(F111,"rcv_shortreply",rdatap,ipktlen);
+ if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) {
+ /* No it's the ACK to the I packet again */
+ x = scmd(vcmd,(CHAR *)cmarg); /* So send the REMOTE command again */
+ /* Maybe this should be resend() */
+ debug(F110,"IPKTZEROHACK",ipktack,x);
+ if (x < 0) {
+ errpkt((CHAR *)srimsg);
+ RESUME;
+ return(-1);
+ }
+ } else {
+ ipktack[0] = NUL;
+#endif /* PKTZEROHACK */
+ urserver = 1;
+#ifndef NOSERVER
+#ifndef NOSPL
+ if (query) { /* If to query, */
+ qbufp = querybuf; /* initialize query response buffer */
+ qbufn = 0;
+ querybuf[0] = NUL;
+ }
+#endif /* NOSPL */
+ x = 1;
+ if (remfile) { /* Response redirected to file */
+ rf_err = "Can't open file";
+ if (rempipe) /* or pipe */
+ x =
+#ifndef NOPUSH
+ zxcmd(ZOFILE,remdest) /* Pipe: Start command */
+#else
+ 0
+#endif /* NOPUSH */
+ ;
+ else
+ x = opena(remdest,&iattr); /* File: Open with attributes */
+ debug(F111,"rcv_shortreply remfile",remdest,x);
+ } else {
+ x = opent(&iattr); /* "open" the screen */
+ }
+ if (x) { /* If file was opened ok */
+ if (decode(rdatap,
+#ifndef NOSPL
+ (query || !remfile) ? puttrm :
+#else
+ !remfile ? puttrm :
+#endif /* NOSPL */
+ zputfil, 1) < 0) { /* Note: zputfil, not putfil. */
+ errpkt((CHAR *)"Error writing data");
+ RESUME;
+ return(-1);
+ } else {
+ if (rdatap) /* If we had data */
+ if (*rdatap) /* add a line terminator */
+ if (remfile) { /* to file */
+ zsoutl(ZOFILE,"");
+ } else { /* or to screen. */
+#ifndef NOICP
+ if (!query || !xcmdsrc)
+#endif /* NOICP */
+ if (!(quiet && rcdactive))
+ conoll("");
+ }
+ if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */
+ msleep(500); /* command and got the ACK... */
+ bye_active = 0;
+ ttclos(0);
+ }
+ clsof(0);
+ if (!epktsent && !epktrcvd) /* If no error packet... */
+ success = 1; /* success. */
+ RESUME;
+ return(-1);
+ }
+ } else { /* File not opened OK */
+ errpkt((CHAR *) rf_err); /* send error message */
+ RESUME; /* and quit. */
+ return(-1);
+ }
+#endif /* NOSERVER */
+#ifdef PKTZEROHACK
+ }
+#endif /* PKTZEROHACK */
+ debug(F101,"rcv_shortreply fallthru","",success);
+ return(-1);
+}
+
+
+static int
+srv_query() {
+#ifndef NOSERVER
+#ifndef NOSPL
+ char c;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), "");
+#endif /* IKSDB */
+ c = *(srvcmd+2); /* Q = Query, S = Set */
+ if (c == 'Q') { /* Query */
+ if (!ENABLED(en_que)) { /* Security */
+ errpkt((CHAR *)"REMOTE QUERY disabled");
+ RESUME;
+ return(-1);
+ } else { /* Query allowed */
+ int n; char *p, *q;
+ qbufp = querybuf; /* Wipe out old stuff */
+ qbufn = 0;
+ querybuf[0] = NUL;
+ p = (char *) srvcmd + 3; /* Pointer for making wrapper */
+ n = strlen((char *)srvcmd); /* Position of end */
+ c = *(srvcmd+4); /* Which type of variable */
+
+ if (*(srvcmd+6) == CMDQ) { /* Starts with command quote? */
+ p = (char *) srvcmd + 6; /* Take it literally */
+ if (*p == CMDQ) p++;
+ } else { /* They played by the rules */
+ if (c == 'K') { /* Kermit variable */
+ int k;
+ k = (int) strlen(p);
+ if (k > 0 && p[k-1] == ')') {
+ p = (char *)(srvcmd + 4);
+ *(srvcmd+4) = CMDQ;
+ *(srvcmd+5) = 'f'; /* Function, so make it \f...() */
+ } else {
+ *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
+ *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
+ *(srvcmd+5) = '('; /* around variable name */
+ *(srvcmd+n) = ')';
+ *(srvcmd+n+1) = NUL;
+ }
+ } else {
+ *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */
+ *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */
+ *(srvcmd+5) = '('; /* around variable name */
+ *(srvcmd+n) = ')';
+ *(srvcmd+n+1) = NUL;
+ if (c == 'S') { /* System variable */
+ *(srvcmd+4) = '$'; /* so it's \$(...) */
+ } else if (c == 'G') { /* Non-\ Global variable */
+ *(srvcmd+4) = 'm'; /* so wrap it in \m(...) */
+ }
+ }
+ } /* Now evaluate it */
+ n = QBUFL; /* Max length */
+ q = querybuf; /* Where to put it */
+ if (zzstring(p,&q,&n) < 0) {
+ errpkt((n > 0) ? (CHAR *)"Can't get value"
+ : (CHAR *)"Value too long"
+ );
+ RESUME;
+ return(-1);
+ } else {
+ if (encstr((CHAR *)querybuf) > -1) { /* Encode it */
+ ack1(data); /* If it fits, send it back in ACK */
+ success = 1;
+ RESUME;
+ return(-1);
+ } else if (sndstring(querybuf)) { /* Long form response */
+ BEGIN ssinit;
+ return(-1);
+ } else { /* sndhlp() fails */
+ errpkt((CHAR *)"Can't send value");
+ RESUME;
+ return(-1);
+ }
+ }
+ }
+ } else if (c == 'S') { /* Set (assign) */
+ if (!ENABLED(en_asg)) { /* Security */
+ errpkt((CHAR *)"REMOTE ASSIGN disabled");
+ RESUME;
+ return(-1);
+ } else { /* OK */
+ int n;
+ n = xunchar(*(srvcmd+3)); /* Length of name */
+ n = 3 + n + 1; /* Position of length of value */
+ *(srvcmd+n) = NUL; /* Don't need it */
+ if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0)
+ errpkt((CHAR *)"REMOTE ASSIGN failed");
+ else {
+ ack();
+ success = 1;
+ }
+ RESUME;
+ return(-1);
+ }
+ } else {
+ errpkt((CHAR *)"Badly formed server command");
+ RESUME;
+ return(-1);
+ }
+#else
+ errpkt((CHAR *)"Variable query/set not available");
+ RESUME;
+ return(-1);
+#endif /* NOSPL */
+#endif /* NOSERVER */
+}
+
+static int
+srv_copy() {
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef ZCOPY
+ if (!ENABLED(en_cpy)) {
+ errpkt((CHAR *)"REMOTE COPY disabled");
+ RESUME;
+ return(-1);
+ } else {
+ char *str1, *str2, f1[256], f2[256];
+ int len1, len2;
+ len1 = xunchar(srvcmd[1]); /* Separate the parameters */
+ len2 = xunchar(srvcmd[2+len1]);
+ strncpy(f1,(char *)(srvcmd+2),len1);
+ f1[len1] = NUL;
+ strncpy(f2,(char *)(srvcmd+3+len1),len2);
+ f2[len2] = NUL;
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2);
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* If CWD is disabled */
+ zstrip(f1,&str1); /* and they included a pathname, */
+ zstrip(f2,&str2);
+ if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ return(-1);
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ if (zcopy(f1,f2)) { /* Try */
+ errpkt((CHAR *)"Can't copy file"); /* give error message */
+ } else {
+ success = 1;
+ ack();
+ }
+ RESUME; /* wait for next server command */
+ return(-1);
+ }
+ }
+ return(-1);
+#else /* no ZCOPY */
+ errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */
+ RESUME; /* wait for next server command */
+ return(-1);
+#endif /* ZCOPY */
+#endif /* NOSERVER */
+}
+
+static int
+srv_rename() {
+#ifndef NOSERVER
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd);
+#endif /* CKSYSLOG */
+#ifdef ZRENAME
+ if (!ENABLED(en_ren)) {
+ errpkt((CHAR *)"REMOTE RENAME disabled");
+ RESUME;
+ return(-1);
+ } else { /* RENAME is enabled */
+ char *str1, *str2, f1[256], f2[256];
+ int len1, len2;
+ len1 = xunchar(srvcmd[1]); /* Separate the parameters */
+ len2 = xunchar(srvcmd[2+len1]);
+ strncpy(f1,(char *)(srvcmd+2),len1);
+ f1[len1] = NUL;
+ strncpy(f2,(char *)(srvcmd+3+len1),len2);
+ f2[len2] = NUL;
+ len2 = xunchar(srvcmd[2+len1]);
+ strncpy(f1,(char *)(srvcmd+2),len1);
+ f1[len1] = NUL;
+ strncpy(f2,(char *)(srvcmd+3+len1),len2);
+ f2[len2] = NUL;
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2);
+#endif /* IKSDB */
+ if (!ENABLED(en_cwd)) { /* If CWD is disabled */
+ zstrip(f1,&str1); /* and they included a pathname, */
+ zstrip(f2,&str2);
+ if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */
+ errpkt((CHAR *)"Access denied");
+ RESUME; /* Remember, this is not a goto! */
+ return(-1);
+ }
+ }
+ if (state == generic) { /* It's OK to go ahead. */
+ if (zrename(f1,f2)) { /* Try */
+ errpkt((CHAR *)"Can't rename file"); /* Give error msg */
+ } else {
+ success = 1;
+ ack();
+ }
+ RESUME; /* Wait for next server command */
+ return(-1);
+ }
+ }
+ return(-1);
+#else /* no ZRENAME */
+ /* Give error message */
+ errpkt((CHAR *)"REMOTE RENAME not available");
+ RESUME; /* Wait for next server command */
+ return(-1);
+#endif /* ZRENAME */
+#endif /* NOSERVER */
+}
+
+static int
+srv_login() {
+#ifndef NOSERVER
+ char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1];
+ CHAR *p;
+ int len, i;
+
+ debug(F101,"REMOTE LOGIN x_login","",x_login);
+ debug(F101,"REMOTE LOGIN x_logged","",x_logged);
+
+ f1[0] = NUL; f2[0] = NUL; f3[0] = NUL;
+ len = 0;
+ if (srvcmd[1]) /* First length field */
+ len = xunchar(srvcmd[1]); /* Separate the parameters */
+
+ if (x_login) { /* Login required */
+ if (x_logged) { /* And already logged in */
+ if (len > 0) { /* Logging in again */
+ errpkt((CHAR *)"Already logged in.");
+ } else { /* Logging out */
+ debug(F101,"REMOTE LOGOUT","",x_logged);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", "");
+#endif /* IKSDB */
+ tlog(F110,"Logged out",x_user,0);
+ ack1((CHAR *)"Logged out");
+ success = 1;
+ msleep(500);
+#ifdef CK_LOGIN
+ x_logged = 0;
+#ifdef IKSD
+ if (inserver)
+ ckxlogout();
+#endif /* IKSD */
+#endif /* CK_LOGIN */
+ }
+ } else { /* Not logged in yet */
+ debug(F101,"REMOTE LOGIN len","",len);
+ if (len > 0) { /* Have username */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL);
+#endif /* CKSYSLOG */
+ if (len > LOGINLEN) {
+ errpkt((CHAR *)"Username too long");
+ }
+ p = srvcmd + 2; /* Point to it */
+ for (i = 0; i < len; i++) /* Copy it */
+ f1[i] = p[i];
+ f1[len] = NUL; /* Terminate it */
+ p += len; /* Point to next length field */
+ if (*p) { /* If we have one */
+ len = xunchar(*p++); /* decode it */
+ if (len > 0 && len <= LOGINLEN) {
+ for (i = 0; i < len; i++) /* Same deal for password */
+ f2[i] = p[i];
+ f2[len] = NUL;
+ p += len; /* And account */
+ if (*p) {
+ len = xunchar(*p++);
+ if (len > 0 && len <= LOGINLEN) {
+ for (i = 0; i < len; i++)
+ f3[i] = p[i]; /* Set but never used */
+ f3[len] = NUL; /* (because account not used) */
+ }
+ }
+ }
+ }
+ debug(F101,"REMOTE LOGIN 1","",x_logged);
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver) { /* Log in to system for real */
+ x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
+ debug(F101,"REMOTE LOGIN 2","",x_logged);
+ if (x_logged) { /* Count attempts */
+ logtries = 0;
+ justone = 1;
+ } else {
+ logtries++;
+ sleep(logtries);
+ }
+ } else
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ if (x_user && x_passwd) { /* User and password must match */
+ if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */
+ if (!strcmp(x_passwd,f2))
+ x_logged = 1;
+ debug(F101,"REMOTE LOGIN 3","",x_logged);
+ } else if (x_user) { /* Only username given, no password */
+ if (!strcmp(x_user,f1)) /* so only username must match */
+ x_logged = 1;
+ debug(F101,"REMOTE LOGIN 4","",x_logged);
+ }
+#ifdef CK_LOGIN
+ else {
+ x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0);
+ debug(F101,"REMOTE LOGIN 5","",x_logged);
+ }
+#endif /* CK_LOGIN */
+ if (x_logged) { /* Logged in? */
+ tlog(F110,"Logged in", x_user, 0);
+ if (isguest)
+ ack1((CHAR *)"Logged in as guest - restrictions apply");
+ else
+ ack1((CHAR *)"Logged in");
+ success = 1;
+ } else {
+ tlog(F110,"Login failed", f1, 0);
+ errpkt((CHAR *)"Access denied.");
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && logtries > 2)
+ ckxlogout();
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ }
+ } else { /* LOGOUT */
+ errpkt((CHAR *)"Logout ignored");
+ }
+ }
+ } else { /* Login not required */
+ if (len > 0)
+ errpkt((CHAR *)"Login ignored.");
+ else
+ errpkt((CHAR *)"Logout ignored.");
+ }
+#endif /* NOSERVER */
+ RESUME;
+ return(-1);
+}
+
+static int
+srv_timeout() {
+ /* K95 does this its own way */
+ if (idletmo) {
+#ifdef IKSD
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl);
+ doexit(GOOD_EXIT,xitsta);
+ }
+#endif /* IKSD */
+ idletmo = 0;
+ printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl);
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ }
+#ifndef NOSERVER
+ else if (fatalio) { /* Connection lost */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL);
+#endif /* CKSYSLOG */
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, "");
+#endif /* IKSDB */
+ xitsta |= what;
+ QUIT;
+ } else if (interrupted) { /* Interrupted by hand */
+ if (!ENABLED(en_fin)) {
+ errpkt((CHAR *)"QUIT disabled");
+ RESUME;
+ return(-1);
+ } else {
+ if (what == W_SEND || what == W_RECV || what == W_REMO) {
+ success = 0;
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_PR && ckxlogging)
+ cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL);
+#endif /* CKSYSLOG */
+ } else if (what == W_NOTHING && filcnt == 0) {
+ success = 1;
+ } /* Otherwise leave success alone */
+ xitsta |= (what & W_KERMIT);
+ QUIT;
+ }
+ } else { /* Shouldn't happen */
+ debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0);
+ QUIT;
+ }
+#endif /* NOSERVER */
+}
+
+static int
+rcv_s_pkt() {
+#ifndef NOSERVER
+ if (state == rgen)
+ urserver = 1;
+ if (/* state == serve && */ x_login && !x_logged) {
+ errpkt((CHAR *)"Login required");
+ SERVE;
+ } else
+#endif /* NOSERVER */
+ if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */
+ errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */
+ RESUME;
+ return(-1);
+ } else { /* OK to go ahead. */
+#ifdef CK_TMPDIR
+ if (dldir && !f_tmpdir) { /* If they have a download directory */
+ debug(F110,"receive download dir",dldir,0);
+ if (s = zgtdir()) { /* Get current directory */
+ debug(F110,"receive current dir",s,0);
+ if (zchdir(dldir)) { /* Change to download directory */
+ debug(F100,"receive zchdir ok","",0);
+ ckstrncpy(savdir,s,TMPDIRLEN);
+ f_tmpdir = 1; /* Remember that we did this */
+ } else
+ debug(F100,"receive zchdir failed","",0);
+ }
+ }
+#endif /* CK_TMPDIR */
+ nakstate = 1; /* Can send NAKs from here. */
+ rinit(rdatap); /* Set parameters */
+ if (bctf) {
+ bctu = 3;
+ bctl = 3;
+ } else {
+ bctu = bctr; /* switch to agreed-upon block check */
+ bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */
+ }
+ what = W_RECV; /* Remember we're receiving */
+ lastxfer = W_RECV;
+ resetc(); /* Reset counters */
+ rtimer(); /* Reset timer */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ streamon();
+ BEGIN rfile; /* Go into receive-file state */
+ }
+ return(-1);
+}
+
+
+/* END OF ROUTINES MOVED OUT OF STATE MACHINE */
+
+
+/* P R O T O -- Protocol entry function */
+
+static int is_tn = 0; /* It's a Telnet connection */
+
+#ifdef CK_SPEED
+int f_ctlp = 0; /* Control-character prefix table */
+#ifdef COMMENT
+short s_ctlp[256];
+#endif /* COMMENT */
+#endif /* CK_SPEED */
+
+/*
+ This is simply a wrapper for the real protocol function just below,
+ that saves any items that might be changed automatically by protocol
+ negotiations and then restores them upon exit from protocol mode.
+*/
+VOID
+proto() {
+ extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear;
+#ifndef NOCSETS
+ extern int fcharset, fcs_save, tcharset, tcs_save;
+#endif /* NOCSETS */
+
+#ifdef PIPESEND
+ extern int pipesend;
+#endif /* PIPESEND */
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int cursorena[], cursor_save, term_io;
+ extern BYTE vmode;
+ extern int display_demo;
+ int term_io_save;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef TNCODE
+ int _u_bin=0, _me_bin = 0;
+#ifdef IKS_OPTION
+ int /* _u_start=0, */ _me_start = 0;
+#endif /* IKS_OPTION */
+#endif /* TNCODE */
+#ifdef PATTERNS
+ int pa_save;
+ int i;
+#endif /* PATTERNS */
+ int scan_save;
+
+#ifdef PATTERNS
+ pa_save = patterns;
+#endif /* PATTERNS */
+ scan_save = filepeek;
+
+ myjob = sstate;
+
+#ifdef CK_LOGIN
+ if (isguest) { /* If user is anonymous */
+ en_pri = 0; /* disable printing */
+ en_mai = 0; /* and disable email */
+ en_del = 0; /* and file deletion */
+ }
+#endif /* CK_LOGIN */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ cursor_save = cursorena[vmode];
+ cursorena[vmode] = 0;
+ term_io_save = term_io;
+ term_io = 0;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ b_save = binary; /* SET FILE TYPE */
+ f_save = fncnv; /* SET FILE NAMES */
+ c_save = bctr;
+ p_save = fnspath;
+ r_save = recursive;
+ s_timint = timint;
+ ss_save = slostart;
+#ifndef NOCSETS
+ fcs_save = fcharset;
+ tcs_save = tcharset;
+#endif /* NOCSETS */
+
+#ifdef COMMENT
+/* Don't do this because then user can never find out what happened. */
+#ifdef CK_SPEED
+ for (i = 0; i < 256; i++)
+ s_ctlp[i] = ctlp[i];
+ f_ctlp = 1;
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+ if (reliable == SET_ON)
+ slostart = 0;
+ is_tn = (!local && sstelnet)
+#ifdef TNCODE
+ || (local && network && ttnproto == NP_TELNET)
+#endif /* TNCODE */
+ ;
+#ifdef TNCODE
+ if (is_tn) {
+ if (tn_b_xfer && !(sstelnet || inserver)) {
+ /* Save the current state of Telnet Binary */
+ _u_bin = TELOPT_U(TELOPT_BINARY);
+ _me_bin = TELOPT_ME(TELOPT_BINARY);
+
+ /* If either direction is not Binary attempt to negotiate it */
+ if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) {
+ tn_sopt(DO,TELOPT_BINARY);
+ TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
+ }
+ if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) {
+ tn_sopt(WILL,TELOPT_BINARY);
+ TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
+ }
+ if (!(_me_bin && _u_bin))
+ tn_wait("proto set binary mode");
+ }
+#ifdef IKS_OPTION
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
+ /* _u_start = 1; */
+ }
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_STOP); /* I'm not servering */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ _me_start = 1;
+ }
+ } else
+#endif /* CK_XYZ */
+ if (sstate == 'x' || sstate == 'v') { /* Responding to a request */
+ if (!inserver && TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */
+ /* _u_start = 1; */
+ }
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_START); /* Send Kermit-Server Start */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
+ }
+ } else { /* Initiating a request */
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_STOP); /* I'm not servering */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ _me_start = 1;
+ }
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ /* Send Req-Server-Start */
+ if (!iks_wait(KERMIT_REQ_START,0)) {
+ if (sstate != 's') {
+ success = 0; /* Other Kermit refused to serve */
+ if (local)
+ printf("A Kermit Server is not available\r\n");
+ debug(F110,"proto()",
+ "A Kermit Server is not available",0);
+ tlog(F110,"IKS client/server failure",
+ "A Kermit Server is not available",0);
+ goto xxprotox;
+ }
+ }
+ }
+ }
+#endif /* IKS_OPTION */
+#ifdef CK_ENCRYPTION
+ if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
+ ck_tn_enc_stop();
+ }
+#endif /* CK_ENCRYPTION */
+ }
+#endif /* TNCODE */
+
+ if (!xfrint) connoi();
+ xxproto(); /* Call the real protocol function */
+
+#ifdef IKS_OPTION
+ xxprotox:
+#endif /* IKS_OPTION */
+ xferstat = success; /* Remember transfer status */
+ kactive = 0;
+
+#ifdef TNCODE
+#ifdef CK_ENCRYPTION
+ if (tn_no_encrypt_xfer && !(sstelnet || inserver)) {
+ ck_tn_enc_start();
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ if (TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) {
+ tn_siks(KERMIT_STOP); /* Server is stopped */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ }
+#endif /* IKS_OPTION */
+ if (is_tn && tn_b_xfer && !(sstelnet || inserver)) {
+ /* if we negotiated Binary mode try to reset it */
+ if (!_u_bin) {
+ /* Check to see if the state changed during the transfer */
+ if (TELOPT_U(TELOPT_BINARY)) {
+ tn_sopt(DONT,TELOPT_BINARY);
+ TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1;
+ } else
+ _u_bin = 1; /* So we don't call tn_wait() */
+ }
+ if (!_me_bin) {
+ /* Check to see if the state changed during the transfer */
+ if (TELOPT_ME(TELOPT_BINARY)) {
+ tn_sopt(WONT,TELOPT_BINARY);
+ TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1;
+ } else
+ _me_bin = 1; /* So we don't call tn_wait() */
+ }
+ if (!(_me_bin && _u_bin))
+ tn_wait("proto reset binary mode");
+ }
+#endif /* TNCODE */
+
+#ifdef PATTERNS
+ patterns = pa_save;
+#endif /* PATTERNS */
+ filepeek = scan_save;
+
+#ifdef STREAMING
+ streaming = 0;
+ /* streamok = 0; */
+#endif /* STREAMING */
+#ifdef COMMENT
+#ifdef CK_SPEED
+ for (i = 0; i < 256; i++)
+ ctlp[i] = s_ctlp[i];
+ f_ctlp = 0;
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+ urclear = 0;
+ if (!success) {
+ xitsta |= (what & W_KERMIT);
+ tlog(F110," failed:",(char *)epktmsg,0);
+ }
+ debug(F111,"proto xferstat",epktmsg,xferstat);
+ slostart = ss_save;
+ if (s_timint > -1) { /* Because of REMOTE SET */
+ timint = s_timint;
+ s_timint = -1;
+ }
+ recursive = r_save;
+ fnspath = p_save;
+ if (c_save > -1) { /* Because of REMOTE SET */
+ bctr = c_save;
+ c_save = -1;
+ }
+ fncnv = f_save;
+ binary = b_save;
+#ifdef PIPESEND
+ pipesend = 0; /* Next time might not be pipesend */
+#endif /* PIPESEND */
+#ifndef NOLOCAL
+#ifdef OS2
+ cursorena[vmode] = cursor_save;
+ term_io = term_io_save;
+ display_demo = 1;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+}
+
+static VOID
+xxproto() {
+ int x;
+ long lx;
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+_PROTOTYP( int pxyz, (int) );
+#endif /* XYZ_INTERNAL */
+#endif /* CK_XYZ */
+
+ char xss[2]; /* String representation of sstate */
+ xss[0] = sstate;
+ xss[1] = NUL;
+ s_timint = timint;
+
+ debug(F101,"xxproto entry justone","",justone);
+ success = 0;
+
+ retrieve = 0; /* Reset these ... */
+ reget = 0;
+ opkt = 0;
+
+ if (local && ttchk() < 0) { /* Giving BYE or FIN */
+ if (bye_active) { /* but there is no connection */
+ ttclos(0);
+ success = 1;
+ return;
+ }
+ /* Ditto for any REMOTE command */
+ if (sstate == 'g' && cmarg ) {
+ if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X')
+ success = 1;
+ else
+ printf("?No connection\r\n");
+ return;
+ }
+ }
+
+/* Set up the communication line for file transfer. */
+/* NOTE: All of the xxscreen() calls prior to the wart() invocation */
+/* could just as easily be printf's or, for that matter, hints. */
+
+ if (local && (speed < 0L) && (network == 0)) {
+ xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first");
+ return;
+ }
+ x = -1;
+ if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {
+ debug(F111,"failed: proto ttopen local",ttname,local);
+ xxscreen(SCR_EM,0,0L,"Can't open line");
+ return;
+ }
+ if (x > -1) local = x;
+ debug(F111,"proto ttopen local",ttname,local);
+
+ lx = (local && !network) ? speed : -1;
+#ifdef NETCONN
+#ifdef CK_SPEED
+ if (is_tn) {
+ ctlp[(unsigned)255] = ctlp[CR] = 1;
+ if (parity == 'e' || parity == 'm') ctlp[127] = 1;
+ if (flow == FLO_XONX) { /* Also watch out for Xon/Xoff */
+ ctlp[17] = ctlp[19] = 1;
+ ctlp[17+128] = ctlp[19+128] = 1;
+ }
+ }
+#endif /* CK_SPEED */
+#endif /* NETCONN */
+ if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */
+ xxscreen(SCR_EM,0,0L,"Can't condition line");
+ return;
+ }
+ if (local && !network && carrier != CAR_OFF) {
+ int x; /* Serial connection */
+ x = ttgmdm(); /* with carrier checking */
+ if (x > -1) {
+ if (!(x & BM_DCD)) {
+ debug(F101,"proto ttgmdm","",0);
+ xxscreen(SCR_EM,0,0L,"Carrier required but not detected");
+ return;
+ }
+ }
+ }
+ /* Send remote side's "receive" or "server" startup string, if any */
+ if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) {
+ char *s = NULL;
+ if (
+#ifdef IKS_OPTION
+ /* Don't send auto-blah string if we know other side is serving */
+ !TELOPT_U(TELOPT_KERMIT) ||
+ !TELOPT_SB(TELOPT_KERMIT).kermit.u_start
+#else
+ 1
+#endif /* IKS_OPTION */
+ ) {
+ if (sstate == 's') { /* Sending file(s) */
+ s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init;
+ } else if (protocol == PROTO_K) { /* Command for server */
+ s = ptab[protocol].h_x_init;
+ }
+ }
+#ifdef CK_SPEED
+#ifndef UNPREFIXZERO
+ if (protocol == PROTO_K) /* Because of C-strings... */
+ ctlp[0] = 1;
+#endif /* UNPREFIXZERO */
+#endif /* CK_SPEED */
+ if (s) if (*s) { /* If we have a command to send... */
+ char tmpbuf[356];
+ int tmpbufsiz = 356;
+ int stuff = -1, stuff2 = -1, len = 0;
+ extern int tnlm;
+ if (sstate == 's') { /* Sending file(s) */
+#ifdef CK_XYZ
+ if (protocol == PROTO_X) {
+ char * s2;
+ s2 = cmarg2[0] ? cmarg2 : cmarg;
+ if ((int)strlen(s) + (int)strlen(s2) + 4 < 356)
+ sprintf(tmpbuf, s, s2);
+ else
+ tmpbuf[0] = NUL;
+ } else {
+#endif /* CK_XYZ */
+ ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL);
+#ifdef CK_XYZ
+ }
+#endif /* CK_XYZ */
+ } else { /* Command for server */
+ ckstrncpy(tmpbuf,s,356);
+ }
+ ckstrncat(tmpbuf, "\015",sizeof(tmpbuf));
+ if (tnlm) /* TERMINAL NEWLINE ON */
+ stuff = LF; /* Stuff LF */
+#ifdef TNCODE
+ /* TELNET NEWLINE MODE */
+ if (is_tn) {
+ switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
+ case TNL_CR:
+ break;
+ case TNL_CRNUL:
+ break;
+ case TNL_CRLF:
+ stuff2 = stuff;
+ stuff = LF;
+ break;
+ }
+ }
+#endif /* TNCODE */
+
+#ifdef NETCONN
+#ifdef TCPSOCKET
+#ifdef RLOGCODE
+ if (network && ttnproto == NP_RLOGIN) {
+ switch (tn_b_nlm) { /* Always BINARY */
+ case TNL_CR:
+ break;
+ case TNL_CRNUL:
+ stuff2 = stuff;
+ stuff = NUL;
+ break;
+ case TNL_CRLF:
+ stuff2 = stuff;
+ stuff = LF;
+ break;
+ }
+ }
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+
+ len = strlen(tmpbuf);
+ if (stuff >= 0 && len < tmpbufsiz - 1) {
+ tmpbuf[len++] = stuff;
+ if (stuff2 >= 0 && len < tmpbufsiz - 1)
+ tmpbuf[len++] = stuff2;
+ tmpbuf[len] = NUL;
+ }
+ ttol((CHAR *)tmpbuf,len);
+ if (protocol == PROTO_K) /* Give remote Kermit time to start */
+ msleep(400);
+ }
+ }
+
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) { /* Non-Kermit protocol selected */
+ char tmpbuf[356];
+ int tmpbufsiz = 356;
+ char * s = "";
+
+#ifdef CK_TMPDIR
+ if (sstate == 'v') { /* If receiving and... */
+ if (dldir && !f_tmpdir) { /* if they have a download directory */
+ if (s = zgtdir()) { /* Get current directory */
+ if (zchdir(dldir)) { /* Change to download directory */
+ ckstrncpy(savdir,s,TMPDIRLEN);
+ f_tmpdir = 1; /* Remember that we did this */
+ }
+ }
+ }
+ }
+#endif /* CK_TMPDIR */
+
+#ifdef XYZ_INTERNAL /* Internal */
+ success = !pxyz(sstate);
+#else
+#ifdef CK_REDIR /* External */
+ switch (sstate) {
+ case 's': /* 'Tis better to SEND... */
+ s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd;
+ break;
+ case 'v': /* ... than RECEIVE */
+ s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd;
+ break;
+ }
+ if (!s) s = "";
+ if (*s) {
+ if (sstate == 's') { /* Sending */
+ extern int xfermode;
+ int k = 0, x = 0, b = binary;
+ /*
+ If just one file we can scan it to set the xfer mode.
+ Otherwise it's up to the external protocol program.
+ */
+ if (patterns && xfermode == XMODE_A && !iswild(fspec)) {
+ extern int nscanfile;
+ k = scanfile(fspec,&x,nscanfile);
+ if (k > -1) {
+ b = (k == FT_BIN) ? XYFT_B : XYFT_T;
+ s = b ?
+ ptab[protocol].p_b_scmd :
+ ptab[protocol].p_t_scmd;
+ }
+ }
+ if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
+ sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
+ tlog(F110,"Sending",fspec,0L);
+ }
+ } else { /* Receiving */
+ if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) {
+ sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */
+ tlog(F110,"Receiving",cmarg2,0L);
+ }
+ }
+ tlog(F110," via external protocol:",tmpbuf,0);
+ debug(F110,"ckcpro ttruncmd",tmpbuf,0);
+ success = ttruncmd(tmpbuf);
+ tlog(F110," status:",success ? "OK" : "FAILED", 0);
+ } else {
+ printf("?Sorry, no external protocol defined for %s\r\n",
+ ptab[protocol].p_name
+ );
+ }
+#else
+ printf(
+"Sorry, only Kermit protocol is supported in this version of Kermit\n"
+ );
+#endif /* CK_REDIR */
+#endif /* XYZ_INTERNAL */
+ return;
+ }
+#endif /* CK_XYZ */
+
+#ifdef NTSIGX
+ conraw();
+ connoi();
+#else
+ if (!local)
+ connoi(); /* No console interrupts if remote */
+#endif /* NTSIG */
+
+ kactive = 1;
+ if (sstate == 'x') { /* If entering server mode, */
+ extern int howcalled;
+ server = 1; /* set flag, */
+ debug(F101,"server backgrd","",backgrd);
+ debug(F101,"server quiet","",quiet);
+ debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0);
+ if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */
+ ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
+ } else if (!local) {
+ if (!quiet && !backgrd
+#ifdef IKS_OPTION
+ && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */
+#endif /* IKS_OPTION */
+ ) {
+ conoll(srvtxt);
+ conoll("KERMIT READY TO SERVE...");
+ }
+ } else {
+ conol("Entering server mode on ");
+ conoll(ttname);
+ conoll("Type Ctrl-C to quit.");
+ if (srvdis) intmsg(-1L);
+#ifdef TCPSOCKET
+#ifndef NOLISTEN
+ if (network && tcpsrfd > 0)
+ ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26);
+#endif /* NOLISTEN */
+#endif /* TCPSOCKET */
+ }
+ } else
+ server = 0;
+#ifdef VMS
+ if (!quiet && !backgrd) /* So message doesn't overwrite prompt */
+ conoll("");
+ if (local) conres(); /* So Ctrl-C will work */
+#endif /* VMS */
+/*
+ If in remote mode, not shushed, not in background, and at top command level,
+ issue a helpful message telling what to do...
+*/
+ if (!local && !quiet && !backgrd) {
+ if (sstate == 'v') {
+ conoll("Return to your local Kermit and give a SEND command.");
+ conoll("");
+ conoll("KERMIT READY TO RECEIVE...");
+ } else if (sstate == 's') {
+ conoll("Return to your local Kermit and give a RECEIVE command.");
+ conoll("");
+ conoll("KERMIT READY TO SEND...");
+ } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' ||
+ sstate == 'j' || sstate == 'c' ) {
+ conoll("Return to your local Kermit and give a SERVER command.");
+ conoll("");
+ conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ?
+ "KERMIT READY TO GET..." :
+ "KERMIT READY TO SEND SERVER COMMAND...");
+ }
+ }
+#ifdef COMMENT
+ if (!local) sleep(1);
+#endif /* COMMENT */
+/*
+ The 'wart()' function is generated by the wart program. It gets a
+ character from the input() routine and then based on that character and
+ the current state, selects the appropriate action, according to the state
+ table above, which is transformed by the wart program into a big case
+ statement. The function is active for one transaction.
+*/
+ rtimer(); /* Reset elapsed-time timer */
+#ifdef GFTIMER
+ rftimer();
+#endif /* GFTIMER */
+ resetc(); /* & other per-transaction counters. */
+
+ debug(F101,"proto calling wart, justone","",justone);
+
+ wart(); /* Enter the state table switcher. */
+/*
+ Note: the following is necessary in case we have just done a remote-mode
+ file transfer, in which case the controlling terminal modes have been
+ changed by ttpkt(). In particular, special characters like Ctrl-C and
+ Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is
+ essential. IMPORTANT: restore interrupt handlers first, otherwise any
+ terminal interrupts that occur before this is done in the normal place
+ later will cause a crash.
+*/
+#ifdef OS2
+ ttres(); /* Reset the communication device */
+#else
+ if (!local) {
+ setint(); /* Arm interrupt handlers FIRST */
+ msleep(500);
+ ttres(); /* Then restore terminal. */
+ }
+#endif /* OS2 */
+ xxscreen(SCR_TC,0,0L,""); /* Transaction complete */
+ x = quiet;
+ quiet=1;
+ clsif(); /* Failsafe in case we missed */
+ clsof(1); /* a case in the state machine. */
+ quiet = x;
+
+ if (server) { /* Back from packet protocol. */
+ if (!quiet && !backgrd
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) { /* Give appropriate message */
+ conoll("");
+ conoll("C-Kermit server done");
+ }
+ server = 0; /* Not a server any more */
+ }
+}
+
+/* S G E T I N I T -- Handle incoming GET-Class packets */
+
+/*
+ Returns:
+ -1: On error
+ 0: GET packet processed OK - ready to Send.
+ 1: Extended GET processed OK - wait for another.
+*/
+static int
+sgetinit(reget,xget) int reget, xget; { /* Server end of GET command */
+ char * fs = NULL; /* Pointer to filespec */
+ int i, n, done = 0;
+#ifdef PIPESEND
+ extern int usepipes, pipesend;
+#endif /* PIPESEND */
+ extern int nolinks;
+
+ if (!ENABLED(en_get)) { /* Only if not disabled! */
+ errpkt((CHAR *)"GET disabled");
+ return(-1);
+ }
+
+ /* OK to proceed */
+
+ nolinks = recursive;
+ filcnt = 0;
+
+#ifdef WHATAMI
+ /* If they are alike this was already done in whoarewe() */
+ debug(F101,"sgetinit whatru","",whatru);
+ if (whatru & WMI_FLAG) { /* Did we get WHATAMI info? */
+ debug(F101,"sgetinit binary (1)","",binary);
+#ifdef VMS
+ if (binary != XYFT_I && binary != XYFT_L)
+#else
+#ifdef OS2
+ if (binary != XYFT_L)
+#endif /* OS2 */
+#endif /* VMS */
+ binary = (whatru & WMI_FMODE) ? /* Yes, set file type */
+ XYFT_B : XYFT_T; /* automatically */
+ debug(F101,"sgetinit binary (2)","",binary);
+ if (!wearealike)
+ fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */
+ }
+#endif /* WHATAMI */
+
+ fs = (char *)srvcmd;
+ srvptr = srvcmd; /* Point to server command buffer */
+ decode(rdatap,putsrv,0); /* Decode the GET command into it */
+ /* Accept multiple filespecs */
+ cmarg2 = ""; /* Don't use cmarg2 */
+ cmarg = ""; /* Don't use cmarg */
+
+ done = 1; /* Only 1 packet needed... */
+ if (xget) { /* Special decoding for Extended GET */
+ char L, next, c; /* PLV items */
+ int len, val; /* More PLV items */
+ char * p = (char *)srvcmd; /* String to decode */
+
+ done = 0; /* Maybe more packets needed */
+ fs = NULL; /* We don't know the filespec yet */
+ c = *p++; /* Get first parameter */
+
+ while (c) { /* For all parameters... */
+ debug(F000,"sgetinit c","",c);
+ L = *p++; /* Get length */
+ if (L >= SP) /* Decode length */
+ len = xunchar(L);
+ else if (c == '@') { /* Allow missing EOP length field */
+ len = 0;
+ } else {
+ len = (xunchar(*p++) * 95);
+ len += xunchar(*p++);
+ }
+ debug(F101,"sgetinit len","",len);
+ next = *(p+len); /* Get next parameter */
+ *(p+len) = NUL; /* Zero it out to terminal value */
+ debug(F110,"sgetinit p",p,0);
+ switch (c) { /* Do the parameter */
+ case 'O': /* GET Options */
+ val = atoi(p); /* Convert to int */
+ debug(F101,"sgetinit O val","",val);
+ if (val & GOPT_DEL) moving = 1;
+ if (val & GOPT_RES) reget = 1;
+ if (val & GOPT_REC) {
+ recursive = 1;
+ nolinks = 2;
+ if (fnspath == PATH_OFF)
+ fnspath = PATH_REL;
+ }
+ break;
+ case 'M': /* Transfer Mode */
+ val = atoi(p);
+ debug(F101,"sgetinit M val","",val);
+ if (val < 1)
+ break;
+ patterns = 0; /* Takes precedence over patterns */
+ filepeek = 0; /* and FILE SCAN */
+ if (val == GMOD_TXT) binary = XYFT_T; /* Text */
+ if (val == GMOD_BIN) binary = XYFT_B; /* Binary */
+ if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */
+ break;
+ case 'F': /* Filename */
+ fs = p;
+ debug(F110,"sgetinit filename",fs,0);
+ break;
+ case '@': /* End Of Parameters */
+ done = 1;
+ debug(F100,"sgetinit EOP","",0);
+ break;
+ default:
+ errpkt((CHAR *)"Unknown GET Parameter");
+ debug(F100,"sgetinit unknown parameter","",0);
+ return(-1);
+ }
+ p += (len + 1);
+ c = next;
+ }
+ }
+ if (!fs) fs = ""; /* A filename is required */
+ if (*fs) {
+ havefs = 1;
+ n = 0; /* Check for quoted name */
+ if ((n = strlen(fs)) > 1) {
+ /* Note: this does not allow for multiple quoted names */
+ if ((fs[0] == '{' && fs[n-1] == '}') ||
+ (fs[0] == '"' && fs[n-1] == '"')) {
+ fs[n-1] = '\0';
+ fs++;
+ debug(F111,"sgetinit unquoted filename",fs,n);
+ } else
+ n = 0; /* This means no quoting */
+ }
+
+#ifdef PIPESEND
+ debug(F111,"sgetinit",fs,usepipes);
+ if (usepipes && ENABLED(en_hos) && *fs == '!') {
+ cmarg = fs + 1; /* Point past the bang */
+ *fs = NUL;
+ nfils = -1;
+ pipesend = 1;
+ debug(F111,"sgetinit pipesend",cmarg,pipesend);
+ }
+ if (!pipesend) { /* If it's not a pipe */
+#endif /* PIPESEND */
+ if (n == 0) { /* If the name was not quoted */
+#ifndef NOMSEND
+ nfils = fnparse(fs); /* Allow it to be a list of names */
+ debug(F111,"sgetinit A",fs,nfils);
+#ifdef COMMENT
+/* This doesn't work if a GET-PATH is set. */
+ if (nfils == 1 && !iswild(fs)) { /* Single file */
+ char * m;
+ if ((x = zchki(fs)) < 0) { /* Check if it's sendable */
+ switch (x) {
+ case -1: m = "File not found"; break;
+ case -2: m = "Not a regular file"; break;
+ case -3: m = "Read access denied"; break;
+ }
+ errpkt((CHAR *)m);
+ return(-1);
+ }
+ }
+#endif /* COMMENT */
+ } else { /* If it was quoted */
+#endif /* NOMSEND */
+ nzxopts = 0;
+#ifdef UNIXOROSK
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+#endif /* UNIXOROSK */
+ if (recursive) nzxopts |= ZX_RECURSE;
+ /* Treat as a single filespec */
+ nfils = 0 - nzxpand(fs,nzxopts);
+ debug(F111,"sgetinit B",fs,nfils);
+ cmarg = fs;
+ }
+#ifdef PIPESEND
+ }
+#endif /* PIPESEND */
+ }
+ if (!done) { /* Need more O packets... */
+ debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */
+ return(1);
+ }
+ debug(F100,"sgetinit O-Packet done - havefs","",havefs);
+ if (!havefs) { /* Done - make sure we have filename */
+ errpkt((CHAR *)"GET without filename");
+ return(-1);
+ }
+ freerpkt(winlo);
+ winlo = 0; /* Back to packet 0 again. */
+ debug(F101,"sgetinit winlo","",winlo);
+ nakstate = 0; /* Now I'm the sender! */
+ if (reget) sendmode = SM_RESEND;
+ if (sinit() > 0) { /* Send Send-Init */
+#ifdef STREAMING
+ if (!streaming)
+#endif /* STREAMING */
+ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */
+ return(0); /* If successful, switch state */
+ } else return(-1); /* Else back to server command wait */
+}
+
+#else /* NOXFER */
+
+#include "ckcdeb.h"
+
+VOID
+proto() {
+ extern int success;
+ success = 0;
+}
+#endif /* NOXFER */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcsig.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcsig.h
new file mode 100644
index 0000000..f0ba85c
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcsig.h
@@ -0,0 +1,214 @@
+/* C K C S I G . H */
+
+/* Definitions and prototypes for signal handling */
+
+/*
+ Author: Jeffrey E Altman (jaltman@secure-endpoints.com),
+ Secure Endpoints Inc., New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifdef OS2
+#ifndef NT
+#ifndef __HEV__ /* INCL_SEMAPHORE may also define HEV */
+#define __HEV__
+typedef ULONG HEV; /* hev */
+typedef HEV *PHEV;
+#endif /* __HEV__ */
+#endif /* NT */
+struct _threadinfo {
+ int inuse;
+ int child;
+ int sibling;
+#ifdef NT
+ HANDLE id;
+ HANDLE handle;
+ HANDLE parent;
+ HANDLE CompletionSem ;
+ HANDLE DieSem ;
+#else /* NT */
+ TID id;
+ TID parent;
+ HEV CompletionSem;
+ HEV DieSem;
+#endif /* NT */
+};
+#endif /* OS2 */
+
+#ifdef CK_ANSIC
+typedef SIGTYP (*ck_sigfunc)(void *);
+typedef SIGTYP (*ck_sighand)(int);
+#else
+typedef SIGTYP (*ck_sigfunc)();
+typedef SIGTYP (*ck_sighand)();
+#endif /* CK_ANSIC */
+
+/* Macros for POSIX vs old-style signal handling. */
+
+#ifdef CK_POSIX_SIG
+typedef sigjmp_buf ckjmpbuf;
+#else
+#ifdef NT
+#define NOCRYPT
+#include <windows.h>
+#ifdef NTASM
+typedef struct {
+ CONTEXT context;
+ DWORD retcode;
+} ckjmpbuf;
+#else /* NTASM */
+typedef jmp_buf ckjmpbuf;
+#endif /* NTASM */
+#else
+typedef jmp_buf ckjmpbuf;
+#endif
+#endif /* CK_POSIX_SIG */
+/*
+ Suppose you want to pass the address of a jmp_buf bar to a function foo.
+ Since jmp_buf is normally defined (typedef'd) as an array, you would do
+ it like this: foo(bar), where foo = foo(jmp_buf bar). But suppose a
+ jmp_buf is (say) a struct rather than an array. Then you must do
+ foo(&bar) where foo is foo(jmp_buf * bar). This is controlled here in
+ the traditional fashion, by ifdefs. By default, we assume that jmp_buf
+ is an array. Define the symbol JBNOTARRAY if jmp_buf is not an array.
+*/
+#ifndef JBNOTARRAY
+#ifdef NT
+#define JBNOTARRAY
+#endif /* NT */
+#endif /* JBNOTARRAY */
+
+#ifdef JBNOTARRAY
+typedef ckjmpbuf * ckjptr;
+#define ckjaddr(x) & x
+#define ckjdref(x) * x
+#ifdef CK_POSIX_SIG
+#define cksetjmp(x) sigsetjmp(x,1)
+#define cklongjmp(x,y) siglongjmp(x,y)
+#else
+#ifdef NT
+__inline int
+ck_ih(void) {
+ extern int TlsIndex;
+#ifdef NTSIG
+ struct _threadinfo * threadinfo;
+ threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
+ if (threadinfo) {
+ if (WaitAndResetSem(threadinfo->DieSem,0)) {
+ ckThreadDie(threadinfo);
+ return 1; /* This should never execute */
+ }
+ }
+#ifdef COMMENT
+ else debug( F100, "ck_ih() threadinfo is NULL","",0);
+#endif /* COMMENT */
+#endif /* NTSIG */
+ return 0;
+}
+#ifdef NTSIG
+#define cksetjmp(x) setjmp(x)
+#define cklongjmp(x,y) longjmp(x,y)
+#else /* NTSIG */
+#ifdef NTASM
+__inline DWORD
+cksetjmp( ckjptr jmp ) {
+ extern int isinterrupted;
+ jmp->retcode = 0;
+ memset( &jmp->context, 0, sizeof(CONTEXT) );
+ jmp->context.ContextFlags = CONTEXT_FULL ;
+ if ( !GetThreadContext( GetCurrentThread(), &jmp->context ) )
+ debug( F101, "cksetjmp GetThreadContext failed","",GetLastError());
+ debug(F101,"cksetjmp returns","",jmp->retcode);
+ isinterrupted = 0;
+ return (jmp->retcode);
+}
+
+__inline void
+cklongjmp( ckjptr jmp, int retval ) {
+ extern HANDLE tidCommand;
+ extern int ttyfd, mdmtyp ;
+ extern DWORD CommandID;
+ extern int isinterrupted;
+
+ connoi();
+ isinterrupted = 1;
+ jmp->retcode = ( retval ? retval : 1 );
+ debug(F101,"about to SetThreadContext for thread","", CommandID);
+ debug(F101,"from Thread","",GetCurrentThreadId());
+ if ( mdmtyp >= 0 ) {
+ PurgeComm( (HANDLE) ttyfd, PURGE_TXABORT | PURGE_RXABORT );
+ }
+ if (SetThreadContext( tidCommand, &jmp->context ))
+ debug(F100,"cklongjmp SetThreadContext success","",0);
+ else
+ debug(F101,"cklongjmp SetThreadContext failed","",GetLastError());
+ msleep(50);
+ cmini(1); /* Reset command parser */
+ putkey(13); /* Stuff a carriage return */
+ /* PostEventAvailSem(); */
+}
+#else /* NTASM */
+void crash( void ) ;
+#define cksetjmp(x) setjmp(x)
+__inline void
+cklongjmp( ckjptr jmp, int retval ) {
+ extern HANDLE tidCommand;
+ extern int ttyfd, mdmtyp;
+ extern DWORD CommandID;
+ CONTEXT context;
+
+ if ( mdmtyp >= 0 ) {
+ PurgeComm( (HANDLE) ttyfd, PURGE_TXABORT | PURGE_RXABORT ) ;
+ }
+ memset( &context, 0, sizeof(CONTEXT) );
+ context.ContextFlags = CONTEXT_FULL;
+ if ( !GetThreadContext( tidCommand, &context ) )
+ debug( F101, "cklongjmp GetThreadContext failed","",GetLastError());
+
+ /* Invalidate the instruction pointer */
+ context.Eip = (unsigned long) crash;
+
+ debug(F101,"about to SetThreadContext for thread","", CommandID);
+ debug(F101,"from Thread","",GetCurrentThreadId());
+ if (SetThreadContext( tidCommand, &context ))
+ debug(F100,"cklongjmp SetThreadContext success","",0);
+ else
+ debug(F101,"cklongjmp SetThreadContext failed","",GetLastError());
+}
+#endif /* NTASM */
+#endif /* NTSIG */
+#else /* NT */
+#define cksetjmp(x) setjmp(x)
+#define cklongjmp(x,y) longjmp(x,y)
+#endif /* NT */
+#endif /* CK_POSIX_SIG */
+#else /* jmp_buf is an array */
+typedef ckjmpbuf ckjptr;
+#define ckjaddr(x) x
+#define ckjdref(x) x
+#ifdef CK_POSIX_SIG
+#define cksetjmp(x) sigsetjmp(x,1)
+#define cklongjmp(x,y) siglongjmp(x,y)
+#else
+#define cksetjmp(x) setjmp(x)
+#define cklongjmp(x,y) longjmp(x,y)
+#endif /* CK_POSIX_SIG */
+#endif /* JBNOTARRAY */
+
+_PROTOTYP( int cc_execute, (ckjptr, ck_sigfunc, ck_sigfunc) );
+_PROTOTYP( int alrm_execute,
+ (ckjptr,
+ int /* timo */,
+ ck_sighand /* handler */,
+ ck_sigfunc, ck_sigfunc) );
+_PROTOTYP( int cc_alrm_execute,
+ (ckjptr,
+ int /* timo */,
+ ck_sighand /* handler */,
+ ck_sigfunc,
+ ck_sigfunc) );
+
+/* End of ckusig.h */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcssl.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcssl.h
new file mode 100644
index 0000000..4e31f12
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcssl.h
@@ -0,0 +1,126 @@
+#ifdef CK_SSL
+#ifndef CK_ANSIC
+#define NOPROTO
+#endif /* CK_ANSIC */
+#include "bio.h"
+#include "buffer.h"
+#include "x509.h"
+#include "pem.h"
+#include "ssl.h"
+
+extern BIO *bio_err;
+extern SSL *ssl_con;
+extern SSL_CTX *ssl_ctx;
+extern int ssl_debug_flag;
+extern int ssl_only_flag;
+extern int ssl_active_flag;
+extern int ssl_verify_flag;
+extern int ssl_secure_flag;
+extern int ssl_verbose_flag;
+extern int ssl_disabled_flag;
+extern int ssl_cert_required;
+extern int ssl_certsok_flag;
+extern int ssl_dummy_flag;
+
+extern char *ssl_log_file;
+extern char *ssl_rsa_cert_file;
+extern char *ssl_rsa_key_file;
+extern char *ssl_dsa_cert_file;
+extern char *ssl_dh_key_file;
+extern char *ssl_cipher_list;
+
+extern SSL_CTX *tls_ctx;
+extern SSL *tls_con;
+extern int tls_only_flag;
+extern int tls_active_flag;
+extern int tls_secure_flag;
+
+_PROTOTYP(int ssl_do_init,(int));
+_PROTOTYP(int ssl_display_connect_details,(SSL *,int));
+_PROTOTYP(int ssl_server_verify_callback,(int, X509_STORE_CTX *));
+_PROTOTYP(int ssl_client_verify_callback,(int, X509_STORE_CTX *));
+
+#ifdef OS2
+#define SSL_get_error ck_SSL_get_error
+#define SSL_read ck_SSL_read
+#define SSL_peek ck_SSL_peek
+#define SSL_connect ck_SSL_connect
+#define SSL_set_fd ck_SSL_set_fd
+#define SSL_free ck_SSL_free
+#define SSL_shutdown ck_SSL_shutdown
+#define SSL_write ck_SSL_write
+#define SSL_pending ck_SSL_pending
+#define SSL_load_error_strings ck_SSL_load_error_strings
+#define SSL_get_peer_certificate ck_SSL_get_peer_certificate
+#define SSL_CIPHER_get_name ck_SSL_CIPHER_get_name
+#define SSL_get_current_cipher ck_SSL_get_current_cipher
+#define SSL_get_shared_ciphers ck_SSL_get_shared_ciphers
+#define SSL_get_ciphers ck_SSL_get_ciphers
+#define SSL_get_cipher_list ck_SSL_get_cipher_list
+#define SSL_CTX_set_default_verify_paths ck_SSL_CTX_set_default_verify_paths
+#define SSL_use_RSAPrivateKey_file ck_SSL_use_RSAPrivateKey_file
+#define SSL_use_DSAPrivateKey_file ck_SSL_use_DSAPrivateKey_file
+#define SSL_use_PrivateKey_file ck_SSL_use_PrivateKey_file
+#define SSL_use_certificate_file ck_SSL_use_certificate_file
+#define SSL_CTX_use_PrivateKey_file ck_SSL_CTX_use_PrivateKey_file
+#define SSL_CTX_use_certificate_file ck_SSL_CTX_use_certificate_file
+#define SSL_set_verify ck_SSL_set_verify
+#define SSL_new ck_SSL_new
+#define SSL_CTX_ctrl ck_SSL_CTX_ctrl
+#define SSL_CTX_new ck_SSL_CTX_new
+#define SSL_CTX_free ck_SSL_CTX_free
+#define SSL_CTX_set_default_passwd_cb ck_SSL_CTX_set_default_passwd_cb
+#define SSLv23_method ck_SSLv23_method
+#define SSLv3_method ck_SSLv3_method
+#define TLSv1_method ck_TLSv1_method
+#define SSLv23_client_method ck_SSLv23_client_method
+#define SSLv3_client_method ck_SSLv3_client_method
+#define TLSv1_client_method ck_TLSv1_client_method
+#define SSLv23_server_method ck_SSLv23_server_method
+#define SSLv3_server_method ck_SSLv3_server_method
+#define TLSv1_server_method ck_TLSv1_server_method
+#define SSL_library_init ck_SSL_library_init
+#define SSL_state_string ck_SSL_state_string
+#define SSL_state_string_long ck_SSL_state_string_long
+#define SSL_accept ck_SSL_accept
+#define SSL_set_cipher_list ck_SSL_set_cipher_list
+
+#define ERR_print_errors ck_ERR_print_errors
+#define ERR_print_errors_fp ck_ERR_print_errors_fp
+#define ERR_error_string ck_ERR_error_string
+#define ERR_get_error ck_ERR_get_error
+
+#define BIO_printf ck_BIO_printf
+#define BIO_ctrl ck_BIO_ctrl
+#define BIO_new ck_BIO_new
+#define BIO_s_file ck_BIO_s_file
+#define BIO_s_mem ck_BIO_s_mem
+#define BIO_s_null ck_BIO_s_null
+#define BIO_read ck_BIO_read
+#define BIO_new_file ck_BIO_new_file
+#define BIO_free ck_BIO_free
+
+#define X509_get_issuer_name ck_X509_get_issuer_name
+#define X509_verify_cert_error_string ck_X509_verify_cert_error_string
+#define X509_NAME_oneline ck_X509_NAME_oneline
+#define X509_get_subject_name ck_X509_get_subject_name
+#define X509_STORE_CTX_get_current_cert ck_X509_STORE_CTX_get_current_cert
+#define X509_get_default_cert_dir ck_X509_get_default_cert_dir
+#define X509_free ck_X509_free
+
+#define RSA_free ck_RSA_free
+#define RSA_generate_key ck_RSA_generate_key
+
+#define DH_new ck_DH_new
+#define DH_free ck_DH_free
+#define DH_generate_key ck_DH_generate_key
+#define DH_generate_parameters ck_DH_generate_parameters
+
+#define DSA_free ck_DSA_free
+#define DSA_generate_key ck_DSA_generate_key
+#define DSA_generate_parameters ck_DSA_generate_parameters
+
+#define PEM_read_bio_DHparams ck_PEM_read_bio_DHparams
+#define BN_bin2bn ck_BN_bin2bn
+#endif /* OS2 */
+#endif /* CK_SSL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcsym.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcsym.h
new file mode 100644
index 0000000..c340ca3
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcsym.h
@@ -0,0 +1,5 @@
+/* This file is for use with compilers that don't have the capability to
+ * #define symbols on the C compiler command line. This file must
+ * be #include'd before all other ck*.h files so that the symbols #define'd
+ * here can be used for any subsequent conditional code.
+ */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckctel.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckctel.c
new file mode 100644
index 0000000..e9f1295
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckctel.c
@@ -0,0 +1,9015 @@
+char *cktelv = "Telnet support, 9.0.274, 16 Mar 2010";
+#define CKCTEL_C
+
+int sstelnet = 0; /* Do server-side Telnet negotiation */
+
+/* C K C T E L -- Telnet support */
+
+/*
+ Authors:
+ Telnet protocol by Frank da Cruz and Jeffrey Altman.
+ Telnet Forward X by Jeffrey Altman
+ Telnet START_TLS support by Jeffrey Altman
+ Telnet AUTH and ENCRYPT support by Jeffrey Altman
+ Telnet COMPORT support by Jeffrey Altman
+ Telnet NEW-ENVIRONMENT support by Jeffrey Altman
+ Telnet NAWS support by Frank da Cruz and Jeffrey Altman
+ Telnet TERMTYPE support by Jeffrey Altman
+ Telnet KERMIT support by Jeffrey Altman
+ Other contributions as indicated in the code.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
+ C-Kermit source files, must be compatible with C preprocessors that support
+ only #ifdef, #else, #endif, #define, and #undef. Please do not use #if,
+ logical operators, or other preprocessor features in this module. Also,
+ don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+
+#ifdef TNCODE
+#include "ckcker.h"
+#define TELCMDS /* to define name array */
+#define TELOPTS /* to define name array */
+#define SLC_NAMES /* to define name array */
+#define ENCRYPT_NAMES
+#define AUTH_NAMES
+#define TELOPT_STATES
+#define TELOPT_MODES
+#define TNC_NAMES
+#include "ckcnet.h"
+#include "ckctel.h"
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifndef NOTERM
+#ifdef OS2 /* For terminal type name string */
+#include "ckuusr.h"
+#ifndef NT
+#include <os2.h>
+#undef COMMENT
+#else
+#define isascii __isascii
+#endif /* NT */
+#include "ckocon.h"
+extern int tt_type, max_tt;
+extern struct tt_info_rec tt_info[];
+#endif /* OS2 */
+#endif /* NOTERM */
+
+#ifdef OS2
+#include <assert.h>
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include <signal.h>
+#include "ckcsig.h"
+#include "ckosyn.h"
+#endif /* OS2 */
+
+#ifdef CK_NAWS /* Negotiate About Window Size */
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_naws, (void) );
+#endif /* RLOGCODE */
+#endif /* CK_NAWS */
+
+int tn_init = 0; /* Telnet protocol initialized flag */
+int tn_begun = 0; /* Telnet protocol started flag */
+static int tn_first = 1; /* First time init flag */
+extern int tn_exit; /* Exit on disconnect */
+extern int nettype;
+extern int inserver; /* Running as IKSD */
+char *tn_term = NULL; /* Terminal type override */
+
+#ifdef CK_SNDLOC
+char *tn_loc = NULL; /* Location override */
+#endif /* CK_SNDLOC */
+int tn_nlm = TNL_CRLF; /* Telnet CR -> CR LF mode */
+int tn_b_nlm = TNL_CR; /* Telnet Binary CR RAW mode */
+int tn_b_meu = 0; /* Telnet Binary ME means U too */
+int tn_b_ume = 0; /* Telnet Binary U means ME too */
+int tn_wait_flg = 1; /* Telnet Wait for Negotiations */
+int tn_infinite = 0; /* Telnet Bug Infinite-Loop-Check */
+int tn_rem_echo = 1; /* We will echo if WILL ECHO */
+int tn_b_xfer = 0; /* Telnet Binary for Xfers? */
+int tn_sb_bug = 1; /* Telnet BUG - SB w/o WILL or DO */
+int tn_auth_krb5_des_bug = 1; /* Telnet BUG - AUTH KRB5 DES */
+ /* truncates long keys */
+int tn_no_encrypt_xfer = 0; /* Turn off Telnet Encrypt? */
+int tn_delay_sb = 1; /* Delay SBs until safe */
+int tn_auth_how = TN_AUTH_HOW_ANY;
+int tn_auth_enc = TN_AUTH_ENC_ANY;
+int tn_deb = 0; /* Telnet Debug mode */
+int tn_sfu = 0; /* Microsoft SFU compatibility */
+#ifdef CK_FORWARD_X
+char * tn_fwdx_xauthority = NULL; /* Xauthority File */
+int fwdx_no_encrypt = 0; /* Forward-X requires encryption */
+#endif /* CK_FORWARD_X */
+
+#ifdef OS2
+int ttnum = -1; /* Last Telnet Terminal Type sent */
+int ttnumend = 0; /* Has end of list been found */
+#endif /* OS2 */
+
+char tn_msg[TN_MSG_LEN]; /* Telnet data can be rather long */
+char hexbuf[TN_MSG_LEN];
+char tn_msg_out[TN_MSG_LEN];
+#ifdef CK_FORWARD_X
+CHAR fwdx_msg_out[TN_MSG_LEN];
+#endif /* CK_FORWARD_X */
+
+/*
+ In order to prevent an infinite telnet negotiation loop we maintain a
+ count of the number of times the same telnet negotiation message is
+ sent. When this count hits MAXTNCNT, we do not send any more of the
+ message. The count is stored in the tncnts[][] array.
+
+ The tncnts[][] array is indexed by negotiation option (SUPPRESS GO AHEAD,
+ TERMINAL TYPE, NAWS, etc. - see the tnopts[] array) and the four
+ negotiation message types (WILL, WONT, DO, DONT). All telnet negotiations
+ are kept track of in this way.
+
+ The count for a message is zeroed when the "opposite" message is sent.
+ WILL is the opposite of WONT, and DO is the opposite of DONT.
+ For example sending "WILL SGA" increments tncnts[TELOPT_SGA][0]
+ and zeroes tncnts[TELOPT_SGA][1].
+
+ The code that does this is in tn_sopt().
+
+ rogersh@fsj.co.jp, 18/3/1995
+
+ 8/16/1998 - with the recent rewrite of the telnet state machine I don't
+ think this code is necessary anymore. However, it can't do any harm so
+ I am leaving it in. - Jeff
+
+ 12/28/1998 - all references to tncnts[] must be done with TELOPT_INDEX(opt)
+ because the Telnet option list is no longer contiguous. We also must
+ allocate NTELOPTS + 1 because the TELOPT_INDEX() macro returns NTELOPTS
+ for an invalid option number.
+*/
+
+#define MAXTNCNT 4 /* Permits 4 intermediate telnet firewalls/gateways */
+
+char tncnts[NTELOPTS+1][4]; /* Counts */
+char tnopps[4] = { 1,0,3,2 }; /* Opposites */
+
+#ifdef CK_ENVIRONMENT
+#ifdef CK_FORWARD_X
+#define TSBUFSIZ 2056
+#else /* CK_FORWARD_X */
+#define TSBUFSIZ 1024
+#endif /* CK_FORWARD_X */
+char tn_env_acct[64];
+char tn_env_disp[64];
+char tn_env_job[64];
+char tn_env_prnt[64];
+char tn_env_sys[64];
+char * tn_env_uservar[8][2];
+int tn_env_flg = 1;
+#else /* CK_ENVIRONMENT */
+#define TSBUFSIZ 41
+int tn_env_flg = 0;
+#endif /* CK_ENVIRONMENT */
+
+#ifdef COMMENT
+/* SIGWINCH handler moved to ckuusx.c */
+#ifndef NOSIGWINCH
+#ifdef CK_NAWS /* Window size business */
+#ifdef UNIX
+#include <signal.h>
+#endif /* UNIX */
+#endif /* CK_NAWS */
+#endif /* NOSIGWINCH */
+#endif /* COMMENT */
+
+CHAR sb[TSBUFSIZ]; /* Buffer - incoming subnegotiations */
+CHAR sb_out[TSBUFSIZ]; /* Buffer - outgoing subnegotiations */
+
+int tn_duplex = 1; /* Local echo */
+
+extern char uidbuf[]; /* User ID buffer */
+extern int quiet, ttnet, ttnproto, debses, what, duplex, oldplex, local;
+extern int seslog, sessft, whyclosed;
+#ifdef OS2
+#ifndef NOTERM
+extern int tt_rows[], tt_cols[];
+extern int tt_status[VNUM];
+extern int scrninitialized[];
+#endif /* NOTERM */
+#else /* OS2 */
+extern int tt_rows, tt_cols; /* Everybody has this */
+#endif /* OS2 */
+extern int cmd_cols, cmd_rows;
+extern char namecopy[];
+extern char myipaddr[]; /* Global copy of my IP address */
+
+#ifndef TELOPT_MACRO
+int
+telopt_index(opt) int opt; {
+ if (opt >= 0 && opt <= TELOPT_STDERR)
+ return(opt);
+ else if (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT)
+ return(opt-88);
+ else if (opt == TELOPT_IBM_SAK)
+ return(opt-147);
+ else
+ return(NTELOPTS);
+}
+
+int
+telopt_ok(opt) int opt; {
+ return((opt >= TELOPT_BINARY && opt <= TELOPT_STDERR) ||
+ (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) ||
+ (opt == TELOPT_IBM_SAK));
+}
+
+CHAR *
+telopt(opt) int opt; {
+ if (telopt_ok(opt))
+ return((CHAR *)telopts[telopt_index(opt)]);
+ else
+ return((CHAR *)"UNKNOWN");
+}
+
+int
+telopt_mode_ok(opt) int opt; {
+ return((unsigned int)(opt) <= TN_NG_MU);
+}
+
+CHAR *
+telopt_mode(opt) int opt; {
+ if (telopt_mode_ok(opt))
+ return((CHAR *)telopt_modes[opt-TN_NG_RF]);
+ else
+ return((CHAR *)"UNKNOWN");
+}
+#endif /* TELOPT_MACRO */
+
+static int
+tn_outst(notquiet) int notquiet; {
+ int outstanding = 0;
+ int x = 0;
+#ifdef CK_ENCRYPTION
+ int e = 0;
+ int d = 0;
+#endif /* CK_ENCRYPTION */
+
+ if (tn_wait_flg) {
+ for (x = TELOPT_FIRST; x <= TELOPT_LAST; x++) {
+ if (TELOPT_OK(x)) {
+ if (TELOPT_UNANSWERED_WILL(x)) {
+ if ( notquiet )
+ printf("?Telnet waiting for response to WILL %s\r\n",
+ TELOPT(x));
+ debug(F111,"tn_outst","unanswered WILL",x);
+ outstanding = 1;
+ if ( !notquiet )
+ break;
+ }
+ if (TELOPT_UNANSWERED_DO(x)) {
+ if ( notquiet )
+ printf("?Telnet waiting for response to DO %s\r\n",
+ TELOPT(x));
+ debug(F111,"tn_outst","unanswered DO",x);
+ outstanding = 1;
+ if ( !notquiet )
+ break;
+ }
+ if (TELOPT_UNANSWERED_WONT(x)) {
+ if ( notquiet )
+ printf("?Telnet waiting for response to WONT %s\r\n",
+ TELOPT(x));
+ debug(F111,"tn_outst","unanswered WONT",x);
+ outstanding = 1;
+ if ( !notquiet )
+ break;
+ }
+ if (TELOPT_UNANSWERED_DONT(x)) {
+ if ( notquiet )
+ printf("?Telnet waiting for response to DONT %s\r\n",
+ TELOPT(x));
+ debug(F111,"tn_outst","unanswered DONT",x);
+ outstanding = 1;
+ if ( !notquiet )
+ break;
+ }
+ if (TELOPT_UNANSWERED_SB(x)) {
+ if ( notquiet )
+ printf("?Telnet waiting for response to SB %s\r\n",
+ TELOPT(x));
+ debug(F111,"tn_outst","unanswered SB",x);
+ outstanding = 1;
+ if ( !notquiet )
+ break;
+ }
+ }
+ }
+#ifdef CK_AUTHENTICATION
+ if (ck_tn_auth_in_progress()) {
+ if (TELOPT_ME(TELOPT_AUTHENTICATION)) {
+ if (notquiet)
+ printf("?Telnet waiting for WILL %s subnegotiation\r\n",
+ TELOPT(TELOPT_AUTHENTICATION));
+ debug(F111,
+ "tn_outst",
+ "ME authentication in progress",
+ TELOPT_AUTHENTICATION
+ );
+ outstanding = 1;
+ } else if (TELOPT_U(TELOPT_AUTHENTICATION)) {
+ if (notquiet)
+ printf("?Telnet waiting for DO %s subnegotiation\r\n",
+ TELOPT(TELOPT_AUTHENTICATION));
+ debug(F111,
+ "tn_outst",
+ "U authentication in progress",
+ TELOPT_AUTHENTICATION
+ );
+ outstanding = 1;
+ }
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ if (!outstanding) {
+ e = ck_tn_encrypting();
+ d = ck_tn_decrypting();
+ if (TELOPT_ME(TELOPT_ENCRYPTION)) {
+ if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && e ||
+ !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !e
+ ) {
+ if ( notquiet )
+ printf("?Telnet waiting for WILL %s subnegotiation\r\n",
+ TELOPT(TELOPT_ENCRYPTION));
+ debug(F111,
+ "tn_outst",
+ "encryption mode switch",
+ TELOPT_ENCRYPTION
+ );
+ outstanding = 1;
+ }
+ }
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && d ||
+ !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !d
+ ) {
+ if ( notquiet )
+ printf("?Telnet waiting for DO %s subnegotiation\r\n",
+ TELOPT(TELOPT_ENCRYPTION));
+ debug(F111,
+ "tn_outst",
+ "decryption mode switch",
+ TELOPT_ENCRYPTION
+ );
+ outstanding = 1;
+ }
+ }
+ }
+#endif /* CK_ENCRYPTION */
+ } /* if (tn_wait_flg) */
+
+#ifdef IKS_OPTION
+ /* Even if we are not waiting for Telnet options we must wait for */
+ /* Kermit Telnet Subnegotiations if we have sent a request to the */
+ /* other guy. Otherwise we will get out of sync. */
+ if (!outstanding) {
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start ||
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop ||
+ !TELOPT_SB(TELOPT_KERMIT).kermit.sop)
+ ) {
+ if ( notquiet )
+ printf("?Telnet waiting for SB %s negotiation\r\n",
+ TELOPT(TELOPT_KERMIT));
+ debug(F111,"tn_outst","U kermit in progress",TELOPT_KERMIT);
+ outstanding = 1;
+ }
+ }
+#endif /* IKS_OPTION */
+
+#ifdef TN_COMPORT
+ if (!outstanding) {
+ if (TELOPT_ME(TELOPT_COMPORT)) {
+ if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb) {
+ if (notquiet)
+ printf("?Telnet waiting for SB %s negotiation\r\n",
+ TELOPT(TELOPT_COMPORT));
+ debug(F111,"tn_outst","ComPort SB in progress",TELOPT_COMPORT);
+ outstanding = 1;
+ }
+ if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms) {
+ if (notquiet)
+ printf("?Telnet waiting for SB %s MODEM_STATUS negotiation\r\n",
+ TELOPT(TELOPT_COMPORT));
+ debug(F111,"tn_outst","ComPort SB MS in progress",TELOPT_COMPORT);
+ outstanding = 1;
+ }
+ }
+ }
+#endif /* TN_COMPORT */
+ return(outstanding);
+}
+
+int
+istncomport() {
+#ifdef TN_COMPORT
+ if (!local) return(0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+ if (TELOPT_ME(TELOPT_COMPORT))
+ return(1);
+ else
+#endif /* TN_COMPORT */
+ return(0);
+}
+
+/* tn_wait() -- Wait for response to Telnet negotiation. */
+/*
+ Wait for up to <timeout> seconds for the response to arrive.
+ Place all non-telnet data into Telnet Wait Buffer.
+ If response does arrive return 1, else return 0.
+*/
+#ifndef TN_WAIT_BUF_SZ
+#define TN_WAIT_BUF_SZ 4096
+#endif /* TN_WAIT_BUF_SZ */
+static char tn_wait_buf[TN_WAIT_BUF_SZ];
+static int tn_wait_idx = 0;
+#ifndef TN_TIMEOUT
+#define TN_TIMEOUT 120
+#endif /* TN_TIMEOUT */
+static int tn_wait_tmo = TN_TIMEOUT;
+
+#ifdef CKSPINNER
+VOID
+prtwait(state) int state; {
+ switch (state % 4) {
+ case 0:
+ printf("/");
+ break;
+ case 1:
+ printf("-");
+ break;
+ case 2:
+ printf("\\");
+ break;
+ case 3:
+ printf("|");
+ break;
+ }
+}
+#endif /* CKSPINNER */
+
+static int nflag = 0;
+
+int
+#ifdef CK_ANSIC
+tn_wait(char * where)
+#else
+tn_wait(where) char * where;
+#endif /* CK_ANSIC */
+/* tn_wait */ {
+ extern int ckxech, local;
+ int ch = 0, count = 0;
+#ifndef NOHINTS
+ int nohintgiven = 1;
+ extern int hints;
+#endif /* NOHINTS */
+ int outstanding;
+#ifdef TN_COMPORT
+ int savcarr;
+ extern int ttcarr;
+#endif /* TN_COMPORT */
+
+ /* if (!IS_TELNET()) return(1); */
+
+ rtimer();
+
+ debug(F110,"tn_wait waiting for",where,0);
+ tn_wait_tmo = TN_TIMEOUT;
+ debug(F111,"tn_wait","timeout",tn_wait_tmo);
+ outstanding = tn_outst(0);
+ debug(F111,"tn_wait","outstanding",outstanding);
+ debug(F111,"tn_wait","tn_wait_flg",tn_wait_flg);
+
+ /* The following is meant to be !(||). We only want to return */
+ /* immediately if both the tn_wait_flg && tn_outst() are false */
+ if (!(outstanding || tn_wait_flg)) /* If no need to wait */
+ return(1); /* Don't. */
+
+ if (tn_deb || debses) tn_debug("<wait for outstanding negotiations>");
+
+#ifdef CKSPINNER
+ if (!sstelnet && !quiet)
+ prtwait(0);
+#endif /* CKSPINNER */
+
+ /* Wait up to TN_TIMEOUT sec for responses to outstanding telnet negs */
+ do {
+#ifdef NTSIG
+ ck_ih();
+#endif /* NTSIG */
+ ch = ttinc(1);
+ if (ch == -1) { /* Timed out */
+ if (!sstelnet && !quiet) { /* Let user know... */
+#ifdef CKSPINNER
+ printf("\b");
+ prtwait(gtimer());
+#else
+ if (nflag == 0) {
+ printf(" Negotiations.");
+ nflag++;
+ }
+ if (nflag > 0) {
+ printf(".");
+ nflag++;
+ fflush(stdout);
+ }
+#endif /* CKSPINNER */
+ }
+ } else if (ch < -1) {
+ printf("\r\n?Connection closed by peer.\r\n");
+ if (tn_deb || debses) tn_debug("<connection closed by peer>");
+ return(-1);
+ } else
+ switch (ch) {
+ case IAC:
+#ifdef CKSPINNER
+ if (!sstelnet && !quiet)
+ printf("\b");
+#endif /* CKSPINNER */
+ ch = tn_doop((CHAR)(ch & 0xff),inserver?ckxech:duplex,ttinc);
+#ifdef CKSPINNER
+ if (!sstelnet && !quiet) {
+ prtwait(gtimer());
+ }
+#endif /* CKSPINNER */
+ debug(F101,"tn_wait tn_doop","",ch);
+ switch (ch) {
+ case 1:
+ duplex = 1; /* Turn on echoing */
+ if (inserver)
+ ckxech = 1;
+ break;
+ case 2:
+ duplex = 0; /* Turn off echoing */
+ if (inserver)
+ ckxech = 0;
+ break;
+ case 3:
+ tn_wait_buf[tn_wait_idx++] = IAC;
+ break;
+ case 4: /* IKS event */
+ case 6: /* Logout */
+ break;
+ case -1:
+ if (!quiet)
+ printf("?Telnet Option negotiation error.\n");
+ if (tn_deb || debses)
+ tn_debug("<Telnet Option negotiation error>");
+ return(-1);
+ case -2:
+ printf("?Connection closed by peer.\n");
+ if (tn_deb || debses) tn_debug("<Connection closed by peer>");
+ ttclos(0);
+ return(-2);
+ default:
+ if (ch < 0) {
+ if (tn_deb || debses) tn_debug("<Unknown connection error>");
+ return(ch);
+ }
+ } /* switch */
+ break;
+ default:
+#ifdef CKSPINNER
+ if (!sstelnet && !quiet) {
+ printf("\b");
+ prtwait(gtimer());
+ }
+#endif /* CKSPINNER */
+ tn_wait_buf[tn_wait_idx++] = (CHAR)(ch & 0xff);
+ } /* switch */
+
+ outstanding = tn_outst(0);
+
+ if ( outstanding && ch != IAC ) {
+ int timer = gtimer();
+ if ( timer > tn_wait_tmo ) {
+ if (!sstelnet) {
+ printf(
+ "\r\n?Telnet Protocol Timeout - connection closed\r\n");
+ if (tn_deb || debses)
+ tn_debug(
+ "<telnet protocol timeout - connection closed>");
+ tn_outst(1);
+ }
+ /* if we do not close the connection, then we will block */
+ /* the next time we hit a wait. and if we don't we will */
+ /* do the wrong thing if the host sends 0xFF and does */
+ /* not intend it to be an IAC. */
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-1);
+ }
+#ifndef NOHINTS
+ else if ( hints && timer > 30 && nohintgiven && !inserver ) {
+#ifdef CKSPINNER
+ printf("\b");
+#else /* CKSPINNER */
+ printf("\r\n");
+#endif /* CKSPINNER */
+ printf("*************************\r\n");
+ printf("The Telnet %s is not sending required responses.\r\n\r\n",
+ sstelnet?"client":"server");
+ tn_outst(1);
+ printf("\nYou can continue to wait or you can cancel with Ctrl-C.\r\n");
+ printf("In case the Telnet server never responds as required,\r\n");
+ printf("you can try connecting to this host with TELNET /NOWAIT.\r\n");
+ printf("Use SET HINTS OFF to suppress further hints.\r\n");
+ printf("*************************\r\n");
+ nohintgiven = 0;
+ }
+#endif /* NOHINTS */
+ }
+
+#ifdef TN_COMPORT
+ /* Must disable carrier detect check if we are using Telnet Comport */
+ savcarr = ttcarr;
+ ttscarr(CAR_OFF);
+ count = ttchk();
+ ttscarr(savcarr);
+#else /* TN_COMPORT */
+ count = ttchk();
+#endif /* TN_COMPORT */
+ } while ((tn_wait_idx < TN_WAIT_BUF_SZ) &&
+ (outstanding && count >= 0));
+
+ if (tn_wait_idx == TN_WAIT_BUF_SZ) {
+ if (tn_deb || debses) tn_debug("<Telnet Wait Buffer filled>");
+ return(0);
+ }
+
+ if (!sstelnet && !quiet) {
+#ifdef CKSPINNER
+ printf("\b \b");
+#else
+ if (nflag > 0) {
+ printf(" (OK)\n");
+ nflag = -1;
+ }
+#endif /* CKSPINNER */
+ }
+ if (tn_deb || debses) tn_debug("<no outstanding negotiations>");
+ return(0);
+}
+
+/* Push data from the Telnet Wait Buffer into the I/O Queue */
+/* Return 1 on success */
+
+int
+tn_push() {
+#ifdef NETLEBUF
+ extern int tt_push_inited;
+#endif /* NETLEBUF */
+ /* if (!IS_TELNET()) return(1); */
+
+ if (tn_wait_idx) {
+ ckhexdump((CHAR *)"tn_push",tn_wait_buf,tn_wait_idx);
+#ifdef NETLEBUF
+ if (!tt_push_inited) /* Local handling */
+ le_init();
+ le_puts((CHAR *)tn_wait_buf,tn_wait_idx);
+#else /* External handling... */
+#ifdef OS2 /* K95 has its own way */
+ le_puts((CHAR *)tn_wait_buf,tn_wait_idx);
+#else
+#ifdef TTLEBUF /* UNIX, etc */
+ le_puts((CHAR *)tn_wait_buf,tn_wait_idx);
+#else
+/*
+ If you see this message in AOS/VS, OS-9, VOS, etc, you need to copy
+ the #ifdef TTLEBUF..#endif code from ckutio.c to the corresponding
+ places in your ck?tio.c module.
+*/
+ printf("tn_push called but not implemented - data lost.\n");
+#endif /* TTLEBUF */
+#endif /* OS2 */
+#endif /* NETLEBUF */
+ tn_wait_idx = 0;
+ }
+ tn_wait_tmo = TN_TIMEOUT; /* Reset wait timer stats */
+ return(1);
+}
+
+/* T N _ S O P T */
+/*
+ Sends a telnet option, avoids loops.
+ Returns 1 if command was sent, 0 if not, -1 on error.
+*/
+int
+tn_sopt(cmd,opt) int cmd, opt; { /* TELNET SEND OPTION */
+ CHAR buf[5];
+ char msg[128];
+ int rc;
+ if (ttnet != NET_TCPB) return(-1); /* Must be TCP/IP */
+ if (ttnproto != NP_TELNET) return(-1); /* Must be telnet protocol */
+ if (!TELCMD_OK(cmd)) return(-1);
+ if (TELOPT_OK(opt)) {
+ if (cmd == DO && TELOPT_UNANSWERED_DO(opt)) return(0);
+ if (cmd == WILL && TELOPT_UNANSWERED_WILL(opt)) return(0);
+ if (cmd == DONT && TELOPT_UNANSWERED_DONT(opt)) return(0);
+ if (cmd == WONT && TELOPT_UNANSWERED_WONT(opt)) return(0);
+ }
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if (cmd == DO && opt == TELOPT_AUTHENTICATION)
+ buf[0] = 0;
+
+ if (tn_infinite && TELOPT_OK(opt)) { /* See comment above about */
+ int index = TELOPT_INDEX(opt); /* preventing infinite loops */
+ int m = cmd - WILL;
+
+ if (tncnts[index][m] > MAXTNCNT) {
+#ifdef DEBUG
+ if (tn_deb || debses || deblog) {
+ ckmakmsg(msg,sizeof(msg),
+ "TELNET negotiation loop ",
+ TELCMD(cmd), " ",
+ TELOPT(opt));
+ debug(F101,msg,"",opt);
+ if (tn_deb || debses) tn_debug(msg);
+ }
+#endif /* DEBUG */
+ return(0);
+ }
+ tncnts[index][m]++;
+ tncnts[index][tnopps[m]] = 0;
+ }
+ buf[0] = (CHAR) IAC;
+ buf[1] = (CHAR) (cmd & 0xff);
+ buf[2] = (CHAR) (opt & 0xff);
+ buf[3] = (CHAR) 0;
+#ifdef DEBUG
+ if ((tn_deb || debses || deblog) && cmd != SB)
+ ckmakmsg(msg,sizeof(msg),"TELNET SENT ",TELCMD(cmd)," ",
+ TELOPT(opt));
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ debug(F101,msg,"",opt);
+ if ((tn_deb || debses) && cmd != SB)
+ tn_debug(msg);
+ rc = (ttol(buf,3) < 3);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+
+ if (TELOPT_OK(opt)) {
+ if (cmd == DONT && TELOPT_UNANSWERED_DO(opt))
+ TELOPT_UNANSWERED_DO(opt) = 0;
+ if (cmd == WONT && TELOPT_UNANSWERED_WILL(opt))
+ TELOPT_UNANSWERED_WILL(opt) = 0;
+ if (cmd == DO && TELOPT_UNANSWERED_DONT(opt))
+ TELOPT_UNANSWERED_DONT(opt) = 0;
+ if (cmd == WILL && TELOPT_UNANSWERED_WONT(opt))
+ TELOPT_UNANSWERED_WONT(opt) = 0;
+ }
+ return(1);
+}
+
+/* Send a telnet sub-option */
+/* Returns 1 if command was sent, 0 if not, -1 on error */
+
+int
+tn_ssbopt(opt,sub,data,len) int opt, sub; CHAR * data; int len; {
+ CHAR buf[256];
+ int n,m,rc;
+
+ if (ttnet != NET_TCPB) return(0); /* Must be TCP/IP */
+ if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
+ if (!TELOPT_OK(opt)) return(-1);
+ if (len < 0 || len > 250) {
+ debug(F111,"Unable to Send TELNET SB - data too long","len",len);
+ return(-1); /* Data too long */
+ }
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ if (ttchk() < 0)
+ return(-1);
+ else
+ return(1);
+ }
+#endif /* CK_SSL */
+
+ if (!data) len = 0;
+
+ buf[0] = (CHAR) IAC;
+ buf[1] = (CHAR) (SB & 0xff);
+ buf[2] = (CHAR) (opt & 0xff);
+ buf[3] = (CHAR) (sub & 0xff);
+ if (data && len > 0) {
+ memcpy(&buf[4],data,len);
+ }
+ buf[4+len] = (CHAR) IAC;
+ buf[5+len] = (CHAR) SE;
+
+#ifdef DEBUG
+ if (tn_deb || debses || deblog) {
+ if (opt == TELOPT_START_TLS && sub == 1)
+ ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(opt)," FOLLOWS IAC SE",NULL);
+ else if (opt == TELOPT_TTYPE && sub == 1)
+ ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(opt),
+ " SEND IAC SE",NULL);
+ else if (opt == TELOPT_TTYPE && sub == 0)
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",TELOPT(opt)," IS ",
+ (char *)data," IAC SE",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ else if (opt == TELOPT_NEWENVIRON) {
+ int i, quote;
+ ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_NEWENVIRON)," ",
+ sub == TELQUAL_SEND ? "SEND" :
+ sub == TELQUAL_IS ? "IS" :
+ sub == TELQUAL_INFO ?"INFO" : "UNKNOWN" );
+ for (i = 0, quote = 0; i < len; i++) {
+ if (quote) {
+ sprintf(hexbuf,"%02x",data[i]); /* safe but ugly */
+ ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN);
+ quote = 0;
+ } else {
+ switch (data[i]) {
+ case TEL_ENV_USERVAR:
+ ckstrncat(tn_msg_out," USERVAR ",TN_MSG_LEN);
+ break;
+ case TEL_ENV_VAR:
+ ckstrncat(tn_msg_out," VAR ",TN_MSG_LEN);
+ break;
+ case TEL_ENV_VALUE:
+ ckstrncat(tn_msg_out," VALUE ",TN_MSG_LEN);
+ break;
+ case TEL_ENV_ESC:
+ ckstrncat(tn_msg_out," ESC ",TN_MSG_LEN);
+ quote = 1;
+ break;
+ case IAC:
+ ckstrncat(tn_msg_out," IAC ",TN_MSG_LEN);
+ break;
+ default:
+ sprintf(hexbuf,"%c",data[i]); /* safe but ugly */
+ ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN);
+ }
+ }
+ }
+ ckstrncat(tn_msg_out," IAC SE",TN_MSG_LEN);
+ } else {
+ sprintf(hexbuf,"%02x",sub); /* safe but ugly */
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(opt),
+ " ",
+ hexbuf,
+ " <data> IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ }
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif /* OS2 */
+#ifdef DEBUG
+ debug(F101,tn_msg_out,"",opt);
+ if (tn_deb || debses)
+ tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol(buf,6+len) < 6+len);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ if (rc)
+ return(-1);
+ return(1);
+}
+
+/*
+ tn_flui() -- Processes all waiting data for Telnet commands.
+ All non-Telnet data is to be stored into the Telnet Wait Buffer.
+ Returns 1 on success.
+*/
+int
+tn_flui() {
+ extern int ckxech;
+ int x = 0;
+
+ /* if (!IS_TELNET()) return(0); */
+
+ /* Wait up to 5 sec for responses to outstanding telnet negotiations */
+ while (x >= 0 && ttchk() > 0 && tn_wait_idx < TN_WAIT_BUF_SZ) {
+ x = ttinc(1);
+ switch (x) {
+ case IAC:
+ x = tn_doop((CHAR)(x & 0xff),inserver?ckxech:duplex,ttinc);
+ debug(F101,"tn_flui tn_doop","",x);
+ switch (x) {
+ case 1: /* Turn on echoing */
+ duplex = 1;
+ if (inserver)
+ ckxech = 1;
+ break;
+ case 2: /* Turn off echoing */
+ duplex = 0;
+ if (inserver)
+ ckxech = 0;
+ break;
+ case 3:
+ tn_wait_buf[tn_wait_idx++] = IAC;
+ break;
+ case 4: /* IKS event */
+ case 6: /* Logout */
+ break;
+ }
+ break;
+ default:
+ if (x >= 0)
+ tn_wait_buf[tn_wait_idx++] = x;
+ }
+ }
+ return(1);
+}
+
+unsigned char *
+tn_get_display()
+{
+ char * disp = NULL;
+ static char tmploc[256];
+
+ /* Must compute the DISPLAY string we are going to send to the host */
+ /* If one is not assigned, do not send a string unless the user has */
+ /* explicitedly requested we try to send one via X-Display Location */
+ /* But do not send a string at all if FORWARD_X is in use. */
+
+ /* if (!IS_TELNET()) return(0); */
+
+ debug(F110,"tn_get_display() myipaddr",myipaddr,0);
+#ifdef CK_ENVIRONMENT
+ debug(F110,"tn_get_display() tn_env_disp",tn_env_disp,0);
+ if (tn_env_disp[0]) {
+ int colon = ckindex(":",tn_env_disp,0,0,1);
+ if ( !colon ) {
+ ckmakmsg(tmploc,256,myipaddr,":",tn_env_disp,NULL);
+ disp = tmploc;
+ } else if ( ckindex("localhost:",tn_env_disp,0,0,0) ||
+ ckindex("unix:",tn_env_disp,0,0,0) ||
+ ckindex("127.0.0.1:",tn_env_disp,0,0,0) ||
+ !ckstrcmp("0:",tn_env_disp,2,1) ||
+ tn_env_disp[0] == ':' ) {
+ ckmakmsg(tmploc,256,myipaddr,":",&tn_env_disp[colon],NULL);
+ disp = tmploc;
+ } else
+ disp = tn_env_disp;
+ }
+ else
+#endif /* CK_ENVIRONMENT */
+ if (TELOPT_ME(TELOPT_XDISPLOC) ||
+ TELOPT_U(TELOPT_FORWARD_X)) {
+ ckmakmsg(tmploc,256,myipaddr,":0.0",NULL,NULL);
+ disp = tmploc;
+ }
+ debug(F110,"tn_get_display() returns",disp,0);
+ return((CHAR *)disp);
+}
+
+#ifdef CK_FORWARD_X
+static Xauth fake_xauth = {0,0,NULL,0,NULL,0,NULL,0,NULL};
+static Xauth *real_xauth=NULL;
+
+/*
+ * Author: Jim Fulton, MIT X Consortium
+ *
+ * fwdx_parse_displayname -
+ * display a display string up into its component parts
+ */
+#ifdef UNIX
+#define UNIX_CONNECTION "unix"
+#define UNIX_CONNECTION_LENGTH 4
+#endif
+
+/*
+ * private utility routines
+ */
+
+static int
+#ifdef CK_ANSIC
+XmuGetHostname (char *buf, int maxlen)
+#else
+XmuGetHostname (buf, maxlen)
+ char *buf;
+ int maxlen;
+#endif /* CK_ANSIC */
+{
+ int len;
+
+#ifdef NEED_UTSNAME
+ /*
+ * same host name crock as in server and xinit.
+ */
+ struct utsname name;
+
+ uname (&name);
+ len = strlen (name.nodename);
+ if (len >= maxlen) len = maxlen - 1;
+ strncpy (buf, name.nodename, len);
+ buf[len] = '\0';
+#else
+ buf[0] = '\0';
+ (void) gethostname (buf, maxlen);
+ buf [maxlen - 1] = '\0';
+ len = strlen(buf);
+#endif /* hpux */
+ return len;
+}
+
+static char *
+#ifdef CK_ANSIC
+copystring (char *src, int len)
+#else
+copystring (src, len)
+ char *src;
+ int len;
+#endif /* CK_ANSIC */
+{
+ char *cp;
+
+ if (!src && len != 0) return NULL;
+ cp = malloc (len + 1);
+ if (cp) {
+ if (src) strncpy (cp, src, len);
+ cp[len] = '\0';
+ }
+ return cp;
+}
+
+static char *
+#ifdef CK_ANSIC
+get_local_hostname (char *buf, int maxlen)
+#else
+get_local_hostname (buf, maxlen)
+ char *buf;
+ int maxlen;
+#endif
+{
+ buf[0] = '\0';
+ (void) XmuGetHostname (buf, maxlen);
+ return (buf[0] ? buf : NULL);
+}
+
+#ifndef UNIX
+static char *
+copyhostname ()
+{
+ char buf[256];
+
+ return (get_local_hostname (buf, sizeof buf) ?
+ copystring (buf, strlen (buf)) : NULL);
+}
+#endif
+
+
+int
+#ifdef CK_ANSIC
+fwdx_parse_displayname (char *displayname, int *familyp, char **hostp,
+ int *dpynump, int *scrnump, char **restp)
+#else
+fwdx_parse_displayname (displayname, familyp, hostp, dpynump, scrnump, restp)
+ char *displayname;
+ int *familyp; /* return */
+ char **hostp; /* return */
+ int *dpynump, *scrnump; /* return */
+ char **restp; /* return */
+#endif /* CK_ANSIC */
+{
+ char *ptr; /* work variables */
+ int len; /* work variable */
+ int family = -1; /* value to be returned */
+ char *host = NULL; /* must free if set and error return */
+ int dpynum = -1; /* value to be returned */
+ int scrnum = 0; /* value to be returned */
+ char *rest = NULL; /* must free if set and error return */
+ int dnet = 0; /* if 1 then using DECnet */
+
+ /* check the name */
+ if (!displayname || !displayname[0])
+ return 0;
+ /* must have at least :number */
+ ptr = (char *)strchr(displayname, ':');
+ if (!ptr || !ptr[1]) return 0;
+ if (ptr[1] == ':') {
+ if (ptr[2] == '\0') return 0;
+ dnet = 1;
+ }
+
+ /*
+ * get the host string; if none is given, use the most effiecient path
+ */
+
+ len = (ptr - displayname); /* length of host name */
+ if (len == 0) { /* choose most efficient path */
+#ifdef UNIX
+ host = copystring (UNIX_CONNECTION, UNIX_CONNECTION_LENGTH);
+ family = FamilyLocal;
+#else
+ if (dnet) {
+ host = copystring ("0", 1);
+ family = FamilyDECnet;
+ } else {
+ host = copyhostname ();
+ family = FamilyInternet;
+ }
+#endif
+ } else {
+ host = copystring (displayname, len);
+ if (dnet) {
+ family = dnet;
+ } else {
+#ifdef UNIX
+ if (host && strcmp (host, UNIX_CONNECTION) == 0)
+ family = FamilyLocal;
+ else
+#endif
+ family = FamilyInternet;
+ }
+ }
+
+ if (!host) return 0;
+
+
+ /*
+ * get the display number; we know that there is something after the
+ * colon (or colons) from above. note that host is now set and must
+ * be freed if there is an error.
+ */
+
+ if (dnet) ptr++; /* skip the extra DECnet colon */
+ ptr++; /* move to start of display num */
+ {
+ register char *cp;
+
+ for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
+ len = (cp - ptr);
+ /* check present and valid follow */
+ if (len == 0 || (*cp && *cp != '.')) {
+ free (host);
+ return 0;
+ }
+
+ dpynum = atoi (ptr); /* it will handle num. as well */
+ ptr = cp;
+ }
+
+ /*
+ * now get screen number if given; ptr may point to nul at this point
+ */
+ if (ptr[0] == '.') {
+ register char *cp;
+
+ ptr++;
+ for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
+ len = (cp - ptr);
+ if (len == 0 || (*cp && *cp != '.')) { /* all prop name */
+ free (host);
+ return 0;
+ }
+
+ scrnum = atoi (ptr); /* it will handle num. as well */
+ ptr = cp;
+ }
+
+ /*
+ * and finally, get any additional stuff that might be following the
+ * the screen number; ptr must point to a period if there is anything
+ */
+
+ if (ptr[0] == '.') {
+ ptr++;
+ len = strlen (ptr);
+ if (len > 0) {
+ rest = copystring (ptr, len);
+ if (!rest) {
+ free (host);
+ return 1;
+ }
+ }
+ }
+
+ /*
+ * and we are done!
+ */
+
+ if ( familyp )
+ *familyp = family;
+ if ( hostp )
+ *hostp = host;
+ else
+ free(host);
+ if ( dpynump )
+ *dpynump = dpynum;
+ if ( scrnump )
+ *scrnump = scrnum;
+ if ( restp )
+ *restp = rest;
+ else
+ free(rest);
+ return 1;
+}
+
+
+int
+#ifdef CK_ANSIC
+fwdx_tn_sb( unsigned char * sb, int n )
+#else
+fwdx_tn_sb( sb, n ) unsigned char * sb; int n;
+#endif /* CK_ANSIC */
+{
+ unsigned short hchannel, nchannel;
+ unsigned char * p;
+ int i;
+ int rc = -1;
+
+ /* check to ensure we have negotiated Forward X */
+ if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
+ !sstelnet && !TELOPT_U(TELOPT_FORWARD_X) ) {
+ debug(F100,"fwdx_tn_sb() not negotiated","",0);
+ return(0);
+ }
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ switch (sb[0]) {
+ case FWDX_SCREEN:
+ if (sstelnet && n == 4)
+ rc = fwdx_create_listen_socket(sb[1]);
+ break;
+ case FWDX_OPEN:
+ if ( !sstelnet && n >= 5 ) {
+ p = (unsigned char *) &nchannel;
+ i = 1;
+ /* IAC quoting has been stripped in tn_sb() */
+ p[0] = sb[i++];
+ p[1] = sb[i++];
+ hchannel = ntohs(nchannel);
+ rc = fwdx_open_client_channel(hchannel);
+ if ( rc < 0 ) {
+ /* Failed; Send CLOSE channel */
+ fwdx_send_close(hchannel);
+ rc = 0; /* Do not consider this to be a telnet error */
+ }
+#ifdef NT
+ if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started ) {
+ ckThreadBegin( &fwdx_thread,32655, 0, FALSE, 0 ) ;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 1;
+ }
+#endif /* NT */
+ }
+ break;
+ case FWDX_CLOSE:
+ p = (unsigned char *) &nchannel;
+ i = 1;
+ /* IAC quoting has been stripped in tn_sb() */
+ p[0] = sb[i++];
+ p[1] = sb[i++];
+ hchannel = ntohs(nchannel);
+ fwdx_close_channel(hchannel);
+ rc = 0; /* no errors when closing */
+ break;
+ case FWDX_DATA:
+ p = (unsigned char *) &nchannel;
+ i = 1;
+ /* IAC quoting has been stripped in tn_sb() */
+ p[0] = sb[i++];
+ p[1] = sb[i++];
+ hchannel = ntohs(nchannel);
+ rc = fwdx_send_xauth_to_xserver(hchannel,(CHAR *)&sb[3],n-5);
+ if ( rc >= 0 && n-5-rc > 0) {
+ rc = fwdx_write_data_to_channel(hchannel,(char *)&sb[3+rc],n-5-rc);
+ if ( rc < 0 ) {
+ /* Failed; Send CLOSE channel */
+ rc = fwdx_send_close(hchannel);
+ }
+ }
+ break;
+ case FWDX_OPTIONS:
+ if ( sstelnet ) {
+#ifndef FWDX_SERVER
+ rc = 0;
+#else
+ rc = fwdx_server_accept_options((char*)&sb[2],n-3);
+#endif
+ } else {
+ rc = fwdx_client_reply_options((char *)&sb[2],n-3);
+ if ( rc >= 0 ) {
+ rc = tn_sndfwdx();
+ }
+ }
+ break;
+ case FWDX_OPT_DATA:
+ switch ( sb[1] ) {
+ default:
+ rc = 0; /* we don't recognize, not an error */
+ }
+ break;
+
+ case FWDX_XOFF:
+ case FWDX_XON:
+ if ( !sstelnet ) {
+ p = (unsigned char *) &nchannel;
+ i = 1;
+ /* IAC quoting has been stripped in tn_sb() */
+ p[0] = sb[i++];
+ p[1] = sb[i++];
+ hchannel = ntohs(nchannel);
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[hchannel].suspend =
+ (sb[0] == FWDX_XOFF);
+ rc = 0;
+ }
+ break;
+ }
+ return(rc < 0 ? -1 : 0);
+}
+
+int
+#ifdef CK_ANSIC
+fwdx_send_xauth_to_xserver(int channel, unsigned char * data, int len)
+#else
+fwdx_send_xauth_to_xserver(channel, data, len)
+ int channel; unsigned char * data; int len;
+#endif /* CK_ANSIC */
+{
+ int name_len, data_len, i;
+
+ for (i = 0; i < MAXFWDX ; i++) {
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
+ break;
+ }
+ if ( i == MAXFWDX )
+ goto auth_err;
+
+ if (!TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth)
+ return(0);
+
+ if (len < 12)
+ goto auth_err;
+
+ /* Parse the lengths of variable-length fields. */
+ if (data[0] == 0x42) { /* byte order MSB first. */
+ /* Xauth packets appear to always have this format */
+ if ( data[1] != 0x00 ||
+ data[2] != 0x00 ||
+ data[3] != 0x0B ||
+ data[4] != 0x00 ||
+ data[5] != 0x00 )
+ goto auth_err;
+
+ name_len = (data[6] << 8) + data[7];
+ data_len = (data[8] << 8) + data[9];
+ } else if (data[0] == 0x6c) { /* Byte order LSB first. */
+ /* Xauth packets appear to always have this format */
+ if ( data[1] != 0x00 ||
+ data[2] != 0x0B ||
+ data[3] != 0x00 ||
+ data[4] != 0x00 ||
+ data[5] != 0x00 )
+ goto auth_err;
+
+ name_len = data[6] + (data[7] << 8);
+ data_len = data[8] + (data[9] << 8);
+ } else {
+ /* bad byte order byte */
+ goto auth_err;
+ }
+
+ /* Check if the whole packet is in buffer. */
+ if (len < 12 + ((name_len + 3) & ~3) + ((data_len + 3) & ~3))
+ goto auth_err;
+ /* If the Telnet Server allows a real Xauth message to be sent */
+ /* Then let the message be processed by the Xserver. */
+ if (name_len + data_len > 0) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+ return(0);
+ }
+ else
+ /* If an empty Xauth message was received. We are going to */
+ /* send our own Xauth message using the real Xauth data. And */
+ /* then send any other data in the buffer. */
+ {
+ int c, err, dpynum, scrnum, family, sb_len;
+ char *display, *host = NULL, *rest = NULL;
+ unsigned char *sb, *p;
+
+ /* parse the local DISPLAY env var */
+ display = getenv("DISPLAY");
+ if ( !display )
+ display = "127.0.0.1:0.0";
+
+ if (fwdx_parse_displayname(display,
+ &family, &host, &dpynum, &scrnum, &rest)) {
+ char * disp_no = ckitoa(dpynum); /* should be unsigned */
+ if (family == FamilyLocal) {
+ /* call with address = "<local host name>" */
+ char address[300] = "localhost";
+ gethostname(address, sizeof(address) - 1);
+ real_xauth = XauGetAuthByAddr(family,
+ strlen(address),
+ address,
+ strlen(disp_no),
+ disp_no, 0, NULL);
+ }
+ else if (family == FamilyInternet) {
+ /* call with address = 4 bytes numeric ip addr (MSB) */
+ struct hostent *hi;
+ if (hi = gethostbyname(host))
+ real_xauth = XauGetAuthByAddr(family, 4,
+ hi->h_addr, strlen(disp_no),
+ disp_no, 0, NULL);
+ }
+ }
+ if (host) free(host);
+ if (rest) free(rest);
+ if (!real_xauth) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+ return(0);
+ }
+
+ if (!strncmp(real_xauth->name,
+ "MIT-MAGIC-COOKIE-1",
+ real_xauth->name_length)) {
+ char msg[64];
+
+ name_len = real_xauth->name_length;
+ data_len = 16;
+
+ if ( data[0] == 0x42 ) {
+ msg[0] = 0x42; /* MSB order */
+ msg[1] = msg[2] = 0;
+ msg[3] = 0x0B;
+ msg[4] = msg[5] = 0;
+ msg[6] = (name_len >> 8);
+ msg[7] = (name_len & 0xFF);
+ msg[8] = (data_len >> 8);
+ msg[9] = (data_len & 0xFF);
+ } else {
+ msg[0] = 0x6c; /* LSB order */
+ msg[1] = 0;
+ msg[2] = 0x0B;
+ msg[3] = msg[4] = msg[5] = 0;
+ msg[6] = (name_len & 0xFF);
+ msg[7] = (name_len >> 8);
+ msg[8] = (data_len & 0xFF);
+ msg[9] = (data_len >> 8);
+ }
+ msg[10] = msg[11] = 0;
+ memcpy(&msg[12],real_xauth->name,18);
+ msg[30] = msg[31] = 0;
+ memcpy(&msg[32],real_xauth->data,16);
+
+ if (fwdx_write_data_to_channel(channel,(char *)msg,48) < 0) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+ return(-1);
+ } else {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+ return(12);
+ }
+ } else {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+ return(0); /* we do not know how to handle this type yet */
+ }
+ }
+
+ auth_err:
+ debug(F100,"fwdx_send_xauth_to_xserver error","",0);
+ return(-1);
+}
+
+
+#ifdef COMMENT
+int
+#ifdef CK_ANSIC
+fwdx_authorize_channel(int channel, unsigned char * data, int len)
+#else
+fwdx_authorize_channel(channel, data, len)
+ int channel; unsigned char * data; int len;
+#endif /* CK_ANSIC */
+{
+ /* XXX maybe we should have some retry handling if not the whole first
+ * authorization packet arrives complete
+ */
+ if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized ) {
+ int name_len, data_len;
+
+ if (len < 12)
+ goto auth_err;
+
+ /* Parse the lengths of variable-length fields. */
+ if (data[0] == 0x42) { /* byte order MSB first. */
+ /* Xauth packets appear to always have this format */
+ if ( data[1] != 0x00 ||
+ data[2] != 0x00 ||
+ data[3] != 0x0B ||
+ data[4] != 0x00 ||
+ data[5] != 0x00 )
+ goto auth_err;
+
+ name_len = (data[6] << 8) + data[7];
+ data_len = (data[8] << 8) + data[9];
+ } else if (data[0] == 0x6c) { /* Byte order LSB first. */
+ /* Xauth packets appear to always have this format */
+ if ( data[1] != 0x00 ||
+ data[2] != 0x0B ||
+ data[3] != 0x00 ||
+ data[4] != 0x00 ||
+ data[5] != 0x00 )
+ goto auth_err;
+
+ name_len = data[6] + (data[7] << 8);
+ data_len = data[8] + (data[9] << 8);
+ } else {
+ /* bad byte order byte */
+ goto auth_err;
+ }
+ /* Check if authentication protocol matches. */
+ if (name_len != fake_xauth.name_length ||
+ memcmp(data + 12, fake_xauth.name, name_len) != 0) {
+ /* connection uses different authentication protocol */
+ goto auth_err;
+ }
+ /* Check if authentication data matches our fake data. */
+ if (data_len != fake_xauth.data_length ||
+ memcmp(data + 12 + ((name_len + 3) & ~3),
+ fake_xauth.data, fake_xauth.data_length) != 0) {
+ /* auth data does not match fake data */
+ goto auth_err;
+ }
+ /* substitute the fake data with real data if we have any */
+ if (real_xauth && real_xauth->data)
+ memcpy(data + 12 + ((name_len + 3) & ~3),
+ real_xauth->data, data_len);
+
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized = 1;
+ }
+ return(0);
+ auth_err:
+ return(-1);
+}
+#endif /* COMMENT */
+
+int
+#ifdef CK_ANSIC
+fwdx_send_close(int channel)
+#else
+fwdx_send_close(channel) int channel;
+#endif /* CK_ANSIC */
+{
+ unsigned short nchannel;
+ int i,rc;
+ CHAR * p;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ nchannel = htons(channel);
+ p = (unsigned char *) &nchannel;
+
+ i = 0;
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_out[i++] = FWDX_CLOSE; /* Open */
+ sb_out[i++] = p[0]; /* First Byte of Channel */
+ if ( p[0] == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = p[1]; /* Second Byte of Channel */
+ if ( p[1] == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg((char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_FORWARD_X),
+ " CLOSE CHANNEL=",ckitoa(channel)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+fwdx_send_open(int channel)
+#else /* CK_ANSIC */
+fwdx_send_open(channel) int channel;
+#endif /* CK_ANSIC */
+{
+ unsigned short nchannel;
+ int i, rc;
+ CHAR * p;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ nchannel = htons(channel);
+ p = (unsigned char *) &nchannel;
+
+ i = 0;
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_out[i++] = FWDX_OPEN; /* Open */
+ sb_out[i++] = p[0]; /* First Byte of Channel */
+ if ( p[0] == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = p[1]; /* Second Byte of Channel */
+ if ( p[1] == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg((char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_FORWARD_X),
+ " OPEN CHANNEL=",ckitoa(channel)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+fwdx_client_reply_options(char *opts, int n)
+#else
+fwdx_client_reply_options(opts, n) char *opts; int n;
+#endif /* CK_ANSIC */
+{
+ int i,j,rc;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ i = 0;
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_out[i++] = FWDX_OPTIONS; /* Options */
+
+ /* Look for the options we recognize and will support for this session */
+ /* and reply with their bytes set */
+ for (j=0; j<n; j++,i++) {
+ sb_out[i] = FWDX_OPT_NONE; /* Add zero byte - no options */
+#ifdef COMMENT
+ /* If we had any options to support, this is how we would do it */
+ if ( j == 0 ) {
+ if (opts[j] & FWDX_OPT_XXXX) {
+ /* set flag to remember option is in use */
+ flag = 1;
+ sb_out[i] |= FWDX_OPT_XXXX;
+ }
+ }
+#endif /* COMMENT */
+ }
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg((char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_FORWARD_X),
+ " OPTIONS ",ckctox(sb_out[4],1)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(0);
+}
+
+
+int
+fwdx_send_options() {
+ int i, rc;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ i = 0;
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_out[i++] = FWDX_OPTIONS; /* Options */
+ sb_out[i] = FWDX_OPT_NONE;
+ /* activate options here */
+ i++;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakmsg((char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_FORWARD_X),
+ " OPTIONS 00 IAC SE",NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+fwdx_send_data_from_channel(int channel, char * data, int len)
+#else
+fwdx_send_data_from_channel(channel, data, len)
+ int channel; char * data; int len;
+#endif
+{
+ unsigned short nchannel;
+ /* static */ CHAR sb_priv[2048];
+ CHAR * p;
+ int i, j, j_sav, rc;
+ unsigned int tmp;
+
+ debug(F111,"fwdx_send_data_from_channel()","channel",channel);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ nchannel = htons(channel);
+ p = (unsigned char *) &nchannel;
+
+ j = 0;
+ sb_priv[j++] = (CHAR) IAC; /* I Am a Command */
+ sb_priv[j++] = (CHAR) SB; /* Subnegotiation */
+ sb_priv[j++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_priv[j++] = FWDX_DATA; /* Data */
+ sb_priv[j++] = p[0]; /* First Byte of Channel */
+ if ( p[0] == IAC )
+ sb_priv[j++] = IAC;
+ sb_priv[j++] = p[1]; /* Second Byte of Channel */
+ if ( p[1] == IAC )
+ sb_priv[j++] = IAC;
+ j_sav = j;
+
+ for (i = 0; i < len; i++) {
+ tmp = (unsigned int)data[i];
+ if ( tmp == IAC ) {
+ sb_priv[j++] = IAC;
+ sb_priv[j++] = IAC;
+ } else {
+ sb_priv[j++] = tmp;
+ }
+ if ( j >= 2045 && (i < len-1) ) {
+ sb_priv[j++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_priv[j++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg( (char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_FORWARD_X),
+ " DATA CHANNEL=",ckitoa(channel)," ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL );
+ tn_hex((CHAR *)fwdx_msg_out,
+ TN_MSG_LEN,&sb_priv[j_sav],j-(j_sav+2));
+ ckstrncat((char *)fwdx_msg_out," IAC SE",TN_MSG_LEN);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = (ttol(sb_priv,j) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc) {
+ debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0);
+ return(-1);
+ }
+
+ j = 0;
+ sb_priv[j++] = (CHAR) IAC; /* I Am a Command */
+ sb_priv[j++] = (CHAR) SB; /* Subnegotiation */
+ sb_priv[j++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_priv[j++] = FWDX_DATA; /* Data */
+ sb_priv[j++] = p[0]; /* First Byte of Channel */
+ if ( p[0] == IAC )
+ sb_priv[j++] = IAC;
+ sb_priv[j++] = p[1]; /* Second Byte of Channel */
+ if ( p[1] == IAC )
+ sb_priv[j++] = IAC;
+ }
+ }
+
+ sb_priv[j++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_priv[j++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg( (char *)fwdx_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X),
+ " DATA ",ckctox(p[0],1)," ",ckctox(p[1],1)," ",
+ NULL,NULL,NULL,NULL,NULL);
+ tn_hex((CHAR *)fwdx_msg_out,TN_MSG_LEN,&sb_priv[6],j-8);
+ ckstrncat((char *)fwdx_msg_out," IAC SE",TN_MSG_LEN);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = (ttol(sb_priv,j) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if ( rc ) {
+ debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0);
+ return(-1);
+ }
+
+
+ return(0);
+}
+
+static unsigned char *
+#ifdef CK_ANSIC
+fwdx_add_quoted_twobyte(unsigned char *p, unsigned short twobyte)
+#else
+fwdx_add_quoted_twobyte(p, twobyte)
+ unsigned char *p; unsigned short twobyte;
+#endif /* CK_ANSIC */
+/* adds the IAC quoted (MSB) representation of 'channel' at buffer pointer 'p',
+ * returning pointer to new buffer position. NO OVERFLOW CHECK!
+ */
+{
+ *p++ = (unsigned char)((twobyte >> 8) & 0xFF);
+ if (*(p - 1) == 0xFF)
+ *p++ = 0xFF;
+ *p++ = (unsigned char)(twobyte & 0xFF);
+ if (*(p - 1) == 0xFF)
+ *p++ = 0xFF;
+ return p;
+}
+
+int
+#ifdef CK_ANSIC
+fwdx_create_fake_xauth(char *name, int name_len, int data_len)
+#else
+fwdx_create_fake_xauth(name, name_len, data_len)
+ char *name; int name_len; int data_len;
+#endif /* CK_ANSIC */
+{
+ char stackdata[256];
+ unsigned int c, n;
+
+ if (!name_len || !data_len)
+ return 1;
+ fake_xauth.name = malloc(name_len);
+ fake_xauth.data = malloc(data_len);
+ if (!fake_xauth.name || !fake_xauth.data)
+ return 2;
+ fake_xauth.name_length = name_len;
+ memcpy(fake_xauth.name, name, name_len);
+ fake_xauth.data_length = data_len;
+
+ /* try to make a random unsigned int to feed srand() */
+ c = time(NULL);
+ c *= getpid();
+ for (n = 0; n < sizeof(stackdata); n++)
+ c += stackdata[n];
+ srand((unsigned int)c);
+ for (c = 0; c < data_len; c++)
+ fake_xauth.data[c] = (unsigned char)rand();
+ return 0;
+}
+
+#ifdef COMMENT
+/* No longer used */
+int
+fwdx_send_xauth(void)
+{
+ int c, err, dpynum, family, sb_len, rc;
+ char *display, *host = NULL;
+ unsigned char *sb_priv, *p;
+
+ /* parse the local DISPLAY env var */
+ if (!(display = tn_get_display()))
+ return (-1);
+ if (fwdx_parse_displayname(display, &family, &host, &dpynum, NULL, NULL)) {
+ char * disp_no = ckitoa(dpynum);
+ if (family == FamilyLocal) {
+ /* call with address = "<local host name>" */
+ char address[300] = "localhost";
+ gethostname(address, sizeof(address) - 1);
+ real_xauth = XauGetAuthByAddr(family,
+ strlen(address),
+ address,
+ strlen(disp_no),
+ disp_no, 0, NULL
+ );
+ }
+ else if (family == FamilyInternet) {
+ /* call with address = 4 bytes numeric ip addr (MSB) */
+ struct hostent *hi;
+ if (hi = gethostbyname(host))
+ real_xauth = XauGetAuthByAddr(family, 4,
+ hi->h_addr,
+ strlen(disp_no),
+ disp_no, 0, NULL
+ );
+ }
+ }
+ if (host) {
+ free(host);
+ host = NULL;
+ }
+ if (real_xauth)
+ err = fwdx_create_fake_xauth(real_xauth->name,
+ real_xauth->name_length,
+ real_xauth->data_length
+ );
+ else
+ err = fwdx_create_fake_xauth("MIT-MAGIC-COOKIE-1",
+ strlen("MIT-MAGIC-COOKIE-1"), 16);
+ if (err)
+ return(-1);
+
+ /* allocate memory for the SB block, alloc for worst case */
+ /* the following sprintf() calls are safe due to length checking */
+ /* buffer is twice as big as the input just in case every byte was IAC */
+ sb_len = 5 + 2 + 2 + fake_xauth.name_length + fake_xauth.data_length + 2;
+ if (!(sb_priv = malloc(2 * sb_len)))
+ return(-1);
+ p = sb_priv;
+ sprintf(p, "%c%c%c%c%c", IAC, SB, TELOPT_FORWARD_X,
+ FWDX_OPT_DATA, FWDX_OPT_XAUTH);
+ p += 5;
+ p = fwdx_add_quoted_twobyte(p, fake_xauth.name_length);
+ p = fwdx_add_quoted_twobyte(p, fake_xauth.data_length);
+ for (c = 0; c < fake_xauth.name_length; c++) {
+ *p++ = fake_xauth.name[c];
+ if ((unsigned char)fake_xauth.name[c] == 0xFF)
+ *p++ = 0xFF;
+ }
+ for (c = 0; c < fake_xauth.data_length; c++) {
+ *p++ = fake_xauth.data[c];
+ if ((unsigned char)fake_xauth.data[c] == 0xFF)
+ *p++ = 0xFF;
+ }
+ sprintf(p, "%c%c", IAC, SE);
+ p += 2;
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ sprintf((char *)fwdx_msg_out,"TELNET SENT SB %s OPTION_DATA XAUTH ",
+ TELOPT(TELOPT_FORWARD_X));
+ tn_hex((char *)fwdx_msg_out,TN_MSG_LEN,&sb_priv[5],(p-sb_priv)-7);
+ ckstrncat((char *)fwdx_msg_out," IAC SE",TN_MSG_LEN);
+ }
+#endif /* DEBUG */
+
+ /* Add Telnet Debug info here */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,(char *)fwdx_msg_out,"",0);
+ if (tn_deb || debses) tn_debug((char *)fwdx_msg_out);
+#endif /* DEBUG */
+ rc = ( ttol(sb_priv,p-sb_priv) < 0 ); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc) {
+ debug(F110,"fwdx_send_xauth()","ttol() failed",0);
+ return(-1);
+ }
+
+
+ free(sb_priv);
+ return(0);
+}
+#endif /* COMMENT */
+#ifdef FWDX_SERVER
+/* Only if we ever become a server - not yet ported to Kermit */
+/* And even so most of this code does not belong in this module */
+
+int
+fwdx_write_xauthfile(void)
+{
+ int dpynum, scrnum, family;
+ char myhost[300], *host, *rest = NULL;
+ FILE *file;
+ struct sockaddr_in saddr;
+ struct hostent *hi;
+
+ if (!fwdx_display && !fwdx_xauthfile)
+ return 1;
+ if (!parse_displayname(fwdx_display,
+ &family, &host, &dpynum, &scrnum, &rest))
+ return 2;
+ if (rest) free(rest);
+ if (host) free(host);
+ if (family != FamilyInternet)
+ return 3; /* every thing but FamilyInternet is unexpected */
+
+ /* X connections to localhost:1 is actually treated as local unix sockets,
+ * see the 'xauth' man page.
+ */
+ xauth.family = FamilyLocal;
+ if (gethostname(myhost, sizeof(myhost) - 1))
+ return 5;
+ xauth.address_length = strlen(myhost);
+ if (!(xauth.address = malloc(xauth.address_length)))
+ return 5;
+ memcpy(xauth.address, myhost, xauth.address_length);
+
+ /* the display number is written as a string, not numeric */
+ if (!(xauth.number = malloc(6)))
+ return 6;
+ snprintf(xauth.number, 5, "%u", dpynum);
+ xauth.number_length = strlen(xauth.number);
+ if (!(file = fopen(fwdx_xauthfile, "wb")))
+ return 7;
+ if (!XauWriteAuth(file, &xauth))
+ return 8;
+ fclose(file);
+ setenv("XAUTHORITY", fwdx_xauthfile, 1);
+ return 0;
+}
+
+int
+fwdx_setup_xauth(unsigned char *sp, int len)
+/* called with 'len' xauth bytes, starting at 'sp'
+ * the data format is: <uint16 name_length> <uint16 data_length> <name> <data>
+ */
+{
+ int xauthfd;
+
+ if (!fwdx_options[FWDX_OPT_XAUTH])
+ return 1;
+ if (len < 4)
+ return 2;
+
+ /* setup the xauth struct */
+ xauth.name_length = (sp[0] << 8) + sp[1];
+ xauth.data_length = (sp[2] << 8) + sp[3];
+ if (len != 4 + xauth.name_length + xauth.data_length)
+ return 3;
+ xauth.name = malloc(xauth.name_length);
+ xauth.data = malloc(xauth.data_length);
+ if (!xauth.name || !xauth.data)
+ return 4;
+ memcpy(xauth.name, sp + 4, xauth.name_length);
+ memcpy(xauth.data, sp + 4 + xauth.name_length, xauth.data_length);
+
+ /* Setup to always have a local .Xauthority. */
+ fwdx_xauthfile = malloc(MAXPATHLEN+1);
+ snprintf(fwdx_xauthfile, MAXPATHLEN, "/tmp/XauthXXXXXX");
+ if ((xauthfd = mkstemp(fwdx_xauthfile)) != -1)
+ /* we change file ownership later, when we know who is to be owner! */
+ close(xauthfd);
+ else {
+ free(fwdx_xauthfile);
+ fwdx_xauthfile = NULL;
+ return 5;
+ }
+/* Must have the subshell's new DISPLAY env var to write xauth to xauthfile */
+ if (fwdx_display)
+ if (fwdx_write_xauthfile())
+ return 6;
+
+ return 0;
+}
+
+void fwdx_set_xauthfile_owner(int uid)
+{
+ struct passwd *pwd;
+
+ if (!fwdx_xauthfile || !(pwd = getpwuid(uid)))
+ return;
+ chown(fwdx_xauthfile, pwd->pw_uid, pwd->pw_gid);
+}
+
+int
+fwdx_server_accept_options(unsigned char *sp, int len)
+/* called with 'len' option bytes, starting at 'sp' */
+{
+ int c;
+
+ for (c = 0; c < len-2; c++) {
+ if (c == 0) {
+ if (sp[c] & FWDX_OPT_XAUTH)
+ flag = 1;
+ }
+ }
+ return(0);
+}
+#endif /* FWDX_SERVER */
+#endif /* CK_FORWARD_X */
+
+#ifdef IKS_OPTION
+/*
+ iks_wait() -- Wait for an IKS subnegotiation response.
+ sb - is either KERMIT_REQ_START or KERMIT_REQ_STOP depending on the desired
+ state of the peer's Kermit server.
+ flushok - specifies whether it is ok to throw away non-Telnet data
+ if so, then we call ttflui() instead of tn_flui().
+ Returns:
+ 1 if the desired state is achieved or if it is unknown.
+ 0 if the desired state is not achieved.
+*/
+int
+#ifdef CK_ANSIC
+iks_wait(int sb, int flushok)
+#else /* CK_ANSIC */
+iks_wait(sb,flushok) int sb; int flushok;
+#endif /* CK_ANSIC */
+{
+ int tn_wait_save = tn_wait_flg;
+ int x;
+
+ if (TELOPT_U(TELOPT_KERMIT)) {
+ switch (sb) {
+ case KERMIT_REQ_START:
+ debug(F111,
+ "iks_wait KERMIT_REQ_START",
+ "u_start",
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start
+ );
+ tn_siks(KERMIT_REQ_START);
+ tn_wait_flg = 1; /* Kermit Option MUST wait */
+ do {
+ if (flushok)
+ tn_wait_idx = 0;
+ x = tn_wait("iks_wait() me_iks_req_start");
+ } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ);
+ tn_wait_flg = tn_wait_save;
+ if (flushok)
+ tn_wait_idx = 0;
+ if (tn_wait_idx == TN_WAIT_BUF_SZ) {
+ /*
+ * We are attempting to start a kermit server on the peer
+ * the most likely reason is because we want to perform a
+ * file transfer. But there is a huge amount of non telnet
+ * negotiation data coming in and so we have not been able
+ * to find the response. So we will lie and assume that
+ * response is 'yes'. The worse that will happen is that
+ * a RESP_STOP is received after we enter protocol mode.
+ * And the protocol operation will be canceled.
+ */
+ tn_push();
+ return(1);
+ } else {
+ tn_push();
+ return(TELOPT_SB(TELOPT_KERMIT).kermit.u_start);
+ }
+ case KERMIT_REQ_STOP:
+ debug(F111,
+ "iks_wait KERMIT_REQ_STOP",
+ "u_start",
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start
+ );
+ tn_siks(KERMIT_REQ_STOP);
+ tn_wait_flg = 1; /* Kermit Option MUST wait */
+ do {
+ if (flushok)
+ tn_wait_idx = 0;
+ x = tn_wait("iks_wait() me_iks_req_stop");
+ } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ);
+ tn_wait_flg = tn_wait_save;
+ if (flushok)
+ tn_wait_idx = 0;
+
+ if (tn_wait_idx == TN_WAIT_BUF_SZ) {
+ /*
+ * We are attempting to stop a kermit server on the peer
+ * the most likely reason being that we want to enter
+ * CONNECT mode. But there is a huge amount of non telnet
+ * negotiation data coming in and so we have not been able
+ * to find the response. So we will lie and assume that
+ * the answer is 'yes' and allow the CONNECT command to
+ * succeed. The worst that happens is that CONNECT mode
+ * swallows the incoming data displaying it to the user
+ * and then it resumes Kermit client mode.
+ */
+ tn_push();
+ return(1);
+ } else {
+ tn_push();
+ return(!TELOPT_SB(TELOPT_KERMIT).kermit.u_start);
+ }
+ }
+ tn_push();
+ }
+ return(1);
+}
+
+int
+#ifdef CK_ANSIC
+iks_tn_sb(CHAR * sb, int n)
+#else
+iks_tn_sb(sb, n) CHAR * sb; int n;
+#endif /* CK_ANSIC */
+{
+ extern int server;
+ extern CHAR sstate;
+#ifdef NOICP
+ extern int autodl;
+ int inautodl = 0, cmdadl = 1;
+#else
+#ifdef CK_AUTODL
+ extern int autodl, inautodl, cmdadl;
+#endif /* CK_AUTODL */
+#endif /* NOICP */
+ switch (sb[0]) {
+ case KERMIT_START: /* START */
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1;
+ return(4);
+
+ case KERMIT_STOP: /* STOP */
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
+ return(4);
+
+ case KERMIT_REQ_START: /* REQ-START */
+#ifndef NOXFER
+ if (inserver) {
+#ifdef CK_AUTODL
+ cmdadl = 1; /* Turn on packet detection */
+#endif /* CK_AUTODL */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
+ tn_siks(KERMIT_RESP_START);
+ } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_RESP_START);
+ } else {
+#ifndef IKSDONLY
+#ifdef CK_AUTODL
+#ifdef OS2
+ if (local && (IsConnectMode() && autodl) ||
+ (!IsConnectMode() &&
+ (inautodl || sstate == 'x' || sstate == 'v'))
+ )
+ tn_siks(KERMIT_RESP_START); /* START */
+ else
+
+#else /* OS2 */
+ if ((local && what == W_CONNECT && autodl) ||
+ (local && what != W_CONNECT &&
+ (inautodl || sstate == 'x' || sstate == 'v')
+ ))
+ tn_siks(KERMIT_RESP_START); /* START */
+ else
+#endif /* OS2 */
+#endif /* CK_AUTODL */
+#endif /* IKSDONLY */
+ tn_siks(KERMIT_RESP_STOP);
+ }
+#else /* NOXFER */
+ tn_siks(KERMIT_RESP_STOP);
+#endif /* NOXFER */
+ return(4);
+
+ case KERMIT_REQ_STOP: /* REQ-STOP */
+ /* The protocol requires that the request be responded to */
+ /* either by changing states or by reporting the current */
+ /* state. */
+
+ /* We need to provide the user some way of dictating what */
+ /* the policies should be. For instance, if we are in */
+ /* CONNECT mode with autodownload ON and we get a REQ-STOP*/
+ /* what should the proper response be? */
+#ifndef NOXFER
+ if (inserver
+#ifdef CK_AUTODL
+ || !local && cmdadl
+#endif /* CK_AUTODL */
+ ) {
+#ifdef CK_AUTODL
+ cmdadl = 0; /* Turn off packet detection */
+#endif /* CK_AUTODL */
+ tn_siks(KERMIT_RESP_STOP);
+ } else if (server) {
+ extern int en_fin;
+ if (en_fin) { /* If the server is allowed to stop */
+ tn_siks(KERMIT_RESP_STOP);
+ } else { /* We are not allowed to stop */
+ tn_siks(KERMIT_RESP_START);
+ }
+ }
+#ifndef IKSDONLY
+#ifdef CK_AUTODL
+#ifdef OS2
+ else if (local && (IsConnectMode() && autodl) ||
+ (!IsConnectMode() && inautodl)
+ ) {
+ /* If we are a pseudo-server and the other side requests */
+ /* that we stop, tell then that we have even though we */
+ /* have not. Otherwise, the other side might refuse to */
+ /* enter SERVER mode. */
+
+ tn_siks(KERMIT_RESP_STOP); /* STOP */
+ }
+#else /* OS2 */
+ else if ((local && what == W_CONNECT && autodl) ||
+ (local && what != W_CONNECT && inautodl)
+ ) {
+ /* If we are a pseudo-server and the other side requests */
+ /* that we stop, tell then that we have even though we */
+ /* have not. Otherwise, the other side might refuse to */
+ /* enter SERVER mode. */
+
+ tn_siks(KERMIT_RESP_STOP); /* STOP */
+ }
+#endif /* OS2 */
+#endif /* CK_AUTODL */
+#endif /* IKSDONLY */
+ else
+#endif /* NOXFER */
+ {
+ /* If we are not currently in any mode that accepts */
+ /* Kermit packets then of course report that we are */
+ /* not being a Kermit server. */
+
+ tn_siks(KERMIT_RESP_STOP); /* STOP */
+ }
+ return(4);
+
+ case KERMIT_SOP: { /* SOP */
+#ifndef NOXFER
+ extern CHAR stchr; /* Incoming SOP character */
+ stchr = sb[1];
+#endif /* NOXFER */
+ TELOPT_SB(TELOPT_KERMIT).kermit.sop = 1;
+ return(4);
+ }
+
+ case KERMIT_RESP_START: /* START */
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1;
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) {
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
+ } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) {
+ /* If we have issued a request to stop a Kermit Server */
+ /* and the response is Start, then we must report this */
+ /* to the caller. */
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
+ }
+ return(4);
+
+ case KERMIT_RESP_STOP: /* STOP */
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) {
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
+ /* If we have issued a request to start a Kermit Server */
+ /* and the response is Stop, then we must report this */
+ /* to the caller. */
+ } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) {
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
+ }
+ return(4);
+
+ default:
+ return(0);
+
+ } /* switch (sb[0]) */
+}
+#endif /* IKS_OPTION */
+
+/* Initialize telnet settings - set default values for ME and U modes */
+int
+tn_set_modes() {
+ int opt,cmd;
+#ifdef CK_FORWARD_X
+ int x;
+#endif /* CK_FORWARD_X */
+#ifdef CK_ENVIRONMENT
+ {
+ int i,j;
+ for (i = 0; i < 8; i++) {
+ tn_env_uservar[i][0] = NULL;
+ tn_env_uservar[i][1] = NULL;
+ }
+ }
+#endif /* CK_ENVIRONMENT */
+
+ /* initialize all options to refuse in both directions */
+ for (opt = 0; opt < NTELOPTS; opt++) {
+ TELOPT_ME(opt) = 0;
+ TELOPT_U(opt) = 0;
+ TELOPT_UNANSWERED_WILL(opt) = 0;
+ TELOPT_UNANSWERED_DO(opt) = 0;
+ TELOPT_UNANSWERED_WONT(opt) = 0;
+ TELOPT_UNANSWERED_DONT(opt) = 0;
+ TELOPT_UNANSWERED_SB(opt) = 0;
+ TELOPT_ME_MODE(opt) = TN_NG_RF;
+ TELOPT_U_MODE(opt) = TN_NG_RF;
+ TELOPT_DEF_S_ME_MODE(opt) = TN_NG_RF;
+ TELOPT_DEF_S_U_MODE(opt) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(opt) = TN_NG_RF;
+ TELOPT_DEF_C_U_MODE(opt) = TN_NG_RF;
+ for (cmd = 0; cmd < 4; cmd ++)
+ tncnts[TELOPT_INDEX(opt)][cmd] = 0;
+ }
+#ifdef IKS_OPTION
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0;
+#endif /* IKS_OPTION */
+
+#ifdef CK_ENCRYPTION
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
+#endif /* CK_ENCRYPTION */
+
+#ifdef CK_NAWS
+ TELOPT_SB(TELOPT_NAWS).naws.x = 0;
+ TELOPT_SB(TELOPT_NAWS).naws.y = 0;
+#endif /* CK_NAWS */
+
+#ifdef CK_SSL
+ TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0;
+ TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0;
+ TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0;
+#endif /* CK_SSL */
+
+ /* Now set the ones we want to accept to the proper values */
+ TELOPT_DEF_S_ME_MODE(TELOPT_SGA) = TN_NG_RQ;
+ TELOPT_DEF_S_U_MODE(TELOPT_SGA) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_SGA) = TN_NG_AC;
+ TELOPT_DEF_C_U_MODE(TELOPT_SGA) = TN_NG_AC;
+
+ TELOPT_DEF_S_ME_MODE(TELOPT_BINARY) = TN_NG_AC;
+ TELOPT_DEF_S_U_MODE(TELOPT_BINARY) = TN_NG_AC;
+ TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_AC;
+ TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = TN_NG_AC;
+
+ TELOPT_DEF_S_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC;
+ TELOPT_DEF_S_U_MODE(TELOPT_LOGOUT) = TN_NG_AC;
+ TELOPT_DEF_C_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC;
+ TELOPT_DEF_C_U_MODE(TELOPT_LOGOUT) = TN_NG_AC;
+
+#ifdef IKS_OPTION
+ TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ;
+ TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ;
+ TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = TN_NG_RQ;
+#endif /* IKS_OPTION */
+
+#ifdef CK_ENCRYPTION
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+#endif /* CK_ENCRYPTION */
+
+ TELOPT_DEF_S_ME_MODE(TELOPT_ECHO) = TN_NG_RQ;
+#ifdef IKSD
+ if ( !inserver )
+#endif /* IKSD */
+ TELOPT_DEF_S_U_MODE(TELOPT_TTYPE) = TN_NG_RQ;
+
+#ifdef CK_ENVIRONMENT
+ TELOPT_DEF_S_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ;
+#endif /* CK_ENVIRONMENT */
+
+#ifdef CK_AUTHENTICATION
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_SSL
+ if (ck_ssleay_is_installed()) {
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_AC;
+ }
+#endif /* CK_SSL */
+
+#ifdef CK_NAWS
+ TELOPT_DEF_S_U_MODE(TELOPT_NAWS) = TN_NG_RQ;
+#endif /* CK_NAWS */
+
+ TELOPT_DEF_C_U_MODE(TELOPT_ECHO) = TN_NG_AC;
+ TELOPT_DEF_C_ME_MODE(TELOPT_TTYPE) = TN_NG_RQ;
+
+#ifdef CK_ENVIRONMENT
+ TELOPT_DEF_C_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ;
+#endif /* CK_ENVIRONMENT */
+
+#ifdef CK_AUTHENTICATION
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_NAWS
+ TELOPT_DEF_C_ME_MODE(TELOPT_NAWS) = TN_NG_RQ;
+#endif /* CK_NAWS */
+
+#ifdef CK_SNDLOC
+ TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RQ;
+#endif /* CK_SNDLOC */
+
+#ifdef CK_FORWARD_X
+ TELOPT_DEF_C_U_MODE(TELOPT_FORWARD_X) = TN_NG_AC;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
+ for (x = 0; x < MAXFWDX; x++) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
+ }
+#endif /* CK_FORWARD_X */
+
+#ifdef TN_COMPORT
+ TELOPT_DEF_C_ME_MODE(TELOPT_COMPORT) = TN_NG_RQ;
+#endif /* TN_COMPORT */
+
+ /* Set the initial values for currently known mode */
+ for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
+ if (TELOPT_OK(opt)) {
+ TELOPT_ME_MODE(opt) = sstelnet ?
+ TELOPT_DEF_S_ME_MODE(opt) :
+ TELOPT_DEF_C_ME_MODE(opt);
+ TELOPT_U_MODE(opt) = sstelnet ?
+ TELOPT_DEF_S_U_MODE(opt) :
+ TELOPT_DEF_C_U_MODE(opt);
+ }
+ }
+ return(1);
+}
+
+
+/* Send Delayed Subnegotiations */
+
+VOID
+tn_sdsb() {
+ /* if (!IS_TELNET()) return; */
+
+ if (TELOPT_SB(TELOPT_TTYPE).term.need_to_send) {
+ tn_sttyp();
+ TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0;
+ }
+#ifdef CK_ENVIRONMENT
+ if (TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send &&
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str) {
+ tn_snenv((CHAR *)TELOPT_SB(TELOPT_NEWENVIRON).env.str,
+ TELOPT_SB(TELOPT_NEWENVIRON).env.len);
+ free(TELOPT_SB(TELOPT_NEWENVIRON).env.str);
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL;
+ TELOPT_SB(TELOPT_NEWENVIRON).env.len=0;
+ TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0;
+ }
+#ifdef CK_XDISPLOC
+ if (TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send) {
+ tn_sxdisploc();
+ TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0;
+ }
+#endif /* CK_XDISPLOC */
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_NAWS
+ if (TELOPT_SB(TELOPT_NAWS).naws.need_to_send) {
+ tn_snaws();
+ TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0;
+ }
+#endif /* CK_NAWS */
+#ifdef CK_SNDLOC
+ if (TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send) {
+ tn_sndloc();
+ TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0;
+ }
+#endif /* CK_SNDLOC */
+#ifdef CK_FORWARD_X
+ if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send) {
+ if ( sstelnet )
+ fwdx_send_options();
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0;
+ }
+#endif /* CK_FORWARD_X */
+#ifdef TN_COMPORT
+ if (TELOPT_SB(TELOPT_COMPORT).comport.need_to_send) {
+ tn_sndcomport();
+ TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0;
+ }
+#endif /* TN_COMPORT */
+
+}
+
+int
+tn_reset() {
+ int x,opt,cmd;
+
+ /* if (!IS_TELNET()) return(1); */
+
+ tn_wait_idx = 0; /* Clear the tn_push() buffer */
+ tn_wait_tmo = TN_TIMEOUT; /* Reset wait timer stats */
+
+ nflag = 0;
+
+ /* Reset the TELNET OPTIONS counts */
+ for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
+ if (TELOPT_OK(opt)) {
+ TELOPT_ME(opt) = 0;
+ TELOPT_U(opt) = 0;
+ TELOPT_UNANSWERED_WILL(opt) = 0;
+ TELOPT_UNANSWERED_DO(opt) = 0;
+ TELOPT_UNANSWERED_WONT(opt) = 0;
+ TELOPT_UNANSWERED_DONT(opt) = 0;
+ TELOPT_UNANSWERED_SB(opt) = 0;
+ TELOPT_ME_MODE(opt) = sstelnet ?
+ TELOPT_DEF_S_ME_MODE(opt) :
+ TELOPT_DEF_C_ME_MODE(opt);
+ TELOPT_U_MODE(opt) = sstelnet ?
+ TELOPT_DEF_S_U_MODE(opt) :
+ TELOPT_DEF_C_U_MODE(opt);
+
+#ifdef DEBUG
+ if (deblog) {
+ switch (TELOPT_ME_MODE(opt)) {
+ case TN_NG_RF:
+ debug(F110,"tn_ini ME REFUSE ",TELOPT(opt),0);
+ break;
+ case TN_NG_AC:
+ debug(F110,"tn_ini ME ACCEPT ",TELOPT(opt),0);
+ break;
+ case TN_NG_RQ:
+ debug(F110,"tn_ini ME REQUEST",TELOPT(opt),0);
+ break;
+ case TN_NG_MU:
+ debug(F110,"tn_ini ME REQUIRE",TELOPT(opt),0);
+ break;
+ }
+ switch (TELOPT_U_MODE(opt)) {
+ case TN_NG_RF:
+ debug(F110,"tn_ini U REFUSE ",TELOPT(opt),0);
+ break;
+ case TN_NG_AC:
+ debug(F110,"tn_ini U ACCEPT ",TELOPT(opt),0);
+ break;
+ case TN_NG_RQ:
+ debug(F110,"tn_ini U REQUEST",TELOPT(opt),0);
+ break;
+ case TN_NG_MU:
+ debug(F110,"tn_ini U REQUIRE",TELOPT(opt),0);
+ break;
+ }
+ }
+#endif /* DEBUG */
+ for (cmd = 0; cmd < 4; cmd ++)
+ tncnts[TELOPT_INDEX(opt)][cmd] = 0;
+ }
+ }
+#ifdef CK_ENVIRONMENT
+ if (!tn_env_flg) {
+ TELOPT_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RF;
+ }
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ if (!tn_loc)
+ TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RF;
+#endif /* CK_SNDLOC */
+#ifdef IKS_OPTION
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
+ TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0;
+#endif /* IKS_OPTION */
+#ifdef CK_ENCRYPTION
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0;
+#endif /* CK_ENCRYPTION */
+#ifdef CK_NAWS
+ TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0;
+ TELOPT_SB(TELOPT_NAWS).naws.x = 0;
+ TELOPT_SB(TELOPT_NAWS).naws.y = 0;
+#endif /* CK_NAWS */
+ TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0;
+ TELOPT_SB(TELOPT_TTYPE).term.type[0] = '\0';
+#ifdef CK_ENVIRONMENT
+ TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0;
+ if (tn_first)
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL;
+ else if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) {
+ free(TELOPT_SB(TELOPT_NEWENVIRON).env.str);
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL;
+ }
+ TELOPT_SB(TELOPT_NEWENVIRON).env.len=0;
+#ifdef CK_XDISPLOC
+ TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0;
+#endif /* CK_XDISPLOC */
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0;
+#endif /* CK_SNDLOC */
+#ifdef CK_FORWARD_X
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
+ for (x = 0; x < MAXFWDX; x++) {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
+ }
+ /* Reset Xauth data */
+ if ( real_xauth ) {
+ XauDisposeAuth(real_xauth);
+ real_xauth = NULL;
+ }
+ if ( fake_xauth.name )
+ free(fake_xauth.name);
+ if ( fake_xauth.data )
+ free(fake_xauth.data);
+ if ( fake_xauth.address )
+ free(fake_xauth.address);
+ if ( fake_xauth.number )
+ free(fake_xauth.number);
+ memset(&fake_xauth,0,sizeof(fake_xauth));
+#ifdef NT
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
+#endif /* NT */
+#endif /* CK_FORWARD_X */
+#ifdef CK_SSL
+ if (tls_only_flag || ssl_only_flag) {
+ TELOPT_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ }
+ TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0;
+ TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0;
+ TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0;
+#endif /* CK_SSL */
+
+#ifdef CK_ENCRYPTION
+ if (!ck_crypt_is_installed()
+#ifdef CK_SSL
+ || tls_only_flag || ssl_only_flag
+#endif /* CK_SSL */
+ ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_ENCRYPTION */
+
+#ifdef TN_COMPORT
+ TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0;
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0;
+ tnc_init();
+#endif /* TN_COMPORT */
+
+ tn_first = 0; /* No longer the first time init */
+
+#ifdef OS2
+ ttnum = -1; /* Reset TermType negotiation */
+ ttnumend = 0;
+#endif /* OS2 */
+
+ return(0);
+}
+
+int
+tn_start() {
+ int wait, x, opt;
+
+ /* if (!IS_TELNET()) return(0); */
+
+ if (tn_init && tn_begun)
+ return(0);
+ tn_begun = 1;
+
+ debug(F111,"tn_start","sstelnet",sstelnet);
+ wait = 0;
+ if (tn_duplex) {
+ oldplex = duplex; /* save old duplex value */
+ duplex = 1; /* and set to half duplex for telnet */
+ }
+#ifdef CK_SSL
+ if (!TELOPT_ME(TELOPT_START_TLS) &&
+ TELOPT_ME_MODE(TELOPT_START_TLS) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_START_TLS) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_START_TLS) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(TELOPT_START_TLS) &&
+ TELOPT_U_MODE(TELOPT_START_TLS) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_START_TLS) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_START_TLS) = 1;
+ wait = 1;
+ }
+#endif /* CK_SSL */
+
+#ifdef CK_AUTHENTICATION
+ debug(F110,"tn_ini() CK_AUTHENTICATION","",0);
+ if (tn_init) /* tn_ini() might be called recursively */
+ return(0);
+ if (!TELOPT_ME(TELOPT_AUTHENTICATION) &&
+ TELOPT_ME_MODE(TELOPT_AUTHENTICATION) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_AUTHENTICATION) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_AUTHENTICATION) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(TELOPT_AUTHENTICATION) &&
+ TELOPT_U_MODE(TELOPT_AUTHENTICATION) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_AUTHENTICATION) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_AUTHENTICATION) = 1;
+ wait = 1;
+ }
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_RF &&
+ TELOPT_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_RF) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_ENCRYPTION */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_NAWS
+#ifndef NOLOCAL
+ debug(F110,"tn_ini() CK_NAWS !NOLOCAL","",0);
+ if (!sstelnet) {
+ /* Console terminal screen rows and columns */
+#ifdef OS2
+ debug(F101,
+ "tn_ini tt_rows 1",
+ "",
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
+ );
+ debug(F101,"tn_ini tt_cols 1","",VscrnGetWidth(VTERM));
+ /* Not known yet */
+ if (VscrnGetWidth(VTERM) < 0 ||
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
+ ttgwsiz(); /* Try to find out */
+ }
+ debug(F101,
+ "tn_ini tt_rows 2",
+ "",
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
+ );
+ debug(F101,"tn_ini tt_cols 2","",VscrnGetWidth(VTERM));
+ /* Now do we know? */
+ if (VscrnGetWidth(VTERM) > 0 &&
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) > 0) {
+ if (!TELOPT_ME(TELOPT_NAWS) &&
+ TELOPT_ME_MODE(TELOPT_NAWS) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_NAWS) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_NAWS) = 1;
+ wait = 1;
+ }
+ }
+#else /* OS2 */
+ debug(F101,"tn_ini tt_rows 1","",tt_rows);
+ debug(F101,"tn_ini tt_cols 1","",tt_cols);
+ if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
+ ttgwsiz(); /* Try to find out */
+ }
+ debug(F101,"tn_ini tt_rows 2","",tt_rows);
+ debug(F101,"tn_ini tt_cols 2","",tt_cols);
+ if (tt_rows > 0 && tt_cols > 0) { /* Now do we know? */
+ if (!TELOPT_ME(TELOPT_NAWS) &&
+ TELOPT_ME_MODE(TELOPT_NAWS) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_NAWS) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_NAWS) = 1;
+ wait = 1;
+ }
+ }
+#endif /* OS2 */
+ } else
+#endif /* NOLOCAL */
+ {
+ if (!TELOPT_U(TELOPT_NAWS) &&
+ TELOPT_U_MODE(TELOPT_NAWS) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_NAWS) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_NAWS) = 1;
+ wait = 1;
+ }
+ }
+#endif /* CK_NAWS */
+
+ if (!TELOPT_ME(TELOPT_SGA) &&
+ TELOPT_ME_MODE(TELOPT_SGA) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_SGA) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_SGA) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(TELOPT_SGA) &&
+ TELOPT_U_MODE(TELOPT_SGA) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_SGA) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_SGA) = 1;
+ wait = 1;
+ }
+ if (!tn_duplex) {
+ if (!TELOPT_U(TELOPT_ECHO) &&
+ TELOPT_U_MODE(TELOPT_ECHO) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_ECHO) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_ECHO) = 1;
+ wait = 1;
+ }
+ }
+ if (!TELOPT_ME(TELOPT_ECHO) &&
+ TELOPT_ME_MODE(TELOPT_ECHO) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_ECHO) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_ECHO) = 1;
+ wait = 1;
+ }
+
+ debug(F100,"tn_ini about to send WILL TTYPE if requested","",0);
+/*
+ Talking to TELNET port, so send WILL TERMINAL TYPE and DO SGA.
+ Also send WILL NAWS if we know our screen dimensions.
+*/
+ if (!TELOPT_ME(TELOPT_TTYPE) &&
+ TELOPT_ME_MODE(TELOPT_TTYPE) >= TN_NG_RQ) {
+ if ((x = tn_sopt(WILL,TELOPT_TTYPE)) < 0) {
+ debug(F101,"tn_ini tn_sopt WILL TTYPE failed","",x);
+ return(-1);
+ }
+ TELOPT_UNANSWERED_WILL(TELOPT_TTYPE) = 1;
+ wait = 1;
+ debug(F100,"tn_ini sent WILL TTYPE ok","",0);
+ }
+ if (!TELOPT_U(TELOPT_TTYPE) &&
+ TELOPT_U_MODE(TELOPT_TTYPE) >= TN_NG_RQ) {
+ if ((x = tn_sopt(DO,TELOPT_TTYPE)) < 0) {
+ debug(F101,"tn_ini tn_sopt DO TTYPE failed","",x);
+ return(-1);
+ }
+ TELOPT_UNANSWERED_DO(TELOPT_TTYPE) = 1;
+ wait = 1;
+ debug(F100,"tn_ini sent DO TTYPE ok","",0);
+ }
+ if (!TELOPT_ME(TELOPT_BINARY) &&
+ TELOPT_ME_MODE(TELOPT_BINARY) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_BINARY) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(TELOPT_BINARY) &&
+ TELOPT_U_MODE(TELOPT_BINARY) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_BINARY) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
+ wait = 1;
+ }
+#ifdef CK_SNDLOC
+ if (tn_loc) {
+ if (!TELOPT_ME(TELOPT_SNDLOC) &&
+ TELOPT_ME_MODE(TELOPT_SNDLOC) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_SNDLOC) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_SNDLOC) = 1;
+ wait = 1;
+ }
+ }
+#endif /* CK_SNDLOC */
+#ifdef CK_ENVIRONMENT
+#ifdef CK_FORWARD_X
+ if (!TELOPT_U(TELOPT_FORWARD_X) &&
+ TELOPT_U_MODE(TELOPT_FORWARD_X) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_FORWARD_X) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_FORWARD_X) = 1;
+ wait = 1;
+ }
+#endif /* FORWARD_X */
+#ifdef CK_XDISPLOC
+ if (!TELOPT_ME(TELOPT_XDISPLOC) &&
+ TELOPT_ME_MODE(TELOPT_XDISPLOC) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_XDISPLOC) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_XDISPLOC) = 1;
+ wait = 1;
+ }
+#endif /* CK_XDISPLOC */
+ /* Will send terminal environment. */
+ if (!TELOPT_ME(TELOPT_NEWENVIRON) &&
+ TELOPT_ME_MODE(TELOPT_NEWENVIRON) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_NEWENVIRON) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_NEWENVIRON) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(TELOPT_NEWENVIRON) &&
+ TELOPT_U_MODE(TELOPT_NEWENVIRON) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_NEWENVIRON) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_NEWENVIRON) = 1;
+ wait = 1;
+ }
+#endif /* CK_ENVIRONMENT */
+
+ /* Take care of any other telnet options that require handling. */
+
+ for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
+ switch (opt) {
+ case TELOPT_AUTHENTICATION:
+ case TELOPT_ENCRYPTION:
+ case TELOPT_TTYPE:
+ case TELOPT_NAWS:
+ case TELOPT_BINARY:
+ case TELOPT_NEWENVIRON:
+ case TELOPT_SNDLOC:
+ case TELOPT_XDISPLOC:
+ case TELOPT_SGA:
+ case TELOPT_ECHO:
+ case TELOPT_KERMIT:
+ case TELOPT_START_TLS:
+ case TELOPT_FORWARD_X:
+ break;
+ break;
+ default:
+ if (TELOPT_OK(opt)) {
+ if (!TELOPT_ME(opt) &&
+ TELOPT_ME_MODE(opt) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, opt) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(opt) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(opt) &&
+ TELOPT_U_MODE(opt) >= TN_NG_RQ) {
+ if (tn_sopt(DO, opt) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(opt) = 1;
+ wait = 1;
+ }
+ }
+ }
+ }
+ if (wait) {
+ if (tn_wait("pre-encrypt") < 0) {
+ tn_push();
+ return(-1);
+ }
+ wait = 0;
+ }
+
+#ifdef CK_ENCRYPTION
+ if (tn_init) /* tn_ini() may be called recursively */
+ return(0);
+
+ if (!TELOPT_ME(TELOPT_ENCRYPTION) &&
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_ENCRYPTION) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_ENCRYPTION) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_U(TELOPT_ENCRYPTION) &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_ENCRYPTION) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_ENCRYPTION) = 1;
+ wait = 1;
+ }
+
+ /* If we are going to encrypt, we want to do it before we send any more */
+ /* data, especially the terminal type and environment variables. */
+ if (wait) {
+ if (tn_wait("post-encrypt") < 0) {
+ tn_push();
+ return(-1);
+ }
+ wait = 0;
+ }
+#endif /* CK_ENCRYPTION */
+
+ tn_sdsb();
+
+ if (tn_init) /* tn_ini() may be called recursively */
+ return(0);
+
+#ifdef IKS_OPTION
+ /* Kermit Server negotiation must go last */
+ /* Send U before ME */
+
+ if (!TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_U_MODE(TELOPT_KERMIT) >= TN_NG_RQ) {
+ if (tn_sopt(DO, TELOPT_KERMIT) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(TELOPT_KERMIT) = 1;
+ wait = 1;
+ }
+ if (!TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_ME_MODE(TELOPT_KERMIT) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, TELOPT_KERMIT) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(TELOPT_KERMIT) = 1;
+ wait = 1;
+ }
+#endif /* IKS_OPTION */
+
+ if (wait) {
+ if (tn_wait("end of telnet negotiations") < 0) {
+ tn_push();
+ return(-1);
+ }
+ wait = 0;
+ }
+
+ tn_sdsb(); /* Send delayed subnegotiations */
+ tn_push();
+ return(0);
+}
+
+/* Start a telnet connection. */
+/* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
+
+int
+tn_ini() {
+ int x;
+
+ debug(F101,"tn_ini ttnproto","",ttnproto);
+ debug(F101,"tn_ini tn_init","",tn_init);
+
+ if (ttnet != NET_TCPB) /* Make sure connection is TCP/IP */
+ return(0);
+/*
+ if (!IS_TELNET())
+ return(0);
+*/
+ if (tn_init) /* Have we done this already? */
+ return(0); /* Don't do it again. */
+
+ tn_reset(); /* Reset telnet parameters */
+ tn_begun = 0; /* Reset; will be set by tn_start() */
+
+ switch ( ttnproto ) {
+ case NP_RLOGIN:
+ case NP_K4LOGIN:
+ case NP_EK4LOGIN:
+ case NP_K5LOGIN:
+ case NP_EK5LOGIN:
+ case NP_K5U2U:
+ tn_init = 1;
+ debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init);
+ return(0);
+#ifdef COMMENT
+ /* Jeff's code from 30 Dec 2005 - doesn't work with SSL POP server */
+ case NP_NONE:
+ case NP_SSL:
+ case NP_TLS:
+ ttnproto = NP_TELNET; /* pretend it's telnet anyway, */
+ oldplex = duplex; /* save old duplex value */
+ duplex = 1; /* and set to half duplex for telnet */
+ if (inserver)
+ debug(F100,"tn_ini skipping telnet negotiations","",0);
+ else
+ tn_wait("tn_ini - waiting to see if telnet negotiations were sent");
+ tn_push();
+ return(0);
+ case NP_SSL_RAW:
+ case NP_TLS_RAW:
+ case NP_TCPRAW: /* Raw socket requested. */
+ debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init);
+ return(0);
+#else
+ /* My code from 4 Dec 2005 - works with SSL POP server */
+ case NP_NONE:
+ case NP_SSL:
+ case NP_TLS: /* If not talking to a telnet port, */
+ case NP_SSL_RAW: /* SSL and TLS with Telnet */
+ case NP_TLS_RAW: /* negotiations disabled. */
+ ttnproto = NP_TELNET; /* pretend it's telnet anyway, */
+ oldplex = duplex; /* save old duplex value */
+ duplex = 1; /* and set to half duplex for telnet */
+ if (inserver)
+ debug(F100,"tn_ini skipping telnet negotiations","",0);
+ else
+ tn_wait("tn_ini - waiting to see if telnet negotiations were sent");
+ tn_push();
+ return(0);
+ case NP_TCPRAW: /* Raw socket requested. */
+ debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init);
+ return(0);
+#endif /* COMMENT */
+ case NP_KERMIT: /* switching to Telnet protocol */
+ case NP_SSL_TELNET:
+ case NP_TLS_TELNET:
+ debug(F101,"tn_ini switching from XXX to Telnet","",ttnproto);
+ ttnproto = NP_TELNET;
+ /* fall through */
+ default:
+ /* We are already using a variation on Telnet protocol */
+ ;
+ }
+
+ x = tn_start();
+ tn_init = 1; /* Remember successful completion. */
+
+ /* Don't send anything else! */
+ debug(F101,"tn_ini duplex","",duplex);
+ debug(F101,"tn_ini done, tn_init","",tn_init);
+ return(x);
+}
+
+int
+#ifdef CK_ANSIC
+tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen)
+#else /* CK_ANSIC */
+tn_hex(buf, buflen, data, datalen)
+ CHAR * buf;
+ int buflen;
+ CHAR * data;
+ int datalen;
+#endif /* CK_ANSIC */
+{
+ int i = 0, j = 0, k = 0;
+ CHAR tmp[16]; /* in case value is treated as negative */
+#ifdef COMMENT
+ int was_hex = 1;
+
+ for (k=0; k < datalen; k++) {
+ if (data[k] < 32 || data[k] >= 127) {
+ sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]);
+ was_hex = 1;
+ } else {
+ sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]);
+ was_hex = 0;
+ }
+ ckstrncat((char *)buf,tmp,buflen);
+ }
+ if (!was_hex)
+ ckstrncat((char *)buf,"\" ",buflen);
+#else /* COMMENT */
+ if (datalen <= 0 || data == NULL || buf == NULL || buflen <= 0)
+ return(0);
+
+ for (i = 0; i < datalen; i++) {
+ ckstrncat((char *)buf,"\r\n ",buflen);
+ for (j = 0 ; (j < 16); j++) {
+ if ((i + j) < datalen)
+ sprintf((char *)tmp,
+ "%s%02x ",
+ (j == 8 ? "| " : ""),
+ (unsigned int) data[i + j]
+ );
+ else
+ sprintf((char *)tmp,
+ "%s ",
+ (j == 8 ? "| " : "")
+ );
+ ckstrncat((char *)buf,(char *)tmp,buflen);
+ }
+ ckstrncat((char *)buf," ",buflen);
+ for (k = 0; (k < 16) && ((i + k) < datalen); k++) {
+ sprintf((char *)tmp,
+ "%s%c",
+ (k == 8 ? " " : ""),
+ isprint((char)(data[i+k])) ? data[i+k] : '.'
+ );
+ ckstrncat((char *)buf,(char *)tmp,buflen);
+ }
+ i += j - 1;
+ } /* end for */
+ ckstrncat((char *)buf,"\r\n ",buflen);
+#endif /* COMMENT */
+ return(strlen((char *)buf));
+}
+
+VOID
+tn_debug(s) char *s; {
+#ifdef NOLOCAL
+ return;
+#else /* NOLOCAL */
+#ifdef OS2
+ void cwrite(unsigned short);
+ char *p = s;
+ _PROTOTYP (void os2bold, (void));
+ extern int tt_type_mode;
+#endif /* OS2 */
+
+ if (!(tn_deb || debses))
+ return;
+ debug(F111,"tn_debug",s,what);
+#ifdef OS2
+ if (1) {
+ extern unsigned char colorcmd;
+ colorcmd ^= 0x8 ;
+ printf("%s\r\n",s);
+ colorcmd ^= 0x8 ;
+ }
+ if (!scrninitialized[VTERM]) {
+ USHORT x,y;
+ checkscreenmode();
+ GetCurPos(&y, &x);
+ SaveCmdMode(x+1,y+1);
+ scrninit();
+ RestoreCmdMode();
+ }
+
+ if ( ISVTNT(tt_type_mode) && ttnum != -1 && !debses )
+ return;
+
+ RequestVscrnMutex( VTERM, SEM_INDEFINITE_WAIT ) ;
+
+ os2bold(); /* Toggle boldness */
+ while (*p)
+ cwrite((CHAR) *p++); /* Go boldly ... */
+ os2bold(); /* Toggle boldness back */
+ if (debses) {
+ debses = 0;
+ cwrite((CHAR) '\015');
+ cwrite((CHAR) '\012');
+ debses = 1;
+ } else {
+ cwrite((CHAR) '\015');
+ cwrite((CHAR) '\012');
+ }
+ ReleaseVscrnMutex(VTERM) ;
+#else
+ if (what != W_CONNECT && what != W_DIALING &&
+ what != W_COMMAND && what != W_NOTHING)
+ return; /* CONNECT/command must be active */
+ conoll(s);
+#endif /* OS2 */
+#endif /* NOLOCAL */
+}
+
+/*
+ Process in-band Telnet negotiation characters from the remote host.
+ Call with the telnet IAC character and the current duplex setting
+ (0 = remote echo, 1 = local echo), and a pointer to a function to call
+ to read more characters. Returns:
+ 6 if DO LOGOUT was received and accepted
+ 5 if the Kermit start of packet character has changed
+ 4 if state of remote Internet Kermit Service has changed
+ 3 if a quoted IAC was received
+ 2 if local echo must be changed to remote
+ 1 if remote echo must be changed to local
+ 0 if nothing happens or no action necessary
+ -1 on failure (= internal or i/o error)
+*/
+#ifdef IKS_OPTION
+int
+tn_siks(cmd) int cmd; { /* TELNET SEND IKS SUB */
+ CHAR buf[8];
+#ifndef NOXFER
+ extern CHAR mystch; /* Outgoing Start of Packet Char */
+#else
+ CHAR mystch = '\1';
+#endif /* NOXFER */
+ int n,m,rc;
+
+ if (ttnet != NET_TCPB) return(0); /* Must be TCP/IP */
+ if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
+
+ if (cmd < KERMIT_START || cmd > KERMIT_RESP_STOP) /* Illegal subcommand */
+ return(-1);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+ if (cmd == KERMIT_START || cmd == KERMIT_RESP_START) {
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
+ } else if (cmd == KERMIT_STOP || cmd == KERMIT_RESP_STOP) {
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
+ } else if (cmd == KERMIT_REQ_STOP)
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 1;
+ else if (cmd == KERMIT_REQ_START)
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 1;
+
+ if (cmd == KERMIT_SOP) {
+ buf[0] = (CHAR) IAC;
+ buf[1] = (CHAR) SB;
+ buf[2] = (CHAR) TELOPT_KERMIT;
+ buf[3] = (CHAR) (cmd & 0xff);
+ buf[4] = (CHAR) mystch;
+ buf[5] = (CHAR) IAC;
+ buf[6] = (CHAR) SE;
+ buf[7] = (CHAR) 0;
+#ifdef DEBUG
+ if (tn_deb || debses || deblog)
+ ckmakmsg( tn_msg_out,TN_MSG_LEN,"TELNET SENT SB KERMIT SOP ",
+ ckctox(mystch,1)," IAC SE",NULL);
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F101,tn_msg_out,"",cmd);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = ( ttol(buf,7) < 7 ); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ } else {
+ buf[0] = (CHAR) IAC;
+ buf[1] = (CHAR) SB;
+ buf[2] = (CHAR) TELOPT_KERMIT;
+ buf[3] = (CHAR) (cmd & 0xff);
+ buf[4] = (CHAR) IAC;
+ buf[5] = (CHAR) SE;
+ buf[6] = (CHAR) 0;
+
+#ifdef DEBUG
+ if (tn_deb || debses || deblog) {
+ char * s = 0;
+ switch (cmd) {
+ case KERMIT_START: s = "START"; break;
+ case KERMIT_STOP: s = "STOP"; break;
+ case KERMIT_REQ_START: s = "REQ-START"; break;
+ case KERMIT_REQ_STOP: s = "REQ-STOP"; break;
+ case KERMIT_RESP_START: s = "RESP-START"; break;
+ case KERMIT_RESP_STOP: s = "RESP-STOP"; break;
+ }
+ ckmakmsg( tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB kermit ",s," IAC SE",NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F101,tn_msg_out,"",cmd);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = ( ttol(buf,6) < 6 ); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ }
+ return(1);
+}
+#endif /* IKS_OPTION */
+
+/* tn_sb() performs Telnet Subnegotiation Parsing and Debugging */
+/* returns <= 0 on error, 1 on success */
+/* the length returned includes the IAC SE bytes */
+
+int
+#ifdef CK_ANSIC /* TELNET SB */
+tn_sb( int opt, int * len, int (*fn)(int) )
+#else
+tn_sb( opt, len, fn ) int opt; int * len; int (*fn)();
+#endif /* CK_ANSIC */
+/* tn_sb */ {
+ int c, x, y, n, m, flag;
+ /* if (!IS_TELNET()) return(1); */
+
+ debug(F100,"Entering tn_sb()","",0);
+ *len = 0; /* Initialize Len to 0 */
+ n = flag = 0; /* Flag for when done reading SB */
+ while (n < TSBUFSIZ) { /* Loop looking for IAC SE */
+ if ((y = (*fn)(0)) < 0) /* Read a byte */
+ return(y);
+ y &= 0xff; /* Make sure it's just 8 bits. */
+ sb[n++] = (char) y; /* Deposit in buffer. */
+ if (seslog && sessft == XYFT_D) { /* Take care of session log */
+ logchar((char) y);
+ }
+ if (y == IAC) { /* If this is an IAC */
+ if (flag) { /* If previous char was IAC */
+ n--; /* it's quoted, keep one IAC */
+ flag = 0; /* and turn off the flag. */
+ } else flag = 1; /* Otherwise set the flag. */
+ } else if (flag) { /* Something else following IAC */
+ if (y == SE) /* If not SE, it's a protocol error */
+ break;
+ else if (y == DONT) { /* Used DONT instead of SE */
+ debug(F100,
+ "TELNET Subnegotiation error - used DONT instead of SE!",
+ ""
+ ,0
+ );
+ if (tn_deb || debses)
+ tn_debug(
+ "TELNET Subnegotiation error - used DONT instead of SE!");
+ flag = 3;
+ break;
+ } else { /* Other protocol error */
+ flag = 0;
+ break;
+ }
+ }
+
+#ifdef CK_FORWARD_X
+ if ( opt == TELOPT_FORWARD_X && sb[0] == FWDX_DATA &&
+ n >= (TSBUFSIZ-4) && !flag ) {
+ /* do not let the buffer over flow */
+ /* write the data to the channel and continue processing */
+ /* the incoming data until IAC SE is reached. */
+ sb[n++] = IAC;
+ sb[n++] = SE;
+
+#ifdef DEBUG
+ if ( deblog || tn_deb || debses ) {
+ int i;
+ ckmakmsg( tn_msg,TN_MSG_LEN,
+ "TELNET RCVD SB ",TELOPT(opt),
+ " DATA(buffer-full) ",NULL);
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&sb[1],n-3);
+ if (flag == 2)
+ ckstrncat(tn_msg," SE",TN_MSG_LEN);
+ else if (flag == 3)
+ ckstrncat(tn_msg," IAC DONT",TN_MSG_LEN);
+ else
+ ckstrncat(tn_msg," IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses)
+ tn_debug(tn_msg);
+ }
+#endif /* DEBUG */
+
+ if ( fwdx_tn_sb(sb,n) < 0 ) {
+ debug(F100,"fxdx_tn_sb() failed","",0);
+ /* We can't return though because that would leave */
+ /* data to be forwarded in the queue to the be sent */
+ /* to the terminal emulator. */
+ }
+ /* reset leave the msg type and channel number in place */
+ n = 3;
+ }
+#endif /* CK_FORWARD_X */
+ }
+ debug(F111,"tn_sb end of while loop","flag",flag);
+ if (!flag) { /* Make sure we got a valid SB */
+ debug(F111, "TELNET Subnegotiation prematurely broken","opt",opt);
+ if (tn_deb || debses) {
+ ckmakmsg( tn_msg, TN_MSG_LEN,
+ "TELNET ", TELOPT(opt),
+ " Subnegotiation prematurely broken",NULL
+ );
+
+ tn_debug(tn_msg);
+ }
+ /* Was -1 but that would be an I/O error, so absorb it and go on. */
+ return(0);
+ }
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ int i;
+ char * s[16];
+ for (i = 0; i < 16; i++)
+ s[i] = "";
+ if (opt == TELOPT_NAWS) {
+ i = 0;
+ } else {
+ i = 1;
+ s[0] = "UNKNOWN";
+
+ switch (sb[0]) {
+ case 0:
+ if (opt == TELOPT_FORWARD_X)
+ s[0] = "SCREEN";
+ else if (opt == TELOPT_KERMIT)
+ s[0] = "START";
+ else if (opt == TELOPT_LFLOW)
+ s[0] = "OFF";
+ else if (opt == TELOPT_COMPORT)
+ s[0] = "SIGNATURE";
+ else
+ s[0] = "IS";
+ if (opt == TELOPT_ENCRYPTION) {
+ i++;
+ if (sb[1] < ENCTYPE_CNT) {
+ s[1] = enctype_names[sb[1]];
+ i++;
+ switch(sb[2]) {
+ case 1:
+ s[2] = "FB64_IV";
+ break;
+ case 2:
+ s[2] = "FB64_IV_OK";
+ break;
+ case 3:
+ s[2] = "FB64_IV_BAD";
+ break;
+ case 4:
+ s[2] = "FB64_CHALLENGE";
+ break;
+ case 5:
+ s[2] = "FB64_RESPONSE";
+ break;
+ }
+ } else {
+ s[1] = "UNKNOWN";
+ }
+ }
+ if (opt == TELOPT_AUTHENTICATION) {
+ i += 2;
+ s[1] = AUTHTYPE_NAME(sb[1]);
+ s[2] = AUTHMODE_NAME(sb[2]);
+ if (sb[1]) {
+ i++;
+ switch (sb[3]) {
+ case 0:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_AUTH";
+ break;
+ default:
+ s[3] = "AUTH";
+ }
+ break;
+ case 1:
+ switch (sb[1]) {
+ case AUTHTYPE_SSL:
+ s[3] = "START";
+ break;
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_CHALLENGE";
+ break;
+ default:
+ s[3] = "REJECT";
+ }
+ break;
+ case 2:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_RESPONSE";
+ break;
+ default:
+ s[3] = "ACCEPT";
+ }
+ break;
+ case 3:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_ACCEPT";
+ break;
+ case 1: /* KERBEROS_v4 */
+ case 5: /* SRP */
+ s[3] = "CHALLENGE";
+ break;
+ case 2: /* KERBEROS_v5 */
+ s[3] = "RESPONSE";
+ break;
+ case AUTHTYPE_SSL:
+ s[3] = "REJECT";
+ break;
+ }
+ break;
+ case 4:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_REJECT";
+ break;
+ case 1: /* KERBEROS_V4 */
+ case 5: /* SRP */
+ s[3] = "RESPONSE";
+ break;
+ case 2: /* KERBEROS_V5 */
+ s[3] = "FORWARD";
+ break;
+ }
+ break;
+ case 5:
+ switch (sb[1]) {
+ case 5: /* SRP */
+ s[3] = "FORWARD";
+ break;
+ case 2: /* KERBEROS_V5 */
+ s[3] = "FORWARD_ACCEPT";
+ break;
+ }
+ break;
+ case 6:
+ switch (sb[1]) {
+ case 5: /* SRP */
+ s[3] = "FORWARD_ACCEPT";
+ break;
+ case 2: /* KERBEROS_V5 */
+ s[3] = "FORWARD_REJECT";
+ break;
+ }
+ break;
+ case 7:
+ switch (sb[1]) {
+ case 5: /* SRP */
+ s[3] = "FORWARD_REJECT";
+ break;
+ case 2: /* KERBEROS_V5 */
+ s[3] = "TLS_VERIFY";
+ break;
+ }
+ break;
+ case 8:
+ switch (sb[1]) {
+ case 5: /* SRP */
+ s[3] = "EXP";
+ break;
+ }
+ break;
+ case 9:
+ switch (sb[1]) {
+ case 5: /* SRP */
+ s[3] = "PARAMS";
+ break;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case 1:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "OPEN";
+ break;
+ case TELOPT_LFLOW:
+ s[0] = "ON";
+ break;
+ case TELOPT_KERMIT:
+ s[0] = "STOP";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "SET-BAUDRATE";
+ break;
+ case TELOPT_AUTHENTICATION:
+ s[0] = "SEND";
+ hexbuf[0] = '\0';
+ for (; i < n-2; i += 2) {
+ if ( AUTHTYPE_NAME_OK(sb[i]) &&
+ AUTHMODE_NAME_OK(sb[i]))
+ ckmakmsg( tn_msg, TN_MSG_LEN,
+ AUTHTYPE_NAME(sb[i])," ",
+ AUTHMODE_NAME(sb[i+1])," "
+ );
+ else
+ ckmakxmsg(tn_msg, TN_MSG_LEN,
+ AUTHTYPE_NAME(sb[i]),
+ "=",
+ ckitoa(sb[i]),
+ " ",
+ AUTHMODE_NAME(sb[i+1]),
+ "=",
+ ckitoa(sb[i+1]),
+ " ",
+ NULL,NULL,NULL,NULL
+ );
+ ckstrncat(hexbuf,tn_msg,sizeof(hexbuf));
+ }
+ s[1] = hexbuf;
+ break;
+
+ case TELOPT_ENCRYPTION:
+ s[0] = "SUPPORT";
+ while (i < n-2) {
+ s[i] = enctype_names[sb[i]];
+ i++;
+ }
+ break;
+
+ case TELOPT_START_TLS:
+ s[0] = "FOLLOWS";
+ break;
+ default:
+ s[0] = "SEND";
+ }
+ break;
+
+ case 2:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "CLOSE";
+ break;
+ case TELOPT_LFLOW:
+ s[0] = "RESTART-ANY";
+ break;
+ case TELOPT_KERMIT:
+ s[0] = "REQ-START";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "SET-DATASIZE";
+ break;
+ case TELOPT_NEWENVIRON:
+ s[0] = "INFO";
+ break;
+ case TELOPT_AUTHENTICATION:
+ s[0] = "REPLY";
+ i=4;
+ s[1] = AUTHTYPE_NAME(sb[1]);
+ s[2] = AUTHMODE_NAME(sb[2]);
+ switch (sb[3]) {
+ case 0:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_AUTH";
+ break;
+ default:
+ s[3] = "AUTH";
+ }
+ break;
+ case 1:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_CHALLENGE";
+ break;
+ default:
+ s[3] = "REJECT";
+ }
+ break;
+ case 2:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_RESPONSE";
+ break;
+ default:
+ s[3] = "ACCEPT";
+ }
+ break;
+ case 3:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_ACCEPT";
+ break;
+ case AUTHTYPE_KERBEROS_V4:
+ case AUTHTYPE_SRP:
+ s[3] = "CHALLENGE";
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ s[3] = "RESPONSE";
+ break;
+ }
+ break;
+ case 4:
+ switch (sb[1]) {
+ case AUTHTYPE_NTLM:
+ s[3] = "NTLM_REJECT";
+ break;
+ case AUTHTYPE_KERBEROS_V4:
+ case AUTHTYPE_SRP:
+ s[3] = "RESPONSE";
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ s[3] = "FORWARD";
+ break;
+ }
+ break;
+ case 5:
+ switch (sb[1]) {
+ case AUTHTYPE_SRP:
+ s[3] = "FORWARD";
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ s[3] = "FORWARD_ACCEPT";
+ break;
+ }
+ break;
+ case 6:
+ switch (sb[1]) {
+ case AUTHTYPE_SRP:
+ s[3] = "FORWARD_ACCEPT";
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ s[3] = "FORWARD_REJECT";
+ break;
+ }
+ break;
+ case 7:
+ switch (sb[1]) {
+ case AUTHTYPE_SRP:
+ s[3] = "FORWARD_REJECT";
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ s[3] = "TLS_VERIFY";
+ break;
+ }
+ break;
+ case 8:
+ switch (sb[1]) {
+ case AUTHTYPE_SRP:
+ s[3] = "EXP";
+ break;
+ }
+ break;
+ case 9:
+ switch (sb[1]) {
+ case AUTHTYPE_SRP:
+ s[3] = "PARAMS";
+ break;
+ }
+ break;
+ }
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "REPLY";
+ s[1] = enctype_names[sb[1]];
+ i++;
+ switch (sb[2]) {
+ case 1:
+ i++;
+ s[2] = "FB64_IV";
+ break;
+ case 2:
+ i++;
+ s[2] = "FB64_IV_OK";
+ break;
+ case 3:
+ i++;
+ s[2] = "FB64_IV_BAD";
+ break;
+ case 4:
+ i++;
+ s[2] = "FB64_CHALLENGE";
+ break;
+ case 5:
+ i++;
+ s[2] = "FB64_RESPONSE";
+ break;
+ }
+ break;
+ }
+ break;
+ case 3:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "DATA";
+ break;
+ case TELOPT_LFLOW:
+ s[0] = "RESTART-XON";
+ break;
+ case TELOPT_KERMIT:
+ s[0] = "REQ-STOP";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "SET-PARITY";
+ break;
+ case TELOPT_AUTHENTICATION:
+ s[0] = "NAME";
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "START";
+ break;
+ }
+ break;
+ case 4:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "OPTIONS";
+ break;
+ case TELOPT_KERMIT:
+ s[0] = "SOP";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "SET-STOPSIZE";
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "END";
+ break;
+ }
+ break;
+ case 5:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "OPTION_DATA";
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "REQUEST-START";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "SET-CONTROL";
+ break;
+ }
+ break;
+ case 6:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "XOFF";
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "REQUEST-END";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "NOTIFY-LINESTATE";
+ break;
+ }
+ break;
+ case 7:
+ switch (opt) {
+ case TELOPT_FORWARD_X:
+ s[0] = "XON";
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "ENC-KEYID";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "NOTIFY-MODEMSTATE";
+ break;
+ }
+ break;
+ case 8:
+ switch (opt) {
+ case TELOPT_KERMIT:
+ s[0] = "RESP-START";
+ break;
+ case TELOPT_ENCRYPTION:
+ s[0] = "DEC-KEYID";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "FLOWCONTROL-SUSPEND";
+ break;
+ }
+ break;
+ case 9:
+ switch (opt) {
+ case TELOPT_KERMIT:
+ s[0] = "RESP-STOP";
+ break;
+ case TELOPT_COMPORT:
+ s[0] = "FLOWCONTROL-RESUME";
+ break;
+ }
+ break;
+ case 10:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "SET-LINESTATE-MASK";
+ break;
+ }
+ break;
+ case 11:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "SET-MODEMSTATE-MASK";
+ break;
+ }
+ break;
+ case 12:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "PURGE-DATA";
+ break;
+ }
+ break;
+
+
+ case 100:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SIGNATURE";
+ break;
+ }
+ break;
+ case 101:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-BAUDRATE";
+ break;
+ }
+ break;
+ case 102:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-DATASIZE";
+ break;
+ }
+ break;
+ case 103:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-PARITY";
+ break;
+ }
+ break;
+ case 104:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-STOPSIZE";
+ break;
+ }
+ break;
+ case 105:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-CONTROL";
+ break;
+ }
+ break;
+ case 106:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_NOTIFY-LINESTATE";
+ break;
+ }
+ break;
+ case 107:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_NOTIFY-MODEMSTATE";
+ break;
+ }
+ break;
+ case 108:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_FLOWCONTROL-SUSPEND";
+ break;
+ }
+ break;
+ case 109:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_FLOWCONTROL-RESUME";
+ break;
+ }
+ break;
+ case 110:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-LINESTATE-MASK";
+ break;
+ }
+ break;
+ case 111:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_SET-MODEMSTATE-MASK";
+ break;
+ }
+ break;
+ case 112:
+ switch (opt) {
+ case TELOPT_COMPORT:
+ s[0] = "S_PURGE-DATA";
+ break;
+ }
+ break;
+ }
+ }
+#ifdef M_XENIX
+ {
+ int len, param, param_len;
+ ckmakmsg( tn_msg, TN_MSG_LEN,
+ "TELNET RCVD SB ",
+ TELOPT(opt)," ",NULL);
+ len = strlen(tn_msg);
+ for (param = 0; param <= 15; param++) {
+ param_len = strlen(s[param]);
+ if (param_len > 0) {
+ strcpy(&tn_msg[len], s[param]);
+ len += param_len;
+ tn_msg[len++] = ' ';
+ }
+ }
+ tn_msg[len] = '\0';
+ }
+#else /* M_XENIX */
+ ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD SB ",TELOPT(opt)," ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ {
+ int i;
+ for (i = 0; i < 16; i++) {
+ if (s[i][0]) {
+ ckstrncat(tn_msg,s[i],TN_MSG_LEN);
+ ckstrncat(tn_msg," ",TN_MSG_LEN);
+ }
+ }
+ }
+#endif /* M_XENIX */
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&sb[i],n-2-i);
+ if (flag == 2)
+ ckstrncat(tn_msg," SE",TN_MSG_LEN);
+ else if (flag == 3)
+ ckstrncat(tn_msg," IAC DONT",TN_MSG_LEN);
+ else
+ ckstrncat(tn_msg," IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses)
+ tn_debug(tn_msg);
+ }
+ debug(F111,"tn_sb","len",n);
+#endif /* DEBUG */
+ *len = n; /* return length */
+ return(1); /* success */
+}
+
+static char rows_buf[16] = { 0, 0 }; /* LINES Environment variable */
+static char cols_buf[16] = { 0, 0 }; /* COLUMNS Enviornment variable */
+static char term_buf[64] = { 0, 0 }; /* TERM Environment variable */
+
+#ifdef CK_CURSES
+#ifndef VMS
+#ifndef COHERENT
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* COHERENT */
+#else
+#ifdef __DECC
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* __DECC */
+#endif /* VMS */
+extern char * trmbuf; /* Real curses */
+#endif /* CK_CURSES */
+
+#ifdef CK_ENCRYPTION
+static int
+tn_no_encrypt()
+{
+ /* Prevent Encryption from being negotiated */
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+
+ /* Cancel any negotiation that might have started */
+ ck_tn_enc_stop();
+
+ if (TELOPT_ME(TELOPT_ENCRYPTION) ||
+ TELOPT_UNANSWERED_WILL(TELOPT_ENCRYPTION)) {
+ TELOPT_ME(TELOPT_ENCRYPTION) = 0;
+ if (tn_sopt(WONT,TELOPT_ENCRYPTION) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WONT(TELOPT_ENCRYPTION) = 1;
+ }
+ if (TELOPT_U(TELOPT_ENCRYPTION) ||
+ TELOPT_UNANSWERED_DO(TELOPT_ENCRYPTION)) {
+ TELOPT_U(TELOPT_ENCRYPTION) = 0;
+ if (tn_sopt(DONT,TELOPT_ENCRYPTION) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DONT(TELOPT_ENCRYPTION) = 1;
+ }
+ return(0);
+}
+#endif /* CK_ENCRYPTION */
+
+/* The following note came from the old SGA negotiation code. This should */
+/* no longer be necessary with the New Telnet negotiation state machine. */
+/*
+ Note: The following is proper behavior, and required for talking to the
+ Apertus interface to the NOTIS library system, e.g. at Iowa State U:
+ scholar.iastate.edu. Without this reply, the server hangs forever. This
+ code should not be loop-inducing, since C-Kermit never sends WILL SGA as
+ an initial bid, so if DO SGA comes, it is never an ACK.
+*/
+/*
+ Return values:
+ -1 = Telnet Option negotiation error
+ -2 = Connection closed by peer
+ -3 = Connection closed by us
+ 0 = Success
+ 1 = Echoing on
+ 2 = Echoing off
+ 3 = Quoted IAC
+ 4 = IKS Event
+ 5 = (unassigned)
+ 6 = Logout
+*/
+
+static int
+#ifdef CK_ANSIC /* TELNET DO OPTION */
+tn_xdoop(CHAR z, int echo, int (*fn)(int))
+#else
+tn_xdoop(z, echo, fn) CHAR z; int echo; int (*fn)();
+#endif /* CK_ANSIC */
+/* tn_xdoop */ {
+ int c, x, y, n, m;
+#ifdef IKS_OPTION
+ extern int server;
+#ifdef NOICP
+ extern int autodl;
+ int inautodl = 0, cmdadl = 1;
+#else
+#ifdef CK_AUTODL
+ extern int autodl, inautodl, cmdadl;
+#endif /* CK_AUTODL */
+#endif /* NOICP */
+#endif /* IKS_OPTION */
+
+ /* if (!IS_TELNET()) return(7); */
+
+/* Have IAC, read command character. */
+
+ while ((c = (*fn)(0)) == -1); /* Read command character */
+ if (c < 0)
+ return(c);
+ c &= 0xFF; /* Strip high bits */
+
+ if (!TELCMD_OK(c)) {
+#ifdef DEBUG
+ if (tn_deb || debses || deblog) {
+ ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD UNKNOWN (",
+ ckitoa(c),")",NULL);
+ debug(F101,tn_msg,"",c);
+ if (tn_deb || debses)
+ tn_debug(tn_msg);
+ }
+#endif /* DEBUG */
+ return(0);
+ }
+ if (ttnproto == NP_NONE) {
+ debug(F100,"tn_doop discovered a Telnet command",
+ "ttnproto = NP_TELNET",0);
+ ttnproto = NP_TELNET;
+ }
+ if (seslog && sessft == XYFT_D) { /* Copy to session log, if any. */
+ logchar((char)z);
+ logchar((char)c);
+ }
+
+ if (c == (CHAR) IAC) /* Quoted IAC */
+ return(3);
+
+ if (c < SB) { /* Other command with no arguments. */
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD ",TELCMD(c),NULL,NULL);
+ debug(F101,tn_msg,"",c);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#endif /* DEBUG */
+ switch (c) { /* What we would like to do here */
+ case TN_GA: /* Is substitute ASCII characters */
+ break; /* for the Telnet Command so that */
+ case TN_EL: /* the command may be processed by */
+ break; /* either the internal emulator or */
+ case TN_EC: /* by the superior process or shell */
+ break;
+ case TN_AYT:
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)"[Yes]\015\012",7);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+ case TN_AO:
+#ifdef BETADEBUG
+ bleep(BP_NOTE);
+#endif /* BETADEBUG */
+ break;
+ case TN_IP:
+ break;
+ case BREAK:
+ break;
+ case TN_DM:
+ break;
+ case TN_NOP:
+ break;
+ case SE:
+ break;
+ case TN_EOR:
+ break;
+ case TN_ABORT:
+ break;
+ case TN_SUSP:
+ break;
+ case TN_EOF:
+ break;
+ case TN_SAK:
+ break;
+ }
+ return(0);
+ }
+
+/* SB, WILL, WONT, DO, or DONT need more bytes... */
+
+ if ((x = (*fn)(0)) < 0) /* Get the option. */
+ return(x);
+ x &= 0xff; /* Trim to 8 bits. */
+
+ if (seslog && sessft == XYFT_D) { /* Session log */
+ logchar((char) x);
+ }
+#ifdef DEBUG
+ if ((deblog || tn_deb || debses) && c != SB) {
+ ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD ",TELCMD(c)," ",TELOPT(x));
+ debug(F101,tn_msg,"",x);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#endif /* DEBUG */
+ /* Now handle the command */
+ switch (c) {
+ case WILL:
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return(0);
+#endif /* CK_SSL */
+#ifdef CK_FORWARD_X
+ if (x == TELOPT_FORWARD_X) {
+ if (!fwdx_server_avail() || !(fwdx_no_encrypt ||
+#ifdef CK_SSL
+ (ssl_active_flag || tls_active_flag)
+#else /* CK_SSL */
+ 0
+#endif /* CK_SSL */
+ ||
+#ifdef CK_ENCRYPTION
+ (ck_tn_encrypting() && ck_tn_decrypting())
+#else /* CK_ENCRYPTION */
+ 0
+#endif /* CK_ENCRYPTION */
+ )) {
+ TELOPT_U_MODE(TELOPT_FORWARD_X) = TN_NG_RF;
+ TELOPT_ME_MODE(TELOPT_FORWARD_X) = TN_NG_RF;
+ }
+ }
+#endif /* CK_FORWARD_X */
+ if (!TELOPT_OK(x) || TELOPT_U_MODE(x) == TN_NG_RF) {
+ if (tn_sopt(DONT,x) < 0)
+ return(-1);
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ } else if (!TELOPT_U(x)) {
+ if (!TELOPT_UNANSWERED_DO(x)) {
+ if (tn_sopt(DO,x) < 0)
+ return -1;
+ }
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ TELOPT_U(x) = 1;
+
+ switch (x) {
+#ifdef CK_SSL
+ case TELOPT_START_TLS:
+ /*
+ If my proposal is accepted, at this point the Telnet
+ protocol is turned off and a TLS negotiation takes
+ place.
+
+ Start by sending SB START_TLS FOLLOWS to signal
+ we are ready. Wait for the peer to send the same
+ and then start the TLS negotiation.
+
+ If the TLS negotiation succeeds we call tn_ini()
+ again to reset the telnet state machine and restart
+ the negotiation process over the now secure link.
+
+ If the TLS negotiation fails, we call ttclos()
+ to terminate the connection.
+
+ Only the server should receive a WILL START_TLS
+ */
+ tn_ssbopt(TELOPT_START_TLS,1,NULL,0);
+ TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 1;
+ break;
+#endif /* CK_SSL */
+
+#ifdef CK_AUTHENTICATION
+ case TELOPT_AUTHENTICATION: {
+ /* We now have to perform a SB SEND to identify the */
+ /* supported authentication types to the other side. */
+ extern int authentication_version;
+
+#ifdef CK_SSL
+ /* if we have an outstanding DO START_TLS then we must
+ * wait for the response before we determine what to do
+ */
+ if (TELOPT_UNANSWERED_DO(TELOPT_START_TLS)) {
+ TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 1;
+ break;
+ }
+#endif /* CK_SSL */
+ authentication_version = AUTHTYPE_AUTO;
+ ck_tn_auth_request();
+ break;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ case TELOPT_ENCRYPTION:
+ if (!(TELOPT_ME(TELOPT_AUTHENTICATION) ||
+ TELOPT_U(TELOPT_AUTHENTICATION))
+ ) {
+ if (tn_sopt(DONT,x) < 0)
+ return(-1);
+ TELOPT_U(x) = 0;
+ } else {
+ if (ck_tn_auth_in_progress()) {
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 1;
+ } else {
+ /* Perform subnegotiation */
+ ck_encrypt_send_support();
+ }
+ if (!(TELOPT_ME(x) || TELOPT_UNANSWERED_WILL(x))
+ && TELOPT_ME_MODE(x) != TN_NG_RF) {
+ if (tn_sopt(WILL, x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(x) = 1;
+ }
+ }
+ break;
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ case TELOPT_KERMIT:
+ if (!TELOPT_ME(x)) {
+ /* Tell the other side what Start of Packet Character */
+ tn_siks(KERMIT_SOP); /* SOP */
+
+ if (!TELOPT_UNANSWERED_WILL(x) &&
+ TELOPT_ME_MODE(x) != TN_NG_RF) {
+ if (tn_sopt(WILL, x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(x) = 1;
+ }
+ }
+ break;
+#endif /* IKS_OPTION */
+ case TELOPT_BINARY:
+ if (!TELOPT_ME(x)) {
+ if (!TELOPT_UNANSWERED_WILL(x) &&
+ TELOPT_ME_MODE(x) >= TN_NG_RQ) {
+ if (tn_sopt(WILL, x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WILL(x) = 1;
+ }
+ }
+ break;
+ case TELOPT_ECHO:
+ if (echo) {
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ return(2);
+ }
+ break;
+ case TELOPT_TTYPE:
+ /* SB TTYPE SEND */
+ tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0);
+ TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1;
+ break;
+#ifdef CK_ENVIRONMENT
+ case TELOPT_NEWENVIRON: /* SB NEW-ENVIRON SEND */
+ {
+ char request[6]; /* request it */
+ sprintf(request,"%cUSER",TEL_ENV_VAR); /* safe */
+ tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_SEND,request,
+ strlen(request));
+ TELOPT_UNANSWERED_SB(TELOPT_NEWENVIRON)=1;
+ }
+ break;
+#endif /* CK_ENVIRONMENT */
+ } /* switch */
+ } else {
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ }
+ break;
+ case WONT:
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return(0);
+#endif /* CK_SSL */
+ if (TELOPT_U(x) || TELOPT_UNANSWERED_DO(x)) {
+ /* David Borman says we should not respond DONT when
+ * the WONT is a response to a DO that we sent.
+ * Nor should we send one if the state is already WONT
+ * such as when we do not recognize the option since
+ * options are initialized in the WONT/DONT state.
+ */
+ if (!(TELOPT_UNANSWERED_DO(x) || TELOPT_UNANSWERED_DONT(x)))
+ if (tn_sopt(DONT,x) < 0)
+ return(-1);
+ if (TELOPT_UNANSWERED_DONT(x))
+ TELOPT_UNANSWERED_DONT(x) = 0;
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ if (TELOPT_U(x)) {
+ TELOPT_U(x) = 0;
+ }
+ switch(x) {
+#ifdef CK_SSL
+ case TELOPT_START_TLS:
+ if (sstelnet) {
+ if (TELOPT_U_MODE(x) == TN_NG_MU) {
+ printf("Telnet Start-TLS refused.\n");
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ }
+ if (TELOPT_SB(x).start_tls.auth_request) {
+ extern int authentication_version;
+ TELOPT_SB(x).start_tls.auth_request = 0;
+ authentication_version = AUTHTYPE_AUTO;
+ ck_tn_auth_request();
+ }
+ }
+ break;
+#endif /* CK_SSL */
+#ifdef CK_AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (sstelnet && TELOPT_U_MODE(x) == TN_NG_MU) {
+ printf("Telnet authentication refused.\n");
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ } else if (TELOPT_U_MODE(x) == TN_NG_RQ) {
+ TELOPT_U_MODE(x) = TN_NG_AC;
+ }
+ if (ck_tn_auth_in_progress())
+ printf("Telnet authentication refused.\n");
+#ifdef CK_ENCRYPTION
+ if (sstelnet) {
+ if (tn_no_encrypt()<0)
+ return(-1);
+ }
+#endif /* CK_ENCRYPTION */
+ break;
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ case TELOPT_ENCRYPTION:
+ ck_tn_enc_stop();
+ break;
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ case TELOPT_KERMIT:
+ TELOPT_SB(x).kermit.u_start = 0;
+ TELOPT_SB(x).kermit.me_req_start = 0;
+ TELOPT_SB(x).kermit.me_req_stop = 0;
+ break;
+#endif /* IKS_OPTION */
+ case TELOPT_NAWS: {
+ /* The client does not support NAWS. */
+ /* Assume a height of 24 and a width of 80 */
+ if (sstelnet
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) {
+ int w = 80, h = 24;
+#ifndef NOLOCAL
+ if (tcp_incoming) {
+#ifdef OS2
+ tt_cols[VTERM] = w;
+ tt_rows[VTERM] = h;
+ VscrnSetWidth(VTERM, w);
+ VscrnSetHeight(VTERM, h+(tt_status[VTERM]?1:0));
+#else /* OS2 */
+ tt_cols = w;
+ tt_rows = h;
+#endif /* OS2 */
+ } else {
+#ifdef OS2
+ tt_cols[VCMD] = w;
+ tt_rows[VCMD] = h;
+ VscrnSetWidth(VCMD, w);
+ VscrnSetHeight(VCMD, h);
+#endif /* OS2 */
+ cmd_cols = w;
+ cmd_rows = h;
+ }
+#else /* NOLOCAL */
+ cmd_cols = w;
+ cmd_rows = h;
+#endif /* NOLOCAL */
+ /* Add LINES and COLUMNS to the environment */
+ ckmakmsg((char *)rows_buf,16,"LINES=",ckitoa(h),
+ NULL,NULL);
+ ckmakmsg((char *)cols_buf,16,"COLUMNS=",ckitoa(w),
+ NULL,NULL);
+#ifdef OS2ORUNIX
+#ifndef NOPUTENV
+ putenv(rows_buf);
+ putenv(cols_buf);
+#endif /* NOPUTENV */
+#endif /* OS2ORUNIX */
+ }
+ break;
+ }
+ case TELOPT_ECHO:
+ if (!echo) {
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ return(1);
+ }
+ break;
+ }
+ } else {
+ if (TELOPT_UNANSWERED_DONT(x))
+ TELOPT_UNANSWERED_DONT(x) = 0;
+ if (TELOPT_UNANSWERED_DO(x))
+ TELOPT_UNANSWERED_DO(x) = 0;
+ }
+ if (TELOPT_U_MODE(x) == TN_NG_MU) {
+ ckmakmsg( tn_msg,TN_MSG_LEN,
+ "Peer refuses TELNET DO ",TELOPT(x),
+ " negotiations - terminating connection",NULL
+ );
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ printf("%s\n",tn_msg);
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ }
+#ifdef COMMENT
+ if (x == TELOPT_ECHO && !echo) /* Special handling for echo */
+ return(1); /* because we allow 'duplex' */
+#endif /* COMMENT */
+ break;
+
+ case DO:
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return(0);
+#endif /* CK_SSL */
+ if (!TELOPT_OK(x) || TELOPT_ME_MODE(x) == TN_NG_RF) {
+ if (tn_sopt(WONT,x) < 0)
+ return(-1);
+ if (TELOPT_UNANSWERED_WILL(x))
+ TELOPT_UNANSWERED_WILL(x) = 0;
+ } else if (!TELOPT_ME(x)) {
+ if (!TELOPT_UNANSWERED_WILL(x)) {
+ if (tn_sopt(WILL,x) < 0)
+ return(-1);
+ }
+ if (TELOPT_UNANSWERED_WILL(x))
+ TELOPT_UNANSWERED_WILL(x) = 0;
+ TELOPT_ME(x) = 1;
+
+ switch (x) {
+#ifdef CK_SSL
+ case TELOPT_START_TLS:
+ /*
+ If my proposal is accepted at this point the Telnet
+ protocol is turned off and a TLS negotiation takes
+ place.
+
+ Start by sending SB START_TLS FOLLOWS to signal
+ we are ready. Wait for the peer to send the same
+ and then start the TLS negotiation.
+
+ If the TLS negotiation succeeds we call tn_ini()
+ again to reset the telnet state machine and restart
+ the negotiation process over the now secure link.
+
+ If the TLS negotiation fails, we call ttclos()
+ to terminate the connection. Then we set the
+ U_MODE and ME_MODE for TELOPT_START_TLS to REFUSE
+ and then call ttopen() to create a new connection
+ to the same host but this time do not attempt
+ TLS security.
+
+ Only the client should receive DO START_TLS.
+ */
+ tn_ssbopt(TELOPT_START_TLS,1,NULL,0);
+ TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 1;
+ break;
+#endif /* CK_SSL */
+
+#ifdef CK_AUTHENTICATION
+ case TELOPT_AUTHENTICATION: {
+ /* We don't know what authentication we are using yet */
+ /* but it is not NULL until a failure is detected so */
+ /* use AUTO in the meantime. */
+ extern int authentication_version;
+ authentication_version = AUTHTYPE_AUTO;
+ break;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ case TELOPT_ENCRYPTION:
+ if (!(TELOPT_ME(TELOPT_AUTHENTICATION) ||
+ TELOPT_U(TELOPT_AUTHENTICATION))
+ ) {
+ if (tn_sopt(WONT,x) < 0)
+ return(-1);
+ TELOPT_ME(x) = 0;
+ } else {
+ if (!(TELOPT_U(x) || TELOPT_UNANSWERED_DO(x))
+ && TELOPT_U_MODE(x) != TN_NG_RF) {
+ if (tn_sopt(DO, x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(x) = 1;
+ }
+ }
+ break;
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ case TELOPT_KERMIT:
+/* If currently processing Kermit server packets, must tell the other side */
+
+ debug(F111,"tn_doop","what",what);
+ debug(F111,"tn_doop","server",server);
+#ifdef CK_AUTODL
+ debug(F111,"tn_doop","autodl",autodl);
+ debug(F111,"tn_doop","inautodl",inautodl);
+ debug(F111,"tn_doop","cmdadl",cmdadl);
+#endif /* CK_AUTODL */
+
+ if (server
+#ifdef CK_AUTODL
+ || (local && ((what == W_CONNECT && autodl) ||
+ (what != W_CONNECT && inautodl)))
+ || (!local && cmdadl)
+#endif /* CK_AUTODL */
+ ) {
+ tn_siks(KERMIT_START); /* START */
+ }
+ if (!TELOPT_U(x)) {
+ /* Tell the other side what Start of Packet Character */
+ tn_siks(KERMIT_SOP); /* SOP */
+ if (!TELOPT_UNANSWERED_DO(x) &&
+ TELOPT_U_MODE(x) != TN_NG_RF) {
+ if (tn_sopt(DO, x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(x) = 1;
+ }
+ }
+ break;
+#endif /* IKS_OPTION */
+
+ case TELOPT_BINARY:
+ if (!TELOPT_U(x)) {
+ if (!TELOPT_UNANSWERED_DO(x) &&
+ TELOPT_U_MODE(x) >= TN_NG_RQ) {
+ if (tn_sopt(DO, x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DO(x) = 1;
+ }
+ }
+ break;
+ case TELOPT_NAWS:
+#ifdef CK_NAWS
+ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
+ if (tn_snaws() < 0)
+ return(-1);
+ } else {
+ TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 1;
+ }
+#endif /* CK_NAWS */
+ break;
+ case TELOPT_LOGOUT:
+ ttclos(0); /* And then hangup */
+ whyclosed = WC_TELOPT;
+ return(6);
+#ifdef CK_SNDLOC
+ case TELOPT_SNDLOC:
+ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
+ if (tn_sndloc() < 0)
+ return(-1);
+ } else {
+ TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 1;
+ }
+ break;
+#endif /* CK_SNDLOC */
+#ifdef CK_FORWARD_X
+ case TELOPT_FORWARD_X:
+ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
+ if (fwdx_send_options() < 0) {
+ if (tn_sopt(DONT,x) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_DONT(x) = 1;
+ }
+ } else {
+ TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 1;
+ }
+ break;
+#endif /* CK_FORWARD_X */
+#ifdef TN_COMPORT
+ case TELOPT_COMPORT: {
+ extern int reliable;
+ if (!tn_delay_sb || !tn_outst(0) || tn_init) {
+ if (tn_sndcomport() < 0)
+ return(-1);
+ } else {
+ TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 1;
+ }
+ /* Telnet -> Serial -> ??? is not a reliable connection. */
+ reliable = SET_OFF;
+ break;
+ }
+#endif /* TN_COMPORT */
+ } /* switch */
+ } else {
+ if (TELOPT_UNANSWERED_WILL(x))
+ TELOPT_UNANSWERED_WILL(x) = 0;
+ }
+ break;
+
+ case DONT:
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return(0);
+#endif /* CK_SSL */
+ if (TELOPT_ME(x) || TELOPT_UNANSWERED_WILL(x)) {
+ /* David Borman says we should not respond WONT when
+ * the DONT is a response to a WILL that we sent.
+ * Nor should we send one if the state is already WONT
+ * such as when we do not recognize the option since
+ * options are initialized in the WONT/DONT state.
+ */
+ if (!(TELOPT_UNANSWERED_WILL(x) || TELOPT_UNANSWERED_WONT(x)))
+ if (tn_sopt(WONT,x) < 0)
+ return(-1);
+
+ if (TELOPT_UNANSWERED_WILL(x))
+ TELOPT_UNANSWERED_WILL(x) = 0;
+ if (TELOPT_UNANSWERED_WONT(x))
+ TELOPT_UNANSWERED_WONT(x) = 0;
+ if (TELOPT_ME(x))
+ TELOPT_ME(x) = 0;
+
+ switch (x) {
+#ifdef CK_SSL
+ case TELOPT_START_TLS:
+ if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) {
+ printf("Telnet Start-TLS refused.\n");
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ }
+ break;
+#endif /* CK_SSL */
+#ifdef CK_AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) {
+#ifdef CK_SSL
+ if (tls_active_flag) {
+ TELOPT_ME_MODE(x) = TN_NG_AC;
+ break;
+ } else
+#endif /* CK_SSL */
+ {
+ printf("Telnet authentication refused.\n");
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ }
+ } else if (TELOPT_ME_MODE(x) == TN_NG_RQ) {
+ TELOPT_ME_MODE(x) = TN_NG_AC;
+ }
+ if (ck_tn_auth_in_progress())
+ printf("Telnet authentication refused.\n");
+#ifdef CK_ENCRYPTION
+ if (!sstelnet) {
+ if (tn_no_encrypt()<0)
+ return(-1);
+ }
+#endif /* CK_ENCRYPTION */
+ break;
+#endif /* CK_AUTHENTICATION */
+ case TELOPT_ENCRYPTION:
+#ifdef CK_ENCRYPTION
+ ck_tn_enc_stop();
+#endif /* CK_ENCRYPTION */
+ break;
+ case TELOPT_KERMIT:
+#ifdef IKS_OPTION
+ TELOPT_SB(x).kermit.me_start = 0;
+#endif /* IKS_OPTION */
+ break;
+ default:
+ break;
+ } /* switch */
+ } else {
+ if (TELOPT_UNANSWERED_WILL(x))
+ TELOPT_UNANSWERED_WILL(x) = 0;
+ if (TELOPT_UNANSWERED_WONT(x))
+ TELOPT_UNANSWERED_WONT(x) = 0;
+ }
+ if (TELOPT_ME_MODE(x) == TN_NG_MU) {
+ ckmakmsg( tn_msg,TN_MSG_LEN,
+ "Peer refuses TELNET WILL ",TELOPT(x),
+ " negotiations - terminating connection",
+ NULL
+ );
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ printf("%s\n",tn_msg);
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ }
+ break;
+ case SB:
+ if ((y = tn_sb(x,&n,fn)) <= 0)
+ return(y);
+
+#ifdef CK_SSL
+ /* Do not process subnegotiations other than START_TLS after we */
+ /* have agreed to begin the TLS negotiation sequence. */
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows &&
+ x != TELOPT_START_TLS)
+ break;
+#endif /* CK_SSL */
+
+ if (!TELOPT_OK(x)) {
+ ckhexdump("unknown telnet subnegotiation",sb,n);
+ break;
+ } else if ( !(TELOPT_ME(x) || TELOPT_U(x)) ) {
+ ckhexdump("telnet option not negotiated",sb,n);
+ if (!tn_sb_bug)
+ break;
+ if (TELOPT_UNANSWERED_WILL(x)) {
+ TELOPT_UNANSWERED_WILL(x) = 0;
+ TELOPT_U(x) = 1;
+ ckmakmsg(tn_msg,TN_MSG_LEN,
+ "TELNET DO ",TELOPT(x),
+ "(implied by receipt of SB - protocol error ignored)",
+ NULL
+ );
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+ if (TELOPT_UNANSWERED_DO(x)) {
+ TELOPT_UNANSWERED_DO(x) = 0;
+ TELOPT_ME(x) = 1;
+ ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET WILL ",TELOPT(x),
+ " (implied by receipt of SB - protocol error ignored)",
+ NULL);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+ }
+
+ TELOPT_UNANSWERED_SB(x)=0;
+ switch (x) {
+#ifdef CK_FORWARD_X
+ case TELOPT_FORWARD_X:
+ return(fwdx_tn_sb(sb, n));
+#endif /* CK_FORWARD_X */
+#ifdef CK_SSL
+ case TELOPT_START_TLS: {
+ /*
+ the other side is saying SB START_TLS FOLLOWS
+ the incoming channel is now ready for starting the
+ TLS negotiation.
+ */
+ int def_tls_u_mode, def_tls_me_mode;
+ int def_enc_u_mode, def_enc_me_mode;
+ int rc = 0;
+
+ if (sb[0] != 1) {
+ break;
+ }
+
+ TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 1;
+ /* Preserve the default modes and make sure we will */
+ /* refuse START_TLS when we retry. */
+ if (sstelnet) {
+ def_tls_u_mode = TELOPT_DEF_S_U_MODE(TELOPT_START_TLS);
+ def_tls_me_mode = TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS);
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS)= TN_NG_RF;
+#ifdef CK_ENCRYPTION
+ def_enc_u_mode = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION);
+ def_enc_me_mode = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION);
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION)= TN_NG_RF;
+#endif /* CK_ENCRYPTION */
+ } else {
+ def_tls_u_mode = TELOPT_DEF_C_U_MODE(TELOPT_START_TLS);
+ def_tls_me_mode = TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS);
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS)= TN_NG_RF;
+#ifdef CK_ENCRYPTION
+ def_enc_u_mode = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION);
+ def_enc_me_mode = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION);
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION)= TN_NG_RF;
+#endif /* CK_ENCRYPTION */
+ }
+ /* Negotiate TLS */
+ ttnproto = NP_TLS;
+ tn_init = 0;
+ tn_begun = 0;
+ if (ck_tn_tls_negotiate()<0) {
+ /* we failed. disconnect and if we are the client */
+ /* then reconnect and try without START_TLS. */
+ extern char * line;
+ int x = -1;
+ extern int mdmtyp;
+
+ if (sstelnet) {
+ printf("TLS failed: Disconnecting.\n");
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = def_tls_u_mode;
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode;
+#ifdef CK_ENCRYPTION
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
+#endif /* CK_ENCRYPTION */
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ ttnproto = NP_TELNET;
+ rc = -3;
+ } else {
+#ifndef NOLOCAL
+ extern int tls_norestore;
+#endif /* NOLOCAL */
+ printf("TLS failed: Disconnecting...\n");
+#ifdef CK_ENCRYPTION
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
+#endif /* CK_ENCRYPTION */
+ /* if START_TLS is not REQUIRED, then retry without it */
+ if ( def_tls_me_mode != TN_NG_MU ) {
+ extern char ttname[];
+#ifndef NOLOCAL
+ tls_norestore = 1;
+#endif /* NOLOCAL */
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+#ifndef NOLOCAL
+ tls_norestore = 0;
+#endif /* NOLOCAL */
+ ttnproto = NP_TELNET;
+ printf("Reconnecting without TLS.\n");
+ sleep(2);
+ if (ttopen(ttname,&x,mdmtyp,0)<0)
+ rc = -3;
+ } else {
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) =
+ def_tls_u_mode;
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) =
+ def_tls_me_mode;
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ ttnproto = NP_TELNET;
+ rc = -3;
+ }
+ }
+ } else {
+#ifdef CK_AUTHENTICATION
+ /* we succeeded. restart telnet negotiations from */
+ /* the beginning. However, if we have received a */
+ /* client certificate and we are a server, then do */
+ /* not offer TELOPT_AUTH. */
+ if ( ck_tn_auth_valid() == AUTH_VALID ) {
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_AC;
+ TELOPT_DEF_S_ME_MODE(TELOPT_AUTHENTICATION)= TN_NG_AC;
+ }
+#endif /* CK_AUTHENTICATION */
+ ttnproto = NP_TELNET;
+ if (tn_ini() < 0)
+ if (ttchk() < 0)
+ rc = -1;
+ }
+ /* Restore the default modes */
+ if (sstelnet) {
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = def_tls_u_mode;
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode;
+#ifdef CK_ENCRYPTION
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
+#endif /* CK_ENCRYPTION */
+ } else {
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = def_tls_u_mode;
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode;
+#ifdef CK_ENCRYPTION
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
+#endif /* CK_ENCRYPTION */
+ }
+ return(rc);
+ }
+#endif /* CK_SSL */
+#ifdef CK_AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (ck_tn_sb_auth((char *)sb,n) < 0) {
+ if (sstelnet && TELOPT_U_MODE(x) == TN_NG_MU) {
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ } else if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) {
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ } else {
+ if (TELOPT_ME_MODE(x) == TN_NG_RQ)
+ TELOPT_ME_MODE(x) = TN_NG_AC;
+ if (TELOPT_U_MODE(x) == TN_NG_RQ)
+ TELOPT_U_MODE(x) = TN_NG_AC;
+ }
+ if (TELOPT_ME(x)) {
+ TELOPT_ME(x) = 0;
+ if (tn_sopt(WONT,x) < 0)
+ return(-1);
+ }
+ if (TELOPT_U(x)) {
+ TELOPT_U(x) = 0;
+ if (tn_sopt(DONT,x) < 0)
+ return(-1);
+ }
+#ifdef CK_ENCRYPTION
+ if (tn_no_encrypt()<0)
+ return(-1);
+#endif /* CK_ENCRYPTION */
+ } else {
+#ifdef CK_ENCRYPTION
+ if (!ck_tn_auth_in_progress()) { /* we are finished */
+ if (ck_tn_authenticated() == AUTHTYPE_SSL) {
+ /* TLS was successful. Disable ENCRYPTION */
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+ if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send) {
+ ck_encrypt_send_support();
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0;
+ }
+ }
+#endif /* CK_ENCRYPTION */
+ }
+ break;
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ case TELOPT_ENCRYPTION:
+ if (ck_tn_sb_encrypt((char *)sb, n) < 0) {
+ if (TELOPT_U_MODE(x) == TN_NG_MU ||
+ TELOPT_ME_MODE(x) == TN_NG_MU)
+ {
+ ttclos(0);
+ whyclosed = WC_TELOPT;
+ return(-3);
+ } else {
+ if (TELOPT_ME_MODE(x) == TN_NG_RQ)
+ TELOPT_ME_MODE(x) = TN_NG_AC;
+ if (TELOPT_U_MODE(x) == TN_NG_RQ)
+ TELOPT_U_MODE(x) = TN_NG_AC;
+ }
+ if (TELOPT_ME(x)) {
+ TELOPT_ME(x) = 0;
+ if (tn_sopt(WONT,x) < 0)
+ return(-1);
+ }
+ if (TELOPT_U(x)) {
+ TELOPT_U(x) = 0;
+ if (tn_sopt(DONT,x) < 0)
+ return(-1);
+ }
+ }
+ break;
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ case TELOPT_KERMIT:
+ return(iks_tn_sb(sb, n-2));
+#endif /* IKS_OPTION */
+#ifdef TN_COMPORT
+ case TELOPT_COMPORT:
+ return(tnc_tn_sb(sb, n-2));
+#endif /* TN_COMPORT */
+ case TELOPT_TTYPE:
+ switch (sb[0]) {
+ case TELQUAL_SEND: /* SEND terminal type? */
+ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
+ if (tn_sttyp() < 0) /* Yes, so send it. */
+ return(-1);
+ } else {
+ TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 1;
+ }
+ break;
+ case TELQUAL_IS: { /* IS terminal type? */
+ /* IS terminal type -- remote gave us its current type */
+ int i = 0;
+#ifndef OS2
+ CHAR oldterm[64], *p;
+#endif /* OS2 */
+ /* Isolate the specified terminal type string */
+ while (sb[i++] != IAC) {
+ if (i == 40 || /* max len of term string - RFC */
+ sb[i] == IAC) {
+ sb[i] = '\0';
+ break;
+ }
+ }
+#ifdef OS2
+#ifndef NOTERM
+ strupr(&(sb[1])); /* Upper case it */
+ for (i = 0; i <= max_tt; i++) { /* find it in our list */
+ if (!strcmp(&(sb[1]),tt_info[i].x_name)
+ && i != TT_VTNT) /* can't support VTNT as server */
+ {
+ /* Set terminal type to the one chosen */
+ if (i != tt_type)
+ settermtype(i,0);
+ break;
+ }
+ }
+ if (i > max_tt &&
+ strcmp(&(sb[1]),TELOPT_SB(TELOPT_TTYPE).term.type)) {
+ /* Couldn't find the specified term type */
+ sb[40] = '\0';
+ strcpy(TELOPT_SB(TELOPT_TTYPE).term.type,&(sb[1]));
+ /* SB TTYPE SEND */
+ tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0);
+ TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1;
+ }
+#endif /* NOTERM */
+#else /* OS2 */
+ p = (CHAR *) getenv("TERM");
+ if (p)
+ ckstrncpy((char *)oldterm,(char *)p,63);
+ else
+ oldterm[0] = '\0';
+ cklower((char *)&(sb[1])); /* Lower case new term */
+ ckmakmsg(term_buf,64,"TERM=",(char *)&(sb[1]),NULL,NULL);
+#ifdef OS2ORUNIX
+#ifndef NOPUTENV
+ putenv(term_buf);
+#endif /* NOPUTENV */
+#endif /* OS2ORUNIX */
+#ifdef CK_CURSES
+#ifndef MYCURSES
+#ifndef COHERENT
+ if (trmbuf) {
+ if (tgetent(trmbuf,(char *)&sb[1]) < 1) {
+ /* Unsupported terminal. If new and old terminal */
+ /* types do not match, ask for another type. */
+ if (strcmp((char *)oldterm,(char *)&sb[1])) {
+ /* SB TTYPE SEND */
+ tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0);
+ TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1;
+ }
+ }
+ }
+#endif /* COHERENT */
+#endif /* MYCURSES */
+#endif /* CK_CURSES */
+#endif /* OS2 */
+ }
+ }
+ break;
+#ifdef CK_ENVIRONMENT
+#ifdef CK_XDISPLOC
+ case TELOPT_XDISPLOC: /* Send X-Display Location */
+ if (sb[0] == TELQUAL_SEND) {/* SEND X-Display Loc? */
+ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
+ if (tn_sxdisploc() < 0) /* Yes, so send it. */
+ return(-1);
+ } else {
+ TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 1;
+ }
+ }
+ /* IS -- X Display Location (not supported) */
+ else if (sb[0] == TELQUAL_IS) {
+ int i = 0;
+ /* Isolate the specified X-display string */
+ while (sb[i++] != IAC) {
+ if (i >= TSBUFSIZ)
+ return (-1);
+ if (sb[i] == IAC) {
+ sb[i] = '\0';
+ break;
+ }
+ }
+ debug(F110,"TELNET SB XDISPLOC IS",&sb[1],0);
+ }
+ break;
+#endif /* CK_XDISPLOC */
+#endif /* CK_ENVIRONMENT */
+ case TELOPT_NAWS:
+ if (sstelnet
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) {
+ int w = 0, h = 0;
+ int i = 0;
+ /* At this point sb[] should contain width and height */
+ if (sb[i] == IAC) i++;
+ w = (sb[i++] << 8); /* save upper height */
+ if (sb[i] == IAC) i++;
+ w += sb[i++]; /* save the width */
+ if (sb[i] == IAC) i++;
+ h = (sb[i++] << 8); /* save upper height */
+ if (sb[i] == IAC) i++;
+ h += sb[i++];
+ debug(F111,"tn_doop NAWS SB","width",w);
+ debug(F111,"tn_doop NAWS SB","height",h);
+
+ if (w == 0)
+ w = 80;
+ if (h == 0)
+ h = 24;
+#ifndef NOLOCAL
+ if (tcp_incoming || inserver) {
+#ifdef OS2
+ tt_cols[VTERM] = w;
+ tt_rows[VTERM] = h;
+ VscrnSetWidth(VTERM, w);
+ VscrnSetHeight(VTERM, h+(tt_status[VTERM]?1:0));
+#ifdef IKSD
+ if (inserver) {
+ cmd_cols = tt_cols[VCMD] = w;
+ cmd_rows = tt_rows[VCMD] = h;
+ VscrnSetWidth(VCMD, w);
+ VscrnSetHeight(VCMD, h);
+ }
+#endif /* IKSD */
+#else /* OS2 */
+ tt_cols = w;
+ tt_rows = h;
+#endif /* OS2 */
+ } else {
+#ifdef OS2
+ tt_cols[VCMD] = w;
+ tt_rows[VCMD] = h;
+ VscrnSetWidth(VCMD, w);
+ VscrnSetHeight(VCMD, h);
+#endif /* OS2 */
+ cmd_cols = w;
+ cmd_rows = h;
+ }
+#else /* NOLOCAL */
+ cmd_cols = w;
+ cmd_rows = h;
+#endif /* NOLOCAL */
+
+ /* Add LINES and COLUMNS to the environment */
+ ckmakmsg((char *)rows_buf,16,"LINES=",ckitoa(h),NULL,NULL);
+ ckmakmsg((char *)cols_buf,16,"COLUMNS=",ckitoa(w),NULL,NULL);
+#ifdef OS2ORUNIX
+#ifndef NOPUTENV
+ putenv(rows_buf);
+ putenv(cols_buf);
+#endif /* NOPUTENV */
+#endif /* OS2ORUNIX */
+ }
+ break;
+#ifdef CK_ENVIRONMENT
+ case TELOPT_NEWENVIRON:
+ switch (sb[0]) {
+ case TELQUAL_IS: /* IS */
+ case TELQUAL_INFO: /* INFO */
+ if (sb[0] == TELQUAL_IS)
+ debug(F101,"tn_doop NEW-ENV SB IS","",n-3);
+ else
+ debug(F101,"tn_doop NEW-ENV SB INFO","",n-3);
+ if (sstelnet || inserver) { /* Yes, receive it. */
+ if (tn_rnenv((CHAR *)&sb[1],n-3) < 0)
+ return(-1);
+ }
+ break;
+ case TELQUAL_SEND: /* SEND */
+ if ( sstelnet || inserver ) /* ignore if server */
+ break;
+ /* We need to take the sb[] and build a structure */
+ /* containing all of the variables and types that */
+ /* we are supposed to keep track of and send to */
+ /* the host, then call tn_snenv(). */
+ /* Or we can punt ... */
+ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
+ if (tn_snenv((CHAR *)&sb[1],n-3) < 0) /* Yes, send it. */
+ return(-1);
+ } else {
+#ifndef VMS
+ CHAR * xxx;
+ xxx = (CHAR *) malloc(n-1);
+#else
+ unsigned char * xxx;
+ xxx = (unsigned char *) malloc(n-1);
+#endif /* VMS */
+ /* Postpone sending until end of tn_ini() */
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str = xxx;
+ if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) {
+ memcpy((char *)TELOPT_SB(TELOPT_NEWENVIRON).env.str,
+ (char *)&sb[1],n-3);
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str[n-3] = IAC;
+ TELOPT_SB(TELOPT_NEWENVIRON).env.str[n-2] = '\0';
+ TELOPT_SB(TELOPT_NEWENVIRON).env.len = n-3;
+ TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 1;
+ }
+ }
+ break;
+ }
+ break;
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ case TELOPT_SNDLOC: {
+ if ( deblog ) {
+ sb[n-2] = '\0';
+ debug(F110,"TELNET Send-Location",sb,0);
+ }
+ break;
+ }
+#endif /* CK_SNDLOC */
+ } /* switch */
+ break;
+ }
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC /* TELNET DO OPTION */
+tn_doop(CHAR z, int echo, int (*fn)(int))
+#else
+tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
+#endif /* CK_ANSIC */
+/* tn_doop */ {
+ int x=0, y=0;
+
+ debug(F101,"tn_doop char","",z);
+ debug(F101,"tn_doop ttnproto","",ttnproto);
+
+ if (!IS_TELNET()) return(3);
+
+#ifdef CK_SSL
+ debug(F101,"tn_doop ssl_raw_flag","",ssl_raw_flag);
+ if (ssl_raw_flag || tls_raw_flag) return(7);
+#endif /* CK_SSL */
+ debug(F100,"tn_doop ttnproto proceeding...","",0);
+
+ if (z != (CHAR) IAC) {
+ debug(F101,"tn_doop bad call","",z);
+ return(-1);
+ }
+ if (ttnet != NET_TCPB) /* Check network type */
+ return(0);
+ if (ttnproto != NP_TELNET &&
+ ttnproto != NP_NONE) /* Check protocol */
+ return(0);
+
+ x = tn_xdoop(z,echo,fn);
+ if (x >= 0 && !tn_begun) {
+ y = tn_start();
+ }
+ return(y < 0 ? y : x);
+}
+
+#ifdef CK_ENVIRONMENT
+
+/* Telnet receive new environment */
+/* Returns -1 on error, 0 if nothing happens, 1 on success */
+/* In order for this code to work, sb[len] == IAC */
+/* We currently only support the USER environment variable */
+
+int
+#ifdef CK_ANSIC
+tn_rnenv(CHAR * sb, int len)
+#else
+tn_rnenv(sb, len) CHAR * sb; int len;
+#endif /* CK_ANSIC */
+/* tn_rnenv */ { /* Receive new environment */
+ char varname[17];
+ char value[65];
+ char * reply = 0, * s = 0;
+ int i,j,k,n; /* Worker. */
+ int type = 0; /* 0 for NONE, 1 for VAR, 2 for USERVAR, */
+ /* 3 for VALUE in progress */
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+ if (sb == NULL) return(-1);
+
+ if (len == 0) return(1);
+
+ /*
+ Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "unterminated"
+ follow here until done...
+ */
+ for (i = 0, j = 0, k = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
+ switch (sb[i]) {
+ case TEL_ENV_VAR: /* VAR */
+ case TEL_ENV_USERVAR: /* USERVAR */
+ case IAC: /* End of the list */
+ switch (type) {
+ case 0: /* Nothing in progress */
+ /* If we get IAC only, then that means there were */
+ /* no environment variables to send. we are done */
+ if (j == 0 && sb[i] == IAC)
+ return(1);
+ case 1: /* VAR in progress */
+ case 2: /* USERVAR in progress */
+ case 3: /* VALUE in progress */
+ value[k] = '\0';
+ varname[j] = '\0';
+ debug(F111,"tn_rnenv varname",varname,type);
+ debug(F111,"tn_rnenv value",value,type);
+ if (!strcmp(varname,"USER")) {
+#ifdef CK_AUTHENTICATION
+ if (ck_tn_auth_valid() != AUTH_VALID) {
+ extern char szUserNameRequested[];
+ debug(F100,"tn_rnenv != AUTH_VALID","",0);
+ ckstrncpy(szUserNameRequested,value,UIDBUFLEN);
+ ckstrncpy(uidbuf,value,UIDBUFLEN);
+#ifdef CK_SSL
+ if (ssl_active_flag) {
+ if ( tls_is_user_valid(ssl_con, uidbuf) ) {
+ extern char szUserNameAuthenticated[];
+ ckstrncpy(szUserNameAuthenticated,uidbuf,
+ UIDBUFLEN);
+ auth_finished(AUTH_VALID);
+ }
+ } else if (tls_active_flag) {
+ if ( tls_is_user_valid(tls_con, uidbuf) ) {
+ extern char szUserNameAuthenticated[];
+ ckstrncpy(szUserNameAuthenticated,uidbuf,
+ UIDBUFLEN);
+ auth_finished(AUTH_VALID);
+ }
+ }
+#endif /* CK_SSL */
+ } else { /* AUTH_VALID */
+ int x = 0;
+ debug(F110,"tn_rnenv AUTH_VALID uidbuf",uidbuf,0);
+
+#ifdef OS2
+ x = ckstrcmp(value,uidbuf,-1,0); /* case insensitive */
+#ifdef NT
+ /* NTLM authentication returns names of the form */
+ /* DOMAIN\user. We need to check to see of the */
+ /* USER VAR contains a domain name or not. If */
+ /* not, then we do not want to change state if */
+ /* the uidbuf matches the USER VAR when the */
+ /* DOMAIN is ignored. */
+ if ( x && ck_tn_authenticated() == AUTHTYPE_NTLM ) {
+ char * s1=NULL, * s2=NULL;
+ int len1, len2, i;
+
+ len1 = strlen(value);
+ for ( i=len1-1 ; i>=0 ; i--) {
+ if ( value[i] == '\\' ) {
+ s1 = &value[i+1]; /* DOMAIN found */
+ break;
+ }
+ }
+
+ if ( s1 == NULL ) {
+ len2 = strlen(uidbuf);
+ for ( i=len2-1 ; i>=0 ; i--) {
+ if ( uidbuf[i] == '\\' ) {
+ s2 = &uidbuf[i+1]; /* DOMAIN found */
+ break;
+ }
+ }
+
+ if ( s2 )
+ x = ckstrcmp(value,s2,-1,0);
+ }
+ }
+#endif /* NT */
+#else /* OS2 */
+ x = ckstrcmp(value,uidbuf,-1,1); /* case sensitive */
+#endif /* OS2 */
+ if ( x ) {
+ extern char szUserNameRequested[];
+ ckstrncpy(uidbuf,value,UIDBUFLEN);
+ ckstrncpy(szUserNameRequested,value,UIDBUFLEN);
+ auth_finished(AUTH_USER);
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ if ( tls_is_user_valid(ssl_con, uidbuf) )
+ auth_finished(AUTH_VALID);
+ }
+#endif /* CK_SSL */
+ }
+ }
+#else /* CK_AUTHENTICATION */
+ ckstrncpy(uidbuf,value,UIDBUFLEN);
+#endif /* CK_AUTHENTICATION */
+ }
+ break;
+ }
+ varname[0] = '\0';
+ value[0] = '\0';
+ j = 0;
+ k = 0;
+ type = (sb[i] == TEL_ENV_USERVAR ? 2 : /* USERVAR */
+ sb[i] == TEL_ENV_VAR ? 1 : /* VAR */
+ 0
+ );
+ break;
+ case TEL_ENV_VALUE: /* VALUE */
+ if ( type == 1 || type == 2 )
+ type = 3;
+ break;
+ case TEL_ENV_ESC: /* ESC */
+ /* Take next character literally */
+ if ( ++i >= len )
+ break;
+ /* otherwise, fallthrough so byte will be added to string. */
+ default:
+ switch (type) {
+ case 1: /* VAR in progress */
+ case 2: /* USERVAR in progress */
+ if ( j < 16 )
+ varname[j++] = sb[i];
+ break;
+ case 3:
+ if ( k < 64 )
+ value[k++] = sb[i];
+ break;
+ }
+ }
+ }
+ return(0);
+}
+
+/* These are for Microsoft SFU version 2 Telnet Server */
+#define SFUTLNTVER "SFUTLNTVER"
+#define SFUTLNTMODE "SFUTLNTMODE"
+#define SFUTLNTVER_VALUE "2"
+#define SFUTLNTMODE_VALUE "console" /* The other value is "stream" */
+
+/* Telnet send new environment */
+/* Returns -1 on error, 0 if nothing happens, 1 on success */
+/* In order for this code to work, sb[len] == IAC */
+
+int
+#ifdef CK_ANSIC
+tn_snenv(CHAR * sb, int len)
+#else
+tn_snenv(sb, len) CHAR * sb; int len;
+#endif /* CK_ANSIC */
+/* tn_snenv */ { /* Send new environment */
+ char varname[16];
+ char * reply = 0, * s = 0;
+ int i,j,n; /* Worker. */
+ int type = 0; /* 0 for NONE, 1 for VAR, 2 for USERVAR in progress */
+ extern int ck_lcname;
+ char localuidbuf[UIDBUFLEN]; /* (Initialized just below) */
+ char * uu = uidbuf;
+ char * disp = NULL;
+
+ localuidbuf[0] = '\0';
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+ if (!sb) return(-1);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+#ifdef CK_FORWARD_X
+ if (TELOPT_U(TELOPT_FORWARD_X)) {
+ disp = NULL;
+ } else
+#endif /* CK_FORWARD_X */
+ disp = (char *)tn_get_display();
+
+ if (ck_lcname) {
+ ckstrncpy(localuidbuf,uidbuf,UIDBUFLEN);
+ cklower(localuidbuf);
+ uu = localuidbuf;
+ }
+
+ ckhexdump((CHAR *)"tn_snenv sb[]",sb,len);
+ debug(F110,"tn_snenv uidbuf",uidbuf,0);
+ debug(F110,"tn_snenv localuidbuf",localuidbuf,0);
+ debug(F110,"tn_snenv tn_env_sys",tn_env_sys,0);
+ debug(F110,"tn_snenv tn_env_disp",tn_env_disp,0);
+ debug(F110,"tn_snenv disp",disp,0);
+
+ /* First determine the size of the buffer we will need */
+ for (i = 0, j = 0, n = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
+ switch (sb[i]) {
+ case TEL_ENV_VAR: /* VAR */
+ case TEL_ENV_USERVAR: /* USERVAR */
+ case IAC: /* End of the list */
+ switch (type) {
+ case 0: /* Nothing in progress */
+ /* If we get IAC only, then that means send all */
+ /* VAR and USERVAR. */
+ if (!(j == 0 && sb[i] == IAC))
+ break;
+ case 1: /* VAR in progress */
+ varname[j] = '\0' ;
+ if (!varname[0]) { /* Send All */
+ if (uu[0])
+ n += strlen(uu) + 4 + 2;
+ if (tn_env_job[0])
+ n += strlen(tn_env_job) + 3 + 2;
+ if (tn_env_acct[0])
+ n += strlen(tn_env_acct) + 4 + 2;
+ if (tn_env_prnt[0])
+ n += strlen(tn_env_prnt) + 7 + 2;
+ if (tn_env_sys[0])
+ n += strlen(tn_env_sys) + 10 + 2;
+ if (disp)
+ n += strlen(disp) + 7 + 2;
+ } else if (!strcmp(varname,"USER") && uu[0])
+ n += strlen(uu) + 4 + 2;
+ else if (!strcmp(varname,"JOB") && tn_env_job[0])
+ n += strlen(tn_env_job) + 3 + 2;
+ else if (!strcmp(varname,"ACCT") && tn_env_acct[0])
+ n += strlen(tn_env_acct) + 4 + 2;
+ else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0])
+ n += strlen(tn_env_prnt) + 7 + 2;
+ else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0])
+ n += strlen(tn_env_sys) + 10 + 2;
+ else if (!strcmp(varname,"DISPLAY") && disp)
+ n += strlen(disp) + 7 + 2;
+ /* If we get IAC only, then that means send all */
+ /* VAR and USERVAR. */
+ if (!(j == 0 && sb[i] == IAC))
+ break;
+ case 2: /* USERVAR in progress */
+ varname[j] = '\0' ;
+ if (!varname[0]) { /* Send All */
+ int x;
+ for ( x=0 ; x<8 ; x++ ) {
+ if ( tn_env_uservar[x][0] &&
+ tn_env_uservar[x][1] )
+ n += strlen(tn_env_uservar[x][0])
+ + strlen(tn_env_uservar[x][1]) + 2;
+ }
+ if ( tn_sfu ) {
+ /* For compatibility with Microsoft Telnet Server */
+ n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2;
+ n += strlen(SFUTLNTMODE) +
+ strlen(SFUTLNTMODE_VALUE) + 2;
+ }
+#ifdef CK_SNDLOC
+ if ( tn_loc && tn_loc[0] )
+ n += strlen("LOCATION") + strlen(tn_loc) + 2;
+#endif /* CK_SNDLOC */
+ }
+ else if (tn_sfu && !strcmp(varname,SFUTLNTVER))
+ n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2;
+ else if (tn_sfu && !strcmp(varname,SFUTLNTMODE))
+ n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2;
+#ifdef CK_SNDLOC
+ else if ( tn_loc && tn_loc[0] && !strcmp(varname,"LOCATION"))
+ n += strlen("LOCATION") + strlen(tn_loc) + 2;
+#endif /* CK_SNDLOC */
+ else {
+ int x;
+ for ( x=0 ; x<8 ; x++ ) {
+ if ( tn_env_uservar[x][0] &&
+ tn_env_uservar[x][1] &&
+ !strcmp(varname,tn_env_uservar[x][0]))
+ n += strlen(tn_env_uservar[x][0])
+ + strlen(tn_env_uservar[x][1]) + 2;
+ }
+ }
+ break;
+ }
+ varname[0] = '\0';
+ j = 0;
+ type = (sb[i] == TEL_ENV_USERVAR ? 2 : /* USERVAR */
+ sb[i] == TEL_ENV_VAR ? 1 : /* VAR */
+ 0
+ );
+ break;
+ case TEL_ENV_VALUE: /* VALUE */
+ /* Protocol Error */
+ debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
+ if (tn_deb || debses)
+ tn_debug("TELNET Subnegotiation error - VALUE in SEND");
+ return(0);
+ case TEL_ENV_ESC: /* ESC */
+ if (++i >= len)
+ break;
+ default:
+ if (j < 16 )
+ varname[j++] = sb[i];
+ }
+ }
+ reply = malloc(n + 16); /* Leave room for IAC stuff */
+ if (!reply) {
+ debug(F100, "TELNET Subnegotiation error - malloc failed", "",0);
+ if (tn_deb || debses)
+ tn_debug("TELNET Subnegotiation error - malloc failed");
+
+ /* Send a return packet with no variables so that the host */
+ /* may continue with additional negotiations */
+ if (tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_IS,"",0) < 0)
+ return(-1);
+ return(0);
+ }
+
+ /* Now construct the real reply */
+
+ n = 0; /* Start at beginning of buffer */
+/*
+ Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "unterminated"
+ follow here until done...
+*/
+ for (i = 0, j = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
+ switch (sb[i]) {
+ case TEL_ENV_VAR: /* VAR */
+ case TEL_ENV_USERVAR: /* USERVAR */
+ case IAC: /* End of the list */
+ switch (type) {
+ case 0: /* Nothing in progress */
+ /* If we get IAC only, then that means send all */
+ /* VAR and USERVAR. */
+ if (!(j == 0 && sb[i] == IAC))
+ break;
+ case 1: /* VAR in progress */
+ varname[j] = '\0';
+ if (!varname[0]) {
+ /* Send All */
+ if (uu[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"USER");
+ reply[n+5] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+6],uu);
+ n += strlen(uu) + 4 + 2;
+ }
+ if (tn_env_job[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"JOB");
+ reply[n+4] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+5],tn_env_job);
+ n += strlen(tn_env_job) + 3 + 2;
+ }
+ if (tn_env_acct[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"ACCT");
+ reply[n+5] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+6],tn_env_acct);
+ n += strlen(tn_env_acct) + 4 + 2;
+ }
+ if (tn_env_prnt[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"PRINTER");
+ reply[n+8] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+9],tn_env_prnt);
+ n += strlen(tn_env_prnt) + 7 + 2;
+ }
+ if (tn_env_sys[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"SYSTEMTYPE");
+ reply[n+11] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+12],tn_env_sys);
+ n += strlen(tn_env_sys) + 10 + 2;
+ }
+ if (disp) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"DISPLAY");
+ reply[n+8] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+9],disp);
+ n += strlen(disp) + 7 + 2;
+ }
+ } else if (!strcmp(varname,"USER") && uu[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"USER");
+ reply[n+5] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+6],uu);
+ n += strlen(uu) + 4 + 2;
+ } else if (!strcmp(varname,"JOB") && tn_env_job[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"JOB");
+ reply[n+4] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+5],tn_env_job);
+ n += strlen(tn_env_job) + 3 + 2;
+ } else if (!strcmp(varname,"ACCT") && tn_env_acct[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"ACCT");
+ reply[n+5] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+6],tn_env_acct);
+ n += strlen(tn_env_acct) + 4 + 2;
+ } else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"PRINTER");
+ reply[n+8] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+9],tn_env_prnt);
+ n += strlen(tn_env_prnt) + 7 + 2;
+ } else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0]) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"SYSTEMTYPE");
+ reply[n+11] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+12],tn_env_sys);
+ n += strlen(tn_env_sys) + 10 + 2;
+ } else if (!strcmp(varname,"DISPLAY") && disp) {
+ reply[n] = TEL_ENV_VAR; /* VAR */
+ strcpy(&reply[n+1],"DISPLAY");
+ reply[n+8] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+9],disp);
+ n += strlen(disp) + 7 + 2;
+ }
+ /* If we get IAC only, then that means send all */
+ /* VAR and USERVAR. */
+ if (!(j == 0 && sb[i] == IAC))
+ break;
+ case 2: /* USERVAR in progress */
+ varname[j] = '\0';
+ if (!varname[0]) {
+ /* Send All */
+ int x,y;
+ for ( x=0 ; x<8 ; x++ ) {
+ if ( tn_env_uservar[x][0] &&
+ tn_env_uservar[x][1] ) {
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ y = strlen(tn_env_uservar[x][0]);
+ strcpy(&reply[n+1],tn_env_uservar[x][0]);
+ reply[n+y+1] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+y+2],tn_env_uservar[x][1]);
+ n += y+strlen(tn_env_uservar[x][1])+2;
+ }
+ }
+ if ( tn_sfu ) {
+ /* Compatibility with Microsoft Telnet Server */
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ strcpy(&reply[n+1],SFUTLNTVER);
+ reply[n+11] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+12],SFUTLNTVER_VALUE);
+ n += strlen(SFUTLNTVER)+strlen(SFUTLNTVER_VALUE)+2;
+
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ strcpy(&reply[n+1],SFUTLNTMODE);
+ reply[n+12] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+13],SFUTLNTMODE_VALUE);
+ n += strlen(SFUTLNTMODE)+strlen(SFUTLNTMODE_VALUE)+2;
+ }
+ if (tn_loc && tn_loc[0]) {
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ strcpy(&reply[n+1],"LOCATION");
+ reply[n+9] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+10],tn_loc);
+ n += strlen("LOCATION") + strlen(tn_loc) + 2;
+ }
+ } else if (tn_sfu && !strcmp(varname,SFUTLNTVER)) {
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ strcpy(&reply[n+1],SFUTLNTVER);
+ reply[n+11] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+12],SFUTLNTVER_VALUE);
+ n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2;
+ } else if (tn_sfu && !strcmp(varname,SFUTLNTMODE)) {
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ strcpy(&reply[n+1],SFUTLNTMODE);
+ reply[n+12] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+13],SFUTLNTMODE_VALUE);
+ n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2;
+ }
+#ifdef CK_SNDLOC
+ else if (tn_loc && tn_loc[0] && !strcmp(varname,"LOCATION")){
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ strcpy(&reply[n+1],"LOCATION");
+ reply[n+9] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+10],tn_loc);
+ n += strlen("LOCATION") + strlen(tn_loc) + 2;
+ }
+#endif /* CK_SNDLOC */
+ else {
+ int x,y;
+ for ( x=0 ; x<8 ; x++ ) {
+ if ( tn_env_uservar[x][0] &&
+ tn_env_uservar[x][1] &&
+ !strcmp(varname,tn_env_uservar[x][0])) {
+ reply[n] = TEL_ENV_USERVAR; /* VAR */
+ y = strlen(tn_env_uservar[x][0]);
+ strcpy(&reply[n+1],tn_env_uservar[x][0]);
+ reply[n+y+1] = TEL_ENV_VALUE; /* VALUE */
+ strcpy(&reply[n+y+2],tn_env_uservar[x][1]);
+ n += y+strlen(tn_env_uservar[x][1])+2;
+ }
+ }
+ }
+ break;
+ }
+ varname[0] = '\0';
+ j = 0;
+ type = (sb[i] == TEL_ENV_USERVAR ? 2 : /* USERVAR */
+ sb[i] == TEL_ENV_VAR ? 1 : /* VAR */
+ 0
+ );
+ break;
+ case TEL_ENV_VALUE: /* VALUE */
+ /* Protocol Error */
+ debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
+ if (tn_deb || debses)
+ tn_debug("TELNET Subnegotiation error - VALUE in SEND");
+ return(0); /* Was -1 but that would be taken as */
+ /* an I/O error, so absorb it and go on. */
+ case TEL_ENV_ESC: /* ESC */
+ /* Not sure what this for. Quote next character? */
+ break;
+ default:
+ varname[j++] = sb[i];
+ }
+ }
+ if (tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_IS,reply,n) < 0) {
+ free(reply);
+ return(-1);
+ }
+ free(reply);
+ return(1);
+}
+#endif /* CK_ENVIRONMENT */
+
+/* Telnet send terminal type */
+/* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
+
+int
+tn_sttyp() { /* Send telnet terminal type. */
+ char *ttn; /* Name of terminal type. */
+#ifdef OS2
+ static int alias = -1; /* which alias are we using ? */
+ int settype = 0;
+#endif /* OS2 */
+ int i, rc; /* Worker. */
+ int tntermflg = 0;
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_TTYPE)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+ ttn = NULL;
+
+#ifndef NOTERM
+#ifdef OS2
+ if (!tn_term) {
+ if (ttnum == -1) {
+ ttnum = tt_type;
+ settype = 0;
+ alias = -1;
+ } else if (ttnumend) {
+ ttnumend = 0;
+ settype = 0;
+ } else {
+ if (tt_info[tt_type].x_aliases[++alias] == NULL) {
+ if (--tt_type < 0)
+ tt_type = max_tt;
+ if (ttnum == tt_type)
+ ttnumend = 1;
+ settype = 1;
+ alias = -1;
+ }
+ }
+ if (tt_type >= 0 && tt_type <= max_tt) {
+ if (alias == -1)
+ ttn = tt_info[tt_type].x_name;
+ else
+ ttn = tt_info[tt_type].x_aliases[alias];
+ } else
+ ttn = NULL;
+ }
+ else settype = 0;
+#endif /* OS2 */
+#endif /* NOTERM */
+
+ if (tn_term) { /* Terminal type override? */
+ debug(F110,"tn_sttyp",tn_term,0);
+ if (*tn_term) {
+ ttn = tn_term;
+ tntermflg = 1;
+ }
+ } else debug(F100,"tn_sttyp no term override","",0);
+
+#ifndef datageneral
+ if (!ttn) { /* If no override, */
+ ttn = getenv("TERM"); /* get it from the environment. */
+ }
+#endif /* datageneral */
+ if ((ttn == ((char *)0)) || ((int)strlen(ttn) >= TSBUFSIZ))
+ ttn = "UNKNOWN";
+ sb_out[0] = (CHAR) IAC; /* I Am a Command */
+ sb_out[1] = (CHAR) SB; /* Subnegotiation */
+ sb_out[2] = TELOPT_TTYPE; /* Terminal Type */
+ sb_out[3] = (CHAR) 0; /* Is... */
+ for (i = 4; *ttn; ttn++,i++) { /* Copy and uppercase it */
+#ifdef VMS
+ if (!tntermflg && *ttn == '-' &&
+ (!strcmp(ttn,"-80") || !strcmp(ttn,"-132")))
+ break;
+ else
+#endif /* VMS */
+ sb_out[i] = (char) ((!tntermflg && islower(*ttn)) ?
+ toupper(*ttn) :
+ *ttn);
+ }
+ ttn = (char *)sb_out; /* Point back to beginning */
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ sb_out[i] = '\0'; /* For debugging */
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_TTYPE)," IS ",(char *)sb_out+4," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+#ifndef NOTERM
+#ifdef OS2
+ if (settype)
+ settermtype(tt_type,0);
+ else {
+ ipadl25();
+ VscrnIsDirty(VTERM);
+ }
+#endif /* OS2 */
+#endif /* NOTERM */
+ return(1);
+}
+
+#ifdef CK_ENVIRONMENT
+#ifdef CK_XDISPLOC
+
+/* Telnet send xdisplay location */
+/* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
+
+int
+tn_sxdisploc() { /* Send telnet X display location. */
+ char * disp=NULL;
+ int i,rc;
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_XDISPLOC)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+#ifdef CK_FORWARD_X
+ if (TELOPT_U(TELOPT_FORWARD_X)) {
+ disp = NULL;
+ } else
+#endif /* CK_FORWARD_X */
+ disp = (char *)tn_get_display();
+ debug(F110,"tn_sxdisploc",disp,0);
+
+ if (!disp) {
+ /* Can't do both, send WONT */
+ if (tn_sopt(WONT,TELOPT_XDISPLOC) < 0)
+ return(-1);
+ TELOPT_UNANSWERED_WONT(TELOPT_XDISPLOC) = 1;
+ return(0);
+ }
+
+ sb_out[0] = (CHAR) IAC; /* I Am a Command */
+ sb_out[1] = (CHAR) SB; /* Subnegotiation */
+ sb_out[2] = TELOPT_XDISPLOC; /* X-Display Location */
+ sb_out[3] = (CHAR) 0; /* Is... */
+ for (i = 4; *disp; disp++,i++) { /* Copy and uppercase it */
+ sb_out[i] = (char) *disp;
+ }
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ sb_out[i] = '\0'; /* For debugging */
+ ckmakxmsg( tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_XDISPLOC),
+ " IS ",(char *)sb_out+4," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(1);
+}
+#endif /* CK_XDISPLOC */
+#endif /* CK_ENVIRONMENT */
+
+#ifdef CK_FORWARD_X
+int
+tn_sndfwdx() { /* Send Fwd X Screen number to host */
+ unsigned char screen = 0;
+ char * disp;
+ int i,rc;
+
+ /* if (!IS_TELNET()) return(0); */
+
+ if (!TELOPT_U(TELOPT_FORWARD_X)) return(0);
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ /*
+ * The format of the DISPLAY variable is [<host>:]<display>[.<screen>]
+ * where <host> is an optional DNS name or ip address with a default of
+ * the localhost; the screen defaults to 0
+ */
+
+ disp = (char *)tn_get_display();
+ if (disp) {
+ int colon,dot;
+ colon = ckindex(":",disp,0,0,1);
+ dot = ckindex(".",&disp[colon],0,0,1);
+
+ if ( dot ) {
+ screen = atoi(&disp[colon+dot]);
+ }
+ } else {
+ screen = 0;
+ }
+
+ i = 0;
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */
+ sb_out[i++] = FWDX_SCREEN; /* Screen */
+ sb_out[i++] = screen;
+ if ( screen == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg( tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X),
+ " SCREEN ",ckctox(screen,1)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(0);
+}
+#endif /* CK_FORWARD_X */
+
+#ifdef CK_SNDLOC
+int
+tn_sndloc() { /* Send location. */
+ int i,rc; /* Worker. */
+ char *ttloc;
+
+ /* if (!IS_TELNET()) return(0); */
+
+ if (!TELOPT_ME(TELOPT_SNDLOC)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+ ttloc = (tn_loc ? tn_loc : ""); /* In case we are being called even */
+ /* though there is no location. */
+ sb_out[0] = (CHAR) IAC; /* I Am a Command */
+ sb_out[1] = (CHAR) SB; /* Subnegotiation */
+ sb_out[2] = TELOPT_SNDLOC; /* Location */
+ for (i = 3; *ttloc && i < TSBUFSIZ; ttloc++,i++) /* Copy it */
+ sb_out[i] = (char) *ttloc;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_SNDLOC)," ",(char *)sb_out+3,
+ " IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ sb_out[i-2] = '\0'; /* For debugging */
+ return(0);
+}
+#endif /* CK_SNDLOC */
+
+#ifdef CK_NAWS /* NAWS = Negotiate About Window Size */
+int
+tn_snaws() { /* Send terminal width and height, RFC 1073 */
+#ifndef NOLOCAL
+ CHAR sb_out[24]; /* multiple threads */
+ int i = 0,rc;
+#ifdef OS2
+ int x = VscrnGetWidth(VTERM),
+ y = VscrnGetHeight(VTERM) - (tt_status[VTERM] ? 1 : 0);
+#else /* OS2 */
+ int x = tt_cols, y = tt_rows;
+#endif /* OS2 */
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+ if (!TELOPT_ME(TELOPT_NAWS)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
+ if (x == TELOPT_SB(TELOPT_NAWS).naws.x && /* Only send if changed */
+ y == TELOPT_SB(TELOPT_NAWS).naws.y
+ )
+ return(0);
+ TELOPT_SB(TELOPT_NAWS).naws.x = x; /* Remember the size */
+ TELOPT_SB(TELOPT_NAWS).naws.y = y;
+
+ sb_out[i++] = (CHAR) IAC; /* Send the subnegotiation */
+ sb_out[i++] = (CHAR) SB;
+ sb_out[i++] = TELOPT_NAWS;
+ sb_out[i++] = (CHAR) (x >> 8) & 0xff;
+ if ((CHAR) sb_out[i-1] == (CHAR) IAC) /* IAC in data must be doubled */
+ sb_out[i++] = (CHAR) IAC;
+ sb_out[i++] = (CHAR) (x & 0xff);
+ if ((CHAR) sb_out[i-1] == (CHAR) IAC)
+ sb_out[i++] = (CHAR) IAC;
+ sb_out[i++] = (CHAR) (y >> 8) & 0xff;
+ if ((CHAR) sb_out[i-1] == (CHAR) IAC)
+ sb_out[i++] = (CHAR) IAC;
+ sb_out[i++] = (CHAR) (y & 0xff);
+ if ((CHAR) sb_out[i-1] == (CHAR) IAC)
+ sb_out[i++] = (CHAR) IAC;
+ sb_out[i++] = (CHAR) IAC;
+ sb_out[i++] = (CHAR) SE;
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB NAWS ",
+ ckitoa(x)," ",ckitoa(y)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+#endif /* NOLOCAL */
+ return (0);
+}
+#endif /* CK_NAWS */
+
+#ifdef TN_COMPORT
+static char * tnc_signature = NULL;
+static int tnc_ls_mask = 0;
+static int tnc_ls = 0;
+static int tnc_ms_mask = 255;
+static int tnc_ms = 0;
+static int tnc_oflow = 0;
+static int tnc_iflow = 0;
+static int tnc_bps = 0;
+static int tnc_datasize = 0;
+static int tnc_parity = 0;
+static int tnc_stopbit = 0;
+static int tnc_break = 0;
+static int tnc_dtr = 0;
+static int tnc_rts = 0;
+static int tnc_suspend_xmit = 0;
+static int tnc_bps_index = -1;
+
+int
+#ifdef CK_ANSIC
+tnc_init(void)
+#else /* CK_ANSIC */
+tnc_init()
+#endif /* CK_ANSIC */
+/* tnc_init */ {
+ debug(F100,"tnc_init","",0);
+
+ /* if (!IS_TELNET()) return(0); */
+
+ if (tnc_signature) {
+ free(tnc_signature);
+ tnc_signature = NULL;
+ }
+ tnc_ls_mask = 0;
+ tnc_ls = 0;
+ tnc_ms_mask = 255;
+ tnc_ms = 0;
+ tnc_oflow = 0;
+ tnc_iflow = 0;
+ tnc_bps = 0;
+ tnc_datasize = 0;
+ tnc_parity = 0;
+ tnc_stopbit = 0;
+ tnc_break = 0;
+ tnc_dtr = 0;
+ tnc_rts = 0;
+ tnc_suspend_xmit = 0;
+ tnc_bps_index = -1;
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tn_sndcomport(void)
+#else /* CK_ANSIC */
+tn_sndcomport()
+#endif /* CK_ANSIC */
+/* tn_sndcomport */ {
+ int baud, datasize, parity, stopsize, oflow, iflow;
+ CONST char * signature;
+
+ /* if (!IS_TELNET()) return(0); */
+
+ debug(F100,"tnc_sndcomport","",0);
+ signature = tnc_get_signature();
+ baud = tnc_get_baud();
+ datasize = tnc_get_datasize();
+ parity = tnc_get_parity();
+ stopsize = tnc_get_stopsize();
+ oflow = tnc_get_oflow();
+ iflow = tnc_get_iflow();
+ tnc_set_ls_mask(255);
+ tnc_set_ms_mask(255);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_wait(CHAR * msg, int ms)
+#else /* CK_ANSIC */
+tnc_wait(msg, ms) CHAR * msg; int ms;
+#endif /* CK_ANSIC */
+/* tnc_wait */ {
+ int rc, tn_wait_save = tn_wait_flg;
+
+ /* if (!IS_TELNET()) return(0); */
+
+ debug(F111,"tnc_wait","begin",ms);
+ if ( ms )
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 1;
+ else
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 1;
+ tn_wait_flg = 1;
+ rc = tn_wait((char *)msg);
+ tn_push();
+ debug(F110,"tnc_wait","end",0);
+ tn_wait_flg = tn_wait_save;
+ return(rc);
+}
+
+/* Returns -1 on error, 0 on success */
+/* In order for this code to work, sb[len] == IAC */
+
+int
+#ifdef CK_ANSIC
+tnc_tn_sb(CHAR * sb, int len)
+#else
+tnc_tn_sb(sb, len) CHAR * sb; int len;
+#endif /* CK_ANSIC */
+/* tnc_tn_sb */ {
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+ if (!sb) return(-1);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ debug(F111,"tnc_tn_sb","sb[0]",sb[0]);
+ debug(F111,"tnc_tn_sb","len",len);
+
+ switch (sb[0]) {
+ case TNC_C2S_SIGNATURE:
+ case TNC_S2C_SIGNATURE:
+ debug(F111,"tnc_tn_sb","signature",len);
+ if (len == 1) {
+ tnc_send_signature("Kermit Telnet Com Port Option");
+ } else {
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (tnc_signature)
+ free(tnc_signature);
+ tnc_signature = malloc(len);
+ if (tnc_signature) {
+ memcpy(tnc_signature,&sb[1],len-1);
+ tnc_signature[len-1] = '\0';
+ }
+ }
+ break;
+
+ case TNC_C2S_SET_BAUDRATE:
+ case TNC_S2C_SET_BAUDRATE: {
+ long baudrate;
+ char * br = (char *)&baudrate;
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (len == 2) {
+ /* Actual behavior of the Access Server... */
+ debug(F111,"tnc_tn_sb","baudrate index",sb[1]);
+ tnc_bps_index = 1;
+ switch (sb[1]) {
+ case TNC_BPS_300:
+ tnc_bps = 300;
+ break;
+ case TNC_BPS_600:
+ tnc_bps = 600;
+ break;
+ case TNC_BPS_1200:
+ tnc_bps = 1200;
+ break;
+ case TNC_BPS_2400:
+ tnc_bps = 2400;
+ break;
+ case TNC_BPS_4800:
+ tnc_bps = 4800;
+ break;
+ case TNC_BPS_9600:
+ tnc_bps = 9600;
+ break;
+ case TNC_BPS_14400:
+ tnc_bps = 14400;
+ break;
+ case TNC_BPS_19200:
+ tnc_bps = 19200;
+ break;
+ case TNC_BPS_28800:
+ tnc_bps = 28800;
+ break;
+ case TNC_BPS_38400:
+ tnc_bps = 38400;
+ break;
+ case TNC_BPS_57600:
+ tnc_bps = 57600;
+ break;
+ case TNC_BPS_115200:
+ tnc_bps = 115200;
+ break;
+ case TNC_BPS_230400:
+ tnc_bps = 230400;
+ break;
+ case TNC_BPS_460800:
+ tnc_bps = 460800;
+ break;
+ default:
+ tnc_bps = -1;
+ }
+ } else if (len == 5) {
+ /* This section attempts to follow RFC 2217 */
+ tnc_bps_index = 0;
+ br[0] = sb[1];
+ br[1] = sb[2];
+ br[2] = sb[3];
+ br[3] = sb[4];
+#ifdef datageneral
+ /* AOS/VS doesn't have ntohl() but MV's are big-endian */
+ tnc_bps = baudrate;
+#else
+ tnc_bps = ntohl(baudrate);
+#endif /* datageneral */
+ debug(F111,"tnc_tn_sb","baudrate rfc",tnc_bps);
+ } else {
+ debug(F111,"tnc_tn_sb","baudrate invalid len",len);
+ return(-1);
+ }
+ break;
+ }
+ case TNC_C2S_SET_DATASIZE:
+ case TNC_S2C_SET_DATASIZE:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (len < 2)
+ return(-1);
+ tnc_datasize = sb[1];
+ debug(F111,"tnc_tn_sb","datasize",sb[1]);
+ break;
+
+ case TNC_C2S_SET_PARITY:
+ case TNC_S2C_SET_PARITY:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (len < 2)
+ return(-1);
+ tnc_parity = sb[1];
+ debug(F111,"tnc_tn_sb","parity",sb[1]);
+ break;
+
+ case TNC_C2S_SET_STOPSIZE:
+ case TNC_S2C_SET_STOPSIZE:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (len < 2)
+ return(-1);
+ tnc_stopbit = sb[1];
+ debug(F111,"tnc_tn_sb","stopsize",sb[1]);
+ break;
+
+ case TNC_C2S_SET_CONTROL:
+ case TNC_S2C_SET_CONTROL:
+ if (len < 2) {
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ return(-1);
+ }
+
+#ifdef COMMENT
+ /* This line should be removed when testing is complete. */
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+#endif /* COMMENT */
+
+ switch ( sb[1] ) {
+ case TNC_CTL_OFLOW_REQUEST:
+ /* determine local outbound flow control and send to peer */
+ /* Cisco IOS returns 0 (TNC_CTL_OFLOW_REQUEST) when attempting */
+ /* to set the inbound flow control if it is not supported */
+ /* separately from outbound flow control. So must reset */
+ /* wait for sb flag. */
+ debug(F110,"tnc_tn_sb","oflow request",0);
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ break;
+ case TNC_CTL_OFLOW_NONE:
+ case TNC_CTL_OFLOW_XON_XOFF:
+ case TNC_CTL_OFLOW_RTS_CTS:
+ case TNC_CTL_OFLOW_DCD:
+ case TNC_CTL_OFLOW_DSR:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_oflow = sb[1];
+ debug(F111,"tnc_tn_sb","oflow",sb[1]);
+ break;
+ case TNC_CTL_BREAK_REQUEST:
+ /* determine local break state and send to peer */
+ debug(F110,"tnc_tn_sb","break request",0);
+ break;
+ case TNC_CTL_BREAK_ON:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_break = 1;
+ debug(F110,"tnc_tn_sb","break on",0);
+ break;
+
+ case TNC_CTL_BREAK_OFF:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_break = 0;
+ debug(F110,"tnc_tn_sb","break off",0);
+ break;
+
+ case TNC_CTL_DTR_REQUEST:
+ /* determine local dtr state and send to peer */
+ debug(F110,"tnc_tn_sb","dtr request",0);
+ break;
+
+ case TNC_CTL_DTR_ON:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_dtr = 1;
+ debug(F110,"tnc_tn_sb","dtr on",0);
+ break;
+
+ case TNC_CTL_DTR_OFF:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_dtr = 0;
+ debug(F110,"tnc_tn_sb","dtr off",0);
+ break;
+
+ case TNC_CTL_RTS_REQUEST:
+ /* determine local rts state and send to peer */
+ debug(F110,"tnc_tn_sb","rts request",0);
+ break;
+
+ case TNC_CTL_RTS_ON:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_rts = 1;
+ debug(F110,"tnc_tn_sb","rts on",0);
+ break;
+
+ case TNC_CTL_RTS_OFF:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_rts = 0;
+ debug(F110,"tnc_tn_sb","rts off",0);
+ break;
+
+ case TNC_CTL_IFLOW_REQUEST:
+ /* determine local inbound flow control and send to peer */
+ debug(F110,"tnc_tn_sb","iflow request",0);
+ break;
+
+ case TNC_CTL_IFLOW_NONE:
+ case TNC_CTL_IFLOW_XON_XOFF:
+ case TNC_CTL_IFLOW_RTS_CTS:
+ case TNC_CTL_IFLOW_DTR:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ tnc_iflow = sb[1];
+ debug(F111,"tnc_tn_sb","iflow",sb[1]);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+
+ case TNC_C2S_NOTIFY_LINESTATE:
+ case TNC_S2C_SEND_LS:
+ if (len < 2)
+ return(-1);
+ tnc_ls = sb[1];
+ debug(F111,"tnc_tn_sb","linestate",sb[1]);
+ if (tn_deb || debses) {
+ if (tnc_ls & TNC_MS_DATA_READY )
+ tn_debug(" ComPort Linestate Data Ready");
+ if (tnc_ls & TNC_MS_OVERRUN_ERROR )
+ tn_debug(" ComPort Linestate Overrun Error");
+ if (tnc_ls & TNC_MS_PARITY_ERROR )
+ tn_debug(" ComPort Linestate Parity Error");
+ if (tnc_ls & TNC_MS_FRAME_ERROR )
+ tn_debug(" ComPort Linestate Framing Error");
+ if (tnc_ls & TNC_MS_BREAK_ERROR )
+ tn_debug(" ComPort Linestate Break Detect Error");
+ if (tnc_ls & TNC_MS_HR_EMPTY )
+ tn_debug(" ComPort Linestate Holding Register Empty");
+ if (tnc_ls & TNC_MS_SR_EMPTY )
+ tn_debug(" ComPort Linestate Shift Register Empty");
+ if (tnc_ls & TNC_MS_TIMEOUT_ERROR )
+ tn_debug(" ComPort Linestate Timeout Error");
+ }
+ break;
+
+ case TNC_C2S_NOTIFY_MODEMSTATE:
+ case TNC_S2C_SEND_MS:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0;
+ if (len < 2)
+ return(-1);
+ tnc_ms = sb[1];
+ debug(F111,"tnc_tn_sb","modemstate",sb[1]);
+ if (tn_deb || debses) {
+ if (tnc_ms & TNC_MS_CTS_DELTA )
+ tn_debug(" ComPort Modemstate CTS State Change");
+ if (tnc_ms & TNC_MS_DSR_DELTA )
+ tn_debug(" ComPort Modemstate DSR State Change");
+ if (tnc_ms & TNC_MS_EDGE_RING )
+ tn_debug(" ComPort Modemstate Trailing Edge Ring Detector On");
+ else
+ tn_debug(" ComPort Modemstate Trailing Edge Ring Detector Off");
+ if (tnc_ms & TNC_MS_RLSD_DELTA )
+ tn_debug(" ComPort Modemstate RLSD State Change");
+ if (tnc_ms & TNC_MS_CTS_SIG )
+ tn_debug(" ComPort Modemstate CTS Signal On");
+ else
+ tn_debug(" ComPort Modemstate CTS Signal Off");
+ if (tnc_ms & TNC_MS_DSR_SIG )
+ tn_debug(" ComPort Modemstate DSR Signal On");
+ else
+ tn_debug(" ComPort Modemstate DSR Signal Off");
+ if (tnc_ms & TNC_MS_RI_SIG )
+ tn_debug(" ComPort Modemstate Ring Indicator On");
+ else
+ tn_debug(" ComPort Modemstate Ring Indicator Off");
+ if (tnc_ms & TNC_MS_RLSD_SIG )
+ tn_debug(" ComPort Modemstate RLSD Signal On");
+ else
+ tn_debug(" ComPort Modemstate RLSD Signal Off");
+ }
+ break;
+
+ case TNC_C2S_FLOW_SUSPEND:
+ case TNC_S2C_FLOW_SUSPEND:
+ debug(F110,"tnc_tn_sb","flow suspend",0);
+ tnc_suspend_xmit = 1;
+ break;
+
+ case TNC_C2S_FLOW_RESUME:
+ case TNC_S2C_FLOW_RESUME:
+ debug(F110,"tnc_tn_sb","flow resume",0);
+ tnc_suspend_xmit = 0;
+ break;
+
+ case TNC_C2S_SET_LS_MASK:
+ case TNC_S2C_SET_LS_MASK:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (len < 2)
+ return(-1);
+ debug(F111,"tnc_tn_sb","linestate mask",sb[1]);
+ tnc_ls_mask = sb[1];
+ break;
+
+ case TNC_C2S_SET_MS_MASK:
+ case TNC_S2C_SET_MS_MASK:
+ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
+ if (len < 2)
+ return(-1);
+ debug(F111,"tnc_tn_sb","modemstate mask",sb[1]);
+ tnc_ls_mask = sb[1];
+ break;
+
+ case TNC_C2S_PURGE:
+ case TNC_S2C_PURGE:
+ if (len < 2)
+ return(-1);
+ debug(F111,"tnc_tn_sb","purge",sb[1]);
+ switch ( sb[1] ) {
+ case TNC_PURGE_RECEIVE:
+ case TNC_PURGE_TRANSMIT:
+ case TNC_PURGE_BOTH:
+ /* purge local buffers */
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ default:
+ return(-1);
+ }
+ return(0);
+}
+
+CONST char *
+#ifdef CK_ANSIC
+tnc_get_signature(void)
+#else /* CK_ANSIC */
+tnc_get_signature()
+#endif /* CK_ANSIC */
+/* tnc_get_signature */ {
+ /* send IAC SB COM-PORT SIGNATURE IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ if (ttnet != NET_TCPB) return(NULL);
+ if (ttnproto != NP_TELNET) return(NULL);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(NULL);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(NULL);
+ }
+#endif /* CK_SSL */
+
+ if ( tnc_signature )
+ return(tnc_signature);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SIGNATURE; /* Signature */
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SIGNATURE IAC SE", NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(NULL);
+
+ if (tnc_wait((CHAR *)"comport signature request",0) < 0) {
+ tn_push();
+ return(NULL);
+ }
+ debug(F110,"tnc_get_signature",tnc_signature,0);
+ return(tnc_signature);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_send_signature(char * signature)
+#else /* CK_ANSIC */
+tnc_send_signature(signature) char * signature;
+#endif /* CK_ANSIC */
+/* tnc_send_signature */ {
+ /* send IAC SB COM-PORT SIGNATURE <text> IAC SE */
+ int i = 0, j = 0, rc;
+
+ debug(F110,"tnc_send_signature",signature,0);
+
+ if (!signature || !signature[0])
+ return(0);
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SIGNATURE; /* Signature */
+ for (; signature[j]; i++,j++)
+ sb_out[i] = signature[j];
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SIGNATURE ", signature, " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_baud( long baud )
+#else /* CK_ANSIC */
+tnc_set_baud(baud) long baud;
+#endif /* CK_ANSIC */
+/* tnc_set_baud */ {
+ /* send IAC SB COM-PORT SET-BAUD <value(4)> IAC SE */
+ /* wait for response */
+ /* 0 is used to request the current baud rate and */
+ /* may not be sent by this func */
+ /* return new host value */
+
+ /*
+ * the above comes from the RFC. But that is not what I am seeing
+ * instead I appear to be seeing to following:
+ *
+ * Value Baud
+ * 1 ?
+ * 2 ?
+ * 3 300
+ * 4 600
+ * 5 1200
+ * 6 2400
+ * 7 4800 ?
+ * 8 9600
+ * 9 ?
+ * 10 19200 ?
+ * 11 ?
+ * 12 38400
+ * 13 57600 ?
+ * 14 115200
+ * 15 230400 ?
+ * 16 460800 ?
+ */
+
+ int i = 0, rc;
+#ifdef datageneral
+ /* AOS/VS doesn't have htonl() but MV's are big-endian */
+ long net_baud = baud;
+#else
+ long net_baud = htonl(baud);
+#endif /* datageneral */
+ CHAR b;
+
+ debug(F111,"tnc_set_baud","begin",baud);
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if (baud <= 0)
+ return(0);
+
+ if ( net_baud != 0 && net_baud == tnc_bps)
+ return(tnc_bps);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_BAUDRATE; /* Set Baud Rate */
+
+ if (tnc_bps_index) {
+ /* IOS Access Server */
+ if (baud <= 300)
+ b = TNC_BPS_300;
+ else if (baud <= 600)
+ b = TNC_BPS_600;
+ else if (baud <= 1200)
+ b = TNC_BPS_1200;
+ else if (baud <= 2400)
+ b = TNC_BPS_2400;
+ else if (baud <= 4800)
+ b = TNC_BPS_4800;
+ else if (baud <= 9600)
+ b = TNC_BPS_9600;
+ else if (baud <= 14400)
+ b = TNC_BPS_14400;
+ else if (baud <= 19200)
+ b = TNC_BPS_19200;
+ else if (baud <= 28800)
+ b = TNC_BPS_28800;
+ else if (baud <= 38400)
+ b = TNC_BPS_38400;
+ else if (baud <= 57600)
+ b = TNC_BPS_57600;
+ else if (baud <= 115200)
+ b = TNC_BPS_115200;
+ else if (baud <= 230400)
+ b = TNC_BPS_230400;
+ else
+ b = TNC_BPS_460800;
+ sb_out[i++] = b;
+ } else {
+ /* RFC 2217 */
+ sb_out[i++] = ((char *)&net_baud)[0];
+ sb_out[i++] = ((char *)&net_baud)[1];
+ sb_out[i++] = ((char *)&net_baud)[2];
+ sb_out[i++] = ((char *)&net_baud)[3];
+ }
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-BAUD-RATE ", ckltoa(baud)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set baud rate",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_baud","end",tnc_bps);
+ return(tnc_bps);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_baud(void)
+#else /* CK_ANSIC */
+tnc_get_baud()
+#endif /* CK_ANSIC */
+/* tnc_get_baud */ {
+ /* send IAC SB COM-PORT SET-BAUD <value(4)=0> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_baud","begin",0);
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_BAUDRATE; /* Set Baud Rate */
+
+ if (tnc_bps_index > 0) {
+ /* Access Server */
+ sb_out[i++] = 0;
+ } else {
+ /* RFC 2217 */
+ sb_out[i++] = 0;
+ sb_out[i++] = 0;
+ sb_out[i++] = 0;
+ sb_out[i++] = 0;
+ }
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-BAUD-RATE ", ckltoa(0)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get baud rate",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_baud","end",tnc_bps);
+ return(tnc_bps);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_datasize(int datasize)
+#else /* CK_ANSIC */
+tnc_set_datasize(datasize) int datasize;
+#endif /* CK_ANSIC */
+/* tnc_set_datasize */ {
+ /* IAC SB COM-PORT SET_DATASIZE <value(1)> IAC SE */
+ /* Valid <value>s are 5 through 8 */
+ /* Wait for response */
+ /* return new host value */
+
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_datasize","begin",datasize);
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( !(datasize >= 5 && datasize <= 8) )
+ return(0);
+
+ if ( datasize != 0 && datasize == tnc_datasize )
+ return(tnc_datasize);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_DATASIZE; /* Set DataSize */
+ sb_out[i++] = (unsigned char)(datasize & 0xFF);
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-DATASIZE ", ckitoa(datasize)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set datasize",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_datasize","end",tnc_datasize);
+ return(tnc_datasize);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_datasize(void)
+#else /* CK_ANSIC */
+tnc_get_datasize()
+#endif /* CK_ANSIC */
+/* tnc_get_datasize */ {
+ /* IAC SB COM-PORT SET_DATASIZE <value(1)=0> IAC SE */
+ /* Wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_datasize","begin",0);
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_DATASIZE; /* Set DataSize */
+ sb_out[i++] = 0;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-DATASIZE ", ckltoa(0)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get datasize",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_datasize","end",tnc_datasize);
+ return(tnc_datasize);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_parity(int parity)
+#else /* CK_ANSIC */
+tnc_set_parity(parity) int parity;
+#endif /* CK_ANSIC */
+/* tnc_set_parity */ {
+ /* IAC SB COM-PORT SET_PARITY <value(1)> IAC SE */
+ /* Value Parity
+ * 1 None
+ * 2 Odd
+ * 3 Even
+ * 4 Mark
+ * 5 Space
+ */
+ /* Wait for response. Return new host value. */
+ int i = 0, rc;
+
+ debug(F110,"tnc_set_parity","begin",parity);
+
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( !(parity >= 1 && parity <= 5) )
+ return(0);
+
+ if ( parity != 0 && parity == tnc_parity )
+ return(tnc_parity);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_PARITY; /* Set Parity */
+ sb_out[i++] = (unsigned char)(parity & 0xFF);
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-PARITY ", ckitoa(parity)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set parity",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_parity","end",tnc_parity);
+ return(tnc_parity);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_parity(void)
+#else /* CK_ANSIC */
+tnc_get_parity()
+#endif /* CK_ANSIC */
+/* tnc_get_parity */ {
+ /* IAC SB COM-PORT SET_PARITY <value(1)=0> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_parity","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_PARITY; /* Set Parity */
+ sb_out[i++] = 0;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-PARITY ", ckitoa(0)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get parity",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_parity","end",tnc_parity);
+ return(tnc_parity);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_stopsize(int stopsize)
+#else /* CK_ANSIC */
+tnc_set_stopsize(stopsize) int stopsize;
+#endif /* CK_ANSIC */
+/* tnc_set_stopsize */ {
+ /* IAC SB COM-PORT SET_STOPSIZE <value(1)> IAC SE */
+ /* Value Stop Bit Size
+ * 1 1
+ * 2 2
+ * 3 1.5
+ */
+ /* Wait for response. Return new host value. */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_stopsize","begin",stopsize);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if (!(stopsize >= 1 && stopsize <= 3) )
+ return(0);
+
+ if ( stopsize != 0 && stopsize == tnc_stopbit )
+ return(tnc_stopbit);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_STOPSIZE; /* Set Stop Bits */
+ sb_out[i++] = (unsigned char)(stopsize & 0xFF);
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-STOPSIZE ", ckitoa(stopsize)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set stopsize",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_stopsize","end",tnc_stopbit);
+ return(tnc_stopbit);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_stopsize(void)
+#else /* CK_ANSIC */
+tnc_get_stopsize()
+#endif /* CK_ANSIC */
+/* tnc_get_stopsize */ {
+ /* IAC SB COM-PORT SET_STOPSIZE <value(1)=0> IAC SE */
+ /* Wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_stopsize","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_STOPSIZE; /* Set Stop Bits */
+ sb_out[i++] = 0;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-STOPSIZE ", ckitoa(0)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set stopsize",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_stopsize","end",tnc_stopbit);
+ return(tnc_stopbit);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_oflow(int control)
+#else /* CK_ANSIC */
+tnc_set_oflow(control) int control;
+#endif /* CK_ANSIC */
+/* tnc_set_oflow */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
+ /* Value Flow Control
+ * 1 No Flow Control
+ * 2 Xon/Xoff
+ * 3 Rts/Cts
+ * 17 DCD
+ * 19 DSR
+ */
+ /* wait for response, return new host value. */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_oflow","begin",control);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if (control != 1 && control != 2 && control != 3 &&
+ control != 17 && control != 19)
+ return(0);
+
+ if ( control != 0 && control == tnc_oflow )
+ return(tnc_oflow);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = (unsigned char)(control & 0xFF);
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ", ckitoa(control)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set outbound flow control",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_oflow","end",tnc_oflow);
+ return(tnc_oflow);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_oflow(void)
+#else /* CK_ANSIC */
+tnc_get_oflow()
+#endif /* CK_ANSIC */
+/* tnc_get_oflow */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)=0> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_oflow","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = TNC_CTL_OFLOW_REQUEST;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ ckitoa(TNC_CTL_OFLOW_REQUEST),
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get outbound flow control",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_oflow","end",tnc_oflow);
+ return(tnc_oflow);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_iflow(int control)
+#else /* CK_ANSIC */
+tnc_set_iflow(control) int control;
+#endif /* CK_ANSIC */
+/* tnc_set_iflow */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
+ /* Value Flow Control
+ * 14 No Flow Control
+ * 15 Xon/Xoff
+ * 16 Rts/Cts
+ * 18 DTR
+ */
+ /* wait for response, return new host value. */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_iflow","begin",control);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if (control != 14 && control != 15 && control != 16 && control != 18)
+ return(0);
+
+ if ( control != 0 && control == tnc_iflow )
+ return(tnc_iflow);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = (unsigned char)(control & 0xFF);
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ", ckitoa(control)," IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set inbound flow control",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_iflow","end",tnc_iflow);
+ return(tnc_iflow);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_iflow(void)
+#else /* CK_ANSIC */
+tnc_get_iflow()
+#endif /* CK_ANSIC */
+/* tnc_get_iflow */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)=13> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_iflow","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = TNC_CTL_IFLOW_REQUEST;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ ckitoa(TNC_CTL_IFLOW_REQUEST),
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get inbound flow control",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_iflow","end",tnc_iflow);
+ return(tnc_iflow);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_break_state(int onoff)
+#else /* CK_ANSIC */
+tnc_set_break_state(onoff) int onoff;
+#endif /* CK_ANSIC */
+/* tnc_set_break_state */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
+ /* Value Break State
+ * 5 On
+ * 6 Off
+ */
+ /* wait for response, return new host value. */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_break_state","begin",onoff);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( onoff != 0 && onoff == tnc_break )
+ return(tnc_break);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = onoff ?
+ TNC_CTL_BREAK_ON : TNC_CTL_BREAK_OFF;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ onoff ? "BREAK-ON" : "BREAK-OFF",
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set break state",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_break_state","end",tnc_break);
+ return(tnc_break);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_break_state(void)
+#else /* CK_ANSIC */
+tnc_get_break_state()
+#endif /* CK_ANSIC */
+/* tnc_get_break_state */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)=4> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_break_state","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = TNC_CTL_BREAK_REQUEST;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ "BREAK-REQUEST",
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get break state",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_break_state","end",tnc_break);
+ return(tnc_break);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_dtr_state(int onoff)
+#else /* CK_ANSIC */
+tnc_set_dtr_state(onoff) int onoff;
+#endif /* CK_ANSIC */
+/* tnc_set_dtr_state */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
+ /* Value Dtr State
+ * 8 On
+ * 9 Off
+ */
+ /* wait for response, return new host value. */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_dtr_state","begin",onoff);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( onoff != 0 && onoff == tnc_dtr )
+ return(tnc_dtr);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = onoff ?
+ TNC_CTL_DTR_ON : TNC_CTL_DTR_OFF;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ onoff ? "DTR-ON" : "DTR-OFF",
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set dtr state",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_dtr_state","end",tnc_dtr);
+ return(tnc_dtr);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_dtr_state(void)
+#else /* CK_ANSIC */
+tnc_get_dtr_state()
+#endif /* CK_ANSIC */
+/* tnc_get_dtr_state */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)=7> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_dtr_state","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = TNC_CTL_DTR_REQUEST;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ "DTR-REQUEST",
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get dtr state",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_dtr_state","end",tnc_dtr);
+ return(tnc_dtr);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_rts_state(int onoff)
+#else /* CK_ANSIC */
+tnc_set_rts_state(onoff) int onoff;
+#endif /* CK_ANSIC */
+/* tnc_set_rts_state */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
+ /* Value Rts State
+ * 5 On
+ * 6 Off
+ */
+ /* wait for response, return new host value. */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_rts_state","begin",onoff);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( onoff != 0 && onoff == tnc_rts )
+ return(tnc_rts);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = onoff ?
+ TNC_CTL_RTS_ON : TNC_CTL_RTS_OFF;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ onoff ? "RTS-ON" : "RTS-OFF",
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport set rts state",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_set_rts_state","end",tnc_rts);
+ return(tnc_rts);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_rts_state(void)
+#else /* CK_ANSIC */
+tnc_get_rts_state()
+#endif /* CK_ANSIC */
+/* tnc_get_rts_state */ {
+ /* IAC SB COM_PORT SET_CONTROL <value(1)=10> IAC SE */
+ /* wait for response */
+ int i = 0, rc;
+
+ debug(F110,"tnc_get_rts_state","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */
+ sb_out[i++] = TNC_CTL_RTS_REQUEST;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-CONTROL ",
+ "RTS-REQUEST",
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ if (tnc_wait((CHAR *)"comport get rts state",0) < 0) {
+ tn_push();
+ return(-1);
+ }
+ debug(F111,"tnc_get_rts_state","end",tnc_rts);
+ return(tnc_rts);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_ls_mask(int mask)
+#else /* CK_ANSIC */
+tnc_set_ls_mask(mask) int mask;
+#endif /* CK_ANSIC */
+/* tnc_set_ls_mask */ {
+ /* IAC SB COM_PORT SET_LINESTATE_MASK <value(1)> IAC SE */
+ /* Bit Meaning
+ * 0 Data Ready
+ * 1 Overrun Error
+ * 2 Parity Error
+ * 3 Framing Error
+ * 4 Break Detect Error
+ * 5 Transfer Holding Register Empty
+ * 6 Transfer Shift Register Empty
+ * 7 Timeout Error
+ */
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_ls_mask","begin",mask);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( mask != 0 && mask == tnc_ls_mask )
+ return(tnc_ls_mask);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_LS_MASK;
+ sb_out[i++] = (unsigned char)(mask & 0xFF);
+ if (sb_out[i-1] == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-LINESTATE-MASK ",
+ ckitoa(mask & 0xFF),
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ tnc_ls_mask = mask;
+ debug(F111,"tnc_set_ls_mask","end",tnc_ls_mask);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_ls_mask(void)
+#else /* CK_ANSIC */
+tnc_get_ls_mask()
+#endif /* CK_ANSIC */
+/* tnc_get_ls_mask */ {
+ debug(F101,"tnc_get_ls_mask","",tnc_ls_mask);
+ return(tnc_ls_mask);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_ls(void)
+#else /* CK_ANSIC */
+tnc_get_ls()
+#endif /* CK_ANSIC */
+/* tnc_get_ls */ {
+ int ls = tnc_ls;
+ debug(F101,"tnc_get_ls","",tnc_ls);
+ return(ls);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_set_ms_mask(int mask)
+#else /* CK_ANSIC */
+tnc_set_ms_mask(mask) int mask;
+#endif /* CK_ANSIC */
+/* tnc_set_ms_mask */ {
+ /* IAC SB COM_PORT SET_MODEMSTATE_MASK <value(1)> IAC SE */
+ /* Bit Meaning
+ * 0 Delta Clear To Send
+ * 1 Delta Data Set Ready
+ * 2 Trailing Edge Ring Detector
+ * 3 Delta Receive Line Signal (Carrier) Detect
+ * 4 Clear To Send Signal State
+ * 5 Data-Set-Ready Signal State
+ * 6 Ring Indicator
+ * 7 Receive Line Signal (Carrier) Detect
+ */
+
+ int i = 0, rc;
+
+ debug(F111,"tnc_set_ms_mask","begin",mask);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( mask != 0 && mask == tnc_ms_mask )
+ return(tnc_ms_mask);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_SET_MS_MASK;
+ sb_out[i++] = (unsigned char)(mask & 0xFF);
+ if (sb_out[i-1] == IAC )
+ sb_out[i++] = IAC;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " SET-MODEMSTATE-MASK ",
+ ckitoa(mask & 0xFF),
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+
+ tnc_ms_mask = mask;
+ debug(F111,"tnc_set_ms_mask","end",tnc_ms_mask);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_ms_mask(void)
+#else /* CK_ANSIC */
+tnc_get_ms_mask()
+#endif /* CK_ANSIC */
+/* tnc_get_ms_mask */ {
+ debug(F101,"tnc_get_gs_mask","",tnc_ms_mask);
+ return(tnc_ms_mask);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_get_ms(void)
+#else /* CK_ANSIC */
+tnc_get_ms()
+#endif /* CK_ANSIC */
+/* tnc_get_ms */ {
+ int ms = tnc_ms;
+ debug(F101,"tnc_get_ms","",tnc_ms);
+ return(ms);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_send_purge_data(int mode)
+#else /* CK_ANSIC */
+tnc_send_purge_data(mode) int mode;
+#endif /* CK_ANSIC */
+/* tnc_send_purge_data */ {
+ /* IAC SB COM_PORT PURGE_DATA <value(1)> IAC SE */
+ /* Value Meaning
+ * 1 Purge access server receive data buffer
+ * 2 Purge access server transmit data buffer
+ * 3 Purge access server receive and transmit data buffers
+ */
+ /* No response */
+ int i = 0, rc;
+
+ debug(F111,"tnc_send_purge_data","begin",mode);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( !(mode >= 1 && mode <= 3) )
+ return(0);
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_PURGE;
+ sb_out[i++] = (unsigned char)(mode & 0xFF);
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " PURGE-DATA ",
+ ckitoa(mode & 0xFF),
+ " IAC SE", NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ debug(F110,"tnc_send_purge_data","end",0);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_flow_suspended(void)
+#else /* CK_ANSIC */
+tnc_flow_suspended()
+#endif /* CK_ANSIC */
+/* tnc_flow_suspended */ {
+ debug(F111,"tnc_flow_suspended","",tnc_suspend_xmit);
+ return(tnc_suspend_xmit);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_suspend_flow(void)
+#else /* CK_ANSIC */
+tnc_suspend_flow()
+#endif /* CK_ANSIC */
+/* tnc_suspend_flow */ {
+ /* IAC SB COM_PORT FLOWCONTROL_SUSPEND IAC SE */
+ int i = 0, rc;
+
+ debug(F110,"tnc_suspend_flow","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_FLOW_SUSPEND;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " FLOWCONTROL-SUSPEND IAC SE", NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ debug(F110,"tnc_suspend_flow","end",0);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnc_resume_flow(void)
+#else /* CK_ANSIC */
+tnc_resume_flow()
+#endif /* CK_ANSIC */
+/* tnc_resume_flow */ {
+ /* IAC SB COM_PORT FLOWCONTROL_RESUME IAC SE */
+ int i = 0, rc;
+
+ debug(F110,"tnc_resume_flow","begin",0);
+ if (ttnet != NET_TCPB) return(0);
+ if (ttnproto != NP_TELNET) return(0);
+
+ if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ sb_out[i++] = (CHAR) IAC; /* I Am a Command */
+ sb_out[i++] = (CHAR) SB; /* Subnegotiation */
+ sb_out[i++] = TELOPT_COMPORT; /* ComPort */
+ sb_out[i++] = TNC_C2S_FLOW_RESUME;
+ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */
+ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */
+
+#ifdef DEBUG
+ if (deblog || tn_deb || debses) {
+ ckmakmsg(tn_msg_out,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
+ " FLOWCONTROL-RESUME IAC SE", NULL);
+ }
+#endif /* DEBUG */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+ debug(F100,tn_msg_out,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg_out);
+#endif /* DEBUG */
+ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if (rc)
+ return(-1);
+ debug(F110,"tnc_resume_flow","end",0);
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+tnsetflow(int nflow)
+#else
+tnsetflow(nflow) int nflow;
+#endif /* CK_ANSIC */
+/* tnsetflow */ {
+
+ int rc = -1;
+
+ debug(F111,"tnsetflow","begin",nflow);
+ if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
+ return(-1);
+
+ if (TELOPT_ME(TELOPT_COMPORT)) {
+ switch(nflow) {
+ case FLO_XONX:
+ rc = tnc_set_oflow(
+ TNC_CTL_OFLOW_XON_XOFF
+ );
+ if (rc >= 0)
+ rc = tnc_set_iflow(
+ TNC_CTL_IFLOW_XON_XOFF
+ );
+ break;
+ case FLO_RTSC:
+ rc = tnc_set_oflow(
+ TNC_CTL_OFLOW_RTS_CTS
+ );
+ if (rc >= 0)
+ rc = tnc_set_iflow(
+ TNC_CTL_IFLOW_RTS_CTS
+ );
+ break;
+ case FLO_KEEP:
+ /* leave things exactly as they are */
+ rc = 0;
+ break;
+ case FLO_NONE:
+ case FLO_DIAL: /* dialing hack */
+ case FLO_DIAX: /* cancel dialing hack */
+ rc = tnc_set_oflow(
+ TNC_CTL_OFLOW_NONE
+ );
+ if (rc >= 0)
+ rc = tnc_set_iflow(
+ TNC_CTL_IFLOW_NONE
+ );
+ break;
+ case FLO_DTRC:
+ case FLO_ETXA:
+ case FLO_STRG:
+ case FLO_DTRT:
+ default:
+ /* not supported */
+ rc = -1;
+ break;
+ }
+ }
+ debug(F111,"tnsetflow","end",rc);
+ return(rc >= 0 ? 0 : -1);
+}
+
+int
+#ifdef CK_ANSIC
+tnsettings(int par, int stop)
+#else
+tnsettings(par, stop) int par, stop;
+#endif /* CK_ANSIC */
+/* tnsettings */ {
+ int rc = -1;
+ int datasize = 0;
+ extern int hwparity;
+
+ debug(F111,"tnsettings begin","par",par);
+ debug(F111,"tnsettings begin","stop",stop);
+ if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
+ return(-1);
+
+ datasize = par ? TNC_DS_7 : TNC_DS_8;
+ if (!par) par = hwparity;
+
+ if (TELOPT_ME(TELOPT_COMPORT)) {
+ switch (par) {
+ case 'e':
+ rc = tnc_set_parity(TNC_PAR_EVEN);
+ if (rc >= 0)
+ rc = tnc_set_datasize(datasize);
+ break;
+ case 'o':
+ rc = tnc_set_parity(TNC_PAR_ODD);
+ if (rc >= 0)
+ rc = tnc_set_datasize(datasize);
+ break;
+ case 'm':
+ rc = tnc_set_parity(TNC_PAR_MARK);
+ if (rc >= 0)
+ rc = tnc_set_datasize(datasize);
+ break;
+ case 's':
+ rc = tnc_set_parity(TNC_PAR_SPACE);
+ if (rc >= 0)
+ rc = tnc_set_datasize(datasize);
+ break;
+ case 0:
+ case 'n':
+ rc = tnc_set_parity(TNC_PAR_NONE);
+ if (rc >= 0)
+ rc = tnc_set_datasize(datasize);
+ break;
+ default:
+ /* no change */
+ rc = 0;
+ }
+ switch(stop) {
+ case 2:
+ if (rc >= 0)
+ rc = tnc_set_stopsize(TNC_SB_2);
+ break;
+ case 1:
+ if (rc >= 0)
+ rc = tnc_set_stopsize(TNC_SB_1);
+ break;
+ default:
+ /* no change */
+ if (rc >= 0)
+ rc = 0;
+ }
+ }
+ debug(F111,"tnsettings","end",rc);
+ return((rc >= 0) ? 0 : -1);
+}
+
+/* T N G M D M -- Telnet Get modem signals */
+/*
+ Looks for the modem signals CTS, DSR, and CTS, and returns those that are
+ on in as its return value, in a bit mask as described for ttwmdm.
+ Returns:
+ -3 Not implemented
+ -2 if the line does not have modem control
+ -1 on error.
+ >= 0 on success, with a bit mask containing the modem signals that are on.
+*/
+int
+#ifdef CK_ANSIC
+tngmdm(void)
+#else
+tngmdm()
+#endif /* CK_ANSIC */
+/* tngmdm */ {
+
+ int rc = -1;
+
+ debug(F110,"tngmdm","begin",0);
+ if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
+ return(-1);
+
+ if (TELOPT_ME(TELOPT_COMPORT)) {
+ int modemstate = tnc_get_ms();
+ int modem = 0;
+ if (modemstate & TNC_MS_CTS_SIG)
+ modem |= BM_CTS;
+ if (modemstate & TNC_MS_DSR_SIG)
+ modem |= BM_DSR;
+ if (modemstate & TNC_MS_RI_SIG)
+ modem |= BM_RNG;
+ if (modemstate & TNC_MS_RLSD_SIG)
+ modem |= BM_DCD;
+ debug(F111,"tngmdm","end",modem);
+ return(modem);
+ } else {
+ debug(F111,"tngmdm","end",-2);
+ return(-2);
+ }
+}
+
+int
+#ifdef CK_ANSIC
+tnsndb(long wait)
+#else
+tnsndb(wait) long wait;
+#endif /* CK_ANSIC */
+/* tnsndb */ {
+ int rc = -1;
+
+ debug(F111,"tnsndb","begin",wait);
+ if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
+ return(-1);
+
+ if (TELOPT_ME(TELOPT_COMPORT)) {
+ rc = tnc_set_break_state(1);
+ if (rc >= 0) {
+ msleep(wait); /* ZZZzzz */
+ rc = tnc_set_break_state(0);
+ }
+ }
+ debug(F111,"tnsndb","end",rc);
+ return((rc >= 0) ? 0 : -1);
+}
+#endif /* TN_COMPORT */
+#endif /* TNCODE */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckctel.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckctel.h
new file mode 100644
index 0000000..242e396
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckctel.h
@@ -0,0 +1,1336 @@
+/* ckctel.h -- Symbol and macro definitions for C-Kermit telnet support */
+
+/*
+ Authors: Jeffrey E Altman <jaltman@secure-endpoints.com>,
+ Secure Endpoints Inc., New York City
+ Frank da Cruz <fdc@columbia.edu>
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Notes:
+ . This file should be used in place of "arpa/telnet.h"
+ . Only one source file should include #defines for
+ TELCMDS, TELOPTS, TELOPT_STATES, SLC_NAMES, and AUTH_NAMES.
+*/
+
+#ifndef CKCTEL_H
+#define CKCTEL_H
+#ifdef TNCODE
+/*
+ Definitions for the TELNET protocol.
+ can't rely on library header files for any of them.
+*/
+#ifdef COMMENT
+/* In some compilers these are prone to sign extension */
+
+#ifndef IAC /* First the telnet commands */
+#define IAC 255
+#endif /* IAC */
+#ifndef DONT
+#define DONT 254
+#endif /* DONT */
+#ifndef DO
+#define DO 253
+#endif /* DO */
+#ifndef WONT
+#define WONT 252
+#endif /* WONT */
+#ifndef WILL
+#define WILL 251
+#endif /* WILL */
+#ifndef SB
+#define SB 250
+#endif /* SB */
+#ifndef TN_GA
+#define TN_GA 249
+#endif /* TN_GA */
+#ifndef TN_EL
+#define TN_EL 248
+#endif /* TN_EL */
+#ifndef TN_EC
+#define TN_EC 247
+#endif /* TN_EC */
+#ifndef TN_AYT
+#define TN_AYT 246
+#endif /* TN_AYT */
+#ifndef TN_AO
+#define TN_AO 245
+#endif /* TN_AO */
+#ifndef TN_IP
+#define TN_IP 244
+#endif /* TN_IP */
+#ifndef BREAK
+#define BREAK 243
+#endif /* BREAK */
+#ifndef TN_DM
+#define TN_DM 242
+#endif /* TN_DM */
+#ifndef TN_NOP
+#define TN_NOP 241
+#endif /* TN_NOP */
+#ifndef SE
+#define SE 240
+#endif /* SE */
+#ifndef TN_EOR
+#define TN_EOR 239
+#endif /* TN_EOR */
+#ifndef TN_ABORT
+#define TN_ABORT 238
+#endif /* TN_ABORT */
+#ifndef TN_SUSP
+#define TN_SUSP 237
+#endif /* TN_SUSP */
+#ifndef TN_EOF
+#define TN_EOF 236
+#endif /* TN_EOF */
+#ifndef LAST_TN_CMD
+#define LAST_TN_CMD 236
+
+#define TN_SAK 200 /* IBM Secure Attention Key */
+#endif /* LAST_TN_CMD */
+#define SYNCH 242 /* for telfunc calls */
+
+#else
+/* Hex notation seems to suppress the sugn extension effect */
+
+
+#ifndef IAC /* First the telnet commands */
+#define IAC 0xff
+#endif /* IAC */
+#ifndef DONT
+#define DONT 0xfe /* 254 */
+#endif /* DONT */
+#ifndef DO
+#define DO 0xfd /* 253 */
+#endif /* DO */
+#ifndef WONT
+#define WONT 0xfc /* 252 */
+#endif /* WONT */
+#ifndef WILL
+#define WILL 0xfb /* 251 */
+#endif /* WILL */
+#ifndef SB
+#define SB 0xfa /* 250 */
+#endif /* SB */
+#ifndef TN_GA
+#define TN_GA 0xf9 /* 249 */
+#endif /* TN_GA */
+#ifndef TN_EL
+#define TN_EL 0xf8 /* 248 */
+#endif /* TN_EL */
+#ifndef TN_EC
+#define TN_EC 0xf7 /* 247 */
+#endif /* TN_EC */
+#ifndef TN_AYT
+#define TN_AYT 0xf6 /* 246 */
+#endif /* TN_AYT */
+#ifndef TN_AO
+#define TN_AO 0xf5 /* 245 */
+#endif /* TN_AO */
+#ifndef TN_IP
+#define TN_IP 0xf4 /* 244 */
+#endif /* TN_IP */
+#ifndef BREAK
+#define BREAK 0xf3 /* 243 */
+#endif /* BREAK */
+#ifndef TN_DM
+#define TN_DM 0xf2 /* 242 */
+#endif /* TN_DM */
+#ifndef TN_NOP
+#define TN_NOP 0xf1 /* 241 */
+#endif /* TN_NOP */
+#ifndef SE
+#define SE 0xf0 /* 240 */
+#endif /* SE */
+#ifndef TN_EOR
+#define TN_EOR 0xef /* 239 */
+#endif /* TN_EOR */
+#ifndef TN_ABORT
+#define TN_ABORT 0xee /* 238 */
+#endif /* TN_ABORT */
+#ifndef TN_SUSP
+#define TN_SUSP 0xed /* 237 */
+#endif /* TN_SUSP */
+#ifndef TN_EOF
+#define TN_EOF 0xec /* 236 */
+#endif /* TN_EOF */
+#ifndef LAST_TN_CMD
+#define LAST_TN_CMD 0xec /* 236 */
+
+#define TN_SAK 0xc8 /* 200 - IBM Secure Attention Key */
+#endif /* LAST_TN_CMD */
+#define SYNCH 0xf2 /* 242 - for telfunc calls */
+
+#endif /* COMMENT */
+
+#ifdef TELCMDS
+char *telcmds[] = {
+ "EOF", "SUSP", "ABORT", "EOR",
+ "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC",
+ "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0
+};
+#else /* TELCMDS */
+extern char *telcmds[];
+#endif /* TELCMDS */
+
+#define TELCMD_FIRST TN_EOF
+#define TELCMD_LAST IAC
+#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \
+ (unsigned int)(x) >= TELCMD_FIRST || \
+ (unsigned int)(x) == TN_SAK)
+#define TELCMD(x) (TELCMD_OK(x)? ((x) == TN_SAK?"SAK": \
+ telcmds[(x)-TELCMD_FIRST]):"UNKNOWN")
+
+/* Then the options */
+/* NB: the following platforms have TELOPT_AUTHENTICATION defined as */
+/* 45 instead of 37. */
+#ifdef TELOPT_AUTHENTICATION
+#ifdef __osf__
+#undef TELOPT_AUTHENTICATION
+#endif /* __osf__ */
+#ifndef IRIX
+#undef TELOPT_AUTHENTICATION
+#endif /* IRIX */
+#ifndef ultrix
+#undef TELOPT_AUTHENTICATION
+#endif /* ultrix */
+#endif /* TELOPT_AUTHENTICATION */
+
+/* telnet options */
+#ifndef TELOPT_BINARY
+#define TELOPT_BINARY 0 /* 8-bit data path (RFC 856)*/
+#endif
+#ifndef TELOPT_ECHO
+#define TELOPT_ECHO 1 /* echo (RFC 857)*/
+#endif
+#ifndef TELOPT_RCP
+#define TELOPT_RCP 2 /* prepare to reconnect (NIC 50005)*/
+#endif
+#ifndef TELOPT_SGA
+#define TELOPT_SGA 3 /* suppress go ahead (RFC 858) */
+#endif
+#ifndef TELOPT_NAMS
+#define TELOPT_NAMS 4 /* approximate message size (ETHERNET) */
+#endif
+#ifndef TELOPT_STATUS
+#define TELOPT_STATUS 5 /* give status (RFC 859) */
+#endif
+#ifndef TELOPT_TM
+#define TELOPT_TM 6 /* timing mark (RFC 860) */
+#endif
+#ifndef TELOPT_RCTE
+#define TELOPT_RCTE 7 /* remote controlled transmission and echo */
+#endif /* (RFC 726) */
+#ifndef TELOPT_NAOL
+#define TELOPT_NAOL 8 /* negotiate about output line width */
+#endif /* (NIC 50005) */
+#ifndef TELOPT_NAOP
+#define TELOPT_NAOP 9 /* negotiate about output page size */
+#endif /* (NIC 50005) */
+#ifndef TELOPT_NAOCRD
+#define TELOPT_NAOCRD 10 /* negotiate about CR disposition (RFC 652) */
+#endif /* [Historic] */
+#ifndef TELOPT_NAOHTS
+#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */
+#endif /* (RFC 653) [Historic] */
+#ifndef TELOPT_NAOHTD
+#define TELOPT_NAOHTD 12 /* negotiate about horiz tab disposition */
+#endif /* (RFC 654) [Historic] */
+#ifndef TELOPT_NAOFFD
+#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */
+#endif /* (RFC 655) [Historic] */
+#ifndef TELOPT_NAOVTS
+#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */
+#endif /* (RFC 656) [Historic] */
+#ifndef TELOPT_NAOVTD
+#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */
+#endif /* (RFC 657) [Historic] */
+#ifndef TELOPT_NAOLFD
+#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */
+#endif /* (RFC 658) [Historic] */
+#ifndef TELOPT_XASCII
+#define TELOPT_XASCII 17 /* extended ascii character set */
+#endif /* (RFC 698) */
+#ifndef TELOPT_LOGOUT
+#define TELOPT_LOGOUT 18 /* force logout (RFC 727) */
+#endif
+#ifndef TELOPT_BM
+#define TELOPT_BM 19 /* byte macro (RFC 735) */
+#endif
+#ifndef TELOPT_DET
+#define TELOPT_DET 20 /* data entry terminal (RFC 1043, 732) */
+#endif
+#ifndef TELOPT_SUPDUP
+#define TELOPT_SUPDUP 21 /* supdup protocol (RFC 736, 734) */
+#endif
+#ifndef TELOPT_SUPDUPOUTPUT
+#define TELOPT_SUPDUPOUTPUT 22 /* supdup output (RFC 749) */
+#endif
+#ifndef TELOPT_SNDLOC
+#define TELOPT_SNDLOC 23 /* send location (RFC 779) */
+#endif
+#ifndef TELOPT_TTYPE
+#define TELOPT_TTYPE 24 /* terminal type (RFC 1091) */
+#endif
+#ifndef TELOPT_EOR
+#define TELOPT_EOR 25 /* end of record (RFC 885) */
+#endif
+#ifndef TELOPT_TUID
+#define TELOPT_TUID 26 /* TACACS user identification (RFC 927) */
+#endif
+#ifndef TELOPT_OUTMRK
+#define TELOPT_OUTMRK 27 /* output marking (RFC 933) */
+#endif
+#ifndef TELOPT_TTYLOC
+#define TELOPT_TTYLOC 28 /* terminal location number (RFC 946) */
+#endif
+#ifndef TELOPT_3270REGIME
+#define TELOPT_3270REGIME 29 /* 3270 regime (RFC 1041) */
+#endif
+#ifndef TELOPT_X3PAD
+#define TELOPT_X3PAD 30 /* X.3 PAD (RFC 1053) */
+#endif
+#ifndef TELOPT_NAWS
+#define TELOPT_NAWS 31 /* window size (RFC 1073) */
+#endif
+#ifndef TELOPT_TSPEED
+#define TELOPT_TSPEED 32 /* terminal speed (RFC 1079) */
+#endif
+#ifndef TELOPT_LFLOW
+#define TELOPT_LFLOW 33 /* remote flow control (RFC 1372) */
+#endif
+#ifndef TELOPT_LINEMODE
+#define TELOPT_LINEMODE 34 /* Linemode option (RFC 1184) */
+#endif
+#ifndef TELOPT_XDISPLOC
+#define TELOPT_XDISPLOC 35 /* X Display Location (RFC 1096) */
+#endif
+#ifndef TELOPT_OLD_ENVIRON
+#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables (RFC 1408) */
+#endif
+#ifndef TELOPT_AUTHENTICATION
+#define TELOPT_AUTHENTICATION 37/* Authenticate (RFC 2941) */
+#endif
+#ifndef TELOPT_ENCRYPTION
+#define TELOPT_ENCRYPTION 38 /* Encryption option (RFC 2946) */
+#endif
+#ifndef TELOPT_NEWENVIRON
+#define TELOPT_NEWENVIRON 39 /* New - Environment variables (RFC 1572) */
+#endif
+#ifndef TELOPT_3270E
+#define TELOPT_3270E 40 /* 3270 Extended (RFC 1647) */
+#endif
+#ifndef TELOPT_XAUTH
+#define TELOPT_XAUTH 41 /* ??? (Earhart) */
+#endif
+#ifndef TELOPT_CHARSET
+#define TELOPT_CHARSET 42 /* Character-set (RFC 2066) */
+#endif
+#ifndef TELOPT_RSP
+#define TELOPT_RSP 43 /* Remote Serial Port (Barnes) */
+#endif
+#ifndef TELOPT_COMPORT
+#define TELOPT_COMPORT 44 /* Com Port Control (RFC 2217) */
+#endif
+#ifndef TELOPT_SLE
+#define TELOPT_SLE 45 /* Suppress Local Echo (Atmar) - [rejected] */
+#endif
+#ifndef TELOPT_START_TLS
+#define TELOPT_START_TLS 46 /* Telnet over Transport Layer Security */
+#endif /* (Boe) */
+#ifndef TELOPT_KERMIT
+#define TELOPT_KERMIT 47 /* Kermit (RFC 2840) */
+#endif
+#ifndef TELOPT_SEND_URL
+#define TELOPT_SEND_URL 48 /* Send URL */
+#endif
+
+#ifndef TELOPT_FORWARD_X
+#define TELOPT_FORWARD_X 49 /* X Windows Forwarding (Altman) */
+#endif /* TELOPT_FORWARD_X */
+
+#ifndef TELOPT_STDERR
+#define TELOPT_STDERR 50 /* Redirected Stderr (Altman) */
+#endif /* TELOPT_STDERR */
+
+#ifndef TELOPT_PRAGMA_LOGON
+#define TELOPT_PRAGMA_LOGON 138 /* Encrypted Logon option (PragmaSys) */
+#endif
+#ifndef TELOPT_SSPI_LOGON
+#define TELOPT_SSPI_LOGON 139 /* MS SSPI Logon option (PragmaSys) */
+#endif
+#ifndef TELOPT_PRAGMA_HEARTBEAT
+ /* Server Send Heartbeat option (PragmaSys) */
+#define TELOPT_PRAGMA_HEARTBEAT 140
+#endif
+
+#define TELOPT_IBM_SAK 200 /* IBM Secure Attention Key */
+
+/*
+ IBM Secure Attention Key (SAK) Option
+
+ In addition to terminal negotiation, the telnet command allows
+ negotiation for the Secure Attention Key (SAK)
+ option. This option, when supported, provides the local user with
+ a secure communication path to the remote
+ host for tasks such as changing user IDs or passwords. If the remote
+ host supports the SAK function, a trusted
+ shell is opened on the remote host when the telnet send sak
+ subcommand is issued. The SAK function can
+ also be assigned to a single key available in telnet input mode,
+ using the set sak subcommand.
+
+ TN_SAK
+
+ Sends the TELNET SAK (Secure Attention Key) sequence, which causes
+ the remote system to invoke the trusted shell. If the SAK is not
+ supported, then an error message is displayed that reads:
+ Remote side does not support SAK.
+*/
+
+#ifndef TELOPT_EXOPL
+#define TELOPT_EXOPL 255 /* Extended-options-list (RFC 861) */
+#endif
+
+#ifdef NTELOPTS
+#undef NTELOPTS
+#endif /* NTELOPTS */
+/* The Telnet Option space is no longer being allocated by ICANN as a */
+/* continuous list. In other words it is becoming sparse. But we do */
+/* not want to have to allocate memory for a long list of strings and */
+/* structs which will never be used. Therefore, the NTELOPTS define */
+/* can no longer be equal to TELOPT_LAST+1. In fact, the notion of */
+/* TELOPT_FIRST and TELOPT_LAST no longer make sense. */
+#define NTELOPTS 55
+
+#define TELOPT_FIRST TELOPT_BINARY
+#define TELOPT_LAST TELOPT_IBM_SAK
+
+/*
+ The following macros speed us up at runtime but are too complex
+ for some preprocessors / compilers; if your compiler bombs on ckctel.c
+ with "Instruction table overflow" or somesuch, rebuild with -DNOTOMACROS.
+*/
+#ifndef NOTOMACROS
+#ifndef TELOPT_MACRO
+#define TELOPT_MACRO
+#endif /* TELOPT_MACRO */
+#endif /* NOTOMACROS */
+
+#ifdef TELOPT_MACRO
+#define TELOPT_INDEX(x) (((x)>=0 && (x)<= TELOPT_STDERR)?(x):\
+ ((x)>=TELOPT_PRAGMA_LOGON && (x)<=TELOPT_PRAGMA_HEARTBEAT)?(x)-87: \
+ ((x) == TELOPT_IBM_SAK)?(x)-146: NTELOPTS)
+
+#define TELOPT_OK(x) (((x) >= TELOPT_BINARY && (x) <= TELOPT_STDERR) ||\
+ ((x) >= TELOPT_PRAGMA_LOGON && (x) <= TELOPT_PRAGMA_HEARTBEAT) ||\
+ ((x) == TELOPT_IBM_SAK))
+#define TELOPT(x) (TELOPT_OK(x)?telopts[TELOPT_INDEX(x)]:"UNKNOWN")
+#else /* TELOPT_MACRO */
+_PROTOTYP(int telopt_index,(int));
+_PROTOTYP(int telopt_ok,(int));
+_PROTOTYP(CHAR * telopt, (int));
+
+#define TELOPT_INDEX(x) telopt_index(x)
+#define TELOPT_OK(x) telopt_ok(x)
+#define TELOPT(x) telopt(x)
+#endif /* TELOPT_MACRO */
+
+#ifdef TELOPTS
+char *telopts[NTELOPTS+2] = {
+/* 0 */ "BINARY", "ECHO", "RCP", "SUPPRESS-GO-AHEAD",
+/* 4 */ "NAME", "STATUS", "TIMING-MARK", "RCTE",
+/* 8 */ "NAOL", "NAOP", "NAOCRD", "NAOHTS",
+/* 12 */ "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD",
+/* 16 */ "NAOLFD", "EXTEND-ASCII", "LOGOUT", "BYTE-MACRO",
+/* 20 */ "DATA-ENTRY-TERMINAL", "SUPDUP", "SUPDUP-OUTPUT", "SEND-LOCATION",
+/* 24 */ "TERMINAL-TYPE", "END-OF-RECORD", "TACACS-UID", "OUTPUT-MARKING",
+/* 28 */ "TTYLOC", "3270-REGIME", "X.3-PAD", "NAWS",
+/* 32 */ "TSPEED", "LFLOW", "LINEMODE", "XDISPLOC",
+/* 36 */ "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPTION", "NEW-ENVIRONMENT",
+/* 40 */ "TN3270E","xauth","CHARSET", "remote-serial-port",
+/* 44 */ "COM-PORT-CONTROL","suppress-local-echo","START-TLS","KERMIT",
+/* 48 */ "send-url","FORWARD-X","stderr",
+/* 138 */ "pragma-logon", "sspi-logon", "pragma-heartbeat",
+/* 200 */ "ibm-sak",
+ "unknown",
+ 0
+};
+#else /*TELOPTS */
+extern char * telopts[];
+#endif /* TELOPTS */
+
+/* TELNET Newline Mode */
+
+#define TNL_CR 0 /* CR sends bare carriage return */
+#define TNL_CRNUL 1 /* CR and NUL */
+#define TNL_CRLF 2 /* CR and LF */
+#define TNL_LF 3 /* LF instead of CR */
+
+/* TELNET Negotiation Mode */
+
+#define TN_NG_RF 0 /* Negotiation REFUSED */
+#define TN_NG_AC 1 /* Negotiation ACCEPTED */
+#define TN_NG_RQ 2 /* Negotiation REQUESTED */
+#define TN_NG_MU 3 /* Negotiation REQUIRED (must) */
+
+
+/* Systems where we know we can define TELNET NAWS automatically. */
+
+#ifndef CK_NAWS /* In other words, if both */
+#ifdef CK_TTGWSIZ /* TNCODE and TTGWSIZ are defined */
+#define CK_NAWS /* then we can do NAWS. */
+#endif /* CK_TTGWSIZ */
+#endif /* CK_NAWS */
+
+#ifdef CK_FORWARD_X
+#ifndef MAXFWDX
+#define MAXFWDX 64 /* Num of X windows to be fwd'd */
+#endif /* MAXFWDX */
+#endif /* CK_FORWARD_X */
+
+/* Telnet State structures and definitions */
+struct _telopt_state {
+ unsigned char def_server_me_mode; /* Default Negotiation Mode */
+ unsigned char def_server_u_mode; /* Default Negotiation Mode */
+ unsigned char def_client_me_mode; /* Default Negotiation Mode */
+ unsigned char def_client_u_mode; /* Default Negotiation Mode */
+ unsigned char me_mode; /* Telnet Negotiation Mode */
+ unsigned char u_mode; /* Telnet Negotiation Mode */
+ unsigned char me; /* Am I ? */
+ unsigned char u; /* Are you? */
+ unsigned char unanswered_will; /* Sent Will, Waiting for DO/DONT */
+ unsigned char unanswered_do; /* Send DO, Waiting for WILL/WONT */
+ unsigned char unanswered_wont; /* Sent WONT, Waiting for DONT */
+ unsigned char unanswered_dont; /* Sent DONT, Waiting for WONT */
+ unsigned char unanswered_sb; /* Sent SB, Waiting for SB (server) */
+ union {
+#ifdef IKS_OPTION
+ struct _telopt_kermit { /* Kermit Option States */
+ unsigned char me_start; /* I have a Server active */
+ unsigned char me_req_start; /* Sent Req-Start, Waiting for response */
+ unsigned char me_req_stop; /* Sent Req-Stop, Waiting for response */
+ unsigned char u_start; /* You have a Server active */
+ unsigned char sop; /* Have we received the SOP char? */
+ } kermit;
+#endif /* IKS_OPTION */
+#ifdef CK_ENCRYPTION
+ struct _telopt_encrypt { /* Encryption Option States */
+ unsigned char need_to_send;
+ unsigned char stop; /* Is encryption stopped? */
+ } encrypt;
+#endif /* CK_ENCRYPTION */
+#ifdef CK_NAWS
+ struct _telopt_naws { /* NAWS Option Information */
+ unsigned char need_to_send;
+ int x; /* Last Width */
+ int y; /* Last Height */
+ } naws;
+#endif /* CK_NAWS */
+#ifdef CK_SSL
+ struct _telopt_start_tls { /* Start TLS Option */
+ unsigned char u_follows; /* u ready for TLS negotiation */
+ unsigned char me_follows; /* me ready for TLS negotiation */
+ unsigned char auth_request; /* Rcvd WILL AUTH before WONT START_TLS */
+ } start_tls;
+#endif /* CK_SSL */
+ struct _telopt_term { /* Terminal Type */
+ unsigned char need_to_send;
+ unsigned char type[41]; /* Last terminal type */
+ } term;
+#ifdef CK_ENVIRONMENT
+ struct _telopt_new_env {
+ unsigned char need_to_send;
+ unsigned char * str;
+ int len;
+ } env;
+#ifdef CK_XDISPLOC
+ struct _telopt_xdisp {
+ unsigned char need_to_send;
+ } xdisp;
+#endif /* CK_XDISPLOC */
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ struct _telopt_sndloc {
+ unsigned char need_to_send;
+ } sndloc;
+#endif /* CK_SNDLOC */
+#ifdef CK_FORWARD_X
+ struct _telopt_fwd_x {
+ unsigned char need_to_send;
+ int listen_socket;
+ struct _channel {
+ int fd;
+ int id;
+ unsigned char need_to_send_xauth;
+ unsigned char suspend;
+ } channel[MAXFWDX];
+#ifdef NT
+ int thread_started;
+#endif /* NT */
+ } forward_x;
+#endif /* CK_FORWARD_X */
+#ifdef TN_COMPORT
+ struct _telopt_comport {
+ unsigned char need_to_send;
+ unsigned char wait_for_sb;
+ unsigned char wait_for_ms;
+ } comport;
+#endif /* TN_COMPORT */
+ /* additional options such as New Environment or Send Location */
+ } sb;
+};
+typedef struct _telopt_state telopt_state, *p_telopt_state;
+
+/* telopt_states[] is the array of structs which the state of each telnet */
+/* option is stored. We allocate one more than we need in case we are */
+/* sent telnet options that we do not recognize. If by some chance the */
+/* TELOPT_OK() check is skipped, TELOPT_INDEX() will force the option to */
+/* use the extra cell. */
+
+#ifdef TELOPT_STATES
+telopt_state telopt_states[NTELOPTS+1];
+#else /* TELOPT_STATES */
+extern telopt_state telopt_states[];
+#endif /* TELOPT_STATES */
+
+#define TELOPT_ME(x) (telopt_states[TELOPT_INDEX(x)].me)
+#define TELOPT_U(x) (telopt_states[TELOPT_INDEX(x)].u)
+#define TELOPT_ME_MODE(x) \
+ (telopt_states[TELOPT_INDEX(x)].me_mode)
+#define TELOPT_U_MODE(x) \
+ (telopt_states[TELOPT_INDEX(x)].u_mode)
+#define TELOPT_UNANSWERED_WILL(x) \
+ (telopt_states[TELOPT_INDEX(x)].unanswered_will)
+#define TELOPT_UNANSWERED_DO(x) \
+ (telopt_states[TELOPT_INDEX(x)].unanswered_do)
+#define TELOPT_UNANSWERED_WONT(x) \
+ (telopt_states[TELOPT_INDEX(x)].unanswered_wont)
+#define TELOPT_UNANSWERED_DONT(x) \
+ (telopt_states[TELOPT_INDEX(x)].unanswered_dont)
+#define TELOPT_UNANSWERED_SB(x) \
+ (telopt_states[TELOPT_INDEX(x)].unanswered_sb)
+#define TELOPT_SB(x) \
+ (telopt_states[TELOPT_INDEX(x)].sb)
+#define TELOPT_DEF_S_ME_MODE(x) \
+ (telopt_states[TELOPT_INDEX(x)].def_server_me_mode)
+#define TELOPT_DEF_S_U_MODE(x) \
+ (telopt_states[TELOPT_INDEX(x)].def_server_u_mode)
+#define TELOPT_DEF_C_ME_MODE(x) \
+ (telopt_states[TELOPT_INDEX(x)].def_client_me_mode)
+#define TELOPT_DEF_C_U_MODE(x) \
+ (telopt_states[TELOPT_INDEX(x)].def_client_u_mode)
+
+#ifdef TELOPT_MODES
+char * telopt_modes[4] = {
+ "REFUSED", "ACCEPTED", "REQUESTED", "REQUIRED"
+};
+#else /* TELOPT_MODES */
+extern char * telopt_modes[];
+#endif /* TELOPT_MODES */
+
+#ifdef TELOPT_MACRO
+#define TELOPT_MODE_OK(x) ((unsigned int)(x) <= TN_NG_MU)
+#define TELOPT_MODE(x) (TELOPT_MODE_OK(x)?telopt_modes[(x)-TN_NG_RF]:"UNKNOWN")
+#else /* TELOPT_MACRO */
+_PROTOTYP(int telopt_mode_ok,(int));
+_PROTOTYP(CHAR * telopt_mode,(int));
+
+#define TELOPT_MODE_OK(x) telopt_mode_ok(x)
+#define TELOPT_MODE(x) telopt_mode(x)
+#endif /* TELOPT_MACRO */
+
+/* Sub-option qualifiers */
+#define TELQUAL_IS 0 /* option is... */
+#define TELQUAL_SEND 1 /* send option */
+#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */
+#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */
+#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */
+
+#define TEL_ENV_VAR 0
+#define TEL_ENV_VALUE 1
+#define TEL_ENV_ESC 2
+#define TEL_ENV_USERVAR 3
+
+#define LFLOW_OFF 0 /* Disable remote flow control */
+#define LFLOW_ON 1 /* Enable remote flow control */
+#define LFLOW_RESTART_ANY 2 /* Restart output on any char */
+#define LFLOW_RESTART_XON 3 /* Restart output only on XON */
+
+/*
+ * LINEMODE suboptions
+ */
+
+#define LM_MODE 1
+#define LM_FORWARDMASK 2
+#define LM_SLC 3
+
+#define MODE_EDIT 0x01
+#define MODE_TRAPSIG 0x02
+#define MODE_ACK 0x04
+#define MODE_SOFT_TAB 0x08
+#define MODE_LIT_ECHO 0x10
+
+#define MODE_MASK 0x1f
+
+/* Not part of protocol, but needed to simplify things... */
+#define MODE_FLOW 0x0100
+#define MODE_ECHO 0x0200
+#define MODE_INBIN 0x0400
+#define MODE_OUTBIN 0x0800
+#define MODE_FORCE 0x1000
+
+#define SLC_SYNCH 1
+#define SLC_BRK 2
+#define SLC_IP 3
+#define SLC_AO 4
+#define SLC_AYT 5
+#define SLC_EOR 6
+#define SLC_ABORT 7
+#define SLC_EOF 8
+#define SLC_SUSP 9
+#define SLC_EC 10
+#define SLC_EL 11
+#define SLC_EW 12
+#define SLC_RP 13
+#define SLC_LNEXT 14
+#define SLC_XON 15
+#define SLC_XOFF 16
+#define SLC_FORW1 17
+#define SLC_FORW2 18
+#define SLC_MCL 19
+#define SLC_MCR 20
+#define SLC_MCWL 21
+#define SLC_MCWR 22
+#define SLC_MCBOL 23
+#define SLC_MCEOL 24
+#define SLC_INSRT 25
+#define SLC_OVER 26
+#define SLC_ECR 27
+#define SLC_EWR 28
+#define SLC_EBOL 29
+#define SLC_EEOL 30
+
+#define NSLC 30
+
+/*
+ * For backwards compatability, we define SLC_NAMES to be the
+ * list of names if SLC_NAMES is not defined.
+ */
+#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \
+ "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \
+ "LNEXT", "XON", "XOFF", "FORW1", "FORW2", \
+ "MCL", "MCR", "MCWL", "MCWR", "MCBOL", "MCEOL", \
+ "INSRT", "OVER", "ECR", "EWR", "EBOL", "EEOL", 0
+#ifdef SLC_NAMES
+char *slc_names[] = {
+ SLC_NAMELIST
+};
+#else
+extern char *slc_names[];
+#define SLC_NAMES SLC_NAMELIST
+#endif
+
+#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC)
+#define SLC_NAME(x) (SLC_NAME_OK(x)?slc_names[x]:"UNKNOWN")
+
+#define SLC_NOSUPPORT 0
+#define SLC_CANTCHANGE 1
+#define SLC_VARIABLE 2
+#define SLC_DEFAULT 3
+#define SLC_LEVELBITS 0x03
+
+#define SLC_FUNC 0
+#define SLC_FLAGS 1
+#define SLC_VALUE 2
+
+#define SLC_ACK 0x80
+#define SLC_FLUSHIN 0x40
+#define SLC_FLUSHOUT 0x20
+
+#define OLD_ENV_VAR 1
+#define OLD_ENV_VALUE 0
+#define NEW_ENV_VAR 0
+#define NEW_ENV_VALUE 1
+#define ENV_ESC 2
+#define ENV_USERVAR 3
+
+#define FWDX_SCREEN 0
+#define FWDX_OPEN 1
+#define FWDX_CLOSE 2
+#define FWDX_DATA 3
+#define FWDX_OPTIONS 4
+#define FWDX_OPT_DATA 5
+#define FWDX_XOFF 6
+#define FWDX_XON 7
+
+#define FWDX_OPT_NONE 0
+#define FWDX_OPT_XAUTH 1
+
+/*
+ * AUTHENTICATION suboptions
+ */
+
+/*
+ * Who is authenticating who ...
+ */
+#define AUTH_CLIENT_TO_SERVER 0 /* Client authenticating server */
+#define AUTH_SERVER_TO_CLIENT 1 /* Server authenticating client */
+#define AUTH_WHO_MASK 1
+
+/*
+ * amount of authentication done
+ */
+#define AUTH_HOW_ONE_WAY 0
+#define AUTH_HOW_MUTUAL 2
+#define AUTH_HOW_MASK 2
+
+/*
+ * should we be encrypting?
+ */
+#define AUTH_ENCRYPT_OFF 0
+#define AUTH_ENCRYPT_USING_TELOPT 4
+#define AUTH_ENCRYPT_AFTER_EXCHANGE 16
+#define AUTH_ENCRYPT_START_TLS 20
+#define AUTH_ENCRYPT_MASK 20
+
+/*
+ * will we be forwarding?
+ * if we want to activate the use of this flag then
+ * #define USE_INI_CRED_FWD
+ */
+#define INI_CRED_FWD_OFF 0
+#define INI_CRED_FWD_ON 8
+#define INI_CRED_FWD_MASK 8
+#define USE_INI_CRED_FWD
+
+#define AUTHTYPE_NULL 0
+#define AUTHTYPE_KERBEROS_V4 1
+#define AUTHTYPE_KERBEROS_V5 2
+#define AUTHTYPE_SPX 3
+#define AUTHTYPE_MINK 4
+#define AUTHTYPE_SRP 5
+#define AUTHTYPE_RSA 6
+#define AUTHTYPE_SSL 7
+#define AUTHTYPE_LOKI 10
+#define AUTHTYPE_SSA 11
+#define AUTHTYPE_KEA_SJ 12
+#define AUTHTYPE_KEA_INTEG 13
+#define AUTHTYPE_DSS 14
+#define AUTHTYPE_NTLM 15
+#define AUTHTYPE_GSSAPI_KRB5 16 /* Not allocated by IANA */
+#ifdef AUTHTYPE_CNT
+#undef AUTHTYPE_CNT
+#endif /* AUTHTYPE_CNT */
+#define AUTHTYPE_CNT 17
+
+/*
+ * AUTHTYPEs Last updated 21 March 1999
+ * from http://www.isi.edu/in-notes/iana/assignments/telnet-options
+ */
+
+#define AUTHTYPE_AUTO 99
+
+#ifdef AUTH_NAMES
+char *authtype_names[] = {
+ "NULL", /* RFC 2941 */
+ "KERBEROS_V4", /* RFC 2941 / 1411 */
+ "KERBEROS_V5", /* RFC 2941 */
+ "SPX", /* RFC 2941 (not Internet Standard) */
+ "MINK", /* RFC 2941 (not Internet Standard) */
+ "SRP", /* RFC 2944 */
+ "RSA", /* RFC 2941 (not Internet Standard) */
+ "SSL", /* RFC 2941 (not Internet Standard) */
+ "IANA_8", /* not assigned by IANA */
+ "IANA_9", /* not assigned by IANA */
+ "LOKI", /* RFC 2941 (not Internet Standard) */
+ "SSA", /* Schoch */
+ "KEA_SJ", /* RFC 2951 */
+ "KEA_SJ_INTEG", /* RFC 2951 */
+ "DSS", /* RFC 2943 */
+ "NTLM", /* Kahn <louisk@microsoft.com> */
+ "GSSAPI-KRB5", /* experimental - altman */
+ 0
+};
+char * authmode_names[] = {
+ "CLIENT_TO_SERVER|ONE_WAY",
+ "SERVER_TO_CLIENT|ONE_WAY",
+ "CLIENT_TO_SERVER|MUTUAL",
+ "SERVER_TO_CLIENT|MUTUAL",
+ "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT",
+ "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_USING_TELOPT",
+ "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT",
+ "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_USING_TELOPT",
+ "CLIENT_TO_SERVER|ONE_WAY|CRED_FWD",
+ "SERVER_TO_CLIENT|ONE_WAY|CRED_FWD",
+ "CLIENT_TO_SERVER|MUTUAL|CRED_FWD",
+ "SERVER_TO_CLIENT|MUTUAL|CRED_FWD",
+ "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT|CRED_FWD",
+ "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_USING_TELOPT|CRED_FWD",
+ "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT|CRED_FWD",
+ "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_USING_TELOPT|CRED_FWD",
+ "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_AFTER_EXCHANGE",
+ "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_AFTER_EXCHANGE",
+ "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE",
+ "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_AFTER_EXCHANGE",
+ "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS",
+ "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_START_TLS",
+ "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS",
+ "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_START_TLS",
+ "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_AFTER_EXCHANGE|CRED_FWD",
+ "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_AFTER_EXCHANGE|CRED_FWD",
+ "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE|CRED_FWD",
+ "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_AFTER_EXCHANGE|CRED_FWD",
+ "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS|CRED_FWD",
+ "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_START_TLS|CRED_FWD",
+ "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS|CRED_FWD",
+ "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_START_TLS|CRED_FWD",
+ 0
+};
+#else
+extern char *authtype_names[];
+extern char *authmode_names[];
+#endif
+#define AUTHMODE_CNT 32
+
+#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT)
+#define AUTHTYPE_NAME(x) (AUTHTYPE_NAME_OK(x)?authtype_names[x]:"UNKNOWN")
+
+#define AUTHMODE_NAME_OK(x) ((unsigned int)(x) < AUTHMODE_CNT)
+#define AUTHMODE_NAME(x) (AUTHMODE_NAME_OK(x)?authmode_names[x]:"UNKNOWN")
+
+/* Kerberos Authentication Message Identifiers */
+#define KRB_AUTH 0 /* Authentication data follows */
+#define KRB_REJECT 1 /* Rejected (reason might follow) */
+#define KRB_ACCEPT 2 /* Accepted */
+#define KRB4_CHALLENGE 3
+#define KRB4_RESPONSE 4
+#define KRB5_RESPONSE 3 /* Response for mutual auth. */
+#define KRB5_FORWARD 4 /* Forwarded credentials follow */
+#define KRB5_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */
+#define KRB5_FORWARD_REJECT 6 /* Forwarded credentials rejected */
+#define KRB5_TLS_VERIFY 7 /* TLS Finished Msg verifier */
+
+/* GSSAPI-KRB5 Authentication Message Identifiers */
+#define GSS_AUTH_DATA 0 /* Authentication data follows */
+#define GSS_REJECT 1 /* Rejected (reason might follow) */
+#define GSS_ACCEPT 2 /* Accepted (username might follow) */
+#define GSS_CONTINUE 3
+
+/* Secure Remote Password Authentication Message Identifiers */
+#define SRP_AUTH 0 /* Authentication data follows */
+#define SRP_REJECT 1 /* Rejected (reason might follow) */
+#define SRP_ACCEPT 2 /* Accepted */
+#define SRP_CHALLENGE 3
+#define SRP_RESPONSE 4
+#define SRP_EXP 8 /* */
+#define SRP_PARAMS 9 /* */
+
+/* Telnet Auth using KEA and SKIPJACK */
+
+#define KEA_CERTA_RA 1
+#define KEA_CERTB_RB_IVB_NONCEB 2
+#define KEA_IVA_RESPONSEB_NONCEA 3
+#define KEA_RESPONSEA 4
+
+/* Tim Hudson's SSL Authentication Message Identifiers */
+#define SSL_START 1
+#define SSL_ACCEPT 2
+#define SSL_REJECT 3
+
+/* Microsoft NTLM Authentication Message Identifiers */
+#define NTLM_AUTH 0
+#define NTLM_CHALLENGE 1
+#define NTLM_RESPONSE 2
+#define NTLM_ACCEPT 3
+#define NTLM_REJECT 4
+
+/* Generic Constants */
+#define AUTH_SUCCESS 0
+#define AUTH_FAILURE 255
+
+/*
+ * ENCRYPTion suboptions
+ */
+#define ENCRYPT_IS 0 /* I pick encryption type ... */
+#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */
+#define ENCRYPT_REPLY 2 /* Initial setup response */
+#define ENCRYPT_START 3 /* Am starting to send encrypted */
+#define ENCRYPT_END 4 /* Am ending encrypted */
+#define ENCRYPT_REQSTART 5 /* Request you start encrypting */
+#define ENCRYPT_REQEND 6 /* Request you send encrypting */
+#define ENCRYPT_ENC_KEYID 7
+#define ENCRYPT_DEC_KEYID 8
+#define ENCRYPT_CNT 9
+
+#define ENCTYPE_ANY 0
+#define ENCTYPE_DES_CFB64 1
+#define ENCTYPE_DES_OFB64 2
+#define ENCTYPE_DES3_CFB64 3
+#define ENCTYPE_DES3_OFB64 4
+#define ENCTYPE_CAST5_40_CFB64 8
+#define ENCTYPE_CAST5_40_OFB64 9
+#define ENCTYPE_CAST128_CFB64 10
+#define ENCTYPE_CAST128_OFB64 11
+#ifdef ENCTYPE_CNT
+#undef ENCTYPE_CNT
+#endif
+#define ENCTYPE_CNT 12
+
+#ifdef ENCRYPT_NAMES
+char *encrypt_names[] = {
+ "IS", "SUPPORT", "REPLY", "START", "END",
+ "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID",
+ 0
+};
+char *enctype_names[] = {
+ "ANY",
+ "DES_CFB64", /* RFC 2952 */
+ "DES_OFB64", /* RFC 2953 */
+ "DES3_CFB64", /* RFC 2947 */
+ "DES3_OFB64", /* RFC 2948 */
+ "UNKNOWN-5",
+ "UNKNOWN-6",
+ "UNKNOWN-7",
+ "CAST5_40_CFB64", /* RFC 2950 */
+ "CAST5_40_OFB64", /* RFC 2949 */
+ "CAST128_CFB64", /* RFC 2950*/
+ "CAST128_OFB64", /* RFC 2949 */
+ 0
+};
+#else
+extern char *encrypt_names[];
+extern char *enctype_names[];
+#endif
+
+#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT)
+#define ENCRYPT_NAME(x) (ENCRYPT_NAME_OK(x)?encrypt_names[x]:"UNKNOWN")
+
+#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT)
+#define ENCTYPE_NAME(x) (ENCTYPE_NAME_OK(x)?enctype_names[x]:"UNKNOWN")
+
+/* For setting the state of validUser */
+
+#define AUTH_REJECT 0 /* Rejected */
+#define AUTH_UNKNOWN 1 /* We don't know who he is, but he's okay */
+#define AUTH_OTHER 2 /* We know him, but not his name */
+#define AUTH_USER 3 /* We know he name */
+#define AUTH_VALID 4 /* We know him, and he needs no password */
+
+/* Kermit Option Subnegotiations */
+
+#define KERMIT_START 0
+#define KERMIT_STOP 1
+#define KERMIT_REQ_START 2
+#define KERMIT_REQ_STOP 3
+#define KERMIT_SOP 4
+#define KERMIT_RESP_START 8
+#define KERMIT_RESP_STOP 9
+
+/* For SET TELNET AUTH HOW */
+#define TN_AUTH_HOW_ANY 0
+#define TN_AUTH_HOW_ONE_WAY 1
+#define TN_AUTH_HOW_MUTUAL 2
+
+/* For SET TELNET AUTH ENCRYPT */
+#define TN_AUTH_ENC_ANY 0
+#define TN_AUTH_ENC_NONE 1
+#define TN_AUTH_ENC_TELOPT 2
+#define TN_AUTH_ENC_EXCH 3 /* not used in Kermit */
+#define TN_AUTH_ENC_TLS 4
+
+/* Telnet protocol functions defined in C-Kermit */
+
+_PROTOTYP( int tn_ini, (void) ); /* Telnet protocol support */
+_PROTOTYP( int tn_reset, (void));
+_PROTOTYP( int tn_set_modes, (void));
+_PROTOTYP( int tn_sopt, (int, int) );
+_PROTOTYP( int tn_doop, (CHAR, int, int (*)(int) ) );
+_PROTOTYP( int tn_sttyp, (void) );
+_PROTOTYP( int tn_snenv, (CHAR *, int) ) ;
+_PROTOTYP( int tn_rnenv, (CHAR *, int) ) ;
+_PROTOTYP( int tn_wait, (char *) ) ;
+_PROTOTYP( int tn_push, (void) ) ;
+_PROTOTYP( int tnsndbrk, (void) );
+_PROTOTYP( VOID tn_debug, (char *));
+_PROTOTYP( int tn_hex, (CHAR *, int, CHAR *, int));
+_PROTOTYP( unsigned char * tn_get_display, (void));
+#ifdef IKS_OPTION
+_PROTOTYP( int tn_siks, (int) );
+_PROTOTYP( int iks_wait, (int, int) );
+#endif /* IKS_OPTION */
+#ifdef CK_NAWS
+_PROTOTYP( int tn_snaws, (void) );
+#endif /* CK_NAWS */
+#ifdef CK_XDISPLOC
+_PROTOTYP( int tn_sxdisploc, (void) );
+#endif /* CK_XDISPLOC */
+#ifdef CK_SNDLOC
+_PROTOTYP( int tn_sndloc, (void) );
+#endif /* CK_SNDLOC */
+#ifdef CK_FORWARD_X
+/* From Xauth.h */
+typedef struct xauth {
+ unsigned short family;
+ unsigned short address_length;
+ char *address;
+ unsigned short number_length;
+ char *number;
+ unsigned short name_length;
+ char *name;
+ unsigned short data_length;
+ char *data;
+} Xauth;
+
+#include <stdio.h>
+
+/* from X.h */
+#define FamilyInternet 0
+#define FamilyDECnet 1
+#define FamilyChaos 2
+
+# define FamilyLocal (256) /* not part of X standard (i.e. X.h) */
+# define FamilyWild (65535)
+# define FamilyNetname (254) /* not part of X standard */
+# define FamilyKrb5Principal (253) /* Kerberos 5 principal name */
+# define FamilyLocalHost (252) /* for local non-net authentication */
+char *XauFileName();
+
+Xauth *XauReadAuth(
+FILE* /* auth_file */
+);
+
+int XauWriteAuth(
+FILE* /* auth_file */,
+Xauth* /* auth */
+);
+
+Xauth *XauGetAuthByName(
+const char* /* display_name */
+);
+
+Xauth *XauGetAuthByAddr(
+unsigned int /* family */,
+unsigned int /* address_length */,
+const char* /* address */,
+unsigned int /* number_length */,
+const char* /* number */,
+unsigned int /* name_length */,
+const char* /* name */
+);
+
+void XauDisposeAuth(
+Xauth* /* auth */
+);
+
+
+_PROTOTYP( int fwdx_create_listen_socket,(int));
+_PROTOTYP( int fwdx_open_client_channel,(int));
+_PROTOTYP( int fwdx_open_server_channel,(VOID));
+_PROTOTYP( int fwdx_close_channel,(int));
+_PROTOTYP( int fwdx_write_data_to_channel,(int, char *,int));
+_PROTOTYP( int fwdx_send_data_from_channel,(int, char *,int));
+_PROTOTYP( int fwdx_close_all,(VOID));
+_PROTOTYP( int fwdx_tn_sb,(unsigned char *, int));
+_PROTOTYP( int tn_sndfwdx, (void));
+_PROTOTYP( int fwdx_send_close,(int));
+_PROTOTYP( int fwdx_send_open,(int));
+_PROTOTYP( int fwdx_client_reply_options,(char *, int));
+_PROTOTYP( int fwdx_send_options,(VOID));
+_PROTOTYP( VOID fwdx_check_sockets,(fd_set *));
+_PROTOTYP( int fwdx_init_fd_set,(fd_set *));
+_PROTOTYP( int fwdx_authorize_channel, (int, unsigned char *, int));
+_PROTOTYP( int fwdx_create_fake_xauth, (char *, int, int));
+_PROTOTYP( int fwdx_send_xauth_to_xserver, (int, unsigned char *, int len));
+_PROTOTYP( int fwdx_server_avail, (VOID));
+_PROTOTYP( int fwdx_parse_displayname, (char *, int *, char **, int *, int *, char **));
+
+#ifdef NT
+_PROTOTYP( VOID fwdx_thread,(VOID *));
+#endif /* NT */
+#endif /* CK_FORWARD_X */
+
+#ifdef TN_COMPORT
+#define TNC_C2S_SIGNATURE 0
+#define TNC_C2S_SET_BAUDRATE 1
+#define TNC_C2S_SET_DATASIZE 2
+#define TNC_C2S_SET_PARITY 3
+#define TNC_C2S_SET_STOPSIZE 4
+#define TNC_C2S_SET_CONTROL 5
+#define TNC_C2S_NOTIFY_LINESTATE 6
+#define TNC_C2S_NOTIFY_MODEMSTATE 7
+#define TNC_C2S_FLOW_SUSPEND 8
+#define TNC_C2S_FLOW_RESUME 9
+#define TNC_C2S_SET_LS_MASK 10
+#define TNC_C2S_SET_MS_MASK 11
+#define TNC_C2S_PURGE 12
+#define TNC_S2C_SIGNATURE 100
+#define TNC_S2C_SET_BAUDRATE 101
+#define TNC_S2C_SET_DATASIZE 102
+#define TNC_S2C_SET_PARITY 103
+#define TNC_S2C_SET_STOPSIZE 104
+#define TNC_S2C_SET_CONTROL 105
+#define TNC_S2C_SEND_LS 106
+#define TNC_S2C_SEND_MS 107
+#define TNC_S2C_FLOW_SUSPEND 108
+#define TNC_S2C_FLOW_RESUME 109
+#define TNC_S2C_SET_LS_MASK 110
+#define TNC_S2C_SET_MS_MASK 111
+#define TNC_S2C_PURGE 112
+
+/* The COMPORT values are not defined in RFC 2217 */
+#define TNC_BPS_REQUEST 0
+#define TNC_BPS_300 3
+#define TNC_BPS_600 4
+#define TNC_BPS_1200 5
+#define TNC_BPS_2400 6
+#define TNC_BPS_4800 7
+#define TNC_BPS_9600 8
+#define TNC_BPS_14400 9
+#define TNC_BPS_19200 10
+#define TNC_BPS_28800 11
+#define TNC_BPS_38400 12
+#define TNC_BPS_57600 13
+#define TNC_BPS_115200 14
+#define TNC_BPS_230400 15
+#define TNC_BPS_460800 16
+
+#define TNC_DS_REQUEST 0
+#define TNC_DS_5 5
+#define TNC_DS_6 6
+#define TNC_DS_7 7
+#define TNC_DS_8 8
+
+#define TNC_PAR_REQUEST 0
+#define TNC_PAR_NONE 1
+#define TNC_PAR_ODD 2
+#define TNC_PAR_EVEN 3
+#define TNC_PAR_MARK 4
+#define TNC_PAR_SPACE 5
+
+#define TNC_SB_REQUEST 0
+#define TNC_SB_1 1
+#define TNC_SB_1_5 3
+#define TNC_SB_2 2
+
+#define TNC_CTL_OFLOW_REQUEST 0
+#define TNC_CTL_OFLOW_NONE 1
+#define TNC_CTL_OFLOW_XON_XOFF 2
+#define TNC_CTL_OFLOW_RTS_CTS 3
+#define TNC_CTL_OFLOW_DCD 17
+#define TNC_CTL_OFLOW_DSR 19
+
+#define TNC_CTL_BREAK_REQUEST 4
+#define TNC_CTL_BREAK_ON 5
+#define TNC_CTL_BREAK_OFF 6
+
+#define TNC_CTL_DTR_REQUEST 7
+#define TNC_CTL_DTR_ON 8
+#define TNC_CTL_DTR_OFF 9
+
+#define TNC_CTL_RTS_REQUEST 10
+#define TNC_CTL_RTS_ON 11
+#define TNC_CTL_RTS_OFF 12
+
+#define TNC_CTL_IFLOW_REQUEST 13
+#define TNC_CTL_IFLOW_NONE 14
+#define TNC_CTL_IFLOW_XON_XOFF 15
+#define TNC_CTL_IFLOW_RTS_CTS 16
+#define TNC_CTL_IFLOW_DTR 18
+
+#define TNC_MS_DATA_READY 1
+#define TNC_MS_OVERRUN_ERROR 2
+#define TNC_MS_PARITY_ERROR 4
+#define TNC_MS_FRAME_ERROR 8
+#define TNC_MS_BREAK_ERROR 16
+#define TNC_MS_HR_EMPTY 32
+#define TNC_MS_SR_EMPTY 64
+#define TNC_MS_TIMEOUT_ERROR 128
+
+#define TNC_MS_CTS_DELTA 1
+#define TNC_MS_DSR_DELTA 2
+#define TNC_MS_EDGE_RING 4
+#define TNC_MS_RLSD_DELTA 8
+#define TNC_MS_CTS_SIG 16
+#define TNC_MS_DSR_SIG 32
+#define TNC_MS_RI_SIG 64
+#define TNC_MS_RLSD_SIG 128
+
+#define TNC_PURGE_RECEIVE 1
+#define TNC_PURGE_TRANSMIT 2
+#define TNC_PURGE_BOTH 3
+
+#ifdef TNC_NAMES
+char *tnc_names[] = {
+ "SIGNATURE", "SET-BAUDRATE", "SET-DATARATE", "SET-PARITY", "SET-STOPSIZE",
+ "SET-CONTROL", "NOTIFY-LINESTATE", "NOTIFY-MODEMSTATE",
+ "FLOWCONTROL-SUSPEND", "FLOWCONTROL-RESUME", "SET-LINESTATE-MASK",
+ "SET-MODEMSTATE-MASK", "PURGE-DATA",
+ 0
+};
+#else
+extern char *tnc_names[];
+#endif
+
+#define TNC_NAME_OK(x) ((x) >= 0 && (x) <= 12 || (x) >= 100 && (x) <= 112)
+#define TNC_NAME(x) \
+ (TNC_NAME_OK(x)?tnc_names[(x)>=100?(x)-100:(x)]:"UNKNOWN")
+
+_PROTOTYP(int tnc_init,(void));
+_PROTOTYP(int tnc_wait,(CHAR *, int));
+_PROTOTYP(int tnc_tn_sb,(CHAR *,int));
+_PROTOTYP(CONST char * tnc_get_signature, (void));
+_PROTOTYP(int tnc_send_signature, (char *));
+_PROTOTYP(int tnc_set_baud,(long));
+_PROTOTYP(int tnc_get_baud,(void));
+_PROTOTYP(int tnc_set_datasize,(int));
+_PROTOTYP(int tnc_get_datasize,(void));
+_PROTOTYP(int tnc_set_parity,(int));
+_PROTOTYP(int tnc_get_parity,(void));
+_PROTOTYP(int tnc_set_stopsize,(int));
+_PROTOTYP(int tnc_get_stopsize,(void));
+_PROTOTYP(int tnc_set_oflow,(int));
+_PROTOTYP(int tnc_get_oflow,(void));
+_PROTOTYP(int tnc_set_iflow,(int));
+_PROTOTYP(int tnc_get_iflow,(void));
+_PROTOTYP(int tnc_set_break_state,(int));
+_PROTOTYP(int tnc_get_break_state,(void));
+_PROTOTYP(int tnc_set_dtr_state,(int));
+_PROTOTYP(int tnc_get_dtr_state,(void));
+_PROTOTYP(int tnc_set_rts_state,(int));
+_PROTOTYP(int tnc_get_rts_state,(void));
+_PROTOTYP(int tnc_set_ls_mask,(int));
+_PROTOTYP(int tnc_get_ls_mask,(void));
+_PROTOTYP(int tnc_get_ls,(void));
+_PROTOTYP(int tnc_set_ms_mask,(int));
+_PROTOTYP(int tnc_get_ms_mask,(void));
+_PROTOTYP(int tnc_get_ms,(void));
+_PROTOTYP(int tnc_send_purge_data,(int));
+_PROTOTYP(int tnc_flow_suspended,(void));
+_PROTOTYP(int tnc_suspend_flow,(void));
+_PROTOTYP(int tnc_resume_flow,(void));
+
+/* The following methods are to be called by ck?tio.c routines */
+_PROTOTYP(int tnsetflow,(int));
+_PROTOTYP(int tnsettings,(int,int));
+_PROTOTYP(int tngmdm,(void));
+_PROTOTYP(int tnsndb,(long));
+_PROTOTYP(int istncomport,(void));
+_PROTOTYP(int tn_sndcomport,(void));
+#endif /* TN_COMPORT */
+
+#ifndef CKCTEL_C /* These are declared in ckctel.c */
+extern int tn_init; /* Telnet protocol initialized flag */
+extern char *tn_term; /* Terminal type override */
+extern int sstelnet; /* Server side telnet? */
+extern int tn_deb; /* Telnet option debugging flag */
+extern int tn_auth_krb5_des_bug; /* Telnet BUG */
+#endif /* CKCTEL_C */
+
+#define TN_MSG_LEN 12292
+#endif /* TNCODE */
+#endif /* CKCTEL_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcuni.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckcuni.c
new file mode 100644
index 0000000..1f58548
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcuni.c
@@ -0,0 +1,16173 @@
+char * ckcuni = "Unicode support 9.0.115, 16 Oct 2009";
+
+#ifdef OS2
+#define KERMITFONT
+#endif /* OS2 */
+
+/* C K C U N I . C -- Unicode/Terminal character-set translations */
+
+/*
+ Copyright (C) 1999, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>
+ The Kermit Project, Columbia University, New York City.
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Functions u_blah() translate from blah to Unicode (incoming material).
+ Functions tx_blah() translate from Unicode to blah (keystrokes).
+ Function pointers are kept in parallel arrays indexed by TX_blah values
+ defined in ckcuni.h. NOTE: tx_decspec and tx_dectech are undefined since
+ these character sets are never typed, only displayed.
+
+ The blah_u() routines accept an unsigned character value in character-set
+ blah, and return the Unicode translation, or 0xfffd if the character is not
+ defined in Unicode. The 8th bit of the argument should be ignored, a`la ISO
+ 4873 and 2022.
+
+ The tx_blah() routines accept a unicode value and return the value of the
+ corresponding character in character-set blah, or else -1 if the character
+ does not exist in blah. In this case, the full 8-bit value is returned,
+ since ISO 2022 only works in the host-to-terminal direction.
+
+ NOTE: KERMITFONT should be defined only if we are using the new (still
+ hypothetical) Kermit font that has all the VT/Heath/Wyse/TVI graphic
+ characters in it. IMPORTANT: all Kermitfont code points need updating to
+ the values in the final proposal to the UTC.
+
+ LATER NOTE: The needed characters were approved for Unicode 3.1, and
+ therefore nothing special should be required to use them, except that it
+ will take some time for them to show up in commercial fonts.
+
+ TO DO: A lot of the functions can be tightened up -- use ranges when
+ possible, sort switch statements in order of frequency, etc.
+*/
+#include "ckcsym.h" /* Includes... */
+#include "ckcdeb.h"
+#include "ckcker.h"
+#include "ckucmd.h"
+#include "ckcxla.h"
+#include "ckuxla.h"
+
+#ifdef UNICODE
+
+#ifdef OS2
+/*
+ This material is needed for the integration of TextPS into Kermit 95.
+ When printing a file we use the SET FILE CHARACTER-SET value as the input
+ character-set and then convert it to the special Latin1 set called
+ CourierLatin1 using the Unicode translation functions.
+*/
+struct _pair { int tx; int fc; } TXFC[] = {
+ TX_ASCII, FC_USASCII,
+ TX_BRITISH, FC_UKASCII,
+ TX_CN_FRENCH, FC_FCASCII,
+ TX_CP437, FC_CP437,
+ TX_CP850, FC_CP850,
+ TX_CP852, FC_CP852,
+ TX_CP857, -2,
+ TX_CP862, FC_CP862,
+ TX_CP864, -2,
+ TX_CP866, FC_CP866,
+ TX_CP869, -2,
+ TX_CUBAN, -2,
+ TX_CZECH, -2,
+ TX_DANISH, -2,
+ TX_DECMCS, FC_DECMCS,
+ TX_DECSPEC, -2, /* while defined, not in fcs tables */
+ TX_DECTECH, -2, /* while defined, not in fcs tables */
+ TX_DGI, FC_DGMCS,
+ TX_DUTCH, FC_DUASCII,
+ TX_FINNISH, FC_FIASCII,
+ TX_FRENCH, FC_FRASCII,
+ TX_GERMAN, FC_GEASCII,
+ TX_HE7, FC_HE7,
+ TX_HPR8, FC_HPR8,
+ TX_HUNGARIAN, FC_HUASCII,
+ TX_ITALIAN, FC_ITASCII,
+ TX_J201R, -2,
+ TX_J201K, -2,
+ TX_KOI7, FC_KOI7,
+ TX_KOI8, FC_KOI8,
+ TX_KOI8R, FC_KOI8R,
+ TX_KOI8U, FC_KOI8U,
+ TX_8859_1, FC_1LATIN,
+ TX_8859_2, FC_2LATIN,
+ TX_8859_3, -2,
+ TX_8859_4, -2,
+ TX_8859_5, FC_CYRILL,
+ TX_8859_6, -2,
+ TX_8859_7, -2,
+ TX_8859_8, FC_HEBREW,
+ TX_8859_9, -2,
+ TX_8859_10, -2,
+ TX_8859_15, -2,
+ TX_MACL1, FC_APPQD,
+ TX_NEXT, FC_NEXT,
+ TX_NORWEGIAN, FC_NOASCII,
+ TX_PORTUGUESE, FC_POASCII,
+ TX_SPANISH, FC_SPASCII,
+ TX_SWEDISH, FC_SWASCII,
+ TX_SWISS, FC_CHASCII,
+ TX_ICELANDIC, -2,
+ TX_JIS7, -2,
+ TX_SHJIS, FC_SHJIS,
+ TX_JEUC, FC_JEUC,
+ TX_JDEC, FC_JDEC,
+ TX_ELOT927, FC_ELOT,
+ TX_DGPCGRPH, -2,
+ TX_DGLDGRPH, -2,
+ TX_DGWPGRPH, -2,
+ TX_HPLINE, -2,
+ TX_HPMATH, -2,
+ TX_QNXGRPH, -2,
+ TX_SNIBRACK, -2,
+ TX_SNIEURO, -2,
+ TX_SNIFACET, -2,
+ TX_SNIIBM, -2,
+ TX_SNIBLANK, -2,
+ TX_CP1252, -2,
+ TX_CP1250, FC_CP1250,
+ TX_CP1251, FC_CP1251,
+ TX_CP1253, -2,
+ TX_CP1254, -2,
+ TX_CP1257, -2,
+ TX_CP856, -2,
+ TX_CP855, FC_CP855,
+ TX_CP819, FC_1LATIN,
+ TX_CP912, FC_2LATIN,
+ TX_CP913, -2,
+ TX_CP914, -2,
+ TX_CP915, FC_CYRILL,
+ TX_CP1089, -2,
+ TX_CP813, FC_GREEK,
+ TX_CP916, FC_HEBREW,
+ TX_CP920, -2,
+ TX_CP1051, -2,
+ TX_CP858, FC_CP858,
+ TX_8859_15, FC_9LATIN,
+ TX_CP923, FC_CP923,
+ TX_ELOT928, -2,
+ TX_CP10000, -2,
+ TX_CP37, -2,
+ TX_CP1255, -2,
+ TX_CP1256, -2,
+ TX_CP1258, -2,
+ TX_MAZOVIA, FC_MAZOVIA,
+ TX_APL1, -2,
+ TX_APL2, -2,
+ TX_APL3, -2,
+ TX_APL4, -2,
+ TX_APL5, -2,
+ TX_TRANSP, FC_TRANSP
+};
+int nTXFC = sizeof(TXFC) / sizeof(struct _pair);
+
+int
+#ifdef CK_ANSIC
+fc2tx(int fc)
+#else
+fc2tx(int c) int fc;
+#endif /* CK_ANSIC */
+{
+ int i;
+ for (i = 0; i < nTXFC ; i++)
+ if (TXFC[i].fc == fc && TXFC[i].tx >= 0)
+ return(TXFC[i].tx);
+ return(TX_ASCII);
+}
+
+int
+#ifdef CK_ANSIC
+tx2fc(int tx)
+#else
+tx2fc(int x) int tx;
+#endif /* CK_ANSIC */
+{
+ int i;
+ for (i = 0; i < nTXFC ; i++)
+ if (TXFC[i].tx == tx && TXFC[i].fc >= 0)
+ return(TXFC[i].fc);
+ return(FC_USASCII);
+}
+
+/* SET TERMINAL REMOTE CHARACTER-SET keyword table */
+
+struct keytab txrtab[] = {
+ "apl2-ibm", TX_APL4, 0,
+ "apl-2741", TX_APL5, 0,
+ "apl-dyadic", TX_APL2, 0,
+ "apl-iso", TX_APL1, 0,
+ "apl-plus-2000", TX_APL3, 0, /* = APL-2000 */
+ "arabic-iso", TX_8859_6, 0,
+ "ascii", TX_ASCII, 0,
+ "british", TX_BRITISH, 0,
+ "canadian-french", TX_CN_FRENCH, 0,
+ "bulgaria-pc", TX_CP856, 0,
+#ifdef COMMENT
+ "cp037", TX_CP37, 0, /* U.S. EBCDIC */
+#endif /* COMMENT */
+ "cp10000", TX_CP10000, 0, /* Apple Quickdraw */
+ "cp1051", TX_CP1051, 0, /* Same as HP Roman 8 */
+ "cp1089", TX_CP1089, 0, /* Same as ISO 8859-6 */
+ "cp1250", TX_CP1250, 0, /* Latin-2 Windows */
+ "cp1251", TX_CP1251, 0, /* Cyrillic Windows */
+ "cp1252", TX_CP1252, 0, /* Latin-1 Windows */
+ "cp1253", TX_CP1253, 0, /* Greek Windows */
+ "cp1254", TX_CP1254, 0, /* Turkey Windows */
+ "cp1255", TX_CP1255, 0, /* Hebrew Windows */
+ "cp1256", TX_CP1256, 0, /* Arabic Windows */
+ "cp1257", TX_CP1257, 0, /* Latin-4 Windows */
+ "cp1258", TX_CP1258, 0, /* Viet Nam Windows */
+ "cp437", TX_CP437, 0,
+ "cp813", TX_CP813, 0, /* Same as ISO 8859-7 */
+ "cp819", TX_CP819, 0, /* Same as ISO 8859-1 */
+ "cp850", TX_CP850, 0,
+ "cp852", TX_CP852, 0,
+ "cp855", TX_CP855, 0, /* Cyrillic */
+ "cp856", TX_CP856, CM_INV, /* Bulgaria */
+ "cp857", TX_CP857, 0, /* Latin-5 */
+ "cp858", TX_CP858, 0, /* Euro modified cp850 */
+ "cp862-hebrew", TX_CP862, 0, /* Hebrew */
+ "cp864", TX_CP864, 0, /* Arabic */
+ "cp866", TX_CP866, 0, /* Cyrillic */
+ "cp869", TX_CP869, 0, /* Greek */
+ "cp912", TX_CP912, 0, /* Same as ISO 8859-2 */
+ "cp913", TX_CP913, 0, /* Same as ISO 8859-3 */
+ "cp914", TX_CP914, 0, /* Same as ISO 8859-4 */
+ "cp915", TX_CP915, 0, /* Same as ISO 8859-5 */
+ "cp916", TX_CP916, 0, /* Same as ISO 8859-8 */
+ "cp920", TX_CP920, 0, /* Same as ISO 8859-9 */
+ "cp923", TX_CP923, 0, /* Same as ISO 8859-15 */
+#ifdef COMMENT
+/* Not implemented yet */
+ "cuban", TX_CUBAN, 0,
+#endif /* COMMENT */
+ "cyrillic-iso", TX_8859_5, 0,
+#ifdef COMMENT
+/* Not implemented yet */
+ "czech", TX_CZECH, 0,
+#endif /* COMMENT */
+ "danish", TX_DANISH, 0,
+ "dec-m", TX_DECMCS, CM_ABR|CM_INV,
+ "dec-mcs", TX_DECMCS, CM_INV,
+ "dec-multinational",TX_DECMCS, 0,
+#ifdef COMMENT /* Not implemented yet */
+ "dec-kanji", TX_JDEC, 0,
+#endif /* COMMENT */
+ "dec-special", TX_DECSPEC, 0,
+ "dec-technical", TX_DECTECH, 0,
+ "dg-international", TX_DGI, 0,
+ "dg-linedrawing", TX_DGLDGRPH, 0,
+ "dg-specialgraphcs",TX_DGPCGRPH, 0,
+ "dg-wordprocessing",TX_DGWPGRPH, 0,
+ "dutch", TX_DUTCH, 0,
+ "elot927-greek", TX_ELOT927, 0,
+ "elot928-greek", TX_ELOT928, 0,
+ "finnish", TX_FINNISH, 0,
+ "french", TX_FRENCH, 0,
+ "german", TX_GERMAN, 0,
+ "greek-iso", TX_8859_7, 0,
+ "hebrew-7", TX_HE7, 0,
+ "hebrew-iso", TX_8859_8, 0,
+ "hp-line-drawing", TX_HPLINE, 0,
+ "hp-math/technical",TX_HPMATH, 0,
+ "hp-roman8", TX_HPR8, 0,
+ "hungarian", TX_HUNGARIAN, 0,
+ "italian", TX_ITALIAN, 0,
+ "japanese-roman", TX_J201R, 0,
+#ifdef COMMENT /* Not implemented yet */
+ "japanese-euc", TX_JEUC, 0,
+ "jis7-kanji", TX_JIS7, 0,
+#endif /* COMMENT */
+ "katakana", TX_J201K, 0,
+ "ko", TX_KOI8, CM_ABR|CM_INV,
+ "koi", TX_KOI8, CM_ABR|CM_INV,
+ "koi8", TX_KOI8, 0,
+ "koi8-cyrillic", TX_KOI8, CM_INV,
+ "koi8r", TX_KOI8R, 0,
+ "koi8u", TX_KOI8U, 0,
+ "l", TX_8859_1, CM_ABR|CM_INV,
+ "la", TX_8859_1, CM_ABR|CM_INV,
+ "lat", TX_8859_1, CM_ABR|CM_INV,
+ "lati", TX_8859_1, CM_ABR|CM_INV,
+ "latin", TX_8859_1, CM_ABR|CM_INV,
+ "latin1-iso", TX_8859_1, 0,
+ "latin2-iso", TX_8859_2, 0,
+ "latin3-iso", TX_8859_3, 0,
+ "latin4-iso", TX_8859_4, 0,
+ "latin5-iso", TX_8859_9, 0,
+ "latin6-iso", TX_8859_10, 0,
+ "latin9-iso", TX_8859_15, 0,
+ "macintosh-latin", TX_MACL1, 0,
+ "mazovia-pc", TX_MAZOVIA, 0,
+ "next-multinational",TX_NEXT, 0,
+ "norwegian", TX_NORWEGIAN, 0,
+ "portuguese", TX_PORTUGUESE, 0,
+ "qnx-console", TX_QNXGRPH, 0,
+#ifdef COMMENT /* Not implemented yet */
+ "shift-jis", TX_SHJIS, 0,
+#endif /* COMMENT */
+ "short-koi", TX_KOI7, 0,
+ "sni-blanks", TX_SNIBLANK, 0,
+ "sni-brackets", TX_SNIBRACK, 0,
+ "sni-euro", TX_SNIEURO, 0,
+ "sni-facet", TX_SNIFACET, 0,
+ "sni-ibm", TX_SNIIBM, 0,
+ "spanish", TX_SPANISH, 0,
+ "swedish", TX_SWEDISH, 0,
+ "swiss", TX_SWISS, 0,
+ "transparent", TX_TRANSP, 0,
+#ifdef COMMENT
+ "utf7", TX_UTF7, 0,
+#endif /* COMMENT */
+ "utf8", TX_UTF8, 0,
+ "", 0, 0
+};
+int ntxrtab = sizeof(txrtab)/sizeof(struct keytab) - 1;
+#endif /* OS2 */
+
+#ifdef KANJI
+/*
+ All Kanji/Unicode translations are based on the Unicode 3.0
+ Shift-JIS mapping. Other character sets, like EUC-JP, JIS-7, etc,
+ are transformed algorithmically to/from Shift-JIS before/after
+ conversion to/from Unicode. This is because Kanji/Unicode mapping
+ tables add about 120K to the program, and we don't want to do this
+ for each Kanji character set.
+*/
+static USHORT /* Shift-JIS to Unicode */
+sju_8140[] = { /* 0x8140 thru 0x9ffc */
+ 0x3000, 0x3001, 0x3002, 0xff0c, 0xff0e, 0x30fb, 0xff1a, 0xff1b,
+ 0xff1f, 0xff01, 0x309b, 0x309c, 0x00b4, 0xff40, 0x00a8, 0xff3e,
+ 0xffe3, 0xff3f, 0x30fd, 0x30fe, 0x309d, 0x309e, 0x3003, 0x4edd,
+ 0x3005, 0x3006, 0x3007, 0x30fc, 0x2015, 0x2010, 0xff0f, 0x005c,
+ 0x301c, 0x2016, 0xff5c, 0x2026, 0x2025, 0x2018, 0x2019, 0x201c,
+ 0x201d, 0xff08, 0xff09, 0x3014, 0x3015, 0xff3b, 0xff3d, 0xff5b,
+ 0xff5d, 0x3008, 0x3009, 0x300a, 0x300b, 0x300c, 0x300d, 0x300e,
+ 0x300f, 0x3010, 0x3011, 0xff0b, 0x2212, 0x00b1, 0x00d7, 0xfffd,
+ 0x00f7, 0xff1d, 0x2260, 0xff1c, 0xff1e, 0x2266, 0x2267, 0x221e,
+ 0x2234, 0x2642, 0x2640, 0x00b0, 0x2032, 0x2033, 0x2103, 0xffe5,
+ 0xff04, 0x00a2, 0x00a3, 0xff05, 0xff03, 0xff06, 0xff0a, 0xff20,
+ 0x00a7, 0x2606, 0x2605, 0x25cb, 0x25cf, 0x25ce, 0x25c7, 0x25c6,
+ 0x25a1, 0x25a0, 0x25b3, 0x25b2, 0x25bd, 0x25bc, 0x203b, 0x3012,
+ 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x2208, 0x220b, 0x2286, 0x2287, 0x2282, 0x2283, 0x222a, 0x2229,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x2227, 0x2228, 0x00ac, 0x21d2, 0x21d4, 0x2200, 0x2203, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x2220, 0x22a5, 0x2312, 0x2202, 0x2207, 0x2261,
+ 0x2252, 0x226a, 0x226b, 0x221a, 0x223d, 0x221d, 0x2235, 0x222b,
+ 0x222c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x212b, 0x2030, 0x266f, 0x266d, 0x266a, 0x2020, 0x2021, 0x00b6,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x25ef, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xff10,
+ 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, 0xff18,
+ 0xff19, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28,
+ 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30,
+ 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38,
+ 0xff39, 0xff3a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+ 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+ 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+ 0xff58, 0xff59, 0xff5a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x3041,
+ 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049,
+ 0x304a, 0x304b, 0x304c, 0x304d, 0x304e, 0x304f, 0x3050, 0x3051,
+ 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, 0x3059,
+ 0x305a, 0x305b, 0x305c, 0x305d, 0x305e, 0x305f, 0x3060, 0x3061,
+ 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, 0x3069,
+ 0x306a, 0x306b, 0x306c, 0x306d, 0x306e, 0x306f, 0x3070, 0x3071,
+ 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, 0x3079,
+ 0x307a, 0x307b, 0x307c, 0x307d, 0x307e, 0x307f, 0x3080, 0x3081,
+ 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, 0x3089,
+ 0x308a, 0x308b, 0x308c, 0x308d, 0x308e, 0x308f, 0x3090, 0x3091,
+ 0x3092, 0x3093, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x30a1, 0x30a2, 0x30a3, 0x30a4, 0x30a5, 0x30a6, 0x30a7, 0x30a8,
+ 0x30a9, 0x30aa, 0x30ab, 0x30ac, 0x30ad, 0x30ae, 0x30af, 0x30b0,
+ 0x30b1, 0x30b2, 0x30b3, 0x30b4, 0x30b5, 0x30b6, 0x30b7, 0x30b8,
+ 0x30b9, 0x30ba, 0x30bb, 0x30bc, 0x30bd, 0x30be, 0x30bf, 0x30c0,
+ 0x30c1, 0x30c2, 0x30c3, 0x30c4, 0x30c5, 0x30c6, 0x30c7, 0x30c8,
+ 0x30c9, 0x30ca, 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf, 0x30d0,
+ 0x30d1, 0x30d2, 0x30d3, 0x30d4, 0x30d5, 0x30d6, 0x30d7, 0x30d8,
+ 0x30d9, 0x30da, 0x30db, 0x30dc, 0x30dd, 0x30de, 0x30df, 0xfffd,
+ 0x30e0, 0x30e1, 0x30e2, 0x30e3, 0x30e4, 0x30e5, 0x30e6, 0x30e7,
+ 0x30e8, 0x30e9, 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ee, 0x30ef,
+ 0x30f0, 0x30f1, 0x30f2, 0x30f3, 0x30f4, 0x30f5, 0x30f6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0391,
+ 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399,
+ 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1,
+ 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x03b1,
+ 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9,
+ 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1,
+ 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416,
+ 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
+ 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426,
+ 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e,
+ 0x042f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436,
+ 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0xfffd,
+ 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445,
+ 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d,
+ 0x044e, 0x044f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2500,
+ 0x2502, 0x250c, 0x2510, 0x2518, 0x2514, 0x251c, 0x252c, 0x2524,
+ 0x2534, 0x253c, 0x2501, 0x2503, 0x250f, 0x2513, 0x251b, 0x2517,
+ 0x2523, 0x2533, 0x252b, 0x253b, 0x254b, 0x2520, 0x252f, 0x2528,
+ 0x2537, 0x253f, 0x251d, 0x2530, 0x2525, 0x2538, 0x2542, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x4e9c,
+ 0x5516, 0x5a03, 0x963f, 0x54c0, 0x611b, 0x6328, 0x59f6, 0x9022,
+ 0x8475, 0x831c, 0x7a50, 0x60aa, 0x63e1, 0x6e25, 0x65ed, 0x8466,
+ 0x82a6, 0x9bf5, 0x6893, 0x5727, 0x65a1, 0x6271, 0x5b9b, 0x59d0,
+ 0x867b, 0x98f4, 0x7d62, 0x7dbe, 0x9b8e, 0x6216, 0x7c9f, 0x88b7,
+ 0x5b89, 0x5eb5, 0x6309, 0x6697, 0x6848, 0x95c7, 0x978d, 0x674f,
+ 0x4ee5, 0x4f0a, 0x4f4d, 0x4f9d, 0x5049, 0x56f2, 0x5937, 0x59d4,
+ 0x5a01, 0x5c09, 0x60df, 0x610f, 0x6170, 0x6613, 0x6905, 0x70ba,
+ 0x754f, 0x7570, 0x79fb, 0x7dad, 0x7def, 0x80c3, 0x840e, 0x8863,
+ 0x8b02, 0x9055, 0x907a, 0x533b, 0x4e95, 0x4ea5, 0x57df, 0x80b2,
+ 0x90c1, 0x78ef, 0x4e00, 0x58f1, 0x6ea2, 0x9038, 0x7a32, 0x8328,
+ 0x828b, 0x9c2f, 0x5141, 0x5370, 0x54bd, 0x54e1, 0x56e0, 0x59fb,
+ 0x5f15, 0x98f2, 0x6deb, 0x80e4, 0x852d, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9662, 0x9670, 0x96a0, 0x97fb, 0x540b, 0x53f3, 0x5b87, 0x70cf,
+ 0x7fbd, 0x8fc2, 0x96e8, 0x536f, 0x9d5c, 0x7aba, 0x4e11, 0x7893,
+ 0x81fc, 0x6e26, 0x5618, 0x5504, 0x6b1d, 0x851a, 0x9c3b, 0x59e5,
+ 0x53a9, 0x6d66, 0x74dc, 0x958f, 0x5642, 0x4e91, 0x904b, 0x96f2,
+ 0x834f, 0x990c, 0x53e1, 0x55b6, 0x5b30, 0x5f71, 0x6620, 0x66f3,
+ 0x6804, 0x6c38, 0x6cf3, 0x6d29, 0x745b, 0x76c8, 0x7a4e, 0x9834,
+ 0x82f1, 0x885b, 0x8a60, 0x92ed, 0x6db2, 0x75ab, 0x76ca, 0x99c5,
+ 0x60a6, 0x8b01, 0x8d8a, 0x95b2, 0x698e, 0x53ad, 0x5186, 0xfffd,
+ 0x5712, 0x5830, 0x5944, 0x5bb4, 0x5ef6, 0x6028, 0x63a9, 0x63f4,
+ 0x6cbf, 0x6f14, 0x708e, 0x7114, 0x7159, 0x71d5, 0x733f, 0x7e01,
+ 0x8276, 0x82d1, 0x8597, 0x9060, 0x925b, 0x9d1b, 0x5869, 0x65bc,
+ 0x6c5a, 0x7525, 0x51f9, 0x592e, 0x5965, 0x5f80, 0x5fdc, 0x62bc,
+ 0x65fa, 0x6a2a, 0x6b27, 0x6bb4, 0x738b, 0x7fc1, 0x8956, 0x9d2c,
+ 0x9d0e, 0x9ec4, 0x5ca1, 0x6c96, 0x837b, 0x5104, 0x5c4b, 0x61b6,
+ 0x81c6, 0x6876, 0x7261, 0x4e59, 0x4ffa, 0x5378, 0x6069, 0x6e29,
+ 0x7a4f, 0x97f3, 0x4e0b, 0x5316, 0x4eee, 0x4f55, 0x4f3d, 0x4fa1,
+ 0x4f73, 0x52a0, 0x53ef, 0x5609, 0x590f, 0x5ac1, 0x5bb6, 0x5be1,
+ 0x79d1, 0x6687, 0x679c, 0x67b6, 0x6b4c, 0x6cb3, 0x706b, 0x73c2,
+ 0x798d, 0x79be, 0x7a3c, 0x7b87, 0x82b1, 0x82db, 0x8304, 0x8377,
+ 0x83ef, 0x83d3, 0x8766, 0x8ab2, 0x5629, 0x8ca8, 0x8fe6, 0x904e,
+ 0x971e, 0x868a, 0x4fc4, 0x5ce8, 0x6211, 0x7259, 0x753b, 0x81e5,
+ 0x82bd, 0x86fe, 0x8cc0, 0x96c5, 0x9913, 0x99d5, 0x4ecb, 0x4f1a,
+ 0x89e3, 0x56de, 0x584a, 0x58ca, 0x5efb, 0x5feb, 0x602a, 0x6094,
+ 0x6062, 0x61d0, 0x6212, 0x62d0, 0x6539, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b41, 0x6666, 0x68b0, 0x6d77, 0x7070, 0x754c, 0x7686, 0x7d75,
+ 0x82a5, 0x87f9, 0x958b, 0x968e, 0x8c9d, 0x51f1, 0x52be, 0x5916,
+ 0x54b3, 0x5bb3, 0x5d16, 0x6168, 0x6982, 0x6daf, 0x788d, 0x84cb,
+ 0x8857, 0x8a72, 0x93a7, 0x9ab8, 0x6d6c, 0x99a8, 0x86d9, 0x57a3,
+ 0x67ff, 0x86ce, 0x920e, 0x5283, 0x5687, 0x5404, 0x5ed3, 0x62e1,
+ 0x64b9, 0x683c, 0x6838, 0x6bbb, 0x7372, 0x78ba, 0x7a6b, 0x899a,
+ 0x89d2, 0x8d6b, 0x8f03, 0x90ed, 0x95a3, 0x9694, 0x9769, 0x5b66,
+ 0x5cb3, 0x697d, 0x984d, 0x984e, 0x639b, 0x7b20, 0x6a2b, 0xfffd,
+ 0x6a7f, 0x68b6, 0x9c0d, 0x6f5f, 0x5272, 0x559d, 0x6070, 0x62ec,
+ 0x6d3b, 0x6e07, 0x6ed1, 0x845b, 0x8910, 0x8f44, 0x4e14, 0x9c39,
+ 0x53f6, 0x691b, 0x6a3a, 0x9784, 0x682a, 0x515c, 0x7ac3, 0x84b2,
+ 0x91dc, 0x938c, 0x565b, 0x9d28, 0x6822, 0x8305, 0x8431, 0x7ca5,
+ 0x5208, 0x82c5, 0x74e6, 0x4e7e, 0x4f83, 0x51a0, 0x5bd2, 0x520a,
+ 0x52d8, 0x52e7, 0x5dfb, 0x559a, 0x582a, 0x59e6, 0x5b8c, 0x5b98,
+ 0x5bdb, 0x5e72, 0x5e79, 0x60a3, 0x611f, 0x6163, 0x61be, 0x63db,
+ 0x6562, 0x67d1, 0x6853, 0x68fa, 0x6b3e, 0x6b53, 0x6c57, 0x6f22,
+ 0x6f97, 0x6f45, 0x74b0, 0x7518, 0x76e3, 0x770b, 0x7aff, 0x7ba1,
+ 0x7c21, 0x7de9, 0x7f36, 0x7ff0, 0x809d, 0x8266, 0x839e, 0x89b3,
+ 0x8acc, 0x8cab, 0x9084, 0x9451, 0x9593, 0x9591, 0x95a2, 0x9665,
+ 0x97d3, 0x9928, 0x8218, 0x4e38, 0x542b, 0x5cb8, 0x5dcc, 0x73a9,
+ 0x764c, 0x773c, 0x5ca9, 0x7feb, 0x8d0b, 0x96c1, 0x9811, 0x9854,
+ 0x9858, 0x4f01, 0x4f0e, 0x5371, 0x559c, 0x5668, 0x57fa, 0x5947,
+ 0x5b09, 0x5bc4, 0x5c90, 0x5e0c, 0x5e7e, 0x5fcc, 0x63ee, 0x673a,
+ 0x65d7, 0x65e2, 0x671f, 0x68cb, 0x68c4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x6a5f, 0x5e30, 0x6bc5, 0x6c17, 0x6c7d, 0x757f, 0x7948, 0x5b63,
+ 0x7a00, 0x7d00, 0x5fbd, 0x898f, 0x8a18, 0x8cb4, 0x8d77, 0x8ecc,
+ 0x8f1d, 0x98e2, 0x9a0e, 0x9b3c, 0x4e80, 0x507d, 0x5100, 0x5993,
+ 0x5b9c, 0x622f, 0x6280, 0x64ec, 0x6b3a, 0x72a0, 0x7591, 0x7947,
+ 0x7fa9, 0x87fb, 0x8abc, 0x8b70, 0x63ac, 0x83ca, 0x97a0, 0x5409,
+ 0x5403, 0x55ab, 0x6854, 0x6a58, 0x8a70, 0x7827, 0x6775, 0x9ecd,
+ 0x5374, 0x5ba2, 0x811a, 0x8650, 0x9006, 0x4e18, 0x4e45, 0x4ec7,
+ 0x4f11, 0x53ca, 0x5438, 0x5bae, 0x5f13, 0x6025, 0x6551, 0xfffd,
+ 0x673d, 0x6c42, 0x6c72, 0x6ce3, 0x7078, 0x7403, 0x7a76, 0x7aae,
+ 0x7b08, 0x7d1a, 0x7cfe, 0x7d66, 0x65e7, 0x725b, 0x53bb, 0x5c45,
+ 0x5de8, 0x62d2, 0x62e0, 0x6319, 0x6e20, 0x865a, 0x8a31, 0x8ddd,
+ 0x92f8, 0x6f01, 0x79a6, 0x9b5a, 0x4ea8, 0x4eab, 0x4eac, 0x4f9b,
+ 0x4fa0, 0x50d1, 0x5147, 0x7af6, 0x5171, 0x51f6, 0x5354, 0x5321,
+ 0x537f, 0x53eb, 0x55ac, 0x5883, 0x5ce1, 0x5f37, 0x5f4a, 0x602f,
+ 0x6050, 0x606d, 0x631f, 0x6559, 0x6a4b, 0x6cc1, 0x72c2, 0x72ed,
+ 0x77ef, 0x80f8, 0x8105, 0x8208, 0x854e, 0x90f7, 0x93e1, 0x97ff,
+ 0x9957, 0x9a5a, 0x4ef0, 0x51dd, 0x5c2d, 0x6681, 0x696d, 0x5c40,
+ 0x66f2, 0x6975, 0x7389, 0x6850, 0x7c81, 0x50c5, 0x52e4, 0x5747,
+ 0x5dfe, 0x9326, 0x65a4, 0x6b23, 0x6b3d, 0x7434, 0x7981, 0x79bd,
+ 0x7b4b, 0x7dca, 0x82b9, 0x83cc, 0x887f, 0x895f, 0x8b39, 0x8fd1,
+ 0x91d1, 0x541f, 0x9280, 0x4e5d, 0x5036, 0x53e5, 0x533a, 0x72d7,
+ 0x7396, 0x77e9, 0x82e6, 0x8eaf, 0x99c6, 0x99c8, 0x99d2, 0x5177,
+ 0x611a, 0x865e, 0x55b0, 0x7a7a, 0x5076, 0x5bd3, 0x9047, 0x9685,
+ 0x4e32, 0x6adb, 0x91e7, 0x5c51, 0x5c48, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x6398, 0x7a9f, 0x6c93, 0x9774, 0x8f61, 0x7aaa, 0x718a, 0x9688,
+ 0x7c82, 0x6817, 0x7e70, 0x6851, 0x936c, 0x52f2, 0x541b, 0x85ab,
+ 0x8a13, 0x7fa4, 0x8ecd, 0x90e1, 0x5366, 0x8888, 0x7941, 0x4fc2,
+ 0x50be, 0x5211, 0x5144, 0x5553, 0x572d, 0x73ea, 0x578b, 0x5951,
+ 0x5f62, 0x5f84, 0x6075, 0x6176, 0x6167, 0x61a9, 0x63b2, 0x643a,
+ 0x656c, 0x666f, 0x6842, 0x6e13, 0x7566, 0x7a3d, 0x7cfb, 0x7d4c,
+ 0x7d99, 0x7e4b, 0x7f6b, 0x830e, 0x834a, 0x86cd, 0x8a08, 0x8a63,
+ 0x8b66, 0x8efd, 0x981a, 0x9d8f, 0x82b8, 0x8fce, 0x9be8, 0xfffd,
+ 0x5287, 0x621f, 0x6483, 0x6fc0, 0x9699, 0x6841, 0x5091, 0x6b20,
+ 0x6c7a, 0x6f54, 0x7a74, 0x7d50, 0x8840, 0x8a23, 0x6708, 0x4ef6,
+ 0x5039, 0x5026, 0x5065, 0x517c, 0x5238, 0x5263, 0x55a7, 0x570f,
+ 0x5805, 0x5acc, 0x5efa, 0x61b2, 0x61f8, 0x62f3, 0x6372, 0x691c,
+ 0x6a29, 0x727d, 0x72ac, 0x732e, 0x7814, 0x786f, 0x7d79, 0x770c,
+ 0x80a9, 0x898b, 0x8b19, 0x8ce2, 0x8ed2, 0x9063, 0x9375, 0x967a,
+ 0x9855, 0x9a13, 0x9e78, 0x5143, 0x539f, 0x53b3, 0x5e7b, 0x5f26,
+ 0x6e1b, 0x6e90, 0x7384, 0x73fe, 0x7d43, 0x8237, 0x8a00, 0x8afa,
+ 0x9650, 0x4e4e, 0x500b, 0x53e4, 0x547c, 0x56fa, 0x59d1, 0x5b64,
+ 0x5df1, 0x5eab, 0x5f27, 0x6238, 0x6545, 0x67af, 0x6e56, 0x72d0,
+ 0x7cca, 0x88b4, 0x80a1, 0x80e1, 0x83f0, 0x864e, 0x8a87, 0x8de8,
+ 0x9237, 0x96c7, 0x9867, 0x9f13, 0x4e94, 0x4e92, 0x4f0d, 0x5348,
+ 0x5449, 0x543e, 0x5a2f, 0x5f8c, 0x5fa1, 0x609f, 0x68a7, 0x6a8e,
+ 0x745a, 0x7881, 0x8a9e, 0x8aa4, 0x8b77, 0x9190, 0x4e5e, 0x9bc9,
+ 0x4ea4, 0x4f7c, 0x4faf, 0x5019, 0x5016, 0x5149, 0x516c, 0x529f,
+ 0x52b9, 0x52fe, 0x539a, 0x53e3, 0x5411, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x540e, 0x5589, 0x5751, 0x57a2, 0x597d, 0x5b54, 0x5b5d, 0x5b8f,
+ 0x5de5, 0x5de7, 0x5df7, 0x5e78, 0x5e83, 0x5e9a, 0x5eb7, 0x5f18,
+ 0x6052, 0x614c, 0x6297, 0x62d8, 0x63a7, 0x653b, 0x6602, 0x6643,
+ 0x66f4, 0x676d, 0x6821, 0x6897, 0x69cb, 0x6c5f, 0x6d2a, 0x6d69,
+ 0x6e2f, 0x6e9d, 0x7532, 0x7687, 0x786c, 0x7a3f, 0x7ce0, 0x7d05,
+ 0x7d18, 0x7d5e, 0x7db1, 0x8015, 0x8003, 0x80af, 0x80b1, 0x8154,
+ 0x818f, 0x822a, 0x8352, 0x884c, 0x8861, 0x8b1b, 0x8ca2, 0x8cfc,
+ 0x90ca, 0x9175, 0x9271, 0x783f, 0x92fc, 0x95a4, 0x964d, 0xfffd,
+ 0x9805, 0x9999, 0x9ad8, 0x9d3b, 0x525b, 0x52ab, 0x53f7, 0x5408,
+ 0x58d5, 0x62f7, 0x6fe0, 0x8c6a, 0x8f5f, 0x9eb9, 0x514b, 0x523b,
+ 0x544a, 0x56fd, 0x7a40, 0x9177, 0x9d60, 0x9ed2, 0x7344, 0x6f09,
+ 0x8170, 0x7511, 0x5ffd, 0x60da, 0x9aa8, 0x72db, 0x8fbc, 0x6b64,
+ 0x9803, 0x4eca, 0x56f0, 0x5764, 0x58be, 0x5a5a, 0x6068, 0x61c7,
+ 0x660f, 0x6606, 0x6839, 0x68b1, 0x6df7, 0x75d5, 0x7d3a, 0x826e,
+ 0x9b42, 0x4e9b, 0x4f50, 0x53c9, 0x5506, 0x5d6f, 0x5de6, 0x5dee,
+ 0x67fb, 0x6c99, 0x7473, 0x7802, 0x8a50, 0x9396, 0x88df, 0x5750,
+ 0x5ea7, 0x632b, 0x50b5, 0x50ac, 0x518d, 0x6700, 0x54c9, 0x585e,
+ 0x59bb, 0x5bb0, 0x5f69, 0x624d, 0x63a1, 0x683d, 0x6b73, 0x6e08,
+ 0x707d, 0x91c7, 0x7280, 0x7815, 0x7826, 0x796d, 0x658e, 0x7d30,
+ 0x83dc, 0x88c1, 0x8f09, 0x969b, 0x5264, 0x5728, 0x6750, 0x7f6a,
+ 0x8ca1, 0x51b4, 0x5742, 0x962a, 0x583a, 0x698a, 0x80b4, 0x54b2,
+ 0x5d0e, 0x57fc, 0x7895, 0x9dfa, 0x4f5c, 0x524a, 0x548b, 0x643e,
+ 0x6628, 0x6714, 0x67f5, 0x7a84, 0x7b56, 0x7d22, 0x932f, 0x685c,
+ 0x9bad, 0x7b39, 0x5319, 0x518a, 0x5237, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x5bdf, 0x62f6, 0x64ae, 0x64e6, 0x672d, 0x6bba, 0x85a9, 0x96d1,
+ 0x7690, 0x9bd6, 0x634c, 0x9306, 0x9bab, 0x76bf, 0x6652, 0x4e09,
+ 0x5098, 0x53c2, 0x5c71, 0x60e8, 0x6492, 0x6563, 0x685f, 0x71e6,
+ 0x73ca, 0x7523, 0x7b97, 0x7e82, 0x8695, 0x8b83, 0x8cdb, 0x9178,
+ 0x9910, 0x65ac, 0x66ab, 0x6b8b, 0x4ed5, 0x4ed4, 0x4f3a, 0x4f7f,
+ 0x523a, 0x53f8, 0x53f2, 0x55e3, 0x56db, 0x58eb, 0x59cb, 0x59c9,
+ 0x59ff, 0x5b50, 0x5c4d, 0x5e02, 0x5e2b, 0x5fd7, 0x601d, 0x6307,
+ 0x652f, 0x5b5c, 0x65af, 0x65bd, 0x65e8, 0x679d, 0x6b62, 0xfffd,
+ 0x6b7b, 0x6c0f, 0x7345, 0x7949, 0x79c1, 0x7cf8, 0x7d19, 0x7d2b,
+ 0x80a2, 0x8102, 0x81f3, 0x8996, 0x8a5e, 0x8a69, 0x8a66, 0x8a8c,
+ 0x8aee, 0x8cc7, 0x8cdc, 0x96cc, 0x98fc, 0x6b6f, 0x4e8b, 0x4f3c,
+ 0x4f8d, 0x5150, 0x5b57, 0x5bfa, 0x6148, 0x6301, 0x6642, 0x6b21,
+ 0x6ecb, 0x6cbb, 0x723e, 0x74bd, 0x75d4, 0x78c1, 0x793a, 0x800c,
+ 0x8033, 0x81ea, 0x8494, 0x8f9e, 0x6c50, 0x9e7f, 0x5f0f, 0x8b58,
+ 0x9d2b, 0x7afa, 0x8ef8, 0x5b8d, 0x96eb, 0x4e03, 0x53f1, 0x57f7,
+ 0x5931, 0x5ac9, 0x5ba4, 0x6089, 0x6e7f, 0x6f06, 0x75be, 0x8cea,
+ 0x5b9f, 0x8500, 0x7be0, 0x5072, 0x67f4, 0x829d, 0x5c61, 0x854a,
+ 0x7e1e, 0x820e, 0x5199, 0x5c04, 0x6368, 0x8d66, 0x659c, 0x716e,
+ 0x793e, 0x7d17, 0x8005, 0x8b1d, 0x8eca, 0x906e, 0x86c7, 0x90aa,
+ 0x501f, 0x52fa, 0x5c3a, 0x6753, 0x707c, 0x7235, 0x914c, 0x91c8,
+ 0x932b, 0x82e5, 0x5bc2, 0x5f31, 0x60f9, 0x4e3b, 0x53d6, 0x5b88,
+ 0x624b, 0x6731, 0x6b8a, 0x72e9, 0x73e0, 0x7a2e, 0x816b, 0x8da3,
+ 0x9152, 0x9996, 0x5112, 0x53d7, 0x546a, 0x5bff, 0x6388, 0x6a39,
+ 0x7dac, 0x9700, 0x56da, 0x53ce, 0x5468, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x5b97, 0x5c31, 0x5dde, 0x4fee, 0x6101, 0x62fe, 0x6d32, 0x79c0,
+ 0x79cb, 0x7d42, 0x7e4d, 0x7fd2, 0x81ed, 0x821f, 0x8490, 0x8846,
+ 0x8972, 0x8b90, 0x8e74, 0x8f2f, 0x9031, 0x914b, 0x916c, 0x96c6,
+ 0x919c, 0x4ec0, 0x4f4f, 0x5145, 0x5341, 0x5f93, 0x620e, 0x67d4,
+ 0x6c41, 0x6e0b, 0x7363, 0x7e26, 0x91cd, 0x9283, 0x53d4, 0x5919,
+ 0x5bbf, 0x6dd1, 0x795d, 0x7e2e, 0x7c9b, 0x587e, 0x719f, 0x51fa,
+ 0x8853, 0x8ff0, 0x4fca, 0x5cfb, 0x6625, 0x77ac, 0x7ae3, 0x821c,
+ 0x99ff, 0x51c6, 0x5faa, 0x65ec, 0x696f, 0x6b89, 0x6df3, 0xfffd,
+ 0x6e96, 0x6f64, 0x76fe, 0x7d14, 0x5de1, 0x9075, 0x9187, 0x9806,
+ 0x51e6, 0x521d, 0x6240, 0x6691, 0x66d9, 0x6e1a, 0x5eb6, 0x7dd2,
+ 0x7f72, 0x66f8, 0x85af, 0x85f7, 0x8af8, 0x52a9, 0x53d9, 0x5973,
+ 0x5e8f, 0x5f90, 0x6055, 0x92e4, 0x9664, 0x50b7, 0x511f, 0x52dd,
+ 0x5320, 0x5347, 0x53ec, 0x54e8, 0x5546, 0x5531, 0x5617, 0x5968,
+ 0x59be, 0x5a3c, 0x5bb5, 0x5c06, 0x5c0f, 0x5c11, 0x5c1a, 0x5e84,
+ 0x5e8a, 0x5ee0, 0x5f70, 0x627f, 0x6284, 0x62db, 0x638c, 0x6377,
+ 0x6607, 0x660c, 0x662d, 0x6676, 0x677e, 0x68a2, 0x6a1f, 0x6a35,
+ 0x6cbc, 0x6d88, 0x6e09, 0x6e58, 0x713c, 0x7126, 0x7167, 0x75c7,
+ 0x7701, 0x785d, 0x7901, 0x7965, 0x79f0, 0x7ae0, 0x7b11, 0x7ca7,
+ 0x7d39, 0x8096, 0x83d6, 0x848b, 0x8549, 0x885d, 0x88f3, 0x8a1f,
+ 0x8a3c, 0x8a54, 0x8a73, 0x8c61, 0x8cde, 0x91a4, 0x9266, 0x937e,
+ 0x9418, 0x969c, 0x9798, 0x4e0a, 0x4e08, 0x4e1e, 0x4e57, 0x5197,
+ 0x5270, 0x57ce, 0x5834, 0x58cc, 0x5b22, 0x5e38, 0x60c5, 0x64fe,
+ 0x6761, 0x6756, 0x6d44, 0x72b6, 0x7573, 0x7a63, 0x84b8, 0x8b72,
+ 0x91b8, 0x9320, 0x5631, 0x57f4, 0x98fe, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x62ed, 0x690d, 0x6b96, 0x71ed, 0x7e54, 0x8077, 0x8272, 0x89e6,
+ 0x98df, 0x8755, 0x8fb1, 0x5c3b, 0x4f38, 0x4fe1, 0x4fb5, 0x5507,
+ 0x5a20, 0x5bdd, 0x5be9, 0x5fc3, 0x614e, 0x632f, 0x65b0, 0x664b,
+ 0x68ee, 0x699b, 0x6d78, 0x6df1, 0x7533, 0x75b9, 0x771f, 0x795e,
+ 0x79e6, 0x7d33, 0x81e3, 0x82af, 0x85aa, 0x89aa, 0x8a3a, 0x8eab,
+ 0x8f9b, 0x9032, 0x91dd, 0x9707, 0x4eba, 0x4ec1, 0x5203, 0x5875,
+ 0x58ec, 0x5c0b, 0x751a, 0x5c3d, 0x814e, 0x8a0a, 0x8fc5, 0x9663,
+ 0x976d, 0x7b25, 0x8acf, 0x9808, 0x9162, 0x56f3, 0x53a8, 0xfffd,
+ 0x9017, 0x5439, 0x5782, 0x5e25, 0x63a8, 0x6c34, 0x708a, 0x7761,
+ 0x7c8b, 0x7fe0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968f,
+ 0x745e, 0x9ac4, 0x5d07, 0x5d69, 0x6570, 0x67a2, 0x8da8, 0x96db,
+ 0x636e, 0x6749, 0x6919, 0x83c5, 0x9817, 0x96c0, 0x88fe, 0x6f84,
+ 0x647a, 0x5bf8, 0x4e16, 0x702c, 0x755d, 0x662f, 0x51c4, 0x5236,
+ 0x52e2, 0x59d3, 0x5f81, 0x6027, 0x6210, 0x653f, 0x6574, 0x661f,
+ 0x6674, 0x68f2, 0x6816, 0x6b63, 0x6e05, 0x7272, 0x751f, 0x76db,
+ 0x7cbe, 0x8056, 0x58f0, 0x88fd, 0x897f, 0x8aa0, 0x8a93, 0x8acb,
+ 0x901d, 0x9192, 0x9752, 0x9759, 0x6589, 0x7a0e, 0x8106, 0x96bb,
+ 0x5e2d, 0x60dc, 0x621a, 0x65a5, 0x6614, 0x6790, 0x77f3, 0x7a4d,
+ 0x7c4d, 0x7e3e, 0x810a, 0x8cac, 0x8d64, 0x8de1, 0x8e5f, 0x78a9,
+ 0x5207, 0x62d9, 0x63a5, 0x6442, 0x6298, 0x8a2d, 0x7a83, 0x7bc0,
+ 0x8aac, 0x96ea, 0x7d76, 0x820c, 0x8749, 0x4ed9, 0x5148, 0x5343,
+ 0x5360, 0x5ba3, 0x5c02, 0x5c16, 0x5ddd, 0x6226, 0x6247, 0x64b0,
+ 0x6813, 0x6834, 0x6cc9, 0x6d45, 0x6d17, 0x67d3, 0x6f5c, 0x714e,
+ 0x717d, 0x65cb, 0x7a7f, 0x7bad, 0x7dda, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x7e4a, 0x7fa8, 0x817a, 0x821b, 0x8239, 0x85a6, 0x8a6e, 0x8cce,
+ 0x8df5, 0x9078, 0x9077, 0x92ad, 0x9291, 0x9583, 0x9bae, 0x524d,
+ 0x5584, 0x6f38, 0x7136, 0x5168, 0x7985, 0x7e55, 0x81b3, 0x7cce,
+ 0x564c, 0x5851, 0x5ca8, 0x63aa, 0x66fe, 0x66fd, 0x695a, 0x72d9,
+ 0x758f, 0x758e, 0x790e, 0x7956, 0x79df, 0x7c97, 0x7d20, 0x7d44,
+ 0x8607, 0x8a34, 0x963b, 0x9061, 0x9f20, 0x50e7, 0x5275, 0x53cc,
+ 0x53e2, 0x5009, 0x55aa, 0x58ee, 0x594f, 0x723d, 0x5b8b, 0x5c64,
+ 0x531d, 0x60e3, 0x60f3, 0x635c, 0x6383, 0x633f, 0x63bb, 0xfffd,
+ 0x64cd, 0x65e9, 0x66f9, 0x5de3, 0x69cd, 0x69fd, 0x6f15, 0x71e5,
+ 0x4e89, 0x75e9, 0x76f8, 0x7a93, 0x7cdf, 0x7dcf, 0x7d9c, 0x8061,
+ 0x8349, 0x8358, 0x846c, 0x84bc, 0x85fb, 0x88c5, 0x8d70, 0x9001,
+ 0x906d, 0x9397, 0x971c, 0x9a12, 0x50cf, 0x5897, 0x618e, 0x81d3,
+ 0x8535, 0x8d08, 0x9020, 0x4fc3, 0x5074, 0x5247, 0x5373, 0x606f,
+ 0x6349, 0x675f, 0x6e2c, 0x8db3, 0x901f, 0x4fd7, 0x5c5e, 0x8cca,
+ 0x65cf, 0x7d9a, 0x5352, 0x8896, 0x5176, 0x63c3, 0x5b58, 0x5b6b,
+ 0x5c0a, 0x640d, 0x6751, 0x905c, 0x4ed6, 0x591a, 0x592a, 0x6c70,
+ 0x8a51, 0x553e, 0x5815, 0x59a5, 0x60f0, 0x6253, 0x67c1, 0x8235,
+ 0x6955, 0x9640, 0x99c4, 0x9a28, 0x4f53, 0x5806, 0x5bfe, 0x8010,
+ 0x5cb1, 0x5e2f, 0x5f85, 0x6020, 0x614b, 0x6234, 0x66ff, 0x6cf0,
+ 0x6ede, 0x80ce, 0x817f, 0x82d4, 0x888b, 0x8cb8, 0x9000, 0x902e,
+ 0x968a, 0x9edb, 0x9bdb, 0x4ee3, 0x53f0, 0x5927, 0x7b2c, 0x918d,
+ 0x984c, 0x9df9, 0x6edd, 0x7027, 0x5353, 0x5544, 0x5b85, 0x6258,
+ 0x629e, 0x62d3, 0x6ca2, 0x6fef, 0x7422, 0x8a17, 0x9438, 0x6fc1,
+ 0x8afe, 0x8338, 0x51e7, 0x86f8, 0x53ea, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x53e9, 0x4f46, 0x9054, 0x8fb0, 0x596a, 0x8131, 0x5dfd, 0x7aea,
+ 0x8fbf, 0x68da, 0x8c37, 0x72f8, 0x9c48, 0x6a3d, 0x8ab0, 0x4e39,
+ 0x5358, 0x5606, 0x5766, 0x62c5, 0x63a2, 0x65e6, 0x6b4e, 0x6de1,
+ 0x6e5b, 0x70ad, 0x77ed, 0x7aef, 0x7baa, 0x7dbb, 0x803d, 0x80c6,
+ 0x86cb, 0x8a95, 0x935b, 0x56e3, 0x58c7, 0x5f3e, 0x65ad, 0x6696,
+ 0x6a80, 0x6bb5, 0x7537, 0x8ac7, 0x5024, 0x77e5, 0x5730, 0x5f1b,
+ 0x6065, 0x667a, 0x6c60, 0x75f4, 0x7a1a, 0x7f6e, 0x81f4, 0x8718,
+ 0x9045, 0x99b3, 0x7bc9, 0x755c, 0x7af9, 0x7b51, 0x84c4, 0xfffd,
+ 0x9010, 0x79e9, 0x7a92, 0x8336, 0x5ae1, 0x7740, 0x4e2d, 0x4ef2,
+ 0x5b99, 0x5fe0, 0x62bd, 0x663c, 0x67f1, 0x6ce8, 0x866b, 0x8877,
+ 0x8a3b, 0x914e, 0x92f3, 0x99d0, 0x6a17, 0x7026, 0x732a, 0x82e7,
+ 0x8457, 0x8caf, 0x4e01, 0x5146, 0x51cb, 0x558b, 0x5bf5, 0x5e16,
+ 0x5e33, 0x5e81, 0x5f14, 0x5f35, 0x5f6b, 0x5fb4, 0x61f2, 0x6311,
+ 0x66a2, 0x671d, 0x6f6e, 0x7252, 0x753a, 0x773a, 0x8074, 0x8139,
+ 0x8178, 0x8776, 0x8abf, 0x8adc, 0x8d85, 0x8df3, 0x929a, 0x9577,
+ 0x9802, 0x9ce5, 0x52c5, 0x6357, 0x76f4, 0x6715, 0x6c88, 0x73cd,
+ 0x8cc3, 0x93ae, 0x9673, 0x6d25, 0x589c, 0x690e, 0x69cc, 0x8ffd,
+ 0x939a, 0x75db, 0x901a, 0x585a, 0x6802, 0x63b4, 0x69fb, 0x4f43,
+ 0x6f2c, 0x67d8, 0x8fbb, 0x8526, 0x7db4, 0x9354, 0x693f, 0x6f70,
+ 0x576a, 0x58f7, 0x5b2c, 0x7d2c, 0x722a, 0x540a, 0x91e3, 0x9db4,
+ 0x4ead, 0x4f4e, 0x505c, 0x5075, 0x5243, 0x8c9e, 0x5448, 0x5824,
+ 0x5b9a, 0x5e1d, 0x5e95, 0x5ead, 0x5ef7, 0x5f1f, 0x608c, 0x62b5,
+ 0x633a, 0x63d0, 0x68af, 0x6c40, 0x7887, 0x798e, 0x7a0b, 0x7de0,
+ 0x8247, 0x8a02, 0x8ae6, 0x8e44, 0x9013, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x90b8, 0x912d, 0x91d8, 0x9f0e, 0x6ce5, 0x6458, 0x64e2, 0x6575,
+ 0x6ef4, 0x7684, 0x7b1b, 0x9069, 0x93d1, 0x6eba, 0x54f2, 0x5fb9,
+ 0x64a4, 0x8f4d, 0x8fed, 0x9244, 0x5178, 0x586b, 0x5929, 0x5c55,
+ 0x5e97, 0x6dfb, 0x7e8f, 0x751c, 0x8cbc, 0x8ee2, 0x985b, 0x70b9,
+ 0x4f1d, 0x6bbf, 0x6fb1, 0x7530, 0x96fb, 0x514e, 0x5410, 0x5835,
+ 0x5857, 0x59ac, 0x5c60, 0x5f92, 0x6597, 0x675c, 0x6e21, 0x767b,
+ 0x83df, 0x8ced, 0x9014, 0x90fd, 0x934d, 0x7825, 0x783a, 0x52aa,
+ 0x5ea6, 0x571f, 0x5974, 0x6012, 0x5012, 0x515a, 0x51ac, 0xfffd,
+ 0x51cd, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5b95, 0x5cf6,
+ 0x5d8b, 0x60bc, 0x6295, 0x642d, 0x6771, 0x6843, 0x68bc, 0x68df,
+ 0x76d7, 0x6dd8, 0x6e6f, 0x6d9b, 0x706f, 0x71c8, 0x5f53, 0x75d8,
+ 0x7977, 0x7b49, 0x7b54, 0x7b52, 0x7cd6, 0x7d71, 0x5230, 0x8463,
+ 0x8569, 0x85e4, 0x8a0e, 0x8b04, 0x8c46, 0x8e0f, 0x9003, 0x900f,
+ 0x9419, 0x9676, 0x982d, 0x9a30, 0x95d8, 0x50cd, 0x52d5, 0x540c,
+ 0x5802, 0x5c0e, 0x61a7, 0x649e, 0x6d1e, 0x77b3, 0x7ae5, 0x80f4,
+ 0x8404, 0x9053, 0x9285, 0x5ce0, 0x9d07, 0x533f, 0x5f97, 0x5fb3,
+ 0x6d9c, 0x7279, 0x7763, 0x79bf, 0x7be4, 0x6bd2, 0x72ec, 0x8aad,
+ 0x6803, 0x6a61, 0x51f8, 0x7a81, 0x6934, 0x5c4a, 0x9cf6, 0x82eb,
+ 0x5bc5, 0x9149, 0x701e, 0x5678, 0x5c6f, 0x60c7, 0x6566, 0x6c8c,
+ 0x8c5a, 0x9041, 0x9813, 0x5451, 0x66c7, 0x920d, 0x5948, 0x90a3,
+ 0x5185, 0x4e4d, 0x51ea, 0x8599, 0x8b0e, 0x7058, 0x637a, 0x934b,
+ 0x6962, 0x99b4, 0x7e04, 0x7577, 0x5357, 0x6960, 0x8edf, 0x96e3,
+ 0x6c5d, 0x4e8c, 0x5c3c, 0x5f10, 0x8fe9, 0x5302, 0x8cd1, 0x8089,
+ 0x8679, 0x5eff, 0x65e5, 0x4e73, 0x5165, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x5982, 0x5c3f, 0x97ee, 0x4efb, 0x598a, 0x5fcd, 0x8a8d, 0x6fe1,
+ 0x79b0, 0x7962, 0x5be7, 0x8471, 0x732b, 0x71b1, 0x5e74, 0x5ff5,
+ 0x637b, 0x649a, 0x71c3, 0x7c98, 0x4e43, 0x5efc, 0x4e4b, 0x57dc,
+ 0x56a2, 0x60a9, 0x6fc3, 0x7d0d, 0x80fd, 0x8133, 0x81bf, 0x8fb2,
+ 0x8997, 0x86a4, 0x5df4, 0x628a, 0x64ad, 0x8987, 0x6777, 0x6ce2,
+ 0x6d3e, 0x7436, 0x7834, 0x5a46, 0x7f75, 0x82ad, 0x99ac, 0x4ff3,
+ 0x5ec3, 0x62dd, 0x6392, 0x6557, 0x676f, 0x76c3, 0x724c, 0x80cc,
+ 0x80ba, 0x8f29, 0x914d, 0x500d, 0x57f9, 0x5a92, 0x6885, 0xfffd,
+ 0x6973, 0x7164, 0x72fd, 0x8cb7, 0x58f2, 0x8ce0, 0x966a, 0x9019,
+ 0x877f, 0x79e4, 0x77e7, 0x8429, 0x4f2f, 0x5265, 0x535a, 0x62cd,
+ 0x67cf, 0x6cca, 0x767d, 0x7b94, 0x7c95, 0x8236, 0x8584, 0x8feb,
+ 0x66dd, 0x6f20, 0x7206, 0x7e1b, 0x83ab, 0x99c1, 0x9ea6, 0x51fd,
+ 0x7bb1, 0x7872, 0x7bb8, 0x8087, 0x7b48, 0x6ae8, 0x5e61, 0x808c,
+ 0x7551, 0x7560, 0x516b, 0x9262, 0x6e8c, 0x767a, 0x9197, 0x9aea,
+ 0x4f10, 0x7f70, 0x629c, 0x7b4f, 0x95a5, 0x9ce9, 0x567a, 0x5859,
+ 0x86e4, 0x96bc, 0x4f34, 0x5224, 0x534a, 0x53cd, 0x53db, 0x5e06,
+ 0x642c, 0x6591, 0x677f, 0x6c3e, 0x6c4e, 0x7248, 0x72af, 0x73ed,
+ 0x7554, 0x7e41, 0x822c, 0x85e9, 0x8ca9, 0x7bc4, 0x91c6, 0x7169,
+ 0x9812, 0x98ef, 0x633d, 0x6669, 0x756a, 0x76e4, 0x78d0, 0x8543,
+ 0x86ee, 0x532a, 0x5351, 0x5426, 0x5983, 0x5e87, 0x5f7c, 0x60b2,
+ 0x6249, 0x6279, 0x62ab, 0x6590, 0x6bd4, 0x6ccc, 0x75b2, 0x76ae,
+ 0x7891, 0x79d8, 0x7dcb, 0x7f77, 0x80a5, 0x88ab, 0x8ab9, 0x8cbb,
+ 0x907f, 0x975e, 0x98db, 0x6a0b, 0x7c38, 0x5099, 0x5c3e, 0x5fae,
+ 0x6787, 0x6bd8, 0x7435, 0x7709, 0x7f8e, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9f3b, 0x67ca, 0x7a17, 0x5339, 0x758b, 0x9aed, 0x5f66, 0x819d,
+ 0x83f1, 0x8098, 0x5f3c, 0x5fc5, 0x7562, 0x7b46, 0x903c, 0x6867,
+ 0x59eb, 0x5a9b, 0x7d10, 0x767e, 0x8b2c, 0x4ff5, 0x5f6a, 0x6a19,
+ 0x6c37, 0x6f02, 0x74e2, 0x7968, 0x8868, 0x8a55, 0x8c79, 0x5edf,
+ 0x63cf, 0x75c5, 0x79d2, 0x82d7, 0x9328, 0x92f2, 0x849c, 0x86ed,
+ 0x9c2d, 0x54c1, 0x5f6c, 0x658c, 0x6d5c, 0x7015, 0x8ca7, 0x8cd3,
+ 0x983b, 0x654f, 0x74f6, 0x4e0d, 0x4ed8, 0x57e0, 0x592b, 0x5a66,
+ 0x5bcc, 0x51a8, 0x5e03, 0x5e9c, 0x6016, 0x6276, 0x6577, 0xfffd,
+ 0x65a7, 0x666e, 0x6d6e, 0x7236, 0x7b26, 0x8150, 0x819a, 0x8299,
+ 0x8b5c, 0x8ca0, 0x8ce6, 0x8d74, 0x961c, 0x9644, 0x4fae, 0x64ab,
+ 0x6b66, 0x821e, 0x8461, 0x856a, 0x90e8, 0x5c01, 0x6953, 0x98a8,
+ 0x847a, 0x8557, 0x4f0f, 0x526f, 0x5fa9, 0x5e45, 0x670d, 0x798f,
+ 0x8179, 0x8907, 0x8986, 0x6df5, 0x5f17, 0x6255, 0x6cb8, 0x4ecf,
+ 0x7269, 0x9b92, 0x5206, 0x543b, 0x5674, 0x58b3, 0x61a4, 0x626e,
+ 0x711a, 0x596e, 0x7c89, 0x7cde, 0x7d1b, 0x96f0, 0x6587, 0x805e,
+ 0x4e19, 0x4f75, 0x5175, 0x5840, 0x5e63, 0x5e73, 0x5f0a, 0x67c4,
+ 0x4e26, 0x853d, 0x9589, 0x965b, 0x7c73, 0x9801, 0x50fb, 0x58c1,
+ 0x7656, 0x78a7, 0x5225, 0x77a5, 0x8511, 0x7b86, 0x504f, 0x5909,
+ 0x7247, 0x7bc7, 0x7de8, 0x8fba, 0x8fd4, 0x904d, 0x4fbf, 0x52c9,
+ 0x5a29, 0x5f01, 0x97ad, 0x4fdd, 0x8217, 0x92ea, 0x5703, 0x6355,
+ 0x6b69, 0x752b, 0x88dc, 0x8f14, 0x7a42, 0x52df, 0x5893, 0x6155,
+ 0x620a, 0x66ae, 0x6bcd, 0x7c3f, 0x83e9, 0x5023, 0x4ff8, 0x5305,
+ 0x5446, 0x5831, 0x5949, 0x5b9d, 0x5cf0, 0x5cef, 0x5d29, 0x5e96,
+ 0x62b1, 0x6367, 0x653e, 0x65b9, 0x670b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x6cd5, 0x6ce1, 0x70f9, 0x7832, 0x7e2b, 0x80de, 0x82b3, 0x840c,
+ 0x84ec, 0x8702, 0x8912, 0x8a2a, 0x8c4a, 0x90a6, 0x92d2, 0x98fd,
+ 0x9cf3, 0x9d6c, 0x4e4f, 0x4ea1, 0x508d, 0x5256, 0x574a, 0x59a8,
+ 0x5e3d, 0x5fd8, 0x5fd9, 0x623f, 0x66b4, 0x671b, 0x67d0, 0x68d2,
+ 0x5192, 0x7d21, 0x80aa, 0x81a8, 0x8b00, 0x8c8c, 0x8cbf, 0x927e,
+ 0x9632, 0x5420, 0x982c, 0x5317, 0x50d5, 0x535c, 0x58a8, 0x64b2,
+ 0x6734, 0x7267, 0x7766, 0x7a46, 0x91e6, 0x52c3, 0x6ca1, 0x6b86,
+ 0x5800, 0x5e4c, 0x5954, 0x672c, 0x7ffb, 0x51e1, 0x76c6, 0xfffd,
+ 0x6469, 0x78e8, 0x9b54, 0x9ebb, 0x57cb, 0x59b9, 0x6627, 0x679a,
+ 0x6bce, 0x54e9, 0x69d9, 0x5e55, 0x819c, 0x6795, 0x9baa, 0x67fe,
+ 0x9c52, 0x685d, 0x4ea6, 0x4fe3, 0x53c8, 0x62b9, 0x672b, 0x6cab,
+ 0x8fc4, 0x4fad, 0x7e6d, 0x9ebf, 0x4e07, 0x6162, 0x6e80, 0x6f2b,
+ 0x8513, 0x5473, 0x672a, 0x9b45, 0x5df3, 0x7b95, 0x5cac, 0x5bc6,
+ 0x871c, 0x6e4a, 0x84d1, 0x7a14, 0x8108, 0x5999, 0x7c8d, 0x6c11,
+ 0x7720, 0x52d9, 0x5922, 0x7121, 0x725f, 0x77db, 0x9727, 0x9d61,
+ 0x690b, 0x5a7f, 0x5a18, 0x51a5, 0x540d, 0x547d, 0x660e, 0x76df,
+ 0x8ff7, 0x9298, 0x9cf4, 0x59ea, 0x725d, 0x6ec5, 0x514d, 0x68c9,
+ 0x7dbf, 0x7dec, 0x9762, 0x9eba, 0x6478, 0x6a21, 0x8302, 0x5984,
+ 0x5b5f, 0x6bdb, 0x731b, 0x76f2, 0x7db2, 0x8017, 0x8499, 0x5132,
+ 0x6728, 0x9ed9, 0x76ee, 0x6762, 0x52ff, 0x9905, 0x5c24, 0x623b,
+ 0x7c7e, 0x8cb0, 0x554f, 0x60b6, 0x7d0b, 0x9580, 0x5301, 0x4e5f,
+ 0x51b6, 0x591c, 0x723a, 0x8036, 0x91ce, 0x5f25, 0x77e2, 0x5384,
+ 0x5f79, 0x7d04, 0x85ac, 0x8a33, 0x8e8d, 0x9756, 0x67f3, 0x85ae,
+ 0x9453, 0x6109, 0x6108, 0x6cb9, 0x7652, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8aed, 0x8f38, 0x552f, 0x4f51, 0x512a, 0x52c7, 0x53cb, 0x5ba5,
+ 0x5e7d, 0x60a0, 0x6182, 0x63d6, 0x6709, 0x67da, 0x6e67, 0x6d8c,
+ 0x7336, 0x7337, 0x7531, 0x7950, 0x88d5, 0x8a98, 0x904a, 0x9091,
+ 0x90f5, 0x96c4, 0x878d, 0x5915, 0x4e88, 0x4f59, 0x4e0e, 0x8a89,
+ 0x8f3f, 0x9810, 0x50ad, 0x5e7c, 0x5996, 0x5bb9, 0x5eb8, 0x63da,
+ 0x63fa, 0x64c1, 0x66dc, 0x694a, 0x69d8, 0x6d0b, 0x6eb6, 0x7194,
+ 0x7528, 0x7aaf, 0x7f8a, 0x8000, 0x8449, 0x84c9, 0x8981, 0x8b21,
+ 0x8e0a, 0x9065, 0x967d, 0x990a, 0x617e, 0x6291, 0x6b32, 0xfffd,
+ 0x6c83, 0x6d74, 0x7fcc, 0x7ffc, 0x6dc0, 0x7f85, 0x87ba, 0x88f8,
+ 0x6765, 0x83b1, 0x983c, 0x96f7, 0x6d1b, 0x7d61, 0x843d, 0x916a,
+ 0x4e71, 0x5375, 0x5d50, 0x6b04, 0x6feb, 0x85cd, 0x862d, 0x89a7,
+ 0x5229, 0x540f, 0x5c65, 0x674e, 0x68a8, 0x7406, 0x7483, 0x75e2,
+ 0x88cf, 0x88e1, 0x91cc, 0x96e2, 0x9678, 0x5f8b, 0x7387, 0x7acb,
+ 0x844e, 0x63a0, 0x7565, 0x5289, 0x6d41, 0x6e9c, 0x7409, 0x7559,
+ 0x786b, 0x7c92, 0x9686, 0x7adc, 0x9f8d, 0x4fb6, 0x616e, 0x65c5,
+ 0x865c, 0x4e86, 0x4eae, 0x50da, 0x4e21, 0x51cc, 0x5bee, 0x6599,
+ 0x6881, 0x6dbc, 0x731f, 0x7642, 0x77ad, 0x7a1c, 0x7ce7, 0x826f,
+ 0x8ad2, 0x907c, 0x91cf, 0x9675, 0x9818, 0x529b, 0x7dd1, 0x502b,
+ 0x5398, 0x6797, 0x6dcb, 0x71d0, 0x7433, 0x81e8, 0x8f2a, 0x96a3,
+ 0x9c57, 0x9e9f, 0x7460, 0x5841, 0x6d99, 0x7d2f, 0x985e, 0x4ee4,
+ 0x4f36, 0x4f8b, 0x51b7, 0x52b1, 0x5dba, 0x601c, 0x73b2, 0x793c,
+ 0x82d3, 0x9234, 0x96b7, 0x96f6, 0x970a, 0x9e97, 0x9f62, 0x66a6,
+ 0x6b74, 0x5217, 0x52a3, 0x70c8, 0x88c2, 0x5ec9, 0x604b, 0x6190,
+ 0x6f23, 0x7149, 0x7c3e, 0x7df4, 0x806f, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x84ee, 0x9023, 0x932c, 0x5442, 0x9b6f, 0x6ad3, 0x7089, 0x8cc2,
+ 0x8def, 0x9732, 0x52b4, 0x5a41, 0x5eca, 0x5f04, 0x6717, 0x697c,
+ 0x6994, 0x6d6a, 0x6f0f, 0x7262, 0x72fc, 0x7bed, 0x8001, 0x807e,
+ 0x874b, 0x90ce, 0x516d, 0x9e93, 0x7984, 0x808b, 0x9332, 0x8ad6,
+ 0x502d, 0x548c, 0x8a71, 0x6b6a, 0x8cc4, 0x8107, 0x60d1, 0x67a0,
+ 0x9df2, 0x4e99, 0x4e98, 0x9c10, 0x8a6b, 0x85c1, 0x8568, 0x6900,
+ 0x6e7e, 0x7897, 0x8155, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5f0c,
+ 0x4e10, 0x4e15, 0x4e2a, 0x4e31, 0x4e36, 0x4e3c, 0x4e3f, 0x4e42,
+ 0x4e56, 0x4e58, 0x4e82, 0x4e85, 0x8c6b, 0x4e8a, 0x8212, 0x5f0d,
+ 0x4e8e, 0x4e9e, 0x4e9f, 0x4ea0, 0x4ea2, 0x4eb0, 0x4eb3, 0x4eb6,
+ 0x4ece, 0x4ecd, 0x4ec4, 0x4ec6, 0x4ec2, 0x4ed7, 0x4ede, 0x4eed,
+ 0x4edf, 0x4ef7, 0x4f09, 0x4f5a, 0x4f30, 0x4f5b, 0x4f5d, 0x4f57,
+ 0x4f47, 0x4f76, 0x4f88, 0x4f8f, 0x4f98, 0x4f7b, 0x4f69, 0x4f70,
+ 0x4f91, 0x4f6f, 0x4f86, 0x4f96, 0x5118, 0x4fd4, 0x4fdf, 0x4fce,
+ 0x4fd8, 0x4fdb, 0x4fd1, 0x4fda, 0x4fd0, 0x4fe4, 0x4fe5, 0x501a,
+ 0x5028, 0x5014, 0x502a, 0x5025, 0x5005, 0x4f1c, 0x4ff6, 0x5021,
+ 0x5029, 0x502c, 0x4ffe, 0x4fef, 0x5011, 0x5006, 0x5043, 0x5047,
+ 0x6703, 0x5055, 0x5050, 0x5048, 0x505a, 0x5056, 0x506c, 0x5078,
+ 0x5080, 0x509a, 0x5085, 0x50b4, 0x50b2, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x50c9, 0x50ca, 0x50b3, 0x50c2, 0x50d6, 0x50de, 0x50e5, 0x50ed,
+ 0x50e3, 0x50ee, 0x50f9, 0x50f5, 0x5109, 0x5101, 0x5102, 0x5116,
+ 0x5115, 0x5114, 0x511a, 0x5121, 0x513a, 0x5137, 0x513c, 0x513b,
+ 0x513f, 0x5140, 0x5152, 0x514c, 0x5154, 0x5162, 0x7af8, 0x5169,
+ 0x516a, 0x516e, 0x5180, 0x5182, 0x56d8, 0x518c, 0x5189, 0x518f,
+ 0x5191, 0x5193, 0x5195, 0x5196, 0x51a4, 0x51a6, 0x51a2, 0x51a9,
+ 0x51aa, 0x51ab, 0x51b3, 0x51b1, 0x51b2, 0x51b0, 0x51b5, 0x51bd,
+ 0x51c5, 0x51c9, 0x51db, 0x51e0, 0x8655, 0x51e9, 0x51ed, 0xfffd,
+ 0x51f0, 0x51f5, 0x51fe, 0x5204, 0x520b, 0x5214, 0x520e, 0x5227,
+ 0x522a, 0x522e, 0x5233, 0x5239, 0x524f, 0x5244, 0x524b, 0x524c,
+ 0x525e, 0x5254, 0x526a, 0x5274, 0x5269, 0x5273, 0x527f, 0x527d,
+ 0x528d, 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8fa8, 0x8fa7,
+ 0x52ac, 0x52ad, 0x52bc, 0x52b5, 0x52c1, 0x52cd, 0x52d7, 0x52de,
+ 0x52e3, 0x52e6, 0x98ed, 0x52e0, 0x52f3, 0x52f5, 0x52f8, 0x52f9,
+ 0x5306, 0x5308, 0x7538, 0x530d, 0x5310, 0x530f, 0x5315, 0x531a,
+ 0x5323, 0x532f, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, 0x5345,
+ 0x4e17, 0x5349, 0x534d, 0x51d6, 0x535e, 0x5369, 0x536e, 0x5918,
+ 0x537b, 0x5377, 0x5382, 0x5396, 0x53a0, 0x53a6, 0x53a5, 0x53ae,
+ 0x53b0, 0x53b6, 0x53c3, 0x7c12, 0x96d9, 0x53df, 0x66fc, 0x71ee,
+ 0x53ee, 0x53e8, 0x53ed, 0x53fa, 0x5401, 0x543d, 0x5440, 0x542c,
+ 0x542d, 0x543c, 0x542e, 0x5436, 0x5429, 0x541d, 0x544e, 0x548f,
+ 0x5475, 0x548e, 0x545f, 0x5471, 0x5477, 0x5470, 0x5492, 0x547b,
+ 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54c7, 0x54a2, 0x54b8,
+ 0x54a5, 0x54ac, 0x54c4, 0x54c8, 0x54a8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x54ab, 0x54c2, 0x54a4, 0x54be, 0x54bc, 0x54d8, 0x54e5, 0x54e6,
+ 0x550f, 0x5514, 0x54fd, 0x54ee, 0x54ed, 0x54fa, 0x54e2, 0x5539,
+ 0x5540, 0x5563, 0x554c, 0x552e, 0x555c, 0x5545, 0x5556, 0x5557,
+ 0x5538, 0x5533, 0x555d, 0x5599, 0x5580, 0x54af, 0x558a, 0x559f,
+ 0x557b, 0x557e, 0x5598, 0x559e, 0x55ae, 0x557c, 0x5583, 0x55a9,
+ 0x5587, 0x55a8, 0x55da, 0x55c5, 0x55df, 0x55c4, 0x55dc, 0x55e4,
+ 0x55d4, 0x5614, 0x55f7, 0x5616, 0x55fe, 0x55fd, 0x561b, 0x55f9,
+ 0x564e, 0x5650, 0x71df, 0x5634, 0x5636, 0x5632, 0x5638, 0xfffd,
+ 0x566b, 0x5664, 0x562f, 0x566c, 0x566a, 0x5686, 0x5680, 0x568a,
+ 0x56a0, 0x5694, 0x568f, 0x56a5, 0x56ae, 0x56b6, 0x56b4, 0x56c2,
+ 0x56bc, 0x56c1, 0x56c3, 0x56c0, 0x56c8, 0x56ce, 0x56d1, 0x56d3,
+ 0x56d7, 0x56ee, 0x56f9, 0x5700, 0x56ff, 0x5704, 0x5709, 0x5708,
+ 0x570b, 0x570d, 0x5713, 0x5718, 0x5716, 0x55c7, 0x571c, 0x5726,
+ 0x5737, 0x5738, 0x574e, 0x573b, 0x5740, 0x574f, 0x5769, 0x57c0,
+ 0x5788, 0x5761, 0x577f, 0x5789, 0x5793, 0x57a0, 0x57b3, 0x57a4,
+ 0x57aa, 0x57b0, 0x57c3, 0x57c6, 0x57d4, 0x57d2, 0x57d3, 0x580a,
+ 0x57d6, 0x57e3, 0x580b, 0x5819, 0x581d, 0x5872, 0x5821, 0x5862,
+ 0x584b, 0x5870, 0x6bc0, 0x5852, 0x583d, 0x5879, 0x5885, 0x58b9,
+ 0x589f, 0x58ab, 0x58ba, 0x58de, 0x58bb, 0x58b8, 0x58ae, 0x58c5,
+ 0x58d3, 0x58d1, 0x58d7, 0x58d9, 0x58d8, 0x58e5, 0x58dc, 0x58e4,
+ 0x58df, 0x58ef, 0x58fa, 0x58f9, 0x58fb, 0x58fc, 0x58fd, 0x5902,
+ 0x590a, 0x5910, 0x591b, 0x68a6, 0x5925, 0x592c, 0x592d, 0x5932,
+ 0x5938, 0x593e, 0x7ad2, 0x5955, 0x5950, 0x594e, 0x595a, 0x5958,
+ 0x5962, 0x5960, 0x5967, 0x596c, 0x5969, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x5978, 0x5981, 0x599d, 0x4f5e, 0x4fab, 0x59a3, 0x59b2, 0x59c6,
+ 0x59e8, 0x59dc, 0x598d, 0x59d9, 0x59da, 0x5a25, 0x5a1f, 0x5a11,
+ 0x5a1c, 0x5a09, 0x5a1a, 0x5a40, 0x5a6c, 0x5a49, 0x5a35, 0x5a36,
+ 0x5a62, 0x5a6a, 0x5a9a, 0x5abc, 0x5abe, 0x5acb, 0x5ac2, 0x5abd,
+ 0x5ae3, 0x5ad7, 0x5ae6, 0x5ae9, 0x5ad6, 0x5afa, 0x5afb, 0x5b0c,
+ 0x5b0b, 0x5b16, 0x5b32, 0x5ad0, 0x5b2a, 0x5b36, 0x5b3e, 0x5b43,
+ 0x5b45, 0x5b40, 0x5b51, 0x5b55, 0x5b5a, 0x5b5b, 0x5b65, 0x5b69,
+ 0x5b70, 0x5b73, 0x5b75, 0x5b78, 0x6588, 0x5b7a, 0x5b80, 0xfffd,
+ 0x5b83, 0x5ba6, 0x5bb8, 0x5bc3, 0x5bc7, 0x5bc9, 0x5bd4, 0x5bd0,
+ 0x5be4, 0x5be6, 0x5be2, 0x5bde, 0x5be5, 0x5beb, 0x5bf0, 0x5bf6,
+ 0x5bf3, 0x5c05, 0x5c07, 0x5c08, 0x5c0d, 0x5c13, 0x5c20, 0x5c22,
+ 0x5c28, 0x5c38, 0x5c39, 0x5c41, 0x5c46, 0x5c4e, 0x5c53, 0x5c50,
+ 0x5c4f, 0x5b71, 0x5c6c, 0x5c6e, 0x4e62, 0x5c76, 0x5c79, 0x5c8c,
+ 0x5c91, 0x5c94, 0x599b, 0x5cab, 0x5cbb, 0x5cb6, 0x5cbc, 0x5cb7,
+ 0x5cc5, 0x5cbe, 0x5cc7, 0x5cd9, 0x5ce9, 0x5cfd, 0x5cfa, 0x5ced,
+ 0x5d8c, 0x5cea, 0x5d0b, 0x5d15, 0x5d17, 0x5d5c, 0x5d1f, 0x5d1b,
+ 0x5d11, 0x5d14, 0x5d22, 0x5d1a, 0x5d19, 0x5d18, 0x5d4c, 0x5d52,
+ 0x5d4e, 0x5d4b, 0x5d6c, 0x5d73, 0x5d76, 0x5d87, 0x5d84, 0x5d82,
+ 0x5da2, 0x5d9d, 0x5dac, 0x5dae, 0x5dbd, 0x5d90, 0x5db7, 0x5dbc,
+ 0x5dc9, 0x5dcd, 0x5dd3, 0x5dd2, 0x5dd6, 0x5ddb, 0x5deb, 0x5df2,
+ 0x5df5, 0x5e0b, 0x5e1a, 0x5e19, 0x5e11, 0x5e1b, 0x5e36, 0x5e37,
+ 0x5e44, 0x5e43, 0x5e40, 0x5e4e, 0x5e57, 0x5e54, 0x5e5f, 0x5e62,
+ 0x5e64, 0x5e47, 0x5e75, 0x5e76, 0x5e7a, 0x9ebc, 0x5e7f, 0x5ea0,
+ 0x5ec1, 0x5ec2, 0x5ec8, 0x5ed0, 0x5ecf, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x5ed6, 0x5ee3, 0x5edd, 0x5eda, 0x5edb, 0x5ee2, 0x5ee1, 0x5ee8,
+ 0x5ee9, 0x5eec, 0x5ef1, 0x5ef3, 0x5ef0, 0x5ef4, 0x5ef8, 0x5efe,
+ 0x5f03, 0x5f09, 0x5f5d, 0x5f5c, 0x5f0b, 0x5f11, 0x5f16, 0x5f29,
+ 0x5f2d, 0x5f38, 0x5f41, 0x5f48, 0x5f4c, 0x5f4e, 0x5f2f, 0x5f51,
+ 0x5f56, 0x5f57, 0x5f59, 0x5f61, 0x5f6d, 0x5f73, 0x5f77, 0x5f83,
+ 0x5f82, 0x5f7f, 0x5f8a, 0x5f88, 0x5f91, 0x5f87, 0x5f9e, 0x5f99,
+ 0x5f98, 0x5fa0, 0x5fa8, 0x5fad, 0x5fbc, 0x5fd6, 0x5ffb, 0x5fe4,
+ 0x5ff8, 0x5ff1, 0x5fdd, 0x60b3, 0x5fff, 0x6021, 0x6060, 0xfffd,
+ 0x6019, 0x6010, 0x6029, 0x600e, 0x6031, 0x601b, 0x6015, 0x602b,
+ 0x6026, 0x600f, 0x603a, 0x605a, 0x6041, 0x606a, 0x6077, 0x605f,
+ 0x604a, 0x6046, 0x604d, 0x6063, 0x6043, 0x6064, 0x6042, 0x606c,
+ 0x606b, 0x6059, 0x6081, 0x608d, 0x60e7, 0x6083, 0x609a, 0x6084,
+ 0x609b, 0x6096, 0x6097, 0x6092, 0x60a7, 0x608b, 0x60e1, 0x60b8,
+ 0x60e0, 0x60d3, 0x60b4, 0x5ff0, 0x60bd, 0x60c6, 0x60b5, 0x60d8,
+ 0x614d, 0x6115, 0x6106, 0x60f6, 0x60f7, 0x6100, 0x60f4, 0x60fa,
+ 0x6103, 0x6121, 0x60fb, 0x60f1, 0x610d, 0x610e, 0x6147, 0x613e,
+ 0x6128, 0x6127, 0x614a, 0x613f, 0x613c, 0x612c, 0x6134, 0x613d,
+ 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615a, 0x616b,
+ 0x6174, 0x616f, 0x6165, 0x6171, 0x615f, 0x615d, 0x6153, 0x6175,
+ 0x6199, 0x6196, 0x6187, 0x61ac, 0x6194, 0x619a, 0x618a, 0x6191,
+ 0x61ab, 0x61ae, 0x61cc, 0x61ca, 0x61c9, 0x61f7, 0x61c8, 0x61c3,
+ 0x61c6, 0x61ba, 0x61cb, 0x7f79, 0x61cd, 0x61e6, 0x61e3, 0x61f6,
+ 0x61fa, 0x61f4, 0x61ff, 0x61fd, 0x61fc, 0x61fe, 0x6200, 0x6208,
+ 0x6209, 0x620d, 0x620c, 0x6214, 0x621b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x621e, 0x6221, 0x622a, 0x622e, 0x6230, 0x6232, 0x6233, 0x6241,
+ 0x624e, 0x625e, 0x6263, 0x625b, 0x6260, 0x6268, 0x627c, 0x6282,
+ 0x6289, 0x627e, 0x6292, 0x6293, 0x6296, 0x62d4, 0x6283, 0x6294,
+ 0x62d7, 0x62d1, 0x62bb, 0x62cf, 0x62ff, 0x62c6, 0x64d4, 0x62c8,
+ 0x62dc, 0x62cc, 0x62ca, 0x62c2, 0x62c7, 0x629b, 0x62c9, 0x630c,
+ 0x62ee, 0x62f1, 0x6327, 0x6302, 0x6308, 0x62ef, 0x62f5, 0x6350,
+ 0x633e, 0x634d, 0x641c, 0x634f, 0x6396, 0x638e, 0x6380, 0x63ab,
+ 0x6376, 0x63a3, 0x638f, 0x6389, 0x639f, 0x63b5, 0x636b, 0xfffd,
+ 0x6369, 0x63be, 0x63e9, 0x63c0, 0x63c6, 0x63e3, 0x63c9, 0x63d2,
+ 0x63f6, 0x63c4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436,
+ 0x651d, 0x6417, 0x6428, 0x640f, 0x6467, 0x646f, 0x6476, 0x644e,
+ 0x652a, 0x6495, 0x6493, 0x64a5, 0x64a9, 0x6488, 0x64bc, 0x64da,
+ 0x64d2, 0x64c5, 0x64c7, 0x64bb, 0x64d8, 0x64c2, 0x64f1, 0x64e7,
+ 0x8209, 0x64e0, 0x64e1, 0x62ac, 0x64e3, 0x64ef, 0x652c, 0x64f6,
+ 0x64f4, 0x64f2, 0x64fa, 0x6500, 0x64fd, 0x6518, 0x651c, 0x6505,
+ 0x6524, 0x6523, 0x652b, 0x6534, 0x6535, 0x6537, 0x6536, 0x6538,
+ 0x754b, 0x6548, 0x6556, 0x6555, 0x654d, 0x6558, 0x655e, 0x655d,
+ 0x6572, 0x6578, 0x6582, 0x6583, 0x8b8a, 0x659b, 0x659f, 0x65ab,
+ 0x65b7, 0x65c3, 0x65c6, 0x65c1, 0x65c4, 0x65cc, 0x65d2, 0x65db,
+ 0x65d9, 0x65e0, 0x65e1, 0x65f1, 0x6772, 0x660a, 0x6603, 0x65fb,
+ 0x6773, 0x6635, 0x6636, 0x6634, 0x661c, 0x664f, 0x6644, 0x6649,
+ 0x6641, 0x665e, 0x665d, 0x6664, 0x6667, 0x6668, 0x665f, 0x6662,
+ 0x6670, 0x6683, 0x6688, 0x668e, 0x6689, 0x6684, 0x6698, 0x669d,
+ 0x66c1, 0x66b9, 0x66c9, 0x66be, 0x66bc, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x66c4, 0x66b8, 0x66d6, 0x66da, 0x66e0, 0x663f, 0x66e6, 0x66e9,
+ 0x66f0, 0x66f5, 0x66f7, 0x670f, 0x6716, 0x671e, 0x6726, 0x6727,
+ 0x9738, 0x672e, 0x673f, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746,
+ 0x675e, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67a9,
+ 0x677c, 0x676a, 0x678c, 0x678b, 0x67a6, 0x67a1, 0x6785, 0x67b7,
+ 0x67ef, 0x67b4, 0x67ec, 0x67b3, 0x67e9, 0x67b8, 0x67e4, 0x67de,
+ 0x67dd, 0x67e2, 0x67ee, 0x67b9, 0x67ce, 0x67c6, 0x67e7, 0x6a9c,
+ 0x681e, 0x6846, 0x6829, 0x6840, 0x684d, 0x6832, 0x684e, 0xfffd,
+ 0x68b3, 0x682b, 0x6859, 0x6863, 0x6877, 0x687f, 0x689f, 0x688f,
+ 0x68ad, 0x6894, 0x689d, 0x689b, 0x6883, 0x6aae, 0x68b9, 0x6874,
+ 0x68b5, 0x68a0, 0x68ba, 0x690f, 0x688d, 0x687e, 0x6901, 0x68ca,
+ 0x6908, 0x68d8, 0x6922, 0x6926, 0x68e1, 0x690c, 0x68cd, 0x68d4,
+ 0x68e7, 0x68d5, 0x6936, 0x6912, 0x6904, 0x68d7, 0x68e3, 0x6925,
+ 0x68f9, 0x68e0, 0x68ef, 0x6928, 0x692a, 0x691a, 0x6923, 0x6921,
+ 0x68c6, 0x6979, 0x6977, 0x695c, 0x6978, 0x696b, 0x6954, 0x697e,
+ 0x696e, 0x6939, 0x6974, 0x693d, 0x6959, 0x6930, 0x6961, 0x695e,
+ 0x695d, 0x6981, 0x696a, 0x69b2, 0x69ae, 0x69d0, 0x69bf, 0x69c1,
+ 0x69d3, 0x69be, 0x69ce, 0x5be8, 0x69ca, 0x69dd, 0x69bb, 0x69c3,
+ 0x69a7, 0x6a2e, 0x6991, 0x69a0, 0x699c, 0x6995, 0x69b4, 0x69de,
+ 0x69e8, 0x6a02, 0x6a1b, 0x69ff, 0x6b0a, 0x69f9, 0x69f2, 0x69e7,
+ 0x6a05, 0x69b1, 0x6a1e, 0x69ed, 0x6a14, 0x69eb, 0x6a0a, 0x6a12,
+ 0x6ac1, 0x6a23, 0x6a13, 0x6a44, 0x6a0c, 0x6a72, 0x6a36, 0x6a78,
+ 0x6a47, 0x6a62, 0x6a59, 0x6a66, 0x6a48, 0x6a38, 0x6a22, 0x6a90,
+ 0x6a8d, 0x6aa0, 0x6a84, 0x6aa2, 0x6aa3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x6a97, 0x8617, 0x6abb, 0x6ac3, 0x6ac2, 0x6ab8, 0x6ab3, 0x6aac,
+ 0x6ade, 0x6ad1, 0x6adf, 0x6aaa, 0x6ada, 0x6aea, 0x6afb, 0x6b05,
+ 0x8616, 0x6afa, 0x6b12, 0x6b16, 0x9b31, 0x6b1f, 0x6b38, 0x6b37,
+ 0x76dc, 0x6b39, 0x98ee, 0x6b47, 0x6b43, 0x6b49, 0x6b50, 0x6b59,
+ 0x6b54, 0x6b5b, 0x6b5f, 0x6b61, 0x6b78, 0x6b79, 0x6b7f, 0x6b80,
+ 0x6b84, 0x6b83, 0x6b8d, 0x6b98, 0x6b95, 0x6b9e, 0x6ba4, 0x6baa,
+ 0x6bab, 0x6baf, 0x6bb2, 0x6bb1, 0x6bb3, 0x6bb7, 0x6bbc, 0x6bc6,
+ 0x6bcb, 0x6bd3, 0x6bdf, 0x6bec, 0x6beb, 0x6bf3, 0x6bef, 0xfffd,
+ 0x9ebe, 0x6c08, 0x6c13, 0x6c14, 0x6c1b, 0x6c24, 0x6c23, 0x6c5e,
+ 0x6c55, 0x6c62, 0x6c6a, 0x6c82, 0x6c8d, 0x6c9a, 0x6c81, 0x6c9b,
+ 0x6c7e, 0x6c68, 0x6c73, 0x6c92, 0x6c90, 0x6cc4, 0x6cf1, 0x6cd3,
+ 0x6cbd, 0x6cd7, 0x6cc5, 0x6cdd, 0x6cae, 0x6cb1, 0x6cbe, 0x6cba,
+ 0x6cdb, 0x6cef, 0x6cd9, 0x6cea, 0x6d1f, 0x884d, 0x6d36, 0x6d2b,
+ 0x6d3d, 0x6d38, 0x6d19, 0x6d35, 0x6d33, 0x6d12, 0x6d0c, 0x6d63,
+ 0x6d93, 0x6d64, 0x6d5a, 0x6d79, 0x6d59, 0x6d8e, 0x6d95, 0x6fe4,
+ 0x6d85, 0x6df9, 0x6e15, 0x6e0a, 0x6db5, 0x6dc7, 0x6de6, 0x6db8,
+ 0x6dc6, 0x6dec, 0x6dde, 0x6dcc, 0x6de8, 0x6dd2, 0x6dc5, 0x6dfa,
+ 0x6dd9, 0x6de4, 0x6dd5, 0x6dea, 0x6dee, 0x6e2d, 0x6e6e, 0x6e2e,
+ 0x6e19, 0x6e72, 0x6e5f, 0x6e3e, 0x6e23, 0x6e6b, 0x6e2b, 0x6e76,
+ 0x6e4d, 0x6e1f, 0x6e43, 0x6e3a, 0x6e4e, 0x6e24, 0x6eff, 0x6e1d,
+ 0x6e38, 0x6e82, 0x6eaa, 0x6e98, 0x6ec9, 0x6eb7, 0x6ed3, 0x6ebd,
+ 0x6eaf, 0x6ec4, 0x6eb2, 0x6ed4, 0x6ed5, 0x6e8f, 0x6ea5, 0x6ec2,
+ 0x6e9f, 0x6f41, 0x6f11, 0x704c, 0x6eec, 0x6ef8, 0x6efe, 0x6f3f,
+ 0x6ef2, 0x6f31, 0x6eef, 0x6f32, 0x6ecc
+};
+
+static USHORT /* Shift-JIS to Unicode */
+sju_e040[] = { /* 0xe040 thru 0xeaa4 */
+ 0x6f3e, 0x6f13, 0x6ef7, 0x6f86, 0x6f7a, 0x6f78, 0x6f81, 0x6f80,
+ 0x6f6f, 0x6f5b, 0x6ff3, 0x6f6d, 0x6f82, 0x6f7c, 0x6f58, 0x6f8e,
+ 0x6f91, 0x6fc2, 0x6f66, 0x6fb3, 0x6fa3, 0x6fa1, 0x6fa4, 0x6fb9,
+ 0x6fc6, 0x6faa, 0x6fdf, 0x6fd5, 0x6fec, 0x6fd4, 0x6fd8, 0x6ff1,
+ 0x6fee, 0x6fdb, 0x7009, 0x700b, 0x6ffa, 0x7011, 0x7001, 0x700f,
+ 0x6ffe, 0x701b, 0x701a, 0x6f74, 0x701d, 0x7018, 0x701f, 0x7030,
+ 0x703e, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70af, 0x70f1,
+ 0x70ac, 0x70b8, 0x70b3, 0x70ae, 0x70df, 0x70cb, 0x70dd, 0xfffd,
+ 0x70d9, 0x7109, 0x70fd, 0x711c, 0x7119, 0x7165, 0x7155, 0x7188,
+ 0x7166, 0x7162, 0x714c, 0x7156, 0x716c, 0x718f, 0x71fb, 0x7184,
+ 0x7195, 0x71a8, 0x71ac, 0x71d7, 0x71b9, 0x71be, 0x71d2, 0x71c9,
+ 0x71d4, 0x71ce, 0x71e0, 0x71ec, 0x71e7, 0x71f5, 0x71fc, 0x71f9,
+ 0x71ff, 0x720d, 0x7210, 0x721b, 0x7228, 0x722d, 0x722c, 0x7230,
+ 0x7232, 0x723b, 0x723c, 0x723f, 0x7240, 0x7246, 0x724b, 0x7258,
+ 0x7274, 0x727e, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296, 0x72a2,
+ 0x72a7, 0x72b9, 0x72b2, 0x72c3, 0x72c6, 0x72c4, 0x72ce, 0x72d2,
+ 0x72e2, 0x72e0, 0x72e1, 0x72f9, 0x72f7, 0x500f, 0x7317, 0x730a,
+ 0x731c, 0x7316, 0x731d, 0x7334, 0x732f, 0x7329, 0x7325, 0x733e,
+ 0x734e, 0x734f, 0x9ed8, 0x7357, 0x736a, 0x7368, 0x7370, 0x7378,
+ 0x7375, 0x737b, 0x737a, 0x73c8, 0x73b3, 0x73ce, 0x73bb, 0x73c0,
+ 0x73e5, 0x73ee, 0x73de, 0x74a2, 0x7405, 0x746f, 0x7425, 0x73f8,
+ 0x7432, 0x743a, 0x7455, 0x743f, 0x745f, 0x7459, 0x7441, 0x745c,
+ 0x7469, 0x7470, 0x7463, 0x746a, 0x7476, 0x747e, 0x748b, 0x749e,
+ 0x74a7, 0x74ca, 0x74cf, 0x74d4, 0x73f1, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x74e0, 0x74e3, 0x74e7, 0x74e9, 0x74ee, 0x74f2, 0x74f0, 0x74f1,
+ 0x74f8, 0x74f7, 0x7504, 0x7503, 0x7505, 0x750c, 0x750e, 0x750d,
+ 0x7515, 0x7513, 0x751e, 0x7526, 0x752c, 0x753c, 0x7544, 0x754d,
+ 0x754a, 0x7549, 0x755b, 0x7546, 0x755a, 0x7569, 0x7564, 0x7567,
+ 0x756b, 0x756d, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758a,
+ 0x7589, 0x7582, 0x7594, 0x759a, 0x759d, 0x75a5, 0x75a3, 0x75c2,
+ 0x75b3, 0x75c3, 0x75b5, 0x75bd, 0x75b8, 0x75bc, 0x75b1, 0x75cd,
+ 0x75ca, 0x75d2, 0x75d9, 0x75e3, 0x75de, 0x75fe, 0x75ff, 0xfffd,
+ 0x75fc, 0x7601, 0x75f0, 0x75fa, 0x75f2, 0x75f3, 0x760b, 0x760d,
+ 0x7609, 0x761f, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634,
+ 0x7630, 0x763b, 0x7647, 0x7648, 0x7646, 0x765c, 0x7658, 0x7661,
+ 0x7662, 0x7668, 0x7669, 0x766a, 0x7667, 0x766c, 0x7670, 0x7672,
+ 0x7676, 0x7678, 0x767c, 0x7680, 0x7683, 0x7688, 0x768b, 0x768e,
+ 0x7696, 0x7693, 0x7699, 0x769a, 0x76b0, 0x76b4, 0x76b8, 0x76b9,
+ 0x76ba, 0x76c2, 0x76cd, 0x76d6, 0x76d2, 0x76de, 0x76e1, 0x76e5,
+ 0x76e7, 0x76ea, 0x862f, 0x76fb, 0x7708, 0x7707, 0x7704, 0x7729,
+ 0x7724, 0x771e, 0x7725, 0x7726, 0x771b, 0x7737, 0x7738, 0x7747,
+ 0x775a, 0x7768, 0x776b, 0x775b, 0x7765, 0x777f, 0x777e, 0x7779,
+ 0x778e, 0x778b, 0x7791, 0x77a0, 0x779e, 0x77b0, 0x77b6, 0x77b9,
+ 0x77bf, 0x77bc, 0x77bd, 0x77bb, 0x77c7, 0x77cd, 0x77d7, 0x77da,
+ 0x77dc, 0x77e3, 0x77ee, 0x77fc, 0x780c, 0x7812, 0x7926, 0x7820,
+ 0x792a, 0x7845, 0x788e, 0x7874, 0x7886, 0x787c, 0x789a, 0x788c,
+ 0x78a3, 0x78b5, 0x78aa, 0x78af, 0x78d1, 0x78c6, 0x78cb, 0x78d4,
+ 0x78be, 0x78bc, 0x78c5, 0x78ca, 0x78ec, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x78e7, 0x78da, 0x78fd, 0x78f4, 0x7907, 0x7912, 0x7911, 0x7919,
+ 0x792c, 0x792b, 0x7940, 0x7960, 0x7957, 0x795f, 0x795a, 0x7955,
+ 0x7953, 0x797a, 0x797f, 0x798a, 0x799d, 0x79a7, 0x9f4b, 0x79aa,
+ 0x79ae, 0x79b3, 0x79b9, 0x79ba, 0x79c9, 0x79d5, 0x79e7, 0x79ec,
+ 0x79e1, 0x79e3, 0x7a08, 0x7a0d, 0x7a18, 0x7a19, 0x7a20, 0x7a1f,
+ 0x7980, 0x7a31, 0x7a3b, 0x7a3e, 0x7a37, 0x7a43, 0x7a57, 0x7a49,
+ 0x7a61, 0x7a62, 0x7a69, 0x9f9d, 0x7a70, 0x7a79, 0x7a7d, 0x7a88,
+ 0x7a97, 0x7a95, 0x7a98, 0x7a96, 0x7aa9, 0x7ac8, 0x7ab0, 0xfffd,
+ 0x7ab6, 0x7ac5, 0x7ac4, 0x7abf, 0x9083, 0x7ac7, 0x7aca, 0x7acd,
+ 0x7acf, 0x7ad5, 0x7ad3, 0x7ad9, 0x7ada, 0x7add, 0x7ae1, 0x7ae2,
+ 0x7ae6, 0x7aed, 0x7af0, 0x7b02, 0x7b0f, 0x7b0a, 0x7b06, 0x7b33,
+ 0x7b18, 0x7b19, 0x7b1e, 0x7b35, 0x7b28, 0x7b36, 0x7b50, 0x7b7a,
+ 0x7b04, 0x7b4d, 0x7b0b, 0x7b4c, 0x7b45, 0x7b75, 0x7b65, 0x7b74,
+ 0x7b67, 0x7b70, 0x7b71, 0x7b6c, 0x7b6e, 0x7b9d, 0x7b98, 0x7b9f,
+ 0x7b8d, 0x7b9c, 0x7b9a, 0x7b8b, 0x7b92, 0x7b8f, 0x7b5d, 0x7b99,
+ 0x7bcb, 0x7bc1, 0x7bcc, 0x7bcf, 0x7bb4, 0x7bc6, 0x7bdd, 0x7be9,
+ 0x7c11, 0x7c14, 0x7be6, 0x7be5, 0x7c60, 0x7c00, 0x7c07, 0x7c13,
+ 0x7bf3, 0x7bf7, 0x7c17, 0x7c0d, 0x7bf6, 0x7c23, 0x7c27, 0x7c2a,
+ 0x7c1f, 0x7c37, 0x7c2b, 0x7c3d, 0x7c4c, 0x7c43, 0x7c54, 0x7c4f,
+ 0x7c40, 0x7c50, 0x7c58, 0x7c5f, 0x7c64, 0x7c56, 0x7c65, 0x7c6c,
+ 0x7c75, 0x7c83, 0x7c90, 0x7ca4, 0x7cad, 0x7ca2, 0x7cab, 0x7ca1,
+ 0x7ca8, 0x7cb3, 0x7cb2, 0x7cb1, 0x7cae, 0x7cb9, 0x7cbd, 0x7cc0,
+ 0x7cc5, 0x7cc2, 0x7cd8, 0x7cd2, 0x7cdc, 0x7ce2, 0x9b3b, 0x7cef,
+ 0x7cf2, 0x7cf4, 0x7cf6, 0x7cfa, 0x7d06, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x7d02, 0x7d1c, 0x7d15, 0x7d0a, 0x7d45, 0x7d4b, 0x7d2e, 0x7d32,
+ 0x7d3f, 0x7d35, 0x7d46, 0x7d73, 0x7d56, 0x7d4e, 0x7d72, 0x7d68,
+ 0x7d6e, 0x7d4f, 0x7d63, 0x7d93, 0x7d89, 0x7d5b, 0x7d8f, 0x7d7d,
+ 0x7d9b, 0x7dba, 0x7dae, 0x7da3, 0x7db5, 0x7dc7, 0x7dbd, 0x7dab,
+ 0x7e3d, 0x7da2, 0x7daf, 0x7ddc, 0x7db8, 0x7d9f, 0x7db0, 0x7dd8,
+ 0x7ddd, 0x7de4, 0x7dde, 0x7dfb, 0x7df2, 0x7de1, 0x7e05, 0x7e0a,
+ 0x7e23, 0x7e21, 0x7e12, 0x7e31, 0x7e1f, 0x7e09, 0x7e0b, 0x7e22,
+ 0x7e46, 0x7e66, 0x7e3b, 0x7e35, 0x7e39, 0x7e43, 0x7e37, 0xfffd,
+ 0x7e32, 0x7e3a, 0x7e67, 0x7e5d, 0x7e56, 0x7e5e, 0x7e59, 0x7e5a,
+ 0x7e79, 0x7e6a, 0x7e69, 0x7e7c, 0x7e7b, 0x7e83, 0x7dd5, 0x7e7d,
+ 0x8fae, 0x7e7f, 0x7e88, 0x7e89, 0x7e8c, 0x7e92, 0x7e90, 0x7e93,
+ 0x7e94, 0x7e96, 0x7e8e, 0x7e9b, 0x7e9c, 0x7f38, 0x7f3a, 0x7f45,
+ 0x7f4c, 0x7f4d, 0x7f4e, 0x7f50, 0x7f51, 0x7f55, 0x7f54, 0x7f58,
+ 0x7f5f, 0x7f60, 0x7f68, 0x7f69, 0x7f67, 0x7f78, 0x7f82, 0x7f86,
+ 0x7f83, 0x7f88, 0x7f87, 0x7f8c, 0x7f94, 0x7f9e, 0x7f9d, 0x7f9a,
+ 0x7fa3, 0x7faf, 0x7fb2, 0x7fb9, 0x7fae, 0x7fb6, 0x7fb8, 0x8b71,
+ 0x7fc5, 0x7fc6, 0x7fca, 0x7fd5, 0x7fd4, 0x7fe1, 0x7fe6, 0x7fe9,
+ 0x7ff3, 0x7ff9, 0x98dc, 0x8006, 0x8004, 0x800b, 0x8012, 0x8018,
+ 0x8019, 0x801c, 0x8021, 0x8028, 0x803f, 0x803b, 0x804a, 0x8046,
+ 0x8052, 0x8058, 0x805a, 0x805f, 0x8062, 0x8068, 0x8073, 0x8072,
+ 0x8070, 0x8076, 0x8079, 0x807d, 0x807f, 0x8084, 0x8086, 0x8085,
+ 0x809b, 0x8093, 0x809a, 0x80ad, 0x5190, 0x80ac, 0x80db, 0x80e5,
+ 0x80d9, 0x80dd, 0x80c4, 0x80da, 0x80d6, 0x8109, 0x80ef, 0x80f1,
+ 0x811b, 0x8129, 0x8123, 0x812f, 0x814b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x968b, 0x8146, 0x813e, 0x8153, 0x8151, 0x80fc, 0x8171, 0x816e,
+ 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818a, 0x8180, 0x8182,
+ 0x81a0, 0x8195, 0x81a4, 0x81a3, 0x815f, 0x8193, 0x81a9, 0x81b0,
+ 0x81b5, 0x81be, 0x81b8, 0x81bd, 0x81c0, 0x81c2, 0x81ba, 0x81c9,
+ 0x81cd, 0x81d1, 0x81d9, 0x81d8, 0x81c8, 0x81da, 0x81df, 0x81e0,
+ 0x81e7, 0x81fa, 0x81fb, 0x81fe, 0x8201, 0x8202, 0x8205, 0x8207,
+ 0x820a, 0x820d, 0x8210, 0x8216, 0x8229, 0x822b, 0x8238, 0x8233,
+ 0x8240, 0x8259, 0x8258, 0x825d, 0x825a, 0x825f, 0x8264, 0xfffd,
+ 0x8262, 0x8268, 0x826a, 0x826b, 0x822e, 0x8271, 0x8277, 0x8278,
+ 0x827e, 0x828d, 0x8292, 0x82ab, 0x829f, 0x82bb, 0x82ac, 0x82e1,
+ 0x82e3, 0x82df, 0x82d2, 0x82f4, 0x82f3, 0x82fa, 0x8393, 0x8303,
+ 0x82fb, 0x82f9, 0x82de, 0x8306, 0x82dc, 0x8309, 0x82d9, 0x8335,
+ 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, 0x8345,
+ 0x832f, 0x832b, 0x8317, 0x8318, 0x8385, 0x839a, 0x83aa, 0x839f,
+ 0x83a2, 0x8396, 0x8323, 0x838e, 0x8387, 0x838a, 0x837c, 0x83b5,
+ 0x8373, 0x8375, 0x83a0, 0x8389, 0x83a8, 0x83f4, 0x8413, 0x83eb,
+ 0x83ce, 0x83fd, 0x8403, 0x83d8, 0x840b, 0x83c1, 0x83f7, 0x8407,
+ 0x83e0, 0x83f2, 0x840d, 0x8422, 0x8420, 0x83bd, 0x8438, 0x8506,
+ 0x83fb, 0x846d, 0x842a, 0x843c, 0x855a, 0x8484, 0x8477, 0x846b,
+ 0x84ad, 0x846e, 0x8482, 0x8469, 0x8446, 0x842c, 0x846f, 0x8479,
+ 0x8435, 0x84ca, 0x8462, 0x84b9, 0x84bf, 0x849f, 0x84d9, 0x84cd,
+ 0x84bb, 0x84da, 0x84d0, 0x84c1, 0x84c6, 0x84d6, 0x84a1, 0x8521,
+ 0x84ff, 0x84f4, 0x8517, 0x8518, 0x852c, 0x851f, 0x8515, 0x8514,
+ 0x84fc, 0x8540, 0x8563, 0x8558, 0x8548, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8541, 0x8602, 0x854b, 0x8555, 0x8580, 0x85a4, 0x8588, 0x8591,
+ 0x858a, 0x85a8, 0x856d, 0x8594, 0x859b, 0x85ea, 0x8587, 0x859c,
+ 0x8577, 0x857e, 0x8590, 0x85c9, 0x85ba, 0x85cf, 0x85b9, 0x85d0,
+ 0x85d5, 0x85dd, 0x85e5, 0x85dc, 0x85f9, 0x860a, 0x8613, 0x860b,
+ 0x85fe, 0x85fa, 0x8606, 0x8622, 0x861a, 0x8630, 0x863f, 0x864d,
+ 0x4e55, 0x8654, 0x865f, 0x8667, 0x8671, 0x8693, 0x86a3, 0x86a9,
+ 0x86aa, 0x868b, 0x868c, 0x86b6, 0x86af, 0x86c4, 0x86c6, 0x86b0,
+ 0x86c9, 0x8823, 0x86ab, 0x86d4, 0x86de, 0x86e9, 0x86ec, 0xfffd,
+ 0x86df, 0x86db, 0x86ef, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703,
+ 0x86fb, 0x8711, 0x8709, 0x870d, 0x86f9, 0x870a, 0x8734, 0x873f,
+ 0x8737, 0x873b, 0x8725, 0x8729, 0x871a, 0x8760, 0x875f, 0x8778,
+ 0x874c, 0x874e, 0x8774, 0x8757, 0x8768, 0x876e, 0x8759, 0x8753,
+ 0x8763, 0x876a, 0x8805, 0x87a2, 0x879f, 0x8782, 0x87af, 0x87cb,
+ 0x87bd, 0x87c0, 0x87d0, 0x96d6, 0x87ab, 0x87c4, 0x87b3, 0x87c7,
+ 0x87c6, 0x87bb, 0x87ef, 0x87f2, 0x87e0, 0x880f, 0x880d, 0x87fe,
+ 0x87f6, 0x87f7, 0x880e, 0x87d2, 0x8811, 0x8816, 0x8815, 0x8822,
+ 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883b, 0x8844, 0x8842,
+ 0x8852, 0x8859, 0x885e, 0x8862, 0x886b, 0x8881, 0x887e, 0x889e,
+ 0x8875, 0x887d, 0x88b5, 0x8872, 0x8882, 0x8897, 0x8892, 0x88ae,
+ 0x8899, 0x88a2, 0x888d, 0x88a4, 0x88b0, 0x88bf, 0x88b1, 0x88c3,
+ 0x88c4, 0x88d4, 0x88d8, 0x88d9, 0x88dd, 0x88f9, 0x8902, 0x88fc,
+ 0x88f4, 0x88e8, 0x88f2, 0x8904, 0x890c, 0x890a, 0x8913, 0x8943,
+ 0x891e, 0x8925, 0x892a, 0x892b, 0x8941, 0x8944, 0x893b, 0x8936,
+ 0x8938, 0x894c, 0x891d, 0x8960, 0x895e, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8966, 0x8964, 0x896d, 0x896a, 0x896f, 0x8974, 0x8977, 0x897e,
+ 0x8983, 0x8988, 0x898a, 0x8993, 0x8998, 0x89a1, 0x89a9, 0x89a6,
+ 0x89ac, 0x89af, 0x89b2, 0x89ba, 0x89bd, 0x89bf, 0x89c0, 0x89da,
+ 0x89dc, 0x89dd, 0x89e7, 0x89f4, 0x89f8, 0x8a03, 0x8a16, 0x8a10,
+ 0x8a0c, 0x8a1b, 0x8a1d, 0x8a25, 0x8a36, 0x8a41, 0x8a5b, 0x8a52,
+ 0x8a46, 0x8a48, 0x8a7c, 0x8a6d, 0x8a6c, 0x8a62, 0x8a85, 0x8a82,
+ 0x8a84, 0x8aa8, 0x8aa1, 0x8a91, 0x8aa5, 0x8aa6, 0x8a9a, 0x8aa3,
+ 0x8ac4, 0x8acd, 0x8ac2, 0x8ada, 0x8aeb, 0x8af3, 0x8ae7, 0xfffd,
+ 0x8ae4, 0x8af1, 0x8b14, 0x8ae0, 0x8ae2, 0x8af7, 0x8ade, 0x8adb,
+ 0x8b0c, 0x8b07, 0x8b1a, 0x8ae1, 0x8b16, 0x8b10, 0x8b17, 0x8b20,
+ 0x8b33, 0x97ab, 0x8b26, 0x8b2b, 0x8b3e, 0x8b28, 0x8b41, 0x8b4c,
+ 0x8b4f, 0x8b4e, 0x8b49, 0x8b56, 0x8b5b, 0x8b5a, 0x8b6b, 0x8b5f,
+ 0x8b6c, 0x8b6f, 0x8b74, 0x8b7d, 0x8b80, 0x8b8c, 0x8b8e, 0x8b92,
+ 0x8b93, 0x8b96, 0x8b99, 0x8b9a, 0x8c3a, 0x8c41, 0x8c3f, 0x8c48,
+ 0x8c4c, 0x8c4e, 0x8c50, 0x8c55, 0x8c62, 0x8c6c, 0x8c78, 0x8c7a,
+ 0x8c82, 0x8c89, 0x8c85, 0x8c8a, 0x8c8d, 0x8c8e, 0x8c94, 0x8c7c,
+ 0x8c98, 0x621d, 0x8cad, 0x8caa, 0x8cbd, 0x8cb2, 0x8cb3, 0x8cae,
+ 0x8cb6, 0x8cc8, 0x8cc1, 0x8ce4, 0x8ce3, 0x8cda, 0x8cfd, 0x8cfa,
+ 0x8cfb, 0x8d04, 0x8d05, 0x8d0a, 0x8d07, 0x8d0f, 0x8d0d, 0x8d10,
+ 0x9f4e, 0x8d13, 0x8ccd, 0x8d14, 0x8d16, 0x8d67, 0x8d6d, 0x8d71,
+ 0x8d73, 0x8d81, 0x8d99, 0x8dc2, 0x8dbe, 0x8dba, 0x8dcf, 0x8dda,
+ 0x8dd6, 0x8dcc, 0x8ddb, 0x8dcb, 0x8dea, 0x8deb, 0x8ddf, 0x8de3,
+ 0x8dfc, 0x8e08, 0x8e09, 0x8dff, 0x8e1d, 0x8e1e, 0x8e10, 0x8e1f,
+ 0x8e42, 0x8e35, 0x8e30, 0x8e34, 0x8e4a, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8e47, 0x8e49, 0x8e4c, 0x8e50, 0x8e48, 0x8e59, 0x8e64, 0x8e60,
+ 0x8e2a, 0x8e63, 0x8e55, 0x8e76, 0x8e72, 0x8e7c, 0x8e81, 0x8e87,
+ 0x8e85, 0x8e84, 0x8e8b, 0x8e8a, 0x8e93, 0x8e91, 0x8e94, 0x8e99,
+ 0x8eaa, 0x8ea1, 0x8eac, 0x8eb0, 0x8ec6, 0x8eb1, 0x8ebe, 0x8ec5,
+ 0x8ec8, 0x8ecb, 0x8edb, 0x8ee3, 0x8efc, 0x8efb, 0x8eeb, 0x8efe,
+ 0x8f0a, 0x8f05, 0x8f15, 0x8f12, 0x8f19, 0x8f13, 0x8f1c, 0x8f1f,
+ 0x8f1b, 0x8f0c, 0x8f26, 0x8f33, 0x8f3b, 0x8f39, 0x8f45, 0x8f42,
+ 0x8f3e, 0x8f4c, 0x8f49, 0x8f46, 0x8f4e, 0x8f57, 0x8f5c, 0xfffd,
+ 0x8f62, 0x8f63, 0x8f64, 0x8f9c, 0x8f9f, 0x8fa3, 0x8fad, 0x8faf,
+ 0x8fb7, 0x8fda, 0x8fe5, 0x8fe2, 0x8fea, 0x8fef, 0x9087, 0x8ff4,
+ 0x9005, 0x8ff9, 0x8ffa, 0x9011, 0x9015, 0x9021, 0x900d, 0x901e,
+ 0x9016, 0x900b, 0x9027, 0x9036, 0x9035, 0x9039, 0x8ff8, 0x904f,
+ 0x9050, 0x9051, 0x9052, 0x900e, 0x9049, 0x903e, 0x9056, 0x9058,
+ 0x905e, 0x9068, 0x906f, 0x9076, 0x96a8, 0x9072, 0x9082, 0x907d,
+ 0x9081, 0x9080, 0x908a, 0x9089, 0x908f, 0x90a8, 0x90af, 0x90b1,
+ 0x90b5, 0x90e2, 0x90e4, 0x6248, 0x90db, 0x9102, 0x9112, 0x9119,
+ 0x9132, 0x9130, 0x914a, 0x9156, 0x9158, 0x9163, 0x9165, 0x9169,
+ 0x9173, 0x9172, 0x918b, 0x9189, 0x9182, 0x91a2, 0x91ab, 0x91af,
+ 0x91aa, 0x91b5, 0x91b4, 0x91ba, 0x91c0, 0x91c1, 0x91c9, 0x91cb,
+ 0x91d0, 0x91d6, 0x91df, 0x91e1, 0x91db, 0x91fc, 0x91f5, 0x91f6,
+ 0x921e, 0x91ff, 0x9214, 0x922c, 0x9215, 0x9211, 0x925e, 0x9257,
+ 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923f, 0x924b, 0x9250,
+ 0x929c, 0x9296, 0x9293, 0x929b, 0x925a, 0x92cf, 0x92b9, 0x92b7,
+ 0x92e9, 0x930f, 0x92fa, 0x9344, 0x932e, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9319, 0x9322, 0x931a, 0x9323, 0x933a, 0x9335, 0x933b, 0x935c,
+ 0x9360, 0x937c, 0x936e, 0x9356, 0x93b0, 0x93ac, 0x93ad, 0x9394,
+ 0x93b9, 0x93d6, 0x93d7, 0x93e8, 0x93e5, 0x93d8, 0x93c3, 0x93dd,
+ 0x93d0, 0x93c8, 0x93e4, 0x941a, 0x9414, 0x9413, 0x9403, 0x9407,
+ 0x9410, 0x9436, 0x942b, 0x9435, 0x9421, 0x943a, 0x9441, 0x9452,
+ 0x9444, 0x945b, 0x9460, 0x9462, 0x945e, 0x946a, 0x9229, 0x9470,
+ 0x9475, 0x9477, 0x947d, 0x945a, 0x947c, 0x947e, 0x9481, 0x947f,
+ 0x9582, 0x9587, 0x958a, 0x9594, 0x9596, 0x9598, 0x9599, 0xfffd,
+ 0x95a0, 0x95a8, 0x95a7, 0x95ad, 0x95bc, 0x95bb, 0x95b9, 0x95be,
+ 0x95ca, 0x6ff6, 0x95c3, 0x95cd, 0x95cc, 0x95d5, 0x95d4, 0x95d6,
+ 0x95dc, 0x95e1, 0x95e5, 0x95e2, 0x9621, 0x9628, 0x962e, 0x962f,
+ 0x9642, 0x964c, 0x964f, 0x964b, 0x9677, 0x965c, 0x965e, 0x965d,
+ 0x965f, 0x9666, 0x9672, 0x966c, 0x968d, 0x9698, 0x9695, 0x9697,
+ 0x96aa, 0x96a7, 0x96b1, 0x96b2, 0x96b0, 0x96b4, 0x96b6, 0x96b8,
+ 0x96b9, 0x96ce, 0x96cb, 0x96c9, 0x96cd, 0x894d, 0x96dc, 0x970d,
+ 0x96d5, 0x96f9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970e, 0x9711,
+ 0x970f, 0x9716, 0x9719, 0x9724, 0x972a, 0x9730, 0x9739, 0x973d,
+ 0x973e, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975c, 0x9760,
+ 0x9764, 0x9766, 0x9768, 0x52d2, 0x976b, 0x9771, 0x9779, 0x9785,
+ 0x977c, 0x9781, 0x977a, 0x9786, 0x978b, 0x978f, 0x9790, 0x979c,
+ 0x97a8, 0x97a6, 0x97a3, 0x97b3, 0x97b4, 0x97c3, 0x97c6, 0x97c8,
+ 0x97cb, 0x97dc, 0x97ed, 0x9f4f, 0x97f2, 0x7adf, 0x97f6, 0x97f5,
+ 0x980f, 0x980c, 0x9838, 0x9824, 0x9821, 0x9837, 0x983d, 0x9846,
+ 0x984f, 0x984b, 0x986b, 0x986f, 0x9870, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9871, 0x9874, 0x9873, 0x98aa, 0x98af, 0x98b1, 0x98b6, 0x98c4,
+ 0x98c3, 0x98c6, 0x98e9, 0x98eb, 0x9903, 0x9909, 0x9912, 0x9914,
+ 0x9918, 0x9921, 0x991d, 0x991e, 0x9924, 0x9920, 0x992c, 0x992e,
+ 0x993d, 0x993e, 0x9942, 0x9949, 0x9945, 0x9950, 0x994b, 0x9951,
+ 0x9952, 0x994c, 0x9955, 0x9997, 0x9998, 0x99a5, 0x99ad, 0x99ae,
+ 0x99bc, 0x99df, 0x99db, 0x99dd, 0x99d8, 0x99d1, 0x99ed, 0x99ee,
+ 0x99f1, 0x99f2, 0x99fb, 0x99f8, 0x9a01, 0x9a0f, 0x9a05, 0x99e2,
+ 0x9a19, 0x9a2b, 0x9a37, 0x9a45, 0x9a42, 0x9a40, 0x9a43, 0xfffd,
+ 0x9a3e, 0x9a55, 0x9a4d, 0x9a5b, 0x9a57, 0x9a5f, 0x9a62, 0x9a65,
+ 0x9a64, 0x9a69, 0x9a6b, 0x9a6a, 0x9aad, 0x9ab0, 0x9abc, 0x9ac0,
+ 0x9acf, 0x9ad1, 0x9ad3, 0x9ad4, 0x9ade, 0x9adf, 0x9ae2, 0x9ae3,
+ 0x9ae6, 0x9aef, 0x9aeb, 0x9aee, 0x9af4, 0x9af1, 0x9af7, 0x9afb,
+ 0x9b06, 0x9b18, 0x9b1a, 0x9b1f, 0x9b22, 0x9b23, 0x9b25, 0x9b27,
+ 0x9b28, 0x9b29, 0x9b2a, 0x9b2e, 0x9b2f, 0x9b32, 0x9b44, 0x9b43,
+ 0x9b4f, 0x9b4d, 0x9b4e, 0x9b51, 0x9b58, 0x9b74, 0x9b93, 0x9b83,
+ 0x9b91, 0x9b96, 0x9b97, 0x9b9f, 0x9ba0, 0x9ba8, 0x9bb4, 0x9bc0,
+ 0x9bca, 0x9bb9, 0x9bc6, 0x9bcf, 0x9bd1, 0x9bd2, 0x9be3, 0x9be2,
+ 0x9be4, 0x9bd4, 0x9be1, 0x9c3a, 0x9bf2, 0x9bf1, 0x9bf0, 0x9c15,
+ 0x9c14, 0x9c09, 0x9c13, 0x9c0c, 0x9c06, 0x9c08, 0x9c12, 0x9c0a,
+ 0x9c04, 0x9c2e, 0x9c1b, 0x9c25, 0x9c24, 0x9c21, 0x9c30, 0x9c47,
+ 0x9c32, 0x9c46, 0x9c3e, 0x9c5a, 0x9c60, 0x9c67, 0x9c76, 0x9c78,
+ 0x9ce7, 0x9cec, 0x9cf0, 0x9d09, 0x9d08, 0x9ceb, 0x9d03, 0x9d06,
+ 0x9d2a, 0x9d26, 0x9daf, 0x9d23, 0x9d1f, 0x9d44, 0x9d15, 0x9d12,
+ 0x9d41, 0x9d3f, 0x9d3e, 0x9d46, 0x9d48, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9d5d, 0x9d5e, 0x9d64, 0x9d51, 0x9d50, 0x9d59, 0x9d72, 0x9d89,
+ 0x9d87, 0x9dab, 0x9d6f, 0x9d7a, 0x9d9a, 0x9da4, 0x9da9, 0x9db2,
+ 0x9dc4, 0x9dc1, 0x9dbb, 0x9db8, 0x9dba, 0x9dc6, 0x9dcf, 0x9dc2,
+ 0x9dd9, 0x9dd3, 0x9df8, 0x9de6, 0x9ded, 0x9def, 0x9dfd, 0x9e1a,
+ 0x9e1b, 0x9e1e, 0x9e75, 0x9e79, 0x9e7d, 0x9e81, 0x9e88, 0x9e8b,
+ 0x9e8c, 0x9e92, 0x9e95, 0x9e91, 0x9e9d, 0x9ea5, 0x9ea9, 0x9eb8,
+ 0x9eaa, 0x9ead, 0x9761, 0x9ecc, 0x9ece, 0x9ecf, 0x9ed0, 0x9ed4,
+ 0x9edc, 0x9ede, 0x9edd, 0x9ee0, 0x9ee5, 0x9ee8, 0x9eef, 0xfffd,
+ 0x9ef4, 0x9ef6, 0x9ef7, 0x9ef9, 0x9efb, 0x9efc, 0x9efd, 0x9f07,
+ 0x9f08, 0x76b7, 0x9f15, 0x9f21, 0x9f2c, 0x9f3e, 0x9f4a, 0x9f52,
+ 0x9f54, 0x9f63, 0x9f5f, 0x9f60, 0x9f61, 0x9f66, 0x9f67, 0x9f6c,
+ 0x9f6a, 0x9f77, 0x9f72, 0x9f76, 0x9f95, 0x9f9c, 0x9fa0, 0x582f,
+ 0x69c7, 0x9059, 0x7464, 0x51dc, 0x7199
+};
+
+/* Unicode-to-Kanji tables... */
+
+static USHORT /* Unicode to Shift-JIS */
+usj_0391[] = { /* 0x0391 thru 0x039c */
+ 0x839f, 0x83a0, 0x83a1, 0x83a2, 0x83a3, 0x83a4, 0x83a5, 0x83a6,
+ 0x83a7, 0x83a8, 0x83a9, 0x83aa, 0x83ab, 0x83ac, 0x83ad, 0x83ae,
+ 0x83af, 0xfffd, 0x83b0, 0x83b1, 0x83b2, 0x83b3, 0x83b4, 0x83b5,
+ 0x83b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x83bf, 0x83c0, 0x83c1, 0x83c2, 0x83c3, 0x83c4, 0x83c5, 0x83c6,
+ 0x83c7, 0x83c8, 0x83c9, 0x83ca, 0x83cb, 0x83cc, 0x83cd, 0x83ce,
+ 0x83cf, 0xfffd, 0x83d0, 0x83d1, 0x83d2, 0x83d3, 0x83d4, 0x83d5, 0x83d6
+};
+
+static USHORT /* Unicode to Shift-JIS */
+usj_0401[] = { /* 0x0401 thru 0x0451 */
+ 0x8446, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8440,
+ 0x8441, 0x8442, 0x8443, 0x8444, 0x8445, 0x8447, 0x8448, 0x8449,
+ 0x844a, 0x844b, 0x844c, 0x844d, 0x844e, 0x844f, 0x8450, 0x8451,
+ 0x8452, 0x8453, 0x8454, 0x8455, 0x8456, 0x8457, 0x8458, 0x8459,
+ 0x845a, 0x845b, 0x845c, 0x845d, 0x845e, 0x845f, 0x8460, 0x8470,
+ 0x8471, 0x8472, 0x8473, 0x8474, 0x8475, 0x8477, 0x8478, 0x8479,
+ 0x847a, 0x847b, 0x847c, 0x847d, 0x847e, 0x8480, 0x8481, 0x8482,
+ 0x8483, 0x8484, 0x8485, 0x8486, 0x8487, 0x8488, 0x8489, 0x848a,
+ 0x848b, 0x848c, 0x848d, 0x848e, 0x848f, 0x8490, 0x8491, 0xfffd, 0x8476
+};
+
+static USHORT /* Unicode to Shift-JIS */
+usj_3000[] = { /* 0x3000 thru 0x30ff */
+ 0x8140, 0x8141, 0x8142, 0x8156, 0xfffd, 0x8158, 0x8159, 0x815a,
+ 0x8171, 0x8172, 0x8173, 0x8174, 0x8175, 0x8176, 0x8177, 0x8178,
+ 0x8179, 0x817a, 0x81a7, 0x81ac, 0x816b, 0x816c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8160, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x829f, 0x82a0, 0x82a1, 0x82a2, 0x82a3, 0x82a4, 0x82a5,
+ 0x82a6, 0x82a7, 0x82a8, 0x82a9, 0x82aa, 0x82ab, 0x82ac, 0x82ad,
+ 0x82ae, 0x82af, 0x82b0, 0x82b1, 0x82b2, 0x82b3, 0x82b4, 0x82b5,
+ 0x82b6, 0x82b7, 0x82b8, 0x82b9, 0x82ba, 0x82bb, 0x82bc, 0x82bd,
+ 0x82be, 0x82bf, 0x82c0, 0x82c1, 0x82c2, 0x82c3, 0x82c4, 0x82c5,
+ 0x82c6, 0x82c7, 0x82c8, 0x82c9, 0x82ca, 0x82cb, 0x82cc, 0x82cd,
+ 0x82ce, 0x82cf, 0x82d0, 0x82d1, 0x82d2, 0x82d3, 0x82d4, 0x82d5,
+ 0x82d6, 0x82d7, 0x82d8, 0x82d9, 0x82da, 0x82db, 0x82dc, 0x82dd,
+ 0x82de, 0x82df, 0x82e0, 0x82e1, 0x82e2, 0x82e3, 0x82e4, 0x82e5,
+ 0x82e6, 0x82e7, 0x82e8, 0x82e9, 0x82ea, 0x82eb, 0x82ec, 0x82ed,
+ 0x82ee, 0x82ef, 0x82f0, 0x82f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x814a, 0x814b, 0x8154, 0x8155, 0xfffd,
+ 0xfffd, 0x8340, 0x8341, 0x8342, 0x8343, 0x8344, 0x8345, 0x8346,
+ 0x8347, 0x8348, 0x8349, 0x834a, 0x834b, 0x834c, 0x834d, 0x834e,
+ 0x834f, 0x8350, 0x8351, 0x8352, 0x8353, 0x8354, 0x8355, 0x8356,
+ 0x8357, 0x8358, 0x8359, 0x835a, 0x835b, 0x835c, 0x835d, 0x835e,
+ 0x835f, 0x8360, 0x8361, 0x8362, 0x8363, 0x8364, 0x8365, 0x8366,
+ 0x8367, 0x8368, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d, 0x836e,
+ 0x836f, 0x8370, 0x8371, 0x8372, 0x8373, 0x8374, 0x8375, 0x8376,
+ 0x8377, 0x8378, 0x8379, 0x837a, 0x837b, 0x837c, 0x837d, 0x837e,
+ 0x8380, 0x8381, 0x8382, 0x8383, 0x8384, 0x8385, 0x8386, 0x8387,
+ 0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838e, 0x838f,
+ 0x8390, 0x8391, 0x8392, 0x8393, 0x8394, 0x8395, 0x8396, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8145, 0x815b, 0x8152, 0x8153, 0xfffd
+};
+
+static USHORT /* Unicode to Shift-JIS */
+usj_ff00[] = { /* 0xff00 thru 0x0ff9f */
+ 0xfffd, 0x8149, 0xfffd, 0x8194, 0x8190, 0x8193, 0x8195, 0xfffd,
+ 0x8169, 0x816a, 0x8196, 0x817b, 0x8143, 0xfffd, 0x8144, 0x815e,
+ 0x824f, 0x8250, 0x8251, 0x8252, 0x8253, 0x8254, 0x8255, 0x8256,
+ 0x8257, 0x8258, 0x8146, 0x8147, 0x8183, 0x8181, 0x8184, 0x8148,
+ 0x8197, 0x8260, 0x8261, 0x8262, 0x8263, 0x8264, 0x8265, 0x8266,
+ 0x8267, 0x8268, 0x8269, 0x826a, 0x826b, 0x826c, 0x826d, 0x826e,
+ 0x826f, 0x8270, 0x8271, 0x8272, 0x8273, 0x8274, 0x8275, 0x8276,
+ 0x8277, 0x8278, 0x8279, 0x816d, 0xfffd, 0x816e, 0x814f, 0x8151,
+ 0x814d, 0x8281, 0x8282, 0x8283, 0x8284, 0x8285, 0x8286, 0x8287,
+ 0x8288, 0x8289, 0x828a, 0x828b, 0x828c, 0x828d, 0x828e, 0x828f,
+ 0x8290, 0x8291, 0x8292, 0x8293, 0x8294, 0x8295, 0x8296, 0x8297,
+ 0x8298, 0x8299, 0x829a, 0x816f, 0x8162, 0x8170, 0xfffd, 0xfffd,
+ 0xfffd, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df
+};
+
+/* Now one humongous table for Kanji */
+
+static USHORT /* Unicode to Shift-JIS */
+usj_4e00[] = { /* 0x4e00 thru 0x9fa0 */
+ 0x88ea, 0x929a, 0xfffd, 0x8eb5, 0xfffd, 0xfffd, 0xfffd, 0x969c,
+ 0x8fe4, 0x8e4f, 0x8fe3, 0x89ba, 0xfffd, 0x9573, 0x975e, 0xfffd,
+ 0x98a0, 0x894e, 0xfffd, 0xfffd, 0x8a8e, 0x98a1, 0x90a2, 0x99c0,
+ 0x8b75, 0x95b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fe5, 0xfffd,
+ 0xfffd, 0x97bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95c0, 0xfffd,
+ 0xfffd, 0xfffd, 0x98a2, 0xfffd, 0xfffd, 0x9286, 0xfffd, 0xfffd,
+ 0xfffd, 0x98a3, 0x8bf8, 0xfffd, 0xfffd, 0xfffd, 0x98a4, 0xfffd,
+ 0x8adb, 0x924f, 0xfffd, 0x8ee5, 0x98a5, 0xfffd, 0xfffd, 0x98a6,
+ 0xfffd, 0xfffd, 0x98a7, 0x9454, 0xfffd, 0x8b76, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9456, 0xfffd, 0x93e1, 0x8cc1, 0x9652,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe568, 0x98a8, 0x8fe6,
+ 0x98a9, 0x89b3, 0xfffd, 0xfffd, 0xfffd, 0x8be3, 0x8cee, 0x96e7,
+ 0xfffd, 0xfffd, 0x9ba4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9790, 0xfffd, 0x93fb, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aa3, 0xfffd,
+ 0x8b54, 0xfffd, 0x98aa, 0xfffd, 0xfffd, 0x98ab, 0x97b9, 0xfffd,
+ 0x975c, 0x9188, 0x98ad, 0x8e96, 0x93f1, 0xfffd, 0x98b0, 0xfffd,
+ 0xfffd, 0x895d, 0x8cdd, 0xfffd, 0x8cdc, 0x88e4, 0xfffd, 0xfffd,
+ 0x986a, 0x9869, 0xfffd, 0x8db1, 0x889f, 0xfffd, 0x98b1, 0x98b2,
+ 0x98b3, 0x9653, 0x98b4, 0xfffd, 0x8cf0, 0x88e5, 0x9692, 0xfffd,
+ 0x8b9c, 0xfffd, 0xfffd, 0x8b9d, 0x8b9e, 0x92e0, 0x97ba, 0xfffd,
+ 0x98b5, 0xfffd, 0xfffd, 0x98b6, 0xfffd, 0xfffd, 0x98b7, 0xfffd,
+ 0xfffd, 0xfffd, 0x906c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8f59, 0x906d, 0x98bc, 0xfffd, 0x98ba, 0xfffd, 0x98bb, 0x8b77,
+ 0xfffd, 0xfffd, 0x8da1, 0x89ee, 0xfffd, 0x98b9, 0x98b8, 0x95a7,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e65, 0x8e64, 0x91bc, 0x98bd,
+ 0x9574, 0x90e5, 0xfffd, 0xfffd, 0xfffd, 0x8157, 0x98be, 0x98c0,
+ 0xfffd, 0xfffd, 0xfffd, 0x91e3, 0x97df, 0x88c8, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98bf, 0x89bc, 0xfffd,
+ 0x8bc2, 0xfffd, 0x9287, 0xfffd, 0xfffd, 0xfffd, 0x8c8f, 0x98c1,
+ 0xfffd, 0xfffd, 0xfffd, 0x9443, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8ae9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x98c2, 0x88c9, 0xfffd, 0xfffd, 0x8cde, 0x8aea, 0x959a,
+ 0x94b0, 0x8b78, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x89ef, 0xfffd, 0x98e5, 0x9360, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x948c,
+ 0x98c4, 0xfffd, 0xfffd, 0xfffd, 0x94ba, 0xfffd, 0x97e0, 0xfffd,
+ 0x904c, 0xfffd, 0x8e66, 0xfffd, 0x8e97, 0x89be, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x92cf, 0xfffd, 0xfffd, 0x9241, 0x98c8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88ca, 0x92e1, 0x8f5a,
+ 0x8db2, 0x9743, 0xfffd, 0x91cc, 0xfffd, 0x89bd, 0xfffd, 0x98c7,
+ 0xfffd, 0x975d, 0x98c3, 0x98c5, 0x8dec, 0x98c6, 0x9b43, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x98ce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98d1,
+ 0x98cf, 0xfffd, 0xfffd, 0x89c0, 0xfffd, 0x95b9, 0x98c9, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x98cd, 0x8cf1, 0xfffd, 0xfffd, 0x8e67,
+ 0xfffd, 0xfffd, 0xfffd, 0x8aa4, 0xfffd, 0xfffd, 0x98d2, 0xfffd,
+ 0x98ca, 0xfffd, 0xfffd, 0x97e1, 0xfffd, 0x8e98, 0xfffd, 0x98cb,
+ 0xfffd, 0x98d0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98d3, 0xfffd,
+ 0x98cc, 0xfffd, 0xfffd, 0x8b9f, 0xfffd, 0x88cb, 0xfffd, 0xfffd,
+ 0x8ba0, 0x89bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9b44, 0xfffd, 0x9699, 0x958e, 0x8cf2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x904e, 0x97b5, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95d6,
+ 0xfffd, 0xfffd, 0x8c57, 0x91a3, 0x89e2, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8f72, 0xfffd, 0xfffd, 0xfffd, 0x98d7, 0xfffd,
+ 0x98dc, 0x98da, 0xfffd, 0xfffd, 0x98d5, 0xfffd, 0xfffd, 0x91ad,
+ 0x98d8, 0xfffd, 0x98db, 0x98d9, 0xfffd, 0x95db, 0xfffd, 0x98d6,
+ 0xfffd, 0x904d, 0xfffd, 0x9693, 0x98dd, 0x98de, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f43, 0x98eb,
+ 0xfffd, 0xfffd, 0xfffd, 0x946f, 0xfffd, 0x9555, 0x98e6, 0xfffd,
+ 0x95ee, 0xfffd, 0x89b4, 0xfffd, 0xfffd, 0xfffd, 0x98ea, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98e4, 0x98ed, 0xfffd,
+ 0xfffd, 0x9171, 0xfffd, 0x8cc2, 0xfffd, 0x947b, 0xfffd, 0xe0c5,
+ 0xfffd, 0x98ec, 0x937c, 0xfffd, 0x98e1, 0xfffd, 0x8cf4, 0xfffd,
+ 0xfffd, 0x8cf3, 0x98df, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ed8,
+ 0xfffd, 0x98e7, 0xfffd, 0x95ed, 0x926c, 0x98e3, 0x8c91, 0xfffd,
+ 0x98e0, 0x98e8, 0x98e2, 0x97cf, 0x98e9, 0x9860, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8be4, 0xfffd,
+ 0xfffd, 0x8c90, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x98ee, 0xfffd, 0xfffd, 0xfffd, 0x98ef,
+ 0x98f3, 0x88cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ce,
+ 0x98f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98f1, 0x98f5, 0xfffd,
+ 0xfffd, 0xfffd, 0x98f4, 0xfffd, 0x92e2, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c92, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98f6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ec3, 0xfffd, 0x91a4, 0x92e3, 0x8bf4, 0xfffd,
+ 0x98f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b55, 0xfffd, 0xfffd,
+ 0x98f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98fa, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9654, 0xfffd, 0xfffd,
+ 0xfffd, 0x8c86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8e50, 0x94f5, 0x98f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dc3, 0x9762, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x98fc, 0x9942, 0x98fb, 0x8dc2, 0xfffd, 0x8f9d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c58, 0xfffd,
+ 0xfffd, 0xfffd, 0x9943, 0xfffd, 0xfffd, 0x8bcd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9940, 0x9941, 0xfffd, 0xfffd, 0x93ad, 0xfffd, 0x919c,
+ 0xfffd, 0x8ba1, 0xfffd, 0xfffd, 0xfffd, 0x966c, 0x9944, 0xfffd,
+ 0xfffd, 0xfffd, 0x97bb, 0xfffd, 0xfffd, 0xfffd, 0x9945, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9948, 0xfffd, 0x9946, 0xfffd, 0x916d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9947, 0x9949, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x994b, 0xfffd, 0xfffd,
+ 0xfffd, 0x994a, 0xfffd, 0x95c6, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b56, 0x994d, 0x994e, 0xfffd, 0x89ad, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x994c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ef2, 0xfffd, 0x9951, 0x9950, 0x994f, 0xfffd,
+ 0x98d4, 0xfffd, 0x9952, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f9e,
+ 0xfffd, 0x9953, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9744, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x96d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9955,
+ 0xfffd, 0xfffd, 0x9954, 0x9957, 0x9956, 0xfffd, 0xfffd, 0x9958,
+ 0x9959, 0x88f2, 0xfffd, 0x8cb3, 0x8c5a, 0x8f5b, 0x929b, 0x8ba2,
+ 0x90e6, 0x8cf5, 0xfffd, 0x8d8e, 0x995b, 0x96c6, 0x9365, 0xfffd,
+ 0x8e99, 0xfffd, 0x995a, 0xfffd, 0x995c, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x937d, 0xfffd, 0x8a95, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x995d, 0xfffd, 0xfffd, 0x93fc, 0xfffd, 0xfffd,
+ 0x9153, 0x995f, 0x9960, 0x94aa, 0x8cf6, 0x985a, 0x9961, 0xfffd,
+ 0xfffd, 0x8ba4, 0xfffd, 0xfffd, 0xfffd, 0x95ba, 0x91b4, 0x8bef,
+ 0x9354, 0xfffd, 0xfffd, 0xfffd, 0x8c93, 0xfffd, 0xfffd, 0xfffd,
+ 0x9962, 0xfffd, 0x9963, 0xfffd, 0xfffd, 0x93e0, 0x897e, 0xfffd,
+ 0xfffd, 0x9966, 0x8dfb, 0xfffd, 0x9965, 0x8dc4, 0xfffd, 0x9967,
+ 0xe3ec, 0x9968, 0x9660, 0x9969, 0xfffd, 0x996a, 0x996b, 0x8fe7,
+ 0xfffd, 0x8eca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8aa5, 0xfffd, 0x996e, 0xfffd, 0x996c, 0x96bb, 0x996d, 0xfffd,
+ 0x9579, 0x996f, 0x9970, 0x9971, 0x937e, 0xfffd, 0xfffd, 0xfffd,
+ 0x9975, 0x9973, 0x9974, 0x9972, 0x8de1, 0x9976, 0x96e8, 0x97e2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9977, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90a6, 0x9978, 0x8f79, 0xfffd,
+ 0xfffd, 0x9979, 0xfffd, 0x929c, 0x97bd, 0x9380, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99c3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x997a, 0xeaa3, 0x8bc3, 0xfffd, 0xfffd,
+ 0x997b, 0x967d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f88, 0x91fa,
+ 0xfffd, 0x997d, 0x93e2, 0xfffd, 0xfffd, 0x997e, 0xfffd, 0xfffd,
+ 0x9980, 0x8a4d, 0xfffd, 0xfffd, 0xfffd, 0x9981, 0x8ba5, 0xfffd,
+ 0x93ca, 0x899a, 0x8f6f, 0xfffd, 0xfffd, 0x949f, 0x9982, 0xfffd,
+ 0x9381, 0xfffd, 0xfffd, 0x906e, 0x9983, 0xfffd, 0x95aa, 0x90d8,
+ 0x8aa0, 0xfffd, 0x8aa7, 0x9984, 0xfffd, 0xfffd, 0x9986, 0xfffd,
+ 0xfffd, 0x8c59, 0xfffd, 0xfffd, 0x9985, 0xfffd, 0xfffd, 0x97f1,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f89, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94bb, 0x95ca, 0xfffd, 0x9987,
+ 0xfffd, 0x9798, 0x9988, 0xfffd, 0xfffd, 0xfffd, 0x9989, 0xfffd,
+ 0x939e, 0xfffd, 0xfffd, 0x998a, 0xfffd, 0xfffd, 0x90a7, 0x8dfc,
+ 0x8c94, 0x998b, 0x8e68, 0x8d8f, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x92e4, 0x998d, 0xfffd, 0xfffd, 0x91a5,
+ 0xfffd, 0xfffd, 0x8ded, 0x998e, 0x998f, 0x914f, 0xfffd, 0x998c,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9991, 0xfffd, 0x9655, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8d84, 0xfffd, 0xfffd, 0x9990, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8c95, 0x8ddc, 0x948d, 0xfffd, 0xfffd,
+ 0xfffd, 0x9994, 0x9992, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x959b,
+ 0x8fe8, 0x999b, 0x8a84, 0x9995, 0x9993, 0x916e, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9997, 0xfffd, 0x9996,
+ 0xfffd, 0xfffd, 0xfffd, 0x8a63, 0xfffd, 0xfffd, 0xfffd, 0x8c80,
+ 0x999c, 0x97ab, 0xfffd, 0xfffd, 0xfffd, 0x9998, 0xfffd, 0xfffd,
+ 0xfffd, 0x999d, 0x999a, 0xfffd, 0x9999, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x97cd, 0xfffd, 0xfffd, 0xfffd, 0x8cf7,
+ 0x89c1, 0xfffd, 0xfffd, 0x97f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8f95, 0x9377, 0x8d85, 0x99a0, 0x99a1, 0xfffd, 0xfffd,
+ 0xfffd, 0x97e3, 0xfffd, 0xfffd, 0x984a, 0x99a3, 0xfffd, 0xfffd,
+ 0xfffd, 0x8cf8, 0xfffd, 0xfffd, 0x99a2, 0xfffd, 0x8a4e, 0xfffd,
+ 0xfffd, 0x99a4, 0xfffd, 0x9675, 0xfffd, 0x92ba, 0xfffd, 0x9745,
+ 0xfffd, 0x95d7, 0xfffd, 0xfffd, 0xfffd, 0x99a5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe8d3, 0xfffd, 0xfffd, 0x93ae, 0xfffd, 0x99a6,
+ 0x8aa8, 0x96b1, 0xfffd, 0xfffd, 0xfffd, 0x8f9f, 0x99a7, 0x95e5,
+ 0x99ab, 0xfffd, 0x90a8, 0x99a8, 0x8bce, 0xfffd, 0x99a9, 0x8aa9,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c4d, 0x99ac, 0xfffd, 0x99ad, 0xfffd, 0xfffd,
+ 0x99ae, 0x99af, 0x8ed9, 0xfffd, 0xfffd, 0xfffd, 0x8cf9, 0x96dc,
+ 0xfffd, 0x96e6, 0x93f5, 0xfffd, 0xfffd, 0x95ef, 0x99b0, 0xfffd,
+ 0x99b1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99b3, 0xfffd, 0x99b5,
+ 0x99b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99b6, 0x89bb, 0x966b,
+ 0xfffd, 0x8dfa, 0x99b7, 0xfffd, 0xfffd, 0x9178, 0xfffd, 0xfffd,
+ 0x8fa0, 0x8ba7, 0xfffd, 0x99b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x94d9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99b9,
+ 0xfffd, 0x99ba, 0xfffd, 0x99bb, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x99bc, 0x9543, 0x8be6, 0x88e3, 0xfffd, 0xfffd, 0xfffd, 0x93bd,
+ 0x99bd, 0x8f5c, 0xfffd, 0x90e7, 0xfffd, 0x99bf, 0x99be, 0x8fa1,
+ 0x8cdf, 0x99c1, 0x94bc, 0xfffd, 0xfffd, 0x99c2, 0xfffd, 0xfffd,
+ 0xfffd, 0x94da, 0x91b2, 0x91ec, 0x8ba6, 0xfffd, 0xfffd, 0x93ec,
+ 0x9250, 0xfffd, 0x948e, 0xfffd, 0x966d, 0xfffd, 0x99c4, 0xfffd,
+ 0x90e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c54, 0xfffd,
+ 0xfffd, 0x99c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99c6, 0x894b,
+ 0x88f3, 0x8aeb, 0xfffd, 0x91a6, 0x8b70, 0x9791, 0xfffd, 0x99c9,
+ 0x89b5, 0xfffd, 0xfffd, 0x99c8, 0xfffd, 0xfffd, 0xfffd, 0x8ba8,
+ 0xfffd, 0xfffd, 0x99ca, 0xfffd, 0x96ef, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99cb, 0xfffd,
+ 0x97d0, 0xfffd, 0x8cfa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cb4,
+ 0x99cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99ce, 0x99cd, 0xfffd,
+ 0x907e, 0x8958, 0xfffd, 0xfffd, 0xfffd, 0x897d, 0x99cf, 0xfffd,
+ 0x99d0, 0xfffd, 0xfffd, 0x8cb5, 0xfffd, 0xfffd, 0x99d1, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8b8e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8e51, 0x99d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9694, 0x8db3, 0x8b79, 0x9746, 0x916f, 0x94bd, 0x8efb, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f66, 0xfffd, 0x8ee6, 0x8ef3,
+ 0xfffd, 0x8f96, 0xfffd, 0x94be, 0xfffd, 0xfffd, 0xfffd, 0x99d5,
+ 0xfffd, 0x8962, 0x9170, 0x8cfb, 0x8cc3, 0x8be5, 0xfffd, 0xfffd,
+ 0x99d9, 0x9240, 0x91fc, 0x8ba9, 0x8fa2, 0x99da, 0x99d8, 0x89c2,
+ 0x91e4, 0x8eb6, 0x8e6a, 0x8945, 0xfffd, 0xfffd, 0x8a90, 0x8d86,
+ 0x8e69, 0xfffd, 0x99db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x99dc, 0xfffd, 0x8b68, 0x8a65, 0xfffd, 0xfffd, 0xfffd,
+ 0x8d87, 0x8b67, 0x92dd, 0x8944, 0x93af, 0x96bc, 0x8d40, 0x9799,
+ 0x9366, 0x8cfc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8c4e, 0xfffd, 0x99e5, 0xfffd, 0x8be1,
+ 0x9669, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94db, 0xfffd,
+ 0xfffd, 0x99e4, 0xfffd, 0x8adc, 0x99df, 0x99e0, 0x99e2, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99e3, 0xfffd,
+ 0x8b7a, 0x9081, 0xfffd, 0x95ab, 0x99e1, 0x99dd, 0x8ce1, 0xfffd,
+ 0x99de, 0xfffd, 0x9843, 0xfffd, 0xfffd, 0xfffd, 0x95f0, 0xfffd,
+ 0x92e6, 0x8ce0, 0x8d90, 0xfffd, 0xfffd, 0xfffd, 0x99e6, 0xfffd,
+ 0xfffd, 0x93db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99ea,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8efc, 0xfffd, 0x8ef4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x99ed, 0x99eb, 0xfffd, 0x96a1, 0xfffd, 0x99e8, 0x99f1, 0x99ec,
+ 0xfffd, 0xfffd, 0xfffd, 0x99ef, 0x8cc4, 0x96bd, 0xfffd, 0xfffd,
+ 0x99f0, 0xfffd, 0xfffd, 0xfffd, 0x99f2, 0xfffd, 0x99f4, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8dee, 0x9861, 0xfffd, 0x99e9, 0x99e7,
+ 0x99f3, 0xfffd, 0x99ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x99f6, 0xfffd, 0x9a42, 0x99f8, 0xfffd, 0xfffd,
+ 0x99fc, 0xfffd, 0xfffd, 0x9a40, 0x99f9, 0xfffd, 0xfffd, 0x9a5d,
+ 0xfffd, 0xfffd, 0x8de7, 0x8a50, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x99f7, 0xfffd, 0xfffd, 0xfffd, 0x9a44, 0x88f4, 0x9a43, 0xfffd,
+ 0x88a3, 0x9569, 0x9a41, 0xfffd, 0x99fa, 0xfffd, 0xfffd, 0x99f5,
+ 0x99fb, 0x8dc6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a45, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x88f5, 0x9a4e, 0xfffd, 0xfffd, 0x9a46, 0x9a47, 0xfffd,
+ 0x8fa3, 0x9689, 0xfffd, 0xfffd, 0xfffd, 0x9a4c, 0x9a4b, 0xfffd,
+ 0xfffd, 0xfffd, 0x934e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9a4d, 0xfffd, 0xfffd, 0x9a4a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8953, 0xfffd, 0x8db4, 0x904f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a48,
+ 0x9382, 0xfffd, 0xfffd, 0xfffd, 0x9a49, 0xfffd, 0x88a0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a53, 0x9742,
+ 0xfffd, 0x8fa5, 0xfffd, 0x9a59, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a58, 0x9a4f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c1, 0xfffd,
+ 0x9a50, 0xfffd, 0xfffd, 0xfffd, 0x91ed, 0x9a55, 0x8fa4, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a52, 0xfffd, 0xfffd, 0x96e2,
+ 0xfffd, 0xfffd, 0xfffd, 0x8c5b, 0xfffd, 0xfffd, 0x9a56, 0x9a57,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a54, 0x9a5a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9a51, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9a60, 0x9a65, 0xfffd, 0x9a61, 0xfffd,
+ 0x9a5c, 0xfffd, 0xfffd, 0x9a66, 0x9150, 0xfffd, 0xfffd, 0x9a68,
+ 0xfffd, 0x8d41, 0x9a5e, 0x929d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a62, 0x9a5b, 0x8aab, 0xfffd, 0x8aec, 0x8a85, 0x9a63, 0x9a5f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c96,
+ 0x9a69, 0x9a67, 0x9172, 0x8b69, 0x8baa, 0xfffd, 0x9a64, 0xfffd,
+ 0x8bf2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8963, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a6d, 0x9a6b, 0xfffd, 0x9aa5,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a70, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9a6a, 0xfffd, 0x9a6e, 0xfffd, 0xfffd, 0x9a6c,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e6b, 0x9a6f, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a72,
+ 0xfffd, 0x9a77, 0xfffd, 0xfffd, 0xfffd, 0x9a75, 0x9a74, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9251, 0xfffd,
+ 0xfffd, 0x89c3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a71, 0xfffd, 0x9a73, 0x8fa6,
+ 0x8952, 0xfffd, 0xfffd, 0x9a76, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x89dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a82,
+ 0xfffd, 0x8ffa, 0x9a7d, 0xfffd, 0x9a7b, 0xfffd, 0x9a7c, 0xfffd,
+ 0x9a7e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x895c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9158, 0xfffd, 0x9a78, 0xfffd,
+ 0x9a79, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8a9a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a81, 0xfffd, 0xfffd, 0xfffd,
+ 0x8aed, 0xfffd, 0x9a84, 0x9a80, 0x9a83, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ac, 0xfffd, 0xfffd, 0xfffd,
+ 0x93d3, 0xfffd, 0x94b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a85, 0x8a64,
+ 0xfffd, 0xfffd, 0x9a87, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a8a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a89, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a88, 0xfffd, 0x9458, 0xfffd, 0xfffd, 0x9a8b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a8c, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a8e, 0xfffd, 0x9a8d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a90, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a93, 0x9a91, 0x9a8f, 0x9a92, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a94, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a95, 0xfffd,
+ 0xfffd, 0x9a96, 0xfffd, 0x9a97, 0xfffd, 0xfffd, 0xfffd, 0x9a98,
+ 0x9964, 0xfffd, 0x8efa, 0x8e6c, 0xfffd, 0xfffd, 0x89f1, 0xfffd,
+ 0x88f6, 0xfffd, 0xfffd, 0x9263, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a99, 0xfffd,
+ 0x8da2, 0xfffd, 0x88cd, 0x907d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9a9a, 0x8cc5, 0xfffd, 0xfffd, 0x8d91, 0xfffd, 0x9a9c,
+ 0x9a9b, 0xfffd, 0xfffd, 0x95de, 0x9a9d, 0xfffd, 0xfffd, 0xfffd,
+ 0x9a9f, 0x9a9e, 0xfffd, 0x9aa0, 0xfffd, 0x9aa1, 0xfffd, 0x8c97,
+ 0xfffd, 0xfffd, 0x8980, 0x9aa2, 0xfffd, 0xfffd, 0x9aa4, 0xfffd,
+ 0x9aa3, 0xfffd, 0xfffd, 0xfffd, 0x9aa6, 0xfffd, 0xfffd, 0x9379,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9aa7, 0x88b3,
+ 0x8ddd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c5c, 0xfffd, 0xfffd,
+ 0x926e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9aa8,
+ 0x9aa9, 0xfffd, 0xfffd, 0x9aab, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9aac, 0xfffd, 0x8de2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bcf,
+ 0xfffd, 0xfffd, 0x9656, 0xfffd, 0xfffd, 0xfffd, 0x9aaa, 0x9aad,
+ 0x8dbf, 0x8d42, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ab1, 0xfffd, 0xfffd, 0x8da3, 0xfffd, 0x9252, 0xfffd,
+ 0xfffd, 0x9aae, 0x92d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab2,
+ 0xfffd, 0xfffd, 0x9082, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ab0, 0x9ab3, 0xfffd, 0x8c5e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9ab4, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ab5, 0xfffd, 0x8d43, 0x8a5f, 0x9ab7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ab8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ab9, 0xfffd, 0xfffd, 0x9ab6, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9aaf, 0xfffd, 0xfffd, 0x9aba, 0xfffd, 0xfffd, 0x9abb, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9684, 0xfffd, 0xfffd, 0x8fe9, 0xfffd,
+ 0xfffd, 0xfffd, 0x9abd, 0x9abe, 0x9abc, 0xfffd, 0x9ac0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9457, 0xfffd, 0xfffd, 0x88e6,
+ 0x9575, 0xfffd, 0xfffd, 0x9ac1, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ffb, 0xfffd, 0xfffd, 0x8eb7,
+ 0xfffd, 0x947c, 0x8aee, 0xfffd, 0x8de9, 0xfffd, 0xfffd, 0xfffd,
+ 0x9678, 0xfffd, 0x93b0, 0xfffd, 0xfffd, 0x8c98, 0x91cd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9abf, 0x9ac2, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c2, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ac3, 0xfffd, 0xfffd, 0xfffd, 0x9ac4, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ac6, 0xfffd, 0xfffd, 0x92e7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8aac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9f,
+ 0x8981, 0x95f1, 0xfffd, 0xfffd, 0x8fea, 0x9367, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8de4, 0xfffd, 0xfffd, 0x9acc, 0xfffd, 0xfffd,
+ 0x95bb, 0x97db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x89f2, 0x9ac8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9159, 0x9acb, 0xfffd, 0x9383, 0xfffd, 0xfffd, 0x9368,
+ 0x9384, 0x94b7, 0x92cb, 0xfffd, 0xfffd, 0xfffd, 0x8dc7, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ac7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8996, 0xfffd, 0x9355, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ac9, 0xfffd, 0x9ac5, 0xfffd, 0xfffd, 0x906f, 0xfffd, 0xfffd,
+ 0xfffd, 0x9acd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f6d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8bab, 0xfffd, 0x9ace, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x95e6, 0xfffd, 0xfffd, 0xfffd, 0x919d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92c4, 0xfffd, 0xfffd, 0x9ad0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x966e, 0xfffd, 0xfffd, 0x9ad1, 0xfffd, 0xfffd, 0x9ad6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x95ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ad5, 0x9acf, 0x9ad2, 0x9ad4, 0xfffd, 0xfffd, 0x8da4, 0xfffd,
+ 0xfffd, 0x95c7, 0xfffd, 0xfffd, 0xfffd, 0x9ad7, 0xfffd, 0x9264,
+ 0xfffd, 0xfffd, 0x89f3, 0xfffd, 0x8feb, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ad9, 0xfffd, 0x9ad8, 0xfffd, 0x8d88, 0xfffd, 0x9ada,
+ 0x9adc, 0x9adb, 0xfffd, 0xfffd, 0x9ade, 0xfffd, 0x9ad3, 0x9ae0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9adf, 0x9add, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e6d, 0x9070, 0xfffd, 0x9173, 0x9ae1,
+ 0x90ba, 0x88eb, 0x9484, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92d9,
+ 0xfffd, 0x9ae3, 0x9ae2, 0x9ae4, 0x9ae5, 0x9ae6, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ae7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x95cf, 0x9ae8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89c4,
+ 0x9ae9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x975b, 0x8a4f, 0xfffd,
+ 0x99c7, 0x8f67, 0x91bd, 0x9aea, 0x96e9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x96b2, 0xfffd, 0xfffd, 0x9aec, 0xfffd, 0x91e5,
+ 0xfffd, 0x9356, 0x91be, 0x9576, 0x9aed, 0x9aee, 0x899b, 0xfffd,
+ 0xfffd, 0x8eb8, 0x9aef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88ce,
+ 0x9af0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9af1, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8982, 0xfffd, 0xfffd, 0x8aef,
+ 0x93de, 0x95f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9af5, 0x9174,
+ 0x9af4, 0x8c5f, 0xfffd, 0xfffd, 0x967a, 0x9af3, 0xfffd, 0x9385,
+ 0x9af7, 0xfffd, 0x9af6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9af9, 0xfffd, 0x9af8, 0xfffd, 0xfffd, 0x899c, 0xfffd, 0x9afa,
+ 0x8fa7, 0x9afc, 0x9244, 0xfffd, 0x9afb, 0xfffd, 0x95b1, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8f97, 0x937a, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b40, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d44, 0xfffd, 0xfffd,
+ 0xfffd, 0x9b41, 0x9440, 0x94dc, 0x96cf, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9444, 0xfffd, 0xfffd, 0x9b4a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8b57, 0xfffd, 0xfffd, 0x9764, 0xfffd,
+ 0xfffd, 0x96ad, 0xfffd, 0x9baa, 0xfffd, 0x9b42, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9b45, 0xfffd, 0x91c3, 0xfffd, 0xfffd,
+ 0x9657, 0xfffd, 0xfffd, 0xfffd, 0x9369, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9b46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9685, 0xfffd, 0x8dc8, 0xfffd, 0xfffd, 0x8fa8, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b47, 0xfffd,
+ 0xfffd, 0x8e6f, 0xfffd, 0x8e6e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x88b7, 0x8cc6, 0xfffd, 0x90a9, 0x88cf, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9b4b, 0x9b4c, 0xfffd, 0x9b49, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8957, 0x8aad, 0xfffd,
+ 0x9b48, 0xfffd, 0x96c3, 0x9550, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88a6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x88f7, 0xfffd, 0xfffd, 0xfffd, 0x8e70,
+ 0xfffd, 0x88d0, 0xfffd, 0x88a1, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9b51, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9b4f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x96ba, 0xfffd, 0x9b52, 0xfffd, 0x9b50, 0xfffd, 0xfffd, 0x9b4e,
+ 0x9050, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b4d, 0xfffd, 0xfffd,
+ 0xfffd, 0x95d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ce2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b56, 0x9b57, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fa9, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b53, 0x984b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x946b, 0xfffd,
+ 0xfffd, 0x9b55, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8da5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9b58, 0xfffd, 0xfffd, 0xfffd, 0x9577, 0xfffd,
+ 0xfffd, 0xfffd, 0x9b59, 0xfffd, 0x9b54, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96b9,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x947d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9b5a, 0x9551, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b5b, 0x9b5f, 0x9b5c, 0xfffd,
+ 0xfffd, 0x89c5, 0x9b5e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8eb9, 0xfffd, 0x9b5d, 0x8c99, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b6b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b64, 0x9b61,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9284, 0xfffd, 0x9b60, 0xfffd, 0xfffd, 0x9b62, 0xfffd,
+ 0xfffd, 0x9b63, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9b65, 0x9b66, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8af0, 0xfffd, 0x9b68, 0x9b67, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b69, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8fec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9b6c, 0xfffd, 0x92da, 0xfffd, 0xfffd, 0xfffd,
+ 0x8964, 0xfffd, 0x9b6a, 0xfffd, 0xfffd, 0xfffd, 0x9b6d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b6e, 0xfffd,
+ 0x9b71, 0xfffd, 0xfffd, 0x9b6f, 0xfffd, 0x9b70, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8e71, 0x9b72, 0xfffd, 0xfffd, 0x8d45, 0x9b73, 0xfffd, 0x8e9a,
+ 0x91b6, 0xfffd, 0x9b74, 0x9b75, 0x8e79, 0x8d46, 0xfffd, 0x96d0,
+ 0xfffd, 0xfffd, 0xfffd, 0x8b47, 0x8cc7, 0x9b76, 0x8a77, 0xfffd,
+ 0xfffd, 0x9b77, 0xfffd, 0x91b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b78, 0x9ba1, 0xfffd, 0x9b79, 0xfffd, 0x9b7a, 0xfffd, 0xfffd,
+ 0x9b7b, 0xfffd, 0x9b7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b7e, 0xfffd, 0xfffd, 0x9b80, 0xfffd, 0x91ee, 0xfffd, 0x8946,
+ 0x8ee7, 0x88c0, 0xfffd, 0x9176, 0x8aae, 0x8eb3, 0xfffd, 0x8d47,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9386, 0xfffd, 0x8f40,
+ 0x8aaf, 0x9288, 0x92e8, 0x88b6, 0x8b58, 0x95f3, 0xfffd, 0x8ec0,
+ 0xfffd, 0xfffd, 0x8b71, 0x90e9, 0x8eba, 0x9747, 0x9b81, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b7b, 0xfffd,
+ 0x8dc9, 0xfffd, 0xfffd, 0x8a51, 0x8983, 0x8faa, 0x89c6, 0xfffd,
+ 0x9b82, 0x9765, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f68,
+ 0xfffd, 0xfffd, 0x8ee2, 0x9b83, 0x8af1, 0x93d0, 0x96a7, 0x9b84,
+ 0xfffd, 0x9b85, 0xfffd, 0xfffd, 0x9578, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b87, 0xfffd, 0x8aa6, 0x8bf5, 0x9b86, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8ab0, 0xfffd, 0x9051, 0x9b8b, 0x8e40,
+ 0xfffd, 0x89c7, 0x9b8a, 0xfffd, 0x9b88, 0x9b8c, 0x9b89, 0x944a,
+ 0x9ecb, 0x9052, 0xfffd, 0x9b8d, 0xfffd, 0xfffd, 0x97be, 0xfffd,
+ 0x9b8e, 0xfffd, 0xfffd, 0x9b90, 0xfffd, 0x929e, 0x9b8f, 0xfffd,
+ 0x90a1, 0xfffd, 0x8e9b, 0xfffd, 0xfffd, 0xfffd, 0x91ce, 0x8ef5,
+ 0xfffd, 0x9595, 0x90ea, 0xfffd, 0x8ecb, 0x9b91, 0x8fab, 0x9b92,
+ 0x9b93, 0x88d1, 0x91b8, 0x9071, 0xfffd, 0x9b94, 0x93b1, 0x8fac,
+ 0xfffd, 0x8fad, 0xfffd, 0x9b95, 0xfffd, 0xfffd, 0x90eb, 0xfffd,
+ 0xfffd, 0xfffd, 0x8fae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b96, 0xfffd, 0x9b97, 0xfffd, 0x96de, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b98, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bc4, 0xfffd, 0xfffd,
+ 0xfffd, 0x8f41, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9b99, 0x9b9a, 0x8eda, 0x904b, 0x93f2, 0x9073, 0x94f6, 0x9441,
+ 0x8bc7, 0x9b9b, 0xfffd, 0xfffd, 0xfffd, 0x8b8f, 0x9b9c, 0xfffd,
+ 0x8bfc, 0xfffd, 0x93cd, 0x89ae, 0xfffd, 0x8e72, 0x9b9d, 0x9ba0,
+ 0x9b9f, 0x8bfb, 0xfffd, 0x9b9e, 0xfffd, 0x9357, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91ae, 0xfffd,
+ 0x936a, 0x8ec6, 0xfffd, 0xfffd, 0x9177, 0x979a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ba2, 0xfffd, 0x9ba3, 0x93d4,
+ 0xfffd, 0x8e52, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ba5, 0xfffd,
+ 0xfffd, 0x9ba6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ba7, 0xfffd, 0xfffd, 0xfffd,
+ 0x8af2, 0x9ba8, 0xfffd, 0xfffd, 0x9ba9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x89aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x915a, 0x8ae2, 0xfffd, 0x9bab, 0x96a6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x91d0, 0xfffd, 0x8a78, 0xfffd, 0xfffd, 0x9bad, 0x9baf,
+ 0x8add, 0xfffd, 0xfffd, 0x9bac, 0x9bae, 0xfffd, 0x9bb1, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bb0, 0xfffd, 0x9bb2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9bb3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x93bb, 0x8bac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x89e3, 0x9bb4, 0x9bb9, 0xfffd, 0xfffd, 0x9bb7, 0xfffd, 0x95f5,
+ 0x95f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9387, 0xfffd,
+ 0xfffd, 0xfffd, 0x9bb6, 0x8f73, 0xfffd, 0x9bb5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9092,
+ 0xfffd, 0xfffd, 0xfffd, 0x9bba, 0xfffd, 0xfffd, 0x8de8, 0xfffd,
+ 0xfffd, 0x9bc0, 0xfffd, 0xfffd, 0x9bc1, 0x9bbb, 0x8a52, 0x9bbc,
+ 0x9bc5, 0x9bc4, 0x9bc3, 0x9bbf, 0xfffd, 0xfffd, 0xfffd, 0x9bbe,
+ 0xfffd, 0xfffd, 0x9bc2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x95f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9bc9, 0x9bc6, 0xfffd, 0x9bc8, 0xfffd,
+ 0x9792, 0xfffd, 0x9bc7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bbd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9093, 0xfffd, 0xfffd, 0x9bca, 0xfffd, 0xfffd, 0x8db5,
+ 0xfffd, 0xfffd, 0xfffd, 0x9bcb, 0xfffd, 0xfffd, 0x9bcc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9bcf, 0xfffd, 0x9bce, 0xfffd, 0xfffd, 0x9bcd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9388, 0x9bb8, 0xfffd, 0xfffd, 0xfffd,
+ 0x9bd5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9bd0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd2, 0xfffd, 0x9bd3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd6,
+ 0xfffd, 0xfffd, 0x97e4, 0xfffd, 0x9bd7, 0x9bd4, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9bd8, 0xfffd, 0xfffd, 0x8ade, 0x9bd9, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9bdb, 0x9bda, 0xfffd, 0xfffd, 0x9bdc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9bdd, 0xfffd, 0x90ec, 0x8f42, 0xfffd,
+ 0xfffd, 0x8f84, 0xfffd, 0x9183, 0xfffd, 0x8d48, 0x8db6, 0x8d49,
+ 0x8b90, 0xfffd, 0xfffd, 0x9bde, 0xfffd, 0xfffd, 0x8db7, 0xfffd,
+ 0xfffd, 0x8cc8, 0x9bdf, 0x96a4, 0x9462, 0x9be0, 0xfffd, 0x8d4a,
+ 0xfffd, 0xfffd, 0xfffd, 0x8aaa, 0xfffd, 0x9246, 0x8bd0, 0xfffd,
+ 0xfffd, 0xfffd, 0x8e73, 0x957a, 0xfffd, 0xfffd, 0x94bf, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9be1, 0x8af3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9be4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x929f, 0xfffd,
+ 0xfffd, 0x9be3, 0x9be2, 0x9be5, 0xfffd, 0x92e9, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9083, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e74, 0xfffd, 0x90c8, 0xfffd, 0x91d1,
+ 0x8b41, 0xfffd, 0xfffd, 0x92a0, 0xfffd, 0xfffd, 0x9be6, 0x9be7,
+ 0x8fed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9658, 0xfffd, 0xfffd,
+ 0x9bea, 0xfffd, 0xfffd, 0x9be9, 0x9be8, 0x959d, 0xfffd, 0x9bf1,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9679, 0xfffd, 0x9beb, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bed, 0x968b, 0xfffd, 0x9bec,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bee,
+ 0xfffd, 0x94a6, 0x9bef, 0x95bc, 0x9bf0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ab1, 0x95bd, 0x944e, 0x9bf2, 0x9bf3, 0xfffd,
+ 0x8d4b, 0x8ab2, 0x9bf4, 0x8cb6, 0x9763, 0x9748, 0x8af4, 0x9bf6,
+ 0xfffd, 0x92a1, 0xfffd, 0x8d4c, 0x8faf, 0xfffd, 0xfffd, 0x94dd,
+ 0xfffd, 0xfffd, 0x8fb0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f98,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92ea, 0x95f7, 0x9358,
+ 0xfffd, 0xfffd, 0x8d4d, 0xfffd, 0x957b, 0xfffd, 0xfffd, 0xfffd,
+ 0x9bf7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9378, 0x8dc0,
+ 0xfffd, 0xfffd, 0xfffd, 0x8cc9, 0xfffd, 0x92eb, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88c1, 0x8f8e, 0x8d4e,
+ 0x9766, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9bf8, 0x9bf9, 0x9470, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9bfa, 0x97f5, 0x984c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bfc,
+ 0x9bfb, 0xfffd, 0xfffd, 0x8a66, 0xfffd, 0xfffd, 0x9c40, 0xfffd,
+ 0xfffd, 0xfffd, 0x9c43, 0x9c44, 0xfffd, 0x9c42, 0xfffd, 0x955f,
+ 0x8fb1, 0x9c46, 0x9c45, 0x9c41, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9c47, 0x9c48, 0xfffd, 0xfffd, 0x9c49, 0xfffd, 0xfffd, 0xfffd,
+ 0x9c4c, 0x9c4a, 0xfffd, 0x9c4b, 0x9c4d, 0xfffd, 0x8984, 0x92ec,
+ 0x9c4e, 0xfffd, 0x8c9a, 0x89f4, 0x9455, 0xfffd, 0x9c4f, 0x93f9,
+ 0xfffd, 0x95d9, 0xfffd, 0x9c50, 0x984d, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9c51, 0x95be, 0x9c54, 0x989f, 0x98af, 0xfffd, 0x8eae,
+ 0x93f3, 0x9c55, 0xfffd, 0x8b7c, 0x92a2, 0x88f8, 0x9c56, 0x95a4,
+ 0x8d4f, 0xfffd, 0xfffd, 0x926f, 0xfffd, 0xfffd, 0xfffd, 0x92ed,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ed, 0x8cb7, 0x8cca,
+ 0xfffd, 0x9c57, 0xfffd, 0xfffd, 0xfffd, 0x9c58, 0xfffd, 0x9c5e,
+ 0xfffd, 0x8ee3, 0xfffd, 0xfffd, 0xfffd, 0x92a3, 0xfffd, 0x8bad,
+ 0x9c59, 0xfffd, 0xfffd, 0xfffd, 0x954a, 0xfffd, 0x9265, 0xfffd,
+ 0xfffd, 0x9c5a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9c5b, 0xfffd, 0x8bae, 0xfffd, 0x9c5c, 0xfffd, 0x9c5d, 0xfffd,
+ 0xfffd, 0x9c5f, 0xfffd, 0x9396, 0xfffd, 0xfffd, 0x9c60, 0x9c61,
+ 0xfffd, 0x9c62, 0xfffd, 0xfffd, 0x9c53, 0x9c52, 0xfffd, 0xfffd,
+ 0xfffd, 0x9c63, 0x8c60, 0xfffd, 0xfffd, 0xfffd, 0x9546, 0xfffd,
+ 0xfffd, 0x8dca, 0x9556, 0x92a4, 0x956a, 0x9c64, 0xfffd, 0xfffd,
+ 0x8fb2, 0x8965, 0xfffd, 0x9c65, 0xfffd, 0xfffd, 0xfffd, 0x9c66,
+ 0xfffd, 0x96f0, 0xfffd, 0xfffd, 0x94de, 0xfffd, 0xfffd, 0x9c69,
+ 0x899d, 0x90aa, 0x9c68, 0x9c67, 0x8c61, 0x91d2, 0xfffd, 0x9c6d,
+ 0x9c6b, 0xfffd, 0x9c6a, 0x97a5, 0x8ce3, 0xfffd, 0xfffd, 0xfffd,
+ 0x8f99, 0x9c6c, 0x936b, 0x8f5d, 0xfffd, 0xfffd, 0xfffd, 0x93be,
+ 0x9c70, 0x9c6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c6e, 0xfffd,
+ 0x9c71, 0x8ce4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9c72, 0x959c, 0x8f7a, 0xfffd, 0xfffd, 0x9c73, 0x94f7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x93bf, 0x92a5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x934f, 0xfffd, 0xfffd, 0x9c74, 0x8b4a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9053, 0xfffd, 0x954b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af5, 0x9445, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c75, 0x8e75,
+ 0x9659, 0x965a, 0xfffd, 0xfffd, 0x899e, 0x9c7a, 0xfffd, 0xfffd,
+ 0x9289, 0xfffd, 0xfffd, 0xfffd, 0x9c77, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x89f5, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9cab, 0x9c79, 0xfffd, 0xfffd, 0xfffd, 0x944f, 0xfffd, 0xfffd,
+ 0x9c78, 0xfffd, 0xfffd, 0x9c76, 0xfffd, 0x8d9a, 0xfffd, 0x9c7c,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c83, 0x9c89,
+ 0x9c81, 0xfffd, 0x937b, 0xfffd, 0xfffd, 0x9c86, 0x957c, 0xfffd,
+ 0xfffd, 0x9c80, 0xfffd, 0x9c85, 0x97e5, 0x8e76, 0xfffd, 0xfffd,
+ 0x91d3, 0x9c7d, 0xfffd, 0xfffd, 0xfffd, 0x8b7d, 0x9c88, 0x90ab,
+ 0x8985, 0x9c82, 0x89f6, 0x9c87, 0xfffd, 0xfffd, 0xfffd, 0x8baf,
+ 0xfffd, 0x9c84, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9c8a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9c8c, 0x9c96, 0x9c94, 0xfffd, 0xfffd, 0x9c91, 0xfffd,
+ 0xfffd, 0xfffd, 0x9c90, 0x97f6, 0xfffd, 0x9c92, 0xfffd, 0xfffd,
+ 0x8bb0, 0xfffd, 0x8d50, 0xfffd, 0xfffd, 0x8f9a, 0xfffd, 0xfffd,
+ 0xfffd, 0x9c99, 0x9c8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c8f,
+ 0x9c7e, 0xfffd, 0x89f8, 0x9c93, 0x9c95, 0x9270, 0xfffd, 0xfffd,
+ 0x8da6, 0x89b6, 0x9c8d, 0x9c98, 0x9c97, 0x8bb1, 0xfffd, 0x91a7,
+ 0x8a86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c62, 0xfffd, 0x9c8e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9c9a, 0xfffd, 0x9c9d, 0x9c9f, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8ebb, 0xfffd, 0x9ca5, 0x92ee, 0x9c9b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ca3, 0xfffd, 0x89f7, 0xfffd, 0x9ca1, 0x9ca2,
+ 0xfffd, 0xfffd, 0x9c9e, 0x9ca0, 0xfffd, 0xfffd, 0xfffd, 0x8ce5,
+ 0x9749, 0xfffd, 0xfffd, 0x8ab3, 0xfffd, 0xfffd, 0x8978, 0x9ca4,
+ 0xfffd, 0x9459, 0x88ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x94df, 0x9c7b, 0x9caa, 0x9cae, 0x96e3, 0xfffd,
+ 0x9ca7, 0xfffd, 0xfffd, 0xfffd, 0x9389, 0x9cac, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fee, 0x9cad, 0x93d5,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9866, 0xfffd, 0x9ca9, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9caf, 0xfffd, 0x8d9b, 0xfffd, 0x90c9, 0xfffd, 0xfffd, 0x88d2,
+ 0x9ca8, 0x9ca6, 0xfffd, 0x9179, 0xfffd, 0xfffd, 0xfffd, 0x9c9c,
+ 0x8e53, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x91c4, 0x9cbb, 0xfffd, 0x917a, 0x9cb6, 0xfffd, 0x9cb3, 0x9cb4,
+ 0xfffd, 0x8ee4, 0x9cb7, 0x9cba, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9cb5, 0x8f44, 0xfffd, 0x9cb8, 0xfffd, 0xfffd, 0x9cb2, 0xfffd,
+ 0x96fa, 0x96f9, 0xfffd, 0xfffd, 0xfffd, 0x9cbc, 0x9cbd, 0x88d3,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cb1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8bf0, 0x88a4, 0xfffd, 0xfffd, 0xfffd, 0x8ab4,
+ 0xfffd, 0x9cb9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cc1,
+ 0x9cc0, 0xfffd, 0xfffd, 0xfffd, 0x9cc5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cc6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cc4, 0x9cc7, 0x9cbf, 0x9cc3,
+ 0xfffd, 0xfffd, 0x9cc8, 0xfffd, 0x9cc9, 0xfffd, 0xfffd, 0x9cbe,
+ 0x8e9c, 0xfffd, 0x9cc2, 0x91d4, 0x8d51, 0x9cb0, 0x9054, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9cd6, 0xfffd, 0x95e7, 0xfffd, 0xfffd,
+ 0x9ccc, 0x9ccd, 0x9cce, 0xfffd, 0xfffd, 0x9cd5, 0xfffd, 0x9cd4,
+ 0xfffd, 0xfffd, 0x969d, 0x8ab5, 0xfffd, 0x9cd2, 0xfffd, 0x8c64,
+ 0x8a53, 0xfffd, 0xfffd, 0x9ccf, 0xfffd, 0xfffd, 0x97b6, 0x9cd1,
+ 0x88d4, 0x9cd3, 0xfffd, 0x9cca, 0x9cd0, 0x9cd7, 0x8c63, 0x9ccb,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x977c, 0xfffd,
+ 0xfffd, 0xfffd, 0x974a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cda,
+ 0xfffd, 0xfffd, 0x9cde, 0xfffd, 0xfffd, 0xfffd, 0x919e, 0xfffd,
+ 0x97f7, 0x9cdf, 0xfffd, 0xfffd, 0x9cdc, 0xfffd, 0x9cd9, 0xfffd,
+ 0xfffd, 0x9cd8, 0x9cdd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ae, 0xfffd, 0xfffd, 0x93b2,
+ 0xfffd, 0x8c65, 0xfffd, 0x9ce0, 0x9cdb, 0xfffd, 0x9ce1, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c9b, 0xfffd, 0xfffd, 0xfffd, 0x89af, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ce9, 0xfffd, 0xfffd, 0xfffd, 0x8ab6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9ce7, 0xfffd, 0xfffd, 0x9ce8, 0x8da7,
+ 0x9ce6, 0x9ce4, 0x9ce3, 0x9cea, 0x9ce2, 0x9cec, 0xfffd, 0xfffd,
+ 0x89f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9cee, 0xfffd, 0xfffd, 0x9ced, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x92a6, 0xfffd, 0x9cf1, 0xfffd, 0x9cef, 0x9ce5,
+ 0x8c9c, 0xfffd, 0x9cf0, 0xfffd, 0x9cf4, 0x9cf3, 0x9cf5, 0x9cf2,
+ 0x9cf6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9cf7, 0x9cf8, 0x95e8, 0xfffd, 0x9cfa, 0x9cf9, 0x8f5e, 0xfffd,
+ 0x90ac, 0x89e4, 0x89fa, 0xfffd, 0x9cfb, 0xfffd, 0x88bd, 0xfffd,
+ 0xfffd, 0xfffd, 0x90ca, 0x9cfc, 0xfffd, 0xe6c1, 0x9d40, 0x8c81,
+ 0xfffd, 0x9d41, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90ed, 0xfffd,
+ 0xfffd, 0xfffd, 0x9d42, 0xfffd, 0xfffd, 0xfffd, 0x9d43, 0x8b59,
+ 0x9d44, 0xfffd, 0x9d45, 0x9d46, 0x91d5, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ccb, 0xfffd, 0xfffd, 0x96df, 0xfffd, 0xfffd, 0xfffd, 0x965b,
+ 0x8f8a, 0x9d47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90ee,
+ 0xe7bb, 0x94e0, 0xfffd, 0x8ee8, 0xfffd, 0x8dcb, 0x9d48, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x91c5, 0xfffd, 0x95a5, 0xfffd, 0xfffd,
+ 0x91ef, 0xfffd, 0xfffd, 0x9d4b, 0xfffd, 0xfffd, 0x9d49, 0xfffd,
+ 0x9d4c, 0xfffd, 0xfffd, 0x9d4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9d4d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95af, 0xfffd,
+ 0xfffd, 0x88b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x957d, 0xfffd,
+ 0xfffd, 0x94e1, 0xfffd, 0xfffd, 0x9d4e, 0xfffd, 0x9d51, 0x8fb3,
+ 0x8b5a, 0xfffd, 0x9d4f, 0x9d56, 0x8fb4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9d50, 0x9463, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x977d, 0x9d52, 0x9d53, 0x9d57, 0x938a, 0x9d54, 0x8d52,
+ 0x90dc, 0xfffd, 0xfffd, 0x9d65, 0x94b2, 0xfffd, 0x91f0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x94e2, 0x9dab, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x95f8, 0xfffd, 0xfffd, 0xfffd, 0x92ef, 0xfffd, 0xfffd,
+ 0xfffd, 0x9695, 0xfffd, 0x9d5a, 0x899f, 0x928a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9d63, 0xfffd, 0xfffd, 0x9253, 0x9d5d, 0x9d64,
+ 0x9d5f, 0x9d66, 0x9d62, 0xfffd, 0x9d61, 0x948f, 0xfffd, 0x9d5b,
+ 0x89fb, 0x9d59, 0x8b91, 0x91f1, 0x9d55, 0xfffd, 0xfffd, 0x9d58,
+ 0x8d53, 0x90d9, 0xfffd, 0x8fb5, 0x9d60, 0x9471, 0xfffd, 0xfffd,
+ 0x8b92, 0x8a67, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a87, 0x9040, 0x9d68, 0x9d6d,
+ 0xfffd, 0x9d69, 0xfffd, 0x8c9d, 0xfffd, 0x9d6e, 0x8e41, 0x8d89,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f45, 0x9d5c,
+ 0xfffd, 0x8e9d, 0x9d6b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e77,
+ 0x9d6c, 0x88c2, 0xfffd, 0xfffd, 0x9d67, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x92a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8b93, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bb2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d6a,
+ 0x88a5, 0xfffd, 0xfffd, 0x8dc1, 0xfffd, 0xfffd, 0xfffd, 0x9055,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x92f0, 0xfffd, 0xfffd, 0x94d2, 0x9d70, 0x917d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x91a8, 0xfffd, 0xfffd, 0x8e4a, 0x9d71, 0xfffd, 0x9d73,
+ 0x9d6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95df, 0xfffd, 0x92bb,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x917b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95f9,
+ 0x8ecc, 0x9d80, 0xfffd, 0x9d7e, 0xfffd, 0xfffd, 0x9098, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c9e, 0xfffd, 0xfffd, 0xfffd, 0x9d78, 0x8fb7,
+ 0xfffd, 0xfffd, 0x93e6, 0x9450, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9d76, 0xfffd, 0xfffd, 0x917c, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ef6, 0x9d7b, 0xfffd, 0xfffd, 0x8fb6, 0xfffd, 0x9d75, 0x9d7a,
+ 0xfffd, 0xfffd, 0x9472, 0xfffd, 0xfffd, 0xfffd, 0x9d74, 0xfffd,
+ 0x8c40, 0xfffd, 0xfffd, 0x8a7c, 0xfffd, 0xfffd, 0xfffd, 0x9d7c,
+ 0x97a9, 0x8dcc, 0x9254, 0x9d79, 0xfffd, 0x90da, 0xfffd, 0x8d54,
+ 0x9084, 0x8986, 0x915b, 0x9d77, 0x8b64, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c66, 0xfffd, 0x92cd, 0x9d7d, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x917e, 0xfffd, 0xfffd, 0x9d81, 0xfffd,
+ 0x9d83, 0xfffd, 0xfffd, 0x91b5, 0x9d89, 0xfffd, 0x9d84, 0xfffd,
+ 0xfffd, 0x9d86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9560,
+ 0x92f1, 0xfffd, 0x9d87, 0xfffd, 0xfffd, 0xfffd, 0x974b, 0xfffd,
+ 0xfffd, 0xfffd, 0x9767, 0x8ab7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x88ac, 0xfffd, 0x9d85, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9d82, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8987, 0xfffd, 0x9d88, 0xfffd,
+ 0xfffd, 0xfffd, 0x9768, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d8c, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91b9, 0xfffd, 0x9d93,
+ 0xfffd, 0xfffd, 0xfffd, 0x9d8d, 0xfffd, 0xfffd, 0x9d8a, 0x9d91,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d72, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d8e, 0xfffd,
+ 0x9d92, 0xfffd, 0xfffd, 0xfffd, 0x94c0, 0x938b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d8b, 0xfffd, 0x9d8f, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c67, 0xfffd, 0xfffd, 0xfffd, 0x8def, 0xfffd,
+ 0xfffd, 0xfffd, 0x90db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d97, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9345, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d94,
+ 0xfffd, 0x9680, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d95,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d96, 0xfffd,
+ 0x96cc, 0xfffd, 0x90a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8c82, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9d9d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8e54, 0x9d9a, 0xfffd, 0x9d99, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9451, 0xfffd, 0xfffd, 0xfffd, 0x93b3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9350, 0x9d9b, 0xfffd, 0xfffd,
+ 0xfffd, 0x9d9c, 0xfffd, 0x958f, 0xfffd, 0x9464, 0x8e42, 0xfffd,
+ 0x90ef, 0xfffd, 0x966f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8a68, 0xfffd, 0x9da3, 0x9d9e, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9769, 0x9da5, 0xfffd, 0xfffd, 0x9da1, 0xfffd, 0x9da2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9180, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9da0, 0xfffd, 0x9d5e, 0xfffd, 0xfffd, 0xfffd,
+ 0x9da4, 0xfffd, 0x9d9f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9da9, 0x9daa, 0x9346, 0x9dac, 0xfffd, 0xfffd, 0x8e43, 0x9da7,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b5b, 0xfffd, 0xfffd, 0x9dad,
+ 0xfffd, 0x9da6, 0x9db1, 0xfffd, 0x9db0, 0xfffd, 0x9daf, 0xfffd,
+ 0xfffd, 0xfffd, 0x9db2, 0xfffd, 0xfffd, 0x9db4, 0x8fef, 0xfffd,
+ 0x9db3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9db7, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9db5, 0xfffd, 0xfffd, 0xfffd, 0x9db6, 0x9d90, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9db9, 0x9db8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9d98, 0x9dba, 0x9dae, 0xfffd, 0xfffd, 0x8e78,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dbb, 0x9dbc, 0x9dbe, 0x9dbd,
+ 0x9dbf, 0x89fc, 0xfffd, 0x8d55, 0xfffd, 0xfffd, 0x95fa, 0x90ad,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ccc, 0xfffd, 0xfffd,
+ 0x9dc1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dc4, 0xfffd, 0x9571,
+ 0xfffd, 0x8b7e, 0xfffd, 0xfffd, 0xfffd, 0x9dc3, 0x9dc2, 0x9473,
+ 0x9dc5, 0x8bb3, 0xfffd, 0xfffd, 0xfffd, 0x9dc7, 0x9dc6, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ab8, 0x8e55, 0xfffd, 0xfffd, 0x93d6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c68, 0xfffd, 0xfffd, 0xfffd,
+ 0x9094, 0xfffd, 0x9dc8, 0xfffd, 0x90ae, 0x9347, 0xfffd, 0x957e,
+ 0x9dc9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9dca, 0x9dcb, 0xfffd, 0xfffd, 0xfffd, 0x95b6,
+ 0x9b7c, 0x90c4, 0xfffd, 0xfffd, 0x956b, 0xfffd, 0x8dd6, 0xfffd,
+ 0x94e3, 0x94c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x936c,
+ 0xfffd, 0x97bf, 0xfffd, 0x9dcd, 0x8ece, 0xfffd, 0xfffd, 0x9dce,
+ 0xfffd, 0x88b4, 0xfffd, 0xfffd, 0x8bd2, 0x90cb, 0xfffd, 0x9580,
+ 0xfffd, 0xfffd, 0xfffd, 0x9dcf, 0x8e61, 0x9266, 0xfffd, 0x8e7a,
+ 0x9056, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dd0,
+ 0xfffd, 0x95fb, 0xfffd, 0xfffd, 0x8997, 0x8e7b, 0xfffd, 0xfffd,
+ 0xfffd, 0x9dd3, 0xfffd, 0x9dd1, 0x9dd4, 0x97b7, 0x9dd2, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x90f9, 0x9dd5, 0xfffd, 0xfffd, 0x91b0,
+ 0xfffd, 0xfffd, 0x9dd6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af8,
+ 0xfffd, 0x9dd8, 0xfffd, 0x9dd7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9dd9, 0x9dda, 0x8af9, 0xfffd, 0xfffd, 0x93fa, 0x9255, 0x8b8c,
+ 0x8e7c, 0x9181, 0xfffd, 0xfffd, 0x8f7b, 0x88ae, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ddb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x89a0, 0x9ddf, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8d56, 0x9dde, 0xfffd, 0xfffd, 0x8da9, 0x8fb8,
+ 0xfffd, 0xfffd, 0x9ddd, 0xfffd, 0x8fb9, 0xfffd, 0x96be, 0x8da8,
+ 0xfffd, 0xfffd, 0xfffd, 0x88d5, 0x90cc, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9de4, 0xfffd, 0xfffd, 0x90af,
+ 0x8966, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f74, 0xfffd, 0x9686,
+ 0x8df0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fba, 0xfffd, 0x90a5,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9de3, 0x9de1, 0x9de2, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x928b, 0xfffd, 0xfffd, 0x9e45,
+ 0xfffd, 0x9de8, 0x8e9e, 0x8d57, 0x9de6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9de7, 0xfffd, 0x9057, 0xfffd, 0xfffd, 0xfffd, 0x9de5,
+ 0xfffd, 0xfffd, 0x8e4e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dea, 0x9de9, 0x9dee,
+ 0xfffd, 0xfffd, 0x9def, 0xfffd, 0x9deb, 0xfffd, 0x8a41, 0x9dec,
+ 0x9ded, 0x94d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9581, 0x8c69,
+ 0x9df0, 0xfffd, 0xfffd, 0xfffd, 0x90b0, 0xfffd, 0x8fbb, 0xfffd,
+ 0xfffd, 0xfffd, 0x9271, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8bc5, 0xfffd, 0x9df1, 0x9df5, 0xfffd, 0xfffd, 0x89c9,
+ 0x9df2, 0x9df4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9df3, 0xfffd,
+ 0xfffd, 0x8f8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9267, 0x88c3,
+ 0x9df6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9df7, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x92a8, 0xfffd, 0xfffd, 0xfffd, 0x97ef, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e62, 0xfffd, 0xfffd, 0x95e9, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x965c, 0xfffd, 0xfffd, 0xfffd,
+ 0x9e41, 0x9df9, 0xfffd, 0xfffd, 0x9dfc, 0xfffd, 0x9dfb, 0xfffd,
+ 0xfffd, 0x9df8, 0xfffd, 0xfffd, 0x9e40, 0xfffd, 0xfffd, 0x93dc,
+ 0xfffd, 0x9dfa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e42, 0xfffd,
+ 0xfffd, 0x8f8c, 0x9e43, 0xfffd, 0x976a, 0x9498, 0xfffd, 0xfffd,
+ 0x9e44, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e46, 0xfffd,
+ 0xfffd, 0x9e47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9e48, 0xfffd, 0x8bc8, 0x8967, 0x8d58, 0x9e49, 0xfffd, 0x9e4a,
+ 0x8f91, 0x9182, 0xfffd, 0xfffd, 0x99d6, 0x915d, 0x915c, 0x91d6,
+ 0x8dc5, 0xfffd, 0xfffd, 0x98f0, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c8e, 0x974c, 0xfffd, 0x95fc, 0xfffd, 0x959e, 0xfffd, 0x9e4b,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8df1, 0x92bd, 0x9e4c, 0x984e,
+ 0xfffd, 0xfffd, 0xfffd, 0x965d, 0xfffd, 0x92a9, 0x9e4d, 0x8afa,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e4e, 0x9e4f,
+ 0x96d8, 0xfffd, 0x96a2, 0x9696, 0x967b, 0x8e44, 0x9e51, 0xfffd,
+ 0xfffd, 0x8ee9, 0xfffd, 0xfffd, 0x9670, 0xfffd, 0x9e53, 0x9e56,
+ 0x9e55, 0xfffd, 0x8af7, 0xfffd, 0xfffd, 0x8b80, 0xfffd, 0x9e52,
+ 0xfffd, 0x9e54, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e57, 0xfffd,
+ 0xfffd, 0x9099, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x979b, 0x88c7,
+ 0x8dde, 0x91ba, 0xfffd, 0x8edb, 0xfffd, 0xfffd, 0x8ff1, 0xfffd,
+ 0xfffd, 0x9e5a, 0xfffd, 0xfffd, 0x936d, 0xfffd, 0x9e58, 0x91a9,
+ 0x9e59, 0x8ff0, 0x96db, 0x9e5b, 0x9e5c, 0x9788, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9e61, 0xfffd, 0xfffd, 0x8d59, 0xfffd, 0x9474,
+ 0x9e5e, 0x938c, 0x9ddc, 0x9de0, 0xfffd, 0x8b6e, 0xfffd, 0x9466,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e60, 0xfffd, 0x8fbc, 0x94c2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e66, 0xfffd, 0x94f8,
+ 0xfffd, 0x9e5d, 0xfffd, 0x9e63, 0x9e62, 0xfffd, 0xfffd, 0xfffd,
+ 0x90cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x968d, 0xfffd, 0x97d1,
+ 0xfffd, 0xfffd, 0x9687, 0xfffd, 0x89ca, 0x8e7d, 0xfffd, 0xfffd,
+ 0x9867, 0x9e65, 0x9095, 0xfffd, 0xfffd, 0xfffd, 0x9e64, 0xfffd,
+ 0xfffd, 0x9e5f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ccd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9e6b, 0x9e69, 0xfffd, 0x89cb, 0x9e67,
+ 0x9e6d, 0x9e73, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x91c6, 0xfffd, 0xfffd, 0x95bf, 0xfffd, 0x9e75, 0xfffd,
+ 0xfffd, 0xfffd, 0x9541, 0xfffd, 0xfffd, 0xfffd, 0x9e74, 0x9490,
+ 0x965e, 0x8ab9, 0xfffd, 0x90f5, 0x8f5f, 0xfffd, 0xfffd, 0xfffd,
+ 0x92d1, 0xfffd, 0x974d, 0xfffd, 0xfffd, 0x9e70, 0x9e6f, 0xfffd,
+ 0xfffd, 0xfffd, 0x9e71, 0xfffd, 0x9e6e, 0xfffd, 0xfffd, 0x9e76,
+ 0xfffd, 0x9e6c, 0xfffd, 0xfffd, 0x9e6a, 0xfffd, 0x9e72, 0x9e68,
+ 0xfffd, 0x928c, 0xfffd, 0x96f6, 0x8ec4, 0x8df2, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8db8, 0xfffd, 0xfffd, 0x968f, 0x8a60,
+ 0xfffd, 0xfffd, 0x92cc, 0x93c8, 0x8968, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x90f0, 0xfffd, 0xfffd, 0x90b2, 0x8c49,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e78, 0xfffd,
+ 0xfffd, 0x8d5a, 0x8a9c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9e7a, 0x8a94, 0x9e81, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9e7d, 0xfffd, 0x90f1, 0xfffd, 0xfffd, 0xfffd,
+ 0x8a6a, 0x8daa, 0xfffd, 0xfffd, 0x8a69, 0x8dcd, 0xfffd, 0xfffd,
+ 0x9e7b, 0x8c85, 0x8c6a, 0x938d, 0xfffd, 0xfffd, 0x9e79, 0xfffd,
+ 0x88c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e7c, 0x9e7e, 0xfffd,
+ 0x8bcb, 0x8c4b, 0xfffd, 0x8aba, 0x8b6a, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9e82, 0xfffd, 0xfffd, 0x8df7, 0x9691, 0xfffd, 0x8e56,
+ 0xfffd, 0xfffd, 0xfffd, 0x9e83, 0xfffd, 0xfffd, 0xfffd, 0x954f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e8f, 0xfffd, 0x89b1, 0x9e84,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e95, 0x9e85,
+ 0xfffd, 0x97c0, 0xfffd, 0x9e8c, 0xfffd, 0x947e, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e94, 0xfffd, 0x9e87,
+ 0xfffd, 0xfffd, 0xfffd, 0x88b2, 0x9e89, 0xfffd, 0xfffd, 0x8d5b,
+ 0xfffd, 0xfffd, 0xfffd, 0x9e8b, 0xfffd, 0x9e8a, 0xfffd, 0x9e86,
+ 0x9e91, 0xfffd, 0x8fbd, 0xfffd, 0xfffd, 0xfffd, 0x9aeb, 0x8ce6,
+ 0x979c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e88, 0xfffd, 0x92f2,
+ 0x8a42, 0x8dab, 0xfffd, 0x9e80, 0xfffd, 0x9e90, 0x8a81, 0xfffd,
+ 0xfffd, 0x9e8e, 0x9e92, 0xfffd, 0x938e, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8afc, 0xfffd, 0x9eb0, 0xfffd,
+ 0xfffd, 0x96c7, 0x9e97, 0x8afb, 0xfffd, 0x9e9e, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x965f, 0xfffd, 0x9e9f, 0x9ea1, 0xfffd, 0x9ea5,
+ 0x9e99, 0xfffd, 0x9249, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x938f,
+ 0x9ea9, 0x9e9c, 0xfffd, 0x9ea6, 0xfffd, 0xfffd, 0xfffd, 0x9ea0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9058, 0x9eaa,
+ 0xfffd, 0xfffd, 0x90b1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ea8, 0x8abb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x986f, 0x9e96, 0xfffd, 0xfffd, 0x9ea4, 0x88d6, 0xfffd, 0xfffd,
+ 0x9e98, 0xfffd, 0xfffd, 0x96b8, 0x9e9d, 0x9041, 0x92c5, 0x9e93,
+ 0xfffd, 0xfffd, 0x9ea3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x909a, 0x9ead, 0x8a91, 0x8c9f, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9eaf, 0x9e9a, 0x9eae, 0xfffd, 0x9ea7, 0x9e9b, 0xfffd,
+ 0x9eab, 0xfffd, 0x9eac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ebd, 0xfffd, 0xfffd, 0xfffd, 0x93cc, 0xfffd, 0x9ea2, 0xfffd,
+ 0xfffd, 0x9eb9, 0xfffd, 0xfffd, 0xfffd, 0x9ebb, 0xfffd, 0x92d6,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x976b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9596, 0x9eb6, 0x91c8, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ebc, 0x915e, 0xfffd, 0x9eb3, 0x9ec0, 0x9ebf, 0xfffd,
+ 0x93ed, 0x9ebe, 0x93e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ec2, 0x9eb5, 0xfffd, 0x8bc6, 0x9eb8, 0x8f7c,
+ 0xfffd, 0xfffd, 0xfffd, 0x9480, 0x9eba, 0x8bc9, 0xfffd, 0x9eb2,
+ 0x9eb4, 0x9eb1, 0xfffd, 0xfffd, 0x984f, 0x8a79, 0x9eb7, 0xfffd,
+ 0xfffd, 0x9ec1, 0x8a54, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8de5, 0xfffd, 0xfffd, 0xfffd, 0x897c, 0xfffd,
+ 0xfffd, 0x9ed2, 0xfffd, 0xfffd, 0x9850, 0x9ed5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9059, 0x9ed4, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ed3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ed0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ec4, 0xfffd,
+ 0xfffd, 0x9ee1, 0x9ec3, 0xfffd, 0x9ed6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9ece, 0xfffd, 0xfffd, 0x9ec9, 0x9ec6,
+ 0xfffd, 0x9ec7, 0xfffd, 0x9ecf, 0xfffd, 0xfffd, 0xfffd, 0xeaa0,
+ 0xfffd, 0xfffd, 0x9ecc, 0x8d5c, 0x92c6, 0x9184, 0x9eca, 0xfffd,
+ 0x9ec5, 0xfffd, 0xfffd, 0x9ec8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x976c, 0x968a, 0xfffd, 0xfffd, 0xfffd, 0x9ecd, 0x9ed7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9edf,
+ 0x9ed8, 0xfffd, 0xfffd, 0x9ee5, 0xfffd, 0x9ee3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ede, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9edd, 0xfffd, 0x92ce, 0xfffd, 0x9185, 0xfffd, 0x9edb,
+ 0xfffd, 0xfffd, 0x9ed9, 0xfffd, 0xfffd, 0x9ee0, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ee6, 0x94f3, 0x9eec, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9ee7, 0x9eea, 0x9ee4, 0xfffd, 0xfffd, 0x9294,
+ 0xfffd, 0x9557, 0xfffd, 0x9eda, 0xfffd, 0xfffd, 0x9ee2, 0x8fbe,
+ 0xfffd, 0x96cd, 0x9ef6, 0x9ee9, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8ca0, 0x89a1, 0x8a7e, 0xfffd, 0xfffd, 0x9ed1, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fbf, 0x9eee, 0xfffd,
+ 0x9ef5, 0x8ef7, 0x8a92, 0xfffd, 0xfffd, 0x924d, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9eeb, 0xfffd, 0xfffd, 0x9ef0,
+ 0x9ef4, 0xfffd, 0xfffd, 0x8bb4, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b6b, 0x9ef2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b40,
+ 0xfffd, 0x93c9, 0x9ef1, 0xfffd, 0xfffd, 0xfffd, 0x9ef3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9eed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9eef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a80,
+ 0x9268, 0xfffd, 0xfffd, 0xfffd, 0x9efa, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ef8, 0x8ce7, 0xfffd,
+ 0x9ef7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f40,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e77, 0xfffd, 0xfffd, 0xfffd,
+ 0x9ef9, 0xfffd, 0x9efb, 0x9efc, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9f4b, 0xfffd, 0x9f47, 0xfffd, 0x9e8d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f46, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9f45, 0xfffd, 0xfffd, 0x9f42, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ee8, 0x9f44, 0x9f43, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9f49, 0xfffd, 0x9845, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9f4c, 0x8bf9, 0xfffd, 0xfffd, 0x9f48, 0x9f4a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x94a5, 0xfffd, 0x9f4d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9f51, 0x9f4e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9793, 0x9f4f, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9edc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9f52, 0xfffd, 0xfffd, 0xfffd, 0x9f53, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8954, 0xfffd, 0x9f55,
+ 0x8c87, 0x8e9f, 0xfffd, 0x8bd3, 0xfffd, 0xfffd, 0xfffd, 0x89a2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x977e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f57,
+ 0x9f56, 0x9f59, 0x8b5c, 0xfffd, 0xfffd, 0x8bd4, 0x8abc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f5c, 0xfffd, 0xfffd, 0xfffd, 0x9f5b,
+ 0xfffd, 0x9f5d, 0xfffd, 0xfffd, 0x89cc, 0xfffd, 0x9256, 0xfffd,
+ 0x9f5e, 0xfffd, 0xfffd, 0x8abd, 0x9f60, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9f5f, 0xfffd, 0x9f61, 0xfffd, 0xfffd, 0xfffd, 0x9f62,
+ 0xfffd, 0x9f63, 0x8e7e, 0x90b3, 0x8d9f, 0xfffd, 0x9590, 0xfffd,
+ 0xfffd, 0x95e0, 0x9863, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e95,
+ 0xfffd, 0xfffd, 0xfffd, 0x8dce, 0x97f0, 0xfffd, 0xfffd, 0xfffd,
+ 0x9f64, 0x9f65, 0xfffd, 0x8e80, 0xfffd, 0xfffd, 0xfffd, 0x9f66,
+ 0x9f67, 0xfffd, 0xfffd, 0x9f69, 0x9f68, 0xfffd, 0x9677, 0xfffd,
+ 0xfffd, 0x8f7d, 0x8eea, 0x8e63, 0xfffd, 0x9f6a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6c, 0x9042, 0xfffd,
+ 0x9f6b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6e, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9f6f, 0x9f70, 0xfffd, 0xfffd, 0xfffd, 0x9f71,
+ 0xfffd, 0x9f73, 0x9f72, 0x9f74, 0x89a3, 0x9269, 0xfffd, 0x9f75,
+ 0xfffd, 0xfffd, 0x8e45, 0x8a6b, 0x9f76, 0xfffd, 0xfffd, 0x9361,
+ 0x9aca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b42, 0x9f77, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f78, 0xfffd, 0x95ea, 0x9688, 0xfffd,
+ 0xfffd, 0xfffd, 0x93c5, 0x9f79, 0x94e4, 0xfffd, 0xfffd, 0xfffd,
+ 0x94f9, 0xfffd, 0xfffd, 0x96d1, 0xfffd, 0xfffd, 0xfffd, 0x9f7a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f7c, 0x9f7b, 0xfffd, 0xfffd, 0x9f7e,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9f81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e81,
+ 0xfffd, 0x96af, 0xfffd, 0x9f82, 0x9f83, 0xfffd, 0xfffd, 0x8b43,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f84, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f86, 0x9f85, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9085, 0xfffd, 0xfffd, 0x9558,
+ 0x8969, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94c3, 0xfffd,
+ 0x92f3, 0x8f60, 0x8b81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94c4, 0xfffd,
+ 0x8eac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f88, 0xfffd, 0x8abe,
+ 0xfffd, 0xfffd, 0x8998, 0xfffd, 0xfffd, 0x93f0, 0x9f87, 0x8d5d,
+ 0x9272, 0xfffd, 0x9f89, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9f91, 0xfffd, 0x9f8a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x91bf, 0xfffd, 0x8b82, 0x9f92, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c88, 0xfffd, 0xfffd, 0x8b44, 0x9f90, 0xfffd,
+ 0xfffd, 0x9f8e, 0x9f8b, 0x9780, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x92be, 0xfffd, 0xfffd, 0xfffd, 0x93d7, 0x9f8c, 0xfffd, 0xfffd,
+ 0x9f94, 0xfffd, 0x9f93, 0x8c42, 0xfffd, 0xfffd, 0x89ab, 0xfffd,
+ 0xfffd, 0x8db9, 0x9f8d, 0x9f8f, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9676, 0x91f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9697, 0xfffd, 0xfffd, 0x9f9c, 0xfffd,
+ 0xfffd, 0x9f9d, 0xfffd, 0x89cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x95a6, 0x96fb, 0x9f9f, 0x8ea1, 0x8fc0, 0x9f98, 0x9f9e, 0x8988,
+ 0xfffd, 0x8bb5, 0xfffd, 0xfffd, 0x9f95, 0x9f9a, 0xfffd, 0xfffd,
+ 0xfffd, 0x90f2, 0x9491, 0xfffd, 0x94e5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9f97, 0xfffd, 0x9640, 0xfffd, 0x9f99,
+ 0xfffd, 0x9fa2, 0xfffd, 0x9fa0, 0xfffd, 0x9f9b, 0xfffd, 0xfffd,
+ 0xfffd, 0x9641, 0x9467, 0x8b83, 0xfffd, 0x9344, 0xfffd, 0xfffd,
+ 0x928d, 0xfffd, 0x9fa3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fa1,
+ 0x91d7, 0x9f96, 0xfffd, 0x896a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x976d, 0x9fae, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9fad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90f4,
+ 0xfffd, 0x9faa, 0xfffd, 0x978c, 0xfffd, 0xfffd, 0x93b4, 0x9fa4,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92c3, 0xfffd, 0xfffd,
+ 0xfffd, 0x896b, 0x8d5e, 0x9fa7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8f46, 0x9fac, 0xfffd, 0x9fab, 0x9fa6, 0xfffd,
+ 0x9fa9, 0xfffd, 0xfffd, 0x8a88, 0xfffd, 0x9fa8, 0x9468, 0xfffd,
+ 0xfffd, 0x97ac, 0xfffd, 0xfffd, 0x8ff2, 0x90f3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9fb4, 0x9fb2, 0xfffd, 0x956c, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9faf, 0x9fb1, 0xfffd, 0x8959, 0xfffd,
+ 0xfffd, 0x8d5f, 0x9851, 0xfffd, 0x8a5c, 0xfffd, 0x9582, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9781, 0xfffd, 0xfffd, 0x8a43,
+ 0x905a, 0x9fb3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fb8, 0xfffd, 0xfffd,
+ 0x8fc1, 0xfffd, 0xfffd, 0xfffd, 0x974f, 0xfffd, 0x9fb5, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9fb0, 0xfffd, 0x9fb6, 0xfffd, 0xfffd,
+ 0xfffd, 0x97dc, 0xfffd, 0x9393, 0x93c0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a55,
+ 0xfffd, 0xfffd, 0x8974, 0xfffd, 0xfffd, 0x9fbc, 0xfffd, 0xfffd,
+ 0x9fbf, 0xfffd, 0xfffd, 0xfffd, 0x97c1, 0xfffd, 0xfffd, 0xfffd,
+ 0x9784, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fc6, 0x9fc0, 0x9fbd,
+ 0xfffd, 0xfffd, 0xfffd, 0x97d2, 0x9fc3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8f69, 0x9fc5, 0xfffd, 0xfffd, 0x9fca, 0xfffd, 0xfffd,
+ 0x9391, 0x9fc8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fc2, 0xfffd,
+ 0xfffd, 0x9257, 0xfffd, 0xfffd, 0x9fc9, 0xfffd, 0x9fbe, 0xfffd,
+ 0x9fc4, 0xfffd, 0x9fcb, 0x88fa, 0x9fc1, 0xfffd, 0x9fcc, 0xfffd,
+ 0xfffd, 0x905b, 0xfffd, 0x8f7e, 0xfffd, 0x95a3, 0xfffd, 0x8dac,
+ 0xfffd, 0x9fb9, 0x9fc7, 0x9359, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90b4, 0xfffd, 0x8a89,
+ 0x8dcf, 0x8fc2, 0x9fbb, 0x8f61, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8c6b, 0xfffd, 0x9fba, 0xfffd, 0xfffd,
+ 0xfffd, 0x9fd0, 0x8f8d, 0x8cb8, 0xfffd, 0x9fdf, 0xfffd, 0x9fd9,
+ 0x8b94, 0x936e, 0xfffd, 0x9fd4, 0x9fdd, 0x88ad, 0x8951, 0xfffd,
+ 0xfffd, 0x89b7, 0xfffd, 0x9fd6, 0x91aa, 0x9fcd, 0x9fcf, 0x8d60,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9fe0, 0xfffd, 0x9fdb, 0xfffd, 0xfffd, 0xfffd, 0x9fd3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9fda, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x96a9, 0xfffd, 0xfffd, 0x9fd8, 0x9fdc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cce, 0xfffd,
+ 0x8fc3, 0xfffd, 0xfffd, 0x9258, 0xfffd, 0xfffd, 0xfffd, 0x9fd2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x974e,
+ 0xfffd, 0xfffd, 0xfffd, 0x9fd5, 0xfffd, 0xfffd, 0x9fce, 0x9392,
+ 0xfffd, 0xfffd, 0x9fd1, 0xfffd, 0xfffd, 0xfffd, 0x9fd7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9870, 0x8ebc,
+ 0x969e, 0xfffd, 0x9fe1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ac, 0xfffd, 0xfffd, 0x9fed,
+ 0x8cb9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f80, 0xfffd,
+ 0x9fe3, 0xfffd, 0xfffd, 0xfffd, 0x97ad, 0x8d61, 0xfffd, 0x9ff0,
+ 0xfffd, 0xfffd, 0x88ec, 0xfffd, 0xfffd, 0x9fee, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9fe2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fe8,
+ 0xfffd, 0xfffd, 0x9fea, 0xfffd, 0xfffd, 0xfffd, 0x976e, 0x9fe5,
+ 0xfffd, 0xfffd, 0x934d, 0xfffd, 0xfffd, 0x9fe7, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9fef, 0xfffd, 0x9fe9, 0x96c5, 0xfffd, 0xfffd,
+ 0xfffd, 0x9fe4, 0xfffd, 0x8ea0, 0x9ffc, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8a8a, 0xfffd, 0x9fe6, 0x9feb, 0x9fec, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91ea, 0x91d8, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff4, 0xfffd, 0xfffd, 0x9ffa,
+ 0xfffd, 0xfffd, 0x9ff8, 0xfffd, 0x9348, 0xfffd, 0xfffd, 0xe042,
+ 0x9ff5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff6, 0x9fde,
+ 0xfffd, 0x8b99, 0x9559, 0xfffd, 0xfffd, 0xfffd, 0x8ebd, 0xfffd,
+ 0xfffd, 0x8d97, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9852,
+ 0xfffd, 0x9ff2, 0xfffd, 0xe041, 0x8989, 0x9186, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9499, 0xfffd, 0x8abf, 0x97f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x969f, 0x92d0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9ff9, 0x9ffb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9151, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe040, 0x9ff7,
+ 0xfffd, 0x9ff1, 0xfffd, 0xfffd, 0xfffd, 0x8ac1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c89, 0xfffd, 0xfffd, 0xfffd,
+ 0xe04e, 0xfffd, 0xfffd, 0xe049, 0x90f6, 0xfffd, 0xfffd, 0x8a83,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f81, 0xfffd, 0xe052, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe04b, 0x92aa, 0xe048,
+ 0x92d7, 0xfffd, 0xfffd, 0xfffd, 0xe06b, 0xfffd, 0xfffd, 0xfffd,
+ 0xe045, 0xfffd, 0xe044, 0xfffd, 0xe04d, 0xfffd, 0xfffd, 0xfffd,
+ 0xe047, 0xe046, 0xe04c, 0xfffd, 0x909f, 0xfffd, 0xe043, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe04f, 0xfffd,
+ 0xfffd, 0xe050, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ac0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe055, 0xfffd, 0xe054, 0xe056, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe059, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9362, 0xfffd, 0xe053, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe057, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c83, 0x91f7, 0xe051, 0x945a, 0xfffd, 0xfffd, 0xe058, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe05d, 0xe05b, 0xfffd, 0xfffd,
+ 0xe05e, 0xfffd, 0xfffd, 0xe061, 0xfffd, 0xfffd, 0xfffd, 0xe05a,
+ 0x8d8a, 0x9447, 0xfffd, 0xfffd, 0x9fb7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9794, 0xe05c, 0xfffd, 0xe060, 0x91f3,
+ 0xfffd, 0xe05f, 0xfffd, 0xe04a, 0xfffd, 0xfffd, 0xe889, 0xfffd,
+ 0xfffd, 0xfffd, 0xe064, 0xfffd, 0xfffd, 0xfffd, 0xe068, 0xfffd,
+ 0xfffd, 0xe066, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe062, 0xfffd, 0xe063, 0xfffd, 0xfffd, 0xfffd, 0xe067,
+ 0xfffd, 0xe065, 0xfffd, 0xfffd, 0xfffd, 0x956d, 0xfffd, 0xfffd,
+ 0xe06d, 0xfffd, 0xe06a, 0xe069, 0xfffd, 0xe06c, 0x93d2, 0xe06e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9295, 0x91eb,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90a3, 0xfffd, 0xfffd, 0xfffd,
+ 0xe06f, 0xfffd, 0xe071, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe070, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe072, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x93e5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe073, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x89ce, 0xfffd, 0xfffd, 0xfffd, 0x9394,
+ 0x8a44, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b84, 0xfffd, 0xfffd, 0xfffd, 0x8edc, 0x8dd0, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9846, 0x9086, 0xfffd, 0xfffd, 0xfffd, 0x898a, 0xfffd,
+ 0xfffd, 0xfffd, 0xe075, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe074, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe078, 0x9259, 0xe07b, 0xe076,
+ 0xfffd, 0xfffd, 0xfffd, 0xe07a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe079, 0x935f, 0x88d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x97f3, 0xfffd, 0xfffd, 0xe07d, 0xfffd, 0xfffd, 0xfffd, 0x8947,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe080, 0xfffd, 0xfffd, 0xfffd, 0xe07e, 0xfffd, 0xe07c,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe077, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9642, 0xfffd, 0xfffd, 0xfffd, 0xe082, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe081, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x898b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe084, 0x95b0, 0xfffd, 0xe083, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x96b3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fc5, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9152, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fc4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x97f9, 0xfffd, 0xfffd, 0xe08a, 0xfffd, 0x90f7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe086, 0xe08b, 0xfffd,
+ 0xfffd, 0x898c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe089, 0xfffd, 0x9481, 0xe085, 0xe088, 0x8fc6,
+ 0xfffd, 0x94cf, 0xfffd, 0xfffd, 0xe08c, 0xfffd, 0x8ecf, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90f8, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe08f, 0xfffd, 0xfffd, 0xfffd,
+ 0xe087, 0xfffd, 0x8c46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe08d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x976f, 0xe090, 0xfffd, 0xfffd,
+ 0xfffd, 0xeaa4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f6e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe091, 0xfffd, 0xfffd, 0xfffd, 0xe092, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x944d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe094, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe095, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9452, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9395, 0xe097, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe099, 0xfffd,
+ 0x97d3, 0xfffd, 0xe096, 0xfffd, 0xe098, 0x898d, 0xfffd, 0xe093,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a7a,
+ 0xe09a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9187, 0x8e57, 0xe09c,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe09b, 0x9043, 0x99d7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe09d, 0xfffd, 0xfffd,
+ 0xfffd, 0xe09f, 0xfffd, 0xe08e, 0xe09e, 0xfffd, 0xfffd, 0xe0a0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x949a, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0a1, 0xfffd, 0xfffd,
+ 0xe0a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe0a3, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0a4, 0xfffd, 0x92dc, 0xfffd, 0xe0a6, 0xe0a5, 0xfffd, 0xfffd,
+ 0xe0a7, 0xfffd, 0xe0a8, 0xfffd, 0xfffd, 0x8edd, 0x9583, 0xfffd,
+ 0xfffd, 0xfffd, 0x96ea, 0xe0a9, 0xe0aa, 0x9175, 0x8ea2, 0xe0ab,
+ 0xe0ac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0ad, 0x95d0,
+ 0x94c5, 0xfffd, 0xfffd, 0xe0ae, 0x9476, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x92ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0af, 0x89e5, 0xfffd, 0x8b8d, 0xfffd, 0x96c4, 0xfffd, 0x96b4,
+ 0xfffd, 0x89b2, 0x9853, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9671,
+ 0xfffd, 0x95a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x90b5, 0xfffd, 0xe0b0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x93c1, 0xfffd, 0xfffd, 0xfffd, 0x8ca1, 0xe0b1, 0xfffd,
+ 0x8dd2, 0xe0b3, 0xe0b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0b4,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe0b5, 0xfffd, 0xfffd, 0xfffd, 0xe0b6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b5d, 0xfffd, 0xe0b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0b8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ca2, 0xfffd, 0xfffd, 0x94c6,
+ 0xfffd, 0xfffd, 0xe0ba, 0xfffd, 0xfffd, 0xfffd, 0x8ff3, 0xfffd,
+ 0xfffd, 0xe0b9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8bb6, 0xe0bb, 0xe0bd, 0xfffd, 0xe0bc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0be, 0xfffd,
+ 0x8ccf, 0xfffd, 0xe0bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8be7,
+ 0xfffd, 0x915f, 0xfffd, 0x8d9d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0c1, 0xe0c2, 0xe0c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8eeb, 0xfffd, 0xfffd, 0x93c6, 0x8bb7, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0c4,
+ 0x924b, 0xe0c3, 0xfffd, 0xfffd, 0x9854, 0x9482, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe0c7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0c9, 0xe0c6,
+ 0xfffd, 0xfffd, 0xfffd, 0x96d2, 0xe0c8, 0xe0ca, 0xfffd, 0x97c2,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0ce, 0xfffd, 0xfffd,
+ 0xfffd, 0xe0cd, 0x9296, 0x944c, 0xfffd, 0xfffd, 0x8ca3, 0xe0cc,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0cb, 0xfffd, 0x9750, 0x9751,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0cf, 0x898e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d96, 0x8e82, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0d0, 0xe0d1,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0d3,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8f62, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0d5, 0xfffd, 0xe0d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0d6, 0xfffd, 0x8a6c, 0xfffd, 0xfffd, 0xe0d8, 0xfffd, 0xfffd,
+ 0xe0d7, 0xfffd, 0xe0da, 0xe0d9, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cba, 0xfffd, 0xfffd, 0x97a6,
+ 0xfffd, 0x8bca, 0xfffd, 0x89a4, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8be8, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8adf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x97e6, 0xe0dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe0de, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0df, 0xfffd, 0x89cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0db, 0xfffd, 0x8e58, 0xfffd, 0xfffd, 0x92bf, 0xe0dd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e2, 0xfffd,
+ 0x8eec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e0, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8c5d, 0xfffd, 0xfffd, 0x94c7, 0xe0e1, 0xfffd,
+ 0xfffd, 0xe0fc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cbb, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8b85, 0xfffd, 0xe0e4, 0x979d, 0xfffd,
+ 0xfffd, 0x97ae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x91f4, 0xfffd, 0xfffd, 0xe0e6, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe0e8, 0x97d4, 0x8bd5, 0x94fa, 0x9469, 0xfffd,
+ 0xfffd, 0xfffd, 0xe0e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0eb,
+ 0xfffd, 0xe0ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0ea, 0xfffd, 0xfffd,
+ 0xfffd, 0xe0ed, 0x8ce8, 0x896c, 0xe0ef, 0xfffd, 0x9090, 0xe0ec,
+ 0x97da, 0xfffd, 0xfffd, 0xe0f2, 0xeaa2, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe0f0, 0xe0f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e5,
+ 0xe0f1, 0xfffd, 0xfffd, 0x8dba, 0xfffd, 0xfffd, 0xe0f4, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f5, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x979e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe0f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f7, 0xfffd,
+ 0xfffd, 0xfffd, 0xe0e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ac2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ea3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe0f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0fa,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0fb, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x895a, 0xfffd, 0xfffd, 0xfffd,
+ 0xe140, 0xfffd, 0x955a, 0xe141, 0xfffd, 0xfffd, 0x8aa2, 0xe142,
+ 0xfffd, 0xe143, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe144, 0xfffd,
+ 0xe146, 0xe147, 0xe145, 0xfffd, 0xfffd, 0xfffd, 0x9572, 0xe149,
+ 0xe148, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe14b, 0xe14a, 0xe14c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe14d, 0xe14f, 0xe14e, 0xfffd,
+ 0xfffd, 0x8d99, 0xfffd, 0xe151, 0xfffd, 0xe150, 0xfffd, 0xfffd,
+ 0x8ac3, 0xfffd, 0x9072, 0xfffd, 0x935b, 0xfffd, 0xe152, 0x90b6,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e59, 0xfffd, 0x8999, 0xe153, 0xfffd,
+ 0x9770, 0xfffd, 0xfffd, 0x95e1, 0xe154, 0xfffd, 0xfffd, 0xfffd,
+ 0x9363, 0x9752, 0x8d62, 0x905c, 0xfffd, 0xfffd, 0xfffd, 0x926a,
+ 0x99b2, 0xfffd, 0x92ac, 0x89e6, 0xe155, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe156, 0xfffd, 0xe15b, 0xfffd,
+ 0xfffd, 0xe159, 0xe158, 0x9dc0, 0x8a45, 0xe157, 0xfffd, 0x88d8,
+ 0xfffd, 0x94a8, 0xfffd, 0xfffd, 0x94c8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x97af, 0xe15c, 0xe15a, 0x927b, 0x90a4, 0xfffd, 0xfffd,
+ 0x94a9, 0xfffd, 0x954c, 0xfffd, 0xe15e, 0x97aa, 0x8c6c, 0xe15f,
+ 0xfffd, 0xe15d, 0x94d4, 0xe160, 0xfffd, 0xe161, 0xfffd, 0xfffd,
+ 0x88d9, 0xfffd, 0xfffd, 0x8ff4, 0xe166, 0xfffd, 0xe163, 0x93eb,
+ 0xe162, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b45,
+ 0xfffd, 0xfffd, 0xe169, 0xfffd, 0xfffd, 0xfffd, 0xe164, 0xe165,
+ 0xfffd, 0xe168, 0xe167, 0x9544, 0xfffd, 0xfffd, 0x9161, 0x9160,
+ 0xfffd, 0x8b5e, 0xfffd, 0xfffd, 0xe16a, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe16b, 0xfffd, 0xfffd, 0xe16c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe16e, 0xfffd, 0xe16d, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8975, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe176, 0x94e6, 0xe170, 0xfffd, 0xe172, 0xfffd, 0xfffd,
+ 0xe174, 0x905d, 0xfffd, 0xfffd, 0xe175, 0xe173, 0x8ebe, 0xfffd,
+ 0xfffd, 0xfffd, 0xe16f, 0xe171, 0xfffd, 0x9561, 0xfffd, 0x8fc7,
+ 0xfffd, 0xfffd, 0xe178, 0xfffd, 0xfffd, 0xe177, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe179, 0xfffd, 0x8ea4, 0x8dad, 0xfffd, 0xfffd,
+ 0x9397, 0xe17a, 0xfffd, 0x92c9, 0xfffd, 0xfffd, 0xe17c, 0xfffd,
+ 0xfffd, 0xfffd, 0x979f, 0xe17b, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9189, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe182, 0xfffd, 0xe184, 0xe185, 0x9273, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe183, 0xfffd, 0xe180, 0xfffd, 0xe17d, 0xe17e,
+ 0xfffd, 0xe181, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe188, 0xfffd, 0xe186, 0xfffd, 0xe187, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe189,
+ 0xe18b, 0xe18c, 0xe18d, 0xfffd, 0xe18e, 0xfffd, 0xfffd, 0xe18a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe190, 0xfffd, 0xfffd, 0xfffd, 0xe18f, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe191, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x97c3, 0xfffd, 0xfffd, 0xfffd, 0xe194, 0xe192,
+ 0xe193, 0xfffd, 0xfffd, 0xfffd, 0x8ae0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x96fc, 0xfffd, 0xfffd, 0xfffd, 0x95c8, 0xfffd,
+ 0xe196, 0xfffd, 0xfffd, 0xfffd, 0xe195, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe197, 0xe198, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe19c,
+ 0xe199, 0xe19a, 0xe19b, 0xfffd, 0xe19d, 0xfffd, 0xfffd, 0xfffd,
+ 0xe19e, 0xfffd, 0xe19f, 0xfffd, 0xfffd, 0xfffd, 0xe1a0, 0xfffd,
+ 0xe1a1, 0xfffd, 0x94ad, 0x936f, 0xe1a2, 0x9492, 0x9553, 0xfffd,
+ 0xe1a3, 0xfffd, 0xfffd, 0xe1a4, 0x9349, 0xfffd, 0x8a46, 0x8d63,
+ 0xe1a5, 0xfffd, 0xfffd, 0xe1a6, 0xfffd, 0xfffd, 0xe1a7, 0xfffd,
+ 0x8e48, 0xfffd, 0xfffd, 0xe1a9, 0xfffd, 0xfffd, 0xe1a8, 0xfffd,
+ 0xfffd, 0xe1aa, 0xe1ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94e7, 0xfffd,
+ 0xe1ac, 0xfffd, 0xfffd, 0xfffd, 0xe1ad, 0xfffd, 0xfffd, 0xea89,
+ 0xe1ae, 0xe1af, 0xe1b0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e4d,
+ 0xfffd, 0xfffd, 0xe1b1, 0x9475, 0xfffd, 0xfffd, 0x967e, 0xfffd,
+ 0x896d, 0xfffd, 0x8976, 0xfffd, 0xfffd, 0xe1b2, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe1b4, 0xfffd, 0xfffd, 0xfffd, 0xe1b3, 0x9390,
+ 0xfffd, 0xfffd, 0xfffd, 0x90b7, 0x9f58, 0xfffd, 0xe1b5, 0x96bf,
+ 0xfffd, 0xe1b6, 0xfffd, 0x8ac4, 0x94d5, 0xe1b7, 0xfffd, 0xe1b8,
+ 0xfffd, 0xfffd, 0xe1b9, 0xfffd, 0xfffd, 0xfffd, 0x96da, 0xfffd,
+ 0xfffd, 0xfffd, 0x96d3, 0xfffd, 0x92bc, 0xfffd, 0xfffd, 0xfffd,
+ 0x918a, 0xfffd, 0xfffd, 0xe1bb, 0xfffd, 0xfffd, 0x8f82, 0xfffd,
+ 0xfffd, 0x8fc8, 0xfffd, 0xfffd, 0xe1be, 0xfffd, 0xfffd, 0xe1bd,
+ 0xe1bc, 0x94fb, 0xfffd, 0x8ac5, 0x8ca7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe1c4, 0xfffd, 0xfffd, 0xe1c1, 0x905e,
+ 0x96b0, 0xfffd, 0xfffd, 0xfffd, 0xe1c0, 0xe1c2, 0xe1c3, 0xfffd,
+ 0xfffd, 0xe1bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1c5,
+ 0xe1c6, 0xfffd, 0x92ad, 0xfffd, 0x8ae1, 0xfffd, 0xfffd, 0xfffd,
+ 0x9285, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1c7,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe1c8, 0xe1cb, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9087, 0xfffd, 0x93c2, 0xfffd, 0xe1cc, 0x9672, 0xfffd,
+ 0xe1c9, 0xfffd, 0xfffd, 0xe1ca, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe1cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ce, 0xe1cd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe1d1, 0xfffd, 0xfffd, 0xe1d0, 0xfffd,
+ 0xfffd, 0xe1d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1d4, 0xfffd,
+ 0xe1d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95cb, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f75, 0x97c4, 0xfffd, 0xfffd,
+ 0xe1d5, 0xfffd, 0xfffd, 0x93b5, 0xfffd, 0xfffd, 0xe1d6, 0xfffd,
+ 0xfffd, 0xe1d7, 0xfffd, 0xe1db, 0xe1d9, 0xe1da, 0xfffd, 0xe1d8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1dc,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1dd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1de,
+ 0xfffd, 0xfffd, 0xe1df, 0x96b5, 0xe1e0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x96ee, 0xe1e1, 0xfffd, 0x926d, 0xfffd, 0x948a,
+ 0xfffd, 0x8be9, 0xfffd, 0xfffd, 0xfffd, 0x925a, 0xe1e2, 0x8bb8,
+ 0xfffd, 0xfffd, 0xfffd, 0x90ce, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8dbb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe1e5, 0xfffd, 0x8ca4, 0x8dd3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe1e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9375, 0x8dd4, 0x8b6d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9643, 0xfffd, 0x946a, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9376, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d7b,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e9, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fc9, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x97b0, 0x8d64, 0xfffd, 0xfffd, 0x8ca5,
+ 0xfffd, 0xfffd, 0x94a1, 0xfffd, 0xe1eb, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ed, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8ce9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ec, 0x92f4,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ef, 0x8a56, 0xe1ea, 0xfffd,
+ 0xfffd, 0x94e8, 0xfffd, 0x894f, 0xfffd, 0x8dea, 0xfffd, 0x9871,
+ 0xfffd, 0xfffd, 0xe1ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe1f0, 0xfffd, 0xfffd, 0xfffd, 0x95c9,
+ 0xfffd, 0x90d7, 0xe1f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1f3,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1f1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8a6d, 0xfffd, 0xe1f9, 0xfffd, 0xe1f8, 0xfffd,
+ 0xfffd, 0x8ea5, 0xfffd, 0xfffd, 0xfffd, 0xe1fa, 0xe1f5, 0xfffd,
+ 0xfffd, 0xfffd, 0xe1fb, 0xe1f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x94d6, 0xe1f4, 0xfffd, 0xfffd, 0xe1f7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe241, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe240,
+ 0x9681, 0xfffd, 0xfffd, 0xfffd, 0xe1fc, 0xfffd, 0xfffd, 0x88e9,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe243, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe242, 0xfffd, 0xfffd,
+ 0xfffd, 0x8fca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe244,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9162, 0xfffd,
+ 0xfffd, 0xe246, 0xe245, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe247, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e6, 0xfffd,
+ 0xfffd, 0xfffd, 0xe1e8, 0xe249, 0xe248, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ea6, 0xfffd, 0x97e7, 0xfffd, 0x8ed0, 0xfffd,
+ 0xe24a, 0x8c56, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b5f,
+ 0x8b46, 0x8e83, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9753, 0xfffd, 0xfffd, 0xe250, 0xfffd, 0xe24f, 0x9163, 0xe24c,
+ 0xfffd, 0xfffd, 0xe24e, 0xfffd, 0xfffd, 0x8f6a, 0x905f, 0xe24d,
+ 0xe24b, 0xfffd, 0x9449, 0xfffd, 0xfffd, 0x8fcb, 0xfffd, 0xfffd,
+ 0x955b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dd5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9398,
+ 0xfffd, 0xfffd, 0xe251, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe252,
+ 0xe268, 0x8bd6, 0xfffd, 0xfffd, 0x985c, 0x9154, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe253, 0xfffd, 0xfffd, 0x89d0, 0x92f5, 0x959f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe254, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b9a, 0xe255,
+ 0xfffd, 0xfffd, 0xe257, 0xfffd, 0xfffd, 0xfffd, 0xe258, 0xfffd,
+ 0x9448, 0xfffd, 0xfffd, 0xe259, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe25a, 0xe25b, 0xfffd, 0xfffd, 0x8bd7, 0x89d1, 0x93c3,
+ 0x8f47, 0x8e84, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe25c, 0xfffd, 0x8f48, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x89c8, 0x9562, 0xfffd, 0xfffd, 0xe25d, 0xfffd, 0xfffd,
+ 0x94e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9164,
+ 0xfffd, 0xe260, 0xfffd, 0xe261, 0x9489, 0xfffd, 0x9060, 0xe25e,
+ 0xfffd, 0x9281, 0xfffd, 0xfffd, 0xe25f, 0xfffd, 0xfffd, 0xfffd,
+ 0x8fcc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x88da, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b48, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe262, 0xfffd, 0xfffd, 0x92f6, 0xfffd, 0xe263, 0x90c5, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ab, 0xfffd, 0xfffd, 0x9542,
+ 0xe264, 0xe265, 0x9274, 0xfffd, 0x97c5, 0xfffd, 0xfffd, 0xe267,
+ 0xe266, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eed, 0xfffd,
+ 0xfffd, 0xe269, 0x88ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe26c,
+ 0xfffd, 0xfffd, 0xfffd, 0xe26a, 0x89d2, 0x8c6d, 0xe26b, 0x8d65,
+ 0x8d92, 0xfffd, 0x95e4, 0xe26d, 0xfffd, 0xfffd, 0x9673, 0xfffd,
+ 0xfffd, 0xe26f, 0xfffd, 0xfffd, 0xfffd, 0x90cf, 0x896e, 0x89b8,
+ 0x88aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe26e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe270, 0xe271, 0x8ff5, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe272, 0xfffd, 0x8a6e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe274, 0xfffd, 0xfffd, 0xfffd, 0x8c8a, 0xfffd, 0x8b86, 0xfffd,
+ 0xfffd, 0xe275, 0x8bf3, 0xfffd, 0xfffd, 0xe276, 0xfffd, 0x90fa,
+ 0xfffd, 0x93cb, 0xfffd, 0x90de, 0x8df3, 0xfffd, 0xfffd, 0xfffd,
+ 0xe277, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9282, 0x918b, 0xfffd, 0xe279, 0xe27b, 0xe278,
+ 0xe27a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c41,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe27c, 0x8c45, 0xfffd, 0xfffd, 0xfffd, 0x8b87, 0x9771,
+ 0xe27e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe280, 0xfffd,
+ 0xfffd, 0xfffd, 0x894d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe283,
+ 0xfffd, 0xfffd, 0xfffd, 0x8a96, 0xe282, 0xe281, 0xfffd, 0xe285,
+ 0xe27d, 0xfffd, 0xe286, 0x97a7, 0xfffd, 0xe287, 0xfffd, 0xe288,
+ 0xfffd, 0xfffd, 0x9af2, 0xe28a, 0xfffd, 0xe289, 0xfffd, 0xfffd,
+ 0xfffd, 0xe28b, 0xe28c, 0xfffd, 0x97b3, 0xe28d, 0xfffd, 0xe8ed,
+ 0x8fcd, 0xe28e, 0xe28f, 0x8f76, 0xfffd, 0x93b6, 0xe290, 0xfffd,
+ 0xfffd, 0xfffd, 0x9247, 0xfffd, 0xfffd, 0xe291, 0xfffd, 0x925b,
+ 0xe292, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ba3, 0xfffd,
+ 0x995e, 0x927c, 0x8eb1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ac6,
+ 0xfffd, 0xfffd, 0xe293, 0xfffd, 0xe2a0, 0xfffd, 0xe296, 0xfffd,
+ 0x8b88, 0xfffd, 0xe295, 0xe2a2, 0xfffd, 0xfffd, 0xfffd, 0xe294,
+ 0xfffd, 0x8fce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe298, 0xe299, 0xfffd, 0x934a, 0xfffd, 0xfffd, 0xe29a, 0xfffd,
+ 0x8a7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9079, 0x9584, 0xfffd,
+ 0xe29c, 0xfffd, 0xfffd, 0xfffd, 0x91e6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe297, 0xfffd, 0xe29b, 0xe29d, 0xfffd,
+ 0xfffd, 0x8df9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2a4, 0x954d, 0xfffd,
+ 0x94a4, 0x9399, 0xfffd, 0x8bd8, 0xe2a3, 0xe2a1, 0xfffd, 0x94b3,
+ 0xe29e, 0x927d, 0x939b, 0xfffd, 0x939a, 0xfffd, 0x8df4, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2b6, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2a6, 0xfffd, 0xe2a8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2ab, 0xfffd, 0xe2ac, 0xfffd,
+ 0xe2a9, 0xe2aa, 0xfffd, 0xfffd, 0xe2a7, 0xe2a5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe29f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95cd, 0x89d3,
+ 0xfffd, 0xfffd, 0xfffd, 0xe2b3, 0xfffd, 0xe2b0, 0xfffd, 0xe2b5,
+ 0xfffd, 0xfffd, 0xe2b4, 0xfffd, 0x9493, 0x96a5, 0xfffd, 0x8e5a,
+ 0xe2ae, 0xe2b7, 0xe2b2, 0xfffd, 0xe2b1, 0xe2ad, 0xfffd, 0xe2af,
+ 0xfffd, 0x8ac7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x925c, 0xfffd, 0xfffd, 0x90fb, 0xfffd, 0xfffd,
+ 0xfffd, 0x94a0, 0xfffd, 0xfffd, 0xe2bc, 0xfffd, 0xfffd, 0xfffd,
+ 0x94a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x90df, 0xe2b9, 0xfffd, 0xfffd, 0x94cd, 0xfffd, 0xe2bd, 0x95d1,
+ 0xfffd, 0x927a, 0xfffd, 0xe2b8, 0xe2ba, 0xfffd, 0xfffd, 0xe2bb,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2be, 0xfffd, 0xfffd,
+ 0x8ec2, 0xfffd, 0xfffd, 0xfffd, 0x93c4, 0xe2c3, 0xe2c2, 0xfffd,
+ 0xfffd, 0xe2bf, 0xfffd, 0xfffd, 0xfffd, 0x9855, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe2c8, 0xfffd, 0xfffd, 0xe2cc, 0xe2c9,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe2c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2c6,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2cb, 0xfffd, 0xfffd,
+ 0xfffd, 0xe2c0, 0x99d3, 0xe2c7, 0xe2c1, 0xfffd, 0xfffd, 0xe2ca,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d0,
+ 0xfffd, 0x8ac8, 0xfffd, 0xe2cd, 0xfffd, 0xfffd, 0xfffd, 0xe2ce,
+ 0xfffd, 0xfffd, 0xe2cf, 0xe2d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d1,
+ 0x94f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d3, 0x97fa, 0x95eb,
+ 0xe2d8, 0xfffd, 0xfffd, 0xe2d5, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d4, 0x90d0, 0xfffd, 0xe2d7,
+ 0xe2d9, 0xfffd, 0xfffd, 0xfffd, 0xe2d6, 0xfffd, 0xe2dd, 0xfffd,
+ 0xe2da, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2db,
+ 0xe2c4, 0xfffd, 0xfffd, 0xfffd, 0xe2dc, 0xe2de, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2df, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x95c4, 0xfffd, 0xe2e0, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96e0, 0xfffd,
+ 0xfffd, 0x8bcc, 0x8c48, 0xe2e1, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x95b2, 0xfffd, 0x9088, 0xfffd, 0x96ae, 0xfffd, 0xfffd,
+ 0xe2e2, 0xfffd, 0x97b1, 0xfffd, 0xfffd, 0x9494, 0xfffd, 0x9165,
+ 0x9453, 0xfffd, 0xfffd, 0x8f6c, 0xfffd, 0xfffd, 0xfffd, 0x88be,
+ 0xfffd, 0xe2e7, 0xe2e5, 0xfffd, 0xe2e3, 0x8a9f, 0xfffd, 0x8fcf,
+ 0xe2e8, 0xfffd, 0xfffd, 0xe2e6, 0xfffd, 0xe2e4, 0xe2ec, 0xfffd,
+ 0xfffd, 0xe2eb, 0xe2ea, 0xe2e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe2ed, 0xfffd, 0xfffd, 0xfffd, 0xe2ee, 0x90b8, 0xfffd,
+ 0xe2ef, 0xfffd, 0xe2f1, 0xfffd, 0xfffd, 0xe2f0, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8cd0, 0xfffd, 0xfffd, 0xfffd, 0x9157, 0xfffd,
+ 0xfffd, 0xfffd, 0xe2f3, 0xfffd, 0xfffd, 0xfffd, 0x939c, 0xfffd,
+ 0xe2f2, 0xfffd, 0xfffd, 0xfffd, 0xe2f4, 0xfffd, 0x95b3, 0x918c,
+ 0x8d66, 0xfffd, 0xe2f5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97c6,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2f7,
+ 0xfffd, 0xfffd, 0xe2f8, 0xfffd, 0xe2f9, 0xfffd, 0xe2fa, 0xfffd,
+ 0x8e85, 0xfffd, 0xe2fb, 0x8c6e, 0xfffd, 0xfffd, 0x8b8a, 0xfffd,
+ 0x8b49, 0xfffd, 0xe340, 0xfffd, 0x96f1, 0x8d67, 0xe2fc, 0xfffd,
+ 0xfffd, 0xfffd, 0xe343, 0x96e4, 0xfffd, 0x945b, 0xfffd, 0xfffd,
+ 0x9552, 0xfffd, 0xfffd, 0xfffd, 0x8f83, 0xe342, 0xfffd, 0x8ed1,
+ 0x8d68, 0x8e86, 0x8b89, 0x95b4, 0xe341, 0xfffd, 0xfffd, 0xfffd,
+ 0x9166, 0x9661, 0x8df5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e87, 0x92db, 0xfffd, 0xe346, 0x97dd,
+ 0x8dd7, 0xfffd, 0xe347, 0x9061, 0xfffd, 0xe349, 0xfffd, 0xfffd,
+ 0xfffd, 0x8fd0, 0x8dae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe348,
+ 0xfffd, 0xfffd, 0x8f49, 0x8cbc, 0x9167, 0xe344, 0xe34a, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe345, 0x8c6f, 0xfffd, 0xe34d, 0xe351,
+ 0x8c8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe34c, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe355, 0xfffd, 0xfffd, 0x8d69, 0xfffd,
+ 0xfffd, 0x978d, 0x88ba, 0xe352, 0xfffd, 0xfffd, 0x8b8b, 0xfffd,
+ 0xe34f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe350, 0xfffd,
+ 0xfffd, 0x939d, 0xe34e, 0xe34b, 0xfffd, 0x8a47, 0x90e2, 0xfffd,
+ 0xfffd, 0x8ca6, 0xfffd, 0xfffd, 0xfffd, 0xe357, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe354, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe356,
+ 0xfffd, 0xfffd, 0xfffd, 0xe353, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8c70, 0x91b1, 0xe358, 0x918e, 0xfffd, 0xfffd, 0xe365,
+ 0xfffd, 0xfffd, 0xe361, 0xe35b, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe35f, 0x8ef8, 0x88db, 0xe35a, 0xe362,
+ 0xe366, 0x8d6a, 0x96d4, 0xfffd, 0x92d4, 0xe35c, 0xfffd, 0xfffd,
+ 0xe364, 0xfffd, 0xe359, 0x925d, 0xfffd, 0xe35e, 0x88bb, 0x96c8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe35d,
+ 0xfffd, 0xfffd, 0x8bd9, 0x94ea, 0xfffd, 0xfffd, 0xfffd, 0x918d,
+ 0xfffd, 0x97ce, 0x8f8f, 0xfffd, 0xfffd, 0xe38e, 0xfffd, 0xfffd,
+ 0xe367, 0xfffd, 0x90fc, 0xfffd, 0xe363, 0xe368, 0xe36a, 0xfffd,
+ 0x92f7, 0xe36d, 0xfffd, 0xfffd, 0xe369, 0xfffd, 0xfffd, 0xfffd,
+ 0x95d2, 0x8ac9, 0xfffd, 0xfffd, 0x96c9, 0xfffd, 0xfffd, 0x88dc,
+ 0xfffd, 0xfffd, 0xe36c, 0xfffd, 0x97fb, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe36b, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x898f, 0xfffd, 0xfffd, 0x93ea, 0xe36e, 0xfffd, 0xfffd,
+ 0xfffd, 0xe375, 0xe36f, 0xe376, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe372, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x949b, 0xfffd, 0xfffd, 0x8ec8, 0xe374,
+ 0xfffd, 0xe371, 0xe377, 0xe370, 0xfffd, 0xfffd, 0x8f63, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9644, 0xfffd, 0xfffd, 0x8f6b, 0xfffd,
+ 0xfffd, 0xe373, 0xe380, 0xfffd, 0xfffd, 0xe37b, 0xfffd, 0xe37e,
+ 0xfffd, 0xe37c, 0xe381, 0xe37a, 0xfffd, 0xe360, 0x90d1, 0xfffd,
+ 0xfffd, 0x94c9, 0xfffd, 0xe37d, 0xfffd, 0xfffd, 0xe378, 0xfffd,
+ 0xfffd, 0xfffd, 0x9140, 0x8c71, 0xfffd, 0x8f4a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9044, 0x9155, 0xe384, 0xfffd,
+ 0xfffd, 0xe386, 0xe387, 0xfffd, 0xfffd, 0xe383, 0xe385, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe379, 0xe382,
+ 0xfffd, 0xe38a, 0xe389, 0xfffd, 0xfffd, 0x969a, 0xfffd, 0xfffd,
+ 0x8c4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe388, 0xfffd, 0xe38c, 0xe38b, 0xe38f, 0xfffd, 0xe391,
+ 0xfffd, 0xfffd, 0x8e5b, 0xe38d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe392, 0xe393, 0xfffd, 0xfffd, 0xe394, 0xfffd, 0xe39a, 0x935a,
+ 0xe396, 0xfffd, 0xe395, 0xe397, 0xe398, 0xfffd, 0xe399, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe39b, 0xe39c, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aca, 0xfffd,
+ 0xe39d, 0xfffd, 0xe39e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe39f, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3a0, 0xe3a1, 0xe3a2, 0xfffd,
+ 0xe3a3, 0xe3a4, 0xfffd, 0xfffd, 0xe3a6, 0xe3a5, 0xfffd, 0xfffd,
+ 0xe3a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3a8,
+ 0xe3a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3ac,
+ 0xe3aa, 0xe3ab, 0x8ddf, 0x8c72, 0xfffd, 0xfffd, 0x9275, 0xfffd,
+ 0x94b1, 0xfffd, 0x8f90, 0xfffd, 0xfffd, 0x946c, 0xfffd, 0x94eb,
+ 0xe3ad, 0x9ceb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe3ae, 0xe3b0, 0xfffd, 0x9785, 0xe3af, 0xe3b2,
+ 0xe3b1, 0xfffd, 0x9772, 0xfffd, 0xe3b3, 0xfffd, 0x94fc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3b4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe3b7, 0xfffd, 0xfffd, 0xe3b6, 0xe3b5, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe3b8, 0x8c51, 0xfffd, 0xfffd, 0xfffd,
+ 0x9141, 0x8b60, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3bc, 0xe3b9,
+ 0xfffd, 0xfffd, 0xe3ba, 0xfffd, 0xfffd, 0xfffd, 0xe3bd, 0xfffd,
+ 0xe3be, 0xe3bb, 0xfffd, 0xfffd, 0xfffd, 0x8948, 0xfffd, 0xfffd,
+ 0xfffd, 0x89a5, 0xfffd, 0xfffd, 0xfffd, 0xe3c0, 0xe3c1, 0xfffd,
+ 0xfffd, 0xfffd, 0xe3c2, 0xfffd, 0x9782, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8f4b, 0xfffd, 0xe3c4, 0xe3c3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9089, 0xe3c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3c6, 0xfffd,
+ 0xfffd, 0xe3c7, 0xfffd, 0x8ae3, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8acb, 0xfffd, 0xfffd, 0xe3c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe3c9, 0xfffd, 0x967c, 0x9783, 0xfffd, 0xfffd, 0xfffd,
+ 0x9773, 0x9856, 0xfffd, 0x8d6c, 0xe3cc, 0x8ed2, 0xe3cb, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe3cd, 0x8ea7, 0xfffd, 0xfffd, 0xfffd,
+ 0x91cf, 0xfffd, 0xe3ce, 0xfffd, 0xfffd, 0x8d6b, 0xfffd, 0x96d5,
+ 0xe3cf, 0xe3d0, 0xfffd, 0xfffd, 0xe3d1, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe3d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe3d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8ea8, 0xfffd, 0xfffd, 0x96eb, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe3d5, 0xfffd, 0x925e, 0xfffd, 0xe3d4,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3d7, 0xfffd,
+ 0xfffd, 0xfffd, 0xe3d6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe3d8, 0xfffd, 0xfffd, 0xfffd, 0x90b9, 0xfffd,
+ 0xe3d9, 0xfffd, 0xe3da, 0xfffd, 0xfffd, 0xfffd, 0x95b7, 0xe3db,
+ 0xfffd, 0x918f, 0xe3dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe3dd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97fc,
+ 0xe3e0, 0xfffd, 0xe3df, 0xe3de, 0x92ae, 0xfffd, 0xe3e1, 0x9045,
+ 0xfffd, 0xe3e2, 0xfffd, 0xfffd, 0xfffd, 0xe3e3, 0x9857, 0xe3e4,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3e5, 0xe3e7, 0xe3e6, 0x94a3,
+ 0xfffd, 0x93f7, 0xfffd, 0x985d, 0x94a7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe3e9, 0xfffd, 0xfffd, 0x8fd1, 0xfffd,
+ 0x9549, 0xfffd, 0xe3ea, 0xe3e8, 0xfffd, 0x8acc, 0xfffd, 0xfffd,
+ 0xfffd, 0x8cd2, 0x8e88, 0xfffd, 0xfffd, 0x94ec, 0xfffd, 0xfffd,
+ 0xfffd, 0x8ca8, 0x9662, 0xfffd, 0xe3ed, 0xe3eb, 0xfffd, 0x8d6d,
+ 0xfffd, 0x8d6e, 0x88e7, 0xfffd, 0x8de6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9478, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x88dd, 0xe3f2, 0xfffd, 0x925f, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9477, 0xfffd, 0x91d9, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3f4, 0xfffd,
+ 0xfffd, 0xe3f0, 0xe3f3, 0xe3ee, 0xfffd, 0xe3f1, 0x9645, 0xfffd,
+ 0xfffd, 0x8cd3, 0xfffd, 0xfffd, 0x88fb, 0xe3ef, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3f6,
+ 0xfffd, 0xe3f7, 0xfffd, 0xfffd, 0x93b7, 0xfffd, 0xfffd, 0xfffd,
+ 0x8bb9, 0xfffd, 0xfffd, 0xfffd, 0xe445, 0x945c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8e89, 0xfffd, 0xfffd, 0x8bba, 0x90c6, 0x9865,
+ 0x96ac, 0xe3f5, 0x90d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8b72, 0xe3f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe3fa, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe3f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3fb,
+ 0xfffd, 0x9245, 0xfffd, 0x945d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x92af, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe442, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe441, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe3fc, 0xfffd, 0xfffd, 0x9074, 0xfffd,
+ 0x9585, 0xe444, 0xfffd, 0xe443, 0x8d6f, 0x9872, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe454,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe448, 0xe449, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8eee, 0xfffd, 0xfffd, 0xe447, 0xfffd,
+ 0x8d98, 0xe446, 0xfffd, 0xfffd, 0xe44a, 0xfffd, 0xfffd, 0xfffd,
+ 0x92b0, 0x95a0, 0x9142, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91da,
+ 0xe44e, 0xfffd, 0xe44f, 0xe44b, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe44c, 0xfffd, 0xe44d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d70,
+ 0xfffd, 0xfffd, 0xfffd, 0xe455, 0xfffd, 0xe451, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9586, 0xfffd, 0x968c, 0x9547, 0xfffd, 0xfffd,
+ 0xe450, 0xfffd, 0xfffd, 0xe453, 0xe452, 0xfffd, 0xfffd, 0xfffd,
+ 0x9663, 0xe456, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe457, 0xfffd, 0xfffd, 0x9156, 0xfffd, 0xe458, 0xfffd, 0xfffd,
+ 0xe45a, 0xfffd, 0xe45e, 0xfffd, 0xfffd, 0xe45b, 0xe459, 0x945e,
+ 0xe45c, 0xfffd, 0xe45d, 0xfffd, 0xfffd, 0xfffd, 0x89b0, 0xfffd,
+ 0xe464, 0xe45f, 0xfffd, 0xfffd, 0xfffd, 0xe460, 0xfffd, 0xfffd,
+ 0xfffd, 0xe461, 0xfffd, 0x919f, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe463, 0xe462, 0xe465, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe466,
+ 0xe467, 0xfffd, 0xfffd, 0x9062, 0xfffd, 0x89e7, 0xfffd, 0xe468,
+ 0x97d5, 0xfffd, 0x8ea9, 0xfffd, 0xfffd, 0x8f4c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8e8a, 0x9276, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe469, 0xe46a, 0x8950, 0xfffd, 0xe46b, 0xfffd,
+ 0xfffd, 0xe46c, 0xe46d, 0xfffd, 0xfffd, 0xe46e, 0xfffd, 0xe46f,
+ 0x8bbb, 0x9da8, 0xe470, 0xfffd, 0x90e3, 0xe471, 0x8ec9, 0xfffd,
+ 0xe472, 0xfffd, 0x98ae, 0xfffd, 0xfffd, 0xfffd, 0xe473, 0x95dc,
+ 0x8ada, 0xfffd, 0xfffd, 0x9143, 0x8f77, 0xfffd, 0x9591, 0x8f4d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe474, 0x8d71, 0xe475, 0x94ca, 0xfffd, 0xe484, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe477, 0xfffd, 0x91c7, 0x9495, 0x8cbd,
+ 0xe476, 0x9144, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe478, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92f8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe47a, 0xe479, 0xe47c, 0xfffd, 0xfffd, 0xe47b, 0xfffd, 0xe47d,
+ 0xfffd, 0xfffd, 0xe480, 0xfffd, 0xe47e, 0xfffd, 0x8acd, 0xfffd,
+ 0xe481, 0xfffd, 0xe482, 0xe483, 0xfffd, 0xfffd, 0x8daf, 0x97c7,
+ 0xfffd, 0xe485, 0x9046, 0xfffd, 0xfffd, 0xfffd, 0x8990, 0xe486,
+ 0xe487, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe488, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x88f0, 0xfffd, 0xe489, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe48a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9587, 0xfffd, 0xfffd, 0xfffd, 0x8ec5, 0xfffd, 0xe48c,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a48, 0x88b0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe48b, 0xe48e, 0x946d, 0xfffd, 0x9063,
+ 0xfffd, 0x89d4, 0xfffd, 0x9646, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c7c, 0x8bda, 0xfffd, 0xe48d, 0xfffd, 0x89e8, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aa1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8991, 0xe492, 0x97e8, 0x91db, 0xfffd, 0xfffd, 0x9563,
+ 0xfffd, 0xe49e, 0xfffd, 0x89d5, 0xe49c, 0xfffd, 0xe49a, 0xe491,
+ 0xfffd, 0xe48f, 0xfffd, 0xe490, 0xfffd, 0x8ee1, 0x8bea, 0x9297,
+ 0xfffd, 0xfffd, 0xfffd, 0x93cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8970, 0xfffd, 0xe494, 0xe493, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe499, 0xe495, 0xe498, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x96ce, 0xe497, 0x89d6, 0x8a9d, 0xe49b, 0xfffd,
+ 0xfffd, 0xe49d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c73, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4a1, 0xe4aa,
+ 0xe4ab, 0xfffd, 0xfffd, 0xfffd, 0x88a9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x88ef, 0xfffd, 0xfffd, 0xe4a9, 0xfffd, 0xfffd, 0xfffd, 0xe4a8,
+ 0xfffd, 0xe4a3, 0xe4a2, 0xfffd, 0xe4a0, 0xe49f, 0x9283, 0xfffd,
+ 0x91f9, 0xe4a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe4a4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4a7, 0xfffd, 0xfffd,
+ 0xfffd, 0x9190, 0x8c74, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8960,
+ 0xe4a6, 0xfffd, 0x8d72, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9191, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4b8, 0xfffd, 0xe4b9, 0xfffd, 0x89d7,
+ 0xfffd, 0xfffd, 0xfffd, 0x89ac, 0xe4b6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4ac, 0xfffd, 0xe4b4,
+ 0xfffd, 0xe4bb, 0xe4b5, 0xfffd, 0xfffd, 0xfffd, 0xe4b3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe496, 0xfffd, 0xfffd, 0xe4b1, 0xfffd,
+ 0xfffd, 0xfffd, 0xe4ad, 0xfffd, 0xfffd, 0xfffd, 0x8ace, 0xe4af,
+ 0xe4ba, 0xfffd, 0xe4b0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe4bc, 0xfffd, 0xe4ae, 0x949c, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9789, 0xfffd, 0xfffd, 0xfffd, 0xe4b7, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4cd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe4c5, 0xfffd, 0xfffd, 0xfffd, 0x909b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8b65, 0xfffd, 0x8bdb, 0xfffd, 0xe4c0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x89d9, 0xfffd, 0xfffd, 0x8fd2, 0xfffd,
+ 0xe4c3, 0xfffd, 0xfffd, 0xfffd, 0x8dd8, 0xfffd, 0xfffd, 0x9370,
+ 0xe4c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x95ec, 0xfffd, 0xe4bf, 0xfffd, 0xfffd, 0xfffd, 0x89d8,
+ 0x8cd4, 0x9548, 0xe4c9, 0xfffd, 0xe4bd, 0xfffd, 0xfffd, 0xe4c6,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4d0, 0xfffd, 0xe4c1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4c2, 0x93b8, 0xfffd, 0xfffd, 0xe4c7,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4c4, 0x9647, 0xe4ca, 0x88de, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4be, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe4cc, 0xfffd, 0xe4cb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x948b, 0xe4d2, 0xfffd, 0xe4dd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8a9e, 0xfffd, 0xfffd, 0xfffd, 0xe4e0, 0xfffd, 0xfffd,
+ 0xe4ce, 0xfffd, 0xfffd, 0xfffd, 0xe4d3, 0x978e, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4dc, 0xfffd,
+ 0xfffd, 0x9774, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97a8, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9298,
+ 0xfffd, 0xfffd, 0xfffd, 0x8a8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x9592, 0xe4e2, 0x939f, 0xfffd, 0xfffd, 0x88af, 0xfffd,
+ 0xfffd, 0xe4db, 0xfffd, 0xe4d7, 0x9192, 0xe4d1, 0xe4d9, 0xe4de,
+ 0xfffd, 0x944b, 0xfffd, 0xfffd, 0xfffd, 0x88a8, 0xfffd, 0xe4d6,
+ 0xfffd, 0xe4df, 0x9598, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe4da, 0xfffd, 0xe4d5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8fd3, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8f4e, 0xfffd, 0xfffd, 0xfffd, 0x8eaa, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x96d6, 0xfffd, 0xfffd, 0x9566, 0xfffd, 0xfffd, 0xe4e5,
+ 0xfffd, 0xe4ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4d8, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8a97, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ff6, 0xe4e3, 0xfffd, 0xe4e8, 0x9193, 0xfffd, 0xfffd, 0xe4e4,
+ 0xfffd, 0xe4eb, 0xfffd, 0xfffd, 0x927e, 0xfffd, 0xe4ec, 0xfffd,
+ 0xfffd, 0x9775, 0xe4e1, 0x8a57, 0xfffd, 0xe4e7, 0xfffd, 0xfffd,
+ 0xe4ea, 0x96aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4ed, 0xfffd,
+ 0xfffd, 0xe4e6, 0xe4e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9648, 0xfffd, 0x9840, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f1, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f8, 0xfffd, 0xfffd, 0xe4f0,
+ 0x8ec1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4cf, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x95cc, 0xfffd, 0x96a0, 0xe4f7, 0xe4f6, 0xfffd, 0xe4f2,
+ 0xe4f3, 0xfffd, 0x8955, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f5,
+ 0xfffd, 0xe4ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92d3, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f4, 0x88fc, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91a0, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95c1, 0xfffd, 0xfffd,
+ 0xe4f9, 0xe540, 0xfffd, 0x94d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe4fc, 0x8fd4, 0x8ec7, 0xe542, 0xfffd, 0xfffd, 0x8bbc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe543, 0xfffd, 0x9599,
+ 0xe4fb, 0xfffd, 0xe4d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe4fa, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x986e, 0x93a0, 0x9593, 0xfffd, 0xfffd, 0xe54a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe550,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe551, 0xfffd,
+ 0xe544, 0xfffd, 0xfffd, 0xfffd, 0x9496, 0xfffd, 0xfffd, 0xe54e,
+ 0xe546, 0xfffd, 0xe548, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe552, 0xe547, 0xfffd, 0xfffd, 0xe54b, 0xfffd, 0xfffd, 0x8992,
+ 0xfffd, 0x93e3, 0xfffd, 0xe54c, 0xe54f, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe545, 0xfffd, 0x9145, 0xfffd,
+ 0xe549, 0x8e46, 0x9064, 0x8c4f, 0x96f2, 0xfffd, 0x96f7, 0x8f92,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe556, 0xe554, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x986d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe553, 0xfffd, 0xfffd, 0xfffd, 0x9795, 0xfffd, 0xe555,
+ 0xe557, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe558, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe55b, 0xe559, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93a1, 0xe55a, 0xfffd, 0xfffd,
+ 0xfffd, 0x94cb, 0xe54d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f93,
+ 0xfffd, 0xe55c, 0xe561, 0x9194, 0xfffd, 0xfffd, 0xe560, 0xfffd,
+ 0xfffd, 0xfffd, 0xe541, 0xfffd, 0xfffd, 0xfffd, 0xe562, 0x9168,
+ 0xfffd, 0xfffd, 0xe55d, 0xe55f, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe55e, 0xfffd, 0xfffd, 0x9f50, 0x9f41,
+ 0xfffd, 0xfffd, 0xe564, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe563, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9796, 0xfffd, 0xe1ba,
+ 0xe565, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe566,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe567, 0x8cd5, 0xfffd,
+ 0x8b73, 0xfffd, 0xfffd, 0xfffd, 0xe569, 0x997c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8b95, 0xfffd, 0x97b8, 0xfffd, 0x8bf1, 0xe56a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe56b,
+ 0xfffd, 0xfffd, 0xfffd, 0x928e, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe56c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x93f8, 0xfffd, 0x88b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x89e1, 0xe571, 0xe572, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe56d, 0xfffd, 0x8e5c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe56e, 0x9461, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe56f, 0xe570, 0xe57a, 0xfffd, 0xfffd, 0xfffd, 0xe574,
+ 0xe577, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe573, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe575, 0xfffd, 0xe576, 0x8ed6,
+ 0xfffd, 0xe578, 0xfffd, 0x9260, 0xfffd, 0x8c75, 0x8a61, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe57b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8a5e, 0xfffd, 0xe581, 0xfffd, 0xfffd, 0xe57c, 0xe580,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94b8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe57d, 0xfffd, 0xfffd, 0xe57e, 0x9567, 0x94d8, 0xe582,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x91fb, 0xe58c, 0xfffd, 0xe588, 0xfffd, 0xfffd, 0x89e9, 0xfffd,
+ 0xe586, 0xfffd, 0x9649, 0xe587, 0xfffd, 0xfffd, 0xe584, 0xfffd,
+ 0xe585, 0xe58a, 0xe58d, 0xfffd, 0xfffd, 0xe58b, 0xfffd, 0xfffd,
+ 0xfffd, 0xe589, 0xe583, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9277, 0xfffd, 0xe594, 0xfffd, 0x96a8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe592, 0xfffd, 0xfffd,
+ 0xfffd, 0xe593, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe58e, 0xfffd, 0xfffd, 0xe590,
+ 0xfffd, 0xfffd, 0xfffd, 0xe591, 0xfffd, 0xfffd, 0xfffd, 0xe58f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x90e4, 0xfffd, 0x9858, 0xe598, 0xfffd, 0xe599, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe59f, 0xfffd, 0x9049, 0xfffd, 0xe59b,
+ 0xfffd, 0xe59e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe596,
+ 0xe595, 0xfffd, 0xfffd, 0xe5a0, 0xfffd, 0xfffd, 0x89da, 0xfffd,
+ 0xe59c, 0xfffd, 0xe5a1, 0xfffd, 0xfffd, 0xfffd, 0xe59d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe59a, 0xfffd, 0x92b1, 0xfffd,
+ 0xe597, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9488,
+ 0xfffd, 0xfffd, 0xe5a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x975a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5a4,
+ 0xfffd, 0xfffd, 0xe5a3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe5ac, 0xfffd, 0xfffd, 0xfffd, 0xe5a6,
+ 0xfffd, 0xfffd, 0xfffd, 0xe5ae, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9786, 0xe5b1, 0xfffd, 0xe5a8, 0xfffd, 0xfffd,
+ 0xe5a9, 0xfffd, 0xfffd, 0xfffd, 0xe5ad, 0xfffd, 0xe5b0, 0xe5af,
+ 0xfffd, 0xfffd, 0xfffd, 0xe5a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe5aa, 0xfffd, 0xe5bb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe5b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5b2,
+ 0xfffd, 0xfffd, 0xe5b3, 0xfffd, 0xfffd, 0xfffd, 0xe5b8, 0xe5b9,
+ 0xfffd, 0x8a49, 0xfffd, 0x8b61, 0xfffd, 0xfffd, 0xe5b7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5a2, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5b6, 0xe5ba, 0xe5b5,
+ 0xfffd, 0xe5bc, 0xfffd, 0xfffd, 0xfffd, 0xe5be, 0xe5bd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe5c0, 0xe5bf, 0xe579, 0xfffd, 0xfffd, 0xfffd, 0xe5c4,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe5c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5c2, 0xfffd,
+ 0xfffd, 0xe5c3, 0xfffd, 0xe5c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c8c, 0xfffd, 0xe5c7, 0xfffd, 0xe5c6, 0xfffd, 0x8f4f, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d73, 0x9fa5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe5c8, 0x8f70, 0xfffd, 0xfffd, 0xfffd, 0x8a58,
+ 0xfffd, 0xe5c9, 0xfffd, 0x8971, 0xfffd, 0x8fd5, 0xe5ca, 0xfffd,
+ 0xfffd, 0x8d74, 0xe5cb, 0x88df, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x955c, 0xfffd, 0xfffd, 0xe5cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x908a, 0xfffd, 0xe5d3, 0xfffd, 0xfffd, 0xe5d0, 0xfffd, 0x928f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5d1, 0xe5ce, 0x8bdc,
+ 0xfffd, 0xe5cd, 0xe5d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c55, 0xfffd, 0xfffd, 0x91dc, 0xfffd, 0xe5da, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe5d6, 0xfffd, 0xfffd, 0xfffd, 0x91b3, 0xe5d5,
+ 0xfffd, 0xe5d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5cf, 0xfffd,
+ 0xfffd, 0xfffd, 0xe5d9, 0xfffd, 0xe5db, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x94ed, 0xfffd, 0xfffd, 0xe5d7, 0xfffd,
+ 0xe5dc, 0xe5de, 0xfffd, 0xfffd, 0x8cd1, 0xe5d2, 0xfffd, 0x88bf,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5dd,
+ 0xfffd, 0x8dd9, 0x97f4, 0xe5df, 0xe5e0, 0x9195, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97a0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5e1, 0x9754, 0xfffd, 0xfffd,
+ 0xe5e2, 0xe5e3, 0xfffd, 0xfffd, 0x95e2, 0xe5e4, 0xfffd, 0x8dbe,
+ 0xfffd, 0x97a1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe5e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe5ea, 0x8fd6, 0xe5e8, 0xfffd, 0xfffd, 0xfffd,
+ 0x9787, 0xe5e5, 0xfffd, 0xfffd, 0xe5e7, 0x90bb, 0x909e, 0xfffd,
+ 0xfffd, 0xfffd, 0xe5e6, 0xfffd, 0xe5eb, 0xfffd, 0xfffd, 0x95a1,
+ 0xfffd, 0xfffd, 0xe5ed, 0xfffd, 0xe5ec, 0xfffd, 0xfffd, 0xfffd,
+ 0x8a8c, 0xfffd, 0x964a, 0xe5ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5fa, 0xe5f0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe5f2, 0xe5f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f7, 0xfffd,
+ 0xe5f8, 0xfffd, 0xfffd, 0xe5f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe5f4, 0xfffd, 0xe5ef, 0xe5f5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f9, 0xe8b5, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a6, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5fc, 0x8bdd,
+ 0xe5fb, 0xfffd, 0xfffd, 0xfffd, 0xe641, 0xfffd, 0xe640, 0xfffd,
+ 0xfffd, 0xfffd, 0xe643, 0xfffd, 0xfffd, 0xe642, 0xfffd, 0xe644,
+ 0xfffd, 0xfffd, 0x8f50, 0xfffd, 0xe645, 0xfffd, 0xfffd, 0xe646,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe647, 0x90bc,
+ 0xfffd, 0x9776, 0xfffd, 0xe648, 0xfffd, 0xfffd, 0x95a2, 0x9465,
+ 0xe649, 0xfffd, 0xe64a, 0x8ca9, 0xfffd, 0xfffd, 0xfffd, 0x8b4b,
+ 0xfffd, 0xfffd, 0xfffd, 0xe64b, 0xfffd, 0xfffd, 0x8e8b, 0x9460,
+ 0xe64c, 0xfffd, 0x8a6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe64d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe64f, 0x9797,
+ 0xfffd, 0xe64e, 0x9065, 0xfffd, 0xe650, 0xfffd, 0xfffd, 0xe651,
+ 0xfffd, 0xfffd, 0xe652, 0x8acf, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe653, 0xfffd, 0xfffd, 0xe654, 0xfffd, 0xe655,
+ 0xe656, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8a70, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe657, 0xfffd, 0xe658, 0xe659, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x89f0, 0xfffd, 0xfffd, 0x9047, 0xe65a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe65b, 0xfffd, 0xfffd, 0xfffd,
+ 0xe65c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8cbe, 0xfffd, 0x92f9, 0xe65d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c76, 0xfffd, 0x9075, 0xfffd, 0xe660, 0xfffd, 0x93a2, 0xfffd,
+ 0xe65f, 0xfffd, 0xfffd, 0x8c50, 0xfffd, 0xfffd, 0xe65e, 0x91f5,
+ 0x8b4c, 0xfffd, 0xfffd, 0xe661, 0xfffd, 0xe662, 0xfffd, 0x8fd7,
+ 0xfffd, 0xfffd, 0xfffd, 0x8c8d, 0xfffd, 0xe663, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x964b, 0xfffd, 0xfffd, 0x90dd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8b96, 0xfffd, 0x96f3, 0x9169, 0xfffd, 0xe664, 0xfffd,
+ 0xfffd, 0xfffd, 0x9066, 0x9290, 0x8fd8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe665, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe668, 0xfffd,
+ 0xe669, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8dbc, 0x91c0, 0xe667, 0xfffd, 0x8fd9, 0x955d, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe666, 0xfffd, 0xfffd, 0x8e8c, 0xfffd,
+ 0x8972, 0xfffd, 0xe66d, 0x8c77, 0xfffd, 0xfffd, 0x8e8e, 0xfffd,
+ 0xfffd, 0x8e8d, 0xfffd, 0x986c, 0xe66c, 0xe66b, 0x9146, 0xfffd,
+ 0x8b6c, 0x9862, 0x8a59, 0x8fda, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe66a, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe66f, 0xfffd, 0xe670, 0xe66e, 0xfffd, 0x8cd6,
+ 0xfffd, 0x975f, 0xfffd, 0xfffd, 0x8e8f, 0x9446, 0xfffd, 0xfffd,
+ 0xfffd, 0xe673, 0xfffd, 0x90be, 0xfffd, 0x9261, 0xfffd, 0xfffd,
+ 0x9755, 0xfffd, 0xe676, 0xfffd, 0xfffd, 0xfffd, 0x8cea, 0xfffd,
+ 0x90bd, 0xe672, 0xfffd, 0xe677, 0x8ceb, 0xe674, 0xe675, 0xfffd,
+ 0xe671, 0xfffd, 0xfffd, 0xfffd, 0x90e0, 0x93c7, 0xfffd, 0xfffd,
+ 0x924e, 0xfffd, 0x89db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x94ee, 0xfffd, 0xfffd, 0x8b62, 0xfffd, 0xfffd, 0x92b2,
+ 0xfffd, 0xfffd, 0xe67a, 0xfffd, 0xe678, 0xfffd, 0xfffd, 0x926b,
+ 0xfffd, 0xfffd, 0xfffd, 0x90bf, 0x8ad0, 0xe679, 0xfffd, 0x907a,
+ 0xfffd, 0xfffd, 0x97c8, 0xfffd, 0xfffd, 0xfffd, 0x985f, 0xfffd,
+ 0xfffd, 0xfffd, 0xe67b, 0xe687, 0x92b3, 0xfffd, 0xe686, 0xfffd,
+ 0xe683, 0xe68b, 0xe684, 0xfffd, 0xe680, 0xfffd, 0x92fa, 0xe67e,
+ 0xfffd, 0xfffd, 0xfffd, 0xe67c, 0xfffd, 0x9740, 0x8e90, 0xfffd,
+ 0xfffd, 0xe681, 0xfffd, 0xe67d, 0xfffd, 0xfffd, 0xfffd, 0xe685,
+ 0x8f94, 0xfffd, 0x8cbf, 0xfffd, 0xfffd, 0xfffd, 0x91f8, 0xfffd,
+ 0x9664, 0x8979, 0x88e0, 0xfffd, 0x93a3, 0xfffd, 0xfffd, 0xe689,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe688, 0xfffd, 0x93e4, 0xfffd,
+ 0xe68d, 0xfffd, 0xfffd, 0xfffd, 0xe682, 0xfffd, 0xe68c, 0xe68e,
+ 0xfffd, 0x8caa, 0xe68a, 0x8d75, 0xfffd, 0x8ed3, 0xfffd, 0xfffd,
+ 0xe68f, 0x9777, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe692, 0xfffd,
+ 0xe695, 0xfffd, 0xfffd, 0xe693, 0x9554, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe690, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8bde, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe694, 0xfffd,
+ 0xfffd, 0xe696, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe69a, 0xfffd, 0xfffd, 0xe697, 0xfffd, 0xe699, 0xe698,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe69b, 0xfffd,
+ 0x8eaf, 0xfffd, 0xe69d, 0xe69c, 0x9588, 0xfffd, 0xfffd, 0xe69f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c78, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe69e, 0xe6a0, 0xfffd, 0xfffd, 0xe6a1,
+ 0x8b63, 0xe3bf, 0x8ff7, 0xfffd, 0xe6a2, 0xfffd, 0xfffd, 0x8cec,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6a3, 0xfffd, 0xfffd,
+ 0xe6a4, 0xfffd, 0xfffd, 0x8e5d, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9dcc, 0xfffd, 0xe6a5, 0xfffd, 0xe6a6, 0xfffd,
+ 0x8f51, 0xfffd, 0xe6a7, 0xe6a8, 0xfffd, 0xfffd, 0xe6a9, 0xfffd,
+ 0xfffd, 0xe6aa, 0xe6ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x924a,
+ 0xfffd, 0xfffd, 0xe6ac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6ae,
+ 0xfffd, 0xe6ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93a4, 0xfffd,
+ 0xe6af, 0xfffd, 0x964c, 0xfffd, 0xe6b0, 0xfffd, 0xe6b1, 0xfffd,
+ 0xe6b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6b3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x93d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8fdb, 0xe6b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8d8b, 0x98ac, 0xe6b5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe6b6, 0x955e, 0xe6b7, 0xfffd, 0xe6bf, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6b8, 0xfffd, 0xfffd, 0xe6ba, 0xfffd, 0xfffd,
+ 0xfffd, 0xe6b9, 0xe6bb, 0xfffd, 0x9665, 0xe6bc, 0xe6bd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6be, 0xfffd, 0xfffd, 0xfffd,
+ 0xe6c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a4c, 0x92e5, 0xfffd,
+ 0x9589, 0x8de0, 0x8d76, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x956e,
+ 0x89dd, 0x94cc, 0xe6c3, 0x8ad1, 0x90d3, 0xe6c2, 0xe6c7, 0x9299,
+ 0x96e1, 0xfffd, 0xe6c5, 0xe6c6, 0x8b4d, 0xfffd, 0xe6c8, 0x9483,
+ 0x91dd, 0xfffd, 0xfffd, 0x94ef, 0x935c, 0xe6c4, 0xfffd, 0x9666,
+ 0x89ea, 0xe6ca, 0x9847, 0x92c0, 0x9864, 0xfffd, 0xfffd, 0x8e91,
+ 0xe6c9, 0xfffd, 0x91af, 0xfffd, 0xfffd, 0xe6da, 0x9147, 0xfffd,
+ 0xfffd, 0x93f6, 0xfffd, 0x956f, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6cd, 0x8e5e, 0x8e92, 0xfffd, 0x8fdc, 0xfffd,
+ 0x9485, 0xfffd, 0x8cab, 0xe6cc, 0xe6cb, 0xfffd, 0x958a, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ebf, 0xfffd, 0xfffd, 0x9371, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6cf, 0xe6d0, 0x8d77, 0xe6ce, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6d1, 0xe6d2, 0xfffd, 0xe6d4,
+ 0x91a1, 0xfffd, 0xe6d3, 0x8ae4, 0xfffd, 0xe6d6, 0xfffd, 0xe6d5,
+ 0xe6d7, 0xfffd, 0xfffd, 0xe6d9, 0xe6db, 0xfffd, 0xe6dc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90d4, 0xfffd, 0x8ecd, 0xe6dd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8a71, 0xfffd, 0xe6de, 0xfffd, 0xfffd,
+ 0x9196, 0xe6df, 0xfffd, 0xe6e0, 0x958b, 0xfffd, 0xfffd, 0x8b4e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe6e1, 0xfffd, 0xfffd, 0xfffd, 0x92b4, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x897a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe6e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8eef, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9096, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x91ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6e5, 0xfffd, 0xfffd, 0xfffd, 0xe6e4, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe6eb, 0xe6e9, 0xfffd, 0xfffd, 0xe6e6,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6e8, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6e7, 0xe6ea, 0xfffd, 0x8b97, 0xfffd, 0xe6ee,
+ 0xfffd, 0x90d5, 0xfffd, 0xe6ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8cd7, 0xfffd, 0xe6ec, 0xe6ed, 0xfffd, 0xfffd, 0xfffd, 0x9848,
+ 0xfffd, 0xfffd, 0xfffd, 0x92b5, 0xfffd, 0x9148, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6f0, 0xfffd, 0xfffd, 0xe6f3,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe6f1, 0xe6f2, 0x9778, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93a5,
+ 0xe6f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6f4, 0xe6f5, 0xe6f7,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe748, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe6fa, 0xfffd, 0xfffd, 0xfffd, 0xe6fb, 0xe6f9, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe6f8, 0xfffd, 0x92fb, 0xfffd, 0xfffd, 0xe740,
+ 0xe744, 0xe741, 0xe6fc, 0xfffd, 0xe742, 0xfffd, 0xfffd, 0xfffd,
+ 0xe743, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe74a, 0xfffd, 0xfffd,
+ 0xfffd, 0xe745, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90d6,
+ 0xe747, 0xfffd, 0xfffd, 0xe749, 0xe746, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe74c, 0xfffd, 0x8f52, 0xfffd, 0xe74b, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe74d, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe74e, 0xfffd, 0xfffd, 0xe751, 0xe750, 0xfffd, 0xe74f,
+ 0xfffd, 0xfffd, 0xe753, 0xe752, 0xfffd, 0x96f4, 0xfffd, 0xfffd,
+ 0xfffd, 0xe755, 0xfffd, 0xe754, 0xe756, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe757, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe759, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe758, 0x9067, 0xe75a, 0xfffd, 0xfffd, 0x8beb,
+ 0xe75b, 0xe75d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe75e, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe75f, 0xe75c, 0xfffd,
+ 0xe760, 0xfffd, 0x8ed4, 0xe761, 0x8b4f, 0x8c52, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8cac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe762, 0xfffd, 0xfffd, 0xfffd, 0x93ee,
+ 0xfffd, 0xfffd, 0x935d, 0xe763, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe766, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8eb2, 0xfffd, 0xfffd, 0xe765, 0xe764, 0x8c79, 0xe767, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8a72, 0xfffd, 0xe769, 0xfffd, 0xfffd,
+ 0xfffd, 0x8dda, 0xe768, 0xfffd, 0xe771, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe76b, 0xe76d, 0x95e3, 0xe76a, 0xfffd, 0xfffd,
+ 0xfffd, 0xe76c, 0xfffd, 0xe770, 0xe76e, 0x8b50, 0xfffd, 0xe76f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe772, 0xfffd,
+ 0xfffd, 0x9479, 0x97d6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f53,
+ 0xfffd, 0xfffd, 0xfffd, 0xe773, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9741, 0xe775, 0xfffd, 0xe774, 0xfffd, 0xfffd, 0xe778, 0x9760,
+ 0xfffd, 0xfffd, 0xe777, 0xfffd, 0x8a8d, 0xe776, 0xe77b, 0xfffd,
+ 0xfffd, 0xe77a, 0xfffd, 0xfffd, 0xe779, 0x9351, 0xe77c, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe77d,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe77e, 0xfffd, 0xfffd, 0x8d8c,
+ 0xfffd, 0x8c44, 0xe780, 0xe781, 0xe782, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9068, 0xe783, 0xfffd, 0x8eab, 0xe784,
+ 0xfffd, 0xfffd, 0xfffd, 0xe785, 0xfffd, 0xfffd, 0xfffd, 0x999f,
+ 0x999e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe786, 0xe390, 0xe787,
+ 0x9243, 0x904a, 0x945f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe788,
+ 0xfffd, 0xfffd, 0x95d3, 0x92d2, 0x8d9e, 0xfffd, 0xfffd, 0x9248,
+ 0xfffd, 0xfffd, 0x8949, 0xfffd, 0x9698, 0x9076, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c7d, 0xfffd,
+ 0xfffd, 0x8bdf, 0xfffd, 0xfffd, 0x95d4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe789, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe78b, 0xfffd, 0xfffd, 0xe78a, 0x89de, 0xfffd,
+ 0xfffd, 0x93f4, 0xe78c, 0x9497, 0xfffd, 0x9352, 0xfffd, 0xe78d,
+ 0x8f71, 0xfffd, 0xfffd, 0xfffd, 0xe78f, 0xfffd, 0xfffd, 0x96c0,
+ 0xe79e, 0xe791, 0xe792, 0xfffd, 0xfffd, 0x92c7, 0xfffd, 0xfffd,
+ 0x91de, 0x9197, 0xfffd, 0x93a6, 0xfffd, 0xe790, 0x8b74, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe799, 0xfffd, 0xe796, 0xe7a3, 0x93a7,
+ 0x9280, 0xe793, 0xfffd, 0x92fc, 0x9372, 0xe794, 0xe798, 0x9080,
+ 0xfffd, 0x9487, 0x92ca, 0xfffd, 0xfffd, 0x90c0, 0xe797, 0x91ac,
+ 0x91a2, 0xe795, 0x88a7, 0x9841, 0xfffd, 0xfffd, 0xfffd, 0xe79a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91df, 0xfffd,
+ 0xfffd, 0x8f54, 0x9069, 0xfffd, 0xfffd, 0xe79c, 0xe79b, 0xfffd,
+ 0x88ed, 0xe79d, 0xfffd, 0xfffd, 0x954e, 0xfffd, 0xe7a5, 0xfffd,
+ 0xfffd, 0x93d9, 0x908b, 0xfffd, 0xfffd, 0x9278, 0xfffd, 0x8bf6,
+ 0xfffd, 0xe7a4, 0x9756, 0x895e, 0xfffd, 0x95d5, 0x89df, 0xe79f,
+ 0xe7a0, 0xe7a1, 0xe7a2, 0x93b9, 0x9242, 0x88e1, 0xe7a6, 0xfffd,
+ 0xe7a7, 0xeaa1, 0xfffd, 0xfffd, 0x91bb, 0xfffd, 0xe7a8, 0xfffd,
+ 0x8993, 0x916b, 0xfffd, 0x8cad, 0xfffd, 0x9779, 0xfffd, 0xfffd,
+ 0xe7a9, 0x934b, 0xfffd, 0xfffd, 0xfffd, 0x9198, 0x8ed5, 0xe7aa,
+ 0xfffd, 0xfffd, 0xe7ad, 0xfffd, 0xfffd, 0x8f85, 0xe7ab, 0x914a,
+ 0x9149, 0xfffd, 0x88e2, 0xfffd, 0x97c9, 0xe7af, 0xfffd, 0x94f0,
+ 0xe7b1, 0xe7b0, 0xe7ae, 0xe284, 0x8ad2, 0xfffd, 0xfffd, 0xe78e,
+ 0xfffd, 0xe7b3, 0xe7b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7b4,
+ 0xfffd, 0x9757, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x93df, 0xfffd, 0xfffd, 0x964d, 0xfffd,
+ 0xe7b5, 0xfffd, 0x8ed7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7b6,
+ 0xfffd, 0xe7b7, 0xfffd, 0xfffd, 0xfffd, 0xe7b8, 0xfffd, 0xfffd,
+ 0x9340, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x88e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x8d78, 0xfffd, 0xfffd, 0xfffd, 0x9859, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe7bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8c53, 0xe7b9, 0xfffd, 0xe7ba, 0xfffd, 0xfffd, 0xfffd,
+ 0x9594, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a73, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9758, 0xfffd, 0x8bbd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9373, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe7bd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe7be, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe7bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9341, 0xfffd, 0xfffd,
+ 0xe7c1, 0xfffd, 0xe7c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x93d1, 0xe7c2, 0x8f55, 0x8ede, 0x947a, 0x9291, 0xfffd,
+ 0xfffd, 0xfffd, 0x8ef0, 0xfffd, 0x908c, 0xfffd, 0xe7c3, 0xfffd,
+ 0xe7c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x907c, 0xe7c5, 0xfffd, 0xe7c6, 0xfffd, 0xfffd,
+ 0xfffd, 0xe7c7, 0x978f, 0xfffd, 0x8f56, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe7c9, 0xe7c8, 0xfffd, 0x8d79, 0xfffd, 0x8d93,
+ 0x8e5f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe7cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f86,
+ 0xfffd, 0xe7cb, 0xfffd, 0xe7ca, 0xfffd, 0x91e7, 0xfffd, 0xfffd,
+ 0x8ced, 0xfffd, 0x90c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ae,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f58, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe7cd, 0xfffd, 0x8fdd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe7d0, 0xe7ce, 0xfffd, 0xfffd, 0xfffd, 0xe7cf,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7d2, 0xe7d1, 0xfffd, 0xfffd,
+ 0x8ff8, 0xfffd, 0xe7d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe7d4, 0xe7d5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ce, 0x8dd1,
+ 0x8edf, 0xe7d6, 0xfffd, 0xe7d7, 0x97a2, 0x8f64, 0x96ec, 0x97ca,
+ 0xe7d8, 0x8be0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7d9, 0xfffd,
+ 0x9342, 0xfffd, 0xfffd, 0xe7dc, 0x8a98, 0x906a, 0xfffd, 0xe7da,
+ 0xfffd, 0xe7db, 0xfffd, 0x92de, 0xfffd, 0xfffd, 0x9674, 0x8bfa,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7de, 0xe7df, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7dd, 0xfffd, 0xfffd, 0xe7e1,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93dd, 0x8a62, 0xfffd,
+ 0xfffd, 0xe7e5, 0xfffd, 0xfffd, 0xe7e2, 0xe7e4, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7e0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe86e, 0xfffd, 0xfffd, 0xe7e3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97e9, 0xfffd, 0xfffd, 0x8cd8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7ed,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9353, 0xe7e8, 0xfffd, 0xfffd,
+ 0xe7eb, 0xe7e9, 0xfffd, 0xe7ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe7ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7e7,
+ 0xfffd, 0xfffd, 0xe7f4, 0x8994, 0xfffd, 0xfffd, 0xe7e6, 0xfffd,
+ 0xfffd, 0xfffd, 0x94ab, 0xfffd, 0xe7ea, 0xfffd, 0x8fde, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8d7a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9667, 0xfffd,
+ 0x8be2, 0xfffd, 0xfffd, 0x8f65, 0xfffd, 0x93ba, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x914c, 0xfffd, 0xe7f2, 0xfffd, 0xe7ec, 0xe7f1, 0xfffd,
+ 0x96c1, 0xfffd, 0x92b6, 0xe7f3, 0xe7f0, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x914b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f7,
+ 0xfffd, 0xe7f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f5,
+ 0xfffd, 0xfffd, 0x964e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f9b, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe7f8, 0x95dd, 0xfffd, 0xfffd, 0x8973, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9565, 0x9292, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b98, 0xfffd, 0xe7fa, 0xfffd, 0x8d7c, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e4b, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f9,
+ 0x908d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x908e, 0xe840, 0xe842, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ff9, 0xfffd, 0xe841, 0xe843, 0xfffd, 0xfffd, 0x8bd1, 0xfffd,
+ 0x9564, 0xfffd, 0xfffd, 0x8ee0, 0x9842, 0xfffd, 0xe7fc, 0x8df6,
+ 0xfffd, 0xfffd, 0x985e, 0xfffd, 0xfffd, 0xe845, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe844, 0xe846, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7fb, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x93e7, 0xfffd, 0x9374, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92d5, 0xfffd, 0xe84b, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9262, 0xe847, 0xfffd, 0xfffd, 0xfffd,
+ 0xe848, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c4c, 0xfffd, 0xe84a, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cae, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe849, 0xfffd, 0x8fdf, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a99, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe84f, 0xfffd, 0x8dbd, 0x9199,
+ 0xfffd, 0xfffd, 0x92c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a5a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe84d, 0xe84e, 0x92c1, 0xfffd,
+ 0xe84c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe850, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe856, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe859, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe858, 0x934c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe851, 0xe852,
+ 0xe855, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe857, 0xfffd, 0xfffd,
+ 0xfffd, 0x8bbe, 0xfffd, 0xfffd, 0xe85a, 0xe854, 0xfffd, 0xfffd,
+ 0xe853, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe85e, 0xfffd, 0xfffd, 0xfffd, 0xe85f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe860, 0xfffd, 0xfffd, 0xe85d, 0xe85c, 0xfffd, 0xfffd, 0xfffd,
+ 0x8fe0, 0x93a8, 0xe85b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe864, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe862, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe863, 0xe861, 0xfffd,
+ 0x91f6, 0xfffd, 0xe865, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe866, 0xfffd, 0xfffd, 0xe868, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8ad3, 0xe867, 0x96f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe873, 0xe869, 0xfffd, 0xfffd, 0xe86c, 0xfffd,
+ 0xe86a, 0xfffd, 0xe86b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xe86d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe86f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe870, 0xfffd, 0xe871,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe874, 0xe872, 0xe875, 0xe877,
+ 0xfffd, 0xe876, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92b7,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x96e5, 0xfffd, 0xe878, 0x914d, 0xfffd, 0xfffd, 0xfffd, 0xe879,
+ 0xfffd, 0x95c2, 0xe87a, 0x8a4a, 0xfffd, 0xfffd, 0xfffd, 0x895b,
+ 0xfffd, 0x8ad5, 0xfffd, 0x8ad4, 0xe87b, 0xfffd, 0xe87c, 0xfffd,
+ 0xe87d, 0xe87e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe880, 0xfffd, 0x8ad6, 0x8a74, 0x8d7d, 0x94b4, 0xfffd, 0xe882,
+ 0xe881, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe883, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x897b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe886, 0xfffd, 0xe885, 0xe884, 0xfffd, 0xe887, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe88a, 0xfffd, 0xfffd, 0xfffd, 0x88c5,
+ 0xfffd, 0xfffd, 0xe888, 0xfffd, 0xe88c, 0xe88b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe88e, 0xe88d, 0xe88f, 0xfffd,
+ 0x93ac, 0xfffd, 0xfffd, 0xfffd, 0xe890, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe891, 0xe893, 0xfffd, 0xfffd, 0xe892, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x958c, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe894, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe895, 0xfffd, 0x8de3, 0xfffd, 0xfffd, 0xfffd, 0xe896, 0xe897,
+ 0xfffd, 0xfffd, 0x9668, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x916a, 0xfffd, 0xfffd, 0xfffd, 0x88a2,
+ 0x91c9, 0xfffd, 0xe898, 0xfffd, 0x958d, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe89b, 0xe899, 0x8d7e, 0xfffd, 0xe89a,
+ 0x8cc0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x95c3, 0xe89d, 0xe89f, 0xe89e, 0xe8a0,
+ 0xfffd, 0xfffd, 0x8940, 0x9077, 0x8f9c, 0x8ad7, 0xe8a1, 0xfffd,
+ 0xfffd, 0xfffd, 0x9486, 0xfffd, 0xe8a3, 0xfffd, 0xfffd, 0xfffd,
+ 0x8941, 0xfffd, 0xe8a2, 0x92c2, 0xfffd, 0x97cb, 0x93a9, 0xe89c,
+ 0x97a4, 0xfffd, 0x8caf, 0xfffd, 0xfffd, 0x977a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bf7, 0x97b2, 0xfffd,
+ 0x8c47, 0xfffd, 0x91e0, 0xe440, 0xfffd, 0xe8a4, 0x8a4b, 0x908f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a75, 0xe8a6, 0xfffd, 0xe8a7,
+ 0xe8a5, 0x8c84, 0xfffd, 0x8ddb, 0x8fe1, 0xfffd, 0xfffd, 0xfffd,
+ 0x8942, 0xfffd, 0xfffd, 0x97d7, 0xfffd, 0xfffd, 0xfffd, 0xe8a9,
+ 0xe7ac, 0xfffd, 0xe8a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe8ac, 0xe8aa, 0xe8ab, 0xfffd, 0xe8ad, 0xfffd, 0xe8ae, 0x97ea,
+ 0xe8af, 0xe8b0, 0xfffd, 0x90c7, 0x94b9, 0xfffd, 0xfffd, 0xfffd,
+ 0x909d, 0x8ae5, 0xfffd, 0xfffd, 0x9759, 0x89eb, 0x8f57, 0x8cd9,
+ 0xfffd, 0xe8b3, 0xfffd, 0xe8b2, 0x8e93, 0xe8b4, 0xe8b1, 0xfffd,
+ 0xfffd, 0x8e47, 0xfffd, 0xfffd, 0xfffd, 0xe8b8, 0xe5ab, 0xfffd,
+ 0xfffd, 0x99d4, 0xfffd, 0x9097, 0xe8b6, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x97a3, 0x93ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x894a, 0xfffd, 0x90e1, 0x8eb4, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x95b5, 0xfffd, 0x895f, 0xfffd, 0xfffd, 0xfffd, 0x97eb, 0x978b,
+ 0xfffd, 0xe8b9, 0xfffd, 0x9364, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ef9, 0xfffd, 0xfffd, 0xfffd, 0xe8ba, 0xfffd, 0xe8bb, 0x906b,
+ 0xe8bc, 0xfffd, 0x97ec, 0xfffd, 0xfffd, 0xe8b7, 0xe8be, 0xe8c0,
+ 0xfffd, 0xe8bf, 0xfffd, 0xe8bd, 0xfffd, 0xfffd, 0xe8c1, 0xfffd,
+ 0xfffd, 0xe8c2, 0xfffd, 0xfffd, 0x919a, 0xfffd, 0x89e0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8c3, 0xfffd, 0xfffd, 0x96b6,
+ 0xfffd, 0xfffd, 0xe8c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe8c5, 0xfffd, 0x9849, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9e50, 0xe8c6, 0xfffd, 0xfffd, 0xfffd, 0xe8c7, 0xe8c8, 0xfffd,
+ 0xfffd, 0xfffd, 0xe8cc, 0xfffd, 0xe8c9, 0xfffd, 0xe8ca, 0xfffd,
+ 0xe8cb, 0xe8cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x90c2, 0xfffd, 0xfffd, 0xfffd, 0x96f5, 0xfffd,
+ 0xfffd, 0x90c3, 0xfffd, 0xfffd, 0xe8ce, 0xfffd, 0x94f1, 0xfffd,
+ 0xe8cf, 0xea72, 0x96ca, 0xfffd, 0xe8d0, 0xfffd, 0xe8d1, 0xfffd,
+ 0xe8d2, 0x8a76, 0xfffd, 0xe8d4, 0xfffd, 0x9078, 0xfffd, 0xfffd,
+ 0xfffd, 0xe8d5, 0xfffd, 0xfffd, 0x8c43, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe8d6, 0xe8da, 0xfffd, 0xe8d8, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe8d9, 0xfffd, 0xfffd, 0x8a93, 0xe8d7, 0xe8db, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe8dc, 0xfffd, 0x88c6, 0xfffd, 0xe8dd,
+ 0xe8de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8fe2, 0xfffd, 0xfffd, 0xfffd, 0xe8df, 0xfffd, 0xfffd, 0xfffd,
+ 0x8b66, 0xfffd, 0xfffd, 0xe8e2, 0xfffd, 0xfffd, 0xe8e1, 0xfffd,
+ 0xe8e0, 0xfffd, 0xfffd, 0xe691, 0xfffd, 0x95da, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe8e3, 0xe8e4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe8e5, 0xfffd, 0xfffd, 0xe8e6, 0xfffd,
+ 0xe8e7, 0xfffd, 0xfffd, 0xe8e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8ad8, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8e9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8ea, 0x9442, 0xfffd,
+ 0xfffd, 0xfffd, 0xe8ec, 0x89b9, 0xfffd, 0xe8ef, 0xe8ee, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8943, 0xfffd, 0xfffd, 0xfffd, 0x8bbf,
+ 0xfffd, 0x95c5, 0x92b8, 0x8da0, 0xfffd, 0x8d80, 0x8f87, 0xfffd,
+ 0x907b, 0xfffd, 0xfffd, 0xfffd, 0xe8f1, 0xfffd, 0xfffd, 0xe8f0,
+ 0x9761, 0x8ae6, 0x94d0, 0x93da, 0xfffd, 0xfffd, 0xfffd, 0x909c,
+ 0x97cc, 0xfffd, 0x8c7a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe8f4, 0xfffd, 0xfffd, 0xe8f3, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x966a, 0x93aa, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x896f, 0xfffd, 0xfffd, 0xe8f5,
+ 0xe8f2, 0xfffd, 0xfffd, 0x9570, 0x978a, 0xe8f6, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8f7, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe8f9, 0x91e8, 0x8a7a, 0x8a7b, 0xe8f8,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ae7, 0x8cb0, 0xfffd, 0xfffd,
+ 0x8ae8, 0xfffd, 0xfffd, 0x935e, 0xfffd, 0xfffd, 0x97de, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cda,
+ 0xfffd, 0xfffd, 0xfffd, 0xe8fa, 0xfffd, 0xfffd, 0xfffd, 0xe8fb,
+ 0xe8fc, 0xe940, 0xfffd, 0xe942, 0xe941, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9597, 0xfffd, 0xe943, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe944,
+ 0xfffd, 0xe945, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe946, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe948, 0xe947, 0xfffd, 0xe949, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x94f2, 0xe3ca, 0xfffd, 0xfffd, 0x9048,
+ 0xfffd, 0xfffd, 0x8b51, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe94a, 0xfffd, 0xe94b, 0xfffd, 0x99aa, 0x9f5a, 0x94d1,
+ 0xfffd, 0xfffd, 0x88f9, 0xfffd, 0x88b9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e94, 0x964f, 0x8ffc, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe94c, 0xfffd, 0x96dd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe94d, 0x977b, 0xfffd, 0x8961, 0xfffd, 0xfffd, 0xfffd,
+ 0x8e60, 0xfffd, 0xe94e, 0x89ec, 0xe94f, 0xfffd, 0xfffd, 0xfffd,
+ 0xe950, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe952, 0xe953, 0xfffd,
+ 0xe955, 0xe951, 0xfffd, 0xfffd, 0xe954, 0xfffd, 0xfffd, 0xfffd,
+ 0x8ad9, 0xfffd, 0xfffd, 0xfffd, 0xe956, 0xfffd, 0xe957, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe958, 0xe959, 0xfffd,
+ 0xfffd, 0xfffd, 0xe95a, 0xfffd, 0xfffd, 0xe95c, 0xfffd, 0xfffd,
+ 0xfffd, 0xe95b, 0xfffd, 0xe95e, 0xe961, 0xfffd, 0xfffd, 0xfffd,
+ 0xe95d, 0xe95f, 0xe960, 0xfffd, 0xfffd, 0xe962, 0xfffd, 0x8bc0,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ef1, 0xe963,
+ 0xe964, 0x8d81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe965, 0xfffd, 0xfffd,
+ 0x8a5d, 0xfffd, 0xfffd, 0xfffd, 0x946e, 0xe966, 0xe967, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9279, 0x93e9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe968, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x949d, 0xfffd, 0xfffd, 0x91ca, 0x8977, 0x8bec, 0xfffd,
+ 0x8bed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x9293, 0xe96d, 0x8bee, 0xfffd, 0xfffd, 0x89ed, 0xfffd, 0xfffd,
+ 0xe96c, 0xfffd, 0xfffd, 0xe96a, 0xfffd, 0xe96b, 0xfffd, 0xe969,
+ 0xfffd, 0xfffd, 0xe977, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe96e, 0xe96f, 0xfffd,
+ 0xfffd, 0xe970, 0xe971, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe973, 0xfffd, 0xfffd, 0xe972, 0xfffd, 0xfffd, 0xfffd, 0x8f78,
+ 0xfffd, 0xe974, 0xfffd, 0xfffd, 0xfffd, 0xe976, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b52, 0xe975,
+ 0xfffd, 0xfffd, 0x919b, 0x8cb1, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe978, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x91cb, 0xfffd, 0xfffd, 0xe979, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x93ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe97a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe980, 0xfffd,
+ 0xe97d, 0xfffd, 0xe97c, 0xe97e, 0xfffd, 0xe97b, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe982, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe981, 0xfffd, 0xe984,
+ 0xfffd, 0xfffd, 0x8bc1, 0xe983, 0xfffd, 0xfffd, 0xfffd, 0xe985,
+ 0xfffd, 0xfffd, 0xe986, 0xfffd, 0xe988, 0xe987, 0xfffd, 0xfffd,
+ 0xfffd, 0xe989, 0xe98b, 0xe98a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8d9c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe98c, 0xfffd, 0xfffd,
+ 0xe98d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x8a5b, 0xfffd, 0xfffd, 0xfffd, 0xe98e, 0xfffd, 0xfffd, 0xfffd,
+ 0xe98f, 0xfffd, 0xfffd, 0xfffd, 0x9091, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe990,
+ 0xfffd, 0xe991, 0xfffd, 0xe992, 0xe993, 0xfffd, 0xfffd, 0xfffd,
+ 0x8d82, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe994, 0xe995,
+ 0xfffd, 0xfffd, 0xe996, 0xe997, 0xfffd, 0xfffd, 0xe998, 0xfffd,
+ 0xfffd, 0xfffd, 0x94af, 0xe99a, 0xfffd, 0x9545, 0xe99b, 0xe999,
+ 0xfffd, 0xe99d, 0xfffd, 0xfffd, 0xe99c, 0xfffd, 0xfffd, 0xe99e,
+ 0xfffd, 0xfffd, 0xfffd, 0xe99f, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9a0, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9a1, 0xfffd, 0xe9a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9a3,
+ 0xfffd, 0xfffd, 0xe9a4, 0xe9a5, 0xfffd, 0xe9a6, 0xfffd, 0xe9a7,
+ 0xe9a8, 0xe9a9, 0xe9aa, 0xfffd, 0xfffd, 0xfffd, 0xe9ab, 0xe9ac,
+ 0xfffd, 0x9f54, 0xe9ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe2f6, 0x8b53, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8a40, 0x8db0, 0xe9af, 0xe9ae, 0x96a3, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9b1, 0xe9b2, 0xe9b0,
+ 0xfffd, 0xe9b3, 0xfffd, 0xfffd, 0x9682, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9b4, 0xfffd, 0x8b9b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9844,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9b5, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe9b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88bc, 0xfffd,
+ 0xfffd, 0xe9b8, 0x95a9, 0xe9b6, 0xfffd, 0xfffd, 0xe9b9, 0xe9ba,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9bb,
+ 0xe9bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9bd, 0xfffd, 0x968e, 0x8e4c, 0xfffd, 0x8df8, 0x914e, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9be, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe9c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9c2, 0xfffd,
+ 0xfffd, 0x8cef, 0xe9c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9c3,
+ 0xfffd, 0xe9c4, 0xe9c5, 0xfffd, 0xe9c9, 0xfffd, 0x8e49, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x91e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe9ca, 0xe9c7, 0xe9c6, 0xe9c8, 0xfffd, 0xfffd, 0xfffd,
+ 0x8c7e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9ce, 0xe9cd, 0xe9cc, 0xfffd, 0xfffd, 0x88b1, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9d8, 0xfffd, 0xe9d4, 0xfffd,
+ 0xe9d5, 0xe9d1, 0xe9d7, 0xfffd, 0xe9d3, 0x8a82, 0xfffd, 0xfffd,
+ 0x986b, 0xfffd, 0xe9d6, 0xe9d2, 0xe9d0, 0xe9cf, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe9da, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xe9dd, 0xfffd, 0xfffd, 0xe9dc, 0xe9db, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9568, 0xe9d9, 0x88f1,
+ 0xe9de, 0xfffd, 0xe9e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x8a8f, 0xe9cb, 0x8956, 0xfffd, 0xfffd, 0xe9e2, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e1, 0xe9df,
+ 0x924c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0x9690, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97d8,
+ 0xfffd, 0xfffd, 0xe9e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9e4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e5,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e6, 0xfffd,
+ 0xe9e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92b9, 0xfffd, 0xe9e8,
+ 0xfffd, 0x94b5, 0xfffd, 0xe9ed, 0xe9e9, 0xfffd, 0xfffd, 0xfffd,
+ 0xe9ea, 0xfffd, 0xfffd, 0x9650, 0x96c2, 0xfffd, 0x93ce, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xe9ee, 0xfffd, 0xfffd, 0xe9ef, 0x93bc,
+ 0xe9ec, 0xe9eb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a8, 0xfffd,
+ 0xfffd, 0xfffd, 0xe9f7, 0xfffd, 0xfffd, 0xe9f6, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8995, 0xfffd, 0xfffd, 0xfffd, 0xe9f4,
+ 0xfffd, 0xfffd, 0xfffd, 0xe9f3, 0xfffd, 0xfffd, 0xe9f1, 0xfffd,
+ 0x8a9b, 0xfffd, 0xe9f0, 0x8eb0, 0x89a7, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8d83, 0xfffd, 0xfffd, 0xe9fa, 0xe9f9,
+ 0xfffd, 0xe9f8, 0xfffd, 0xfffd, 0xe9f5, 0xfffd, 0xe9fb, 0xfffd,
+ 0xe9fc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xea44, 0xea43, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xea45, 0xfffd, 0xfffd, 0x894c, 0xea40, 0xea41, 0xfffd,
+ 0x8d94, 0x96b7, 0xfffd, 0xfffd, 0xea42, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9651, 0xfffd, 0xfffd, 0xea4a,
+ 0xfffd, 0xfffd, 0xea46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xea4b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea48,
+ 0xfffd, 0xea47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c7b,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xea4c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea4d, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xea4e, 0xfffd, 0xea49, 0xfffd, 0xfffd, 0xfffd, 0xe9f2,
+ 0xfffd, 0xfffd, 0xea4f, 0xfffd, 0x92df, 0xfffd, 0xfffd, 0xfffd,
+ 0xea53, 0xfffd, 0xea54, 0xea52, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xea51, 0xea57, 0xfffd, 0xea50, 0xfffd, 0xea55, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea56,
+ 0xfffd, 0xfffd, 0xfffd, 0xea59, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xea58, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea5b, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea5c, 0xfffd, 0xea5d,
+ 0xfffd, 0xfffd, 0x9868, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xea5a, 0x91e9, 0x8deb, 0xfffd, 0xfffd, 0xea5e, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xea5f, 0xea60, 0xfffd, 0xfffd, 0xea61, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea62, 0xfffd, 0xfffd,
+ 0x8cb2, 0xea63, 0xfffd, 0xfffd, 0xfffd, 0xea64, 0xfffd, 0x8ead,
+ 0xfffd, 0xea65, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xea66, 0xfffd, 0xfffd, 0xea67, 0xea68, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xea6b, 0xea69, 0x985b, 0xfffd, 0xea6a, 0xfffd, 0x97ed,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea6c, 0xfffd, 0x97d9,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea6d, 0x949e, 0xfffd,
+ 0xfffd, 0xea6e, 0xea70, 0xfffd, 0xfffd, 0xea71, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xea6f, 0x8d8d, 0x96cb, 0x9683, 0x9bf5, 0xfffd, 0x9f80, 0x969b,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a9, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea73, 0x8b6f, 0xea74, 0xea75,
+ 0xea76, 0xfffd, 0x8d95, 0xfffd, 0xea77, 0xfffd, 0xfffd, 0xfffd,
+ 0xe0d2, 0x96d9, 0xfffd, 0x91e1, 0xea78, 0xea7a, 0xea79, 0xfffd,
+ 0xea7b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea7c, 0xfffd, 0xfffd,
+ 0xea7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea7e,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea80, 0xfffd, 0xea81, 0xea82,
+ 0xfffd, 0xea83, 0xfffd, 0xea84, 0xea85, 0xea86, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea87,
+ 0xea88, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9343, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x8cdb, 0xfffd, 0xea8a, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x916c, 0xea8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea8c, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x9540, 0xfffd, 0xfffd, 0xea8d, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xea8e, 0xe256, 0xfffd, 0xfffd, 0xe6d8, 0xe8eb,
+ 0xfffd, 0xfffd, 0xea8f, 0xfffd, 0xea90, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea92,
+ 0xea93, 0xea94, 0x97ee, 0xea91, 0xfffd, 0xfffd, 0xea95, 0xea96,
+ 0xfffd, 0xfffd, 0xea98, 0xfffd, 0xea97, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xea9a, 0xfffd, 0xfffd, 0xfffd, 0xea9b, 0xea99,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97b4, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9c, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9d, 0xe273, 0xfffd, 0xfffd,
+ 0xea9e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+#endif /* KANJI */
+
+/* Blah-to-Unicode translation tables */
+
+struct x_to_unicode u_transparent = {
+ 256, X2U_CXG, 0, 0, "Transparent", "transparent", 0, "",
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+
+/* 7-bit character sets: ISO 646, DEC NRCs, Short KOI, and Hebrew-7 */
+
+struct x_to_unicode u_ascii = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "US ASCII", "ascii", 6, "B",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e
+};
+
+struct x_to_unicode u_british = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "British ISO 646", "british", 1, "A",
+ 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e
+};
+
+struct x_to_unicode u_dutch = {
+ 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Dutch NRC", "dutch", 0, "4",
+ 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00be, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00ff, 0x00bd, 0x007c, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00a8, 0x00a4, 0x00bc, 0x0027
+};
+
+struct x_to_unicode u_finnish = {
+ 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Finnish NRC", "finnish", 0, "5C",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f,
+ 0x00e9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00e5, 0x00fc
+};
+
+struct x_to_unicode u_french = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "French ISO 646", "french", 0, "fR",
+ 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00e0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00b0, 0x00e7, 0x00a7, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e9, 0x00f9, 0x00e8, 0x00a8
+};
+
+struct x_to_unicode u_fr_canadian = {
+ 94,33,X2U_DEC|X2U_STD,AL_ROMAN,"French Canadian NRC","canadian-french",0,"9Q",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00e0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00e2, 0x00e7, 0x00ea, 0x00ee, 0x005f,
+ 0x00f4, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e9, 0x00f9, 0x00e8, 0x00fb
+};
+
+struct x_to_unicode u_german = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "German ISO 646", "german", 21, "K",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00a7, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00dc, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00fc, 0x00df
+};
+
+struct x_to_unicode u_hungarian = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Hungarian ISO 646","hungarian",86,"i",
+ 0x0021, 0x0022, 0x0023, 0x00a4, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00c1, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c9, 0x00d6, 0x00dc, 0x005e, 0x005f,
+ 0x00e1, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e9, 0x00f6, 0x00fc, 0x0022, 0x02dd
+};
+
+struct x_to_unicode u_italian = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Italian ISO 646", "italian", 15, "Y",
+ 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00a7, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00b0, 0x00e7, 0x00e9, 0x005e, 0x005f,
+ 0x00f9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e0, 0x00f2, 0x00e8, 0x00ec
+};
+
+struct x_to_unicode u_icelandic = {
+ 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Icelandic NRC", "icelandic", 0, NULL,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00de, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00f0, 0x00d8, 0x00c6, 0x00d6, 0x005f,
+ 0x00fe, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00f0, 0x007c, 0x00e6, 0x00f6
+};
+
+struct x_to_unicode u_jis0201r = {
+ 94, 33, X2U_ISO|X2U_STD,AL_ROMAN,"Japanese Roman","japanese-roman",14,"J",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x00a5, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x203e
+};
+
+struct x_to_unicode u_jis0201k = {
+ 94, 33, X2U_ISO|X2U_STD,AL_KANA,"Japanese Katakana", "katakana", 13, "I",
+ 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67,
+ 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
+ 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77,
+ 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f,
+ 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87,
+ 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f,
+ 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97,
+ 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd
+};
+
+struct x_to_unicode u_norwegian = { /* Same as Danish */
+ 94,33,X2U_ISO|X2U_STD,AL_ROMAN,"Norwegian ISO 646", "norwegian", 60, "`E6",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c6, 0x00d8, 0x00c5, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e6, 0x00f8, 0x00e5, 0x007e
+};
+
+struct x_to_unicode u_danish = { /* Same as Norwegian */
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Danish ISO 646", "danish", 60, "`E6",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c6, 0x00d8, 0x00c5, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e6, 0x00f8, 0x00e5, 0x007e
+};
+
+struct x_to_unicode u_portuguese = {
+ 94,33,X2U_ISO|X2U_STD,AL_ROMAN,"Portuguese ISO 646","portuguese",16,"L%6",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c6, 0x00d8, 0x00c5, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e6, 0x00f8, 0x00e5, 0x007e
+};
+
+struct x_to_unicode u_spanish = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Spanish ISO 646", "spanish", 17, "Z",
+ 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00a7, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00a1, 0x00d1, 0x00bf, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00b0, 0x00f1, 0x00e7, 0x007e
+};
+
+struct x_to_unicode u_swedish = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Swedish ISO 646", "swedish", 11, "HG",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00c9, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f,
+ 0x00e9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00e5, 0x00fc
+};
+
+struct x_to_unicode u_swiss = {
+ 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Swiss NRC", "swiss", 0, "=",
+ 0x0021, 0x0022, 0x00f9, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x00e0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x00e9, 0x00e7, 0x00ea, 0x00ee, 0x00e8,
+ 0x00f4, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00fc, 0x00fb
+};
+
+struct x_to_unicode u_koi7 = {
+ 94, 33, X2U_STD, AL_CYRIL, "Short KOI", "short-koi", 0, NULL,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
+ 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427
+};
+
+struct x_to_unicode u_elot927 = {
+ 94, 33, X2U_STD, AL_GREEK, "ELOT 927", "elot927-greek", 0, NULL,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
+ 0x03a0, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8,
+ 0x03a9, 0x0020, 0x0020, 0x007b, 0x007c, 0x007d, 0x007e
+};
+
+
+struct x_to_unicode u_hebrew7 = {
+ 94, 33, X2U_STD, AL_HEBREW, "Hebrew-7", "hebrew-7", 0, NULL,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+ 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+ 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+ 0x05e8, 0x05e9, 0x05ea, 0x007b, 0x007c, 0x007d, 0x007e
+};
+
+struct x_to_unicode u_apl1 = {
+ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "APL ISO", "apl-iso", 68, "e",
+ 0x00a8, 0x0029, 0x003c, 0x2264, 0x003d, 0x003e, 0x005d,
+ 0x2228, 0x2227, 0x2260, 0x00f7, 0x002c, 0x002b, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x0028, 0x005b, 0x003b, 0x00d7, 0x003a, 0x005c,
+ 0x00af, 0x237a, 0x22a5, 0x22c2, 0x230a, 0x220a, 0x005f, 0x2207,
+ 0x2206, 0x2373, 0x2218, 0x0027, 0x25af, 0x007c, 0x22a4, 0x25cb,
+ 0x22c6, 0x003f, 0x2374, 0x2308, 0x223c, 0x2193, 0x222a, 0x2375,
+ 0x2283, 0x2191, 0x2282, 0x2190, 0x22a2, 0x2192, 0x2265, 0x002d,
+ 0x22c4, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x007b, 0x22a3, 0x007d, 0x0024
+};
+
+/* ISO 8859 Latin Alphabets */
+
+struct x_to_unicode u_8859_1 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-1", "latin1", 100, "A",
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+struct x_to_unicode u_8859_2 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-2", "latin2", 101, "B",
+ 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
+ 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
+ 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
+ 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+struct x_to_unicode u_8859_3 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-3", "latin3", 109, "C",
+ 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xfffd, 0x0124, 0x00A7,
+ 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xfffd, 0x017B,
+ 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7,
+ 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xfffd, 0x017C,
+ 0x00C0, 0x00C1, 0x00C2, 0xfffd, 0x00C4, 0x010A, 0x0108, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0xfffd, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7,
+ 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0xfffd, 0x00E4, 0x010B, 0x0109, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0xfffd, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7,
+ 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9
+};
+
+struct x_to_unicode u_8859_4 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-4", "latin4", 110, "D",
+ 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7,
+ 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF,
+ 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7,
+ 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B,
+ 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A,
+ 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF,
+ 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B,
+ 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9
+};
+
+struct x_to_unicode u_8859_5 = {
+ 96,32,X2U_ISO|X2U_STD,AL_CYRIL,"ISO Latin/Cyrillic","cyrillic-iso",144,"L",
+ 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F
+};
+
+struct x_to_unicode u_8859_6 = {
+ 96, 32, X2U_ISO|X2U_STD,AL_ARABIC,"ISO Latin/Arabic","arabic-iso",127,"G",
+ 0x00A0, 0xfffd, 0xfffd, 0xfffd, 0x00A4, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x060C, 0x00AD, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0x061B, 0xfffd, 0xfffd, 0xfffd, 0x061F,
+ 0xfffd, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
+ 0x0638, 0x0639, 0x063A, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
+ 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
+ 0x0650, 0x0651, 0x0652, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd
+};
+
+struct x_to_unicode u_8859_7 = {
+ 96, 32, X2U_ISO|X2U_STD,AL_GREEK,"ISO Latin/Greek", "greek-iso", 126, "F",
+ 0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7,
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0xfffd, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xfffd
+};
+
+struct x_to_unicode u_8859_8 = {
+ 96, 32, X2U_ISO|X2U_STD,AL_HEBREW,"ISO Latin/Hebrew","hebrew-iso",121,"H",
+ 0x00A0, 0xfffd, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2017,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd
+};
+
+struct x_to_unicode u_8859_9 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-5", "latin5", 148, "M",
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
+};
+
+struct x_to_unicode u_8859_10 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-6", "latin6", 157, "V",
+ 0x00a0, 0x0104, 0x0112, 0x0122, 0x012a, 0x0128, 0x0136, 0x013b,
+ 0x0143, 0x0156, 0x0160, 0x0166, 0x017d, 0x00ad, 0x0138, 0x014a,
+ 0x0111, 0x0105, 0x0113, 0x0123, 0x012b, 0x0129, 0x0137, 0x013c,
+ 0x0144, 0x0157, 0x0161, 0x0167, 0x017e, 0x00bd, 0x00be, 0x014b,
+ 0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x00cf,
+ 0x0110, 0x0145, 0x014c, 0x00de, 0x00d4, 0x00d5, 0x00d6, 0x0168,
+ 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x016a,
+ 0x0101, 0x00e1, 0x00e2, 0x00d3, 0x00e4, 0x00e5, 0x00e6, 0x012f,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x014d, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0169,
+ 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x016b
+};
+
+/* Latin-9 (ISO 8859-15) is the same as Latin-1 with the following changes:
+ * A4 is Euro Symbol 20AC
+ * A6 is Capital S Caron 0160
+ * A8 is Small s caron 0161
+ * B4 is Capital Z caron 017D
+ * B8 is Small z caron 017E
+ * BC is Capital OE ligature 0152
+ * BD is Small oe ligature 0153
+ * BE is Capital Y diaeresis 0178
+ */
+
+struct x_to_unicode u_8859_15 = {
+ 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-9", "latin9", 0, NULL,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7,
+ 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7,
+ 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+/* Dyadic Systems Dyalog/X APL, corresponds to APLTERMI.TTF. */
+/* Unicode mappings according to ISO-IEC / JTC 1 / SC 22 N 3067, 1999-12-28. */
+
+struct x_to_unicode u_apl2 = { /* Dyadic Systems APL + box drawings */
+ 96, 32, X2U_STD, AL_ROMAN, "Dyadic Systems APL", "apl-dyadic", 0, NULL,
+ 0x00a0, 0x00d7, 0x2502, 0x2524, 0x00a2, 0x2510, 0x2514, 0x2534,
+ 0x252c, 0x251c, 0x2500, 0x253c, 0x2518, 0x250c, 0x2206, 0x00f7,
+ 0x2260, 0x22c4, 0x2375, 0x2374, 0x237a, 0x220a, 0x2261, 0x2265,
+ 0x2264, 0x22a5, 0x22a4, 0x2190, 0x2218, 0x235d, 0x233f, 0x2340,
+ 0x234e, 0x2355, 0x234b, 0x2352, 0x2372, 0x2371, 0x2368, 0x235f,
+ 0x25af, 0x235e, 0x2339, 0x236b, 0x236a, 0x2262, 0x230a, 0x2308,
+ 0x2349, 0x2229, 0x222a, 0x236c, 0x00a3, 0x233d, 0x2296, 0x22a2,
+ 0x22a3, 0x2337, 0x00af, 0x2373, 0x00a8, 0x25cb, 0x2192, 0x2228,
+ 0x2282, 0x2283, 0x2359, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045,
+ 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d,
+ 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055,
+ 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x2207, 0x2191, 0x2193
+};
+
+struct x_to_unicode u_apl3 = { /* APL-Plus = APL-2000 */
+ 128, 0, X2U_CXG, AL_ROMAN, "APL-2000", "apl-2000", 0, NULL,
+ 0x20ac, 0x22a3, 0x22a4, 0x22a5, 0x2190, 0x2192, 0x2191, 0x2193,
+ 0x2264, 0x2265, 0x2372, 0x2371, 0x25af, 0x235e, 0x2339, 0x2359,
+ 0x236b, 0x2206, 0x2207, 0x234b, 0x2352, 0x2355, 0x234e, 0x2308,
+ 0x230a, 0x2340, 0x233f, 0x2282, 0x2283, 0x2229, 0x222a, 0x2228,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x22a2, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x235d, 0x22c4, 0x00ab, 0x2260, 0x2261, 0x236a, 0x00af,
+ 0x2218, 0x25cb, 0x233d, 0x2349, 0x2296, 0x235f, 0x00b6, 0x00b7,
+ 0x237a, 0x220a, 0x2377, 0x00bb, 0x2373, 0x2374, 0x2375, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x236c, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x2337, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x2364, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x2205, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x2368, 0x00ff
+};
+
+struct x_to_unicode u_apl4 = { /* IBM APL2 */
+ 128, 0, X2U_CXG, AL_ROMAN, "IBM APL2", "apl2-ibm", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x25af, 0x235e, 0x2339, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x22a4, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x22a5, 0x2190, 0x2336,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+ 0x00bf, 0x2308, 0x00ac, 0x2192, 0x222a, 0x00a1, 0x2355, 0x234e,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x235f, 0x2206, 0x2207,
+ 0x2192, 0x2563, 0x2551, 0x2557, 0x255d, 0x2190, 0x230a, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x2191, 0x2193,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2261,
+ 0x2378, 0x2377, 0x2235, 0x2337, 0x2342, 0x233b, 0x22a2, 0x22a3,
+ 0x22c4, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,
+ 0x237a, 0x00df, 0x2282, 0x2283, 0x235d, 0x2372, 0x2374, 0x2371,
+ 0x233d, 0x2296, 0x25cb, 0x2228, 0x2373, 0x2349, 0x00c5, 0x2229,
+ 0x233f, 0x2340, 0x2265, 0x2264, 0x2260, 0x00d7, 0x00f7, 0x2359,
+ 0x2218, 0x2375, 0x236b, 0x234b, 0x2352, 0x00af, 0x00a8, 0x00a0
+};
+
+struct x_to_unicode u_apl5 = { /* APL-2741 */
+ 128, 0, X2U_CXG, AL_ROMAN, "APL-2741", "apl-2741", 0, NULL,
+ 0x20ac, 0x22a3, 0x22a4, 0x22a5, 0x2190, 0x2192, 0x2191, 0x2193,
+ 0x2264, 0x2265, 0x2372, 0x2371, 0x25af, 0x235e, 0x2339, 0x2359,
+ 0x236b, 0x2206, 0x2207, 0x234b, 0x2352, 0x2355, 0x234e, 0x2308,
+ 0x230a, 0x2340, 0x233f, 0x2282, 0x2283, 0x2229, 0x222a, 0x2228,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x22a2, 0x2378, 0x2261, 0x2336,
+ 0x00a8, 0x235d, 0x22c4, 0x236c, 0x2260, 0x2261, 0x236a, 0x00af,
+ 0x2218, 0x25cb, 0x233d, 0x2349, 0x2296, 0x235f, 0x00b6, 0x00b7,
+ 0x237a, 0x220a, 0x2377, 0x2262, 0x2373, 0x2374, 0x2375, 0x00bf,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x2342, 0x233b, 0x2510, 0x00cd, 0x2500, 0x253c,
+ 0x236c, 0x00d1, 0x2350, 0x2357, 0x2347, 0x2348, 0x00d6, 0x00d7,
+ 0x00d8, 0x2518, 0x250c, 0x2502, 0x00dc, 0x2524, 0x2337, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x2364, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x2205, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x2235, 0x2368, 0x2365
+};
+
+/* 8-bit GOST standard sets */
+
+struct x_to_unicode u_koi8 = {
+ 96, 32, X2U_STD, AL_CYRIL, "KOI-8", "koi8", 0, NULL,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
+ 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
+ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
+ 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0xfffd
+};
+
+/* Other KOI-8 based sets */
+
+struct x_to_unicode u_koi8r = { /* (Russia) Table from RFC1489 */
+ 128, 0, X2U_CP, AL_CYRIL, "KOI8-R", "koi8r", 0, NULL,
+ 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
+ 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
+ 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
+ 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
+ 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556,
+ 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E,
+ 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565,
+ 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9,
+ 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
+ 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
+ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
+ 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
+};
+
+struct x_to_unicode u_koi8u = { /* (Ukraine) From RFC2319 */
+ 128, 0, X2U_CP, AL_CYRIL, "KOI8-U", "koi8u", 0, NULL,
+ 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
+ 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
+ 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
+ 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
+ 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457,
+ 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E,
+ 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407,
+ 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9,
+ 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
+ 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
+ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
+ 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
+};
+
+/* PC Code Pages */
+
+struct x_to_unicode u_cp437 = {
+ 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 437","cp437", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
+ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, /* 0x25ae */ 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_mazovia = {
+ 128, 0, X2U_CP, AL_ROMAN,"Polish Mazovia PC Code Page","mazovia", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x0105, 0x00e7, /* 80 */
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0107, 0x00c4, 0x0104, /* 88 */
+ 0x0118, 0x0119, 0x0142, 0x00f4, 0x00f6, 0x0106, 0x00fb, 0x00f9, /* 90 */
+ 0x015a, 0x00d6, 0x00dc, 0x00a2, 0x0141, 0x00a5, 0x015b, 0x0192, /* 98 */
+ 0x0179, 0x017b, 0x00f3, 0x00d3, 0x0144, 0x0143, 0x017a, 0x017c, /* a0 */
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, /* a8 */
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, /* b0 */
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, /* b8 */
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, /* c0 */
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, /* c8 */
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, /* d0 */
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, /* d8 */
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, /* e0 */
+ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, /* e8 */
+ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, /* f0 */
+ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 /* f8 */
+};
+
+struct x_to_unicode u_cp850 = {
+ 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 850","cp850", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+ 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0,
+ 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
+ 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce,
+ 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,
+ 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe,
+ 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4,
+ 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8,
+ 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_cp852 = {
+ 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 852","cp852", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x016f, 0x0107, 0x00e7,
+ 0x0142, 0x00eb, 0x0150, 0x0151, 0x00ee, 0x0179, 0x00c4, 0x0106,
+ 0x00c9, 0x0139, 0x013a, 0x00f4, 0x00f6, 0x013d, 0x013e, 0x015a,
+ 0x015b, 0x00d6, 0x00dc, 0x0164, 0x0165, 0x0141, 0x00d7, 0x010d,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x0104, 0x0105, 0x017d, 0x017e,
+ 0x0118, 0x0119, 0x00ac, 0x017a, 0x010c, 0x015f, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x011a,
+ 0x015e, 0x2563, 0x2551, 0x2557, 0x255d, 0x017b, 0x017c, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x0102, 0x0103,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
+ 0x0111, 0x0110, 0x010e, 0x00cb, 0x010f, 0x0147, 0x00cd, 0x00ce,
+ 0x011b, 0x2518, 0x250c, 0x2588, 0x2584, 0x0162, 0x016e, 0x2580,
+ 0x00d3, 0x00df, 0x00d4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+ 0x0154, 0x00da, 0x0155, 0x0170, 0x00fd, 0x00dd, 0x0163, 0x00b4,
+ 0x00ad, 0x02dd, 0x02db, 0x02c7, 0x02d8, 0x00a7, 0x00f7, 0x00b8,
+ 0x00b0, 0x00a8, 0x02d9, 0x0171, 0x0158, 0x0159, 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_cp855 = { /* CP855 Cyrillic to Unicode */
+ 128, 0, X2U_CP, AL_CYRIL,"PC Code Page 855","cp855", 0, NULL,
+ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
+ 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
+ 0x0459, 0x0409, 0x045a, 0x040a, 0x045b, 0x040b, 0x045c, 0x040c,
+ 0x045e, 0x040e, 0x045f, 0x040f, 0x044e, 0x042e, 0x044a, 0x042a,
+ 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+ 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+ 0x0418, 0x2563, 0x2551, 0x2557, 0x255d, 0x0439, 0x0419, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x043a, 0x041a,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
+ 0x043b, 0x041b, 0x043c, 0x041c, 0x043d, 0x041d, 0x043e, 0x041e,
+ 0x043f, 0x2518, 0x250c, 0x2588, 0x2584, 0x041f, 0x044f, 0x2580,
+ 0x042f, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+ 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044c, 0x042c, 0x2116,
+ 0x002d, 0x044b, 0x042b, 0x0437, 0x0417, 0x0448, 0x0428, 0x044d,
+ 0x042d, 0x0449, 0x0429, 0x0447, 0x0427, 0x00a7, 0x25a0, 0x0020
+};
+
+struct x_to_unicode u_cp856 = { /* CP856 (Bulgaria) to Unicode */
+ 128, 0, X2U_CP, AL_CYRIL,"PC Code Page 856","cp856", 0, NULL,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x2563, 0x2551,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2510,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2116, 0x00a7, 0x2557,
+ 0x255d, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
+ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_cp857 = {
+ 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 857","cp857", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, /* 0x80 */
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0131, 0x00c4, 0x00c5, /* 0x88 */
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, /* 0x90 */
+ 0x0130, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x015e, 0x015f, /* 0x98 */
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x011e, 0x011f, /* 0xa0 */
+ 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, /* 0xa8 */
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, /* 0xb0 */
+ 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, /* 0xb8 */
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, /* 0xc0 */
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, /* 0xc8 */
+ 0x00ba, 0x00aa, 0x00ca, 0x00cb, 0x00c8, 0x20ac, 0x00cd, 0x00ce, /* 0xd0 */
+ 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, /* 0xd8 */
+ 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0xfffd, /* 0xe0 */
+ 0x00d7, 0x00da, 0x00db, 0x00d9, 0x00ec, 0x00ff, 0x00af, 0x00b4, /* 0xe8 */
+ 0x00ad, 0x00b1, 0xfffd, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, /* 0xf0 */
+ 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 /* 0xf8 */
+};
+
+struct x_to_unicode u_cp858 = {
+ 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 858","cp858", 0, NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+ 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0,
+ 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
+ 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x20ac, 0x00cd, 0x00ce,
+ 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,
+ 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe,
+ 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4,
+ 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8,
+ 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_cp862 = {
+ 128, 0, X2U_CP, AL_HEBREW,"PC Code Page 862","cp862", 0, NULL,
+ 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+ 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+ 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+ 0x05e8, 0x05e9, 0x05ea, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
+ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_cp864 = {
+ 128, 0, X2U_CP, AL_ARABIC,"PC Code Page 864","cp864", 0, NULL,
+ 0x00b0, 0x00b7, 0x2219, 0x221a, 0x2592, 0x2500, 0x2502, 0x253c,
+ 0x2524, 0x252c, 0x251c, 0x2534, 0x2510, 0x250c, 0x2514, 0x2518,
+ 0x03b2, 0x221e, 0x03c6, 0x00b1, 0x00bd, 0x00bc, 0x2248, 0x00ab,
+ 0x00bb, 0xfef7, 0xfef8, 0xfffd, 0xfffd, 0xfefb, 0xfefc, 0xfffd,
+ 0x00a0, 0x00ad, 0xfe82, 0x00a3, 0x00a4, 0xfe84, 0xfffd, 0xfffd,
+ 0xfe8e, 0xfe8f, 0xfe95, 0xfe99, 0x060c, 0xfe9d, 0xfea1, 0xfea5,
+ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667,
+ 0x0668, 0x0669, 0xfed1, 0x061b, 0xfeb1, 0xfeb5, 0xfeb9, 0x061f,
+ 0x00a2, 0xfe80, 0xfe81, 0xfe83, 0xfe85, 0xfeca, 0xfe8b, 0xfe8d,
+ 0xfe91, 0xfe93, 0xfe97, 0xfe9b, 0xfe9f, 0xfea3, 0xfea7, 0xfea9,
+ 0xfeab, 0xfead, 0xfeaf, 0xfeb3, 0xfeb7, 0xfebb, 0xfebf, 0xfec1,
+ 0xfec5, 0xfecb, 0xfecf, 0x00a6, 0x00ac, 0x00f7, 0x00d7, 0xfec9,
+ 0x0640, 0xfed3, 0xfed7, 0xfedb, 0xfedf, 0xfee3, 0xfee7, 0xfeeb,
+ 0xfeed, 0xfeef, 0xfef3, 0xfebd, 0xfecc, 0xfece, 0xfecd, 0xfee1,
+ 0xfe7d, 0x0651, 0xfee5, 0xfee9, 0xfeec, 0xfef0, 0xfef2, 0xfed0,
+ 0xfed5, 0xfef5, 0xfef6, 0xfedd, 0xfed9, 0xfef1, 0x25a0, 0xfffd
+};
+
+struct x_to_unicode u_cp866 = {
+ 128, 0, X2U_CP, AL_CYRIL,"PC Code Page 866","cp866", 0, NULL,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040e, 0x045e,
+ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x2116, 0x00a4, 0x25a0, 0x00a0
+};
+
+struct x_to_unicode u_cp869 = {
+ 128, 0, X2U_CP, AL_GREEK,"PC Code Page 869","cp869", 0, NULL,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0386, 0xfffd,
+ 0x00b7, 0x00ac, 0x00a6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
+ 0x038a, 0x03aa, 0x038c, 0xfffd, 0xfffd, 0x038e, 0x03ab, 0x00a9,
+ 0x038f, 0x00b2, 0x00b3, 0x03ac, 0x00a3, 0x03ad, 0x03ae, 0x03af,
+ 0x03ca, 0x0390, 0x03cc, 0x03cd, 0x0391, 0x0392, 0x0393, 0x0394,
+ 0x0395, 0x0396, 0x0397, 0x00bd, 0x0398, 0x0399, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039a, 0x039b, 0x039c,
+ 0x039d, 0x2563, 0x2551, 0x2557, 0x255d, 0x039e, 0x039f, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x03a0, 0x03a1,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x03a3,
+ 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03b1, 0x03b2,
+ 0x03b3, 0x2518, 0x250c, 0x2588, 0x2584, 0x03b4, 0x03b5, 0x2580,
+ 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd,
+ 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x0384,
+ 0x00ad, 0x00b1, 0x03c5, 0x03c6, 0x03c7, 0x00a7, 0x03c8, 0x0385,
+ 0x00b0, 0x00a8, 0x03c9, 0x03cb, 0x03b0, 0x03ce, 0x25a0, 0x00a0
+};
+
+/* Windows code pages */
+
+struct x_to_unicode u_cp1250 = { /* Windows Latin-2 */
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1250","cp1250", 0, NULL,
+ 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */
+ 0x005e, 0x2031, 0x0160, 0x003c, 0x015a, 0x0164, 0x017d, 0x0179, /* 88 */
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */
+ 0xfffd, 0x2122, 0x0161, 0x003e, 0x015b, 0x0165, 0x017e, 0x017a, /* 98 */
+ 0x00A0, 0x02c7, 0x02d8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, /* A0 */
+ 0x00A8, 0x00a9, 0x015E, 0x00ab, 0x00ac, 0x002D, 0x00ae, 0x017B, /* A8 */
+ 0x00B0, 0x00b1, 0x02DB, 0x0142, 0x00B4, 0x00b5, 0x00b6, 0x00b7, /* B0 */
+ 0x00B8, 0x0105, 0x015F, 0x00bb, 0x013d, 0x02DD, 0x013E, 0x017C, /* B8 */
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, /* C0 */
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+struct x_to_unicode u_cp1251 = { /* Windows Cyrillic */
+ 128, 0, X2U_CP, AL_CYRIL,"Windows Code Page 1251","cp1251", 0, NULL,
+ 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */
+ 0x20ac, 0x2031, 0x0409, 0x003c, 0x040a, 0x040c, 0x040b, 0x040f, /* 88 */
+ 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */
+ 0x007e, 0x2122, 0x0459, 0x003e, 0x045a, 0x045c, 0x045b, 0x045f, /* 98 */
+ 0x00A0, 0x040e, 0x045e, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, /* a0 */
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, /* a8 */
+ 0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, /* b0 */
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, /* b8 */
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, /* c0 */
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, /* c8 */
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, /* d0 */
+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, /* d8 */
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, /* e0 */
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, /* e8 */
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, /* f0 */
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f /* f8 */
+};
+
+struct x_to_unicode u_cp1252 = { /* Windows Latin-1 */
+/*
+ The following code points added September 1998:
+ 0x80: Euro
+ 0x8E: Latin Capital Letter Z with Caron
+ 0x9E: Latin Small Letter Z with Caron
+ Announced by Murray Sargent <murrays@microsoft.com> to Unicode consortium,
+ email, 3 September 1998. The code page was changed in June 1998. The
+ change is reflected in Windows 98 and "recent service packs" for Window 95
+ and Windows NT 4.0.
+*/
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1252","cp1252", 0, NULL,
+ 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x005e, 0x2031, 0x0160, 0x003c, 0x0152, 0xfffd, 0x017D, 0xfffd,
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014,
+ 0x007e, 0x2122, 0x0161, 0x003e, 0x0153, 0xfffd, 0x017E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+struct x_to_unicode u_cp1253 = { /* Windows Greece */
+ 128, 0, X2U_CP, AL_GREEK,"Windows Code Page 1253","cp1253", 0, NULL,
+ 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */
+ 0xfffd, 0x2031, 0xfffd, 0x003c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 88 */
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */
+ 0xfffd, 0x2122, 0xfffd, 0x003e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 98 */
+ 0x00A0, 0x00b7, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, /* a0 */
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, /* a8 */
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B7, 0x00B5, 0x00B6, 0x00B7, /* b0 */
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, /* b8 */
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* c0 */
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, /* c8 */
+ 0x03a0, 0x03a1, 0xfffd, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* d0 */
+ 0x03a8, 0x03a9, 0x03aA, 0x03aB, 0x03aC, 0x03aD, 0x03aE, 0x03aF, /* d8 */
+ 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* e0 */
+ 0x03b8, 0x03b9, 0x03bA, 0x03bB, 0x03bC, 0x03bD, 0x03bE, 0x03bF, /* e8 */
+ 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* f0 */
+ 0x03c8, 0x03c9, 0x03cA, 0x03cB, 0x03cC, 0x03cD, 0x03cE, 0xfffd /* f8 */
+};
+
+struct x_to_unicode u_cp1254 = { /* Windows Turkey */
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1254","cp1254", 0, NULL,
+ 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */
+ 0x005e, 0x2031, 0x0160, 0x003c, 0x0152, 0xfffd, 0xfffd, 0xfffd, /* 88 */
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */
+ 0x007e, 0x2122, 0x0161, 0x003e, 0x0153, 0xfffd, 0xfffd, 0x0178, /* 98 */
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011e, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015e, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011f, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015f, 0x00FF
+};
+
+struct x_to_unicode u_cp1255 = { /* Windows Hebrew */
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1255 (Hebrew)","cp1255",
+ 0, NULL,
+ 0x20AC, 0xFFFD, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x02c6, 0x2030, 0xfffd, 0x2039, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x02dc, 0x2122, 0xfffd, 0x203a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20aa, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
+ 0x05b8, 0x05b9, 0xfffd, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
+ 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f0, 0x05f1, 0x05f2, 0x05f3,
+ 0x05f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+ 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+ 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+ 0x05e8, 0x05e9, 0x05ea, 0xfffd, 0xfffd, 0x200e, 0x200f, 0xfffd
+};
+
+struct x_to_unicode u_cp1256 = { /* Windows Arabic */
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1256 (Arabic)","cp1256",
+ 0, NULL,
+ 0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x02c6, 0x2030, 0xfffd, 0x2039, 0x0152, 0x0686, 0x0698, 0xfffd, /* 88 */
+ 0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, /* 90 */
+ 0xfffd, 0x2122, 0xfffd, 0x003a, 0x0153, 0x200c, 0x200d, 0xfffd, /* 98 */
+ 0x00A0, 0x060c, 0x00A2, 0x00A3, 0x00A4, 0x00a5, 0x00A6, 0x00A7, /* a0 */
+ 0x00a8, 0x00A9, 0xfffd, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00af, /* a8 */
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00b4, 0x00B5, 0x00B6, 0x00B7, /* b0 */
+ 0x00b8, 0x00B9, 0x061b, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061f, /* b8 */
+ 0xfffd, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* c0 */
+ 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* c8 */
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, /* d0 */
+ 0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643, /* d8 */
+ 0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7, /* e0 */
+ 0x00e8, 0x00E9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef, /* e8 */
+ 0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00F7, /* f0 */
+ 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0xfffd /* f8 */
+};
+
+struct x_to_unicode u_cp1257 = { /* Windows Latin-4 */
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1257","cp1257", 0, NULL,
+ 0x20ac, 0xfffd, 0x201a, 0xfffd, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */
+ 0xfffd, 0x2031, 0xfffd, 0x003c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 88 */
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */
+ 0xfffd, 0x2122, 0xfffd, 0x003e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 98 */
+ 0x00A0, 0xfffd, 0x00A2, 0x00A3, 0x00A4, 0xfffd, 0x00A6, 0x00A7, /* a0 */
+ 0x00d8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00c6, /* a8 */
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xfffd, 0x00B5, 0x00B6, 0x00B7, /* b0 */
+ 0x00f8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00e6, /* b8 */
+ 0x0104, 0x012e, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, /* c0 */
+ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x00b7, /* c8 */
+ 0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00D5, 0x00D6, 0x00D7, /* d0 */
+ 0x0172, 0x0141, 0x015A, 0x016a, 0x00DC, 0x017b, 0x017d, 0x00DF, /* d8 */
+ 0x0105, 0x012f, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, /* e0 */
+ 0x010D, 0x00E9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c, /* e8 */
+ 0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00F5, 0x00F6, 0x00F7, /* f0 */
+ 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0xfffd /* f8 */
+};
+
+struct x_to_unicode u_cp1258 = { /* Windows Viet Nam */
+ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1258 (Viet Nam)","cp1258",
+ 0, NULL,
+ 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */
+ 0x02c6, 0x2030, 0xfffd, 0x2039, 0x0152, 0xfffd, 0xfffd, 0xfffd, /* 88 */
+ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, /* 90 */
+ 0x02dc, 0x2122, 0xfffd, 0x203a, 0x0153, 0xfffd, 0xfffd, 0x0178, /* 98 */
+ 0x00A0, 0x00a1, 0x00A2, 0x00A3, 0x00A4, 0x00a5, 0x00A6, 0x00A7, /* a0 */
+ 0x00a8, 0x00A9, 0x00aa, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00af, /* a8 */
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00b4, 0x00B5, 0x00B6, 0x00B7, /* b0 */
+ 0x00b8, 0x00B9, 0x00ba, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00bf, /* b8 */
+ 0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00C4, 0x00C5, 0x00c6, 0x00c7, /* c0 */
+ 0x00c8, 0x00C9, 0x00ca, 0x00cb, 0x0300, 0x00cd, 0x00ce, 0x00cf, /* c8 */
+ 0x0110, 0x00d1, 0x0309, 0x00d3, 0x00d4, 0x01a0, 0x00D6, 0x00D7, /* d0 */
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00DC, 0x01af, 0x0303, 0x00DF, /* d8 */
+ 0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00E4, 0x00E5, 0x00e6, 0x00d7, /* e0 */
+ 0x00e8, 0x00E9, 0x00ea, 0x00eb, 0x0301, 0x00ed, 0x00ee, 0x00ef, /* e8 */
+ 0x0111, 0x00f1, 0x0323, 0x00f3, 0x00f4, 0x01a1, 0x00F6, 0x00F7, /* f0 */
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x01b0, 0x20ab, 0x00ff /* f8 */
+};
+
+struct x_to_unicode u_cp37 = { /* EBCDIC U.S. */
+ 256, 0, X2U_CP, AL_ROMAN,"Code Page 037 EBCDIC (U.S.)","cp037", 0, NULL,
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
+ 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
+ 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
+ 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
+ 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5,
+ 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C,
+ 0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF,
+ 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC,
+ 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5,
+ 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
+ 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF,
+ 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
+ 0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
+ 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
+ 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4,
+ 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
+ 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE,
+ 0x005E, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC,
+ 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
+ 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5,
+ 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
+ 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF,
+ 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F
+};
+
+/* Other proprietary 8-bit sets */
+
+struct x_to_unicode u_decmcs = {
+ 96, 32, X2U_DEC|X2U_STD, AL_ROMAN, "DEC Multinational", "dec-mcs", 0, "%5",
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0xfffd, 0x00A5, 0xfffd, 0x00A7,
+ 0x00A4, 0x00A9, 0x00AA, 0x00AB, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xfffd, 0x00B5, 0x00B6, 0x00B7,
+ 0xfffd, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0xfffd, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0xfffd, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0152,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0xfffd, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0xfffd, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0153,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0xfffd, 0x00FF
+};
+
+struct x_to_unicode u_hproman8 = {
+ 96, 32, X2U_STD, AL_ROMAN, "Hewlett Packard Roman 8", "hp-roman8", 0, NULL,
+ 0x00a0, 0x00c0, 0x00c2, 0x00c8, 0x00ca, 0x00cb, 0x00ce, 0x00cf,
+ 0x00b4, 0x00a6, 0x00a9, 0x00a8, 0x00ac, 0x00d9, 0x00db, 0x20a4,
+ 0x00af, 0x00dd, 0x00fd, 0x00b0, 0x00c7, 0x00e7, 0x00d1, 0x00f1,
+ 0x00a1, 0x00bf, 0x00a4, 0x00a3, 0x00a5, 0x00a7, 0x0192, 0x00a2,
+ 0x00e2, 0x00ea, 0x00f4, 0x00fb, 0x00e1, 0x00e9, 0x00f3, 0x00fa,
+ 0x00e0, 0x00e8, 0x00f2, 0x00f9, 0x00e4, 0x00eb, 0x00f6, 0x00fc,
+ 0x00c5, 0x00ee, 0x00d8, 0x00c6, 0x00e5, 0x00ed, 0x00f8, 0x00e6,
+ 0x00c4, 0x00ec, 0x00d6, 0x00dc, 0x00c9, 0x00ef, 0x00df, 0x00d4,
+ 0x00c1, 0x00c3, 0x00e3, 0x00d0, 0x00f0, 0x00cd, 0x00cc, 0x00d3,
+ 0x00d2, 0x00d5, 0x00f5, 0x0160, 0x0161, 0x00da, 0x00b8, 0x00ff,
+ 0x00de, 0x00fe, 0x00b7, 0x00b5, 0x00b6, 0x00be, 0x2015, 0x00bc,
+ 0x00bd, 0x00aa, 0x00ba, 0x00ab, 0x2588, 0x00bb, 0x00b1, 0xfffd
+};
+
+struct x_to_unicode u_dgi = {
+ 96,32,X2U_STD,AL_ROMAN,"Data General International","dg-international",0,NULL,
+ 0x00a0, 0x00ac, 0x00bd, 0x00b5, 0x00b2, 0x00b3, 0x00a4, 0x00a2,
+ 0x00a3, 0x00aa, 0x00ba, 0x00a1, 0x00bf, 0x00a9, 0x00ae, 0x2021,
+ 0x00bb, 0x00ab, 0x00b6, 0x2122, 0x0192, 0x00a5, 0x00b1, 0x2264,
+ 0x2265, 0x00b7, 0x00b8, 0x00a7, 0x00b0, 0x00a8, 0x00b4, 0x2191,
+ 0x00c1, 0x00c0, 0x00c2, 0x00c4, 0x00c3, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c9, 0x00c8, 0x00ca, 0x00cb, 0x00cd, 0x00cc, 0x00ce, 0x00cf,
+ 0x00d1, 0x00d3, 0x00d2, 0x00d4, 0x00d6, 0x00d5, 0x00d8, 0x0276,
+ 0x00da, 0x00d9, 0x00db, 0x00dc, 0xfffd, 0x0178, 0xfffd, 0xfffd,
+ 0x00e1, 0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e9, 0x00e8, 0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef,
+ 0x00f1, 0x00f3, 0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00f8, 0x0153,
+ 0x00fa, 0x00f9, 0x00fb, 0x00fc, 0x00df, 0x00ff, 0xfffd, 0x2588
+};
+
+struct x_to_unicode u_nextstep = {
+ 128, 0, 0, AL_ROMAN,"NeXTSTEP Multinational","next-multinational",0,NULL,
+ 0x00a0, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d9,
+ 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00b5, 0x00d7, 0x00f7,
+ 0x00a9, 0x00a1, 0x00a2, 0x00a3, 0x2044, 0x00a5, 0x0192, 0x00a7,
+ 0x00a4, 0x2019, 0x201c, 0x00ab, 0x2039, 0x203a, 0xfb01, 0xfb02,
+ 0x00ae, 0x2013, 0x2020, 0x2021, 0x00b7, 0x00a6, 0x00b6, 0x2022,
+ 0x201a, 0x201e, 0x201d, 0x00bb, 0x2026, 0x2030, 0x00ac, 0x00bf,
+ 0x00b9, 0x02cb, 0x00b4, 0x02c6, 0x02dc, 0x00af, 0x02d8, 0x02d9,
+ 0x00a8, 0x00b2, 0x02da, 0x00b8, 0x00b3, 0x02dd, 0x02db, 0x02c7,
+ 0x2014, 0x00b1, 0x00bc, 0x00bd, 0x00be, 0x00e0, 0x00e1, 0x00e2,
+ 0x00e3, 0x00e4, 0x00e5, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb,
+ 0x00ec, 0x00c6, 0x00ed, 0x00aa, 0x00ee, 0x00ef, 0x00f0, 0x00f1,
+ 0x0141, 0x00d8, 0x0152, 0x00ba, 0x00f2, 0x00f3, 0x00f4, 0x00f5,
+ 0x00f6, 0x00e6, 0x00f9, 0x00fa, 0x00fb, 0x0131, 0x00fc, 0x00fd,
+ 0x0142, 0x00f8, 0x0153, 0x00df, 0x00fe, 0x00ff, 0xfffd, 0xfffd
+};
+
+struct x_to_unicode u_maclatin = {
+ 128, 0, 0, AL_ROMAN,"Macintosh Latin","maclatin", 0, NULL,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x00DD, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x2126, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x00A4, 0x00D0, 0x00F0, 0x00DE, 0x00FE,
+ 0x00FD, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+};
+
+struct x_to_unicode u_quickdraw = {
+ 128, 0, 0, AL_ROMAN,"QuickDraw","quickdraw", 0, NULL,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x00A4, 0x2039, 0x203A, 0xFB01, 0xFB02,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+};
+
+/* DEC special graphics / technical sets for VT emulation */
+
+#ifdef KERMITFONT
+struct x_to_unicode u_dectech = {
+ 94, 33, X2U_DEC|X2U_STD,AL_ROMAN,"DEC Technical", "dec-technical", 0, ">",
+ 0xE400, 0x250c, 0x2500, 0x2320, 0x2321, 0x2502, 0xE204,
+ 0xE203, 0xE209, 0xE208, 0xE202, 0xE201, 0xE207, 0xE206, 0xE200,
+ 0xE205, 0xE20D, 0xE20C, 0x2572, 0x2571, 0xE20E, 0xE20F, 0x232a,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2264, 0x2260, 0x2265, 0x222b,
+ 0x2234, 0x221d, 0x221e, 0x00f7, 0x2206, 0x2207, 0x03a6, 0x0393,
+ 0x223c, 0x2243, 0x0398, 0x00d7, 0x039b, 0x21d4, 0x21d2, 0x2261,
+ 0x220f, 0x03a8, 0xE401, 0x03a3, 0xFFFD, 0xfffd, 0x221a, 0x03a9,
+ 0x039e, 0x03d2, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228,
+ 0x00ac, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3,
+ 0x03b7, 0x03b9, 0x03b8, 0x03ba, 0x03bb, 0xFFFD, 0x03bd, 0x2202,
+ 0x03c0, 0x03c8, 0x03c1, 0x03c3, 0x03c4, 0xFFFD, 0x0192, 0x03c9,
+ 0x03be, 0x03c5, 0x03b6, 0x2190, 0x2191, 0x2192, 0x2193
+};
+#else
+struct x_to_unicode u_dectech = {
+ 94, 33, X2U_DEC|X2U_STD,AL_ROMAN,"DEC Technical", "dec-technical", 0, ">",
+ 0x221a, 0x250c, 0x2500, 0x2320, 0x2321, 0x2502, 0x2308, /* 21-27 */
+ 0x230a, 0x2309, 0x230b, 0x256d, 0x2570, 0x256e, 0x256f, 0x2525, /* 28-2f */
+ 0x251d, 0x2211, 0x2211, 0x2572, 0x2571, 0x231d, 0x231f, 0x232a, /* 30-37 */
+ 0x005b, 0x2022, 0x005d, 0x00b1, 0x2264, 0x2260, 0x2265, 0x222b, /* 38-3f */
+ 0x2234, 0x221d, 0x221e, 0x00f7, 0x25b3, 0x25bd, 0x03a6, 0x0393, /* 40-47 */
+ 0x223c, 0x2243, 0x0398, 0x00d7, 0x039b, 0x21d4, 0x21d2, 0x2261, /* 48-4f */
+ 0x220f, 0x03a8, 0x2218, 0x2211, 0x00a7, 0x00b6, 0x221a, 0x03a9, /* 50-57 */
+ 0x039e, 0x03d2, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 58-5f */
+ 0x00ac, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3, /* 60-67 */
+ 0x03b7, 0x03b9, 0x03b8, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x2202, /* 68-6f */
+ 0x03c0, 0x03c8, 0x03c1, 0x03c3, 0x03c4, 0x0020, 0x0192, 0x03c9, /* 70-77 */
+ 0x03be, 0x03c5, 0x03b6, 0x2190, 0x2191, 0x2192, 0x2193 /* 78-7e */
+};
+#endif /* KERMITFONT */
+
+#ifdef KERMITFONT
+struct x_to_unicode u_decspec = {
+ 94,33,X2U_DEC|X2U_STD,AL_ROMAN,"DEC Special Graphics","dec-special",0,"0",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x2666, 0x2591, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
+ 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23BA,
+ 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251c, 0x2524, 0x2534, 0x252c,
+ 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00B7
+};
+#else
+struct x_to_unicode u_decspec = {
+ 94,33,X2U_DEC|X2U_STD,AL_ROMAN,"DEC Special Graphics","dec-special",0,"0",
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x2666, 0x2591, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
+ 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2594,
+ 0x2500, 0x2500, 0x2500, 0x2500, 0x251c, 0x2524, 0x2534, 0x252c,
+ 0x2502, 0x2264, 0x2265, 0x03a0, 0x2260, 0x00a3, 0x00B7
+};
+#endif /* KERMITFONT */
+
+/*
+ Hazeltine 1500/1520 graphic set. Includes several approximations:
+ . (0,9) should be heavy black right arrow. Unicode has one of these
+ at U+27A1 but...
+ . (3,9) should be heavy black down arrow; Unicode doesn't have one.
+ So we use the white versions of the heavy arrows instead.
+ . (1,9) the letters "Pe" in one cell, doesn't exist in Unicode.
+ Substitution is just "P".
+*/
+struct x_to_unicode u_hz1500 = {
+ 94,33,X2U_STD,AL_ROMAN,"Hazeltime Graphics","hz1500-graphics",0,"0",
+/* 0 1 2 3 4 5 6 7 */
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, /* 0 */
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, /* 1 */
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, /* 2 */
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, /* 3 */
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, /* 4 */
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, /* 5 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, /* 6 */
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, /* 7 */
+ 0x2500, 0x2502, 0x253c, 0x2534, 0x252c, 0x2514, 0x250c, 0x00b1, /* 8 */
+ 0x21e8, 0x0050, 0x00f7, 0x21e9, 0x2510, 0x2518, 0x251c, 0x2524, /* 9 */
+ 0x0070, 0x0071, 0x0072, 0x250c, 0x0074, 0x0075, 0x0076, 0x0077, /* a */
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e /* b */
+
+};
+
+#ifdef KERMITFONT
+struct x_to_unicode u_heath19g = {
+ 94,33,X2U_STD,AL_ROMAN,"Heath-19 Special Graphics","h19-special",0,NULL,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x25cf, 0xe30b,
+ 0x2502, 0x2500, 0x253c, 0x2510, 0x2518, 0x2514, 0x250c, 0x00b1,
+ 0x2192, 0x2592, 0x00f7, 0x2193, 0xe321, 0xe320, 0xe322, 0xe328,
+ 0x2580, 0xe325, 0xe30a, 0x252c, 0x2524, 0x2534, 0x251c, 0x2573,
+ 0x2571, 0x2572, 0xe311, 0xe319, 0xe300, 0xe309, 0x00b6
+};
+#else
+struct x_to_unicode u_heath19g = {
+ 94,33,X2U_STD,AL_ROMAN,"Heath-19 Special Graphics","h19-special",0,NULL,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x25cf, 0x25e5,
+ 0x2502, 0x2500, 0x253c, 0x2510, 0x2518, 0x2514, 0x250c, 0x00b1,
+ 0x2192, 0x2592, 0x00f7, 0x2193, 0x2590, 0x258c, 0x258c, 0x2590,
+ 0x2580, 0x2590, 0x25e4, 0x252c, 0x2524, 0x2534, 0x251c, 0x2573,
+ 0x2571, 0x2572, 0x2500, 0x2500, 0x2502, 0x2502, 0x00b6
+};
+#endif /* KERMITFONT */
+
+/* DG Graphic sets - "KERMITFONT" these later... */
+
+/* Missing, backwards question mark
+ eighth note
+ "DT" control pic
+ horizontal scan lines
+*/
+struct x_to_unicode u_dgspec = { /* Needs to be checked */
+ 94, 33, X2U_STD,AL_ROMAN,"DG Special Graphics","dg-specialgraphics",0,NULL,
+ 0xfffd, 0xfffd, 0x2424, 0x2594, 0x2594, 0x2581, 0x2581,
+ 0x25a1, 0x263a, 0x263b, 0x2665, 0x2663, 0x2660, 0x25cf, 0x25d8,
+ 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266c, 0x263c, 0x2195,
+ 0x2583, 0x21a8, 0x231e, 0x2194, 0x2207, 0x00ff, 0x20a7, 0x00aa,
+ 0x00ba, 0x231c, 0x231d, 0x2591, 0x2591, 0x2593, 0x2561, 0x2562,
+ 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b,
+ 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550,
+ 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552,
+ 0x2553, 0x256b, 0x256a, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+ 0x0393, 0x03c0, 0x03a3, 0x03a6, 0x0398, 0x03d5, 0x03b5, 0x03a0,
+ 0x039e, 0x00b7, 0x03b7, 0x25a0, 0x0178, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd
+};
+
+/* Missing: arrow-to-line, various orientations */
+
+struct x_to_unicode u_dgline = {
+ 94, 33, X2U_STD,AL_ROMAN,"DG Line Drawing","dg-linedrawing",0,NULL,
+ 0x250c, 0x2510, 0x2514, 0x2518, 0x252c, 0x2524, 0x251c,
+ 0x2534, 0x253c, 0x2502, 0x2500, 0x219f, 0x21e5, 0x21e4, 0x21a1,
+ 0x2506, 0x250f, 0x2513, 0x2517, 0x251b, 0x2533, 0x252b, 0x2523,
+ 0x253b, 0x254b, 0x2503, 0x2501, 0x2504, 0x00f7, 0x00a2, 0x2122,
+ 0x00ae, 0x00a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd
+};
+
+struct x_to_unicode u_dgword = {
+ 94, 33, X2U_STD,AL_ROMAN,"DG Word Processing","dg-wordprocessing",0,NULL,
+ 0x2308, 0x230a, 0x2309, 0x230b, 0x0192, 0x223c, 0x2202,
+ 0xfffd, 0xfffd, 0x2320, 0x2321, 0x221a, 0xfffd, 0x221e, 0x221d,
+ 0x2070, 0x00b9, 0x00b2, 0x00b3, 0x2074, 0x2075, 0x2076, 0x2077,
+ 0x2078, 0x2079, 0x2260, 0xfffd, 0x21ef, 0xfffd, 0x21e5, 0x00b7,
+ 0x203c, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8,
+ 0x03c9, 0x03a9, 0x0394, 0x00b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x22a6, 0x25c6, 0x25b6, 0x25b7, 0x25c0, 0x25b2, 0x25bc, 0x2327,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x25e3, 0x25e2,
+ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+ 0x2088, 0x2089, 0xfffd, 0x2191, 0x2192, 0x2190, 0x2193
+};
+
+/* HP Graphic sets - "KERMITFONT" these later... */
+
+/*
+ Many are missing from Unicode,
+ Single-to-triple-line box-drawing characters.
+ Double/double cross & some others.
+*/
+struct x_to_unicode u_hpline = { /* Needs to be checked */
+ 94, 33, X2U_STD,AL_ROMAN,"HP Line Drawing Graphics",
+ "hp-line-drawing",0,NULL,
+ 0x2520, 0x2528, 0x252f, 0x2537, 0x255f, 0x2562, 0x2564,
+ 0x2567, 0x2551, 0x2542, 0x253f, 0x2550, 0x230a, 0x2502, 0x253c,
+ 0x254b, 0x2523, 0x252b, 0x2533, 0x253b, 0x251c, 0x2524, 0x252c,
+ 0x2534, 0x2550, 0x2503, 0x2501, 0x256b, 0x2308, 0x256a, 0x256c,
+ 0x255e, 0x2517, 0x2549, 0x2588, 0x258c, 0x258e, 0x2514, 0x2518,
+ 0x2510, 0x2555, 0x252c, 0x2556, 0x2556, 0x2547, 0x2548, 0x2555,
+ 0x230b, 0x250f, 0x250c, 0x251b, 0x2510, 0x2524, 0x254a, 0x2513,
+ 0x2584, 0x2309, 0x2582, 0x2561, 0x2504, 0x2559, 0x2576, 0x2565,
+ 0x255e, 0x2517, 0x2549, 0x2588, 0x258c, 0x258e, 0x2514, 0x2518,
+ 0x2510, 0x2555, 0x252c, 0x2556, 0x2556, 0x2547, 0x2548, 0x2555,
+ 0x230b, 0x250f, 0x250c, 0x251b, 0x2510, 0x2524, 0x254a, 0x2513,
+ 0x2584, 0x2309, 0x2582, 0x2561, 0x2504, 0x2559, 0x2576
+};
+
+struct x_to_unicode u_hpmath = {
+ 94, 33, X2U_STD,AL_ROMAN,"HP Math/Technical","hp-math/technical",0,NULL,
+ 0x221a, 0x2223, 0x00a7, 0x2207, 0x00b1, 0x03b1, 0x2320,
+ 0x00f7, 0x2243, 0x03a0, 0x0393, 0x03c8, 0x2261, 0x03a6, 0x039e,
+ 0x2070, 0x00b9, 0x00b2, 0x00b3, 0x2074, 0x2075, 0x2076, 0x2077,
+ 0x2078, 0x2079, 0x03a9, 0x039b, 0x221e, 0x2321, 0x2020, 0x03a3,
+ 0x00b6, 0x03b1, 0x03b2, 0x03c8, 0x03d5, 0x03b5, 0x2202, 0x03bb,
+ 0x03b7, 0x03b9, 0x0398, 0x03ba, 0x03c9, 0x03bc, 0x03bd, 0x03c1,
+ 0x03c0, 0x03b3, 0x03b8, 0x03c3, 0x03c4, 0x03be, 0x0394, 0x03b4,
+ 0x00d7, 0x03c5, 0x03b6, 0x2191, 0x2192, 0x03d2, 0x2190, 0x2193,
+ 0x00b6, 0x03b1, 0x03b2, 0x03c8, 0x03d5, 0x03b5, 0x2202, 0x03bb,
+ 0x03b7, 0x03b9, 0x0398, 0x03ba, 0x03c9, 0x03bc, 0x03bd, 0x03c1,
+ 0x03c0, 0x03b3, 0x03b8, 0x03c3, 0x03c4, 0x03be, 0x0394, 0x03b4,
+ 0x00d7, 0x03c5, 0x03b6, 0x2191, 0x2192, 0x03d2, 0x2190
+};
+
+struct x_to_unicode u_tvig = {
+ 15,65,0,0,"Televideo Special Graphics","tvi-special",0,NULL,
+ 0x2570, 0x256D, 0x256E, 0x256F, 0x2514, 0x250C, 0x2510,
+ 0x2518, 0x253C, 0x2502, 0x2500, 0x2524, 0x251C, 0x252C, 0x2534
+};
+
+struct x_to_unicode u_wyse_gn = {
+#ifdef COMMENT
+ 16,16,0,0,"Wyse Normal-Mode Graphics","wy-graphics-normal",0,NULL,
+ 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588,
+ 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591
+#else
+ 80,48,0,0,"Wyse Normal-Mode Graphics","wy-graphics-normal",0,NULL,
+ 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588,
+ 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591,
+ 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588,
+ 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591,
+ 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588,
+ 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591,
+ 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588,
+ 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591,
+ 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588,
+ 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591
+#endif /* COMMENT */
+};
+
+struct x_to_unicode u_wyse_g1 = {
+ 79,48,0,0,"Wyse Graphics 1","wy-graphics-1",0,NULL,
+ 0x2070, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2075, 0x2077,
+ 0x2078, 0x2079, 0xFFFD, 0xFFFD, 0x25BA, 0x25C4, 0x25B2, 0x25BC,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+ 0x2088, 0x2089, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x258C,
+ 0x2590, 0x2500, 0x2584, 0x2580, 0x251C, 0x2524, 0x2534, 0x252C,
+ 0x2502, 0xFFFD, 0x256E, 0x256F, 0x2570, 0x256D, 0x258C
+};
+
+struct x_to_unicode u_wyse_g2 = {
+ 41,64,0,0,"Wyse Graphics 2","wy-graphics-2",0,NULL,
+ 0x250C, 0xFFFD, 0xFFFD, 0xFFFD, 0x2510, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x2514, 0xFFFD, 0xFFFD, 0xFFFD, 0x2518, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x252C, 0xFFFD, 0xFFFD, 0xFFFD, 0x2524, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x251C, 0xFFFD, 0xFFFD, 0xFFFD, 0x2534, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x2500, 0xFFFD, 0xFFFD, 0xFFFD, 0x2502, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x253C
+};
+
+#ifdef KERMITFONT
+struct x_to_unicode u_wyse_g3 = {
+ 31,65,0,0,"Wyse Graphics 3","wy-graphics-3",0,NULL,
+ 0x2570, 0x256D, 0x256E, 0x256F, 0x2514, 0x250C, 0x2510,
+ 0x2518, 0x253C, 0x2502, 0x2500, 0x2524, 0x251C, 0x252C, 0x2534,
+ 0x23BA, 0x23BD, 0x2666, 0xE328, 0xE321, 0xE320, 0xE322, 0x2590,
+ 0x2584, 0x258C, 0x2580, 0xE323, 0xE326, 0xE327, 0xE329, 0x258C
+};
+#else
+struct x_to_unicode u_wyse_g3 = {
+ 31,65,0,0,"Wyse Graphics 3","wy-graphics-3",0,NULL,
+ 0x2570, 0x256D, 0x256E, 0x256F, 0x2514, 0x250C, 0x2510,
+ 0x2518, 0x253C, 0x2502, 0x2500, 0x2524, 0x251C, 0x252C, 0x2534,
+ 0x2500, 0x2500, 0x2666, 0x2590, 0x2590, 0x258c, 0x258c, 0x2590,
+ 0x2584, 0x258C, 0x2580, 0x2588, 0x2588, 0x2588, 0x2588, 0x258C
+};
+#endif /* KERMITFONT */
+/*
+ QNX Console -- This is exactly the same as CP437 except for the code
+ point at 0xEE (epsilon vs element-of), which I think was just a mistake
+ in reading glyphs by the QNX people, but who knows. Also the glyph at
+ 0xED might be a fi (as it is in CP437, and as I have it here) or it might
+ be a null-set symbol.
+*/
+struct x_to_unicode u_qnxgrph = {
+ 128,0,0,0,"QNX Console","qnx-console",0,NULL,
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, /* 128 */
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, /* 136 */
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, /* 144 */
+ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, /* 152 */
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, /* 160 */
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, /* 168 */
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, /* 176 */
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, /* 184 */
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, /* 192 */
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, /* 200 */
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, /* 208 */
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, /* 216 */
+ 0x221d, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, /* 224 */
+ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x2208, 0x2229, /* 232 */
+ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, /* 240 */
+ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25ae, 0x00a0 /* 248 */
+};
+
+struct x_to_unicode u_snibrack = {
+ 94, 33, 0, 0,"Siemens Nixdorf 97801 Brackets","sni-brackets",0,"w",
+ 0x2590, 0x258c, 0x2584, 0x2580, 0x2590, 0x258c, 0x2584, /* a0-7 */
+ 0x2580, 0x2329, 0x2327, 0x25af, 0x00b7, 0x25b9, 0x25c1, 0x003c, /* a8-f */
+ 0x253b, 0x2533, 0x2523, 0x252b, 0x2329, 0x232a, 0x2304, 0x2303, /* b0-7 */
+ 0x25e4, 0x25e5, 0x25e3, 0x25e2, 0x253f, 0x231b, 0x25cf, 0x25cb, /* b8-f */
+ 0x2502, 0x2500, 0x250c, 0x2510, 0x2514, 0x2518, 0x251c, 0x2524, /* c0-7 */
+ 0x252c, 0x2534, 0x253c, 0x2192, 0x2190, 0x2191, 0x2193, 0x2575, /* c8-f */
+ 0x2577, 0x25d4, 0x256d, 0x256e, 0x2570, 0x256f, 0x251c, 0x2524, /* d0-7 */
+ 0x252c, 0x2534, 0x253c, 0x253c, 0x2592, 0x2591, 0x2592, 0x2593, /* d8-f */
+ 0x2503, 0x2501, 0x250f, 0x2513, 0x2517, 0x251b, 0x2523, 0x252b, /* e0-7 */
+ 0x2533, 0x253b, 0x254b, 0x279e, 0x2190, 0x2191, 0x2193, 0x2579, /* e8-f */
+ 0x257b, 0x2261, 0x2554, 0x2557, 0x255a, 0x255d, 0x2523, 0x252b, /* f0-7 */
+ 0x2533, 0x253b, 0x254b, 0x254b, 0x0393, 0x03c3, 0x03c4 /* f8-f */
+};
+
+struct x_to_unicode u_sniblanks = {
+ 94, 33, 0, 0,"Siemens Nixdorf 97801 Blanks","sni-blanks",0,"y",
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* a0-7 */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* a8-f */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* b0-7 */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* b8-f */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* c0-7 */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* c8-f */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* d0-7 */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* d8-f */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* e0-7 */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* e8-f */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* f0-7 */
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 /* f8-f */
+};
+
+struct x_to_unicode u_snifacet = {
+ 94, 33, 0, 0,"Siemens Nixdorf 97801 Facet","sni-facet",0,"c",
+ 0x0020, 0x2581, 0x2582, 0x2583, 0x2584, 0x2585, 0x2587, /* a1-a7 */
+ 0x005f, 0x2581, 0x2582, 0x2583, 0x2584, 0x2585, 0x2586, 0x2587, /* a8-af */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* b0-b7 */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* b8-bf */
+ 0x2503, 0x2501, 0x250f, 0x2513, 0x2517, 0x251b, 0x2523, 0x252b, /* c0-c7 */
+ 0x2533, 0x253b, 0x254b, 0x258f, 0x2595, 0xfffd, 0xfffd, 0xfffd, /* c8-cf */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* d0-d7 */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2591, 0x2591, 0x2588, /* d8-df */
+ 0x2503, 0x2501, 0x250f, 0x2513, 0x2517, 0x251b, 0x2523, 0x252b, /* e0-e7 */
+ 0x2533, 0x253b, 0x254b, 0xfffd, 0xfffd, 0x2593, 0x2593, 0x0020, /* e8-ef */
+ 0x2585, 0x2586, 0x2587, 0x2588, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* f0-f7 */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2594, 0x2594, 0xfffd /* f8-fe */
+};
+
+struct x_to_unicode u_sniibm = {
+ 94, 33, 0, 0,"Siemens Nixdorf 97801 IBM","sni-ibm",0,"v",
+ 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x25cf,
+ 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
+ 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x25c1, 0x2582, 0x21a8,
+ 0x2191, 0x2193, 0x2192, 0x2190, 0x2319, 0x2194, 0x25b4, 0x25be,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* Hex */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* bytes */
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0x2070, 0x00b9, 0x00b2, 0x00b3, 0x2074, 0x2075, 0x2076, 0x2077,
+ 0x2078, 0x2079, 0x207b, 0x207a, 0xfffd, 0xfffd, 0x2320, 0x2321,
+ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+ 0x2088, 0x2089, 0x208b, 0x208a, 0x221e, 0x03b1, 0x03a6
+};
+
+struct x_to_unicode u_snieuro = {
+ 94, 33, 0, 0,"Siemens Nixdorf 97801 Euro","sni-euro",0,"u",
+ 0x00e0, 0x00e1, 0x00e2, 0x00e4, 0x00e5, 0x0105, 0x00e3,
+ 0x0103, 0x00e6, 0x00e7, 0x010d, 0x0107, 0x00f0, 0x0111, 0x010f,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x011b, 0x0119, 0x011f, 0x0131,
+ 0x00ee, 0x00ec, 0x01d0, 0x00ef, 0x0133, 0x013a, 0x0142, 0x013e,
+ 0x0148, 0x0144, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f6, 0x00f5,
+ 0x00f8, 0x0151, 0x0153, 0x00fe, 0x0159, 0x0155, 0x0161, 0x015b,
+ 0x015f, 0x00df, 0x0163, 0x0165, 0x00f9, 0x00fa, 0x00fb, 0x00fc,
+ 0x016f, 0x0171, 0x00fd, 0x00ff, 0x017e, 0x017a, 0x017c, 0x00c9,
+ 0x00c5, 0x00c6, 0x00d0, 0x0130, 0x0132, 0x0167, 0x00d8, 0x0152,
+ 0x00de, 0x00c4, 0x00d6, 0x00dc, 0x00a7, 0x0024, 0x00a3, 0x00ae,
+ 0x00a9, 0x03a9, 0x00b5, 0x00b0, 0x00c7, 0x20a7, 0x03c0, 0x02d8,
+ 0x00b4, 0x02dd, 0x00d1, 0x2514, 0x2518, 0x007e, 0x02c7
+};
+
+struct x_to_unicode u_smiley = {
+ 32,0,X2U_CXG,0,"PC C0 Graphics","smiley-faces",0,NULL,
+ 0x00a0, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
+ 0x25d8, 0x25ef, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266c, 0x263c,
+ 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
+ 0x2191, 0x2193, 0x2192, 0x2190, 0x2319, 0x2194, 0x25b2, 0x25bc
+};
+
+struct x_to_unicode u_c0pics = {
+ 128,0,X2U_CXG,0,"C0/C1 Display Controls","display-controls",0,NULL,
+ 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407,
+ 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f,
+ 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417,
+ 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f,
+ 0x2420, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2421
+};
+
+#ifdef KERMITFONT
+struct x_to_unicode u_c1pics = {
+ 32,0,X2U_CXG,0,"C1 Display Controls","c1-display-controls",0,NULL,
+ 0xe080, 0xe081, 0xe082, 0xe083, 0xe084, 0xe085, 0xe086, 0xe087,
+ 0xe088, 0xe089, 0xe08a, 0xe08b, 0xe08c, 0xe08d, 0xe08e, 0xe08f,
+ 0xe090, 0xe091, 0xe092, 0xe093, 0xe094, 0xe095, 0xe096, 0xe097,
+ 0xe098, 0xe099, 0xe09a, 0xe09b, 0xe09c, 0xe09d, 0xe09e, 0xe09f
+};
+#else
+struct x_to_unicode u_c1pics = {
+ 32,0,X2U_CXG,0,"C1 Display Controls","c1-display-controls",0,NULL,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd
+};
+#endif /* KERMITFONT */
+
+
+/* Blah-to-Unicode functions */
+
+USHORT
+#ifdef CK_ANSIC
+ascii_u(CHAR c)
+#else
+ascii_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+/*
+ NOTE: Strict ANSI compilers complain about "<" and similar comparisons
+ between unsigned and signed quantities, as found in all the routines of
+ the "blah_u()" class -- casts must be added to squelch the warnings.
+*/
+ if (c < u_ascii.offset)
+ return(c);
+ else if (c >= u_ascii.offset + u_ascii.size)
+ return(c);
+ else
+ return(u_ascii.map[c - u_ascii.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+british_u(CHAR c)
+#else
+british_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_british.offset)
+ return(c);
+ else if (c >= u_british.offset + u_british.size)
+ return(c);
+ else
+ return(u_british.map[c - u_british.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+dutch_u(CHAR c)
+#else
+dutch_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_dutch.offset)
+ return(c);
+ else if (c >= u_dutch.offset + u_dutch.size)
+ return(c);
+ else
+ return(u_dutch.map[c - u_dutch.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+finnish_u(CHAR c)
+#else
+finnish_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_finnish.offset)
+ return(c);
+ else if (c >= u_finnish.offset + u_finnish.size)
+ return(c);
+ else
+ return(u_finnish.map[c - u_finnish.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+french_u(CHAR c)
+#else
+french_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_french.offset)
+ return(c);
+ else if (c >= u_french.offset + u_french.size)
+ return(c);
+ else
+ return(u_french.map[c - u_french.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+fr_canadian_u(CHAR c)
+#else
+fr_canadian_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_fr_canadian.offset)
+ return(c);
+ else if (c >= u_fr_canadian.offset + u_fr_canadian.size)
+ return(c);
+ else
+ return(u_fr_canadian.map[c - u_fr_canadian.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+german_u(CHAR c)
+#else
+german_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_german.offset)
+ return(c);
+ else if (c >= u_german.offset + u_german.size)
+ return(c);
+ else
+ return(u_german.map[c - u_german.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+hungarian_u(CHAR c)
+#else
+hungarian_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_hungarian.offset)
+ return(c);
+ else if (c >= u_hungarian.offset + u_hungarian.size)
+ return(c);
+ else
+ return(u_hungarian.map[c - u_hungarian.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+italian_u(CHAR c)
+#else
+italian_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_italian.offset)
+ return(c);
+ else if (c >= u_italian.offset + u_italian.size)
+ return(c);
+ else
+ return(u_italian.map[c - u_italian.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+icelandic_u(CHAR c)
+#else
+icelandic_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_icelandic.offset)
+ return(c);
+ else if (c >= u_icelandic.offset + u_icelandic.size)
+ return(c);
+ else
+ return(u_icelandic.map[c - u_icelandic.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+jis0201r_u(CHAR c)
+#else
+jis0201r_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_jis0201r.offset)
+ return(c);
+ else if (c >= u_jis0201r.offset + u_jis0201r.size)
+ return(c);
+ else
+ return(u_jis0201r.map[c - u_jis0201r.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+jis0201k_u(CHAR c)
+#else
+jis0201k_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_jis0201k.offset)
+ return(c);
+ else if (c >= u_jis0201k.offset + u_jis0201k.size)
+ return(c);
+ else
+ return(u_jis0201k.map[c - u_jis0201k.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+norwegian_u(CHAR c)
+#else
+norwegian_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_norwegian.offset)
+ return(c);
+ else if (c >= u_norwegian.offset + u_norwegian.size)
+ return(c);
+ else
+ return(u_norwegian.map[c - u_norwegian.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+danish_u(CHAR c)
+#else
+danish_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_danish.offset)
+ return(c);
+ else if (c >= u_danish.offset + u_danish.size)
+ return(c);
+ else
+ return(u_danish.map[c - u_danish.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+portuguese_u(CHAR c)
+#else
+portuguese_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_portuguese.offset)
+ return(c);
+ else if (c >= u_portuguese.offset + u_portuguese.size)
+ return(c);
+ else
+ return(u_portuguese.map[c - u_portuguese.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+spanish_u(CHAR c)
+#else
+spanish_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_spanish.offset)
+ return(c);
+ else if (c >= u_spanish.offset + u_spanish.size)
+ return(c);
+ else
+ return(u_spanish.map[c - u_spanish.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+swedish_u(CHAR c)
+#else
+swedish_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_swedish.offset)
+ return(c);
+ else if (c >= u_swedish.offset + u_swedish.size)
+ return(c);
+ else
+ return(u_swedish.map[c - u_swedish.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+swiss_u(CHAR c)
+#else
+swiss_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_swiss.offset)
+ return(c);
+ else if (c >= u_swiss.offset + u_swiss.size)
+ return(c);
+ else
+ return(u_swiss.map[c - u_swiss.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+apl1_u(CHAR c)
+#else
+apl1_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_apl1.offset)
+ return(c);
+ else if (c >= u_apl1.offset + u_apl1.size)
+ return(c);
+ else
+ return(u_apl1.map[c - u_apl1.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+ident_u(CHAR c)
+#else /* CK_ANSIC */
+ident_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return((USHORT)c);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_1_u(CHAR c)
+#else
+iso_8859_1_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_1.offset)
+ return(c);
+ else if (c >= u_8859_1.offset + u_8859_1.size)
+ return(c);
+ else
+ return(u_8859_1.map[c - u_8859_1.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_2_u(CHAR c)
+#else
+iso_8859_2_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_2.offset)
+ return(c);
+ else if (c >= u_8859_2.offset + u_8859_2.size)
+ return(c);
+ else
+ return(u_8859_2.map[c - u_8859_2.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_3_u(CHAR c)
+#else
+iso_8859_3_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_3.offset)
+ return(c);
+ else if (c >= u_8859_3.offset + u_8859_3.size)
+ return(c);
+ else
+ return(u_8859_3.map[c - u_8859_3.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_4_u(CHAR c)
+#else
+iso_8859_4_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_4.offset)
+ return(c);
+ else if (c >= u_8859_4.offset + u_8859_4.size)
+ return(c);
+ else
+ return(u_8859_4.map[c - u_8859_4.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_5_u(CHAR c)
+#else
+iso_8859_5_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_5.offset)
+ return(c);
+ else if (c >= u_8859_5.offset + u_8859_5.size)
+ return(c);
+ else
+ return(u_8859_5.map[c - u_8859_5.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+koi8_u(CHAR c)
+#else
+koi8_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_koi8.offset)
+ return(c);
+ else if (c >= u_koi8.offset + u_koi8.size)
+ return(c);
+ else
+ return(u_koi8.map[c - u_koi8.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+koi8r_u(CHAR c) /* KOI8-R to Unicode */
+#else
+koi8r_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_koi8r.offset)
+ return(c);
+ else if (c >= u_koi8r.offset + u_koi8r.size)
+ return(c);
+ else
+ return(u_koi8r.map[c - u_koi8r.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+koi8u_u(CHAR c)
+#else
+koi8u_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_koi8u.offset)
+ return(c);
+ else if (c >= u_koi8u.offset + u_koi8u.size)
+ return(c);
+ else
+ return(u_koi8u.map[c - u_koi8u.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_6_u(CHAR c)
+#else
+iso_8859_6_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_6.offset)
+ return(c);
+ else if (c >= u_8859_6.offset + u_8859_6.size)
+ return(c);
+ else
+ return(u_8859_6.map[c - u_8859_6.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_7_u(CHAR c)
+#else
+iso_8859_7_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_7.offset)
+ return(c);
+ else if (c >= u_8859_7.offset + u_8859_7.size)
+ return(c);
+ else
+ return(u_8859_7.map[c - u_8859_7.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_8_u(CHAR c)
+#else
+iso_8859_8_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_8.offset)
+ return(c);
+ else if (c >= u_8859_8.offset + u_8859_8.size)
+ return(c);
+ else
+ return(u_8859_8.map[c - u_8859_8.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+hebrew7_u(CHAR c)
+#else
+hebrew7_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_hebrew7.offset)
+ return(c);
+ else if (c >= u_hebrew7.offset + u_hebrew7.size)
+ return(c);
+ else
+ return(u_hebrew7.map[c - u_hebrew7.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+elot927_u(CHAR c)
+#else
+elot927_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_elot927.offset)
+ return(c);
+ else if (c >= u_elot927.offset + u_elot927.size)
+ return(c);
+ else
+ return(u_elot927.map[c - u_elot927.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_9_u(CHAR c)
+#else
+iso_8859_9_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_9.offset)
+ return(c);
+ else if (c >= u_8859_9.offset + u_8859_9.size)
+ return(c);
+ else
+ return(u_8859_9.map[c - u_8859_9.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_10_u(CHAR c)
+#else
+iso_8859_10_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_10.offset)
+ return(c);
+ else if (c >= u_8859_10.offset + u_8859_10.size)
+ return(c);
+ else
+ return(u_8859_10.map[c - u_8859_10.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+iso_8859_15_u(CHAR c)
+#else
+iso_8859_15_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_8859_15.offset)
+ return(c);
+ else if (c >= u_8859_15.offset + u_8859_15.size)
+ return(c);
+ else
+ return(u_8859_15.map[c - u_8859_15.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+apl2_u(CHAR c)
+#else
+apl2_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_apl2.offset)
+ return(c);
+ else if (c >= u_apl2.offset + u_apl2.size)
+ return(c);
+ else
+ return(u_apl2.map[c - u_apl2.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+apl3_u(CHAR c)
+#else
+apl3_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_apl3.offset)
+ return(c);
+ else if (c >= u_apl3.offset + u_apl3.size)
+ return(c);
+ else
+ return(u_apl3.map[c - u_apl3.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+apl4_u(CHAR c)
+#else
+apl4_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_apl4.offset)
+ return(c);
+ else if (c >= u_apl4.offset + u_apl4.size)
+ return(c);
+ else
+ return(u_apl4.map[c - u_apl4.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+apl5_u(CHAR c)
+#else
+apl5_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_apl5.offset)
+ return(c);
+ else if (c >= u_apl5.offset + u_apl5.size)
+ return(c);
+ else
+ return(u_apl5.map[c - u_apl5.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+koi7_u(CHAR c)
+#else
+koi7_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0x80)
+ return(UNK);
+ if (c < u_koi7.offset)
+ return(c);
+ else if (c >= u_koi7.offset + u_koi7.size)
+ return(c);
+ else
+ return(u_koi7.map[c - u_koi7.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+decmcs_u(CHAR c)
+#else
+decmcs_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ c &= 0x7f;
+ if (c < u_decmcs.offset)
+ return(c);
+ else if (c >= u_decmcs.offset + u_decmcs.size)
+ return(c);
+ else
+ return(u_decmcs.map[c - u_decmcs.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+nextstep_u(CHAR c)
+#else
+nextstep_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_nextstep.map[(c & 0x7f) - u_nextstep.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+dgi_u(CHAR c)
+#else
+dgi_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ return(u_dgi.map[(c & 0x7f) - u_dgi.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+hproman8_u(CHAR c)
+#else
+hproman8_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x80 && c < 0xa0)
+ return(c);
+ return(u_hproman8.map[(c & 0x7f) - u_hproman8.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp37_u(CHAR c)
+#else
+cp37_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp37.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp437_u(CHAR c)
+#else
+cp437_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp437.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+mazovia_u(CHAR c) /* Mazovia = CP437 with substitutions */
+#else
+mazovia_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_mazovia.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp850_u(CHAR c)
+#else
+cp850_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp850.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp858_u(CHAR c)
+#else
+cp858_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp858.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1250_u(CHAR c)
+#else
+cp1250_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1250.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1251_u(CHAR c)
+#else
+cp1251_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1251.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1252_u(CHAR c)
+#else
+cp1252_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1252.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1253_u(CHAR c)
+#else
+cp1253_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1253.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1254_u(CHAR c)
+#else
+cp1254_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1254.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1255_u(CHAR c)
+#else
+cp1255_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1255.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1256_u(CHAR c)
+#else
+cp1256_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1256.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1257_u(CHAR c)
+#else
+cp1257_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1257.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp1258_u(CHAR c)
+#else
+cp1258_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp1258.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp852_u(CHAR c)
+#else
+cp852_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp852.map[c & 0x7f]);
+}
+
+USHORT /* Cyrillic */
+#ifdef CK_ANSIC
+cp855_u(CHAR c)
+#else
+cp855_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp855.map[c & 0x7f]);
+}
+
+USHORT /* Bulgaria */
+#ifdef CK_ANSIC
+cp856_u(CHAR c)
+#else
+cp856_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp856.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp857_u(CHAR c)
+#else
+cp857_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp857.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp862_u(CHAR c)
+#else
+cp862_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp862.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp864_u(CHAR c)
+#else
+cp864_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp864.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp866_u(CHAR c)
+#else
+cp866_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp866.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+cp869_u(CHAR c)
+#else
+cp869_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_cp869.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+maclatin_u(CHAR c)
+#else
+maclatin_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_maclatin.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+quickdraw_u(CHAR c)
+#else
+quickdraw_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ return(u_quickdraw.map[c & 0x7f]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+decspec_u(CHAR c)
+#else
+decspec_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_decspec.offset)
+ return(c);
+ else if (c >= u_decspec.offset + u_decspec.size)
+ return(c);
+ else
+ return (u_decspec.map[c - u_decspec.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+dectech_u(CHAR c)
+#else
+dectech_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_dectech.offset)
+ return(c);
+ else if (c >= u_dectech.offset + u_dectech.size)
+ return(c);
+ else
+ return(u_dectech.map[c - u_dectech.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+dgspec_u(CHAR c)
+#else
+dgspec_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_dgspec.offset)
+ return(c);
+ else if (c >= u_dgspec.offset + u_dgspec.size)
+ return(c);
+ else
+ return(u_dgspec.map[c - u_dgspec.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+dgline_u(CHAR c)
+#else
+dgline_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_dgline.offset)
+ return(c);
+ else if (c >= u_dgline.offset + u_dgline.size)
+ return(c);
+ else
+ return(u_dgline.map[c - u_dgline.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+dgword_u(CHAR c)
+#else
+dgword_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_dgword.offset)
+ return(c);
+ else if (c >= u_dgword.offset + u_dgword.size)
+ return(c);
+ else
+ return(u_dgword.map[c - u_dgword.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+hpline_u(CHAR c)
+#else
+hpline_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_hpline.offset)
+ return(c);
+ else if (c >= u_hpline.offset + u_hpline.size)
+ return(c);
+ else
+ return(u_hpline.map[c - u_hpline.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+hpmath_u(CHAR c)
+#else
+hpmath_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_hpmath.offset)
+ return(c);
+ else if (c >= u_hpmath.offset + u_hpmath.size)
+ return(c);
+ else
+ return(u_hpmath.map[c - u_hpmath.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+qnxgrph_u(CHAR c)
+#else
+qnxgrph_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_qnxgrph.offset)
+ return(c);
+ else if (c >= u_qnxgrph.offset + u_qnxgrph.size)
+ return(c);
+ else
+ return(u_qnxgrph.map[c - u_qnxgrph.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+hz1500_u(CHAR c)
+#else
+hz1500_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_hz1500.offset)
+ return(c);
+ else if (c >= u_hz1500.offset + u_hz1500.size)
+ return(c);
+ else
+ return(u_hz1500.map[c - u_hz1500.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+sniblanks_u(CHAR c)
+#else
+sniblanks_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_sniblanks.offset)
+ return(c);
+ else if (c >= u_sniblanks.offset + u_sniblanks.size)
+ return(c);
+ else
+ return(u_sniblanks.map[c - u_sniblanks.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+snibrack_u(CHAR c)
+#else
+snibrack_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_snibrack.offset)
+ return(c);
+ else if (c >= u_snibrack.offset + u_snibrack.size)
+ return(c);
+ else
+ return(u_snibrack.map[c - u_snibrack.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+snifacet_u(CHAR c)
+#else
+snifacet_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_snifacet.offset)
+ return(c);
+ else if (c >= u_snifacet.offset + u_snifacet.size)
+ return(c);
+ else
+ return(u_snifacet.map[c - u_snifacet.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+sniibm_u(CHAR c)
+#else
+sniibm_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_sniibm.offset)
+ return(c);
+ else if (c >= u_sniibm.offset + u_sniibm.size)
+ return(c);
+ else
+ return(u_sniibm.map[c - u_sniibm.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+snieuro_u(CHAR c)
+#else
+snieuro_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_snieuro.offset)
+ return(c);
+ else if (c >= u_snieuro.offset + u_snieuro.size)
+ return(c);
+ else
+ return(u_snieuro.map[c - u_snieuro.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+heath19g_u(CHAR c)
+#else
+heath19g_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_heath19g.offset)
+ return(c);
+ else if (c >= u_heath19g.offset + u_heath19g.size)
+ return(c);
+ else
+ return(u_heath19g.map[c - u_heath19g.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+tvig_u(CHAR c)
+#else
+tvig_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_tvig.offset)
+ return(c);
+ else if (c >= u_tvig.offset + u_tvig.size)
+ return(c);
+ else
+ return(u_tvig.map[c - u_tvig.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+wyse_gn_u(CHAR c)
+#else
+wyse_gn_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_wyse_gn.offset)
+ return(c);
+ else if (c >= u_wyse_gn.offset + u_wyse_gn.size)
+ return(c);
+ else
+ return(u_wyse_gn.map[c - u_wyse_gn.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+wyse_g1_u(CHAR c)
+#else
+wyse_g1_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_wyse_g1.offset)
+ return(c);
+ else if (c >= u_wyse_g1.offset + u_wyse_g1.size)
+ return(c);
+ else
+ return(u_wyse_g1.map[c - u_wyse_g1.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+wyse_g2_u(CHAR c)
+#else
+wyse_g2_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_wyse_g2.offset)
+ return(c);
+ else if (c >= u_wyse_g2.offset + u_wyse_g2.size)
+ return(c);
+ else
+ return(u_wyse_g2.map[c - u_wyse_g2.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+wyse_g3_u(CHAR c)
+#else
+wyse_g3_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_wyse_g3.offset)
+ return(c);
+ else if (c >= u_wyse_g3.offset + u_wyse_g3.size)
+ return(c);
+ else
+ return(u_wyse_g3.map[c - u_wyse_g3.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+smiley_u(CHAR c)
+#else
+smiley_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_smiley.offset)
+ return(c);
+ else if (c >= u_smiley.offset + u_smiley.size)
+ return(c);
+ else
+ return(u_smiley.map[c - u_smiley.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+c0pics_u(CHAR c)
+#else
+c0pics_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_c0pics.offset)
+ return(c);
+ else if (c >= u_c0pics.offset + u_c0pics.size)
+ return(c);
+ else
+ return(u_c0pics.map[c - u_c0pics.offset]);
+}
+
+USHORT
+#ifdef CK_ANSIC
+c1pics_u(CHAR c)
+#else
+c1pics_u(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ c &= 0x7f;
+ if (c < u_c1pics.offset)
+ return(c);
+ else if (c >= u_c1pics.offset + u_c1pics.size)
+ return(c);
+ else
+ return(u_c1pics.map[c - u_c1pics.offset]);
+}
+
+#ifdef KANJI /* Kanji/Unicode functions */
+
+static long /* Statistics counters */
+ bad = 0, /* REMOVE THESE LATER... */
+ kanji = 0,
+ kana = 0,
+ greek = 0,
+ cyrillic = 0,
+ special = 0,
+ roman = 0;
+
+USHORT
+#ifdef CK_ANSIC
+sj_to_un(USHORT sj) /* Shift-JIS to Unicode */
+#else
+sj_to_un(sj) USHORT sj;
+#endif /* CK_ANSIC */
+{
+
+/* Kanji blocks */
+
+ if (sj >= 0x8140) { /* All possible Kanjis */
+ kanji++; /* Optimistically count a Kanji */
+ if (sj <= 0x9ffc) { /* 7869-element table */
+ return(sju_8140[sj - 0x8140]);
+ } else if (sj >= 0xe040 && sj <= 0xeaa4) { /* 2660-element table */
+ return(sju_e040[sj - 0xe040]);
+ } else if (sj >= 0xf040) { /* User-defined areas */
+ if (sj <= 0xf0fc) { /* ten 189-char chunks */
+ return(0xe000 + (sj - 0xf040));
+ } else if (sj >= 0xf140 && sj <= 0xf1fc) {
+ return(0xe0bc + (sj - 0xf140));
+ } else if (sj >= 0xf240 && sj <= 0xf2fc) {
+ return(0xe178 + (sj - 0xf240));
+ } else if (sj >= 0xf340 && sj <= 0xf3fc) {
+ return(0xe234 + (sj - 0xf340));
+ } else if (sj >= 0xf440 && sj <= 0xf4fc) {
+ return(0xe2f0 + (sj - 0xf440));
+ } else if (sj >= 0xf540 && sj <= 0xf5fc) {
+ return(0xe3ac + (sj - 0xf540));
+ } else if (sj >= 0xf640 && sj <= 0xf6fc) {
+ return(0xe468 + (sj - 0xf640));
+ } else if (sj >= 0xf740 && sj <= 0xf7fc) {
+ return(0xe524 + (sj - 0xf740));
+ } else if (sj >= 0xf840 && sj <= 0xf8fc) {
+ return(0xe5e0 + (sj - 0xf840));
+ } else if (sj >= 0xf940 && sj <= 0xf9fc) {
+ return(0xe69c + (sj - 0xf940));
+ }
+ }
+ kanji--; /* None of the above, uncount */
+ }
+
+/* C0 / Halfwidth-Roman / C1 block (0x00-0x9f, no holes) */
+
+ else if (sj < 0x00a0) {
+ roman++; /* Count a Roman */
+ if (sj == 0x5c) { /* Yen sign */
+ return(0x00a5);
+ } else if (sj == 0x7e) { /* Overline (macron) */
+ return(0x203e);
+ } else { /* Control or Halfwidth Roman */
+ return(sj);
+ }
+ }
+
+/* Halfwidth Katakana block (0xa0-0xdf, no holes) */
+
+ else if (sj >= 0xa1 && sj <= 0xdf) {
+ kana++;
+ return(sj + 0xfec0);
+ }
+
+/* Catch-all must be final */
+
+ bad++;
+ return(0xfffd);
+}
+
+USHORT
+#ifdef CK_ANSIC
+un_to_sj(USHORT un) /* Unicode to Shift-JIS */
+#else
+un_to_sj(un) USHORT un;
+#endif /* CK_ANSIC */
+{
+
+ if (un < 0x00a0) {
+ switch (un) {
+ case 0x005c: roman++; return(0x815f); /* Backslash */
+ case 0x007e: bad++; return(0xfffd); /* No tilde in Shift-JIS */
+ default: /* ASCII or C0/C1 control */
+ roman++;
+ return(un);
+ }
+ }
+ if (un >= 0x00a0 && un < 0x0391) { /* Latin-1 symbols */
+ roman++;
+ switch(un) {
+ case 0x00A2: return(0x8191);
+ case 0x00A3: return(0x8192);
+ case 0x00A5: return(0x005C); /* Yen */
+ case 0x00A7: return(0x8198);
+ case 0x00A8: return(0x814E);
+ case 0x00AC: return(0x81CA);
+ case 0x00B0: return(0x818B);
+ case 0x00B1: return(0x817D);
+ case 0x00B4: return(0x814C);
+ case 0x00B6: return(0x81F7);
+ case 0x00D7: return(0x817E);
+ case 0x00F7: return(0x8180);
+ default:
+ roman--;
+ bad++;
+ return(0xfffd);
+ }
+ }
+ if (un >= 0x0391 && un < 0x0401) { /* Greek */
+ greek++;
+ if (un <= 0x039c)
+ return(usj_0391[un-0x0391]);
+ greek--;
+ bad++;
+ return(0xfffd);
+ }
+ if (un >= 0x0401 && un < 0x2010) { /* Cyrillic */
+ cyrillic++;
+ if (un <= 0x0451)
+ return(usj_0401[un-0x0401]);
+ cyrillic--;
+ bad++;
+ return(0xfffd);
+ }
+ if (un >= 0x2010 && un < 0x2500) { /* General punctuation */
+ special++;
+ switch(un) {
+ case 0x2010: return(0x815D);
+ case 0x2015: return(0x815C);
+ case 0x2016: return(0x8161);
+ case 0x2018: return(0x8165);
+ case 0x2019: return(0x8166);
+ case 0x201C: return(0x8167);
+ case 0x201D: return(0x8168);
+ case 0x2020: return(0x81F5);
+ case 0x2021: return(0x81F6);
+ case 0x2025: return(0x8164);
+ case 0x2026: return(0x8163);
+ case 0x2030: return(0x81F1);
+ case 0x2032: return(0x818C);
+ case 0x2033: return(0x818D);
+ case 0x203B: return(0x81A6);
+ case 0x203E: return(0x007E);
+ case 0x2103: return(0x818E); /* Letterlike symbols */
+ case 0x212B: return(0x81F0);
+ case 0x2190: return(0x81A9); /* Arrows */
+ case 0x2191: return(0x81AA);
+ case 0x2192: return(0x81A8);
+ case 0x2193: return(0x81AB);
+ case 0x21D2: return(0x81CB);
+ case 0x21D4: return(0x81CC);
+ case 0x2200: return(0x81CD); /* Math */
+ case 0x2202: return(0x81DD);
+ case 0x2203: return(0x81CE);
+ case 0x2207: return(0x81DE);
+ case 0x2208: return(0x81B8);
+ case 0x220B: return(0x81B9);
+ case 0x2212: return(0x817C);
+ case 0x221A: return(0x81E3);
+ case 0x221D: return(0x81E5);
+ case 0x221E: return(0x8187);
+ case 0x2220: return(0x81DA);
+ case 0x2227: return(0x81C8);
+ case 0x2228: return(0x81C9);
+ case 0x2229: return(0x81BF);
+ case 0x222A: return(0x81BE);
+ case 0x222B: return(0x81E7);
+ case 0x222C: return(0x81E8);
+ case 0x2234: return(0x8188);
+ case 0x2235: return(0x81E6);
+ case 0x223D: return(0x81E4);
+ case 0x2252: return(0x81E0);
+ case 0x2260: return(0x8182);
+ case 0x2261: return(0x81DF);
+ case 0x2266: return(0x8185);
+ case 0x2267: return(0x8186);
+ case 0x226A: return(0x81E1);
+ case 0x226B: return(0x81E2);
+ case 0x2282: return(0x81BC);
+ case 0x2283: return(0x81BD);
+ case 0x2286: return(0x81BA);
+ case 0x2287: return(0x81BB);
+ case 0x22A5: return(0x81DB);
+ case 0x2312: return(0x81DC); /* Arc */
+ default:
+ special--;
+ bad++;
+ return(0xfffd);
+ }
+ }
+ if (un >= 0x2500 && un < 0x3000) { /* Box drawing */
+ special++;
+ switch(un) {
+ case 0x2500: return(0x849F);
+ case 0x2501: return(0x84AA);
+ case 0x2502: return(0x84A0);
+ case 0x2503: return(0x84AB);
+ case 0x250C: return(0x84A1);
+ case 0x250F: return(0x84AC);
+ case 0x2510: return(0x84A2);
+ case 0x2513: return(0x84AD);
+ case 0x2514: return(0x84A4);
+ case 0x2517: return(0x84AF);
+ case 0x2518: return(0x84A3);
+ case 0x251B: return(0x84AE);
+ case 0x251C: return(0x84A5);
+ case 0x251D: return(0x84BA);
+ case 0x2520: return(0x84B5);
+ case 0x2523: return(0x84B0);
+ case 0x2524: return(0x84A7);
+ case 0x2525: return(0x84BC);
+ case 0x2528: return(0x84B7);
+ case 0x252B: return(0x84B2);
+ case 0x252C: return(0x84A6);
+ case 0x252F: return(0x84B6);
+ case 0x2530: return(0x84BB);
+ case 0x2533: return(0x84B1);
+ case 0x2534: return(0x84A8);
+ case 0x2537: return(0x84B8);
+ case 0x2538: return(0x84BD);
+ case 0x253B: return(0x84B3);
+ case 0x253C: return(0x84A9);
+ case 0x253F: return(0x84B9);
+ case 0x2542: return(0x84BE);
+ case 0x254B: return(0x84B4);
+ case 0x25A0: return(0x81A1); /* Geometric shapes */
+ case 0x25A1: return(0x81A0);
+ case 0x25B2: return(0x81A3);
+ case 0x25B3: return(0x81A2);
+ case 0x25BC: return(0x81A5);
+ case 0x25BD: return(0x81A4);
+ case 0x25C6: return(0x819F);
+ case 0x25C7: return(0x819E);
+ case 0x25CB: return(0x819B);
+ case 0x25CE: return(0x819D);
+ case 0x25CF: return(0x819C);
+ case 0x25EF: return(0x81FC);
+ case 0x2605: return(0x819A); /* Misc symbols */
+ case 0x2606: return(0x8199);
+ case 0x2640: return(0x818A);
+ case 0x2642: return(0x8189);
+ case 0x266A: return(0x81F4);
+ case 0x266D: return(0x81F3);
+ case 0x266F: return(0x81F2);
+ default:
+ special--;
+ bad++;
+ return(0xfffd);
+ }
+ }
+ if (un >= 0x3000 && un < 0x4e00) { /* CJK symbols & punc */
+ kanji++;
+ if (un <= 0x30ff)
+ return(usj_3000[un-0x3000]);
+ kanji--;
+ bad++;
+ return(0xfffd);
+ }
+ if (un >= 0xff00 && un < 0xffff) { /* Half/full-width Roman & Katakana */
+ if (un <= 0xff9f) {
+ if (un > 0xff60)
+ kana++;
+ return(usj_ff00[un-0xff00]);
+ }
+ bad++;
+ return(0xfffd);
+ }
+ if (un >= 0x4e00 && un < 0xe000) { /* Kanji */
+ kanji++;
+ if (un <= 0x9fa0)
+ return(usj_4e00[un-0x4e00]);
+ kanji--;
+ bad++;
+ return(0xfffd);
+ }
+ if (un >= 0xe000 && un < 0xff00) { /* User-defined (Gaiji) */
+ kanji++;
+ if (un <= 0xe0bb) { /* ten 189-char chunks */
+ return(0xf040 + (un - 0xe000));
+ } else if (un >= 0xe0bc && un <= 0xe177) {
+ return(0xf140 + (un - 0xe0bc));
+ } else if (un >= 0xe178 && un <= 0xe233) {
+ return(0xf240 + (un - 0xe178));
+ } else if (un >= 0xe234 && un <= 0xe2ef) {
+ return(0xf340 + (un - 0xe234));
+ } else if (un >= 0xe2f0 && un <= 0xe3ab) {
+ return(0xf440 + (un - 0xe2f0));
+ } else if (un >= 0xe3ac && un <= 0xe467) {
+ return(0xf540 + (un - 0xe3ac));
+ } else if (un >= 0xe468 && un <= 0xe523) {
+ return(0xf640 + (un - 0xe468));
+ } else if (un >= 0xe524 && un <= 0xe5df) {
+ return(0xf740 + (un - 0xe524));
+ } else if (un >= 0xe5e0 && un <= 0xe69b) {
+ return(0xf840 + (un - 0xe5e0));
+ } else if (un >= 0xe69c && un <= 0xe757) {
+ return(0xf940 + (un - 0xe69c));
+ }
+ bad++;
+ return(0xfffd);
+ }
+ /* NOTREACHED */
+ /* Some compilers (correctly) warn of "statement not reached" here. */
+ /* But others give up the ghost with "no return value". The former */
+ /* is the lesser of two evils. */
+ bad++;
+ return(0xfffd);
+}
+#endif /* KANJI */
+
+/* Unicode-to-blah functions, tx_blah(). */
+
+static int
+#ifdef CK_ANSIC
+tx_punc(USHORT c)
+#else
+tx_punc(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x2000 && c <= 0x200a) /* Various-width spaces */
+ return((CHAR)(0x20));
+ else if (c >= 0x2010 && c <= 0x2015) /* Various-width dashes */
+ return((CHAR)'-');
+ else if (c >= 0x2018 && c <= 0x201b) /* Assorted single quotes */
+ return((CHAR)0x27);
+ else if (c >= 0x201c && c <= 0x201f) /* Assorted double quotes */
+ return((CHAR)0x22);
+ else if ((c >= 0x2022 && c <= 0x2024) || c == 0x2043) /* Bullets */
+ return((CHAR)0xb7);
+ switch (c) {
+ case 0x2039: /* Less-than sign */
+ return((CHAR)0x3c);
+ case 0x203a: /* Greater-than sign */
+ return((CHAR)0x3e);
+ case 0x2044: /* Solidus -> Slash */
+ return((CHAR)0x2f);
+ default:
+ return(-1);
+ }
+}
+
+
+int /* For Latin-1 */
+#ifdef CK_ANSIC
+tx_ident(USHORT c)
+#else
+tx_ident(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c == 0x203e) /* Overline -> Macron */
+ return((CHAR)0xaf);
+ else if (c < 0x100) /* Latin-1 range */
+ return((CHAR)(c & 0xff));
+ else /* Or maybe from punctuation block */
+ return(tx_punc(c));
+}
+
+int
+#ifdef CK_ANSIC
+tx_usascii(USHORT c)
+#else
+tx_usascii(c) USHORT c; /* US ASCII */
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80)
+ return((CHAR)(c & 0xff));
+ else if (c >= 0x2000 && c <= 0x200a) /* Various-width spaces */
+ return((CHAR)(0x20));
+ else if (c >= 0x2010 && c <= 0x2015) /* Various-width dashes */
+ return((CHAR)'-');
+ else if (c >= 0x2018 && c <= 0x201b) /* Assorted single quotes */
+ return((CHAR)0x27);
+ else if (c >= 0x201c && c <= 0x201f) /* Assorted double quotes */
+ return((CHAR)0x22);
+ else if ((c >= 0x2022 && c <= 0x2024) || c == 0x2043) /* Bullets */
+ return((CHAR)0xb7);
+ switch (c) {
+ case 0x2039: /* Less-than sign */
+ return((CHAR)0x3c);
+ case 0x203a: /* Greater-than sign */
+ return((CHAR)0x3e);
+ case 0x2044: /* Solidus -> Slash */
+ return((CHAR)0x2f);
+ }
+ /*
+ Here we might also (a) map accented Roman letters to unaccented ones;
+ (b) map Greek/Cyrillic A (etc) to Roman, and so on.
+ */
+ return((c & 0xff80) ? -1 : (CHAR)(c & 0x7f));
+}
+
+int
+#ifdef CK_ANSIC
+tx_british(USHORT c)
+#else
+tx_british(c) USHORT c; /* British */
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00)
+ return(-1);
+ else if (c == (USHORT) 0x00a3) /* Pound sign */
+ return(0x2b);
+ else
+ return(tx_usascii(c));
+}
+
+int
+#ifdef CK_ANSIC
+tx_apl1(USHORT c)
+#else
+tx_apl1(c) USHORT c; /* Apl1 */
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x0041 && c <= 0x005a) /* Letters */
+ return(c + 0x20);
+ switch (c) { /* Others */
+ case 0x0024: return((CHAR)0x7e);
+ case 0x0027: return((CHAR)0x4b);
+ case 0x0028: return((CHAR)0x3a);
+ case 0x0029: return((CHAR)0x22);
+ case 0x002b: return((CHAR)0x2d);
+ case 0x002c: return((CHAR)0x2c);
+ case 0x002d: return((CHAR)0x5f);
+ case 0x002e: return((CHAR)0x2e);
+ case 0x002f: return((CHAR)0x2f);
+ case 0x0030: return((CHAR)0x30);
+ case 0x0031: return((CHAR)0x31);
+ case 0x0032: return((CHAR)0x32);
+ case 0x0033: return((CHAR)0x33);
+ case 0x0034: return((CHAR)0x34);
+ case 0x0035: return((CHAR)0x35);
+ case 0x0036: return((CHAR)0x36);
+ case 0x0037: return((CHAR)0x37);
+ case 0x0038: return((CHAR)0x38);
+ case 0x0039: return((CHAR)0x39);
+ case 0x003a: return((CHAR)0x3e);
+ case 0x003b: return((CHAR)0x3c);
+ case 0x003c: return((CHAR)0x23);
+ case 0x003d: return((CHAR)0x25);
+ case 0x003e: return((CHAR)0x26);
+ case 0x003f: return((CHAR)0x51);
+ case 0x005b: return((CHAR)0x3b);
+ case 0x005c: return((CHAR)0x3f);
+ case 0x005d: return((CHAR)0x27);
+ case 0x005f: return((CHAR)0x46);
+ case 0x007b: return((CHAR)0x7b);
+ case 0x007c: return((CHAR)0x4d);
+ case 0x007d: return((CHAR)0x7d);
+ case 0x00a8: return((CHAR)0x21);
+ case 0x00af: return((CHAR)0x40);
+ case 0x00d7: return((CHAR)0x3d);
+ case 0x00f7: return((CHAR)0x2b);
+ case 0x2190: return((CHAR)0x5b);
+ case 0x2191: return((CHAR)0x59);
+ case 0x2192: return((CHAR)0x5d);
+ case 0x2193: return((CHAR)0x55);
+ case 0x2206: return((CHAR)0x48);
+ case 0x2207: return((CHAR)0x47);
+ case 0x220a: return((CHAR)0x45);
+ case 0x2218: return((CHAR)0x4a);
+ case 0x2227: return((CHAR)0x29);
+ case 0x2228: return((CHAR)0x28);
+ case 0x222a: return((CHAR)0x56);
+ case 0x223c: return((CHAR)0x54);
+ case 0x2260: return((CHAR)0x2a);
+ case 0x2264: return((CHAR)0x24);
+ case 0x2265: return((CHAR)0x5e);
+ case 0x2282: return((CHAR)0x5a);
+ case 0x2283: return((CHAR)0x58);
+ case 0x22a2: return((CHAR)0x5c);
+ case 0x22a3: return((CHAR)0x7c);
+ case 0x22a4: return((CHAR)0x4e);
+ case 0x22a5: return((CHAR)0x42);
+ case 0x22c2: return((CHAR)0x43);
+ case 0x22c4: return((CHAR)0x60);
+ case 0x22c6: return((CHAR)0x50);
+ case 0x2308: return((CHAR)0x53);
+ case 0x230a: return((CHAR)0x44);
+ case 0x2373: return((CHAR)0x49);
+ case 0x2374: return((CHAR)0x52);
+ case 0x2375: return((CHAR)0x57);
+ case 0x237a: return((CHAR)0x41);
+ case 0x25af: return((CHAR)0x4c);
+ case 0x25cb: return((CHAR)0x4f);
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Canadian French */
+#ifdef CK_ANSIC
+tx_fr_canadian(USHORT c)
+#else
+tx_fr_canadian(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xe0: return(0x40); /* a grave */
+ case 0xe2: return(0x5b); /* a circumflex */
+ case 0xe7: return(0x5c); /* c cedilla */
+ case 0xe8: return(0x7d); /* e grave */
+ case 0xe9: return(0x7b); /* e acute */
+ case 0xea: return(0x5d); /* e circumflex */
+ case 0xee: return(0x5e); /* i circumflex */
+ case 0xf4: return(0x60); /* o circumflex */
+ case 0xf9: return(0x7c); /* u grave */
+ case 0xfb: return(0x6e); /* u circumflex */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Danish/Norwegian */
+#ifdef CK_ANSIC
+tx_danish(USHORT c)
+#else
+tx_danish(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xc6: return(0x5b); /* AE */
+ case 0xd8: return(0x5c); /* O stroke */
+ case 0xe6: return(0x7b); /* ae */
+ case 0xf8: return(0x7c); /* o stroke */
+ case 0xe5: return(0x7d); /* a ring */
+ case 0xaf: return(0x7e); /* macron */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Dutch */
+#ifdef CK_ANSIC
+tx_dutch(USHORT c)
+#else
+tx_dutch(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xfe00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0x007c: return(0x5d); /* vertical bar */
+ case 0x00a3: return(0x23); /* pound sign */
+ case 0x00ab: return(0x7b); /* diaeresis */
+ case 0x00b4: return(0x7e); /* acute accent */
+ case 0x00bc: return(0x7d); /* 1/4 */
+ case 0x00be: return(0x40); /* 3/4 */
+ case 0x00bd: return(0x5c); /* 1/2 */
+ case 0x00ff: return(0x5b); /* y diaeresis (ij) */
+ case 0x0192: return(0x7c); /* Florin */
+ default: return((c & 0x80) ? -1 : (CHAR)(c & 0x7f));
+ }
+}
+
+int /* Finnish */
+#ifdef CK_ANSIC
+tx_finnish(USHORT c)
+#else
+tx_finnish(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xc4: return(0x5b); /* A diaeresis */
+ case 0xd6: return(0x5c); /* O diaeresis */
+ case 0xc5: return(0x5d); /* A ring */
+ case 0xdc: return(0x5e); /* U diaeresis */
+ case 0xe9: return(0x60); /* e acute */
+ case 0xe4: return(0x7b); /* a diaeresis */
+ case 0xf6: return(0x7c); /* o diaeresis */
+ case 0xe5: return(0x7d); /* a ring */
+ case 0xfc: return(0x7e); /* u diaeresis */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* French */
+#ifdef CK_ANSIC
+tx_french(USHORT c)
+#else
+tx_french(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xa3: return(0x23); /* pound sign */
+ case 0xa7: return(0x5d); /* section sign */
+ case 0xa8: return(0x7e); /* diaeresis */
+ case 0xb0: return(0x5b); /* ring */
+ case 0xb5: return(0x60); /* micron sign (mu) */
+ case 0xe0: return(0x40); /* a grave */
+ case 0xe7: return(0x5c); /* c cedilla */
+ case 0xe8: return(0x7d); /* e grave */
+ case 0xe9: return(0x7b); /* e acute */
+ case 0xf9: return(0x7c); /* u grave */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* German */
+#ifdef CK_ANSIC
+tx_german(USHORT c)
+#else
+tx_german(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xa7: return(0x40); /* section sign */
+ case 0xc4: return(0x5b); /* A umlaut */
+ case 0xd6: return(0x5c); /* O umlaut */
+ case 0xdc: return(0x5d); /* U umlaut */
+ case 0xdf: return(0x7e); /* ess-zet */
+ case 0xe4: return(0x7b); /* a umlaut */
+ case 0xf6: return(0x7c); /* o umlaut */
+ case 0xfc: return(0x7d); /* u umlaut*/
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Hebrew-7 */
+#ifdef CK_ANSIC
+tx_hebrew7(USHORT c)
+#else
+tx_hebrew7(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x60) /* ASCII */
+ return((CHAR)(c & 0x7f));
+ else if (c >= 123 && c < 128) /* ASCII */
+ return((CHAR)(c & 0x7f));
+ else if (c >= 0x05d0 && c <= 0x05ea) /* Hebrew 27 contiguous characters */
+ return((CHAR)((int)c - 0x5d0 + 96));
+ else return(-1);
+}
+
+int /* Greek ELOT 927 */
+#ifdef CK_ANSIC
+tx_elot927(USHORT c)
+#else
+tx_elot927(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c <= 0x80) { /* ASCII */
+ if (islower(c)) c = toupper(c); /* Send all letters in uppercase */
+ return((CHAR)(c & 0x7f));
+ }
+
+/* Greek -- map all Greek characters to unaccented uppercase */
+
+ if (c >= 0x0391 && c <= 0x03a1) /* Alpha thru Rho - uppercase */
+ return((CHAR)((int)c - 0x0391 + 97));
+ else if (c >= 0x03a3 && c <= 0x03a9) /* Sigma thru Omega - uppercase */
+ return((CHAR)((int)c - 0x0391 + 96));
+ else if (c >= 0x03b1 && c <= 0x03c1) /* Alpha thru Rho - lowercase */
+ return((CHAR)((int)c - 0x0391 + 97));
+ else if (c >= 0x03c3 && c <= 0x03c9) /* Sigma thru Omega - uppercase */
+ return((CHAR)((int)c - 0x0391 + 96));
+ switch (c) {
+ case 0x03c2: return((CHAR)114); /* Terminal sigma */
+ case 0x0386: return((CHAR)97); /* Alpha Tonos */
+ case 0x03ac: return((CHAR)97); /* alpha Tonos */
+ case 0x0388: return((CHAR)101); /* Epsilon Tonos */
+ case 0x03ad: return((CHAR)101); /* epsilon Tonos */
+ case 0x0389: return((CHAR)103); /* Eta Tonos */
+ case 0x03ae: return((CHAR)103); /* eta Tonos */
+ case 0x038a: return((CHAR)105); /* Iota Tonos */
+ case 0x03af: return((CHAR)105); /* iota Tonos */
+ case 0x03ca: return((CHAR)105); /* iota Dialytika */
+ case 0x038c: return((CHAR)111); /* Omicron Tonos */
+ case 0x03cc: return((CHAR)111); /* omicron Tonos */
+ case 0x038e: return((CHAR)116); /* Upsilon Tonos */
+ case 0x03d3: return((CHAR)116); /* Upsilon Tonos */
+ case 0x03cd: return((CHAR)116); /* upsilon Tonos */
+ case 0x03cb: return((CHAR)116); /* upsilon Dialytika */
+ case 0x03b0: return((CHAR)116); /* upsilon Dialytika+Tonos */
+ case 0x038f: return((CHAR)120); /* Omega Tonos */
+ case 0x03ce: return((CHAR)120); /* omega Tonos */
+ case 0x0390: return((CHAR)105); /* iota Dialytika+Tonos */
+ case 0x03aa: return((CHAR)105); /* Iota Dialytika */
+ case 0x03ab: return((CHAR)116); /* Upsilon Dialytika */
+ case 0x03d4: return((CHAR)116); /* Upsilon Dialytika */
+ case 0x03d0: return((CHAR)98); /* Alternative beta */
+ case 0x03d1: return((CHAR)104); /* Open theta */
+ case 0x03d5: return((CHAR)117); /* Open phi */
+ case 0x03d6: return((CHAR)112); /* Alternative Pi */
+ default: return(-1);
+ }
+}
+
+int /* Hungarian */
+#ifdef CK_ANSIC
+tx_hungarian(USHORT c)
+#else
+tx_hungarian(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c == 0x02dd || c == 0x2033)
+ return(0x7e); /* double acute accent */
+ else if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xc1: return(0x40); /* A acute */
+ case 0xc9: return(0x5b); /* E acute */
+ case 0xd6: return(0x5c); /* O umlaut */
+ case 0xdc: return(0x5d); /* U umlaut */
+ case 0xe9: return(0x7b); /* e acute */
+ case 0xf6: return(0x7c); /* o umlaut */
+ case 0xfa: return(0x60); /* u acute */
+ case 0xfc: return(0x7d); /* u umlaut */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Icelandic */
+#ifdef CK_ANSIC
+tx_icelandic(USHORT c)
+#else
+tx_icelandic(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xde: return(0x40); /* Thorn */
+ case 0xd0: return(0x5b); /* Eth */
+ case 0xc6: return(0x5d); /* AE */
+ case 0xd6: return(0x5e); /* O umlaut */
+ case 0xfe: return(0x60); /* thorn */
+ case 0xf0: return(0x7b); /* eth */
+ case 0xe6: return(0x7d); /* ae */
+ case 0xf6: return(0x7e); /* o umlaut */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Italian */
+#ifdef CK_ANSIC
+tx_italian(USHORT c)
+#else
+tx_italian(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xa3: return(0x23); /* pound sign */
+ case 0xa7: return(0x40); /* section sign */
+ case 0xb0: return(0x5b); /* ring */
+ case 0xe7: return(0x5c); /* c cedilla */
+ case 0xe9: return(0x5d); /* e acute */
+ case 0xf9: return(0x60); /* u grave */
+ case 0xe0: return(0x7b); /* a grave */
+ case 0xf2: return(0x7c); /* o grave */
+ case 0xe8: return(0x7d); /* e grave */
+ case 0xec: return(0x7e); /* i grave */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* JIS 0201 Roman */
+#ifdef CK_ANSIC
+tx_jis0201r(USHORT c)
+#else
+tx_jis0201r(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c && 0xff80) /* 7 bits */
+ return(-1);
+ switch (c) { /* Like ASCII with */
+ case 0x00a5: return(92); /* two exceptions */
+ case 0x00af: return(126);
+ case 0x203e: return(126);
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* JIS 0201 Katakana */
+#ifdef CK_ANSIC
+tx_jis0201k(USHORT c)
+#else
+tx_jis0201k(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xff61 || c > 0xff9f)
+ return(-1); /* Out of range */
+ else
+ return((int)c - 0xfec0); /* 0xff61 - a0 = 0xfec0 */
+}
+
+int /* Short KOI */
+#ifdef CK_ANSIC
+tx_koi7(USHORT c)
+#else
+tx_koi7(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x50)
+ return((CHAR)(c & 0x7f));
+ else if (c > 0x7f)
+ return(-1); /* Out of range */
+ switch(c) {
+ case 0x0410: return((CHAR)97);
+ case 0x0411: return((CHAR)98);
+ case 0x0412: return((CHAR)119);
+ case 0x0413: return((CHAR)103);
+ case 0x0414: return((CHAR)100);
+ case 0x0415: return((CHAR)101);
+ case 0x0416: return((CHAR)118);
+ case 0x0417: return((CHAR)122);
+ case 0x0418: return((CHAR)105);
+ case 0x0419: return((CHAR)106);
+ case 0x041a: return((CHAR)107);
+ case 0x041b: return((CHAR)108);
+ case 0x041c: return((CHAR)109);
+ case 0x041d: return((CHAR)110);
+ case 0x041e: return((CHAR)111);
+ case 0x041f: return((CHAR)112);
+ case 0x0420: return((CHAR)114);
+ case 0x0421: return((CHAR)115);
+ case 0x0422: return((CHAR)116);
+ case 0x0423: return((CHAR)117);
+ case 0x0424: return((CHAR)102);
+ case 0x0425: return((CHAR)104);
+ case 0x0426: return((CHAR)99);
+ case 0x0427: return((CHAR)126);
+ case 0x0428: return((CHAR)123);
+ case 0x0429: return((CHAR)125);
+ case 0x042b: return((CHAR)121);
+ case 0x042c: return((CHAR)120);
+ case 0x042d: return((CHAR)124);
+ case 0x042e: return((CHAR)96);
+ case 0x042f: return((CHAR)113);
+ default: return(-1);
+ }
+}
+
+int /* Portuguese */
+#ifdef CK_ANSIC
+tx_portuguese(USHORT c)
+#else
+tx_portuguese(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xe0: return(0xa7); /* section sign */
+ case 0xb0: return(0xc3); /* A tilde */
+ case 0xe7: return(0xc7); /* C cedilla */
+ case 0xa7: return(0xd5); /* O tilde */
+ case 0xe9: return(0xe3); /* a tilde */
+ case 0xf9: return(0xe7); /* c cedilla */
+ case 0xe8: return(0xf5); /* o tilde */
+ case 0xa8: return(0xb0); /* ring */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Spanish */
+#ifdef CK_ANSIC
+tx_spanish(USHORT c)
+#else
+tx_spanish(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xa3: return(0x23); /* pound sign */
+ case 0xa7: return(0x40); /* section */
+ case 0xa1: return(0x5b); /* inverted exclamation */
+ case 0xd1: return(0x5c); /* N tilde */
+ case 0xbf: return(0x5d); /* inverted question mark */
+ case 0xb0: return(0x7b); /* ring */
+ case 0xf1: return(0x7c); /* n tilde */
+ case 0xe7: return(0x7d); /* c cedilla */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Swedish */
+#ifdef CK_ANSIC
+tx_swedish(USHORT c)
+#else
+tx_swedish(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xc9: return(0x40); /* E acute */
+ case 0xc4: return(0x5b); /* A umlaut*/
+ case 0xd6: return(0x5c); /* O umlaut */
+ case 0xc5: return(0x5d); /* A ring */
+ case 0xdc: return(0x5e); /* U umlaut */
+ case 0xe9: return(0x60); /* e acute */
+ case 0xe4: return(0x7b); /* a umlaut */
+ case 0xf6: return(0x7c); /* o umlaut */
+ case 0xe5: return(0x7d); /* a ring */
+ case 0xfc: return(0x7e); /* u umlaut */
+ default: return(tx_usascii(c));
+ }
+}
+
+
+int /* Swiss NRC */
+#ifdef CK_ANSIC
+tx_swiss(USHORT c)
+#else
+tx_swiss(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c & 0xff00) /* Out of range */
+ return(-1);
+ switch(c) {
+ case 0xf9: return(0x23); /* u grave */
+ case 0xe0: return(0x40); /* a grave */
+ case 0xe9: return(0x5b); /* e acute */
+ case 0xe7: return(0x5c); /* c cedilla */
+ case 0xea: return(0x5d); /* e circumflex */
+ case 0xee: return(0x5e); /* i circumflex */
+ case 0xe8: return(0x5f); /* e grave */
+ case 0xf4: return(0x60); /* o circumflex */
+ case 0xe4: return(0x7b); /* a umlaut */
+ case 0xf6: return(0x7c); /* o umlaut */
+ case 0xfc: return(0x7d); /* u umlaut */
+ case 0xfb: return(0x7e); /* u circumflex */
+ default: return(tx_usascii(c));
+ }
+}
+
+int /* Dyadic APL */
+#ifdef CK_ANSIC
+tx_apl2(USHORT c)
+#else
+tx_apl2(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x0041 && c <= 0x005a) /* Letters */
+ return(c - 0xa2);
+ switch (c) {
+ case 0x00a0: return((CHAR)0xa0);
+ case 0x00a2: return((CHAR)0xa4);
+ case 0x00a3: return((CHAR)0xd4);
+ case 0x00a8: return((CHAR)0xdc);
+ case 0x00af: return((CHAR)0xda);
+ case 0x00d7: return((CHAR)0xa1);
+ case 0x00f7: return((CHAR)0xaf);
+ case 0x2190: return((CHAR)0xbb);
+ case 0x2191: return((CHAR)0xfe);
+ case 0x2192: return((CHAR)0xde);
+ case 0x2193: return((CHAR)0xff);
+ case 0x2206: return((CHAR)0xae);
+ case 0x2207: return((CHAR)0xfd);
+ case 0x220a: return((CHAR)0xb5);
+ case 0x2218: return((CHAR)0xbc);
+ case 0x2228: return((CHAR)0xdf);
+ case 0x2229: return((CHAR)0xd1);
+ case 0x222a: return((CHAR)0xd2);
+ case 0x2260: return((CHAR)0xb0);
+ case 0x2261: return((CHAR)0xb6);
+ case 0x2262: return((CHAR)0xcd);
+ case 0x2264: return((CHAR)0xb8);
+ case 0x2265: return((CHAR)0xb7);
+ case 0x2282: return((CHAR)0xe0);
+ case 0x2283: return((CHAR)0xe1);
+ case 0x2296: return((CHAR)0xd6);
+ case 0x22a2: return((CHAR)0xd7);
+ case 0x22a3: return((CHAR)0xd8);
+ case 0x22a4: return((CHAR)0xba);
+ case 0x22a5: return((CHAR)0xb9);
+ case 0x22c4: return((CHAR)0xb1);
+ case 0x2308: return((CHAR)0xcf);
+ case 0x230a: return((CHAR)0xce);
+ case 0x2337: return((CHAR)0xd9);
+ case 0x2339: return((CHAR)0xca);
+ case 0x233d: return((CHAR)0xd5);
+ case 0x233f: return((CHAR)0xbe);
+ case 0x2340: return((CHAR)0xbf);
+ case 0x2349: return((CHAR)0xd0);
+ case 0x234b: return((CHAR)0xc2);
+ case 0x234e: return((CHAR)0xc0);
+ case 0x2352: return((CHAR)0xc3);
+ case 0x2355: return((CHAR)0xc1);
+ case 0x2359: return((CHAR)0xe2);
+ case 0x235d: return((CHAR)0xbd);
+ case 0x235e: return((CHAR)0xc9);
+ case 0x235f: return((CHAR)0xc7);
+ case 0x2368: return((CHAR)0xc6);
+ case 0x236a: return((CHAR)0xcc);
+ case 0x236b: return((CHAR)0xcb);
+ case 0x236c: return((CHAR)0xd3);
+ case 0x2371: return((CHAR)0xc5);
+ case 0x2372: return((CHAR)0xc4);
+ case 0x2373: return((CHAR)0xdb);
+ case 0x2374: return((CHAR)0xb3);
+ case 0x2375: return((CHAR)0xb2);
+ case 0x237a: return((CHAR)0xb4);
+ case 0x2500: return((CHAR)0xaa);
+ case 0x2502: return((CHAR)0xa2);
+ case 0x250c: return((CHAR)0xad);
+ case 0x2510: return((CHAR)0xa5);
+ case 0x2514: return((CHAR)0xa6);
+ case 0x2518: return((CHAR)0xac);
+ case 0x251c: return((CHAR)0xa9);
+ case 0x2524: return((CHAR)0xa3);
+ case 0x252c: return((CHAR)0xa8);
+ case 0x2534: return((CHAR)0xa7);
+ case 0x253c: return((CHAR)0xab);
+ case 0x25af: return((CHAR)0xc8);
+ case 0x25cb: return((CHAR)0xdd);
+ default:
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ return(tx_punc(c));
+ }
+}
+
+int /* APL-Plus */
+#ifdef CK_ANSIC
+tx_apl3(USHORT c)
+#else
+tx_apl3(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ switch (c) {
+ case 0x00a0: return((CHAR)0xa0);
+ case 0x00a1: return((CHAR)0xa1);
+ case 0x00a2: return((CHAR)0xa2);
+ case 0x00a3: return((CHAR)0xa3);
+ case 0x00a5: return((CHAR)0xa5);
+ case 0x00a6: return((CHAR)0xa6);
+ case 0x00a7: return((CHAR)0xa7);
+ case 0x00a8: return((CHAR)0xa8);
+ case 0x00ab: return((CHAR)0xab);
+ case 0x00af: return((CHAR)0xaf);
+ case 0x00b6: return((CHAR)0xb6);
+ case 0x00b7: return((CHAR)0xb7);
+ case 0x00bb: return((CHAR)0xbb);
+ case 0x00bf: return((CHAR)0xbf);
+ case 0x00c0: return((CHAR)0xc0);
+ case 0x00c1: return((CHAR)0xc1);
+ case 0x00c2: return((CHAR)0xc2);
+ case 0x00c3: return((CHAR)0xc3);
+ case 0x00c4: return((CHAR)0xc4);
+ case 0x00c5: return((CHAR)0xc5);
+ case 0x00c6: return((CHAR)0xc6);
+ case 0x00c7: return((CHAR)0xc7);
+ case 0x00c8: return((CHAR)0xc8);
+ case 0x00c9: return((CHAR)0xc9);
+ case 0x00ca: return((CHAR)0xca);
+ case 0x00cb: return((CHAR)0xcb);
+ case 0x00cc: return((CHAR)0xcc);
+ case 0x00cd: return((CHAR)0xcd);
+ case 0x00ce: return((CHAR)0xce);
+ case 0x00cf: return((CHAR)0xcf);
+ case 0x00d1: return((CHAR)0xd1);
+ case 0x00d2: return((CHAR)0xd2);
+ case 0x00d3: return((CHAR)0xd3);
+ case 0x00d4: return((CHAR)0xd4);
+ case 0x00d5: return((CHAR)0xd5);
+ case 0x00d6: return((CHAR)0xd6);
+ case 0x00d7: return((CHAR)0xd7);
+ case 0x00d8: return((CHAR)0xd8);
+ case 0x00d9: return((CHAR)0xd9);
+ case 0x00da: return((CHAR)0xda);
+ case 0x00db: return((CHAR)0xdb);
+ case 0x00dc: return((CHAR)0xdc);
+ case 0x00dd: return((CHAR)0xdd);
+ case 0x00df: return((CHAR)0xdf);
+ case 0x00e0: return((CHAR)0xe0);
+ case 0x00e1: return((CHAR)0xe1);
+ case 0x00e2: return((CHAR)0xe2);
+ case 0x00e3: return((CHAR)0xe3);
+ case 0x00e4: return((CHAR)0xe4);
+ case 0x00e5: return((CHAR)0xe5);
+ case 0x00e6: return((CHAR)0xe6);
+ case 0x00e7: return((CHAR)0xe7);
+ case 0x00e8: return((CHAR)0xe8);
+ case 0x00e9: return((CHAR)0xe9);
+ case 0x00ea: return((CHAR)0xea);
+ case 0x00eb: return((CHAR)0xeb);
+ case 0x00ec: return((CHAR)0xec);
+ case 0x00ed: return((CHAR)0xed);
+ case 0x00ee: return((CHAR)0xee);
+ case 0x00ef: return((CHAR)0xef);
+ case 0x00f1: return((CHAR)0xf1);
+ case 0x00f2: return((CHAR)0xf2);
+ case 0x00f3: return((CHAR)0xf3);
+ case 0x00f4: return((CHAR)0xf4);
+ case 0x00f5: return((CHAR)0xf5);
+ case 0x00f6: return((CHAR)0xf6);
+ case 0x00f7: return((CHAR)0xf7);
+ case 0x00f9: return((CHAR)0xf9);
+ case 0x00fa: return((CHAR)0xfa);
+ case 0x00fb: return((CHAR)0xfb);
+ case 0x00fc: return((CHAR)0xfc);
+ case 0x00fd: return((CHAR)0xfd);
+ case 0x00ff: return((CHAR)0xff);
+ case 0x20ac: return((CHAR)0x80);
+ case 0x2190: return((CHAR)0x84);
+ case 0x2191: return((CHAR)0x86);
+ case 0x2192: return((CHAR)0x85);
+ case 0x2193: return((CHAR)0x87);
+ case 0x2205: return((CHAR)0xf8);
+ case 0x2206: return((CHAR)0x91);
+ case 0x2207: return((CHAR)0x92);
+ case 0x220a: return((CHAR)0xb9);
+ case 0x2218: return((CHAR)0xb0);
+ case 0x2228: return((CHAR)0x9f);
+ case 0x2229: return((CHAR)0x9d);
+ case 0x222a: return((CHAR)0x9e);
+ case 0x2260: return((CHAR)0xac);
+ case 0x2261: return((CHAR)0xad);
+ case 0x2264: return((CHAR)0x88);
+ case 0x2265: return((CHAR)0x89);
+ case 0x2282: return((CHAR)0x9b);
+ case 0x2283: return((CHAR)0x9c);
+ case 0x2296: return((CHAR)0xb4);
+ case 0x22a2: return((CHAR)0xa4);
+ case 0x22a3: return((CHAR)0x81);
+ case 0x22a4: return((CHAR)0x82);
+ case 0x22a5: return((CHAR)0x83);
+ case 0x22c4: return((CHAR)0xaa);
+ case 0x2308: return((CHAR)0x97);
+ case 0x230a: return((CHAR)0x98);
+ case 0x2337: return((CHAR)0xde);
+ case 0x2339: return((CHAR)0x8e);
+ case 0x233d: return((CHAR)0xb2);
+ case 0x233f: return((CHAR)0x9a);
+ case 0x2340: return((CHAR)0x99);
+ case 0x2349: return((CHAR)0xb3);
+ case 0x234b: return((CHAR)0x93);
+ case 0x234e: return((CHAR)0x96);
+ case 0x2352: return((CHAR)0x94);
+ case 0x2355: return((CHAR)0x95);
+ case 0x2359: return((CHAR)0x8f);
+ case 0x235d: return((CHAR)0xa9);
+ case 0x235e: return((CHAR)0x8d);
+ case 0x235f: return((CHAR)0xb5);
+ case 0x2364: return((CHAR)0xf0);
+ case 0x2368: return((CHAR)0xfe);
+ case 0x236a: return((CHAR)0xae);
+ case 0x236b: return((CHAR)0x90);
+ case 0x236c: return((CHAR)0xd0);
+ case 0x2371: return((CHAR)0x8b);
+ case 0x2372: return((CHAR)0x8a);
+ case 0x2373: return((CHAR)0xbc);
+ case 0x2374: return((CHAR)0xbd);
+ case 0x2375: return((CHAR)0xbe);
+ case 0x2377: return((CHAR)0xba);
+ case 0x237a: return((CHAR)0xb8);
+ case 0x25af: return((CHAR)0x8c);
+ case 0x25cb: return((CHAR)0xb1);
+ default:
+ return(tx_punc(c));
+ }
+}
+
+int /* IBM APL2 */
+#ifdef CK_ANSIC
+tx_apl4(USHORT c)
+#else
+tx_apl4(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ switch (c) {
+ case 0x00a0: return((CHAR)0xff);
+ case 0x00a1: return((CHAR)0xad);
+ case 0x00a3: return((CHAR)0x9c);
+ case 0x00a6: return((CHAR)0xdd);
+ case 0x00a8: return((CHAR)0xfe);
+ case 0x00aa: return((CHAR)0xa6);
+ case 0x00ac: return((CHAR)0xaa);
+ case 0x00af: return((CHAR)0xfd);
+ case 0x00ba: return((CHAR)0xa7);
+ case 0x00bf: return((CHAR)0xa8);
+ case 0x00c4: return((CHAR)0x8e);
+ case 0x00c5: return((CHAR)0xee); /* and 0x8f */
+ case 0x00c7: return((CHAR)0x80);
+ case 0x00cc: return((CHAR)0xde);
+ case 0x00d1: return((CHAR)0xa5);
+ case 0x00d6: return((CHAR)0x99);
+ case 0x00d7: return((CHAR)0xf5);
+ case 0x00dc: return((CHAR)0x9a);
+ case 0x00df: return((CHAR)0xe1);
+ case 0x00e0: return((CHAR)0x85);
+ case 0x00e1: return((CHAR)0xa0);
+ case 0x00e2: return((CHAR)0x83);
+ case 0x00e4: return((CHAR)0x84);
+ case 0x00e5: return((CHAR)0x86);
+ case 0x00e7: return((CHAR)0x87);
+ case 0x00e8: return((CHAR)0x8a);
+ case 0x00e9: return((CHAR)0x82);
+ case 0x00ea: return((CHAR)0x88);
+ case 0x00eb: return((CHAR)0x89);
+ case 0x00ec: return((CHAR)0x8d);
+ case 0x00ed: return((CHAR)0xa1);
+ case 0x00ee: return((CHAR)0x8c);
+ case 0x00ef: return((CHAR)0x8b);
+ case 0x00f1: return((CHAR)0xa4);
+ case 0x00f2: return((CHAR)0x95);
+ case 0x00f3: return((CHAR)0xa2);
+ case 0x00f4: return((CHAR)0x93);
+ case 0x00f6: return((CHAR)0x94);
+ case 0x00f7: return((CHAR)0xf6);
+ case 0x00f8: return((CHAR)0x9b);
+ case 0x00f9: return((CHAR)0x97);
+ case 0x00fa: return((CHAR)0xa3);
+ case 0x00fb: return((CHAR)0x96);
+ case 0x00fc: return((CHAR)0x81);
+ case 0x2190: return((CHAR)0x9e);
+ case 0x2191: return((CHAR)0xc6);
+ case 0x2192: return((CHAR)0xab);
+ case 0x2193: return((CHAR)0xc7);
+ case 0x2206: return((CHAR)0xb6);
+ case 0x2207: return((CHAR)0xb7);
+ case 0x2218: return((CHAR)0xf8);
+ case 0x2228: return((CHAR)0xeb);
+ case 0x2229: return((CHAR)0xef);
+ case 0x222a: return((CHAR)0xac);
+ case 0x2235: return((CHAR)0xd2);
+ case 0x2260: return((CHAR)0xf4);
+ case 0x2261: return((CHAR)0xcf);
+ case 0x2264: return((CHAR)0xf3);
+ case 0x2265: return((CHAR)0xf2);
+ case 0x2282: return((CHAR)0xe2);
+ case 0x2283: return((CHAR)0xe3);
+ case 0x2296: return((CHAR)0xe9);
+ case 0x22a2: return((CHAR)0xd6);
+ case 0x22a3: return((CHAR)0xd7);
+ case 0x22a4: return((CHAR)0x98);
+ case 0x22a5: return((CHAR)0x9d);
+ case 0x22c4: return((CHAR)0xd8);
+ case 0x2308: return((CHAR)0xa9);
+ case 0x230a: return((CHAR)0xbe);
+ case 0x2336: return((CHAR)0x9f);
+ case 0x2337: return((CHAR)0xd3);
+ case 0x2339: return((CHAR)0x92);
+ case 0x233b: return((CHAR)0xd5);
+ case 0x233d: return((CHAR)0xe8);
+ case 0x233f: return((CHAR)0xf0);
+ case 0x2340: return((CHAR)0xf1);
+ case 0x2342: return((CHAR)0xd4);
+ case 0x2349: return((CHAR)0xed);
+ case 0x234b: return((CHAR)0xfb);
+ case 0x234e: return((CHAR)0xaf);
+ case 0x2352: return((CHAR)0xfc);
+ case 0x2355: return((CHAR)0xae);
+ case 0x2359: return((CHAR)0xf7);
+ case 0x235d: return((CHAR)0xe4);
+ case 0x235e: return((CHAR)0x91);
+ case 0x235f: return((CHAR)0xb5);
+ case 0x236b: return((CHAR)0xfa);
+ case 0x2371: return((CHAR)0xe7);
+ case 0x2372: return((CHAR)0xe5);
+ case 0x2373: return((CHAR)0xec);
+ case 0x2374: return((CHAR)0xe6);
+ case 0x2375: return((CHAR)0xf9);
+ case 0x2377: return((CHAR)0xd1);
+ case 0x2378: return((CHAR)0xd0);
+ case 0x237a: return((CHAR)0xe0);
+ case 0x2500: return((CHAR)0xc4);
+ case 0x2502: return((CHAR)0xb3);
+ case 0x250c: return((CHAR)0xda);
+ case 0x2510: return((CHAR)0xbf);
+ case 0x2514: return((CHAR)0xc0);
+ case 0x2518: return((CHAR)0xd9);
+ case 0x251c: return((CHAR)0xc3);
+ case 0x2524: return((CHAR)0xb4);
+ case 0x252c: return((CHAR)0xc2);
+ case 0x2534: return((CHAR)0xc1);
+ case 0x253c: return((CHAR)0xc5);
+ case 0x2550: return((CHAR)0xcd);
+ case 0x2551: return((CHAR)0xba);
+ case 0x2554: return((CHAR)0xc9);
+ case 0x2557: return((CHAR)0xbb);
+ case 0x255a: return((CHAR)0xc8);
+ case 0x255d: return((CHAR)0xbc);
+ case 0x2560: return((CHAR)0xcc);
+ case 0x2563: return((CHAR)0xb9);
+ case 0x2566: return((CHAR)0xcb);
+ case 0x2569: return((CHAR)0xca);
+ case 0x256c: return((CHAR)0xce);
+ case 0x2580: return((CHAR)0xdf);
+ case 0x2584: return((CHAR)0xdc);
+ case 0x2588: return((CHAR)0xdb);
+ case 0x2591: return((CHAR)0xb0);
+ case 0x2592: return((CHAR)0xb1);
+ case 0x2593: return((CHAR)0xb2);
+ case 0x25af: return((CHAR)0x90);
+ case 0x25cb: return((CHAR)0xea);
+ default:
+ return(tx_punc(c));
+ }
+}
+
+int /* APL-2741 */
+#ifdef CK_ANSIC
+tx_apl5(USHORT c)
+#else
+tx_apl5(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ switch (c) {
+ case 0x00a0: return((CHAR)0xa0);
+ case 0x00a1: return((CHAR)0xa1);
+ case 0x00a2: return((CHAR)0xa2);
+ case 0x00a3: return((CHAR)0xa3);
+ case 0x00a8: return((CHAR)0xa8);
+ case 0x00af: return((CHAR)0xaf);
+ case 0x00b6: return((CHAR)0xb6);
+ case 0x00b7: return((CHAR)0xb7);
+ case 0x00bf: return((CHAR)0xbf);
+ case 0x00c4: return((CHAR)0xc4);
+ case 0x00c5: return((CHAR)0xc5);
+ case 0x00c6: return((CHAR)0xc6);
+ case 0x00c7: return((CHAR)0xc7);
+ case 0x00c8: return((CHAR)0xc8);
+ case 0x00c9: return((CHAR)0xc9);
+ case 0x00cd: return((CHAR)0xcd);
+ case 0x00d1: return((CHAR)0xd1);
+ case 0x00d6: return((CHAR)0xd6);
+ case 0x00d7: return((CHAR)0xd7);
+ case 0x00d8: return((CHAR)0xd8);
+ case 0x00dc: return((CHAR)0xdc);
+ case 0x00df: return((CHAR)0xdf);
+ case 0x00e0: return((CHAR)0xe0);
+ case 0x00e1: return((CHAR)0xe1);
+ case 0x00e2: return((CHAR)0xe2);
+ case 0x00e3: return((CHAR)0xe3);
+ case 0x00e4: return((CHAR)0xe4);
+ case 0x00e5: return((CHAR)0xe5);
+ case 0x00e6: return((CHAR)0xe6);
+ case 0x00e7: return((CHAR)0xe7);
+ case 0x00e8: return((CHAR)0xe8);
+ case 0x00e9: return((CHAR)0xe9);
+ case 0x00ea: return((CHAR)0xea);
+ case 0x00eb: return((CHAR)0xeb);
+ case 0x00ec: return((CHAR)0xec);
+ case 0x00ed: return((CHAR)0xed);
+ case 0x00ee: return((CHAR)0xee);
+ case 0x00ef: return((CHAR)0xef);
+ case 0x00f1: return((CHAR)0xf1);
+ case 0x00f2: return((CHAR)0xf2);
+ case 0x00f3: return((CHAR)0xf3);
+ case 0x00f4: return((CHAR)0xf4);
+ case 0x00f5: return((CHAR)0xf5);
+ case 0x00f6: return((CHAR)0xf6);
+ case 0x00f7: return((CHAR)0xf7);
+ case 0x00f9: return((CHAR)0xf9);
+ case 0x00fa: return((CHAR)0xfa);
+ case 0x00fb: return((CHAR)0xfb);
+ case 0x00fc: return((CHAR)0xfc);
+ case 0x20ac: return((CHAR)0x80);
+ case 0x2190: return((CHAR)0x84);
+ case 0x2191: return((CHAR)0x86);
+ case 0x2192: return((CHAR)0x85);
+ case 0x2193: return((CHAR)0x87);
+ case 0x2205: return((CHAR)0xf8);
+ case 0x2206: return((CHAR)0x91);
+ case 0x2207: return((CHAR)0x92);
+ case 0x220a: return((CHAR)0xb9);
+ case 0x2218: return((CHAR)0xb0);
+ case 0x2228: return((CHAR)0x9f);
+ case 0x2229: return((CHAR)0x9d);
+ case 0x222a: return((CHAR)0x9e);
+ case 0x2235: return((CHAR)0xfd);
+ case 0x2260: return((CHAR)0xac);
+ case 0x2261: return((CHAR)0xa6);
+ case 0x2262: return((CHAR)0xbb);
+ case 0x2264: return((CHAR)0x88);
+ case 0x2265: return((CHAR)0x89);
+ case 0x2282: return((CHAR)0x9b);
+ case 0x2283: return((CHAR)0x9c);
+ case 0x2296: return((CHAR)0xb4);
+ case 0x22a2: return((CHAR)0xa4);
+ case 0x22a3: return((CHAR)0x81);
+ case 0x22a4: return((CHAR)0x82);
+ case 0x22a5: return((CHAR)0x83);
+ case 0x22c4: return((CHAR)0xaa);
+ case 0x2308: return((CHAR)0x97);
+ case 0x230a: return((CHAR)0x98);
+ case 0x2336: return((CHAR)0xa7);
+ case 0x2337: return((CHAR)0xde);
+ case 0x2339: return((CHAR)0x8e);
+ case 0x233b: return((CHAR)0xcb);
+ case 0x233d: return((CHAR)0xb2);
+ case 0x233f: return((CHAR)0x9a);
+ case 0x2340: return((CHAR)0x99);
+ case 0x2342: return((CHAR)0xca);
+ case 0x2347: return((CHAR)0xd4);
+ case 0x2348: return((CHAR)0xd5);
+ case 0x2349: return((CHAR)0xb3);
+ case 0x234b: return((CHAR)0x93);
+ case 0x234e: return((CHAR)0x96);
+ case 0x2350: return((CHAR)0xd2);
+ case 0x2352: return((CHAR)0x94);
+ case 0x2355: return((CHAR)0x95);
+ case 0x2357: return((CHAR)0xd3);
+ case 0x2359: return((CHAR)0x8f);
+ case 0x235d: return((CHAR)0xa9);
+ case 0x235e: return((CHAR)0x8d);
+ case 0x235f: return((CHAR)0xb5);
+ case 0x2364: return((CHAR)0xf0);
+ case 0x2365: return((CHAR)0xff);
+ case 0x2368: return((CHAR)0xfe);
+ case 0x236a: return((CHAR)0xae);
+ case 0x236b: return((CHAR)0x90);
+ case 0x236c: return((CHAR)0xab);
+ case 0x2371: return((CHAR)0x8b);
+ case 0x2372: return((CHAR)0x8a);
+ case 0x2373: return((CHAR)0xbc);
+ case 0x2374: return((CHAR)0xbd);
+ case 0x2375: return((CHAR)0xbe);
+ case 0x2377: return((CHAR)0xba);
+ case 0x2378: return((CHAR)0xa5);
+ case 0x237a: return((CHAR)0xb8);
+ case 0x2500: return((CHAR)0xce);
+ case 0x2502: return((CHAR)0xdb);
+ case 0x250c: return((CHAR)0xda);
+ case 0x2510: return((CHAR)0xcc);
+ case 0x2514: return((CHAR)0xc0);
+ case 0x2518: return((CHAR)0xd9);
+ case 0x251c: return((CHAR)0xc3);
+ case 0x2524: return((CHAR)0xdd);
+ case 0x252c: return((CHAR)0xc2);
+ case 0x2534: return((CHAR)0xc1);
+ case 0x253c: return((CHAR)0xcf);
+ case 0x25af: return((CHAR)0x8c);
+ case 0x25cb: return((CHAR)0xb1);
+ default:
+ return(tx_punc(c));
+ }
+}
+
+/* For Latin-1, use tx_ident() */
+
+int /* Latin-2 */
+#ifdef CK_ANSIC
+tx_8859_2(USHORT c)
+#else
+tx_8859_2(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)160);
+ case 0x00A4: return((CHAR)164);
+ case 0x00A7: return((CHAR)167);
+ case 0x00A8: return((CHAR)168);
+ case 0x00AD: return((CHAR)173);
+ case 0x00B0: return((CHAR)176);
+ case 0x00B4: return((CHAR)180);
+ case 0x00B8: return((CHAR)184);
+ case 0x00C1: return((CHAR)193);
+ case 0x00C2: return((CHAR)194);
+ case 0x00C4: return((CHAR)196);
+ case 0x00C7: return((CHAR)199);
+ case 0x00C9: return((CHAR)201);
+ case 0x00CB: return((CHAR)203);
+ case 0x00CD: return((CHAR)205);
+ case 0x00CE: return((CHAR)206);
+ case 0x00D3: return((CHAR)211);
+ case 0x00D4: return((CHAR)212);
+ case 0x00D6: return((CHAR)214);
+ case 0x00D7: return((CHAR)215);
+ case 0x00DA: return((CHAR)218);
+ case 0x00DC: return((CHAR)220);
+ case 0x00DD: return((CHAR)221);
+ case 0x00DF: return((CHAR)223);
+ case 0x00E1: return((CHAR)225);
+ case 0x00E2: return((CHAR)226);
+ case 0x00E4: return((CHAR)228);
+ case 0x00E7: return((CHAR)231);
+ case 0x00E9: return((CHAR)233);
+ case 0x00EB: return((CHAR)235);
+ case 0x00ED: return((CHAR)237);
+ case 0x00EE: return((CHAR)238);
+ case 0x00F3: return((CHAR)243);
+ case 0x00F4: return((CHAR)244);
+ case 0x00F6: return((CHAR)246);
+ case 0x00F7: return((CHAR)247);
+ case 0x00FA: return((CHAR)250);
+ case 0x00FC: return((CHAR)252);
+ case 0x00FD: return((CHAR)253);
+ case 0x0102: return((CHAR)195);
+ case 0x0103: return((CHAR)227);
+ case 0x0104: return((CHAR)161);
+ case 0x0105: return((CHAR)177);
+ case 0x0106: return((CHAR)198);
+ case 0x0107: return((CHAR)230);
+ case 0x010C: return((CHAR)200);
+ case 0x010D: return((CHAR)232);
+ case 0x010E: return((CHAR)207);
+ case 0x010F: return((CHAR)239);
+ case 0x0110: return((CHAR)208);
+ case 0x0111: return((CHAR)240);
+ case 0x0118: return((CHAR)202);
+ case 0x0119: return((CHAR)234);
+ case 0x011A: return((CHAR)204);
+ case 0x011B: return((CHAR)236);
+ case 0x0139: return((CHAR)197);
+ case 0x013A: return((CHAR)229);
+ case 0x013D: return((CHAR)165);
+ case 0x013E: return((CHAR)181);
+ case 0x0141: return((CHAR)163);
+ case 0x0142: return((CHAR)179);
+ case 0x0143: return((CHAR)209);
+ case 0x0144: return((CHAR)241);
+ case 0x0147: return((CHAR)210);
+ case 0x0148: return((CHAR)242);
+ case 0x0150: return((CHAR)213);
+ case 0x0151: return((CHAR)245);
+ case 0x0154: return((CHAR)192);
+ case 0x0155: return((CHAR)224);
+ case 0x0158: return((CHAR)216);
+ case 0x0159: return((CHAR)248);
+ case 0x015A: return((CHAR)166);
+ case 0x015B: return((CHAR)182);
+ case 0x015E: return((CHAR)170);
+ case 0x015F: return((CHAR)186);
+ case 0x0160: return((CHAR)169);
+ case 0x0161: return((CHAR)185);
+ case 0x0162: return((CHAR)222);
+ case 0x0163: return((CHAR)254);
+ case 0x0164: return((CHAR)171);
+ case 0x0165: return((CHAR)187);
+ case 0x016E: return((CHAR)217);
+ case 0x016F: return((CHAR)249);
+ case 0x0170: return((CHAR)219);
+ case 0x0171: return((CHAR)251);
+ case 0x0179: return((CHAR)172);
+ case 0x017A: return((CHAR)188);
+ case 0x017B: return((CHAR)175);
+ case 0x017C: return((CHAR)191);
+ case 0x017D: return((CHAR)174);
+ case 0x017E: return((CHAR)190);
+ case 0x02C7: return((CHAR)183);
+ case 0x02D8: return((CHAR)162);
+ case 0x02D9: return((CHAR)255);
+ case 0x02DB: return((CHAR)178);
+ case 0x02DD: return((CHAR)189);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* Latin-3 */
+#ifdef CK_ANSIC
+tx_8859_3(USHORT c)
+#else
+tx_8859_3(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)160);
+ case 0x00A3: return((CHAR)163);
+ case 0x00A4: return((CHAR)164);
+ case 0x00A7: return((CHAR)167);
+ case 0x00A8: return((CHAR)168);
+ case 0x00AD: return((CHAR)173);
+ case 0x00B0: return((CHAR)176);
+ case 0x00B2: return((CHAR)178);
+ case 0x00B3: return((CHAR)179);
+ case 0x00B4: return((CHAR)180);
+ case 0x00B5: return((CHAR)181);
+ case 0x00B7: return((CHAR)183);
+ case 0x00B8: return((CHAR)184);
+ case 0x00BD: return((CHAR)189);
+ case 0x00C0: return((CHAR)192);
+ case 0x00C1: return((CHAR)193);
+ case 0x00C2: return((CHAR)194);
+ case 0x00C4: return((CHAR)196);
+ case 0x00C7: return((CHAR)199);
+ case 0x00C8: return((CHAR)200);
+ case 0x00C9: return((CHAR)201);
+ case 0x00CA: return((CHAR)202);
+ case 0x00CB: return((CHAR)203);
+ case 0x00CC: return((CHAR)204);
+ case 0x00CD: return((CHAR)205);
+ case 0x00CE: return((CHAR)206);
+ case 0x00CF: return((CHAR)207);
+ case 0x00D1: return((CHAR)209);
+ case 0x00D2: return((CHAR)210);
+ case 0x00D3: return((CHAR)211);
+ case 0x00D4: return((CHAR)212);
+ case 0x00D6: return((CHAR)214);
+ case 0x00D7: return((CHAR)215);
+ case 0x00D9: return((CHAR)217);
+ case 0x00DA: return((CHAR)218);
+ case 0x00DB: return((CHAR)219);
+ case 0x00DC: return((CHAR)220);
+ case 0x00DF: return((CHAR)223);
+ case 0x00E0: return((CHAR)224);
+ case 0x00E1: return((CHAR)225);
+ case 0x00E2: return((CHAR)226);
+ case 0x00E4: return((CHAR)228);
+ case 0x00E7: return((CHAR)231);
+ case 0x00E8: return((CHAR)232);
+ case 0x00E9: return((CHAR)233);
+ case 0x00EA: return((CHAR)234);
+ case 0x00EB: return((CHAR)235);
+ case 0x00EC: return((CHAR)236);
+ case 0x00ED: return((CHAR)237);
+ case 0x00EE: return((CHAR)238);
+ case 0x00EF: return((CHAR)239);
+ case 0x00F1: return((CHAR)241);
+ case 0x00F2: return((CHAR)242);
+ case 0x00F3: return((CHAR)243);
+ case 0x00F4: return((CHAR)244);
+ case 0x00F6: return((CHAR)246);
+ case 0x00F7: return((CHAR)247);
+ case 0x00F9: return((CHAR)249);
+ case 0x00FA: return((CHAR)250);
+ case 0x00FB: return((CHAR)251);
+ case 0x00FC: return((CHAR)252);
+ case 0x0108: return((CHAR)198);
+ case 0x0109: return((CHAR)230);
+ case 0x010A: return((CHAR)197);
+ case 0x010B: return((CHAR)229);
+ case 0x011C: return((CHAR)216);
+ case 0x011D: return((CHAR)248);
+ case 0x011E: return((CHAR)171);
+ case 0x011F: return((CHAR)187);
+ case 0x0120: return((CHAR)213);
+ case 0x0121: return((CHAR)245);
+ case 0x0124: return((CHAR)166);
+ case 0x0125: return((CHAR)182);
+ case 0x0126: return((CHAR)161);
+ case 0x0127: return((CHAR)177);
+ case 0x0130: return((CHAR)169);
+ case 0x0131: return((CHAR)185);
+ case 0x0134: return((CHAR)172);
+ case 0x0135: return((CHAR)188);
+ case 0x015C: return((CHAR)222);
+ case 0x015D: return((CHAR)254);
+ case 0x015E: return((CHAR)170);
+ case 0x015F: return((CHAR)186);
+ case 0x016C: return((CHAR)221);
+ case 0x016D: return((CHAR)253);
+ case 0x017B: return((CHAR)175);
+ case 0x017C: return((CHAR)191);
+ case 0x02D8: return((CHAR)162);
+ case 0x02D9: return((CHAR)255);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* Latin-4 */
+#ifdef CK_ANSIC
+tx_8859_4(USHORT c)
+#else
+tx_8859_4(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)160);
+ case 0x00A4: return((CHAR)164);
+ case 0x00A7: return((CHAR)167);
+ case 0x00A8: return((CHAR)168);
+ case 0x00AD: return((CHAR)173);
+ case 0x00AF: return((CHAR)175);
+ case 0x00B0: return((CHAR)176);
+ case 0x00B4: return((CHAR)180);
+ case 0x00B8: return((CHAR)184);
+ case 0x00C1: return((CHAR)193);
+ case 0x00C2: return((CHAR)194);
+ case 0x00C3: return((CHAR)195);
+ case 0x00C4: return((CHAR)196);
+ case 0x00C5: return((CHAR)197);
+ case 0x00C6: return((CHAR)198);
+ case 0x00C9: return((CHAR)201);
+ case 0x00CB: return((CHAR)203);
+ case 0x00CD: return((CHAR)205);
+ case 0x00CE: return((CHAR)206);
+ case 0x00D4: return((CHAR)212);
+ case 0x00D5: return((CHAR)213);
+ case 0x00D6: return((CHAR)214);
+ case 0x00D7: return((CHAR)215);
+ case 0x00D8: return((CHAR)216);
+ case 0x00DA: return((CHAR)218);
+ case 0x00DB: return((CHAR)219);
+ case 0x00DC: return((CHAR)220);
+ case 0x00DF: return((CHAR)223);
+ case 0x00E1: return((CHAR)225);
+ case 0x00E2: return((CHAR)226);
+ case 0x00E3: return((CHAR)227);
+ case 0x00E4: return((CHAR)228);
+ case 0x00E5: return((CHAR)229);
+ case 0x00E6: return((CHAR)230);
+ case 0x00E9: return((CHAR)233);
+ case 0x00EB: return((CHAR)235);
+ case 0x00ED: return((CHAR)237);
+ case 0x00EE: return((CHAR)238);
+ case 0x00F4: return((CHAR)244);
+ case 0x00F5: return((CHAR)245);
+ case 0x00F6: return((CHAR)246);
+ case 0x00F7: return((CHAR)247);
+ case 0x00F8: return((CHAR)248);
+ case 0x00FA: return((CHAR)250);
+ case 0x00FB: return((CHAR)251);
+ case 0x00FC: return((CHAR)252);
+ case 0x0100: return((CHAR)192);
+ case 0x0101: return((CHAR)224);
+ case 0x0104: return((CHAR)161);
+ case 0x0105: return((CHAR)177);
+ case 0x010C: return((CHAR)200);
+ case 0x010D: return((CHAR)232);
+ case 0x0110: return((CHAR)208);
+ case 0x0111: return((CHAR)240);
+ case 0x0112: return((CHAR)170);
+ case 0x0113: return((CHAR)186);
+ case 0x0116: return((CHAR)204);
+ case 0x0117: return((CHAR)236);
+ case 0x0118: return((CHAR)202);
+ case 0x0119: return((CHAR)234);
+ case 0x0122: return((CHAR)171);
+ case 0x0123: return((CHAR)187);
+ case 0x0128: return((CHAR)165);
+ case 0x0129: return((CHAR)181);
+ case 0x012A: return((CHAR)207);
+ case 0x012B: return((CHAR)239);
+ case 0x012E: return((CHAR)199);
+ case 0x012F: return((CHAR)231);
+ case 0x0136: return((CHAR)211);
+ case 0x0137: return((CHAR)243);
+ case 0x0138: return((CHAR)162);
+ case 0x013B: return((CHAR)166);
+ case 0x013C: return((CHAR)182);
+ case 0x0145: return((CHAR)209);
+ case 0x0146: return((CHAR)241);
+ case 0x014A: return((CHAR)189);
+ case 0x014B: return((CHAR)191);
+ case 0x014C: return((CHAR)210);
+ case 0x014D: return((CHAR)242);
+ case 0x0156: return((CHAR)163);
+ case 0x0157: return((CHAR)179);
+ case 0x0160: return((CHAR)169);
+ case 0x0161: return((CHAR)185);
+ case 0x0166: return((CHAR)172);
+ case 0x0167: return((CHAR)188);
+ case 0x0168: return((CHAR)221);
+ case 0x0169: return((CHAR)253);
+ case 0x016A: return((CHAR)222);
+ case 0x016B: return((CHAR)254);
+ case 0x0172: return((CHAR)217);
+ case 0x0173: return((CHAR)249);
+ case 0x017D: return((CHAR)174);
+ case 0x017E: return((CHAR)190);
+ case 0x02C7: return((CHAR)183);
+ case 0x02D9: return((CHAR)255);
+ case 0x02DB: return((CHAR)178);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* ISO 8859-5 (Latin/Cyrillic) */
+#ifdef CK_ANSIC
+tx_8859_5(USHORT c)
+#else
+tx_8859_5(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0) /* (8859-5 is not Latin-5!) */
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)160);
+ case 0x00A7: return((CHAR)253);
+ case 0x00AD: return((CHAR)173);
+ case 0x0401: return((CHAR)161);
+ case 0x0402: return((CHAR)162);
+ case 0x0403: return((CHAR)163);
+ case 0x0404: return((CHAR)164);
+ case 0x0405: return((CHAR)165);
+ case 0x0406: return((CHAR)166);
+ case 0x0407: return((CHAR)167);
+ case 0x0408: return((CHAR)168);
+ case 0x0409: return((CHAR)169);
+ case 0x040A: return((CHAR)170);
+ case 0x040B: return((CHAR)171);
+ case 0x040C: return((CHAR)172);
+ case 0x040E: return((CHAR)174);
+ case 0x040F: return((CHAR)175);
+ case 0x0410: return((CHAR)176);
+ case 0x0411: return((CHAR)177);
+ case 0x0412: return((CHAR)178);
+ case 0x0413: return((CHAR)179);
+ case 0x0414: return((CHAR)180);
+ case 0x0415: return((CHAR)181);
+ case 0x0416: return((CHAR)182);
+ case 0x0417: return((CHAR)183);
+ case 0x0418: return((CHAR)184);
+ case 0x0419: return((CHAR)185);
+ case 0x041A: return((CHAR)186);
+ case 0x041B: return((CHAR)187);
+ case 0x041C: return((CHAR)188);
+ case 0x041D: return((CHAR)189);
+ case 0x041E: return((CHAR)190);
+ case 0x041F: return((CHAR)191);
+ case 0x0420: return((CHAR)192);
+ case 0x0421: return((CHAR)193);
+ case 0x0422: return((CHAR)194);
+ case 0x0423: return((CHAR)195);
+ case 0x0424: return((CHAR)196);
+ case 0x0425: return((CHAR)197);
+ case 0x0426: return((CHAR)198);
+ case 0x0427: return((CHAR)199);
+ case 0x0428: return((CHAR)200);
+ case 0x0429: return((CHAR)201);
+ case 0x042A: return((CHAR)202);
+ case 0x042B: return((CHAR)203);
+ case 0x042C: return((CHAR)204);
+ case 0x042D: return((CHAR)205);
+ case 0x042E: return((CHAR)206);
+ case 0x042F: return((CHAR)207);
+ case 0x0430: return((CHAR)208);
+ case 0x0431: return((CHAR)209);
+ case 0x0432: return((CHAR)210);
+ case 0x0433: return((CHAR)211);
+ case 0x0434: return((CHAR)212);
+ case 0x0435: return((CHAR)213);
+ case 0x0436: return((CHAR)214);
+ case 0x0437: return((CHAR)215);
+ case 0x0438: return((CHAR)216);
+ case 0x0439: return((CHAR)217);
+ case 0x043A: return((CHAR)218);
+ case 0x043B: return((CHAR)219);
+ case 0x043C: return((CHAR)220);
+ case 0x043D: return((CHAR)221);
+ case 0x043E: return((CHAR)222);
+ case 0x043F: return((CHAR)223);
+ case 0x0440: return((CHAR)224);
+ case 0x0441: return((CHAR)225);
+ case 0x0442: return((CHAR)226);
+ case 0x0443: return((CHAR)227);
+ case 0x0444: return((CHAR)228);
+ case 0x0445: return((CHAR)229);
+ case 0x0446: return((CHAR)230);
+ case 0x0447: return((CHAR)231);
+ case 0x0448: return((CHAR)232);
+ case 0x0449: return((CHAR)233);
+ case 0x044A: return((CHAR)234);
+ case 0x044B: return((CHAR)235);
+ case 0x044C: return((CHAR)236);
+ case 0x044D: return((CHAR)237);
+ case 0x044E: return((CHAR)238);
+ case 0x044F: return((CHAR)239);
+ case 0x0451: return((CHAR)241);
+ case 0x0452: return((CHAR)242);
+ case 0x0453: return((CHAR)243);
+ case 0x0454: return((CHAR)244);
+ case 0x0455: return((CHAR)245);
+ case 0x0456: return((CHAR)246);
+ case 0x0457: return((CHAR)247);
+ case 0x0458: return((CHAR)248);
+ case 0x0459: return((CHAR)249);
+ case 0x045A: return((CHAR)250);
+ case 0x045B: return((CHAR)251);
+ case 0x045C: return((CHAR)252);
+ case 0x045E: return((CHAR)254);
+ case 0x045F: return((CHAR)255);
+ case 0x2116: return((CHAR)240);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* ISO 8859-6 (Latin/Arabic) */
+#ifdef CK_ANSIC
+tx_8859_6(USHORT c)
+#else
+tx_8859_6(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0) /* (8859-6 != Latin-6) */
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)160);
+ case 0x00A4: return((CHAR)164);
+ case 0x00AD: return((CHAR)173);
+ case 0x060C: return((CHAR)172);
+ case 0x061B: return((CHAR)187);
+ case 0x061F: return((CHAR)191);
+ case 0x0621: return((CHAR)193);
+ case 0x0622: return((CHAR)194);
+ case 0x0623: return((CHAR)195);
+ case 0x0624: return((CHAR)196);
+ case 0x0625: return((CHAR)197);
+ case 0x0626: return((CHAR)198);
+ case 0x0627: return((CHAR)199);
+ case 0x0628: return((CHAR)200);
+ case 0x0629: return((CHAR)201);
+ case 0x062A: return((CHAR)202);
+ case 0x062B: return((CHAR)203);
+ case 0x062C: return((CHAR)204);
+ case 0x062D: return((CHAR)205);
+ case 0x062E: return((CHAR)206);
+ case 0x062F: return((CHAR)207);
+ case 0x0630: return((CHAR)208);
+ case 0x0631: return((CHAR)209);
+ case 0x0632: return((CHAR)210);
+ case 0x0633: return((CHAR)211);
+ case 0x0634: return((CHAR)212);
+ case 0x0635: return((CHAR)213);
+ case 0x0636: return((CHAR)214);
+ case 0x0637: return((CHAR)215);
+ case 0x0638: return((CHAR)216);
+ case 0x0639: return((CHAR)217);
+ case 0x063A: return((CHAR)218);
+ case 0x0640: return((CHAR)224);
+ case 0x0641: return((CHAR)225);
+ case 0x0642: return((CHAR)226);
+ case 0x0643: return((CHAR)227);
+ case 0x0644: return((CHAR)228);
+ case 0x0645: return((CHAR)229);
+ case 0x0646: return((CHAR)230);
+ case 0x0647: return((CHAR)231);
+ case 0x0648: return((CHAR)232);
+ case 0x0649: return((CHAR)233);
+ case 0x064A: return((CHAR)234);
+ case 0x064B: return((CHAR)235);
+ case 0x064C: return((CHAR)236);
+ case 0x064D: return((CHAR)237);
+ case 0x064E: return((CHAR)238);
+ case 0x064F: return((CHAR)239);
+ case 0x0650: return((CHAR)240);
+ case 0x0651: return((CHAR)241);
+ case 0x0652: return((CHAR)242);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* ISO 8859-7 (Latin/Greek) */
+#ifdef CK_ANSIC
+tx_8859_7(USHORT c)
+#else
+tx_8859_7(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00a0: return((CHAR)160);
+ case 0x00a3: return((CHAR)163);
+ case 0x00a6: return((CHAR)166);
+ case 0x00a7: return((CHAR)167);
+ case 0x00a8: return((CHAR)168);
+ case 0x00a9: return((CHAR)169);
+ case 0x00ab: return((CHAR)171);
+ case 0x00ac: return((CHAR)172);
+ case 0x00ad: return((CHAR)173);
+ case 0x00b0: return((CHAR)176);
+ case 0x00b1: return((CHAR)177);
+ case 0x00b2: return((CHAR)178);
+ case 0x00b3: return((CHAR)179);
+ case 0x00b7: return((CHAR)183);
+ case 0x00bb: return((CHAR)187);
+ case 0x00bd: return((CHAR)189);
+ case 0x02bc: return((CHAR)162);
+ case 0x02bd: return((CHAR)161);
+ case 0x0384: return((CHAR)180);
+ case 0x0385: return((CHAR)181);
+ case 0x0386: return((CHAR)182);
+ case 0x0388: return((CHAR)184);
+ case 0x0389: return((CHAR)185);
+ case 0x038a: return((CHAR)186);
+ case 0x038c: return((CHAR)188);
+ case 0x038e: return((CHAR)190);
+ case 0x038f: return((CHAR)191);
+ case 0x0390: return((CHAR)192);
+ case 0x0391: return((CHAR)193);
+ case 0x0392: return((CHAR)194);
+ case 0x0393: return((CHAR)195);
+ case 0x0394: return((CHAR)196);
+ case 0x0395: return((CHAR)197);
+ case 0x0396: return((CHAR)198);
+ case 0x0397: return((CHAR)199);
+ case 0x0398: return((CHAR)200);
+ case 0x0399: return((CHAR)201);
+ case 0x039a: return((CHAR)202);
+ case 0x039b: return((CHAR)203);
+ case 0x039c: return((CHAR)204);
+ case 0x039d: return((CHAR)205);
+ case 0x039e: return((CHAR)206);
+ case 0x039f: return((CHAR)207);
+ case 0x03a0: return((CHAR)208);
+ case 0x03a1: return((CHAR)209);
+ case 0x03a3: return((CHAR)211);
+ case 0x03a4: return((CHAR)212);
+ case 0x03a5: return((CHAR)213);
+ case 0x03a6: return((CHAR)214);
+ case 0x03a7: return((CHAR)215);
+ case 0x03a8: return((CHAR)216);
+ case 0x03a9: return((CHAR)217);
+ case 0x03aa: return((CHAR)218);
+ case 0x03ab: return((CHAR)219);
+ case 0x03ac: return((CHAR)220);
+ case 0x03ad: return((CHAR)221);
+ case 0x03ae: return((CHAR)222);
+ case 0x03af: return((CHAR)223);
+ case 0x03b0: return((CHAR)224);
+ case 0x03b1: return((CHAR)225);
+ case 0x03b2: return((CHAR)226);
+ case 0x03b3: return((CHAR)227);
+ case 0x03b4: return((CHAR)228);
+ case 0x03b5: return((CHAR)229);
+ case 0x03b6: return((CHAR)230);
+ case 0x03b7: return((CHAR)231);
+ case 0x03b8: return((CHAR)232);
+ case 0x03b9: return((CHAR)233);
+ case 0x03ba: return((CHAR)234);
+ case 0x03bb: return((CHAR)235);
+ case 0x03bc: return((CHAR)236);
+ case 0x03bd: return((CHAR)237);
+ case 0x03be: return((CHAR)238);
+ case 0x03bf: return((CHAR)239);
+ case 0x03c0: return((CHAR)240);
+ case 0x03c1: return((CHAR)241);
+ case 0x03c2: return((CHAR)242);
+ case 0x03c3: return((CHAR)243);
+ case 0x03c4: return((CHAR)244);
+ case 0x03c5: return((CHAR)245);
+ case 0x03c6: return((CHAR)246);
+ case 0x03c7: return((CHAR)247);
+ case 0x03c8: return((CHAR)248);
+ case 0x03c9: return((CHAR)249);
+ case 0x03ca: return((CHAR)250);
+ case 0x03cb: return((CHAR)251);
+ case 0x03cc: return((CHAR)252);
+ case 0x03cd: return((CHAR)253);
+ case 0x03ce: return((CHAR)254);
+ case 0x2015: return((CHAR)175);
+ case 0x2018: return((CHAR)161);
+ case 0x2019: return((CHAR)162);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* ISO 8859-8 (Latin/Hebrew) */
+#ifdef CK_ANSIC
+tx_8859_8(USHORT c)
+#else
+tx_8859_8(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00a0: return((CHAR)160);
+ case 0x00a2: return((CHAR)162);
+ case 0x00a3: return((CHAR)163);
+ case 0x00a4: return((CHAR)164);
+ case 0x00a5: return((CHAR)165);
+ case 0x00a6: return((CHAR)166);
+ case 0x00a7: return((CHAR)167);
+ case 0x00a8: return((CHAR)168);
+ case 0x00a9: return((CHAR)169);
+ case 0x00d7: return((CHAR)170);
+ case 0x00ab: return((CHAR)171);
+ case 0x00ac: return((CHAR)172);
+ case 0x00ad: return((CHAR)173);
+ case 0x00ae: return((CHAR)174);
+ case 0x203e: return((CHAR)175);
+ case 0x00b0: return((CHAR)176);
+ case 0x00b1: return((CHAR)177);
+ case 0x00b2: return((CHAR)178);
+ case 0x00b3: return((CHAR)179);
+ case 0x00b4: return((CHAR)180);
+ case 0x00b5: return((CHAR)181);
+ case 0x00b6: return((CHAR)182);
+ case 0x00b7: return((CHAR)183);
+ case 0x00b8: return((CHAR)184);
+ case 0x00b9: return((CHAR)185);
+ case 0x00f7: return((CHAR)186);
+ case 0x00bb: return((CHAR)187);
+ case 0x00bc: return((CHAR)188);
+ case 0x00bd: return((CHAR)189);
+ case 0x00be: return((CHAR)190);
+ case 0x2017: return((CHAR)223);
+ case 0x05d0: return((CHAR)224);
+ case 0x05d1: return((CHAR)225);
+ case 0x05d2: return((CHAR)226);
+ case 0x05d3: return((CHAR)227);
+ case 0x05d4: return((CHAR)228);
+ case 0x05d5: return((CHAR)229);
+ case 0x05d6: return((CHAR)230);
+ case 0x05d7: return((CHAR)231);
+ case 0x05d8: return((CHAR)232);
+ case 0x05d9: return((CHAR)233);
+ case 0x05da: return((CHAR)234);
+ case 0x05db: return((CHAR)235);
+ case 0x05dc: return((CHAR)236);
+ case 0x05dd: return((CHAR)237);
+ case 0x05de: return((CHAR)238);
+ case 0x05df: return((CHAR)239);
+ case 0x05e0: return((CHAR)240);
+ case 0x05e1: return((CHAR)241);
+ case 0x05e2: return((CHAR)242);
+ case 0x05e3: return((CHAR)243);
+ case 0x05e4: return((CHAR)244);
+ case 0x05e5: return((CHAR)245);
+ case 0x05e6: return((CHAR)246);
+ case 0x05e7: return((CHAR)247);
+ case 0x05e8: return((CHAR)248);
+ case 0x05e9: return((CHAR)249);
+ case 0x05ea: return((CHAR)250);
+ default: return(tx_punc(c));
+ }
+}
+
+int /* ISO 8859-9 (Latin-4) */
+#ifdef CK_ANSIC
+tx_8859_9(USHORT c)
+#else
+tx_8859_9(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x011E: return((CHAR)208); /* Differs from Latin-1 in */
+ case 0x011F: return((CHAR)240); /* only six places */
+ case 0x0130: return((CHAR)221);
+ case 0x0131: return((CHAR)253);
+ case 0x015E: return((CHAR)222);
+ case 0x015F: return((CHAR)254);
+ default: return(tx_ident(c));
+ }
+}
+
+int /* Latin-6 */
+#ifdef CK_ANSIC
+tx_8859_10(USHORT c)
+#else
+tx_8859_10(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00a0: return((CHAR)160);
+ case 0x00ad: return((CHAR)173);
+ case 0x00bd: return((CHAR)189);
+ case 0x00be: return((CHAR)190);
+ case 0x00c1: return((CHAR)193);
+ case 0x00c2: return((CHAR)194);
+ case 0x00c3: return((CHAR)195);
+ case 0x00c4: return((CHAR)196);
+ case 0x00c5: return((CHAR)197);
+ case 0x00c6: return((CHAR)198);
+ case 0x00c9: return((CHAR)201);
+ case 0x00cb: return((CHAR)203);
+ case 0x00cd: return((CHAR)205);
+ case 0x00ce: return((CHAR)206);
+ case 0x00cf: return((CHAR)207);
+ case 0x00d3: return((CHAR)211);
+ case 0x00d4: return((CHAR)212);
+ case 0x00d5: return((CHAR)213);
+ case 0x00d6: return((CHAR)214);
+ case 0x00d8: return((CHAR)216);
+ case 0x00da: return((CHAR)218);
+ case 0x00db: return((CHAR)219);
+ case 0x00dc: return((CHAR)220);
+ case 0x00dd: return((CHAR)221);
+ case 0x00de: return((CHAR)222);
+ case 0x00e1: return((CHAR)225);
+ case 0x00e2: return((CHAR)226);
+ case 0x00e3: return((CHAR)227);
+ case 0x00e4: return((CHAR)228);
+ case 0x00e5: return((CHAR)229);
+ case 0x00e6: return((CHAR)230);
+ case 0x00e9: return((CHAR)233);
+ case 0x00eb: return((CHAR)235);
+ case 0x00ed: return((CHAR)237);
+ case 0x00ee: return((CHAR)238);
+ case 0x00ef: return((CHAR)239);
+ case 0x00f0: return((CHAR)240);
+ case 0x00f1: return((CHAR)241);
+ case 0x00f3: return((CHAR)243);
+ case 0x00f4: return((CHAR)244);
+ case 0x00f5: return((CHAR)245);
+ case 0x00f6: return((CHAR)246);
+ case 0x00f8: return((CHAR)248);
+ case 0x00fa: return((CHAR)250);
+ case 0x00fb: return((CHAR)251);
+ case 0x00fc: return((CHAR)252);
+ case 0x00fd: return((CHAR)253);
+ case 0x00fe: return((CHAR)254);
+ case 0x0100: return((CHAR)192);
+ case 0x0101: return((CHAR)224);
+ case 0x0104: return((CHAR)161);
+ case 0x0105: return((CHAR)177);
+ case 0x010c: return((CHAR)200);
+ case 0x010d: return((CHAR)232);
+ case 0x0110: return((CHAR)208);
+ case 0x0111: return((CHAR)176);
+ case 0x0112: return((CHAR)162);
+ case 0x0113: return((CHAR)178);
+ case 0x0116: return((CHAR)204);
+ case 0x0117: return((CHAR)236);
+ case 0x0118: return((CHAR)202);
+ case 0x0119: return((CHAR)234);
+ case 0x0122: return((CHAR)163);
+ case 0x0123: return((CHAR)179);
+ case 0x0128: return((CHAR)165);
+ case 0x0129: return((CHAR)181);
+ case 0x012a: return((CHAR)164);
+ case 0x012b: return((CHAR)180);
+ case 0x012e: return((CHAR)199);
+ case 0x012f: return((CHAR)231);
+ case 0x0136: return((CHAR)166);
+ case 0x0137: return((CHAR)182);
+ case 0x0138: return((CHAR)174);
+ case 0x013b: return((CHAR)167);
+ case 0x013c: return((CHAR)183);
+ case 0x0143: return((CHAR)168);
+ case 0x0144: return((CHAR)184);
+ case 0x0145: return((CHAR)209);
+ case 0x014a: return((CHAR)175);
+ case 0x014b: return((CHAR)191);
+ case 0x014c: return((CHAR)210);
+ case 0x014d: return((CHAR)242);
+ case 0x0156: return((CHAR)169);
+ case 0x0157: return((CHAR)185);
+ case 0x0160: return((CHAR)170);
+ case 0x0161: return((CHAR)186);
+ case 0x0166: return((CHAR)171);
+ case 0x0167: return((CHAR)187);
+ case 0x0168: return((CHAR)215);
+ case 0x0169: return((CHAR)247);
+ case 0x016a: return((CHAR)223);
+ case 0x016b: return((CHAR)255);
+ case 0x0172: return((CHAR)217);
+ case 0x0173: return((CHAR)249);
+ case 0x017d: return((CHAR)172);
+ case 0x017e: return((CHAR)188);
+ default: return(tx_ident(c));
+ }
+}
+
+
+int /* ISO 8859-15 Latin-9 */
+#ifdef CK_ANSIC
+tx_8859_15(USHORT c)
+#else
+tx_8859_15(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x20AC: return((CHAR)0xA4); /* Differs from Latin-1 in */
+ case 0x0160: return((CHAR)0xAC); /* only eight places */
+ case 0x0161: return((CHAR)0xA8);
+ case 0x017D: return((CHAR)0xB4);
+ case 0x017E: return((CHAR)0xB8);
+ case 0x0152: return((CHAR)0xBC);
+ case 0x0153: return((CHAR)0xBD);
+ case 0x0178: return((CHAR)0xBE);
+ default: return(tx_ident(c));
+ }
+}
+
+int /* Old KOI-8 (ECMA 113 First Ed.) */
+#ifdef CK_ANSIC
+tx_koi8(USHORT c)
+#else
+tx_koi8(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x0410: return((CHAR)(225 & 0xff));
+ case 0x0411: return((CHAR)(226 & 0xff));
+ case 0x0412: return((CHAR)(247 & 0xff));
+ case 0x0413: return((CHAR)(231 & 0xff));
+ case 0x0414: return((CHAR)(228 & 0xff));
+ case 0x0415: return((CHAR)(229 & 0xff));
+ case 0x0416: return((CHAR)(246 & 0xff));
+ case 0x0417: return((CHAR)(250 & 0xff));
+ case 0x0418: return((CHAR)(233 & 0xff));
+ case 0x0419: return((CHAR)(234 & 0xff));
+ case 0x041a: return((CHAR)(235 & 0xff));
+ case 0x041b: return((CHAR)(236 & 0xff));
+ case 0x041c: return((CHAR)(237 & 0xff));
+ case 0x041d: return((CHAR)(238 & 0xff));
+ case 0x041e: return((CHAR)(239 & 0xff));
+ case 0x041f: return((CHAR)(240 & 0xff));
+ case 0x0420: return((CHAR)(242 & 0xff));
+ case 0x0421: return((CHAR)(243 & 0xff));
+ case 0x0422: return((CHAR)(244 & 0xff));
+ case 0x0423: return((CHAR)(245 & 0xff));
+ case 0x0424: return((CHAR)(230 & 0xff));
+ case 0x0425: return((CHAR)(232 & 0xff));
+ case 0x0426: return((CHAR)(227 & 0xff));
+ case 0x0427: return((CHAR)(254 & 0xff));
+ case 0x0428: return((CHAR)(251 & 0xff));
+ case 0x0429: return((CHAR)(253 & 0xff));
+ case 0x042b: return((CHAR)(249 & 0xff));
+ case 0x042c: return((CHAR)(248 & 0xff));
+ case 0x042d: return((CHAR)(252 & 0xff));
+ case 0x042e: return((CHAR)(224 & 0xff));
+ case 0x042f: return((CHAR)(241 & 0xff));
+ case 0x0430: return((CHAR)(193 & 0xff));
+ case 0x0431: return((CHAR)(194 & 0xff));
+ case 0x0432: return((CHAR)(215 & 0xff));
+ case 0x0433: return((CHAR)(199 & 0xff));
+ case 0x0434: return((CHAR)(196 & 0xff));
+ case 0x0435: return((CHAR)(197 & 0xff));
+ case 0x0436: return((CHAR)(214 & 0xff));
+ case 0x0437: return((CHAR)(218 & 0xff));
+ case 0x0438: return((CHAR)(201 & 0xff));
+ case 0x0439: return((CHAR)(202 & 0xff));
+ case 0x043a: return((CHAR)(203 & 0xff));
+ case 0x043b: return((CHAR)(204 & 0xff));
+ case 0x043c: return((CHAR)(205 & 0xff));
+ case 0x043d: return((CHAR)(206 & 0xff));
+ case 0x043e: return((CHAR)(207 & 0xff));
+ case 0x043f: return((CHAR)(208 & 0xff));
+ case 0x0440: return((CHAR)(210 & 0xff));
+ case 0x0441: return((CHAR)(211 & 0xff));
+ case 0x0442: return((CHAR)(212 & 0xff));
+ case 0x0443: return((CHAR)(213 & 0xff));
+ case 0x0444: return((CHAR)(198 & 0xff));
+ case 0x0445: return((CHAR)(200 & 0xff));
+ case 0x0446: return((CHAR)(195 & 0xff));
+ case 0x0447: return((CHAR)(222 & 0xff));
+ case 0x0448: return((CHAR)(219 & 0xff));
+ case 0x0449: return((CHAR)(221 & 0xff));
+ case 0x044a: return((CHAR)(223 & 0xff));
+ case 0x044b: return((CHAR)(217 & 0xff));
+ case 0x044c: return((CHAR)(216 & 0xff));
+ case 0x044d: return((CHAR)(220 & 0xff));
+ case 0x044e: return((CHAR)(192 & 0xff));
+ case 0x044f: return((CHAR)(209 & 0xff));
+ default: return(tx_ident(c));
+ }
+}
+
+int /* UCS-2 to KOI8-R (Russia) */
+#ifdef CK_ANSIC
+tx_koi8r(USHORT c)
+#else
+tx_koi8r(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x00A0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)(154 & 0xff));
+ case 0x00A9: return((CHAR)(191 & 0xff));
+ case 0x00B0: return((CHAR)(156 & 0xff));
+ case 0x00B2: return((CHAR)(157 & 0xff));
+ case 0x00B7: return((CHAR)(158 & 0xff));
+ case 0x00F7: return((CHAR)(159 & 0xff));
+ case 0x0401: return((CHAR)(179 & 0xff));
+ case 0x0410: return((CHAR)(225 & 0xff));
+ case 0x0411: return((CHAR)(226 & 0xff));
+ case 0x0412: return((CHAR)(247 & 0xff));
+ case 0x0413: return((CHAR)(231 & 0xff));
+ case 0x0414: return((CHAR)(228 & 0xff));
+ case 0x0415: return((CHAR)(229 & 0xff));
+ case 0x0416: return((CHAR)(246 & 0xff));
+ case 0x0417: return((CHAR)(250 & 0xff));
+ case 0x0418: return((CHAR)(233 & 0xff));
+ case 0x0419: return((CHAR)(234 & 0xff));
+ case 0x041A: return((CHAR)(235 & 0xff));
+ case 0x041B: return((CHAR)(236 & 0xff));
+ case 0x041C: return((CHAR)(237 & 0xff));
+ case 0x041D: return((CHAR)(238 & 0xff));
+ case 0x041E: return((CHAR)(239 & 0xff));
+ case 0x041F: return((CHAR)(240 & 0xff));
+ case 0x0420: return((CHAR)(242 & 0xff));
+ case 0x0421: return((CHAR)(243 & 0xff));
+ case 0x0422: return((CHAR)(244 & 0xff));
+ case 0x0423: return((CHAR)(245 & 0xff));
+ case 0x0424: return((CHAR)(230 & 0xff));
+ case 0x0425: return((CHAR)(232 & 0xff));
+ case 0x0426: return((CHAR)(227 & 0xff));
+ case 0x0427: return((CHAR)(254 & 0xff));
+ case 0x0428: return((CHAR)(251 & 0xff));
+ case 0x0429: return((CHAR)(253 & 0xff));
+ case 0x042A: return((CHAR)(255 & 0xff));
+ case 0x042B: return((CHAR)(249 & 0xff));
+ case 0x042C: return((CHAR)(248 & 0xff));
+ case 0x042D: return((CHAR)(252 & 0xff));
+ case 0x042E: return((CHAR)(224 & 0xff));
+ case 0x042F: return((CHAR)(241 & 0xff));
+ case 0x0430: return((CHAR)(193 & 0xff));
+ case 0x0431: return((CHAR)(194 & 0xff));
+ case 0x0432: return((CHAR)(215 & 0xff));
+ case 0x0433: return((CHAR)(199 & 0xff));
+ case 0x0434: return((CHAR)(196 & 0xff));
+ case 0x0435: return((CHAR)(197 & 0xff));
+ case 0x0436: return((CHAR)(214 & 0xff));
+ case 0x0437: return((CHAR)(218 & 0xff));
+ case 0x0438: return((CHAR)(201 & 0xff));
+ case 0x0439: return((CHAR)(202 & 0xff));
+ case 0x043A: return((CHAR)(203 & 0xff));
+ case 0x043B: return((CHAR)(204 & 0xff));
+ case 0x043C: return((CHAR)(205 & 0xff));
+ case 0x043D: return((CHAR)(206 & 0xff));
+ case 0x043E: return((CHAR)(207 & 0xff));
+ case 0x043F: return((CHAR)(208 & 0xff));
+ case 0x0440: return((CHAR)(210 & 0xff));
+ case 0x0441: return((CHAR)(211 & 0xff));
+ case 0x0442: return((CHAR)(212 & 0xff));
+ case 0x0443: return((CHAR)(213 & 0xff));
+ case 0x0444: return((CHAR)(198 & 0xff));
+ case 0x0445: return((CHAR)(200 & 0xff));
+ case 0x0446: return((CHAR)(195 & 0xff));
+ case 0x0447: return((CHAR)(222 & 0xff));
+ case 0x0448: return((CHAR)(219 & 0xff));
+ case 0x0449: return((CHAR)(221 & 0xff));
+ case 0x044A: return((CHAR)(223 & 0xff));
+ case 0x044B: return((CHAR)(217 & 0xff));
+ case 0x044C: return((CHAR)(216 & 0xff));
+ case 0x044D: return((CHAR)(220 & 0xff));
+ case 0x044E: return((CHAR)(192 & 0xff));
+ case 0x044F: return((CHAR)(209 & 0xff));
+ case 0x0451: return((CHAR)(163 & 0xff));
+ case 0x2219: return((CHAR)(149 & 0xff));
+ case 0x221A: return((CHAR)(150 & 0xff));
+ case 0x2248: return((CHAR)(151 & 0xff));
+ case 0x2264: return((CHAR)(152 & 0xff));
+ case 0x2265: return((CHAR)(153 & 0xff));
+ case 0x2320: return((CHAR)(147 & 0xff));
+ case 0x2321: return((CHAR)(155 & 0xff));
+ case 0x2500: return((CHAR)(128 & 0xff));
+ case 0x2502: return((CHAR)(129 & 0xff));
+ case 0x250C: return((CHAR)(130 & 0xff));
+ case 0x2510: return((CHAR)(131 & 0xff));
+ case 0x2514: return((CHAR)(132 & 0xff));
+ case 0x2518: return((CHAR)(133 & 0xff));
+ case 0x251C: return((CHAR)(134 & 0xff));
+ case 0x2524: return((CHAR)(135 & 0xff));
+ case 0x252C: return((CHAR)(136 & 0xff));
+ case 0x2534: return((CHAR)(137 & 0xff));
+ case 0x253C: return((CHAR)(138 & 0xff));
+ case 0x2550: return((CHAR)(160 & 0xff));
+ case 0x2551: return((CHAR)(161 & 0xff));
+ case 0x2552: return((CHAR)(162 & 0xff));
+ case 0x2553: return((CHAR)(164 & 0xff));
+ case 0x2554: return((CHAR)(165 & 0xff));
+ case 0x2555: return((CHAR)(166 & 0xff));
+ case 0x2556: return((CHAR)(167 & 0xff));
+ case 0x2557: return((CHAR)(168 & 0xff));
+ case 0x2558: return((CHAR)(169 & 0xff));
+ case 0x2559: return((CHAR)(170 & 0xff));
+ case 0x255A: return((CHAR)(171 & 0xff));
+ case 0x255B: return((CHAR)(172 & 0xff));
+ case 0x255C: return((CHAR)(173 & 0xff));
+ case 0x255D: return((CHAR)(174 & 0xff));
+ case 0x255E: return((CHAR)(175 & 0xff));
+ case 0x255F: return((CHAR)(176 & 0xff));
+ case 0x2560: return((CHAR)(177 & 0xff));
+ case 0x2561: return((CHAR)(178 & 0xff));
+ case 0x2562: return((CHAR)(180 & 0xff));
+ case 0x2563: return((CHAR)(181 & 0xff));
+ case 0x2564: return((CHAR)(182 & 0xff));
+ case 0x2565: return((CHAR)(183 & 0xff));
+ case 0x2566: return((CHAR)(184 & 0xff));
+ case 0x2567: return((CHAR)(185 & 0xff));
+ case 0x2568: return((CHAR)(186 & 0xff));
+ case 0x2569: return((CHAR)(187 & 0xff));
+ case 0x256A: return((CHAR)(188 & 0xff));
+ case 0x256B: return((CHAR)(189 & 0xff));
+ case 0x256C: return((CHAR)(190 & 0xff));
+ case 0x2580: return((CHAR)(139 & 0xff));
+ case 0x2584: return((CHAR)(140 & 0xff));
+ case 0x2588: return((CHAR)(141 & 0xff));
+ case 0x258C: return((CHAR)(142 & 0xff));
+ case 0x2590: return((CHAR)(143 & 0xff));
+ case 0x2591: return((CHAR)(144 & 0xff));
+ case 0x2592: return((CHAR)(145 & 0xff));
+ case 0x2593: return((CHAR)(146 & 0xff));
+ case 0x25A0: return((CHAR)(148 & 0xff));
+ default: return(tx_ident(c));
+ }
+}
+
+int /* KOI8-U (Ukraine) */
+#ifdef CK_ANSIC
+tx_koi8u(USHORT c)
+#else
+tx_koi8u(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00A0: return((CHAR)(154 & 0xff));
+ case 0x00A9: return((CHAR)(191 & 0xff));
+ case 0x00B0: return((CHAR)(156 & 0xff));
+ case 0x00B2: return((CHAR)(157 & 0xff));
+ case 0x00B7: return((CHAR)(158 & 0xff));
+ case 0x00F7: return((CHAR)(159 & 0xff));
+ case 0x0401: return((CHAR)(179 & 0xff));
+ case 0x0404: return((CHAR)(180 & 0xff));
+ case 0x0406: return((CHAR)(182 & 0xff));
+ case 0x0407: return((CHAR)(183 & 0xff));
+ case 0x0410: return((CHAR)(225 & 0xff));
+ case 0x0411: return((CHAR)(226 & 0xff));
+ case 0x0412: return((CHAR)(247 & 0xff));
+ case 0x0413: return((CHAR)(231 & 0xff));
+ case 0x0414: return((CHAR)(228 & 0xff));
+ case 0x0415: return((CHAR)(229 & 0xff));
+ case 0x0416: return((CHAR)(246 & 0xff));
+ case 0x0417: return((CHAR)(250 & 0xff));
+ case 0x0418: return((CHAR)(233 & 0xff));
+ case 0x0419: return((CHAR)(234 & 0xff));
+ case 0x041A: return((CHAR)(235 & 0xff));
+ case 0x041B: return((CHAR)(236 & 0xff));
+ case 0x041C: return((CHAR)(237 & 0xff));
+ case 0x041D: return((CHAR)(238 & 0xff));
+ case 0x041E: return((CHAR)(239 & 0xff));
+ case 0x041F: return((CHAR)(240 & 0xff));
+ case 0x0420: return((CHAR)(242 & 0xff));
+ case 0x0421: return((CHAR)(243 & 0xff));
+ case 0x0422: return((CHAR)(244 & 0xff));
+ case 0x0423: return((CHAR)(245 & 0xff));
+ case 0x0424: return((CHAR)(230 & 0xff));
+ case 0x0425: return((CHAR)(232 & 0xff));
+ case 0x0426: return((CHAR)(227 & 0xff));
+ case 0x0427: return((CHAR)(254 & 0xff));
+ case 0x0428: return((CHAR)(251 & 0xff));
+ case 0x0429: return((CHAR)(253 & 0xff));
+ case 0x042A: return((CHAR)(255 & 0xff));
+ case 0x042B: return((CHAR)(249 & 0xff));
+ case 0x042C: return((CHAR)(248 & 0xff));
+ case 0x042D: return((CHAR)(252 & 0xff));
+ case 0x042E: return((CHAR)(224 & 0xff));
+ case 0x042F: return((CHAR)(241 & 0xff));
+ case 0x0430: return((CHAR)(193 & 0xff));
+ case 0x0431: return((CHAR)(194 & 0xff));
+ case 0x0432: return((CHAR)(215 & 0xff));
+ case 0x0433: return((CHAR)(199 & 0xff));
+ case 0x0434: return((CHAR)(196 & 0xff));
+ case 0x0435: return((CHAR)(197 & 0xff));
+ case 0x0436: return((CHAR)(214 & 0xff));
+ case 0x0437: return((CHAR)(218 & 0xff));
+ case 0x0438: return((CHAR)(201 & 0xff));
+ case 0x0439: return((CHAR)(202 & 0xff));
+ case 0x043A: return((CHAR)(203 & 0xff));
+ case 0x043B: return((CHAR)(204 & 0xff));
+ case 0x043C: return((CHAR)(205 & 0xff));
+ case 0x043D: return((CHAR)(206 & 0xff));
+ case 0x043E: return((CHAR)(207 & 0xff));
+ case 0x043F: return((CHAR)(208 & 0xff));
+ case 0x0440: return((CHAR)(210 & 0xff));
+ case 0x0441: return((CHAR)(211 & 0xff));
+ case 0x0442: return((CHAR)(212 & 0xff));
+ case 0x0443: return((CHAR)(213 & 0xff));
+ case 0x0444: return((CHAR)(198 & 0xff));
+ case 0x0445: return((CHAR)(200 & 0xff));
+ case 0x0446: return((CHAR)(195 & 0xff));
+ case 0x0447: return((CHAR)(222 & 0xff));
+ case 0x0448: return((CHAR)(219 & 0xff));
+ case 0x0449: return((CHAR)(221 & 0xff));
+ case 0x044A: return((CHAR)(223 & 0xff));
+ case 0x044B: return((CHAR)(217 & 0xff));
+ case 0x044C: return((CHAR)(216 & 0xff));
+ case 0x044D: return((CHAR)(220 & 0xff));
+ case 0x044E: return((CHAR)(192 & 0xff));
+ case 0x044F: return((CHAR)(209 & 0xff));
+ case 0x0451: return((CHAR)(163 & 0xff));
+ case 0x0454: return((CHAR)(164 & 0xff));
+ case 0x0456: return((CHAR)(166 & 0xff));
+ case 0x0457: return((CHAR)(167 & 0xff));
+ case 0x0490: return((CHAR)(189 & 0xff));
+ case 0x0491: return((CHAR)(173 & 0xff));
+ case 0x2219: return((CHAR)(149 & 0xff));
+ case 0x221A: return((CHAR)(150 & 0xff));
+ case 0x2248: return((CHAR)(151 & 0xff));
+ case 0x2264: return((CHAR)(152 & 0xff));
+ case 0x2265: return((CHAR)(153 & 0xff));
+ case 0x2320: return((CHAR)(147 & 0xff));
+ case 0x2321: return((CHAR)(155 & 0xff));
+ case 0x2500: return((CHAR)(128 & 0xff));
+ case 0x2502: return((CHAR)(129 & 0xff));
+ case 0x250C: return((CHAR)(130 & 0xff));
+ case 0x2510: return((CHAR)(131 & 0xff));
+ case 0x2514: return((CHAR)(132 & 0xff));
+ case 0x2518: return((CHAR)(133 & 0xff));
+ case 0x251C: return((CHAR)(134 & 0xff));
+ case 0x2524: return((CHAR)(135 & 0xff));
+ case 0x252C: return((CHAR)(136 & 0xff));
+ case 0x2534: return((CHAR)(137 & 0xff));
+ case 0x253C: return((CHAR)(138 & 0xff));
+ case 0x2550: return((CHAR)(160 & 0xff));
+ case 0x2551: return((CHAR)(161 & 0xff));
+ case 0x2552: return((CHAR)(162 & 0xff));
+ case 0x2554: return((CHAR)(165 & 0xff));
+ case 0x2557: return((CHAR)(168 & 0xff));
+ case 0x2558: return((CHAR)(169 & 0xff));
+ case 0x2559: return((CHAR)(170 & 0xff));
+ case 0x255A: return((CHAR)(171 & 0xff));
+ case 0x255B: return((CHAR)(172 & 0xff));
+ case 0x255D: return((CHAR)(174 & 0xff));
+ case 0x255E: return((CHAR)(175 & 0xff));
+ case 0x255F: return((CHAR)(176 & 0xff));
+ case 0x2560: return((CHAR)(177 & 0xff));
+ case 0x2561: return((CHAR)(178 & 0xff));
+ case 0x2563: return((CHAR)(181 & 0xff));
+ case 0x2566: return((CHAR)(184 & 0xff));
+ case 0x2567: return((CHAR)(185 & 0xff));
+ case 0x2568: return((CHAR)(186 & 0xff));
+ case 0x2569: return((CHAR)(187 & 0xff));
+ case 0x256A: return((CHAR)(188 & 0xff));
+ case 0x256C: return((CHAR)(190 & 0xff));
+ case 0x2580: return((CHAR)(139 & 0xff));
+ case 0x2584: return((CHAR)(140 & 0xff));
+ case 0x2588: return((CHAR)(141 & 0xff));
+ case 0x258C: return((CHAR)(142 & 0xff));
+ case 0x2590: return((CHAR)(143 & 0xff));
+ case 0x2591: return((CHAR)(144 & 0xff));
+ case 0x2592: return((CHAR)(145 & 0xff));
+ case 0x2593: return((CHAR)(146 & 0xff));
+ case 0x25A0: return((CHAR)(148 & 0xff));
+ default: return(tx_ident(c));
+ }
+}
+
+
+int /* DEC MCS */
+#ifdef CK_ANSIC
+tx_decmcs(USHORT c)
+#else
+tx_decmcs(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00a6:
+ case 0x00a8:
+ case 0x00ac:
+ case 0x00ae:
+ case 0x00af:
+ case 0x00b4:
+ case 0x00b8:
+ case 0x00be:
+ case 0x00d0:
+ case 0x00de:
+ case 0x00f0:
+ case 0x00fe:
+ case 0x00ff:
+ return(-1); /* These are all undefined in DECMCS */
+ case 0x00a4: /* Currency sign */
+ return((CHAR)0xa8);
+ case 0x0152: /* OE */
+ return((CHAR)0xd7);
+ case 0x0153: /* oe */
+ return((CHAR)0xf7);
+ default: return(tx_ident(c));
+ }
+}
+
+int /* NeXTSTEP */
+#ifdef CK_ANSIC
+tx_nextstep(USHORT c)
+#else
+tx_nextstep(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(128 & 0xff));
+ case 0x00a1: return((CHAR)(161 & 0xff));
+ case 0x00a2: return((CHAR)(162 & 0xff));
+ case 0x00a3: return((CHAR)(163 & 0xff));
+ case 0x00a4: return((CHAR)(168 & 0xff));
+ case 0x00a5: return((CHAR)(165 & 0xff));
+ case 0x00a6: return((CHAR)(181 & 0xff));
+ case 0x00a7: return((CHAR)(167 & 0xff));
+ case 0x00a8: return((CHAR)(200 & 0xff));
+ case 0x00a9: return((CHAR)(160 & 0xff));
+ case 0x00aa: return((CHAR)(227 & 0xff));
+ case 0x00ab: return((CHAR)(171 & 0xff));
+ case 0x00ac: return((CHAR)(190 & 0xff));
+ case 0x00ae: return((CHAR)(176 & 0xff));
+ case 0x00af: return((CHAR)(197 & 0xff));
+ case 0x00b1: return((CHAR)(209 & 0xff));
+ case 0x00b2: return((CHAR)(201 & 0xff));
+ case 0x00b3: return((CHAR)(204 & 0xff));
+ case 0x00b4: return((CHAR)(194 & 0xff));
+ case 0x00b5: return((CHAR)(157 & 0xff));
+ case 0x00b6: return((CHAR)(182 & 0xff));
+ case 0x00b7: return((CHAR)(180 & 0xff));
+ case 0x00b8: return((CHAR)(203 & 0xff));
+ case 0x00b9: return((CHAR)(192 & 0xff));
+ case 0x00ba: return((CHAR)(235 & 0xff));
+ case 0x00bb: return((CHAR)(187 & 0xff));
+ case 0x00bc: return((CHAR)(210 & 0xff));
+ case 0x00bd: return((CHAR)(211 & 0xff));
+ case 0x00be: return((CHAR)(212 & 0xff));
+ case 0x00bf: return((CHAR)(191 & 0xff));
+ case 0x00c0: return((CHAR)(129 & 0xff));
+ case 0x00c1: return((CHAR)(130 & 0xff));
+ case 0x00c2: return((CHAR)(131 & 0xff));
+ case 0x00c3: return((CHAR)(132 & 0xff));
+ case 0x00c4: return((CHAR)(133 & 0xff));
+ case 0x00c5: return((CHAR)(134 & 0xff));
+ case 0x00c6: return((CHAR)(225 & 0xff));
+ case 0x00c7: return((CHAR)(135 & 0xff));
+ case 0x00c8: return((CHAR)(136 & 0xff));
+ case 0x00c9: return((CHAR)(137 & 0xff));
+ case 0x00ca: return((CHAR)(138 & 0xff));
+ case 0x00cb: return((CHAR)(139 & 0xff));
+ case 0x00cc: return((CHAR)(140 & 0xff));
+ case 0x00cd: return((CHAR)(141 & 0xff));
+ case 0x00ce: return((CHAR)(142 & 0xff));
+ case 0x00cf: return((CHAR)(143 & 0xff));
+ case 0x00d0: return((CHAR)(144 & 0xff));
+ case 0x00d1: return((CHAR)(145 & 0xff));
+ case 0x00d2: return((CHAR)(146 & 0xff));
+ case 0x00d3: return((CHAR)(147 & 0xff));
+ case 0x00d4: return((CHAR)(148 & 0xff));
+ case 0x00d5: return((CHAR)(149 & 0xff));
+ case 0x00d6: return((CHAR)(150 & 0xff));
+ case 0x00d7: return((CHAR)(158 & 0xff));
+ case 0x00d8: return((CHAR)(233 & 0xff));
+ case 0x00d9: return((CHAR)(151 & 0xff));
+ case 0x00da: return((CHAR)(152 & 0xff));
+ case 0x00db: return((CHAR)(153 & 0xff));
+ case 0x00dc: return((CHAR)(154 & 0xff));
+ case 0x00dd: return((CHAR)(155 & 0xff));
+ case 0x00de: return((CHAR)(156 & 0xff));
+ case 0x00df: return((CHAR)(251 & 0xff));
+ case 0x00e0: return((CHAR)(213 & 0xff));
+ case 0x00e1: return((CHAR)(214 & 0xff));
+ case 0x00e2: return((CHAR)(215 & 0xff));
+ case 0x00e3: return((CHAR)(216 & 0xff));
+ case 0x00e4: return((CHAR)(217 & 0xff));
+ case 0x00e5: return((CHAR)(218 & 0xff));
+ case 0x00e6: return((CHAR)(241 & 0xff));
+ case 0x00e7: return((CHAR)(219 & 0xff));
+ case 0x00e8: return((CHAR)(220 & 0xff));
+ case 0x00e9: return((CHAR)(221 & 0xff));
+ case 0x00ea: return((CHAR)(222 & 0xff));
+ case 0x00eb: return((CHAR)(223 & 0xff));
+ case 0x00ec: return((CHAR)(224 & 0xff));
+ case 0x00ed: return((CHAR)(226 & 0xff));
+ case 0x00ee: return((CHAR)(228 & 0xff));
+ case 0x00ef: return((CHAR)(229 & 0xff));
+ case 0x00f0: return((CHAR)(230 & 0xff));
+ case 0x00f1: return((CHAR)(231 & 0xff));
+ case 0x00f2: return((CHAR)(236 & 0xff));
+ case 0x00f3: return((CHAR)(237 & 0xff));
+ case 0x00f4: return((CHAR)(238 & 0xff));
+ case 0x00f5: return((CHAR)(239 & 0xff));
+ case 0x00f6: return((CHAR)(240 & 0xff));
+ case 0x00f7: return((CHAR)(159 & 0xff));
+ case 0x00f8: return((CHAR)(249 & 0xff));
+ case 0x00f9: return((CHAR)(242 & 0xff));
+ case 0x00fa: return((CHAR)(243 & 0xff));
+ case 0x00fb: return((CHAR)(244 & 0xff));
+ case 0x00fc: return((CHAR)(246 & 0xff));
+ case 0x00fd: return((CHAR)(247 & 0xff));
+ case 0x00fe: return((CHAR)(252 & 0xff));
+ case 0x00ff: return((CHAR)(253 & 0xff));
+ case 0x0131: return((CHAR)(245 & 0xff));
+ case 0x0141: return((CHAR)(232 & 0xff));
+ case 0x0142: return((CHAR)(248 & 0xff));
+ case 0x0152: return((CHAR)(234 & 0xff));
+ case 0x0153: return((CHAR)(250 & 0xff));
+ case 0x0192: return((CHAR)(166 & 0xff));
+ case 0x02c6: return((CHAR)(195 & 0xff));
+ case 0x02c7: return((CHAR)(207 & 0xff));
+ case 0x02cb: return((CHAR)(193 & 0xff));
+ case 0x02d8: return((CHAR)(198 & 0xff));
+ case 0x02d9: return((CHAR)(199 & 0xff));
+ case 0x02da: return((CHAR)(202 & 0xff));
+ case 0x02db: return((CHAR)(206 & 0xff));
+ case 0x02dc: return((CHAR)(196 & 0xff));
+ case 0x02dd: return((CHAR)(205 & 0xff));
+ case 0x2013: return((CHAR)(177 & 0xff));
+ case 0x2014: return((CHAR)(208 & 0xff));
+ case 0x2019: return((CHAR)(169 & 0xff));
+ case 0x201a: return((CHAR)(184 & 0xff));
+ case 0x201c: return((CHAR)(170 & 0xff));
+ case 0x201d: return((CHAR)(186 & 0xff));
+ case 0x201e: return((CHAR)(185 & 0xff));
+ case 0x2020: return((CHAR)(178 & 0xff));
+ case 0x2021: return((CHAR)(179 & 0xff));
+ case 0x2022: return((CHAR)(183 & 0xff));
+ case 0x2026: return((CHAR)(188 & 0xff));
+ case 0x2030: return((CHAR)(189 & 0xff));
+ case 0x2039: return((CHAR)(172 & 0xff));
+ case 0x203a: return((CHAR)(173 & 0xff));
+ case 0x2044: return((CHAR)(164 & 0xff));
+ case 0xfb01: return((CHAR)(174 & 0xff));
+ case 0xfb02: return((CHAR)(175 & 0xff));
+ default: return(tx_punc(c));
+ }
+}
+
+int /* DG International */
+#ifdef CK_ANSIC
+tx_dgi(USHORT c)
+#else
+tx_dgi(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00a0: return((CHAR)(160 & 0xff));
+ case 0x00a1: return((CHAR)(171 & 0xff));
+ case 0x00a2: return((CHAR)(167 & 0xff));
+ case 0x00a3: return((CHAR)(168 & 0xff));
+ case 0x00a4: return((CHAR)(166 & 0xff));
+ case 0x00a5: return((CHAR)(181 & 0xff));
+ case 0x00a7: return((CHAR)(187 & 0xff));
+ case 0x00a8: return((CHAR)(189 & 0xff));
+ case 0x00a9: return((CHAR)(173 & 0xff));
+ case 0x00aa: return((CHAR)(169 & 0xff));
+ case 0x00ab: return((CHAR)(177 & 0xff));
+ case 0x00ac: return((CHAR)(161 & 0xff));
+ case 0x00ae: return((CHAR)(174 & 0xff));
+ case 0x00b0: return((CHAR)(188 & 0xff));
+ case 0x00b1: return((CHAR)(182 & 0xff));
+ case 0x00b2: return((CHAR)(164 & 0xff));
+ case 0x00b3: return((CHAR)(165 & 0xff));
+ case 0x00b4: return((CHAR)(190 & 0xff));
+ case 0x00b5: return((CHAR)(163 & 0xff));
+ case 0x00b6: return((CHAR)(178 & 0xff));
+ case 0x00b7: return((CHAR)(185 & 0xff));
+ case 0x00b8: return((CHAR)(186 & 0xff));
+ case 0x00ba: return((CHAR)(170 & 0xff));
+ case 0x00bb: return((CHAR)(176 & 0xff));
+ case 0x00bd: return((CHAR)(162 & 0xff));
+ case 0x00bf: return((CHAR)(172 & 0xff));
+ case 0x00c0: return((CHAR)(193 & 0xff));
+ case 0x00c1: return((CHAR)(192 & 0xff));
+ case 0x00c2: return((CHAR)(194 & 0xff));
+ case 0x00c3: return((CHAR)(196 & 0xff));
+ case 0x00c4: return((CHAR)(195 & 0xff));
+ case 0x00c5: return((CHAR)(197 & 0xff));
+ case 0x00c6: return((CHAR)(198 & 0xff));
+ case 0x00c7: return((CHAR)(199 & 0xff));
+ case 0x00c8: return((CHAR)(201 & 0xff));
+ case 0x00c9: return((CHAR)(200 & 0xff));
+ case 0x00ca: return((CHAR)(202 & 0xff));
+ case 0x00cb: return((CHAR)(203 & 0xff));
+ case 0x00cc: return((CHAR)(205 & 0xff));
+ case 0x00cd: return((CHAR)(204 & 0xff));
+ case 0x00ce: return((CHAR)(206 & 0xff));
+ case 0x00cf: return((CHAR)(207 & 0xff));
+ case 0x00d1: return((CHAR)(208 & 0xff));
+ case 0x00d2: return((CHAR)(210 & 0xff));
+ case 0x00d3: return((CHAR)(209 & 0xff));
+ case 0x00d4: return((CHAR)(211 & 0xff));
+ case 0x00d5: return((CHAR)(213 & 0xff));
+ case 0x00d6: return((CHAR)(212 & 0xff));
+ case 0x00d8: return((CHAR)(214 & 0xff));
+ case 0x00d9: return((CHAR)(217 & 0xff));
+ case 0x00da: return((CHAR)(216 & 0xff));
+ case 0x00db: return((CHAR)(218 & 0xff));
+ case 0x00dc: return((CHAR)(219 & 0xff));
+ case 0x00df: return((CHAR)(252 & 0xff));
+ case 0x00e0: return((CHAR)(225 & 0xff));
+ case 0x00e1: return((CHAR)(224 & 0xff));
+ case 0x00e2: return((CHAR)(226 & 0xff));
+ case 0x00e3: return((CHAR)(228 & 0xff));
+ case 0x00e4: return((CHAR)(227 & 0xff));
+ case 0x00e5: return((CHAR)(229 & 0xff));
+ case 0x00e6: return((CHAR)(230 & 0xff));
+ case 0x00e7: return((CHAR)(231 & 0xff));
+ case 0x00e8: return((CHAR)(233 & 0xff));
+ case 0x00e9: return((CHAR)(232 & 0xff));
+ case 0x00ea: return((CHAR)(234 & 0xff));
+ case 0x00eb: return((CHAR)(235 & 0xff));
+ case 0x00ec: return((CHAR)(237 & 0xff));
+ case 0x00ed: return((CHAR)(236 & 0xff));
+ case 0x00ee: return((CHAR)(238 & 0xff));
+ case 0x00ef: return((CHAR)(239 & 0xff));
+ case 0x00f1: return((CHAR)(240 & 0xff));
+ case 0x00f2: return((CHAR)(242 & 0xff));
+ case 0x00f3: return((CHAR)(241 & 0xff));
+ case 0x00f4: return((CHAR)(243 & 0xff));
+ case 0x00f5: return((CHAR)(245 & 0xff));
+ case 0x00f6: return((CHAR)(244 & 0xff));
+ case 0x00f8: return((CHAR)(246 & 0xff));
+ case 0x00f9: return((CHAR)(249 & 0xff));
+ case 0x00fa: return((CHAR)(248 & 0xff));
+ case 0x00fb: return((CHAR)(250 & 0xff));
+ case 0x00fc: return((CHAR)(251 & 0xff));
+ case 0x00ff: return((CHAR)(253 & 0xff));
+ case 0x0153: return((CHAR)(247 & 0xff));
+ case 0x0178: return((CHAR)(221 & 0xff));
+ case 0x0192: return((CHAR)(180 & 0xff));
+ case 0x0276: return((CHAR)(215 & 0xff));
+ case 0x2021: return((CHAR)(175 & 0xff));
+ case 0x2122: return((CHAR)(179 & 0xff));
+ case 0x2191: return((CHAR)(191 & 0xff));
+ case 0x2264: return((CHAR)(183 & 0xff));
+ case 0x2265: return((CHAR)(184 & 0xff));
+ case 0x2588: return((CHAR)(255 & 0xff));
+ default: return(tx_punc(c));
+ }
+}
+
+int /* Macintosh Latin */
+#ifdef CK_ANSIC
+tx_maclatin(USHORT c)
+#else
+tx_maclatin(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(202 & 0xff));
+ case 0x00a1: return((CHAR)(193 & 0xff));
+ case 0x00a2: return((CHAR)(162 & 0xff));
+ case 0x00a3: return((CHAR)(163 & 0xff));
+ case 0x00a4: return((CHAR)(219 & 0xff));
+ case 0x00a5: return((CHAR)(180 & 0xff));
+ case 0x00a7: return((CHAR)(164 & 0xff));
+ case 0x00a8: return((CHAR)(172 & 0xff));
+ case 0x00a9: return((CHAR)(169 & 0xff));
+ case 0x00aa: return((CHAR)(187 & 0xff));
+ case 0x00ab: return((CHAR)(199 & 0xff));
+ case 0x00ac: return((CHAR)(194 & 0xff));
+ case 0x00ae: return((CHAR)(168 & 0xff));
+ case 0x00af: return((CHAR)(248 & 0xff));
+ case 0x00b0: return((CHAR)(161 & 0xff));
+ case 0x00b1: return((CHAR)(177 & 0xff));
+ case 0x00b4: return((CHAR)(171 & 0xff));
+ case 0x00b5: return((CHAR)(181 & 0xff));
+ case 0x00b6: return((CHAR)(166 & 0xff));
+ case 0x00b7: return((CHAR)(225 & 0xff));
+ case 0x00b8: return((CHAR)(252 & 0xff));
+ case 0x00ba: return((CHAR)(188 & 0xff));
+ case 0x00bb: return((CHAR)(200 & 0xff));
+ case 0x00bf: return((CHAR)(192 & 0xff));
+ case 0x00c0: return((CHAR)(203 & 0xff));
+ case 0x00c1: return((CHAR)(231 & 0xff));
+ case 0x00c2: return((CHAR)(229 & 0xff));
+ case 0x00c3: return((CHAR)(204 & 0xff));
+ case 0x00c4: return((CHAR)(128 & 0xff));
+ case 0x00c5: return((CHAR)(129 & 0xff));
+ case 0x00c6: return((CHAR)(174 & 0xff));
+ case 0x00c7: return((CHAR)(130 & 0xff));
+ case 0x00c8: return((CHAR)(233 & 0xff));
+ case 0x00c9: return((CHAR)(131 & 0xff));
+ case 0x00ca: return((CHAR)(230 & 0xff));
+ case 0x00cb: return((CHAR)(232 & 0xff));
+ case 0x00cc: return((CHAR)(237 & 0xff));
+ case 0x00cd: return((CHAR)(234 & 0xff));
+ case 0x00ce: return((CHAR)(235 & 0xff));
+ case 0x00cf: return((CHAR)(236 & 0xff));
+ case 0x00d0: return((CHAR)(220 & 0xff));
+ case 0x00d1: return((CHAR)(132 & 0xff));
+ case 0x00d2: return((CHAR)(241 & 0xff));
+ case 0x00d3: return((CHAR)(238 & 0xff));
+ case 0x00d4: return((CHAR)(239 & 0xff));
+ case 0x00d5: return((CHAR)(205 & 0xff));
+ case 0x00d6: return((CHAR)(133 & 0xff));
+ case 0x00d8: return((CHAR)(175 & 0xff));
+ case 0x00d9: return((CHAR)(244 & 0xff));
+ case 0x00da: return((CHAR)(242 & 0xff));
+ case 0x00db: return((CHAR)(243 & 0xff));
+ case 0x00dc: return((CHAR)(134 & 0xff));
+ case 0x00dd: return((CHAR)(160 & 0xff));
+ case 0x00de: return((CHAR)(222 & 0xff));
+ case 0x00df: return((CHAR)(167 & 0xff));
+ case 0x00e0: return((CHAR)(136 & 0xff));
+ case 0x00e1: return((CHAR)(135 & 0xff));
+ case 0x00e2: return((CHAR)(137 & 0xff));
+ case 0x00e3: return((CHAR)(139 & 0xff));
+ case 0x00e4: return((CHAR)(138 & 0xff));
+ case 0x00e5: return((CHAR)(140 & 0xff));
+ case 0x00e6: return((CHAR)(190 & 0xff));
+ case 0x00e7: return((CHAR)(141 & 0xff));
+ case 0x00e8: return((CHAR)(143 & 0xff));
+ case 0x00e9: return((CHAR)(142 & 0xff));
+ case 0x00ea: return((CHAR)(144 & 0xff));
+ case 0x00eb: return((CHAR)(145 & 0xff));
+ case 0x00ec: return((CHAR)(147 & 0xff));
+ case 0x00ed: return((CHAR)(146 & 0xff));
+ case 0x00ee: return((CHAR)(148 & 0xff));
+ case 0x00ef: return((CHAR)(149 & 0xff));
+ case 0x00f0: return((CHAR)(221 & 0xff));
+ case 0x00f1: return((CHAR)(150 & 0xff));
+ case 0x00f2: return((CHAR)(152 & 0xff));
+ case 0x00f3: return((CHAR)(151 & 0xff));
+ case 0x00f4: return((CHAR)(153 & 0xff));
+ case 0x00f5: return((CHAR)(155 & 0xff));
+ case 0x00f6: return((CHAR)(154 & 0xff));
+ case 0x00f7: return((CHAR)(214 & 0xff));
+ case 0x00f8: return((CHAR)(191 & 0xff));
+ case 0x00f9: return((CHAR)(157 & 0xff));
+ case 0x00fa: return((CHAR)(156 & 0xff));
+ case 0x00fb: return((CHAR)(158 & 0xff));
+ case 0x00fc: return((CHAR)(159 & 0xff));
+ case 0x00fd: return((CHAR)(224 & 0xff));
+ case 0x00fe: return((CHAR)(223 & 0xff));
+ case 0x00ff: return((CHAR)(216 & 0xff));
+ case 0x0131: return((CHAR)(245 & 0xff));
+ case 0x0152: return((CHAR)(206 & 0xff));
+ case 0x0153: return((CHAR)(207 & 0xff));
+ case 0x0178: return((CHAR)(217 & 0xff));
+ case 0x0192: return((CHAR)(196 & 0xff));
+ case 0x02c6: return((CHAR)(246 & 0xff));
+ case 0x02c7: return((CHAR)(255 & 0xff));
+ case 0x02d8: return((CHAR)(249 & 0xff));
+ case 0x02d9: return((CHAR)(250 & 0xff));
+ case 0x02da: return((CHAR)(251 & 0xff));
+ case 0x02db: return((CHAR)(254 & 0xff));
+ case 0x02dc: return((CHAR)(247 & 0xff));
+ case 0x02dd: return((CHAR)(253 & 0xff));
+ case 0x03c0: return((CHAR)(185 & 0xff));
+ case 0x2013: return((CHAR)(208 & 0xff));
+ case 0x2014: return((CHAR)(209 & 0xff));
+ case 0x2018: return((CHAR)(212 & 0xff));
+ case 0x2019: return((CHAR)(213 & 0xff));
+ case 0x201a: return((CHAR)(226 & 0xff));
+ case 0x201c: return((CHAR)(210 & 0xff));
+ case 0x201d: return((CHAR)(211 & 0xff));
+ case 0x201e: return((CHAR)(227 & 0xff));
+ case 0x2022: return((CHAR)(165 & 0xff));
+ case 0x2026: return((CHAR)(201 & 0xff));
+ case 0x2030: return((CHAR)(228 & 0xff));
+ case 0x2044: return((CHAR)(218 & 0xff));
+ case 0x2122: return((CHAR)(170 & 0xff));
+ case 0x2126: return((CHAR)(189 & 0xff));
+ case 0x2202: return((CHAR)(182 & 0xff));
+ case 0x2206: return((CHAR)(198 & 0xff));
+ case 0x220f: return((CHAR)(184 & 0xff));
+ case 0x2211: return((CHAR)(183 & 0xff));
+ case 0x221a: return((CHAR)(195 & 0xff));
+ case 0x221e: return((CHAR)(176 & 0xff));
+ case 0x222b: return((CHAR)(186 & 0xff));
+ case 0x2248: return((CHAR)(197 & 0xff));
+ case 0x2260: return((CHAR)(173 & 0xff));
+ case 0x2264: return((CHAR)(178 & 0xff));
+ case 0x2265: return((CHAR)(179 & 0xff));
+ case 0x25ca: return((CHAR)(215 & 0xff));
+ case 0xf8ff: return((CHAR)(240 & 0xff));
+ default: return(tx_punc(c));
+ }
+}
+
+int /* Apple QuickDraw / CP10000 */
+#ifdef CK_ANSIC
+tx_quickdraw(USHORT c)
+#else
+tx_quickdraw(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(202 & 0xff));
+ case 0x00a1: return((CHAR)(193 & 0xff));
+ case 0x00a2: return((CHAR)(162 & 0xff));
+ case 0x00a3: return((CHAR)(163 & 0xff));
+ case 0x00a4: return((CHAR)(219 & 0xff));
+ case 0x00a5: return((CHAR)(180 & 0xff));
+ case 0x00a7: return((CHAR)(164 & 0xff));
+ case 0x00a8: return((CHAR)(172 & 0xff));
+ case 0x00a9: return((CHAR)(169 & 0xff));
+ case 0x00aa: return((CHAR)(187 & 0xff));
+ case 0x00ab: return((CHAR)(199 & 0xff));
+ case 0x00ac: return((CHAR)(194 & 0xff));
+ case 0x00ae: return((CHAR)(168 & 0xff));
+ case 0x00af: return((CHAR)(248 & 0xff));
+ case 0x00b0: return((CHAR)(161 & 0xff));
+ case 0x00b1: return((CHAR)(177 & 0xff));
+ case 0x00b4: return((CHAR)(171 & 0xff));
+ case 0x00b5: return((CHAR)(181 & 0xff));
+ case 0x00b6: return((CHAR)(166 & 0xff));
+ case 0x00b7: return((CHAR)(225 & 0xff));
+ case 0x00b8: return((CHAR)(252 & 0xff));
+ case 0x00ba: return((CHAR)(188 & 0xff));
+ case 0x00bb: return((CHAR)(200 & 0xff));
+ case 0x00bf: return((CHAR)(192 & 0xff));
+ case 0x00c0: return((CHAR)(203 & 0xff));
+ case 0x00c1: return((CHAR)(231 & 0xff));
+ case 0x00c2: return((CHAR)(229 & 0xff));
+ case 0x00c3: return((CHAR)(204 & 0xff));
+ case 0x00c4: return((CHAR)(128 & 0xff));
+ case 0x00c5: return((CHAR)(129 & 0xff));
+ case 0x00c6: return((CHAR)(174 & 0xff));
+ case 0x00c7: return((CHAR)(130 & 0xff));
+ case 0x00c8: return((CHAR)(233 & 0xff));
+ case 0x00c9: return((CHAR)(131 & 0xff));
+ case 0x00ca: return((CHAR)(230 & 0xff));
+ case 0x00cb: return((CHAR)(232 & 0xff));
+ case 0x00cc: return((CHAR)(237 & 0xff));
+ case 0x00cd: return((CHAR)(234 & 0xff));
+ case 0x00ce: return((CHAR)(235 & 0xff));
+ case 0x00cf: return((CHAR)(236 & 0xff));
+ case 0x2039: return((CHAR)(220 & 0xff));
+ case 0x00d1: return((CHAR)(132 & 0xff));
+ case 0x00d2: return((CHAR)(241 & 0xff));
+ case 0x00d3: return((CHAR)(238 & 0xff));
+ case 0x00d4: return((CHAR)(239 & 0xff));
+ case 0x00d5: return((CHAR)(205 & 0xff));
+ case 0x00d6: return((CHAR)(133 & 0xff));
+ case 0x00d8: return((CHAR)(175 & 0xff));
+ case 0x00d9: return((CHAR)(244 & 0xff));
+ case 0x00da: return((CHAR)(242 & 0xff));
+ case 0x00db: return((CHAR)(243 & 0xff));
+ case 0x00dc: return((CHAR)(134 & 0xff));
+ case 0x2020: return((CHAR)(160 & 0xff));
+ case 0xfb01: return((CHAR)(222 & 0xff));
+ case 0x00df: return((CHAR)(167 & 0xff));
+ case 0x00e0: return((CHAR)(136 & 0xff));
+ case 0x00e1: return((CHAR)(135 & 0xff));
+ case 0x00e2: return((CHAR)(137 & 0xff));
+ case 0x00e3: return((CHAR)(139 & 0xff));
+ case 0x00e4: return((CHAR)(138 & 0xff));
+ case 0x00e5: return((CHAR)(140 & 0xff));
+ case 0x00e6: return((CHAR)(190 & 0xff));
+ case 0x00e7: return((CHAR)(141 & 0xff));
+ case 0x00e8: return((CHAR)(143 & 0xff));
+ case 0x00e9: return((CHAR)(142 & 0xff));
+ case 0x00ea: return((CHAR)(144 & 0xff));
+ case 0x00eb: return((CHAR)(145 & 0xff));
+ case 0x00ec: return((CHAR)(147 & 0xff));
+ case 0x00ed: return((CHAR)(146 & 0xff));
+ case 0x00ee: return((CHAR)(148 & 0xff));
+ case 0x00ef: return((CHAR)(149 & 0xff));
+ case 0x203a: return((CHAR)(221 & 0xff));
+ case 0x00f1: return((CHAR)(150 & 0xff));
+ case 0x00f2: return((CHAR)(152 & 0xff));
+ case 0x00f3: return((CHAR)(151 & 0xff));
+ case 0x00f4: return((CHAR)(153 & 0xff));
+ case 0x00f5: return((CHAR)(155 & 0xff));
+ case 0x00f6: return((CHAR)(154 & 0xff));
+ case 0x00f7: return((CHAR)(214 & 0xff));
+ case 0x00f8: return((CHAR)(191 & 0xff));
+ case 0x00f9: return((CHAR)(157 & 0xff));
+ case 0x00fa: return((CHAR)(156 & 0xff));
+ case 0x00fb: return((CHAR)(158 & 0xff));
+ case 0x00fc: return((CHAR)(159 & 0xff));
+ case 0x2021: return((CHAR)(224 & 0xff));
+ case 0xfb02: return((CHAR)(223 & 0xff));
+ case 0x00ff: return((CHAR)(216 & 0xff));
+ case 0x0131: return((CHAR)(245 & 0xff));
+ case 0x0152: return((CHAR)(206 & 0xff));
+ case 0x0153: return((CHAR)(207 & 0xff));
+ case 0x0178: return((CHAR)(217 & 0xff));
+ case 0x0192: return((CHAR)(196 & 0xff));
+ case 0x02c6: return((CHAR)(246 & 0xff));
+ case 0x02c7: return((CHAR)(255 & 0xff));
+ case 0x02d8: return((CHAR)(249 & 0xff));
+ case 0x02d9: return((CHAR)(250 & 0xff));
+ case 0x02da: return((CHAR)(251 & 0xff));
+ case 0x02db: return((CHAR)(254 & 0xff));
+ case 0x02dc: return((CHAR)(247 & 0xff));
+ case 0x02dd: return((CHAR)(253 & 0xff));
+ case 0x03c0: return((CHAR)(185 & 0xff));
+ case 0x2013: return((CHAR)(208 & 0xff));
+ case 0x2014: return((CHAR)(209 & 0xff));
+ case 0x2018: return((CHAR)(212 & 0xff));
+ case 0x2019: return((CHAR)(213 & 0xff));
+ case 0x201a: return((CHAR)(226 & 0xff));
+ case 0x201c: return((CHAR)(210 & 0xff));
+ case 0x201d: return((CHAR)(211 & 0xff));
+ case 0x201e: return((CHAR)(227 & 0xff));
+ case 0x2022: return((CHAR)(165 & 0xff));
+ case 0x2026: return((CHAR)(201 & 0xff));
+ case 0x2030: return((CHAR)(228 & 0xff));
+ case 0x2044: return((CHAR)(218 & 0xff));
+ case 0x2122: return((CHAR)(170 & 0xff));
+ case 0x03a9: return((CHAR)(189 & 0xff));
+ case 0x2202: return((CHAR)(182 & 0xff));
+ case 0x2206: return((CHAR)(198 & 0xff));
+ case 0x220f: return((CHAR)(184 & 0xff));
+ case 0x2211: return((CHAR)(183 & 0xff));
+ case 0x221a: return((CHAR)(195 & 0xff));
+ case 0x221e: return((CHAR)(176 & 0xff));
+ case 0x222b: return((CHAR)(186 & 0xff));
+ case 0x2248: return((CHAR)(197 & 0xff));
+ case 0x2260: return((CHAR)(173 & 0xff));
+ case 0x2264: return((CHAR)(178 & 0xff));
+ case 0x2265: return((CHAR)(179 & 0xff));
+ case 0x25ca: return((CHAR)(215 & 0xff));
+ case 0xf8ff: return((CHAR)(240 & 0xff));
+ default: return(tx_punc(c));
+ }
+}
+
+int /* HP Roman-8 */
+#ifdef CK_ANSIC
+tx_hproman8(USHORT c)
+#else
+tx_hproman8(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xa0)
+ return((CHAR)(c & 0xff));
+ switch(c) {
+ case 0x00a0: return((CHAR)(160 & 0xff));
+ case 0x00a1: return((CHAR)(171 & 0xff));
+ case 0x00a2: return((CHAR)(167 & 0xff));
+ case 0x00a3: return((CHAR)(168 & 0xff));
+ case 0x00a4: return((CHAR)(166 & 0xff));
+ case 0x00a5: return((CHAR)(181 & 0xff));
+ case 0x00a7: return((CHAR)(187 & 0xff));
+ case 0x00a8: return((CHAR)(189 & 0xff));
+ case 0x00a9: return((CHAR)(173 & 0xff));
+ case 0x00aa: return((CHAR)(169 & 0xff));
+ case 0x00ab: return((CHAR)(177 & 0xff));
+ case 0x00ac: return((CHAR)(161 & 0xff));
+ case 0x00ae: return((CHAR)(174 & 0xff));
+ case 0x00b0: return((CHAR)(188 & 0xff));
+ case 0x00b1: return((CHAR)(182 & 0xff));
+ case 0x00b2: return((CHAR)(164 & 0xff));
+ case 0x00b3: return((CHAR)(165 & 0xff));
+ case 0x00b4: return((CHAR)(190 & 0xff));
+ case 0x00b5: return((CHAR)(163 & 0xff));
+ case 0x00b6: return((CHAR)(178 & 0xff));
+ case 0x00b7: return((CHAR)(185 & 0xff));
+ case 0x00b8: return((CHAR)(186 & 0xff));
+ case 0x00ba: return((CHAR)(170 & 0xff));
+ case 0x00bb: return((CHAR)(176 & 0xff));
+ case 0x00bd: return((CHAR)(162 & 0xff));
+ case 0x00bf: return((CHAR)(172 & 0xff));
+ case 0x00c0: return((CHAR)(193 & 0xff));
+ case 0x00c1: return((CHAR)(192 & 0xff));
+ case 0x00c2: return((CHAR)(194 & 0xff));
+ case 0x00c3: return((CHAR)(196 & 0xff));
+ case 0x00c4: return((CHAR)(195 & 0xff));
+ case 0x00c5: return((CHAR)(197 & 0xff));
+ case 0x00c6: return((CHAR)(198 & 0xff));
+ case 0x00c7: return((CHAR)(199 & 0xff));
+ case 0x00c8: return((CHAR)(201 & 0xff));
+ case 0x00c9: return((CHAR)(200 & 0xff));
+ case 0x00ca: return((CHAR)(202 & 0xff));
+ case 0x00cb: return((CHAR)(203 & 0xff));
+ case 0x00cc: return((CHAR)(205 & 0xff));
+ case 0x00cd: return((CHAR)(204 & 0xff));
+ case 0x00ce: return((CHAR)(206 & 0xff));
+ case 0x00cf: return((CHAR)(207 & 0xff));
+ case 0x00d1: return((CHAR)(208 & 0xff));
+ case 0x00d2: return((CHAR)(210 & 0xff));
+ case 0x00d3: return((CHAR)(209 & 0xff));
+ case 0x00d4: return((CHAR)(211 & 0xff));
+ case 0x00d5: return((CHAR)(213 & 0xff));
+ case 0x00d6: return((CHAR)(212 & 0xff));
+ case 0x00d8: return((CHAR)(214 & 0xff));
+ case 0x00d9: return((CHAR)(217 & 0xff));
+ case 0x00da: return((CHAR)(216 & 0xff));
+ case 0x00db: return((CHAR)(218 & 0xff));
+ case 0x00dc: return((CHAR)(219 & 0xff));
+ case 0x00df: return((CHAR)(252 & 0xff));
+ case 0x00e0: return((CHAR)(225 & 0xff));
+ case 0x00e1: return((CHAR)(224 & 0xff));
+ case 0x00e2: return((CHAR)(226 & 0xff));
+ case 0x00e3: return((CHAR)(228 & 0xff));
+ case 0x00e4: return((CHAR)(227 & 0xff));
+ case 0x00e5: return((CHAR)(229 & 0xff));
+ case 0x00e6: return((CHAR)(230 & 0xff));
+ case 0x00e7: return((CHAR)(231 & 0xff));
+ case 0x00e8: return((CHAR)(233 & 0xff));
+ case 0x00e9: return((CHAR)(232 & 0xff));
+ case 0x00ea: return((CHAR)(234 & 0xff));
+ case 0x00eb: return((CHAR)(235 & 0xff));
+ case 0x00ec: return((CHAR)(237 & 0xff));
+ case 0x00ed: return((CHAR)(236 & 0xff));
+ case 0x00ee: return((CHAR)(238 & 0xff));
+ case 0x00ef: return((CHAR)(239 & 0xff));
+ case 0x00f1: return((CHAR)(240 & 0xff));
+ case 0x00f2: return((CHAR)(242 & 0xff));
+ case 0x00f3: return((CHAR)(241 & 0xff));
+ case 0x00f4: return((CHAR)(243 & 0xff));
+ case 0x00f5: return((CHAR)(245 & 0xff));
+ case 0x00f6: return((CHAR)(244 & 0xff));
+ case 0x00f8: return((CHAR)(246 & 0xff));
+ case 0x00f9: return((CHAR)(249 & 0xff));
+ case 0x00fa: return((CHAR)(248 & 0xff));
+ case 0x00fb: return((CHAR)(250 & 0xff));
+ case 0x00fc: return((CHAR)(251 & 0xff));
+ case 0x00ff: return((CHAR)(253 & 0xff));
+ case 0x0153: return((CHAR)(247 & 0xff));
+ case 0x0178: return((CHAR)(221 & 0xff));
+ case 0x0192: return((CHAR)(180 & 0xff));
+ case 0x0276: return((CHAR)(215 & 0xff));
+ case 0x2021: return((CHAR)(175 & 0xff));
+ case 0x2122: return((CHAR)(179 & 0xff));
+ case 0x2191: return((CHAR)(191 & 0xff));
+ case 0x2264: return((CHAR)(183 & 0xff));
+ case 0x2265: return((CHAR)(184 & 0xff));
+ case 0x2588: return((CHAR)(255 & 0xff));
+ default: return(tx_punc(c));
+ }
+}
+
+int /* PC Code Page 437 */
+#ifdef CK_ANSIC
+tx_cp437(USHORT c)
+#else
+tx_cp437(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ case 0x00a1: return((CHAR)(173 & 0xff));
+ case 0x00a2: return((CHAR)(155 & 0xff));
+ case 0x00a3: return((CHAR)(156 & 0xff));
+ case 0x00a4: return((CHAR)(15 & 0xff));
+ case 0x00a5: return((CHAR)(157 & 0xff));
+ case 0x00a6: return((CHAR)(124 & 0xff));
+ case 0x00a7: return((CHAR)(21 & 0xff));
+ case 0x00a8: return((CHAR)(34 & 0xff));
+ case 0x00a9: return((CHAR)(67 & 0xff));
+ case 0x00aa: return((CHAR)(166 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00ac: return((CHAR)(170 & 0xff));
+ case 0x00ad: return((CHAR)(45 & 0xff));
+ case 0x00ae: return((CHAR)(84 & 0xff));
+ case 0x00af: return((CHAR)(22 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00b1: return((CHAR)(241 & 0xff));
+ case 0x00b2: return((CHAR)(253 & 0xff));
+ case 0x00b3: return((CHAR)(51 & 0xff));
+ case 0x00b4: return((CHAR)(39 & 0xff));
+ case 0x00b5: return((CHAR)(230 & 0xff));
+ case 0x00b6: return((CHAR)(20 & 0xff));
+ case 0x00b7: return((CHAR)(250 & 0xff));
+ case 0x00b8: return((CHAR)(44 & 0xff));
+ case 0x00b9: return((CHAR)(49 & 0xff));
+ case 0x00ba: return((CHAR)(167 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x00bc: return((CHAR)(172 & 0xff));
+ case 0x00bd: return((CHAR)(171 & 0xff));
+ case 0x00be: return((CHAR)(19 & 0xff));
+ case 0x00bf: return((CHAR)(168 & 0xff));
+ case 0x00c0: return((CHAR)(65 & 0xff));
+ case 0x00c1: return((CHAR)(65 & 0xff));
+ case 0x00c2: return((CHAR)(65 & 0xff));
+ case 0x00c3: return((CHAR)(65 & 0xff));
+ case 0x00c4: return((CHAR)(142 & 0xff));
+ case 0x00c5: return((CHAR)(143 & 0xff));
+ case 0x00c6: return((CHAR)(146 & 0xff));
+ case 0x00c7: return((CHAR)(128 & 0xff));
+ case 0x00c8: return((CHAR)(69 & 0xff));
+ case 0x00c9: return((CHAR)(144 & 0xff));
+ case 0x00ca: return((CHAR)(69 & 0xff));
+ case 0x00cb: return((CHAR)(69 & 0xff));
+ case 0x00cc: return((CHAR)(73 & 0xff));
+ case 0x00cd: return((CHAR)(73 & 0xff));
+ case 0x00ce: return((CHAR)(73 & 0xff));
+ case 0x00cf: return((CHAR)(73 & 0xff));
+ case 0x00d0: return((CHAR)(19 & 0xff));
+ case 0x00d1: return((CHAR)(165 & 0xff));
+ case 0x00d2: return((CHAR)(79 & 0xff));
+ case 0x00d3: return((CHAR)(79 & 0xff));
+ case 0x00d4: return((CHAR)(79 & 0xff));
+ case 0x00d5: return((CHAR)(79 & 0xff));
+ case 0x00d6: return((CHAR)(153 & 0xff));
+ case 0x00d7: return((CHAR)(120 & 0xff));
+ case 0x00d8: return((CHAR)(79 & 0xff));
+ case 0x00d9: return((CHAR)(85 & 0xff));
+ case 0x00da: return((CHAR)(85 & 0xff));
+ case 0x00db: return((CHAR)(85 & 0xff));
+ case 0x00dc: return((CHAR)(154 & 0xff));
+ case 0x00dd: return((CHAR)(89 & 0xff));
+ case 0x00de: return((CHAR)(19 & 0xff));
+ case 0x00df: return((CHAR)(225 & 0xff));
+ case 0x00e0: return((CHAR)(133 & 0xff));
+ case 0x00e1: return((CHAR)(160 & 0xff));
+ case 0x00e2: return((CHAR)(131 & 0xff));
+ case 0x00e3: return((CHAR)(97 & 0xff)); /* a-tilde -> a (not 101 = e) */
+ case 0x00e4: return((CHAR)(132 & 0xff));
+ case 0x00e5: return((CHAR)(134 & 0xff));
+ case 0x00e6: return((CHAR)(145 & 0xff));
+ case 0x00e7: return((CHAR)(135 & 0xff));
+ case 0x00e8: return((CHAR)(138 & 0xff));
+ case 0x00e9: return((CHAR)(130 & 0xff));
+ case 0x00ea: return((CHAR)(136 & 0xff));
+ case 0x00eb: return((CHAR)(137 & 0xff));
+ case 0x00ec: return((CHAR)(141 & 0xff));
+ case 0x00ed: return((CHAR)(161 & 0xff));
+ case 0x00ee: return((CHAR)(140 & 0xff));
+ case 0x00ef: return((CHAR)(139 & 0xff));
+ case 0x00f0: return((CHAR)(19 & 0xff));
+ case 0x00f1: return((CHAR)(164 & 0xff));
+ case 0x00f2: return((CHAR)(149 & 0xff));
+ case 0x00f3: return((CHAR)(162 & 0xff));
+ case 0x00f4: return((CHAR)(147 & 0xff));
+ case 0x00f5: return((CHAR)(111 & 0xff));
+ case 0x00f6: return((CHAR)(148 & 0xff));
+ case 0x00f7: return((CHAR)(246 & 0xff));
+ case 0x00f8: return((CHAR)(111 & 0xff));
+ case 0x00f9: return((CHAR)(151 & 0xff));
+ case 0x00fa: return((CHAR)(163 & 0xff));
+ case 0x00fb: return((CHAR)(150 & 0xff));
+ case 0x00fc: return((CHAR)(129 & 0xff));
+ case 0x00fd: return((CHAR)(121 & 0xff));
+ case 0x00fe: return((CHAR)(19 & 0xff));
+ case 0x00ff: return((CHAR)(152 & 0xff));
+ case 0x0192: return((CHAR)(159 & 0xff));
+ case 0x0393: return((CHAR)(226 & 0xff));
+ case 0x0398: return((CHAR)(233 & 0xff));
+ case 0x03a3: return((CHAR)(228 & 0xff));
+ case 0x03a6: return((CHAR)(232 & 0xff));
+ case 0x03a9: return((CHAR)(234 & 0xff));
+ case 0x03b1: return((CHAR)(224 & 0xff));
+ case 0x03b4: return((CHAR)(235 & 0xff));
+ case 0x03b5: return((CHAR)(238 & 0xff));
+ case 0x03c0: return((CHAR)(227 & 0xff));
+ case 0x03c3: return((CHAR)(229 & 0xff));
+ case 0x03c4: return((CHAR)(231 & 0xff));
+ case 0x03c6: return((CHAR)(237 & 0xff));
+ case 0x207f: return((CHAR)(252 & 0xff));
+ case 0x20a7: return((CHAR)(158 & 0xff));
+ case 0x2219: return((CHAR)(249 & 0xff));
+ case 0x221a: return((CHAR)(251 & 0xff));
+ case 0x221e: return((CHAR)(236 & 0xff));
+ case 0x2229: return((CHAR)(239 & 0xff));
+ case 0x2248: return((CHAR)(247 & 0xff));
+ case 0x2261: return((CHAR)(240 & 0xff));
+ case 0x2264: return((CHAR)(243 & 0xff));
+ case 0x2265: return((CHAR)(242 & 0xff));
+ case 0x2310: return((CHAR)(169 & 0xff));
+ case 0x2320: return((CHAR)(244 & 0xff));
+ case 0x2321: return((CHAR)(245 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2552: return((CHAR)(213 & 0xff));
+ case 0x2553: return((CHAR)(214 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2555: return((CHAR)(184 & 0xff));
+ case 0x2556: return((CHAR)(183 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x2558: return((CHAR)(212 & 0xff));
+ case 0x2559: return((CHAR)(211 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255b: return((CHAR)(190 & 0xff));
+ case 0x255c: return((CHAR)(189 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x255e: return((CHAR)(198 & 0xff));
+ case 0x255f: return((CHAR)(199 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2561: return((CHAR)(181 & 0xff));
+ case 0x2562: return((CHAR)(182 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2564: return((CHAR)(209 & 0xff));
+ case 0x2565: return((CHAR)(210 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2567: return((CHAR)(207 & 0xff));
+ case 0x2568: return((CHAR)(208 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256a: return((CHAR)(216 & 0xff));
+ case 0x256b: return((CHAR)(215 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x258c: return((CHAR)(221 & 0xff));
+ case 0x2590: return((CHAR)(222 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff)); /* Black square */
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* Mazovia */
+#ifdef CK_ANSIC
+tx_mazovia(USHORT c)
+#else
+tx_mazovia(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00d3: return((CHAR)0xa3 & 0xff); /* O acute */
+ case 0x00f3: return((CHAR)0xa2 & 0xff); /* O acute */
+ case 0x0104: return((CHAR)0x8f & 0xff); /* A Ogonek */
+ case 0x0105: return((CHAR)0x86 & 0xff); /* a Ogonek */
+ case 0x0106: return((CHAR)0x95 & 0xff); /* C acute */
+ case 0x0107: return((CHAR)0x8d & 0xff); /* c acute */
+ case 0x0118: return((CHAR)0x90 & 0xff); /* E Ogonek */
+ case 0x0119: return((CHAR)0x91 & 0xff); /* E Ogonek */
+ case 0x0141: return((CHAR)0x9c & 0xff); /* L stroke */
+ case 0x0142: return((CHAR)0x92 & 0xff); /* L stroke */
+ case 0x0143: return((CHAR)0xa5 & 0xff); /* N acute */
+ case 0x0144: return((CHAR)0xa4 & 0xff); /* N acute */
+ case 0x015a: return((CHAR)0x98 & 0xff); /* S acute */
+ case 0x015b: return((CHAR)0x9e & 0xff); /* S acute */
+ case 0x0179: return((CHAR)0xa0 & 0xff); /* Z acute */
+ case 0x017a: return((CHAR)0xa6 & 0xff); /* Z acute */
+ case 0x017b: return((CHAR)0xa1 & 0xff); /* Z dot above */
+ case 0x017c: return((CHAR)0xa7 & 0xff); /* Z dot above */
+ default: return(tx_cp437(c));
+ }
+}
+
+int /* PC Code Page 850 */
+#ifdef CK_ANSIC
+tx_cp850(USHORT c)
+#else
+tx_cp850(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ case 0x00a1: return((CHAR)(173 & 0xff));
+ case 0x00a2: return((CHAR)(189 & 0xff));
+ case 0x00a3: return((CHAR)(156 & 0xff));
+ case 0x00a4: return((CHAR)(207 & 0xff));
+ case 0x00a5: return((CHAR)(190 & 0xff));
+ case 0x00a6: return((CHAR)(221 & 0xff));
+ case 0x00a7: return((CHAR)(245 & 0xff));
+ case 0x00a8: return((CHAR)(249 & 0xff));
+ case 0x00a9: return((CHAR)(184 & 0xff));
+ case 0x00aa: return((CHAR)(166 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00ac: return((CHAR)(170 & 0xff));
+ case 0x00ad: return((CHAR)(240 & 0xff));
+ case 0x00ae: return((CHAR)(169 & 0xff));
+ case 0x00af: return((CHAR)(238 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00b1: return((CHAR)(241 & 0xff));
+ case 0x00b2: return((CHAR)(253 & 0xff));
+ case 0x00b3: return((CHAR)(252 & 0xff));
+ case 0x00b4: return((CHAR)(239 & 0xff));
+ case 0x00b5: return((CHAR)(230 & 0xff));
+ case 0x00b6: return((CHAR)(244 & 0xff));
+ case 0x00b7: return((CHAR)(250 & 0xff));
+ case 0x00b8: return((CHAR)(247 & 0xff));
+ case 0x00b9: return((CHAR)(251 & 0xff));
+ case 0x00ba: return((CHAR)(167 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x00bc: return((CHAR)(172 & 0xff));
+ case 0x00bd: return((CHAR)(171 & 0xff));
+ case 0x00be: return((CHAR)(243 & 0xff));
+ case 0x00bf: return((CHAR)(168 & 0xff));
+ case 0x00c0: return((CHAR)(183 & 0xff));
+ case 0x00c1: return((CHAR)(181 & 0xff));
+ case 0x00c2: return((CHAR)(182 & 0xff));
+ case 0x00c3: return((CHAR)(199 & 0xff));
+ case 0x00c4: return((CHAR)(142 & 0xff));
+ case 0x00c5: return((CHAR)(143 & 0xff));
+ case 0x00c6: return((CHAR)(146 & 0xff));
+ case 0x00c7: return((CHAR)(128 & 0xff));
+ case 0x00c8: return((CHAR)(212 & 0xff));
+ case 0x00c9: return((CHAR)(144 & 0xff));
+ case 0x00ca: return((CHAR)(210 & 0xff));
+ case 0x00cb: return((CHAR)(211 & 0xff));
+ case 0x00cc: return((CHAR)(222 & 0xff));
+ case 0x00cd: return((CHAR)(214 & 0xff));
+ case 0x00ce: return((CHAR)(215 & 0xff));
+ case 0x00cf: return((CHAR)(216 & 0xff));
+ case 0x00d0: return((CHAR)(209 & 0xff));
+ case 0x00d1: return((CHAR)(165 & 0xff));
+ case 0x00d2: return((CHAR)(227 & 0xff));
+ case 0x00d3: return((CHAR)(224 & 0xff));
+ case 0x00d4: return((CHAR)(226 & 0xff));
+ case 0x00d5: return((CHAR)(229 & 0xff));
+ case 0x00d6: return((CHAR)(153 & 0xff));
+ case 0x00d7: return((CHAR)(158 & 0xff));
+ case 0x00d8: return((CHAR)(157 & 0xff));
+ case 0x00d9: return((CHAR)(235 & 0xff));
+ case 0x00da: return((CHAR)(233 & 0xff));
+ case 0x00db: return((CHAR)(234 & 0xff));
+ case 0x00dc: return((CHAR)(154 & 0xff));
+ case 0x00dd: return((CHAR)(237 & 0xff));
+ case 0x00de: return((CHAR)(232 & 0xff));
+ case 0x00df: return((CHAR)(225 & 0xff));
+ case 0x00e0: return((CHAR)(133 & 0xff));
+ case 0x00e1: return((CHAR)(160 & 0xff));
+ case 0x00e2: return((CHAR)(131 & 0xff));
+ case 0x00e3: return((CHAR)(198 & 0xff));
+ case 0x00e4: return((CHAR)(132 & 0xff));
+ case 0x00e5: return((CHAR)(134 & 0xff));
+ case 0x00e6: return((CHAR)(145 & 0xff));
+ case 0x00e7: return((CHAR)(135 & 0xff));
+ case 0x00e8: return((CHAR)(138 & 0xff));
+ case 0x00e9: return((CHAR)(130 & 0xff));
+ case 0x00ea: return((CHAR)(136 & 0xff));
+ case 0x00eb: return((CHAR)(137 & 0xff));
+ case 0x00ec: return((CHAR)(141 & 0xff));
+ case 0x00ed: return((CHAR)(161 & 0xff));
+ case 0x00ee: return((CHAR)(140 & 0xff));
+ case 0x00ef: return((CHAR)(139 & 0xff));
+ case 0x00f0: return((CHAR)(208 & 0xff));
+ case 0x00f1: return((CHAR)(164 & 0xff));
+ case 0x00f2: return((CHAR)(149 & 0xff));
+ case 0x00f3: return((CHAR)(162 & 0xff));
+ case 0x00f4: return((CHAR)(147 & 0xff));
+ case 0x00f5: return((CHAR)(228 & 0xff));
+ case 0x00f6: return((CHAR)(148 & 0xff));
+ case 0x00f7: return((CHAR)(246 & 0xff));
+ case 0x00f8: return((CHAR)(155 & 0xff));
+ case 0x00f9: return((CHAR)(151 & 0xff));
+ case 0x00fa: return((CHAR)(163 & 0xff));
+ case 0x00fb: return((CHAR)(150 & 0xff));
+ case 0x00fc: return((CHAR)(129 & 0xff));
+ case 0x00fd: return((CHAR)(236 & 0xff));
+ case 0x00fe: return((CHAR)(231 & 0xff));
+ case 0x00ff: return((CHAR)(152 & 0xff));
+ case 0x0131: return((CHAR)(213 & 0xff));
+ case 0x0192: return((CHAR)(159 & 0xff));
+ case 0x2017: return((CHAR)(242 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 858 */
+#ifdef CK_ANSIC
+tx_cp858(USHORT c)
+#else
+tx_cp858(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ case 0x00a1: return((CHAR)(173 & 0xff));
+ case 0x00a2: return((CHAR)(189 & 0xff));
+ case 0x00a3: return((CHAR)(156 & 0xff));
+ case 0x00a4: return((CHAR)(207 & 0xff));
+ case 0x00a5: return((CHAR)(190 & 0xff));
+ case 0x00a6: return((CHAR)(221 & 0xff));
+ case 0x00a7: return((CHAR)(245 & 0xff));
+ case 0x00a8: return((CHAR)(249 & 0xff));
+ case 0x00a9: return((CHAR)(184 & 0xff));
+ case 0x00aa: return((CHAR)(166 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00ac: return((CHAR)(170 & 0xff));
+ case 0x00ad: return((CHAR)(240 & 0xff));
+ case 0x00ae: return((CHAR)(169 & 0xff));
+ case 0x00af: return((CHAR)(238 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00b1: return((CHAR)(241 & 0xff));
+ case 0x00b2: return((CHAR)(253 & 0xff));
+ case 0x00b3: return((CHAR)(252 & 0xff));
+ case 0x00b4: return((CHAR)(239 & 0xff));
+ case 0x00b5: return((CHAR)(230 & 0xff));
+ case 0x00b6: return((CHAR)(244 & 0xff));
+ case 0x00b7: return((CHAR)(250 & 0xff));
+ case 0x00b8: return((CHAR)(247 & 0xff));
+ case 0x00b9: return((CHAR)(251 & 0xff));
+ case 0x00ba: return((CHAR)(167 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x00bc: return((CHAR)(172 & 0xff));
+ case 0x00bd: return((CHAR)(171 & 0xff));
+ case 0x00be: return((CHAR)(243 & 0xff));
+ case 0x00bf: return((CHAR)(168 & 0xff));
+ case 0x00c0: return((CHAR)(183 & 0xff));
+ case 0x00c1: return((CHAR)(181 & 0xff));
+ case 0x00c2: return((CHAR)(182 & 0xff));
+ case 0x00c3: return((CHAR)(199 & 0xff));
+ case 0x00c4: return((CHAR)(142 & 0xff));
+ case 0x00c5: return((CHAR)(143 & 0xff));
+ case 0x00c6: return((CHAR)(146 & 0xff));
+ case 0x00c7: return((CHAR)(128 & 0xff));
+ case 0x00c8: return((CHAR)(212 & 0xff));
+ case 0x00c9: return((CHAR)(144 & 0xff));
+ case 0x00ca: return((CHAR)(210 & 0xff));
+ case 0x00cb: return((CHAR)(211 & 0xff));
+ case 0x00cc: return((CHAR)(222 & 0xff));
+ case 0x00cd: return((CHAR)(214 & 0xff));
+ case 0x00ce: return((CHAR)(215 & 0xff));
+ case 0x00cf: return((CHAR)(216 & 0xff));
+ case 0x00d0: return((CHAR)(209 & 0xff));
+ case 0x00d1: return((CHAR)(165 & 0xff));
+ case 0x00d2: return((CHAR)(227 & 0xff));
+ case 0x00d3: return((CHAR)(224 & 0xff));
+ case 0x00d4: return((CHAR)(226 & 0xff));
+ case 0x00d5: return((CHAR)(229 & 0xff));
+ case 0x00d6: return((CHAR)(153 & 0xff));
+ case 0x00d7: return((CHAR)(158 & 0xff));
+ case 0x00d8: return((CHAR)(157 & 0xff));
+ case 0x00d9: return((CHAR)(235 & 0xff));
+ case 0x00da: return((CHAR)(233 & 0xff));
+ case 0x00db: return((CHAR)(234 & 0xff));
+ case 0x00dc: return((CHAR)(154 & 0xff));
+ case 0x00dd: return((CHAR)(237 & 0xff));
+ case 0x00de: return((CHAR)(232 & 0xff));
+ case 0x00df: return((CHAR)(225 & 0xff));
+ case 0x00e0: return((CHAR)(133 & 0xff));
+ case 0x00e1: return((CHAR)(160 & 0xff));
+ case 0x00e2: return((CHAR)(131 & 0xff));
+ case 0x00e3: return((CHAR)(198 & 0xff));
+ case 0x00e4: return((CHAR)(132 & 0xff));
+ case 0x00e5: return((CHAR)(134 & 0xff));
+ case 0x00e6: return((CHAR)(145 & 0xff));
+ case 0x00e7: return((CHAR)(135 & 0xff));
+ case 0x00e8: return((CHAR)(138 & 0xff));
+ case 0x00e9: return((CHAR)(130 & 0xff));
+ case 0x00ea: return((CHAR)(136 & 0xff));
+ case 0x00eb: return((CHAR)(137 & 0xff));
+ case 0x00ec: return((CHAR)(141 & 0xff));
+ case 0x00ed: return((CHAR)(161 & 0xff));
+ case 0x00ee: return((CHAR)(140 & 0xff));
+ case 0x00ef: return((CHAR)(139 & 0xff));
+ case 0x00f0: return((CHAR)(208 & 0xff));
+ case 0x00f1: return((CHAR)(164 & 0xff));
+ case 0x00f2: return((CHAR)(149 & 0xff));
+ case 0x00f3: return((CHAR)(162 & 0xff));
+ case 0x00f4: return((CHAR)(147 & 0xff));
+ case 0x00f5: return((CHAR)(228 & 0xff));
+ case 0x00f6: return((CHAR)(148 & 0xff));
+ case 0x00f7: return((CHAR)(246 & 0xff));
+ case 0x00f8: return((CHAR)(155 & 0xff));
+ case 0x00f9: return((CHAR)(151 & 0xff));
+ case 0x00fa: return((CHAR)(163 & 0xff));
+ case 0x00fb: return((CHAR)(150 & 0xff));
+ case 0x00fc: return((CHAR)(129 & 0xff));
+ case 0x00fd: return((CHAR)(236 & 0xff));
+ case 0x00fe: return((CHAR)(231 & 0xff));
+ case 0x00ff: return((CHAR)(152 & 0xff));
+ case 0x20ac: return((CHAR)(213 & 0xff));
+ case 0x0192: return((CHAR)(159 & 0xff));
+ case 0x2017: return((CHAR)(242 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* Windows Code Page 1250 (Latin-2) */
+#ifdef CK_ANSIC
+tx_cp1250(USHORT c)
+#else
+tx_cp1250(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80 || (c > 0xbf && c <= 0xff)) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x002D: return((CHAR)(0xad & 0xff));
+ case 0x00A0: return((CHAR)(0xa0 & 0xff));
+ case 0x00A4: return((CHAR)(0xa4 & 0xff));
+ case 0x00A6: return((CHAR)(0xa6 & 0xff));
+ case 0x00A7: return((CHAR)(0xa7 & 0xff));
+ case 0x00A8: return((CHAR)(0xa8 & 0xff));
+ case 0x00A9: return((CHAR)(0xa9 & 0xff));
+ case 0x00AB: return((CHAR)(0xab & 0xff));
+ case 0x00AC: return((CHAR)(0xac & 0xff));
+ case 0x00AE: return((CHAR)(0xae & 0xff));
+ case 0x00B0: return((CHAR)(0xb0 & 0xff));
+ case 0x00B1: return((CHAR)(0xb1 & 0xff));
+ case 0x00B4: return((CHAR)(0xb4 & 0xff));
+ case 0x00B5: return((CHAR)(0xb5 & 0xff));
+ case 0x00B6: return((CHAR)(0xb6 & 0xff));
+ case 0x00B7: return((CHAR)(0xb7 & 0xff));
+ case 0x00B8: return((CHAR)(0xb8 & 0xff));
+ case 0x00BB: return((CHAR)(0xbb & 0xff));
+ case 0x0104: return((CHAR)(0xa5 & 0xff));
+ case 0x0105: return((CHAR)(0xb9 & 0xff));
+ case 0x013D: return((CHAR)(0xbc & 0xff));
+ case 0x013E: return((CHAR)(0xbe & 0xff));
+ case 0x0141: return((CHAR)(0xa3 & 0xff));
+ case 0x0142: return((CHAR)(0xb3 & 0xff));
+ case 0x015A: return((CHAR)(0x8c & 0xff)); /* S acute */
+ case 0x015E: return((CHAR)(0xaa & 0xff));
+ case 0x015F: return((CHAR)(0xba & 0xff));
+ case 0x015b: return((CHAR)(0x9c & 0xff)); /* s acute */
+ case 0x0164: return((CHAR)(0x8d & 0xff)); /* T caron */
+ case 0x0165: return((CHAR)(0x9d & 0xff)); /* t caron */
+ case 0x0173: return((CHAR)(0x9e & 0xff)); /* z caron */
+ case 0x0179: return((CHAR)(0x8f & 0xff)); /* Z acute */
+ case 0x017A: return((CHAR)(0x9f & 0xff)); /* z acute */
+ case 0x017B: return((CHAR)(0xaf & 0xff));
+ case 0x017C: return((CHAR)(0xbf & 0xff));
+ case 0x017D: return((CHAR)(0x8e & 0xff)); /* Z caron */
+ case 0x02C7: return((CHAR)(0xa1 & 0xff));
+ case 0x02D8: return((CHAR)(0xa2 & 0xff));
+ case 0x02DB: return((CHAR)(0xb2 & 0xff));
+ case 0x02DD: return((CHAR)(0xbd & 0xff));
+ case 0x2010: case 0x2011: /* Hyphens */
+ return((CHAR)(0x2d & 0xff));
+ case 0x2012: case 0x2013: /* en-dashes */
+ return((CHAR)(0x96 & 0xff));
+ case 0x2014: case 0x2015: /* em-dashes */
+ return((CHAR)(0x97 & 0xff));
+ case 0x2018: /* Various quotation marks... */
+ return((CHAR)(0x91 & 0xff));
+ case 0x2019:
+ return((CHAR)(0x92 & 0xff));
+ case 0x201c:
+ return((CHAR)(0x93 & 0xff));
+ case 0x201d:
+ return((CHAR)(0x94 & 0xff));
+ case 0x201e:
+ return((CHAR)(0x84 & 0xff));
+ case 0x2020: /* Dagger */
+ return((CHAR)(0x86 & 0xff));
+ case 0x2021: /* Double Dagger */
+ return((CHAR)(0x87 & 0xff));
+ case 0x2022: /* Bullet */
+ return((CHAR)(0x95 & 0xff));
+ case 0x2026: /* Ellipsis */
+ return((CHAR)(0x85 & 0xff));
+ case 0x2030: /* Per mil */
+ return((CHAR)(0x89 & 0xff));
+ case 0x20AC: /* Euro */
+ return((CHAR)(0x80 & 0xff));
+ case 0x2122: /* Trade Mark */
+ return((CHAR)(0x99 & 0xff));
+ default: return(0x003f);
+ }
+}
+
+int /* Windows Code Page 1251 (Cyrillic) */
+#ifdef CK_ANSIC
+tx_cp1251(USHORT c)
+#else
+tx_cp1251(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ /* This is simply the inverse of u_cp1251.map */
+ switch (c) {
+ case 0x003c: return((CHAR)(0x8b & 0xff));
+ case 0x003e: return((CHAR)(0x9b & 0xff));
+ case 0x007e: return((CHAR)(0x98 & 0xff));
+ case 0x00A0: return((CHAR)(0xa0 & 0xff));
+ case 0x00A4: return((CHAR)(0xa4 & 0xff));
+ case 0x00A6: return((CHAR)(0xa6 & 0xff));
+ case 0x00A7: return((CHAR)(0xa7 & 0xff));
+ case 0x00A9: return((CHAR)(0xa9 & 0xff));
+ case 0x00AB: return((CHAR)(0xab & 0xff));
+ case 0x00AC: return((CHAR)(0xac & 0xff));
+ case 0x00AD: return((CHAR)(0xad & 0xff));
+ case 0x00AE: return((CHAR)(0xae & 0xff));
+ case 0x00b0: return((CHAR)(0xb0 & 0xff));
+ case 0x00b1: return((CHAR)(0xb1 & 0xff));
+ case 0x00B5: return((CHAR)(0xb5 & 0xff));
+ case 0x00B6: return((CHAR)(0xb6 & 0xff));
+ case 0x00B7: return((CHAR)(0xb7 & 0xff));
+ case 0x00BB: return((CHAR)(0xbb & 0xff));
+ case 0x0401: return((CHAR)(0xa8 & 0xff));
+ case 0x0402: return((CHAR)(0x80 & 0xff));
+ case 0x0403: return((CHAR)(0x81 & 0xff));
+ case 0x0404: return((CHAR)(0xaa & 0xff));
+ case 0x0405: return((CHAR)(0xbd & 0xff));
+ case 0x0406: return((CHAR)(0xb2 & 0xff));
+ case 0x0407: return((CHAR)(0xaf & 0xff));
+ case 0x0408: return((CHAR)(0xa3 & 0xff));
+ case 0x0409: return((CHAR)(0x8a & 0xff));
+ case 0x040a: return((CHAR)(0x8c & 0xff));
+ case 0x040b: return((CHAR)(0x8e & 0xff));
+ case 0x040c: return((CHAR)(0x8d & 0xff));
+ case 0x040e: return((CHAR)(0xa1 & 0xff));
+ case 0x040f: return((CHAR)(0x8f & 0xff));
+ case 0x0410: return((CHAR)(0xc0 & 0xff));
+ case 0x0411: return((CHAR)(0xc1 & 0xff));
+ case 0x0412: return((CHAR)(0xc2 & 0xff));
+ case 0x0413: return((CHAR)(0xc3 & 0xff));
+ case 0x0414: return((CHAR)(0xc4 & 0xff));
+ case 0x0415: return((CHAR)(0xc5 & 0xff));
+ case 0x0416: return((CHAR)(0xc6 & 0xff));
+ case 0x0417: return((CHAR)(0xc7 & 0xff));
+ case 0x0418: return((CHAR)(0xc8 & 0xff));
+ case 0x0419: return((CHAR)(0xc9 & 0xff));
+ case 0x041a: return((CHAR)(0xca & 0xff));
+ case 0x041b: return((CHAR)(0xcb & 0xff));
+ case 0x041c: return((CHAR)(0xcc & 0xff));
+ case 0x041d: return((CHAR)(0xcd & 0xff));
+ case 0x041e: return((CHAR)(0xce & 0xff));
+ case 0x041f: return((CHAR)(0xcf & 0xff));
+ case 0x0420: return((CHAR)(0xd0 & 0xff));
+ case 0x0421: return((CHAR)(0xd1 & 0xff));
+ case 0x0422: return((CHAR)(0xd2 & 0xff));
+ case 0x0423: return((CHAR)(0xd3 & 0xff));
+ case 0x0424: return((CHAR)(0xd4 & 0xff));
+ case 0x0425: return((CHAR)(0xd5 & 0xff));
+ case 0x0426: return((CHAR)(0xd6 & 0xff));
+ case 0x0427: return((CHAR)(0xd7 & 0xff));
+ case 0x0428: return((CHAR)(0xd8 & 0xff));
+ case 0x0429: return((CHAR)(0xd9 & 0xff));
+ case 0x042a: return((CHAR)(0xda & 0xff));
+ case 0x042b: return((CHAR)(0xdb & 0xff));
+ case 0x042c: return((CHAR)(0xdc & 0xff));
+ case 0x042d: return((CHAR)(0xdd & 0xff));
+ case 0x042e: return((CHAR)(0xde & 0xff));
+ case 0x042f: return((CHAR)(0xdf & 0xff));
+ case 0x0430: return((CHAR)(0xe0 & 0xff));
+ case 0x0431: return((CHAR)(0xe1 & 0xff));
+ case 0x0432: return((CHAR)(0xe2 & 0xff));
+ case 0x0433: return((CHAR)(0xe3 & 0xff));
+ case 0x0434: return((CHAR)(0xe4 & 0xff));
+ case 0x0435: return((CHAR)(0xe5 & 0xff));
+ case 0x0436: return((CHAR)(0xe6 & 0xff));
+ case 0x0437: return((CHAR)(0xe7 & 0xff));
+ case 0x0438: return((CHAR)(0xe8 & 0xff));
+ case 0x0439: return((CHAR)(0xe9 & 0xff));
+ case 0x043a: return((CHAR)(0xea & 0xff));
+ case 0x043b: return((CHAR)(0xeb & 0xff));
+ case 0x043c: return((CHAR)(0xec & 0xff));
+ case 0x043d: return((CHAR)(0xed & 0xff));
+ case 0x043e: return((CHAR)(0xee & 0xff));
+ case 0x043f: return((CHAR)(0xef & 0xff));
+ case 0x0440: return((CHAR)(0xf0 & 0xff));
+ case 0x0441: return((CHAR)(0xf1 & 0xff));
+ case 0x0442: return((CHAR)(0xf2 & 0xff));
+ case 0x0443: return((CHAR)(0xf3 & 0xff));
+ case 0x0444: return((CHAR)(0xf4 & 0xff));
+ case 0x0445: return((CHAR)(0xf5 & 0xff));
+ case 0x0446: return((CHAR)(0xf6 & 0xff));
+ case 0x0447: return((CHAR)(0xf7 & 0xff));
+ case 0x0448: return((CHAR)(0xf8 & 0xff));
+ case 0x0449: return((CHAR)(0xf9 & 0xff));
+ case 0x044a: return((CHAR)(0xfa & 0xff));
+ case 0x044b: return((CHAR)(0xfb & 0xff));
+ case 0x044c: return((CHAR)(0xfc & 0xff));
+ case 0x044d: return((CHAR)(0xfd & 0xff));
+ case 0x044e: return((CHAR)(0xfe & 0xff));
+ case 0x044f: return((CHAR)(0xff & 0xff));
+ case 0x0451: return((CHAR)(0xb8 & 0xff));
+ case 0x0452: return((CHAR)(0x90 & 0xff));
+ case 0x0453: return((CHAR)(0x83 & 0xff));
+ case 0x0454: return((CHAR)(0xba & 0xff));
+ case 0x0455: return((CHAR)(0xbe & 0xff));
+ case 0x0456: return((CHAR)(0xb3 & 0xff));
+ case 0x0457: return((CHAR)(0xbf & 0xff));
+ case 0x0458: return((CHAR)(0xbc & 0xff));
+ case 0x0459: return((CHAR)(0x9a & 0xff));
+ case 0x045a: return((CHAR)(0x9c & 0xff));
+ case 0x045b: return((CHAR)(0x9e & 0xff));
+ case 0x045c: return((CHAR)(0x9d & 0xff));
+ case 0x045e: return((CHAR)(0xa2 & 0xff));
+ case 0x045f: return((CHAR)(0x9f & 0xff));
+ case 0x0490: return((CHAR)(0xa5 & 0xff));
+ case 0x0491: return((CHAR)(0xb4 & 0xff));
+ case 0x2012: return((CHAR)(0x96 & 0xff));
+ case 0x2014: return((CHAR)(0x97 & 0xff));
+ case 0x2018: return((CHAR)(0x91 & 0xff));
+ case 0x2019: return((CHAR)(0x92 & 0xff));
+ case 0x201a: return((CHAR)(0x82 & 0xff));
+ case 0x201c: return((CHAR)(0x93 & 0xff));
+ case 0x201d: return((CHAR)(0x94 & 0xff));
+ case 0x201e: return((CHAR)(0x84 & 0xff));
+ case 0x2020: return((CHAR)(0x86 & 0xff));
+ case 0x2021: return((CHAR)(0x87 & 0xff));
+ case 0x2022: return((CHAR)(0x95 & 0xff));
+ case 0x2026: return((CHAR)(0x85 & 0xff));
+ case 0x2031: return((CHAR)(0x89 & 0xff));
+ case 0x20AC: /* Euro */
+ return((CHAR)(0x88 & 0xff));
+ case 0x2116: return((CHAR)(0xb9 & 0xff));
+ case 0x2122: return((CHAR)(0x99 & 0xff));
+ default: return(0x003f);
+ }
+}
+
+int /* Unicode to Windows Code Page 1252 (Latin-1) */
+#ifdef CK_ANSIC
+tx_cp1252(USHORT c)
+#else
+tx_cp1252(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80 || (c > 0x9f && c <= 0xff)) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x0152: /* OE */
+ return((CHAR)(0x8c & 0xff));
+ case 0x0153: /* oe */
+ return((CHAR)(0x9c & 0xff));
+ case 0x0160: /* S caron */
+ return((CHAR)(0x8a & 0xff));
+ case 0x0161: /* s caron */
+ return((CHAR)(0x9a & 0xff));
+ case 0x0178: /* Y diaeresis */
+ return((CHAR)(0x9f & 0xff));
+ case 0x017D: /* Z caron */
+ return((CHAR)(0x8e & 0xff));
+ case 0x017E: /* z caron */
+ return((CHAR)(0x9e & 0xff));
+ case 0x0192: /* Florin */
+ return((CHAR)(0x83 & 0xff));
+ case 0x2010: case 0x2011: /* Hyphens */
+ return((CHAR)(0x2d & 0xff));
+ case 0x2012: case 0x2013: /* en-dashes */
+ return((CHAR)(0x96 & 0xff));
+ case 0x2014: case 0x2015: /* em-dashes */
+ return((CHAR)(0x97 & 0xff));
+ case 0x2018: /* Various quotation marks... */
+ return((CHAR)(0x91 & 0xff));
+ case 0x2019:
+ return((CHAR)(0x92 & 0xff));
+ case 0x201c:
+ return((CHAR)(0x93 & 0xff));
+ case 0x201d:
+ return((CHAR)(0x94 & 0xff));
+ case 0x201e:
+ return((CHAR)(0x84 & 0xff));
+ case 0x2020: /* Dagger */
+ return((CHAR)(0x86 & 0xff));
+ case 0x2021: /* Double Dagger */
+ return((CHAR)(0x87 & 0xff));
+ case 0x2022: /* Bullet */
+ return((CHAR)(0x95 & 0xff));
+ case 0x2026: /* Ellipsis */
+ return((CHAR)(0x85 & 0xff));
+ case 0x2030: /* Per mil */
+ return((CHAR)(0x89 & 0xff));
+ case 0x20AC: /* Euro */
+ return((CHAR)(0x80 & 0xff));
+ case 0x2122: /* Trade Mark */
+ return((CHAR)(0x99 & 0xff));
+ default: return(0x003f);
+ }
+}
+
+int /* PC Code Page 852 */
+#ifdef CK_ANSIC
+tx_cp852(USHORT c)
+#else
+tx_cp852(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ case 0x00a4: return((CHAR)(207 & 0xff));
+ case 0x00a7: return((CHAR)(245 & 0xff));
+ case 0x00a8: return((CHAR)(249 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00ac: return((CHAR)(170 & 0xff));
+ case 0x00ad: return((CHAR)(240 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00b4: return((CHAR)(239 & 0xff));
+ case 0x00b8: return((CHAR)(247 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x00c1: return((CHAR)(181 & 0xff));
+ case 0x00c2: return((CHAR)(182 & 0xff));
+ case 0x00c4: return((CHAR)(142 & 0xff));
+ case 0x00c7: return((CHAR)(128 & 0xff));
+ case 0x00c9: return((CHAR)(144 & 0xff));
+ case 0x00cb: return((CHAR)(211 & 0xff));
+ case 0x00cd: return((CHAR)(214 & 0xff));
+ case 0x00ce: return((CHAR)(215 & 0xff));
+ case 0x00d3: return((CHAR)(224 & 0xff));
+ case 0x00d4: return((CHAR)(226 & 0xff));
+ case 0x00d6: return((CHAR)(153 & 0xff));
+ case 0x00d7: return((CHAR)(158 & 0xff));
+ case 0x00da: return((CHAR)(233 & 0xff));
+ case 0x00dc: return((CHAR)(154 & 0xff));
+ case 0x00dd: return((CHAR)(237 & 0xff));
+ case 0x00df: return((CHAR)(225 & 0xff));
+ case 0x00e1: return((CHAR)(160 & 0xff));
+ case 0x00e2: return((CHAR)(131 & 0xff));
+ case 0x00e4: return((CHAR)(132 & 0xff));
+ case 0x00e7: return((CHAR)(135 & 0xff));
+ case 0x00e9: return((CHAR)(130 & 0xff));
+ case 0x00eb: return((CHAR)(137 & 0xff));
+ case 0x00ed: return((CHAR)(161 & 0xff));
+ case 0x00ee: return((CHAR)(140 & 0xff));
+ case 0x00f3: return((CHAR)(162 & 0xff));
+ case 0x00f4: return((CHAR)(147 & 0xff));
+ case 0x00f6: return((CHAR)(148 & 0xff));
+ case 0x00f7: return((CHAR)(246 & 0xff));
+ case 0x00fa: return((CHAR)(163 & 0xff));
+ case 0x00fc: return((CHAR)(129 & 0xff));
+ case 0x00fd: return((CHAR)(236 & 0xff));
+ case 0x0102: return((CHAR)(198 & 0xff));
+ case 0x0103: return((CHAR)(199 & 0xff));
+ case 0x0104: return((CHAR)(164 & 0xff));
+ case 0x0105: return((CHAR)(165 & 0xff));
+ case 0x0106: return((CHAR)(143 & 0xff));
+ case 0x0107: return((CHAR)(134 & 0xff));
+ case 0x010c: return((CHAR)(172 & 0xff));
+ case 0x010d: return((CHAR)(159 & 0xff));
+ case 0x010e: return((CHAR)(210 & 0xff));
+ case 0x010f: return((CHAR)(212 & 0xff));
+ case 0x0110: return((CHAR)(209 & 0xff));
+ case 0x0111: return((CHAR)(208 & 0xff));
+ case 0x0118: return((CHAR)(168 & 0xff));
+ case 0x0119: return((CHAR)(169 & 0xff));
+ case 0x011a: return((CHAR)(183 & 0xff));
+ case 0x011b: return((CHAR)(216 & 0xff));
+ case 0x0139: return((CHAR)(145 & 0xff));
+ case 0x013a: return((CHAR)(146 & 0xff));
+ case 0x013d: return((CHAR)(149 & 0xff));
+ case 0x013e: return((CHAR)(150 & 0xff));
+ case 0x0141: return((CHAR)(157 & 0xff));
+ case 0x0142: return((CHAR)(136 & 0xff));
+ case 0x0143: return((CHAR)(227 & 0xff));
+ case 0x0144: return((CHAR)(228 & 0xff));
+ case 0x0147: return((CHAR)(213 & 0xff));
+ case 0x0148: return((CHAR)(229 & 0xff));
+ case 0x0150: return((CHAR)(138 & 0xff));
+ case 0x0151: return((CHAR)(139 & 0xff));
+ case 0x0154: return((CHAR)(232 & 0xff));
+ case 0x0155: return((CHAR)(234 & 0xff));
+ case 0x0158: return((CHAR)(252 & 0xff));
+ case 0x0159: return((CHAR)(253 & 0xff));
+ case 0x015a: return((CHAR)(151 & 0xff));
+ case 0x015b: return((CHAR)(152 & 0xff));
+ case 0x015e: return((CHAR)(184 & 0xff));
+ case 0x015f: return((CHAR)(173 & 0xff));
+ case 0x0160: return((CHAR)(230 & 0xff));
+ case 0x0161: return((CHAR)(231 & 0xff));
+ case 0x0162: return((CHAR)(221 & 0xff));
+ case 0x0163: return((CHAR)(238 & 0xff));
+ case 0x0164: return((CHAR)(155 & 0xff));
+ case 0x0165: return((CHAR)(156 & 0xff));
+ case 0x016e: return((CHAR)(222 & 0xff));
+ case 0x016f: return((CHAR)(133 & 0xff));
+ case 0x0170: return((CHAR)(235 & 0xff));
+ case 0x0171: return((CHAR)(251 & 0xff));
+ case 0x0179: return((CHAR)(141 & 0xff));
+ case 0x017a: return((CHAR)(171 & 0xff));
+ case 0x017b: return((CHAR)(189 & 0xff));
+ case 0x017c: return((CHAR)(190 & 0xff));
+ case 0x017d: return((CHAR)(166 & 0xff));
+ case 0x017e: return((CHAR)(167 & 0xff));
+ case 0x02c7: return((CHAR)(243 & 0xff));
+ case 0x02d8: return((CHAR)(244 & 0xff));
+ case 0x02d9: return((CHAR)(250 & 0xff));
+ case 0x02db: return((CHAR)(242 & 0xff));
+ case 0x02dd: return((CHAR)(241 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* Windows Code Page 1253 (Greek) */
+#ifdef CK_ANSIC
+tx_cp1253(USHORT c)
+#else
+tx_cp1253(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x003c: return((CHAR)(0x8b & 0xff));
+ case 0x003e: return((CHAR)(0x9b & 0xff));
+ case 0x00A0: return((CHAR)(0xa0 & 0xff));
+ case 0x00A3: return((CHAR)(0xa3 & 0xff));
+ case 0x00A4: return((CHAR)(0xa4 & 0xff));
+ case 0x00A5: return((CHAR)(0xa5 & 0xff));
+ case 0x00A6: return((CHAR)(0xa6 & 0xff));
+ case 0x00A7: return((CHAR)(0xa7 & 0xff));
+ case 0x00A8: return((CHAR)(0xa8 & 0xff));
+ case 0x00A9: return((CHAR)(0xa9 & 0xff));
+ case 0x00AA: return((CHAR)(0xaa & 0xff));
+ case 0x00AB: return((CHAR)(0xab & 0xff));
+ case 0x00AC: return((CHAR)(0xac & 0xff));
+ case 0x00AD: return((CHAR)(0xad & 0xff));
+ case 0x00AE: return((CHAR)(0xae & 0xff));
+ case 0x00AF: return((CHAR)(0xaf & 0xff));
+ case 0x00B0: return((CHAR)(0xb0 & 0xff));
+ case 0x00B1: return((CHAR)(0xb1 & 0xff));
+ case 0x00B2: return((CHAR)(0xb2 & 0xff));
+ case 0x00B3: return((CHAR)(0xb3 & 0xff));
+ case 0x00B5: return((CHAR)(0xb5 & 0xff));
+ case 0x00B6: return((CHAR)(0xb6 & 0xff));
+ case 0x00b7: return((CHAR)(0xa1 & 0xff));
+ case 0x00BB: return((CHAR)(0xbb & 0xff));
+ case 0x00BD: return((CHAR)(0xbd & 0xff));
+ case 0x0192: return((CHAR)(0x83 & 0xff));
+ case 0x0386: return((CHAR)(0xa2 & 0xff));
+ case 0x0388: return((CHAR)(0xb8 & 0xff));
+ case 0x0389: return((CHAR)(0xb9 & 0xff));
+ case 0x038A: return((CHAR)(0xba & 0xff));
+ case 0x038C: return((CHAR)(0xbc & 0xff));
+ case 0x038E: return((CHAR)(0xbe & 0xff));
+ case 0x038F: return((CHAR)(0xbf & 0xff));
+ case 0x0390: return((CHAR)(0xc0 & 0xff));
+ case 0x0391: return((CHAR)(0xc1 & 0xff));
+ case 0x0392: return((CHAR)(0xc2 & 0xff));
+ case 0x0393: return((CHAR)(0xc3 & 0xff));
+ case 0x0394: return((CHAR)(0xc4 & 0xff));
+ case 0x0395: return((CHAR)(0xc5 & 0xff));
+ case 0x0396: return((CHAR)(0xc6 & 0xff));
+ case 0x0397: return((CHAR)(0xc7 & 0xff));
+ case 0x0398: return((CHAR)(0xc8 & 0xff));
+ case 0x0399: return((CHAR)(0xc9 & 0xff));
+ case 0x039A: return((CHAR)(0xca & 0xff));
+ case 0x039B: return((CHAR)(0xcb & 0xff));
+ case 0x039C: return((CHAR)(0xcc & 0xff));
+ case 0x039D: return((CHAR)(0xcd & 0xff));
+ case 0x039E: return((CHAR)(0xce & 0xff));
+ case 0x039F: return((CHAR)(0xcf & 0xff));
+ case 0x03a0: return((CHAR)(0xd0 & 0xff));
+ case 0x03a1: return((CHAR)(0xd1 & 0xff));
+ case 0x03a3: return((CHAR)(0xd3 & 0xff));
+ case 0x03a4: return((CHAR)(0xd4 & 0xff));
+ case 0x03a5: return((CHAR)(0xd5 & 0xff));
+ case 0x03a6: return((CHAR)(0xd6 & 0xff));
+ case 0x03a7: return((CHAR)(0xd7 & 0xff));
+ case 0x03a8: return((CHAR)(0xd8 & 0xff));
+ case 0x03a9: return((CHAR)(0xd9 & 0xff));
+ case 0x03aA: return((CHAR)(0xda & 0xff));
+ case 0x03aB: return((CHAR)(0xdb & 0xff));
+ case 0x03aC: return((CHAR)(0xdc & 0xff));
+ case 0x03aD: return((CHAR)(0xdd & 0xff));
+ case 0x03aE: return((CHAR)(0xde & 0xff));
+ case 0x03aF: return((CHAR)(0xdf & 0xff));
+ case 0x03b0: return((CHAR)(0xe0 & 0xff));
+ case 0x03b1: return((CHAR)(0xe1 & 0xff));
+ case 0x03b2: return((CHAR)(0xe2 & 0xff));
+ case 0x03b3: return((CHAR)(0xe3 & 0xff));
+ case 0x03b4: return((CHAR)(0xe4 & 0xff));
+ case 0x03b5: return((CHAR)(0xe5 & 0xff));
+ case 0x03b6: return((CHAR)(0xe6 & 0xff));
+ case 0x03b7: return((CHAR)(0xe7 & 0xff));
+ case 0x03b8: return((CHAR)(0xe8 & 0xff));
+ case 0x03b9: return((CHAR)(0xe9 & 0xff));
+ case 0x03bA: return((CHAR)(0xea & 0xff));
+ case 0x03bB: return((CHAR)(0xeb & 0xff));
+ case 0x03bC: return((CHAR)(0xec & 0xff));
+ case 0x03bD: return((CHAR)(0xed & 0xff));
+ case 0x03bE: return((CHAR)(0xee & 0xff));
+ case 0x03bF: return((CHAR)(0xef & 0xff));
+ case 0x03c0: return((CHAR)(0xf0 & 0xff));
+ case 0x03c1: return((CHAR)(0xf1 & 0xff));
+ case 0x03c2: return((CHAR)(0xf2 & 0xff));
+ case 0x03c3: return((CHAR)(0xf3 & 0xff));
+ case 0x03c4: return((CHAR)(0xf4 & 0xff));
+ case 0x03c5: return((CHAR)(0xf5 & 0xff));
+ case 0x03c6: return((CHAR)(0xf6 & 0xff));
+ case 0x03c7: return((CHAR)(0xf7 & 0xff));
+ case 0x03c8: return((CHAR)(0xf8 & 0xff));
+ case 0x03c9: return((CHAR)(0xf9 & 0xff));
+ case 0x03cA: return((CHAR)(0xfa & 0xff));
+ case 0x03cB: return((CHAR)(0xfb & 0xff));
+ case 0x03cC: return((CHAR)(0xfc & 0xff));
+ case 0x03cD: return((CHAR)(0xfd & 0xff));
+ case 0x03cE: return((CHAR)(0xfe & 0xff));
+ case 0x2012: return((CHAR)(0x96 & 0xff));
+ case 0x2014: return((CHAR)(0x97 & 0xff));
+ case 0x2018: return((CHAR)(0x91 & 0xff));
+ case 0x2019: return((CHAR)(0x92 & 0xff));
+ case 0x201a: return((CHAR)(0x82 & 0xff));
+ case 0x201c: return((CHAR)(0x93 & 0xff));
+ case 0x201d: return((CHAR)(0x94 & 0xff));
+ case 0x201e: return((CHAR)(0x84 & 0xff));
+ case 0x2020: return((CHAR)(0x86 & 0xff));
+ case 0x2021: return((CHAR)(0x87 & 0xff));
+ case 0x2022: return((CHAR)(0x95 & 0xff));
+ case 0x2026: return((CHAR)(0x85 & 0xff));
+ case 0x2031: return((CHAR)(0x89 & 0xff));
+ case 0x20AC: /* Euro */
+ return((CHAR)(0x80 & 0xff));
+ case 0x2122: return((CHAR)(0x99 & 0xff));
+ default: return(0x003f);
+ }
+}
+
+int /* Windows Code Page 1254 (Turkish) */
+#ifdef CK_ANSIC
+tx_cp1254(USHORT c)
+#else
+tx_cp1254(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80)
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x011e: return((CHAR)(0xd0 & 0xff)); /* G breve */
+ case 0x0130: return((CHAR)(0xdd & 0xff)); /* I with dot */
+ case 0x015e: return((CHAR)(0xde & 0xff)); /* S cedilla */
+ case 0x011f: return((CHAR)(0xf0 & 0xff)); /* g breve */
+ case 0x0131: return((CHAR)(0xfd & 0xff)); /* i dotless */
+ case 0x015f: return((CHAR)(0xfe & 0xff)); /* s cedilla */
+ default: return(tx_cp1252(c)); /* The rest is like Windows Latin-1 */
+ }
+}
+
+int
+#ifdef CK_ANSIC
+tx_cp1255(USHORT c)
+#else
+tx_cp1255(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x080)
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x20AC:
+ return((CHAR)(0x80 & 0xff)); /* EURO SIGN */
+ case 0x201A:
+ return((CHAR)(0x82 & 0xff)); /* SINGLE LOW-9 QUOTATION MARK */
+ case 0x0192:
+ return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER F WITH HOOK */
+ case 0x201E:
+ return((CHAR)(0x84 & 0xff)); /* DOUBLE LOW-9 QUOTATION MARK */
+ case 0x2026:
+ return((CHAR)(0x85 & 0xff)); /* HORIZONTAL ELLIPSIS */
+ case 0x2020:
+ return((CHAR)(0x86 & 0xff)); /* DAGGER */
+ case 0x2021:
+ return((CHAR)(0x87 & 0xff)); /* DOUBLE DAGGER */
+ case 0x02C6:
+ return((CHAR)(0x88 & 0xff)); /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ case 0x2030:
+ return((CHAR)(0x89 & 0xff)); /* PER MILLE SIGN */
+ case 0x2039:
+ return((CHAR)(0x8B & 0xff)); /* SINGLE LEFT-POINTING ANGLE QUOTE */
+ case 0x2018:
+ return((CHAR)(0x91 & 0xff)); /* LEFT SINGLE QUOTATION MARK */
+ case 0x2019:
+ return((CHAR)(0x92 & 0xff)); /* RIGHT SINGLE QUOTATION MARK */
+ case 0x201C:
+ return((CHAR)(0x93 & 0xff)); /* LEFT DOUBLE QUOTATION MARK */
+ case 0x201D:
+ return((CHAR)(0x94 & 0xff)); /* RIGHT DOUBLE QUOTATION MARK */
+ case 0x2022:
+ return((CHAR)(0x95 & 0xff)); /* BULLET */
+ case 0x2013:
+ return((CHAR)(0x96 & 0xff)); /* EN DASH */
+ case 0x2014:
+ return((CHAR)(0x97 & 0xff)); /* EM DASH */
+ case 0x02DC:
+ return((CHAR)(0x98 & 0xff)); /* SMALL TILDE */
+ case 0x2122:
+ return((CHAR)(0x99 & 0xff)); /* TRADE MARK SIGN */
+ case 0x203A:
+ return((CHAR)(0x9B & 0xff)); /* SINGLE RIGHT-POINTING ANGLE QUOTE */
+ case 0x00A0:
+ return((CHAR)(0xA0 & 0xff)); /* NO-BREAK SPACE */
+ case 0x00A1:
+ return((CHAR)(0xA1 & 0xff)); /* INVERTED EXCLAMATION MARK */
+ case 0x00A2:
+ return((CHAR)(0xA2 & 0xff)); /* CENT SIGN */
+ case 0x00A3:
+ return((CHAR)(0xA3 & 0xff)); /* POUND SIGN */
+ case 0x20AA:
+ return((CHAR)(0xA4 & 0xff)); /* NEW SHEQEL SIGN */
+ case 0x00A5:
+ return((CHAR)(0xA5 & 0xff)); /* YEN SIGN */
+ case 0x00A6:
+ return((CHAR)(0xA6 & 0xff)); /* BROKEN BAR */
+ case 0x00A7:
+ return((CHAR)(0xA7 & 0xff)); /* SECTION SIGN */
+ case 0x00A8:
+ return((CHAR)(0xA8 & 0xff)); /* DIAERESIS */
+ case 0x00A9:
+ return((CHAR)(0xA9 & 0xff)); /* COPYRIGHT SIGN */
+ case 0x00D7:
+ return((CHAR)(0xAA & 0xff)); /* MULTIPLICATION SIGN */
+ case 0x00AB:
+ return((CHAR)(0xAB & 0xff)); /* LEFT-POINTING DOUBLE ANGLE QUOTE */
+ case 0x00AC:
+ return((CHAR)(0xAC & 0xff)); /* NOT SIGN */
+ case 0x00AD:
+ return((CHAR)(0xAD & 0xff)); /* SOFT HYPHEN */
+ case 0x00AE:
+ return((CHAR)(0xAE & 0xff)); /* REGISTERED SIGN */
+ case 0x00AF:
+ return((CHAR)(0xAF & 0xff)); /* MACRON */
+ case 0x00B0:
+ return((CHAR)(0xB0 & 0xff)); /* DEGREE SIGN */
+ case 0x00B1:
+ return((CHAR)(0xB1 & 0xff)); /* PLUS-MINUS SIGN */
+ case 0x00B2:
+ return((CHAR)(0xB2 & 0xff)); /* SUPERSCRIPT TWO */
+ case 0x00B3:
+ return((CHAR)(0xB3 & 0xff)); /* SUPERSCRIPT THREE */
+ case 0x00B4:
+ return((CHAR)(0xB4 & 0xff)); /* ACUTE ACCENT */
+ case 0x00B5:
+ return((CHAR)(0xB5 & 0xff)); /* MICRO SIGN */
+ case 0x00B6:
+ return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */
+ case 0x00B7:
+ return((CHAR)(0xB7 & 0xff)); /* MIDDLE DOT */
+ case 0x00B8:
+ return((CHAR)(0xB8 & 0xff)); /* CEDILLA */
+ case 0x00B9:
+ return((CHAR)(0xB9 & 0xff)); /* SUPERSCRIPT ONE */
+ case 0x00F7:
+ return((CHAR)(0xBA & 0xff)); /* DIVISION SIGN */
+ case 0x00BB:
+ return((CHAR)(0xBB & 0xff)); /* RIGHT-POINTING DOUBLE ANGLE QUOTE */
+ case 0x00BC:
+ return((CHAR)(0xBC & 0xff)); /* VULGAR FRACTION ONE QUARTER */
+ case 0x00BD:
+ return((CHAR)(0xBD & 0xff)); /* VULGAR FRACTION ONE HALF */
+ case 0x00BE:
+ return((CHAR)(0xBE & 0xff)); /* VULGAR FRACTION THREE QUARTERS */
+ case 0x00BF:
+ return((CHAR)(0xBF & 0xff)); /* INVERTED QUESTION MARK */
+ case 0x05B0:
+ return((CHAR)(0xC0 & 0xff)); /* HEBREW POINT SHEVA */
+ case 0x05B1:
+ return((CHAR)(0xC1 & 0xff)); /* HEBREW POINT HATAF SEGOL */
+ case 0x05B2:
+ return((CHAR)(0xC2 & 0xff)); /* HEBREW POINT HATAF PATAH */
+ case 0x05B3:
+ return((CHAR)(0xC3 & 0xff)); /* HEBREW POINT HATAF QAMATS */
+ case 0x05B4:
+ return((CHAR)(0xC4 & 0xff)); /* HEBREW POINT HIRIQ */
+ case 0x05B5:
+ return((CHAR)(0xC5 & 0xff)); /* HEBREW POINT TSERE */
+ case 0x05B6:
+ return((CHAR)(0xC6 & 0xff)); /* HEBREW POINT SEGOL */
+ case 0x05B7:
+ return((CHAR)(0xC7 & 0xff)); /* HEBREW POINT PATAH */
+ case 0x05B8:
+ return((CHAR)(0xC8 & 0xff)); /* HEBREW POINT QAMATS */
+ case 0x05B9:
+ return((CHAR)(0xC9 & 0xff)); /* HEBREW POINT HOLAM */
+ case 0x05BB:
+ return((CHAR)(0xCB & 0xff)); /* HEBREW POINT QUBUTS */
+ case 0x05BC:
+ return((CHAR)(0xCC & 0xff)); /* HEBREW POINT DAGESH OR MAPIQ */
+ case 0x05BD:
+ return((CHAR)(0xCD & 0xff)); /* HEBREW POINT METEG */
+ case 0x05BE:
+ return((CHAR)(0xCE & 0xff)); /* HEBREW PUNCTUATION MAQAF */
+ case 0x05BF:
+ return((CHAR)(0xCF & 0xff)); /* HEBREW POINT RAFE */
+ case 0x05C0:
+ return((CHAR)(0xD0 & 0xff)); /* HEBREW PUNCTUATION PASEQ */
+ case 0x05C1:
+ return((CHAR)(0xD1 & 0xff)); /* HEBREW POINT SHIN DOT */
+ case 0x05C2:
+ return((CHAR)(0xD2 & 0xff)); /* HEBREW POINT SIN DOT */
+ case 0x05C3:
+ return((CHAR)(0xD3 & 0xff)); /* HEBREW PUNCTUATION SOF PASUQ */
+ case 0x05F0:
+ return((CHAR)(0xD4 & 0xff)); /* HEBREW LIG. YIDDISH DOUBLE VAV */
+ case 0x05F1:
+ return((CHAR)(0xD5 & 0xff)); /* HEBREW LIGATURE YIDDISH VAV YOD */
+ case 0x05F2:
+ return((CHAR)(0xD6 & 0xff)); /* HEBREW LIG. YIDDISH DOUBLE YOD */
+ case 0x05F3:
+ return((CHAR)(0xD7 & 0xff)); /* HEBREW PUNCTUATION GERESH */
+ case 0x05F4:
+ return((CHAR)(0xD8 & 0xff)); /* HEBREW PUNCTUATION GERSHAYIM */
+ case 0x05D0:
+ return((CHAR)(0xE0 & 0xff)); /* HEBREW LETTER ALEF */
+ case 0x05D1:
+ return((CHAR)(0xE1 & 0xff)); /* HEBREW LETTER BET */
+ case 0x05D2:
+ return((CHAR)(0xE2 & 0xff)); /* HEBREW LETTER GIMEL */
+ case 0x05D3:
+ return((CHAR)(0xE3 & 0xff)); /* HEBREW LETTER DALET */
+ case 0x05D4:
+ return((CHAR)(0xE4 & 0xff)); /* HEBREW LETTER HE */
+ case 0x05D5:
+ return((CHAR)(0xE5 & 0xff)); /* HEBREW LETTER VAV */
+ case 0x05D6:
+ return((CHAR)(0xE6 & 0xff)); /* HEBREW LETTER ZAYIN */
+ case 0x05D7:
+ return((CHAR)(0xE7 & 0xff)); /* HEBREW LETTER HET */
+ case 0x05D8:
+ return((CHAR)(0xE8 & 0xff)); /* HEBREW LETTER TET */
+ case 0x05D9:
+ return((CHAR)(0xE9 & 0xff)); /* HEBREW LETTER YOD */
+ case 0x05DA:
+ return((CHAR)(0xEA & 0xff)); /* HEBREW LETTER FINAL KAF */
+ case 0x05DB:
+ return((CHAR)(0xEB & 0xff)); /* HEBREW LETTER KAF */
+ case 0x05DC:
+ return((CHAR)(0xEC & 0xff)); /* HEBREW LETTER LAMED */
+ case 0x05DD:
+ return((CHAR)(0xED & 0xff)); /* HEBREW LETTER FINAL MEM */
+ case 0x05DE:
+ return((CHAR)(0xEE & 0xff)); /* HEBREW LETTER MEM */
+ case 0x05DF:
+ return((CHAR)(0xEF & 0xff)); /* HEBREW LETTER FINAL NUN */
+ case 0x05E0:
+ return((CHAR)(0xF0 & 0xff)); /* HEBREW LETTER NUN */
+ case 0x05E1:
+ return((CHAR)(0xF1 & 0xff)); /* HEBREW LETTER SAMEKH */
+ case 0x05E2:
+ return((CHAR)(0xF2 & 0xff)); /* HEBREW LETTER AYIN */
+ case 0x05E3:
+ return((CHAR)(0xF3 & 0xff)); /* HEBREW LETTER FINAL PE */
+ case 0x05E4:
+ return((CHAR)(0xF4 & 0xff)); /* HEBREW LETTER PE */
+ case 0x05E5:
+ return((CHAR)(0xF5 & 0xff)); /* HEBREW LETTER FINAL TSADI */
+ case 0x05E6:
+ return((CHAR)(0xF6 & 0xff)); /* HEBREW LETTER TSADI */
+ case 0x05E7:
+ return((CHAR)(0xF7 & 0xff)); /* HEBREW LETTER QOF */
+ case 0x05E8:
+ return((CHAR)(0xF8 & 0xff)); /* HEBREW LETTER RESH */
+ case 0x05E9:
+ return((CHAR)(0xF9 & 0xff)); /* HEBREW LETTER SHIN */
+ case 0x05EA:
+ return((CHAR)(0xFA & 0xff)); /* HEBREW LETTER TAV */
+ case 0x200E:
+ return((CHAR)(0xFD & 0xff)); /* LEFT-TO-RIGHT MARK */
+ case 0x200F:
+ return((CHAR)(0xFE & 0xff)); /* RIGHT-TO-LEFT MARK */
+ default: return(0x003f);
+ }
+}
+
+int /* Windows Arabic */
+#ifdef CK_ANSIC
+tx_cp1256(USHORT c)
+#else
+tx_cp1256(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80)
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x20AC:
+ return((CHAR)(0x80 & 0xff)); /* EURO SIGN */
+ case 0x067E:
+ return((CHAR)(0x81 & 0xff)); /* ARABIC LETTER PEH */
+ case 0x201A:
+ return((CHAR)(0x82 & 0xff)); /* SINGLE LOW-9 QUOTATION MARK */
+ case 0x0192:
+ return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER F WITH HOOK */
+ case 0x201E:
+ return((CHAR)(0x84 & 0xff)); /* DOUBLE LOW-9 QUOTATION MARK */
+ case 0x2026:
+ return((CHAR)(0x85 & 0xff)); /* HORIZONTAL ELLIPSIS */
+ case 0x2020:
+ return((CHAR)(0x86 & 0xff)); /* DAGGER */
+ case 0x2021:
+ return((CHAR)(0x87 & 0xff)); /* DOUBLE DAGGER */
+ case 0x02C6:
+ return((CHAR)(0x88 & 0xff)); /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ case 0x2030:
+ return((CHAR)(0x89 & 0xff)); /* PER MILLE SIGN */
+ case 0x2039:
+ return((CHAR)(0x8B & 0xff)); /* SINGLE LEFT-POINTING ANGLE QUOTE */
+ case 0x0152:
+ return((CHAR)(0x8C & 0xff)); /* LATIN CAPITAL LIGATURE OE */
+ case 0x0686:
+ return((CHAR)(0x8D & 0xff)); /* ARABIC LETTER TCHEH */
+ case 0x0698:
+ return((CHAR)(0x8E & 0xff)); /* ARABIC LETTER JEH */
+ case 0x06AF:
+ return((CHAR)(0x90 & 0xff)); /* ARABIC LETTER GAF */
+ case 0x2018:
+ return((CHAR)(0x91 & 0xff)); /* LEFT SINGLE QUOTATION MARK */
+ case 0x2019:
+ return((CHAR)(0x92 & 0xff)); /* RIGHT SINGLE QUOTATION MARK */
+ case 0x201C:
+ return((CHAR)(0x93 & 0xff)); /* LEFT DOUBLE QUOTATION MARK */
+ case 0x201D:
+ return((CHAR)(0x94 & 0xff)); /* RIGHT DOUBLE QUOTATION MARK */
+ case 0x2022:
+ return((CHAR)(0x95 & 0xff)); /* BULLET */
+ case 0x2013:
+ return((CHAR)(0x96 & 0xff)); /* EN DASH */
+ case 0x2014:
+ return((CHAR)(0x97 & 0xff)); /* EM DASH */
+ case 0x2122:
+ return((CHAR)(0x99 & 0xff)); /* TRADE MARK SIGN */
+ case 0x203A:
+ return((CHAR)(0x9B & 0xff)); /* SINGLE RIGHT-POINTING ANGLE QUOTE */
+ case 0x0153:
+ return((CHAR)(0x9C & 0xff)); /* LATIN SMALL LIGATURE OE */
+ case 0x200C:
+ return((CHAR)(0x9D & 0xff)); /* ZERO WIDTH NON-JOINER */
+ case 0x200D:
+ return((CHAR)(0x9E & 0xff)); /* ZERO WIDTH JOINER */
+ case 0x00A0:
+ return((CHAR)(0xA0 & 0xff)); /* NO-BREAK SPACE */
+ case 0x060C:
+ return((CHAR)(0xA1 & 0xff)); /* ARABIC COMMA */
+ case 0x00A2:
+ return((CHAR)(0xA2 & 0xff)); /* CENT SIGN */
+ case 0x00A3:
+ return((CHAR)(0xA3 & 0xff)); /* POUND SIGN */
+ case 0x00A4:
+ return((CHAR)(0xA4 & 0xff)); /* CURRENCY SIGN */
+ case 0x00A5:
+ return((CHAR)(0xA5 & 0xff)); /* YEN SIGN */
+ case 0x00A6:
+ return((CHAR)(0xA6 & 0xff)); /* BROKEN BAR */
+ case 0x00A7:
+ return((CHAR)(0xA7 & 0xff)); /* SECTION SIGN */
+ case 0x00A8:
+ return((CHAR)(0xA8 & 0xff)); /* DIAERESIS */
+ case 0x00A9:
+ return((CHAR)(0xA9 & 0xff)); /* COPYRIGHT SIGN */
+ case 0x00AB:
+ return((CHAR)(0xAB & 0xff)); /* LEFT-POINTING DOUBLE ANGLE QUOTE */
+ case 0x00AC:
+ return((CHAR)(0xAC & 0xff)); /* NOT SIGN */
+ case 0x00AD:
+ return((CHAR)(0xAD & 0xff)); /* SOFT HYPHEN */
+ case 0x00AE:
+ return((CHAR)(0xAE & 0xff)); /* REGISTERED SIGN */
+ case 0x00AF:
+ return((CHAR)(0xAF & 0xff)); /* MACRON */
+ case 0x00B0:
+ return((CHAR)(0xB0 & 0xff)); /* DEGREE SIGN */
+ case 0x00B1:
+ return((CHAR)(0xB1 & 0xff)); /* PLUS-MINUS SIGN */
+ case 0x00B2:
+ return((CHAR)(0xB2 & 0xff)); /* SUPERSCRIPT TWO */
+ case 0x00B3:
+ return((CHAR)(0xB3 & 0xff)); /* SUPERSCRIPT THREE */
+ case 0x00B4:
+ return((CHAR)(0xB4 & 0xff)); /* ACUTE ACCENT */
+ case 0x00B5:
+ return((CHAR)(0xB5 & 0xff)); /* MICRO SIGN */
+ case 0x00B6:
+ return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */
+ case 0x00B7:
+ return((CHAR)(0xB7 & 0xff)); /* MIDDLE DOT */
+ case 0x00B8:
+ return((CHAR)(0xB8 & 0xff)); /* CEDILLA */
+ case 0x00B9:
+ return((CHAR)(0xB9 & 0xff)); /* SUPERSCRIPT ONE */
+ case 0x061B:
+ return((CHAR)(0xBA & 0xff)); /* ARABIC SEMICOLON */
+ case 0x00BB:
+ return((CHAR)(0xBB & 0xff)); /* RIGHT-POINTING DOUBLE ANGLE QUOTE */
+ case 0x00BC:
+ return((CHAR)(0xBC & 0xff)); /* VULGAR FRACTION ONE QUARTER */
+ case 0x00BD:
+ return((CHAR)(0xBD & 0xff)); /* VULGAR FRACTION ONE HALF */
+ case 0x00BE:
+ return((CHAR)(0xBE & 0xff)); /* VULGAR FRACTION THREE QUARTERS */
+ case 0x061F:
+ return((CHAR)(0xBF & 0xff)); /* ARABIC QUESTION MARK */
+ case 0x0621:
+ return((CHAR)(0xC1 & 0xff)); /* ARABIC LETTER HAMZA */
+ case 0x0622:
+ return((CHAR)(0xC2 & 0xff)); /* ARABIC LTR. ALEF WITH MADDA ABOVE */
+ case 0x0623:
+ return((CHAR)(0xC3 & 0xff)); /* ARABIC LTR. ALEF WITH HAMZA ABOVE */
+ case 0x0624:
+ return((CHAR)(0xC4 & 0xff)); /* ARABIC LTR. WAW WITH HAMZA ABOVE */
+ case 0x0625:
+ return((CHAR)(0xC5 & 0xff)); /* ARABIC LTR. ALEF WITH HAMZA BELOW */
+ case 0x0626:
+ return((CHAR)(0xC6 & 0xff)); /* ARABIC LTR. YEH WITH HAMZA ABOVE */
+ case 0x0627:
+ return((CHAR)(0xC7 & 0xff)); /* ARABIC LTR. ALEF */
+ case 0x0628:
+ return((CHAR)(0xC8 & 0xff)); /* ARABIC LTR. BEH */
+ case 0x0629:
+ return((CHAR)(0xC9 & 0xff)); /* ARABIC LETTER TEH MARBUTA */
+ case 0x062A:
+ return((CHAR)(0xCA & 0xff)); /* ARABIC LETTER TEH */
+ case 0x062B:
+ return((CHAR)(0xCB & 0xff)); /* ARABIC LETTER THEH */
+ case 0x062C:
+ return((CHAR)(0xCC & 0xff)); /* ARABIC LETTER JEEM */
+ case 0x062D:
+ return((CHAR)(0xCD & 0xff)); /* ARABIC LETTER HAH */
+ case 0x062E:
+ return((CHAR)(0xCE & 0xff)); /* ARABIC LETTER KHAH */
+ case 0x062F:
+ return((CHAR)(0xCF & 0xff)); /* ARABIC LETTER DAL */
+ case 0x0630:
+ return((CHAR)(0xD0 & 0xff)); /* ARABIC LETTER THAL */
+ case 0x0631:
+ return((CHAR)(0xD1 & 0xff)); /* ARABIC LETTER REH */
+ case 0x0632:
+ return((CHAR)(0xD2 & 0xff)); /* ARABIC LETTER ZAIN */
+ case 0x0633:
+ return((CHAR)(0xD3 & 0xff)); /* ARABIC LETTER SEEN */
+ case 0x0634:
+ return((CHAR)(0xD4 & 0xff)); /* ARABIC LETTER SHEEN */
+ case 0x0635:
+ return((CHAR)(0xD5 & 0xff)); /* ARABIC LETTER SAD */
+ case 0x0636:
+ return((CHAR)(0xD6 & 0xff)); /* ARABIC LETTER DAD */
+ case 0x00D7:
+ return((CHAR)(0xD7 & 0xff)); /* MULTIPLICATION SIGN */
+ case 0x0637:
+ return((CHAR)(0xD8 & 0xff)); /* ARABIC LETTER TAH */
+ case 0x0638:
+ return((CHAR)(0xD9 & 0xff)); /* ARABIC LETTER ZAH */
+ case 0x0639:
+ return((CHAR)(0xDA & 0xff)); /* ARABIC LETTER AIN */
+ case 0x063A:
+ return((CHAR)(0xDB & 0xff)); /* ARABIC LETTER GHAIN */
+ case 0x0640:
+ return((CHAR)(0xDC & 0xff)); /* ARABIC TATWEEL */
+ case 0x0641:
+ return((CHAR)(0xDD & 0xff)); /* ARABIC LETTER FEH */
+ case 0x0642:
+ return((CHAR)(0xDE & 0xff)); /* ARABIC LETTER QAF */
+ case 0x0643:
+ return((CHAR)(0xDF & 0xff)); /* ARABIC LETTER KAF */
+ case 0x00E0:
+ return((CHAR)(0xE0 & 0xff)); /* LATIN SMALL LETTER A WITH GRAVE */
+ case 0x0644:
+ return((CHAR)(0xE1 & 0xff)); /* ARABIC LETTER LAM */
+ case 0x00E2:
+ return((CHAR)(0xE2 & 0xff)); /* SMALL LETTER A WITH CIRCUMFLEX */
+ case 0x0645:
+ return((CHAR)(0xE3 & 0xff)); /* ARABIC LETTER MEEM */
+ case 0x0646:
+ return((CHAR)(0xE4 & 0xff)); /* ARABIC LETTER NOON */
+ case 0x0647:
+ return((CHAR)(0xE5 & 0xff)); /* ARABIC LETTER HEH */
+ case 0x0648:
+ return((CHAR)(0xE6 & 0xff)); /* ARABIC LETTER WAW */
+ case 0x00E7:
+ return((CHAR)(0xE7 & 0xff)); /* LATIN SMALL LETTER C WITH CEDILLA */
+ case 0x00E8:
+ return((CHAR)(0xE8 & 0xff)); /* LATIN SMALL LETTER E WITH GRAVE */
+ case 0x00E9:
+ return((CHAR)(0xE9 & 0xff)); /* LATIN SMALL LETTER E WITH ACUTE */
+ case 0x00EA:
+ return((CHAR)(0xEA & 0xff)); /* SMALL LETTER E WITH CIRCUMFLEX */
+ case 0x00EB:
+ return((CHAR)(0xEB & 0xff)); /* SMALL LETTER E WITH DIAERESIS */
+ case 0x0649:
+ return((CHAR)(0xEC & 0xff)); /* ARABIC LETTER ALEF MAKSURA */
+ case 0x064A:
+ return((CHAR)(0xED & 0xff)); /* ARABIC LETTER YEH */
+ case 0x00EE:
+ return((CHAR)(0xEE & 0xff)); /* SMALL LETTER I WITH CIRCUMFLEX */
+ case 0x00EF:
+ return((CHAR)(0xEF & 0xff)); /* SMALL LETTER I WITH DIAERESIS */
+ case 0x064B:
+ return((CHAR)(0xF0 & 0xff)); /* ARABIC FATHATAN */
+ case 0x064C:
+ return((CHAR)(0xF1 & 0xff)); /* ARABIC DAMMATAN */
+ case 0x064D:
+ return((CHAR)(0xF2 & 0xff)); /* ARABIC KASRATAN */
+ case 0x064E:
+ return((CHAR)(0xF3 & 0xff)); /* ARABIC FATHA */
+ case 0x00F4:
+ return((CHAR)(0xF4 & 0xff)); /* SMALL LETTER O WITH CIRCUMFLEX */
+ case 0x064F:
+ return((CHAR)(0xF5 & 0xff)); /* ARABIC DAMMA */
+ case 0x0650:
+ return((CHAR)(0xF6 & 0xff)); /* ARABIC KASRA */
+ case 0x00F7:
+ return((CHAR)(0xF7 & 0xff)); /* DIVISION SIGN */
+ case 0x0651:
+ return((CHAR)(0xF8 & 0xff)); /* ARABIC SHADDA */
+ case 0x00F9:
+ return((CHAR)(0xF9 & 0xff)); /* LATIN SMALL LETTER U WITH GRAVE */
+ case 0x0652:
+ return((CHAR)(0xFA & 0xff)); /* ARABIC SUKUN */
+ case 0x00FB:
+ return((CHAR)(0xFB & 0xff)); /* SMALL LETTER U WITH CIRCUMFLEX */
+ case 0x00FC:
+ return((CHAR)(0xFC & 0xff)); /* SMALL LETTER U WITH DIAERESIS */
+ case 0x200E:
+ return((CHAR)(0xFD & 0xff)); /* LEFT-TO-RIGHT MARK */
+ case 0x200F:
+ return((CHAR)(0xFE & 0xff)); /* RIGHT-TO-LEFT MARK */
+ default: return(0x003f);
+ }
+}
+
+int /* Windows Code Page 1257 (Latin-4) */
+#ifdef CK_ANSIC
+tx_cp1257(USHORT c)
+#else
+tx_cp1257(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80)
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x003c: return((CHAR)(0x8b & 0xff));
+ case 0x003e: return((CHAR)(0x9b & 0xff));
+ case 0x00A0: return((CHAR)(0xa0 & 0xff));
+ case 0x00A2: return((CHAR)(0xa2 & 0xff));
+ case 0x00A3: return((CHAR)(0xa3 & 0xff));
+ case 0x00A4: return((CHAR)(0xa4 & 0xff));
+ case 0x00A6: return((CHAR)(0xa6 & 0xff));
+ case 0x00A7: return((CHAR)(0xa7 & 0xff));
+ case 0x00A9: return((CHAR)(0xa9 & 0xff));
+ case 0x00AB: return((CHAR)(0xab & 0xff));
+ case 0x00AC: return((CHAR)(0xac & 0xff));
+ case 0x00AD: return((CHAR)(0xad & 0xff));
+ case 0x00AE: return((CHAR)(0xae & 0xff));
+ case 0x00B0: return((CHAR)(0xb0 & 0xff));
+ case 0x00B1: return((CHAR)(0xb1 & 0xff));
+ case 0x00B2: return((CHAR)(0xb2 & 0xff));
+ case 0x00B3: return((CHAR)(0xb3 & 0xff));
+ case 0x00B5: return((CHAR)(0xb5 & 0xff));
+ case 0x00B6: return((CHAR)(0xb6 & 0xff));
+ case 0x00B7: return((CHAR)(0xb7 & 0xff));
+ case 0x00B9: return((CHAR)(0xb9 & 0xff));
+ case 0x00BB: return((CHAR)(0xbb & 0xff));
+ case 0x00BC: return((CHAR)(0xbc & 0xff));
+ case 0x00BD: return((CHAR)(0xbd & 0xff));
+ case 0x00BE: return((CHAR)(0xbe & 0xff));
+ case 0x00C4: return((CHAR)(0xc4 & 0xff));
+ case 0x00C5: return((CHAR)(0xc5 & 0xff));
+ case 0x00c6: return((CHAR)(0xaf & 0xff));
+ case 0x00C9: return((CHAR)(0xc9 & 0xff));
+ case 0x00d3: return((CHAR)(0xd3 & 0xff));
+ case 0x00D5: return((CHAR)(0xd5 & 0xff));
+ case 0x00D6: return((CHAR)(0xd6 & 0xff));
+ case 0x00D7: return((CHAR)(0xd7 & 0xff));
+ case 0x00d8: return((CHAR)(0xa8 & 0xff));
+ case 0x00DC: return((CHAR)(0xdc & 0xff));
+ case 0x00DF: return((CHAR)(0xdf & 0xff));
+ case 0x00E4: return((CHAR)(0xe4 & 0xff));
+ case 0x00E5: return((CHAR)(0xe5 & 0xff));
+ case 0x00e6: return((CHAR)(0xbf & 0xff));
+ case 0x00E9: return((CHAR)(0xe9 & 0xff));
+ case 0x00f3: return((CHAR)(0xf3 & 0xff));
+ case 0x00F5: return((CHAR)(0xf5 & 0xff));
+ case 0x00F6: return((CHAR)(0xf6 & 0xff));
+ case 0x00F7: return((CHAR)(0xf7 & 0xff));
+ case 0x00f8: return((CHAR)(0xb8 & 0xff));
+ case 0x00fc: return((CHAR)(0xfc & 0xff));
+ case 0x0100: return((CHAR)(0xc2 & 0xff));
+ case 0x0101: return((CHAR)(0xe2 & 0xff));
+ case 0x0104: return((CHAR)(0xc0 & 0xff));
+ case 0x0105: return((CHAR)(0xe0 & 0xff));
+ case 0x0106: return((CHAR)(0xc3 & 0xff));
+ case 0x0107: return((CHAR)(0xe3 & 0xff));
+ case 0x010C: return((CHAR)(0xc8 & 0xff));
+ case 0x010D: return((CHAR)(0xe8 & 0xff));
+ case 0x0112: return((CHAR)(0xc7 & 0xff));
+ case 0x0113: return((CHAR)(0xe7 & 0xff));
+ case 0x0116: return((CHAR)(0xcb & 0xff));
+ case 0x0117: return((CHAR)(0xeb & 0xff));
+ case 0x0118: return((CHAR)(0xc6 & 0xff));
+ case 0x0119: return((CHAR)(0xe6 & 0xff));
+ case 0x0122: return((CHAR)(0xcc & 0xff));
+ case 0x0123: return((CHAR)(0xec & 0xff));
+ case 0x012a: return((CHAR)(0xce & 0xff));
+ case 0x012b: return((CHAR)(0xee & 0xff));
+ case 0x012e: return((CHAR)(0xc1 & 0xff));
+ case 0x012f: return((CHAR)(0xe1 & 0xff));
+ case 0x0136: return((CHAR)(0xcd & 0xff));
+ case 0x0137: return((CHAR)(0xed & 0xff));
+ case 0x013c: return((CHAR)(0xef & 0xff));
+ case 0x0141: return((CHAR)(0xd9 & 0xff));
+ case 0x0142: return((CHAR)(0xf9 & 0xff));
+ case 0x0143: return((CHAR)(0xd1 & 0xff));
+ case 0x0144: return((CHAR)(0xf1 & 0xff));
+ case 0x0145: return((CHAR)(0xd2 & 0xff));
+ case 0x0146: return((CHAR)(0xf2 & 0xff));
+ case 0x014c: return((CHAR)(0xd4 & 0xff));
+ case 0x014d: return((CHAR)(0xf4 & 0xff));
+ case 0x0156: return((CHAR)(0xaa & 0xff));
+ case 0x0157: return((CHAR)(0xba & 0xff));
+ case 0x015A: return((CHAR)(0xda & 0xff));
+ case 0x015b: return((CHAR)(0xfa & 0xff));
+ case 0x0160: return((CHAR)(0xd0 & 0xff));
+ case 0x0161: return((CHAR)(0xf0 & 0xff));
+ case 0x016a: return((CHAR)(0xdb & 0xff));
+ case 0x016b: return((CHAR)(0xfb & 0xff));
+ case 0x0172: return((CHAR)(0xd8 & 0xff));
+ case 0x0173: return((CHAR)(0xf8 & 0xff));
+ case 0x0179: return((CHAR)(0xca & 0xff));
+ case 0x017a: return((CHAR)(0xea & 0xff));
+ case 0x017b: return((CHAR)(0xdd & 0xff));
+ case 0x017c: return((CHAR)(0xfd & 0xff));
+ case 0x017d: return((CHAR)(0xde & 0xff));
+ case 0x017e: return((CHAR)(0xfe & 0xff));
+ case 0x2012: return((CHAR)(0x96 & 0xff));
+ case 0x2014: return((CHAR)(0x97 & 0xff));
+ case 0x2018: return((CHAR)(0x91 & 0xff));
+ case 0x2019: return((CHAR)(0x92 & 0xff));
+ case 0x201a: return((CHAR)(0x82 & 0xff));
+ case 0x201c: return((CHAR)(0x93 & 0xff));
+ case 0x201d: return((CHAR)(0x94 & 0xff));
+ case 0x201e: return((CHAR)(0x84 & 0xff));
+ case 0x2020: return((CHAR)(0x86 & 0xff));
+ case 0x2021: return((CHAR)(0x87 & 0xff));
+ case 0x2022: return((CHAR)(0x95 & 0xff));
+ case 0x2026: return((CHAR)(0x85 & 0xff));
+ case 0x2031: return((CHAR)(0x89 & 0xff));
+ case 0x20AC: /* Euro */
+ return((CHAR)(0x80 & 0xff));
+ case 0x2122: return((CHAR)(0x99 & 0xff));
+ default: return(0x003f);
+ }
+}
+
+int /* Windows Code Page 1258 (Viet Nam) */
+#ifdef CK_ANSIC
+tx_cp1258(USHORT c)
+#else
+tx_cp1258(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x20AC:
+ return((CHAR)(0x80 & 0xff)); /* EURO SIGN */
+ case 0x201A:
+ return((CHAR)(0x82 & 0xff)); /* SINGLE LOW-9 QUOTATION MARK */
+ case 0x0192:
+ return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER F WITH HOOK */
+ case 0x201E:
+ return((CHAR)(0x84 & 0xff)); /* DOUBLE LOW-9 QUOTATION MARK */
+ case 0x2026: return((CHAR)(0x85 & 0xff)); /* HORIZONTAL ELLIPSIS */
+ case 0x2020: return((CHAR)(0x86 & 0xff)); /* DAGGER */
+ case 0x2021: return((CHAR)(0x87 & 0xff)); /* DOUBLE DAGGER */
+ case 0x02C6:
+ return((CHAR)(0x88 & 0xff)); /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ case 0x2030: return((CHAR)(0x89 & 0xff)); /* PER MILLE SIGN */
+ case 0x2039:
+ return((CHAR)(0x8B & 0xff)); /* SINGLE LEFT ANGLE QUOTATION MARK */
+ case 0x0152: return((CHAR)(0x8C & 0xff)); /* LATIN CAPITAL LIGATURE OE */
+ case 0x2018:
+ return((CHAR)(0x91 & 0xff)); /* LEFT SINGLE QUOTATION MARK */
+ case 0x2019:
+ return((CHAR)(0x92 & 0xff)); /* RIGHT SINGLE QUOTATION MARK */
+ case 0x201C:
+ return((CHAR)(0x93 & 0xff)); /* LEFT DOUBLE QUOTATION MARK */
+ case 0x201D:
+ return((CHAR)(0x94 & 0xff)); /* RIGHT DOUBLE QUOTATION MARK */
+ case 0x2022:
+ return((CHAR)(0x95 & 0xff)); /* BULLET */
+ case 0x2013:
+ return((CHAR)(0x96 & 0xff)); /* EN DASH */
+ case 0x2014:
+ return((CHAR)(0x97 & 0xff)); /* EM DASH */
+ case 0x02DC:
+ return((CHAR)(0x98 & 0xff)); /* SMALL TILDE */
+ case 0x2122:
+ return((CHAR)(0x99 & 0xff)); /* TRADE MARK SIGN */
+ case 0x203A:
+ /* SINGLE RIGHT-POINTING ANGLE QUOTATION MAR K*/
+ return((CHAR)(0x9B & 0xff));
+ case 0x0153:
+ return((CHAR)(0x9C & 0xff)); /* LATIN SMALL LIGATURE OE */
+ case 0x0178:
+ /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ return((CHAR)(0x9F & 0xff));
+ case 0x00A0:
+ return((CHAR)(0xA0 & 0xff)); /* NO-BREAK SPACE */
+ case 0x00A1:
+ return((CHAR)(0xA1 & 0xff)); /* INVERTED EXCLAMATION MARK */
+ case 0x00A2:
+ return((CHAR)(0xA2 & 0xff)); /* CENT SIGN */
+ case 0x00A3:
+ return((CHAR)(0xA3 & 0xff)); /* POUND SIGN */
+ case 0x00A4:
+ return((CHAR)(0xA4 & 0xff)); /* CURRENCY SIGN */
+ case 0x00A5:
+ return((CHAR)(0xA5 & 0xff)); /* YEN SIGN */
+ case 0x00A6:
+ return((CHAR)(0xA6 & 0xff)); /* BROKEN BAR */
+ case 0x00A7:
+ return((CHAR)(0xA7 & 0xff)); /* SECTION SIGN */
+ case 0x00A8:
+ return((CHAR)(0xA8 & 0xff)); /* DIAERESIS */
+ case 0x00A9:
+ return((CHAR)(0xA9 & 0xff)); /* COPYRIGHT SIGN */
+ case 0x00AA:
+ return((CHAR)(0xAA & 0xff)); /* FEMININE ORDINAL INDICATOR */
+ case 0x00AB:
+ /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ return((CHAR)(0xAB & 0xff));
+ case 0x00AC:
+ return((CHAR)(0xAC & 0xff)); /* NOT SIGN */
+ case 0x00AD:
+ return((CHAR)(0xAD & 0xff)); /* SOFT HYPHEN */
+ case 0x00AE:
+ return((CHAR)(0xAE & 0xff)); /* REGISTERED SIGN */
+ case 0x00AF:
+ return((CHAR)(0xAF & 0xff)); /* MACRON */
+ case 0x00B0:
+ return((CHAR)(0xB0 & 0xff)); /* DEGREE SIGN */
+ case 0x00B1:
+ return((CHAR)(0xB1 & 0xff)); /* PLUS-MINUS SIGN */
+ case 0x00B2:
+ return((CHAR)(0xB2 & 0xff)); /* SUPERSCRIPT TWO */
+ case 0x00B3:
+ return((CHAR)(0xB3 & 0xff)); /* SUPERSCRIPT THREE */
+ case 0x00B4:
+ return((CHAR)(0xB4 & 0xff)); /* ACUTE ACCENT */
+ case 0x00B5:
+ return((CHAR)(0xB5 & 0xff)); /* MICRO SIGN */
+ case 0x00B6:
+ return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */
+ case 0x00B7:
+ return((CHAR)(0xB7 & 0xff)); /* MIDDLE DOT */
+ case 0x00B8:
+ return((CHAR)(0xB8 & 0xff)); /* CEDILLA */
+ case 0x00B9:
+ return((CHAR)(0xB9 & 0xff)); /* SUPERSCRIPT ONE */
+ case 0x00BA:
+ return((CHAR)(0xBA & 0xff)); /* MASCULINE ORDINAL INDICATOR */
+ case 0x00BB:
+ /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MAR K*/
+ return((CHAR)(0xBB & 0xff));
+ case 0x00BC:
+ return((CHAR)(0xBC & 0xff)); /* VULGAR FRACTION ONE QUARTER */
+ case 0x00BD:
+ return((CHAR)(0xBD & 0xff)); /* VULGAR FRACTION ONE HALF */
+ case 0x00BE:
+ return((CHAR)(0xBE & 0xff)); /* VULGAR FRACTION THREE QUARTERS */
+ case 0x00BF:
+ return((CHAR)(0xBF & 0xff)); /* INVERTED QUESTION MARK */
+ case 0x00C0:
+ return((CHAR)(0xC0 & 0xff)); /* LATIN CAPITAL LETTER A WITH GRAVE */
+ case 0x00C1:
+ return((CHAR)(0xC1 & 0xff)); /* LATIN CAPITAL LETTER A WITH ACUTE */
+ case 0x00C2:
+ return((CHAR)(0xC2 & 0xff)); /* A CIRCUMFLEX */
+ case 0x0102:
+ return((CHAR)(0xC3 & 0xff)); /* LATIN CAPITAL LETTER A WITH BREVE */
+ case 0x00C4:
+ return((CHAR)(0xC4 & 0xff)); /* A DIAERESIS */
+ case 0x00C5:
+ return((CHAR)(0xC5 & 0xff)); /* A RING */
+ case 0x00C6:
+ return((CHAR)(0xC6 & 0xff)); /* LATIN CAPITAL LETTER AE */
+ case 0x00C7:
+ return((CHAR)(0xC7 & 0xff)); /* C CEDILLA */
+ case 0x00C8:
+ return((CHAR)(0xC8 & 0xff)); /* E GRAVE */
+ case 0x00C9:
+ return((CHAR)(0xC9 & 0xff)); /* LATIN CAPITAL LETTER E WITH ACUTE */
+ case 0x00CA:
+ return((CHAR)(0xCA & 0xff)); /* E WITH CIRCUMFLEX */
+ case 0x00CB:
+ return((CHAR)(0xCB & 0xff)); /* E WITH DIAERESIS */
+ case 0x0300:
+ return((CHAR)(0xCC & 0xff)); /* COMBINING GRAVE ACCENT */
+ case 0x00CD:
+ return((CHAR)(0xCD & 0xff)); /* I WITH ACUTE */
+ case 0x00CE:
+ return((CHAR)(0xCE & 0xff)); /* I WITH CIRCUMFLEX */
+ case 0x00CF:
+ return((CHAR)(0xCF & 0xff)); /* I WITH DIAERESIS */
+ case 0x0110:
+ return((CHAR)(0xD0 & 0xff)); /* D WITH STROKE */
+ case 0x00D1:
+ return((CHAR)(0xD1 & 0xff)); /* LATIN CAPITAL LETTER N WITH TILDE */
+ case 0x0309:
+ return((CHAR)(0xD2 & 0xff)); /* COMBINING HOOK ABOVE */
+ case 0x00D3:
+ return((CHAR)(0xD3 & 0xff)); /* LATIN CAPITAL LETTER O WITH ACUTE */
+ case 0x00D4:
+ return((CHAR)(0xD4 & 0xff)); /* O WITH CIRCUMFLEX */
+ case 0x01A0:
+ return((CHAR)(0xD5 & 0xff)); /* LATIN CAPITAL LETTER O WITH HORN */
+ case 0x00D6:
+ return((CHAR)(0xD6 & 0xff)); /* O WITH DIAERESIS */
+ case 0x00D7:
+ return((CHAR)(0xD7 & 0xff)); /* MULTIPLICATION SIGN */
+ case 0x00D8:
+ return((CHAR)(0xD8 & 0xff)); /* O WITH STROKE */
+ case 0x00D9:
+ return((CHAR)(0xD9 & 0xff)); /* LATIN CAPITAL LETTER U WITH GRAVE */
+ case 0x00DA:
+ return((CHAR)(0xDA & 0xff)); /* LATIN CAPITAL LETTER U WITH ACUTE */
+ case 0x00DB:
+ return((CHAR)(0xDB & 0xff)); /* U WITH CIRCUMFLEX */
+ case 0x00DC:
+ return((CHAR)(0xDC & 0xff)); /* U WITH DIAERESIS */
+ case 0x01AF:
+ return((CHAR)(0xDD & 0xff)); /* LATIN CAPITAL LETTER U WITH HORN */
+ case 0x0303:
+ return((CHAR)(0xDE & 0xff)); /* COMBINING TILDE */
+ case 0x00DF:
+ return((CHAR)(0xDF & 0xff)); /* LATIN SMALL LETTER SHARP S */
+ case 0x00E0:
+ return((CHAR)(0xE0 & 0xff)); /* LATIN SMALL LETTER A WITH GRAVE */
+ case 0x00E1:
+ return((CHAR)(0xE1 & 0xff)); /* LATIN SMALL LETTER A WITH ACUTE */
+ case 0x00E2:
+ return((CHAR)(0xE2 & 0xff)); /* SMALL A WITH CIRCUMFLEX */
+ case 0x0103:
+ return((CHAR)(0xE3 & 0xff)); /* LATIN SMALL LETTER A WITH BREVE */
+ case 0x00E4:
+ return((CHAR)(0xE4 & 0xff)); /* SMALL A WITH DIAERESIS */
+ case 0x00E5:
+ return((CHAR)(0xE5 & 0xff)); /* SMALL A WITH RING ABOVE */
+ case 0x00E6:
+ return((CHAR)(0xE6 & 0xff)); /* LATIN SMALL LETTER AE */
+ case 0x00E7:
+ return((CHAR)(0xE7 & 0xff)); /* LATIN SMALL LETTER C WITH CEDILLA */
+ case 0x00E8:
+ return((CHAR)(0xE8 & 0xff)); /* LATIN SMALL LETTER E WITH GRAVE */
+ case 0x00E9:
+ return((CHAR)(0xE9 & 0xff)); /* LATIN SMALL LETTER E WITH ACUTE */
+ case 0x00EA:
+ return((CHAR)(0xEA & 0xff)); /* SMALL E WITH CIRCUMFLEX */
+ case 0x00EB:
+ return((CHAR)(0xEB & 0xff)); /* SMALL E WITH DIAERESIS */
+ case 0x0301:
+ return((CHAR)(0xEC & 0xff)); /* COMBINING ACUTE ACCENT */
+ case 0x00ED:
+ return((CHAR)(0xED & 0xff)); /* LATIN SMALL LETTER I WITH ACUTE */
+ case 0x00EE:
+ return((CHAR)(0xEE & 0xff)); /* SMALL I WITH CIRCUMFLEX */
+ case 0x00EF:
+ return((CHAR)(0xEF & 0xff)); /* SMALL I WITH DIAERESIS */
+ case 0x0111:
+ return((CHAR)(0xF0 & 0xff)); /* LATIN SMALL LETTER D WITH STROKE */
+ case 0x00F1:
+ return((CHAR)(0xF1 & 0xff)); /* LATIN SMALL LETTER N WITH TILDE */
+ case 0x0323:
+ return((CHAR)(0xF2 & 0xff)); /* COMBINING DOT BELOW */
+ case 0x00F3:
+ return((CHAR)(0xF3 & 0xff)); /* LATIN SMALL LETTER O WITH ACUTE */
+ case 0x00F4:
+ return((CHAR)(0xF4 & 0xff)); /* SMALL O WITH CIRCUMFLEX */
+ case 0x01A1:
+ return((CHAR)(0xF5 & 0xff)); /* LATIN SMALL LETTER O WITH HORN */
+ case 0x00F6:
+ return((CHAR)(0xF6 & 0xff)); /* SMALL O WITH DIAERESIS */
+ case 0x00F7:
+ return((CHAR)(0xF7 & 0xff)); /* DIVISION SIGN */
+ case 0x00F8:
+ return((CHAR)(0xF8 & 0xff)); /* LATIN SMALL LETTER O WITH STROKE */
+ case 0x00F9:
+ return((CHAR)(0xF9 & 0xff)); /* LATIN SMALL LETTER U WITH GRAVE */
+ case 0x00FA:
+ return((CHAR)(0xFA & 0xff)); /* LATIN SMALL LETTER U WITH ACUTE */
+ case 0x00FB:
+ return((CHAR)(0xFB & 0xff)); /* SMALL U WITH CIRCUMFLEX */
+ case 0x00FC:
+ return((CHAR)(0xFC & 0xff)); /* SMALL U WITH DIAERESIS */
+ case 0x01B0:
+ return((CHAR)(0xFD & 0xff)); /* LATIN SMALL LETTER U WITH HORN */
+ case 0x20AB:
+ return((CHAR)(0xFE & 0xff)); /* DONG SIGN */
+ case 0x00FF:
+ return((CHAR)(0xFF & 0xff)); /* SMALL Y WITH DIAERESIS */
+ default: return(0x003f);
+ }
+}
+
+int /* Code Page 037 - EBCDIC (U.S.) */
+#ifdef CK_ANSIC
+tx_cp37(USHORT c)
+#else
+tx_cp37(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ switch (c) {
+ case 0x0000:
+ return((CHAR)(0x00 & 0xff)); /* NULL */
+ case 0x0001:
+ return((CHAR)(0x01 & 0xff)); /* START OF HEADING */
+ case 0x0002:
+ return((CHAR)(0x02 & 0xff)); /* START OF TEXT */
+ case 0x0003:
+ return((CHAR)(0x03 & 0xff)); /* END OF TEXT */
+ case 0x009C:
+ return((CHAR)(0x04 & 0xff)); /* CONTROL */
+ case 0x0009:
+ return((CHAR)(0x05 & 0xff)); /* HORIZONTAL TABULATION */
+ case 0x0086:
+ return((CHAR)(0x06 & 0xff)); /* CONTROL */
+ case 0x007F:
+ return((CHAR)(0x07 & 0xff)); /* DELETE */
+ case 0x0097:
+ return((CHAR)(0x08 & 0xff)); /* CONTROL */
+ case 0x008D:
+ return((CHAR)(0x09 & 0xff)); /* CONTROL */
+ case 0x008E:
+ return((CHAR)(0x0A & 0xff)); /* CONTROL */
+ case 0x000B:
+ return((CHAR)(0x0B & 0xff)); /* VERTICAL TABULATION */
+ case 0x000C:
+ return((CHAR)(0x0C & 0xff)); /* FORM FEED */
+ case 0x000D:
+ return((CHAR)(0x0D & 0xff)); /* CARRIAGE RETURN */
+ case 0x000E:
+ return((CHAR)(0x0E & 0xff)); /* SHIFT OUT */
+ case 0x000F:
+ return((CHAR)(0x0F & 0xff)); /* SHIFT IN */
+ case 0x0010:
+ return((CHAR)(0x10 & 0xff)); /* DATA LINK ESCAPE */
+ case 0x0011:
+ return((CHAR)(0x11 & 0xff)); /* DEVICE CONTROL ONE */
+ case 0x0012:
+ return((CHAR)(0x12 & 0xff)); /* DEVICE CONTROL TWO */
+ case 0x0013:
+ return((CHAR)(0x13 & 0xff)); /* DEVICE CONTROL THREE */
+ case 0x009D:
+ return((CHAR)(0x14 & 0xff)); /* CONTROL */
+ case 0x0085:
+ return((CHAR)(0x15 & 0xff)); /* CONTROL */
+ case 0x0008:
+ return((CHAR)(0x16 & 0xff)); /* BACKSPACE */
+ case 0x0087:
+ return((CHAR)(0x17 & 0xff)); /* CONTROL */
+ case 0x0018:
+ return((CHAR)(0x18 & 0xff)); /* CANCEL */
+ case 0x0019:
+ return((CHAR)(0x19 & 0xff)); /* END OF MEDIUM */
+ case 0x0092:
+ return((CHAR)(0x1A & 0xff)); /* CONTROL */
+ case 0x008F:
+ return((CHAR)(0x1B & 0xff)); /* CONTROL */
+ case 0x001C:
+ return((CHAR)(0x1C & 0xff)); /* FILE SEPARATOR */
+ case 0x001D:
+ return((CHAR)(0x1D & 0xff)); /* GROUP SEPARATOR */
+ case 0x001E:
+ return((CHAR)(0x1E & 0xff)); /* RECORD SEPARATOR */
+ case 0x001F:
+ return((CHAR)(0x1F & 0xff)); /* UNIT SEPARATOR */
+ case 0x0080:
+ return((CHAR)(0x20 & 0xff)); /* CONTROL */
+ case 0x0081:
+ return((CHAR)(0x21 & 0xff)); /* CONTROL */
+ case 0x0082:
+ return((CHAR)(0x22 & 0xff)); /* CONTROL */
+ case 0x0083:
+ return((CHAR)(0x23 & 0xff)); /* CONTROL */
+ case 0x0084:
+ return((CHAR)(0x24 & 0xff)); /* CONTROL */
+ case 0x000A:
+ return((CHAR)(0x25 & 0xff)); /* LINE FEED */
+ case 0x0017:
+ return((CHAR)(0x26 & 0xff)); /* END OF TRANSMISSION BLOCK */
+ case 0x001B:
+ return((CHAR)(0x27 & 0xff)); /* ESCAPE */
+ case 0x0088:
+ return((CHAR)(0x28 & 0xff)); /* CONTROL */
+ case 0x0089:
+ return((CHAR)(0x29 & 0xff)); /* CONTROL */
+ case 0x008A:
+ return((CHAR)(0x2A & 0xff)); /* CONTROL */
+ case 0x008B:
+ return((CHAR)(0x2B & 0xff)); /* CONTROL */
+ case 0x008C:
+ return((CHAR)(0x2C & 0xff)); /* CONTROL */
+ case 0x0005:
+ return((CHAR)(0x2D & 0xff)); /* ENQUIRY */
+ case 0x0006:
+ return((CHAR)(0x2E & 0xff)); /* ACKNOWLEDGE */
+ case 0x0007:
+ return((CHAR)(0x2F & 0xff)); /* BELL */
+ case 0x0090:
+ return((CHAR)(0x30 & 0xff)); /* CONTROL */
+ case 0x0091:
+ return((CHAR)(0x31 & 0xff)); /* CONTROL */
+ case 0x0016:
+ return((CHAR)(0x32 & 0xff)); /* SYNCHRONOUS IDLE */
+ case 0x0093:
+ return((CHAR)(0x33 & 0xff)); /* CONTROL */
+ case 0x0094:
+ return((CHAR)(0x34 & 0xff)); /* CONTROL */
+ case 0x0095:
+ return((CHAR)(0x35 & 0xff)); /* CONTROL */
+ case 0x0096:
+ return((CHAR)(0x36 & 0xff)); /* CONTROL */
+ case 0x0004:
+ return((CHAR)(0x37 & 0xff)); /* END OF TRANSMISSION */
+ case 0x0098:
+ return((CHAR)(0x38 & 0xff)); /* CONTROL */
+ case 0x0099:
+ return((CHAR)(0x39 & 0xff)); /* CONTROL */
+ case 0x009A:
+ return((CHAR)(0x3A & 0xff)); /* CONTROL */
+ case 0x009B:
+ return((CHAR)(0x3B & 0xff)); /* CONTROL */
+ case 0x0014:
+ return((CHAR)(0x3C & 0xff)); /* DEVICE CONTROL FOUR */
+ case 0x0015:
+ return((CHAR)(0x3D & 0xff)); /* NEGATIVE ACKNOWLEDGE */
+ case 0x009E:
+ return((CHAR)(0x3E & 0xff)); /* CONTROL */
+ case 0x001A:
+ return((CHAR)(0x3F & 0xff)); /* SUBSTITUTE */
+ case 0x0020:
+ return((CHAR)(0x40 & 0xff)); /* SPACE */
+ case 0x00A0:
+ return((CHAR)(0x41 & 0xff)); /* NO-BREAK SPACE */
+ case 0x00E2:
+ return((CHAR)(0x42 & 0xff)); /* SMALL LETTER A WITH CIRCUMFLEX */
+ case 0x00E4:
+ return((CHAR)(0x43 & 0xff)); /* SMALL LETTER A WITH DIAERESIS */
+ case 0x00E0:
+ return((CHAR)(0x44 & 0xff)); /* LATIN SMALL LETTER A WITH GRAVE */
+ case 0x00E1:
+ return((CHAR)(0x45 & 0xff)); /* LATIN SMALL LETTER A WITH ACUTE */
+ case 0x00E3:
+ return((CHAR)(0x46 & 0xff)); /* LATIN SMALL LETTER A WITH TILDE */
+ case 0x00E5:
+ return((CHAR)(0x47 & 0xff)); /* SMALL LETTER A WITH RING ABOVE */
+ case 0x00E7:
+ return((CHAR)(0x48 & 0xff)); /* LATIN SMALL LETTER C WITH CEDILLA */
+ case 0x00F1:
+ return((CHAR)(0x49 & 0xff)); /* LATIN SMALL LETTER N WITH TILDE */
+ case 0x00A2:
+ return((CHAR)(0x4A & 0xff)); /* CENT SIGN */
+ case 0x002E:
+ return((CHAR)(0x4B & 0xff)); /* FULL STOP */
+ case 0x003C:
+ return((CHAR)(0x4C & 0xff)); /* LESS-THAN SIGN */
+ case 0x0028:
+ return((CHAR)(0x4D & 0xff)); /* LEFT PARENTHESIS */
+ case 0x002B:
+ return((CHAR)(0x4E & 0xff)); /* PLUS SIGN */
+ case 0x007C:
+ return((CHAR)(0x4F & 0xff)); /* VERTICAL LINE */
+ case 0x0026:
+ return((CHAR)(0x50 & 0xff)); /* AMPERSAND */
+ case 0x00E9:
+ return((CHAR)(0x51 & 0xff)); /* SMALL LETTER E WITH ACUTE */
+ case 0x00EA:
+ return((CHAR)(0x52 & 0xff)); /* SMALL LETTER E WITH CIRCUMFLEX */
+ case 0x00EB:
+ return((CHAR)(0x53 & 0xff)); /* SMALL LETTER E WITH DIAERESIS */
+ case 0x00E8:
+ return((CHAR)(0x54 & 0xff)); /* LATIN SMALL LETTER E WITH GRAVE */
+ case 0x00ED:
+ return((CHAR)(0x55 & 0xff)); /* LATIN SMALL LETTER I WITH ACUTE */
+ case 0x00EE:
+ return((CHAR)(0x56 & 0xff)); /* SMALL LETTER I WITH CIRCUMFLEX */
+ case 0x00EF:
+ return((CHAR)(0x57 & 0xff)); /* SMALL LETTER I WITH DIAERESIS */
+ case 0x00EC:
+ return((CHAR)(0x58 & 0xff)); /* LATIN SMALL LETTER I WITH GRAVE */
+ case 0x00DF:
+ return((CHAR)(0x59 & 0xff)); /* SMALL LETTER SHARP S (GERMAN) */
+ case 0x0021:
+ return((CHAR)(0x5A & 0xff)); /* EXCLAMATION MARK */
+ case 0x0024:
+ return((CHAR)(0x5B & 0xff)); /* DOLLAR SIGN */
+ case 0x002A:
+ return((CHAR)(0x5C & 0xff)); /* ASTERISK */
+ case 0x0029:
+ return((CHAR)(0x5D & 0xff)); /* RIGHT PARENTHESIS */
+ case 0x003B:
+ return((CHAR)(0x5E & 0xff)); /* SEMICOLON */
+ case 0x00AC:
+ return((CHAR)(0x5F & 0xff)); /* NOT SIGN */
+ case 0x002D:
+ return((CHAR)(0x60 & 0xff)); /* HYPHEN-MINUS */
+ case 0x002F:
+ return((CHAR)(0x61 & 0xff)); /* SOLIDUS */
+ case 0x00C2:
+ return((CHAR)(0x62 & 0xff)); /* CAPITAL LETTER A WITH CIRCUMFLEX */
+ case 0x00C4:
+ return((CHAR)(0x63 & 0xff)); /* CAPITAL LETTER A WITH DIAERESIS */
+ case 0x00C0:
+ return((CHAR)(0x64 & 0xff)); /* LATIN CAPITAL LETTER A WITH GRAVE */
+ case 0x00C1:
+ return((CHAR)(0x65 & 0xff)); /* LATIN CAPITAL LETTER A WITH ACUTE */
+ case 0x00C3:
+ return((CHAR)(0x66 & 0xff)); /* LATIN CAPITAL LETTER A WITH TILDE */
+ case 0x00C5:
+ return((CHAR)(0x67 & 0xff)); /* CAPITAL LETTER A WITH RING ABOVE */
+ case 0x00C7:
+ return((CHAR)(0x68 & 0xff)); /* CAPITAL LETTER C WITH CEDILLA */
+ case 0x00D1:
+ return((CHAR)(0x69 & 0xff)); /* LATIN CAPITAL LETTER N WITH TILDE */
+ case 0x00A6:
+ return((CHAR)(0x6A & 0xff)); /* BROKEN BAR */
+ case 0x002C:
+ return((CHAR)(0x6B & 0xff)); /* COMMA */
+ case 0x0025:
+ return((CHAR)(0x6C & 0xff)); /* PERCENT SIGN */
+ case 0x005F:
+ return((CHAR)(0x6D & 0xff)); /* LOW LINE */
+ case 0x003E:
+ return((CHAR)(0x6E & 0xff)); /* GREATER-THAN SIGN */
+ case 0x003F:
+ return((CHAR)(0x6F & 0xff)); /* QUESTION MARK */
+ case 0x00F8:
+ return((CHAR)(0x70 & 0xff)); /* LATIN SMALL LETTER O WITH STROKE */
+ case 0x00C9:
+ return((CHAR)(0x71 & 0xff)); /* LATIN CAPITAL LETTER E WITH ACUTE */
+ case 0x00CA:
+ /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ return((CHAR)(0x72 & 0xff));
+ case 0x00CB:
+ /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+ return((CHAR)(0x73 & 0xff));
+ case 0x00C8:
+ return((CHAR)(0x74 & 0xff)); /* LATIN CAPITAL LETTER E WITH GRAVE */
+ case 0x00CD:
+ return((CHAR)(0x75 & 0xff)); /* LATIN CAPITAL LETTER I WITH ACUTE */
+ case 0x00CE:
+ /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ return((CHAR)(0x76 & 0xff));
+ case 0x00CF:
+ /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+ return((CHAR)(0x77 & 0xff));
+ case 0x00CC:
+ return((CHAR)(0x78 & 0xff)); /* LATIN CAPITAL LETTER I WITH GRAVE */
+ case 0x0060:
+ return((CHAR)(0x79 & 0xff)); /* GRAVE ACCENT */
+ case 0x003A:
+ return((CHAR)(0x7A & 0xff)); /* COLON */
+ case 0x0023:
+ return((CHAR)(0x7B & 0xff)); /* NUMBER SIGN */
+ case 0x0040:
+ return((CHAR)(0x7C & 0xff)); /* COMMERCIAL AT */
+ case 0x0027:
+ return((CHAR)(0x7D & 0xff)); /* APOSTROPHE */
+ case 0x003D:
+ return((CHAR)(0x7E & 0xff)); /* EQUALS SIGN */
+ case 0x0022:
+ return((CHAR)(0x7F & 0xff)); /* QUOTATION MARK */
+ case 0x00D8:
+ /* LATIN CAPITAL LETTER O WITH STROKE */
+ return((CHAR)(0x80 & 0xff));
+ case 0x0061:
+ return((CHAR)(0x81 & 0xff)); /* LATIN SMALL LETTER A */
+ case 0x0062:
+ return((CHAR)(0x82 & 0xff)); /* LATIN SMALL LETTER B */
+ case 0x0063:
+ return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER C */
+ case 0x0064:
+ return((CHAR)(0x84 & 0xff)); /* LATIN SMALL LETTER D */
+ case 0x0065:
+ return((CHAR)(0x85 & 0xff)); /* LATIN SMALL LETTER E */
+ case 0x0066:
+ return((CHAR)(0x86 & 0xff)); /* LATIN SMALL LETTER F */
+ case 0x0067:
+ return((CHAR)(0x87 & 0xff)); /* LATIN SMALL LETTER G */
+ case 0x0068:
+ return((CHAR)(0x88 & 0xff)); /* LATIN SMALL LETTER H */
+ case 0x0069:
+ return((CHAR)(0x89 & 0xff)); /* LATIN SMALL LETTER I */
+ case 0x00AB:
+ /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ return((CHAR)(0x8A & 0xff));
+ case 0x00BB:
+ /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MAR K*/
+ return((CHAR)(0x8B & 0xff));
+ case 0x00F0:
+ /* LATIN SMALL LETTER ETH (ICELANDIC) */
+ return((CHAR)(0x8C & 0xff));
+ case 0x00FD:
+ return((CHAR)(0x8D & 0xff)); /* LATIN SMALL LETTER Y WITH ACUTE */
+ case 0x00FE:
+ /* LATIN SMALL LETTER THORN (ICELANDIC) */
+ return((CHAR)(0x8E & 0xff));
+ case 0x00B1:
+ return((CHAR)(0x8F & 0xff)); /* PLUS-MINUS SIGN */
+ case 0x00B0:
+ return((CHAR)(0x90 & 0xff)); /* DEGREE SIGN */
+ case 0x006A:
+ return((CHAR)(0x91 & 0xff)); /* LATIN SMALL LETTER J */
+ case 0x006B:
+ return((CHAR)(0x92 & 0xff)); /* LATIN SMALL LETTER K */
+ case 0x006C:
+ return((CHAR)(0x93 & 0xff)); /* LATIN SMALL LETTER L */
+ case 0x006D:
+ return((CHAR)(0x94 & 0xff)); /* LATIN SMALL LETTER M */
+ case 0x006E:
+ return((CHAR)(0x95 & 0xff)); /* LATIN SMALL LETTER N */
+ case 0x006F:
+ return((CHAR)(0x96 & 0xff)); /* LATIN SMALL LETTER O */
+ case 0x0070:
+ return((CHAR)(0x97 & 0xff)); /* LATIN SMALL LETTER P */
+ case 0x0071:
+ return((CHAR)(0x98 & 0xff)); /* LATIN SMALL LETTER Q */
+ case 0x0072:
+ return((CHAR)(0x99 & 0xff)); /* LATIN SMALL LETTER R */
+ case 0x00AA:
+ return((CHAR)(0x9A & 0xff)); /* FEMININE ORDINAL INDICATOR */
+ case 0x00BA:
+ return((CHAR)(0x9B & 0xff)); /* MASCULINE ORDINAL INDICATOR */
+ case 0x00E6:
+ return((CHAR)(0x9C & 0xff)); /* LATIN SMALL LIGATURE AE */
+ case 0x00B8:
+ return((CHAR)(0x9D & 0xff)); /* CEDILLA */
+ case 0x00C6:
+ return((CHAR)(0x9E & 0xff)); /* LATIN CAPITAL LIGATURE AE */
+ case 0x00A4:
+ return((CHAR)(0x9F & 0xff)); /* CURRENCY SIGN */
+ case 0x00B5:
+ return((CHAR)(0xA0 & 0xff)); /* MICRO SIGN */
+ case 0x007E:
+ return((CHAR)(0xA1 & 0xff)); /* TILDE */
+ case 0x0073:
+ return((CHAR)(0xA2 & 0xff)); /* LATIN SMALL LETTER S */
+ case 0x0074:
+ return((CHAR)(0xA3 & 0xff)); /* LATIN SMALL LETTER T */
+ case 0x0075:
+ return((CHAR)(0xA4 & 0xff)); /* LATIN SMALL LETTER U */
+ case 0x0076:
+ return((CHAR)(0xA5 & 0xff)); /* LATIN SMALL LETTER V */
+ case 0x0077:
+ return((CHAR)(0xA6 & 0xff)); /* LATIN SMALL LETTER W */
+ case 0x0078:
+ return((CHAR)(0xA7 & 0xff)); /* LATIN SMALL LETTER X */
+ case 0x0079:
+ return((CHAR)(0xA8 & 0xff)); /* LATIN SMALL LETTER Y */
+ case 0x007A:
+ return((CHAR)(0xA9 & 0xff)); /* LATIN SMALL LETTER Z */
+ case 0x00A1:
+ return((CHAR)(0xAA & 0xff)); /* INVERTED EXCLAMATION MARK */
+ case 0x00BF:
+ return((CHAR)(0xAB & 0xff)); /* INVERTED QUESTION MARK */
+ case 0x00D0:
+ /* LATIN CAPITAL LETTER ETH (ICELANDIC) */
+ return((CHAR)(0xAC & 0xff));
+ case 0x00DD:
+ return((CHAR)(0xAD & 0xff)); /* LATIN CAPITAL LETTER Y WITH ACUTE */
+ case 0x00DE:
+ /* LATIN CAPITAL LETTER THORN (ICELANDIC) */
+ return((CHAR)(0xAE & 0xff));
+ case 0x00AE:
+ return((CHAR)(0xAF & 0xff)); /* REGISTERED SIGN */
+ case 0x005E:
+ return((CHAR)(0xB0 & 0xff)); /* CIRCUMFLEX ACCENT */
+ case 0x00A3:
+ return((CHAR)(0xB1 & 0xff)); /* POUND SIGN */
+ case 0x00A5:
+ return((CHAR)(0xB2 & 0xff)); /* YEN SIGN */
+ case 0x00B7:
+ return((CHAR)(0xB3 & 0xff)); /* MIDDLE DOT */
+ case 0x00A9:
+ return((CHAR)(0xB4 & 0xff)); /* COPYRIGHT SIGN */
+ case 0x00A7:
+ return((CHAR)(0xB5 & 0xff)); /* SECTION SIGN */
+ case 0x00B6:
+ return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */
+ case 0x00BC:
+ return((CHAR)(0xB7 & 0xff)); /* VULGAR FRACTION ONE QUARTER */
+ case 0x00BD:
+ return((CHAR)(0xB8 & 0xff)); /* VULGAR FRACTION ONE HALF */
+ case 0x00BE:
+ return((CHAR)(0xB9 & 0xff)); /* VULGAR FRACTION THREE QUARTERS */
+ case 0x005B:
+ return((CHAR)(0xBA & 0xff)); /* LEFT SQUARE BRACKET */
+ case 0x005D:
+ return((CHAR)(0xBB & 0xff)); /* RIGHT SQUARE BRACKET */
+ case 0x00AF:
+ return((CHAR)(0xBC & 0xff)); /* MACRON */
+ case 0x00A8:
+ return((CHAR)(0xBD & 0xff)); /* DIAERESIS */
+ case 0x00B4:
+ return((CHAR)(0xBE & 0xff)); /* ACUTE ACCENT */
+ case 0x00D7:
+ return((CHAR)(0xBF & 0xff)); /* MULTIPLICATION SIGN */
+ case 0x007B:
+ return((CHAR)(0xC0 & 0xff)); /* LEFT CURLY BRACKET */
+ case 0x0041:
+ return((CHAR)(0xC1 & 0xff)); /* LATIN CAPITAL LETTER A */
+ case 0x0042:
+ return((CHAR)(0xC2 & 0xff)); /* LATIN CAPITAL LETTER B */
+ case 0x0043:
+ return((CHAR)(0xC3 & 0xff)); /* LATIN CAPITAL LETTER C */
+ case 0x0044:
+ return((CHAR)(0xC4 & 0xff)); /* LATIN CAPITAL LETTER D */
+ case 0x0045:
+ return((CHAR)(0xC5 & 0xff)); /* LATIN CAPITAL LETTER E */
+ case 0x0046:
+ return((CHAR)(0xC6 & 0xff)); /* LATIN CAPITAL LETTER F */
+ case 0x0047:
+ return((CHAR)(0xC7 & 0xff)); /* LATIN CAPITAL LETTER G */
+ case 0x0048:
+ return((CHAR)(0xC8 & 0xff)); /* LATIN CAPITAL LETTER H */
+ case 0x0049:
+ return((CHAR)(0xC9 & 0xff)); /* LATIN CAPITAL LETTER I */
+ case 0x00AD:
+ return((CHAR)(0xCA & 0xff)); /* SOFT HYPHEN */
+ case 0x00F4:
+ return((CHAR)(0xCB & 0xff)); /* SMALL LETTER O WITH CIRCUMFLEX */
+ case 0x00F6:
+ return((CHAR)(0xCC & 0xff)); /* SMALL LETTER O WITH DIAERESIS */
+ case 0x00F2:
+ return((CHAR)(0xCD & 0xff)); /* LATIN SMALL LETTER O WITH GRAVE */
+ case 0x00F3:
+ return((CHAR)(0xCE & 0xff)); /* LATIN SMALL LETTER O WITH ACUTE */
+ case 0x00F5:
+ return((CHAR)(0xCF & 0xff)); /* LATIN SMALL LETTER O WITH TILDE */
+ case 0x007D:
+ return((CHAR)(0xD0 & 0xff)); /* RIGHT CURLY BRACKET */
+ case 0x004A:
+ return((CHAR)(0xD1 & 0xff)); /* LATIN CAPITAL LETTER J */
+ case 0x004B:
+ return((CHAR)(0xD2 & 0xff)); /* LATIN CAPITAL LETTER K */
+ case 0x004C:
+ return((CHAR)(0xD3 & 0xff)); /* LATIN CAPITAL LETTER L */
+ case 0x004D:
+ return((CHAR)(0xD4 & 0xff)); /* LATIN CAPITAL LETTER M */
+ case 0x004E:
+ return((CHAR)(0xD5 & 0xff)); /* LATIN CAPITAL LETTER N */
+ case 0x004F:
+ return((CHAR)(0xD6 & 0xff)); /* LATIN CAPITAL LETTER O */
+ case 0x0050:
+ return((CHAR)(0xD7 & 0xff)); /* LATIN CAPITAL LETTER P */
+ case 0x0051:
+ return((CHAR)(0xD8 & 0xff)); /* LATIN CAPITAL LETTER Q */
+ case 0x0052:
+ return((CHAR)(0xD9 & 0xff)); /* LATIN CAPITAL LETTER R */
+ case 0x00B9:
+ return((CHAR)(0xDA & 0xff)); /* SUPERSCRIPT ONE */
+ case 0x00FB:
+ return((CHAR)(0xDB & 0xff)); /* SMALL LETTER U WITH CIRCUMFLEX */
+ case 0x00FC:
+ return((CHAR)(0xDC & 0xff)); /* SMALL LETTER U WITH DIAERESIS */
+ case 0x00F9:
+ return((CHAR)(0xDD & 0xff)); /* SMALL LETTER U WITH GRAVE */
+ case 0x00FA:
+ return((CHAR)(0xDE & 0xff)); /* SMALL LETTER U WITH ACUTE */
+ case 0x00FF:
+ return((CHAR)(0xDF & 0xff)); /* SMALL LETTER Y WITH DIAERESIS */
+ case 0x005C:
+ return((CHAR)(0xE0 & 0xff)); /* REVERSE SOLIDUS */
+ case 0x00F7:
+ return((CHAR)(0xE1 & 0xff)); /* DIVISION SIGN */
+ case 0x0053:
+ return((CHAR)(0xE2 & 0xff)); /* LATIN CAPITAL LETTER S */
+ case 0x0054:
+ return((CHAR)(0xE3 & 0xff)); /* LATIN CAPITAL LETTER T */
+ case 0x0055:
+ return((CHAR)(0xE4 & 0xff)); /* LATIN CAPITAL LETTER U */
+ case 0x0056:
+ return((CHAR)(0xE5 & 0xff)); /* LATIN CAPITAL LETTER V */
+ case 0x0057:
+ return((CHAR)(0xE6 & 0xff)); /* LATIN CAPITAL LETTER W */
+ case 0x0058:
+ return((CHAR)(0xE7 & 0xff)); /* LATIN CAPITAL LETTER X */
+ case 0x0059:
+ return((CHAR)(0xE8 & 0xff)); /* LATIN CAPITAL LETTER Y */
+ case 0x005A:
+ return((CHAR)(0xE9 & 0xff)); /* LATIN CAPITAL LETTER Z */
+ case 0x00B2:
+ return((CHAR)(0xEA & 0xff)); /* SUPERSCRIPT TWO */
+ case 0x00D4:
+ return((CHAR)(0xEB & 0xff)); /* CAPITAL LETTER O WITH CIRCUMFLEX */
+ case 0x00D6:
+ return((CHAR)(0xEC & 0xff)); /* CAPITAL LETTER O WITH DIAERESIS */
+ case 0x00D2:
+ return((CHAR)(0xED & 0xff)); /* CAPITAL LETTER O WITH GRAVE */
+ case 0x00D3:
+ return((CHAR)(0xEE & 0xff)); /* CAPITAL LETTER O WITH ACUTE */
+ case 0x00D5:
+ return((CHAR)(0xEF & 0xff)); /* CAPITAL LETTER O WITH TILDE */
+ case 0x0030:
+ return((CHAR)(0xF0 & 0xff)); /* DIGIT ZERO */
+ case 0x0031:
+ return((CHAR)(0xF1 & 0xff)); /* DIGIT ONE */
+ case 0x0032:
+ return((CHAR)(0xF2 & 0xff)); /* DIGIT TWO */
+ case 0x0033:
+ return((CHAR)(0xF3 & 0xff)); /* DIGIT THREE */
+ case 0x0034:
+ return((CHAR)(0xF4 & 0xff)); /* DIGIT FOUR */
+ case 0x0035:
+ return((CHAR)(0xF5 & 0xff)); /* DIGIT FIVE */
+ case 0x0036:
+ return((CHAR)(0xF6 & 0xff)); /* DIGIT SIX */
+ case 0x0037:
+ return((CHAR)(0xF7 & 0xff)); /* DIGIT SEVEN */
+ case 0x0038:
+ return((CHAR)(0xF8 & 0xff)); /* DIGIT EIGHT */
+ case 0x0039:
+ return((CHAR)(0xF9 & 0xff)); /* DIGIT NINE */
+ case 0x00B3:
+ return((CHAR)(0xFA & 0xff)); /* SUPERSCRIPT THREE */
+ case 0x00DB:
+ return((CHAR)(0xFB & 0xff)); /* CAPITAL LETTER U WITH CIRCUMFLEX */
+ case 0x00DC:
+ return((CHAR)(0xFC & 0xff)); /* CAPITAL LETTER U WITH DIAERESIS */
+ case 0x00D9:
+ return((CHAR)(0xFD & 0xff)); /* LATIN CAPITAL LETTER U WITH GRAVE */
+ case 0x00DA:
+ return((CHAR)(0xFE & 0xff)); /* LATIN CAPITAL LETTER U WITH ACUTE */
+ case 0x009F:
+ return((CHAR)(0xFF & 0xff)); /* CONTROL */
+ default: return(0x003f);
+ }
+}
+
+
+int /* PC Code Page 855 */
+#ifdef CK_ANSIC
+tx_cp855(USHORT c)
+#else
+tx_cp855(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a4: return((CHAR)(207 & 0xff));
+ case 0x00a7: return((CHAR)(253 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x0401: return((CHAR)(133 & 0xff));
+ case 0x0402: return((CHAR)(129 & 0xff));
+ case 0x0403: return((CHAR)(131 & 0xff));
+ case 0x0404: return((CHAR)(135 & 0xff));
+ case 0x0405: return((CHAR)(137 & 0xff));
+ case 0x0406: return((CHAR)(139 & 0xff));
+ case 0x0407: return((CHAR)(141 & 0xff));
+ case 0x0408: return((CHAR)(143 & 0xff));
+ case 0x0409: return((CHAR)(145 & 0xff));
+ case 0x040a: return((CHAR)(147 & 0xff));
+ case 0x040b: return((CHAR)(149 & 0xff));
+ case 0x040c: return((CHAR)(151 & 0xff));
+ case 0x040e: return((CHAR)(153 & 0xff));
+ case 0x040f: return((CHAR)(155 & 0xff));
+ case 0x0410: return((CHAR)(161 & 0xff));
+ case 0x0411: return((CHAR)(163 & 0xff));
+ case 0x0412: return((CHAR)(236 & 0xff));
+ case 0x0413: return((CHAR)(173 & 0xff));
+ case 0x0414: return((CHAR)(167 & 0xff));
+ case 0x0415: return((CHAR)(169 & 0xff));
+ case 0x0416: return((CHAR)(234 & 0xff));
+ case 0x0417: return((CHAR)(244 & 0xff));
+ case 0x0418: return((CHAR)(184 & 0xff));
+ case 0x0419: return((CHAR)(190 & 0xff));
+ case 0x041a: return((CHAR)(199 & 0xff));
+ case 0x041b: return((CHAR)(209 & 0xff));
+ case 0x041c: return((CHAR)(211 & 0xff));
+ case 0x041d: return((CHAR)(213 & 0xff));
+ case 0x041e: return((CHAR)(215 & 0xff));
+ case 0x041f: return((CHAR)(221 & 0xff));
+ case 0x0420: return((CHAR)(226 & 0xff));
+ case 0x0421: return((CHAR)(228 & 0xff));
+ case 0x0422: return((CHAR)(230 & 0xff));
+ case 0x0423: return((CHAR)(232 & 0xff));
+ case 0x0424: return((CHAR)(171 & 0xff));
+ case 0x0425: return((CHAR)(182 & 0xff));
+ case 0x0426: return((CHAR)(165 & 0xff));
+ case 0x0427: return((CHAR)(252 & 0xff));
+ case 0x0428: return((CHAR)(246 & 0xff));
+ case 0x0429: return((CHAR)(250 & 0xff));
+ case 0x042a: return((CHAR)(159 & 0xff));
+ case 0x042b: return((CHAR)(242 & 0xff));
+ case 0x042c: return((CHAR)(238 & 0xff));
+ case 0x042d: return((CHAR)(248 & 0xff));
+ case 0x042e: return((CHAR)(157 & 0xff));
+ case 0x042f: return((CHAR)(224 & 0xff));
+ case 0x0430: return((CHAR)(160 & 0xff));
+ case 0x0431: return((CHAR)(162 & 0xff));
+ case 0x0432: return((CHAR)(235 & 0xff));
+ case 0x0433: return((CHAR)(172 & 0xff));
+ case 0x0434: return((CHAR)(166 & 0xff));
+ case 0x0435: return((CHAR)(168 & 0xff));
+ case 0x0436: return((CHAR)(233 & 0xff));
+ case 0x0437: return((CHAR)(243 & 0xff));
+ case 0x0438: return((CHAR)(183 & 0xff));
+ case 0x0439: return((CHAR)(189 & 0xff));
+ case 0x043a: return((CHAR)(198 & 0xff));
+ case 0x043b: return((CHAR)(208 & 0xff));
+ case 0x043c: return((CHAR)(210 & 0xff));
+ case 0x043d: return((CHAR)(212 & 0xff));
+ case 0x043e: return((CHAR)(214 & 0xff));
+ case 0x043f: return((CHAR)(216 & 0xff));
+ case 0x0440: return((CHAR)(225 & 0xff));
+ case 0x0441: return((CHAR)(227 & 0xff));
+ case 0x0442: return((CHAR)(229 & 0xff));
+ case 0x0443: return((CHAR)(231 & 0xff));
+ case 0x0444: return((CHAR)(170 & 0xff));
+ case 0x0445: return((CHAR)(181 & 0xff));
+ case 0x0446: return((CHAR)(164 & 0xff));
+ case 0x0447: return((CHAR)(251 & 0xff));
+ case 0x0448: return((CHAR)(245 & 0xff));
+ case 0x0449: return((CHAR)(249 & 0xff));
+ case 0x044a: return((CHAR)(158 & 0xff));
+ case 0x044b: return((CHAR)(241 & 0xff));
+ case 0x044c: return((CHAR)(237 & 0xff));
+ case 0x044d: return((CHAR)(247 & 0xff));
+ case 0x044e: return((CHAR)(156 & 0xff));
+ case 0x044f: return((CHAR)(222 & 0xff));
+ case 0x0451: return((CHAR)(132 & 0xff));
+ case 0x0452: return((CHAR)(128 & 0xff));
+ case 0x0453: return((CHAR)(130 & 0xff));
+ case 0x0454: return((CHAR)(134 & 0xff));
+ case 0x0455: return((CHAR)(136 & 0xff));
+ case 0x0456: return((CHAR)(138 & 0xff));
+ case 0x0457: return((CHAR)(140 & 0xff));
+ case 0x0458: return((CHAR)(142 & 0xff));
+ case 0x0459: return((CHAR)(144 & 0xff));
+ case 0x045a: return((CHAR)(146 & 0xff));
+ case 0x045b: return((CHAR)(148 & 0xff));
+ case 0x045c: return((CHAR)(150 & 0xff));
+ case 0x045e: return((CHAR)(152 & 0xff));
+ case 0x045f: return((CHAR)(154 & 0xff));
+ case 0x2116: return((CHAR)(239 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 856 */
+#ifdef CK_ANSIC
+tx_cp856(USHORT c)
+#else
+tx_cp856(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(0xff & 0xff));
+ case 0x00a7: return((CHAR)(0xd6 & 0xff));
+ case 0x00b0: return((CHAR)(0xf8 & 0xff));
+ case 0x00b1: return((CHAR)(0xf1 & 0xff));
+ case 0x00b2: return((CHAR)(0xfd & 0xff));
+ case 0x00b5: return((CHAR)(0xe6 & 0xff));
+ case 0x00b7: return((CHAR)(0xfa & 0xff));
+ case 0x00df: return((CHAR)(0xe1 & 0xff));
+ case 0x00f7: return((CHAR)(0xf6 & 0xff));
+ case 0x0393: return((CHAR)(0xe2 & 0xff));
+ case 0x0398: return((CHAR)(0xe9 & 0xff));
+ case 0x03a3: return((CHAR)(0xe4 & 0xff));
+ case 0x03a6: return((CHAR)(0xe8 & 0xff));
+ case 0x03a9: return((CHAR)(0xea & 0xff));
+ case 0x03b1: return((CHAR)(0xe0 & 0xff));
+ case 0x03b4: return((CHAR)(0xeb & 0xff));
+ case 0x03b5: return((CHAR)(0xee & 0xff));
+ case 0x03c0: return((CHAR)(0xe3 & 0xff));
+ case 0x03c3: return((CHAR)(0xe5 & 0xff));
+ case 0x03c4: return((CHAR)(0xe7 & 0xff));
+ case 0x03c6: return((CHAR)(0xed & 0xff));
+ case 0x0410: return((CHAR)(0x80 & 0xff));
+ case 0x0411: return((CHAR)(0x81 & 0xff));
+ case 0x0412: return((CHAR)(0x82 & 0xff));
+ case 0x0413: return((CHAR)(0x83 & 0xff));
+ case 0x0414: return((CHAR)(0x84 & 0xff));
+ case 0x0415: return((CHAR)(0x85 & 0xff));
+ case 0x0416: return((CHAR)(0x86 & 0xff));
+ case 0x0417: return((CHAR)(0x87 & 0xff));
+ case 0x0418: return((CHAR)(0x88 & 0xff));
+ case 0x0419: return((CHAR)(0x89 & 0xff));
+ case 0x041a: return((CHAR)(0x8a & 0xff));
+ case 0x041b: return((CHAR)(0x8b & 0xff));
+ case 0x041c: return((CHAR)(0x8c & 0xff));
+ case 0x041d: return((CHAR)(0x8d & 0xff));
+ case 0x041e: return((CHAR)(0x8e & 0xff));
+ case 0x041f: return((CHAR)(0x8f & 0xff));
+ case 0x0420: return((CHAR)(0x90 & 0xff));
+ case 0x0421: return((CHAR)(0x91 & 0xff));
+ case 0x0422: return((CHAR)(0x92 & 0xff));
+ case 0x0423: return((CHAR)(0x93 & 0xff));
+ case 0x0424: return((CHAR)(0x94 & 0xff));
+ case 0x0425: return((CHAR)(0x95 & 0xff));
+ case 0x0426: return((CHAR)(0x96 & 0xff));
+ case 0x0427: return((CHAR)(0x97 & 0xff));
+ case 0x0428: return((CHAR)(0x98 & 0xff));
+ case 0x0429: return((CHAR)(0x99 & 0xff));
+ case 0x042a: return((CHAR)(0x9a & 0xff));
+ case 0x042b: return((CHAR)(0x9b & 0xff));
+ case 0x042c: return((CHAR)(0x9c & 0xff));
+ case 0x042d: return((CHAR)(0x9d & 0xff));
+ case 0x042e: return((CHAR)(0x9e & 0xff));
+ case 0x042f: return((CHAR)(0x9f & 0xff));
+ case 0x0430: return((CHAR)(0xa0 & 0xff));
+ case 0x0431: return((CHAR)(0xa1 & 0xff));
+ case 0x0432: return((CHAR)(0xa2 & 0xff));
+ case 0x0433: return((CHAR)(0xa3 & 0xff));
+ case 0x0434: return((CHAR)(0xa4 & 0xff));
+ case 0x0435: return((CHAR)(0xa5 & 0xff));
+ case 0x0436: return((CHAR)(0xa6 & 0xff));
+ case 0x0437: return((CHAR)(0xa7 & 0xff));
+ case 0x0438: return((CHAR)(0xa8 & 0xff));
+ case 0x0439: return((CHAR)(0xa9 & 0xff));
+ case 0x043a: return((CHAR)(0xaa & 0xff));
+ case 0x043b: return((CHAR)(0xab & 0xff));
+ case 0x043c: return((CHAR)(0xac & 0xff));
+ case 0x043d: return((CHAR)(0xad & 0xff));
+ case 0x043e: return((CHAR)(0xae & 0xff));
+ case 0x043f: return((CHAR)(0xaf & 0xff));
+ case 0x0440: return((CHAR)(0xb0 & 0xff));
+ case 0x0441: return((CHAR)(0xb1 & 0xff));
+ case 0x0442: return((CHAR)(0xb2 & 0xff));
+ case 0x0443: return((CHAR)(0xb3 & 0xff));
+ case 0x0444: return((CHAR)(0xb4 & 0xff));
+ case 0x0445: return((CHAR)(0xb5 & 0xff));
+ case 0x0446: return((CHAR)(0xb6 & 0xff));
+ case 0x0447: return((CHAR)(0xb7 & 0xff));
+ case 0x0448: return((CHAR)(0xb8 & 0xff));
+ case 0x0449: return((CHAR)(0xb9 & 0xff));
+ case 0x044a: return((CHAR)(0xba & 0xff));
+ case 0x044b: return((CHAR)(0xbb & 0xff));
+ case 0x044c: return((CHAR)(0xbc & 0xff));
+ case 0x044d: return((CHAR)(0xbd & 0xff));
+ case 0x044e: return((CHAR)(0xbe & 0xff));
+ case 0x044f: return((CHAR)(0xbf & 0xff));
+ case 0x207f: return((CHAR)(0xfc & 0xff));
+ case 0x2116: return((CHAR)(0xd5 & 0xff));
+ case 0x2219: return((CHAR)(0xf9 & 0xff));
+ case 0x221a: return((CHAR)(0xfb & 0xff));
+ case 0x221e: return((CHAR)(0xec & 0xff));
+ case 0x2229: return((CHAR)(0xef & 0xff));
+ case 0x2248: return((CHAR)(0xf7 & 0xff));
+ case 0x2261: return((CHAR)(0xf0 & 0xff));
+ case 0x2264: return((CHAR)(0xf3 & 0xff));
+ case 0x2265: return((CHAR)(0xf2 & 0xff));
+ case 0x2320: return((CHAR)(0xf4 & 0xff));
+ case 0x2321: return((CHAR)(0xf5 & 0xff));
+ case 0x2500: return((CHAR)(0xc4 & 0xff));
+ case 0x2502: return((CHAR)(0xd3 & 0xff));
+ case 0x250c: return((CHAR)(0xda & 0xff));
+ case 0x2510: return((CHAR)(0xcf & 0xff));
+ case 0x2514: return((CHAR)(0xc0 & 0xff));
+ case 0x2518: return((CHAR)(0xd9 & 0xff));
+ case 0x251c: return((CHAR)(0xc3 & 0xff));
+ case 0x2524: return((CHAR)(0xd4 & 0xff));
+ case 0x252c: return((CHAR)(0xc2 & 0xff));
+ case 0x2534: return((CHAR)(0xc1 & 0xff));
+ case 0x253c: return((CHAR)(0xc5 & 0xff));
+ case 0x2550: return((CHAR)(0xcd & 0xff));
+ case 0x2551: return((CHAR)(0xc7 & 0xff));
+ case 0x2554: return((CHAR)(0xc9 & 0xff));
+ case 0x2557: return((CHAR)(0xd7 & 0xff));
+ case 0x255a: return((CHAR)(0xc8 & 0xff));
+ case 0x255d: return((CHAR)(0xd8 & 0xff));
+ case 0x2560: return((CHAR)(0xcc & 0xff));
+ case 0x2563: return((CHAR)(0xc6 & 0xff));
+ case 0x2566: return((CHAR)(0xcb & 0xff));
+ case 0x2569: return((CHAR)(0xca & 0xff));
+ case 0x256c: return((CHAR)(0xce & 0xff));
+ case 0x2580: return((CHAR)(0xdf & 0xff));
+ case 0x2584: return((CHAR)(0xdc & 0xff));
+ case 0x2588: return((CHAR)(0xdb & 0xff));
+ case 0x258c: return((CHAR)(0xdd & 0xff));
+ case 0x2590: return((CHAR)(0xde & 0xff));
+ case 0x2591: return((CHAR)(0xd0 & 0xff));
+ case 0x2592: return((CHAR)(0xd1 & 0xff));
+ case 0x2593: return((CHAR)(0xd2 & 0xff));
+ case 0x25a0: return((CHAR)(0xfe & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 857 */
+#ifdef CK_ANSIC
+tx_cp857(USHORT c)
+#else
+tx_cp857(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00c7: return((CHAR)(128 & 0xff));
+ case 0x00fc: return((CHAR)(129 & 0xff));
+ case 0x00e9: return((CHAR)(130 & 0xff));
+ case 0x00e2: return((CHAR)(131 & 0xff));
+ case 0x00e4: return((CHAR)(132 & 0xff));
+ case 0x00e0: return((CHAR)(133 & 0xff));
+ case 0x00e5: return((CHAR)(134 & 0xff));
+ case 0x00e7: return((CHAR)(135 & 0xff));
+ case 0x00ea: return((CHAR)(136 & 0xff));
+ case 0x00eb: return((CHAR)(137 & 0xff));
+ case 0x00e8: return((CHAR)(138 & 0xff));
+ case 0x00ef: return((CHAR)(139 & 0xff));
+ case 0x00ee: return((CHAR)(140 & 0xff));
+ case 0x0131: return((CHAR)(141 & 0xff));
+ case 0x00c4: return((CHAR)(142 & 0xff));
+ case 0x00c5: return((CHAR)(143 & 0xff));
+ case 0x00c9: return((CHAR)(144 & 0xff));
+ case 0x00e6: return((CHAR)(145 & 0xff));
+ case 0x00c6: return((CHAR)(146 & 0xff));
+ case 0x00f4: return((CHAR)(147 & 0xff));
+ case 0x00f6: return((CHAR)(148 & 0xff));
+ case 0x00f2: return((CHAR)(149 & 0xff));
+ case 0x00fb: return((CHAR)(150 & 0xff));
+ case 0x00f9: return((CHAR)(151 & 0xff));
+ case 0x0130: return((CHAR)(152 & 0xff));
+ case 0x00d6: return((CHAR)(153 & 0xff));
+ case 0x00dc: return((CHAR)(154 & 0xff));
+ case 0x00f8: return((CHAR)(155 & 0xff));
+ case 0x00a3: return((CHAR)(156 & 0xff));
+ case 0x00d8: return((CHAR)(157 & 0xff));
+ case 0x015e: return((CHAR)(158 & 0xff));
+ case 0x015f: return((CHAR)(159 & 0xff));
+ case 0x00e1: return((CHAR)(160 & 0xff));
+ case 0x00ed: return((CHAR)(161 & 0xff));
+ case 0x00f3: return((CHAR)(162 & 0xff));
+ case 0x00fa: return((CHAR)(163 & 0xff));
+ case 0x00f1: return((CHAR)(164 & 0xff));
+ case 0x00d1: return((CHAR)(165 & 0xff));
+ case 0x011e: return((CHAR)(166 & 0xff));
+ case 0x011f: return((CHAR)(167 & 0xff));
+ case 0x00bf: return((CHAR)(168 & 0xff));
+ case 0x00ae: return((CHAR)(169 & 0xff));
+ case 0x00ac: return((CHAR)(170 & 0xff));
+ case 0x00bd: return((CHAR)(171 & 0xff));
+ case 0x00bc: return((CHAR)(172 & 0xff));
+ case 0x00a1: return((CHAR)(173 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x20ac: return((CHAR)(213 & 0xff)); /* Euro */
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x00c1: return((CHAR)(181 & 0xff));
+ case 0x00c2: return((CHAR)(182 & 0xff));
+ case 0x00c0: return((CHAR)(183 & 0xff));
+ case 0x00a9: return((CHAR)(184 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x00a2: return((CHAR)(189 & 0xff));
+ case 0x00a5: return((CHAR)(190 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x00e3: return((CHAR)(198 & 0xff));
+ case 0x00c3: return((CHAR)(199 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x00a4: return((CHAR)(207 & 0xff));
+ case 0x00ba: return((CHAR)(208 & 0xff));
+ case 0x00aa: return((CHAR)(209 & 0xff));
+ case 0x00ca: return((CHAR)(210 & 0xff));
+ case 0x00cb: return((CHAR)(211 & 0xff));
+ case 0x00c8: return((CHAR)(212 & 0xff));
+ case 0x00cd: return((CHAR)(214 & 0xff));
+ case 0x00ce: return((CHAR)(215 & 0xff));
+ case 0x00cf: return((CHAR)(216 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x00a6: return((CHAR)(221 & 0xff));
+ case 0x00cc: return((CHAR)(222 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x00d3: return((CHAR)(224 & 0xff));
+ case 0x00df: return((CHAR)(225 & 0xff));
+ case 0x00d4: return((CHAR)(226 & 0xff));
+ case 0x00d2: return((CHAR)(227 & 0xff));
+ case 0x00f5: return((CHAR)(228 & 0xff));
+ case 0x00d5: return((CHAR)(229 & 0xff));
+ case 0x00b5: return((CHAR)(230 & 0xff));
+ case 0x00d7: return((CHAR)(232 & 0xff));
+ case 0x00da: return((CHAR)(233 & 0xff));
+ case 0x00db: return((CHAR)(234 & 0xff));
+ case 0x00d9: return((CHAR)(235 & 0xff));
+ case 0x00ec: return((CHAR)(236 & 0xff));
+ case 0x00ff: return((CHAR)(237 & 0xff));
+ case 0x00af: return((CHAR)(238 & 0xff));
+ case 0x00b4: return((CHAR)(239 & 0xff));
+ case 0x00ad: return((CHAR)(240 & 0xff));
+ case 0x00b1: return((CHAR)(241 & 0xff));
+ case 0x00be: return((CHAR)(243 & 0xff));
+ case 0x00b6: return((CHAR)(244 & 0xff));
+ case 0x00a7: return((CHAR)(245 & 0xff));
+ case 0x00f7: return((CHAR)(246 & 0xff));
+ case 0x00b8: return((CHAR)(247 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00a8: return((CHAR)(249 & 0xff));
+ case 0x00b7: return((CHAR)(250 & 0xff));
+ case 0x00b9: return((CHAR)(251 & 0xff));
+ case 0x00b3: return((CHAR)(252 & 0xff));
+ case 0x00b2: return((CHAR)(253 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 862 */
+#ifdef CK_ANSIC
+tx_cp862(USHORT c)
+#else
+tx_cp862(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x05d0: return((CHAR)(128 & 0xff));
+ case 0x05d1: return((CHAR)(129 & 0xff));
+ case 0x05d2: return((CHAR)(130 & 0xff));
+ case 0x05d3: return((CHAR)(131 & 0xff));
+ case 0x05d4: return((CHAR)(132 & 0xff));
+ case 0x05d5: return((CHAR)(133 & 0xff));
+ case 0x05d6: return((CHAR)(134 & 0xff));
+ case 0x05d7: return((CHAR)(135 & 0xff));
+ case 0x05d8: return((CHAR)(136 & 0xff));
+ case 0x05d9: return((CHAR)(137 & 0xff));
+ case 0x05da: return((CHAR)(138 & 0xff));
+ case 0x05db: return((CHAR)(139 & 0xff));
+ case 0x05dc: return((CHAR)(140 & 0xff));
+ case 0x05dd: return((CHAR)(141 & 0xff));
+ case 0x05de: return((CHAR)(142 & 0xff));
+ case 0x05df: return((CHAR)(143 & 0xff));
+ case 0x05e0: return((CHAR)(144 & 0xff));
+ case 0x05e1: return((CHAR)(145 & 0xff));
+ case 0x05e2: return((CHAR)(146 & 0xff));
+ case 0x05e3: return((CHAR)(147 & 0xff));
+ case 0x05e4: return((CHAR)(148 & 0xff));
+ case 0x05e5: return((CHAR)(149 & 0xff));
+ case 0x05e6: return((CHAR)(150 & 0xff));
+ case 0x05e7: return((CHAR)(151 & 0xff));
+ case 0x05e8: return((CHAR)(152 & 0xff));
+ case 0x05e9: return((CHAR)(153 & 0xff));
+ case 0x05ea: return((CHAR)(154 & 0xff));
+ case 0x00a2: return((CHAR)(155 & 0xff));
+ case 0x00a3: return((CHAR)(156 & 0xff));
+ case 0x00a5: return((CHAR)(157 & 0xff));
+ case 0x20a7: return((CHAR)(158 & 0xff));
+ case 0x0192: return((CHAR)(159 & 0xff));
+ case 0x00e1: return((CHAR)(160 & 0xff));
+ case 0x00ed: return((CHAR)(161 & 0xff));
+ case 0x00f3: return((CHAR)(162 & 0xff));
+ case 0x00fa: return((CHAR)(163 & 0xff));
+ case 0x00f1: return((CHAR)(164 & 0xff));
+ case 0x00d1: return((CHAR)(165 & 0xff));
+ case 0x00aa: return((CHAR)(166 & 0xff));
+ case 0x00ba: return((CHAR)(167 & 0xff));
+ case 0x00bf: return((CHAR)(168 & 0xff));
+ case 0x2310: return((CHAR)(169 & 0xff));
+ case 0x00ac: return((CHAR)(170 & 0xff));
+ case 0x00bd: return((CHAR)(171 & 0xff));
+ case 0x00bc: return((CHAR)(172 & 0xff));
+ case 0x00a1: return((CHAR)(173 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x2561: return((CHAR)(181 & 0xff));
+ case 0x2562: return((CHAR)(182 & 0xff));
+ case 0x2556: return((CHAR)(183 & 0xff));
+ case 0x2555: return((CHAR)(184 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x255c: return((CHAR)(189 & 0xff));
+ case 0x255b: return((CHAR)(190 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x255e: return((CHAR)(198 & 0xff));
+ case 0x255f: return((CHAR)(199 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2567: return((CHAR)(207 & 0xff));
+ case 0x2568: return((CHAR)(208 & 0xff));
+ case 0x2564: return((CHAR)(209 & 0xff));
+ case 0x2565: return((CHAR)(210 & 0xff));
+ case 0x2559: return((CHAR)(211 & 0xff));
+ case 0x2558: return((CHAR)(212 & 0xff));
+ case 0x2552: return((CHAR)(213 & 0xff));
+ case 0x2553: return((CHAR)(214 & 0xff));
+ case 0x256b: return((CHAR)(215 & 0xff));
+ case 0x256a: return((CHAR)(216 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x258c: return((CHAR)(221 & 0xff));
+ case 0x2590: return((CHAR)(222 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x03b1: return((CHAR)(224 & 0xff));
+ case 0x00df: return((CHAR)(225 & 0xff));
+ case 0x0393: return((CHAR)(226 & 0xff));
+ case 0x03c0: return((CHAR)(227 & 0xff));
+ case 0x03a3: return((CHAR)(228 & 0xff));
+ case 0x03c3: return((CHAR)(229 & 0xff));
+ case 0x00b5: return((CHAR)(230 & 0xff));
+ case 0x03c4: return((CHAR)(231 & 0xff));
+ case 0x03a6: return((CHAR)(232 & 0xff));
+ case 0x0398: return((CHAR)(233 & 0xff));
+ case 0x03a9: return((CHAR)(234 & 0xff));
+ case 0x03b4: return((CHAR)(235 & 0xff));
+ case 0x221e: return((CHAR)(236 & 0xff));
+ case 0x03c6: return((CHAR)(237 & 0xff));
+ case 0x03b5: return((CHAR)(238 & 0xff));
+ case 0x2229: return((CHAR)(239 & 0xff));
+ case 0x2261: return((CHAR)(240 & 0xff));
+ case 0x00b1: return((CHAR)(241 & 0xff));
+ case 0x2265: return((CHAR)(242 & 0xff));
+ case 0x2264: return((CHAR)(243 & 0xff));
+ case 0x2320: return((CHAR)(244 & 0xff));
+ case 0x2321: return((CHAR)(245 & 0xff));
+ case 0x00f7: return((CHAR)(246 & 0xff));
+ case 0x2248: return((CHAR)(247 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x2219: return((CHAR)(249 & 0xff));
+ case 0x00b7: return((CHAR)(250 & 0xff));
+ case 0x221a: return((CHAR)(251 & 0xff));
+ case 0x207f: return((CHAR)(252 & 0xff));
+ case 0x00b2: return((CHAR)(253 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 864 */
+#ifdef CK_ANSIC
+tx_cp864(USHORT c)
+#else
+tx_cp864(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00b0: return((CHAR)0x80 & 0xff);
+ case 0x00b7: return((CHAR)0x81 & 0xff);
+ case 0x2219: return((CHAR)0x82 & 0xff);
+ case 0x221a: return((CHAR)0x83 & 0xff);
+ case 0x2592: return((CHAR)0x84 & 0xff);
+ case 0x2500: return((CHAR)0x85 & 0xff);
+ case 0x2502: return((CHAR)0x86 & 0xff);
+ case 0x253c: return((CHAR)0x87 & 0xff);
+ case 0x2524: return((CHAR)0x88 & 0xff);
+ case 0x252c: return((CHAR)0x89 & 0xff);
+ case 0x251c: return((CHAR)0x8a & 0xff);
+ case 0x2534: return((CHAR)0x8b & 0xff);
+ case 0x2510: return((CHAR)0x8c & 0xff);
+ case 0x250c: return((CHAR)0x8d & 0xff);
+ case 0x2514: return((CHAR)0x8e & 0xff);
+ case 0x2518: return((CHAR)0x8f & 0xff);
+ case 0x03b2: return((CHAR)0x90 & 0xff);
+ case 0x221e: return((CHAR)0x91 & 0xff);
+ case 0x03c6: return((CHAR)0x92 & 0xff);
+ case 0x00b1: return((CHAR)0x93 & 0xff);
+ case 0x00bd: return((CHAR)0x94 & 0xff);
+ case 0x00bc: return((CHAR)0x95 & 0xff);
+ case 0x2248: return((CHAR)0x96 & 0xff);
+ case 0x00ab: return((CHAR)0x97 & 0xff);
+ case 0x00bb: return((CHAR)0x98 & 0xff);
+ case 0xfef7: return((CHAR)0x99 & 0xff);
+ case 0xfef8: return((CHAR)0x9a & 0xff);
+ case 0xfefb: return((CHAR)0x9d & 0xff);
+ case 0xfefc: return((CHAR)0x9e & 0xff);
+ case 0x00a0: return((CHAR)0xa0 & 0xff);
+ case 0x00ad: return((CHAR)0xa1 & 0xff);
+ case 0xfe82: return((CHAR)0xa2 & 0xff);
+ case 0x00a3: return((CHAR)0xa3 & 0xff);
+ case 0x00a4: return((CHAR)0xa4 & 0xff);
+ case 0xfe84: return((CHAR)0xa5 & 0xff);
+ case 0xfe8e: return((CHAR)0xa8 & 0xff);
+ case 0xfe8f: return((CHAR)0xa9 & 0xff);
+ case 0xfe95: return((CHAR)0xaa & 0xff);
+ case 0xfe99: return((CHAR)0xab & 0xff);
+ case 0x060c: return((CHAR)0xac & 0xff);
+ case 0xfe9d: return((CHAR)0xad & 0xff);
+ case 0xfea1: return((CHAR)0xae & 0xff);
+ case 0xfea5: return((CHAR)0xaf & 0xff);
+ case 0x0660: return((CHAR)0xb0 & 0xff);
+ case 0x0661: return((CHAR)0xb1 & 0xff);
+ case 0x0662: return((CHAR)0xb2 & 0xff);
+ case 0x0663: return((CHAR)0xb3 & 0xff);
+ case 0x0664: return((CHAR)0xb4 & 0xff);
+ case 0x0665: return((CHAR)0xb5 & 0xff);
+ case 0x0666: return((CHAR)0xb6 & 0xff);
+ case 0x0667: return((CHAR)0xb7 & 0xff);
+ case 0x0668: return((CHAR)0xb8 & 0xff);
+ case 0x0669: return((CHAR)0xb9 & 0xff);
+ case 0xfed1: return((CHAR)0xba & 0xff);
+ case 0x061b: return((CHAR)0xbb & 0xff);
+ case 0xfeb1: return((CHAR)0xbc & 0xff);
+ case 0xfeb5: return((CHAR)0xbd & 0xff);
+ case 0xfeb9: return((CHAR)0xbe & 0xff);
+ case 0x061f: return((CHAR)0xbf & 0xff);
+ case 0x00a2: return((CHAR)0xc0 & 0xff);
+ case 0xfe80: return((CHAR)0xc1 & 0xff);
+ case 0xfe81: return((CHAR)0xc2 & 0xff);
+ case 0xfe83: return((CHAR)0xc3 & 0xff);
+ case 0xfe85: return((CHAR)0xc4 & 0xff);
+ case 0xfeca: return((CHAR)0xc5 & 0xff);
+ case 0xfe8b: return((CHAR)0xc6 & 0xff);
+ case 0xfe8d: return((CHAR)0xc7 & 0xff);
+ case 0xfe91: return((CHAR)0xc8 & 0xff);
+ case 0xfe93: return((CHAR)0xc9 & 0xff);
+ case 0xfe97: return((CHAR)0xca & 0xff);
+ case 0xfe9b: return((CHAR)0xcb & 0xff);
+ case 0xfe9f: return((CHAR)0xcc & 0xff);
+ case 0xfea3: return((CHAR)0xcd & 0xff);
+ case 0xfea7: return((CHAR)0xce & 0xff);
+ case 0xfea9: return((CHAR)0xcf & 0xff);
+ case 0xfeab: return((CHAR)0xd0 & 0xff);
+ case 0xfead: return((CHAR)0xd1 & 0xff);
+ case 0xfeaf: return((CHAR)0xd2 & 0xff);
+ case 0xfeb3: return((CHAR)0xd3 & 0xff);
+ case 0xfeb7: return((CHAR)0xd4 & 0xff);
+ case 0xfebb: return((CHAR)0xd5 & 0xff);
+ case 0xfebf: return((CHAR)0xd6 & 0xff);
+ case 0xfec1: return((CHAR)0xd7 & 0xff);
+ case 0xfec5: return((CHAR)0xd8 & 0xff);
+ case 0xfecb: return((CHAR)0xd9 & 0xff);
+ case 0xfecf: return((CHAR)0xda & 0xff);
+ case 0x00a6: return((CHAR)0xdb & 0xff);
+ case 0x00ac: return((CHAR)0xdc & 0xff);
+ case 0x00f7: return((CHAR)0xdd & 0xff);
+ case 0x00d7: return((CHAR)0xde & 0xff);
+ case 0xfec9: return((CHAR)0xdf & 0xff);
+ case 0x0640: return((CHAR)0xe0 & 0xff);
+ case 0xfed3: return((CHAR)0xe1 & 0xff);
+ case 0xfed7: return((CHAR)0xe2 & 0xff);
+ case 0xfedb: return((CHAR)0xe3 & 0xff);
+ case 0xfedf: return((CHAR)0xe4 & 0xff);
+ case 0xfee3: return((CHAR)0xe5 & 0xff);
+ case 0xfee7: return((CHAR)0xe6 & 0xff);
+ case 0xfeeb: return((CHAR)0xe7 & 0xff);
+ case 0xfeed: return((CHAR)0xe8 & 0xff);
+ case 0xfeef: return((CHAR)0xe9 & 0xff);
+ case 0xfef3: return((CHAR)0xea & 0xff);
+ case 0xfebd: return((CHAR)0xeb & 0xff);
+ case 0xfecc: return((CHAR)0xec & 0xff);
+ case 0xfece: return((CHAR)0xed & 0xff);
+ case 0xfecd: return((CHAR)0xee & 0xff);
+ case 0xfee1: return((CHAR)0xef & 0xff);
+ case 0xfe7d: return((CHAR)0xf0 & 0xff);
+ case 0x0651: return((CHAR)0xf1 & 0xff);
+ case 0xfee5: return((CHAR)0xf2 & 0xff);
+ case 0xfee9: return((CHAR)0xf3 & 0xff);
+ case 0xfeec: return((CHAR)0xf4 & 0xff);
+ case 0xfef0: return((CHAR)0xf5 & 0xff);
+ case 0xfef2: return((CHAR)0xf6 & 0xff);
+ case 0xfed0: return((CHAR)0xf7 & 0xff);
+ case 0xfed5: return((CHAR)0xf8 & 0xff);
+ case 0xfef5: return((CHAR)0xf9 & 0xff);
+ case 0xfef6: return((CHAR)0xfa & 0xff);
+ case 0xfedd: return((CHAR)0xfb & 0xff);
+ case 0xfed9: return((CHAR)0xfc & 0xff);
+ case 0xfef1: return((CHAR)0xfd & 0xff);
+ case 0x25a0: return((CHAR)0xfe & 0xff);
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 866 */
+#ifdef CK_ANSIC
+tx_cp866(USHORT c)
+#else
+tx_cp866(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ case 0x00a4: return((CHAR)(253 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00b7: return((CHAR)(250 & 0xff));
+ case 0x0401: return((CHAR)(240 & 0xff));
+ case 0x0404: return((CHAR)(242 & 0xff));
+ case 0x0407: return((CHAR)(244 & 0xff));
+ case 0x040e: return((CHAR)(246 & 0xff));
+ case 0x0410: return((CHAR)(128 & 0xff));
+ case 0x0411: return((CHAR)(129 & 0xff));
+ case 0x0412: return((CHAR)(130 & 0xff));
+ case 0x0413: return((CHAR)(131 & 0xff));
+ case 0x0414: return((CHAR)(132 & 0xff));
+ case 0x0415: return((CHAR)(133 & 0xff));
+ case 0x0416: return((CHAR)(134 & 0xff));
+ case 0x0417: return((CHAR)(135 & 0xff));
+ case 0x0418: return((CHAR)(136 & 0xff));
+ case 0x0419: return((CHAR)(137 & 0xff));
+ case 0x041a: return((CHAR)(138 & 0xff));
+ case 0x041b: return((CHAR)(139 & 0xff));
+ case 0x041c: return((CHAR)(140 & 0xff));
+ case 0x041d: return((CHAR)(141 & 0xff));
+ case 0x041e: return((CHAR)(142 & 0xff));
+ case 0x041f: return((CHAR)(143 & 0xff));
+ case 0x0420: return((CHAR)(144 & 0xff));
+ case 0x0421: return((CHAR)(145 & 0xff));
+ case 0x0422: return((CHAR)(146 & 0xff));
+ case 0x0423: return((CHAR)(147 & 0xff));
+ case 0x0424: return((CHAR)(148 & 0xff));
+ case 0x0425: return((CHAR)(149 & 0xff));
+ case 0x0426: return((CHAR)(150 & 0xff));
+ case 0x0427: return((CHAR)(151 & 0xff));
+ case 0x0428: return((CHAR)(152 & 0xff));
+ case 0x0429: return((CHAR)(153 & 0xff));
+ case 0x042a: return((CHAR)(154 & 0xff));
+ case 0x042b: return((CHAR)(155 & 0xff));
+ case 0x042c: return((CHAR)(156 & 0xff));
+ case 0x042d: return((CHAR)(157 & 0xff));
+ case 0x042e: return((CHAR)(158 & 0xff));
+ case 0x042f: return((CHAR)(159 & 0xff));
+ case 0x0430: return((CHAR)(160 & 0xff));
+ case 0x0431: return((CHAR)(161 & 0xff));
+ case 0x0432: return((CHAR)(162 & 0xff));
+ case 0x0433: return((CHAR)(163 & 0xff));
+ case 0x0434: return((CHAR)(164 & 0xff));
+ case 0x0435: return((CHAR)(165 & 0xff));
+ case 0x0436: return((CHAR)(166 & 0xff));
+ case 0x0437: return((CHAR)(167 & 0xff));
+ case 0x0438: return((CHAR)(168 & 0xff));
+ case 0x0439: return((CHAR)(169 & 0xff));
+ case 0x043a: return((CHAR)(170 & 0xff));
+ case 0x043b: return((CHAR)(171 & 0xff));
+ case 0x043c: return((CHAR)(172 & 0xff));
+ case 0x043d: return((CHAR)(173 & 0xff));
+ case 0x043e: return((CHAR)(174 & 0xff));
+ case 0x043f: return((CHAR)(175 & 0xff));
+ case 0x0440: return((CHAR)(224 & 0xff));
+ case 0x0441: return((CHAR)(225 & 0xff));
+ case 0x0442: return((CHAR)(226 & 0xff));
+ case 0x0443: return((CHAR)(227 & 0xff));
+ case 0x0444: return((CHAR)(228 & 0xff));
+ case 0x0445: return((CHAR)(229 & 0xff));
+ case 0x0446: return((CHAR)(230 & 0xff));
+ case 0x0447: return((CHAR)(231 & 0xff));
+ case 0x0448: return((CHAR)(232 & 0xff));
+ case 0x0449: return((CHAR)(233 & 0xff));
+ case 0x044a: return((CHAR)(234 & 0xff));
+ case 0x044b: return((CHAR)(235 & 0xff));
+ case 0x044c: return((CHAR)(236 & 0xff));
+ case 0x044d: return((CHAR)(237 & 0xff));
+ case 0x044e: return((CHAR)(238 & 0xff));
+ case 0x044f: return((CHAR)(239 & 0xff));
+ case 0x0451: return((CHAR)(241 & 0xff));
+ case 0x0454: return((CHAR)(243 & 0xff));
+ case 0x0457: return((CHAR)(245 & 0xff));
+ case 0x045e: return((CHAR)(247 & 0xff));
+ case 0x2116: return((CHAR)(252 & 0xff));
+ case 0x2219: return((CHAR)(249 & 0xff));
+ case 0x221a: return((CHAR)(251 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2552: return((CHAR)(213 & 0xff));
+ case 0x2553: return((CHAR)(214 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2555: return((CHAR)(184 & 0xff));
+ case 0x2556: return((CHAR)(183 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x2558: return((CHAR)(212 & 0xff));
+ case 0x2559: return((CHAR)(211 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255b: return((CHAR)(190 & 0xff));
+ case 0x255c: return((CHAR)(189 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x255e: return((CHAR)(198 & 0xff));
+ case 0x255f: return((CHAR)(199 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2561: return((CHAR)(181 & 0xff));
+ case 0x2562: return((CHAR)(182 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2564: return((CHAR)(209 & 0xff));
+ case 0x2565: return((CHAR)(210 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2567: return((CHAR)(207 & 0xff));
+ case 0x2568: return((CHAR)(208 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256a: return((CHAR)(216 & 0xff));
+ case 0x256b: return((CHAR)(215 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x258c: return((CHAR)(221 & 0xff));
+ case 0x2590: return((CHAR)(222 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page 869 */
+#ifdef CK_ANSIC
+tx_cp869(USHORT c)
+#else
+tx_cp869(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x80) /* Has C1 graphics */
+ return((CHAR)(c & 0xff));
+ switch (c) {
+ case 0x00a0: return((CHAR)(255 & 0xff));
+ case 0x00a3: return((CHAR)(156 & 0xff));
+ case 0x00a6: return((CHAR)(138 & 0xff));
+ case 0x00a7: return((CHAR)(245 & 0xff));
+ case 0x00a8: return((CHAR)(249 & 0xff));
+ case 0x00a9: return((CHAR)(151 & 0xff));
+ case 0x00ab: return((CHAR)(174 & 0xff));
+ case 0x00ac: return((CHAR)(137 & 0xff));
+ case 0x00ad: return((CHAR)(240 & 0xff));
+ case 0x00b0: return((CHAR)(248 & 0xff));
+ case 0x00b1: return((CHAR)(241 & 0xff));
+ case 0x00b2: return((CHAR)(153 & 0xff));
+ case 0x00b3: return((CHAR)(154 & 0xff));
+ case 0x00b7: return((CHAR)(136 & 0xff));
+ case 0x00bb: return((CHAR)(175 & 0xff));
+ case 0x00bd: return((CHAR)(171 & 0xff));
+ case 0x0384: return((CHAR)(239 & 0xff));
+ case 0x0385: return((CHAR)(247 & 0xff));
+ case 0x0386: return((CHAR)(134 & 0xff));
+ case 0x0388: return((CHAR)(141 & 0xff));
+ case 0x0389: return((CHAR)(143 & 0xff));
+ case 0x038a: return((CHAR)(144 & 0xff));
+ case 0x038c: return((CHAR)(146 & 0xff));
+ case 0x038e: return((CHAR)(149 & 0xff));
+ case 0x038f: return((CHAR)(152 & 0xff));
+ case 0x0390: return((CHAR)(161 & 0xff));
+ case 0x0391: return((CHAR)(164 & 0xff));
+ case 0x0392: return((CHAR)(165 & 0xff));
+ case 0x0393: return((CHAR)(166 & 0xff));
+ case 0x0394: return((CHAR)(167 & 0xff));
+ case 0x0395: return((CHAR)(168 & 0xff));
+ case 0x0396: return((CHAR)(169 & 0xff));
+ case 0x0397: return((CHAR)(170 & 0xff));
+ case 0x0398: return((CHAR)(172 & 0xff));
+ case 0x0399: return((CHAR)(173 & 0xff));
+ case 0x039a: return((CHAR)(181 & 0xff));
+ case 0x039b: return((CHAR)(182 & 0xff));
+ case 0x039c: return((CHAR)(183 & 0xff));
+ case 0x039d: return((CHAR)(184 & 0xff));
+ case 0x039e: return((CHAR)(189 & 0xff));
+ case 0x039f: return((CHAR)(190 & 0xff));
+ case 0x03a0: return((CHAR)(198 & 0xff));
+ case 0x03a1: return((CHAR)(199 & 0xff));
+ case 0x03a3: return((CHAR)(207 & 0xff));
+ case 0x03a4: return((CHAR)(208 & 0xff));
+ case 0x03a5: return((CHAR)(209 & 0xff));
+ case 0x03a6: return((CHAR)(210 & 0xff));
+ case 0x03a7: return((CHAR)(211 & 0xff));
+ case 0x03a8: return((CHAR)(212 & 0xff));
+ case 0x03a9: return((CHAR)(213 & 0xff));
+ case 0x03aa: return((CHAR)(145 & 0xff));
+ case 0x03ab: return((CHAR)(150 & 0xff));
+ case 0x03ac: return((CHAR)(155 & 0xff));
+ case 0x03ad: return((CHAR)(157 & 0xff));
+ case 0x03ae: return((CHAR)(158 & 0xff));
+ case 0x03af: return((CHAR)(159 & 0xff));
+ case 0x03b0: return((CHAR)(252 & 0xff));
+ case 0x03b1: return((CHAR)(214 & 0xff));
+ case 0x03b2: return((CHAR)(215 & 0xff));
+ case 0x03b3: return((CHAR)(216 & 0xff));
+ case 0x03b4: return((CHAR)(221 & 0xff));
+ case 0x03b5: return((CHAR)(222 & 0xff));
+ case 0x03b6: return((CHAR)(224 & 0xff));
+ case 0x03b7: return((CHAR)(225 & 0xff));
+ case 0x03b8: return((CHAR)(226 & 0xff));
+ case 0x03b9: return((CHAR)(227 & 0xff));
+ case 0x03ba: return((CHAR)(228 & 0xff));
+ case 0x03bb: return((CHAR)(229 & 0xff));
+ case 0x03bc: return((CHAR)(230 & 0xff));
+ case 0x03bd: return((CHAR)(231 & 0xff));
+ case 0x03be: return((CHAR)(232 & 0xff));
+ case 0x03bf: return((CHAR)(233 & 0xff));
+ case 0x03c0: return((CHAR)(234 & 0xff));
+ case 0x03c1: return((CHAR)(235 & 0xff));
+ case 0x03c2: return((CHAR)(237 & 0xff));
+ case 0x03c3: return((CHAR)(236 & 0xff));
+ case 0x03c4: return((CHAR)(238 & 0xff));
+ case 0x03c5: return((CHAR)(242 & 0xff));
+ case 0x03c6: return((CHAR)(243 & 0xff));
+ case 0x03c7: return((CHAR)(244 & 0xff));
+ case 0x03c8: return((CHAR)(246 & 0xff));
+ case 0x03c9: return((CHAR)(250 & 0xff));
+ case 0x03ca: return((CHAR)(160 & 0xff));
+ case 0x03cb: return((CHAR)(251 & 0xff));
+ case 0x03cc: return((CHAR)(162 & 0xff));
+ case 0x03cd: return((CHAR)(163 & 0xff));
+ case 0x03ce: return((CHAR)(253 & 0xff));
+ case 0x2015: return((CHAR)(142 & 0xff));
+ case 0x2018: return((CHAR)(139 & 0xff));
+ case 0x2019: return((CHAR)(140 & 0xff));
+ case 0x2500: return((CHAR)(196 & 0xff));
+ case 0x2502: return((CHAR)(179 & 0xff));
+ case 0x250c: return((CHAR)(218 & 0xff));
+ case 0x2510: return((CHAR)(191 & 0xff));
+ case 0x2514: return((CHAR)(192 & 0xff));
+ case 0x2518: return((CHAR)(217 & 0xff));
+ case 0x251c: return((CHAR)(195 & 0xff));
+ case 0x2524: return((CHAR)(180 & 0xff));
+ case 0x252c: return((CHAR)(194 & 0xff));
+ case 0x2534: return((CHAR)(193 & 0xff));
+ case 0x253c: return((CHAR)(197 & 0xff));
+ case 0x2550: return((CHAR)(205 & 0xff));
+ case 0x2551: return((CHAR)(186 & 0xff));
+ case 0x2554: return((CHAR)(201 & 0xff));
+ case 0x2557: return((CHAR)(187 & 0xff));
+ case 0x255a: return((CHAR)(200 & 0xff));
+ case 0x255d: return((CHAR)(188 & 0xff));
+ case 0x2560: return((CHAR)(204 & 0xff));
+ case 0x2563: return((CHAR)(185 & 0xff));
+ case 0x2566: return((CHAR)(203 & 0xff));
+ case 0x2569: return((CHAR)(202 & 0xff));
+ case 0x256c: return((CHAR)(206 & 0xff));
+ case 0x2580: return((CHAR)(223 & 0xff));
+ case 0x2584: return((CHAR)(220 & 0xff));
+ case 0x2588: return((CHAR)(219 & 0xff));
+ case 0x2591: return((CHAR)(176 & 0xff));
+ case 0x2592: return((CHAR)(177 & 0xff));
+ case 0x2593: return((CHAR)(178 & 0xff));
+ case 0x25a0: return((CHAR)(254 & 0xff));
+ default: return(tx_cpsub(c)); /* For box characters etc */
+ }
+}
+
+int /* PC Code Page C0 graphics */
+#ifdef CK_ANSIC
+tx_smiley(USHORT c)
+#else
+tx_smiley(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c > 0x1f)
+ return(-1);
+ switch (c) {
+ case 0x00a0: return((CHAR)0 & 0x7f);
+ case 0x00a7: return((CHAR)21 & 0x7f);
+ case 0x00b6: return((CHAR)20 & 0x7f);
+ case 0x2022: return((CHAR)7 & 0x7f);
+ case 0x203c: return((CHAR)19 & 0x7f);
+ case 0x2190: return((CHAR)27 & 0x7f);
+ case 0x2191: return((CHAR)24 & 0x7f);
+ case 0x2192: return((CHAR)26 & 0x7f);
+ case 0x2193: return((CHAR)25 & 0x7f);
+ case 0x2194: return((CHAR)29 & 0x7f);
+ case 0x2195: return((CHAR)18 & 0x7f);
+ case 0x21a8: return((CHAR)23 & 0x7f);
+ case 0x2319: return((CHAR)28 & 0x7f);
+ case 0x25ac: return((CHAR)22 & 0x7f);
+ case 0x25b2: return((CHAR)30 & 0x7f);
+ case 0x25ba: return((CHAR)16 & 0x7f);
+ case 0x25bc: return((CHAR)31 & 0x7f);
+ case 0x25c4: return((CHAR)17 & 0x7f);
+ case 0x25d8: return((CHAR)8 & 0x7f);
+ case 0x25d9: return((CHAR)10 & 0x7f);
+ case 0x25ef: return((CHAR)9 & 0x7f);
+ case 0x263a: return((CHAR)1 & 0x7f);
+ case 0x263b: return((CHAR)2 & 0x7f);
+ case 0x263c: return((CHAR)15 & 0x7f);
+ case 0x2640: return((CHAR)12 & 0x7f);
+ case 0x2642: return((CHAR)11 & 0x7f);
+ case 0x2660: return((CHAR)6 & 0x7f);
+ case 0x2663: return((CHAR)5 & 0x7f);
+ case 0x2665: return((CHAR)3 & 0x7f);
+ case 0x2666: return((CHAR)4 & 0x7f);
+ case 0x266a: return((CHAR)13 & 0x7f);
+ case 0x266c: return((CHAR)14 & 0x7f);
+ default: return(-1);
+ }
+}
+
+USHORT /* Horizontal Scan Lines Unicode substitutions */
+#ifdef CK_ANSIC
+tx_hslsub(USHORT c)
+#else
+tx_hslsub(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c >= 0x23BA && c <= 0x23BD )
+ switch (c) {
+ case 0x23BA: return(0x2500); /* H line - Scan 1 */
+ case 0x23BB: return(0x2500); /* H line - Scan 3 */
+ case 0x23BC: return(0x2500); /* H line - Scan 7 */
+ case 0x23BD: return(0x2500); /* H line - Scan 9 */
+ }
+ return(c);
+}
+
+USHORT /* Kermit font 0xE??? Unicode substitutions */
+#ifdef CK_ANSIC
+tx_usub(USHORT c)
+#else
+tx_usub(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0xE000 || c > 0xEFFF)
+ return(c);
+ switch (c) {
+ case 0xE200: return(0x2524); /* Extensible Left Brace Middle */
+ case 0xE201: return(0x2570); /* Extensible Left Parenthesis bot */
+ case 0xE202: return(0x256d); /* Extensible left parenthesis top */
+ case 0xE203: return(0x2514); /* Extensible left SB bot */
+ case 0xE204: return(0x250c); /* Extensible left SB top */
+ case 0xE205: return(0x251c); /* Extensible right brace middle */
+ case 0xE206: return(0x256f); /* Extensible right parenthesis bot */
+ case 0xE207: return(0x256e); /* Extensible right parenthesis top */
+ case 0xE208: return(0x2518); /* Extensible right SB bot */
+ case 0xE209: return(0x2510); /* Extensible right SB top */
+ case 0xE20C: return(0x03a3); /* Summation symbol bot */
+ case 0xE20D: return(0x03a3); /* Summation symbol top */
+ case 0xE20E: return(0x2510); /* Right ceiling corner */
+ case 0xE20F: return(0x2518); /* Right floor corner */
+ case 0xE300: return(0x2502); /* V box line, extensible, left */
+ case 0xE309: return(0x2502); /* V box line, extensible, right */
+ case 0xE30A: return(0x258c); /* Diagonal fill, dark, UL */
+ case 0xE30B: return(0x2590); /* Diagonal fill, dark, UR */
+ case 0xE320: return(0x2583); /* Quadrant LL */
+ case 0xE321: return(0x2490); /* Quadrant LR */
+ case 0xE322: return(0x258c); /* Quadrant UL */
+ case 0xE323: return(0x2588); /* Quadrant UL and LL and LR */
+ case 0xE324: return(0x2588); /* Quadrant UL and LR */
+ case 0xE325: return(0x2588); /* Quadrant UL and LR */
+ case 0xE326: return(0x2588); /* Quadrant UL and UR and LL */
+ case 0xE327: return(0x2588); /* Quadrant UL and UR and LR */
+ case 0xE328: return(0x2590); /* Quadrant UR */
+ case 0xE329: return(0x2588); /* Quadrant UR and LL and LR */
+ case 0xE400: return(0x221a); /* Radical symbol, small */
+ case 0xE401: return(0x00bf); /* Reverse question mark */
+ default: return((unsigned)0xfffd);
+ }
+}
+
+int /* Unicode to CP437 substitutions */
+#ifdef CK_ANSIC
+tx_cpsub(USHORT c)
+#else
+tx_cpsub(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ int x;
+ if (c < 0x0080) /* ASCII */
+ return((CHAR)(c & 0xff));
+
+ if (c >= 0x0080 && c <= 0x0100) {
+ switch (c) { /* Latin-1 */
+ case 0x00A2: return(0x9b); /* Cent sign */
+ case 0x00A3: return(156); /* Pound sign */
+ case 0x00AC: return(170); /* Not symbol */
+ case 0x00B0: return(248); /* Degree symbol */
+ case 0x00B1: return(241); /* Plus or minus symbol */
+ case 0x00B2: return(253); /* Superscript 2 */
+ case 0x00B3: return(51); /* Superscript 3 */
+ case 0x00B6: return(14); /* Pilcrow symbol */
+ case 0x00B7: return(250); /* Center dot, small */
+ case 0x00B9: return(49); /* Superscript 1 */
+ case 0x00D0: return(68); /* Eth -> D */
+ case 0x00D7: return(120); /* Multiplication symbol */
+ case 0x00DE: return(84); /* Thorn -> T */
+ case 0x00F0: return(100); /* eth -> eth */
+ case 0x00F7: return(246); /* Division symbol */
+ case 0x00FE: return(116); /* thorn -> t */
+ default: return(0x13);
+ }
+ } else if (c >= 0x0100 && c <= 0x02ff) { /* Latin-2 etc */
+ switch (c) {
+ case 0x0103: return(97); /* a breve */
+ case 0x0105: return(97); /* a ogonek */
+ case 0x0107: /* c acute */
+ case 0x010d: return(99); /* c caron */
+ case 0x010f: /* d caron */
+ case 0x0111: return(100); /* d with stroke */
+ case 0x0119: /* e ogonek */
+ case 0x011b: return(101); /* e caron */
+ case 0x011f: return(103); /* g breve */
+ case 0x0130: return(73); /* Capital I with Dot */
+ case 0x0131: return(105); /* Dotless i */
+ case 0x0132: return(89); /* IJ => Y */
+ case 0x0133: return(152); /* ij -> y diaeresis */
+ case 0x013a: /* l acute */
+ case 0x013e: /* l caron */
+ case 0x0142: return(108); /* l with stroke */
+ case 0x0144: /* n acute */
+ case 0x0148: return(110); /* n caron */
+ case 0x0151: return(111); /* o double acute */
+ case 0x0152: return(79); /* OE */
+ case 0x0153: return(111); /* oe */
+ case 0x0155: /* r acute */
+ case 0x0159: return(114); /* r caron */
+ case 0x015b: /* s acute */
+ case 0x015f: /* s ogonek */
+ case 0x0161: return(115); /* s caron */
+ case 0x0163: /* t ogonek */
+ case 0x0165: /* t caron */
+ case 0x0167: return(116); /* t with stroke */
+ case 0x016f: /* u ring */
+ case 0x0171: return(117); /* u double acute */
+ case 0x017a: /* z acute */
+ case 0x017c: /* z dot above */
+ case 0x017e: return(122); /* z caron */
+ case 0x0192: return(159); /* Function-of symbol, Script f */
+ case 0x01d0: return(105); /* i caron */
+ case 0x02c7: /* caron -> UNK */
+ case 0x02d8: return(0x13); /* breve -> UNK */
+ case 0x02dd: return(34); /* Double acute -> Doublequote */
+ default: return(0x13);
+ }
+ } else if (c >= 0x0300 && c <= 0x03ff) { /* Greek */
+ switch (c) {
+ case 0x0393: return(226); /* Uppercase Greek Gamma */
+ case 0x0398: return(233); /* Uppercase Greek Theta */
+ case 0x039B: return(235); /* Uppercase Greek Lambda */
+ case 0x03A0: return(227); /* Uppercase Greek Pi */
+ case 0x03A3: return(228); /* Uppercase Greek Sigma */
+ case 0x03A4: return(0xEA); /* Omega */
+ case 0x03A6: return(232); /* Uppercase Greek Phi */
+ case 0x03A9: return(234); /* Uppercase Greek Omega */
+ case 0x03B1: return(0xE0); /* alpha */
+ case 0x03B2: return(0xE1); /* beta */
+ case 0x03B3: return(226); /* Lowercase Greek gamma */
+ case 0x03B4: return(0xEB); /* delta */
+ case 0x03B5: return(238); /* Lowercase Greek epsilon */
+ case 0x03B7: return(238); /* Lowercase Greek eta */
+ case 0x03B8: return(233); /* Lowercase Greek theta */
+ case 0x03B9: return(105); /* Lowercase Greek iota */
+ case 0x03BA: return(107); /* Lowercase Greek kappa */
+ case 0x03BB: return(235); /* Lowercase Greek lambda */
+ case 0x03BC: return(230); /* Lowercase Greek mu */
+ case 0x03C0: return(227); /* Lowercase Greek pi */
+ case 0x03C3: return(229); /* Lowercase Greek sigma */
+ case 0x03C4: return(231); /* Lowercase Greek tau */
+ case 0x03C6: return(237); /* Lowercase Greek phi */
+ case 0x03C7: return(120); /* Lowercase Greek chi */
+ case 0x03C9: return(234); /* Lowercase Greek omega */
+ default: return(0x13);
+ }
+ } else if (c >= 0x2000 && c <= 0x20ff) { /* Sub+Superscripts & Currency */
+ switch (c) {
+ case 0x203C: return(0x13); /* !! */
+ case 0x2070: return(48); /* Superscript 0 */
+ case 0x2074: return(52); /* Superscript 4 */
+ case 0x2075: return(53); /* Superscript 5 */
+ case 0x2076: return(54); /* Superscript 6 */
+ case 0x2077: return(55); /* Superscript 7 */
+ case 0x2078: return(56); /* Superscript 8 */
+ case 0x2079: return(57); /* Superscript 9 */
+ case 0x207a: return(43); /* Superscript + */
+ case 0x207b: return(45); /* Superscript - */
+ case 0x207F: return(252); /* Superscript n */
+ case 0x2080: return(48); /* Subscript 0 */
+ case 0x2081: return(49); /* Subscript 1 */
+ case 0x2082: return(50); /* Subscript 2 */
+ case 0x2083: return(51); /* Subscript 3 */
+ case 0x2084: return(52); /* Subscript 4 */
+ case 0x2085: return(53); /* Subscript 5 */
+ case 0x2086: return(54); /* Subscript 6 */
+ case 0x2087: return(55); /* Subscript 7 */
+ case 0x2088: return(56); /* Subscript 8 */
+ case 0x2089: return(57); /* Subscript 9 */
+ case 0x208a: return(43); /* Subscript + */
+ case 0x208b: return(45); /* Subscript - */
+ case 0x20a7: return(0x93); /* Peseta */
+ default:
+ x = tx_punc(c); /* Various spaces, dashes, etc */
+ return((x < 0) ? 0x13 : x);
+ }
+ } else if (c >= 0x2100 && c <= 0x21ff) { /* Arrows */
+ switch (c) {
+ case 0x2190: return(27); /* Arrow, left-pointing */
+ case 0x2191: return(24); /* Arrow, up-pointing */
+ case 0x2192: return(26); /* Arrow, right-pointing */
+ case 0x2193: return(25); /* Arrow, down-pointing */
+ case 0x2194: return(0x1d); /* Arrow, left-right */
+ case 0x2195: return(0x12); /* Arrow, up-down */
+ case 0x219F: return(0x18); /* Arrow, up, doublehead */
+ case 0x21A1: return(0x19); /* Arrow, down, doublehead */
+ case 0x21A8: return(0x17); /* Arrow, up-down with base */
+ case 0x21D2: return(26); /* Implies symbol */
+ case 0x21D4: return(29); /* If and only if symbol */
+ case 0x21E4: return(0x1B); /* Arrow, left, to bar */
+ case 0x21E5: return(0x1A); /* Arrow, right, to bar */
+ case 0x21E8: return(0x10); /* Outline white right arrow */
+ case 0x21E9: return(0x0f); /* Outline white down arrow */
+ default: return(0x13);
+ }
+ } else if (c >= 0x2200 && c <= 0x22ff) { /* Math */
+ switch (c) {
+ case 0x2202: return(235); /* Partial differential symbol */
+ case 0x2207: return(31); /* Nabla, Laplace operator */
+ case 0x2208: return(0x33); /* (because of QNX misunderstanding) */
+ case 0x221A: return(251); /* Radical symbol */
+ case 0x221D: return(236); /* Proportional-to */
+ case 0x221E: return(236); /* Infinity symbol */
+ case 0x2227: return(30); /* Logical AND */
+ case 0x2228: return(31); /* Logical OR */
+ case 0x2229: return(239); /* Intersection symbol */
+ case 0x222A: return(85); /* Union symbol */
+ case 0x222B: return(244); /* Integral symbol */
+ case 0x2234: return(254); /* Therefore symbol */
+ case 0x223C: return(126); /* Centered tilde operator */
+ case 0x2243: return(247); /* Asymptotically equals */
+ case 0x2248: return(247); /* Almost equal to symbol */
+ case 0x2260: return(88); /* Not equal symbol */
+ case 0x2261: return(240); /* Identity symbol */
+ case 0x2264: return(243); /* Less than or equal symbol */
+ case 0x2265: return(242); /* Greater than or equal symbol */
+ case 0x2282: return(40); /* Subset symbol */
+ case 0x2283: return(41); /* Superset symbol */
+ case 0x22A6: return(0xC3); /* Assertion symbol */
+ default: return(0x13);
+ }
+ } else if (c >= 0x23BA && c <= 0x23BD ) {
+ switch (c) {
+ case 0x23BA: return(0x2500); /* H line - Scan 1 */
+ case 0x23BB: return(0x2500); /* H line - Scan 3 */
+ case 0x23BC: return(0x2500); /* H line - Scan 7 */
+ case 0x23BD: return(0x2500); /* H line - Scan 9 */
+ }
+ } else if (c >= 0x2300 && c <= 0x24ff) { /* Tech */
+ switch (c) {
+ case 0x2308: return(0xDA); /* Left ceiling */
+ case 0x2309: return(0xBF); /* Right ceiling */
+ case 0x230A: return(0xC0); /* Left floor */
+ case 0x230B: return(0xD9); /* Right floor */
+ case 0x2319: return(0x1C); /* Turned Not sign */
+ case 0x2320: return(244); /* Integral symbol top */
+ case 0x2321: return(245); /* Integral symbol bot */
+ case 0x2329: return(60); /* BRA, large left angle bracket */
+ case 0x232A: return(62); /* KET, large right angle bracket */
+ case 0x2409: return(26); /* "HT" becomes right arrow */
+ case 0x240A: return(25); /* "LF" becomes down arrow */
+ case 0x240B: return(23); /* "VT" becomes up-down arrow */
+ case 0x240C: return(24); /* "FF" becomes up arrow */
+ case 0x240D: return(27); /* "CR" becomes left arrow */
+ case 0x2424: return(31); /* "NL" becomes down triangle */
+ default: return(0x13);
+ }
+ } else if (c >= 0x2500 && c <= 0x2552) { /* Box drawing */
+ switch (c) {
+ case 0x2500: return(196); /* Center box bar horizontal */
+ case 0x2501: return(0xCD); /* Bold -> Double */
+ case 0x2502: return(179); /* Center box bar vertical */
+ case 0x2503: return(0xBA); /* Bold */
+ case 0x2504: return(45); /* Dashed line */
+ case 0x2506: return(124); /* Broken vertical bar */
+ case 0x250C: return(218); /* UL box corner */
+ case 0x250F: return(0xC9); /* Bold */
+ case 0x2510: return(191); /* UR Box Corner */
+ case 0x2513: return(0xBB); /* Bold */
+ case 0x2514: return(192); /* LL box corner */
+ case 0x2517: return(0xC8); /* Bold */
+ case 0x2518: return(217); /* LR box corner */
+ case 0x251B: return(0xBC); /* Bold */
+ case 0x251C: return(195); /* Left middle box side */
+ case 0x2520: return(0xC3);
+ case 0x2523: return(0xCC); /* Bold */
+ case 0x2524: return(180); /* Right middle box side */
+ case 0x2528: return(180);
+ case 0x252B: return(0xB9); /* Bold */
+ case 0x252C: return(194); /* Middle box top */
+ case 0x252F: return(194);
+ case 0x2533: return(0xCB); /* Bold */
+ case 0x2534: return(193); /* Middle box bot */
+ case 0x2537: return(193);
+ case 0x253B: return(0xCA); /* Bold */
+ case 0x253C: return(197); /* Box intersection */
+ case 0x253F: return(197);
+ case 0x2542: return(197);
+ case 0x2547: return(197);
+ case 0x2548: return(197);
+ case 0x2549: return(197);
+ case 0x254A: return(197);
+ case 0x254B: return(0xCE); /* Bold */
+ case 0x2550: return(205); /* Center box bar horizontal double */
+ case 0x2551: return(186); /* Center box bar vertical double */
+ case 0x2552: return(213); /* UL box corner single to double */
+ default: return(0x13);
+ }
+ } else if (c >= 0x2553 && c <= 0x2579) { /* More box drawing */
+ switch (c) {
+ case 0x2553: return(214); /* UL box corner double to single */
+ case 0x2554: return(201); /* UL box corner double */
+ case 0x2555: return(184); /* UR box corner double to single */
+ case 0x2556: return(183); /* UR box corner single to double */
+ case 0x2557: return(187); /* UR box corner double */
+ case 0x2558: return(212); /* LL box corner single to double */
+ case 0x2559: return(211); /* LL box corner double to single */
+ case 0x255A: return(200); /* LL box corner double */
+ case 0x255B: return(190); /* LR box corner double to single */
+ case 0x255C: return(189); /* LR box corner single to double */
+ case 0x255D: return(188); /* LR box corner double */
+ case 0x255E: return(198); /* Left mid box side single to doubl */
+ case 0x255F: return(199); /* Left mid box side double to singl */
+ case 0x2560: return(204); /* Left middle box side double */
+ case 0x2561: return(181); /* Right box side double to single */
+ case 0x2562: return(182); /* Right box side single to double */
+ case 0x2563: return(185); /* Right middle box side double */
+ case 0x2564: return(209); /* Middle box top double to single */
+ case 0x2565: return(210); /* Middle box top single to double */
+ case 0x2566: return(203); /* Middle box top double */
+ case 0x2567: return(207); /* Middle box bot single to double */
+ case 0x2568: return(208); /* Middle box bot double to single */
+ case 0x2569: return(202); /* Middle box bot double */
+ case 0x256A: return(216); /* Box intersection double to single */
+ case 0x256B: return(215); /* Box intersection single to double */
+ case 0x256C: return(206); /* Box intersection double */
+ case 0x256D: return(218); /* UL arc */
+ case 0x256E: return(191); /* UR arc */
+ case 0x256F: return(217); /* LR arc */
+ case 0x2570: return(192); /* LL arc */
+ case 0x2571: return(179); /* Diagonal line LL to UR */
+ case 0x2572: return(196); /* Diagonal line UL to LR */
+ case 0x2573: return(88); /* Diagonal lines crossed */
+ case 0x2575: return(0xb3); /* High vertical line */
+ case 0x2576: return(45); /* Short horizontal line */
+ case 0x2577: return(0xb3); /* Low vertical line */
+ case 0x2579: return(0xb3); /* High vertical line bold */
+ default: return(0x13);
+ }
+ } else if (c >= 0x257a && c <= 0x25ff) { /* Still more box drawing */
+ switch (c) {
+ case 0x257b: return(0xb3); /* Low vertical line bold */
+ case 0x2580: return(223); /* Quadrant UL and UR (top half) */
+ case 0x2581: return(0xc4); /* Scan line 9 */
+ case 0x2582: return(0xDC); /* Black blob lower half */
+ case 0x2584: return(220); /* Quadrant LL and LR (lower half) */
+ case 0x2588: return(219); /* Fill character dark */
+ case 0x258C: return(221); /* Quadrant UL and LL (left half) */
+ case 0x258E: return(0xDD);
+ case 0x2590: return(222); /* Quadrant UR and LR (right half) */
+ case 0x2591: return(176); /* Fill character light */
+ case 0x2592: return(177); /* Fill character medium */
+ case 0x2593: return(178); /* Fill character heavy */
+ case 0x2594: return(0xc4); /* Scan line 1 */
+ case 0x25A0: return(254); /* Solid square, center */
+ case 0x25A6: return(177); /* Blotch */
+ case 0x25AC: /* Black rectangle */
+ case 0x25AF: return(0x16); /* White rectangle */
+ case 0x25B2: /* Triangle, up-pointing */
+ case 0x25B4: return(0x1e); /* Triangle, up-pointing */
+ case 0x25B6: /* Triangle, right-pointing, dark */
+ case 0x25B7: /* Triangle, right-pointing, light */
+ case 0x25B9: /* Triangle, right-pointing, light */
+ case 0x25BA: return(0x10); /* Triangle, right-pointing, narrow */
+ case 0x25BC: /* Triangle, down-pointing */
+ case 0x25BE: return(0x1f); /* Triangle, down-pointing */
+ case 0x25C0: /* Triangle, left-pointing, dark */
+ case 0x25C1: /* Triangle, left-pointing, dark */
+ case 0x25C4: return(0x11); /* Triangle, left-pointing, narrow */
+ case 0x25C6: return(4); /* Diamond, center, solid */
+ case 0x25CB: return(0x09); /* Circle */
+ case 0x25CF: return(249); /* Center dot, large */
+ case 0x25d8: return(0x08); /* Inverse bullet */
+ case 0x25d9: return(0x0a); /* Inverse white circle */
+ case 0x25E2: return(0xD9); /* Lower right triangle */
+ case 0x25E3: return(0xC0); /* Lower left triangle */
+ case 0x25E4: return(0xDA); /* Upper left triangle */
+ case 0x25E5: return(0xBf); /* Upper right triangle */
+ default: return(0x13);
+ }
+ } else if (c >= 0x2600) { /* All the rest */
+ switch (c) {
+ case 0x263a: return(0x01); /* Smiley */
+ case 0x263b: return(0x02); /* Inverse Smiley */
+ case 0x263c: return(0x0f); /* White Sun with Rays */
+ case 0x2640: return(0x0c); /* Male sign */
+ case 0x2642: return(0x0b); /* Female sign */
+ case 0x2660: return(0x06); /* Spade */
+ case 0x2663: return(0x05); /* Club */
+ case 0x2665: return(0x03); /* Heart */
+ case 0x2666: return(0x04); /* Diamond, center, solid */
+ case 0x266a: return(0x0d); /* Quarter note */
+ case 0x266b: /* Beamed quarter notes */
+ case 0x266c: return(0x0e); /* Beamed 8th notes */
+ case 0x279e: return(0x1a); /* Bold right arrow */
+ case 0x27a1: return(0x1a); /* Heavy black right arrow. */
+ case 0xE200: return(180); /* Extensible left brace middle */
+ case 0xE201: return(192); /* Extensible Left parenthesis bot */
+ case 0xE202: return(218); /* Extensible left parenthesis top */
+ case 0xE203: return(192); /* Extensible left SB bot */
+ case 0xE204: return(218); /* Extensible left SB top */
+ case 0xE205: return(195); /* Extensible right brace middle */
+ case 0xE206: return(217); /* Extensible right parenthesis bot */
+ case 0xE207: return(191); /* Extensible right parenthesis top */
+ case 0xE208: return(217); /* Extensible right SB bot */
+ case 0xE209: return(191); /* Extensible right SB top */
+ case 0xE20C: return(228); /* Summation symbol bot */
+ case 0xE20D: return(228); /* Summation symbol top */
+ case 0xE20E: return(191); /* Right ceiling corner */
+ case 0xE20F: return(217); /* Right floor corner */
+ case 0xE300: return(179); /* V box line, extensible, left */
+ case 0xE309: return(179); /* V box line, extensible, right */
+ case 0xE30A: return(221); /* Diagonal fill, dark, UL */
+ case 0xE30B: return(222); /* Diagonal fill, dark, UR */
+ case 0xE320: return(221); /* Quadrant LL */
+ case 0xE321: return(222); /* Quadrant LR */
+ case 0xE322: return(221); /* Quadrant UL */
+ case 0xE323: return(219); /* Quadrant UL and LL and LR */
+ case 0xE324: return(219); /* Quadrant UL and LR */
+ case 0xE325: return(219); /* Quadrant UL and LR */
+ case 0xE326: return(219); /* Quadrant UL and UR and LL */
+ case 0xE327: return(219); /* Quadrant UL and UR and LR */
+ case 0xE328: return(222); /* Quadrant UR */
+ case 0xE329: return(219); /* Quadrant UR and LL and LR */
+ case 0xE400: return(251); /* Radical symbol, small */
+ case 0xE401: return(168); /* Reverse question mark */
+ case 0xFFFD: return(0x13); /* !! for unknown */
+ default: return(0x13);
+ }
+ }
+ return(0x13);
+}
+
+#ifdef OS2
+/*
+ Lucida Console is a Unicode font, but it is very sparsely populated.
+ Since it is the only monospace Unicode font most people have, we have
+ to make reasonable substitutions or else 3/4 of the glyphs will show
+ up as blobs on the screen.
+*/
+USHORT /* Unicode to Lucida Console */
+#ifdef CK_ANSIC
+tx_lucidasub(USHORT c)
+#else
+tx_lucidasub(c) USHORT c;
+#endif /* CK_ANSIC */
+{
+ if (c < 0x0180) /* Latin-1 and Extended A */
+ return(c);
+
+/* For efficiency we try to arrange the sections by frequency of use. */
+ if (c >= 0x23BA && c <= 0x23BD) {
+ switch(c) {
+ case 0x23BA: /* H line - Scan 1 */
+ case 0x23BB: /* H line - Scan 3 */
+ case 0x23BC: /* H line - Scan 7 */
+ case 0x23BD: /* H line - Scan 9 */
+ return(0x2500);
+ }
+ }
+ if (c >= 0x2500 && c <= 0x257f) { /* Box drawing */
+ if (c >= 0x2550 && c <= 0x256c)
+ return(c);
+ switch (c) {
+ /* Themselves */
+ case 0x2500:
+ case 0x2502:
+ case 0x250c:
+ case 0x2510:
+ case 0x2514:
+ case 0x2518:
+ case 0x251c:
+ case 0x2524:
+ case 0x252c:
+ case 0x2534:
+ case 0x253c:
+ return(c);
+ /* Horizontal lines */
+ case 0x2501: /* Bold */
+ return(0x2550); /* Use double */
+ case 0x2504:
+ case 0x2505:
+ case 0x2508:
+ case 0x2509:
+ case 0x254c:
+ case 0x254d:
+ case 0x257c:
+ case 0x257e:
+ return(0x2500);
+ /* Vertical lines */
+ case 0x2503: /* Bold */
+ return(0x2551); /* Use double */
+ case 0x2506:
+ case 0x2507:
+ case 0x250a:
+ case 0x250b: /* Other */
+ case 0x254e:
+ case 0x254f:
+ case 0x257d:
+ case 0x257f:
+ case 0x2575:
+ case 0x2577:
+ case 0x2579:
+ case 0x257b:
+ return(0x2502);
+ /* Upper left box corner */
+ case 0x250f: /* Bold */
+ return(0x2554); /* Use double */
+ case 0x250d: case 0x250e: /* Other */
+ return(0x250c);
+ /* Upper right box corner */
+ case 0x2513: /* Bold */
+ return(0x2557);
+ case 0x2511:
+ case 0x2512: /* Other */
+ return(0x2510);
+ /* Lower left box corner */
+ case 0x2517: /* Bold */
+ return(0x255a);
+ case 0x2515:
+ case 0x2516: /* Other */
+ return(0x2514);
+ /* Lower right box corner */
+ case 0x251b: /* Bold */
+ return(0x255d);
+ case 0x2519:
+ case 0x251a: /* Other */
+ return(0x2518);
+ /* Vertical and right */
+ case 0x2523: /* Bold */
+ return(0x2560);
+ case 0x251d:
+ case 0x251e:
+ case 0x251f:
+ case 0x2520:
+ case 0x2521:
+ case 0x2522:
+ return(0x251c);
+ /* Vertical and left */
+ case 0x252b: /* Bold */
+ return(0x2563);
+ case 0x2525:
+ case 0x2526:
+ case 0x2527:
+ case 0x2528:
+ case 0x2529:
+ case 0x252a:
+ return(0x2524);
+ /* Horizontal and down */
+ case 0x2533: /* Bold */
+ return(0x2566);
+ case 0x252d:
+ case 0x252e:
+ case 0x252f:
+ case 0x2530:
+ case 0x2531:
+ case 0x2532:
+ return(0x252c);
+ /* Horizontal and up */
+ case 0x253b: /* Bold */
+ return(0x2569);
+ case 0x2535: case 0x2536: case 0x2537:
+ case 0x2538: case 0x2539: case 0x253a:
+ return(0x2534);
+ /* Horizontal and Vertical */
+ case 0x254b: /* Bold */
+ return(0x256c);
+ case 0x253d: case 0x253e: case 0x253f:
+ case 0x2540: case 0x2541: case 0x2542: case 0x2543:
+ case 0x2544: case 0x2545: case 0x2546: case 0x2547:
+ case 0x2548: case 0x2549: case 0x254a:
+ return(0x253c);
+ /* Curved corners */
+ case 0x256d: /* UL */
+ return(0x250c);
+ case 0x256e: /* UR */
+ return(0x2510);
+ case 0x256f: /* LL */
+ return(0x2518);
+ case 0x2570: /* LR */
+ return(0x2514);
+ case 0x2571: /* Diagonal */
+ return(0x002f);
+ case 0x2572: /* Other diagonal */
+ return(0x005c);
+ case 0x2573: /* Diagonal cross */
+ return(0x00d7);
+ /* Partial horizontal lines */
+ case 0x2574: case 0x2576: case 0x2578: case 0x257a:
+ return(0x002d);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x2190 && c <= 0x21ff) { /* Arrows */
+ if (c >= 0x2190 && c <= 0x2195 || c == 0x21a8)
+ return(c);
+ switch (c) {
+ /* Left-arrow forms */
+ case 0x219e: case 0x21a2: case 0x21a4: case 0x21a9:
+ case 0x21bc: case 0x21d0: case 0x21da: case 0x21dc:
+ case 0x21e0: case 0x21e4: case 0x21e6: case 0x21c7:
+ return(0x2190);
+ /* Right-arrow forms */
+ case 0x21a0: case 0x21a3: case 0x21a6: case 0x21aa:
+ case 0x21c0: case 0x21c1: case 0x21c9: case 0x21d2:
+ case 0x21db: case 0x21dd: case 0x21e2: case 0x21e5:
+ case 0x21e8:
+ return(0x2192);
+ /* Up-arrow forms */
+ case 0x219f: case 0x21a5: case 0x21be: case 0x21bf:
+ case 0x21c8: case 0x21d1: case 0x21de: case 0x21e1:
+ case 0x21e7: case 0x21ea:
+ return(0x2191);
+ /* Down-arrow forms */
+ case 0x21a1: case 0x21a7: case 0x21af: case 0x21c2:
+ case 0x21ce: case 0x21ca: case 0x21d3: case 0x21df:
+ case 0x21e3: case 0x21e9:
+ return(0x2193);
+ /* Up-down-arrow forms */
+ case 0x21c5: case 0x21d5:
+ return(0x2195);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x2580 && c <= 0x259f) { /* Block elements */
+ switch (c) {
+ case 0x2580: case 0x2584: case 0x2588: case 0x258c:
+ case 0x2590: case 0x2591: case 0x2592: case 0x2593:
+ return(c);
+ case 0x2581: case 0x2582: case 0x2583:
+ case 0x2585: case 0x2586: case 0x2587:
+ return(0x2584);
+ case 0x2589: case 0x258a: case 0x258b:
+ case 0x258d: case 0x258e: case 0x258f:
+ return(0x258c);
+ case 0x2595:
+ return(0x2502);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x2200 && c <= 0x22ff) { /* Mathematical operators */
+ switch (c) {
+ case 0x2202: case 0x2206: case 0x220f: case 0x2211: case 0x2212:
+ case 0x2219: case 0x2220: case 0x221e: case 0x221f: case 0x2229:
+ case 0x222b: case 0x2248: case 0x2260: case 0x2261: case 0x2264:
+ case 0x2265:
+ return(c);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x2300 && c <= 0x237f) { /* Miscellaneous Technical */
+ if (c == 0x2302 || c == 0x2310 || c == 0x2320 || c == 0x2321)
+ return(c);
+ switch (c) {
+ case 0x2329: /* BRA */
+ return(0x003c);
+ case 0x232a: /* KET */
+ return(0x003e);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x25a0 && c <= 0x25ff) { /* Geometric shapes */
+ switch (c) {
+ /* Themselves */
+ case 0x25a0: case 0x25ac: case 0x25b2: case 0x25ba:
+ case 0x25bc: case 0x25c4: case 0x25ca: case 0x25cb:
+ case 0x25d8: case 0x25d9:
+ return(c);
+ /* Squares */
+ case 0x25a1: case 0x25a2: case 0x25a3: case 0x25a4:
+ case 0x25a5: case 0x25a6: case 0x25a7: case 0x25a8:
+ case 0x25a9: case 0x25aa: case 0x25ab:
+ case 0x25e7: case 0x25e8: case 0x25e9: case 0x25ea: case 0x25eb:
+ return(0x25a0);
+ case 0x25ad: case 0x25ae: case 0x25af: /* Rectangles */
+ case 0x25b0: case 0x25b1:
+ return(0x25ac);
+ case 0x25b3: case 0x25b4: case 0x25b5: /* Upright triangles */
+ case 0x25ec: case 0x25ed: case 0x25ee:
+ return(0x25b2);
+ case 0x25b6: case 0x25b7: case 0x25b8: case 0x25b9: case 0x25bb:
+ return(0x25ba); /* Right-pointing triangles */
+ case 0x25bd: case 0x25be: case 0x25bf: /* Down-pointing triangles */
+ return(0x25bc);
+ case 0x25c0: case 0x25c1: case 0x25c2: case 0x25c3: case 0x25c5:
+ return(0x25c4); /* Left-pointing triangles */
+ case 0x25c6: case 0x25c7: case 0x25c8: /* Diamonds */
+ return(0x2666);
+ /* Circles */
+ case 0x25c9: case 0x25cc: case 0x25cd: case 0x25ce: case 0x25cf:
+ case 0x25d0: case 0x25d1: case 0x25d2: case 0x25d3: case 0x25d4:
+ case 0x25d5: case 0x25e6: case 0x25ef:
+ return(0x25cb);
+ /* Curves and corner triangles */
+ case 0x25dc: case 0x25e4: /* UL */
+ return(0x250c);
+ case 0x25dd: case 0x25e5: /* UR */
+ return(0x2510);
+ case 0x25df: case 0x25e3: /* LL */
+ return(0x2514);
+ case 0x25de: case 0x25e2: /* LR */
+ return(0x2518);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x2600 && c <= 0x26ff) { /* Misc symbols */
+ switch (c) {
+ /* Themselves */
+ case 0x263a: case 0x263b: case 0x263c: case 0x2640:
+ case 0x2642: case 0x2660: case 0x2663: case 0x2665:
+ case 0x2666: case 0x266a: case 0x266b:
+ return(c);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x2794 && c <= 0x27be) /* Right-arrow Dingbats */
+ return(0x2192);
+ if (c >= 0x2070 && c <= 0x209f) { /* Super & subscripts */
+ if (c == 0x207f) /* n */
+ return(c);
+ else if (c == 0x2070) /* 0 */
+ return(0x0030);
+ else if (c >= 0x2074 && c <= 0x2079)
+ return(c - 0x2040);
+ else if (c >= 0x2080 && c <= 0x2089)
+ return(c - 0x2050);
+ switch (c) {
+ case 0x207a: case 0x208a:
+ return(0x002b);
+ case 0x207b: case 0x208b:
+ return(0x002d);
+ case 0x207c: case 0x208c:
+ return(0x003d);
+ case 0x207d: case 0x208d:
+ return(0x0028);
+ case 0x207e: case 0x208e:
+ return(0x0029);
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x0180 && c <= 0x024f) { /* Latin Extended B, Part I */
+ if (c == 0x0192 || c >= 0x01fa && c <= 0x01ff)
+ return(c); /* Latin Extended B */
+ switch (c) {
+ case 0x0180: case 0x0183: case 0x0184: case 0x0185:
+ return(0x0062); /* Lowercase b variants */
+ case 0x0181: case 0x0182:
+ return(0x0042); /* Uppercase B variants */
+ case 0x0186: case 0x0187:
+ return(0x0043); /* Uppercase C variants */
+ case 0x0189: /* D with stroke */
+ return(0x00D0); /* Looks just like Eth */
+ case 0x018a: /* D with hook */
+ return(0x0044);
+ case 0x018e: case 0x0190: /* E-like letters */
+ return(0x0045);
+ case 0x018f: /* e-like letters */
+ return(0x0065);
+ case 0x0191: /* F-like */
+ return(0x0046);
+ case 0x0193: /* G-like */
+ return(0x0047);
+ case 0x0194: /* Latin Capital Gamma */
+ return(0x0393); /* Use Greek */
+ case 0x0195: /* Gothic hv */
+ return(0x0068); /* Use h */
+ case 0x0196: /* Latin Capital Iota */
+ return(0x0399); /* Use Greek */
+ case 0x0197: /* I with bar */
+ return(0x0069);
+ case 0x0198: /* K with hook */
+ return(0x004B);
+ case 0x0199: /* k with hook */
+ return(0x006B);
+ case 0x019A: /* l with bar */
+ return(0x006C);
+ case 0x019B: /* lambda with bar */
+ return(0x03bb); /* Use Greek */
+ case 0x019C: /* Upside down m */
+ return(0x006d);
+ case 0x019D: /* N with left hook */
+ return(0x004e);
+ case 0x019E: /* n with long right leg */
+ return(0x006e);
+ case 0x019F: case 0x01a0: case 0x01a2: /* O-like letters */
+ return(0x004f);
+ case 0x01a1: case 0x01a3: /* o-like */
+ return(0x006f);
+ case 0x01A4: /* P with hook */
+ return(0x0050);
+ case 0x01A5: /* p with hook */
+ return(0x0070);
+ case 0x01A6: /* Old Norse YR */
+ return(0x0052);
+ case 0x01A7: /* Backwards S */
+ return(0x0053);
+ case 0x01A8: case 0x01AA: /* s-like letters */
+ return(0x0073);
+ case 0x01A9: /* Esh */
+ return(0x03a3); /* Looks just like Sigma */
+ case 0x01AB: case 0x01AD: /* t-like */
+ return(0x0074);
+ case 0x01AC: case 0x01AE: /* T-like */
+ return(0x0054);
+ case 0x01AF: case 0x01B1: /* U-like */
+ return(0x0055);
+ case 0x01B0: /* u-like */
+ return(0x0075);
+ case 0x01B2: /* V-like */
+ return(0x0056);
+ case 0x01B3: /* Y-like */
+ return(0x0059);
+ case 0x01B4: /* y-like */
+ return(0x0079);
+ case 0x01B5: /* Z-like */
+ return(0x005a);
+ case 0x01B6: /* z-like */
+ return(0x007a);
+ case 0x01B7: /* Yogh */
+ return(0x0033); /* Use "3" */
+ case 0x01BF: /* Wynn */
+ return(0x0077); /* Use "w" */
+ case 0x01CD: /* A caron */
+ return(0x0041);
+ case 0x01CE: /* a caron */
+ return(0x0061);
+ case 0x01CF: /* I caron */
+ return(0x0049);
+ case 0x01D0: /* i caron */
+ return(0x0069);
+ case 0x01D1: /* O caron */
+ return(0x004f);
+ case 0x01D2: /* o caron */
+ return(0x006f);
+ case 0x01D3: /* U caron */
+ return(0x0055);
+ case 0x01D4: /* u caron */
+ return(0x0075);
+ /* U diaeresis + other things */
+ case 0x01D5: case 0x01D7: case 0x01D9: case 0x01DB:
+ return(0x00dc);
+ /* u diaeresis + other things */
+ case 0x01D6: case 0x01Da: case 0x01Dc:
+ return(0x00fc);
+
+ /* Fill in more here if anybody asks */
+
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x1e00 && c <= 0x1eff) { /* Latin Extended Additional */
+ if (c >= 0x1e80 && c <= 0x1e85)
+ return(c);
+ else
+ return(0xfffd);
+ }
+ if (c >= 0x0400 && c <= 0x04ff) { /* Cyrillic */
+ if (c >= 0x0400 && c <= 0x045f || c == 0x0490 || c == 0x0491)
+ return(c);
+ else
+ return(0xfffd);
+ }
+ if (c >= 0x0370 && c <= 0x03ff) { /* Greek */
+ if (c == 0x037e || c >= 0x0384 && c <= 0x03ce)
+ return(c);
+ switch (c) {
+ case 0x0374: case 0x0375:
+ return(0x0027);
+ case 0x037a:
+ return(0x002c);
+ /* Fill in more here if needed */
+ default:
+ return(0xfffd);
+ }
+ }
+ if (c >= 0x1f00 && c <= 0x1fff) { /* Greek Extended */
+ /* Fill in if asked */
+ return(0xfffd);
+ }
+ if (c >= 0x20a0 && c <= 0x20cf) { /* Currency symbols */
+ if (c == 0x20a3 || c == 0x20a4 || c == 0x20a7 || c == 0x20ac)
+ return(c);
+ else
+ return(0xfffd);
+ }
+ if (c >= 0x2100 && c <= 0x214f) { /* Letterlike symbols */
+ if (c == 0x2116 || c == 0x2122 || c == 0x2126)
+ return(c);
+ else
+ return(0xfffd);
+ }
+ if (c >= 0x2150 && c <= 0x218f) { /* Number forms */
+ if (c >= 0x215b && c <= 0x215e) /* Roman numerals etc */
+ return(c);
+ else
+ return(0xfffd);
+ }
+ if (c >= 0x02b0 && c <= 0x02ff) { /* Spacing modifier letters */
+ if (c == 0x02c6 || c == 0x02c7 || c == 0x02c9 ||
+ c >= 0x02d8 && c <= 0x02dd)
+ return(c);
+ switch (c) {
+ case 0x02b0: case 0x02b1:
+ return(0x0068);
+ case 0x02b2:
+ return(0x006a);
+ case 0x02b3: case 0x02b4: case 0x02b5:
+ return(0x0072);
+ case 0x02b7:
+ return(0x0077);
+ case 0x02b8:
+ return(0x0079);
+ case 0x02b9:
+ return(0x00b4);
+ case 0x02ba:
+ return(0x0022);
+ case 0x02bb: case 0x02bc: case 0x02bd: case 0x02be: case 0x02bf:
+ return(0x0027);
+ case 0x02c2: return(0x003c);
+ case 0x02c3: return(0x003e);
+ case 0x02da: return(0x00b0);
+ case 0x02dc: return(0x007e);
+ default: return(0xfffd);
+ }
+ }
+ if (c >= 0x2000 && c <= 0x206f) { /* General Punctuation */
+ if (c >= 0x2013 && c <= 0x2015 ||
+ c >= 0x2017 && c <= 0x201a ||
+ c >= 0x201c && c <= 0x201e ||
+ c >= 0x2020 && c <= 0x2022 || c == 0x2026 || c == 0x2030 ||
+ c >= 0x2039 && c <= 0x203a || c == 0x203c || c == 0x203e ||
+ c == 0x2044)
+ return(c);
+ else if (c == 0x2016)
+ return(0x2551);
+ else if (c == 0x2017)
+ return(0x2550);
+ else if (c == 0x2044)
+ return(0x002f);
+ else
+ return(0xfffd);
+ }
+ if (c == 0xfb01 || c == 0xfb02) /* Alphabetic Presentation Forms */
+ return(c);
+ return(0xfffd); /* Catch-all */
+}
+#endif /* OS2 */
+
+
+/*
+ Table of Blah-to-Unicode information structures.
+ KEEP THIS IN SYNC WITH THE TX_blah DEFINITIONS in ckcuni.h.
+*/
+struct x_to_unicode *
+txrinfo[MAXTXSETS+1] = {
+ &u_ascii, /* 0 US ISO 646 (ASCII) */
+ &u_british, /* 1 UK ISO 646 */
+ &u_fr_canadian, /* 2 Canadian French NRC */
+ NULL, /* 3 Cuba */
+ NULL, /* 4 Czecho */
+ &u_danish, /* 5 Danish/Norwegian ISO 646 */
+ &u_dutch, /* 6 Dutch NRC */
+ &u_finnish, /* 7 Finnish NRC */
+ &u_french, /* 8 French ISO 646 */
+ &u_german, /* 9 German ISO 646 */
+ &u_hebrew7, /* 10 Hebrew-7 (DEC) */
+ &u_hungarian, /* 11 Hungarian ISO 646 */
+ &u_icelandic, /* 12 Icelandic NRC */
+ &u_italian, /* 13 Italian ISO 646 */
+ &u_jis0201r, /* 14 Japanese Roman ISO 646 */
+ &u_jis0201k, /* 15 Japanese Katakana */
+ &u_koi7, /* 16 Short KOI */
+ &u_danish, /* 17 Norwegian/Danish ISO 646 */
+ &u_portuguese, /* 18 Portuguese ISO 646 */
+ &u_spanish, /* 19 spanish ISO 646 */
+ &u_swedish, /* 20 Swedish ISO 646 */
+ NULL, /* 21 Swedish ISO 646 for names */
+ &u_swiss, /* 22 Swiss NRC */
+ &u_8859_1, /* 23 ISO 8859-1 */
+ &u_8859_2, /* 24 ISO 8859-2 */
+ &u_8859_3, /* 25 ISO 8859-3 */
+ &u_8859_4, /* 26 ISO 8859-4 */
+ &u_8859_5, /* 27 ISO 8859-5 */ /* Cyrillic */
+ &u_8859_6, /* 28 ISO 8859-6 */ /* Arabic */
+ &u_8859_7, /* 29 ISO 8859-7 */ /* Greek */
+ &u_8859_8, /* 30 ISO 8859-8 */ /* Hebrew */
+ &u_8859_9, /* 31 ISO 8859-9 */
+ &u_8859_10, /* 32 ISO 8859-10 */
+ &u_koi8, /* 33 KOI-8 */
+ NULL, /* 34 JIS-7 */
+ NULL, /* 35 Shift JIS */
+ NULL, /* 36 Japanese EUC (JAE) */
+ NULL, /* 37 Japanese DEC Kanji */
+ &u_decmcs, /* 38 DEC MCS */
+ &u_nextstep, /* 39 NeXT */
+ &u_dgi, /* 40 DGI */
+ &u_maclatin, /* 41 Macintosh Latin */
+ &u_hproman8, /* 42 HP Roman 8 */
+ &u_cp437, /* 43 CP437 - Original */
+ &u_cp850, /* 44 CP850 - W Europe */
+ &u_cp852, /* 45 CP852 - E Europe */
+ &u_cp857, /* 46 CP857 - Turkish */
+ &u_cp862, /* 47 CP862 - Hebrew */
+ &u_cp864, /* 48 CP864 - Arabic */
+ &u_cp866, /* 49 CP866 - Cyrillic */
+ &u_cp869, /* 50 CP869 - Greek */
+ &u_decspec, /* 51 DEC Special Graphics */
+ &u_dectech, /* 52 DEC Technical */
+ &u_c0pics, /* 53 C0 Pictures */
+ &u_c1pics, /* 54 C1 Pictures */
+ &u_smiley, /* 55 IBM C0 Graphics */
+ &u_heath19g, /* 56 Heath 19 Graphics */
+ &u_tvig, /* 57 TVI Graphics */
+ &u_wyse_gn, /* 58 Wyse 60 Graphics Normal */
+ &u_wyse_g1, /* 59 Wyse 60 Graphics 1 */
+ &u_wyse_g2, /* 60 Wyse 60 Graphics 2 */
+ &u_wyse_g3, /* 61 Wyse 60 Graphics 3 */
+ &u_elot927, /* 62 Greek ELOT 927 */
+ &u_dgspec, /* 63 DG Special graphics */
+ &u_dgline, /* 64 DG Line drawing */
+ &u_dgword, /* 65 DG Word processing */
+ &u_hpline, /* 66 HP Line drawing */
+ &u_hpmath, /* 67 HP Math/Technical */
+ &u_qnxgrph, /* 68 QNX Graphics */
+ &u_snibrack, /* 69 SNI Brackets */
+ &u_snieuro, /* 70 SNI Euro */
+ &u_snifacet, /* 71 SNI Facet */
+ &u_sniibm, /* 72 SNI IBM */
+ &u_sniblanks, /* 73 SNI Blanks */
+ &u_cp1252, /* 74 Windows Latin-1 */
+ &u_cp1250, /* 75 Windows Latin-2 */
+ &u_cp1251, /* 76 Windows Cyrillic */
+ &u_cp1253, /* 77 Windows Greek */
+ &u_cp1254, /* 78 Windows Turkish */
+ &u_cp1257, /* 79 Windows Latin-4 */
+ &u_cp856, /* 80 Cyrillic PC Code Page 856 */
+ &u_cp855, /* 81 Cyrillic PC Code Page 855 */
+ &u_8859_1, /* 82 CP819 - Same as 8859-1 */
+ &u_8859_2, /* 83 CP912 - Same as 8859-2 */
+ &u_8859_3, /* 84 CP913 - Same as 8859-3 */
+ &u_8859_4, /* 85 CP914 - Same as 8859-4 */
+ &u_8859_5, /* 86 CP915 - Same as 8859-5 */
+ &u_8859_6, /* 87 CP1089 - Same as 8859-6 */
+ &u_8859_7, /* 88 CP813 - Same as 8859-7 */
+ &u_8859_8, /* 89 CP916 - Same as 8859-8 */
+ &u_8859_9, /* 90 CP920 - Same as 8859-9 */
+ &u_hproman8, /* 91 CP1051 - Same as HP Roman 8 */
+ &u_cp858, /* 92 CP858 - W Europe w/Euro */
+ &u_8859_15, /* 93 ISO 8859-15 Latin-15 */
+ &u_8859_15, /* 94 CP923 - Same as 8859-15 */
+ &u_8859_7, /* 95 ELOT928 - Same as 8859-7 */
+ &u_quickdraw, /* 96 CP10000 - Apple Quickdraw */
+ &u_cp37, /* 97 CP37 - U.S. EBCDIC */
+ &u_cp1255, /* 98 CP1255 - Windows Hebrew */
+ &u_cp1256, /* 99 CP1256 - Windows Arabic */
+ &u_cp1258, /* 100 CP1258 - Windows Viet Nam */
+ &u_mazovia, /* 101 Mazovia Polish code page */
+ &u_transparent, /* 102 Transparent */
+ &u_hz1500, /* 103 Hazeltine 1500/1520 graphics */
+ &u_koi8r, /* 104 KOI8-R */
+ &u_koi8u, /* 105 KOI8-U */
+ &u_apl1, /* 106 APL 1 (ISO) */
+ &u_apl2, /* 107 APL 2 (Dyadic) */
+ &u_apl3, /* 108 APL 3 (Plus) */
+ &u_apl4, /* 108 APL 4 (IBM) */
+ &u_apl5 /* 110 APL 5 (2741) */
+};
+
+/*
+ Table of Blah-to-Unicode translation functions.
+ KEEP THIS IN SYNC WITH THE TX_blah DEFINITITIONS in ckcuni.h.
+*/
+USHORT
+#ifdef CK_ANSIC
+(*xl_u[MAXTXSETS+1])(CHAR)
+#else
+(*xl_u[MAXTXSETS+1])()
+#endif /* CK_ANSIC */
+= {
+ ascii_u, /* 0 US ISO 646 (ASCII) */
+ british_u, /* 1 UK ISO 646 */
+ fr_canadian_u, /* 2 Canadian French NRC */
+ NULL, /* 3 Cuba */
+ NULL, /* 4 Czecho */
+ danish_u, /* 5 Danish/Norwegian ISO 646 */
+ dutch_u, /* 6 Dutch NRC */
+ finnish_u, /* 7 Finnish NRC */
+ french_u, /* 8 French ISO 646 */
+ german_u, /* 9 German ISO 646 */
+ hebrew7_u, /* 10 Hebrew-7 (DEC) */
+ hungarian_u, /* 11 Hungarian ISO 646 */
+ icelandic_u, /* 12 Icelandic */
+ italian_u, /* 13 Italian ISO 646 */
+ jis0201r_u, /* 14 Japanese Roman ISO 646 */
+ jis0201k_u, /* 15 Japanese Katakana */
+ koi7_u, /* 16 Short KOI */
+ danish_u, /* 17 Norwegian/Danish ISO 646 */
+ portuguese_u, /* 18 Portuguese ISO 646 */
+ spanish_u, /* 19 spanish ISO 646 */
+ swedish_u, /* 20 Swedish ISO 646 */
+ NULL, /* 21 Swedish ISO 646 for names */
+ swiss_u, /* 22 Swiss NRC */
+ iso_8859_1_u, /* 23 ISO 8859-1 */
+ iso_8859_2_u, /* 24 ISO 8859-2 */
+ iso_8859_3_u, /* 25 ISO 8859-3 */
+ iso_8859_4_u, /* 26 ISO 8859-4 */
+ iso_8859_5_u, /* 27 ISO 8859-5 */ /* Cyrillic */
+ iso_8859_6_u, /* 28 ISO 8859-6 */ /* Arabic */
+ iso_8859_7_u, /* 29 ISO 8859-7 */ /* Greek */
+ iso_8859_8_u, /* 30 ISO 8859-8 */ /* Hebrew */
+ iso_8859_9_u, /* 31 ISO 8859-9 */ /* Latin-5 */
+ iso_8859_10_u, /* 32 ISO 8859-10 */
+ koi8_u, /* 33 KOI-8 */
+ NULL, /* 34 JIS-7 */
+ NULL, /* 35 Shift JIS */
+ NULL, /* 36 Japanese EUC (JAE) */
+ NULL, /* 37 Japanese DEC Kanji */
+ decmcs_u, /* 38 DEC MCS */
+ nextstep_u, /* 39 NeXT */
+ dgi_u, /* 40 DGI */
+ maclatin_u, /* 41 Macintosh Latin */
+ hproman8_u, /* 42 HP Roman 8 */
+ cp437_u, /* 43 CP437 - Original */
+ cp850_u, /* 44 CP850 - W Europe */
+ cp852_u, /* 45 CP852 - E Europe */
+ cp857_u, /* 46 CP857 - Turkish */
+ cp862_u, /* 47 CP862 - Hebrew */
+ cp864_u, /* 48 CP864 - Arabic */
+ cp866_u, /* 49 CP866 - Cyrillic */
+ cp869_u, /* 50 CP869 - Greek */
+ decspec_u, /* 51 DEC Special Graphics */
+ dectech_u, /* 52 DEC Technical */
+ c0pics_u, /* 53 C0 Pictures */
+ c1pics_u, /* 54 C1 Pictures */
+ smiley_u, /* 55 IBM C0 Graphics */
+ heath19g_u, /* 56 Heath 19 graphics */
+ tvig_u, /* 57 TVI graphics */
+ wyse_gn_u, /* 58 Wyse 60 normal-mode graphics */
+ wyse_g1_u, /* 59 Wyse 60 graphics 1 */
+ wyse_g2_u, /* 60 Wyse 60 graphics 2 */
+ wyse_g3_u, /* 61 Wyse 60 graphics 3 */
+ elot927_u, /* 62 Greek ELOT 927 */
+ dgspec_u, /* 63 DG Special graphics */
+ dgline_u, /* 64 DG Line drawing */
+ dgword_u, /* 65 DG Word processing */
+ hpline_u, /* 66 HP Line drawing */
+ hpmath_u, /* 67 HP Math/Technical */
+ qnxgrph_u, /* 68 QNX Graphics */
+ snibrack_u, /* 69 SNI Brackets */
+ snieuro_u, /* 70 SNI Euro */
+ snifacet_u, /* 71 SNI Facet */
+ sniibm_u, /* 72 SNI IBM */
+ sniblanks_u, /* 73 SNI Blanks */
+ cp1252_u, /* 74 Windows Latin-1 */
+ cp1250_u, /* 75 Windows Latin-2 */
+ cp1251_u, /* 76 Windows Cyrillic */
+ cp1253_u, /* 77 Windows Greek */
+ cp1254_u, /* 78 Windows Turkish */
+ cp1257_u, /* 79 Windows Latin-4 */
+ cp856_u, /* 80 Cyrillic PC Code Page 856 */
+ cp855_u, /* 81 Cyrillic PC Code Page 856 */
+ iso_8859_1_u, /* 82 CP819 - Same as 8859-1 */
+ iso_8859_2_u, /* 83 CP912 - Same as 8859-2 */
+ iso_8859_3_u, /* 84 CP913 - Same as 8859-3 */
+ iso_8859_4_u, /* 85 CP914 - Same as 8859-4 */
+ iso_8859_5_u, /* 86 CP915 - Same as 8859-5 */
+ iso_8859_6_u, /* 87 CP1089 - Same as 8859-6 */
+ iso_8859_7_u, /* 88 CP813 - Same as 8859-7 */
+ iso_8859_8_u, /* 89 CP916 - Same as 8859-8 */
+ iso_8859_9_u, /* 90 CP920 - Same as 8859-9 */
+ hproman8_u, /* 91 CP1051 -Same as HP Roman 8 */
+ cp858_u, /* 92 CP858 - W Europe w/Euro */
+ iso_8859_15_u, /* 93 ISO 8859-15 Latin 15 */
+ iso_8859_15_u, /* 94 CP923 - Same as 8859-15 */
+ iso_8859_7_u, /* 95 ELOT928 - Same as 8859-7 */
+ quickdraw_u, /* 96 CP10000 - Apple Quickdraw */
+ cp37_u, /* 97 CP37 - U.S. EBCDIC */
+ cp1255_u, /* 98 CP1255 - Windows Hebrew */
+ cp1256_u, /* 99 CP1256 - Windows Arabic */
+ cp1258_u, /* 100 CP1258 - Windows Viet Nam */
+ mazovia_u, /* 101 Mazovia PC code page */
+ ident_u, /* 102 Transparent - no translation */
+ hz1500_u, /* 103 Hazeltine 1500/1520 graphics */
+ koi8r_u, /* 104 KOI8-R */
+ koi8u_u, /* 105 KOI8-U */
+ apl1_u, /* 106 APL 1 (ISO) */
+ apl2_u, /* 107 APL 2 (AIX) */
+ apl3_u, /* 108 APL 3 (Plus) */
+ apl4_u, /* 109 APL 4 (IBM) */
+ apl5_u /* 110 APL 5 (2741) */
+};
+/*
+ Table of Unicode-to-Blah translation functions.
+ KEEP THIS IN SYNC WITH THE TX_blah DEFINITITIONS in ckcuni.h, and also
+ with the tables above.
+*/
+int
+#ifdef CK_ANSIC
+(*xl_tx[MAXTXSETS+1])(USHORT)
+#else
+(*xl_tx[MAXTXSETS+1])()
+#endif /* CK_ANSIC */
+ = {
+ tx_usascii, /* 0 US ISO 646 (ASCII) */
+ tx_british, /* 1 UK ISO 646 */
+ tx_fr_canadian, /* 2 Canadian French NRC */
+ NULL, /* 3 Cuba */
+ NULL, /* 4 Czecho */
+ tx_danish, /* 5 Danish/Norwegian ISO 646 */
+ tx_dutch, /* 6 Dutch NRC */
+ tx_finnish, /* 7 Finnish NRC */
+ tx_french, /* 8 French ISO 646 */
+ tx_german, /* 9 German ISO 646 */
+ tx_hebrew7, /* 10 Hebrew-7 (DEC) */
+ tx_hungarian, /* 11 Hungarian ISO 646 */
+ tx_icelandic, /* 12 Icelandic */
+ tx_italian, /* 13 Italian ISO 646 */
+ tx_jis0201r, /* 14 Japanese Roman ISO 646 */
+ tx_jis0201k, /* 15 Japanese Katakana */
+ tx_koi7, /* 16 Short KOI */
+ tx_danish, /* 17 Norwegian/Danish ISO 646 */
+ tx_portuguese, /* 18 Portuguese ISO 646 */
+ tx_spanish, /* 19 spanish ISO 646 */
+ tx_swedish, /* 20 Swedish ISO 646 */
+ NULL, /* 21 Swedish ISO 646 for names */
+ tx_swiss, /* 22 Swiss NRC */
+ tx_ident, /* 23 ISO 8859-1 */
+ tx_8859_2, /* 24 ISO 8859-2 */
+ tx_8859_3, /* 25 ISO 8859-3 */
+ tx_8859_4, /* 26 ISO 8859-4 */
+ tx_8859_5, /* 27 ISO 8859-5 */ /* Cyrillic */
+ tx_8859_6, /* 28 ISO 8859-6 */ /* Arabic */
+ tx_8859_7, /* 29 ISO 8859-7 */ /* Greek */
+ tx_8859_8, /* 30 ISO 8859-8 */ /* Hebrew */
+ tx_8859_9, /* 31 ISO 8859-9 */ /* Latin-5 */
+ tx_8859_10, /* 32 ISO 8859-10 */ /* Latin-6 */
+ tx_koi8, /* 33 KOI-8 */
+ NULL, /* 34 JIS-7 */
+ NULL, /* 35 Shift JIS */
+ NULL, /* 36 Japanese EUC (JAE) */
+ NULL, /* 37 Japanese DEC Kanji */
+ tx_decmcs, /* 38 DEC MCS */
+ tx_nextstep, /* 39 NeXT */
+ tx_dgi, /* 40 DGI */
+ tx_maclatin, /* 41 Macintosh Latin */
+ tx_hproman8, /* 42 HP Roman 8 */
+ tx_cp437, /* 43 CP437 - Original */
+ tx_cp850, /* 44 CP850 - W Europe */
+ tx_cp852, /* 45 CP852 - E Europe */
+ tx_cp857, /* 46 CP857 - Turkish */
+ tx_cp862, /* 47 CP862 - Hebrew */
+ tx_cp866, /* 48 CP864 - Arabic */
+ tx_cp866, /* 49 CP866 - Cyrillic */
+ tx_cp869, /* 50 CP869 - Greek */
+ NULL, /* Display only */ /* 51 DEC Special Graphics */
+ NULL, /* Display only */ /* 52 DEC Technical */
+ NULL, /* Display only */ /* 53 C0 Pictures */
+ NULL, /* Display only */ /* 54 C1 Pictures */
+ NULL, /* Display only */ /* 55 IBM C0 Graphics */
+ NULL, /* Display only */ /* 56 Heath 19 graphics */
+ NULL, /* Display only */ /* 57 TVI graphics */
+ NULL, /* Display only */ /* 58 Wyse 60 normal-mode graphics */
+ NULL, /* Display only */ /* 59 Wyse 60 graphics 1 */
+ NULL, /* Display only */ /* 60 Wyse 60 graphics 2 */
+ NULL, /* Display only */ /* 61 Wyse 60 graphics 3 */
+ tx_elot927, /* 62 Greek ELOT 927 */
+ NULL, /* Display only */ /* 63 DG special graphics */
+ NULL, /* Display only */ /* 64 DG line-drawing */
+ NULL, /* Display only */ /* 65 DG word-processing */
+ NULL, /* Display only */ /* 66 HP line-drawing */
+ NULL, /* Display only */ /* 67 HP math/techical */
+ NULL, /* Display only */ /* 68 QNX Graphics */
+ NULL, /* Display only */ /* 69 SNI Brackets */
+ NULL, /* Display only */ /* 70 SNI Euro */
+ NULL, /* Display only */ /* 71 SNI Facet */
+ NULL, /* Display only */ /* 72 SNI IBM */
+ NULL, /* Display only */ /* 73 SNI Blanks */
+ tx_cp1252, /* 74 Windows Latin-1 */
+ tx_cp1250, /* 75 Windows Latin-2 */
+ tx_cp1251, /* 76 Windows Cyrillic */
+ tx_cp1253, /* 77 Windows Greek */
+ tx_cp1254, /* 78 Windows Turkish */
+ tx_cp1257, /* 79 Windows Latin-4 */
+ tx_cp856, /* 80 Cyrillic PC Code Page 856 */
+ tx_cp855, /* 81 Cyrillic PC Code Page 855 */
+ tx_ident, /* 82 CP819 - Same as 8859-1 */
+ tx_8859_2, /* 83 CP912 - Same as 8859-2 */
+ tx_8859_3, /* 84 CP913 - Same as 8859-3 */
+ tx_8859_4, /* 85 CP914 - Same as 8859-4 */
+ tx_8859_5, /* 86 CP915 - Same as 8859-5 */
+ tx_8859_6, /* 87 CP1089 - Same as 8859-6 */
+ tx_8859_7, /* 88 CP813 - Same as 8859-7 */
+ tx_8859_8, /* 89 CP916 - Same as 8859-8 */
+ tx_8859_9, /* 90 CP920 - Same as 8859-9 */
+ tx_hproman8, /* 91 CP1051 -Same as HP Roman 8 */
+ tx_cp858, /* 92 CP858 - W Europe w/Euro */
+ tx_8859_15, /* 93 ISO 8859-15 Latin 15 */
+ tx_8859_15, /* 94 CP923 - Same as Latin 15 */
+ tx_8859_7, /* 95 ELOT928 - Same as 8859-7 */
+ tx_quickdraw, /* 96 CP10000 - Apple Quickdraw */
+ tx_cp37, /* 97 CP37 - U.S. EBCDIC */
+ tx_cp1255, /* 98 CP1255 - Windows Hebrew */
+ tx_cp1256, /* 99 CP1256 - Windows Arabic */
+ tx_cp1258, /* 100 CP1258 - Windows Viet Nam */
+ tx_mazovia, /* 101 Mazovia PC code page */
+ tx_ident, /* 102 Transparent - no translation */
+ NULL, /* Display only */ /* 103 Hazeltine 1500/1520 graphics */
+ tx_koi8r, /* 104 KOI8-R */
+ tx_koi8u, /* 105 KOI8-U */
+ tx_apl1, /* 106 APL 1 (ISO) */
+ tx_apl2, /* 107 APL 2 (AIX) */
+ tx_apl3, /* 108 APL 3 (Plus) */
+ tx_apl4, /* 108 APL 4 (IBM) */
+ tx_apl5 /* 110 APL 5 (2741) */
+};
+
+/*
+ Table of FCS-to-Unicode translation functions.
+ KEEP THIS IN SYNC WITH THE FC_blah DEFINITITIONS in ckuxla.h.
+*/
+USHORT
+#ifdef CK_ANSIC
+(*xl_fcu[MAXFCSETS+1])(CHAR)
+#else
+(*xl_fcu[MAXFCSETS+1])()
+#endif /* CK_ANSIC */
+= {
+ ascii_u, /* 0 US ISO 646 (ASCII) */
+ british_u, /* 1 UK ISO 646 */
+ dutch_u, /* 2 Dutch NRC */
+ finnish_u, /* 3 Finnish NRC */
+ french_u, /* 4 French ISO 646 */
+ fr_canadian_u, /* 5 Canadian French NRC */
+ german_u, /* 6 German ISO 646 */
+ hungarian_u, /* 7 Hungarian ISO 646 */
+ italian_u, /* 8 Italian ISO 646 */
+ danish_u, /* 9 Danish/Norwegian ISO 646 */
+ portuguese_u, /* 10 Portuguese ISO 646 */
+ spanish_u, /* 11 spanish ISO 646 */
+ swedish_u, /* 12 Swedish ISO 646 */
+ swiss_u, /* 13 Swiss NRC */
+ iso_8859_1_u, /* 14 ISO 8859-1 Latin-1 */
+ iso_8859_2_u, /* 15 ISO 8859-2 Latin-2 */
+ decmcs_u, /* 16 DEC MCS */
+ nextstep_u, /* 17 NeXT */
+ cp437_u, /* 18 CP437 - Original */
+ cp850_u, /* 19 CP850 - W Europe */
+ cp852_u, /* 20 CP852 - E Europe */
+ quickdraw_u, /* 21 CP10000 - Apple Quickdraw */
+ dgi_u, /* 22 DGI */
+ hproman8_u, /* 23 HP Roman 8 */
+ iso_8859_5_u, /* 24 ISO 8859-5 Cyrillic */
+ cp866_u, /* 25 CP866 - Cyrillic */
+ koi7_u, /* 26 Short KOI */
+ koi8_u, /* 27 KOI-8 */
+ NULL, /* 28 JIS-7 */
+ NULL, /* 29 Shift-JIS */
+ NULL, /* 30 Japanese EUC */
+ NULL, /* 31 DEC Kanji */
+ hebrew7_u, /* 32 Hebrew-7 (DEC) */
+ iso_8859_8_u, /* 33 ISO 8859-8 Hebrew */
+ cp862_u, /* 34 CP862 Hebrew */
+ elot927_u, /* 35 Greek ELOT 927 */
+ iso_8859_7_u, /* 36 ISO 8859-7 Greek */
+ cp869_u, /* 37 CP869 Greek */
+ iso_8859_15_u, /* 38 ISO 8859-15 Latin-9 */
+ cp858_u, /* 39 CP858 - W Europe w/Euro */
+ cp855_u, /* 40 Cyrillic PC Code Page 856 */
+ cp1251_u, /* 41 Windows Cyrillic */
+ cp856_u, /* 42 Bulgarian PC Code Page 856 */
+ cp1250_u, /* 43 Windows Latin-2 */
+ mazovia_u, /* 44 Mazovia PC code page */
+ NULL, /* 45 UCS-2 */
+ NULL, /* 46 UTF-8 */
+ koi8r_u, /* 47 KOI8-R */
+ koi8u_u, /* 48 KOI8-U */
+ cp1252_u /* 49 CP1252 */
+};
+
+/*
+ Table of Unicode-to-FCS translation functions.
+ KEEP THIS IN SYNC WITH THE FC_blah DEFINITITIONS in ckuxla.h.
+*/
+int
+#ifdef CK_ANSIC
+(*xl_ufc[MAXFCSETS+1])(USHORT)
+#else
+(*xl_ufc[MAXFCSETS+1])()
+#endif /* CK_ANSIC */
+= {
+ tx_usascii, /* 0 US ISO 646 (ASCII) */
+ tx_british, /* 1 UK ISO 646 */
+ tx_dutch, /* 2 Dutch NRC */
+ tx_finnish, /* 3 Finnish NRC */
+ tx_french, /* 4 French ISO 646 */
+ tx_fr_canadian, /* 5 Canadian French NRC */
+ tx_german, /* 6 German ISO 646 */
+ tx_hungarian, /* 7 Hungarian ISO 646 */
+ tx_italian, /* 8 Italian ISO 646 */
+ tx_danish, /* 9 Danish/Norwegian ISO 646 */
+ tx_portuguese, /* 10 Portuguese ISO 646 */
+ tx_spanish, /* 11 spanish ISO 646 */
+ tx_swedish, /* 12 Swedish ISO 646 */
+ tx_swiss, /* 13 Swiss NRC */
+ tx_ident, /* 14 ISO 8859-1 Latin-1 */
+ tx_8859_2, /* 15 ISO 8859-2 Latin-2 */
+ tx_decmcs, /* 16 DEC MCS */
+ tx_nextstep, /* 17 NeXT */
+ tx_cp437, /* 18 CP437 - Original */
+ tx_cp850, /* 19 CP850 - W Europe */
+ tx_cp852, /* 20 CP852 - E Europe */
+ tx_quickdraw, /* 21 CP10000 - Apple Quickdraw */
+ tx_dgi, /* 22 DGI */
+ tx_hproman8, /* 23 HP Roman 8 */
+ tx_8859_5, /* 24 ISO 8859-5 Cyrillic */
+ tx_cp866, /* 25 CP866 - Cyrillic */
+ tx_koi7, /* 26 Short KOI */
+ tx_koi8, /* 27 KOI-8 */
+ NULL, /* 28 JIS-7 */
+ NULL, /* 29 Shift-JIS */
+ NULL, /* 30 Japanese EUC */
+ NULL, /* 31 DEC Kanji */
+ tx_hebrew7, /* 32 Hebrew-7 (DEC) */
+ tx_8859_8, /* 33 ISO 8859-8 Hebrew */
+ tx_cp862, /* 34 CP862 Hebrew */
+ tx_elot927, /* 35 Greek ELOT 927 */
+ tx_8859_7, /* 36 ISO 8859-7 Greek */
+ tx_cp869, /* 37 CP869 Greek */
+ tx_8859_15, /* 38 ISO 8859-15 Latin-9 */
+ tx_cp858, /* 39 CP858 - W Europe w/Euro */
+ tx_cp855, /* 40 Cyrillic PC Code Page 856 */
+ tx_cp1251, /* 41 Windows Cyrillic */
+ tx_cp856, /* 42 Bulgarian PC Code Page 856 */
+ tx_cp1250, /* 43 Windows Latin-2 */
+ tx_mazovia, /* 44 Mazovia PC code page */
+ NULL, /* 45 UCS-2 */
+ NULL, /* 46 UTF-8 */
+ tx_koi8r, /* 47 KOI8-R */
+ tx_koi8u, /* 48 KOI8-U */
+ tx_cp1252 /* 49 CP1252 */
+};
+
+/*
+ Table of TCS-to-Unicode translation functions.
+ KEEP THIS IN SYNC WITH THE TC_blah DEFINITIONS in ckuxla.h.
+*/
+USHORT
+#ifdef CK_ANSIC
+(*xl_tcu[MAXTCSETS+1])(CHAR)
+#else
+(*xl_tcu[MAXTCSETS+1])()
+#endif /* CK_ANSIC */
+= {
+ NULL, /* 0 = Transparent */
+ ascii_u, /* 1 = ASCII */
+ iso_8859_1_u, /* 2 ISO 8859-1 Latin-1 */
+ iso_8859_2_u, /* 3 ISO 8859-2 Latin-2 */
+ iso_8859_5_u, /* 4 ISO 8859-5 Cyrillic */
+ NULL, /* 5 Japanese EUC */
+ iso_8859_8_u, /* 6 ISO 8859-8 Hebrew */
+ iso_8859_7_u, /* 7 ISO 8859-7 Greek */
+ iso_8859_15_u, /* 8 ISO 8859-15 Latin-9 */
+ NULL, /* 9 UCS-2 */
+ NULL /* 10 UTF-8 */
+};
+
+
+/*
+ Table of Unicode-to-TCS translation functions.
+ KEEP THIS IN SYNC WITH THE TC_blah DEFINITIONS in ckuxla.h.
+*/
+int
+#ifdef CK_ANSIC
+(*xl_utc[MAXTCSETS+1])(USHORT)
+#else
+(*xl_utc[MAXTCSETS+1])()
+#endif /* CK_ANSIC */
+= {
+ NULL, /* 0 = Transparent */
+ tx_usascii, /* 1 = ASCII */
+ tx_ident, /* 2 ISO 8859-1 Latin-1 */
+ tx_8859_2, /* 3 ISO 8859-2 Latin-2 */
+ tx_8859_5, /* 4 ISO 8859-5 Cyrillic */
+ NULL, /* 5 Japanese EUC */
+ tx_8859_8, /* 6 ISO 8859-8 Hebrew */
+ tx_8859_7, /* 7 ISO 8859-7 Greek */
+ tx_8859_15, /* 8 ISO 8859-15 Latin-9 */
+ NULL, /* 9 UCS-2 */
+ NULL /* 10 UTF-8 */
+};
+
+#ifdef COMMENT
+/*
+ The UTF8 conversions are based on the ConvertUTF functions written
+ by Mark E. Davis, copyright 1994 Taligent, Inc.
+
+ Tables for use in calculating UTF8 conversions. These contain
+ support for ISO-10646 which supports a 31-bit char size.
+
+ NOTE: 0xnnnUL is NOT portable!
+*/
+ULONG
+offsetsFromUTF8[7] = {
+#ifdef CK_ANSIC
+ 0x00000000UL, /* Ignored */
+ 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL
+#else
+ 0x00000000L, /* Ignored */
+ 0x00000000L, 0x00003080L, 0x000E2080L,
+ 0x03C82080L, (unsigned) 0xFA082080L, (unsigned) 0x82082080L
+#endif /* CK_ANSIC */
+};
+
+CHAR bytesInUTF8[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6
+};
+#endif /* COMMENT */
+
+CHAR firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
+
+/*
+ utf8_to_ucs2() takes one UTF-8 byte at a time. It returns a pointer the
+ UCS-2 character if and only if the entire UTF-8 string has been received.
+ Return values:
+ 0: Complete UTF-8 sequence received; ucs2 points to valid ucs2 character.
+ >0: UTF-8 sequence incomplete, ignore ucs2 value.
+ <0: UTF-8 error, 0xfffd should be inserted BEFORE the ucs2 value.
+
+ NOTE: A negative value is returned only when two return values are indicated,
+ e.g. when a UTF-8 sequence is interrupted by an ASCII char. In this case
+ the incomplete UTF-8 sequence must be replaced by 0xfffd, and then the ASCII
+ character is kept as-is. In other error cases, ucs2 is set to 0xfffd and
+ the return value is 0.
+*/
+#define UTFBUFSIZ 16
+
+int
+#ifdef CK_ANSIC
+utf8_to_ucs2(CHAR ch, USHORT ** ucs2)
+#else
+utf8_to_ucs2(ch, ucs2) CHAR ch; USHORT ** ucs2;
+#endif /* CK_ANSIC */
+{
+ static USHORT ucs2return = 0;
+
+#ifdef COMMENT
+ /* Unicode Consortium sample code works only with well-formed UTF8 */
+
+ int i = 0;
+ static int len = 0;
+ static CHAR utf8[UTFBUFSIZ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ ULONG ucs4 = 0;
+
+ utf8[len++] = ch; /* Add char to string to process */
+
+ if (len < bytesInUTF8[utf8[0]]) /* Need more bytes */
+ return(bytesInUTF8[utf8[0]] - len);
+
+ switch (len) { /* Have complete sequence... */
+ case 6: ucs4 += utf8[i++]; ucs4 <<= 6; /* (fall-thru is intentional) */
+ case 5: ucs4 += utf8[i++]; ucs4 <<= 6;
+ case 4: ucs4 += utf8[i++]; ucs4 <<= 6;
+ case 3: ucs4 += utf8[i++]; ucs4 <<= 6;
+ case 2: ucs4 += utf8[i++]; ucs4 <<= 6;
+ case 1: ucs4 += utf8[i++];
+ }
+ ucs4 -= offsetsFromUTF8[len];
+ ucs2return = (USHORT)(ucs4 & 0xFFFF);
+#ifdef DEBUG
+ /* This shows that our return value is in the prevailing byte order: */
+ /* e.g. LE on PC, BE on Sparc. */
+ if (deblog) {
+ char buf[16];
+ union ck_short xx;
+ xx.x_short = ucs2return;
+ sprintf(buf,"%04X",ucs2return);
+ debug(F111,"utf8_to_ucs2 short",buf,ucs2return);
+ debug(F101,"utf8_to_ucs2 char[0]","",xx.x_char[0]);
+ debug(F101,"utf8_to_ucs2 char[1]","",xx.x_char[1]);
+ }
+#endif /* DEBUG */
+ *ucs2 = &ucs2return;
+ len = 0;
+ return(0);
+#else
+ /*
+ Robuster code adapted from Thomas Dickey, Xfree86,
+ recommended by Markus Kuhn.
+ */
+ static int utfcount = 0; /* Position in UTF sequence */
+ int utferror = 0; /* Flag for malformed UTF */
+ unsigned c = ch; /* Input byte */
+ int haveucs2 = 0;
+
+ if (ch < 0x80) { /* ASCII char... */
+ if (utfcount > 0) /* Not legal in UTF-8 sequence */
+ utferror = 1; /* so flag */
+ haveucs2 = 1;
+ ucs2return = ch; /* but also return it */
+ utfcount = 0; /* reset UTF-8 count */
+ } else if (ch < 0xc0) { /* 0x80 <= c < 0xc0... */
+ if (utfcount < 1) { /* Not valid in first position... */
+ utferror = 1;
+ } else { /* Maybe valid */
+ if (ucs2return > 0x03ff) { /* Value would be > 0xffff */
+ utferror = 1; /* so not valid */
+ } else { /* OK... */
+ ucs2return <<= 6; /* Shift result */
+ ucs2return |= (ch & 0x3f); /* and OR in this byte */
+ }
+ if (--utfcount == 0)
+ haveucs2 = 1;
+ }
+ } else { /* c >= 0xc0... */
+ if (utfcount > 0)
+ utferror = 1;
+ if (c < 0xe0) {
+ utfcount = 1;
+ ucs2return = (c & 0x1f);
+ haveucs2 = 1;
+ } else if (c < 0xf0) {
+ utfcount = 2;
+ ucs2return = (c & 0x0f);
+ haveucs2 = 1;
+ } else if (c < 0xf8) {
+ utfcount = 3;
+ ucs2return = (c & 0x07);
+ haveucs2 = 1;
+ } else if (c < 0xfc) {
+ utfcount = 4;
+ ucs2return = (c & 0x03);
+ haveucs2 = 1;
+ } else if (c < 0xfe) {
+ utfcount = 5;
+ ucs2return = (c & 0x01);
+ haveucs2 = 1;
+ } else {
+ utferror = 1;
+ utfcount = 0;
+ }
+ }
+ if (haveucs2 == 0 && utferror != 0) {
+ haveucs2 = 1;
+ ucs2return = 0xfffd;
+ utferror = 0;
+ }
+ if (haveucs2) {
+ *ucs2 = &ucs2return;
+ if (utferror)
+ utfcount = 0 - utfcount;
+ return(utfcount);
+ } else {
+ if (utfcount == 0)
+ utfcount++;
+ return(utfcount);
+ }
+#endif /* COMMENT */
+}
+
+/*
+ ucs2_to_utf8() takes one ucs2 character and returns the length and
+ and a pointer to an array containing the equivalent utf8 string.
+ This code can easily be altered to support UCS4 simply by changing
+ the input from USHORT to ULONG. Returns:
+ >0: Number of bytes in the utf8 string.
+ 0: (or less) Error.
+*/
+
+int
+#ifdef CK_ANSIC
+ucs2_to_utf8(USHORT ucs2, CHAR ** utf8)
+#else
+ucs2_to_utf8(ucs2, utf8) USHORT ucs2; CHAR ** utf8;
+#endif /* CK_ANSIC */
+{
+ static CHAR utf8return[8]={0,0,0,0,0,0,0,0};
+ register CONST ULONG byteMask = 0xBF;
+ register CONST ULONG byteMark = 0x80;
+ int utf8len = 0;
+ int i = 0;
+
+ if (ucs2 < 0x80) {
+ utf8len = 1;
+ debug(F101,"ucs2_to_utf8 X1","",utf8len);
+ } else if (ucs2 < 0x800) {
+ utf8len = 2;
+ debug(F101,"ucs2_to_utf8 X2","",utf8len);
+ } else
+#ifdef DO_UCS4
+ /* This is always true for UCS-2 but would be needed for UCS-4*/
+ /* When ucs2 is USHORT this gives compiler warnings. */
+ if (ucs2 <= 0xffff)
+#endif /* DO_UCS4 */
+ {
+ utf8len = 3;
+ debug(F101,"ucs2_to_utf8 X3","",utf8len);
+ }
+#ifdef DO_UCS4
+/* The following would be for UCS-4 */
+ else if (ucs2 < 0x200000) {
+ utf8len = 4;
+ } else if (ucs2 < 0x4000000) {
+ utf8len = 5;
+ } else if (ucs2 <=
+#ifdef CK_ANSIC
+ 0x7FFFFFFFUL /* (doesn't really need the "U") */
+#else
+ 0x7FFFFFFFL
+#endif /* CK_ANSIC */
+ ) { /* 31 bits = max for UCS4 */
+ utf8len = 6;
+ } else {
+ utf8len = 2;
+ ucs2 = 0xFFFD; /* Replacement for invalid char */
+ }
+#endif /* DO_UCS4 */
+ i = utf8len; /* index into utf8return */
+ utf8return[i--] = 0; /* Null terminate the string */
+
+ switch (utf8len) { /* code falls through cases! */
+ case 6: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6;
+ case 5: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6;
+ case 4: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6;
+ case 3: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6;
+ case 2: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6;
+ case 1: utf8return[i--] = ucs2 | firstByteMark[utf8len];
+ }
+ debug(F111,"ucs2_to_utf8",utf8return,utf8len);
+ *utf8 = utf8return;
+ return(utf8len);
+}
+
+/* UTF-8 functions... */
+
+#ifdef CK_ANSIC
+extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
+extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
+#else
+extern int (*xuf)();
+extern USHORT (*xfu)();
+#endif /* CK_ANSIC */
+
+/* u _ t o _ b -- UTF-8 to Byte */
+/*
+ Converts from UTF-8 to the current terminal or file character set.
+ Call with:
+ c: a single byte, which is part of a UTF-8 stream.
+ Returns:
+ -9: Error, with second char to follow (call u_to_b2() to get it).
+ -2: UCS line/paragraph end (LS or PS).
+ -1: UTF-8 stream is incomplete and more input is required.
+ >=0: Byte value of result, possibly the "error" byte (e.g. '?').
+ Requires:
+ Global (*xuf)() to point to a function that translates from UCS-2 to
+ the appropriate term/file character set.
+*/
+static int savedbyte = 0;
+
+int /* Call if u_to_b() returns -9 */
+u_to_b2() {
+ return((unsigned)(savedbyte & 0xff));
+}
+
+int /* UTF-8 to byte */
+#ifdef CK_ANSIC
+u_to_b(CHAR c)
+#else
+u_to_b(c) CHAR c;
+#endif /* CK_ANSIC */
+{
+ int x;
+ USHORT * ucs2, uc;
+ if (!xuf) /* If no conversion function */
+ return(c); /* don't convert (shouldn't happen). */
+ x = utf8_to_ucs2(c,&ucs2); /* Send for conversion to UCS-2 */
+ if (x > 0) /* Not done yet... */
+ return(-1);
+ uc = (x < 0) ? 0xfffd : *ucs2; /* Done, check result */
+ if (uc == 0x2028 || uc == 0x2029) /* LS or PS */
+ return(-2);
+ return((unsigned)(((*xuf)(uc)) & 0xff)); /* Convert UCS-2 to byte */
+}
+
+/* b _ t o _ u -- Byte to UTF-8 */
+/*
+ Converts a byte from the current terminal or file character set to UTF-8.
+ Call with:
+ c........ The byte to be converted.
+ buf...... Pointer to buffer in which to place the result.
+ buflen... Length of the result buffer.
+ setsize.. The size of the source character set (128 or 256).
+ Requires:
+ Global (*xfu)() to point to the function to convert the byte to UCS-2.
+ Returns:
+ -1 if the xfu is NULL; otherwise:
+ >0 indicating the length (in bytes) of the UTF-8 string.
+ If the translation fails, the Unicode "Replacement Character" is returned
+ (0xFFFD translated to UTF-8 == 0xFFBD).
+*/
+int /* Byte to UTF-8 */
+#ifdef CK_ANSIC
+b_to_u(CHAR c, CHAR * buf, int buflen, int setsize)
+#else
+b_to_u(c, buf, buflen, setsize) CHAR c, * buf; int buflen, setsize;
+#endif /* CK_ANSIC */
+{
+ CHAR * tmp = NULL;
+ int i, count = 0;
+ USHORT uc;
+ if (!xfu) {
+ debug(F100,"b_to_u no xfu","",0);
+ return(-1);
+ }
+ uc = c;
+ if (((setsize > 128) && (c & 0x80)) || setsize <= 128) {
+ if (xfu) /* FCS-to-UCS function */
+ uc = (*xfu)(c);
+ }
+ count = ucs2_to_utf8(uc,&tmp);
+ if (count < 0) {
+ buf[0] = 0xef; /* == 0xFFFD in UTF-8 */
+ buf[1] = 0xbf;
+ buf[2] = 0xbd;
+ buf[3] = '\0';
+ return(2);
+ }
+ if (count >= buflen) {
+ debug(F101,"WARNING: UTF8 buffer overflow","",count);
+ count = buflen - 1;
+ }
+ for (i = 0; i < count; i++) /* Copy to result buffer */
+ buf[i] = tmp[i];
+ buf[i] = '\0';
+ return(count);
+}
+
+#ifndef OS2
+int
+isunicode( /* Tells whether the host we are */
+#ifdef CK_ANSIC /* running on supports Unicode */
+ void /* display */
+#endif /* CK_ANSIC */
+ ) {
+#ifdef NT
+ extern int tt_unicode;
+#ifdef KUI
+ return(tt_unicode);
+#else /* KUI */
+ if (tt_unicode && !isWin95())
+ return(1);
+ else
+ return(0);
+#endif /* KUI */
+#else /* NT */
+ return(0);
+#endif /* NT */
+}
+#endif /* OS2 */
+#endif /* UNICODE */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcuni.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcuni.h
new file mode 100644
index 0000000..06dff9b
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcuni.h
@@ -0,0 +1,268 @@
+/* C K C U N I . H -- Unicode/Terminal character-set translations */
+
+/*
+ Copyright (C) 1999, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>
+ The Kermit Project, Columbia University, New York City.
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+*/
+
+/* Terminal character sets */
+
+#ifndef CKOUNI_H
+#define CKOUNI_H
+#ifdef OS2
+#ifndef CKOUNI
+#define CKOUNI /* Use UNICODE for OS/2 functions */
+#endif /* CKOUNI */
+#ifdef KUI
+#define X_CKOUNI_IN /* Use Unicode Input */
+#define CKOUNI_OUT
+#endif /* KUI */
+#endif /* OS2 */
+
+/* Terminal Character Sets */
+
+#define TX_ASCII 0 /* US ASCII */
+#define TX_BRITISH 1 /* British ISO 646 */
+#define TX_CN_FRENCH 2 /* Canadian French NRC */
+#define TX_CUBAN 3 /* Cuba */
+#define TX_CZECH 4 /* Czech Republic */
+#define TX_DANISH 5 /* Denmark / Norway ISO 646 */
+#define TX_DUTCH 6 /* Dutch NRC */
+#define TX_FINNISH 7 /* Finnish NRC */
+#define TX_FRENCH 8 /* French ISO 646 */
+#define TX_GERMAN 9 /* German ISO 646 */
+#define TX_HE7 10 /* Hebrew 7 (DEC) */
+#define TX_HUNGARIAN 11 /* Hungarian ISO 646 */
+#define TX_ICELANDIC 12 /* Icelandic NRC */
+#define TX_ITALIAN 13 /* Italian ISO 646 */
+#define TX_J201R 14 /* JIS 0201 Japanese Roman */
+#define TX_J201K 15 /* JIS 0201 Katakana */
+#define TX_KOI7 16 /* Short KOI */
+#define TX_NORWEGIAN 17 /* Denmark / Norway ISO 646 */
+#define TX_PORTUGUESE 18 /* Portuguese ISO 646 */
+#define TX_SPANISH 19 /* Spanish ISO 646 */
+#define TX_SWEDISH 20 /* Swedish ISO 646 */
+#define TX_SWE_2 21 /* Swedish for names ISO 646 */
+#define TX_SWISS 22 /* Swiss NRC */
+#define TX_8859_1 23 /* Latin-1 */
+#define TX_8859_2 24 /* Latin-2 */
+#define TX_8859_3 25 /* Latin-3 */
+#define TX_8859_4 26 /* Latin-4 */
+#define TX_8859_5 27 /* Latin/Cyrillic */
+#define TX_8859_6 28 /* Latin/Arabic */
+#define TX_8859_7 29 /* Latin/Greek */
+#define TX_8859_8 30 /* Latin/Hebrew */
+#define TX_8859_9 31 /* Latin-5 */
+#define TX_8859_10 32 /* Latin-6 */
+
+#define TX_KOI8 33 /* GOST 19768-74 KOI-8 */
+
+#define TX_JIS7 34 /* JIS-7 */
+#define TX_SHJIS 35 /* Shift JIS */
+#define TX_JEUC 36 /* Japanese EUC */
+#define TX_JDEC 37 /* Japanese DEC Kanji */
+
+#define TX_DECMCS 38 /* DEC MCS */
+#define TX_NEXT 39 /* NeXT */
+#define TX_DGI 40 /* Data General International */
+#define TX_MACL1 41 /* Macintosh Latin-1 */
+#define TX_HPR8 42 /* HP Roman 8 */
+
+/* Code pages */
+
+#define TX_CP437 43 /* Original */
+#define TX_CP850 44 /* Multinational (Western Europe) */
+#define TX_CP852 45 /* Eastern Europe */
+#define TX_CP857 46 /* Turkey */
+#define TX_CP862 47 /* Hebrew */
+#define TX_CP864 48 /* Arabic */
+#define TX_CP866 49 /* Cyrillic */
+#define TX_CP869 50 /* Greek */
+
+#define TX_DECSPEC 51 /* DEC Special Graphics */
+#define TX_DECTECH 52 /* DEC Technical */
+#define TX_C0PICT 53 /* C0 Display Controls */
+#define TX_C1PICT 54 /* C1 Display Controls */
+#define TX_IBMC0GRPH 55 /* IBM C0 Graphics (smileys) */
+#define TX_H19GRAPH 56 /* Heath/Zenith 19 Graphics */
+#define TX_TVIGRAPH 57 /* Televideo Graphics */
+#define TX_WYSE60G_N 58 /* Wyse 60 Native Mode Graphics */
+#define TX_WYSE60G_1 59 /* Wyse 60 Graphics 1 */
+#define TX_WYSE60G_2 60 /* Wyse 60 Graphics 2 */
+#define TX_WYSE60G_3 61 /* Wyse 60 Graphics 3 */
+
+/* New ones that came too late for the nice grouping... */
+
+#define TX_ELOT927 62 /* Greek ELOT 927 */
+#define TX_DGPCGRPH 63 /* DG PC Graphics */
+#define TX_DGLDGRPH 64 /* DG Line Drawing Graphics */
+#define TX_DGWPGRPH 65 /* DG Word Processing (etc) Graphics */
+#define TX_HPLINE 66 /* HP Line Drawing */
+#define TX_HPMATH 67 /* HP Math/Technical */
+#define TX_QNXGRPH 68 /* QNX Graphics */
+
+/* Siemens Nixdorf character sets */
+
+#define TX_SNIBRACK 69 /* SNI 97801 Brackets */
+#define TX_SNIEURO 70 /* SNI 97801 Euro */
+#define TX_SNIFACET 71 /* SNI 97801 Facet */
+#define TX_SNIIBM 72 /* SNI 97801 "IBM" */
+#define TX_SNIBLANK 73 /* SNI 97801 Blanks */
+
+/* Windows Code pages */
+
+#define TX_CP1252 74 /* Latin-1 Windows */
+#define TX_CP1250 75 /* Latin-2 Windows */
+#define TX_CP1251 76 /* Cyrillic Windows */
+#define TX_CP1253 77 /* Greece Windows */
+#define TX_CP1254 78 /* Turkey Windows */
+#define TX_CP1257 79 /* Latin-4 Windows */
+
+#define TX_CP856 80 /* Bulgaria CP856 (DATECS Ltd) */
+#define TX_CP855 81
+#define TX_CP819 82 /* Same as ISO 8859-1 */
+#define TX_CP912 83 /* Same as ISO 8859-2 */
+#define TX_CP913 84 /* Same as ISO 8859-3 */
+#define TX_CP914 85 /* Same as ISO 8859-4 */
+#define TX_CP915 86 /* Same as ISO 8859-5 */
+#define TX_CP1089 87 /* Same as ISO 8859-6 */
+#define TX_CP813 88 /* Same as ISO 8859-7 */
+#define TX_CP916 89 /* Same as ISO 8859-8 */
+#define TX_CP920 90 /* Same as ISO 8859-9 */
+#define TX_CP1051 91 /* Same as HP Roman 8 */
+#define TX_CP858 92 /* Multinational (W. Europe) w/Euro */
+#define TX_8859_15 93 /* Latin-9 */
+#define TX_CP923 94 /* Same as ISO 8859-15 */
+
+#define TX_ELOT928 95 /* Same as ISO 8859-7 */
+#define TX_CP10000 96 /* Same as original Apple Quickdraw */
+#define TX_CP37 97 /* EBCDIC */
+#define TX_CP1255 98 /* Israel Windows */
+#define TX_CP1256 99 /* Arabic Windows */
+#define TX_CP1258 100 /* Viet Nam Windows */
+#define TX_MAZOVIA 101
+#define TX_TRANSP 102 /* Transparent - no translation */
+#define TX_HZ1500 103 /* Hazeltine 1500 graphics set */
+#define TX_KOI8R 104 /* KOI8R - Russian */
+#define TX_KOI8U 105 /* KOI8U - Ukrainian */
+#define TX_APL1 106 /* APL ISO IR 68 */
+#define TX_APL2 107 /* Dyadic Systems Inc APL */
+#define TX_APL3 108 /* APL-Plus (APL-2000) */
+#define TX_APL4 109 /* IBM APL/2 */
+#define TX_APL5 110 /* APL-2741 */
+
+#define MAXTXSETS 111 /* Number of terminal character sets */
+
+/* The following are not implemented yet */
+/* UTF-8 is supported as a special mode in Kermit 95 (see utf8 flag) */
+
+#define TX_UTF7 128
+#define TX_UTF8 129
+
+#define TX_HEXBYTES 242 /* Hex bytes */
+#define TX_DEBUG 243 /* Debugging but not hex bytes */
+
+/* These are actually used */
+
+#define TX_UNDEF 255 /* Unknown character-set */
+
+/* Flag bit values */
+
+#define X2U_STD 1 /* Has standard ISO 4873 layout */
+#define X2U_ISO 2 /* ISO standard character set */
+#define X2U_JIS 4 /* Japan Industrial Standard */
+#define X2U_CP 8 /* PC Code Page */
+#define X2U_DEC 16 /* DEC Private character set */
+#define X2U_CXG 32 /* Control codes used for graphics */
+
+struct x_to_unicode {
+ int size; /* 94, 96, 128, or other */
+ int offset; /* 0, 32, 33, 128, 160, ... */
+ int flags;
+ int family; /* Language family, writing system */
+ char * keywd; /* Keyword name */
+ char * name; /* Descriptive name */
+ int code; /* ISO reg number if Standard */
+ /* CP number if Code-page, etc. */
+ char * final; /* Esc seq final char(s) (ISO, DEC) */
+ unsigned short map[256]; /* Mapping table */
+};
+
+extern struct keytab txrtab[];
+extern int ntxrtab;
+
+#ifndef NULL
+#define NULL (char *)0
+#endif /* NULL */
+
+#ifndef USHORT
+#define USHORT unsigned short
+#endif /* USHORT */
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif /* ULONG */
+
+#ifndef CHAR
+#define CHAR unsigned char
+#endif /* CHAR */
+
+#ifdef CK_ANSIC
+extern USHORT (*xl_u[MAXTXSETS+1])(CHAR); /* Blah-to-Unicode functions */
+extern int (*xl_tx[MAXTXSETS+1])(USHORT); /* Unicode-to-Blah functions */
+#else
+extern USHORT (*xl_u[MAXTXSETS+1])();
+extern int (*xl_tx[MAXTXSETS+1])();
+#endif /* CK_ANSIC */
+extern struct x_to_unicode * txrinfo[MAXTXSETS+1];
+
+_PROTOTYP(int isunicode, (void));
+_PROTOTYP(int utf8_to_ucs2, (CHAR, USHORT **));
+_PROTOTYP(int ucs2_to_utf8, (USHORT, CHAR **));
+_PROTOTYP(int tx_cpsub, (USHORT));
+_PROTOTYP(int u_to_b, (CHAR) );
+_PROTOTYP(int u_to_b2, (void) );
+_PROTOTYP(int b_to_u, (CHAR, CHAR *, int, int) );
+
+#ifdef KANJI
+_PROTOTYP(USHORT sj_to_un, (USHORT) ); /* Shift-JIS to Unicode */
+_PROTOTYP(USHORT un_to_sj, (USHORT) ); /* Unicode to Shift-JIS */
+#endif /* KANJI */
+
+#ifdef OS2
+#ifdef NT
+_inline
+#else
+_Inline
+#endif /* NT */
+int
+isunicode(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ ) {
+ extern int tt_unicode;
+#ifdef NT
+#ifdef KUI
+ return(tt_unicode);
+#else /* KUI */
+ if (tt_unicode && !isWin95())
+ return(1);
+ else
+ return(0);
+#endif /* KUI */
+#else /* NT */
+ return(0);
+#endif /* NT */
+}
+#endif /* OS2 */
+#endif /* CKOUNI_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckcxla.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckcxla.h
new file mode 100644
index 0000000..6403c81
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckcxla.h
@@ -0,0 +1,337 @@
+/*
+ File CKCXLA.H
+
+ System-independent character-set translation header file for C-Kermit.
+*/
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project - Columbia University, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+/*
+ NOTE:
+ ISO 204 is Latin-1 + Euro.
+ ISO 205 is Latin-4 + Euro.
+ ISO 206 is Latin-7 + Euro.
+*/
+#ifndef CKCXLA_H /* Guard against multiple inclusion */
+#define CKCXLA_H
+
+#ifndef KANJI /* Systems supporting Kanji */
+#ifdef OS2
+#define KANJI
+#endif /* OS2 */
+#endif /* KANJI */
+
+#ifdef NOKANJI /* Except if NOKANJI is defined. */
+#ifdef KANJI
+#undef KANJI
+#endif /* KANJI */
+#endif /* NOKANJI */
+
+#ifndef NOUNICODE
+#ifndef UNICODE /* Unicode support */
+#ifdef OS2ORUNIX /* Only for K95, UNIX, VMS,... */
+#define UNICODE
+#else
+#ifdef VMS
+#define UNICODE
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#endif /* UNICODE */
+#endif /* NOUNICODE */
+
+#define XLA_NONE 0 /* Translation types - none */
+#define XLA_BYTE 1 /* Byte-for-byte */
+#define XLA_JAPAN 2 /* Japanese */
+#define XLA_UNICODE 3 /* Unicode */
+
+#ifndef UNIORKANJI /* Unicode OR Kanji */
+#ifdef UNICODE /* i.e. some support for */
+#define UNIORKANJI /* multibyte character sets */
+#endif /* UNICODE */
+#ifdef KANJI
+#define UNIORKANJI
+#endif /* KANJI */
+#endif /* UNIORKANJI */
+/*
+ Disable all support for all classes of character sets
+ if NOCSETS is defined.
+*/
+#ifdef NOCSETS
+
+#ifdef CKOUNI
+#undef CKOUNI
+#endif /* CKOUNI */
+#ifdef KANJI
+#undef KANJI
+#endif /* KANJI */
+#ifdef CYRILLIC
+#undef CYRILLIC
+#endif /* CYRILLIC */
+#ifdef LATIN2
+#undef LATIN2
+#endif /* LATIN2 */
+#ifdef HEBREW
+#undef HEBREW
+#endif /* HEBREW */
+#ifdef UNICODE
+#undef UNICODE
+#endif /* UNICODE */
+#ifndef NOUNICODE
+#define NOUNICODE
+#endif /* NOUNICODE */
+
+#else /* Not NOCSETS - Rest of this file... */
+
+#ifdef NOUNICODE /* Unicode */
+#ifdef UNICODE
+#undef UNICODE
+#endif /* UNICODE */
+#endif /* NOUNICODE */
+
+#ifdef UNICODE
+#ifdef OS2
+#ifndef CKOUNI
+#define CKOUNI /* Special Unicode features for K95 */
+#endif /* CKOUNI */
+#endif /* OS2 */
+#endif /* UNICODE */
+
+#ifndef OS2
+#ifdef CKOUNI
+#undef CKOUNI
+#endif /* CKOUNI */
+#endif /* OS2 */
+
+#ifndef NOLATIN2 /* If they didn't say "no Latin-2" */
+#ifndef LATIN2 /* Then if LATIN2 isn't already */
+#define LATIN2 /* defined, define it. */
+#endif /* LATIN2 */
+#endif /* NOLATIN2 */
+
+#ifdef NOCYRILLIC /* (spelling variant...) */
+#ifndef NOCYRIL
+#define NOCYRIL
+#endif /* NOCYRIL */
+#endif /* NOCYRILLIC */
+
+#ifndef NOCYRIL /* If they didn't say "no Cyrillic" */
+#ifndef CYRILLIC /* Then if CYRILLIC isn't already */
+#define CYRILLIC /* defined, define it. */
+#endif /* CYRILLIC */
+#endif /* NOCYRIL */
+
+#ifndef NOHEBREW /* If they didn't say "no Hebrew" */
+#ifndef HEBREW /* Then if HEBREW isn't already */
+#define HEBREW /* defined, define it. */
+#endif /* HEBREW */
+#endif /* NOHEBREW */
+
+#ifndef NOGREEK /* If not no Greek */
+#ifndef GREEK /* then if GREEK isn't already */
+#define GREEK /* defined, define it. */
+#endif /* GREEK */
+#endif /* NOGREEK */
+
+#ifndef NOKANJI /* If not no Kanji */
+#ifndef KANJI /* then if KANJI isn't already */
+#define KANJI /* defined, define it. */
+#endif /* KANJI */
+#endif /* NOKANJI */
+
+/* File ckcxla.h -- Character-set-related definitions, system independent */
+
+/* Codes for Kermit Transfer Syntax Level (obsolete) */
+
+#define TS_L0 0 /* Level 0 (Transparent) */
+#define TS_L1 1 /* Level 1 (one standard character set) */
+#define TS_L2 2 /* Level 2 (multiple character sets in same file) */
+
+#define UNK 63 /* Symbol to use for unknown character (63 = ?) */
+
+/*
+ Codes for the base alphabet of a given character set.
+ These are assigned in roughly ISO 8859 order.
+ (Each is assumed to include ASCII/Roman.)
+*/
+#define AL_UNIV 0 /* Universal (like ISO 10646) */
+#define AL_ROMAN 1 /* Roman (Latin) alphabet */
+#define AL_CYRIL 2 /* Cyrillic alphabet */
+#define AL_ARABIC 3 /* Arabic */
+#define AL_GREEK 4 /* Greek */
+#define AL_HEBREW 5 /* Hebrew */
+#define AL_KANA 6 /* Japanese Katakana */
+#define AL_JAPAN 7 /* Japanese Katakana+Kanji ideograms */
+#define AL_HAN 8 /* Chinese/Japanese/Korean ideograms */
+#define AL_INDIA 9 /* Indian scripts (ISCII) */
+#define AL_VIET 10 /* Vietnamese (VISCII) */
+ /* Add more here... */
+#define AL_UNK 999 /* Unknown (transparent) */
+
+/* Codes for languages */
+/*
+ NOTE: It would perhaps be better to use ISO 639-1988 2-letter "Codes for
+ Representation of Names of Languages" here, shown in the comments below.
+*/
+#define L_ASCII 0 /* EN ASCII, English */
+#define L_USASCII 0 /* EN ASCII, English */
+#define L_DUTCH 1 /* NL Dutch */
+#define L_FINNISH 2 /* FI Finnish */
+#define L_FRENCH 3 /* FR French */
+#define L_GERMAN 4 /* DE German */
+#define L_HUNGARIAN 5 /* HU Hungarian */
+#define L_ITALIAN 6 /* IT Italian */
+#define L_NORWEGIAN 7 /* NO Norwegian */
+#define L_PORTUGUESE 8 /* PT Portuguese */
+#define L_SPANISH 9 /* ES Spanish */
+#define L_SWEDISH 10 /* SV Swedish */
+#define L_SWISS 11 /* RM Swiss (Rhaeto-Romance) */
+#define L_DANISH 12 /* DA Danish */
+#define L_ICELANDIC 13 /* IS Icelandic */
+#define L_RUSSIAN 14 /* RU Russian */
+#define L_JAPANESE 15 /* JA Japanese */
+#define L_HEBREW 16 /* IW Hebrew */
+#define L_GREEK 17 /* Greek */
+
+#define MAXLANG 17 /* Number of languages */
+
+/*
+ File character-sets are defined in the system-specific ck?xla.h file,
+ except for the following ones, which must be available to all versions:
+*/
+#define FC_TRANSP 254 /* Transparent */
+#define FC_UNDEF 255 /* Undefined */
+/*
+ Designators for Kermit's transfer character sets. These are all standard
+ sets, or based on them. Symbols must be unique in the first 8 characters,
+ because some C preprocessors have this limit.
+*/
+/* LIST1 */
+#define TC_TRANSP 0 /* Transparent, no character translation */
+#define TC_USASCII 1 /* ISO 646 IRV / US 7-bit ASCII */
+#define TC_1LATIN 2 /* ISO 8859-1, Latin Alphabet 1 */
+#define TC_2LATIN 3 /* ISO 8859-2, Latin Alphabet 2 */
+#define TC_CYRILL 4 /* ISO 8859-5, Latin/Cyrillic */
+#define TC_JEUC 5 /* Japanese EUC = JIS 0201+0202+0208 */
+#define TC_HEBREW 6 /* ISO 8859-8, Latin/Hebrew */
+#define TC_GREEK 7 /* ISO 8859-7, Latin/Greek */
+#define TC_9LATIN 8 /* ISO 8859-15 Latin Alphabet 9 (with Euro) */
+#define TC_UCS2 9 /* ISO 10646 / Unicode UCS-2 */
+#define TC_UTF8 10 /* ISO 10646 / Unicode UTF-8 */
+
+#define MAXTCSETS 10 /* Highest Transfer Character Set Number */
+
+#ifdef COMMENT
+/*
+ Not used and probably won't be due to ISO-10646 / Unicode.
+*/
+#define TC_3LATIN 11 /* ISO 8859-3, Latin-3 */
+#define TC_4LATIN 12 /* ISO 8859-4, Latin-4 */
+#define TC_5LATIN 13 /* ISO 8859-9, Latin-5 */
+#define TC_ARABIC 14 /* ISO-8859-6, Latin/Arabic */
+#define TC_JIS208 15 /* Japanese JIS X 0208 multibyte set */
+#define TC_CHINES 16 /* Chinese Standard GB 2312-80 */
+#define TC_KOREAN 17 /* Korean KS C 5601-1987 */
+#define TC_ISCII 18 /* Indian standard code for ii... */
+#define TC_VSCII 19 /* Vietnam standard code for ii... */
+/* etc... */
+#endif /* COMMENT */
+
+/* Structure for character-set information */
+
+struct csinfo {
+ char *name; /* Descriptive name of character set */
+ int size; /* Size (e.g. 128, 256, 16384) */
+ int code; /* Like TC_1LATIN, etc. */
+ char *designator; /* Designator, like I2/100 = Latin-1 */
+ int alphabet; /* Base alphabet */
+ char *keyword; /* Keyword for this character-set */
+};
+
+/* Structure for language information */
+
+struct langinfo {
+ int id; /* Language ID code (L_whatever) */
+ int fc; /* File character set to use */
+ int tc; /* Transfer character set to use */
+ char *description; /* Description of language */
+};
+
+/* Now take in the system-specific definitions */
+
+#ifdef UNIX
+#include "ckuxla.h"
+#endif /* UNIX */
+
+#ifdef OSK /* OS-9 */
+#include "ckuxla.h"
+#endif /* OS-9 */
+
+#ifdef VMS /* VAX/VMS */
+#include "ckuxla.h"
+#endif /* VMS */
+
+#ifdef GEMDOS /* Atari ST */
+#include "ckuxla.h"
+#endif /* GEMDOS */
+
+#ifdef MAC /* Macintosh */
+#include "ckmxla.h"
+#endif /* MAC */
+
+#ifdef OS2 /* OS/2 */
+#include "ckuxla.h" /* Uses big UNIX version */
+#endif /* OS2 */
+
+#ifdef AMIGA /* Commodore Amiga */
+#include "ckuxla.h"
+#endif /* AMIGA */
+
+#ifdef datageneral /* Data General MV AOS/VS */
+#include "ckuxla.h"
+#endif /* datageneral */
+
+#ifdef STRATUS /* Stratus Computer, Inc. VOS */
+#include "ckuxla.h"
+#endif /* STRATUS */
+
+#ifdef UNICODE
+#include "ckcuni.h" /* Unicode */
+#endif /* UNICODE */
+
+#ifdef KANJI
+#define UNKSJIS 0x817f
+_PROTOTYP(USHORT eu_to_sj, (USHORT) ); /* EUC-JP to Shift-JIS */
+_PROTOTYP(USHORT sj_to_eu, (USHORT) ); /* Shift-JIS to EUC-JP */
+_PROTOTYP( int xkanjf, (void) );
+_PROTOTYP( int xkanji, (int, int (*)(char)) );
+_PROTOTYP( int xkanjz, (int (*)(char) ) );
+_PROTOTYP( int zkanjf, (void) );
+_PROTOTYP( int zkanji, (int (*)(void)) ); /* Kanji function prototypes */
+_PROTOTYP( int zkanjz, (void) );
+_PROTOTYP(VOID j7init, ( void ) ); /* Initialize JIS-7 parser */
+_PROTOTYP(int getj7, ( void ) ); /* Get next JIS-7 character */
+#endif /* KANJI */
+
+#ifndef MAC
+#ifndef NOLOCAL
+_PROTOTYP( int cs_size, (int) );
+_PROTOTYP( int cs_is_std, (int) );
+_PROTOTYP( int cs_is_nrc, (int) );
+_PROTOTYP( VOID setremcharset, (int, int) );
+_PROTOTYP( VOID setlclcharset, (int) );
+#endif /* NOLOCAL */
+#endif /* MAC */
+
+_PROTOTYP(VOID setxlatype, (int, int));
+
+#endif /* NOCSETS */
+#endif /* CKCXLA_H */
+
+/* End of ckcxla.h */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckermit.ini b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit.ini
new file mode 100644
index 0000000..b30f389
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit.ini
@@ -0,0 +1,8 @@
+COMMENT - Standard C-Kermit initialization file
+;
+echo
+echo The very long standard initialization file that was distributed
+echo with C-Kermit 6, 7, and 8 is no longer recommended as "standard",
+echo since its features were little used. It is still available in
+echo the C-Kermit distribution as ockermit.ini.
+echo
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckermit70.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit70.txt
new file mode 100644
index 0000000..a796cfd
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit70.txt
@@ -0,0 +1,17690 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+Supplement to [11]Using C-Kermit , 2nd Edition
+
+For C-Kermit 7.0
+
+As of C-Kermit version: 7.0.196
+This file created: 8 February 2000
+This file last updated:
+Mon Aug 8 10:39:18 2011
+
+
+Authors: Frank da Cruz and Christine M. Gianone
+Address: The Kermit Project
+ Columbia University
+ 612 West 115th Street
+ New York NY 10025-7799
+ USA
+Fax: +1 (212) 662-6442
+E-Mail: [12]kermit-support@columbia.edu
+Web: [13]http://www.columbia.edu/kermit/
+Or: [14]http://www.kermit-project.org/
+Or: [15]http://www.columbia.nyc.ny.us/kermit/
+
+NOTICES
+
+ This document:
+ Copyright � 1997, 2000, Frank da Cruz and Christine M. Gianone.
+ All rights reserved.
+
+ Kermit 95:
+ Copyright � 1995, 2000, Trustees of Columbia University in the
+ City of New York. All rights reserved.
+
+ C-Kermit:
+ Copyright � 1985, 2000,
+ Trustees of Columbia University in the City of New York. All
+ rights reserved. See the C-Kermit [16]COPYING.TXT file or the
+ copyright text in the [17]ckcmai.c module for disclaimer and
+ permissions.
+
+ When Kerberos(TM) and/or SRP(TM) (Secure Remote Password) and/or SSL
+ protocol are included:
+ Portions Copyright � 1990, Massachusetts Institute of
+ Technology.
+ Portions Copyright � 1991, 1993 Regents of the University of
+ California.
+ Portions Copyright � 1991, 1992, 1993, 1994, 1995 by AT&T.
+ Portions Copyright � 1997, Stanford University.
+ Portions Copyright � 1995-1997, Eric Young <eay@cryptosoft.com>.
+
+ For the full text of the third-party copyright notices, see
+ [18]Appendix V.
+
+WHAT IS IN THIS FILE
+
+ This file lists changes made to C-Kermit since the second edition of
+ the book [19]Using C-Kermit was published and C-Kermit 6.0 was released
+ in November 1996. Use this file as a supplement to the second edition
+ of Using C-Kermit until the third edition is published some time in
+ 2000. If the "most recent update" shown above is long ago, contact
+ Columbia University to see if there is a newer release.
+
+ For further information, also see the [20]CKCBWR.TXT ("C-Kermit
+ beware") file for hints, tips, tricks, restrictions, frequently asked
+ questions, etc, plus the system-specific "beware file", e.g.
+ [21]CKUBWR.TXT for UNIX, [22]CKVBWR.TXT for VMS, etc, and also any
+ system-specific update files such as KERMIT95.HTM for Kermit 95 (in the
+ DOCS\MANUAL\ subdirectory of your K95 directory).
+
+ This Web-based copy of the C-Kermit 7.0 update notes supersedes the
+ plain-text CKERMIT2.TXT file. All changes after 19 January 2000
+ appear only here in the Web version. If you need an up-to-date
+ plain-text copy, use your Web browser to save this page as plain
+ text.
+
+ABOUT FILENAMES
+
+ In this document, filenames are generally shown in uppercase, but on
+ file systems with case-sensitive names such as UNIX, OS-9, and AOS/VS,
+ lowercase names are used: [23]ckubwr.txt, [24]ckermit70.txt, etc.
+
+ADDITIONAL FILES
+
+ Several other files accompany this new Kermit release:
+
+ SECURITY.TXT
+ Discussion of Kermit's new authentication and encryption
+ features:
+
+ + [25]Plain-text version
+ + [26]HTML (hypertext) version
+
+ IKSD.TXT
+ How to install and manage an Internet Kermit Service Daemon.
+
+ + [27]Plain-text version
+ + [28]HTML (hypertext) version
+
+ Also see [29]cuiksd.htm for instructions for use.
+
+ TELNET.TXT
+ A thorough presentation of Kermit's new advanced Telnet features
+ and controls.
+
+ + [30]Plain-text version
+ + [31]HTML (hypertext) version
+
+THE NEW C-KERMIT LICENSE
+
+ The C-Kermit license was rewritten for version 7.0 to grant automatic
+ permission to packagers of free operating-system distributions to
+ include C-Kermit 7.0. Examples include Linux (GNU/Linux), FreeBSD,
+ NetBSD, etc. The new license is in the [32]COPYING.TXT file, and is
+ also displayed by C-Kermit itself when you give the VERSION or
+ COPYRIGHT command. The new C-Kermit license does not apply to
+ [33]Kermit 95.
+
+ACKNOWLEDGMENTS
+
+ Thanks to Jeff Altman, who joined the Kermit Project in 1995, for much
+ of what you see in C-Kermit 7.0, especially in the networking and
+ security areas, and his key role in designing and implementing the
+ Internet Kermit Service Daemon. And special thanks to Lucas Hart for
+ lots of help with the VMS version; to Peter Eichhorn for continuous
+ testing on the full range of HP-UX versions and for a consolidated set
+ of HP-UX makefile targets; and to Colin Allen, Mark Allen, Roger Allen,
+ Ric Anderson, William Bader, Mitch Baker, Mitchell Bass, Nelson Beebe,
+ Gerry Belanger, Jeff Bernsten, Mark Berryman, John Bigg, Volker
+ Borchert, Jonathan Boswell, Tim Boyer, Frederick Bruckman, Kenneth
+ Cochran, Jared Crapo, Bill Delaney, Igor Sobrado Delgado, Clarence
+ Dold, Joe Doupnik, John Dunlap, Max Evarts, Patrick French, Carl
+ Friedberg, Carl Friend, Hirofumi Fujii, Andrew Gabriel, Gabe Garza,
+ Boyd Gerber, David Gerber, George Gilmer, Hunter Goatley, DJ Hagberg,
+ Kevin Handy, Andy Harper, Randolph Herber, Sven Holstr�m, Michal
+ Jaegermann, Graham Jenkins, Dick Jones, Terry Kennedy, Robert D Keys,
+ Nick Kisseberth, Igor Kovalenko, David Lane, Adam Laurie, Jeff
+ Liebermann, Eric Lonvick, Hoi Wan Louis, Arthur Marsh, Gregorie Martin,
+ Peter Mauzey, Dragan Milicic, Todd Miller, Christian Mondrup, Daniel
+ Morato, Dat Nguyen, Herb Peyerl, Jean-Pierre Radley, Steve Rance,
+ Stephen Riehm, Nigel Roles, Larry Rosenman, Jay S Rouman, David
+ Sanderson, John Santos, Michael Schmitz, Steven Schultz, Bob Shair,
+ Richard Shuford, Fred Smith, Michael Sokolov, Jim Spath, Peter Szell,
+ Ted T'so, Brian Tillman, Linus Torvalds, Patrick Volkerding, Martin
+ Vorl�nder, Steve Walton, Ken Weaverling, John Weekley, Martin Whitaker,
+ Jim Whitby, Matt Willman, Joellen Windsor, Farrell Woods, and many
+ others for binaries, hosting, reviews, suggestions, advice, bug
+ reports, and all the rest over the 3+ year C-Kermit 7.0 development
+ cycle. Thanks to Russ Nelson and the board of the Open Software
+ Initiative ([34]http://www.opensource.org) for their cooperation in
+ developing the new C-Kermit license and to the proprietors of those
+ free UNIX distributions that have incorporated C-Kermit 7.0 for their
+ cooperation and support, especially FreeBSD's J�rg Wunsch.
+
+NOTE TO KERMIT 95 USERS
+
+ Kermit 95 and C-Kermit share the same command and scripting language,
+ the same Kermit file-transfer protocol implementation, and much else
+ besides.
+
+ Like the book [35]Using C-Kermit, this file concentrates on the aspects
+ of C-Kermit that are common to all versions: UNIX, VMS, Windows, OS/2,
+ VOS, AOS/VS, etc. Please refer to your Kermit 95 documentation for
+ information that is specific to Kermit 95.
+
+ C-Kermit 7.0 corresponds to Kermit 95 1.1.19.
+
+C-KERMIT VERSIONS AND VERSION NUMBERS
+
+ "C-Kermit" refers to all the many programs that are compiled in whole
+ or in part from common C-language source code, comprising:
+
+ * A Kermit file transfer protocol module
+ * A command parser and script execution module
+ * A modem-dialing module
+ * A network support module
+ * A character-set translation module.
+
+ and several others. These "system-independent" modules are combined
+ with system-dependent modules for each platform to provide the required
+ input/output functions, and also in some cases overlaid with an
+ alternative user interface, such as Macintosh Kermit's point-and-click
+ interface, and in some cases also a terminal emulator, as Kermit 95.
+
+ The C-Kermit version number started as 1.0, ... 3.0, 4.0, 4.1 and then
+ (because of confusion at the time with Berkeley UNIX 4.2), 4B, 4C, and
+ so on, with the specific edit number in parentheses, for example
+ 4E(072) or 5A(188). This scheme was used through 5A(191), but now we
+ have gone back to the traditional numbering scheme with decimal points:
+ major.minor.edit; for example 7.0.196. Internal version numbers (the
+ \v(version) variable), however, are compatible in C-Kermit 5A upwards.
+
+ Meanwhile, C-Kermit derivatives for some platforms (Windows, Macintosh)
+ might go through several releases while C-Kermit itself remains the
+ same. These versions have their own platform-specific version numbers,
+ such as Kermit 95 1.1.1, 1.1.2, and so on.
+
+ C-Kermit Version History:
+
+ 1.0 1981-1982 Command-line only, 4.2 BSD UNIX only
+ 2.0 (*) (who remembers...)
+ 3.0 May 1984 Command-line only, supports several platforms
+ 4.0-4.1 Feb-Apr 1985 (*) First interactive and modular version
+ 4C(050) May 1985
+ 4D(060) April 1986
+ 4E(066) August 1987 Long packets
+ 4E(068) January 1988
+ 4E(072) January 1989
+ 4F(095) August 1989 (*) Attribute packets
+ 5A(188) November 1992 Scripting, TCP/IP, sliding windows (1)
+ 5A(189) September 1993 Control-char unprefixing
+ 5A(190) October 1994 Recovery
+ 5A(191) April 1995 OS/2 only
+ 6.0.192 September 1996 Intelligent dialing, autodownload, lots more (2)
+ 6.1.193 1997-98 (*) Development only
+ 6.1.194 June 1998 K95 only - switches, directory recursion, more
+ 7.0.195 August 1999 IKSD + more (CU only as K95 1.1.18-CU)
+ 7.0.196 1 January 2000 Unicode, lots more
+
+ (*) Never formally released (4.0 was a total rewrite)
+ (1) Using C-Kermit, 1st Edition
+ (2) Using C-Kermit, 2nd Edition
+
+CONTENTS
+
+ I. [36]C-KERMIT DOCUMENTATION
+
+ II. [37]NEW FEATURES
+
+ (0) [38]INCOMPATIBILITIES WITH PREVIOUS RELEASES
+ (1) [39]PROGRAM AND FILE MANAGEMENT AND COMMANDS
+ 1.0. [40]Bug fixes
+ 1.1. [41]Command Continuation
+ 1.2. [42]Editor Interface
+ 1.3. [43]Web Browser and FTP Interface
+ 1.4. [44]Command Editing
+ 1.5. [45]Command Switches
+ 1.5.1. [46]General Switch Syntax
+ 1.5.2. [47]Order and Effect of Switches
+ 1.5.3. [48]Distinguishing Switches from Other Fields
+ 1.5.4. [49]Standard File Selection Switches
+ 1.5.5. [50]Setting Preferences for Different Commands
+ 1.6. [51]Dates and Times
+ 1.7. [52]Partial Completion of Keywords
+ 1.8. [53]Command Recall
+ 1.9. [54]EXIT Messages
+ 1.10. [55]Managing Keyboard Interruptions
+ 1.11. [56]Taming the Wild Backslash -- Part Deux
+ 1.11.1. [57]Background
+ 1.11.2. [58]Kermit's Quoting Rules
+ 1.11.3. [59]Passing DOS Filenames from Kermit to Shell Commands
+ 1.11.4. [60]Using Variables to Hold DOS Filenames
+ 1.11.5. [61]Passing DOS Filenames as Parameters to Macros
+ 1.11.6. [62]Passing DOS File Names from Macro Parameters to the D
+OS Shell
+ 1.11.7. [63]Passing DOS Filenames to Kermit from the Shell
+ 1.12. [64]Debugging
+ 1.13. [65]Logs
+ 1.14. [66]Automatic File-Transfer Packet Recognition at the Command Pro
+mpt
+ 1.15. [67]The TYPE Command
+ 1.16. [68]The RESET Command
+ 1.17. [69]The COPY and RENAME Commands
+ 1.18. [70]The MANUAL Command
+ 1.19. [71]String and Filename Matching Patterns
+ 1.20. [72]Multiple Commands on One Line
+ 1.21. [73]What Do I Have?
+ 1.22. [74]Generalized File Input and Output
+ 1.22.1. [75]Why Another I/O System?
+ 1.22.2. [76]The FILE Command
+ 1.22.3. [77]FILE Command Examples
+ 1.22.4. [78]Channel Numbers
+ 1.22.5. [79]FILE Command Error Codes
+ 1.22.6. [80]File I/O Variables
+ 1.22.7. [81]File I/O Functions
+ 1.22.8. [82]File I/O Function Examples
+ 1.23. [83]The EXEC Command
+ 1.24. [84]Getting Keyword Lists with '?'
+ (2) [85]MAKING AND USING CONNECTIONS
+ 2.0. [86]SET LINE and SET HOST Command Switches
+ 2.1. [87]Dialing
+ 2.1.1. [88]The Dial Result Message
+ 2.1.2. [89]Long-Distance Dialing Changes
+ 2.1.3. [90]Forcing Long-Distance Dialing
+ 2.1.4. [91]Exchange-Specific Dialing Decisions
+ 2.1.5. [92]Cautions about Cheapest-First Dialing
+ 2.1.6. [93]Blind Dialing (Dialing with No Dialtone)
+ 2.1.7. [94]Trimming the Dialing Dialog
+ 2.1.8. [95]Controlling the Dialing Speed
+ 2.1.9. [96]Pretesting Phone Number Conversions
+ 2.1.10. [97]Greater Control over Partial Dialing
+ 2.1.11. [98]New DIAL-related Variables and Functions
+ 2.1.12. [99]Increased Flexibility of PBX Dialing
+ 2.1.13. [100]The DIAL macro - Last-Minute Phone Number Conversions
+ 2.1.14. [101]Automatic Tone/Pulse Dialing Selection
+ 2.1.15. [102]Dial-Modifier Variables
+ 2.1.16. [103]Giving Multiple Numbers to the DIAL Command
+ 2.2. [104]Modems
+ 2.2.1. [105]New Modem Types
+ 2.2.2. [106]New Modem Controls
+ 2.3. [107]TELNET and RLOGIN
+ 2.3.0. [108]Bug Fixes
+ 2.3.1. [109]Telnet Binary Mode Bug Adjustments
+ 2.3.2. [110]VMS UCX Telnet Port Bug Adjustment
+ 2.3.3. [111]Telnet New Environment Option
+ 2.3.4. [112]Telnet Location Option
+ 2.3.5. [113]Connecting to Raw TCP Sockets
+ 2.3.6. [114]Incoming TCP Connections
+ 2.4. [115]The EIGHTBIT Command
+ 2.5. [116]The Services Directory
+ 2.6. [117]Closing Connections
+ 2.7. [118]Using C-Kermit with External Communication Programs
+ 2.7.0. [119]C-Kermit over tn3270 and tn5250
+ 2.7.1. [120]C-Kermit over Telnet
+ 2.7.2. [121]C-Kermit over Rlogin
+ 2.7.3. [122]C-Kermit over Serial Communication Programs
+ 2.7.4. [123]C-Kermit over Secure Network Clients
+ 2.7.4.1. [124]SSH
+ 2.7.4.2. [125]SSL
+ 2.7.4.3. [126]SRP
+ 2.7.4.4. [127]SOCKS
+ 2.7.4.5. [128]Kerberos and SRP
+ 2.8. [129]Scripting Local Programs
+ 2.9. [130]X.25 Networking
+ 2.9.1. [131]IBM AIXLink/X.25 Network Provider Interface for AIX
+ 2.9.2. [132]HP-UX X.25
+ 2.10. [133]Additional Serial Port Controls
+ 2.11. [134]Getting Access to the Dialout Device
+ 2.12. [135]The Connection Log
+ 2.13. [136]Automatic Connection-Specific Flow Control Selection
+ 2.14. [137]Trapping Connection Establishment and Loss
+ 2.15. [138]Contacting Web Servers with the HTTP Command
+ (3) [139]TERMINAL CONNECTION
+ 3.1. [140]CONNECT Command Switches
+ 3.2. [141]Triggers
+ 3.3. [142]Transparent Printing
+ 3.4. [143]Binary and Text Session Logs
+ (4) [144]FILE TRANSFER AND MANAGEMENT
+ 4.0. [145]Bug Fixes, Minor Changes, and Clarifications
+ 4.1. [146]File-Transfer Filename Templates
+ 4.1.1. [147]Templates in the As-Name
+ 4.1.2. [148]Templates on the Command Line
+ 4.1.3. [149]Post-Transfer Renaming
+ 4.2. [150]File-Transfer Pipes and Filters
+ 4.2.1. [151]Introduction
+ 4.2.1.1. [152]Terminology
+ 4.2.1.2. [153]Notation
+ 4.2.1.3. [154]Security
+ 4.2.2. [155]Commands for Transferring from and to Pipes
+ 4.2.2.1. [156]Sending from a Command
+ 4.2.2.2. [157]Receiving to a Command
+ 4.2.3. [158]Using File-Transfer Filters
+ 4.2.3.1. [159]The SEND Filter
+ 4.2.3.2. [160]The RECEIVE Filter
+ 4.2.4. [161]Implicit Use of Pipes
+ 4.2.5. [162]Success and Failure of Piped Commands
+ 4.2.6. [163]Cautions about Using Pipes to Transfer Directory Trees
+ 4.2.7. [164]Pipes and Encryption
+ 4.2.8. [165]Commands and Functions Related to Pipes
+ 4.2.8.1. [166]The OPEN !READ and OPEN !WRITE Commands
+ 4.2.8.2. [167]The REDIRECT Command
+ 4.2.8.3. [168]Receiving Mail and Print Jobs
+ 4.2.8.4. [169]Pipe-Related Functions
+ 4.3. [170]Automatic Per-File Text/Binary Mode Switching
+ 4.3.1. [171]Exceptions
+ 4.3.2. [172]Overview
+ 4.3.3. [173]Commands
+ 4.3.4. [174]Examples
+ 4.4. [175]File Permissions
+ 4.4.1. [176]When ATTRIBUTES PROTECTION is OFF
+ 4.4.1.1. [177]Unix
+ 4.4.1.2. [178]VMS
+ 4.4.2. [179]When ATTRIBUTES PROTECTION is ON
+ 4.4.2.1. [180]System-Specific Permissions
+ 4.4.2.1.1. [181]UNIX
+ 4.4.2.1.2. [182]VMS
+ 4.4.2.2. [183]System-Independent Permissions
+ 4.5. [184]File Management Commands
+ 4.5.1. [185]The DIRECTORY Command
+ 4.5.2. [186]The CD and BACK Commands
+ 4.5.2.1. [187]Parsing Improvements
+ 4.5.2.2. [188]The CDPATH
+ 4.5.3. [189]Creating and Removing Directories
+ 4.5.4. [190]The DELETE and PURGE Commands
+ 4.6. [191]Starting the Remote Kermit Server Automatically
+ 4.7. [192]File-Transfer Command Switches
+ 4.7.1. [193]SEND Command Switches
+ 4.7.2. [194]GET Command Switches
+ 4.7.3. [195]RECEIVE Command Switches
+ 4.8. [196]Minor Kermit Protocol Improvements
+ 4.8.1. [197]Multiple Attribute Packets
+ 4.8.2. [198]Very Short Packets
+ 4.9. [199]Wildcard / File Group Expansion
+ 4.9.1. [200]In UNIX C-Kermit
+ 4.9.2. [201]In Kermit 95
+ 4.9.3. [202]In VMS, AOS/VS, OS-9, VOS, etc.
+ 4.10. [203]Additional Pathname Controls
+ 4.11. [204]Recursive SEND and GET: Transferring Directory Trees
+ 4.11.1. [205]Command-Line Options
+ 4.11.2. [206]The SEND /RECURSIVE Command
+ 4.11.3. [207]The GET /RECURSIVE Command
+ 4.11.4. [208]New and Changed File Functions
+ 4.11.5. [209]Moving Directory Trees Between Like Systems
+ 4.11.6. [210]Moving Directory Trees Between Unlike Systems
+ 4.12. [211]Where Did My File Go?
+ 4.13. [212]File Output Buffer Control
+ 4.14. [213]Improved Responsiveness
+ 4.15. [214]Doubling and Ignoring Characters for Transparency
+ 4.16. [215]New File-Transfer Display Formats
+ 4.17. [216]New Transaction Log Formats
+ 4.17.1. [217]The BRIEF Format
+ 4.17.2. [218]The FTP Format
+ 4.18. [219]Unprefixing NUL
+ 4.19. [220]Clear-Channel Protocol
+ 4.20. [221]Streaming Protocol
+ 4.20.1. [222]Commands for Streaming
+ 4.20.2. [223]Examples of Streaming
+ 4.20.2.1. [224]Streaming on Socket-to-Socket Connections
+ 4.20.2.2. [225]Streaming on Telnet Connections
+ 4.20.2.3. [226]Streaming with Limited Packet Length
+ 4.20.2.4. [227]Streaming on Dialup Connections
+ 4.20.2.5. [228]Streaming on X.25 Connections
+ 4.20.3. [229]Streaming - Preliminary Conclusions
+ 4.21. [230]The TRANSMIT Command
+ 4.22. [231]Coping with Faulty Kermit Implementations
+ 4.22.1. [232]Failure to Accept Modern Negotiation Strings
+ 4.22.2. [233]Failure to Negotiate 8th-bit Prefixing
+ 4.22.3. [234]Corrupt Files
+ 4.22.4. [235]Spurious Cancellations
+ 4.22.5. [236]Spurious Refusals
+ 4.22.6. [237]Failures during the Data Transfer Phase
+ 4.22.7. [238]Fractured Filenames
+ 4.22.8. [239]Bad File Dates
+ 4.23. [240]File Transfer Recovery
+ 4.24. [241]FILE COLLISION UPDATE Clarification
+ 4.25. [242]Autodownload Improvements
+ (5) [243]CLIENT/SERVER
+ 5.0. [244]Hints
+ 5.1. [245]New Command-Line Options
+ 5.2. [246]New Client Commands
+ 5.3. [247]New Server Capabilities
+ 5.3.1. [248]Creating and Removing Directories
+ 5.3.2. [249]Directory Listings
+ 5.4. [250]Syntax for Remote Filenames with Embedded Spaces
+ 5.5. [251]Automatic Orientation Messages upon Directory Change
+ 5.6. [252]New Server Controls
+ 5.7. [253]Timeouts during REMOTE HOST Command Execution
+ (6) [254]INTERNATIONAL CHARACTER SETS
+ 6.0. [255]ISO 8859-15 Latin Alphabet 9
+ 6.1. [256]The HP-Roman8 Character Set
+ 6.2. [257]Greek Character Sets
+ 6.3. [258]Additional Latin-2 Character Sets
+ 6.4. [259]Additional Cyrillic Character Sets
+ 6.5. [260]Automatic Character-Set Switching
+ 6.6. [261]Unicode
+ 6.6.1. [262]Overview of Unicode
+ 6.6.2. [263]UCS Byte Order
+ 6.6.2. [264]UCS Transformation Formats
+ 6.6.3. [265]Conformance Levels
+ 6.6.4. [266]Relationship of Unicode with Kermit's Other Character Sets
+ 6.6.5. [267]Kermit's Unicode Features
+ 6.6.5.1. [268]File Transfer
+ 6.6.5.2. [269]The TRANSLATE Command
+ 6.6.5.3. [270]Terminal Connection
+ 6.6.5.4. [271]The TRANSMIT Command
+ 6.6.5.5. [272]Summary of Kermit Unicode Commands
+ 6.7. [273]Client/Server Character-Set Switching
+ (7) [274]SCRIPT PROGRAMMING
+ 7.0. [275]Bug Fixes
+ 7.1. [276]The INPUT Command
+ 7.1.1. [277]INPUT Timeouts
+ 7.1.2. [278]New INPUT Controls
+ 7.1.3. [279]INPUT with Pattern Matching
+ 7.1.4. [280]The INPUT Match Result
+ 7.2. [281]New or Improved Built-In Variables
+ 7.3. [282]New or Improved Built-In Functions
+ 7.4. [283]New IF Conditions
+ 7.5. [284]Using More than Ten Macro Arguments
+ 7.6. [285]Clarification of Function Call Syntax
+ 7.7. [286]Autodownload during INPUT Command Execution
+ 7.8. [287]Built-in Help for Functions.
+ 7.9. [288]Variable Assignments
+ 7.9.1. [289]Assignment Operators
+ 7.9.2. [290]New Assignment Commands
+ 7.10. [291]Arrays
+ 7.10.1. [292]Array Initializers
+ 7.10.2. [293]Turning a String into an Array of Words
+ 7.10.3. [294]Arrays of Filenames
+ 7.10.4. [295]Automatic Arrays
+ 7.10.5. [296]Sorting Arrays
+ 7.10.6. [297]Displaying Arrays
+ 7.10.7. [298]Other Array Operations
+ 7.10.8. [299]Hints for Using Arrays
+ 7.10.9. [300]Do-It-Yourself Arrays
+ 7.10.10. [301]Associative Arrays
+ 7.11. [302]OUTPUT Command Improvements
+ 7.12. [303]Function and Variable Diagnostics
+ 7.13. [304]Return Value of Macros
+ 7.14. [305]The ASSERT, FAIL, and SUCCEED Commands.
+ 7.15. [306]Using Alarms
+ 7.16. [307]Passing Arguments to Command Files
+ 7.17. [308]Dialogs with Timed Responses
+ 7.18. [309]Increased Flexibility of SWITCH Case Labels
+ 7.19. "[310]Kerbang" Scripts
+ 7.20. [311]IF and XIF Statement Syntax
+ 7.20.1. [312]The IF/XIF Distinction
+ 7.20.2. [313]Boolean Expressions (The IF/WHILE Condition)
+ 7.21. [314]Screen Formatting and Cursor Control
+ 7.22. [315]Evaluating Arithmetic Expressions
+ 7.23. [316]Floating-Point Arithmetic
+ 7.24. [317]Tracing Script Execution
+ 7.25. [318]Compact Substring Notation
+ 7.26. [319]New WAIT Command Options
+ 7.26.1. [320]Waiting for Modem Signals
+ 7.26.2. [321]Waiting for File Events
+ 7.27. [322]Relaxed FOR and SWITCH Syntax
+ (8) [323]USING OTHER FILE TRANSFER PROTOCOLS
+ (9) [324]COMMAND-LINE OPTIONS
+ 9.0. [325]Extended-Format Command-Line Options
+ 9.1. [326]Command Line Personalities
+ 9.2. [327]Built-in Help for Command Line Options
+ 9.3. [328]New Command-Line Options
+ (10) [329]C-KERMIT AND G-KERMIT
+
+III. [330]APPENDICES
+
+III.1. [331]Character Set Tables
+III.1.1. [332]The Hewlett Packard Roman8 Character Set
+III.1.2. [333]Greek Character Sets
+III.1.2.1. [334]The ISO 8859-7 Latin / Greek Alphabet
+III.1.2.2. [335]The ELOT 927 Character Set
+III.1.2.3. [336]PC Code Page 869
+III.2. [337]Updated Country Codes
+
+IV. [338]ERRATA & CORRIGENDA: Corrections to "Using C-Kermit" 2nd Edition.
+V. [339]ADDITIONAL COPYRIGHT NOTICES
+
+I. C-KERMIT DOCUMENTATION
+
+ The user manual for C-Kermit is:
+
+ Frank da Cruz and Christine M. Gianone, [340]Using C-Kermit, Second
+ Edition, Digital Press / Butterworth-Heinemann, Woburn, MA, 1997,
+ 622 pages, ISBN 1-55558-164-1.
+
+ [341]CLICK HERE for reviews.
+
+ The present document is a supplement to Using C-Kermit 2nd Ed, not a
+ replacement for it.
+
+ US single-copy price: $52.95; quantity discounts available. Available
+ in bookstores or directly from Columbia University:
+
+ The Kermit Project
+ Columbia University
+ 612 West 115th Street
+ New York NY 10025-7799
+ USA
+ Telephone: +1 (212) 854-3703
+ Fax: +1 (212) 662-6442
+
+ Domestic and overseas orders accepted. Price: US $44.95 (US, Canada,
+ and Mexico). Shipping: $4.00 within the USA; $15.00 to all other
+ countries. Orders may be paid by MasterCard or Visa, or prepaid by
+ check in US dollars. Add $65 bank fee for checks not drawn on a US
+ bank. Do not include sales tax. Inquire about quantity discounts.
+
+ You can also order by phone from the publisher, Digital Press /
+ [342]Butterworth-Heinemann, with MasterCard, Visa, or American Express:
+
+ +1 800 366-2665 (Woburn, Massachusetts office for USA & Canada)
+ +44 1865 314627 (Oxford, England distribution centre for UK & Europe)
+ +61 03 9245 7111 (Melbourne, Vic, office for Australia & NZ)
+ +65 356-1968 (Singapore office for Asia)
+ +27 (31) 2683111 (Durban office for South Africa)
+
+ A [343]German-language edition of the First Edition is also available:
+
+ Frank da Cruz and Christine M. Gianone, C-Kermit - Einf�hrung und
+ Referenz, Verlag Heinz Heise, Hannover, Germany (1994). ISBN
+ 3-88229-023-4. Deutsch von Gisbert W. Selke. Price: DM 88,00. Verlag
+ Heinz Heise GmbH & Co. KG, Helstorfer Strasse 7, D-30625 Hannover.
+ Tel. +49 (05 11) 53 52-0, Fax. +49 (05 11) 53 52-1 29.
+
+ The [344]Kermit file transfer protocol is specified in:
+
+ Frank da Cruz, Kermit, A File Transfer Protocol, Digital Press,
+ Bedford, MA, 1987, 379 pages, ISBN 0-932376-88-6. US single-copy
+ price: $39.95. Availability as above.
+
+ News and articles about Kermit software and protocol are published
+ periodically in the journal, [345]Kermit News. Subscriptions are free;
+ contact Columbia University at the address above.
+
+ Online news about Kermit is published in the
+ [346]comp.protocols.kermit.announce and [347]comp.protocols.kermit.misc
+ newsgroups.
+
+II. NEW FEATURES
+
+ Support for the Bell Labs Plan 9 operating system was added to version
+ 6.0 too late to be mentioned in the book (although it does appear on
+ the cover).
+
+ Specific changes and additions are grouped together by major topic,
+ roughly corresponding to the chapters of [348]Using C-Kermit.
+
+0. INCOMPATIBILITIES WITH PREVIOUS RELEASES
+
+ 1. C-Kermit 7.0 uses FAST Kermit protocol settings by default. This
+ includes "unprefixing" of certain control characters. Because of
+ this, file transfers that worked with previous releases might not
+ work in the new release (but it is more likely that they will work,
+ and much faster). If a transfer fails, you'll get a
+ context-sensitive hint suggesting possible causes and cures.
+ Usually SET PREFIXING ALL does the trick.
+ 2. C-Kermit 7.0 transfers files in BINARY mode by default. To restore
+ the previous behavior, put SET FILE TYPE TEXT in your C-Kermit
+ initialization file.
+ 3. No matter whether FILE TYPE is BINARY or TEXT by default, C-Kermit
+ 7.0 now switches between text and binary mode automatically on a
+ per-file basis according to various criteria, including (a) which
+ kind of platform is on the other end of the connection (if known),
+ (b) the version of Kermit on the other end, and (c) the file's name
+ (see [349]Section 4, especially [350]4.3). To disable this
+ automatic switching and restore the earlier behavior, put SET
+ TRANSFER MODE MANUAL in your C-Kermit initialization file. To
+ disable automatic switching for a particular transfer, include a
+ /TEXT or /BINARY switch with your SEND or GET command.
+ 4. The RESEND and REGET commands automatically switch to binary mode;
+ previously if RESEND or REGET were attempted when FILE TYPE was
+ TEXT, these commands would fail immediately, with a message telling
+ you they work only when the FILE TYPE is BINARY. Now they simply do
+ this for you. See [351]Section 4.23 for additional (important)
+ information.
+ 5. SET PREFIXING CAUTIOUS and MINIMAL now both prefix linefeed (10 and
+ 138) in case rlogin, ssh, or cu are "in the middle", since
+ otherwise <LF>~ might appear in Kermit packets, and this would
+ cause rlogin, ssh, or cu to disconnect, suspend, escape back, or
+ otherwise wreck the file transfer. Xon and Xoff are now always
+ prefixed too, even when Xon/Xoff flow control is not in effect,
+ since unprefixing them has proven dangerous on TCP/IP connections.
+ 6. In UNIX, VMS, Windows, and OS/2, the DIRECTORY command is built
+ into C-Kermit itself rather than implemented by running an external
+ command or program. The built-in command might not behave the way
+ the platform-specific external one did, but many options are
+ available for customization. Of course the underlying
+ platform-specific command can still be accessed with "!", "@", or
+ "RUN" wherever the installation does not forbid. In UNIX, the "ls"
+ command can be accessed directly as "ls" in C-Kermit. See
+ [352]Section 4.5.1 for details.
+ 7. SEND ? prints a list of switches rather than a list of filenames.
+ If you want to see a list of filenames, use a (system-dependent)
+ construction such as SEND ./? (for UNIX, Windows, or OS/2), SEND
+ []? (VMS), etc. See [353]Sections 1.5 and [354]4.7.1.
+ 8. In UNIX, OS-9, and Kermit 95, the wildcard characters in previous
+ versions were * and ?. In C-Kermit 7.0 they are *, ?, [, ], {, and
+ }, with dash used inside []'s to denote ranges and comma used
+ inside {} to separate list elements. If you need to include any of
+ these characters literally in a filename, precede each one with
+ backslash (\). See [355]Section 4.9.
+ 9. SET QUIET { ON, OFF } is now on the command stack, just like SET
+ INPUT CASE, SET COUNT, SET MACRO ERROR, etc, as described on p.458
+ of [356]Using C-Kermit, 2nd Edition. This allows any macro or
+ command file to SET QUIET ON or OFF without worrying about saving
+ and restoring the global QUIET value. For example, this lets you
+ write a script that tries SET LINE on lots of devices until it
+ finds one free without spewing out loads of error messages, and
+ also without disturbing the global QUIET setting, whatever it was.
+ 10. Because of the new "." operator (which introduces assignments),
+ macros whose names begin with "." can not be invoked "by name".
+ However, they still can be invoked with DO.
+ 11. The syntax of the EVALUATE command has changed. See [357]Section
+ 7.9.2. To restore the previous syntax, use SET EVALUATE OLD.
+ 12. The \v(directory) variable now includes the trailing directory
+ separator; in previous releases it did not. This is to allow
+ constructions such as:
+ cd \v(dir)data.tmp
+
+ to work across platforms that might have different directory
+ notation, such as UNIX, Windows, and VMS.
+ 13. Prior to C-Kermit 7.0, the FLOW-CONTROL setting was global and
+ sticky. In C-Kermit 7.0, there is an array of default flow-control
+ values for each kind of connection, that are applied automatically
+ at SET LINE/PORT/HOST time. Thus a SET FLOW command given before
+ SET LINE/PORT/HOST is likely to be undone. Therefore SET FLOW can
+ be guaranteed to have the desired effect only if given after the
+ SET LINE/PORT/HOST command.
+ 14. Character-set translation works differently in the TRANSMIT command
+ when (a) the file character-set is not the same as the local end of
+ the terminal character-set, or (b) when the terminal character-set
+ is TRANSPARENT.
+
+1. PROGRAM AND FILE MANAGEMENT AND COMMANDS
+
+1.0. Bug Fixes
+
+ The following patches were issued to correct bugs in C-Kermit 6.0.
+ These are described in detail in the 6.0 PATCHES file. All of these
+ fixes have been incorporated in C-Kermit 6.1 (never released except as
+ K95 1.1.16-17) and 7.0.
+
+ 0001 All UNIX C-Kermit mishandles timestamps on files before 1970
+ 0002 Solaris 2.5++ Compilation error on Solaris 2.5 with Pro C
+ 0003 All VMS CKERMIT.INI Fix for VMS
+ 0004 VMS/VAX/UCX 2.0 C-Kermit 6.0 can't TELNET on VAX/VMS with UCX 2.0
+ 0005 All C-Kermit Might Send Packets Outside Window
+ 0006 All MOVE from SEND-LIST does not delete original files
+ 0007 Solaris 2.5++ Higher serial speeds on Solaris 2.5
+ 0008 All C-Kermit application file name can't contain spaces
+ 0009 AT&T 7300 UNIXPC setuid and hardware flow-control problems
+ 0010 Linux on Alpha Patch to make ckutio.c compile on Linux/Alpha
+ 0011 OS-9/68000 2.4 Patch to make ck9con.c compile on OS-9/68000 2.4
+ 0012 MW Coherent 4.2 Patches for successful build on Coherent 4.2
+ 0013 SINIX-Y 5.43 "delay" variable conflicts with <sys/clock.h>
+ 0014 VMS/VAX/CMU-IP Subject: Patches for VAX/VMS 5.x + CMU-IP
+ 0015 All XECHO doesn't flush its output
+ 0016 VMS CD and other directory operations might not work
+ 0017 Linux 1.2.x++ Use standard POSIX interface for high serial speeds
+ 0018 UNIX SET WILDCARD-EXPANSION SHELL dumps core
+ 0019 All Hayes V.34 modem init string problem
+ 0020 All READ command does not fail if file not open
+ 0021 All Problems with long function arguments
+ 0022 All Certain \function()s can misbehave
+ 0023 All X MOD 0 crashes program
+ 0024 All Internal bulletproofing for lower() function
+ 0025 OpenBSD Real OpenBSD support for C-Kermit 6.0
+ 0026 All Incorrect checks for macro/command-file nesting depth
+ 0027 All ANSWER doesn't automatically CONNECT
+ 0028 All Overzealous EXIT warning
+ 0029 All OUTPUT doesn't echo when DUPLEX is HALF
+ 0030 All Minor problems with REMOTE DIRECTORY/DELETE/etc
+ 0031 All CHECK command broken
+ 0032 All Problem with SET TRANSMIT ECHO
+ 0033 UNIX, VMS, etc HELP SET SERVER says too much
+ 0034 All READ and !READ too picky about line terminators
+ 0035 All END from inside SWITCH doesn't work
+ 0036 All Problem telnetting to multihomed hosts
+ 0037 All Redirection failures in REMOTE xxx > file
+
+ REDIRECT was missing in many UNIX C-Kermit implementations; in version
+ 7.0, it should be available in all of them.
+
+1.1. Command Continuation
+
+ Comments that start with ";" or "#" can no longer be continued. In:
+
+ ; this is a comment -
+ echo blah
+
+ the ECHO command will execute, rather than being taken as a
+ continuation of the preceding comment line. This allows easy
+ "commenting out" of commands from macro definitions.
+
+ However, the text of the COMMENT command can still be continued onto
+ subsequent lines:
+
+ comment this is a comment -
+ echo blah
+
+ As of version 6.0, backslash is no longer a valid continuation
+ character. Only hyphen should be used for command continuation. This is
+ to make it possible to issue commands like "cd a:\" on DOS-like
+ systems.
+
+ As of version 7.0:
+
+ * You can quote a final dash to prevent it from being a continuation
+ character:
+ echo foo\-
+
+ This prints "foo-". The command is not continued.
+ * You can enter commands such as:
+ echo foo - ; this is a comment
+
+ interactively and they are properly treated as continued commands.
+ Previously this worked only in command files.
+
+1.2. Editor Interface
+
+ SET EDITOR name [ options ]
+ Lets you specify a text-editing program. The name can be a fully
+ specified pathname like /usr/local/bin/emacs19/emacs, or it can
+ be the name of any program in your PATH, e.g. "set editor
+ emacs". In VMS, it must be a DCL command like "edit",
+ "edit/tpu", "emacs", etc. If an environment variable EDITOR is
+ defined when Kermit starts, its value is the default editor. You
+ can also specify options to be included on the editor command
+ line. Returns to Kermit when the editor exits.
+
+ EDIT [ filename ]
+ If the EDIT command is given without a filename, then if a
+ previous filename had been given to an EDIT command, it is used;
+ if not, the editor is started without a file. If a filename is
+ given, the editor is started on that file, and the filename is
+ remembered for subsequent EDIT commands.
+
+ SHOW EDITOR
+ Displays the full pathname of your text editor, if any, along
+ with any command line options, and the file most recently edited
+ (and therefore the default filename for your next EDIT command).
+
+ Related variables: \v(editor), \v(editopts), \v(editfile).
+
+1.3. Web Browser and FTP Interface
+
+ C-Kermit includes an FTP command, which simply runs the FTP program;
+ C-Kermit does not include any built-in support for Internet File
+ Transfer Protocol, nor any method for interacting directly with an FTP
+ server. In version 7.0, however, C-Kermit lets you specify your FTP
+ client:
+
+ SET FTP-CLIENT [ name [ options ] ]
+ The name is the name of the FTP executable. In UNIX, Windows, or
+ OS/2, it can be the filename of any executable program in your
+ PATH (e.g. "ftp.exe" in Windows, "ftp" in UNIX); elsewhere (or
+ if you do not have a PATH definition), it must be the fully
+ specified pathname of the FTP program. If the name contains any
+ spaces, enclose it braces. Include any options after the
+ filename; these depend the particular ftp client.
+
+ The Web browser interface is covered in the following subsections.
+
+1.3.1. Invoking your Browser from C-Kermit
+
+ BROWSE [ url ]
+ Starts your preferred Web browser on the URL, if one is given,
+ otherwise on the most recently given URL, if any. Returns to
+ Kermit when the browser exits.
+
+ SET BROWSER [ name [ options ] ]
+ Use this command to specify the name of your Web browser
+ program, for example: "set browser lynx". The name must be in
+ your PATH, or else it must be a fully specified filename; in VMS
+ it must be a DCL command.
+
+ SHOW BROWSER
+ Displays the current browser, options, and most recent URL.
+
+ Related variables: \v(browser), \v(browsopts), \v(browsurl).
+
+ Also see [358]Section 2.15: Contacting Web Servers with the HTTP
+ Command.
+
+1.3.2. Invoking C-Kermit from your Browser
+
+ The method for doing this depends, of course, on your browser. Here are
+ some examples:
+
+ Netscape on UNIX (X-based)
+ In the Options->Applications section, set your Telnet
+ application to:
+
+ xterm -e /usr/local/bin/kermit/kermit -J %h %p
+
+ (replace "/usr/local/bin/kermit/kermit" by C-Kermit's actual
+ pathname). -J is C-Kermit's command-line option to "be like
+ Telnet"; %h and %p are Netscape placeholders for hostname and
+ port.
+
+ Lynx on UNIX
+ As far as we know, this can be done only at compile time. Add
+ the following line to the Lynx userdefs.h file before building
+ the Lynx binary:
+
+ #define TELNET_COMMAND "/opt/bin/kermit -J"
+
+ And then add lines like the following to the Lynx.cfg file:
+
+ DOWNLOADER:Kermit binary download:/opt/bin/kermit -i -V -s %s -a %s:TRUE
+ DOWNLOADER:Kermit text download:/opt/bin/kermit -s %s -a %s:TRUE
+
+ UPLOADER:Kermit binary upload:/opt/bin/kermit -i -r -a %s:TRUE
+ UPLOADER:Kermit text upload:/opt/bin/kermit -r -a %s:TRUE
+ UPLOADER:Kermit text get:/opt/bin/kermit -g %s:TRUE
+ UPLOADER:Kermit binary get:/opt/bin/kermit -ig %s:TRUE
+
+ But none of the above is necessary if you make C-Kermit your default
+ Telnet client, which you can do by making a symlink called 'telnet' to
+ the C-Kermit 7.0 binary. See [359]Section 9.1 for details.
+
+1.4. Command Editing
+
+ Ctrl-W ("Word delete") was changed in 7.0 to delete back to the
+ previous non-alphanumeric, rather than all the way back to the previous
+ space.
+
+1.5. Command Switches
+
+ As of version 7.0, C-Kermit's command parser supports a new type of
+ field, called a "switch". This is an optional command modifier.
+
+1.5.1. General Switch Syntax
+
+ A switch is a keyword beginning with a slash (/). If it takes a value,
+ then the value is appended to it (with no intervening spaces),
+ separated by a colon (:) or equal sign (=). Depending on the switch,
+ the value may be a number, a keyword, a filename, a date/time, etc.
+ Examples:
+
+ send oofa.txt ; No switches
+ send /binary oofa.zip ; A switch without a value
+ send /protocol:zmodem oofa.zip ; A switch with a value (:)
+ send /protocol=zmodem oofa.zip ; A switch with a value (=)
+ send /text /delete /as-name:x.x oofa.txt ; Several switches
+
+ Like other command fields, switches are separated from other fields,
+ and from each other, by whitespace, as shown in the examples just
+ above. You can not put them together like so:
+
+ send/text/delete/as-name:x.x oofa.txt
+
+ (as you might do in VMS or DOS, or as we might once have done in
+ TOPS-10 or TOPS0-20, or PIP). This is primarily due to ambiguity
+ between "/" as switch introducer versus "/" as UNIX directory
+ separator; e.g. in:
+
+ send /delete/as-name:foo/text oofa.txt
+
+ Does "foo/text" mean the filename is "foo" and the transfer is to be in
+ text mode, or does it mean the filename is "foo/text"? Therefore we
+ require whitespace between switches to resolve the ambiguity. (That's
+ only one of several possible ambiguities -- it is also conceivable that
+ a file called "text" exists in the path "/delete/as-name:foo/").
+
+ In general, if a switch can take a value, but you omit it, then either
+ a reasonable default value is supplied, or an error message is printed:
+
+ send /print:-Plaserwriter oofa.txt ; Value included = print options
+ send /print oofa.txt ; Value omitted, OK
+ send /mail:kermit@columbia.edu oofa.txt ; Value included = address
+ send /mail oofa.txt ; Not OK - address required
+ ?Address required
+
+ Context-sensitive help (?) and completion (Esc or Tab) are available in
+ the normal manner:
+
+ C-Kermit> send /pr? Switch, one of the following:
+ /print /protocol
+ C-Kermit> send /pro<ESC>tocol:? File-transfer protocol,
+ one of the following:
+ kermit xmodem ymodem ymodem-g zmodem
+ C-Kermit> send /protocol:k<TAB>ermit
+
+ If a switch takes a value and you use completion on it, a colon (:) is
+ printed at the end of its name to indicate this. If it does not take a
+ value, a space is printed.
+
+ Also, if you type ? in a switch field, switches that take values are
+ shown with a trailing colon; those that don't take values are shown
+ without one.
+
+1.5.2. Order and Effect of Switches
+
+ The order of switches should not matter, except that they are evaluated
+ from left to right, so if you give two switches with opposite effects,
+ the rightmost one is used:
+
+ send /text /binary oofa.zip ; Sends oofa.zip in binary mode.
+
+ Like other command fields, switches have no effect whatsoever until the
+ command is entered (by pressing the Return or Enter key). Even then,
+ switches affect only the command with which they are included; they do
+ not have global effect or side effects.
+
+1.5.3. Distinguishing Switches from Other Fields
+
+ All switches are optional. A command that uses switches lets you give
+ any number of them, including none at all. Example:
+
+ send /binary oofa.zip
+ send /bin /delete oofa.zip
+ send /bin /as-name:mupeen.zip oofa.zip
+ send oofa.zip
+
+ But how does Kermit know when the first "non-switch" is given? It has
+ been told to look for both a switch and for something else, the data
+ type of the next field (filename, number, etc). In most cases, this
+ works well. But conflicts are not impossible. Suppose, for example, in
+ UNIX there was a file named "text" in the top-level directory. The
+ command to send it would be:
+
+ send /text
+
+ But C-Kermit would think this was the "/text" switch. To resolve the
+ conflict, use braces:
+
+ send {/text}
+
+ or other circumlocutions such as "send //text", "send /./text", etc.
+
+ The opposite problem can occur if you give an illegal switch that
+ happens to match a directory name. For example:
+
+ send /f oofa.txt
+
+ There is no "/f" switch (there are several switches that begin with
+ "/f", so "/f" is ambiguous). Now suppose there is an "f" directory in
+ the root directory; then this command would be interpreted as:
+
+ Send all the files in the "/f" directory, giving each one an as-name
+ of "oofa.txt".
+
+ This could be a mistake, or it could be exactly what you intended;
+ C-Kermit has no way of telling the difference. To avoid situations like
+ this, spell switches out in full until you are comfortable enough with
+ them to know the minimum abbreviation for each one. Hint: use ? and
+ completion while typing switches to obtain the necessary feedback.
+
+1.5.4. Standard File Selection Switches
+
+ The following switches are used on different file-oriented commands
+ (such as SEND, DIRECTORY, DELETE, PURGE) to refine the selection of
+ files that match the given specification.
+
+ /AFTER:date-time
+ Select only those files having a date-time later than the one
+ given. See [360]Section 1.6 for date-time formats. Synonym:
+ /SINCE.
+
+ /NOT-AFTER:date-time
+ Select only those files having a date-time not later than (i.e.
+ earlier or equal to) the one given. Synonym: /NOT-SINCE.
+
+ /BEFORE:date-time
+ Select only those files having a date-time earlier than the one
+ given.
+
+ /NOT-BEFORE:date-time
+ Select only those files having a date-time not earlier than
+ (i.e. later or equal to) the one given.
+
+ /DOTFILES
+ UNIX and OS-9 only: The filespec is allowed to match files whose
+ names start with (dot) period. Normally these files are not
+ shown.
+
+ /NODOTFILES
+ (UNIX and OS-9 only) Don't show files whose names start with dot
+ (period). This is the opposite of /DOTFILES, and is the default.
+ Note that when a directory name starts with a period, the
+ directory and (in recursive operations) all its subdirectories
+ are skipped.
+
+ /LARGER-THAN:number
+ Only select files larger than the given number of bytes.
+
+ /SMALLER-THAN:number
+ Only select files smaller than the given number of bytes.
+
+ /EXCEPT:pattern
+ Specifies that any files whose names match the pattern, which
+ can be a regular filename, or may contain "*" and/or "?"
+ metacharacters (wildcards), are not to be selected. Example:
+
+ send /except:*.log *.*
+
+ sends all files in the current directory except those with a
+ filetype of ".log". Another:
+
+ send /except:*.~*~ *.*
+
+ sends all files except the ones that look like Kermit or EMACS
+ backup files (such as "oofa.txt.~17~") (of course you can also
+ use the /NOBACKUP switch for this).
+
+ The pattern matcher is the same one used by IF MATCH string
+ pattern ([361]Section 7.4), so you can test your patterns using
+ IF MATCH. If you need to match a literal * or ? (etc), precede
+ it by a backslash (\). If the pattern contains any spaces, it
+ must be enclosed in braces:
+
+ send /except:{Foo bar} *.*
+
+ The pattern can also be a list of up to 8 patterns. In this
+ case, the entire pattern must be enclosed in braces, and each
+ sub-pattern must also be enclosed in braces; this eliminates the
+ need for designating a separator character, which is likely to
+ also be a legal filename character on some platform or other,
+ and therefore a source of confusion. You may include spaces
+ between the subpatterns but they are not necessary. The
+ following two commands are equivalent:
+
+ send /except:{{ck*.o} {ck*.c}} ck*.?
+ send /except:{{ck*.o}{ck*.c}} ck*.?
+
+ If a pattern is to include a literal brace character, precede it
+ with "\". Also note the apparent conflict of this list format
+ and the string-list format described in [362]Section 4.9.1. In
+ case you want to include a wildcard string-list with braces on
+ its outer ends as an /EXCEPT: argument, do it like this:
+
+ send /except:{{{ckuusr.c,ckuus2.c,ckuus6.c}}} ckuus*.c
+
+1.5.5. Setting Preferences for Different Commands
+
+ Certain oft-used commands offer lots of switches because different
+ people have different requirements or preferences. For example, some
+ people want to be able to delete files without having to watch a list
+ of the deleted files scroll past, while others want to be prompted for
+ permission to delete each file. Different people prefer different
+ directory-listing styles. And so on. Such commands can be tailored with
+ the SET OPTIONS command:
+
+ SET OPTIONS command [ switch [ switch [ ... ] ] ]
+ Sets each switch as the default for the given command, replacing
+ the "factory default". Of course you can also override any
+ defaults established by the SET OPTIONS command by including the
+ relevant switches in the affected command any time you issue it.
+
+ SHOW OPTIONS
+ Lists the commands that allows option-setting, and the options
+ currently in effect, if any, for each. Switches that have
+ synonyms are shown under their primary name; for example. /LOG
+ and /VERBOSE are shown as /LIST.
+
+ Commands for which options may be set include DIRECTORY, DELETE, PURGE,
+ and TYPE. Examples:
+
+ SET OPTIONS DIRECTORY /PAGE /NOBACKUP /HEADING /SORT:DATE /REVERSE
+ SET OPTIONS DELETE /LIST /NOHEADING /NOPAGE /NOASK /NODOTFILES
+ SET OPTIONS TYPE /PAGE
+
+ Not necessarily all of a command's switches can be set as options. For
+ example, file selection switches, since these would normally be
+ different for each command.
+
+ Put the desired SET OPTIONS commands in your C-Kermit customization
+ file for each command whose default switches you want to change every
+ time you run C-Kermit.
+
+1.6. Dates and Times
+
+ Some commands and switches take date-time values, such as:
+
+ send /after:{8-Feb-2000 10:28:01}
+
+ Various date-time formats are acceptable. The rules for the date are:
+
+ * The year must have 4 digits.
+ * If the year comes first, the second field is the month.
+ * The day, month, and year may be separated by spaces, /, -, or
+ underscore.
+ * The month may be numeric (1 = January) or spelled out or
+ abbreviated in English.
+
+ If the date-time string contains any spaces, it must be enclosed in
+ braces. Examples of legal dates:
+
+ Interpretation:
+ 2000-Feb-8 8 February 2000
+ {2000 Feb 8} 8 February 2000
+ 2000/Feb/8 8 February 2000
+ 2000_Feb_8 8 February 2000
+ 2000-2-8 8 February 2000
+ 2000-02-08 8 February 2000
+ 8-Feb-2000 8 February 2000
+ 08-Feb-2000 8 February 2000
+ 12/25/2000 25 December 2000
+ 25/12/2000 25 December 2000
+
+ The last two examples show that when the year comes last, and the month
+ is given numerically, the order of the day and month doesn't matter as
+ long as the day is 13 or greater (mm/dd/yyyy is commonly used in the
+ USA, whereas dd/mm/yyyy is the norm in Europe). However:
+
+ 08/02/2000 Is ambiguous and therefore not accepted.
+
+ If a date is given, the time is optional and defaults to 00:00:00. If
+ the time is given with a date, it must follow the date, separated by
+ space, /, -, or underscore, and with hours, minutes, and seconds
+ separated by colon (:). Example:
+
+ 2000-Feb-8 10:28:01 Represents 8 February 2000, 10:28:01am
+
+ If a date is not given, the current date is used and a time is
+ required.
+
+ Time format is hh:mm:ss or hh:mm or hh in 24-hour format, or followed
+ by "am" or "pm" (or "AM" or "PM") to indicate morning or afternoon.
+ Examples of times that are acceptable:
+
+ Interpretation:
+ 3:23:56 3:23:56am
+ 3:23:56am 3:23:56am
+ 3:23:56pm 3:23:56pm = 15:23:56
+ 15:23:56 3:23:56pm = 15:23:56
+ 3:23pm 3:23:00pm = 15:23:00
+ 3:23PM 3:23:00pm = 15:23:00
+ 3pm 3:00:00pm = 15:00:00
+
+ Examples of legal date-times:
+
+ send /after:{8 Feb 2000 10:28:01}
+ send /after:8_Feb_2000_10:28:01
+ send /after:8-Feb-2000/10:28:01
+ send /after:2000/02/08/10:28:01
+ send /after:2000/02/08_10:28:01
+ send /after:2000/02/08_10:28:01am
+ send /after:2000/02/08_10:28:01pm
+ send /after:2000/02/08_10:28pm
+ send /after:2000/02/08_10pm
+ send /after:10:00:00pm
+ send /after:10:00pm
+ send /after:10pm
+ send /after:22
+
+ Finally, there is a special all-numeric format you can use:
+
+ yyyymmdd hh:mm:ss
+
+ For example:
+
+ 20000208 10:28:01
+
+ This is Kermit's standard date-time format (based on ISO 8601), and is
+ accepted (among other formats) by any command or switch that requires a
+ date-time, and is output by any function whose result is a calendar
+ date-time.
+
+ There are no optional parts to this format and it must be exactly 17
+ characters long, punctuated as shown (except you can substitute
+ underscore for space in contexts where a single "word" is required).
+ The time is in 24-hour format (23:00:00 is 11:00pm). This is the format
+ returned by \fdate(filename), so you can also use constructions like
+ this:
+
+ send /after:\fdate(oofa.txt)
+
+ which means "all files newer than oofa.txt".
+
+ Besides explicit dates, you can also use the any of the following
+ shortcuts:
+
+ TODAY
+ Stands for the current date at 00:00:00.
+
+ TODAY 12:34:56
+ Stands for the current date at the given time.
+
+ YESTERDAY
+ Stands for yesterday's date at 00:00:00. A time may also be
+ given.
+
+ TOMORROW
+ Stands for tomorrow's date at 00:00:00. A time may also be
+ given.
+
+ + number { DAYS, WEEKS, MONTHS, YEARS } [ time ]
+ Is replaced by the future date indicated, relative to the
+ current date. If the time is omitted, 00:00:00 is used.
+ Examples: +3days, +2weeks, +1year, +37months.
+
+ - number { DAYS, WEEKS, MONTHS, YEARS } [ time ]
+
+ Is replaced by the past date indicated, relative to the current
+ date. If the time is omitted, 00:00:00 is used.
+
+ The time can be separated from the date shortcut by any of the same
+ separators that are allowed for explicit date-times: space, hyphen,
+ slash, period, or underscore. In switches and other space-delimited
+ fields, use non-spaces to separate date/time fields, or enclose the
+ date-time in braces, e.g.:
+
+ purge /before:-4days_12:00:00
+ purge /before:{- 4 days 12:00:00}
+
+ Of course you can also use variables:
+
+ define \%n 43
+ purge /before:-\%ndays_12:00:00
+
+ Shortcut names can be abbreviated to any length that still
+ distinguishes them from any other name that can appear in the same
+ context, e.g. "TOD" for today, "Y" for yesterday. Also, the special
+ abbreviation "wks" is accepted for WEEKS, and "yrs" for "YEARS".
+
+ (To see how to specify dates relative to a specific date, rather than
+ the current one, see the [363]\fmjd() function description below.)
+
+ You can check date formats with the DATE command. DATE by itself prints
+ the current date and time in standard format: yyyymmdd hh:mm:ss. DATE
+ followed by a date and/or time (including shortcuts) converts it to
+ standard format if it can understand it, otherwise it prints an error
+ message.
+
+ The following variables and functions deal with dates and times; any
+ function argument designated as "date-time" can be in any of the
+ formats described above.
+
+ \v(day)
+ The first three letters of the English word for the current day
+ of the week, e.g. "Wed".
+
+ \fday(date-time)
+ The first three letters of the English word for day of the week
+ of the given date. If a time is included, it is ignored.
+ Example: \fday(8 Feb 1988) = "Mon".
+
+ \v(nday)
+ The numeric day of the week: 0 = Sunday, 1 = Monday, ..., 6 =
+ Saturday.
+
+ \fnday(date-time)
+ The numeric day of the week for the given date. If a time is
+ included, it is ignored. Example: \fnday(8 Feb 1988) = "1".
+
+ \v(date)
+ The current date as dd mmm yyyy, e.g. "08 Feb 2000" (as in this
+ example, a leading zero is supplied for day-of-month less than
+ 10).
+
+ \v(ndate)
+ The current date in numeric format: yyyymmdd, e.g. "20000208".
+
+ \v(time)
+ The current time as hh:mm:ss, e.g. "15:27:14".
+
+ \ftime(time)
+ The given free-format date and/or time (e.g. "3pm") returns the
+ time (without the date) converted to hh:mm:ss 24-hour format,
+ e.g. "15:00:00" (the date, if given, is ignored).
+
+ \v(ntime)
+ The current time as seconds since midnight, e.g. "55634".
+
+ \v(tftime)
+ The elapsed time of the most recent file-transfer operation in
+ seconds.
+
+ \v(intime)
+ The elapsed time for the most recent INPUT command to complete,
+ in milliseconds.
+
+ \fntime(time)
+ The given free-format date and/or time is converted to seconds
+ since midnight (the date, if given, is ignored). This function
+ replaces \ftod2secs(), which is now a synonym for \fntime().
+ Unlike \ftod2secs(), \fntime() allows a date to be included, and
+ it allows the time to be in free format (like 3pm), and it
+ allows the amount of time to be more than 24 hours. E.g.
+ \fntime(48:00:00) = 172800. Example of use:
+
+ set alarm \fntime(48:00:00) ; set alarm 48 hours from now.
+
+ \fn2time(seconds)
+ The given number of seconds is converted to hh:mm:ss format.
+
+ \fdate(filename)
+ Returns the modification date-time of the given file in standard
+ format: yyyymmdd hh:mm:ss.
+
+ \fcvtdate(date-time)
+ Converts a free-format date and/or time to Kermit standard
+ format: yyyymmdd hh:mm:ss. If no argument is given, returns the
+ current date-time in standard format. If a date is given but no
+ time, the converted date is returned without a time. If a time
+ is given with no date, the current date is supplied. Examples:
+
+ \fcvtdate(4 Jul 2000 2:21:17pm) = 20000704 14:21:17
+ \fcvtdate() = 20000704 14:21:17 (on 4 Jul 2000 at 2:21:17pm).
+ \fcvtd(4 Jul 2000) = 20000704
+ \fcvtd(6pm) = 20000704 18:00:00 (on 4 Jul 2000 at 6:00pm).
+
+ \fdayofyear(date-time)
+ \fdoy(date-time)
+ Converts a free-format date and/or time to yyyyddd, where ddd is
+ the 3-digit day of the year, and 1 January is Day 1. If a time
+ is included with the date, it is returned in standard format. If
+ a date is included but no time, the date is returned without a
+ time. If a time is given with no date, the time is converted and
+ the current date is supplied. If no argument is given, the
+ current date-time is returned. Synonym: \fdoy(). Examples:
+
+ \fddayofyear(4 Jul 2000 2:21:17pm) = 2000185 14:21:17
+ \fdoy() = 2000185 14:21:17 (on 4 Jul 2000 at 2:21:17pm).
+ \fdoy(4 Jul 2000) = 2000185
+ \fdoy(6pm) = 2000185 18:00:00 (on 4 Jul 2000 at 6:00pm).
+
+ Note: The yyyyddd day-of-year format is often erroneously referred to
+ as a Julian date. However, a true Julian date is a simple counting
+ number, the number of days since a certain fixed day in the past.
+ [364]See \fmjd() below.
+
+ \fdoy2date(date-time)
+ Converts a date or date-time in day-of-year format to a standard
+ format date. A yyyyddd-format date must be supplied; time is
+ optional. The given date is converted to yyyymmdd format. If a
+ time is given, it is converted to 24-hour format. Examples:
+
+ \fdoy2date(2000185) = 20000704
+ \fdoy2(2000185 3pm) = 20000704 15:00:00
+
+ \fmjd(date-time)
+ Converts free-format date and/or time to a Modified Julian Date
+ (MJD), the number of days since 17 Nov 1858 00:00:00. If a time
+ is given, it is ignored. Examples:
+
+ \fmjd(4 Jul 2000) = 50998
+ \fmjd(17 Nov 1858) = 0
+ \fmjd(16 Nov 1858) = -1
+
+ \fmjd2date(mjd)
+ Converts an MJD (integer) to standard date format, yyyymmdd:
+
+ \fmjd2(50998) = 4 Jul 1998
+ \fmjd2(0) = 17 Nov 1858
+ \fmjd2(-1) = 16 Nov 1858
+ \fmjd2(-365) = 17 Nov 1857
+
+ MJDs are normal integers and, unlike DOYs, may be added, subtracted,
+ etc, with each other or with other integers, to obtain meaningful
+ results. For example, to find out the date 212 days ago:
+
+ echo \fmjd2date(\fmjd()-212)
+
+ Constructions such as this can be used in any command where a date-time
+ is required, e.g.:
+
+ send /after:\fmjd2date(\fmjd()-212)
+
+ to send all files that are not older than 212 days (this is equivalent
+ to "send /after:-212days").
+
+ MJDs also have other regularities not exhibited by other date formats.
+ For example, \fmodulus(\fmjd(any-date),7) gives the day of the week for
+ any date (where 4=Sun, 5=Mon, ..., 3=Sat). (However, it is easier to
+ use \fnday() for this purpose, and it gives the more conventional
+ result of 0=Sun, 1=Mon, ..., 6=Sat).
+
+ Note that if MJDs are to be compared, they must be compared numerically
+ (IF <, =, >) and not lexically (IF LLT, EQUAL, LGT), whereas DOYs must
+ be compared lexically if they include a time (which contains ":"
+ characters); however, if DOYs do not include a time, they may also be
+ compared numerically.
+
+ In any case, lexical comparison of DOYs always produces the appropriate
+ result, as does numeric comparison of MJDs.
+
+ The same comments apply to sorting. Also note that DOYs are fixed
+ length, but MJDs can vary in length. However, all MJDs between 3 April
+ 1886 and 30 Aug 2132 are 5 decimal digits long. (MJDs become 6 digits
+ long on 31 Aug 2132, and 7 digits long on 13 Oct 4596).
+
+1.7. Partial Completion of Keywords
+
+ Partial completion of keywords was added in C-Kermit 7.0. In prior
+ versions, if completion was attempted (by pressing the Esc or Tab key)
+ on a string that matched different keywords, you'd just get a beep. Now
+ Kermit completes up to the first character where the possibly matching
+ keywords differ and then beeps. For example:
+
+ C-Kermit> send /n<Tab>
+
+ which matches /NOT-BEFORE and /NOT-AFTER, now completes up to the dash:
+
+ C-Kermit> send /n<Tab>ot-<Beep>
+
+ Partial completion works for filenames too (as it has for some years).
+
+1.8. Command Recall
+
+ C-Kermit has had a command history buffer for some time, which could be
+ scrolled interactively using control characters or (in Kermit 95 only)
+ arrow keys. Version 7.0 adds a REDO command that allows the most recent
+ command matching a given pattern to be re-executed:
+
+ { REDO, RR, ^ } [ pattern ]
+ Search the command history list for the most recent command that
+ matches the given pattern, and if one is found, execute it
+ again.
+
+ The pattern can be a simple string (like "send"), in which case the
+ last SEND command is re-executed. Or it can contain wildcard characters
+ "*" and/or "?", which match any string and any single character,
+ respectively (note that "?" must be preceded by backslash to override
+ its normal function of giving help), and in most C-Kermit versions may
+ also include [] character lists and {} string lists (see [365]Section
+ 4.9).
+
+ The match works by appending "*" to the end of the given pattern (if
+ you didn't put one there yourself). Thus "redo *oofa" becomes "redo
+ *oofa*" and therefore matches the most recent command that contains
+ "oofa" anywhere within the command. If you want to inhibit the
+ application of the trailing "*", e.g. to force matching a string at the
+ end of a command, enclose the pattern in braces:
+
+ redo {*oofa}
+
+ matches the most recent command that ends with "oofa".
+
+ REDO commands themselves are not entered into the command history list.
+ If no pattern is given, the previous (non-REDO) command is re-executed.
+ The REDOne command is reinserted at the end of the command history
+ buffer, so the command scrollback character (Ctrl-P, Ctrl-B, or
+ Uparrow) can retrieve it.
+
+ Examples:
+
+ C-Kermit> echo foo
+ foo
+ C-Kermit> show alarm
+ (no alarm set)
+ C-Kermit> echo blah
+ blah
+ C-Kermit> redo ; Most recent command
+ blah
+ C-Kermit> redo s ; Most recent command starting with "s"
+ (no alarm set)
+ C-Kermit> redo echo f ; Most recent command starting with "echo f"
+ foo
+ C-Kermit> redo *foo ; Most recent command that has "foo" in it
+ foo
+ C-Kermit> <Ctrl-P> ; Scroll back
+ C-Kermit> echo foo ; The REDOne command is there
+ C-Kermit> redo {*foo} ; Most recent command that ends with "foo"
+ foo
+ C-Kermit>
+
+ Since REDO, REDIAL, and REDIRECT all start the same way, and RED is the
+ designated non-unique abbreviation for REDIAL, REDO must be spelled out
+ in full. For convenience, RR is included as an invisible easy-to-type
+ synonym for REDO. You can also use the "^" character for this:
+
+ C-Kermit> ^ ; Most recent command
+ C-Kermit> ^ s ; Most recent command starting with "s"
+ C-Kermit> ^s ; Ditto (space not required after "^").
+ C-Kermit> ^*foo ; Most recent command that has "foo" in it.
+ C-Kermit> ^{*foo} ; Most recent command ends with "foo".
+
+ Unlike the manual command-history-scrolling keys, the REDO command can
+ be used in a script, but it's not recommended (since the command to be
+ REDOne might not be found, so if the REDO command fails, you can't tell
+ whether it was because REDO failed to find the requested command, or
+ because the command was found but it failed).
+
+1.9. EXIT Messages
+
+ The EXIT and QUIT commands now accept an optional message to be
+ printed. This makes the syntax of EXIT and QUIT just like END and STOP:
+
+ { EXIT, QUIT, END, STOP } [ status-code [ message ] ]
+
+ where status-code is a number (0 indicating success, nonzero indicating
+ failure). This is handy in scripts that are never supposed to enter
+ interactive mode:
+
+ dial 7654321
+ if fail exit 1 Can't make connection - try again later.
+
+ Previously this could only be done in two steps:
+
+ dial 7654321
+ xif fail { echo Can't make connection - try again later, exit 1 }
+
+ A status code must be included in order to specify a message. In the
+ case of EXIT and QUIT, the default status code is contained in the
+ variable \v(exitstatus), and is set automatically by various events
+ (file transfer failures, etc; it can also be set explicitly with the
+ SET EXIT STATUS command). If you want to give an EXIT or QUIT command
+ with a message, but without changing the exit status from what it
+ normally would have been, use the \v(exitstatus) variable, e.g.:
+
+ exit \v(exitstatus) Goodbye from \v(cmdfile).
+
+ The EXIT status is returned to the system shell or whatever other
+ process invoked C-Kermit, e.g. in UNIX:
+
+ C-Kermit> exit 97 bye bye
+ bye bye
+ $ echo $?
+ 97
+ $
+
+1.10. Managing Keyboard Interruptions
+
+ When C-Kermit is in command or file-transfer mode (as opposed to
+ CONNECT mode), it can be interrupted with Ctrl-C. Version 7.0 adds the
+ ability to disarm the Ctrl-C interrupt:
+
+ SET COMMAND INTERRUPT { ON, OFF }
+ COMMAND INTERRUPT is ON by default, meaning the Ctrl-C can be
+ used to interrupt a command or a file transfer in progress. Use
+ OFF to disable these interruptions, and use it with great
+ caution for obvious reasons.
+
+ SET TRANSFER INTERRUPT { ON, OFF }
+ This can be used to disable keyboard interruption of file
+ transfer when C-Kermit is in local mode, or to re-enable it
+ after it has been disabled. This applies to the X, Z, E, and
+ similar keys as well as to the system interrupt character,
+ usually Ctrl-C. This is distinct from SET TRANSFER CANCELLATION,
+ which tells whether packet mode can be exited by sending a
+ special sequence of characters.
+
+ Several other commands can be interrupted by pressing any key while
+ they are active. Version 7.0 adds the ability to disable this form of
+ interruption also:
+
+ SET INPUT CANCELLATION { ON, OFF }
+ Whether an INPUT command in progress can be interrupted by
+ pressing a key. Normally ON. Setting INPUT CANCELLATION OFF
+ makes INPUT commands uninterruptible except by Ctrl-C (unless
+ COMMAND INTERRUPTION is also OFF).
+
+ SET SLEEP CANCELLATION { ON, OFF }
+ Whether a SLEEP, PAUSE, or WAIT command in progress can be
+ interrupted by pressing a key. Normally ON. Setting SLEEP
+ CANCELLATION OFF makes these commands uninterruptible except by
+ Ctrl-C (unless COMMAND INTERRUPTION is also OFF). Synonyms: SET
+ PAUSE CANCELLATION, SET WAIT CANCELLATION.
+
+ So to make certain a script is not interruptible by the user, include
+ these commands:
+
+ SET TRANSFER INTERRUPT OFF
+ SET SLEEP CANCELLATION OFF
+ SET INPUT CANCELLATION OFF
+ SET COMMAND INTERRUPTION OFF
+
+ Make sure to turn them back on afterwards if interruption is to be
+ re-enabled.
+
+ When a PAUSE, SLEEP, WAIT, or INPUT command is interrupted from the
+ keyboard, the new variable \v(kbchar) contains a copy of the (first)
+ character that was typed and caused the interruption, provided it was
+ not the command interrupt character (usually Ctrl-C). If these commands
+ complete successfully or time out without a keyboard interruption, the
+ \v(kbchar) variable is empty.
+
+ The \v(kbchar) variable (like any other variable) can be tested with:
+
+ if defined \v(kbchar) command
+
+ The command is executed if the variable is not empty.
+
+ The \v(kbchar) variable can be reset with WAIT 0 (PAUSE 0, SLEEP 0,
+ etc).
+
+1.11. Taming The Wild Backslash -- Part Deux
+
+ [366]Using C-Kermit, 2nd Edition, contains a brief section, "Taming the
+ Wild Backslash", on page 48, which subsequent experience has shown to
+ be inadequate for Kermit users intent on writing scripts that deal with
+ Windows, DOS, and OS/2 filenames, in which backslash (\) is used as the
+ directory separator. This section fills in the blanks.
+
+1.11.1. Background
+
+ The Kermit command language shares a certain unavoidable but annoying
+ characteristic with most other command languages that are capable of
+ string replacement, namely the necessity to "quote" certain characters
+ when you want them to be taken literally. This is a consequence of the
+ facts that:
+
+ 1. One or more characters must be set aside to denote replacement,
+ rather than acting as literal text.
+ 2. We have only 96 printable characters to work with in ASCII, which
+ is still the only universally portable character set.
+ 3. There is no single printable character that is unused everywhere.
+ 4. Variables are not restricted to certain contexts, as they are in
+ formal programming languages like C and Fortran, but can appear
+ anywhere at all within a command, and therefore require special
+ syntax.
+
+ Thus there can be conflicts. To illustrate, the standard UNIX shell
+ uses dollar sign ($) to introduce variables. So the shell command:
+
+ echo $TERM
+
+ displays the value of the TERM variable, e.g. vt320. But suppose you
+ want to display a real dollar sign:
+
+ echo The price is $10.20
+
+ This causes the shell to evaluate the variable "$1", which might or
+ might not exist, and substitute its value, e.g.:
+
+ The price is 0.20
+
+ (in this case the $1 variable had no value.) This is probably not what
+ you wanted. To force the dollar sign to be taken literally, you must
+ apply a "quoting rule", such as "precede a character by backslash (\)
+ to force the shell to take the character literally":
+
+ echo The price is \$10.20
+ The price is $10.20
+
+ But now suppose you want the backslash AND the dollar sign to be taken
+ literally:
+
+ echo The price is \\$10.20
+
+ This doesn't work, since the first backslash quotes the second one,
+ thereby leaving the dollar sign unquoted again:
+
+ The price is \0.20
+
+ Quoting the dollar sign requires addition of a third backslash:
+
+ echo The price is \\\$10.20
+ The price is \$10.20
+
+ The first backslash quotes the second one, and the third backslash
+ quotes the dollar sign.
+
+ Every command language -- all UNIX shells, VMS DCL, DOS Batch, AOS/VS
+ CLI, etc etc -- has similar rules. UNIX shell rules are probably the
+ most complicated, since many printable characters -- not just one --
+ are special there: dollar sign, single quote, double quote, backslash,
+ asterisk, accent grave, number sign, ampersand, question mark,
+ parentheses, brackets, braces, etc -- practically every
+ non-alphanumeric character needs some form of quoting if it is to be
+ taken literally. And to add to the confusion, the UNIX shell offers
+ many forms of quoting, and many alternative UNIX shells are available,
+ each using slightly different syntax.
+
+1.11.2. Kermit's Quoting Rules
+
+ Kermit's basic quoting rules are simple by comparison (there are, of
+ course, additional syntax requirements for macro definitions, command
+ blocks, function calls, etc, but they are not relevant here).
+
+ The following characters are special in Kermit commands:
+
+ Backslash (\)
+ Introduces a variable, or the numeric representation of a
+ special character, or a function, or other item for
+ substitution. If the backslash is followed by a digit or by any
+ of the following characters:
+
+ x, o, d, m, s, f, v, $, %, &, :, {
+
+ this indicates a special substitution item; otherwise the
+ following character is to be taken literally (exceptions: \ at
+ end of line is taken literally; \n, \b, and \n are special items
+ in the OUTPUT command only).
+
+ Semicolon (;)
+ (Only when at the beginning of a line or preceded by at least
+ one space or tab) Introduces a comment.
+
+ Number sign (#)
+ (Only when at the beginning of a line or preceded by at least
+ one space or tab) Just like semicolon; introduces a comment.
+
+ Question mark (?)
+ (Only at the command prompt - not in command files or macros)
+ Requests context-sensitive help.
+
+ To force Kermit to take any of these characters literally, simply
+ precede it by a backslash (\).
+
+ Sounds easy! And it is, except when backslash also has a special
+ meaning to the underlying operating system, as it does in DOS, Windows,
+ and OS/2, where it serves as the directory separator in filenames such
+ as:
+
+ D:\K95\KEYMAPS\READ.ME
+
+ Using our rule, we would need to refer to this file in Kermit commands
+ as follows:
+
+ D:\\K95\\KEYMAPS\\READ.ME
+
+ But this would not be obvious to new users of Kermit software on DOS,
+ Windows, or OS/2, and it would be annoying to seasoned ones. Thus
+ MS-DOS Kermit and Kermit 95 go to rather extreme lengths to allow the
+ more natural notation, as in:
+
+ send d:\k95\keymaps\read.me
+
+ The reason this is tricky is that we also need to allow for variables
+ and other expressions introduced by backslash in the same command. For
+ example, suppose \%a is a variable whose value is "oofa" (without the
+ quotes). What does the following command do?
+
+ send d:\%a
+
+ Does it send the file named "oofa" in the current directory of the D:
+ disk, or does it send a file named "%a" in the root directory of the D:
+ disk? This is the kind of trouble we get into when we attempt to bend
+ the rules in the interest of user friendliness. (The answer is: if the
+ variable \%a has definition that is the name of an existing file, that
+ file is sent; if a file d:\%a exists, it is sent; otherwise if both
+ conditions are true, the variable takes precedence, and the literal
+ filename can be forced by quoting: \\%a.)
+
+ In Kermit 95 (but not MS-DOS Kermit), we also bend the rules another
+ way by allowing you to use forward slash (/) rather than backslash (\)
+ as the directory separator:
+
+ send d:/k95/keymaps/read.me
+
+ This looks more natural to UNIX users, and in fact is perfectly
+ acceptable to the Windows 95/98/NT and OS/2 operating systems on the
+ API level. BUT (there is always a "but") the Microsoft shell,
+ COMMAND.COM, for Windows 95/98 and NT does not allow this notation, and
+ therefore it can not be used in any Kermit command -- such as RUN --
+ that invokes the Windows command shell AND your command shell is
+ COMMAND.COM or any other shell that does not allow forward slash as
+ directory separator (some alternative shells do allow this).
+
+ NOTE: There exists a wide variety of alternative shells from third
+ parties that do not have this restriction. If you are using a shell
+ that accepts forward slash as a directory separator, you can stop
+ reading right now -- UNLESS (there is always an "unless") you want
+ your scripts to be portable to systems that have other shells. Also
+ note that some Windows shells might actually REQUIRE forward slashes
+ (instead of backslashes) as directory separators; we do not treat
+ this situation below, but the treatment is obvious -- use slash
+ rather backslash as the directory separator.
+
+1.11.3. Passing DOS Filenames from Kermit to Shell Commands
+
+ The following Kermit commands invoke the system command shell:
+
+ RUN (and its synonyms ! and @)
+ REDIRECT
+ PIPE
+
+ Each of these commands takes a shell command as an operand. These shell
+ commands are not, and can not be, parsed by Kermit since Kermit does
+ not know the syntax of shell commands, and so can't tell the difference
+ between a keyword, a filename, a variable, a switch, or other item.
+ Therefore the rules can not be bent since Kermit doesn't know where or
+ how to bend them. To illustrate (using the regular Windows shell):
+
+ run c:\\windows\\command\\chkdsk.exe
+
+ works OK, but:
+
+ run c:/windows/command/chkdsk.exe
+
+ is not accepted by COMMAND.COM. But:
+
+ run c:\windows\command\chkdsk.exe
+
+ results in Kermit applying its quoting rules before sending the text to
+ the shell. Since "w" and "c" are not in the list of backslash-item
+ codes, the backslash means "take the following character literally".
+ Thus, by the time this filename gets to the Windows shell, it has
+ become:
+
+ c:windowscommandchkdsk.exe
+
+ which is probably not what you wanted. (If "w" and "c" were in the
+ list, the results could be even stranger.) Even more confusing is the
+ case where a directory or filename starts with one or more digits:
+
+ run c:\123\lotus.exe
+
+ in which "\123" is the Kermit notation for ASCII character 123, which
+ happens to be left brace ({), resulting in "c:{lotus.exe".
+
+ So when passing filenames to a Windows shell, always use double
+ backslashes as directory separators, to ensure that the shell gets
+ single backslashes:
+
+ run c:\\windows\\command\\chkdsk.exe
+ run c:\\123\\lotus.exe
+
+ Similar problems might occur with the built-in EDIT, BROWSE, and FTP
+ commands. These commands result in Kermit building a shell command
+ internally to invoke the associated helper program; the form of this
+ command might conflict with the form demanded by certain alternative
+ shells.
+
+1.11.4. Using Variables to Hold DOS Filenames
+
+ Now to the next level. Suppose you want to write a script in which
+ filenames are parameters, and therefore are stored in variables.
+ Example:
+
+ define \%f c:\windows\command\chkdsk.exe
+ ...
+ run \%f
+
+ Obviously this won't work for the reasons just noted; the RUN command
+ requires directory separators be coded as double backslashes:
+
+ define \%f c:\\windows\\command\\chkdsk.exe
+ ...
+ run \%f
+
+ This will work; no surprises here. However, if you had used ASSIGN
+ rather than DEFINE, you might have been surprised after all; review
+ pages 348-349 of [367]Using C-Kermit (2nd Ed) for the difference
+ between DEFINE and ASSIGN.
+
+ We have said that any Kermit 95 or MS-DOS Kermit command that parses
+ filenames itself -- SEND, for example -- does not require double
+ backslashes since it knows it is parsing a filename. So since the
+ following works:
+
+ send c:\windows\command\chkdsk.exe
+
+ Should the following also work?
+
+ define \%f c:\windows\command\chkdsk.exe
+ ...
+ send \%f
+
+ Answer: No. Why? Because \%f is evaluated "recursively", to allow for
+ the possibility that its definition contains further variable
+ references. This is true of all "backslash-percent-letter" (or -digit)
+ variables, and also for array references. So \%f becomes
+ c:\windows\command\chkdsk.exe, which becomes
+ c:windowscommandchkdsk.exe.
+
+ The trick here is to use the "other" kind of variable, that is
+ evaluated only "one level deep" rather than recursively:
+
+ define filename c:\windows\command\chkdsk.exe
+ ...
+ send \m(filename)
+
+ Similarly if you want to prompt the user for a filename:
+
+ ask filename { Please type a filename: }
+ Please type a filename: c:\windows\command\chkdsk.exe
+ send \m(filename)
+
+1.11.5. Passing DOS Filenames as Parameters to Macros
+
+ Suppose you want to pass a DOS filename containing backslashes as a
+ parameter to a Kermit macro. This raises two issues:
+
+ 1. Parameters to macros are "just text" and so are fully evaluated
+ before they are passed to the macro.
+ 2. Once inside the macro, the formal parameters \%1, \%2, ... \%9 are
+ the type of variable that is evaluated recursively.
+
+ Thus a DOS filename is ruined once in the act of parsing the macro
+ invocation, and again when referring to it from within the macro. To
+ illustrate, suppose "test" is a macro. Then in the invocation:
+
+ test c:\mydir\blah.txt
+
+ "c:mydirblah.txt" is assigned to \%1. However, if we double the
+ backslashes:
+
+ test c:\\mydir\\blah.txt
+
+ "c:\mydir\blah.txt" is assigned to \%1. But then when you refer to \%1
+ in the macro, it is evaluated recursively, resulting in
+ "c:mydirblah.txt". To illustrate:
+
+ define test echo \%1
+ test c:\mydir\blah.txt
+ c:mydirblah.txt
+ test c:\\mydir\\blah.txt
+ c:mydirblah.txt
+ test c:\\\\mydir\\\\blah.txt
+ c:\mydir\blah.txt
+
+ Let's address each part of the problem separately. First, inside the
+ macro. You can use the \fcontents() function to force a
+ backslash-percent variable (such as a macro argument) to be evaluated
+ one level deep instead of recursively, for example:
+
+ define test echo { The filename is "\fcontents(\%1)"}
+
+ test c:\mydir\blah.txt ; We don't expect this to work
+ The filename is "c:mydirblah.txt" ; and it doesn't.
+ test c:\\mydir\\blah.txt ; But this does...
+ The filename is "c:\mydir\blah.txt"
+
+ Thus if the filename arrives inside the macro with single backslashes,
+ the backslashes are preserved if you always refer to the parameter
+ through the \fcontents() function.
+
+ Now how to ensure that backslashes are not stripped or misinterpreted
+ when passing a filename to a macro? This brings us back to what we
+ learned in earlier sections:
+
+ 1. If it is a literal filename, either double the backslashes, or (if
+ the filename is to be used only within Kermit itself and not passed
+ to a DOS shell, or it is to be passed to an alternative shell that
+ accepts forward slash as a directory separator), use forward slash
+ instead of backslash as the directory separator.
+ 2. If it is a variable that contains a filename, make sure you use a
+ macro-style variable name, rather than a
+ backslash-percent-character name.
+
+ Examples:
+
+ define test echo \fcontents(\%1)
+ define filename c:\mydir\blah.txt
+
+ test c:\\mydir\\blah.txt ; Literal filename with double backslashes
+ c:\mydir\blah.txt
+
+ test c:/mydir/blah.txt ; Literal filename with forward slashes
+ c:/mydir/blah.txt
+
+ test \m(filename) ; Variable
+ c:\mydir\blah.txt
+
+ But what if you don't like these rules and you still want to pass a
+ literal filename containing single backslashes to a macro? This is
+ possible too, but a bit tricky: turn command quoting off before
+ invoking the macro, and then turn it back on inside the macro. Example:
+
+ define test set command quoting on, echo \fcontents(\%1)
+
+ set command quoting off
+ test c:\mydir\blah.txt
+ c:\mydir\blah.txt
+
+ Upon return from the macro, command quoting is back on (since the macro
+ turned it on).
+
+ Obviously this trick can not be used if the filename is stored in a
+ variable, since it prevents the variable from being evaluated.
+
+1.11.6. Passing DOS File Names from Macro Parameters to the DOS Shell
+
+ Now suppose you need to pass a DOS filename to a macro, and the macro
+ needs to pass it, in turn, to the Windows shell via (say) Kermit's RUN
+ command. This works too:
+
+ define xrun run \fcontents(\%1)
+ xrun c:\\windows\\command\\chkdsk.exe
+
+ (or you can use the SET COMMAND QUOTING OFF / ON technique described
+ above to avoid the double backslashes.) But..
+
+ xrun c:/windows/command/chkdsk.exe
+
+ does not work if the Windows shell does not recognize "/" as a
+ directory separator. If there is a chance that a filename might be
+ passed to the macro in this form, the macro will need to convert it to
+ a form acceptable to the shell:
+
+ define xrun run \freplace(\fcontents(\%1),/,\\)
+
+ Here we replace all occurrences (if any) of "/" in the argument with
+ "\" prior to issuing the RUN command. Of course, in order to specify
+ "\" as a literal character in the \freplace() argument list, we have to
+ double it.
+
+1.11.7. Passing DOS Filenames to Kermit from the Shell
+
+ As noted in the manual, the \&@[] array contains Kermit's command-line
+ arguments. Suppose one of these arguments, say \&@[3], is a DOS
+ filename such as C:\FOO\BAR\BAZ\OOFA.TXT. (Note: In C-Kermit 7.0 and
+ K95 1.1.18 and later, command-line arguments after "=" or "--" are also
+ available in the top-level \%1..9 variables; see [368]Section 7.5.)
+
+ Of course you can eliminate any problems by using forward slashes
+ rather than backslashes in the filename, but sometimes this is not
+ possible, as when the Kermit command line is being generated by another
+ program than can only generate "native" format DOS filenames.
+
+ As noted in the manual, "\%x" variables and \&x[] arrays are always
+ evaluated "all the way" (recursively). If the contents of one of these
+ variables contains backslashes, this causes another level of
+ evaluation.
+
+ There is another kind of variable, which is evaluated only "one level
+ deep". You can use this to prevent interpretation of the backslashes in
+ the filenames. Example:
+
+ assign filename \fcontents(\&@[3]) ; Transfer contents
+ ...
+ send \m(filename)
+
+ Or, more simply:
+
+ send \fcontents(\&@[3])
+
+1.12. Debugging
+
+ The debug log is produced when you give a "log debug" command. This is
+ normally done at the request of the Kermit help desk, for forwarding to
+ the Kermit developers for analysis as a last resort in troubleshooting
+ problems. (Last resort because it can grow quite huge in a very short
+ time.) In cases where timing information is critical to understanding a
+ problem, you can tell C-Kermit to put a timestamp on each debug log
+ line by giving the command:
+
+ SET DEBUG TIMESTAMP ON
+
+ At any time before or after activating the debug log (SET DEBUG
+ TIMESTAMP OFF turns off timestamping). Timestamps can be turned off and
+ on as desired while logging. Obviously, they increase the size and
+ growth rate of the log significantly, and so should be used sparingly.
+ Timestamps are of the form hh:mm:ss.xxx, where .xxx is thousands of a
+ second (but is included only on platforms that include this feature).
+
+1.13. Logs
+
+ In UNIX C-Kermit and in K-95, you can now direct any log to a pipe.
+ This not only lets you send your logs to places other than disk files,
+ but also lets you customize them to any desired degree.
+
+ LOG { DEBUG, PACKETS, SESSION, TRANSACTION, CONNECTION } { file, pipe }
+ ...
+ A "pipe" is the name of a command, preceded by a vertical bar.
+ If the pipe contains any spaces, it must be enclosed in braces.
+
+ Here are some examples for UNIX (always remember the importance of
+ getting the UNIX shell quoting rules right):
+
+ LOG TRANSACTIONS |lpr
+ This sends the transaction log to the default UNIX printer,
+ rather than to a file (use "lp" rather than "lpr" if necessary).
+
+ LOG TRANSACTIONS {| myfilter > t.log}
+ For those who don't like the format of the transaction log, or
+ want to extract certain information from it; write your own
+ output filter.
+
+ LOG SESSION {| lpr -Plaserwriter}
+ This sends the session log to a specific UNIX printer, rather
+ than to a file. Note the braces around the pipeline. These are
+ required because it contains spaces.
+
+ LOG DEBUG {| tail -100 > debug.log}
+ This causes the debug log file to contain only the final 100
+ lines. Suppose C-Kermit crashes under some unpredictable
+ circumstances, and you need a debug log to catch it in the act.
+ But the debug log can grow to huge proportions very quickly,
+ possibly filling up the disk. Piping the debug log through
+ "tail" results in keeping only the last 100 lines (or other
+ number of your choice).
+
+ LOG DEBUG {| grep "^TELNET" > debug.log}
+ This one shows how to log only Telnet negotiations. Piping the
+ debug log through grep or egrep lets you log only specific
+ information, rather than everything. "man grep" for further
+ info.
+
+ LOG DEBUG {| gzip -c > debug.log.gz}
+ Creates a full debug log, but compressed by gzip to save space.
+
+ LOG PACKETS {| tr "\\01" "X" | cut -c9- > packet.log}
+ This one writes the regular packet log, but translates the
+ Ctrl-A that starts each packet to the letter "X" and removes the
+ s-nn-nn- notation from the beginning of each line. Note the
+ double backslash (normal Kermit quoting rules). "man tr" and
+ "man cut" for further info.
+
+ See [369]Section 2.12 for information about the new connection log.
+
+1.14. Automatic File-Transfer Packet Recognition at the Command Prompt
+
+ Beginning in version 7.0, C-Kermit can recognize Kermit (and in some
+ cases also Zmodem) file-transfer packets while at its command prompt.
+ This is convenient (for example), if you escaped back from a remote
+ Kermit program and told the local Kermit program to send a file, but
+ forgot to tell the remote Kermit program to receive it (and the local
+ Kermit did not have the "send a Kermit receive command" feature
+ available). This feature is controlled by the following command:
+
+ SET COMMAND AUTODOWNLOAD { ON, OFF }
+ When ON, which is the default, the command parser recognizes
+ Kermit packets when Kermit is in remote mode. An S packet makes
+ it go into receive mode, an I packet makes it go into server
+ mode. When OFF, packet recognition is disabled and the behavior
+ when a packet is received at the command prompt is as it was in
+ C-Kermit 6.1 and earlier (namely to print an error message).
+
+ COMMAND AUTODOWNLOAD is the command-mode equivalent of TERMINAL
+ AUTODOWNLOAD, which is effective during CONNECT mode.
+
+1.15. The TYPE Command
+
+ The TYPE command now accepts a selection of optional switches
+ ([370]Section 1.5), and also sets several variables.
+
+ Syntax: TYPE [ switches... ] filename
+
+ Variables:
+
+ \v(ty_ln)
+ Line number of current line (during TYPE command; see /PREFIX)
+
+ \v(ty_lc)
+ Line count of file most recently TYPEd.
+
+ \v(ty_mc)
+ Match count of file most recently TYPEd (see /MATCH).
+
+ Switches:
+
+ /PAGE
+ If /PAGE is included, Kermit pauses at the end of each screenful
+ and issues a "more?" prompt. You may press the space bar to view
+ the next page (screenful), or press "q" or "n" to return to the
+ C-Kermit prompt. If this switch is given, it overrides the
+ COMMAND MORE-PROMPTING setting for this command only. If it is
+ not given, paging is according to COMMAND MORE-PROMPTING.
+
+ /NOPAGE
+ Do not pause at the end of each screenful; show the whole file
+ (or all selected lines) at once. If this switch is given, it
+ overrides the COMMAND MORE-PROMPTING setting for this command
+ only. If it is not given, paging is according to COMMAND
+ MORE-PROMPTING.
+
+ /HEAD[:n]
+ Only show the first n lines of the file (where n is a number).
+ If n is omitted, 10 is used.
+
+ /TAIL[:n]
+ Only show the last n lines of the file (where n is a number). If
+ nis omitted, 10 is used. Note: /HEAD and /TAIL can't be
+ combined; if you give both switches, only the most recent one is
+ used.
+
+ /MATCH:pattern
+ Only type lines from the file that match the given pattern (see
+ [371]Section 4.9.1 for pattern notation). UNIX users familiar
+ with grep should note a significant difference: there is no
+ implied "*" at the beginning and end of the pattern. Thus:
+
+ TYPE /MATCH:foo Lists lines whose entire contents are "foo".
+ TYPE /MATCH:foo* Lists lines that start with "foo".
+ TYPE /MATCH:*foo Lists lines that end with "foo".
+ TYPE /MATCH:*foo* Lists lines that have "foo" anywhere in them.
+
+ /HEAD and /TAIL apply after /MATCH, so "type /tail:20 /match:x*"
+ shows the last 20 lines in the file that start with "x".
+
+ /PREFIX:string
+ Print the given string at the beginning of each line. The string
+ may be a constant, a variable, or a quoted variable. If it's an
+ unquoted variable, its value at the time the TYPE command was
+ given is used as a constant. If it is a quoted variable, it is
+ re-evaluated for each line; a useful variable for this context
+ is \v(ty_ln) (the line number of the current line being typed).
+ If the prefix is to include spaces, it must be enclosed in
+ braces. Examples:
+
+ type /prefix:{oofa.txt: } /match:*thing* oofa.txt
+ Prints all lines in oofa.txt that contain "thing" with the
+ filename itself as the prefix (similar to UNIX grep).
+
+ type /prefix:{\v(time). } oofa.txt
+ Prefixes each line of oofa.txt with the time at which the
+ TYPE command was given (one backslash)
+
+ type /prefix:{\\v(time). } oofa.txt
+ Prefixes each line of oofa.txt with the time at which that
+ line is being typed (two backslashes).
+
+ type /prefix:{\\v(ty_ln). } oofa.txt
+ Prefixes each line of oofa.txt with its line number.
+
+ type /prefix:{\\flpad(\\v(ty_ln),4). } oofa.txt
+ Same as the previous example, except the line number is
+ right-adjusted in a 4-column field.
+
+ /WIDTH[:n]
+ Truncates each line at column n (which must be a number) prior
+ to printing it. This option can be used for long lines when you
+ don't want them to wrap. If nis omitted, your current screen
+ width is used.
+
+ /COUNT
+ Counts lines and -- if /MATCH was included, matches -- but does
+ not print any lines from the file. The line and match count is
+ shown at the end, and the variables \v(ty_lc) and \v(ty_lm) are
+ set accordingly.
+
+ SET OPTIONS TYPE { /PAGE, /NOPAGE, /WIDTH:n }
+ Sets the paging default for TYPE commands, which can be
+ overridden in any particular TYPE command by including the
+ desired switch.
+
+ If a TYPE command is given with no switch, and no SET OPTIONS TYPE
+ selection is in effect, paging is according to your COMMAND
+ MORE-PROMPTING setting (SHOW COMMAND).
+
+1.16. The RESET Command
+
+ The RESET command, added in 7.0, closes all open files and logs, but
+ does not affect the open connection (if any).
+
+1.17. The COPY and RENAME Commands
+
+ As of C-Kermit 7.0, in the UNIX version only, the COPY and RENAME
+ commands are built in and do not call the underlying platform's COPY or
+ RENAME command. This allows them to work in "NOPUSH" versions and other
+ circumstances where it can't access system commands, and it allows file
+ copying and renaming to be done portably in scripts. The
+ characteristics of the built-in COPY or RENAME include:
+ * It fails if the source file is a directory or is wild or lacks read
+ access.
+ * It fails if the source file is the destination file.
+ * It allows the destination file to be a directory, in which case the
+ source file is copied (or renamed) into it with the same name.
+ * It overwrites an existing destination file if its permission
+ allows.
+ * It sets the new file's permission according to umask but also
+ carries forward the source file's execute permission bits if the
+ destination file did not already exist.
+ * It fails if interrupted by Ctrl-C.
+ * Upon error, it prints an appropriate message.
+ * It returns standardized error codes that can be tested by IF
+ SUCCESS / FAIL.
+
+ These commands now also accept the following switches:
+
+ /LIST (/LOG, /VERBOSE) = Print "file1 => file2 (OK)" (or error message).
+ /NOLIST (/NOLOG, /QUIET) = Don't print anything (except error messages).
+
+ /NOLIST is the default.
+
+ The same built-in code is used by the UNIX C-Kermit server to execute
+ REMOTE COPY commands (except in this case no switches are available).
+
+ The COPY command also accepts the following additional switches. When
+ any of these are given (and they can be used in any combination except
+ /SWAP and /APPEND), some of the checks listed above are relaxed, and
+ thus it might be possible to get into trouble in certain cases, e.g.
+ when the source and target files are the same file:
+
+ /APPEND = Append source file to destination file.
+ /SWAP-BYTES = Swap bytes (see [372]Section 6.6.5).
+ /FROMB64 = Decode the source file from Base64 encoding.
+ /TOB64 = Encode the target file in Base64.
+
+ Base64 is the encoding commonly used for enclosures in Internet email.
+
+1.18. The MANUAL Command
+
+ The MANUAL command can be used to access the appropriate Kermit manual
+ or other manual. The general syntax is:
+
+ MANUAL [ string ]
+ If the string is omitted, C-Kermit asks the underlying system to
+ access the C-Kermit manual using whatever method is appropriate
+ for the system.
+
+ The specific action depends on the system. In UNIX, a "man" command is
+ issued; "kermit" is the default argument but other manual topics may be
+ specified. If the "man" command allows index or string searching, the
+ appropriate syntax may be included.
+
+ In Kermit 95, the MANUAL command brings up the HTML online K95 manual.
+
+ In VMS and elsewhere, "man" is simply translated to "help", with a
+ default argument of "kermit"; other and/or additional arguments may be
+ included according to the definition of the system's "help" command.
+
+ Correct operation of the "man" command in C-Kermit depends on the
+ appropriate man page or help topic having been installed in the right
+ place with the right permissions and format.
+
+1.19. String and Filename Matching Patterns
+
+ A pattern is a string that includes special notation for matching
+ classes or sequences of characters. C-Kermit 7.0 / K95 1.1.19 supports
+ patterns in several places:
+
+ * Filenames ([373]Section 4.9)
+ * SWITCH case labels ([374]Section 7.18)
+ * The new IF MATCH statement ([375]Section 7.4)
+ * TYPE /MATCH ([376]Section 1.15)
+ * SET FILE TEXT-PATTERNS and BINARY-PATTERNS ([377]Section 4.3)
+ * The \fsearch() and \farraylook() functions ([378]Sections 7.3 and
+ [379]7.10.7)
+ * The \fpattern() function used with [M,RE]INPUT ([380]Section 7.1)
+
+ Patterns are also called wildcards, especially when used for filename
+ matching. C-Kermit's pattern syntax is explained in [381]Section 4.9.1,
+ and also by the HELP WILDCARDS command.
+
+1.20. Multiple Commands on One Line
+
+ As of C-Kermit 7.0, commands can be grouped together on one line by
+ separating the commands with commas and enclosing the list in braces.
+ For example:
+
+ C-Kermit> { echo One, echo Two, echo Three }
+ C-Kermit> do { echo One, echo Two, echo Three }
+
+ Command lists can be nested:
+
+ [ do ] { echo One, echo Two, if true { echo A, echo B}, echo Three }
+
+ and the END command works as it does in macros:
+
+ [ do ] { echo One, echo Two, if true end, echo Three }
+
+ The "one line" stricture is, of course, pliant to line-continuation
+ conventions, namely that lines ending in hyphen (-) or left brace ({)
+ are to be continued. Thus the first example can also be rendered:
+
+ [ do ] {
+ echo One
+ echo Two
+ echo Three
+ }
+
+ (the "do" is optional).
+
+1.21. What Do I Have?
+
+ C-Kermit can be built for hundreds of different platforms with
+ practically countless configuration options. Certain commands might not
+ be available in certain configurations, etc. Even on the same platform,
+ different builds are possible: "maximum functionality", "minimum size",
+ "maximum performance", and so on. You can find out a lot about the
+ configuration of your C-Kermit program with the SHOW FEATURES command.
+ Of course, a lot of what it says, especially in the bottom part, might
+ seem like gibberish, but can be deciphered with a Rosetta Stone (such
+ as the C-Kermit source or the [382]ckccfg.txt file). In any case, the
+ output from SHOW FEATURES might easily explain why some expected
+ feature is missing, or some buffer is smaller than expected. Here's a
+ sample of the bottom section for the SunOS version:
+
+C-Kermit 7.0.196, 1 Jan 2000
+
+Major optional features included:
+ Network support (type SHOW NET for further info)
+ Telnet Kermit Option
+ Hardware flow control
+ External XYZMODEM protocol support
+ Latin-1 (West European) character-set translation
+ Latin-2 (East European) character-set translation
+ Cyrillic (Russian, Ukrainian, etc) character-set translation
+ Greek character-set translation
+ Hebrew character-set translation
+ Japanese character-set translation
+ Unicode character-set translation
+ Pseudoterminal control
+ REDIRECT command
+ RESEND command
+ Fullscreen file transfer display
+ Control-character unprefixing
+ Streaming
+ Autodownload
+
+Major optional features not included:
+ No Kerberos(TM) authentication
+ No SRP(TM) (Secure Remote Password) protocol
+ No Secure Sockets Layer (SSL) protocol
+ No Transport Layer Security (TLS) protocol
+ No encryption
+ No X Windows forwarding
+
+Host info:
+ Machine: sun4m
+ Model: (unknown)
+ OS: SunOS
+ OS Release: 4.1.3_U1
+ OS Version: 4
+
+Target: sunos41gsc
+GCC version: 2.7.2
+Compiled Dec 31 1999 10:38:54, options:
+ __GNUC__ __STDC__ _POSIX_JOB_CONTROL _SC_JOB_CONTROL ARRAYREFLEN=1024 BIGBUFOK
+ BROWSER BSD4 CK_ANSIC CK_APC CK_AUTODL CK_CURSES CK_DNS_SRV CK_ENVIRONMENT
+ CK_FAST CK_LOGIN CK_MKDIR CK_NAWS CK_PCT_BAR CK_PERMS CK_RECALL CK_RTSCTS
+ CK_SPEED CK_TIMERS CK_TMPDIR CK_TTGWSIZ CK_TTYFD CK_WREFRESH CKEXEC
+ CKFLOAT=double CKGHNLHOST ckmaxfiles=64 CKMAXOPEN=64 CKMAXPATH=1023 CKREALPATH
+ CKREGEX CKSYSLOG CKTUNING CMDBL=32763 CMDDEP=64 CONGSPD DCMDBUF DIRENT DYNAMIC
+ FNFLOAT FORDEPTH=32 GFTIMER HADDRLIST HDBUUCP IFDEBUG IKS_OPTION IKSDB
+ IKSDCONF INBUFSIZE=32768 INPBUFSIZ=4096 MAC_MAX=16384 MACLEVEL=128 MAXDDIR=32
+ MAXDNUMS=4095 MAXGETPATH=128 MAXTAKE=54 MAXWLD=102400 MSENDMAX=1024 NETCMD
+ NETCONN NETPTY NOKVERBS NOSETBUF OBUFSIZE=32768 PARSENSE PATTERNS PIPESEND
+ RENAME RLOGCODE SAVEDUID SELECT SIG_V SOL_SOCKET sparc STREAMING sun SUNOS4
+ SYSTIMEH TCPSOCKET TIMEH TLOG TNCODE TTLEBUF TTSPDLIST UIDBUFLEN=256 UNIX
+ UNPREFIXZERO USE_LSTAT USE_MEMCPY VNAML=4096 WHATAMI XFRCAN Z_MAXCHAN=46
+ z_maxchan=46 ZXREWIND
+
+ byte order: big endian
+
+ sizeofs: int=4 long=4 short=2 char=1 char*=4 float=4 double=8
+
+ floating-point: precision=16 rounding=1
+
+ Without going into detail about what all the notation means, notice a
+ couple things:
+
+ * The Options section shows symbols ("macros") in effect during
+ compilation, together with their values (for those that have
+ values). The options are listed in alphabetical order to make any
+ particular option easier to find.
+ * MAXWLD is the maximum number of files that a wildcard can expand
+ to.
+ * Anything starting with "NO" is a feature (or something other than a
+ feature) that has been deliberately "compiled out", or omitted.
+ * Important items for script writers include: CMDBL=32763 (the size
+ of the command buffer and therefore the maximum length for a macro
+ or variable definition; CMDDEP=64 (the limit on recursion depth);
+ FORDEPTH=32 (the nesting limit on FOR loops); INBUFSIZE=32768 (the
+ size of the INPUT command circular buffer); MAC_MAX=16384 (the
+ maximum number of macros), etc.
+
+ See the [383]ckccfg.txt file for details.
+
+1.22. Generalized File Input and Output
+
+ C-Kermit 7.0 adds a new generalized I/O system for stream files,
+ augmenting (and to some extent, overlapping with) the older OPEN, READ,
+ WRITE, and CLOSE commands. In the new file i/o system, which can be
+ used simultaneously with the old one, all commands are grouped together
+ under the new FILE keyword, and some related functions and variables
+ are added.
+
+1.22.1. Why Another I/O System?
+
+ The well-known LOG, OPEN, READ, WRITE, and CLOSE commands have the
+ following restrictions:
+
+ 1. Only one READ file and one WRITE file can be open at a time.
+ 2. The READ and WRITE commands are strictly line oriented.
+ 3. These commands can not be used with binary files.
+ 4. They do not support read/write access or random access.
+ 5. The syntax is a bit counterintuitive for programmers.
+
+ The new file i/o system allows multiple files to be open at once, in
+ any desired combination of modes (read/write/append) supported by the
+ operating system, for line, block (record), or character i/o, for
+ sequential or random access, using consistent syntax and conventions.
+
+ The new system, however, does not replace the old one, since the old
+ system still must be used for:
+
+ 1. The session, packet, debug, transaction, and connection logs.
+ 2. Reading and writing commands rather than files.
+ 3. Existing scripts.
+
+ The new system works only with regular files, not with commands or
+ pipes or mailboxes or pseudoterminals. No special provisions are made
+ in the FILE commands for handling devices or network connections, nor
+ for preventing you from trying to open them; if the underlying
+ operating system treats them like regular stream disk files, the FILE
+ commands (except, of course SEEK, REWIND, and COUNT) might work with
+ them. (In C programming terms, the FILE commands are, at present,
+ nothing more than a front end to fopen() / fread() / fwrite() /
+ fclose() and friends, which are a portable API to sequential files, but
+ this might change in the future for platforms like VMS and VOS that
+ have more complicated file systems.)
+
+ Definitions:
+
+ Channel
+ A number assigned to a file when it is opened, by which it must
+ be referred to in all input/output operations.
+
+ Read/Write Pointer
+ The current position in an open file, expressed as the 0-based
+ byte count from the beginning.
+
+1.22.2. The FILE Command
+
+ FILE keyword [ switches ] channel [ data ]
+ The keyword specifies the function: FILE OPEN, FILE READ, FILE
+ WRITE, FILE CLOSE, etc. For convenience (and for familiarity to
+ C programmers), the two-word FILE commands can be shortened to
+ the single words FOPEN, FREAD, FWRITE, FCLOSE, and so on.
+ Switches are optional, and modify or amplify the requested file
+ function.
+
+ As in C, Fortran, and other programming languages, open files are
+ referred to by "channels", integers such as 0, 1, 2, 3, and so on. A
+ channel number is assigned when you open a file. The number of
+ available channels depends on the underlying operating system, and can
+ be seen in the variable:
+
+ \v(f_max)
+
+ or by giving the FILE LIST (FLIST) command. Channels are discussed in
+ greater detail in [384]Section 1.22.4.
+
+ FILE command errors can be caught with IF FAIL after the FILE command.
+ In addition, the \v(f_error) variable is set to the completion code of
+ the command: 0 if no error, or a negative number if there was an error.
+ The error codes are listed in [385]Section 1.22.5.
+
+ The command to open a file is:
+
+ FILE OPEN [ switches ] variable filename
+ Opens a file for the type of access specified by the switches,
+ or for read-only access if no switches are given. Upon success,
+ a channel number is assigned to this file and stored in the
+ given variable so you can refer to the open file in subsequent
+ i/o commands. If the file can not be opened, the FILE OPEN
+ command fails. Synonym: FOPEN.
+
+ The FILE OPEN switches are:
+
+ /READ
+ Open the file for read access. If no switches are given, /READ
+ is assumed. If the file does not exist or can't be opened for
+ read access, the FILE OPEN command fails.
+
+ /WRITE
+ Allow writing. If a file of the same name already exists, it is
+ overwritten unless /READ or /APPEND is also included. If a file
+ of the given name does not exist, it is created.
+
+ /APPEND
+ Equivalent to /WRITE, except that if the file exists, it is not
+ destroyed. The read/write pointer is set to the end of the file,
+ so unless you change it with FILE SEEK or REWIND (see below),
+ the first FILE WRITE command adds to the end of the file,
+ preserving what was there already. If /WRITE is also given, it
+ is ignored.
+
+ /BINARY
+ Open the file in "binary" mode, rather than text mode. This
+ switch is meaningless (but still can be used) in UNIX. In VMS,
+ Windows, and OS/2, it inhibits end-of-line processing and
+ conversion, and so should be used for binary files and/or files
+ that are to be accessed in record or character mode rather than
+ line by line.
+
+ The variable for the channel number can be any kind of variable: the
+ \%x kind, a macro name, or an array element. But it must be a variable,
+ not a number -- C-Kermit assigns the channel number; you can't tell it
+ what number to use.
+
+ Example:
+
+ FILE OPEN \%c oofa.txt ; Open oofa.txt for reading.
+ IF FAIL exit 1 Can't open oofa.txt ; Always check to see if it worked.
+ ECHO oofa.txt: channel = \%c
+
+ If the file oofa.txt is opened successfully, a channel number is
+ assigned to the variable \%c. Here's another example using a macro name
+ for the channel number:
+
+ FILE OPEN channel oofa.txt ; Open oofa.txt for reading.
+ IF SUCCESS ECHO oofa.txt: channel = \m(channel)
+
+ Switches can be combined when it makes sense and the underlying
+ operating system allows it. For example, to open a file in binary mode
+ for reading and writing (sometimes called "update"):
+
+ FILE OPEN /READ /WRITE /BINARY \%c budget.db
+
+ Some combinations might be allowed, others not. For example /READ
+ /APPEND will usually not be allowed. /WRITE /APPEND is treated as
+ /APPEND.
+
+ A major advantage of the new system over the older one is that you can
+ have multiple files open at once. Suppose, for example, that you want
+ to open all the files in a certain directory at once:
+
+ .\%n := \ffiles(/usr/olga*,&f) ; Get file list into array.
+ if ( > \%n \v(f_max) ) { ; Make sure there aren't too many.
+ exit 1 {\v(dir): \%n = Too many files}
+ }
+ declare \&c[\%n] ; Make array for channel numbers.
+ for \%i 1 \%n 1 { ; Loop to open every file...
+ file open \&c[\%i] \&f[\%i] ; Try to open this one
+ if fail exit 1 Open error: \&f[\%i] ; Check for failure
+ }
+
+ If this loop completes successfully, the \&c[] array will contain \%n
+ channel numbers of open files in elements 1 through \%n.
+
+ Any file that you open with FILE OPEN stays open until Kermit exits, or
+ you close it explicitly. The command to close a file is:
+
+ FILE CLOSE { ALL, channel }
+ If a channel number is given and the channel refers to an open
+ file, the file is closed and the channel is freed for reuse; if
+ the channel does not refer to an open file, an error message is
+ printed and the command fails. If ALL is specified instead of a
+ specific channel, all files opened with FILE OPEN are closed and
+ if all open files were closed successfully (even if no files
+ were open), the command succeeds; if any open file could not be
+ closed, the command fails; however, all open files that could be
+ closed are still closed. Synonym: FCLOSE.
+
+ FILE CLOSE might fail because, for example, the disk filled up or a
+ quota was exceeded. Example:
+
+ fopen /write \%c new.txt ; Open new.txt for writing.
+ if fail exit 1 ; Check for error.
+ fclose \%c ; Close the file we just opened.
+
+ This creates a 0-length file called new.txt.
+
+ Note that FILE OPEN /WRITE (without /READ or /APPEND) always creates a
+ new file, and therefore destroys any file with the same name that might
+ already exist (assuming you have permission to delete it). To avoid
+ overwriting existing files, simply check first:
+
+ if exist new.txt exit 1 {Fatal - new.txt already exists}
+ fopen /write \%c new.txt
+ if fail ...
+
+ The next two commands give information about open files:
+
+ FILE STATUS channel
+ Tells the name of the file, if any, open on the given channel
+ and the switches it was opened with. The read/write pointer is
+ also shown; this is where the next read or write will occur;
+ "[EOF]" is shown if the current position in the open file is the
+ end -- i.e. the next read will fail if the file was opened in
+ /READ mode; the next write will add material to the end. The
+ current line number (0-based) is also shown if known. The FILE
+ STATUS command succeeds if the channel is open, and fails if
+ there is no open file on the given channel, or if the channel
+ number is invalid or out of range. Synonym: FSTATUS.
+
+ FILE LIST
+ Lists the channel number and name of each open file, along with
+ its OPEN modes (R, W, A, B, RW, etc) and its current read/write
+ pointer or "[EOF]" if it is at the end. Also tells the number of
+ files currently opened with FILE OPEN, plus the maximum number
+ of open files allowed by the system and the maximum number
+ allowed for FILE OPEN. Synonym: FLIST.
+
+ Next come the commands for reading and writing files:
+
+ FILE READ [ switches ] channel [ variable ]
+ Reads data from the file on the given channel number into the
+ variable, if one was given; if no variable was given, the result
+ is printed on the screen. IMPORTANT: The variable should
+ normally be a macro name rather than a \%x or \&x[] variable if
+ you want backslash characters in the file to be taken literally
+ (see pp.408-412 of [386]Using C-Kermit for an explanation; you
+ can also read into a \%x or \&x[] variable, but then you must
+ remember to protect future references to by \fcontents() if you
+ don't want C-Kermit to process any backslashes it might
+ contain). The desired amount of data (according to the switches)
+ is read from the file at the current read/write pointer, and
+ upon completion the read/write position is updated to first byte
+ after the data that was read, no matter what switches were
+ given. Synonym: FREAD.
+
+ FILE WRITE [ switches ] channel text
+ Writes the given text to the file on the given channel number.
+ The text, of course, can be literal text or a variable, or any
+ combination. If the text might contain leading or trailing
+ spaces, it must be enclosed in braces if you want to preserve
+ them. Synonym: FWRITE.
+
+ Before proceeding, a caution about the NUL character. C-Kermit is so
+ named because it is a Kermit program written in the C language. In C,
+ character strings are represented as a sequence of non-NUL bytes
+ terminated by a NUL byte (a byte in which all bits are 0). Thus a C
+ string can not contain NUL bytes; it always ends with the first NUL
+ byte. C-Kermit variables are implemented as C strings and therefore
+ can't contain NUL bytes either, so the FILE READ and FILE WRITE
+ commands do not handle files or strings that contain NUL bytes, except
+ when the /CHARACTER switch is included with the FILE READ or WRITE
+ command, or when /LPAD:0 or /RPAD:0 is given with the FILE WRITE
+ command; these switches are explained below.
+
+ Also note that Kermit can not be used read or write binary numbers in
+ the machine's internal format (integer or floating-point); in general,
+ numbers can be processed only when represented as numeric or
+ floating-point strings.
+
+ FILE READ switches are:
+
+ /LINE
+ Specifies that a line of text is to be read. A line is defined
+ according to the underlying operating system's text-file format.
+ For example, in UNIX a line is a sequence of characters up to
+ and including a linefeed, or the end of the file, which ever
+ comes first. The line terminator (if any) is removed before
+ assigning the text to the variable. If no switches are included
+ with the FILE READ command, /LINE is assumed. Normally this
+ switch should not be used with files opened in /BINARY mode (but
+ nothing prevents it either).
+
+ /SIZE:number
+ Specifies that the given number of bytes (characters) is to be
+ read. The actual number of bytes returned will be less if the
+ end of file is reached (or a NUL byte is encountered). For
+ example, if a file is 514 bytes long, FILE READ /SIZE:512
+ returns 512 bytes the first time and 2 bytes the second time.
+ FILE READ /SIZE provides a kind of "record i/o" for files that
+ do not necessarily contain lines. The resulting block of
+ characters is assigned to the variable without any editing.
+ Synonym: /BLOCK.
+
+ /CHARACTER
+ Equivalent to /SIZE:1. If FILE READ /CHAR succeeds but the
+ variable is empty, this indicates a NUL byte was read. Synonym:
+ BYTE.
+
+ FILE WRITE switches are:
+
+ /LINE
+ Specifies that an appropriate line terminator is to be added to
+ the end of the text. If no switches are included, /LINE is
+ assumed.
+
+ /SIZE:number
+ Specifies that the given number of bytes (characters) is to be
+ written. If the given text is longer than the requested size, it
+ is truncated; if is shorter, it is padded according /LPAD and
+ /RPAD switches. Synonym: /BLOCK.
+
+ /LPAD[:value]
+ If /SIZE was given, but the text is shorter than the requested
+ size, the text is padded on the left with sufficient copies of
+ the character whose ASCII value is given to write the given
+ length. If no value is specified, 32 (the code for Space) is
+ used. The value can also be 0 to write the indicated number of
+ NUL bytes. If /SIZE was not given, this switch is ignored.
+
+ /RPAD[:value]
+ Like LPAD, but pads on the right.
+
+ /CHARACTER
+ Specifies that one character should be written. If the text is
+ empty or not given, a NUL character is written; otherwise the
+ first character of text is given. Synonym: /BYTE.
+
+ /STRING
+ Specifies that the text is to be written as-is, with no
+ terminator added.
+
+ Here's an example in which we copy a text file line by line:
+
+ file open /read \%c oofa.txt ; Open input file
+ if fail exit 1 Can't open input file ; Check that it's open
+ file open /write \%d new.txt ; Open output file
+ if fail exit 1 Can't open output file ; Check
+ while true { ; Loop to copy lines
+ file read /line \%c line ; Read a line
+ if fail break ; Assume failure = end of file
+ file write /line \%d {\m(line)} ; Write the line to output file
+ if fail exit 1 Write failure ; Failure here is fatal
+ }
+ file close \%c ; Close the two files
+ file close \%d
+
+ Note that since /LINE is the default for both FILE READ and FILE WRITE,
+ it can be omitted as in the following example, where we also use the
+ short names for the FILE commands.
+
+ fopen /read \%c oofa.txt ; Open input file
+ if fail exit 1 Can't open input file ; Check that it's open
+ fopen /write \%d new.txt ; Open output file
+ if fail exit 1 Can't open output file ; Check
+ while true { ; Loop to copy lines
+ fread \%c line ; Read a line
+ if fail break ; Assume failure = end of file
+ fwrite \%d {\m(line)} ; Write the line to output file
+ if fail exit 1 Write failure ; Failure here is fatal
+ }
+ fclose \%c ; Close the two files
+ fclose \%d
+
+ Here's the same example using "record i/o" (the open and close
+ sequences are are omitted since they are the same as above). The result
+ is the same, but execution is much faster:
+
+ while true { ; Loop to copy blocks
+ fread /size:512 \%c block ; Read a block into \%a
+ if fail break ; Assume failure = end of file
+ fwrite /string \%d {\m(block)} ; Write the block to output file
+ if fail exit 1 Write failure ; Failure here is fatal
+ }
+
+ Although record i/o is faster, it should not be used in line-oriented
+ applications, since it returns arbitrary chunks of the file to your
+ script, rather than lines. In this example, FWRITE /STRING is used
+ rather than FWRITE /SIZE:512 to avoid the last output block being
+ padded beyond the original file's length.
+
+ A file can also be copied character by character, but this is much
+ slower than line i/o and VERY much slower than block i/o:
+
+ while true { ; Loop to copy blocks
+ fread /char \%c c ; Read a character into c
+ if fail break ; Assume failure = end of file
+ fwrite /char \%d {\m(c)} ; Write character to output file
+ if fail exit 1 Write failure ; Failure is fatal
+ }
+
+ Although character i/o is slow, it is the only way to process files
+ that contain NUL characters (i.e. bytes composed of only zero bits). In
+ the example above, when "fread /char \%c c" returns a NUL, the c
+ variable is empty. But since the FREAD /CHAR command did not fail, we
+ know the result was really a NUL. FWRITE /CHAR, when given an empty
+ variable (or no variable at all) writes a NUL. Thus the loop above will
+ copy any file at all (very slowly). In non-copying applications, NULs
+ are detected like this:
+
+ fread /char \%c c
+ if fail (do something)
+ if not def c (a NUL byte was read)
+
+ Finally some advanced file operations:
+
+ FILE FLUSH channel
+ For output files only: commits all previous writes to disk, in
+ case the computer was buffering them. Synonym: FFLUSH.
+
+ FILE COUNT [ { /BYTES, /LINES, /LIST, /NOLIST } ] channel
+ By default, or if the /BYTES switch is given, counts the bytes
+ in the file, if any, open on the given channel. If the /LINES
+ switch is given, counts lines in the file. If the /LIST switch
+ is given, the result is printed. If the /NOLIST switch is given,
+ the result is not printed. /QUIET is a synonym for /NOLIST. If
+ neither /LIST nor /NOLIST is given, the result is printed if the
+ command is given at top level, i.e. not from a command file or
+ macro. In all cases, the result of the most recent FILE COUNT
+ command is stored in the variable \v(f_count). Note that FILE
+ COUNT /LINE works (and can only work) by reading the entire
+ file; expect it to take some time if the file is large. Synonym:
+ FCOUNT.
+
+ FILE REWIND channel
+ Moves the read/write pointer to the beginning of the file.
+ Equivalent to FILE SEEK channel 0. Synonym: FREWIND.
+
+ FILE SEEK [ switches ] channel { [{+,-}]number, LAST, EOF }
+ Moves the read/write pointer for the file on this channel to the
+ given position, which may be a byte (character) number or a line
+ number, expressed in either absolute or relative terms.
+ Switches:
+
+ /BYTE
+ The number given is a byte number. Synonym: /CHARACTER.
+
+ /LINE
+ The number given is a line number.
+
+ /ABSOLUTE
+ The number given is absolute.
+
+ /RELATIVE
+ The number given is relative to the current position.
+
+ By default, or if the /BYTE switch is given, the number is a
+ byte number (0 = first byte). If /LINE is given, the number is a
+ line number (0 = first line). EOF means to move to the end of
+ the file. LAST means to move to the last line or character of
+ the file, depending on whether it's a line or character seek.
+
+ If neither the /RELATIVE nor the /ABSOLUTE switch is given, then
+ if a signed number is given, the motion is relative to the
+ current position. An expression that evaluates to a negative
+ number is not considered signed for this purpose; that is, a
+ sign (+ or -) must be included as the first character of the
+ number in the command itself to force a relative seek (in the
+ absence of /RELATIVE or /ABSOLUTE).
+
+ If the number has no sign, or if the /ABSOLUTE switch is given,
+ the number represents an absolute position (relative to the
+ beginning of the file). Subsequent FILE READs or WRITEs will
+ take place at the new position.
+
+ If the read/write pointer is placed after the end of the file, a
+ subsequent FILE READ will fail, but a FILE WRITE will succeed
+ (possibly creating a file with "holes"). If a FILE SEEK /BYTE
+ command is given, the current line becomes unknown (unless the
+ position is 0) and subsequent FILE SEEK /RELATIVE /LINE commands
+ will fail until the next non-relative FILE SEEK /LINE command is
+ given. Synonym: FSEEK.
+
+ An absolute FILE SEEK to a negative position fails silently, as does a
+ relative seek to a position before the beginning of the file.
+
+ A caution about relative SEEKs: remember that the number is relative to
+ the current position. Whenever you read or write, this changes the
+ position. In each of the following examples, assume the file open on
+ channel \%c is positioned at line n (the FREAD target variable is
+ omitted for lack of space):
+
+ { FREAD \%c, FSEEK /LINE \%c -1, FREAD \%c } <-- Reads line n twice
+ { FREAD \%c, FSEEK /LINE \%c +0, FREAD \%c } <-- Reads lines n and n+1
+ { FREAD \%c, FSEEK /LINE \%c +1, FREAD \%c } <-- Reads lines n and n+2
+ { FREAD \%c, FSEEK /LINE \%c -2, FREAD \%c } <-- Reads lines n and n-1
+ { FREAD \%c, FSEEK /LINE \%c -3, FREAD \%c } <-- Reads lines n and n-2
+
+ Another caution: Using FSEEK and FREAD /SIZE to repeatedly read the
+ same disk block (e.g. when sampling a database record that is
+ frequently updated) might not give you updated disk blocks due to the
+ internal buffering and caching of the C library (this probably varies
+ from one platform/compiler combination to another). If necessary you
+ can force a fresh disk read with a close/open sequence:
+
+ FCLOS \%c
+ FOPEN \%c samefilename
+ FSEEK \%c samespot
+ FREAD /SIZE:howmanybytes \%c variable
+
+1.22.3. FILE Command Examples
+
+ To read the last 10 lines of a text file into an array:
+
+ fopen /read \%c oofa.txt ; Open the file
+ if fail exit 1 Can't open oofa.txt ; Always check for failure
+ dcl \&a[10] ; Declare a 10-element array
+ fcount /line \%c ; Count lines in the file
+ fseek /line \%c \v(f_count)-10 ; Seek to 10 lines from the end
+ if fail exit 1 Can't seek ; Check for failure
+ for \%i 1 10 1 { fread \%c \&a[\%i] } ; Read the last 10 lines
+ fclose \%c ; Close the file
+
+ Note that blank lines show up as empty (undefined) array elements, for
+ example if you give a "show array a" command at this point. This is
+ normal. You can still use these elements; e.g.:
+
+ for \%i 1 10 1 { echo \%i. \&a[\%i] } ; Display the 10 lines
+
+ Here is how to read the last line of a file (already open on channel
+ \%c):
+
+ fseek /line \%c last ; Seek directly to last line
+
+ Alternatively:
+
+ fseek /line \%c eof ; Seek to end of file
+ fseek /line \%c -1 ; Seek to beginning of last line
+
+ Alternatively:
+
+ fcount /line \%c ; Count the file's lines
+ fseek /line \%c \v(f_count)-1 ; Seek to last line
+ fread \%c ; Read it
+
+ To read every other line from the file (using relative SEEK), skipping
+ the first line:
+
+ fopen /read \%c oofa.txt ; Open the file
+ while ( success ) { ; Loop through lines
+ fseek /line \%c +1 ; Skip a line
+ if success fread \%c ; Read & display a line
+ }
+ fclose \%c ; Close the file
+
+ Here is how to read the lines of a file in reverse order:
+
+ fopen /read \%c oofa.txt ; Open
+ if fail exit 1 ; Check
+ fseek /line \%c last ; Seek to last line
+ while success { ; Loop
+ fread \%c ; Read line
+ fseek /line \%c -2 ; Seek backwards two lines
+ }
+ fclose \%c ; Close the file
+
+ The loop works because a relative SEEK outside the file fails.
+
+ It is also possible to use block i/o to manage random-access files with
+ fixed-length records (as long as they don't contain NUL characters).
+ Suppose, for example, you have a file of "card image" records with
+ fixed-field information about customers, such as:
+
+ Name: Columns 1-32 (column numbers are 1-based)
+ Address: Columns 33-72
+ Balance: Columns 73-80
+
+ The records are indexed by customer number, starting with 0. There are
+ no line terminators separating them. Therefore the record for customer
+ number n starts at position nx 80 (\%n*80).
+
+ Now suppose we received a payment from customer number 173 and want to
+ update the balance:
+
+ .\%n = 173 ; Customer (record) number
+ .\%a = 12.72 ; Amount
+ fopen /read /write \%c customer.db ; Open the file
+ if fail stop 1 OPEN FAILED: \f_errmsg() ; Check
+ fseek /byte \%c 80*\%n ; Seek to record
+ fread /size:80 \%c r ; Read the record
+ if fail stop 1 READ FAILED: \f_errmsg() ; Check (IMPORTANT)
+ .\%b := \fright(\m(r),8) ; Extract the balance
+ .\%b := \ffpadd(\%b,\%a,2) ; Add the new payment
+ if fail stop 1 ARITHMETIC ERROR: \%b/\%a ; Catch bad records
+ .r := {\fleft(\m(r),72)\flpad(\%b,8)} ; Update the record
+ fseek /byte \%c 80*\%n ; Reposition to same spot
+ fwrite /size:80 \%c {\m(r)} ; Replace the record
+ if fail stop 1 WRITE FAILED: \f_errmsg() ; Check
+ fclose \%c ; Close the file
+
+ REMEMBER: Using FILE SEEK to move beyond the end of file can result in
+ a file with holes when writing; when reading, an end-of-file error will
+ occur -- be sure to check for it.
+
+1.22.4. Channel Numbers
+
+ C-Kermit's channel numbers are integers from 0 to some
+ platform-dependent limit, such as 46 or 1985 (the value of \v(f_max)).
+ This is the limit placed by the operating system on the number of files
+ that may be opened by one process or user or job, minus the standard
+ input, output, and error files, and minus the number of files reserved
+ by C-Kermit for logs, OPEN READ and WRITE, and file transfer (and maybe
+ some command files -- the \v(f_max) number can't be exact).
+
+ Although you must include a variable in the FILE OPEN command, to which
+ the channel number is assigned, you don't have to use a variable in the
+ other FILE commands if you know what the number is -- you can just put
+ the number. This saves you a few keystrokes when typing commands at the
+ prompt:
+
+ fopen \%c oofa.txt
+ flist
+ 0. /usr/olga.oofa.txt (R) 0
+
+ This tells the channel number is 0 (the number on the left is the
+ channel file's channel number). Of course you can also find it by
+ echoing the variable:
+
+ echo \%c
+ 0
+
+ Or with "fstatus \%c". Now you can type commands like:
+
+ fread 0
+
+ to read a line from the file. Obviously, however, using digits rather
+ than a variable for the channel number would be poor practice in a
+ script.
+
+ If in commands like:
+
+ fread \%c \%a
+
+ you have trouble remembering which variable is which, note that the
+ channel number is, indeed, a number. Anywhere C-Kermit accepts a number
+ it can also accept an expression, so you can put parentheses around the
+ channel number to remind you it's the channel number and not the
+ variable into which data is to be read:
+
+ fread (\%c) \%a
+
+ Normally channel numbers are assigned sequentially as 0, 1, 2, ... up
+ to the limit. However, once you start closing files, there can be holes
+ in the sequence. New channels are assigned to fill in the holes. Thus
+ you can't depend on channel numbers being in any particular sequence.
+
+1.22.5. FILE Command Errors
+
+ Each FILE command sets the variable \v(f_error) to one of the following
+ values:
+
+ 0 = No error
+ -1 = System error
+ -2 = Attempt to read after end of file
+ -3 = Channel not open
+ -4 = Channel number out of range (negative or too large)
+ -5 = Numeric argument (size, ...) out of range
+ -6 = File not found
+ -7 = Bad or missing filename
+ -8 = Too many files are already open (FILE OPEN only)
+ -9 = Forbidden operation (e.g. write to a read-only file)
+ -10 = Access denied
+ -11 = Illegal combination of OPEN modes (FILE OPEN only)
+ -12 = Buffer overflow
+ -13 = Current line number unknown (for relative line seeks)
+ -14 through -98: Reserved.
+ -99 = Requested operation not implemented in this version of C-Kermit
+ -999 = Unknown error
+
+ When \v(f_error) is -1, this means the FILE command failed because
+ because of a system error, in which case you can examine the following
+ variables:
+
+ \v(errno) = System error number.
+ \v(errstring) = Error message corresponding to \v(errno).
+
+ A special function is available for translating the \v(f_error) code to
+ an error message string:
+
+\f_errmsg([code])
+ If the code is -1, returns error message of the most recent system
+ error; otherwise if the code is a valid \v(f_error) value, the associated
+ message is returned. If the code is omitted, the status message
+ corresponding to the current \v(f_error) value is returned.
+
+ A FILE command that fails prints the appropriate error message
+ automatically, except when the command is READ or SEEK and the error is
+ -2 (end of file); in that case, the command still fails, but does not
+ print a message. This allows constructions such as:
+
+ fopen \%c oofa.txt
+ while success { fread \%c }
+ fclose \%c
+
+ to work as expected, i.e. without an annoying message when the end of
+ file is reached.
+
+1.22.6. File I/O Variables
+
+ The variables associated with the file i/o package are:
+
+ \v(f_count)
+ Result of the most recent FILE COUNT (FCOUNT) command.
+
+ \v(f_error)
+ Numeric error code of most recent FILE command (0 = no error).
+
+ \v(f_max)
+ Maximum number of files open simultaneously.
+
+1.22.7. File I/O Functions
+
+ Some of the FILE commands can also be issued as function calls, which
+ makes script writing a bit more convenient, especially for C
+ programmers. Also, several functions are provided that do not have
+ command equivalents. Each of these functions takes a channel number as
+ the first argument. These functions do not work for OPEN { READ, !READ,
+ WRITE, !WRITE, and APPEND } files.
+
+ \f_status(channel)
+ Returns 0 if the channel is not open, otherwise a number between
+ 1 and 15 which is the sum of the OPEN modes:
+
+ 1 = /READ
+ 2 = /WRITE
+ 4 = /APPEND
+ 8 = /BINARY
+
+ The remaining functions work only for open channels. Each of these
+ functions can fail for the applicable reasons listed in [387]Section
+ 1.22.5. For instructions on handling function errors, see [388]Section
+ 7.12.
+
+ \f_pos(channel)
+ Returns the file's current read/write pointer (0-based). There
+ is no FILE command equivalent.
+
+ \f_line(channel)
+ Returns the file's current line number (0-based), if known,
+ otherwise -1. There is no FILE command equivalent. The line
+ number is known as long as no character or block i/o has been
+ done on the channel.
+
+ \f_handle(channel)
+ Returns the "file handle" of the file. That is, it translates
+ the portable C-Kermit channel number into a system-specific file
+ handle or number that can be passed to other programs on the
+ same platform. In UNIX this is a file descriptor. There is no
+ FILE command equivalent.
+
+ \f_eof(channel)
+ Returns 1 if the read/write pointer of the file on the given
+ channel is at the end of the file, 0 otherwise. Convenient in
+ WHILE statements, e.g.:
+
+ while not \f_eof(\%c) { fread \%c }
+
+ \f_getchar(channel)
+ Equivalent to FREAD /CHAR. Returns the character actually read.
+ If \f_getchar() does not fail but the return value is empty,
+ this means a NULL character was read.
+
+ \f_getline(channel)
+ Equivalent to FREAD /LINE. Returns the line actually read, but
+ with the line terminator stripped. If \f_getline() does not fail
+ but the return value is empty, this normally means an empty line
+ was read.
+
+ \f_getblock(channel,n)
+ Equivalent to FREAD /SIZE:n. Returns the block of characters
+ actually read. If the returned block is smaller than n, it
+ indicates either that the end of file was reached or a NUL
+ character is in the block.
+
+ \f_putchar(channel,c)
+ Equivalent to FWRITE /CHARACTER. Writes the character c. If c
+ contains more than one character, only the first is written. If
+ c is empty a NUL is written. Returns the number of characters
+ written on success, or a negative error code upon failure.
+
+ \f_putline(channel,string)
+ Equivalent to FWRITE /LINE. Writes the string and adds the
+ appropriate line termination character or sequence. If the
+ string is empty or omitted, an empty line is written. Returns
+ the number of characters written on success, or a negative error
+ code upon failure.
+
+ \f_putblock(channel,string)
+ Equivalent to FWRITE /STRING. Writes the string as given. If the
+ string is empty or omitted, nothing is written. Returns the
+ number of characters written on success, or a negative error
+ code upon failure.
+
+1.22.8. File I/O Function Examples
+
+ fopen /read \%c oofa.txt ; Open our favorite file for reading
+ if failure exit 1 ; Check that it's open
+ while not \f_eof(\%c) { ; Loop until EOF
+ .line := \f_getline(\%c) ; Get a line
+ if success echo {\m(line)} ; Echo it
+ }
+ if not \f_eof(\%c) { ; Check reason for loop exit
+ exit 1 File Error: \f_errmsg() ; If not EOF say so.
+ }
+
+ frewind \%c ; Rewind the file
+ while not \f_eof(\%c) { ; Same thing but with block i/o
+ .block := \f_getblock(\%c,256) ; (much faster than line i/o)
+ if success xecho {\m(block)}
+ }
+
+ frewind \%c ; Rewind again
+ while not \f_eof(\%c) { ; Same deal but with character i/o
+ .c := \f_getchar(\%c) ; (much slower than line i/o)
+ if success xecho {\m(c)}
+ }
+ close \%c
+
+ To close all open files (equivalent to FCLOSE ALL):
+
+ for \%i 0 \v(f_max)-1 1 {
+ if \f_status(\%i) fclose \%i
+ }
+
+1.23. The EXEC Command
+
+ The EXEC command is available only in UNIX.
+
+ EXEC [ /REDIRECT ] command [ arg1 [ arg2 [ ... ] ]
+ Runs the given command with the arguments in such a way that the
+ command replaces C-Kermit in memory, and C-Kermit ceases to
+ execute. EXEC is like RUN, except instead of returning to
+ C-Kermit when finished, the command returns to whatever process
+ invoked Kermit.
+
+ In the normal case, no files are closed, so the EXEC'd command inherits
+ the open files, read/write pointers, working directory, process ID,
+ user ID (unless command is SUID), group ID (unless command is SGID),
+ groups, etc. (In UNIX, the EXEC command is simply a front end for
+ execvp().)
+
+ If the /REDIRECT switch is included, then if a connection is open (SET
+ LINE or SET HOST), it becomes the standard input and output of the
+ EXEC'd program. If no connection is open, the /REDIRECT switch has no
+ effect. For example to use C-Kermit for PPP dialing in Linux:
+
+ set modem type usr ; Specify the kind of modem you have
+ set line /dev/ttyS1 ; Specify the device it's connected to
+ set speed 57600 ; and the speed
+ set flow rts/cts ; and flow control.
+ set dial retries 100 ; Try the dial sequence up to 100 times.
+ dial {{9-212-555-1212}{9-212-555-1213}{9-212-555-1214}{9-212-555-1215}}
+ if fail exit 1
+ for \%i 1 16 1 { ; Try up to 16 times to get login prompt
+ input 10 Login: ; Wait 10 sec for it to appear
+ if success break ; Got it - proceed...
+ output \13 ; Send a carriage return and try again
+ }
+ if ( > \%i 16 ) stop 1 NO LOGIN PROMPT
+ lineout \(myuserid) ; Send user ID
+ input 30 assword: ; Wait for Password prompt
+ if fail stop 1 NO PASSWORD PROMPT
+ lineout \m(mypassword) ; Send the password.
+ exec /redirect pppd ; Replace ourselves with pppd.
+
+ In this example we assume that the script has already set up the
+ myuserid and mypassword variables -- normally the password should be
+ prompted for, rather than stored on disk. Notice the advantages over
+ the well-known "chat script":
+ * You don't have to control the modem itself with AT commands;
+ Kermit's DIAL command does this for you.
+ * You can have Kermit automatically redial as many times as you want
+ until it gets a connection (if this is legal in your country).
+ * You can have Kermit fetch the number or numbers from a dialing
+ directory.
+ * You can have Kermit cycle through a list of phone numbers (this is
+ new in C-Kermit 7.0; see [389]Section 2.1.16) without having to
+ enter the numbers in a dialing directory.
+ * Dialing is location-independent; you can use the same script to
+ dial from different areas or countries.
+ * Once the connection is made, the full power of Kermit's script
+ language is available to manage the dialog with the terminal server
+ or other device that answers the phone call.
+
+ NOTE: PPP and SLIP dialing are not available in Windows 95/98/NT/2000,
+ whose APIs do not provide a method for an application to hand over a
+ connection to the PPP or SLIP driver.
+
+1.24. Getting Keyword Lists with '?'
+
+ Suppose you type "te" at the C-Kermit> 6.0 prompt and then Esc or Tab
+ to request keyword completion. Kermit beeps, indicating that more than
+ one command starts with "te". But if you type '?' to see what they are,
+ Kermit shows only "telnet". So why the beep? Because of invisible
+ keywords like "telopt", "terminal", and "text". Lots of keywords are
+ invisible because they are either synonyms for other keywords or else
+ esoteric options to be used only in special circumstances, so we don't
+ want them cluttering up the menus.
+
+ But then there is no way for you to discover them. So in C-Kermit 7.0,
+ if you type '?' AFTER the beginning of a keyword field, then invisible
+ keywords are shown too:
+
+ C-Kermit> te<Esc><BEEP>
+ C-Kermit> te? Command, one of the following:
+ telnet telopt terminal text
+ C-Kermit>te
+
+ But if '?' is typed at the beginning of a field, only visible keywords
+ are shown, as before (so, in this example, if '?' is typed at the
+ C-Kermit> prompt, "telnet" is the only command shown that starts with
+ "te").
+
+2. MAKING AND USING CONNECTIONS The SET LINE, SET HOST, and SET PORT (a
+synonym for SET LINE) commands have new synonyms, in which the word SET is
+replaced by the word OPEN: OPEN LINE, etc. There is no new functionality
+here, but OPEN is a better verb, since SET generally takes no action, whereas
+these commands actually try to open a connection. Furthermore, there is the
+symmetry with CLOSE. 2.0. SET LINE and SET HOST Command SwitchesThe SET LINE
+(SET PORT) and SET HOST commands now allow switches before the device or host
+name, in most cases, and under certain circumstances, also at the end. The
+new syntax is backwards compatible with the previous syntax; thus SET LINE,
+SET PORT, and SET HOST commands in command files written for C-Kermit 6.0 or
+earlier still work. The expanded syntax is:
+
+{ OPEN, SET } { LINE, PORT, HOST } [ switches ] device-or-address [ switches
+]
+
+The first group of switches is:
+
+ /NETWORK-TYPE:{TCP/IP,X.25,PIPE,PTY...}
+ When more than one network type is available, this lets you
+ specify the type of network to use for this connection without
+ affecting your global SET NETWORK TYPE. See [390]Section 2.7
+ about pipes and ptys.
+
+ /USERID:[string]
+ This switch is equivalent to SET LOGIN USERID. If a string is
+ given, it sent to host during Telnet negotiations; if this
+ switch is given but the string is omitted, no user ID is sent to
+ the host. If this switch is not given, your current LOGIN USERID
+ (\v(userid) value), if any, is sent. Unlike most other switches,
+ this one is "sticky", since the value must persist throughout
+ the session in case the server requests the ID string at a later
+ time.
+
+ /CONNECT
+ Enter CONNECT mode immediately and automatically after the
+ device or connection is open. On serial devices, however, when
+ CARRIER-WATCH is not OFF, wait up to 1 second for the Carrier
+ Detect signal to appear before trying to connect, to give the
+ device time to react DTR, which might have been off prior to
+ opening the device.
+
+ /SERVER
+ Enter server mode immediately and automatically after the device
+ or connection is open. Treatment of carrier is the same as for
+ /CONNECT.
+
+ /WAIT
+ /NOWAIT
+ For Telnet connections only: Like SET TELNET WAIT { ON, OFF },
+ but applies only to this connection, and in fact applies only
+ when OPENing this connection (which is usually the only place it
+ matters). Typically you would use TELNET /NOWAIT to make a
+ connection to a misbehaving Telnet server that does not reply to
+ negotiations as required by the Telnet protocol definition.
+
+ Note: /CONNECT and /SERVER switches are not available in the RLOGIN and
+ TELNET commands, since these commands already include an implicit
+ /CONNECT and preclude automatic entry into server mode.
+
+ The /CONNECT and /SERVER switches are especially useful with "set host
+ *" connections. For example, suppose you want to start a Kermit server
+ on socket 3000 of your TCP host. Normally you would have to give the
+ command:
+
+ set host * 3000
+
+ and then wait for a connection to come in, and only then could you give
+ the SERVER command (or else define a macro to do this, and then execute
+ the macro). Now you can do it in one step:
+
+ set host /server * 3000
+
+ This tells C-Kermit to wait for the connection and then enter server
+ mode once it comes in, no matter how long it takes. Similarly, "set
+ host /conn *" can be used to wait for a "chat" connection to come in.
+
+ Another set of switches is available in VMS only, for use only with SET
+ LINE:
+
+ /SHARE
+ Allows the SET LINE device to be opened in shared mode. Normally
+ it makes no sense to open a serial device in shared mode, but
+ it's necessary when C-Kermit is running in an environment such
+ as DECIntact, that opens your job's controlling terminal in such
+ a way that C-Kermit can't open it too, unless it enables SHARE
+ privilege. Note: SHARE privilege is required.
+
+ /NOSHARE
+ Requires that the SET LINE device not be in use by any other
+ process in order for it to be successfully opened by C-Kermit.
+ If neither /SHARE nor /NOSHARE is specified, /NOSHARE is used.
+
+ The second group of switches is:
+
+ /NO-TELNET-INIT
+ Do not send initial Telnet negotiations even if this is a Telnet
+ port.
+
+ /RAW-SOCKET
+ This is a connection to a raw TCP socket ([391]Section 2.3.5).
+
+ /RLOGIN
+ Use Rlogin protocol even if this is not an Rlogin port.
+
+ /TELNET
+ Send initial Telnet negotiations even if this is not a Telnet
+ port.
+
+ As of C-Kermit 7.0 and K95 1.1.19, the TELNET command includes an
+ implicit /TELNET switch. So if you TELNET to a non-TELNET port, Kermit
+ sends initial Telnet negotiations. This makes sense, since that's what
+ "telnet" means.
+
+ If you want to make a connection to a non-Telnet port without sending
+ initial Telnet negotiations, use:
+
+ set host [ /connect ] name-or-address port
+
+ or:
+
+ telnet name-or-address port /no-telnet-init
+
+ Additional switches might be added in the future; type "set host ?" or
+ "set line ?" to see a current list.
+
+2.1. Dialing
+
+ Automatic redialing is illegal or restricted in many countries, so
+ until C-Kermit 7.0, it was disabled by default, i.e. until a SET DIAL
+ RETRIES command was given. In C-Kermit 7.0, if no SET DIAL RETRIES
+ command has been given, a default is picked dynamically at DIAL time
+ based on the calling country code, if known. At this writing, the only
+ country code known to have no restrictions on automatic redialing is 1.
+ So in this case a limit of 10 is chosen; otherwise 1. If you have not
+ given an explicit SET DIAL RETRIES command, SHOW DIAL shows the value
+ as "(auto)", and then the value actually used is shown when you give
+ the DIAL command.
+
+ As of C-Kermit 7.0, automatic redialing is automatically canceled if
+ the call could not be placed because no dialtone was detected.
+
+2.1.1. The Dial Result Message
+
+ If DIAL DISPLAY is not ON, the "Call complete" message now shows the
+ modem's call result message, for example:
+
+ Dialing: ...
+ Call complete: "CONNECT 31200/ARQ/V32/LAPM/V42BIS"
+
+ The exact format and contents of this message, of course, depends on
+ the make, model, and configuration of your modem, so use your modem
+ manual to interpret it. The call result message is also available in
+ C-Kermit's \v(dialresult) variable.
+
+ C-Kermit> echo \v(dialresult)
+ CONNECT 31200/ARQ/V32/LAPM/V42BIS
+ C-Kermit> echo Speed = \fword(\v(dialresult),2)
+ Speed = 31200
+ C-Kermit>
+
+ Suppose your modem reports the modulation speed as shown above and you
+ want to ensure your call is completed at (say) 24000 bps or more. You
+ can use a little macro to do the job:
+
+define HSDIAL { ; High Speed DIAL
+ local \%s
+ if < \v(argc) 1 if not def \v(dialnumber) end 1 Usage: \%0 number
+ set dial retries 100
+ set dial interval 1
+ while true {
+ dial \%*
+ if fail end 1 DIAL failed.
+ asg \%s \fword(\v(dialresult),2)
+ if def \%s if numeric \%s if not < \%s 24000 break
+ }
+}
+
+ (See [392]Section 7.5 about the \%* variable.)
+
+2.1.2. Long-Distance Dialing Changes
+
+ Due to the glut of cell phones, pagers, fax machines, ISPs, etc, area
+ codes and dialing rules are changing all the time. In the North
+ American Numbering Plan (NANP) countries (USA, Canada, etc), area codes
+ are split or overlayed with increasing frequency, and 10- and 11-digit
+ dialing is gradually becoming the norm for local calls. Changes are
+ occurring In Europe, too, partly for these reasons and partly because
+ of some new EC rules.
+
+ In France, effective 18 October 1996, all calls, even local ones, must
+ be dialed with an area code. French area codes are presently 1-digit
+ numbers, 1-6, and the long-distance dialing prefix is 0. All calls
+ within France are considered long distance and begin with 01, 02, ...,
+ 06.
+
+ Effective 1 May 1997, all calls within the US state of Maryland, even
+ local ones, must be dialed with an area code but without the
+ long-distance prefix -- this is the now widely-known North American
+ phenomenon of "ten digit dialing". The same is happening elsewhere --
+ many cities in Florida adopted 10-digit dialing in 1998.
+
+ In Italy beginning 19 June 1998, all calls to fixed (as opposed to
+ mobile) numbers must be prefixed by 0. When calling into Italy from
+ outside, the 0 must follow the country code (39). Calls to cell phones,
+ however, must be placed without the 0. Then on 29 December 2000, the 0
+ will become a 4 (for calling fixed numbers) and a prefix of 3 must used
+ for calling mobile phones. More info at:
+ http://www.telecomitalia.it/npnn/.
+
+ In Spain, effective 4 April 1998, with hard cutover on 18 July 1998,
+ all calls within the country must be dialed with 9 digits, and all
+ calls from outside Spain must also be dialed with 9 digits (after the
+ country code, 34). The new 9-digit numbers all begin with "9". More
+ info at: [393]http://www.telefonica.es/cambiodenumeracion/
+
+ Several new dialing features and commands have been added in version
+ 6.1 and 7.0 to address these changes.
+
+ C-Kermit 6.0 and Kermit 95 1.1.11 and earlier handle the French
+ situation via a reasonable subterfuge (setting the local area code to a
+ nonexistent one), but did not handle "ten-digit dialing" well at all;
+ the recommended technique was to change the long-distance dialing
+ prefix to nothing, but this defeated Kermit's "list numbers for one
+ name" feature when the numbers were in different locations. For
+ example:
+
+ set dial ld-prefix
+ dial onlineservice
+
+ where "onlineservice" is a dialing directory entry name corresponding
+ to entries that are in (say) Maryland as well as other states, would
+ not correctly dial the numbers not in Maryland.
+
+ A new command lets you specify a list of area codes to be considered
+ local, except that the area code must be dialed:
+
+ SET DIAL LC-AREA-CODES [ areacode [ areacode [ areacode [ ... ] ] ] ]
+ The list may include up to 32 area codes. If a number is called
+ whose area code is in this list, it is dialed WITHOUT the
+ long-distance prefix, but WITH the area code.
+
+ So in Maryland, which (last time we looked) has two area codes, 410 and
+ 301, the setup would be:
+
+ SET DIAL LC-AREA-CODES 410 301
+
+ Example:
+
+ SET DIAL LD-PREFIX 1
+ SET DIAL AREA-CODE 301
+ SET DIAL LC-AREA-CODES 410 301 <-- Area codes in 10-digit dialing region
+ DIAL +1 (301) 765-4321 <-- Dials 3017654321 (local with area code)
+ DIAL +1 (410) 765-4321 <-- Dials 4107654321 (local with area code)
+ DIAL +1 (212) 765-4321 <-- Dials 12127654321 (long distance)
+
+ The SET DIAL LC-AREA-CODES command does not replace the SET DIAL
+ AREA-CODE command. The latter specifies the area code you are dialing
+ from. If the called number is in the same area code, then the area code
+ is dialed if it is also in the LC-AREA-CODES list, and it is not dialed
+ otherwise. So if "301" had not appeared in the LC-AREA-CODES list in
+ the previous example:
+
+ SET DIAL LD-PREFIX 1
+ SET DIAL AREA-CODE 301
+ SET DIAL LC-AREA-CODES 410 <-- Area codes in 10-digit dialing region
+ DIAL +1 (301) 765-4321 <-- Dials 7654321 (local)
+ DIAL +1 (410) 765-4321 <-- Dials 4107654321 (local with area code)
+ DIAL +1 (212) 765-4321 <-- Dials 12127654321 (long distance)
+
+ The new Kermit versions also add a Local Call Prefix and Local Call
+ Suffix, in case you have any need for it. These are added to the
+ beginning and of local phone numbers (i.e. numbers that are not
+ long-distance or international). Examples:
+
+ SET DIAL LD-PREFIX 1
+ SET DIAL LC-PREFIX 9
+ SET DIAL LC-SUFFIX *
+ SET DIAL LC-AREA-CODES 410 <-- Area codes in 10-digit dialing region
+ SET DIAL AREA-CODE 301
+ DIAL +1 (301) 765-4321 <-- Dials 97654321* (local)
+ DIAL +1 (410) 765-4321 <-- Dials 94107654321* (local with area code)
+ DIAL +1 (212) 765-4321 <-- Dials 12127654321 (long distance)
+
+2.1.3. Forcing Long-Distance Dialing
+
+ Suppose a number is in your country and area, but for some reason you
+ need to dial it long-distance anyway (as is always the case in France).
+ There have always been various ways to handle this:
+
+ 1. Temporarily set your area code to a different (or nonexistent or
+ impossible) one (but this required knowledge of which area codes
+ were nonexistent or impossible in each country).
+ 2. Dial the number literally instead of using the portable format, but
+ this defeats the purpose of the portable dialing directory.
+
+ Now there is also a new command that, very simply, can force
+ long-distance dialing:
+
+ SET DIAL FORCE-LONG-DISTANCE { ON, OFF }
+ If a call is placed to a portable phone number within the same
+ country code as the calling number, it is dialed with the
+ long-distance prefix and the area code if FORCE-LONG-DISTANCE is
+ ON. If OFF, the regular rules and procedures apply.
+
+ Example (France):
+
+ SET DIAL COUNTRY-CODE 33
+ SET DIAL AREA-CODE 6
+ SET DIAL FORCE-LONG-DISTANCE ON
+
+ (In fact, SET DIAL COUNTRY-CODE 33 automatically sets DIAL
+ FORCE-LONG-DISTANCE ON...)
+
+ Example (USA, for a certain type of reverse-charge calling in which the
+ called number must always be fully specified):
+
+ SET DIAL PREFIX 18002666328$ ; 1-800-COLLECT
+ SET DIAL COUNTRY-CODE 1
+ SET DIAL AREA-CODE 212
+ SET DIAL FORCE-LONG-DISTANCE ON
+
+ Example (Toronto, where calls to exchange 976 within area code 416 must
+ be dialed as long distance, even when you are dialing from area code
+ 416):
+
+ SET DIAL COUNTRY-CODE 1
+ SET DIAL AREA-CODE 416
+ SET DIAL FORCE-LONG-DISTANCE ON
+ DIAL +1 (416) 976-xxxx
+
+ If dialing methods were consistent and sensible, of course it would be
+ possible to always dial every domestic call as if it were long
+ distance. But in many locations this doesn't work or if it does, it
+ costs extra. The following macro can be used for dialing any given
+ number with forced long-distance format:
+
+ define LDIAL {
+ local \%x
+ set dial force-long-distance on
+ dial \%*
+ asg \%x \v(success)
+ set dial force-long-distance off
+ end \%x
+ }
+
+ (See [394]Section 7.5 about the \%* variable.)
+
+2.1.4. Exchange-Specific Dialing Decisions
+
+ This applies mainly to the North American Numbering Plan (NANP). Refer
+ to the section "Alternative notations" in [395]Using C-Kermit 2nd
+ Edition, pages 106-107, and the story about Toronto on page 110. Using
+ the new LC-AREA-CODES list, we can address the problem by treating the
+ exchange as part of the area code:
+
+ SET DIAL LD-PREFIX 1
+ SET DIAL AREA-CODE 416
+ SET DIAL LC-AREA-CODES 905276
+ DIAL +1 416 765 4321 <-- 7654321 (local)
+ DIAL +1 905 276 4321 <-- 9052764321 (local with area code)
+ DIAL +1 905 528 4321 <-- 19055284321 (long distance)
+
+ The same technique can be used in Massachusetts (story at top of page
+ 111) and in any other place where dialing to some exchanges within a
+ particular area code is local, but to others in the same area code is
+ long distance.
+
+2.1.5. Cautions about Cheapest-First Dialing
+
+ Kermit does not maintain a knowledge base of telephony information; it
+ only provides the tools to let you enter a phone number in a standard
+ format and dial it correctly from any location in most cases.
+
+ In particular, Kermit does not differentiate the charging method from
+ the dialing method. If a call that is DIALED as long-distance (e.g.
+ from 212 to 718 in country code 1) is not CHARGED as long distance, we
+ have no way of knowing that without keeping a matrix of charging
+ information for every area-code combination within every country, and
+ any such matrix would be obsolete five minutes after it was
+ constructed. Thus, "cheapest-first" sorting is only as reliable as our
+ assumption that the charging method follows the dialing method. A good
+ illustration would be certain online services that have toll-free
+ dialup numbers which they charge you a premium (in your online service
+ bill) for using.
+
+2.1.6. Blind Dialing (Dialing with No Dialtone)
+
+ C-Kermit's init string for Hayes-like modems generally includes an X4
+ command to enable as many result codes as possible, so that Kermit can
+ react appropriately to different failure reasons. One of the result
+ codes that X4 enables is "NO DIALTONE". A perhaps not obvious side
+ effect of enabling this result code that the modem must hear dialtone
+ before it will dial.
+
+ It is becoming increasingly necessary to force a modem to dial even
+ though it does not hear a dialtone on the phone line; for example, with
+ PBXs that have strange dialtones, or with phone systems in different
+ countries, or with ISDN phones, etc. This is called "blind dialing".
+
+ C-Kermit 7.0 has two new commands to cope with this situation:
+
+ SET DIAL IGNORE-DIALTONE { ON, OFF }
+ OFF (the default) means to tell the modem to wait for dialtone
+ before dialing. ON means to enable "blind dialing", i.e. tell
+ the modem NOT to wait for dialtone before dialing. Generally
+ this is accomplished by sending ATX3 to the modem just prior to
+ dialing. SET MODEM TYPE xxx and then SHOW MODEM displays
+ Kermit's built-in "ignore dialtone" command.
+
+ SET DIAL COMMAND IGNORE-DIALTONE text
+ This lets you change the built-in ignore-dialtone command (such
+ as ATX3) to whatever you choose, in case the built-in one does
+ not work, or another command works better.
+
+ Notes:
+ 1. The ignore-dialtone command is not sent unless SET DIAL
+ IGNORE-DIALTONE is ON.
+ 2. The ATX3 command generally disables not only NO DIALTONE, but also
+ BUSY. So this will prevent Kermit from detecting when the line is
+ busy. This is a property of the modem, not of Kermit.
+
+2.1.7. Trimming the Dialing Dialog
+
+ The command:
+
+ SET MODEM COMMAND action [ command ]
+
+ is used to override Kermit's built-in modem commands for each action,
+ for each kind of modem in its internal database. If you include a
+ command, this is used instead of the built-in one. If you omit the
+ command, this restores the original built-in command.
+
+ If you want to omit the command altogether, so Kermit doesn't send the
+ command at all, or wait for a response, use:
+
+ SET MODEM COMMAND action {}
+
+ That is, specify a pair of empty braces as the command, for example:
+
+ SET MODEM COMMAND ERROR-CORRECTION ON {}
+
+2.1.8. Controlling the Dialing Speed
+
+ The rate at which characters are sent to the modem during dialing is
+ normally controlled by the built-in modem database. You might want to
+ override this if Kermit seems to be dialing too slowly, or it is
+ sending characters to the modem faster than the modem handle them. A
+ new command was added for this in C-Kermit 7.0:
+
+ SET DIAL PACING number
+ Specifies the number of milliseconds (thousandths of seconds) to
+ pause between each character when sending commands to the modem
+ during DIAL or ANSWER command execution. 0 means no pause at
+ all, -1 (the default) or any other negative number means to use
+ the value from the database. Any number greater than 0 is the
+ number of milliseconds to pause.
+
+ HINT: You might also need to control the rate at which the modem
+ generates Touch Tones during dialing, for example when sending a
+ numeric page. There are two ways to do this. One way is to insert pause
+ characters into the dialing string. For modems that use the AT command
+ set, the pause character is comma (,) and causes a 2-second pause. On
+ most modems, you can use the S8 register to change the pause interval
+ caused by comma in the dialing string. The other way is to set your
+ modem's tone generation interval, if it has a command for that. Most
+ AT-command-set modems use S11 for this; the value is in milliseconds.
+ For example on USR modems:
+
+ ATS11=200
+
+ selects an interval of 200 milliseconds to separate each dialing tone.
+
+ Hint: To add S-Register settings or other commands to your dialing
+ procedure, use the new SET MODEM COMMAND PREDIAL-INIT command
+ ([396]Section 2.2.2).
+
+2.1.9. Pretesting Phone Number Conversions
+
+ The LOOKUP command now accepts telephone numbers as well as
+ directory-entry names, for example:
+
+ LOOKUP +1 (212) 7654321
+
+ When given a phone number, LOOKUP prints the result of converting the
+ phone number for dialing under the current dialing rules. For example,
+ if my country code is 1 and my area code is 212, and I am dialing out
+ from a PBX whose outside-line prefix is "93,":
+
+ C-Kermit> lookup +1 (212) 7654321
+ +1 (212) 7654321 => 93,7654321
+ C-Kermit>
+
+ You can also use the \fdialconvert(phone-number) function ([397]Section
+ 2.1.11) to do this programmatically:
+
+ C-Kermit> echo "\fdialconvert(+1 (212) 7654321)"
+ "93,7654321"
+ C-Kermit>
+
+ So the new LOOKUP behaves as follows:
+
+ LOOKUP portable-format-phone-number
+ Displays how the number would actually be dialed Sets FAILURE if
+ there was a conversion error, otherwise SUCCESS.
+
+ LOOKUP literal-format-phone-number
+ Displays the same literal-format-phone-number Always sets
+ SUCCESS.
+
+ LOOKUP dialing-directory-name
+ Displays all matching entries and converts portable phone
+ numbers. Sets SUCCESS if at least one entry was found, otherwise
+ FAILURE.
+
+ LOOKUP =anything
+ Displays "=anything" and sets SUCCESS.
+
+ There is, at present, no programmatic way to fetch numbers from the
+ dialing directory. This will be considered for a future release.
+
+2.1.10. Greater Control over Partial Dialing
+
+ The following rules now apply to partial dialing:
+
+ * Phone number transformations based on country and area code,
+ application of prefixes, etc, are performed only on the first
+ PDIAL.
+ * Each PDIAL argument is looked up in the dialing directory, so it is
+ possible have directory entries for pieces of phone numbers or
+ other information.
+ * Suffixes are not applied automatically, since there is no way for
+ C-Kermit to know in which PDIAL segment you want them to be
+ applied.
+
+ However, the suffix that *would* have been applied, based on the
+ dialing rules that were invoked when processing the first PDIAL
+ command, is stored in the variable:
+
+ \v(dialsuffix)
+
+ which you can include in any subsequent PDIAL or DIAL commands.
+
+ Example:
+
+ pdial {\m(my_long_distance_pager_number_part_1)}
+ pdial {\m(my_long_distance_pager_number_part_2)}
+ pdial {\v(dialsuffix)}
+ pdial {\m(my_long_distance_pager_number_part_3)}
+ pdial {@\m(numeric_pager_code)#}
+
+2.1.11. New DIAL-related Variables and Functions
+
+ \fdialconvert(s)
+ s is a phone number in either literal or portable format (not a
+ dialing directory entry name). The function returns the dial
+ string that would actually be used by the DIAL command when
+ dialing from the current location, after processing country
+ code, area code, and other SET DIAL values, and should be the
+ same as the result of LOOKUP when given a telephone number.
+
+ \v(dialsuffix)
+ Contains the suffix, if any, that was applied in the most recent
+ DIAL command, or the suffix that would have been applied in the
+ most recent PDIAL command. Use this variable to send the dial
+ suffix at any desired point in a PDIAL sequence.
+
+ \v(dialtype)
+ A number indicating the type of call that was most recently
+ placed. Can be used after a normal DIAL command, or after the
+ first PDIAL command in a PDIAL sequence. Values are:
+
+ -2: Unknown because TAPI handled the phone number translation.
+ -1: Unknown because some kind of error occurred.
+ 0: Internal within PBX.
+ 1: Toll-free.
+ 2: Local within calling area.
+ 3: Unknown (e.g. because a literal-format phone number was given).
+ 4: Long distance within country.
+ 5: International
+
+ \v(dialcount)
+ The current value of the DIAL retry counter, for use in a DIAL
+ macro ([398]Section 2.1.13).
+
+ \v(d$px)
+ PBX Exchange (see [399]Section 2.1.12).
+
+ Other dial-related variables, already documented in [400]Using C-Kermit
+ (or other sections of this document, e.g. [401]Section 2.1.1), include
+ \v(dialnumber), \v(dialstatus), etc. A convenient way to display all of
+ them is:
+
+ show variable dial ; hint: abbreviate "sho var dial"
+
+ This shows the values of all the variables whose names start with
+ "dial". Also "show variable d$" (to show the \v(d$...) variables).
+
+2.1.12. Increased Flexibility of PBX Dialing
+
+ Refer to [402]Using C-Kermit, 2nd Edition, pages 107-108. Recall that
+ three commands are needed to configure C-Kermit for dialing from a PBX:
+
+ SET DIAL PBX-EXCHANGE number
+ SET DIAL PBX-INSIDE-PREFIX number
+ SET DIAL PBX-OUTSIDE-PREFIX number
+
+ Unfortunately, this model does not accommodate PBXs that have more than
+ one exchange. For example our PBX at Columbia University (which must
+ handle more than 10,000 phones) has 853-xxxx and 854-xxxx exchanges.
+
+ Beginning in C-Kermit 7.0, the SET DIAL PBX-EXCHANGE command accepts a
+ list of exchanges, e.g.:
+
+ SET DIAL PBX-EXCHANGE 853 854
+
+ (multiple exchanges are separated by spaces, not commas).
+
+ So now when dialing a portable-format number that has the same country
+ and area codes as those of your dialing location, C-Kermit compares the
+ exchange of the dialed number with each number in the PBX Exchange list
+ (rather than with a single PBX Exchange number, as it did formerly) to
+ determine whether this is an internal PBX number or an external call.
+ If it is an external call, then the PBX Outside Prefix is applied, and
+ then the normal dialing rules for local or long-distance calls.
+
+ If it is an inside call, the exchange is replaced by the PBX Inside
+ Prefix. But if the PBX has more than one exchange, a single fixed PBX
+ Inside Prefix is probably not sufficient. For example, at Columbia
+ University, we must dial 3-xxxx for an internal call to 853-xxxx, but
+ 4-xxxx for a call to 854-xxxx. That is, the inside prefix is the final
+ digit of the exchange we are dialing. For this reason, C-Kermit 7.0
+ provides a method to determine the inside prefix dynamically at dialing
+ time, consisting of a new variable and new syntax for the SET DIAL
+ PBX-INSIDE-PREFIX command:
+
+ \v(d$px)
+ This variable contains the exchange that was matched when a PBX
+ internal call was detected. For example, if the PBX exchange
+ list is "853 854" and a call is placed to +1 (212) 854-9999,
+ \v(d$px) is set to 854.
+
+ SET DIAL PBX-INSIDE-PREFIX \fxxx(...)
+ If the PBX Inside Prefix is defined to be a function, its
+ evaluation is deferred until dialing time. Normally, this would
+ be a string function having \v(d$px) as an operand. Of course,
+ you can still specify a constant string, as before.
+
+ So given the following setup:
+
+ SET DIAL COUNTRY-CODE 1
+ SET DIAL AREA-CODE 212
+ SET DIAL PBX-OUTSIDE-PREFIX 93,
+ SET DIAL PBX-EXCHANGE 853 854
+ SET DIAL PBX-INSIDE-PREFIX \fright(\v(d$px),1)
+
+ The following numbers give the results indicated:
+
+ Number Result
+ +1 (212) 854-9876 4-9876
+ +1 (212) 853-1234 3-1234
+ +1 (212) 765-4321 93,765-4321
+ +1 (333) 765-4321 93,1333765-4321
+
+ Furthermore, the K_PBX_XCH environment variable may now be set to a
+ list of exchanges to automatically initialize C-Kermit's PBX exchange
+ list, for example (in UNIX ksh or bash):
+
+ export K_PBX_XCH="853 854"
+
+ (Quotes required because of the space.) Of course, this variable can
+ also be set to a single exchange, as before:
+
+ export K_PBX_XCH=853
+
+2.1.13. The DIAL macro - Last-Minute Phone Number Conversions
+
+ After a DIAL or LOOKUP command is given, a list of phone numbers is
+ assembled from the dialing directory (if any), with all
+ location-dependent conversion rules applied as described in Chapter 5
+ of [403]Using C-Kermit.
+
+ However, additional conversions might still be required at the last
+ minute based on local or ephemeral conditions. So that you can have the
+ final word on the exact format of the dial string, C-Kermit 7.0 lets
+ you pass the converted string through a macro of your own design for
+ final processing before dialing. The relevant command is:
+
+ SET DIAL MACRO [ name ]
+ Specifies the name of a macro to be run on each phone number
+ after all built-in conversions have been applied, just before
+ the number is dialed. If no name is given, no macro is run. The
+ phone number, as it would have been dialed if there were no dial
+ macro, is passed to the macro.
+
+ The dial macro can do anything at all (except start a file transfer).
+ However, the normal use for the macro would be to modify the phone
+ number. For this reason the phone number is passed to the macro as
+ argument number 1 (\%1). To cause a modified number to be dialed, the
+ macro should terminate with a RETURN statement specifying a return
+ value. To leave the number alone, the macro should simply end. Example:
+
+ define xxx return 10108889999$\%1
+ set dial macro xxx
+ dial xyzcorp
+
+ This defines a DIAL MACRO called xxx, which puts an access code on the
+ front of the number. Another example might be:
+
+ def xxx if equal "\v(modem)" "hayes-1200" return \freplace(\%1,$,{,,,,,})
+ set dial macro xxx
+ dial xyzcorp
+
+ which replaces any dollar-sign in the dial string by a series of five
+ commas, e.g. because this particular modem does not support the "wait
+ for bong" feature (remember that commas that are to be included
+ literally in function arguments must be enclosed in braces to
+ distinguish them from the commas that separate the arguments) and when
+ the IF condition is not satisfied, the macro does not return a value,
+ and so the number is not modified. Then when a DIAL command is given
+ referencing a dialing directory entry, "xyzcorp". The macro is
+ automatically applied to each matching number.
+
+ Numerous dial-, modem-, communications-, and time-related variables are
+ available for decision making your dial macro. Type SHOW VARIABLES for
+ a list. Of particular interest is the \v(dialcount) variable, which
+ tells how many times the DIAL command gone through its retry loop: 1 on
+ the first try, 2 on the second, 3 on the third, and so on, and the
+ \v(dialresult) and \v(dialstatus) variables.
+
+ Here are some other applications for the DIAL MACRO (from users):
+
+ * Phone numbers in the dialing directory are formatted with '-' for
+ readability, but some modems don't like the hyphens, so the DIAL
+ macro is used to remove them before dialing; e.g 0090-123-456-78-99
+ becomes 00901234567899: "def xxx return \freplace(\%1,-)".
+ * To set some specific modem (or other) options depending on the
+ called customer or telephone number.
+ * Choosing the most appropriate provider based on (e.g.) time of day,
+ or cycling through a list of providers in case some providers might
+ be busy.
+
+ To illustrate the final item, suppose you have a choice among many
+ phone service providers; the provider is chosen by dialing an access
+ code before the number. Different providers might be better (e.g.
+ cheaper) for certain times of day or days of the week, or for dialing
+ certain locations; you can use the DIAL macro to add the access for the
+ most desirable provider.
+
+ Similarly, when the same number might be reached through multiple
+ providers, it's possible that one provider might not be able to
+ complete the call, but another one can. In that case, you can use the
+ DIAL macro to switch providers each time through the DIAL loop --
+ that's where the \v(dialcount) variable comes in handy.
+
+ The following command can be used to debug the DIAL macro:
+
+ SET DIAL TEST { ON, OFF }
+ Normally OFF, so the DIAL command actually dials. When ON, the
+ DIAL command performs all lookups and number conversions, and
+ then goes through the number list and retry loop, but instead of
+ actually dialing, lists the numbers it would have called if none
+ of the DIAL attempts succeeded (or more precisely, every number
+ was always busy).
+
+2.1.14. Automatic Tone/Pulse Dialing Selection
+
+ SET DIAL METHOD { AUTO, DEFAULT, PULSE, TONE }
+ Chooses the dialing method for subsequent calls.
+
+ Prior to version 7.0, C-Kermit's DIAL METHOD was DEFAULT by default,
+ meaning it does not specify a dialing method to the modem, but relies
+ on the modem to have an appropriate default dialing method set. So, for
+ example, when using Hayes compatible modems, the dial string would be
+ something like ATD7654321, rather than ATDT7654321 or ATDP7654321.
+
+ In C-Kermit 7.0 and K95 1.1.19, the dial method can be set from the
+ environment variable:
+
+ K_DIAL_METHOD
+
+ when Kermit starts. The values can be TONE, PULSE, or DEFAULT, e.g.
+ (UNIX):
+
+ set K_DIAL_METHOD=TONE; export K_DIAL_METHOD
+
+ In the absence of a K_DIAL_METHOD definition, the new default SET DIAL
+ METHOD is AUTO rather than DEFAULT. When DIAL METHOD is AUTO and the
+ local country code is known, then if tone dialing is universally
+ available in the corresponding area, tone dialing is used; if dialing
+ from a location where pulse dialing is mandatory, pulse dialing is
+ used.
+
+ The "tone country" and "pulse country" lists are preloaded according to
+ our knowledge at the time of release. You can see their contents in the
+ SHOW DIAL listing. You can change the lists with:
+
+ SET DIAL TONE-COUNTRIES [ cc [ cc [ ... ] ] ]
+ Replaces the current TONE-COUNTRIES list with the one given.
+ Each cc is a country code; separate them with spaces (not
+ commas). Example:
+
+ set dial tone-countries 1 358 44 46 49
+
+ If no country codes are given, the current list, if any, is
+ removed, in which case SET DIAL METHOD AUTO is equivalent to SET
+ DIAL METHOD DEFAULT.
+
+ SET DIAL PULSE-COUNTRIES [ cc [ cc [ ... ] ] ]
+ Replaces the current PULSE-COUNTRIES list with the one give.
+ Syntax and operation is like SET DIAL TONE-COUNTRIES.
+
+ If the same country code appears in both lists, Pulse takes precedence.
+
+ The SET DIAL TONE- and PULSE-COUNTRIES commands perform no verification
+ whatsoever on the cc's, since almost any syntax might be legal in some
+ settings. Furthermore, there is no facility to edit the lists; you can
+ only replace the whole list. However, since the only purpose of these
+ lists is to establish a basis for picking tone or pulse dialing
+ automatically, all you need to override the effect of the list is to
+ set a specific dialing method with SET DIAL METHOD TONE or SET DIAL
+ METHOD PULSE.
+
+2.1.15. Dial-Modifier Variables
+
+ As of C-Kermit 7.0, dial modifiers are available in the following
+ variables:
+
+ \v(dm_lp) Long pause
+ \v(dm_sp) Short pause
+ \v(dm_pd) Pulse dial
+ \v(dm_td) Tone dial
+ \v(dm_wa) Wait for answer
+ \v(dm_wd) Wait for dialtone
+ \v(dm_rc) Return to command mode
+
+ You can use these in your dial strings in place of hardwired modifiers
+ like "@", ",", etc, for increased portability of scripts. Example:
+
+ C-Kermit>set modem type usrobotics
+ C-Kermit>sho variables dm
+ \v(dm_lp) = ,
+ \v(dm_sp) = /
+ \v(dm_pd) = P
+ \v(dm_td) = T
+ \v(dm_wa) = @
+ \v(dm_wd) = W
+ \v(dm_rc) = ;
+ C-Kermit>exit
+
+2.1.16. Giving Multiple Numbers to the DIAL Command
+
+ Prior to C-Kermit 7.0, the only way to give a DIAL command a list of
+ phone numbers to try until one answers was to create a dialing
+ directory that had multiple entries under the same name, and then use
+ that entry name in the DIAL command. Now a list of numbers can be given
+ to the DIAL command directly in the following format:
+
+ dial {{number1}{number2}{number3}...}
+
+ This is the same list format used by SEND /EXCEPT: and other commands
+ that allow a list where normally a single item is given. Restrictions
+ on this form of the DIAL command are:
+
+ * The first two braces must be adjacent; spacing is optional
+ thereafter.
+ * Each number must be an actual number to dial, not a dialing
+ directory entry.
+ * Dialing directory entries may not contain number lists in this
+ format.
+
+ In all other respects, the numbers are treated as if they had been
+ fetched from the dialing directory; they can be in literal or portable
+ format, etc. Example:
+
+ dial {{7654321} {+1 (212) 5551212} { 1-212-5556789 }}
+
+ The list can be any length at all, within reason.
+
+ This feature is especially handy for use with the K95 Dialer, allowing
+ a list of phone numbers to be specified in the Telephone Number box
+ without having to set up or reference a separate dialing directory.
+
+ You can also use it to add commonly-dialed sequences as variables in
+ your C-Kermit customization file, e.g.:
+
+ define work {{7654321}{7654322}{7654323}}
+
+ and then:
+
+ dial {\m(work)}
+
+ (the variable name must be enclosed in braces).
+
+ Or more simply:
+
+ define work dial {{7654321}{7654322}{7654323}}
+
+ and then:
+
+ work
+
+2.2. Modems
+
+2.2.1. New Modem Types
+
+ Since C-Kermit 6.0:
+
+ atlas-newcom-33600ifxC Atlas/Newcom 33600
+ att-keepintouch AT&T KeepinTouch PCMCIA V.32bis Card Modem
+ att-1900-stu-iii AT&T Secure Data STU-III Model 1900
+ att-1910-stu-iii AT&T Secure Data STU-III Model 1910
+ bestdata Best Data
+ cardinal Cardinal V.34 MVP288X series.
+ compaq Compaq Data+Fax (e.g. in Presario)
+ fujitsu Fujitsu Fax/Modem Adapter
+ generic-high-speed Any modern error-correcting data-compressing modem
+ itu-t-v25ter/v250 ITU-T (CCITT) V.25ter (V.250) standard command set
+ megahertz-att-v34 Megahertz AT&T V.34
+ megahertz-xjack Megahertz X-Jack
+ motorola-codex Motorola Codex 326X Series
+ motorola-montana Motorola Montana
+ mt5634zpx Multitech MT5634ZPX
+ rockwell-v90 Rockwell V.90 56K
+ rolm-244pc Siemens/Rolm 244PC (AT command set)
+ rolm-600-series Siemens/Rolm 600 Series (AT command set)
+ spirit-ii QuickComm Spirit II
+ suprasonic SupraSonic V288+
+ supra-express-v90 Supra Express V.90
+
+ One of the new types, "generic-high-speed" needs a bit of explanation.
+ This type was added to easily handle other types that are not
+ explicitly covered, without going through the bother of adding a
+ complete user-defined modem type. This one works for modern modems that
+ use the AT command set, on the assumption that all the default
+ ("factory") settings of the modem (a) are appropriate for Kermit, (b)
+ include error correction, data compression, and speed buffering; and
+ (c) are recallable with the command AT&F.
+
+ If the command to recall your modem's profile is not AT&F, use the SET
+ MODEM COMMAND INIT-STRING command to specify the appropriate modem
+ command. The default init-string is AT&F\13 (that is, AT, ampersand, F,
+ and then carriage return); a survey of about 20 modern modem types
+ shows they all support this, but they might mean different things by
+ it. For example, the USR Sportster or Courier needs AT&F1 (not AT&F,
+ which is equivalent to AT&F0, which recalls an inappropriate profile),
+ so for USR modems:
+
+ set modem type generic-high-speed
+ set modem command init AT&F1\13
+
+ Of course, USR modems already have their own built-in modem type. But
+ if you use this one instead, it will dial faster because it has fewer
+ commands to give to the modem; in that sense "&F1" is like a macro that
+ bundles numerous commands into a single one. See your modem manual for
+ details about factory profiles and commands to recall them.
+
+ WARNING: Do not use the generic-high-speed modem type in operating
+ systems like VMS where hardware flow control is not available, at least
+ not unless you change the init string from AT&F\13 to something else
+ that enables local Xon/Xoff or other appropriate type of flow control.
+
+ Also see [404]Section 2.1.7 for additional hints about making dialing
+ go faster.
+
+2.2.2. New Modem Controls
+
+ SET MODEM CAPABILITIES list
+ In C-Kermit 7.0, this command automatically turns MODEM
+ SPEED-MATCHING OFF if SB (Speed Buffering) is in the list, and
+ turns it ON if SB is absent.
+
+ SET MODEM COMMAND PREDIAL-INIT [ text ]
+ Commands to be sent to the modem just prior to dialing. Normally
+ none.
+
+ SET MODEM SPEAKER { ON, OFF }
+ Determines whether modem speaker is on or off while call is
+ being placed. ON by default. Note: This command does not provide
+ fine-grained control over when the speaker is on or off.
+ Normally, ON means while the call is being placed, until the
+ point at which carrier is successfully established. If your
+ modem has a different speaker option that you want to choose,
+ then use the SET MODEM COMMAND SPEAKER ON text command to
+ specify this option.
+
+ SET MODEM COMMAND SPEAKER { ON, OFF } [ text ]
+ Specify or override the commands to turn your modem's speaker on
+ and off.
+
+ SET MODEM VOLUME { LOW, MEDIUM, HIGH }
+ When MODEM SPEAKER is on, select volume. Note: In some modems,
+ especially internal ones, these commands have no effect; this is
+ a limitation of the particular modem, not of Kermit.
+
+ SET MODEM COMMAND VOLUME { LOW, MEDIUM, HIGH } [ text ]
+ Specify or override the commands to set your modem's speaker
+ volume.
+
+ SET MODEM COMMAND IGNORE-DIALTONE [ text ]
+ The command to enable blind dialing ([405]Section 2.1.6).
+
+ SET MODEM ESCAPE-CHARACTER code
+ Has been augmented to allow codes of 0 or less: < 0 means the
+ escape mechanism is disabled. = 0 means to use (restore) the
+ default value from the modem database. > 0 and < 128 is a
+ literal value to be used instead of the default one. > 127 means
+ the escape mechanism is disabled. This affects "modem hangup".
+ When the escape mechanism is disabled, but SET MODEM
+ HANGUP-METHOD is MODEM-COMMAND, it sends the hangup command
+ immediately, without the <pause>+++<pause> business first. This
+ is useful (for example) when sending lots of numeric pages, a
+ process in which never we go online, and so never need to escape
+ back. Eliminating the unnecessary pauses and escape sequence
+ allows a lot more pages to be sent per unit time.
+
+ Recall that C-Kermit can dial modems to which it is connected via
+ TCP/IP (Telnet or Rlogin) as described on page 126 of [406]Using
+ C-Kermit, 2nd Ed. In this case the MODEM HANGUP-METHOD should be
+ MODEM-COMMAND, since RS-232 signals don't work over TCP/IP connections.
+ As noted in the manual, such connections are set up by the following
+ sequence:
+
+ set host host [ port ]
+ set modem type name
+ dial number
+
+ But this can cause complications when you use Kermit to switch between
+ serial and TCP/IP connections. In the following sequence:
+
+ set host name
+ set modem type name
+ set port name
+
+ the first two commands obey the rules for dialing out over Telnet.
+ However, the SET PORT command requires that Kermit close its current
+ (Telnet) connection before it can open the serial port (since Kermit
+ can only have one connection open at a time). But since a modem type
+ was set after the "set host" command was given, Kermit assumes it is a
+ Telnet dialout connection and so sends the modem's hangup sequence is
+ sent to the Telnet host. To avoid this, close the network connection
+ explicitly before opening the serial one:
+
+ set host name
+ close
+ set modem type name
+ set port name
+
+2.3. TELNET and RLOGIN
+
+ For additional background, please also read the [407]TELNET.TXT file,
+ also available on the Web in [408]HTML format.
+
+ Cautions:
+
+ * If making a Telnet connection with C-Kermit takes a very long time,
+ like over a minute, whereas the system Telnet program makes the
+ same connection immediately, try including the /NOWAIT switch:
+ C-Kermit> telnet /nowait hostname
+
+ See [409]TELNET.TXT or [410]TELNET.HTM for details. If it also
+ takes a very long time to make a Telnet connection with system
+ Telnet, then the delay is most likely caused by reverse DNS lookups
+ when your host is not properly registered in DNS.
+ * When supplying numeric IP addresses to C-Kermit or to any other
+ application (regular Telnet, Rlogin, etc), do not include leading
+ 0's in any fields unless you intend for those fields to be
+ interpreted as octal (or hex) numbers. The description of the
+ Internet address interpreter (the sockets library inet_addr()
+ routine) includes these words:
+
+ All numbers supplied as "parts" in a "." notation may be decimal,
+ octal, or hexadecimal, as specified in the C language (that is, a
+ leading 0x or 0X implies hexadecimal; otherwise, a leading 0 implies
+ octal; otherwise, the number is interpreted as decimal).
+ To illustrate, 128.59.39.2 and 128.059.039.002 are not the same
+ host! Even though most of the fields contain non-octal digits.
+ Using system Telnet (not Kermit):
+ $ telnet 128.059.039.002
+ Trying 128.49.33.2 ...
+
+ Of course the same thing happens with Kermit because it uses (as it
+ must) the same system service for resolving network addresses that
+ Telnet, FTP, and all other TCP/IP applications use.
+ * The RLOGIN section on page 123 does not make it clear that you can
+ use the SET TELNET TERMINAL-TYPE command to govern the terminal
+ type that is reported by C-Kermit to the RLOGIN server.
+ * Note that the SET TCP commands described on pages 122-123 might be
+ absent; some platforms that support TCP/IP do not support these
+ particular controls.
+
+ New commands:
+
+ TELOPT { AO, AYT, BREAK, CANCEL, EC, EL, EOF, EOR, GA, IP, DMARK,
+ DO, DONT, NOP, SB, SE, SUSP, WILL, WONT }
+ This command was available previously, but supported only DO,
+ DONT, WILL, and WONT. Now it lets you send all the Telnet
+ protocol commands. Note that certain commands do not require a
+ response, and therefore can be used as nondestructive "probes"
+ to see if the Telnet session is still open; e.g.:
+
+ set host xyzcorp.com
+ ...
+ telopt nop
+ if fail stop 1 Connection lost
+
+ SET TCP ADDRESS [ ip-address ]
+ Specifies the IP address of the computer that C-Kermit is
+ running on. Normally this is not necessary. The exception would
+ be if your machine has multiple network adapters (physical or
+ virtual) with a different address for each adapter AND you want
+ C-Kermit to use a specific address when making outgoing
+ connections or accepting incoming connections.
+
+ SET TCP DNS-SERVICE-RECORDS { ON, OFF }
+ Tells C-Kermit whether to try to use DNS SRV records to
+ determine the host and port number upon which to find an
+ advertised service. For example, if a host wants regular Telnet
+ connections redirected to some port other than 23, this feature
+ allows C-Kermit to ask the host which port it should use. Since
+ not all domain servers are set up to answer such requests, this
+ feature is OFF by default.
+
+ SET TCP REVERSE-DNS-LOOKUP { ON, OFF, AUTO }
+ Tells Kermit whether to perform a reverse DNS lookup on TCP/IP
+ connections. This allows Kermit to determine the actual hostname
+ of the host it is connected to, which is useful for connections
+ to host pools, and is required for Kerberos connections to host
+ pools and for incoming connections. If the other host does not
+ have a DNS entry, the reverse lookup could take a long time
+ (minutes) to fail, but the connection will still be made. Turn
+ this option OFF for speedier connections if you do not need to
+ know exactly which host you are connected to and you are not
+ using Kerberos. AUTO, the default, means the lookup is done on
+ hostnames, but not on numeric IP addresses.
+
+ SET TELNET WAIT-FOR-NEGOTIATIONS { ON, OFF }
+ Each Telnet option must be fully negotiated either On or Off
+ before the session can continue. This is especially true with
+ options that require sub-negotiations such as Authentication,
+ Encryption, and Kermit; for proper support of these options
+ Kermit must wait for the negotiations to complete. Of course,
+ Kermit has no way of knowing whether a reply is delayed or not
+ coming at all, and so will wait a minute or more for required
+ replies before continuing the session. If you know that Kermit's
+ Telnet partner will not be sending the required replies, you can
+ set this option of OFF to avoid the long timeouts. Or you can
+ instruct Kermit to REFUSE specific options with the SET TELOPT
+ command.
+
+ SET TELOPT [ { /CLIENT, /SERVER } ] option
+ { ACCEPTED, REFUSED, REQUESTED, REQUIRED }
+ [ { ACCEPTED, REFUSED, REQUESTED, REQUIRED } ]
+ SET TELOPT lets you specify policy requirements for Kermit's
+ handling of Telnet option negotiations. Setting an option is
+ REQUIRED causes Kermit to offer the option to the peer and
+ disconnect if the option is refused. REQUESTED causes Kermit to
+ offer an option to the peer. ACCEPTED results in no offer but
+ Kermit will attempt to negotiate the option if it is requested.
+ REFUSED instructs Kermit to refuse the option if it is requested
+ by the peer.
+
+ Some options are negotiated in two directions and accept
+ separate policies for each direction; the first keyword applies
+ to Kermit itself, the second applies to Kermit's Telnet partner;
+ if the second keyword is omitted, an appropriate
+ (option-specific) default is applied. You can also include a
+ /CLIENT or /SERVER switch to indicate whether the given policies
+ apply when Kermit is the Telnet client or the Telnet server; if
+ no switch is given, the command applies to the client.
+
+ Note that some of Kermit's Telnet partners fail to refuse
+ options that they do not recognize and instead do not respond at
+ all. In this case it is possible to use SET TELOPT to instruct
+ Kermit to REFUSE the option before connecting to the problem
+ host, thus skipping the problematic negotiation.
+
+ Use SHOW TELOPT to view current Telnet Option negotiation
+ settings. SHOW TELNET displays current Telnet settings.
+
+2.3.0. Bug Fixes
+
+ If "set host nonexistent-host" was given (and it properly failed),
+ followed by certain commands like SEND, the original line and modem
+ type were not restored and C-Kermit thought that it still had a network
+ hostname; fixed in 7.0.
+
+2.3.1. Telnet Binary Mode Bug Adjustments
+
+ SET TELNET BUG BINARY-ME-MEANS-U-TOO { ON, OFF } was added to edit 192
+ after the book was printed. Also SET TELNET BUG BINARY-U-MEANS-ME-TOO.
+ The default for both is OFF. ON should be used when communicating with
+ a Telnet partner (client or server) that mistakenly believes that
+ telling C-Kermit to enter Telnet binary mode also means that it, too,
+ is in binary mode, contrary to the Telnet specification, which says
+ that binary mode must be negotiated in each direction separately.
+
+2.3.2. VMS UCX Telnet Port Bug Adjustment
+
+ A new command, SET TCP UCX-PORT-BUG, was added for VMS versions with
+ UCX (DEC TCP/IP), applying only to early versions of UCX, like 2.2 or
+ earlier. If you try to use VMS C-Kermit to make a Telnet connection
+ using a port name (like "telnet", which is used by default), the
+ underlying UCX getservbyname() function might return the service number
+ with its bytes swapped and the connection will fail. If "telnet
+ hostname 23" works, then your version of UCX has this bug and you can
+ put "set tcp ucx-port-bug on" in your CKERMIT.INI file to get around
+ it.
+
+2.3.3. Telnet New Environment Option
+
+ The TELNET NEW-ENVIRONMENT option ([411]RFC 1572) is supported as 7.0.
+ This option allows the C-Kermit Telnet client to send certain
+ well-known variables to the Telnet server, including USER, PRINTER,
+ DISPLAY, and several others. This feature is enabled by default in
+ Windows and OS/2, disabled by default elsewhere. The command to enable
+ and disable it is:
+
+ SET TELNET ENVIRONMENT { ON, OFF }
+
+ When ON, and you Telnet to another computer, you might (or might not)
+ notice that the "login:" or "Username:" prompt does not appear --
+ that's because your username was sent ahead, in which case the remote
+ system might prompt you only for your password (similar to Rlogin). Use
+ "set telnet environment off" to defeat this feature, particularly in
+ scripts where the dialog must be predictable. You can also use this
+ command to specify or override specific well-known environment variable
+ values:
+
+ SET TELNET ENVIRONMENT { ACCT,DISPLAY,JOB,PRINTER,SYSTEMTYPE,USER } [ text ]
+
+2.3.4. Telnet Location Option
+
+ The TELNET LOCATION option ([412]RFC 779) is supported in 7.0. This
+ option allows the C-Kermit Telnet client to send a location string to
+ the server if the server indicates its willingness to accept one. If an
+ environment variable named LOCATION exists at the time C-Kermit starts,
+ its value is used as the location string. If you want to change it,
+ use:
+
+ SET TELNET LOCATION text
+
+ If you omit the text from this command, the Telnet location feature is
+ disabled.
+
+ SET TELNET ENVIRONMENT DISPLAY is used to set the DISPLAY variable that
+ is sent to the host, as well as the XDISPLAY location.
+
+2.3.5. Connecting to Raw TCP Sockets
+
+ The SET HOST and TELNET commands now accept an optional switch,
+ /RAW-SOCKET, at the end, only if you first give a host and a port.
+ Example:
+
+ set host xyzcorp.com 23 /raw-socket
+ set host 128.49.39.2:2000 /raw-socket
+ telnet xyzcorp.com 3000 /raw
+
+ Without this switch, C-Kermit behaves as a Telnet client when (a) the
+ port is 23 or 1649, or (b) the port is not 513 and the server sent what
+ appeared to be Telnet negotiations -- that is, messages starting with
+ 0xFF (IAC). With this switch, Kermit should treat all incoming bytes as
+ raw data, and will not engage in any Telnet negotiations or NVT CRLF
+ manipulations. This allows transparent operation through (e.g.) raw TCP
+ ports on Cisco terminal servers, through the 'modemd' modem server,
+ etc.
+
+2.3.6. Incoming TCP Connections
+
+ Accomplished via SET HOST * port, were introduced in C-Kermit 6.0, but
+ for UNIX only. In Version 7.0, they are also available for VMS.
+
+2.4. The EIGHTBIT Command
+
+ EIGHTBIT is simply a shorthand for: SET PARITY NONE, SET TERMINAL
+ BYTESIZE 8, SET COMMAND BYTESIZE 8; that is, a way to set up an 8-bit
+ clean connection in a single command.
+
+2.5. The Services Directory
+
+ Chapter 7 of [413]Using C-Kermit does not mention the ULOGIN macro,
+ which is used by our sample services directory, CKERMIT.KND. Unlike
+ UNIXLOGIN, VMSLOGIN, etc, this one is for use with systems that require
+ a user ID but no password. Therefore it doesn't prompt for a password
+ or wait for a password prompt from the remote service.
+
+ In version 7.0, the CALL macro was changed to not execute a SET MODEM
+ TYPE command if the given modem type was the same as the current one;
+ otherwise the new SET MODEM TYPE command would overwrite any
+ customizations that the user had made to the modem settings. Ditto for
+ SET LINE / SET PORT and SET SPEED.
+
+2.6. Closing Connections
+
+ Until version 7.0, there was never an obvious and general way to close
+ a connection. If a serial connection was open, it could be closed by
+ "set line" or "set port" (giving no device name); if a network
+ connection was open, it could be closed by "set host" (no host name).
+
+ In version 7.0, a new command closes the connection in an obvious and
+ straightforward way, no matter what the connection type:
+
+ CLOSE [ CONNECTION ]
+
+ The CLOSE command was already present, and required an operand such as
+ DEBUG-LOG, WRITE-FILE, etc, and so could never be given by itself. The
+ new CONNECTION operand is now the default operand for CLOSE, so CLOSE
+ by itself closes the connection, if one is open, just as you would
+ expect, especially if you are a Telnet or Ftp user.
+
+ Also see the description of the new SET CLOSE-ON-DISCONNECT command in
+ [414]Section 2.10.
+
+2.7. Using C-Kermit with External Communication Programs
+
+ C-Kermit 7.0 includes a new ability to create and conduct sessions
+ through other communications programs. Two methods are available:
+
+ 1. Pty (pseudoterminal): The external program is run on a
+ "pseudoterminal", which is controlled by Kermit. This method works
+ with practically any external program, but it is not portable. At
+ this writing, it works only on some (not all) UNIX versions, and
+ not on any non-UNIX platforms.
+ 2. Pipe: The external program's standard input and output are
+ redirected through a "pipe" controlled by Kermit. This method is
+ relatively portable -- it should work across all UNIX versions, and
+ it also works in Windows and OS/2 -- but it is effective only when
+ the external program actually uses standard i/o (and many don't).
+
+ The two methods are started differently but are used the same way
+ thereafter.
+
+ The purpose of this feature is to let you use C-Kermit services like
+ file transfer, character-set translation, scripting, automatic dialing,
+ etc, on connections that Kermit can't otherwise make itself.
+
+ This feature is the opposite of the REDIRECT feature, in which C-Kermit
+ makes the connection, and redirects an external (local) command or
+ program over this connection. In a pty or pipe connection, C-Kermit
+ runs and controls a local command or program, which makes the
+ connection. (The same method can be used to simply to control a local
+ program without making a connection; see [415]Section 2.8.)
+
+ To find out if your version of Kermit includes PTY support, type "show
+ features" and look for NETPTY in the alphabetical list of options. For
+ pipes, look for NETCMD.
+
+ The commands are:
+
+ SET NETWORK TYPE PTY or SET NETWORK TYPE PIPE
+ SET HOST command
+ where command is any interactive command. If the command does
+ not use standard i/o, you must use SET NETWORK TYPE PTY.
+
+ Notes:
+
+ * COMMAND is an invisible synonym for PIPE.
+ * The command and its arguments are case-sensitive in UNIX.
+
+ The SET NETWORK TYPE, SET HOST sequence sets the given network type for
+ all subsequent SET HOST commands until another SET NETWORK TYPE command
+ is given to change it.
+
+ You can also use the new /NETWORK-TYPE:PTY or /NETWORK-TYPE:PIPE (or
+ simply /PIPE or /PTY) switches on the SET HOST command itself:
+
+ SET HOST /NETWORK-TYPE:PIPE command ; These two are the same
+ SET HOST /PIPE command
+
+ SET HOST /NETWORK-TYPE:PTY command ; Ditto
+ SET HOST /PTY command
+
+ These are like SET NETWORK TYPE followed by SET HOST, except they apply
+ only to the connection being made and do not change the global network
+ type setting (see [416]Section 1.5 about the difference between
+ switches and SET commands).
+
+ Include any command-line options with the command that might be needed,
+ as in this example where C-Kermit uses another copy of itself as the
+ communications program:
+
+ SET HOST /PIPE /CONNECT kermit -YQJ xyzcorp.com
+
+ IMPORTANT: In Unix, wildcards and redirectors are interpreted by the
+ shell. If you want to run a program with (say) SET HOST /PTY with
+ its i/o redirected or with wildcard file arguments, you will need to
+ invoke the shell too. Example:
+
+SET HOST /PTY {sh -c "crypt < foo.x"}
+SET HOST /PTY {sh -c "grep somestring *.txt"}
+
+ As usual, if you include the /CONNECT switch, SET HOST enters CONNECT
+ mode immediately upon successful execution of the given command.
+ Therefore new commands are available as a shorthand for SET HOST
+ /CONNECT /PTY and /PIPE:
+
+ PTY [ command ]
+ PIPE [ command ]
+ The PTY and PIPE commands work like the TELNET and RLOGIN
+ commands: they set up the connection (in this case, using the
+ given command) and then enter CONNECT mode automatically (if the
+ PIPE or PTY command is given without a command, it continues the
+ current session if one is active; otherwise it gives an error
+ message).
+
+ The PIPE command is named after the mechanism by which C-Kermit
+ communicates with the command: UNIX pipes. C-Kermit's i/o is "piped"
+ through the given command. Here is a typical example:
+
+ PIPE rlogin -8 xyzcorp.com
+
+ This is equivalent to:
+
+ SET HOST /PIPE rlogin -8 xyzcorp.com
+ CONNECT
+
+ and to:
+
+ SET HOST /PIPE /CONNECT rlogin -8 xyzcorp.com
+
+ IMPORTANT:
+ If you are writing a script, do not use the PIPE, PTY, TELNET,
+ or RLOGIN command unless you really want C-Kermit to enter
+ CONNECT mode at that point. Normally SET HOST is used in scripts
+ to allow the login and other dialogs to be controlled by the
+ script itself, rather than by an actively participating human at
+ the keyboard.
+
+ Throughput of pty and pipe connections is limited by the performance of
+ the chosen command or program and by the interprocess communication
+ (IPC) method used and/or buffering capacity of the pipe or pty, which
+ in turn depends on the underlying operating system.
+
+ In one trial (on SunOS 4.1.3), we observed file transfer rates over an
+ rlogin connection proceeding at 200Kcps for downloads, but only 10Kcps
+ for uploads on the same connection with the same settings (similar
+ disparities were noted in HP-UX). Examination of the logs revealed that
+ a write to the pipe could take as long as 5 seconds, whereas reads were
+ practically instantaneous. On the other hand, using Telnet as the
+ external program rather than rlogin, downloads and uploads were better
+ matched at about 177K each.
+
+ Most external communication programs, like C-Kermit itself, have escape
+ characters or sequences. Normally these begin with (or consist entirely
+ of) a control character. You must be sure that this control character
+ is not "unprefixed" when uploading files, otherwise the external
+ program will "escape back" to its prompt, or close the connection, or
+ take some other unwanted action. When in CONNECT mode, observe the
+ program's normal interaction rules. Of course C-Kermit's own escape
+ character (normally Ctrl-\) is active too, unless you have taken some
+ action to disable it.
+
+ On PTY connections, the underlying PTY driver is not guaranteed to be
+ transparent to control characters -- for example, it might expand tabs,
+ translate carriage returns, generate signals if it sees an interrupt
+ character, and so on. Similar things might happen on a PIPE connection.
+ For this reason, if you plan to transfer files over a PTY or PIPE
+ connection, tell the file sender to:
+
+ SET PREFIXING ALL
+ This causes all control characters to be prefixed and
+ transmitted as printable ASCII characters.
+
+ If the external connection program is not 8-bit clean, you should also:
+
+ SET PARITY SPACE
+ This causes 8-bit data to be encoded in 7 bits using single
+ and/or locking shifts.
+
+ And if it does not make a reliable connection (such as those made by
+ Telnet, Rlogin, Ssh, etc), you should:
+
+ SET STREAMING OFF
+ This forces C-Kermit to treat the connection as unreliable and
+ to engage in its normal ACK/NAK protocol for error detection and
+ correction, rather than "streaming" its packets, as it normally
+ does on a network connection ([417]Section 4.20).
+
+ In some cases, buffer sizes might be restricted, so you might also need
+ to reduce the Kermit packet length to fit; this is a trial-and-error
+ affair. For example, if transfers always fail with 4000-byte packets,
+ try 2000. If that fails too, try 1000, and so on. The commands are:
+
+ SET RECEIVE PACKET-LENGTH number
+ This tells the file receiver to tell the file sender the longest
+ packet length it can accept.
+
+ SET SEND PACKET-LENGTH number
+ This tells the file sender not to send packets longer than the
+ given length, even if the receiver says longer ones are OK. Of
+ course, if the receiver's length is shorter, the shorter length
+ is used.
+
+ If none of this seems to help, try falling back to the bare minimum,
+ lowest-common-denominator protocol settings:
+
+ ROBUST
+ No sliding windows, no streaming, no control-character
+ unprefixing, packet length 90.
+
+ And then work your way back up by trial and error to get greater
+ throughput.
+
+ Note that when starting a PIPE connection, and the connection program
+ (such as telnet or rlogin) prints some greeting or information messages
+ before starting the connection, these are quite likely to be printed
+ with a stairstep effect (linefeed without carriage return). This is
+ because the program is not connected with the UNIX terminal driver;
+ there's not much Kermit can do about it. Once the connection is made,
+ everything should go back to normal. This shouldn't happen on a PTY
+ connection because a PTY is, indeed, a terminal.
+
+ On a similar note, some connection programs (like Solaris 2.5 rlogin)
+ might print lots of error messages like "ioctl TIOCGETP: invalid
+ argument" when used through a pipe. They are annoying but usually
+ harmless. If you want to avoid these messages, and your shell allows
+ redirection of stderr, you can redirect stderr in your pipe command, as
+ in this example where the user's shell is bash:
+
+ PIPE rlogin xyzcorp.com 2> /dev/null
+
+ Or use PTY rather than PIPE, since PTY is available on Solaris.
+
+2.7.0. C-Kermit over tn3270 and tn5250
+
+ Now you can make a connection from C-Kermit "directly" to an IBM
+ mainframe and transfer files with it, assuming it has Kermit-370
+ installed. Because tn3270 is neither 8-bit clean nor transparent to
+ control characters, you must give these commands:
+
+ SET PREFIXING ALL ; Prefix all control characters
+ SET PARITY SPACE ; Telnet connections are usually not 8-bit clean
+
+ and then:
+
+ SET HOST /PTY /CONNECT tn3270 abccorp.com
+
+ or simply:
+
+ pty tn3270 abccorp.com
+
+ SET HOST /PIPE does not work in this case, at least not for file
+ transfer. File transfer does work, however, with SET HOST /PTY,
+ provided you use the default packet length of 90 bytes; anything longer
+ seems to kill the session.
+
+ You can also make connections to IBM AS/400 computers if you have a
+ tn5250 program installed:
+
+ pty tn5250 hostname
+
+ In this case, however, file transfer is probably not in the cards since
+ nobody has ever succeeded in writing a Kermit program for the AS/400.
+ Hint:
+
+ define tn3270 {
+ check pty
+ if fail end 1 Sorry - no PTY support...
+ pty tn3270 \%*
+ }
+
+ Similarly for tn5250. Note that CHECK PTY and CHECK PIPE can be used in
+ macros and scripts to test whether PTY or PIPE support is available.
+
+2.7.1. C-Kermit over Telnet
+
+ Although C-Kermit includes its own Telnet implementation, you might
+ need to use an external Telnet program to make certain connections;
+ perhaps because it has access or security features not available in
+ C-Kermit itself. As noted above, the only precautions necessary are
+ usually:
+
+ SET PREFIXING ALL ; Prefix all control characters
+ SET PARITY SPACE ; Telnet connections might not be 8-bit clean
+
+ and then:
+
+ SET HOST /PTY (or /PIPE) /CONNECT telnet abccorp.com
+
+ or, equivalently:
+
+ PTY (or PIPE) telnet abccorp.com
+
+2.7.2. C-Kermit over Rlogin
+
+ C-Kermit includes its own Rlogin client, but this can normally be used
+ only if you are root, since the rlogin TCP port is privileged. But ptys
+ and pipes let you make rlogin connections with C-Kermit through your
+ computer's external rlogin program, which is normally installed as a
+ privileged program:
+
+ SET PREFIXING ALL
+
+ and then:
+
+ SET HOST /PTY (or /PIPE) /CONNECT rlogin -8 abccorp.com
+
+ or, equivalently:
+
+ PTY (or PIPE) rlogin -8 abccorp.com
+
+ The "-8" option to rlogin enables transmission of 8-bit data. If this
+ is not available, then include SET PARITY SPACE if you intend to
+ transfer files.
+
+ Note that the normal escape sequence for rlogin is Carriage Return
+ followed by Tilde (~), but only when the tilde is followed by certain
+ other characters; the exact behavior depends on your rlogin client, so
+ read its documentation.
+
+2.7.3. C-Kermit over Serial Communication Programs
+
+ Ptys and pipes also let you use programs that make serial connections,
+ such as cu or tip. For example, C-Kermit can be used through cu to make
+ connections that otherwise might not be allowed, e.g. because C-Kermit
+ is not installed with the required write permissions to the dialout
+ device and the UUCP lockfile directory.
+
+ Suppose your UUCP Devices file contains an entry for a serial device
+ tty04 to be used for direct connections, but this device is protected
+ against you (and Kermit when you run it). In this case you can:
+
+ SET CONTROL PREFIX ALL
+ PTY (or PIPE) cu -l tty04
+
+ (Similarly for dialout devices, except then you also need to include
+ the phone number in the "cu" command.)
+
+ As with other communication programs, watch out for cu's escape
+ sequence, which is the same as the rlogin program's: Carriage Return
+ followed by Tilde (followed by another character to specify an action,
+ like "." for closing the connection and exiting from cu).
+
+2.7.4. C-Kermit over Secure Network Clients
+
+ DISCLAIMER: There are laws in the USA and other countries regarding
+ use, import, and/or export of encryption and/or decryption or other
+ forms of security software, algorithms, technology, and intellectual
+ property. The Kermit Project attempts to follow all known statutes,
+ and neither intends nor suggests that Kermit software can or should
+ be used in any way, in any location, that circumvents any
+ regulations, laws, treaties, covenants, or other legitimate canons
+ or instruments of law, international relations, trade, ethics, or
+ propriety.
+
+ For secure connections or connections through firewalls, C-Kermit 7.0
+ can be a Kerberos, SRP, and/or SOCKS client when built with the
+ appropriate options and libraries. But other application-level security
+ acronyms and methods -- SSH, SSL, SRP, TLS -- pop up at an alarming
+ rate and are (a) impossible to keep up with, (b) usually mutually
+ incompatible, and (c) have restrictions on export or redistribution and
+ so cannot be included in C-Kermit itself.
+
+ However, if you have a secure text-based Telnet (or other) client that
+ employs one of these security methods, you can use C-Kermit "through"
+ it via a pty or pipe.
+
+2.7.4.1. SSH
+
+ C-Kermit does not and can not incorporate SSH due to licensing, patent,
+ and USA export law restrictions.
+
+ The UNIX SSH client does not use standard input/output, and therefore
+ can be used only by Kermit's PTY interface, if one is present. The
+ cautions about file transfer, etc, are the same as for Rlogin. Example:
+
+ SET PREFIXING ALL
+ PTY ssh XYZCORP.COM
+
+ Or, for a scripted session:
+
+ SET PREFIXING ALL
+ SET HOST /PTY ssh XYZCORP.COM
+
+ Hint:
+
+ define ssh {
+ check pty
+ if fail end 1 Sorry - no PTY support...
+ pty ssh \%*
+ }
+
+2.7.4.2. SSL
+
+ Secure Sockets Layer (SSL) is another TCP/IP security overlay, this one
+ designed by and for Netscape. An SSL Telnet client is available for
+ UNIX from the University of Queensland. More info at:
+
+ [418]http://www.psy.uq.oz.au/~ftp/Crypto/
+
+ Interoperability with C-Kermit is unknown. C-Kermit also includes its
+ own built-in SSL/TLS support, but it is not exportable; [419]CLICK HERE
+ file for details.
+
+2.7.4.3. SRP
+
+ SRP(TM) is Stanford University's Secure Remote Password protocol. An
+ SRP Telnet client is available from Stanford:
+
+ [420]http://srp.stanford.edu/srp/
+
+ Stanford's SRP Telnet client for UNIX has been tested on SunOS and
+ works fine with C-Kermit, as described in [421]Section 2.7.1, e.g.
+
+ SET PREFIX ALL
+ PTY (or PIPE) srp-telnet xenon.stanford.edu
+
+ C-Kermit itself can be built as an SRP Telnet client on systems that
+ have libsrp.a installed; the C-Kermit support code, however, may not be
+ exported outside the USA or Canada.
+
+2.7.4.4. SOCKS
+
+ C-Kermit can be built as a SOCKS-aware client on systems that have a
+ SOCKS library. See section 8.1.1 of the [422]ckccfg.txt file.
+
+ C-Kermit 7.0 can also be run over SOCKSified Telnet or rlogin clients
+ with SET NETWORK TYPE COMMAND. Suppose the Telnet program on your
+ system is SOCKS enabled but C-Kermit is not. Make Kermit connections
+ like this:
+
+ SET PREFIX ALL
+ PTY (or PIPE) telnet zzz.com
+
+2.7.4.5. Kerberos
+
+ UNIX C-Kermit can be built with MIT Kerberos IV or V authentication and
+ encryption. Instructions are available in a [423]separate document.
+ Additional modules are required that can not be exported from the USA
+ to any country except Canada, by US law.
+
+ If you have Kerberos installed but you don't have a Kerberized version
+ of C-Kermit, you can use ktelnet as C-Kermit's external communications
+ program to make secure connections without giving up C-Kermit's
+ services:
+
+ SET PREFIX ALL
+ PTY (or PIPE) ktelnet cia.gov
+
+2.8. Scripting Local Programs
+
+ If your version of Kermit has PTY support built in, then any text-based
+ program can be invoked with SET HOST /PTY or equivalent command and
+ controlled using the normal sequence of OUTPUT, INPUT, IF SUCCESS
+ commands (this is the same service that is provided by the 'expect'
+ program, but controlled by the Kermit script language rather than Tcl).
+
+ When PTY service is not available, then any program that uses standard
+ input and output can be invoked with SET HOST /PIPE.
+
+ Here's an example in which we start an external Kermit program, wait
+ for its prompt, give it a VERSION command, and then extract the numeric
+ version number from its response:
+
+ set host /pty kermit -Y
+ if fail stop 1 {Can't start external command}
+ input 10 C-Kermit>
+ if fail stop 1 {No C-Kermit> prompt}
+ output version\13
+ input 10 {Numeric: }
+ if fail stop 1 {No match for "Numeric:"}
+ clear input
+ input 10 \10
+ echo VERSION = "\fsubstr(\v(input),1,6)"
+ output exit\13
+
+ This technique could be used to control any other interactive program,
+ even those that do screen formatting (like Emacs or Vi), if you can
+ figure out the sequence of events. If your Kermit program doesn't have
+ PTY support, then the commands are restricted to those using standard
+ i/o, including certain shells, interactive text-mode "hardcopy" editors
+ like ex, and so on.
+
+ If you are using the PTY interface, you should be aware that it runs
+ the given program or command directly on the pty, without any
+ intervening shell to interpret metacharacters, redirectors, etc. If you
+ need this sort of thing, include the appropriate shell invocation as
+ part of your command; for example:
+
+ pty echo *
+
+ just echoes "*"; whereas:
+
+ pty ksh -c "echo *"
+
+ echoes all the filenames that ksh finds matching "*".
+
+ Similarly for redirection:
+
+ set host /pty ksh -c "cat > foo" ; Note: use shell quoting rules here
+ set transmit eof \4
+ transmit bar
+
+ And for that matter, for built-in shell commands:
+
+ set host /pty ksh -c "for i in *; do echo $i; done"
+
+ The PIPE interface, on the other hand, invokes the shell automatically,
+ so:
+
+ pipe echo *
+
+ prints filenames, not "*".
+
+2.9. X.25 Networking
+
+ X.25 networking is documented in [424]Using C-Kermit, 2nd Edition. When
+ the book was published, X.25 was available only in SunOS, Solaris, and
+ Stratus VOS. Unlike TCP/IP, X.25 APIs are not standardized; each
+ vendor's X.25 libraries and services (if they have them at all) are
+ unique.
+
+ This section describes new additions.
+
+2.9.1. IBM AIXLink/X.25 Network Provider Interface for AIX
+
+ Support for X.25 was added via IBM's Network Provider Interface (NPI),
+ AIXLink/X.25 1.1, to the AIX 4.x version of C-Kermit 7.0.
+ Unfortunately, AIXLink/X.25 is a rather bare-bones facility, lacking in
+ particular any form of PAD support (X.3, X.28, X.29). Thus, the AIX
+ version of C-Kermit, when built to include X.25 networking, has neither
+ a PAD command, nor a SET PAD command. The same is true for the
+ underlying AIX system: no PAD support. Thus it is not possible to have
+ an interactive shell session over an X.25 connection into an AIX system
+ (as far as we know), even from X.25-capable Kermit versions (such as
+ Solaris or VOS) that do include PAD support.
+
+ Thus the X.25 capabilities in AIX C-Kermit are limited to peer-to-peer
+ connections, e.g. from a C-Kermit client to a C-Kermit server. Unlike
+ the Solaris, SunOS, and VOS versions, the AIX version can accept
+ incoming X.25 connections:
+
+ set network type x.25
+ if fail stop 1 Sorry - no X.25 support
+ ; Put any desired DISABLE or ENABLE or SET commands here.
+ set host /server *
+ if fail stop 1 X.25 "set host *" failed
+
+ And then access it from the client as follows:
+
+ set network type x.25
+ if fail stop 1 Sorry - no X.25 support
+ set host xxxxxxx ; Specify the X.25/X.121 address
+ if fail stop 1 Can't open connection
+
+ And at this point the client can use the full range of client commands:
+ SEND, GET, REMOTE xxx, FINISH, BYE.
+
+ The AIX version also adds two new variables:
+
+ \v(x25local_nua)
+ The local X.25 address.
+
+ \v(x25remote_nua)
+ The X.25 address of the host on the other end of the connection.
+
+ C-Kermit's AIX X.25 client has not been tested against anything other
+ than a C-Kermit X.25 server on AIX. It is not known if it will
+ interoperate with C-Kermit servers on Solaris, SunOS, or VOS.
+
+ To make an X.25 connection from AIX C-Kermit, you must:
+
+ set x25 call-user-data xxxx
+
+ where xxxx can be any even-length string of hexadecimal digits, e.g.
+ 123ABC.
+
+2.9.2. HP-UX X.25
+
+ Although C-Kermit presently does not include built-in support for HP-UX
+ X.25, it can still be used to make X.25 connections as follows: start
+ Kermit and tell it to:
+
+ set prefixing all
+ set parity space
+ pty padem address
+
+ This should work in HP-UX 9.00 and later (see [425]Section 2.7). If you
+ have an earlier HP-UX version, or the PTY interface doesn't work or
+ isn't available, try:
+
+ set prefixing all
+ set parity space
+ pipe padem address
+
+ Failing that, use Kermit to telnet to localhost and then after logging
+ back in, start padem as you would normally do to connect over X.25.
+
+2.10. Additional Serial Port Controls
+
+ C-Kermit 7.0 adds the following commands for greater control over
+ serial ports. These commands are available only in C-Kermit versions
+ whose underlying operating systems provide the corresponding services
+ (such as POSIX and UNIX System V), and even then their successful
+ operation depends on the capabilities of the specific device and
+ driver.
+
+ SET DISCONNECT { ON, OFF }
+ On a SET LINE or SET PORT connection with SET CARRIER ON or
+ AUTO, if the carrier signal drops during the connection,
+ indicating that the connection has been lost, and C-Kermit
+ notices it, this setting governs what happens next. With SET
+ DISCONNECT OFF, which is consistent with previous behavior, and
+ therefore the default, C-Kermit continues to keep the device
+ open and allocated. With SET DISCONNECT ON, C-Kermit
+ automatically closes and releases the device when it senses a
+ carrier on-to-off transition, thus allowing others to use it.
+ However, it remains the default device for i/o (DIAL, REDIAL,
+ INPUT, SEND, CONNECT, etc), so if a subsequent i/o command is
+ given, the device is reopened if it is still available. When it
+ has been automatically closed in this manner, SHOW
+ COMMUNICATIONS puts "(closed)" after its name, and in UNIX, the
+ lockfile disappears -- both from SHOW COMM and from the lockfile
+ directory itself. Synonym: SET CLOSE-ON-DISCONNECT.
+
+ SET EXIT ON-DISCONNECT { ON, OFF }
+ Like DISCONNECT, but makes the program exit if a connection
+ drops.
+
+ Note that SET CLOSE-ON-DISCONNECT and SET EXIT ON-DISCONNECT apply only
+ to connections that drop; they do not apply to connections that can't
+ be made in the first place. For example, they have no effect when a SET
+ LINE, SET HOST, TELNET, or DIAL command fails.
+
+ HANGUP
+ If [CLOSE-ON-]DISCONNECT is ON, and the HANGUP command is given
+ on a serial device, and the carrier signal is no longer present
+ after the HANGUP command, the device is closed and released.
+
+ SET PARITY HARDWARE { EVEN, ODD }
+ Unlike SET PARITY { EVEN, ODD, MARK, SPACE }, which selects 7
+ data bits plus the indicated kind of parity (to be done in
+ software by Kermit itself), SET PARITY HARDWARE selects 8 data
+ bits plus even or odd parity, to be done by the underlying
+ hardware, operating system, or device driver. This command is
+ effective only with a SET LINE or SET PORT device. That is, it
+ has no effect in remote mode, nor on network connections. There
+ is presently no method for selecting 8 data bits plus mark or
+ space parity. If hardware parity is in effect, the variable
+ \v(hwparity) is set to "even" or "odd". Note: some platforms
+ might also support settings of SPACE, MARK, or NONE.
+
+ SET STOP-BITS { 1, 2 }
+ This tells the number of 1-bits to insert after an outbound
+ character's data and parity bits, to separate it from the next
+ character. Normally 1. Choosing 2 stop bits should do no harm,
+ but will slow down serial transmission by approximately 10
+ percent. Historically, 2 stop bits were used with Teletypes (at
+ 110 bps or below) for print-head recovery time. There is
+ presently no method for choosing any number of stop bits besides
+ 1 and 2.
+
+ SET SERIAL [ dps ]
+ dps stands for Data-bits, Parity, Stop-bits. This is the
+ notation familiar to many people for serial port configuration:
+ 7E1, 8N1, 7O2, etc. The data bits number also becomes the
+ TERMINAL BYTESIZE setting. The second character is E for Even, O
+ for Odd, M for Mark, S for Space, or N for None. The list of
+ available options depends on the capabilities of the specific
+ platform. If dps is omitted, 8N1 is used. Type "set serial ?"
+ for a list of available choices. Examples:
+
+ SET SERIAL 7E1
+ Equivalent to SET PARITY EVEN, SET STOP-BITS 1, SET TERM
+ BYTE 7.
+
+ SET SERIAL 8N1
+ Equivalent to SET PARITY NONE, SET STOP-BITS 1, SET TERM
+ BYTE 8.
+
+ SET SERIAL 7E2
+ Equivalent to SET PARITY EVEN and SET STOP-BITS 2, SET
+ TERM BYTE 7.
+
+ SET SERIAL 8E2
+ Same as SET PARITY HARDWARE EVEN, SET STOP-BITS 2, SET
+ TERM BYTE 8.
+
+ SET SERIAL
+ Same as SET PARITY NONE and SET STOP-BITS 1, SET TERM BYTE
+ 8.
+
+ Notes:
+
+ * The SET SERIAL xx2 options are available only in Kermit versions
+ where the SET PARITY HARDWARE command is also available. (SHOW
+ FEATURES includes "HWPARITY" in its options list.)
+ * The SET SERIAL 7xx and 8N1 options affect the software parity
+ setting, even for network connections.
+ * As noted in the manual, selecting 8 data bits does not give you
+ 8-bit terminal sessions in CONNECT mode unless you also SET
+ TERMINAL BYTESIZE 8. The default terminal bytesize remains 7, to
+ protect against the situation where the remote host is generating
+ parity but you don't know about it. If the terminal bytesize was 8
+ by default and you CONNECTed to such a host, you would see only
+ garbage on your screen.
+ * If you do not give a SET STOP-BITS or SET SET SERIAL command,
+ C-Kermit does not attempt to set the device's stop bits; instead,
+ it uses whatever setting the device uses when not given explicit
+ instructions about stop bits.
+
+ SHOW COMMUNICATIONS displays the current settings. Stop bits and
+ hardware parity are shown only for SET PORT / SET LINE (serial)
+ devices, since they do not apply to network connections or to remote
+ mode. STOP-BITS is shown as "(default)" if you have not given an
+ explicit SET STOP-BITS or SET SERIAL command.
+
+ The \v(serial) variable shows the SET SERIAL setting (8N1, 7E1, etc).
+
+2.11. Getting Access to the Dialout Device
+
+ This section is for UNIX only; note the special words about QNX at
+ the end. Also see [426]Section 2.0 for SET LINE switches,
+ particularly the /SHARE switch for VMS only.
+
+ C-Kermit does its best to obey the UUCP lockfile conventions of each
+ platform (machine, operating system, OS version) where it runs, if that
+ platform uses UUCP.
+
+ But simply obeying the conventions is often not good enough, due to the
+ increasing likelihood that a particular serial device might have more
+ than one name (e.g. /dev/tty00 and /dev/term/00 are the same device in
+ Unixware 7; /dev/cua and /dev/cufa are the same device in NeXTSTEP),
+ plus the increasingly widespread use of symlinks for device names, such
+ as /dev/modem.
+
+ C-Kermit 7.0 goes to greater lengths than previous versions to
+ successfully interlock with other communications program (and other
+ instances of Kermit itself); for example, by:
+
+ * Creation of dual lockfiles whenever a symlink is used; one for the
+ link name and one for the real name.
+ * Creation of dual lockfiles in HP-UX according to HP rules.
+ * Creation of dual uppercase/lowercase lockfile names in SCO
+ UNIX/ODT/OSR5.
+ * The use of ttylock() in versions of AIX where it works.
+ * The use, wherever possible, of lockfile names based on
+ inode/major/minor device number rather than device name.
+
+ See the [427]ckuins.txt and [428]ckubwr.txt files for details.
+
+ QNX is almost unique among UNIX varieties in having no UUCP programs
+ nor UUCP-oriented dialout-device locking conventions. QNX does,
+ however, allow a program to get the device open count. This can not be
+ a reliable form of locking unless all applications do it (and they
+ don't), so by default, Kermit uses this information only for printing a
+ warning message such as:
+
+ C-Kermit>set line /dev/ser1
+ WARNING - "/dev/ser1" looks busy...
+
+ However, if you want to use it as a lock, you can do so with:
+
+ SET QNX-PORT-LOCK { ON, OFF }
+
+ QNX-PORT-LOCK is OFF by default; if you set in ON, C-Kermit fails to
+ open any dialout device when its open count indicates that another
+ process has it open. SHOW COMM (in QNX only) displays the setting, and
+ if you have a port open, it also shows the current open count (with
+ C-Kermit's own access always counting as 1).
+
+2.12. The Connection Log
+
+ C-Kermit 7.0 adds the ability to log connections, so you can see where
+ you've been and have a record of calls you've made. A connection is
+ defined as any communications session that is begun by SET LINE, SET
+ PORT, DIAL, SET HOST, TELNET, or RLOGIN. Connections are not logged
+ unless you request it; the command is:
+
+ LOG CX [ filename [ { NEW, APPEND } ] ]
+ Enables logging of connections in the given file. If the
+ trailing { NEW, APPEND } keyword is omitted, the file is opened
+ for appending; i.e. new records are written to the end. If NEW
+ is specified, a new file is created; if a file of the same name
+ already existed, it is overwritten. If the filename is omitted,
+ CX.LOG in your home (login) directory is used (note: uppercase).
+ To accept all defaults, just use "log connections" (or "l c" for
+ short). Synonym: LOG CONNECTIONS.
+
+ CLOSE CX-LOG
+ This closes the connection log if it was open. (Note, the CLOSE
+ CONNECTION command closes the connection itself).
+
+ SHOW CX
+ This shows your current connection, if any, including the
+ elapsed time (since you opened it). Synonym: SHOW CONNECTION.
+
+ \v(cx_time)
+ This variable shows the elapsed time of your current connection,
+ or if there is no current connection, of your most recent
+ connection, of if there have been no connections, 0.
+
+ The connection contains one line per connection, of the form:
+
+ yyyymmdd hh:mm:ss username pid p=v [ p=v [ ... ] ]
+
+ where the timestamp (in columns 1-18) shows when the connection was
+ made; username is the login identity of the person who made the
+ connection; pid is Kermit's process ID when it made the connection. The
+ p's are parameters that depend on the type of connection, and the v's
+ are their values:
+
+ T = Connection Type (TCP, SERIAL, DIAL, DECNET, etc).
+ H = The name of the Host from which the connection was made.
+ N = Destination phone Number or Network host name or address.
+ D = Serial connections only: Device name.
+ O = Dialed calls only: Originating country code & area code if known.
+ E = Elapsed time in hh:mm:ss format (or hhh:mm:ss, etc).
+
+ If you always want to keep a connection log, simply add:
+
+ log connections
+
+ to your C-Kermit customization file. Note, however, that if you make a
+ lot of connections, your CX.LOG will grow and grow. You can handle this
+ by adding a "logrotate" procedure like the following to your
+ customization file, before the "log connections" command:
+
+ define LOGROTATE { ; Define LOGROTATE macro
+ local \%i \%m \%d \%n \%f MAX
+ def MAX 4 ; How many months to keep
+ if not def \%1 - ; No argument given
+ end 1 \%0: No filename given
+ if not = 1 \ffiles(\%1) - ; Exactly 1 file must match
+ end 1 \%0: \%1 - File not found
+ .\%d := \fsubstr(\fdate(\%1),1,6) ; Arg OK - get file year & month
+ if = \%d - ; Compare file year & month
+ \fsubstr(\v(ndate),1,6) - ; with current year & month
+ end 0 ; Same year & month - done
+ rename \%1 \%1.\%d ; Different - rename file
+ .\%n := \ffiles(\%1.*) ; How many old files
+ if < \%n \m(MAX) end 0 ; Not enough to rotate
+ .\%m := \%1.999999 ; Initial compare string
+ for \%i 1 \%n 1 { ; Loop thru old logs
+ .\%f := \fnextfile() ; Get next file name
+ if llt \%f \%m .\%m := \%f ; If this one older remember it
+ }
+ delete \%m ; Delete the oldest one
+ }
+ log connections ; Now open the (possibly new) log
+ logrotate \v(home)CX.LOG ; Run the LOGROTATE macro
+
+ As you can see, this compares the yyyymm portion of the modification
+ date (\fdate()) of the given file (\%1) with the current yyyymm. If
+ they differ, the current file has the yyyymm suffix (from its most
+ recent modification date) appended to its name. Then we search through
+ all other such files, find the oldest one, and delete it. Thus the
+ current log, plus the logs from the most recent four months, are kept.
+ This is all done automatically every time you start C-Kermit.
+
+ On multiuser systems, it is possible to keep a single, shared,
+ system-wide connection log, but this is not recommended since (a) it
+ requires you keep a publicly write-accessible logfile (a glaring target
+ for mischief), and (b) it would require each user to log to that file
+ and not disable logging. A better method for logging connections, in
+ UNIX at least, is syslogging (see [429]ckuins.txt Section 15 and
+ [430]Section 4.2 of the [431]IKSD Administration Guide for details).
+
+2.13. Automatic Connection-Specific Flow Control Selection
+
+ Beginning in C-Kermit 7.0, the appropriate flow-control method for each
+ connection type is kept in a table, for example:
+
+ Remote: NONE
+ Modem: RTS/CTS
+ Direct-Serial: NONE
+ TCPIP: NONE
+
+ The size of the table and values for each connection type can vary from
+ platform to platform. Type "set flow ?" for a list of available
+ flow-control types.
+
+ The table is used to automatically select the appropriate kind of flow
+ control whenever you make a connection. You can display the table with:
+
+ SHOW FLOW-CONTROL
+
+ The defaults are as follows:
+
+ Remote:
+ NONE or XON/XOFF. This is because C-Kermit is not allowed to
+ find out what type of connection the incoming user has (*). No
+ kind of flow control will work on every kind of connection,
+ including (unexpectedly) KEEP, which we would have liked to use,
+ but not turning off flow control at the remote end during file
+ transfer on TCP/IP connections is fatal to the transfer (except
+ in VMS and HP-UX, where it must be set to Xon/Xoff!) Therefore
+ if you are dialing in to a serial port on a server (UNIX or VMS)
+ where C-Kermit is running, you will need to tell C-Kermit to
+ "set flow keep" before transferring files (assuming the modem
+ and port are configured correctly by the system administrator;
+ otherwise you'll need to give a specific kind of flow control,
+ e.g. "set flow xon/xoff"), so in this case C-Kermit will not
+ disable flow control, as it must do when you are coming via
+ Telnet (directly or through a terminal server, except on VMS and
+ HP-UX).
+
+ Modem:
+ This applies when you dial out with a modem. In this case, the
+ MODEM FLOW-CONTROL setting takes affect after the SET FLOW
+ setting, so it can pick the most appropriate flow control for
+ the combination of the particular modem and the
+ computer/port/driver that is dialing.
+
+ Direct-Serial:
+ The default here is NONE because C-Kermit has no way of knowing
+ what kind of flow control, if any, is or can be done by the
+ device at the other end of the connection. RTS/CTS would be a
+ bad choice here, because if the CTS signal is not asserted, the
+ connection will hang. And since direct connections are often
+ made with 3-wire cables, there is a good chance the CTS signal
+ will not be received.
+
+ TCPIP:
+ NONE, since TCP and IP provide their own flow control
+ transparently to the application, except in VMS, where Xon/Xoff
+ is the default due to the requirements of the VMS TCP/IP
+ products.
+
+ Other networks:
+ NONE, since networks should provide their flow control
+ transparently to the application.
+
+ (*) This is possibly the worst feature of UNIX, VMS, and other
+ platforms where C-Kermit runs. If C-Kermit was able to ask the
+ operating system what kind of connection it had to the user, it could
+ set up many things for you automatically.
+
+ You can modify the default-flow-control table with:
+
+ SET FLOW-CONTROL /xxx { NONE, KEEP, RTS/CTS, XON/XOFF, ... }
+
+ where "xxx" is the connection type, e.g.
+
+ SET FLOW /REMOTE NONE
+ SET FLOW /DIRECT RTS/CTS
+
+ If you leave out the switch, SET FLOW works as before, choosing the
+ flow control method to be used on the current connection:
+
+ SET FLOW XON/XOFF
+
+ Thus, whenever you make a connection with SET PORT, SET LINE, DIAL, SET
+ HOST, TELNET, RLOGIN, etc, an appropriate form of flow control is
+ selected automatically. You can override the automatic selection with a
+ subsequent SET FLOW command, such as SET FLOW NONE (no switch
+ included).
+
+ The flow control is changed automatically too when you give a SET MODEM
+ TYPE command. For example, suppose your operating system (say Linux)
+ supports hardware flow control (RTS/CTS). Now suppose you give the
+ following commands:
+
+ set line /dev/ttyS2 ; Automatically sets flow to NONE
+ set modem type usr ; Automatically sets flow to RTS/CTS
+ set modem type rolm ; Doesn't support RTS/CTS so now flow is XON/XOFF
+
+ IMPORTANT: This new feature tends to make the order of SET LINE/HOST
+ and SET FLOW commands matter, where it didn't before. For example, in
+ VMS:
+
+ SET FLOW KEEP
+ SET LINE TTA0:
+
+ the SET LINE undoes the SET FLOW KEEP command; the sequence now must
+ be:
+
+ SET FLOW /DIRECT KEEP
+ SET LINE TTA0:
+
+ or:
+
+ SET LINE TTA0:
+ SET FLOW KEEP
+
+2.14. Trapping Connection Establishment and Loss
+
+ If you define a macro called ON_OPEN, it is executed any time that a
+ SET LINE, SET PORT, SET HOST, TELNET, RLOGIN or similar command
+ succeeds in opening a connection. The argument is the host or device
+ name (as shown by SHOW COMMUNICATIONS, and the same as \v(line)). This
+ macro can be used for all sorts of things, like automatically setting
+ connection- or host-specific parameters when the connection is opened.
+ Example:
+
+ def ON_OPEN {
+ switch \%1 {
+ :abccorp.com, set reliable off, break
+ :xyzcorp.com, set receive packet-length 1000, break
+ etc etc...
+ }
+ }
+
+ If you define a macro called ON_CLOSE, it will be executed any time
+ that a SET LINE, SET PORT, SET HOST, TELNET, RLOGIN or any other kind
+ of connection that C-Kermit has made is closed, either by the remote or
+ by a local CLOSE, HANGUP, or EXIT command or other local action, such
+ as when a new connection is opened before an old one was explicitly
+ closed.
+
+ As soon as C-Kermit notices the connection has been closed, the
+ ON_CLOSE macro is invoked at (a) the top of the command parsing loop,
+ or (b) when a connection is closed implicitly by a command such as SET
+ LINE that closes any open connection prior to making a new connection,
+ or (c) when C-Kermit closes an open connection in the act of exiting.
+
+ The ON_CLOSE macro was inspired by the neverending quest to unite
+ Kermit and SSH. In this case using the "tunnel" mechanism:
+
+ def TUNNEL { ; \%1 = host to tunnel to
+ local \%p
+ if not def \%1 stop 1
+ assign tunnelhost \%1 ; Make global copy
+ undef on_close
+ set macro error off
+ close connection ; Ignore any error
+ open !read tunnel start \%1
+ read \%p ; Get port number
+ if fail stop 1 Tunnel failure: \%1
+ close read
+ if fail stop 1 Tunnel failure: \%1 ; See [432]Section 4.2.8.1
+ assign on_close { ; Set up close handler
+ echo Closing tunnel: \m(tunnelhost)
+ !tunnel stop \m(tunnelhost)
+ undef on_close
+ }
+ set host localhost:\%p /telnet
+ if success end 0
+ undef on_close
+ stop 1 Connection failure: \%1
+ }
+
+ In this case, when the connection stops, we also need to shut down the
+ tunnel, even if it is at a later time after TUNNEL has finished
+ executing. This way we can escape back, reconnect, transfer files, and
+ so on until the connection is broken by logging out from the remote, or
+ by explicitly closing it, or by EXITing from C-Kermit, at which time
+ the tunnel is shut down.
+
+ When the connection is closed, no matter how, the ON_CLOSE macro
+ executes and then undefines (destroys) itself, since we don't want to
+ be closing tunnels in the future when we close subsequent connections.
+
+ Other such tricks can be imagined, including ending ON_CLOSE with a
+ STOP command to force the command stack to be peeled all the way back
+ to the top, for example in a deeply nested script that depends on the
+ connection being open:
+
+ def on_close { stop 1 CONNECTION LOST }
+
+ When C-Kermit invokes the ON_CLOSE macro, it supplies one argument
+ (\%1): the reason the connection was closed as a number, one of the
+ following:
+
+ 2 - Fatal failure to negotiate a required item on a network connection.
+ 1 - Closed by C-Kermit command.
+ 0 - All others (normally closed by remote).
+
+ which may be used for any purpose; for example, to add a comment to the
+ connection log:
+
+ def on_close {
+ local \%m
+ if not open cx end 0
+ switch \%1 {
+ :0, .\%m = Closed by remote, break
+ :1, .\%m = Closed by me, break
+ :2, .\%m = Network protocol negotiation failure, break
+ }
+ if def \%m writeln cx {# \%m}
+ }
+
+2.15. Contacting Web Servers with the HTTP Command
+
+ C-Kermit 7.0 (at this writing, the UNIX version only) supports direct
+ contact and interaction with Web servers via HTTP 1.0 protocol. To make
+ a connection, use Kermit's normal method for making a TCP/IP
+ connection, but specify the HTTP port:
+
+ SET HOST host http [ switches ]
+
+ where host is the IP hostname or address, and http is the name of the
+ TCP port for the Web server. Relevant switches include:
+
+ /RAW
+ Treat the connection as a transparent binary pipe. This switch
+ may be required if a port other than 'http' is used.
+
+ /SSL
+ Make an secure private connection with SSL (only if SSL support
+ is included in your version of Kermit). In this case the port
+ name might need to be https rather than http, e.g. "set host
+ secureserver.xyzcorp.com https /ssl".
+
+ /TLS
+ Make an secure private connection with TLS (only if TLS support
+ is included in your version of Kermit). In this case the port
+ name would be https rather than http.
+
+ Then you can issue an HTTP command. In most cases, the server closes
+ the connection when the command is complete. Example:
+
+ SET HOST www.columbia.edu http
+ IF FAIL EXIT 1 Can't contact server
+ HTTP GET kermit/index.html
+
+ At this point the connection is closed, since that's how HTTP 1.0
+ works. If you want to perform additional operations, you must establish
+ a new connection with another SET HOST command.
+
+ The HTTP command acts as a client to the Web server, except instead of
+ displaying the results like a Web browser would, it stores them. Any
+ HTTP command can (but need not) include any or all of the following
+ switches:
+
+ /AGENT:user-agent
+ Identifies the client to the server; "C-Kermit" or "Kermit-95"
+ by default.
+
+ /HEADER:header-line
+ Used for specifying any optional headers. A list of headers is
+ provided using braces for grouping:
+
+ /HEADER:{{tag:value}{tag:value}...}
+
+ For a listing of valid tag value and value formats see [433]RFC
+ 1945: Hypertext Transfer Protocol -- HTTP/1.0. A maximum of
+ eight headers may be specified.
+
+ /USER:name
+ In case a page requires a username for access.
+
+ /PASSWORD:password
+ In case a page requires a password for access.
+
+ /ARRAY:arrayname
+ Tells Kermit to store the response headers in the given array,
+ one line per element. The array need not be declared in advance.
+ Example:
+
+ C-Kermit? http /array:c get kermit/index.html
+ C-Kermit? show array c
+ Dimension = 9
+ 1. Date: Fri, 26 Nov 1999 23:12:22 GMT
+ 2. Server: Apache/1.3.4 (Unix)
+ 3. Last-Modified: Mon, 06 Sep 1999 22:35:58 GMT
+ 4. ETag: "bc049-f72-37d441ce"
+ 5. Accept-Ranges: bytes
+ 6. Content-Length: 3954
+ 7. Connection: close
+ 8. Content-Type: text/html
+
+ As you can see, the header lines are like MIME e-mail header lines:
+ identifier, colon, value. The /ARRAY switch is the only method
+ available to a script to process the server responses for a POST or PUT
+ command.
+
+ The HTTP commands are:
+
+ HTTP [ switches ] GET remote-filename [ local-filename ]
+ Retrieves the named file. If a local-filename is given, the file
+ is stored locally under that name; otherwise it is stored with
+ its own name.
+
+ HTTP [ switches ] HEAD remote-filename local-filename
+ Like GET except without actually getting the file; instead it
+ gets only the headers, storing them into the given file, whose
+ name must be given, one line per header item, as shown above in
+ the /ARRAY: switch description.
+
+ HTTP [ switches ] INDEX remote-directory [ local-filename ]
+ Retrieves the file listing for the given server directory. NOTE:
+ This command is not supported by most Web servers.
+
+ HTTP [ switches ] POST [ /MIME-TYPE:type ] local-file remote-file
+ Used to send a response as if it were sent from a form. The data
+ to be posted must be read from a file.
+
+ HTTP [ switches ] PUT [ /MIME-TYPE:type ] local-file remote-file
+ Uploads a local file to a server file.
+
+ HTTP [ switches ] DELETE remote-filename
+ Instructs the server to delete the specified filename.
+
+3. TERMINAL CONNECTION
+
+3.1. CONNECT Command Switches
+
+ The following switches (see [434]Section 1.5) were added to the CONNECT
+ command in 7.0:
+
+ /QUIETLY
+ Don't print the "Connecting to..." or "Back at..." messages. CQ
+ is an invisible command synonym for CONNECT /QUIETLY.
+
+ /TRIGGER:string
+ Specify a trigger or triggers ([435]Section 3.2) effective for
+ this CONNECT command only, temporarily overriding any current
+ SET TERMINAL TRIGGER values ([436]Section 3.2).
+
+ Note: Other switches might also be available; type "connect ?" for a
+ list, "help connect" for a description of each.
+
+3.2. Triggers
+
+ Triggers were added for UNIX, VMS, AOS/VS, and K95 in C-Kermit 7.0.
+
+ SET TERMINAL TRIGGER string
+ Tells C-Kermit to look for the given string during all
+ subsequent CONNECT sessions, and if seen, to return to command
+ mode automatically, as if you had escaped back manually. If the
+ string includes any spaces, you must enclose it in braces.
+ Example:
+
+ set terminal trigger {NO CARRIER}
+
+ Comparisons are made after character-set translation.
+
+ If a string is to include a literal brace character, precede it with a
+ backslash:
+
+ ; My modem always makes this noise when the connection is lost:
+ set terminal trigger |||ppp\{\{\{\{UUUUUUU
+
+ If you want Kermit to look for more than one string simultaneously, use
+ the following syntax:
+
+ set terminal trigger {{string1}{string2}...{stringn}}
+
+ In this case, C-Kermit will return to command mode automatically if any
+ of the given strings is encountered. Up to 8 strings may be specified.
+
+ If the most recent return to command mode was caused by a trigger, the
+ new variable, \v(trigger), shows the trigger value; otherwise
+ \v(trigger) is empty.
+
+ The SHOW TRIGGER command displays the SET TERMINAL TRIGGER values as
+ well as the \v(trigger) value.
+
+3.3. Transparent Printing
+
+ As noted in the manual, C-Kermit's CONNECT command on UNIX is not a
+ terminal emulator, but rather a "semitransparent pipe" between the
+ terminal or emulator you are using to access C-Kermit, and the remote
+ host to which C-Kermit is connected. The "semitransparent" qualifier is
+ because of character-set translation as well as several actions taken
+ by the emulator in response to the characters or strings that pass
+ through it, such as APCs, Kermit packets (autodownload), triggers, etc.
+
+ The UNIX version of C-Kermit 7.0 adds another such action: Transparent
+ printing, also called Controller printing (as distinct from Autoprint
+ or line or screen print). It is intended mainly for use on UNIX
+ workstation consoles (as opposed to remote logins), but with some care
+ can also be used when accessing C-Kermit remotely.
+
+ Transparent printing is related to APC by sharing C-Kermit's built-in
+ ANSI escape-sequence parser to detect "printer on" and "printer off"
+ sequences from the host. When the printer-on sequence is received, all
+ subsequent arriving characters -- including NUL, control characters,
+ and escape sequences -- are sent to the SET PRINTER device instead of
+ to your screen until the printer-off sequence is received, or you
+ escape back, whichever happens first. These bytes are not translated or
+ modified or filtered in any way by Kermit (except for possibly
+ stripping of the 8th bit, as noted below), but if filtering or
+ translation is desired, this can be accomplished by your SET PRINTER
+ selection (e.g. by choosing a pipeline of filters).
+
+ By default, your SET PRINTER device is your default UNIX printer, but
+ it can also be a file, a command, or the null device (which causes all
+ printer material to be discarded). See [437]Using C-Kermit, 2nd Ed.,
+ p.41 for details.
+
+ Transparent printing is controlled by the command:
+
+ SET TERMINAL PRINT { ON, OFF }
+ When ON, transparent-print sequences are obeyed, and printing
+ occurs on the system where C-Kermit is running. When OFF,
+ transparent print sequences are ignored and passed through to
+ your actual terminal or emulator, along with the data they
+ enclose. OFF is the default, for compatibility with earlier
+ C-Kermit releases. As noted in the manual, when the current SET
+ PRINTER device is a file, transparent-print material is appended
+ to it; the file is not overwritten.
+
+ SET TERMINAL BYTESIZE { 7, 8 }
+ SET PARITY { EVEN, ODD, MARK, SPACE, NONE }
+ If the terminal bytesize is 7, or PARITY is not NONE, the 8th
+ bit of each byte is stripped prior to printing.
+
+ The transparent-print escape sequences are:
+
+ <ESC>[5i
+ Printer On. Send all subsequent incoming bytes to the printer
+ without any kind of filtering, translation, or alteration. Note:
+ <ESC> stands for ASCII character number 27 (decimal), Escape.
+
+ <ESC>[4i
+ Printer Off. Resume displaying incoming bytes on the screen.
+
+ These are the same sequences used by DEC VT100 and higher terminals and
+ other ANSI X3.64 and ISO 6429 compatible terminals. There is no
+ provision for selecting other printer-control sequences.
+
+ Restrictions:
+
+ 1. You must SET TERM TRANSPARENT-PRINT ON before you can use this
+ feature.
+ 2. Only the 7-bit forms of the escape sequences are supported. The
+ 8-bit CSI C1 control is not recognized.
+ 3. Autoprint is not supported, since this requires a full-fledged
+ terminal emulator with direct access to the screen.
+ 4. The start-print and stop-print sequences pass through to the screen
+ (there is no way to avoid this without causing unacceptable delays
+ or deadlocks in CONNECT mode). Thus if your terminal or emulator
+ also supports transparent printing via these same sequences, an
+ empty file will be sent to its printer. Normally this has no
+ effect.
+
+ Point (4) is similar to the situation with autodownload and APC -- when
+ you have several Kermit clients in a chain, you should take care that
+ these features are enabled in only one of them.
+
+ Example 1:
+
+ set printer {|lpr -Plaser} ; Specify the printer (if not default).
+ set term print on ; Enable transparent printing.
+ set term byte 8 ; Enable 8-bit characters.
+ connect ; Enter CONNECT mode.
+
+ Example 2:
+
+ set printer /home/users/olga/printer.log ; Send printer material to a file.
+
+ Example 3:
+
+ set printer {| grep -v ^Received | lpr} ; Filter out some lines
+
+ Then use "pcprint" or "vtprint" commands on the host to initiate
+ transparent print operations. See [438]Using C-Kermit, 2nd Ed., p.406
+ for details.
+
+ Here is a sample "pcprint" shell script for UNIX:
+
+ #!/bin/sh
+ echo -n '<ESC>[5i'
+ if [ $# -eq 0 ]; then
+ cat
+ else
+ cat $*
+ fi
+ echo -n '<FF><ESC>[4i'
+ # (end)
+
+ (Replace "<ESC>" by the actual ASCII Escape character and "<FF>" by the
+ ASCII Formfeed character).
+
+ If you always want transparent printing enabled, put "set term print
+ on" in your C-Kermit customization file (~/.mykermrc in UNIX). The "set
+ term bytesize" selection, however, is a property of each separate
+ connection.
+
+3.4. Binary and Text Session Logs
+
+ C-Kermit 7.0 corrects an oversight in earlier releases, in which binary
+ session logs (SET SESSION-LOG BINARY) translated character sets and
+ performed various formatting transformations (e.g. "newline mode")
+ before writing characters to the session log. In C-Kermit 7.0,
+ binary-mode session logging writes characters as they come in, before
+ anything (other that parity-bit stripping) is done to them. Text-mode
+ session logging records the characters after processing.
+
+4. FILE TRANSFER
+
+ Every file is transferred either in text mode (which implies
+ record-format and character-set translation) or binary mode (in which
+ each byte is sent literally without any kind of conversion). The mode
+ in which a file is transferred is controlled by (a) the default mode,
+ in the absence of any other indications; (b) the SET FILE TYPE command;
+ (c) various automatic mechanisms based on client/server negotiations,
+ directory information or filename patterns, etc.
+
+ The default FILE TYPE was changed from TEXT to BINARY in C-Kermit 7.0
+ because:
+
+ * Transferring a text file in binary mode does less damage than
+ transferring a binary file in text mode.
+ * Only binary-mode transfers can be recovered from the point of
+ failure.
+ * The automatic transfer-mode mechanisms switch to text mode on a
+ per-file basis anyway, so only those files that are not covered by
+ the automatic mechanisms are affected.
+ * All file transfers on the Web are done in binary mode, so people
+ are accustomed to it and expect it.
+
+4.0. BUG FIXES, MINOR CHANGES, AND CLARIFICATIONS
+
+4.0.0. Filenames with Spaces
+
+ Filenames that contain spaces are a major nuisance to a program like
+ Kermit, whose command language is line- and word-oriented, in which
+ words are separated by spaces and a filename is assumed to be a "word".
+ In general (unless noted otherwise in the description of a particular
+ command), there is only one way to refer to such files in Kermit
+ commands, and that is to enclose the name in braces:
+
+ send {this file}
+
+ Tells Kermit to send the file whose name is "this file" (two words, no
+ quotes). Of course, various circumlocutions are also possible, such as:
+
+ define \%a this file
+ send \%a
+
+ BUT, perhaps contrary to expectation, you can't use "\32" to represent
+ the space:
+
+ send this\32file
+
+ does not work. Why? Because the Kermit parser, which must work on many
+ operating systems including Windows, has no way of knowing what you
+ mean by "this\32file". Do you mean a file whose name is "this file" in
+ the current directory? Or do you mean a file whose name is "32file" in
+ the "this" subdirectory of the current directory? Guessing won't do
+ here; Kermit must behave consistently and deterministically in all
+ cases on all platforms.
+
+ Note that you can't use Esc or Tab within {...} for filename
+ completion, or question mark to get a filename list. However, you can
+ include wildcards; for example:
+
+ send {* *}
+
+ sends all files whose name contains a space.
+
+ All things considered, it is best to avoid spaces in file and directory
+ names if you can. Also see [439]Section 5.4 on this topic.
+
+4.0.1. Packet out of Window
+
+ C-Kermit 6.0 could send packets "out of window" if the window size was
+ greater than 1 and ACKs had arrived out of order. Fixed in 6.1.
+
+4.0.2. MOVE after ADD SEND-LIST
+
+ ADD SEND-LIST followed by MOVE did not delete original files; fixed in
+ 6.1. Carrier loss was not detected during transfer; in 7.0 C-Kermit
+ checks for this (but results can not be guaranteed). In any case, the
+ protocol will eventually time out if the connection is lost.
+
+4.0.3. GET and RECEIVE As-Names
+
+ In 5A(190) through 6.0.192, the GET and RECEIVE as-name did not
+ properly override the RECEIVE PATHNAMES setting. In 7.0 it does.
+
+4.0.4. New Brief Statistics Listing
+
+ Version 7.0 adds a /BRIEF switch to the STATISTICS command, to display
+ a short file-transfer statistics report. /BRIEF is now the default. Use
+ /VERBOSE to see the full display, which is about 25 lines long.
+
+4.0.5. Improved FAST Command
+
+ The preinstalled definition of the FAST macro did not take enough
+ factors into account. Now it sets packet lengths and window sizes
+ appropriate to the configuration. Furthermore, in IRIX only, it might
+ restrict the SEND packet length to 4000, to work around a bug in the
+ IRIX Telnet server, depending on the IRIX version (see [440]ckubwr.txt,
+ IRIX section). To see the built-in definition of the FAST macro, type
+ "show macro fast". To change it, simply define it to be whatever you
+ want -- it's just a macro, like any other.
+
+4.0.6. The SET SEND BACKUP Command
+
+ Version 7.0 adds SET SEND BACKUP { ON, OFF }. This tells whether backup
+ files should be sent. Backup files are the ones created by Kermit (and
+ EMACS, and possibly other applications) to preserve old copies of files
+ when creating new ones with the same name. Kermit does this when
+ receiving a file and its FILE COLLISION setting is BACKUP (or RENAME,
+ in which case it the new file gets the backup name). On most platforms,
+ the backup name is formed by adding:
+
+ .~n~
+
+ to the end of the filename, where "n" is a number. For example, if the
+ original file is oofa.txt, a backup file might be called:
+
+ oofa.txt.~1~
+
+ (or oofa.txt.~2~, etc). If you SET SEND BACKUP OFF, this tells Kermit
+ not to send files that have backup names. Normally, SET SEND BACKUP is
+ ON (as shown by SHOW PROTOCOL), and backup files are sent if their
+ names match the SEND file specification.
+
+ Also see PURGE, SET FILE COLLISION, SEND /NOBACKUP, DIRECTORY
+ /[NO]BACKUP.
+
+4.0.7. The SET { SEND, RECEIVE } VERSION-NUMBERS Command
+
+ VMS Only. Normally when sending files, VMS C-Kermit strips the version
+ number. For example, if the file is FOO.BAR;34, the name is sent as
+ FOO.BAR (without the ";34"). If you want to keep version numbers on
+ when sending files, use SET SEND VERSION-NUMBERS ON. The effect depends
+ on the receiver.
+
+ Normally when receiving files, and an incoming filename includes a
+ VMS-style version number (such as FOO.BAR;34) VMS C-Kermit strips it
+ before trying to create the new file; this way the new file receives
+ the next highest version number in the customary manner for VMS. If you
+ want version numbers on incoming filenames to be used in creating the
+ new files, use SET RECEIVE VERSION-NUMBERS ON.
+
+ Normally these commands would be effective only when VMS C-Kermit is
+ exchanging files with a non-VMS Kermit program, since VMS-to-VMS
+ transfers use labeled mode unless you have gone out of your way to
+ defeat it.
+
+ Example: You want to send all versions of all files in the current
+ directory from a VMS C-Kermit client to a UNIX C-Kermit server. Use:
+
+ set send version-numbers on
+ send *.*;*
+
+ The resulting Unix files will have VMS-style version numbers as part of
+ their name, for example "foo.bar;1", "foo.bar;2", etc.
+
+ Now suppose you want to send these files from Unix to another VMS
+ system and preserve the version numbers. Again we have a Unix C-Kermit
+ server and VMS C-Kermit client. Give these commands to the client:
+
+ set receive version-numbers on
+ get *
+
+4.0.8. The SET { SEND, RECEIVE } { MOVE-TO, RENAME-TO } Commands
+
+ These commands are persistent global versions of the /MOVE-TO: and
+ /RENAME-TO: switches of the SEND, GET, and RECEIVE commands. They
+ should normally be used only when setting up a dedicated
+ transaction-processing application, in which each file is to be moved
+ or renamed immediately after, and only if, it is transferred
+ successfully, so that (for example) an independent, concurrent process
+ can notice when new files appear and process them immediately without
+ having to guess whether they are complete.
+
+4.0.9. SET FILE INCOMPLETE AUTO
+
+ SET FILE INCOMPLETE { KEEP, DISCARD }, which tells whether to keep or
+ discard incompletely received files, has a new option, AUTO, which is
+ also the default. It means KEEP the incomplete file if the transfer is
+ in binary mode, otherwise DISCARD it. This reduces the chances that a
+ subsequent recovery operation (RESEND, REGET, etc) could produce a
+ corrupt file, since recovery works only for binary-mode transfers.
+
+4.1. FILE-TRANSFER FILENAME TEMPLATES
+
+ File-transfer filename templates allow files to be renamed
+ automatically by the file sender, the receiver, or both, during
+ transfer of groups of files.
+
+4.1.1. Templates in the As-Name
+
+ Prior to C-Kermit 6.1 and Kermit 95 1.1.12 the only options that could
+ be used to affect the names of files being transferred were SET
+ FILENAMES { LITERAL, CONVERTED } and SET { SEND, RECEIVE } PATHNAMES {
+ ON, OFF }, plus the "as-name" feature of the SEND (MOVE, etc) and
+ RECEIVE commands.
+
+ Previously, the as-name could be used only for a single file. For
+ example:
+
+ SEND FOO BAR
+
+ would send the file FOO under the name BAR, but:
+
+ SEND *.TXT anything
+
+ was not allowed, since it would give the same name to each file that
+ was sent. When receiving:
+
+ RECEIVE FOO
+
+ would rename the first incoming file to FOO before storing it on the
+ disk, but subsequent files would not be renamed to FOO, since this
+ would result in overwriting the same file repeatedly. Instead, they
+ were stored under the names they arrived with.
+
+ Beginning in C-Kermit 6.1 and Kermit 95 1.1.12, it is possible to
+ specify as-names in SEND, RECEIVE, and related commands even for file
+ groups. This is accomplished by using replacement variables in the
+ as-name, along with optional material such character-string functions
+ and/or constant strings. An as-name containing replacement variables is
+ called a filename template.
+
+ The key to filename templates is the new variable:
+
+ \v(filename)
+
+ During file transfer it is replaced by the name of each file currently
+ being transferred (after transfer, it is the name of the last file
+ transferred).
+
+ So, for example:
+
+ send *.txt \v(filename).new
+
+ sends each file with its own name, but with ".new" appended to it. Of
+ course if the name already contains periods, this could confuse the
+ file receiver, so you can also achieve fancier effects with
+ constructions like:
+
+ send *.txt \freplace(\v(filename),.,_).new
+
+ which replaces all periods in the original filename by underscores, and
+ then appends ".new" to the result. So, for example, oofa.txt would be
+ sent as oofa_txt.new.
+
+ Another new variable that is useful in this regard is \v(filenumber),
+ which is the ordinal number of the current file in the file group, so
+ you can also:
+
+ send *.txt FILE\flpad(\v(filenum),2,0)
+
+ resulting in a series of files called FILE00, FILE01, FILE02, etc. (At
+ the end of the transfer, \v(filenum) tells the number of files that
+ were transferred).
+
+ If you specify a constant as-name when sending a file group:
+
+ send *.txt thisnameonly
+
+ Kermit complains and asks you to include replacement variables in the
+ as-name. You should generally use \v(filename) or \v(filenumber) for
+ this purpose, since other variables (with the possible exception of
+ date/time related variables) do not change from one file to the next.
+ But Kermit accepts any as-name at all that contains any kind of
+ variables for file group, even if the variable will not change. So:
+
+ send *.txt \%a
+
+ is accepted, but all files are sent with the same name (the value of
+ \%a, if it has one and it is constant). If the variable has no value at
+ all, the files are sent under their own names.
+
+ Of course, the value of \%a in the previous example need not be
+ constant:
+
+ define \%a FILE\flpad(\v(filenum),2,0)_at_\v(time)
+ send *.txt \%a
+
+ The RECEIVE command, when given without an as-name, behaves as always,
+ storing all incoming files under the names they arrive with, subject to
+ SET FILE NAME and SET RECEIVE PATHNAMES modifications ([441]Section
+ 4.10).
+
+ However, when an as-name is given in the RECEIVE command, it is applied
+ to all incoming files rather than to just the first. If it does not
+ contain replacement variables, then the current FILE COLLISION setting
+ governs the result. For example:
+
+ receive foo
+
+ will result in incoming files named foo, foo.~1~, foo.~2~, and so on,
+ with the default FILE COLLISION setting of BACKUP. If it does contain
+ replacement variables, of course they are used.
+
+ When receiving files, the \v(filename) variable refers to the name that
+ was received in the incoming file-header packet, BEFORE any processing
+ by SET FILE NAMES or SET RECEIVE PATHNAMES. Since the filenames in
+ file-header packets are usually in uppercase, you would need to convert
+ them explicitly if you want them in lowercase, e.g.:
+
+ receive \flower(\v(filename)).new
+
+4.1.2. Templates on the Command Line
+
+ On the command-line, use templates as shown above as the -a option
+ argument, bearing in mind the propensity of UNIX and perhaps other
+ shells to treat backslash as a shell escape character. So in UNIX (for
+ example):
+
+ kermit -s oofa.* -a x.\\v(filenum)
+
+ By the way, this represents a change from 6.0 and earlier releases in
+ which the as-name (-a argument or otherwise) was not evaluated by the
+ command parser. Thus, for example, in VMS (where the shell does not
+ care about backslashes), it was possible to:
+
+ kermit -s oofa.txt -a c:\tmp\oofa.txt
+
+ Now backslashes in the as-name must be quoted not only for the shell
+ (if necessary) but also for Kermit itself:
+
+ kermit -s oofa.txt -a c:\\tmp\\oofa.txt ; Kermit only
+ kermit -s oofa.txt -a c:\\\\tmp\\\\oofa.txt ; Shell and Kermit
+
+ You can also use the \fliteral() function for this:
+
+ kermit -s oofa.txt -a \fliteral(c:\tmp\oofa.txt) ; Kermit only
+ kermit -s oofa.txt -a \\fliteral(c:\\tmp\\oofa.txt) ; Shell and Kermit
+
+4.1.3. Post-Transfer Renaming
+
+ Filename templates are now also useful in SET { SEND, RECEIVE }
+ RENAME-TO and in the /RENAME-TO: switch, that can be given to the SEND,
+ GET, or RECEIVE commands; this is similar to an as-name, but is
+ effective on a per-file basis if and only if the file was transferred
+ successfully.
+
+ MOVE-TO and RENAME-TO address a requirement commonly stated for
+ transaction processing and similar systems. Suppose, for example, a
+ central system "X" accepts connections from multiple clients
+ simultaneously; a process on X waits for a file to appear and then
+ processes the file. This process must have a way of knowing when the
+ file has been completely and successfully transferred before it starts
+ to process it. This can be accomplished easily using C-Kermit's SET {
+ SEND, RECEIVE } { MOVE-TO, RENAME-TO } command or /MOVE-TO: or
+ /RENAME-TO: switches, described in [442]Sections 4.7.1 through
+ [443]4.7.3.
+
+ Here's an example for the client side, in which files to be sent are
+ placed in a certain directory (/usr/olga/tosend in this example) by
+ another process when they are ready to go. This might be in a hospital
+ or big doctor's office, where medical insurance claims are entered at a
+ number of workstations, and then deposited in the "tosend" directory,
+ from which they are sent to a claims clearinghouse. We assume the
+ connection is already made and a Kermit server is on the other end.
+
+ local srcdir findir ; Declare local (automatic) variables
+ assign srcdir /usr/olga/tosend ; Local source directory (files to send)
+ assign findir /usr/olga/sent ; Where to move files after they are sent
+ log transactions ; Keep a log of transfers
+ cd \m(srcdir) ; Change to the source directory
+ while true { ; Loop forever...
+ send /move-to:\m(findir) * ; Send all files
+ sleep 60 ; Sleep a minute
+ } ; Go back and do it again
+
+ Note how simple this is. Once each file is sent, it is moved so it
+ won't be sent again (you could also use SEND /RENAME-TO: or even SEND
+ /DELETE). If a transfer fails, the file is not moved and so we try
+ again to send it next time around. If there are no files to send, the
+ SEND command does nothing but a message is printed; you can avoid the
+ message by checking first to see if any files are in the directory:
+
+ while true { ; Loop forever...
+ if > \ffiles(*) 0 - ; If there are any files
+ send /move-to:\m(findir) * ; send them.
+ sleep 60 ; Sleep a minute.
+ } ; Go back and do it again.
+
+ It's even simpler on the server side (here again we assume the
+ connection is already in place):
+
+ local rcvdir findir ; Declare local (automatic) variables
+ assign rcvdir /usr/ivan/tmp ; Temporary receiving directory
+ assign findir /usr/ivan/new ; Where to move files after reception
+ log transactions ; Keep a log of transfers
+ cd \m(rcvdir) ; Change to the source directory
+ set receive move-to \m(findir) ; Declare move-to directory.
+ server ; Enter server mode.
+
+ A separate process (e.g. the medical claim-form decoder) can look for
+ files appearing in the /usr/ivan/new directory and process them with
+ every confidence that they have been completely received.
+
+ Note that the use of MOVE-TO can result in moved files overwriting one
+ another (the application would normally avoid this by assigning each
+ transaction a unique, e.g. based on customer number and claim number).
+ But if filename collisions are a possibility in your application,
+ RENAME-TO might be a better choice; you can use any variables you like
+ in the template to ensure uniqueness of the RENAME-TO filename; for
+ example:
+
+ SET RECEIVE RENAME-TO \v(filename)_\v(ndate)_\v(ntime)_\v(userid)_\v(pid)
+
+4.2. FILE-TRANSFER PIPES AND FILTERS
+
+4.2.1. INTRODUCTION
+
+ Beginning in C-Kermit 6.1 and Kermit 95 1.1.12, it is possible to send
+ from a command, or "pipe", as well as from a file, and to receive to a
+ pipe or command. In a typical example, we might want to transfer an
+ entire directory tree from one UNIX system to another (but without
+ using the methods described in [444]Sections 4.3 , [445]4.10,
+ [446]4.11, and [447]4.15). We could do this in multiple steps as
+ follows:
+
+ 1. Create a tar archive of the desired directory tree
+ 2. Compress the tar archive
+ 3. Transfer it in binary mode to the other computer
+ 4. Decompress it
+ 5. Extract the directory tree from the tar archive
+
+ But this is inconvenient and it requires a temporary file, which might
+ be larger than we have room for.
+
+ The new pipe-transfer feature lets you do such things in a single step,
+ and without intermediate files.
+
+ Additional new features, also discussed here, let you specify pre- and
+ post- processing filters for outbound and incoming files, and give you
+ a way to insert the output from shell or system commands into C-Kermit
+ commands.
+
+ The file-transfer related features are available only with Kermit
+ protocol, not with any external protocols, nor with K95's built-in
+ XYZMODEM protocols (because XYZMODEM recovers from transmission errors
+ by rewinding the source file, and you can't rewind a pipe).
+
+ This section begins by discussing the simple and straightforward use of
+ these features in UNIX, in which pipes and input/output redirection are
+ a fundamental component and therefore "just work", and then goes on to
+ discuss their operation in Windows and OS/2, where matters are much
+ more complicated.
+
+4.2.1.1. TERMINOLOGY
+
+ Standard Input
+ This is a precise technical term denoting the normal source of
+ input for a command or program, which is the keyboard of your
+ terminal by default, but which can be redirected to a file or
+ pipe.
+
+ Stdin
+ Abbreviation for Standard Input.
+
+ Standard Output
+ A precise technical term denoting the normal destination for
+ output from a command or program, which is your terminal screen
+ by default, but which can be redirected to a file.
+
+ Stdout
+ Abbreviation for Standard Output.
+
+ Stdio
+ Abbreviation for Standard Input / Standard Output.
+
+ I/O
+ Abbreviation for Input / Output.
+
+ Shell
+ Text-based system command processor, such as the UNIX shell, DOS
+ COMMAND.COM, etc.
+
+ Pipe
+ A mechanism by which the standard output of one program is sent
+ to the standard input of another.
+
+ Pipeline
+ A series of programs connected by pipes.
+
+4.2.1.2. NOTATION
+
+ In command descriptions, "command" is replaced by a shell or system
+ command or pipeline. The command names specified in these commands are
+ interpreted by your shell, just as if you were typing them at the shell
+ prompt, and so if they are in your PATH, they will be found in the
+ expected manner. Therefore you don't have to specify complete pathnames
+ for commands that are programs (but it shouldn't hurt if you do).
+
+ The normal notation for I/O redirection is as follows:
+
+ < Read Stdin from the given file.
+ > Send Stdout to the given file.
+ | Send Stdout from the command on the left to the command on the right.
+
+ Examples:
+
+ sort < foo > bar
+ Sorts the lines in file "foo" and writes the results to file
+ "bar"
+
+ grep -c "some text" *.txt | grep -v ":0" | sort | pr -3 | lpr
+ This is a command pipeline composed of 5 commands:
+
+ grep -c "some text" *.txt
+ Looks in all files whose names end with ".txt" for the string
+ "some text" and writes to Stdout the names of each file followed
+ by a colon and the number of occurrences in each.
+
+ grep -v ":0"
+ Prints to Stdout the lines from Stdin that do NOT contain the
+ string ":0", in this case, it removes the names of files that do
+ not contain "some text".
+
+ sort
+ Sorts the lines from Stdin alphabetically to Stdout.
+
+ pr -3
+ Arranges the lines from Stdin in three columns.
+
+ lpr
+ Prints its Stdin on the default printer.
+
+ Note that the Kermit features described here work only with commands
+ that use Stdio. If you attempt to use them with commands whose input
+ and output can not be redirected, Kermit will most likely get stuck.
+ Kermit has no way of telling how an external command works, nor what
+ the syntax of the shell is, so it's up to you to make sure you use
+ these features only with redirectable commands.
+
+ The quoting rules of your shell apply to the command. Thus in UNIX,
+ where C-Kermit tries to use your preferred shell for running commands,
+ shell "metacharacters" within commands must be escaped if they are to
+ be taken literally, using the methods normal for your shell. For
+ example, the UNIX tr (translate) command must have its arguments in
+ quotes:
+
+ tr "[a-z]" "[A-Z]"
+
+ otherwise the shell is likely to replace them by all filenames that
+ match, which is probably not what you want. This is also true when
+ using your shell directly, and has nothing to do with Kermit.
+
+4.2.1.3. SECURITY
+
+ Some sites might not wish to allow access to system commands or
+ external programs from within Kermit. Such access, including all the
+ features described here, can be disabled in various ways:
+
+ 1. When building from source code, include -DNOPUSH among the CFLAGS.
+ 2. At runtime, give the NOPUSH command.
+ 3. For server mode, give the DISABLE HOST command.
+ 4. Implicit use of pipes can be disabled as described in [448]Section
+ 4.2.4.
+
+ Note: 3 and 4 are not necessary if you have done 1 or 2.
+
+4.2.2. Commands for Transferring from and to Pipes
+
+ SEND /COMMAND sends data from a command or command pipeline, and
+ RECEIVE /COMMENT writes data to a command or pipeline. The GET /COMMAND
+ command asks a server to send material, and then writes the incoming
+ material to a command or pipeline. These features, along with switches
+ (like "/COMMAND", described in [449]Section 4.7) are new to C-Kermit
+ 6.1. The following synonyms are also provided:
+
+ CSEND = SEND /COMMAND
+ CRECEIVE = RECEIVE /COMMAND
+ CGET = GET /COMMAND
+
+ None of these commands can be used if a SEND or RECEIVE FILTER
+ (respectively, [450]Section 4.2.3) is in effect, or if a NOPUSH command
+ ([451]Section 4.2.1.3) has been given, or if the current protocol is
+ not Kermit.
+
+4.2.2.1. Sending from a Command
+
+ SEND /COMMAND command [ as-name ]
+ SEND /AS-NAME:as-name /COMMAND command
+ CSEND command [ as-name ]
+ These three forms are the same. They work like the SEND command,
+ but instead of sending a file, it sends the standard output of
+ the given command, either under the command's own name, or else
+ with the given as-name. If the command contains spaces, it must
+ be enclosed in braces. Braces should also be used for the
+ as-name if it contains spaces. If braces are included around
+ either the command or the as-name, they are removed after
+ parsing but before use. As with SEND, the transfer is in text or
+ binary mode according the current FILE TYPE setting, unless you
+ override the global transfer mode by including a /TEXT or
+ /BINARY switch. The command must require no input.
+
+ When sending from a command or pipeline, C-Kermit has no way of knowing
+ in advance how much data will be sent, and so it can not send the size
+ to the other Kermit in the Attribute packet, and so the receiving
+ Kermit has no way of displaying "percent done" or a progress bar
+ (thermometer).
+
+ Examples that make sense in text mode (illustrated by common UNIX
+ commands):
+
+ SEND /COMMAND finger
+ CSEND finger
+ sends the current "finger" listing (who's logged in) under the
+ name "finger". The two forms "send /command" and "csend" are
+ equivalent; we won't bother showing them both in the rest of the
+ examples.
+
+ SEND /COMMAND:{finger}
+ CSEND {finger}
+ Same as previous example (braces are removed from "{finger}").
+
+ SEND /COMMAND:{ finger }
+ CSEND { finger }
+ Same as previous example, but note that the spaces are kept.
+ This does not prevent the shell from running the "finger"
+ program, but its output is sent under the name " finger " (with
+ a leading and trailing space).
+
+ SEND /COMMAND:finger /AS-NAME:userlist
+ CSEND finger userlist
+ sends the current finger listing under the name "userlist".
+
+ SEND /COMMAND:{finger | sort -r} /AS-NAME:userlist
+ CSEND {finger | sort -r} userlist
+ sends the current finger listing, sorted in reverse order, under
+ the name "userlist". The braces are needed to distinguish the
+ command from the as-name.
+
+ SEND /COMMAND:{finger | sort -r} /AS-NAME:{userlist}
+ CSEND {finger | sort -r} {userlist}
+ Same as previous example (braces are removed from "{userlist}").
+
+ SEND /COMMAND:{finger | sort -r}
+ /AS-NAME:{\freplace(\v(filename),\32,_)}
+
+ CSEND {finger | sort -r} {\freplace(\v(filename),\32,_)}
+ Like the previous example, but sends the output of the command
+ under the name of the command, but with all spaces (\32)
+ replaced by underscores, so the as-name is "finger_|_sort_-r".
+
+ Examples that make sense in binary mode (three equivalent forms are
+ shown):
+
+ SEND /COMMAND /BINARY {tar cf - . | gzip -c} mydir.tar.gz
+ SEND /COMMAND /BINARY /AS-NAME:mydir.tar.gz {tar cf - . | gzip -c}
+ CSEND /BINARY {tar cf - . | gzip -c} mydir.tar.gz
+ Makes a tar archive of the current directory, compresses it with
+ the GNU gzip program, and sends it as "mydir.tar.gz". The other
+ Kermit can, of course, just store it as a file, or it can use
+ CRECEIVE to uncompress and dearchive it as part of the transfer
+ process.
+
+ When using a "pipeline" of commands in the command field, obviously,
+ the first command must not require any input, and the last command
+ should produce some output, and all intermediate commands should get
+ some input and produce some output.
+
+4.2.2.2. Receiving to a Command
+
+ RECEIVE /COMMAND command
+ CRECEIVE command
+ This is like RECEIVE, except incoming material is written to the
+ standard input of the given command, in text or binary mode
+ according to the normal rules for file reception. Be sure to
+ include a redirector to a file (if the command normally writes
+ to standard output), or the output of the command won't go
+ anywhere. The command may contain spaces; braces are not needed,
+ but they are removed if used.
+
+ WARNING: C-Kermit has no way of knowing anything about the command, or
+ even whether it is a command. Thus this command will always cause
+ C-Kermit to enter protocol mode, as long as some text is specified in
+ the command field. However, if the text does not correspond to a
+ command, the transfer will eventually fail with a message such as
+ "Error writing data" or "Failure to close file".
+
+ Examples for text mode (in UNIX):
+
+ RECEIVE /COMMAND sort -r > reverse.txt
+ CRECEIVE sort -r > reverse.txt
+ The text that is received is sorted in reverse order and stored
+ in the file "reverse.txt". The two forms shown are equivalent.
+
+ RECEIVE /COMMAND {sort -r > reverse.txt}
+ CRECEIVE {sort -r > reverse.txt}
+ The same as the previous example; if braces are included, they
+ are simply removed.
+
+ RECEIVE /COMMAND {sort -r > \flower(\v(filename)).reverse}
+ CRECEIVE {sort -r > \flower(\v(filename)).reverse}
+ Same but stores result under the incoming filename, lowercased,
+ and with ".reverse" appended to it.
+
+ RECEIVE /COMMAND sort
+ CRECEIVE sort
+ Does nothing useful, since the output of sort has nowhere to go.
+
+ RECEIVE /COMMAND sort -r | pr -3 | lpr -Plaserjet
+ CRECEIVE sort -r | pr -3 | lpr -Plaserjet
+ The text that is received is sorted in reverse order, arranged
+ into three columns, and sent to the "laserjet" printer.
+
+ Examples for binary mode:
+
+ RECEIVE /COMMAND:{gunzip -c | tar xf -}
+ CRECEIVE {gunzip -c | tar xf -}
+ Assuming the data that is received is a compressed tar archive,
+ uncompresses the archive and passes it to tar for extraction. In
+ this case the braces are needed because otherwise the final "-"
+ would be taken as a command continuation character (see
+ [452]Using C-Kermit, 2nd Edition, p.33).
+
+ GET /COMMAND remote-file command
+ GET /COMMAND /AS-NAME:command remote-file
+ CGET remote-file command
+ This command tells the Kermit client to send a GET request for
+ the given remote file to a Kermit server. Unlike GET, however,
+ the incoming material is written to a command, rather than to a
+ file. If the remote-file or the command contain spaces, they
+ must be enclosed in braces. The same cautions about the command
+ apply as for CRECEIVE.
+
+ Examples (for UNIX):
+
+ GET /COMMAND oofa.txt sort -r > oofa.new
+ GET /COMMAND {oofa.txt} {sort -r > oofa.new}
+ CGET oofa.txt sort -r > oofa.new
+ CGET {oofa.txt} {sort -r > oofa.new}
+ These four are equivalent. Each of them requests the server to
+ send its "oofa.txt" file, and as it arrives, it is sorted in
+ reverse order and written to "oofa.new".
+
+ GET /COMMAND {profile exec a} lpr
+ GET /COMMAND {profile exec a} {lpr}
+ GET /COMMAND /AS-NAME:lpr {profile exec a}
+ GET /COMMAND /AS-NAME:{lpr} {profile exec a}
+ GET /COMMAND /AS:lpr {profile exec a}
+ CGET {profile exec a} lpr
+ CGET {profile exec a} {lpr}
+ Here the remote filename contains spaces so it MUST be enclosed
+ in braces. As it arrives it is sent to the lpr program for
+ printing. Braces are optional around "lpr" since it contains no
+ spaces.
+
+ GET /COMMAND *.txt {cat >> new.txt}
+ GET /AS-NAME:{cat >> new.txt} /COMMAND *.txt
+ CGET *.txt {cat >> new.txt}
+ This gets all the ".txt" files from the server and concatenates
+ them all into a single "new.txt" file on the client.
+
+ GET /COMMAND *.txt {echo \v(filename)>>new.txt;cat>>new.txt}
+ CGET *.txt {echo \v(filename)>>new.txt;cat>>new.txt}
+ As above, but inserts each file's name before its contents.
+
+4.2.3. Using File-Transfer Filters
+
+ The commands described in [453]Section 4.2.2 let you send the output of
+ a command, or receive data into a command. But what if you want to
+ specify preprocessing for files that you send, or postprocessing of
+ files that you receive, even when multiple files are involved? For this
+ you need a way to specify send and receive filters. The commands are
+ SET SEND FILTER and SET RECEIVE FILTER; SHOW PROTOCOL displays the
+ current settings.
+
+4.2.3.1. The SEND Filter
+
+ SET SEND FILTER [ command ]
+ This command specifies a command to be run on any file that you
+ SEND (or MOVE, MSEND, etc). It also applies to files sent when
+ in server mode, in response to GET commands, but not to the
+ results of REMOTE commands like REMOTE DIRECTORY, REMOTE TYPE,
+ REMOTE HOST, etc. The command may be, but need not be, enclosed
+ in braces; if it is, the braces are stripped before use. The
+ output of this command is sent, rather than the file itself. The
+ current FILE TYPE setting (TEXT or BINARY) applies to the output
+ of the command. The command must contain at least one instance
+ of \v(filename), for which the name of the actual file is
+ substituted. If the command is omitted, the send filter is
+ removed and files are sent in the normal manner.
+
+ The SET SEND FILTER sets up a "global" filter -- that is, one that
+ applies to all subsequent file-sending commands until you change or
+ remove it. You can also specify a "local" filter to be used in a
+ specific file-sending command by using the /FILTER switch (see
+ [454]Section 1.5); for example:
+
+ SEND /FILTER:command [ other-switches ] filename
+
+ Besides \v(filename), you can include any other script programming
+ notation in the send filter: variable names, array references, calls to
+ built-in string or other functions, and so on. These are evaluated
+ during file transfer, NOT during parsing, and they are evaluated
+ separately for each file.
+
+ When the SEND or MOVE (SEND /DELETE) command is used with a send
+ filter, the output from the filter is sent under the file's original
+ name unless you specify an "as-name" or template. The Attribute packet
+ (if any) contains the original file's attributes (size, creation date,
+ etc). So (for example) if the filter changes the file's size, the
+ progress thermometer might be wrong. (We can't send the size of the
+ output from the filter, because it is not known until the transfer is
+ finished.) If you prefer that the size not be sent, use "set attributes
+ size off".
+
+ You can not use send filters with RESEND (SEND /RECOVER) or PSEND (SEND
+ /START).
+
+ Examples for text mode:
+
+ SET SEND FILTER sort -r \v(filename) ; Braces may be omitted
+ SET SEND FILTER {sort -r \v(filename)} ; Braces may be included
+ SEND *.txt
+ This sends every file in the current directory whose name ends
+ with ".txt" under its own name, but with its lines sorted in
+ reverse order.
+
+ SEND /FILTER:{sort -r \v(filename)} *.txt
+ Same as above, but the filter applies only to this SEND command.
+ Braces are required in this case.
+
+ SET SEND FILTER {sort -r \v(filename)}
+ SEND oofa.txt reverse.txt
+ Sends the oofa.txt file with its lines sorted in reverse order
+ under the name "reverse.txt".
+
+ SET SEND FILTER {sort -r \v(filename)}
+ SEND oofa.* \v(filename).reverse
+ Sends all the oofa.* files with their lines sorted in reverse
+ order; each file is sent under its own name but with ".reverse"
+ appended to it.
+
+ SET SEND FILTER {tr "[a-z]" "[A-Z]" < \v(filename)}
+ SEND *.txt
+ Sends all ".txt" files under their own names, but uppercasing
+ their contents.
+
+ Note that the SEND FILTER applies not only to files that are sent with
+ SEND, MOVE, MSEND, etc, but also to files sent by the C-Kermit server
+ in response to GET requests.
+
+ Examples for binary mode:
+
+ SET SEND FILTER {gzip -c \v(filename)}
+ SEND /BINARY oofa.txt oofa.txt.gz
+ Sends the oofa.txt file, compressed by gzip, as oofa.txt.gz.
+
+ SEND /BINARY /FILTER:{gzip -c \v(filename)} oofa.txt oofa.txt.gz
+ As above, but the filter applies only to this SEND command.
+
+ SET SEND FILTER {gzip -c \v(filename)}
+ SEND /BINARY oofa.* \fupper(\replace(\v(filename),.,_)).GZ
+ Sends all the oofa.* files, compressed by gzip, each under its
+ own name, but with the name uppercased, all periods within the
+ name converted to underscores, and ".GZ" appended to it. So, for
+ example, "oofa.txt" is sent as "OOFA_TXT.GZ".
+
+ In the gzip examples, note that the amount of data that is sent is
+ normally less than the original file size because gzip compresses the
+ file. But Kermit sends the original file size ahead in the attribute
+ packet anyway (unless you tell it not too). Thus the transfer will
+ probably appear to terminate early, e.g. when the receiver's
+ file-transfer display thermometer is only at 40%. If this annoys you,
+ tell Kermit to "set attribute length off". On the other hand, you can
+ use the final position of the thermometer as a measure of the
+ effectiveness of compression.
+
+4.2.3.2. The RECEIVE Filter
+
+ SET RECEIVE FILTER [ command ]
+ This command specifies that the given command will be run on any
+ file that is received before it is written to disk. The command
+ may be, but need not be, enclosed in braces; if it is the braces
+ are stripped before use. The following two commands are
+ equivalent:
+
+ SET RECEIVE FILTER sort -r > \v(filename)
+ SET RECEIVE FILTER {sort -r > \v(filename)}
+
+ The RECEIVE filter command may contain a "\v(filename)" sequence to be
+ replaced by the incoming filename from the file header packet, but it
+ is not required. However you must use it whenever your filter would
+ normally write to Stdout, otherwise its output will be lost.
+
+ The RECEIVE filter command may contain one or more "\v(filename)"
+ sequence to be replaced by the incoming filename from the file header
+ packet, but it is not required. However you must use it whenever your
+ filter would normally write to Stdout, otherwise its output will be
+ lost.
+
+ RECEIVE /FILTER:command and GET /FILTER:command can also be used to
+ specify a filter to be used for only one file-transfer operation.
+
+ UNIX examples for text mode:
+
+ SET RECEIVE FILTER lpr
+ RECEIVE
+ All the files that are received are sent to the default UNIX
+ print spooler.
+
+ RECEIVE /FILTER:lpr
+ Same as above, except the lpr filter is used only with this
+ RECEIVE command.
+
+ RECEIVE lpr
+ This is probably not what you want; it creates a file called
+ lpr.
+
+ SET RECEIVE FILTER {sort -r > \v(filename)}
+ RECEIVE
+ Stores each incoming file with its lines sorted in reverse
+ order, under its own name.
+
+ RECEIVE /FILTER:{sort -r > \v(filename)}
+ As above, but the filter is used only for this RECEIVE command.
+
+ SET RECEIVE FILTER sort -r > \v(filename)
+ RECEIVE reverse.txt
+ Stores each incoming file with its lines sorted in reverse
+ order, under the name "reverse.txt". The actual result depends
+ on the FILE COLLISION setting. If it is OVERWRITE and multiple
+ files arrive, then each incoming file destroys the previous one.
+ If it is BACKUP (the default), filename conflicts are resolve by
+ adding "version numbers" to the filenames: reverse.txt,
+ reverse.txt.~1~, reverse.txt.~2~, etc.
+
+ SET RECEIVE FILTER sort -r > \v(filename)
+ RECEIVE \v(filename).reverse
+ Stores each incoming file with its lines sorted in reverse
+ order, under the name it arrived with, but with ".reverse"
+ appended to it.
+
+ SET RECEIVE FILTER sort -r > \v(filename)
+ RECEIVE \flower(\v(filename)).reverse
+ Like the previous example, but ensures that the filename is
+ lowercase.
+
+ Examples for binary mode:
+
+ SET RECEIVE FILTER gunzip -c > \v(filename)
+ RECEIVE
+ This receives one or more presumably compressed file and
+ uncompresses each one into a file having the same name it was
+ sent with. For example, if the file is sent with the name
+ OOFA.TXT.GZ, it is stored with that name, even after
+ decompression.
+
+ SET RECEIVE FILTER gunzip -c > \v(filename)
+ RECEIVE \flower(\fsubstring(\v(filename),1,\flength(\v(filename))-3))
+ Like the previous example, but the resulting filename has its
+ rightmost three characters removed from it and the remainder is
+ lowercased. So if the incoming filename is OOFA.TXT.GZ, it is
+ stored as oofa.txt after decompression.
+
+ Of course you don't want to type such long hideous commands, so we have
+ also introduced several new functions:
+
+ \fstripx(string[,character])
+ This function removes the rightmost segment of the string that
+ starts with the given character. If no character is given,
+ period (.) is used. Thus it is most conveniently used for
+ stripping the extension from a filename (or the decimal portion
+ from a floating-point number written in US/UK style). Examples:
+
+ \fstripx(OOFA.TXT.GZ) => OOFA.TXT
+ \fstripx(OOFA.TXT.GZ,.) => OOFA.TXT
+ \fstripx(OOFA.TXT.GZ,X) => OOFA.T
+ \fstripx(\fstripx(OOFA.TXT.GZ)) => OOFA
+ \fstripx($100.00) => $100
+
+ \fstripn(string,number)
+ Removes the rightmost number characters from the string.
+ Examples:
+
+ \fstripn(OOFA.TXT.GZ) => OOFA.TXT.GZ
+ \fstripn(OOFA.TXT.GZ,3) => OOFA.TXT
+ \fstripn(OOFA.TXT.GZ,7) => OOFA
+
+ \fstripb(string[,c1[,c2]])
+ Strips enclosing matching braces, brackets, parentheses, or
+ quotes from the string. The second argument, c1, specifies which
+ kind of enclosure to look for; if not specified, any enclosing
+ (), [], <>, {}, "", '', or `' are removed. If c1 is specified
+ and c2 is not, then if c1 is an opening brace, bracket, or
+ parenthesis, the matching closing one is supplied automatically
+ as c2. If both c1 and c2 are specified, then to be stripped the
+ string must begin with c1 and end with c2. If the string is not
+ enclosed in the indicated manner, the result is the original
+ string. Examples:
+
+ \fstripb("abc") => abc
+ \fstripb([abc]) => abc
+ \fstripb([abc) => [abc
+ \fstripb(<abc>) => abc
+ \fstripb(<abc>,[) => <abc>
+ \fstripb((abc)) => abc
+ \fstripb((abc),[) => (abc)
+ \fstripb((abc),{(}) => abc
+ \fstripb(+abc+) => +abc+
+ \fstripb(+abc+,+) => abc
+ \fstripb(+abc+,+,^) => +abc+
+ \fstripb(+abc^,+,^) => abc
+ \fstripb('abc') => abc
+ \fstripb(`abc') => abc
+ \fstripb(``abc'') => `abc'
+ \fstripb(\fstripb(``abc'')) => abc
+
+ Notice the special syntax required for including a literal
+ parenthesis in the argument list. As the last two examples
+ illustrate, \fstripb() strips only one level at at a time;
+ nesting can be used to strip a small fixed number of levels;
+ loops can be used to strip larger or indeterminate numbers of
+ levels.
+
+ \flop(string[,char])
+ Removes the leftmost segment of the string that ends with the
+ given character. If no character is given, period (.) is used.
+ Examples:
+
+ \flop(OOFA.TXT.GZ) => TXT.GZ
+ \flop(OOFA.TXT.GZ,.) => TXT.GZ
+ \flop(OOFA.TXT.GZ,X) => T.GZ
+
+ To remove the leftmost number characters, just use
+ \fsubstring(s,number+1). To return the rightmost number
+ characters, use \fright(s,number).
+
+ So the hideous example:
+
+ receive \flower(\fsubstring(\v(filename),1,\flength(\v(filename))-3))
+
+ can now be written as:
+
+ receive \flower(\fstripx(\v(filename)))
+
+ That is, the filename stripped of its extension and then lowercased.
+ This is not only shorter and less hideous, but also does not depend on
+ the length of the extension being 3.
+
+ Note that when a receive filter is in effect, this overrides your FILE
+ COLLISION setting, since Kermit has no way of knowing what the final
+ destination filename will be (because it does not know, and can not be
+ expected to know, the syntax of every version of every command shell on
+ every platform on the planet).
+
+4.2.4. Implicit Use of Pipes
+
+ If you wish, C-Kermit can also examine incoming filenames to see if
+ they start with "!", and if so, the subsequent text is treated as a
+ command to read from or write to. For example, if a Kermit client is
+ given the following command:
+
+ get {!finger | sort}
+
+ the server on the other end, if it supports this feature, will run the
+ "finger" program, pipe its standard output to the "sort" program, and
+ send sort's standard output back to you. Similarly, if you:
+
+ send oofa.txt !sort -r > oofa.new
+
+ or, equivalently:
+
+ send oofa.txt {!sort -r > oofa.new}
+
+ or:
+
+ send /as-name:{!sort -r > oofa.new} oofa.txt
+
+ this has the receiver send the contents of the incoming oofa.txt file
+ to the sort program, which sorts the text in reverse order and stores
+ the result in oofa.new.
+
+ This use of the exclamation mark should be familiar to UNIX users as
+ the "bang" feature that lets you run an external application or command
+ from within another application.
+
+ Kermit's "bang" feature is disabled by default, since it is not unheard
+ for filenames to actually begin with "!". So if you want to use this
+ feature, you must enable it with the following command:
+
+ SET TRANSFER PIPES { ON, OFF }
+ ON enables the recognition of "!" notation in incoming filenames
+ during file transfer as an indicator that the remaining text is
+ the name of a command. OFF, the default, disables this feature
+ and uses the text as a filename in the normal fashion. This
+ command does NOT affect SEND /COMMAND, GET /COMMAND, CSEND, etc.
+
+ So using a combination of CSEND (SEND /COMMAND) and the "bang" feature,
+ you can transfer a directory tree all in one command (assuming the
+ remote Kermit supports pipe transfers and has them enabled):
+
+ CSEND {tar cf - . | gzip -c} {!gunzip -c | tar xf -}
+
+ or:
+
+ SEND /COMMAND:{tar cf - . | gzip -c} /as:{!gunzip -c | tar xf -}
+
+ Pay close attention to the syntax. Braces are needed around the command
+ because it contains spaces; braces are needed around the as-name
+ because it ends with "-". The as-name must begin with "!" or receiving
+ Kermit will not recognize it as a command. The CSEND command must NOT
+ begin with "!" unless you are running a command whose name really does
+ start that character.
+
+ Similarly, you have a Kermit server send a directory tree to be
+ unpacked on the client end:
+
+ CGET {!tar cf - . | gzip -c} {gunzip -c | tar xf -}
+
+ or:
+
+ GET /COMMAND {!tar cf - . | gzip -c} /as:{gunzip -c | tar xf -}
+
+ Notice how, in this case, the bang is required in the remote command,
+ to distinguish it from a filename, but not in the local command, since
+ by definition of CGET (or GET /COMMAND), it is known to be a command.
+
+ SEND and RECEIVE FILTERs supersede the bang feature. For example, if a
+ file arrives under the name "!gunzip -c | tar xf -", but the receiving
+ Kermit also has been given a command like:
+
+ set receive filter sort -r > \v(filename)
+
+ then the incoming data will be sorted rather than gunzipped.
+
+ Finally, if SET TRANSFER PIPES is ON (and in this case, this must be
+ done in your C-Kermit initialization file), you can send from a pipe on
+ the C-Kermit command line:
+
+ kermit -s "!finger | sort -r" -a userlist
+
+ In this case the "filename" contains spaces and so must be quoting
+ using your shell's quoting rules.
+
+4.2.5. Success and Failure of Piped Commands
+
+ Commands or programs started by Kermit as a result of CSEND or CRECEIVE
+ commands, CGET, SEND /COMMAND, REDIRECT commands (see [455]Section
+ 4.2.8.2), implicit use of pipes, RUN commands, and so forth, should
+ return their exit status codes to the Kermit command that caused them
+ to be run, and therefore IF SUCCESS and IF FAILURE tests after these
+ commands should work as expected. For example:
+
+ CSEND blah < filename
+
+ should fail if there is no command called "blah" or if there is no file
+ called "filename". However, this is not foolproof and sometimes
+ C-Kermit might think a command succeeded when it failed, or vice versa.
+ This is most likely to happen when the highly system-dependent methods
+ that Kermit must use to determine a command's exit status code do not
+ supply the right information.
+
+ It can also happen because some commands might define success and
+ failure differently from what you expect, or because you are using a
+ pipeline composed of many commands, and one of them fails to pass
+ failing exit status codes up the chain. The most likely culprit is the
+ shell itself, which in most cases must be interposed between Kermit and
+ any external program to be run.
+
+ In any case, you can examine the following variable to find out the
+ exit status code returned to Kermit by the process most recently run by
+ any command that runs external commands or programs, including CSEND,
+ CRECEIVE, REDIRECT, RUN, etc:
+
+ \v(pexitstat)
+
+ In UNIX, Windows and OS/2, the value should be -2 if no command has
+ been run yet, 0 if the most recent command succeeded, -1, -3, or -4 if
+ there was an internal error, and a positive number returned by the
+ command itself if the command failed. If the number is in the range
+ 1-127, this is the program's exit status code. If it is 128 or greater,
+ this is supposed to indicate that the command or program was
+ interrupted or terminated from outside itself.
+
+ In Windows 95 and 98, the return values of the default shell are
+ unreliable; various third-party shells can be used to work around this
+ deficiency.
+
+ In VMS, it is the actual exit status code of the command that was run.
+ This is an odd number if the command succeeded, and an even number if
+ it failed. You can see the associated message as follows:
+
+ run write sys$output f$message(\v(pexitstat))
+
+ Or, more conveniently, use the new Kermit function:
+
+ echo \ferrstring(\v(pexitstat))
+
+ which converts a system error code (number) to the corresponding
+ message.
+
+4.2.6. Cautions about Using Pipes to Transfer Directory Trees
+
+ Although utilities such as tar and zip/unzip might be available on
+ different platforms (such as UNIX and Windows), this does not
+ necessarily mean you can use them successfully to transfer directory
+ trees between unlike platforms. For example:
+
+ CSEND {tar cf - . | gzip -c} {!gunzip -c | tar xf -}
+
+ when used from UNIX to Windows will have satisfactory results for
+ binary files, but not for text files. UNIX text files have lines ending
+ with Linefeed (LF) only, whereas Windows text files have lines ending
+ in Carriage Return and Linefeed (CRLF). Thus any text files that were
+ in the archive formed by the first tar command will be unpacked by the
+ second tar command in their original form, and will display and print
+ incorrectly in Windows (except in applications that have been
+ explicitly coded to handle UNIX-format text files). On the other hand
+ if you told gzip to use "text mode" to do record format conversion
+ (assuming there was a way to tell it, as there is with most "zip"
+ programs), this would destroy any binary files in the archive.
+
+ Furthermore, if the archive contains text files that are written in
+ languages other than English, the "special" (accented and/or non-Roman)
+ characters are NOT translated, and are therefore likely show up as
+ gibberish on the target system. For example, West European languages
+ are usually encoded in ISO Latin Alphabet 1 in UNIX, but in PC code
+ page 850 on the PC. Capital A with acute accent is code point 193
+ (decimal) Latin-1, but 181 in CP850. So A-acute in the UNIX file
+ becomes Middle Box Bottom on the PC, and similarly for all the other
+ special characters, and for all other languages -- Greek, Russian,
+ Hebrew, Japanese, etc.
+
+ So when transferring text files between unlike platforms, you should
+ use direct Kermit file transfers so Kermit can apply the needed
+ record-format and character-set transformations. Use pipelines
+ containing archivers like tar or zip only if all the files are binary
+ or the two systems use the same record format and character set for
+ text files.
+
+ Also see [456]Sections 4.3, [457]4.10, [458]4.11, and [459]4.15 for how
+ to transfer directory trees between both like and unlike systems
+ directly with Kermit.
+
+4.2.7. Pipes and Encryption
+
+ Of course pipelines could be used for encrypted file transfers,
+ assuming proper precautions could be taken concerning the transmission
+ of the key. But there is rarely a good way to do this. To illustrate
+ using UNIX crypt:
+
+ csend {crypt key < filename} {!crypt key > filename}
+
+ Or, more ambitiously:
+
+ csend {tar cf - . | gzip -c | crypt key} {!crypt key | gunzip -c | tar xf -}
+
+ transmits the key in the file header packet as part of the (clear-text)
+ remote command, defeating the entire purpose of encrypting the file
+ data.
+
+ But if you are connected in terminal mode to the remote computer and
+ type:
+
+ creceive {crypt key > filename}
+
+ at the remote Kermit prompt, you have also transmitted the key in clear
+ text over the communications link.
+
+ At present, the only secure way to use CSEND and CRECEIVE with an
+ encryption filter is to have a human operator at both ends, so the key
+ does not have to be transmitted.
+
+ Theoretically it would be possible to use PGP software (Pretty Good
+ Privacy, by Phil Zimmerman, Phil's Pretty Good Software) to avoid key
+ transmission (since PGP uses separate public and private key and "lets
+ you communicate securely with people you've never met, with no secure
+ channels needed for prior exchange of keys"), but the specific method
+ has yet to be worked out.
+
+ HINT: See the PGP User's Guide, e.g. at:
+ [460]http://www.telstra.com.au/docs/PGP/
+ Especially the topic "Using PGP as a UNIX-Style Filter":
+ [461]http://www.telstra.com.au/docs/PGP/pgpdoc2/pgpdoc2_17.html
+
+ In any case, better and more convenient security options are now
+ available: Kerberos authentication and encryption ([462]CLICK HERE for
+ details) and the new ability to run C-Kermit "though" other
+ communication programs, described in [463]Section 2.7.
+
+4.2.8. Commands and Functions Related to Pipes
+
+4.2.8.1. The OPEN !READ and OPEN !WRITE Commands
+
+ These are described in [464]Using C-Kermit, and are generally useful
+ with reading output from commands that produce more than one line on
+ their standard output, or writing multiple lines into commands that
+ accept them on their standard input.
+
+ In C-Kermit 7.0 CLOSE !READ is accepted as a synonym for CLOSE READ,
+ and CLOSE !WRITE for CLOSE WRITE.
+
+ Testing the success and failure of these commands, however, can be a
+ bit tricky. Consider:
+
+ open !read lalaskjfsldkfjsldkfj
+
+ (where "lalaskjfsldkfjsldkfj" is neither a valid command nor the name
+ of a program or script that can be run). OPEN !READ, in UNIX at least,
+ translates this into execl(shellpath,shellname,"-c",command). This
+ means it starts your preferred shell (e.g. from the SHELL environment
+ variable) and asks it to execute the given command. It must be this
+ way, because your command can be a either an internal shell command
+ (which only your shell can execute) or an external command, which only
+ your shell knows how to find (it knows your PATH and interprets, etc).
+ Therefore unless OPEN !READ can't start your shell, it always succeeds.
+
+ Continuing with the nonexistent-command example:
+
+ C-Kermit> open !read lalaskjfsldkfjsldkfj
+ C-Kermit> status
+ SUCCESS
+ C-Kermit> read line
+ C-Kermit> status
+ SUCCESS
+ C-Kermit> echo "\m(line)"
+ "bash: lalaskjfsldkfjsldkfj: command not found"
+ C-Kermit> close read
+ C-Kermit> status
+ FAILURE
+ C-Kermit>
+
+ In other words, the failure can not be detected on OPEN, since the OPEN
+ command succeeds if it can start your shell. It can't be detected on
+ READ, since all this does is read output from the shell, which in this
+ case happens to be an error message. However, failure IS detected upon
+ close, since this is the occasion upon which the shell gives Kermit its
+ exit status code.
+
+ For an illustration of this situation, see [465]Section 2.14.
+
+4.2.8.2. The REDIRECT Command
+
+ A second method of I/O redirection is offered by the REDIRECT command.
+ This is a rather advanced and tricky feature that is presently
+ supported only in UNIX C-Kermit, in OS-9 C-Kermit, and in Kermit 95.
+ Syntax:
+
+ REDIRECT command
+ Runs the given command, sending its standard output to the
+ current communications channel (SET LINE, SET PORT, or SET HOST
+ connection), and reading its standard input from the same
+ connection. Works only in local mode -- i.e. a connection is
+ required -- and then only if the given command uses Standard
+ I/O.
+
+ Example:
+
+ redirect finger
+
+ runs the local "finger" command and sends its output over the
+ connection as plain text, where presumably there is a process set up to
+ read it. Another example:
+
+ redirect finger | sort -r
+
+ shows the use of a pipeline.
+
+ Note: REDIRECT differs from CSEND/CRECEIVE in two important ways: (1)
+ it does not use the Kermit protocol, and (2) it uses a bidirectional
+ pipe rather than a one-way pipe.
+
+ The primary use of the REDIRECT command is to run external protocols,
+ such as sz/rz in UNIX for ZMODEM, when they work over Standard I/O(*).
+ Example:
+
+ set host xyzcorp.com
+ (login, etc)
+ redirect sz oofa.zip
+
+ lets you make a Telnet connection with C-Kermit and then do a ZMODEM
+ transfer over it. ZMODEM protocol messages go both ways over the same
+ connection simultaneously.
+
+ It is possible to use C-Kermit on UNIX as your PPP dialer and then to
+ REDIRECT the connection to the PPP software, but C-Kermit 7.0 offers a
+ better approach to PPP dialing in its new EXEC command ([466]Section
+ 1.23).
+
+ In theory, you can also redirect an interactive process. For example,
+ suppose you tell Kermit 95 to wait for an incoming TCP/IP connection:
+
+ set host * 3000
+
+ and then tell C-Kermit on UNIX to:
+
+ set host kermit95hostname 3000
+ redirect ksh
+
+ and then tell Kermit 95 to CONNECT: now you are talking to the UNIX
+ K-shell; you can give commands (pwd, ls, etc) and see the results. In
+ practice, the K-shell's terminal modes are messed up because (a) it is
+ not going through the Unix terminal driver, and (b) it is "smart" and
+ knows it is being redirected, and so acts in a decidedly inhospitable
+ manner (other applications like EMACS, vi, etc, simply refuse to run if
+ their standard i/o has been redirected).
+
+ (*) The publicly-distributed sz/rz programs do not work as clients.
+ However, Omen Technology does offer an up-to-date redirectable
+ client XYZMODEM program called crzsz.
+
+4.2.8.3. Receiving Mail and Print Jobs
+
+ As of 7.0, and in UNIX only, files that are sent to C-Kermit as mail
+ (when the other Kermit uses a MAIL or SEND /MAIL command) or to be
+ printed (via REMOTE PRINT or SEND /PRINT) are now piped directly to the
+ mail or print program, rather than written to temporary files and then
+ mailed or printed and then deleted. This has the advantages of (a) not
+ requiring a temporary file, and (b) allowing mail to have a proper
+ subject in place of the filename. Temporary files were bad not only
+ because they required (a) space, and (b) writability of the current
+ directory, but also because using them could result in wiping out an
+ existing file. See [467]Section 4.7 for more about SEND /MAIL and SEND
+ /PRINT.
+
+4.2.8.4. Pipe-Related Functions
+
+ The \fcommand(command) function runs the given shell or system command
+ and returns the command's standard output as its value (with any
+ newline characters stripped from the end), unless the result is too
+ long, in which case it returns the empty string. The maximum length for
+ the result is at least 1022 bytes, and it might be longer on some
+ platforms. Examples (UNIX):
+
+ C-Kermit> echo "\fcommand(date)"
+ "Fri Apr 18 13:31:42 1997"
+ C-Kermit> echo "\fcommand(finger | wc -l)" ; how many users logged in?
+ " 83"
+ C-Kermit> evaluate \fcommand(finger | wc -l) * 2
+ 166
+ C-Kermit> echo Welcome to \fcommand(tty) on \fcommand(date)
+ Welcome to /dev/ttyre on Fri Apr 18 13:31:42 1997
+ C-Kermit> echo "\fcommand(ls oofa.*)"
+ "oofa.c
+ oofa.h
+ oofa.o"
+ C-Kermit> cd /directory-with-thousands-of-files
+ C-Kermit> echo "\fcommand(ls -l)" ; This would be too long
+ ""
+ C-Kermit>
+
+ If a command's output would be too long, you can use the other, more
+ laborious method of reading from a command: OPEN !READ command, READ
+ each line, CLOSE !READ.
+
+ The \frawcommand(command) function is identical to \fcommand(command),
+ except it does not remove trailing newline characters:
+
+ C-Kermit> echo "\frawcommand(date)"
+ "Fri Apr 18 13:31:42 1997
+ "
+ C-Kermit> echo "\frawcommand(ls oofa.*)"
+ "oofa.c
+ oofa.h
+ oofa.o
+ "
+ C-Kermit>
+
+ Use \frawcommand() if you want to retain the final line terminators, or
+ if the command's output is "binary". But remember that if the result of
+ this (or any other) function contains any NUL (ASCII code 0)
+ characters, the first NUL will terminate the result string because this
+ is how C strings work (it's "C-Kermit", remember?).
+
+ These functions are useful not only locally, but also in the
+ client/server arena. If you need to get the results from a system
+ command on the server end into a variable on the client end, just do:
+
+ [ remote ] query kermit command(date)
+
+ The result is in the local \v(query) variable; see [468]Using C-Kermit,
+ 2nd Ed., pp.359-360 for details.
+
+4.3. Automatic Per-File Text/Binary Mode Switching
+
+ When transferring files between like systems (e.g. UNIX-to-UNIX),
+ binary mode can be used for all files unless character-set translation
+ is needed, and in fact Kermit programs of recent vintage recognize each
+ others' platforms and switch to binary mode automatically when it is
+ appropriate (e.g. DOS to OS/2, or UNIX to UNIX). (Exception: LABELED
+ mode is chosen for VMS-to-VMS and OS/2-to-OS/2 transfers so complex
+ file formats can be preserved.)
+
+ On a client/server connection between like systems, the transfer mode
+ is currently determined by the file sender, rather than always by the
+ client. If the client is sending, it controls the transfer mode. If a
+ GET command is sent to the server, the server sends all files in binary
+ mode if its TRANSFER CHARACTER-SET is TRANSPARENT; otherwise it uses
+ text mode for text files (according to its text-pattern list) and
+ binary mode for binary files. Of course, the client can control the
+ server's transfer character-set with the REMOTE SET TRANSFER
+ CHARACTER-SET command.
+
+ When transferring files between unlike systems, however, (e.g.
+ UNIX-to-DOS), some files (such as executable program images) must be
+ transferred in binary mode but others (such as plain-text files) must
+ be transferred in text mode so their record format and character sets
+ can be appropriately converted. If a binary file is transferred in text
+ mode, it is ruined. If a text file is transferred in binary mode, then
+ at the very least, its format can be incorrect; at worst it is also
+ corrupted because its character set was not converted (in extreme cases
+ the corruption is total, e.g. because one system is ASCII-based and the
+ other EBCDIC).
+
+4.3.1. Exceptions
+
+ VMS C-Kermit, when sending files to a non-VMS system, switches to text
+ or binary mode automatically for each file, based on the record format
+ in the file's directory entry; thus the mechanisms described in this
+ section do not apply to VMS C-Kermit, yet the effect is the same:
+ automatic text/binary mode switching when VMS C-Kermit is sending
+ files. See the VMS Appendix of [469]Using C-Kermit for details.
+
+ Kermit versions that support LABELED or IMAGE transfer mode are
+ likewise not affected by this feature when one of those modes is
+ selected (normally used only when transferring between like systems).
+
+ Kermit versions that support file-transfer pipes and filters are not
+ affected by this feature when pipes or filters are used, since the
+ output of a pipe or filter (such as gzip) is likely to require transfer
+ in a different mode than the original file.
+
+ Finally, SEND /TEXT or SEND /BINARY will force files to be sent in the
+ indicated mode, overriding all automatic transfer-mode-choosing
+ mechanisms.
+
+4.3.2. Overview
+
+ Suppose you give C-Kermit a command like:
+
+ SEND *.*
+
+ And suppose the pattern *.* matches a mixture of text files (such as
+ program source code) and binary files (such os object modules or
+ executable programs).
+
+ C-Kermit 6.0 and earlier (except on VMS) send all files in the same
+ mode: whatever you said in your most recent SET FILE TYPE command, or
+ else whatever mode was chosen automatically according to the rules on
+ page 236 of Using C-Kermit, 2nd Ed.
+
+ But when text and binary files are mixed in the same group, and the
+ files are being transferred to an unlike system (e.g. UNIX to IBM
+ Mainframe), this results in corruption of either all the text files or
+ all the binary files.
+
+ Stream-oriented file systems such as in UNIX and DOS do not record any
+ information about the file to tell us whether the file should be
+ transferred in binary or text mode, making it impossible to select the
+ transfer mode for each file in a group automatically with any
+ certainty.
+
+ However, we can use some fairly-well established file naming
+ conventions for this purpose. C-Kermit 7.0 lets you provide lists of
+ filename patterns that are used to separately determine the file type
+ for each individual file being transferred. A pattern is a string,
+ possibly containing the special characters "*" (asterisk, which matches
+ any string of zero of more characters) and/or "?" (question mark, which
+ matches any single character). For example "a*b" matches all files
+ whose names start with "a" and end with "b", such as "ab", "arb",
+ "ababababab", etc, but not "abba". And "a?b" matches any file whose
+ name starts with "a", ends with "b", and is exactly 3 characters long.
+
+ NOTE: When typing commands at the C-Kermit prompt, you must prefix
+ "?" with \ to override its normal function of giving help.
+
+ (Also see [470]Section 4.9 for additional pattern-matching notations
+ that might be available in your version of C-Kermit.)
+
+ When you have specified filename recognition patterns, C-Kermit can
+ transfer the ones whose names match any of the binary-mode patterns in
+ binary mode, and those with names that match any of the text-mode
+ patterns in text mode, and those whose names match neither in the
+ prevailing mode you have chosen, or that was chosen automatically via
+ peer recognition.
+
+4.3.3. Commands
+
+ SET FILE PATTERNS { ON, OFF, AUTO }
+ This tells Kermit whether to do per-file filename
+ pattern-matching to determine text or binary mode. The normal
+ and default setting is AUTO, which means to use pattern lists to
+ switch transfer mode only when it is certain that the other
+ Kermit program supports automatic notification of transfer mode
+ (via Attribute packets) on a per-file basis (this information is
+ obtained automatically during protocol startup negotiation). ON
+ means to always determine the transfer mode from the filename
+ and pattern list when sending files. Use OFF to disable this
+ feature (without resetting your pattern lists). Also note that
+ if you have selected LABELED file transfer (SET FILE TYPE
+ LABELED), this takes precedence over filename-matching patterns
+ and all files are sent in labeled mode.
+
+ SET TRANSFER MODE MANUAL
+ Disables the use of filename patterns, no matter what the FILE
+ PATTERNS setting.
+
+ REMOTE SET TRANSFER MODE MANUAL
+ Client command to disable automatic transfer mode, and therefore
+ also filename patterns, in the server. Synonym: REMOTE SET XFER
+ MODE MANUAL.
+
+ { GET, SEND, etc } { /BINARY, /TEXT }
+ Including a /BINARY or /TEXT (or, where supported, /IMAGE or
+ /LABELED) switch with a file-transfer command changes the
+ transfer mode to manual for that command only, and therefore
+ disables patterns that that command.
+
+ SET FILE BINARY-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+ A list of zero or more patterns, separated by spaces (not
+ commas). Letters in a pattern are case-sensitive if the
+ underlying filenames are case sensitive (as in UNIX), and
+ case-insensitive otherwise (as in Windows). If a file's name is
+ matched by any pattern in the list and SET FILE PATTERNS is ON,
+ the file is sent in binary mode. Examples:
+
+ SET FILE BINARY-PATTERNS *.gz *.Z *.tar *.zip *.o *.so *.a *.out ; UNIX
+ SET FILE BINARY-PATTERNS *.EXE *.ZIP *.OBJ *.COM ; DOS or OS/2 or Windows
+
+ If a pattern contains spaces, enclose it in braces.
+
+ SET FILE TEXT-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+ Like SET FILE BINARY-PATTERNS, but the patterns choose text
+ files rather than binary ones. Examples:
+
+ SET FILE TEXT-PATTERNS *.TXT *.KSC *.HTM* *.BAT ; DOS, Windows, OS/2
+
+ ADD BINARY-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+ Adds one or more patterns to the BINARY-PATTERN list.
+
+ ADD TEXT-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+ Adds one or more patterns to the TEXT-PATTERN list.
+
+ REMOVE BINARY-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+ Removes one or more patterns from the BINARY-PATTERN list. The
+ given patterns are matched with the ones in the BINARY-PATTERNS
+ list with case sensitivity if the underlying file system has
+ case-sensitive names (as do UNIX and OS-9), otherwise with case
+ independence.
+
+ REMOVE TEXT-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+ Removes one or more patterns from the TEXT-PATTERN list.
+
+ SHOW PATTERNS
+ Displays the current pattern selections.
+
+ Whenever you give a SET FILE BINARY-PATTERNS or SET FILE TEXT-PATTERNS
+ command, the previous list is replaced. If you give one of these
+ commands without a pattern list, the previous list is removed.
+
+ When patterns are active and files are being sent, text patterns (if
+ any) are applied first (but only if not RESENDing and not sending in
+ LABELED mode), then binary patterns, so if the same pattern appears in
+ both lists, binary mode is chosen.
+
+4.3.4. Examples
+
+ Here's an example that might be used when sending files from UNIX:
+
+ set file type binary
+ set file text-patterns *.c *.h *.w *.txt makefile
+ set file binary-patterns *.o
+ msend makefile wermit wart ck*.[cwho] ck*.txt
+
+ Note that "wermit" and "wart" do not match any patterns so they are
+ sent in the prevailing mode, which is binary. Also note the use of
+ "makefile" as a pattern that does not contain any wildcard characters
+ (there is no other convention to distinguish among "wermit" and "wart",
+ which are binary executables, and "makefile", which is a text file,
+ purely by their names).
+
+ Most C-Kermit implementations have a default pattern list built in,
+ which includes patterns that are almost certain to succeed in picking
+ the right transfer mode. Others are omitted due to ambiguity. For
+ example ".hlp", and ".ini" are generally binary types in Windows but
+ text types everywhere else.
+
+ NOTE: ".doc", used for decades to denote plain-text documentation
+ files, now more often than not denotes a Microsoft Word Document, so
+ ".doc" is now considered a binary type since it does less harm to
+ transfer a plain-text document in binary mode than it does to
+ transfer an MS Word file in text mode (except when IBM mainframes
+ are involved!)
+
+ ANOTHER NOTE: ".com" files are binary in DOS-like operating systems,
+ but they are text (DCL command procedures) in VMS. VMS C-Kermit
+ sends .COM files in text mode; K95 sends them in binary mode. If you
+ download a .COM file from VMS to DOS or Windows, and then upload it
+ to another VMS system, be sure to use SEND /TEXT to preserve its
+ textness.
+
+ You can see the default pattern list by starting C-Kermit without its
+ initialization file (e.g. "kermit -Y") and using the SHOW PATTERNS
+ command. If you will be depending on this feature, be sure to examine
+ the list carefully in conjunction with the applications that you use.
+
+ The default pattern list does not take "backup files" into account
+ because (a) people usually don't want to transfer them; and (b) it
+ would make the pattern lists more than twice as long. For example, we
+ would need to include both *.txt and *.txt.~[0-9]*~ for ".txt" files,
+ and similarly for all the others. Instead, you can use SEND /NOBACKUP
+ (or SET SEND BACKUP OFF) to skip over all backup files.
+
+ Put your most commonly-used safe pattern declarations in your C-Kermit
+ customization file (ckermod.ini, .mykermrc, k95custom.ini, etc).
+
+ As noted, SET FILE PATTERNS is ON by default. Sometimes, however, it is
+ desirable, or necessary, to force files to be sent in a particular
+ mode, and often this must be done from the command line (e.g. when
+ using Kermit as a download helper in a Web browser like Lynx). The -V
+ command-line options is equivalent to SET FILE PATTERNS OFF and SET
+ TRANSFER MODE MANUAL. Example:
+
+ kermit -Vis oofa.txt
+
+ forces oofa.txt to be sent in binary mode, even though ".txt" might
+ match a text pattern.
+
+4.4. File Permissions
+
+ "Permissions" refers to a code associated with a file that specifies
+ who is allowed to access it, and in what manner. For example, the
+ owner, the members of one or more groups, the system administrator, and
+ everybody else, might be allowed various combinations of Read, Write,
+ Append, Execute, or Listing access.
+
+ The permission code goes by different names on different platforms. In
+ UNIX, it might be called the filemode. In VMS, it is called the file
+ protection (or protection mask).
+
+ The comments in this section presently apply only to the UNIX and VMS
+ versions of C-Kermit, to which these features were added in version
+ 7.0; the DOS, Windows, and OS/2 file systems embody no notions of
+ protection, and so MS-DOS Kermit and Kermit 95 do not send file
+ permissions, and ignore them when received.
+
+ The permissions for a received file are determined by a combination of
+ the file transfer mode (VMS-to-VMS transfers only), whether a file of
+ the same name exists already, whether permissions of the file are
+ received in the file attribute packet, and the setting of ATTRIBUTES
+ PROTECTION.
+
+ The default for ATTRIBUTES PROTECTION is ON. If no attributes are
+ received, the effect is the same as if attributes PROTECTION were OFF.
+
+ For VMS-to-VMS transfers, the default LABELED mode simply copies the
+ protection code from source to destination.
+
+4.4.1. When ATTRIBUTES PROTECTION is OFF
+
+ If no file of the same name exists, system defaults determine the
+ permissions of the new file. Otherwise, the actions taken depend on the
+ current FILE COLLISION setting: BACKUP, OVERWRITE, RENAME, etc, as
+ documented in [471]Using C-Kermit. But now the new file (if it is
+ created at all) automatically inherits the permissions (mode bits) of
+ the existing file in a way that is appropriate for the platform.
+
+4.4.1.1. Unix
+
+ All mode bits are inherited except the directory bit, since the
+ incoming file can not possibly be a directory. (In any case, it is not
+ possible to receive a file that has the same name as an existing
+ directory unless FILE COLLISION is set to RENAME).
+
+4.4.1.2. VMS
+
+ Files with the same name as an existing file, transferred in modes
+ other than LABELED between VMS systems, inherit the protection of the
+ prior version.
+
+4.4.2 When ATTRIBUTES PROTECTION is ON
+
+ File permissions can be conveyed as part of the file transfer process,
+ in accordance with the Kermit protocol definition. If the file sender
+ puts system-dependent and/or system-independent versions of the file
+ protection (permissions) into the Attribute (A) packet, the file
+ receiver can set the new file's permissions from them. Otherwise, the
+ permissions are set the same as for ATTRIBUTES PROTECTION OFF.
+
+ When the incoming A packet contains system-dependent permissions, the
+ file receiver checks to see if the sender has the same system ID (e.g.
+ both the sending and receiving systems are UNIX, or both are VMS); if
+ so, it decodes and uses the system-dependent permissions; otherwise it
+ uses the generic ones (if any) and applies them to the owner field,
+ setting the other fields appropriately as described in the following
+ sections.
+
+ Setting the incoming file's protection from the A packet is controlled
+ by SET ATTRIBUTES PROTECTION (or PERMISSION), which is ON by default,
+ and its status is displayed by SHOW ATTRIBUTES.
+
+ The main benefit of this feature is to not have to "chmod +x" an
+ executable file after transfer from UNIX to UNIX. Its cross-platform
+ benefits are less evident, perhaps to retain the status of the Unix 'x'
+ bit on a VMS system, for subsequent transfer back to a Unix system.
+
+4.4.2.1. System-Specific Permissions
+
+ System-specific file permissions are used when the two Kermit programs
+ recognize each other as running on the same type of system. For
+ example, both are running under some form of UNIX (it doesn't matter
+ which UNIX variation -- HP-UX, Solaris, AIX, etc -- all use the same
+ scheme for file permissions); or both are running under VMS (even if
+ one is on an Alpha and the other on a VAX, and/or one is old and the
+ other is new).
+
+4.4.2.1.1. UNIX
+
+ UNIX supports three categories of users, File Owner, Group, and World,
+ and three types of file access permission: Read, Write, and Execute.
+ Thus, a UNIX file's permissions are expressed in 9 bits.
+
+ The system-dependent permission string for UNIX is a 3-digit octal
+ string, the low-order 9 bits of the st_mode member of the stat struct;
+ we deliberately chop off the "file format" bits because they are not
+ permissions, nor do we convey the setuid/setgid bits, lock bit, sticky
+ bit, etc.
+
+4.4.2.1.2. VMS
+
+ VMS supports four categories of users, System, File Owner, Group, and
+ World, and four types of file access permission: Read, Write, Execute,
+ and Delete. Thus, a VMS file's permissions are expressed in 16 bits.
+
+ The system-dependent protection string for VMS is a 4-digit hexadecimal
+ string, corresponding to the internal-format protection word of the
+ file (RWED for each of World,Group,Owner,System). A new file normally
+ gets all 16 protection bits from the original file of the same name.
+
+ Note: VMS-to-VMS transfers take place in LABELED mode when the two
+ C-Kermits recognize each other's platform as VMS (unless you have
+ disabled LABELED-mode transfers). In this case, all of a file's
+ attributes are preserved in the transfer and the protection mask (and
+ other information) is taken from the file's internal information, and
+ this takes precedence over any information in the Attribute packets.
+ You can defeat the automatic switching into LABELED mode (if you want
+ to) with SET TRANSFER MODE MANUAL.
+
+4.4.2.2. System-Independent Permissions
+
+ The system-independent ("generic") protection is used when the system
+ IDs of the two Kermit programs do not agree (e.g. one is UNIX, the
+ other is VMS). The generic protection attribute includes the following
+ permissions (not all are applicable to every file system): Read, Write,
+ Append, Execute, Delete, Search. The generic permissions are derived
+ from the owner permissions of the source file, thus, a Unix 'w'
+ permission becomes VMS Write,Delete.
+
+ The Owner field of the new file's permissions is set from the incoming
+ generic protection attribute.
+
+ In UNIX, the Group and World permissions are set according to your
+ umask, except that execute permission is NOT set in these fields if it
+ was not also set in the generic protection (and consequently, is set in
+ the Owner field).
+
+ In VMS, the System, Group, and World permissions are set according to
+ the process default file permission (as shown in VMS by SHOW
+ PROTECTION), except that no permissions are allowed in these fields
+ that are not included in the generic permissions.
+
+ Note that the VMS and UNIX interpretations of Execute permission are
+ not identical. In UNIX, a file (binary executable, shell script, etc)
+ may not be executed unless it has Execute permission, and normally
+ files that are not intended for execution do not have Execute
+ permission. In VMS, Read permission implicitly supplies Execute
+ capability. Generally files that have Read permission also have
+ explicit Execute permission, but files (binary executables, DCL command
+ procedures) that have Read permission and not Execute permission can
+ still be executed.
+
+4.5. File Management Commands
+
+4.5.1. The DIRECTORY Command
+
+ Prior to C-Kermit 7.0, the DIRECTORY command always ran an external
+ system command (such as "ls" on UNIX) or program to product the
+ directory listing. This had certain advantages, mostly that you could
+ include system-dependent options for customized listings, e.g. on UNIX:
+
+ dir -lt c* | more
+
+ or in VMS:
+
+ directory /size/date/protection/except=*.obj oofa.*;0
+
+ This approach, however, carries some disadvantages: C-Kermit can't
+ return SUCCESS or FAILURE status for (e.g.) "dir foo" according to
+ whether the file "foo" exists; and it runs an inferior process, which
+ might be a problem in some environments for resource and/or security
+ reasons, and won't work at all in a "nopush" environment (e.g. one in
+ which C-Kermit is configured to forbid access to exterior commands and
+ programs, e.g. in a VMS "captive account").
+
+ In C-Kermit 7.0 on VMS and UNIX, and in K95 1.1.19 and later, the
+ DIRECTORY command is internal to Kermit. It can be run in a "nopush"
+ environment and returns SUCCESS or FAILURE status appropriately. In
+ UNIX it prints all dates and times in a consistent way (unlike ls). In
+ VMS it prints precise file sizes, rather than "blocks". It offers
+ several formatting and other options, but it is not necessarily more
+ flexible than the corresponding external commands or programs (the UNIX
+ "ls" program, the VMS "directory" command). The syntax is:
+
+ DIRECTORY [ switch [ switch [ ... ] ] ] [ filespec ]
+
+ If no filespec is given, all files in the current directory are listed.
+
+ Optional switches include all the standard file-selection switches
+ presented in [472]Section 1.5.4, plus:
+
+ /ALL
+ Show both regular files and directories; this is the default.
+
+ /ARRAY:x
+ Instead of displaying a directory listing, put the files that
+ would have been shown (based on the filespec and other selection
+ switches) in the given array. The array need not (and should
+ not) be predeclared; if the array already exists, it is
+ destroyed and reused. The array name can be a single letter,
+ like "a", or any fuller form, such as "&a", "\&a", "\&a[]", etc.
+ If the /ARRAY switch is included, the following other switches
+ are ignored: /BRIEF, /VERBOSE, /HEADING, /PAGE, /ENGLISHDATE,
+ /ISODATE, /XFERMODE, /MESSAGE, /SORT, /REVERSE, /ASCENDING. In
+ other words, only file selection switches are meaningful with
+ /ARRAY: /FILES, /DIRECTORIES, /ALL, /DOTFILES, /NOBACKUP,
+ /RECURSIVE, /SMALLER, /LARGER, /AFTER, /BEFORE, /EXCEPT, etc.
+ The resulting array has the number of files (n) as its 0th
+ element, and the filenames in elements 1 through n Example:
+
+ dir /array:&a /files /nobackup /after:19990101 /larger:10000 [ab]*
+ show array &a
+
+ /FILES
+ Only show regular files.
+
+ /DIRECTORIES
+ Only show directories.
+
+ /BACKUP
+ In UNIX, OS-9, K-95, and other versions that support SET FILE
+ COLLISION BACKUP and create backup files by appending .~n~ to
+ the filename (where "n" is a number), /BACKUP means to include
+ these files in directory listings. This is the default.
+
+ /NOBACKUP
+ This is the opposite of /BACKUP: that is, do not include backup
+ files in the listing.
+
+ /BRIEF
+ List filenames only; use a compact format, as many filenames as
+ will fit across the screen (based on the longest name). A brief
+ listing is always sorted alphabetically.
+
+ /VERBOSE
+ List one file per line, and include date, size, and (in UNIX
+ only) permissions of each file. This is the opposite of /BRIEF,
+ and is the default.
+
+ /PAGE
+ Pause at the end of each screenful and give a "more?" prompt,
+ even if SET COMMAND MORE-PROMPTING is OFF.
+
+ /NOPAGE
+ Don't pause at the end of each screenful and give a "more?"
+ prompt, even if SET COMMAND MORE-PROMPTING is ON. If neither
+ /PAGE or /NOPAGE is given, paging is according to the prevailing
+ COMMAND MORE-PROMPTING setting (which can be displayed with SHOW
+ COMMAND).
+
+ /ENGLISHDATE
+ Show dates in dd-mmm-yyyy format; mmm is the first three letters
+ of the English month name.
+
+ /ISODATE
+ Show dates in yyyy-mm-dd format; mm is the month number, 1-12.
+ This is the opposite of /ENGLISHDATE, and is the default.
+
+ /HEADINGS
+ Print a heading before the listing and a summary at the end.
+
+ /NOHEADINGS
+ Don't print a heading before the listing or a summary at the
+ end. This is the opposite of /HEADINGS, and is the default.
+
+ /XFERMODE
+ Only in Kermit programs that support SET FILE PATTERNS. If this
+ switch is included, and the filename matches any FILE
+ BINARY-PATTERN ([473]Section 4.3), "(B)" is printed after the
+ filename; otherwise, if it matches a FILE TEXT-PATTERN, "(T)" is
+ printed.
+
+ /NOXFERMODE
+ Don't display transfer-mode indicators. This is the opposite of
+ /XFERMODE and is the default.
+
+ /RECURSIVE
+ Show files not only in the given directory, but also in its
+ subdirectories (if any), their subdirectories, etc.
+
+ /NORECURSIVE
+ Don't show files in subdirectories. This is the opposite of
+ /RECURSIVE, and is the default.
+
+ /MESSAGE:text
+ This lets you specify a short text string to be appended to the
+ end of each directory listing line (a space is supplied
+ automatically). If the text contains any spaces, enclose it in
+ braces, e.g. /MESSAGE:{two words}.
+
+ /NOMESSAGE
+ Don't append any message to the end of each directory listing
+ line (default).
+
+ /SORT:[{NAME,SIZE,DATE}]
+ Sort the listing by name, size, or date. If the /SORT switch is
+ given but the "sort-by" keyword is omitted, the listing is
+ sorted by name. /SORT:NAME /ASCENDING (alphabetic sort by name)
+ is the default.
+
+ /NOSORT
+ Don't sort the listing. Files are listed in whatever order they
+ are supplied by the operating system, e.g. inode order in UNIX.
+
+ /REVERSE
+ If the /SORT switch is given, reverse the order of the sort.
+ Synonym: /DESCENDING.
+
+ /ASCENDING
+ If the /SORT switch is given, sort the listing in normal order.
+ This is the opposite of /REVERSE and is the default.
+
+ Note that most of the DIRECTORY-specific switches come in pairs, in
+ which one member of a pair (e.g. /NOHEADINGS) is the opposite of the
+ other (e.g. /HEADINGS).
+
+ If you always want to use certain options, you can set them with the
+ SET OPTIONS DIRECTORY command ([474]Section 1.5.5). Use SHOW OPTIONS to
+ list the options currently in effect. To make the desired options apply
+ every time you run C-Kermit, put a SET OPTIONS DIRECTORY command in
+ your C-Kermit customization file, specifying the desired options.
+ Options set in this manner apply to every subsequent DIRECTORY command.
+ Of course, if you include switches in a DIRECTORY command, these
+ override any defaults, built-in or custom. Example:
+
+ DIRECTORY ; Use "factory defaults"
+ SET OPTIONS DIRECTORY /SORT:SIZE /REVERSE /HEADINGS ; Customize defaults
+ DIRECTORY ; Use customized defaults
+ DIR /SORT:NAME ; Override customized default SORT key
+ SET OPT DIR /RECURS ; Add /RECURSIVE to customized defaults
+ DIR /ASCEND ; Override customized default SORT order
+
+ Notes:
+
+ * Only a single sort key is supported; there is presently no way to
+ have multiple sort keys.
+ * If the /BRIEF switch is given, all other switches (except
+ /[NO]RECURSIVE, /[NO]DOTFILES, /DIRECTORIES, /FILES, and /ALL) are
+ ignored.
+ * /SORT:anything gives incorrect results if any files have lengths
+ greater than 10 digits (i.e. that are more than 9999999999 bytes
+ long, i.e. if they are 10GB or more in size) because the overlong
+ length field causes the date and name fields to be misaligned.
+ * /SORT:NAME is redundant in VMS since VMS returns filenames in
+ alphabetic order anyway.
+ * /SORT:NAME ignores alphabetic case on platforms where case does not
+ matter in filenames, but this works only for unaccented Roman
+ letters A-Z.
+ * /SORT:NAME is currently based on code values, and so works fine for
+ ASCII, but will probably produce unexpected results for files with
+ non-ASCII or 8-bit characters in their names. (Locale-based sorting
+ raises rather significant issues of portability, size, performance,
+ etc.)
+ * /SORT:DATE works right only for ISO-format dates, not English ones.
+ * /SORT:SIZE sorts the size field lexically. On some platforms (e.g.
+ Windows), the size of a directory file is listed as "<DIR>" rather
+ than as a number; in this case, the "<DIR>" files are gathered at
+ the end (or beginning, depending on the sort order) of the listing.
+ * /RECURSIVE is accepted but ignored in AOS/VS. Use the normal
+ system-specific filespec notation, e.g. "dir #.txt".
+ * /RECURSIVE has no affect when a full, absolute pathname is given;
+ e.g. "dir /recursive /tmp/foo" (where "foo" is a regular file) only
+ shows the "/tmp/foo" file. If you want to see all "foo" files in
+ the /tmp tree, do "cd /tmp" and then "dir /recursive foo".
+ * If a file size of -1 is shown, or date-time of 0000-00-00 00:00:00,
+ this means the file was located, but access to information about
+ the file was denied to C-Kermit.
+ * In VMS, if FOO.DIR;1 is a directory within your current directory,
+ "directory foo" and "directory [.foo]" list the files in the [.FOO]
+ subdirectory, but "directory foo.dir" lists the directory file
+ itself; similarly for "*.dir" versus "[.*]", etc.
+ * In UNIX, if "foo" is a directory within your current directory,
+ "directory foo" lists the files in the foo directory. If you want
+ to list the foo directory file itself, put an asterisk at the end:
+ "dir foo*".
+
+ Hint: How to find the biggest files in a directory tree:
+
+ cd xxx ; (root of tree)
+ directory /sort:size /recursive /reverse /dotfiles /page
+
+ Another hint: If you often use several different directory-listing
+ formats, define macro shortcuts for them:
+
+ DEFINE WD DIRECTORY /SORT:DATE /REVERSE \%* ; Reverse chronological order
+ DEFINE SD DIRECTORY /SORT:SIZE /REVERSE \%* ; Reverse order of size
+ DEFINE ND DIRECTORY /SORT:NAME /ASCEND \%* ; Alphabetical by name
+ DEFINE DL DIR /DIR /SORT:NAME /ASCEND \%* ; Alphabetical directory list
+
+ Put these definitions in your C-Kermit customization file. Note that
+ "\%*" ([475]Section 7.5) in these definitions lets you include other
+ switches in your macro invocations, e.g.:
+
+ wd /headings *.txt
+
+ Of course you can still access your external directory listing program
+ by using RUN or "!", e.g. in VMS:
+
+ run directory /size/date/protection/except=*.obj oofa.*;0
+
+ or:
+
+ !dir /size/date/prot/exc=*.obj oofa.*;0
+
+ In UNIX, use "!ls" or just "ls" (which is a special synonym for "!ls").
+
+4.5.2. The CD and BACK Commands
+
+ In C-Kermit 7.0, the CD command has a new friend, the BACK command.
+ BACK means "CD to my previous current directory". A second BACK brings
+ you back to where you were before the first one; thus successive BACK
+ commands switch back and forth between two directories.
+
+4.5.2.1. Parsing Improvements
+
+ The CD command, as well as other commands that parse a directory name,
+ were changed in 7.0 to provide all the expected functions: completion
+ on Tab or Esc, directory-name lists on ?, etc. Other affected commands
+ include SET SERVER GET-PATH, SET TEMP-DIRECTORY, SET FILE
+ DOWNLOAD-DIRECTORY, and SPACE. CD and REMOTE CD also now work with
+ logical names.
+
+ In VMS, the situation is a bit complicated since a directory name can
+ look like "DEV:", "[FOO.BAR]", "DEV:[FOO.BAR]", "[FOO]BAR.DIR;1", etc.
+ Completion and ?-help might not always work, but they do in many cases.
+ Examples:
+
+ cd ? Lists all subdirectories of the current directory
+ cd []? Ditto
+ cd k? Ditto, but only those starting with K
+ cd [foo]? Lists all subdirectories of the [FOO] directory
+ cd [-]? Lists all subdirectories of the superior directory
+ cd [--]? Lists all subdirectories of the directory 2 levels up
+ cd [...]? Lists all directories below the current one
+ cd [foo.? Does not work.
+
+ C-Kermit allows all of the following in VMS:
+
+ cd bar CD to subdirectory BAR of the current directory
+ cd .bar Ditto
+ cd [.bar] Ditto
+ cd bar.dir etc...
+ cd bar.dir;
+ cd bar.dir;1
+ cd [foo.bar]
+ cd <foo.bar>
+ cd bar.baz This can go more than 1 level deep...
+ cd dir: (where logical name DIR is defined as [FOO.BAR])
+
+ As well as the following:
+
+ cd .. Go up one level as in UNIX
+ cd . The current directory
+ cd My login directory
+
+ Note that "cd -" (go up one level) does not work as expected, because
+ "-" is Kermit's command continuation character. However, "cd [-]", and
+ "
+ cd {-}" have the desired effect (and so does "cd ..", which is easier
+ to type).
+
+4.5.2.2. The CDPATH
+
+ The CD command in the UNIX, Windows, OS/2, and VMS versions of
+ C-Kermit, as of version 6.1 / 1.1.12, searches the CDPATH for the given
+ directory, if it is not absolute and if a CDPATH environment variable
+ is defined. Example (in UNIX ksh or bash):
+
+ $ export CDPATH=$HOME:$HOME/kermit:/tmp
+
+ Now if you give a "cd xxx" command, no matter what your current
+ directory is, if the "xxx" directory is not a subdirectory of your
+ current directory, then the xxx subdirectory of your home directory is
+ used or if that does not exist, then the xxx subdirectory of the kermit
+ subdirectory of your home directory is used or if that does not exist,
+ then /tmp/xxx is used. This is how the ksh "cd" command works, and now
+ the C-Kermit CD command works the same way.
+
+ In VMS, you can define CDPATH to be a list of directories that contain
+ actual directory delimiters, and/or logical names representing
+ directories, using commas to separate them, e.g.:
+
+ $ define cdpath [HOME],[SOMEOTHERDIR],[HOME.MISC]
+ $ define cdpath SYS$LOGIN:,DISK1:[HOME],DISK2:[SCRATCH.IVAN]
+
+ Example:
+
+ $ define cdpath SYS$LOGIN:,[IVAN],[OLAF],[OLGA.MISC]
+ $ kermit
+ DISK1:[OLGA] C-Kermit> cd blah
+
+ tries the BLAH subdirectory of the user's login directory, then
+ [OLGA.BLAH], [IVAN.BLAH], [OLAF.BLAH], and [OLGA.MISC.BLAH], in that
+ order, using the first one it finds, failing if it finds none.
+
+ In C-Kermit 7.0, you may also set the CDPATH from the Kermit prompt:
+
+ SET CD PATH path
+ Allows the CD PATH to be set from within C-Kermit.
+
+ SHOW CD shows the CD path and all other information relevant to the CD
+ command.
+
+4.5.2.3. CD Messages
+
+ Whenever you change directory, you can have C-Kermit display a "Read
+ Me" file from the new directory automatically. The commands are:
+
+ SET CD MESSAGE { ON, OFF, FILE list }
+ ON enables this feature; OFF (the default) disables it. File
+ lets you specify the name of the "Read Me" file. A list of names
+ to look for can be given in the following format:
+
+ {{name1}{name2}{name3}{...}}
+
+ e.g.:
+
+ SET SERVER CD-MESSAGE FILE {{./.readme}{README.TXT}{READ.ME}}
+
+ The default list of CD-message files is system dependent.
+
+ SHOW CD shows your current directory, previous directory, CD path, and
+ CD message info.
+
+4.5.3. Creating and Removing Directories
+
+ The MKDIR command now allows you to create multiple directories at
+ once:
+
+ C-Kermit> mkdir a/b/c/d
+
+ creates the directory a in the current directory (if it doesn't exist
+ already), and then creates subdirectory b in the a directory (if it
+ didn't exist already), and so on.
+
+ If you use MKDIR to try to create a directory that already exists,
+ C-Kermit will print a warning ("?Directory already exists"), but the
+ MKDIR command will still succeed. If you want to avoid the warning
+ message, use IF DIRECTORY first to check if the directory already
+ exists.
+
+ The RMDIR command, however, will not remove more than one directory,
+ nor will it remove a directory that contains any files. (There is, as
+ yet, no RMDIR /RECURSIVE command, although one might be added later.)
+
+ In VMS, these commands (like CD) are more forgiving of your syntax than
+ is the DCL command shell; "mkdir oofa" is equivalent to "mkdir [.oofa]"
+ and so on. Also in VMS, you'll find that C-Kermit's RMDIR command is
+ easier than deleting a directory in DCL, since it automatically first
+ gives it owner delete permission if you are the owner.
+
+4.5.4. The DELETE and PURGE Commands
+
+ The DELETE command now offers a selection of switches, and has a new
+ companion, the PURGE command. First, DELETE:
+
+ DELETE [ switches... ] filespec
+ Deletes the file or files that match the filespec, which may
+ contain wildcards ([476]Section 4.9).
+
+ Optional switches include the standard file-selection switches
+ presented in [477]Section 1.5.4, plus:
+
+ /ASK
+ Before deleting each file, ask permission interactively. Answers
+ are Yes or OK (delete the file), No (don't delete it), or Quit
+ (stop executing the DELETE command).
+
+ /NOASK
+ Don't ask permission to delete each file.
+
+ /LIST
+ List each file and show whether it was deleted. Synonyms: /LOG,
+ /VERBOSE.
+
+ /NOLIST
+ Don't list files while deleting them. Synonyms: /NOLOG, /QUIET.
+
+ /HEADING
+ Print a heading and summary line.
+
+ /NOHEADING
+ Don't print a heading and summary line.
+
+ /PAGE
+ When listing, pause at the end of each screenful and give the
+ "More?" prompt. If you reply "n" (no), the DELETE command
+ terminates.
+
+ /SIMULATE
+ Do everything implied by the given switches and filespec, except
+ do not actually delete any files. This lets you preview which
+ files would be deleted; implies /LIST.
+
+ Now the PURGE command:
+
+ PURGE [ switches... ] [ filespec ]
+ (VMS only) Runs the DCL PURGE command. Switches and filespec, if
+ any, are passed directly to DCL without parsing or verification.
+ Deletes excess versions of the given (or all) files. The rest of
+ this section does not apply to VMS.
+
+ PURGE [ switches... ] [ filespec ]
+ (UNIX only) Deletes "backup files" that match the filespec,
+ which may contain wildcards ([478]Section 4.9). If no filespec
+ is given, all backup files in the current directory are selected
+ (subject to modification by any switches). Do not include backup
+ notation in the filespec.
+
+ Explanation:
+
+ To avoid destroying preexisting files when a new file arrives that has
+ the same name, C-Kermit backs up the old file by appending a "backup
+ number" to its name. In UNIX, the backup suffix consists of a period, a
+ tilde, a number, and another tilde. For example, if a file called
+ oofa.txt exists and a new oofa.txt file arrives, the original is
+ renamed to oofa.txt.~1~. If another oofa.txt file arrives, the existing
+ one is renamed to oofa.txt.~2~. And so on. This system is compatible
+ with the one used by EMACS. Thus over time, if you receive a lot of
+ files with C-Kermit or edit them with EMACS, backup files can build up.
+ The new PURGE command lets you clean out accumulated backup files:
+
+ Optional switches include the standard file-selection switches
+ presented in [479]Section 1.5.4, plus all the switches listed above for
+ the DELETE command, plus:
+
+ /KEEP:n
+ Retains the n most recent (highest-numbered) backup files for
+ each file. For example, if oofa.txt, oofa.txt.~1~, oofa.txt.~2~,
+ oofa.txt.~10~, oofa.txt.~12~, and oofa.txt.~100~ exist, "purge
+ /keep:2 oofa.txt" deletes oofa.txt.~1~, oofa.txt.~2~, and
+ oofa.txt.~10~, and keeps oofa.txt, oofa.txt.~12~, and
+ oofa.txt.~100~. If /KEEP is given without a number, one (the
+ highest numbered) backup file is kept.
+
+ CAUTION: The PURGE command should be used only when *.~*~ files truly
+ are backup files. This is the case for EMACS, and it is the DEFAULT for
+ C-Kermit. However, if C-Kermit's FILE COLLISION has been set to RENAME,
+ newly received files will look like backup files. In that case, don't
+ use the PURGE command or you'll be removing new files rather than old
+ ones. (Use SHOW FILE to find the FILE COLLISION setting.)
+
+ The PURGE command is presently available only in UNIX. The command
+ succeeds if it deleted any files, or if it deleted no files but there
+ were no errors. It fails if it deleted no files and there were errors
+ (i.e. deletion was attempted but failed). In VMS, backup file versions
+ are handled automatically by the OS, and a PURGE command can be used at
+ the VMS prompt to clean them up.
+
+ If you want certain switches to be supplied automatically with each
+ DELETE or PURGE command, you can set them with SET OPTIONS
+ ([480]Section 1.5.5) and you can display any such settings with SHOW
+ OPTIONS. Of course you can override them on a per-command basis by
+ including switches in your PURGE or DELETE command.
+
+ Also see SET FILE COLLISION, SHOW FILE, SEND /NOBACKUP, SET SEND
+ BACKUP, and DIRECTORY /[NO]BACKUP.
+
+4.6. Starting the Remote Kermit Server Automatically
+
+ As noted on pages 275-276 of [481]Using C-Kermit 2nd edition, you can
+ have Kermit send "kermit receive" commands automatically when it is in
+ local mode and you give a SEND or similar command, to start the remote
+ Kermit receiver in case it is not already started. The "kermit receive"
+ commands are specified by:
+
+ SET PROTOCOL KERMIT binary-receive-command text-receive-command
+
+ As of version 7.0, a Kermit protocol option has been added to send a
+ string to the host in advance of any Kermit packets when you give a
+ GET-class or REMOTE command. This will switch the remote C-Kermit into
+ the appropriate mode or, if the remote system is at a system command
+ (shell) prompt, execute the string on the remote system. The new syntax
+ of the SET PROTOCOL KERMIT command is:
+
+ SET PROTOCOL KERMIT [ s1 [ s2 [ s3 ] ] ]
+
+ where:
+
+ Default Meaning
+ s1 {kermit -ir} Remote "kermit receive in binary mode" command.
+ s2 {kermit -r} Remote "kermit receive in text mode" command.
+ s3 {kermit -x} Remote "start kermit server" command.
+
+ NOTE: If the remote Kermit is 6.0, the following are recommended for
+ fast startup and high-performance file transfer (see Appendix I in
+ [482]Using C-Kermit, second Edition, for command-line options):
+
+ s1 kermit -YQir (Kermit receive binary, skip init file, fast.)
+ s2 kermit -YQTr (Kermit receive text, skip init file, fast.)
+ s3 kermit -YQx (Kermit server, skip init file, fast.)
+
+ If the remote is C-Kermit 7.0 or later, change the -x option (enter
+ server mode) to -O (uppercase letter O), which means "enter server mode
+ for One transaction only); this way, it is not stuck in server after
+ the transfer. Also note that the Q is redundant in version 7.0, since
+ fast Kermit protocol settings are now the default.
+
+ Note that in case the C-Kermit executable is called "wermit" or
+ "ckermit" you can change "kermit" in the strings above to "wermit" or
+ "ckermit" and C-Kermit 7.0 or later will recognize these as synonyms
+ for "kermit", in case it is at its command prompt when one of these
+ strings is sent to it.
+
+4.7. File-Transfer Command Switches
+
+ Over the years, various new methods of transferring a file have
+ accumulated, until we had, in addition to the SEND command, also MOVE
+ (send and then delete), MAIL (send as email), REMOTE PRINT (send to be
+ printed), CSEND (send the output of a command), PSEND (send a part of a
+ file), BSEND (send in binary mode), RESEND (resume an interrupted
+ SEND), etc etc. Similarly: GET, REGET, CGET, RETRIEVE, and so on.
+
+ Not only is it confusing to have different names for these commands,
+ many of which are not real words, but this also does not allow all
+ combinations, like "send a file as mail, then delete it".
+
+ In C-Kermit 7.0, the SEND, GET, and RECEIVE commands were restructured
+ to accept modifier switches (switches are explained in [483]Section
+ 1.5).
+
+4.7.1. SEND Command Switches
+
+ Without switches, the SEND command still works exactly as before:
+
+ send oofa.txt ; send a single file
+ send oofa.* ; send multiple files
+ send oofa.txt x.x ; send oofa.txt as x.x (tell receiver its name is x.x)
+ send ; send from SEND-LIST
+
+ But now the following modifier switches may be included between "send"
+ and the filename. Zero, one, two, or more switches may be included in
+ any combination that makes sense. Switch names (such as /BINARY) can be
+ abbreviated, just like any other keywords. Most of these switches work
+ only when using Kermit protocol (/TEXT and /BINARY are the exceptions).
+
+ /AFTER:date-time
+ Specifies that only those files modified (or, in VMS, created)
+ after the given date-time (see [484]Section 1.6) are to be sent.
+ Examples:
+
+ send /text /after:{2-Feb-1997 10:28:30} *.txt
+ send /text /after:\fdate(oofa.txt) *.txt
+
+ Synonym: /SINCE.
+
+ /ARRAY:arrayname
+ Specifies that instead of sending a file, C-Kermit is to send
+ the contents of the given array. Since an array does not have a
+ filename, you should include an /AS-NAME switch to specify the
+ name under which the array is to be sent (if you do not, the
+ name "_array_x_" is used, where 'x' is replaced by the array
+ designator). See [485]section 7.10 for array-name syntax. As
+ noted in that section, you can also include a range to have a
+ segment of the array sent, rather than the whole thing; for
+ example: "send /array:&a[100:199]". It is strongly recommended
+ that you accompany the /ARRAY switch with a /TEXT or /BINARY
+ switch to force the desired transfer mode, since otherwise the
+ various automatic mechanisms might switch to binary mode when
+ you really wanted text, or vice versa. In text mode a line
+ terminator is added to the end of each array element, but not in
+ binary mode. For details and examples see [486]Section 7.10.11.
+
+ /AS-NAME:text
+ Specifies "text" as the name to send the file under. You can
+ also still specify the as-name as the second filename on the
+ SEND command line. The following two commands are equivalent:
+
+ send oofa.txt oofa.new
+ send /as:oofa.new oofa.txt
+
+ /BEFORE:date-time
+ Specifies that only those files modified (or, in VMS, created)
+ before the given date-time ([487]Section 1.6) are to be sent.
+
+ /BINARY
+ Performs this transfer in binary mode without affecting the
+ global transfer mode, overriding not only the FILE TYPE and
+ TRANSFER MODE settings, but also the FILE PATTERN setting, but
+ for this SEND command only. In other words, SEND /BINARY means
+ what it says: send the file in binary mode, regardless of any
+ other settings. Example:
+
+ set file type text ; Set global transfer mode to text
+ send /binary oofa.zip ; Send a file in binary
+ send oofa.txt ; This one is sent in text mode
+
+ /COMMAND
+ SEND /COMMAND is equivalent to CSEND ([488]Section 4.2.2) -- it
+ says to send the output from a command, rather than the contents
+ of a file. The first "filename" on the SEND command line is
+ interpreted as the name of a command; the second (if any) is the
+ as-name. Examples:
+
+ send /command {grep Sunday oofa.txt} sunday.txt
+ send /as-name:sunday.txt /command {grep Sunday oofa.txt}
+ send /bin /command {tar cf - . | gzip -c} {!gunzip -c | tar xf -}
+
+ /DELETE
+ Deletes the file (or each file in the group) after it has been
+ sent successfully (but does not delete it if it was not sent
+ successfully). SEND /DELETE is equivalent to MOVE. Has no effect
+ when used with /COMMAND. Example:
+
+ send /delete *.log
+
+ /DOTFILES
+ (UNIX and OS-9 only) Normally files whose names begin with "."
+ are skipped when matching wildcards that do not also begin with
+ ".". Include /DOTFILES to force these files to be included too.
+
+ /RECURSIVE
+ Descend the through the directory tree when locating files to
+ send. Automatically sets /PATHNAMES:RELATIVE. Explained in
+ [489]Section 4.11 .
+
+ /EXCEPT:pattern
+ See [490]Section 1.5.4.
+
+ /NOBACKUP
+ This means to skip backup files when sending, even if they match
+ the SEND file specification. This is equivalent to using SEND
+ /EXCEPT and including *.~[0-9]*~ in the exception list (or *.~*~
+ if Kermit was built without pattern-matching support; see
+ [491]Section 4.9.1). Including this switch is equivalent to
+ giving SET SEND BACKUP OFF ([492]Section 4.0.6) prior to SEND,
+ except its effect is local to the SEND command with which it was
+ given.
+
+ /NODOTFILES
+ The opposite of /DOTFILES (q.v.)
+
+ /FILENAMES:{CONVERTED,LITERAL}
+ Use this switch to override the current global SET FILE NAMES
+ setting for this transfer only.
+
+ /FILTER:command
+ This specifies a filter to pass the file through before sending
+ it. See the [493]section on file-transfer pipes and filters. The
+ /FILTER switch applies only to the file-transfer command it is
+ given with; it does not affect the global SEND FILTER setting,
+ if any.
+
+ /IMAGE
+ VMS: Sends in image mode. Non-VMS: same as /BINARY.
+
+ /LABELED
+ VMS and OS/2 only: Sends in labeled mode.
+
+ /LARGER-THAN:number
+ Specifies that only those files that are longer than the given
+ number of bytes are to be sent.
+
+ /LISTFILE:filename
+ Specifies that the files to be sent are listed in a file with
+ the given filename. The file contains one filename per line.
+ These filenames are not checked in any way; each filename is
+ taken and does not use or depend on any Kermit-specific syntax.
+ In particular, backslashes are not treated specially, leading
+ and trailing spaces are not stripped, etc. However, if a
+ filename contains wildcards, they are expanded. Example: If a
+ file named files.txt contains the following lines:
+
+ blah.txt
+ oofa*
+ x.x
+
+ (but without leading or trailing spaces), then the C-Kermit
+ command "send /listfile:files.txt" will send the files blah.txt,
+ x.x, and all files whose names start with "oofa", assuming the
+ files exist and are readable. The /LISTFILE switch, can, of
+ course, be used with other switches when it makes sense, for
+ example, /EXCEPT, /BINARY, /AFTER, /SMALLER, /MOVE-TO, /DELETE,
+ /AS-NAME with a template, etc.
+
+ /MAIL:address
+ Sends the file as e-mail to the given address or addresses.
+ "send /mail:address filename" is equivalent to "mail filename
+ address". You can include multiple addresses separated by
+ commas. Examples:
+
+ send /mail:kermit-support@columbia.edu packet.log
+ send /mail:cmg,fdc,jrd oofa.txt
+
+ As with any switch argument, if the address or address list
+ contains any spaces, you must enclose it in braces. The format
+ of the addresses must agree with that understood by the
+ mail-sending program on the receiver's computer.
+
+ /MOVE-TO:directory-name
+ Specifies that after each (or the only) source file is sent
+ successfully, and ONLY if it is sent successfully, it should be
+ moved to the named directory. If the directory name contains
+ spaces, enclose it in braces. If the directory does not exist,
+ it is created if possible; if it can't be created, the command
+ fails and an error message is printed. Example:
+
+ send /text /move-to:/users/olga/backup/ *.txt
+
+ /NOT-AFTER:date-time
+ Specifies that only those files modified at or before the given
+ date and time are to be sent.
+
+ /NOT-BEFORE:date-time
+ Specifies that only those files modified at or after the given
+ date and time are to be sent.
+
+ /PATHNAMES:{OFF,ABSOLUTE,RELATIVE}
+ Use this switch to override the current global SET SEND
+ PATHNAMES setting for this transfer only. /PATHNAMES:ABSOLUTE or
+ RELATIVE also sets /FILENAMES:LITERAL (also for this transfer
+ only) since pathnames are not sent otherwise.
+
+ /RENAME-TO:text
+ Specifies that after the (or each) source file is sent
+ successfully, and ONLY if it is sent successfully, it should be
+ renamed to the name given. If the name contains spaces, enclose
+ it in braces. If a file group is being sent, then the "text"
+ must contain a variable reference such as \v(filename) (see
+ [494]Section 4.1). Example:
+
+ send /rename-to:ok_\v(filename) *.*
+
+ This sends each file in the current directory and if it was sent
+ successfully, changes its name to begin with "ok_".
+
+ /SMALLER-THAN:number
+ Specifies that only those files that are smaller than the given
+ number of bytes are to be sent.
+
+ /SUBJECT:text
+ Subject for email. Actually, this is just a synonym for
+ /AS-NAME. If the text includes spaces, you must enclose it in
+ braces. If you don't specify a subject (or as-name), the name of
+ the file is used as the subject. Example:
+
+ send /mail:kermit-support@columbia.edu /subj:{As requested} packet.log
+
+ /PRINT:options
+ Sends the file to be printed, optionally specifying options for
+ the printer. Equivalent to REMOTE PRINT filename options.
+ Examples:
+
+ send /print oofa.txt ; No options.
+ send /print:/copies=3 oofa.txt ; "/copies=3" is a VMS PRINT switch.
+ send /print:-#3 oofa.txt ; "-#3" is a UNIX lpr switch.
+
+ /PROTOCOL:name
+ Uses the given protocol to send the file (Kermit, Zmodem, etc)
+ for this transfer without changing global protocol. Only
+ available in Kermit 95, UNIX, and OS-9. Example:
+
+ set protocol kermit ; Set global protocol
+ send /proto:zmodem /bin oofa.zip ; Send just this file with Zmodem
+ send oofa.txt ; This file is sent with Kermit
+
+ /QUIET
+ When sending in local mode, this suppresses the file-transfer
+ display.
+
+ /RECOVER
+ Used to recover from a previously interrupted transfer; SEND
+ /RECOVER is equivalent to RESEND. Recovery only works in binary
+ mode; SEND /RECOVER and RESEND include an implied /BINARY
+ switch. Even then, recovery will successful only if (a) the
+ original (interrupted) transfer was also in binary mode, or (b)
+ if it was in text mode, the two Kermit programs run on platforms
+ where text-mode transfers are not length-changing.
+
+ /STARTING:number
+ Starts sending the file from the given byte position. SEND
+ /STARTING:n filename is equivalent to PSEND filename n.
+
+ /TEXT
+ Performs this transfer in text mode without affecting the global
+ transfer mode, overriding not only the FILE TYPE and TRANSFER
+ MODE settings, but also the FILE PATTERN setting, for this SEND
+ command only. In other words, SEND /TEXT really send the file in
+ text mode, regardless of any other settings or negotiations.
+
+ About mail... Refer to [495]Section 4.7.1. The same rules apply as for
+ file transfer. If you are mailing multiple files, you can't use an
+ as-name (in this case, a subject) unless it contains replacement
+ variables like \v(filenum). For example, if you:
+
+ send /mail:somebody@xyz.com *.txt
+
+ Then each file will arrive as a separate email message with its name as
+ the subject. But if you:
+
+ send /mail:somebody@xyz.com /subject:{Here is a file} *.txt
+
+ Then each file message will have the same subject, which is probably
+ not what you want. You can get around this with constructions like:
+
+ send /mail:somebody@xyz.com /subject:{Here is \v(filename)} *.txt
+
+ which embed the filename in the subject.
+
+ The MOVE, CSEND, MAIL, and RESEND commands now also accept the same
+ switches. And the switches are also operative when sending from a
+ SEND-LIST (see [496]Using C-Kermit, 2nd Ed, pp.191-192), so, for
+ example, it is now possible to SEND /PRINT or SEND /MAIL from a
+ SEND-LIST.
+
+ The MSEND and MMOVE commands also take switches, but not all of them.
+ With these commands, which take an arbitrary list of filespecs, you can
+ use /BINARY, /DELETE, /MAIL, /PRINT, /PROTOCOL, /QUIET, /RECOVER, and
+ /TEXT (and /IMAGE or /LABELED, depending on the platform). MMOVE is
+ equivalent to MSEND /DELETE. (If you want to send a group of files, but
+ in mixed transfer modes with per-file as-names, use ADD SEND-LIST and
+ then SEND.)
+
+ The MSEND/MMOVE switches come before the filenames, and apply to all of
+ them:
+
+ msend /print /text *.log oofa.txt /etc/motd
+
+ If you type any of these commands (SEND, CSEND, MSEND, etc) followed by
+ a question mark (?), you will see a list of the switches you can use.
+ If you want to see a list of filenames, you'll need to type something
+ like "send ./?" (UNIX, OS/2, Windows, etc), or "send []?" (VMS), etc.
+ Of course, you can also type pieces of a filename (anything that does
+ not start with "/") and then "?" to get a list of filenames that start
+ that way; e.g. "send x.?" still works as before.
+
+ In UNIX, where "/" is also the directory separator, there is usually no
+ ambiguity between a fully-specified pathname and a switch, except when
+ a file in the root directory has the same name as a switch (as noted in
+ [497]Section 1.5):
+
+ send /etc/motd ; Works as expected
+ send /command ; ???
+
+ The second example interprets "/command" as a switch, not a filename.
+ To send a file actually called "command" in the root directory, use:
+
+ send {/command}
+
+ or other system-dependent forms such as //command, /./command,
+ c:/command, etc, or cd to / and then "send command".
+
+4.7.2. GET Command Switches
+
+ Without switches, the GET command still works about the same as before:
+
+ get oofa.txt ; GET a single file
+ get oofa.* ; GET multiple files
+
+ However, the mechanism for including an "as-name" has changed.
+ Previously, in order to include an as-name, you were required to use
+ the "multiline" form of GET:
+
+ get
+ remote-filespec
+ local-name
+
+ This was because the remote filespec might contain spaces, and so there
+ would be no good way of telling where it ended and where the local name
+ began, e.g:
+
+ get profile exec a foo
+
+ But now since we can use {braces} for grouping, we don't need the
+ multiline GET form any more, and in fact, support for it has been
+ removed. If you give a GET command by itself on a line, it fails and an
+ error message is printed. The new form is:
+
+ GET [ switches... ] remote-name [ local-name ]
+ Ask the server to send the file whose name is remote-name. If
+ the optional local-name is given, store it locally under this
+ name. If the remote-name or local-name contains spaces, they
+ must be enclosed in braces:
+
+ get {profile exec a} foo
+ get oofa.txt {~/My Files/Oofa text}
+
+ If you want to give a list of remote file specifications, use the MGET
+ command:
+
+ MGET [ switches... ] remote-name [ remote-name [ remote-name ... ] ]
+ Ask the server to send the files whose names are given.
+
+ Now you can also include modifier switches between GET or MGET and the
+ remote-name; most of the same switches as SEND:
+
+ /AS-NAME:text
+ Specifies "text" as the name to store the incoming file under.
+ (This switch is not available for MGET.) You can also still
+ specify the as-name as the second filename on the GET command
+ line. The following two commands are equivalent:
+
+ get oofa.txt oofa.new
+ get /as:oofa.new oofa.txt
+
+ /BINARY
+ Tells the server to send the given file(s) in binary mode
+ without affecting the global transfer mode. Example:
+
+ set file type text ; Set global transfer mode to text
+ get /binary oofa.zip ; get a file in binary mode
+ get oofa.txt ; This one is transferred in text mode
+
+ Or, perhaps more to the point:
+
+ get /binary foo.txt ; where "*.txt" is a text-pattern
+
+ This has the expected effect only if the server is C-Kermit 7.0
+ or later or K95 1.1.19 or later.
+
+ /COMMAND
+ GET /COMMAND is equivalent to CGET ([498]Section 4.2.2) -- it
+ says to receive the file into the standard input of a command,
+ rather than saving it on disk. The /AS-NAME or the second
+ "filename" on the GET command line is interpreted as the name of
+ a command. Examples:
+
+ get /command sunday.txt {grep Sunday oofa.txt}
+ get /command /as-name:{grep Sunday oofa.txt} sunday.txt
+ get /bin /command {!gunzip -c | tar xf -} {tar cf - . | gzip -c}
+
+ /DELETE
+ Asks the Kermit server to delete the file (or each file in the
+ group) after it has been transferred successfully (but not to
+ delete it if it was not sent successfully). GET /DELETE is
+ equivalent to RETRIEVE. Example:
+
+ get /delete *.log
+
+ /EXCEPT:pattern
+ Specifies that any files whose names match the pattern, which
+ can be a regular filename, or may contain "*" and/or "?"
+ metacharacters, are to be refused upon arrival. To specify
+ multiple patterns (up to 8), use outer braces around the group,
+ and inner braces around each pattern:
+
+ /EXCEPT:{{pattern1}{pattern2}...}
+
+ See the description of SEND /EXCEPT in [499]Section 4.7.1 for
+ examples, etc. Refusal is accomplished using the Attribute
+ Rejection mechanism (reason "name"), which works only when
+ Attribute packets have been successfully negotiated.
+
+ /FILENAMES:{CONVERTED,LITERAL}
+ Use this switch to override the current global SET FILE NAMES
+ setting for this transfer only.
+
+ /FILTER:command
+ This specifies a filter to pass the incoming file through before
+ writing to disk. See the [500]section on file-transfer pipes and
+ filters. The /FILTER switch applies only to the file-transfer
+ command it is given with; it does not affect the global RECEIVE
+ FILTER setting, if any.
+
+ /IMAGE
+ VMS: Transfer in image mode. Non-VMS: same as /BINARY.
+
+ /LABELED
+ VMS and OS/2 only: Specifies labeled transfer mode.
+
+ /MOVE-TO:directory
+ This tells C-Kermit to move each file that is successfully
+ received to the given directory. Files that are not successfully
+ received are not moved. By default, files are not moved.
+
+ /PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}
+ Use this switch to override the current global SET RECEIVE
+ PATHNAMES setting for this transfer only. /PATHNAMES:ABSOLUTE or
+ RELATIVE also sets /FILENAMES:LITERAL (also for this transfer
+ only) since incoming pathnames would not be treated as pathnames
+ otherwise. See [501]Section 4.10.
+
+ /QUIET
+ When sending in local mode, this suppresses the file-transfer
+ display.
+
+ /RECOVER
+ Used to recover from a previously interrupted transfer; GET
+ /RECOVER is equivalent to REGET. Recovery only works in binary
+ mode; SEND /RECOVER and RESEND include an implied /BINARY
+ switch. Even then, recovery will successful only if (a) the
+ original (interrupted) transfer was also in binary mode, or (b)
+ if it was in text mode, the two Kermit programs run on platforms
+ where text-mode transfers are not length-changing.
+
+ /RECURSIVE
+ Tells the server that the GET file specification applies
+ recursively. This switch also automatically sets
+ /PATHNAMES:RELATIVE in both the server AND the client. When used
+ in conjunction with /DELETE, this "moves" a directory tree from
+ the server's computer to the client's computer (except that only
+ regular files are deleted from the server's computer, not
+ directories; thus the original directories will be left, but
+ will contain no files). Note that all servers that support
+ /RECURSIVE do not necessarily do so in combination with other
+ switches, such as /RECOVER. (Servers that do include C-Kermit
+ 7.0 and later, K95 1.1.19 and later.)
+
+ /RENAME-TO:string
+ This tells C-Kermit to rename each file that is successfully
+ received to the given string. Files that are not successfully
+ received are not renamed. By default, files are not renamed. The
+ string can be a literal string, which is appropriate when only
+ one file is being received, or it can contain one or more
+ variables that are to be evaluated at the time each file is
+ received, such as \v(filename), \v(filenumber), \v(ntime),
+ \v(pid), \v(user), etc. WARNING: if you give a literal string
+ and more than one file arrives, each incoming file will be given
+ the same name (but SET FILE COLLISION BACKUP or RENAME can be
+ used to keep the incoming files from overwriting each other).
+
+ /TEXT
+ Tells the server to perform this transfer in text mode without
+ affecting its global transfer mode. See /BINARY for additional
+ info.
+
+ The /MAIL and /PRINT options are not available (as they are for SEND),
+ but you can use /COMMAND to achieve the same effect, as in these UNIX
+ examples:
+
+ get /command oofa.txt {mail kermit@columbia.edu}
+ get /command oofa.txt lpr
+
+ In OS/2 or Windows, you can GET and print like this:
+
+ get oofa.txt prn
+
+ The CGET, REGET, RETRIEVE commands also accept the same switches as
+ GET. CGET automatically sets /COMMAND; REGET automatically sets
+ /RECOVER and /BINARY, and RETRIEVE automatically sets /DELETE.
+
+4.7.3. RECEIVE Command Switches
+
+ Without switches, the RECEIVE command still works as before:
+
+ receive ; Receives files under their own names
+ receive /tmp ; Ditto, but into the /tmp directory
+ r ; Same as "receive"
+ receive foo.txt ; Receives a file and renames to foo.txt
+
+ Now you can also include modifier switches may be included between
+ "receive" and the as-name; most of the same switches as GET:
+
+ /AS-NAME:text
+ Specifies "text" as the name to store the incoming file under.
+ You can also still specify the as-name as a filename on the
+ command line. The following two commands are equivalent:
+
+ r oofa.new
+ r /as:oofa.new
+
+ /BINARY
+ Performs this transfer in binary mode without affecting the
+ global transfer mode. NOTE: This does not override the incoming
+ filetype (as it does with GET), so this switch is useful only if
+ ATTRIBUTE TYPE is OFF, or if the other Kermit does not send a
+ TYPE (text or binary) attribute. In any case, it has no affect
+ whatsoever on the file sender.
+
+ /COMMAND
+ RECEIVE /COMMAND is equivalent to CRECEIVE ([502]Section 4.2.2)
+ -- it says to receive the file into the standard input of a
+ command, rather than saving it on disk. The /AS-NAME or the
+ "filename" on the RECEIVE command line is interpreted as the
+ name of a command.
+
+ r /command {grep Sunday oofa.txt}
+ r /command /as-name:{grep Sunday oofa.txt}
+ r /bin /command {tar cf - . | gzip -c}
+
+ /EXCEPT:pattern
+ Specifies that any files whose names match the pattern, which
+ can be a regular filename, or may contain "*" and/or "?"
+ metacharacters, are to be refused upon arrival. To specify
+ multiple patterns (up to 8), use outer braces around the group,
+ and inner braces around each pattern:
+
+ /EXCEPT:{{pattern1}{pattern2}...}
+
+ See the description of SEND /EXCEPT in [503]Section 4.7.1 for
+ examples, etc. Refusal is accomplished using the Attribute
+ Rejection mechanism (reason "name"), which works only when
+ Attribute packets have been successfully negotiated.
+
+ /FILENAMES:{CONVERTED,LITERAL}
+ Use this switch to override the current global SET FILE NAMES
+ setting for this transfer only.
+
+ /FILTER:command
+ This specifies a filter to pass the incoming file through before
+ writing to disk. See the [504]section on file-transfer pipes and
+ filters. The /FILTER switch applies only to the file-transfer
+ command it is given with; it does not affect the global RECEIVE
+ FILTER setting, if any.
+
+ /IMAGE
+ VMS: Transfer in image mode. Non-VMS: same as /BINARY. See
+ comments under RECEIVE /BINARY.
+
+ /LABELED
+ VMS and OS/2 only: Specifies labeled transfer mode. See comments
+ under RECEIVE /BINARY.
+
+ /MOVE-TO:directory
+ This tells C-Kermit to move each file that is successfully
+ received to the given directory. Files that are not successfully
+ received are not moved. By default, files are not moved.
+
+ /PATHNAMES:{ABSOLUTE,RELATIVE,OFF,AUTO}
+ Use this switch to override the current global SET RECEIVE
+ PATHNAMES setting for this transfer only. See [505]Section 4.10.
+
+ /RECURSIVE
+ When used with the RECEIVE command, /RECURSIVE is simply a
+ synonym for /PATHNAMES:RELATIVE.
+
+ /RENAME-TO:string
+ This tells C-Kermit to rename each file that is successfully
+ received to the given string. Files that are not successfully
+ received are not renamed. By default, files are not renamed. The
+ string can be a literal string, which is appropriate when only
+ one file is being received, or it can contain one or more
+ variables that are to be evaluated at the time each file is
+ received, such as \v(filename), \v(filenumber), \v(ntime),
+ \v(pid), \v(user), etc. WARNING: if you give a literal string
+ and more than one file arrives, each incoming file will be given
+ the same name (but SET FILE COLLISION BACKUP or RENAME can be
+ used to keep the incoming files from overwriting each other).
+
+ /QUIET
+ When receiving in local mode, this suppresses the file-transfer
+ display.
+
+ /TEXT
+ Receives in text mode without affecting the global transfer
+ mode. See comments under RECEIVE /BINARY.
+
+ The /MAIL and /PRINT options are not available, but you can use
+ /COMMAND to achieve the same effect, as in these UNIX examples:
+
+ r /command {mail kermit@columbia.edu}
+ r /command lpr
+
+ In OS/2 or Windows, you can RECEIVE and print like this:
+
+ receive prn
+
+ The CRECEIVE command now also accepts the same switches.
+
+4.8. Minor Kermit Protocol Improvements
+
+4.8.1. Multiple Attribute Packets
+
+ C-Kermit 7.0 now sends more than one Attribute packet if a file's
+ attributes do not fit into a single packet of the negotiated length. If
+ a particular attribute (such as file creation date-time) does not fit
+ within the negotiated length (which will only happen when the
+ negotiated length is around 20 or less), that attribute is not sent at
+ all.
+
+4.8.2. Very Short Packets
+
+ There are certain situations where extremely short packets must be
+ used; 20 or 30 bytes at most. This can happen when one or more devices
+ along the communication path have very small buffers and lack an
+ effective means of flow control. Examples are sometimes cited involving
+ radio modems.
+
+ When the maximum packet length is shorter than certain packets that
+ would be sent, those packets are either truncated or else broken up
+ into multiple packets. Specifically:
+
+ 1. Parameter negotiation packets (I, S, and their ACKs) are truncated
+ to the negotiated length. Any parameters that do not fit are reset
+ to their default values. There is no provision in the Kermit
+ protocol for fragmentation and reassembly of parameter strings.
+ 2. File header packets (containing the filename) are simply truncated.
+ There is no provision in the Kermit protocol for fragmentation and
+ reassembly of filenames.
+ 3. Attribute packets are fragmented and reassembled as described in
+ 4.8.1 without loss of data, except in case a field will not fit at
+ all in the negotiated length (the longest attribute is usually the
+ date and time of file creation/modification) because of the rule
+ that attributes may not be broken across packets.
+ 4. Data packets and other packets are unaffected -- they can be as
+ short as they need to be, within reason.
+
+4.9. Wildcard / File Group Expansion
+
+ "Wildcard" refers to the notation used in filenames to specify a group
+ of files by pattern matching.
+
+4.9.1. In UNIX C-Kermit
+
+ Prior to C-Kermit 7.0, C-Kermit was capable of expanding wildcard
+ strings containing only the "metacharacters" '*' and '?':
+
+ *
+ Matches any sequence of zero or more characters. For example:
+ "ck*.c" matches all files whose names start with "ck" and end
+ with ".c", including "ck.c".
+
+ ?
+ Matches any single character. For example, "ck?.c" matches all
+ files whose names are exactly 5 characters long and start with
+ "ck" and end with ".c". When typing commands at the prompt, you
+ must precede any question mark to be used for matching by a
+ backslash (\) to override the normal function of question mark,
+ which is providing menus and file lists.
+
+ C-Kermit 7.0 adds the additional features that users of ksh, csh, and
+ bash are accustomed to:
+
+ [abc]
+ Square brackets enclosing a list of characters matches any
+ single character in the list. Example: ckuusr.[ch] matches
+ ckuusr.c and ckuusr.h.
+
+ [a-z]
+ Square brackets enclosing a range of characters; the hyphen
+ separates the low and high elements of the range. For example,
+ [a-z] matches any character from a to z.
+
+ [acdm-z]
+ Lists and ranges may be combined. This example matches a, c, d,
+ or m through z.
+
+ {string1,string2,...}
+ Braces enclose a list of strings to be matched. For example:
+ ck{ufio,vcon,cmai}.c matches ckufio.c, ckvcon.c, or ckcmai.c.
+ The strings may themselves contain metacharacters, bracket
+ lists, or indeed, other lists of strings, but (when matching
+ filenames) they may not contain directory separators.
+
+ Thus, the metacharacters in filenames (and in any other field
+ that can be a pattern, such as the IF MATCH pattern, SEND or GET
+ exception lists, etc) are:
+
+ * ? [ {
+
+ And within braces only, comma (,) is a metacharacter.
+
+ To include a metacharacter in a pattern literally, precede it with a
+ backslash '\' (or two if you are passing the pattern to a macro).
+ Examples:
+
+ send a*b ; Send all files whose names start with 'a' and end with 'b'.
+ send a?b ; Ditto, but the name must be exactly three characters long.
+ send a[a-z]b ; Ditto, but the second character must be a lowercase letter.
+ send a[x\-z]b ; Ditto, except the second character must be 'x', '-', or 'y'.
+ send a[ghi]b ; Ditto, except the second character must be 'g', 'h', or 'i'.
+ send a[?*]b ; Ditto, except the second character must be '?' or '*'.
+ send a[\?\*]b ; Same as previous.
+ send *?[a-z]* ; All files with names containing at least one character
+ ; that is followed by a lowercase letter.
+
+ Or, more practically:
+
+ send ck[cuw]*.[cwh] ; Send the UNIX C-Kermit source files.
+
+ To refer to the C-Kermit sources files and makefile all in one
+ filespec:
+
+ {{makefile,ck[cuw]*.[cwh]}}
+
+ (NOTE: if the entire pattern is a {stringlist}, you must enclose it it
+ TWO pairs of braces, since the SEND command strips the outer brace
+ pair, because of the "enclose in braces if the filename contains
+ spaces" rule).
+
+ If the makefile is called ckuker.mak:
+
+ ck[cuw]*.{[cwh],mak}
+
+ (NOTE: double braces are not needed here since the pattern does not
+ both begin and end with a brace.)
+
+ To add in all the C-Kermit text files:
+
+ ck[cuw]*.{[cwh],mak,txt}
+
+ All of these features can be used anywhere you would type a filename
+ that is allowed to contain wildcards.
+
+ When you are typing at the command prompt, an extra level of quoting is
+ required for the '?' character to defeat its regular function of
+ producing a list of files that match what you have typed so far, for
+ example:
+
+ send ck[cu]?
+
+ lists all the files whose names start with ckc and cku. If you quote
+ the question mark, it is used as a pattern-matching character, for
+ example:
+
+ send ck\?[ft]io.c
+
+ sends all the file and communications i/o modules for all the
+ platforms: ckufio.c, ckutio.c, ckvfio.c, ckvtio.c, etc.
+
+ If, however, a filename actually contains a question mark and you need
+ to refer to it on the command line, you must use three (3) backslashes.
+ For example, if the file is actually called ck?fio.c, you would use:
+
+ send ck\\\?fio.c
+
+ Further notes on quoting:
+
+ * A single backslash is sufficient for quoting a special character at
+ the command prompt or in a command file. However, when passing
+ patterns to macros you'll need double backslashes, and when
+ referring to these patterns within the macro, you'll need to use
+ \fcontents(\%1) (see [506]Section 1.11.5). You should enclose macro
+ argument references in braces in case grouped arguments were
+ passed. Example:
+ define ismatch {
+ if match {\fcont(\%1)} {\fcont(\%2)} {
+ end 0 MATCH
+ } else {
+ end 1 NO MATCH
+ }
+ }
+ ismatch ab*yz a*\\**z ; Backslash must be doubled
+ ismatch {abc def xyz} *b*e*y* ; Braces must be used for grouping
+
+ * Watch out for possible conflicts between {} in filename patterns
+ and {} used for grouping multiple words into a single field, when
+ the pattern has outer braces. For example, in:
+ if match {abc xyz} {a* *z} echo THEY MATCH
+
+ braces must be used to group "abc xyz" into a single string. Kermit
+ strips off the braces before comparing the string with the pattern.
+ Therefore:
+ if match makefile {makefile,Makefile} echo THEY MATCH
+
+ does not work, but:
+ if match makefile {{makefile,Makefile}} echo THEY MATCH
+
+ does.
+ * If you use a pattern that has outer braces, like {*.txt,*.doc}, in
+ a field that accepts a pattern list (like SEND /EXCEPT:xxx), you'll
+ need to add two extra sets of outer braces:
+ send /except:{{{*.txt,*.doc}}} *.*
+
+ C-Kermit's new pattern matching capabilities are also used when
+ C-Kermit is in server mode, so now you can send requests such as:
+
+ get ck[cuw]*.[cwh]
+
+ to a C-Kermit server without having to tell it to SET WILD SHELL first.
+ Previously this would have required:
+
+ mget ckc*.c ckc*.w ckc*.h cku*.c cku*.w cku*.h ckw*.c ckw*.w ckw*.h
+
+ The new pattern matching features make SET WILD SHELL redundant, and
+ barring any objections, it will eventually be phased out. (One possible
+ reason for retaining it would be as an escape mechanism when Kermit
+ does not understand the underlying file system.)
+
+ By the way, patterns such as these are sometimes referred to as
+ "regular expressions", but they are not quite the same. In a true
+ regular expression (for example), "*" means "zero or more repetitions
+ of the previous item", so (for example), "([0-9]*)" would match zero or
+ more digits in parentheses. In Kermit (and in most shells), this
+ matches one digit followed by zero or more characters, within
+ parentheses. Here are some hints:
+
+ * Although you can't match any sequence of digits (or letters, etc),
+ you can match (say) 1, 2, or 3 of them in row. For example, the
+ following pattern matches Kermit backup files (with backup numbers
+ from 1 to 999):
+ *.~{[1-9],[1-9][0-9],[1-9][0-9][0-9]}~
+
+ * There is presently no NOT operator, so no way to match any
+ character or string EXCEPT the one(s) shown.
+
+ In other wildcarding news...
+
+ * You may now "send xxx" where "xxx" is a directory name, and this
+ will send all the files from the directory xxx, as if you had typed
+ "send xxx/*". You can also use the special shorthand "send ." to
+ send all the files from the current directory.
+ * To easily skip over backup files (the ones whose names end like
+ .~22~) when sending, you can use SEND /NOBACKUP (see [507]Section
+ 4.0.6 for details).
+ * When choosing Kermit to expand wildcards, rather than the shell,
+ you can choose whether "dot files" -- files whose names begin with
+ ".", which are normally "invisible" -- should be matched:
+ SET WILD KERMIT /NO-MATCH-DOT-FILES (this is the default)
+ SET WILD KERMIT /MATCH-DOT-FILES (this allows matching of "." files)
+
+ or include the /DOTFILES or /NODOTFILES switch on the command you
+ are using, such as SEND or DIRECTORY.
+ * Commands such as DIRECTORY and SEND allow recursive directory
+ traversal. There are also new functions for this to use in scripts.
+ See [508]Section 4.11 for details.
+
+ When building file lists in UNIX, C-Kermit follows symbolic links.
+ Because of this, you might encounter any or all of the following
+ phenomena:
+
+ * Multiple copies of the same file; e.g. one from its real directory
+ and others from links to its real directory, if both the real
+ directory and the links to it are in the wildcard expansion list.
+ * A command might unexpectedly "hang" for a long time because an NFS
+ link might not be responding, or the directory you are looking at
+ contains a link to a huge directory tree (example: "directory
+ /recursive /etc" when /etc/spool is a symlink to /var/spool, which
+ is a large organization's incoming email directory, containing tens
+ of thousands of subdirectories).
+
+ The size of the file list that Kermit can build is limited in most
+ C-Kermit implementations. The limit, if any, depends on the
+ implementation. Use the SHOW FEATURES command and look in the
+ alphabetized options list for MAXWLD to see the value.
+
+4.9.2. In Kermit 95
+
+ Kermit 95 1.1.19 and later uses the same pattern matching syntax as in
+ UNIX, but (as always) you will encounter numerous difficulties if you
+ use backslash (\) as the directory separator. In any command where K95
+ parses filenames itself (that is, practically any file-oriented command
+ except RUN), you can use forward slash (/) as the directory separator
+ to avoid all the nasty conflicts.
+
+4.9.3. In VMS, AOS/VS, OS-9, VOS, etc.
+
+ Platforms other than UNIX, Windows 95/98/NT, and OS/2 have their own
+ filename matching capabilities that are, in general, different from
+ Kermit's built-in ones and in any case might conflict with them. For
+ example, [] encloses directory names in VMS.
+
+ Nevertheless you can still use all the pattern-matching capabilities
+ described in [509]Section 4.9.1 by loading a file list into an array
+ (e.g. with \ffiles(*,&a), see [510]Section 4.11.3) and then using IF
+ MATCH on the members.
+
+4.10. Additional Pathname Controls
+
+ In version 6.0 and earlier, C-Kermit's SET { SEND, RECEIVE } PATHNAMES
+ command had only ON and OFF as options. In version 7.0, there are more
+ choices:
+
+ SET SEND PATHNAMES OFF
+ When sending a file, strip all disk/directory information from
+ the name. Example: "send /usr/olga/letters/oofa.txt" sends the
+ file as "oofa.txt". This applies to actual filenames, not to any
+ as-name you might specify.
+
+ SET SEND PATHNAMES RELATIVE
+ When sending a file, leave the pathname on as given. For
+ example, if your current directory is /usr/olga, "send
+ letters/oofa.txt" sends the file as "letters/oofa.txt", not
+ "/usr/olga/letters/oofa.txt" or "letters.txt".
+
+ SET SEND PATHNAMES ABSOLUTE
+ When sending a file, convert its name to the full, absolute
+ local pathname. For example, if your current directory is
+ /usr/olga, "send letters/oofa.txt" sends the file as
+ "/usr/olga/letters/oofa.txt". NOTE: Even with this setting,
+ device and/or node names are not included. For example, in VMS,
+ any node or device name is stripped; in Windows or OS/2, any
+ disk letter is stripped.
+
+ SET RECEIVE PATHNAMES OFF
+ When receiving a file, strip all disk/directory information from
+ the name before attempting to store it. This applies to incoming
+ filename, not to any as-name you might specify. Example: If a
+ file arrives under the name "/usr/olga/letters/oofa.txt" it is
+ stored simply as "oofa.txt" in your download directory or, if no
+ download directory has been specified, in your current
+ directory.
+
+ SET RECEIVE PATHNAMES RELATIVE
+ When receiving a file, leave the pathname on as it appears in
+ the incoming name, but if the incoming name appears to be
+ absolute, make it relative to your current or download
+ directory. Examples:
+
+ + "oofa.txt" is stored as "oofa.txt".
+ + "letters/oofa.txt" is stored as "letters/oofa.txt"; the
+ "letters" subdirectory is created if it does not already
+ exist.
+ + "/usr/olga/letters/oofa.txt" is stored as
+ "usr/olga/letters/oofa.txt" in your current or download
+ directory, and the "usr", "usr/olga", etc, directories are
+ created if they do not exist.
+
+ SET RECEIVE PATHNAMES ABSOLUTE
+ The incoming filename is used as given. Thus it cannot be stored
+ unless the given path (if any) already exists or can be created.
+ In this case, node, device, or disk designations are NOT
+ stripped, since they most likely were given explicitly by the
+ user as an as-name, meant to be used as given.
+
+ SET RECEIVE PATHNAMES AUTO
+ This is the default, and means RELATIVE if the sender tells me
+ it is a recursive transfer, OFF otherwise.
+
+ Set FILE NAMES CONVERTED now also affects pathnames too. When PATHNAMES
+ are RELATIVE or ABSOLUTE and FILE NAMES are CONVERTED, the file sender
+ converts its native directory-name format to UNIX format, and the file
+ receiver converts from UNIX format to its native one; thus UNIX format
+ is the common intermediate representation for directory hierarchies, as
+ it is in the ZIP/UNZIP programs (which is why ZIP archives are
+ transportable among, UNIX, DOS, and VMS).
+
+ Here's an example in which a file is sent from Windows to UNIX with
+ relative pathnames and FILE NAMES CONVERTED:
+
+ Source name Intermediate name Destination Name
+ C:\K95\TMP\OOFA.TXT K95/TMP/OOFA.TXT k95/tmp/oofa.txt
+
+ In a more complicated example, we send the same file from Windows to
+ VMS:
+
+ Source name Intermediate name Destination Name
+ C:\K95\TMP\OOFA.TXT K95/TMP/OOFA.TXT [.K95.TMP]OOFA.TXT
+
+ (Note that disk letters and device designations are always stripped
+ when pathnames are relative).
+
+ As you can imagine, as more and more directory formats are considered,
+ this approach keeps matters simple: on each platform, Kermit must know
+ only its own local format and the common intermediate one. In most
+ cases, the receiver can detect which format is used automatically.
+
+4.11. Recursive SEND and GET: Transferring Directory Trees
+
+ C-Kermit 7.0 in selected versions (UNIX, VMS, VOS, AOS/VS, Windows, and
+ OS/2 at this writing) now permits the SEND command to traverse
+ directories "recursively" if you ask it to; that is, to send files from
+ the current or specified directory and all of its subdirectories too,
+ and their subdirectories, etc. (Some other commands can do this too,
+ including DIRECTORY.)
+
+ This feature is new to UNIX, Windows, VOS, and OS/2. VMS and AOS/VS
+ have always included "wildcard" or "template" characters that allow
+ this, and in this case, recursive directory traversal could happen
+ behind Kermit's back, i.e. Kermit does not have to do it itself (in
+ VMS, the notation is "[...]" or "[directory...]"; in AOS/VS is "#"). In
+ C-Kermit 7.0, however, SEND /RECURSIVE is supported by C-Kermit itself
+ for VMS.
+
+4.11.1. Command-Line Options
+
+ To descend a directory tree when sending files, use the -L command-line
+ option to indicate that the send operation is to be recursive, and
+ include a name or pattern to be sent. When giving a pattern, you should
+ enclose it in quotes to prevent the shell from expanding it. Examples:
+
+ $ kermit -Ls "/usr/olga/*" # send all of Olga's files in all her directories
+ $ kermit -Ls foo.txt # send all foo.txt files in this directory tree
+ $ kermit -Ls "*.txt" # send all .txt files in this directory tree
+ $ kermit -Ls "letters/*" # send all files in the letters directory tree
+ $ kermit -Ls letters # send all files in the letters directory tree
+ $ kermit -Ls "*" # send all files in this directory tree
+ $ kermit -Ls . # UNIX only: send all files in this directory tree
+ $ kermit -s . # UNIX only: a filename of . implies -L
+
+ If you let the shell expand wildcards, Kermit only sends files whose
+ names match files in the current or given directory, because the shell
+ replaces an unquoted wildcard expression with the list of matching
+ files -- and the shell does not build recursive lists. Note that the
+ "." notation for the tree rooted at the current directory is allowed
+ only in UNIX, since in Windows and OS/2, it means "*.*" (nonrecursive).
+
+4.11.2. The SEND /RECURSIVE Command
+
+ If you include the /RECURSIVE switch in a SEND (or MOVE, or similar)
+ command, it means to descend the current or specified directory tree
+ searching for files whose names match the given name or pattern. Since
+ this is not terribly useful unless you also include pathnames with the
+ outbound files, the /RECURSIVE switch also includes an implicit
+ /PATHNAMES:RELATIVE switch (which you can undo by including an explicit
+ /PATHNAMES switch after the /RECURSIVE switch).
+
+ Examples:
+
+ SEND /RECURSIVE *
+ Sends all of the files in the current directory and all the
+ files in all of its subdirectories, and all of their
+ subdirectories, etc, including their relative pathnames. Empty
+ directories are not sent.
+
+ SEND /RECURSIVE /PATHNAMES:ABSOLUTE *
+ Sends all of the files in the current directory and all the
+ files in all of its subdirectories, and all of their
+ subdirectories, etc, including their absolute pathnames.
+
+ SEND /RECURSIVE /PATHNAMES:OFF *
+ Sends all of the files in the current directory and all the
+ files in all of its subdirectories, and all of their
+ subdirectories, etc, without pathnames.
+
+ SEND /RECURSIVE /usr/olga/*
+ Sends all of the files in the /usr/olga directory and all the
+ files in all of its subdirectories, and all of their
+ subdirectories, etc.
+
+ SEND /RECURSIVE /usr/olga (or /usr/olga/)
+ Same as above. If the name is a directory name (with or without
+ a trailing slash), its files are sent, and those of its
+ subdirectories, and their subdirectories, etc (see [511]Section
+ 4.9).
+
+ SEND /RECURSIVE /TEXT /usr/olga/*.txt
+ As above, but only files whose names end with ".txt" are sent,
+ and they are sent in text mode (as they would be by default
+ anyway if SET FILE PATTERNS is ON or AUTO).
+
+ SEND .
+ UNIX only: Send all the files in the current directory.
+
+ SEND /RECURSIVE .
+ UNIX only: Sends all of the files in the current directory and
+ all of its subdirectories, etc ([512]Section 4.9).
+
+ The /RECURSIVE switch is different from most other switches in that its
+ effect is immediate (but still local to the command in which it is
+ given), because it determines how filenames are to be parsed. For
+ example, "send *.txt" fails with a parse error ("No files match") if
+ there are no *.txt files in the current directory, but "send /recursive
+ *.txt" succeeds if there are ".txt" files anywhere in the tree rooted
+ at the current directory.
+
+ The /RECURSIVE switch also affects the file lists displayed if you type
+ "?" in a filename field. "send ./?" lists the regular files in the
+ current directory, but "send /recursive ./?" lists the entire directory
+ tree rooted at the current directory.
+
+4.11.3. The GET /RECURSIVE Command
+
+ In a client/server setting, the client can also request a recursive
+ transfer with:
+
+ GET /RECURSIVE [ other switches ] remote-filespec [ local-spec ]
+
+ In which remote file specification can be a directory name, a filename,
+ a wildcard, or any combination. If the local-spec is not given (and
+ PATHNAMES are RELATIVE), incoming files and directories go into the
+ current local directory. If local-spec is given and is a directory, it
+ becomes the root of the tree into which the incoming files and
+ directories are placed. If local-spec has the syntax of a directory
+ name (e.g. in UNIX it ends with /), C-Kermit creates the directory and
+ then places the incoming files into it. If local-spec is a filename
+ (not recommended), then all incoming files are stored with that name
+ with collisions handled according to the FILE COLLISION setting.
+
+ Again, the normal method for transferring directory trees uses relative
+ pathnames, and this is the default when the sender has been given the
+ /RECURSIVE switch. The action at the receiver depends on its RECEIVE
+ PATHNAMES setting. The default is AUTO, meaning that if the sender
+ tells it to expect a recursive transfer, then it should automatically
+ switch to relative pathnames for this transfer only; otherwise it obeys
+ the RECEIVE PATHNAMES setting of OFF, ABSOLUTE, or RELATIVE.
+
+ What happens if a file arrives that has an absolute pathname, when the
+ receiver has been told to use only relative pathnames? As a security
+ precaution, in this case the receiver treats the name as if it was
+ relative. For example, if a file arrives as:
+
+ /usr/olga/oofa.txt
+
+ The receiver creates a "usr" subdirectory in its current directory, and
+ then an "olga" subdirectory under the "usr" subdirectory in which to
+ store the incoming file.
+
+ Suppose, however there is a sequence of directories:
+
+ /usr/olga/a/b/c/d/
+
+ in which "a" contains nothing but a subdirectory "b", which in turn
+ contains nothing but a subdirectory "c", which in turn contains nothing
+ but a subdirectory "d", which contains nothing at all. Thus there are
+ no files in the "/usr/olga/a/" tree, and so it is not sent, and
+ therefore it is not reproduced on the target computer.
+
+4.11.4. New and Changed File Functions
+
+ C-Kermit 7.0 adds the following functions:
+
+ \ffiles(pattern[,&a])
+ This function has been changed to match only regular files in
+ the current or given directory, and to take an optional array
+ name as a second argument (explained below).
+
+ \fdirectories(pattern[,&a])
+ Returns the number of directories that match the given pattern.
+ If the pattern does not include a directory, then the search is
+ performed in the current directory.
+
+ \frfiles(pattern[,&a])
+ Returns the number of files in the current or given directory
+ and all of its subdirectories, and their subdirectories, etc,
+ that match the given pattern. Warning -- this one can take quite
+ some time if performed at the root of a large directory tree.
+
+ \frdirectories(pattern[,&a])
+ Returns the number of directories in the current or given
+ directory and all of its subdirectories, and their
+ subdirectories, etc, that match the given pattern.
+
+ Each of these functions builds up a list of files to be returned by the
+ \fnextfile() function, just as \ffiles() always has done. (This can
+ also be done with the /ARRAY switch of the DIRECTORY command; see
+ [513]Sections 4.5.1 and [514]7.10).
+
+ Each of these functions can be given an array name as an optional
+ second argument. If an array name is supplied, the array will contain
+ the number of files as its 0th element, and the filenames in elements 1
+ through last. If the array already existed, its previous contents are
+ lost. For example, if the current directory contains two files,
+ oofa.txt and foo.bar, then "\ffiles(*,&a)" creates an array \&a[] with
+ a dimension of 2, containing the following elements:
+
+ \&a[0] = 2
+ \&a[1] = oofa.txt
+ \&a[2] = foo.bar
+
+ If no files match the specification given in the first argument, the
+ array gets a dimension of 0, which is the same as undeclaring the
+ array.
+
+ Note that the order in which the array is filled (and in which
+ \fnextfile() returns filenames) is indeterminate (but see [515]Section
+ 7.10.5).
+
+ Here's an example that builds and prints a list of all the file whose
+ names end in .txt in the current directory and all its descendents:
+
+ asg \%n \frfiles(*.txt)
+ declare \&a[\%n]
+ for \%i 1 \%n 1 {
+ asg \&a[\%i] \fnextfile()
+ echo \flpad(\%i,4). "\&a[\%i]"
+ }
+
+ Alternatively, using the array method, and then printing the filenames
+ in alphabetic order (see [516]Section 7.10.3 and [517]7.10.5):
+
+ asg \%n \frfiles(*.txt,&a)
+ sort &a
+ for \%i 1 \%n 1 {
+ echo \flpad(\%i,4). "\&a[\%i]"
+ }
+
+ Or even more simply:
+
+ asg \%n \frfiles(*.txt,&a)
+ sort &a
+ show array &a
+
+ As noted elsewhere, the file lists built by \ffiles(), \frfiles(), etc,
+ are now "safe" in the sense that SEND and other file-related commands
+ can reference \fnextfile() without resetting the list:
+
+ set send pathnames relative
+ for \%i 1 \frfiles(*.txt) 1 {
+ asg \%a \fnextfile()
+ echo Sending \%a...
+ send \%a
+ if fail break
+ }
+
+ Copying to an array (as shown on p.398 of [518]Using C-Kermit 2nd Ed)
+ is no longer necessary.
+
+4.11.5. Moving Directory Trees Between Like Systems
+
+4.11.5.1. UNIX to UNIX
+
+ Transferring a directory tree from one computer to another replicates
+ the file sender's arrangement of files and directories on the file
+ receiver's computer. Normally this is done using relative pathnames,
+ since the user IDs might not be identical on the two computers. Let's
+ say both computers are UNIX based, running C-Kermit 7.0 or later. On
+ the sending computer (leaving out the connection details, etc):
+
+ C-Kermit> cd /usr/olga
+ C-Kermit> send /recursive .
+
+ The /RECURSIVE switch tells C-Kermit to descend through the directory
+ tree and to include relative pathnames on outbound filenames.
+
+ On the receiving computer:
+
+ C-Kermit> mkdir olgas-files ; Make a new directory.
+ C-Kermit> cd olgas-files ; CD to it.
+ C-Kermit> receive /recursive ; = /PATHNAMES:RELATIVE
+
+ Each Kermit program recognizes that the other is running under UNIX and
+ switches to binary mode and literal filenames automatically.
+ Directories are automatically created on the receiving system as
+ needed. File dates and permissions are automatically reproduced from
+ source to destination.
+
+4.11.5.2. VMS to VMS
+
+ To send recursively from VMS, simply include the /RECURSIVE switch, for
+ example at the sender:
+
+ $ kermit
+ C-Kermit> cd [olga]
+ C-Kermit> send /recursive *.*;0
+
+ And at the receiver:
+
+ C-Kermit> cd [.olga]
+ C-Kermit> receive /recursive
+
+ The notation "..." within directory brackets in VMS means "this
+ directory and all directories below it"; the /RECURSIVE switch, when
+ given to the sender, implies the use of "..." in the file specification
+ so you don't have to include "..."; but it makes no difference if you
+ do:
+
+ $ kermit
+ C-Kermit> send /recursive [olga...]*.*;0
+
+ And at the receiver:
+
+ C-Kermit> cd [.olga]
+ C-Kermit> receive /recursive
+
+ In either case, since both systems recognize each other as VMS, they
+ switch into LABELED transfer mode automatically.
+
+4.11.6. Moving Directory Trees Between Unlike Systems
+
+ There are several difficulties with recursive transfers between unlike
+ systems:
+
+ * File formats can be different, especially text files character sets
+ and record formats. This can now be handled by using SET FILE
+ PATTERN, SET FILE TEXT-PATTERNS, and SET FILE BINARY-PATTERNS
+ ([519]Section 4.3).
+ * File naming conventions are different. For example, one system
+ might allow (and use) longer filenames than the other. You can tell
+ Kermit how to handle file names with the normal "set file names"
+ and "set file collision" mechanisms. Most modern Kermits are fairly
+ tolerant of illegal filenames and should not fail simply because of
+ an incoming filename; rather, it will do its best to convert it to
+ a recognizable and unique legal filename.
+ * Directory notations can be different, e.g. backslashes instead of
+ slashes, brackets, parentheses, spaces, etc. But this is now
+ handled by converting pathnames to a standard format during
+ transfer ([520]Section 4.10).
+
+ So now, for the first time, it is possible to send directory trees
+ among any combination of UNIX, DOS, Windows, OS/2, VMS, AOS/VS, etc.
+ Here's an example sending files from an HP-UX system (where text files
+ are encoded in the HP Roman8 character set) to a PC with K95 (where
+ text files are encoded in CP850):
+
+ Sender:
+ cd xxx ; CD to root of source tree
+ set file type binary ; Default transfer mode
+ set file character-set hp-roman8 ; Local character set for text files
+ set xfer character-set latin1 ; Transfer character set
+ set file patterns on ; Enable automatic file-type switching...
+ set file binary-patterns *.Z *.gz *.o ; based on these patterns...
+ set file text-patterns *.txt *.c *.h ; for binary and text files.
+ send /recursive * ; Send all the file in this directory tree
+
+ Receiver:
+ cd yyy ; CD to root of destination tree
+ set file character-set cp850 ; Local character set for text files
+ receive /pathnames:relative ; Receive with pathnames
+
+ Notes:
+ * Replace "xxx" and "yyy" with the desired directories.
+ * Replace the file character sets appropriately.
+ * Change the patterns as needed (or just use the built-in default
+ lists).
+ * SEND /RECURSIVE also implies /PATHNAMES:RELATIVE.
+ * The file sender tells the file receiver the transfer mode of each
+ file.
+ * The file sender tells the file receiver the transfer character set.
+ * By default, destination file dates will be the same as on the
+ source.
+ * Many of the settings shown might already be set by default.
+ * See [521]Sections 4.3, [522]4.10, and [523]4.15 for additional
+ explanation.
+
+ If you are refreshing an existing directory on the destination
+ computer, use "set file collision update" or other appropriate file
+ collision option to handle filename collisions.
+
+4.12. Where Did My File Go?
+
+ Now that Kermit can be started by clicking on desktop icons (thus
+ obscuring the concept of "current directory"), and can have a download
+ directory, and can create directories for incoming files on the fly,
+ etc, sometimes it is easy to lose a file after transfer. Of course, if
+ you keep a transaction log:
+
+ LOG TRANSACTIONS
+
+ it will record the fate and final resting place of each file. But in
+ case you did not keep a log, the new command:
+
+ WHERE
+
+ added in C-Kermit 7.0, gives you as much information as it has about
+ the location of the last files transferred, including the pathname
+ reported by the receiving Kermit, if any, when C-Kermit is the sender.
+ This information was also added to SHOW FILE in somewhat less detail.
+
+4.13. File Output Buffer Control
+
+ (UNIX only). The new command SET FILE OUTPUT lets you control how
+ incoming files are written to disk:
+
+ SET FILE OUTPUT BUFFERED [ size ]
+ Chooses buffered file output; this is the default. UNIX does its
+ normal sort of disk buffering. The optional size specifies
+ Kermit's own file output buffer size, and therefore the
+ frequency of disk accesses (write() system calls) -- the bigger
+ the size, the fewer the disk accesses.
+
+ SET FILE OUTPUT UNBUFFERED [ size ]
+ This forces each file output write() call to actually commit the
+ data to disk immediately. Choosing this option will usually slow
+ file reception down.
+
+ SET FILE OUTPUT BLOCKING
+ Write() calls should not return until they are complete. This is
+ the normal setting, and it lets Kermit detect disk-write errors
+ immediately.
+
+ SET FILE OUTPUT NONBLOCKING
+ Write() calls should return immediately. This can speed up file
+ reception, but also delay the detection of disk-write errors.
+
+ Experimentation with these parameters should be harmless, and might (or
+ might not) have a perceptible, even dramatic, effect on performance.
+
+4.14. Improved Responsiveness
+
+ In version 7.0, C-Kermit's file-transfer protocol engine has been tuned
+ for additional speed and responsiveness.
+
+ * Binary-mode transfers over 8-bit connections, a very common case,
+ are now handled in a special way that minimizes overhead.
+ * SET TRANSFER CRC-CALCULATION is now OFF by default, rather than ON.
+ (This affects only the overall per-transfer CRC, \v(crc16), not the
+ per-packet CRCs)
+ * Connection loss during file transfer is now detected immediately in
+ most cases on Internet connections and on serial connections when
+ CARRIER-WATCH is not set to OFF.
+
+4.15. Doubling and Ignoring Characters for Transparency
+
+ The following commands were added in 7.0, primarily to allow successful
+ file transfer through ARPAnet TACs and with Honeywell DPS6 systems, but
+ can be used in any setting where they might be needed:
+
+ SET SEND DOUBLE-CHAR { [ char [ char [ ... ] ] ], NONE }
+ Tells C-Kermit to double the specified characters (use decimal
+ notation) in packets that it sends. For example, if you are
+ sending files through a device that uses @ as an escape
+ character, but allows you to send a single copy of @ through by
+ doubling it, use "set send double 64".
+
+ SET RECEIVE IGNORE-CHAR [ char [ char [ ... ] ] ]
+ Tells C-Kermit to ignore the specified character(s) in incoming
+ packets. Use this, for example, when something between the
+ sender and receiver is inserting linefeeds for wrapping, NULs
+ for padding, etc.
+
+4.16. New File-Transfer Display Formats
+
+ SET TRANSFER DISPLAY { BRIEF, CRT, FULLSCREEN, NONE, SERIAL }
+ Selects the file-transfer display format.
+
+ BRIEF is the new one. This writes one line to the screen per file,
+ showing the file's name, transfer mode, size, the status of the
+ transfer, and when the transfer is successful, the effective data rate
+ in characters per second (CPS). Example:
+
+ SEND ckcfn3.o (binary) (59216 bytes): OK (0.104 sec, 570206 cps)
+ SEND ckcfns.o (binary) (114436 bytes): OK (0.148 sec, 772006 cps)
+ SEND ckcmai.c (text) (79147 bytes): OK (0.180 sec, 438543 cps)
+ SEND ckcmai.o (binary) (35396 bytes): OK (0.060 sec, 587494 cps)
+ SEND ckcnet.o (binary) (62772 bytes): REFUSED
+ SEND ckcpro.o (binary) (121448 bytes): OK (0.173 sec, 703928 cps)
+ SEND ckcpro.w (text) (63687 bytes): OK (0.141 sec, 453059 cps)
+ SEND makefile (text) (186636 bytes): OK (0.444 sec, 420471 cps)
+ SEND wermit (binary) (1064960 bytes): OK (2.207 sec, 482477 cps)
+
+ Note that transfer times are now obtained in fractional seconds, rather
+ than whole seconds, so the CPS figures are more accurate (the display
+ shows 3 decimal places, but internally the figure is generally precise
+ to the microsecond).
+
+4.17. New Transaction Log Formats
+
+ The new command:
+
+ SET TRANSACTION-LOG { VERBOSE, FTP, BRIEF [ separator ] }
+
+ lets you choose the format of the transaction log. VERBOSE (the
+ default) indicates the traditional format described in the book. BRIEF
+ and FTP are new. This command must be given prior to the LOG
+ TRANSACTION command if a non-VERBOSE type is desired.
+
+4.17.1. The BRIEF Format
+
+ BRIEF chooses a one-line per file format suitable for direct
+ importation into databases like Informix, Oracle, or Sybase, in which:
+
+ * Each record has 8 fields.
+ * Fields are separated by a non-alphanumeric separator character.
+ * The default separator character is comma (,).
+ * Any field containing the separator character is enclosed in
+ doublequotes.
+ * The final field is enclosed in doublequotes.
+
+ The fields are:
+
+ 1. Date in yyyymmdd format
+ 2. Time in hh:mm:ss format
+ 3. Action: SEND or RECV
+ 4. The local filename
+ 5. The size of the file
+ 6. The transfer mode (text, binary, image, labeled)
+ 7. The status of the transfer: OK or FAILED
+ 8. Additional status-dependent info, in doublequotes.
+
+ Examples:
+
+ 20000208,12:08:52,RECV,/u/olga/oofa.txt,5246,text,OK,"0.284sec 18443cps"
+ 20000208,12:09:31,SEND,/u/olga/oofa.exe,32768,binary,OK,"1.243sec 26362cps"
+ 20000208,12:10:02,SEND,"/u/olga/a,b",10130,text,FAILED,"Refused: date"
+
+ Note how the filename is enclosed in doublequotes in the final example,
+ because it contains a comma.
+
+ To obtain BRIEF format, you must give the SET TRANSACTION-LOG BRIEF
+ command before the LOG TRANSACTIONS command. (If you give them in the
+ opposite order, a heading is written to the log by the LOG command.)
+
+4.17.2. The FTP Format
+
+ SET TRANSACTION-LOG FTP (available only in UNIX) chooses a format that
+ is compatible with the WU-FTPD (Washington University FTP daemon) log,
+ and so can be processed by any software that processes the WU-FTPD log.
+ It logs only transfers in and out, both successful and failed (but
+ success or failure is not indicated, due to lack of a field in the
+ WU-FTPD log format for this purpose). Non-transfer events are not
+ recorded.
+
+ Unlike other logs, the FTP-format transaction log is opened in append
+ mode by default. This allows you to easily keep a record of all your
+ kermit transfers, and it also allows the same log to be shared by
+ multiple simultaneous Kermit processes or (permissions permitting)
+ users. You can, of course, force creation of a new logfile by
+ specifying the NEW keyword after the filename, e.g.
+
+ log transactions oofa.log new
+
+ All records in the FTP-style log are in a consistent format. The first
+ field is fixed-length and contains spaces; subsequent fields are
+ variable length, contain no spaces, and are separated by one or more
+ spaces. The fields are:
+
+ Timestamp
+ This is an asctime-style timestamp, example: "Wed Sep 16
+ 20:19:05 1999" It is always exactly 24 characters long, and the
+ subfields are always in fixed positions.
+
+ Elapsed time
+ The whole number of seconds required to transfer the file, as a
+ string of decimal digits, e.g. "24".
+
+ Connection
+ The name of the network host to which C-Kermit is connected, or
+ the name of the serial device through which it has dialed (or
+ has a direct connection), or "/dev/tty" for transfers in remote
+ mode.
+
+ Bytes transferred
+ The number of bytes transferred, decimal digits, e.g. "1537904".
+
+ Filename
+ The name of the file that was transferred, e.g.
+ "/pub/ftp/kermit/a/README.TXT". If the filename contains any
+ spaces or control characters, each such character is replaced by
+ an underscore ('_') character.
+
+ Mode
+ The letter 'b' if the file was transferred in binary mode, or
+ 'a' if it was transferred in text (ASCII) mode.
+
+ Options
+ This field always contains an underscore ('_') character.
+
+ Direction
+ The letter 'o' if the file was transferred Out, and 'i' if the
+ file was transferred In.
+
+ User class
+ The letter 'r' indicates the file was transferred by a Real
+ user.
+
+ User identification
+ The ID of the user who transferred the file.
+
+ Server identification
+ The string "kermit". This distinguishes a Kermit transfer log
+ record from a WU-FTPD record, which contains "ftp" in this
+ field.
+
+ Authentication class
+ The digit '1' if we know the user's ID on the client system,
+ otherwise '0'. Currently, always '0'.
+
+ Authenticated user
+ If the authentication class is '1', this is the user's ID on the
+ client system. Otherwise it is an asterisk ('*'). Currently it
+ is always an asterisk.
+
+ Examples:
+
+ Thu Oct 22 17:42:48 1998 0 * 94 /usr/olga/new.x a _ i r olga kermit 0 *
+ Thu Oct 22 17:51:29 1998 1 * 147899 /usr/olga/test.c a _ o r olga kermit 0 *
+ Thu Oct 22 17:51:44 1998 1 * 235 /usr/olga/test.o b _ i r olga kermit 0 *
+ Fri Oct 23 12:10:25 1998 0 * 235 /usr/olga/x.ksc a _ o r olga kermit 0 *
+
+ Note that an ftp-format transaction log can also be selected on the
+ Kermit command line as follows:
+
+ kermit --xferfile:filespec
+
+ This is equivalent to:
+
+ SET TRANSACTION-LOG FTP
+ LOG TRANSACTIONS filespec APPEND
+
+ Conceivably it could be possible to have a system-wide shared Kermit
+ log, except that UNIX lacks any notion of an append-only file; thus any
+ user who could append to the log could also delete it (or alter it).
+ This problem could be worked around using setuid/setgid tricks, but
+ these would most likely interfere with the other setuid/setgid tricks
+ C-Kermit must use for getting at dialout devices and UUCP logfiles.
+
+4.18. Unprefixing NUL
+
+ As of 6.1.193 Alpha.10, C-Kermit can finally send and receive
+ file-transfer packets in which NUL (ASCII 0) is unprefixed (no more
+ NUL-terminated packets!). NUL is, of course, extremely prevalent in
+ binary files such as executables, and this has been a significant
+ source of packet overhead. For example, when transferring itself (the
+ SunOS C-Kermit executable) with minimal prefixing and 9000-byte
+ packets, we see:
+
+ File size: 1064960
+ Packet chars with 0 prefixed: 1199629 overhead = 12.65%
+ Packet chars with 0 unprefixed: 1062393 overhead = -0.03%
+
+ Transfer rates go up accordingly, not only because of the reduced
+ amount of i/o, but also because less computation is required on each
+ end.
+
+4.19. Clear-Channel Protocol
+
+ Now that C-Kermit itself is capable of sending and receiving any byte
+ at all on a clear channel ([524]Section 4.18), it is, for the first
+ time, in a position to negotiate a clear channel with the other Kermit,
+ giving it permission (but not requiring it) to unprefix any and all
+ characters that it knows are safe. In general this means all but the
+ Kermit start-of-packet character (normally Ctrl-A), Carriage Return
+ (not only Kermit's end-of-packet character, but also treated specially
+ on Telnet NVT links), and IAC (255, also special to Telnet).
+
+ By default, C-Kermit will say it has a clear channel only if it has
+ opened a TCP socket. Since the Kermit program on the far end of a
+ TCP/IP connection generally does not know it has a TCP/IP connection,
+ it will not announce a clear channel unless it has been told to do so.
+ The command is:
+
+ SET CLEAR-CHANNEL { ON, OFF, AUTO }
+
+ AUTO is the default, meaning that the clear-channel status is
+ determined automatically from the type of connection. ON means to
+ announce a clear channel, OFF means not to announce it. Use SHOW
+ STREAMING ([525]Section 4.20) to see the current CLEAR-CHANNEL status.
+ Synonym: SET CLEARCHANNEL.
+
+ CLEAR-CHANNEL is also set if you start C-Kermit with the -I switch (see
+ [526]Section 4.20).
+
+ Whenever a clear channel is negotiated, the resulting control-character
+ unprefixing is "sticky"; that is, it remains in effect after the
+ transfer so you can use SHOW CONTROL to see what was negotiated.
+
+ You can also see whether a clear channel was negotiated in the
+ STATISTICS /VERBOSE Display.
+
+ The advantage of the clear channel feature is that it can make file
+ transfers go faster automatically. The disadvantage would be
+ file-transfer failures if the channel is not truly clear, for example
+ if C-Kermit made a Telnet connection to a terminal server, and then
+ dialed out from there; or if C-Kermit made an Rlogin connection to host
+ and then made a Telnet connection from there to another host. If a file
+ transfer fails on a TCP/IP connection, use SHOW CONTROL to check
+ whether control characters became unprefixed as a result of protocol
+ negotiations, and/or SHOW STREAMING ([527]Section 4.20) to see if
+ "clear-channel" was negotiated. If this happened, use SET CLEAR-CHANNEL
+ OFF and SET PREFIXING CAUTIOUS (or whatever) to prevent it from
+ happening again.
+
+4.20. Streaming Protocol
+
+ A new Kermit protocol option called "streaming" was added in C-Kermit
+ 7.0. The idea is that if the two Kermit partners have a reliable
+ transport (such as TCP/IP or X.25) between them, then there is no need
+ to send ACKs for Data packets, or NAKs, since a reliable transport
+ will, by definition, deliver all packets in order and undamaged. On
+ such a connection, streaming cuts down not only on Kermit program
+ overhead (switching back and forth between reading and sending
+ packets), but also tends to make the underlying transport use itself
+ more efficiently (e.g. by defeating the Nagle algorithm and/or Delayed
+ ACK stratagem of the TCP layer). Furthermore, it allows transfers to
+ work smoothly on extremely slow network congestions that would
+ otherwise cause timeouts and retransmissions, and even failure when the
+ retry limit was exceeded.
+
+ The trick is knowing when we can stream:
+
+ 1. If C-Kermit has opened a TCP socket or X.25 connection, it offers
+ stream.
+ 2. If C-Kermit has been started with the -I (uppercase) option, or if
+ it has been told to SET RELIABLE ON, it offers to stream.
+ 3. If C-Kermit is in remote mode, and has been told to SET RELIABLE
+ AUTO (or ON), it always offers to stream, and also always agrees to
+ stream, if the other Kermit offers. Unless you take explicit
+ actions to override the defaults, this allows the local Kermit (the
+ one that made the connection, and so knows whether it's reliable)
+ to control streaming.
+
+ (Note that an offer to stream also results in a Clear-Channel
+ announcement if CLEAR-CHANNEL is set to AUTO; see [528]Section 4.19.)
+
+ When BOTH Kermits offer to stream, then they stream; otherwise they
+ don't. Thus streaming-capable Kermit programs interoperate
+ automatically and transparently with nonstreaming ones. If the two
+ Kermits do agree to stream, you'll see the word "STREAMING" on the
+ fullscreen file-transfer display in the Window Slots field. You can
+ also find out afterwards with the STATISTICS or SHOW STREAMING
+ commands.
+
+ WARNING: Automatic choice of streaming is based on the assumption of
+ a "direct" end-to-end network connection; for example, a Telnet or
+ Rlogin connection from host A to host B, and transferring files
+ between A and B. However, if your connection has additional
+ components -- something "in the middle" (B) that you have made a
+ network connection to, which makes a separate connection to the
+ destination host (C), then you don't really have a reliable
+ connection, but C-Kermit has no way of knowing this; transferring
+ files between A and C will probably fail. In such cases, you'll need
+ to tell the *local* C-Kermit to "set reliable off" before
+ transferring files (it does no good to give this command to the
+ remote Kermit since the local one controls the RELIABLE setting).
+
+ Streaming is like using an infinite window size, with no timeouts and
+ no tolerance for transmission errors (since there shouldn't be any). It
+ relies on the underlying transport for flow control, error correction,
+ timeouts, and retransmission. Thus it is very suitable for use on
+ TCP/IP connections, especially slow or bursty ones, since Kermit's
+ packet timeouts won't interfere with the transfer -- each packet takes
+ as long to reach its destination as it takes TCP to deliver it. If TCP
+ can't deliver the packet within its own timeout period (over which
+ Kermit has no control), it signals a fatal error. Just like FTP.
+
+ Streaming goes much faster than non-streaming when a relatively small
+ packet length is used, and it tends to go faster than non-streaming
+ with even the longest packet lengths. The Kermit window size is
+ irrelevant to streaming protocol, but still might affect performance in
+ small ways since it can result in different paths through the code.
+
+ The definition of "reliable transport" does not necessarily demand
+ 8-bit and control-character transparency. Streaming can work with
+ parity and/or control-character prefixing just as well (but not as
+ fast) as without them; in such cases you can leave RELIABLE set to ON,
+ but set CLEARCHANNEL and/or PARITY appropriately.
+
+ Maximum performance -- comparable to and often exceeding FTP -- is
+ achieved on socket-to-socket connections (in which the considerable
+ overhead of the terminal driver and Telnet or Rlogin server is
+ eliminated) with long packets and the new "brief" file-transfer display
+ ([529]Section 4.16).
+
+4.20.1. Commands for Streaming
+
+ SET RELIABLE { ON, OFF, AUTO }
+ SET RELIABLE ON tells Kermit that it has a reliable transport.
+ SET RELIABLE OFF tells Kermit the transport is not reliable.
+ SET RELIABLE AUTO tells Kermit that it should SET RELIABLE ON
+ whenever it makes a reliable connection (e.g. TELNET or SET HOST
+ on a TCP/IP or X.25 network), and when in remote mode it should
+ believe the transport is reliable if the other Kermit says it is
+ during Kermit protocol negotiation.
+
+ AUTO is the default; the Kermit program that makes the connection knows
+ whether it is reliable, and tells the remote Kermit.
+
+ The RELIABLE setting has several effects, including:
+
+ * It can affect the timeouts used during normal ACK/NAK protocol.
+ * It can affect the clear-channel announcement.
+ * It can affect streaming.
+
+ If you TELNET or SET HOST somewhere, this includes an implicit SET
+ RELIABLE ON command. The -I command-line option is equivalent to SET
+ RELIABLE ON.
+
+ Since SET RELIABLE ON (and -I) also implies SET CLEAR CHANNEL ON, you
+ might find that in certain cases you need to tell Kermit that even
+ though the connection is reliable, it doesn't have a clear channel
+ after all:
+
+ SET CLEAR-CHANNEL OFF
+ SET PREFIXING CAUTIOUS ; or whatever...
+
+ You can control streaming without affecting the other items with:
+
+ SET STREAMING { ON, OFF, AUTO }
+
+ AUTO is the default, meaning streaming will occur if Kermit has made a
+ TCP/IP connection or if RELIABLE is ON (or it was started with the -I
+ command line option). OFF means don't stream; ON means offer to stream
+ no matter what.
+
+4.20.2. Examples of Streaming
+
+ Here we look at the use and behavior of streaming on several different
+ kinds of connections, and compare its performance with non-streaming
+ transfers.
+
+4.20.2.1. Streaming on Socket-to-Socket Connections
+
+ Here we get streaming automatically when both Kermit programs are
+ capable of it, since they both make socket connections. For example, on
+ the far end:
+
+ C-Kermit> set host * 3000
+ C-Kermit> server
+
+ and on the near end:
+
+ C-Kermit> set host foo.bar.xyz.com 3000
+ (now give SEND and GET command)
+
+ All subsequent file transfers use streaming automatically.
+
+ Here are the results from 84 trials, run on a production network,
+ disk-to-disk, in which a 1-MB binary file (the SunOS C-Kermit Sparc
+ executable) was sent from a Sun Sparc-10 with SunOS 4.1.3 to an IBM
+ Power Server 850 with AIX 4.1, socket-to-socket, over a 10Mbps 10BaseT
+ Ethernet, using minimal control-character unprefixing, window sizes
+ from 10 to 32, and packet sizes from 1450 to 9010:
+
+ Streaming Nonstreaming
+ Max CPS 748955 683354
+ Min CPS 221522 172491
+ Mean CPS 646134 558680
+ Median CPS 678043 595874
+ Std Dev 101424 111493
+
+ Correlations:
+
+ CPS and window size: -0.036
+ CPS and packet length: 0.254
+ CPS and streaming: 0.382
+
+ Note that the relationship between streaming and throughput is
+ significantly stronger than that between CPS and window size or packet
+ length.
+
+ Also note that this and all other performance measurements in this
+ section are snapshots in time; the results could be much different at
+ other times when the load on the systems and/or the network is higher
+ or lower.
+
+ In a similar socket-to-socket trial, but this time over a wide-area
+ TCP/IP connection (from New York City to Logan, Utah, about 2000
+ miles), the following results were obtained:
+
+ Streaming Nonstreaming
+ Max CPS 338226 318203
+ Min CPS 191659 132314
+ Mean CPS 293744 259240
+ Median CPS 300845 273271
+ Std Dev 41914 52351
+
+ Correlations:
+
+ CPS and window size: 0.164
+ CPS and packet length: 0.123
+ CPS and streaming: 0.346
+
+4.20.2.2. Streaming on Telnet Connections
+
+ In this case the local copy of Kermit is told to TELNET or SET HOST,
+ and so it knows it has a reliable connection and -- unless it has been
+ told not to -- will offer to stream, and the other Kermit program,
+ since it has STREAMING set to AUTO, agrees.
+
+ Since we have a reliable connection, we'll also get control-character
+ unprefixing automatically because of the new clear-channel protocol
+ ([530]Section 4.19).
+
+ Any errors that occur during streaming are fatal to the transfer. The
+ message is "Transmission error on reliable link". Should this happen:
+
+ 1. Check the remote Kermit's flow control setting (SHOW
+ COMMUNICATIONS). If it is NONE, change it to XON/XOFF, or vice
+ versa. If it is XON/XOFF (or you just changed it to XOFF/XOFF),
+ make sure the file sender is prefixing the XON and XOFF characters.
+ In the most drastic case, use "set prefix all" to force prefixing
+ of all control characters.
+ 2. The remote Telnet server might chop off the 8th bit. In that case,
+ tell C-Kermit to "set parity space". Or, you might be able to force
+ the Telnet to allow eight-bit data by telling C-Kermit to "set
+ telopt binary request accept" -- that is, request the Telnet server
+ to enter binary mode, and accept binary-mode bids from the server.
+ 3. The remote Telnet server might have a buffering limitation. If a
+ and b don't cure the problem, tell the file receiver to "set
+ receive packet-length 1000" (or other number -- use the largest one
+ that works). This too, is no different from the non-streaming case
+ (more about this in [531]Section 4.20.2.3).
+
+ And remember you can continue interrupted binary-mode transfers where
+ they left off with the RESEND (= SEND /RECOVER) command.
+
+ Here are the figures for the same 84 trials between the same Sun and
+ IBM hosts as in 4.20.2.1, on the same network, but over a Telnet
+ connection rather than socket-to-socket:
+
+ Streaming Nonstreaming
+ Max CPS 350088 322523
+ Min CPS 95547 173152
+ Mean CPS 321372 281830
+ Median CPS 342604 291469
+ Std Dev 40503 29948
+
+ Correlations:
+
+ CPS and window size: 0.001
+ CPS and packet length: 0.152
+ CPS and streaming: 0.128
+
+ Here the effect is not as emphatic as in the socket-to-socket case, yet
+ on the whole streaming tends to be beneficial.
+
+ Additional measurements on HP-UX using C-Kermit 7.0 Beta.06:
+
+ Windowing Streaming
+ HP-UX 8->8 not tested 14Kcps
+ HP-UX 8->9 not tested 76Kcps
+ HP-UX 8->10 36Kcps 66Kcps
+ HP-UX 9->9 not tested 190Kcps
+ HP-UX 9->10 160Kcps 378Kcps
+
+4.20.2.3. Streaming with Limited Packet Length
+
+ The IRIX telnet server (at least the ones observed in IRIX 5.3 and 6.2)
+ does not allow Kermit to send packets longer than 4096 bytes. Thus when
+ sending from IRIX C-Kermit when it is on the remote end of a Telnet
+ connection, the packet length must be 4K or less. Trials in this case
+ (in which packet lengths range from 1450 to 4000) show a strong
+ advantage for streaming, which would be evident in any other case where
+ the packet length is restricted, and stronger the shorter the maximum
+ packet length.
+
+ Streaming Nonstreaming
+ Max CPS 426187 366870
+ Min CPS 407500 276517
+ Mean CPS 415226 339168
+ Median CPS 414139 343803
+ Std Dev 6094 25851
+
+ Correlations:
+
+ CPS and window size: 0.116
+ CPS and packet length: 0.241
+ CPS and streaming: 0.901
+
+4.20.2.4. Streaming on Dialup Connections
+
+ Here "dialup" refers to a "direct" dialup connection, not a SLIP or PPP
+ connection, which is only a particular kind of TCP/IP connection.
+
+ Attempt this at your own risk, and then only if (a) you have
+ error-correcting modems, and (b) the connections between the modems and
+ computers are also error-free, perfectly flow-controlled, and free of
+ interrupt conflicts. Streaming can be used effectively and to fairly
+ good advantage on such connections, but remember that the transfer is
+ fatal if even one error is detected (also remember that should a
+ binary-mode transfer fail, it can be recovered from the point of
+ failure with RESEND).
+
+ To use streaming on an unreliable connection, you must tell both
+ Kermits that the connection is reliable:
+
+ kermit -I
+
+ or:
+
+ C-Kermit> set reliable on
+
+ In this case, it will probably be necessary to prefix some control
+ characters, for example if your connection is through a terminal server
+ that has an escape character. Most Cisco terminal servers, for example,
+ require Ctrl-^ (30, as well as its high-bit equivalent, 158) to be
+ prefixed. To unprefix these, you'll need to defeat the "clear channel"
+ feature:
+
+ C-Kermit> set reliable on
+ C-Kermit> set clear-channel off
+ C-Kermit> set prefixing none
+ C-Kermit> set control prefix 1 13 30 158 ; and whatever else is necessary
+
+ Dialup trials were done using fixed large window and packet sizes. They
+ compare uploading and downloading of two common types of files, with
+ and without streaming. Configuration:
+
+ HP-9000/715/33 -- 57600bps, RTS/CTS -- USR Courier V.34 --
+ V.34+V.42, 31200bps -- USR V.34+ Rackmount -- 57600bps, RTS/CTS --
+ Cisco terminal server -- Solaris 2.5.1. Packet size = 8000, Window
+ Size = 30, Control Character Unprefixing Minimal (but including the
+ Cisco escape character).
+
+ Since this is not a truly reliable connection, a few trials failed when
+ a bad packet was received (most likely due to UART overruns); the
+ failure was graceful and immediate, and the message was informative.
+ The results of ten successful trials uploading and downloading the two
+ files with and without streaming are:
+
+ Streaming..
+ Off On
+ Upload 5194 5565 txt (= C source code, 78K)
+ 3135 3406 gz (= gzip file, compressed, 85K)
+ Download 5194 5565 txt
+ 3041 3406 gz
+
+ Each CPS figure is the mean of 10 results.
+
+ A brief test was also performed on a LAT-based dialout connection from
+ a VAX 3100 with VMS 5.5 to a USR Courier V.34 connected to a DECserver
+ 700 at 19200 bps. The 1-MB Sparc executable downloaded from a Sun to
+ the VAX at 1100cps without streaming and 1900cps with streaming, using
+ 8000-byte packets, 30 window slots, and minimal prefixing in both
+ cases.
+
+4.20.2.5. Streaming on X.25 Connections
+
+ We have only limited access to X.25 networks. One trial was performed
+ in which the 1MB Solaris 2.4 Sparc executable was transferred over a
+ SunLink X.25 connection; nothing is known about the actual physical
+ connection. With a packet length of 8000 and a window size of 30, the
+ file transferred at 6400 cps (using a maximum of 6 window slots). With
+ the same packet length, but with streaming, it transferred without
+ mishap at 6710 cps, about 5% faster.
+
+4.20.3. Streaming - Preliminary Conclusions
+
+ The results vary with the particular connection, but are good overall.
+ Although numerous lower-level tricks can be used to improve performance
+ on specific platforms or connection methods, streaming occurs at a
+ high, system-independent level of the Kermit protocol and therefore can
+ apply to all types of platforms and (reliable) connections
+ transparently.
+
+4.21. The TRANSMIT Command
+
+ Prior to C-Kermit 7.0, the TRANSMIT command transmitted in text or
+ binary mode according to SET FILE TYPE { TEXT, BINARY }. But now that
+ binary mode is likely to be the default for protocol transfers, it is
+ evident that this not also an appropriate default for TRANSMIT, since
+ binary-mode TRANSMIT is a rather specialized and tricky operation.
+ Therefore, TRANSMIT defaults to text mode always, regardless of the
+ FILE TYPE setting.
+
+ C-Kermit 7.0 expands the capabilities of the TRANSMIT command by adding
+ the following switches (see [532]Section 1.5). The new syntax is:
+
+ TRANSMIT [ switches... ] filename
+
+ Zero or more switches may be included:
+
+ /PIPE
+ When /PIPE is included, "filename" is interpreted as a system
+ command or program whose output is to be sent. Synonym:
+ /COMMAND. Example:
+
+ transmit /pipe finger
+
+ You may enclose the command in braces, but you don't have to:
+
+ xmit /pipe {ls -l | sort -r +0.22 -0.32 | head}
+
+ /BINARY
+ Transmits the file (or pipe output) in binary mode.
+
+ /TEXT
+ Transmits the file (or pipe output) in line-oriented text mode.
+ Current FILE CHARACTER-SET and TERMINAL CHARACTER-SET selections
+ govern translation. Default.
+
+ /TRANSPARENT
+ Specifies text mode without character-set translation, no matter
+ what the FILE and TERMINAL CHARACTER-SET selections are.
+
+ /NOWAIT
+ This is equivalent to SET TRANSMIT PROMPT 0, but for this
+ TRANSMIT command only. Applies only to text mode; it means to
+ not wait for any kind of echo or turnaround character after
+ sending a line before sending the next line. (Normally Kermit
+ waits for a linefeed.)
+
+ When TRANSMIT ECHO is ON, C-Kermit tries to read back the echo of each
+ character that is sent. Prior to C-Kermit 7.0, 1 second was allowed for
+ each echo to appear; if it didn't show up in a second, the TRANSMIT
+ command would fail. Similarly for the TRANSMIT PROMPT character.
+ However, with today's congested Internet connections, etc, more time is
+ often needed:
+
+ SET TRANSMIT TIMEOUT number
+
+ Specifies the number of seconds to wait for an echo or the prompt
+ character when TRANSMIT PROMPT is nonzero; the default wait is 1
+ second. If you specify 0, the wait is indefinite. When a timeout
+ interval of 0 is specified, and a desired echo or prompt does not show
+ up, the TRANSMIT command will not terminate until or unless you
+ interrupt it with Ctrl-C; use SET TRANSMIT TIMEOUT 0 with caution.
+
+ Note: to blast a file out the communications connection without any
+ kind of synchronization or timeouts or other manner of checking, use:
+
+ SET TRANSMIT ECHO OFF
+ SET TRANSMIT PROMPT 0 (or include the /NOWAIT switch)
+ SET TRANSMIT PAUSE 0
+ TRANSMIT [ switches ] filename
+
+ In this case, text-file transmission is not-line oriented and large
+ blocks can be sent, resulting in a significant performance improvement
+ over line-at-at-time transmission. Successful operation depends (even
+ more than usual for the TRANSMIT command!) on a clean connection with
+ effective flow control.
+
+ For details on TRANSMIT and character sets, see [533]Section 6.6.5.4.
+
+ 4.22. Coping with Faulty Kermit Implementations
+
+ Kermit protocol has been implemented in quite a few third-party
+ commercial, shareware, and freeware software packages, with varying
+ degrees of success. In most cases operation is satisfactory but slow --
+ only the bare minimum subset of the protocol is available -- short
+ packets, no sliding windows, no attributes, etc. In other cases, the
+ implementation is incorrect, resulting in failures at the initial
+ negotiation stage or corrupted files.
+
+ C-Kermit 7.0 and Kermit 95 1.1.19 include some new defense mechanisms
+ to help cope with the most common situations. However, bear in mind
+ there is only so much we can do in such cases -- the responsibility for
+ fixing the problem lies with the maker of the faulty software.
+
+ 4.22.1. Failure to Accept Modern Negotiation Strings
+
+ The published Kermit protocol specification states that new fields can
+ be added to the parameter negotiation string. These are to be ignored
+ by any Kermit implementation that does not understand them; this is
+ what makes the Kermit protocol extensible. Unfortunately, some Kermit
+ implementations become confused (or worse) when receiving a negotiation
+ string longer than the one they expect. You can try working around such
+ problems by telling Kermit to shorten its negotiation string (and thus
+ disable the corresponding new features):
+
+ SET SEND NEGOTIATION-STRING-MAX-LENGTH number
+
+ Try a number like 10. If that doesn't work, try 9, 8, 7, 6, and so on.
+
+ 4.22.2. Failure to Negotiate 8th-bit Prefixing
+
+ The published Kermit protocol specification states that 8th-bit
+ prefixing (which allows transfer of 8-bit data over a 7-bit connection)
+ occurs if the file sender puts a valid prefix character (normally "&")
+ in the 8th-bit-prefix field of the negotiation string, and the receiver
+ puts either a letter "Y" or the same prefix character. At least one
+ faulty Kermit implementation exists that does not accept the letter
+ "Y". To force C-Kermit / K-95 to reply with the other Kermit's prefix
+ character rather than a "Y", give the following (invisible) command:
+
+ SET Q8FLAG ON
+
+ Use SET Q8FLAG OFF to restore the normal behavior.
+
+ 4.22.3. Corrupt Files
+
+ Refer to [534]Section 4.22.2. Some Kermit implementations mistakenly
+ interpret the "Y" as a prefix character. Then, whenever a letter Y
+ appears in the data, the Y and the character that follows it are
+ replaced by a garbage character. At this writing, we are not sure if
+ there is any solution, but try "set send negotiation-string-max-length
+ 6" and/or "set q8flag on".
+
+ File corruption can also occur when control characters within the file
+ data are sent without prefixing, as at least some are by default in
+ C-Kermit 7.0 and K-95. Some Kermit implementations do not handle
+ incoming "bare" control characters. To work around, "set prefixing
+ all".
+
+ 4.22.4. Spurious Cancellations
+
+ The Kermit protocol specification states that if an ACK to a Data
+ packet contains X in its data field, the transfer of the current file
+ is canceled, and if it contains a Z, the entire transfer is canceled.
+ At least one overzealous Kermit implementation applies this rule to
+ non-Data packets as well, the typical symptom being that any attempt to
+ transfer a file whose name begins with X or Z results in cancellation.
+ This is because the file receiver typically sends back the name under
+ which it stored the file (which might not be the same as the name it
+ was sent with) in the ACK to the File Header packet. This is
+ information only and should not cause cancellation. To work around the
+ problem, use:
+
+ SET F-ACK-BUG { ON, OFF }
+
+ ON tells Kermit not to send back the filename in the ACK to the file
+ header packet as it normally would do (OFF puts Kermit back to normal
+ after using ON).
+
+ A variation on the this bug occurs in an obscure Kermit program for
+ MUMPS: When this Kermit program sends a file called (say) FOO.BAR, it
+ requires that the ACK to its F packet contain exactly the same name,
+ FOO.BAR. However, C-Kermit likes to send back the full pathname,
+ causing the MUMPS Kermit to fail. SET F-ACK-BUG ON doesn't help here.
+ So a separate command has been added to handle this situation:
+
+ SET F-ACK-PATH { ON, OFF }
+
+ Normally it is ON (regardless of the SET SEND PATHNAMES setting). Use
+ SET F-ACK-PATH OFF to instruct Kermit to send back only the filename
+ without the path in the ACK to the F packet.
+
+ 4.22.5. Spurious Refusals
+
+ Some Kermit implementations, notably PDP-11 Kermit 3.60 and earlier,
+ have bugs in their handling of Attribute packets that can cause
+ unwarranted refusal of incoming files, e.g. based on date or size. This
+ can be worked around by telling one or both of the Kermit partners to:
+
+ SET ATTRIBUTES OFF
+
+ 4.22.6. Failures during the Data Transfer Phase
+
+ This can be caused by control-character unprefixing ([535]Section
+ 4.22.3 ), and fixed by:
+
+ SET PREFIXING ALL
+
+ It can also have numerous other causes, explained in Chapter 10 of
+ [536]Using C-Kermit: the connection is not 8-bit transparent (so use
+ "set parity space" or somesuch), inadequate flow control, etc. Consult
+ the manual.
+
+ 4.22.7. Fractured Filenames
+
+ At least one well-known PC-based communications package negotiates data
+ compression, which (according to the protocol specification) applies to
+ both the filename and the file data, but then fails to decompress the
+ filename. Example: C-Kermit sends a file called R000101.DAT (where
+ 000101 might be non-Y2K-wise YYMMDD notation), and the package in
+ question stores the files as R~#0101.DAT. Workaround: Tell C-Kermit to
+ SET REPEAT COUNTS OFF.
+
+ 4.22.8. Bad File Dates
+
+ At least one well-known PC-based communications package negotiates the
+ passing of file timestamps from sender to receiver, but when it is
+ sending files, it always gives them a timestamp of 1 February 1970.
+ Workaround: tell C-Kermit to SET ATTRIBUTE DATE OFF. You don't get the
+ file's real date, but you also don't get 1 Feb 1970; instead the file
+ gets the current date and time.
+
+ 4.23. File Transfer Recovery
+
+ Prior to C-Kermit 7.0, RESEND (SEND /RECOVER) and REGET (GET /RECOVER)
+ refused to work if FILE TYPE was not BINARY or the /BINARY switch was
+ not included. Now these commands include an implied /BINARY switch,
+ meaning they set the file type to binary for the duration of the
+ command automatically.
+
+ In the client/server arrangement, this also forces the server into
+ binary mode (if it is C-Kermit 7.0 or greater, or K95 1.1.19 or
+ greater) so the recovery operation proceeds, just as you asked and
+ expected.
+
+ BUT... Just as before, the results are correct only under the following
+ conditions:
+
+ * If the prior interrupted transfer was also in binary mode; or:
+ * If the prior transfer was in text mode and the other computer was a
+ "like platform" (e.g. UNIX-to-UNIX, Windows-to-Windows,
+ DOS-to-Windows) AND there was no character-set translation (i.e.
+ TRANSFER CHARACTER-SET was TRANSPARENT).
+
+ Note that these circumstances are more likely to obtain in C-Kermit
+ 7.0, in which:
+
+ * The default FILE TYPE in C-Kermit 7.0 is BINARY.
+ * The default FILE INCOMPLETE setting is AUTO, which means KEEP if
+ the transfer is in binary mode, DISCARD otherwise.
+ * C-Kermit 7.0, Kermit 95 1.1.17, and MS-DOS Kermit 3.15 and later
+ can recognize "like platforms" and switch into binary mode
+ automatically. Transfers between like platforms are always binary
+ unless character-set translation has been requested, and then is
+ still binary for all files whose names match a binary pattern,
+ unless the automatic mechanisms have been disabled (with a /TEXT
+ switch, or with SET TRANSFER MODE MANUAL).
+ * SEND /BINARY and GET /BINARY always force binary-mode transfers,
+ even when FILE TYPE is TEXT, even when TRANSFER MODE is AUTOMATIC,
+ even when PATTERNS are ON and the file's name matches a text
+ pattern.
+
+ But also note that the automatic client/server transfer-mode
+ adjustments do not work with versions of C-Kermit prior to 7.0 or K95
+ prior to 1.1.16.
+
+ If the prior transfer was in text mode:
+
+ * If text-mode transfers between the two platforms are
+ "length-changing" (as they are between UNIX -- which terminates
+ text lines with LF -- and DOS or Windows -- which terminates text
+ lines with CRLF), the recovered file will be corrupt.
+ * If text-mode transfers between the two platforms are not
+ length-changing, but character-set translation was active in the
+ prior transfer, the result will be a file in which the first part
+ has translated characters and the second part does not.
+
+ But in C-Kermit 7.0 and K95 1.1.19 and later, incompletely transferred
+ text files are not kept unless you change the default. But if you have
+ done this, and you have an incompletely transferred text file, you'll
+ need to:
+
+ * Transfer the whole file again in text mode, or:
+ * Use SEND /STARTING-AT: to recover the transfer at the correct
+ point; but you have to find out what that point is, as described in
+ the manual.
+
+ Kermit has no way of knowing whether the previous transfer was in text
+ or binary mode so it is your responsibility to choose the appropriate
+ recovery method.
+
+ If you use C-Kermit to maintain parallel directories on different
+ computers, using SET FILE COLLISION to transfer only those files that
+ changed since last time, and the files are big enough (or the
+ connection slow enough) to require SEND /RECOVER to resume interrupted
+ transfers, you should remember that SEND /RECOVER (RESEND) overrides
+ all FILE COLLISION settings. Therefore you should use SEND /RECOVER
+ (RESEND) only on the file that was interrupted, not the file group. For
+ example, if the original transfer was initiated with:
+
+ SEND *
+
+ and was interrupted, then after reestablishing your connection and
+ starting the Kermit receiver with SET FILE COLLISION UPDATE on the
+ remote end, use the following sequence at the sender to resume the
+ transfer:
+
+ SEND /RECOVER name-of-interrupted-file
+
+ and then:
+
+ SEND *
+
+ (In C-Kermit 7.0 and later, \v(filename) contains the name of the file
+ most recently transferred, as long you have not EXITed from Kermit or
+ changed directory, etc.
+
+ 4.24. FILE COLLISION UPDATE Clarification
+
+ In UNIX, file modification dates are used when comparing the file date
+ with the date in the attribute packet. In VMS, however, the file
+ creation date is used. These two policies reflect the preferences of
+ the two user communities.
+
+ Also, remember that the file date/time given in the attribute packet is
+ the local time at the file sender. At present, no timezone conversions
+ are defined in or performed by the Kermit protocol. This is primarily
+ because this feature was designed at a time when many of the systems
+ where Kermit runs had no concept of timezone, and therefore would be
+ unable to convert (say, to/from GMT or UTC or Zulu time).
+
+ As a consequence, some unexpected results might occur when transferring
+ files across timezones; e.g. commands on the target system that are
+ sensitive to file dates might not work (UNIX "make", backups, etc).
+
+ Timezone handling is deferred for a future release.
+
+ 4.25. Autodownload Improvements
+
+ Refer to pages 164-165 of [537]Using C-Kermit about the hazards of
+ autodownload when C-Kermit is "in the middle". As of C-Kermit 7.0, no
+ more hazards. If C-Kermit has TERMINAL AUTODOWNLOAD ON and it detects a
+ packet of the current protocol type (Kermit or Zmodem), it "erases" the
+ visual aspect of the packet that would be seen by the terminal (or,
+ more to the point, the emulator, such as K95). This way, only C-Kermit
+ goes into RECEIVE mode, and not also the terminal emulator through
+ which C-Kermit is accessed. And therefore, it is no longer necessary to
+ SET TERMINAL AUTODOWNLOAD OFF to prevent multiple Kermits from going
+ into receive mode at once, but of course it is still necessary to
+ ensure that, when you have multiple Kermits in a chain, that the
+ desired one receives the autodownload.
+
+ The defaults have not been changed; Kermit 95 still has autodownload ON
+ by default, and C-Kermit has it OFF by default.
+
+ 5. CLIENT/SERVER
+
+ 5.0. Hints
+
+ If you use SET SERVER GET-PATH to set up your server, and the GET-PATH
+ does not include the server's current directory, clients can become
+ quite confused. For example, "remote dir oofa.txt" shows a file named
+ oofa.txt, but "get oofa.txt" fails. In this situation, you should
+ either DISABLE DIR or make your GET-PATH include the current directory.
+
+ 5.1. New Command-Line Options
+
+ The -G command-line option is like -g (GET), except the incoming file
+ is sent to standard output rather than written to disk.
+
+ The -I option ("Internet") is used to tell a remote C-Kermit program
+ that you are coming in via Internet Telnet or Rlogin and therefore have
+ a reliable connection. The -I option is equivalent to SET RELIABLE ON
+ and SET FLOW NONE.
+
+ The -O option ("Only One") tells C-Kermit to enter server mode but then
+ exit after the first client operation.
+
+ See [538]Section 9.3 for details.
+
+ 5.2. New Client Commands
+
+ BYE and FINISH no longer try to do anything if a connection is not
+ active. Thus a sequence like "hangup" followed by "bye" or "finish"
+ will no longer get stuck in a long timeout-and-retransmission cycle,
+ nor will it try to open a new connection.
+
+ REMOTE EXIT
+ Similar to FINISH, except it ensures that the Kermit server
+ program exits back to the operating system or shell prompt.
+ (FINISH would return it to its interactive prompt if it was
+ started in interactive mode, and would cause it to exit if it
+ entered server mode via command-line option.) When C-Kermit is
+ to be the server, you can use { ENABLE, DISABLE } EXIT to
+ control the client's access to this feature.
+
+ REMOTE MKDIR directory-name
+ Tells the client to ask the server to create a directory with
+ the given name, which can be absolute or relative. The syntax of
+ the directory name depends on the Kermit server (see [539]next
+ section); in all cases, it can be in the syntax of the system
+ where the server is running (UNIX, VMS, DOS, etc) but newer
+ servers also accept UNIX syntax, no matter what the underlying
+ platform. The server will not execute this command if (a) it
+ does not understand it, (b) a DISABLE MKDIR command has been
+ given, or (c) a DISABLE CWD command has been given; otherwise,
+ the command is executed, but will fail if the directory can not
+ be created, in which cases most servers will attempt to return a
+ message giving the reason for failure. The REMOTE MKDIR command
+ succeeds if the remote directory is created, or if it already
+ exists and therefore does not need to be created, and fails
+ otherwise.
+
+ REMOTE RMDIR directory-name
+ Tells the client to ask the server to remove (delete) a
+ directory with the given name. The same considerations apply as
+ for REMOTE MKDIR.
+
+ REMOTE SET FILE INCOMPLETE { DISCARD, KEEP, AUTO }
+ Previously this was only available in its earlier form, REMOTE
+ SET INCOMPLETE (no FILE). The earlier form is still available,
+ but invisible. Also, AUTO was added, meaning KEEP if in binary
+ mode, DISCARD otherwise.
+
+ REMOTE SET TRANSFER MODE { AUTOMATIC, MANUAL }
+ Tells the client to ask the server to set the given
+ file-transfer mode. Automatic means (roughly): if the client and
+ the server are running on the same kind of computer (e.g. both
+ are on UNIX), then use binary mode automatically; if the system
+ types are different, use some other method to automatically
+ determine text or binary mode, such as filename pattern
+ matching. MANUAL means, in this context, obey the client's FILE
+ TYPE setting (TEXT or BINARY). Synonym: REMOTE SET XFER MODE.
+
+ [ REMOTE ] QUERY KERMIT function(args...)
+ Prior to C-Kermit 7.0, the arguments were not evaluated locally.
+ Thus it was not possible to have the server run the function
+ with client-side variables as arguments. Now:
+
+ define \%a oofa.*
+ remote query kermit files(\%a) ; Client's \%a
+ remote query kermit files(\\%a) ; Server's \%a
+
+ [ REMOTE ] LOGIN [ user [ password ] ]
+ LOGIN is now a synonym for REMOTE LOGIN.
+
+ LOGOUT
+ This command, when given in local mode, is equivalent to REMOTE
+ LOGOUT. When given at the IKSD prompt, it logs out the IKSD.
+ When given at the C-Kermit prompt when it has no connection, it
+ does nothing.
+
+ Note that in C-Kermit 7.0, the REMOTE (or R) prefix is not required for
+ QUERY, since there is no local QUERY command. The new top-level QUERY
+ command does exactly what REMOTE QUERY (RQUERY) does.
+
+ All REMOTE commands now have single-word shortcuts:
+
+ Shortcut Full Form
+ RASG REMOTE ASSIGN
+ RCD REMOTE CD
+ RCOPY REMOTE COPY
+ RDEL REMOTE DELETE
+ RDIR REMOTE DIRECTORY
+ REXIT REMOTE EXIT
+ RHELP REMOTE HELP
+ RHOST REMOTE HOST
+ RPWD REMOTE PWD
+ RSET REMOTE SET
+ etc.
+
+ The R prefix is not applied to LOGIN because there is already an RLOGIN
+ command with a different meaning. It is not applied to LOGOUT either,
+ since LOGOUT knows what to do in each case, and for symmetry with
+ LOGIN.
+
+ 5.2.1. Remote Procedure Definitions and Calls
+
+ This is nothing new, but it might not be obvious... REMOTE ASSIGN and
+ REMOTE QUERY may be used to achieve remote procedure execution. The
+ remote procedure can be defined locally or remotely.
+
+ A remote procedure call is accomplished as noted in the previous
+ section:
+
+ [ remote ] query kermit function-name(args...)
+
+ This invokes any function that is built in to the Kermit server, e.g.:
+
+ [ remote ] query kermit size(foo.bar)
+
+ returns the size of the remote file, foo.bar.
+
+ Now note that C-Kermit includes an \fexecute() function, allowing it to
+ execute any macro as if it were a built-in function. So suppose MYMACRO
+ is the name of a macro defined in the server. You can execute it from
+ the client as follows (the redundant "remote" prefix is omitted in the
+ remaining examples):
+
+ query kermit execute(mymacro arg1 arg2...)
+
+ The return value, if any, is the value of the RETURN command that
+ terminated execution of the macro, for example:
+
+ define addtwonumbers return \feval(\%1+\%2)
+
+ The client invocation would be:
+
+ query kermit execute(addtwonumbers 3 4)
+ 7
+
+ The result ("7" in this case) is also assigned to the client's
+ \v(query) variable.
+
+ To execute a remote system command or command procedure (shell script,
+ etc) use:
+
+ query kermit command(name args...)
+
+ Finally, suppose you want the client to send a macro to the server to
+ be executed on the server end. This is done as follows:
+
+ remote assign macroname definition
+ query kermit execute(macroname arg1 arg2...)
+
+ Quoting is required if the definition contains formal parameters.
+
+ 5.3. New Server Capabilities
+
+ 5.3.1. Creating and Removing Directories
+
+ The C-Kermit 7.0 server responds to REMOTE MKDIR and REMOTE RMDIR
+ commands. The directory name may be in either the native format of the
+ server's computer, or in UNIX format. For example, a server running on
+ VMS with a current directory of [IVAN] can accept commands from the
+ client like:
+
+ remote mkdir olga ; Makes [IVAN.OLGA] (nonspecific format)
+ remote mkdir .olga ; Makes [IVAN.OLGA] (VMS format without brackets)
+ remote mkdir olga/ ; Makes [IVAN.OLGA] (UNIX relative format)
+ remote mkdir /ivan/olga ; Makes [IVAN.OLGA] (UNIX absolute format)
+ remote mkdir [ivan.olga] ; Makes [IVAN.OLGA] (VMS absolute format)
+ remote mkdir [.olga] ; Makes [IVAN.OLGA] (VMS relative format)
+
+ 5.3.1.1. Creating Directories
+
+ If a directory name is given that contains more than one segment that
+ does not exist, the server attempts to create all the segments. For
+ example, if the client says:
+
+ REMOTE MKDIR letters/angry
+
+ a "letters" subdirectory is created in the server's current directory
+ if it does not already exist, and then an "angry" subdirectory is
+ created beneath it, if it does not already have one. This can repeated
+ to any reasonable depth:
+
+ REMOTE MKDIR a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/z/y/z
+
+ 5.3.1.2. Removing Directories
+
+ When attempting to execute a REMOTE RMDIR, the server can remove only a
+ single directory, not an entire sequence or tree. The system service
+ that is called to remove the directory generally requires not only that
+ the server process has write delete access, but also that the directory
+ contain no files.
+
+ In the future, a REMOTE RMDIR /RECURSIVE command (and the accompanying
+ protocol) might be added. For now, use the equivalent REMOTE HOST
+ command(s), if any.
+
+ 5.3.2. Directory Listings
+
+ Directory listings are generated by C-Kermit itself, rather than by
+ running the underlying system's directory command. Some control over
+ the listing format can be obtained with the SET OPTIONS DIRECTORY
+ command ([540]Section 4.5.1). The following options affect listings
+ sent by the server: /[NO]HEADING, /[NO]DOTFILES, and /[NO]BACKUP. In
+ UNIX and VMS, the listing is always sorted by filename. There is, at
+ present, no protocol defined for the client to request listing options
+ of the server; this might be added in the future.
+
+ The server's directory listings are in the following format:
+
+ Protection or permissions:
+ In UNIX and OS-9, this is a 10-character field, left adjusted.
+ In VMS it is a 22-character field, left-adjusted. In each case,
+ the protection / permission codes are shown in the server
+ platform's native format. In other operating systems, this field
+ is not shown.
+
+ Size in bytes:
+ This is always a 10-character field. The file's size is shown as
+ a decimal number, right adjusted in the field. If the file is a
+ directory and its size can not be obtained, the size is shown as
+ "<DIR>". Two blanks follow this field.
+
+ Date:
+ Always in yyyy-mm-dd hh:mm:ss numeric format, and therefore 19
+ characters long. If the file's date/time can't be obtained,
+ zeros (0) are shown for all the digits. This field is followed
+ by two blanks.
+
+ Filename:
+ This field extends to the end of the line. Filenames are shown
+ relative to the server's current directory. In UNIX, symbolic
+ links are shown as they are in an "ls -l" listing as "linkname
+ -> filename".
+
+ In UNIX and VMS, listings are returned by the server in alphabetical
+ order of filename. There are presently no other sort or selection
+ options.
+
+ However, since these are fixed-field listings, all fields can be used
+ as sort keys by external sort programs. Note, in particular, that the
+ format used for the date allows a normal lexical on that field to
+ achieve the date ordering. For example, let's assume we have a UNIX
+ client and a UNIX server. In this case, the server's listing has the
+ date in columns 22-40, and thus could be sorted by the UNIX sort
+ program using "sort +0.22 -0.40" or in reverse order by "sort +0.22
+ -0.40r".
+
+ Since the UNIX client can pipe responses to REMOTE commands through
+ filters, any desired sorting can be accomplished this way, for example:
+
+C-Kermit> remote directory | sort +0.22 -0.40
+
+ You can also sort by size:
+
+ C-Kermit> remote directory | sort +0.11 -0.19
+
+ You can use sort options to select reverse or ascending order. "man
+ sort" (in UNIX) for more information. And of course, you can pipe these
+ listings through any other filter of your choice, such as grep to skip
+ unwanted lines.
+
+ 5.4. Syntax for Remote Filenames with Embedded Spaces
+
+ C-Kermit and K95, when in server mode, assume that any spaces in the
+ file specification in an incoming GET command are filename separators.
+ Thus if the client gives a command like:
+
+ get {oofa.txt oofa.bin}
+
+ or, equivalently:
+
+ mget oofa.txt oofa.bin
+
+ the server tries to send the two files, oofa.txt and oofa.bin. But what
+ if you want the server to send you a file named, say:
+
+ D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL
+
+ How does the server know this is supposed to be one file and not seven?
+ In this case, you need to the send file name to the server enclosed in
+ either curly braces:
+
+ {D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL}
+
+ or ASCII doublequotes:
+
+ "D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL"
+
+ The method for doing this depends on your client. If your client is
+ C-Kermit 7.0, any recent version of Kermit 95, or MS-DOS Kermit 3.16,
+ then you have to enclose the name in braces just so the client can
+ parse it, so to send braces or doublequotes to the server, you must put
+ them inside the first, outside pair of braces. And you also need to
+ double the backslashes to prevent them from being interpreted:
+
+ get {{D:\\HP OfficeJet 500\\Images\\My Pretty Picture Dot PCL}}
+ get {"D:\\HP OfficeJet 500\\Images\\My Pretty Picture Dot PCL"}
+
+ To get around the requirement to double backslashes in literal
+ filenames, of course you can also use:
+
+ set command quoting off
+ get {{D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL}}
+ get {"D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL"}
+ set command quoting on
+
+ If you are giving a "kermit" command to the UNIX shell, you have to
+ observe the shell's quoting rules, something like this:
+
+ kermit -ig "{D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL}"
+
+ Here, the quotes go on the outside so UNIX will pass the entire
+ filename, spaces, braces, and all, as a single argument to Kermit, and
+ the backslashes are not doubled because (a) the UNIX shell ignores them
+ since they are in a quoted string, and (b) Kermit ignores them since
+ the interactive command parser is not activated in this case.
+
+ 5.5. Automatic Orientation Messages upon Directory Change
+
+ C-Kermit 7.0, when acting as a server, can send an orientation message
+ to the client whenever the server directory changes. For example, when
+ the client gives a REMOTE CD command, the server sends the contents of
+ the new directory's "Read Me" file to the client's screen. The
+ following commands govern this feature:
+
+ SET SERVER CD-MESSAGE FILE name
+ Given to the servr, allows the message-file name to be specified
+ at runtime. A list of names to look for can be given in the
+ following format:
+
+ {{name1}{name2}{name3}{...}}
+
+ e.g. SET SERVER CD-MESSAGE FILE
+ {{./.readme}{README.TXT}{READ.ME}}
+
+ REMOTE SET SERVER CD-MESSAGE { ON, OFF }
+ Given to the client, lets the client control whether the server
+ sends automatic CD messages.
+
+ SHOW SERVER
+ Given to server, includes CD-Message status.
+
+ The default CD message file name is system dependent. SHOW CD or SHOW
+ SERVER displays the list. Also see [541]Section 4.5.2.
+
+ 5.6. New Server Controls
+
+ DISABLE ENABLE
+ Allows the server to configured such that DISABLEd features can
+ not be re-enabled by any means -- e.g. if the client is somehow
+ able to get the server into command mode. Once DISABLEd, ENABLE
+ can not be re-ENABLEd.
+
+ SET SERVER IDLE-TIMEOUT seconds
+ This was available previously in Kermit 95 only. Now it can be
+ used in C-Kermit also to specify a maximum number of seconds the
+ server is allowed to be idle before exiting server mode. 0
+ seconds means no idle timeout. In C-Kermit (but not K-95), SET
+ SERVER TIMEOUT and SET SERVER IDLE-TIMEOUT are mutually
+ exclusive -- you can have one or the other (or neither), but not
+ both. (Server timeouts are for the benefit of primitive Kermit
+ clients that are not capable of timing out on their own; to our
+ knowledge, no such clients are still in circulation.)
+
+ SET SERVER KEEPALIVE { ON, OFF }
+ (See next section).
+
+ 5.7. Timeouts during REMOTE HOST Command Execution
+
+ Prior to C-Kermit 7.0, the C-Kermit server would block waiting for
+ output from a system command invoked via REMOTE HOST from the client.
+ If the system command took a long time to execute, the client would
+ time out and send NAK packets. If the command took too long, the client
+ would reach its retry limit and give up. Even if it didn't, the NAKs
+ would cause unnecessary retransmissions.
+
+ In version 7.0, the C-Kermit server (VMS and select()-capable UNIX
+ versions only), sends "keepalive packets" (empty data packets) once per
+ second while waiting for the system command to complete. This procedure
+ should be entirely transparent to the Kermit client, and should prevent
+ the unwanted timeouts and NAKs. When C-Kermit 7.0 itself (or K95
+ 1.1.19) is the client, it prints dots to show the keepalive packets.
+
+ The keepalive feature can be turned off and on with:
+
+ SET SERVER KEEPALIVE { ON, OFF }
+
+ Normally it should be on. Turn it off it if causes trouble with the
+ client, or if it seems to slow down the server (as it might on some
+ platforms under certain circumstances).
+
+ 6. INTERNATIONAL CHARACTER SETS
+
+ Support for several new single-byte character sets was added in
+ C-Kermit 7.0. Unicode / ISO 10646 is not yet supported, but is a high
+ priority for forthcoming releases.
+
+ 6.0. ISO 8859-15 Latin Alphabet 9
+
+ To accommodate the Euro currency symbol, and to correct several other
+ longstanding problems with ISO Latin Alphabet 1, ISO 8859-15 Latin
+ Alphabet 9 was issued in May 1998. It is supported by C-Kermit 7.0 as a
+ transfer character set, a file character set, and a terminal character
+ set. Translations that preserve the new characters are available
+ between Latin-9 and several other sets including:
+
+ PC Code Page 858 (Western European languages, similar to CP850)
+ Windows Code Page 1252 (Western European languages, similar to Latin-1)
+ Windows Code Page 1250 (Eastern European languages, similar to Latin-2)
+
+ The Latin-9 transfer character set also allows for the OE digraph
+ character, used primarily in French, to be preserved in transfers
+ involving the DEC MCS or NeXT character sets.
+
+ The Euro character is also present in the Universal Character Set,
+ described in [542]Section 6.6.
+
+ 6.1. The HP-Roman8 Character Set
+
+ The HP-Roman8 character set is supported in C-Kermit 6.0 and later but
+ was omitted from Table VII-4 in the 2nd Edition of Using C-Kermit due
+ to lack of space. It is listed in [543]Appendix III.
+
+ 6.2. Greek Character Sets
+
+ Greek character sets were added in 6.1:
+
+ SET FILE CHARACTER-SET { CP869, ELOT927, GREEK-ISO }
+ SET TRANSFER CHARACTER-SET { GREEK-ISO }
+
+ GREEK-ISO is ISO 8859-7, which the same as ELOT 928.
+
+ The new Greek character sets are listed in [544]Appendix III.
+
+ 6.3. Additional Latin-2 Character Sets
+
+ The following have been added as FILE and TERMINAL CHARACTER-SETs:
+
+ MAZOVIA-PC
+ A PC code page used in Poland, equivalent to CP437, but with 18
+ substitutions needed for Polish.
+
+ CP1250
+ The Windows Latin 2 Code Page. Equivalent to ISO 8859-2, but
+ with different encoding.
+
+ 6.4. Additional Cyrillic Character Sets
+
+ The following have been added as FILE and TERMINAL CHARACTER-SETs:
+
+ BULGARIA-PC
+ This is the Cyrillic PC code page used in Bulgaria, where it is
+ called Code Page 856. It is attributed to a company called
+ DATEC, Inc, but CP856 is not a proper designation, since it
+ refers to a Hebrew Code Page (see the IBM Registry).
+
+ CP855
+ This PC Code Page contains all the Cyrillic letters that are
+ also in ISO 8859-5, and is therefore useful for non-Russian
+ Cyrillic text (Ukrainian, Belarusian, etc), unlike CP866, which
+ has a smaller repertoire of Cyrillic letters.
+
+ CP1251
+ The Windows Cyrillic Code Page. Equivalent to CP855, but with
+ different encoding.
+
+ KOI8R
+ An extension to "Old KOI-8" that adds upper and lower case
+ Cyrillic letter Io (looks like Roman E with diaeresis) plus a
+ selection of box-drawing characters to columns 8 through 11,
+ which are vacant in original Old KOI-8. KOI8-R is used for the
+ Russian language. It is specified in [545]RFC 1489.
+
+ KOI8U
+ A similar extension of Old KOI-8, but for Ukrainian. It is
+ specified in [546]RFC 2319.
+
+ 6.5. Automatic Character-Set Switching
+
+ Prior to version 7.0, C-Kermit's file character-set always had to be
+ set explicitly. In 7.0 and later, it is set automatically when:
+
+ 1. This feature is enabled (as it is unless you disable it).
+ 2. An incoming text-mode transfer includes a transfer-character-set
+ announcer and you have not previously given a SET FILE
+ CHARACTER-SET command. In this case, C-Kermit switches to an
+ appropriate file character set. For example, on an HP-UX
+ workstation, an incoming Latin-1 file automatically selects
+ HP-Roman8 for the local copy of the file; in Data General AOS/VS,
+ it would select DG International.
+ 3. You give a SET TRANSFER CHARACTER-SET command without having
+ previously specified a FILE CHARACTER-SET. An appropriate file
+ character-set is chosen automatically.
+
+ In addition, when you give a SET FILE CHARACTER-SET command, the
+ appropriate transfer character-set is automatically chosen, to be used
+ when you are sending files (but this does not override the one
+ announced by the sender when you are receiving files).
+
+ You might not agree about what is "appropriate", so of course you can
+ disable or change all of the above actions.
+
+ You can disable (or re-enable) the new automatic character-set
+ switching feature in each direction separately:
+
+ SET RECEIVE CHARACTER-SET-SELECTION { AUTOMATIC, MANUAL }
+ AUTOMATIC is the default, causing the behavior described above
+ when an incoming file arrives. Choose MANUAL to defeat this
+ behavior and force your current FILE CHARACTER-SET setting to be
+ used, no matter what it is. Note that SET RECEIVE CHARACTER-SET
+ MANUAL does not disable recognition of the incoming transfer
+ character-set announcer, and translation from the corresponding
+ character-set to your current file character-set. To disable
+ that, use SET ATTRIBUTE CHARACTER-SET OFF.
+
+ SET SEND CHARACTER-SET-SELECTION { AUTOMATIC, MANUAL }
+ Again AUTOMATIC is the default, causing the behavior described
+ above when you give a SET { FILE, TRANSFER } CHARACTER-SET
+ command. Use MANUAL to allow you to specify the transfer and
+ file character-sets independently.
+
+ SHOW CHARACTER-SETS
+ Tells settings of { SEND, RECEIVE } CHARACTER-SET-SELECTION.
+
+ Normally, however, it is more convenient to leave automatic switching
+ active, and change any associations that are not appropriate for your
+ application, area, or country. The commands are:
+
+ SHOW ASSOCIATIONS
+ This command lists all the associations in each direction: for
+ each possible transfer character-set, it lists the associated
+ file character-set, and vice versa. These are two separate and
+ independent lists.
+
+ ASSOCIATE TRANSFER-CHARACTER-SET name1 [ name2 ]
+ Changes the association for the transfer character-set name1 to
+ be the file character-set name2. If name2 is omitted, automatic
+ switching is disabled for this transfer character-set only.
+
+ ASSOCIATE FILE-CHARACTER-SET name1 [ name2 ]
+ Changes the association for the file character-set name1 to be
+ the transfer character-set name2. If name2 is omitted, automatic
+ switching is disabled for this file character-set only.
+
+ 6.6. UNICODE
+
+ C-Kermit 7.0 adds support for Unicode, the Universal Character Set,
+ for:
+
+ * File Transfer (SEND, RECEIVE, GET, etc)
+ * Terminal connection (CONNECT)
+ * Unguarded file capture (LOG SESSION)
+ * Unguarded file transmission (TRANSMIT)
+ * Local file character-set conversion (TRANSLATE)
+
+ C-Kermit is not, however, a "Unicode application" in the sense that its
+ commands, messages, or user interface are Unicode. Rather, it is
+ "Unicode aware" in its ability to handle and convert Unicode text in
+ the course of file transfer and terminal connection, and you can also
+ use Kermit to convert local files between Unicode and other character
+ sets. TLA's:
+
+ BMP - Base Multilingual Plane
+ BOM - Byte Order Mark
+ CJK - Chinese, Japanese, and Korean
+ ISO - International Standards Organization
+ TLA - Three-Letter Acronym
+ UCS - Universal Character Set
+ UTF - UCS Transformation Format
+
+ Unicode and ISO 10646 are the coordinated and compatible corporate and
+ international standards for the Universal Character Set (UCS). Unlike
+ single-byte and even most multibyte character sets, the UCS can
+ represent all characters in every existing writing system. A flat
+ plain-text file encoded in some form of UCS can contain any mixture of
+ English, Spanish, Italian, German, Hebrew, Arabic, Greek, Russian,
+ Armenian, Georgian, Japanese, Chinese, Korean, Vietnamese, Tibetan,
+ Hindi, Bengali, Tamil, Thai, Ethiopic, and so on, plus scientific and
+ mathematical notation, as well as texts in Runes, Ogham, Glagolitic,
+ and other historic scripts.
+
+ The UCS already covers these scripts and many more, but it's an
+ evolving standard with efforts underway to accommodate even more
+ languages and writing systems. Support is growing for native UCS use on
+ many platforms and in many applications. The goal of the framers of the
+ UCS is for it to replace ASCII, the ISO Latin Alphabets, ISCII, VISCII,
+ the Chinese, Japanese, and Korean (CJK) multibyte sets, etc, as well as
+ the many private character sets in use today, in other words to become
+ *the* Universal Character Set.
+
+ Until that time, however, conversions between existing sets and the UCS
+ will be necessary when moving text between platforms and applications.
+ Now Kermit can help.
+
+ 6.6.1. Overview of Unicode
+
+ For a more complete picture, please visit:
+
+ [547]http://www.unicode.org/
+
+ and access the various online introductions, FAQs, technical reports,
+ and other information. For greater depth, order the latest version of
+ the published Unicode Standard. The following overview contains a great
+ many oversimplifications and perhaps an opinion or two.
+
+ At present, the UCS is a 16-bit (2-byte) character set, but with
+ provisions to grow to a 4-byte set. UCS-2 refers to the two-byte set,
+ also called the Base Multilingual Plane (BMP), in which each character
+ has 16 bits, and therefore there are 2^16 = 65536 possible characters.
+ The first 128 characters are the same as US ASCII (C0 control
+ characters and DEL included), the next 32 are the C1 control characters
+ of ISO 6429, and the next 96 are the Right Half of ISO 8859-1 Latin
+ Alphabet 1. The remaining tens of thousands of characters are arranged
+ newly for the UCS, usually (but not always) in sections corresponding
+ to existing standards, such as ISO Latin/Cyrillic, often plus
+ additional characters not appearing in the existing standards due to
+ lack of space (or other reasons).
+
+ ISO 10646 allows for additional planes, e.g. for Egyptian hieroglyphics
+ or ancient (or other esoteric) CJK characters, but these planes are not
+ yet defined and so we will say nothing more about them here, except
+ that their use will require the 4-byte form of UCS, called UCS-4, in
+ some form (more about "forms" in [548]Section 6.6.2).
+
+ Unicode and ISO 10646 are constantly under revision, mainly to add new
+ characters. The Unicode revision is denoted by a version number, such
+ as 1.0, 1.1, 2.0, 3.0. The ISO 10646 standard revision is identified by
+ Edition (such as ISO 10646-1 1993), plus reference to any amendments.
+ The first versions of these standards included encodings for Korean
+ Hangul syllables (Jamos); these encodings were changed in version 1.1
+ of Unicode and by Amendment 5 to ISO 10646-1. The Unicode Technical
+ Committee and the ISO acknowledge that this was a bad thing to do, and
+ promise never change encodings or character names again, since this
+ poses serious problems for conformance and data interchange.
+
+ A UCS-2 value is customarily written like this:
+
+ U+xxxx
+
+ where "xxxx" represents four hexadecimal digits, 0-9 and A-F. For
+ example, U+0041 is "A", U+00C1 is A-acute, U+042F is uppercase Cyrillic
+ "Ya", U+FB4F is Hebrew Ligature Alef Lamed, and U+FFFD is the special
+ character that means "not a character".
+
+ Most characters from widely-used alphabetic writing systems such as the
+ West European ones, Cyrillic, Greek, Hebrew, Vietnamese, etc, are
+ available in "precomposed" form; for example Uppercase Latin Letter A
+ with Acute Accent is a single character (as it is in Latin-1). However,
+ the UCS also permits composition of a base character with one or more
+ nonspacing diacritics. This means the same character can be represented
+ in more than one way, which can present problems in many application
+ areas, including transfer and character-set conversion of text.
+
+ Conversion from ASCII or Latin-1 to UCS-2 text is "trivial": simply
+ insert a NUL (0) byte before each ASCII or Latin-1 byte. Converting in
+ the reverse direction (provided the UCS-2 file contains only U+0000 to
+ U+00FF) is equally simple (if we ignore the issue of composition):
+ remove every second (NUL) byte. Conversion of other character sets to
+ and from UCS, however, requires tables or algorithms specific to each
+ set. Nevertheless, the relatively transparent upwards compatibility
+ from ASCII and Latin-1, in which a very large share of the world's
+ textual data is encoded, gives the UCS an entree onto existing
+ platforms.
+
+ But the 2-byte format and the preponderance of NUL and other control
+ bytes in UCS-2 text pose problems for current applications and
+ transmission methods. And to make matters worse, different hardware
+ platforms store UCS-2 characters in different byte order. Thus a UCS-2
+ file transferred by FTP (or accessed via NFS, etc) between two
+ computers with different architecture might have its bytes in the wrong
+ order (or worse; see [549]Section 6.6.5.1 ).
+
+ 6.6.2. UCS Byte Order
+
+ Consider the number 1. In an 8-bit byte, this would be represented by
+ the following series of 0- and 1-bits:
+
+ +-----------------+
+ | 0 0 0 0 0 0 0 1 |
+ +-----------------+
+
+ Therefore in a 16-bit "word" the representation might be:
+
+ +-----------------+-----------------+
+ | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 1 |
+ +-----------------+-----------------+
+
+ Now consider the number 256, which is 2 to the 8th power. The binary
+ representation is 100000000 (1 followed by 8 zeros). 256 would go into
+ a 16-bit word like this:
+
+ +-----------------+-----------------+
+ | 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0 |
+ +-----------------+-----------------+
+
+ When a computer works this way, it is said to be Big Endian, meaning it
+ puts the most significant (biggest) byte first (on the "left") in a
+ 16-bit word, and the least significant byte second (on the right).
+
+ However, some other computers have the opposite arrangement, called
+ Little Endian, in which 1 is:
+
+ +-----------------+-----------------+
+ | 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0 |
+ +-----------------+-----------------+
+
+ and 256 is:
+
+ +-----------------+-----------------+
+ | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 1 |
+ +-----------------+-----------------+
+
+ Computers such as Sparc, MIPS, PA-RISC, and PowerPC are Big Endian,
+ whereas the PC and the Alpha are Little Endian. Endianness has never
+ been an issue with 7- or 8-bit characters, but it is with UCS
+ characters. It can be a tricky business to share or transfer a UCS-2
+ file between two different kinds of computers.
+
+ To alleviate (but not entirely solve) the problem, UCS-2 files are
+ supposed to begin with the Unicode character U+FEFF, Zero-Width
+ No-Break Space (ZWNBS). This is a kind of "no-op" (note: any such
+ assertion must normally be qualified with many "but ifs" and "excepts"
+ which are omitted here in the interest of brevity). If the bytes are
+ reversed the ZWNBS becomes U+FFFE, which is not (and never will be) a
+ defined UCS character. U+FEFF at the beginning of a UCS file is
+ therefore called a Byte Order Mark, or BOM.
+
+ Any application that creates a UCS-2 (or UTF-16, or UCS-4) file should
+ include a BOM, and any application that reads one should test for a
+ BOM, and if one is found, infer the byte order from it. This is a
+ convention, however -- not a standard or a requirement -- and
+ applications vary in their ability to handle BOMs and "backwards" UCS-2
+ files.
+
+ Note that a BOM is useful only at the beginning of a file. If you
+ append one UCS-2 file to another, and both have BOMs, the internal BOM
+ is no longer a BOM. And if the byte orders of the two files differ,
+ then either the first part or the second will be backwards. (Various
+ other undesirable effects might also occur, not discussed here.)
+
+ 6.6.2. UCS Transformation Formats
+
+ UCS textual data can be modified in various ways for transmission or
+ storage. Any officially sanctioned method of doing this is called a UCS
+ Transformation Format, or UTF. One such method, called UTF-16, is
+ essentially identical with UCS-2 except that it designates certain code
+ values as "escape sequences" (called surrogate pairs) to access
+ characters in other planes without having to use full UCS-4. We won't
+ discuss UTF-16 further here, since at the moment there are no other
+ planes. Several other UTF's (such as UTF-1, UTF-2, and UTF-7) have
+ fallen into disuse and are not discussed here. The most important
+ transformation format today is UTF-8.
+
+ UTF-8, so called because it "serializes" UCS-2 data into a stream of
+ 8-bit bytes, is designed to allow the UCS to work with present-day
+ communications gear, computers, and software. The most important
+ properties of UTF-8 are that byte order is constant (no byte swapping)
+ and all (7-bit) ASCII characters represent themselves. Therefore
+ conversion between ASCII and UTF-8 is no conversion at all, and
+ applications or platforms (such as Plan 9 from Bell Labs) that use
+ UTF-8 "for everything" can still run traditional ASCII-only
+ applications and be accessed from them. In particular, unlike UCS-2,
+ ASCII characters are not padded with NUL bytes. But also unlike UCS-2,
+ there is no transparency for Latin-1 or any other non-ASCII character
+ set. Every non-ASCII UCS-2 character is represented by a sequence of 2
+ or 3 UTF-8 bytes. Thus UTF-8 is more compact than UCS-2 for text
+ containing a preponderance of ABC's (or other ASCII characters), about
+ the same as UCS-2 for other alphabetic scripts (Cyrillic, Roman, Greek,
+ etc), and larger than UCS-2 for Chinese, Japanese, and Korean.
+
+ The UTF-8 uncoding of the UCS has been adopted by the Internet as the
+ preferred character set for new applications, and is gradually being
+ retrofitted into traditional applications like FTP ([550]RFC 2640).
+
+ 6.6.3. Conformance Levels
+
+ Although the Unicode and ISO 10646 standards both describe the same
+ character set, these standards differ in many ways, including their
+ stated requirements for conformance and their classification of
+ conformance levels.
+
+ Kermit has always abided by ISO character-set standards, including ISO
+ character-set designation and invocation methods. In adapting Unicode,
+ therefore, we had to choose from among the available ISO designations
+ which, in turn, correspond with ISO 10646 conformance levels. At
+ present, Kermit claims the lowest conformance level, 1, meaning
+ (roughly) that it does not handle combining forms and it does not
+ handle Korean Hangul Jamos (just as, at present, it does not handle
+ Korean in general). Note that ISO 10646 Conformance Levels 1 and 2
+ sidestep the issue of the code changes for Korean Hangul by announcing
+ non-support for Hangul regardless of encoding.
+
+ ISO 10646 Conformance Level 1 is approximately equivalent to Unicode
+ Normalization Form C (described in Unicode Technical Report 15,
+ incorporated into Unicode 3.0).
+
+ As noted in [551]Section 6.6.2, Kermit does not claim to support UTF-16
+ at the present time, hence the UCS-2 nomenclature. Kermit treats
+ surrogates just as if they were any other UCS-2 characters, rather than
+ as escapes to other planes, which means that (except when converting
+ between UCS-2 and UTF-8) they are translated to "error" characters,
+ since (a) no other planes are defined yet (and if they were, no other
+ character sets supported by Kermit would encode their characters), and
+ (b) no valid surrogate character corresponds to any other UCS-2
+ character.
+
+ A minor yet significant aspect of Unicode 3.0 and some recent
+ perturbation of ISO 10646-1 (probably Amendment 18, "Symbols and Other
+ Characters") is the addition of the Euro Sign at U+20AC. As noted in
+ [552]Section 6.0, Kermit's "Euro compliance" includes conversion
+ between Latin Alphabet 9 and various PC code pages. Text can also be
+ converted between UCS-2 or UTF-8 and any other Euro-compliant character
+ set (Latin-9, CP858, CP1250, CP1252) without loss of the Euro Sign.
+
+ 6.6.4. Relationship of Unicode with Kermit's Other Character Sets
+
+ Kermit's character sets are divided into two groups: single-byte sets
+ (such as Roman, Hebrew, Cyrillic, Greek) and multibyte (various
+ Japanese sets). The two groups are distinct since one normally would
+ not expect to convert Kanji ideograms to Roman (or other) letters, or
+ vice versa.
+
+ Unicode character-set conversion works with both groups, but obviously
+ the result depends on the repertoires of the source and destination
+ character-sets both including the characters in the file. For example,
+ you can translate a Hungarian text file between Latin-2 and Unicode,
+ but not between (say) Unicode and Latin/Greek. By the same token you
+ can convert Japanese text from Shift-JIS or EUC or JIS-7 to Unicode and
+ back, but you can't convert the same file to (say) Latin-1 if it
+ contains Japanese characters.
+
+ JIS-7 is equivalent to DEC Kanji and ISO-2022-JP except that the
+ latter two do not support halfwidth Katakana. Kermit treats all
+ three of these sets the same way, i.e. as JIS-7.
+
+ As noted, Kermit presently does not handle combining diacritics, and so
+ will not correctly convert UCS files that use them into a single-byte
+ character set. For example, if a UCS file contains Latin Capital Letter
+ A (U+0041) followed by Combining Acute Accent (U+0301), the result will
+ be a two-character sequence, A followed by another character. This is
+ what is meant by Conformance Level 1. (The situation grows worse with
+ multiple diacritics, since they can occur in any order.)
+
+ A higher level of conformance is possible, in which "canonical
+ equivalences" are handled via algorithms and databases, at some
+ (perhaps considerable) cost in performance, since a fair amount of
+ additional code must be executed for every character during data
+ transfer (database lookup, sorting of combining sequences into
+ canonical order, etc). This can be added in future releases if there is
+ a need (but in many cases, pre- and postpostprocessing might be a
+ better option).
+
+ Within these constraints, Kermit converts between the UCS and its other
+ character sets. For example, a mixture of Russian and English (and/or
+ Dutch, or Latin) text can bet converted between the UCS and ISO
+ Latin/Cyrillic or KOI-8. But since Kermit does not presently support
+ Arabic character-set conversion, the new availability of UCS conversion
+ does not mean that Kermit can convert from Arabic UCS text to some
+ other character set, because Kermit does not support any other
+ character set that includes Arabic. Ditto for Thai, Armenian, Georgian,
+ Tibetan, Chinese, Korean, etc. However, Kermit CAN convert Arabic (or
+ any other script) between UCS-2 and UTF-8.
+
+ Considering Cyrillic more carefully, note that the UCS also contains
+ numerous Cyrillic characters not found in any of the Cyrillic sets (ISO
+ Latin/Cyrillic, KOI8, CP866, etc) that Kermit supports; characters
+ needed for Abkhasian, Yakut, Tatar, Bashkir, Altaic, Old Church
+ Slavonic, etc; UCS text containing any of these historic or "extended"
+ Cyrillic characters can not be converted to any of Kermit's current
+ single-byte Cyrillic sets without loss. The situation is similar for
+ Greek, Hebrew, etc, and even worse for Japanese since Unicode contains
+ thousands of Kanjis that are lacking from the Japanese character sets
+ based on JIS X 0208, such as EUC-JP, JIS-7, and Shift-JIS.
+
+ In general, when converting from UCS to a single-byte set, there is
+ always the possibility of data loss, just as there is when converting
+ from any larger set to a smaller one. For example, if a UCS file
+ contains Devanagari characters, these characters will be lost when
+ converting to (say) Latin-1, just as Roman vowels with acute accents
+ are lost when converting from Latin-1 (an 8-bit set) to German ISO 646
+ (a 7-bit set).
+
+ 6.6.5. Kermit's Unicode Features
+
+ C-Kermit can convert between UCS-2 or UTF-8 and any of its other
+ character sets, and also between UCS-2 and UTF-8. When converting
+ between UCS-2 or UTF-8 and a non-Unicode character set (such as
+ Latin-1), the UCS Line Separator (LS, U+2028) and Paragraph Separator
+ (PS, U+2029) characters are converted to the appropriate line
+ terminator (CR, LF, or CRLF). When converting from a non-Unicode set to
+ UCS-2 or UTF-8, however, line terminators are not converted to LS or
+ PS. This is in accordance with the recommendations of Unicode Technical
+ Report #13.
+
+ When C-Kermit starts, it tests the native byte order of the computer.
+ You can see the result in the SHOW FEATURES or SHOW FILE display. It's
+ also available in the variable \v(byteorder): 0 means Big Endian, 1
+ means Little Endian.
+
+ When UCS-2 is involved in file transfer or translation, the following
+ commands tell C-Kermit what to do about byte order:
+
+ SET FILE UCS BYTE-ORDER { BIG-ENDIAN, LITTLE-ENDIAN }
+ This is for reading UCS-2 files that don't have a BOM, and also
+ for writing UCS-2 files. If this command is not given, the
+ machine's native byte order is used when writing UCS-2 files,
+ and also when reading UCS-2 files that don't have a BOM.
+
+ SET FILE UCS BOM { ON, OFF }
+ This setting is used when creating UCS-2 files. A BOM is added
+ at the beginning by default. Use OFF to not add the BOM. This
+ command has no affect when writing files.
+
+ COPY /SWAP-BYTES sourcefile destinationfile
+ Use this for fixing a UCS-2 file whose bytes are in the wrong
+ order.
+
+ Use SHOW FILE to display the FILE UCS settings.
+
+ Please note, again, that C-Kermit's user interface, including its
+ script language, is not internationalized in any way. String
+ comparisons, case conversion, and so on, work only for US ASCII
+ (comparisons for equality work with other sets, but not
+ lexically-greater-or-less-than or caseless comparisons; even
+ comparisons for equality can fail when composed characters or byte
+ order are involved). String functions such as \findex() and
+ \fsubstring() that reference byte positions do just that; they won't
+ work with UTF-8 text that contains any non-ASCII characters, and they
+ will not work with UCS-2 text at all since they use C strings
+ internally, which are NUL-terminated. These are just a few examples to
+ illustrate that neither Unicode nor any other character-set beyond
+ ASCII is supported at the user-interface, command, or scripting level
+ in this version of C-Kermit.
+
+ 6.6.5.1. File Transfer
+
+ Kermit supports both UCS-2 and UTF-8 as file and transfer character
+ sets in text-mode file transfer.
+
+ To select UCS-2 or UTF-8 as a file character-set, use:
+
+ SET FILE CHARACTER-SET { UCS2, UTF8 }
+
+ If you want to send a UCS-2 text file (or save an incoming file in
+ UCS-2 format), tell Kermit to:
+
+ SET FILE CHARACTER-SET UCS2
+
+ and if you want to send a UTF-8 text file (or store an incoming file in
+ UTF-8 format), tell Kermit to:
+
+ SET FILE CHARACTER-SET UTF8
+
+ When sending UCS-2 files, Kermit determines the byte order from the
+ BOM, if there is one (and if there is a BOM, it is stripped, i.e. not
+ sent). If there is no BOM, the byte order is the one specified in the
+ most recent SET FILE UCS BYTE-ORDER command, if any, otherwise the
+ computer's native byte order is assumed. When storing incoming files as
+ UCS-2, the byte order is according SET FILE UCS BYTE-ORDER, if given,
+ otherwise the native one; a BOM is written according to SET FILE UCS
+ BOM.
+
+ A transfer character-set should be chosen that includes all of the
+ characters in the source file. So, for example, if you are sending a
+ UCS-2 file containing only German-language text, your transfer
+ character-set can be Latin-1, Latin-2, Latin-9, UCS-2, or UTF-8. But if
+ you are sending a file that contains a combination of Hebrew and Greek,
+ your transfer character-set must be UCS-2 or UTF-8 if you don't want to
+ lose one script or the other. Furthermore, the transfer character-set
+ must be one that is supported by the receiving Kermit program. Since
+ UCS support is new, it is possible that the other Kermit program (if it
+ supports character sets at all) does not support it, but does support
+ single-byte sets such as Latin-1, Latin/Cyrillic, etc.
+
+ To select UCS-2 or UTF-8 as a transfer character-set, use:
+
+ SET TRANSFER CHARACTER-SET { UCS2, UTF8 }
+
+ It is up to the receiving Kermit program to convert the transfer format
+ to its own local format, if necessary. If it does not understand the
+ UTF-8 or UCS-2 transfer character-set, and your file can not be
+ adequately represented by any single-byte transfer character-set (such
+ as Latin-1 or Latin/Cyrillic) then, if UTF-8 format is acceptable on
+ the receiving computer, use UTF-8 as the transfer character-set, with
+ the receiver told to "set unknown-char keep", or with the sender told
+ to "set attribute char off". If you want the file to be stored in UCS-2
+ format at the receiver, send it it binary mode if the source file is
+ also UCS-2, or else use the TRANSLATE command (next section) to convert
+ it to UCS-2 first, then send it in binary mode. You should not use
+ UCS-2 as a transfer character-set in text-mode transfers to Kermit
+ programs that don't support it, because they are likely to corrupt the
+ result the same way FTP would (see the final paragraph of this
+ section).
+
+ When UCS-2 is the transfer character set, it always goes into Kermit
+ packets in Big Endian format, with no BOM. As always, the transfer
+ character-set is announced by the sender to the receiver. The
+ announcement for UCS-2 is "I162" (ISO Registration 162 = UCS-2 Level 1)
+ and by definition it is Big Endian (the standards say that when UCS-2
+ is serialized into bytes, the order must be Big Endian). The
+ announcement for UTF-8 is "I190" (UTF-8 Level 1).
+
+ When receiving a file whose transfer character-set is UCS-2 or UTF-8,
+ you must choose the appropriate file character set for the result.
+ There is no way Kermit can do this for you automatically, since UCS
+ data can be in any script at all, or any combination.
+
+ In general, UTF-8 or UCS-2 should be chosen as a transfer character-set
+ if the source file is also encoded in some form of UCS and it contains
+ more than one script. But there are other situations where where UTF-8
+ or UCS-2 offer advantages. For example, suppose the source file is on a
+ NeXTstation and the destination file is on VMS. Both the NeXT and the
+ DEC Multinational character sets include the French OE digraph, but
+ Latin-1 does not. Therefore French words containing this character
+ might not arrive intact when Latin-1 is the transfer character-set, but
+ will with UTF-8 or UCS-2, since the UCS includes the OE digraph (but so
+ does Latin-9).
+
+ UCS-2 should be chosen as a transfer character-set only for Japanese
+ text files that contain a large preponderance of Kanji, since in this
+ case (and only this case) UCS-2 (two bytes per Kanji) is more efficient
+ than UTF-8 (three bytes per Kanji). The same will be true for Chinese
+ and Korean when they are supported by Kermit. UCS-2 should never be
+ used as a transfer character-set with a transfer partner that does not
+ support UCS-2 since this can cause file corruption (see last paragraph
+ in this section).
+
+ Note that Kermit's repeat-count compression is 100% ineffective for
+ UCS-2, and is also ineffective for multibyte characters in UTF-8 and
+ EUC-JP; this is because repeat-compression is a transport-level
+ mechanism that operates on a per-byte basis; it has no knowledge of the
+ distinction between a byte and a character.
+
+ When C-Kermit starts, it sets up associations ([553]Section 6.5) for
+ incoming files whose transfer character sets are UCS-2 or UTF-8
+ appropriately for the platform so that the file character-set for the
+ incoming file is UCS-2 in Windows and UTF-8 elsewhere. Otherwise,
+ C-Kermit does not make any default associations for UCS-2 or UTF-8, but
+ of course you may add or change associations to suit your needs and
+ preferences by including the appropriate ASSOCIATE commands in your
+ Kermit startup file. For example, if you are a PC user and deal only
+ with text written in Greek and English, you can:
+
+ ASSOCIATE TRANSFER-CHARACTER-SET UTF8 CP869
+ ASSOCIATE TRANSFER-CHARACTER-SET UCS2 CP869
+ ASSOCIATE FILE-CHARACTER-SET CP869 UTF8
+
+ Note that when file transfer involves conversion between a single-byte
+ character set and UCS-2 or UTF-8, the file-transfer thermometer and
+ estimated time left might be inaccurate, since they are based on the
+ source file size, not the transfer encoding. This is purely a cosmetic
+ issue and does not effect the final result. (And is not, strictly
+ speaking, a bug; Kermit protocol presently includes no method for the
+ sender to furnish an "estimated transfer size" to the receiver, and in
+ any case any such guess could be as far off as the file size, given the
+ many other factors that come into play, such as compression and
+ prefixing).
+
+ A caution about FTP and UCS-2. As noted previously, if you transfer a
+ UCS-2 file with FTP in binary mode between two computers with opposite
+ Endianness, the result will have its bytes in the wrong order. However,
+ if you use FTP to transfer a UCS-2 file in "ascii" (text) mode to ANY
+ computer, even if it is identical to yours, the result will be
+ corrupted because FTP's line-terminator conversions do not account for
+ UCS-2. The same holds when sending from a UCS-aware Kermit program to
+ an older Kermit program in text mode with a transfer character-set of
+ UCS-2. So use UCS-2 as a transfer character-set ONLY with a UCS-2-aware
+ Kermit partner.
+
+ 6.6.5.2. The TRANSLATE Command
+
+ In Kermit versions that have Unicode support included, TRANSLATE now
+ always goes through Unicode; that is, the source set is converted to
+ UCS-2 and thence to the target set. This is a major improvement, since
+ in prior releases, C-Kermit had to pick the "most appropriate" transfer
+ character-set as the intermediate set, and this would result in the
+ loss of any characters that the source and target sets had in common
+ but were lacking from the intermediate set (for example the OE digraph
+ when translating from NeXT to DEC MCS through Latin-1). This never
+ happens when Unicode is the intermediate set because Unicode is a
+ superset of all other character sets supported by Kermit. A more
+ dramatic example would be translation between Cyrillic PC code page 866
+ and KOI8-R ([554]Section 6.4); formerly all the line- and box-drawing
+ characters would be lost (since ISO 8859-5 does not have any); now the
+ ones that these two sets have in common are preserved.
+
+ UCS-2 and UTF-8 are now both supported as source-file and
+ destination-file character sets by C-Kermit's TRANSLATE command, for
+ example:
+
+ translate oofa.txt ucs2 latin1 oofa-l1.txt
+
+ translates oofa.txt from UCS-2 to Latin-1, storing the result as
+ oofa-l1.txt. Similarly:
+
+ translate oofa.txt utf8 latin1 oofa-l1.txt
+ translate oofa.txt latin1 ucs2 oofa-ucs2.txt
+ translate oofa.txt latin1 utf8 oofa-utf8.txt
+ translate oofa.txt ucs2 utf8 oofa-utf8.txt
+ translate oofa.txt utf8 ucs2 oofa-ucs2.txt
+
+ Treatment of the UCS-2 BOM is exactly the same as for file transfer.
+ Note that if a UCS-2 source file is in the "wrong" byte order and lacks
+ a BOM, and you don't tell Kermit about it with SET FILE UCS BYTE-ORDER,
+ the result of the translation is total gibberish. Recall that you can
+ use COPY /SWAP-BYTES to switch the byte order of an errant UCS-2 file
+ (or any other file for that matter, if you can think of a reason to).
+ Also note that:
+
+ translate oofa.txt ucs2 ucs2 new.txt
+
+ Produces a result in the native (or SET FILE UCS) byte-order as long as
+ oofa.txt has a BOM.
+
+ As a side benefit of the Unicode work, the TRANSLATE command now works
+ for the first time also for all Japanese character sets that Kermit
+ supports. In other words, if you have a Japanese text file in any of
+ the following encodings:
+
+ EUC-JP
+ Shift-JIS
+ JIS-7
+ UCS-2
+ UTF-8
+
+ You can use the TRANSLATE command to convert to any other encoding from
+ the same list.
+
+ 6.6.5.3. Terminal Connection
+
+ The CONNECT command now allows UTF-8 as a local or remote terminal
+ character-set:
+
+ SET TERMINAL CHARACTER-SET { ..., UTF8 } { ..., UTF8 }
+ SET TERMINAL REMOTE-CHARACTER-SET { ..., UTF8 }
+ SET TERMINAL LOCAL-CHARACTER-SET { ..., UTF8 }
+
+ (Recall that Kermit's terminal character-set has two "ends" -- the set
+ used on the host to which Kermit is connected, and the set used on the
+ local keyboard and screen.)
+
+ UCS-2 is not supported as a terminal character-set (either end) since
+ (a) it is not used that way anywhere to our knowledge, and (b) the
+ problems of Endianness and the high likelihood of loss of
+ synchronization make it impractical. (Telecommunications is
+ byte-oriented; if one byte, or any odd number of bytes, is lost because
+ of buffer overruns, circuit resets, etc (or likewise if a burst of
+ noise appears that takes the guise of an odd number of bytes), the byte
+ order of the subsequent data stream will be backwards; unlike UTF-8 and
+ traditional byte-based character sets, UCS-2 is not "self
+ synchronizing".)
+
+ UTF-8 does not have byte-order or synchronization problems and is
+ growing in popularity as a terminal character set as well as in other
+ application areas. It allows a single terminal session to use multiple
+ scripts (Roman, Cyrillic, Greek, etc) without ISO 2022 character-set
+ switching (which terminal emulators like Kermit 95 can handle but few
+ host applications understand or use), and meshes nicely with the
+ Unicode screen fonts that are beginning to appear.
+
+ UTF-8 was first used in Plan 9 and soon will be available in Linux. It
+ will probably spread from there (Unicode in some form is, of course,
+ also used in Windows NT, but only internally -- not for access from
+ outside).
+
+ To use UTF-8 or any other character set that uses 8-bit bytes in your
+ terminal session, be sure to tell C-Kermit to:
+
+ SET TERMINAL BYTESIZE 8
+ SET COMMAND BYTESIZE 8
+ SET PARITY NONE
+
+ (or use the shortcut command, EIGHTBIT, which does all three at once).
+
+ In a setup where your local Kermit program uses a single-byte character
+ set such as PC Code Page 850 and the remote host uses UTF-8:
+
+ SET TERM CHAR UTF8 CP850
+
+ or:
+
+ SET TERM REMOTE CHAR UTF8
+ SET TERM LOCAL CHAR CP850
+
+ all works as expected. UTF-8 text on the remote displays correctly on
+ your screen, and when you type CP850 characters, they are translated to
+ UTF-8 sequences for transmission, and the echo from the host is
+ translated from UTF-8 back to CP850. Telnet negotiations and
+ autodownload take place before any character-set translation and work
+ as before. The session log (if text mode was selected for it) contains
+ only the local terminal character-set. And so on.
+
+ Kermit merely supplies translations from UTF-8 to your local terminal
+ character-set (this includes treating UTF-8 Line Separator and
+ Paragraph separator as CRLF). However, Kermit does does not, at
+ present, perform "canonicalization" of composed sequences, nor does it
+ automatically execute bidirectionality algorithms for display of
+ mixed-direction text (e.g. Hebrew and English). Such presentation
+ issues, like all others in the terminal-host regime, are left to the
+ host.
+
+ By the way, C-Kermit also allows UTF-8 to be the local end of the
+ terminal character-set, but so far this code is not tested, since we
+ don't have a UTF-8 console or terminal to work with. However, it can be
+ stated without doubt that C-Kermit's key mapping will not work for
+ UTF-8 values, since (a) the key map is indexed by 8-bit byte values and
+ (b) C-Kermit reads keystrokes a byte at a time (these comments do not
+ apply to K95, which has direct access to the keyboard and can read
+ "wide" keycodes and uses them to index a "wide" keymap).
+
+ Restrictions: As noted, the CONNECT command does not support UCS-2 as a
+ REMOTE TERMINAL character-set. Neither does it support the Japanese
+ sets EUC-JP, JIS-7, and Shift-JIS. Support for the Japanese sets (and
+ possibly Chinese and Korean too) might be added in a future release.
+ Since the TRANSMIT command (next section) uses the same REMOTE TERMINAL
+ character-sets as the CONNECT command, it has the same restrictions.
+
+ 6.6.5.4. The TRANSMIT Command
+
+ As described in Chapter 15 of [555]Using C-Kermit and [556]Section 4.21
+ of this document, the TRANSMIT command can be used to upload a file
+ without protocol, more or less as if you were typing it on your
+ keyboard while connected to the host. When TRANSMITting in text mode,
+ the file's character set is converted to the host's unless you have SET
+ TERMINAL CHARACTER-SET TRANSPARENT, or you include the new TRANSMIT
+ switch, /TRANSPARENT.
+
+ Before C-Kermit 7.0, the file character-set was assumed to be the same
+ as the local end of the terminal character-set, and the TRANSMIT
+ command used the same translations as the CONNECT command, ignoring the
+ file character-set.
+
+ In C-Kermit 7.0, that assumption (a poor one to begin with) can no
+ longer be made, since UCS-2 can be a file character-set but not a
+ terminal character-set. So now the file's character-set is given by
+ your most recent SET FILE CHARACTER-SET command. The host's character
+ set is the remote end of your most recent SET TERMINAL CHARACTER-SET
+ command:
+
+ SET TERMINAL CHARACTER-SET remote-set [ local-set ]
+
+ or:
+
+ SET TERMINAL REMOTE-CHARACTER-SET remote-set
+
+ The TRANSMIT command converts each source-file character from the FILE
+ character-set to the REMOTE TERMINAL character-set, and then transmits
+ the translated characters according to your SET TRANSMIT preferences
+ (Chapter 15).
+
+ If you have SET TRANSMIT ECHO ON, and the host is echoing the
+ transmitted characters, the echos are converted from the remote
+ terminal character-set to the local terminal character-set.
+
+ [ A picture would help... ]
+
+ Confused? Let's work through an example. Suppose your local computer is
+ a NeXTstation, on which text files are encoded in the NeXT character
+ set, and that the remote computer is a Data General AViiON, which uses
+ the Data General International character set. Further suppose that you
+ are logged in to the NeXT from a VT220 terminal which uses the DEC
+ Multinational character set.
+
+ You need to convert the file from NeXT encoding to DG encoding and
+ convert the echoes from DG encoding to DEC encoding. So on the NeXT,
+ tell C-Kermit to:
+
+ eightbit
+ set file character-set next
+ set term character-set dg-international dec-mcs
+ transmit /text nextdata.txt
+
+ (This assumes you have some sort of collection process already set up
+ on the Data General, such as a text editor or the venerable "cat >
+ foo". The EIGHTBIT command is equivalent to SET TERMINAL BYTESIZE 8,
+ SET COMMAND BYTESIZE 8, SET PARITY NONE.)
+
+ To further complicate matters, suppose your local terminal character
+ set is the same as the remote one, so you don't need terminal
+ character-set translation, but you need to TRANSMIT a file that is in a
+ different character set and you want it translated to the host set. In
+ this case, use SET TERM CHARACTER-SET to actually specify the character
+ set used on each end, rather than specifying TRANSPARENT:
+
+ eightbit
+ set file character-set ucs2
+ set term character-set latin1 latin1
+ transmit /text ucs2data.txt
+
+ The distinction between:
+
+ SET TERMINAL CHARACTER-SET xxx yyy
+
+ (where xxx and yyy are the same set) and:
+
+ SET TERMINAL CHARACTER-SET TRANSPARENT
+
+ is new to C-Kermit 7.0, but affects only the TRANSMIT command.
+
+ The TRANSMIT command currently does nothing special with UCS-2/UTF-8
+ Line and Paragraph Separator characters; more experience is required to
+ find out how these behave in a genuine Unicode terminal-host setting.
+
+ Restrictions: As noted, the TRANSMIT command translates from the FILE
+ character-set to the REMOTE TERMINAL character-set. This rules out
+ translations to any character set that is not supported as a REMOTE
+ TERMINAL character-set, such as UCS-2, EUC-JP, JIS-7, and Shift-JIS.
+
+ 6.6.5.5. Summary of Kermit Unicode Commands
+
+ Specifying file character-set and byte order:
+ SET FILE CHARACTER-SET { ..., UCS2, UTF8 }
+ REMOTE SET FILE CHARACTER-SET { ..., UCS2, UTF8 } (See next
+ section)
+ SET FILE UCS BOM { ON, OFF }
+ SET FILE UCS BYTE-ORDER { BIG-ENDIAN, LITTLE-ENDIAN }
+
+ Specifying the transfer character-set:
+ SET TRANSFER CHARACTER-SET { ..., UCS-2, UTF-8 }
+ REMOTE SET TRANSFER CHARACTER-SET { ..., UCS-2, UTF-8 }
+
+ Specifying the terminal character-set:
+ SET TERMINAL CHARACTER-SET { ..., UTF8 } { ..., UTF8 }
+ SET TERMINAL REMOTE-CHARACTER-SET { ..., UTF8 }
+ SET TERMINAL LOCAL-CHARACTER-SET { ..., UTF8 }
+
+ Displaying settings:
+ SHOW FILE
+ SHOW TRANSFER
+ SHOW TERMINAL
+ SHOW CHARACTER-SETS
+
+ Commands that use these settings include:
+ SEND, RECEIVE, GET, etc.
+ CONNECT
+ TRANSMIT
+ LOG SESSION
+
+ Converting files:
+ TRANSLATE infile { ..., UCS-2, UTF-8 } { ..., UCS-2, UTF-8 }
+ outfile
+ COPY /SWAP-BYTES infile outfile
+
+ 6.7. Client/Server Character-Set Switching
+
+ A simple mechanism has been added to allow the client to change the
+ server's FILE CHARACTER-SET:
+
+ REMOTE SET FILE CHARACTER-SET name
+ The client asks the server to change its file character-set to
+ the one given. The name must match one of the server's file
+ character-set names. For convenience, C-Kermit uses its own file
+ character-set keyword list for parsing this command so you can
+ use ? for help and Tab or Esc for completion. However, since the
+ server might have a different repertoire (or even use different
+ names for the same sets), C-Kermit accepts any string you supply
+ and sends it to the server. The server, if it supports this
+ command (C-Kermit 7.0 and K95 1.1.19 do), sets its file
+ character-set as requested, and also disables automatic
+ character-set switching ([557]Section 6.5). If the server does
+ not support this command or if it does not support the given
+ character set, the REMOTE SET FILE CHARACTER-SET command fails.
+
+ Here's an example that sends a Japanese text file encoded in Shift-JIS
+ to a server using every combination of Kermit's Japanese-capable file
+ and transfer character sets:
+
+ dcl \&x[] = euc ucs2 utf8 ; transfer character-sets
+ dcl \&y[] = eu uc ut ; 2-letter abbreviations for them
+ dcl \&f[] = shift euc jis7 ucs2 utf8 ; file character-sets
+ dcl \&g[] = sj eu j7 uc ut ; 2-letter abbreviations
+
+ set file char shift-jis ; local file character-set is Shift-JIS
+ for \%i 1 \fdim(&x) 1 { ; for each transfer character-set...
+ set xfer char \&x[\%i] ; set it
+ for \%j 1 \fdim(&f) 1 { ; for each remote file character-set...
+ remote set file char \&f[\%j] ; set it
+ if fail exit 1 SERVER REJECTED CHARSET
+ send /text meibo-sj.html meibo-sj-\&y[\%i]-\&g[\%j].txt ; send the fil
+e
+ if fail exit 1 TRANSFER FAILED
+ }
+ }
+
+ The Kermit-370 server does not support REMOTE SET FILE CHARACTER-SET,
+ but since it supports REMOTE KERMIT commands, you can get the same
+ effect with REMOTE KERMIT SET FILE CHARACTER-SET name.
+
+ 7. SCRIPT PROGRAMMING
+
+ (Also see [558]Section 2.8, Scripting Local Programs.)
+
+ 7.0. Bug Fixes
+
+ The following script programming bugs were fixed in C-Kermit 7.0:
+
+ * IF EXIST and IF DIRECTORY were fixed to properly strip braces from
+ around their arguments, so "if directory {C:\Program Files}", etc,
+ would work as expected. However, this means that if the file or
+ directory name is actually enclosed in braces, the braces must be
+ doubled.
+ * The READ command did not fail if the READ file wasn't open; now it
+ does.
+ * The READ command refused to read the last or only line of a file if
+ it did not end with a proper line terminator; now it does.
+ * The END command, when given from within a SWITCH statement, did not
+ exit from the current macro or command file; instead it just
+ terminated the SWITCH.
+
+ 7.1. The INPUT Command
+
+ 7.1.1. INPUT Timeouts
+
+ The description of the INPUT command on page 422 fails to mention the
+ following two points about the timeout (which apply to C-Kermit 6.0 and
+ later):
+
+ 1. "INPUT -1 text" (or "INPUT \%x text", where \%x is any variable
+ whose value is -1 or less) means "wait forever". This form of the
+ INPUT command fails only if it is interrupted, since it will never
+ time out.
+ 2. INPUT 0 performs a nonblocking read of material that has already
+ arrived but has not yet been read, and succeeds immediately if the
+ target string is found, or fails immediately if it is not found.
+
+ The same points apply to MINPUT. REINPUT ignores its timeout parameter.
+
+ 7.1.2. New INPUT Controls
+
+ The following new INPUT controls were added in version 7.0:
+
+ SET INPUT AUTODOWNLOAD { ON, OFF }
+ Explained in [559]Section 7.7.
+
+ SET INPUT CANCELLATION { ON, OFF }
+ This governs whether an INPUT command can be canceled by
+ "pressing any key" on the keyboard. Normally it can be, in which
+ case the INPUT command fails immediately and \v(instatus) is set
+ to 2, indicating interruption. SET INPUT CANCELLATION OFF
+ disables keyboard cancellations; thus if the search text is not
+ encountered, the INPUT command will run for its entire timeout
+ interval. SET INPUT CANCELLATION OFF does not disable
+ interruption by Ctrl-C, however; every command needs an
+ emergency exit. (If you really want to disable interruption by
+ Ctrl-C, use SET COMMAND INTERRUPTION OFF.)
+
+ Also see [560]Section 7.2 for any new variables related to INPUT.
+
+ 7.1.3. INPUT with Pattern Matching
+
+ C-Kermit 7.0 allows INPUT, MINPUT, and REINPUT targets to be a pattern
+ (explained in [561]Sections 1.19 and [562]4.9). This solves a
+ long-standing problem illustrated by the following scenario: a certain
+ company has a bank of TCP/IP modem servers, with hostnames server1,
+ server2, server3, and so on. Each server's prompt is its name, followed
+ by a colon (:), for example "Server72:". Without INPUT patterns, it
+ would be rather difficult to wait for the prompt. The brute force
+ approach:
+
+ minput 20 Server1: Server2: Server3: ... (enumerating each one)
+
+ is subject to failure whenever a new server is added. A more subtle
+ approach:
+
+ input 20 Server
+ if fail ...
+ input 2 :
+
+ is liable to false positives, e.g. "Welcome to the XYZ Corp Modem
+ Server. Please read the following message:"...
+
+ With patterns, you can match the prompt with "Server*:" (which doesn't
+ solve the "false positives" problem, but certainly is more compact than
+ the brute force method), or with more specific patterns such as
+ "Server[1-9]:" and "Server[1-9][0-9]:", or equivalently:
+
+ Server{[1-9],[1-9][0-9]}:
+
+ meaning the word "Server" followed by a single digit (1-9) or by two
+ digits representing a number from 1 to 99, followed by a colon.
+
+ INPUT pattern matching has been added in a way that does not interfere
+ with existing scripts. No new commands or switches are used. The simple
+ rule is: if an INPUT search target is the argument of the (new)
+ \fpattern() function, it is a pattern. Otherwise it is taken literally,
+ as before. For example:
+
+ input 5 a*b
+
+ searches for an 'a' followed by an asterisk ('*'), followed by a 'b'.
+ But:
+
+ input 5 \fpattern(a*b)
+
+ searches for an 'a' followed by anything at all up to and including the
+ first 'b'. This means that any search target to INPUT, MINPUT, or
+ REINPUT can be a pattern or a literal string, and in particular that
+ MINPUT can accommodate any mixture of patterns and literal strings.
+
+ In selecting patterns, note that:
+
+ * A leading '*' is always implied so there is no need to include one.
+ * A trailing '*' is meaningless and ignored.
+ * A '*' by itself matches the first character that arrives.
+
+ A syntax note: If your pattern is a selection list, meaning a list of
+ alternatives separated by commas and enclosed in braces, then the outer
+ braces will be stripped by various levels of parsers, so you must
+ include three of each:
+
+ input 10 \fpattern({{{abc,mno,xyz}}})
+
+ Note that this is equivalent to:
+
+ minput 10 abc mno xyz
+
+ except for the setting of the \v(minput) variable.
+
+ And a caution: INPUT pattern matching has a limitation that you
+ probably never noticed with literal-string matching, namely that there
+ is a limit on the size of the match. For example, if the pattern is
+ "a*b", the match will succeed if the 'a' and 'b' are not separated by
+ more than (say) 8K bytes, but will fail if they are farther apart than
+ that. In such cases, it better to use two INPUTs (e.g. "input 10 a" and
+ then "input 100 b").
+
+ 7.1.4. The INPUT Match Result
+
+ The result of any INPUT, MINPUT, or REINPUT command, no matter whether
+ the search targets are patterns or literal strings, is available in the
+ new \v(inmatch) variable. For example:
+
+ minput 10 cat \fpattern([dh]og)
+ if success echo MINPUT matched "\v(inmatch)"
+
+ This is especially useful when a pattern was matched, since it makes
+ the string that matched the pattern available to Kermit; there would be
+ no way to get it otherwise.
+
+ After an INPUT command, you can view all the INPUT-related variables by
+ typing "show variables in" (abbreviate as "sho var in"), which shows
+ the values of all built-in variables whose names start with "in".
+
+ 7.2. New or Improved Built-In Variables
+
+ \v(blockcheck)
+ Current BLOCK-CHECK setting, 1, 2, 3, or 4. 4 is the code for
+ BLANK-FREE-2.
+
+ \v(byteorder)
+ The machine's byte order: 0 = Big Endian, 1 = Little Endian.
+
+ \v(cmdbufsize)
+ The length of the command buffer, which is the maximum size for
+ a macro, a command, a variable, or anything else in C-Kermit's
+ script language.
+
+ \v(ctty)
+ The device name of C-Kermit's controlling (login) terminal.
+
+ \v(filename)
+ Described in [563]Sections 4.1 and [564]4.2.
+
+ \v(filenumber)
+ Described in [565]Sections 4.1 and [566]4.2.
+
+ \v(filespec)
+ As of C-Kermit 7.0, contains fully qualified filenames rather
+ than (usually) relative ones.
+
+ \v(return)
+ Now holds the END n value of the macro that most recently
+ returned, in case END was used rather than RETURN.
+
+ \v(editor)
+ Pathname of preferred text editor
+
+ \v(editopts)
+ Command-line options for editor
+
+ \v(editfile)
+ File most recently edited
+
+ \v(browser)
+ Pathname of preferred Web browser
+
+ \v(browsopts)
+ Command-line options for Web browser
+
+ \v(browsurl)
+ URL most recently given to Web browser
+
+ \v(dialtype)
+ Type of call most recently placed (see [567]Section 2.1.11).
+
+ \v(kbchar)
+ The character, if any, that was typed at the keyboard to to
+ interrupt the most recent PAUSE, SLEEP, WAIT, MSLEEP, or INPUT
+ command; empty if the most recent such command was not
+ interrupted from the keyboard.
+
+ \v(lockdir)
+ UNIX only - The name of the UUCP lockfile directory, if known,
+ otherwise "(unknown)".
+
+ \v(lockpid)
+ UNIX only - PID of process that owns the communication port that
+ you tried to open with a SET LINE command that failed because
+ the port was in use, otherwise empty. This variable is set with
+ every SET LINE command.
+
+ \v(cx_time)
+ If no connection (SET HOST, SET LINE, DIAL, TELNET, etc) is
+ active, this is 0. If a connection is active, this is the number
+ of seconds since the connection was made.
+
+ \v(hwparity)
+ If hardware parity is in effect, this variable gives its value,
+ such as "even" or "odd" (in which case, the \v(parity) variable
+ will be "none"). Otherwise this variable is empty.
+
+ \v(serial)
+ Current serial port settings in 8N1 format ([568]Section 2.10).
+
+ \v(errno)
+ In UNIX, the current value of the C runtime errno variable,
+ which is quite volatile (meaning that often an "interesting"
+ error code can be overwritten by some other library call or
+ system service that sets errno before you have a chance to look
+ at it). In VMS, the error code returned by the system or library
+ call that most recently failed (success codes are not saved).
+ Not available in other operating systems.
+
+ \v(errstring)
+ The UNIX or VMS system error message that corresponds to
+ \v(errno). Not available in all OS's. Also see
+ [569]\ferrstring().
+
+ \v(setlinemsg)
+ The error message, if any, from the most recent SET LINE, SET
+ PORT, SET HOST, TELNET, or other connection-making command. This
+ is not necessarily the same as \v(errstring) since these
+ commands might fail without generating a system error code, for
+ example (in UNIX) because a lockfile existed indicating the
+ device was assigned by another user.
+
+ \v(exitstatus)
+ The exit status C-Kermit would return if it exited now.
+
+ \v(pexitstat)
+ The exit status of the inferior process most recently invoked by
+ C-Kermit (by RUN, !, REDIRECT, SEND /COMMAND, etc). In VMS, this
+ code can be given to \ferrstring() to get the corresponding
+ error message (in UNIX, program/command return codes are not the
+ same as system error codes). Not available in operating systems
+ other than UNIX and VMS. See [570]Section 4.2.5 for details.
+
+ \v(inmatch)
+ The incoming string of characters, if any, that matched the most
+ recent INPUT, REINPUT, or MINPUT command.
+
+ \v(intime)
+ The number of milliseconds (thousandths of seconds) it took for
+ the most recent INPUT command to find its match, or -1 if no
+ INPUT command has been given yet. If the INPUT command timed
+ out, the value is approximately equal to 1000 times the INPUT
+ timeout. If INPUT failed for some other reason, the value is
+ undefined (\v(instatus) gives INPUT completion status). If your
+ version of C-Kermit is built without high-precision
+ floating-point timers, this number will always be a multiple of
+ 1000.
+
+ \v(inwait)
+ The number of seconds specified as the timeout in the most
+ recent INPUT command.
+
+ \v(dialsuffix)
+ Dialing suffix for use during PDIAL sequence; see [571]Section
+ 2.1.10.
+
+ \v(pid)
+ UNIX, VMS, and K95 only. C-Kermit's primary process ID, numeric,
+ decimal. If you want to show it in hex, use \fn2hex(\v(pid)) If
+ you want to show it in octal, use \fn2octal(\v(pid)).
+
+ \v(printer)
+ Current printer name or SET PRINTER value.
+
+ \v(p_ctl)
+ Control prefix char \v(p_8bit) 8-bit prefix char (if parity not
+ none)
+
+ \v(p_rpt)
+ Repeat prefix char (if repeat compression enabled)
+
+ \v(herald)
+ Kermit's version herald
+
+ \v(test)
+ Kermit's test version, if any, or 0 if this is not a test
+ version. Typical values for test versions are "Alpha.03" or
+ "Beta.14".
+
+ \v(sendlist)
+ The number of entries in the SEND-LIST, 0 if none. Note: entries
+ do not necessarily correspond to files, since an entry might
+ contain wildcards. Also note that the value does not go back to
+ 0 after the files in the list are sent. To reset this variable,
+ use CLEAR SEND-LIST. The purpose of this variable is to
+ determine if a SEND command, when given without any filenames,
+ will be legal. Example:
+
+ xif \v(sendlist) { send } else { send oofa.txt }
+
+ \v(trigger)
+ If the most recent CONNECT session was terminated automatically
+ by a trigger, this variable contains the trigger value.
+
+ \v(ty_ln)
+ TYPE line number (during TYPE)
+
+ \v(ty_lc)
+ TYPE line count (after TYPE)
+
+ \v(ty_mc)
+ TYPE match count (after TYPE)
+
+ \v(xferstat)
+ Status of most recent file transfer:
+
+-1: No transfer yet
+ 0: Succeeded
+ 1: Failed
+
+ \v(xfermsg)
+ If the most recent file transfer failed, this is the reason. If
+ it succeeded, \v(xfermsg) is an empty string.
+
+ \v(tftime)
+ Total elapsed time of most recent file transfer operation, in
+ seconds.
+
+ \v(textdir)
+ Directory that holds (or is supposed to hold) Kermit text files
+ such as installation instructions, release notes, update notes,
+ read-me files, "beware" files, etc.
+
+ \v(name)
+ The name with which the Kermit program was invoked, e.g.
+ "kermit", "wermit", "k95", "k2", etc (see [572]Section 9.1).
+
+ \v(osname)
+ Name of operating system on computer where C-Kermit is running,
+ obtained at runtime (from uname or equivalent).
+
+ \v(osversion)
+ Version of operating system on computer where C-Kermit is
+ running, obtained at runtime (from uname or equivalent).
+
+ \v(osrelease)
+ Release of operating system on computer where C-Kermit is
+ running, obtained at runtime (from uname or equivalent).
+
+ \v(model)
+ The specific hardware model of the computer where C-Kermit is
+ running, if known.
+
+ \v(math_pi)
+ The value of Pi (see [573]Section 7.23)
+
+ \v(math_e)
+ The value of e (see [574]Section 7.23)
+
+ \v(math_precision)
+ How many significant digits in a floating-point number.
+
+ \v(f_count)
+ Result of the most recent FILE COUNT (FCOUNT) command.
+
+ \v(f_error)
+ Numeric error code of most recent FILE command.
+
+ \v(f_max)
+ Maximum number of files open simultaneously.
+
+ The math constants are given in the precision of underlying computer's
+ floating-point arithmetic.
+
+ Note the distinction between \v(osname), \v(osversion), and
+ \v(platform); the latter refers to the platform for which and/or upon
+ which C-Kermit was built, as opposed to the one on which it is actually
+ running. Also note that each operating system can, and probably will,
+ interpret and fill in the os* variables differently, or not at all.
+
+ The SHOW VARIABLES command now accepts a variable name, prefix, or
+ pattern:
+
+ show variables Shows all variables.
+ show variables t Shows all variables that start with "t".
+ show variables *ver* Shows all variables whose names contain "ver".
+ show variables *ver Ditto (an implied "*" is appended).
+
+ 7.3. New or Improved Built-In Functions
+
+ The following new file-i/o functions are explained in [575]Section
+ 1.22.
+
+ \f_status(channel) Status of file open on channel
+ \f_pos(channel) Read/write (byte) pointer of given file
+ \f_line(channel) Current line of file
+ \f_handle(channel) Handle of file
+ \f_eof(channel) Whether given file is at EOF
+ \f_getchar(channel) Read a char from given file
+ \f_getline(channel) Read a line from given file
+ \f_getblock(channel,n) Read a block from given file
+ \f_putchar(channel,c) Write a char to given file
+ \f_putline(channel,string) Write a line to given file
+ \f_putblock(channel,string) Write a block to given file
+
+ The following new date-time-related functions are explained in
+ [576]Section 1.6:
+
+ \fday() Returns day of week of given date
+ \fnday() Returns numeric day of week of given date
+ \ftime() Returns time portion of given date-time
+ \fntime() Converts time to seconds since midnight
+ \fn2time() Converts seconds since midnight to hh:mm:ss
+ \fcvtdate(date-time) Converts free-format date to yyyymmdd hh:mm:ss
+ \fdayofyear(date-time) Converts date to yyyyddd (day-of-year) format
+ \fdoy(date-time) Synonym for \fdayofyear()
+ \fdoy2date(dayofyear) Converts yyyyddd to yyyymmdd
+ \fmjd(date-time) Converts free-format date to Modified Julian Date
+ \fmjd2date(mjd) Converts modified Julian date to yyyymmdd
+
+ The new floating-point arithmetic functions are explained in
+ [577]Section 7.23. f1 and f2 are floating-point (real) numbers; d is
+ the number of decimal places to show:
+
+ \ffpabsolute(f1,d) Absolute value of f1
+ \ffpadd(f1,f2,d) f1 + f1
+ \ffpcosine(f1,d) Cosine of f1
+ \ffpdivide(f1,f2,d) f1 divided by f2
+ \ffpexp(f1,d) e to the f1 power
+ \ffpint(f1) Integer part of f1
+ \ffplog10(f1,d) Log base 10 of f1
+ \ffplogn(f1,d) Natural log of f1
+ \ffpmaximum(f1,f2,d) Maximum of f1 and f2
+ \ffpminimum(f1,f2,d) Minimum of f1 and f2
+ \ffpmodulus(f1,f2,d) Modulus of f1 and f2
+ \ffpmultiply(f1,f2,d) Product of f1 and f2
+ \ffpraise(f1,f2,d) Raise f1 to power f2
+ \ffpround(f1,d) Round f1 to d places
+ \ffpsine(f1,d) Sine of f1
+ \ffpsqrt(f1,d) Square root of f1
+ \ffpsubtract(f1,f2,d) f2 - f1
+ \ffptangent(f1,d) Tangent of f1
+
+ Integer number functions:
+
+ \fabsolute(n)
+ Absolute value of integer n.
+
+ \frandom(n)
+ Returns a random integer between 0 and n-1.
+
+ \fradix(s,n1,n2)
+ If the string s is an integer in radix n1, the result is the
+ same number expressed in radix n2, where n1 and n2 may be any
+ number from 2 through 36, expressed as decimal numbers, or
+ variables (etc) that evaluate to decimal numbers. For the source
+ and result, the digits of any radix, r, are the first r
+ characters in the sequence 0-9,a-z (case doesn't matter for the
+ letters). The string s may have a sign, + or -; if it starts
+ with a minus (-) sign, the result also has a minus sign.
+
+ The \fradix() function does not work with floating-point numbers. It
+ does not reveal the internal storage format of a number; for example,
+ \fradix(-1,10,16) is -1, not something like FFFFFFFFFF. If all three
+ arguments are not given, or if n1 or n2 are not numbers between 2 and
+ 36 inclusive, or s is not a number in radix n1, an error occurs and the
+ empty string is returned. \fradix() also does not offer
+ extended-precision arithmetic; number values are limited to those
+ expressed as a long integer in the architecture of the underlying
+ computer, usually 32 or 64 bits. If you give it an argument whose
+ absolute value is larger than can be held in an unsigned long, the
+ result is -1.
+
+ The next four are shorthand functions for decimal/hexadecimal and
+ decimal/octal number conversion:
+
+ \fn2hex(n)
+ Returns the hexadecimal (base 16) representation of the integer
+ n. This is different from \fhexify(s), which treats its argument
+ as a string rather than a number. The result is always
+ left-padded with 0's to make its length even. Examples:
+
+ \n2hex(0) = "00" \fhexify(0) = "30"
+ \n2hex(255) = "ff" \fhexify(255) = "323535"
+ \n2hex(256) = "0100" \fhexify(256) = "323536"
+
+ \fhex2n(x)
+ Converts hexadecimal number x to decimal equivalent decimal
+ number. This is the inverse of \fn2hex(). Equivalent to
+ \fradix(s,16,10).
+
+ \fn2octal(n)
+ Returns the octal (base 8) representation of the number n.
+ Examples:
+
+ \n2octal(0) = "0"
+ \n2oct(255) = "377"
+ \n2oct(256) = "400"
+ Equivalent to \fradix(n,10,8).
+
+ \foct2n(n)
+ Returns the decimal representation of the given octal number, n.
+ The inverse of \fn2octal(). Equivalent to \fradix(n,8,10).
+
+ String functions:
+
+ \s(name[n:m])
+ Equivalent to \fsubstring(\m(name),n,m) ([578]Section 7.24).
+
+ \:(name[n:m])
+ Equivalent to \fsubstring(name,n,m) (where "name" is any
+ \-quantity) ([579]Section 7.24).
+
+ \fleft(s,n)
+ The leftmost ncharacters of string s; equivalent to
+ \fsubstring(s,1,n).
+
+ \fstripx(string,char)
+ Returns the part of the string up to the rightmost occurrence,
+ if any, of the given character. The default character is period
+ (.) Examples:
+
+ \fstripx(foo/bar,/) = "foo"
+ \fstripx(foo/bar/baz,/) = "foo/bar"
+ \fstripx(autoexec.bat,.) = "autoexec"
+ \fstripx(autoexec.bat) = "autoexec"
+ \fstripx(fstripx(foo/bar/baz,/),/) = "foo"
+
+ \flop(string,character)
+ Returns the portion of the string starting after the first
+ occurrence of the given character. The default character is
+ period (.) Examples:
+
+ \flop(autoexec.bat) = "bat"
+ \flop(baz.foo/bar) = "foo/bar"
+ \flop(baz.foo/bar,/) = "bar
+
+ \fstripn(string,n)
+ Returns the string with ncharacters removed from the end.
+ Example:
+
+ \fstripn(12345678,3) = "12345"
+
+ (For more discussion of \fstripx(), \fstripn(), and \flop() see
+ [580]Section 4.2.3).
+
+ \fb64encode(s)
+ Returns the Base-64 encoding of the string s.
+
+ \fb64decode(s)
+ Returns the decoding of the Base-64 string s. Fails if s is not
+ a Base-64 string, or if its length is not a multiple of 4. Note
+ that if any of the result bytes are null (0), the result string
+ stops there. There is no way to represent strings that contain
+ null bytes in C-Kermit (the same is true for \funhexify()).
+
+ \fword(s1,n,s2,s3)
+ Extracts word number nfrom string s1. By default, a "word" is
+ any sequence of ASCII letters or digits; nis 1-based. If n is
+ omitted, "1" is used. Examples:
+
+ \fword(one two three) = "one"
+ \fword(one two three,1) = "one"
+ \fword(one two three,2) = "two"
+ \fword(one two three,3) = "three"
+
+ and:
+
+ \fword(\v(dialresult),2) = "31200"
+
+ is "31200" if \v(dialresult) is (e.g.) "CONNECT
+ 31200/ARQ/V32/LAPM/V42BIS".
+
+ If you include s2, this replaces the default break set. For
+ example, suppose you have a string \%a whose value is:
+
+ $150.00 $300.00 $39.95
+
+ and you want each dollar amount to be a word; use:
+
+ \fword(\%a,\%n,{ })
+
+ This returns dollar amount number \%n, e.g. "$300.00" for \%n =
+ 2. "{ }" denotes a space (you must enclose it in braces,
+ otherwise it is squeezed out). Note that ASCII control
+ characters are always included in the break set; you don't have
+ to specify them (and you can't not specify them).
+
+ The optional s3 argument lists characters (even control
+ characters) that normally would be considered separators that
+ you want included in words. So the dollars-and-cents example
+ could also be handled this way:
+
+ \fword(\%a,\%n,,$.)
+
+ in other words, use the default separator list, but remove "$"
+ and "." from it so they will be considered part of a word.
+
+ Note that since 8-bit characters are not ASCII, they act as
+ break characters unless you put them in the include list.
+ Suppose, for example, you have a file in which each line is a
+ Tab-separated list of words, numbers, or phrases that might
+ contain punctuation, special characters like $ and @, 8-bit bit
+ characters, etc (like something that might have been exported
+ from a spreadsheet or database), and you want to split only on
+ Tab; here is a way (\m(line) is a line read from the file):
+
+undef keep
+for \%i 1 255 1 {
+ if == \%i 9 continue
+ .keep := \m(keep)\fchar(\%i)
+}
+while true {
+ fread /line \%c line
+ if fail break
+ .\%n := \fsplit(\m(line),&a,\9,\m(keep))
+ ...
+}
+
+ This problem is addressed in [581]C-Kermit 9.0.
+
+ \fsplit(s1,&a,s2,s3)
+ This is like \fword(), except instead of extracting and
+ returning a particular word from string s1, it counts the words
+ and optionally assigns them to the array whose identifying
+ letter, a-z, is given after the "&" in the second argument, with
+ the first word going into element 1, the second into element 2,
+ and so on. The rules regarding break and include lists (s2 and
+ s3) are exactly the same as for \fword(). \fsplit() returns the
+ number of words that were assigned, which is either the number
+ of words in the string, or the dimension of the array, whichever
+ is less. If the array is not declared, \fsplit() creates it and
+ returns a number which is both the number of words in s1 and the
+ dimension of the new array. Examples:
+
+ declare \&w[20] ; (Optional.)
+ ...
+ read \%s ; \%s is "This is a sentence with seven words."
+ ...
+ echo "\fsplit(\%s)" ; This would print "7".
+ echo "\fsplit(\%s,&w)" ; Ditto, and also assigns them to array \&w[].
+
+ echo "\&w[7]" ; This would print "words".
+
+ If the line contained fields that were delimited by colon (:),
+ you would use \fsplit(\%s,&w,:). If the fields were delimited by
+ comma, then you would use \fsplit(\%s,&w,{,}); in this case the
+ literal comma must be enclosed in braces to distinguish it from
+ the comma that separates function arguments. To get a word count
+ without loading an array, but still specify break and/or include
+ lists, leave the array argument empty:
+
+ echo "\fsplit(\%s,,:)" ; Use colon as the separator.
+
+ WARNINGS:
+
+ 1. If you use the same array repeatedly, \fsplit() leaves any
+ trailing members undisturbed. For example:
+ dcl \&w[10]
+ \fsplit(1 2 3 4 5,&w) ; Sets \&w[1] thru \&w[5].
+ \fsplit(a b c,&w) ; Sets \&w[1]-[3] leaving [4]-[5] as they were.
+
+ 2. If you allow \fsplit to create the array (by not declaring it
+ first), it is dimensioned to the number of elements it was
+ created with:
+ \fsplit(1 2 3,&x) ; Creates an array \&x[] with 3 elements.
+ \fsplit(a b c d e,&x) ; This overflows the array.
+
+ Thus if you want to use \fsplit() repeatedly on the same array,
+ either dimension it in advance to the maximum expected size (and
+ then some -- more efficient), or else destroy it after each use
+ (to allow for unexpectedly large arguments). Example using a
+ dynamic array:
+
+ fopen /read \%c some-file
+ if fail ...
+ set function error on ; See [582]Section 7.12
+ while true {
+ dcl \&w[] ; Destroy \&[w] each time thru the loop
+ fread /line \%c \%a
+ if fail break
+ asg \%x \fsplit(\%a,&w)
+ if fail ...
+ ; (do what you want with \&w[] here...)
+ }
+ fclose \%c
+
+ \frindex(s1,s2,n)
+ The "n" argument to \frindex() now works consistently (in mirror
+ image) with the corresponding \findex() argument. In each case,
+ the (n-1)-most characters of s2 are ignored in the search; for
+ findex, this means the starting position of the search is n (the
+ default n is 1, and 0 is treated like 1). For \frindex() it
+ means the default starting point is:
+
+ length(s2) - length(s1) - n (with the same defaults for n).
+
+ \fsearch(pattern,string[,position])
+ Exactly like \findex(), except with a pattern (see [583]Section
+ 7.9) rather than a literal string.
+
+ \frsearch(pattern,string[,position])
+ Exactly like \frindex(), except with a pattern rather than a
+ literal string.
+
+ File Functions:
+
+ \ffiles(), \fnextfile()
+ It is no longer necessary to copy the file list to an array
+ before use, as shown on p.398 of [584]Using C-Kermit 2nd
+ Edition. \ffiles() and friends now make their own safe copies of
+ the file list. Thus constructions like the following are now
+ possible:
+
+ for \%i 1 \ffiles(*.txt) 1 { send \fnextfile() }
+
+ The same is true for the new function \frfiles(),
+ \fdirectories(), and \frdirectories(), described in [585]Section
+ 4.11.3.
+
+ But note that each reference to \fnextfile() still gets you the
+ next file. So "if newer \fnextfile() foo.txt send \fnextfile()"
+ compares one file's age with that of foo.txt, and then sends an
+ entirely different file. If you're going to refer to the same
+ file more than once, assign it to a variable:
+
+ asg \%f \fnextfile()
+ if newer \%f foo.txt send \%f
+
+ (note: assign, not define).
+
+ Also note that \ffiles(), \frfiles(), \fdirectories(), and
+ \frdirectories() all now accept on optional 2nd argument: the
+ name of an array to load with the resulting file or directory
+ list, explained in [586]Section 4.11.3. So you can also load an
+ array with the filelist when you need to refer to the same file
+ more than once:
+
+ for \%i 1 \ffiles(*,&a) 1 { if newer \&a[\%i] foo.txt send \&a[\%i] }
+
+ \fpermissions(file)
+ Returns the platform-specific permissions string for the file,
+ such as "-rw-rw-r--" in UNIX or "(RWE,RWE,RE,E)" in VMS.
+
+ \fdirname(f)
+ Given a file specification f, this function returns the complete
+ pathname of directory the file is in.
+
+ Array Functions:
+
+ \fdimension(&a)
+ Returns the dimension declared for the array whose identifying
+ letter, a-z, or special character "_" or "@", is given after the
+ "&" in the argument. If the array is not declared, 0 is
+ returned. Note that when used with the macro argument vector
+ array, \&_[] (see [587]Section 7.5), the value of this function
+ is one less than \v(argc), and when used with the C-Kermit
+ command-line argument vector array, \&@[], it is equal to the
+ \v(args) variable. Examples:
+
+ echo \fdimension(&a) ; Not declared.
+ 0
+ declare \&a[12] ; Now it's declared.
+ echo \fdim(&a)
+ 12
+
+ \farraylook(pattern,arrayname)
+ Looks in the given array for the pattern and returns the index
+ of the first element that matches, if any, or -1 if none match.
+ The arrayname can include a range specifier to restrict to
+ search to a segment of the array, e.g.
+ \farraylook(*xyz*,&a[32:63]). For greater detail see
+ [588]Section 7.10.7.
+
+ \ftablelook(keyword,arrayname[,delimiter])
+ Looks in the given "table", which must be sorted, for the given
+ keyword. Returns the index of the table element that uniquely
+ matches the given keyword, or -1 if none match, or -2 if more
+ than 1 match. For greater detail see [589]Section 7.10.7.
+
+ Other new functions:
+
+ \fip2hex(s)
+ Converts a dotted decimal IP address to an 8-digit hexadecimal
+ number. \fip2hex(128.59.39.2) = 803b2702.
+
+ \fhex2ip(x)
+ Converts an 8-digit hexadecimal IP address to dotted decimal
+ form, e.g. \fhex2ip(803b2702) = 128.59.39.2. The inverse of
+ \fip2hex().
+
+ \fcommand()
+ \frawcommand()
+ These run an external command and return its output; see
+ [590]Section 4.2.8.4.
+
+ \fdialconvert(s)
+ s is a phone number in either literal or portable format (not a
+ dialing directory entry name). The function returns the dial
+ string that would actually be used when dialing from the current
+ location (after processing country code, area code, and other
+ SET DIAL values).
+
+ \ferrstring(n)
+ Returns the system error message associated with the (numeric)
+ error code n. UNIX and VMS only. Use in conjunction with
+ \v(errno) or \v(pexitstat). See [591]Section 4.2.5 for a usage
+ example. Note: This function doesn't work in Windows because
+ there is not a consistent error-code-to-message mapping; error
+ code "x" means something completely different depending on
+ whether it comes from the C runtime library, Winsock, a
+ Windows-32 API, TAPI, etc,
+
+ \fpattern(s)
+ Used in INPUT, REINPUT, and MINPUT commands to denote search
+ strings that are to be treated as patterns rather than
+ literally.
+
+ Also see [592]Section 7.8 on built-in help for functions.
+
+ 7.4. New IF Conditions
+
+ IF AVAILABLE feature command
+ Executes the command if the given feature is available.
+ Presently used only to determine if specific authentication and
+ encryption options are available. Type "if available ?" to see
+ which features may be tested.
+
+ IF FLOAT f1 command
+ Executes command if f1 is a legal floating point number (which
+ includes integers). Use this to preverify arguments for the
+ \ffp...() floating-point arithmetic functions, e.g. "if float
+ \%1 echo \ffpint(\%1)".
+
+ IF == n1 n2 command
+ Synonym for "if =" (numeric equality). Note that as of C-Kermit
+ 7.0, this and all other numeric comparison operators also work
+ for floating-point numbers.
+
+ IF != n1 n2 command
+ Executes the command if n1 and n2 are both numbers or variables
+ containing numbers and the value of n1 is not equal to the value
+ of n2. This is equivalent to "if not = n1 n2".
+
+ IF <= n1 n2 command
+ Executes the command if n1 and n2 are both numbers or variables
+ containing numbers and the value of n1 is less than or equal to
+ the value of n2. This is equivalent to "if not > n1 n2".
+
+ IF >= n1 n2 command
+ Executes the command if n1 and n2 are both numbers or variables
+ containing numbers and the value of n1 is greater than or equal
+ to the value of n2. Equivalent to "if not < n1 n2".
+
+ IF COMMAND word command
+ Executes the command if word is a built-in C-Kermit command.
+ Example:
+
+ if not command copy define { copy run copy \%1 \%2 }".
+
+ This defines a COPY macro that runs an external COPY command if
+ COPY is not already a built-in command.
+
+ IF LOCAL command
+ Executes the command if Kermit is in local mode, i.e. if it has
+ a SET LINE, SET PORT, or SET HOST (TELNET, RLOGIN, etc) device
+ or connection open. Does not execute the command if in remote
+ mode.
+
+ IF MATCH string pattern command
+ Executes the command if the string matches the pattern. For a
+ description of the syntax for the pattern, see [593]Section
+ 4.9.1. If you want to test if the string contains pattern, use
+ IF \fsearch(pattern,string).
+
+ IF OPEN { DEBUG-LOG, SESSION-LOG, TRANSACTION-LOG, ... } command
+ Executes the command if the given file is open, fails if it is
+ not open. Type IF OPEN ? for a complete list of files that can
+ be checked (all the files that can be opened with the OPEN or
+ LOG commands).
+
+ IF QUIET command
+ Executes the command if SET QUIET is ON, and does not execute it
+ if SET QUIET is OFF. Example: IF NOT QUIET ECHO { This is a
+ message.}.
+
+ IF READABLE name
+ Succeeds if name is the name of an existing file or directory
+ that is readable.
+
+ IF WRITEABLE name
+ Succeeds if name is the name of an existing file or directory
+ that is writable, e.g.:
+
+ if not writeable \v(lockdir) echo Please read installation instructions!
+
+ IF FLAG command
+ This tests a user-settable condition, which can mean anything
+ you like. SET FLAG ON causes subsequent IF FLAG commands to
+ succeed; SET FLAG OFF causes them to fail. One way to use it
+ would be for debugging your scripts; precede any debugging
+ statements with IF FLAG. Then SET FLAG on to debug your script,
+ SET FLAG OFF to run it without debugging. Another common use is
+ for causing an inner loop to cause an outer loop to exit.
+
+ IF C-KERMIT command
+ C-Kermit, but not Kermit 95 or MS-DOS Kermit, executes the
+ command.
+
+ IF K-95 command
+ Kermit 95, but not C-Kermit or MS-DOS Kermit, executes the
+ command.
+
+ IF MS-KERMIT command
+ MS-DOS Kermit, but not C-Kermit or Kermit 95, executes the
+ command.
+
+ 7.5. Using More than Ten Macro Arguments
+
+ The \v(argc) variable now gives the actual number of arguments, even if
+ the number is greater than 9:
+
+ C-Kermit> define xx echo \v(argc)
+ C-Kermit> xx a b c d e f g h i j k l m n o p q r s t u v w x y z
+ 27
+
+ Remember that \v(argc) includes the name of the macro itself, so it is
+ always at least 1, and is always 1 greater than the actual number of
+ arguments. As in versions 6.0 and earlier, if more than 9 arguments are
+ given, only the first nine are assigned to the variables \%1..\%9.
+
+ The \&_[] array, discussed on page 353 of [594]Using C-Kermit, 2nd ed,
+ now holds all the arguments, up to some implementation-dependent limit
+ (64 or greater), rather than only the first 9. To illustrate: the
+ following macro tells the number of arguments it was called with and
+ then prints them:
+
+ define show_all_args {
+ local \%i
+ echo \&_[0] - Number of arguments: \feval(\v(argc)-1)
+ for \%i 1 \v(argc)-1 1 { echo \flpad(\%i,3). "\&_[\%i]" }
+ }
+
+ Within a macro \&_[0], like \%0, contains the name of the macro.
+
+ At top level, the \&_[] array is filled as follows:
+
+ * If the first argument on the C-Kermit command line was a filename,
+ or C-Kermit was invoked from a "Kerbang" script ([595]Section
+ 7.19), element 0 contains the filename, and elements 1 through
+ \v(argc)-1 hold the remaining command-line arguments.
+ * Otherwise the program name goes in element 0, and elements 1
+ through \v(argc)-1 hold any arguments that were included after "--"
+ or "="
+
+ The new \%* variable, when used within a macro, is replaced by the text
+ that followed the macro name in the macro invocation. If no arguments
+ were given, \%* is replaced by the empty string. Examples:
+
+ C-Kermit> define xx echo [\%*]
+ C-Kermit> define \%a oofa
+ C-Kermit> xx
+ []
+ C-Kermit> xx \%a
+ [oofa]
+ C-Kermit> xx a
+ [a]
+ C-Kermit> xx a b
+ [a b]
+ C-Kermit> xx a b c
+ [a b c]
+ C-Kermit> xx a b c d e f g h i j k l m n o p q r s t u v w x y z
+ [a b c d e f g h i j k l m n o p q r s t u v w x y z]
+
+ Note that \%* can not be used at top level, since Kermit does not have
+ access to the raw command line (only to its elements separately, after
+ they have been processed by the shell and the C library).
+
+ C-Kermit 7.0 also adds a SHIFT command:
+
+ SHIFT [ number ]
+ Shifts the macro arguments (except argument 0) the given number
+ of places to the left and adjusts \v(argc) accordingly. The
+ default number is 1.
+
+ To illustrate, suppose macro XXX is invoked as follows:
+
+ xxx arg1 arg2 arg3
+
+ Then inside XXX, \%1 is "arg1", \%2 is "arg2", and \%3 is "arg3". After
+ a SHIFT command is given inside XXX, then \%1 is "arg2", \%2 is "arg3",
+ and \%3 is empty. \%0 (the name of the macro) remains unchanged.
+
+ If more than 9 arguments were given, then arguments are shifted into
+ the \%1..9 variables from the argument vector array.
+
+ At top level, the SHIFT command operates on the \&_[] array and \%1..9
+ variables; the \&@[] array is not affected. See [596]Section 7.16 for
+ details.
+
+ The \%* variable is not affected by the SHIFT command.
+
+ 7.6. Clarification of Function Call Syntax
+
+ Spaces are normally stripped from the front and back of each function
+ argument; to prevent this enclose the argument in braces:
+
+ \fsplit(\%a,&a,{ })
+
+ However, function calls that contain spaces can make trouble when the
+ function is to be used in a "word" field, since space separates words.
+ For example:
+
+ for \%i 1 \fsplit(\%a,&a,{ }) 1 {
+ echo \%i. "\&a[\%i]"
+ }
+
+ In most cases, the trouble can be averted by enclosing the function
+ reference in braces:
+
+ for \%i 1 {\fsplit(\%a,&a,{ })} 1 {
+ echo \%i. "\&a[\%i]"
+ }
+
+ or by replacing spaces with \32 (the ASCII code for space):
+
+ for \%i 1 \fsplit(\%a,&a,\32) 1 {
+ echo \%i. "\&a[\%i]"
+ }
+
+ Braces are also used in function calls to indicate grouping. For
+ example:
+
+ \fsubstring(abcd,2,2) = "bc"
+
+ But suppose "abcd" needed to contain a comma:
+
+ \fsubstring(ab,cd,2,2)
+
+ This would cause an error, since "cd" appears to be the second
+ argument, when really you want the first "2" to be the second argument.
+ Braces to the rescue:
+
+ \fsubstring({ab,cd},2,2) = "b,"
+
+ Similarly, leading and trailing spaces are stripped from each argument,
+ so:
+
+ \fsubstring( abcd ,2,2) = "bc"
+
+ but braces preserve them:
+
+ \fsubstring({ abcd },2,2) = "ab"
+
+ Given these special uses for braces, there is no way to pass literal
+ braces to the function itself. For example:
+
+ \fsubstring(ab{cd,2,2)
+
+ causes an error.
+
+ So if you need a function to include braces, define a variable
+ containing the string that has braces. Example:
+
+ define \%a ab{cd
+ \fsubstring(\%a,2,2) = "b{"
+
+ If the string is to start with a leading brace and end with a closing
+ brace, then double braces must appear around the string (which itself
+ is enclosed in braces):
+
+ define \%a {{{foo}}}
+ \fsubstring(\%a) = "{foo}"
+
+ This also works for any other kind of string:
+
+ define \%a {{ab{cd}}
+ echo \fsubstring(\%a) = "ab{cd"
+
+ 7.7. Autodownload during INPUT Command Execution
+
+ As of 6.1 / 1.1.12, C-Kermit can be told to look for incoming Kermit
+ (or Zmodem) packets during execution of an INPUT command. By default
+ (for consistency with earlier releases), this is not done. You can
+ enable this feature with:
+
+ SET INPUT AUTODOWNLOAD ON
+
+ (and disable it again with OFF.)
+
+ One possible use for this feature is as a server mode with a time
+ limit:
+
+ INPUT 3600 secret-string-to-end-the-INPUT-command
+
+ In this example, any GET, SEND, or REMOTE commands received within one
+ hour (3600 seconds) of when the INPUT command was issued will be
+ executed. Here's another example, in which we want to stay open until
+ 11:30pm, or until interrupted by seven consecutive Ctrl-C (\3)
+ characters:
+
+ INPUT 23:30:00 \3\3\3\3\3\3\3
+
+ The INPUT AUTODOWNLOAD setting is displayed by SHOW SCRIPTS or SHOW
+ INPUT.
+
+ 7.8. Built-in Help for Functions.
+
+ Beginning in C-Kermit 7.0, you may obtain a description of the calling
+ conventions and return values of any built-in function, such as
+ \fsubstring(), with the new HELP FUNCTION command; give the function's
+ name without the leading "\f", e.g. "help func substring". You can use
+ ?, completion, and abbreviation in the normal manner.
+
+ 7.9. Variable Assignments
+
+ 7.9.1. Assignment Operators
+
+ Programmers accustomed to languages such as C or Fortran might find
+ Kermit's method of assigning values to variables unnatural or awkward.
+ Beginning in C-Kermit 7.0, you can use the following alternative
+ notation:
+
+ .name = value is equivalent to DEFINE name value
+ .name := value is equivalent to ASSIGN name value
+ .name ::= value is equivalent to ASSIGN name \feval(value)
+
+ When the command begins with a period (.), this indicates an
+ assignment. The name can be a macro name, a \%{digit,letter} variable,
+ or an array element. There can be space(s) between "." and the name.
+ Examples:
+
+ .\%a = This is a string ; Same as "define \%a This is a string"
+ echo \%a
+ This is a string
+
+ .xxx = \%a ; Same as "define xxx \%a"
+ echo \m(xxx)
+ \%a
+
+ .xxx := \%a ; Same as "assign xxx \%a"
+ echo \m(xxx)
+ This is a string
+
+ declare \&a[2] ; Use with arrays...
+ define \%i 2
+ .\&a[1] = first
+ .\&a[\%i] = second
+
+ The following sequence illustrates the differences among three levels
+ of evaluation:
+
+ .\%x = 2 ; Define a variable to have a numeric value
+ .\%y = (3 + \%x) ; Define another variable as an arithmetic expression
+
+ .xxx = 4 * \%y ; "=" simply copies the right-hand side.
+ echo \m(xxx)
+ 4 * \%y
+
+ .xxx := 4 * \%y ; ":=" evaluates the variables first, then copies.
+ echo \m(xxx)
+ 4 * (3 + 2)
+
+ .xxx ::= 4 * \%y ; "::=" evaluates the expression, then copies.
+ echo \m(xxx)
+ 20
+
+ You can also use this syntax to clear (undefine) a variable:
+
+ .\%a = oofa ; Define the variable
+ echo "\%a"
+ "oofa"
+ .\%a ; Clear the variable
+ echo "\%a"
+ ""
+
+ Extra credit: Can you guess what happens below when the file "abc" does
+ not exist?
+
+ fopen /read \%c abc
+ if fail ...
+
+ 7.9.2. New Assignment Commands
+
+ Recall the DEFINE and ASSIGN commands, and their hidden counterparts,
+ _DEFINE and _ASSIGN. The former take the variable name literally, the
+ latter evaluate the variable-name field to form the variable name
+ dynamically. Examples:
+
+ DEFINE \%x foo ; Sets the value of the variable \%x to "foo".
+ DEFINE \%a \%x ; Sets the value of the variable \%a to "\%x".
+ _DEFINE x_\%a \%x ; Sets the value of the variable x_foo to "\%x".
+ ASSIGN \%a \%x ; Sets the value of the variable \%a to the "foo".
+ _ASSIGN x_\%a \%x ; Sets the value of the variable x_foo to "foo".
+
+ This concept has been carried over to the remaining variable-assignment
+ commands: EVALUATE, INCREMENT, and DECREMENT:
+
+ EVALUATE variablename expression
+ Evaluates the arithmetic expression and assigns its value to the
+ variable whose name is given. Example: "eval \%a 1+1" assigns
+ "2" to \%a.
+
+ _EVALUATE metaname expression
+ Evaluates the arithmetic expression and assigns its value to the
+ variable whose name is computed from the given metaname.
+ Example: "eval foo<\%a>::\%1 \%2 * (\%3 + \%4)" assigns the
+ value of "\%2 * (\%3 + \%4)" to the variable whose name is
+ computed from "foo<\%a>::\%1".
+
+ INCREMENT variablename [ expression ]
+ Evaluates the arithmetic expression and adds its value to the
+ value of the variable whose name is given. Example: "increment
+ \%a".
+
+ _INCREMENT metaname [ expression ]
+ Evaluates the arithmetic expression and adds its value to the
+ value of the variable whose name is computed from the given
+ metaname. Example: "_increment Words::\%1.count[\%2]".
+
+ DECREMENT variablename [ expression ]
+ Evaluates the arithmetic expression and subtracts its value from
+ the value of the variable whose name is given.
+
+ _DECREMENT metaname [ expression ]
+ Evaluates the arithmetic expression and subtracts its value from
+ the value of the variable whose name is computed from the given
+ metaname.
+
+ WARNING: The syntax of the EVALUATE command has changed since C-Kermit
+ 6.0 and K95 1.1.17. Previously, it did not include a variable name,
+ only an expression. To restore the old behavior, use SET EVALUATE OLD.
+ To return to the new behavior after restoring the old behavior, use SET
+ EVALUATE NEW.
+
+ NOTE: There are no analogs to the "_" commands for the operators
+ described in [597]Section 7.9.1; those operators can not be used to
+ assign values to variables whose names must be computed.
+
+ 7.10. Arrays
+
+ C-Kermit 7.0 adds lots of new array-related features, and groups them
+ together under the NEW ARRAY command:
+
+ ARRAY { CLEAR, COPY, DECLARE, DESTROY, RESIZE, SHOW, SORT }
+
+ In each of the ARRAY commands, wherever an array name is expected,
+ "short forms" may be used. For example, all of the following are
+ acceptable:
+
+ array show \&a[] (or SHOW ARRAY...)
+ array show &a[]
+ array show a[]
+ array show &a
+ array show a
+
+ In addition, ranges are accepted in the ARRAY COPY, ARRAY CLEAR, ARRAY
+ SET, ARRAY SHOW, and ARRAY SORT commands:
+
+ array clear \&a[16] ; Clears 16 thru end
+ array clear &a[16] ; Ditto
+ array clear a[16] ; Ditto
+
+ array clear \&a[16:32] ; Clears 16 thru 32
+ array clear &a[16:32] ; Ditto
+ array clear a[16:32] ; Ditto
+
+ When using array names as function arguments, you must omit the "\" and
+ you must include the "&". You may optionally include empty brackets.
+ Examples:
+
+ \fsplit(\%a,a) ; Bad
+ \fsplit(\%a,\&a) ; Bad
+ \fsplit(\%a,&a[3]) ; Bad
+
+ \fsplit(\%a,&a) ; Good
+ \fsplit(\%a,&a[]) ; Good
+
+ 7.10.1. Array Initializers
+
+ Beginning in C-Kermit 7.0, you may initialize an array -- in whole or
+ in part -- in its declaration:
+
+ [ ARRAY ] DECLARE array-name[size] [ = ] [ value1 [ value2 [...] ] ]
+
+ For compatibility with versions 5A and 6.0, the ARRAY keyword is
+ optional. DECLARE can also be spelled DCL.
+
+ Initializers are (a) optional, (b) start with element 1, (c) must be
+ enclosed in braces if they contain spaces, and (d) are evaluated
+ according to normal rules by the DECLARE command prior to assignment.
+ Thus the assignments made here are the same as those made by the ASSIGN
+ command. This allows you to initialize array elements from the values
+ of other variables. If you actually want to initialize an array element
+ to variable's name, as opposed to its value, use double backslashes (as
+ in "\\&a", "\\v(time)", etc).
+
+ The size (dimension) of the array is optional. If the size is omitted,
+ as in "\&a[]", then the array sizes itself to the number of
+ initializers; if there are no initializers the array is not declared
+ or, if it was declared previously, it is destroyed. If a size is given,
+ any extra elements in the initialization list are discarded and
+ ignored.
+
+ NOTE: Unlike in C, the list of initializers is NOT enclosed in braces.
+ Instead, braces are used to group multiple words together. So:
+
+ ARRAY DECLARE \&a[] = { one two three }
+
+ would create an array with two elements (0 and 1), with element 1
+ having the value " one two three ".
+
+ Examples:
+
+ ARRAY DECLARE \&a[16]
+ Declares the array \&a with 17 elements (0 through 16), in which
+ all elements are initially empty. If the array \&a[] existed
+ before, the earlier copy is destroyed.
+
+ ARRAY DECLARE &a[16]
+ ARRAY DECLARE a[16]
+ ARRAY DCL \&a[16]
+ ARRAY DCL &a[16]
+ ARRAY DCL a[16]
+ DECLARE \&a[16]
+ DECLARE &a[16]
+ DECLARE a[16]
+ DCL \&a[16]
+ DCL &a[16]
+ DCL a[16]
+ All of the above are the same as the first example.
+
+ ARRAY DECLARE \&a[16] = alpha beta {gamma delta}
+ Declares the array \&a with 17 elements (0 through 16),
+ initializing \&a[1] to "alpha", \&a[2] to "beta", and \&a[3] to
+ "gamma delta". The remaining elements are empty.
+
+ ARRAY DECLARE \&a[] = alpha beta {gamma delta}
+ Same as the previous example, but the array is automatically
+ dimensioned to 3.
+
+ ARRAY DECLARE \&a[3] = alpha beta {gamma delta} epsilon zeta
+ Too many initializers; only the first three are kept.
+
+ ARRAY DECLARE \&a[0]
+ ARRAY DECLARE \&a[]
+ ARRAY DECLARE &a[]
+ ARRAY DECLARE &a
+ ARRAY DECLARE a
+ DECLARE \&[0]
+ DECLARE a
+ DCL a
+ All of these are equivalent. Each destroys \&a[] if it exists.
+ Declaring an array with a dimension of 0 is the same as ARRAY
+ DESTROY arrayname.
+
+ ARRAY DECLARE \&a[] = \%1 \%2 \%3
+ Declares the array \&a with 3 elements (0 through 3),
+ initializing \&a[1] to the value of \%1, \&a[2] to the value of
+ \%2, and \&a[3] to the value of \%3. In this case, any reference
+ to one of these array elements is replaced by the value of the
+ corresponding \%n variable at the time the declaration was
+ executed (immediate evaluation; the array element's value does
+ not change if the initializer variable's value changes).
+
+ ARRAY DECLARE \&a[] = \\%1 \\%2 \\%3
+ Declares the array \&a with 3 elements (0 through 3),
+ initializing \&a[1] to the string "\%1", \&a[2] to "\%2", and
+ \&a[3] to "\%3". In this case any reference to one of these
+ array elements is replaced by the CURRENT value of the
+ corresponding \%n variable (deferred evaluation -- the array
+ element's value follows the value of the initializer variable).
+
+ The equal sign (=) preceding the initializer list is optional, but is
+ recommended for clarity. If you need to initialize element 1 to a
+ literal equal sign, use two of them, separated by a space, as in this
+ example:
+
+ ARRAY DECLARE \&a[] = = + - * /
+
+ Remember, element 0 is not initialized by the DECLARE command. To
+ initialize element 0, use a regular DEFINE or ASSIGN command:
+
+ ARRAY DECLARE \&a[] one two three four five six seven eight nine
+ DEFINE \&a[0] zero
+
+ Finally, remember that every command level has its own local array,
+ \&_[], containing all the macro arguments (\%0, \%1, ...) for that
+ level. See [598]Section 7.5 for details.
+
+ 7.10.2. Turning a String into an Array of Words
+
+ The \fsplit(s1,&a,s2,s3) function assigns the words of string s1 to
+ successive elements of the array (beginning with element 1) whose
+ identifying letter, a-z, is given after the "&" in the second argument,
+ using break and include characters given in s2 and s3. See [599]Section
+ 7.3 for details.
+
+ 7.10.3. Arrays of Filenames
+
+ See [600]Section 4.11.3 for news about how \ffiles() and related
+ functions can assign a list of filenames to an array. To recapitulate
+ briefly here:
+
+ \ffiles(*,&a)
+
+ assigns all files that match the first argument to the array denoted by
+ the second argument. If the array has not been declared, it is declared
+ automatically, with exactly the number of elements needed to hold the
+ file list; if it was previously declared, it is destroyed and reused.
+ The filenames are assigned starting at array element 1. Element 0 holds
+ the number of files in the list.
+
+ The DIRECTORY command ([601]Section 4.5.1) can also create filename
+ arrays if you give it the /ARRAY: switch; this allows selection
+ criteria beyond whether the filename matches the given pattern.
+
+ All functions and commands that create filename arrays store the number
+ of filenames, n, as element 0 of the array, and the filenames as
+ elements 1 through n.
+
+ 7.10.4. Automatic Arrays
+
+ In a command file or macro, you can now have local (automatic) arrays.
+ Just give the name followed by empty subscript brackets (no spaces
+ inside the brackets please) in a LOCAL command, and then declare the
+ array:
+
+ LOCAL \%a \&a[] oofa
+ ARRAY DECLARE \&a[32] = value1 value2 value3 ...
+
+ This declares the scalar variable \%a, the array \&a[], and the macro
+ name "oofa" to be local, and then declares the new local copy of \&a[]
+ with 32 elements, perhaps assigning some initial values. When C-Kermit
+ exits from the command file or macro containing these command, the
+ previous \&a[] array is restored (and if there was no \&a[] at any
+ higher level, this will still be true). The process can be repeated to
+ any level. Thus it is now safe to write scripts or macros containing
+ arrays without danger of interfering with global arrays of the same
+ name.
+
+ Just as scalars are inherited by lower command levels, so are arrays.
+ So, for example, if \&a[] is declared at top level, all lower levels
+ will see it unless they include a "local \&a[]" statement, in which
+ case all levels at and beneath the level where the LOCAL statement was
+ executed will see the local copy. This too can be repeated to any
+ level.
+
+ On the other hand, if you DECLARE an array at a lower command level
+ without also making it LOCAL, this replaces the copy that was declared
+ at the lowest command level above this one.
+
+ 7.10.5. Sorting Arrays
+
+ Although arrays can be sorted using FOR loops as shown on page 383 of
+ Using C-Kermit, 2nd Ed., this involves quite a bit of repetitive
+ interpretation by the command parser, and so can be slow for large
+ arrays. For this reason, C-Kermit 7.0 adds a built-in SORT command:
+
+ ARRAY SORT [ switches ] array [ array2 ]
+ Sorts the given array in place. Sorting is strictly lexical
+ (string based). The array name can be given fully, e.g. "\&a[]",
+ or the "\" and/or "&" and/or brackets can be omitted, e.g.
+ "array sort \&a[]", "sort &a", "sort a". Also, a range can be
+ indicated in the brackets as noted in [602]Section 7.10, to
+ restrict the sort to a range of elements (equivalent to the
+ /RANGE switch, described just below), e.g. "array sort
+ &a[20:30]".
+
+ A second array may be specified. If it is, and if it is at least as big
+ as the first array, it is sorted according to the first array. For a
+ sample application, see [603]Section 7.10.10.
+
+ See [604]Section 1.5 for an explanation of switches. The optional
+ switches are:
+
+ /CASE:{ON,OFF}
+ /CASE:ON means that alphabetic case is significant in
+ comparisons; uppercase letters are sorted before lowercase ones.
+ /CASE:OFF means case is ignored, e.g. "A" is the same as "a". If
+ this switch is not given, sorting is according the current SET
+ CASE setting.
+
+ /KEY:n
+ Comparison begins at position n(1-based) in each string. If no
+ key is given, the entire strings are compared. Only one key can
+ be given. If an array element is shorter than the key value, n,
+ that element is considered empty for comparison purposes, and
+ therefore lexically less than any element at least ncharacters
+ long.
+
+ /NUMERIC
+ If this switch is included, it means sorting should be numeric,
+ rather than lexical. The sort key is the string starting at the
+ key position, skipping any leading blanks or tabs, and then as
+ much of the string from that point on that fits the definition
+ of "numeric", terminating at the first character that does not
+ qualify. A numeric string has an optional sign (+ or -) followed
+ by one or more digits, and (if your version of Kermit was built
+ with floating-point support; see [605]Section 7.23 ) zero or one
+ decimal point (period). If both /CASE and /NUMERIC are given,
+ /NUMERIC takes precedence.
+
+ /RANGE:n[:m]
+ Sort elements nthrough m of the array. By default, the entire
+ array from element 1 to its dimensioned size is sorted, which
+ might produce surprising results if the array is not full; see
+ example in [606]Section 7.10.7. If ":m" is omitted from the
+ range, the dimensioned size is used. Thus, to sort an entire
+ array, \&a[], including its 0th element, use "sort /range:0 &a".
+ You can also sort any desired section of an array, e.g. "sort
+ /range:10:20 &a" or "sort /range:\%i:\%j-1 &b". As noted above,
+ you can also specify a range in the array-name brackets. If you
+ specify a range in the array-name brackets AND with a /RANGE
+ switch, the ones in the brackets take precedence.
+
+ /REVERSE
+ Sort in reverse order. If this switch is not given, the array is
+ sorted in ascending order.
+
+ Remember that numeric switch arguments can be numbers, arithmetic
+ expressions, or variables whose values are numbers or expressions, as
+ illustrated in the /RANGE examples above.
+
+ A typical sorting application might be to list students' test scores in
+ descending order. Suppose you had the following records:
+
+ olaf 65
+ olga 98
+ ivan 83
+ xena 100
+
+ (and so on) stored in array \&s[] (e.g. by reading them from a file as
+ illustrated in [607]section 7.10.7). In these records, the student's
+ name is in columns 1-9 and the score in 10-12. So to rearrange the list
+ in descending order of score:
+
+ sort /key:10 /reverse &s
+
+ Then to list your top five students:
+
+ for \%i 1 5 1 { echo \&s[\%i] }
+
+ Or more simply (see next section):
+
+ show array a[1:5]
+
+ To illustrate the difference between a lexical and a numeric sort,
+ suppose you have the following records (the lines that are numbered,
+ starting at column 1) in array \&a[]:
+
+ Column 1 2
+ 12345678901234567890
+
+ 1. Ivan 10.0 2. Olaf 9.95 3. Olga 101.5
+
+ ARRAY SORT /KEY:10 &a[] would order them 3,1,2, but ARRAY SORT /KEY:10
+ /NUMERIC &a[] would order them 2,1,3.
+
+ 7.10.6. Displaying Arrays
+
+ The SHOW ARRAY command (or ARRAY SHOW) now accepts an optional
+ array-name argument:
+
+ SHOW ARRAY \&a[]
+
+ (you can leave off the \, the \&, and/or the []'s if you like; "show
+ array a" is equivalent to "show array \&a[]"). When an array is
+ specified, its dimension is shown and all defined (non-empty) elements
+ are listed.
+
+ Example:
+
+ assign \%n \ffiles(*,&a) ; Fill an array with filenames ([608]Section 4.11.3)
+ show array \&a[] ; Show the array we just read
+ array show \&a[] ; Same as previous
+ array sort \&a[] ; Sort the array
+ array show \&a[] ; Show it after sorting
+ array show \&a ; Show it again
+ array show &a ; Show it again
+ array show a ; Show it again
+
+ (The final four commands demonstrate the alternative forms that are
+ accepted for the array name.)
+
+ If you SHOW ARRAY without giving an array name, all defined arrays are
+ listed by name and dimension, but their contents are not shown.
+
+ You can also show a piece of an array by including a subscript or range
+ within the array brackets:
+
+ array show \&a[5] ; Shows \&a[5]
+ array show &a[3:8] ; Shows \&a[3] through \&a[8]
+ array show a[:\%n-1] ; Shows \&a[0] through \&a[\%n-1]
+
+ 7.10.7. Other Array Operations
+
+ ARRAY DESTROY arrayname
+ Destroys and undeclares the named array. Subscripts or ranges
+ are not accepted in this command.
+
+ ARRAY COPY array1 array2
+ Copies the first array to the second array. If the target array
+ has not been declared, it is created automatically with the same
+ size as the first. If it has been declared, it will be used as
+ declared; if the source array is larger, only as much of it as
+ will fit is copied to the target array. Syntax for array1 and
+ array2 is as in ARRAY SHOW (SHOW ARRAY). Example:
+
+ .\%n := \ffiles(*,&a) ; Create and load array A with a file list.
+ array copy &a &b ; Copy array A to array B.
+
+ The ARRAY COPY command also lets you copy pieces of arrays by
+ including range specifiers, as in these examples:
+
+ ARRAY COPY \&a[4:27] \&b
+ This copies \&a[] elements 4-27 to \&b[] elements 1-23,
+ creating \&b[] if necessary or, if \&b[] is already
+ declared, stopping early if its size is less than 23.
+
+ ARRAY COPY \&a[4:27] \&b[12]
+ This copies \&a[] elements 4-27 to \&b[] elements 12-35,
+ creating \&b[] if necessary or, if \&b[] is already
+ declared, stopping early if its size is less than 35.
+
+ ARRAY COPY \&a[4:27] \&b[12:14]
+ This copies \&a[] elements 4-6 to \&b[] elements 12-14,
+ creating \&b[] if necessary or, if \&b[] is already
+ declared, stopping early if its size is less than 14.
+
+ ARRAY COPY \&a[17:] \&b
+ This copies all the elements of \&a[] starting with 17
+ until the last to \&b[], creating \&b[] if necessary or,
+ if \&b[] is already declared, stopping early if \&b[] is
+ not big enough. Suppose, for example, you have a script
+ whose arguments are string1, string2, and a list of files,
+ whose job is to change all occurrences of string1 to
+ string2 in each of the files. But if the list of files is
+ omitted, then "*" (all files in the current directory) is
+ assumed:
+
+if < \v(argc) 3 exit 1 "Usage: \%0 string1 string2 [ files ]"
+if not def \%3 {
+ .n := \ffiles(*,&a)
+} else {
+ array copy &_[3:] &a
+ .n := \fdim(&a)
+}
+for i 1 n 1 {
+ ! cat \&a[i] | sed -e "s|\%1|\%2|g" > /tmp/_x
+ rename /tmp/_x \&a[i]
+}
+
+ ARRAY COPY \&a[17] \&b
+ Same as previous example.
+
+ ARRAY CLEAR arrayname
+ Sets all the elements of the array to the empty value. You may
+ also include a range specifier to clear only a selected portion
+ of the array; for example "array clear \&a[37:214]". If the
+ range is out of bounds, only the part of the array that is in
+ bounds is cleared.
+
+ ARRAY SET arrayname [ value ]
+ Sets all the elements of the array to the given value. If no
+ value is given, the array is cleared. You may also include a
+ range specifier to set only a selected portion of the array; for
+ example "array set \&a[1:9] -1". If the range is out of bounds,
+ only the part of the array that is in bounds is set.
+
+ ARRAY RESIZE arrayname size
+ Resizes the given array. If the size is greater than the array's
+ current dimension, new empty elements are added to the end. If
+ the size is less than the current dimension, the extra elements
+ are discarded. Note: If you have stored the array size in
+ element 0, ARRAY RESIZE does not change this value. Alternative
+ notation: ARRAY RESIZE arrayname[size]. For a practical example,
+ see [609]Section 7.10.11.
+
+ \farraylook(pattern,arrayname)
+ This function returns the index of the first element of the
+ given array that matches the given pattern (for details about
+ pattern syntax, see [610]section 4.9). The array name can
+ include a range specification to restrict the search to a given
+ segment of the array. If no elements match the pattern, -1 is
+ returned.
+
+ \ftablelook(keyword,arrayname[,delimiter])
+ Looks in the given "table", which must be sorted, for the given
+ keyword. The keyword need not be spelled out in full.
+ Pattern-matching characters should not be included as part of
+ the keyword. The function returns the index of the table element
+ that uniquely matches the given keyword, or -1 if none match, or
+ -2 if more than 1 match.
+
+ A "table" is an array that is sorted in lexical order; each of its
+ elements may contain multiple fields, delimited by the given delimiter
+ character or, if no delimiter is specified, a colon (:).
+
+ The \farraylook() function does exactly what you tell it. If you give
+ it a pattern that does not include wildcard characters (such as *, ?,
+ etc), it requires an exact match. For example:
+
+ \farraylook(oofa,&a)
+
+ searches for the first element of \&a[] whose value is "oofa". But:
+
+ \farraylook(oofa*,&a)
+
+ finds the first element whose value starts with "oofa", and;
+
+ \farraylook(*oofa,&a)
+
+ finds the first element whose value ends with "oofa", and;
+
+ \farraylook(*oofa*,&a)
+
+ finds the first element whose value contains "oofa".
+
+ Here's a simple demonstration of looking up patterns in arrays:
+
+ local \&a[] \%x \%n
+ declare \&a[] = zero one two three four five six seven eight nine ten
+ while true {
+ .\%x = 1
+ .\%n = 0
+ ask \%a { Pattern? }
+ if not def \%a exit 0 Done.
+ while <= \%x \fdim(&a) {
+ .\%x := \farraylook(\%a,&a[\%x])
+ if ( < \%x 0 ) break
+ echo \flpad(\%x,3). \&a[\%x]
+ increment \%x
+ increment \%n
+ }
+ if ( < \%n 1 ) echo Pattern not found - "\%a"
+ }
+
+ The array need not be sorted. When a pattern is given, a search is
+ performed; if there is a match, the matching element's index and the
+ element itself are printed, and the search begins again at the next
+ element. Thus each matching element is printed. If none match, the
+ "Pattern not found" message is printed. The process repeats for as many
+ patterns as the user wants to type, and terminates when the user types
+ an empty pattern.
+
+ Now let's build a little command parser, consisting of a keyword table,
+ and a loop to look up the user's commands in it with \ftablelook(). In
+ this case the array elements have "fields" separated by colon (:) -- a
+ keyword and a value. Keyword tables must be sorted if \tablelook() is
+ to work right, so after declaring and initializing the table array, we
+ sort it.
+
+ local \&k[] \%a \%i \%n
+
+ array declare \&k[] = drive:9 do:8 discuss:7 live:6 spend:5 help:4 quit:0
+
+ array sort &k ; Make sure array is sorted
+ echo Type "help" for help. ; Print greeting & instructions
+
+ while true { ; Loop to get commands
+ undefine \%a
+ while not defined \%a { ; Get a command
+ ask \%a { Command? }
+ }
+ .\%n := \ftablelook(\%a,&k) ; Look up the command
+ switch \%n { ; Handle errors
+ :-1, echo Not found - "\%a" ; Doesn't match
+ continue
+ :-2, echo Ambiguous - "\%a" ; Matches too many
+ continue
+ }
+ switch \fword(\&k[\%n],2) { ; Dispatch according to value
+ :9, echo Driving..., break
+ :8, echo Doing..., break
+ :7, echo Discussing..., break
+ :6, echo Living..., break
+ :5, echo Spending..., break
+ :4, echo { Commands (may be abbreviated):}
+ for \%i 1 \fdim(&k) 1 {
+ echo { \%i. \fword(\&k[\%i],1) }
+ }
+ break
+ :0, exit 0 Bye!
+ :default, stop 1 Internal error
+ }
+ }
+
+ In this example, keywords are "drive", "do", "discuss", etc, and their
+ values are unique numbers (values need not be numbers, and there need
+ not be only one value -- there can be 0, 1, 2, or more of them). The
+ user types a command, which can be the whole word (like "help") or any
+ abbreviation (like "hel", "he", or just "h"). If this does not match
+ any keywords, \ftablelook() returns -1; if it matches more than one (as
+ would "d"), it returns -2. Otherwise the array index is returned, 1 or
+ higher.
+
+ Given the array index \%n, we can get the table values as follows:
+
+ \fword(\&k[\%n],1) is the keyword (first field)
+ \fword(\&k[\%n],2) is the value (second field, in this case a number)
+
+ In our example, we use the value (number) as the SWITCH variable. As
+ noted, \fablelook() expects the array elements to contain multiple
+ fields separated by colon (:) (or other character that you specify,
+ e.g. \ftablelook(\%a,&a,^)) and when matching the keyword, ignores the
+ first delimiter and everything after it.
+
+ 7.10.8. Hints for Using Arrays
+
+ C programmers are accustomed to out-of-bounds array references causing
+ core dumps or worse. In C-Kermit:
+
+ * A reference to an an out-of-bounds array element returns the empty
+ string.
+ * An attempt to set the value of an array element that is out of
+ bounds or that has not been declared simply fails.
+
+ C programmers expect an array of size n to have elements 0 through n-1.
+ Fortran programmers expect the same array to have elements 1 through n.
+ C-Kermit accommodates both styles; when you declare an array of size n,
+ it has n+1 elements, 0 through n, and you can use the array in your
+ accustomed manner, 0-based or 1-based.
+
+ However, note that C-Kermit has certain biases towards 1-based arrays:
+
+ * Assignment of file lists starts with element 1 ([611]Section
+ 7.10.3).
+ * Assignment by \fsplit() starts with element 1 ([612]Section 7.3).
+ * Array initialization skips the 0th element. To initialize a 0-based
+ array, use something like this:
+ declare \&a[3] = one two three
+ .\&a[0] = zero
+
+ * The ARRAY SORT command skips the 0th element unless you include
+ /RANGE:0
+ * The SHIFT command ignores element 0 of the \&_[] array.
+
+ The distinction between an array's dimensioned size and the number of
+ elements in the array is important when sorting. To illustrate:
+
+ declare \&a[100] ; Declare array &a with 100 elements
+ fopen /read \%c oofa.txt ; Open a file
+ if fail...
+ for \%i 1 \fdim(&a) 1 { ; Read the file into the array
+ fread \%c \&a[\%i]
+ if fail break
+ }
+ fclose \%c
+ if > \%i \fdim(&a) end 1 File has too many lines for array.
+ .\%n ::= \%i - 1
+ echo File has \%n line(s).
+
+ Let's say the file had 95 lines. This leaves elements 96-100 of the
+ array empty. Now suppose you sort the array and write out the result:
+
+ sort &a ; Sort the whole array
+ fopen /write \%o oofa.txt.sorted ; Open an output file
+ if fail ...
+ for \%i 1 \%n 1 { ; Write out 95 records
+ fwrite /line \%o \&a[\%i]
+ if fail end 1 Write error
+ }
+ close write
+
+ You might be surprised at the contents of "oofa.txt.sorted" -- five
+ empty elements, 96-100, floated to the top of the array in the sort,
+ and since your write loop only had 95 iterations, the final 5 lines of
+ the sorted file are lost.
+
+ Therefore, when dealing with partially filled arrays -- especially when
+ sorting them -- remember to specify the number of elements. A handy way
+ of recording an array's "true" size is to put it in the 0th element.
+ That way, it "travels with the array". To illustrate (continuing the
+ previous example at the "close read" statement):
+
+ close read
+ if > \%i \fdim(&a) end 1 File has too many lines for array.
+ .\&a[0] ::= \%i - 1 ; Assign number of lines to \&a[0].
+ echo File has \&a[0] line(s).
+ sort /range:1:\&a[0] &a
+ open write oofa.txt.sorted
+ if fail ...
+ for \%i 1 \&a[0] 1 {
+ writeln file \&a[\%j]
+ if fail end 1 Write error
+ }
+ close write
+
+ Note the SORT switch, /RANGE:1:\&a[0]. This keeps the sort 1-based, and
+ uses element 0 of the array as its size indicator.
+
+ Finally, note that even though some commands or functions might put a
+ size in array element 0, no built-in functions or commands depend on a
+ size actually being there. Thus you are perfectly free to replace the
+ size with something else and treat the array as 0-based.
+
+ 7.10.9. Do-It-Yourself Arrays
+
+ Kermit's \&x[] arrays are nice because of the accompanying built-in
+ functionality -- ARRAY commands, built-in functions that load and
+ search arrays, automatic evaluation of arithmetic expressions within
+ the subscript brackets, and so on. Yet they also have certain
+ limitations:
+
+ 1. Except when created by dynamic loading (e.g. by \ffiles()) they
+ must be declared and dimensioned in advance.
+ 2. Indices must be numeric, positive, and in range.
+ 3. There can be only one dimension. Matrices or other
+ higher-dimensioned arrays are not available.
+
+ But none of this is to say you can't invent any kind of data structure
+ you like. In [613]Section 7.9.2 you can see some examples. Here's
+ another (courtesy of Dat Thuc Nguyen), in which a pair of matrices is
+ created and then added: no dimensioning necessary.
+
+ .row = 4
+ .col = 9
+
+ ; MACRO TO PRINT A MATRIX
+ define PMATRIX {
+ echo Matrix \%1:
+ for \%r 1 \m(row) 1 {
+ for \%c 1 \m(col) 1 {
+ xecho \flpad(\m(\%1[\%r][\%c]),4)
+ }
+ echo
+ }
+ echo
+ }
+ ; CREATE MATRICES A AND B
+ for \%r 1 \m(row) 1 {
+ for \%c 1 \m(col) 1 {
+ _eval A[\%r][\%c] \%r + \%c
+ _eval B[\%r][\%c] \%r * \%c
+ }
+ }
+ ; CREATE MATRIX C = SUM OF MATRIX A AND MATRIX B
+ for \%r 1 \m(row) 1 {
+ for \%c 1 \m(col) 1 {
+ _eval C[\%r][\%c] \m(A[\%r][\%c]) + \m(B[\%r][\%c])
+ }
+ }
+ pmatrix A ; Print Matrix A
+ pmatrix B ; Print Matrix B
+ pmatrix C ; Print Matrix C
+
+ In the example, we use matrix-like notation to create macros with names
+ like "A[1][1]", "B[3][7]", and so on.
+
+ 7.10.10. Associative Arrays
+
+ An associative array is a special kind of Do-It-Yourself array. It
+ differs from a regular array in that its indices need not be numbers --
+ they can be anything at all -- words, filenames, names of months, any
+ character string at all, and that it doesn't have to be (and in fact
+ can't be) declared. An associative array element is simply a macro
+ whose name ends with an index enclosed in angle brackets, for example:
+
+ file<oofa.txt>
+
+ More formally:
+
+ basename<index>
+
+ An associative array is a collection of all associative array elements
+ that have the same basename. Any number of associative arrays, each
+ with any number of elements, can exist at the same time.
+
+ An associative array element can be assigned a value, such as "1", just
+ like any other macro:
+
+ define file<oofa.txt> 1 ; Give "file<oofa.txt>" the value "1".
+
+ or:
+
+ assign file<oofa.txt> \%a ; Give it the value of the variable \%a.
+
+ However, since an associative array element is a macro, it may not have
+ an empty (null) value, since assigning an empty value to a macro
+ undefines the macro.
+
+ You can refer to the value of an associative array element using the
+ familiar notation for macro values:
+
+ echo \m(file<oofa.txt>) ; Echo the value of "file<oofa.txt>".
+
+ Associative arrays are most useful, however, when the value of the
+ index is a variable. In that case, you must use the "hidden" forms of
+ the DEFINE or ASSIGN commands that evaluate the macro name before
+ making the assignment (see [614]Using C-Kermit, page 457). Example:
+
+ define \%f oofa.txt
+ _define file<\%f> 1
+ echo file<\%f> = \m(file<\%f>)
+
+ prints:
+
+ file<oofa.txt> = 1
+
+ and then:
+
+ _increment file<\%f>
+ echo file<\%f> = \m(file<\%f>)
+
+ prints:
+
+ file<oofa.txt> = 2
+
+ What are associative arrays good for? The classic example is "word
+ counts": finding the number of times each word is used in a text
+ without knowing in advance what the words are. Without associative
+ arrays, your program would have to build a table of some kind, and
+ every time a word was encountered, look it up in the table to find its
+ position and counter, or add it to the table if it wasn't found -- a
+ time-consuming and laborious process. Associative arrays, however, let
+ you use the word itself as the table index and therefore sidestep all
+ the table building and lookups.
+
+ Let's work through a practical example. Suppose you have a
+ file-transfer log in which each line is composed of a number of
+ blank-separated fields, and the 9th field is a filename (which happens
+ to be the format of certain FTP server logs, as well as of C-Kermit's
+ new FTP-format transaction log, described in [615]Section 4.17.2), for
+ example:
+
+ Wed Jul 14 09:35:31 1999 22 xx.mit.edu 13412 /pub/ftp/mm/intro.txt ....
+
+ and you want to find out how many times each file was transferred. The
+ following code builds an associative array, file<>, containing the
+ counts for each file:
+
+ local name line max \%c \%n ; Declare local variables
+ fopen /read \%c /var/log/ftpd.log ; Open the log file ([616]Section 1.22)
+ if fail exit 1 Can't open log ; Check
+ while true { ; Loop for each record
+ fread /line \%c line ; Read a line
+ if fail break ; Check for end of file
+ .name := \fword(\m(line),9,{ }) ; Get 9th field = filename (Sec 7.3)
+ _increment file<\m(name)> ; Increment its counter (Sec 7.9.2)
+ }
+ fclose \%c ; Close file when done.
+
+ Note that _INCREMENT (and INCREMENT, and [_]DECREMENT) treat an empty
+ (i.e. nonexistent) variable as having a value of 0, and therefore
+ creates the variable with a value of 1.
+
+ At this point, if you told Kermit to "show macro file<", it would list
+ the associative array. But since you don't necessarily know the names
+ of the files in the array, or even how many elements are in the array,
+ how can you use it in a script program?
+
+ The idea of creating macro names that include character-string indices
+ enclosed in angle brackets is perfectly arbitrary and doesn't depend on
+ any Kermit features that weren't already there -- we could just as
+ easily have used some other notation, such as "file[index]",
+ "file:index", or "file.index", and the code above would have worked
+ just as well (with the corresponding syntax adjustments). But to be
+ able to use an associative array in a program after the array is built,
+ we need a method of accessing all its elements without knowing in
+ advance what they are. That's where the chosen notation comes in.
+
+ First of all, any macro name that ends with "<xxx>" (where "xxx" is any
+ string) is case sensitive, unlike all other macro names, which are case
+ independent. To illustrate, "file<oofa.txt>" and "file<OOFA.TXT>" are
+ two distinct macros, whereas "OOFA", "Oofa", and "oofa", when used as
+ macro names, are all the same.
+
+ Second, the new \faaconvert() function converts an associative array
+ (that is, all macros with names of the form "base<index>" that have the
+ same "base" part) into a pair of regular arrays and returns the number
+ of elements:
+
+ \faaconvert(name,&a[,&b])
+
+ "name" is the name of the associative array, without the angle brackets
+ or index ("file" in our example).
+
+ The second argument is the name of a regular array in which to store
+ the indices of the associative array (filenames in our example); if an
+ array of this name already exists, it is destroyed unless the array is
+ LOCAL. The third argument is the name of another regular array in which
+ to store the values (the counts in our example), with the same rules
+ about array name collisions. If you care only about the indices and not
+ the values, you can omit the third argument to \faaconvert(). In any
+ case, the associative array is converted, not copied: its elements are
+ moved to the specified regular arrays, so after conversion the original
+ associative array is gone.
+
+ As with other array-loading functions, \faaconvert() sets element 0 of
+ each array to the number of elements in the array.
+
+ To continue our example:
+
+ .max := 0 ; Maximum count
+ .\%n := \faaconvert(file,&a,&b) ; Convert
+ for \%i 1 \%n 1 { ; Loop through values
+ echo \flpad(\%i,3). \&a[\%i]: \&b[\%i] ; Echo this pair
+ if ( > \&b[\%i] \m(max) ) { ; Check for new maximum
+ .name := \&a[\%i]
+ .max := \&b[\%i]
+ }
+ }
+ echo Most popular file: \m(name), accesses: \m(max)
+
+ This lists the files and counts and then announces which file has the
+ highest count.
+
+ Now suppose you want to sort the array pair created from an associative
+ array. In our example, \&a[] contains filenames, and \&b[] contains the
+ associated counts. Here we take advantage of the ARRAY SORT command's
+ ability to sort a second array according to the first one:
+
+ array sort /reverse /numeric &b &a ; Descending sort by count
+
+ Now to see the top five files and their counts:
+
+ echo The top 5 files are:
+ for \%i 1 5 1 { ; Loop through top 5 values
+ echo \flpad(\%i,3). \&a[\%i]: \&b[\%i] ; Echo this pair
+ }
+
+ 7.10.11. Transferring Array Contents to Other Computers
+
+ The SEND /ARRAY:arrayname command ([617]Section 4.7.1) allows you to
+ send the contents of any array, or any contiguous segment of it, in
+ either text or binary mode to another computer, using Kermit protocol.
+ When used in conjunction with C-Kermit's other features (the array
+ features described in this section; the file i/o package from
+ [618]Section 1.22; its decision-making, pattern-matching, and string
+ manipulation capabilities, and so on) the possibilities are endless:
+ extracts of large files, remote database queries, ..., all without
+ recourse to system-dependent mechanisms such UNIX pipes and filters,
+ thus ensuring cross-platform portability of scripts that use these
+ features.
+
+ When sending an array in text mode, Kermit appends a line terminator to
+ each array element, even empty ones, and it also converts the character
+ set from your current FILE character-set to your current TRANSFER
+ character-set, if any. No conversions are made or line terminations
+ added in binary mode. For example, the following array:
+
+ dcl \&a[] = One Two Three Four Five Six
+
+ is sent as six lines, one word per line, in text mode, and as the bare
+ unterminated string "OneTwoThreeFourFiveSix" in binary mode.
+
+ You should always include a /TEXT or /BINARY switch in any SEND /ARRAY
+ command to force the desired transfer mode, otherwise you're likely to
+ be surprised by the effects described in [619]Section 4.3.
+
+ Here are some examples:
+
+ send /text /array:\&a[]
+ Sends the entire contents of the array \&a[] in text mode. Since
+ an as-name is not included, the receiver is told the filename is
+ _array_a_.
+
+ send /text /array:&a[]
+ send /text /array:a[]
+ send /text /array:&a
+ send /text /array:a
+ These are all equivalent to the previous example.
+
+ send /text /array:&a /as-name:foo.bar
+ As above, but the array is sent under the name foo.bar.
+
+ send /text /array:&a[100:199] /as:foo.bar
+ As above, but only the elements from 100 through 199 are sent.
+
+ In text-mode transfers, character sets are translated according to your
+ current settings, just as for text files. In binary mode, of course,
+ there is no character-set translation or other conversion of any kind.
+ But remember that array elements can not contain the NUL (ASCII 0)
+ character, since they are implemented as NUL-terminated strings.
+
+ Here's an example that shows how to send all the lines (up to 1000 of
+ them) from a file animals.txt that contain the words "cat", "dog", or
+ "hog" (see [620]Section 4.9 about pattern matching):
+
+ declare \&a[1000]
+ fopen /read \%c animals.txt
+ if fail exit 1
+ .\%i = 0
+ while true {
+ fread \%c line
+ if fail break
+ if match {\m(line)} {*{cat,[dh]og}*} {
+ increment \%i
+ if ( > \%i \fdim(&a) ) break
+ .\&a[\%i] := \m(line)
+ }
+ }
+ fclose \%c
+ send /array:a[1:\%i] /text
+
+ Note that we are careful to send only the part of the array that was
+ filled, not the entire array, because there are likely to be lots of
+ unused elements at the end, and these would be sent as blank lines
+ otherwise.
+
+ This example raises an interesting question: what if we want to send
+ ALL the matching lines, even if there are more than 1000 of them, but
+ we don't know the number in advance? Clearly the problem is limited by
+ Kermit's (and the computer's) memory. If there are a thousand trillion
+ matching lines, they most likely will not fit in memory, and in this
+ case the only solution is to write them first to a temporary file on
+ mass storage and then send the temporary file and delete it afterwards.
+
+ However, when the selection is likely to fit in memory, the
+ once-familiar technique of initial allocation with extents can be used:
+
+ if match {\m(line)} {*{cat,[dh]og}*} {
+ increment \%i
+ if ( > \%i \fdim(&a) ) {
+ array resize a \fdim(&a)+100
+ if fail stop 1 MEMORY FULL
+ echo NEW DIMENSION: \fdim(&a)
+ }
+ .\&a[\%i] := \m(line)
+ }
+
+ This grows the array in chunks of 100 as needed.
+
+ 7.11. OUTPUT Command Improvements
+
+ LINEOUT [ text ]
+ This command is exactly like OUTPUT, except it supplies a
+ carriage return at the end of the text. "lineout exit" is
+ exactly the same as "output exit\13".
+
+ SET OUTPUT SPECIAL-ESCAPES { ON, OFF }
+ This command lets you tell C-Kermit whether to process \N, \L,
+ and \B specially in an OUTPUT command, as distinct from other \
+ sequences (such as \%a, \13, \v(time), etc). Normally the
+ special escapes are handled. Use SET OUTPUT SPECIAL-ESCAPES OFF
+ to disable them.
+
+ Disabling special escapes is necessary in situations when you need to
+ transmit lines of data and you have no control over what is in the
+ lines. For example, a file oofa.txt that contains:
+
+ This is a file
+ It has \%a variables in it
+ And it has \B in it.
+ And it has \L in it.
+ And it has \N in it.
+ And this is the last line.
+
+ can be sent like this:
+
+ local line
+ set output special-escapes off
+ fopen /read \%c oofa.txt
+ if fail stop 1 Can't open oofa.txt
+ while success {
+ fread \%c line
+ if fail break
+ ; Add filtering or processing commands here...
+ output \m(line)\13
+ }
+
+ 7.12. Function and Variable Diagnostics
+
+ In C-Kermit 6.0 and earlier, the only diagnostic returned by a failing
+ function call was an empty value, which (a) could not be distinguished
+ from an empty value returned by a successful function call; (b) did not
+ give any indication of the cause of failure; and (c) did not cause the
+ enclosing statement to fail. C-Kermit 7.0 corrects these deficiencies.
+
+ SET FUNCTION DIAGNOSTICS { ON, OFF }
+ when ON, allows built-in functions to return diagnostic messages
+ when improperly referenced, instead of an empty string. FUNCTION
+ DIAGNOSTICS are ON by default. When OFF, improperly referenced
+ functions continue to return an empty string. This command also
+ affects built-in variables; in this case, an error message is
+ returned only if the variable does not exist. When FUNCTION
+ DIAGNOSTICS are ON, the error message is also printed.
+
+ For variables, the only message is:
+
+ <ERROR:NO_SUCH_VARIABLE:\v(name)>
+
+ where "name" is the name of the nonexistent variable.
+
+ For functions, the diagnostic message is:
+
+ <ERROR:message:\fname()>
+
+ where "message" is replaced by a message, and "name" is replaced by the
+ function name, e.g. <ERROR:ARG_NOT_NUMERIC:\fmod()>. Messages include:
+
+ ARG_BAD_ARRAY An argument contains a malformed array reference.
+ ARG_BAD_DATE An argument contains a malformed date and/or time.
+ ARG_BAD_PHONENUM An argument contains a malformed telephone number.
+ ARG_BAD_VARIABLE An argument contains a malformed \%x variable.
+ ARG_INCOMPLETE An argument is incomplete (e.g. a broken Base64 string).
+ ARG_EVAL_FAILURE An argument could not be evaluated (internal error).
+ ARG_NOT_ARRAY An argument references an array that is not declared.
+ ARG_NOT_NUMERIC An argument that must be integer contains non-digits.
+ ARG_NOT_FLOAT An argument has bad floating-point number format.
+ ARG_NOT_VARIABLE An argument that must be a variable is not a variable.
+ ARG_OUT_OF_RANGE An argument's numeric value is too big or too small,
+ or an argument contains illegal characters (e.g. a hex
+ or Base-64 string).
+ ARG_TOO_LONG An argument's value is too long.
+ ARRAY_FAILURE Failure to create an array.
+ DIVIDE_BY_ZERO Execution of the function would cause division by zero.
+ FLOATING_POINT_OP Execution error in a floating-point operation.
+ FILE_NOT_FOUND Filename argument names a file that can't be found.
+ FILE_NOT_READABLE Filename argument is not a regular file.
+ FILE_NOT_ACCESSIBLE Filename argument names a file that is read-protected.
+ FILE_ERROR Other error with filename argument.
+ FILE_NOT_OPEN A file function was given a channel that is not open.
+ FILE_ERROR_-n A file function got error -n ([621]Section 1.22).
+ LOOKUP_FAILURE Error looking up function (shouldn't happen).
+ MALLOC_FAILURE Failure to allocate needed memory (shouldn't happen).
+ NAME_AMBIGUOUS The function is not uniquely identified.
+ MISSING_ARG A required argument is missing.
+ NO_SUCH_FUNCTION An argument references a function that is not defined.
+ NO_SUCH_MACRO An argument references a macro that is not defined.
+ RESULT_TOO_LONG The result of a function is too long.
+ UNKNOWN_FUNCTION Internal error locating function (shouldn't happen).
+
+ Examples:
+
+ assign \%m \fmod()
+ ?<ERROR:MISSING_ARG:\fmod()>
+ echo "\fcontents(\%m)"
+ "<ERROR:MISSING_ARG:\fmod()>"
+ echo \fmod(3,x)
+ ?<ERROR:ARG_NOT_NUMERIC:\fmod()>
+ echo \fmod(3,4-2*2)
+ ?<ERROR:DIVIDE_BY_ZERO:\fmod()>
+
+ Notice the use of \fcontents() in echoing the value of a variable that
+ contains a returned error message. That's because the error message
+ includes the name of the variable or function that failed, so you must
+ use \fcontents() to prevent it from being evaluated again -- otherwise
+ the same error will occur.
+
+ The handling of function and variable errors is controlled by:
+
+ SET FUNCTION ERROR { ON, OFF }
+ Tells whether invalid function calls or variable references
+ should cause command errors. FUNCTION ERROR is ON by default.
+ When ON, and an error is diagnosed in a built-in function or
+ variable, the command that includes the function call or
+ variable reference fails. The failing command can be handled in
+ the normal way with IF FAILURE / IF SUCCESS, SET TAKE ERROR, or
+ SET MACRO ERROR.
+
+ When FUNCTION DIAGNOSTICS is OFF, there is no error message.
+
+ SHOW SCRIPTS displays the current FUNCTION DIAGNOSTICS and ERROR
+ settings.
+
+ 7.13. Return Value of Macros
+
+ In C-Kermit 5A and 6.0, there are two ways to return one level from a
+ macro: RETURN value and END number text. When RETURN is used, the
+ value, which can be a number or a text string, is assigned to
+ \v(return). When END was used, however, \v(return) was not set.
+ SUCCESS/FAILURE was set according to whether the number was zero, and
+ the text was printed, but the actual value of the number was lost.
+
+ In C-Kermit 7.0, the END number is available in the \v(return)
+ variable.
+
+ 7.14. The ASSERT, FAIL, and SUCCEED Commands.
+
+ The ASSERT command is just like the IF command, but without a command
+ to execute. It simply succeeds or fails, and this can be tested by a
+ subsequent IF SUCCESS or IF FAILURE command. Example:
+
+ ASSERT = 1 1
+ IF SUCCESS echo 1 = 1.
+
+ The FAIL command does nothing, but always fails. The SUCCEED command
+ does nothing, but always succeeds.
+
+ These commands are handy in debugging scripts when you want to induce a
+ failure (or success) that normally would not occur, e.g. for testing
+ blocks of code that normally are not executed.
+
+ 7.15. Using Alarms
+
+ Alarms may be set in two ways:
+
+ SET ALARM number
+ Sets an alarm for the given number of seconds "from now", i.e.
+ in the future, relative to when the SET ALARM command was given.
+ Examples:
+
+ set alarm 60 ; 60 seconds from now
+ set alarm +60 ; The same as "60"
+ set alarm -60 ; Not legal - you can't set an alarm in the past.
+ set alarm 60*60 ; 60 minutes from now.
+ set alarm \%a+10 ; You can use variables, etc.
+
+ SET ALARM hh:mm:ss
+ Sets an alarm for the specified time. If the given time is
+ earlier than the current time, the alarm is set for the given
+ time in the next day. You may give the time in various formats:
+
+ set alarm 15:00:00 ; 3:00:00pm
+ set alarm 3:00:00pm ; 3:00:00pm
+ set alarm 3:00pm ; 3:00:00pm
+ set alarm 3pm ; 3:00:00pm
+
+ SHOW ALARM
+ Displays the current alarm, if any, in standard date-time format
+ (see [622]Section 1.6): yyyymmdd hh:mm:ss.
+
+ IF ALARM command
+ Executes the command if an alarm has been set and the alarm time
+ has passed.
+
+ IF ALARM { command-list } [ ELSE { command-list } ]
+ Executes the command-list if an alarm has been set and the alarm
+ time has passed. Otherwise, if an ELSE part is given, its
+ command-list is executed.
+
+ CLEAR ALARM
+ Clears the alarm.
+
+ Only one alarm may be set at a time.
+
+ Example: Suppose you have a script that is always running, and that
+ transfers files periodically, and that keeps a transaction log. Suppose
+ you want to start a new transaction log each day:
+
+ log transactions \v(date).log
+ set alarm 00:00:00 ; Set an alarm for midnight
+ while true { ; Main script loop
+ xif alarm { ; If the alarm time is past...
+ close transactions ; Close current log
+ log transactions \v(date).log ; Start new one
+ pause 1 ; To make sure 00:00:00 is past
+ set alarm 00:00:00 ; Set a new alarm
+ }
+ ; put the rest of the script here...
+ }
+
+ Note that IF ALARM -- no matter whether it succeeds or fails -- does
+ NOT clear an expired alarm. Thus, once an alarm has expired, every IF
+ ALARM will succeed until the alarm is cleared (with the CLEAR ALARM
+ command) or reset with a new SET ALARM command.
+
+ 7.16. Passing Arguments to Command Files
+
+ Beginning in version 7.0, C-Kermit accepts arguments on the TAKE
+ command line, for example:
+
+ C-Kermit> take oofa.ksc one two {this is three} four
+
+ This automatically sets the variables \%1 through \%9 to the arguments,
+ and \%0 to the name of the file, in this case:
+
+ \%0 = /usr/olga/oofa.ksc
+ \%1 = one
+ \%2 = two
+ \%3 = this is three
+ \%4 = four
+
+ and \%5..\%9 are undefined (empty). Arguments past the ninth are
+ available in the \&_[] argument-vector array ( [623]Section 7.5).
+
+ The variables are those at the current macro level. Thus, if the TAKE
+ command is executed from within a macro, the macro's arguments are
+ replaced by those given on the TAKE command line (but only if at least
+ one argument is given). The command shown above is exactly equivalent
+ to:
+
+ assign \%0 /usr/olga/oofa.ksc
+ assign \%1 one
+ assign \%2 two
+ assign \%3 this is three
+ assign \%4 four
+ assign \%5
+ assign \%6
+ assign \%7
+ assign \%8
+ assign \%9
+ take oofa.ksc
+
+ Remember, the variables \%0..\%9 are on the macro call stack, and
+ command files are independent of the macro stack. Thus, if a command
+ file TAKEs another command file and passes arguments to it, the
+ variables are changed from that point on for both files, and so forth
+ for all levels of nested command files without intervening macro
+ invocations.
+
+ It would have been possible to change C-Kermit to use the overall
+ command stack, rather than the macro stack, for arguments -- this would
+ have made TAKE work exactly like DO, which is "nicer", but it would
+ also have broken countless existing scripts. However, the new SHIFT
+ command ([624]Section 7.5) makes it possible to create an alternative
+ TAKE command that does indeed save and restore the argument variables
+ at its own level around execution of a command file:
+
+ define mtake {
+ local \%f
+ assign \%f \fcontents(\%1)
+ shift
+ take \%f
+ }
+
+ C-Kermit 7.0 also supports a new, easier way to pass arguments to
+ scripts from the system command line:
+
+ kermit filename arg1 arg2 arg3 ...
+
+ in which arg1, arg2, arg3 (etc) are arguments for the script (whose
+ filename is given), and are assigned to \%1, \%2, ... \%9. The filename
+ is assigned to \%0. This applies equally to "Kerbang" scripts in UNIX
+ ([625]Section 7.19). For example, suppose you have a file called
+ "showargs" containing the following lines:
+
+ #!/usr/local/bin/kermit +
+ echo Hello from \%0
+ show args
+ exit
+
+ (except not indented, since the "#!" line must be on the left margin).
+ If you give this file execute permission:
+
+ chmod +x showargs
+
+ then you can run it exactly as you would run a UNIX shell script, e.g.:
+
+ $ showargs one two three
+ Hello from /usr/olga/showargs
+ Top-level arguments (\v(argc) = 4):
+ \&_[0] = /usr/olga/showargs
+ \&_[1] = one
+ \&_[2] = two
+ \&_[3] = three
+
+ Furthermore, the \&_[] array now contains the filename, if one was
+ given as the first command line argument, or it is a "Kerbang" script,
+ in element 0.
+
+ Otherwise element 0 is program name, and elements 1 through \v(argc)-1
+ contain the command-line arguments, if any, that appear after "--" or
+ "=", if any. This array is saved and restored around macro calls;
+ recall that inside macros it contains the macro argument vector
+ (allowing you to access arguments programmatically, and to have more
+ than 9 of them).
+
+ At top level, notice the difference between the \&@[] and \&_[] arrays.
+ The former includes C-Kermit options; the latter omits them.
+
+ 7.17. Dialogs with Timed Responses
+
+ The ASK, ASKQ, GETOK, and GETC commands (let's call them the "ASK-class
+ commands") let you write scripts that carry on dialogs with the user,
+ asking them for text, a Yes/No answer, or a character, respectively.
+ Prior to C-Kermit 7.0, these questions would always wait forever for an
+ answer. In C-Kermit 7.0, you may specify a time limit for them with the
+ new command:
+
+ SET ASK-TIMER number
+ Sets a time-limit on ASK-CLASS commands to the given number of
+ seconds. If the number is 0 or less, there is no time limit and
+ these commands wait forever for a response. Any timer that is
+ established by this command remains in effect for all future
+ ASK-class commands until another SET ASK-TIMER command is given
+ (e.g. with a value of 0 to disable ASK timeouts).
+
+ IF ASKTIMEOUT command
+ An ASK-class command that times out returns a failure status.
+ You can test explicitly for a timeout with:
+
+ 7.18. Increased Flexibility of SWITCH Case Labels
+
+ Prior to C-Kermit 7.0 / K95 1.1.19, the case labels in SWITCH
+ statements were string constants.
+
+ Now case labels can be variables, function calls, or any mixture of
+ these with each other and/or with regular characters.
+
+ Furthermore, after the case label is evaluated, it is treated not as a
+ string constant, but as a pattern against which the SWITCH variable is
+ matched ([626]Section 4.9.1).
+
+ This introduces a possible incompatibility with previous releases,
+ since the following characters in case labels are no longer taken
+ literally:
+
+ \ * ? [ {
+
+ Any scripts that previously included any of these characters in case
+ labels must now quote them with backslash (\).
+
+ 7.19. "Kerbang" Scripts
+
+ In UNIX only, Kermit scripts can be stored in files and run "directly",
+ without starting Kermit first (as noted on page 467 of the manual),
+ just as a shell script can be "run" as if it were a program. This
+ section amplifies on that idea a bit, and presents some new aspects of
+ version 7.0 that make it easier to write and run Kermit scripts
+ directly.
+
+ NOTE: On non-UNIX platforms, such as VMS or Windows, Kerbang scripts
+ can be run as "kermit + scriptfilename arg1 arg2 arg3 ...". Windows
+ 95/98/NT file associations do not allow for the passing of
+ parameters. In VMS, however, you can achieve the Kerbang effect by
+ defining a symbol, as in this example:
+
+ $ autotelnet :== "$SYS$TOOLS:KERMIT.EXE + AUTOTELNET.KSC"
+
+ and then running the script like any other command:
+
+ $ autotelnet xyzcorp.com myuserid
+
+ See [627]Section 9.3 for an explanation of the "+" symbol.
+
+ UNIX shell scripts can specify which shell should run them by including
+ a "shebang" line at the top, e.g.:
+
+ #!/bin/sh
+
+ (but not indented; the shebang line must be on the left margin). The
+ term "shebang" is a contraction of "shell" and "bang". "Bang" is a
+ slang word for the exclamation mark ("!"); "shebang" itself is an
+ American slang word used in in the phrase "the whole shebang".
+
+ We can run Kermit scripts directly too, by including a "shebang" line
+ that names Kermit as the "shell"; thus we call these "Kerbang" scripts.
+ This mechanism has been considerably simplified in C-Kermit 7.0 to
+ facilitate C-Kermit's use a scripting tool just like any of the UNIX
+ shells or scripting languages. The rules are the same as for shell
+ scripts:
+
+ 1. The first line of the Kermit script must begin with "#!"
+ immediately followed by the full pathname of the program that will
+ execute the script (in this case, C-Kermit rather than a UNIX
+ shell), followed by any Kermit command-line options. To suppress
+ execution of the C-Kermit initialization file and to make command
+ line arguments available to the script, the final option should be
+ "+":
+ #!/usr/local/bin/kermit +
+
+ Some users have reported that in some circumstances a space might
+ be necessary after the plus sign; this depends on your shell -- it
+ has nothing to do with Kermit. In most cases, no space is needed.
+ 2. The file must have execute permission (granted via "chmod +x
+ filename").
+
+ When C-Kermit is invoked from a Kerbang script (or from the system
+ prompt with a "+" command-line argument, which amounts to the same
+ thing), the following special rules apply:
+
+ 1. The C-Kermit initialization file is NOT executed automatically. If
+ you want it to be executed, include a TAKE command for it in the
+ script, e.g. "take \v(home).kermrc". (In previous releases, the
+ initialization file was always executed, with no way to prevent it
+ except for the user to include Kermit-specific command line options
+ which had nothing to do with the script). Many scripts have no need
+ for the standard Kermit initialization file, which is quite lengthy
+ and not only delays startup of the script, but also spews forth
+ numerous messages that are most likely unrelated to the script.
+ 2. If the initialization file is not executed, neither is your
+ customization file, since the initialization file is the command
+ file from which the customization file is TAKEn. Again, you can
+ include a TAKE command for the initialization file if desired, or
+ for the customization file by itself, or for any other file.
+ 3. C-Kermit does not process command-line arguments at all. Instead,
+ it passes all words on the command line after the "+" to the script
+ as \%0 (the script name), \%1..\%9 (the first nine arguments), as
+ well as in the argument vector array \&_[]. The variable \v(argc)
+ is set to the total number of "words" (as passed by the shell to
+ Kermit) including the script name. Quoting and grouping rules are
+ those of the shell.
+ 4. At any point where the script terminates, it must include an EXIT
+ command if you want it to exit back to the shell; otherwise
+ C-Kermit enters interactive prompting mode when the script
+ terminates. The EXIT command can include a numeric status to be
+ returned to the shell (0, 1, etc), plus an optional message.
+
+ Here is a simple Kerbang script that prints its arguments:
+
+ #/usr/local/bin/kermit +
+ echo Hello from \%0
+ for \%i 0 \v(argc)-1 1 {
+ echo \%i. "\&_[\%i]"
+ }
+ exit 0
+
+ Save this file as (say) "showargs", then give it execute permission and
+ run it (the \&_[] array is the same as \%0..\%9, but allows you to
+ refer to argument variables programmatically; see [628]Section 7.5).
+ (Yes, you could substitute SHOW ARGUMENTS for the loop.)
+
+ $ chmod +x showargs
+ $ ./showargs one "this is two" three
+
+ The script displays its arguments:
+
+ Hello from /usr/olga/showargs
+ 0. "/usr/olga/showargs"
+ 1. "one"
+ 2. "this is two"
+ 3. "three"
+ $
+
+ Notice that no banners or greetings are printed and that startup is
+ instantaneous, just like a shell script. Also notice that grouping of
+ arguments is determined by *shell* quoting rules, not Kermit ones,
+ since the command line is parsed by the shell before Kermit ever sees
+ it.
+
+ Of course you can put any commands at all into a Kerbang script. It can
+ read and write files, make connections, transfer files, anything that
+ Kermit can do -- because it *is* Kermit. And of course, Kerbang scripts
+ can also be executed from the Kermit prompt (or from another script)
+ with a TAKE command; the Kerbang line is ignored since it starts with
+ "#", which is a comment introducer to Kermit just as it is to the UNIX
+ shell. In VMS and other non-UNIX platforms, the Kerbang line has no
+ effect and can be omitted.
+
+ It might be desirable for a script to know whether it has been invoked
+ directly from the shell (as a Kerbang script) or by a TAKE command
+ given to the Kermit prompt or in a Kermit command file or macro. This
+ can be done as in this example:
+
+ #!/usr/local/bin/kermit +
+ assign \%m \fbasename(\%0)
+ define usage { exit 1 {usage: \%m phonenumber message} }
+ define apage { (definition of APAGE...) } ; (See [629]book pp.454-456)
+ xif equal "\%0" "\v(cmdfil)" {
+ if not def \%1 usage
+ if not def \%2 usage
+ apage {\%1} {\%2}
+ exit \v(status)
+ }
+
+ In a Kerbang script, \%0 and \v(cmdfile) are the same; both of them are
+ the name of the script. When a script is invoked by a Kermit TAKE
+ command, \%0 is the name of the Kermit program, but \v(cmdfile) is the
+ name of the script. In the example above, a macro called APAGE is
+ defined. If the script was invoked directly, the APAGE macro is also
+ executed. Otherwise, it is available for subsequent and perhaps
+ repeated use later in the Kermit session.
+
+ An especially handy use for Kerbang scripts is to have the
+ initialization file itself be one. Since the standard initialization
+ file is rather long and time-consuming to execute, it is often overkill
+ if you want to start Kermit just to transfer a file. Of course there
+ are command-line switches to suppress initialization-file execution,
+ etc, but another approach is to "run" the initialization file when you
+ want its features (notably the services directory), and run C-Kermit
+ directly when you don't. A setup like this requires that (a) the
+ C-Kermit initialization file is configured as a Kerbang script (has
+ #!/path.../kermit as first line), has execute permission, and is in
+ your PATH; and (b) that you don't have a .kermrc file in your login
+ directory.
+
+ 7.20. IF and XIF Statement Syntax
+
+ The IF command has been improved in two significant ways in C-Kermit
+ 7.0, described in the following subsections. All changes are backwards
+ compatible.
+
+ 7.20.1. The IF/XIF Distinction
+
+ The distinction between IF and XIF is no longer important as of
+ C-Kermit 7.0. You should be able to use IF in all cases (and of course,
+ also XIF for backwards compatibility). In the past, IF was used for
+ single-command THEN parts, followed optionally by a separate ELSE
+ command:
+
+ IF condition command1 ; THEN part
+ ELSE command2 ; ELSE part
+
+ whereas XIF was required if either part had multiple commands:
+
+ XIF condition { command, command, ... } ELSE { command, command, ... }
+
+ The syntactic differences were primarily that IF / ELSE was two
+ commands on two separate lines, whereas XIF was one command on one
+ line, and that XIF allowed (and in fact required) braces around its
+ command lists, whereas IF did not allow them.
+
+ Furthermore, the chaining or nesting of parts and conditions was
+ inconsistent. For example, the IF command could be used like this:
+
+ IF condition command
+ ELSE IF condition command
+ ELSE IF condition command
+ ELSE IF condition command
+ ...
+
+ but XIF could not. C-Kermit 7.0 accepts the old syntax and executes it
+ the same as previous versions, but also accepts a new unified and more
+ convenient syntax:
+
+ IF condition command-list [ ELSE command-list ]
+
+ or:
+
+IF condition command-list
+ELSE command-list
+
+ in which the ELSE part is optional, and where command-list can be a
+ single command (with or without braces around it) or a list of commands
+ enclosed in braces. Examples:
+
+ Example 1:
+
+ IF condition { command1, command2 } ELSE { command3, command4 }
+
+ Example 2 (same as Example 1):
+
+ IF condition {
+ command1
+ command2
+ } ELSE {
+ command3
+ command4
+ }
+
+ Example 3 (same as 1 and 2):
+
+ IF condition {
+ command1
+ command2
+ }
+ ELSE { command3, command4 }
+
+ Example 4 (same as 1-3):
+
+ IF condition {
+ command1
+ command2
+ }
+ ELSE {
+ command3
+ command4
+ }
+
+ Example 5 (ELSE can be followed by another command):
+
+ IF condition1 {
+ command1
+ command2
+ } ELSE IF condition2 {
+ command3
+ command4
+ } ELSE {
+ command5
+ command6
+ }
+
+ Example 5 suggests other possibilities:
+
+ IF condition {
+ command1
+ command2
+ } ELSE FOR variable initial final increment {
+ command3
+ command4
+ }
+
+ And this too is possible, except for some non-obvious quoting
+ considerations:
+
+ dcl \&a[6] = one two three four five six
+
+ IF < \%n 3 {
+ echo \\%n is too small: \%n
+ } ELSE FOR \\%i 1 \\%n 1 {
+ echo \\%i. \\&a[\\%i]
+ }
+
+ (The loop variable must be quoted in this context to prevent premature
+ evaluation.)
+
+ Many C programmers prefer to code IF-ELSE, WHILE, FOR, and SWITCH with
+ the block-open bracket on its own line. This does not work in Kermit:
+
+ IF condition ; THIS FORMAT DOES NOT NOT WORK
+ {
+ command1
+ command2
+ }
+ ELSE
+ {
+ command3
+ command4
+ }
+
+ Explanation: the Kermit command language is line oriented; each line is
+ a command, each command is a line. The first line above, having no hint
+ of continuation, is an incomplete command, yet syntactically correct --
+ an IF statement with an empty THEN part. Interestingly enough, since
+ the next line begins with "{" it is a block that (in [630]C-Kermit 8.0
+ and later) is a block that is executed unconditionally. Thus the
+ commands in the THEN part are executed regardless of whether the
+ condition is true -- not what you wanted!
+
+ The new block syntax used in the IF, WHILE, FOR, and SWITCH commands
+ employs certain tricks to allow multiple lines to be treated as a
+ single line:
+
+ * Any line ending with "{" (ignoring whitespace and comments) marks
+ the beginning of a block;
+ * Any line beginning with "}" (ignoring whitespace) marks the end of
+ a block;
+ * Line breaks within a block separate commands; the comma is implied
+ by the line end.
+
+ Thus:
+
+ IF condition {
+ command1
+ command2
+ } ELSE {
+ command3
+ command4
+ }
+
+ is "assembled" into:
+
+ IF condition { command1, command2 } ELSE { command3, command4 }
+
+ Note the addition of commas to separate commands within blocks. As
+ always, if you need continue a command onto additional lines, you can
+ end the continued lines with the continuation character, "-". You can
+ also do this if you want to put opening brackets on their own line:
+
+ IF condition -
+ {
+ command1
+ command2
+ }
+ ELSE -
+ {
+ command3
+ command4
+ }
+
+ 7.20.2. Boolean Expressions (The IF/WHILE Condition)
+
+ Prior to C-Kermit 7.0, the IF and WHILE commands accepted only a single
+ Boolean ("true or false") assertion, e.g. "if > \%m 0 command" or "if
+ exist filename command". There was no way to form Boolean expressions
+ and, in particular, nothing that approached a Boolean OR function (AND
+ could be simulated by concatenating IF statements: "if condition1 if
+ condition2..").
+
+ C-Kermit 7.0 (and K95 1.1.19) allow grouping of Boolean assertions
+ using parentheses and combining them using AND (or &&) and OR (or ||).
+ Each of these operators -- including the parentheses -- is a field and
+ must be set off by spaces. AND has higher precedence than OR, NOT has
+ higher precedence than AND, but parentheses can be used to force any
+ desired order of evaluation. The old syntax is still accepted.
+
+ Here are some examples:
+
+ define \%z 0 ; Define some variables
+ define \%n 1 ; for use in the examples.
+
+ if > \%n \%z echo \%n is greater. ; Original format - still accepted.
+ if ( > \%n \%z ) echo \%n is greater. ; Parentheses may be used in 7.0.
+ if ( > \%n \%z && not = \%z 0 ) ... ; Two assertions combined with AND.
+ if ( > \%n \%z and not = \%z 0 ) ... ; Same as previous ("and" = "&&").
+ if ( > \%n \%z || not = \%z 0 ) ... ; Two assertions combined with OR.
+ if ( > \%n \%z or not = \%z 0 ) ... ; Same as previous ("or" = "||").
+ if ( > \%n \%z || != \%z 0 ) ... ; Ditto ("!=" = "not =").
+ while ( 1 ) { ... } ; Just like C.
+
+ Notice the spaces around all operators including the parentheses --
+ these are required. The following examples show how parentheses can be
+ used to alter the precedence of the AND and OR operators:
+
+ if ( false || false && false || true ) ,.. ; True
+ if ( false || ( false && false ) || true ) ... ; Same as previous
+ if ( ( false || false ) && ( false || true ) ) ... ; False
+
+ Similarly for NOT:
+
+ if ( not true && false ) ... ; False (NOT binds to TRUE only)
+ if ( ( not true ) && false ) ... ; Same as previous
+ if ( not ( true && false ) ) ... ; True (NOT binds to (TRUE && FALSE))
+
+ Notes:
+
+ 1. The syntax of the Boolean expression itself has not changed; each
+ expression begins with a keyword or token such as "EXIST", ">", or
+ "=", etc; operators such as "<", "=", and ">" do not go between
+ their operands but precede them as before; this might be called
+ "reverse reverse Polish notation"; it allows deterministic
+ on-the-fly parsing of these expressions at the C-Kermit> prompt as
+ well as in scripts, and allows ?-help to be given for each item
+ when IF or WHILE commands are typed at the prompt.
+ 2. Parentheses are required when there is more than one Boolean
+ assertion.
+ 3. Parentheses are not required, but are allowed, when there is only
+ one Boolean assertion.
+ 4. Evaluation of Boolean assertions occurs left to right, but the
+ resulting Boolean expression is evaluated afterwards according to
+ the rules of precedence. All Boolean assertions are always
+ evaluated; there is no "early stopping" property and therefore no
+ question about when or if side effects will occur -- if any Boolean
+ assertion has side effects, they will always occur. (Early stopping
+ is, however, possible with the [631]S-Expression IF introduced in
+ C-Kermit 8.0.)
+
+ Constructions of arbitrary complexity are possible, within reason.
+
+ Also see [632]Section 7.4 for new IF / WHILE conditions.
+
+ 7.21. Screen Formatting and Cursor Control
+
+ C-Kermit 7.0 adds a simple way to create formatted screens, the SCREEN
+ command:
+
+ SCREEN { CLEAR, CLEOL, MOVE-TO row [ column ] }
+ Performs screen-formatting actions. Correct operation of these
+ commands depends on proper terminal setup on both ends of the
+ connection -- mainly that the host terminal type is set to agree
+ with the kind of terminal or the emulation you are viewing
+ C-Kermit through. The UNIX version uses terminfo or termcap (not
+ curses); the VMS version uses SMG; K-95 uses its built in screen
+ manager.
+
+ SCREEN CLEAR
+ Moves the cursor to home position and clears the entire screen.
+ Synonyms: CLEAR COMMAND-SCREEN ALL (K-95 only), CLS, CLEAR
+ SCREEN.
+
+ SCREEN CLEOL
+ Clears from the current cursor position to the end of the line.
+ Synonym: CLEAR COMMAND-SCREEN EOL (K-95 only)
+
+ SCREEN MOVE-TO row column
+ Moves the cursor to the indicated row and column. The row and
+ column numbers are 1-based, so on a 24x80 screen the home
+ position is 1 1 and the lower right corner is 24 80. If a row or
+ column number is given that too large for what Kermit or the
+ operating system thinks is your screen size, the appropriate
+ number is substituted.
+
+ These escape sequences used by these commands depends on the platform.
+ In UNIX, your TERM environment variable is used to query the
+ terminfo/termcap database; if the query fails, ANSI/VT100 sequences are
+ used. In VMS, the SMG library is used, which sends sequences based on
+ your VMS terminal type. K95 does its own screen control. On other
+ platforms (such as AOS/VS, VOS, etc), screen formatting is not
+ supported, and the SCREEN command does nothing.
+
+ The three SCREEN actions can be used in scripts to produce menus,
+ formatted screens, dynamic displays, etc. Related variables include:
+
+ \v(terminal) The type terminal C-Kermit thinks you have.
+ \v(rows) The number of rows C-Kermit thinks your terminal has.
+ \v(columns) The number of columns C-Kermit thinks your terminal has.
+
+ And functions:
+
+ \fscrncurx() The current X coordinate of the cursor (K-95 only).
+ \fscrncury() The current Y coordinate of the cursor (K-95 only).
+ \fscrnstr(x,y,n) The string of length nat position (x,y) (K-95 only).
+
+ And commands:
+
+ ECHO string Writes string + CRLF at the current cursor position.
+ XECHO string Writes string at current cursor position; CRLF not supplied.
+ GETC v prompt Issues prompt, reads one character into variable v, no echo.
+
+ And special characters:
+
+ Ctrl-L At the C-Kermit> command prompt, or in a C-Kermit command,
+ works like Return or Enter, but also clears the screen
+
+ Example 1: A macro that prints a message \%1 at cursor position
+ (\%2,\%3):
+
+ define MSG {
+ if not def \%3 def \%3 0 ; Default column to 0
+ if > \v(argc) 2 screen move \%2 \%3 ; Move to given row/col (if any)
+ screen cleol ; Clear to end of line
+ if def \%1 xecho \fcontents(\%1) ; Print message (if any)
+ }
+
+ Example 2: A macro put the cursor on the bottom screen line, left
+ margin:
+
+ define BOT {
+ screen move \v(rows) 0
+ }
+
+ Example 3: A macro to center message \%1 on line \%2.
+
+ define CENTER {
+ if not def \%2 def \%2 1
+ .\%x ::= (\v(cols)-\flen(\%1))/2
+ msg {\%1} {\%2} {\%x}
+ }
+
+ Example 4: A simple menu (building on Examples 1-3):
+
+ def \%c 0 ; Menu choice variable
+ screen clear ; Clear the screen
+ center {Welcome to This Menu} 2 ; Display the menu
+ msg {Choices:} 4
+ msg { 1. File} 6
+ msg { 2. Edit} 7
+ msg { 3. Exit} 8
+ while ( != \%c 3 ) { ; Read and verify choice
+ while true { ; Keep trying till we get a good one
+ screen move 10 ; Move to line 10
+ screen cleol ; Clear this line
+ getc \%c {Your choice: } ; Prompt and get and echo 1 character
+ xecho \%c
+ if ( not numeric \%c ) { msg {Not numeric - "\%c"} 12, continue }
+ if ( >= \%c 1 && <= \%c 3 ) break
+ msg {Out of range - "\%c"} 12
+ }
+ switch \%c { ; Valid choice - execute it.
+ :1, msg {Filing... } 12, break
+ :2, msg {Editing...} 12, break
+ :3, msg {Exiting...} 12, break
+ }
+ }
+ echo Bye ; Exit chosen - say goodbye.
+ bot ; Leave cursor at screen bottom.
+ exit ; And exit.
+
+ Similar scripts can work over the communication connection; substitute
+ INPUT and OUTPUT for GETC and ECHO/XECHO.
+
+ 7.22. Evaluating Arithmetic Expressions
+
+ A new arithmetic operator was added to the list recognized by the
+ EVALUATE command, the \feval() function, and which can also be used
+ anywhere else arithmetic expressions are accepted (numeric command
+ fields, array subscripts, etc):
+
+ Prefix "!"
+ This operator inverts the "truth value" of the number or
+ arithmetic expression that follows. If the value of the operand
+ is 0, the result is 1. If the value is nonzero, the result is 0.
+
+ Examples:
+
+ set eval old
+ evaluate 0
+ 0
+
+ evaluate !0
+ 1
+
+ evaluate !3
+ 0
+
+ evaluate !(-3)
+ 0
+
+ .\%a = 1
+ .\%b = 0
+ evaluate !(\%a|\%b)
+ 0
+
+ evaluate !(\%a&\%b)
+ 1
+
+ evaluate !(!(\%a&\%b))
+ 0
+
+ Note the distinction between Prefix ! (invert truth value) and Suffix !
+ (factorial). Also the distinction between Prefix ! and Prefix ~ (which
+ inverts all the bits in its operand). Also note that prefix operators
+ (!, -, and ~) can not be adjacent unless you use parentheses to
+ separate them, as shown in the final example above.
+
+ 7.23. Floating-Point Arithmetic
+
+ For a more convenient way of dealing with floating-point numbers
+ than the one described here, see the [633]C-Kermit 8.0 update notes,
+ the section on [634]S-Expressions.
+
+ C-Kermit 7.0 adds limited support for floating-point numbers (numbers
+ that have fractional parts, like 3.141592653). This support is provided
+ through a small repertoire of functions and in Boolean expressions that
+ compare numbers, but does not apply to number parsing in general, or to
+ expression evaluation, array subscripts, the INCREMENT and DECREMENT
+ commands, or in any context other than those listed in this section.
+
+ A floating point number has an optional sign (+ or -), followed by a
+ series of decimal digits containing either zero or one period (.)
+ character, which is the decimal point. The use of comma or any other
+ character besides period as a decimal point is not supported.
+ Scientific notation is not supported either. Examples of legal
+ floating-point numbers:
+
+ 0 Integers can be used
+ 1 Ditto
+ 2. A decimal point without decimal digits
+ 3.0 A decimal point with decimal digits
+ 3.141592653 Ditto
+ -4.0 A negative sign can be included
+ +5.0 A positive sign can be included
+
+ Examples of notations that are not accepted:
+
+ 1,000,000 Separators can not be used
+ 1.000.000 Ditto (or multiple decimal points)
+ 6.022137E23 No scientific notation
+ 6.62606868e-34 Ditto
+ 12.5+6.25 No "bare" expressions
+
+ You can use IF FLOAT test a string or variable to see if it's in
+ acceptable floating-point format. Example:
+
+ ask \%f { Type a number: }
+ if not def \%f .\%f = 0.0
+ if not float \%f stop 1 Invalid floating-point number: "\%f"
+
+ C-Kermit's floating-point support, like its support for whole numbers
+ (integers), relies on the capabilities of the underlying computer. Your
+ computer has only a limited amount of precision for numbers, depending
+ on its architecture. Thus floating-point numbers that have too many
+ digits will not be accurate; adding a very small number to a very large
+ one might have no effect at all; and so on. For details, read a text on
+ numerical analysis. Example:
+
+ .\%a = 11111111111111111111 ; A long number
+ .\%b = 22222222222222222222 ; Another one
+ echo \ffpadd(\%a,\%b) ; Add them - the result should be all 3's
+ 33333333333333330000.0 ; See the result
+
+ In this example, the computer has 16 digits of precision; after that,
+ the (low-order) digits are set to 0, since the computer doesn't know
+ what they really are. In fact, the computer returns random digits, but
+ Kermit sets all digits beyond the computer's precision to 0.
+
+ C-Kermit's floating-point functions have names of the form
+ "\ffpxxx(args)" ("\f" for function, "fp" for floating-point), where
+ "xxx" is replaced by the name of the function, such as "sqrt", and
+ "args" is the argument list, consisting of one or two floating-point
+ numbers (depending on the function), and an optional "d" argument that
+ says now many decimal places should be shown in the result. Example:
+
+ \ffpdiv(10,3,1) returns "3.3"
+ \ffpdiv(10,3,2) returns "3.33"
+ \ffpdiv(10,3,3) returns "3.333"
+
+ and so on, up to the precision of the computer. If the decimal-places
+ argument is less than zero, the fractional part of the result is
+ truncated:
+
+ \ffpdiv(10,3,-1) returns "3".
+
+ If the decimal-places argument is 0, or is omitted, C-Kermit returns as
+ many decimal places as are meaningful in the computer's floating-point
+ precision, truncating any extraneous trailing 0's:
+
+ \ffpdiv(10,8) returns "1.25".
+ \ffpdiv(10,4) returns "2.5".
+ \ffpdiv(10,2) returns "5.0".
+ \ffpdiv(10,3) returns "3.333333333333333" (for 16-digit precision).
+
+ There is no way to request that a floating-point function return a
+ decimal point but no decimal places. However, this is easy enough to
+ accomplish in other ways, for example by supplying it outside the
+ function call:
+
+ echo \ffpadd(\%a,\%b,-1).
+
+ Kermit's floating-point functions always round the result for the
+ requested number of decimal places when the "d" argument is given and
+ has a value greater than 0 (see the description of \ffpround() just
+ below).
+
+ Floating-point arguments can be constants in floating-point format or
+ variables whose values are floating-point numbers. If a floating-point
+ argument is omitted, or is a variable with no value, 0.0 is supplied
+ automatically. Example:
+
+ def \%x 999.999
+ undef \%y
+ echo \ffpmin(\%x,\%y)
+ 0.0
+
+ Or equivalently:
+
+ echo \ffpmin(999.999)
+ 0.0
+
+ The floating-point functions are:
+
+ \ffpround(f1,d)
+ Returns f1 rounded to d decimal places. For this function only,
+ d = 0 (or d omitted) has a special meaning: return the integer
+ part of f1 rounded according to the fractional part. Examples:
+
+ \ffpround(2.74653,-1) returns "2" (fraction truncated, no rounding).
+ \ffpround(2.74653,0) returns "3" (integer part is rounded).
+ \ffpround(2.74653) returns "3" (d omitted same as d = 0).
+ \ffpround(2.74653,1) returns "2.7".
+ \ffpround(2.74653,2) returns "2.75".
+ \ffpround(2.74653,3) returns "2.747".
+ \ffpround(2.74653,4) returns "2.7465", etc.
+
+ \ffpadd(f1,f2,d)
+ Returns the sum of f1 and f2.
+
+ \ffpsubtract(f1,f2,d)
+ Subtracts f2 from f1 and returns the result.
+
+ \ffpmultiply(f1,f2,d)
+ Returns the product of f1 and f2.
+
+ \ffpdivide(f1,f2,d)
+ If f2 is not 0, divides f1 by f2 and returns the quotient.
+ If f2 is 0, a DIVIDE_BY_ZERO error occurs.
+
+ \ffpraise(f1,f2,d)
+ If f1 = 0 and f2 <= 0, or if f1 < 0 and f2 has a fractional
+ part, an ARG_OUT_OF_RANGE error occurs; otherwise f1 raised to
+ the f2 power is returned.
+
+ \ffpsqrt(f1,d)
+ If f1 >= 0, returns the square root of f1; otherwise
+ ARG_OUT_OF_RANGE.
+
+ \ffpabsolute(f1,d)
+ Returns the absolute value of f1 (i.e. f1 without a sign). This
+ is the floating-point analog of \fabsolute(n1).
+
+ \ffpint(f1)
+ Returns the integer part of f1. Equivalent to \ffpround(f1,-1).
+
+ \ffpexp(f1,d)
+ The base of natural logarithms, e (2.718282...), raised to the
+ f1 power.
+
+ \ffplogn(f1,d)
+ The natural logarithm of f1 (the power to which e must be raised
+ to obtain f1).
+
+ \ffplog10(f1,d)
+ The base-10 logarithm of f1 (the power to which 10 must be
+ raised to obtain f1).
+
+ \ffpmodulus(f1,f2,d)
+ If f2 is not 0, the remainder after dividing f1 by f2.
+ If f2 is 0, a DIVIDE_BY_ZERO error occurs.
+ This is the floating-point analog of \fmod(n1,n2).
+
+ \ffpmaximum(f1,f2,d)
+ Returns the maximum of f1 and f2. This is the floating-point
+ analog of \fmax(n1,n2).
+
+ \ffpminimum(f1,f2,d)
+ Returns the minimum of f1 and f2. This is the floating-point
+ analog of \fmin(n1,n2).
+
+ \ffpsine(f1,d)
+ Returns the sine of f1 radians.
+
+ \ffpcosine(f1,d)
+ Returns the cosine of f1 radians.
+
+ \ffptangent(f1,d)
+ Returns the tangent of f1 radians.
+
+ Note that all of these functions can be used with integer arguments. If
+ you want an integer result, specify d = -1 (to truncate) or feed the
+ result to \ffpround(xxx,0) (to round).
+
+ Floating-point numbers (or variables or functions that return them) can
+ be used in Boolean expressions (see [635]Section 7.20.2) that compare
+ numbers:
+
+ = x y
+ != x y
+ < x y
+ > x y
+ <= x y
+ >= x y
+
+ In these examples, x and y can be either integers or floating-point
+ numbers in any combination. In an arithmetic comparison of an integer
+ and a floating-point number, the integer is converted to floating-point
+ before the comparison is made. Examples:
+
+ .\%t = 3.000000000
+ .\%f = 3.141592653
+ .\%i = 3
+
+ if > \%f \%i echo Pi is greater.
+ if = \%t \%i echo "\%i" = "\%t".
+
+ A floating-point number can also be used in:
+
+ IF number command
+
+ where the command is executed if the number is nonzero. If the number
+ is floating-point, the command is not executed if the number is 0.0,
+ and is executed otherwise.
+
+ Floating-point numbers can be sorted using ARRAY SORT /NUMERIC (see
+ [636]Section 7.10.5 ).
+
+ Two floating-point constants are provided:
+
+ \v(math_pi) = Pi (3.141592653...)
+ \v(math_e) = e, the base of natural logarithms (2.71828...)
+
+ These are given to the computer's precision, e.g. 16 digits. This
+ number itself is available in a variable:
+
+ \v(math_precision)
+ How many significant digits in a floating-point number.
+
+ 7.24. Tracing Script Execution
+
+ The TRACE command is handy for debugging scripts.
+
+ TRACE [ { /ON, /OFF } ] [ { ASSIGNMENTS, COMMAND-LEVEL, ALL } ]
+ Selects tracing of the given object.
+
+ Optional switches are /ON and /OFF. If no switch is given, /ON is
+ implied. The trace objects are ASSIGNMENTS, COMMAND-LEVEL, and ALL. The
+ default object is ALL, meaning to select all trace objects (besides
+ ALL). Thus TRACE by itself selects tracing of everything, as does TRACE
+ /ON, and TRACE /OFF turns off all tracing.
+
+ When tracing of ASSIGNMENTS is on, every time the value of any
+ user-defined variable or macro changes, C-Kermit prints one of the
+ following:
+
+ >>> name: "value"
+ The name of the variable or macro followed by the new value in
+ quotes. This includes implicit macro-parameter assignments
+ during macro invocation.
+
+ >>> name: (undef)
+ This indicates that the variable or macro has been undefined.
+
+ <<< name: "value"
+ For RETURN statements: the name of the macro and the return
+ value.
+
+ <<< name: (null)
+ For RETURN statements that include no value or an empty value.
+
+ When tracing of COMMAND-LEVEL is on, C-Kermit prints:
+
+ [n] +F: "name"
+ Whenever a command file is entered, where "n" is the command
+ level (0 = top); the name of the command file is shown in
+ quotes.
+
+ [n] +M: "name"
+ Whenever a macro is entered; "n" is the command level. The name
+ of the macro is shown in quotes.
+
+ [n] -F: "name"
+ Whenever a command file is reentered from below, when a macro or
+ command file that it has invoked has returned.
+
+ [n] -M: "name"
+ Whenever a macro is reentered from below.
+
+ For other debugging tools, see SHOW ARGS, SHOW STACK, SET TAKE, SET
+ MACRO, and of course, ECHO.
+
+ 7.25. Compact Substring Notation
+
+ It is often desirable to extract a substring from a string which is
+ stored in a variable, and for this we have the \fsubstring() function,
+ which is used like this:
+
+ define \%a 1234567890
+ echo \fsubstring(\%a,3,4) ; substring from 3rd character length 4
+ 3456
+
+ or like this with macro-named variables:
+
+ define string 1234567890
+ echo \fsubstring(\m(string),3,4)
+ 3456
+
+ C-Kermit 7.0 adds a pair of alternative compact notations:
+
+\:(variablename[start:length]) <-- Substring of variable's value
+\s(macroname[start:length]) <-- Substring of macro's definition
+
+ These are exactly equivalent to using \fsubstring(), except more
+ compact to write and also faster since evaluation is in one step
+ instead of two.
+
+ The "\:()" notation can be used with any Kermit variable, that is,
+ almost anything that starts with a backslash:
+
+ \:(\%a[2:6]) <-- equivalent to \fsubstring(\%a,2,6)
+ \:(\&x[1][2:6]) <-- equivalent to \fsubstring(\&x[1],2,6)
+ \:(\m(foo)[2:6]) <-- equivalent to \fsubstring(\m(foo),2,6)
+ \:(\v(time)[2:6]) <-- equivalent to \fsubstring(\v(time),2,6)
+ \:(\$(TERM)[2:6]) <-- equivalent to \fsubstring(\$(TERM),2,6)
+ \:(ABCDEFGH[2:6]) <-- equivalent to \fsubstring(ABCDEFGH,2,6)
+
+ Whatever appears between the left parenthesis and the left bracket is
+ evaluated and then the indicated substring of the result is returned.
+
+ The "\s()" notation is the same, except after evaluating the variable,
+ the result is treated as a macro name and is looked up in the macro
+ table. Then the indicated substring of the macro definition is
+ returned. Example:
+
+ define testing abcdefghijklmnopqrstuvwxyz
+ define \%a testing
+
+ \s(testing[2:6]) --> bcdefg
+ \:(testing[2:6]) --> esting
+ \:(\%a[2:6]) --> esting
+ \s(\%a[2:6]) --> bcdefg
+
+ Note that the following two examples are equivalent:
+
+ \:(\m(foo)[2:6])
+ \s(foo[2:6])
+
+ The first number in the brackets is the 1-based starting position. If
+ it is omitted, or less than 1, it is treated as 1. If it is greater
+ than the length of the string, an empty string is returned.
+
+ The second number is the length of the desired substring. If the second
+ number is omitted, is less than 0, or would be past the end of the
+ string, then "through the end of the string" is assumed. If it is 0,
+ the empty string is returned.
+
+ If the brackets are empty or omitted, the original string is returned.
+
+ The starting position and length need not be literal numbers; they can
+ also be variables, functions, arithmetic expressions, or even other
+ \s() or \:() quantities; anything that evaluates to a number, for
+ example:
+
+ \s(block[1025:\fhex2n(\s(block[\%b:\%n+4]))/2])
+
+ Syntactically, \m(name) and \s(name) differ only in that the sequence
+ [*] at the end of the name (where * is any sequence of 0 or more
+ characters) is treated as substring notation in \s(name), but is
+ considered part of the name in \m(name) (to see why, see [637]Section
+ 7.10.9).
+
+ 7.26. New WAIT Command Options
+
+ The WAIT command has been extended to allow waiting for different kinds
+ of things (formerly it only waited for modem signals). Now it also can
+ wait for file events.
+
+ 7.26.1. Waiting for Modem Signals
+
+ The previous syntax:
+
+ WAIT time { CD, DSR, RTS, RI, ... }
+
+ has changed to:
+
+ WAIT time MODEM-SIGNALS { CD, DSR, RTS, RI, ... }
+
+ However, the previous syntax is still accepted. The behavior is the
+ same in either case.
+
+ 7.26.2. Waiting for File Events
+
+ The new WAIT option:
+
+ WAIT time FILE { CREATION, DELETION, MODIFICATION } filename
+
+ lets you tell Kermit to wait the given amount of time (or until the
+ given time of day) for a file whose name is filename to be created,
+ deleted, or modified, respectively. The filename may not contain
+ wildcards. If the specified event does not occur within the time limit,
+ or if WAIT CANCELLATION is ON and you interrupt from the keyboard
+ before the time is up, the WAIT command fails. If the event is
+ MODIFICATION and the file does not exist, the command fails. Otherwise,
+ if the given event occurs within the time limit, the command succeeds.
+ Examples:
+
+ WAIT 600 FILE DELETION oofa.tmp
+ Wait up to 10 minutes for file oofa.tmp to disappear.
+
+ WAIT 23:59:59 FILE MOD orders.db
+ Wait until just before midnight for the orders.db file to be
+ changed.
+
+ Example: Suppose you want to have the current copy of /etc/motd on your
+ screen at all times, and you want to hear a bell whenever it changes:
+
+ def \%f /etc/motd ; The file of interest.
+ while 1 { ; Loop forever...
+ cls ; Clear the screen.
+ echo \%f: \v(date) \v(time)... ; Print 2-line heading...
+ echo
+ if ( not exist \%f ) { ; If file doesn't exist,
+ echo \%f does not exist... ; print message,
+ wait 600 file creat \%f ; and wait for it to appear.
+ continue
+ }
+ beep ; Something new - beep.
+ type /head:\v(rows-2) \%f ; Display the file
+ if fail exit 1 \%f: \ferrstring() ; (checking for errors).
+ wait 999 file mod \%f ; Wait for it to change.
+ }
+
+ This notices when the file is created, deleted, or modified, and acts
+ only then (or when you interrupt it with); the time shown in the
+ heading is the time of the most recent event (including when the
+ program started).
+
+ See [638]Section 1.10, where the \v(kbchar) variable is explained. This
+ lets you modify a loop like the one above to also accept
+ single-character commands, which interrupt the WAIT, and dispatch
+ accordingly. For example:
+
+ wait 999 file mod \%f ; Wait for the file to change.
+ if defined \v(kbchar) { ; Interrupted from keyboard?
+ switch \v(kbchar) { ; Handle the keystroke...
+ :q, exit ; Q to Quit
+ :h, echo blah blah, break ; H for Help
+ :default, beep, continue ; Anything else beep and ignore
+ }
+ }
+
+ This lets you write event-driven applications that wait for up to three
+ events at once: a file or modem event, a timeout, and a keystroke.
+
+ 7.27. Relaxed FOR and SWITCH Syntax
+
+ For consistency with the extended IF and WHILE syntax, the FOR and
+ SWITCH control lists may (but need not be) enclosed in parentheses:
+
+ FOR ( \%i 1 \%n 1 ) { command-list... }
+ SWITCH ( \%c ) { command-list... }
+
+ In the FOR command, the increment item can be omitted if the control
+ list is enclosed in parentheses, in which case the increment defaults
+ appropriately to 1 or -1, depending on the values of the first two
+ variables.
+
+ As with IF, the parentheses around the FOR-command control list must be
+ set off by spaces (in the SWITCH command, the spaces are not required
+ since the SWITCH expression is a single arithmetic expression).
+
+ Also, outer braces around the command list are supplied automatically
+ if you omit them, e.g.:
+
+ FOR ( \%i 1 %n 1 ) echo \%i
+
+ 8. USING OTHER FILE TRANSFER PROTOCOLS
+
+ In C-Kermit 7.0, alternative protocols can be selected using switches.
+ Switches are described in [639]Section 1.5; the use of
+ protocol-selection switches is described in [640]Section 4.7.1.
+ Example:
+
+ send /binary /protocol:zmodem x.tar.gz
+
+ Note that file transfer recovery works only with Kermit and Zmodem
+ protocols. With Zmodem, recovery can be initiated only by the sender.
+
+ Only pre-1988 versions of the publicly-distributed sz/rz programs use
+ Standard I/O; those released later than that do not use Standard I/O
+ and therefore do not work with REDIRECT. However, Omen Technology does
+ offer an up-to-date redirectable version called crzsz, which must be
+ licensed for use:
+
+ "Unix Crz and Csz support XMODEM, YMODEM, and ZMODEM transfers when
+ called by dial-out programs such as Kermit and certain versions of
+ cu(1). They are clients designed for this use.
+
+ "Crz and Csz are Copyrighted shareware programs. Use of these
+ programs beyond a brief evaluation period requires registration.
+ Please print the "mailer.rz" file, fill out the form and return same
+ with your registration."
+
+ To use the crzsz programs as your external XYZMODEM programs in
+ C-Kermit, follow the instructions in the book, but put a "c" before
+ each command, e.g.:
+
+ set protocol zmodem {csz %s} {csz -a %s} crz crz crz crz
+
+ To use Zmodem protocol over Telnet or other non-transparent
+ connections, you might need to add the -e (Escape) option:
+
+ set protocol zmodem {csz -e %s} {csz -e -a %s} crz crz crz crz
+
+ 9. COMMAND-LINE OPTIONS
+
+ 9.0. Extended-Format Command-Line Options
+
+ Standard UNIX command line options are a single letter. C-Kermit has
+ run out of letters, so new options are in a new extended format:
+
+ --word[:arg]
+
+ where a keyword (rather than a single letter) specifies the function,
+ and if an argument is to be included, it is separated by a colon (or
+ equal sign). Most of the new extended-format command-line options are
+ only for use with the Internet Kermit Service Daemon; see the [641]IKSD
+ Administration Guide for details. However, several of them are also
+ general in nature:
+
+ --nointerrupts
+ Disables keyboard interrupts that are normally enabled, which
+ are usually Ctrl-C (to interrupt a command) and Ctrl-Z (UNIX
+ only, to suspend C-Kermit).
+
+ --help
+ Lists the extended command-line options that are available in
+ your version of C-Kermit. If any options seem to be missing,
+ that is because your copy of C-Kermit was built with
+ compile-time options to deselect them.
+
+ --helpfile:filename
+ Specifies the name of a file to be displayed if the user types
+ HELP (not followed by a specific command or topic), in place of
+ the built-in top-level help text. The file need not fit on one
+ screen; more-prompting is used if the file is more than one
+ screen long if COMMAND MORE-PROMPTING is ON, as it is by
+ default.
+
+ --bannerfile:filename
+ The name of a file containing a message to be printed after the
+ user logs in, in place of the normal message (Copyright notice,
+ "Type HELP or ? for help", "Default transfer mode is...", etc).
+
+ --cdmessage:{on,off,0,1,2}
+ For use in the Server-Side Server configuration; whenever the
+ client tells the server to change directory, the server sends
+ the contents of a "read me" file to the client's screen. This
+ feature is On by default, and operates only in client/server
+ mode when ON or 1. If set to 2 or higher, it also operates when
+ the CD command is given at the IKSD> prompt. Synonym: --cdmsg.
+
+ --cdfile:filename
+ When cdmessage is on, this is the name of the "read me" file to
+ be sent. Normally you would specify a relative (not absolute)
+ name, since the file is opened using the literal name you
+ specified, after changing to the new directory. Example:
+
+ --cdfile:READ.ME
+
+ You can also give a list of up to 8 filenames by (a) enclosing
+ each filename in braces, and (b) enclosing the entire list in
+ braces. Example:
+ --cdfile:{{./.readme}{READ.ME}{aaareadme.txt}{README}{read-this-
+ first}} When a list is given, it is searched from left to right
+ and the first file found is displayed. The default list for UNIX
+ is:
+
+ {{./.readme}{README.TXT}{READ.ME}}
+
+ 9.1. Command Line Personalities
+
+ Beginning in version 7.0, if the C-Kermit binary is renamed to "telnet"
+ (or TELNET.EXE, telnet.pr, etc, depending on the platform), it accepts
+ the Telnet command line:
+
+ telnet [ host [ port ] ]
+
+ In Unix, you can achieve the same effect with a symlink:
+
+ cd /usr/bin
+ mv telnet oldtelnet
+ ln -ls /usr/local/bin/kermit telnet
+
+ When installed in this manner, C-Kermit always reads its initialization
+ file. If no host (and therefore no port) is given, C-Kermit starts in
+ interactive prompting mode. If a host is given as the first
+ command-line argument, C-Kermit makes a connection to it. The host
+ argument can be an IP host name or address, or the name of a TCP/IP
+ entry in your C-Kermit network directory.
+
+ If a port is given, it is used. If a port is not given, then if the
+ hostname was found in your network directory and port was also listed
+ there, then that port is used. Otherwise port 23 (the Telnet port) is
+ used.
+
+ When C-Kermit is called "telnet" and it is invoked with a hostname on
+ the command line, it exits automatically when the connection is closed.
+ While the connection is open, however, you may escape back and forth as
+ many times as you like, transfer files, etc.
+
+ An rlogin personality is also available, but it is less useful, at
+ least in UNIX and VMS, where the Rlogin TCP port is privileged.
+
+ The new variable \v(name) indicates the name with which C-Kermit was
+ invoked ("kermit", "wermit", "k95", "telnet", etc).
+
+ 9.2. Built-in Help for Command Line Options
+
+ "kermit -h", given from the system prompt, lists as many command-line
+ options as will fit on a standard 24x80 screen. For more comprehensive
+ help, use the interactive HELP OPTIONS command that was added in
+ C-Kermit 7.0:
+
+ HELP OPTIONS
+ Explains how command-line options work, their syntax, etc.
+
+ HELP OPTIONS ALL
+ Lists all command-line options and gives brief help about each one.
+
+ HELP OPTION x
+ Gives brief help about option "x".
+
+ HELP EXTENDED-OPTIONS
+ Lists the available extended-format command-line options.
+
+ HELP EXTENDED-OPTION xxx
+ Gives help for the specified extended option.
+
+ 9.3. New Command-Line Options
+
+ Command-line options added since C-Kermit 6.0 are:
+
+ +
+ (plus sign by itself): The next argument is the name of a script
+ to execute; all subsequent arguments are ignored by C-Kermit
+ itself, but passed to the script as top-level copies of \%1,
+ \%2, etc; the \&_[] is also set accordingly. \%0 and \&_[0]
+ become the name of the script file, rather than the pathname of
+ the C-Kermit program, which is its normal value. Primarily for
+ use in the top line of "Kerbang" scripts in UNIX (see
+ [642]Section 7.19). Example from UNIX command line:
+
+ $ kermit [ regular kermit args ] + filename
+
+ Sample first line of Kerbang script:
+
+ #!/usr/local/bin/kermit +
+
+ --
+ (two hyphens surrounded by whitespace) Equivalent to "=", for
+ compatibility with UNIX getopt(1,3).
+
+ -G
+ GET (like -g), but send the incoming file to standard output.
+ Example: "kermit -G oofa.txt | lpr" retrieves a file from your
+ local computer (providing it is running a Kermit program that
+ supports the autodownload feature and has it enabled) and prints
+ it.
+
+ -O
+ equivalent to -x (start up in server mode), but exits after the
+ first client command has been executed (mnemonic: O = Only One).
+ This one is handy replacing "kermit -x" in the "automatically
+ start Kermit on the other end" string:
+
+ set protocol kermit {kermit -ir} {kermit -r} {kermit -x}
+
+ since -x leaves the remote Kermit in server mode after the
+ transfer, which can be confusing, whereas -O makes it go away
+ automatically after the transfer.
+
+ -L
+ Recursive, when used in combination with -s (mnemonic: L =
+ Levels). In UNIX or other environments where the shell expands
+ wildcards itself, the -s argument, if it contains wildcards,
+ must be quoted to prevent this, e.g.:
+
+ kermit -L -s "*.c"
+
+ In UNIX only, "kermit -L -s ." means to send the current
+ directory tree. See [643]Sections 4.10 and [644]4.11 about
+ recursive file transfer.
+
+ -V
+ Equivalent to SET FILE PATTERNS OFF ([645]Section 4.3) and SET
+ TRANSFER MODE MANUAL. In other words, take the FILE TYPE setting
+ literally. For example, "kermit -VT oofa.bin" means send the
+ file in Text mode, no matter what its name is and no matter
+ whether a kindred spirit is recognized at the other end of the
+ connection.
+
+ -0
+ (digit zero) means "be 100% transparent in CONNECT mode". This
+ is equivalent to the following series of commands: SET PARITY
+ NONE, SET COMMAND BYTESIZE 8, SET TERMINAL BYTESIZE 8, SET FLOW
+ NONE, SET TERM ESCAPE DISABLED, SET TERM CHAR TRANSPARENT, SET
+ TERM AUTODOWNLOAD OFF, SET TERM APC OFF, SET TELOPT KERMIT
+ REFUSE REFUSE.
+
+ 10. C-KERMIT AND G-KERMIT
+
+ Every multifunctioned and long-lived software program grows in
+ complexity and size over time to meet the needs and requests of its
+ users and the demands of the underlying technology as it changes.
+
+ Eventually users begin to notice how big the application has grown, how
+ much disk space it occupies, how long it takes to load, and they start
+ to long for the good old days when it was lean and mean. Not long after
+ that they begin asking for a "light" version that only does the basics
+ with no frills.
+
+ And so it is with C-Kermit. A "light" version of Kermit was released
+ (for UNIX only) in December 1999 under the GNU General Public License;
+ thus it is called G-Kermit (for GNU Kermit). All it does is send and
+ receive files, period. You can find it at:
+
+ [646]http://www.columbia.edu/kermit/gkermit.html
+
+ Where the C-Kermit 7.0 binary might be anywhere from 1 to 3 million
+ bytes in size, the G-Kermit binary ranges from 30K to 100K, depending
+ on the underlying architecture (RISC vs CISC, etc).
+
+ G-Kermit and C-Kermit may reside side-by-side on the same computer.
+ G-Kermit does not make connections; it does not have a script language;
+ it does not translate character sets. G-Kermit may be used instead of
+ C-Kermit when:
+
+ * It is on the remote end.
+ * Files are to be transferred in binary mode or in text mode without
+ character-set translation.
+ * File timestamps don't need to be preserved.
+
+ In such cases G-Kermit might be preferred since it generally starts up
+ faster, and yet transfers files just as fast on most (but not
+ necessarily all) kinds of connections; for example, it supports
+ streaming ([647]Section 4.20).
+
+ G-Kermit is also handy for bootstrapping. It is easier to load on a new
+ computer than C-Kermit -- it fits on a floppy diskette with plenty of
+ room to spare. Thus if you have (say) an old PC running (say) SCO Xenix
+ and no network connection, you can download the Xenix version of
+ G-Kermit to (say) a DOS or Windows PC, copy it to diskette, read the
+ diskette on Xenix with "dosread", and then use G-Kermit to receive
+ C-Kermit (which does not fit on a diskette). If diskettes aren't an
+ option, other bootstrapping methods are possible too -- see the
+ [648]G-Kermit web page for details.
+
+III. APPENDICES
+
+ III.1. Character Set Tables
+
+ III.1.1. The Hewlett Packard Roman8 Character Set
+
+dec col/row oct hex description
+160 10/00 240 A0 (Undefined)
+161 10/01 241 A1 A grave
+162 10/02 242 A2 A circumflex
+163 10/03 243 A3 E grave
+164 10/04 244 A4 E circumflex
+165 10/05 245 A5 E diaeresis
+166 10/06 246 A6 I circumflex
+167 10/07 247 A7 I diaeresis
+168 10/08 250 A8 Acute accent
+169 10/09 251 A9 Grave accent
+170 10/10 252 AA Circumflex accent
+171 10/11 253 AB Diaeresis
+172 10/12 254 AC Tilde accent
+173 10/13 255 AD U grave
+174 10/14 256 AE U circumflex
+175 10/15 257 AF Lira symbol
+176 11/00 260 B0 Top bar (macron)
+177 11/01 261 B1 Y acute
+178 11/02 262 B2 y acute
+179 11/03 263 B3 Degree Sign
+180 11/04 264 B4 C cedilla
+181 11/05 265 B5 c cedilla
+182 11/06 266 B6 N tilde
+183 11/07 267 B7 n tilde
+184 11/08 270 B8 Inverted exclamation mark
+185 11/09 271 B9 Inverted question mark
+186 11/10 272 BA Currency symbol
+187 11/11 273 BB Pound sterling symbol
+188 11/12 274 BC Yen symbol
+189 11/13 275 BD Paragraph
+190 11/14 276 BE Florin (Guilder) symbol
+191 11/15 277 BF Cent symbol
+192 12/00 300 C0 a circumflex
+193 12/01 301 C1 e circumflex
+194 12/02 302 C2 o circumflex
+195 12/03 303 C3 u circumflex
+196 12/04 304 C4 a acute
+197 12/05 305 C5 e acute
+198 12/06 306 C6 o acute
+199 12/07 307 C7 u acute
+200 12/08 310 C8 a grave
+201 12/09 311 C9 e grave
+202 12/10 312 CA o grave
+203 12/11 313 CB u grave
+204 12/12 314 CC a diaeresis
+205 12/13 315 CD e diaeresis
+206 12/14 316 CE o diaeresis
+207 12/15 317 CF u diaeresis
+208 13/00 320 D0 A ring
+209 13/01 321 D1 i circumflex
+210 13/02 322 D2 O with stroke
+211 13/03 323 D3 AE digraph
+212 13/04 324 D4 a ring
+213 13/05 325 D5 i acute
+214 13/06 326 D6 o with stroke
+215 13/07 327 D7 ae digraph
+216 13/08 330 D8 A diaeresis
+217 13/09 331 D9 i grave
+218 13/10 332 DA O diaeresis
+219 13/11 333 DB U diaeresis
+220 13/12 334 DC E acute
+221 13/13 335 DD i diaeresis
+222 13/14 336 DE German sharp s
+223 13/15 337 DF O circumflex
+224 14/00 340 E0 A acute
+225 14/01 341 E1 A tilde
+226 14/02 342 E2 a tilde
+227 14/03 343 E3 Icelandic Eth
+228 14/04 344 E4 Icelandic eth
+229 14/05 345 E5 I acute
+230 14/06 346 E6 I grave
+231 14/07 347 E7 O acute
+232 14/08 350 E8 O grave
+233 14/09 351 E9 O tilde
+234 14/10 352 EA o tilde
+235 14/11 353 EB S caron
+236 14/12 354 EC s caron
+237 14/13 355 ED U acute
+238 14/14 356 EE Y diaeresis
+239 14/15 357 EF y diaeresis
+240 15/00 360 F0 Icelandic Thorn
+241 15/01 361 F1 Icelandic thorn
+242 15/02 362 F2 Middle dot
+243 15/03 363 F3 Greek mu
+244 15/04 364 F4 Pilcrow sign
+245 15/05 365 F5 Fraction 3/4
+246 15/06 366 F6 Long dash, horizontal bar
+247 15/07 367 F7 Fraction 1/4
+248 15/08 370 F8 Fraction 1/2
+249 15/09 371 F9 Feminine ordinal
+250 15/10 372 FA Masculine ordinal
+251 15/11 373 FB Left guillemot
+252 15/12 374 FC Solid box
+253 15/13 375 FD Right guillemot
+254 15/14 376 FE Plus or minus sign
+255 15/15 377 FF (Undefined)
+
+ III.1.2. Greek Character Sets
+
+ III.1.2.1. The ISO 8859-7 Latin / Greek Alphabet = ELOT 928
+
+dec col/row oct hex description
+160 10/00 240 A0 No-break space
+161 10/01 241 A1 Left single quotation mark
+162 10/02 242 A2 right single quotation mark
+163 10/03 243 A3 Pound sign
+164 10/04 244 A4 (UNUSED)
+165 10/05 245 A5 (UNUSED)
+166 10/06 246 A6 Broken bar
+167 10/07 247 A7 Paragraph sign
+168 10/08 250 A8 Diaeresis (Dialytika)
+169 10/09 251 A9 Copyright sign
+170 10/10 252 AA (UNUSED)
+171 10/11 253 AB Left angle quotation
+172 10/12 254 AC Not sign
+173 10/13 255 AD Soft hyphen
+174 10/14 256 AE (UNUSED)
+175 10/15 257 AF Horizontal bar (Parenthetiki pavla)
+176 11/00 260 B0 Degree sign
+177 11/01 261 B1 Plus-minus sign
+178 11/02 262 B2 Superscript two
+179 11/03 263 B3 Superscript three
+180 11/04 264 B4 Accent (tonos)
+181 11/05 265 B5 Diaeresis and accent (Dialytika and Tonos)
+182 11/06 266 B6 Alpha with accent
+183 11/07 267 B7 Middle dot (Ano Teleia)
+184 11/08 270 B8 Epsilon with accent
+185 11/09 271 B9 Eta with accent
+186 11/10 272 BA Iota with accent
+187 11/11 273 BB Right angle quotation
+188 11/12 274 BC Omicron with accent
+189 11/13 275 BD One half
+190 11/14 276 BE Upsilon with accent
+191 11/15 277 BF Omega with accent
+192 12/00 300 C0 iota with diaeresis and accent
+193 12/01 301 C1 Alpha
+194 12/02 302 C2 Beta
+195 12/03 303 C3 Gamma
+196 12/04 304 C4 Delta
+197 12/05 305 C5 Epsilon
+198 12/06 306 C6 Zeta
+199 12/07 307 C7 Eta
+200 12/08 310 C8 Theta
+201 12/09 311 C9 Iota
+202 12/10 312 CA Kappa
+203 12/11 313 CB Lamda
+204 12/12 314 CC Mu
+205 12/13 315 CD Nu
+206 12/14 316 CE Ksi
+207 12/15 317 CF Omicron
+208 13/00 320 D0 Pi
+209 13/01 321 D1 Rho
+210 13/02 322 D2 (UNUSED)
+211 13/03 323 D3 Sigma
+212 13/04 324 D4 Tau
+213 13/05 325 D5 Upsilon
+214 13/06 326 D6 Phi
+215 13/07 327 D7 Khi
+216 13/08 330 D8 Psi
+217 13/09 331 D9 Omega
+218 13/10 332 DA Iota with diaeresis
+219 13/11 333 DB Upsilon with diaeresis
+220 13/12 334 DC alpha with accent
+221 13/13 335 DD epsilon with accent
+222 13/14 336 DE eta with accent
+223 13/15 337 DF iota with accent
+224 14/00 340 E0 upsilon with diaeresis and accent
+225 14/01 341 E1 alpha
+226 14/02 342 E2 beta
+227 14/03 343 E3 gamma
+228 14/04 344 E4 delta
+229 14/05 345 E5 epsilon
+230 14/06 346 E6 zeta
+231 14/07 347 E7 eta
+232 14/08 350 E8 theta
+233 14/09 351 E9 iota
+234 14/10 352 EA kappa
+235 14/11 353 EB lamda
+236 14/12 354 EC mu
+237 14/13 355 ED nu
+238 14/14 356 EE ksi
+239 14/15 357 EF omicron
+240 15/00 360 F0 pi
+241 15/01 361 F1 rho
+242 15/02 362 F2 terminal sigma
+243 15/03 363 F3 sigma
+244 15/04 364 F4 tau
+245 15/05 365 F5 upsilon
+246 15/06 366 F6 phi
+247 15/07 367 F7 khi
+248 15/08 370 F8 psi
+249 15/09 371 F9 omega
+250 15/10 372 FA iota with diaeresis
+251 15/11 373 FB upsilon with diaeresis
+252 15/12 374 FC omicron with diaeresis
+253 15/13 375 FD upsilon with accent
+254 15/14 376 FE omega with accent
+255 15/15 377 FF (UNUSED)
+
+ III.1.2.2. The ELOT 927 Character Set
+
+dec col/row oct hex description
+ 32 02/00 40 20 SPACE
+ 33 02/01 41 21 EXCLAMATION MARK
+ 34 02/02 42 22 QUOTATION MARK
+ 35 02/03 43 23 NUMBER SIGN
+ 36 02/04 44 24 DOLLAR SIGN
+ 37 02/05 45 25 PERCENT SIGN
+ 38 02/06 46 26 AMPERSAND
+ 39 02/07 47 27 APOSTROPHE
+ 40 02/08 50 28 LEFT PARENTHESIS
+ 41 02/09 51 29 RIGHT PARENTHESIS
+ 42 02/10 52 2A ASTERISK
+ 43 02/11 53 2B PLUS SIGN
+ 44 02/12 54 2C COMMA
+ 45 02/13 55 2D HYPHEN, MINUS SIGN
+ 46 02/14 56 2E PERIOD, FULL STOP
+ 47 02/15 57 2F SOLIDUS, SLASH
+ 48 03/00 60 30 DIGIT ZERO
+ 49 03/01 61 31 DIGIT ONE
+ 50 03/02 62 32 DIGIT TWO
+ 51 03/03 63 33 DIGIT THREE
+ 52 03/04 64 34 DIGIT FOUR
+ 53 03/05 65 35 DIGIT FIVE
+ 54 03/06 66 36 DIGIT SIX
+ 55 03/07 67 37 DIGIT SEVEN
+ 56 03/08 70 38 DIGIT EIGHT
+ 57 03/09 71 39 DIGIT NINE
+ 58 03/10 72 3A COLON
+ 59 03/11 73 3B SEMICOLON
+ 60 03/12 74 3C LESS-THAN SIGN, LEFT ANGLE BRACKET
+ 61 03/13 75 3D EQUALS SIGN
+ 62 03/14 76 3E GREATER-THAN SIGN, RIGHT ANGLE BRACKET
+ 63 03/15 77 3F QUESTION MARK
+ 64 04/00 100 40 COMMERCIAL AT SIGN
+ 65 04/01 101 41 CAPITAL LETTER A
+ 66 04/02 102 42 CAPITAL LETTER B
+ 67 04/03 103 43 CAPITAL LETTER C
+ 68 04/04 104 44 CAPITAL LETTER D
+ 69 04/05 105 45 CAPITAL LETTER E
+ 70 04/06 106 46 CAPITAL LETTER F
+ 71 04/07 107 47 CAPITAL LETTER G
+ 72 04/08 110 48 CAPITAL LETTER H
+ 73 04/09 111 49 CAPITAL LETTER I
+ 74 04/10 112 4A CAPITAL LETTER J
+ 75 04/11 113 4B CAPITAL LETTER K
+ 76 04/12 114 4C CAPITAL LETTER L
+ 77 04/13 115 4D CAPITAL LETTER M
+ 78 04/14 116 4E CAPITAL LETTER N
+ 79 04/15 117 4F CAPITAL LETTER O
+ 80 05/00 120 50 CAPITAL LETTER P
+ 81 05/01 121 51 CAPITAL LETTER Q
+ 82 05/02 122 52 CAPITAL LETTER R
+ 83 05/03 123 53 CAPITAL LETTER S
+ 84 05/04 124 54 CAPITAL LETTER T
+ 85 05/05 125 55 CAPITAL LETTER U
+ 86 05/06 126 56 CAPITAL LETTER V
+ 87 05/07 127 57 CAPITAL LETTER W
+ 88 05/08 130 58 CAPITAL LETTER X
+ 89 05/09 131 59 CAPITAL LETTER Y
+ 90 05/10 132 5A CAPITAL LETTER Z
+ 91 05/11 133 5B LEFT SQUARE BRACKET
+ 92 05/12 134 5C REVERSE SOLIDUS, BACKSLASH
+ 93 05/13 135 5D RIGHT SQUARE BRACKET
+ 94 05/14 136 5E CIRCUMFLEX ACCENT
+ 95 05/15 137 5F UNDERSCORE
+ 96 06/00 140 60 ACCENT GRAVE
+ 97 06/01 141 61 GREEK LETTER ALPHA
+ 98 06/02 142 62 GREEK LETTER BETA
+ 99 06/03 143 63 GREEK LETTER GAMMA
+100 06/04 144 64 GREEK LETTER DELTA
+101 06/05 145 65 GREEK LETTER EPSILON
+102 06/06 146 66 GREEK LETTER ZETA
+103 06/07 147 67 GREEK LETTER ETA
+104 06/08 150 68 GREEK LETTER THETA
+105 06/09 151 69 GREEK LETTER IOTA
+106 06/10 152 6A GREEK LETTER KAPPA
+107 06/11 153 6B GREEK LETTER LAMDA
+108 06/12 154 6C GREEK LETTER MU
+109 06/13 155 6D GREEK LETTER NU
+110 06/14 156 6E GREEK LETTER KSI
+111 06/15 157 6F GREEK LETTER OMICRON
+112 07/00 160 70 GREEK LETTER PI
+113 07/01 161 71 GREEK LETTER RHO
+114 07/02 162 72 GREEK LETTER SIGMA
+115 07/03 163 73 GREEK LETTER TAU
+116 07/04 164 74 GREEK LETTER UPSILON
+117 07/05 165 75 GREEK LETTER FI
+118 07/06 166 76 GREEK LETTER XI
+119 07/07 167 77 GREEK LETTER PSI
+120 07/08 170 78 GREEK LETTER OMEGA
+121 07/09 171 79 SPACE
+122 07/10 172 7A SPACE
+123 07/11 173 7B LEFT CURLY BRACKET, LEFT BRACE
+124 07/12 174 7C VERTICAL LINE, VERTICAL BAR
+125 07/13 175 7D RIGHT CURLY BRACKET, RIGHT BRACE
+126 07/14 176 7E TILDE
+127 07/15 177 7F RUBOUT, DELETE
+
+ III.1.2.3. PC Code Page 869
+
+ (to be filled in...)
+
+ III.2. Updated Country Codes
+
+ Date: Mon, 7 Apr 1997 23:23:49 EDT
+ From: Dave Leibold <dleibold@else.net>
+ Newsgroups: comp.dcom.telecom
+ Subject: Ex-USSR Country Codes Profile
+ Organization: TELECOM Digest
+
+ Ex-USSR Country Codes Profile
+ 4 April 1997
+
+ Below is a summary of the country codes that have formed in the wake of
+ the USSR dissolution, along with some updated findings and reports.
+ Additional or corrected information on any of these nations would be
+ welcome (c/o dleibold@else.net).
+ * Kyrgyz Republic country code 996 will take effect, at least in
+ Canada, effective 1 May 1997, according to CRTC Telecom Order
+ 97-464, based on Stentor Tariff Notice 433. There is no indication
+ whether there will be a permissive dialing period involved or for
+ how long such a permissive operation would remain.
+ * Country code 992 was reported as a recent assignment for
+ Tajikistan, which will be moving from country code 7 at some
+ unknown time.
+ * Uzbekistan has its own country code assignment, but I have no
+ information if this is in service yet or what implementation dates
+ have been set.
+ * Kazakstan does not have a known separate country code assignment at
+ present. It remains in country code 7 for the time being.
+ * Russia seems destined to keep country code 7.
+ * Recent news reports speak of some agreements forming between Russia
+ and Belarus. While there is no outright reunification yet, there is
+ expected to be much closer ties between the two nations. Whether
+ this will lead to a reunification of telephone codes remains to be
+ seen.
+
+ In the table, "Effective" means the date at which the country code
+ began service (which could vary according to the nation). "Mandatory"
+ means the date at which the country code 7 is invalid for calls to that
+ nation. There are a number of question marks since exact dates have not
+ been collected in all cases.
+
+CC Nation Effective Mandatory Notes
+
+370 Lithuania 1993? ??? Announced Jan 1993
+371 Latvia 1993? ???
+372 Estonia 1 Feb 1993? March 1993?
+373 Moldova 1993? ??? Announced Jan 1993
+374 Armenia 1 May 1995 1 July 1995 Announced Jan 1995 (ITU)
+375 Belarus 16 Apr 1995 1997?
+380 Ukraine 16 Apr 1995 Oct 1995?
+7 Kazakstan (no known changes)
+7 Russia (presumably not changing)
+992 Tajikistan ??? ??? Announced 1996-7?
+993 Turkmenistan 3 Jan 1997 3 Apr 1997 Canada as of 29 Nov 1996
+994 Azerbaijan Sept 1994? ??? Announced 1992
+995 Georgia 1994? ??? ref: Telecom Digest Oct 1994
+996 Kyrgyz Republic 1 May 1997 ??? ref: Stentor Canada/CRTC
+998 Uzbekistan ??? ??? Announced 1996? (ITU)
+
+ Details courtesy Toby Nixon, ITU, Stentor (Canada), CRTC (Canada),
+ TELECOM Digest (including information collected for the country code
+ listings).
+
+IV. ERRATA & CORRIGENDA
+
+ The following errors in [649]Using C-Kermit, Second Edition, first
+ printing, have been noted.
+
+ First, some missing acknowledgements for C-Kermit 6.0: JE Jones of
+ Microware for help with OS-9, Nigel Roles for his help with Plan 9,
+ Lucas Hart for help with VMS and Digital UNIX, Igor Kovalenko for his
+ help with QNX. And later, to Susan Kleinmann for her help with Debian
+ Linux packaging; Patrick Volkerding for his help with Slackware Linux
+ packaging; Jim Knoble for his help with Red Hat Linux packaging; and to
+ dozens of others for sending individual C-Kermit binaries for varied
+ and diverse platforms.
+
+ Thanks to James Spath for both binaries and reporting many of the typos
+ noted below. Also to Dat Thuc Nguyen for spotting several typos.
+
+PAGE REMARKS
+COVER "COS" is a misprint. There is no COS. Pretend it says "SCO" or "VOS".
+ (This is fixed in the second printing.)
+ xxi Second line: Fred Smith's affiliation should be Computrition.
+ 83 Change "commands other" to "commands as other" (1st paragraph)
+ 87 Change "The the" to "The" (2nd paragraph)
+ 92 "set modem-type user-defined supra" should be "set modem type ..."
+ 95 Change "VI" to "vi" (1st paragraph)
+ 96 Change "it it" to "it is" (1st paragraph)
+ 97 Change "advantage a literal" to "advantage of a literal" (2nd
+ paragraph)
+102 The call-waiting example would be better as SET DIAL PREFIX *70W
+ (rather than "*70,") because the former will not cause an incorrect
+ call to be placed with pulse dialing.
+123 Third paragraph from bottom: "..otherwise if a your local username.."
+ should be "..otherwise your local username..".
+160 Delete the "it" between "and" and "to" (2nd paragraph)
+185 In "When TRANSFER DISPLAY is OFF, C-Kermit skips the display...",
+ "OFF" should be "NONE".
+187 The last paragraph says the "A command" is ignored, should be "S".
+194 Change "it known" to "it is known" (4th paragraph).
+235 In C-Kermit 7.0, the syntax of the GET command changed. MGET now
+ must be used to get a list of files and there is no more multiline
+ GET command.
+268 Last paragraph: "effect" should be "affect".
+275 In the SET PROTOCOL KERMIT description, the following sentence is
+ incorrect and should be removed: 'If you omit the commands, the
+ default ones are restored: "kermit -ir" and "kermit -r" respectively".
+ The correct information is given at the bottom of page 281.
+279 9th line. The decimal value of ST is 156, not 155.
+295 In the stepping stones, skip ahead to Chapter 17 on p. 327.
+298 Table 16-2, Portuguese entry. Column 4/00 should show section sign,
+ not acute accent.
+316 Other languages written in the Hebrew alphabet include Karaim (a Turkic
+ language spoken in Lithuania and Poland), Judeo-Kurdish, and Judeo-
+ Georgian.
+332 UNDEFINE definition, change "This just" to "This is just".
+344 It might be necessary to set the modem's pulse generation rate when
+ sending numeric pages; most Hayes compatible modems use the S11
+ register for this.
+350 Delete "is" from between "It" and "ceases" (4th paragraph)
+351 Top - both occurrences of "print \%a" should be "echo \%a".
+364 \v(input) and \v(query) out of alphabetical order.
+378 In the MYSEND macro, "if not \m(rc) goto bad" should be:
+ "if \m(rc) goto bad" (remove the "not").
+382-383 It should be stated that the loop control variable must be of the \%a
+ type, or else an array element; macro names can not be used for this.
+383 In line 3, "\%f[\%i]" should be "\&f[\%i]".
+383 In the sort example, it should be stated that the array is 1-based.
+387 Change "You can list" to "You can get a list" (5th paragraph)
+393 \Fverify() description. The 3rd sentence could be stated more clearly
+ as "If all characters in string2 are also in string1, 0 is returned."
+398 Copying \ffiles() results to an array before is not required as of
+ C-Kermit 7.0 (see [650]Section 7.3).
+403 In "(\%a + 3) * (\%b 5)", a minus sign is missing between b and 5.
+407 C-Kermit 7.0 no longer supports multiline GET. Change
+ "get, \%1, \%2" to "get {\%1} {\%2}" or "get /as:{\%2} {\%1}".
+409 READ example while loop should be:
+ while success { echo \m(line), read line }
+409 "WRITE file" should be "WRITE keyword" (you can't put a filename there)
+ (The same applies to WRITE-LINE / WRITELN).
+414 \Funhexify() missing from Table 18-3.
+425 MINPUT definition, change 2nd "text2" to "text3".
+436 Several lines are missing from the UNIXLOGIN macro listing.
+ After the "xif fail" block, insert:
+
+ out \%1\13 ; Send username, carriage return
+ inp 5 Password: ; Wait 5 sec for this prompt
+ if fail end 1 No password prompt
+ pause ; Wait a sec
+ out \%2\13 ; Send password
+
+440 Change "set terminal byteszie" to "set terminal bytesize".
+ Change "input Password:" to "input 10 Password".
+448 Franchise script: "access line" should be "access \m(line)".
+453 There are two incorrectly coded IF statements in the DELIVER macro
+ definition. Replace both occurrences of "if > \%1 \%3 {" with
+ "xif > \%i \%3 {" (replace "if" by "xif" and "\%1" with "\%i").
+453 "the the" (last paragraph) should be "the".
+454 EOT (last paragraph) is End of Transmission, not End of Text.
+457 _DEFINE definition: "name constructed" should be "name is constructed".
+457 "macro for and" (last paragraph) should be "macro and".
+459 Should explain that \v(user) is a legal abbreviation of \v(userid).
+480 Figure II-2 is backwards; the least-significant bit is transmitted
+ first, then up to the highest, and the parity bit last.
+534 The VMS Appendix section on Odd Record Lengths no longer applies;
+ C-Kermit 7.0 handles odd record lengths as well as even ones.
+559 Table VIII-3, Portuguese entry. Column 4/00 should show section sign,
+ not acute accent.
+560-563 HP-Roman8 missing from Table VII-4; there wasn't room to squeeze it in.
+ It is listed in section II(6).
+565 "d stroke" in Table VII-5 has the wrong appearance; the stem should
+ be upright. The letter shown in the table is actually a lowercase
+ Icelandic eth, which has a curved stem.
+601-604 BeBox, BeOS, Plan 9, and probably others not listed in trademarks.
+604 The words "SCRIBE TEXT FORMATTER" appear at the end of the last
+ sentence of the first paragraph of the Colophon. They should have
+ been in the Index.
+Index: Missing entries: SET { SEND, RECEIVE } PATHNAMES, Call waiting, ...
+ \F() Page 605, add also 413-414
+ \Fbreak 389
+ \Fcapitalize 390
+ \Fchecksum 414
+ \Fcrc16 414
+ \Fexecute 414
+ \Fhexify 390
+ \Fltrim 391
+ \Frepeat 392
+ \Fspawn 392
+ \Ftod2secs 399
+ \v() built_in Page 606, add also 361-364
+ \v(_line) 354, 361
+ \v(apcactive) 361
+ \v(charset) 362
+ \v(cpu) 362
+ \v(crc16) 357, 362
+ \v(d$xxx) add page 362
+ \v(dialnumber) 362
+ \v(dialresult) 362
+ \v(errno) 362
+ \v(errstring) 362
+ \v(exedir) 362
+ \v(inidir) 363
+ \v(ipaddress) 363
+ \v(keyboard) 363
+ \v(macro) 363
+ \v(minput) 363
+ \v(m_xxx) 94, 363
+ \v(password) 364
+ \v(query) 364
+ \v(prompt) 364
+ \v(speed) 356, 364
+ \v(startup) 364
+ \v(status) 364
+ \v(sysid) 364
+ \v(system) 364
+ \v(fsize) at lower half page 606 should read \v(tfsize)
+ \v(xversion) 364
+ BEEP Command 40
+ SET FLOW 62, 212
+
+ Figure II-5 on page 493. The pin assignments of the Mini Din-8
+ connector are not described anywhere. As noted in the text, these tend
+ to vary from vendor to vendor. One common arrangement is:
+
+ 1. HSKout (Handshake out -- definition depends on software)
+ 2. HSKin (Handshake in or external clock)
+ 3. TxD-
+ 4. Not used
+ 5. RxD-
+ 6. TxD+
+ 7. Not used
+ 8. RxD+
+
+ Note the "balanced pairs" for Receive Data (RxD) and Transmit Data
+ (TxD), and the utter lack of modem signals. These connectors follow the
+ RS-423 standard, rather than RS-232. In some arrangements, Pin 1 is
+ used for DTR and Pin 2 for CD; in others Pin 1 is RTS and Pin 2 is CTS.
+
+ Please send reports of other errors to the authors, as well as
+ suggestions for improvements, additional index entries, and any other
+ comments:
+
+ [651]kermit@columbia.edu
+
+APPENDIX V. ADDITIONAL COPYRIGHT NOTICES
+
+ The following copyrights cover some of the source code used in the
+ development of C-Kermit, Kermit 95, or Kermit 95 support libraries.
+
+/*****************************************************************************/
+/* */
+/* Copyright (c) 1995 by Oy Online Solutions Ltd. */
+/* */
+/* Distribution of this source code is strictly forbidden. Use of this */
+/* source code is granted to the University of Columbia C-Kermit project */
+/* to be distributed in binary format only. Please familiarize yourself */
+/* with the accompanying LICENSE.P file. */
+/* */
+/*****************************************************************************/
+
+ used for Xmodem, Ymodem, and Zmodem protocol in Kermit 95 (p95.dll,
+ p2.dll)
+
+ Copyright (c) 1997 Stanford University
+
+ The use of this software for revenue-generating purposes may require a
+ license from the owners of the underlying intellectual property.
+ Specifically, the SRP-3 protocol may not be used for revenue-generating
+ purposes without a license.
+
+ Within that constraint, permission to use, copy, modify, and distribute
+ this software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notices and this
+ permission notice appear in all copies of the software and related
+ documentation.
+
+ THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+ IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+ ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ SOFTWARE.
+
+ Used for Secure Remote Password (TM) protocol (SRP) in C-Kermit, Kermit
+ 95 (k95.exe, k2.exe, k95crypt.dll, k2crypt.dll)
+
+ Copyright 1990 by the Massachusetts Institute of Technology. All Rights
+ Reserved.
+
+ Export of this software from the United States of America may require a
+ specific license from the United States Government. It is the
+ responsibility of any person or organization contemplating export to
+ obtain such a license before exporting.
+
+ WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ this software and its documentation for any purpose and without fee is
+ hereby granted, provided that the above copyright notice appear in all
+ copies and that both that copyright notice and this permission notice
+ appear in supporting documentation, and that the name of M.I.T. not be
+ used in advertising or publicity pertaining to distribution of the
+ software without specific, written prior permission. M.I.T. makes no
+ representations about the suitability of this software for any purpose.
+ It is provided "as is" without express or implied warranty.
+
+ Used for Telnet Authentication Option, Telnet Encryption Option, and
+ Kerberos (TM) authentication in C-Kermit, Kermit 95 (k95.exe, k2.exe,
+ k95crypt.dll, k2crypt.dll)
+
+ Copyright (c) 1991, 1993 The Regents of the University of California.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the
+ distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgement:
+
+ This product includes software developed by the University of
+ California, Berkeley and its contributors.
+ 4. Neither the name of the University nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Used for Telnet Authentication Option, Telnet Encryption Option, and
+ Kerberos (TM) authentication in C-Kermit, Kermit 95 (k95.exe, k2.exe,
+ k95crypt.dll, k2crypt.dll)
+
+ Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) All rights
+ reserved.
+
+ This package is an DES implementation written by Eric Young
+ (eay@cryptsoft.com). The implementation was written so as to conform
+ with MIT's libdes.
+
+ This library is free for commercial and non-commercial use as long as
+ the following conditions are aheared to. The following conditions apply
+ to all code found in this distribution.
+
+ Copyright remains Eric Young's, and as such any Copyright notices in
+ the code are not to be removed. If this package is used in a product,
+ Eric Young should be given attribution as the author of that the SSL
+ library. This can be in the form of a textual message at program
+ startup or in documentation (online or textual) provided with the
+ package.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ 1. Redistributions of source code must retain the copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the
+ distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgement: This product
+ includes software developed by Eric Young (eay@cryptsoft.com)
+
+ THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ The license and distribution terms for any publically available version
+ or derivative of this code cannot be changed. i.e. this code cannot
+ simply be copied and put under another distribution license [including
+ the GNU Public License.]
+
+ The reason behind this being stated in this direct manner is past
+ experience in code simply being copied and the attribution removed from
+ it and then being distributed as part of other packages. This
+ implementation was a non-trivial and unpaid effort.
+
+ Used DES encryption in Kermit 95 (k95crypt.dll, k2crypt.dll)
+ __________________________________________________________________
+
+ * This is version 1.1 of CryptoLib
+ *
+ * The authors of this software are Jack Lacy, Don Mitchell and Matt Blaze
+ * Copyright (c) 1991, 1992, 1993, 1994, 1995 by AT&T.
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * NOTE:
+ * Some of the algorithms in cryptolib may be covered by patents.
+ * It is the responsibility of the user to ensure that any required
+ * licenses are obtained.
+ *
+ *
+ * SOME PARTS OF CRYPTOLIB MAY BE RESTRICTED UNDER UNITED STATES EXPORT
+ * REGULATIONS.
+ *
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+
+ Used for Big Number library in Kermit 95 (k95crypt.dll, k2crypt.dll).
+
+ [ [652]Top ] [ [653]C-Kermit ] [ [654]Kermit Home ]
+ __________________________________________________________________
+
+ CKERMIT70.HTM / The Kermit Project / Columbia University / 8 Feb 2000 /
+ Last update: 8 Aug 2011
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+ 12. mailto:kermit-support@columbia.edu
+ 13. http://www.columbia.edu/kermit/
+ 14. http://www.kermit-project.org/
+ 15. http://www.columbia.nyc.ny.us/kermit/
+ 16. ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
+ 17. ftp://kermit.columbia.edu/kermit/f/ckcmai.c
+ 18. http://www.columbia.edu/kermit/ckermit70.html#xv
+ 19. http://www.columbia.edu/kermit/ckb2.htm
+ 20. ftp://kermit.columbia.edu/kermit/f/ckcbwr.txt
+ 21. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 22. ftp://kermit.columbia.edu/kermit/f/ckvbwr.txt
+ 23. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 24. ftp://kermit.columbia.edu/kermit/f/ckermit70.txt
+ 25. ftp://kermit.columbia.edu/kermit/f/security.txt
+ 26. http://www.columbia.edu/kermit/security.htm
+ 27. ftp://kermit.columbia.edu/kermit/f/iksd.txt
+ 28. http://www.columbia.edu/kermit/iksd.htm
+ 29. http://www.columbia.edu/kermit/cuiksd.htm
+ 30. ftp://kermit.columbia.edu/kermit/f/telnet.txt
+ 31. http://www.columbia.edu/kermit/telnet.htm
+ 32. ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
+ 33. http://www.columbia.edu/kermit/k95.html
+ 34. http://www.opensource.org/
+ 35. http://www.columbia.edu/kermit/ckb2.htm
+ 36. http://www.columbia.edu/kermit/ckermit70.html#xi
+ 37. http://www.columbia.edu/kermit/ckermit70.html#xii
+ 38. http://www.columbia.edu/kermit/ckermit70.html#x0
+ 39. http://www.columbia.edu/kermit/ckermit70.html#x1
+ 40. http://www.columbia.edu/kermit/ckermit70.html#x1.0
+ 41. http://www.columbia.edu/kermit/ckermit70.html#x1.1
+ 42. http://www.columbia.edu/kermit/ckermit70.html#x1.2
+ 43. http://www.columbia.edu/kermit/ckermit70.html#x1.3
+ 44. http://www.columbia.edu/kermit/ckermit70.html#x1.4
+ 45. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 46. http://www.columbia.edu/kermit/ckermit70.html#x1.5.1
+ 47. http://www.columbia.edu/kermit/ckermit70.html#x1.5.2
+ 48. http://www.columbia.edu/kermit/ckermit70.html#x1.5.3
+ 49. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 50. http://www.columbia.edu/kermit/ckermit70.html#x1.5.5
+ 51. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 52. http://www.columbia.edu/kermit/ckermit70.html#x1.7
+ 53. http://www.columbia.edu/kermit/ckermit70.html#x1.8
+ 54. http://www.columbia.edu/kermit/ckermit70.html#x1.9
+ 55. http://www.columbia.edu/kermit/ckermit70.html#x1.10
+ 56. http://www.columbia.edu/kermit/ckermit70.html#x1.11
+ 57. http://www.columbia.edu/kermit/ckermit70.html#x1.11.1
+ 58. http://www.columbia.edu/kermit/ckermit70.html#x1.11.2
+ 59. http://www.columbia.edu/kermit/ckermit70.html#x1.11.3
+ 60. http://www.columbia.edu/kermit/ckermit70.html#x1.11.4
+ 61. http://www.columbia.edu/kermit/ckermit70.html#x1.11.5
+ 62. http://www.columbia.edu/kermit/ckermit70.html#x1.11.6
+ 63. http://www.columbia.edu/kermit/ckermit70.html#x1.11.7
+ 64. http://www.columbia.edu/kermit/ckermit70.html#x1.12
+ 65. http://www.columbia.edu/kermit/ckermit70.html#x1.13
+ 66. http://www.columbia.edu/kermit/ckermit70.html#x1.14
+ 67. http://www.columbia.edu/kermit/ckermit70.html#x1.15
+ 68. http://www.columbia.edu/kermit/ckermit70.html#x1.16
+ 69. http://www.columbia.edu/kermit/ckermit70.html#x1.17
+ 70. http://www.columbia.edu/kermit/ckermit70.html#x1.18
+ 71. http://www.columbia.edu/kermit/ckermit70.html#x1.19
+ 72. http://www.columbia.edu/kermit/ckermit70.html#x1.20
+ 73. http://www.columbia.edu/kermit/ckermit70.html#x1.21
+ 74. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 75. http://www.columbia.edu/kermit/ckermit70.html#x1.22.1
+ 76. http://www.columbia.edu/kermit/ckermit70.html#x1.22.2
+ 77. http://www.columbia.edu/kermit/ckermit70.html#x1.22.3
+ 78. http://www.columbia.edu/kermit/ckermit70.html#x1.22.4
+ 79. http://www.columbia.edu/kermit/ckermit70.html#x1.22.5
+ 80. http://www.columbia.edu/kermit/ckermit70.html#x1.22.6
+ 81. http://www.columbia.edu/kermit/ckermit70.html#x1.22.7
+ 82. http://www.columbia.edu/kermit/ckermit70.html#x1.22.8
+ 83. http://www.columbia.edu/kermit/ckermit70.html#x1.23
+ 84. http://www.columbia.edu/kermit/ckermit70.html#x1.24
+ 85. http://www.columbia.edu/kermit/ckermit70.html#x2
+ 86. http://www.columbia.edu/kermit/ckermit70.html#x2.0
+ 87. http://www.columbia.edu/kermit/ckermit70.html#x2.1
+ 88. http://www.columbia.edu/kermit/ckermit70.html#x2.1.1
+ 89. http://www.columbia.edu/kermit/ckermit70.html#x2.1.2
+ 90. http://www.columbia.edu/kermit/ckermit70.html#x2.1.3
+ 91. http://www.columbia.edu/kermit/ckermit70.html#x2.1.4
+ 92. http://www.columbia.edu/kermit/ckermit70.html#x2.1.5
+ 93. http://www.columbia.edu/kermit/ckermit70.html#x2.1.6
+ 94. http://www.columbia.edu/kermit/ckermit70.html#x2.1.7
+ 95. http://www.columbia.edu/kermit/ckermit70.html#x2.1.8
+ 96. http://www.columbia.edu/kermit/ckermit70.html#x2.1.9
+ 97. http://www.columbia.edu/kermit/ckermit70.html#x2.1.10
+ 98. http://www.columbia.edu/kermit/ckermit70.html#x2.1.11
+ 99. http://www.columbia.edu/kermit/ckermit70.html#x2.1.12
+ 100. http://www.columbia.edu/kermit/ckermit70.html#x2.1.13
+ 101. http://www.columbia.edu/kermit/ckermit70.html#x2.1.14
+ 102. http://www.columbia.edu/kermit/ckermit70.html#x2.1.15
+ 103. http://www.columbia.edu/kermit/ckermit70.html#x2.1.16
+ 104. http://www.columbia.edu/kermit/ckermit70.html#x2.2
+ 105. http://www.columbia.edu/kermit/ckermit70.html#x2.2.1
+ 106. http://www.columbia.edu/kermit/ckermit70.html#x2.2.2
+ 107. http://www.columbia.edu/kermit/ckermit70.html#x2.3
+ 108. http://www.columbia.edu/kermit/ckermit70.html#x2.3.0
+ 109. http://www.columbia.edu/kermit/ckermit70.html#x2.3.1
+ 110. http://www.columbia.edu/kermit/ckermit70.html#x2.3.2
+ 111. http://www.columbia.edu/kermit/ckermit70.html#x2.3.3
+ 112. http://www.columbia.edu/kermit/ckermit70.html#x2.3.4
+ 113. http://www.columbia.edu/kermit/ckermit70.html#x2.3.5
+ 114. http://www.columbia.edu/kermit/ckermit70.html#x2.3.6
+ 115. http://www.columbia.edu/kermit/ckermit70.html#x2.4
+ 116. http://www.columbia.edu/kermit/ckermit70.html#x2.5
+ 117. http://www.columbia.edu/kermit/ckermit70.html#x2.6
+ 118. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 119. http://www.columbia.edu/kermit/ckermit70.html#x2.7.0
+ 120. http://www.columbia.edu/kermit/ckermit70.html#x2.7.1
+ 121. http://www.columbia.edu/kermit/ckermit70.html#x2.7.2
+ 122. http://www.columbia.edu/kermit/ckermit70.html#x2.7.3
+ 123. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4
+ 124. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.1
+ 125. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.2
+ 126. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.3
+ 127. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.4
+ 128. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.5
+ 129. http://www.columbia.edu/kermit/ckermit70.html#x2.8
+ 130. http://www.columbia.edu/kermit/ckermit70.html#x2.9
+ 131. http://www.columbia.edu/kermit/ckermit70.html#x2.9.1
+ 132. http://www.columbia.edu/kermit/ckermit70.html#x2.9.2
+ 133. http://www.columbia.edu/kermit/ckermit70.html#x2.10
+ 134. http://www.columbia.edu/kermit/ckermit70.html#x2.11
+ 135. http://www.columbia.edu/kermit/ckermit70.html#x2.12
+ 136. http://www.columbia.edu/kermit/ckermit70.html#x2.13
+ 137. http://www.columbia.edu/kermit/ckermit70.html#x2.14
+ 138. http://www.columbia.edu/kermit/ckermit70.html#x2.15
+ 139. http://www.columbia.edu/kermit/ckermit70.html#x3
+ 140. http://www.columbia.edu/kermit/ckermit70.html#x3.1
+ 141. http://www.columbia.edu/kermit/ckermit70.html#x3.2
+ 142. http://www.columbia.edu/kermit/ckermit70.html#x3.3
+ 143. http://www.columbia.edu/kermit/ckermit70.html#x3.4
+ 144. http://www.columbia.edu/kermit/ckermit70.html#x4
+ 145. http://www.columbia.edu/kermit/ckermit70.html#x4.0
+ 146. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 147. http://www.columbia.edu/kermit/ckermit70.html#x4.1.1
+ 148. http://www.columbia.edu/kermit/ckermit70.html#x4.1.2
+ 149. http://www.columbia.edu/kermit/ckermit70.html#x4.1.3
+ 150. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 151. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1
+ 152. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.1
+ 153. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.2
+ 154. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.3
+ 155. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 156. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2.1
+ 157. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2.2
+ 158. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3
+ 159. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3.1
+ 160. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3.2
+ 161. http://www.columbia.edu/kermit/ckermit70.html#x4.2.4
+ 162. http://www.columbia.edu/kermit/ckermit70.html#x4.2.5
+ 163. http://www.columbia.edu/kermit/ckermit70.html#x4.2.6
+ 164. http://www.columbia.edu/kermit/ckermit70.html#x4.2.7
+ 165. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8
+ 166. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.1
+ 167. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.2
+ 168. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.3
+ 169. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.4
+ 170. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 171. http://www.columbia.edu/kermit/ckermit70.html#x4.3.1
+ 172. http://www.columbia.edu/kermit/ckermit70.html#x4.3.2
+ 173. http://www.columbia.edu/kermit/ckermit70.html#x4.3.3
+ 174. http://www.columbia.edu/kermit/ckermit70.html#x4.3.4
+ 175. http://www.columbia.edu/kermit/ckermit70.html#x4.4
+ 176. http://www.columbia.edu/kermit/ckermit70.html#x4.4.1
+ 177. http://www.columbia.edu/kermit/ckermit70.html#x4.4.1.1
+ 178. http://www.columbia.edu/kermit/ckermit70.html#x4.4.1.2
+ 179. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2
+ 180. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.1
+ 181. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.1.1
+ 182. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.1.2
+ 183. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.2
+ 184. http://www.columbia.edu/kermit/ckermit70.html#x4.5
+ 185. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 186. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2
+ 187. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2.1
+ 188. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2.2
+ 189. http://www.columbia.edu/kermit/ckermit70.html#x4.5.3
+ 190. http://www.columbia.edu/kermit/ckermit70.html#x4.5.4
+ 191. http://www.columbia.edu/kermit/ckermit70.html#x4.6
+ 192. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 193. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 194. http://www.columbia.edu/kermit/ckermit70.html#x4.7.2
+ 195. http://www.columbia.edu/kermit/ckermit70.html#x4.7.3
+ 196. http://www.columbia.edu/kermit/ckermit70.html#x4.8
+ 197. http://www.columbia.edu/kermit/ckermit70.html#x4.8.1
+ 198. http://www.columbia.edu/kermit/ckermit70.html#x4.8.2
+ 199. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 200. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 201. http://www.columbia.edu/kermit/ckermit70.html#x4.9.2
+ 202. http://www.columbia.edu/kermit/ckermit70.html#x4.9.3
+ 203. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 204. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 205. http://www.columbia.edu/kermit/ckermit70.html#x4.11.1
+ 206. http://www.columbia.edu/kermit/ckermit70.html#x4.11.2
+ 207. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 208. http://www.columbia.edu/kermit/ckermit70.html#x4.11.4
+ 209. http://www.columbia.edu/kermit/ckermit70.html#x4.11.5
+ 210. http://www.columbia.edu/kermit/ckermit70.html#x4.11.6
+ 211. http://www.columbia.edu/kermit/ckermit70.html#x4.12
+ 212. http://www.columbia.edu/kermit/ckermit70.html#x4.13
+ 213. http://www.columbia.edu/kermit/ckermit70.html#x4.14
+ 214. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 215. http://www.columbia.edu/kermit/ckermit70.html#x4.16
+ 216. http://www.columbia.edu/kermit/ckermit70.html#x4.17
+ 217. http://www.columbia.edu/kermit/ckermit70.html#x4.17.1
+ 218. http://www.columbia.edu/kermit/ckermit70.html#x4.17.2
+ 219. http://www.columbia.edu/kermit/ckermit70.html#x4.18
+ 220. http://www.columbia.edu/kermit/ckermit70.html#x4.19
+ 221. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 222. http://www.columbia.edu/kermit/ckermit70.html#x4.20.1
+ 223. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2
+ 224. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.1
+ 225. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.2
+ 226. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.3
+ 227. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.4
+ 228. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.5
+ 229. http://www.columbia.edu/kermit/ckermit70.html#x4.20.3
+ 230. http://www.columbia.edu/kermit/ckermit70.html#x4.21
+ 231. http://www.columbia.edu/kermit/ckermit70.html#x4.22
+ 232. http://www.columbia.edu/kermit/ckermit70.html#x4.22.1
+ 233. http://www.columbia.edu/kermit/ckermit70.html#x4.22.2
+ 234. http://www.columbia.edu/kermit/ckermit70.html#x4.22.3
+ 235. http://www.columbia.edu/kermit/ckermit70.html#x4.22.4
+ 236. http://www.columbia.edu/kermit/ckermit70.html#x4.22.5
+ 237. http://www.columbia.edu/kermit/ckermit70.html#x4.22.6
+ 238. http://www.columbia.edu/kermit/ckermit70.html#x4.22.7
+ 239. http://www.columbia.edu/kermit/ckermit70.html#x4.22.8
+ 240. http://www.columbia.edu/kermit/ckermit70.html#x4.23
+ 241. http://www.columbia.edu/kermit/ckermit70.html#x4.24
+ 242. http://www.columbia.edu/kermit/ckermit70.html#x4.25
+ 243. http://www.columbia.edu/kermit/ckermit70.html#x5
+ 244. http://www.columbia.edu/kermit/ckermit70.html#x5.0
+ 245. http://www.columbia.edu/kermit/ckermit70.html#x5.1
+ 246. http://www.columbia.edu/kermit/ckermit70.html#x5.2
+ 247. http://www.columbia.edu/kermit/ckermit70.html#x5.3
+ 248. http://www.columbia.edu/kermit/ckermit70.html#x5.3.1
+ 249. http://www.columbia.edu/kermit/ckermit70.html#x5.3.2
+ 250. http://www.columbia.edu/kermit/ckermit70.html#x5.4
+ 251. http://www.columbia.edu/kermit/ckermit70.html#x5.5
+ 252. http://www.columbia.edu/kermit/ckermit70.html#x5.6
+ 253. http://www.columbia.edu/kermit/ckermit70.html#x5.7
+ 254. http://www.columbia.edu/kermit/ckermit70.html#x6
+ 255. http://www.columbia.edu/kermit/ckermit70.html#x6.0
+ 256. http://www.columbia.edu/kermit/ckermit70.html#x6.1
+ 257. http://www.columbia.edu/kermit/ckermit70.html#x6.2
+ 258. http://www.columbia.edu/kermit/ckermit70.html#x6.3
+ 259. http://www.columbia.edu/kermit/ckermit70.html#x6.4
+ 260. http://www.columbia.edu/kermit/ckermit70.html#x6.5
+ 261. http://www.columbia.edu/kermit/ckermit70.html#x6.6
+ 262. http://www.columbia.edu/kermit/ckermit70.html#x6.6.1
+ 263. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 264. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 265. http://www.columbia.edu/kermit/ckermit70.html#x6.6.3
+ 266. http://www.columbia.edu/kermit/ckermit70.html#x6.6.4
+ 267. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5
+ 268. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.1
+ 269. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.2
+ 270. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.3
+ 271. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.4
+ 272. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.5
+ 273. http://www.columbia.edu/kermit/ckermit70.html#x6.7
+ 274. http://www.columbia.edu/kermit/ckermit70.html#x7
+ 275. http://www.columbia.edu/kermit/ckermit70.html#x7.0
+ 276. http://www.columbia.edu/kermit/ckermit70.html#x7.1
+ 277. http://www.columbia.edu/kermit/ckermit70.html#x7.1.1
+ 278. http://www.columbia.edu/kermit/ckermit70.html#x7.1.2
+ 279. http://www.columbia.edu/kermit/ckermit70.html#x7.1.3
+ 280. http://www.columbia.edu/kermit/ckermit70.html#x7.1.4
+ 281. http://www.columbia.edu/kermit/ckermit70.html#x7.2
+ 282. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 283. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 284. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 285. http://www.columbia.edu/kermit/ckermit70.html#x7.6
+ 286. http://www.columbia.edu/kermit/ckermit70.html#x7.7
+ 287. http://www.columbia.edu/kermit/ckermit70.html#x7.8
+ 288. http://www.columbia.edu/kermit/ckermit70.html#x7.9
+ 289. http://www.columbia.edu/kermit/ckermit70.html#x7.9.1
+ 290. http://www.columbia.edu/kermit/ckermit70.html#x7.9.2
+ 291. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 292. http://www.columbia.edu/kermit/ckermit70.html#x7.10.1
+ 293. http://www.columbia.edu/kermit/ckermit70.html#x7.10.2
+ 294. http://www.columbia.edu/kermit/ckermit70.html#x7.10.3
+ 295. http://www.columbia.edu/kermit/ckermit70.html#x7.10.4
+ 296. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 297. http://www.columbia.edu/kermit/ckermit70.html#x7.10.6
+ 298. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 299. http://www.columbia.edu/kermit/ckermit70.html#x7.10.8
+ 300. http://www.columbia.edu/kermit/ckermit70.html#x7.10.9
+ 301. http://www.columbia.edu/kermit/ckermit70.html#x7.10.10
+ 302. http://www.columbia.edu/kermit/ckermit70.html#x7.11
+ 303. http://www.columbia.edu/kermit/ckermit70.html#x7.12
+ 304. http://www.columbia.edu/kermit/ckermit70.html#x7.13
+ 305. http://www.columbia.edu/kermit/ckermit70.html#x7.14
+ 306. http://www.columbia.edu/kermit/ckermit70.html#x7.15
+ 307. http://www.columbia.edu/kermit/ckermit70.html#x7.16
+ 308. http://www.columbia.edu/kermit/ckermit70.html#x7.17
+ 309. http://www.columbia.edu/kermit/ckermit70.html#x7.18
+ 310. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 311. http://www.columbia.edu/kermit/ckermit70.html#x7.20
+ 312. http://www.columbia.edu/kermit/ckermit70.html#x7.20.1
+ 313. http://www.columbia.edu/kermit/ckermit70.html#x7.20.2
+ 314. http://www.columbia.edu/kermit/ckermit70.html#x7.21
+ 315. http://www.columbia.edu/kermit/ckermit70.html#x7.22
+ 316. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 317. http://www.columbia.edu/kermit/ckermit70.html#x7.24
+ 318. http://www.columbia.edu/kermit/ckermit70.html#x7.25
+ 319. http://www.columbia.edu/kermit/ckermit70.html#x7.26
+ 320. http://www.columbia.edu/kermit/ckermit70.html#x7.26.1
+ 321. http://www.columbia.edu/kermit/ckermit70.html#x7.26.2
+ 322. http://www.columbia.edu/kermit/ckermit70.html#x7.27
+ 323. http://www.columbia.edu/kermit/ckermit70.html#x8
+ 324. http://www.columbia.edu/kermit/ckermit70.html#x9
+ 325. http://www.columbia.edu/kermit/ckermit70.html#x9.0
+ 326. http://www.columbia.edu/kermit/ckermit70.html#x9.1
+ 327. http://www.columbia.edu/kermit/ckermit70.html#x9.2
+ 328. http://www.columbia.edu/kermit/ckermit70.html#x9.3
+ 329. http://www.columbia.edu/kermit/ckermit70.html#x10
+ 330. http://www.columbia.edu/kermit/ckermit70.html#xiii
+ 331. http://www.columbia.edu/kermit/ckermit70.html#xiii.1
+ 332. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.1
+ 333. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2
+ 334. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2.1
+ 335. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2.2
+ 336. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2.3
+ 337. http://www.columbia.edu/kermit/ckermit70.html#xiii.2
+ 338. http://www.columbia.edu/kermit/ckermit70.html#xiv
+ 339. http://www.columbia.edu/kermit/ckermit70.html#xv
+ 340. http://www.columbia.edu/kermit/ckb2.htm
+ 341. http://www.columbia.edu/kermit/ckbreviews.html
+ 342. http://www.bhusa.com/
+ 343. http://www.columbia.edu/kermit/manuals.html#ckde
+ 344. http://www.columbia.edu/kermit/manuals.html#ktb
+ 345. http://www.columbia.edu/kermit/news.html
+ 346. news:comp.protocols.kermit.announce
+ 347. news:comp.protocols.kermit.misc
+ 348. http://www.columbia.edu/kermit/ckb2.htm
+ 349. http://www.columbia.edu/kermit/ckermit70.html#x4
+ 350. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 351. http://www.columbia.edu/kermit/ckermit70.html#x4.23
+ 352. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 353. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 354. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 355. http://www.columbia.edu/kermit/ckermit70.html#x4.9.
+ 356. http://www.columbia.edu/kermit/ckb2.htm
+ 357. http://www.columbia.edu/kermit/ckermit70.html#x7.9.2
+ 358. http://www.columbia.edu/kermit/ckermit70.html#x2.15
+ 359. http://www.columbia.edu/kermit/ckermit70.html#x9.1
+ 360. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 361. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 362. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 363. http://www.columbia.edu/kermit/ckermit70.html#mjd
+ 364. http://www.columbia.edu/kermit/ckermit70.html#mjd
+ 365. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 366. http://www.columbia.edu/kermit/ckb2.htm
+ 367. http://www.columbia.edu/kermit/ckb2.htm
+ 368. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 369. http://www.columbia.edu/kermit/ckermit70.html#x2.12
+ 370. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 371. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 372. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5
+ 373. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 374. http://www.columbia.edu/kermit/ckermit70.html#x7.18
+ 375. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 376. http://www.columbia.edu/kermit/ckermit70.html#x1.15
+ 377. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 378. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 379. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 380. http://www.columbia.edu/kermit/ckermit70.html#x7.1
+ 381. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 382. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 383. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 384. http://www.columbia.edu/kermit/ckermit70.html#x1.22.4
+ 385. http://www.columbia.edu/kermit/ckermit70.html#x1.22.5
+ 386. http://www.columbia.edu/kermit/ckb2.htm
+ 387. http://www.columbia.edu/kermit/ckermit70.html#x1.22.5
+ 388. http://www.columbia.edu/kermit/ckermit70.html#x7.12
+ 389. http://www.columbia.edu/kermit/ckermit70.html#x2.1.16
+ 390. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 391. http://www.columbia.edu/kermit/ckermit70.html#x2.3.5
+ 392. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 393. http://www.telefonica.es/cambiodenumeracion/
+ 394. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 395. http://www.columbia.edu/kermit/ckb2.htm
+ 396. http://www.columbia.edu/kermit/ckermit70.html#x2.2.2
+ 397. http://www.columbia.edu/kermit/ckermit70.html#x2.1.11
+ 398. http://www.columbia.edu/kermit/ckermit70.html#x2.1.13
+ 399. http://www.columbia.edu/kermit/ckermit70.html#x2.1.12
+ 400. http://www.columbia.edu/kermit/ckb2.htm
+ 401. http://www.columbia.edu/kermit/ckermit70.html#x2.1.1
+ 402. http://www.columbia.edu/kermit/ckb2.htm
+ 403. http://www.columbia.edu/kermit/ckb2.htm
+ 404. http://www.columbia.edu/kermit/ckermit70.html#x2.1.7
+ 405. http://www.columbia.edu/kermit/ckermit70.html#x2.1.6
+ 406. http://www.columbia.edu/kermit/ckb2.htm
+ 407. ftp://kermit.columbia.edu/kermit/f/telnet.txt
+ 408. http://www.columbia.edu/kermit/telnet.htm
+ 409. ftp://kermit.columbia.edu/kermit/f/telnet.txt
+ 410. http://www.columbia.edu/kermit/telnet.htm
+ 411. ftp://ftp.isi.edu/in-notes/rfc1572.txt
+ 412. ftp://ftp.isi.edu/in-notes/rfc779.txt
+ 413. http://www.columbia.edu/kermit/ckb2.htm
+ 414. http://www.columbia.edu/kermit/ckermit70.html#x2.10
+ 415. http://www.columbia.edu/kermit/ckermit70.html#x2.8
+ 416. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 417. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 418. http://www.psy.uq.oz.au/~ftp/Crypto/
+ 419. http://www.columbia.edu/kermit/security.htm
+ 420. http://srp.stanford.edu/srp/
+ 421. http://www.columbia.edu/kermit/ckermit70.html#x2.7.1,
+ 422. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 423. http://www.columbia.edu/kermit/security.htm
+ 424. http://www.columbia.edu/kermit/ckb2.htm
+ 425. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 426. http://www.columbia.edu/kermit/ckermit70.html#x2.0
+ 427. ftp://kermit.columbia.edu/kermit/f/ckuins.txt
+ 428. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 429. ftp://kermit.columbia.edu/kermit/f/ckuins.txt
+ 430. http://www.columbia.edu/kermit/iksd.html#x4.2
+ 431. http://www.columbia.edu/kermit/iksd.html
+ 432. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.1
+ 433. ftp://ftp.isi.edu/in-notes/rfc1945.txt
+ 434. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 435. http://www.columbia.edu/kermit/ckermit70.html#x3.2
+ 436. http://www.columbia.edu/kermit/ckermit70.html#x3.2
+ 437. http://www.columbia.edu/kermit/ckb2.htm
+ 438. http://www.columbia.edu/kermit/ckb2.htm
+ 439. http://www.columbia.edu/kermit/ckermit70.html#x5.4
+ 440. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 441. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 442. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 443. http://www.columbia.edu/kermit/ckermit70.html#x4.7.3
+ 444. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 445. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 446. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 447. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 448. http://www.columbia.edu/kermit/ckermit70.html#x4.2.4
+ 449. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 450. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3
+ 451. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.3
+ 452. http://www.columbia.edu/kermit/ckb2.htm
+ 453. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 454. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 455. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.2
+ 456. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 457. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 458. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 459. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 460. http://www.telstra.com.au/docs/PGP/
+ 461. http://www.telstra.com.au/docs/PGP/pgpdoc2/pgpdoc2_17.html
+ 462. http://www.columbia.edu/kermit/security.htm
+ 463. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 464. http://www.columbia.edu/kermit/ckb2.htm
+ 465. http://www.columbia.edu/kermit/ckermit70.html#x2.14
+ 466. http://www.columbia.edu/kermit/ckermit70.html#x1.23
+ 467. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 468. http://www.columbia.edu/kermit/ckb2.htm
+ 469. http://www.columbia.edu/kermit/ckb2.htm
+ 470. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 471. http://www.columbia.edu/kermit/ckb2.htm
+ 472. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 473. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 474. http://www.columbia.edu/kermit/ckermit70.html#x1.5.5
+ 475. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 476. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 477. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 478. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 479. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 480. http://www.columbia.edu/kermit/ckermit70.html#x1.5.5
+ 481. http://www.columbia.edu/kermit/ckb2.htm
+ 482. http://www.columbia.edu/kermit/ckb2.htm
+ 483. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 484. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 485. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 486. http://www.columbia.edu/kermit/ckermit70.html#x7.10.11
+ 487. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 488. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 489. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 490. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 491. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 492. http://www.columbia.edu/kermit/ckermit70.html#x4.0.6
+ 493. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 494. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 495. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 496. http://www.columbia.edu/kermit/ckb2.htm
+ 497. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 498. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 499. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 500. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 501. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 502. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 503. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 504. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 505. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 506. http://www.columbia.edu/kermit/ckermit70.html#x1.11.5
+ 507. http://www.columbia.edu/kermit/ckermit70.html#x4.0.6
+ 508. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 509. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 510. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 511. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 512. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 513. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 514. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 515. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 516. http://www.columbia.edu/kermit/ckermit70.html#x7.10.3
+ 517. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 518. http://www.columbia.edu/kermit/ckb2.htm
+ 519. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 520. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 521. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 522. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 523. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 524. http://www.columbia.edu/kermit/ckermit70.html#x4.18
+ 525. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 526. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 527. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 528. http://www.columbia.edu/kermit/ckermit70.html#x4.19
+ 529. http://www.columbia.edu/kermit/ckermit70.html#x4.16
+ 530. http://www.columbia.edu/kermit/ckermit70.html#x4.19
+ 531. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.3
+ 532. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 533. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.4
+ 534. http://www.columbia.edu/kermit/ckermit70.html#x4.22.2
+ 535. http://www.columbia.edu/kermit/ckermit70.html#x4.22.3
+ 536. http://www.columbia.edu/kermit/ckb2.htm
+ 537. http://www.columbia.edu/kermit/ckb2.htm
+ 538. http://www.columbia.edu/kermit/ckermit70.html#x9.3
+ 539. http://www.columbia.edu/kermit/ckermit70.html#x5.2.1
+ 540. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 541. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2
+ 542. http://www.columbia.edu/kermit/ckermit70.html#x6.6
+ 543. http://www.columbia.edu/kermit/ckermit70.html#xiii
+ 544. http://www.columbia.edu/kermit/ckermit70.html#xiii
+ 545. ftp://ftp.isi.edu/in-notes/rfc1489.txt
+ 546. ftp://ftp.isi.edu/in-notes/rfc2319.txt
+ 547. http://www.unicode.org/
+ 548. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 549. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.1
+ 550. ftp://ftp.isi.edu/in-notes/rfc2640.txt
+ 551. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 552. http://www.columbia.edu/kermit/ckermit70.html#x6.0
+ 553. http://www.columbia.edu/kermit/ckermit70.html#x6.5
+ 554. http://www.columbia.edu/kermit/ckermit70.html#x6.4
+ 555. http://www.columbia.edu/kermit/ckb2.htm
+ 556. http://www.columbia.edu/kermit/ckermit70.html#x4.21
+ 557. http://www.columbia.edu/kermit/ckermit70.html#x6.5
+ 558. http://www.columbia.edu/kermit/ckermit70.html#x2.8
+ 559. http://www.columbia.edu/kermit/ckermit70.html#x7.7
+ 560. http://www.columbia.edu/kermit/ckermit70.html#x7.2
+ 561. http://www.columbia.edu/kermit/ckermit70.html#x1.19
+ 562. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 563. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 564. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 565. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 566. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 567. http://www.columbia.edu/kermit/ckermit70.html#x2.1.11
+ 568. http://www.columbia.edu/kermit/ckermit70.html#x2.10
+ 569. http://www.columbia.edu/kermit/ckermit70.html#ferrstring
+ 570. http://www.columbia.edu/kermit/ckermit70.html#x4.2.5
+ 571. http://www.columbia.edu/kermit/ckermit70.html#x2.1.10
+ 572. http://www.columbia.edu/kermit/ckermit70.html#x9.1
+ 573. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 574. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 575. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 576. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 577. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 578. http://www.columbia.edu/kermit/ckermit70.html#x7.24
+ 579. http://www.columbia.edu/kermit/ckermit70.html#x7.24
+ 580. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3
+ 581. http://www.columbia.edu/kermit/ck90.html
+ 582. http://www.columbia.edu/kermit/ckermit70.html#x7.12
+ 583. http://www.columbia.edu/kermit/ckermit70.html#x7.9
+ 584. http://www.columbia.edu/kermit/ckb2.htm
+ 585. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 586. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 587. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 588. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 589. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 590. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.4
+ 591. http://www.columbia.edu/kermit/ckermit70.html#x4.2.5
+ 592. http://www.columbia.edu/kermit/ckermit70.html#x7.8
+ 593. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 594. http://www.columbia.edu/kermit/ckb2.htm
+ 595. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 596. http://www.columbia.edu/kermit/ckermit70.html#x7.16
+ 597. http://www.columbia.edu/kermit/ckermit70.html#x7.9.1
+ 598. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 599. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 600. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 601. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 602. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 603. http://www.columbia.edu/kermit/ckermit70.html#x7.10.10
+ 604. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 605. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 606. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 607. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 608. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 609. http://www.columbia.edu/kermit/ckermit70.html#x7.10.11
+ 610. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 611. http://www.columbia.edu/kermit/ckermit70.html#x7.10.3
+ 612. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 613. http://www.columbia.edu/kermit/ckermit70.html#x7.9.2
+ 614. http://www.columbia.edu/kermit/ckb2.htm
+ 615. http://www.columbia.edu/kermit/ckermit70.html#x4.17.2
+ 616. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 617. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 618. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 619. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 620. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 621. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 622. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 623. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 624. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 625. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 626. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 627. http://www.columbia.edu/kermit/ckermit70.html#x9.3
+ 628. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 629. http://www.columbia.edu/kermit/ckb2.htm
+ 630. http://www.columbia.edu/kermit/ckermit80.html
+ 631. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 632. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 633. http://www.columbia.edu/kermit/ckermit80.html
+ 634. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 635. http://www.columbia.edu/kermit/ckermit70.html#x7.20.2
+ 636. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 637. http://www.columbia.edu/kermit/ckermit70.html#x7.10.9
+ 638. http://www.columbia.edu/kermit/ckermit70.html#x1.10
+ 639. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 640. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 641. http://www.columbia.edu/kermit/iksd.html
+ 642. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 643. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 644. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 645. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 646. http://www.columbia.edu/kermit/gkermit.html
+ 647. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 648. http://www.columbia.edu/kermit/gkermit.html
+ 649. http://www.columbia.edu/kermit/ckb2.htm
+ 650. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 651. mailto:kermit@columbia.edu
+ 652. http://www.columbia.edu/kermit/ckermit70.html#top
+ 653. http://www.columbia.edu/kermit/ckermit.html
+ 654. http://www.columbia.edu/kermit/index.html
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckermit80.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit80.txt
new file mode 100644
index 0000000..196b68b
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit80.txt
@@ -0,0 +1,10286 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+C-Kermit 8.0 Update Notes
+
+ [ [11]Contents ] [ [12]C-Kermit ] [ [13]Kermit Home ]
+
+Second Supplement to [14]Using C-Kermit, 2nd Edition
+
+For C-Kermit 8.0
+
+ As of C-Kermit version: 8.0.211
+ Date of C-Kermit release: 10 April 2003
+ This file last updated: Mon Sep 13 08:52:36 2010
+
+ * IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+ it is a plain-text dump of a Web page. You can visit the original
+ (and possibly more up-to-date) Web page here:
+ [15]http://www.columbia.edu/kermit/ckermit80.html
+
+ * If you are reading the HTML version of this file with a GUI Web
+ browser, the features added since C-Kermit 8.0.201 are shown in red
+ if your browser and monitor permit. Features that were new to
+ versions 8.0.200 and 201 are in black.
+
+Authors: Frank da Cruz and Christine M. Gianone
+Address: The Kermit Project
+ Columbia University
+ 612 West 115th Street
+ New York NY 10025-7799
+ USA
+Fax: +1 (212) 662-6442
+E-Mail: [16]kermit-support@columbia.edu
+Web: [17]http://www.columbia.edu/kermit/
+Or: [18]http://www.kermit-project.org/
+Or: [19]http://www.columbia.nyc.ny.us/kermit/
+
+NOTICES
+
+ This document:
+ Copyright � 1997, 2002, Frank da Cruz and Christine M. Gianone.
+ All rights reserved.
+
+ Kermit 95:
+ Copyright � 1995, 2002, Trustees of Columbia University in the
+ City of New York. All rights reserved.
+
+ C-Kermit:
+ Copyright � 1985, 2002,
+ Trustees of Columbia University in the City of New York. All
+ rights reserved. See the C-Kermit [20]COPYING.TXT file or the
+ copyright text in the [21]ckcmai.c module for disclaimer and
+ permissions.
+
+ When Kerberos(TM) and/or SRP(TM) (Secure Remote Password) and/or
+ SSL/TLS protocol are included:
+ Portions Copyright � 1990, Massachusetts Institute of
+ Technology.
+ Portions Copyright � 1991, 1993 Regents of the University of
+ California.
+ Portions Copyright � 1991, 1992, 1993, 1994, 1995 by AT&T.
+ Portions Copyright � 1997, Stanford University.
+ Portions Copyright � 1995-1997, Eric Young <eay@cryptosoft.com>.
+
+ For the full text of the third-party copyright notices, see
+ [22]Appendix V.
+
+WHAT IS IN THIS FILE
+
+ This file lists changes made to C-Kermit since version 7.0 was released
+ in January 2000. Use this file as a supplement to:
+
+ * The second edition of [23]Using C-Kermit; and:
+ * The [24]C-Kermit 7.0 Update Notes. Also available in plain-text
+ form as [25]ckermit70.txt.
+
+ until the third edition of Using C-Kermit is published. We apologize
+ for the scattered documentation and will consolidate it when we are
+ able.
+
+ADDITIONAL FILES
+
+ Several other files accompany this new Kermit release:
+
+ [26]ckututor.html
+ C-Kermit Tutorial (for Unix). Also distributed in Nroff form as
+ [27]ckuker.nr, the Unix C-Kermit manual page.
+
+ [28]security.htm
+ Discussion of Kermit's new authentication and encryption
+ features, updated for C-Kermit 8.0.
+
+ [29]telnet.htm
+ Detailed documentation of Kermit's Telnet client, updated for
+ C-Kermit 8.0.
+
+ [30]ftpscripts.html
+ Tutorial: Writing FTP automation scripts
+
+ [31]ckcbwr.html
+ Platform-independent C-Kermit hints and tips. Also distributed
+ in plain text form as [32]ckcbwr.txt
+
+ [33]ckubwr.html
+ Unix-specific C-Kermit hints and tips. Also distributed in plain
+ text form as [34]ckubwr.txt.
+
+ [35]ckvbwr.html
+ VMS-specific C-Kermit hints and tips. Also distributed in plain
+ text form as [36]ckvbwr.txt.
+
+ [37]ckuins.html
+ Unix C-Kermit installation instructions. Also distributed in
+ plain text form as [38]ckuins.txt.
+
+ [39]ckvins.html
+ VMS C-Kermit installation instructions. Also distributed in
+ plain text form as [40]ckvins.txt.
+
+ [41]ckccfg.html
+ Compile-time configuration options. Also distributed in plain
+ text form as [42]ckccfg.txt.
+
+ [43]ckcplm.html
+ C-Kermit Program Logic Manual. Also distributed in plain text
+ form as [44]ckcplm.txt.
+
+ [45]iksd.html
+ Internet Kermit Service Administrators Guide for Unix.
+
+ [46]skermit.html
+ C-Kermit as an SSH Subsystem (SFTP server replacement).
+
+ [ [47]Top ] [ [48]C-Kermit ] [ [49]Kermit Home ]
+
+CONTENTS
+
+ [50]0. WHAT'S NEW
+ [51]1. FIXES SINCE VERSION 7.0.196
+ [52]2. SSH AND HTTP
+ [53]2.1. SSH Connections
+ [54]2.2. HTTP Connections
+ [55]2.2.1. HTTP Command Switches
+ [56]2.2.2. HTTP Action Commands
+ [57]2.2.3. HTTP Headers
+ [58]2.2.4. Secure HTTP Connections
+ [59]2.2.5. HTTP Variables
+ [60]2.2.6. The HTTP Command-Line Personality
+ [61]3. THE BUILT-IN FTP CLIENT
+ [62]3.1. Making and Managing FTP Connections
+ [63]3.1.1. Kermit Command-Line Options for FTP
+ [64]3.1.2. The FTP Command-Line Personality
+ [65]3.1.3. The FTP URL Interpreter
+ [66]3.1.4. Interactive FTP Session Establishment
+ [67]3.2. Making Secure FTP Connections
+ [68]3.3. Setting FTP Preferences
+ [69]3.4. Managing Directories and Files
+ [70]3.5. Uploading Files With FTP
+ [71]3.5.1. FTP PUT Switches
+ [72]3.5.2. Update Mode
+ [73]3.5.3. Recovery
+ [74]3.6. Downloading Files With FTP
+ [75]3.6.1. FTP GET Switches
+ [76]3.6.2. Filename Collisions
+ [77]3.6.3. Recovery
+ [78]3.7. Translating Character Sets
+ [79]3.7.1. Character Sets and Uploading
+ [80]3.7.2. Character Sets and Downloading
+ [81]3.8. FTP Command Shortcuts
+ [82]3.9. Dual Sessions
+ [83]3.10. Automating FTP Sessions
+ [84]3.10.1. FTP-Specific Variables and Functions
+ [85]3.10.2. Examples
+ [86]3.10.3. Automating Secure FTP Connections
+ [87]3.11. Advanced FTP Protocol Features [88]4. FILE SCANNING
+ [89]5. FILE AND DIRECTORY NAMES CONTAINING SPACES
+ [90]6. OTHER COMMAND PARSING IMPROVEMENTS
+ [91]6.1. Grouping Macro Arguments
+ [92]6.2. Directory and File Name Completion
+ [93]6.3. Passing Arguments to Command Files
+ [94]6.4. More-Prompting
+ [95]6.5. Commas in Macro Definitions
+ [96]6.6. Arrow Keys
+ [97]7. NEW COMMANDS AND SWITCHES
+ [98]8. SCRIPTING IMPROVEMENTS
+ [99]8.1. Performance and Debugging
+ [100]8.2. Using Macros as Numeric Variables
+ [101]8.3. New IF Conditions
+ [102]8.4. The ON_UNKNOWN_COMMAND and ON_CD Macros
+ [103]8.5. The SHOW MACRO Command
+ [104]8.6. Arrays
+ [105]8.7. New or Improved Built-in Variables and Functions
+ [106]8.8. The RETURN and END Commands
+ [107]8.9. UNDEFINing Groups of Variables
+ [108]8.10. The INPUT and MINPUT Commands
+ [109]8.11. Learned Scripts
+ [110]8.12. Pattern Matching
+ [111]8.13. Dates and Times
+ [112]8.14. Trapping Keyboard Interruption
+ [113]9. S-EXPRESSIONS
+ [114]9.1. What is an S-Expression?
+ [115]9.2. Integer and Floating-Point-Arithmetic
+ [116]9.3. How to Use S-Expressions
+ [117]9.4. Summary of Built-in Constants and Operators
+ [118]9.5. Variables
+ [119]9.6. Assignments and Scope
+ [120]9.7. Conditional Expressions
+ [121]9.8. Extensibility
+ [122]9.9. Examples
+ [123]9.10. Differences from Algebraic Notation
+ [124]9.11.Differences from Lisp
+ [125]10. FILE TRANSFER
+ [126]11. MODEMS AND DIALING
+ [127]12. TERMINAL CONNECTION
+ [128]13. CHARACTER SETS
+ [129]14. DIALOUT FROM TELNET TERMINAL SERVERS
+ [130]15. COPING WITH BROKEN KERMIT PARTNERS
+ [131]16. NEW COMMAND-LINE OPTIONS
+ [132]17. LOGS
+
+ [ [133]Top ] [ [134]C-Kermit ] [ [135]Kermit Home ]
+
+0. WHAT'S NEW
+
+ The Initialization and Customization Files
+ C-Kermit 8.0 now supports specification of the initialization
+ file name (path) in an environment variable, CKERMIT_INI. It
+ also relies far less than before on the initialization for
+ functioning. See [136]Section 5 of the Unix C-Kermit
+ [137]installation instructions for details. As of version
+ 8.0.201, C-Kermit also executes your customization file (if you
+ have one) even if the initialization file was not found.
+ Previously, the customization file was executed by a TAKE
+ command in the initialization file (and it still is, if an
+ initialization is found).
+
+ Incompatible Changes
+ As always, we do our best to avoid changes that break existing
+ scripts. However, C-Kermit 8.0 does include a rather pervasive
+ syntax change that might alter the behavior of scripts that
+ depend on the previous behavior. As described in [138]Section 5,
+ C-Kermit now accepts doublequotes in most contexts where you
+ previously had to use braces to group multiple words into a
+ single field, or to force inclusion of leading or trailing
+ blanks. Most noticeably, in C-Kermit 7.0 and earlier:
+
+ echo {this is a string}
+
+ would print:
+
+ this is a string
+
+ whereas:
+
+ echo "this is a string"
+
+ printed:
+
+ "this is a string"
+
+ In C-Kermit 8.0, both print:
+
+ this is a string
+
+ To force the doublequotes to be treated as part of the string,
+ use either of the following forms:
+
+ echo {"this is a string"}
+ echo ""this is a string""
+
+ Similarly, to force braces to be treated as part of the string:
+
+ echo "{this is a string}"
+ echo {{this is a string}}
+
+ Other incompatibilities:
+
+ 1. Using the SET HOST command to make HTTP connections is no
+ longer supported. Instead, use the new HTTP OPEN command,
+ described in [139]Section 2.2.
+
+ C-Kermit 7.1 Alpha.01 (8 December 2000)
+
+ Its major new features are those listed in the [140]Table of
+ Contents: the FTP client, file scanning, command parsing and
+ scripting improvements, S-Expressions, and support for the
+ Telnet Com Port Option, plus wider availability of the Kerberos,
+ SSL/TLS, and SRP security options for secure Internet
+ connections.
+
+ C-Kermit 7.1.199 Alpha.02 (4 January 2001)
+
+ + C-Kermit now accepts [141]FTP, TELNET, and IKSD URLs as its
+ first command-line argument.
+ + Character-set translation added to the FTP client for
+ [142]filenames.
+ + Optional [143]setting of date of incoming files by FTP [M]GET
+ from the server date.
+ + [144]FTP CHECK filename added to let FTP client check the
+ existence of a file on the server.
+ + [145]FTP GET /NAMELIST:filename added to get list of server
+ filenames into a local file.
+ + [146]FTP [M]PUT /SERVER-RENAME:template added to make server
+ rename a file as indicated by the template after it has
+ arrived completely.
+ + FTP [M]GET /SERVER-RENAME:template added to make server rename
+ a file as indicated by the template after it has been sent
+ completely.
+ + FTP [147]VDIRECTORY added for getting verbose directory
+ listings from TOPS-20.
+ + [148]FTP TYPE TENEX added for transferring 8-bit binary files
+ with PDP-10s.
+ + Added [149]automatic text/binary mode switching for FTP
+ [M]GET, based on filename patterns (e.g. *.zip, *.gz, *.exe
+ are binary; *.txt, *.c are text).
+ + [150]SET SEND I-PACKETS OFF added for coping with Kermit
+ servers that do not support I packets.
+ + A new option was added to [151]\fword() and \fsplit() for
+ parsing comma-separated lists that might contain empty
+ elements.
+ + Bug fixes including:
+ o {} or "" could not be used as expected to represent the
+ empty string.
+ o ,- on a line by itself in a macro definition caused
+ subsequent statements to be skipped.
+ o FTP [M]GET didn't work right if path segments were
+ included in the filespec.
+ o FTP MGET, if interrupted, did not clear its file list.
+ o Various problems with FTP PUT /AS-NAME that nobody
+ noticed.
+ o Some FTP messages and displays interfered with each
+ other.
+ o Parsing of YESTERDAY, TODAY, and TOMORROW in date-time
+ fields was broken.
+ o Automatic old-to-new dialing directory format conversion
+ was broken on VMS.
+ o Various source-code portability problems fixed.
+ + Improvement of various HELP and SHOW messages.
+
+ C-Kermit 7.1.199 Alpha.04 (1 April 2001)
+
+ + Big changes:
+ o Changed default modem type from NONE to GENERIC.
+ o Generic dialing now sends no init string at all.
+ o Changed default terminal bytesize from 7 to 8.
+ + New features:
+ o SET SESSION-LOG TIMESTAMPED-TEXT for timestamped session
+ log.
+ + New modem types:
+ o Conexant modem family
+ o Lucent VENUS chipset
+ o PCTel V.90 chipset
+ o Zoom V.90
+ o Zoom V.92
+ + FTP client:
+ o FTP OPEN /PASSIVE and /ACTIVE switches added.
+ o Now works with servers that that don't include path in
+ NLST response.
+ o Fixed SEND /RECURSIVE not to follow symlinks (UNIX).
+ o SET FTP VERBOSE-MODE default is now OFF instead of ON.
+ + Kermit protocol:
+ o Fixed what I hope is the last "Receive window full"
+ error.
+ o SET PREFIXING or SET CONTROL PREFIX now automatically
+ sets CLEARCHANNEL OFF.
+ o Fixed incorrect report of number of files transferred at
+ end of transfer.
+ o Fixed SEND /RECURSIVE not to follow symlinks (UNIX).
+ + UNIX:
+ o HTTP and shadow passwords enabled for SCO 5.0.6.
+ o Even with SET FILENAMES CONVERTED, spaces were still
+ accepted in incoming filenames; now they are converted to
+ underscores.
+ o Added support for compile-time mktemp()/mkstemp()
+ selection.
+ + VMS:
+ o Session-log format for scripted sessions fixed.
+ + Scripting:
+ o Fixed \frdir() not to follow symlinks (UNIX).
+ o Fixed \fday() not to dump core for dates prior to 17 Mar
+ 1858.
+ + General:
+ o "Closing blah..." message upon exit could not be
+ suppressed.
+ o Added /PAGE and /NOPAGE to DELETE switches.
+ o Added GO response for DELETE /ASK (delete all the rest
+ without asking).
+ o Added GO response to "more?" prompt (for multi-page
+ screen output).
+ o Updated HELP texts.
+
+ C-Kermit 7.1.199 Beta.01 (10 May 2001)
+
+ + FTP client verbosity adjustments.
+ + Bug with generic modem dialing pausing several secs fixed.
+ + SET HOST /USER:, SET LOGIN USERID, etc, fixed when given no
+ user ID.
+ + A couple \v(dm_blah) dial modifier variables added.
+ + "--version" command-line switch added.
+ + Fixed NetBSD serial-port DTR handling.
+ + Lots of syntax cleanups for Flexelint and gcc -Wall.
+ + Fixed modem-type aliases to not take precedence over real
+ names.
+ + Fixed funny treatment of doublequotes by ECHO command.
+ + Enabled SET SESSION-LOG for VMS and other non-UNIX platforms.
+ + Fixed changing direction in command history buffer.
+ + Fixed handling of IKSD URLs.
+ + Made sure DELETE prints a message if it got any errors.
+
+ C-Kermit 8.0.200 Beta.02 (28 June 2001)
+
+ + Major version number increased from 7 to 8.
+ + [152]SSH command.
+ + More-consistent Kermit protocol defaults.
+ + CONNECT idle timeout and action selection.
+ + CONNECT status variable.
+ + A way to allocate more space for filename lists.
+ + Pseudoterminal handler fixed for late-model Linuxes.
+ + Command-line option -dd for timestamped debug log.
+ + Download directory now works for external protocols too.
+ + GREP /COUNT:variable.
+ + SET ATTRIBUTE RECORD-FORMAT { OFF, ON }.
+ + Bug fixes.
+
+ C-Kermit 8.0.200 Beta.03 (9 Sep 2001)
+
+ + [153]HTTP 1.1 connections and scripting
+ + [154]ON_CTRLC macro for trapping Ctrl-C in scripts
+ + [155]Date-time parsing improvements, timezones, comparison,
+ arithmetic
+ + [156]Pattern-matching improvements
+ + FTP improvements
+ + SET EXIT HANGUP { ON, OFF }
+ + SET FILE EOF { CTRL-Z, LENGTH }
+ + ASK[Q] /TIMEOUT
+ + Bug fixes
+ + New platforms
+
+ C-Kermit 8.0.200 Beta.04 (16 Nov 2001)
+
+ + [157]New Unix man page
+ + [158]New Unix installation instructions
+ + SET TELOPT policies are now enforced on non-Telnet ports if
+ the server begins Telnet negotiations.
+ + SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }.
+ + UUCP lockfile creation race condition fixed.
+ + Dialout, modem signals, hangup, hardware flow control, etc,
+ tested extensively on many platforms, numerous problems fixed.
+ + Improved hints when dialing fails.
+ + SET STOP-BITS 2 can now be given without SET FLOW HARDWARE.
+ + Major improvements in RFC 2217 Telnet Com-Port Control.
+ + Improved ability to REDIAL a modem server port.
+ + kermit -h now shows the command name in the usage usage
+ string.
+ + kermit -h now shows ALL command-line options.
+ + kermit -s blah, where blah is a symlink, now works.
+ + --noperms command-line option = SET ATTRIBUTE PERMISSIONS OFF.
+ + HTTP and HTTPS URLs now supported on the command line.
+ + An http command-line personality is now available.
+ + Initialization file streamlined to load faster, anachronisms
+ removed.
+ + Updated NEWS, INTRO, HELP text, SHOW commands. In particular,
+ see SHOW COMM, HELP SET LINE, HELP WAIT.
+ + Date/time arithmetic routines converted from floating-point to
+ integer arithmetic (internally) for greater accuracy and
+ portability.
+ + Quoted strings containing commas no longer break macro
+ execution.
+ + Dynamic Kermit file-transfer timeouts are now much more
+ aggressive.
+ + New "hot keys" to turn debug.log on/off during file transfer.
+ + Improved hints when file transfer fails.
+ + FTP CD orientation messages are now printed.
+ + -R now accepted on the FTP command line to request Recursion.
+ + -m allows Active or Passive mode to be chosen on the FTP
+ command line.
+ + -dd on the FTP command line creates a timestamped debug.log.
+ + FTP command-line security options filled in.
+ + Improved automatic text/binary mode switching for MGET.
+ + Removed spurious error messages that sometimes occur during
+ MGET.
+ + DIRECTORY, GREP, TYPE, HEAD, and TAIL now have a /OUTPUT:file
+ option.
+ + TYPE /NUMBER adds line numbers.
+ + CAT = TYPE /NOPAGE; MORE = TYPE /PAGE.
+ + GETOK ?-help fixed.
+ + \v(timestamp) (= "\v(ndate) \v(time)")
+ + \v(hour) (hour of the day, 0-23)
+ + \funix2dospath() converts a UNIX path (/) to a DOS one (\).
+ + \fdos2unixpath() converts a DOS (Windows, OS/2) path to a UNIX
+ one.
+ + \fkeywordval() parses name=value pair, allows macro keyword
+ parameters.
+ + We now make every attempt to not write passwords to the
+ debug.log.
+ + New Certificate Authority certificates file, includes the
+ Kermit Project at Columbia University so you can access our
+ IKSD securely.
+ + Secure targets improved and better documented in Unix
+ makefile.
+ + All Linux (libc and glibc) builds consolidated under "make
+ linux".
+ + HP-UX makefile targets now have consistent names.
+ + New aix50 and aix51 targets added.
+
+ C-Kermit 8.0.200 Final (12 Dec 2001)
+
+ + Remote/local-mode confusion on some platforms introduced in
+ Beta.04, fixed.
+ + Many of the makefile targets adjusted, new ones added.
+ + New "make install" target should please most people.
+ + New command: SHOW IKSD.
+ + FTP over TLS.
+ + Last-minute touchups to text messages, HELP text, etc.
+ + Enable modem-signal reading for SCO OSR5 and Unixware 7.
+ + Special superfast TRANSMIT /BINARY /NOECHO /NOWAIT mode added.
+ + Fixed PBX dialing in unmarked-area-code case.
+ + Improved SHOW COMMUNICATIONS tells lockfile directory, typical
+ dialout device name.
+ + Some FTP OPEN command parsing problems fixed.
+ + Some errors in date arithmetic fixed.
+ + New command: SET TERMINAL AUTODOWNLOAD { ..., ERROR { STOP,
+ CONTINUE } }
+ + New command: HELP FIREWALL.
+ + SET MODEM HANGUP-METHOD DTR added as synonym for RS232-SIGNAL
+ + Support for secure URL protocols added: telnets:, ftps:,
+ https:.
+
+ C-Kermit 8.0.201 (8 Feb 2002)
+
+ + Installability as an [159]SSH v2 Subsystem.
+ + [160]SET LOCUS command.
+ + [161]L-versions of CD, DIR, DELETE, MKDIR, etc, to force local
+ execution.
+ + [162]USER and ACCOUNT added as synonyms for FTP USER and FTP
+ ACCOUNT.
+ + [163]SHOW VARIABLES now accepts a list of variables.
+ + Rudimentary support for [164]Caller ID when receiving phone
+ calls.
+ + Up/Down [165]Arrow-key navigation of command history buffer.
+ + [166]Automatic execution of customization file if init file is
+ missing.
+
+ C-Kermit 8.0.206 Beta.01 (11 Oct 2002)
+
+ New commands:
+
+ o ORIENTATION lists location-related variables and their
+ values.
+ o KCD changes to special directories by their symbolic
+ names ("kcd ?" for a list).
+ o SET CD HOME path to specify home directory for CD and KCD
+ commands.
+ o CONTINUE given at top level is equivalent to END -- handy
+ when PROMPT'ed out of a script, to continue the script.
+
+ New switches or operands for existing commands:
+
+ o GETOK /TIMEOUT
+ o ASK, ASKQ, GETOK /QUIET (suppresses error message on
+ timeout)
+ o COPY /APPEND now allows concatenating multiple source
+ files into one dest file.
+ o SET TCP { HTTP-PROXY, SOCKS-SERVER } /USER, /PASSWORD.
+ o DIRECTORY command now accepts multiple filespecs, e.g.
+ "dir a b c".
+
+ SET QUIET ON now also applies to:
+
+ o SET HOST connection progress messages.
+ o "Press the X or E key to cancel" file-transfer message.
+ o REMOTE CD response.
+ o REMOTE LOGIN response.
+
+ Improvements and new features:
+
+ o Numerous FTP client fixes and new features, listed below.
+ o C-Kermit, when in remote mode at the end of a file
+ transfer, now prints a one-line "where" message. Control
+ with SET TRANSFER REPORT.
+ o Unix makefile "install" target now creates an UNINSTALL
+ script.
+ o Improved operation and performance on RFC 2217 Telnet
+ connections.
+ o Improved CONNECT (interactive terminal connection)
+ performance.
+ o HELP text updated for many commands.
+
+ New or fixed makefile targets:
+
+ o Solaris 9 (several variations)
+ o Concurrent PowerMAX
+ o Mac OS X 10.2
+ o FreeBSD 1.0
+ o FreeBSD 4.6, 5.0
+ o AIX 5.2, 5.3
+
+ Bugs fixed (general):
+
+ o Failure to run in VMS Batch fixed.
+ o LDIRECTORY fixed to run Kermit's built-in DIRECTORY
+ command rather than an external one.
+ o Fixed Solaris and other SVORPOSIX builds to find out
+ their full hostnames rather than just the "uname -n"
+ name.
+ o Fixed some problems matching strings that start with ".".
+ o Fixed some problems matching pattern that contain {a,b,c}
+ lists.
+ o Fixed erroneous reporting of text-mode reception as
+ binary when sender did not report the file size (cosmetic
+ only).
+ o Many problems with SWITCH statements fixed.
+ o Fixed SET OPTIONS DIRECTORY /DOTFILES to work for server
+ too.
+ o Fixed DELETE to print an error message if the file was
+ not found.
+ o Fixed SET CONTROL UNPREFIX ALL and SET PREFIXING NONE to
+ do the same thing.
+ o Fixed bugs executing macros from within the ON_EXIT
+ macro.
+ o \fday() and \fnday() fixed for dates prior to 17 Nov
+ 1858.
+ o Serial speed-changing bug in Linux fixed.
+ o "Unbalanced braces" script parsing errors when using
+ \{number} fixed.
+ o "if defined \v(name)" fixed to behave as described in the
+ book.
+ o Fixed Problems caused by LOCAL variables whose names are
+ left substrings of macro names.
+ o The INPUT command was fixed to honor the PARITY setting.
+ o Fixed bug with COPY to existing file that is longer than
+ source file.
+ o REINPUT command failed to strip braces/quotes around its
+ target string.
+ o Network directory lookups didn't work for SSH
+ connections.
+ o REMOTE SET { FILE, TRANSFER } CHARACTER-SET fixed.
+ o Closed some holes whereby an incompletely received file
+ was not deleted when SET FILE INCOMPLETE is DISCARD, e.g.
+ when the Kermit is hung up upon.
+ o SET XFER CHARACTER-SET TRANSPARENT fixed to do the same
+ as SET XFER TRANSLATION OFF.
+ o SET HOST PTY (e.g. SSH) connection fixed to pass along
+ window-size changes.
+ o C-Kermit search path for TAKE files was accidentally
+ disabled.
+
+ FTP client bugs fixed:
+
+ o Character set translation was broken on little-endian
+ (e.g. PC) architectures.
+ o FTP PUT /SERVER-RENAME:, /RENAME-TO:, /MOVE-TO: switches
+ were sticky.
+ o Make SET TRANSFER MODE MANUAL apply to FTP.
+ o Make SET FILE INCOMPLETE { KEEP, DISCARD } apply to FTP.
+ o FTP MGET /UPDATE handled equal times incorrectly.
+ o FTP MGET /RECOVER fixed to ignore file dates, use only
+ size.
+ o FTP MGET /RECOVER sometimes downloaded files it didn't
+ need to.
+ o FTP downloads with TRANSFER DISPLAY BRIEF could give
+ misleading error messages.
+ o FTP MGET temp file not deleted if FTP DEBUG set to OFF
+ after it was ON.
+ o LOCUS not switched back when FTP connection is lost.
+ o Set incoming file date even if it was not completely
+ received.
+ o FTP MGET sent SIZE and MDTM commands even when it didn't
+ have to.
+ o FTP MGET sent SIZE and MDTM commands even when it knew
+ they wouldn't work.
+ o FTP MGET failed if no files were selected for download.
+ o FTP MGET a* b* c* would fail to get any c*'s if no b*'s
+ existed.
+ o Big problems canceling MGET with Ctrl-C.
+ o Some extraneous LOCUS dialogs squelched.
+ o Some inconsistencies in SET FTP FILENAMES AUTO fixed.
+ o Fixed file-descriptor pileup after multiple MGETs when
+ using mkstemp().
+ o Fixed "mget foo", where foo is a directory name.
+
+ FTP improvements:
+
+ o New [167]FTP protocol features added (FEAT, MLSD).
+ o FTP MGET /RECURSIVE now works as expected if server
+ supports MLSD.
+ o FTP MGET /DATES-DIFFER to download if local and remote
+ file dates differ.
+ o FTP DATES default changed to ON.
+ o FTP MPUT, MGET /EXCEPT now allows up to 64 patterns (up
+ from 8).
+ o Top-level SITE and PASSIVE commands added for
+ convenience.
+ o MGET /COLLISION:APPEND /AS-NAME:newfile *.* puts all
+ remote files into one local file.
+ o SET FTP SERVER-TIME-OFFSET for when server has wrong
+ timezone set.
+ o Allow for alternative server interpretations of [M]MPUT
+ /UNIQUE.
+ o SET FTP ANONYMOUS-PASSWORD lets you specify the default
+ anonymous password.
+ o Allow "GET /RECURSIVE path/file" to force local
+ subdirectory creation.
+ o SET FTP DISPLAY is like SET TRANSFER DISPLAY but applies
+ only to FTP.
+ o FTP { ENABLE, DISABLE } new-protocol-feature-name.
+ o FTP MGET /NODOTFILES.
+ o Debug log now records FTP commands and responses in
+ grep-able format.
+
+ [ [168]Top ] [ [169]Contents ] [ [170]C-Kermit ] [ [171]Kermit Home ]
+
+1. FIXES SINCE VERSION 7.0.196 First, the changes from 7.0.196 to 7.0.197...
+Source and makefile tweaks to get successful builds on platforms that were
+not available in time for the 7.0 release:
+
+ * 4.2BSD
+ * 4.3BSD
+ * AIX 4.3
+ * AT&T 3B2 and 3B20
+ * BeOS 4.5
+ * CLIX
+ * Interactive UNIX System V/386 R3.2 V4.1.1
+ * OS-9/68000
+ * OSF/1 1.3.
+ * PS/2 AIX 1.2.1
+ * SCO OSR5.0.x
+ * SCO Xenix 2.3.4
+ * SINIX 5.41/Intel
+ * Stratus FTX
+ * Stratus VOS
+ * SunOS 4.1 with X.25
+ * Ultrix 4.2
+ * Unixware 2.0
+
+ There were no functional changes from 196 to 197.
+
+ Fixes applied after C-Kermit 7.0.197 was released:
+
+ Source code: Big flexelint and "gcc -Wall" audit and cleanup.
+
+ Configuration:
+ * Solaris RTS/CTS (hardware flow control) didn't work.
+ * BSDI RTS/CTS worked only in one direction.
+ * FreeBSD 4.0 with ncurses 5.0 broke interactive command parsing.
+ * QNX-32 build lacked -DBIGBUFOK so couldn't execute big macros.
+
+ Connections:
+ * SET HOST /PTY didn't work on some platforms.
+ * Broken SET HOST /USER:xxx /PASSWORD:yyy /ACCOUNT:zzz switches
+ fixed.
+ * Transparent printing was broken in Unix.
+ * ANSWER 0 (wait forever) didn't work.
+ * Some problems in Multitech modem command strings.
+ * Spurious "?Sorry, can't condition console terminal" errors.
+ * Disabling modem command strings by setting them to nothing broke
+ dialing.
+ * SET DIAL TIMEOUT value was usually ignored.
+ * SET DIAL METHOD PULSE didn't work.
+ * Certain modem commands, if changed, not refreshed if modem type
+ changed.
+ * SET SESSION-LOG command was missing from VMS.
+ * VMS session log format fixed for scripts.
+ * HANGUP by dropping DTR didn't work in NetBSD.
+ * SET FLOW /AUTO versus SET FLOW confusion fixed.
+ * Spurious secondary Solaris lockfile removed.
+ * SCO OSR5 DTR On/Off hangup.
+ * UUCP lockfile race condition.
+
+ Commands and scripts:
+ * Missing CAUTIOUS and FAST commands restored.
+ * Broken PTY command in late-model Linuxes fixed (API changed).
+ * Fixed off-by-one error in command recall when switching direction.
+ * Fixed recall of commands that contain '?'.
+ * COPY /SWAP-BYTES didn't work on some architectures.
+ * Various combinations of COPY switches didn't work.
+ * Various problems with COPY or RENAME with a directory name as
+ target.
+ * SHIFT didn't decrement \v(argc) if used within IF, ELSE, or SWITCH
+ block.
+ * SHIFT didn't affect the \%* variable.
+ * Divide by zero improperly handled in some \function()s.
+ * Problems with RETURN from right-recursive functions.
+ * FSEEK /LINE \%c LAST didn't work if already at end.
+ * Some buffer vulnerabilities and potential memory leaks were
+ discovered and fixed.
+ * \frdirectory() fixed not to follow symbolic links.
+ * SET EXIT WARNING OFF fixed to work when EXIT given in a script.
+ * Missing DELETE and MKDIR error message fixed.
+ * \fday() core dump for ancient dates fixed.
+
+ File transfer:
+ * SEND /COMMAND was broken.
+ * CRECEIVE was broken (but RECEIVE /COMMAND was OK).
+ * Quoting wildcard chars in filenames didn't work.
+ * Problems canceling streaming file transfers with X or Z.
+ * Problems shifting between streaming and windowing file transfer.
+ * Non-FULL file-transfer displays erroneously said STREAMING when
+ not.
+ * An active SEND-LIST prevented GET from working.
+ * SET SERVER GET-PATH interpretation of relative names like "." was
+ wrong.
+ * The MAIL command was broken.
+ * "kermit -s *" might have skipped some files.
+ * Transaction log entries were not made for external protocol
+ transfers.
+ * File count report fixed to show number of files actually
+ transferred.
+ * Fixed filename conversion to convert spaces to underscores.
+ * Made SET PREFIXING / SET CONTROL PREFIX also adjust CLEARCHANNEL.
+ * More "Receive window full" errors fixed.
+ * Broken terminal buffering after curses display in Solaris fixed.
+ * SET FILE INCOMPLETE DISCARD did not work in all cases.
+ * Packet log changed to reformat the start-of-packet character
+ printably.
+ * Dynamic timeouts could grow ridiculously large.
+
+ Character sets:
+ * Hebrew-7 translations missed the letter Tav.
+ * C1 area of CP1252 was ignored.
+ * SET TRANSFER CHARACTER-SET TRANSPARENT could give garbage
+ translations.
+ * TRANSLATE might not work on Little Endian architectures.
+ * Insufficient range checking in certain TRANSLATE operations.
+
+ The following bugs in C-Kermit 8.0.200 were fixed in 8.0.201:
+
+ * An obscure path through the code could cause the Unix version of
+ C-Kermit to dump core during its startup sequence. This happened to
+ only one person, but now it's fixed.
+ * When C-Kermit 8.0 is in Kermit server mode and the client says "get
+ blah", where blah (on the server) is a symlink rather than a real
+ file, the server unreasonably refused to send the linked-to file.
+ * When C-Kermit is an FTP client and says "get foo/bar" (i.e. a
+ filename that includes one or more path segments), it failed to
+ accept the incoming file (this happened only with GET, not MGET).
+ * Array references should be case insensitive but only lowercase
+ array letters were accepted.
+ * SHOW VARIABLES dumped core on \v(sexpression) and \v(svalue).
+ * Spurious refusals of remote directory listings if the remote
+ server's date was set in the past.
+ * In AIX, and maybe elsewhere too, Kermit's COPY command always
+ failed with "Source and destination are the same file" when the
+ destination file didn't exist.
+ * The VMS version of C-Kermit did not work in Batch or when SPAWN'd.
+ To compound the problem, it also pretty much ignored the -B and -z
+ command-line options, whose purpose is to work around such
+ problems.
+ * C-Kermit 8.0 could not be built on IRIX 5.x.
+ * The C-Kermit 8.0 build for QNX6 said it was an "(unknown version)".
+
+ Other fixes are listed in the [172]previous section.
+
+ [ [173]Top ] [ [174]Contents ] [ [175]C-Kermit ] [ [176]Kermit Home ]
+
+2. SSH AND HTTP
+
+2.1. SSH Connections
+
+ This section does not apply to [177]Kermit 95 2.0, which has its own
+ built-in SSH client, which is documented [178]SEPARATELY.
+
+ On most UNIX platforms, C-Kermit can make SSH (Secure SHell) connection
+ by running the external SSH command or program through its
+ pseudoterminal interface. The command is:
+
+ SSH text
+ Tells Kermit to start the external SSH client, passing the given
+ text to it on the command line. Normally the text is just the
+ hostname, but it can be anything else that is acceptable to the
+ ssh client. If the command succeeds, the connection is made and
+ Kermit automatically enters CONNECT (terminal) mode. You can use
+ the SSH command to make a connection to any host that has an SSH
+ server.
+
+ Kermit's SSH command gives you all the features of Kermit on an SSH
+ connection: command language, file transfer, character-set translation,
+ scripting, and all the rest. By default, C-Kermit invokes SSH with "-e
+ none", which disables the ssh escape character and makes the connection
+ transparent for purposes of file transfer. You can, however, change the
+ SSH invocation to whatever else you might need (an explicit path,
+ additional command-line arguments, etc) with:
+
+ SET SSH COMMAND text
+ Specifies the system command that Kermit's SSH command should
+ use to invoke the external SSH client. Use this command to
+ supply a specific path or alternative name, or to include
+ different or more command-line options.
+
+ In most cases, these connections work quite well. They can be scripted
+ like any other connection, and file transfer goes as fast as, or faster
+ than, on a regular Telnet connection. In some cases, however, the
+ underlying pseudoterminal driver is a limiting factor, resulting in
+ slow or failed file transfers. Sometimes you can work around such
+ problems by reducing the Kermit packet length. Note that Kermit does
+ not consider SSH connections to be reliable, so it does not offer to
+ use streaming in Kermit protocol transfers (but you can force it with
+ SET RELIABLE or SET STREAMING if you wish).
+
+ The SSH command is like the TELNET command: it enters CONNECT mode
+ automatically when the connection is made. Therefore, to script an SSH
+ connection, use:
+
+ set host /pty ssh -e none [ other-options ] host
+ if fail ...
+
+ to make the connection.
+
+ Here's a sequence that can be used to make a connection to a given host
+ using Telnet if the host accepts it, otherwise SSH:
+
+ if not defined \%1 exit 1 Usage: \%0 host
+ set quiet on
+ set host \%1 23 /telnet
+ if fail {
+ set host /pty ssh -l \m(user) -e none \%1
+ if fail exit 1 \%1: Telnet and SSH both fail
+ echo SSH connection to \%1 successful
+ } else {
+ echo Telnet connection to \%1 successful
+ }
+
+ In SSH v2, it is possible to make an SSH connection direct to a Kermit
+ server system if the host administrator has configured the SSH server
+ to allow this; [179]CLICK HERE for details.
+
+ Since Kermit uses external ssh client software, and since there are
+ different ssh clients (and different releases of each one), the exact
+ command to be used to make an SSH/Kermit connection can vary. Here is
+ the command for the OpenSSH 3.0.2p1 client:
+
+set host /pipe ssh -e none [ -l username ] -T -s hostname kermit
+
+ Example:
+
+set host /pipe ssh -e none -l olga -T -s hq.xyzcorp.com kermit
+
+ The SSH client might or might not prompt you for a password or other
+ information before it makes the connection; this depends on your SSH
+ configuration (your public and private keys, your authorized hosts
+ file, etc). Here's a brief synopsis of the OpenSSH client command
+ syntax ("man ssh" for details):
+
+ -e none
+ This tells the SSH client to use no escape character. Since we
+ will be transferring files across the connection, we don't want
+ the connection to suddenly block because some character in the
+ data.
+
+ -l username
+ This is the username on the remote host. You can omit the -l
+ option and its argument if your local and remote usernames are
+ the same. If they are different, you must supply the remote
+ username.
+
+ -T
+ This tells the SSH client to tell the SSH server not to allocate
+ a pseudoterminal. We are not making a terminal connection, we
+ don't need a terminal, and in fact if a terminal were allocated
+ on the remote end, the connection would not work.
+
+ -s ... kermit
+ This tells the SSH client to tell the SSH server to start the
+ specified subsystem ("kermit") once the connection is made. The
+ subsystem name comes after the hostname.
+
+ hostname
+ The IP host name or address of the desired host.
+
+ You might want to include other or additional ssh command-line options;
+ "man ssh" explains what they are. Here are some examples for the
+ OpenSSH 3.0.2p1 client:
+
+ -oClearAllForwardings yes
+ -oForwardAgent no
+ -oForwardX11 no
+ -oFallbackToRsh no
+ These ensure that a secure connection is used and that the
+ connection used for file transfer is not also used for
+ forwarding other things that might be specified in the
+ ssh_config file.
+
+ -oProtocol 2
+ (i.e. SSH v2) Ensures that the negotiated protocol supports
+ subsystems.
+
+ Once you have an SSH connection to a Kermit server, it's just like any
+ other connection to a Kermit server (and very similar to a connection
+ to an FTP server). You give the client file transfer and management
+ commands for the server, and the server executes them. Of course you
+ can also give the client any other commands you wish.
+
+ [ [180]SSH Kermit Server Subsystem ] [ [181]Kermit 95 Built-in SSH
+ Client ]
+
+2.2. HTTP Connections
+
+ Hypertext Transfer Protocol, or HTTP, is the application protocol of
+ the World Wide Web (WWW), used between Web browsers (clients) and Web
+ servers. It allows a client to get files from websites, upload files to
+ websites, delete files from websites, get information about website
+ directories and files, and interact with server-side CGI scripts.
+ C-Kermit includes an HTTP client capable of both clear-text and secure
+ HTTP connections, that can do all these tasks and can be automated
+ through the Kermit scripting language.
+
+ Although C-Kermit 7.0 could make HTTP connections to Web servers, it
+ could do so only when no other connection was open, and the procedure
+ was somewhat awkward. C-Kermit 8.0 improves matters by:
+
+ * Allowing an HTTP connection to be open at the same time as a
+ regular SET LINE or SET HOST connection, and also at the same time
+ as an FTP connection ([182]Section 3);
+ * Upgrading the HTTP protocol level from 1.0 to 1.1, thus allowing
+ for persistent connections, in which a series of commands can be
+ sent on the same connection, rather than only one as in HTTP 1.0
+ (and C-Kermit 7.0);
+ * Providing for "one-shot" URL-driven HTTP operations such as GET or
+ PUT.
+ * Providing a distinct HTTP command-line personality.
+
+ Persistent HTTP connections are managed with the following commands:
+
+ HTTP [ switches ] OPEN [ security-options ] host-or-url [ port ]
+ Opens a persistent connection to the specified host (IP host
+ name or address) on the specified port. If any switches
+ (options, listed in the next section) are included, their values
+ are saved and used for all subsequent HTTP action commands on
+ the same connection. If no port is specified, HTTP (80) is used.
+ A Uniform Resource Locator (URL, [183]RFC 1738) can be given
+ instead of a hostname (or address) and port (but the URL can not
+ include a directory/file path). The security options are
+ explained [184]below. The HTTP OPEN command replaces the
+ C-Kermit 7.0 SET HOST hostname HTTP command, which no longer
+ works with HTTP GET and related commands.
+
+ HTTP CLOSE
+ Closes any open HTTP connection and clears any saved switch
+ values.
+
+ A URL starts with a protocol name, which must be http or https in this
+ case; optionally includes a username and password; and must contain a
+ host name or address:
+
+ protocol://[user[.password]]@host[:port][URI]
+
+ HTTP is Hypertext Transfer Protocol. HTTPS is the secure (SSL/TLS)
+ version of HTTP. The TCP service port is derived from the protocol
+ prefix (so normally the ":port" field is omitted). Thus the URL
+ protocol name specifies a default TCP service port and the URL user and
+ password fields can take the place of the /USER and /PASSWORD switches
+ ([185]Section 2.2.1). The optional URI is a "compact string of
+ characters for identifying an abstract or physical resource" ([186]RFC
+ 2396), such as a file. It must begin with a slash (/); if the URI is
+ omitted, "/" is supplied. Examples:
+
+ http open http://www.columbia.edu/
+ Equivalent to http open www.columbia.edu or http open
+ www.columbia.edu http.
+
+ http open https://olga.secret@www1.xyzcorp.com/
+ Equivalent to http /user:olga /pass:secret open www1.xyzcorp.com
+ https.
+
+ Persistence is accomplished unilaterally by C-Kermit 8.0. An HTTP 1.0
+ server closes the connection after each action. Although HTTP 1.1
+ allows multiple actions on the same connection, an HTTP 1.1 server
+ tends to close the connection if it is idle for more than a few
+ seconds, to defend itself against denial-of-service attacks. But when
+ you use Kermit's HTTP OPEN command to create a connection, Kermit
+ reopens it automatically (if necessary) for each HTTP action until you
+ close it with HTTP CLOSE, regardless of the server's HTTP protocol
+ version, or how many times it closes the connection.
+
+ Firewalls can be negotiated through proxies with the following
+ commands:
+
+ SET TCP HTTP-PROXY [ host[:port] ]
+ If a host (by hostname or IP address) is specified, Kermit uses
+ it as a proxy server when attempting outgoing TCP connections --
+ not only HTTP connections, but all TCP/IP connections, Telnet
+ and FTP included. This allows Kermit to adapt to the HTTP
+ firewall penetration method (as opposed to other methods such as
+ SOCKS4). If no hostname or ip-address is specified, any
+ previously specified Proxy server is removed. If no port number
+ is specified, the "http" service is used. This command must be
+ given before the HTTP OPEN command if a proxy is to be used or
+ canceled.
+
+ HTTP [ switches ] CONNECT host[:port]
+ Instructs the HTTP server to act as a proxy, establishing a
+ connection to the specified host (IP hostname or address) on the
+ given port (80 = HTTP by default) and to redirect all data
+ transmitted between Kermit and itself to the given host for the
+ life of the connection. This command is to be used only for
+ debugging HTTP proxy connections. If a proxy connection is
+ required, instruct Kermit to use the proxy with the SET TCP
+ HTTP-PROXY command.
+
+2.2.1. HTTP Command Switches
+
+ HTTP switches, like all other switches, are optional. When HTTP
+ switches are included with the HTTP OPEN command, they apply
+ automatically to this and all subsequent HTTP actions (GET, PUT, ...)
+ on the same connection until an HTTP CLOSE command is given. So if you
+ include switches (or the equivalent URL fields, such as user and
+ password) in the HTTP OPEN command, you can omit them from subsequent
+ commands on the same connection. If the connection has closed since
+ your last command, it is automatically reopened with the same options.
+
+ If you include switches with an HTTP action command (such as GET or
+ PUT), they apply only to that command.
+
+ /USER:name
+ To be used in case a page requires a username for access. The
+ username is sent with page requests. If it is given with the
+ OPEN command it is saved until needed. If a username is included
+ in a URL, it overrides the username given in the switch.
+ CAUTION: Username and password (and all other information,
+ including credit card numbers and other material that you might
+ prefer to protect from public view) are sent across the network
+ in clear text on regular HTTP connections, but authentication is
+ performed securely on HTTPS connections.
+
+ /PASSWORD:text
+ To be used in case a web page requires a password for access.
+ The password is sent with page requests. If it is given with the
+ OPEN command it is saved until needed. If a password is given in
+ a URL, it overrides the one given here. CAUTION: (same as for
+ /USER:).
+
+ /AGENT:user-agent
+ Identifies the client to the server. Overrides the default agent
+ string, which is "C-Kermit" (for C-Kermit) or "Kermit-95" (for
+ Kermit 95).
+
+ /ARRAY:array-designator
+ Tells Kermit to store the response headers in the given array,
+ one line per element. The array need not be declared in advance.
+ Example: /array:&a.
+
+ /TOSCREEN
+ Tells Kermit to display any response text on the screen. It
+ applies independently of the output file specification; thus it
+ is possible to have the server response go to the screen, a
+ file, both, or neither.
+
+ /HEADER:header-item(s)
+ Used for specifying any optional headers to be sent with HTTP
+ requests.
+
+ /HEADER:tag:value
+
+ To send more than one header, use braces for grouping:
+
+ /HEADER:{{tag:value}{tag:value}...}
+
+ For a list of valid tags and value formats see [187]RFC 2616,
+ "Hypertext Transfer Protocol -- HTTP/1.1". A maximum of eight
+ headers may be specified.
+
+2.2.2. HTTP Action Commands
+
+ HTTP actions can occur within a persistent connection, or they can be
+ self-contained ("connectionless"). A persistent HTTP connection begins
+ with an HTTP OPEN command, followed by zero or more HTTP action
+ commands, and is terminated with an HTTP CLOSE command:
+
+ http open www.columbia.edu
+ if failure stop 1 HTTP OPEN failed: \v(http_message)
+ http get kermit/index.html
+ if failure stop 1 HTTP GET failed: \v(http_message)
+ (more actions possible here...)
+ http close
+
+ A self-contained HTTP action occurs when a URL is given instead of a
+ remote file name to an HTTP action command. In this case, Kermit makes
+ the HTTP connection, takes the action, and then closes the connection.
+ If an HTTP connection was already open, it is closed silently and
+ automatically.
+
+ http get http://www.columbia.edu/kermit/index.html
+
+ Kermit's HTTP action commands are as follows. Switches may be included
+ with any of these to override switch (or default) values given in the
+ HTTP OPEN command.
+
+ HTTP [ switches ] GET remote-filename [ local-filename ]
+ Retrieves the named file from the server specified in the most
+ recent HTTP OPEN command for which a corresponding HTTP CLOSE
+ command has not been given. The filename may not include
+ wildcards (HTTP protocol does not support them). If no HTTP OPEN
+ command is in effect, this form of the HTTP GET command fails.
+ The default local filename is the same as the remote name, but
+ with any pathname stripped. For example, the command http get
+ kermit/index.html stores the file in the current local directory
+ as index.html. If the /HEADERS: switch is included, information
+ about the file is also stored in the specified array (explained
+ in [188]Section 2.2.3). All files are transferred in binary
+ mode. HTTP does not provide for record-format or character-set
+ conversion.
+
+ HTTP [ switches ] GET url [ local-filename ]
+ When HTTP GET is given a URL rather than a filename, Kermit
+ opens a connection to the designated server (closing any
+ previously open HTTP connection), gets the file, and then closes
+ the connection. If the URL does not include a filename,
+ index.html is supplied. This is the self-contained one-step
+ "connectionless" method for getting a file from a Web server.
+ The data is not interpreted; HTTP GET is like "lynx -source"
+ rather than "lynx -dump".
+
+ In the remaining HTTP action commands, the distinction between a remote
+ filename and a URL are the same as in the HTTP GET command.
+
+ HTTP [ switches ] HEAD remote-filename-or-url [ local-filename ]
+ Like GET except without actually getting the file; instead it
+ retrieves only the headers. If the /ARRAY: or /TOSCREEN switch
+ is included, there is no default local output filename but you
+ can still specify one. If neither of these switches is included,
+ the default local filename is the same as the remote filename,
+ but with any path stripped and with ".head" appended. The HEAD
+ command can be used in a script with the /ARRAY: switch to
+ retrieve information about the requested resource to determine
+ whether the resource should actually be retrieved with a
+ subsequent GET request.
+
+ HTTP [ switches ] INDEX remote-directory-or-url [ local-filename ]
+ Asks the server to send a listing of the files in the given
+ server directory. This command is not supported by most Web
+ servers. Even when it is supported, there is no standard format
+ for the listing.
+
+ HTTP [ switches ] POST [ /MIME-TYPE:type ] source-file
+ remote-path-or-url [ result-file ]
+ Sends data to a process running on the remote host; the result
+ is usually an HTML file but could be anything. The data to be
+ posted must be read from a local file (the source-file). If a
+ result file is specified, Kermit stores the server's response in
+ it.
+
+ HTTP [ switches ] PUT [ MIME-TYPE:type ] local-file [
+ remote-file-or-url [ result-file ] ]
+ Uploads a local file to the server. Only the name of a single
+ file can be given; wildcards (and group transfers) are not
+ supported by HTTP protocol. If no remote filename is given, the
+ file is sent with the same name as the local file, but with any
+ pathname stripped.
+
+ HTTP [ switches ] DELETE remote-file-or-url [ local-result-file ]
+ Asks the server to delete the specified single file. If a result
+ file is specified, it will contain any response data returned by
+ the server.
+
+ Note the limitations of HTTP protocol compared to (say) FTP or Kermit.
+ There is no command for changing directories, no standard way to get
+ file or directory lists, no way to transfer file groups by using
+ wildcard notation, etc, and therefore no good way to (say) fetch all
+ pages, descend through subdirectories, perform automatic updates, etc.
+ There is no assurance a connection will stay open and, as noted, there
+ is no provision for data conversion between unlike platforms. The
+ data's MIME headers can be used for postprocessing.
+
+2.2.3. HTTP Headers
+
+ Each HTTP request and response contains a set of name/value pairs
+ called headers. HTTP headers are specified in [189]RFC 2616. For
+ example, an HTTP GET request for /index.html on www.columbia.edu
+ contains the following headers:
+
+ GET /index.html HTTP/1.1
+ Host: www.columbia.edu:80
+ User-agent: C-Kermit 8.0
+ Authorization: Basic base64-encoded-username-password
+
+ These might be followed by any others specified with a /HEADERS:
+ switch:
+
+ Accept: image/gif, image/x-xbitmap, image/jpeg, *.*
+ Accept-Encoding: gzip
+ Accept-Language: en
+ Accept-Charset: iso-8859-1,utf-8
+ Cookie: cookie-data
+
+ The server sends back a short report about the file prior to sending
+ the file contents. Example:
+
+ HTTP/1.1 200 OK
+ Date: Fri, 24 Aug 2001 21:09:39 GMT
+ Server: Apache/1.3.4 (Unix)
+ Last-Modified: Mon, 06 Aug 2001 21:16:13 GMT
+ ETag: "1fa137-10d7-3b6f091d"
+ Accept-Ranges: bytes
+ Content-Length: 4311
+ Content-Type: text/html
+
+ If you want to have this information available to a Kermit script you
+ can use the /ARRAY switch to have Kermit put it in array, one line per
+ array element. Example:
+
+ set exit warning off
+ http open www.columbia.edu
+ if fail exit 1 Can't reach server
+ http /array:&a get /index.html
+ if fail exit 1 Can't get file
+ echo Header lines: \fdim(&a)
+ for \%i 1 \fdim(&a) 1 {
+ echo \%i. \&a[\%i]
+ }
+
+ Note that the "Date:" item is the current date and time; the
+ "Last-Modified:" item is the file's modification date and time. An
+ example showing how to use this information is presented in
+ [190]Section 8.13.7.
+
+2.2.4. Secure HTTP Connections
+
+ SSL/TLS (Secure Sockets Layer / Transport Layer Security) is the
+ protocol used to secure HTTP, SMTP, and other Internet applications.
+ See the [191]C-Kermit Reference Section 5.4 for an introduction to
+ SSL/TLS. To make a secure HTTP connection, you need:
+
+ 1. A secure client (a version of C-Kermit or Kermit 95 with SSL/TLS
+ security built in). Type "check ssl" at the Kermit prompt to make
+ sure you have it.
+ 2. A secure server to connect to.
+ 3. The CA Root Certificate used to authenticate the server to the
+ client. (see [192]Section 15 of the security reference for an
+ introduction to certificates).
+
+ And you must make a connection to the secure HTTP port: service name
+ HTTPS, port number 443 (as opposed to service HTTP, port 80). You can
+ also make secure connections to other ports by including the /TLS or
+ /SSL switch with the HTTP OPEN command, if the host supports SSL/TLS on
+ the given port:
+
+ The quality of the SSL/TLS connection depends on the cipher suite.
+ There are several possibilities:
+
+ Anonymous cipher suite:
+ If an anonymous cipher suite is negotiated, the connection is
+ encrypted but there is no authentication. This connection is
+ subject to a Man-In-The-Middle (MITM) attack.
+
+ X.509 certificate on the server:
+ When you connect to certain secure servers, an X.509 certificate
+ is returned. This certificate is issued to a special hostname,
+ something like www1.xyzcorp.com or wwws.xyzcorp.com (rather than
+ the normal www.xyzcorp.com). It is signed by the host's
+ Certificate Authority (CA). If the host certificate is
+ configured on the client, it can be used to verify the
+ certificate received from the server. If the certificate it
+ verified as authentic, a check is made to ensure it has not
+ expired and it was issued to the host you were attempting to
+ connect to. If you had asked to connect to (say) www.xyzcorp.com
+ but were given a certificate for www1.xyzcorp.com, you would be
+ prompted for permission to continue.
+
+ If the verification succeeded, the connection would be encrypted
+ with one-way (server-to-client) authentication. This connection
+ is not subject to a MITM attack.
+
+ If a username and password are transmitted over this connection,
+ they are not subject to interception. However, the standard
+ risks associated with passing the password to the host for
+ verification apply; for example, if the host has been
+ compromised, the password will be compromised.
+
+ X.509 client certificate:
+ If a connection has been established with an X.509 server
+ certificate, the server can ask the client to send a certificate
+ of its own. This certificate must be verified against a CA Root
+ certificate. The certificate itself (or subject info from the
+ certificate) is used to determine the authorization for the
+ client, and if successful, the username and password need not be
+ sent to the server.
+
+ Kerberos 5:
+ Instead of using X.509 certificates, Kerberos 5 can be used to
+ perform the authentication and key exchange. In this situation,
+ there is mutual authentication between the client and server.
+ The Kerberos 5 principal is used by the server to look up the
+ appropriate authorization data. There is no need to send
+ username and password.
+
+ An HTTP connection is made with the HTTP OPEN command:
+
+ HTTP [ switches ] OPEN [ { /SSL, /TLS } ] host [ port ]
+ If /SSL or /TLS switches are included (these are synonyms), or
+ if the service is HTTPS or the port is 443, a secure connection
+ is attempted using the current authentication settings; see HELP
+ SET AUTHENTICATION for details ([193]Section 6.2 of the security
+ reference). If the no /SSL or /TLS switch is included but the
+ port is 443 or the service is HTTPS, a secure connection is
+ attempted. If an /SSL or /TLS switch is included but a port is
+ not specified, an SSL/TLS connection is attempted on the default
+ port (80).
+
+ Certificates are covered in the separate [194]Kermit Security Reference
+ for C-Kermit 8.0. You should let Kermit know to verify certificates
+ with the SET AUTHENTICATION TLS command. For example:
+
+ SET AUTHENTICATION TLS CRL-DIR directory
+ Specifies a directory that contains certificate revocation files
+ where each file is named by the hash of the certificate that has
+ been revoked.
+
+ SET AUTHENTICATION TLS CRL-FILE filename
+ Specifies a file that contains a list of certificate
+ revocations.
+
+ SET AUTHENTICATION TLS VERIFY-DIR directory
+ Specifies a directory that contains root CA certificate files
+ used to verify the certificate chains presented by the peer.
+ Each file is named by a hash of the certificate.
+
+ SET AUTHENTICATION TLS VERIFY-FILE filename
+ Specifies a file that contains root CA certificates to be used
+ for verifying certificate chains.
+
+ SET AUTHENTICATION TLS VERIFY OFF
+ Tells Kermit not to require a certificate and accept any
+ certificate that is presented regardless of whether it is valid.
+
+ There are many other options; see the security document for details.
+
+ Now suppose you need need to fetch the file denoted by the following
+ URL:
+
+ https://myuserid:mypassword@wwws.xyzcorp.com/clients/info/secret.html
+
+ Once you have set up the handling of certificates as desired, you can
+ use the following Kermit commands:
+
+ http /user:myuserid /password:mypassword open www1.xyzcorp.com https
+ if success {
+ http get /clients/info/secret.html
+ http close
+ }
+
+ As another example, let's say that you have a web form you need to
+ populate with three fields: red,white and blue.
+
+ <FORM ACTION="http://www.xyzcorp.com/cgi-bin/form.cgi" METHOD="POST">
+ <INPUT NAME="Red">
+ <INPUT NAME="White">
+ <INPUT NAME="Blue">
+ </FORM>
+
+ You can handle this with the HTTP POST command. The data to be posted
+ is stored in the local file data.txt.
+
+ Red=seven stripes&White=six stripes&Blue=fifty stars
+
+ and the response from the server will be stored into response.txt.
+
+ http open www.xyzcorp.com http
+ if success {
+ http /array:c post data.txt /cgi-bin/form.cgi response.txt
+ http close
+ }
+
+ In this scenario, the Common Gateway Interface (CGI) sends a response
+ whether it succeeds or fails in a script-dependent manner. The script
+ can either report success and enclose the response data; or it might
+ send a 302 Found error which indicates that the "Location:" header
+ should be used to determine the URL at which the data can be found.
+
+2.2.5. HTTP Variables
+
+ \v(http_code)
+ The HTTP protocol code number of the most recent server reply,
+ e.g. 404 for "not found".
+
+ \v(http_connected)
+ 1 when an HTTP connection is open, 0 when there is no HTTP
+ connection.
+
+ \v(http_host)
+ If an HTTP connection is open, the hostname:port, e.g.
+ www.columbia.edu:80; otherwise, empty.
+
+ \v(http_message)
+ Server error message, if any, from most recent HTTP command.
+
+ \v(http_security)
+ A list of the security parameters and values for the current
+ connection, if any. Empty if the connection is not to a secure
+ server, or there is no connection.
+
+ To display all the HTTP variables at once, type SHOW VAR HTTP:
+
+ C-Kermit> http open www.columbia.edu
+ C-Kermit> http get lkjlkjlkjlkj
+ C-Kermit> sho var http
+ \v(http_code) = 404
+ \v(http_connected) = 1
+ \v(http_host) = www.columbia.edu:80
+ \v(http_message) = Not Found
+ \v(http_security) = NULL
+ C-Kermit>
+
+2.2.6. The HTTP Command-Line Personality
+
+ If you invoke C-Kermit with the name "http" or "https", you can use a
+ special set of HTTP-specific command-line options. You can do this by
+ creating a symbolic linke "http" or "https" to the C-Kermit 8.0
+ executable, or by having a separate copy of it called "http" or
+ "https". Here's the usage message ("http -h"):
+
+ Usage: ./http host [ options... ]
+ -h This message.
+ -d Debug to debug.log.
+ -S Stay (issue command prompt when done).
+ -Y Do not execute Kermit initialization file.
+ -q Quiet (suppress most messages).
+ -u name Username.
+ -P password Password.
+ -g pathname Get remote pathname.
+ -p pathname Put remote pathname.
+ -H pathname Head remote pathname.
+ -l pathname Local path for -g, -p, and -H.
+ -z opt[=value] Security options...
+ cert=file Client certificate file
+ certsok Accept all certificates
+ key=file Client private key file
+ secure Use SSL
+ verify=n 0 = none, 1 = peer , 2 = certificate required
+
+ The "host" argument is the name of a Web host, e.g. www.columbia.edu.
+ The action options are -p, -g, and -H. If you give an action option,
+ Kermit does the action and then exits. If you give a host without an
+ action option, Kermit makes an HTTP connection to the host and then
+ gives you the C-Kermit prompt. Here's a simple example that fetches a
+ publicly readable Web page:
+
+ http www.columbia.edu -g kermit/index.html
+
+ If you need to access a website for which a username and password are
+ required, you can supply them on the command line with -u and -P. If
+ you include a username but omit the password, Kermit prompts you for
+ it:
+
+ http www.columbia.edu -u olga -p kermit/index.html -l index.html
+ Password:
+
+ Note that when PUT'ing files to websites, you have to supply both the
+ -p (remote pathname) and -l (local path) options.
+
+ If your version of Kermit is built with SSL/TLS security, you can also
+ use the -z option to make secure HTTP (https) connections.
+
+ Finally, as noted in [195]Section 16, you can also give a URL instead
+ of a host name and options.
+
+ [ [196]Top ] [ [197]Contents ] [ [198]C-Kermit Home ] [ [199]Kermit
+ Home ]
+
+3. KERMIT'S BUILT-IN FTP CLIENT
+
+ 3.1. [200]Making and Managing FTP Connections
+ 3.2. [201]Making Secure FTP Connections
+ 3.3. [202]Setting FTP Preferences
+ 3.4. [203]Managing Directories and Files
+ 3.5. [204]Uploading Files With FTP
+ 3.6. [205]Downloading Files With FTP
+ 3.7. [206]Translating Character Sets
+ 3.8. [207]FTP Command Shortcuts
+ 3.9. [208]Dual Sessions
+ 3.10. [209]Automating FTP Sessions
+ 3.11. [210]Advanced FTP Protocol Features
+
+ Earlier versions of C-Kermit and K95 included an FTP command, but it
+ simply invoked an external FTP client. Now, by popular demand, Kermit
+ includes its own built-in FTP client that offers the following
+ advantages over traditional FTP clients (and its previous interface to
+ them):
+
+ * Any of Kermit's built-in [211]security methods can be used to
+ establish and conduct secure FTP sessions with [212]FTP servers
+ that support these methods. (Security modules can be subject to
+ export restrictions.)
+ * Kermit's FTP client uses "passive mode" by default to avoid
+ blockage by firewalls and network address translators. Of course
+ active mode can be chosen too when needed.
+ * [213]Character sets can be translated as part of the transfer
+ process even when the FTP server does not support character-set
+ translation, including to/from the new Internet standard
+ international character set, [214]Unicode UTF-8. This includes both
+ the file's name and (for text files only) its contents.
+ * All of C-Kermit's [215]file-selection mechanisms are available:
+ size, date, name patterns and lists, exception lists, etc.
+ * [216]Atomic file movement capabilities are provided (delete, move,
+ or rename files automatically after successful transfer).
+ * The correct file type, "ascii" (i.e. text) or binary, is chosen
+ automatically for each file (explained in [217]Section 4), and any
+ mixture of text and binary files can be sent in a single operation,
+ even across platforms.
+ * Update mode ("don't bother transferring files that didn't change
+ since last time") and recovery (resumption of an interrupted
+ transfer from the point of failure) are available in both
+ directions.
+ * When uploading files from UNIX to UNIX, the file's permissions can
+ be preserved if desired.
+ * Recursive directory-tree PUTs are supported between any two
+ platforms that have tree-structured file systems. Recursive GETs
+ are supported between like platforms if the server cooperates and
+ between like or unlike platforms if the server supports MLSD
+ ([218]Section 3.11).
+ * When receiving files, all of Kermit's file collision actions are
+ available: backup, update, refuse, rename, etc.
+ * Multi-file transfers can be interrupted on a per-file basis,
+ automatically skipping to the next file.
+ * FTP sessions are [219]fully scriptable.
+ * An entire FTP session (connect, login, CD, upload or download,
+ logout) can be specified on the command line without using a
+ script.
+ * All of Kermit's logging options and formats are available to keep
+ an accurate and complete record of each connection and file
+ transfer, and to aid in troubleshooting.
+ * All of Kermit's file-transfer display options are available
+ (fullscreen, brief, CRT, serial, none).
+
+ And best of all:
+ * Kermit doesn't give you those annoying per-file prompts every time
+ you start a multi-file transfer without remembering to give a
+ "prompt" command first :-).
+
+ [ [220]Top ] [ [221]FTP Top ] [ [222]FTP Client Overview ] [ [223]FTP
+ Script Tutorial ] [ [224]C-Kermit Home ] [ [225]Kermit Home ]
+
+3.1. Making and Managing FTP Connections
+
+ Each copy of Kermit can have one FTP connection open at a time. FTP
+ connections are independent of regular terminal connections; a terminal
+ connection (serial or network via SET LINE, DIAL, SET HOST, TELNET,
+ etc) may be, but need not be, open at the same time as an FTP
+ connection, and terminal connections can also be closed, and new
+ connections opened, without interfering with the FTP connection (and
+ vice versa). Thus, for example, Kermit can have an FTP connection and a
+ TELNET connection open to the same host simultaneously, using the
+ TELNET connection (e.g.) to send mail or take other desired actions as
+ various FTP actions complete. Of course, each copy of Kermit can do
+ only one thing at a time, so it can't (for example) transfer a file
+ with FTP and another file with Kermit protocol simultaneously.
+
+ A Kermit FTP session can be established by [226]command-line options,
+ by [227]URL, or by [228]interactive commands.
+
+3.1.1. Kermit Command-Line Options for FTP
+
+ The new command-line option '-9' (sorry, we're out of letters) can be
+ used when starting C-Kermit, telling it to make an FTP connection:
+
+ kermit -9 hostname
+
+ or if a non-default FTP port is needed:
+
+ kermit -9 hostname:port
+
+ You can also specify the username on the command line with the -M ("My
+ User ID") option that was already there for other connection types:
+
+ kermit -9 hostname -M olga
+
+ If you specify the username on the command line, Kermit uses it when
+ making the connection and does not prompt you for it (but it does
+ prompt you for the password if one is required).
+
+ Once the connection is made, you get the regular Kermit prompt, and can
+ give interactive commands such as the ones described below. When you
+ give a BYE command, Kermit closes the session and exits, just as a
+ regular FTP client would do. If you don't want Kermit to exit when you
+ give a BYE command, include the -S ("Stay") option on the command line.
+
+ Other Kermit command-line options that are not specific to non-FTP
+ connections should affect the FTP session in the expected ways; for
+ example, -i and -T force binary and text mode transfers, respectively.
+
+ File transfers can not be initiated on the "kermit -9" command line;
+ for that you need to use Kermit's FTP personality (next section) or you
+ can use URLs ([229]Section 3.1.3).
+
+3.1.2. The FTP Command-Line Personality
+
+ If you want to replace your regular FTP client with C-Kermit, you can
+ make a link called "ftp" to the C-Kermit binary (or you can store a
+ copy of the C-Kermit binary under the name "ftp"). When C-Kermit is
+ invoked with a program name of "ftp" (or "FTP", case doesn't matter),
+ it assumes the command-line personality of the regular FTP client:
+
+ ftp [ options ] hostname [ port ]
+
+ In this case the options are like those of a regular FTP client:
+
+ -d Debug: enables debug messages and creates a debug.log file.
+ -n No autologin: Kermit should not send your user ID automatically.
+ -t Packet trace: accepted but is treated the same as -d.
+ -v Verbose: accepted but ignored (operation is verbose by default).
+ -i Not interactive: accepted but ignored.
+
+ and the hostname can also be a URL (explained in [230]Section 3.1.3).
+ To specify a non-default TCP port for the FTP server, include the port
+ number or name after the hostname.
+
+ There are also some bonus options that allow you to execute an entire
+ FTP session from the shell command line, as long as you don't include
+ the -n option. These are not available with regular FTP clients, and at
+ least one of these options (-g) conflicts with UNIX ftp (where -g means
+ "no globbing", which does not apply to Kermit), and some of them (like
+ the options above) also conflict with regular Kermit command-line
+ options:
+
+ -m mode = "passive" (default) or "active"
+ -Y Don't execute the Kermit initialization file [1]
+ -q Quiet, suppresses all but error messages [1]
+ -S Stay, don't exit automatically [1]
+ -A Autologin anonymously [2]
+ -u name Username for autologin [2] (synonym: -M [1])
+ -P password Password for autologin (see cautions below) [2]
+ -D directory cd after autologin [2]
+ -b Binary mode [2]
+ -a Text ("ascii") mode [2] (synonym: -T [1])
+ -R Recursive (works with -p) [4]
+ -p files Files to put (upload) after autologin [2] (synonym: -s [1])
+ -g files Files to get (download) after autologin [3]
+
+ [1] Same as Kermit, not available in regular FTP clients.
+ [2] Conflicts with Kermit, not available in regular FTP clients.
+ [3] Same as Kermit, conflicts with regular FTP clients.
+ [4] Conflicts with Kermit, available in some FTP clients.
+
+ Fancier options such as restart, character-set translation, filename
+ collision selection, automatic move/rename/delete, etc, are not
+ available from the command line; for these you can use the commands
+ described in the following sections. The -R option might also work with
+ -g (GET) but that depends on the server.
+
+ The following security options are also available, explained in
+ [231]Section 3.2:
+
+ -k realm Kerberos 4 realm [4]
+ -f Kerberos 5 credentials forwarding [4]
+ -x autoencryption mode [4]
+ -c cipher SRP cipher type [4]
+ -H hash SRP encryption hash [4]
+ -z option Security options [4]
+
+ If you include -A or specify a name of "anonymous" or "ftp", you are
+ logged in anonymously and, in the absence of -P, Kermit automatically
+ supplies a password of "user@host", where "user" is your local user ID,
+ and "host" is the hostname of the computer where Kermit is running. If
+ you do not include -p or -g, Kermit enters command mode so you can type
+ commands or execute them from a script.
+
+ If you include -p or -g, Kermit attempts to transfer the specified
+ files and then exits automatically at the end of the transfer unless
+ you also included -S (Stay). It uses the "brief" file transfer display
+ (one line per file) unless you include the -q option to suppress it.
+
+ When uploading files with -p, Kermit switches automatically between
+ text and binary mode for each file.
+
+ When downloading, you can either specify a particular mode (text or
+ binary) to be used for all the files, or you can let Kermit select the
+ type for each file automatically, based on its name (see [232]Sections
+ 3.5 and [233]3.6 for greater detail). In UNIX be sure to quote any
+ wildcard characters to prevent the shell from expanding them, as shown
+ in the examples just below. Filename collisions are handled according
+ Kermit's FILE COLLISION setting (if specified in your Kermit
+ customization file; otherwise the default, which is BACKUP).
+
+ It should go without saying that the -P option should be used with
+ caution. In addition to the well-known risks of transmitting plaintext
+ passwords over the Internet, in this case the password also echos to
+ the screen if you type it, and can be seen in ps and w listings that
+ show the user's currently active command and command-line arguments.
+ Thus command-line FTP sessions are most appropriate for secure or
+ anonymous connections (those that do not require passwords).
+
+ Here's an example in which you download the latest C-Kermit "tarball"
+ from the Columbia University FTP archive:
+
+ ftp -A kermit.columbia.edu -bg kermit/archives/ckermit.tar.gz
+
+ This assumes that "ftp" is a symbolic link to C-Kermit. It logs you in
+ anonymously and gets the ckermit.tar.gz file in binary mode from the
+ kermit/archives directory.
+
+ Here's a slightly more ambitious example that illustrates CD'ing to the
+ desired server directory to get a group of files in text mode (in this
+ case the C-Kermit source files):
+
+ ftp -A kermit.columbia.edu -D kermit/f -ag "ck[cuw]*.[cwh]" makefile
+
+ In this case we CD to the kermit/f directory so we don't have to
+ include it in each file specification, and we quote the ck[cuw]*.[cwh]
+ specification so the shell doesn't expand it, since we have to pass it
+ as-is to the server. Note also that the quotes don't go around the
+ entire file list; only around each file specification that needs to be
+ quoted.
+
+ Here's one more example, that uploads a debug log file in binary mode
+ to the Kermit incoming directory (as we might ask you to do when
+ following up on a problem report):
+
+ ftp -A kermit.columbia.edu -D kermit/incoming -bp debug.log
+
+ In this case the -D option is required to tell the server where to put
+ the incoming file.
+
+ Unless the -Y option is included, your Kermit initialization file
+ (.mykermrc in UNIX, K95.INI in Windows) is executed before the command
+ line options, so you can set any FTP-related preferences there, as
+ described in the subsequent sections.
+
+3.1.3. The FTP URL Interpreter
+
+ If Kermit is invoked with either its regular personality (as "kermit")
+ or its FTP personality (as "ftp"), you can also give a URL
+ (Universal Resource Locator) instead of a hostname and options,
+ with or without a username and password:
+ ftp ftp://user:password@host/path
+ ftp ftp://user@host/path
+ ftp ftp://@host/path (or ftp://:@host/path)
+ ftp ftp://host/path
+ kermit ftp://host/path
+
+ If the FTP personality is used, the service must be "ftp". In all
+ cases, a hostname or address must be included. If a user is included
+ but no password, you are prompted for the password. If a path
+ (filename) is included:
+ * If "@" is included without a user, Kermit prompts for the username
+ and password.
+ * If no user and no "@" are included, "anonymous" is used.
+ * GET is assumed.
+
+ If no path (and no action options) are included, an interactive FTP
+ session is started, as in this example:
+ ftp ftp://kermit.columbia.edu
+
+ If a path is included, but a username is not included, "anonymous" is
+ used and an appropriate user@host password is supplied automatically.
+ If authentication is successful, Kermit attempts to GET the file
+ indicated by the path or, if the path is the name of a directory, it
+ asks the server for a directory listing. In both cases, Kermit
+ disconnects from the server and exits after the operation is complete
+ (unless you have included the -S option on the command line).
+
+ Here's an example that gets a listing of the Kermit directory at the
+ Kermit ftp site:
+ ftp ftp://kermit.columbia.edu/kermit/
+
+ This example gets the top-level READ.ME file from the same directory:
+ ftp ftp://kermit.columbia.edu/kermit/READ.ME
+
+ Here's the same example, but requesting a text-mode transfer:
+ ftp -T ftp://kermit.columbia.edu/kermit/READ.ME
+ This illustrates that you can mix command-line options and URLs
+ if you desire.
+
+ Here's an example that logs in as a (fictitious) real user to get a
+ file:
+ ftp ftp://olga@ftp.xyzcorp.com/resume.txt
+ The password is not included, so Kermit prompts for it.
+
+ This scheme allows Kermit to be used as the FTP helper of other
+ applications, such as Web browsers, with all its advantages over other
+ FTP clients (especially the ones that are built in to most Web
+ browsers), e.g. that it can be given wildcards, and it can pick text
+ and binary mode automatically for each file.
+
+ HINT: suppose somebody sends you an FTP URL in email, or you see it in
+ some text. If your terminal screen supports copy/paste, copy the url,
+ and then at the shell prompt type "kermit", a space, and then paste the
+ URL, e.g.:
+
+ $ kermit ftp://alpha.greenie.net/pub/mgetty/source/1.1/mgetty1.1.27-O
+
+ "$ is the shell prompt; the part you type is underlined, the rest is
+ pasted in. Kermit does the rest.
+
+3.1.4. Interactive FTP Session Establishment
+
+ As you read this and the following sections, bear in mind that any
+ command that can be given at the prompt can also be used in a script
+ program. Kermit's script programming language is the same as its
+ interactive command language. [234]CLICK HERE if you would like to
+ learn a bit more about script writing.
+
+ An FTP session is established with the FTP OPEN command:
+
+ FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ switches ] [ port ]
+ Opens an FTP connection to the given host on the given port and,
+ if FTP AUTOLOGIN is ON, also logs you in to the server,
+ prompting for username and password if necessary. If no port is
+ specified, the regular FTP protocol port (21) is used. The OPEN
+ keyword is optional (unless the hostname conflicts with one of
+ the FTP command keywords, which you can list by typing "ftp ?").
+
+ The hostname can be an IP host name, numeric IP address, or if you have
+ a network directory active (SET NETWORK DIRECTORY; see Chapter 6 of
+ [235]Using C-Kermit), an entry name in the directory. In the latter
+ case, if the given hostname matches exactly one entry, the associated
+ name or address is used; if it matches more than one, Kermit cycles
+ through them until one is found that can be opened; if it matches none,
+ then the hostname is used as-is. If a directory is active but you want
+ to bypass directory lookup, include an "=" sign at the beginning of the
+ hostname, and/or use a numeric IP address.
+
+ When an FTP connection is opened, the default file-transfer mode is set
+ to binary if the client and server platforms are alike (e.g. both of
+ them are some kind of UNIX), and to text ("ascii") if they are not
+ alike. This has no particular effect for uploading since Kermit
+ automatically switches between text and binary mode for each file, but
+ might be important for downloading. The connection is also set to
+ Stream mode and File structure. Record- or page-oriented file transfers
+ are not supported by C-Kermit's FTP client.
+
+ The optional FTP OPEN switches are:
+
+ /ANONYMOUS
+ Logs you in anonymously, automatically supplying username
+ "anonymous" and user@host as the password, based on your local
+ user and host names.
+
+ /NOLOGIN
+
+ Overrides SET FTP AUTOLOGIN ON for this connection only.
+
+ /USER:name
+ Uses the given username to log you in, thus avoiding the Name:
+ prompt.
+ Overrides SET FTP AUTOLOGIN OFF for this connection only.
+
+ /PASSWORD:text
+ Uses the given text as your password, thus avoiding the
+ Password: prompt. This switch is not recommended for use in
+ script files, which would be a security risk.
+
+ /ACCOUNT:text
+ Uses the given text as your account (or secondary password,
+ depending on the requirements of the server; most servers do not
+ require or accept an account name). If an account is not
+ supplied, you are not prompted for one.
+
+ /PASSIVE
+ Opens the connection in passive mode. Passive mode is the
+ default in Kermit's FTP client, unlike in most others, since it
+ works better through firewalls. The /PASSIVE and /ACTIVE
+ switches apply only to the connection that is being opened, and
+ do not affect the global FTP PASSIVE-MODE setting.
+
+ /ACTIVE
+ Opens the connection in active mode. Use this switch if the
+ server does not support passive mode, or use the command SET FTP
+ PASSIVE-MODE OFF.
+
+ /NOINIT
+ Added in C-Kermit 8.0.201. Tells C-Kermit not to send REST,
+ STRU, FEAT, and MODE commands to the server when the connection
+ is opened, since these have been reported to cause confusion in
+ certain servers.
+
+ When a username or password is missing, a prompt is issued at the
+ controlling terminal and you must type the response; the response can
+ not be scripted. Use the switches to avoid prompts, or one of the
+ secure authentication methods described in the next section, or see
+ [236]SET FTP AUTOLOGIN and the [237]FTP USER and similar commands
+ described later in this section.
+
+ Examples:
+
+ ftp open kermit.columbia.edu /anonymous ; Open and log in anonymously
+ ftp kermit.columbia.edu /anonymous ; The OPEN keyword can be omitted
+ ftp xyzcorp.com ; Open and maybe prompt for username
+ ftp xyzcorp.com /user:olga ; Open and log in as olga
+ ftp testing.abccorp.com 449 ; Specify a special TCP port number
+ ftp testing.abccorp.com /user:olaf /password:secret 449
+
+ The FTP OPEN command succeeds if a connection was opened to the server
+ (even if the given username and password were not valid) and fails
+ otherwise (see [238]Section 3.8 for details).
+
+ When your FTP session is complete, you can terminate it as follows:
+
+ FTP BYE
+ Closes the FTP connection if one was open. The FTP prefix can be
+ omitted if no other connection is open at the same time (see
+ [239]Section 3.8 for details). If a connection log is active, an
+ FTP record is written to it. If Kermit was started with the -9
+ command-line option or with its FTP command-line personality,
+ and the -S (Stay) option was not given, AND there is no other
+ active connection, the FTP BYE command also exits, just as it
+ does on a regular FTP client. Synonyms: FTP CLOSE, FTP QUIT (but
+ if the FTP prefix is omitted from QUIT, this becomes the regular
+ Kermit QUIT command, which is equivalent to EXIT; i.e. it closes
+ the connection and exits from Kermit).
+
+ The following commands can be used to achieve greater control over the
+ connection and login process:
+
+ SET FTP ANONYMOUS-PASSWORD text
+ Allows you to choose the password text to be sent automatically
+ by Kermit when you open an FTP connection with the /ANONYMOUS
+ switch.
+
+ SET FTP AUTOLOGIN { ON, OFF }
+ If you give this command prior to opening an FTP connection, it
+ controls whether Kermit tries to log you in automatically as
+ part of the connection process. Normally ON, which means the
+ username and password are sent automatically (and prompted for
+ if they are not yet known). When OFF, FTP OPEN connects to the
+ server without logging in. OFF is equivalent to the -n
+ command-line option when using Kermit's FTP command-line
+ personality.
+
+ FTP USER name [ password [ account ] ]
+ Used to log in to an FTP server to which a connection has been
+ made without autologin, or when autologin failed. If the
+ password is furnished on the command line, it is used; otherwise
+ you are prompted for a password. An account may also be
+ furnished if required by the server; it is not required by
+ Kermit and is not prompted for if omitted. Synonyms: USER, FTP
+ LOGIN.
+
+ FTP ACCOUNT text
+ Sends an account name to a server that supports accounts. If the
+ server does not support accounts, an error response occurs. If
+ the server does support accounts, the account is accepted if it
+ is valid and rejected if it is not. The account might be used
+ for charging purposes or it might be a secondary password, or it
+ might be used for any other purpose, such as an access password
+ for a particular disk. Servers that support accounts might or
+ might not allow or require the account to be sent prior to
+ login; usually it is sent after login, if at all. Synonym:
+ ACCOUNT.
+
+ Example:
+
+set ftp autologin off ; One thing at a time please
+ftp xyzcorp.com ; Try to make the connection
+if fail exit 1 FTP connection failed ; Check that it was made
+ftp user olga secret ; Now log in to the server
+if fail exit 1 FTP login failed ; Check that it worked
+ftp account 103896854 ; Login OK - send account
+if fail echo WARNING - FTP ACCT failed ; Warn if problem
+... ; (have session here)
+bye ; Log out and disconnect
+
+ The following commands are used to control or get information about the
+ FTP connection. Any particular FTP server does not necessarily support
+ all of them.
+
+ FTP RESET
+ Terminates a user session but leaves the connection open,
+ allowing a new login via FTP USER.
+
+ FTP IDLE [ number ]
+ Most FTP servers automatically log you out and and disconnect
+ your session if there has been no activity for a certain amount
+ of time. Use this command to ask the server to set its idle
+ limit to the given number of seconds. Omit the number to ask the
+ server to inform you of its current idle limit.
+
+ FTP STATUS [ filename ]
+ Asks the FTP server to send information about the current
+ session. The result is a free-format report that might include
+ server identification, username and login time, FTP protocol
+ settings, and file-transfer statistics. If a filename is given,
+ the server is supposed to send detailed information about the
+ file.
+
+ FTP SYSTEM
+ Asks the FTP server to identify its operating system (Listed in
+ Internet Assigned Numbers, Operating System Names). Examples:
+ UNIX, VMS, VM/CMS, WINDOWS-NT. Unfortunately many variations are
+ allowed (e.g. LINUX-2.0, LINUX-2.2, FREEBSD, ULTRIX, etc,
+ instead of UNIX; WINDOWS-NT-3, WINDOWS-NT-3.5, WINDOWS-NT-3.51,
+ WINDOWS-NT-4, etc). The report might also include other
+ information like "Type L8", "Type I", or "Type A", indicating
+ the file-transfer mode.
+
+ FTP HELP [ keyword [ keyword [ ... ] ]
+ Asks the server to list the commands it supports. The response
+ is usually cryptic, listing FTP command mnemonics, not the
+ commands used by the client (since the server has no way of
+ knowing anything about the client's user interface). For
+ example, the PUT command is STOR in FTP protocol. If a keyword
+ is given, which should be an FTP protocol command,
+ slightly-more- detailed help is given about the corresponding
+ command (if the FTP server supports this feature). Examples:
+ "ftp help", "ftp help stor".
+
+ FTP SITE text
+ (Advanced) Sends an FTP SITE (site-specific) command. Usually
+ this means that the FTP server is asked to run an external
+ command with the given arguments. You might be able to find out
+ what SITE commands are available by sending "ftp help site" to
+ the server, but in general the availability of and response to
+ SITE commands is (not surprisingly) site specific.
+
+ FTP QUOTE text
+ (Advanced) Sends an FTP command in FTP protocol format. Use this
+ command to send commands to the server that the FTP client might
+ not know about.
+
+ SHOW FTP
+ Lists client (Kermit) FTP settings and information. Also SHOW
+ CONNECTION, SHOW COMMUNICATIONS.
+
+ HELP FTP [ keyword ]
+ Asks Kermit to list and describe its built-in FTP commands.
+
+ HELP SET FTP [ keyword ]
+ Asks Kermit to list and describe its built-in SET FTP commands.
+
+ [ [240]Top ] [ [241]FTP Top ] [ [242]C-Kermit Home ] [ [243]Kermit Home
+ ]
+
+3.1.5. Making Proxy Connections
+
+ 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. In order to allow secure web connections to be established,
+ the CONNECT command works by authenticating the client with a
+ username/password and then establishing a tunnel to the desired host.
+
+ Many web servers support the CONNECT command and it can be configured
+ to allow outgoing connections to authenticated user to any TCP/IP
+ hostname/port combination accessible to the web server. The limitations
+ of HTTP CONNECT is that it can only be used for outgoing connections
+ for protocols that are implemented using TCP/IP. Protocols such as
+ Kerberos authentication that use UDP/IP cannot be tunneled using HTTP
+ CONNECT.
+
+ Kermit provides support for the use of HTTP CONNECT proxy services with
+ the command:
+
+ SET TCP HTTP-PROXY [/USER:username /PASSWORD:password] hostname/ip-address[:po
+rt]
+
+ When a port is not specified the default port configured on the HTTP
+ server is used. This is frequently port 443. When a hostname is
+ specified, it is resolved using the DNS available to the web server.
+
+3.2. Making Secure FTP Connections
+
+ Also see: [244]Accessing IBM Information Exchange with Kermit.
+
+ In the previous section, you can see several examples of traditional
+ insecure authentication: username and password sent across the network
+ in clear text. Of course this is bad practice on at least two counts:
+ (1) storing passwords in files (such as script files) gives access to
+ the target systems to anybody who can obtain read access to your
+ scripts; and (2) sending this information over the network leaves it
+ open to interception by network sniffers or compromised hosts.
+
+ Because of the increasing need for security on the Internet, FTP
+ servers are beginning to appear that offer secure forms of
+ authentication, in which no information is sent over the network that
+ would allow anyone who intercepts it to usurp your identity and gain
+ your access rights.
+
+ Kermit provides an equivalent form of FTP security for each type of
+ IETF standard security implemented in Telnet. These include
+ GSSAPI-KERBEROS5, KERBEROS4, Secure Remote Password (SRP), and
+ Transport Layer Security (SSL and TLS). It does not presently include
+ SSL tunneling nor any form of SSH v1 or v2. When Kermit is built with
+ the necessary libraries, secure FTP connections are attempted by
+ default, in which all connections are authenticated and the command and
+ data channels are private.
+
+ The use of authentication and encryption for FTP connections can be
+ adjusted with the commands listed below, which are available only if
+ your version of Kermit was built with the corresponding security
+ options and libraries:
+
+ SET FTP AUTHTYPE { AUTOMATIC, GSSAPI-KRB5, KERBEROS4, SRP, SSL, TLS }
+ Specifies an ordered list of authentication methods to be
+ attempted when AUTOAUTHENTICATION is ON. The default list is:
+ GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL. If none of the selected
+ methods are supported by the server, an insecure login is used
+ as a fallback. Note, by the way, that SSL or TLS can be used to
+ secure an anonymous connection.
+
+ SET FTP AUTOAUTHENTICATION { ON, OFF }
+ Tells whether authentication should be negotiated by the FTP
+ OPEN command. Default is ON. Use SET FTP AUTOAUTHENTICATION OFF
+ to force a clear-text, unencrypted connection to FTP servers
+ (such as the one at the Kermit FTP site) that normally would try
+ to negotiate secure authentication and encryption.
+
+ SET FTP AUTOENCRYPTION { ON, OFF }
+ Tells whether encryption (privacy) should be negotiated by the
+ FTP OPEN command, which can happen only if secure authentication
+ is also negotiated. Default is ON.
+
+ SET FTP AUTOLOGIN { ON, OFF }
+ Tells Kermit whether to try logging in automatically when you
+ make an FTP connection, as opposed to letting you do it "by
+ hand" with the FTP USER command.
+
+ SET FTP COMMAND-PROTECTION-LEVEL { CLEAR, CONFIDENTIAL, PRIVATE, SAFE }
+ Determines the level of protection applied to the command
+ channel:
+
+ CLEAR Data is sent in plaintext and not protected against tampering.
+ CONFIDENTIAL Data is encrypted but not protected against tampering.
+ PRIVATE Data is encrypted and is protected against tampering.
+ SAFE Data is sent in plaintext but protected against tampering.
+
+ The default is PRIVATE.
+
+ SET FTP CREDENTIAL-FORWARDING { ON, OFF }
+ Tells whether end-user credentials are to be forwarded to the
+ server if supported by the authentication method (GSSAPI-KRB5
+ only). This is often required to allow access to distributed
+ file systems (e.g. AFS.)
+
+ SET FTP DATA-PROTECTION-LEVEL { CLEAR, CONFIDENTIAL, PRIVATE, SAFE }
+ Tells what level of protection is applied to subsequent data
+ channels. The meanings of the protection-level keywords are the
+ same as for SET FTP COMMAND-PROTECTION-LEVEL. The default is
+ PRIVATE.
+
+ SET FTP SRP CIPHER name
+ Specifies the cipher to be used for encryption when SRP
+ authentication is in use. The list of possible choices is
+ computed based on the capabilities of the local SRP library and
+ includes NONE plus zero or more of the following:
+
+ BLOWFISH_ECB CAST5_ECB DES_ECB DES3_ECB
+ BLOWFISH_CBC CAST5_CBC DES_CBC DES3_CBC
+ BLOWFISH_CFB64 CAST5_CFB64 DES_CFB64 DES3_CFB64
+ BLOWFISH_OFB64 CAST5_OFB64 DES_OFB64 DES3_OFB64
+
+ The default is DES3_ECB.
+
+ SET FTP SRP HASH name
+ Specifies the hash to be used for data protection when SRP
+ authentication is in use. The choices are MD5 and SHA. The
+ default is SHA.
+
+ Command-line options:
+
+ -k name
+ Specifies the realm to be used with Kerberos 4 authentication (=
+ SET AUTH K4 REALM name).
+
+ -f
+ Enables forwarding of Kerberos 5 credentials to the host when
+ using GSSAPI authentication (= SET AUTH K5 FORWARDABLE ON).
+
+ -x
+ Enables autoencryption (= SET FTP AUTOENCRYPTION ON).
+
+ -c cipher
+ Specifies the kind of cipher to be used for encryption with SRP
+ authentication. Equivalent to SET FTP SRP CIPHER, with the same
+ choices. If this option is not given, CAST5_CBC is used.
+
+ -H hash
+ Specifies the hash to be used for encryption with SRP
+ authentication. Equivalent to SET FTP SRP HASH, with the same
+ choices. If this option is not given, SHA is used.
+
+ -z debug
+ Turns on SSL/TLS debugging.
+
+ -z secure
+ Requires secure connection.
+
+ -z certsok
+ Says to accept all certificates without checking validity.
+
+ -z verify=n
+ Sets certificate verification mode to the given number, n:
+ 0 = no verification
+ 1 = verify certificate if presented
+ 2 = require verification of certificate
+
+ -z cert=filename
+ Specifies a file containing a client certificate to be presented
+ to the FTP server.
+
+ -z key=filename
+ Specifies a file containing a private key matching the client
+ certificate.
+
+ -z !krb4
+ (nokrb4) Disables the use of Kerberos 4.
+
+ -z !gss
+ -z nogss
+ Disables the use of GSSAPI - Kerberos 5.
+
+ -z !srp
+ -z nosrp
+ Disables use of SRP.
+
+ -z !ssl
+ -z nossl
+ Disables the use of SSL.
+
+ -z !tls
+ -z notls
+ Disables the use of TLS.
+
+ Caution: If your FTP connection is secured via AUTH TLS, it is not
+ possible to interrupt a file transfer. This is a limitation of all
+ known FTP servers that support AUTH TLS.
+
+ Note that when using certain security methods, such as SSL or TLS, you
+ may be prompted to confirm or verify certain actions or conditions, for
+ example, whether to accept self-signed certificates. This can interfere
+ with unattended operation of scripts; see [245]Section 3.10.
+
+ [ [246]Top ] [ [247]FTP Top ] [ [248]C-Kermit Home ] [ [249]Kermit Home
+ ]
+
+3.3. Setting FTP Preferences
+
+ FTP preferences can be set globally and persistently with the commands
+ in the following sections; many of these can also be overridden on a
+ per-command basis with switches that have the same name.
+
+3.3.1. Logs, Messages, and Other Feedback
+
+ You can control the amount of feedback received from your FTP session
+ with the commands in this section. First, you can create a log of your
+ FTP transfers with the following commands:
+
+ SET TRANSACTION-LOG { VERBOSE, FTP, BRIEF }
+ Selects the log format. VERBOSE is the default, and is described
+ in [250]the manual. FTP chooses a WU-FTPD format, the same as is
+ used by the popular FTP server. BRIEF creates per-file records
+ in comma-separated-list format. For greater detail, see
+ [251]Section 4.17 of the [252]C-Kermit 7.0 Update Notes.
+
+ LOG TRANSACTIONS filename
+ Records FTP (or Kermit, or any other protocol) uploads and
+ downloads in the given file using the format selected by the
+ most recent SET TRANSACTION-LOG command, if any, or else the
+ default format.
+
+ FTP screen messages and displays are controlled by the following
+ commands:
+
+ SET TRANSFER DISPLAY { FULLSCREEN, CRT, SERIAL, BRIEF, NONE, OFF }
+ FTP transfers use Kermit's normal file-transfer display styles.
+ Use this command to choose the desired format; the default on
+ most platforms is FULLSCREEN. The display is automatically
+ disabled if Kermit is running in the background or in batch.
+ BRIEF is always used for command-line initiated transfers
+ (unless suppressed by -q). While a file-transfer is in progress,
+ you can interrupt it in the normal Kermit way by typing one of
+ the following keys or key combinations:
+ X - Cancel current file but go on to the next one (if any).
+ Z - Cancel the entire transfer. Ctrl-L or Ctrl-W - Refresh
+ the file-transfer display (if any).
+
+ SET FTP DISPLAY { FULLSCREEN, CRT, SERIAL, BRIEF, NONE, OFF }
+ Like SET TRANSFER DISPLAY, but applies only to FTP connections,
+ and does not affect Kermit- or other protocol file transfers.
+
+ SET QUIET { ON, OFF }
+ This command applies to Kermit in general, not just FTP. OFF by
+ default; when ON, it suppresses most messages from most commands
+ as well as the file-transfer display.
+
+ SET FTP PROGRESS-MESSAGES { ON, OFF }
+ Tells whether Kermit should print locally-generated feedback
+ messages for each non-file-transfer command. ON by default.
+
+ SET FTP VERBOSE-MODE { ON, OFF }
+ Tells whether to display all responses from the FTP server. OFF
+ by default. This shows all responses to all commands, except
+ when the file-transfer display is active, and unless you have
+ SET QUIET ON. When OFF, responses are shown only for commands
+ such as FTP PWD whose purpose is to display a response.
+
+ SET FTP DEBUG { ON, OFF }
+ Tells whether local client debugging information should be
+ displayed. OFF by default. When ON, the commands that are sent
+ to the server are shown, as well as its responses (even if
+ VERBOSE-MODE is OFF), plus additional informational messages are
+ printed regarding the progress of secure operations. Also, the
+ temporary file created by the [253]MGET command is not deleted
+ so you can see what's in it.
+
+ Set all of these to OFF when silent running is desired.
+
+3.3.2. Operational Preferences
+
+ FTP DISABLE new-protocol-feature-name
+ FTP ENABLE new-protocol-feature-name
+ Explained in [254]Section 3.11.
+
+ SET FTP AUTOLOGIN { ON, OFF }
+ If you give this command prior to opening an FTP connection, it
+ controls whether Kermit tries to log you in automatically as
+ part of the connection process. Normally ON, which means the
+ username and password are sent automatically (and prompted for
+ if they are not yet known). When OFF, FTP OPEN connects to the
+ server without logging in. OFF is equivalent to the -n
+ command-line option when using Kermit's FTP command-line
+ personality. See [255]Section 3.1.4 for usage.
+
+ SET FTP PASSIVE-MODE { ON, OFF }
+ ON by default, to avoid random TCP port assignment for data
+ connections, which can prevent FTP protocol from working through
+ firewalls and network address translators (for more on these
+ topics, see the [256]Kermit security reference. Set to OFF in
+ case the FTP server does not support passive mode, or in case
+ the client has problems with it (it has been observed, for
+ example, that when using passive mode, the SCO XENIX 2.3.4
+ TCP/IP stack hangs in the connect() call forever). Synonyms:
+ PASSIVE [ ON ], PASSIVE OFF, PASV [ ON ], PASV OFF.
+
+ SET FTP SEND-PORT-COMMANDS { ON, OFF }
+ This command determines whether the FTP client sends a new PORT
+ command to the server when accepting incoming data connections
+ (as when not using passive mode.) When PASSIVE-MODE is OFF and
+ SET SEND-PORT is OFF, the port that was originally specified is
+ reused. This is the default behavior for normal FTP clients but
+ it is not compatible with many firewalls.
+
+ SET FTP CHARACTER-SET-TRANSLATION { ON, OFF }
+ Whether to translate character sets when transferring files with
+ FTP (explained in [257]Section 3.7). OFF by default.
+
+ SET FTP SERVER-CHARACTER-SET name
+ Tells Kermit the character set used by the FTP server, UTF-8 by
+ default ([258]Section 3.7).
+
+ SET FTP SERVER-TIME-OFFSET delta-time
+ Tells Kermit to apply the given [259]delta time to file
+ timestamps provided by the server for its files; for use when
+ (for example) the server does not have its timezone set
+ correctly.
+
+ SET FTP ERROR-ACTION { PROCEED, QUIT }
+ When transferring a group of files with FTP, and an error occurs
+ with one of the files, Kermit normally goes on the next file.
+ Use SET FTP ERROR-ACTION to QUIT to make Kermit stop the
+ transfer immediately and fail if an error occurs with any single
+ file in the group. Example: you have given Kermit a list of
+ files to send, and one of the files can not be found, or read
+ permission is denied. Note that canceling a file by typing 'X'
+ during transfer is not considered an error (if you want to
+ cancel the entire transfer, type 'Z' or Ctrl-C).
+
+ SET FTP PERMISSIONS { AUTO, ON, OFF }
+ When uploading files with PUT or MPUT, this tells whether Kermit
+ should send each file's permissions. The default is OFF, which
+ means not to send permissions, in which case the uploaded file's
+ permissions are set by the FTP server according to its own
+ criteria. ON means to send them, AUTO means to send them only if
+ the client (Kermit) and server are on like platforms (e.g. both
+ UNIX). This command has no effect when downloading, since the
+ FTP protocol does not include a way for the server to inform the
+ client of a file's permissions. Also see [260]FTP PUT
+ /PERMISSIONS. Note that setting permissions after uploading is
+ likely to work (correctly or at all) only when the client and
+ server platforms are alike (e.g. both of them are some form of
+ UNIX). Also note that Windows files don't have permissions. Also
+ see [261]FTP CHMOD.
+
+ SET FTP DATES { ON, OFF }
+ When downloading files with GET or MGET, this tells whether
+ Kermit should try to set the received file's date from the
+ server's date. FTP DATES is ON by default. Note, however, that
+ FTP protocol does not allow date preservation when uploading. So
+ at best, SET FTP DATES ON can work only when downloading, and
+ then only when the server agrees to furnish file dates.
+
+ SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }
+ When uploading (sending) files, this tells whether to convert
+ outbound filenames to "common form". This means allowing only
+ one period in a name, uppercasing any lowercase letters,
+ replacing spaces by underscores, etc. AUTOMATIC is the default,
+ meaning LITERAL when client and server are the same type of
+ system (e.g. UNIX) and CONVERTED otherwise. Special case: if the
+ setting is AUTOMATIC and the client is not UNIX and the server
+ identifies itself as UNIX, Kermit uses a less-strict form of
+ conversion, in which lowercase letters are not uppercased and
+ the filename can contain any number of periods, but spaces are
+ still converted to underscore. When receiving, conversion
+ generally means to change all-uppercase names to lowercase and
+ spaces to underscore.
+
+ SET FTP UNIQUE-SERVER-NAMES { ON, OFF }
+ Applies only to uploads. Tells the server to create new, unique
+ names for incoming files that have the same names as existing
+ files. OFF by default, in which case the server overwrites
+ existing files with new files of the same name. When ON, the
+ server uses its own built-in method for creating new names for
+ incoming files; for example, appending a period (.) and a number
+ to the name. CAUTION: Use this option only if you do not need to
+ refer to the file after it is uploaded, since FTP protocol
+ provides no mechanism for the client to find out what name was
+ assigned by the server.
+
+ SET FTP COLLISION { ... }
+ When downloading, what to do if an incoming file has the same
+ name as an existing file. Options are the same as for SET FILE
+ COLLISION. If this command is not given, Kermit's regular FILE
+ COLLISION setting is used. If this command is given, it
+ overrides the FILE COLLISION setting for FTP transfers only. See
+ [262]Section 3.6.2 for details.
+
+ SET FTP TYPE { TEXT, BINARY, TENEX }
+ Changes the default transfer mode. When sending (uploading)
+ files, this command has no effect unless you disable automatic
+ text/binary mode switching ([263]Section 4) with SET FILE SCAN
+ OFF or SET TRANSFER MODE MANUAL. When receiving (downloading)
+ files, this command establishes the transfer mode to be used
+ when a filename does not match any of Kermit's text or binary
+ filename patterns, unless you use SET FTP GET-FILETYPE-SWITCHING
+ or SET TRANSFER MODE MANUAL to disable automatic switching, in
+ which case, this command establishes the transfer mode for all
+ downloaded files. In all cases, however, the FTP TYPE can be
+ overridden in any GET or PUT command by including a /TEXT
+ (/ASCII), /BINARY, or /TENEX switch. The FTP TYPE is independent
+ of the Kermit FILE TYPE setting. TENEX is used for sending 8-bit
+ binary files to 36-bit platforms such as TOPS-10, TOPS-20, and
+ TENEX, and getting them back again. Synonym: ASCII = TEXT. Note:
+ there is also an FTP TYPE command, which does what SET FTP TYPE
+ does but also sends a TYPE command to the server immediately if
+ the given type is different from the current one.
+
+ If you want want specific FTP preference settings to be in effect for
+ all your Kermit FTP sessions, put the desired SET FTP commands in your
+ Kermit customization file (~/.mykermrc in UNIX, K95CUSTOM.INI in
+ Windows).
+
+ [ [264]Top ] [ [265]FTP Top ] [ [266]C-Kermit Home ] [ [267]Kermit Home
+ ]
+
+3.4. Managing Directories and Files
+
+ In Kermit, commands for directory and file management can refer to:
+
+ * The local computer
+ * A remote computer when you have a connection to a Kermit server or
+ IKSD.
+ * A remote computer when you have a connection to an FTP server.
+
+ (There can also be an HTTP connection, but the commands in this section
+ don't apply to HTTP connections.)
+
+ Thus in general, each such command comes in three forms:
+
+ 1. With no prefix in C-Kermit 8.0.200, it refers to the local computer
+ (CD, DIR, etc). In C-Kermit 8.0.201 and later, however, the "locus"
+ switches to automatically to the remote FTP server when you make an
+ FTP connection (see the SET LOCUS description [268]Section 7); thus
+ C-Kermit 8.0.201 acts almost exactly like a regular FTP client when
+ it has an FTP connection, yet still acts like itself on other kinds
+ of connections.
+ 2. With the REMOTE prefix, it is for a Kermit server (REMOTE CD,
+ REMOTE DIR).
+ 3. With the FTP prefix, it's for an FTP server (FTP CD, FTP DIR).
+ 4. Also see [269]Section 3.8, which explains "R-commands" and
+ "L-commands".
+
+ Kermit's FTP file and directory management commands are as follows.
+ When an R-command is included in the Synonyms list, be sure to read
+ [270]Section 3.8 about rules for use of R-commands.
+
+ FTP CD [ directory ]
+ Tells the FTP server to change its default (working) directory
+ to the one given, which usually must be expressed in the syntax
+ of the server platform (UNIX, VMS, etc). If the directory is not
+ specified, the result depends on the FTP server -- it might
+ complain that the command is illegal, or it might change to your
+ original login directory. Synonyms: FTP CWD (Change Wording
+ Directory); RCD.
+
+ FTP CDUP
+ Tells the FTP server to change its default (working) directory
+ to the parent directory of its current one (equivalent to
+ "cd .." in UNIX, or "cd [-]" in VMS). Synonyms: RCDUP, FTP UP.
+
+ FTP PWD
+ Asks the FTP server to report ("print") its current working
+ directory. Synonym: RPWD.
+
+ FTP MKDIR directory
+ Asks the FTP server to create the directory whose name is given.
+ In general, the name must be in the syntax of the server's file
+ system, and it must be either absolute (a full pathname) or
+ relative to the server's current (working) directory. This
+ command fails if the directory can't be created for any reason,
+ including that it exists already. Synonym: RMKDIR.
+
+ FTP RMDIR directory
+ Asks the FTP server to remove the directory whose name is given.
+ The rules are the same as for MKDIR, plus in most cases, the
+ server will not remove any directory unless it is empty.
+ Synonym: RRMDIR.
+
+ FTP DIRECTORY [ filespec ] [ redirectors ]
+ Tells the FTP server to send a directory listing of the
+ specified files. If no filespec is given, the server lists all
+ files in its current working directory. The results are in
+ whatever format the server chooses to send them. You can use
+ UNIX-like redirectors to send the listing to a file or a
+ pipeline, exactly as with the regular Kermit client/server
+ REMOTE DIRECTORY command ([271]Using C-Kermit, Chapter 11).
+ Synonym: RDIRECTORY. Examples:
+
+ ftp dir ; Show listing of all files on screen
+ ftp dir *.txt ; List *.txt files on screen
+ ftp dir *.txt > somefile ; Put listing in somefile
+ ftp dir *.txt >> somefile ; Append listing to somefile
+ ftp dir *.txt | sort > somefile ; Put sorted listing in somefile
+ ftp dir | more ; Runs list through "more"
+ ftp dir | sort | more ; Runs list through "sort" and "more"
+
+ FTP VDIRECTORY [ filespec ] [ redirectors ]
+ "Verbose" directory. This is an alternative FTP DIRECTORY
+ command primarily for use with DECSYSTEM-20 (TOPS-20) FTP
+ servers, which send only filenames when given a DIRECTORY
+ command; the VDIRECTORY command makes them also send file sizes,
+ dates, and attributes.
+
+ FTP CHECK filespec
+ Asks the FTP server whether the given file exists or, if the
+ filespec contains wildcards, if any files match, and this
+ command succeeds or fails accordingly.
+
+ FTP MODTIME filename
+ Asks the FTP server, via the not-yet-standard FTP MDTM command,
+ to send the modification date and time of the given file. The
+ response should be a numeric string in the format:
+ yyyymmddhhmmssxxxxx... where yyyy is the year, mm is the month,
+ dd is the day, hh is the hour (0-23), mm is the minute, ss is
+ the second, and xxx... is the optional fraction of the second (0
+ or more digits). The date and time is expressed in UTC (GMT,
+ Zulu, Zero-Meridian). The result is available programmatically
+ in the [272]\v(ftp_message) variable, and is understandable by
+ Kermit's date-time switches and functions. For example, suppose
+ we want to upload all local files that are newer than a
+ particular file on the server:
+
+ C-Kermit> ftp modtime signpost
+ C-Kermit> echo \v(ftp_message)
+ 20010807113542.014
+ C-Kermit> ftp mput /after:\v(ftp_message)GMT *
+
+ Note that we must append "GMT" to the date-time string to let
+ the /AFTER switch know the time is GMT rather than local.
+
+ FTP SIZE filename
+ Asks the FTP server to send the size (in bytes) of the given
+ file. The result might vary depending on whether the current FTP
+ TYPE is binary or text ("ascii"). For a reliable byte count, do
+ FTP TYPE BINARY first. The result is available programmatically
+ in the [273]\v(ftp_message) variable.
+
+ FTP CHMOD permissions filename
+ Tells the FTP server to set the permissions (protection) of the
+ given file to the ones given. The permissions and filename must
+ be given in whatever syntax is required by the server. Example
+ (for a UNIX-based FTP server):
+
+ ftp chmod 664 oofa.txt
+
+ Not all servers support this command. For non-UNIX-based
+ servers, you might need to use FTP QUOTE or FTP SITE and the
+ appropriate platform-specific FTP server command.
+
+ FTP UMASK [ number ]
+ This command is probably specific to UNIX-based servers; it sets
+ the UNIX "umask", which is the default permissions mask for new
+ (in this case, incoming) files. Crudely put, the UNIX umask is
+ an octal representation of a binary number in in which a 1 bit
+ stands for a permission bit that must be 0, and a 0 bit stands
+ for a permission bit that can be 0 or 1 depending on other
+ factors, such as the permissions of the parent directory.
+ Example: "umask 007" requires that new files are created without
+ read/write/execute world permission. If the number is not
+ specified, the server's current umask is reported.
+
+ FTP RENAME filename newname
+ Asks the FTP server to rename the file whose name is "filename"
+ to "newname". Works only for one file; can not be used with
+ wildcards. The server's interpretation of "newname" can vary (in
+ some cases it must be a filename, in others perhaps it can also
+ be a directory name, in which case if the filename denote a
+ regular file, the file might be moved to the given directory).
+ Some servers might allow files to be renamed ("moved") between
+ physical disks or partitions, others might not. Synonym:
+ RRENAME.
+
+ FTP DELETE [ switches ] filespec [ filespec [ ... ] ]
+ Tells the FTP server to delete the file or files listed. Each
+ file specification may, but need not, contain wildcard
+ characters to match multiple files. File specifications and
+ wildcard syntax must be those of the server. Any file
+ specifications that contain spaces must be enclosed in braces or
+ doublequotes. FTP DELETE switches are:
+
+ /ERROR-ACTION: /FILENAMES: /NOBACKUPFILES /QUIET
+ /EXCEPT: /LARGER-THAN: /NODOTFILES /NOPAGE
+ /PAGE /RECURSIVE /SMALLER-THAN:
+
+ When used with FTP DELETE, the /RECURSIVE switch deletes files
+ but not directories, and furthermore depends on the server
+ providing recursive file lists, which is not the normal
+ behavior. For further details, see the descriptions of these
+ switches in [274]Section 3.6. Synonyms: FTP MDELETE (Kermit
+ makes no distinction between DELETE and MDELETE); RDELETE.
+
+ FTP TYPE { TEXT, BINARY, TENEX }
+ Tells the FTP server to change its file-transfer type to the one
+ given, immediately. See [275]SET FTP TYPE for details.
+
+ [ [276]Top ] [ [277]FTP Top ] [ [278]C-Kermit Home ] [ [279]Kermit Home
+ ]
+
+3.5. Uploading Files With FTP
+
+ Uploading means sending files from the client (Kermit) to the FTP
+ server. The basic command for uploading files with FTP is PUT:
+
+ FTP PUT [ switches ] [ filespec [ as-name ] ]
+ Uploads (sends) the file or files that match the file
+ specification, which may include wildcards, to the server. If no
+ filespec is given, the names of files to send are taken from the
+ /LISTFILE: file, if any, otherwise from the SEND-LIST, if any.
+ Unless you go out of your way to prevent it, Kermit determines
+ the transfer mode (text or binary) for each file automatically,
+ and switches automatically on a per-file basis. If an as-name is
+ given, the file is sent under that name instead of its own (if
+ an as-name is given with a wildcard filespec, the result is a
+ bit more complicated, and is explained later in this section).
+
+ Unlike normal FTP clients, Kermit does not prompt you by default (or at
+ all) for each file; it just sends them, just as it does with Kermit
+ protocol. The filespec can be a literal filename or a Kermit pattern,
+ described in:
+
+ [280]http://www.columbia.edu/kermit/ckermit70.html#x4.9
+
+ Kermit patterns are equivalent to C-Shell patterns and provide a fair
+ amount of flexibility in selecting which files to send, which is
+ augmented by the file-selection switches presented in [281]Section
+ 3.5.1.
+
+ FTP MPUT [ switches ] filespec [ filespec [ ... ] ]
+ FTP MPUT is just like FTP PUT except it allows you to give more
+ than one file specification, and it does not allow an as-name in
+ the file list. However, as-names can be given to either PUT or
+ MPUT with the /AS-NAME: switch.
+
+ If a PUT or MPUT command results in one file being uploaded, it
+ succeeds if the file is uploaded completely and fails otherwise. If
+ more than one file is selected for upload, success or failure depends
+ on the [282]FTP ERROR-ACTION setting; if it is PROCEED (the default
+ setting), then the [M]PUT command succeeds if at least one of the files
+ was completely uploaded, and fails otherwise, If FTP ERROR-ACTION is
+ QUIT, the [M]PUT command succeeds if all selected files were uploaded
+ successfully, and fails if any file failed.
+
+ FTP uploads may be interrupted just like Kermit uploads. While the
+ transfer is in progress, type:
+
+ X to interrupt the current file and go on to the next file.
+ Z to cancel the current file and all remaining files.
+ ^C (Control-C): Like Z, but might act more quickly.
+
+ MPUT may be used as in regular FTP clients, but it is not required to
+ send multiple files; in Kermit it is required only if you want to give
+ multiple file specifications. Examples:
+
+ ftp put oofa.txt ; Send a single file oofa.txt
+ ftp put oofa.txt budget.txt ; Send single file oofa.txt as budget.txt
+ ftp put *.txt ; Send all *.txt files
+ ftp mput *.txt ; Send all *.txt files (same as "put *.txt")
+ ftp mput *.txt foo.bar ; Send all *.txt files plus foo.bar
+
+ The distinction between PUT and MPUT is important only when more than
+ one filespec is given, just like the distinction between Kermit SEND
+ and MSEND:
+
+ ftp put oofa.txt budget.txt ; Send oofa.txt AS budget.txt
+ ftp mput oofa.txt budget.txt ; Send oofa.txt AND budget.txt
+
+ If the source file specification includes any path segments, for
+ example:
+
+ put /tmp/oofa.txt
+ put subdir/another/andanother/oofa.txt
+
+ the path portion is stripped from the filename that is sent to the
+ server. However, if an as-name contains a path, it is retained.
+ Examples:
+
+ ftp put /usr/doc/oofa.txt ; Send as "oofa.txt".
+ ftp put oofa.txt /tmp/oofa.txt ; Send as "/tmp/oofa.txt"
+
+ The latter example sends the file oofa.txt from your current local
+ directory to the server's /tmp directory. This works only if the server
+ uses the same directory notation that you used in the as-name AND the
+ given directory already exists on the server AND if you have write
+ access to it.
+
+ Use caution when uploading from a case-sensitive file system, such as
+ UNIX, to a file system that is not case sensitive, such as Windows or
+ VMS. If you have two files in UNIX, AA and aa and upload both of them,
+ the second one will overwrite the first. The only way around this
+ provided by FTP protocol is its "unique server names" feature (SET FTP
+ UNIQUE-SERVER-NAMES or the /UNIQUE switch described below).
+
+3.5.1. FTP PUT Switches
+
+ FTP PUT and MPUT are similar in format and behavior to the regular
+ Kermit SEND and MSEND commands, and they allow most of the same
+ optional switches:
+
+C-Kermit>ftp put ? Filename, or switch, one of the following:
+ /after: /larger-than: /rename-to:
+ /array: /listfile: /server-character-set:
+ /as-name: /local-character-set: /server-rename-to:
+ /before: /move-to: /simulate
+ /binary /nobackupfiles /smaller-than:
+ /command /nodotfiles /tenex
+ /delete /nofollowlinks /text
+ /dotfiles /not-after: /transparent
+ /error-action: /not-before: /type:
+ /except: /permissions: /update
+ /filenames: /quiet /unique-server-names
+ /filter: /recover
+ /followlinks /recursive
+
+ Since most of these switches are common to Kermit's SEND and MSEND
+ commands, they described only briefly here. For greater detail see:
+
+ [283]http://www.columbia.edu/kermit/ckermit70.html#x1.5 (explanation
+ of switches)
+ [284]http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ (file-transfer switches)
+
+ First the file-selection switches:
+
+ /AFTER:date-time
+ /BEFORE:date-time
+ /NOT-AFTER:date-time
+ /NOT-BEFORE:date-time
+ Only send those files modified on or after or before the given
+ date and time. These switches can be combined to select files
+ modified between two date/times. Various date-time formats are
+ accepted; if the date-time contains spaces, it must be enclosed
+ in braces or doublequotes. See
+ [285]http://www.columbia.edu/kermit/ckermit70.html#x1.6 and
+ [286]Section 8.13 of this document for details about date-time
+ formats. Examples:
+
+ ftp put /after:{1 jan 2000 0:00:00} *
+ ftp put /after:-5days *
+
+ /LARGER-THAN:number
+ /SMALLER-THAN:number
+ Only send files larger (smaller) than the given number of bytes
+ (octets). These switches can be combined to select files in a
+ certain size range.
+
+ /TYPE:{TEXT,BINARY}
+ Only send files that are the given type, which is determined for
+ each file just before sending it by file scanning. BINARY
+ includes TENEX; if you have included a /TENEX switch, or
+ previously given a [SET] FTP TYPE TENEX command, binary files
+ are sent in TENEX, rather than BINARY mode.
+
+ /[NO]DOTFILES
+ [Don't] include files whose names begin with dot (.). By
+ default, such files are not included unless your filespec
+ explicitly mentions them.
+
+ /NOBACKUPFILES
+ Don't include files whose names end with .~nnn~, where nnn is a
+ number, e.g. oofa.txt.~27~. These are backup files created by
+ Kermit, EMACS, and other applications. By default, backup files
+ are included.
+
+ /NOFOLLOWLINKS
+ (UNIX only) Skip over symbolic links rather than following them
+ (default). This applies to wildcard and/or recursive [M]PUTs; if
+ a single filename is given, and it happens to be a symbolic
+ link, the file it points to is sent.
+
+ /FOLLOWLINKS
+ (UNIX only) Always follow (resolve) symbolic links, even in
+ wildcard or recursive [M]PUTs. Use with caution. Watch out for
+ circular links, endless loops, etc.
+
+ /EXCEPT:pattern
+ Exception list -- don't send files whose names match the given
+ pattern. See [287]Section 1.5.4 of the [288]C-Kermit 7.0 Update
+ Notes for details. If you want to exclude a directory from a
+ recursive [M]PUT, use /EXCEPT:{dirname/*}.
+
+ /RECURSIVE
+ Sends the desired files from the current (or given) directory,
+ plus all directories beneath it, including empty directories,
+ replicating the directory structure on the server. No special
+ capabilities are required in the server, but of course your
+ login ID on the server must have the appropriate access and
+ permission to create directories. Recursive PUTs work not only
+ between like platforms (e.g. UNIX to UNIX) but also between
+ unlike ones (e.g. UNIX to VMS or Windows), in which case
+ text-file format differences are handled by Kermit's automatic
+ text/binary mode switching ([289]Section 4) and character-set
+ translation ([290]Section 3.7). Synonym: /SUBDIRECTORIES.
+
+ /UPDATE
+ Send only files that have changed since last time ([291]Section
+ 3.5.2).
+
+ /ARRAY:arrayname
+ The "file" to be sent is an array, or a segment of one, rather
+ than a real file. In this case the other selection switches
+ don't apply. The array contents are sent in text mode, and each
+ array element is treated as a line. Example:
+
+ ftp put /as-name:array.txt /array:&a
+
+ (or, to send a segment of the array, /array:&a[100:199]). If you
+ don't include an /AS-NAME, a name of "_array_x_" is used (where
+ x is the array letter). If you include this switch, most other
+ switches are meaningless and ignored.
+
+ /COMMAND
+ The "file" to be sent is the standard output of a command,
+ rather than a real file. It is sent in text or binary mode
+ according to the prevailing FTP TYPE, which can be overridden
+ with a /TEXT or /BINARY switch. Example: Example:
+
+ ftp put /command /as-name:{userlist} {finger | sort -r}
+
+ /LISTFILE:filename
+ Tells Kermit to obtain the list of files to be sent from the
+ file whose name is given. This file must contain one file
+ specification (which may be wild) per line. If the list includes
+ files from different directories, such as a recursive listing of
+ a directory tree, the paths are recreated on the server (if
+ possible) if you include the /RECURSIVE switch; otherwise all
+ the files are sent to the current directory on the server.
+
+ Now the other switches:
+
+ /AS-NAME:text
+ If a single file is being sent, send it with the given text as
+ its name. If multiple files are being sent, the text must be a
+ template that includes variables such as \v(filename),
+ \v(filenumber), \v(ntime), to allow dynamic creation of each
+ name. The same applies to the as-name field of the FTP PUT
+ command. If this switch is not included (and an as-name is not
+ included as the second filename to PUT), each file is sent with
+ its own name.
+
+ /BINARY
+ /TEXT
+ /TENEX
+ Forces this upload to take place in the given mode, regardless
+ of the current FTP TYPE setting, and without automatic
+ text/binary switching. /ASCII is a synonym for /TEXT.
+
+ /FILTER:command
+ Specifies that the file(s) is/are to be passed through the given
+ command or pipeline on their way to the server. Example:
+
+ ftp put /binary /filter:{gzip -c \v(filename)} /as-name:\v(filename).gz *
+
+ /TRANSPARENT
+ /LOCAL-CHARACTER-SET:name
+ /SERVER-CHARACTER-SET:name
+ Character-set translation for text files, explained in
+ [292]Section 3.7.
+
+ /ERROR-ACTION:{PROCEED,QUIT}
+ Overrides the prevailing [293]FTP ERROR-ACTION for the duration
+ of this PUT or MPUT command only.
+
+ /RECOVER
+ Resume an interrupted transfer where from the point of
+ interruption (explained in [294]Section 3.5.2). Synonym:
+ /RESTART.
+
+ /DELETE
+ Tells Kermit to delete each source file immediately after, and
+ only if, it has been uploaded completely and successfully. This,
+ in effect, moves the file from the client to the server.
+
+ /MOVE-TO:directory
+ Tells Kermit to move each source file to the named local
+ directory after, and only if, it has been uploaded completely
+ and successfully.
+
+ /RENAME-TO:template
+ Tells Kermit to rename each (local) source file according to the
+ given template after, and only if, it has been uploaded
+ completely and successfully. The template works as in /AS-NAME.
+
+ /SERVER-RENAME-TO:template
+ Tells Kermit to ask the server to rename each file according to
+ the given template as soon as, and only if, it has been received
+ completely and successfully. The template works as in /AS-NAME.
+ Requires write and rename access on the server, so doesn't
+ usually work with (e.g.) anonymous uploads to public incoming
+ areas where the permissions don't allow renaming. Examples:
+
+ ftp mput /server-rename:\v(filename).ok *
+ Appends ".ok" to each filename on the server when it's
+ finished uploading.
+
+ ftp mput /as-name:\v(filename).tmp /server-rename:\v(filename) *
+ This is the reverse of the previous example; it uses a
+ temporary name while uploading is in progress and reverts
+ the file to its real name when uploading is complete.
+
+ ftp mput /as-name:\v(filename)
+ /server-rename:../final/\v(filename) *
+ Moves the file from the working directory to a final
+ directory when the upload is complete, but in this case
+ you have to know the pathname syntax of the server. If the
+ rename fails, the [M]PUT command fails according to the
+ [295]FTP ERROR-ACTION selection.
+
+ /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}
+ Overrides the [296]FTP FILENAMES setting for this upload only.
+
+ /PERMISSIONS:{ON,OFF}
+ Overrides the [297]FTP PERMISSIONS setting for this upload only.
+
+ /UNIQUE
+ Tells Kermit to tell the server to give [298]unique names to
+ incoming files that would otherwise overwrite existing files
+ that have the same name. This switch conflicts with /UPDATE,
+ /RECOVER, /PERMISSIONS, and /SERVER-RENAME since the client has
+ no way of knowing the name assigned by the server.
+
+ /QUIET
+ Don't display file-transfer progress or statistics.
+
+ /SIMULATE
+ Shows which files would be sent without actually sending them.
+ Useful (for example) with /UPDATE (next section). The results
+ are shown in the file-transfer display (if it is not disabled)
+ and in the transaction log (if one is active). Hint: use SET
+ TRANSFER DISPLAY BRIEF.
+
+3.5.2. Update Mode
+
+ When you include the /UPDATE switch, this means to skip sending any
+ file that already exists on the server if the local file's modification
+ date/time is not later than that of the corresponding file on the
+ server. Here is a typical application for update mode: Suppose that on
+ Computer A, you maintain a large set of files (say, a collection of Web
+ pages and graphics images, or the source files for a software
+ application), and you need to keep a parallel copy on another Computer,
+ B. Of course you could upload the entire collection every day:
+
+ cd source-directory
+ ftp computerb.xyzcorp.com
+ ( authentication details... )
+ ftp cd target-directory
+ ftp put [ switches ] *
+
+ But if the total size is large or the network slow, this would be
+ unnecessarily time-consuming. Worse, if other users or sites had to
+ update whenever new files appeared in B's directory, this would cause
+ them unnecessary work. By including the /UPDATE switch:
+
+ ftp put /update [ other-switches ] *
+
+ only those files that changed since last time are uploaded. Here's how
+ it works. For each local file that is selected for uploading:
+
+ * The remote filename is determined in the normal way, according to
+ the [299]FTP FILENAMES setting, /FILENAMES switch, or the as-name,
+ if any.
+ * Kermit sends an MDTM (modification time) command for the
+ corresponding remote filename to the server.
+ * If the server does not understand the MDTM command, the file is
+ sent.
+ * If the server can't find a file with the given name, the file is
+ sent.
+ * If the local file's modification time is later than that of the
+ remote file, the file is sent.
+ * Otherwise -- the remote file exists but its modification time is
+ equal to or earlier than that of the local file -- the file is
+ skipped.
+
+ All time comparisons take place in Coordinated Universal Time
+ (UTC)([300]1), also known as GMT or Zulu time: Timezone 0; standard
+ time, without daylight savings.
+
+ WARNING: Some FTP servers, such as Novell NWFTPD.NLM, ignore or
+ misimplement the FTP specification and send local time rather than
+ UTC.
+
+ Update mode is useful only when always used in the same direction. When
+ you upload (PUT) a file with FTP, the destination file receives the
+ current timestamp on the server's computer, not the original file's
+ timestamp ([301]2). If you try to FTP PUT /UPDATE the same file again,
+ it will be skipped (as expected) since the remote copy is newer.
+ However, if you try to FTP GET /UPDATE the same file ([302]Section
+ 3.6), it will be transferred for the same reason.
+
+ To check the availability of PUT /UPDATE on a particular connection,
+ issue an FTP MODTIME command for a file that is known to exist on the
+ server. If it succeeds, PUT /UPDATE should work and in that case, you
+ can run a procedure like the one above every day: the first time, it
+ sends all the files; after that, it sends only the ones that changed.
+ If a transaction log is active, a notation is included for any files
+ that are skipped.
+
+ Notes:
+ 1. Why is Coordinated Universal Time abbreviated UTC? From the
+ [303]National Institute of Standards and Technology FAQ: "In 1970
+ the Coordinated Universal Time system was devised by an
+ international advisory group of technical experts within the
+ International Telecommunication Union (ITU). The ITU felt it was
+ best to designate a single abbreviation for use in all languages in
+ order to minimize confusion. Since unanimous agreement could not be
+ achieved on using either the English word order, CUT, or the French
+ word order, TUC, the acronym UTC was chosen as a compromise."
+ 2. The Kermit FTP client is unusual in that, when downloading only, it
+ can set the received file's date from the file's date on the
+ server, but this should not affect the update feature. When
+ uploading to an FTP server, however, there is no mechanism for the
+ client to set the date of the uploaded file on the server.
+
+3.5.3 Recovery
+
+ Suppose that while you are uploading a large file over a slow
+ connection, the connection is lost before the entire file is
+ transferred. With most FTP clients, you would have to start over, thus
+ resending the portion of the file that was sent already, and that is
+ already on the server. But Kermit's /RECOVER switch (Synonym: /RESTART)
+ lets you continue an interrupted transfer from the point of failure,
+ thus transferring only the part that wasn't sent already. The
+ prerequisites for recovery are:
+
+ * The transfer must be in BINARY mode, or else the client and server
+ must reside on like systems (e.g. both on some form of UNIX).
+ * The FTP server must support the SIZE command.
+
+ Here's how it works. When you include the /RECOVER switch:
+
+ * Kermit checks for conflicting switches, such as /UPDATE and
+ /UNIQUE; if /RECOVER is given with these switches an error occurs.
+ If /RECOVER is given in other circumstances where it could serve no
+ useful purpose (e.g. with arrays, pipes, or filters), it is
+ ignored.
+
+ If the switch is accepted, then for each selected file:
+
+ * If it is not binary (determined by scanning) and the client and
+ server are not on like platforms, recovery is canceled (the entire
+ file is sent). Otherwise:
+ * A SIZE command is sent for the file (using its remote name). If the
+ reply indicates the file was not found, or the SIZE command was not
+ understood, or any other kind of error, recovery is canceled.
+ Otherwise:
+ * A MDTM (modification time) command is sent for the file. If a valid
+ reply is received, and the modification time of the local file is
+ later than that of the remote file, recovery is canceled.
+ Otherwise:
+ * If the sizes of the two files are identical, the file is not sent.
+ Otherwise:
+ * Kermit seeks to the recovery spot in the local file, tells the
+ server to APPEND the data which is about to arrive to the remote
+ file, and then sends the data starting at the recovery point.
+
+ To safeguard file integrity, recovery is not attempted unless all the
+ preconditions are met. For the widest possible usefulness, APPEND is
+ used rather than RESTART. For stream transfers (the only kind that
+ Kermit supports) the results are the same.
+
+ By design, the /RECOVER switch can be included with any FTP PUT or MPUT
+ command, even if it specifies a group of files. This allows you to
+ resume an interrupted batch transfer from where it left off. The files
+ that were already completely sent are skipped, the file that was
+ interrupted is recovered, and the remaining files are uploaded.
+
+ By the way, it doesn't matter how the original partial file was
+ uploaded -- FTP, Kermit, Zmodem, etc: as long as the preconditions are
+ met, it can be recovered with FTP PUT /RECOVER, or for that matter also
+ using Kermit protocol and SEND /RECOVER.
+
+ A word of caution, however, when the original upload was in text mode
+ with character-set translation ([304]Section 3.7):
+
+ * If the original upload involved a translation from one single-byte
+ character set to another (e.g. Code Page 850 to Latin-1), recovery
+ is safe if you specify the same translations for the recovery. If
+ you don't, the resulting file will contain a mixture of character
+ sets.
+ * If the original upload involved a translation that changed the size
+ of the file (e.g. from an alphabetic Code Page or Latin Alphabet to
+ Unicode, or vice versa), recovery is NOT safe, even if you specify
+ the same translations.
+
+ Kermit has no way of knowing anything about the previous upload. As a
+ safeguard, an error occurs if you include /RECOVER and also specify a
+ character-set of UCS2 or UTF8, since recovery can't possibly work in
+ that situation. Otherwise, it's up to you to avoid unsafe recovery
+ operations.
+
+ [ [305]Top ] [ [306]FTP Top ] [ [307]C-Kermit Home ] [ [308]Kermit Home
+ ]
+
+3.6. Downloading Files With FTP
+
+ Although uploading files with Kermit's FTP client is just as easy and
+ flexible as sending files with Kermit protocol, the same is not always
+ true for downloading because FTP servers lack some of the capabilities
+ of a Kermit server:
+
+ * If you want to get more than one file, you have to use MGET, not
+ GET, since the underlying FTP protocol is different in the two
+ cases. Kermit can't "autodetect" which one you mean, as it can with
+ PUT and MPUT, since it can't be expected to know the wildcard
+ syntax of the remote platform and/or FTP server (the same is true
+ for all other FTP clients). To complicate matters, FTP protocol now
+ includes two underlying mechanisms (NLST and MLSD) for
+ accomplishing MGET operations and, as explained in [309]Section
+ 3.11, the two behave differently.
+ * Automatic text-binary mode switching is not done by the server. It
+ can be done by the client (Kermit), but in this case it is not
+ based on a file scan (since there is no way for Kermit prescan a
+ server file), but rather on the filename, using C-Kermit 7.0
+ [310]filename patterns.
+ * Some options that are available with FTP PUT can not be used with
+ FTP [M]GET or don't work the same way:
+ /PERMISSIONS (FTP protocol has no mechanism for this).
+ /[NOT-]BEFORE, /[NOT-]AFTER (because of the timezone problem).
+ /RECOVER works only in binary mode. /RECURSIVE has limited
+ utility.
+
+ The commands for downloading are:
+
+ SET FILE DOWNLOAD-DIRECTORY [ directory ]
+ As with Kermit transfers, this command, if given, tells C-Kermit
+ where to store incoming files in the absence of a specific
+ as-name. If not given, incoming files are stored as indicated by
+ the as-name, if any, otherwise in the current directory, just as
+ with Kermit transfers. The more verbose transfer display formats
+ give the full pathname of each received file, and, in case you
+ have trouble finding a downloaded file afterwards, its full path
+ is also listed in the transaction log (if you kept one), and you
+ can also ask Kermit where it went with the [311]WHERE command.
+
+ SET FTP GET-FILETYPE-SWITCHING { ON, OFF }
+ ON by default, causing Kermit to switch automatically into text
+ or binary mode for each file based on whether its name matches a
+ text pattern or binary pattern. Set this OFF, or use a /TEXT,
+ /BINARY, or /TENEX switch to defeat this feature. Use SHOW
+ PATTERNS to see the current pattern list.
+
+ [ FTP ] GET [ switches ] filename [ as-name ]
+ Asks the server to send the given file, and if it comes, stores
+ it locally under the given as-name, if any, otherwise under its
+ original name (modified according to the selected filename
+ conversion option), in your download directory, if you have
+ specified one, otherwise in the directory indicated in the
+ as-name, if any, otherwise in your current directory. If you
+ accidentally use a wildcard in the filename ("get *.txt") the
+ server will reply with a message like "File not found" (unless
+ there is a file whose name actually is "*.txt"). If FTP
+ GET-FILETYPE-SWITCHING is ON, and in the absence of any GET
+ switches to override it, the file is transferred in binary mode
+ if it matches any of Kermit's binary name patterns, and in text
+ mode if it matches any of Kermit's text name patterns, and in
+ the prevailing FTP TYPE if it matches none of these patterns.
+
+ [ FTP ] MGET [ switches ] filespec [ filespec [ filespec [ ... ] ] ]
+ Like GET, but for multiple files. One or more file
+ specifications can be given, and any or all (or none) of them
+ can contain wildcards or can be directory names. The file list
+ may not include an as-name, but you can still give one with the
+ /AS-NAME: switch.
+
+ In both the FTP GET and MGET commands, any filenames that contain
+ spaces must be enclosed in braces or doublequotes (see [312]Section 5
+ for details).
+
+ FTP downloads may be interrupted just like Kermit transfers. While the
+ transfer is in progress, type:
+
+ * X to interrupt the current file and go on to the next file.
+ * Z (or Control-C) to cancel the current file and all remaining
+ files.
+
+ Before proceeding, a brief word about temporary files. In FTP protocol,
+ the MGET command works by requesting a file list from the server, and
+ then (internally) issuing a GET command (FTP RETR protocol directive)
+ for each file. The file list returned by the server can be any size at
+ all, so in case it is huge, we don't store it in memory; instead we put
+ it in a temporary file. For troubleshooting purposes, you should be
+ aware of two points:
+
+ 1. The location of the temporary file is chosen according the TMP or
+ TEMP environment variables. If neither of these variables is
+ defined, you might need to define it. In case there is not enough
+ space on the indicated disk or partition for the server's file
+ list, you might need to either clean up the temporary area, or
+ redefine the environment variable to indicate a different area that
+ has sufficient space.
+ 2. If you want to look at the list yourself, use SET FTP DEBUG ON.
+ This tells Kermit to (a) give you the full pathname of the
+ temporary file at the end of each MGET command, and (b) not to
+ delete it, as it normally does.
+
+3.6.1. FTP GET Switches
+
+ The following switches are available with FTP GET and MGET:
+
+ /TEXT
+ Specifies a text-mode transfer. Overrides the global FTP TYPE
+ setting and filename pattern-matching for the duration of the
+ current command only, All files are downloaded in text mode.
+ Synonym: /ASCII.
+
+ /BINARY
+ Specifies a binary-mode transfer. Overrides the global FTP TYPE
+ setting and filename pattern-matching for the duration of the
+ current command only. All files are downloaded in binary mode.
+
+ /TENEX
+ Like /BINARY but specifies a special binary transfer mode to be
+ used when getting 8-bit binary files from a 36-bit platform such
+ as TOPS-10, TOPS-20, or TENEX. All files are downloaded in the
+ special binary mode.
+
+ /RECOVER
+ This instructs Kermit to try to recover an incomplete download
+ from the point of failure. Works only in binary mode, and only
+ if the server supports the (not-yet-standard) FTP "REST"
+ directive. See [313]Section 3.6.3 for details. Synonym:
+ /RESTART.
+
+ /FILENAMES:{CONVERTED,LITERAL}
+ Overrides the [314]FTP FILENAMES (filename conversion) setting
+ for this download only, forcing incoming filenames to be either
+ converted or taken literally.
+
+ /AS-NAME:text
+ For GET, this is equivalent to giving an as-name after the
+ filename. For MGET, this is the only way to specify alternative
+ names for the incoming files. With MGET, the /AS-NAME text
+ should (must) contain a Kermit variable, usually \v(filename) or
+ \v(filenumber). Example:
+
+ mget /text /as-name:\v(filename).new *.c
+
+ This gets all ".c" files and stores them with "
+
+ .new" appended to their names. See the [315]C-Kermit 7.0 Update
+ Notes for details.
+
+ /COMMAND
+ This specifies that the incoming file is to be written to the
+ standard input of a command, rather than to a file. The command
+ name is the as-name from the GET command or the /AS-NAME
+ argument. If you need to refer to the incoming file's name in
+ the command, use \v(filename). See the description of the
+ regular Kermit [316]GET /COMMAND command for details and
+ examples.
+
+ /QUIET
+ Transfers the files quietly; don't put up a file-transfer
+ display.
+
+ /ERROR-ACTION:{QUIT,PROCEED}
+ This switch affects only MGET. If an error occurs with a
+ particular file, this tells whether to go on to the next file
+ (PROCEED) or to stop right away and fail (QUIT). The default is
+ PROCEED.
+
+ The file selection switches are:
+
+ /EXCEPT:{pattern} or /EXCEPT:{{pattern}{pattern}{...}}
+ Exception list for MGET; skip downloading any file whose name
+ matches any of the given patterns (when using the second format,
+ up to 64 patterns may be specified). [317]CLICK HERE for syntax
+ details.
+
+ /SMALLER-THAN:number
+ Download only files whose size is smaller than the given number
+ of bytes (octets). Requires that the FTP server support the SIZE
+ or MLSD directive.
+
+ /LARGER-THAN:number
+ Download only files whose size is greater than the given number
+ of bytes. Requires that the FTP server support the SIZE or MLSD
+ directive.
+
+ /NOBACKUPFILES
+ During MGET, don't download any files whose names end with
+ backup suffixes (.~n~ where n is a number).
+
+ /NODOTFILES
+ During MGET, don't download any files whose names begin with
+ period (.). Equivalent to /EXCEPT:{.*}.
+
+ /LISTFILE:local-filename
+ The given file contains a list of files to GET, one per line.
+ Filenames in the listfile can contain wildcard characters in the
+ syntax of the server. There is no limit on the number of lines
+ in the listfile.
+
+ /NAMELIST:local-filename
+ If this switch is given, then instead of actually retrieving the
+ selected files, the GET command retrieves a list of the names of
+ the files that would be retrieved, and places it in the
+ specified file. The resulting file is an ordinary text file,
+ with one filename per line, suitable for reading by a person, or
+ processing by a computer program, including Kermit itself (FOPEN
+ / FREAD / FWRITE / FCLOSE), and as /FILELIST: file. If the
+ filename is omitted or given as "-" (dash, hyphen), the list
+ goes to the screen. NOTE: if you want a copy of the complete
+ list sent by the server, use SET FTP DEBUG ON, perform an MGET,
+ and the temporary file containing the list will be kept rather
+ than deleted (and Kermit tells you its name).
+
+ /UPDATE, /COLLISION:keyword
+ Explained in [318]Section 3.6.2.
+
+ /RECURSIVE
+ This means to try to download an entire directory tree, rather
+ than just files from a particular directory. In fact, FTP
+ protocol does not provide a method to request a recursive
+ download (unless the server supports MLSD; see [319]Section
+ 3.11), so this works only if the FTP server does it anyway,
+ without being asked, as some do. In this case, Kermit detects
+ that names in the returned file list contain directory
+ separators, and therefore attempts to create the needed
+ directories as the files arrive. But this can work only if the
+ server is on the same kind of platform as the client, so the
+ pathname syntax can be recognized, and also because the server
+ does not switch between text and binary mode, which would be
+ vital for cross-platform transfers. Use with caution. Synonym:
+ /SUBDIRECTORIES.
+
+ Even when the server does not provide recursive file lists,
+ [M]GET /RECURSIVE forces Kermit to replicate any directory
+ structure implied or expressed by the server's file list. For
+ example:
+
+ get somepath/somefile
+
+ Gets the file named somefile from the server's somepath
+ directory and puts it Kermit's current (or download) directory,
+ whereas:
+
+ get /recursive somepath/somefile
+
+ creates the path locally and then puts the file in it. Similarly
+ for MGET:
+
+ mget */data/*
+
+ downloads all the files in all the data subdirectories of all
+ the subdirectories of the server's current directory and stores
+ them locally in Kermit's current (or download) directory,
+ whereas:
+
+ mget /recursive */data/*
+
+ re-creates the server's directory structure locally.
+
+ The FTP protocol does not include explicit mechanisms for recursion, so
+ Kermit builds upon what is available. Although an Internet draft
+ describes a mechanism ("MLSD") that would allow protocol-driven
+ recursion, similar to Kermit's File Attribute packets (circa 1984), it
+ has not yet attained RFC or standard status, and servers are not yet
+ widely available that offer this feature. In the meantime, the
+ effectiveness of MGET /RECURSIVE depends on the FTP server
+ implementation. If the server returns a recursive list in response to
+ the standard NLST command (whose behavior is ill-defined), Kermit's FTP
+ MGET /RECURSIVE command uses it to re-create the remote directory tree
+ locally. If the server supports MLSD, C-Kermit 8.0.206 and Kermit 95
+ 2.1 and later are able to sense it automatically and use it, as
+ described below in [320]Section 3.11.
+
+ The /BEFORE:, /AFTER:, /NOT-BEFORE:, and /NOT-AFTER: switches are not
+ available for downloading because of the confusion with timezones.
+ Would the given times be in the local timezone, the server's timezone,
+ or GMT? The FTP server's directory listings show its own local times
+ but since we don't know what timezone the server is in, there's no way
+ to reconcile our local times with the server's. Similarly, /PERMISSIONS
+ can't be preserved in downloads because FTP protocol provides no means
+ of querying the server for a file's permission.
+
+ Source-file disposition switches:
+
+ /DELETE
+ Each file that is downloaded successfully is to be deleted from
+ the server. Requires the appropriate file access rights on the
+ server.
+
+ /SERVER-RENAME-TO:template
+ Asks the server to rename each (remote) source file immediately
+ after, and only if, it is sent correctly. See [321]PUT
+ /SERVER-RENAME-TO: for details.
+
+ Destination-file disposition switches:
+
+ /TO-SCREEN
+ Displays the incoming file on the screen rather than storing it
+ on disk. If this switch is given, the /RENAME-TO and /MOVE-TO
+ switches are ignored, the file-transfer display is suppressed,
+ and the given file(s) is/are shown on the screen. Can be used
+ with /FILTER, e.g.
+
+ get /text /to-screen /filter:more oofa.txt
+
+ In fact, you should always use /TO-SCREEN with /FILTER or
+ /COMMAND when the command would result in displaying the
+ incoming file on the screen; otherwise C-Kermit would have no
+ way of knowing to suppress its file transfer display (since it
+ can't be expected to know what the command or filter does).
+
+ /RENAME-TO:template
+ Each file that is downloaded is to be renamed as indicated if
+ and only if it was received completely and without error. The
+ template can be literal text or can contain variables that are
+ evaluated for each file. For MGET, the text must contain
+ variables; for GET it can be a literal string. The \v(filename)
+ variable contains the name of the current file, so:
+
+ ftp mget /rename-to:\v(filename).ok *
+
+ causes each file that is successfully downloaded to have ".ok"
+ appended to its name. For details see [322]Section 4.1 of the
+ [323]C-Kermit 7.0 Update Notes.
+
+ /MOVE-TO:text
+ Just like /RENAME-TO:, except the text denotes the name of a
+ directory to which successfully downloaded files are to be
+ moved. If the directory does not exist, it is created.
+
+ The file transfer display does not show the /MOVE-TO or /RENAME-TO
+ value, since the incoming file has not yet been moved or renamed.
+
+3.6.2. Filename Collisions
+
+ What should happen if an incoming file has the same name as an existing
+ file in the same directory? By default, Kermit's FILE COLLISION setting
+ applies: BACKUP, RENAME, UPDATE, DISCARD, etc, as described in
+ [324]Using C-Kermit. Kermit's default FILE COLLISION setting is BACKUP
+ (rename the existing file and store the incoming file under its own
+ name) and therefore this is also the default FTP collision action.
+
+ The name under which an incoming file is to be stored is determined as
+ follows:
+
+ * If an as-name was given, the as-name is used. Otherwise:
+ * If the client and server platforms are alike or [325]FTP FILENAMES
+ is set to LITERAL (or the /FILENAMES:LITERAL switch was given for
+ this download), the incoming filename is used literally. Otherwise:
+ * The incoming filename is converted to a form that is friendly to
+ the local platform. For UNIX, for example, incoming filenames that
+ are all uppercase (as they might be from, say, VMS or an IBM
+ mainframe) are converted to lowercase.
+
+ If the resulting name coincides with the name of a local file that
+ already exists, we have a filename collision. Collisions are handled
+ according to the currently selected collision action:
+
+ SET FTP COLLISION { BACKUP, RENAME, UPDATE, DISCARD, APPEND, OVERWRITE
+ }
+ This establishes a filename collision for FTP, separate from the
+ Kermit one. The initial FTP collision setting is inherited from
+ Kermit's FILE COLLISION setting when the first FTP command is
+ given, but subsequent changes to Kermit's FILE COLLISION setting
+ do not affect the FTP COLLISION setting. SHOW FTP tells the
+ current FTP COLLISION setting.
+
+ FTP GET /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}
+ Overrides the current FTP COLLISION action for this download
+ only.
+
+ FTP GET /UPDATE
+ This is equivalent to GET /COLLISION:UPDATE, and is included for
+ symmetry with PUT /UPDATE
+
+ FTP GET /UPDATE and /COLLISION:UPDATE mean to download only those files
+ whose modification dates on the server are later than those on the
+ client. Date-time comparisons are done in Coordinated Universal Time
+ (UTC, GMT, ZULU). The command:
+
+ FTP MGET /COLLISION:APPEND /AS-NAME:newfilename *.*
+
+ Downloads all matching remote files into a single local file (in
+ whatever order the server sends them).
+
+3.6.3. Recovery
+
+ Recovery is available for downloads too, but there are some differences
+ from the uploading case described in [326]Section 3.5.3:
+
+ * The transfer must be in BINARY mode. It can not be in text mode,
+ even if the FTP server is on the same kind of platform as Kermit,
+ and even if there is no character-set translation. The original
+ download must also have been in binary mode.
+ * The FTP server must support the REST ("restart") directive.
+ Unfortunately, this is not a standard command; at this writing, it
+ is described only in an Internet Draft, not an RFC or Internet
+ Standard, but nevertheless it is found in several popular FTP
+ servers, such as [327]ProFTPD.
+
+ Here's how download recovery works:
+
+ * Kermit checks for conflicting switches, such as /UPDATE, /COMMAND,
+ or /FILTER. If /RECOVER is given with these switches an error
+ occurs.
+ * The prevailing transfer mode (SET FTP TYPE) must be BINARY. If it
+ is not, the /BINARY switch must have been included with the FTP
+ [M]GET command.
+
+ If the /RECOVER switch is accepted, then for each selected file:
+
+ * A SIZE command is sent for the file (using its remote name). If the
+ reply indicates the file was not found, or the SIZE command was not
+ understood, or any other kind of error, recovery is canceled (i.e.
+ the entire file is downloaded).
+ * If the sizes of the two files are identical, the file is not sent.
+ Otherwise:
+ * Kermit sends the REST directive to the server, indicating the size
+ of the local file. If the server responds affirmatively, Kermit
+ opens the local file in append mode and appends the incoming data
+ to it. Otherwise, recovery is canceled and the entire file is
+ downloaded.
+
+ The /RECOVER switch can be included with any FTP GET or MGET command,
+ even if it specifies a group of files. This lets you resume an
+ interrupted batch transfer from where it left off. The files that were
+ already completely sent are skipped, the file that was interrupted is
+ recovered, and the remaining files are uploaded. BUT... unlike with
+ uploading, where this can be done with any mixture of text and binary
+ files, when downloading, it can only be done if all the files are
+ binary.
+
+ It doesn't matter how the original partial file was downloaded -- FTP,
+ Kermit, HTTP, Zmodem, etc: as long as the preconditions are met, it can
+ be recovered with FTP [M]GET /RECOVER, or for that matter also with GET
+ /RECOVER (using Kermit protocol).
+
+ [ [328]Top ] [ [329]FTP Top ] [ [330]C-Kermit Home ] [ [331]Kermit Home
+ ]
+
+3.7. Translating Character Sets
+
+ A possibly unique feature of Kermit's FTP client is its ability to
+ convert character sets when transferring files in text mode,
+ independent of the capabilities of the FTP server, as well as to
+ translate the character sets of filenames regardless of transfer mode.
+ For compatibility with existing FTP clients, and because there is a
+ certain performance penalty, Kermit won't do this unless you ask for
+ it. If you enable this feature, you need to inform Kermit of the
+ character set (to be) used on the server and in some cases (explained
+ below) also the local file character set. This discussion assumes you
+ know a bit about character sets (as you must if you have to use them);
+ see Chapter 16 of [332]Using C-Kermit for a detailed treatment. The
+ Kermit commands for FTP character-set conversion are:
+
+ SET FTP CHARACTER-SET-TRANSLATION { ON, OFF }
+ Whether to translate character sets when transferring text files
+ with FTP. OFF by default. Set this to ON to enable character-set
+ translation for subsequent FTP uploads and downloads.
+
+ SET FTP SERVER-CHARACTER-SET [333]name
+ Text character set (to be) used by the server. Most FTP servers
+ are ignorant of character sets, so all translations are done
+ unilaterally by Kermit's FTP client. This means that when
+ downloading files, you must know in advance the character-set
+ used in the files you are downloading (and in their names). When
+ uploading, you must specify the character-set to which local
+ filenames and text-file contents are to be translated for
+ transmission to the server. If you SET FTP
+ CHARACTER-SET-TRANSLATION ON but do not specify an FTP
+ SERVER-CHARACTER-SET, [334]UTF8 is used, since this is the new
+ Internet standard international character set; it is upwards
+ compatible with ASCII and it encompasses most written languages
+ and therefore does not favor any particular group of people, as
+ any other default would do. If you SET FTP SERVER-CHARACTER-SET
+ to something (anything) when FTP CHARACTER-SET TRANSLATION is
+ OFF, this also sets the latter ON.
+
+ SET FILE CHARACTER-SET [335]name
+ This is the regular Kermit (non-FTP-specific) command for
+ identifying the character set (to be) used in local text files
+ and filenames.
+
+ TO REITERATE: If you SET FTP CHARACTER-SET TRANSLATION ON but do not
+ specify an FTP SERVER-CHARACTER-SET, outbound text files are converted
+ to UTF-8 and inbound text files are assumed to be UTF-8. If this is not
+ appropriate, be sure to also specify the desired FTP
+ SERVER-CHARACTER-SET.
+
+ You can use "special" (non-ASCII) characters in filenames in all the
+ client / server file management commands (FTP MKDIR, RMDIR, DIRECTORY,
+ VDIRECTORY, DELETE, etc), and also in file-transfer commands. When
+ giving commands such as FTP DIR (RDIR) and FTP PWD (RPWD), the reply is
+ translated too, so you can read it. In this example, the client and
+ server use entirely different codes to represent the special characters
+ of German:
+
+ C-Kermit> ftp xyzcorp.de /anonymous
+ C-Kermit> set ftp server-character-set latin1
+ C-Kermit> set file character-set german
+ C-Kermit> rcd St�dte
+ C-Kermit> rpwd
+ "/pub/ftp/St�dte is current directory"
+ C-Kermit> rdir
+ -rw-rw---- 1 olaf 54018 Jan 6 17:58 Adenb�ttel.txt
+ -rw-rw---- 1 ursula 373 Jan 5 15:19 A�lar.txt
+ -rw-rw---- 1 gisbert 482 Jan 5 15:20 Blowatz.txt
+ -rw-rw---- 1 gudrun 124 Jan 5 15:19 B�blingen.txt
+ -rw-rw---- 1 olga 14348 Jan 7 14:23 K�ln.txt
+
+ When the client and server file systems use different character sets,
+ you should take care to use only those characters that the two sets
+ share in common when creating filenames or text-file contents. For
+ example, PC code pages contain a lot line- and box-drawing characters,
+ and sometimes "smart quotes", etc, that are not found in ISO standard
+ 8-bit character sets. You should be especially careful to avoid using
+ such characters in filenames.
+
+ [ [336]C-Kermit Character Sets ]
+
+3.7.1. Character Sets and Uploading
+
+ Kermit's PUT and MPUT commands include full file-scanning capabilities,
+ as described in [337]Section 4. Thus if FTP CHARACTER-SET-TRANSLATION
+ is ON and your character-set associations are set up appropriately,
+ Kermit automatically switches on a per-file basis between text and
+ binary mode, and for each text file between your chosen 7-bit text
+ character set (e.g. ASCII or ISO 646 German), 8-bit text (e.g. Latin-1
+ or Japanese EUC), UCS-2, and UTF-8, and converts each of these
+ automatically to the server character-set, and furthermore
+ automatically differentiates between the Little and Big Endian forms of
+ UCS-2, always sending in Big Endian form.
+
+ WARNING: It is not advisable to use UCS-2 (or any Unicode
+ transformation other than UTF-8) "on the wire", i.e. as a server
+ character set. Most FTP servers are not able to cope with it, since
+ it contains lots of 0 (NUL) characters. If you do use it, Kermit
+ does not translate filenames to or from UCS-2, for reasons well
+ known to C programmers (for example, UNIX APIs assume filename
+ strings are NUL-terminated). [338]UTF-8 is the preferred (and
+ standard) Unicode format for the Internet.
+
+ FTP character-set translations differ from the regular Kermit ones by
+ not restricting translations to a file-character-set /
+ transfer-character-set pair. You can have Kermit's FTP client translate
+ between any pair of character sets it knows about. You can see the list
+ of supported character sets by typing either of the following:
+
+ set ftp server-character-set ?
+ set file character-set ?
+
+ A typical list looks like this ([339]CLICK HERE for an explanation of
+ the names):
+
+ C-Kermit>set file char ? One of the following:
+ ascii cp869-greek hebrew-7 mazovia-pc
+ british cyrillic-iso hebrew-iso next-multinational
+ bulgaria-pc danish hp-roman8 norwegian
+ canadian-french dec-kanji hungarian portuguese
+ cp1250 dec-multinational iso2022jp-kanji shift-jis-kanji
+ cp1251-cyrillic dg-international italian short-koi
+ cp1252 dutch jis7-kanji spanish
+ cp437 elot927-greek koi8 swedish
+ cp850 elot928-greek koi8r swiss
+ cp852 euc-jp koi8u ucs2
+ cp855-cyrillic finnish latin1-iso utf8
+ cp858 french latin2-iso
+ cp862-hebrew german latin9-iso
+ cp866-cyrillic greek-iso macintosh-latin
+ C-Kermit>
+
+ Thus you can translate not only between private sets (like PC code
+ pages) and standard ones (like Latin-1) as in Kermit protocol, but also
+ between any given pair of private sets (e.g. CP852 and Mazovia). All
+ conversions go through Unicode as the intermediate character set,
+ resulting in a minimum of character loss, since Unicode is a superset
+ of all other character sets known to Kermit.
+
+ In addition to the SET commands listed above, the FTP PUT and MPUT
+ commands include switches that apply only to the current command:
+
+ /LOCAL-CHARACTER-SET:name
+ /SERVER-CHARACTER-SET:name
+ Use these switches to force a particular translation. These
+ switches override the global FTP CHARACTER-SET-TRANSLATION and
+ SERVER-CHARACTER-SET settings and also character-set
+ differentiation by file scanning for the duration of the PUT or
+ MPUT command. The file scan is still performed, however, to
+ determine whether the file is text or binary; thus these
+ switches do not affect binary files unless you also include the
+ /TEXT switch to force all files to be treated as text.
+
+ In other words, if you include one or both of these switches with a PUT
+ or MPUT command, they are used. Similarly, the /TRANSPARENT switch
+ disables character-set translation for the PUT or MPUT command despite
+ the prevailing FTP CHARACTER-SET-TRANSLATION and SERVER-CHARACTER-SET
+ settings.
+
+ When uploading, the FILE CHARACTER-SET setting is ignored unless you
+ have forced Kermit not to [340]scan local files by including a /TEXT or
+ /BINARY switch with your [M]PUT command, or by disabling automatic
+ text/binary switching in some other way.
+
+ Examples:
+
+ 1. Suppose you have a CP852 (East European) text file that you want to
+ upload and store in ISO Latin Alphabet 2 encoding:
+ ftp put /local-char:cp852 /server-char:latin2 magyar.txt
+
+ 2. Suppose you always want your text files converted to Latin-2 when
+ uploading with FTP. Then put:
+ set ftp server-character-set latin2
+
+ in your Kermit customization file, and then you can omit the
+ /SERVER-CHARACTER-SET: switch from your FTP PUT commands:
+ ftp put /local-char:cp852 magyar.txt
+
+ 3. Now suppose that all the text files on your PC are written in
+ Hungarian, but they have a variety of encodings, and you don't want
+ to have to include the /LOCAL-CHARACTER-SET: switch on every FTP
+ PUT command, or (more to the point) you want to be able to send a
+ mixture of these files all at once. Put these commands in your
+ Kermit customization file:
+ set ftp server-character-set latin2 ; ISO 8859-2
+ set file default 7-bit-character-set hungarian ; ISO 646 Hungarian
+ set file default 8-bit-character-set cp852 ; PC East European Code Page
+
+ and now PUT and MPUT will automatically detect and switch among ISO
+ 646 Hungarian, Code Page 852, UTF-8, and UCS-2 encodings,
+ translating each one to Latin-2 for uploading:
+ ftp put *.txt
+
+ And since binary files are also detected automatically, the latter can
+ be simplified to:
+
+ ftp put *
+
+ even when "*" matches a diverse collection of binary and text files,
+ because translations are skipped automatically for binary files.
+
+3.7.2. Character Sets and Downloading
+
+ The commands and switches are the same as for uploading, but automatic
+ character-set switching works differently, since Kermit can't scan the
+ server files in advance. Instead, the transfer mode (text or binary) is
+ based on the filenames; each name is compared with Kermit's list of
+ text name patterns and binary name patterns. If the name matches a
+ binary pattern (for example, if the filename is oofa.tar.gz and one of
+ the filename patterns is "*.gz"), the file is downloaded in binary
+ mode; otherwise if it matches a text pattern (e.g. oofa.txt matches
+ "*.txt"), it is transferred in text ("ascii") mode. Otherwise, it is
+ transferred in the prevailing FTP TYPE.
+
+ In C-Kermit 8.0, the pattern lists used with FTP GET are not the same
+ lists used with Kermit transfers, and can not be viewed with SHOW
+ PATTERNS, nor adjusted with ADD and REMOVE TEXT-PATTERNS and
+ BINARY-PATTERNS, or SET FILE TEXT-PATTERNS and BINARY-PATTERNS.
+ Configuration of the FTP patterns list will be added in a future
+ release.
+
+ Examples:
+
+ get /server-char:latin1 /local-char:cp850 Gr��e.txt
+ In this command, the filename contains special characters, which
+ you enter using whatever character set your local computer uses,
+ in this case PC Code Page 850 (cp850). The command tells Kermit
+ (in case it didn't know already from its FILE CHARACTER-SET
+ setting) that the local character set is cp850 and the server's
+ character-set is ISO 8859-1 Latin Alphabet 1 (latin1). Kermit
+ translates the filename from cp850 to latin1 and sends the
+ latin1 name to the server. Since it's a text file (matches
+ "*.txt"), its contents are translated to cp850 on arrival, and
+ it is saved with a cp850 name.
+
+ mget /text /server:latin1 /local:utf8 *.txt
+ This command:
+
+ + Tells C-Kermit that the server's files are encoded in ISO
+ 8859-1 Latin Alphabet 1.
+ + Tells C-Kermit to translate the incoming files into Unicode
+ UTF-8 for storage.
+ + Asks the server to send all ".txt" files in text mode.
+
+ mget /server:latin1 /local:utf8 *
+ Tells Kermit to get all files from the server's directory,
+ switching between text and binary mode based on the filename.
+ The names of all the files are translated (to UTF-8 in this
+ case), but contents are translated (also to UTF-8) only for text
+ files.
+
+ Note that any pair of 8-bit character sets is likely to have some
+ incompatibilities. Any characters in the source file that do not have
+ equivalents in the destination file's character set are converted to
+ question marks. This applies to both filenames and to text file
+ contents.
+
+ Also note that the server's ability to accept special characters in
+ filenames depends on the particular server. For example:
+
+ get Gr��e.txt
+
+ works with WU-FTPD, but:
+
+ mget Gr��*.txt
+
+ does not.
+
+3.7.3. RFC2640
+
+ [341]RFC2640, July 1999, specifies a method by which the FTP client and
+ server can negotiate the use of UTF8. However, RFC2640-capable servers
+ are rare to nonexistent at this writing, and in any case you don't need
+ them to be able to transfer text in UTF8. C-Kermit lets you upload and
+ download text files in any character set it knows about, converting to
+ or from any other character set it knows about, without the knowledge,
+ permission, or cooperation of the server, and regardless of its
+ capabilities.
+
+ [ [342]Top ] [ [343]FTP Top ] [ [344]C-Kermit Home ] [ [345]Kermit Home
+ ]
+
+3.8. FTP Command Shortcuts
+
+ C-Kermit's FTP client coexists with other C-Kermit functions by
+ requiring the "ftp" prefix for each FTP-related command: FTP OPEN, FTP
+ GET, FTP BYE, and so on. For interactive use, however, this can be
+ rather awkward and sometimes surprising, for example when a GET command
+ starts a Kermit GET rather than an FTP GET. In fact, many Kermit
+ commands might just as easily apply to an FTP connection: GET, PUT
+ (SEND), BYE, and CLOSE. The following command lets you choose how these
+ commands are interpreted:
+
+ SET GET-PUT-REMOTE { AUTO, KERMIT, FTP }
+ Controls the orientation of GET, PUT, REMOTE and other
+ file-transfer and client/server commands that might apply to
+ either Kermit or FTP. The default setting is AUTO, meaning that
+ these commands apply to FTP if an FTP connection is open, and to
+ Kermit otherwise. KERMIT means they always apply to Kermit, FTP
+ means they always apply to FTP.
+
+ Here is a complete list of affected commands:
+
+ Kermit Command FTP Equivalent
+ (none) FTP [ OPEN ]
+ LOGIN FTP USER
+ LOGOUT FTP RESET
+ BYE FTP BYE
+ FINISH FTP BYE
+ CLOSE FTP BYE
+ HANGUP FTP BYE
+ BINARY FTP TYPE BINARY
+ TEXT (or ASCII) FTP TYPE ASCII
+ SEND (or PUT) FTP PUT
+ MSEND (or MPUT) FTP MPUT
+ RESEND FTP PUT /RECOVER
+ CSEND FTP PUT /COMMAND
+ GET FTP GET
+ MGET FTP MGET
+ REGET FTP GET /RECOVER
+ REMOTE HELP (RHELP) FTP HELP
+ REMOTE CD (RCD) FTP CD (CWD)
+ REMOTE PWD (RPWD) FTP PWD
+ REMOTE DIRECTORY (RDIR) FTP DIRECTORY
+ REMOTE DELETE (RDEL) FTP DELETE
+ REMOTE MKDIR (RMKDIR) FTP MKDIR
+ REMOTE RMDIR (RRMDIR) FTP RMDIR
+ REMOTE RENAME (RRENAME) FTP RENAME
+ REMOTE TYPE (RTYPE) FTP TYPE
+ REMOTE EXIT (REXIT) FTP BYE
+
+ The commands in the right-hand column always access FTP. The commands
+ in the left column can access either Kermit protocol or FTP:
+
+ * When GET-PUT-REMOTE is set to KERMIT, or to AUTO when there is no
+ FTP connection, the commands in the left-hand column access Kermit
+ protocol, and those right-hand column are required for FTP.
+ * When GET-PUT-REMOTE is set to FTP, or to AUTO when there is an
+ active FTP connection, the commands in the left-hand column access
+ the FTP connection and can not be used to access Kermit protocol.
+ In this case, if you want to be able to use both Kermit protocol
+ and the FTP connection, you must SET GET-PUT-REMOTE KERMIT, and
+ then use the FTP commands in the right-hand column to access the
+ FTP connection.
+
+ Note that file-management commands such as DIRECTORY, DELETE, CD, PWD,
+ MKDIR, RMDIR, HELP, RENAME, COPY, TYPE, and so on, always apply
+ locally, no matter what kind of connection you have. This is the
+ opposite of most FTP clients, where these commands are intended for the
+ server, and require an "L" prefix for local execution (e.g. "dir" gets
+ a directory listing from the server, "ldir" gets a local directory
+ listing). To illustrate with the CD command and a typical UNIX FTP
+ client:
+
+ Client Server Change Local Directory Change Remote Directory
+ FTP FTP lcd cd (cwd)
+ Kermit Kermit cd rcd, remote cd
+ Kermit FTP cd ftp cd, rcd, remote cd
+
+ Also note that not all REMOTE commands are useful with FTP, since FTP
+ servers do not offer the corresponding functions. These include:
+
+ * REMOTE ASSIGN - FTP servers don't have variables
+ * REMOTE COPY - FTP servers don't copy files
+ * REMOTE HOST - FTP servers don't execute host (shell) commands
+ * REMOTE KERMIT - FTP servers don't execute Kermit commands
+ * REMOTE PRINT - FTP servers don't print files
+ * REMOTE QUERY - FTP servers don't have variables
+ * REMOTE SET - FTP servers don't have Kermit settings
+ * REMOTE WHO - FTP servers don't send user lists
+
+ Finally note that command shortcuts do not apply to the HELP command.
+ For help about an FTP command, use (for example) "help ftp delete", not
+ "help delete" or "help rdelete".
+
+ [ [346]Top ] [ [347]FTP Top ] [ [348]C-Kermit Home ] [ [349]Kermit Home
+ ]
+
+3.9. Dual Sessions
+
+ You can have an FTP session open at the same time as a regular Kermit
+ SET LINE or SET HOST (terminal) session. In this case, the default SET
+ GET-PUT-REMOTE AUTO setting should ensure that all "two-faced" commands
+ like GET, PUT, REMOTE, HANGUP, BYE, etc, apply to the Kermit session,
+ and all commands for the FTP session must include the FTP prefix. To be
+ absolutely certain, you can use SET GET-PUT-REMOTE KERMIT.
+
+ ftp foo.bar.baz.com
+ if fail ...
+ (log in)
+ set host foo.bar.baz.com
+ if fail ...
+ (log in)
+
+ Now you have both an FTP and Telnet connection to the same host (of
+ course they could also be to different hosts, and you could also have a
+ direct or dialed serial connection instead of a Telnet connection). Now
+ assuming you have a Kermit server on the far end of the Kermit
+ connection:
+
+ rcd incoming ; Changes Kermit server's directory (= REMOTE CD)
+ ftp cd incoming ; Changes FTP server's directory
+ put oofa.txt ; Sends a file on the Kermit connection
+ ftp put oofa.txt ; Sends a file on the FTP connection
+ bye ; Shuts down the Kermit connection
+ ftp bye ; Shuts down the FTP connection
+
+ Note that PUT and SEND are synonyms for both FTP and Kermit
+ connections.
+
+ You can also establish dual sessions on the Kermit command line:
+
+ kermit -j host1 -9 host2
+
+ This makes a Telnet connection to host1 and an FTP connection to host2.
+
+ [ [350]Top ] [ [351]FTP Top ] [ [352]C-Kermit Home ] [ [353]Kermit Home
+ ]
+
+3.10. Automating FTP Sessions
+
+ Most of Kermit's scripting features can be used to make and control FTP
+ sessions: FOR and WHILE loops, IF-ELSE and SWITCH constructions,
+ variables, arrays, built-in functions, and all the rest. You can't use
+ INPUT, MINPUT, OUTPUT, CLEAR, or SCRIPT on an FTP session, but these
+ are not needed since the FTP protocol is well defined.
+
+ [354]CLICK HERE for an FTP scripting tutorial.
+
+3.10.1. FTP-Specific Variables and Functions
+
+ The following variable tells whether an FTP connection is open:
+
+ \v(ftp_connected)
+ 1 if there is an active FTP connection, 0 if there isn't.
+
+ The FTP OPEN command sets:
+
+ \v(ftp_host)
+ The host to which the most recent FTP connection was made.
+
+ \v(ftp_security)
+ The security method negotiated for the current FTP session. The
+ value is "NULL" when no security is used. Other possibilities
+ are GSSAPI, KERBEROS_V4, SSL, TLS, and SRP. Also see
+ \v(authname), \v(authstate), and \v(authtype). See [355]3.2.
+ Making Secure FTP Connections.
+
+ \v(ftp_server)
+ The OS type (UNIX, VMS, etc) of the FTP server host.
+
+ The FTP USER command (or FTP OPEN /USER:, or FTP with automatic login)
+ sets:
+
+ \v(ftp_loggedin)
+ 1 if you are logged in to an FTP server, 0 if you are not.
+
+ The current COMMAND-PROTECTION-LEVEL and DATA-PROTECTION-LEVEL values
+ are reflected in:
+
+ \v(ftp_cpl)
+ \v(ftp_dpl)
+ The values are "clear", "confidential", "safe" or "private". See
+ [356]3.2. Making Secure FTP Connections.
+
+ The FTP GET-PUT-REMOTE setting is reflected in:
+
+ \v(ftp_getputremote)
+ The values are "auto", "ftp", or "kermit".
+
+ Every FTP command sets the \v(success) variable, as well as the
+ following two FTP-specific variables:
+
+ \v(ftp_code)
+ The standardized numeric FTP protocol code from the server's
+ response to the last client command, a 3-digit decimal number
+ defined in [357]RFC959. Briefly:
+
+ 1xx = Positive Preliminary Reply
+ 2xx = Positive Completion Reply
+ 3xx = Positive Intermediate Reply
+ 4xx = Transient Negative Completion Reply
+ 5xx = Permanent Negative Completion Reply
+
+ \v(ftp_message)
+ The text message, if any, from the server's response to the last
+ client command. If the most recent response had multiple lines,
+ this variable has only the final line. These messages are not
+ standardized and vary in format and content from server to
+ server. Synonym: \v(ftp_msg).
+
+ FTP file transfers set the regular Kermit transfer status variables:
+
+ \v(cps) Characters per second of most recent transfer.
+ \v(filespec) File specification used in most recent transfer.
+ \v(fsize) Size of file most recently transferred.
+ \v(tfsize) Total size of file group most recently transferred.
+ \v(xferstatus) Status of most recent transfer (0 = success, 1 = failure).
+ \v(tftime) Elapsed time of most recent transfer, in seconds.
+
+ During an FTP transfer, the per-file variables are:
+
+ \v(filename) Name of current file.
+ \v(filenumber) Ordinal file number in group (1, 2, 3, ...)
+
+3.10.2. Examples
+
+ Let's begin with a simple example showing how to log in, send some
+ files, and log out:
+
+ define error if fail { ftp bye, stop 1 Error: \%1 }
+ set transact brief
+ log t
+ ftp ftp.xyzcorp.com /anonymous
+ if fail stop 1 Connection failed
+ if not \v(ftp_loggedin) stop 1 Login failed
+ ftp cd incoming
+ error {ftp cd}
+ cd upload
+ error {local cd}
+ ftp put /delete *
+ error {put}
+ ftp bye
+
+ First we define an error handling macro to be used after the connection
+ is made. Then we set up a brief-format transaction log to keep a record
+ of our file transfers. Then we make a connection to the host and log in
+ anonymously. The "if fail" command checks whether the connection was
+ made. The "if not" command checks whether login was successful.
+ Obviously the script should not continue unless both tests succeed.
+
+ Next we change to the server's 'incoming' directory and to our own
+ 'upload' directory, and send all the files that are in it (they can be
+ any mixture of text and binary files), deleting each source file
+ automatically after it is successfully uploaded. Each of these
+ operations is checked with the ERROR macro, which prevents the script
+ from continuing past a failure.
+
+ Finally we close the FTP session with the "bye" command.
+
+ Just like any other Kermit script, this one can be used in many ways:
+
+ * It can be stored in a file, and Kermit can be told to TAKE the
+ file.
+ * In UNIX, it can be a "[358]kerbang" script and therefore run
+ directly from the shell prompt or as a cron job.
+
+ We could have used command shortcuts like "rcd", "put", and "bye", but
+ since they can be ambiguous under certain circumstances, it is better
+ to avoid them in scripts; they are intended mainly for convenience
+ during interactive use. However, if you wish to use the shortcuts in a
+ script, you can do it this way (error handling omitted for brevity):
+
+ local \%t ; Declare a local temporary variable
+ assign \%t \v(ftp_getputremote) ; Save current FTP GET-PUT-REMOTE setting
+ set ftp get-put-remote ftp ; Choose FTP orientation
+ ftp xyzcorp.com /anonymous ; Open an FTP connection
+ get oofa.txt ; GET a file
+ put foo.bar ; PUT a file
+ rdel yesterday.log ; Delete a file on the server
+ bye ; Log out and disconnect from server.
+ set ftp get-put-remote \%t ; Restore previous GET-PUT-REMOTE setting
+
+ Of course, FTP scripts can also be written as macros. This lets you
+ pass parameters such as hostnames, usernames, and filenames to them:
+
+ define doftpget {
+ if < \v(argc) 4 end 1 Usage: \%0 host user remotefile [ localfile ]
+ ftp \%1 /user:\%2
+ if fail end 1 FTP OPEN \%1 failed
+ if not \v(ftp_loggedin) end 1 FTP LOGIN failed
+ ftp get {\%3} {\%4}
+ if fail end 1 FTP GET \%3 failed
+ ftp bye
+ }
+
+ Add this definition to your Kermit customization file, and it will
+ always be available when you start Kermit. This macro lets you download
+ a file with FTP by giving a single command, e.g.:
+
+ doftpget xyzcorp.com anonymous oofa.txt
+
+3.10.3. Automating Secure FTP Sessions
+
+ Often when making secure connections, you are prompted interactively
+ for certain information or permission to proceed. These prompts can
+ stop an automated procedure. To avoid them, you must give the
+ appropriate commands to disable them, and/or supply the prompted-for
+ information beforehand. Here are a few hints:
+
+ * Make sure that SET TAKE ERROR and SET MACRO ERROR are both OFF.
+ This is the default, but in case you have set either one of these
+ ON in your script or initialization file, this makes the script
+ halt on any kind of error. Normally you would want to check each
+ operation for success or failure and take appropriate action.
+ * On SSL and TLS connections, you may be asked whether it is OK to
+ proceed with a connection to server that presents a self-signed
+ certificate. You can use the SET AUTHENTICATION SSL (or TLS) VERIFY
+ or SET AUTH SSL (or TLS) CERTS-OK commands to avoid this prompt by
+ not requesting a certificate from the peer.
+ * (More to be added...)
+
+ [ [359]Top ] [ [360]FTP Top ] [ [361]FTP Script Tutorial ] [
+ [362]C-Kermit Home ] [ [363]Kermit Home ]
+
+3.11. Advanced FTP Protocol Features
+
+ The remainder of the FTP documentation (through the end of Section 3)
+ is new to C-Kermit 8.0.206, but we leave it in black to prevent
+ headaches. Except for titles.
+ * [364]TERMINOLOGY
+ * [365]FEATURE NEGOTIATION
+ * [366]USING MGET: NLST VERSUS MLSD
+ * [367]EXAMPLES
+ * [368]REFERENCES
+
+ The new releases of [369]C-Kermit (8.0.206) and [370]Kermit 95 (2.1)
+ support new FTP protocol features from RFC 2389 as well as most of
+ what's in the Elz and Hethmon Extensions to FTP Internet Draft (see
+ [371]References). Some of these features, such as SIZE (request a
+ file's size), MDTM (request file's modification time), and REST
+ (restart interrupted transfer) have been widely implemented in FTP
+ clients and servers for years (as well as in the initial release of the
+ Kermit FTP clients). Others such as FEAT and MLSD are rarely seen and
+ are new to the upcoming Kermit releases. TVFS (Trivial Virtual File
+ Store) is supported implicitly, and the UTF-8 character-set is already
+ fully supported at the protocol and data-interchange level.
+
+ For Kermit users, the main benefit of the new FTP protocol extensions
+ is the ability to do recursive downloads. But the extensions also
+ introduce complications and tradeoffs that you should be aware of. Of
+ course Kermit tries to "do the right thing" automatically in every case
+ for backwards compatibility. But (as noted later) some cases are
+ inherently ambiguous and/or can result in nasty surprises, and for
+ those situations new commands and switches are available to give you
+ precise control over Kermit's behavior, in case the defaults don't
+ produce the desired results.
+
+3.11.1. Terminology
+
+ Command-line FTP clients such as Kermit (as well as the traditional FTP
+ programs found on Unix, VMS, ..., even Windows) have commands like PUT,
+ MPUT, GET, MGET, and BYE, which they convert into zero or more FTP
+ protocol commands, such as NLST, RETR, QUIT. For clarity, we'll use
+ "command" to refer to commands given by the user to the FTP client, and
+ "directive" for FTP protocol commands sent by the FTP client to the FTP
+ server.
+
+3.11.2. Feature Negotiation
+
+ New FTP protocol features are negotiated by the client sending a FEAT
+ directive and the server responding with a list of (new) features it
+ supports, or else with an error indication if it does not support the
+ FEAT directive at all, in which case the client has to guess which new
+ features it supports (Kermit guesses that it supports SIZE and MDTM but
+ not MLST). Note that the MLST feature includes MLSD, which is not
+ listed separately as a feature.
+
+ Guessing is nice when it works, but sometimes it doesn't, and some FTP
+ servers become confused when you send them a directive they don't
+ understand, or they do something you didn't want, sometimes to the
+ point of closing the connection. For this reason, Kermit lets you
+ override default or negotiated features with the following new
+ commands:
+
+ FTP { ENABLE, DISABLE } FEAT
+ Enables or disables the automatic sending of a FEAT directive
+ upon connection to an FTP server. Note that FTP [ OPEN ] /NOINIT
+ also inhibits sending the FEAT directive (and several others)
+ for the connection being OPEN'd, but without necessarily
+ disabling FEAT for subsequent connections in the same Kermit
+ instance. FEAT is ENABLED by default, in which case many FTP
+ servers are likely to reply:
+
+500 'FEAT': command not understood
+
+ which is normally harmless (but you never know). (In C-Kermit
+ 8.0.208, this error message is suppressed unless you SET FTP
+ DEBUG ON.)
+
+ FTP ENABLE { MDTM, MLST, SIZE }
+ Enables the given directive for implicit use by the FTP GET and
+ MGET commands in case it has been disabled or erroneously
+ omitted by the server in its FEAT response. Note: MLSD can be
+ used in the FTP ENABLE and DISABLE commands as a synonym for
+ MLST. YOU MUST GIVE THIS COMMAND AFTER MAKING THE FTP
+ CONNECTION.
+
+ FTP DISABLE { MDTM, MLST, SIZE }
+ Disables implicit use of the given directive by GET or MGET in
+ case it causes problems; for example, because it makes multifile
+ downloads take too long or the server announces it erroneously
+ or misimplements it. Use DISABLE FEAT before making a connection
+ to prevent Kermit from sending the FEAT directive as part of its
+ initial sequence. Note that disabling FEAT, SIZE, or MDTM does
+ not prevent you from executing explicit FTP FEATURES, FTP SIZE,
+ or FTP MODTIME commands. Also note that disabling SIZE prevents
+ PUT /RESTART (recovery of interrupted uploads) from working. YOU
+ MUST GIVE THIS COMMAND AFTER MAKING THE FTP CONNECTION.
+
+ To enable or disable more than one feature, use multiple FTP ENABLE or
+ FTP DISABLE commands. The SHOW FTP command shows which features are
+ currently enabled and disabled.
+
+ FTP FEATURES
+ This command sends a FEAT directive to the server. In case you
+ have been disabling and enabling different features, this
+ resynchronizes Kermit's feature list with the server's. If the
+ server does not support the FEAT directive, Kermit's feature
+ list is not changed.
+
+ FTP OPTIONS directive
+ Informational only: the server tells what options, if any, it
+ supports for the given directive, e.g. MLST. Fails if the server
+ does not support the OPTS directive or if the directive for
+ which options are requested is not valid. The directive is
+ case-insensitive.
+
+ FTP SIZE filename
+ Sends a SIZE directive to the server for the given file. The
+ filename must not contain wildcards. The server responds with an
+ error if the file can't be found, is not accessible, or the SIZE
+ directive is not supported, otherwise with the length of the
+ file in bytes, which Kermit displays and also makes available to
+ you in its \v(ftp_message) variable. If the directive is
+ successful, Kermit (re-)enables it for internal use by the GET
+ and MGET directives on this connection.
+
+ FTP MODTIME filename
+ Works just like the SIZE directive except it sends an MDTM
+ directive. Upon success, the server sends modification date-time
+ string, which Kermit interprets for you and also makes available
+ in its \v(ftp_message) variable.
+
+ Whenever a SIZE or MDTM directive is sent implicitly and rejected by
+ the server because it is unknown, Kermit automatically disables it.
+
+3.11.3. Using MGET: NLST versus MLSD
+
+ When you give an MGET command to an FTP client, it sends a request to
+ the FTP server for a list of files, and then upon successful receipt of
+ the list, goes through it and issues a RETR (retrieve) directive for
+ each file on the list (or possibly only for selected files).
+
+ With the new FTP protocol extensions, now there are two ways to get the
+ list of files: the NLST directive, which has been part of FTP protocol
+ since the beginning, and the new MLSD directive, which is new and not
+ yet widely implemented. When NLST is used and you give a command like
+ "mget *.txt", the FTP client sends:
+
+NLST *.txt
+
+ and the server sends back a list of the files whose names match, e.g.
+
+foo.txt
+bar.txt
+baz.txt
+
+ Then when downloading each file, the client sends SIZE (if it wants
+ have a percent-done display) and MDTM (if it wants to set the
+ downloaded file's timestamp to match that of the original), as well as
+ RETR (to retrieve the file).
+
+ But when MLSD is used, the client is not supposed to send the filename
+ or wildcard to the server; instead it sends an MLSD directive with no
+ argument (or the name of a directory), and the server sends back a list
+ of all the files in the current or given directory; then the client
+ goes through the list and checks each file to see if it matches the
+ given pattern, the rationale being that the user knows only the local
+ conventions for wildcards and not necessarily the server's conventions.
+ So with NLST the server interprets wildcards; with MLSD the client
+ does.
+
+ The interpretation of NLST wildcards by the server is not
+ necessarily required or even envisioned by the FTP protocol
+ definition (RFC 959), but in practice most clients and servers work
+ this way.
+
+ The principal advantage of MLSD is that instead of sending back a
+ simple list of filenames, it sends back a kind of database in which
+ each entry contains a filename together with information about the
+ file: type, size, timestamp, and so on; for example:
+
+size=0;type=dir;perm=el;modify=20020409191530; bin
+size=3919312;type=file;perm=r;modify=20000310140400; bar.txt
+size=6686176;type=file;perm=r;modify=20001215181000; baz.txt
+size=3820092;type=file;perm=r;modify=20000310140300; foo.txt
+size=27439;type=file;perm=r;modify=20020923151312; foo.zip
+(etc etc...)
+
+ (If the format of the file list were the only difference between NLST
+ and MLSD, the discussion would be finished: it would always be better
+ to use MLSD when available, and the MGET user interface would need no
+ changes. But there's a lot more to MLSD than the file-list format; read
+ on...)
+
+ The client learns whether the server supports MLSD in FEAT exchange.
+ But the fact that the server supports MLSD doesn't mean the client
+ should always use it. It is better to use MLSD:
+
+ * On connections where the server imposes a time penalty for every
+ command, e.g. the Red Hat Rawhide server. With MLSD, the client
+ needs to send only one command (RETR) per file, whereas NLST
+ requires three (SIZE, RETR, and MDTM). Suppose there is a 30-second
+ delay for each command and 1000 files are to be fetched; in that
+ case, MLSD saves 60,000 seconds = 1000 minutes = 16 hours and 40
+ minutes.
+ * For recursive downloads since there is no dependable way to
+ download directory trees with NLST.
+
+ But it is better to use NLST:
+
+ * If you want only a couple short files out of a large directory. In
+ this case, NLST is the better choice since the server sends a list
+ of only the files you want, not a list of (say) a million files,
+ which can make a big difference on slow connections. For example,
+ suppose your wildcard matches three files of 1K each, but the
+ million-file listing is 80MB long, and your connection is through a
+ modem. The overhead of using MLSD is practically infinite.
+ * If the server supports wildcarding features not known to the
+ client, but that can be used to achieve desirable effects otherwise
+ unobtainable, such as "[dir...]*.txt" in VMS or AOS/VS "except"
+ clauses.
+ * If you have been given a wildcard string by an FTP site
+ administrator for fetching a specific group of files out of a
+ larger directory, e.g. "mget ck[cuw]*.[cwh] makefile", that is
+ expected to work with any client (an FTP site administrator can't
+ be expected to know the wildcard syntax of every FTP client).
+
+ But when using MLSD there are complications:
+
+ * MLSD wants either a blank argument (meaning the current directory)
+ or else the name of a specific directory. The client must not send
+ it a wildcard or a filename.
+ * But if the user's command is "mget xxx", how does the client know
+ whether to send "xxx" in the MLSD directive? It might be the name
+ of a directory on on the server, in which case it should be sent,
+ or it might be the name of a file on the server (or a wildcard), in
+ which case it must not be sent. Since the client knows its own
+ wildcard syntax, then in most cases it would be right to send
+ "MLSD" with no argument if xxx is wild, and to send "MLSD xxx" if
+ it is not.
+ * But suppose the server's file system allows filename characters
+ that correspond with the client's wildcard syntax? For example:
+ "[abc]" could be either a valid VMS directory name or a wildcard
+ pattern used by the FTP client. What should the client do with
+ "mget [abc]"? In this case there must be a way for the user to
+ force sending the MGET argument as the MLSD argument.
+ * If "xxx" is a regular file in the server's current directory, "mget
+ xxx" works with NLST but not with MLSD.
+
+ To further complicate matters, NLST can (in theory) work just like
+ MLSD: if sent with a blank argument or a directory name, it is supposed
+ to return a complete list of files in the current or given directory,
+ which the client can match locally against some pattern. It is not
+ known if any FTP server or client does this but nevertheless, it should
+ be possible since this behavior can be inferred from RFC 959.
+
+ In view of these considerations, and given the need to preserve the
+ traditional FTP client command structure and behavior so the software
+ will be usable by most people:
+
+ 1. The MGET command should produce the expected result in the common
+ cases, regardless of whether NLST or MLSD is used underneath.
+ 2. For anomalous cases, the user needs a way to control whether the
+ MGET argument is sent to the server or kept for local use.
+ 3. At the same time, the user might need a way to send a directory
+ name to the server, independent of any wildcard pattern.
+ 4. The user needs a way to force NLST or MLSD for a given MGET
+ command.
+
+ By default, Kermit's MGET command uses MLSD if MLST is reported by the
+ server in its FEAT list. When MLSD is used, the filespec is sent to the
+ server if it is not wild (according to Kermit's own definition of
+ "wild" since it can't possibly know the server's definition). If the
+ filespec is wild it is held for local use to select files from the list
+ returned by the server. If MLST is not reported by the server or is
+ disabled, Kermit sends the MGET filespec with the NLST directive.
+
+ The default behavior can be overridden globally with FTP DISABLE MLST,
+ which forces Kermit to use NLST to get file lists. And then for
+ situations in which MLSD is enabled, the following MGET switches can be
+ used to override the defaults for a specific MGET operation:
+
+ /NLST
+ Forces the client to send NLST. Example:
+
+mget /nlst foo.*
+
+ /MLSD
+ Forces the client to send MLSD (even if MLST is disabled).
+ Example:
+
+mget /mlsd foo.*
+
+ /MATCH:pattern
+ When this switch is given, it forces the client to hold the
+ pattern for local use against the returned file list. If a
+ remote filespec is also given (e.g. the "blah" in "mget
+ /match:*.txt blah"), then it is sent as the NLST or MLSD
+ argument, presumably to specify the directory whose files are to
+ be listed. When the /MATCH switch is not given, the MGET
+ filespec is sent to the server if the directive is NLST or if
+ the filespec is not wild. Examples:
+
+ Command: With NLST: With MLSD:
+ mget NLST MLSD
+ mget *.txt NLST *.txt MLSD
+ mget foo NLST foo MLSD foo
+ mget /match:*.txt NLST MLSD
+ mget /match:*.txt foo NLST foo MLSD foo
+
+ In other words, the pattern is always interpreted locally unless MGET
+ uses NLST and no /MATCH switch was given.
+
+3.11.4. Examples
+
+3.11.4.1. Downloading a Single File
+
+ There are no choices here, just use the FTP GET command. Kermit always
+ sends the RETR directive, and possibly SIZE and/or MDTM. The small
+ advantage of using MLST in this case is outweighed by the risk and
+ effort of coding a special case.
+
+3.11.4.2. Downloading a Group of Files from a Single Directory
+
+ This case presents tradeoffs, especially on slow connections:
+
+ * For downloading all or most of the files in a directory, MLSD is
+ better because it eliminates the need to send SIZE and MDTM for
+ each file. No special actions are required in this case; Kermit
+ uses MLSD automatically if the server supports it (unless you have
+ disabled it).
+ * For a small number of files from a large directory, NLST is better
+ because it bypasses downloading of a potentially huge file list
+ prior to the files themselves. If you have a connection to a server
+ that supports MLSD, use the /NLST switch to force NLST:
+
+mget /nlst t[1234].h
+
+ * If the server supports MLSD but does not support separate SIZE or
+ MDTM directives, and you need the size and/or timestamp
+ information, MLSD is better; no special actions required.
+ * If the server supports MLSD but does not support the "size" and
+ "modify" facts, but it does support the SIZE or MDTM directives,
+ and you need the size and/or timestamp information, NLST is better.
+
+3.11.4.3. Downloading a Directory Tree
+
+ MLSD is the only choice for recursive downloads; they rarely, if ever,
+ work with NLST (the few cases where they do work rely on extra-protocol
+ "secret" notations for the NLST argument). No special actions are
+ required to force MLSD when the server supports it, unless you have
+ disabled it. Examples:
+
+ MGET /RECURSIVE
+ This tells the server to send all files and directories in the
+ tree rooted at its current directory.
+
+ MGET /RECURSIVE *.txt
+ This tells the server to send all *.txt files in the tree rooted
+ at its current directory.
+
+ MGET /MLSD /RECURSIVE *.txt
+ Same as the previous example but forces Kermit to send MLSD in
+ case it was disabled, or in case the server is known to support
+ it even though it did not announce it in its FEAT listing.
+
+ MGET /RECURSIVE /MATCH:*.zip archives
+ Tells the server to send all ZIP files in the tree rooted at its
+ "archives" directory.
+
+ MGET /RECURSIVE /MATCH:* [abc]
+ The server is running on VMS and you want it to send all the
+ files in the directory tree rooted at [ABC]. But since "[abc]"
+ looks just like a wildcard, you have to include a /MATCH: switch
+ to force Kermit to send "[abc]" as the MLSD argument.
+
+ In all cases in which the /RECURSIVE switch is included, the server's
+ tree is duplicated locally.
+
+ Although MLSD allows recursion and NLST does not, the MLSD
+ specification places a heavy burden on the client; the obvious,
+ straightforward, and elegant implementation (depth-first, the one
+ that Kermit currently uses) requires as many open temporary files as
+ the server's directory tree is deep, and therefore client resource
+ exhaustion -- e.g. exceeding the maximum number of open files -- is
+ a danger. Unfortunately MLSD was not designed with recursion in
+ mind. (Breadth-first traversal could be problematic due to lack of
+ sufficient navigation information.)
+
+ Of course all of Kermit's other MGET switches can be used too, e.g. for
+ finer-grained file selection (by date, size, etc), for moving or
+ renaming files as they arrive, to override Kermit's automatic per-file
+ text/binary mode switching, to pass the incoming files through a
+ filter, to convert text-file character sets, and so on.
+
+3.11.4.4. NLST/MLSD Summary Table
+
+ Here's a table summarizing MGET behavior when the server supports both
+ NLST and MLSD. /NLST and /MLSD switches are included for clarity to
+ indicate which protocol is being used, and the expected effects. In
+ practice you can omit the /NLST and /MLSD switches and the Kermit
+ client chooses the appropriate or desired protocol as described above.
+ Sample commands presume a Unix file system on the server, but of course
+ the server can have any file system or syntax at all.
+
+ User's Command FTP Sends Remarks
+ mget /nlst NLST Gets a list of all the files in the server's current
+ and downloads each file. The list includes names only, so Kermit also
+ must send SIZE and MDTM directives if size and timestamp information is
+ required (this is always true of NLST). Sending NLST without an
+ argument is allowed by the RFC959 NLST definition and by the Kermit FTP
+ client, but might not work with other clients, and also might not work
+ with every server.
+ mget /nlst foo NLST foo If "foo" is a directory, this gets a list of
+ all the files from the server's "foo" directory and downloads each
+ file; otherwise this downloads the file named "foo" (if any) from the
+ server's current directory.
+ mget /nlst *.txt NLST *.txt Gets a list of the files in the server's
+ current directory whose names match the pattern *.txt, and then
+ downloads each file from the list. Because we are using NLST, we send
+ the filespec (*.txt) to the server and the server interprets any
+ wildcards.
+ mget /nlst foo/*.txt NLST foo/*.txt Gets a list of the files in the
+ server's "foo" directory whose names match the pattern *.txt, and then
+ downloads each file from the list (server interprets wildcards).
+ mget /nlst /match:*.txt NLST Gets a list of all the files in the
+ server's current directory and then downloads each one whose name
+ matches the pattern *.txt (client interprets wildcards).
+ mget /nlst /match:*.txt foo NLST foo Gets a list of all the files in
+ the server's "foo" directory and then downloads each one whose name
+ matches the pattern *.txt (client interprets wildcards).
+ mget /mlsd MLSD Gets a list of all the files from the server's current
+ directory and then downloads each one. The list might include size and
+ timestamp information, in which case Kermit does not need to send SIZE
+ and MDTM directives for each file (this is always true of MLSD).
+ mget /mlsd foo MLSD foo Gets a list of all the files from the server's
+ "foo" directory (where the string "foo" does not contain wildcards) and
+ then downloads each one. If "foo" is a regular file and not a
+ directory, this command is supposed to fail, but some servers have been
+ observed that send the file.
+ mget /mlsd *.txt MLSD Gets a list of all the files from the server's
+ current directory and then downloads only the ones whose names match
+ the pattern "*.txt". Because we are using MLSD and the MGET filespec is
+ wild, we do not send the filespec to the server, but treat it as though
+ it had been given in a /MATCH: switch and use it locally to match the
+ names in the list.
+ mget /mlsd foo/*.txt MLSD This one won't work because MLSD requires
+ that the notions of server directory and filename-matching pattern be
+ separated. However, the client, which can't be expected to know the
+ server's file-system syntax, winds up sending a request that the server
+ will (or should) reject.
+ mget /mlsd /match:*.txt MLSD Gets a list of all the files from the
+ server's current directory and then downloads only the ones whose names
+ match the pattern "*.txt" (client interprets wildcards).
+ mget /mlsd /match:*.txt foo MLSD foo If "foo" is a directory on the
+ server, this gets a list of all the files from the server's "foo"
+ directory and then downloads only the ones whose names match the
+ pattern "*.txt" (client interprets wildcards). This leaves the server
+ CD'd to the "foo" directory; there's no way the client can restore the
+ server's original directory because MLSD doesn't give that information,
+ and since the client can not be expected to know the server's
+ file-system syntax, it would not be safe to guess. If "foo" is a
+ regular file, MLSD fails.
+ mget /mlsd foo bar MLSD This one is problematic. You're supposed to be
+ able to give MGET a list a filespecs; in this case we name two
+ directories. The client must change the server's directory to "foo" to
+ get the list of files, and then the files themselves. But then it has
+ no way to return to the server's previous directory in order to do the
+ same for "bar", as explained in the previous example.
+ mget /mlsd /match:* [abc] MLSD [abc] Including a /MATCH: switch forces
+ [abc] to be sent to the server even though the client would normally
+ think it was a wildcard and hold it for local interpretation. In this
+ example, [abc] might be a VMS directory name.
+ mget /mlsd /match:* t*.h MLSD t*.h Contrary to the MLSD specification,
+ some MLSD-capable FTP servers do interpret wildcards. This form of the
+ MGET command can be used to force a wildcard to be sent to the server
+ for interpretation.
+
+ When MLSD is used implicitly (that is, without an /MLSD switch given to
+ force the use of MLSD) and an MGET command such as "mget foo/*.txt"
+ fails, Kermit automatically falls back to NLST and tries again.
+
+3.11.5. References
+
+ 1. Postel, J., and J. Reynolds, File Transfer Protocol (FTP), RFC 959,
+ October 1985: [372]ftp://ftp.isi.edu/in-notes/rfc959.txt.
+ 2. Hethmon, P, and R. Elz, Feature negotiation mechanism for the File
+ Transfer Protocol, RFC 2389, August 1998:
+ [373]ftp://ftp.isi.edu/in-notes/rfc2389.txt.
+ 3. Elz, R, and P. Hethmon, Extensions to FTP, Internet Draft
+ draft-ietf-ftpext-mlst-16.txt, September 2002:
+ [374]http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.
+ txt.
+ 4. [375]The Kermit FTP Client (overview).
+
+ [ [376]Top ] [ [377]FTP Top ] [ [378]C-Kermit Home ] [ [379]Kermit Home
+ ]
+
+4. FILE SCANNING
+
+ A new feature called file scanning is used in various contexts to
+ determine if a file is text or binary, and if it is text, what kind of
+ text. The overhead of file scanning is surprisingly tolerable, usually
+ about a quarter second per file. File scanning is now used instead of
+ filename patterns unless you SET FILE SCAN OFF, which restores the
+ previous behavior.
+
+ The primary benefit of file scanning is in file transfer. For all
+ practical purposes, now you can stop worrying about whether a file
+ should be sent in binary or text mode, or about sending mixtures of
+ text and binary files in a single operation, or configuring and
+ fine-tuning your lists of binary-file and text-file name patterns: now
+ it all just works.
+
+ File scanning is done by the file sender, which determines the type of
+ each file before it sends it and informs the receiver (Kermit or FTP
+ server) of the type. File scanning is NOT done by the receiver, because
+ it is the sender's responsibility to determine each file's type, send
+ the file in the right mode, and inform the receiver of the mode. If
+ both transfer partners are capable of this (or any other) form of
+ automatic text/binary mode switching, then files can be sent in both
+ directions with no worries about corruption due to inappropriate
+ transfer mode. (As noted in [380]Section 3, FTP servers don't do this,
+ so this discussion does not apply when using Kermit to download from an
+ FTP server.)
+
+ The rest of this section is mainly for the curious. If you don't read
+ it and simply accept all defaults, every file you send should go in the
+ appropriate mode automatically. As always, however, for character-set
+ translation to work for 7- and 8-bit character-set files, the
+ appropriate SET FILE CHARACTER-SET command(s) must have been executed
+ to identify their encoding (Kermit's default file character-set is
+ neutral ASCII except on platforms like HP-UX or DG/UX, where the
+ default file character-set is known). And of course, receiving is
+ another matter -- obviously the other Kermit must also send each file
+ in the appropriate mode.
+
+ Scanning is more reliable than filename patterns simply because
+ filenames are not reliable indicators of the file's contents. Classic
+ examples include ".doc" files, which are binary if Microsoft Word
+ documents but text on most other platforms, and ".com" files, which are
+ binary on DOS and Windows but text on VMS. Anyway, nobody knows the
+ naming conventions (if any) of all the applications (and persons!) on
+ your computer. Scanning, on the other hand, determines each file's type
+ by inspecting its contents rather than just looking at its name.
+
+ Also, file patterns -- even when they work as intended -- categorize
+ each file only as text or binary, whereas file scanning can make finer
+ distinctions:
+
+ BINARY
+ Binary data, not to be converted in any way. Examples include
+ binary machine code (executable programs), graphics images (GIF,
+ JPG, etc), compressed files (Z, GZ, etc), archives and packages
+ (ZIP, TAR, RPM, etc), object files and libraries (OBJ, DLL,
+ etc).
+
+ 7-BIT TEXT
+ Text encoded in a 7-bit character set such as ASCII or one of
+ the ISO 646 national versions. Kermit has no way to tell which
+ character is used, only that it's 7-bit text. Typical examples
+ include program source code, README files, Perl or Kermit
+ scripts, plain-text email, HTML, TeX, and various textual
+ encodings of binary files: Hex, Base64, etc. When sending such
+ files, the FILE DEFAULT 7BIT-CHARACTER-SET is used as the file
+ character-set, and then the appropriate transfer character set
+ is chosen from the associations list (ASSOCIATE, SHOW
+ ASSOCIATIONS).
+
+ 8-BIT TEXT
+ Text encoded in an 8-bit character set such as Latin-1, Latin-2,
+ Latin/Hebrew, Latin/Cyrillic, KOI8, HP-Roman8, JIS X 0208, Code
+ Page 437, or Code Page 1252. Again, Kermit has no way of knowing
+ which particular set is in use, only that it's 8-bit text. When
+ sending such files, the FILE DEFAULT 8BIT-CHARACTER-SET is used
+ as the file character-set, and then the appropriate transfer
+ character set is chosen from the associations list.
+
+ UCS2 TEXT
+ Unicode in its basic form, 16 bits (2 octets) per character.
+ When sending such files, UCS2 is the file character-set and the
+ byte order is identified automatically; the appropriate transfer
+ character set is chosen from the associations list. Normally
+ this would be UTF8. UTF-16 is not supported yet; Kermit's
+ Unicode translations are restricted to Plane 0, the Base
+ Multilingual Plane (BMP).
+
+ UTF8 TEXT
+ Unicode in its 8-bit transformation format. When sending such
+ files, UTF8 is the file character-set; the appropriate transfer
+ character set is chosen from the associations list, normally
+ UCS2 or UTF8.
+
+ File scanning is available in UNIX C-Kermit, in K-95, and to a limited
+ extent, in VMS C-Kermit (full scanning is problematic in VMS because
+ even plain-text files might contain binary record-format information).
+ The relevant commands are:
+
+ SET TRANSFER MODE { AUTOMATIC, MANUAL }
+ Tells whether the file-transfer mode (text or binary) should be
+ set by automatic or "manual" means. AUTOMATIC is the default,
+ which allows any of the automatic methods that are enabled to do
+ their jobs: FILE SCAN, FILE PATTERNS, peer recognition, etc.
+ MANUAL lets you control the transfer mode with the SET FILE TYPE
+ commands. As always, /TEXT and /BINARY switches on your
+ file-transfer commands override all other methods; if you give
+ one of these switches, scanning is not done. SHOW TRANSFER
+ displays the current TRANSFER MODE setting.
+
+ SET FILE SCAN { ON [ number ], OFF }
+ Turns this feature on and off. It's ON by default. When OFF, the
+ previous rules apply (SET FILE PATTERNS, etc). When ON is given,
+ you can also specify a number of bytes to be scanned. The
+ default is 49152 (= 48K). If a negative number is given, the
+ entire file is scanned, no matter how big, for maximum certainty
+ (for example, a PostScript file that appears to be plain text
+ might include an embedded graphic past the normal scanning
+ limit). SHOW FILE displays the current FILE SCAN setting.
+
+ SET FILE DEFAULT 7BIT-CHARACTER-SET name
+ Tells the 7-bit character-set to use if scanning identifies a
+ 7-bit text file, e.g. GERMAN. SHOW FILE displays the current SET
+ FILE DEFAULT settings. So does SHOW CHARACTER-SETS.
+
+ SET FILE DEFAULT 8BIT-CHARACTER-SET name
+ Tells the 8-bit character-set to use if scanning identifies an
+ 8-bit text file, e.g. LATIN1. SHOW FILE and SHOW CHARACTER-SET
+ display this.
+
+ ASSOCIATE FILE-CHARACTER-SET fcs tcs
+ When sending files and a file character-set (fcs) is identified
+ by scanning, this tells C-Kermit which transfer character-set
+ (tcs) to translate it to. It also allows C-Kermit to set the
+ appropriate transfer character-set automatically whenever you
+ give a SET FILE CHARACTER-SET command.
+
+ ASSOCIATE TRANSFER-CHARACTER-SET tcs fcs
+ When receiving files and a file arrives whose transfer
+ character-set (tcs) is announced by the sender, this command
+ tells C-Kermit which file character-set (fcs) to translate it
+ to. It also allows C-Kermit to set the appropriate file
+ character-set whenever you give a SET TRANSFER CHARACTER-SET
+ command.
+
+ SET FILE CHARACTER-SET name
+ When given for a 7-bit set, also sets FILE DEFAULT
+ 7BIT-CHARACTER-SET to the same set. When given for an 8-bit set,
+ also sets FILE DEFAULT 8BIT-CHARACTER-SET to the same set. If an
+ ASSOCIATE FILE-CHARACTER-SET command has been given for this
+ set, also sets the corresponding transfer character-set.
+
+ DIRECTORY /XFERMODE [ filespec ]
+ Performs a file scan of the given files, listing the result for
+ each file. If FILE SCAN is OFF but PATTERNS are ON, the result
+ shown according to the current FILE TEXT-PATTERNS and
+ BINARY-PATTERNS, and are restricted to (B) and (T). When FILE
+ SCAN is ON, the results are:
+
+ (B) Binary
+ (T)(7BIT) Text: 7-bit
+ (T)(8BIT) Text: 8-bit
+ (T)(UTF8) Text: Unicode UTF8
+ (T)(UCS2BE) Text: Unicode UCS2 Big Endian
+ (T)(UCS2LE) Text: Unicode UCS2 Little Endian
+
+ So you can use DIR /XFER to get a preview of how each file in a
+ selected group will be transferred. Everything to the right of
+ the (B) or (T) is new. If FILE SCAN is OFF, you only get the (B)
+ or (T) as before.
+
+ Note: Big and Little Endian refer to the ordering of bytes
+ within a computer word. Big Endian architecture is standard and
+ is used on most non-PC computers. Little Endian architecture is
+ used on PCs.
+
+ To illustrate file-transfer with scanning, suppose you have a directory
+ containing a mixture of text and binary files, and each text file can
+ be 7-bit German ISO 646, 8-bit Latin-1, or Unicode in any of the
+ following forms: UCS2 Little Endian, UCS2 Big Endian, or UTF8
+ ([381]UTF-16 is not supported yet). Assuming all the built-in defaults
+ are in effect, the following three commands do the job:
+
+ set file char german ; This sets the default for 7-bit text files
+ set file char latin1 ; This sets the default for 8-bit text files
+ send *
+
+ Each file is sent in the appropriate mode (text or binary), with text
+ files converted to the appropriate transfer character-set and labeled
+ so the receiver can convert them according to its own local
+ conventions.
+
+ By the way, what if you want to inhibit character-set translation but
+ still allow automatic text/binary mode switching? Previously, you could
+ simply SET TRANSFER CHARACTER-SET TRANSPARENT. But now with file
+ scanning, the file and transfer character-sets are set automatically
+ per file. A new command was added for this purpose:
+
+ SET TRANSFER TRANSLATION { ON, OFF }
+ Enables and disables file-transfer character-set translation. It
+ is enabled by default.
+
+ When TRANSFER TRANSLATION is OFF but FILE SCAN is ON, files are still
+ scanned to see if they are text or binary, but no character-set
+ translation is done when they text: only the normal record-format
+ conversion.
+
+ Like all SET commands, SET TRANSFER TRANSLATION is global and
+ persistent. You can also force a particular file-transfer command
+ (SEND, MSEND, GET, RECEIVE, TRANSMIT, etc) to not translate without
+ affecting the global translation settings by including the new
+ /TRANSPARENT switch, e.g.
+
+ send /transparent oofa.txt
+
+ As of C-Kermit 8.0.206, SET TRANSFER CHARACTER-SET TRANSPARENT implies
+ SET TRANSFER TRANSLATION OFF.
+
+ File scanning is also used in the TYPE command. The source file type
+ and character set are determined as above, and then the file is
+ automatically converted to your display character-set, line by line. In
+ Kermit 95, the display character-set is Unicode, perhaps converted to
+ your current console code page; in other versions of C-Kermit, it is
+ your current file character-set. Thus if you have the following set
+ appropriately:
+
+ SET FILE CHARACTER-SET (necessary in Unix but not K95)
+ SET FILE DEFAULT 7BIT CHARACTER-SET
+ SET FILE DEFAULT 8BIT CHARACTER-SET
+
+ then you should be able to TYPE any text file and see something
+ reasonable. For example, in Unix, if your DEFAULT 7BIT-CHARACTER-SET is
+ ITALIAN and your DEFAULT 8BIT-CHARACTER-SET is LATIN1, and your FILE
+ CHARACTER-SET is LATIN1, you can TYPE an Italian ISO 646 file, a
+ Latin-1 file, or any kind of Unicode file, and have it translated
+ automatically to Latin-1 for your display.
+
+ In the GUI version of Kermit 95, you can see mixtures of many different
+ scripts if the file is UTF8 or UCS2: Roman, Cyrillic, Hebrew, Greek,
+ Armenian, Georgian, etc, all on the same screen at once.
+
+ File scanning also adds a new criterion for file selection, i.e. to
+ select only text (or binary) files. Several commands now include a new
+ switch, /TYPE:{BINARY,TEXT,ALL}. BINARY means select only binary
+ regular files (not directories). TEXT means select only text files. ALL
+ means don't scan; select all files. Examples:
+
+ SEND /TYPE:BINARY *.*
+ Sends only binary files, skipping over text files.
+
+ NOTE: File scanning is NOT done when using external protocols (because
+ the external protocol programs, such as sz, are processing each file,
+ not Kermit).
+
+ DIRECTORY /TYPE:TEXT
+ Lists only text files but not binary files.
+
+ DELETE /TYPE:BINARY foo.*
+ Deletes all foo.* files that are regular binary files but does
+ not delete any text files.
+
+ CHMOD /TYPE:BINARY 775 *
+ (UNIX) Changes the permissions of all binary files to 775.
+
+ When FILE SCAN is OFF and FILE PATTERNS are ON, behavior is as before
+ with PATTERNS ON, but with some improvements:
+
+ * Pathnames are now stripped prior to pattern matching.
+ * Backup suffixes (like .~3~) are stripped prior to pattern matching.
+
+ [ [382]Top ] [ [383]Contents ] [ [384]C-Kermit Home ] [ [385]Kermit
+ Home ]
+
+5. FILE AND DIRECTORY NAMES CONTAINING SPACES
+
+ Prior to the introduction of the graphical user interface (GUI), it was
+ inconceivable that file or directory names could contain spaces,
+ because space is a field delimiter in all command languages. GUIs,
+ however, use dialog boxes for filenames, so there is never any question
+ of distinguishing a filename from adjacent fields -- because there are
+ no adjacent fields -- and therefore it has become quite common on
+ computers that have GUIs to have file and directory names composed of
+ multiple words. Of course this poses problems for command shells and
+ other text-oriented programs.
+
+ Most command shells address these problems by allowing such names to be
+ enclosed in doublequotes, e.g.:
+
+ cd "c:\Program Files"
+
+ C-Kermit previously used braces for this:
+
+ cd {c:\Program Files}
+
+ which was not what most people expected. And even when braces were
+ used, Kermit had difficulties with completion, file menus, and so
+ forth, within braced fields.
+
+ C-Kermit 8.0 allows either doublequotes or braces to be used for
+ grouping:
+
+ send "this file"
+ send {this file}
+ rename "this file" "that file"
+ rename {this file} "that file"
+ rename "this file" {that file}
+ cd {Program Files}
+ cd "Program Files"
+
+ Note that the doublequotes or brackets must enclose the whole file or
+ directory specification:
+
+ "c:\My Directory"
+
+ not:
+
+ c:\"My Directory"
+
+ In C-Kermit 8.0, you can also use completion on these filenames, in
+ which case Kermit supplies the quotes (or braces) automatically.
+ Example (in which the current directory contains only one file whose
+ name starts with "th" and its full name is "this file" (without the
+ quotes, but with the space)):
+
+ cat th<Tab>
+
+ Kermit repaints the filename field like this:
+
+ cat "this file"
+
+ That is, it backspaces over the original "th" and then writes the
+ filename in doublequotes.
+
+ If completion is only partial, Kermit still supplies the quotes, but in
+ this case also beeps. To continue the filename, you must first
+ backspace over the closing quote. The closing quote is supplied in this
+ case to make sure that you can see the spaces, especially if they are
+ trailing. For example, if the current directory contains two files
+ whose names start with "th", and their fill names are "this file" and
+ "this other file":
+
+ cat th<Tab>
+
+ Kermit prints:
+
+ cat "this "<Beep>
+
+ If it didn't print the closing quote, you would probably wonder why it
+ was beeping.
+
+ Also, if you begin a filename field with a doublequote or opening
+ brace, now you can use completion or get ?-help; this was never
+ possible before.
+
+ C-Kermit>type "thi? Input file specification, one of the following:
+ this file this other file
+ C-Kermit>type "thi_
+
+ [ [386]Top ] [ [387]Contents ] [ [388]C-Kermit Home ] [ [389]Kermit
+ Home ]
+
+6. OTHER COMMAND PARSING IMPROVEMENTS
+
+6.1. Grouping Macro Arguments
+
+ Doublequotes now can be used in macro invocations to group arguments
+ containing spaces, where previously only braces could be used:
+
+ define xx show args
+ xx one "this is two" three
+
+ Result:
+
+ Macro arguments at level 0 (\v(argc) = 4):
+ \%0 = xx
+ \%1 = one
+ \%2 = this is two
+ \%3 = three
+
+ Also, you can now quote braces and quotes in macro args (this didn't
+ work before). Examples:
+
+ xx "{" ; The argument is a single left brace
+ xx {"} ; The argument is a doublequote character
+
+ In case this new behavior interferes with your scripts, you can restore
+ the previous behavior with:
+
+ SET COMMAND DOUBLEQUOTING OFF
+
+6.2. Directory and File Name Completion
+
+ C-Kermit 8.0 also includes better completion for directory names, e.g.
+ in the CD command. If the name typed so far uniquely matches a
+ directory name, it is completed (as before), but now if the directory
+ contains any subdirectories, completion is partial (allowing you to
+ supply additional path segments without backspacing); otherwise it is
+ complete.
+
+ Completion has also been improved for file and directory names that
+ contain not only spaces (as described above) but also "metacharacters"
+ such as asterisk (*) and tilde (~): now the field is repainted if
+ necessary. For example, if the current directory contains only one file
+ whose name contains "blah", then in:
+
+ type *blah<Tab>
+
+ "*blah" is replaced by the filename. In earlier releases, the part
+ typed so far was left on the command line (and in the history buffer),
+ so even when the original command worked, the recalled version would
+ not. Similarly for ~ (the nearly-universal Unix notation for username):
+
+ type ~olga/x<Tab>
+
+ is repainted as (e.g.):
+
+ type /users/home/olga/x(Beep)
+
+ Speaking of command history, the new SHOW HISTORY command shows your
+ command history and recall buffer. SAVE COMMAND HISTORY saves it into a
+ file of your choice.
+
+6.3. Passing Arguments to Command Files
+
+ The method for passing arguments to command files has been improved.
+ Prior to C-Kermit 7.0 there was no provision for doing this. In
+ C-Kermit 7.0, the TAKE command was changed to allow arguments to be
+ given after the filename:
+
+ take commandfile arg1 arg2 ...
+
+ This was accomplished by replacing the current \%1, \%2, etc, with the
+ given arguments, since a new set of macro argument variables is created
+ only when a macro is executed, not a command file. It is much more
+ intuitive, however, if arguments to command files worked like those to
+ macros: the command file sees the arguments as its own \%1, \%2, etc,
+ but the caller's variables are not disturbed. C-Kermit 8.0 accomplishes
+ this by automatically creating an intermediate temporary macro to start
+ the command file (if any arguments were given), thus creating a new
+ level of arguments as expected.
+
+6.4. More-Prompting
+
+ The familiar --more?-- prompt that appears at the end of each screenful
+ of command-response output now accepts a new answer: G (Go) meaning
+ "show all the rest without pausing and asking me any more questions". P
+ (Proceed) is a synonym for G.
+
+6.5. Commas in Macro Definitions
+
+ As noted in the [390]C-Kermit manual, comma is used to separate
+ commands in a macro definition. Even when the macro is defined on
+ multiple lines using curly-brace block-structure notation without
+ commas, the definition is still stored internally as a comma-separated
+ list of commands. Therefore special tricks are needed to include a
+ comma in a command. The classic example is:
+
+ define foo {
+ (some command)
+ if fail echo Sorry, blah failed...
+ }
+
+ This would result in Kermit trying to execute a "blah" command. This
+ could always be handled by enclosing the text in braces:
+
+ define foo {
+ (some command)
+ if fail echo {Sorry, blah failed...}
+ }
+
+ but doublequotes (more intuitive) should have worked too. Now they do:
+
+ define foo {
+ (some command)
+ if fail echo "Sorry, blah failed..."
+ }
+
+6.6. Arrow Keys
+
+ As of version 8.0.201, C-Kermit on most platforms lets you access the
+ command history buffer with arrow keys, just as you always could with
+ control characters. The restrictions are:
+
+ 1. Only Up and Down arrow keys are accepted.
+ 2. Only 7-bit ANSI arrow-key sequences are understood (ESC followed by
+ [ or uppercase letter O, followed by uppercase letter A or (up) B
+ (down).
+
+ This change was made to facilitate command recall in Linux-based PDAs
+ that don't have a Control key, or at least not one that's easily (or
+ always) accessible, such as the Sharp Zaurus SL5500.
+
+ [ [391]Top ] [ [392]Contents ] [ [393]C-Kermit Home ] [ [394]Kermit
+ Home ]
+
+7. NEW COMMANDS AND SWITCHES
+
+ See [395]Section 4 for more about file scanning and the /TYPE: switch.
+
+ ASK[Q] [ /TIMEOUT:number /QUIET /DEFAULT:text ] variable [ prompt ]
+ The new optional /TIMEOUT: switch for ASK and ASKQ causes the
+ command to time out and and fail if no response is given within
+ the specified number of seconds, 1 or greater (0 or less means
+ no timeout, wait forever). This works just like SET ASK-TIMER,
+ except its effect is local to the ASK command with which it is
+ given and it does not disturb the global ask timer setting. The
+ new /QUIET switch tells Kermit not to print an error message if
+ the ASK or ASKQ command times out waiting for a response.
+
+ Version 8.0.211 adds the /DEFAULT:text switch for ASK-Class
+ commands (ASK, ASKQ, and GETOK). This lets you supply a default
+ answer in case the user supplies an empty answer or the
+ /TIMEOUT: switch was included and the time limit expired without
+ an answer. In both these cases, the command succeeds.
+
+ CAT filename
+ Equivalent to TYPE /NOPAGE.
+
+ CDUP
+ Changes Kermit's local working directory to the parent of the
+ current one. Equivalent to "cd .." in UNIX or Windows, "cd [-]"
+ in VMS, "cd ^" in AOS/VS, etc; in other words, it's a
+ platform-independent way of moving one level up in a directory
+ tree.
+
+ CHMOD [ switches ] permission files
+ UNIX only. Sets file permissions for one or more files or
+ directories. The permission must be given as an octal number,
+ e.g. 664, 755. Switches: /DIRECTORIES, /FILES, /NOLIST, /PAGE,
+ /DOTFILES, /LIST, /NOPAGE, /RECURSIVE, /TYPE:{TEXT,BINARY,ALL},
+ /SIMULATE. The /TYPE: switch allows selection of only text or
+ binary files. For example, if you have a mixture of source files
+ and executables, you can use "chmod /files /type:text 664" to
+ give owner/group read/write and world read permission to the
+ text files, and "chmod /files /type:binary 775" to give the same
+ plus execute permission to the executables. Use /SIMULATE to see
+ which files would be affected, without actually changing their
+ permissions.
+
+ CLEAR KEYBOARD-BUFFER
+ Flushes any as-yet unread characters from the keyboard input
+ buffer. Useful for flushing typeahead in scripts.
+
+ CONTINUE
+ When given at an interactive command prompt that was reached by
+ issuing a PROMPT command (described in this section) from a
+ script, this command returns to the script, continuing its
+ execution at the command after the PROMPT command. In this
+ context, CONTINUE is simply a more-intuitive synonym for END.
+
+ COPY, RENAME, and TRANSLATE
+ These commands now work on file groups if the target filename is
+ a directory, e.g. "copy oofa.* ..", "rename * ~olga/tmp/"
+
+ COPY /APPEND source destination
+ The source file specification can now include wildcards, in
+ which case all of the source files that match will go into the
+ destination file in alphabetical order by name.
+
+ DELETE /ASK
+ Asks permission to delete each file before deleting it. In
+ C-Kermit 7.0, the answers were "yes" (or "ok") and "no".
+ C-Kermit 8.0 adds "go" (meaning, delete all the rest without
+ asking) and "quit" (cancel the DELETE command and return to the
+ prompt).
+
+ DELETE /DIRECTORIES
+ Deletes not only files but also directories.
+
+ DELETE /RECURSIVE
+ Deletes all files that match the given file specification in the
+ current (or given) directory and all directories beneath it.
+
+ DELETE /SUMMARY
+ Prints only the number of files deleted and total size freed,
+ without listing each file.
+
+ DELETE /TREE
+ Shorthand for DELETE /RECURSIVE /DIRECTORIES /DOTFILES/.
+ Equivalent to Windows DELTREE or Unix "rm -Rf". If no file
+ specification is given, the contents of the current directory,
+ plus all of its subdirectories and their contents, are deleted.
+
+ DELETE /TYPE:BINARY
+ Delete only regular binary files (requires FILE SCAN ON).
+
+ DELETE /TYPE:TEXT
+ Delete only regular text files (requires FILE SCAN ON).
+
+ DIRECTORY [ switches ] [ filespec [ filespec [ filespec ... ] ] ]
+ The DIRECTORY command now accepts more than one file
+ specification; e.g. "directory moon.txt sun.doc stars.*".
+
+ DIRECTORY /NORECURSIVE xxx
+ If xxx is a directory name, forces listing of the directory
+ itself rather than its contents.
+
+ DIRECTORY /FOLLOWLINKS xxx
+ (UNIX only) Tells the DIRECTORY command to follow symbolic
+ links. This not the default because it can cause endless loops.
+
+ DIRECTORY /NOFOLLOWLINKS xxx
+ (UNIX only) Tells the DIRECTORY command not to follow symbolic
+ links, but rather, merely to list them. This is the default.
+
+ DIRECTORY /OUTPUT:filename
+ Sends the results of the DIRECTORY command to the given file.
+
+ DIRECTORY /SUMMARY
+ Prints only the number of directories and files and the total
+ size, without listing each file.
+
+ DIRECTORY /TYPE:{TEXT,BINARY}
+ Shows only files of the selected type, based on file scan.
+
+ DIRECTORY /XFERMODE
+ Now shows results of file scan (see [396]Section 4).
+
+ FOPEN [ switches ] channel filename
+
+ As of version 8.0.211, FOPEN allows /dev/tty as a filename in
+ Unix-based operating systems.
+
+ FREAD /TRIM
+ (8.0.211) Trims any trailing blanks or tabs from the item (such
+ as a line of text) that it has read.
+
+ FREAD /UNTABIFY
+ (8.0.211) Converts Horizontal Tab characters to the appropriate
+ number of spaces, based on VT100-like tab stops (1,9,17,25,...).
+
+ GREP [ switches ] pattern files
+ Similar to Unix grep command: displays file lines that match the
+ given [397]pattern. Switches:
+
+ /COUNT[:variable]
+ Don't show the matching lines, just tell how many lines
+ match. If a variable name is specified, the count is
+ stored in the given variable.
+
+ /DOTFILES
+ Include files whose names begin with dot.
+
+ /LINENUMBERS
+ Show line numbers of matching lines.
+
+ /NAMEONLY
+ only list the names of files that contain matching lines,
+ but not the lines themselves.
+
+ /NOBACKUP
+ Skip backup files.
+
+ /NOCASE
+ Ignore alphabetic case while pattern matching.
+
+ /NODOTFILES
+ skip files whose names start with dot (period).
+
+ /NOLIST
+ Suppress output but set SUCCESS or FAILURE according to
+ search result.
+
+ /NOMATCH
+ Look for lines that do not match the pattern.
+
+ /NOPAGE
+ Don't pause between screens of output.
+
+ /OUTPUT:filename
+ Write results into the given file.
+
+ /PAGE
+ Pause between screens of output.
+
+ /RECURSIVE
+ Search files in subdirectories too.
+
+ /TYPE:{TEXT,BINARY}
+ Search only files of the specified type.
+
+ Synonyms: FIND, SEARCH.
+
+ GETOK /TIMEOUT:n /QUIET /DEFAULT:text
+ The new /QUIET switch instructs GETOK, when given a timeout, not
+ to print an error message if it times out. As of 8.0.211, a
+ default answer can be supplied (see ASK).
+
+ HEAD [ switches ] filename
+ Equivalent to TYPE /HEAD [ other-switches ] filename.
+
+ HELP DATE
+ Explains date-time formats, including timezone notation and
+ delta times.
+
+ HELP FIREWALLS
+ Explains the firewall negotiation capabilities of your version
+ of Kermit.
+
+ KCD [ symbolic-directory-name ]
+ Changes Kermit's working directory to the named symbolic
+ directory, such as such as exedir, inidir, startup, download, or
+ and home. Type "kcd ?" for a list of symbolic directory names
+ known to your copy of Kermit, or give the new ORIENTATION
+ command for a more detailed explanation. If you give a KCD
+ command without a directory name, Kermit returns to its "home"
+ directory, which is determined in some way that depends on the
+ underlying operating system, but which you can redefine with the
+ (new) SET CD HOME command. Your home directory is shown by SHOW
+ CD and it's also the value of the \v(home) variable.
+
+ LICENSE
+ Displays the C-Kermit license.
+
+ L-commands
+ When Kermit has a connection to a Kermit or FTP server, file
+ management commands such as CD, DIRECTORY, and DELETE might be
+ intended for the local computer or the remote server. C-Kermit
+ 8.0.200 and earlier always executes these commands on the local
+ computer. If you want them executed by the remote server, you
+ have to prefix them with REMOTE (e.g. REMOTE CD) or use special
+ R-command aliases (e.g. RCD = REMOTE CD, RDIR = REMOTE DIR,
+ etc). But this feels unnatural to FTP users, who expect
+ unprefixed file management commands to be executed by the remote
+ server, rather than locally. C-Kermit 8.0.201 adds automatic
+ locus switching to present an FTP-like interface for FTP
+ connections and the normal Kermit interface for Kermit
+ connections, and a SET LOCUS command (described below) to
+ control whether or how this is done. For when LOCUS is REMOTE, a
+ new set of commands was added for local management: LCD (Local
+ CD), LDIR (Local DIR), etc. These are described below under SET
+ LOCUS.
+
+ MORE filename
+ Equivalent to TYPE /PAGE.
+
+ ORIENTATION
+ Displays symbolic directory names and the corresponding variable
+ names and values. The symbolic names, such as exedir, inidir,
+ startup, download, and home, can be used as arguments to the new
+ KCD command.
+
+ PROMPT [ text ]
+ For use in a macro or command file: enters interactive command
+ mode within the current context ([398]Section 8.1). If the
+ optional text is included, the prompt is set to it. The text can
+ include variables, functions, etc, as in the SET PROMPT command.
+ They are evaluated each time the prompt is printed. Unlike the
+ SET PROMPT command, the text argument applies only to the
+ current command level. Thus you can have different prompts at
+ different levels.
+
+ REMOTE SET MATCH { DOTFILE, FIFO } { ON, OFF }
+ Allows the client to tell the server whether wildcards sent to
+ the server should match dot files (files whose names begin with
+ period) or FIFOs (named pipes). See SET MATCH.
+
+ SET ATTRIBUTE RECORD-FORMAT { ON, OFF }
+ Allows control of the Kermit's Record-Format attribute. Set this
+ to OFF in case incoming file are refused due to unknown or
+ invalid record formats if you want to accept the file anyway
+ (and, perhaps, postprocess it to fix its record format).
+
+ SET CD HOME [ directory ]
+ Specifies the target directory for the CD and KCD commands, when
+ they are given without an argument, and also sets the value of
+ the \v(home) variable.
+
+ SET EXIT HANGUP { OFF, ON }
+ Normally ON, meaning that when Kermit exits, it also explicitly
+ hangs up the current SET LINE / SET PORT serial port according
+ to the current SET MODEM TYPE and SET MODEM HANGUP METHOD, and
+ closes the port device if it was opened by Kermit in the first
+ place (as opposed to inherited). SET EXIT HANGUP OFF tells
+ Kermit not to do this. This can't prevent the operating system
+ from closing the device when Kermit exits (and it's a "last
+ close") but if the port or modem have been conditioned to
+ somehow ignore the close and keep the connection open, at least
+ Kermit itself won't do anything explicit to hang it up or close
+ it.
+
+ SET FILE EOF { CTRL-Z, LENGTH }
+ Specifies the end-of-file detection method to be used by
+ C-Kermit when sending and receiving text files, and in the TYPE
+ and similar text-file oriented commands. The normal and default
+ method is LENGTH. You can specify CTRL-Z when handling CP/M or
+ MS-DOS format text files, in which a Ctrl-Z (ASCII 26) character
+ within the file marks the end of the file.
+
+ SET FILE LISTSIZE number
+ Allocates space for the given number of filenames to be filled
+ in by the wildcard expander. The current number is shown by SHOW
+ FILE. If you give a command that includes a filename containing
+ a wildcard (such as "*") that matches more files that Kermit's
+ list has room for, you can adjust the list size with this
+ command.
+
+ SET FILE STRINGSPACE number
+ Allocates space for the given amount of filename strings for use
+ by the wildcard expander. The current number is shown by SHOW
+ FILE. The number is the total number of bytes of all the file
+ specifications that match the given wildcard.
+
+ If you need to process a bigger list of files than your computer has
+ memory for, you might be able use an external file list. The Kermit
+ SEND and the FTP PUT and GET commands accept a /LISTFILE: switch,
+ which gives the name of a file that contains the list of files to be
+ transferred. Example for UNIX:
+
+ !find . -print | grep / > /tmp/names
+ ftp put /update /recursive /listfile:/tmp/names
+
+ SET LOCUS { AUTO, LOCAL, REMOTE }
+ Added in C-Kermit 8.0.201. Sets the locus for unprefixed file
+ management commands such as CD, DIRECTORY, MKDIR, etc. When
+ LOCUS is LOCAL these commands act locally and a REMOTE (or R)
+ prefix (e.g. REMOTE CD, RCD, RDIR) is required to send file
+ management commands to a remote server. When LOCUS is REMOTE, an
+ L prefix is required to issue local file management commands
+ (e.g. LCD, LDIR). The word LOCAL can't be used as a prefix since
+ it is already used for declaring local variables. LOCUS applies
+ to all types of connections, and thus is orthogonal to SET
+ GET-PUT-REMOTE, which selects between Kermit and FTP for remote
+ file-transfer and management commands. The default LOCUS is
+ AUTO, which means we switch to REMOTE whenever an FTP connection
+ is made, and to LOCAL whenever a non-FTP connection is made, and
+ switch back accordingly whenever a connection is closed. So by
+ default, Kermit behaves in its traditional manner unless you
+ make an FTP connection, in which case it acts like a regular FTP
+ client (but better :-) LOCUS applies to the following
+ commands:
+
+ Unprefixed Remote Local Description
+ CD (CWD) RCD LCD Change (Working) Directory
+ CDUP RCDUP LCDUP CD Up
+ PWD RPWD LPWD Print Working Directory
+ DIRECTORY RDIR LDIR Request a directory listing
+ DELETE RDEL LDEL Delete (a) file(s)
+ RENAME RREN LREN Rename a file
+ MKDIR RMKDIR LMKDIR Create a directory
+ RMDIR RRMDIR LRMDIR Remove a directory
+
+ SET MATCH { DOTFILE, FIFO } { ON, OFF }
+ Whether C-Kermit filename patterns (wildcards) should match
+ filenames that start with dot (period), or (Unix only) FIFOs
+ (named pipes). The defaults are to skip dotfiles in Unix but
+ match them elsewhere, and to skip FIFOs. Applies to both
+ interactive use and to server mode, when the server receives
+ wildcards, e.g. in a GET command. Also see REMOTE SET MATCH.
+
+ SET OPTIONS DIRECTORY /DOTFILES
+ Now works for server listings too (UNIX only). Give this command
+ prior to having Kermit enter server mode, and then it will show
+ files whose names begin with dot (period) when sent a REMOTE
+ DIRECTORY command.
+
+ SET QUIET ON
+ (as well as the -q command-line option) Now applies also to:
+
+ + SET HOST connection progress messages.
+ + "Press the X or E key to cancel" file-transfer message.
+ + REMOTE CD response.
+ + REMOTE LOGIN response.
+
+ SET RECEIVE PERMISSIONS { ON, OFF }
+ Tells C-Kermit whether to set the permissions of incoming files
+ (received with Kermit protocol) from the permissions supplied in
+ the file's Attribute packet (if any). Normally ON. Also see SET
+ SEND PERMISSIONS.
+
+ SET ROOT directory
+ Like UNIX chroot, without requiring privilege. Sets the root for
+ file access, does not allow reference to or creation of files
+ outside the root, and can't be undone.
+
+ SET SEND PERMISSIONS { ON, OFF }
+ Tells C-Kermit whether to include file permissions in the
+ attributes it includes with each file when sending with Kermit
+ protocol. Also see SET RECEIVE PERMISSIONS.
+
+ SET TCP { HTTP-PROXY, SOCKS-SERVER } /USER:name /PASSWORD:text
+ These commands now allow specification of username and password.
+
+ SET TERMINAL . . .
+ (See [399]Section 12.)
+
+ SET TRANSFER MESSAGE [ text ]
+ Sets an initial text message to be displayed in the
+ file-transfer display. The transfer message is automatically
+ deleted once used, so must be set each time a message a desired.
+ Any variables in the message are evaluated at the time the SET
+ command is given. If the optional text is omitted, any transfer
+ message that is currently set is removed. Synonym: SET XFER MSG.
+ SHOW TRANSFER displays it if it has been set but not yet used.
+
+ SHOW COMMUNICATIONS
+ In C-Kermit 8.0, SHOW COMMUNICATIONS, when given in remote mode
+ (i.e. before any connection has been established), tells the
+ typical dialout device name for the particular platform on which
+ it's running (e.g. TXA0: for VMS, or /dev/cua0p0 for HP-UX). On
+ Unix platforms, it also tells the name of the lockfile
+ directory. This way, you have an idea of what the SET LINE
+ device name should look like, and if the SET LINE command fails,
+ you know the name of the directory or device that is protected
+ against you.
+
+ SHOW VARIABLES [ name [ name [ ... ] ] ]
+ In C-Kermit 8.0.201 you can request values of a list of built-in
+ (\v(xxx)) variables. Each name is a pattern, as before, but now
+ it a free pattern rather than an anchored one (explained in
+ [400]Section 8.12) so now "show var date time" shows the values
+ of all variables whose names include the strings "date" or
+ "time".
+
+ TAIL [ switches ] filename
+ Equivalent to TYPE /TAIL [ other-switches ] filename.
+
+ TRANSMIT /NOECHO [ other switches ] filename
+ The /NOECHO switch is equivalent to giving the command SET
+ TRANSMIT ECHO OFF prior to the TRANSMIT command, except the
+ switch affects only the command with which it was given and does
+ not affect the prevailing global setting.
+
+ TRANSMIT /NOWAIT [ other switches ] filename
+ The /NOWAIT switch is equivalent to giving the command SET
+ TRANSMIT PROMPT 0 prior to the TRANSMIT command, except the
+ switch affects only the command with which it was given and does
+ not affect the prevailing global setting.
+
+ TRANSMIT /NOWAIT /NOECHO /BINARY [ other switches ] filename
+ When the TRANSMIT command is given with the /NOWAIT, /NOECHO,
+ and /BINARY switches, this activates a special "blast the whole
+ file out the communications connection all at once" mode that
+ Kermit didn't have prior to version 8.0. There has been
+ increasing demand for this type of transmission with the advent
+ of devices that expect image (e.g. .JPG) or sound (e.g. .MP3)
+ files as raw input. The obvious question is: how does the
+ receiving device know when it has the whole file? This depends
+ on the device, of course; usually after a certain amount of time
+ elapses with nothing arriving, or else when Kermit hangs up or
+ closes the connection.
+
+ TYPE /CHARACTER-SET:name
+ Allows you to specify the character set in which the file to be
+ typed is encoded.
+
+ TYPE /NUMBER
+ Adds line numbers.
+
+ TYPE /OUTPUT:filename
+ Sends the results of the TYPE command to the given file.
+
+ TYPE /TRANSLATE-TO:name
+ Used in conjunction with TYPE /CHARACTER-SET:xxx; allows you to
+ specify the character set in which the file is to be displayed.
+
+ TYPE /TRANSPARENT
+ Used to disable character-set translation in the TYPE command,
+ which otherwise can take place automatically based on file
+ scanning, even when /CHARACTER-SET and /TRANSLATE-TO switches
+ are not given.
+
+ VOID text
+ Parses the text, evaluating any backslash items in it (such as
+ function calls) but doesn't do anything further, except possibly
+ printing error messages. Useful for invoking functions that have
+ side effects without using or printing their direct results,
+ e.g. "void \fsplit(\%a,&a)".
+
+Symbolic Links in UNIX
+
+ The UNIX versions of C-Kermit have had /FOLLOWLINKS and /NOFOLLOWLINKS
+ switches added to several commands to control the treatment of symbolic
+ links. Different commands deal differently with symbolic links:
+
+ Kermit SEND, FTP MPUT
+ /NOFOLLOWLINKS is the default, which means symbolic links are
+ skipped entirely. The alternative, /FOLLOWLINKS, should be used
+ with caution, since an innocent link might point to a whole file
+ system, or it might cause a loop. There is no way in Kermit or
+ FTP protocol to send the link itself. We either skip them or
+ follow them; we can't duplicate them.
+
+ DIRECTORY
+ /NOFOLLOWLINKS is the default, which means the DIRECTORY command
+ lists symbolic links in a way that shows they are links, but it
+ does not follow them. The alternative, /FOLLOWLINKS, follows
+ links and gives information about the linked-to directories and
+ files.
+
+ DELETE, RMDIR
+ The DELETE command does not have link-specific switches. DELETE
+ never follows links. If you tell Kermit to delete a symbolic
+ link, it deletes the link itself, not the linked-to file. Ditto
+ for RMDIR.
+
+ COPY
+ The COPY command behaves just like the UNIX cp command; it
+ always follows links.
+
+ RENAME
+ The RENAME command behaves just like the UNIX mv command; it
+ operates on links directly rather than following.
+
+ [ [401]Top ] [ [402]Contents ] [ [403]C-Kermit Home ] [ [404]Kermit
+ Home ]
+
+8. OTHER SCRIPTING IMPROVEMENTS
+
+8.1. Performance and Debugging
+
+ A command cache for frequently used commands plus some related
+ optimizations increases the speed of compute-bound scripts by anywhere
+ from 50% to 1000%.
+
+ The new PROMPT command can be used to set breakpoints for debugging
+ scripts. If executed in a command file or macro, it gives you an
+ interactive command prompt in the current context of the script, with
+ all its variables, arguments, command stack, etc, available for
+ examination or change, and the ability to resume the script at any
+ point (END resumes it, Ctrl-C or STOP cancels it and returns to top
+ level).
+
+ The new Ctrl-C trapping feature ([405]Section 8.14) lets you intercept
+ interruption of scripts. This can be used in combination with the
+ PROMPT command to debug scripts. Example:
+
+define ON_CTRLC {
+ echo INTERRUPTED BY CTRL-C...
+ echo The command stack has not yet been rolled back:
+ show stack
+ echo Type Ctrl-C again or use the END command to return to top level.
+ prompt Debug>
+}
+
+ Adding this ON_CTRL definition to your script lets you interrupt it at
+ any point and get prompt that is issued at the current command level,
+ so you can query local variables, etc.
+
+ [ [406]Top ] [ [407]Contents ] [ [408]C-Kermit Home ] [ [409]Kermit
+ Home ]
+
+8.2. Using Macros as Numeric Variables
+
+ A macro is a way to assign a value to a name, and then use the name to
+ refer to the value. Macros are used in two ways in Kermit: as
+ "subroutines" or functions composed of Kermit commands, which are
+ executed, or as variables to hold arbitrary values -- text, numbers,
+ filenames, etc.
+
+ When a macro is to be executed, its name is given as if it were a
+ C-Kermit command, optionally preceded by the word "do". When a macro is
+ used as a variable, it must be "escaped" with \m(xxx) (or equivalent
+ function, e.g. \s(xxx), \:(xxx), \fdefinition(xxx)), where xxx is the
+ macro name, for example:
+
+ define filename /usr/olga/oofa.txt
+ send \m(filename)
+
+ Of course variables can also hold numbers:
+
+ define size 17
+ declare \&a[\m(size)]
+ ...
+ define index 3
+ if ( == \m(index) 3 ) echo The third value is: \&a[\m(index)]
+ evaluate index (\m(index) * 4)
+ if ( > \m(index) \m(size) ) echo Out of range!
+
+ But these are contexts in which only numbers are valid. C-Kermit 8.0
+ has been changed to treat non-escaped non-numeric items in strictly
+ numeric contexts as macro names. So it is now possible (but not
+ required) to omit the \m(...) notation and just use the macro name in
+ these contexts:
+
+ define size 17
+ declare \&a[size]
+ ...
+ define index 3
+ if ( == index 3 ) echo The third value is: \&a[index]
+ evaluate index (index * 4)
+ if ( > index size ) echo Out of range!
+
+ This is especially nice for loops that deal with arrays. Here, for
+ example, is a loop that reverses the order of the elements in an array.
+ Whereas formerly it was necessary to write:
+
+ .\%n ::= \fdim(&a)
+ for \%i 1 \%n/2 1 {
+ .tmp := \&a[\%n-\%i+1]
+ .\&a[\%n-\%i+1] := \&a[\%i]
+ .\&a[\%i] := \m(tmp)
+ }
+
+ Recoding this to use macro names "i" and "n" instead of the backslash
+ variables \%i and \%n, we have:
+
+ .n ::= \fdim(&a)
+ for i 1 n/2 1 {
+ .tmp := \&a[n-i+1]
+ .\&a[n-i+1] := \&a[i]
+ .\&a[i] := \m(tmp)
+ }
+
+ which reduces the backslash count to less than half. The final
+ statement in the loop could be written ".\&a[i] ::= tmp" if the array
+ contained only numbers (since ::= indicates arithmetic expression
+ evaluation).
+
+ Also, now you can use floating-point numbers in integer contexts (such
+ as array subscripts), in which case they are truncated to an integer
+ value (i.e. the fractional part is discarded).
+
+ Examples of numeric contexts include:
+
+ * Array subscripts.
+ * Any numeric function argument.
+ * Right-hand side of ::= assignments.
+ * EVALUATE command or \fevaluate() function expression.
+ * The INCREMENT or DECREMENT by-value.
+ * IF =, >, <, !=, >=, and <= comparands.
+ * The IF number construct.
+ * FOR-loop variables.
+ * STOP, END, and EXIT status codes.
+ * The INPUT timeout value.
+ * PAUSE, WAIT, SLEEP, MSLEEP intervals.
+ * The SHIFT argument.
+ * Numeric switch arguments, e.g. TYPE /WIDTH:number, SEND
+ /LARGER:number.
+ * SCREEN MOVE-TO row and column number.
+ * Various SET DIAL parameters (timeout, retry limit, etc).
+ * Various SET SEND or RECEIVE parameters (packet length, window size,
+ etc).
+ * Various other SET parameters.
+
+ and:
+
+ * S-Expressions (explained in [410]Section 9).
+
+ Macro names used in numeric contexts must not include mathematical
+ operators. Although it is legal to create a macro called "foo+bar", in
+ a numeric context this would be taken as the sum of the values of "foo"
+ and "bar". Any such conflict can be avoided, of course, by enclosing
+ the macro name in \m(...).
+
+ [ [411]Top ] [ [412]Contents ] [ [413]C-Kermit Home ] [ [414]Kermit
+ Home ]
+
+8.3. New IF Conditions
+
+ Several new IF conditions are available:
+
+ IF DECLARED arrayname
+ Explained in [415]Section 8.6.
+
+ IF KBHIT
+ Allows a script to test whether a key was pressed without
+ actually trying to read it.
+
+ IF KERBANG (Unix only)
+ True if Kermit was started from a Kerbang script. This is useful
+ for knowing how to interpret the \&@[] and \&_[] argument vector
+ arrays, and under what conditions to exit.
+
+ IF INTEGER n
+ This is just a synonym for IF NUMERIC, which is true if n
+ contains only digits (or, if n is a variable, its value contains
+ only digits).
+
+ By contrast, IF FLOAT n succeeds if n is a floating-point number OR an
+ integer (or a variable with floating-point or integer value).
+ Therefore, IF FLOAT should be used whenever any kind of number is
+ acceptable, whereas IF INTEGER (or IF NUMERIC) when only an integer can
+ be used.
+
+ [ [416]Top ] [ [417]Contents ] [ [418]C-Kermit Home ] [ [419]Kermit
+ Home ]
+
+8.4. The ON_UNKNOWN_COMMAND Macro
+
+ The new ON_UNKNOWN_COMMAND macro, if defined, is executed whenever you
+ give a command that is not known to C-Kermit; any operands are passed
+ as arguments. Here are some sample definitions:
+
+ DEF ON_UNKNOWN_COMMAND telnet \%1 ; Treat unknown commands as hostnames
+ DEF ON_UNKNOWN_COMMAND dial \%1 ; Treat unknown commands phone numbers
+ DEF ON_UNKNOWN_COMMAND take \%1 ; Treat unknown commands as filenames
+ DEF ON_UNKNOWN_COMMAND !\%* ; Treat unknown commands as shell commands
+
+ The ON_CD macro, if defined, is executed whenever Kermit is given a CD
+ (change directory) command (8.0.211). Upon entry to this macro, the
+ directory has already changed and the new directory string is available
+ in the \v(directory) variable, and also as the first argument (\%1).
+
+ [ [420]Top ] [ [421]Contents ] [ [422]C-Kermit Home ] [ [423]Kermit
+ Home ]
+
+8.5. The SHOW MACRO Command
+
+ The SHOW MACRO command has been changed to accept more than one macro
+ name:
+
+ (setq a 1 b 2 c 3)
+ show mac a b c
+ a = 1
+ b = 2
+ c = 3
+
+ An exact match is required for each name (except that case doesn't
+ matter). If you include wildcard characters, however, a pattern match
+ is performed:
+
+ show mac [a-c]*x
+
+ shows all macros whose names start with a, b, or c, and end with x.
+
+ [ [424]Top ] [ [425]Contents ] [ [426]C-Kermit Home ] [ [427]Kermit
+ Home ]
+
+8.6. Arrays
+
+ A clarification regarding references to array names (as opposed to
+ array elements): You can use array-name "abbreviations" like &a only in
+ contexts that expect array names, like ARRAY commands or array-name
+ function arguments such as the second argument of \fsplit(). In a LOCAL
+ statement, however, you have to write \&a[], since "local &a" might
+ refer to a macro named "&a".
+
+ In function arguments, however, you MUST use the abbreviated form:
+ \fsplit(\%a,&a) or \fsplit(\%a,&a[]). If you include the backslash (as
+ in "\fsplit(\%a,\&a[])") a parse error occurs.
+
+ Here are the new array-related commands:
+
+ IF DECLARED arrayname
+ Allows a script to test whether an array has been declared. The
+ arrayname can be a non-array backslash variable such as \%1 or
+ \m(name), in which case it is evaluated first, and the result is
+ treated as the array name. Otherwise, arrayname is treated as in
+ the ARRAY commands: it can be a, &a, &a[], \&a, \&a[], \&a[3],
+ \&a[3:9], etc, with the appropriate results in each case.
+ Synonym: IF DCL.
+
+ UNDECLARE arrayname
+ UNDECLARE is a new top-level command to undeclare an array.
+ Previously this could only be done with "declare \&a[0]" (i.e.
+ re-declare the array with a dimension of 0).
+
+ ARRAY LINK linkname arrayname
+ Creates a symbolic link from the array named by linkname (which
+ must be the name of an array that is not yet declared in the
+ current context) to the array named by arrayname (which must the
+ name of a currently declared array that is not itself a link, or
+ a variable containing the name of such an array). The two names
+ indicate the same array: if you change an array element, the
+ change is reflected in the link too, and vice versa. If you
+ undeclare the link, the real array is unaffected. If you
+ undeclare the real array, all links to it disappear. If you
+ resize an array (directly or through a link), all links to it
+ are updated automatically.
+
+ Array links let you pass array names as arguments to macros. For
+ example, suppose you had a program that needed to uppercase all the
+ elements of different arrays at different times. You could write a
+ macro to do this, with the array name as an argument. But without array
+ links, there would be no way to refer to the argument array within the
+ macro. Array links make it easy:
+
+ define arrayupper {
+ local \&e[] \%i
+ array link \&e[] \%1
+ for i 1 \fdim(&e) 1 { .\&e[i] := \fupper(\&e[i]) }
+ }
+ declare \&a[] = these are some words
+ arrayupper &a
+ show array &a
+
+ The macro declares the array link LOCAL, which means it doesn't
+ conflict with any array of the same name that might exist outside the
+ macro, and that the link is destroyed automatically when the macro
+ exits. This works, by the way, even if the link name and the macro
+ argument name are the same, as long as the link is declared LOCAL.
+
+ As noted, you can't make a link to a nonexistent array. So when writing
+ a macro whose job is to create an array whose name is passed as an
+ argument, you must declare the array first (the size doesn't matter as
+ long as it's greater than 0). Example:
+
+ define tryme { ; Demonstration macro
+ local \&e[] ; We only need this inside the macro
+ array link \&e[] \%1 ; Make local link
+ shift ; Shift argument list
+ void \fsplit(\%*,&e) ; Split remainder of arg list into array
+ }
+ declare \&a[1] ; Declare target array in advance
+ tryme &a here are some words ; Invoke the macro with array name and words
+ show array a ; See the results
+
+ One final improvement allows the macro itself to declare the array
+ (this was not possible in earlier Kermit releases): if the array name
+ in the DECLARE command is a variable (and not an array name), or
+ includes variables, the resulting value is used as the array name. So:
+
+ define tryme { ; Demonstration macro
+ declare \%1[1] ; Preliminary declaration for target array
+ local \&e[] ; We only need this inside the macro
+ array link \&e[] \%1 ; Make local link
+ shift ; Shift argument list
+ void \fsplit(\%*,&e) ; Split remainder of arg list into array
+ }
+ tryme &a here are some words ; Invoke the macro with array name and words
+ show array a ; See the results
+
+ The SHOW ARRAY command now indicates whether an array name is a link.
+
+ Also see the descriptions of [428]\fjoin() and [429]\fsplit(), plus
+ [430]Section 8.10 on the MINPUT command, which shows how an entire
+ array (or segment of it) can be used as the MINPUT target list.
+
+ [ [431]Top ] [ [432]Contents ] [ [433]C-Kermit Home ] [ [434]Kermit
+ Home ]
+
+8.7. New or Improved Built-in Variables and Functions
+
+ The following new built-in variables are available:
+
+ \v(buildid) A date string like "20000808" indicating when C-Kermit was b
+uilt.
+ \v(ftime) Current time, secs since midnight, including fraction of sec
+ond.
+ \v(iprompt) The current SET PROMPT value
+ \v(sexp) The most recent S-Expression (see [435]Section 9)
+ \v(sdepth) The current S-Expression invocation depth ([436]Section 9)
+ \v(svalue) The value of the most recent S-Expression ([437]Section 9)
+
+ \v(ftp_code) Most recent FTP response code ([438]Section 3)
+ \v(ftp_connected) FTP connection status ([439]Section 3)
+ \v(ftp_cpl) FTP Command Protection Level ([440]Section 3.2)
+ \v(ftp_dpl) FTP Data Protection Level ([441]Section 3.2)
+ \v(ftp_getputremote) The current SET GET-PUT-REMOTE setting ([442]Section 3.8)
+
+ \v(ftp_host) Name or IP address of FTP server ([443]Section 3)
+ \v(ftp_loggedin) FTP login status ([444]Section 3)
+ \v(ftp_message) Most recent FTP response message ([445]Section 3)
+ \v(ftp_security) FTP Security method ([446]Section 3.2)
+ \v(ftp_server) OS type of FTP server ([447]Section 3)
+
+ \v(http_code) Most recent HTTP response code
+ \v(http_connected) HTTP connection status
+ \v(http_host) Name or IP address of HTTP server
+ \v(http_message) Most recent HTTP response message
+ \v(http_security) TLS cipher used to secure the HTTP session
+
+ \v(hour) Hour of the day, 0 to 23.
+ \v(timestamp) Equivalent to "\v(ndate) \v(time)".
+
+ \v(log_debug) Current debug log file, if any.
+ \v(log_packet) Current packet log file, if any.
+ \v(log_session) Current session log file, if any.
+ \v(log_transaction) Current transaction log file, if any.
+ \v(log_connection) Current connection log file, if any.
+
+ The following new or improved built-in functions are available:
+
+ \fcmdstack() Allows programmatic access to the command stack.
+ \fcvtdate() [448]Section 8.13, format options added
+ \fdelta2secs() [449]Section 8.13
+ \fdostounixpath(s1) Converts a DOS filename to Unix format.
+ \fsplit() Now allows grouping/nesting in source string.
+ \fword() Allows the same grouping and nesting.
+ \fjoin(&a,s1,n1,n2) Copies an array into a single string.
+ \fsubstitute(s1,s2,s3) Substitutes characters within a string.
+ \freplace() Has new 4th "occurrence" argument.
+ \fsexpression() Evaluates an S-Expression (explained in [450]Section 9
+).
+ \ftrim(), \fltrim() Now trim CR and LF by default, as well as SP and Tab.
+ \funixtodospath(s1) Converts a Unix filename to DOS format.
+ \fkeywordval(s1,c1) Assigns values to keywords (macros) (explained below).
+
+ Most functions that have "2" in their names to stand for the word "to"
+ can now also be written with "to", e.g. "\fdelta2secs(),"
+ \fdeltatosecs()."
+
+ \funtabify(string)
+ (New to 8.0.211) Replaces Horizontal Tab characters in the given
+ string with spaces based on VT100-like tab stops.
+
+ \fverify(s1,s2,n)
+ As of version 8.0.211, returns -1 if s2 is an empty string.
+ Previously it returned 0, making \fverify(abc,\%a) look as if
+ \%a was a string composed of a's, b's, and/or c's when in fact
+ it contained nothing.
+
+ \fcode(string)
+ As of version 8.0.211, returns 0 if string is empty or missing.
+ Previously it returned the empty string, which made it unsafe to
+ use in arithmetic or boolean expressions.
+
+ \v(inscale)
+ New to version 8.0.211, its value is the INPUT SCALE-FACTOR
+ ([451]Section 8.10), default 1.0.
+
+8.7.1. The \fkeywordval() Function
+
+ \fkeywordval(s1,c1) is new to C-Kermit 8.0. Given a string s1 of the
+ form "name=value", it creates a macro with the given name and assigns
+ it the given value. If no value appears after the equal sign, any
+ existing macro of the given name is undefined. Blanks are automatically
+ trimmed from around the name and value. The optional c1 parameter is
+ the assignment operator character, equal sign (=) by default. This
+ function is handy for processing keyword parameters or any other form
+ of parameter-value pair. Suppose, for example, you want to write a
+ macro that accepts keyword parameters rather than positional ones:
+
+ define MYDIAL {
+ local \%i modem hangup method device speed number
+ def number 5551234 ; Assign default parameter values
+ def speed 57600
+ def modem usrobotics
+ def hangup rs232
+ def method tone
+ def country 1
+ for \%i 1 \v(argc)-1 1 { ; Parse any keyword parameters...
+ if not \fkeywordval(\&_[\%i]) end 1 Bad parameter: "\&_[\%i]"
+ }
+ set dial country \m(country)
+ set modem type \m(modem)
+ set modem hang \m(hangup)
+ set dial method \m(tone)
+ set line \m(device)
+ if fail stop 1
+ set speed \m(speed)
+ if fail stop 1
+ show comm
+ set dial display on
+ dial \m(number)
+ if success connect
+ }
+
+ In this example, all the defaults are set up inside the macro, and
+ therefore it can be invoked with no parameters at all. But if you want
+ to have the macro dial a different number, you can supply it as
+ follows:
+
+ mydial number=7654321
+
+ You can supply any number of keyword parameters, and you can give them
+ in any order:
+
+ mydial number=7654321 hangup=modem speed=115200
+
+8.7.2. The \fsplit(), \fjoin(), and \fword() Functions
+
+ \fjoin(&a,s1,n1,n2) is also new; it creates a string from an array (or
+ a piece of one). &a is the name of the array (a range specifier can be
+ included); s1 is a character or string to separate each element in the
+ result string (can be omitted, in which case the elements are not
+ separated at all), and n1 is a grouping mask, explained below. If s1 is
+ empty or not specified, the array elements are separated with spaces.
+ If you want the elements concatenated with no separator, include a
+ nonzero n2 argument. Given the array:
+
+ declare \&a[] = 0 1 2 3 4 5 6 7 8 9
+
+ you can get effects like this:
+
+ \fjoin(&a) 0 1 2 3 4 5 6 7 8 9
+ \fjoin(&a,:) 0:1:2:3:4:5:6:7:8:9
+ \fjoin(&a,{,}) 0,1,2,3,4,5,6,7,8,9
+ \fjoin(&a,...) 0...1...2...3...4...5...6...7...8...9
+ \fjoin(&a,,,1) 0123456789
+
+ \fsplit(), \fword(), \fstripb(), and \fjoin() accept a "grouping mask"
+ argument, n1, which is a number from 0 to 63, in which:
+
+ 1 = "" doublequotes
+ 2 = {} braces
+ 4 = '' singlequotes
+ 8 = () parentheses
+ 16 = [] square brackets
+ 32 = <> angle brackets
+
+ These can be OR'd (added) together to make any number 0-63 (-1 is
+ treated the same as 63, 0 means no grouping). If a bit is on, the
+ corresponding kind of grouping is selected. (If more than 1 bit is set
+ for \fjoin(), only the lowest-order one is used.)
+
+ If you include the same character in the grouping mask and the include
+ list, the grouping mask takes precedence. Example:
+
+ def \%a a "b c d" e
+ \fsplit(\%a,&a[],,,-1) = 3 <-- doublequote used for grouping
+ \fsplit(\%a,&a[],,",-1) = 3 <-- doublequote still used for grouping
+
+ Nesting of matched left and right grouping characters (parentheses,
+ braces, and brackets, but not quotes) is recognized. Example:
+
+ def \%a a (b c <d e [f g {h i} j k] l m> n o) p
+ \fsplit(\%a,&a,,,0) = 16 (no grouping)
+ \fsplit(\%a,&a,,,2) = 15 (braces only)
+ \fsplit(\%a,&a,,,16) = 11 (square brackets only)
+ \fsplit(\%a,&a,,,32) = 7 (angle brackets only)
+ \fsplit(\%a,&a,,,63) = 3 (all)
+ \fsplit(\%a,&a,,,-1) = 3 (all)
+
+ \fsplit() and \fjoin() are "reciprocal" functions. You can split a
+ string up into an array and join it back into a new string that is
+ equivalent, as long as \fsplit() and \fjoin() are given equivalent
+ grouping masks, except that the type of braces might change. Example:
+
+ def \%a a {b c [d e] f g} "h i" j <k l> m
+ echo STRING=[\%a]
+ echo WORDS=\fsplit(\%a,&a,,,-1)
+ show array a
+ asg \%b \fjoin(&a,{ },2)
+ echo JOIN =[\%b]
+ echo WORDS=\fsplit(\%b,&b,,,-1)
+ show array b
+
+ The arrays a and b are identical. The strings a and b are as follows:
+
+ \%a: a {b c [d e] f g} "h i" j <k l> m
+ \%b: a {b c [d e] f g} {h i} j {k l} m
+
+ It is possible to quote separator grouping characters with backslash to
+ override their grouping function. And of course to include backslash
+ itself in the string, it must be quoted too. Furthermore, each
+ backslash must be doubled, so the command parser will still pass one
+ backslash to \fsplit() for each two that it sees. Here are some
+ examples using \fsplit() with a grouping mask of 8 (treat parentheses
+ as grouping characters).
+
+ String Result
+ a b c d e f 6
+ a b\\ c d e f 5
+ a b (c d e) f 4
+ a b \\(c d e\\) f 6
+ a b \\\\(c d e\\\\) f 7
+
+ \fsplit() has also been changed to create its array (if one is given)
+ each time it is called, so now it can be conveniently called in a loop
+ without having to redeclare the array each time.
+
+ Incidentally... Sometimes you might want to invoke \fsplit() in a
+ situation where you don't care about its return value, e.g. when you
+ just want to fill the array. Now you can "call" \fsplit() or any other
+ function with the new [452]VOID command:
+
+ void \fsplit(\%a,&a)
+
+ \fsplit() and \fjoin() also accept a new, optional 6th argument, an
+ options flag, a number that can specify a number of options. So far
+ there is just one option, whose value is 1:
+
+ separator-flag
+ Normally separators are collapsed. So, for example,
+
+ \fword(Three little words,2)
+
+ returns "little" (the second word). Space is a separator, but
+ there are multiple spaces between each word. If the value 1 is
+ included in the option flag, however, each separator counts. If
+ two separators are adjacent, an empty word is produced between
+ them. This is useful for parsing (e.g.) comma-separated lists
+ exported from databases or spreadsheets.
+
+8.7.3. The \fcmdstack() Function
+
+ The new \fcmdstack() function gives access to the command stack:
+
+ \fcmdstack(n1,n2)
+ Arguments: n1 is the command stack level. If omitted, the
+ current level, \v(cmdlevel), is used. n2 is a function code
+ specifying the desired type of information:
+
+ 0 (default) = name of object at level n1.
+ 1 (nonzero) = object type (0 = prompt; 1 = command file; 2 = macro).
+
+ The default for n2 is 0.
+
+ The name associated with prompt is "(prompt)". Here's a loop that can
+ be included in a macro or command file to show the stack (similar to
+ what the SHOW STACK command does):
+
+ for \%i \v(cmdlevel) 0 -1 {
+ echo \%i. [\fcmdstack(\%i,1)] \fcmdstack(\%i,0)
+ }
+
+ In this connection, note that \v(cmdfile) always indicates the most
+ recently invoked active command file (if any), even if that file is
+ executing a macro. Similarly, \v(macro) indicates the most recently
+ invoked macro (if any), even if the current command source is not a
+ macro. The name of the "caller" of the currently executing object
+ (command file or macro) is:
+
+ \fcmdstack(\v(cmdlevel)-1)
+
+ and its type is:
+
+ \fcmdstack(\v(cmdlevel)-1,1)
+
+ To find the name of the macro that invoked the currently executing
+ object, even if one or more intermediate command files (or prompting
+ levels) are involved, use a loop like this:
+
+ for \%i \v(cmdlevel)-1 0 -1 {
+ if = \fcmdstack(\%i,1) 2 echo CALLER = \fcmdstack(\%i,0)
+ }
+
+ Of course if you make a macro to do this, the macro must account for
+ its own additional level:
+
+ define CALLER {
+ for \%i \v(cmdlevel)-2 0 -1 {
+ if = \fcmdstack(\%i,1) 2 return \fcmdstack(\%i,0)
+ }
+ return "(none)"
+ }
+
+ The built-in variable \v(cmdsource) gives the current command source as
+ a word ("prompt", "file", or "macro").
+
+8.7.4. The VOID Command
+
+ VOID is like ECHO in that all functions and variables in its argument
+ text are evaluated. but it doesn't print anything (except possibly an
+ error message if a function was invocation contained or resulted in any
+ errors). VOID sets FAILURE if it encounters any errors, SUCCESS
+ otherwise.
+
+ [ [453]Top ] [ [454]Contents ] [ [455]C-Kermit Home ] [ [456]Kermit
+ Home ]
+
+8.8. The RETURN and END Commands
+
+ The execution of a macro is terminated in any of the following ways:
+
+ * With an END [ number [ message ] ] command. If a number is given,
+ the macro succeeds if the number is 0, and fails if it is not zero;
+ if a number is not given, the macro succeeds.
+ * With a STOP command, which works just like END except it peels back
+ the command stack all the way to top level.
+ * With a RETURN [ text ] command, in which case the macro always
+ succeeds.
+ * By running out of commands to execute, in which case the macro
+ succeeds or fails according the most recently executed command that
+ sets success or failure.
+
+ The same considerations apply to command files invoked by the TAKE
+ command.
+
+ If a macro does not execute any commands that set success or failure,
+ then invoking the macro does not change the current SUCCESS/FAILURE
+ status. It follows, then, that the mere invocation of a macro does not
+ change the SUCCESS/FAILURE status either. This makes it possible to
+ write macros to react to the status of other commands (or macros), for
+ example:
+
+ define CHKLINE {
+ if success end 0
+ stop 1 SET LINE failed - please try another device.
+ }
+ set modem type usrobotics
+ set line /dev/cua0
+ chkline
+ set speed 57600
+ dial 7654321
+
+ By the way, none of this is news. But it was not explicitly documented
+ before, and C-Kermit 7.0 and earlier did not always handle the RETURN
+ statement as it should have.
+
+ [ [457]Top ] [ [458]Contents ] [ [459]C-Kermit Home ] [ [460]Kermit
+ Home ]
+
+8.9. UNDEFINing Groups of Variables
+
+ The UNDEFINE command, which previously accepted one variable name, now
+ accepts a list of them, and also accepts wildcard notation to allow
+ deletion of variables that match a given pattern.
+
+ UNDEFINE [ switches ] name [ name [ name [ ... ] ] ]
+ Undefines the variables whose names are given. Up to 64 names
+ may be given in one UNDEFINE command.
+
+ If you omit the switches and include only one name, the UNDEFINE
+ command works as before.
+
+ Switches include:
+
+ /MATCHING
+ Specifies that the names given are to treated as patterns rather
+ than literal variable names. Note: pattern matching can't be
+ used with array references; use the ARRAY command to manipulate
+ arrays and subarrays.
+
+ /LIST
+ List the name of each variable to be undefined, and whether it
+ was undefined successfully ("ok" or "error"), plus a summary
+ count at the end.
+
+ /SIMULATE
+ List the names of the variables that would be deleted without
+ actually deleting them. Implies /LIST.
+
+ The UNDEFINE command fails if there were any errors and succeeds
+ otherwise.
+
+ The new _UNDEFINE command is like UNDEFINE, except the names are
+ assumed to be variable names themselves, which contain the names (or
+ parts of them) of the variables to be undefined. For example, if you
+ have the following definitions:
+
+ define \%a foo
+ define foo This is some text
+
+ then:
+
+ undef \%a
+
+ undefines the variable \%a, but:
+
+ _undef \%a
+
+ undefines the macro foo.
+
+ Normal Kermit patterns are used for matching; metacharacters include
+ asterisk, question mark, braces, and square brackets. Thus, when using
+ the /MATCHING switch, if the names of the macros you want to undefine
+ contain any of these characters, you must quote them with backslash to
+ force them to be taken literally. Also note that \%* is not the name of
+ a variable; it is a special notation used within a macro for "all my
+ arguments". The command "undef /match \%*" deletes all \%x variables,
+ where x is 0..9 and a..z. Use "undef /match \%[0-9]" to delete macro
+ argument variables or "undef /match \%[i-n]" to delete a range of \%x
+ variables.
+
+ [ [461]Top ] [ [462]Contents ] [ [463]C-Kermit Home ] [ [464]Kermit
+ Home ]
+
+8.10. The INPUT and MINPUT Commands
+
+ As of C-Kermit 8.0.211, the INPUT and MINPUT commands accept a switch:
+
+ [M]INPUT /NOMATCH timeout
+ The /NOMATCH switch allows INPUT or MINPUT to read incoming
+ material for the specified amount of time, without attempting to
+ match it with any text or patterns. When this switch is
+ included, the [M]INPUT command succeeds when the timeout
+ interval expires, with \v(instatus) set to 1, meaning "timed
+ out", or fails upon interruption or i/o error.
+
+ Also in version 8.0.211, there is a new way to apply a scale factor to
+ [M]INPUT timeouts:
+
+ SET INPUT SCALE-FACTOR floating-point-number
+ This scales all [M]INPUT timeouts by the given factor, allowing
+ time-sensitive scripts to be adjusted to changing conditions
+ such as congested networks or different-speed modems without
+ having to change each INPUT-class command. This affects only
+ those timeouts that are given in seconds, not as wall-clock
+ times. Although the scale factor can have a fractional part, the
+ INPUT timeout is still an integer. The new built-in variable
+ \v(inscale) tells the current INPUT SCALE-FACTOR.
+
+ The MINPUT command can be used to search the incoming data stream for
+ several targets simultaneously. For example:
+
+ MINPUT 8 one two three
+
+ waits up to 8 seconds for one of the words "one", "two", or "three" to
+ arrive. Words can be grouped to indicate targets that contain spaces:
+
+ MINPUT 8 nineteen twenty "twenty one"
+
+ And of course you can also use variables in place of (or as part of)
+ the target names:
+
+ MINPUT 8 \%a \&x[3] \m(foo)
+
+ Until now you had to know the number of targets in advance when writing
+ the MINPUT statement. Each of the examples above has exactly three
+ targets.
+
+ But suppose your script needs to look for a variable number of targets.
+ For this you can use arrays and \fjoin(), described in [465]Section
+ 8.7. Any number of \fjoin() invocations can be included in the MINPUT
+ target list, and each one is expanded into the appropriate number of
+ separate targets each time the MINPUT command is executed. Example:
+
+ declare \&a[10] = one two three
+ minput 10 foo \fjoin(&a) bar
+
+ This declares an array of ten elements, and assigns values to the first
+ three of them. The MINPUT command looks for these three (as well as the
+ words "foo" and "bar"). Later, if you assign additional elements to the
+ array, the same MINPUT command also looks for the new elements.
+
+ If an array element contains spaces, each word becomes a separate
+ target. To create one target per array element, use \fjoin()'s grouping
+ feature:
+
+ dcl \&a[] = {aaa bbb} {ccc ddd} {xxx yyy zzz}
+
+ minput 10 \fjoin(&a) <-- 7 targets
+ minput 10 \fjoin(&a,,2) <-- 3 targets
+
+ [ [466]Top ] [ [467]Contents ] [ [468]C-Kermit Home ] [ [469]Kermit
+ Home ]
+
+8.11. Learned Scripts
+
+ C-Kermit now includes a simple script recorder that monitors your
+ commands, plus your actions during CONNECT mode, and automatically
+ generates a script program that mimics what it observed. You should
+ think of this feature as a script-writing ASSISTANT since, as you will
+ see [470]later in this section, the result generally needs some editing
+ to make it both secure and flexible. The script recorder is controlled
+ by the new LEARN command:
+
+ LEARN [ /ON /OFF /CLOSE ] [ filename ]
+ If you give a filename, the file is opened for subsequent
+ recording. The /ON switch enables recording to the current file
+ (if any); /OFF disables recording. /CLOSE closes the current
+ script recording file (if any). If you give a filename without
+ any switches, /ON is assumed.
+
+ The /OFF and /ON switches let you turn recording off and on during a
+ session without closing the file.
+
+ When recording:
+
+ * All commands that you type (or recall) at the prompt are recorded
+ in the file except:
+ + LEARN commands are not recorded.
+ + The CONNECT command is not recorded.
+ + The TELNET command is converted to SET HOST /NETWORK:TCP.
+ * Commands obtained from macros or command files are not recorded.
+ * During CONNECT:
+ + Every line you type is converted to an OUTPUT command.
+ + The last prompt before any line you type becomes an INPUT
+ command.
+ + Timeouts are calculated automatically for each INPUT command.
+ + A PAUSE command is inserted before each OUTPUT command just to
+ be safe.
+
+ Thus the script recorder is inherently line-oriented. It can't be used
+ to script character-oriented interactions like typing Space to a
+ "More?" prompt or editing a text file with VI or EMACS.
+
+ But it has advantages too; for example it takes control characters into
+ account that might not be visible to you otherwise, and it
+ automatically converts control characters in both the input and output
+ streams to the appropriate notation. It can tell, for example that the
+ "$ " prompt on the left margin in UNIX is really {\{13}\{10}$ },
+ whereas in VMS it might be {\{13}\{10}\{13}$ }. These sequences are
+ detected and recorded automatically.
+
+ A learned script should execute correctly when you give a TAKE command
+ for it. However, it is usually appropriate to edit the script a bit.
+ The most important change would be to remove any passwords from it. For
+ example, if the script contains:
+
+ INPUT 9 {\{13}\{10}Password: }
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT bigsecret\{13}
+
+ you should replace this by something like:
+
+ INPUT 9 {\{13}\{10}Password: }
+ IF FAIL STOP 1 INPUT timeout
+ ASKQ pswd Please type your password:
+ PAUSE 1
+ OUTPUT \m(pswd)\{13}
+
+ The LEARN command can't do this for you since it knows nothing about
+ "content"; it only knows about lines and can't be expected to parse or
+ understand them -- after all, the Password prompt might be in some
+ other language. So remember: if you use the LEARN command to record a
+ login script, be sure edit the resulting file to remove any passwords.
+ Also be sure to delete any backup copies your editor or OS might have
+ made of the file.
+
+ Other manual adjustments might also be appropriate:
+
+ * If the target of an INPUT command can vary, you can replace the
+ INPUT command with MINPUT and the appropriate target list, and/or
+ the target with a \fpattern(). For example, suppose you are dialing
+ a number that can be answered by any one of 100 terminal servers,
+ whose prompts are ts-00>, ts-01>, ts-02>, ... ts-99>. The script
+ records a particular one of these, but you want it to work for all
+ of them, so change (e.g.):
+ INPUT 10 ts-23> ; or whatever
+
+ to:
+ INPUT 10 \fpattern(ts-[0-9][0-9]>)
+
+ * The INPUT timeout values are conservative, but they are based only
+ on a single observation; you might need to tune them.
+ * The PAUSE commands might not be necessary, or the PAUSE interval
+ might need adjustment.
+ * In case you made typographical errors during recording, they are
+ incorporated in your script; you can edit them out if you want to.
+
+ Here is a sample script generated by Kermit ("learn vms.ksc") in which
+ a Telnet connection is made to a VMS computer, the user logs in, starts
+ Kermit on VMS, sends it a file, and then logs out:
+
+ ; Scriptfile: vms.ksc
+ ; Directory: /usr/olga
+ ; Recorded: 20001124 15:21:23
+
+ SET HOST /NETWORK:TCP vms.xyzcorp.com
+ IF FAIL STOP 1 Connection failed
+
+ INPUT 7 {\{13}\{10}\{13}Username: }
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT olga\{13}
+ INPUT 3 {\{13}\{10}\{13}Password: }
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT secret\{13}
+ INPUT 18 {\{13}\{10}\{13}$ }
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT set default [.incoming]\{13}
+ INPUT 12 {\{13}\{10}\{13}$ }
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT kermit\{13}
+ INPUT 15 {\{13}\{10}\{13}ALTO:[OLGA.INCOMING] C-Kermit>}
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT receive\{13}
+ send myfile.txt
+
+ INPUT 18 {\{13}\{10}\{13}ALTO:[OLGA.INCOMING] C-Kermit>}
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT exit\{13}
+ INPUT 6 {\{13}\{10}\{13}$ }
+ IF FAIL STOP 1 INPUT timeout
+ PAUSE 1
+ OUTPUT logout\{13}
+ close
+ exit
+
+ The commands generated by Kermit during CONNECT (INPUT, IF FAIL, PAUSE,
+ and OUTPUT) have uppercase keywords; the commands typed by the user are
+ in whatever form the user typed them (in this case, lowercase).
+
+ [ [471]Top ] [ [472]Contents ] [ [473]C-Kermit Home ] [ [474]Kermit
+ Home ]
+
+8.12. Pattern Matching
+
+ A pattern is a character string that is used to match other strings.
+ Patterns can contain metacharacters that represent special actions like
+ "match any single character", "match zero or more characters", "match
+ any single character from a list", and so on. The best known
+ application of patterns is in file specifications that contain
+ wildcards, as in "send *.txt", meaning "send all files whose names end
+ with .txt".
+
+ Patterns are also used in increasingly many other ways, to the extent
+ it is useful to point out certain important distinctions in the ways in
+ which they are used:
+
+ Anchored Patterns
+ If an anchored pattern does not begin with "*", it must match
+ the beginning of the string, and if it does not end with "*", it
+ must match the end of the string. For example, the anchored
+ pattern "abc" matches only the string "abc", not "abcde" or
+ "xyzabc" or "abcabc". The anchored pattern "abc*" matches any
+ string that starts with "abc"; the anchored pattern "*abc"
+ matches any string that ends with "abc"; the anchored pattern
+ "*abc*" matches any string that contains "abc" (including any
+ that start and/or end with it).
+
+ Floating Patterns
+ A floating pattern matches any string that contains a substring
+ that matches the pattern. In other words, a floating pattern has
+ an implied "*" at the beginning and end. You can anchor a
+ floating pattern to the beginning by starting it with "^", and
+ you can anchor it to the end by ending it with "$" (see examples
+ below).
+
+ Wildcards
+ A wildcard is an anchored pattern that has the additional
+ property that "*" does not match directory separators.
+
+ This terminology lets us describe Kermit's commands with a bit more
+ precision. When a pattern is used for matching filenames, it is a
+ wildcard, except in the TEXT-PATTERNS and BINARY-PATTERNS lists and
+ /EXCEPT: clauses, in which case directory separators are not
+ significant (for example, a BINARY-PATTERN of "*.exe" matches any file
+ whose name ends in .exe, no matter how deeply it might be buried in
+ subdirectories). When Kermit parses a file specification directly,
+ however, it uses the strict wildcard definition. For example, "send
+ a*b" sends all files whose names start with "a" and end with "b" in the
+ current directory, and not any files whose names end with "b" that
+ happen to be in subdirectories whose names start with "a". And as
+ noted, wildcards are anchored, so "delete foo" deletes the file named
+ "foo", and not all files whose names happen to contain "foo".
+
+ Most other patterns are anchored. For example:
+
+ if match abc bc ...
+
+ does not succeed (and you would be surprised if it did!). In fact, the
+ only floating patterns are the ones used by commands or functions that
+ search for patterns in files, arrays, or strings. These include:
+
+ * The GREP and TYPE /MATCH commands.
+ * The \fsearch(), \frsearch(), and \farraylook() functions.
+
+ Thus these are the only contexts in which explicit anchors ("^" and
+ "$") may be used:
+
+ grep abc *.txt
+ Prints all lines containing "abc" in all files whose names end
+ with ".txt".
+
+ grep ^abc *.txt
+ Prints all lines that start with "abc" in all ".txt" files.
+
+ grep abc$ *.txt
+ Prints all lines that end with "abc" in all ".txt" files.
+
+ grep ^a*z$ *.txt
+ Prints all lines that start with "a" and end with "z" in all
+ ".txt" files.
+
+ Similarly for TYPE /PAGE, /fsearch(), /frsearch(), and \farraylook().
+
+ Here is a brief summary of anchored and floating pattern equivalences:
+
+ Anchored Floating
+ abc ^abc$
+ *abc abc$
+ abc* ^abc
+ *abc* abc
+
+ [ [475]Top ] [ [476]Contents ] [ [477]C-Kermit Home ] [ [478]Kermit
+ Home ]
+
+8.13. Dates and Times
+
+ C-Kermit's comprehension of date-time formats is considerably expanded
+ in version 8.0. Any command that reads dates, including the DATE
+ command itself, or any switch, such as the /BEFORE: and /AFTER:
+ switches, or any function such as \fcvtdate(), now can understand dates
+ and times expressed in any ISO 8601 format, in Unix "asctime" format,
+ in FTP MDTM format, and in practically any format used in RFC 822 or
+ RFC 2822 electronic mail, with or without timezones, and in a great
+ many other formats as well. HELP DATE briefly summarizes the acceptable
+ date-time formats.
+
+ Furthermore, C-Kermit 8.0 includes a new and easy-to-use form of
+ date-time arithmetic, in which any date or time can be combined with a
+ "delta time", to add or subtract the desired time interval (years,
+ months, weeks, days, hours, minutes, seconds) to/from the given date.
+ And new functions are available to compare dates and to compute their
+ differences.
+
+ As you can imagine, all this requires quite a bit of "syntax". The
+ basic format is:
+
+ [ date ] [ time ] [ delta ]
+
+ Each field is optional, but in most cases (depending on the context)
+ there must be at least one field. If a date is given, it must come
+ first. If no date is given, the current date is assumed. If no time is
+ given, an appropriate time is supplied depending on whether a date was
+ supplied. If no delta is given, no arithmetic is done. If a delta is
+ given without a date or time, the current date and time are used as the
+ base.
+
+ Date-time-delta fields are likely to contain spaces (although they need
+ not; space-free forms are always available). Therefore, in most
+ contexts -- and notably as switch arguments -- date-time information
+ must be enclosed in braces or doublequotes, for example:
+
+ send /after:"8-Aug-2001 12:00 UTC" *.txt
+
+ Kermit's standard internal format for dates and times is:
+
+ yyyymmdd hh:mm:ss
+
+ for example:
+
+ 20010208 10:28:01
+
+ Date-times can always be given in this format. yyyy is the 4-digit
+ year, mm is the two-digit month (1-12; supply leading zero for
+ Jan-Sep), dd is the 2-digit day (leading zero for 1-9), hh is the hour
+ (0-23), mm the minute (0-59), ss the second (0-59), each with leading
+ zero if less than the field width. The date and time can be separated
+ by a space, an underscore, a colon, or the letter T. The time is in
+ 24-hour format. Thus the various quantities are at the following fixed
+ positions:
+
+Position Contents
+ 1-4 Year (4 digits, 0000-9999)
+ 5-6 Month (2 digits, 1-12)
+ 7-8 Day (2 digits, 1-31)
+ 9 Date-Time Separator (space, :, _, or the letter T)
+ 10-11 Hour (2 digits, 0-23)
+ 12 Hour-Minute Separator (colon)
+ 13-14 Minute (2 digits, 0-59)
+ 15 Minute-Second Separator (colon)
+ 16-17 Second (2 digits, 0-59)
+
+ Example:
+
+ 19800526 13:07:12 26 May 1980, 13:07:12 (1:07:12PM)
+
+ This is the format produced by the DATE command and by any function
+ that returns a date-time. It is suitable for lexical comparison and
+ sorting, and for use as a date-time in any Kermit command. When this
+ format is given as input to a command or function, various date-time
+ separators (as noted) are accepted:
+
+ 19800526 13:07:12 26 May 1980, 13:07:12 (1:07:12PM)
+ 20010208_10:28:35 2 February 2001, 10:28:35 AM
+ 18580101:12:00:00 1 January 1858, noon
+ 20110208T00:00:00 2 February 2011, midnight
+
+ Certain other special date-time formats that are encountered on
+ computer networks are recognized:
+
+ Asctime Format
+ This is a fixed format used by Unix, named after Unix's
+ asctime() ("ASCII time") function. It is always exactly 24
+ characters long. Example: Fri Aug 10 16:38:01 2001
+
+ Asctime with Timezone
+ This is like Asctime format, but includes a 3-character timezone
+ between the time and year. It is exactly 28 characters long.
+ Example: Fri Aug 10 16:38:01 GMT 2001
+
+ E-Mail Format
+ E-mail date-time formats are defined in [479]RFC 2822 with a
+ fair amount of flexibility and options. The following examples
+ are typical of e-mails and HTTP (web-page) headers:
+
+ Sat, 14 Jul 2001 11:49:29 (No timezone)
+ Fri, 24 Mar 2000 14:19:59 EST (Symbolic timezone)
+ Tue, 26 Jun 2001 10:19:45 -0400 (EDT) (GMT Offset + comment)
+
+ FTP MDTM Format
+ This is the date-time format supplied by FTP servers that
+ support the (not yet standard but widely used nevertheless) MDTM
+ command, by which the FTP client asks for a file's modification
+ time:
+
+ yyyymmddhhmmss[.ffff]
+
+ where yyyy is the 4-digit year, mm is the 2-digit month, and so
+ on, exactly 14 digits long. An optional fractional part
+ (fraction of second) may also be included, separated by a
+ decimal point (period). Kermit rounds to the nearest second.
+ Example:
+
+ 20020208102835.515 (8 February 2002 10:28:36 AM)
+
+8.13.1. The Date
+
+ The date, if given, must precede the time and/or delta, and can be in
+ many, many formats. For starters, you can use several symbolic date
+ names in place of actual dates:
+
+ NOW
+ This is replaced by the current date and time. The time can not
+ be overriden (if you want to supply a specific time, use TODAY
+ rather than NOW).
+
+ TODAY
+ This is replaced by the current date and a default time of
+ 00:00:00 is supplied, but can be overridden by a specific time;
+ for example, if today is 8 February 2002, then "TODAY" is
+ "20020802 00:00:00" but "TODAY 10:28" is "20020802 10:28:00".
+
+ TOMORROW
+ Like TODAY, but one day later (if today is 8 February 2002, then
+ "TOMORROW" is "20020803 00:00:00" but "TOMORROW 16:30" is
+ "20020803 16:30:00").
+
+ YESTERDAY
+ Like TODAY, but one day earlier.
+
+ MONDAY, TUESDAY, WEDNESDAY, ..., SUNDAY
+ The date on the given day of the week, today or later. A default
+ time of 00:00:00 is supplied but can be overridden. Example:
+ "SATURDAY 12:00" means next Saturday (or today, if today is
+ Saturday) at noon.
+
+ You can give an explicit date in almost any conceivable format, but
+ there are some rules:
+
+ * If a date is given, it must have three fields: day, month, and
+ year; the order can vary (except that the month can not be last).
+ * If names are used for days, months, etc, they must be English.
+ * The year must lie between 0000 and 9999, inclusive.
+ * All calendar calculations use Gregorian dating, so calculated dates
+ for years prior to 1582 (or later, depending on the country) will
+ not agree with historical dates. Other forms of dating (e.g.
+ Hebrew, Chinese) are not supported.
+
+ Various date-field separators are accepted: hyphen, slash, space,
+ underscore, period. The same field separator (if any) must be used in
+ both places; for example 18-Sep-2001 but not 18-Sep/2001. Months can be
+ numeric (1-12) or English names or abbreviations. Month name
+ abbreviations are normally three letters, e.g. Apr, May, Jun, Jul.
+ Capitalization doesn't matter.
+
+ Here are a few examples:
+
+ 18 Sep 2001 (English month, abbreviated)
+ 18 September 2001 (English month, spelled out)
+ 2001 Sept 18 (Year, month, day)
+ 18-Sep-2001 (With hyphens)
+ 18/09/2001 (All numeric with slashes)
+ 18.09.2001 (Ditto, with periods)
+ 18_09_2001 (Ditto, with underscores)
+ 09/18/2001 (See below)
+ 2001/09/18 (See below)
+ September 18, 2001 (Correspondence style)
+ Sep-18-2001 (Month-day-year)
+ 20010918 (Numeric, no separators)
+
+ You can also include the day of the week with a specific date, in which
+ case it is accepted (if it is a valid day name), but not verified to
+ agree with the given date:
+
+ Tue, 18 Sep 2001 (Abbreviated, with comma)
+ Tue,18 Sep 2001 (Comma but no space)
+ Tue 18 Sep 2001 (Abbreviated, no comma)
+ Tuesday 18 Sep 2001 (Spelled out)
+ Tuesday, 18 Sep 2001 (etc)
+ Friday, 18 Sep 2001 (Accepted even if not Friday)
+
+ In all-numeric dates with the year last, such as 18/09/2001, Kermit
+ identifies the year because it's 4 digits, then decides which of the
+ other two numbers is the month or day based on its value. If both are
+ 12 or less and are unequal, the date is ambiguous and is rejected. In
+ all-numeric dates with the year first, the second field is always the
+ month and the third is the day. The month never comes last. A date with
+ no separators is accepted only if it is all numeric and has exactly
+ eight digits, and is assumed to be in yyyymmdd format.
+
+ 20010918 (18-Sep-2001 00:00:00)
+
+ or 14 digits (as in FTP MDTM format):
+
+ 20010918123456 (18-Sep-2001 12:34:56)
+
+ You can always avoid ambiguity by putting the year first, or by using
+ an English, rather than numeric, month. A date such as 09/08/2001 would
+ be ambiguous but 2001/09/08 is not, nor is 09-Aug-2001.
+
+ Until the late 1990s, it was common to encounter 2-digit years, and
+ these are found to this day in old e-mails and other documents. Kermit
+ accepts these dates if they have English months, and interprets them
+ according to the windowing rules of [480]RFC 2822: "If a two digit year
+ is encountered whose value is between 00 and 49, the year is
+ interpreted by adding 2000, ending up with a value between 2000 and
+ 2049. If a two digit year is encountered with a value between 50 and
+ 99, or any three digit year is encountered, the year is interpreted by
+ adding 1900."
+
+ If you need to specify a year prior to 1000, use leading zeros to
+ ensure it is not misinterpreted as a "non-Y2K-compliant" modern year:
+
+ 7-Oct-77 (19771007 00:00:00)
+ 7-Oct-0077 (00771007 00:00:00)
+
+8.13.2. The Time
+
+ The basic time format is hh:mm:dd; that is hours, minutes, seconds,
+ separated by colons, perhaps with an optional fractional second
+ separated by a decimal point (period). The hours are in 24-hour format;
+ 12 is noon, 13 is 1pm, and so on. Fields omitted from the right default
+ to zero. Fields can be omitted from the left or middle by including the
+ field's terminating colon. Examples:
+
+ 11:59:59 (11:59:59 AM)
+ 11:59 (11:59:00 AM)
+ 11 (11:00:00 AM)
+ 11:59:59.33 (11:59:59 AM)
+ 11:59:59.66 (Noon)
+ 03:21:00 (3:21:00 AM)
+ 3:21:00 (3:21:00 AM)
+ 15:21:00 (3:21:00 PM)
+ :21:00 (00:21:00 AM)
+ ::01 (00:00:01 AM)
+ 11::59 (11:00:59 AM)
+
+ Leading zeros can be omitted, but it is customary and more readable to
+ keep them in the minute and second fields:
+
+ 03:02:01 (03:02:01 AM)
+ 3:02:01 (03:02:01 AM)
+ 3:2:1 (03:02:01 AM)
+
+ AM/PM notation is accepted if you wish to use it:
+
+ 11:59:59 (11:59:59 AM)
+ 11:59:59AM (11:59:59 AM)
+ 11:59:59A.M. (11:59:59 AM)
+ 11:59:59am (11:59:59 AM)
+ 11:59:59a.m. (11:59:59 AM)
+ 11:59:59PM (11:59:59 PM = 23:59:59)
+ 11:59:59P.M. (11:59:59 PM = 23:59:59)
+ 11:59:59pm (11:59:59 PM = 23:59:59)
+ 11:59:59p.m. (11:59:59 PM = 23:59:59)
+
+ You can omit the colons if you wish, in which case Kermit uses the
+ following rules to interpret the time:
+
+ 1. 6 digits is hh:mm:ss, e.g. 123456 is 12:34:56.
+ 2. 5 digits is h:mm:ss, e.g. 12345 is 1:23:45.
+ 3. 4 digits is hh:mm, e.g. 1234 is 12:34.
+ 4. 3 digits is h:mm, e.g. 123 is 1:23.
+ 5. 2 digits is hh, e.g. 12 is 12:00.
+ 6. 1 digit is h (the hour), e.g. 1 is 1:00.
+
+ Examples:
+
+ 1 (01:00:00 AM)
+ 10 (10:00:00 AM)
+ 230 (02:30:00 AM)
+ 230pm (02:30:00 PM = 14:30:00)
+ 1115 (11:15:00 AM)
+ 2315 (11:15:00 PM = 23:15:00 PM)
+ 23150 (02:31:50 AM)
+ 231500 (23:15:00 PM)
+
+8.13.3. Time Zones
+
+ If a time is given, it can (but need not) be followed by a time zone
+ designator. If no time zone is included, the time is treated as local
+ time and no timezone conversions are performed.
+
+ The preferred time zone designator is the UTC Offset, as specified in
+ [481]RFC 2822: a plus sign or minus sign immediately followed by
+ exactly four decimal digits, signifying the difference in hh (hours)
+ and mm (minutes) from Universal Coordinated Time (UTC, also known as
+ Greenwich Mean Time, or GMT), with negative numbers to the West and
+ positive numbers to the East. For example:
+
+ Fri, 13 Jul 2001 12:54:29 -0700
+
+ indicates a local time of 12:54:29 that is 07 hours and 00 minutes
+ behind (less than, East of) Universal Time. The space is optional, so
+ the example could also be written as:
+
+ Fri, 13 Jul 2001 12:54:29-0700
+
+ The following symbolic time zones are also accepted, as specified by
+ [482]RFC 2822 and/or in ISO 8601:
+
+ GMT = +0000 Greenwich Mean Time
+ Z = +0000 Zulu (Zero Meridian) Time
+ UTC = +0000 Universal Coordinated Time
+ UT = +0000 Universal Time
+ EDT = -0400 Eastern (USA) Daylight Time
+ EST = -0500 Eastern (USA) Standard Time
+ CDT = -0500 Central (USA) Daylight Time
+ CST = -0600 Central (USA) Standard Time
+ MDT = -0600 Mountain (USA) Daylight Time
+ MST = -0700 Mountain (USA) Standard Time
+ PDT = -0700 Pacific (USA) Daylight Time
+ PST = -0800 Pacific (USA) Standard Time
+
+ Note that GMT, Z, UTC, and UT all express the same concept: standard
+ (not daylight) time at the Zero Meridian. UTC, by the way, is an
+ international standard symbol and does not correspond to the order of
+ the English words, Universal Coordinated Time, but it happens to have
+ the same initial letters as these words. Of course hundreds of other
+ symbolic timezones and variations exist, but they are not standardized,
+ and are therefore not supported by Kermit.
+
+ When a time zone is included with a time, the time is converted to
+ local time. In case the conversion crosses a midnight boundary, the
+ date is adjusted accordingly. Examples converting to EST (Eastern USA
+ Standard Time = -0500):
+
+ 11:30:00 = 11:30:00
+ 11:30:00 EST = 11:30:00
+ 11:30:00 GMT = 06:30:00
+ 11:30:00 PST = 14:30:00
+ 11:30:00Z = 06:30:00
+ 11:30PM GMT = 18:30:00
+ 11:30 -0500 = 11:30:00
+ 11:30 -0800 = 08:30:00
+ 11:30 +0200 = 04:30:00
+
+ Unlike most of Kermit's other date-time conversions, timezone knowledge
+ (specifically, the offset of local time from UTC) is embodied in the
+ underlying operating system, not in Kermit itself, and any conversion
+ errors in this department are the fault of the OS. For example, most
+ UNIX platforms do not perform conversions for years prior to 1970.
+
+8.13.4. Delta Time
+
+ Date/time expressions can be composed of a date and/or time and a delta
+ time, or a delta time by itself. When a delta time is given by itself,
+ it is relative to the current local date and time. Delta times have the
+ following general format:
+
+ {+,-}[number units][hh[:mm[:ss]]]
+
+ In other words, a delta time always starts with a plus or minus sign,
+ which is followed by a "part1", a "part2", or both. The "part1", if
+ given, specifies a number of days, weeks, months, or years; "part2"
+ specifies a time in hh:mm:ss notation. In arithmetic terms, these
+ represents some number of days or other big time units, and then a
+ fraction of a day expressed as hours, minutes, and seconds; these are
+ to be added to or subtracted from the given (or implied) date and time.
+ The syntax is somewhat flexible, as shown by the following examples:
+
+ +1 day (Plus one day)
+ +1day (Ditto)
+ +1d (Ditto)
+ + 1 day (Ditto)
+ + 1 day 3:00 (Plus one day and 3 hours)
+ +1d3:00 (Ditto)
+ +1d3 (Ditto)
+ +3:00:00 (Plus 3 hours)
+ +3:00 (Ditto)
+ +3 (Ditto)
+ +2 days (Plus 2 days)
+ -12 days 7:14:22 (Minus 12 days, 7 hours, 14 minutes, and 22 seconds)
+
+ The words "week", "month", and "year" can be used like "day" in the
+ examples above. A week is exactly equivalent to 7 days. When months are
+ specified, the numeric month number of the date is incremented or
+ decremented by the given number, and the year and day adjusted
+ accordingly if necessary (for example, 31-Jan-2001 +1month =
+ 03-Mar-2001 because February does not have 31 days). When years are
+ specified, they are added or subtracted to the base year. Examples
+ (assuming the current date is 10-Aug-2001 and the current time is
+ 19:21:11):
+
+ 18-Sep-2001 +1day (20010918 00:00:00)
+ today +1day (20010811 00:00:00)
+ now+1d (20010811 19:21:11)
+ + 1 day (20010811 19:21:11)
+ + 1 day 3:14:42 (20010811 22:35:54)
+ + 7 weeks (20010928 19:21:11)
+ +1d3:14:42 (20010811 22:35:54)
+ +1w3:14:42 (20010817 22:35:54)
+ +1m3:14:42 (20010910 22:35:54)
+ +1y3:14:42 (20020810 22:35:54)
+ 2 feb 2001 + 10 years (20110208 00:00:00)
+ 2001-02-08 +10y12 (20110208 12:00:00)
+ 31-dec-1999 23:59:59+00:00:01 (20000101 00:00:00)
+ 28-feb-1996 +1day (19960229 00:00:00) (leap year)
+ 28-feb-1997 +1day (19970301 00:00:00) (nonleap year)
+ 28-feb-1997 +1month (19970328 00:00:00)
+ 28-feb-1997 +1month 11:59:59 (19970328 11:59:59)
+ 28-feb-1997 +20years (20170228 00:00:00)
+ 28-feb-1997 +8000years (99970228 00:00:00)
+
+ For compatibility with VMS, the following special delta-time format is
+ also accepted:
+
+ +number-hh:mm:ss
+ -number-hh:mm:ss
+
+ (no spaces). The hyphen after the number indicates days. It corresponds
+ exactly to the Kermit notation:
+
+ +numberdhh:mm:ss
+ -numberdhh:mm:ss
+
+ The following forms all indicate exactly the same date and time:
+
+ 18-Sep-2001 12:34:56 +1-3:23:01
+ 18-Sep-2001 12:34:56 +1d3:23:01
+ 18-Sep-2001 12:34:56 +1 day 3:23:01
+
+ and mean "add a day plus 3 hours, 23 minutes, and 1 second" to the
+ given date.
+
+ Note that delta times are not at all the same as UTC offsets; the
+ former specifies an adjustment to the given date/time and the latter
+ specifies that the local time is a particular distance from Universal
+ Time, for example:
+
+ 11-Aug-2001 12:34:56 -0800 (20010811 16:34:56 -- UTC Offset)
+ 11-Aug-2001 12:34:56 -08:00 (20010811 04:34:56 -- Delta time)
+
+ If you give a time followed by a modifier that starts with a + or -
+ sign, how does Kermit know whether it's a UTC offset or a delta time?
+ It is treated as a UTC offset if the sign is followed by exactly four
+ decimal digits; otherwise it is a delta time. Examples (for USA Eastern
+ Daylight Time):
+
+ 11-Aug-2001 12:34:56 -0800 (20010811 16:34:56 -- UTC Offset)
+ 11-Aug-2001 12:34:56 -08:00 (20010811 04:34:56 -- Delta time)
+ 11-Aug-2001 12:34:56 -800 (20010811 04:34:56 -- Delta time)
+ 11-Aug-2001 12:34:56 -8 (20010811 04:34:56 -- Delta time)
+
+ The first example says that at some unknown place which is 8 hours
+ ahead of Universal Time, the time is 12:34:56, and this corresponds to
+ 16:34:56 in Eastern Daylight time. The second example says to subtract
+ 8 hours from the local time. The third and fourth are delta times
+ because, even though a colon is not included, the time does not consist
+ of exactly 4 digits.
+
+ When a delta time is written after a timezone, however, there is no
+ ambiguity and no syntax distinction is required:
+
+ 11-Aug-2001 12:34:56 -0800 -0800 (20010811 08:34:56)
+ 11-Aug-2001 12:34:56 -0800 -08:00 (Ditto)
+ 11-Aug-2001 12:34:56 -08:00 -08:00 (Illegal)
+
+8.13.5. The DATE Command
+
+ Obviously a great many combinations of date, time, time zone, and delta
+ time are possible, as well as many formatting options. The purpose of
+ all this flexibility is to comply with as many standards as possible --
+ Internet RFCs, ISO standards, and proven corporate standards -- as well
+ as with notations commonly used by real people, in order that dates and
+ times from the widest variety of sources can be assigned to a variable
+ and used in any date-time field in any Kermit command.
+
+ You can test any date-and/or-time format with the DATE command, which
+ converts it to standard yyyymmdd hh:mm:ss format if it is understood,
+ or else gives an explicit error message (rather than just "BAD DATE" as
+ in previous C-Kermit releases) to indicate what is wrong with it.
+ Examples (on Tuesday, 31 July 2001 in New York City, Eastern Daylight
+ Time, UTC -0400):
+
+ DATE command argument Result
+ 12:30 20010731 12:30:00
+ 12:30:01 20010731 12:30:01
+ 12:30:01.5 20010731 12:30:02
+ 1230 20010731 12:30:00
+ 230 20010731 02:30:00
+ 230+1d 20010801 02:30:00
+ 230+1d3:00 20010801 05:30:00
+ 20010718 19:21:15 20010718 19:21:15
+ 20010718_192115 20010718 19:21:15
+ 20010718T192115 20010718 19:21:15
+ 18 Jul 2001 +0400 20010717 23:59:59
+ 18 Jul 2001 192115 20010718 19:21:15
+ 18 Jul 2001 192115.8 20010718 19:21:16
+ 18-Jul-2001T1921 20010718 19:21:00
+ 18-Jul-2001 1921Z 20010718 15:21:00
+ 18-Jul-2001 1921 GMT 20010718 15:21:00
+ 18-Jul-2001 1921 UTC 20010718 15:21:00
+ 18-Jul-2001 1921 Z 20010718 15:21:00
+ 18-Jul-2001 1921Z 20010718 15:21:00
+ 18-Jul-2001 1921 -04:00:00 20010718 19:21:00
+ 21-Jul-2001_08:20:00am 20010721 08:20:00
+ 21-Jul-2001_8:20:00P.M. 20010721 20:20:00
+ Fri Jul 20 11:26:25 2001 20010720 11:26:25
+ Fri Jul 20 11:26:25 GMT 2001 20010720 07:26:25
+ Sun, 9 Apr 2000 06:46:46 +0100 20000409 01:46:46
+ Sunday, 9 Apr 2000 06:46:46 +0100 20000409 01:46:46
+ now 20010731 19:41:12
+ today 20010731 00:00:00
+ today 09:00 20010731 09:00:00
+ tomorrow 20010801 00:00:00
+ tomorrow 09:00 20010801 09:00:00
+ tomorrow 09:00 GMT 20010801 05:00:00
+ yesterday 20010730 00:00:00
+ yesterday 09:00 20010730 09:00:00
+ + 3 days 20010803 00:00:00
+ +3 days 20010803 00:00:00
+ +3days 20010803 00:00:00
+ + 3days 20010803 00:00:00
+ + 3 days 09:00 20010803 09:00:00
+ + 2 weeks 20010814 00:00:00
+ + 1 month 20010831 00:00:00
+ - 7 months 20001231 00:00:00
+ + 10 years 20110731 00:00:00
+ friday 20010803 00:00:00
+ saturday 20010804 00:00:00
+ sunday 20010805 00:00:00
+ monday 20010806 00:00:00
+ tuesday 20010731 00:00:00
+ wednesday 20010801 00:00:00
+ thursday 20010802 00:00:00
+ friday 07:00 20010803 07:00:00
+ thursday 1:00pm 20010802 13:00:00
+ thursday 1:00pm GMT 20010802 09:00:00
+ Thu, 10 Nov 94 10:50:47 EST 19941110 10:50:47
+ Fri, 20 Oct 1995 18:35:15 -0400 (EDT) 19951020 18:35:15
+ 31/12/2001 20011231 00:00:00
+ 12/31/2001 20011231 00:00:00
+ 2001-July-20 20010720 00:00:00
+ 2001-September-30 20010930 00:00:00
+ 30-September-2001 20010930 00:00:00
+ Sep 30, 2001 12:34:56 20010930 12:34:56
+ September 30, 2001 20010930 00:00:00
+ September 30, 2001 630 20010930 06:30:00
+ September 30 2001 630 20010930 06:30:00
+ Sep-30-2001 12:34:59 20010930 12:34:59
+ 20010807113542.014 20010807 11:35.42
+ 20010807113542.014Z 20010807 07:35:42
+
+8.13.6. New Date-Time Functions
+
+ In the following descriptions, date-time function arguments are the
+ same free-format date-time strings discussed above, with the same
+ defaults for missing fields. They are automatically converted to
+ standard format internally prior to processing.
+
+ \fcvtdate(d1)
+ Converts the date-time d1 to standard format and local time.
+ This function is not new, but now it accepts a wider range of
+ argument formats that can include timezones and/or delta times.
+ If the first argument is omitted, the current date and time are
+ assumed. The optional second argument is a format code for the
+ result:
+
+ n1 = 1: yyyy-mmm-dd hh:mm:ss (mmm = English 3-letter month
+ abbreviation)
+ n1 = 2: dd-mmm-yyyy hh:mm:ss (ditto)
+ n1 = 3: yyyymmddhhmmss (all numeric)
+
+ \futcdate(d1)
+ Converts the date-time d1 to Universal Coordinated Time (UTC),
+ also known as GMT or Zulu or Zero-Meridian time. The default d1
+ is NOW. If d1 is a valid date-time, the UTC result is returned
+ in standard format, yyyymmdd hh:ss:mm.
+
+ \fcmpdates(d1,d2)
+ Compares two free-format date-times, d1 and d2, and, if both
+ arguments are valid, returns a number: -1 if d1 is earlier than
+ (before) d2; 0 if d1 is the same as d2; 1 if d1 is later than
+ (after) d2.
+
+ \fdiffdates(d1,d2)
+ Computes the difference between two free-format date-times, d1
+ and d2. If both arguments are valid, returns a delta time which
+ is negative if d1 is earlier than (before) d2 and positive
+ otherwise. If d1 and d2 are equal, the result is "+0:00".
+ Otherwise, the result consists of the number of days, hours,
+ minutes, and seconds that separate the two date-times. If the
+ number of days is zero, it is omitted. If the number of days is
+ nonzero but the hours, minutes, and seconds are all zero, the
+ time is omitted. if the seconds are zero, they are omitted.
+
+ \fdelta2secs(dt)
+ Converts a delta time to seconds. For example, "+1d00:00:01" to
+ 86401. Valid delta times must start with a + or - sign. Days are
+ accepted as time units, but not years, months, or weeks. If the
+ result would overflow a computer long word (as would happen with
+ 32-bit long words when the number of days is greater than
+ 24854), the function fails.
+
+ HINT: Although Kermit has a number of built-in date and time variables,
+ it doesn't have a single one suitable for writing a timestamp. For this
+ you would normally use something like "\v(ndate) \v(time)". But
+ \fcvtdate() (with no arguments) is equivalent: it returns the current
+ date and time in yyyymmdd hh:mm:ss format, suitable for time stamping.
+
+8.13.7. Date-Time Programming Examples
+
+ Here's a macro that converts any date-time to UTC, which you might use
+ if C-Kermit didn't already have a \futcdate() function:
+
+ define utcdate {
+ .local := \fcvtdate(\%*) ; 1.
+ .tmp := \fcvtdate(\m(local)UTC) ; 2.
+ .offset := \fdiffdate(\m(local),\m(tmp)) ; 3.
+ .utc := \fcvtdate(\m(local)\m(offset)) ; 4.
+ sho mac utc ; 5.
+ }
+
+ Brief explanation: Line 1 converts the macro argument, a free-format
+ date-time, to standard-format local time. Line 2 appends the "UTC"
+ timezone to the local time and converts the result to local time. In
+ other words, we take the same time as the local time, but pretend it's
+ UTC time, and convert it to local time. For example, if New York time
+ is 4 hours ahead of UTC, then 6:00pm New York time is 2:00pm UTC. Line
+ 3 gets the difference of the two results (e.g. "+04:00"). Line 4
+ appends the difference (delta time) to the local time, and converts it
+ again, which adds (or subtracts) the UTC offset to the given time. Line
+ 5 displays the result.
+
+ Here's a script that opens a web page, gets its headers into an array,
+ scans the array for the "Last-Modified:" header, and interprets it:
+ http open www.columbia.edu
+ if fail stop 1 HTTP OPEN failed
+ http /array:a head index.html /dev/null
+ if fail stop 1 HTTP GET failed
+ show array a
+ for \%i 1 \fdim(&a) 1 {
+ .\%x := \findex(:,\&a[\%i])
+ if not \%x continue
+ .tag := \fleft(\&a[\%i],\%x-1)
+ .val := \fltrim(\fsubstr(\&a[\%i],\%x+1))
+ if ( eq "\m(tag)" "Last-Modified" ) {
+ echo HTTP Date: \m(val)
+ .rdate := \fcvtdate(\m(val))
+ echo {Standard Date (local): \m(rdate)}
+ echo {Standard Date (UTC): \futcdate(\m(rdate))}
+ break
+ }
+ }
+ http close
+
+ The result:
+
+ HTTP Date: Mon, 13 Aug 2001 20:05:42 GMT
+ Standard Date (local): 20010813 16:05:42
+ Standard Date (UTC): 20010813 20:05:42
+
+ As you can see, Kermit had no trouble decoding the date-time-string
+ from the website, converting to local time, and converting back to UTC
+ with no conflicts or loss of information. If it had been in any other
+ known format, the result would have been the same.
+
+ Now suppose we want to download the web page only if it is newer than
+ our local copy. The \fdate(filename) function (which returns the
+ modification date-time of the given file) and the new \fcmpdates()
+ function make it easy. Insert the following just before the BREAK
+ statement:
+
+ if ( < 0 \fcmpdates(\m(rdate),\fdate(index.html)) ) {
+ echo GETTING index.html...
+ http get index.html index.html
+ if success echo HTTP GET OK
+ } else {
+ echo index.html: no update needed
+ }
+ http close
+ exit
+
+ This says, "if 0 is less than the comparison of the remote file date
+ and the local file date, get the remote file, otherwise skip it." And
+ it automatically reconciles the time-zone difference (if any).
+
+ It would be nice to be able to extend this script into a
+ general-purpose website updater, but unfortunately HTTP protocol
+ doesn't provide any mechanism for the client to ask the server for a
+ list of files, recursive or otherwise.
+
+ [ [483]Top ] [ [484]Contents ] [ [485]C-Kermit Home ] [ [486]Kermit
+ Home ]
+
+8.14. Trapping Keyboard Interruption
+
+ Normally when you type Ctrl-C and Kermit is in command mode (as opposed
+ to CONNECT mode) with COMMAND INTERRUPTION ON (as it is unless you have
+ set it OFF), Kermit interrupts any command that is currently in
+ progress, and if a command file or macro is executing, rolls the
+ command stack back to top level, closing all open command files,
+ deactivating all macros, deallocating all local variables and arrays,
+ and leaving you at the command prompt.
+
+ Suppose, however, you want certain actions to occur when a script is
+ interrupted; for example, closing open files, writing log entries, or
+ displaying summary results. You can do this by defining a macro named
+ ON_CTRLC. When Ctrl-C is detected, and a macro with this name is
+ defined, Kermit executes it from the current command level, thus giving
+ it full access to the environment in which the interruption occurred,
+ including local variables and open files. Only when the ON_CTRLC macro
+ completes execution is the command stack rolled back to top level.
+
+ Once the ON_CTRLC macro is defined, it can be executed only once. This
+ is to prevent recursion if the user types Ctrl-C while the ON_CTRLC
+ macro is executing. If you type Ctrl-C while the Ctrl-C macro is
+ active, this does not start a new copy of ON_CTRLC; rather, it returns
+ to the top-level command prompt. After the ON_CTRLC macro returns, it
+ has been removed from the macro table so if you want to use it again or
+ install a different Ctrl-C trap, you must execute a new DEFINE ON_CTRLC
+ command. In any case, as always when you interrupt a script with
+ Ctrl-C, its completion status is FAILURE.
+
+ Normally the ON_CTRLC macro would be defined in the command file or
+ macro to which it applies, and should be declared LOCAL. This way, if
+ the command file or macro completes successfully without being
+ interrupted, the ON_CTRLC definition disappears automatically.
+ Otherwise the definition would still be valid and the macro would be
+ executed, probably out of context, the next time you typed Ctrl-C.
+
+ Here's a simple example of a command file that sets a Ctrl-C trap for
+ itself:
+
+ local on_ctrlc ; Make Ctrl-C trap local to this command file.
+ define on_ctrlc { ; Define the ON_CTRLC macro.
+ echo Interrupted at \v(time).
+ echo Iterations: \%n
+ }
+ xecho Type Ctrl-C to quit
+ for \%n 1 999 1 { ; Prints a dot every second until interrupted.
+ sleep 1
+ xecho .
+ }
+ echo Finished normally at \v(time) ; Get here only if not interrupted.
+ decrement \%n
+ echo Iterations: \%n
+
+ This prints a summary no matter whether it completes normally or is
+ interrupted from the keyboard. In both cases the trap is automatically
+ removed afterwards.
+
+ For an example of how to use ON_CTRLC to debug scripts, see
+ [487]Section 8.1.
+
+ [ [488]Top ] [ [489]Contents ] [ [490]C-Kermit Home ] [ [491]Kermit
+ Home ]
+
+9. S-EXPRESSIONS
+
+ This section is primarily for those who want to write
+ calculation-intensive scripts, especially if they require
+ floating-point arithmetic, and/or for those who are familiar with the
+ LISP programming language.
+
+ Ever since C-Kermit version 5 was released in 1988, scripting has been
+ one of its major attractions, and arithmetic is a key part of it.
+ Versions 5 and 6 included integer arithmetic only, using traditional
+ algebraic notation, e.g.:
+
+ echo \fevaluate(3*(2+7)/2)
+ 13
+
+ C-Kermit 7.0 added support for floating-point arithmetic, but only
+ through function calls:
+
+ echo \ffpdivide(\ffpmultiply(3.0,\ffpadd(2.0,7.0)),2.0)
+ 13.5
+
+ C-Kermit 8.0 introduces a third form of arithmetic that treats integers
+ and floating-point numbers uniformly, is easier to read and write, and
+ executes very quickly:
+
+ (/ (* 3 (+ 2 7)) 2)
+ 13.5
+
+ But first some background.
+
+ The Kermit command and scripting language differs from true programming
+ languages (such as C or Fortran) in many ways; one of the most
+ prominent differences is the way in which variables are distinguished
+ from constants. In a command language, words are taken literally; for
+ example, the Unix shell:
+
+ cat foo.bar
+
+ displays the file named foo.bar. Whereas in a programming language like
+ C, words are assumed to be variables:
+
+ s = foo.bar; /* Assigns the value of foo.bar to the variable s */
+
+ To make a programming language take words literally, you have to quote
+ or "escape" them:
+
+ s = "foo.bar"; /* Assigns a pointer to the string "foo.bar" to the variable s
+ */
+
+ The opposite holds for command languages: to get them to treat a word
+ as a variable rather than a constant, you have to escape them. For
+ example, in the Unix shell:
+
+ foo=123 ; Assign value 123 to variable foo.
+ echo foo ; Prints "foo"
+ echo $foo ; Prints "123"
+
+ And in Kermit:
+
+ define foo 123 ; Assign value 123 to variable foo.
+ echo 123 ; This prints "123".
+ echo foo ; This prints "foo".
+ echo \m(foo) ; This prints "123".
+
+ In other words, character strings (such as "foo" above) are interpreted
+ as literal strings, rather than variable names, except in special
+ commands like DEFINE that deal specifically with variable names (or in
+ numeric contexts as explained in [492]Section 8.2). The special
+ "escape" character (dollar sign ($) for the shell, backslash (\) for
+ Kermit) indicates that a variable is to be replaced by its value.
+
+ The requirement to escape variable names in command languages normally
+ does not impose any special hardship, but can add a considerable
+ notational burden to arithmetic expressions, which are typically full
+ of variables. Especially in Kermit when floating point numbers are
+ involved, where you must use special \ffpxxx() functions, e.g.
+ "\ffpadd(\m(a),\m(b))" rather than the simple "+" operator to add two
+ floating-point numbers together, because the original arithmetic
+ handler doesn't support floating point (this might change in the
+ future). To illustrate, the general formula for the area of a triangle
+ is:
+
+ sqrt(s * (s - a) * (s - b) * (s - c))
+
+ where a, b, and c are the lengths of the triangle's three sides and:
+
+ s = (a + b + c) / 2
+
+ Except in special cases (e.g. a = 3, b = 4, c = 5), the result has a
+ fractional part so the computation must be done using floating-point
+ arithmetic. We can create a Kermit 7.0 function for this as follows:
+
+ def area {
+ local s t1 t2 t3
+ assign s \ffpdiv(\ffpadd(\ffpadd(\%1,\%2),\%3),2.0)
+ assign t1 \ffpsub(\m(s),\%1)
+ assign t2 \ffpsub(\m(s),\%2)
+ assign t3 \ffpsub(\m(s),\%3)
+ return \ffpsqrt(\ffpmul(\m(s),\ffpmul(\m(t1),\ffpmul(\m(t2),\m(t3)))))
+ }
+
+ But as you can see, this is rather cumbersome. Note, in particular,
+ that arithmetic functions like \ffpadd(), \ffpmul(), etc, take exactly
+ two operands (like their symbolic counterparts + and *), so obtaining
+ the product of three or more numbers (as we do in this case) is
+ awkward.
+
+ Using the alternative S-Expression notation, we can reduce this to a
+ form that is both easier to read and executes faster (the details are
+ explained later):
+
+ def newarea {
+ (let s (/ (+ \%1 \%2 \%3) 2.0))
+ (sqrt (* s (- s \%1) (- s \%2) (- s \%3)))
+ }
+
+ In both examples, the \%1..3 variables are the normal Kermit macro
+ arguments, referenced by the normal escaping mechanism. For increased
+ readability, we can also assign the macro arguments \%1, \%2, and \%3
+ to the letters a, b, and c corresponding to our formula:
+
+def newarea {
+ (let a \%1 b \%2 c \%3)
+ (let s (/ (+ a b c) 2.0))
+ (sqrt (* s (- s a) (- s b) (- s c)))
+}
+
+ And now the Kermit function reads almost like the original formula.
+ Here Kermit behaves more like a regular programming language. In an
+ S-Expression, macro names need not be escaped when they are used as the
+ names of numeric variables.
+
+ [ [493]Top ] [ [494]Contents ] [ [495]C-Kermit Home ] [ [496]Kermit
+ Home ]
+
+9.1. What is an S-Expression?
+
+ The S-Expression concept is borrowed from the Lisp programming
+ language. "S-Expression" is short for Symbolic Expression (itself
+ sometimes shortened to SEXP). S-Expressions provide a kind of
+ Alternative Mini-Universe within the Kermit command language when the
+ regular rules don't apply, a universe enclosed in parentheses.
+
+ C-Kermit does not pretend to be a full Lisp interpreter; only the
+ arithmetic parts of Lisp have been incorporated: S-Expressions that
+ operate on numbers and return numeric values (plus extensibility
+ features described in [497]Section 9.8, which allow some degree of
+ string processing).
+
+ An S-Expression is a list of zero or more items, separated by spaces,
+ within parentheses. Examples:
+
+ ()
+ (1)
+ (a)
+ (+ a 1)
+ (* 2 a b)
+
+ If the S-Expression is empty, it has the NIL (empty) value. If it is
+ not empty and the first item is an operator (such as + or *), there can
+ be zero or more subsequent items, called the operands:
+
+ (+ 1 2)
+
+ Here the operator is "+" and the operands are "1" and "2", and the
+ value of the S-Expression is the value of the operation (in this case
+ 3). The operator always comes first, which is different from the
+ familiar algebraic notation; this because S-Expression operators can
+ have different numbers of operands:
+
+ (+ 1)
+ (+ 1 2)
+ (+ 1 2 3 4 5 6 7 8 9)
+
+ If the first item in the S-Expression is not an operator, then it must
+ be a variable or a number (or a macro; see [498]Section 9.8), and the
+ S-Expression can only contain one item; in this case, the
+ S-Expression's value is the value of the variable or number:
+
+ (a)
+ (3)
+
+ Operands can be numbers, variables that have numeric values, functions
+ that return numbers, or other S-Expressions. To illustrate an
+ S-Expression within an S-Expression, observe that:
+
+ (+ 1 2)
+
+ is equivalent to any of the following (plus an infinite number of
+ others):
+
+ (+ 1 (+ 1 1))
+ (+ (- 3 2) (/ 14 (+ 3 4)))
+
+ S-Expressions can be nested to any reasonable level; for example, the
+ value of the following S-Expression is 64:
+
+ (- (* (+ 2 (* 3 4)) (- 9 (* 2 2))) 6)
+
+ Operators have no precedence, implied or otherwise, since they can't be
+ mixed. The only exceptions are unary + and -, which simply indicate the
+ sign of a number:
+
+ (* 3 -1)
+
+ Order of evaluation is specified entirely by parentheses, which are
+ required around each operator and its operands: (+ a (* b c)) instead
+ of (a + b * c).
+
+ S-Expressions provide a simple and isolated environment in which
+ Kermit's macro names can be used without the \m(...) escaping that is
+ normally required. Given:
+
+ define a 1
+ define b 2
+ define c 3
+
+ Then:
+
+ (+ \m(a) \m(b) \m(c))
+
+ is equivalent to:
+
+ (+ a b c)
+
+ Within an S-Expression, as in other strictly numeric contexts
+ ([499]Section 8.2), any operand that starts with a letter is treated as
+ a Kermit macro name. In this context, abbreviations are not accepted;
+ variable names must be spelled out in full. Alphabetic case is not
+ significant; "a" and "A" are the same variable, but both are different
+ from "area".
+
+ Of course, regular Kermit variables and functions can be used in
+ S-Expressions in the normal ways:
+
+ (* \v(math_pi) (^ \%r 2)) ; Area of a circle with radius \%r
+ (+ \fjoin(&a)) ; Sum of all elements of array \&a[]
+
+ [ [500]Top ] [ [501]Contents ] [ [502]C-Kermit Home ] [ [503]Kermit
+ Home ]
+
+9.2. Integer and Floating-Point-Arithmetic
+
+ Normally, if all numbers in an S-Expression are integers, the result is
+ an integer:
+
+ (+ 1 1) ; Result is 2
+ (/ 9 3) ; Result is 3
+
+ If any of the operands is floating point, however, the result is also
+ floating point:
+
+ (+ 1 1.0) ; Result is 2.0
+ (/ 9.0 3) ; Result is 3.0
+
+ If all the operands are integers but the result has a fractional part,
+ the result is floating point:
+
+ (/ 10 3) ; Result is 3.333333333333333
+
+ To force an integer result in such cases, use the TRUNCATE operator:
+
+ (truncate (/ 10 3)) ; Result is 3
+
+ Similarly, to force a computation to occur in floating point, you can
+ coerce one of its operands to FLOAT:
+
+ (+ 1 (float 1)) ; Result is 2.0
+
+ The result is also floating point if the magnitude of any integer
+ operand, intermediate result, or the result itself, is larger than the
+ maximum for the underlying machine architecture:
+
+ (^ 100 100)
+
+ If the result is too large even for floating-point representation,
+ "Infinity" is printed; if it is too small to be distinguished from 0,
+ 0.0 is returned.
+
+ Large numbers can be used and large results generated, but they are
+ accurate only to the precision of the underlying machine. For example,
+ the result of:
+
+ (+ 111111111111111111111 222222222222222222222)
+
+ should be 333333333333333333333, but 333333333333333300000.0 is
+ produced instead if the machine is accurate to only about 16 decimal
+ digits, even with coercion to floating-point. The order of magnitude is
+ correct but the least significant digits are wrong. The imprecise
+ nature of the result is indicated by the ".0" at the end. Contrast
+ with:
+
+ (+ 111111111 222222222)
+
+ which produces an exact integer result.
+
+ [ [504]Top ] [ [505]Contents ] [ [506]C-Kermit Home ] [ [507]Kermit
+ Home ]
+
+9.3. How to Use S-Expressions
+
+ S-Expressions may be given as commands to C-Kermit. Any command whose
+ first character is "(" (left parenthesis) is interpreted as an
+ S-Expression.
+
+ If you enter an S-Expression at the C-Kermit> prompt, its result is
+ printed:
+
+ C-Kermit>(/ 10.0 3)
+ 3.333333333333333
+ C-Kermit>
+
+ If an S-Expression is executed within a macro or command file, its
+ value is not printed. However, you can control the printing action
+ with:
+
+ SET SEXPRESSION ECHO { AUTO, ON, OFF }
+ AUTO is the default, meaning print the value at top level only;
+ ON means always print the value; OFF means never print it.
+
+ In any case, the value of the most recent S-Expression (and the
+ S-Expression itself) may be accessed programmatically through the
+ following variables:
+
+ \v(sexpression)
+ The S-Expression most recently executed.
+
+ \v(svalue)
+ The value of the S-Expression most recently executed.
+
+ Besides issuing S-Expressions as commands in themselves, you can also
+ execute them anywhere within a Kermit command, but in this case they
+ must be enclosed in a function call (otherwise they are taken
+ literally):
+
+ \fsexpression(s)
+ The argument "s" is an S-Expression; the outer parentheses may
+ be omitted. The value of the S-Expression is returned. Note that
+ since S-Expressions usually contain spaces, some form of
+ grouping or quoting might be needed in some contexts:
+
+ echo \fsexpression((+ 1 1)) ; Outer parentheses may be included
+ echo \fsexpr(+ 1 1) ; Outer parentheses may be omitted
+ echo Value = "\fsexp(+ 1 a)" ; Can be embedded in strings
+ echo Value = \&a[\fsexp(/ b 2)] ; Can be used in array subscripts
+ if = {\fsexp(+ 1 1)} 2 { ; Braces needed here for grouping
+ echo One plus one still equals two
+ }
+
+ The IF statement illustrates how to use S-Expressions as (or in) IF or
+ WHILE conditions:
+
+ * Although S-Expressions and IF conditions are similar in appearance,
+ they are not interchangeable. Therefore you must use \fsexpr() to
+ let Kermit know it's an S-Expression rather than a regular IF
+ condition, or a boolean or algebraic expression within an IF
+ condition.
+ * In contexts where a single "word" is expected, you must enclose the
+ \fsexp() invocation in braces if the S-Expression contains spaces
+ (and most of them do).
+
+ If an S-Expression is the last command executed in a macro, its value
+ becomes the return value of the macro; no RETURN command is needed.
+ Example:
+
+ def newarea {
+ (let s (/ (+ \%1 \%2 \%3) 2.0))
+ (sqrt (* s (- s \%1) (- s \%2) (- s \%3)))
+ }
+
+ This is equivalent to (but more efficient than):
+
+ def newarea {
+ (let s (/ (+ \%1 \%2 \%3) 2.0))
+ return \fsexp(sqrt (* s (- s \%1) (- s \%2) (- s \%3)))
+ }
+
+ When an S-Expression is entered as a command -- that is, the first
+ nonblank character of the command is a left parenthesis -- then it is
+ allowed to span multiple lines, as many as you like, until the first
+ left parenthesis is matched:
+
+ (let s (/
+ (+
+ \%1
+ \%2
+ \%3
+ )
+ 2.0
+ )
+ )
+ (sqrt (*
+ s
+ (- s \%1)
+ (- s \%2)
+ (- s \%3)
+ )
+ )
+
+ The S-Expression concept lends itself easily to embedding and
+ recursion, but the depth to which recursion can occur is limited by the
+ resources of the computer (memory size, address space, swap space on
+ disk) and other factors. There is no way that C-Kermit can know what
+ this limit is, since it varies not only from computer to computer, but
+ also from moment to moment. If resources are exhausted by recursion,
+ C-Kermit simply crashes; there's no way to trap this error. However,
+ you can set a depth limit on S-Expressions:
+
+ SET SEXPRESSION DEPTH-LIMIT number
+ Limits the number of times the S-Expression reader can invoke
+ itself without returning to the given number. The default limit
+ is 1000. This limit applies to S-Expressions embedded within
+ other S-Expressions as well as to S-Expressions that invoke
+ recursive macros. If the limit is exceeded, Kermit prints
+ "?S-Expression depth limit exceeded" and returns to its prompt.
+ More about recursion in [508]Section 9.8.
+
+ You can also test the depth programmatically:
+
+ \v(sdepth)
+ The current S-Expression invocation depth. The depth includes
+ both nesting level and recursion. For example, in:
+ (foo (foo (foo (foo (foo))))), the innermost (foo) is at depth
+ 5.
+
+ Help, completion, and syntax checking are not available within an
+ S-Expression. If you type ? within an S-Expression, it says:
+
+ C-Kermit>(? S-Expression ("help sexp" for details)
+
+ As it says, typing "help sexp" will display a brief help text.
+
+ The SHOW SEXPRESSION command displays current SET SEXPRESSION settings
+ and related information.
+
+ [ [509]Top ] [ [510]Contents ] [ [511]C-Kermit Home ] [ [512]Kermit
+ Home ]
+
+9.4. Summary of Built-in Constants and Operators
+
+ Three constants are built in:
+
+ * PI, whose value is the value of pi (the quotient of circumference
+ of any circle and its diameter, 3.141592653...) to the underlying
+ machine's precision;
+ * T, which always has the value 1, which signifies truth in Kermit
+ logical expressions or S-Expressions;
+ * NIL, which always has the empty value, and can serve as a False
+ truth value.
+
+ These constants are specific to S-Expressions and are not visible
+ outside them. They may not be used as the target of an assignment. So,
+ for example:
+
+ (setq t 0) Fails
+ assign t 0 Succeeds but this is not the same T!
+
+ E (the base of natural logarithms, 2.7182818184...) is not built in
+ since it is not intrinsic in most Lisp dialects. If you want E to be
+ the base of natural logarithms you can:
+
+ (setq e (exp 1))
+
+ Operators are either symbols (such as "+") or words. Words must be
+ spelled out in full, not abbreviated. Differences of alphabetic case
+ are ignored.
+
+ The most basic operation in S-Expressions is evaluation:
+
+ EVAL [ s-expression or variable or number [ another [ another ... ] ] ]
+ Evaluates its operands and returns the value of the last one
+ evaluated. Examples:
+
+ (eval) 0
+ (eval 1) 1
+ (eval a) value of a
+ (eval (+ 1 a)) value of a+1
+ (eval (setq a 1) (setq b (+ a 0.5))) value of b (= a+0.5)
+
+ You can use "." as a shorthand for EVAL:
+
+ (.)
+ (. 1)
+ (. a)
+ (. (+ 1 a))
+ (. (setq a 1) (setq b (+ a 0.5)))
+
+ Opposite of EVAL is the operator that suppresses evaluation of its
+ operand:
+
+ QUOTE item
+ The value (quote item) is "item". If the item is itself an
+ S-Expression, the result is the S-Expression with the outer
+ parentheses stripped. Examples:
+
+ (quote) (illegal)
+ (quote a) a
+ (quote hello) hello
+ (quote (this is a string)) this is a string
+ (quote this is a string) (illegal)
+
+ A shorthand notation is also accepted for quoting:
+ 'a is equivalent to (quote a). And therefore:
+ '(a b c) is equivalent to (quote (a b c)).
+ More about quoting in [513]Section 9.8.
+
+ STRING item
+ Is a combination of EVAL and QUOTE. It evaluates the item as an
+ S-Expression, and then puts quotes around the result (more about
+ this in [514]Section 9.8).
+
+ The following operators assign values to variables:
+
+ SETQ [ variable [ value [ variable [ value [ ... ] ] ] ] ]
+ Applies to global variables. For each variable given: if a value
+ is not given, the variable is undefined. If a value is given,
+ assigns the value to the variable. The value may be a number, a
+ variable, or anything that resolves to a number including an
+ S-Expression. Returns the value of the last assignment.
+ Examples:
+
+ (setq) Does nothing, returns NIL.
+ (setq a) Undefines a, returns NIL.
+ (setq a 1) Assigns 1 to a, returns 1.
+ (setq a 1 b 2) Assigns 1 to a, 2 to b, returns 2.
+ (setq a 1 b 2 c) Assigns 1 to a, 2 to b, undefines c, returns NIL.
+
+ To undefine a variable that is not the final one in the list, give it a
+ value of "()" or NIL:
+
+ (setq a () b 2) Undefines a, assigns 2 to b, returns 2.
+ (setq a nil b 2) Ditto.
+
+ Note that a variable can be used right away once it has a value:
+
+ (setq a 1 b a) Assigns 1 to a, the value of a (1) to b, returns 1.
+
+ The results of SETQ (when used with macro names) can be checked
+ conveniently with SHOW MACRO, e.g:
+
+ show mac a b c
+
+ LET [ variable [ value [ variable [ value [ ... ] ] ] ] ]
+ Like SETQ, but applies to local variables. Note that "local" is
+ used in the Kermit sense, not the Lisp sense; it applies to the
+ current Kermit command level, not to the current S-Expression.
+
+ If you want to use SETQ or LET to assign a value to a backslash
+ variable such as \%a or \&a[2], you must double the backslash:
+
+ (setq \\%a 3)
+ (setq \\%b (+ \%a 1))
+ (setq \\&a[2] (setq (\\%c (+ \%a \%b))))
+
+ In other words:
+
+ * Double the backslash when you want to indicate the variable's NAME;
+ * Don't double the backslash when you want its VALUE.
+
+ See [515]Section 9.6 for a fuller explanation of variable syntax and
+ scope.
+
+ Here's a summary table of arithmetic operators; in the examples, a is 2
+ and b is -1.3:
+
+ Operator Description Example Result
+ + Adds all operands (0 or more) (+ a b) 0.7
+ - Subtracts all operands (0 or more) (- 9 5 2 1) 1
+ * Multiplies all operands (0 or more) (* a (+ b 1) 3) -1.80
+ / Divides all operands (2 or more) (/ b a 2) -0.325
+ ^ Raise given number to given power (^ 3 2) 9
+ ++ Increments variables (++ a 1.2) 3.2
+ -- Decrements variables (-- a) 1
+ ABS Absolute value of 1 operand (abs (* a b 3)) 7.8
+ MAX Maximum of all operands (1 or more) (max 1 2 3 4) 4
+ MIN Minimum of all operands (1 or more) (min 1 2 3 4) 1
+ MOD (%) Modulus of all operands (1 or more) (mod 7 4 2) 1
+ FLOAT Convert an integer to floating-point (float 1) 1.0
+ TRUNCATE Integer part of floating-point operand (truncate 3.333) 3
+ CEILING Ceiling of floating-point operand (ceiling 1.25) 2
+ FLOOR Floor of floating-point operand (floor 1.25) 1
+ ROUND Operand rounded to nearest integer (round 1.75) 2
+ SQRT Square root of 1 operand (sqrt 2) 1.414..
+ EXP e (2.71828..) to the given power (exp -1) 0.367..
+ SIN Sine of angle-in-radians (sin (/ pi 2)) 1.0
+ COS Cosine of angle-in-radians (cos pi) -1.0
+ TAN Tangent of angle-in-radians (tan pi) 0.0
+ LOG Natural log (base e) of given number (log 2.7183) 1.000..
+ LOG10 Log base 10 of given number (log10 1000) 3.0
+
+ The ++ and -- operators are also assignment operators and work just
+ like SETQ and LET in their interpretations of operators and operands,
+ but:
+
+ * Each target variable must already be defined and have a numeric
+ value;
+ * The assignment value is the amount by which to increment or
+ decrement the variable.
+ * If an assignment value is not given, 1 is used.
+
+ If you include more than one variable-value pair in a ++ or --
+ expression, every variable (except, optionally, the last) must be
+ followed by a value. Examples:
+
+ (++ a) Equivalent to (setq a (+ a 1)) and to (++ a 1)
+ (++ a 2) Equivalent to (setq a (+ a 2))
+ (-- a (* 2 pi)) Equivalent to (setq a (- a (* 2 pi)))
+ (++ a 1 b 1 c 1 d) Equivalent to four SETQs incrementing a,b,c,d by 1.
+
+ Another group of operators forms the predicates. These return a "truth
+ value", in which 0 (or NIL) is false, and 1 or any other nonzero number
+ is true.
+
+ Operator Description Example Result
+ = (or ==) Operands are equal (= 1 1.0) 1
+ != Operands are not equal (!= 1 1.0) 0
+ < Operands in strictly ascending order (< 1 2 3) 1
+ <= Operands in ascending order (<= 1 1 2 3) 1
+ > Operands in strictly descending order (> 3 2 1) 1
+ >= Operands in descending order (<= 3 3 2 1) 1
+ AND (&&) Operands are all true (and 1 1 1 1 0) 0
+ OR (||) At least one operand is true (or 1 1 1 1 0) 1
+ XOR Logical Exclusive OR (xor 3 1) 0
+ NOT (!) Reverses truth value of operand (not 3) 0
+
+ The Exclusive OR of two values is true if one value is true and the
+ other value is false.
+
+ And another group operates on bits within an integer word:
+
+ Operator Description Example Result
+ & Bitwise AND (& 7 2) 2
+ | Bitwise OR (| 1 2 3 4) 7
+ # Bitwise Exclusive OR (# 3 1) 2
+ ~ Reverses all bits (~ 3) -4
+
+ These operators coerce their operands to integer by truncation if
+ necessary. The result of bit reversal is hardware dependent.
+
+ The final category of operator works on truth values:
+
+ Operator Description Example Result
+ IF Conditional evaluation (if (1) 2 3) 2
+
+ IF (predicate) (s1) [ (s2) ]
+ The IF operator is similar to Kermit's IF command. If the
+ predicate is true (i.e. evaluates to a nonzero number), the
+ first S-Expression (s1) is evaluated and its value is returned.
+ Otherwise, if (s2) is given, it is evaluated and its value
+ returned; if (s2) is not given, nothing happens and the NIL
+ (empty) value is returned.
+
+ You can group multiple expressions in the s1 and s2 expressions using
+ EVAL (or "."):
+
+ (if (< a 0) (eval (setq x 0) (setq y 0)) (eval (setq x a) (setq y b)))
+
+ or equivalently:
+
+ (if (< a 0) (. (setq x 0) (setq y 0)) (. (setq x a) (setq y b)))
+
+ Each operator has its own requirement as to number and type of
+ operands. In the following table, "number" means any kind of number --
+ integer or floating-point -- or a variable, function, macro, or
+ S-Expression that returns a number; "vname" means variable name,
+ "fpnumber" means a floating-point number (or anything that resolves to
+ one), and "integer" means integer (or anything that resolves to one).
+ "truthvalue" means anything that resolves to a value of zero or an
+ empty value (which indicates false) or a nonzero value (which indicates
+ true). "any" means any kind of value, including none at all.
+
+ Operator Number of operands Type of operands Returns
+ EVAL (.) 0 or more S-Expression Last value (default NIL)
+ STRING 1 S-Expression string
+ QUOTE (') 1 word string
+ SETQ 0 or more vname value pairs Last value (default NIL)
+ LET 0 or more vname value pairs Last value (default NIL)
+ + 0 or more number number (default 0)
+ - 0 or more number number (default 0)
+ * 0 or more number number (see note (1))
+ / 2 or more number number
+ ^ 2 or more number number
+ ++ 1 or more vname value pairs Result of last increment
+ -- 1 or more vname value pairs Result of last decrement
+ ABS 1 number number
+ MAX 1 or more number number
+ MIN 1 or more number number
+ MOD (%) 2 number number
+ FLOAT 1 number fpnumber
+ TRUNCATE 1 number integer
+ CEILING 1 number integer
+ FLOOR 1 number integer
+ ROUND 1 number integer
+ SQRT 1 number fpnumber
+ EXP 1 number fpnumber
+ SIN 1 number fpnumber
+ COS 1 number fpnumber
+ TAN 1 number fpnumber
+ LOG 1 number fpnumber
+ LOG10 1 number fpnumber
+ = (==) 1 or more number truthvalue
+ != 1 or more number truthvalue
+ < 1 or more number truthvalue
+ <= 1 or more number truthvalue
+ > 1 or more number truthvalue
+ >= 1 or more number truthvalue
+ AND (&&) 1 or more truthvalue truthvalue
+ OR (||) 1 or more truthvalue truthvalue
+ XOR 2 truthvalue truthvalue
+ NOT (!) 1 truthvalue truthvalue
+ & 1 or more number (see note 2) integer
+ | 1 or more number (see note 2) integer
+ # 2 number (see note 2) integer
+ ~ 1 number (see note 2) integer
+ IF 2 or 3 truthvalue,any,any any
+
+ Operators that don't require any arguments return the default values
+ shown.
+
+ 1. The value of "*", when used as an operand, is initially "1" and the
+ value of the most recent S-Expression thereafter, as in Franz Lisp.
+ This is handy when doing a series of calculations by hand:
+ C-Kermit>(* 13272.42 0.40)
+ 5308.968
+ C-Kermit>(/ * 2)
+ 2654.4840
+ C-Kermit>
+
+ 2. The bitwise operators coerce their operands to integer by
+ truncation.
+
+ [ [516]Top ] [ [517]Contents ] [ [518]C-Kermit Home ] [ [519]Kermit
+ Home ]
+
+9.5. Variables
+
+ As noted elsewhere in this discussion, all backslash items (variables
+ such as \%a, macro parameters such as \%1, array elements such as
+ \&a[\%i], built-in variables such as \v(ndate), built-in functions such
+ as \fjoin(), macro names enclosed in \m(), \s(), or \:(), etc) are
+ evaluated at "top level" before the S-Expression is sent to the
+ S-Expression reader. To use a backslash variable as the target of an
+ assignment (e.g. by SETQ, LET, ++, or --), you must double the
+ backslash, e.g. (setq \\%r 1234). This is discussed at greater length
+ in the next section.
+
+ Thus S-Expression reader generally deals only with macro names (not
+ backslash items) as variables. It is important to understand how the
+ reader handles macro names. There are fundamentally two kinds of
+ S-Expressions: those that contain a single element, such as:
+
+ (foo)
+
+ and those that contain more than one element:
+
+ (foo a b c)
+
+ If an S-Expression contains only one element, and it is the name of a
+ macro, the macro's definition is examined. If the definition is a
+ number (integer or floating-point, positive or negative), then this
+ becomes the value of the expression. If the definition starts with '
+ (apostrophe), then the quoted word or string is the value of the
+ expression (explained in [520]Section 9.8). Otherwise, the macro is
+ assumed to be composed of Kermit commands (possibly including
+ S-Expressions), which are executed. If the macro has a RETURN value, or
+ it executes an S-Expression as its last command, the result becomes the
+ value of the S-Expression; otherwise the result is empty.
+
+ For S-Expressions that contain more than one element, and the first
+ element is the name of a macro, then this macro is executed with the
+ arguments that are given, after the arguments are evaluated by the
+ S-Expression reader. Likewise, If the first element is a built-in
+ operator, then it is applied to the operands after they are evaluated.
+ In both cases, each operand is fed to the S-Expression reader
+ recursively for evaluation. If an operand is a number or a quoted
+ string, it is used as-is. But if it's a macro name, this degenerates
+ into the first case, and the previous paragraph applies.
+
+ Examples:
+
+ define foo 123
+ (foo) Result: 123
+ define foo 'abc
+ (foo) Result: abc
+ define foo '(one two three)
+ (foo) Result: one two three
+ define foo return \frandom(1000)
+ (foo) Result: 713 (or other number)
+ define foo (+ a b)
+ (foo) Result: The sum of a and b
+
+ A more difficult example:
+
+ define foo abc
+ (foo) Result: ???
+
+ The result in the last example depends on the definition of abc:
+
+ * If it has no definition, an error occurs; otherwise:
+ * If the definition is an S-Expression, the result is the
+ S-Expression's value; otherwise:
+ * If the definition consists of Kermit commands, they are executed.
+ But in this case "(foo)" produces the empty result, because it
+ doesn't RETURN anything.
+
+ The use of macros as S-Expression operators is described in
+ [521]Section 9.8.
+
+ [ [522]Top ] [ [523]Contents ] [ [524]C-Kermit Home ] [ [525]Kermit
+ Home ]
+
+9.6. Assignments and Scope
+
+ The assignment operators SETQ and LET apply to global and local
+ variables, respectively. SETQ and LET are standard Lisp operators
+ adapted to Kermit scoping rules. When the operands are numeric or
+ arithmetic, SETQ is equivalent to Kermit's EVALUATE command:
+
+ (setq a (+ 1 2))
+ evaluate a 1 + 2
+
+ When the operand is a string, SETQ is equivalent to DEFINE:
+
+ (setq a '(this is a string))
+ define a this is a string
+
+ In the first case, both statements create a macro named "a" with a
+ value of 3. But in neither case is the macro "a" necessarily global. If
+ either of these commands executes in an environment (i.e. macro
+ invocation level) where a "local a" command has been given, the "a"
+ macro is global to that environment, but is not visible outside it.
+
+ LET is equivalent to the Kermit LOCAL command, followed by the
+ corresponding EVALUATE:
+
+ (let a (+ 1 2))
+
+ is equivalent to:
+
+ local a
+ evaluate a 1 + 2
+
+ Again, "local" in this context applies to the Kermit macro invocation
+ stack, not to the S-Expression nesting level. To illustrate, recall our
+ "newarea" macro:
+
+def newarea {
+ (let a \%1 b \%2 c \%3)
+ (let s (/ (+ a b c) 2.0))
+ (sqrt (* s (- s a) (- s b) (- s c)))
+}
+
+ Because SETQ and LET expressions return a value, they can be placed
+ within a larger S-Expression. In this case we can replace the first
+ reference to the "s" variable by its defining expression:
+
+def newarea {
+ (let a \%1 b \%2 c \%3)
+ (sqrt (* (let s (/ (+ a b c) 2.0)) (- s a) (- s b) (- s c)))
+}
+
+ This would not work if LET were local to the S-Expression, but it works
+ nicely in the context of Kermit macros. The previous definition is
+ equivalent to:
+
+def newarea {
+ local a b c s
+ (setq a \%1 b \%2 c \%3)
+ (sqrt (* (setq s (/ (+ a b c) 2.0)) (- s a) (- s b) (- s c)))
+}
+
+ In both cases, the variables a, b, c, and s are local to the "newarea"
+ macro, and global within it.
+
+ Multiple assignments can be handled in several ways. Here is the
+ obvious way to initialize a series of variables to the same value:
+
+ (setq a 0)
+ (setq b 0)
+ (setq c 0)
+ (setq s 0)
+
+ Here is a more compact and efficient way of doing the same thing:
+
+ (setq a 0 b 0 c 0 s 0)
+
+ However, in case the value was more complex, it's better to put only
+ one copy of it in the S-Expression; in this case we rely on the fact
+ that SETQ returns the value of its last assignment:
+
+ (setq a (setq b (setq c (setq s (* x (^ y 2))))))
+
+ Similarly, to set a series of variables to x, x+1, x+2, ...
+
+ (setq c (+ (setq b (+ (setq a (+ (setq s x) 1)) 1)) 1))
+
+ In the last example, you can see why "last" does not always correspond
+ to "rightmost" (the leftmost variable "c" is assigned last).
+
+ If you are working with backslash variables like \%a or array elements
+ like \&a[1], remember two rules:
+ 1. Don't put spaces inside array brackets.
+ 2. You must double the backslash when using SETQ, LET, ++, or -- to
+ assign a value to a backslash variable.
+
+ Examples of assigning to a backslash variable:
+
+ (setq x 1)
+ (setq \\%a 0)
+ (setq \\&a[x+1] 1)
+ (++ \\%x)
+ (-- \\&a[x+2])
+
+ Examples of referring to a backslash variable's value:
+
+ (setq a (+ \%a 1))
+ (setq b (+ \%a \&a[1]))
+ (++ a \%x)
+ (-- b \&a[1])
+
+ The special notation is required because all backslashed items (\%x
+ variables, array elements, built-in \v(xxx) variables, and \fxxx()
+ function invocations) are evaluated in a single pass BEFORE the
+ S-Expression is executed; any other approach would result in
+ unacceptable performance. So, for example, in:
+
+ declare \&a[] = 1 2 3
+ define \%x 4
+ define \%y 0
+ (setq \\%y (+ \%x \&a[1]))
+
+ the S-Expression becomes:
+
+ (setq \%y (+ 4 1))
+
+ before it is sent to the S-Expression evaluator. If the backslash had
+ not been doubled on the assignment target, the result would have been:
+
+ (setq 0 (+ 4 1))
+
+ which is illegal because you can't assign a value to a number.
+ Conversely, if backslashes were doubled on right-hand-side values:
+
+ (setq \\%y (+ \\%x \\&a[1])
+
+ this too, would give an error (not numeric - "\%x").
+
+ If you omit the double backslash in the assignment target, the result
+ depends on whether the variable already has a value:
+
+ (setq \%a (* 3 3))
+
+ If \%a has a non-numeric single-word value, then this becomes the name
+ of the variable that is assigned by SETQ. To illustrate:
+
+ define \%a foo
+ echo \%a
+ foo
+ (setq \%a (* 3 3))
+ echo \%a
+ foo
+ show macro foo
+ foo = 9
+
+ If \%a has no value, a numeric value, or a multiword value, an "invalid
+ assignment" error occurs.
+
+ [ [526]Top ] [ [527]Contents ] [ [528]C-Kermit Home ] [ [529]Kermit
+ Home ]
+
+9.7. Conditional Expressions
+
+ The IF operator provides a compact form of decision-making within
+ S-Expressions. An IF expression can stand wherever a number might
+ stand, as long is it returns a number. Here's a quick way to obtain the
+ average value of all the elements in an array that contains only
+ numbers:
+
+ (/ (+ \fjoin(&a)) (float \fdim(&a)))
+
+ This results in a "Divide by zero" error if the array is empty. If you
+ want to define the average value of an empty array to be 0 instead of
+ getting an error, you can use IF to check the array size:
+
+ (if \fdim(&a) (/ (+ \fjoin(&a)) (float \fdim(&a))) 0)
+
+ or equivalently:
+
+ (if (not \fdim(&a)) 0 (/ (+ \fjoin(&a)) (float \fdim(&a))))
+
+ Of course, IF can fit anywhere else into an S-Expression:
+
+ (setq a (+ b (if (< c 0) 0 c)))
+
+ and the IF expression can be as complex as you like:
+
+ (setq a (+ b (if (and (or (> x 0) (> y 0)) (< c 0) (> d 1) (!= e 0)) 1 0)))
+
+ and the "then" and "else" parts can contain multiple S-Expressions
+ enclosed within (EVAL ...):
+
+ (if x (eval (...) (...) (...)) (eval (...) (...) (...)))
+
+ AND and OR operators are guaranteed to "short circuit". If any operand
+ of AND is false, none of the subsequent operands is evaluated;
+ likewise, if an OR operand is true, no further operands are evaluated.
+
+ Bear in mind that the S-Expression IF is not the same as Kermit IF; the
+ condition is only allowed to be an S-Expression or a variable or
+ number, not the whole list of possibilities you see when you type "if
+ ?" at the C-Kermit> prompt. But keep reading...
+
+ [ [530]Top ] [ [531]Contents ] [ [532]C-Kermit Home ] [ [533]Kermit
+ Home ]
+
+9.8. Extensibility
+
+ To extend the capabilities of S-Expressions, you can use Kermit macro
+ names as operators, with the following limitations:
+
+ * The macro must not have the same name as a built-in operator.
+ * You must use the full macro name, not an abbreviation.
+
+ And with the following enhancement:
+
+ * If the last statement executed by the macro is an S-Expression, its
+ value is returned automatically. In other words:
+
+ define bump (++ \%1)
+
+ is equivalent to:
+
+ define bump return \fsexpression(++ \%1)
+
+ Here's an example in which we define a FIBONACCI operator that returns
+ the nth element, n >= 0, of the Fibonacci series, 0 1 1 2 3 5 8 13 21
+ 34 55, . . ., in which the first element is 0, the second is 1, and
+ each subsequent element is the sum of the two before it. This series
+ was devised by Leonardo Pisano, Filius Bonacci (Fibonacci for short) in
+ 1202 to describe how fast rabbits can breed, and also forms the basis
+ for the Golden Mean, the branching behavior of plants, the spiral of a
+ nautilus shell, etc. (Thanks to [534]Dat Thuc Nguyen for December 2003
+ corrections to this section!)
+
+ We can write a FIBONACCI function as a macro easily with S-Expressions:
+
+ define FIBONACCI {
+ (if (== \%1 0) 0
+ (if (== \%1 1) 1 (+ (fibonacci (- \%1 2)) (fibonacci (- \%1 1)))))
+ }
+
+ You can read this as:
+
+ If the argument (\%1) is 0, return a result of 0; if it is 1,
+ return 1; otherwise:
+ return the sum of fibonacci(argument - 2) and fibonacci(argument -
+ 1)
+
+ Note that a RETURN statement is not needed, since S-Expressions
+ automatically set the return value of their containing macros.
+
+ For comparison, here's how it would be coded without S-Expressions:
+
+ define FIBONACCI {
+ if == \%1 0 {
+ return 0
+ } else if == \%1 1 {
+ return 1
+ } else {
+ return \feval(\fexec(fibonacci \feval(\%1-2)) -
+ + \fexec(fibonacci \feval(\%1-1)))
+ }
+ }
+
+ Now we can use the FIBONACCI function (whichever way you write it) just
+ as if it were a built-in operator:
+
+ (fibonacci 6)
+
+ Or:
+
+ (setq a 10)
+ (fibonacci a)
+
+ Within S-Expressions only (not outside them), S-Expressions themselves
+ can be used as macro arguments:
+
+ (setq a 2 b 4)
+ (setq x (fibonacci (* a b )))
+
+ The value of the S-Expression (in this case "8"), and not the
+ S-Expression itself, is sent to the macro.
+
+ Your macro is responsible for argument validation and error handling. A
+ robust Fibonacci macro would be more like this:
+
+ define FIBONACCI {
+ if < \v(argc) 2 end 1 ?\%0: Missing argument
+ if > \v(argc) 2 end 1 ?\%0: Too many arguments
+ if not integer \%1 end 1 ?\%0: Integers only
+ if < \%1 1 end 1 ?\%0: Argument out of range
+ (if (== \%1 0) 0
+ (if (== \%1 1) 1 (+ (fibonacci (- \%1 2)) (fibonacci (- \%1 1)))))
+ }
+
+ Recall that "END nonzero-number [ message ]" causes a macro invocation
+ to fail. When the macro is the operator in an S-Expression, this makes
+ the S-Expression fail too. Also note that our Fibonacci macro is just
+ an illustration, not a practical example. Since it is recursive (calls
+ itself), it won't work for large arguments because the call stack can
+ exceed available memory. See [535]Section 9.9.2 for a practical
+ alternative.
+
+ Kermit macros, when used as S-Expression operators, can do anything at
+ all except initiate file transfers: they can print messages on the
+ screen, read and write files, interact with the user, and so on. For
+ example, here's a macro ASKME that asks you to enter a number, makes
+ sure that you did, and then returns its value for use in the
+ S-Expression:
+
+ define ASKME {
+ local \%n
+ while true {
+ ask \%n { Number: }
+ if not def \%n continue
+ if not numeric \%n {
+ echo Not numeric - "\%n"
+ continue
+ }
+ break
+ }
+ return \%n
+ }
+ (setq a (* 2 (askme))) ; Get number from user, double it, assign result to a.
+
+ Here's a macro you can use to validate that a number is in a given
+ range:
+
+ define inrange {
+ if != \v(argc) 4 end 1 ?\%0: Wrong number of arguments
+ if ( < \%1 \%2 || > \%1 \%3 ) return 0
+ return 1
+ }
+
+ The first argument is the number to be checked, the second is the
+ minimum acceptable value, the third is the maximum. You can use this
+ (for example) in IF conditions:
+
+ define yes echo \%1 IS OK
+ define no echo \%1 IS NOT OK
+
+ (setq a -1 b 999)
+ (if (inrange a 0 100) (yes a) (no a))
+ (if (inrange b -1000 +1000) (yes b) (no b))
+
+ This is just an illustration, of course; there's already a built-in
+ operator to let you do range checking without help from macros:
+
+ (if (<= 0 a 100) (yes a) (no a))
+ (if (<= -1000 b +1000) (yes b) (no b))
+
+ To send string parameters to a macro, some kind of quoting is required
+ to tell the S-Expression parser to take a given "word" literally rather
+ than replacing it by its value. For this we use the Lisp QUOTE
+ operator:
+
+ define length return \flength(\%1)
+ (length (quote abcdefghijklmnopqrstuvwxyz))
+ 26
+
+ This causes the string "abcdefghijklmnopqrstuvwxyz" to be sent
+ literally to the LENGTH macro. Kermit, like Lisp, also offers a
+ shortcut for QUOTE, that lets us quote a word by prefixing it with a
+ single quote (') character, also called apostrophe (ASCII 39):
+
+ (length 'abcdefghijklmnopqrstuvwxyz)
+ 26
+
+ The two forms are equivalent.
+
+ How the macro treats its arguments is up to the macro. In the example
+ above, the argument is treated as a literal string. However, it can
+ also be treated as a variable name:
+
+ define string This is a string
+ define length return \flength(\m(\%1))
+ (length 'string)
+ 16
+
+ Note the construct \m(\%1). This means "the value of the macro whose
+ name is the value of
+ \%1". The value of \%1 in this case is the word "string", and the value
+ of the macro whose name is "string" is "This is a string".
+
+ What if the macro takes multiple arguments, or a variable number of
+ them? Here's a simple macro that prints a phrase that includes its
+ arguments:
+
+ define complain echo It's too \%*!
+
+ (Recall that \%* means "all arguments".)
+
+ It can be called in the traditional way:
+
+ complain hot Result: "It's too hot!"
+ complain cold and wet Result: "It's too cold and wet!"
+
+ Or from an S-Expression if you quote the arguments:
+
+ (complain 'hot) Result: "It's too hot!"
+ (complain 'cold 'and 'wet) Result: "It's too cold and wet!"
+
+ To group multiple words into a single argument, use parentheses:
+
+ (complain (quote (cold and wet))) Result: "It's too cold and wet!"
+ (complain '(cold and wet)) Result: "It's too cold and wet!"
+
+ Note the difference:
+
+ (complain 'cold 'and 'wet) Three arguments
+ (complain '(cold and wet)) One argument
+
+ Since the COMPLAIN macro uses \%* to refer to all its arguments, no
+ matter how many, it doesn't care which form you use. But it makes a
+ difference in cases where the macro refers to its arguments
+ individually.
+
+ To illustrate, let's consider a macro that receives the name of a macro
+ and its argument list and executes it with its arguments, without
+ knowing how many arguments there are. The following LOOP macro is used
+ to execute the given macro with the given argument list the requested
+ number of times:
+
+ def loop { local i, for i 1 \%1 1 do \%2 \%3 }
+
+ Within the LOOP macro, the first argument (\%1) is the loop count, \%2
+ is the macro name, and \%3 is the argument list. When the LOOP macro is
+ invoked traditionally like this:
+
+ loop 3 complain hot
+
+ it prints "It's too hot!" three times. To invoke it from an
+ S-Expression, you must quote both the macro name as well as the
+ argument, since in this case the macro name itself is an argument:
+
+ (loop 3 'complain 'hot)
+
+ Now what if you need to send different or variable numbers of arguments
+ to the LOOP macro? The LOOP macro can handle it already, provided you
+ group the arguments into LOOP's third argument (\%3). In Kermit syntax,
+ without grouping:
+
+ loop 3 complain cold and wet
+
+ prints "It's too cold!" three times ("and wet" is lost); but with
+ grouping (either of the following two forms):
+
+ loop 3 complain {cold and wet}
+ loop 3 complain "cold and wet"
+
+ the LOOP macro prints "It's too cold and wet!" three times as desired.
+
+ To do the same thing in an S-Expression, just use the Lisp forms of
+ quoting instead of the Kermit forms; the following two are equivalent:
+
+ (loop 3 'complain (quote (cold and wet)))
+ (loop 3 'complain '(cold and wet))
+
+ Here's a similar example in which we write a macro that shows both the
+ name and the value of one or more other macros, whose names are given
+ as arguments (similar to "show macro"):
+
+ define display {
+ local \%i
+ for \%i 1 \v(argc)-1 1 {
+ echo \&_[\%i] = \m(\&_[\%i])
+ }
+ }
+
+ (Recall that \&_[] is the macro's argument vector array, equivalent to
+ \%1, \%2, ...) The DISPLAY macro can be used in S-Expressions like
+ this:
+
+ (setq a 1 b 2 c 3)
+ (display 'a 'b 'c 'd)
+
+ which prints:
+
+ a = 1
+ b = 2
+ c = 3
+ d =
+
+ The names must be quoted to prevent their evaluation before they are
+ sent to the macro. This ability to pass variables "by name" to macros,
+ rather than by value, lets you write macros that change the values of
+ argument variables. For example, here's a macro that doubles the value
+ of its argument variable:
+
+ define double (++ \%1 \%1)
+
+ which you can call like this:
+
+ (setq a 12)
+ (double 'a)
+
+ In the macro, \%1 is replace by the variable name "a"; "(++ a a)" adds
+ "a" to itself, and sets the value of "a" to the result.
+
+ There are no built-in operators other than QUOTE, ', and STRING for
+ handling strings in S-Expressions, but using just these, plus macros
+ that use Kermit's regular string-handling features, you can easily
+ extend S-Expressions to do string manipulation:
+
+ define len return \flen(\%1) Returns length of argument string
+ define cap return \fupper(\%1) Uppercase argument string
+ define rev return \freverse(\%1) Reverses argument string
+ define sub return \fsubstr(\%1,\%2,\%3) Returns substring of arg string
+
+ (len '(this is a string)) Result: 16
+ (rev '(this is a string)) Result: gnirts a si siht
+ (rev (cap '(this is a string))) Result: GNIRTS A SI SIHT
+ (sub (rev (cap '(this is a string))) 5 9) Result: TS A SI S
+
+ You can assign a string to a macro name as follows:
+
+ (setq foo '(this is a string))
+ (setq foo (quote (this is a string)))
+
+ The two are exactly equivalent. In both cases, the macro "foo" has the
+ value:
+
+ '(this is a string)
+
+ so when it is retrieved it can be identified as a string rather than a
+ number or commands to be executed. Thus:
+
+ (setq foo (quote (this is a string)))
+ show macro foo
+ foo = '(this is a string)
+ (foo)
+ this is a string
+
+ Note the different results for "show macro foo" and "(foo)". The former
+ shows the internal definition; the latter evaluates the variable, which
+ removes the quoting. And perhaps more important, note that if the
+ apostrophe and surrounding parentheses were not stored as part of the
+ definition, (foo) would try to execute "this is a string" as a command.
+
+ Given the assignment above, the following work as expected:
+
+ (len foo) Result: 16
+ (rev foo) Result: gnirts a si siht
+ (rev (cap foo)) Result: GNIRTS A SI SIHT
+ (sub (rev (cap foo)) 5 8) Result: TS A SI S
+
+ Note that, unlike built-in S-Expression operators that return numbers
+ or truth values, these operators return strings. If you want to assign
+ their return values to other variables, you can do so:
+
+ (setq bar (rev (cap foo))) Result: GNIRTS A SI SIHT
+
+ But now the S-Expression processor doesn't know the value of "bar" is
+ supposed to be a string, rather than a macro to execute. For this you
+ need one final special operator, STRING. The STRING operator takes an
+ S-Expression as an operand, evaluates it, and then returns its value
+ enclosed in '(), so you can use the value as a string is subsequent
+ S-Expressions. Use STRING for referencing macros that return strings:
+
+ (setq bar (string (rev (cap foo)))) Result: '(GNIRTS A SI SIHT)
+
+ STRING is like QUOTE, except that it evaluates its operand before
+ applying the quoting, rather than taking the operand literally.
+
+ To reference backslash variables or functions that return string
+ values, you must use the regular quoting mechanisms:
+
+ (setq time '(\v(time)))
+ (setq date '(\v(date)))
+ assign \%r this is a string
+ (setq s1 '(\%r))
+
+ That's because backslash items are evaluated BEFORE the S-Expression
+ parser ever sees them, and the values of \v(time) and so on are not
+ valid S-Expressions, so STRING won't like them.
+
+ Finally a brief word on the touchy topic of quoting. Suppose you want
+ to include (say) literal parentheses in a string that will later be
+ processed by the S-Expression reader (or \fsplit() or \fword()).
+ Normally, you can't do this because parentheses are meaningful in these
+ contexts. To defeat the normal parsing rules, you can quote the
+ parentheses with backslash. However, due to the many levels of string
+ processing involved, a surprisingly large amount of backslashes might
+ be required, for example:
+
+ (setq s '(a b (c d) \\\\\\\\\\\\\\\\(e f (g h) x\\\\\\\\\\\\\\\\) j k))
+
+ This is nearly impossible to explain(*). Instead, just remember two
+ points:
+
+ * In situations like this, it's better to use DEFINE to create the
+ string, rather than SETQ. The example above requires only double
+ backslashes when DEFINE is used:
+ define s '(a b (c d) \\(e f (g h) x\\) j k)
+
+ * The level of quoting depends on how many levels of evaluation the
+ string must pass through, which is not always obvious. However, the
+ number of backslashes required in any given situation is always a
+ power of 2. So if 1 doesn't work, try 2; if 2 doesn't work, try 4;
+ if 4 doesn't work, try 8, 16, 32, and so on.
+
+ Considerations like this apply in any scripting language (shell, Tcl,
+ Perl, Python, etc). The situation is known as "Quoting Hell".
+
+ (*) If you really want an explanation, here it is:
+
+ * Every SEXP has its backslash items evaluated in a single pass at
+ top level before being passed to the SEXP reader, so \%1,
+ \v(ftime), etc, can be evaluated up front, freeing the SEXP reader
+ of having to know about such things, which in turn makes it much
+ more efficient. Therefore one level of quoting is lost right away,
+ and therefore you must double each backslash that is to be used as
+ a quote.
+ * When the SEXP reader sees '\', it treats it as a quote; discards it
+ and keeps the next character. Thus '\\' becomes '\'. This would be
+ the end of it, except that:
+ * The SEXP reader must call itself recursively on its operands, so we
+ must double any quotes in the operands: 2^2 = 4.
+ * If the result is to be passed as an argument to a macro, the
+ backslashes must again be doubled, because the macro processor
+ evaluates the arguments before sending them to the macro: 2^3 = 8.
+ * If the macro itself is to see the quotes, rather than just the
+ result of the quoting, the quotes must be doubled again: 2^4 = 16.
+
+ Moral: To create string constants in which grouping characters must be
+ quoted, use DEFINE rather than SETQ.
+
+ [ [536]Top ] [ [537]Contents ] [ [538]C-Kermit Home ] [ [539]Kermit
+ Home ]
+
+9.9. Examples
+
+9.9.1. Statistics
+
+ The following program computes statistics -- means, maxima, minima,
+ variance, standard deviation, and correlation -- from data stored in
+ parallel arrays, \&x[] and \&y[], which can contain any mixture of
+ integer and floating-point numbers: positive, negative, or zero. Array
+ setup and validation are not shown. Except for the traditional FOR loop
+ and printing the results at the end, the entire computation is done
+ with S-Expressions:
+
+; Initialize sums, maxima, minima, and number of elements
+
+ (setq xsum 0 ysum 0 xsum2 0 ysum2 0 xysum 0)
+ (setq xmin (setq xmax \&x[1]) ymin (setq ymax \&y[1]))
+ (setq n \fdim(&x))
+
+; Loop through elements and accumulate sums, maxima, and minima
+
+ for i 1 n 1 {
+ (setq x \&x[i] y \&y[i]) ; Notational convenience
+ (setq xmax (max xmax x) ymax (max ymax y)) ; X and Y maxima
+ (setq xmin (min xmin x) ymin (min ymin y)) ; X and Y minima
+ (++ xsum x ysum y) ; X and Y sums
+ (++ xsum2 (^ x 2) ysum2 (^ y 2)) ; Sum of X and Y squares
+ (++ xysum (* x y)) ; Sum of XY products
+ }
+
+; Calculate results
+
+ (setq xmean (/ xsum n) ymean (/ ysum n)) ; Mean X and Y
+ (setq xss (- xsum2 (/ (^ xsum 2) n))) ; Intermediate values
+ (setq yss (- ysum2 (/ (^ ysum 2) n)))
+ (setq xyss (- xysum (/ (* xsum ysum) n)))
+ (setq xvar (/ xss n) yvar (/ yss n)) ; X and Y variance
+ (setq sdx (sqrt xvar) sdy (sqrt yvar)) ; Std deviation in X and Y
+ (setq tmp (* xss yss))
+ (setq cc (if tmp (/ xyss (sqrt tmp)) 1.0)) ; Correlation coefficient
+ show macro xmean ymean xvar yvar sdx sdy cc ; Print the results
+
+ The final "if tmp" check accounts for the possibility that both arrays
+ contain all 0's. Results can also be printed with "echo CC = \m(cc)",
+ or any other desired way. Interestingly, if we had not needed the sum
+ of the squares and products, we could have obtained the sums, maxima,
+ and minima of the X's and Y's without a loop like this:
+
+ (setq xsum (+ \fjoin(&x)) ysum (+ \fjoin(&y)))
+ (setq xmax (max \fjoin(&x)) ymax (max \fjoin(&y)))
+ (setq xmin (min \fjoin(&x)) ymin (min \fjoin(&y)))
+
+ Any Kermit function that returns numbers or lists of numbers can be
+ included in an S-Expression as an operand.
+
+9.9.2. Practical Fibonacci Series
+
+ The recursive Fibonacci example given previously is simple and elegant,
+ but not very useful since it causes memory occupation to grow each time
+ it calls itself, until eventually both physical memory and disk swap
+ space are filled and the program crashes. Even for small arguments,
+ like 17, execution time can be prohibitive:
+
+ (setq t1 \v(ftime))
+ (setq result (fibonacci 17))
+ (setq t2 (- \v(ftime) t1))
+ echo FIBONACCI(17) = \m(result): TIME = \ffpround(t2,3)
+
+ prints (on a certain rather slow computer):
+
+ FIBONACCI(17) = 1597: TIME = 5.861
+
+ Any recursive function can be recoded iteratively. The result is not as
+ pretty, but execution is far less expensive:
+
+ define FIBITER {
+ (if (== \%3 0) (\%2) (fibiter (+ \%1 \%2) \%1 (- \%3 1)))
+ }
+ define FIBONACCI {
+ (fibiter 1 0 \%1)
+ }
+
+ Here's the result on the same computer for the same argument of 17:
+
+ FIBONACCI(17) = 1597: TIME = 0.015
+
+ (47 times faster.) Execution time increases proportionally to the size
+ of the argument in the iterative case, whereas in the recursive case it
+ goes up geometrically, quickly reaching infinity.
+
+ [ [540]Top ] [ [541]Contents ] [ [542]C-Kermit Home ] [ [543]Kermit
+ Home ]
+
+9.10. Differences from Algebraic Notation
+
+ In C-Kermit:
+
+ * Algebraic notation uses infix operators and normal rules of
+ operator precedence, with parentheses used to force exceptions to
+ the rules; many operations can be included in an expression.
+ S-Expressions use prefix operators with no intrinsic precedence;
+ each operation is enclosed in parentheses, and the arrangement of
+ parentheses determines precedence.
+ * Algebraic infix operators require two operands; S-Expression prefix
+ operators can accept a variable number of operands.
+ * You can use algebraic notation anywhere that C-Kermit accepts a
+ number, e.g. "echo \&a[((1+1)*2-1]", but you can use S-Expressions
+ only as top-level commands. You can, however, use either algebraic
+ or S-Expressions anywhere at all by enclosing them in \fevaluate()
+ or \fsexpression(), respectively.
+ * You can use any mixture of integer and floating-point numbers in
+ S-Expressions, but only integers are permitted in algebraic
+ expressions. Outside of S-Expressions, floating point arithmetic is
+ supported only by \ffp...() function calls.
+ * Operators and operands in S-Expressions must be separated by
+ spaces, e.g. "(+ a b)". Spaces are not required in algebraic
+ expressions: "((a+b)*c)".
+ * When assigning values to backslash variables (such as \%x or
+ \&a[2]) using SETQ or LET, you must double the backslash.
+
+ [ [544]Top ] [ [545]Contents ] [ [546]C-Kermit Home ] [ [547]Kermit
+ Home ]
+
+9.11. Differences from Lisp
+
+ * Kermit has a lot of built-in operators not found in Lisp: ++, ^,
+ etc.
+ * Most dialects of real Lisp do not allow S-Expressions that don't
+ start with an operator, for example:
+ (a)
+
+ This expression can cause an error in Lisp (even if "a" has a
+ value), but is acceptable in Kermit, where it returns the value of
+ the variable "a". Similarly, (1) returns the value "1".
+ * In real Lisp, EVAL requires exactly one operand. In Kermit, it can
+ have 0, 1, 2, or more operands. It returns the value of the last
+ operand evaluated.
+ * Real Lisp SETQ and LET usually require an even number of operands.
+ Kermit allows an odd number, in which case the last (or only)
+ variable is undefined (i.e. deleted, destroyed).
+ * Kermit does not support ratios such as "7/8". Some Lisp dialects
+ accept ratios as numbers, and generate ratios when told to divide
+ two integers whose quotient is not a whole number; e.g. in Common
+ Lisp:
+ [13] USER(37): (/ (+ 1 2 3 4) 3)
+ 10/3
+ [13] USER(38):
+
+ * The result of (/ 10 3) is 3.333.... Some Lisp dialects truncate the
+ result to 3 since both operands are integers, some don't; some give
+ the result as a ratio. C-Kermit always gives a floating point
+ result when there is a fractional part. If you want an integer
+ result, you can use TRUNCATE, FLOOR, or CEILING, e.g. (truncate (/
+ 10 3)).
+ * There is currently no "bignum" support. Large numbers can be used
+ and large results generated, but (as noted in [548]Section 9.2)
+ they are accurate only to the precision of the underlying machine.
+ \v(math_precision) gives the machine precision as a number of
+ decimal digits, e.g. 16.
+ * Scientific notation for floating-point numbers is not supported. If
+ the magnitude of a number is greater than the precision of the
+ underlying hardware, the less-significant digits are shown but
+ their values are meaningless. If it the number is too small to be
+ represented internally, it is shown as "0.0".
+ * Many Lisp features are omitted: List processing (CAR, CDR, etc),
+ DEFUN, Lisp-specific control structures, and so on.
+
+ [ [549]Top ] [ [550]Contents ] [ [551]C-Kermit Home ] [ [552]Kermit
+ Home ]
+
+10. FILE TRANSFER
+
+ New commands and switches:
+
+ SET TRANSFER REPORT { OFF, ON }
+ Enables or disables the (new) one-line message printed by Kermit
+ after a remote-mode file transfer to indicate the source and
+ destination file, complete with path, to let you know where the
+ file went.
+
+ SEND /TYPE:{TEXT,BINARY}
+ Sends only files of the given type (see [553]Section 4).
+
+ SEND /NOFOLLOWLINKS:
+ (UNIX only) Skip over symbolic links rather than following them
+ (default). This applies to wildcard and/or recursive SENDs; if a
+ single filename is given, and it happens to be a symbolic link,
+ the file it points to is sent.
+
+ SEND /FOLLOWLINKS:
+ (UNIX only) Follow (resolve) symbolic links. Watch out for
+ circular links, endless loops, etc.
+
+ SET SEND I-PACKETS { OFF, ON }
+ When sending commands to a Kermit server, this tells whether
+ command packets should be preceded by an I (information) packet,
+ which is used to synchronize parameters prior to executing the
+ command. Normally ON. The only reason to set this OFF is for
+ communicating with buggy Kermit servers that misbehave when an I
+ packet is sent to them. There is also a SET RECEIVE I-PACKETS
+ command, but presently it has no effect.
+
+ SET TRANSFER MESSAGE [ text ]
+ Sets an initial message to be shown in the Last Message field of
+ the fullscreen file-transfer display.
+
+ SET TRANSFER TRANSLATION { ON, OFF }
+ Inhibits or re-enables text-file transfer character-set
+ translation globally.
+
+ { SEND, MSEND, GET, RECEIVE } /TRANSPARENT
+ Inhibits character-set translation for this transfer only.
+
+ { GET, RECEIVE } /PIPES:{ON,OFF}
+ Overrides global TRANSFER PIPES setting for this transfer only;
+ ON allows incoming files with names like "!tar xf -" to be
+ opened as pipelines rather than regular files.
+
+ The following new "hot keys" are available when Kermit's file-transfer
+ display is visible:
+
+ D: Turn on debugging, open "debug.log" if not already open.
+ d: Turn off debugging but leave log open (if it was open).
+ T: Turn on debug-log timestamps.
+ t: Turn off debug-log timestamps.
+
+ Other improvements:
+ * SET FILE DOWNLOAD-DIRECTORY now works for external protocols (e.g.
+ sz/rz) too.
+ * Improved automatic per-file text/binary switching, described in
+ [554]Section 4.
+ * When sending a file group (e.g. "send *.*"), failure to open a file
+ is no longer fatal; now C-Kermit simply goes ahead to the next
+ file.
+ * Transaction log entries are now made for external protocols too.
+
+ [ [555]Top ] [ [556]Contents ] [ [557]C-Kermit Home ] [ [558]Kermit
+ Home ]
+
+11. MODEMS AND DIALING
+
+ In C-Kermit 8.0, the default modem type for dialing has changed from
+ NONE (= DIRECT, meaning no modem) to GENERIC. This change should have
+ no impact on direct connections. For dialing, it means that, unless you
+ SET MODEM TYPE to a specific type, such as USROBOTICS or CONEXANT,
+ Kermit assumes:
+
+ 1. The modem uses the Hayes AT command set.
+ 2. The modem supports error correction, data compression, and hardware
+ flow control and is already configured to use them.
+
+ In fact, Kermit assumes the modem is completely configured, and
+ therefore does not send it an initialization string or any
+ configuration commands. Instead, it sends only the simplest and most
+ portable commands:
+
+ ATQ0V1 Give dial result codes.
+ ATDTnumber Dial the number.
+
+ (or ATD or ATDP, as appropriate).
+
+ The new defaults work for direct connections and for most modern modems
+ on most platforms, and they work much faster than "full-treatment"
+ dialing. If the new defaults don't work for you, or if you need to
+ perform explicit modem configurations or interactions, then set a
+ specific modem type and use the SET MODEM and SET DIAL commands as
+ documented in Using C-Kermit.
+
+ WARNING: Don't use the generic modem on hosts that do not support
+ RTS/CTS flow control. If Xon/Xoff is in use on the serial port,
+ you'll need to select a particular modem type so Kermit knows what
+ command to give it to enable Xon/Xoff flow control between itself
+ and your serial port.
+
+ The following new modem types were added in C-Kermit 8.0:
+
+ lucent: Lucent Venus chipset
+ pctel: PCTel V.90 chipset
+ conexant: Conexant (ex-Rockwell) modem family
+ zoom-v32bis: New name for "Zoom"
+ zoom-v34 Zoom V.34
+ zoom-v90 Zoom V.90 56K
+ zoom-v92: Zoom V.92 with V.44 data compression
+ zoltrix-v34: New name for "zoltrix"
+ zoltrix-hsp-v90: Synonym for PCTel
+ zoltrix-hcf-v90: Synonym for ITU-T-V250
+ smartlink-v90: Synonym for usrobotics (same chipset)
+ acer-v90: Synonym for Rockwell-v90
+
+ New DIAL-related variables:
+
+ \v(dm_hf): Dial modifier: Wait for Hook-Flash.
+ \v(dm_wb): Dial modifier: Wait for Bong.
+
+ Finally, if dialing fails, Kermit now prints a context-sensitive hint
+ suggesting possible reasons and remedies.
+
+ Added in C-Kermit 8.0.201: Rudimentary support for Caller ID, for use
+ with the ANSWER command. If the modem reports Caller ID information,
+ Kermit stores it in variables that you can access after the call is
+ answered:
+
+ \v(callid_date) The date of the call
+ \v(callid_time) The time of the call
+ \v(callid_name) The name of the caller
+ \v(callid_nmbr) The telephone number of the caller
+ \v(callid_mesg) A message
+
+ The format of these items depends on the originating and answering
+ phone companies and the modems and their configuration.
+
+ Not very many modems support Caller ID, and those that do (a) tend to
+ have it disabled by default, and (b) use different commands to enable
+ it. A quick survey shows of some current models shows:
+
+ - USR V.90: No
+ - ITU-T V.250: No
+ - Lucent Venus: No
+ - Diamond Supra: #CID=1
+ - Rockwell 56K: #CID=1
+ - PCTEL: #CID=1
+ - Zoltrix: +VCID=1
+ - Conexant: +VCID=1
+
+ To use Kermit's Caller ID feature, you have to set the modem to wait
+ for at least two rings before answering, and you have to give the
+ command to enable Caller ID; for example (after choosing a modem with
+ SET MODEM TYPE):
+
+ set modem command autoanswer on ATS0=2#CID=1\{13}
+ set modem command autoanswer on ATS0=2+VCID=1\{13}
+
+ These commands can be undone with:
+
+ set modem command autoanswer on ATS0=1#CID=0\{13}
+ set modem command autoanswer on ATS0=1+VCID=0\{13}
+
+ Kermit presently has no built-in knowledge of the Caller ID
+ capabilities or commands of the modems in its database.
+
+ Since the variables can be accessed only after the call is answered,
+ the only way to refuse a call is to answer it, inspect the variables,
+ and then hang it up if desired.
+
+ [ [559]Top ] [ [560]Contents ] [ [561]C-Kermit Home ] [ [562]Kermit
+ Home ]
+
+12. TERMINAL CONNECTION
+
+ Now that 7-bit connections are no longer the norm, the default terminal
+ bytesize (also called "data size" or "word size") in C-Kermit 8.0 is 8
+ bits, rather than 7 bits as it was in C-Kermit 7.0 and earlier:
+
+ SET ESCAPE character
+ This command, which specifies your CONNECT-mode escape
+ character, allows you to specify any ASCII control character in
+ a variety of formats. C-Kermit 8.0.201 now also lets you specify
+ any 8-bit value, 128-255, as the escape character. In the SET
+ ESCAPE command, you can type the 8-bit character literally or
+ you can enter its numeric code. Here are examples that you can
+ enter from a terminal or console that uses the ISO Latin-1
+ character set:
+
+ C-Kermit> set escape �
+ C-Kermit> set escape 195
+ C-Kermit> show escape
+ Escape character: Code 195 (�): enabled
+ C-Kermit>
+
+ Both of these commands set the escape character value to 195
+ (decimal), which happens to be uppercase letter A with Tilde in
+ Latin-1. SHOW ESCAPE and SHOW TERMINAL show the value, as does
+ the CONNECT message.
+
+ SET TERMINAL AUTODOWNLOAD ERROR { STOP, CONTINUE }
+ When Kermit has a terminal connection to another computer, and a
+ file transfer is initiated automatically because a Kermit packet
+ was received in CONNECT mode (i.e. in the terminal screen), this
+ command tells what Kermit should do if the transfer fails. The
+ default is to STOP, which leaves Kermit in command mode with its
+ file-transfer display showing, so you can see that the transfer
+ failed and why. If you SET TERMINAL AUTODOWNLOAD ERROR CONTINUE,
+ this causes Kermit to return automatically to its terminal
+ screen (i.e. resume its CONNECT session) as if the transfer had
+ succeeded; this can be desirable if the entire session is under
+ control of a host-based script.
+
+ SET TERMINAL BYTESIZE { 7, 8 }
+ The byte size to use during CONNECT and INPUT command execution,
+ which can be more restrictive than the bytesize implied by the
+ current PARITY setting, but not less restrictive. In C-Kermit
+ 7.0 and earlier, the terminal bytesize was 7 by default to
+ protect against the likelihood that parity was in use on the
+ connection without the user's knowledge. When the terminal
+ bytesize is 8 (as it is in C-Kermit 8.0 and later), the user
+ will see garbage in this (increasingly unlikely) situation. Note
+ that 8 data bits are required for most character sets other than
+ ASCII: Latin-1, UTF-8, and so on.
+
+ A new command has been added to produce timestamped session logs:
+
+ SET TERMINAL SESSION-LOG TIMESTAMPED-TEXT
+ Records the terminal session in text mode (like SET TERMINAL
+ SESSION-LOG TEXT) but adds a timestamp at the beginning of each
+ line. The timestamp format is hh:mm:ss.nnn, and indicates the
+ time at which the first character of the line appeared.
+
+ In most UNIX versions (those built with the select()-capable CONNECT
+ module -- pretty much all the ones that have or could have TELNET
+ included), an idle timeout feature has been added:
+
+ SET TERMINAL IDLE-TIMEOUT number
+ If the number is not 0, then Kermit is to take an action when
+ the given amount of time passes with no activity during CONNECT
+ mode. If the number is positive it is the maximum number of idle
+ seconds; if number is negative it represents milliseconds
+ (thousandths of seconds). If 0 is given as the number, there are
+ no idle timeouts. Synonym: SET TERMINAL IDLE-LIMIT.
+
+ SET TERMINAL IDLE-ACTION { RETURN, HANGUP, EXIT, OUTPUT [ string ] }
+ The action to be taken upon an idle timeout in CONNECT mode.
+ RETURN to the prompt, HANGUP the connection, EXIT from Kermit,
+ or OUTPUT the given string (if no string is given, a NUL (ASCII
+ 0) character is sent).
+
+ SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }
+ Actions that can be selected on Telnet connections only, that
+ might be useful if idle limits are enforced by the Telnet server
+ or in the TCP/IP protocol: TELNET-NOP sends a "NO Operation"
+ (do-nothing) command, which causes no response from the server;
+ TELNET-AYT sends an "Are You There" message to the server, which
+ should make the server send back a message. Neither of these
+ actions interferes with your remote session.
+
+ SET TERMINAL IDLE-ACTION is useful for connections to hosts or services
+ that automatically log you out after a certain amount of idle time,
+ e.g.:
+
+ set term idle-timeout 300
+ set term idle-action output \32
+
+ sends a space (as if you had pressed the space bar) every 300 seconds
+ (five minutes) while there is no activity (32 is the ASCII code for
+ space).
+
+ When C-Kermit returns from CONNECT to command mode, the reason for the
+ transition is given in a new variable, \v(cx_status):
+
+ 0 No CONNECT command given yet.
+ 1 User escaped back manually.
+ 2 A trigger string was encountered.
+ 3 IKSD entered server mode.
+ 4 Application Program Command received from host.
+ 5 Idle timeout.
+ 6 Telnet protocol error.
+ 7 Keystroke macro.
+ 8 Time limit exceeded.
+ 100 Internal error.
+ 101 Carrier required by not detected.
+ 102 I/O error on connection.
+ 103 Disconnected by host.
+ 104 Disconnected by user.
+ 105 Session limit exceeded.
+ 106 Rejected due to Telnet policy.
+ 107 Received kill signal.
+
+ Values 100 and above indicate there is no connection.
+
+ [ [563]Top ] [ [564]Contents ] [ [565]C-Kermit Home ] [ [566]Kermit
+ Home ]
+
+13. CHARACTER SETS
+
+ See the section on [567]file scanning above, and the section on
+ character-set conversion in [568]FTP. Also:
+
+ * True support for CP1252 (rather than treating it as Latin-1).
+ * Proper handling of C1 values when converting ISO 8-bit text to
+ UTF-8.
+ * TYPE /CHARACTER-SET: /TRANSLATE-TO: allows specific translations.
+ * The TRANSLATE command now works on multiple files.
+ * K_CHARSET environment variable to set the file character-set.
+ * SET TRANSFER TRANSLATION OFF.
+ * FTP client character-set translation ([569]Section 3.7).
+
+ [ [570]Top ] [ [571]Contents ] [ [572]C-Kermit Home ] [ [573]Kermit
+ Home ]
+
+14. DIALOUT FROM TELNET TERMINAL SERVERS
+
+ For years, C-Kermit has supported dialing out from Telnet modem servers
+ (also called reverse terminal servers or access servers), but until now
+ there was no way for Kermit to control the communication parameters
+ (speed, parity, etc) on the serial port of the terminal server; it had
+ to use whatever was there.
+
+ But now, if you make a connection to a server that supports the Telnet
+ Com Port Control Option, [574]RFC 2217, you have the same degree of
+ control as you would have over a serial port on the computer where
+ Kermit is running: SET SPEED, SET FLOW, SET PARITY, SET STOP-BITS, SHOW
+ COMM, WAIT, SET CARRIER-WATCH, the modem-signal variables, sending
+ Break, and so on, apply to the connection between the terminal server
+ and the modem.
+
+ For example, using a Cisco Access Server 2509, where specifying a TCP
+ port in the 6000's selects a serial port that can be used for dialing
+ out:
+
+ set host xxx 6001 ; xxx is the IP hostname or address of the server
+ (log in if necessary) ; With a script or by hand
+ set modem type usr ; Tell Kermit what kind of modem it has
+ set speed 57600 ; This affects the server's port
+ set flow rts/cts ; Ditto
+ dial 7654321
+
+ The modem server might or might not require a login sequence. It might
+ also allow for automatic authentication, e.g. via Kerberos tickets.
+ NOTE: If the modem server requires a login sequence, then REDIAL might
+ not work as expected.
+
+ When you have a Telnet Com Port connection, your SET SPEED and SET FLOW
+ options change automatically to reflect the capabilities of the server,
+ rather than those of your local computer.
+
+ See the configuration manual for your server for additional
+ information. For example, how to set up the server to drop the Telnet
+ connection automatically when the telephone call is hung up (e.g.
+ "autohangup" on Cisco models).
+
+ For a Linux-based Telnet Com-Port server, click the Sredird link:
+
+ [ [575]Top ] [ [576]Contents ] [ [577]Sredird ] [ [578]C-Kermit Home ]
+ [ [579]Kermit Home ]
+
+15. COPING WITH BROKEN KERMIT PARTNERS
+
+ There are lots of faulty Kermit protocol implementations out there,
+ found mainly in 3rd-party products ranging from communications software
+ packages to file-transfer functions embedded within devices. This topic
+ is covered [580]HERE for C-Kermit 7.0, but C-Kermit 8.0 adds some
+ additional tricks.
+
+ SET ATTRIBUTE RECORD-FORMAT { ON, OFF }
+ Allows control of the Kermit's Record-Format attribute. Set this
+ to OFF in case incoming file are refused due to unknown or
+ invalid record formats if you want to accept the file anyway.
+
+ SET ATTRIBUTES OFF
+ This is not a new trick, but it was recently discovered that the
+ Kermit implementation embedded within a certain kind of
+ punching/bending machine (Salvagnini if you must know) hangs
+ upon reception of standard format Kermit attributes when
+ receiving files. When sending files, it sends attributes of its
+ own, one per A-packet, which is slightly unusual but legal. When
+ receiving files from C-Kermit, K95, MS-DOS Kermit, Kermit-370,
+ etc, it simply exits upon reception of the first A-packet;
+ apparently it was not coded according to the protocol
+ specification, which allows multiple attributes per A-packet.
+ Solution: tell the file sender to SET ATTRIBUTES OFF.
+
+ SET SEND I-PACKETS { ON, OFF }
+ A Kermit server is supposed to accept I-packets; this is how the
+ client lets the server know its capabilities and preferences
+ before sending a command. Apparently there is at least one
+ Kermit server implementation that does not accept I-packets, and
+ does not properly respond with an Error packet if it gets one.
+ To get around such situations in C-Kermit 8.0, you can use SET
+ SEND I-PACKETS OFF to inhibit the sending of I packets. In this
+ case, the client must be able to adjust to the server's
+ configuration, rather than the other way around as we are used
+ to.
+
+ SET PROTOCOL KERMIT {} {} {}
+ C-Kermit 6.0 and later automatically send "autoupload" and
+ "autodownload" commands when in local mode and you give a file
+ transfer command. For example, if you tell kermit to "send
+ oofa.txt", Kermit sends "kermit -r" and a carriage return, in
+ case you had forgotten to start Kermit on the far end and told
+ it to receive a file. If a Kermit program had already been
+ started on the far end, it should harmlessly absorb this string.
+ However, some Kermit programs violate the Kermit protocol
+ definition and treat such strings as Kermit packets even though
+ they are not. In such cases, give this command to set the Kermit
+ protocol autoupload and download strings to nothing, which tells
+ Kermit not to send them. (This is not a new feature, but it was
+ not previously included in the "Coping" section of the
+ documentation.)
+
+ [ [581]Top ] [ [582]Contents ] [ [583]C-Kermit Home ] [ [584]Kermit
+ Home ]
+
+16. NEW COMMAND-LINE OPTIONS
+
+ kermit -h Now prints a complete listing of its command-line options,
+ rather than an abbreviated list squeezed into a 24x80 space.
+
+ -dd Debug, like -d but adds timestamps
+ --version Shows C-Kermit version number.
+ --noperms Equivalent to SET ATTRIBUTE PROTECTION OFF.
+
+ Kermit now accepts a selection of URLs (Universal Resource Locators) as
+ its first command-line argument. These are:
+
+ telnet:hostname
+ Makes a Telnet connection to the given host (IP hostname or
+ address).
+
+ ftp://[user[:password]@]hostname[/path...]
+ Makes an FTP connection to the given host (IP hostname or
+ address). If a username is given, Kermit tries to log you in; if
+ a password is given, it is used; if not, you are prompted for
+ one. If no username is given, an anonymous login is performed.
+ If a pathname is included, Kermit tries to GET the given file.
+ See [585]Section 3.1.3 for details.
+
+ ftps://[user[:password]@]hostname[/path...]
+ Makes a secure FTP connection over SSL.
+
+ telnets://[user[:password]@]hostname
+ Makes a secure Telnet connection over SSL.
+
+ kermit://[user[:password]@]hostname[/path...]
+ Makes a connection to an [586]Internet Kermit Server.
+
+ http://[user[:password]@]hostname[/path...]
+ Makes a connection to Web server.
+
+ https://[user[:password]@]hostname[/path...]
+ Makes a connection to secure Web server.
+
+ [ [587]Top ] [ [588]Contents ] [ [589]C-Kermit Home ] [ [590]Kermit
+ Home ]
+
+17. LOGS
+
+ In C-Kermit 8.0, we make an effort to keep passwords out of the debug
+ log. This can never be 100% effective, but it's better than before,
+ when there were no precautions at all. Whenever Kermit knows it's
+ prompting for, parsing, or transmitting a password, it temporarily
+ turns off logging and then turns it back on afterwards. This keeps the
+ debug log password-free in most common cases, but there can be no
+ guarantees.
+
+ As noted elsewhere, the new "-dd" command-line option selects a
+ timestamped debug log (equivalent to "set debug timestamps on", "log
+ debug debug.log").
+
+ C-Kermit 8.0 also supports a new timestamped session log via "set
+ session-log timestamped-text", "log session".
+
+ There have been requests for other kinds of logs, for example a command
+ log. These might be added at some point. One person wanted to be able
+ to log commands with timestamps, but only commands issued at the
+ prompt, not commands from files or macros, and also wanted a header
+ line at the beginning showing the date, user, and host. This can be
+ done as follows:
+
+ .filename := \v(home)commands.log ; (for example)
+ fopen /write \%c \m(filename)
+ if success {
+ fwrite /line \%c \v(date): User=\v(user) Host=\v(host)
+ fclose \%c
+ set debug timestamps on
+ log debug {| grep "CMD(P)" >> \m(filename)} append
+ }
+
+ [ [591]Top ] [ [592]Contents ] [ [593]C-Kermit Home ] [ [594]Kermit
+ Home ]
+ __________________________________________________________________
+
+
+ C-Kermit 8.0 Update Notes / [595]The Kermit Project / Columbia
+ University / 15 Dec 2003 - 13 Sep 2010
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 12. http://www.columbia.edu/kermit/ckermit.html
+ 13. http://www.columbia.edu/kermit/index.html
+ 14. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+ 15. http://www.columbia.edu/kermit/ckermit80.html
+ 16. mailto:kermit-support@columbia.edu
+ 17. http://www.columbia.edu/kermit/
+ 18. http://www.kermit-project.org/
+ 19. http://www.columbia.nyc.ny.us/kermit/
+ 20. ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
+ 21. ftp://kermit.columbia.edu/kermit/f/ckcmai.c
+ 22. http://www.columbia.edu/kermit/ckermit80.html#xv
+ 23. http://www.columbia.edu/kermit/ck60manual.html
+ 24. http://www.columbia.edu/kermit/ckermi70.html
+ 25. ftp://kermit.columbia.edu/kermit/f/ckermit70.txt
+ 26. http://www.columbia.edu/kermit/ckututor.html
+ 27. ftp://kermit.columbia.edu/kermit/f/ckuker.nr
+ 28. http://www.columbia.edu/kermit/security.htm
+ 29. http://www.columbia.edu/kermit/telnet.htm
+ 30. http://www.columbia.edu/kermit/ftpscripts.html
+ 31. http://www.columbia.edu/kermit/ckcbwr.html
+ 32. ftp://kermit.columbia.edu/kermit/f/ckcbwr.txt
+ 33. http://www.columbia.edu/kermit/ckubwr.html
+ 34. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 35. http://www.columbia.edu/kermit/ckvbwr.html
+ 36. ftp://kermit.columbia.edu/kermit/f/ckvbwr.txt
+ 37. http://www.columbia.edu/kermit/ckuins.html
+ 38. ftp://kermit.columbia.edu/kermit/f/ckuins.txt
+ 39. http://www.columbia.edu/kermit/ckvins.html
+ 40. ftp://kermit.columbia.edu/kermit/f/ckvins.txt
+ 41. http://www.columbia.edu/kermit/ckccfg.html
+ 42. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 43. http://www.columbia.edu/kermit/ckcplm.html
+ 44. ftp://kermit.columbia.edu/kermit/f/ckcplm.txt
+ 45. http://www.columbia.edu/kermit/iksd.html
+ 46. http://www.columbia.edu/kermit/skermit.html
+ 47. http://www.columbia.edu/kermit/ckermit80.html#top
+ 48. http://www.columbia.edu/kermit/ckermit.html
+ 49. http://www.columbia.edu/kermit/index.html
+ 50. http://www.columbia.edu/kermit/ckermit80.html#x0
+ 51. http://www.columbia.edu/kermit/ckermit80.html#x1
+ 52. http://www.columbia.edu/kermit/ckermit80.html#x2
+ 53. http://www.columbia.edu/kermit/ckermit80.html#x2.1
+ 54. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+ 55. http://www.columbia.edu/kermit/ckermit80.html#x2.2.1
+ 56. http://www.columbia.edu/kermit/ckermit80.html#x2.2.2
+ 57. http://www.columbia.edu/kermit/ckermit80.html#x2.2.3
+ 58. http://www.columbia.edu/kermit/ckermit80.html#x2.2.4
+ 59. http://www.columbia.edu/kermit/ckermit80.html#x2.2.5
+ 60. http://www.columbia.edu/kermit/ckermit80.html#x2.2.6
+ 61. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 62. http://www.columbia.edu/kermit/ckermit80.html#x3.1
+ 63. http://www.columbia.edu/kermit/ckermit80.html#x3.1.1
+ 64. http://www.columbia.edu/kermit/ckermit80.html#x3.1.2
+ 65. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 66. http://www.columbia.edu/kermit/ckermit80.html#x3.1.4
+ 67. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 68. http://www.columbia.edu/kermit/ckermit80.html#x3.3
+ 69. http://www.columbia.edu/kermit/ckermit80.html#x3.4
+ 70. http://www.columbia.edu/kermit/ckermit80.html#x3.5
+ 71. http://www.columbia.edu/kermit/ckermit80.html#x3.5.1
+ 72. http://www.columbia.edu/kermit/ckermit80.html#x3.5.2
+ 73. http://www.columbia.edu/kermit/ckermit80.html#x3.5.3
+ 74. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 75. http://www.columbia.edu/kermit/ckermit80.html#x3.6.1
+ 76. http://www.columbia.edu/kermit/ckermit80.html#x3.6.2
+ 77. http://www.columbia.edu/kermit/ckermit80.html#x3.6.3
+ 78. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 79. http://www.columbia.edu/kermit/ckermit80.html#x3.7.1
+ 80. http://www.columbia.edu/kermit/ckermit80.html#x3.7.2
+ 81. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 82. http://www.columbia.edu/kermit/ckermit80.html#x3.9
+ 83. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 84. http://www.columbia.edu/kermit/ckermit80.html#x3.10.1
+ 85. http://www.columbia.edu/kermit/ckermit80.html#x3.10.2
+ 86. http://www.columbia.edu/kermit/ckermit80.html#x3.10.3
+ 87. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 88. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 89. http://www.columbia.edu/kermit/ckermit80.html#x5
+ 90. http://www.columbia.edu/kermit/ckermit80.html#x6
+ 91. http://www.columbia.edu/kermit/ckermit80.html#x6.1
+ 92. http://www.columbia.edu/kermit/ckermit80.html#x6.2
+ 93. http://www.columbia.edu/kermit/ckermit80.html#x6.3
+ 94. http://www.columbia.edu/kermit/ckermit80.html#x6.4
+ 95. http://www.columbia.edu/kermit/ckermit80.html#x6.5
+ 96. http://www.columbia.edu/kermit/ckermit80.html#x6.6
+ 97. http://www.columbia.edu/kermit/ckermit80.html#x7
+ 98. http://www.columbia.edu/kermit/ckermit80.html#x8
+ 99. http://www.columbia.edu/kermit/ckermit80.html#x8.1
+ 100. http://www.columbia.edu/kermit/ckermit80.html#x8.2
+ 101. http://www.columbia.edu/kermit/ckermit80.html#x8.3
+ 102. http://www.columbia.edu/kermit/ckermit80.html#x8.4
+ 103. http://www.columbia.edu/kermit/ckermit80.html#x8.5
+ 104. http://www.columbia.edu/kermit/ckermit80.html#x8.6
+ 105. http://www.columbia.edu/kermit/ckermit80.html#x8.7
+ 106. http://www.columbia.edu/kermit/ckermit80.html#x8.8
+ 107. http://www.columbia.edu/kermit/ckermit80.html#x8.9
+ 108. http://www.columbia.edu/kermit/ckermit80.html#x8.10
+ 109. http://www.columbia.edu/kermit/ckermit80.html#x8.11
+ 110. http://www.columbia.edu/kermit/ckermit80.html#x8.12
+ 111. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 112. http://www.columbia.edu/kermit/ckermit80.html#x8.14
+ 113. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 114. http://www.columbia.edu/kermit/ckermit80.html#x9.1
+ 115. http://www.columbia.edu/kermit/ckermit80.html#x9.2
+ 116. http://www.columbia.edu/kermit/ckermit80.html#x9.3
+ 117. http://www.columbia.edu/kermit/ckermit80.html#x9.4
+ 118. http://www.columbia.edu/kermit/ckermit80.html#x9.5
+ 119. http://www.columbia.edu/kermit/ckermit80.html#x9.6
+ 120. http://www.columbia.edu/kermit/ckermit80.html#x9.7
+ 121. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 122. http://www.columbia.edu/kermit/ckermit80.html#x9.9
+ 123. http://www.columbia.edu/kermit/ckermit80.html#x9.10
+ 124. http://www.columbia.edu/kermit/ckermit80.html#x9.11
+ 125. http://www.columbia.edu/kermit/ckermit80.html#x10
+ 126. http://www.columbia.edu/kermit/ckermit80.html#x11
+ 127. http://www.columbia.edu/kermit/ckermit80.html#x12
+ 128. http://www.columbia.edu/kermit/ckermit80.html#x13
+ 129. http://www.columbia.edu/kermit/ckermit80.html#x14
+ 130. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 131. http://www.columbia.edu/kermit/ckermit80.html#x16
+ 132. http://www.columbia.edu/kermit/ckermit80.html#x17
+ 133. http://www.columbia.edu/kermit/ckermit80.html#top
+ 134. http://www.columbia.edu/kermit/ckermit.html
+ 135. http://www.columbia.edu/kermit/index.html
+ 136. http://www.columbia.edu/kermit/ckuins.html#x5
+ 137. http://www.columbia.edu/kermit/ckuins.html
+ 138. http://www.columbia.edu/kermit/ckermit80.html#x5
+ 139. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+ 140. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 141. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 142. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 143. http://www.columbia.edu/kermit/ckermit80.html#ftpdates
+ 144. http://www.columbia.edu/kermit/ckermit80.html#ftpcheck
+ 145. http://www.columbia.edu/kermit/ckermit80.html#ftpnamelist
+ 146. http://www.columbia.edu/kermit/ckermit80.html#srvrename
+ 147. http://www.columbia.edu/kermit/ckermit80.html#ftpvdir
+ 148. http://www.columbia.edu/kermit/ckermit80.html#setftptype
+ 149. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 150. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 151. http://www.columbia.edu/kermit/ckermit80.html#x8.7
+ 152. http://www.columbia.edu/kermit/ckermit80.html#x2.1
+ 153. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+ 154. http://www.columbia.edu/kermit/ckermit80.html#x8.14
+ 155. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 156. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 157. http://www.columbia.edu/kermit/ckututor.html
+ 158. http://www.columbia.edu/kermit/ckuins.html
+ 159. http://www.columbia.edu/kermit/skermit.html
+ 160. http://www.columbia.edu/kermit/ckermit80.html#setlocus
+ 161. http://www.columbia.edu/kermit/ckermit80.html#lcommands
+ 162. http://www.columbia.edu/kermit/ckermit80.html#ftpuser
+ 163. http://www.columbia.edu/kermit/ckermit80.html#showvar
+ 164. http://www.columbia.edu/kermit/ckermit80.html#callerid
+ 165. http://www.columbia.edu/kermit/ckermit80.html#x6.6
+ 166. http://www.columbia.edu/kermit/ckermit80.html#x0
+ 167. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 168. http://www.columbia.edu/kermit/ckermit80.html#top
+ 169. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 170. http://www.columbia.edu/kermit/ckermit.html
+ 171. http://www.columbia.edu/kermit/index.html
+ 172. http://www.columbia.edu/kermit/ckermit80.html#x0
+ 173. http://www.columbia.edu/kermit/ckermit80.html#top
+ 174. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 175. http://www.columbia.edu/kermit/ckermit.html
+ 176. http://www.columbia.edu/kermit/index.html
+ 177. http://www.columbia.edu/kermit/k95.html
+ 178. http://www.columbia.edu/kermit/sshclient.html
+ 179. http://www.columbia.edu/kermit/skermit.html
+ 180. http://www.columbia.edu/kermit/skermit.html
+ 181. http://www.columbia.edu/kermit/sshclien.htm
+ 182. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 183. ftp://ftp.isi.edu/in-notes/rfc1738.txt
+ 184. http://www.columbia.edu/kermit/ckermit80.html#x2.2.2
+ 185. http://www.columbia.edu/kermit/ckermit80.html#x2.2.1
+ 186. ftp://ftp.isi.edu/in-notes/rfc2396.txt
+ 187. ftp://ftp.isi.edu/in-notes/rfc2616.txt
+ 188. http://www.columbia.edu/kermit/ckermit80.html#x2.2.3
+ 189. ftp://ftp.isi.edu/in-notes/rfc2616.txt
+ 190. http://www.columbia.edu/kermit/ckermit80.html#x8.13.7
+ 191. http://www.columbia.edu/kermit/security.htm#x5.4
+ 192. http://www.columbia.edu/kermit/security.htm#x15
+ 193. http://www.columbia.edu/kermit/security.htm#x6.2
+ 194. http://www.columbia.edu/kermit/security.html
+ 195. http://www.columbia.edu/kermit/ckermit80.html#x16
+ 196. http://www.columbia.edu/kermit/ckermit80.html#top
+ 197. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 198. http://www.columbia.edu/kermit/ckermit.html
+ 199. http://www.columbia.edu/kermit/index.html
+ 200. http://www.columbia.edu/kermit/ckermit80.html#x3.1
+ 201. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 202. http://www.columbia.edu/kermit/ckermit80.html#x3.3
+ 203. http://www.columbia.edu/kermit/ckermit80.html#x3.4
+ 204. http://www.columbia.edu/kermit/ckermit80.html#x3.5
+ 205. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 206. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 207. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 208. http://www.columbia.edu/kermit/ckermit80.html#x3.9
+ 209. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 210. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 211. http://www.columbia.edu/kermit/security.htm
+ 212. http://www.columbia.edu/kermit/security.htm#servers
+ 213. http://www.columbia.edu/kermit/ckcsets.html
+ 214. http://www.columbia.edu/kermit/unicode.html
+ 215. http://www.columbia.edu/kermit/ckermi70.htm#x1.5.4
+ 216. http://www.columbia.edu/kermit/case10.html
+ 217. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 218. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 219. http://www.columbia.edu/kermit/ftpscripts.html
+ 220. http://www.columbia.edu/kermit/ckermit80.html#top
+ 221. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 222. http://www.columbia.edu/kermit/ftpclient.html
+ 223. http://www.columbia.edu/kermit/ftpscripts.html
+ 224. http://www.columbia.edu/kermit/ckermit.html
+ 225. http://www.columbia.edu/kermit/index.html
+ 226. http://www.columbia.edu/kermit/ckermit80.html#x3.1.1
+ 227. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 228. http://www.columbia.edu/kermit/ckermit80.html#x3.1.4
+ 229. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 230. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 231. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 232. http://www.columbia.edu/kermit/ckermit80.html#x3.5
+ 233. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 234. http://www.columbia.edu/kermit/ftpscripts.html
+ 235. http://www.columbia.edu/kermit/ckb2.htm
+ 236. http://www.columbia.edu/kermit/ckermit80.html#ftpautolog
+ 237. http://www.columbia.edu/kermit/ckermit80.html#ftpuser
+ 238. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 239. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 240. http://www.columbia.edu/kermit/ckermit80.html#top
+ 241. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 242. http://www.columbia.edu/kermit/ckermit.html
+ 243. http://www.columbia.edu/kermit/index.html
+ 244. http://www.columbia.edu/kermit/ibm_ie.html
+ 245. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 246. http://www.columbia.edu/kermit/ckermit80.html#top
+ 247. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 248. http://www.columbia.edu/kermit/ckermit.html
+ 249. http://www.columbia.edu/kermit/index.html
+ 250. http://www.columbia.edu/kermit/ck60manual.html
+ 251. http://www.columbia.edu/kermit/ckermit70.html#x4.17
+ 252. http://www.columbia.edu/kermit/ckermit70.html
+ 253. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 254. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 255. http://www.columbia.edu/kermit/ckermit80.html#x3.1.4
+ 256. http://www.columbia.edu/kermit/security.html
+ 257. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 258. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 259. http://www.columbia.edu/kermit/ckermit80.html#x8.13.4
+ 260. http://www.columbia.edu/kermit/ckermit80.html#permswitch
+ 261. http://www.columbia.edu/kermit/ckermit80.html#ftpchmod
+ 262. http://www.columbia.edu/kermit/ckermit80.html#x3.6.2
+ 263. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 264. http://www.columbia.edu/kermit/ckermit80.html#top
+ 265. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 266. http://www.columbia.edu/kermit/ckermit.html
+ 267. http://www.columbia.edu/kermit/index.html
+ 268. http://www.columbia.edu/kermit/ckermit80.html#x7
+ 269. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 270. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 271. http://www.columbia.edu/kermit/ckb2.htm
+ 272. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 273. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 274. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 275. http://www.columbia.edu/kermit/ckermit80.html#setftptype
+ 276. http://www.columbia.edu/kermit/ckermit80.html#top
+ 277. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 278. http://www.columbia.edu/kermit/ckermit.html
+ 279. http://www.columbia.edu/kermit/index.html
+ 280. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 281. http://www.columbia.edu/kermit/ckermit80.html#x3.5.1
+ 282. http://www.columbia.edu/kermit/ckermit80.html#erroraction
+ 283. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 284. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 285. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 286. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 287. http://www.columbia.edu/kermit/ckermi70.htm#x1.5.4
+ 288. http://www.columbia.edu/kermit/ckermi70.htm
+ 289. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 290. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 291. http://www.columbia.edu/kermit/ckermit80.html#x3.5.2
+ 292. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 293. http://www.columbia.edu/kermit/ckermit80.html#erroraction
+ 294. http://www.columbia.edu/kermit/ckermit80.html#x3.5.2
+ 295. http://www.columbia.edu/kermit/ckermit80.html#erroraction
+ 296. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 297. http://www.columbia.edu/kermit/ckermit80.html#ftpperms
+ 298. http://www.columbia.edu/kermit/ckermit80.html#ftpunique
+ 299. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 300. http://www.columbia.edu/kermit/ckermit80.html#note_utc
+ 301. http://www.columbia.edu/kermit/ckermit80.html#note_date
+ 302. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 303. http://www.boulder.nist.gov/timefreq/faq/faq.htm#10:
+ 304. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 305. http://www.columbia.edu/kermit/ckermit80.html#top
+ 306. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 307. http://www.columbia.edu/kermit/ckermit.html
+ 308. http://www.columbia.edu/kermit/index.html
+ 309. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 310. http://www.columbia.edu/kermit/ckermi70.htm#x4.3
+ 311. http://www.columbia.edu/kermit/ckermit70.html
+ 312. http://www.columbia.edu/kermit/ckermit80.html#x5
+ 313. http://www.columbia.edu/kermit/ckermit80.html#x3.6.3
+ 314. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 315. http://www.columbia.edu/kermit/ckermi70.htm#x4.1
+ 316. http://www.columbia.edu/kermit/ckermi70.htm#x4.2.2
+ 317. http://www.columbia.edu/kermit/ckermi70.htm#x1.5.4
+ 318. http://www.columbia.edu/kermit/ckermit80.html#x3.6.2
+ 319. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 320. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 321. http://www.columbia.edu/kermit/ckermit80.html#srvrename
+ 322. http://www.columbia.edu/kermit/ckermi70.htm#x4.1
+ 323. http://www.columbia.edu/kermit/ckermi70.htm
+ 324. http://www.columbia.edu/kermit/ckb2.htm
+ 325. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 326. http://www.columbia.edu/kermit/ckermit80.html#x3.5.3
+ 327. http://www.proftpd.net/
+ 328. http://www.columbia.edu/kermit/ckermit80.html#top
+ 329. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 330. http://www.columbia.edu/kermit/ckermit.html
+ 331. http://www.columbia.edu/kermit/index.html
+ 332. http://www.columbia.edu/kermit/ckb2.htm
+ 333. http://www.columbia.edu/kermit/ckcsets.html
+ 334. http://www.columbia.edu/kermit/unicode.html
+ 335. http://www.columbia.edu/kermit/ckcsets.html
+ 336. http://www.columbia.edu/kermit/ckcsets.html
+ 337. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 338. http://www.columbia.edu/kermit/utf8.html
+ 339. http://www.columbia.edu/kermit/ckcsets.html
+ 340. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 341. ftp://ftp.isi.edu/in-notes/rfc2640.txt
+ 342. http://www.columbia.edu/kermit/ckermit80.html#top
+ 343. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 344. http://www.columbia.edu/kermit/ckermit.html
+ 345. http://www.columbia.edu/kermit/index.html
+ 346. http://www.columbia.edu/kermit/ckermit80.html#top
+ 347. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 348. http://www.columbia.edu/kermit/ckermit.html
+ 349. http://www.columbia.edu/kermit/index.html
+ 350. http://www.columbia.edu/kermit/ckermit80.html#top
+ 351. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 352. http://www.columbia.edu/kermit/ckermit.html
+ 353. http://www.columbia.edu/kermit/index.html
+ 354. http://www.columbia.edu/kermit/ftpscripts.html
+ 355. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 356. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 357. ftp://ftp.isi.edu/in-notes/rfc959.txt
+ 358. http://www.columbia.edu/kermit/ckscripts.html
+ 359. http://www.columbia.edu/kermit/ckermit80.html#top
+ 360. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 361. http://www.columbia.edu/kermit/ftpscript.html
+ 362. http://www.columbia.edu/kermit/ckermit.html
+ 363. http://www.columbia.edu/kermit/index.html
+ 364. http://www.columbia.edu/kermit/ckermit80.html#x3.11.1
+ 365. http://www.columbia.edu/kermit/ckermit80.html#x3.11.2
+ 366. http://www.columbia.edu/kermit/ckermit80.html#x3.11.3
+ 367. http://www.columbia.edu/kermit/ckermit80.html#x3.11.4
+ 368. http://www.columbia.edu/kermit/ckermit80.html#x3.11.5
+ 369. http://www.columbia.edu/kermit/ckermit.html
+ 370. http://www.columbia.edu/kermit/k95.html
+ 371. http://www.columbia.edu/kermit/ckermit80.html#x3.11.5
+ 372. ftp://ftp.isi.edu/in-notes/rfc959.txt
+ 373. ftp://ftp.isi.edu/in-notes/rfc2389.txt
+ 374. http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt
+ 375. http://www.columbia.edu/kermit/ftpclient.html
+ 376. http://www.columbia.edu/kermit/ckermit80.html#top
+ 377. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 378. http://www.columbia.edu/kermit/ckermit.html
+ 379. http://www.columbia.edu/kermit/index.html
+ 380. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 381. http://www.columbia.edu/kermit/ckermit80.html#ucs2
+ 382. http://www.columbia.edu/kermit/ckermit80.html#top
+ 383. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 384. http://www.columbia.edu/kermit/ckermit.html
+ 385. http://www.columbia.edu/kermit/index.html
+ 386. http://www.columbia.edu/kermit/ckermit80.html#top
+ 387. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 388. http://www.columbia.edu/kermit/ckermit.html
+ 389. http://www.columbia.edu/kermit/index.html
+ 390. http://www.columbia.edu/kermit/ckb2.htm
+ 391. http://www.columbia.edu/kermit/ckermit80.html#top
+ 392. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 393. http://www.columbia.edu/kermit/ckermit.html
+ 394. http://www.columbia.edu/kermit/index.html
+ 395. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 396. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 397. http://www.columbia.edu/kermit/ckermit80.html#x8.12
+ 398. http://www.columbia.edu/kermit/ckermit80.html#x8.1
+ 399. http://www.columbia.edu/kermit/ckermit80.html#x12
+ 400. http://www.columbia.edu/kermit/ckermit80.html#x8.12
+ 401. http://www.columbia.edu/kermit/ckermit80.html#top
+ 402. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 403. http://www.columbia.edu/kermit/ckermit.html
+ 404. http://www.columbia.edu/kermit/index.html
+ 405. http://www.columbia.edu/kermit/ckermit80.html#x8.14
+ 406. http://www.columbia.edu/kermit/ckermit80.html#top
+ 407. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 408. http://www.columbia.edu/kermit/ckermit.html
+ 409. http://www.columbia.edu/kermit/index.html
+ 410. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 411. http://www.columbia.edu/kermit/ckermit80.html#top
+ 412. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 413. http://www.columbia.edu/kermit/ckermit.html
+ 414. http://www.columbia.edu/kermit/index.html
+ 415. http://www.columbia.edu/kermit/ckermit80.html#x8.6
+ 416. http://www.columbia.edu/kermit/ckermit80.html#top
+ 417. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 418. http://www.columbia.edu/kermit/ckermit.html
+ 419. http://www.columbia.edu/kermit/index.html
+ 420. http://www.columbia.edu/kermit/ckermit80.html#top
+ 421. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 422. http://www.columbia.edu/kermit/ckermit.html
+ 423. http://www.columbia.edu/kermit/index.html
+ 424. http://www.columbia.edu/kermit/ckermit80.html#top
+ 425. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 426. http://www.columbia.edu/kermit/ckermit.html
+ 427. http://www.columbia.edu/kermit/index.html
+ 428. http://www.columbia.edu/kermit/ckermit80.html#fjoin
+ 429. http://www.columbia.edu/kermit/ckermit80.html#fsplit
+ 430. http://www.columbia.edu/kermit/ckermit80.html#x8.10
+ 431. http://www.columbia.edu/kermit/ckermit80.html#top
+ 432. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 433. http://www.columbia.edu/kermit/ckermit.html
+ 434. http://www.columbia.edu/kermit/index.html
+ 435. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 436. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 437. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 438. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 439. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 440. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 441. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 442. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 443. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 444. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 445. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 446. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 447. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 448. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 449. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 450. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 451. http://www.columbia.edu/kermit/ckermit80.html#x8.10
+ 452. http://www.columbia.edu/kermit/ckermit80.html#x8.7.4
+ 453. http://www.columbia.edu/kermit/ckermit80.html#top
+ 454. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 455. http://www.columbia.edu/kermit/ckermit.html
+ 456. http://www.columbia.edu/kermit/index.html
+ 457. http://www.columbia.edu/kermit/ckermit80.html#top
+ 458. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 459. http://www.columbia.edu/kermit/ckermit.html
+ 460. http://www.columbia.edu/kermit/index.html
+ 461. http://www.columbia.edu/kermit/ckermit80.html#top
+ 462. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 463. http://www.columbia.edu/kermit/ckermit.html
+ 464. http://www.columbia.edu/kermit/index.html
+ 465. http://www.columbia.edu/kermit/ckermit80.html#x8.7
+ 466. http://www.columbia.edu/kermit/ckermit80.html#top
+ 467. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 468. http://www.columbia.edu/kermit/ckermit.html
+ 469. http://www.columbia.edu/kermit/index.html
+ 470. http://www.columbia.edu/kermit/ckermit80.html#scriptedit
+ 471. http://www.columbia.edu/kermit/ckermit80.html#top
+ 472. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 473. http://www.columbia.edu/kermit/ckermit.html
+ 474. http://www.columbia.edu/kermit/index.html
+ 475. http://www.columbia.edu/kermit/ckermit80.html#top
+ 476. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 477. http://www.columbia.edu/kermit/ckermit.html
+ 478. http://www.columbia.edu/kermit/index.html
+ 479. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 480. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 481. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 482. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 483. http://www.columbia.edu/kermit/ckermit80.html#top
+ 484. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 485. http://www.columbia.edu/kermit/ckermit.html
+ 486. http://www.columbia.edu/kermit/index.html
+ 487. http://www.columbia.edu/kermit/ckermit80.html#x8.1
+ 488. http://www.columbia.edu/kermit/ckermit80.html#top
+ 489. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 490. http://www.columbia.edu/kermit/ckermit.html
+ 491. http://www.columbia.edu/kermit/index.html
+ 492. http://www.columbia.edu/kermit/ckermit80.html#x8.2
+ 493. http://www.columbia.edu/kermit/ckermit80.html#top
+ 494. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 495. http://www.columbia.edu/kermit/ckermit.html
+ 496. http://www.columbia.edu/kermit/index.html
+ 497. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 498. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 499. http://www.columbia.edu/kermit/ckermit80.html#x8.2
+ 500. http://www.columbia.edu/kermit/ckermit80.html#top
+ 501. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 502. http://www.columbia.edu/kermit/ckermit.html
+ 503. http://www.columbia.edu/kermit/index.html
+ 504. http://www.columbia.edu/kermit/ckermit80.html#top
+ 505. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 506. http://www.columbia.edu/kermit/ckermit.html
+ 507. http://www.columbia.edu/kermit/index.html
+ 508. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 509. http://www.columbia.edu/kermit/ckermit80.html#top
+ 510. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 511. http://www.columbia.edu/kermit/ckermit.html
+ 512. http://www.columbia.edu/kermit/index.html
+ 513. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 514. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 515. http://www.columbia.edu/kermit/ckermit80.html#x9.6
+ 516. http://www.columbia.edu/kermit/ckermit80.html#top
+ 517. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 518. http://www.columbia.edu/kermit/ckermit.html
+ 519. http://www.columbia.edu/kermit/index.html
+ 520. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 521. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 522. http://www.columbia.edu/kermit/ckermit80.html#top
+ 523. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 524. http://www.columbia.edu/kermit/ckermit.html
+ 525. http://www.columbia.edu/kermit/index.html
+ 526. http://www.columbia.edu/kermit/ckermit80.html#top
+ 527. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 528. http://www.columbia.edu/kermit/ckermit.html
+ 529. http://www.columbia.edu/kermit/index.html
+ 530. http://www.columbia.edu/kermit/ckermit80.html#top
+ 531. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 532. http://www.columbia.edu/kermit/ckermit.html
+ 533. http://www.columbia.edu/kermit/index.html
+ 534. mailto:thucdat@hotmail.com
+ 535. http://www.columbia.edu/kermit/ckermit80.html#x9.9.2
+ 536. http://www.columbia.edu/kermit/ckermit80.html#top
+ 537. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 538. http://www.columbia.edu/kermit/ckermit.html
+ 539. http://www.columbia.edu/kermit/index.html
+ 540. http://www.columbia.edu/kermit/ckermit80.html#top
+ 541. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 542. http://www.columbia.edu/kermit/ckermit.html
+ 543. http://www.columbia.edu/kermit/index.html
+ 544. http://www.columbia.edu/kermit/ckermit80.html#top
+ 545. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 546. http://www.columbia.edu/kermit/ckermit.html
+ 547. http://www.columbia.edu/kermit/index.html
+ 548. http://www.columbia.edu/kermit/ckermit80.html#x9.2
+ 549. http://www.columbia.edu/kermit/ckermit80.html#top
+ 550. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 551. http://www.columbia.edu/kermit/ckermit.html
+ 552. http://www.columbia.edu/kermit/index.html
+ 553. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 554. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 555. http://www.columbia.edu/kermit/ckermit80.html#top
+ 556. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 557. http://www.columbia.edu/kermit/ckermit.html
+ 558. http://www.columbia.edu/kermit/index.html
+ 559. http://www.columbia.edu/kermit/ckermit80.html#top
+ 560. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 561. http://www.columbia.edu/kermit/ckermit.html
+ 562. http://www.columbia.edu/kermit/index.html
+ 563. http://www.columbia.edu/kermit/ckermit80.html#top
+ 564. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 565. http://www.columbia.edu/kermit/ckermit.html
+ 566. http://www.columbia.edu/kermit/index.html
+ 567. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 568. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 569. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 570. http://www.columbia.edu/kermit/ckermit80.html#top
+ 571. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 572. http://www.columbia.edu/kermit/ckermit.html
+ 573. http://www.columbia.edu/kermit/index.html
+ 574. ftp://ftp.isi.edu/in-notes/rfc2217.txt
+ 575. http://www.columbia.edu/kermit/ckermit80.html#top
+ 576. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 577. ftp://kermit.columbia.edu/kermit/sredird/
+ 578. http://www.columbia.edu/kermit/ckermit.html
+ 579. http://www.columbia.edu/kermit/index.html
+ 580. http://www.columbia.edu/kermit/ckermi70.htm#x4.22
+ 581. http://www.columbia.edu/kermit/ckermit80.html#top
+ 582. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 583. http://www.columbia.edu/kermit/ckermit.html
+ 584. http://www.columbia.edu/kermit/index.html
+ 585. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 586. http://www.columbia.edu/kermit/cuiksd.html
+ 587. http://www.columbia.edu/kermit/ckermit80.html#top
+ 588. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 589. http://www.columbia.edu/kermit/ckermit.html
+ 590. http://www.columbia.edu/kermit/index.html
+ 591. http://www.columbia.edu/kermit/ckermit80.html#top
+ 592. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 593. http://www.columbia.edu/kermit/ckermit.html
+ 594. http://www.columbia.edu/kermit/index.html
+ 595. http://www.columbia.edu/kermit/index.html
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckermit90.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit90.txt
new file mode 100644
index 0000000..adf6ee3
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckermit90.txt
@@ -0,0 +1,2152 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+
+ [11]CLICK HERE to read about some of these items.
+
+ [12]Table of platforms [13]Book: Using C-Kermit [14]Download
+ C-Kermit 9.0
+
+C-Kermit 9.0 Update Notes
+
+ Note: C-Kermit 9.0.301 contains a correction that applies only to
+ Solaris 10 and 11.
+ C-Kermit 9.0.302 contains corrections that apply only to FreeBSD 8
+ and 9.
+ * [15]Large Files
+ * [16]How to Test Large-File Transfer
+ * [17]Arithmetic with Large Integers
+ * [18]FORCE-3 Packet Protocol
+ * [19]Variable Evaluation
+
+ * [20]The RENAME Command You Always Wanted
+ * [21]Other New Features
+ * [22]Incompatibilities
+ * [23]What's Not In C-Kermit 9.0
+ * [24]And a Loose End
+
+ * [25]Demonstration: Secure POP mail fetcher
+ * [26]Demonstration: HP Switch Configuration Backup
+ * [27]Demonstration: HP iLO Blade Configuration
+ * [28]Demonstration: IBM/Rolm/Siemens CBX Management
+ * [29]Demonstration: CSV and TSV Files
+ * [30]Demonstration Scripts for Webmasters
+
+ This is the third supplement to [31]Using C-Kermit, Second Edition. I
+ apologize for the scattered nature of the information and I hope I can
+ organize it and gather it all into one place for easy and definitive
+ reference some day. It's a big job so it depends on the demand. For the
+ time being the definitive reference and introduction is the book (which
+ is now available also in a [32]Kindle Edition), plus the [33]C-Kermit
+ 7.0 update, [34]C-Kermit 8.0 update, and now this one. Plus tons of
+ other web pages on this site, sample script programs, and so on.
+
+ In version 6.0, C-Kermit was a pretty powerful and flexible
+ communication program with scripting capabilities. By version 9.0, I'd
+ like to think of it more as a scripting language with built-in
+ communications. You can get an idea of the kinds of programs you can
+ write in Kermit language [35]here. You can develop programs quickly
+ because it's an interactive program, not a compiler. The scripting
+ language is the command language. Kind of like the Unix shell but
+ "somewhat" less cryptic, including concepts not only from C but from
+ PL/I, Snobol, LISP, Bliss, and Smalltalk. The language itself is built
+ upon the command language of the much-loved [36]DECSYSTEM-20 from the
+ 1970s and 80s, the Clipper Ship of the Text Era. (Text is not a bad
+ word. Those of us who can touch-type and who are proficient in
+ text-based computing environments like Unix shell or VMS DCL are likely
+ to be orders of magnitude more productive than users of GUIs.)
+
+ Thanks to (at least) Jeff Altman, William Bader, Ian Beckwith, Nelson
+ Beebe, Gerry Belanger, Joop Boonen, Rob Brown, Christian Corti, Alexey
+ Dokuchaev, John Dunlap, Peter Eichhorn, Carl Friedberg, Terry Kennedy,
+ G�nter Knauf, Jason Lehr, Arthur Marsh, Lewis McCarthy, Gary Mills, Ed
+ Ravin, Jonathan Reams, Mike Rechtman, Mark Sapiro, Steven Schweda
+ (SMS), Kinjal Shah, Michael Sokolov, Andy Tanenbaum, Seth Theriault,
+ Zach A. Thomas, Martin Vorl�nder, and Eric Weaver for assistance, and
+ to Hewlett-Packard Company for support.
+
+ - Frank da Cruz [37]fdc@columbia.edu, 30 June 2011
+
+ P.S. It occurred to me just before the end of the day that maybe I
+ should back up the Kermit website on DVD, just in case. Using
+ [38]Kermit 95 on the desktop over an SSH connection to the Unix file
+ system where the website resides, I made a fresh directory on the PC,
+ CD'd to it, and on Unix cd'd to the Website directory, and told
+ C-Kermit 9.0 to:
+
+C-Kermit> send /recursive /dotfiles /nobackup *
+
+ and it re-created the website directory tree in the PC directory, text
+ files correctly converted to Windows format and binary files correctly
+ left as-is. The /dotfiles switch means to include files such as
+ .htaccess whose names start with a dot (period), and the /nobackup
+ switch means to skip backup files created by EMACs (such as
+ index.html.~243~). And then I did the same with the FTP sites, about
+ 8GB in all. Watching the file-transfer display was kind of like having
+ 30 years of my life flash before my eyes in a few minutes. Then I
+ copied the two directories to DVD (the FTP site had to be split over 2
+ DVDs). The whole operation took under half an hour. The directory tree
+ on the CD is directly usable in Windows, Unix, or any other operating
+ system (unlike if I had transferred the files all in binary mode or all
+ in text mode, or if I had made, say, a gzipped tar archive or a zip
+ archive). I believe that, to this day, Kermit is the only software that
+ can do this. If someday I have to upload from these DVDs to Unix, VMS,
+ or any other operating system, it can be done exactly the same way,
+ with any necessary conversions on text files done automatically, and
+ binary files left intact, recursively through a whole very large
+ directory tree.
+
+What's New in General
+
+ Very briefly, the major items:
+ * [39]Open Source license.
+ * [40]64-bit file access and transfer and 64-bit integer arithmetic
+ on most common platforms.
+ * Support for recent releases of Linux, Mac OS X, *BSD, etc ([41]see
+ table).
+ * Support for newer OpenSSL releases up to and including 1.0.0d
+ ([42]see table).
+ * [43]Strengthened error checking for file transfer under extremely
+ harsh conditions.
+ * [44]Simplified semantics for variables used in scripts.
+ * Super-handy [45]extensions to the RENAME command.
+ * Other scripting improvements including support for reading and
+ writing [46]CSV and TSV files.
+ * [47]MIME character-set names are now recognized.
+ * Improved logging and debugging (see demo [48]here).
+ * Lots more described or listed below, and [49]here.
+
+Open Source License
+
+ C-Kermit 9.0 has the [50]Revised 3-Clause BSD License, an open source
+ license approved by OSI, the [51]Open Source Initiative.
+
+Large Files
+
+ Kermit is, first and foremost, a file-transfer program. One might
+ expect it to be able to transfer any kind of file, but that has been
+ decreasingly the case as file sizes began to cross the 2 gigabyte
+ threshold.
+
+ The biggest change since C-Kermit 8.0.211 is support for large files on
+ platforms that support them. A "large file" is one whose size is
+ greater than 2^31-1 (2,147,483,647) bytes (2GB-1); that is, one whose
+ size requires more than 31 bits to represent. Before now, Kermit was
+ able to access such files only on 100% 64-bit platforms such as Digital
+ Unix, later known as Tru64 Unix. In the new release, Kermit takes
+ advantage of the X/Open Single UNIX Specification Version 2 (UNIX 98)
+ Large File Support (LFS) specification, which allows 32-bit platforms
+ to create, access, and manage files larger than 2GB.
+
+ Accommodating large files required code changes in many modules,
+ affecting not only file transfer, but also file management functions
+ from directory listings to local file manipulation, plus the user
+ interface itself to allow entry and display of large numbers. All this
+ had to be done in a way that would not affect pure 32-bit builds on
+ platforms that do not support large files. Large file support is
+ summarized in the [52]Table of Platforms; entries in Yellow (32-bit
+ builds that support 64-bit integers) and Green (64-bit builds) support
+ large files.
+
+ Note that VMS C-Kermit and Kermit 95 for Windows have always been able
+ to transfer large files. However their user interface used 32-bit
+ integers for statistics and the file transfer display. In C-Kermit 9.0
+ Alpha.03, VMS C-Kermit on 64-bit platforms (Alpha and Itanium) should
+ now give correct statistics and progress displays. (We'll see about
+ Kermit 95 later.)
+
+How to Test Large-File Transfer
+
+ Several methods are available for testing large-file transfers:
+ * By transferring a real file that is more than 2147483648 bytes long
+ (a file whose length requires more than 31 bits to express); or to
+ be totally sure, that is longer than 4294967296 bytes (32 bits or
+ more). Or to be double super sure, longer than 8589934592 (33
+ bits).
+ * If you don't have such a file or there is not sufficient disk space
+ for such a file, you can create a special kind of file that takes
+ up one block on the disk but appears to be 4.3GB long by compiling
+ and running [53]THIS C PROGRAM on Linux, Solaris, HP-UX, or other
+ Unix platform that supports large files. Kermit or FTP or any other
+ file transfer program will transfer the result (BIGFILE) in such a
+ way as to actually put 4.3GB (or other desired size; see source) on
+ the wire.
+ * You can use Kermit's CALIBRATE feature to transfer a large file
+ that doesn't exist. At the receiver, use RECEIVE /CALIBRATE. At the
+ sender, use SEND /CALIBRATE:length, e.g.:
+
+ (At remote kermit...)
+ $ kermit -Y
+ C-Kermit> receive /calibrate
+ (Return to local kermit...)
+ Ctrl-\c
+ C-Kermit> send /calibrate:4300000000
+ This sends a simulated file 4.3GB in length, that does not exist on
+ the sender and will not take up any disk space on the receiver.
+ SEND /CALIBRATE: accepts big numbers only in Kermit versions that
+ support them (this does not include Kermit 95 on Windows). This
+ method tests only Kermit's ability to express and understand large
+ file sizes, but does not test Kermit's file-system interface, since
+ no files are involved.
+
+Arithmetic with Large Integers
+
+ Because large file support requires the availability of a 64-bit signed
+ integer data type, other aspects of C-Kermit were adapted to use it
+ too, most notably Kermit's algebraic expression evaluator and its
+ [54]S-Expression interpreter, on all platforms that support large files
+ (those listed as 64 or 32/64 in the Word column of the [55]table). In
+ fact, every Kermit command that parses a number in any field can now
+ parse a large number on those platforms.
+
+ S-Expressions can now be forced to operate with integers only, without
+ floating-point conversion or having to explicitly truncate each result;
+ as an example. see the revised [56]Easter date calculation script.
+
+FORCE-3 Packet Protocol
+
+ The Kermit protocol has proven itself over the past 30 years to be
+ robust in terms of surviving harsh transmission environments and
+ delivering the data correctly and completely. In these times of
+ Internet everywhere and error-correcting modems in the few places where
+ the Internet isn't, few people even recall the kinds of difficult
+ conditions that were common when the Kermit protocol was first
+ developed: noisy telephone lines, serial interfaces that drop
+ characters, lack of transparency to control or 8-bit characters,
+ absence of flow control, "bare" modems without error correction.
+
+ But the Internet is not everywhere, and not all modems are
+ error-correcting. Perhaps the most difficult trial so far for Kermit or
+ any other protocol is the [57]EM-APEX project, in which floats are
+ dropped into the ocean from an aircraft into the path of a hurricane;
+ these floats dive into the water measuring current, temperature, and
+ salinity at different depths and then surface to phone home, sending
+ the data to land stations using Kermit protocol over
+ non-error-correcting 300bps [58]Iridium satellite modems, with high
+ seas and winds battering the floats and heavy ([59]sometimes
+ electrical) storms between the modem and the satellite.
+
+ Because of the transmission speed and long distances involved, the
+ transfers were very slow. The Kermit software in the floats is
+ [60]Embedded Kermit, which did not implement sliding windows, which
+ would have sped up the flow considerably. John Dunlap, engineer at the
+ University of Washington's Applied Physics Laboratory, undertook the
+ task of adding sliding windows to E-Kermit. For testing, he rigged up a
+ [61]simulator in which Kermit transfers take place over a connection
+ with different amounts of noise and delay. He found that occasionally,
+ a transfer would appear to succeed, but the received file would be
+ corrupt.
+
+ According to the Kermit protocol definition, the first packet always
+ has block-check type 1, a 6-bit checksum, which is the only block check
+ type that all Kermit implementations are required to support; thus any
+ Kermit partner can process this packet. This packet itself can
+ negotiate a higher level of checking, such that subsequent packets have
+ (say) block-check type 3, a 16-bit cyclic redundancy check (CRC)
+ encoded as three printable 7-bit ASCII characters. The 16-bit CRC can
+ catch all errors of certain kinds (single-bit, double-bit, bursts of 16
+ bits or less), and more than 99.9984741210937% of all other possible
+ errors.
+
+ John's simulations revealed that file corruption could occur undetected
+ when the initial packet was corrupted in such a way that a parameter or
+ capability byte was changed and the checksum also changed to make the
+ packet appear to be correct, thus allowing the transfer to proceed with
+ the two Kermit partners out of sync as to packet encoding and
+ interpretation (the chances of two such errors producing a seemingly
+ valid packet are about 1 in 6000 when using the 6-bit checksum). For
+ example, the compression technique might be misnegotiated and then the
+ receiver might store incoming data without decompressing it.
+
+ The solution is a new option, selected by:
+
+ BLOCK-CHECK TYPE 5
+
+ to require a type 3 block check (16-bit CRC) on every packet, including
+ the initial ones, thus reducing the probability of a misnegotiation by
+ many orders of magnitude. THIS PARAMETER CAN NOT BE NEGOTIATED. Each
+ Kermit program must be given the "set block 5" command prior to
+ transfer. That's because normally every Kermit program expects the
+ first packet to have a 6-bit checksum, and if the first packet has a
+ 3-byte, 16-bit CRC, the packet receiver will think it is corrupted.
+
+ In practice, however, it is possible to code the packet receiver
+ "cheat" by reading the packet data before verifying the block check.
+ Thus when the receiver is C-Kermit 9.0 or later or E-Kermit 1.7 or
+ later, it is only necessary to give the "set block 5" command to the
+ file sender, and the receiver will check for a FORCE-3 first packet. If
+ the receiver does not support this feature, however, the initial packet
+ will be be rejected (after several retries) and the file transfer will
+ not take place. There is no attempt to "back off" to normal behavior.
+
+ CAPTION: Table 4. Kermit Protocol Packet Block Check Types
+
+ Type Command Bytes Status Explanation
+ 1 SET BLOCK 1 1 Required in all Kermit implementations. Negotiated.
+ 6-bit checksum, suitable for good connections.
+ 2 SET BLOCK 2 2 Optional, negotiated. 12-bit checksum. 64 times
+ stronger than type 1.
+ 3 SET BLOCK 3 3 Optional, negotiated. 16-bit CRC.
+ BLANK-FREE-2 SET BLOCK 4 2 Optional, negotiated. 12-bit checksum, two
+ nonblank bytes.
+ FORCE-3 SET BLOCK 5 3 Optional, not negotiated. 16-bit CRC forced all
+ packets.
+
+ BLANK-FREE-2 is for environments where Kermit packets are treated as
+ lines of text, and in which trailing blanks can be stripped; for
+ example, when transferring files with an IBM mainframe through a 3270
+ protocol converter.
+ [62]E-Kermit 1.7
+
+Variable Evaluation
+
+ Does the strange behavior of Kermit's \%x variables puzzle or annoy
+ you?
+
+ Kermit software development has been a collaborative project over the
+ years, with contributions coming in from almost every country and every
+ sector of the economy - academic, corporate, government. Thus not all
+ versions, and not all features of a given version, are a product of
+ systematic design.
+
+ One example was the introduction of variables for text substitution,
+ first in a version of MS-DOS Kermit that was sent in by someone
+ somewhere (I could look it up, but no time...) Although the design of
+ the notation for variable names (table below) is mine, the underlying
+ code was contributed. In that code there was only one kind of variable,
+ and if I recall correctly the variable name was a backslash followed by
+ a single letter, for example \a, \b, etc. The contributed code
+ evaluated these variables recursively, meaning if the definition of a
+ variable contained variable references, then these were resolved when
+ dereferencing the variable, and the process would continue as deep down
+ as necessary to resolve the thing fully.
+
+ This was sometimes handy, but it had one severe drawback: There was no
+ way to use variables in a straightforward way to represent strings that
+ contained literal backslashes; for example, DOS or Windows pathnames.
+ This gave rise to all kinds of quoting rules and conventions (e.g.
+ doubling backslashes or forcing single-level evaluation with
+ \\fcontents()), and also to the introduction of other kinds of
+ variables that were evaluated one level deep, rather than recursively.
+
+ To accommodate coexistence of different kinds of variables as well as
+ "escape sequences" for representing control and 8-bit characters, the
+ syntax for variable names was extended to include three elements: the
+ leading backslash, then a single character indicating the type of
+ variable, and then the name of the variable in a format corresponding
+ to the type designator, as shown in this somewhat simplified table:
+
+ CAPTION: Table 1. Variable-name Syntax in Kermit
+
+ Notation Meaning
+ \000 - \255 8-bit character constant (decimal)
+ \d000 - \d255 Alternative notation for 8-bit character (byte) constant
+ (decimal)
+ \o000 - \o377 8-bit character constant (octal)
+ \x00 - \xff 8-bit character constant (hexadecimal)
+ \%a - \%z Scalar variable, evaluated recursively.
+ \%0 - \%9 Macro argument, scalar, evaluated recursively.
+ \&a - \%& Array name
+ \&a[x] Array reference, evaluated recursively (x is any constant or
+ variable)
+ \v(name) Built-in scalar variable, evaluated one level deep.
+ \m(name) User-defined scalar variable, evaluated one level deep.
+ \$(name) An environment variable, evaluated one level deep.
+ \s(name[n:m]) Compact substring notation, evaluated one level deep.
+ \fname(args...) Built-in function with zero or more arguments.
+ \\ Literal backslash
+ \N OUTPUT command only: NUL, ASCII 0
+ \B OUTPUT command only: BREAK (250ms, for serial connections)
+ \L OUTPUT command only: Long BREAK (1.5sec, ditto)
+
+ Variable names in Kermit are case-independent. The simplifications in
+ the table are that the notation for decimal and octal bytes can have
+ from one to three digits, and can include braces to separate them from
+ text digits, e.g. \7, \{123}, \o{50}. Hex bytes too, except they must
+ always have exactly two hex digits, 0-9a-f. Array indices must be, or
+ must evaluate to, numbers (floating point numbers are truncated).
+ Associative arrays are also available (dynamic arrays with arbitrary
+ text as subscript), but they are really just a variation on \m()
+ variables (read about associative arrays [63]here). Also, there are
+ some alternative notations for compact substring notation.
+
+ We didn't want to have lots of "distinguished" characters, as the UNIX
+ shell does; one is enough, clarity over brevity. Although the notation
+ can be a bit cumbersome, we can use the \m(name) form to circumvent the
+ overevaluation in most contexts. But macro arguments are always
+ assigned to the \%0-9 variables, and thus always evaluated recursively,
+ making it difficult and confusing to pass (e.g.) Windows pathnames as
+ arguments to macros. The same is true for array elements, especially in
+ contexts where they are used to return results from built-in functions
+ (for example, \fsplit() used to return the elements of a
+ [64]comma-separated value list if any of the values contained
+ backslashes). An even worse scenario is when macro arguments are passed
+ from one macro to another; for some graphic illustrations see
+ [65]Taming the Wild Backslash - Part Deux from the [66]C-Kermit 7.0
+ Update Notes.
+
+ We can't just change how variables are evaluated because that would
+ break existing scripts. But we can always add Yet Another SET Command:
+
+ SET COMMAND VARIABLE-EVALUATION { RECURSIVE, SIMPLE }
+
+ This applies only to \%a-z and \%0-9 variables and to \&a-z[] arrays
+ (since all other kinds of variables are evaluated only one level deep).
+ The default, of course, for backwards compatibility, is RECURSIVE.
+ SIMPLE forces the evaluation of these variables to return their literal
+ contents, without further evaluation:
+
+ * An exception is made in the case of array subscripts, because
+ changing how they are evaluated could break a lot of scripts, and
+ anyway there should never be any harm in evaluating them
+ recursively because their final value is always (or should be)
+ numeric, not some string that might contain backslashes.
+ * The VARIABLE-EVALUATION setting is on the command stack. Thus you
+ can give this command in a macro, command file, or user-defined
+ function without affecting the calling environment.
+ * The new \frecurse() function forces recursive evaluation of its
+ argument regardless of the VARIABLE-EVALUATION setting. The
+ argument can be any string (or nothing at all); all the variables
+ in the string, even \m() ones, are evaluated recursively:
+
+def \%a 1 \%b 3
+def \%b 2
+def xx easy as \%a
+show mac xx
+echo \frecurse(\m(xx))
+easy as 1 2 3
+echo \frecurse(it's as easy as \m(xx))
+it's as easy as easy as 1 2 3
+
+ * The new \v(vareval) built-in variable contains the current setting
+ (recursive or simple) at the current command-stack level.
+
+ Here's a short script for illustration:
+
+define path c:\users\fdc\somefile.txt
+define test1 { # Normal recursive argument evaluation
+ echo \%0: arg=\%1
+}
+define test2 { # Simple argument evaluation
+ set var simple
+ echo \%0: arg=\%1
+}
+test1 \m(path)
+test2 \m(path)
+exit
+
+ And here's the result:
+
+?<ERROR:NO_SUCH_FUNCTION:\fdc\somefile.txt()>
+test2: arg=c:\users\fdc\somefile.txt
+
+ The first line might seem surprising, but under the normal rules (see
+ table above) \f indicates a function call, with the letters following
+ the 'f' being the name of the function. But there is no function by
+ that name... and if there were, you probably didn't intend to call it!
+
+ SET COMMAND VARIABLE-EVALUATION SIMPLE has no effect on constants, only
+ on variables. Note how \m(path) is defined. The DEFINE command assigns
+ the literal value of its argument to the named variable (see Table 3
+ below), thus in this case no special syntax is needed. But in other
+ contexts, you must double the backslashes or use the \fliteral()
+ function to use literal backslashes in data:
+
+test2 c:\\users\\fdc\\somefile.txt
+test2 \fliteral(c:\users\fdc\somefile.txt)
+
+ C-Kermit 9.0 adds a new notation for \fliteral() which also has certain
+ advantages over it: \q(string):
+
+test2 \q(c:\users\fdc\somefile.txt)
+
+ Since \fliteral() is a function, its argument list (the text within
+ parentheses) has special syntax of its own, in which commas and braces
+ are treated specially and introduce another set of quoting problems.
+ \q(string) doesn't have these problems. The only consideration is that
+ parentheses must be balanced or else quoted (preceded by backslash), or
+ represented as numeric character entities (left paren = \40, (right
+ paren = \41).
+
+ Or else hold the value in a simple variable as we did with \\m(path)
+ above.
+
+ SET COMMAND VARIABLE-EVALUATION SIMPLE is a big change and might have
+ repercussions that didn't show up in the initial tests; a lot more
+ testing is needed.
+
+ On the topic of variables, let's summarize in one place the ways in
+ which values can be explicitly assigned to variables. There is nothing
+ new here except the table itself:
+
+ CAPTION: Table 2. Variable Assignment in Kermit
+
+ Command Shorthand Explanation
+ DEFINE name value .name = value The literal value becomes the contents
+ of the named variable; variables names in the value are copied without
+ evaluation. This command is for defining macros that take parameters,
+ as well as for defining simple variables, especially if the values
+ contain backslashes.
+ _DEFINE name value Like DEFINE but the name is evaluated before use.
+ ASSIGN name value .name := value The value is evaluated and the result
+ becomes the contents of the named variable.
+ _ASSIGN name value Like ASSIGN but the name is evaluated before use.
+ EVALUATE name expression .name ::= value The expression (in regular
+ algebraic notation) is evaluated arithmetically and the result becomes
+ the contents of the named variable. If the expression contains any
+ variables they are evaluated first.
+ _EVALUATE name expression Like EVALUATE but the name is evaluated
+ before use.
+ INCREMENT name expression Evaluates the variables in the expression,
+ then evaluates the expression arithmetically, and then adds the value
+ to the contents of the named variable, which must be a number or an
+ algebraic expression. If the expression is empty, a value of 1 is used.
+ _INCREMENT name expression Like INCREMENT but the name is evaluated
+ before use.
+ DECREMENT name expression Evaluates the variables in the expression,
+ then evaluates the expression arithmetically, and then subtracts the
+ value from the contents of the named variable, which must be a number
+ or an algebraic expression. If the expression is empty, a value of 1 is
+ used.
+ _DECREMENT name expression Like DECREMENT but the name is evaluated
+ before use.
+ DECLARE name = list An array declaration can include an initializer
+ list; items in the list are evaluated before assignment. This can be
+ defeated by doubling any backslashes or enclosing individual arguments
+ in \fliteral().
+ DO name arguments name arguments When invoking a macro with a DO
+ command (or an implied one), the arguments are evaluated, then assigned
+ to \%1, \%2, etc, and the macro's name to \%0.
+ (SETQ name value) Kermit also includes a mini-[67]LISP interpreter
+
+ Variables are evaluated automatically in Kermit commands simply by
+ referencing them, according to rules given in Table 1. The following
+ functions can be used to change how a a particular variable is
+ evaluated:
+
+ CAPTION: Table 3. Kermit Functions for Evaluating Variables
+
+ Function Argument Description
+ \fcontents() \%x or \&x[y] Evaluates the variable or array element
+ (which normally would be evaluated recursively) one level deep.
+ \fdefinition() name If the argument is a \%x variable or an array
+ element, it is evaluated to get the name; otherwise the argument is the
+ name. Its definition is returned with no recursion.
+ \m() name Equivalent to \fdefinition().
+ \frecurse() \m(name) Forces recursive evaluation of a macro definition
+ (a.k.a. long variable name). NOTE: \frecurse() can operate on any kind
+ of variable as well as on any string containing any mixture of
+ variables.
+
+C-Kermit's RENAME Command
+
+ C-Kermit's RENAME command, which is used for changing the names of
+ local files or for moving files locally, has two basic forms:
+
+ RENAME [ optional-switches ] oldfilename newfilename
+ This form lets you change the name of a single file from
+ oldfilename to newfilename. Example:
+ rename thismonth.log lastmonth.log
+
+ RENAME [ optional-switches ] filespec directoryname
+ This form lets you move (without renaming) one or more files
+ (all the files that match the filespec, which may contain
+ wildcard characters such as "*") to the given directory.
+ Example:
+ rename *.txt ~/textfiles/
+
+ Traditionally, the optional switches have been:
+
+ RENAME /LIST oldname newname
+ Display the old and new name for each file while renaming.
+ Synonyms: /LOG, /VERBOSE. Example:
+ rename /list *.txt ~/textfiles/
+
+ RENAME /NOLIST oldname newname
+ Don't display the old and new name for each file while renaming.
+ This is the default behavior. Synonyms: /NOLOG, /QUIET. Example:
+ rename /nolist *.txt ~/textfiles/
+
+ Reminder: Every switch starts with a slash (/) and must be preceded by
+ a space.
+
+New RENAME Features for C-Kermit 9.0
+
+ A series of new options (switches) have been added to let you change
+ the names of multiple files at once by case conversion, string
+ substitution, or character-set conversion, and optionally also move
+ them to a different directory:
+
+ /LOWER: Convert the filename to lowercase
+ /UPPER: Convert the filename to uppercase
+ /CONVERT: Change the filename's character encoding
+ /REPLACE: Do string substitutions on the filename
+
+ If the source-file specification includes a path or directory, any
+ changes are applied to the filenames only, not to the directory or path
+ specification.
+
+ Since name changes, when applied to many files at once, can have
+ consequences that are not easily undone, there are also some new
+ controls, safeguards, and conveniences:
+
+ RENAME /SIMULATE
+ This switch tells Kermit to show you what the RENAME command
+ would do without actually doing it. /SIMULATE implies /LIST.
+
+ RENAME /COLLISION:{FAIL,SKIP,OVERWRITE}
+ This switch governs Kermit's behavior when renaming multiple
+ files, and any of the names would collide with the name of a
+ file that already exists. The default, for compatibility with
+ earlier releases of C-Kermit, is OVERWRITE, i.e. write over the
+ existing file. The other two protect existing files. SKIP means
+ to skip (not rename) the file that would cause the collision,
+ and proceed to the next file, if any. FAIL means that no files
+ will be renamed if there would be any collisions; for this
+ Kermit makes two passes, checking each new name it constructs
+ for existence before starting the second pass (however, there is
+ no guarantee that in the second pass, it won't create the same
+ new name for more than one file; in that case, it will stop
+ before executing the second rename). Example:
+ rename /simulate /collision:proceed * ~/tmp/
+
+ Reminder: In switches such as /COLLISION that take arguments
+ (operands), the switch name and its argument(s) are separated by a
+ colon (:) with no intervening spaces. Also remember that Kermit
+ keywords can always be abbreviated by leaving off characters from the
+ right, as long as the result is still unique in its context. Thus "ren
+ /col:f" would be equivalent to "rename /collision:fail".
+
+ You can change the following preferences for the RENAME command with
+ the new SET RENAME command:
+
+ SET RENAME LIST { ON, OFF }
+ Tells the RENAME command whether to list its actions if you
+ don't include a /LIST or /NOLIST or equivalent switch.
+
+ SET RENAME COLLISION { FAIL, OVERWRITE, SKIP }
+ Tells the RENAME command how to handle filename collisions in
+ the absence of a /COLLISION switch. That is, it replaces the
+ default action of OVERWRITE with action of your choosing, which
+ is then used in any RENAME command that does not include an
+ explicit /COLLISION switch.
+
+ SHOW RENAME
+ Displays the current SET RENAME settings.
+
+Changing the Case of Filenames
+
+ RENAME /UPPER:{ALL,LOWER} filespec [ directory ]
+ RENAME /LOWER:{ALL,UPPER} filespec [ directory ]
+ These switches let you change the alphabetic case of letters in
+ all the files whose names match the filespec. If a directory
+ name is given after the filespec, then the files are also moved
+ to the given directory.
+
+ By default, all files that match the given filespec have their names
+ changed (if necessary). This is what the ALL argument means, e.g.:
+
+ RENAME /LOWER:ALL *
+ RENAME /LOWER *
+
+ You can use either form: RENAME /LOWER is equivalent to RENAME
+ /LOWER:ALL. The other argument (/LOWER:UPPER or /UPPER:LOWER) means to
+ leave mixed-case filenames alone, and rename only those files whose
+ names contain letters of only the given case. Examples:
+
+ RENAME /UPPER:ALL foo.bar
+ Changes the filename to FOO.BAR.
+
+ RENAME /UPPER foo.bar
+ Same as "rename /upper:all foo.bar".
+
+ RENAME /UPPER foo.bar ~/old/
+ Renames foo.bar to FOO.BAR and moves it to the user's old
+ directory (Unix).
+
+ RENAME /LOWER *
+ Changes the names of all files to have only lowercase letters.
+
+ RENAME /LOWER:UPPER *
+ Changes the names of only those files whose names contain no
+ lowercase letters to have only lowercase letters. For example,
+ FOO.BAR would be changed, Foo.Bar would not be changed. foo.bar
+ would not be changed either because it's already all lowercase.
+
+ RENAME /LOWER:UPPER * ~/new/
+ Same as the previous example, but also moves each file to the
+ user's new directory (whether it was renamed or not).
+
+ Case conversion works reliably for ASCII characters only. Kermit uses
+ the C library for this, which on any given platform might or might not
+ handle non-ASCII letters, and if it does, then how it works would
+ normally depend on your locale definitions (the LC_CTYPE and/or LANG
+ environment variable in Unix). When non-ASCII letters are not handled
+ by the C library, the RENAME command does change their case. For
+ example, Olga_Ta��n.txt might become OLGA_TA��N.TXT.
+
+String Replacement in Filenames
+
+ The RENAME command also lets you change filenames by string
+ substitution.
+
+ RENAME /FIXSPACES[:String] filespec [ directory ]
+ Replaces all spaces in each matching filename by the given
+ string, if any, or if none is given, by underscore. Examples:
+
+ RENAME /FIX *
+ RENAME /FIXSPACES:_ *
+ RENAME /FIXSPACES:"" *
+ RENAME /FIXSPACES:<040> *
+
+ The first two are equivalent, replacing each space with
+ underscore; a file called "My Favorite Photo.jpg" becomes
+ "My_Favorite_Photo.jpg". The third example removes all spaces
+ ("MyFavoritePhoto.jpg"). The fourth replaces each space with the
+ string "<040>" ("My<040>Favorite<040>Photo.jpg").
+
+ RENAME /REPLACE:{{String1}{String2}} filespec [ directory ]
+ Renames each matching file by changing occurrences of String1 in
+ its name to String2. If a directory specification is included,
+ the file is also moved to the given directory (even if the name
+ was not changed). Note that in this case, the curly braces are
+ part of the command. Example:
+
+ RENAME /REPLACE:{{.jpeg}{.jpg}} *
+
+ changes all *.jpeg files to *.jpg.
+
+ By default, RENAME /REPLACE changes all occurrences of String1 in each
+ filename to String2 so, for example, if you had a file called
+ abcjpegxyz.jpeg, the command just shown would change its name to
+ abcjpgxyz.jpg.
+
+ For greater control and flexibility, the /REPLACE: switch argument can
+ take several distinct forms:
+
+ RENAME /REPLACE:String1 filespec [ directory ]
+ This means to remove all occurrences of String1 from the given
+ filenames name. It is equivalent to /REPLACE:{{String1}{}}. A
+ handy use for this option is to remove spaces from filenames.
+
+ RENAME /REPLACE:{{String1}{String2}} filespec [ directory ]
+ As already noted, this replaces every occurrence of String1 with
+ String2 in each filename. Alphabetic case in string matching is
+ done according to the current SET CASE setting.
+
+ RENAME /REPLACE:{{ }{_}} filespec [ directory ]
+ This replaces all spaces in the given filenames with underscore,
+ equivalent to RENAME /FIXSPACES.
+
+ RENAME /REPLACE:{{String1}{String2}{Options}} filespec [ directory ]
+ Options can be included that add more control to the process.
+ The option string is a sequence of characters; each character in
+ the string is an option. The choices are:
+
+ A String matching is to be case-sensitive, regardless of SET CASE.
+ a String matching is to be case-independent, regardless of SET CASE.
+ ^ String replacement will occur only at the beginning of the filename.
+ $ String replacement will occur only at the end of the filename.
+ 1 Only the first occurrence of the string will be replaced.
+ 2 Only the second occurrence of the string will be replaced.
+ 3 4 5 6 7 8 ...
+ 9 Only the ninth occurrence of the string will be replaced.
+ - (hyphen, minus sign) Before a digit: occurrences will be counted from
+ the right.
+ ~ (tilde) Before digit or minus sign: all occurrences but the given one
+ will be replaced.
+
+ The tilde modifier works only with single-byte character sets such as
+ ASCII, CP437, ISO 8859-1, etc, but not with multibyte character sets
+ such as UCS2, UTF8, or any of the Japanese Kanji sets.
+
+ Here are some examples showing how to use the /REPLACE options:
+
+ RENAME /REPLACE:{{foo}{bar}{^}} *
+ For all files whose names start with "foo", replaces the "foo"
+ at the beginning with "bar".
+
+ RENAME /REPLACE:{{}{New-}{^}} *
+ Prepends "New-" to the name of each file.
+
+ RENAME /REPLACE:{{.jpeg}{.jpg}{$}} *
+ Replaces ".jpeg" at the end of each filename with ".jpg".
+
+ RENAME /REPLACE:{{}{-Old}{$}} *
+ Appends "-Old" to the name of each file.
+
+ RENAME /REPLACE:{{foo}{bar}{a}} *
+ Replaces "foo", "FOO", "Foo", "fOO", etc, with "bar" in each
+ filename.
+
+ RENAME /REPLACE:{{foo}{bar}{A}} *
+ Replaces only (lowercase) "foo" in filenames with "bar".
+
+ RENAME /REPLACE:{{a}{XX}} *
+ Changes every "a" to "XX". For example a file called "a.a.a.a"
+ would become "XX.XX.XX.XX".
+
+ RENAME /REPLACE:{{a}{X}{2}}
+ Changes only the second "a" to "X". For example a file called
+ "a.a.a.a" would become "a.X.a.a".
+
+ RENAME /REPLACE:{{a}{X}{-1}}
+ Changes only the final "a" in the filename (it doesn't have to
+ be at the end) to "X". For example a file called "a.b.a.c.a.d"
+ would become "a.b.a.c.X.d".
+
+ RENAME /REPLACE:{{foo}{NOTFOO}{-2}}
+ Changes the second-to-last "foo" (if any) in the filename to
+ "NOTFOO".
+
+ RENAME /REPLACE:{{foo}{}{-2}}
+ Deletes the second-to-last "foo" (if any) from the filename.
+
+ RENAME /REPLACE:{{.}{_}{~1}}
+ Changes all but the first period to an underscore; for example,
+ "a.b.c.d.e" would become "a.b_c_d_e".
+
+ RENAME /REPLACE:{{.}{_}{~-1}}
+ Changes all but the final period to an underscore; for example,
+ "a.b.c.d.e" would become "a_b_c_d.e".
+
+ In the Options field, digits (and their modifiers), ^, and $ are
+ mutually exclusive. If you include more than one of these in the option
+ string, only the last one is used. Similarly for 'a' and 'A':
+
+ RENAME /REPLACE:{{foo}{bar}{Aa2$^}} *
+ This replaces "foo" with "bar" no matter what combination of
+ upper and lower case letters are used in "foo" ('a' overrides
+ 'A' in the option string), but only if "foo" is at the beginning
+ of the filename ('^' overrides '$' and '2').
+
+ If you give an /UPPER or /LOWER switch and a /REPLACE switch in the
+ same RENAME command, the /REPLACE action occurs first, then the case
+ conversion:
+
+ RENAME /REPLACE:{{foo}{bar}} /UPPER * /tmp
+ For each file: changes all occurrences of "foo" in the name to
+ "bar", then converts the result to uppercase, and then moves the
+ file to the /tmp directory. So (for example) "foot.txt" would
+ become "/tmp/BART.TXT".
+
+Changing the Character Encoding of Filenames
+
+ As you know, text is represented on the computer as a series of
+ numbers, with a given number corresponding to a given character
+ according to some convention or standard. Filenames are represented the
+ same way. The trouble is, different computers, or even different
+ applications on the same computer, might use different standards or
+ conventions ("character sets") for representing the same characters.
+ Usually ASCII is safe, but anything beyond that -- non-ASCII characters
+ such as accented or non-Roman letters -- is likely to vary. Sometimes
+ you have text that's in the "wrong" character set and you need to
+ convert it to something you can can use. Kermit has always been able to
+ handle this as part of file transfer and terminal emulation, as well as
+ being able to convert text files locally with its TRANSLATE command.
+ Now there's a way to convert filenames too, for example after copying
+ files from a CD that uses a different encoding:
+
+ RENAME /CONVERT:charset1:charset2 filespec [ directory ]
+ Converts filenames from the first character set to the second
+ one. The two character sets can be chosen from the SET FILE
+ CHARACTER-SET list; for complete details see [68]this page. For
+ example suppose you have a file called "Olga_Ta��n.txt" on a
+ computer where ISO 8859-1 Latin Alphabet 1 is used, and you have
+ transported it (e.g. on CDROM) to another computer where the
+ text encoding is UTF8. Maybe you also have a lot of other files
+ with similar names in the same directory. You can convert the
+ filenames to UTF8 like this:
+
+ RENAME /CONVERT:latin1:utf8 *
+
+ /CONVERT can not be combined with /UPPER, /LOWER, or /REPLACE.
+
+ You should NOT use UCS2 for filenames since this encoding is not
+ compatible with C strings used in Unix and elsewhere.
+
+ RENAME /CONVERT affects only the filename, not the file's contents. You
+ can use the TRANSLATE command to convert the encoding of the contents
+ of a text file.
+
+Other New Features
+
+ See the [69]C-Kermit Daily Builds page for details. Very briefly:
+
+ * Perhaps most important, modernized makefile targets for the major
+ Unix platforms: Linux, Mac OS X, AIX, Solaris, etc. These are
+ somewhat automated; not autoconf exactly, but they cut down
+ significantly on redundant targets. For example, one single "linux"
+ target works on many (hopefully all) different Linux
+ configurations, where before different targets were required for
+ different combinations of (e.g.) curses / ncurses / no curses;
+ 32-bit / 64-bit; different feature sets and library locations.
+ (Separate targets are still required for Kerberos and/or SSL
+ builds, but they are "subroutinized".)
+ * Bigger buffers, more storage for commands, macros, scripts,
+ strings, and filename expansion in 64-bit versions and in 32-bit
+ versions that support large files.
+ * User-settable FTP timeout, works on both the data and control
+ connection.
+ * FTP access to ports higher than 16383.
+ * Built-in FTP client for VMS. This is the [70]same FTP client Unix
+ C-Kermit has had since version 8.0, minimally adapted to VMS by
+ SMS, supporting binary and Stream_LF file transfer only (in other
+ words, nothing to handle RMS files), but otherwise fully functional
+ (and scriptable) and theoretically capable of making connections
+ secured by SSL (at least it compiles and links OK with SSL - HP SSL
+ 1.3 in this case).
+ * Large file support in VMS, also by SMS. Alpha and Itanium only (not
+ VAX). VMS C-Kermit was already able to transfer large files, but
+ the file-transfer display (numbers and progress bar) and statistics
+ were wrong because they used ints. In the present Alpha test
+ release, this is an optional feature requested by including the "f"
+ option in P1.
+ * New PUTENV command that allows Kermit to pass environment variables
+ to subprocesses (Unix only, "help putenv").
+ * New TOUCH command, many file selection options ("help touch").
+ * New DIRECTORY command options and switches (/TOP, /COUNT;
+ HDIRECTORY, WDIRECTORY...). To see the ten biggest files in the
+ current directory: "dir /top:10 /sort:size /reverse *" or
+ equivalently, "hdir /top:10 *". WDIR lists files in reverse
+ chronological order, shorthand for "dir /sort:date /reverse".
+ * New command FSEEK /FIND:string-or-pattern, seeks to the first line
+ in an FOPEN'd file that contains the given string or matches the
+ given pattern. Example: Suppose you have a file of lines like this:
+
+ quantity description...
+ in which the first "word" is a number, followed by a description
+ (for example, the name of an item). Here is how to use FSEEK to
+ quickly get the total quantity of any given item, which is passed
+ as a parameter (either a literal string or a pattern) on the
+ command line:
+
+#!/usr/local/bin/kermit +
+if not def \%1 exit 1 Usage: \fbasename(\%0) string-or-pattern
+
+.filename = /usr/local/data/items.log # Substitute the actual filename
+set case off # Searches are case-independent
+fopen /read \%c \m(filename) # Open the file
+if fail exit 1 "\m(filename): \v(errstring)" # Fail: exit with error message
+.total = 0 # OK: Initialize the total
+echo Searching "\%1"...
+
+while true {
+ fseek /line /relative /find:\%1 \%c 0 # Get next line that has target
+ if fail break # Failure indicates EOF
+ fread /line \%c line # Read it
+ if fail break # (shouldn't happen)
+ increment total \fword(\m(line),1) # Increment the total
+}
+fclose \%c # Close the file
+echo Total for "\%1" : \m(total) # Print the result
+exit 0
+
+ The syntax of the FSEEK command in this example indicates that each
+ search should start relative to the current file line. Since Kermit
+ is an interpretive language, FSEEK is a lot faster than FREAD'ing
+ each line and checking it for the target, especially for big files.
+ An especially handy use for FSEEK is for use with potentially huge
+ sequentially timestamped logs, to seek directly to the date-time
+ where you want to start processing. Some other improvements for the
+ FOPEN/FREAD/FWRITE/FCLOSE family of commands are included also
+ (performance, bug fixes, convenience features), listed in the
+ [71]change log. (Prior to 9.0.299 Alpha.02, the FSEEK /FIND:
+ command always started from the top.)
+ * MIME synonyms for character-set names: A new equivalence between
+ MIME names and Kermit names for character sets, with a new table
+ showing the supported sets [72]HERE (this feature is also
+ illustrated in the [73]Weblog script).
+ * Unix C-Kermit SET TERMINAL TYPE now passes its arguments to
+ subprocesses as an environment variable.
+ * SET SESSION-LOG TEXT now strips out ANSI escape sequences from the
+ session log.
+ * For interacting with POP servers over clear-text or SSL-secured
+ connections:
+ + New SSL and TLS "raw" connections (no Telnet protocol).
+ + New INPUT command options for reading and capturing (perhaps
+ while scanning) continuous incoming text, such as INPUT
+ /NOWRAP (explained [74]HERE).
+ + New \femailaddress() command to extract the e-mail address
+ from an Internet mail message To: or From: line, used in
+ fetching mail from POP servers.
+ + Improved date parsing commands and functions for parsing the
+ different date formats that can appear in e-mail.
+ + Production scripts for fetching mail from a secure POP server,
+ available [75]HERE.
+ * Various features added to make Kermit more useful for writing CGI
+ scripts such as INPUT /COUNT:n to INPUT exactly n characters
+ (useful for reading form data).
+ * New \fpictureinfo() function for getting orientation and dimensions
+ of JPG and GIF images, described [76]HERE.
+ * New \fgetpidinfo() function for testing whether a given process
+ exists.
+ * \fkwdvalue() function fixed to allow multiword values.
+ * New function \fcount(s1,s2) to tell the number of occurrences of s1
+ in s2.
+ * New \flopx() function returns rightmost field from string (such as
+ a file's extension).
+ * New function \ffunction(s1) to tell whether a built-in s1 function
+ exists.
+ * New \fsqueeze(s1) function removes leading and trailing whitespace
+ from string s1, changes tabs to spaces, squeezing each run of
+ repeated whitespace characters to a single space.
+ * Compact substring notation: \s(somestring[12:18]) is the same as
+ \fsubstring(\m(somestring),12,18), i.e. the substring starting at
+ position 12, 18 characters long. \s(somestring[12_18]) means
+ characters 12 through 18 of the string (7 characters). Also,
+ \s(somestring[17.]) returns character number 17 of somestring.
+ * The string indexing functions now accept an optional trailing
+ argument specifying the occurrence number of the target string.
+ Likewise, \fword() can fetch words from the right as well as the
+ left.
+ * The COPY command in Unix C-Kermit has a new /PRESERVE switch,
+ equivalent to Unix "cp -p".
+ * ASKQ /ECHO:c can be used to make the characters the user types echo
+ as the character c, e.g. asterisk when typing a password.
+ * IF LINK filename to test if the filename is a symlink.
+ * Ctrl-K, when typed at the command parser, replaces itself with most
+ recently entered file specification.
+ * In Unix, the ability to log a terminal session to a serial port,
+ for use with speaking devices or serial printers; described
+ [77]HERE. Also for the same purpose, SET SESSION-LOG
+ NULL-PADDED-LINES for a speech synthesizer than needed this.
+ * Adaptation to OpenSSL 0.9.8 and 1.0.0.
+ * Lifted the restriction on having a remote Kermit program send
+ REMOTE commands to the local. A very big ex-client needed to be
+ able to do this (branches would connect to headquarters and upload
+ files; HQ would then download patches, a REMOTE HOST command was
+ necessary to allow the remote headquarters machines to install the
+ patches on the local client; of course the client first has to
+ ENABLE HOST because this is a risky scenario). The reason for the
+ restriction was that the server, upon receiving any REMOTE command
+ would send the results (output) back to the client as a file
+ transfer with "destination screen", but of course the remote has no
+ screen.
+ * Added XMESSAGE, which is to [78]MESSAGE as XECHO is ECHO: it
+ outputs a string with no line terminator DEBUG MESSAGE is ON.
+ * Fixed \frecurse() to not dump core when invoked with no arguments.
+ * Improved text for HELP FUNCTION SPLIT and HELP FUNCTION WORD.
+ * Patches for Debian 6.0 "Squeeze" from Ian Beckwith.
+ * \fcontents(\&a[3]) got an error if the array was declared but its
+ dimension was less than 3. Now it simply returns and empty string.
+ * \fsplit(), when parsing lines from CSV and TSV files, was treating
+ backslash in the data the same way it treats backslash in Kermit
+ commands. This was fixed to treat backslash like any other
+ character.
+ * Builds for Solaris 9 and later now use streams ptys rather then the
+ old BSD-style ptys. Thanks to Gary Mills for this one, who noticed
+ that he couldn't have more than 48 C-Kermit SSH sessions going at
+ once and figured out why.
+ * As noted [79]below DES encryption is being retired from many
+ platforms and libraries that once used it. I changed the Solaris
+ and Linux OpenSSL builds to account for this by testing for it. I
+ probably should also add a OMITDES option to omit DES even if it is
+ installed, but "KFLAGS=-UCK_DES" seems to do the job for now.
+ * I changed the Linux build to test for the OpenSSL version (like the
+ Solaris version already did), rather than assuming OpenSSL 0.9.7.
+ * A couple minor changes for Tru64 Unix 5.1B from Steven Schweda but
+ we still have some trouble on that platform. As a workaround "make
+ osf1" can be used there.
+ * Unix makefile and man page are now included in the Zip
+ distribution.
+ * \fjoin(), which is the inverse function of fsplit() now accepts CSV
+ and TSV as a second argument, to transform an array into a
+ comma-separated or tab-separated value list, as described [80]HERE.
+ * Even in 2010, Unix distributions continue to change their UUCP
+ lockfile conventions. C-Kermit 9.0 contains support from Joop
+ Boonen for OpenSuSE >= 11.3 and recent Debian, which no longer have
+ baudboy.h, which first appeared in Red Hat 7.2 in 2003.
+ * From Lewis McCarthy:
+
+ Based on code inspection, C-Kermit appears to have an SSL-related
+ security vulnerability analogous to that identified as CVE-2009-3767
+ (see e.g.
+ [81]http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3767).
+
+ I'm attaching a patch for this issue relative to the revision of
+ ck_ssl.c obtained from a copy of
+ [82]http://www.columbia.edu/kermit/ftp/test/tar/x.zip downloaded on
+ 2010/07/30, which I believe is the latest.
+ When this flaw was first widely publicized at last year's Black Hat
+ conference, it was claimed that some public certificate authorities
+ had indeed issued certificates that could be used to exploit this
+ class of vulnerability. As far as I know they have not revealed
+ specifically which public CA(s) had been found issuing such
+ certificates. Some references:
+ + [83]http://www.mseclab.com/?p=180
+ + [84]http://www.theregister.co.uk/2009/07/30/universal_ssl_cert
+ ificate/
+
+ * Peter Eichhorn reported that "RENAME ../x ." didn't work; fixed
+ now.
+ * If only one file is FOPEN'd, FCLOSE given with no arguments would
+ close it; this was a "convenience feature" that turned out to be
+ dangerous. For safety FCLOSE has to require a specific channel
+ number or the word ALL.
+ * Added \fstrcmp(s1,s2,case,start,length), which has the advantage
+ over IF EQU,LGT,LLT that case sensitivity can be specified as a
+ function arg, and also substrings can be specified.
+ * New built-in functions:
+
+ \fcvtcsets(string,cs1,cs2)
+ Function to convert a string from one character set to
+ another.
+
+ \fdecodehex(string[,prefix])
+ Function to decode a string containing hex escapes.
+
+ \fstringtype(string)
+ Function to tell whether a string is 7-bit, 8-bit, or
+ UTF-8.
+
+ For the motivation for these features and an application that uses
+ them to analyze web logs, see the Weblog script below.
+ *
+
+ Lazy IF Conditions: Now you can do this:
+ define foo some number
+ if foo command
+
+ instead of this:
+ define foo some number
+ if \m(foo) command
+
+ Of course the old way still works too. But watch out because if the
+ variable name is the same as a symbolic IF condition (for example
+ COUNT), it won't do what you expected. (IF COUNT was used for loop
+ control in early versions of MS-DOS Kermit, before it got real FOR
+ and WHILE loops; it was added to C-Kermit for compatibility, and it
+ can't be removed because that could break existing scripts).
+ * Escape sequences are now stripped from text-mode session logs not
+ only in CONNECT sessions but also in whatever is logged by the
+ INPUT command; described in the [85]next section.
+ * New commands for selectively issuing progress or debugging messages
+ from scripts, also described in the next section.
+ * Fix from [86]John Dunlap to prevent the fixed packet-timeout
+ interval from going to an unexpected value.
+ * Alpha.04 fixes a problem with FTP connections made from 64-bit Unix
+ platforms. All the other changes in this section were to Alpha.03.
+ * Relaunching a closed SSH connection with the CONNECT command is now
+ possible, as it always has been with Telnet and other connection
+ types; suggested by Peter Eichhorn (needs testing).
+ * A symbol conflict fixed that prevented successful build on
+ [87]FreeBSD 8.0.
+ * Fixes from Christian Corti for building on SunOS 4.1.
+ * New aixg target for building on AIX with gcc.
+ * New aix+ibmssl target. This is nice because the IBM-supplied SSL
+ libraries and header files are in a known location; no need to
+ [88]set environment variables giving their locations.
+ * "Large File Support" is now included by default on Alpha and IA64
+ hardware on VMS 7.3 and later, and it should work much better than
+ before.
+ * Kermit's internal FTP client is now included by default in any
+ build that also includes TCP/IP networking. At present, the FTP
+ client seems to work well for binary-mode transfers; text (ASCII)
+ mode transfers still need some work. In builds that also include
+ Secure Sockets Layer (SSL) security (next item) the FTP client
+ should be able to make securely authenticated and encrypted
+ connections.
+ * In network builds that request OpenSSL support, e.g.:
+
+ $ @ckvker "" "" "CK_SSL"
+ the OpenSSL version is detected automatically and the appropriate
+ compile-time options are emitted (such as
+ OPENSSL_DISABLE_OLD_DES_SUPPORT).
+ * Preliminary / limited support for the ODS-5 file system on VMS 7.2
+ and later, Alpha and Itanium only (needs testing): Filenames can be
+ mixed case and can be longer.
+ * Support for older and older VMS versions.
+ * In the VMS build procedure, CKVKER.COM, the "i" option in P1 now
+ means don't include the internal FTP client, and the "f" option
+ means do not include "Large File" support. Large File support in
+ VMS really only applies to the file-transfer display and
+ statistics, which would go out of whack as soon as the byte count
+ overflowed 31 bits because this is C-Kermit, built with the C
+ compiler and the C library (runtime system), which did not support
+ long integers until VMS 7.3.
+ * The [89]LISP Operator ROUND now takes an optional second argument
+ that specifies the number of places to round to, e.g.
+ (ROUND dollars 2) rounds dollars to 2 decimal places.
+ * Improved pattern matching in many commands for both strings and
+ filenames.
+ * Various minor new features, plus numerous bug fixes and speedups.
+
+Incompatibilities
+
+ A top priority for new Kermit software releases has always been
+ backwards compatibility. A script written for a previous Kermit release
+ should run the same way in the new release.
+
+ There's one exception this time. The [90]\fsplit() function is
+ incredibly handy, it can do almost anything, up to and including
+ parsing a LISP program (the underlying code is the basis of the
+ [91]S-Expression interpreter). But did you ever try to use it to parse
+ (say) a Tab-Separated-List (TSV file) or Comma-Separated-List (CSV)? It
+ works as expected as long as the data contains only 7-bit characters.
+ But if your data contains (say) Spanish or German or Russian text
+ written in an 8-bit character set such as ISO 8859-1, every 8-bit
+ character (any value 128-255) is treated as a break character. This is
+ fixed in C-Kermit 9.0 by treating all 8-bit bytes as "include"
+ characters rather than break characters, a total reversal of past
+ behavior. I don't think it will affect anyone though, because if this
+ had happened to anyone, I would have heard about it!
+
+ Since most standard 8-bit character sets have control characters in
+ positions 128-160, it might have made sense to keep 128-160 in the
+ break set, but with the proliferation of Microsoft Windows code pages,
+ there is no telling which 8-bit character is likely to be some kind of
+ text, e.g. "smart quotes" or East European or Turkish accented letters.
+
+What's Not In C-Kermit 9.0
+
+ Some large projects that were contemplated have not been done,
+ including:
+ * IPv6. Honestly, there has been zero demand for this, and it would
+ be a lot of work and disruption to the code base. Volunteers
+ welcome, I guess. It could be a CS project.
+ * A database interface - MySQL or ODBC. For this one, there is some
+ demand but I haven't had a chance to even look into it.
+ * There's a looming issue with DES encryption; major vendors are
+ removing it from their platforms, starting with Apple in Mac OS X
+ 10.6, with Microsoft to follow suit. A secure version of Kermit can
+ be built without DES, but in limited testing successful connections
+ were spotty (e.g. with Kerberos 5).
+ * Cleaning up the Unix makefile. It has 25 years' worth of targets in
+ it. It is very likely safe to remove most of them, since (a) most
+ old platforms have gone away by now, or have been upgraded, due to
+ hacking vulnerabilities; (b) the market has consolidated
+ considerably; and (c) most of the new features of C-Kermit 9.0,
+ such as large files, won't be of any use on older platforms and
+ previous C-Kermit versions will remain available.
+ * Packages. Everybody wants an install package custom made for their
+ own computer, Linux RPMs being the prime example but far from the
+ only one. These will come, I suppose (especially with some Linux
+ sites having a policy against installing any application that does
+ not come as an RPM). In the meantime, here's a page that describes
+ some Kermit-specific issues in package construction:
+ [92]ckpackages.html.
+
+And a Loose End...
+Using External File-Transfer Protocols on Secure Connections
+
+ After C-Kermit 8.0.212 Dev.27 (2006/12/22), I spent a big chunk of time
+ trying to solve a particular problem that some of you have complained
+ about and others might be familiar with: If you use C-Kermit to make a
+ secure Telnet connection to another host (e.g. with Telnet SSL/TLS,
+ Kerberos, or SRP) and then attempt to transfer a file using an external
+ protocol such as Zmodem, it doesn't work.
+
+ That's because as coded (through 8.0.211), C-Kermit simply starts the
+ external protocol in a fork with its standard i/o redirected to the
+ connection. This completely bypasses the encryption and decryption that
+ is done by C-Kermit itself, and of course it doesn't work. The same
+ thing occurs if you use the REDIRECT command. The routine that handles
+ this is ttruncmd() in ckutio.c.
+
+ In order to allow (say) Zmodem transfers on secure connections, it is
+ necessary for C-Kermit to interpose itself between the external Zmodem
+ program and the connection, decrypting the incoming stream before
+ feeding it to Zmodem and encrypting Zmodem's output before sending out
+ the connection.
+
+ In principal, this is simple enough. We open a pseudoterminal pair
+ ("master" and "slave") for Zmodem's i/o and we create a fork and start
+ Zmodem in it; we read from the fork pty's standard output, encrypt, and
+ send to the net; we read from the net, decrypt, and write to the fork
+ pty's standard input.
+
+ In practice, it's not so simple. First of all, pseudoterminals (ptys)
+ don't seem to interface correctly with certain crucial APIs, at least
+ not in the OS's I have tried (Mac OS X, Linux, NetBSD, etc), such as
+ select(). And i/o with the pty often - perhaps always - fails to
+ indicate errors when they occur; for example, when the fork has exited.
+
+ But, even after coding around the apparent uselessness of select() for
+ multiplexing pty and net, and using various tricks to detect when the
+ external protocol exits and what its exit status is, I'm still left
+ with a show-stopping problem: I just simply can not download (receive)
+ a file with Zmodem, which is the main thing that people would probably
+ want to do. I can send files just fine, but not receive. The incoming
+ stream is delivered to Zmodem (to the pty slave) but upon arrival at
+ the Zmodem process itself, pieces are always missing and/or corrupt.
+ Yet I can receive files just fine if I use Kermit itself (C-Kermit or
+ G-Kermit) as the external protocol, rather than Zmodem.
+
+ I can think of two reasons why this might be the case:
+
+ 1. Zmodem sends all 8-bit bytes and control codes in the clear, and
+ maybe the pty is choking on them because it thinks it is a real
+ terminal.
+
+ But Zmodem puts its controlling terminal into raw mode. And C-Kermit
+ puts the pty into raw mode too, just for good measure. If any 0xFF
+ codes are in the Zmodem data stream, and it's a Telnet session, Kermit
+ does any needed byte stuffing/unstuffing automatically. Anyway, if I
+ tell Zmodem to prefix everything, it makes no difference.
+
+ 2. Zmodem is a streaming protocol and perhaps the pty driver can't
+ keep up with a sustained stream of input at network speeds. What
+ would be the method of flow control?
+
+ I can vary the size of the i/o buffers used for writing to the pty, and
+ get different effects, but I am not able to get a clean download, no
+ matter what buffer size I use. write()'ing to the pty does not return
+ an error, and I can't see the errors because they happen on the master
+ side. It's as if the path between the pty slave and master lacks flow
+ control; I deliver a valid data stream to the pty slave and the master
+ gets bits and pieces. This impression is bolstered somewhat by the
+ "[93]man 7 pty" page in HP-UX, which talks about some special modes for
+ ptys that turn off all termio processing and guarantee a
+ flow-controlled reliable stream of bytes in both directions - a feature
+ that seems to be specific to HP-UX, and exactly the one we need
+ everywhere.
+
+ Well, in Pass One I used C-Kermit's existing pty routines from
+ ckupty.[ch], which are well-proven in terms of portability and of
+ actually working. They are currently used by SET HOST /PTY for making
+ terminal connections to external processes. But these routines are
+ written on the assumption that the pty is to be accessed interactively,
+ and maybe they are setting the fork/pty arrangement up in such a way
+ that that's not suitable for file transfer. The Pass One routine is
+ called xttptycmd() in ckutio.c.
+
+ So in Pass Two I made a second copy of the routine, yttptycmd(), that
+ manages the pty and fork itself, so all the code is in one place and
+ it's simple and understandable. But it still doesn't work for Zmodem
+ downloads. In this routine, I use openpty() to get the pty pair, which
+ is not portable, so I can have access to both the master and slave pty
+ file descriptors. This version can be used only a platforms that have
+ openpty(): Linux, Mac OS X, NetBSD, etc.
+
+ In Pass Three, zttptycmd(), I tried using pipes instead of ptys, in
+ case ptys are simply not up to this task (but that can't be true
+ because if I make a Telnet or SSH connection into a host, I can send
+ files to it with Zmodem, and the remote Zmodem receiver is, indeed,
+ running on a pty). But pipes didn't work either.
+
+ In Pass Four, I extracted the relevant routines into a standalone
+ program based on yttptycmd() (the openpty() version, for simplicity),
+ which I tested on Mac OS X, the idea being to rule out any
+ "environmental" effects of running inside the C-Kermit process. There
+ was no difference -- Kermit transfers (with C-Kermit itself as the
+ external protocol) worked; Zmodem transfers (neither sz or lsz) did
+ not.
+
+ Well, it's a much longer story. As the external protocol, I've tried
+ rzsz, crzsz, and lrzsz. We know that some of these have quirks
+ regarding standard i/o, etc, which is one of the reasons for using ptys
+ in the first place, and i/o does work - just not reliably. Anyway, the
+ 1100 lines or so of [94]ckc299.txt, starting just below where it says
+ "--- Dev.27 ---" tell the full story. At this point I have to give up
+ and move on; it might be more productive to let somebody else who has
+ more experience with ptys take a look at it - if indeed anyone still
+ cares about being able to do Zmodem transfers over secure Telnet
+ connections.
+
+ C-Kermit 9.0 contains the three new routines (and some auxiliary ones),
+ but they are not compiled or called unless you build it specially:
+
+ make targetname KFLAGS=-DXTTPTYCMD (builds with xttptycmd())
+ make targetname KFLAGS=-DYTTPTYCMD (builds with yttptycmd())
+ make targetname KFLAGS=-DZTTPTYCMD (builds with zttptycmd())
+
+ These are all in [95]ckutio.c. As noted, the second one works only for
+ Linux, FreeBSD, NetBSD, and Mac OS X, because it uses non-POSIX,
+ non-portable openpty(). If you want to try it on some other platform
+ that has openpty(), you can build it like this:
+
+ make targetname "KFLAGS=-DYTTPTYCMD -DHAVE_OPENPTY"
+
+ (and let me know, so I can have HAVE_OPENPTY predefined for that
+ platform too). The best strategy to get this working, I think, would be
+ to concentrate on yttptycmd(), which is the simpler of the two
+ pty-based routines. If it can be made to work, then we'll see if we can
+ retrofit it to use the ckupty.c routines so it will be portable to
+ non-BSD platforms.
+
+ By the way, if you build with any of [XYZ]TTPTYCMD defined, then the
+ selected routine will always be used in place of ttruncmd(). This is to
+ allow testing on all kinds of connections, not just secure ones, in
+ both local and remote mode. Once the thing works, if it ever does, I'll
+ add the appropriate tests and/or commands.
+
+ By default, in the initial test release, C-Kermit 9.0 uses ttruncmd()
+ on serial connections and ttyptycmd() on network connections. Even when
+ a network connection is not encrypted, Kermit still needs to handle the
+ network protocol, e.g. the quoting of 0xff bytes on Telnet connections.
+
+Demonstration: Fetch Mail from POP Server Secured by SSL
+
+ [96]pop.ksc is a fully elaborated production script for fetching one's
+ mail from a POP3 server over a connection secured by SSL. For
+ explanation and documentation, [97]CLICK HERE. [98]mailcheck is a
+ wrapper for the pop.ksc script, which collects your password one time,
+ and then checks for new mail every 5 minutes (or other selected
+ interval) and calls pop.ksc to fetch it if there is any.
+
+Demonstration: HP Switch Configuration Backup
+
+ A common use for Kermit software is to make automated backups of the
+ configuration of network switches and routers, such as those made by
+ Cisco or Hewlett-Packard (although [99]tftp can be used for this, it is
+ not available in all such devices; Kermit, however, works with those
+ that have tftp as well as those that don't).
+
+ Typically a backup can be done by making a Telnet, SSH, or serial
+ connection to the device with Kermit and giving a command such as "show
+ config" at the command-line prompt of the device with Kermit's session
+ log activated. The result is a list of the commands that were used to
+ establish the current configuration, suitable for feeding back to the
+ device's console (e.g. with C-Kermit's TRANSMIT command) to reestablish
+ the same configuration or to duplicate it on another device.
+
+ At an HP installation it was noted, however, that while the HP switches
+ (various ProCurve models) produced the desired list of commands, they
+ were interspersed with escape sequences for special effects, thus
+ rendering the recorded sessions unsuitable for feeding back into the
+ switches.
+
+ C-Kermit 9.0 introduces a new feature to strip the offending sequences
+ out of a session log, leaving just the text. The command SET
+ SESSION-LOG TEXT activates this feature. In C-Kermit 9.0 Alpha.02 and
+ earlier, escape sequence stripping occurred only while logging
+ interactive (CONNECT) sessions; beginning with Alpha.03 it is done also
+ for data that is read by INPUT commands and therefore works for scripts
+ too.
+
+ A sample HP Switch Configuration Backup script is [100]HERE, and its
+ data file is [101]HERE. This script also illustrates some other new
+ features of Alpha.03:
+
+ MESSAGE text
+ This lets you put debugging messages in your script that can be
+ displayed or not, according to SET DEBUG MESSAGE (below). This
+ way you don't have to change your script for debugging. Hint:
+ In Unix, invoke the script like this:
+
+ $ DEBUG=1 scriptname arg1 arg2...
+
+ and then include the following command in your script:
+
+ if defined \$(DEBUG) set debug message on
+
+ XMESSAGE text
+ Like MESSAGE but prints the text with no line terminator, so it
+ can be continued by subsequent messages.
+
+ SET DEBUG MESSAGE { ON, OFF, STDERR }
+ ON means MESSAGE commands should print to standard output; OFF
+ means they shouldn't print anything; STDERR means the messages
+ should be printed to [102]stderr. DEBUG MESSAGE is OFF by
+ default, i.e. unless you SET it to ON or STDERR.
+
+ IF DEBUG command
+ Executes the command if SET DEBUG MESSAGE is not OFF.
+
+ The \v(lastcommand) variable
+ This variable contains the previous command. You can use it in
+ debugging and error message to show (for example) exactly what
+ the command was that just failed, without having to make a copy
+ of the command:
+
+set host somehost.somecompany.com
+if fail exit 1 "FATAL - \v(lastcommand)"
+
+ which, if the SET HOST command fails, prints "FATAL - set host
+ somehost.somecompany.com" and then exits with status 1 (which
+ normally indicates failure).
+
+Demonstration: HP iLO Blade Configuration
+
+ [103]THIS DOCUMENT describes a script in production use at Columbia
+ University for configuring and deploying racks full of HP blade servers
+ through their "integrated Lights Out" (iLO) management interface,
+ bypassing the tedious and error-prone process of configuring the
+ servers one by one through the vendor-provided point-and-click Web
+ interface, which is ill-suited to configuring large numbers of blades.
+ The script illustrates some of C-Kermit 9.0's new features; source code
+ is available through the link. The code is apt to change from time to
+ time as new requirements surface.
+
+Demonstration: IBM/Rolm/Siemens CBX Management
+
+ [104]THIS DOCUMENT describes a suite of scripts (some in production,
+ some in development) used to manage the Columbia campus 20,000-line
+ main telephone switch, along with about 10 satellite switches at
+ off-campus locations. These switches are 1980s technology*, their
+ management consoles are serial ports. Access is via Telnet to reverse
+ terminal servers. The scripts allow for interactive sessions as well as
+ automatic production (and in some cases formatting) of different
+ reports required by different groups at different intervals. These
+ scripts replace a whole assortment of ad-hoc ProComm ASPECT scripts
+ that were scattered all over the place, with passwords embedded. The
+ new scripts are intended to be run from a centralized server where
+ there is a single well-secured configuration file, and where they can
+ be used on demand, or in cron jobs. They are modular so code
+ duplication is minimal.
+ __________________________
+ * Of course the University is deploying new technology but the but the
+ old system will be used in parallel for some time to come.
+
+Demonstration: CSV and TSV Files
+
+ Contents
+
+ * [105]Reading a CSV or TSV Record and Converting it to an Array
+ * [106]Using \fjoin() to create a Comma- or Tab-Separated Value List
+ from an Array
+ * [107]Using CSV or TSV Files
+
+ Comma-Separated Value (CSV) format is commonly output by spreadsheets
+ and databases when exporting data into plain-text files for import into
+ other applications. Here are the details:
+
+ Comma-Separated List Syntax
+
+ 1. Each record is a series of fields.
+ 2. Records are in whatever format is used by the underlying file
+ system for lines of text.
+ 3. Fields within records are separated by commas, with zero or more
+ whitespace characters (space or tab) before and/or after the comma;
+ such whitespace is considered part of the separator.
+ 4. Fields with embedded commas must be enclosed in ASCII doublequote
+ characters.
+ 5. Fields with leading or trailing spaces must be enclosed in ASCII
+ doublequotes.
+ 6. Any field may be enclosed in ASCII doublequotes.
+ 7. Fields with embedded doublequotes must be enclosed in doublequotes
+ and each interior doublequote is doubled.
+
+ Here is an example:
+
+aaa, bbb, has spaces,,"ddd,eee,fff", " has spaces ","Muhammad ""The Greatest"" A
+li"
+
+ The first two are regular fields. The second is a field that has an
+ embedded space but in which any leading or trailing spaces are to be
+ ignored. The fourth is an empty field, but still a field. The fifth is
+ a field that contains embedded commas. The sixth has leading and
+ trailing spaces. The last field has embedded quotation marks.
+
+ Prior to C-Kermit 9.0 Alpha.06, C-Kermit did not handle CSV files
+ according to the specification above. Most seriously, there was no
+ provision for a separator to be surrounded by whitespace that was to be
+ considered part of the separator. Also there was no provision for
+ quoting doublequotes inside of a quoted string.
+
+Reading a CSV record
+
+ Now the \fsplit() function can handle any CSV-format string if you
+ include the symbolic include set "CSV" as the 4th parameter. To
+ illustrate, this program:
+
+def xx {
+ echo [\fcontents(\%1)]
+ .\%9 := \fsplit(\fcontents(\%1), &a, \44, CSV)
+ for \%i 1 \%9 1 { echo "\flpad(\%i,3). [\&a[\%i]]" }
+ echo "-----------"
+}
+xx {a,b,c}
+xx { a , b , c }
+xx { aaa,,ccc," with spaces ",zzz }
+xx { "1","2","3","","5" }
+xx { this is a single field }
+xx { this is one field, " and this is another " }
+xx { name,"Mohammad ""The Greatest"" Ali", age, 67 }
+xx { """field enclosed in doublequotes""" }
+exit
+
+ gives the following results:
+
+[a,b,c]
+ 1. [a]
+ 2. [b]
+ 3. [c]
+-----------
+[ a , b , c ]
+ 1. [a]
+ 2. [b]
+ 3. [c]
+-----------
+[ aaa,,ccc," with spaces ",zzz ]
+ 1. [aaa]
+ 2. []
+ 3. [ccc]
+ 4. [ with spaces ]
+ 5. [zzz]
+-----------
+[ "1","2","3","","5" ]
+ 1. [1]
+ 2. [2]
+ 3. [3]
+ 4. []
+ 5. [5]
+-----------
+[ this is a single field ]
+ 1. [this is a single field]
+-----------
+[ this is one field, " and this is another " ]
+ 1. [this is one field]
+ 2. [ and this is another ]
+-----------
+[ name,"Mohammad ""The Greatest"" Ali", age, 67 ]
+ 1. [name]
+ 2. [Mohammad "The Greatest" Ali]
+ 3. [age]
+ 4. [67]
+-----------
+[ """field enclosed in doublequotes""" ]
+ 1. ["field enclosed in doublequotes"]
+-----------
+
+ The separator \44 (comma) must still be specified as the break set (3rd
+ \fsplit() parameter). When "CSV" is specified as the include set:
+ * The Grouping Mask is automatically set to 1 (which specifies that
+ the ASCII doublequote character (") is used for grouping;
+ * The Separator Flag is automatically set to 1 so that adjacent field
+ separators will not be collapsed;
+ * All bytes (values 0 through 255) other than the break character are
+ added to the include set;
+ * Any leading whitespace is stripped from the first element unless it
+ is enclosed in doublequotes;
+ * Any trailing whitespace is trimmed from the end of the last element
+ unless it is enclosed in doublequotes;
+ * If the separator character has any spaces or tabs preceding it or
+ following it, they are ignored and discarded;
+ * The separator character is treated as an ordinary data character if
+ it appears in a quoted field;
+ * A sequence of two doublequote characters ("") within a quoted field
+ is converted to a single doublequote.
+
+ There is also a new TSV symbolic include set, which is like CSV except
+ without the quoting rules or the stripping of whitespace around the
+ separator because, by definition, TSV fields do not contain tabs.
+
+ Of course you can specify any separator(s) you want with either the
+ CSV, TSV, or ALL symbolic include sets. For example, if you have a TSV
+ file in which you want the spaces around each Tab to be discarded, you
+ can use:
+
+\fsplit(variable, &a, \9, CSV)
+
+ \9 is Tab.
+
+ The new symbolic include sets can also be used with \fword(), which is
+ just like \fsplit() except that it retrieves the nth word from the
+ argument string, rather than an array of all the words. In C-Kermit you
+ can get information about these or any other functions with the HELP
+ FUNCTION command, e.g.:
+
+C-Kermit> help func word
+
+Function \fword(s1,n1,s2,s3,n2,n3) - Extracts a word from a string.
+ s1 = source string.
+ n1 = word number (1-based) counting from left; if negative, from right.
+ s2 = optional break set.
+ s3 = optional include set (or ALL, CSV, or TSV).
+ n2 = optional grouping mask.
+ n3 = optional separator flag:
+ 0 = collapse adjacent separators;
+ 1 = don't collapse adjacent separators.
+
+ \fword() returns the n1th "word" of the string s1, according to the
+ criteria specified by the other parameters.
+
+ The BREAK SET is the set of all characters that separate words. The
+ default break set is all characters except ASCII letters and digits.
+ ASCII (C0) control characters are treated as break characters by default,
+ as are spacing and punctuation characters, brackets, and so on, and
+ all 8-bit characters.
+
+ The INCLUDE SET is the set of characters that are to be treated as
+ parts of words even though they normally would be separators. The
+ default include set is empty. Three special symbolic include sets are
+ also allowed:
+
+ ALL (meaning include all bytes that are not in the break set)
+ CSV (special treatment for Comma-Separated-Value records)
+ TSV (special treatment for Tab-Separated-Value records)
+
+ For operating on 8-bit character sets, the include set should be ALL.
+
+ If the GROUPING MASK is given and is nonzero, words can be grouped by
+ quotes or brackets selected by the sum of the following:
+
+ 1 = doublequotes: "a b c"
+ 2 = braces: {a b c}
+ 4 = apostrophes: 'a b c'
+ 8 = parentheses: (a b c)
+ 16 = square brackets: [a b c]
+ 32 = angle brackets: <a b c>
+
+ Nesting is possible with {}()[]<> but not with quotes or apostrophes.
+
+Returns string:
+ Word number n1, if there is one, otherwise an empty string.
+
+Also see:
+ HELP FUNCTION SPLIT
+
+C-Kermit>
+
+Using \fjoin() to create Comma- or Tab-Separated Value Lists from Arrays
+
+ In C-Kermit 9.0, \fsplit()'s inverse function, [108]\fjoin() received
+ the capability of converting an array into a comma-separated or a
+ tab-separated value list. Thus, given a CSV, if you split it into an
+ array with \fsplit() and then join the array with \fjoin(), giving each
+ function the new CSV parameter in the appropriate argument position,
+ the result will be will be equivalent to the original, according to the
+ CSV definition. It might not be identical, because if the result had
+ extraneous spaces before or after the separating commas, these are
+ discarded, but that does not affect the elements themselves. The new
+ syntax for \fjoin() is:
+
+ \fjoin(&a,CSV)
+ Given the array \&a[] or any other valid array designator, joins
+ its elements into a comma-separated list according to the
+ [109]rules listed above.
+
+ \fjoin(&a,TSV)
+ Joins the elements of the given array into a tab-separated list,
+ also described above.
+
+ [110]Previous calling conventions for \fjoin() are undisturbed,
+ including the ability to specify a portion of an array, rather than the
+ whole array:
+
+declare \&a[] = 1 2 3 4 5 6 7 8 9
+echo \fjoin(&a[3:7],CSV)
+3,4,5,6,7
+
+ Using \fsplit() and \fjoin() it is now possible to convert a
+ comma-separated value list into a tab-separated value list, and vice
+ versa (which is not a simple matter of changing commas to tabs or vice
+ versa).
+
+Applications for CSV Files
+
+ Databases such as MS Access or MySQL can export tables or reports in
+ CSV format, and then Kermit can read the resulting CSV file and do
+ whatever you like with it; typically something that could not be done
+ with the database query language itself (or that you didn't know how to
+ do that way): create reports or datasets based on complex criteria or
+ procedures, edit or modify some fields, etc, and then use \fjoin() to
+ put each record back in CSV form so it can be reimported into a
+ spreadsheet or database.
+
+ Here is a simple example in which we purge all records of customers who
+ have two or more unpaid bills. The file is sorted so that each license
+ purchase record is followed by its annual maintenance payment records
+ in chronological order.
+
+#!/usr/local/bin/kermit
+.filename = somefile.csv # Input file in CSV format
+fopen /read \%c \m(filename) # Open it
+if fail exit # Don't go on if open failed
+copy \m(filename) ./new # Make a copy of the file
+
+.oldserial = 00000000000 # Multiple records for each serial number
+.zeros = 0 # Unpaid bill counter
+
+while true { # Loop
+ fread /line \%c line # Get a record
+ if fail exit # End of file
+ .n := \fsplit(\m(line),&a,\44,CSV) # Split the fields into an array
+ if not equ "\m(oldserial)" "\&a[6]" { # Have new serial number?
+ # Remove all records for previous serial number
+ # if two or more bills were not paid...
+ if > \m(zeros) 1 {
+ grep /nomatch \m(oldserial) /output:./new2 ./new
+ rename ./new2 ./new
+ }
+ .oldserial := \&a[6] # To detect next time serial number changes
+ .zeros = 0 # Reset unpaid bill counter
+ }
+ if equ "\&a[5]" "$0.00" { # Element 5 is amount paid
+ increment zeros # If it's zero, count it.
+ }
+}
+fclose \%c
+
+ Rewriting the file multiple times is inelegant, but this is a quick and
+ dirty use-once-and-discard script, so elegance doesn't count. The
+ example is interesting in that it purges certain records based on the
+ contents of other records. Maybe there is a way to do this directly
+ with SQL, but why use SQL when you can use Kermit?
+
+ Here is the same task but this time no shelling out, and this time we
+ do change and add some fields and then join the result back into a CSV
+ record and write it out to a new file. The object is to create a record
+ for each license that shows not only the date and purchase price of the
+ license but also the date and amount of the last maintenance payment,
+ and to add new fields for sorting by anniversary (month and day):
+
+#!usr/local/bin/kermit +
+cd ~/somedirectory # CD to appropriate directory
+if fail exit 1 # Make sure we did
+.filename := \%1 # Filename from command line
+if not def filename { # If none give usage message
+ exit 1 "Usage: \%0: infile [ outfile ]"
+}
+fopen /read \%c \m(filename) # Open the input CSV file
+if fail exit # Make sure we did
+
+.output := \%2 # Output filename from command line
+if not def output { # Supply one if not given
+ .output := New_\m(filename)
+}
+fopen /write \%o \m(output) # Open output file
+if fail exit # Check that we did
+
+.serial = 00000000000 # Initialize serial number
+.licenses = 0 # and license counter
+
+fread /line \%c line # First line is column labels
+if fail exit # Check
+fwrite /line \%o "\m(line),AMM_DD,AYYYY" # Write new labels line
+
+# Remaining lines are license purchases (K95B) followed by zero or more
+# maintenance invoices (K95BM) for each license.
+
+.datepaid = 00/00/0000 # Initialize last maint payment date
+.amtpaid = $0.00 # Initialize last maint payment amount
+set flag off # For remembering we're at end of file
+while not flag { # Loop to read all records
+ fread /line \%c line # Read a record
+ if fail set flag on # If EOF set flag for later
+ .n := \fsplit(\m(line),&a,\44,CSV) # Break record into array
+ if ( flag || equ "\&a[3]" "K95B" ) { # License or EOF
+ if fail exit 1 "FAILED: \v(lastcommand)"
+ if licenses { # If this is not the first license
+ .\&x[5] := \m(amtpaid) # Substitute most recent amount paid
+ .\&x[21] := \m(datepaid) # Substitute most recent date paid
+ void \fsplit(\&x[18],&d,/) # Break up original (anniversary) date
+ # and put mm_dd and yyyy in separate fields for sorting...
+ fwrite /line \%o "\fjoin(&x,CSV),\flpad(\&d[1],2,0)_\flpad(\&d[2],2,
+0),\&d[3]"
+ if fail exit 1 WRITE # Check for error
+ xecho . # Show progress as one dot per record
+ }
+ if flag break # We're at EOF so we're finished
+ increment licenses # New license - count it
+ array copy &a &x # Keep this record while reading next
+ .serial := \&a[6] # Remember serial number
+ .datepaid = 00/00/0000 # Initial maintenance payment date
+ .amtpaid = $0.00 # and amount
+ continue # and go back to read next record
+ }
+ if not eq "\m(serial)" "\&a[6]" { # Catch out-of-sequence record
+ echo
+ echo "SEQUENCE: \m(serial)..\&a[6]: \&a[7] [\&a[1]]"
+ continue
+ }
+ if equ "\&a[5]" "" .\&a[5] = $0.00 # If amount is empty make it $0.00
+ if not equ "\&a[5]" "$0.00" { # If amount is not $0.00
+ .datepaid := \&a[21] # remember date paid
+ .amtpaid := \&a[5] # and amount paid
+ }
+}
+fclose ALL # Done - close all files and exit
+exit 0 Done.
+
+
+ The result imports back into Excel, where it can be sorted, formatted,
+ or otherwise manipulated as desired.
+
+Using CSV Files: Extending Kermit's Data Structures
+
+ Now that we can parse a CSV record, what would we do with a CSV file -
+ that is, a sequence of records? If we needed all the data available at
+ once, we would want to load it into a matrix of (row,column) values.
+ But Kermit doesn't have matrices. Or does it?
+
+ Kermit has several built-in data types, but you can invent your own
+ data types as needed using Kermit's macro feature:
+
+define variablename value
+
+ For example:
+
+define alphabet abcdefghijklmnopqrstuvwxyz
+
+ This defines a macro named alphabet and gives it the value
+ abcdefghijklmnopqrstuvwxyz. A more convenient notation (added in
+ C-Kermit 7.0, see [111]Table 2) for this is:
+
+.alphabet = abcdefghijklmnopqrstuvwxyz
+
+ The two are exactly equivalent: they make a literal copy the "right
+ hand side" as the value of the macro. Then you can refer to the macro
+ anywhere in a Kermit command as "\m(macroname)":
+
+echo "Alphabet = \m(alphabet)"
+
+ There is a second way to define a macro, which is like the first except
+ that the right-hand side is evaluated first; that is, any variable
+ references or function calls in the right-hand side are replaced by
+ their values before the result is assigned to the macro. The command
+ for this is ASSIGN rather than DEFINE:
+
+define alphabet abcdefghijklmnopqrstuvwxyz
+assign backwards \freverse(\m(alphabet))
+echo "Alphabet backwards = \m(backwards)"
+
+ which prints:
+
+Alphabet backwards = zyxwvutsrqponmlkjihgfedcba
+
+ This kind of assignment can also be done like this:
+
+.alphabet = abcdefghijklmnopqrstuvwxyz
+.backwards := \freverse(\m(alphabet))
+
+ [112]Any command starting with a period is an assignment, and the
+ operator (= or :=) tells what to do with the right-hand side before
+ making the assignment.
+
+ In both the DEFINE and ASSIGN commands, the variable name itself is
+ taken literally. It is also possible, however, to have Kermit compute
+ the variable name. This is done (as described in [113]Using C-Kermit,
+ 2nd Ed., p.457), using parallel commands that start with underscore:
+ _DEFINE and _ASSIGN (alias _DEF and _ASG). These are just like DEFINE
+ and ASSIGN except they evaluate the variable name before making the
+ assignment. For example:
+
+define \%a one
+_define \%a\%a\%a 111
+
+ would create a macro named ONEONEONE with a value of 111, and:
+
+define \%a one
+define number 111
+_assign \%a\%a\%a \m(number)
+
+ would create the same macro with the same value, but:
+
+define \%a one
+define number 111
+_define \%a\%a\%a \m(number)
+
+ would give the macro a value of "\m(number)".
+
+ You can use the _ASSIGN command to create any kind of data structure
+ you want; you can find some examples in the [114]Object-Oriented
+ Programming section of the [115]Kermit Script Library. In the following
+ program we use this capability to create a two-dimensional array, or
+ matrix, to hold the all the elements of the CSV file, and then to
+ display the matrix:
+
+fopen /read \%c data.csv # Open CSV file
+if fail exit 1
+
+.\%r = 0 # Row
+.\%m = 0 # Maximum columns
+while true {
+ fread /line \%c line # Read a record
+ if fail break # End of file
+ .\%n := \fsplit(\m(line),&a,\44,CSV) # Split record into items
+ incr \%r # Count this row
+ for \%i 1 \%n 1 { # Assign items to this row of matrix
+ _asg a[\%r][\%i] \&a[\%i]
+ }
+ if > \%i \%m { .\%m := \%i } # Remember width of widest row
+}
+fclose \%c # Close CSV file
+decrement \%m # (because of how FOR loop works)
+echo MATRIX A ROWS: \%r COLUMNS: \%m # Show the matrix
+
+for \%i 1 \%r 1 { # Loop through rows
+ for \%j 1 \%m 1 { # Loop through columns of each row
+ xecho "\flpad(\m(a[\%i][\%j]),6)"
+ }
+ echo
+}
+exit 0
+
+ The matrix is called a and its elements are a[1][1], a[1][2], a[1][3],
+ ... a[2][1], etc, and you can treat this data structure exactly like a
+ two-dimensional array, in which you can refer to any element by its "X
+ and Y coordinates". For example, if the CSV file contained numeric data
+ you could compute row and column sums using simple FOR loops and
+ Kermit's built-in one-dimensional array data type:
+
+declare \&r[\%r] # Make an array for the row sums
+declare \&c[\%m] # Make an array for the column sums
+for \%i 1 \%r 1 { # Loop through rows
+ for \%j 1 \%m 1 { # Loop through columns of each row
+ increment \&r[\%i] \m(a[\%i][\%j]) # Accumulate row sum
+ increment \&c[\%j] \m(a[\%i][\%j]) # Accumulate column sum
+ }
+}
+
+ Note that the sum arrays don't have to be initialized to zero because
+ Kermit's INCREMENT command treats empty definitions as zero.
+
+Demonstration Scripts for Webmasters
+
+ These scripts all use new features of C-Kermit 9.0.
+
+ [116]ksitemap
+ A C-Kermit 9.0 script to build sitemap.xml for a website,
+ complete with Google image extensions (this is the file used by
+ webmasters to get their sites crawled and indexed optimally).
+
+ [117]The Weblog Script
+ Reads a web log, extracts the Google searches, normalizes the
+ search strings, and prints the top 20 searches, along with their
+ counts.
+
+ [118]The Amazon Script
+ Reads an Amazon Associate orders report and lists the products
+ according to the number of orders for each, or the number of
+ clicks on each.
+
+ [119]Photoalbum
+ Makes a website from a collection of JPG images.
+
+ [120]Home [121]Kermit 95 [122]C-Kermit [123]Scripts [124]Current
+ [125]New [126]FAQ [127]Support
+
+
+ C-Kermit 9.0 / [128]The Kermit Project / [129]Columbia University /
+ [130]kermit@columbia.edu / [131]validate
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/cu/computinghistory/books/#menagerie
+ 12. http://www.columbia.edu/kermit/ck90tables.html
+ 13. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+ 14. http://www.columbia.edu/kermit/ckermit.html#download
+ 15. http://www.columbia.edu/kermit/ckermit90.html#LargeFiles
+ 16. http://www.columbia.edu/kermit/ckermit90.html#TestLargeFiles
+ 17. http://www.columbia.edu/kermit/ckermit90.html#Bignums
+ 18. http://www.columbia.edu/kermit/ckermit90.html#force3
+ 19. http://www.columbia.edu/kermit/ckermit90.html#Vareval
+ 20. http://www.columbia.edu/kermit/ckermit90.html#rename
+ 21. http://www.columbia.edu/kermit/ckermit90.html#Other
+ 22. http://www.columbia.edu/kermit/ckermit90.html#Incompatibilities
+ 23. http://www.columbia.edu/kermit/ckermit90.html#NotIn9.0
+ 24. http://www.columbia.edu/kermit/ckermit90.html#LooseEnd
+ 25. http://www.columbia.edu/kermit/ckermit90.html#pop
+ 26. http://www.columbia.edu/kermit/ckermit90.html#HPswitch
+ 27. http://www.columbia.edu/kermit/ckermit90.html#iLO
+ 28. http://www.columbia.edu/kermit/ckermit90.html#Rolm
+ 29. http://www.columbia.edu/kermit/ckermit90.html#CSV
+ 30. http://www.columbia.edu/kermit/ckermit90.html#Otherdemos
+ 31. http://www.columbia.edu/kermit/ck60manual.html
+ 32. http://www.amazon.com/gp/product/B002ACPF9M?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=B002ACPF9M
+ 33. http://www.columbia.edu/kermit/ckermit70.html
+ 34. http://www.columbia.edu/kermit/ckermit80.html
+ 35. http://www.columbia.edu/kermit/ckscripts.html
+ 36. http://www.columbia.edu/cu/computinghistory/dec20.html
+ 37. mailto:fdc@columbia.edu
+ 38. http://www.columbia.edu/kermit/k95.html
+ 39. http://www.columbia.edu/kermit/cu-bsd-license.html
+ 40. http://www.columbia.edu/kermit/ckermit90.html#LargeFiles
+ 41. http://www.columbia.edu/kermit/ck90tables.html
+ 42. http://www.columbia.edu/kermit/ck90tables.html
+ 43. http://www.columbia.edu/kermit/ckermit90.html#force3
+ 44. http://www.columbia.edu/kermit/ckermit90.html#Vareval
+ 45. http://www.columbia.edu/kermit/ckrename.html
+ 46. http://www.columbia.edu/kermit/csv.html
+ 47. http://www.columbia.edu/kermit/csetnames.html
+ 48. http://www.columbia.edu/kermit/ckermit90.html#HPswitch
+ 49. http://www.columbia.edu/kermit/ckdaily.html
+ 50. http://www.columbia.edu/kermit/cu-bsd-license.html
+ 51. http://www.opensource.org/
+ 52. http://kermit.columbia.edu/ck90tables.html#LF
+ 53. ftp://kermit.columbia.edu/kermit/utils/bigfile.c
+ 54. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 55. http://www.columbia.edu/kermit/ck90tables.html#LF
+ 56. ftp://kermit.columbia.edu/kermit/scripts/ckermit/easter2
+ 57. http://www.columbia.edu/kermit/em-apex.html
+ 58. http://www.iridium.com/
+ 59. http://science1.nasa.gov/science-news/science-at-nasa/2006/09jan_electrichurricanes/
+ 60. http://www.columbia.edu/kermit/ek.html
+ 61. ftp://kermit.columbia.edu/kermit/ek/simirid/
+ 62. http://www.columbia.edu/kermit/ek.html
+ 63. http://www.columbia.edu/kermit/ckermit70.html#x7.10.10
+ 64. http://www.columbia.edu/kermit/csv.html
+ 65. http://www.columbia.edu/kermit/ckermit70.html#x1.11
+ 66. http://www.columbia.edu/kermit/ckermit70.html
+ 67. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 68. http://www.columbia.edu/kermit/csetnames.html
+ 69. http://www.columbia.edu/kermit/ckdaily.html
+ 70. http://www.columbia.edu/kermit/ftpclient.html
+ 71. http://www.columbia.edu/kermit/ckdaily.html
+ 72. http://www.columbia.edu/kermit/csetnames.html
+ 73. http://www.columbia.edu/kermit/ckermit90.html#Otherdemos
+ 74. http://www.columbia.edu/kermit/input_nowrap.html
+ 75. http://www.columbia.edu/~fdc/mm/index.html
+ 76. http://www.columbia.edu/kermit/photoalbum.html
+ 77. http://www.columbia.edu/~fdc/kermit/logserial.html
+ 78. http://www.columbia.edu/kermit/ckermit90.html#message
+ 79. http://www.columbia.edu/kermit/ckermit90.html#NotIn9.0
+ 80. http://www.columbia.edu/kermit/csv.html#join
+ 81. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3767
+ 82. http://www.columbia.edu/kermit/ftp/test/tar/x.zip
+ 83. http://www.mseclab.com/?p=180
+ 84. http://www.theregister.co.uk/2009/07/30/universal_ssl_certificate/
+ 85. http://www.columbia.edu/kermit/ckermit90.html#HPswitch
+ 86. http://www.columbia.edu/kermit/em-apex.html
+ 87. http://www.freebsd.org/releases/8.0R/announce.html
+ 88. http://www.columbia.edu/kermit/security81.html#x4.2.3
+ 89. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 90. http://www.columbia.edu/kermit/ckermit80.html#x8.7.2
+ 91. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 92. http://www.columbia.edu/kermit/ckpackages.html
+ 93. http://docs.hp.com/en/B9106-90013/pty.7.html
+ 94. http://www.columbia.edu/kermit/test/text/ckc299.txt
+ 95. http://www.columbia.edu/kermit/test/text/ckutio.c
+ 96. http://www.columbia.edu/~fdc/mm/pop
+ 97. http://www.columbia.edu/~fdc/mm/
+ 98. http://www.columbia.edu/~fdc/mm/mailcheck
+ 99. http://en.wikipedia.org/wiki/Trivial_File_Transfer_Protocol
+ 100. http://www.columbia.edu/kermit/ftp/scripts/ckermit/gethpconfig
+ 101. http://www.columbia.edu/kermit/ftp/scripts/ckermit/TestSwitches.txt
+ 102. http://en.wikipedia.org/wiki/Standard_streams
+ 103. http://kermit.columbia.edu/cudocs/ilosetup.html
+ 104. http://www.columbia.edu/kermit/cudocs/cbx.html
+ 105. http://www.columbia.edu/kermit/ckermit90.html#record
+ 106. http://www.columbia.edu/kermit/ckermit90.html#join
+ 107. http://www.columbia.edu/kermit/ckermit90.html#file
+ 108. http://www.columbia.edu/kermit/ckermit80.html#fjoin
+ 109. http://www.columbia.edu/kermit/ckermit90.html#rules
+ 110. http://www.columbia.edu/kermit/ckermit80.html#fjoin
+ 111. http://www.columbia.edu/kermit/ckermit90.html#varasg
+ 112. http://www.columbia.edu/kermit/ckermit70.html#x7.9
+ 113. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+ 114. http://www.columbia.edu/kermit/ckscripts.html#oops
+ 115. http://www.columbia.edu/kermit/ckscripts.html
+ 116. http://www.columbia.edu/kermit/ksitemap.html
+ 117. http://www.columbia.edu/kermit/weblog.html
+ 118. http://kermit.columbia.edu/ftp/scripts/ckermit/amazon
+ 119. http://www.columbia.edu/kermit/photoalbum.html
+ 120. http://www.columbia.edu/kermit/index.html
+ 121. http://www.columbia.edu/kermit/k95.html
+ 122. http://www.columbia.edu/kermit/ckermit.html
+ 123. http://www.columbia.edu/kermit/ckscripts.html
+ 124. http://www.columbia.edu/kermit/current.html
+ 125. http://www.columbia.edu/kermit/whatsnew.html
+ 126. http://www.columbia.edu/kermit/faq.html
+ 127. http://www.columbia.edu/kermit/support.html
+ 128. http://www.columbia.edu/kermit/index.html
+ 129. http://www.columbia.edu/
+ 130. mailto:kermit@columbia.edu
+ 131. http://validator.w3.org/check?uri=http%3A%2F%2Fkermit.columbia.edu%2Fckermit90.html
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckermod.ini b/ckermit-9.0.302-build/ckermit-9.0.302/ckermod.ini
new file mode 100644
index 0000000..6b13c85
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckermod.ini
@@ -0,0 +1,8 @@
+; File CKERMOD.INI, Sample C-Kermit 7.0 customization file.
+;
+echo
+echo The very long standard initialization file that was distributed
+echo with C-Kermit 6, 7, and 8 is no longer recommended as "standard",
+echo since its features were little used. It is still available in
+echo the C-Kermit distribution as ockermod.ini.
+echo
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuat2.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckuat2.h
new file mode 100644
index 0000000..8679a99
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuat2.h
@@ -0,0 +1,358 @@
+/*
+ C K U A T 2 . H -- Kerberos headers for C-Kermit
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Author:
+ Kerberos IV and V intergration.
+ Jeffrey E Altman (jaltman@secure-endpoints.com)
+ Secure Endpoints Inc., New York City
+*/
+/*
+ * Based on a concatenation of all necessary include files distributed with
+ * the Kerberos 5 NT Alpha 2 Telnet package from MIT.
+ */
+
+#ifndef KRB5_TELNET_H
+#define KRB5_TELNET_H
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)encrypt.h 8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef CK_ENCRYPTION
+
+#ifndef __ENCRYPTION__
+#define __ENCRYPTION__
+
+#define DIR_DECRYPT 1
+#define DIR_ENCRYPT 2
+
+#ifndef CK_DES_C
+#ifndef NOBLOCKDEF
+typedef unsigned char Block[8];
+#endif /* NOBLOCKDEF */
+typedef unsigned char *BlockT;
+#ifndef KRB4 /* already defined in kerberosiv/des.h */
+typedef struct des_ks_struct { Block _; } Schedule[16];
+#else /* KRB4 */
+#ifndef OS2
+#ifndef NOBLOCKDEF /* already defined in kerberosiv/des.h */
+typedef struct des_ks_struct { Block _; } Schedule[16];
+#endif /* NOBLOCKDEF */
+#endif /* OS2 */
+#endif /* KRB4 */
+
+#define VALIDKEY(key) (key[0]|key[1]|key[2]|key[3]|key[4]|key[5]|key[6]|key[7])
+
+#define SAMEKEY(k1, k2) (!memcmp((void *)k1, (void *)k2, sizeof(Block)))
+#endif /* CK_DES_C */
+
+typedef struct _session_key {
+ short type;
+ int length;
+ unsigned char *data;
+} Session_Key;
+
+#ifdef __STDC__
+typedef struct {
+ char *name;
+ int type;
+ void (*output)(unsigned char *, int);
+ int (*input)(int);
+ void (*init)(int);
+ int (*start)(int, int);
+ int (*is)(unsigned char *, int);
+ int (*reply)(unsigned char *, int);
+ int (*session)(Session_Key *, int);
+ int (*keyid)(int, unsigned char *, int *);
+ void (*printsub)(unsigned char *, int, unsigned char *, int);
+} Encryptions;
+#if !defined(P)
+#define P(x) x
+#endif
+#else
+typedef struct {
+ char *name;
+ int type;
+ void (*output)();
+ int (*input)();
+ void (*init)();
+ int (*start)();
+ int (*is)();
+ int (*reply)();
+ int (*session)();
+ int (*keyid)();
+ void (*printsub)();
+} Encryptions;
+#if !defined(P)
+#define P(x) ()
+#endif
+#endif
+
+int encrypt_parse(unsigned char *, int);
+
+#ifdef DEBUG
+int printsub(char, unsigned char *, size_t);
+#endif
+
+#define SK_GENERIC 0 /* Just a string of bits */
+#define SK_DES 1 /* Matched Kerberos v5 ENCTYPE_DES */
+
+void encrypt_init P((kstream,int));
+Encryptions *findencryption P((int));
+void encrypt_send_support P((void));
+void encrypt_auto P((int));
+void decrypt_auto P((int));
+int encrypt_is P((unsigned char *, int));
+int encrypt_reply P((unsigned char *, int));
+void encrypt_start_input P((int));
+int encrypt_session_key P((Session_Key *, int));
+int encrypt_dont_support P((int));
+void encrypt_end_input P((void));
+void encrypt_start_output P((int));
+void encrypt_end_output P((void));
+void encrypt_send_request_start P((void));
+void encrypt_send_request_end P((void));
+void encrypt_send_end P((void));
+void encrypt_wait P((void));
+int encrypt_is_encrypting P((void));
+void encrypt_send_support P((void));
+int encrypt_send_keyid P((int, unsigned char *, int, int));
+
+int encrypt_cmd P((int, char **));
+void encrypt_display P((void));
+
+#ifdef CK_KERBEROS
+void krbdes_encrypt P((unsigned char *, int));
+int krbdes_decrypt P((int));
+int krbdes_is P((unsigned char *, int));
+int krbdes_reply P((unsigned char *, int));
+void krbdes_init P((int));
+int krbdes_start P((int, int));
+void krbdes_session P((Session_Key *, int));
+void krbdes_printsub P((unsigned char *, int, unsigned char *, int));
+#endif /* CK_KERBEROS */
+
+void cfb64_encrypt P((unsigned char *, int));
+int cfb64_decrypt P((int));
+void cfb64_init P((int));
+int cfb64_start P((int, int));
+int cfb64_is P((unsigned char *, int));
+int cfb64_reply P((unsigned char *, int));
+int cfb64_session P((Session_Key *, int));
+int cfb64_keyid P((int, unsigned char *, int *));
+void cfb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+void ofb64_encrypt P((unsigned char *, int));
+int ofb64_decrypt P((int));
+void ofb64_init P((int));
+int ofb64_start P((int, int));
+int ofb64_is P((unsigned char *, int));
+int ofb64_reply P((unsigned char *, int));
+int ofb64_session P((Session_Key *, int));
+int ofb64_keyid P((int, unsigned char *, int *));
+void ofb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+void des3_cfb64_encrypt P((unsigned char *, int));
+int des3_cfb64_decrypt P((int));
+void des3_cfb64_init P((int));
+int des3_cfb64_start P((int, int));
+int des3_cfb64_is P((unsigned char *, int));
+int des3_cfb64_reply P((unsigned char *, int));
+int des3_cfb64_session P((Session_Key *, int));
+int des3_cfb64_keyid P((int, unsigned char *, int *));
+void des3_cfb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+void des3_ofb64_encrypt P((unsigned char *, int));
+int des3_ofb64_decrypt P((int));
+void des3_ofb64_init P((int));
+int des3_ofb64_start P((int, int));
+int des3_ofb64_is P((unsigned char *, int));
+int des3_ofb64_reply P((unsigned char *, int));
+int des3_ofb64_session P((Session_Key *, int));
+int des3_ofb64_keyid P((int, unsigned char *, int *));
+void des3_ofb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+#ifdef CAST_ENCRYPTION
+void cast_cfb64_encrypt P((unsigned char *, int));
+int cast_cfb64_decrypt P((int));
+void cast_cfb64_init P((int));
+int cast_cfb64_start P((int, int));
+int cast_cfb64_is P((unsigned char *, int));
+int cast_cfb64_reply P((unsigned char *, int));
+int cast_cfb64_session P((Session_Key *, int));
+int cast_cfb64_keyid P((int, unsigned char *, int *));
+void cast_cfb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+void cast_ofb64_encrypt P((unsigned char *, int));
+int cast_ofb64_decrypt P((int));
+void cast_ofb64_init P((int));
+int cast_ofb64_start P((int, int));
+int cast_ofb64_is P((unsigned char *, int));
+int cast_ofb64_reply P((unsigned char *, int));
+int cast_ofb64_session P((Session_Key *, int));
+int cast_ofb64_keyid P((int, unsigned char *, int *));
+void cast_ofb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+void castexp_cfb64_encrypt P((unsigned char *, int));
+int castexp_cfb64_decrypt P((int));
+void castexp_cfb64_init P((int));
+int castexp_cfb64_start P((int, int));
+int castexp_cfb64_is P((unsigned char *, int));
+int castexp_cfb64_reply P((unsigned char *, int));
+int castexp_cfb64_session P((Session_Key *, int));
+int castexp_cfb64_keyid P((int, unsigned char *, int *));
+void castexp_cfb64_printsub P((unsigned char *, int, unsigned char *, int));
+
+void castexp_ofb64_encrypt P((unsigned char *, int));
+int castexp_ofb64_decrypt P((int));
+void castexp_ofb64_init P((int));
+int castexp_ofb64_start P((int, int));
+int castexp_ofb64_is P((unsigned char *, int));
+int castexp_ofb64_reply P((unsigned char *, int));
+int castexp_ofb64_session P((Session_Key *, int));
+int castexp_ofb64_keyid P((int, unsigned char *, int *));
+void castexp_ofb64_printsub P((unsigned char *, int, unsigned char *, int));
+#endif /* CAST_ENCRYPTION */
+
+/* int des_string_to_key P((char *, Block)); */
+
+#ifdef DEBUG
+extern int encrypt_debug_mode;
+#endif
+
+int decrypt_ks_hack(unsigned char *, int);
+
+#endif /* __ENCRYPTION__ */
+#endif /* ENCRYPTION */
+
+#ifdef CRYPT_DLL
+struct _crypt_dll_init {
+ int version;
+
+ /* Version 1 variables */
+ int (*p_ttol)(char *,int);
+ int (*p_dodebug)(int,char *,char *,CK_OFF_T);
+ int (*p_dohexdump)(char *,char *,int);
+ void (*p_tn_debug)(char *);
+ int (*p_vscrnprintf)(char *, ...);
+
+ /* Version 2 variables */
+ void * p_k5_context;
+
+ /* Version 3 variables */
+ void (*p_install_funcs)(char *,void *);
+
+ /* Version 5 variables */
+ unsigned long (*p_reqtelmutex)(unsigned long);
+ unsigned long (*p_reltelmutex)(void);
+};
+#endif /* CRYPT_DLL */
+
+/* per Kerberos v5 protocol spec */
+#ifndef ENCTYPE_NULL
+#define ENCTYPE_NULL 0x0000
+#endif
+#ifndef ENCTYPE_DES_CBC_CRC
+#define ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */
+#endif
+#ifndef ENCTYPE_DES_CBC_MD4
+#define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */
+#endif
+#ifndef ENCTYPE_DES_CBC_MD5
+#define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */
+#endif
+#ifndef ENCTYPE_DES_CBC_RAW
+#define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */
+#endif
+/* XXX deprecated? */
+#ifndef ENCTYPE_DES3_CBC_SHA
+#define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */
+#endif
+#ifndef ENCTYPE_DES3_CBC_RAW
+#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
+#endif
+#ifndef ENCTYPE_DES_HMAC_SHA1
+#define ENCTYPE_DES_HMAC_SHA1 0x0008
+#endif
+#ifndef ENCTYPE_DES3_CBC_SHA1
+#define ENCTYPE_DES3_CBC_SHA1 0x0010
+#endif
+#ifndef ENCTYPE_AES128_CTS_HMAC_SHA1_96
+#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011
+#endif
+#ifndef ENCTYPE_AES256_CTS_HMAC_SHA1_96
+#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012
+#endif
+#ifndef ENCTYPE_ARCFOUR_HMAC
+#define ENCTYPE_ARCFOUR_HMAC 0x0017
+#endif
+#ifndef ENCTYPE_ARCFOUR_HMAC_EXP
+#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018
+#endif
+#ifndef ENCTYPE_LOCAL_RC4_MD4
+#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80
+#endif
+#ifndef ENCTYPE_UNKNOWN
+#define ENCTYPE_UNKNOWN 0x01ff
+#endif
+/* local crud */
+/* marc's DES-3 with 32-bit length */
+#ifndef ENCTYPE_LOCAL_DES3_HMAC_SHA1
+#define ENCTYPE_LOCAL_DES3_HMAC_SHA1 0x7007
+#endif
+#endif /* KRB5_TELNET_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuath.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuath.c
new file mode 100644
index 0000000..ea9bc7d
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuath.c
@@ -0,0 +1,13362 @@
+char *ckathv = "Authentication, 9.0.235, 16 Mar 2010";
+/*
+ C K U A T H . C -- Authentication for C-Kermit
+
+ Copyright (C) 1999, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Author: Jeffrey E Altman (jaltman@secure-endpoints.com)
+ Secure Endpoints Inc., New York City
+*/
+/*
+ * Additional copyrights included with affected code.
+ */
+
+#ifdef HEIMDAL
+/*
+ Turned off User to User support
+ Turned off KDESTROY support
+ Turned off KLIST support
+ Turned off krb5_prompter() support
+ Turned off ticket validation
+ Turned off ticket renewal
+ Turned off alternative cache support in k5_get_ccache()
+
+ Remaining link problems:
+
+ ckuath.o: In function `ck_krb5_initTGT':
+ ckuath.o(.text+0x50c2): undefined reference to `krb5_string_to_deltat'
+ ckuath.o(.text+0x516d): undefined reference to `krb5_string_to_deltat'
+ ckuath.o(.text+0x51ef): undefined reference to `krb5_string_to_deltat'
+*/
+#endif /* HEIMDAL */
+
+/*
+ * Implements Kerberos 4/5, SRP, SSL, NTLM authentication and START_TLS
+ */
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+
+#ifdef CK_SECURITY
+
+#define CKUATH_C
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckucmd.h" /* For struct keytab */
+#include "ckcnet.h"
+#include "ckctel.h"
+
+char szUserNameRequested[UIDBUFLEN+1]; /* for incoming connections */
+char szUserNameAuthenticated[UIDBUFLEN+1];/* for incoming connections */
+char szHostName[UIDBUFLEN+1];
+char szUserName[UIDBUFLEN+1];
+static char szIP[16];
+static int validUser = AUTH_REJECT; /* User starts out invalid */
+int authentication_version = AUTHTYPE_NULL;
+int accept_complete = 0;
+
+#ifdef CK_AUTHENTICATION
+#ifdef CK_SSL
+#ifdef KRB5
+#define TLS_VERIFY
+#endif /* KRB5 */
+#endif /* CK_SSL */
+
+#ifdef CK_DES
+#ifdef CK_SSL
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+#endif /* CK_SSL */
+#endif /* CK_DES */
+
+#ifdef CRYPT_DLL
+#ifndef LIBDES
+#define LIBDES
+#endif /* LIBDES */
+#ifdef OS2
+#ifdef NT
+#include <windows.h>
+#else /* NT */
+#define INCL_DOSMODULEMGR
+#include <os2.h>
+#endif /* NT */
+#endif /* OS2 */
+#endif /* CRYPT_DLL */
+
+#ifdef NT
+#define KRB5_AUTOCONF__
+#define NTLM
+#endif /* NT */
+
+#ifdef CK_KERBEROS
+#define KINIT
+#ifndef HEIMDAL
+#define KLIST
+#define KDESTROY
+#endif /* HEIMDAL */
+#define CHECKADDRS
+#else /* CK_KERBEROS */
+#ifdef KRB4
+#undef KRB4
+#endif /* KRB4 */
+#ifdef KRB5
+#undef KRB5
+#endif /* KRB5 */
+#ifdef KRB524
+#undef KRB524
+#endif /* KRB524 */
+#endif /* CK_KERBEROS */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifndef malloc
+#ifndef VMS
+#ifndef FREEBSD4
+#ifndef OpenBSD
+#ifdef MACOSX
+#include <sys/malloc.h>
+#else /* MACOSX */
+#include <malloc.h>
+#endif /* MACOSX */
+#endif /* OpenBSD */
+#endif /* FREEBSD4 */
+#endif /* VMS */
+#endif /* malloc */
+#ifdef OS2
+#include <io.h>
+#endif /* OS2 */
+
+#ifdef KRB5
+#ifdef HEIMDAL
+#ifdef printf
+#define saveprintf printf
+#undef printf
+#endif /* printf */
+#include "krb5.h"
+
+#include "com_err.h"
+
+#ifdef saveprintf
+#define printf saveprintf
+#endif /* saveprintf */
+#else /* HEIMDAL */
+#include "krb5.h"
+#include "profile.h"
+#include "com_err.h"
+#ifdef KRB5_GET_INIT_CREDS_OPT_TKT_LIFE
+#define KRB5_HAVE_GET_INIT_CREDS
+#else
+#define krb5_free_unparsed_name(con,val) krb5_xfree((char *)(val))
+#endif
+#ifndef KRB5_HAVE_GET_INIT_CREDS
+#define krb5_free_data_contents(c,v) krb5_xfree((char *)(v)->data)
+#endif
+#endif /* HEIMDAL */
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#endif /* KRB5 */
+
+#ifdef KRB4
+#define des_cblock Block
+#define const_des_cblock const Block
+#define des_key_schedule Schedule
+#ifdef KRB524
+#ifdef NT
+#define _WINDOWS
+#endif /* NT */
+#include "kerberosIV/krb.h"
+#ifndef OS2
+#ifdef KRB524_CONV
+#include "krb524.h"
+#endif /* KRB524_CONV */
+_PROTOTYP(const char * krb_get_err_text_entry, (int));
+#endif /* OS2 */
+#else /* KRB524 */
+#ifdef SOLARIS
+#ifndef sun
+/* for some reason the Makefile entries for the Solaris systems have -Usun */
+#define sun
+#endif /* sun */
+#endif /* SOLARIS */
+#include "krb.h"
+#define krb_get_err_text_entry krb_get_err_text
+#endif /* KRB524 */
+#else /* KRB4 */
+#ifdef CK_SSL
+#define des_cblock Block
+#ifdef COMMENT
+#define const_des_cblock const Block
+#endif /* COMMENT */
+#define des_key_schedule Schedule
+#endif /* CK_SSL */
+#endif /* KRB4 */
+
+#include "ckuath.h"
+#ifdef CK_KERBEROS
+#ifndef KRB5
+#define NOBLOCKDEF
+#else /* KRB5 */
+#ifdef KRB524
+#define NOBLOCKDEF
+#endif /* KRB524 */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+#include "ckuat2.h"
+
+#ifdef CK_SSL
+#ifdef LIBDES
+#ifdef OPENSSL_097
+#ifdef CK_DES
+#define OPENSSL_ENABLE_OLD_DES_SUPPORT
+#include <openssl/des.h>
+#endif /* CK_DES */
+#endif /* OPENSSL_097 */
+#ifndef HEADER_DES_H
+#define HEADER_DES_H
+#endif /* HEADER_DES_H */
+#endif /* LIBDES */
+#include "ck_ssl.h"
+extern int ssl_finished_messages;
+#endif /* SSL */
+
+#define PWD_SZ 128
+
+#ifndef LIBDES
+#ifdef UNIX
+#define des_set_random_generator_seed(x) des_init_random_number_generator(x)
+#endif /* UNIX */
+#else /* LIBDES */
+#define des_fixup_key_parity des_set_odd_parity
+#endif /* LIBDES */
+
+#ifdef OS2
+#ifdef CK_ENCRYPTION
+#define MAP_DES
+#endif /* CK_ENCRYPTION */
+#ifdef KRB4
+#define MAP_KRB4
+#endif /* KRB4 */
+#ifdef SRPDLL
+#define MAP_SRP
+#endif /* SRPDLL */
+#ifdef KRB5
+#define MAP_KRB5
+#endif /* KRB5 */
+#ifdef CRYPT_DLL
+#define MAP_CRYPT
+#endif /* CRYPT_DLL */
+#define MAP_NTLM
+#include "ckoath.h"
+#include "ckosyn.h"
+#endif /* OS2 */
+
+/*
+ * Globals
+ */
+int auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_AUTO, AUTHTYPE_NULL};
+int auth_how=0;
+int auth_crypt=0;
+int auth_fwd=0;
+
+/* These are state completion variables */
+static int mutual_complete = 0;
+
+#ifdef KRB4
+#ifdef OS2
+static LEASH_CREDENTIALS cred;
+#else /* OS2 */
+static CREDENTIALS cred;
+#endif /* OS2 */
+static KTEXT_ST k4_auth;
+static char k4_name[ANAME_SZ];
+static AUTH_DAT k4_adat = { 0 };
+static MSG_DAT k4_msg_data;
+#ifdef CK_ENCRYPTION
+static Block k4_session_key = { 0 };
+static Schedule k4_sched;
+static Block k4_challenge = { 0 };
+#ifdef MIT_CURRENT
+static krb5_keyblock k4_krbkey;
+#endif /* MIT_CURRENT */
+#endif /* ENCRYPTION */
+#define KRB4_SERVICE_NAME "rcmd"
+
+_PROTOTYP(static int k4_auth_send,(VOID));
+_PROTOTYP(static int k4_auth_reply,(unsigned char *, int));
+_PROTOTYP(static int k4_auth_is,(unsigned char *, int));
+#endif /* KRB4 */
+
+#ifdef KRB5
+static krb5_data k5_auth;
+static krb5_auth_context auth_context;
+static krb5_keyblock *k5_session_key = NULL;
+static krb5_ticket *k5_ticket = NULL;
+#ifndef KRB5_SERVICE_NAME
+#define KRB5_SERVICE_NAME "host"
+#ifdef MACOSX
+#define MIT_CURRENT 1
+#define decode_krb5_ticket krb5_decode_ticket
+#define krb5_read_message ck_krb5_read_message
+#define krb5_write_message ck_krb5_write_message
+#endif /* MACOSX */
+#endif
+
+_PROTOTYP(static int k5_auth_send,(int,int,int));
+_PROTOTYP(static int k5_auth_reply,(int, unsigned char *, int));
+_PROTOTYP(static int k5_auth_is,(int,unsigned char *, int));
+_PROTOTYP(static int SendK5AuthSB,(int, void *, int));
+#ifdef TLS_VERIFY
+static int krb5_tls_verified = 0;
+#endif /* TLS_VERIFY */
+#endif /* KRB5 */
+
+#ifdef GSSAPI_KRB5
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+
+static gss_ctx_id_t gcontext;
+#define GSS_BUFSIZ 4096
+static gss_buffer_desc gss_send_tok, gss_recv_tok, *gss_token_ptr;
+static char gss_stbuf[GSS_BUFSIZ];
+static gss_name_t gss_target_name;
+static struct gss_channel_bindings_struct gss_chan;
+
+_PROTOTYP(static int gssk5_auth_send,(int,int,int));
+_PROTOTYP(static int gssk5_auth_reply,(int, unsigned char *, int));
+_PROTOTYP(static int gssk5_auth_is,(int,unsigned char *, int));
+_PROTOTYP(static int SendGSSK5AuthSB,(int, void *, int));
+#endif /* GSSAPI_KRB5 */
+
+#ifdef CK_SRP
+#ifdef PRE_SRP_1_7_3
+_PROTOTYP(static int srp_reply,(int, unsigned char *, int));
+_PROTOTYP(static int srp_is,(int, unsigned char *, int));
+#else /* PRE_SRP_1_7_3 */
+_PROTOTYP(static int new_srp_reply,(int, unsigned char *, int));
+_PROTOTYP(static int new_srp_is,(int, unsigned char *, int));
+#endif /* PRE_SRP_1_7_3 */
+#endif /* SRP */
+
+#ifdef CK_ENCRYPTION
+int encrypt_flag = 1;
+#endif
+#ifdef FORWARD
+int forward_flag = 0; /* forward tickets? */
+int forwardable_flag = 1; /* get forwardable tickets to forward? */
+int forwarded_tickets = 0; /* were tickets forwarded? */
+#endif
+
+static unsigned char str_data[4096] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+ AUTHTYPE_KERBEROS_V5, };
+#define AUTHTMPBL 2048
+static char strTmp[AUTHTMPBL+1];
+static char szLocalHostName[UIDBUFLEN+1];
+static kstream g_kstream=NULL;
+
+#ifdef KRB5
+krb5_context k5_context=NULL;
+static krb5_creds * ret_cred=NULL;
+static krb5_context telnet_context=NULL;
+static char * telnet_krb5_realm = NULL;
+static krb5_principal fwd_server = NULL;
+#endif /* KRB5 */
+
+#ifdef CK_SRP
+#ifdef PRE_SRP_1_4_4
+#ifndef PRE_SRP_1_4_5
+#define PRE_SRP_1_4_5
+#endif /* PRE_SRP_1_4_5 */
+#endif /* PRE_SRP_1_4_5 */
+#ifdef PRE_SRP_1_4_5
+#ifndef PRE_SRP_1_7_3
+#define PRE_SRP_1_7_3
+#endif /* PRE_SRP_1_7_3 */
+#endif /* PRE_SRP_1_4_5 */
+#include <t_pwd.h>
+#include <t_client.h>
+#include <t_server.h>
+static struct t_server * ts = NULL;
+static struct t_client * tc = NULL;
+#ifdef PRE_SRP_1_4_4
+static struct t_pw * tpw = NULL;
+static struct t_conf * tconf = NULL;
+#endif /* PRE_SRP_1_4_4 */
+#ifndef PRE_SRP_1_7_3
+#ifndef STDC_HEADERS
+#define STDC_HEADERS 1
+#endif /* STDC_HEADERS */
+#include <srp.h>
+static SRP * s_srp = NULL;
+static cstr * s_key = NULL;
+static SRP * c_srp = NULL;
+static cstr * c_key = NULL;
+#endif /* PRE_SRP_1_7_3 */
+static int srp_waitresp = 0; /* Flag to indicate readiness for response */
+static char srp_passwd[PWD_SZ];
+#endif /* CK_SRP */
+
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+#define OPTS_FORWARD_CREDS 0x00000020
+#define OPTS_FORWARDABLE_CREDS 0x00000010
+#define KCMD_KEYUSAGE 1026
+
+#define RLOG_BUFSIZ 5120
+static int rlog_encrypt = 0;
+char des_inbuf[2*RLOG_BUFSIZ]; /* needs to be > largest read size */
+char des_outpkt[2*RLOG_BUFSIZ+4]; /* needs to be > largest write size */
+#ifdef KRB5
+krb5_data desinbuf,desoutbuf;
+krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
+static krb5_data encivec_i[2], encivec_o[2];
+
+enum krb5_kcmd_proto {
+ /* Old protocol: DES encryption only. No subkeys. No protection
+ for cleartext length. No ivec supplied. OOB hacks used for
+ rlogin. Checksum may be omitted at connection startup. */
+ KCMD_OLD_PROTOCOL = 1,
+ /* New protocol: Any encryption scheme. Client-generated subkey
+ required. Prepend cleartext-length to cleartext data (but don't
+ include it in count). Starting ivec defined, chained. In-band
+ signalling. Checksum required. */
+ KCMD_NEW_PROTOCOL,
+ /* Hack: Get credentials, and use the old protocol iff the session
+ key type is single-DES. */
+ KCMD_PROTOCOL_COMPAT_HACK,
+ KCMD_UNKNOWN_PROTOCOL
+};
+enum krb5_kcmd_proto krb5_rlog_ver = KCMD_PROTOCOL_COMPAT_HACK;
+#endif /* KRB5 */
+#endif /* RLOGCODE */
+static char storage[65536]; /* storage for the decryption */
+static int nstored = 0;
+static char *store_ptr = storage;
+
+extern char * krb5_d_principal; /* Default principal */
+extern char * krb5_d_instance; /* Default instance */
+extern char * krb5_d_realm; /* Default realm */
+extern char * krb5_d_cc; /* Default credentials cache */
+extern char * krb5_d_srv; /* Default service name */
+extern int krb5_d_lifetime; /* Default lifetime */
+extern int krb5_d_forwardable;
+extern int krb5_d_proxiable;
+extern int krb5_d_renewable;
+extern int krb5_autoget;
+extern int krb5_checkaddrs;
+extern int krb5_d_getk4;
+extern int krb5_d_no_addresses;
+extern char * k5_keytab;
+
+extern int krb5_errno;
+extern char * krb5_errmsg;
+
+extern char * krb4_d_principal; /* Default principal */
+extern char * krb4_d_realm; /* Default realm */
+extern char * krb4_d_srv; /* Default service name */
+extern int krb4_d_lifetime; /* Default lifetime */
+extern int krb4_d_preauth;
+extern char * krb4_d_instance;
+extern int krb4_autoget;
+extern int krb4_checkaddrs;
+extern char * k4_keytab;
+
+extern int krb4_errno;
+extern char * krb4_errmsg;
+#endif /* CK_KERBEROS */
+
+extern char tn_msg[], hexbuf[]; /* from ckcnet.c */
+extern CHAR pwbuf[];
+extern int pwflg, pwcrypt;
+extern int deblog, debses, tn_deb;
+extern int sstelnet, inserver;
+#ifdef CK_LOGIN
+extern int ckxanon;
+#endif /* CK_LOGIN */
+extern int tn_auth_how;
+extern int tn_auth_enc;
+#ifdef CK_ENCRYPTION
+extern int cx_type;
+#endif /* CK_ENCRYPTION */
+extern int quiet, ttyfd, ttnproto;
+
+int
+ck_gssapi_is_installed()
+{
+#ifdef KRB5
+#ifdef OS2
+ return(hGSSAPI != NULL);
+#else /* OS2 */
+ return(1);
+#endif /* OS2 */
+#else /* KRB5 */
+ return(0);
+#endif /* KRB5 */
+}
+
+int
+ck_krb5_is_installed()
+{
+#ifdef KRB5
+#ifdef OS2
+ return(hKRB5_32 != NULL);
+#else /* OS2 */
+ return(1);
+#endif /* OS2 */
+#else /* KRB5 */
+ return(0);
+#endif /* KRB5 */
+}
+
+
+int
+ck_krb5_is_installed_as_server()
+{
+#ifdef KRB5
+#ifdef HEIMDAL
+ krb5_error_code ret;
+ krb5_keytab kt;
+ krb5_kt_cursor cursor;
+
+ ret = krb5_kt_default(k5_context, &kt);
+ if ( ret ) {
+ krb5_kt_close(k5_context, kt);
+ return(0);
+ } else {
+ krb5_kt_end_seq_get(k5_context, kt, &cursor);
+ krb5_kt_close(k5_context, kt);
+ return(1);
+ }
+#else /* HEIMDAL */
+#ifndef COMMENT
+ char ktname[CKMAXPATH]="";
+
+ if ( k5_keytab ) {
+ ckstrncpy(ktname,k5_keytab,CKMAXPATH);
+ } else {
+ krb5_error_code code;
+
+ if ( k5_context == NULL)
+ if (krb5_init_context(&k5_context))
+ return(0);
+
+ code = krb5_kt_default_name(k5_context,ktname,CKMAXPATH);
+ debug(F101,"krb5_kt_default_name","",code);
+ if ( code ) {
+ /* We can't check the existence of the file since we can't */
+ /* determine the file name. So we return TRUE and let */
+ /* Krb5 be offered to the user even though it may fail later */
+ return(1);
+ }
+ }
+
+ if ( !strncmp("FILE:",ktname,5) ) {
+ if ( zchki(&ktname[5]) > 0 )
+ return(1);
+ else
+ return(0);
+ } else {
+ if (ktname[0])
+ return(1);
+ else
+ return(0);
+ }
+#else /* COMMENT */
+ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
+ krb5_context krb5context = NULL;
+ krb5_ccache krb5ccdef = NULL;
+ krb5_creds krb5creds, *krb5credsp = NULL;
+ int rc = 0;
+
+ if ( !ck_krb5_is_installed() )
+ return(0);
+
+ memset((char *)&krb5creds, 0, sizeof(krb5creds));
+
+ if ((krb5rc = krb5_init_context(&krb5context)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_sname_to_principal(krb5context,
+ szHostName,
+ krb5_d_srv ?
+ krb5_d_srv :
+ KRB5_SERVICE_NAME,
+ KRB5_NT_SRV_HST,
+ &krb5creds.server)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
+ &krb5creds.client)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
+ &krb5creds, &krb5credsp)) != 0)
+ goto err;
+ rc = 1;
+
+ err:
+
+ if (krb5creds.client)
+ krb5_free_principal(krb5context, krb5creds.client);
+ if (krb5creds.server)
+ krb5_free_principal(krb5context, krb5creds.server);
+ if (krb5context)
+ krb5_free_context(krb5context);
+ return(rc);
+
+#endif /* COMMENT */
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return(0);
+#endif /* KRB5 */
+}
+
+int
+ck_krb4_is_installed()
+{
+#ifdef KRB4
+#ifdef OS2
+ return(hKRB4_32 != NULL);
+#else /* OS2 */
+ return(1);
+#endif /* OS2 */
+#else /* KRB4 */
+ return(0);
+#endif /* KRB4 */
+}
+
+int
+ck_krb4_is_installed_as_server()
+{
+ if ( !ck_krb4_is_installed() )
+ return(0);
+
+#ifdef KRB4
+ if ( !k4_keytab ) {
+#ifdef NT
+ char name[CKMAXPATH]="";
+ DWORD len = CKMAXPATH;
+
+ len = GetWindowsDirectory(name,len);
+ if ( len > 0 )
+ ckstrncat(name,"/srvtab",CKMAXPATH);
+ if ( name[0] )
+ makestr(&k4_keytab,name);
+#else /* NT */
+ makestr(&k4_keytab,"/etc/srvtab");
+#endif /* NT */
+ }
+
+ if ( !k4_keytab )
+ return(0);
+
+ if ( zchki(k4_keytab) > 0 )
+ return(1);
+#ifdef KRB524
+ else if (ck_krb5_is_installed_as_server())
+ return(1);
+#endif /* KRB524 */
+ else
+ return(0);
+#endif /* KRB4 */
+}
+
+int
+ck_srp_is_installed_as_server()
+{
+#ifdef CK_SRP
+#ifdef SRPDLL
+ if ( hSRP == NULL )
+ return(0);
+#endif /* SRPDLL */
+#ifdef COMMENT
+ /* This is the new API as of 1.7.4. However, all it does
+ is allocate a data structure. It can never fail.
+ */
+ {
+ SRP * s_srp = SRP_new(SRP_RFC2945_server_method());
+ if ( s_srp ) {
+ SRP_free(s_srp);
+ s_srp = NULL;
+ return(1);
+ }
+ return(0);
+ }
+#else /* COMMENT */
+ {
+ struct t_pw * tpw = NULL;
+ struct t_conf * tconf = NULL;
+ if((tconf = t_openconf(NULL)) == NULL)
+ return(0);
+ if((tpw = t_openpw(NULL)) == NULL) {
+ t_closeconf(tconf);
+ return(0);
+ }
+ t_closeconf(tconf);
+ t_closepw(tpw);
+ return(1);
+ }
+#endif /* COMMENT */
+#else /* SRP */
+ return(0);
+#endif /* SRP */
+}
+
+int
+ck_srp_is_installed()
+{
+#ifdef CK_SRP
+#ifdef SRPDLL
+ if ( hSRP == NULL )
+ return(0);
+#endif /* SRPDLL */
+ return(1);
+#else /* CK_SRP */
+ return(0);
+#endif /* CK_SRP */
+}
+
+int
+ck_krypto_is_installed()
+{
+#ifdef CK_SRP
+#ifdef OS2
+ if ( hLIBKRYPTO == NULL )
+ return(0);
+#endif /* OS2 */
+ return(1);
+#else /* CK_SRP */
+ return(0);
+#endif /* CK_SRP */
+}
+
+int
+ck_crypt_is_installed()
+{
+#ifdef CK_ENCRYPTION
+#ifdef CRYPT_DLL
+ return(hCRYPT != NULL);
+#else /* CRYPT_DLL */
+ return(1);
+#endif /* CRYPT_DLL */
+#else /* ENCRYPTION */
+ return(0);
+#endif /* ENCRYPTION */
+}
+
+int
+ck_ntlm_is_installed()
+{
+#ifdef NT
+ return(hSSPI != NULL);
+#else /* NT */
+ return(0);
+#endif /* NT */
+}
+
+int
+ck_tn_auth_valid()
+{
+ return(validUser);
+}
+
+/* C K _ K R B _ A U T H _ I N _ P R O G R E S S
+ *
+ * Is an authentication negotiation still in progress?
+ *
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_auth_in_progress(void)
+#else
+ck_tn_auth_in_progress()
+#endif
+{
+ switch (authentication_version) {
+ case AUTHTYPE_AUTO:
+ return(1);
+ case AUTHTYPE_NULL:
+ return(0);
+#ifdef KRB4
+ case AUTHTYPE_KERBEROS_V4:
+ if (!accept_complete) {
+ debug(F100,"ck_auth_in_progress() Kerberos 4 !accept_complete",
+ "",0);
+ return(1);
+ }
+ else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) {
+ debug(F100,"ck_auth_in_progress() Kerberos 4 !mutual_complete",
+ "",0);
+ return(1);
+ }
+ else
+ return(0);
+#endif /* KRB4 */
+#ifdef KRB5
+ case AUTHTYPE_KERBEROS_V5:
+ if (!accept_complete) {
+ debug(F100,"ck_auth_in_progress() Kerberos 5 !accept_complete",
+ "",0);
+ return(1);
+ }
+ else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) {
+ debug(F100,"ck_auth_in_progress() Kerberos 5 !mutual_complete",
+ "",0);
+ return(1);
+ }
+ else
+ return(0);
+#ifdef GSSAPI_K5
+ case AUTHTYPE_GSSAPI_KRB5:
+ if (!accept_complete) {
+ debug(F100,
+ "ck_auth_in_progress() GSSAPI Kerberos 5 !accept_complete",
+ "",
+ 0
+ );
+ return(1);
+ }
+ else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) {
+ debug(F100,
+ "ck_auth_in_progress() GSSAPI Kerberos 5 !mutual_complete",
+ "",
+ 0
+ );
+ return(1);
+ } else
+ return(0);
+ break;
+#endif /* GSSAPI_K5 */
+#endif /* KRB5 */
+#ifdef CK_SRP
+ case AUTHTYPE_SRP:
+ if (!accept_complete || srp_waitresp)
+ return(1);
+ else
+ return(0);
+#endif /* CK_SRP */
+#ifdef NTLM
+ case AUTHTYPE_NTLM:
+ if (!accept_complete) {
+ debug(F100,"ck_auth_in_progress() NTLM !accept_complete",
+ "",0);
+ return(1);
+ }
+ else
+ return(0);
+#endif /* NTLM */
+ case AUTHTYPE_SSL:
+ if (!accept_complete) {
+ debug(F100,"ck_auth_in_progress() SSL !accept_complete",
+ "",0);
+ return(1);
+ }
+ else
+ return(0);
+ default:
+ return(0);
+ }
+ return(0);
+}
+
+
+/* C K _ K R B _ T N _ A U T H _ R E Q U E S T
+ *
+ * Builds a Telnet Authentication Send Negotiation providing the
+ * list of supported authentication methods. To be used only
+ * when accepting incoming connections as only the server (DO) side of the
+ * Telnet negotiation is allowed to send an AUTH SEND.
+ *
+ * Returns: 0 on success and -1 on failure
+ */
+
+static unsigned char str_request[64] = { IAC, SB,
+ TELOPT_AUTHENTICATION,
+ TELQUAL_SEND };
+#ifdef GSSAPI_K5
+static int
+ck_tn_auth_request_gsskrb5(int i)
+{
+ if (ck_gssapi_is_installed() && ck_krb5_is_installed_as_server()) {
+ if ( (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_EXCH) ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_AFTER_EXCHANGE;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+}
+#endif /* GSSAPI_K5 */
+
+#ifdef KRB5
+static int
+ck_tn_auth_request_krb5(int i)
+{
+ if (ck_krb5_is_installed_as_server()) {
+#ifdef CK_SSL
+ if ( ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) &&
+ ssl_finished_messages )
+ {
+#ifdef USE_INI_CRED_FWD
+ if ( forward_flag &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT)
+ )
+ {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_START_TLS;
+ str_request[i] |= INI_CRED_FWD_ON;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS|INI_CRED_FWD_ON ",
+ TN_MSG_LEN);
+ i++;
+ }
+#endif /* USE_INI_CRED_FWD */
+ if ( (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT) ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_START_TLS;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS ",
+ TN_MSG_LEN);
+ i++;
+ }
+ if ( tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_START_TLS;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+#ifdef CK_ENCRYPTION
+ else
+ {
+#endif /* CK_ENCRYPTION */
+#endif /* CK_SSL */
+#ifdef CK_ENCRYPTION
+#ifdef USE_INI_CRED_FWD
+ if ( forward_flag &&
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT)
+ )
+ {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
+ str_request[i] |= INI_CRED_FWD_ON;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT|INI_CRED_FWD_ON ",
+ TN_MSG_LEN);
+ i++;
+ }
+#endif /* USE_INI_CRED_FWD */
+
+ if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT) ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT ",
+ TN_MSG_LEN);
+ i++;
+ }
+#ifdef CK_SSL
+ }
+#endif /* CK_SSL */
+#endif /* CK_ENCRYPTION */
+
+ if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_NONE)
+#ifdef CK_SSL
+ && !(ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) &&
+ tls_is_anon(0))
+#endif /* CK_SSL */
+ )
+ {
+#ifdef CK_ENCRYPTION
+ /* Can't perform mutual authentication without encryption */
+ if ( tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL ",
+ TN_MSG_LEN);
+ i++;
+ }
+#endif /* CK_ENCRYPTION */
+ if ( tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V5;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+ }
+ return(i);
+}
+#endif /* KRB5 */
+#ifdef KRB4
+static int
+ck_tn_auth_request_krb4(int i)
+{
+ if (ck_krb4_is_installed_as_server()) {
+#ifdef CK_ENCRYPTION
+ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT) )
+ {
+ str_request[i++] = AUTHTYPE_KERBEROS_V4;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL|ENCRYPT ",
+ TN_MSG_LEN);
+ i++;
+ }
+#endif /* CK_ENCRYPTION */
+
+ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_NONE) )
+ {
+#ifdef CK_ENCRYPTION
+ /* Can't perform mutual authentication without encryption */
+ if ( tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V4;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL ",
+ TN_MSG_LEN);
+ i++;
+ }
+#endif /* CK_ENCRYPTION */
+ if ( tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY ) {
+ str_request[i++] = AUTHTYPE_KERBEROS_V4;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|ONE_WAY ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+ }
+
+ return(i);
+}
+#endif /* KRB4 */
+
+#ifdef CK_SRP
+static int
+ck_tn_auth_request_srp(int i)
+{
+ if (ck_srp_is_installed_as_server()) {
+#ifndef PRE_SRP_1_4_5
+ /* Dont' do this yet. SRP when it uses the ENCRYPT_USING_TELOPT */
+ /* flag it must perform a checksum of the auth-type-pair but there */
+ /* is no mechansim to do that yet. */
+#ifdef CK_SSL
+ if ( ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) &&
+ ssl_finished_messages &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT))
+ {
+ str_request[i++] = AUTHTYPE_SRP;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_START_TLS;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ",
+ TN_MSG_LEN);
+ i++;
+ }
+#ifdef CK_ENCRYPTION
+ else {
+#endif /* CK_ENCRYPTION */
+#endif /* CK_SSL */
+#ifdef CK_ENCRYPTION
+ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_TELOPT)
+ ) {
+ str_request[i++] = AUTHTYPE_SRP;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_USING_TELOPT;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,
+ "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT ",
+ TN_MSG_LEN);
+ i++;
+ }
+#ifdef CK_SSL
+ }
+#endif /* CK_SSL */
+#endif /* CK_ENCRYPTION */
+#endif /* PRE_SRP_1_4_5 */
+ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_MUTUAL) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_NONE)
+#ifdef CK_SSL
+ && !(ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) &&
+ tls_is_anon(0))
+#endif /* CK_SSL */
+ )
+ {
+ str_request[i++] = AUTHTYPE_SRP;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"SRP CLIENT_TO_SERVER|ONE_WAY ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+
+ return(i);
+}
+#endif /* CK_SRP */
+
+#ifdef CK_SSL
+static int
+ck_tn_auth_request_ssl(int i)
+{
+ if (ck_ssleay_is_installed()
+ && !tls_active_flag && !ssl_active_flag && ssl_initialized
+ ) {
+ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_NONE) )
+ {
+ str_request[i++] = AUTHTYPE_SSL;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"SSL CLIENT_TO_SERVER|ONE_WAY ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+
+ return(i);
+}
+#endif /* CK_SSL */
+#ifdef NTLM
+static int
+ck_tn_auth_request_ntlm(int i)
+{
+ /* Microsoft's Telnet client won't perform authentication if */
+ /* NTLM is not first. */
+ if ( ck_ntlm_is_valid(1) ) {
+ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU &&
+ (tn_auth_how == TN_AUTH_HOW_ANY ||
+ tn_auth_how == TN_AUTH_HOW_ONE_WAY) &&
+ (tn_auth_enc == TN_AUTH_ENC_ANY ||
+ tn_auth_enc == TN_AUTH_ENC_NONE) )
+ {
+ str_request[i++] = AUTHTYPE_NTLM;
+ str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
+ str_request[i] |= AUTH_ENCRYPT_OFF;
+ if ( deblog || tn_deb || debses )
+ ckstrncat(tn_msg,"NTLM CLIENT_TO_SERVER|ONE_WAY ",
+ TN_MSG_LEN);
+ i++;
+ }
+ }
+
+ return(i);
+}
+#endif /* NTLM */
+int
+#ifdef CK_ANSIC
+ck_tn_auth_request(void)
+#else
+ck_tn_auth_request()
+#endif
+{
+ int i = 4, rc = -1;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return(0);
+ }
+#endif /* CK_SSL */
+
+ if ( deblog || tn_deb || debses )
+ strcpy(tn_msg,"TELNET SENT SB AUTHENTICATION SEND ");
+
+ /* Create a list of acceptable Authentication types to send to */
+ /* the client and let it choose find one that we support */
+
+ /* For those authentication methods that support Encryption or */
+ /* Credentials Forwarding we must send all of the appropriate */
+ /* combinations based upon the state of */
+ /* TELOPT_x_MODE(TELOPT_ENCRYPTION) and forward_flag. */
+
+ if ( auth_type_user[0] == AUTHTYPE_AUTO ) {
+#ifdef GSSAPI_K5
+ i = ck_tn_auth_request_gsskrb5(i);
+#endif /* GSSAPI_K5 */
+#ifdef KRB5
+ i = ck_tn_auth_request_krb5(i);
+#endif /* KRB5 */
+#ifdef KRB4
+ i = ck_tn_auth_request_krb4(i);
+#endif /* KRB4 */
+#ifdef CK_SRP
+ i = ck_tn_auth_request_srp(i);
+#endif /* SRP */
+#ifdef CK_SSL
+ i = ck_tn_auth_request_ssl(i);
+#endif /* CK_SSL */
+#ifdef NTLM
+ i = ck_tn_auth_request_ntlm(i);
+#endif /* NTLM */
+ } else {
+ int j;
+ for ( j=0;
+ j<AUTHTYPLSTSZ && auth_type_user[j] != AUTHTYPE_NULL;
+ j++) {
+#ifdef NTLM
+ if (auth_type_user[j] == AUTHTYPE_NTLM)
+ i = ck_tn_auth_request_ntlm(i);
+#endif /* NTLM */
+#ifdef CK_SSL
+ if ( auth_type_user[j] == AUTHTYPE_SSL )
+ i = ck_tn_auth_request_ssl(i);
+#endif /* CK_SSL */
+#ifdef CK_SRP
+ if ( auth_type_user[j] == AUTHTYPE_SRP )
+ i = ck_tn_auth_request_srp(i);
+#endif /* SRP */
+#ifdef GSSAPI_K5
+ if ( auth_type_user[j] == AUTHTYPE_GSSAPI_KRB5 )
+ i = ck_tn_auth_request_gsskrb5(i);
+#endif /* GSSAPI_K5 */
+#ifdef KRB5
+ if ( auth_type_user[j] == AUTHTYPE_KERBEROS_V5 )
+ i = ck_tn_auth_request_krb5(i);
+#endif /* KRB5 */
+#ifdef KRB4
+ if ( auth_type_user[j] == AUTHTYPE_KERBEROS_V4 )
+ i = ck_tn_auth_request_krb4(i);
+#endif /* KRB4 */
+ }
+ }
+
+ str_request[i++] = IAC;
+ str_request[i++] = SE;
+ if ( deblog || tn_deb || debses ) {
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Send data */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ rc = ttol((CHAR *)str_request, i);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ if ( rc == i )
+ return(0);
+ else
+ return(-1);
+}
+
+#ifdef CK_ENCRYPTION
+VOID
+ck_tn_enc_start()
+{
+ if (!TELOPT_ME(TELOPT_ENCRYPTION) && !TELOPT_U(TELOPT_ENCRYPTION))
+ return;
+ if (!TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop &&
+ (!encrypt_is_decrypting() || !encrypt_is_encrypting())) {
+ debug(F110,"ck_tn_enc_start","nothing to do",0);
+ return;
+ }
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
+ if (TELOPT_ME(TELOPT_ENCRYPTION) && !encrypt_is_encrypting()) {
+ debug(F110,"ck_tn_enc_start","encrypt_request_start",0);
+ encrypt_request_start();
+ }
+ if (TELOPT_U(TELOPT_ENCRYPTION) && !encrypt_is_decrypting()) {
+ debug(F110,"ck_tn_enc_start","encrypt_send_request_start",0);
+ encrypt_send_request_start();
+ }
+ tn_wait("encrypt start");
+ tn_push();
+}
+
+VOID
+ck_tn_enc_stop()
+{
+ if (!TELOPT_ME(TELOPT_ENCRYPTION) && !TELOPT_U(TELOPT_ENCRYPTION))
+ return;
+ if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop ||
+ !(encrypt_is_decrypting() || encrypt_is_encrypting())) {
+ debug(F110,"ck_tn_enc_stop","nothing to do",0);
+ return;
+ }
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 1;
+ if (TELOPT_U(TELOPT_ENCRYPTION) && encrypt_is_decrypting()) {
+ debug(F110,"ck_tn_enc_stop","encrypt_send_request_end",0);
+ encrypt_send_request_end();
+ }
+ if (TELOPT_ME(TELOPT_ENCRYPTION) && encrypt_is_encrypting()) {
+ debug(F110,"ck_tn_enc_stop","encrypt_send_end",0);
+ encrypt_send_end();
+ }
+ tn_wait("encrypt stop");
+ tn_push();
+}
+#endif /* CK_ENCRYPTION */
+
+/* C K _ K R B _ T N _ S B _ A U T H
+ * An interface between the C-Kermit Telnet Command Parser and the Authent-
+ * ication option parser implemented in the Kerberos Telnet client.
+ *
+ * sb - the subnegotiation as calculated in ckcnet.c
+ * len - the length of the buffer
+ *
+ * Returns: 0 on success and -1 on failure
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_sb_auth(char * sb, int len)
+#else /* CK_ANSIC */
+ck_tn_sb_auth(sb,len) char * sb; int len;
+#endif /* CK_ANSIC */
+{
+ /* auth_parse() assumes that sb starts at pos 1 not 0 as in ckcnet.c */
+ /* and it wants the length to exclude the IAC SE bytes */
+ CHAR * buf;
+ int rc = -1;
+
+ buf = malloc(len-1);
+ if ( !buf ) return(-1);
+
+ buf[0] = SB;
+ memcpy( &buf[1], sb, len-2 );
+ rc = auth_parse(buf,len-1);
+ free(buf);
+ debug(F111,"ck_tn_sb_auth","rc",rc);
+ if (rc == AUTH_FAILURE) {
+ authentication_version = AUTHTYPE_NULL;
+#ifndef NOLOCAL
+#ifdef OS2
+ ipadl25();
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(-1);
+ }
+#ifndef NOLOCAL
+#ifdef OS2
+ ipadl25();
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(0);
+}
+
+/* C K _ K R B _ T N _ S B _ E N C R Y P T
+ * An interface between the C-Kermit Telnet Command Parser and the Encryption
+ * option parser implemented in the Kerberos Telnet client.
+ *
+ * sb - the subnegotiation as calculated in ckcnet.c
+ * len - the length of the buffer
+ *
+ * Returns: Always returns 0 for success since encrypt_parse is void
+ */
+
+
+int
+#ifdef CK_ANSIC
+ck_tn_sb_encrypt(char * sb, int len)
+#else
+ck_tn_sb_encrypt(sb,len) char * sb; int len;
+#endif /* CK_ANSIC */
+{
+ /* encrypt_parse() assumes that sb starts at pos 1 not 0 as in ckcnet.c */
+ /* and it wants the length to exclude the IAC SE bytes */
+#ifdef CK_ENCRYPTION
+ char * buf;
+ int rc = -1;
+
+ buf = malloc(len-1);
+ if ( !buf ) return(-1);
+
+ buf[0] = SB;
+ memcpy( &buf[1], sb, len-2 );
+ rc = encrypt_parse((CHAR *)buf,len-1);
+
+ if (rc < 0) {
+ free(buf);
+ return(-1);
+ }
+
+ /* This is a hack. It does not belong here but should really be in */
+ /* encrypt_parse() but in K95 the encrypt_parse() routine does not */
+ /* have access to the telopt_states array. */
+ if ( buf[1] == ENCRYPT_REQEND )
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 1;
+ else if ( buf[1] == ENCRYPT_REQSTART )
+ TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
+#ifndef NOLOCAL
+#ifdef OS2
+ ipadl25();
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ free(buf);
+#endif /* ENCRYPTION */
+ return(0);
+}
+
+
+/* C K _ K R B _ E N C R Y P T I N G
+ * Returns 1 if we are encrypting and 0 if we are not
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_encrypting(VOID)
+#else /* CK_ANSIC */
+ck_tn_encrypting()
+#endif /* CK_ANSIC */
+{
+#ifdef CK_ENCRYPTION
+ if ( g_kstream == NULL )
+ return(0);
+ if ( g_kstream->encrypt && encrypt_is_encrypting()) {
+ debug(F111,"ck_tn_encrypting","encrypting",
+ g_kstream->encrypt_type);
+ return(g_kstream->encrypt_type);
+ }
+#endif /* CK_ENCRYPTION */
+ debug(F110,"ck_tn_encrypting","not encrypting",0);
+ return(0);
+}
+
+/* C K _ K R B _ D E C R Y P T I N G
+ * Returns 1 if we are decrypting and 0 if we are not
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_decrypting(VOID)
+#else
+ck_tn_decrypting()
+#endif /* CK_ANSIC */
+{
+#ifdef CK_ENCRYPTION
+ if ( g_kstream == NULL )
+ return(0);
+ if ( g_kstream->decrypt && encrypt_is_decrypting()) {
+ debug(F111,"ck_tn_decrypting","decrypting",
+ g_kstream->decrypt_type);
+ return(g_kstream->decrypt_type);
+ }
+#endif /* CK_ENCRYPTION */
+ debug(F110,"ck_tn_decrypting","not decrypting",0);
+ return(0);
+}
+
+/* C K _ K R B _ A U T H E N T I C A T E D
+ * Returns the authentication type: AUTHTYPE_NULL, AUTHTYPE_KERBEROS4,
+ * or AUTHTYPE_KERBEROS5, AUTHTYPE_SRP, ... (see ckctel.h)
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_authenticated(VOID)
+#else
+ck_tn_authenticated()
+#endif
+{
+ return(authentication_version);
+}
+
+/* C K _ K R B _ E N C R Y P T
+ * encrypts n characters in s if we are encrypting
+ */
+
+VOID
+#ifdef CK_ANSIC
+ck_tn_encrypt( char * s, int n )
+#else
+ck_tn_encrypt( s,n ) char * s; int n;
+#endif
+{
+#ifdef CK_ENCRYPTION
+ struct kstream_data_block i;
+
+ if (g_kstream->encrypt && encrypt_is_encrypting()) {
+#ifdef DEBUG
+ ckhexdump("from plaintext", s, n);
+#endif
+ i.ptr = s;
+ i.length = n;
+ g_kstream->encrypt(&i, NULL);
+#ifdef DEBUG
+ ckhexdump("to cyphertext", s, n);
+#endif
+ }
+ else debug(F101,"ck_tn_encrypt not encrypting","",n);
+#endif /* ENCRYPTION */
+}
+
+/* C K _ K R B _ D E C R Y P T
+ * decrypts n characters in s if we are decrypting
+ */
+
+VOID
+#ifdef CK_ANSIC
+ck_tn_decrypt( char * s, int n )
+#else
+ck_tn_decrypt( s,n ) char * s; int n;
+#endif
+{
+#ifdef CK_ENCRYPTION
+ struct kstream_data_block i;
+
+ if (g_kstream->decrypt && encrypt_is_decrypting()) {
+
+#ifdef DEBUG
+ ckhexdump("from cyphertext", s, n);
+#endif
+
+ i.ptr = s;
+ i.length = n;
+ g_kstream->decrypt(&i, NULL);
+#ifdef DEBUG
+ ckhexdump("to plaintext", s, n);
+#endif
+ }
+ else debug(F101,"ck_tn_decrypt not decrypting","",n);
+#endif /* ENCRYPTION */
+}
+
+/* S E N D K 5 A U T H S B
+ * Send a Kerberos 5 Authentication Subnegotiation to host and
+ * output appropriate Telnet Debug messages
+ *
+ * type - Sub Negotiation type
+ * data - ptr to buffer containing data
+ * len - len of buffer if not NUL terminated
+ *
+ * returns number of characters sent or error value
+ */
+
+static int
+#ifdef CK_ANSIC
+SendK5AuthSB(int type, void *data, int len)
+#else
+SendK5AuthSB(type,data,len) int type; void *data; int len;
+#endif
+{
+ int rc;
+ unsigned char *p = str_data + 3;
+ unsigned char *cd = (unsigned char *)data;
+ extern int sstelnet;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ if (ttchk() < 0)
+ return(0);
+ else
+ return(1);
+ }
+#endif /* CK_SSL */
+
+ if ( type < 0 || type > 7 ) /* Check for invalid values */
+ return(0);
+
+ if (!cd) {
+ cd = (unsigned char *)"";
+ len = 0;
+ }
+
+ if (len == -1) /* Use strlen() for len */
+ len = strlen((char *)cd);
+
+ /* Construct Message */
+ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
+ *p++ = AUTHTYPE_KERBEROS_V5;
+ *p = AUTH_CLIENT_TO_SERVER;
+ *p |= auth_how;
+#ifdef CK_ENCRYPTION
+ *p |= auth_crypt;
+#endif
+#ifdef USE_INI_CRED_FWD
+ if (auth_fwd)
+ *p |= INI_CRED_FWD_ON;
+#endif /* USE_INI_CRED_FWD */
+ p++;
+ *p++ = type;
+ while (len-- > 0) {
+ if ((*p++ = *cd++) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ /* Handle Telnet Debugging Messages */
+ if (deblog || tn_deb || debses) {
+ int i;
+ int deblen=p-str_data-2;
+ char *s=NULL;
+ int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) |
+ auth_crypt
+#ifdef USE_INI_CRED_FWD
+ | (auth_fwd?INI_CRED_FWD_ON:INI_CRED_FWD_OFF)
+#endif /* USE_INI_CRED_FWD */
+ ;
+
+ switch (type) {
+ case 0:
+ s = "AUTH";
+ break;
+ case 1:
+ s = "REJECT";
+ break;
+ case 2:
+ s = "ACCEPT";
+ break;
+ case 3:
+ s = "RESPONSE";
+ break;
+ case 4:
+ s = "FORWARD";
+ break;
+ case 5:
+ s = "FORWARD_ACCEPT";
+ break;
+ case 6:
+ s = "FORWARD_REJECT";
+ break;
+ case 7:
+ s = "TLS_VERIFY";
+ break;
+ }
+
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",
+ TELOPT(TELOPT_AUTHENTICATION)," ",
+ str_data[3] == TELQUAL_IS ? "IS" :
+ str_data[3] == TELQUAL_REPLY ? "REPLY" : "???"," ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," ",
+ s," ",NULL);
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Send data */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ rc = ttol((CHAR *)str_data, p - str_data);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ debug(F111,"SendK5AuthSB","ttol()",rc);
+ return(rc);
+}
+
+/* S E N D K 4 A U T H S B
+ * Send a Kerberos 4 Authentication Subnegotiation to host and
+ * output appropriate Telnet Debug messages
+ *
+ * type - Sub Negotiation type
+ * data - ptr to buffer containing data
+ * len - len of buffer if not NUL terminated
+ *
+ * returns number of characters sent or error value
+ */
+
+static int
+#ifdef CK_ANSIC
+SendK4AuthSB(int type, void *data, int len)
+#else
+SendK4AuthSB(type,data,len) int type; void *data; int len;
+#endif
+{
+ int rc;
+ unsigned char *p = str_data + 3;
+ unsigned char *cd = (unsigned char *)data;
+ extern int sstelnet;
+ int mode = (auth_how & AUTH_HOW_MASK) |
+ auth_crypt;
+
+ if ( type < 0 || type > 4 ) /* Check for invalid values */
+ return(0);
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ if (ttchk() < 0)
+ return(0);
+ else
+ return(1);
+ }
+#endif /* CK_SSL */
+
+ if (!cd) {
+ cd = (unsigned char *)"";
+ len = 0;
+ }
+
+ if (len == -1) /* Use strlen() for len */
+ len = strlen((char *)cd);
+
+
+ /* Construct Message */
+ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
+ *p++ = AUTHTYPE_KERBEROS_V4;
+ *p = AUTH_CLIENT_TO_SERVER;
+ *p |= mode;
+ p++;
+ *p++ = type;
+ while (len-- > 0) {
+ if ((*p++ = *cd++) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ /* Handle Telnet Debugging Messages */
+ if (deblog || tn_deb || debses) {
+ int i;
+ int deblen=p-str_data-2;
+ char *s=NULL;
+
+ switch (type) {
+ case 0:
+ s = "AUTH";
+ break;
+ case 1:
+ s = "REJECT";
+ break;
+ case 2:
+ s = "ACCEPT";
+ break;
+ case 3:
+ s = "CHALLENGE";
+ break;
+ case 4:
+ s = "RESPONSE";
+ break;
+ }
+
+ ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET SENT SB ",
+ TELOPT(TELOPT_AUTHENTICATION)," ",
+ str_data[3] == TELQUAL_IS ? "IS" :
+ (str_data[3] == TELQUAL_REPLY ? "REPLY" : "???")," ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," ",
+ s," ",NULL);
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Send data */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ rc = ttol((CHAR *)str_data, p - str_data);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ debug(F111,"SendK4AuthSB","ttol()",rc);
+ return(rc);
+}
+
+/* S E N D S R P A U T H S B
+ * Send a SRP Authentication Subnegotiation to host and
+ * output appropriate Telnet Debug messages
+ *
+ * type - Sub Negotiation type
+ * data - ptr to buffer containing data
+ * len - len of buffer if not NUL terminated
+ *
+ * returns number of characters sent or error value
+ */
+
+static int
+#ifdef CK_ANSIC
+SendSRPAuthSB(int type, void *data, int len)
+#else
+SendSRPAuthSB(type,data,len) int type; void *data; int len;
+#endif
+{
+ int rc;
+ unsigned char *p = str_data + 3;
+ unsigned char *cd = (unsigned char *)data;
+ extern int sstelnet;
+
+ /* Check for invalid values */
+ if ( type != SRP_EXP && type != SRP_RESPONSE &&
+ type != SRP_REJECT && type != SRP_ACCEPT &&
+ type != SRP_CHALLENGE && type != SRP_PARAMS &&
+ type != SRP_AUTH)
+ return(0);
+
+ if (len == -1) /* Use strlen() for len */
+ len = strlen((char *)cd);
+
+ /* Construct Message */
+ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
+ *p++ = AUTHTYPE_SRP;
+ *p = AUTH_CLIENT_TO_SERVER;
+ *p |= auth_how;
+#ifdef CK_ENCRYPTION
+ *p |= auth_crypt;
+#endif
+ p++;
+ *p++ = type;
+ while (len-- > 0) {
+ if ((*p++ = *cd++) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ /* Handle Telnet Debugging Messages */
+ if (deblog || tn_deb || debses) {
+ int i;
+ int deblen=p-str_data-2;
+ char *s=NULL;
+ int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) |
+ auth_crypt;
+
+ switch (type) {
+ case 0:
+ s = "AUTH";
+ break;
+ case 1:
+ s = "REJECT";
+ break;
+ case 2:
+ s = "ACCEPT";
+ break;
+ case 3:
+ s = "CHALLENGE";
+ break;
+ case 4:
+ s = "RESPONSE";
+ break;
+ case 5:
+ s = "FORWARD";
+ break;
+ case 6:
+ s = "FORWARD_ACCEPT";
+ break;
+ case 7:
+ s = "FORWARD_REJECT";
+ break;
+ case 8:
+ s = "EXP";
+ break;
+ case 9:
+ s = "PARAMS";
+ break;
+ }
+
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",
+ TELOPT(TELOPT_AUTHENTICATION)," ",
+ str_data[3] == TELQUAL_REPLY ? "REPLY" :
+ str_data[3] == TELQUAL_IS ? "IS" : "???"," ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," ",
+ s," ",NULL);
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Send data */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ rc = ttol((CHAR *)str_data, p - str_data);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ return(rc);
+}
+
+#ifdef CK_ENCRYPTION
+/*
+ * Function: Enable or disable the encryption process.
+ *
+ * Parameters:
+ * enable - TRUE to enable, FALSE to disable.
+ */
+static VOID
+#ifdef CK_ANSIC
+auth_encrypt_enable(BOOL enable)
+#else
+auth_encrypt_enable(enable) BOOL enable;
+#endif
+{
+ encrypt_flag = enable;
+}
+#endif
+
+/*
+ * Function: Abort the authentication process
+ *
+ * Parameters:
+ */
+static VOID
+#ifdef CK_ANSIC
+auth_abort(char *errmsg, long r)
+#else
+auth_abort(errmsg,r) char *errmsg; long r;
+#endif
+{
+ char buf[9];
+ extern int sstelnet;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ return;
+ }
+#endif /* CK_SSL */
+ debug(F111,"auth_abort",errmsg,r);
+
+ /* Construct Telnet Debugging messages */
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
+ " IS ",AUTHTYPE_NAME(AUTHTYPE_NULL)," ",
+ AUTHTYPE_NAME(AUTHTYPE_NULL)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL
+ );
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Construct the Abort message to send to the host */
+ /* Basicly we change the authentication type to NULL */
+ sprintf(buf, "%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION,
+ sstelnet ? TELQUAL_REPLY : TELQUAL_IS, AUTHTYPE_NULL,
+ AUTHTYPE_NULL, IAC, SE); /* safe */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, 8);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+ /* If there is an error message, and error number construct */
+ /* an explanation to display to the user */
+ if (errmsg != NULL) {
+ ckstrncpy(strTmp, errmsg, AUTHTMPBL);
+ } else
+ strTmp[0] = '\0';
+
+
+ if (r != AUTH_SUCCESS) {
+ ckstrncat(strTmp, "\r\n",AUTHTMPBL);
+#ifdef KRB4
+ if ( authentication_version == AUTHTYPE_KERBEROS_V4 ) {
+ ckstrncat(strTmp, (char *)krb_get_err_text_entry(r),
+ AUTHTMPBL);
+ debug(F111,"auth_abort",(char *)krb_get_err_text_entry(r),r);
+ }
+#endif
+#ifdef KRB5
+ if ( authentication_version == AUTHTYPE_KERBEROS_V5 ) {
+ ckstrncat(strTmp, error_message(r),AUTHTMPBL);
+ debug(F111,"auth_abort",error_message(r),r);
+ }
+#endif
+ }
+ printf("Authentication failed: %s\r\n",strTmp);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ cksyslog(SYSLG_LI, 0, "Telnet authentication failure",
+ (char *) szUserNameRequested,
+ strTmp);
+ }
+#endif /* CKSYSLOG */
+ authentication_version = AUTHTYPE_NULL;
+}
+
+
+/*
+ * Function: Copy data to buffer, doubling IAC character if present.
+ *
+ */
+int
+#ifdef CK_ANSIC
+copy_for_net(unsigned char *to, unsigned char *from, int c)
+#else
+copy_for_net(to,from,c) unsigned char *to; unsigned char *from; int c;
+#endif
+{
+ int n;
+
+ n = c;
+ debug(F111,"copy_for_net","before",n);
+ while (c-- > 0) {
+ if ((*to++ = *from++) == IAC) {
+ n++;
+ *to++ = IAC;
+ }
+ }
+ debug(F111,"copy_for_net","after",n);
+ return n;
+}
+
+#ifdef CK_SSL
+/* S E N D S S L A U T H S B
+ * Send a SSL Authentication Subnegotiation to host and
+ * output appropriate Telnet Debug messages
+ *
+ * type - Sub Negotiation type
+ * data - ptr to buffer containing data
+ * len - len of buffer if not NUL terminated
+ *
+ * returns number of characters sent or error value
+ */
+
+int
+#ifdef CK_ANSIC
+SendSSLAuthSB(int type, void *data, int len)
+#else
+SendSSLAuthSB(type,data,len) int type; void *data; int len;
+#endif
+{
+ int rc;
+ unsigned char *p = str_data + 3;
+ unsigned char *cd = (unsigned char *)data;
+ extern int sstelnet;
+
+ /* Check for invalid values */
+ if ( type != SSL_START && type != SSL_ACCEPT &&
+ type != SSL_REJECT)
+ return(0);
+
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
+ if (ttchk() < 0)
+ return(0);
+ else
+ return(1);
+ }
+
+ if (len == -1) /* Use strlen() for len */
+ len = strlen((char *)cd);
+
+ /* Construct Message */
+ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS;
+ *p++ = AUTHTYPE_SSL;
+ *p = AUTH_CLIENT_TO_SERVER;
+ *p |= auth_how;
+#ifdef CK_ENCRYPTION
+ *p |= auth_crypt;
+#endif
+ p++;
+ *p++ = type;
+ while (len-- > 0) {
+ if ((*p++ = *cd++) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+
+ /* Handle Telnet Debugging Messages */
+ if (deblog || tn_deb || debses) {
+ int i;
+ int deblen=p-str_data-2;
+ char *s=NULL;
+ int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) |
+ (auth_crypt?AUTH_ENCRYPT_USING_TELOPT:AUTH_ENCRYPT_OFF);
+
+ switch (type) {
+ case SSL_START:
+ s = "START";
+ break;
+ case SSL_ACCEPT:
+ s = "ACCEPT";
+ break;
+ case SSL_REJECT:
+ s = "REJECT";
+ break;
+ }
+
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",
+ TELOPT(TELOPT_AUTHENTICATION)," ",
+ str_data[3] == TELQUAL_REPLY ? "REPLY" :
+ str_data[3] == TELQUAL_IS ? "IS" : "???"," ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," ",
+ s," ",NULL);
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Send data */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ rc = ttol((CHAR *)str_data, p - str_data);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ return(rc);
+}
+#endif /* CK_SSL */
+
+int
+tn_how_ok(int how)
+{
+ switch ( tn_auth_how ) {
+ case TN_AUTH_HOW_ANY:
+ return(1);
+ case TN_AUTH_HOW_ONE_WAY:
+ return((how & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY);
+ case TN_AUTH_HOW_MUTUAL:
+ return((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL);
+ default:
+ return(0);
+ }
+}
+
+int
+tn_enc_ok(int enc)
+{
+ switch ( tn_auth_enc ) {
+ case TN_AUTH_ENC_ANY:
+ if ((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS &&
+ (!ck_ssleay_is_installed()
+#ifdef CK_SSL
+ || !ssl_finished_messages ||
+ !(tls_active_flag || ssl_active_flag)
+#endif /* CK_SSL */
+ )) {
+#ifdef CK_SSL
+ if (!ssl_finished_messages)
+ debug(F100,"tn_enc_ok !ssl_finished_messages","",0);
+#endif /* CK_SSL */
+ return(0);
+ }
+ return(1);
+ case TN_AUTH_ENC_NONE:
+ return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_OFF);
+ case TN_AUTH_ENC_TELOPT:
+ return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT);
+ case TN_AUTH_ENC_EXCH:
+ return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE);
+ case TN_AUTH_ENC_TLS:
+ return(((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) &&
+ ck_ssleay_is_installed()
+#ifdef CK_SSL
+ && ssl_finished_messages &&
+ (tls_active_flag || ssl_active_flag)
+#endif /* CK_SSL */
+ );
+ default:
+ return(0);
+ }
+}
+
+static int
+atok(int at) {
+ int i;
+ if ( auth_type_user[0] == AUTHTYPE_AUTO )
+ return(1);
+ if ( auth_type_user[0] == AUTHTYPE_NULL )
+ return(0);
+
+ for ( i=0;
+ i<AUTHTYPLSTSZ && auth_type_user[i] != AUTHTYPE_NULL;
+ i++ ) {
+ if ( auth_type_user[i] == at )
+ return(1);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Function: Parse authentication send command
+ *
+ * Parameters:
+ * parsedat - the sub-command data.
+ *
+ * end_sub - index of the character in the 'parsedat' array which
+ * is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+
+static unsigned char send_list[512];
+static int send_len = 0;
+
+_PROTOTYP(static int auth_send, (unsigned char *parsedat, int end_sub));
+
+static int
+#ifdef CK_ANSIC
+auth_resend(int type)
+#else
+auth_resend(type) int type;
+#endif /* CK_ANSIC */
+{
+ int i=2;
+ while (i+1 <= send_len) {
+ if (send_list[i] == type) {
+ int j;
+ send_len -= 2;
+ for (j = i; j < send_len; j++)
+ send_list[j] = send_list[j+2];
+ } else {
+ i += 2;
+ }
+ }
+ return(auth_send(send_list,send_len));
+}
+
+static int
+#ifdef CK_ANSIC
+auth_send(unsigned char *parsedat, int end_sub)
+#else
+auth_send(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+ static unsigned char buf[4096];
+ unsigned char *pname;
+ int plen;
+ int r;
+ int i;
+ int mode;
+#ifdef MIT_CURRENT
+#ifdef CK_ENCRYPTION
+ krb5_data data;
+ krb5_enc_data encdata;
+ krb5_error_code code;
+ krb5_keyblock random_key;
+#endif /* ENCRYPTION */
+#endif /* MIT_CURRENT */
+#ifdef KRB5
+ int krb5_msg = 0;
+#endif /* KRB5 */
+#ifdef KRB4
+ int krb4_msg = 0;
+#endif /* KRB4 */
+#ifdef GSSAPI_KRB5
+ int gssk5_msg = 0;
+#endif /* GSSAPI_KRB5 */
+ int iaccnt=0;
+
+#ifdef CK_SSL
+ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+ return(AUTH_SUCCESS);
+#endif /* CK_SSL */
+
+ auth_how = -1; /* We have not found an auth method */
+ auth_crypt = 0; /* We are not using encryption (yet) */
+ send_len = end_sub > 512 ? 512 : end_sub;
+ memcpy(send_list,parsedat,send_len);
+
+ /* Search the list of acceptable Authentication types sent from */
+ /* the host and find one that we support */
+
+ /* For Kerberos authentications, try to determine if we have a */
+ /* valid TGT, if not skip over the authentication type because */
+ /* we wouldn't be able to successfully login anyway. Perhaps */
+ /* there is another supported authentication which we could use */
+
+#ifdef NO_FTP_AUTH
+ /* If the userid is "ftp" or "anonymous" refuse to perform AUTH */
+ /* for Kerberos or SRP. */
+#endif /* NO_FTP_AUTH */
+
+ if ( auth_type_user[0] == AUTHTYPE_AUTO ) {
+ for (i = 2; i+1 <= end_sub; i += 2) {
+#ifdef NTLM
+ if (parsedat[i] == AUTHTYPE_NTLM &&
+ ck_ntlm_is_valid(1) &&
+ ntlm_auth_send() == 0) {
+ if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef CK_ENCRYPTION
+ /* NTLM does not support Telnet Encryption */
+ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#endif /* CK_ENCRYPTION */
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ authentication_version = AUTHTYPE_NTLM;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* NTLM */
+#ifdef CK_SSL
+ if ( parsedat[i] == AUTHTYPE_SSL && ssl_initialized &&
+#ifdef SSLDLL
+ ck_ssleay_is_installed() &&
+#endif /* SSLDLL */
+ !tls_active_flag && !ssl_active_flag
+#ifndef USE_CERT_CB
+ && tls_load_certs(ssl_ctx,ssl_con,0)
+#endif /* USE_CERT_CB */
+ ) {
+
+ if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef CK_ENCRYPTION
+ /* SSL does not support Telnet Encryption */
+ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#endif /* CK_ENCRYPTION */
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ authentication_version = AUTHTYPE_SSL;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* SSL */
+#ifdef CK_SRP
+ if ( parsedat[i] == AUTHTYPE_SRP
+#ifdef SRPDLL
+ && hSRP
+#endif /* SRPDLL */
+#ifdef NO_FTP_AUTH
+ && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName)
+#endif /* NO_FTP_AUTH */
+ ) {
+ if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef PRE_SRP_1_4_5
+ if (parsedat[i+1] & AUTH_ENCRYPT_MASK)
+ /* Do not support ENCRYPT_USING_TELOPT yet. */
+ continue;
+#endif /* PRE_SRP_1_4_5 */
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_USING_TELOPT) &&
+ (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
+ continue;
+
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#ifdef CK_ENCRYPTION
+ if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
+ ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_SSL */
+ authentication_version = AUTHTYPE_SRP;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* SRP */
+#ifdef GSSAPI_KRB5
+ if (parsedat[i] == AUTHTYPE_GSSAPI_KRB5 &&
+ (parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_AFTER_EXCHANGE &&
+#ifdef OS2
+ hGSSAPI &&
+#endif /* OS2 */
+#ifdef NO_FTP_AUTH
+ strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
+#endif /* NO_FTP_AUTH */
+ ck_gssapi_is_installed() && !gssk5_msg)
+ {
+ if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
+ parsedat[i+1] & AUTH_ENCRYPT_MASK,
+ parsedat[i+1] & INI_CRED_FWD_MASK) )
+ {
+ /* If we are auto-getting TGTs, try */
+ if ( !ck_krb5_is_tgt_valid() ) {
+ printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n");
+ }
+ gssk5_msg = 1;
+ }
+ else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
+ AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#ifdef CK_ENCRYPTION
+ if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_ENCRYPTION */
+ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK;
+ authentication_version = AUTHTYPE_GSSAPI_KRB5;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* GSSAPI_KRB5 */
+#ifdef KRB5
+ if (parsedat[i] == AUTHTYPE_KERBEROS_V5 &&
+#ifdef OS2
+ hKRB5_32 &&
+#endif /* OS2 */
+#ifdef NO_FTP_AUTH
+ strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
+#endif /* NO_FTP_AUTH */
+ ck_krb5_is_installed() && !krb5_msg) {
+
+ /* Without encryption we can't perform mutual authentication */
+ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
+ !ck_crypt_is_installed())
+ continue;
+
+ /* Skip over entries that request credential forwarding */
+ /* if we are not forwarding. */
+ if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) ||
+ (forward_flag &&
+ ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY)))
+ continue;
+
+ if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
+ parsedat[i+1] & AUTH_ENCRYPT_MASK,
+ parsedat[i+1] & INI_CRED_FWD_MASK) )
+ {
+ /* If we are auto-getting TGTs, try */
+ if ( !ck_krb5_is_tgt_valid() ) {
+ printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n");
+ }
+ krb5_msg = 1;
+ }
+ else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
+ AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_USING_TELOPT) &&
+ (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
+ continue;
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_START_TLS) &&
+ (!ck_ssleay_is_installed()
+#ifdef CK_SSL
+ || !(tls_active_flag || ssl_active_flag)
+#endif /* CK_SSL */
+ ))
+ continue;
+
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#ifdef CK_ENCRYPTION
+ if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
+ ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_SSL */
+ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK;
+ authentication_version = AUTHTYPE_KERBEROS_V5;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ if ( auth_how == AUTH_HOW_ONE_WAY ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+ break;
+ }
+ }
+#endif /* KRB5 */
+#ifdef KRB4
+ if (parsedat[i] == AUTHTYPE_KERBEROS_V4 &&
+#ifdef OS2
+ hKRB4_32 &&
+#endif /* OS2 */
+#ifdef NO_FTP_AUTH
+ strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
+#endif /* NO_FTP_AUTH */
+ ck_krb4_is_installed() && !krb4_msg) {
+ int rc = 0;
+
+ /* Without encryption we can't perform mutual authentication */
+ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
+ !ck_crypt_is_installed() )
+ continue;
+
+ if ( !k4_auth_send() )
+ {
+ /* If we are auto-getting TGTs, try */
+ if ( !ck_krb4_is_tgt_valid() ) {
+ printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n");
+ }
+ krb4_msg = 1;
+ }
+ else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
+ AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef CK_ENCRYPTION
+ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) &&
+ (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+ if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+#endif /* CK_ENCRYPTION */
+ authentication_version = AUTHTYPE_KERBEROS_V4;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ if ( auth_how == AUTH_HOW_ONE_WAY ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+ break;
+ }
+ }
+#endif /* KRB4 */
+ }
+ } else {
+ for (i = 2; i+1 <= end_sub; i += 2) {
+#ifdef CK_SSL
+ if ( atok(AUTHTYPE_SSL) && parsedat[i] == AUTHTYPE_SSL &&
+#ifdef SSLDLL
+ ck_ssleay_is_installed() &&
+#endif /* SSLDLL */
+ !tls_active_flag && !ssl_active_flag && ssl_initialized
+#ifndef USE_CERT_CB
+ && tls_load_certs(ssl_ctx,ssl_con,0)
+#endif /* USE_CERT_CB */
+ )
+ {
+ if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef CK_ENCRYPTION
+ /* SSL does not support Telnet Encryption */
+ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#endif /* CK_ENCRYPTION */
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ authentication_version = AUTHTYPE_SSL;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* SSL */
+#ifdef CK_SRP
+ if ( atok(AUTHTYPE_SRP) &&
+ parsedat[i] == AUTHTYPE_SRP
+#ifdef SRPDLL
+ && hSRP
+#endif /* SRPDLL */
+#ifdef NO_FTP_AUTH
+ && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName)
+#endif /* NO_FTP_AUTH */
+ ) {
+ if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef PRE_SRP_1_4_5
+ if (parsedat[i+1] & AUTH_ENCRYPT_MASK)
+ /* Do not support ENCRYPT_USING_TELOPT yet. */
+ continue;
+#endif /* PRE_SRP_1_4_5 */
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_USING_TELOPT) &&
+ (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
+ continue;
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_START_TLS) &&
+ (!ck_ssleay_is_installed()
+#ifdef CK_SSL
+ || !(tls_active_flag || ssl_active_flag)
+#endif /* CK_SSL */
+ ))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#ifdef CK_ENCRYPTION
+ if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
+ ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_SSL */
+ authentication_version = AUTHTYPE_SRP;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* SRP */
+#ifdef GSSAPI_KRB5
+ if (atok(AUTHTYPE_GSSAPI_KRB5) &&
+ parsedat[i] == AUTHTYPE_GSSAPI_KRB5 &&
+ (parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_AFTER_EXCHANGE &&
+#ifdef OS2
+ hGSSAPI &&
+#endif /* OS2 */
+#ifdef NO_FTP_AUTH
+ strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
+#endif /* NO_FTP_AUTH */
+ ck_gssapi_is_installed() && !gssk5_msg)
+ {
+ if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
+ parsedat[i+1] & AUTH_ENCRYPT_MASK,
+ parsedat[i+1] & INI_CRED_FWD_MASK) )
+ {
+ /* If we are auto-getting TGTs, try */
+ if ( !ck_krb5_is_tgt_valid() ) {
+ printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n");
+ }
+ gssk5_msg = 1;
+ }
+ else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
+ AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#ifdef CK_ENCRYPTION
+ if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_ENCRYPTION */
+ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK;
+ authentication_version = AUTHTYPE_GSSAPI_KRB5;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* GSSAPI_KRB5 */
+#ifdef KRB5
+ if ( atok(AUTHTYPE_KERBEROS_V5) &&
+ parsedat[i] == AUTHTYPE_KERBEROS_V5 &&
+#ifdef OS2
+ hKRB5_32 &&
+#endif /* OS2 */
+#ifdef NO_FTP_AUTH
+ strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
+#endif /* NO_FTP_AUTH */
+ ck_krb5_is_installed() && !krb5_msg) {
+
+ /* Without encryption we can't perform mutual authentication */
+ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
+ !ck_crypt_is_installed())
+ continue;
+
+ /* Skip over entries that request credential forwarding */
+ /* if we are not forwarding. */
+ if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) ||
+ (forward_flag &&
+ ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY)))
+ continue;
+
+ if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK,
+ parsedat[i+1] & AUTH_ENCRYPT_MASK,
+ parsedat[i+1] & INI_CRED_FWD_MASK) )
+ {
+ /* If we are auto-getting TGTs, try */
+ if ( !ck_krb5_is_tgt_valid() ) {
+ printf(
+ "Kerberos 5: Ticket Getting Ticket not valid.\r\n");
+ }
+ krb5_msg = 1;
+ }
+ else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
+ AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1]))
+ {
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_USING_TELOPT) &&
+ (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
+ continue;
+ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) ==
+ AUTH_ENCRYPT_START_TLS) &&
+ (!ck_ssleay_is_installed()
+#ifdef CK_SSL
+ || !(tls_active_flag || ssl_active_flag)
+#endif /* CK_SSL */
+ ))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#ifdef CK_ENCRYPTION
+ if (auth_crypt) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if ( auth_crypt == AUTH_ENCRYPT_START_TLS &&
+ ck_ssleay_is_installed() &&
+ (tls_active_flag || ssl_active_flag) ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_SSL */
+ authentication_version = AUTHTYPE_KERBEROS_V5;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ if ( auth_how == AUTH_HOW_ONE_WAY ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+ break;
+ }
+ }
+#endif /* KRB5 */
+#ifdef KRB4
+ if ( atok(AUTHTYPE_KERBEROS_V4) &&
+ parsedat[i] == AUTHTYPE_KERBEROS_V4 &&
+#ifdef OS2
+ hKRB4_32 &&
+#endif /* OS2 */
+#ifdef NO_FTP_AUTH
+ strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) &&
+#endif /* NO_FTP_AUTH */
+ ck_krb4_is_installed() && !krb4_msg) {
+ int rc = 0;
+
+ /* Without encryption we can't perform mutual authentication */
+ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
+ !ck_crypt_is_installed())
+ continue;
+
+ if ( !k4_auth_send() )
+ {
+ /* If we are auto-getting TGTs, try */
+ if ( !ck_krb4_is_tgt_valid() ) {
+ printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n");
+ }
+ krb4_msg = 1;
+ }
+ else if ((parsedat[i+1] & AUTH_WHO_MASK) ==
+ AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1]))
+ {
+#ifdef CK_ENCRYPTION
+ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) &&
+ (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF ||
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+ if (auth_crypt) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+#endif /* CK_ENCRYPTION */
+ authentication_version = AUTHTYPE_KERBEROS_V4;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ if ( auth_how == AUTH_HOW_ONE_WAY ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+ break;
+ }
+ }
+#endif /* KRB4 */
+#ifdef NTLM
+ if ( atok(AUTHTYPE_NTLM) &&
+ parsedat[i] == AUTHTYPE_NTLM &&
+ ck_ntlm_is_valid(1) &&
+ ntlm_auth_send() == 0) {
+ if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER &&
+ tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) {
+#ifdef CK_ENCRYPTION
+ /* NTLM does not support Telnet Encryption */
+ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK))
+ continue;
+ auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK;
+#endif /* CK_ENCRYPTION */
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ authentication_version = AUTHTYPE_NTLM;
+ auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+ break;
+ }
+ }
+#endif /* NTLM */
+ }
+ }
+
+ if (auth_how == -1) { /* Did we find one? */
+ switch ( auth_type_user[0] ) { /* If not, abort the negotiation */
+ case AUTHTYPE_NULL:
+ auth_abort("User refused to accept any authentication method",0);
+ break;
+ case AUTHTYPE_AUTO:
+ auth_abort("No authentication method available", 0);
+ break;
+ default: {
+ char msg[80];
+ ckmakmsg(msg,80,AUTHTYPE_NAME(auth_type_user[0]),
+ " could not be negotiated",NULL,NULL
+ );
+ auth_abort(msg, 0);
+ }
+ }
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ printf("Authenticating with %s\r\n",
+ AUTHTYPE_NAME(authentication_version));
+
+ /* Send Telnet Auth Name message (if necessary) */
+ switch ( authentication_version ) {
+ case AUTHTYPE_SRP:
+ case AUTHTYPE_KERBEROS_V4:
+ case AUTHTYPE_KERBEROS_V5:
+ case AUTHTYPE_GSSAPI_KRB5:
+ /* if we do not have a name to login with get one now. */
+ while ( szUserName[0] == '\0' ) {
+ extern char * tn_pr_uid;
+ int ok = uq_txt(NULL,
+ tn_pr_uid && tn_pr_uid[0] ? tn_pr_uid : "Host Userid: ",
+ 1, NULL, szUserName, 63, NULL,DEFAULT_UQ_TIMEOUT);
+ if ( !ok )
+ return AUTH_FAILURE;
+ }
+ plen = strlen(szUserName);
+ pname = (unsigned char *) szUserName;
+
+ /* Construct Telnet Debugging Message */
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
+ " NAME ",(char *)pname," IAC SE",NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+
+ /* Construct and send Authentication Name subnegotiation */
+ if ( plen < sizeof(buf) - 6 ) {
+ sprintf((char *)buf, "%c%c%c%c", IAC, SB,
+ TELOPT_AUTHENTICATION,
+ TELQUAL_NAME);
+ memcpy(&buf[4], pname, plen); /* safe */
+ sprintf((char *)&buf[plen + 4], "%c%c", IAC, SE); /* safe */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, plen+6);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ } else {
+ sprintf((char *)buf, "%c%c%c%c%c%c", IAC, SB,
+ TELOPT_AUTHENTICATION,
+ TELQUAL_NAME, IAC, SE); /* safe */
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, 6);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ }
+ }
+
+ /* Construct Authentication Mode subnegotiation message (if necessary) */
+ switch ( authentication_version ) {
+ case AUTHTYPE_SRP:
+ case AUTHTYPE_KERBEROS_V4:
+ case AUTHTYPE_KERBEROS_V5:
+ case AUTHTYPE_GSSAPI_KRB5:
+ case AUTHTYPE_NTLM:
+ mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt
+#ifdef USE_INI_CRED_FWD
+ | (((authentication_version == AUTHTYPE_KERBEROS_V5) &&
+ auth_fwd)?INI_CRED_FWD_ON:INI_CRED_FWD_OFF)
+#endif /* USE_INI_CRED_FWD */
+ ;
+ sprintf((char *)buf, "%c%c%c%c%c%c%c",
+ IAC, SB, TELOPT_AUTHENTICATION,
+ TELQUAL_IS,
+ authentication_version,
+ mode,
+ KRB_AUTH); /* safe */
+ break;
+ }
+
+ /* Send initial authentication data */
+ switch ( authentication_version ) {
+#ifdef CK_SSL
+ case AUTHTYPE_SSL:
+ SendSSLAuthSB(SSL_START,NULL,0);
+ break;
+#endif /* SSL */
+#ifdef CK_SRP
+ case AUTHTYPE_SRP:
+ sprintf(&buf[7], "%c%c", IAC, SE); /* safe */
+ if (deblog || tn_deb || debses) {
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
+ " IS ",AUTHTYPE_NAME(authentication_version),
+ " AUTH ",AUTHMODE_NAME(mode)," IAC SE",
+ NULL,NULL,NULL,NULL,NULL
+ );
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, 9);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+#endif /* SRP */
+#ifdef NTLM
+ case AUTHTYPE_NTLM: {
+ int length = 0;
+
+ for ( i=0 ; i<NTLMSecBuf[0].cbBuffer ; i++ ) {
+ if ( ((char *)NTLMSecBuf[0].pvBuffer)[i] == IAC )
+ iaccnt++;
+ }
+
+ if ( ( 2*sizeof(ULONG) + NTLMSecBuf[0].cbBuffer + iaccnt + 10) <
+ sizeof(buf) ) {
+ length = copy_for_net(&buf[7],(char *)&NTLMSecBuf[0],
+ 2*sizeof(ULONG));
+ length += copy_for_net(&buf[7+length], NTLMSecBuf[0].pvBuffer,
+ NTLMSecBuf[0].cbBuffer);
+ }
+ sprintf(&buf[7+length], "%c%c", IAC, SE);
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
+ " IS ",AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," NTLM_AUTH ",
+ NULL,NULL,NULL,NULL,NULL
+ );
+ tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],length);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, length+9);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+ }
+#endif /* NTLM */
+#ifdef KRB4
+ case AUTHTYPE_KERBEROS_V4:
+ for ( i=0 ; i<k4_auth.length ; i++ ) {
+ if ( k4_auth.dat[i] == IAC )
+ iaccnt++;
+ }
+
+ if ( k4_auth.length + iaccnt + 10 < sizeof(buf) )
+ k4_auth.length = copy_for_net(&buf[7], k4_auth.dat, k4_auth.length);
+ else
+ k4_auth.length = 0;
+ sprintf(&buf[k4_auth.length+7], "%c%c", IAC, SE);
+
+ if (deblog || tn_deb || debses) {
+ int i;
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," AUTH ",
+ NULL,NULL,NULL,NULL,NULL
+ );
+ tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],k4_auth.length);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, k4_auth.length+9);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+
+#ifndef REMOVE_FOR_EXPORT
+#ifdef CK_ENCRYPTION
+ /*
+ * If we are doing mutual authentication, get set up to send
+ * the challenge, and verify it when the response comes back.
+ */
+ if ((auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+ register int i;
+ int rc = 0;
+
+#ifdef MIT_CURRENT
+ data.data = cred.session;
+ data.length = 8; /* sizeof(cred.session) */;
+
+ if (code = krb5_c_random_seed(k5_context, &data)) {
+ com_err("libtelnet", code,
+ "while seeding random number generator");
+ return(0);
+ }
+
+ if (code = krb5_c_make_random_key(k5_context,
+ ENCTYPE_DES_CBC_RAW,
+ &random_key)) {
+ com_err("libtelnet", code,
+ "while creating random session key");
+ return(0);
+ }
+
+ /* the krb4 code uses ecb mode, but on a single block
+ with a zero ivec, ecb and cbc are the same */
+ k4_krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+ k4_krbkey.length = 8;
+ k4_krbkey.contents = cred.session;
+
+ encdata.ciphertext.data = random_key.contents;
+ encdata.ciphertext.length = random_key.length;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ data.data = k4_session_key;
+ data.length = 8;
+
+ code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
+ &encdata, &data);
+
+ krb5_free_keyblock_contents(k5_context, &random_key);
+
+ if (code) {
+ com_err("libtelnet", code, "while encrypting random key");
+ return(0);
+ }
+
+ encdata.ciphertext.data = k4_session_key;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ data.data = k4_challenge;
+ data.length = 8;
+
+ code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
+ &encdata, &data);
+#else /* MIT_CURRENT */
+ memset(k4_sched,0,sizeof(Schedule));
+ ckhexdump("auth_send",cred.session,8);
+ rc = des_key_sched(cred.session, k4_sched);
+ if ( rc == -1 ) {
+ printf("?Invalid DES key specified in credentials\r\n");
+ debug(F110,"auth_send",
+ "invalid DES Key specified in credentials",0);
+ } else if ( rc == -2 ) {
+ printf("?Weak DES key specified in credentials\r\n");
+ debug(F110,"auth_send",
+ "weak DES Key specified in credentials",0);
+ } else if ( rc != 0 ) {
+ printf("?DES Key Schedule not set by credentials\r\n");
+ debug(F110,"auth_send",
+ "DES Key Schedule not set by credentials",0);
+ }
+ ckhexdump("auth_send schedule",k4_sched,8*16);
+
+ des_set_random_generator_seed(cred.session);
+
+ do {
+ des_new_random_key(k4_session_key);
+ des_fixup_key_parity(k4_session_key);
+ } while ( ck_des_is_weak_key(k4_session_key) );
+
+ ckhexdump("auth_send des_new_random_key(k4_session_key)",
+ k4_session_key,8);
+
+ /* Decrypt the session key so that we can send it to the */
+ /* host as a challenge */
+#ifdef NT
+ des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 0);
+#else /* NT */
+ des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 0);
+#endif /* NT */
+ ckhexdump(
+ "auth_send des_ecb_encrypt(k4_session_key,k4_session_key,0)",
+ k4_session_key,8
+ );
+ /* Prepare the result of the challenge */
+ /* Decrypt the session_key, add 1, and then encrypt it */
+ /* The result stored in k4_challenge should match the */
+ /* KRB4_RESPONSE value from the host. */
+#ifdef NT
+ des_ecb_encrypt(k4_session_key, k4_challenge, k4_sched, 0);
+#else /* NT */
+ des_ecb_encrypt(&k4_session_key, &k4_challenge, k4_sched, 0);
+#endif /* NT */
+
+ ckhexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,0)",
+ k4_challenge,8);
+#endif /* MIT_CURRENT */
+ /*
+ * Increment the challenge by 1, and encrypt it for
+ * later comparison.
+ */
+ for (i = 7; i >= 0; --i) {
+ register int x;
+ x = (unsigned int)k4_challenge[i] + 1;
+ k4_challenge[i] = x; /* ignore overflow */
+ if (x < 256) /* if no overflow, all done */
+ break;
+ }
+ ckhexdump("auth_send k4_challenge+1",k4_challenge,8);
+#ifdef MIT_CURRENT
+ data.data = k4_challenge;
+ data.length = 8;
+
+ encdata.ciphertext.data = k4_challenge;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &data,
+ &encdata)) {
+ com_err("libtelnet", code, "while encrypting random key");
+ return(0);
+ }
+#else /* MIT_CURRENT */
+#ifdef NT
+ des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1);
+#else /* NT */
+ des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1);
+#endif /* NT */
+ ckhexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,1)",
+ k4_challenge,8);
+#endif /* MIT_CURRENT */
+ }
+#endif /* ENCRYPTION */
+#endif /* REMOVE_FOR_EXPORT */
+ break;
+#endif /* KRB4 */
+#ifdef GSSAPI_KRB5
+ case AUTHTYPE_GSSAPI_KRB5:
+ for ( i=0 ; i<gss_send_tok.length ; i++ ) {
+ if ( ((char *)gss_send_tok.value)[i] == IAC )
+ iaccnt++;
+ }
+
+ if ( gss_send_tok.length + iaccnt + 10 < sizeof(buf) )
+ gss_send_tok.length = copy_for_net(&buf[7], gss_send_tok.value,
+ gss_send_tok.length);
+ else
+ gss_send_tok.length = 0;
+ sprintf(&buf[gss_send_tok.length+7], "%c%c", IAC, SE); /* safe */
+ if (deblog || tn_deb || debses) {
+ int i;
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," AUTH ",
+ NULL,NULL,NULL,NULL,NULL
+ );
+ tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],gss_send_tok.length);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, gss_send_tok.length+9);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+ break;
+#endif /* GSSAPI_KRB5 */
+#ifdef KRB5
+ case AUTHTYPE_KERBEROS_V5:
+ debug(F111,"auth_send KRB5","k5_auth.length",k5_auth.length);
+ for ( i=0 ; i<k5_auth.length ; i++ ) {
+ if ( (char *)k5_auth.data[i] == IAC )
+ iaccnt++;
+ }
+ if ( k5_auth.length + iaccnt + 10 < sizeof(buf) ) {
+ k5_auth.length = copy_for_net(&buf[7],
+ (CHAR *)k5_auth.data,
+ k5_auth.length);
+ } else {
+ debug(F100,"auth_send() KRB5 auth data too large for buffer","",0);
+ k5_auth.length = 0;
+ }
+
+ sprintf((char *)&buf[k5_auth.length+7], "%c%c", IAC, SE); /* safe */
+ if (deblog || tn_deb || debses) {
+ int i;
+ ckmakxmsg(tn_msg,TN_MSG_LEN,
+ "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
+ AUTHTYPE_NAME(authentication_version)," ",
+ AUTHMODE_NAME(mode)," AUTH ",
+ NULL,NULL,NULL,NULL,NULL
+ );
+ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&buf[7],k5_auth.length);
+ ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN);
+ debug(F100,tn_msg,"",0);
+ if (tn_deb || debses) tn_debug(tn_msg);
+ }
+#ifdef OS2
+ RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+ ttol((CHAR *)buf, k5_auth.length+9);
+#ifdef OS2
+ ReleaseTelnetMutex();
+#endif
+#ifdef HEIMDAL
+ krb5_data_free(&k5_auth);
+#else /* HEIMDAL */
+ krb5_free_data_contents(k5_context,&k5_auth);
+ memset(&k5_auth,0,sizeof(krb5_data));
+#endif /* HEIMDAL */
+ break;
+#endif /* KRB5 */
+ }
+ return AUTH_SUCCESS;
+}
+
+/*
+ * Function: Parse authentication REPLY command
+ *
+ * Parameters:
+ * parsedat - the sub-command data.
+ *
+ * end_sub - index of the character in the 'parsedat' array which
+ * is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+static int
+#ifdef CK_ANSIC
+auth_reply(unsigned char *parsedat, int end_sub)
+#else
+auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+ int n = AUTH_FAILURE;
+
+ if ( parsedat[2] != authentication_version ) {
+ printf("Authentication version mismatch (%s [%d] != %s [%d])\r\n",
+ AUTHTYPE_NAME(parsedat[2]),parsedat[2],
+ AUTHTYPE_NAME(authentication_version),authentication_version);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+ if ( parsedat[3] != (auth_how|auth_crypt|auth_fwd) ) {
+ printf("Authentication mode mismatch (%s != %s)\r\n",
+ AUTHMODE_NAME(parsedat[3]),
+ AUTHMODE_NAME(auth_how|auth_crypt|auth_fwd));
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+
+#ifdef KRB4
+ if (authentication_version == AUTHTYPE_KERBEROS_V4)
+ n = k4_auth_reply(parsedat, end_sub);
+#endif
+#ifdef KRB5
+ if (authentication_version == AUTHTYPE_KERBEROS_V5)
+ n = k5_auth_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif
+#ifdef CK_SRP
+ if (authentication_version == AUTHTYPE_SRP) {
+#ifndef PRE_SRP_1_7_3
+ n = new_srp_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#else /* PRE_SRP_1_7_3 */
+ n = srp_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif /* PRE_SRP_1_7_3 */
+ }
+#endif /* SRP */
+#ifdef CK_SSL
+ if (authentication_version == AUTHTYPE_SSL)
+ n = ssl_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif /* SSL */
+#ifdef NTLM
+ if (authentication_version == AUTHTYPE_NTLM)
+ n = ntlm_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif /* NTLM */
+ return n;
+}
+
+
+/*
+ * Function: Parse authentication IS command
+ *
+ * Parameters:
+ * parsedat - the sub-command data.
+ *
+ * end_sub - index of the character in the 'parsedat' array which
+ * is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+static int
+#ifdef CK_ANSIC
+auth_is(unsigned char *parsedat, int end_sub)
+#else
+auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+ int n = AUTH_FAILURE;
+
+ if ( parsedat[2] == AUTHTYPE_NULL ) {
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+
+ /*
+ * If CLIENT_CHOOSE_ONCE is selected the server will not allow the
+ * client to switch to an alternate authentication method if the one
+ * it originally selected fails. (ie, if the host's SRP parameters
+ * are invalid.) However, I think this is a bit of a security risk
+ * since allowing that functionality means that it is impossible to
+ * detect if an attack is being carried out on
+ */
+#define CLIENT_CHOOSE_ONCE
+#ifdef CLIENT_CHOOSE_ONCE
+ if ( authentication_version == AUTHTYPE_AUTO )
+#endif /* CLIENT_CHOOSE_ONCE */
+ {
+ /* this block of code needs to check the initial parameters */
+ /* to ensure that those returned match one of the sets that */
+ /* were sent to the client in the first place. */
+
+ int i=0;
+ for ( i=4; str_request[i] != IAC ; i+=2) {
+ if (str_request[i] == parsedat[2] &&
+ str_request[i+1] == parsedat[3])
+ break;
+ }
+
+ if ( str_request[i] == IAC ) {
+ printf("Invalid authentication type pair (%s,%s)\r\n",
+ AUTHTYPE_NAME(parsedat[2]),
+ AUTHMODE_NAME(parsedat[3]));
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+
+ if (authentication_version != parsedat[2]) {
+ authentication_version = parsedat[2];
+ auth_how = (parsedat[3] & AUTH_HOW_MASK);
+ auth_crypt = (parsedat[3] & AUTH_ENCRYPT_MASK);
+ auth_fwd = (parsedat[3] & INI_CRED_FWD_MASK);
+ debug(F111,"auth_is","authentication_version",
+ authentication_version);
+ debug(F111,"auth_is","auth_how",auth_how);
+ debug(F111,"auth_is","auth_crypt",auth_crypt);
+ debug(F111,"auth_is","auth_fwd",auth_fwd);
+ }
+ }
+
+#ifdef CLIENT_CHOOSE_ONCE
+ if ( parsedat[2] != authentication_version ) {
+ printf("Authentication version mismatch (%s [%d] != %s [%d])\r\n",
+ AUTHTYPE_NAME(parsedat[2]),parsedat[2],
+ AUTHTYPE_NAME(authentication_version),authentication_version);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+ if ( parsedat[3] != (auth_how|auth_crypt|auth_fwd) ) {
+ printf("Authentication mode mismatch (%s != %s)\r\n",
+ AUTHMODE_NAME(parsedat[3]),
+ AUTHMODE_NAME(auth_how|auth_crypt|auth_fwd));
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+#endif /* CLIENT_CHOOSE_ONCE */
+
+ switch (authentication_version) {
+#ifdef KRB4
+ case AUTHTYPE_KERBEROS_V4:
+ n = k4_auth_is(parsedat, end_sub);
+ break;
+#endif
+#ifdef KRB5
+ case AUTHTYPE_KERBEROS_V5:
+ n = k5_auth_is(parsedat[3],parsedat, end_sub);
+ break;
+#endif
+#ifdef CK_SRP
+ case AUTHTYPE_SRP:
+#ifndef PRE_SRP_1_7_3
+ n = new_srp_is(parsedat[3], parsedat, end_sub);
+#else /* PRE_SRP_1_7_3 */
+ n = srp_is(parsedat[3], parsedat, end_sub);
+#endif /* PRE_SRP_1_7_3 */
+ break;
+#endif /* SRP */
+#ifdef CK_SSL
+ case AUTHTYPE_SSL:
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ n = ssl_is(parsedat, end_sub);
+ break;
+#endif /* SSL */
+#ifdef NTLM
+ case AUTHTYPE_NTLM:
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ n = ntlm_is(parsedat, end_sub);
+ break;
+#endif /* NTLM */
+ case AUTHTYPE_NULL:
+ default:
+ n = AUTH_FAILURE;
+ }
+ debug(F111,"auth_is","n",n);
+ return n;
+}
+
+/*
+ * Function: Parse authentication NAME command
+ *
+ * Parameters:
+ * parsedat - the sub-command data.
+ *
+ * end_sub - index of the character in the 'parsedat' array which
+ * is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+static int
+#ifdef CK_ANSIC
+auth_name(unsigned char *parsedat, int end_sub)
+#else
+auth_name(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+ int len = (end_sub-2) > 63 ? 63 : (end_sub-2);
+ if ( len > 0 && (len + 1) < sizeof(szUserNameRequested)) {
+ memcpy(szUserNameRequested,&parsedat[2],len); /* safe */
+ szUserNameRequested[len] = '\0';
+ } else
+ szUserNameRequested[0] = '\0';
+ debug(F111,"auth_name szUserNameRequested",szUserNameRequested,len);
+ return(AUTH_SUCCESS);
+}
+
+/*
+ * Function: Parse the athorization sub-options and reply.
+ *
+ * Parameters:
+ * parsedat - sub-option string to parse.
+ *
+ * end_sub - last charcter position in parsedat.
+ */
+int
+auth_parse(unsigned char *parsedat, int end_sub)
+{
+ int rc = AUTH_FAILURE;
+ switch (parsedat[1]) {
+ case TELQUAL_SEND:
+ rc = auth_send(parsedat, end_sub);
+ break;
+ case TELQUAL_REPLY:
+ rc= auth_reply(parsedat, end_sub);
+ break;
+ case TELQUAL_IS:
+ rc = auth_is(parsedat, end_sub);
+ break;
+ case TELQUAL_NAME:
+ rc = auth_name(parsedat, end_sub);
+ break;
+ }
+ debug(F111,"auth_parse","rc",rc);
+ return(rc);
+}
+
+
+/*
+ * Function: Initialization routine called kstream encryption system.
+ *
+ * Parameters:
+ * data - user data.
+ */
+int
+#ifdef CK_ANSIC
+auth_init(kstream ks)
+#else
+auth_init(ks) kstream_ptr ks;
+#endif
+{
+#ifdef FORWARD
+ forwarded_tickets = 0; /* were tickets forwarded? */
+#endif /* FORWARD */
+#ifdef CK_ENCRYPTION
+ encrypt_init(ks,cx_type);
+#endif
+ return 0;
+}
+
+
+/*
+ * Function: Destroy routine called kstream encryption system.
+ *
+ * Parameters:
+ * data - user data.
+ */
+VOID
+#ifdef CK_ANSIC
+auth_destroy(void)
+#else
+auth_destroy()
+#endif
+{
+}
+
+
+/*
+ * Function: Callback to encrypt a block of characters
+ *
+ * Parameters:
+ * out - return as pointer to converted buffer.
+ *
+ * in - the buffer to convert
+ *
+ * Returns: number of characters converted.
+ */
+int
+#ifdef CK_ANSIC
+auth_encrypt(struct kstream_data_block *out,
+ struct kstream_data_block *in)
+#else
+auth_encrypt(out,in)
+ struct kstream_data_block *out; struct kstream_data_block *in;
+#endif
+{
+ out->ptr = in->ptr;
+
+ out->length = in->length;
+
+ return(out->length);
+}
+
+
+/*
+ * Function: Callback to decrypt a block of characters
+ *
+ * Parameters:
+ * out - return as pointer to converted buffer.
+ *
+ * in - the buffer to convert
+ *
+ * Returns: number of characters converted.
+ */
+int
+#ifdef CK_ANSIC
+auth_decrypt(struct kstream_data_block *out,
+ struct kstream_data_block *in)
+#else
+auth_decrypt(out,in)
+ struct kstream_data_block *out; struct kstream_data_block *in;
+#endif
+{
+ out->ptr = in->ptr;
+
+ out->length = in->length;
+
+ return(out->length);
+}
+
+#ifdef KRB4
+#ifdef NT
+void
+ck_krb4_debug(int x)
+{
+ set_krb_debug(x);
+ set_krb_ap_req_debug(x);
+}
+#endif /* NT */
+int
+ck_krb4_autoget_TGT(char * realm)
+{
+ extern struct krb_op_data krb_op;
+ extern struct krb4_init_data krb4_init;
+ char passwd[PWD_SZ];
+ char prompt[256];
+ char * saverealm=NULL;
+ int rc = -1;
+ extern char * k4prprompt;
+ extern char * k4pwprompt;
+
+ ini_kerb(); /* Place defaults in above structs */
+ passwd[0] = '\0';
+
+ if ( krb4_init.principal == NULL ||
+ krb4_init.principal[0] == '\0') {
+ int ok = uq_txt(NULL,
+ k4prprompt && k4prprompt[0] ?
+ k4prprompt :
+ "Kerberos 4 Principal: ",
+ 2, NULL, passwd,PWD_SZ-1, NULL, DEFAULT_UQ_TIMEOUT);
+ if ( ok && passwd[0] )
+ makestr(&krb4_init.principal,passwd);
+ else
+ return(0);
+ }
+
+ /* Save realm in init structure so it can be restored */
+ if ( realm ) {
+ saverealm = krb4_init.realm;
+ krb4_init.realm = realm;
+ }
+
+ if ( passwd[0] || !(pwbuf[0] && pwflg) ) {
+ int ok;
+ if ( k4pwprompt && k4pwprompt[0] &&
+ (strlen(k4pwprompt) + strlen(krb4_init.principal) +
+ strlen(krb4_init.realm) - 4) < sizeof(prompt)) {
+ sprintf(prompt,k4pwprompt,krb4_init.principal,krb4_init.realm);
+ } else
+ ckmakxmsg(prompt,sizeof(prompt),
+ "Kerberos 4 Password for ",krb4_init.principal,"@",
+ krb4_init.realm,": ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if ( !ok )
+ passwd[0] = '\0';
+ } else {
+ ckstrncpy(passwd,pwbuf,sizeof(passwd));
+#ifdef OS2
+ if ( pwcrypt )
+ ck_encrypt((char *)passwd);
+#endif /* OS2 */
+ }
+
+ if ( passwd[0] ) {
+ makestr(&krb4_init.password,passwd);
+ rc = ck_krb4_initTGT(&krb_op, &krb4_init);
+ free(krb4_init.password);
+ krb4_init.password = NULL;
+ }
+
+ krb4_init.password = NULL;
+ memset(passwd,0,PWD_SZ);
+
+ /* restore realm to init structure if needed */
+ if ( saverealm )
+ krb4_init.realm = saverealm;
+ return(rc == 0);
+}
+
+char *
+ck_krb4_realmofhost(char *host)
+{
+ return (char *)krb_realmofhost(host);
+}
+
+/*
+ *
+ * K4_auth_send - gets authentication bits we need to send to KDC.
+ *
+ * Result is left in auth
+ *
+ * Returns: 0 on failure, 1 on success
+ */
+static int
+#ifdef CK_ANSIC
+k4_auth_send(void)
+#else
+k4_auth_send()
+#endif
+{
+ int r=0; /* Return value */
+ char instance[INST_SZ+1]="";
+ char *realm=NULL;
+ char tgt[4*REALM_SZ+1];
+
+ memset(instance, 0, sizeof(instance));
+
+#ifdef COMMENT
+ /* we only need to call krb_get_phost if the hostname */
+ /* is not fully qualified. But we have already done */
+ /* this in netopen() call. This will save a round of */
+ /* DNS queries. */
+ debug(F110,"k4_auth_send","krb_get_phost",0);
+ if (realm = (char *)krb_get_phost(szHostName)) {
+ ckstrncpy(instance, realm, INST_SZ);
+ }
+#else /* COMMENT */
+ {
+ char *p;
+ ckstrncpy(instance, szHostName, INST_SZ);
+ for ( p=instance; *p && *p != '.' ; p++ );
+ *p = '\0';
+ }
+#endif /* COMMENT */
+
+ debug(F110,"k4_auth_send","krb_get_realmofhost",0);
+ realm = (char *)krb_realmofhost(szHostName);
+
+ if (!realm) {
+ strcpy(strTmp, "Can't find realm for host \"");
+ ckstrncat(strTmp, szHostName,AUTHTMPBL);
+ ckstrncat(strTmp, "\"",AUTHTMPBL);
+ printf("?Kerberos 4 error: %s\r\n",strTmp);
+ krb4_errno = r;
+ makestr(&krb4_errmsg,strTmp);
+ return(0);
+ }
+
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm);
+ r = ck_krb4_tkt_isvalid(tgt);
+
+ if ( r <= 0 && krb4_autoget )
+ ck_krb4_autoget_TGT(realm);
+
+ debug(F110,"k4_auth_send","krb_mk_req",0);
+ r = krb_mk_req(&k4_auth, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
+ instance, realm, 0);
+
+ if (r == 0) {
+ debug(F110,"k4_auth_send","krb_get_cred",0);
+ r = krb_get_cred(krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
+ instance, realm, &cred);
+ if (r)
+ debug(F111,"k4_auth_send","krb_get_cred() failed",r);
+ }
+ else
+ debug(F111,"k4_auth_send","krb_mk_req() failed",r);
+
+ if (r) {
+ strcpy(strTmp, "Can't get \"");
+ ckstrncat(strTmp,
+ krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,AUTHTMPBL);
+ if (instance[0] != 0) {
+ ckstrncat(strTmp, ".",AUTHTMPBL);
+ ckstrncat(strTmp, instance,AUTHTMPBL);
+ }
+ ckstrncat(strTmp, "@",AUTHTMPBL);
+ ckstrncat(strTmp, realm,AUTHTMPBL);
+ ckstrncat(strTmp, "\" ticket\r\n ",AUTHTMPBL);
+ ckstrncat(strTmp, (char *)krb_get_err_text_entry(r),AUTHTMPBL);
+ debug(F111,"k4_auth_send",(char *)krb_get_err_text_entry(r),r);
+ printf("?Kerberos 4 error: %s\r\n",strTmp);
+ krb4_errno = r;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno));
+ return(0);
+ }
+
+#ifdef OS2
+ if ( !szUserName[0] || !stricmp(szUserName,cred.pname) ) {
+ ckstrncpy(szUserName, cred.pname, UIDBUFLEN);
+ }
+#endif /* OS2 */
+ krb4_errno = r;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno));
+ debug(F110,"k4_auth_send",krb4_errmsg,0);
+ return(1);
+}
+
+/*
+ * Function: K4 parse authentication reply command
+ *
+ * Parameters:
+ * parsedat - the sub-command data.
+ *
+ * end_sub - index of the character in the 'parsedat' array which
+ * is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+static int
+#ifdef CK_ANSIC
+k4_auth_reply(unsigned char *parsedat, int end_sub)
+#else
+k4_auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#ifdef MIT_CURRENT
+ krb5_data kdata;
+ krb5_enc_data encdata;
+ krb5_error_code code;
+#endif /* MIT_CURRENT */
+#endif
+ time_t t;
+ int x;
+ int i;
+
+ if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ if (parsedat[4] == KRB_REJECT) {
+ strTmp[0] = 0;
+
+ for (i = 5; i <= end_sub; i++) {
+ if (parsedat[i] == IAC)
+ break;
+ strTmp[i-5] = parsedat[i];
+ strTmp[i-4] = 0;
+ }
+
+ if (!strTmp[0])
+ strcpy(strTmp, "Authentication rejected by remote machine!");
+ printf("Kerberos V4 authentication failed!\r\n%s\r\n",strTmp);
+ krb4_errno = -1;
+ makestr(&krb4_errmsg,strTmp);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ if (parsedat[4] == KRB_ACCEPT) {
+ int net_len;
+ if ((parsedat[3] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) {
+ ckmakmsg(strTmp,sizeof(strTmp),"Kerberos V4 accepts you as ",
+ szUserName,NULL,NULL);
+ printf("%s\r\n",strTmp);
+ accept_complete = 1;
+ krb4_errno = 0;
+ makestr(&krb4_errmsg,strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+ }
+
+ if ((parsedat[3] & AUTH_HOW_MASK) != AUTH_HOW_MUTUAL) {
+ printf("Kerberos V4 authentication failed!\r\n");
+ ckstrncpy(strTmp,
+ "Kerberos V4 accepted you, but didn't provide mutual authentication",
+ sizeof(strTmp));
+ printf("%s\r\n",strTmp);
+ krb4_errno = -1;
+ makestr(&krb4_errmsg,strTmp);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+#ifndef REMOVE_FOR_EXPORT
+#ifdef CK_ENCRYPTION
+ SendK4AuthSB(KRB4_CHALLENGE,k4_session_key,sizeof(k4_session_key));
+
+ /* We have sent the decrypted session key to the host as a challenge */
+ /* now encrypt it to restore it to its original valid DES key value */
+#ifdef MIT_CURRENT
+ kdata.data = k4_session_key;
+ kdata.length = 8;
+
+ encdata.ciphertext.data = k4_session_key;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(k5_context, &k4_krbkey,
+ 0, 0, &kdata, &encdata)) {
+ com_err("k4_auth_reply", code,
+ "while encrypting session_key");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+#else /* MIT_CURRENT */
+#ifdef NT
+ des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 1);
+#else /* NT */
+ des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 1);
+#endif /* NT */
+ ckhexdump(
+ "k4_auth_reply des_ecb_encrypt(k4_session_key,k4_session_key,1)",
+ k4_session_key,
+ 8
+ );
+#endif /* MIT_CURRENT */
+
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ {
+ /* And then use it to configure the encryption state machine. */
+ skey.type = SK_DES;
+ skey.length = 8;
+ skey.data = k4_session_key;
+ encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
+ }
+#endif /* ENCRYPTION */
+#endif /* REMOVE_FOR_EXPORT */
+ accept_complete = 1;
+ ckmakmsg(strTmp,sizeof(strTmp),
+ "Kerberos V4 accepts you as ",szUserName,NULL,NULL);
+ printf("%s\r\n",strTmp);
+ krb4_errno = 0;
+ makestr(&krb4_errmsg,strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+ }
+
+ if (parsedat[4] == KRB4_RESPONSE) {
+ if (end_sub < 12) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ ckhexdump("KRB4_RESPONSE &parsedat[5]",&parsedat[5],8);
+#ifdef CK_ENCRYPTION
+ ckhexdump("KRB4_RESPONSE k4_challenge",k4_challenge,8);
+
+ /* The datablock returned from the host should match the value */
+ /* we stored in k4_challenge. */
+ if (memcmp(&parsedat[5], k4_challenge, sizeof(k4_challenge)) != 0) {
+ printf("Kerberos V4 authentication failed!\r\n%s\r\n",
+ "Remote machine is being impersonated!");
+ krb4_errno = -1;
+ makestr(&krb4_errmsg,"Remote machine is being impersonated!");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+#else /* ENCRYPTION */
+ makestr(&krb4_errmsg,"Kermit built without support for encryption.");
+ return AUTH_FAILURE;
+#endif /* ENCRYPTION */
+ mutual_complete = 1;
+ ckstrncpy(strTmp,"Remote machine has been mutually authenticated",
+ sizeof(strTmp));
+ printf("%s\r\n",strTmp);
+ krb4_errno = 0;
+ makestr(&krb4_errmsg,strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+ }
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+}
+
+/*
+ * Function: K4 parse authentication IS command
+ *
+ * Parameters:
+ * parsedat - the sub-command data.
+ *
+ * end_sub - index of the character in the 'parsedat' array which
+ * is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+
+static int
+#ifdef CK_ANSIC
+k4_auth_is(unsigned char *parsedat, int end_sub)
+#else
+k4_auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#ifdef MIT_CURRENT
+ Block datablock, tmpkey;
+ krb5_data kdata;
+ krb5_enc_data encdata;
+ krb5_error_code code;
+#else /* MIT_CURRENT */
+ Block datablock;
+#endif /* MIT_CURRENT */
+#endif /* ENCRYPTION */
+ char realm[REALM_SZ+1];
+ char instance[INST_SZ];
+ int r = 0;
+ char * data = &parsedat[5];
+ int cnt = end_sub - 5;
+ extern char myipaddr[];
+ struct hostent *host;
+ struct in_addr inaddr;
+ int i;
+
+ if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) {
+ debug(F110,"k4_auth_is","Not kerberos v4",0);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ switch (parsedat[4]) {
+ case KRB_AUTH:
+ debug(F110,"k4_auth_is","KRB_AUTH",0);
+ ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ+1);
+ if (realm[0] == '\0') {
+ SendK4AuthSB(KRB_REJECT, (void *)"No local V4 Realm.", -1);
+ printf("\r\n? Kerberos 4 - No Local Realm\r\n");
+ debug(F110,"k4_auth_is","No local realm",0);
+ krb4_errno = -1;
+ makestr(&krb4_errmsg,"No local realm");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ debug(F110,"k4_auth_is",realm,0);
+ if ( cnt < sizeof(k4_auth.dat) ) {
+ k4_auth.length = cnt;
+ memcpy((void *)k4_auth.dat, (void *)data, k4_auth.length);
+ } else
+ k4_auth.length = 0;
+ ckhexdump("k4_auth.dat",k4_auth.dat, k4_auth.length);
+
+ /* Get Instance */
+ inaddr.s_addr = inet_addr(myipaddr);
+ host = gethostbyaddr((unsigned char *)&inaddr,4,PF_INET);
+ if ( host ) {
+#ifdef HADDRLIST
+ host = ck_copyhostent(host);
+#endif /* HADDRLIST */
+ ckstrncpy(instance,host->h_name,INST_SZ);
+ for ( i=0;i<INST_SZ;i++ ) {
+ if ( instance[i] == '.' )
+ instance[i] = '\0';
+ else
+ instance[i] = tolower(instance[i]);
+ }
+ } else {
+ instance[0] = '*';
+ instance[1] = 0;
+ }
+
+ if (r = krb_rd_req(&k4_auth,
+ krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
+ instance, 0, &k4_adat, k4_keytab)) {
+
+ ckhexdump("k4_adat", &k4_adat, sizeof(AUTH_DAT));
+ krb_kntoln(&k4_adat, k4_name);
+ ckmakmsg(strTmp,sizeof(strTmp),
+ "Kerberos failed him as ", k4_name,NULL,NULL);
+ printf("%s\r\n",strTmp);
+ krb4_errno = r;
+ makestr(&krb4_errmsg,strTmp);
+ SendK4AuthSB(KRB_REJECT, (void *)krb_get_err_text_entry(r), -1);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+#ifdef CK_ENCRYPTION
+ memcpy((void *)k4_session_key, (void *)k4_adat.session,
+ sizeof(Block)); /* safe */
+ ckhexdump("k4_auth_is k4_session_key",k4_session_key,sizeof(Block));
+#endif /* ENCRYPTION */
+ krb_kntoln(&k4_adat, k4_name);
+
+ ckstrncpy(szUserNameAuthenticated,k4_name,UIDBUFLEN);
+ if (szUserNameRequested && !kuserok(&k4_adat, k4_name)) {
+ SendK4AuthSB(KRB_ACCEPT, (void *)0, 0);
+ if ( !strcmp(k4_name,szUserNameRequested) )
+ auth_finished(AUTH_VALID);
+ else
+ auth_finished(AUTH_USER);
+ accept_complete = 1;
+ }
+ else {
+ SendK4AuthSB(KRB_REJECT,
+ (void *)"user is not authorized", -1);
+ auth_finished(AUTH_REJECT);
+ krb4_errno = r;
+ makestr(&krb4_errmsg,"user is not authorized");
+ return(AUTH_FAILURE);
+ }
+ break;
+
+ case KRB4_CHALLENGE:
+ debug(F110,"k4_auth_is","KRB_CHALLENGE",0);
+#ifndef CK_ENCRYPTION
+ SendK4AuthSB(KRB4_RESPONSE, (void *)0, 0);
+#else /* ENCRYPTION */
+ if (!VALIDKEY(k4_session_key)) {
+ /*
+ * We don't have a valid session key, so just
+ * send back a response with an empty session
+ * key.
+ */
+ SendK4AuthSB(KRB4_RESPONSE, (void *)0, 0);
+ mutual_complete = 1;
+ break;
+ }
+
+ /*
+ * Initialize the random number generator since it's
+ * used later on by the encryption routine.
+ */
+#ifdef MIT_CURRENT
+ kdata.data = k4_session_key;
+ kdata.length = 8;
+
+ if (code = krb5_c_random_seed(k5_context, &kdata)) {
+ com_err("k4_auth_is", code,
+ "while seeding random number generator");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ memcpy((void *)datablock, (void *)data, sizeof(Block)); /* safe */
+ /*
+ * Take the received encrypted challenge, and encrypt
+ * it again to get a unique session_key for the
+ * ENCRYPT option.
+ */
+ k4_krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+ k4_krbkey.length = 8;
+ k4_krbkey.contents = k4_session_key;
+
+ kdata.data = datablock;
+ kdata.length = 8;
+
+ encdata.ciphertext.data = tmpkey;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0,
+ &kdata, &encdata)) {
+ com_err("k4_auth_is", code, "while encrypting random key");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ {
+ skey.type = SK_DES;
+ skey.length = 8;
+ skey.data = tmpkey;
+ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+ }
+ /*
+ * Now decrypt the received encrypted challenge,
+ * increment by one, re-encrypt it and send it back.
+ */
+ encdata.ciphertext.data = datablock;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ kdata.data = k4_challenge;
+ kdata.length = 8;
+
+ if (code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
+ &encdata, &kdata)) {
+ com_err("k4_auth_is", code, "while decrypting challenge");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+#else /* MIT_CURRENT */
+ des_set_random_generator_seed(k4_session_key);
+ r = des_key_sched(k4_session_key, k4_sched);
+ if ( r == -1 ) {
+ printf("?Invalid DES key specified in credentials\r\n");
+ debug(F110,"auth_is CHALLENGE",
+ "invalid DES Key specified in credentials",0);
+ } else if ( r == -2 ) {
+ printf("?Weak DES key specified in credentials\r\n");
+ debug(F110,"auth_is CHALLENGE",
+ "weak DES Key specified in credentials",0);
+ } else if ( r != 0 ) {
+ printf("?DES Key Schedule not set by credentials\r\n");
+ debug(F110,"auth_is CHALLENGE",
+ "DES Key Schedule not set by credentials",0);
+ }
+ ckhexdump("auth_is schedule",k4_sched,8*16);
+
+ memcpy((void *)datablock, (void *)data, sizeof(Block)); /* safe */
+ ckhexdump("auth_is challege",datablock,sizeof(Block));
+
+ /*
+ * Take the received encrypted challenge, and encrypt
+ * it again to get a unique k4_session_key for the
+ * ENCRYPT option.
+ */
+#ifdef NT
+ des_ecb_encrypt(datablock, k4_session_key, k4_sched, 1);
+#else /* NT */
+ des_ecb_encrypt(&datablock, &k4_session_key, k4_sched, 1);
+#endif /* NT */
+ ckhexdump("auth_is des_ecb_encrypt(datablock,k4_session_key,1)",
+ k4_session_key,8);
+
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ {
+ skey.type = SK_DES;
+ skey.length = 8;
+ skey.data = k4_session_key;
+ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+ }
+ /*
+ * Now decrypt the received encrypted challenge,
+ * increment by one, re-encrypt it and send it back.
+ */
+#ifdef NT
+ des_ecb_encrypt(datablock, k4_challenge, k4_sched, 0);
+#else /* NT */
+ des_ecb_encrypt(&datablock, &k4_challenge, k4_sched, 0);
+#endif /* NT */
+ ckhexdump("auth_is des_ecb_encrypt(datablock,k4_challenge,0)",
+ k4_session_key,8);
+#endif /* MIT_CURRENT */
+ for (r = 7; r >= 0; r--) {
+ register int t;
+ t = (unsigned int)k4_challenge[r] + 1;
+ k4_challenge[r] = t; /* ignore overflow */
+ if (t < 256) /* if no overflow, all done */
+ break;
+ }
+ ckhexdump("auth_is k4_challenge+1",k4_challenge,8);
+
+#ifdef MIT_CURRENT
+ kdata.data = k4_challenge;
+ kdata.length = 8;
+
+ encdata.ciphertext.data = k4_challenge;
+ encdata.ciphertext.length = 8;
+ encdata.enctype = ENCTYPE_UNKNOWN;
+
+ if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0,
+ &kdata, &encdata)) {
+ com_err("k4_auth_is", code, "while decrypting challenge");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+#else /* MIT_CURRENT */
+#ifdef NT
+ des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1);
+#else /* NT */
+ des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1);
+#endif /* NT */
+ ckhexdump("auth_is des_ecb_encrypt(k4_challenge_key,k4_challenge,1)",
+ k4_challenge,8);
+
+#endif /* MIT_CURRENT */
+ SendK4AuthSB(KRB4_RESPONSE,(void *)k4_challenge,sizeof(k4_challenge));
+#endif /* ENCRYPTION */
+ mutual_complete = 1;
+ break;
+
+ default:
+ if (1)
+ printf("Unknown Kerberos option %d\r\n", data[-1]);
+ SendK4AuthSB(KRB_REJECT, 0, 0);
+ return(AUTH_FAILURE);
+ }
+ krb4_errno = r;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno));
+ return(AUTH_SUCCESS);
+}
+#endif /* KRB4 */
+
+#ifdef KRB5
+int
+ck_krb5_autoget_TGT(char * realm)
+{
+ extern struct krb_op_data krb_op;
+ extern struct krb5_init_data krb5_init;
+ char passwd[PWD_SZ];
+ char prompt[64];
+ char * saverealm=NULL;
+ int rc = -1;
+ extern char * k5prprompt;
+ extern char * k5pwprompt;
+
+ ini_kerb(); /* Place defaults in above structs */
+ passwd[0] = '\0';
+
+ if ( krb5_init.principal == NULL ||
+ krb5_init.principal[0] == '\0') {
+ int ok = uq_txt(NULL,k5prprompt && k5prprompt[0] ? k5prprompt :
+ "Kerberos 5 Principal: ",2,NULL,passwd,PWD_SZ-1,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if ( ok && passwd[0] )
+ makestr(&krb5_init.principal,passwd);
+ else
+ return(0);
+ }
+
+ /* Save realm in init structure so it can be restored */
+ if ( realm ) {
+ saverealm = krb5_init.realm;
+ krb5_init.realm = realm;
+ }
+
+ if ( passwd[0] || !(pwbuf[0] && pwflg) ) {
+ int ok;
+ if ( k5pwprompt && k5pwprompt[0] &&
+ (strlen(k5pwprompt) + strlen(krb5_init.principal) +
+ strlen(krb5_init.realm) - 4) < sizeof(prompt)) {
+ sprintf(prompt,k5pwprompt,krb5_init.principal,krb5_init.realm);
+ } else
+ ckmakxmsg(prompt,sizeof(prompt),
+ k5pwprompt && k5pwprompt[0] ? k5pwprompt :
+ "Kerberos 5 Password for ",
+ krb5_init.principal,"@",krb5_init.realm,": ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if ( !ok )
+ passwd[0] = '\0';
+ } else {
+ ckstrncpy(passwd,(char *)pwbuf,sizeof(passwd));
+#ifdef OS2
+ if ( pwcrypt )
+ ck_encrypt((char *)passwd);
+#endif /* OS2 */
+ }
+
+ if ( passwd[0] ) {
+ extern struct krb4_init_data krb4_init;
+ char * savek4realm=NULL;
+
+ makestr(&krb5_init.password,passwd);
+
+ if ( krb5_d_getk4 ) {
+ krb5_init.getk4 = 1;
+ makestr(&krb4_init.principal,krb5_init.principal);
+ makestr(&krb4_init.password,passwd);
+ if ( realm ) {
+ savek4realm = krb4_init.realm;
+ krb4_init.realm = realm;
+ }
+ rc = ck_krb5_initTGT(&krb_op, &krb5_init,&krb4_init);
+
+ if ( savek4realm )
+ krb4_init.realm = savek4realm;
+ free(krb4_init.password);
+ krb4_init.password = NULL;
+ } else {
+ rc = ck_krb5_initTGT(&krb_op, &krb5_init,NULL);
+ }
+
+ free(krb5_init.password);
+ krb5_init.password = NULL;
+
+ memset(passwd,0,PWD_SZ);
+ }
+
+ /* restore realm to init structure if needed */
+ if ( saverealm )
+ krb5_init.realm = saverealm;
+ return(rc == 0);
+}
+
+static krb5_error_code
+#ifdef CK_ANSIC
+k5_get_ccache( krb5_context k5_context, krb5_ccache * p_ccache,
+ char * cc_name )
+#else /* CK_ANSIC */
+k5_get_ccache(k5_context, p_ccache, cc_name)
+ krb5_context k5_context;
+ krb5_ccache * p_ccache;
+ char * cc_name;
+#endif /* CK_ANSIC */
+{
+ krb5_error_code r=0;
+ char cc_tmp[CKMAXPATH+1];
+ const char * def_name = NULL;
+
+#ifndef HEIMDAL
+ if ( cc_name ) {
+ if ( strncmp("FILE:",cc_name,5) &&
+ strncmp("MEMORY:",cc_name,7) &&
+ strncmp("API:",cc_name,4) &&
+ strncmp("STDIO:",cc_name,6) &&
+ strncmp("MSLSA:",cc_name,6))
+#ifdef NT
+ ckmakmsg(cc_tmp,CKMAXPATH,"API:",cc_name,NULL,NULL);
+#else /* NT */
+ ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",cc_name,NULL,NULL);
+#endif /* NT */
+ else {
+ ckstrncpy(cc_tmp,cc_name,CKMAXPATH);
+ }
+ r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache);
+ if (r != 0) {
+ com_err("k5_get_ccache resolving ccache",r,
+ cc_tmp);
+ } else {
+ /* Make sure GSSAPI sees the same cache we are using */
+ char buf[128];
+ ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL);
+ putenv(buf);
+ }
+ } else if ( krb5_d_cc ) {
+ if ( strncmp("FILE:",krb5_d_cc,5) &&
+ strncmp("MEMORY:",krb5_d_cc,7) &&
+ strncmp("API:",krb5_d_cc,4) &&
+ strncmp("STDIO:",krb5_d_cc,6) &&
+ strncmp("MSLSA:", krb5_d_cc,6))
+#ifdef NT
+ ckmakmsg(cc_tmp,CKMAXPATH,"API:",krb5_d_cc,NULL,NULL);
+#else /* NT */
+ ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",krb5_d_cc,NULL,NULL);
+#endif /* NT */
+ else {
+ ckstrncpy(cc_tmp,krb5_d_cc,CKMAXPATH);
+ }
+ r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache);
+ if (r != 0) {
+ com_err("k5_get_ccache resolving ccache",r,
+ krb5_d_cc);
+ } else {
+ /* Make sure GSSAPI sees the same cache we are using */
+ char buf[128];
+ ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL);
+ putenv(buf);
+ }
+ } else
+#endif /* HEIMDAL */
+ {
+ if ((r = krb5_cc_default(k5_context, p_ccache))) {
+ com_err("k5_get_ccache",r,"while getting default ccache");
+ }
+ }
+ /* do not set krb5_errno/krb5_errmsg here since the value returned */
+ /* is being passed internally within the krb5 functions. */
+ return(r);
+}
+
+
+char *
+ck_krb5_realmofhost(char *host)
+{
+ char ** realmlist=NULL;
+ krb5_context private_context=NULL;
+ static char * realm = NULL;
+
+ if ( !host )
+ return NULL;
+
+ if ( realm ) {
+ free(realm);
+ realm = NULL;
+ }
+
+ /* create private_context */
+ if (krb5_init_context(&private_context)) {
+ debug(F110,"ck_krb5_realmofhost()","unable to init_context",0);
+ return(NULL);
+ }
+
+ krb5_get_host_realm(private_context,host,&realmlist);
+ if (realmlist && realmlist[0]) {
+ makestr(&realm,realmlist[0]);
+ krb5_free_host_realm(private_context,realmlist);
+ realmlist = NULL;
+ }
+
+ if ( private_context ) {
+ krb5_free_context(private_context);
+ private_context = NULL;
+ }
+
+ if (ckstrchr(realm,'.') == NULL) {
+ int n = 0;
+ char * p = host;
+ while ( (p = ckstrchr(p,'.')) != NULL ) {
+ n++;
+ p++;
+ }
+ if (n == 1) {
+ makestr(&realm,host);
+ ckupper(realm);
+ } else {
+ free(realm);
+ realm = NULL;
+ }
+ }
+ return(realm);
+}
+
+/*
+ *
+ * K5_auth_send - gets authentication bits we need to send to KDC.
+ *
+ * Code lifted from telnet sample code in the appl directory.
+ *
+ * Result is left in k5_auth
+ *
+ * Returns: 0 on failure, 1 on success
+ *
+ */
+
+static int
+#ifdef CK_ANSIC
+k5_auth_send(int how, int encrypt, int forward)
+#else
+k5_auth_send(how,encrypt,forward) int how; int encrypt; int forward;
+#endif
+{
+ krb5_error_code r=0;
+ krb5_ccache ccache=NULL;
+#ifndef HEIMDAL
+ krb5_creds creds;
+#endif /* HEIMDAL */
+ krb5_creds * new_creds=NULL;
+#ifdef CK_ENCRYPTION
+ krb5_keyblock *newkey = 0;
+#endif /* CK_ENCRYPTION */
+ krb5_flags ap_opts, auth_flags;
+ char type_check[32];
+ krb5_data checksum;
+ int len=0;
+ char * realm = NULL;
+ char tgt[256];
+
+ realm = ck_krb5_realmofhost(szHostName);
+ if (!realm) {
+ ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL);
+ ckstrncat(strTmp, szHostName,AUTHTMPBL);
+ ckstrncat(strTmp, "\"",AUTHTMPBL);
+ printf("?Kerberos 5 error: %s\r\n",strTmp);
+ krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN;
+ makestr(&krb5_errmsg,strTmp);
+ return(0);
+ }
+
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
+ debug(F110,"k5_auth_send TGT",tgt,0);
+ if ( krb5_autoget &&
+ !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
+ (ck_krb5_is_tgt_valid() > 0)) )
+ ck_krb5_autoget_TGT(realm);
+
+ r = k5_get_ccache(k5_context,&ccache,NULL);
+ if ( r ) {
+ com_err(NULL, r, "while authorizing (0).");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(0);
+ }
+
+#ifndef HEIMDAL
+ memset((char *)&creds, 0, sizeof(creds));
+ if (r = krb5_sname_to_principal(k5_context, szHostName,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
+ KRB5_NT_SRV_HST, &creds.server)) {
+ com_err(NULL, r, "while authorizing (1).");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(0);
+ }
+
+ if (forward_flag) {
+ if (fwd_server) {
+ krb5_free_principal(k5_context,fwd_server);
+ fwd_server = NULL;
+ }
+ krb5_copy_principal(k5_context,creds.server,&fwd_server);
+ }
+
+ r = krb5_cc_get_principal(k5_context, ccache, &creds.client);
+ if (r) {
+ com_err(NULL, r, "while authorizing (2).");
+ krb5_free_cred_contents(k5_context, &creds);
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(0);
+ }
+
+ if (szUserName[0] == '\0') { /* Get user name now */
+ len = krb5_princ_component(k5_context, creds.client, 0)->length;
+ if ( len < sizeof(szUserName) ) {
+ memcpy(szUserName,
+ krb5_princ_component(k5_context, creds.client, 0)->data,
+ len); /* safe */
+ } else
+ len = 0;
+ szUserName[len] = '\0';
+ } else {
+ char * name = NULL;
+ len = krb5_princ_component(k5_context, creds.client, 0)->length;
+ if ( len == strlen(szUserName) ) {
+ name = krb5_princ_component(k5_context, creds.client, 0)->data;
+#ifdef OS2
+ if ( !strnicmp(szUserName,name,len) )
+ memcpy(szUserName,name,len); /* safe */
+#endif /* OS2 */
+ }
+ }
+ if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */
+ /* Not sure if this is necessary anymore. What impact does it have
+ * on Win2000 TGTs that use DES_CBC_MD5 or RC4_HMAC?
+ *
+ * This prevents using 3DES Service Tickets.
+ */
+ creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+ }
+
+ if (r = krb5_get_credentials(k5_context, 0,
+ ccache, &creds, &new_creds)) {
+ com_err(NULL, r, "while authorizing (3).");
+ krb5_free_cred_contents(k5_context, &creds);
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(0);
+ }
+#endif /* HEIMDAL */
+
+ if (auth_context) {
+ krb5_auth_con_free(k5_context, auth_context);
+ auth_context = 0;
+ }
+ if (r = krb5_auth_con_init(k5_context, &auth_context)) {
+ com_err(NULL, r, "while initializing auth context");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(0);
+ }
+
+ /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */
+ /* client and then server finished messages. */
+
+ type_check[0] = AUTHTYPE_KERBEROS_V5;
+ type_check[1] = AUTH_CLIENT_TO_SERVER |
+ (how ? AUTH_HOW_MUTUAL : AUTH_HOW_ONE_WAY) |
+ (encrypt) |
+ (forward ? INI_CRED_FWD_ON : INI_CRED_FWD_OFF);
+#ifdef CK_SSL
+ if (encrypt == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ }
+#endif /* CK_SSL */
+
+#ifndef HEIMDAL
+ checksum.magic = KV5M_DATA;
+#endif /* HEIMDAL */
+ checksum.length =
+#ifdef CK_SSL
+ (encrypt == AUTH_ENCRYPT_START_TLS) ? 26 :
+#endif /* CK_SSL */
+ 2;
+ checksum.data = (char *)&type_check;
+
+ ap_opts = 0;
+ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+ ap_opts |= AP_OPTS_MUTUAL_REQUIRED;
+
+#ifdef HEIMDAL
+ r = krb5_auth_setkeytype(k5_context, auth_context, KEYTYPE_DES);
+ if (r)
+ com_err(NULL, r, "while setting auth keytype");
+ r = krb5_auth_con_setaddrs_from_fd(k5_context,auth_context, &ttyfd);
+ if (r)
+ com_err(NULL, r, "while setting auth addrs");
+ r = krb5_mk_req(k5_context, &auth_context, ap_opts,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
+ szHostName, &checksum, ccache, &k5_auth);
+ if (r)
+ com_err(NULL, r, "while making request");
+#else /* HEIMDAL */
+ auth_flags = KRB5_AUTH_CONTEXT_RET_TIME;
+#ifdef CK_ENCRYPTION
+ ap_opts |= AP_OPTS_USE_SUBKEY;
+#endif /* CK_ENCRYPTION */
+#ifdef TLS_VERIFY
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ auth_flags |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
+ if (!krb5_d_no_addresses)
+ r = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+ }
+#endif /* CK_SSL */
+ krb5_auth_con_setflags(k5_context, auth_context, auth_flags);
+ r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts,
+ &checksum, new_creds, &k5_auth);
+#endif /* HEIMDAL */
+
+#ifdef CK_ENCRYPTION
+ if (!r) {
+ r = krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey);
+ if (r)
+ r = krb5_auth_con_getkey(k5_context, auth_context, &newkey);
+
+ if (k5_session_key) {
+ krb5_free_keyblock(k5_context, k5_session_key);
+ k5_session_key = 0;
+ }
+ }
+ if (newkey) {
+ /*
+ * keep the key in our private storage, but don't use it
+ * yet---see kerberos5_reply() below
+ */
+#ifdef HEIMDAL
+ if ((newkey->keytype == ETYPE_DES_CBC_CRC) ||
+ (newkey->keytype == ETYPE_DES_CBC_MD5) ||
+ (newkey->keytype == ETYPE_DES_CBC_MD4))
+ {
+ debug(F111,"k5_auth_send()","newkey->keytype",newkey->keytype);
+ krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
+ }
+#else /* HEIMDAL */
+ /* look for all possible DES keys first - just for compatibility */
+ /* other key types are much less likely to be available */
+ if ((newkey->enctype == ENCTYPE_DES_CBC_CRC) ||
+ (newkey->enctype == ENCTYPE_DES_CBC_MD5) ||
+ (newkey->enctype == ENCTYPE_DES_CBC_MD4))
+ {
+ debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype);
+ krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
+ }
+ else if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
+ (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
+ {
+ /* use the session key in credentials instead */
+ debug(F111,"k5_auth_send()","new_creds->keyblock.enctype",
+ new_creds->keyblock.enctype);
+ krb5_copy_keyblock(k5_context,
+ &new_creds->keyblock, &k5_session_key);
+ }
+ else if (newkey->enctype != 0)
+ {
+ debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype);
+ krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
+ }
+ else if (new_creds->keyblock.enctype != 0)
+ {
+ /* use the session key in credentials instead */
+ debug(F111,"k5_auth_send()","new_creds->keyblock.enctype",
+ new_creds->keyblock.enctype);
+ krb5_copy_keyblock(k5_context,
+ &new_creds->keyblock, &k5_session_key);
+ }
+ else {
+ debug(F110,"k5_auth_send()","NO KEY in newkey",0);
+ }
+#endif /* HEIMDAL */
+ krb5_free_keyblock(k5_context, newkey);
+ }
+#endif /* CK_ENCRYPTION */
+#ifndef HEIMDAL
+ krb5_free_cred_contents(k5_context, &creds);
+ krb5_free_creds(k5_context, new_creds);
+#endif /* HEIMDAL */
+ krb5_cc_close(k5_context,ccache);
+
+ if (r) {
+ com_err(NULL, r, "while authorizing (4).");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(0);
+ }
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,"OK");
+ return(1);
+}
+
+/*
+ * K5_auth_reply -- checks the reply for mutual authentication.
+ */
+static int
+#ifdef CK_ANSIC
+k5_auth_reply(int how, unsigned char *data, int cnt)
+#else
+k5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#endif /* CK_ENCRYPTION */
+
+ data += 4; /* Point to status byte */
+ cnt -=5;
+
+ switch (*data++) {
+ case KRB_REJECT:
+ if (cnt > 0) {
+ char *s;
+ int len;
+ ckstrncpy(strTmp,"Kerberos V5 refuses authentication because\r\n",
+ sizeof(strTmp));
+ len = strlen(strTmp);
+ if ( len + cnt < sizeof(strTmp) ) {
+ s = strTmp + strlen(strTmp);
+ memcpy(s, data, cnt); /* safe */
+ s[cnt] = 0;
+ }
+ } else
+ ckstrncpy(strTmp,"Kerberos V5 refuses authentication",
+ sizeof(strTmp));
+ krb5_errno = -1;
+ makestr(&krb5_errmsg,strTmp);
+ printf("Kerberos authentication failed!\r\n%s\r\n",strTmp);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+
+ case KRB_ACCEPT:
+ if (!mutual_complete) {
+ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !mutual_complete) {
+ ckstrncpy(strTmp,
+ "Kerberos V5 accepted you, but didn't provide"
+ " mutual authentication",sizeof(strTmp));
+ printf("Kerberos authentication failed!\r\n%s\r\n",strTmp);
+ krb5_errno = -1;
+ makestr(&krb5_errmsg,strTmp);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+#ifdef CK_ENCRYPTION
+ if (k5_session_key) {
+ if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */
+ skey.type = SK_DES;
+ skey.length = 8;
+#ifdef HEIMDAL
+ skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+ skey.data = k5_session_key->contents;
+#endif /* HEIMDAL */
+ } else {
+#ifdef HEIMDAL
+ switch ( k5_session_key->keytype ) {
+ case ETYPE_DES_CBC_CRC:
+ case ETYPE_DES_CBC_MD5:
+ case ETYPE_DES_CBC_MD4:
+ skey.type = SK_DES;
+ skey.length = 8;
+ break;
+ default:
+ skey.type = SK_GENERIC;
+ skey.length = k5_session_key->length;
+ encrypt_dont_support(ENCTYPE_DES_CFB64);
+ encrypt_dont_support(ENCTYPE_DES_OFB64);
+ }
+ skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+ switch ( k5_session_key->enctype ) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_MD4:
+ skey.type = SK_DES;
+ skey.length = 8;
+ default:
+ skey.type = SK_GENERIC;
+ skey.length = k5_session_key->length;
+ encrypt_dont_support(ENCTYPE_DES_CFB64);
+ encrypt_dont_support(ENCTYPE_DES_OFB64);
+ }
+ skey.data = k5_session_key->contents;
+#endif /* HEIMDAL */
+ }
+ encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
+ }
+#endif /* CK_ENCRYPTION */
+ }
+ if ( cnt > 0 ) {
+ char *s;
+ int len;
+ ckstrncpy(strTmp,"Kerberos V5 accepts you as ",sizeof(strTmp));
+ len = strlen(strTmp);
+ if ( len + cnt < sizeof(strTmp) ) {
+ s = strTmp + strlen(strTmp);
+ memcpy(s,data,cnt);
+ s[cnt] = 0;
+ }
+ }
+ accept_complete = 1;
+ printf("%s\r\n",strTmp);
+
+#ifdef FORWARD
+ if (forward_flag
+#ifdef COMMENT
+ /* Marc Horowitz <marc@mit.edu> has successfully argued
+ that it is indeed safe to send Forwarded credentials
+ to an untrusted host.
+ */
+ && (auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL
+#endif /* COMMENT */
+ )
+ kerberos5_forward();
+#endif /* FORWARD */
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+
+ case KRB5_RESPONSE:
+#ifdef TLS_VERIFY
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS &&
+ !krb5_tls_verified) {
+ printf(
+ "Man in the middle attack detected. Session terminated.\r\n");
+#ifndef BETATEST
+ netclos();
+#endif /* BETATEST */
+ krb5_errno = -1;
+ makestr(&krb5_errmsg,"TLS not verified");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ if((ssl_active_flag || tls_active_flag) &&
+ (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ printf("TLS session parameters verified by Kerberos 5\r\n");
+ }
+#endif /* TLS_VERIFY */
+ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+ /* the rest of the reply should contain a krb_ap_rep */
+ krb5_ap_rep_enc_part *reply;
+ krb5_data inbuf;
+ krb5_error_code r;
+
+ inbuf.length = cnt;
+ inbuf.data = (char *)data;
+
+ if (r = krb5_rd_rep(k5_context, auth_context, &inbuf, &reply)) {
+ com_err(NULL, r, "while authorizing. (5)");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ krb5_free_ap_rep_enc_part(k5_context, reply);
+
+#ifdef CK_ENCRYPTION
+ if (encrypt_flag && k5_session_key) {
+ if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */
+ skey.type = SK_DES;
+ skey.length = 8;
+#ifdef HEIMDAL
+ skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+ skey.data = k5_session_key->contents;
+#endif /* HEIMDAL */
+ } else {
+#ifdef HEIMDAL
+ switch ( k5_session_key->keytype ) {
+ case ETYPE_DES_CBC_CRC:
+ case ETYPE_DES_CBC_MD5:
+ case ETYPE_DES_CBC_MD4:
+ skey.type = SK_DES;
+ skey.length = 8;
+ default:
+ skey.type = SK_GENERIC;
+ skey.length = k5_session_key->length;
+ }
+ skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+ switch ( k5_session_key->enctype ) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_MD4:
+ skey.type = SK_DES;
+ skey.length = 8;
+ break;
+ default:
+ skey.type = SK_GENERIC;
+ skey.length = k5_session_key->length;
+ }
+ skey.data = k5_session_key->contents;
+#endif /* HEIMDAL */
+ }
+ encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
+ }
+#endif /* ENCRYPTION */
+ mutual_complete = 1;
+ }
+ ckstrncpy(strTmp,"Remote machine has been mutually authenticated",
+ sizeof(strTmp));
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,strTmp);
+ printf("%s\r\n",strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+
+#ifdef FORWARD
+ case KRB5_FORWARD_ACCEPT:
+ forwarded_tickets = 1;
+ ckstrncpy(strTmp,"Remote machine has accepted forwarded credentials",
+ sizeof(strTmp));
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,strTmp);
+ printf("%s\r\n",strTmp);
+ return AUTH_SUCCESS;
+
+ case KRB5_FORWARD_REJECT:
+ forwarded_tickets = 0;
+ if (cnt > 0) {
+ char *s;
+ int len;
+ len = ckstrncpy(strTmp,
+ "Kerberos V5 refuses forwarded credentials because ",
+ sizeof(strTmp));
+ if ( len + cnt < sizeof(strTmp) ) {
+ s = strTmp + strlen(strTmp);
+ memcpy(s, data, cnt);
+ s[cnt] = 0;
+ }
+ } else
+ ckstrncpy(strTmp, "Kerberos V5 refuses forwarded credentials",
+ sizeof(strTmp));
+
+ printf("%s\r\n",strTmp);
+ krb5_errno = -1;
+ makestr(&krb5_errmsg,strTmp);
+ return AUTH_SUCCESS;
+#endif /* FORWARD */
+
+#ifdef TLS_VERIFY
+ case KRB5_TLS_VERIFY:
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ krb5_data reply, msg;
+ char tls_verify[24];
+ krb5_replay_data repdata;
+ krb5_error_code r;
+
+ ssl_get_server_finished(&tls_verify[0],12);
+ ssl_get_client_finished(&tls_verify[12],12);
+
+ reply.data = (char *)data;
+ reply.length = cnt;
+
+ krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+
+ if (r = krb5_rd_safe(k5_context,auth_context,&reply,&msg,&repdata))
+ {
+ com_err("", r, "decoding tls verifier");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,"TLS verify failure");
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+ if ( msg.length == 24 && !memcmp(msg.data,tls_verify,24) )
+ krb5_tls_verified = 1;
+ krb5_free_data_contents(k5_context,&msg);
+ if (krb5_tls_verified)
+ return(AUTH_SUCCESS);
+ }
+ printf("Man in the middle attack detected. Session terminated.\r\n");
+ netclos();
+ krb5_errno = -1;
+ makestr(&krb5_errmsg,"TLS verify failure");
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+#endif /* CK_SSL */
+
+ default:
+ krb5_errno = -1;
+ makestr(&krb5_errmsg,"Unknown reply type");
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE; /* Unknown reply type */
+ }
+}
+
+#ifdef FORWARD
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+/* Needed for KRB5_FORWARD */
+static krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, client)
+ krb5_context context;
+ krb5_auth_context auth_context;
+ krb5_data *inbuf;
+ krb5_const_principal client;
+{
+ krb5_creds ** creds=NULL;
+ krb5_error_code retval;
+ krb5_ccache ccache=NULL;
+
+#ifdef HEIMDAL
+ /*
+ Heimdal Telnetd creates the cache file at this point and sets
+ the KRB5CCNAME environment variable.
+
+ struct passwd *pwd;
+ char ccname[1024];
+
+ pwd = getpwnam(szUserNameRequested);
+ if (pwd == NULL)
+ break;
+ snprintf(ccname, sizeof(ccname)-1, "FILE:/tmp/krb5cc_%u",pwd->pw_uid);
+ retval = krb5_cc_resolve(context,ccname,&ccache);
+
+ chown(ccname + 5, pwd->pw_uid, -1);
+ */
+#endif /* HEIMDAL */
+
+ if (retval = k5_get_ccache(context,&ccache,NULL))
+ return(retval);
+
+#ifdef HEIMDAL
+ if ((retval = krb5_cc_initialize(context, ccache, client)))
+ return(retval);
+
+ if ((retval = krb5_rd_cred(context, auth_context, ccache, inbuf)))
+ return(retval);
+#else /* HEIMDAL */
+ if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)))
+ return(retval);
+
+ if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
+ goto cleanup;
+
+ if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
+ goto cleanup;
+
+ if ((retval = krb5_cc_close(context, ccache)))
+ goto cleanup;
+
+ cleanup:
+ krb5_free_tgt_creds(context, creds);
+#endif /* HEIMDAL */
+ return retval;
+}
+#endif /* FORWARD */
+
+/*
+ *
+ * K5_auth_is.
+ *
+ */
+
+static int
+#ifdef CK_ANSIC
+k5_auth_is(int how, unsigned char *data, int cnt)
+#else
+k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ int r = 0;
+ krb5_principal server;
+ krb5_keyblock *newkey = NULL;
+ krb5_data outbuf;
+ char errbuf[128]="";
+ char *getenv();
+#ifndef HEIMDAL
+ krb5_authenticator *authenticator;
+ krb5_keytab keytabid = 0;
+#endif /* HEIMDAL */
+ krb5_data inbuf;
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#endif /* CK_ENCRYPTION */
+ char princ[256]="";
+ int len;
+
+ data += 4; /* Point to status byte */
+ cnt -= 4;
+
+ ckhexdump("k5_auth_is data",data,cnt);
+ debug(F111,"k5_auth_is","how",how);
+
+ if (cnt-- < 1) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ switch (*data++) {
+ case KRB_AUTH:
+ k5_auth.data = (char *)data;
+ k5_auth.length = cnt;
+
+ debug(F110,"k5_auth_is","KRB_AUTH",0);
+ debug(F111,"k5_auth_is","auth_context",auth_context);
+
+ if (!r && !auth_context) {
+ r = krb5_auth_con_init(k5_context, &auth_context);
+ debug(F111,"k5_auth_is","krb5_auth_con_init",r);
+ }
+
+#ifdef HEIMDAL
+ if (!r)
+ r = krb5_auth_con_setaddrs_from_fd(k5_context,
+ auth_context,
+ &ttyfd);
+ if (!r)
+ r = krb5_sock_to_principal(k5_context,
+ 0,
+ "host",
+ KRB5_NT_SRV_HST,
+ &server);
+ if (!r)
+#else /* HEIMDAL */
+ if (!r) {
+ krb5_rcache rcache = NULL;
+
+ r = krb5_auth_con_getrcache(k5_context, auth_context,
+ &rcache);
+ debug(F111,"k5_auth_is","krb5_auth_con_getrcache",r);
+
+ if (!r && !rcache) {
+ /* Do not resolve server's principal name, we will check */
+ /* for validity after the krb5_rd_req() call. */
+ r = krb5_sname_to_principal(k5_context, 0, 0,
+ KRB5_NT_SRV_HST, &server);
+ debug(F111,"k5_auth_is","krb5_sname_to_principal",r);
+
+ if (!r) {
+ r = krb5_get_server_rcache(k5_context,
+ krb5_princ_component(k5_context, server, 0),
+ &rcache);
+ debug(F111,"k5_auth_is","krb5_get_server_rcache",r);
+ krb5_free_principal(k5_context, server);
+ }
+ }
+ if (!r) {
+ r = krb5_auth_con_setrcache(k5_context,
+ auth_context, rcache);
+ debug(F111,"k5_auth_is","krb5_auth_con_setrcache",r);
+ }
+ }
+ if (!r && k5_keytab) {
+ r = krb5_kt_resolve(k5_context,
+ k5_keytab, &keytabid);
+ debug(F111,"k5_auth_is","krb5_kt_resolve",r);
+ }
+#endif /* HEIMDAL */
+ if (!r) {
+ r = krb5_rd_req(k5_context, &auth_context, &k5_auth,
+#ifdef HEIMDAL
+ server, NULL, NULL,
+#else /* HEIMDAL */
+ NULL, keytabid, NULL,
+#endif /* HEIMDAL */
+ &k5_ticket);
+ debug(F111,"k5_auth_is","krb5_rd_req",r);
+ }
+ if (r) {
+ (void) ckstrncpy(errbuf, "krb5_rd_req failed: ",sizeof(errbuf));
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ goto errout;
+ }
+#ifdef HEIMDAL
+ krb5_free_principal(k5_context, server);
+
+ {
+ char type_check[26];
+
+ /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */
+ /* client and then server finished messages. */
+
+ type_check[0] = AUTHTYPE_KERBEROS_V5;
+ type_check[1] = how; /* not broken into parts */
+#ifdef CK_SSL
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ ckhexdump("k5_auth_is type_check",type_check,26);
+ }
+#endif /* CK_SSL */
+
+ r = krb5_verify_authenticator_checksum(k5_context,
+ auth_context,
+ type_check,
+#ifdef CK_SSL
+ ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 :
+#endif /* CK_SSL */
+ 2);
+ }
+#else /* HEIMDAL */
+ len = krb5_princ_component(k5_context,k5_ticket->server,0)->length;
+ if (len < 256)
+ {
+ memcpy(princ,
+ krb5_princ_component(k5_context,k5_ticket->server,0)->data,
+ len);
+ princ[len] = '\0';
+ }
+ if ( strcmp((krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME), princ) )
+ {
+ debug(F110,"k5_auth_is incorrect service name",princ,0);
+ ckstrncpy(errbuf,"incorrect service name: ",sizeof(errbuf));
+ ckstrncat(errbuf,krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
+ sizeof(errbuf));
+ ckstrncat(errbuf," != ",sizeof(errbuf));
+ ckstrncat(errbuf,princ,sizeof(errbuf));
+ goto errout;
+ }
+
+ r = krb5_auth_con_getauthenticator(k5_context,
+ auth_context,
+ &authenticator);
+ debug(F111,"k5_auth_is","krb5_auth_con_getauthenticator",r);
+ if (r) {
+ (void) ckstrncpy(errbuf,
+ "krb5_auth_con_getauthenticator failed: ",
+ sizeof(errbuf)
+ );
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ goto errout;
+ }
+
+ if (authenticator->checksum) {
+ char type_check[26];
+ krb5_checksum *cksum = authenticator->checksum;
+ krb5_keyblock *key;
+
+ /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */
+ /* client and then server finished messages. */
+
+ type_check[0] = AUTHTYPE_KERBEROS_V5;
+ type_check[1] = how; /* not broken into parts */
+#ifdef CK_SSL
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ ckhexdump("k5_auth_is type_check",type_check,26);
+ }
+#endif /* CK_SSL */
+
+ r = krb5_auth_con_getkey(k5_context, auth_context,
+ &key);
+ debug(F111,"k5_auth_is","krb5_auth_con_getkey",r);
+ if (r) {
+ (void) ckstrncpy(errbuf, "krb5_auth_con_getkey failed: ",
+ sizeof(errbuf));
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ goto errout;
+ }
+
+ r = krb5_verify_checksum(k5_context,
+ cksum->checksum_type,
+ cksum,
+ &type_check,
+ ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 :
+ 2,
+ key->contents,
+ key->length
+ );
+ debug(F111,"k5_auth_is","krb5_verify_checksum",r);
+ if (r) {
+ (void) ckstrncpy(errbuf,
+ "checksum verification failed: ",
+ sizeof(errbuf)
+ );
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ goto errout;
+ }
+ krb5_free_keyblock(k5_context, key);
+ } else {
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) {
+ (void) strcpy(errbuf,
+ "authenticator is missing required checksum");
+ goto errout;
+ }
+ }
+
+ krb5_free_authenticator(k5_context, authenticator);
+#endif /* HEIMDAL */
+
+#ifdef TLS_VERIFY
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ krb5_data in, msg;
+ char tls_verify[24];
+ krb5_replay_data repdata;
+
+ ssl_get_server_finished(&tls_verify[0],12);
+ ssl_get_client_finished(&tls_verify[12],12);
+
+ in.data = tls_verify;
+ in.length = 24;
+
+ krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
+ if (r = krb5_mk_safe(k5_context,auth_context,&in,&msg,&repdata)) {
+ com_err("", r, "encoding tls verifier");
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ goto errout;
+ }
+ SendK5AuthSB(KRB5_TLS_VERIFY, msg.data, msg.length);
+ krb5_free_data_contents(k5_context,&msg);
+ }
+#endif /* CK_SSL */
+ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+ /* do ap_rep stuff here */
+ if ((r = krb5_mk_rep(k5_context,
+#ifdef HEIMDAL
+ &auth_context,
+#else /* HEIMDAL */
+ auth_context,
+#endif /* HEIMDAL */
+ &outbuf))) {
+ debug(F111,"k5_auth_is","krb5_mk_rep",r);
+ (void) ckstrncpy(errbuf, "Make reply failed: ",sizeof(errbuf));
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ goto errout;
+ }
+ debug(F111,"k5_auth_is","krb5_mk_rep",r);
+
+ SendK5AuthSB(KRB5_RESPONSE, outbuf.data, outbuf.length);
+ mutual_complete = 1;
+ }
+
+#ifdef HEIMDAL
+ {
+ char * name = NULL;
+ if (krb5_unparse_name(k5_context, k5_ticket->client,
+ &name))
+ {
+ szUserNameAuthenticated[0] = '\0';
+ } else {
+ ckstrncpy(szUserNameAuthenticated,UIDBUFLEN,name);
+ free(name);
+ }
+ }
+#else /* HEIMDAL */
+ if ( krb5_aname_to_localname(k5_context,
+ k5_ticket->enc_part2->client,
+ UIDBUFLEN,szUserNameAuthenticated) )
+ szUserNameAuthenticated[0] = '\0';
+#endif /* HEIMDAL */
+
+ SendK5AuthSB(KRB_ACCEPT, szUserNameAuthenticated,
+ szUserNameAuthenticated[0] ? -1 : 0);
+ accept_complete = 1;
+ ckmakmsg(strTmp,sizeof(strTmp),
+ "Kerberos5 identifies him as ``",
+ szUserNameAuthenticated,"''",NULL);
+ printf("%s\r\n",strTmp);
+
+ if (szUserNameRequested[0] &&
+ krb5_kuserok(k5_context,
+#ifdef HEIMDAL
+ k5_ticket->client,
+#else /* HEIMDAL */
+ k5_ticket->enc_part2->client,
+#endif /* HEIMDAL */
+ szUserNameRequested))
+ auth_finished(AUTH_VALID);
+ else
+ auth_finished(AUTH_USER);
+
+ krb5_auth_con_getremotesubkey(k5_context, auth_context,
+ &newkey);
+ if (k5_session_key) {
+ krb5_free_keyblock(k5_context, k5_session_key);
+ k5_session_key = 0;
+ }
+ if (newkey) {
+ krb5_copy_keyblock(k5_context, newkey, &k5_session_key);
+ krb5_free_keyblock(k5_context, newkey);
+ } else {
+ krb5_copy_keyblock(k5_context,
+#ifdef HEIMDAL
+ &k5_ticket->ticket.key,
+#else /* HEIMDAL */
+ k5_ticket->enc_part2->session,
+#endif /* HEIMDAL */
+ &k5_session_key);
+ }
+
+#ifdef CK_ENCRYPTION
+#ifdef HEIMDAL
+ skey.type = k5_session_key->keyvalue.length == 8 ? SK_DES : SK_GENERIC;
+ skey.length = k5_session_key->keyvalue.length;
+ skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+ skey.type = k5_session_key->length == 8 ? SK_DES : SK_GENERIC;
+ skey.length = k5_session_key->length;
+ skey.data = k5_session_key->contents;
+#endif /* HEIMDAL */
+ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+#endif /* CK_ENCRYPTION */
+ debug(F100,"k5_auth_is AUTH_SUCCESS","",0);
+ krb5_errno = r;
+ if ( krb5_errno )
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ else
+ makestr(&krb5_errmsg,strTmp);
+ return AUTH_SUCCESS;
+
+#ifdef FORWARD
+ case KRB5_FORWARD:
+ if ( !forward_flag ) {
+ SendK5AuthSB(KRB5_FORWARD_REJECT,
+ "forwarded credentials are being refused.",
+ -1);
+ return(AUTH_SUCCESS);
+ }
+
+ inbuf.length = cnt;
+ inbuf.data = (char *)data;
+ if (
+#ifndef HEIMDAL
+ (!krb5_d_no_addresses &&
+ (r = krb5_auth_con_genaddrs(k5_context,auth_context,g_kstream->fd,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) ||
+#endif /* HEIMDAL */
+ (r = rd_and_store_for_creds(k5_context, auth_context,&inbuf,
+#ifdef HEIMDAL
+ k5_ticket->client
+#else /* HEIMDAL */
+ k5_ticket->enc_part2->client
+#endif /* HEIMDAL */
+ ))) {
+ (void) ckstrncpy(errbuf, "Read forwarded creds failed: ",
+ sizeof(errbuf));
+ (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf));
+ SendK5AuthSB(KRB5_FORWARD_REJECT, errbuf, -1);
+ printf("Could not read forwarded credentials\r\n");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ }
+ else {
+ SendK5AuthSB(KRB5_FORWARD_ACCEPT, 0, 0);
+ ckstrncpy(strTmp,"Forwarded credentials obtained",sizeof(strTmp));
+ printf("%s\r\n",strTmp);
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,strTmp);
+ }
+ /* A failure to accept forwarded credentials is not an */
+ /* authentication failure. */
+ return AUTH_SUCCESS;
+#endif /* FORWARD */
+ default:
+ printf("Unknown Kerberos option %d\r\n", data[-1]);
+ SendK5AuthSB(KRB_REJECT, 0, 0);
+ break;
+ }
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+
+ errout:
+ SendK5AuthSB(KRB_REJECT, errbuf, -1);
+ krb5_errno = r;
+ makestr(&krb5_errmsg,errbuf);
+ printf("%s\r\n", errbuf);
+ if (auth_context) {
+ krb5_auth_con_free(k5_context, auth_context);
+ auth_context = 0;
+ }
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+}
+
+#ifdef FORWARD
+int
+#ifdef CK_ANSIC
+kerberos5_forward(void)
+#else
+kerberos5_forward()
+#endif
+{
+ krb5_error_code r;
+ krb5_ccache ccache=NULL;
+ krb5_principal client = 0;
+ krb5_principal server = 0;
+ krb5_data forw_creds;
+#ifdef HEIMDAL
+ krb5_creds creds;
+#endif /* HEIMDAL */
+
+ forw_creds.data = 0;
+
+ r = k5_get_ccache(k5_context,&ccache,NULL);
+ if ( r ) {
+ com_err(NULL, r, "Kerberos V5: could not get default ccache");
+ krb5_errno = r;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(AUTH_FAILURE);
+ }
+
+ if ((r = krb5_cc_get_principal(k5_context, ccache, &client))) {
+ com_err(NULL, r, "Kerberos V5: could not get default principal");
+ goto cleanup;
+ }
+
+#ifdef HEIMDAL
+ memset(&creds, 0, sizeof(creds));
+ creds.client = client;
+
+ if (r = krb5_build_principal(k5_context,
+ &creds.server,
+ strlen(client->realm),
+ client->realm,
+ "krbtgt",
+ client->realm,
+ NULL)) {
+ com_err(NULL, r, "Kerberos V5: could not get principal");
+ goto cleanup;
+ }
+
+ creds.times.endtime = 0;
+
+ if (r = krb5_get_forwarded_creds(k5_context,
+ auth_context,
+ ccache,
+ 0,
+ szHostName,
+ &creds,
+ &forw_creds)) {
+ com_err(NULL, r, "Kerberos V5: error getting forwarded creds");
+ goto cleanup;
+ }
+#else /* HEIMDAL */
+ /* we should not need to make this call since we are storing the */
+ /* server's principal in fwd_server from our call to */
+ /* krb5_sname_to_principal() in k5_auth_send() */
+ if (fwd_server == NULL) {
+ if ((r = krb5_sname_to_principal(k5_context, szHostName,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
+ KRB5_NT_SRV_HST, &server))) {
+ com_err(NULL, r, "Kerberos V5: could not make server principal");
+ goto cleanup;
+ }
+ }
+
+ if (!krb5_d_no_addresses &&
+ (r = krb5_auth_con_genaddrs(k5_context, auth_context, g_kstream->fd,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR)))
+ {
+ com_err(NULL, r, "Kerberos V5: could not gen local full address");
+ goto cleanup;
+ }
+
+ if (r = krb5_fwd_tgt_creds(k5_context, auth_context, 0, client,
+ fwd_server ? fwd_server : server,
+ ccache, forwardable_flag, &forw_creds)) {
+ com_err(NULL, r, "Kerberos V5: error getting forwardable credentials");
+ goto cleanup;
+ }
+#endif /* HEIMDAL */
+
+ /* Send forwarded credentials */
+ if (!SendK5AuthSB(KRB5_FORWARD, forw_creds.data, forw_creds.length)) {
+ printf("Kerberos V5 forwarding error!\r\n%s\r\n",
+ "Not enough room for authentication data");
+ }
+
+cleanup:
+ if (client)
+ krb5_free_principal(k5_context, client);
+ if (server)
+ krb5_free_principal(k5_context, server);
+#ifdef HEIMDAL
+ krb5_data_free(&forw_creds);
+#else /* HEIMDAL */
+ krb5_free_data_contents(k5_context,&forw_creds);
+#endif /* HEIMDAL */
+ krb5_cc_close(k5_context, ccache);
+
+ krb5_errno = r;
+ makestr(&krb5_errmsg,krb5_errno?error_message(krb5_errno):"OK");
+ return(r?AUTH_FAILURE:AUTH_SUCCESS);
+}
+#endif /* FORWARD */
+#else /* KRB5 */
+int
+ck_krb5_autoget_TGT(char * dummy)
+{
+ return(0);
+}
+#ifdef CK_KERBEROS
+int
+#ifdef CK_ANSIC
+ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init,
+ struct krb4_init_data * k4_init)
+#else
+ck_krb5_initTGT(op,init,k4_init)
+ krb_op_data * op; struct krb5_init_data * init;
+ struct krb4_init_data * k4_init;
+#endif /* CK_ANSIC*/
+{
+ return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb5_destroy(struct krb_op_data * op)
+#else
+ck_krb5_destroy(op) struct krb_op_data * op;
+#endif
+{
+ return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc)
+#else
+ck_krb5_list_creds(op,lc)
+ struct krb_op_data * op; struct krb5_list_cred_data * lc;
+#endif
+{
+ return(-1);
+}
+#else /* CK_KERBEROS */
+int
+#ifdef CK_ANSIC
+ck_krb5_initTGT(void * op, void * init, void * k4_init )
+#else
+ck_krb5_initTGT(op,init,k4_init)
+ void * op; void * init; void * k4_init;
+#endif /* CK_ANSIC*/
+{
+ return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb5_destroy(void * op)
+#else
+ck_krb5_destroy(op) void * op;
+#endif
+{
+ return(-1);
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb5_list_creds(void * op, void * lc)
+#else
+ck_krb5_list_creds(op,lc)
+ void * op; void * lc;
+#endif
+{
+ return(-1);
+}
+#endif /* CK_KERBEROS */
+#endif /* KRB5 */
+
+#ifdef GSSAPI_KRB5
+/*
+ *
+ * gssk5_auth_send - gets authentication bits we need to send to KDC.
+ *
+ * Result is left in k5_auth
+ *
+ * Returns: 0 on failure, 1 on success
+ *
+ */
+
+static int
+#ifdef CK_ANSIC
+gssk5_auth_send(int how, int encrypt, int forward)
+#else
+gssk5_auth_send(how,encrypt,forward) int how; int encrypt; int forward;
+#endif
+{
+ OM_uint32 maj_stat, min_stat;
+#ifdef KRB5
+ char * realm = NULL;
+ char tgt[256];
+#endif /* KRB5 */
+
+ gss_chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+ gss_chan.initiator_address.length = 4;
+ gss_chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
+ gss_chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+ gss_chan.acceptor_address.length = 4;
+ gss_chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
+ gss_chan.application_data.length = 0;
+ gss_chan.application_data.value = 0;
+
+#ifdef KRB5
+ realm = ck_krb5_realmofhost(ftp_host);
+ if (realm) {
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
+ debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
+ if ( krb5_autoget &&
+ !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
+ (ck_krb5_is_tgt_valid() > 0)) )
+ ck_krb5_autoget_TGT(realm);
+ }
+#endif /* KRB5 */
+
+ /* Blob from gss-client */
+ /* host@hostname */
+ /* the V5 GSSAPI binding canonicalizes this for us... */
+ ckmakmsg(gss_stbuf,GSS_BUFSIZ,
+ krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME,
+ "@",
+ szHostName,
+ NULL
+ );
+ fprintf(stderr, "Authenticating to <%s>...\n", gss_stbuf);
+ gss_send_tok.value = gss_stbuf;
+ gss_send_tok.length = strlen(gss_stbuf);
+ maj_stat = gss_import_name(&min_stat, &gss_send_tok,
+ gss_nt_service_name,
+ &gss_target_name
+ );
+ if (maj_stat != GSS_S_COMPLETE) {
+ user_gss_error(maj_stat, min_stat, "parsing name");
+ secure_error("name parsed <%s>\n", gss_stbuf);
+ return(0);
+ }
+ token_ptr = GSS_C_NO_BUFFER;
+ gcontext = GSS_C_NO_CONTEXT; /* structure copy */
+
+ fprintf(stderr, "calling gss_init_sec_context\n");
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &gcontext,
+ gss_target_name,
+ gss_mech_krb5,
+ GSS_C_MUTUAL_FLAG |
+ GSS_C_REPLAY_FLAG |
+ ((forward && forward_flag) ?
+ GSS_C_DELEG_FLAG : 0),
+ 0,
+ (krb5_d_no_addresses ? /* channel bindings */
+ GSS_C_NO_CHANNEL_BINDINGS :
+ &gss_chan),
+ gss_token_ptr,
+ NULL, /* ignore mech type */
+ &gss_send_tok,
+ NULL, /* ignore ret_flags */
+ NULL
+ ); /* ignore time_rec */
+
+
+ if (maj_stat != GSS_S_COMPLETE &&
+ maj_stat != GSS_S_CONTINUE_NEEDED) {
+ user_gss_error(maj_stat,
+ min_stat,
+ "initializing context"
+ );
+ gss_release_name(&min_stat, &gss_target_name);
+ return(0);
+ }
+ return(1);
+}
+
+/*
+ * gssk5_auth_reply -- checks the reply for mutual authentication.
+ */
+static int
+#ifdef CK_ANSIC
+gssk5_auth_reply(int how, unsigned char *data, int cnt)
+#else
+gssk5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ data += 4; /* Point to status byte */
+ cnt -=5;
+
+ switch (*data++) {
+ case GSS_REJECT:
+ if (cnt > 0) {
+ char *s;
+ int len;
+ ckstrncpy(strTmp,"GSSAPI refuses authentication because\r\n",
+ sizeof(strTmp));
+ len = strlen(strTmp);
+ if ( len + cnt < sizeof(strTmp) ) {
+ s = strTmp + strlen(strTmp);
+ memcpy(s, data, cnt); /* safe */
+ s[cnt] = 0;
+ }
+ } else
+ ckstrncpy(strTmp,"GSSAPI refuses authentication",
+ sizeof(strTmp));
+ printf("GSSAPI authentication failed!\r\n%s\r\n",strTmp);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+
+ case GSS_ACCEPT:
+ if ( cnt > 0 ) {
+ char *s;
+ int len;
+ ckstrncpy(strTmp,"GSSAPI accepts you as ",sizeof(strTmp));
+ len = strlen(strTmp);
+ if ( len + cnt < sizeof(strTmp) ) {
+ s = strTmp + strlen(strTmp);
+ memcpy(s,data,cnt);
+ s[cnt] = 0;
+ }
+ }
+ accept_complete = 1;
+ printf("%s\r\n",strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+
+ case GSS_RESPONSE:
+ gss_token_ptr = &gss_recv_tok;
+ gss_recv_tok.value = data;
+ gss_recv_tok.length = cnt;
+
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &gcontext,
+ gss_target_name,
+ gss_krb5_mech,
+ GSS_C_MUTUAL_FLAG |
+ GSS_C_REPLAY_FLAG |
+ (forward_flag ?
+ GSS_C_DELEG_FLAG : 0),
+ 0,
+ (krb5_d_no_addresses ? /* channel bindings */
+ GSS_C_NO_CHANNEL_BINDINGS :
+ &gss_chan),
+ gss_token_ptr,
+ NULL, /* ignore mech type */
+ &gss_send_tok,
+ NULL, /* ignore ret_flags */
+ NULL
+ ); /* ignore time_rec */
+
+ if ( maj_stat == GSS_S_COMPLETE )
+ {
+
+ } else if ( maj_stat == CSS_S_CONTINUE_NEEDED ) {
+ } else {
+ }
+
+ ckstrncpy(strTmp,"Remote machine has been mutually authenticated",
+ sizeof(strTmp));
+ printf("%s\r\n",strTmp);
+ auth_finished(AUTH_USER);
+ return AUTH_SUCCESS;
+
+ default:
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE; /* Unknown reply type */
+ }
+}
+
+/*
+ *
+ * gssk5_auth_is.
+ *
+ */
+
+static int
+#ifdef CK_ANSIC
+k5_auth_is(int how, unsigned char *data, int cnt)
+#else
+k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ int replied = 0;
+ gss_cred_id_t server_creds, deleg_creds;
+ gss_name_t client;
+ int ret_flags;
+ gss_buffer_desc name_buf;
+ gss_name_t server_name;
+ OM_uint32 acquire_maj,
+ acquire_min,
+ accept_maj,
+ accept_min,
+ stat_maj,
+ stat_min;
+ gss_OID mechid;
+ gss_buffer_desc tok, out_tok;
+ char gbuf[GSS_BUFSIZ];
+ u_char gout_buf[GSS_BUFSIZ];
+ char localname[MAXHOSTNAMELEN];
+ char service_name[MAXHOSTNAMELEN+10];
+ char **service;
+ struct hostent *hp;
+
+ data += 4; /* Point to status byte */
+ cnt -= 4;
+
+ ckhexdump("gssk5_auth_is data",data,cnt);
+ debug(F111,"gssk5_auth_is","how",how);
+
+ if (cnt-- < 1) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ switch (*data++) {
+ case GSS_AUTH:
+ gss_chan.initiator_addrtype = GSS_C_AF_INET;
+ gss_chan.initiator_address.length = 4;
+ gss_chan.initiator_address.value = &his_addr.sin_addr.s_addr;
+ gss_chan.acceptor_addrtype = GSS_C_AF_INET;
+ gss_chan.acceptor_address.length = 4;
+ gss_chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr;
+ gss_chan.application_data.length = 0;
+ gss_chan.application_data.value = 0;
+
+ tok.value = data;
+ tok.length = cnt;
+
+ if (gethostname(localname, MAXHOSTNAMELEN)) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ if (!(hp = gethostbyname(localname))) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+#ifdef HADDRLIST
+ hp = ck_copyhostent(hp);
+#endif /* HADDRLIST */
+ strncpy(localname, hp->h_name, sizeof(localname) - 1);
+ localname[sizeof(localname) - 1] = '\0';
+
+ sprintf(service_name, "%s@%s", *service, localname);
+ name_buf.value = service_name;
+ name_buf.length = strlen(name_buf.value) + 1;
+ stat_maj = gss_import_name(&stat_min, &name_buf,
+ gss_nt_service_name,
+ &server_name);
+ if (stat_maj != GSS_S_COMPLETE) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ acquire_maj = gss_acquire_cred(&acquire_min, server_name, 0,
+ GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+ &server_creds, NULL, NULL);
+ (void) gss_release_name(&stat_min, &server_name);
+
+ if (acquire_maj != GSS_S_COMPLETE) {
+ reply_gss_error(535, accept_maj, accept_min,
+ "accepting context");
+ syslog(LOG_ERR, "failed accepting context");
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG)
+ (void) gss_release_cred(&stat_min,
+ &deleg_creds);
+ return 0;
+ }
+
+ gcontext = GSS_C_NO_CONTEXT;
+ accept_maj = gss_accept_sec_context(&accept_min,
+ &gcontext, /* context_handle */
+ /* verifier_cred_handle */
+ server_creds,
+ &tok, /* input_token */
+ (krb5_d_no_addresses ?
+ /* channel bindings */
+ GSS_C_NO_CHANNEL_BINDINGS :
+ &gss_chan),
+ &client, /* src_name */
+ &mechid, /* mech_type */
+ &out_tok, /* output_token */
+ &ret_flags,
+ NULL, /* ignore time_rec */
+ /* forwarded credentials */
+ &deleg_creds
+ );
+
+ if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED) {
+ reply_gss_error(535, accept_maj, accept_min,
+ "accepting context");
+ syslog(LOG_ERR, "failed accepting context");
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG)
+ (void) gss_release_cred(&stat_min,
+ &deleg_creds);
+ return 0;
+ }
+
+ if (out_tok.length) {
+ if (kerror = radix_encode(out_tok.value,gbuf,&out_tok.length, 0)) {
+ secure_error("Couldn't encode ADAT reply (%s)",
+ radix_error(kerror));
+ syslog(LOG_ERR, "couldn't encode ADAT reply");
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG)
+ (void) gss_release_cred(&stat_min,
+ &deleg_creds);
+ return(0);
+ }
+ if (stat_maj == GSS_S_COMPLETE) {
+ reply(235, "ADAT=%s", gbuf);
+ replied = 1;
+ } else {
+ /* If the server accepts the security data, and
+ requires additional data, it should respond
+ with reply code 335. */
+ reply(335, "ADAT=%s", gbuf);
+ }
+ (void) gss_release_buffer(&stat_min, &out_tok);
+ }
+
+ if (stat_maj == GSS_S_COMPLETE) {
+ /* GSSAPI authentication succeeded */
+ stat_maj = gss_display_name(&stat_min, client,
+ &client_name, &mechid);
+ if (stat_maj != GSS_S_COMPLETE) {
+ /* "If the server rejects the security data (if
+ a checksum fails, for instance), it should
+ respond with reply code 535." */
+ reply_gss_error(535, stat_maj, stat_min,
+ "extracting GSSAPI identity name");
+ syslog(LOG_ERR, "gssapi error extracting identity");
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG)
+ (void) gss_release_cred(&stat_min,
+ &deleg_creds);
+ return 0;
+ }
+ auth_type = temp_auth_type;
+ temp_auth_type = NULL;
+
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG) {
+ if (want_creds)
+ ftpd_gss_convert_creds(client_name.value,
+ deleg_creds);
+ (void) gss_release_cred(&stat_min, &deleg_creds);
+ }
+
+ /* If the server accepts the security data, but does
+ not require any additional data (i.e., the security
+ data exchange has completed successfully), it must
+ respond with reply code 235. */
+ if (!replied)
+ {
+ if (ret_flags & GSS_C_DELEG_FLAG && !have_creds)
+ reply(235,
+ "GSSAPI Authentication succeeded, but could not accept forwarded credentials"
+ );
+ else
+ reply(235, "GSSAPI Authentication succeeded");
+ }
+ return(1);
+ } else if (stat_maj == GSS_S_CONTINUE_NEEDED) {
+ /* If the server accepts the security data, and
+ requires additional data, it should respond with
+ reply code 335. */
+ reply(335, "more data needed");
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG)
+ (void) gss_release_cred(&stat_min, &deleg_creds);
+ return(0);
+ } else {
+ /* "If the server rejects the security data (if
+ a checksum fails, for instance), it should
+ respond with reply code 535." */
+ reply_gss_error(535, stat_maj, stat_min,
+ "GSSAPI failed processing ADAT");
+ syslog(LOG_ERR, "GSSAPI failed processing ADAT");
+ (void) gss_release_cred(&stat_min, &server_creds);
+ if (ret_flags & GSS_C_DELEG_FLAG)
+ (void) gss_release_cred(&stat_min, &deleg_creds);
+ return(0);
+ }
+
+ debug(F100,"gssk5_auth_is AUTH_SUCCESS","",0);
+ krb5_errno = r;
+ if ( krb5_errno )
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ else
+ makestr(&krb5_errmsg,strTmp);
+ return AUTH_SUCCESS;
+
+ default:
+ printf("Unknown Kerberos option %d\r\n", data[-1]);
+ SendGSSK5AuthSB(GSS_REJECT, 0, 0);
+ break;
+ }
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+}
+#endif /* GSSAPI_KRB5 */
+
+#ifdef CK_SRP
+/*
+ * Copyright (c) 1997 Stanford University
+ *
+ * The use of this software for revenue-generating purposes may require a
+ * license from the owners of the underlying intellectual property.
+ * Specifically, the SRP-3 protocol may not be used for revenue-generating
+ * purposes without a license.
+ *
+ * NOTE: Columbia University has a license.
+ *
+ * Within that constraint, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notices and this permission
+ * notice appear in all copies of the software and related documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static void
+srp_encode_length(data, num)
+ unsigned char * data;
+ int num;
+{
+ *data = (num >> 8) & 0xff;
+ *++data = num & 0xff;
+}
+
+static int
+srp_decode_length(data)
+ unsigned char * data;
+{
+ return (((int) *data & 0xff) << 8) | (*(data + 1) & 0xff);
+}
+
+#ifdef PRE_SRP_1_7_3
+static int
+#ifdef CK_ANSIC
+srp_reply(int how, unsigned char *data, int cnt)
+#else
+srp_reply(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ struct t_num n;
+ struct t_num g;
+ struct t_num s;
+ struct t_num B;
+ struct t_num * A;
+ char type_check[26];
+ int pflag;
+
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#endif /* ENCRYPTION */
+
+ char * str=NULL;
+
+ data += 4; /* Point to status byte */
+ cnt -= 4;
+
+ if(cnt-- < 1) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ switch(*data++) {
+ case SRP_REJECT:
+ ckmakmsg(strTmp,sizeof(strTmp),
+ "SRP refuses authentication for '",szUserName,
+ "'\r\n",NULL);
+ if (cnt > 0) {
+ int len = strlen(strTmp);
+ if ( len + cnt < sizeof(strTmp) ) {
+ str = strTmp + strlen(strTmp);
+ memcpy(str,data,cnt);
+ str[cnt] = 0;
+ }
+ }
+ printf("SRP authentication failed!\r\n%s\r\n",strTmp);
+ if (tc != NULL) {
+ t_clientclose(tc);
+ tc = NULL;
+ }
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+
+ case SRP_ACCEPT:
+ if(cnt < RESPONSE_LEN || !srp_waitresp ||
+ tc == NULL
+ ) {
+ printf("SRP Protocol error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ srp_waitresp = 0;
+
+ if(t_clientverify(tc, data) == 0) {
+ printf("SRP accepts you as %s\r\n",szUserName);
+#ifdef CK_SSL
+ if((ssl_active_flag || tls_active_flag) &&
+ (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ printf("TLS session parameters verified by SRP\r\n");
+ } else
+#endif /* CK_SSL */
+
+#ifdef CK_ENCRYPTION
+ {
+ skey.type = SK_GENERIC;
+ skey.length = SESSION_KEY_LEN;
+ skey.data = tc->session_key;
+ encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
+ }
+#endif /* ENCRYPTION */
+ t_clientclose(tc);
+ tc = NULL;
+ accept_complete = 1;
+ auth_finished(AUTH_VALID);
+ return AUTH_SUCCESS;
+ } else {
+ printf("SRP server authentication failed!\r\n");
+ t_clientclose(tc);
+ tc = NULL;
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ break;
+
+ case SRP_PARAMS:
+ if(!szUserName) {
+ printf("No username available\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+ n.len = srp_decode_length(data);
+ data += 2;
+ cnt -= 2;
+ if(n.len > cnt) {
+ printf("n too long\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ n.data = data;
+ data += n.len;
+ cnt -= n.len;
+
+ g.len = srp_decode_length(data);
+ data += 2;
+ cnt -= 2;
+ if(g.len > cnt) {
+ printf("g too long\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ g.data = data;
+ data += g.len;
+ cnt -= g.len;
+
+ s.len = srp_decode_length(data);
+ data += 2;
+ cnt -= 2;
+ if(s.len > cnt) {
+ printf("salt too long\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ s.data = data;
+ data += s.len;
+ cnt -= s.len;
+
+ /* If the parameters provided by the server cannot be
+ * validated the following function will fail.
+ */
+ tc = t_clientopen(szUserName, &n, &g, &s);
+ if (tc == NULL) {
+ printf("SRP parameter initialization error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ A = t_clientgenexp(tc);
+ if(A == NULL) {
+ printf("SRP protocol error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ SendSRPAuthSB(SRP_EXP, A->data, A->len);
+
+ if ( pwbuf[0] && pwflg ) {
+ printf("SRP using %d-bit modulus for '%s'\r\n",
+ 8 * n.len,
+ szUserName
+ );
+ ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd));
+#ifdef OS2
+ if ( pwcrypt )
+ ck_encrypt((char *)srp_passwd);
+#endif /* OS2 */
+ } else {
+ extern char * srppwprompt;
+ char preface[128];
+ int ok;
+
+ if (srppwprompt && srppwprompt[0] &&
+ (strlen(srppwprompt) + strlen(szUserName) - 2) <
+ sizeof(preface)) {
+ sprintf(preface,srppwprompt,szUserName);
+ } else {
+ ckmakxmsg( preface,sizeof(preface),
+ "SRP using ",ckitoa(8*n.len),"-bit modulus for '",
+ szUserName, "'", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ }
+ ok = uq_txt( preface,"Password: ",2,NULL,
+ srp_passwd,sizeof(srp_passwd)-1,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if ( !ok )
+ srp_passwd[0] = '\0';
+ }
+
+ t_clientpasswd(tc, srp_passwd);
+ memset(srp_passwd, 0, sizeof(srp_passwd));
+ return AUTH_SUCCESS;
+
+ case SRP_CHALLENGE:
+ if(tc == NULL) {
+ printf("SRP protocol error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+#ifndef PRE_SRP_1_4_5
+ /*
+ * The original SRP AUTH implementation did not protect against
+ * tampering of the auth-type-pairs. Therefore, when the
+ * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
+ * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS
+ * is set we also insert the SSL/TLS client and server finished
+ * messages to ensure that there is no man in the middle attack
+ * underway on the SSL/TLS connection.
+ */
+ if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) {
+ type_check[0] = AUTHTYPE_SRP;
+ type_check[1] = how;
+#ifdef CK_SSL
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ t_clientaddexdata(tc,type_check,26);
+ } else
+#endif /* CK_SSL */
+ t_clientaddexdata(tc,type_check,2);
+ }
+#endif /* PRE_SRP_1_4_5 */
+
+ B.data = data;
+ B.len = cnt;
+ t_clientgetkey(tc, &B);
+
+ SendSRPAuthSB(SRP_RESPONSE, t_clientresponse(tc), RESPONSE_LEN);
+ srp_waitresp = 1;
+ return AUTH_SUCCESS;
+
+ default:
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ return AUTH_FAILURE;
+}
+
+static int
+#ifdef CK_ANSIC
+srp_is(int how, unsigned char *data, int cnt)
+#else
+srp_is(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ char * pbuf = NULL;
+ char * ptr;
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#endif
+ struct t_num A;
+ struct t_pw * tpw = NULL;
+ struct t_conf * tconf = NULL;
+ struct passwd * pass;
+ static struct t_num * B = NULL; /* Holder for B */
+#ifdef CK_SSL
+ char type_check[26];
+#else
+ char type_check[2];
+#endif /* CK_SSL */
+
+ if ((cnt -= 4) < 1) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ data += 4;
+ cnt -= 1;
+ switch(*data++) {
+ case SRP_AUTH:
+ /* Send parameters back to client */
+ if(ts != NULL) {
+ t_serverclose(ts);
+ ts = NULL;
+ }
+ if(!szUserNameRequested[0]) {
+ if (1)
+ printf("No username available\r\n");
+ SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && ckxanon &&
+ !strcmp(szUserNameRequested,"anonymous")) {
+ SendSRPAuthSB(SRP_REJECT, (void *)
+ "anonymous login cannot be performed with Secure Remote Password",
+ -1);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+#ifndef PRE_SRP_1_4_4
+ if(tpw == NULL) {
+ if((tpw = t_openpw(NULL)) == NULL) {
+ if (1)
+ printf("Unable to open password file\r\n");
+ SendSRPAuthSB(SRP_REJECT, (void *) "No password file", -1);
+ return(AUTH_FAILURE);
+ }
+ }
+ if(tconf == NULL) {
+ if((tconf = t_openconf(NULL)) == NULL) {
+ if (1)
+ printf("Unable to open configuration file\r\n");
+ SendSRPAuthSB(SRP_REJECT, (void *)"No configuration file", -1);
+ return(AUTH_FAILURE);
+ }
+ }
+ ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf);
+ t_closepw(tpw);
+ tpw = NULL;
+ t_closeconf(tconf);
+ tconf = NULL;
+#else /* PRE_SRP_1_4_4 */
+#ifdef COMMENT
+ /* the code in this block should no longer be necessary on OS/2
+ or Windows because I have added functionality to libsrp.lib
+ to find the srp files. 4/22/2000
+ */
+
+ /* On Windows and OS/2 there is no well defined place for the */
+ /* ETC directory. So we look for either an SRP_ETC or ETC */
+ /* environment variable in that order. If we find one we */
+ /* attempt to open the files manually. */
+ /* We will reuse the strTmp[] for the file names. */
+ ptr = getenv("SRP_ETC");
+ if ( !ptr )
+ ptr = getenv("ETC");
+#ifdef NT
+ if ( !ptr ) {
+ DWORD len;
+ len = AUTHTMPBL;
+
+ len = GetWindowsDirectory(strTmp,len);
+ if ( len > 0 && len < AUTHTMPBL) {
+ if ( !isWin95() ) {
+ if ( len == 1 )
+ ckstrncat(strTmp,"SYSTEM32/DRIVERS/ETC",sizeof(strTmp));
+ else
+ ckstrncat(strTmp,"/SYSTEM32/DRIVERS/ETC",sizeof(strTmp));
+ }
+ }
+ ptr = strTmp;
+ }
+#endif /* NT */
+ if ( ptr ) {
+ int len = strlen(ptr);
+ int i;
+ if (ptr != strTmp)
+ strcpy(strTmp,ptr);
+ for ( i=0;i<len;i++ ) {
+ if ( strTmp[i] == '\\' )
+ strTmp[i] = '/';
+ }
+ if ( strTmp[len-1] != '/' )
+ ckstrncat(strTmp,"/tpasswd",sizeof(strTmp));
+ else
+ ckstrncat(strTmp,"tpasswd",sizeof(strTmp));
+ tpw = t_openpwbyname(strTmp);
+
+ ckstrncat(strTmp,".conf",sizeof(strTmp));
+ tconf = t_openconfbyname(strTmp);
+ }
+
+ if ( tpw && tconf )
+ ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf);
+ else
+ ts = t_serveropen(szUserNameRequested);
+ if ( tpw ) {
+ t_closepw(tpw);
+ tpw = NULL;
+ }
+ if ( tconf ) {
+ t_closeconf(tconf);
+ tconf = NULL;
+ }
+#else /* COMMENT */
+ ts = t_serveropen(szUserNameRequested);
+#endif /* COMMENT */
+#endif /* PRE_SRP_1_4_4 */
+
+ if( ts == NULL ) {
+ printf("User %s not found\r\n", szUserNameRequested);
+ SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1);
+ return(AUTH_FAILURE);
+ }
+
+ pbuf = (char *)malloc(ts->n.len + ts->g.len + ts->s.len + 7);
+ ptr = pbuf;
+
+ srp_encode_length(ptr, ts->n.len);
+ ptr += 2;
+ memcpy(ptr, ts->n.data, ts->n.len); /* safe */
+ ptr += ts->n.len;
+
+ srp_encode_length(ptr, ts->g.len);
+ ptr += 2;
+ memcpy(ptr, ts->g.data, ts->g.len); /* safe */
+ ptr += ts->g.len;
+
+ srp_encode_length(ptr, ts->s.len);
+ ptr += 2;
+ memcpy(ptr, ts->s.data, ts->s.len); /* safe */
+ ptr += ts->s.len;
+
+ SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf);
+ free(pbuf); pbuf = NULL;
+
+ B = t_servergenexp(ts);
+ ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN);
+ return AUTH_SUCCESS;
+
+ case SRP_EXP:
+ /* Client is sending A to us, compute challenge & expected response. */
+ if (ts == NULL || B == NULL) {
+ printf("Protocol error: SRP_EXP unexpected\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Protocol error: unexpected EXP",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+
+ /* Wait until now to send B, since it contains the key to "u" */
+ SendSRPAuthSB(SRP_CHALLENGE, B->data, B->len);
+ B = NULL;
+
+#ifndef PRE_SRP_1_4_5
+ /*
+ * The original SRP AUTH implementation did not protect against
+ * tampering of the auth-type-pairs. Therefore, when the
+ * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
+ * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS
+ * is set we also insert the SSL/TLS client and server finished
+ * messages to ensure that there is no man in the middle attack
+ * underway on the SSL/TLS connection.
+ */
+ if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) {
+ type_check[0] = AUTHTYPE_SRP;
+ type_check[1] = how;
+#ifdef CK_SSL
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ }
+#endif /* CK_SSL */
+ t_serveraddexdata(ts,type_check,
+#ifdef CK_SSL
+ ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 :
+#endif /* CK_SSL */
+ 2);
+ }
+#endif /* PRE_SRP_1_4_5 */
+
+ A.data = data;
+ A.len = cnt;
+ ptr = t_servergetkey(ts, &A);
+
+ if(ptr == NULL) {
+ if (1)
+ printf("Security alert: Trivial session key attempted\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Trivial session key detected",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+ srp_waitresp = 1;
+ return AUTH_SUCCESS;
+
+ case SRP_RESPONSE:
+ /* Got the response; see if it's correct */
+ if (!srp_waitresp ||
+ ts == NULL
+ ) {
+ if (1)
+ printf("Protocol error: SRP_RESPONSE unexpected\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Protocol error: unexpected RESPONSE",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+ srp_waitresp = 0; /* we got a response */
+
+ if (cnt < RESPONSE_LEN) {
+ if (1)
+ printf("Protocol error: malformed response\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Protocol error: malformed response",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+
+ if (t_serververify(ts, data) == 0) {
+ SendSRPAuthSB(SRP_ACCEPT, t_serverresponse(ts), RESPONSE_LEN);
+ accept_complete = 1;
+#ifdef CK_ENCRYPTION
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ {
+ ckhexdump("SRP_RESPONSE ts",ts,sizeof(ts));
+ ckhexdump("SRP_RESPONSE session_key",
+ ts->session_key,
+ SESSION_KEY_LEN
+ );
+ skey.type = SK_GENERIC;
+ skey.length = SESSION_KEY_LEN;
+ skey.data = ts->session_key;
+ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+ }
+#endif /* CK_ENCRYPTION */
+ auth_finished(AUTH_VALID);
+ }
+ else {
+ SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+ return AUTH_SUCCESS;
+
+ default:
+ printf("Unknown SRP option %d\r\n", data[-1]);
+ SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1);
+ return(AUTH_FAILURE);
+ }
+}
+#else /* PRE_SRP_1_7_3 */
+static int
+#ifdef CK_ANSIC
+new_srp_reply(int how, unsigned char *data, int cnt)
+#else
+new_srp_reply(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ data += 4; /* Point to status byte */
+ cnt -= 4;
+
+ if(cnt-- < 1) { /* Matches with data++ */
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ switch(*data++) {
+ case SRP_PARAMS: {
+ struct t_num n;
+ struct t_num g;
+ struct t_num s;
+ cstr * A;
+
+ if(!szUserName) {
+ printf("No username available\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+ n.len = srp_decode_length(data);
+ data += 2;
+ cnt -= 2;
+ if(n.len > cnt) {
+ printf("n too long\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ n.data = data;
+ data += n.len;
+ cnt -= n.len;
+
+ g.len = srp_decode_length(data);
+ data += 2;
+ cnt -= 2;
+ if(g.len > cnt) {
+ printf("g too long\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ g.data = data;
+ data += g.len;
+ cnt -= g.len;
+
+ s.len = srp_decode_length(data);
+ data += 2;
+ cnt -= 2;
+ if(s.len != cnt) {
+ printf("invalid salt\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ s.data = data;
+ data += s.len;
+ cnt -= s.len;
+
+ /* If the parameters provided by the server cannot be
+ * validated the following function will fail.
+ */
+ c_srp = SRP_new(SRP_RFC2945_client_method());
+ if (c_srp == NULL ||
+ SRP_set_username(c_srp, szUserName) != SRP_SUCCESS ||
+ SRP_set_params(c_srp,n.data,n.len,g.data,g.len,s.data,s.len) !=
+ SRP_SUCCESS) {
+ printf("SRP Parameter initialization error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+ A = cstr_new();
+ if(SRP_gen_pub(c_srp, &A) != SRP_SUCCESS) {
+ printf("SRP Error generating key exchange\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+ SendSRPAuthSB(SRP_EXP, A->data, A->length);
+ cstr_free(A);
+
+ if ( pwbuf[0] && pwflg ) {
+ printf("SRP using %d-bit modulus for '%s'\r\n",
+ 8 * n.len,
+ szUserName
+ );
+ ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd));
+#ifdef OS2
+ if ( pwcrypt )
+ ck_encrypt((char *)srp_passwd);
+#endif /* OS2 */
+ } else {
+ extern char * srppwprompt;
+ char preface[128];
+ int ok;
+
+ if (srppwprompt && srppwprompt[0] &&
+ (strlen(srppwprompt) + strlen(szUserName) - 2) <
+ sizeof(preface)) {
+ sprintf(preface,srppwprompt,szUserName);
+ } else {
+ ckmakxmsg( preface,sizeof(preface),
+ "SRP using ",ckitoa(8*n.len),"-bit modulus for '",
+ szUserName, "'", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ }
+ ok = uq_txt(preface,"Password: ",2,NULL,
+ srp_passwd,sizeof(srp_passwd)-1,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if ( !ok )
+ srp_passwd[0] = '\0';
+ }
+
+ if(SRP_set_auth_password(c_srp, srp_passwd) != SRP_SUCCESS) {
+ memset(srp_passwd, 0, sizeof(srp_passwd));
+ printf("SRP Error setting client password\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ memset(srp_passwd, 0, sizeof(srp_passwd));
+ return AUTH_SUCCESS;
+ }
+ case SRP_CHALLENGE: {
+ char type_check[26];
+ cstr * resp = NULL;
+
+ if(c_srp == NULL) {
+ printf("SRP protocol error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+ /*
+ * The original SRP AUTH implementation did not protect against
+ * tampering of the auth-type-pairs. Therefore, when the
+ * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
+ * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS
+ * is set we also insert the SSL/TLS client and server finished
+ * messages to ensure that there is no man in the middle attack
+ * underway on the SSL/TLS connection.
+ */
+ if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) {
+ type_check[0] = AUTHTYPE_SRP;
+ type_check[1] = how;
+#ifdef CK_SSL
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ SRP_add_ex_data(c_srp, type_check, 26);
+ } else
+#endif /* CK_SSL */
+ SRP_add_ex_data(c_srp, type_check, 2);
+ }
+
+ if(SRP_compute_key(c_srp, &c_key, data, cnt) != SRP_SUCCESS) {
+ printf("SRP ERROR: unable to compute client key\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+
+ resp = cstr_new();
+ if(SRP_respond(c_srp, &resp) != SRP_SUCCESS) {
+ printf("SRP ERROR: unable to compute client response\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ SendSRPAuthSB(SRP_RESPONSE, resp->data, resp->length);
+ cstr_free(resp);
+ srp_waitresp = 1;
+ return AUTH_SUCCESS;
+ }
+ case SRP_ACCEPT: {
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#endif /* ENCRYPTION */
+
+ if(cnt < RESPONSE_LEN || !srp_waitresp || c_srp == NULL) {
+ printf("SRP Protocol error\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ srp_waitresp = 0;
+
+ if(SRP_verify(c_srp, data, cnt) == SRP_SUCCESS) {
+ printf("SRP accepts you as %s\r\n",szUserName);
+
+#ifdef CK_SSL
+ if((ssl_active_flag || tls_active_flag) &&
+ (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ printf("TLS session parameters verified by SRP\r\n");
+ } else
+#endif /* CK_SSL */
+#ifdef CK_ENCRYPTION
+ {
+ skey.type = SK_GENERIC;
+ skey.length = c_key->length;
+ skey.data = c_key->data;
+ encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER);
+ cstr_clear_free(c_key);
+ c_key = NULL;
+ }
+#endif /* CK_ENCRYPTION */
+ accept_complete = 1;
+ auth_finished(AUTH_VALID);
+ SRP_free(c_srp);
+ c_srp = NULL;
+ return AUTH_SUCCESS;
+ }
+ else {
+ printf("[ Error: SRP server authentication failed ]\r\n");
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ }
+ case SRP_REJECT: {
+ char * str=NULL;
+
+ ckmakmsg(strTmp,sizeof(strTmp),
+ "SRP refuses authentication for '",szUserName,
+ "'\r\n",NULL);
+ if (cnt > 0) {
+ int len = strlen(strTmp);
+ if ( len + cnt < sizeof(strTmp) ) {
+ str = strTmp + strlen(strTmp);
+ memcpy(str,data,cnt);
+ str[cnt] = 0;
+ }
+ }
+ printf("SRP authentication failed!\r\n%s\r\n",strTmp);
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+ default:
+ printf("Unknown SRP option %d\r\n", data[-1]);
+ return(auth_resend(AUTHTYPE_SRP));
+ }
+ /* NEVER REACHED */
+}
+
+static int
+#ifdef CK_ANSIC
+new_srp_is(int how, unsigned char *data, int cnt)
+#else
+new_srp_is(how,data,cnt) int how; unsigned char *data; int cnt;
+#endif
+{
+ char * pbuf = NULL;
+ char * ptr;
+#ifdef CK_ENCRYPTION
+ Session_Key skey;
+#endif
+ static cstr * B = NULL; /* Holder for B */
+ struct t_passwd * pass;
+ cstr * resp;
+ char type_check[26];
+
+ if ((cnt -= 4) < 1) {
+ auth_finished(AUTH_REJECT);
+ return AUTH_FAILURE;
+ }
+
+ data += 4;
+ cnt -= 1;
+ switch(*data++) {
+ case SRP_AUTH:
+ /* Send parameters back to client */
+ if(s_srp != NULL) {
+ SRP_free(s_srp);
+ s_srp = NULL;
+ }
+ if (B != NULL) {
+ cstr_free(B);
+ B = NULL;
+ }
+ if(!szUserNameRequested[0]) {
+ if (1)
+ printf("No username available\r\n");
+ SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && ckxanon &&
+ !strcmp(szUserNameRequested,"anonymous")) {
+ SendSRPAuthSB(SRP_REJECT, (void *)
+ "anonymous login cannot be performed with Secure Remote Password",
+ -1);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ s_srp = SRP_new(SRP_RFC2945_server_method());
+ if(s_srp == NULL) {
+ printf("Error initializing SRP server\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "SRP server init failed",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+ pass = gettpnam(szUserNameRequested);
+ if(pass == NULL) {
+ printf("User %s not found\r\n", szUserNameRequested);
+ SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1);
+ return(AUTH_FAILURE);
+ }
+ if(SRP_set_username(s_srp, szUserNameRequested) != SRP_SUCCESS ||
+ SRP_set_params(s_srp, pass->tc.modulus.data,
+ pass->tc.modulus.len,
+ pass->tc.generator.data,
+ pass->tc.generator.len,
+ pass->tp.salt.data,
+ pass->tp.salt.len) != SRP_SUCCESS ||
+ SRP_set_authenticator(s_srp,
+ pass->tp.password.data,
+ pass->tp.password.len) != SRP_SUCCESS) {
+ printf("Error initializing SRP parameters\r\n");
+ SendSRPAuthSB(SRP_REJECT,(void *)"SRP parameter init failed", -1);
+ return(AUTH_FAILURE);
+ }
+
+ pbuf = (char *)malloc(pass->tc.modulus.len + pass->tc.generator.len +
+ pass->tp.salt.len + 7);
+ ptr = pbuf;
+
+ srp_encode_length(ptr, pass->tc.modulus.len);
+ ptr += 2;
+ memcpy(ptr, pass->tc.modulus.data, pass->tc.modulus.len);
+ ptr += pass->tc.modulus.len;
+
+ srp_encode_length(ptr, pass->tc.generator.len);
+ ptr += 2;
+ memcpy(ptr, pass->tc.generator.data, pass->tc.generator.len);
+ ptr += pass->tc.generator.len;
+
+ srp_encode_length(ptr, pass->tp.salt.len);
+ ptr += 2;
+ memcpy(ptr, pass->tp.salt.data, pass->tp.salt.len);
+ ptr += pass->tp.salt.len;
+
+ SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf);
+ free(pbuf);
+ pbuf = NULL;
+
+ if(SRP_gen_pub(s_srp, &B) != SRP_SUCCESS) {
+ printf("Error generating SRP public value\r\n");
+ SendSRPAuthSB(SRP_REJECT, (void *) "SRP_gen_pub failed", -1);
+ return(AUTH_FAILURE);
+ }
+ ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN);
+ return AUTH_SUCCESS;
+
+ case SRP_EXP:
+ /* Client is sending A to us, compute challenge and expected response. */
+ if (s_srp == NULL || B == NULL) {
+ printf("Protocol error: SRP_EXP unexpected\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *)"Protocol error: unexpected EXP", -1);
+ return(AUTH_FAILURE);
+ }
+ /* Wait until now to send B, since it contains the key to "u" */
+ SendSRPAuthSB(SRP_CHALLENGE, B->data, B->length);
+ cstr_free(B);
+ B = NULL;
+
+ /*
+ * The original SRP AUTH implementation did not protect against
+ * tampering of the auth-type-pairs. Therefore, when the
+ * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted
+ * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS
+ * is set we also insert the SSL/TLS client and server finished
+ * messages to ensure that there is no man in the middle attack
+ * underway on the SSL/TLS connection.
+ */
+ if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) {
+ type_check[0] = AUTHTYPE_SRP;
+ type_check[1] = how;
+#ifdef CK_SSL
+ if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) {
+ ssl_get_client_finished(&type_check[2],12);
+ ssl_get_server_finished(&type_check[14],12);
+ SRP_add_ex_data(s_srp, type_check, 26);
+ } else
+#endif /* CK_SSL */
+ SRP_add_ex_data(s_srp, type_check, 2);
+ }
+
+ if(SRP_compute_key(s_srp, &s_key, data, cnt) != SRP_SUCCESS) {
+ printf("Security alert: Trivial session key attempted\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Trivial session key detected", -1);
+ return(AUTH_FAILURE);
+ }
+ srp_waitresp = 1;
+ return AUTH_SUCCESS;
+
+ case SRP_RESPONSE:
+ /* Got the response; see if it's correct */
+ if (!srp_waitresp || s_srp == NULL) {
+ if (1)
+ printf("Protocol error: SRP_RESPONSE unexpected\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Protocol error: unexpected RESPONSE",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+ srp_waitresp = 0; /* we got a response */
+
+ if (cnt < RESPONSE_LEN) {
+ if (1)
+ printf("Protocol error: malformed response\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Protocol error: malformed response",
+ -1
+ );
+ return(AUTH_FAILURE);
+ }
+
+ if(SRP_verify(s_srp, data, cnt) == SRP_SUCCESS) {
+ resp = cstr_new();
+ if(SRP_respond(s_srp, &resp) != SRP_SUCCESS) {
+ printf("Error computing response\r\n");
+ SendSRPAuthSB(SRP_REJECT,
+ (void *) "Error computing response", -1);
+ return(AUTH_FAILURE);
+ }
+ SendSRPAuthSB(SRP_ACCEPT, resp->data, resp->length);
+ accept_complete = 1;
+ cstr_free(resp);
+
+#ifdef CK_ENCRYPTION
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ {
+ skey.type = SK_GENERIC;
+ skey.length = s_key->length;
+ skey.data = s_key->data;
+ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+ cstr_clear_free(s_key);
+ s_key = NULL;
+ }
+#endif /* CK_ENCRYPTION */
+ auth_finished(AUTH_VALID);
+ }
+ else {
+ SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1);
+ auth_finished(AUTH_REJECT);
+ return(AUTH_FAILURE);
+ }
+ return AUTH_SUCCESS;
+
+ default:
+ printf("Unknown SRP option %d\r\n", data[-1]);
+ SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1);
+ return(AUTH_FAILURE);
+ }
+}
+#endif /* PRE_SRP_1_7_3 */
+#endif /* SRP */
+
+#ifdef KRB5
+#ifdef KINIT
+/*
+ * clients/kinit/kinit.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Initialize a credentials cache.
+ */
+
+#define KRB5_DEFAULT_OPTIONS 0
+#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
+
+static krb5_data tgtname = {
+#ifndef HEIMDAL
+ 0,
+#endif /* HEIMDAL */
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME
+};
+
+/* Internal prototypes */
+_PROTOTYP(static krb5_error_code krb5_validate_tgt,
+ (krb5_context, krb5_ccache,krb5_principal, krb5_data *));
+_PROTOTYP(static krb5_error_code krb5_renew_tgt,
+ (krb5_context, krb5_ccache,
+ krb5_principal, krb5_data *));
+_PROTOTYP(static krb5_error_code krb5_tgt_gen,
+ (krb5_context, krb5_ccache,
+ krb5_principal, krb5_data *, int opt));
+
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+static krb5_error_code KRB5_CALLCONV
+ck_krb5_prompter( krb5_context context,
+ void *data,
+ const char *name,
+ const char *banner,
+ int num_prompts,
+ krb5_prompt prompts[])
+{
+ krb5_error_code errcode = 0;
+ int i;
+#ifdef KUI
+ struct txtbox * tb = NULL;
+#else /* KUI */
+ char * prompt = NULL;
+#endif /* KUI */
+ int len = 0, blen=0, nlen=0;
+
+ debug(F110,"ck_krb5_prompter name",name,0);
+ debug(F110,"ck_krb5_prompter banner",banner,0);
+ debug(F101,"ck_krb5_prompter num_prompts","",num_prompts);
+
+ if (name)
+ nlen = strlen(name)+2;
+
+ if (banner)
+ blen = strlen(banner)+2;
+
+#ifdef KUI
+ tb = (struct txtbox *) malloc(sizeof(struct txtbox) * num_prompts);
+ if ( tb != NULL ) {
+ int ok;
+ memset(tb,0,sizeof(struct txtbox) * num_prompts);
+ for ( i=0; i < num_prompts; i++ ) {
+ tb[i].t_buf = prompts[i].reply->data;
+ tb[i].t_len = prompts[i].reply->length;
+ tb[i].t_lbl = prompts[i].prompt;
+ tb[i].t_dflt = NULL;
+ tb[i].t_echo = (prompts[i].hidden ? 2 : 1);
+ }
+
+ ok = uq_mtxt((char *)banner,NULL,num_prompts,tb);
+ if ( ok ) {
+ for ( i=0; i < num_prompts; i++ )
+ prompts[i].reply->length = strlen(prompts[i].reply->data);
+ } else
+ errcode = -2;
+ }
+#else /* KUI */
+ for (i = 0; i < num_prompts; i++) {
+ debug(F111,"ck_krb5_prompter prompt",prompts[i].prompt,i);
+
+ if ( prompt && len < (nlen + blen + strlen(prompts[i].prompt)+2) ) {
+ free(prompt);
+ prompt = NULL;
+ }
+ if ( !prompt )
+ prompt = (char *)malloc(nlen + blen + strlen(prompts[i].prompt)+2);
+ if ( !prompt ) {
+ errcode = KRB5_RC_MALLOC;
+ goto cleanup;
+ }
+ len = nlen + blen + strlen(prompts[i].prompt)+2;
+ ckmakxmsg(prompt,len,
+ (char *) (name?name:""),
+ name?"\r\n":"",
+ (char *) (banner?banner:""),
+ banner?"\r\n":"",
+ (char *)prompts[i].prompt,
+ ": ",NULL,NULL,NULL,NULL,NULL,NULL);
+
+ memset(prompts[i].reply->data, 0, prompts[i].reply->length);
+ if (prompts[i].hidden) {
+ readpass(prompt, prompts[i].reply->data,
+ prompts[i].reply->length);
+ } else {
+ readtext(prompt, prompts[i].reply->data,
+ prompts[i].reply->length);
+ }
+ prompts[i].reply->length = strlen(prompts[i].reply->data);
+ }
+#endif /* KUI */
+
+ cleanup:
+#ifdef KUI
+ if ( tb )
+ free(tb);
+#else /* KUI */
+ if ( prompt )
+ free(prompt);
+#endif /* KUI */
+ if (errcode) {
+ for (i = 0; i < num_prompts; i++) {
+ memset(prompts[i].reply->data, 0, prompts[i].reply->length);
+ }
+ }
+ return errcode;
+}
+
+/*
+ * I'm not really sure what to do with this. The NRL DLLs use a
+ * different interface for the krb5_prompter callback. It has
+ * one less parameter. This is going to be ugly.
+ */
+static krb5_error_code KRB5_CALLCONV
+ck_NRL_krb5_prompter( krb5_context context,
+ const char *name,
+ const char *banner,
+ int num_prompts,
+ krb5_prompt prompts[])
+{
+ return(ck_krb5_prompter(context,NULL,name,banner,num_prompts,prompts));
+}
+#endif /* KRB5_HAVE_GET_INIT_CREDS */
+
+#ifdef KRB524_CONV
+long
+try_convert524(krb5_context ctx, krb5_principal me, krb5_ccache cc)
+{
+ char * progname = "convert524";
+ krb5_error_code code = 0;
+ int icode = 0;
+ krb5_principal kpcserver = 0;
+ krb5_creds *v5creds = 0;
+ krb5_creds increds;
+#ifdef OS2
+ LEASH_CREDENTIALS v4creds;
+#else /* OS2 */
+ CREDENTIALS v4creds;
+#endif /* OS2 */
+
+ memset((char *) &increds, 0, sizeof(increds));
+ /*
+ From this point on, we can goto cleanup because increds is
+ initialized.
+ */
+
+ if ((code = krb5_build_principal(ctx,
+ &kpcserver,
+ krb5_princ_realm(ctx, me)->length,
+ krb5_princ_realm(ctx, me)->data,
+ "krbtgt",
+ krb5_princ_realm(ctx, me)->data,
+ NULL))) {
+ com_err(progname, code,
+ "while creating service principal name");
+ goto cleanup;
+ }
+
+ memset((char*) &increds, 0, sizeof(increds));
+ increds.client = me;
+ increds.server = kpcserver;
+ /* Prevent duplicate free calls. */
+ kpcserver = 0;
+
+ increds.times.endtime = 0;
+ increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+ if ((code = krb5_get_credentials(ctx, 0,
+ cc,
+ &increds,
+ &v5creds))) {
+ com_err(progname, code,
+ "getting V5 credentials");
+ goto cleanup;
+ }
+ if ((icode = krb524_convert_creds_kdc(ctx,
+ v5creds,
+ &v4creds))) {
+ com_err(progname, icode,
+ "converting to V4 credentials");
+ goto cleanup;
+ }
+ /* this is stolen from the v4 kinit */
+ /* initialize ticket cache */
+ if ((icode = krb_in_tkt(v4creds.pname, v4creds.pinst, v4creds.realm)
+ != KSUCCESS)) {
+ com_err(progname, icode,
+ "trying to create the V4 ticket file");
+ goto cleanup;
+ }
+ /* stash ticket, session key, etc. for future use */
+ if ((icode = krb_save_credentials(v4creds.service,
+ v4creds.instance,
+ v4creds.realm,
+ v4creds.session,
+ v4creds.lifetime,
+ v4creds.kvno,
+ &(v4creds.ticket_st),
+ v4creds.issue_date))) {
+ com_err(progname, icode,
+ "trying to save the V4 ticket");
+ goto cleanup;
+ }
+
+ cleanup:
+ memset(&v4creds, 0, sizeof(v4creds));
+ if (v5creds)
+ krb5_free_creds(ctx, v5creds);
+ increds.client = 0;
+ krb5_free_cred_contents(ctx, &increds);
+ if (kpcserver)
+ krb5_free_principal(ctx, kpcserver);
+ return !(code || icode);
+}
+#endif /* KRB524_CONV */
+
+#define NO_KEYTAB
+
+int
+#ifdef CK_ANSIC
+ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init,
+ struct krb4_init_data * k4_init)
+#else
+ck_krb5_initTGT(op,init,k4_init)
+ krb_op_data * op; struct krb5_init_data * init;
+ struct krb4_init_data * k4_init;
+#endif /* CK_ANSIC*/
+{
+ krb5_context kcontext;
+ krb5_ccache ccache = NULL;
+ krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */
+ krb5_timestamp starttime = 0;
+ krb5_deltat rlife = 0;
+ int options = KRB5_DEFAULT_OPTIONS;
+ int option;
+ int errflg = 0;
+ krb5_error_code code;
+ krb5_principal me=NULL;
+ krb5_principal server=NULL;
+ krb5_creds my_creds;
+ krb5_timestamp now;
+#ifndef HEIMDAL
+ krb5_address **addrs = (krb5_address **)0;
+#endif /* HEIMDAL */
+ int addr_count=0;
+ int i,j;
+#ifndef NO_KEYTAB
+ int use_keytab = 0; /* -k option */
+ krb5_keytab keytab = NULL;
+#endif /* NO_KEYTAB */
+ struct passwd *pw = 0;
+ int pwsize;
+ char *client_name=NULL, principal[256]="", realm[256]="", numstr[40]="";
+ char *password=NULL, passwd[80]="";
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ krb5_get_init_creds_opt opts;
+#endif
+ char * name;
+ int len;
+
+ if ( !ck_krb5_is_installed() )
+ return(-1);
+
+#ifdef COMMENT
+ printf("Kerberos V initialization\r\n");
+#endif /* COMMENT */
+
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ com_err("krb5_kinit",code,"while init_context");
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ debug(F110,"krb5_init","krb5_init_context",0);
+
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ com_err("krb5_kinit",code,"while getting time of day");
+ goto exit_k5_init;
+ }
+
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ memset(&opts, 0, sizeof(opts));
+ krb5_get_init_creds_opt_init(&opts);
+ debug(F110,"krb5_init","krb5_get_init_creds_opt_init",0);
+#endif
+
+ if ( init->renewable ) {
+ options |= KDC_OPT_RENEWABLE;
+ ckmakmsg(numstr,sizeof(numstr),ckitoa(init->renewable),"m",NULL,NULL);
+#ifdef HEIMDAL
+ code = -1;
+#else /* HEIMDAL */
+ code = krb5_string_to_deltat(numstr, &rlife);
+#endif /* HEIMDAL */
+ if (code != 0 || rlife == 0) {
+ printf("Bad renewable time value %s\r\n", numstr);
+ errflg++;
+ }
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
+#endif
+ }
+ if ( init->renew ) {
+ /* renew the ticket */
+ options |= KDC_OPT_RENEW;
+ }
+
+ if ( init->validate ) {
+ /* validate the ticket */
+ options |= KDC_OPT_VALIDATE;
+ }
+ if ( init->proxiable ) {
+ options |= KDC_OPT_PROXIABLE;
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ krb5_get_init_creds_opt_set_proxiable(&opts, 1);
+#endif
+ }
+ if ( init->forwardable ) {
+ options |= KDC_OPT_FORWARDABLE;
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ krb5_get_init_creds_opt_set_forwardable(&opts, 1);
+#endif
+ }
+#ifndef NO_KEYTAB
+ if ( ) {
+ use_keytab = 1;
+ }
+ if ( ) {
+ if (keytab == NULL && keytab_name != NULL) {
+ code = krb5_kt_resolve(kcontext, keytab_name, &keytab);
+ if (code != 0) {
+ debug(F111,"krb5_init resolving keytab",
+ keytab_name,code);
+ errflg++;
+ }
+ }
+ }
+#endif /* NO_KEYTAB */
+ if ( init->lifetime ) {
+ ckmakmsg(numstr,sizeof(numstr),ckitoa(init->lifetime),"m",NULL,NULL);
+#ifdef HEIMDAL
+ code = -1;
+#else /* HEIMDAL */
+ code = krb5_string_to_deltat(numstr, &lifetime);
+#endif /* HEIMDAL */
+ if (code != 0 || lifetime == 0) {
+ printf("Bad lifetime value %s\r\n", numstr);
+ errflg++;
+ }
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
+#endif
+ }
+ if ( init->postdate ) {
+ /* Convert cmdate() to a time_t value */
+ struct tm * time_tm;
+ struct tm * cmdate2tm(char *,int);
+ time_tm = cmdate2tm(init->postdate,0);
+ if ( time_tm )
+ starttime = (krb5_timestamp) mktime(time_tm);
+
+ if (code != 0 || starttime == 0 || starttime == -1) {
+ krb5_deltat ktmp;
+#ifdef HEIMDAL
+ code = -1;
+#else /* HEIMDAL */
+ code = krb5_string_to_deltat(init->postdate, &ktmp);
+#endif /* HEIMDAL */
+ if (code == 0 && ktmp != 0) {
+ starttime = now + ktmp;
+ options |= KDC_OPT_POSTDATED;
+ } else {
+ printf("Bad postdate start time value %s\r\n",
+ init->postdate);
+ errflg++;
+ }
+ } else {
+ options |= KDC_OPT_POSTDATED;
+ }
+ }
+
+ debug(F110,"krb5_init searching for ccache",op->cache,0);
+
+ code = k5_get_ccache(kcontext,&ccache,op->cache);
+ if (code != 0) {
+ com_err("krb5_kinit",code,"while getting default ccache");
+ goto exit_k5_init;
+ }
+
+ /* This is our realm unless it is changed */
+ ckstrncpy(realm,init->realm ? init->realm : krb5_d_realm, 256);
+
+#ifdef BETATEST
+ /* This code is going to take the realm and attempt to correct */
+ /* the case. */
+ {
+ profile_t profile;
+
+ code = krb5_get_profile(kcontext, &profile);
+ if ( !code ) {
+ const char *names[4];
+ char ** realms;
+ int found = 0;
+
+ names[0] = "realms";
+ names[1] = NULL;
+
+ code = profile_get_subsection_names(profile,names,&realms);
+ if ( code == 0 ) {
+ int i=0;
+ while ( realms[i] ) {
+ if (ckstrcmp(realm,realms[i],-1,0) == 0) {
+ strcpy(realm,realms[i]);
+ found = 1;
+ break;
+ }
+ i++;
+ }
+ }
+
+#ifdef CK_DNS_SRV
+ if ( !found ) {
+ char * dns_realm = NULL;
+
+ /* We did not find the realm in the profile so let's try DNS */
+ locate_txt_rr("_kerberos",realm,&dns_realm);
+ if ( dns_realm &&
+ ckstrcmp(realm,dns_realm,-1,0) == 0 &&
+ ckstrcmp(realm,dns_realm,-1,1) != 0
+ ) {
+ ckstrncpy(realm,dns_realm,256);
+ free(dns_realm);
+ }
+ }
+#endif /* CK_DNS_SRV */
+ }
+
+ if (init->realm &&
+ ckstrcmp(realm,init->realm,-1,0) == 0 &&
+ ckstrcmp(realm,init->realm,-1,1) != 0)
+ strcpy(init->realm,realm);
+ if (ckstrcmp(realm,krb5_d_realm,-1,0) == 0 &&
+ ckstrcmp(realm,krb5_d_realm,-1,1) != 0)
+ strcpy(krb5_d_realm,realm);
+ }
+#endif /* BETATEST */
+
+ if (init->principal == NULL) { /* No principal name specified */
+#ifndef NO_KEYTAB
+ if (use_keytab) {
+ /* Use the default host/service name */
+ code = krb5_sname_to_principal(kcontext, NULL, NULL,
+ KRB5_NT_SRV_HST, &me);
+ if (code == 0 &&
+ krb5_princ_realm(kcontext, me)->length < sizeof(realm))
+ {
+ /* Save the realm */
+ memcpy(realm,krb5_princ_realm(kcontext, me)->data,
+ krb5_princ_realm(kcontext, me)->length); /* safe */
+ realm[krb5_princ_realm(kcontext, me)->length]='\0';
+ } else {
+ com_err("krb5_kinit",
+ code,
+ "when creating default server principal name");
+ goto exit_k5_init;
+ }
+ } else
+#endif /* NO_KEYTAB */
+ {
+ int len;
+ char * name;
+
+ /* Get default principal from cache if one exists */
+ code = krb5_cc_get_principal(kcontext, ccache, &me);
+#ifdef HEIMDAL
+ name = me->realm;
+ len = strlen(name);
+#else /* HEIMDAL */
+ len = krb5_princ_realm(kcontext, me)->length;
+ name = krb5_princ_realm(kcontext, me)->data;
+#endif /* HEIMDAL */
+ if (code == 0 && len < sizeof(realm))
+ {
+ /* Save the realm */
+ memcpy(realm,name,len); /* safe */
+ realm[len]='\0';
+ } else {
+#ifdef HAVE_PWD_H
+ /* Else search passwd file for client */
+
+ pw = getpwuid((int) getuid());
+ if (pw) {
+ char princ_realm[256];
+ if ( (strlen(pw->pw_name) + strlen(realm) + 1) > 255 )
+ goto exit_k5_init;
+
+ ckstrncpy(principal,pw->pw_name,256);
+ ckstrncpy(princ_realm,pw->pw_name,256);
+ ckstrncat(princ_realm,"@",256);
+ ckstrncat(princ_realm,realm,256);
+
+ if ((code = krb5_parse_name(kcontext,princ_realm,&me))) {
+ krb5_errno = code;
+ com_err("krb5_kinit",code,"when parsing name",
+ princ_realm);
+ goto exit_k5_init;
+ }
+ } else {
+ printf(
+ "Unable to identify user from password file\r\n");
+ goto exit_k5_init;
+ }
+#else /* HAVE_PWD_H */
+ printf("Unable to identify user\r\n");
+ goto exit_k5_init;
+#endif /* HAVE_PWD_H */
+ }
+ }
+
+#ifdef HEIMDAL
+ len = me->name.name_string.len;
+ name = *me->name.name_string.val;
+#else /* HEIMDAL */
+ len = krb5_princ_name(kcontext, me)->length;
+ name = krb5_princ_name(kcontext, me)->data;
+#endif /* HEIMDAL */
+ if ( len < sizeof(principal) ) {
+ memcpy(principal,name,len); /* safe */
+ principal[len]='\0';
+ }
+ } /* Use specified name */
+ else {
+ char princ_realm[256];
+ if ( (strlen(init->principal) +
+ (init->instance ? strlen(init->instance)+1 : 0) +
+ strlen(realm)
+ + 2) > 255 )
+ goto exit_k5_init;
+
+ ckstrncpy(principal,init->principal,256);
+ ckstrncpy(princ_realm,init->principal,256);
+ if (init->instance) {
+ ckstrncat(princ_realm,"/",256);
+ ckstrncat(princ_realm,init->instance,256);
+ }
+ if (realm[0]) {
+ ckstrncat(princ_realm,"@",256);
+ ckstrncat(princ_realm,realm,256);
+ }
+ if ((code = krb5_parse_name (kcontext, princ_realm, &me))) {
+ com_err("krb5_kinit",code,"when parsing name",princ_realm);
+ goto exit_k5_init;
+ }
+ }
+
+ if ((code = krb5_unparse_name(kcontext, me, &client_name))) {
+ com_err("krb5_kinit",code,"when unparsing name");
+ goto exit_k5_init;
+ }
+ debug(F110,"krb5_init client_name",client_name,0);
+
+
+ memset((char *)&my_creds, 0, sizeof(my_creds));
+ my_creds.client = me;
+
+ if (init->service == NULL) {
+ if ((code =
+ krb5_build_principal_ext(kcontext,
+ &server,
+ strlen(realm),realm,
+ tgtname.length, tgtname.data,
+ strlen(realm),realm,
+ 0))) {
+ com_err("krb5_kinit",code,"while building server name");
+ goto exit_k5_init;
+ }
+ } else {
+ if (code = krb5_parse_name(kcontext, init->service, &server)) {
+ com_err("krb5_kinit",code,"while parsing service name",
+ init->service);
+ goto exit_k5_init;
+ }
+ }
+
+ my_creds.server = server;
+
+ if (options & KDC_OPT_POSTDATED) {
+ my_creds.times.starttime = starttime;
+ my_creds.times.endtime = starttime + lifetime;
+ } else {
+ my_creds.times.starttime = 0; /* start timer when request
+ gets to KDC */
+ my_creds.times.endtime = now + lifetime;
+ }
+ if (options & KDC_OPT_RENEWABLE) {
+ my_creds.times.renew_till = now + rlife;
+ } else
+ my_creds.times.renew_till = 0;
+
+ if (options & KDC_OPT_VALIDATE) {
+ krb5_data outbuf;
+
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ code = krb5_get_validated_creds(kcontext,
+ &my_creds, me, ccache, init->service);
+ if ( code == -1 )
+#endif
+ {
+#ifdef HEIMDAL
+ printf("?validate not implemented\r\n");
+ code = -1;
+ goto exit_k5_init;
+#else /* HEIMDAL */
+ code = krb5_validate_tgt(kcontext, ccache, server, &outbuf);
+#endif /* HEIMDAL */
+ }
+ if (code) {
+ com_err("krb5_kinit",code,"validating tgt");
+ goto exit_k5_init;
+ }
+ /* should be done... */
+ goto exit_k5_init;
+ }
+
+ if (options & KDC_OPT_RENEW) {
+ krb5_data outbuf;
+
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ code = krb5_get_renewed_creds(kcontext,
+ &my_creds, me, ccache, init->service);
+ if ( code == -1 )
+#endif
+ {
+#ifdef HEIMDAL
+ printf("?renew not implemented\r\n");
+ code = -1;
+ goto exit_k5_init;
+#else /* HEIMDAL */
+ code = krb5_renew_tgt(kcontext, ccache, server, &outbuf);
+#endif /* HEIMDAL */
+ }
+ if (code) {
+ com_err("krb5_kinit",code,"while renewing tgt");
+ goto exit_k5_init;
+ }
+ /* should be done... */
+ goto store_cred;
+ }
+
+#ifndef HEIMDAL
+ if ( init->addrs && !init->no_addresses ) {
+ /* construct an array of krb5_address structs to pass to get_in_tkt */
+ /* include both the local ip addresses as well as any other that */
+ /* are specified. */
+ unsigned long ipaddr;
+
+ for ( addr_count=0;addr_count<KRB5_NUM_OF_ADDRS;addr_count++ )
+ if ( init->addrs[addr_count] == NULL )
+ break;
+
+ if (addr_count > 0) {
+ krb5_address ** local_addrs=NULL;
+ krb5_os_localaddr(kcontext, &local_addrs);
+ i = 0;
+ while ( local_addrs[i] )
+ i++;
+ addr_count += i;
+
+ addrs = (krb5_address **)
+ malloc((addr_count+1) * sizeof(krb5_address *));
+ if ( !addrs ) {
+ krb5_free_addresses(kcontext, local_addrs);
+ goto exit_k5_init;
+ }
+ memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
+ i = 0;
+ while ( local_addrs[i] ) {
+ addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
+ if (addrs[i] == NULL) {
+ krb5_free_addresses(kcontext, local_addrs);
+ goto exit_k5_init;
+ }
+
+ addrs[i]->magic = local_addrs[i]->magic;
+ addrs[i]->addrtype = local_addrs[i]->addrtype;
+ addrs[i]->length = local_addrs[i]->length;
+ addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
+ if (!addrs[i]->contents) {
+ krb5_free_addresses(kcontext, local_addrs);
+ goto exit_k5_init;
+ }
+
+ memcpy(addrs[i]->contents,local_addrs[i]->contents,
+ local_addrs[i]->length); /* safe */
+ i++;
+ }
+ krb5_free_addresses(kcontext, local_addrs);
+
+ for ( j=0;i<addr_count;i++,j++ ) {
+ addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
+ if (addrs[i] == NULL)
+ goto exit_k5_init;
+
+ addrs[i]->magic = KV5M_ADDRESS;
+ addrs[i]->addrtype = AF_INET;
+ addrs[i]->length = 4;
+ addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
+ if (!addrs[i]->contents)
+ goto exit_k5_init;
+
+ ipaddr = inet_addr(init->addrs[j]);
+ memcpy(addrs[i]->contents,&ipaddr,4); /* safe */
+ }
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ krb5_get_init_creds_opt_set_address_list(&opts,addrs);
+#endif
+ }
+ }
+#endif /* !HEIMDAL */
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ if ( init->no_addresses )
+ krb5_get_init_creds_opt_set_address_list(&opts,NULL);
+#endif
+
+#ifndef NO_KEYTAB
+ if (!use_keytab)
+#endif
+ {
+ if ( init->password ) {
+ pwsize = strlen(init->password);
+ if ( pwsize )
+ password = init->password;
+ } else if (init->getk4 && k4_init) {
+ /* When we are requesting that K4 tickets be automatically */
+ /* acquired when K5 tickets are acquired, we must get the */
+ /* password up front. */
+ char prmpt[256];
+ extern char * k5prprompt;
+ extern char * k5pwprompt;
+ int ok = 0;
+
+ if ( k5pwprompt && k5pwprompt[0] &&
+ (strlen(k5pwprompt) + strlen(principal) +
+ strlen(realm) - 4) < sizeof(prmpt)) {
+ sprintf(prmpt,k5pwprompt,principal,realm);
+ } else
+ ckmakxmsg(prmpt,sizeof(prmpt),
+ k5pwprompt && k5pwprompt[0] ? k5pwprompt :
+ "Kerberos 5 Password for ",
+ principal,"@",realm,": ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT);
+ if ( ok )
+ password = passwd;
+
+ if ( k4_init->password == NULL )
+ makestr(&k4_init->password,passwd);
+ }
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ debug(F100,"krb5_init calling krb5_get_init_creds_password()","",0);
+#ifdef OS2
+ if ( is_NRL_KRB5() )
+ code = krb5_get_init_creds_password(kcontext, &my_creds, me,
+ password,
+ (void *)ck_NRL_krb5_prompter,
+ NULL,
+ starttime, init->service,
+ &opts);
+ else
+#endif /* OS2 */
+ code = krb5_get_init_creds_password(kcontext, &my_creds, me,
+ password,
+ ck_krb5_prompter,
+ NULL,
+ starttime, init->service,
+ &opts);
+ debug(F111,"krb5_init","krb5_get_init_creds_password()",code);
+
+ if ( code == -1 )
+ {
+ if (!password) {
+ char prmpt[256];
+ int ok;
+
+ ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ",
+ client_name,": ",NULL);
+ ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,
+ DEFAULT_UQ_TIMEOUT);
+ if ( ok )
+ password = passwd;
+ else {
+ code = -2;
+ goto exit_k5_init;
+ }
+ }
+
+ if ( !password )
+ password = "";
+ code = krb5_get_in_tkt_with_password(kcontext, options,
+#ifdef HEIMDAL
+ NULL,
+#else /* HEIMDAL */
+ init->no_addresses ? NULL :addrs,
+#endif /* HEIMDAL */
+ NULL, NULL,
+ password,
+ NULL, &my_creds, NULL);
+ if ( code )
+ debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code);
+ }
+#else /* KRB5_HAVE_GET_INIT_CREDS */
+ if (!password) {
+ char prmpt[256];
+ int ok;
+
+ ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ",
+ client_name,": ",NULL);
+ ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT);
+ if ( ok )
+ password = passwd;
+ else {
+ code = -2;
+ goto exit_k5_init;
+ }
+ }
+ if ( !password )
+ password = "";
+ code = krb5_get_in_tkt_with_password(kcontext, options,
+#ifdef HEIMDAL
+ NULL,
+#else /* HEIMDAL */
+ init->no_addresses ? NULL :addrs,
+#endif /* HEIMDAL */
+ NULL, NULL,
+ password,
+ NULL, &my_creds, NULL);
+ if ( code )
+ debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code);
+#endif /* KRB5_HAVE_GET_INIT_CREDS */
+
+ if ( init->password && pwsize > 0 )
+ memset(init->password, 0, pwsize);
+ memset(passwd,0,80);
+ }
+#ifndef NO_KEYTAB
+ else {
+#ifdef KRB5_HAVE_GET_INIT_CREDS
+ code = krb5_get_init_creds_keytab(kcontext, &my_creds, me, keytab,
+ starttime, init->service,
+ &opts);
+#ifdef OS2
+ if ( code == -1)
+ code = krb5_get_in_tkt_with_keytab(kcontext, options,
+ init->no_addresses ? NULL :addrs,
+ NULL, NULL, keytab, NULL,
+ &my_creds, 0);
+#endif /* OS2 */
+#else /* KRB5_HAVE_GET_INIT_CREDS */
+ code = krb5_get_in_tkt_with_keytab(kcontext, options,
+#ifdef HEIMDAL
+ NULL,
+#else /* HEIMDAL */
+ init->no_addresses ? NULL :addrs,
+#endif /* HEIMDAL */
+ NULL, NULL, keytab, NULL,
+ &my_creds, 0);
+#endif /* KRB5_HAVE_GET_INIT_CREDS */
+ }
+#endif
+
+ if (code) {
+ switch (code) {
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ printf("Password incorrect\r\n");
+ goto exit_k5_init;
+ case KRB5KRB_AP_ERR_V4_REPLY:
+ if (init->getk4 && k4_init) {
+ printf("Kerberos 5 Tickets not support by server. ");
+ printf("A version 4 Ticket will be requested.\r\n");
+ }
+ goto exit_k5_init;
+ default:
+ goto exit_k5_init;
+ }
+ }
+
+ store_cred:
+ debug(F100,"krb5_init calling krb5_cc_initialize()","",0);
+
+ code = krb5_cc_initialize (kcontext, ccache, me);
+ if ( code == KRB5_CC_BADNAME ) {
+ /* This is a really ugly hack that should not have to be here.
+ * krb5_cc_initialize should not fail with an error if the
+ * cache already exists. The reason the problem is occuring
+ * is that the krb5 library is no longer calling cc_destroy()
+ * when cc_initialize() is called and the CCAPI implementation
+ * on Windows has not yet been corrected to handle it. To
+ * ensure that K95 will continue to work with both we will call
+ * cc_destroy() if the cc_initialize() call fails with a BADNAME
+ * error. If the cc_destroy() is successful, we will try again.
+ */
+
+ debug(F100,"krb5_init calling krb5_cc_destroy()","",0);
+ code = krb5_cc_destroy (kcontext, ccache);
+ if ( !code ) {
+ debug(F100,"krb5_init calling k5_get_ccache()","",0);
+ code = k5_get_ccache(kcontext,&ccache,op->cache);
+ debug(F100,"krb5_init calling krb5_cc_initialize()","",0);
+ code = krb5_cc_initialize (kcontext, ccache, me);
+ } else
+ code = KRB5_CC_BADNAME;
+ }
+ if (code) {
+ com_err("krb5_kinit",code,"when initializing cache",op->cache);
+ goto exit_k5_init;
+ }
+
+ debug(F100,"krb5_init calling krb5_cc_store_cred()","",0);
+ code = krb5_cc_store_cred(kcontext, ccache, &my_creds);
+ if (code) {
+ com_err("krb5_kinit",code,"while storing credentials");
+ goto exit_k5_init;
+ }
+
+ if ( init->getk4 &&
+#ifdef KRB524_CONV
+ !try_convert524(kcontext,me,ccache) &&
+#endif /* KRB524_CONV */
+ k4_init ) {
+ int k4rc = ck_krb4_initTGT(op,k4_init);
+ if (k4rc < 0)
+ code = -3;
+ }
+
+exit_k5_init:
+ debug(F100,"krb5_init exit_k5_init","",0);
+
+#ifndef HEIMDAL
+ /* Free krb5_address structures if we created them */
+ if ( addrs ) {
+ for ( i=0;i<addr_count;i++ ) {
+ if ( addrs[i] ) {
+ if ( addrs[i]->contents )
+ free(addrs[i]->contents);
+ free(addrs[i]);
+ }
+ }
+ }
+#endif /* HEIMDAL */
+
+
+ krb5_errno = code;
+ makestr(&krb5_errmsg,krb5_errno ? error_message(krb5_errno) : "OK");
+
+ if (client_name)
+ krb5_free_unparsed_name(kcontext, client_name);
+
+ /* my_creds is pointing at server */
+ debug(F100,"krb5_init calling krb5_free_principal()","",0);
+ krb5_free_principal(kcontext, server);
+ debug(F100,"krb5_init calling krb5_cc_close()","",0);
+ krb5_cc_close(kcontext,ccache);
+ debug(F100,"krb5_init calling krb5_free_context()","",0);
+ krb5_free_context(kcontext);
+
+ if (code != -2)
+ printf("Result from realm %s: %s\r\n",realm,
+ code==-3?"Unable to retrieve Kerberos IV credentials":
+ code?error_message(code):"OK");
+ return(code?-1:0);
+}
+
+#ifndef HEIMDAL
+#define VALIDATE 0
+#define RENEW 1
+
+/* stripped down version of krb5_mk_req */
+static krb5_error_code
+#ifdef CK_ANSIC
+krb5_validate_tgt( krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal server, /* tgtname */
+ krb5_data *outbuf )
+#else
+krb5_validate_tgt(context, ccache, server, outbuf)
+ krb5_context context;
+ krb5_ccache ccache;
+ krb5_principal server; /* tgtname */
+ krb5_data *outbuf;
+#endif
+{
+ return krb5_tgt_gen(context, ccache, server, outbuf, VALIDATE);
+}
+
+/* stripped down version of krb5_mk_req */
+static krb5_error_code
+#ifdef CK_ANSIC
+krb5_renew_tgt(krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal server, /* tgtname */
+ krb5_data *outbuf)
+#else
+krb5_renew_tgt(context, ccache, server, outbuf)
+ krb5_context context;
+ krb5_ccache ccache;
+ krb5_principal server; /* tgtname */
+ krb5_data *outbuf;
+#endif
+{
+ return krb5_tgt_gen(context, ccache, server, outbuf, RENEW);
+}
+
+
+/* stripped down version of krb5_mk_req */
+static krb5_error_code
+#ifdef CK_ANSIC
+krb5_tgt_gen(krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal server, /* tgtname */
+ krb5_data *outbuf,
+ int opt)
+#else
+krb5_tgt_gen(context, ccache, server, outbuf, opt)
+ krb5_context context;
+ krb5_ccache ccache;
+ krb5_principal server; /* tgtname */
+ krb5_data *outbuf;
+ int opt;
+#endif
+{
+ krb5_error_code retval;
+ krb5_creds * credsp;
+ krb5_creds creds;
+
+ /* obtain ticket & session key */
+ memset((char *)&creds, 0, sizeof(creds));
+ if ((retval = krb5_copy_principal(context, server, &creds.server)))
+ goto cleanup;
+
+ if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
+ goto cleanup_creds;
+
+ if (opt == VALIDATE) {
+ if ((retval = krb5_get_credentials_validate(context, 0,
+ ccache, &creds, &credsp)))
+ goto cleanup_creds;
+ } else {
+ if ((retval = krb5_get_credentials_renew(context, 0,
+ ccache, &creds, &credsp)))
+ goto cleanup_creds;
+ }
+
+ /* we don't actually need to do the mk_req, just get the creds. */
+cleanup_creds:
+ krb5_free_cred_contents(context, &creds);
+
+cleanup:
+
+ return retval;
+}
+#endif /* HEIMDAL */
+#endif /* KINIT */
+#ifdef KDESTROY
+int
+#ifdef CK_ANSIC
+ck_krb5_destroy(struct krb_op_data * op)
+#else
+ck_krb5_destroy(op) struct krb_op_data * op;
+#endif
+{
+ krb5_context kcontext;
+ krb5_error_code retval;
+ int c;
+ krb5_ccache ccache = NULL;
+ char *cache_name = NULL;
+ int code;
+ int errflg=0;
+ int quiet = 0;
+
+ if ( !ck_krb5_is_installed() )
+ return(-1);
+
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ debug(F101,"ck_krb5_destroy while initializing krb5","",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ code = k5_get_ccache(kcontext,&ccache,op->cache);
+ if (code != 0) {
+ debug(F101,"ck_krb5_destroy while getting ccache",
+ "",code);
+ krb5_free_context(kcontext);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ code = krb5_cc_destroy (kcontext, ccache);
+ if (code != 0) {
+ debug(F101,"ck_krb5_destroy while destroying cache","",code);
+ if ( code == KRB5_FCC_NOFILE )
+ printf("No ticket cache to destroy.\r\n");
+ else
+ printf("Ticket cache NOT destroyed!\r\n");
+ krb5_cc_close(kcontext,ccache);
+ krb5_free_context(kcontext);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ printf("Tickets destroyed.\r\n");
+ /* Do not call krb5_cc_close() because cache has been destroyed */
+ krb5_free_context(kcontext);
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,"OK");
+ return (0);
+}
+#else /* KDESTROY */
+#ifdef KRB5
+int
+#ifdef CK_ANSIC
+ck_krb5_destroy(struct krb_op_data * op)
+#else
+ck_krb5_destroy(op) struct krb_op_data * op;
+#endif
+{
+ printf("?Not implemented.\r\n");
+ return(-1);
+}
+#endif /* KRB5 */
+#endif /* KDESTROY */
+#ifndef KLIST
+#ifdef KRB5
+int
+#ifdef CK_ANSIC
+ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc)
+#else
+ck_krb5_list_creds(op,lc)
+ struct krb_op_data * op; struct krb5_list_cred_data * lc;
+#endif
+{
+ printf("?Not implemented.\r\n");
+ return(-1);
+}
+#endif /* KRB5 */
+#else /* KLIST */
+static int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
+static int show_etype = 0, show_addr = 0;
+static char *defname;
+static char *progname;
+static krb5_int32 now;
+static int timestamp_width;
+
+_PROTOTYP(static char * etype_string, (krb5_enctype ));
+_PROTOTYP(static void show_credential,(krb5_context,krb5_creds *));
+_PROTOTYP(static int do_ccache, (krb5_context,char *));
+_PROTOTYP(static int do_keytab, (krb5_context,char *));
+_PROTOTYP(static void printtime, (time_t));
+_PROTOTYP(static void fillit, (int, int));
+
+#define DEFAULT 0
+#define CCACHE 1
+#define KEYTAB 2
+
+int
+#ifdef CK_ANSIC
+ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc)
+#else
+ck_krb5_list_creds(op,lc)
+ struct krb_op_data * op; struct krb5_list_cred_data * lc;
+#endif
+{
+ krb5_context kcontext;
+ krb5_error_code retval;
+ int code;
+ char *name = op->cache;
+ int mode;
+
+ if ( !ck_krb5_is_installed() )
+ return(-1);
+
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ debug(F101,"ck_krb5_list_creds while initializing krb5","",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ name = op->cache;
+ mode = DEFAULT;
+ show_flags = 0;
+ show_time = 0;
+ status_only = 0;
+ show_keys = 0;
+ show_etype = 0;
+ show_addr = 0;
+
+ show_flags = lc->flags;
+ show_etype = lc->encryption;
+ show_addr = lc->addr;
+ show_time = 1;
+ show_keys = 1;
+ mode = CCACHE;
+
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ if (!status_only)
+ debug(F101,"ck_krb5_list_creds while getting time of day.",
+ "",code);
+ krb5_free_context(kcontext);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+ else {
+ char tmp[BUFSIZ];
+
+ if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) ||
+ !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), (char *) NULL))
+ timestamp_width = (int) strlen(tmp);
+ else
+ timestamp_width = 15;
+ }
+
+ if (mode == DEFAULT || mode == CCACHE)
+ retval = do_ccache(kcontext,name);
+ else
+ retval = do_keytab(kcontext,name);
+ krb5_free_context(kcontext);
+ return(retval);
+}
+
+static int
+#ifdef CK_ANSIC
+do_keytab(krb5_context kcontext, char * name)
+#else
+do_keytab(kcontext,name) krb5_context kcontext; char * name;
+#endif
+{
+ krb5_keytab kt;
+ krb5_keytab_entry entry;
+ krb5_kt_cursor cursor;
+ char buf[BUFSIZ]; /* hopefully large enough for any type */
+ char *pname;
+ int code = 0;
+
+ if (name == NULL) {
+ if ((code = krb5_kt_default(kcontext, &kt))) {
+ debug(F101,"ck_krb5_list_creds while getting default keytab",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+ } else {
+ if ((code = krb5_kt_resolve(kcontext, name, &kt))) {
+ debug(F111,"ck_krb5_list_creds while resolving keytab",
+ name,code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+ }
+
+ if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) {
+ debug(F101,"ck_krb5_list_creds while getting keytab name",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ printf("Keytab name: %s\r\n", buf);
+
+ if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
+ debug(F101,"ck_krb5_list_creds while starting keytab scan",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ if (show_time) {
+ printf("KVNO Timestamp");
+ fillit(timestamp_width - sizeof("Timestamp") + 2, (int) ' ');
+ printf("Principal\r\n");
+ printf("---- ");
+ fillit(timestamp_width, (int) '-');
+ printf(" ");
+ fillit(78 - timestamp_width - sizeof("KVNO"), (int) '-');
+ printf("\r\n");
+ } else {
+ printf("KVNO Principal\r\n");
+ printf(
+"---- --------------------------------------------------------------------\
+------\r\n");
+ }
+
+ while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
+ if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
+ debug(F101,"ck_krb5_list_creds while unparsing principal name",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+ printf("%4d ", entry.vno);
+ if (show_time) {
+ printtime(entry.timestamp);
+ printf(" ");
+ }
+ printf("%s", pname);
+ if (show_etype)
+ printf(" (%s) " ,
+#ifdef HEIMDAL
+ etype_string(entry.key.keytype)
+#else /* HEIMDAL */
+ etype_string(entry.key.enctype)
+#endif /* HEIMDAL */
+ );
+ if (show_keys) {
+ printf(" (0x");
+ {
+ int i;
+ for (i = 0; i < entry.key.length; i++)
+ printf("%02x",
+#ifdef HEIMDAL
+ entry.key.keyvalue[i]
+#else /* HEIMDAL */
+ entry.key.contents[i]
+#endif /* HEIMDAL */
+ );
+ }
+ printf(")");
+ }
+ printf("\r\n");
+ krb5_free_unparsed_name(kcontext,pname);
+ }
+ if (code && code != KRB5_KT_END) {
+ debug(F101,"ck_krb5_list_creds while scanning keytab",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+ if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) {
+ debug(F101,"ck_krb5_list_creds while ending keytab scan",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,"OK");
+ return(0);
+}
+
+static int
+#ifdef CK_ANSIC
+do_ccache(krb5_context kcontext, char * cc_name)
+#else
+do_ccache(kcontext,name) krb5_context kcontext; char * cc_name;
+#endif
+{
+ krb5_ccache cache = NULL;
+ krb5_cc_cursor cur;
+ krb5_creds creds;
+ krb5_principal princ=NULL;
+ krb5_flags flags=0;
+ krb5_error_code code = 0;
+ int exit_status = 0;
+
+ if (status_only)
+ /* exit_status is set back to 0 if a valid tgt is found */
+ exit_status = 1;
+
+ code = k5_get_ccache(kcontext,&cache,cc_name);
+ if (code != 0) {
+ debug(F111,"do_ccache while getting ccache",
+ error_message(code),code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return(-1);
+ }
+
+ flags = 0; /* turns off OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ if (code == ENOENT) {
+ debug(F111,"ck_krb5_list_creds (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ } else {
+ debug(F111,
+ "ck_krb5_list_creds while setting cache flags (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ }
+ printf("No ticket File.\r\n");
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
+ debug(F101,"ck_krb5_list_creds while retrieving principal name",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
+ debug(F101,"ck_krb5_list_creds while unparsing principal name",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ if (!status_only) {
+ printf("Ticket cache: %s:%s\r\nDefault principal: %s\r\n\r\n",
+ krb5_cc_get_type(kcontext, cache),
+ krb5_cc_get_name(kcontext, cache), defname);
+ printf("Valid starting");
+ fillit(timestamp_width - sizeof("Valid starting") + 3,
+ (int) ' ');
+ printf("Expires");
+ fillit(timestamp_width - sizeof("Expires") + 3,
+ (int) ' ');
+ printf("Service principal\r\n");
+ }
+ if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_list_creds while starting to retrieve tickets",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+ if (status_only) {
+ if (exit_status && creds.server->length == 2 &&
+ strcmp(creds.server->realm.data, princ->realm.data) == 0 &&
+ strcmp((char *)creds.server->data[0].data, "krbtgt") == 0 &&
+ strcmp((char *)creds.server->data[1].data,
+ princ->realm.data) == 0 &&
+ creds.times.endtime > now)
+ exit_status = 0;
+ } else {
+ show_credential(kcontext, &creds);
+ }
+ krb5_free_cred_contents(kcontext, &creds);
+ }
+ printf("\r\n");
+ if (code == KRB5_CC_END || code == KRB5_CC_NOTFOUND) {
+ if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_list_creds while finishing ticket retrieval",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ debug(F101,"ck_krb5_list_creds while closing ccache",
+ "",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,"OK");
+ krb5_cc_close(kcontext,cache);
+ return(0);
+ } else {
+ debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code);
+ krb5_errno = code;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ krb5_cc_close(kcontext,cache);
+ return(-1);
+ }
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,"OK");
+ krb5_cc_close(kcontext,cache);
+ return(0);
+}
+
+static char *
+#ifdef CK_ANSIC
+#ifdef HEIMDAL
+etype_string(krb5_keytype enctype)
+#else /* HEIMDAL */
+etype_string(krb5_enctype enctype)
+#endif /* HEIMDAL */
+#else
+#ifdef HEIMDAL
+etype_string(enctype) krb5_keytype enctype;
+#else /* HEIMDAL */
+etype_string(enctype) krb5_enctype enctype;
+#endif /* HEIMDAL */
+#endif
+{
+ static char buf[12];
+
+ switch (enctype) {
+ case ENCTYPE_NULL:
+ return "NULL";
+ case ENCTYPE_DES_CBC_CRC:
+ return "DES-CBC-CRC";
+ case ENCTYPE_DES_CBC_MD4:
+ return "DES-CBC-MD4";
+ case ENCTYPE_DES_CBC_MD5:
+ return "DES-CBC-MD5";
+ case ENCTYPE_DES_CBC_RAW:
+ return "DES-CBC-RAW";
+ case ENCTYPE_DES3_CBC_SHA:
+ return "DES3-CBC-SHA";
+ case ENCTYPE_DES3_CBC_RAW:
+ return "DES3-CBC-RAW";
+ case ENCTYPE_DES_HMAC_SHA1:
+ return "DES-HMAC-SHA1";
+ case ENCTYPE_DES3_CBC_SHA1:
+ return "DES3-CBC-SHA1";
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ return "AES128_CTS-HMAC-SHA1_96";
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return "AES256_CTS-HMAC-SHA1_96";
+ case ENCTYPE_ARCFOUR_HMAC:
+ return "RC4-HMAC-NT";
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ return "RC4-HMAC-NT-EXP";
+ case ENCTYPE_UNKNOWN:
+ return "UNKNOWN";
+ case ENCTYPE_LOCAL_DES3_HMAC_SHA1:
+ return "LOCAL-DES3-HMAC-SHA1";
+ case ENCTYPE_LOCAL_RC4_MD4:
+ return "LOCAL-RC4-MD4";
+ default:
+ ckmakmsg(buf, sizeof(buf),"etype ", ckitoa(enctype),NULL,NULL);
+ return buf;
+ break;
+ }
+}
+
+static char *
+#ifdef CK_ANSIC
+flags_string(register krb5_creds *cred)
+#else
+flags_string(cred) register krb5_creds *cred;
+#endif
+{
+ static char buf[32];
+ int i = 0;
+
+ if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
+ buf[i++] = 'F';
+ if (cred->ticket_flags & TKT_FLG_FORWARDED)
+ buf[i++] = 'f';
+ if (cred->ticket_flags & TKT_FLG_PROXIABLE)
+ buf[i++] = 'P';
+ if (cred->ticket_flags & TKT_FLG_PROXY)
+ buf[i++] = 'p';
+ if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
+ buf[i++] = 'D';
+ if (cred->ticket_flags & TKT_FLG_POSTDATED)
+ buf[i++] = 'd';
+ if (cred->ticket_flags & TKT_FLG_INVALID)
+ buf[i++] = 'i';
+ if (cred->ticket_flags & TKT_FLG_RENEWABLE)
+ buf[i++] = 'R';
+ if (cred->ticket_flags & TKT_FLG_INITIAL)
+ buf[i++] = 'I';
+ if (cred->ticket_flags & TKT_FLG_HW_AUTH)
+ buf[i++] = 'H';
+ if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
+ buf[i++] = 'A';
+ buf[i] = '\0';
+ return(buf);
+}
+
+static char *
+#ifdef CK_ANSIC
+short_date(long *dp)
+#else
+short_date(dp) long *dp;
+#endif
+{
+ register char *cp;
+#ifndef ctime
+ extern char *ctime();
+#endif /* ctime */
+ cp = ctime(dp) + 4;
+ cp[15] = '\0';
+ return (cp);
+}
+
+
+static VOID
+#ifdef CK_ANSIC
+printtime(time_t tv)
+#else
+printtime(tv) time_t tv;
+#endif
+{
+ char timestring[BUFSIZ];
+ char format[12];
+ char fill;
+
+ fill = ' ';
+ sprintf(format,"%%-%ds",timestamp_width); /* safe */
+ if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv,
+ timestring,
+ timestamp_width+1,
+ &fill)) {
+ printf(format,timestring);
+ }
+ else {
+ printf(format,short_date(&tv));
+ }
+
+}
+
+static void
+#ifdef CK_ANSIC
+one_addr(krb5_address *a)
+#else
+one_addr(a) krb5_address *a;
+#endif
+{
+ struct hostent *h;
+ extern tcp_rdns;
+
+ if ((a->addrtype == ADDRTYPE_INET) &&
+ (a->length == 4)) {
+ if (tcp_rdns != SET_OFF) {
+ h = gethostbyaddr(a->contents, 4, AF_INET);
+ if (h) {
+#ifdef HADDRLIST
+ h = ck_copyhostent(h);
+#endif /* HADDRLIST */
+ printf("%s (%d.%d.%d.%d)", h->h_name,
+ a->contents[0], a->contents[1],
+ a->contents[2], a->contents[3]);
+ }
+ }
+ if (tcp_rdns == SET_OFF || !h) {
+ printf("%d.%d.%d.%d", a->contents[0], a->contents[1],
+ a->contents[2], a->contents[3]);
+ }
+ } else {
+ printf("unknown addr type %d", a->addrtype);
+ }
+}
+
+static VOID
+#ifdef CK_ANSIC
+show_credential(krb5_context kcontext, register krb5_creds * cred)
+#else
+show_credential(kcontext, cred)
+ krb5_context kcontext;
+ register krb5_creds * cred;
+#endif
+{
+ krb5_error_code retval=0;
+ krb5_ticket *tkt=NULL;
+ char *name=NULL, *sname=NULL, *flags=NULL;
+ int extra_field = 0;
+
+ retval = krb5_unparse_name(kcontext, cred->client, &name);
+ if (retval) {
+ debug(F101,"ck_krb5_list_creds while unparsing client name","",retval);
+ krb5_errno = retval;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return;
+ }
+ retval = krb5_unparse_name(kcontext, cred->server, &sname);
+ if (retval) {
+ debug(F101,"ck_krb5_list_creds while unparsing server name","",retval);
+ free(name);
+ krb5_errno = retval;
+ makestr(&krb5_errmsg,error_message(krb5_errno));
+ return;
+ }
+ if (!cred->times.starttime)
+ cred->times.starttime = cred->times.authtime;
+
+ printtime(cred->times.starttime);
+ printf(" ");
+
+ if ( time(0) < cred->times.endtime )
+ printtime(cred->times.endtime);
+ else
+ printf("** expired ** ");
+
+ printf(" %s\r\n", sname);
+
+ if (strcmp(name, defname)) {
+ printf(" for client %s", name);
+ extra_field++;
+ }
+
+ if (cred->times.renew_till) {
+ if (!extra_field)
+ printf(" ");
+ else
+ printf(", ");
+ printf("renew until ");
+ printtime(cred->times.renew_till);
+ extra_field += 2;
+ }
+
+ if (extra_field > 3) {
+ printf("\r\n");
+ extra_field = 0;
+ }
+
+ if (show_flags) {
+ flags = flags_string(cred);
+ if (flags && *flags) {
+ if (!extra_field)
+ printf(" ");
+ else
+ printf(", ");
+ printf("Flags: %s", flags);
+ extra_field++;
+ }
+ }
+
+ if (extra_field > 2) {
+ printf("\r\n");
+ extra_field = 0;
+ }
+
+ if (show_etype) {
+ retval = decode_krb5_ticket(&cred->ticket, &tkt);
+ if (!extra_field)
+ printf(" ");
+ else
+ printf(", ");
+#ifdef HEIMDAL
+ printf("Etype (skey, tkt): %s, %s ",
+ etype_string(cred->session.keytype),
+ etype_string(tkt->enc_part.keytype));
+#else /* HEIMDAL */
+ printf("Etype (skey, tkt): %s, %s ",
+ etype_string(cred->keyblock.enctype),
+ etype_string(tkt->enc_part.enctype));
+#endif /* HEIMDAL */
+ krb5_free_ticket(kcontext, tkt);
+ extra_field++;
+ }
+
+ /* if any additional info was printed, extra_field is non-zero */
+ if (extra_field)
+ printf("\r\n");
+
+ if ( show_addr ) {
+ if (!cred->addresses || !cred->addresses[0]) {
+ printf("\tAddresses: (none)\r\n");
+ } else {
+ int i;
+ for (i=0; cred->addresses[i]; i++) {
+ if (i)
+ printf(" ");
+ else
+ printf(" Addresses: ");
+ one_addr(cred->addresses[i]);
+ printf("\r\n");
+ }
+ }
+ }
+
+ krb5_free_unparsed_name(kcontext,name);
+ krb5_free_unparsed_name(kcontext,sname);
+
+ krb5_errno = 0;
+ makestr(&krb5_errmsg,"OK");
+}
+
+static VOID
+#ifdef CK_ANSIC
+fillit(int num, int c)
+#else
+fillit(num, c) int num; int c;
+#endif
+{
+ int i;
+
+ for (i=0; i<num; i++)
+ printf("%c",c);
+}
+#endif /* KLIST */
+#endif /* KRB5 */
+
+#ifdef KRB4
+#define KDEBUG 1
+int k4debug = 0; /* Kerberos 4 runtime debugging */
+
+#ifdef KINIT
+#define KRB_DEFAULT_LIFE 120 /* 10 hours in 5 minute intervals */
+
+#ifdef SNK4
+/* SNK4 is a hardware authentication system used to pre-authenticate */
+/* a ticket getting ticket. We do not support this code at the present */
+/* time in Kermit. */
+void
+get_input(s, size, stream)
+char *s;
+int size;
+FILE *stream;
+{
+ char *p;
+
+ if (fgets(s, size, stream) == NULL)
+ exit(1);
+ if ( (p = strchr(s, '\n')) != NULL)
+ *p = '\0';
+}
+#endif /* SNK4 */
+
+#ifdef COMMENT
+static char
+#ifdef CK_ANSIC
+hex_scan_nybble(char c)
+#else
+hex_scan_nybble(c) char c;
+#endif
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+/* returns: NULL for ok, pointer to error string for bad input */
+static char*
+#ifdef CK_ANSIC
+hex_scan_four_bytes(char *out, char *in)
+#else
+hex_scan_four_bytes(out, in) char *out; char *in;
+#endif
+{
+ int i;
+ int c;
+ char c1;
+ for (i=0; i<8; i++) {
+ if(!in[i])
+ return "not enough input";
+ c = hex_scan_nybble(in[i]);
+ if(c<0)
+ return "invalid digit";
+ c1 = c;
+ i++;
+ if(!in[i])
+ return "not enough input";
+ c = hex_scan_nybble(in[i]);
+ if(c<0)
+ return "invalid digit";
+ *out++ = (c1 << 4) + c;
+ }
+ switch(in[i]) {
+ case 0:
+ case '\r':
+ case '\n':
+ return NULL;
+ default:
+ return "extra characters at end of input";
+ }
+}
+#endif /* COMMENT */
+
+/* ck_krb4_initTGT() returns 0 on success */
+int
+#ifdef CK_ANSIC
+ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init)
+#else
+ck_krb4_initTGT(op,init)
+ struct krb_op_data * op, struct krb4_init_data * init
+#endif
+{
+ char aname[ANAME_SZ+1];
+ char inst[INST_SZ+1];
+ char realm[REALM_SZ+1];
+ char *password=NULL;
+ char passwd[80]="";
+ char *username = NULL;
+ char *usernameptr=NULL;
+ int iflag, /* Instance */
+ rflag, /* Realm */
+ vflag, /* Verbose */
+ lflag, /* Lifetime */
+ pflag, /* Preauth */
+ lifetime=KRB_DEFAULT_LIFE, /* Life Time */
+ k_errno;
+ register char *cp;
+ register i;
+
+ if ( !ck_krb4_is_installed() )
+ return(-1);
+
+ *inst = *realm = '\0';
+ iflag = rflag = vflag = lflag = pflag = 0;
+
+ vflag = init->verbose;
+ pflag = init->preauth;
+
+ if ( init->lifetime ) {
+ lifetime = init->lifetime<5?1:init->lifetime/5;
+ if ( lifetime > 255 ) lifetime = 255;
+ }
+ else
+ lifetime = KRB_DEFAULT_LIFE;
+
+ username = init->principal;
+
+ if (username && username[0] &&
+ (k_errno = kname_parse(aname, inst, realm, username))
+ != AUTH_SUCCESS) {
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ printf("%s\r\n", krb_get_err_text_entry(k_errno));
+ iflag = rflag = 1;
+ username = NULL;
+ }
+
+ if ( init->realm ) {
+ ckstrncpy(realm,init->realm,REALM_SZ);
+ }
+
+ if ( init->instance ) {
+ ckstrncpy(inst,init->instance, INST_SZ);
+ }
+
+#ifdef COMMENT
+ if ( vflag )
+ printf("Kerberos IV initialization\r\n");
+#endif /* COMMENT */
+
+ if (!username || !username[0]) {
+ debug(F100,"ck_krb4_initTGT no username specified","",0);
+ printf("?Invalid principal specified.\r\n");
+ krb4_errno = -1;
+ makestr(&krb4_errmsg,"No principal specified");
+ return(-1);
+ }
+ if (!*realm) {
+ ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ);
+ }
+
+ if ( init->password )
+ password = init->password;
+ else {
+ char prmpt[80];
+ int ok;
+
+ ckmakxmsg(prmpt,sizeof(prmpt),
+ "Kerberos 4 Password for ",username,"@",realm,": ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT);
+ if ( ok )
+ password = passwd;
+ }
+
+ if (pflag) {
+ k_errno = krb_get_pw_in_tkt_preauth( aname, inst, realm,
+ "krbtgt", realm,
+ lifetime,
+ password);
+ if (k_errno == -1) { /* preauth method not available */
+ k_errno = krb_get_pw_in_tkt(aname,
+ inst, realm,
+ "krbtgt", realm,
+ lifetime,
+ password);
+ }
+ } else {
+ k_errno = krb_get_pw_in_tkt(aname,
+ inst, realm,
+ "krbtgt", realm,
+ lifetime,
+ password);
+ }
+
+ memset(passwd,0,sizeof(passwd));
+ if (k_errno) {
+ printf("%s for principal %s%s%s@%s\r\n",
+ krb_get_err_text_entry(k_errno), aname,
+ inst[0]?".":"", inst, realm);
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(-1);
+ } else if (vflag) {
+ printf("Result from realm %s: ", realm);
+ printf("%s\r\n", krb_get_err_text_entry(k_errno));
+ }
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(0);
+}
+#endif /* KINIT */
+#ifdef KDESTROY
+int
+#ifdef CK_ANSIC
+ck_krb4_destroy(struct krb_op_data * op)
+#else
+ck_krb4_destroy(op) struct krb_op_data * op;
+#endif
+{
+ int k_errno=0;
+
+ if ( !ck_krb4_is_installed() )
+ return(-1);
+
+ k_errno = dest_tkt();
+
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+
+ if (k_errno == 0)
+ printf("Tickets destroyed.\r\n");
+ else if (k_errno == RET_TKFIL)
+ printf("No tickets to destroy.\r\n");
+ else {
+ printf("Tickets MAY NOT be destroyed.\r\n");
+ return(-1);
+ }
+ return(0);
+}
+#endif /* KDESTROY */
+#ifdef KLIST
+_PROTOTYP(static int display_tktfile,(char *, int, int, int));
+
+int
+#ifdef CK_ANSIC
+ck_krb4_list_creds(struct krb_op_data * op)
+#else
+ck_krb4_list_creds(op) struct krb_op_data * op;
+#endif
+{
+ int long_form = 1;
+ int tgt_test = 0;
+ int do_srvtab = 0;
+ int show_kvnos = 0;
+ char *tkt_file = NULL;
+
+ if ( !ck_krb4_is_installed() )
+ return(-1);
+
+ if ( op->cache )
+ tkt_file = op->cache;
+
+ if ( k4debug ) {
+ show_kvnos = 1;
+ }
+
+ if (do_srvtab)
+ return(display_srvtab(tkt_file));
+ else
+ return(display_tktfile(tkt_file, tgt_test, long_form, show_kvnos));
+}
+
+#ifndef KRB5
+static int timestamp_width=0;
+
+static char *
+#ifdef CK_ANSIC
+short_date(long *dp)
+#else
+short_date(dp) long *dp;
+#endif
+{
+ register char *cp;
+ extern char *ctime();
+ cp = ctime(dp) + 4;
+ cp[15] = '\0';
+ return (cp);
+}
+
+
+static VOID
+#ifdef CK_ANSIC
+printtime(time_t tv)
+#else
+printtime(tv) time_t tv;
+#endif
+{
+ char timestring[BUFSIZ];
+ char format[12];
+ char fill;
+
+ fill = ' ';
+ sprintf(format,"%%-%ds",timestamp_width); /* safe */
+ printf(format,short_date(&tv));
+}
+#endif /* KRB5 */
+
+static int
+#ifdef CK_ANSIC
+display_tktfile(char *file, int tgt_test, int long_form, int show_kvnos)
+#else
+display_tktfile(file,tgt_test,long_form,show_kvnos)
+ char *file; int tgt_test; int long_form; int show_kvnos;
+#endif
+{
+ char pname[ANAME_SZ];
+ char pinst[INST_SZ];
+ char prealm[REALM_SZ];
+ char buf1[20], buf2[20];
+ int k_errno;
+#ifdef OS2
+ LEASH_CREDENTIALS creds;
+#else /* OS2 */
+ CREDENTIALS creds;
+#endif /* OS2 */
+ int header = 1;
+
+ file = tkt_string();
+
+ if (long_form) {
+ printf("Ticket cache: %s\r\n", file);
+ }
+
+ /*
+ * Since krb_get_tf_realm will return a ticket_file error,
+ * we will call tf_init and tf_close first to filter out
+ * things like no ticket file. Otherwise, the error that
+ * the user would see would be
+ * klist: can't find realm of ticket file: No ticket file (tf_util)
+ * instead of
+ * klist: No ticket file (tf_util)
+ */
+
+ /* Open ticket file */
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ if (!tgt_test)
+ printf("%s\r\n", krb_get_err_text_entry (k_errno));
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(-1);
+ }
+
+
+ /* Close ticket file */
+ (void) tf_close();
+
+ /*
+ * We must find the realm of the ticket file here before calling
+ * tf_init because since the realm of the ticket file is not
+ * really stored in the principal section of the file, the
+ * routine we use must itself call tf_init and tf_close.
+ */
+ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
+ if (!tgt_test)
+ printf("can't find realm of ticket file: %s\r\n",
+ krb_get_err_text_entry (k_errno));
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(-1);
+ }
+
+ /* Open ticket file */
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ if (!tgt_test)
+ printf("%s\r\n", krb_get_err_text_entry (k_errno));
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(-1);
+ }
+ /* Get principal name and instance */
+ if ((k_errno = tf_get_pname(pname)) ||
+ (k_errno = tf_get_pinst(pinst))) {
+ (void) tf_close();
+ if (!tgt_test)
+ printf("%s\r\n", krb_get_err_text_entry (k_errno));
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(-1);
+ }
+
+ /*
+ * You may think that this is the obvious place to get the
+ * realm of the ticket file, but it can't be done here as the
+ * routine to do this must open the ticket file. This is why
+ * it was done before tf_init.
+ */
+
+ if (!tgt_test && long_form)
+ printf("Default principal: %s%s%s%s%s\r\n\r\n", pname,
+ (pinst[0] ? "." : ""), pinst,
+ (prealm[0] ? "@" : ""), prealm);
+
+ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
+ if (!tgt_test && long_form && header) {
+ printf("%-17s %-17s %s\r\n",
+ "Valid starting", "Expires", "Service principal");
+ header = 0;
+ }
+ if (tgt_test) {
+ creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60;
+ if (!strcmp(creds.service, "krbtgt") &&
+ !strcmp(creds.instance, prealm)) {
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+
+ (void) tf_close();
+ if (time(0) < creds.issue_date) {
+ return(0); /* tgt hasn't expired */
+ } else {
+ return(-1); /* has expired */
+ }
+ }
+ continue; /* not a tgt */
+ }
+ if (long_form) {
+ timestamp_width = 17; /* for k5 display function */
+ /* if available */
+ printtime(creds.issue_date);
+ printf(" ");
+ creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60;
+ if ( time(0) < creds.issue_date )
+ printtime(creds.issue_date);
+ else
+ printf("*** expired *** ");
+ printf(" ");
+ }
+ if (show_kvnos)
+ printf("%s%s%s%s%s (%d)\r\n",
+ creds.service, (creds.instance[0] ? "." : ""), creds.instance,
+ (creds.realm[0] ? "@" : ""), creds.realm, creds.kvno);
+ else
+ printf("%s%s%s%s%s\r\n",
+ creds.service, (creds.instance[0] ? "." : ""), creds.instance,
+ (creds.realm[0] ? "@" : ""), creds.realm);
+
+#ifdef OS2
+ if ( creds.address[0] )
+ printf(" Address: %s\r\n",creds.address);
+#endif /* OS2 */
+ }
+
+ (void) tf_close();
+
+ if (tgt_test) {
+ return(-1);
+ }/* no tgt found */
+ if (header && long_form && k_errno == EOF) {
+ printf("No tickets in file.\r\n");
+ }
+ krb4_errno = k_errno;
+ makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno));
+ return(0);
+}
+
+#ifdef COMMENT
+/* Just so we remember what the command line interface looked like */
+usage()
+{
+ printf(
+ "Usage: [ -s | -t ] [ -file filename ] [ -srvtab ] [ -version ]\r\n");
+ return(-1);
+}
+#endif /* COMMENT */
+
+/* adapted from getst() in librkb */
+/*
+ * ok_getst() takes a file descriptor, a string and a count. It reads
+ * from the file until either it has read "count" characters, or until
+ * it reads a null byte. When finished, what has been read exists in
+ * the given string "s". If "count" characters were actually read, the
+ * last is changed to a null, so the returned string is always null-
+ * terminated. ok_getst() returns the number of characters read, including
+ * the null terminator.
+ *
+ * If there is a read error, it returns -1 (like the read(2) system call)
+ */
+
+static int
+#ifdef CK_ANSIC
+ok_getst(int fd, register char *s, int n)
+#else
+ok_getst(fd, s, n) int fd; register char *s; int n;
+#endif
+{
+ register int count = n;
+ int err;
+ while ((err = read(fd, s, 1)) > 0 && --count)
+ if (*s++ == '\0')
+ return (n - count);
+ if (err < 0)
+ return(-1);
+ *s = '\0';
+ return (n - count);
+}
+
+int
+#ifdef CK_ANSIC
+display_srvtab(char *file)
+#else
+display_srvtab(file) char *file;
+#endif
+{
+ int stab;
+ char serv[SNAME_SZ];
+ char inst[INST_SZ];
+ char rlm[REALM_SZ];
+ unsigned char key[8];
+ unsigned char vno;
+ int count;
+
+ printf("Server key file: %s\r\n", file);
+#ifdef NT
+#ifndef O_RDONLY
+#define O_RDONLY _O_RDONLY
+#endif /* O_RDONLY */
+#endif /* NT */
+
+ if ((stab = open(file, O_RDONLY, 0400)) < 0) {
+ perror(file);
+ return(-1);
+ }
+ printf("%-15s %-15s %-10s %s\r\n","Service","Instance","Realm",
+ "Key Version");
+ printf("------------------------------------------------------\r\n");
+
+ /* argh. getst doesn't return error codes, it silently fails */
+ while (((count = ok_getst(stab, serv, SNAME_SZ)) > 0)
+ && ((count = ok_getst(stab, inst, INST_SZ)) > 0)
+ && ((count = ok_getst(stab, rlm, REALM_SZ)) > 0)) {
+ if (((count = read(stab,(char *) &vno,1)) != 1) ||
+ ((count = read(stab,(char *) key,8)) != 8)) {
+ if (count < 0)
+ perror("reading from key file");
+ else
+ printf("key file truncated\r\n");
+ return(-1);
+ }
+ printf("%-15s %-15s %-15s %d\r\n",serv,inst,rlm,vno);
+ }
+ if (count < 0)
+ perror(file);
+ (void) close(stab);
+ return(0);
+}
+#endif /* KLIST */
+#else /* KRB4 */
+int
+ck_krb4_autoget_TGT(char * dummy)
+{
+ return(-1);
+}
+#ifdef CK_KERBEROS
+int
+#ifdef CK_ANSIC
+ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init)
+#else
+ck_krb4_initTGT(op,init)
+ struct krb_op_data * op, struct krb4_init_data * init
+#endif
+{
+ return(-1);
+}
+
+#ifdef CK_ANSIC
+ck_krb4_destroy(struct krb_op_data * op)
+#else
+ck_krb4_destroy(op) struct krb_op_data * op;
+#endif
+{
+ return(-1);
+}
+int
+#ifdef CK_ANSIC
+ck_krb4_list_creds(struct krb_op_data * op)
+#else
+ck_krb4_list_creds(op) struct krb_op_data * op;
+#endif
+{
+ return(-1);
+}
+#else /* CK_KERBEROS */
+int ck_krb4_initTGT(void * a, void *b)
+{
+ return(-1);
+}
+int ck_krb4_destroy(void *a)
+{
+ return(-1);
+}
+int ck_krb4_list_creds(void *a)
+{
+ return(-1);
+}
+#endif /* CK_KERBEROS */
+#endif /* KRB4 */
+
+/* The following functions are used to implement the Kermit Script Language */
+/* functions */
+
+struct tkt_list_item {
+ char * name;
+ struct tkt_list_item * next;
+};
+
+static struct tkt_list_item * k4_tkt_list = NULL;
+
+int
+#ifdef CK_ANSIC
+ck_krb4_get_tkts(VOID)
+#else
+ck_krb4_get_tkts()
+#endif
+{
+#ifdef KRB4
+ char *file=NULL;
+ char pname[ANAME_SZ];
+ char pinst[INST_SZ];
+ char prealm[REALM_SZ];
+ char buf1[20], buf2[20];
+ int k_errno;
+#ifdef OS2
+ LEASH_CREDENTIALS creds;
+#else /* OS2 */
+ CREDENTIALS creds;
+#endif /* OS2 */
+ int tkt_count=0;
+ struct tkt_list_item ** list = &k4_tkt_list;
+
+ while ( k4_tkt_list ) {
+ struct tkt_list_item * next;
+ next = k4_tkt_list->next;
+ free(k4_tkt_list->name);
+ free(k4_tkt_list);
+ k4_tkt_list = next;
+ }
+
+ if ( !ck_krb4_is_installed() )
+ return(-1);
+
+ file = tkt_string();
+
+ /*
+ * Since krb_get_tf_realm will return a ticket_file error,
+ * we will call tf_init and tf_close first to filter out
+ * things like no ticket file. Otherwise, the error that
+ * the user would see would be
+ * klist: can't find realm of ticket file: No ticket file (tf_util)
+ * instead of
+ * klist: No ticket file (tf_util)
+ */
+
+ /* Open ticket file */
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ return(-1);
+ }
+
+ /* Close ticket file */
+ (void) tf_close();
+
+ /*
+ * We must find the realm of the ticket file here before calling
+ * tf_init because since the realm of the ticket file is not
+ * really stored in the principal section of the file, the
+ * routine we use must itself call tf_init and tf_close.
+ */
+ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
+ return(-1);
+ }
+
+ /* Open ticket file */
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ return(-1);
+ }
+ /* Get principal name and instance */
+ if ((k_errno = tf_get_pname(pname)) ||
+ (k_errno = tf_get_pinst(pinst))) {
+ return(-1);
+ }
+
+ /*
+ * You may think that this is the obvious place to get the
+ * realm of the ticket file, but it can't be done here as the
+ * routine to do this must open the ticket file. This is why
+ * it was done before tf_init.
+ */
+
+ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
+ char tkt_buf[256];
+ ckmakxmsg(tkt_buf,sizeof(tkt_buf),
+ creds.service, (creds.instance[0] ? "." : ""), creds.instance,
+ (creds.realm[0] ? "@" : ""), creds.realm,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item));
+ (*list)->name = strdup(tkt_buf);
+ (*list)->next = NULL;
+ list = &((*list)->next);
+ tkt_count++;
+ }
+
+ tf_close();
+ return(tkt_count);
+#else /* KRB4 */
+ return(0);
+#endif /* KRB4 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb4_get_next_tkt(VOID)
+#else
+ck_krb4_get_next_tkt()
+#endif
+{
+#ifdef KRB4
+ static char * s=NULL;
+ struct tkt_list_item * next=NULL;
+
+ if ( s ) {
+ free(s);
+ s = NULL;
+ }
+
+ if ( k4_tkt_list == NULL )
+ return(NULL);
+
+ next = k4_tkt_list->next;
+ s = k4_tkt_list->name;
+ free(k4_tkt_list);
+ k4_tkt_list = next;
+ return(s);
+#else /* KRB4 */
+ return(NULL);
+#endif /* KRB4 */
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb4_tkt_isvalid(char * tktname)
+#else
+ck_krb4_tkt_isvalid(tktname) char * tktname;
+#endif
+{
+#ifdef KRB4
+ char *file=NULL;
+ char pname[ANAME_SZ];
+ char pinst[INST_SZ];
+ char prealm[REALM_SZ];
+ char buf1[20], buf2[20];
+ int k_errno;
+ time_t issue_t, expire_t, now_t;
+#ifdef OS2
+ LEASH_CREDENTIALS creds;
+#else /* OS2 */
+ CREDENTIALS creds;
+#endif /* OS2 */
+
+ if ( !ck_krb4_is_installed() )
+ return(-1);
+
+ debug(F110,"ck_krb4_tkt_isvalid","tkt_string",0);
+ file = tkt_string();
+
+ /*
+ * Since krb_get_tf_realm will return a ticket_file error,
+ * we will call tf_init and tf_close first to filter out
+ * things like no ticket file. Otherwise, the error that
+ * the user would see would be
+ * klist: can't find realm of ticket file: No ticket file (tf_util)
+ * instead of
+ * klist: No ticket file (tf_util)
+ */
+
+ /* Open ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_init",0);
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ return(-1);
+ }
+
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+
+ /*
+ * We must find the realm of the ticket file here before calling
+ * tf_init because since the realm of the ticket file is not
+ * really stored in the principal section of the file, the
+ * routine we use must itself call tf_init and tf_close.
+ */
+ debug(F110,"ck_krb4_tkt_isvalid","krb_get_tf_realm",0);
+ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
+ return(-1);
+ }
+
+ /* Open ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_init",0);
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ return(-1);
+ }
+ /* Get principal name and instance */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_get_name/tf_get_pinst",0);
+ if ((k_errno = tf_get_pname(pname)) ||
+ (k_errno = tf_get_pinst(pinst))) {
+
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+
+ return(-1);
+ }
+
+ /*
+ * You may think that this is the obvious place to get the
+ * realm of the ticket file, but it can't be done here as the
+ * routine to do this must open the ticket file. This is why
+ * it was done before tf_init.
+ */
+
+ debug(F110,"ck_krb4_tkt_isvalid","tf_get_cred",0);
+ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
+ char tkt_buf[256];
+ ckmakxmsg(tkt_buf,sizeof(tkt_buf),
+ creds.service, (creds.instance[0] ? "." : ""), creds.instance,
+ (creds.realm[0] ? "@" : ""), creds.realm,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ if ( !strcmp(tktname,tkt_buf) ) {
+
+ /* we found the ticket we are looking for */
+ issue_t = creds.issue_date;
+ expire_t = creds.issue_date
+ + ((unsigned char) creds.lifetime) * 5 * 60;
+ now_t = time(0);
+
+ /* We add a 5 minutes fudge factor to compensate for potential */
+ /* clock skew errors between the KDC and K95's host OS */
+
+ if ( now_t >= (issue_t-300) && now_t < expire_t) {
+#ifdef OS2
+#ifdef CHECKADDRS
+ if ( krb4_checkaddrs ) {
+ extern char myipaddr[20]; /* From ckcnet.c */
+ if ( !myipaddr[0] ) {
+ int i;
+ char buf[60];
+ for ( i=0;i<64;i++ ) {
+ if ( getlocalipaddrs(buf,60,i) < 0 )
+ break;
+
+ if ( !strcmp(buf,creds.address) ) {
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(1); /* They're the same */
+ }
+ }
+
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(0); /* They're different */
+ } else if ( strcmp(myipaddr,creds.address) ) {
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(0); /* They're different */
+ }
+ else {
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(1); /* They're the same */
+ }
+ } else {
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(1); /* They're the same */
+ }
+#else /* CHECKADDRS */
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(1); /* valid but no ip address check */
+#endif /* CHECKADDRS */
+#else /* OS2 */
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(1); /* Valid but no ip address check */
+#endif /* OS2 */
+ }
+ else {
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(0); /* expired or otherwise invalid */
+ }
+ }
+ }
+ /* Close ticket file */
+ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0);
+ (void) tf_close();
+ return(0); /* could not find the desired ticket */
+#else /* KRB4 */
+ return(-1);
+#endif /* KRB4 */
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb4_is_tgt_valid(VOID)
+#else
+ck_krb4_is_tgt_valid()
+#endif
+{
+#ifdef KRB4
+ char tgt[256];
+ char * s;
+ int rc = 0;
+
+ s = krb4_d_realm ? krb4_d_realm : ck_krb4_getrealm();
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt.",s,"@",s);
+ rc = ck_krb4_tkt_isvalid(tgt);
+ debug(F111,"ck_krb4_is_tgt_valid",tgt,rc);
+ return(rc > 0);
+#else /* KRB4 */
+ return(0);
+#endif /* KRB4 */
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb4_tkt_time(char * tktname)
+#else
+ck_krb4_tkt_time(tktname) char * tktname;
+#endif
+{
+#ifdef KRB4
+ char *file=NULL;
+ char pname[ANAME_SZ];
+ char pinst[INST_SZ];
+ char prealm[REALM_SZ];
+ char buf1[20], buf2[20];
+ int k_errno;
+#ifdef OS2
+ LEASH_CREDENTIALS creds;
+#else /* OS2 */
+ CREDENTIALS creds;
+#endif /* OS2 */
+
+ if ( !ck_krb4_is_installed() )
+ return(-1);
+
+ file = tkt_string();
+
+ /*
+ * Since krb_get_tf_realm will return a ticket_file error,
+ * we will call tf_init and tf_close first to filter out
+ * things like no ticket file. Otherwise, the error that
+ * the user would see would be
+ * klist: can't find realm of ticket file: No ticket file (tf_util)
+ * instead of
+ * klist: No ticket file (tf_util)
+ */
+
+ /* Open ticket file */
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ return(-1);
+ }
+
+ /* Close ticket file */
+ (void) tf_close();
+
+ /*
+ * We must find the realm of the ticket file here before calling
+ * tf_init because since the realm of the ticket file is not
+ * really stored in the principal section of the file, the
+ * routine we use must itself call tf_init and tf_close.
+ */
+ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) {
+ return(-1);
+ }
+
+ /* Open ticket file */
+ if (k_errno = tf_init(file, R_TKT_FIL)) {
+ return(-1);
+ }
+ /* Get principal name and instance */
+ if ((k_errno = tf_get_pname(pname)) ||
+ (k_errno = tf_get_pinst(pinst))) {
+ tf_close();
+ return(-1);
+ }
+
+ /*
+ * You may think that this is the obvious place to get the
+ * realm of the ticket file, but it can't be done here as the
+ * routine to do this must open the ticket file. This is why
+ * it was done before tf_init.
+ */
+
+ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) {
+ char tkt_buf[256];
+ ckmakxmsg(tkt_buf,sizeof(tkt_buf),
+ creds.service, (creds.instance[0] ? "." : ""),
+ creds.instance,
+ (creds.realm[0] ? "@" : ""), creds.realm,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ if ( !strcmp(tktname,tkt_buf) ) {
+ /* we found the ticket we are looking for */
+ int n = (creds.issue_date
+ + (((unsigned char) creds.lifetime) * 5 * 60))
+ - time(0);
+ tf_close();
+ return(n <= 0 ? 0 : n);
+ }
+ }
+ tf_close();
+ return(0); /* could not find the desired ticket */
+#else /* KRB4 */
+ return(-1);
+#endif /* KRB4 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb4_getrealm(void)
+#else
+ck_krb4_getrealm()
+#endif
+{
+#ifdef KRB4
+ char *file=NULL;
+ int k_errno;
+ static char realm[256]="";
+ realm[0]='\0';
+
+ if ( !ck_krb4_is_installed() )
+ return(realm);
+
+ /* Try to get realm from ticket file */
+ /* If failure get the local realm */
+
+ /*
+ * Since krb_get_tf_realm will return a ticket_file error,
+ * we will call tf_init and tf_close first to filter out
+ * things like no ticket file.
+ */
+
+ /* Open ticket file */
+ file = tkt_string();
+ if (file == NULL || !file[0])
+ return(realm);
+
+ if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) {
+ /* Close ticket file */
+ (void) tf_close();
+
+ k_errno = krb_get_tf_realm(file, realm);
+ }
+ if (k_errno != KSUCCESS) {
+ k_errno = krb_get_lrealm(realm, 1);
+ }
+ return(realm);
+#else /* KRB4 */
+ return("");
+#endif /* KRB4 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb4_getprincipal(void)
+#else
+ck_krb4_getprincipal()
+#endif
+{
+#ifdef KRB4
+ char *file=NULL;
+ int k_errno;
+ static char principal[256]="";
+ char instance[256]="";
+ char realm[256]="";
+ principal[0]='\0';
+
+ if ( !ck_krb4_is_installed() )
+ return(principal);
+
+ /* Try to get realm from ticket file */
+ /* If failure get the local realm */
+
+ /*
+ * Since krb_get_tf_realm will return a ticket_file error,
+ * we will call tf_init and tf_close first to filter out
+ * things like no ticket file.
+ */
+
+ /* Open ticket file */
+ file = tkt_string();
+ if (file == NULL || !file[0])
+ return(principal);
+
+ if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) {
+ /* Close ticket file */
+ (void) tf_close();
+
+ k_errno = krb_get_tf_fullname(file, principal, instance, realm);
+ }
+ return(principal);
+#else /* KRB4 */
+ return("");
+#endif /* KRB4 */
+}
+
+static struct tkt_list_item * k5_tkt_list = NULL;
+
+int
+#ifdef CK_ANSIC
+ck_krb5_get_tkts(char * cc_name)
+#else
+ck_krb5_get_tkts(cc_name) char * cc_name;
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ krb5_context kcontext;
+ krb5_error_code retval;
+ krb5_ccache cache = NULL;
+ krb5_cc_cursor cur;
+ krb5_creds creds;
+ krb5_principal princ=NULL;
+ krb5_flags flags=0;
+ krb5_error_code code=0;
+ int exit_status = 0;
+
+ int tkt_count=0;
+ struct tkt_list_item ** list = &k5_tkt_list;
+
+ while ( k5_tkt_list ) {
+ struct tkt_list_item * next;
+ next = k5_tkt_list->next;
+ free(k5_tkt_list->name);
+ free(k5_tkt_list);
+ k5_tkt_list = next;
+ }
+
+ if ( !ck_krb5_is_installed() )
+ return(-1);
+
+ retval = krb5_init_context(&kcontext);
+ if (retval) {
+ debug(F101,"ck_krb5_get_tkts while initializing krb5","",retval);
+ return(-1);
+ }
+
+ code = k5_get_ccache(kcontext,&cache,cc_name);
+ if (code != 0) {
+ debug(F111,"ck_krb5_get_tkts while getting ccache",
+ error_message(code),code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ flags = 0; /* turns off OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ if (code == ENOENT) {
+ debug(F111,"ck_krb5_get_tkts (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ } else {
+ debug(F111,
+ "ck_krb5_get_tkts while setting cache flags (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ }
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
+ debug(F101,"ck_krb5_get_tkts while retrieving principal name",
+ "",code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
+ debug(F101,"ck_krb5_get_tkts while unparsing principal name",
+ "",code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_get_tkts while starting to retrieve tickets",
+ "",code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+ char *sname=NULL;
+
+ retval = krb5_unparse_name(kcontext, creds.server, &sname);
+ if (retval) {
+ debug(F101,
+ "ck_krb5_get_tkts while unparsing server name","",retval);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item));
+ (*list)->name = sname;
+ (*list)->next = NULL;
+ list = &((*list)->next);
+
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ tkt_count++;
+ }
+
+ if (code == KRB5_CC_END) {
+ if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_get_tkts while finishing ticket retrieval",
+ "",code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+ flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ debug(F101,"ck_krb5_get_tkts while closing ccache",
+ "",code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+ } else {
+ debug(F101,"ck_krb5_get_tkts while retrieving a ticket","",code);
+ tkt_count = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ exit_k5_get_tkt:
+ krb5_free_principal(kcontext,princ);
+ krb5_free_unparsed_name(kcontext,defname);
+ krb5_cc_close(kcontext,cache);
+ krb5_free_context(kcontext);
+ return(tkt_count);
+#else /* HEIMDAL */
+ return(-1);
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return(0);
+#endif /* KRB5 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb5_get_next_tkt(VOID)
+#else
+ck_krb5_get_next_tkt()
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ static char * s=NULL;
+ struct tkt_list_item * next=NULL;
+
+ if ( s ) {
+ free(s);
+ s = NULL;
+ }
+
+ if ( k5_tkt_list == NULL )
+ return(NULL);
+
+ next = k5_tkt_list->next;
+ s = k5_tkt_list->name;
+ free(k5_tkt_list);
+ k5_tkt_list = next;
+ return(s);
+#else /* HEIMDAL */
+ return("Not implemented");
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return(NULL);
+#endif /* KRB5 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb5_tkt_flags(char * cc_name, char * tktname)
+#else
+ck_krb5_tkt_flags(cc_name,tktname) char * cc_name; char * tktname;
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ krb5_context kcontext;
+ krb5_error_code retval;
+ krb5_ccache cache = NULL;
+ krb5_cc_cursor cur;
+ krb5_creds creds;
+ krb5_principal princ=NULL;
+ krb5_flags flags=0;
+ krb5_error_code code=0;
+ char * flag_str = "";
+
+ if ( !ck_krb5_is_installed() )
+ return("");
+
+ retval = krb5_init_context(&kcontext);
+ if (retval) {
+ debug(F101,"ck_krb5_tkt_flags while initializing krb5","",retval);
+ return("");
+ }
+
+ code = k5_get_ccache(kcontext,&cache,cc_name);
+ if (code != 0) {
+ debug(F111,"ck_krb5_tkt_isvalid while getting ccache",
+ error_message(code),code);
+ goto exit_k5_get_tkt;
+ }
+
+ flags = 0; /* turns off OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ if (code == ENOENT) {
+ debug(F111,"ck_krb5_tkt_flags (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ } else {
+ debug(F111,
+ "ck_krb5_tkt_flags while setting cache flags (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ }
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
+ debug(F101,"ck_krb5_tkt_flags while retrieving principal name",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
+ debug(F101,"ck_krb5_tkt_flags while unparsing principal name",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_tkt_flags while starting to retrieve tickets",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ if (!status_only)
+ debug(F101,"ck_krb5_tkt_flags while getting time of day.",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+ char *sname=NULL;
+
+ retval = krb5_unparse_name(kcontext, creds.server, &sname);
+ if (retval) {
+ debug(F101,
+ "ck_krb5_tkt_flags while unparsing server name","",retval);
+ retval = -1;
+ krb5_free_cred_contents(kcontext, &creds);
+ goto exit_k5_get_tkt;
+ }
+
+ if ( !strcmp(sname,tktname) ) {
+ /* we found the ticket we are looking for */
+
+ flag_str = flags_string(&creds);
+
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ code = KRB5_CC_END;
+ break;
+ }
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ }
+
+ if (code == KRB5_CC_END) {
+ if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_tkt_flags while finishing ticket retrieval",
+ "",code);
+ goto exit_k5_get_tkt;
+ }
+ flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ debug(F101,"ck_krb5_tkt_flags while closing ccache",
+ "",code);
+ goto exit_k5_get_tkt;
+ }
+ } else {
+ debug(F101,"ck_krb5_tkt_flags while retrieving a ticket","",code);
+ goto exit_k5_get_tkt;
+ }
+
+ exit_k5_get_tkt:
+ krb5_free_principal(kcontext,princ);
+ krb5_free_unparsed_name(kcontext,defname);
+ krb5_cc_close(kcontext,cache);
+ krb5_free_context(kcontext);
+ return(flag_str);
+#else /* HEIMDAL */
+ return("Not implemented");
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return("");
+#endif /* KRB5 */
+}
+
+
+int
+#ifdef CK_ANSIC
+ck_krb5_tkt_isvalid(char * cc_name, char * tktname)
+#else
+ck_krb5_tkt_isvalid(cc_name,tktname) char * cc_name; char * tktname;
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ krb5_context kcontext=NULL;
+ krb5_error_code retval;
+ krb5_ccache cache = NULL;
+ krb5_cc_cursor cur;
+ krb5_creds creds;
+ krb5_principal princ=NULL;
+ krb5_flags flags=0;
+ krb5_error_code code=0;
+#ifdef CHECKADDRS
+ krb5_address ** myAddrs=NULL;
+ krb5_address ** p=NULL;
+ BOOL Addrfound = FALSE;
+#endif /*CHECKADDRS*/
+
+ if ( !ck_krb5_is_installed() )
+ return(-1);
+
+ retval = krb5_init_context(&kcontext);
+ if (retval) {
+ debug(F101,"ck_krb5_tkt_isvalid while initializing krb5","",retval);
+ return(-1);
+ }
+
+ code = k5_get_ccache(kcontext,&cache,cc_name);
+ if (code != 0) {
+ debug(F111,"ck_krb5_tkt_isvalid while getting ccache",
+ error_message(code),code);
+ goto exit_k5_get_tkt;
+ }
+
+ flags = 0; /* turns off OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ if (code == ENOENT) {
+ debug(F111,"ck_krb5_tkt_isvalid (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ } else {
+ debug(F111,
+ "ck_krb5_tkt_isvalid while setting cache flags (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ }
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
+ debug(F101,"ck_krb5_tkt_isvalid while retrieving principal name",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
+ debug(F101,"ck_krb5_tkt_isvalid while unparsing principal name",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_tkt_isvalid while starting to retrieve tickets",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ if (!status_only)
+ debug(F101,"ck_krb5_tkt_isvalid while getting time of day.",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+ char *sname=NULL;
+
+ retval = krb5_unparse_name(kcontext, creds.server, &sname);
+ if (retval) {
+ debug(F101,
+ "ck_krb5_tkt_isvalid while unparsing server name","",retval);
+ retval = -1;
+ krb5_free_cred_contents(kcontext, &creds);
+ goto exit_k5_get_tkt;
+ }
+
+ if ( !strcmp(sname,tktname) ) {
+ /* we found the ticket we are looking for */
+
+ /* We add a 5 minutes fudge factor to compensate for potential */
+ /* clock skew errors between the KDC and K95's host OS */
+
+ retval = ((creds.times.starttime > 0) &&
+ now >= (creds.times.starttime - 300) &&
+ now < (creds.times.endtime + 300) &&
+ !(creds.ticket_flags & TKT_FLG_INVALID));
+
+#ifdef CHECKADDRS
+ if ( retval && krb5_checkaddrs &&
+ creds.addresses && creds.addresses[0] ) {
+ /* if we think it is valid, then lets check the IP Addresses */
+ /* to make sure it is valid for our current connection. */
+ /* Also make sure it's for the correct IP address */
+ retval = krb5_os_localaddr(kcontext, &myAddrs);
+ if (retval) {
+ com_err(NULL, retval, "retrieving my IP address");
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ code = KRB5_CC_END;
+ retval = -1;
+ break;
+ }
+
+ /* See if any of our addresses match any in cached credentials */
+
+ for (Addrfound=FALSE, p=myAddrs;
+ (Addrfound==FALSE) && (*p);
+ p++
+ ) {
+ if (krb5_address_search(kcontext, *p, creds.addresses)) {
+ Addrfound = TRUE;
+ }
+ }
+ krb5_free_addresses(k5_context, myAddrs);
+
+ if (Addrfound) {
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ code = KRB5_CC_END;
+ retval = 1;
+ break;
+ } else {
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ code = KRB5_CC_END;
+ retval = 0;
+ break;
+ }
+ }
+#endif /* CHECKADDRS */
+
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ code = KRB5_CC_END;
+ break;
+ }
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ }
+
+ if (code == KRB5_CC_END) {
+ if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_tkt_isvalid while finishing ticket retrieval",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ debug(F101,"ck_krb5_tkt_isvalid while closing ccache",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ } else {
+ debug(F101,"ck_krb5_tkt_isvalid while retrieving a ticket","",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ exit_k5_get_tkt:
+ krb5_free_principal(kcontext,princ);
+ krb5_free_unparsed_name(kcontext,defname);
+ krb5_cc_close(kcontext,cache);
+ krb5_free_context(kcontext);
+ return(retval);
+#else /* HEIMDAL */
+ return(-1);
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return(-1);
+#endif /* KRB5 */
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb5_is_tgt_valid(VOID)
+#else
+ck_krb5_is_tgt_valid()
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ char tgt[256];
+ char * s;
+ int rc = 0;
+
+ s = ck_krb5_getrealm(krb5_d_cc);
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt/",s,"@",s);
+ rc = ck_krb5_tkt_isvalid(krb5_d_cc,tgt);
+ debug(F111,"ck_krb5_is_tgt_valid",tgt,rc);
+ return(rc>0);
+#else /* HEIMDAL */
+ return(-1);
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return(0);
+#endif /* KRB5 */
+}
+
+int
+#ifdef CK_ANSIC
+ck_krb5_tkt_time(char * cc_name, char * tktname)
+#else
+ck_krb5_tkt_time(cc_name, tktname) char * cc_name; char * tktname;
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ krb5_context kcontext;
+ krb5_error_code retval;
+ krb5_ccache cache = NULL;
+ krb5_cc_cursor cur;
+ krb5_creds creds;
+ krb5_principal princ=NULL;
+ krb5_flags flags=0;
+ krb5_error_code code=0;
+
+ if ( !ck_krb5_is_installed() )
+ return(-1);
+
+ retval = krb5_init_context(&kcontext);
+ if (retval) {
+ debug(F101,"ck_krb5_list_creds while initializing krb5","",retval);
+ return(-1);
+ }
+
+ code = k5_get_ccache(kcontext,&cache,cc_name);
+ if (code != 0) {
+ debug(F111,"ck_krb5_tkt_time while getting ccache",
+ error_message(code),code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ flags = 0; /* turns off OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ if (code == ENOENT) {
+ debug(F111,"ck_krb5_list_creds (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ } else {
+ debug(F111,
+ "ck_krb5_list_creds while setting cache flags (ticket cache)",
+ krb5_cc_get_name(kcontext, cache),code);
+ }
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
+ debug(F101,"ck_krb5_list_creds while retrieving principal name",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
+ debug(F101,"ck_krb5_list_creds while unparsing principal name",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_list_creds while starting to retrieve tickets",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ if ((code = krb5_timeofday(kcontext, &now))) {
+ if (!status_only)
+ debug(F101,"ck_krb5_list_creds while getting time of day.",
+ "",code);
+ krb5_free_context(kcontext);
+ return(-1);
+ }
+
+ while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+ char *sname=NULL;
+
+ retval = krb5_unparse_name(kcontext, creds.server, &sname);
+ if (retval) {
+ debug(F101,
+ "ck_krb5_list_creds while unparsing server name","",retval);
+ retval = -1;
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ goto exit_k5_get_tkt;
+ }
+
+ if ( !strcmp(sname,tktname) ) {
+ /* we found the ticket we are looking for */
+ int valid = (creds.times.starttime &&
+ now > creds.times.starttime &&
+ now < creds.times.endtime &&
+ !(creds.ticket_flags & TKT_FLG_INVALID));
+ if ( valid ) {
+ retval = creds.times.endtime - now;
+ }
+ else
+ retval = 0;
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ code = KRB5_CC_END;
+ break;
+ }
+ krb5_free_unparsed_name(kcontext,sname);
+ krb5_free_cred_contents(kcontext, &creds);
+ }
+
+ if (code == KRB5_CC_END) {
+ if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
+ debug(F101,"ck_krb5_list_creds while finishing ticket retrieval",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+ debug(F101,"ck_krb5_list_creds while closing ccache",
+ "",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+ } else {
+ debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code);
+ retval = -1;
+ goto exit_k5_get_tkt;
+ }
+
+ exit_k5_get_tkt:
+ krb5_free_principal(kcontext,princ);
+ krb5_free_unparsed_name(kcontext,defname);
+ krb5_cc_close(kcontext,cache);
+ krb5_free_context(kcontext);
+ return(retval);
+#else /* HEIMDAL */
+ return(-1);
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return(-1);
+#endif /* KRB5 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb5_get_cc_name(void)
+#else
+ck_krb5_get_cc_name()
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ static char cc_name[CKMAXPATH+1]="";
+ krb5_context kcontext = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_error_code code;
+ char * p=NULL;
+
+ cc_name[0] = '\0';
+
+ if ( !ck_krb5_is_installed() )
+ return(cc_name);
+
+ p = getenv("KRB5CCNAME");
+ if ( !p ) {
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ com_err("ck_krb5_get_cc_name",code,"while init_context");
+ return(cc_name);
+ }
+ if ((code = krb5_cc_default(kcontext, &ccache))) {
+ com_err("ck_krb5_get_cc_name",code,"while getting default ccache");
+ goto exit_k5_get_cc;
+ }
+
+ ckmakmsg(cc_name,sizeof(cc_name),
+ (char *)krb5_cc_get_type(kcontext,ccache),":",
+ (char *)krb5_cc_get_name(kcontext,ccache),NULL);
+ } else {
+ ckstrncpy(cc_name,p,CKMAXPATH);
+ }
+
+ if ( !strncmp("FILE:",cc_name,5) ) {
+ for ( p=cc_name; *p ; p++ )
+ if ( *p == '\\' ) *p = '/';
+ }
+
+ exit_k5_get_cc:
+ if ( ccache )
+ krb5_cc_close(kcontext,ccache);
+ if ( kcontext )
+ krb5_free_context(kcontext);
+ return(cc_name);
+#else /* HEIMDAL */
+ return("Not implemented");
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return("");
+#endif /* KRB5 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb5_getrealm(char * cc_name)
+#else
+ck_krb5_getrealm(cc_name) char * cc_name;
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ static char realm[256]="";
+ krb5_context kcontext;
+ krb5_ccache ccache = NULL;
+ krb5_error_code code;
+ krb5_principal me=NULL;
+
+ realm[0] = '\0';
+
+ if ( !ck_krb5_is_installed() )
+ return(realm);
+
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ return(realm);
+ }
+
+ code = k5_get_ccache(kcontext,&ccache,cc_name);
+ if (code != 0) {
+ goto exit_k5_getrealm;
+ }
+
+ code = krb5_cc_get_principal(kcontext, ccache, &me);
+ if (code)
+ code = krb5_parse_name(kcontext, "foo", &me);
+ if (code) {
+ goto exit_k5_getrealm;
+ }
+ if ( krb5_princ_realm(kcontext, me)->length < sizeof(realm) ) {
+ memcpy(realm,krb5_princ_realm(kcontext, me)->data,
+ krb5_princ_realm(kcontext, me)->length); /* safe */
+ realm[krb5_princ_realm(kcontext, me)->length]='\0';
+ }
+ exit_k5_getrealm:
+ if ( me )
+ krb5_free_principal(kcontext,me);
+ if ( ccache )
+ krb5_cc_close(kcontext,ccache);
+ if (kcontext)
+ krb5_free_context(kcontext);
+ return(realm);
+#else /* HEIMDAL */
+ return("Not implemented");
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return("");
+#endif /* KRB5 */
+}
+
+char *
+#ifdef CK_ANSIC
+ck_krb5_getprincipal(char * cc_name)
+#else
+ck_krb5_getprincipal(cc_name) char * cc_name;
+#endif
+{
+#ifdef KRB5
+#ifndef HEIMDAL
+ static char principal[UIDBUFLEN+1]="";
+ krb5_context kcontext;
+ krb5_ccache ccache = NULL;
+ krb5_error_code code;
+ krb5_principal me;
+ char * p=NULL;
+ int i;
+
+ principal[0] = '\0';
+
+ if ( !ck_krb5_is_installed() )
+ return(principal);
+
+ code = krb5_init_context(&kcontext);
+ if (code) {
+ return(principal);
+ }
+
+ code = k5_get_ccache(kcontext,&ccache,cc_name);
+ if (code != 0) {
+ goto exit_k5_getprincipal;
+ }
+
+ if ((code = krb5_cc_get_principal(kcontext, ccache, &me))) {
+ goto exit_k5_getprincipal;
+ }
+
+ if ((code = krb5_unparse_name (kcontext, me, &p))) {
+ krb5_free_principal(kcontext,me);
+ goto exit_k5_getprincipal;
+ }
+
+ ckstrncpy(principal,p,UIDBUFLEN);
+ i = ckindex("@",principal,0,0,0);
+ if (i)
+ principal[i-1] = '\0';
+
+ krb5_free_unparsed_name(kcontext,p);
+
+ exit_k5_getprincipal:
+ if ( ccache )
+ krb5_cc_close(kcontext,ccache);
+ if (kcontext)
+ krb5_free_context(kcontext);
+ return(principal);
+#else /* HEIMDAL */
+ return("Not implemented");
+#endif /* HEIMDAL */
+#else /* KRB5 */
+ return("");
+#endif /* KRB5 */
+}
+
+#ifndef CRYPT_DLL
+int
+ck_get_crypt_table(struct keytab ** pTable, int * pN)
+{
+#ifdef CK_ENCRYPTION
+ return(get_crypt_table(pTable, pN));
+#else /* ENCRYPTION */
+ int i=0;
+#ifndef OS2
+ char * tmpstring = NULL;
+#endif /* OS2 */
+
+ if ( *pTable )
+ {
+ for ( i=0 ; i < *pN ; i++ )
+ free( (*pTable)[i].kwd ) ;
+ free ( *pTable ) ;
+ }
+ *pTable = NULL;
+ *pN = 0;
+
+ *pTable = malloc( sizeof(struct keytab) * 2 ) ;
+ if ( !(*pTable) )
+ return(0);
+
+#ifdef OS2
+ (*pTable)[0].kwd =strdup("automatic");
+#else /* OS2 */
+ makestr(&tmpstring,"automatic");
+ (*pTable)[0].kwd = tmpstring;
+ tmpstring = NULL;
+#endif /* OS2 */
+ (*pTable)[0].kwval = ENCTYPE_ANY;
+ (*pTable)[0].flgs = 0;
+#ifdef OS2
+ (*pTable)[1].kwd =strdup("none");
+#else /* OS2 */
+ makestr(&tmpstring,"none");
+ (*pTable)[1].kwd = tmpstring;
+ tmpstring = NULL;
+#endif /* OS2 */
+ (*pTable)[1].kwval = 999;
+ (*pTable)[1].flgs = 0;
+ (*pN) = 2;
+
+ return(2);
+#endif /* ENCRYPTION */
+}
+
+VOID
+ck_encrypt_send_support()
+{
+#ifdef CK_ENCRYPTION
+ encrypt_send_support();
+#endif /* ENCRYPTION */
+}
+#endif /* CRYPT_DLL */
+
+/*
+ *
+ * Kstream
+ *
+ * Emulates the kstream package in Kerberos 4
+ *
+ */
+
+int
+kstream_destroy()
+{
+ if (g_kstream != NULL) {
+ auth_destroy(); /* Destroy authorizing */
+ free(g_kstream);
+ g_kstream=NULL;
+ }
+ return 0;
+}
+
+VOID
+#ifdef CK_ANSIC
+kstream_set_buffer_mode(int mode)
+#else
+kstream_set_buffer_mode(mode) int mode;
+#endif
+{
+}
+
+
+int
+#ifdef CK_ANSIC
+kstream_create_from_fd(int fd,
+ kstream_ptr data)
+#else
+kstream_create_from_fd(fd,data)
+ int fd; kstream_ptr data;
+#endif
+{
+ int n;
+
+ g_kstream = malloc(sizeof(struct kstream_int));
+ if (g_kstream == NULL)
+ return 0;
+
+ g_kstream->fd = fd;
+
+ n = auth_init(g_kstream); /* Initialize authorizing */
+ if (n) {
+ free(g_kstream);
+ g_kstream = NULL;
+ return 0;
+ }
+
+ g_kstream->encrypt = NULL;
+ g_kstream->decrypt = NULL;
+ g_kstream->encrypt_type = ENCTYPE_ANY;
+ g_kstream->decrypt_type = ENCTYPE_ANY;
+ return 1;
+}
+
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+static int do_lencheck, use_ivecs;
+extern int rlog_inband;
+
+#ifdef KRB5
+void
+rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck, am_client,
+ protonum)
+ krb5_keyblock *in_keyblock;
+ int encrypt_flag;
+ int lencheck;
+ int am_client;
+ enum krb5_kcmd_proto protonum;
+{
+ krb5_error_code status;
+ size_t blocksize;
+
+ if (!encrypt_flag)
+ return;
+
+ desinbuf.data = des_inbuf;
+ desoutbuf.data = des_outpkt+4; /* Set up des buffers */
+ k5_session_key = in_keyblock;
+
+ do_lencheck = lencheck;
+
+ if ( protonum == KCMD_OLD_PROTOCOL ) {
+ use_ivecs = 0;
+ return;
+ }
+
+ use_ivecs = 1;
+
+ if (status = krb5_c_block_size(k5_context, k5_session_key->enctype,
+ &blocksize)) {
+ /* XXX what do I do? */
+ printf("fatal kerberos 5 crypto library error\n");
+ ttclos(0);
+ return;
+ }
+
+ encivec_i[0].length = encivec_i[1].length =
+ encivec_o[0].length = encivec_o[1].length = blocksize;
+
+ if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) == NULL) {
+ /* XXX what do I do? */
+ printf("fatal malloc failed\n");
+ ttclos(0);
+ return;
+ }
+
+ encivec_i[1].data = encivec_i[0].data + encivec_i[0].length;
+ encivec_o[0].data = encivec_i[1].data + encivec_i[1].length;
+ encivec_o[1].data = encivec_o[0].data + encivec_o[0].length;
+
+ /* is there a better way to initialize this? */
+ memset(encivec_i[0].data, am_client, blocksize);
+ memset(encivec_o[0].data, 1 - am_client, blocksize);
+ memset(encivec_i[1].data, 2 | am_client, blocksize);
+ memset(encivec_o[1].data, 2 | (1 - am_client), blocksize);
+}
+#endif /* KRB5 */
+
+int
+#ifdef CK_ANSIC
+ck_krb_rlogin(CHAR * hostname, int port,
+ CHAR * localuser, CHAR * remoteuser, CHAR * term_speed,
+ struct sockaddr_in * l_addr, struct sockaddr_in * r_addr,
+ int kversion, int encrypt_flag)
+#else /* CK_ANSIC */
+ck_krb_rlogin(hostname, port,
+ localuser, remoteuser, term_speed, l_addr, r_addr, encrypt_flag)
+ CHAR * hostname; int port;
+ CHAR * localuser; CHAR * remoteuser; CHAR * term_speed;
+ struct sockaddr_in * l_addr; struct sockaddr_in * r_addr;
+ int kversion; int encrypt_flag;
+#endif /* CK_ANSIC */
+{
+ unsigned long status;
+ char * realm=NULL;
+ extern int ttyfd;
+ int c;
+ long msglen;
+
+ debug(F111,"ck_krb_rlogin",hostname,port);
+
+ if ( kversion == 4 && !ck_krb4_is_installed() ) {
+ printf("?Kerberos 4 is not installed\r\n");
+ return(-1);
+ } else if ( kversion == 5 && !ck_krb5_is_installed() ) {
+ printf("?Kerberos 5 is not installed\r\n");
+ return(-1);
+ }
+
+ if ( encrypt_flag && !ck_crypt_is_installed() ) {
+ printf("?Encryption is not installed\r\n");
+ return(-1);
+ }
+
+ if ( kversion == 5 ) {
+#ifdef KRB5
+ krb5_flags authopts=0;
+ krb5_ccache ccache=NULL;
+ char *cksumbuf=NULL;
+ char *service=NULL;
+ char * kcmd_version=NULL;
+ enum krb5_kcmd_proto use_proto;
+ krb5_data cksumdat;
+ krb5_creds *get_cred = 0;
+ krb5_error_code status;
+ krb5_error *error = 0;
+ krb5_ap_rep_enc_part *rep_ret = NULL;
+ krb5_data outbuf;
+ int rc;
+ krb5_int32 seqno=0;
+ krb5_int32 server_seqno=0;
+ char ** realmlist=NULL;
+ int buflen;
+ char tgt[256];
+
+ debug(F100,"ck_krb_rlogin version 5","",0);
+
+ realm = ck_krb5_realmofhost((char *)hostname);
+ if (!realm) {
+ ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL);
+ ckstrncat(strTmp, (char *)hostname,AUTHTMPBL);
+ ckstrncat(strTmp, "\"",AUTHTMPBL);
+ printf("?Kerberos 5 error: %s\r\n",strTmp);
+ krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN;
+ makestr(&krb5_errmsg,strTmp);
+ return(0);
+ }
+
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
+ debug(F110,"ck_rlog_rlogin TGT",tgt,0);
+ if ( krb5_autoget &&
+ !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
+ (ck_krb5_is_tgt_valid() > 0)) )
+ ck_krb5_autoget_TGT(realm);
+
+ buflen = strlen((char *)term_speed) + strlen((char *)remoteuser) + 64;
+ if ((cksumbuf = malloc(buflen)) == 0) {
+ printf("Unable to allocate memory for checksum buffer.\r\n");
+ return(-1);
+ }
+ ckmakmsg(cksumbuf,buflen,ckuitoa((unsigned short) ntohs(port)),":",
+ (char *)term_speed,(char *)remoteuser);
+ cksumdat.data = cksumbuf;
+ cksumdat.length = strlen(cksumbuf);
+
+ status = krb5_init_context(&k5_context);
+ if (status) {
+ debug(F110,"ck_krb_rlogin()","unable to init_context",0);
+ return(-1);
+ }
+
+ desinbuf.data = des_inbuf;
+ desoutbuf.data = des_outpkt+4; /* Set up des buffers */
+
+ rc = k5_get_ccache(k5_context,&ccache,NULL);
+ if (rc != 0) {
+ com_err(NULL, rc, "while getting ccache.");
+ return(0);
+ }
+
+ service = krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME;
+
+ if (!(get_cred = (krb5_creds *)calloc(1, sizeof(krb5_creds)))) {
+ printf("ck_krb_rlogin: no memory\r\n");
+ return(-1);
+ }
+ memset(get_cred,0,sizeof(krb5_creds));
+ status = krb5_sname_to_principal(k5_context, (char *) hostname,
+ service, KRB5_NT_SRV_HST,
+ &get_cred->server);
+ if (status) {
+ printf("ck_krb_rlogin: krb5_sname_to_principal failed: %s\r\n",
+ error_message(status));
+ return(-1);
+ }
+
+ ttoc(0);
+
+ if (status = krb5_cc_get_principal(k5_context,
+ ccache,
+ &get_cred->client)
+ ) {
+ (void) krb5_cc_close(k5_context, ccache);
+ krb5_free_creds(k5_context, get_cred);
+ goto bad;
+ }
+
+ if (krb5_rlog_ver == KCMD_OLD_PROTOCOL)
+ get_cred->keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+
+ /* Get ticket from credentials cache or kdc */
+ status = krb5_get_credentials(k5_context,
+ 0,
+ ccache,
+ get_cred,
+ &ret_cred
+ );
+ krb5_free_creds(k5_context, get_cred);
+ get_cred = NULL;
+ (void) krb5_cc_close(k5_context, ccache);
+
+ if (status)
+ goto bad;
+
+ /* Reset internal flags; these should not be set. */
+ authopts &= (~OPTS_FORWARD_CREDS);
+ authopts &= (~OPTS_FORWARDABLE_CREDS);
+
+ if (krb5_auth_con_init(k5_context, &auth_context))
+ goto bad;
+
+ if (krb5_auth_con_setflags(k5_context, auth_context,
+ KRB5_AUTH_CONTEXT_RET_TIME))
+ goto bad;
+
+ /* Only need local address for mk_cred() to send to krlogind */
+ if (!krb5_d_no_addresses)
+ if (status = krb5_auth_con_genaddrs(k5_context,
+ auth_context,
+ ttyfd,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR
+ ))
+ goto bad;
+
+ /* Here is where we start to handle the new protocol in earnest */
+ if ( krb5_rlog_ver == KCMD_PROTOCOL_COMPAT_HACK ) {
+ krb5_boolean is_des;
+
+ if (status = krb5_c_enctype_compare( k5_context,
+ ENCTYPE_DES_CBC_CRC,
+#ifdef HEIMDAL
+ ret_cred->session.keytype,
+#else /* HEIMDAL */
+ ret_cred->keyblock.enctype,
+#endif /* HEIMDAL */
+ &is_des)) {
+ krb5_free_creds(k5_context, ret_cred);
+ ret_cred = NULL;
+ goto bad;
+ }
+
+ if ( is_des ) {
+ kcmd_version = "KCMDV0.1";
+ use_proto = KCMD_OLD_PROTOCOL;
+ } else {
+ authopts = AP_OPTS_USE_SUBKEY;
+ kcmd_version = "KCMDV0.2";
+ use_proto = KCMD_NEW_PROTOCOL;
+ }
+ } else {
+ use_proto = krb5_rlog_ver;
+ switch ( krb5_rlog_ver ) {
+ case KCMD_NEW_PROTOCOL:
+ authopts = AP_OPTS_USE_SUBKEY;
+ kcmd_version = "KCMDV0.2";
+ break;
+ case KCMD_OLD_PROTOCOL:
+ kcmd_version = "KCMDV0.1";
+ break;
+ default:
+ goto bad;
+ }
+ }
+
+ /* call Kerberos library routine to obtain an authenticator,
+ pass it over the socket to the server, and obtain mutual
+ authentication.
+ */
+ status = krb5_sendauth(k5_context,
+ &auth_context,
+ (krb5_pointer) &ttyfd,
+ kcmd_version,
+ ret_cred->client,
+ ret_cred->server,
+ authopts,
+ &cksumdat,
+ ret_cred,
+ 0,
+ &error,
+ &rep_ret,
+ NULL
+ );
+ krb5_free_data_contents(k5_context,&cksumdat);
+
+ if (status) {
+ if ( !quiet )
+ printf("Couldn't authenticate to server: %s\r\n",
+ error_message(status));
+ if (error) {
+ if ( !quiet ) {
+ printf("Server returned error code %d (%s)\r\n",
+ error->error,
+ error_message(ERROR_TABLE_BASE_krb5 + error->error));
+ if (error->text.length) {
+ printf("Error text sent from server: %s\r\n",
+ error->text.data);
+ }
+ }
+ krb5_free_error(k5_context, error);
+ error = 0;
+ }
+ goto bad;
+ }
+
+ if (rep_ret) {
+ server_seqno = rep_ret->seq_number;
+ krb5_free_ap_rep_enc_part(k5_context, rep_ret);
+ }
+
+ (void) ttol(remoteuser, strlen((char *)remoteuser)+1);
+ (void) ttol(term_speed, strlen((char *)term_speed)+1);
+ (void) ttol(localuser, strlen((char *)localuser)+1);
+
+ if (forward_flag) { /* Forward credentials (global) */
+ if (status = krb5_fwd_tgt_creds( k5_context,
+ auth_context,
+ (char *)hostname,
+ ret_cred->client,
+ ret_cred->server,
+ 0,
+ (forwardable_flag ?
+ OPTS_FORWARDABLE_CREDS :
+ 0),
+ &outbuf
+ )
+ )
+ {
+ printf("Error forwarding credentials: %s\r\n",
+ error_message(status));
+ goto bad2;
+ }
+
+ /* Send forwarded credentials */
+ status = krb5_write_message(k5_context,
+ (krb5_pointer)&ttyfd,
+ &outbuf
+ );
+ }
+ else { /* Dummy write to signal no forwarding */
+ bad2:
+ outbuf.length = 0;
+ status = krb5_write_message(k5_context,
+ (krb5_pointer)&ttyfd,
+ &outbuf);
+ }
+
+ if ((c = ttinc(0)) < 0) {
+ if (c==-1) {
+ perror((char *)hostname);
+ } else {
+ printf("ck_krb_rlogin: bad connection with remote host\r\n");
+ }
+ status = -1;
+ goto bad;
+ }
+ if (c != 0) {
+ while ((c = ttinc(1)) >= 0) {
+ (void) printf("%c",c);
+ if (c == '\n')
+ break;
+ }
+ status = -1;
+ goto bad;
+ }
+
+ if ( status == 0 ) { /* success */
+ krb5_keyblock * key = 0;
+
+ if ( use_proto == KCMD_NEW_PROTOCOL ) {
+ int on = 1;
+ rlog_inband = 1;
+ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,
+ (char *) &on, sizeof on);
+
+ status = krb5_auth_con_getlocalsubkey( k5_context,
+ auth_context,
+ &key);
+ if ((status || !key) && encrypt_flag )
+ goto bad2;
+ }
+ if ( key == 0 ) {
+#ifdef HEIMDAL
+ key = &ret_cred->session;
+#else /* HEIMDAL */
+ key = &ret_cred->keyblock;
+#endif /* HEIMDAL */
+ }
+
+ rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, use_proto);
+ if ( encrypt_flag )
+ rlog_encrypt = 1;
+ }
+ return (0); /* success */
+
+ bad:
+ if ( status && !quiet ) {
+ printf("Kerberos authentication error: %s\r\n",
+ error_message(status));
+ }
+ if (ret_cred) {
+ krb5_free_creds(k5_context, ret_cred);
+ ret_cred = NULL;
+ }
+ return (status);
+#else /* KRB5 */
+ return(-1);
+#endif /* KRB5 */
+ } else if (kversion == 4) {
+#ifdef KRB4
+ char tgt[4*REALM_SZ+1];
+ debug(F100,"ck_krb_rlogin version 4","",0);
+
+ realm = (char *)krb_realmofhost(hostname);
+ if (!realm) {
+ strcpy(strTmp, "Can't find realm for host \"");
+ ckstrncat(strTmp, hostname,AUTHTMPBL);
+ ckstrncat(strTmp, "\"",AUTHTMPBL);
+ printf("?Kerberos 4 error: %s\r\n",strTmp);
+ krb4_errno = 0;
+ makestr(&krb4_errmsg,strTmp);
+ return(0);
+ }
+
+ ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm);
+ status = ck_krb4_tkt_isvalid(tgt);
+
+ if ( status <= 0 && krb4_autoget )
+ ck_krb4_autoget_TGT(realm);
+
+ ttoc(0); /* write a NUL */
+
+ status = krb_sendauth(encrypt_flag?KOPT_DO_MUTUAL:0,
+ ttyfd,
+ &k4_auth,
+ krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
+ hostname,
+ realm,
+ (unsigned long) getpid(),
+ &k4_msg_data,
+ &cred,
+#ifdef CK_ENCRYPTION
+ &k4_sched,
+#else /* ENCRYPTION */
+ NULL,
+#endif /* ENCRYPTION */
+ l_addr,
+ r_addr,
+ "KCMDV0.1");
+ debug(F111,"ck_krb_rlogin","krb_sendauth",status);
+ if (status != KSUCCESS) {
+ printf( "krb_sendauth failed: %s\r\n",
+ krb_get_err_text_entry(status)
+ );
+ return(-1);
+ }
+ ttol(remoteuser,strlen(remoteuser)+1);
+ ttol(term_speed,strlen(term_speed)+1);
+
+ reread:
+ if ((c = ttinc(0)) < 0) {
+ printf("rcmd: bad connection with remote host\r\n");
+ return(-1);
+ }
+ debug(F111,"ck_krb_rlogin","first byte",c);
+
+ if (c != 0) {
+ char *check = "ld.so: warning:";
+ /* If rlogind was compiled on SunOS4, and it somehow
+ got the shared library version numbers wrong, it
+ may give an ld.so warning about an old version of a
+ shared library. Just ignore any such warning.
+ Note that the warning is a characteristic of the
+ server; we may not ourselves be running under
+ SunOS4. */
+ if (c == 'l') {
+ char *p;
+ char cc;
+
+ p = &check[1];
+ while ((c = ttinc(0)) >= 0) {
+ if (*p == '\0') {
+ if (c == '\n')
+ break;
+ } else {
+ if (c != *p)
+ break;
+ ++p;
+ }
+ }
+
+ if (*p == '\0')
+ goto reread;
+ }
+
+ printf(check);
+ while ((c = ttinc(1)) >= 0) {
+ printf("%c",c);
+ if (c == '\n')
+ break;
+ }
+ debug(F110,"ck_krb_rlogin","fatal error 1",0);
+ return(-1);
+ }
+
+#ifdef CK_ENCRYPTION
+ if ( encrypt_flag ) {
+ /* if we are encrypting we need to setup the encryption */
+ /* routines. */
+ des_key_sched(cred.session, k4_sched);
+ rlog_encrypt = 1;
+ }
+#endif /* ENCRYPTION */
+#else /* KRB4 */
+ return(-1);
+#endif /* KRB4 */
+ }
+ return(0); /* success */
+}
+
+#define SRAND srand
+#define RAND rand
+#define RAND_TYPE int
+
+static long
+random_confounder(size, fillin)
+size_t size;
+char * fillin;
+{
+ static int seeded = 0;
+ register unsigned char *real_fill;
+ RAND_TYPE rval;
+
+ if (!seeded) {
+ /* time() defined in 4.12.2.4, but returns a time_t, which is an
+ "arithmetic type" (4.12.1) */
+ rval = (RAND_TYPE) time(0);
+ SRAND(rval);
+ rval = RAND();
+ rval ^= getpid();
+ SRAND(rval);
+ seeded = 1;
+ }
+
+ real_fill = (unsigned char *)fillin;
+ while (size > 0) {
+ rval = RAND();
+ *real_fill = rval & 0xff;
+ real_fill++;
+ size--;
+ if (size) {
+ *real_fill = (rval >> 8) & 0xff;
+ real_fill++;
+ size--;
+ }
+ }
+ return 0;
+}
+
+#ifdef KRB5
+int
+krb5_des_avail(fd)
+ int fd;
+{
+ return(nstored);
+}
+
+int
+krb5_des_read(fd, buf, len, secondary)
+ int fd;
+ register char *buf;
+ int len;
+ int secondary;
+{
+ int nreturned = 0;
+ long net_len,rd_len;
+ int cc;
+ krb5_error_code status;
+ unsigned char c;
+ krb5_data plain;
+ krb5_enc_data cipher;
+
+ debug(F111,"krb5_des_read","len",len);
+ debug(F111,"krb5_des_read","rlog_encrypt",rlog_encrypt);
+ if ( !rlog_encrypt ) {
+ cc = net_read(fd, buf, len);
+ debug(F111,"krb5_des_read","chars read",cc);
+ if ( cc < 0 )
+ netclos();
+ return(cc);
+ }
+
+ if (nstored >= len) {
+ if ( buf ) {
+ memcpy(buf, store_ptr, len); /* safe */
+ store_ptr += len;
+ nstored -= len;
+ return(len);
+ } else
+ return(0);
+ } else if (nstored) {
+ if ( buf ) {
+ memcpy(buf, store_ptr, nstored); /* safe */
+ nreturned += nstored;
+ buf += nstored;
+ len -= nstored;
+ nstored = 0;
+ }
+ else
+ return(0);
+ }
+
+ /* See the comment in v4_des_read. */
+ while (1) {
+ cc = net_read(fd, &c, 1);
+ /* we should check for non-blocking here, but we'd have
+ to make it save partial reads as well. */
+ if (cc <= 0) {
+ return cc; /* read error */
+ }
+ if (cc == 1) {
+ if (c == 0 || !do_lencheck)
+ break;
+ }
+ }
+
+ rd_len = c;
+ if ((cc = net_read(fd, &c, 1)) != 1) return 0;
+ rd_len = (rd_len << 8) | c;
+ if ((cc = net_read(fd, &c, 1)) != 1) return 0;
+ rd_len = (rd_len << 8) | c;
+ if ((cc = net_read(fd, &c, 1)) != 1) return 0;
+ rd_len = (rd_len << 8) | c;
+
+ if (status = krb5_c_encrypt_length(k5_context,
+ k5_session_key->enctype,
+ use_ivecs ? rd_len + 4 : rd_len,
+ (size_t *)&net_len)) {
+ errno = status;
+ return(-1);
+ }
+
+ if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
+ /* preposterous length; assume out-of-sync; only
+ recourse is to close connection, so return 0 */
+ printf("Read size problem.\r\n");
+ return(0);
+ }
+ if ((cc = net_read(fd, desinbuf.data, net_len)) != net_len )
+ {
+ /* pipe must have closed, return 0 */
+ printf( "Read error: length received %d != expected %d.\r\n",
+ cc,
+ net_len
+ );
+ return(cc);
+ }
+
+
+ /* decrypt info */
+ cipher.enctype = ENCTYPE_UNKNOWN;
+ cipher.ciphertext.length = net_len;
+ cipher.ciphertext.data = desinbuf.data;
+ plain.length = sizeof(storage);
+ plain.data = storage;
+
+ if ( status = krb5_c_decrypt(k5_context, k5_session_key, KCMD_KEYUSAGE,
+ use_ivecs ? encivec_i + secondary : 0,
+ &cipher,&plain) ) {
+ /* probably out of sync */
+ printf("Cannot decrypt data from network: %s\r\n",
+ error_message(status));
+ errno = EIO;
+ return(-1);
+ }
+
+ store_ptr = storage;
+ nstored = rd_len;
+
+ if ( use_ivecs ) {
+ int rd_len2;
+ rd_len2 = storage[0] & 0xff;
+ rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff;
+ rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff;
+ rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff;
+ if (rd_len2 != rd_len) {
+ /* cleartext length trashed? */
+ errno = EIO;
+ return -1;
+ }
+ store_ptr += 4;
+ }
+
+ if ( !buf )
+ return(0);
+
+#ifdef RLOGCODE /* blah */
+ if (rlog_inband && (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN))
+ {
+ int i, left, n;
+
+ for (i = 0; i < nstored; i++) {
+ if (store_ptr[i] == '\377' &&
+ store_ptr[i+1] == '\377') {
+ left = nstored - i;
+ n = rlog_ctrl(&store_ptr[i], left);
+ if (n < 0) {
+ left -= (-n);
+ nstored = left;
+ /* flush before, and (-n) bytes */
+ if (left > 0)
+ memmove(store_ptr, &store_ptr[i-n], left);
+ } else if (n) {
+ left -= n;
+ nstored -= n;
+ if (left > 0)
+ memmove(store_ptr, &store_ptr[n], left);
+ }
+ }
+ }
+ }
+#endif /* RLOGCODE */
+
+ if (nstored > len) {
+ memcpy(buf, store_ptr, len); /* safe */
+ nreturned += len;
+ store_ptr += len;
+ nstored -= len;
+ } else {
+ memcpy(buf, store_ptr, nstored); /* safe */
+ nreturned += nstored;
+ nstored = 0;
+ }
+ return(nreturned);
+}
+
+int
+krb5_des_write(fd, buf, len, secondary)
+ int fd;
+ char *buf;
+ int len;
+ int secondary;
+{
+ char tmpbuf[2*RLOG_BUFSIZ+8];
+ unsigned char *len_buf = (unsigned char *) tmpbuf;
+ krb5_error_code status;
+ krb5_data plain;
+ krb5_enc_data cipher;
+
+ debug(F111,"krb5_des_write","rlog_encrypt",rlog_encrypt);
+ if ( !rlog_encrypt ) {
+ int cc = net_write(fd, buf, len);
+ debug(F111,"net_write","chars written",cc);
+ return(cc != len ? -1 : len);
+ }
+
+ if (use_ivecs) {
+ unsigned char *lenbuf2 = (unsigned char *) tmpbuf;
+ if (len + 4 > sizeof(tmpbuf))
+ abort ();
+ lenbuf2[0] = (len & 0xff000000) >> 24;
+ lenbuf2[1] = (len & 0xff0000) >> 16;
+ lenbuf2[2] = (len & 0xff00) >> 8;
+ lenbuf2[3] = (len & 0xff);
+ memcpy (tmpbuf + 4, buf, len);
+
+ plain.data = tmpbuf;
+ plain.length = len + 4;
+ } else {
+ plain.data = buf;
+ plain.length = len;
+ }
+
+ cipher.ciphertext.length = sizeof(des_outpkt)-4;
+ cipher.ciphertext.data = desoutbuf.data;
+
+ if ( status = krb5_c_encrypt(k5_context, k5_session_key, KCMD_KEYUSAGE,
+ use_ivecs ? encivec_o + secondary : 0,
+ &plain, &cipher)) {
+ printf("Write encrypt problem: %s.\r\n",
+ error_message(status));
+ errno = EIO;
+ return(-1);
+ }
+ desoutbuf.length = cipher.ciphertext.length;
+
+ len_buf = (unsigned char *) des_outpkt;
+ len_buf[0] = (len & 0xff000000) >> 24;
+ len_buf[1] = (len & 0xff0000) >> 16;
+ len_buf[2] = (len & 0xff00) >> 8;
+ len_buf[3] = (len & 0xff);
+
+ if (net_write(fd, des_outpkt,desoutbuf.length+4)
+ != desoutbuf.length+4){
+ printf("Could not write out all data\r\n");
+ return(-1);
+ }
+ else return(len);
+}
+#endif /* KRB5 */
+
+#ifdef KRB4
+/*
+ * Note that the encrypted rlogin packets take the form of a four-byte
+ * length followed by encrypted data. On writing the data out, a significant
+ * performance penalty is suffered (at least one RTT per character, two if we
+ * are waiting for a shell to echo) by writing the data separately from the
+ * length. So, unlike the input buffer, which just contains the output
+ * data, the output buffer represents the entire packet.
+ */
+
+int
+krb4_des_avail(fd)
+ int fd;
+{
+ return(nstored);
+}
+
+int
+krb4_des_read(fd, buf, len)
+int fd;
+register char *buf;
+int len;
+{
+ int nreturned = 0;
+ unsigned long net_len, rd_len;
+ int cc;
+ unsigned char c;
+ int gotzero = 0;
+
+ debug(F111,"krb4_des_read","rlog_encrypt",rlog_encrypt);
+ debug(F111,"krb4_des_read","len",len);
+ if ( !rlog_encrypt ) {
+ cc = net_read(fd, buf, len);
+ debug(F111,"krb4_des_read","chars read",cc);
+ if ( cc < 0 )
+ netclos();
+ return(cc);
+ }
+
+ if (nstored >= len) {
+ if ( buf ) {
+ debug(F111,"krb4_des_read (nstored >= len)","nstored",nstored);
+ memcpy(buf, store_ptr, len); /* safe */
+ store_ptr += len;
+ nstored -= len;
+ return(len);
+ } else
+ return(0);
+ } else if (nstored) {
+ if ( buf ) {
+ debug(F111,"krb4_des_read (nstored)","nstored",nstored);
+ memcpy(buf, store_ptr, nstored); /* safe */
+ nreturned += nstored;
+ buf += nstored;
+ len -= nstored;
+ nstored = 0;
+ } else
+ return(0);
+ }
+
+ /* We're fetching the length which is MSB first, and the MSB
+ has to be zero unless the client is sending more than 2^24
+ (16M) bytes in a single write (which is why this code is in
+ rlogin but not rcp or rsh.) The only reasons we'd get something
+ other than zero are:
+ -- corruption of the tcp stream (which will show up when
+ everything else is out of sync too)
+ -- un-caught Berkeley-style "pseudo out-of-band data" which
+ happens any time the user hits ^C twice.
+ The latter is *very* common, as shown by an 'rlogin -x -d'
+ using the CNS V4 rlogin. Mark EIchin 1/95
+ */
+ debug(F110,"krb4_des_read",
+ "about to call net_read() this will block",
+ 0
+ );
+ do {
+ cc = net_read(fd, &c, 1);
+ debug(F111,"net_read","chars read",cc);
+ if (cc <= 0) {
+ netclos();
+ return(-1);
+ }
+ if (cc != 1) return 0; /* read error */
+ if (cc == 1) {
+ if (c == 0) gotzero = 1;
+ }
+ } while (!gotzero);
+
+ debug(F110,"krb4_des_read","gotzero",0);
+ cc = net_read(fd, &c, 1);
+ debug(F111,"net_read","chars read",cc);
+ if (cc < 0) {
+ netclos();
+ return(-1);
+ } else if ( cc != 1 )
+ return(0);
+ net_len = c;
+ cc = net_read(fd, &c, 1);
+ debug(F111,"net_read","chars read",cc);
+ if (cc < 0) {
+ netclos();
+ return(-1);
+ } else if ( cc != 1 )
+ return(0);
+ net_len = (net_len << 8) | c;
+ debug(F111,"net_read","chars read",cc);
+ cc = net_read(fd, &c, 1);
+ if (cc < 0) {
+ netclos();
+ return(-1);
+ } else if ( cc != 1 )
+ return(0);
+ net_len = (net_len << 8) | c;
+ debug(F111,"krb4_des_read","net_len",net_len);
+
+ /* Note: net_len is unsigned */
+ if (net_len > sizeof(des_inbuf)) {
+ /* XXX preposterous length, probably out of sync.
+ act as if pipe closed */
+ return(0);
+ }
+ /* the writer tells us how much real data we are getting, but
+ we need to read the pad bytes (8-byte boundary) */
+#ifndef roundup
+#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
+#endif /* roundup */
+ rd_len = roundup(net_len, 8);
+ debug(F111,"krb4_des_read","rd_len",rd_len);
+ cc = net_read(fd, des_inbuf, rd_len);
+ debug(F111,"net_read","chars read",cc);
+ if (cc < 0) {
+ netclos();
+ return(-1);
+ } else if ( cc != rd_len )
+ return(0);
+
+ ckhexdump("krb4_des_read des_inbuf",des_inbuf,8);
+#ifdef CK_ENCRYPTION
+#ifdef KRB524
+ (void) des_pcbc_encrypt(des_inbuf,
+ storage,
+ (net_len < 8) ? 8 : net_len,
+ k4_sched,
+ cred.session,
+ DECRYPT);
+#else /* KRB524 */
+ (void) des_pcbc_encrypt((Block *)des_inbuf,
+ (Block *)storage,
+ (net_len < 8) ? 8 : net_len,
+ k4_sched,
+ &cred.session,
+ DECRYPT);
+#endif /* KRB524 */
+#endif /* ENCRYPTION */
+ ckhexdump("krb4_des_read storage",storage,8);
+
+ /*
+ * when the cleartext block is < 8 bytes, it is "right-justified"
+ * in the block, so we need to adjust the pointer to the data
+ */
+ if (net_len < 8)
+ store_ptr = storage + 8 - net_len;
+ else
+ store_ptr = storage;
+ nstored = net_len;
+
+ if ( !buf )
+ return(0);
+
+ if (nstored > len) {
+ memcpy(buf, store_ptr, len); /* safe */
+ nreturned += len;
+ store_ptr += len;
+ nstored -= len;
+ } else {
+ memcpy(buf, store_ptr, nstored); /* safe */
+ nreturned += nstored;
+ nstored = 0;
+ }
+
+ debug(F111,"net_read","nreturned",nreturned);
+ return(nreturned);
+}
+
+int
+krb4_des_write(fd, buf, len)
+int fd;
+char *buf;
+int len;
+{
+ static char garbage_buf[8];
+ unsigned char *len_buf = (unsigned char *) des_outpkt;
+ int cc;
+
+ debug(F111,"krb4_des_write","rlog_encrypt",rlog_encrypt);
+ if ( !rlog_encrypt ) {
+ cc = net_write(fd, buf, len);
+ debug(F111,"net_write","chars written",cc);
+ return(cc);
+ }
+
+ /*
+ * pcbc_encrypt outputs in 8-byte (64 bit) increments
+ *
+ * it zero-fills the cleartext to 8-byte padding,
+ * so if we have cleartext of < 8 bytes, we want
+ * to insert random garbage before it so that the ciphertext
+ * differs for each transmission of the same cleartext.
+ * if len < 8 - sizeof(long), sizeof(long) bytes of random
+ * garbage should be sufficient; leave the rest as-is in the buffer.
+ * if len > 8 - sizeof(long), just garbage fill the rest.
+ */
+ if (len < 8) {
+ random_confounder(8 - len, garbage_buf);
+ /* this "right-justifies" the data in the buffer */
+ (void) memcpy(garbage_buf + 8 - len, buf, len); /* safe */
+ ckhexdump("krb4_des_write garbage_buf",garbage_buf,8);
+ } else
+ ckhexdump("krb4_des_write buf",buf,8);
+#ifdef CK_ENCRYPTION
+#ifdef KRB524
+ (void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf,
+ des_outpkt+4,
+ (len < 8) ? 8 : len,
+ k4_sched,
+ cred.session,
+ ENCRYPT);
+#else /* KRB524 */
+ (void) des_pcbc_encrypt((Block *)((len < 8) ? garbage_buf : buf),
+ (Block *)(des_outpkt+4),
+ (len < 8) ? 8 : len,
+ k4_sched,
+ &cred.session,
+ ENCRYPT);
+#endif /* KRB524 */
+#endif /* ENCRYPTION */
+ if ( len < 8 )
+ ckhexdump("krb4_des_write (post pcbc) garbage_buf",garbage_buf,8);
+ else
+ ckhexdump("krb4_des_write (post pcbc) buf",buf,8);
+ ckhexdump("krb4_des_write (des_outpkt+4)",(des_outpkt+4),8);
+
+ /* tell the other end the real amount, but send an 8-byte padded
+ packet */
+ len_buf[0] = (len & 0xff000000) >> 24;
+ len_buf[1] = (len & 0xff0000) >> 16;
+ len_buf[2] = (len & 0xff00) >> 8;
+ len_buf[3] = (len & 0xff);
+ ckhexdump("krb4_des_write des_outpkt len",des_outpkt,12);
+ cc = net_write(fd, des_outpkt, roundup(len,8)+4);
+ debug(F111,"net_write","chars written",cc);
+ return(len);
+}
+#endif /* KRB4 */
+#endif /* RLOGCODE */
+
+#ifdef KRB524
+#ifndef OS2
+/* The following functions are missing from the compatibility library */
+const char *
+krb_get_err_text_entry(r) int r;
+{
+ extern char krb_err_text[];
+ return(krb_err_txt[r]);
+}
+#endif /* OS2 */
+#endif /* KRB524 */
+#endif /* CK_KERBEROS */
+
+#ifdef CK_KERBEROS
+#ifdef KRB5_U2U
+/* Kerberos 5 User to User Client */
+int
+k5_user_to_user_client_auth()
+{
+ extern int ttyfd;
+ register int retval, i;
+ char **srealms; /* realm(s) of server */
+ char *princ; /* principal in credentials cache */
+ krb5_ccache cc;
+ krb5_creds creds, *new_creds;
+ krb5_data reply, msg, msgtext, princ_data;
+ krb5_ticket * ticket = NULL;
+
+ if (retval = k5_get_ccache(k5_context,&cc,NULL))
+ {
+ com_err("uu-client", retval, "getting credentials cache");
+ return(-1);
+ }
+
+ memset ((char*)&creds, 0, sizeof(creds));
+ if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client))
+ {
+ com_err("uu-client", retval, "getting principal name");
+ return(-1);
+ }
+
+ if (retval = krb5_get_host_realm(k5_context, szHostName, &srealms))
+ {
+ com_err("uu-client", retval, "getting realms for \"%s\"", szHostName);
+ return(-1);
+ }
+
+ if (retval = krb5_build_principal_ext(k5_context, &creds.server,
+ krb5_princ_realm(k5_context,
+ creds.client)->length,
+ krb5_princ_realm(k5_context,
+ creds.client)->data,
+ 6, "krbtgt",
+ krb5_princ_realm(k5_context,
+ creds.client)->length,
+ krb5_princ_realm(k5_context,
+ creds.client)->data,
+ 0))
+ {
+ com_err("uu-client", retval, "setting up tgt server name");
+ return(-1);
+ }
+
+ /* Get TGT from credentials cache */
+ if (retval = krb5_get_credentials(k5_context, KRB5_GC_CACHED, cc,
+ &creds, &new_creds))
+ {
+ com_err("uu-client", retval, "getting TGT");
+ return(-1);
+ }
+
+ if (retval = krb5_unparse_name(k5_context, creds.client, &princ)) {
+ com_err("uu-client", retval, "printing principal name");
+ return(-1);
+ }
+ i = strlen(princ) + 1;
+ princ_data.data = princ;
+ princ_data.length = i; /* include null terminator for
+ server's convenience */
+ retval = krb5_write_message(k5_context,
+ (krb5_pointer) &ttyfd, &princ_data);
+ if (retval)
+ {
+ com_err("uu-client", retval, "sending principal name to server");
+ return(-1);
+ }
+ krb5_free_unparsed_name(k5_context,princ);
+
+ retval = krb5_write_message(k5_context,
+ (krb5_pointer) &ttyfd, &new_creds->ticket);
+ if (retval)
+ {
+ com_err("uu-client", retval, "sending ticket to server");
+ return(-1);
+ }
+
+ retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &reply);
+ if (retval)
+ {
+ com_err("uu-client", retval, "reading reply from server");
+ return(-1);
+ }
+
+ if (retval = krb5_auth_con_init(k5_context, &auth_context)) {
+ com_err("uu-client", retval, "initializing the auth_context");
+ return(-1);
+ }
+
+ if (!krb5_d_no_addresses) {
+ if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) {
+ com_err("uu-client", retval, "generating addrs for auth_context");
+ return(-1);
+ }
+ }
+
+ if (retval = krb5_auth_con_setflags(k5_context, auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ com_err("uu-client", retval, "initializing the auth_context flags");
+ return(-1);
+ }
+
+ if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context,
+ &new_creds->keyblock)) {
+ com_err("uu-client", retval, "setting useruserkey for authcontext");
+ return(-1);
+ }
+
+ /* read the ap_req to get the session key */
+ retval = krb5_rd_req(k5_context, &auth_context, &reply,
+ NULL, NULL, NULL, &ticket);
+ if (retval) {
+ com_err("uu-client", retval, "reading AP_REQ from server");
+ return(-1);
+ }
+
+ if (k5_u2u_read_msg(k5_context,&msg) < 0)
+ return(-1);
+
+ if ( strcmp("Kermit implements Kerberos 5 User to User",msg.data) )
+ return(-1);
+ krb5_free_data_contents(k5_context,&msg);
+
+ msgtext.data = "As do I! :-)";
+ msgtext.length = strlen(msgtext.data)+1;
+
+ if (k5_u2u_write_msg(k5_context,&msgtext) < 0)
+ return(-1);
+
+ if (retval = krb5_unparse_name(k5_context,
+#ifdef HEIMDAL
+ ticket->client,
+#else /* HEIMDAL */
+ ticket->enc_part2->client,
+#endif /* HEIMDAL */
+ &princ))
+ com_err("uu-client", retval, "while unparsing client name");
+ else {
+ ckstrncpy(szUserNameAuthenticated,princ,UIDBUFLEN);
+ validUser = AUTH_VALID;
+ authentication_version = AUTHTYPE_KERBEROS_V5;
+ if ( !quiet )
+ printf("Peer name is \"%s\"\n", princ);
+ krb5_free_unparsed_name(k5_context,princ);
+ }
+ return 0;
+}
+
+/* Kerberos 5 User to User Server */
+
+int
+k5_user_to_user_server_auth()
+{
+ krb5_data pname_data, tkt_data;
+ int retval;
+ krb5_creds creds, *new_creds;
+ krb5_ccache cc;
+ krb5_data msg, msgtext;
+ extern int ttyfd;
+
+ if (retval = krb5_read_message(k5_context,
+ (krb5_pointer) &ttyfd, &pname_data)) {
+ com_err ("uu-server", retval, "reading pname");
+ return(-1);
+ }
+ /* client sends it already null-terminated. */
+ if ( !quiet )
+ printf ("Peer name is \"%s\".\n", pname_data.data);
+ ckstrncpy(szUserNameAuthenticated,pname_data.data,UIDBUFLEN);
+ validUser = AUTH_VALID;
+ authentication_version = AUTHTYPE_KERBEROS_V5;
+
+ if (retval = krb5_read_message(k5_context,
+ (krb5_pointer) &ttyfd, &tkt_data)) {
+ com_err ("uu-server", retval, "reading ticket data");
+ return(-1);
+ }
+
+ if (retval = k5_get_ccache(k5_context,&cc,NULL))
+ {
+ com_err("uu-server", retval, "getting credentials cache");
+ return(-1);
+ }
+
+ memset ((char*)&creds, 0, sizeof(creds));
+ if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client))
+ {
+ com_err("uu-server", retval, "getting principal name");
+ return(-1);
+ }
+
+ if (retval = krb5_parse_name(k5_context, pname_data.data, &creds.server))
+ {
+ com_err("uu-server", retval, "parsing client name");
+ return(-1);
+ }
+ creds.second_ticket = tkt_data;
+
+ if (retval = krb5_get_credentials(k5_context, KRB5_GC_USER_USER,
+ cc, &creds, &new_creds))
+ {
+ com_err("uu-server", retval, "getting user-user ticket");
+ return(-1);
+ }
+
+ /* send a ticket/authenticator to the other side, so it can get the key
+ we're using for the krb_safe below. */
+
+ if (retval = krb5_auth_con_init(k5_context, &auth_context)) {
+ com_err("uu-server", retval, "making auth_context");
+ return(-1);
+ }
+
+ if (retval = krb5_auth_con_setflags(k5_context, auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ com_err("uu-server", retval, "initializing the auth_context flags");
+ return(-1);
+ }
+
+ if (!krb5_d_no_addresses) {
+ if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) {
+ com_err("uu-server", retval, "generating addrs for auth_context");
+ return(-1);
+ }
+ }
+
+ if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context,
+ &new_creds->keyblock)) {
+ com_err("uu-server", retval, "setting useruserkey for authcontext");
+ return(-1);
+ }
+
+ if (retval = krb5_mk_req_extended(k5_context, &auth_context,
+ AP_OPTS_USE_SESSION_KEY |
+ AP_OPTS_MUTUAL_REQUIRED,
+ NULL, new_creds, &msg)) {
+ com_err("uu-server", retval, "making AP_REQ");
+ return(-1);
+ }
+ retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &msg);
+ if (retval) {
+ com_err("uu-server", retval, "writing message to client");
+ return(-1);
+ }
+ krb5_free_data_contents(k5_context,&msg);
+
+ msgtext.data = "Kermit implements Kerberos 5 User to User";
+ msgtext.length = strlen(msgtext.data)+1;
+
+ if (k5_u2u_write_msg(k5_context,&msgtext) < 0)
+ return(-1);
+
+ if (k5_u2u_read_msg(k5_context,&msg) < 0)
+ return(-1);
+
+ if ( strcmp("As do I! :-)",msg.data) )
+ return(-1);
+ krb5_free_data_contents(k5_context,&msg);
+
+
+ return(0);
+}
+
+int
+k5_u2u_read_msg(krb5_context context, int fd, krb5_data * msg)
+{
+ int retval;
+ krb5_data reply;
+
+ retval = krb5_read_message(context, (krb5_pointer) &fd, &reply);
+ if (retval)
+ {
+ com_err("uu-client", retval, "reading reply");
+ return(-1);
+ }
+
+ if (retval = krb5_rd_priv(context, auth_context, &reply, msg, NULL)) {
+ com_err("uu-client", retval, "decoding reply");
+ return(-1);
+ }
+ return(0);
+}
+
+int
+k5_u2u_write_msg(krb5_context context, int fd, krb5_data * msgtext)
+{
+ int retval;
+ krb5_data msg;
+
+ if (retval = krb5_mk_priv(k5_context, auth_context, msgtext, &msg, NULL))
+ {
+ com_err("uu-server", retval, "encoding message");
+ return(-1);
+ }
+
+ retval = krb5_write_message(k5_context, (krb5_pointer) &fd, &msg);
+ krb5_free_data_contents(k5_context,&msg);
+ if (retval)
+ {
+ com_err("uu-server", retval, "writing message");
+ return(-1);
+ }
+ return(0);
+}
+
+int
+krb5_u2u_avail(fd)
+ int fd;
+{
+ return(nstored);
+}
+
+int
+krb5_u2u_read(fd, buf, len)
+ int fd;
+ register char *buf;
+ int len;
+{
+ int nreturned = 0;
+ krb5_data msg;
+
+ debug(F111,"krb5_u2u_read","len",len);
+
+ if ( !buf )
+ return(0);
+
+ if (nstored >= len) {
+ memcpy(buf, store_ptr, len); /* safe */
+ store_ptr += len;
+ nstored -= len;
+ return(len);
+ } else if (nstored) {
+ memcpy(buf, store_ptr, nstored); /* safe */
+ nreturned += nstored;
+ buf += nstored;
+ len -= nstored;
+ nstored = 0;
+ }
+
+ if (k5_u2u_read_msg(k5_context, fd, &msg) < 0)
+ return(-1);
+
+ if ( msg.length <= len ) {
+ memcpy(buf, msg.data, msg.length);
+ nreturned += msg.length;
+ nstored = 0;
+ } else {
+ memcpy(buf, msg.data, len);
+ nreturned += len;
+
+ if ( msg.length - len < sizeof(storage) ) {
+ store_ptr = storage;
+ nstored = msg.length - len;
+ memcpy(storage,msg.data+len,nstored);
+ } else {
+ nstored = 0;
+ return(-1);
+ }
+ }
+ return(nreturned);
+}
+
+int
+krb5_u2u_write(fd, buf, len)
+ int fd;
+ char *buf;
+ int len;
+{
+ krb5_data msg;
+
+ msg.length = len;
+ msg.data = buf;
+
+ if ( k5_u2u_write_msg(k5_context, fd, &msg) < 0 )
+ return(-1);
+ else
+ return(len);
+}
+
+#endif /* KRB5_U2U */
+#endif /* CK_KERBEROS */
+
+#ifdef CK_FORWARD_X
+/*
+
+Copyright (c) 1988 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+/* Modified for stand-alone compiling by
+ * Peter 'Luna' Runestig <peter@runestig.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <time.h>
+#define Time_t time_t
+
+void
+XauDisposeAuth (auth)
+Xauth *auth;
+{
+ if (auth) {
+ if (auth->address) (void) free (auth->address);
+ if (auth->number) (void) free (auth->number);
+ if (auth->name) (void) free (auth->name);
+ if (auth->data) {
+ (void) bzero (auth->data, auth->data_length);
+ (void) free (auth->data);
+ }
+ free ((char *) auth);
+ }
+ return;
+}
+
+char *
+XauFileName ()
+{
+ char *slashDotXauthority = "/.Xauthority";
+ char *name;
+ static char *buf=NULL;
+ static int bsize=0;
+ int size, namelen;
+ extern char * tn_fwdx_xauthority;
+
+ if ( tn_fwdx_xauthority )
+ return(tn_fwdx_xauthority);
+
+ if (name = getenv ("XAUTHORITY"))
+ return(name);
+ name = zhome();
+ if ( !name )
+ return(NULL);
+ namelen = strlen (name);
+ size = namelen + strlen(slashDotXauthority) + 1;
+ if (size > bsize) {
+ if (buf)
+ free (buf);
+ buf = malloc ((unsigned) size);
+ if (!buf)
+ return 0;
+ bsize = size;
+ }
+ ckstrncpy (buf, name, bsize);
+ if ( name[namelen-1] != '/'
+#ifdef OS2
+ && name[namelen-1] != '\\'
+#endif /* OS2 */
+ )
+ ckstrncat (buf, slashDotXauthority, bsize);
+ else
+ ckstrncat (buf, &slashDotXauthority[1], bsize);
+ return(buf);
+}
+
+static int
+binaryEqual (a, b, len)
+register char *a, *b;
+register int len;
+{
+ while (len--)
+ if (*a++ != *b++)
+ return 0;
+ return 1;
+}
+
+#ifndef R_OK
+#define R_OK 04
+#endif /* R_OK */
+
+Xauth *
+XauGetAuthByAddr (family, address_length, address,
+ number_length, number,
+ name_length, name)
+unsigned int family;
+unsigned int address_length;
+const char *address;
+unsigned int number_length;
+const char *number;
+unsigned int name_length;
+const char *name;
+{
+ FILE *auth_file;
+ char *auth_name;
+ Xauth *entry;
+
+ auth_name = XauFileName();
+ if (!auth_name)
+ return 0;
+ if (access (auth_name, R_OK) != 0) /* checks REAL id */
+ return 0;
+ auth_file = fopen (auth_name, "rb");
+ if (!auth_file)
+ return 0;
+ for (;;) {
+ entry = XauReadAuth (auth_file);
+ if (!entry)
+ break;
+ /*
+ * Match when:
+ * either family or entry->family are FamilyWild or
+ * family and entry->family are the same
+ * and
+ * either address or entry->address are empty or
+ * address and entry->address are the same
+ * and
+ * either number or entry->number are empty or
+ * number and entry->number are the same
+ * and
+ * either name or entry->name are empty or
+ * name and entry->name are the same
+ */
+
+/* if ((family == FamilyWild || entry->family == FamilyWild ||
+ (entry->family == family &&
+ address_length == entry->address_length &&
+ binaryEqual (entry->address, address, (int)address_length))) &&
+ (number_length == 0 || entry->number_length == 0 ||
+ (number_length == entry->number_length &&
+ binaryEqual (entry->number, number, (int)number_length))) &&
+ (name_length == 0 || entry->name_length == 0 ||
+ (entry->name_length == name_length &&
+ binaryEqual (entry->name, name, (int)name_length)))) */
+ /* the original matching code above doesn't seem to meet the matching
+ * algorithm, it doesn't check if "address_length == 0 ||
+ * entry->address_length == 0". / Luna 2000-02-09
+ */
+ if ((family == FamilyWild || entry->family == FamilyWild ||
+ entry->family == family) &&
+ (address_length == 0 || entry->address_length == 0 ||
+ (address_length == entry->address_length &&
+ binaryEqual (entry->address, address, (int)address_length))) &&
+ (number_length == 0 || entry->number_length == 0 ||
+ (number_length == entry->number_length &&
+ binaryEqual (entry->number, number, (int)number_length))) &&
+ (name_length == 0 || entry->name_length == 0 ||
+ (entry->name_length == name_length &&
+ binaryEqual (entry->name, name, (int)name_length))))
+ break;
+ XauDisposeAuth (entry);
+ }
+ (void) fclose (auth_file);
+ return entry;
+}
+
+static int
+read_short (shortp, file)
+unsigned short *shortp;
+FILE *file;
+{
+ unsigned char file_short[2];
+
+ if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ *shortp = file_short[0] * 256 + file_short[1];
+ return 1;
+}
+
+static int
+read_counted_string (countp, stringp, file)
+unsigned short *countp;
+char **stringp;
+FILE *file;
+{
+ unsigned short len;
+ char *data;
+
+ if (read_short (&len, file) == 0)
+ return 0;
+ if (len == 0) {
+ data = 0;
+ } else {
+ data = malloc ((unsigned) len);
+ if (!data)
+ return 0;
+ if (fread (data, (int) sizeof (char), (int) len, file) != len) {
+ bzero (data, len);
+ free (data);
+ return 0;
+ }
+ }
+ *stringp = data;
+ *countp = len;
+ return 1;
+}
+
+Xauth *
+XauReadAuth (auth_file)
+FILE *auth_file;
+{
+ Xauth local;
+ Xauth *ret;
+
+ if (read_short (&local.family, auth_file) == 0)
+ return 0;
+ if (read_counted_string (&local.address_length,
+ &local.address, auth_file) == 0)
+ return 0;
+ if (read_counted_string (&local.number_length,
+ &local.number, auth_file) == 0) {
+ if (local.address) free (local.address);
+ return 0;
+ }
+ if (read_counted_string (&local.name_length,
+ &local.name, auth_file) == 0) {
+ if (local.address) free (local.address);
+ if (local.number) free (local.number);
+ return 0;
+ }
+ if (read_counted_string (&local.data_length,
+ &local.data, auth_file) == 0) {
+ if (local.address) free (local.address);
+ if (local.number) free (local.number);
+ if (local.name) free (local.name);
+ return 0;
+ }
+ ret = (Xauth *) malloc (sizeof (Xauth));
+ if (!ret) {
+ if (local.address) free (local.address);
+ if (local.number) free (local.number);
+ if (local.name) free (local.name);
+ if (local.data) {
+ bzero (local.data, local.data_length);
+ free (local.data);
+ }
+ return 0;
+ }
+ *ret = local;
+ return ret;
+}
+
+static int
+write_short (s, file)
+unsigned short s;
+FILE *file;
+{
+ unsigned char file_short[2];
+
+ file_short[0] = (s & (unsigned)0xff00) >> 8;
+ file_short[1] = s & 0xff;
+ if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+static int
+write_counted_string (count, string, file)
+unsigned short count;
+char *string;
+FILE *file;
+{
+ if (write_short (count, file) == 0)
+ return 0;
+ if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
+ return 0;
+ return 1;
+}
+
+int
+XauWriteAuth (auth_file, auth)
+FILE *auth_file;
+Xauth *auth;
+{
+ if (write_short (auth->family, auth_file) == 0)
+ return 0;
+ if (write_counted_string (auth->address_length,
+ auth->address, auth_file) == 0)
+ return 0;
+ if (write_counted_string (auth->number_length,
+ auth->number, auth_file) == 0)
+ return 0;
+ if (write_counted_string (auth->name_length, auth->name, auth_file) == 0)
+ return 0;
+ if (write_counted_string (auth->data_length, auth->data, auth_file) == 0)
+ return 0;
+ return 1;
+}
+
+#ifdef KRB5
+#ifdef K5_XAUTH
+/*
+ * functions to encode/decode Kerberos V5 principals
+ * into something that can be reasonable spewed over
+ * the wire
+ *
+ * Author: Tom Yu <tlyu@MIT.EDU>
+ *
+ * Still needs to be fixed up wrt signed/unsigned lengths, but we'll worry
+ * about that later.
+ */
+
+/*
+ * XauKrb5Encode
+ *
+ * this function encodes the principal passed to it in a format that can
+ * easily be dealt with by stuffing it into an X packet. Encoding is as
+ * follows:
+ * length count of the realm name
+ * realm
+ * component count
+ * length of component
+ * actual principal component
+ * etc....
+ *
+ * Note that this function allocates a hunk of memory, which must be
+ * freed to avoid nasty memory leak type things. All counts are
+ * byte-swapped if needed. (except for the total length returned)
+ *
+ * nevermind.... stuffing the encoded packet in net byte order just to
+ * always do the right thing. Don't have to frob with alignment that way.
+ */
+int
+XauKrb5Encode(princ, outbuf)
+ krb5_principal princ; /* principal to encode */
+ krb5_data *outbuf; /* output buffer */
+{
+ CARD16 i, numparts, totlen = 0, plen, rlen;
+ char *cp, *pdata;
+
+ rlen = krb5_princ_realm(princ)->length;
+ numparts = krb5_princ_size(princ);
+ totlen = 2 + rlen + 2; /* include room for realm length
+ and component count */
+ for (i = 0; i < numparts; i++)
+ totlen += krb5_princ_component(princ, i)->length + 2;
+ /* add 2 bytes each time for length */
+ if ((outbuf->data = (char *)malloc(totlen)) == NULL)
+ return -1;
+ cp = outbuf->data;
+ *cp++ = (char)((int)(0xff00 & rlen) >> 8);
+ *cp++ = (char)(0x00ff & rlen);
+ memcpy(cp, krb5_princ_realm(princ)->data, rlen); /* safe */
+ cp += rlen;
+ *cp++ = (char)((int)(0xff00 & numparts) >> 8);
+ *cp++ = (char)(0x00ff & numparts);
+ for (i = 0; i < numparts; i++)
+ {
+ plen = krb5_princ_component(princ, i)->length;
+ pdata = krb5_princ_component(princ, i)->data;
+ *cp++ = (char)((int)(0xff00 & plen) >> 8);
+ *cp++ = (char)(0x00ff & plen);
+ memcpy(cp, pdata, plen); /* safe */
+ cp += plen;
+ }
+ outbuf->length = totlen;
+ return 0;
+}
+
+/*
+ * XauKrb5Decode
+ *
+ * This function essentially reverses what XauKrb5Encode does.
+ * return value: 0 if okay, -1 if malloc fails, -2 if inbuf format bad
+ */
+int
+XauKrb5Decode(inbuf, princ)
+ krb5_data inbuf;
+ krb5_principal *princ;
+{
+ CARD16 i, numparts, plen, rlen;
+ CARD8 *cp, *pdata;
+
+ if (inbuf.length < 4)
+ {
+ return -2;
+ }
+ *princ = (krb5_principal)malloc(sizeof (krb5_principal_data));
+ if (*princ == NULL)
+ return -1;
+ bzero(*princ, sizeof (krb5_principal_data));
+ cp = (CARD8 *)inbuf.data;
+ rlen = *cp++ << 8;
+ rlen |= *cp++;
+ if (inbuf.length < 4 + (int)rlen + 2)
+ {
+ krb5_free_principal(*princ);
+ return -2;
+ }
+ krb5_princ_realm(*princ)->data = (char *)malloc(rlen);
+ if (krb5_princ_realm(*princ)->data == NULL)
+ {
+ krb5_free_principal(*princ);
+ return -1;
+ }
+ krb5_princ_realm(*princ)->length = rlen;
+ memcpy(krb5_princ_realm(*princ)->data, cp, rlen); /* safe */
+ cp += rlen;
+ numparts = *cp++ << 8;
+ numparts |= *cp++;
+ krb5_princ_name(*princ) =
+ (krb5_data *)malloc(numparts * sizeof (krb5_data));
+ if (krb5_princ_name(*princ) == NULL)
+ {
+ krb5_free_principal(*princ);
+ return -1;
+ }
+ krb5_princ_size(*princ) = 0;
+ for (i = 0; i < numparts; i++)
+ {
+ if (cp + 2 > (CARD8 *)inbuf.data + inbuf.length)
+ {
+ krb5_free_principal(*princ);
+ return -2;
+ }
+ plen = *cp++ << 8;
+ plen |= *cp++;
+ if (cp + plen > (CARD8 *)inbuf.data + inbuf.length)
+ {
+ krb5_free_principal(*princ);
+ return -2;
+ }
+ pdata = (CARD8 *)malloc(plen);
+ if (pdata == NULL)
+ {
+ krb5_free_principal(*princ);
+ return -1;
+ }
+ krb5_princ_component(*princ, i)->data = (char *)pdata;
+ krb5_princ_component(*princ, i)->length = plen;
+ memcpy(pdata, cp, plen); /* safe */
+ cp += plen;
+ krb5_princ_size(*princ)++;
+ }
+ return 0;
+}
+#endif /* K5_XAUTH */
+#endif /* KRB5 */
+#endif /* CK_FORWARD_X */
+#endif /* CK_AUTHENTICATION */
+
+/* C K _ A U T H _ I N I T
+ * Initialize the Kerberos system for a pending connection
+ * hostname - a reverse DNS lookup of the hostname when possible
+ * ipaddr - the ip address of the host
+ * username - the name the user wants to connect under not necessarily
+ * the same as principal
+ * socket - the socket handle (ttyfd in Kermit speak)
+ *
+ * Returns: 1 on success and 0 on failure
+ */
+
+int
+#ifdef CK_ANSIC
+ck_auth_init( char * hostname, char * ipaddr, char * username, int socket )
+#else /* CK_ANSIC */
+ck_auth_init( hostname, ipaddr, username, socket )
+ char * hostname; char * ipaddr; char *username; int socket;
+#endif /* CK_ANSIC */
+{
+#ifdef CK_AUTHENTICATION
+#ifdef OS2
+ if ( !ck_security_loaddll() ) {
+ TELOPT_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ return(0);
+ }
+#endif /* OS2 */
+#endif /* CK_AUTHENTICAITON */
+#ifdef CK_ENCRYPTION
+ if ( !!ck_crypt_is_installed() ) {
+ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ }
+#endif /* CK_ENCRYPTION */
+
+ if (!hostname) hostname = "";
+ if (!ipaddr) ipaddr = "";
+ if (!username) username = "";
+
+ debug(F110,"ck_auth_init Username",username,0);
+ debug(F110,"ck_auth_init Hostname",hostname,0);
+ debug(F110,"ck_auth_init Ipaddr",ipaddr,0);
+
+ ckstrncpy( szUserName, username, UIDBUFLEN );
+ ckstrncpy( szHostName, hostname, UIDBUFLEN );
+ ckstrncpy( szIP, ipaddr, 16 );
+ szUserNameRequested[0] = '\0';
+ szUserNameAuthenticated[0] = '\0';
+ validUser = AUTH_REJECT;
+ accept_complete = 0;
+ authentication_version = AUTHTYPE_NULL;
+
+#ifdef CK_AUTHENTICATION
+ auth_how = 0;
+ auth_crypt = 0;
+ auth_fwd = 0;
+ mutual_complete = 0;
+ if ( sstelnet )
+ str_data[3] = TELQUAL_REPLY;
+ else
+ str_data[3] = TELQUAL_IS;
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_SRP
+ srp_waitresp = 0;
+#endif /* SRP */
+
+#ifdef CK_KERBEROS
+#ifdef KRB5
+ /* free previous ret_cred */
+ if ( ret_cred ) {
+#ifdef CK_ENCRYPTION
+#ifdef HEIMDAL
+ if ( k5_session_key == &ret_cred->session)
+ k5_session_key = NULL;
+#else /* HEIMDAL */
+ if ( k5_session_key == &ret_cred->keyblock)
+ k5_session_key = NULL;
+#endif /* HEIMDAL */
+#endif /* CK_ENCRYPTION */
+ krb5_free_creds(k5_context, ret_cred);
+ ret_cred = NULL;
+ }
+ if (k5_ticket) {
+ krb5_free_ticket(k5_context, k5_ticket);
+ k5_ticket = NULL;
+ }
+ /* and context */
+ if ( k5_context ) {
+ krb5_free_context(k5_context);
+ k5_context = NULL;
+ }
+
+ /* create k5_context */
+ krb5_init_context(&k5_context);
+#ifndef MIT_CURRENT
+#ifndef NO_KRB5_INIT_ETS
+/* This routine is a no-op in Kerberos 1.4.x and later */
+/* and in some installations it can't be found in which case */
+/* define NO_KRB5_INIT_ETS */
+ if (k5_context)
+ krb5_init_ets(k5_context);
+#endif /* NO_KRB5_INIT_ETS */
+#endif /* MIT_CURRENT */
+#ifdef KRB524_CONV
+ krb524_init_ets(k5_context);
+#endif /* KRB524_CONV */
+ memset(&k5_auth,0,sizeof(k5_auth));
+ if (auth_context) {
+ krb5_auth_con_free(k5_context, auth_context);
+ auth_context = 0;
+ }
+#ifdef CK_ENCRYPTION
+ if (k5_session_key) {
+ krb5_free_keyblock(k5_context, k5_session_key);
+ k5_session_key = 0;
+ }
+#endif /* ENCRYPTION */
+#ifdef TLS_VERIFY
+ krb5_tls_verified = 0;
+#endif /* TLS_VERIFY */
+#endif /* KRB5 */
+
+#ifdef KRB4
+#ifdef CK_ENCRYPTION
+ /* Initialize buffers used for authentication */
+ memset(&k4_session_key, 0, sizeof(k4_session_key));
+ memset(&k4_challenge, 0, sizeof(k4_challenge));
+#endif /* CK_ENCRYPTION */
+#endif /* KRB4 */
+
+#ifdef RLOGCODE
+ rlog_encrypt = 0;
+#endif /* RLOGCODE */
+ nstored = 0;
+ store_ptr = storage;
+ memset(storage,0,sizeof(storage));
+#endif /* CK_KERBEROS */
+
+#ifdef CK_ENCRYPTION
+ kstream_destroy();
+ if (!kstream_create_from_fd(socket, NULL))
+ return(0);
+#endif /* CK_ENCRYPTION */
+ return(1);
+}
+
+void
+auth_finished(result) int result; {
+ extern char uidbuf[];
+ extern int sstelnet;
+
+ validUser = result;
+ switch (result) {
+ case AUTH_REJECT: /* Rejected */
+ if (sstelnet)
+ uidbuf[0] = '\0';
+ authentication_version = AUTHTYPE_NULL;
+ break;
+ case AUTH_UNKNOWN: /* We don't know who he is, but he's okay */
+ if (sstelnet)
+ strcpy(uidbuf,"(unknown)");
+ break;
+ case AUTH_OTHER: /* We know him, but not his name */
+ if (sstelnet)
+ strcpy(uidbuf,"(other)");
+ break;
+ case AUTH_USER: /* We know he name */
+ case AUTH_VALID: /* We know him, and he needs no password */
+ if (sstelnet)
+ strcpy(uidbuf,szUserNameRequested);
+ break;
+ }
+}
+
+#ifdef MACOSX
+#ifdef KRB5
+
+krb5_error_code
+ck_krb5_write_message(krb5_context con, krb5_pointer ptr, krb5_data *data)
+{
+ int fd = *((int *)ptr);
+ long msglen;
+
+ msglen = htonl(data->length);
+ if (net_write(fd,(CHAR *)&msglen,4) != 4) {
+ return(-1);
+ }
+ if ( data->length ) {
+ if (net_write(fd,data->data,data->length) != data->length) {
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+krb5_error_code
+ck_krb5_read_message( krb5_context context,
+ krb5_pointer ptr,
+ krb5_data * data)
+{
+ extern int ttyfd;
+ int fd = *((int *)ptr);
+ long msglen;
+ char *p;
+ int i, rc;
+
+ if (net_read(fd,&msglen,4) < 0)
+ return(-1);
+
+ data->length = ntohl(msglen);
+ if ( data->length ) {
+ data->data = malloc(data->length);
+
+ i = 0;
+ while ( i < data->length ) {
+ if ((rc = net_read(fd,&data->data[i],(data->length - i))) < 0)
+ return(-1);
+ i += rc;
+ }
+ }
+ return(0);
+}
+#endif /* KRB5 */
+#endif /* MACOSX */
+#endif /* CK_SECURITY */
+
+
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuath.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckuath.h
new file mode 100644
index 0000000..914a06f
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuath.h
@@ -0,0 +1,235 @@
+/* C K U A T H . H -- "C-Kermit to Authentication" interface */
+
+/*
+ Author: Jeffrey E Altman <jaltman@secure-endpoints.com>,
+ Secure Endpoints Inc., New York City.
+
+ Copyright (C) 1999, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ * Based on a concatenation of all necessary include files distributed with
+ * the Kerberos 5 NT Alpha 2 Telnet package from MIT.
+ */
+
+#ifndef KRB5_KERMIT_H
+#define KRB5_KERMIT_H
+
+#ifndef BOOL
+#define BOOL int
+#endif
+
+/* Header file for encrypted-stream library.
+ * Written by Ken Raeburn (Raeburn@Cygnus.COM).
+ * Copyright (C) 1991, 1992, 1994 by Cygnus Support.
+ *
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef K5STREAM_H
+#define K5STREAM_H
+
+typedef void *kstream_ptr; /* Data send on the kstream */
+struct kstream_data_block {
+ kstream_ptr ptr;
+ size_t length;
+};
+
+typedef struct kstream_int { /* Object we pass around */
+ int fd; /* Open socket descriptor */
+ int (*encrypt)(struct kstream_data_block *, /* output */
+ struct kstream_data_block *); /* input */
+ int encrypt_type;
+ int (*decrypt)(struct kstream_data_block *, /* output */
+ struct kstream_data_block *); /* input */
+ int decrypt_type;
+} *kstream;
+
+/* Prototypes */
+
+int kstream_destroy();
+void kstream_set_buffer_mode(int);
+int kstream_create_from_fd(int fd, kstream_ptr);
+int kstream_write(void *, size_t);
+int kstream_read(void *, size_t);
+
+#endif /* K5STREAM_H */
+
+/*
+ * Implements Telnet authentication and encryption
+ */
+
+#ifndef TELNET_AUTH_H
+#define TELNET_AUTH_H
+
+int auth_parse(unsigned char *, int);
+
+int auth_init(kstream);
+
+void auth_destroy(void);
+
+int auth_encrypt(struct kstream_data_block *, struct kstream_data_block *);
+
+int auth_decrypt(struct kstream_data_block *, struct kstream_data_block *);
+
+extern BOOL forward_flag;
+extern BOOL forwardable_flag;
+extern BOOL forwarded_tickets;
+#endif /* TEL_AUTH_H */
+
+
+/* C-Kermit specific functions */
+_PROTOTYP(void auth_finished,(int));
+_PROTOTYP(int ck_auth_init, (char *, char *, char *, int));
+_PROTOTYP(int ck_tn_auth_valid, (VOID));
+_PROTOTYP(int ck_tn_auth_in_progress,(VOID));
+_PROTOTYP(int ck_tn_sb_auth, (char *, int));
+_PROTOTYP(int ck_tn_sb_encrypt, (char *, int));
+_PROTOTYP(int ck_tn_auth_request, (VOID));
+_PROTOTYP(void ck_tn_encrypt, (char *, int));
+_PROTOTYP(void ck_tn_decrypt, (char *, int));
+_PROTOTYP(void ck_tn_encrypt_start, (VOID));
+_PROTOTYP(void ck_tn_encrypt_stop, (VOID));
+_PROTOTYP(int ck_tn_authenticated, (VOID));
+#ifdef CK_ENCRYPTION
+_PROTOTYP(int ck_tn_encrypting, (VOID));
+_PROTOTYP(int ck_tn_decrypting, (VOID));
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+_PROTOTYP(int ck_tn_tls_negotiate, (VOID));
+_PROTOTYP(int SendSSLAuthSB, (int, void *, int));
+#endif /* CK_SSL */
+
+#ifdef CK_KERBEROS
+ /* Define MIT_CURRENT to compile the code for use with versions of */
+ /* Kerberos later than KRB5 1.0.5. Note. This will not compile */
+ /* successfully in Kermit 95 due to the segmentation of crypto */
+ /* into a separate DLL. */
+
+#ifndef KRB5_INIT_ETS
+/* krb5_init_ets() is a no-op in Kerberos 1.4.x and later */
+/* and in some installations it can't be found so now by default */
+/* we don't use it. */
+#define NO_KRB5_INIT_ETS
+#endif /* KRB5_INIT_ETS */
+
+#define KRB_DEFTIM 600 /* Default lifetime (minutes) */
+
+/* Kerberos structure definitions */
+
+struct krb_op_data { /* Operational data for all actions */
+ int version; /* Kerberos version */
+ char * cache; /* Kerberos cache file */
+};
+
+struct krb4_init_data { /* INITIALIZE data structure */
+ int lifetime;
+ char * principal; /* Principal string */
+ char * instance;
+ char * realm; /* Realm string */
+ char * password; /* Kerberos password */
+ int preauth; /* Use preauth mode? */
+ int verbose; /* Verbose output? */
+};
+
+#define KRB5_NUM_OF_ADDRS 16
+struct krb5_init_data { /* INITIALIZE data structure */
+ int forwardable; /* Switch values */
+ int proxiable; /* Correspond to switch names... */
+ int lifetime;
+ int renew;
+ int renewable;
+ int validate;
+ char * postdate;
+ char * service;
+ char * principal; /* Principal string */
+ char * instance;
+ char * realm; /* Realm string */
+ char * password; /* Kerberos password */
+ int preauth; /* Use preauth mode? */
+ int verbose; /* Verbose output? */
+ int getk4; /* Get K4 TGT? */
+ char * addrs[KRB5_NUM_OF_ADDRS+1]; /* List of IP Addresses */
+ int no_addresses; /* Do not include IP Addresses */
+};
+
+struct krb5_list_cred_data { /* List Credentials data */
+ int encryption;
+ int flags;
+ int addr;
+};
+
+_PROTOTYP(int ck_krb5_autoget_TGT, (char *));
+_PROTOTYP(int ck_krb5_initTGT, (struct krb_op_data *,struct krb5_init_data *,
+ struct krb4_init_data *));
+_PROTOTYP(int ck_krb5_destroy, (struct krb_op_data *));
+_PROTOTYP(int ck_krb5_list_creds, (struct krb_op_data *,
+ struct krb5_list_cred_data *));
+_PROTOTYP(char * ck_krb5_getrealm, (char *));
+_PROTOTYP(char * ck_krb5_getprincipal, (char *));
+_PROTOTYP(char * ck_krb5_get_cc_name, (VOID));
+
+_PROTOTYP(int ck_krb4_autoget_TGT, (char *));
+_PROTOTYP(int ck_krb4_initTGT, (struct krb_op_data *,struct krb4_init_data *));
+_PROTOTYP(int ck_krb4_destroy, (struct krb_op_data *));
+_PROTOTYP(int ck_krb4_list_creds, (struct krb_op_data *));
+_PROTOTYP(char * ck_krb4_getrealm, (VOID));
+_PROTOTYP(char * ck_krb4_getprincipal, (VOID));
+
+_PROTOTYP(int ck_krb4_get_tkts, (VOID));
+_PROTOTYP(char * ck_krb4_get_next_tkt, (VOID));
+_PROTOTYP(int ck_krb4_tkt_isvalid,(char *));
+_PROTOTYP(int ck_krb4_is_tgt_valid,(VOID));
+_PROTOTYP(int ck_krb4_tkt_time,(char *));
+
+_PROTOTYP(int ck_krb5_get_tkts, (char *));
+_PROTOTYP(char * ck_krb5_get_next_tkt, (VOID));
+_PROTOTYP(int ck_krb5_tkt_isvalid,(char *,char *));
+_PROTOTYP(char * ck_krb5_tkt_flags,(char *,char *));
+_PROTOTYP(int ck_krb5_is_tgt_valid,(VOID));
+_PROTOTYP(int ck_krb5_tkt_time,(char *,char *));
+
+_PROTOTYP(int krb4_des_avail,(int));
+_PROTOTYP(int krb4_des_write,(int,char *,int));
+_PROTOTYP(int krb4_des_read, (int,char *,int));
+_PROTOTYP(int krb5_des_avail,(int));
+_PROTOTYP(int krb5_des_write,(int,char *,int,int));
+_PROTOTYP(int krb5_des_read, (int,char *,int,int));
+_PROTOTYP(int krb5_u2u_avail,(int));
+_PROTOTYP(int krb5_u2u_write,(int,char *,int));
+_PROTOTYP(int krb5_u2u_read, (int,char *,int));
+_PROTOTYP(int k5_user_to_user_server_auth,(VOID));
+_PROTOTYP(int k5_user_to_user_client_auth,(VOID));
+#endif /* CK_KERBEROS */
+
+_PROTOTYP(int ck_krb5_is_installed,(void));
+_PROTOTYP(int ck_krb4_is_installed,(void));
+_PROTOTYP(int ck_srp_is_installed,(void));
+_PROTOTYP(int ck_ntlm_is_installed,(void));
+_PROTOTYP(int ck_crypt_is_installed,(void));
+_PROTOTYP(int ck_ssleay_is_installed,(void));
+_PROTOTYP(int ck_gssapi_is_installed,(void));
+_PROTOTYP(int ck_krypto_is_installed,(void));
+
+_PROTOTYP(VOID ck_encrypt_send_support,(VOID));
+_PROTOTYP(int ck_get_crypt_table,(struct keytab **, int *));
+_PROTOTYP(char * ck_krb4_realmofhost,(char *));
+_PROTOTYP(char * ck_krb5_realmofhost,(char *));
+
+#define FORWARD /* allow forwarding of credential */
+#ifdef FORWARD
+_PROTOTYP(int kerberos5_forward,(VOID));
+#endif /* FORWARD */
+
+#define AUTHTYPLSTSZ 8
+#endif /*KRB5_KERMIT_H*/
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckubwr.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckubwr.txt
new file mode 100644
index 0000000..38b064a
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckubwr.txt
@@ -0,0 +1,5363 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+C-Kermit Unix Hints and Tips
+
+ Frank da Cruz
+ [11]The Kermit Project, [12]Columbia University
+
+ As of: C-Kermit 9.0.302, 20 August 2011
+ This page last updated: Sun Aug 21 12:08:52 2011 (New York USA Time)
+
+ IF YOU ARE READING A PLAIN-TEXT version of this document, note it is
+ a plain-text dump of a Web page. You can visit the original (and
+ possibly more up-to-date) Web page here:
+
+ [13]http://www.columbia.edu/kermit/ckubwr.html
+
+ Since the material in this file has been accumulating since 1985,
+ some (much) of it might be dated.
+
+Known problems with C-Kermit 9.0
+
+ * Domain name resolution does not work in Solaris 10 or 11 (fixed in
+ [14]9.0.301).
+ * UUCP lockfile failure in FreeBSD 8 (fixed in [15]9.0.302).
+ * Build failure FreeBSD 9 (fixed in [16]9.0.302).
+ * Opening new SSH sessions after closing previous ones sometimes
+ fails.
+ * Heimdal Kerberos not supported.
+
+ [ [17]C-Kermit ] [ [18]Installation Instructions ] [ [19]TUTORIAL ]
+
+CONTENTS
+
+ 1. [20]INTRODUCTION
+ 2. [21]PREBUILT C-KERMIT BINARIES
+ 3. [22]PLATFORM-SPECIFIC NOTES
+ 4. [23]GENERAL UNIX-SPECIFIC LIMITATIONS AND BUGS
+ 5. [24]INITIALIZATION AND COMMAND FILES
+ 6. [25]COMMUNICATION SPEED SELECTION
+ 7. [26]COMMUNICATIONS AND DIALING
+ 8. [27]HARDWARE FLOW CONTROL
+ 9. [28]TERMINAL CONNECTION AND KEY MAPPING
+ 10. [29]FILE TRANSFER
+ 11. [30]EXTERNAL FILE TRANSFER PROTOCOLS
+ 12. [31]SECURITY
+ 13. [32]MISCELLANEOUS USER REPORTS
+ 14. [33]THIRD-PARTY DRIVERS
+
+ Quick Links: [ [34]Linux ] [ [35]*BSD ] [[36]Mac OS X] [ [37]AIX ] [
+ [38]HP-UX ] [ [39]Solaris ] [ [40]SCO ]
+
+1. INTRODUCTION
+
+ [ [41]Top ] [ [42]Contents ] [ [43]Next ]
+
+ SECTION CONTENTS
+
+ 1.1. [44]Documentation
+ 1.2. [45]Technical Support
+ 1.3. [46]The Year 2000
+ 1.4. [47]The Euro
+
+ THIS IS WHAT USED TO BE CALLED the "beware file" for the Unix version
+ of C-Kermit, previously distributed as ckubwr.txt and, before that, as
+ ckuker.bwr, after the fashion of old Digital Equipment Corporation
+ (DEC) software releases that came with release notes (describing what
+ had changed) and a "beware file" listing known bugs, limitations,
+ "non-goals", and things to watch out for. The C-Kermit beware file has
+ been accumulating since 1985, and it applies to many different hardware
+ platforms and operating systems, and many versions of them, so it is
+ quite large. Prior to C-Kermit 8.0, it was distributed only in
+ plain-text format. Now it is available as a Web document with links,
+ internal cross references, and so on, to make it easier to use.
+
+ This document applies to Unix C-Kermit in general, as well as to
+ specific Unix variations like [48]Linux, [49]AIX, [50]HP-UX,
+ [51]Solaris, and so on, and should be read in conjunction with the
+ [52]platform-independent C-Kermit beware file, which contains similar
+ information, but applying to all versions of C-Kermit (VMS, Windows,
+ OS/2, AOS/VS, VOS, etc, as well as to Unix).
+
+ There is much in this document that is (only) of historical interest.
+ The navigation links should help you skip directly to the sections that
+ are relevant to you. Numerous offsite Web links are supposed to lead to
+ further information but, as you know, Web links go stale frequently and
+ without warning. If you can supply additional, corrected, updated, or
+ better Web links, please feel free to [53]let me know.
+
+1.1. Documentation
+
+ [ [54]Top ] [ [55]Contents ] [ [56]Next ]
+
+ C-Kermit 6.0 is documented in the book [57]Using C-Kermit, Second
+ Edition, by Frank da Cruz and Christine M. Gianone, Digital Press,
+ Burlington, MA, USA, ISBN 1-55558-164-1 (1997), 622 pages. This remains
+ the definitive C-Kermit documentation. Until the third edition is
+ published (sorry, there is no firm timeframe for this), please also
+ refer to:
+
+ [58]Supplement to Using C-Kermit, Second Edition, For C-Kermit 7.0
+ Thorough documentation of features new to version 7.0.
+
+ [59]Supplement to Using C-Kermit, Second Edition, For C-Kermit 8.0
+ Thorough documentation of features new to version 8.0.
+
+ [60]Supplement to Using C-Kermit, Second Edition, For C-Kermit 9.0
+ Thorough documentation of features new to version 9.0.
+
+1.2. Technical Support
+
+ [ [61]Top ] [ [62]Contents ] [ [63]Section Contents ] [ [64]Next ] [
+ [65]Previous ]
+
+ For information on how to get technical support, please visit:
+
+ [66]http://www.columbia.edu/kermit/support.html
+
+1.3. The Year 2000
+
+ [ [67]Top ] [ [68]Contents ] [ [69]Section Contents ] [ [70]Next ] [
+ [71]Previous ]
+
+ The Unix version of C-Kermit, release 6.0 and later, is "Year 2000
+ compliant", but only if the underlying operating system is too. Contact
+ your Unix operating system vendor to find out which operating system
+ versions, patches, hardware, and/or updates are required. (Quite a few
+ old Unixes are still in operation in the new millenium, but with their
+ date set 28 years in the past so at least the non-year parts of the
+ calendar are correct.)
+
+ As of C-Kermit 6.0 (6 September 1996), post-millenium file dates are
+ recognized, transmitted, received, and reproduced correctly during the
+ file transfer process in C-Kermit's File Attribute packets. If
+ post-millenium dates are not processed correctly on the other end, file
+ transfer still takes place, but the modification or creation date of
+ the received file might be incorrect. The only exception would be if
+ the "file collision update" feature is being used to prevent
+ unnecessary transfer of files that have not changed since the last time
+ a transfer took place; in this case, a file might be transferred
+ unnecessarily, or it might not be transferred when it should have been.
+ Correct operation of the update feature depends on both Kermit programs
+ having the correct date and time.
+
+ Of secondary importance are the time stamps in the transaction and/or
+ debug logs, and the date-related script programming constructs, such as
+ \v(date), \v(ndate), \v(day), \v(nday), and perhaps also the
+ time-related ones, \v(time) and \v(ntime), insofar as they might be
+ affected by the date. The \v(ndate) is a numeric-format date of the
+ form yyyymmdd, suitable for both lexical and numeric comparison and
+ sorting: e.g. 19970208 or 20011231. If the underlying operating system
+ returns the correct date information, these variables will have the
+ proper values. If not, then scripts that make decisions based on these
+ variables might not operate correctly.
+
+ Most date-related code is based upon the C Library asctime() string,
+ which always has a four-digit year. In Unix, the one bit of code in
+ C-Kermit that is an exception to this rule is several calls to
+ localtime(), which returns a pointer to a tm struct, in which the year
+ is presumed to be expressed as "years since 1900". The code depends on
+ this assumption. Any platforms that violate it will need special
+ coding. As of this writing, no such platforms are known.
+
+ Command and script programming functions that deal with dates use
+ C-Kermit specific code that always uses full years.
+
+1.4. The Euro
+
+ [ [72]Top ] [ [73]Contents ] [ [74]Section Contents ] [ [75]Previous ]
+
+ C-Kermit 7.0 and later support Unicode (ISO 10646), ISO 8859-15 Latin
+ Alphabet 9, PC Code Page 858, Windows Code Pages 1250 and 1251, and
+ perhaps other character sets, that encode the Euro symbol, and can
+ translate among them as long as no intermediate character-set is
+ involved that does not include the Euro.
+
+2. PREBUILT C-KERMIT BINARIES
+
+ [ [76]Top ] [ [77]Contents ] [ [78]Next ] [ [79]Previous ]
+
+ It is often dangerous to run a binary C-Kermit (or any other) program
+ built on a different computer. Particularly if that computer had a
+ different C compiler, libraries, operating system version, processor
+ features, etc, and especially if the program was built with shared
+ libraries, because as soon as you update the libraries on your system,
+ they no longer match the ones referenced in the binary, and the binary
+ might refuse to load when you run it, in which case you'll see error
+ messages similar to:
+
+ Could not load program kermit
+ Member shr4.o not found or file not an archive
+ Could not load library libcurses.a[shr4.o]
+ Error was: No such file or directory
+
+ (These samples are from AIX.) To avoid this problem, we try to build
+ C-Kermit with statically linked libraries whenever we can, but this is
+ increasingly impossible as shared libraries become the norm.
+
+ It is often OK to run a binary built on an earlier OS version, but it
+ is rarely possible (or safe) to run a binary built on a later one, for
+ example to run a binary built under Solaris 8 on Solaris 2.6. Sometimes
+ even the OS-or-library patch/ECO level makes a difference.
+
+ A particularly insidious problem occurs when a binary was built on a
+ version of the OS that has patches from the vendor (e.g. to libraries);
+ in many cases you won't be able to run such a binary on an unpatched
+ version of the same platform.
+
+ When in doubt, build C-Kermit from the source code on the computer
+ where it is to be run (if possible!). If not, ask us for a binary
+ specific to your configuration. We might have one, and if we don't, we
+ might be able to find somebody who will build one for you.
+
+3. NOTES ON SPECIFIC UNIX VERSIONS
+
+ [ [80]Top ] [ [81]Contents ] [ [82]Next ] [ [83]Previous ]
+
+ SECTION CONTENTS
+
+ 3.0. [84]C-KERMIT ON PC-BASED UNIXES
+ 3.1. [85]C-KERMIT AND AIX
+ 3.2. [86]C-KERMIT AND HP-UX
+ 3.3. [87]C-KERMIT AND LINUX
+ 3.4. [88]C-KERMIT AND NEXTSTEP
+ 3.5. [89]C-KERMIT AND QNX
+ 3.6. [90]C-KERMIT AND SCO
+ 3.7. [91]C-KERMIT AND SOLARIS
+ 3.8. [92]C-KERMIT AND SUNOS
+ 3.9. [93]C-KERMIT AND ULTRIX
+ 3.10. [94]C-KERMIT AND UNIXWARE
+ 3.11. [95]C-KERMIT AND APOLLO SR10
+ 3.12. [96]C-KERMIT AND TANDY XENIX 3.0
+ 3.13. [97]C-KERMIT AND OSF/1 (DIGITAL UNIX) (TRU64 UNIX)
+ 3.14. [98]C-KERMIT AND SGI IRIX
+ 3.15. [99]C-KERMIT AND THE BEBOX
+ 3.16. [100]C-KERMIT AND DG/UX
+ 3.17. [101]C-KERMIT AND SEQUENT DYNIX
+ 3.18. [102]C-KERMIT AND {FREE,OPEN,NET}BSD
+ 3.19. [103]C-KERMIT AND MAC OS X
+ 3.20. [104]C-KERMIT AND COHERENT
+
+ The following sections apply to specific Unix versions. Most of them
+ contain references to FAQs (Frequently Asked Questions), but these tend
+ to be ephemeral. For possibly more current information see:
+
+ [105]http://www.faqs.org
+ [106]http://aplawrence.com/Unixart/newtounix.html
+
+ One thread that runs through many of them, and implicitly perhaps
+ through all, concerns the problems that occur when trying to dial out
+ on a serial device that is (also) enabled for dialing in. The
+ "solutions" to this problem are many, varied, diverse, and usually
+ gross, involving configuring the device for bidirectional use. This is
+ done in a highly OS-dependent and often obscure manner, and the effects
+ (good or evil) are also highly dependent on the particular OS (and
+ getty variety, etc). Many examples are given in the [107]OS-specific
+ sections below.
+
+ An important point to keep in mind is that C-Kermit is a
+ cross-platform, portable software program. It was not designed
+ specifically and only for your particular Unix version, or for that
+ matter, for Unix in particular at all. It also runs on VMS, AOS/VS,
+ VOS, and other non-Unix platforms. All the Unix versions of C-Kermit
+ share common i/o modules, with compile-time #ifdef constructions used
+ to account for the differences among the many Unix products and
+ releases. If you think that C-Kermit is behaving badly or missing
+ something on your particular Unix version, you might be right -- we
+ can't claim to be expert in hundreds of different OS / version /
+ hardware / library combinations. If you're a programmer, take a look at
+ the source code and [108]send us your suggested fixes or changes. Or
+ else just [109]send us a report about what seems to be wrong and we'll
+ see what we can do.
+
+3.0. C-KERMIT ON PC-BASED UNIXES
+
+ [ [110]Top ] [ [111]Contents ] [ [112]Section Contents ] [ [113]Next ]
+
+ Also see: [114]http://www.pcunix.com/.
+
+ SECTION CONTENTS
+
+ 3.0.1. [115]Interrupt Conflicts
+ 3.0.2. [116]Windows-Specific Hardware
+ 3.0.3. [117]Modems
+ 3.0.4. [118]Character Sets
+ 3.0.5. [119]Keyboard, Screen, and Mouse Access
+ 3.0.6. [120]Laptops
+
+3.0.1. Interrupt Conflicts
+
+ [ [121]Top ] [ [122]Contents ] [ [123]Section Contents ] [ [124]Next ]
+
+ PCs are not the best platform for real operating systems like Unix. The
+ architecture suffers from numerous deficiencies, not the least of which
+ is the stiflingly small number of hardware interrupts (either 7 or 15,
+ many of which are preallocated). Thus adding devices, using multiple
+ serial ports, etc, is always a challenge and often a nightmare. The
+ free-for-all nature of the PC market and the lack of standards combined
+ with the diversity of Unix OS versions make it difficult to find
+ drivers for any particular device on any particular version of Unix.
+
+ Of special interest to Kermit users is the fact that there is no
+ standard provision in the PC architecture for more than 2 communication
+ (serial) ports. COM3 and COM4 (or higher) will not work unless you (a)
+ find out the hardware address and interrupt for each, (b) find out how
+ to provide your Unix version with this information, and (c) actually
+ set up the configuration in the Unix startup files (or whatever other
+ method is used). Watch out for interrupt conflicts, especially when
+ using a serial mouse, and don't expect to be able to use more than two
+ serial ports.
+
+ The techniques for resolving interrupt conflicts are different for each
+ operating system (Linux, NetBSD, etc). In general, there is a
+ configuration file somewhere that lists COM ports, something like this:
+
+ com0 at isa? port 0x3f8 irq 4 # DOS COM1
+ com1 at isa? port 0x2f8 irq 3 # DOS COM2
+
+ The address and IRQ values in this file must agree with the values in
+ the PC BIOS and with the ports themselves, and there must not be more
+ than one device with the same interrupt. Unfortunately, due to the
+ small number of available interrupts, installing new devices on a PC
+ almost always creates a conflict. Here is a typical tale from a Linux
+ user (Fred Smith) about installing a third serial port:
+
+ ...problems can come from a number of causes. The one I fought with
+ for some time, and finally conquered, was that my modem is on an
+ add-in serial port, cua3/IRQ5. By default IRQ5 has a very low
+ priority, and does not get enough service in times when the system
+ is busy to prevent losing data. This in turn causes many resends.
+ There are two 'fixes' that I know of, one is to relax hard disk
+ interrupt hogging by using the correct parameter to hdparm, but I
+ don't like that one because the hdparm man page indicates it is
+ risky to use. The other one, the one I used, was to get 'irqtune'
+ and use it to give IRQ5 the highest priority instead of nearly the
+ lowest. Completely cured the problem.
+
+ Here's another one from a newsgroup posting:
+
+ After much hair pulling, I've discovered why my serial port won't
+ work. Apparently my [PC] has three serial devices (two comm ports
+ and an IR port), of which only two at a time can be active. I looked
+ in the BIOS setup and noticed that the IR port was activated, but
+ didn't realize at the time that this meant that COM2 was thereby
+ de-activated. I turned off the IR port and now the serial port works
+ as advertised.
+
+3.0.2. Windows-Specific Hardware
+
+ [ [125]Top ] [ [126]Contents ] [ [127]Section Contents ] [ [128]Next ]
+ [ [129]Previous ]
+
+ To complicate matters, the PC platform is becoming increasingly and
+ inexorably Windows-oriented. More and more add-on devices are "Windows
+ only" -- meaning they are incomplete and rely on proprietary
+ Windows-based software drivers to do the jobs that you would expect the
+ device itself to do. PCMCIA, PCI, or "Plug-n-Play" devices are rarely
+ supported on PC-based Unix versions such as SCO; Winmodems,
+ Winprinters, and the like are not supported on any Unix variety (with
+ [130]a few exceptions). The self-proclaimed Microsoft PC 97 (or later)
+ standard only makes matters worse since its only purpose to ensure that
+ PCs are "optimized to run Windows 95 and Windows NT 4.0 and future
+ versions of these operating systems".
+
+ With the exception noted (the Lucent modem, perhaps a handful of others
+ by the time you read this), drivers for "Win" devices are available
+ only for Windows, since the Windows market dwarfs that of any
+ particular Unix brand, and for that matter all Unixes (or for that
+ matter, all non-Windows operating systems) combined. If your version of
+ Unix (SCO, Linux, BSDI, FreeBSD, etc) does not support a particular
+ device, then C-Kermit can't use it either. C-Kermit, like any Unix
+ application, must access all devices through drivers and not directly
+ because Unix is a real operating system.
+
+ Don't waste time thinking that you, or anybody else, could write a
+ Linux (or other Unix) driver for a Winmodem or other "Win" device.
+ First of all, these devices generally require realtime control, but
+ since Unix is a true multitasking operating system, realtime device
+ control is not possible outside the kernel. Second, the specifications
+ for these devices are secret and proprietary, and each one (and each
+ version of each one) is potentially different. Third, a Winmodem driver
+ would be enormously complex; it would take years to write and debug, by
+ which time it would be obsolete.
+
+ A more recent generation of PCs (circa 1999-2000) is marketed as
+ "Legacy Free". One can only speculate what that could mean. Most likely
+ it means it will ONLY run the very latest versions of Windows, and is
+ made exclusively of Winmodems, Winprinters, Winmemory, and Win-CPU-fans
+ (Legacy Free is a concept [131]pioneered by Microsoft).
+
+ Before you buy a new PC or add-on equipment, especially serial ports,
+ internal modems, or printers, make sure they are compatible with your
+ version of Unix. This is becoming an ever-greater challenge; only a
+ huge company like Microsoft can afford to be constantly cranking out
+ and/or verifying drivers for the thousands of video boards, sound
+ cards, network adapters, SCSI adapters, buses, etc, that spew forth in
+ an uncontrolled manner from all corners of the world on a daily basis.
+ With very few exceptions, makers of PCs assemble the various components
+ and then verify them only with Windows, which they must do since they
+ are, no doubt, preloading the PC with Windows. To find a modern PC that
+ is capable of running a variety of non-Windows operating systems (e.g.
+ Linux, SCO OpenServer, Unixware, and Solaris) is a formidable challenge
+ requiring careful study of each vendor's "compatibility lists" and
+ precise attention to exact component model numbers and revision levels.
+
+3.0.3. Modems
+
+ [ [132]Top ] [ [133]Contents ] [ [134]Section Contents ] [ [135]Next ]
+ [ [136]Previous ]
+
+ External modems are recommended:
+
+ * They don't need any special drivers.
+ * You can use the lights and speaker to troubleshoot dialing.
+ * You can share them among all types of computers.
+ * You can easily turn them off and on when power-cycling seems
+ warranted.
+ * They are more likely to have manuals.
+
+ Internal PC modems (even when they are not Winmodems, which is
+ increasingly unlikely in new PCs) are always trouble, especially in
+ Unix. Even when they work for dialing out, they might not work for
+ dialing in, etc. Problems that occur when using an internal modem can
+ almost always be eliminated by switching to an external one. Even when
+ an internal modem is not a Winmodem or Plug-n-Play, it is often a
+ no-name model of unknown quality -- not the sort of thing you want
+ sitting directly on your computer's bus. (Even if it does not cause
+ hardware problems, it probably came without a command list, so no Unix
+ software will know how to control it.) For more about Unix compatible
+ modems, see:
+
+ [137]http://www.idir.net/~gromitkc/winmodem.html
+
+ Remember that PCs, even now -- more than two decades after they were
+ first introduced -- are not (in general) capable of supporting more
+ than 2 serial devices. Here's a short success story from a recent
+ newsgroup posting: "I have a Diamond SupraSonic II dual modem in my
+ machine. What I had to end up doing is buying a PS/2 mouse and port and
+ install it. Had to get rid of my serial mouse. I also had to disable
+ PnP in my computer bios. I was having IRQ conflicts between my serial
+ mouse and 'com 3'. Both modems work fine for me. My first modem is
+ ttyS0 and my second is ttyS1." Special third-party multiport boards
+ such as [138]DigiBoard are available for certain Unix platforms
+ (typically SCO, maybe Linux) that come with special platform-specific
+ drivers.
+
+3.0.4. Character Sets
+
+ [ [139]Top ] [ [140]Contents ] [ [141]Section Contents ] [ [142]Next ]
+ [ [143]Previous ]
+
+ PCs generally have PC code pages such as CP437 or CP850, and these are
+ often used by PC-based Unix operating systems, particularly on the
+ console. These are supported directly by C-Kermit's SET FILE
+ CHARACTER-SET and SET TERMINAL CHARACTER-SET commands. Some PC-based
+ Unix versions, such as recent Red Hat Linux releases, might also
+ support Microsoft Windows code pages such as CP1252, or even Latin
+ Alphabet 1 itself (perhaps displayed with CP437 glyphs). (And work is
+ in progress to support Unicode UTF8 in Linux.)
+
+ Certain Windows code pages are not supported directly by C-Kermit, but
+ since they are ISO Latin Alphabets with nonstandard "extensions" in the
+ C1 control range, you can substitute the corresponding Latin alphabet
+ (or other character set) in any C-Kermit character-set related
+ commands:
+
+ Windows Code Page Substitution
+ CP 1004 Latin-1
+ CP 1051 HP Roman-8
+
+ Other Windows code pages are mostly (or totally) incompatible with
+ their Latin Alphabet counterparts (e.g. CP1250 and Latin-2), and
+ several of these are already supported by C-Kermit 7.0 and later (1250,
+ 1251, and 1252).
+
+3.0.5. Keyboard, Screen, and Mouse Access
+
+ [ [144]Top ] [ [145]Contents ] [ [146]Section Contents ] [ [147]Next ]
+ [ [148]Previous ]
+
+ Finally, note that as a real operating system, Unix (unlike Windows)
+ does not provide the intimate connection to the PC keyboard, screen,
+ and mouse that you might expect. Unix applications can not "see" the
+ keyboard, and therefore can not be programmed to understand F-keys,
+ Editing keys, Arrow keys, Alt-key combinations, and the like. This is
+ because:
+
+ a. Unix is a portable operating system, not only for PCs;
+ b. Unix sessions can come from anywhere, not just the PC's own
+ keyboard and screen; and:
+ c. even though it might be possible for an application that actually
+ is running on the PC's keyboard and screen to access these devices
+ directly, there are no APIs (outside of X) for this.
+
+3.0.6. Laptops
+
+ [ [149]Top ] [ [150]Contents ] [ [151]Section Contents ] [
+ [152]Previous ]
+
+ (To be filled in . . .)
+
+3.1. C-KERMIT AND AIX
+
+ [ [153]Top ] [ [154]Contents ] [ [155]Section Contents ] [ [156]Next ]
+ [ [157]Previous ]
+
+ SECTION CONTENTS
+
+ 3.1.1. [158]AIX: General
+ 3.1.2. [159]AIX: Network Connections
+ 3.1.3. [160]AIX: Serial Connections
+ 3.1.4. [161]AIX: File Transfer
+ 3.1.5. [162]AIX: Xterm Key Map
+
+ For additional information see:
+ * [163]http://www.emerson.emory.edu/services/aix-faq/
+ * [164]http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.aix.html
+ * [165]http://www.cis.ohio-state.edu/hypertext/faq/usenet/aix-faq/top
+ .html
+ * [166]http://aixpdslib.seas.ucla.edu/
+ * [167]http://www.rootvg.net (AIX history)
+ * [168]ftp://rtfm.mit.edu/pub/usenet/news.answers/aix-faq/part1
+ * [169]ftp://mirrors.aol.com/pub/rtfm/usenet-by-hierarchy/comp/unix/a
+ ix
+
+ and/or read the [170]comp.unix.aix newsgroup.
+ ________________________________________________________________________
+
+3.1.1. AIX: General
+
+ [ [171]Top ] [ [172]Contents ] [ [173]Section Contents ] [ [174]Next ]
+
+ About AIX version numbers: "uname -a" tells the two-digit version
+ number, such as 3.2 or 4.1. The three-digit form can be seen with the
+ "oslevel" command (this information is unavailable at the API level and
+ is reportedly obtained by scanning the installed patch list).
+ Supposedly all three-digit versions within the same two-digit version
+ (e.g. 4.3.1, 4.3.2) are binary compatible; i.e. a binary built on any
+ one of them should run on all others, but who knows. Most AIX advocates
+ tell you that any AIX binary will run on any AIX version greater than
+ or equal to the one under which it was built, but experience with
+ C-Kermit suggests otherwise. It is always best to run a binary built
+ under your exact same AIX version, down to the third decimal place, if
+ possible. Ideally, build it from source code yourself. Yes, this advice
+ would be easier to follow if AIX came with a C compiler.
+ ________________________________________________________________________
+
+3.1.2. AIX: Network Connections
+
+ [ [175]Top ] [ [176]Contents ] [ [177]Section Contents ] [ [178]Next ]
+ [ [179]Previous ]
+
+ File transfers into AIX 4.2 or 4.3 through the AIX Telnet or Rlogin
+ server have been observed to fail (or accumulate huge numbers of
+ correctable errors, or even disconnect the session), when exactly the
+ same kind of transfers into AIX 4.1 work without incident, as do such
+ transfers into all non-AIX platforms on the same kind of connections
+ (with a few exceptions noted elsewhere in this document). AIX 4.3.3
+ seems to be particularly fragile in this regard; the weakness seems to
+ be in its pseudoterminal (pty) driver. High-speed streaming transfers
+ work perfectly, however, if the AIX Telnet server and pty driver are
+ removed from the picture; e.g, by using "set host * 3000" on AIX.
+
+ The problem can be completely cured by replacing the IBM Telnet server
+ with [180]MIT's Kerberos Telnet server -- even if you don't actually
+ use the Kerberos part. Diagnosis: AIX pseudoterminals (which are
+ controlled by the Telnet server to give you a login terminal for your
+ session) have quirks that not even IBM knows about. The situation with
+ AIX 5.x is not known, but if it has the same problem, the same cure is
+ available.
+
+ Meanwhile, the only remedy when going through the IBM Telnet server is
+ to cut back on Kermit's performance settings until you find a
+ combination that works:
+
+ * SET STREAMING OFF
+ * SET WINDOW-SIZE small-number
+ * SET { SEND, RECEIVE } PACKET-LENGTH small-number
+ * SET PREFIXING { CAUTIOUS, ALL }
+
+ In some cases, severe cutbacks are required, e.g. those implied by the
+ ROBUST command. Also be sure that the AIX C-Kermit on the remote end
+ has "set flow none" (which is the default). NOTE: Maybe this one can
+ also be addressed by starting AIX telnetd with the "-a" option. The
+ situation with SSH connections is not known, but almost certainly the
+ same.
+
+ When these problems occur, the system error log contains:
+
+ LABEL: TTY_TTYHOG
+ IDENTIFIER: 0873CF9F
+ Type: TEMP
+ Resource Name: pts/1
+
+ Description
+ TTYHOG OVER-RUN
+
+ Failure Causes
+ EXCESSIVE LOAD ON PROCESSOR
+
+ Recommended Actions
+ REDUCE SYSTEM LOAD.
+ REDUCE SERIAL PORT BAUD RATE
+
+ Before leaving the topic of AIX pseudoterminals, it is very likely that
+ Kermit's PTY and SSH commands do not work well either, for the same
+ reason that Telnet connections into AIX don't work well. A brief test
+ with "pty rlogin somehost" got a perfectly usable terminal (CONNECT)
+ session, but file-transfer problems like those just described.
+
+ Reportedly, telnet from AIX 4.1-point-something to non-Telnet ports
+ does not work unless the port number is in the /etc/services file; it's
+ not clear from the report whether this is a problem with AIX Telnet (in
+ which case it would not affect Kermit), or with the sockets library (in
+ which case it would). The purported fix is IBM APAR IX61523.
+
+ C-Kermit SET HOST or TELNET from one AIX 3.1 (or earlier) system to
+ another won't work right unless you set your local terminal type to
+ something other than AIXTERM. When your terminal type is AIXTERM, AIX
+ TELNET sends two escapes whenever you type one, and the AIX telnet
+ server swallows one of them. This has something to do with the "hft"
+ device. This behavior seems to be removed in AIX 3.2 and later.
+ ________________________________________________________________________
+
+3.1.3. AIX: Serial Connections
+
+ [ [181]Top ] [ [182]Contents ] [ [183]Section Contents ] [ [184]Next ]
+ [ [185]Previous ]
+
+ In AIX 3, 4, or 5, C-Kermit won't be able to "set line /dev/tty0" (or
+ any other dialout device) if you haven't installed "cu" or "uucp" on
+ your system, because installing these is what creates the UUCP lockfile
+ directory. If SET LINE commands always result in "Sorry, access to lock
+ denied", even when C-Kermit has been given the same owner, group, and
+ permissions as cu:
+
+ -r-sr-xr-x 1 uucp uucp 67216 Jul 27 1999 cu
+
+ and even when you run it as root, then you must go back and install
+ "cu" from your AIX installation media.
+
+ According to IBM's "From Strength to Strength" document (21 April
+ 1998), in AIX 4.2 and later "Async supports speeds on native serial
+ ports up to 115.2kbps". However, no API is documented to achieve serial
+ speeds higher than 38400 bps. Apparently the way to do this -- which
+ might or might not work only on the IBM 128-port multiplexer -- is:
+
+ cxma-stty fastbaud /dev/tty0
+
+ which, according to "man cxma-stty":
+
+ fastbaud Alters the baud rate table, so 50 baud becomes 57600 baud.
+ -fastbaud Restores the baud rate table, so 57600 baud becomes 50
+ baud.
+
+ Presumably (but not certainly) this extrapolates to 110 "baud" becomes
+ 76800 bps, and 150 becomes 115200 bps. So to use high serial speeds in
+ AIX 4.2 or 4.3, the trick would be to give the "cxma-stty fastbaud"
+ command for the desired tty device before starting Kermit, and then use
+ "set speed 50", "set speed 110", or "set speed 150" to select 56700,
+ 76800, or 115200 bps. It is not known whether cxma-stty requires
+ privilege.
+
+ According to one report, "Further investigation with IBM seems to
+ indicate that the only hardware capable of doing this is the 128-port
+ multiplexor with one (or more) of the 16 port breakout cables (Enhanced
+ Remote Async Node 16-Port EIA-232). We are looking at about CDN$4,000
+ in hardware just to hang a 56kb modem on there. Of course, we can then
+ hang 15 more, if we want. This hardware combo is described to be good
+ to 230.4kbps."
+
+ Another report says (quote from AIX newsgroup, March 1999):
+
+ The machine type and the adapter determine the speed that one can
+ actually run at. The older microchannel machines have much slower
+ crystal frequencies and may not go beyond 76,800. A feature put into
+ AIX 421 allows one to key in non-POSIX baud rates and if the uart
+ can support that speed, it will get set. this applies also to 43p's
+ and beyond. 115200 is the max for the 43P's native serial port. As
+ crytal frequencies continue to increase, the built-in serial ports
+ speeds will improve. To use 'uucp' or 'ate' at the higher baud
+ rates, configure the port for the desired speed, but set the speed
+ of uucp or ate to 50. Any non-POSIX speeds set in the ttys
+ configuration will the be used. In the case of the 128-port adapters
+ or the ISA 8-port or PCI 8-port adapter, there are only a few higher
+ baud rates.
+
+ a. Change the port to enable high baud rates:
+ + B50 for 57600
+ + B75 for 76800
+ + B110 for 115200
+ + B200 for 230000
+ b. chdev -l ttyX -a fastbaud=enable
+ + For the 128 ports original style rans, only 57600 bps is
+ supported.
+ + For the new enhanced RANs, up to 230Kbps is supported.
+
+ In AIX 2.2.1 on the RT PC with the 8-port multiplexer, SET SPEED 38400
+ gives 9600 bps, but SET SPEED 19200 gives 19200 (on the built-in S1
+ port).
+
+ Note that some RS/6000s (e.g. the IBM PowerServer 320) have nonstandard
+ rectangular 10-pin serial ports; the DB-25 connector is NOT a serial
+ port; it is a parallel printer port. IBM cables are required for the
+ serial ports, (The IBM RT PC also had rectangular serial ports --
+ perhaps the same as these, perhaps different.)
+
+ If you dial in to AIX through a modem that is connected directly to an
+ AIX port (e.g. on the 128-port multiplexer) and find that data is lost,
+ especially when uploading files to the AIX system (and system error
+ logs report buffer overruns on the port):
+
+ 1. Make sure the port and modem are BOTH configured for hardware
+ (RTS/CTS) flow control. The port is configured somewhere in the
+ system configuration, outside of Kermit.
+ 2. Tell C-Kermit to "set flow keep"; experimentation shows that SET
+ FLOW RTS/CTS has no effect when used in remote mode (i.e. on
+ /dev/tty, as opposed to a specify port device).
+ 3. Fixes for bugs in the original AIX 4.2 tty (serial i/o) support and
+ other AIX bugs are available from IBM at:
+ [186]http://service.software.ibm.com/rs6000/
+
+ Downloads -> Software Fixes -> Download FixDist gets an application
+ for looking up known problems.
+
+ Many problems reported with bidirectional terminal lines on AIX 3.2.x
+ on the RS/6000. Workaround: don't use bidirectional terminal lines, or
+ write a shell-script wrapper for Kermit that turns getty off on the
+ line before starting Kermit, or before Kermit attempts to do the SET
+ LINE. (But note: These problems MIGHT be fixed in C-Kermit 6.0 and
+ later.) The commands for turning getty off and on (respectively) are
+ /usr/sbin/pdisable and /usr/sbin/penable.
+ ________________________________________________________________________
+
+3.1.4. AIX: File Transfer
+
+ [ [187]Top ] [ [188]Contents ] [ [189]Section Contents ] [ [190]Next ]
+ [ [191]Previous ]
+
+ Evidently AIX 4.3 (I don't know about earlier versions) does not allow
+ open files to be overwritten. This can cause Kermit transfers to fail
+ when FILE COLLISION is OVERWRITE, where they might work on other Unix
+ varieties or earlier AIX versions.
+
+ Transfer of binary -- and maybe even text -- files can fail in AIX if
+ the AIX terminal has particular port can have character-set translation
+ done for it by the tty driver. The following advice from a
+ knowledgeable AIX user:
+
+ [This feature] has to be checked (and set/cleared) with a separate
+ command, unfortunately stty doesn't handle this. To check:
+
+ $ setmaps
+ input map: none installed
+ output map: none installed
+
+ If it says anything other than "none installed" for either one, it
+ is likely to cause a problem with kermit. To get rid of installed
+ maps:
+
+ $ setmaps -t NOMAP
+
+ However, I seem to recall that with some versions of AIX before
+ 3.2.5, only root could change the setting. I'm not sure what
+ versions - it might have only been under AIX 3.1 that this was true.
+ At least with AIX 3.2.5 an ordinary user can set or clear the maps.
+
+ On the same problem, another knowledgeable AIX user says:
+
+ The way to get information on the NLS mapping under AIX (3.2.5
+ anyway) is as follows. From the command line type:
+
+ lsattr -l tty# -a imap -a omap -E -H
+
+ Replace the tty number for the number sign above. This will give a
+ human readable output of the settings that looks like this;
+
+ # lsattr -l tty2 -a imap -a omap -E -H
+ attribute value description user_settable
+
+ imap none INPUT map file True
+ omap none OUTPUT map file True
+
+ If you change the -H to a -O, you get output that can easily be
+ processed by another program or a shell script, for example:
+
+ # lsattr -l tty2 -a imap -a omap -E -O
+ #imap:omap
+ none:none
+
+ To change the settings from the command line, the chdev command is
+ used with the following syntax.
+
+ chdev -l tty# -a imap='none' -a omap='none'
+
+ Again substituting the appropriate tty port number for the number
+ sign, "none" being the value we want for C-Kermit. Of course, the
+ above can also be changed by using the SMIT utility and selecting
+ devices - tty. (...end quote)
+
+ In 2007 I noticed the following on high-speed SSH connections (local
+ network) into AIX 5.3: streaming transfers into AIX just don't work.
+ The same might be true for Telnet connections; I have no way to check.
+ It appears that the AIX pty driver and/or the SSH (and possibly Telnet)
+ server are not capable of receiving a steady stream of incoming data at
+ high speed. Solution: unknown. Workaround: put "set streaming off" in
+ your .kermrc or .mykermrc file, since streaming is the default for
+ network connections.
+ ________________________________________________________________________
+
+3.1.5. AIX: Xterm Key Map
+
+ [ [192]Top ] [ [193]Contents ] [ [194]Section Contents ] [
+ [195]Previous ]
+
+ Here is a sample configuration for setting up an xterm keyboard for
+ VT220 or higher terminal emulation on AIX, courtesy of Bruce Momjian,
+ Drexel Hill, PA. Xterm can be started like this:
+
+ xterm $XTERMFLAGS +rw +sb +ls $@ -tm 'erase ^? intr ^c' -name vt220 \
+ -title vt220 -tn xterm-220 "$@" &
+
+---------------------------------------------------------------------------
+ XTerm*VT100.Translations: #override \n\
+ <Key>Home: string(0x1b) string("[3~") \n \
+ <Key>End: string(0x1b) string("[4~") \n
+ vt220*VT100.Translations: #override \n\
+ Shift <Key>F1: string("[23~") \n \
+ Shift <Key>F2: string("[24~") \n \
+ Shift <Key>F3: string("[25~") \n \
+ Shift <Key>F4: string("[26~") \n \
+ Shift <Key>F5: string("[K~") \n \
+ Shift <Key>F6: string("[31~") \n \
+ Shift <Key>F7: string("[31~") \n \
+ Shift <Key>F8: string("[32~") \n \
+ Shift <Key>F9: string("[33~") \n \
+ Shift <Key>F10: string("[34~") \n \
+ Shift <Key>F11: string("[28~") \n \
+ Shift <Key>F12: string("[29~") \n \
+ <Key>Print: string(0x1b) string("[32~") \n\
+ <Key>Cancel: string(0x1b) string("[33~") \n\
+ <Key>Pause: string(0x1b) string("[34~") \n\
+ <Key>Insert: string(0x1b) string("[2~") \n\
+ <Key>Delete: string(0x1b) string("[3~") \n\
+ <Key>Home: string(0x1b) string("[1~") \n\
+ <Key>End: string(0x1b) string("[4~") \n\
+ <Key>Prior: string(0x1b) string("[5~") \n\
+ <Key>Next: string(0x1b) string("[6~") \n\
+ <Key>BackSpace: string(0x7f) \n\
+ <Key>Num_Lock: string(0x1b) string("OP") \n\
+ <Key>KP_Divide: string(0x1b) string("Ol") \n\
+ <Key>KP_Multiply: string(0x1b) string("Om") \n\
+ <Key>KP_Subtract: string(0x1b) string("OS") \n\
+ <Key>KP_Add: string(0x1b) string("OM") \n\
+ <Key>KP_Enter: string(0x1b) string("OM") \n\
+ <Key>KP_Decimal: string(0x1b) string("On") \n\
+ <Key>KP_0: string(0x1b) string("Op") \n\
+ <Key>KP_1: string(0x1b) string("Oq") \n\
+ <Key>KP_2: string(0x1b) string("Or") \n\
+ <Key>KP_3: string(0x1b) string("Os") \n\
+ <Key>KP_4: string(0x1b) string("Ot") \n\
+ <Key>KP_5: string(0x1b) string("Ou") \n\
+ <Key>KP_6: string(0x1b) string("Ov") \n\
+ <Key>KP_7: string(0x1b) string("Ow") \n\
+ <Key>KP_8: string(0x1b) string("Ox") \n\
+ <Key>KP_9: string(0x1b) string("Oy") \n
+
+ ! <Key>Up: string(0x1b) string("[A") \n\
+ ! <Key>Down: string(0x1b) string("[B") \n\
+ ! <Key>Right: string(0x1b) string("[C") \n\
+ ! <Key>Left: string(0x1b) string("[D") \n\
+
+ *visualBell: true
+ *saveLines: 1000
+ *cursesemul: true
+ *scrollKey: true
+ *scrollBar: true
+
+3.2. C-KERMIT AND HP-UX
+
+ [ [196]Top ] [ [197]Contents ] [ [198]Section Contents ] [ [199]Next ]
+ [ [200]Previous ]
+
+ SECTION CONTENTS
+
+ 3.2.0. [201]Common Problems
+ 3.2.1. [202]Building C-Kermit on HP-UX
+ 3.2.2. [203]File Transfer
+ 3.2.3. [204]Dialing Out and UUCP Lockfiles in HP-UX
+ 3.2.4. [205]Notes on Specific HP-UX Releases
+ 3.2.5. [206]HP-UX and X.25
+
+ REFERENCES
+
+ For further information, read the [207]comp.sys.hp.hpux newsgroup.
+
+ C-Kermit is included as part of the HP-UX operating system by contract
+ between Hewlett Packard and Columbia University for HP-UX 10.00 and
+ later. Each level of HP-UX includes a freshly built C-Kermit binary in
+ /bin/kermit, which should work correctly. Binaries built for regular
+ HP-UX may be used on Trusted HP-UX and vice-versa, except for use as
+ IKSD because of the different authentication methods.
+
+ Note that HP does not update C-Kermit versions for any but its most
+ current HP-UX release. So, for example, HP-UX 10.20 has C-Kermit 6.0;
+ 11.00 has C-Kermit 7.0, and 11.22 has 8.0. Of course, as with all
+ software, older Kermit versions have bugs (such as buffer overflow
+ vulnerabilities) that are fixed in later versions. From time to time,
+ HP discovers one of these (long-ago fixed) bugs and issues a security
+ alert for the older OS's, recommending some draconian measure to avoid
+ the problem. The true fix in each situation is to install the current
+ release of C-Kermit.
+
+3.2.0. Common Problems
+
+ [ [208]Top ] [ [209]Contents ] [ [210]Section Contents ] [ [211]Next ]
+
+ Some HP workstations have a BREAK/RESET key. If you hit this key while
+ C-Kermit is running, it might kill or suspend the C-Kermit process.
+ C-Kermit arms itself against these signals, but evidently the
+ BREAK/RESET key is -- at least in some circumstances, on certain HP-UX
+ versions -- too powerful to be caught. (Some report that the first
+ BREAK/RESET shows up as SIGINT and is caught by C-Kermit's former
+ SIGINT handler even when SIGINT is currently set to SIG_IGN; the second
+ kills Kermit; other reports suggest the first BREAK/RESET sends a
+ SIGTSTP (suspend signal) to Kermit, which it catches and suspends
+ itself. You can tell C-Kermit to ignore suspend signals with SET
+ SUSPEND OFF. You can tell C-Kermit to ignore SIGINT with SET COMMAND
+ INTERRUPTION OFF. It is not known whether these commands also grant
+ immunity to the BREAK/RESET key (one report states that with SET
+ SUSPEND OFF, the BREAK/RESET key is ignored the first four times, but
+ kills Kermit the 5th time). In any case:
+
+ 1. If this key is mapped to SIGINT or SIGTSTP, C-Kermit catches or
+ ignores it, depending on which mode (CONNECT, command, etc) Kermit
+ is in.
+ 2. If it causes HP-UX to kill C-Kermit, there is nothing C-Kermit can
+ do to prevent it.
+
+ When HP-UX is on the remote end of the connection, it is essential that
+ HP-UX C-Kermit be configured for Xon/Xoff flow control (this is the
+ default, but in case you change it and then experience file-transfer
+ failures, this is a likely reason).
+
+3.2.1. Building C-Kermit on HP-UX
+
+ [ [212]Top ] [ [213]Contents ] [ [214]Section Contents ] [ [215]Next ]
+ [ [216]Previous ]
+
+ This section applies mainly to old (pre-10.20) HP-UX version on old,
+ slow, and/or memory-constrained hardware.
+
+ During the C-Kermit 6.0 Beta cycle, something happened to ckcpro.w (or,
+ more precisely, the ckcpro.c file that is generated from it) which
+ causes HP optimizing compilers under HP-UX versions 7.0 and 8.0
+ (apparently on all platforms) as well as under HP-UX 9.0 on Motorola
+ platforms only, to blow up. In versions 7.0 and 8.0 the problem has
+ spread to other modules.
+
+ The symptoms vary from the system grinding to a halt, to the compiler
+ crashing, to the compilation of the ckcpro.c module taking very long
+ periods of time, like 9 hours. This problem is handled by compiling the
+ modules that tickle it without optimization; the new C-Kermit makefile
+ takes care of this, and shows how to do it in case the same thing
+ begins happening with other modules.
+
+ On HP-UX 9.0, a kernel parameter, maxdsiz (maximum process data segment
+ size), seems to be important. On Motorola systems, it is 16MB by
+ default, whereas on RISC systems the default is much bigger. Increasing
+ maxdsiz to about 80MB seems to make the problem go away, but only if
+ the system also has a lot of physical memory -- otherwise it swaps
+ itself to death.
+
+ The optimizing compiler might complain about "some optimizations
+ skipped" on certain modules, due to lack of space available to the
+ optimizer. You can increase the space (the incantation depends on the
+ particular compiler version -- see the [217]makefile), but doing so
+ tends to make the compilations take a much longer time. For example,
+ the "hpux0100o+" makefile target adds the "+Onolimit" compiler flag,
+ and about an hour to the compile time on an HP-9000/730. But it *does*
+ produce an executable that is about 10K smaller :-)
+
+ In the makefile, all HP-UX entries automatically skip optimization of
+ problematic modules.
+
+3.2.2. File Transfer
+
+ [ [218]Top ] [ [219]Contents ] [ [220]Section Contents ] [ [221]Next ]
+ [ [222]Previous ]
+
+ Telnet connections into HP-UX versions up to and including 11.11 (and
+ possibly 11.20) tend not to lend themselves to file transfer due to
+ limitations, restrictions, and/or bugs in the HP-UX Telnet server
+ and/or pseudoterminal (pty) driver.
+
+ In C-Kermit 6.0 (1996) an unexpected slowness was noted when
+ transferring files over local Ethernet connections when an HP-UX system
+ (9.05 or 10.00) was on the remote end. The following experiment was
+ conducted to determine the cause. C-Kermit 6.0 was used; the situation
+ is slightly better using C-Kermit 7.0's streaming feature and HP-UX
+ 10.20 on the far end.
+
+ The systems were HP-UX 10.00 (on 715/33) and SunOS 4.1.3 (on Sparc-20),
+ both on the same local 10Mbps Ethernet, packet length 4096, parity
+ none, control prefixing "cautious", using only local disks on each
+ machine -- no NFS. In the C-Kermit 6.0 (ACK/NAK) case, the window size
+ was 20; in the streaming case there is no window size (i.e. it is
+ infinite). The test file was C-Kermit executable, transferred in binary
+ mode. Conditions were relatively poor: the Sun and the local net
+ heavily loaded; the HP system is old, slow, and memory-constrained.
+
+ C-Kermit 6.0... C-Kermit 7.0...
+ Local Remote ACK/NAK........ Streaming......
+ Client Server Send Receive Send Receive
+ Sun HP 36 18 64 18
+ HP HP 25 15 37 16
+ HP Sun 77 83 118 92
+ Sun Sun 60 60 153 158
+
+ So whenever HP is the remote we have poor performance. Why?
+
+ * Changing file display to CRT has no effect (so it's not the curses
+ library on the client side).
+ * Changing TCP RECV-BUFFER or SEND-BUFFER has little effect.
+ * Telling the client to make a binary-mode connection (SET TELNET
+ BINARY REQUESTED, which successfully negotiates a binary
+ connection) has no effect on throughput.
+
+ BUT... If I start HP-UX C-Kermit as a TCP service:
+
+ set host * 3000
+ server
+
+ and then from the client "set host xxx 3000", I get:
+
+ C-Kermit 6.0... C-Kermit 7.0...
+ Local Remote ACK/NAK........ Streaming......
+ Client Server Send Receive Send Receive
+ Sun HP 77 67 106 139
+ HP HP 50 50 64 62
+ HP Sun 57 85 155 105
+ Sun Sun 57 50 321 314
+
+ Therefore the HP-UX telnet server or pty driver seems to be adding more
+ overhead than the SunOS one, and most others. When going through this
+ type of connection (a remote telnet server) there is little Kermit can
+ do improve matters, since the telnet server and pty driver are between
+ the two Kermits, and neither Kermit program can have any influence over
+ them (except putting the Telnet connection in binary mode, but that
+ doesn't help).
+
+ (The numbers for the HP-HP transfers are lower than the others since
+ both Kermit processes are running on the same slow 33MHz CPU.)
+
+ Matters seem to have deteriorated in HP-UX 11. Now file transfers over
+ Telnet connections fail completely, rather than just being slow. In the
+ following trial, a Telnet connection was made from Kermit 95 to HP-UX
+ 11.11 on an HP-9000/785/B2000 over local 10Mbps Ethernet running
+ C-Kermit 8.00 in server mode (under the HP-UX Telnet server):
+
+ Text........ Binary......
+ Stream Pktlen GET SEND GET SEND
+ On 4000 Fail Fail Fail Fail
+ Off 4000 Fail Fail Fail Fail
+ Off 2000 OK Fail OK Fail
+ On 2000 OK Fail OK Fail
+ On 3000 Fail Fail Fail Fail
+ On 2500 Fail Fail Fail Fail
+ On 2047 OK Fail OK Fail
+ On 2045 OK Fail OK Fail
+ Off 500 OK OK OK OK
+ On 500 OK Fail OK Fail
+ On 240 OK Fail OK Fail
+
+ As you can see, downloads are problematic unless the receiver's Kermit
+ packet length is 2045 or less, but uploads work only with streaming
+ disabled and the packet length restricted to 500. To force file
+ transfers to work on this connection, the desktop Kermit must be told
+ to:
+
+ set streaming off
+ set receive packet-length 2000
+ set send packet-length 500
+
+ However, if a connection is made between the same two programs on the
+ same two computers over the same network, but this time a direct
+ socket-to-socket connection bypassing the HP-UX Telnet server and pty
+ driver (tell HP-UX C-Kermit to "set host /server * 3000 /raw"; tell
+ desktop client program to "set host blah 3000 /raw"), everything works
+ perfectly with the default Kermit settings (streaming, 4K packets,
+ liberal control-character unprefixing, 8-bit transparency, etc):
+
+ Text........ Binary......
+ Stream Pktlen GET SEND GET SEND
+ On 4000 OK OK OK OK
+
+ And in this case, transfer rates were approximately 900,000 cps. To
+ verify that the behavior reported here is not caused by the new Kermit
+ release, the same experiment was performed on a Telnet connection from
+ the same PC over the same network to the old 715/33 running HP-UX 10.20
+ and C-Kermit 8.00. Text and binary uploads and downloads worked
+ perfectly (albeit slowly) with all the default settings -- streaming,
+ 4K packets, etc.
+
+3.2.3. Dialing Out and UUCP Lockfiles in HP-UX
+
+ [ [223]Top ] [ [224]Contents ] [ [225]Section Contents ] [ [226]Next ]
+ [ [227]Previous ]
+
+ HP workstations do not come with dialout devices configured; you have
+ to do it yourself (as root). First look in /dev to see what's there;
+ for example in HP-UX 10.00 or later:
+
+ ls -l /dev/cua*
+ ls -l /dev/tty*
+
+ If you find a tty0p0 device but no cua0p0, you'll need to creat one if
+ you want to dial out; the tty0p0 does not work for dialing out. It's
+ easy: start SAM; in the main Sam window, double-click on Peripheral
+ Device, then in the Peripheral Devices window, double-click on
+ Terminals and Modems. In the Terminals and Modems dialog, click on
+ Actions, then choose "Add modem" and fill in the blanks. For example:
+ Port number 0, speed 57600 (higher speeds tend not to work reliably),
+ "Use device for calling out", do NOT "Receive incoming calls" (unless
+ you know what you are doing), leave "CCITT modem" unchecked unless you
+ really have one, and do select "Use hardware flow control (RTS/CTS)".
+ Then click OK. This creates cua0p0 as well as cul0p0 and ttyd0p0
+
+ If the following sequence:
+
+ set line /dev/cua0p0 ; or other device
+ set speed 115200 ; or other normal speed
+
+ produces the message "?Unsupported line speed". This means either that
+ the port is not configured for dialout (go into SAM as described above
+ and make sure "Use device for calling out" is selected), or else that
+ speed you have given (such as 460800) is supported by the operating
+ system but not by the physical device (in which case, use a lower speed
+ like 57600).
+
+ In HP-UX 9.0, serial device names began to change. The older names
+ looked like "/dev/cua00", "/dev/tty01", etc (sometimes with only one
+ digit). The newer names have two digits with the letter "p" in between.
+ HP-UX 8.xx and earlier have the older form, HP-UX 10.00 and later have
+ the newer form. HP-UX 9.xx has the newer form on Series 800 machines,
+ and the older form on other hardware models. The situation is
+ summarized in the following table (the Convio 10.0 column applies to
+ HP-UX 10 and 11).
+
+ Converged HP-UX Serial I/O Filenames : TTY Mux Naming
+ ---------------------------------------------------------------------
+ General meaning Old Form S800 9.0 Convio 10.0
+ ---------------------------------------------------------------------
+ tty* hardwired ports tty<YY> tty<X>p<Y> tty<D>p<p>
+ diag:mux<X> diag:mux<D>
+ ---------------------------------------------------------------------
+ ttyd* dial-in modems ttyd<YY> ttyd<X>p<Y> ttyd<D>p<p>
+ diag:ttyd<X>p<Y> diag:ttyd<D>p<p>
+ ---------------------------------------------------------------------
+ cua* auto-dial out cua<YY> cua<X>p<Y> cua<D>p<p>
+ diag:cua<X>p<Y>
+ ---------------------------------------------------------------------
+ cul* dial-out cul<YY> cul<X>p<Y> cul<D>p<p>
+ diag:cul<X>p<Y>
+ ---------------------------------------------------------------------
+ <X>= LU (Logical Unit) <D>= Devspec (decimal card instance)
+ <Y> or <YY> = Port <p>= Port
+
+ For dialing out, you should use the cua or cul devices. When C-Kermit's
+ CARRIER setting is AUTO or ON, C-Kermit should pop back to its prompt
+ automatically if the carrier signal drops, e.g. when you log out from
+ the remote computer or service. If you use the tty<D>p<d> (e.g. tty0p0)
+ device, the carrier signal should be ignored. The tty<D>p<d> device
+ should be used for direct connections where the carrier signal does not
+ follow RS-232 conventions (use the cul device for hardwired connections
+ through a true null modem). Do not use the ttyd<D>p<d> device for
+ dialing out.
+
+ Kermit's access to serial devices is controlled by "UUCP lockfiles",
+ which are intended to prevent different users using different software
+ programs (Kermit, cu, etc, and UUCP itself) from accessing the same
+ serial device at the same time. When a device is in use by a particular
+ user, a file with a special name is created in:
+
+ /var/spool/locks (HP-UX 10.00 and later)
+ /usr/spool/uucp (HP-UX 9.xx and earlier)
+
+ The file's name indicates the device that is in use, and its contents
+ indicates the process ID (pid) of the process that is using the device.
+ Since serial devices and the locks directory are not both publicly
+ readable and writable, Kermit and other communication software must be
+ installed setuid to the owner (bin) of the serial device and setgid to
+ the group (daemon) of the /var/spool/locks directory. Kermit's setuid
+ and setgid privileges are enabled only when opening the device and
+ accessing the lockfiles.
+
+ Let's say "unit" means a string of decimal digits (the interface
+ instance number) followed (in HP-UX 10.00 and later) by the letter "p"
+ (lowercase), followed by another string of decimal digits (the port
+ number on the interface), e.g.:
+
+ "0p0", "0p1", "1p0", etc (HP-UX 10.00 and later)
+ "0p0", "0p1", "1p0", etc (HP-UX 9.xx on Series 800)
+ "00", "01", "10", "0", etc (HP-UX 9.xx not on Series 800)
+ "00", "01", "10", "0", etc (HP-UX 8.xx and earlier)
+
+ Then a normal serial device (driver) name consists of a prefix ("tty",
+ "ttyd", "cua", "cul", or possibly "cuad" or "culd") followed by a unit,
+ e.g. "cua0p0". Kermit's treatment of UUCP lockfiles is as close as
+ possible to that of the HP-UX "cu" program. Here is a table of the
+ lockfiles that Kermit creates for unit 0p0:
+
+ Selection Lockfile 1 Lockfile 2
+ /dev/tty0p0 LCK..tty0p0 (none)
+* /dev/ttyd0p0 LCK..ttyd0p0 (none)
+ /dev/cua0p0 LCK..cua0p0 LCK..ttyd0p0
+ /dev/cul0p0 LCK..cul0p0 LCK..ttyd0p0
+ /dev/cuad0p0 LCK..cuad0p0 LCK..ttyd0p0
+ /dev/culd0p0 LCK..culd0p0 LCK..ttyd0p0
+ <other> LCK..<other> (none)
+
+ (* = Dialin device, should not be used.)
+
+ In other words, if the device name begins with "cu", a second lockfile
+ for the "ttyd" device, same unit, is created, which should prevent
+ dialin access on that device.
+
+ The <other> case allows for symbolic links, etc, but of course it is
+ not foolproof since we have no way of telling which device is really
+ being used.
+
+ When C-Kermit tries to open a dialout device whose name ends with a
+ "unit", it searches the lockfile directory for all possible names for
+ the same unit. For example, if user selects /dev/cul2p3, Kermit looks
+ for lockfiles named:
+
+ LCK..tty2p3
+ LCK..ttyd2p3
+ LCK..cua2p3
+ LCK..cul2p3
+ LCK..cuad2p3
+ LCK..culd2p3
+
+ If any of these files are found, Kermit opens them to find out the ID
+ (pid) of the process that created them; if the pid is still valid, the
+ process is still active, and so the SET LINE command fails and the user
+ is informed of the pid so s/he can use "ps" to find out who is using
+ the device.
+
+ If the pid is not valid, the file is deleted. If all such files (i.e.
+ with same "unit" designation) are successfully removed, then the SET
+ LINE command succeeds; up to six messages are printed telling the user
+ which "stale lockfiles" are being removed.
+
+ When the "set line" command succeeds in HP-UX 10.00 and later, C-Kermit
+ also creates a Unix System V R4 "advisory lock" as a further precaution
+ (but not guarantee) against any other process obtaining access to the
+ device while you are using it.
+
+ If the selected device was in use by "cu", Kermit can't open it,
+ because "cu" has changed its ownership, so we never get as far as
+ looking at the lockfiles. In the normal case, we can't even look at the
+ device to see who the owner is because it is visible only to its
+ (present) owner. In this case, Kermit says (for example):
+
+ /dev/cua0p0: Permission denied
+
+ When Kermit releases a device it has successfully opened, it removes
+ all the lockfiles that it created. This also happens whenever Kermit
+ exits "under its own power".
+
+ If Kermit is killed with a device open, the lockfile(s) are left
+ behind. The next Kermit program that tries to assign the device, under
+ any of its various names, will automatically clean up the stale
+ lockfiles because the pids they contain are invalid. The behavior of cu
+ and other communication programs under these conditions should be the
+ same.
+
+ Here, by the way, is a summary of the differences between the HP-UX
+ port driver types from John Pezzano of HP:
+
+ There are three types of device files for each port.
+
+ The ttydXXX device file is designed to work as follows:
+
+ 1. The process that opens it does NOT get control of the port until CD
+ is asserted. This was intentional (over 15 years ago) to allow
+ getty to open the port but not control it until someone called in.
+ If a process wants to use the direct or callout device files
+ (ttyXXX and culXXX respectively), they will then get control and
+ getty would be blocked. This eliminated the need to use uugetty
+ (and its inherent problems with lock files) for modems. You can see
+ this demonstrated by the fact that "ps -ef" shows a ? in the tty
+ column for the getty process as getty does not have the port yet.
+ 2. Once CD is asserted, the port is controlled by getty (or the
+ process handling an incoming call) if there was no process using
+ the port. The ? in the "ps" command now shows the port. At this
+ point, the port accepts data.
+
+ Therefore you should use either the callout culXXX device file
+ (immediate control but no data until CD is asserted) or the direct
+ device file ttyXXX which gives immediate control and immediate data
+ and which ignores by default modem control signals.
+
+ The ttydXXX device should be used only for callin and my
+ recommendation is to use it only for getty and uugetty.
+
+3.2.4 Notes on Specific HP-UX Releases
+
+ SECTION CONTENTS
+
+ 3.2.4.1. [228]HP-UX 11
+ 3.2.4.2. [229]HP-UX 10
+ 3.2.4.3. [230]HP-UX 9
+ 3.2.4.4. [231]HP-UX 8
+ 3.2.4.5. [232]HP-UX 7 and Earlier
+
+3.2.4.1. HP-UX 11
+
+ [ [233]Top ] [ [234]Contents ] [ [235]Section Contents ] [ [236]Next ]
+
+ As noted in [237]Section 3.2.2, the HP-UX 11 Telnet server and/or
+ pseudoterminal driver are a serious impediment to file transfer over
+ Telnet connections into HP-UX. If you have a Telnet connection into
+ HP-UX 11, tell your desktop Kermit program to:
+
+ set streaming off
+ set receive packet-length 2000
+ set send packet-length 500
+
+ File transfer speeds over connections from HP-UX 11 (dialed or Telnet)
+ are not impeded whatsoever, and can go at whatever speed is allowed by
+ the connection and the Kermit partner on the far end.
+
+ PA-RISC binaries for HP-UX 10.20 or later should run on any PA-RISC
+ system, S700 or S800, as long as the binary was not built under a later
+ HP-UX version than the host operating system. HP-UX 11.00 and 11.11 are
+ only for PA-RISC systems. HP-UX 11.20 is only for IA64 (subsequent
+ HP-UX releases will be for both PA-RISC and IA64). To check binary
+ compatibility, the following C-Kermit 8.0 binaries were run
+ successfully on an HP-9000/785 with HP-UX 11.11:
+
+ * Model 7xx HP-UX 10.20
+ * Model 8xx HP-UX 10.20
+ * Model 7xx HP-UX 11.00
+ * Model 8xx HP-UX 11.00
+ * Model 7xx HP-UX 11.11
+ * Model 8xx HP-UX 11.11
+
+ Binaries built under some of the earlier HP-UX releases, such as 9.05,
+ might also work, but only if built for the same hardware family (e.g.
+ s700).
+
+3.2.4.2. HP-UX 10
+
+ [ [238]Top ] [ [239]Contents ] [ [240]Section Contents ] [ [241]Next ]
+ [ [242]Previous ]
+
+ Beginning in HP-UX 10.10, libcurses is linked to libxcurses, the new
+ UNIX95 (X/Open) version of curses, which has some serious bugs; some
+ routines, when called, would hang and never return, some would dump
+ core. Evidently libxcurses contains a select() routine, and whenever
+ C-Kermit calls what it thinks is the regular (sockets) select(), it
+ gets the curses one, causing a segmentation fault. There is a patch for
+ this from HP, PHCO_8086, "s700_800 10.10 libcurses patch", "shared lib
+ curses program hangs on 10.10", "10.10 enhanced X/Open curses core
+ dumps due to using wrong select call", 96/08/02 (you can tell if the
+ patch is installed with "what /usr/lib/libxcurses.1"; the unpatched
+ version is 76.20, the patched one is 76.20.1.2). It has been verified
+ that C-Kermit works OK with the patched library, but results are not
+ definite for HP-UX 10.20 or higher.
+
+ To ensure that C-Kermit works even on non-patched HP-UX 10.10 systems,
+ separate makefile entries are provided for HP-UX 10.00/10.01, 10.10,
+ 10.20, etc, in which the entries for 10.10 and above link with
+ libHcurses, which is "HP curses", the one that was used in 10.00/10.01.
+ HP-UX 11.20 and later, however, link with libcurses, as libHcurses
+ disappeared in 11.20.
+
+3.2.4.3. HP-UX 9
+
+ [ [243]Top ] [ [244]Contents ] [ [245]Section Contents ] [ [246]Next ]
+ [ [247]Previous ]
+
+ HP-UX 9.00 and 9.01 need patch PHNE_10572 (note: this replaces
+ PHNE_3641) for hptt0.o, asio0.o, and ttycomn.o in libhp-ux.a. Contact
+ Hewlett Packard if you need this patch. Without it, the dialout device
+ (tty) will be hung after first use; subsequent attempts to use will
+ return an error like "device busy". (There are also equivalent patches
+ for s700 9.03 9.05 9.07 (PHNE_10573) and s800 9.00 9.04 (PHNE_10416).
+
+ When C-Kermit is in server mode, it might have trouble executing REMOTE
+ HOST commands. This problem happens under HP-UX 9.00 (Motorola) and
+ HP-UX 9.01 (RISC) IF the C-Shell is the login shell AND with the
+ C-Shell Revision 70.15. Best thing is to install HP's Patch PHCO_4919
+ for Series 300/400 and PHCO_5015 for the Series 700/800. PHCO_5015 is
+ called "s700_800 9.X cumulative csh(1) patch with memory leak fix"
+ which works for HP-UX 9.00, 9.01, 9.03, 9.04, 9.05 and 9.07. At least
+ you need C-Shell Revision 72.12!
+
+ C-Kermit works fine -- including its curses-based file-transfer display
+ -- on the console terminal, in a remote session (e.g. when logged in to
+ the HP 9000 on a terminal port or when telnetted or rlogin'd), and in
+ an HP-VUE hpterm window or an xterm window.
+
+3.2.4.4. HP-UX 8
+
+ [ [248]Top ] [ [249]Contents ] [ [250]Section Contents ] [ [251]Next ]
+ [ [252]Previous ]
+
+ To make C-Kermit work on HP-UX 8.05 on a model 720, obtain and install
+ HP-UX patch PHNE_0899. This patch deals with a lot of driver issues,
+ particularly related to communication at higher speeds.
+
+ One user reports:
+
+ On HP-UX 8 DON'T install 'tty patch' PHKL_4656, install PHKL_3047
+ instead! Yesterday I tried this latest tty patch PHKL_4656 and had
+ terrible problems. This patch should fix RTS/CTS problems. With text
+ transfer all looks nice. But when I switched over to binary files
+ the serial interface returned only rubish to C-Kermit. All sorts of
+ protocol, CRC and packed errors I had. After several tests and after
+ uninstalling that patch, all transfers worked fine. MB's of data
+ without any errors. So keep your fingers away from that patch. If
+ anybody needs the PHKL_3047 patch I have it here. It is no longer
+ available from HP's patch base.
+
+3.2.4.5. HP-UX 7 and Earlier
+
+ [ [253]Top ] [ [254]Contents ] [ [255]Section Contents ] [
+ [256]Previous ]
+
+ When transferring files into HP-UX 5 or 6 over a Telnet connection, you
+ must not use streaming, and you must not use a packet length greater
+ than 512. However, you can use streaming and longer packets when
+ sending files from HP-UX on a Telnet connection. In C-Kermit 8.0, the
+ default receive packet length for HP-UX 5 and 6 was changed to 500 (but
+ you can still increase it with SET RECEIVE PACKET-LENGTH if you wish,
+ e.g. for non-Telnet connections). Disable streaming with SET STREAMING
+ OFF.
+
+ The HP-UX 5.00 version of C-Kermit does not include the fullscreen
+ file-transfer because of problems with the curses library.
+
+ If HP-UX 5.21 with Wollongong TCP/IP is on the remote end of a Telnet
+ connection, streaming transfers to HP-UX invariably fail. Workaround:
+ SET STREAMING OFF. Packets longer than about 1000 should not be used.
+ Transfers from these systems, however, can use streaming and/or longer
+ packets.
+
+ Reportedly, "[there is] a bug in C-Kermit using HP-UX version 5.21 on
+ the HP-9000 series 500 computers. It only occurs when the controlling
+ terminal is using an HP-27140 six-port modem mux. The problem is not
+ present if the controlling terminal is logged into an HP-27130
+ eight-port mux. The symptom is that just after dialing successfully and
+ connecting Kermit locks up and the port is unusable until both forks of
+ Kermit and the login shell are killed." (This report predates C-Kermit
+ 6.0 and might no longer apply.)
+
+3.2.5. HP-UX and X.25
+
+ [ [257]Top ] [ [258]Contents ] [ [259]Section Contents ] [
+ [260]Previous ]
+
+ Although C-Kermit presently does not include built-in support for HP-UX
+ X.25 (as it does for the Sun and IBM X.25 products), it can still be
+ used to make X.25 connections as follows: start Kermit and then telnet
+ to localhost. After logging back in, start padem as you would normally
+ do to connect over X.25. Padem acts as a pipe between Kermit and X.25.
+ In C-Kermit 7.0, you might also be able to avoid the "telnet localhost"
+ step by using:
+
+ C-Kermit> pty padem address
+
+ This works if padem uses standard i/o (who knows?).
+
+3.3. C-KERMIT AND LINUX
+
+ [ [261]Top ] [ [262]Contents ] [ [263]Section Contents ] [ [264]Next ]
+ [ [265]Previous ]
+
+ SECTION CONTENTS
+
+ 3.3.1. [266]Problems Building C-Kermit for Linux
+ 3.3.2. [267]Problems with Serial Devices in Linux
+ 3.3.3. [268]Terminal Emulation in Linux
+ 3.3.4. [269]Dates and Times
+ 3.3.5. [270]Startup Errors
+ 3.3.6. [271]The Fullscreen File Transfer Display
+
+ (August 2010) Reportedly C-Kermit packages for certain Linux
+ distributions such as Centos and Ubuntu have certain features
+ disabled, for example the SSH command, SET HOST PTY /SSH, and
+ perhaps anything else to do with SSH and/or pseudoterminals and who
+ knows what else. If you download the regular package ("tarball")
+ from the Kermit Project and build from it ("make linux"), everything
+ is fine.
+
+ C-Kermit in Ubuntu 10.04 and 9.10 was reported slow to start because
+ it was trying to resolve the IP address 255.255.255.255. Later, also
+ in recent Debian versions. The following is seen in the strace:
+
+write(3, "RESOLVE-ADDRESS 255.255.255.255\n", 32)
+
+ This is not Kermit Project code. Turns out to be something in
+ glibc's resolver, and can be fixed by changing /etc/nsswitch.conf,
+ but it might break other software, such as [272]Avahi or anything
+ (such as Gnome, Java, or Cups) that depends on it. I'm not sure
+ where it happens; I don't think Kermit tries to get its IP address
+ at startup time, only when it's needed or asked for, e.g. when
+ making a connection or evaluating \v(ipaddress).
+
+ REFERENCES
+
+ For further information, read the [273]comp.os.linux.misc,
+ [274]comp.os.linux.answers, and other Linux-oriented newsgroups, and
+ see:
+
+ The Linux Document Project (LDP)
+ [275]http://www.tldp.org/
+
+ The Linux FAQ
+ [276]http://www.tldp.org/FAQ/Linux-FAQ.html
+
+ The Linux HOWTOs (especially the Serial HOWTO)
+
+ [277]http://www.tldp.org/HOWTO/Serial-HOWTO.html
+
+ [278]http://tldp.org/HOWTO/Modem-HOWTO.html
+
+ [279]ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO
+
+ [280]ftp://tsx-11.mit.edu/pub/linux/docs/HOWTO
+
+ [281]http://www.tldp.org/HOWTO/
+
+ [282]http://www.tldp.org/hmirrors.html
+
+ Linux Vendor Tech Support Pages:
+
+ [283]http://www.redhat.com/apps/support/
+
+ [284]http://www.debian.org/support
+
+ [285]http://www.slackware.com/support/
+
+ [286]http://www.caldera.com/support/
+
+ [287]SUSE Linux Support
+
+ [288]http://www.mandrake.com/support/
+
+ [289]http://www.turbolinux.com/support/
+
+ Linux Winmodem Support
+ [290]http://www.linmodems.org/
+
+ Also see general comments on PC-based Unixes in [291]Section 3.0.
+
+ What Linux version is it? -- "uname -a" supplies only kernel
+ information, but these days it's the distribution that matters: Red Hat
+ 7.3, Debian 2.2, Slackware 8.0, etc. Unfortunately there's no
+ consistent way to get the distribution version. Usually it's in a
+ distribution-specific file:
+
+ Red Hat: /etc/issue or /etc/redhat-release
+ Debian: /etc/debian_version
+ Slackware: /etc/slackware-version (at least in later versions)
+
+ Did you know: DECnet is available for Linux? See:
+
+ [292]http://linux.dreamtime.org/decnet/
+
+ (But there is no support for it in C-Kermit -- anybody interested in
+ adding it, please [293]let me know).
+
+ Before proceeding, let's handle the some of the most frequently asked
+ question in the Linux newsgroups:
+
+ 1. Neither C-Kermit nor any other Linux application can use Winmodems,
+ except in the [294]rare cases where Linux drivers have been written
+ for them. See [295]Section 3.0.2 for details.
+ 2. "Why does it take such a long time to make a telnet connection to
+ (or from) my Linux PC?" (this applies to C-Kermit and to regular
+ Telnet). Most telnet servers these days perform reverse DNS lookups
+ on the client (for security and/or logging reasons). If the Telnet
+ client's address cannot be found by the server's local DNS server,
+ the DNS request goes out to the Internet at large, and this can
+ take quite some time. The solution to this problem is to make sure
+ that both client and host are registered in DNS, and that the
+ registrations are exported. C-Kermit itself performs reverse DNS
+ lookups unless you tell it not to; this is to allow C-Kermit to let
+ you know which host it is actually connected to in case you have
+ made a connection to a host pool (multihomed host). You can disable
+ C-Kermit's reverse DNS lookup with SET TCP REVERSE-DNS-LOOKUP OFF.
+ 3. (Any question that has the word "Telnet" in it...) The knee-jerk
+ reaction is "don't use Telnet, use SSH!" There's nothing wrong with
+ Telnet. In fact it's far superior to SSH as a protocol in terms of
+ features and extensibility, not to mention platform neutrality. The
+ issue lurking behind the knee-jerk reaction is security. SSH is
+ thought to be secure, whereas Telnet is thought to be insecure.
+ This is true for clear-text Telnet (because passwords travel in the
+ clear across the network), but apparently few people realize that
+ [296]secure Telnet clients and servers have been available for
+ years, and these are more secure than SSH (for reasons explained
+ [297]HERE).
+ 4. (Any question that has the word "FTP" in it...) The knee-jerk
+ reaction being "Don't use FTP, use SCP!" (or SFTP). Same answer as
+ above, but moreso. SCP and SFTP are not only not platform neutral,
+ they're diversity-hostile. They transfer files only in binary mode,
+ which mangles text files across different platforms, to the same
+ degree the platform's text-file record format and character set
+ differ. An extreme example would be an Variable-Block format EBCDIC
+ text file on an IBM mainframe, binary transfer of which to Unix
+ would do you little good indeed. FTP was designed with diversity in
+ mind and secure versions are available.
+
+3.3.1. Problems Building C-Kermit for Linux
+
+ [ [298]Top ] [ [299]Contents ] [ [300]Section Contents ] [ [301]Next ]
+
+ Modern Linux distributions like Red Hat give you a choice at
+ installation whether to include "developer tools". Obviously, you can't
+ build C-Kermit or any other C program from source code if you have not
+ installed the developer tools. But to confuse matters, you might also
+ have to choose (separately) to install the "curses" or "ncurses"
+ terminal control library; thus it is possible to install the C compiler
+ and linker, but omit the (n)curses library and headers. If curses is
+ not installed, you will not be able to build a version of C-Kermit that
+ supports the fullscreen file-transfer display, in which case you'll
+ need to use the "linuxnc" makefile target (nc = No Curses) or else
+ install ncurses before building.
+
+ There are all sorts of confusing issues caused by the many and varied
+ Linux distributions. Some of the worst involve the curses library and
+ header files: where are they, what are they called, which ones are they
+ really? Other vexing questions involve libc5 vs libc6 vs glibc vs
+ glibc2 (C libraries), gcc vs egcs vs lcc (compilers), plus using or
+ avoiding features that were added in a certain version of Linux or a
+ library or a distribution, and are not available in others. As of
+ C-Kermit 8.0, these questions should be resolved by the "linux"
+ makefile target itself, which does a bit of looking around to see
+ what's what, and then sets the appropriate CFLAGS.
+
+3.3.2. Problems with Serial Devices in Linux
+
+ [ [302]Top ] [ [303]Contents ] [ [304]Section Contents ] [ [305]Next ]
+ [ [306]Previous ]
+
+ Also see: "man setserial", "man irqtune".
+ And: [307]Sections 3.0, [308]6, [309]7, and [310]8 of this document.
+
+ NOTE: Red Hat Linux 7.2 and later include a new API that allows
+ serial-port arbitration by non-setuid/gid programs. This API has not
+ yet been added to C-Kermit. If C-Kermit is to be used for dialing
+ out on Red Hat 7.2 or later, it must still be installed as described
+ in in Sections [311]10 and [312]11 of the [313]Installation
+ Instructions.
+
+ Don't expect it to be easy. Queries like the following are posted to
+ the Linux newsgroups almost daily:
+
+ Problem of a major kind with my Compaq Presario 1805 in the sense
+ that the pnpdump doesn't find the modem and the configuration tells
+ me that the modem is busy when I set everything by hand!
+
+ I have <some recent SuSE distribution>, kernel 2.0.35. Using the
+ Compaq tells me that the modem (which is internal) is on COM2, with
+ the usual IRQ and port numbers. Running various Windows diagnostics
+ show me AT-style commands exchanged so I have no reason to believe
+ that it is a Winmodem. Also, the diagnostics under Win98 tell me
+ that I am talking to an NS 16550AN.
+
+ [Editor's note: This does not necessarily mean it isn't a Winmodem.]
+
+ Under Linux, no joy trying to talk to the modem on /dev/cua1 whether
+ via minicom, kppp, or chat; kppp at least tells me that tcgetattr()
+ failed.
+
+ Usage of setserial:
+
+ setserial /dev/cua1 port 0x2F8 irq 3 autoconfig
+ setserial -g /dev/cua1
+
+ tells me that the uart is 'unknown'. I have tried setting the UART
+ manually via. setserial to 16550A, 16550, and the other one (8550?)
+ (I didn't try 16540). None of these manual settings resulted in any
+ success.
+
+ A look at past articles leads me to investigate PNP issues by
+ calling pnpdump but pnpdump returns "no boards found". I have looked
+ around on my BIOS (Phoenix) and there is not much evidence of it
+ being PNP aware. However for what it calls "Serial port A", it
+ offers a choice of Auto, Disabled or Manual settings (currently set
+ to Auto), but using the BIOS interface I tried to change to 'manual'
+ and saw the default settings offered to be were 0x3F8 and IRQ 4
+ (COM1). The BIOS menus did not give me any chance to configure COM2
+ or any "modem". I ended up not saving any BIOS changes in the course
+ of my investigations.
+
+ You can also find out a fair amount about your PC's hardware
+ configuration in the text files in /proc, e.g.:
+
+ -r--r--r-- 1 root 0 Sep 4 14:00 /proc/devices
+ -r--r--r-- 1 root 0 Sep 4 14:00 /proc/interrupts
+ -r--r--r-- 1 root 0 Sep 4 14:00 /proc/ioports
+ -r--r--r-- 1 root 0 Sep 4 14:00 /proc/pci
+
+ From the directory listing they look like empty files, but in fact they
+ are text files that you "cat":
+
+$ cat /proc/pci
+ Bus 0, device 14, function 0:
+ Serial controller: US Robotics/3Com 56K FaxModem Model 5610 (rev 1).
+ IRQ 10.
+ I/O at 0x1050 [0x1057].
+
+$ setserial -g /dev/ttyS4
+/dev/ttyS4, UART: 16550A, Port: 0x1050, IRQ: 10
+
+$ cat /proc/ioports
+1050-1057 : US Robotics/3Com 56K FaxModem Model 5610
+ 1050-1057 : serial(auto)
+
+$ cat /proc/interrupts
+ CPU0
+ 0: 7037515 XT-PIC timer
+ 1: 2 XT-PIC keyboard
+ 2: 0 XT-PIC cascade
+ 4: 0 XT-PIC serial
+ 8: 1 XT-PIC rtc
+ 9: 209811 XT-PIC usb-uhci, eth0
+ 14: 282015 XT-PIC ide0
+ 15: 6 XT-PIC ide1
+
+ Watch out for PCI, PCMCIA and Plug-n-Play devices, Winmodems, and the
+ like (see cautions in [314]Section 3.0 Linux supports Plug-n-Play
+ devices to some degree via the isapnp and pnpdump programs; read the
+ man pages for them. (If you don't have them, look on your installation
+ CD for isapnptool or download it from sunsite or a sunsite mirror or
+ other politically correct location du jour).
+
+ PCI modems do not use standard COM port addresses. The I/O address and
+ IRQ are assigned by the BIOS. All you need to do to get one working,
+ find out the I/O address and interrupt number with (as root) "lspci -v
+ | more" and then give the resulting address and interrupt number to
+ setserial.
+
+ Even when you have a real serial port, always be wary of interrupt
+ conflicts and similar PC hardware configuration issues: a PC is not a
+ real computer like other Unix workstations -- it is generally pieced
+ together from whatever random components were the best bargain on the
+ commodity market the week it was built. Once it's assembled and boxed,
+ not even the manufacturer will remember what it's made of or how it was
+ put together because they've moved on to a new model. Their job is to
+ get it (barely) working with Windows; for Linux and other OS's you are
+ on your own.
+
+ "set line /dev/modem" or "set line /dev/ttyS2", etc, results in an
+ error, "/dev/modem is not a tty". Cause unknown, but obviously a driver
+ issue, not a Kermit one (Kermit uses "isatty()" to check that the
+ device is a tty, so it knows it will be able to issue all the
+ tty-related ioctl's on it, like setting the speed & flow control). Try
+ a different name (i.e. driver) for the same port, e.g. "set line
+ /dev/cua2" or whatever.
+
+ To find what serial ports were registered at the most recent system
+ boot, type (as root): "grep tty /var/log/dmesg".
+
+ "set modem type xxx" (where xxx is the name of a modem) followed by
+ "set line /dev/modem" or "set
+ line /dev/ttyS2", etc, hangs (but can be interrupted with Ctrl-C).
+ Experimentation shows that if the modem is configured to always assert
+ carrier (&C0) the same command does not hang. Again, a driver issue.
+ Use /dev/cua2 (or whatever) instead. (Or not -- hopefully none of these
+ symptoms occurs in C-Kermit 7.0 or later.)
+
+ "set line /dev/cua0" reports "Device is busy", but "set line
+ /dev/ttyS0" works OK.
+
+ In short: If the cua device doesn't work, try the corresponding ttyS
+ device. If the ttyS device doesn't work, try the corresponding cua
+ device -- but note that Linux developers do not recommend this, and are
+ phasing out the cua devices. From /usr/doc/faq/howto/Serial-HOWTO:
+
+ 12.4. What's The Real Difference Between the /dev/cuaN And /dev/ttySN
+ Devices?
+ The only difference is the way that the devices are opened. The
+ dialin devices /dev/ttySN are opened in blocking mode, until CD
+ is asserted (ie someone connects). So, when someone wants to use
+ the /dev/cuaN device, there is no conflict with a program
+ watching the /dev/ttySN device (unless someone is connected of
+ course). The multiple /dev entries, allow operation of the same
+ physical device with different operating characteristics. It
+ also allows standard getty programs to coexist with any other
+ serial program, without the getty being retrofitted with locking
+ of some sort. It's especially useful since standard Unix kernel
+ file locking, and UUCP locking are both advisory and not
+ mandatory.
+
+ It was discovered during development of C-Kermit 7.0 that rebuilding
+ C-Kermit with -DNOCOTFMC (No Close/Open To Force Mode Change) made the
+ aforementioned problem with /dev/ttyS0 go away. It is not yet clear,
+ however, what its affect might be on the /dev/cua* devices. As of 19
+ March 1998, this option has been added to the CFLAGS in the makefile
+ entries for Linux ("make linux").
+
+ Note that the cua device is now "deprecated", and new editions of Linux
+ will phase (have phased) it out in favor of the ttyS device. See (if
+ it's still there):
+
+ [315]http://linuxwww.db.erau.edu/mail_archives/linux-kernel/Mar_98/1441.html
+
+ (no, of course it isn't; you'll have to use your imagination). One user
+ reported that C-Kermit 7.0, when built with egcs 1.1.2 and run on Linux
+ 2.2.6 with glibc 2.1 (hardware unknown but probably a PC) dumps core
+ when given a "set line /dev/ttyS1" command. When rebuilt with gcc, it
+ works fine.
+
+ All versions of Linux seem to have the following deficiency: When a
+ modem call is hung up and CD drops, Kermit can no longer read the modem
+ signals; SHOW COMMUNICATIONS says "Modem signals not available". The
+ TIOCMGET ioctl() returns -1 with errno 5 ("I/O Error").
+
+ The Linux version of POSIX tcsendbreak(), which is used by C-Kermit to
+ send regular (275msec) and long (1.5sec) BREAK signals, appears to
+ ignore its argument (despite its description in the man page and info
+ topic), and always sends a regular 275msec BREAK. This has been
+ observed in Linux versions ranging from Debian 2.1 to Red Hat 7.1.
+
+3.3.3. Terminal Emulation in Linux
+
+ [ [316]Top ] [ [317]Contents ] [ [318]Section Contents ] [ [319]Next ]
+ [ [320]Previous ]
+
+ C-Kermit is not a terminal emulator. For a brief explanation of why
+ not, see [321]Section 3.0.5. For a fuller explanation, [322]ClICK HERE.
+
+ In Unix, terminal emulation is supplied by the Window in which you run
+ Kermit: the regular console screen, which provides Linux Console
+ "emulation" via the "console" termcap entry, or under X-Windows in an
+ xterm window, which gives VTxxx emulation. An xterm that includes color
+ ANSI and VT220 emulation is available with Xfree86:
+
+ [323]http://dickey.his.com/xterm/xterm.html
+
+ Before starting C-Kermit in an xterm window, you might need to tell the
+ xterm window's shell to "stty sane".
+
+ To set up your PC console keyboard to send VT220 key sequences when
+ using C-Kermit as your communications program in an X terminal window
+ (if it doesn't already), create a file somewhere (e.g. in /root/)
+ called .xmodmaprc, containing something like the following:
+
+ keycode 77 = KP_F1 ! Num Lock => DEC Gold (PF1)
+ keycode 112 = KP_F2 ! Keypad / => DEC PF1
+ keycode 63 = KP_F3 ! Keypad * => DEC PF3
+ keycode 82 = KP_F4 ! Keypad - => DEC PF4
+ keycode 111 = Help ! Print Screen => DEC Help
+ keycode 78 = F16 ! Scroll Lock => DEC Do
+ keycode 110 = F16 ! Pause => DEC Do
+ keycode 106 = Find ! Insert => DEC Find
+ keycode 97 = Insert ! Home => DEC Insert
+ keycode 99 = 0x1000ff00 ! Page Up => DEC Remove
+ keycode 107 = Select ! Delete => DEC Select
+ keycode 103 = Page_Up ! End => DEC Prev Screen
+ keycode 22 = Delete ! Backspace sends Delete (127)
+
+ Then put "xmodmap filename" in your .xinitrc file (in your login
+ directory), e.g.
+
+ xmodmap /root/.xmodmaprc
+
+ Of course you can move things around. Use the xev program to find out
+ key codes.
+
+ Console-mode keys are mapped separately using loadkeys, and different
+ keycodes are used. Find out what they are with showkey.
+
+ For a much more complete VT220/320 key mapping for [324]Xfree86 xterm,
+ [325]CLICK HERE.
+
+3.3.4. Dates and Times
+
+ [ [326]Top ] [ [327]Contents ] [ [328]Section Contents ] [ [329]Next ]
+ [ [330]Previous ]
+
+ If C-Kermit's date-time (e.g. as shown by its DATE command) differs
+ from the system's date and time:
+
+ a. Make sure the libc to which Kermit is linked is set to GMT or is
+ not set to any time zone. Watch out for mixed libc5/libc6 systems;
+ each must be set independently.
+ b. If you have changed your TZ environment variable, make sure it is
+ exported. This is normally done in /etc/profile or /etc/TZ.
+
+3.3.5. Startup Errors
+
+ [ [331]Top ] [ [332]Contents ] [ [333]Section Contents ] [ [334]Next ]
+ [ [335]Previous ]
+
+ C-Kermit should work on all versions of Linux current through March
+ 2003, provided it was built on the same version you have, with the same
+ libraries and header files (just get the source code and "make linux").
+ Binaries tend not to travel well from one Linux machine to another, due
+ to their many differences. There is no guarantee that a particular
+ C-Kermit binary will not stop working at a later date, since Linux
+ tends to change out from under its applications. If that happens,
+ rebuild C-Kermit from source. If something goes wrong with the build
+ process, look on the [336]C-Kermit website for a newer version. If you
+ have the latest version, then [337]report the problem to us.
+
+ Inability to transfer files in Red Hat 7.2: the typical symptom would
+ be if you start Kermit and tell it to RECEIVE, it fails right away with
+ "?/dev/tty: No such device or address" or "?Bad file descriptor". One
+ report says this is because of csh, and if you change your shell to
+ bash or other shell, it doesn't happen. Another report cite bugs in Red
+ Hat 7.2 Telnetd "very seldom (if ever) providing a controlling tty, and
+ lots of other people piled on saying they have the same problem.") A
+ third theory is that this happens only when Linux has been installed
+ without "virtual terminal support".
+
+ A search of RedHat's errata pages shows a bug advisory (RHBA-2001-153)
+ issued 13 November 2001, but updated 6 December, about this same
+ symptom (but with tcsh and login.) Seems that login was not always
+ assigning a controlling TTY for the session, which would make most use
+ of "/dev/tty" somewhat less than useful.
+
+ [338]http://www.redhat.com/support/errata/RHBA-2001-153.html
+
+ Quoting: "Due to terminal handling problems in /bin/login, tcsh would
+ not find the controlling terminal correctly, and a shell in single user
+ mode would exhibit strange terminal input characteristics. This update
+ fixes both of these problems."
+
+ Since the Red Hat 5.1 release (circa August 1998), there have been
+ numerous reports of prebuilt Linux executables, and particularly the
+ Kermit RPM for Red Hat Linux, not working; either it won't start at
+ all, or it gives error messages about "terminal type unknown" and
+ refuses to initialize its curses support. The following is from the
+ [339]Kermit newsgroup:
+
+ From: rchandra@hal9000.buf.servtech.com
+ Newsgroups: comp.protocols.kermit.misc
+ Subject: Red Hat Linux/Intel 5.1 and ncurses: suggestions
+ Date: 22 Aug 1998 15:54:46 GMT
+ Organization: Verio New York
+ Keywords: RedHat RPM 5.1
+
+ Several factors can influence whether "linux" is recognized as a
+ terminal type on many Linux systems.
+
+ 1. Your program, or the libraries it linked with (if statically
+ linked), or the libraries it dynamically links with at runtime, are
+ looking for an entry in /etc/termcap that isn't there. (not likely,
+ but possible... I believe but am not certain that this is a very
+ old practice in very old [n]curses library implementations to use a
+ single file for all terminal descriptions.)
+ 2. Your program, or the libraries...are looking for a terminfo file
+ that just plain isn't there. (also not so likely, since many people
+ in other recent message threads said that other programs work OK).
+ 3. Your program, or the libraries...are looking for a terminfo file
+ that is stored at a pathname that isn't expected by your program,
+ the libraries--and so on. I forgot if I read this in the errata Web
+ page or where exactly I discovered this (Netscape install? Acrobat
+ install?), but it may just be that one libc (let's say for sake of
+ argument, libc5, but I don't know this to be true) expects your
+ terminfo to be in /usr/share/terminfo, and the other (let's say
+ libc6/glibc) expects /usr/lib/terminfo. I remember that the
+ specific instructions in this bugfix/workaround were to do the
+ following or equivalent:
+ cd /usr/lib
+ ln -s ../share/terminfo ./terminfo
+
+ or:
+ ln -s /usr/share/terminfo /usr/lib/terminfo
+
+ So what this says is that the terminfo database/directory structure
+ can be accessed by either path. When something goes to reference
+ /usr/lib/terminfo, the symlink redirects it to essentially
+ /usr/share/terminfo, which is where it really resides on your
+ system. I personally prefer wherever possible to use relative
+ symlinks, because they still hold, more often than break, across
+ mount points, particularly NFS mounts, where the directory structure
+ may be different on the different systems.
+
+ Evidently the terminfo file moved between Red Hat 5.0 and 5.1, but Red
+ Hat did not include a link to let applications built prior to 5.1 find
+ it. Users reported that installing the link fixes the problem.
+
+3.3.6. The Fullscreen File Transfer Display
+
+ [ [340]Top ] [ [341]Contents ] [ [342]Section Contents ] [
+ [343]Previous ]
+
+ Starting with ncurses versions dated 1998-12-12 (about a year before
+ ncurses 5.0), ncurses sets the terminal for buffered i/o, but
+ unfortunately is not able to restore it upon exit from curses (via
+ endwin()). Thus after a file transfer that uses the fullscreen file
+ transfer display, the terminal no longer echos nor responds immediately
+ to Tab, ?, and other special command characters. The same thing happens
+ on other platforms that use ncurses, e.g. FreeBSD. Workarounds:
+
+ * Use SET XFER DISPLAY BRIEF, CRT, SERIAL, or NONE instead of
+ FULLSCREEN; or:
+ * Rebuild with KFLAGS=-DNONOSETBUF (C-Kermit 8.0)
+
+ In Red Hat 7.1, when using C-Kermit in a Gnome terminal window, it was
+ noticed that when the fullscreen file transfer display exits (via
+ endwin()), the previous (pre-file-transfer-display) screen is restored.
+ Thus you can't look at the completed display to see what happened. This
+ is a evidently a new feature of xterm. I can only speculate that
+ initscreen() and endwin() must send some kind of special escape
+ sequences that command xterm to save and restore the screen. To defeat
+ this effect, tell Linux you have a vt100 or other xterm-compatible
+ terminal that is not actually an xterm, or else tell Kermit to SET
+ TRANSFER DISPLAY to something besides FULLSCREEN.
+
+3.4. C-KERMIT AND NEXTSTEP
+
+ [ [344]Top ] [ [345]Contents ] [ [346]Section Contents ] [ [347]Next ]
+ [ [348]Previous ]
+
+ Run C-Kermit in a Terminal, Stuart, or xterm window, or when logged in
+ remotely through a serial port or TELNET connection. C-Kermit does not
+ work correctly when invoked directly from the NeXTSTEP File Viewer or
+ Dock. This is because the terminal-oriented gtty, stty, & ioctl calls
+ don't work on the little window that NeXTSTEP pops up for non-NeXTSTEP
+ applications like Kermit. CBREAK and No-ECHO settings do not take
+ effect in the command parser -- commands are parsed strictly line at a
+ time. "set line /dev/cua" works. During CONNECT mode, the console stays
+ in cooked mode, so characters are not transmitted until carriage return
+ or linefeed is typed, and you can't escape back. If you want to run
+ Kermit directly from the File Viewer, then launch it from a shell
+ script that puts it in the desired kind of window, something like this
+ (for "Terminal"):
+
+ Terminal -Lines 24 -Columns 80 -WinLocX 100 -WinLocY 100 $FONT $FONTSIZE \
+ -SourceDotLogin -Shell /usr/local/bin/kermit &
+
+ C-Kermit does not work correctly on a NeXT with NeXTSTEP 3.0 to which
+ you have established an rlogin connection, due to a bug in NeXTSTEP
+ 3.0, which has been reported to NeXT.
+
+ The SET CARRIER command has no effect on the NeXT -- this is a
+ limitation of the NeXTSTEP serial-port device drivers.
+
+ Hardware flow control on the NeXT is selected not by "set flow rts/cts"
+ in Kermit (since NeXTSTEP offers no API for this), but rather, by using
+ a specially-named driver for the serial device: /dev/cufa instead
+ /dev/cua; /dev/cufb instead of /dev/cub. This is available only on
+ 68040-based NeXT models (the situation for Intel NeXTSTEP
+ implementations is unknown).
+
+ NeXT-built 68030 and 68040 models have different kinds of serial
+ interfaces; the 68030 has a Macintosh-like RS-422 interface, which
+ lacks RTS and CTS signals; the 68040 has an RS-423 (RS-232 compatible)
+ interface, which supports the commonly-used modem signals. WARNING: the
+ connectors look exactly the same, but the pins are used in completely
+ DIFFERENT ways -- different cables are required for the two kinds of
+ interfaces.
+
+ IF YOU GET LOTS OF RETRANSMISSIONS during file transfer, even when
+ using a /dev/cuf* device and the modem is correctly configured for
+ RTS/CTS flow control, YOU PROBABLY HAVE THE WRONG KIND OF CABLE.
+
+ On the NeXT, Kermit reportedly (by TimeMon) causes the kernel to use a
+ lot of CPU time when using a "set line" connection. That's because
+ there is no DMA channel for the NeXT serial port, so the port must
+ interrupt the kernel for each character in or out.
+
+ One user reported trouble running C-Kermit on a NeXT from within NeXT's
+ Subprocess class under NeXTstep 3.0, and/or when rlogin'd from one NeXT
+ to another: Error opening /dev/tty:, congm: No such device or address.
+ Diagnosis: Bug in NeXTSTEP 3.0, cure unknown.
+
+3.5. C-KERMIT AND QNX
+
+ [ [349]Top ] [ [350]Contents ] [ [351]Section Contents ] [ [352]Next ]
+ [ [353]Previous ]
+
+ See also: The [354]comp.os.qnx newsgroup.
+
+ Support for QNX 4.x was added in C-Kermit 5A(190). This is a
+ full-function implementation, thoroughly tested on QNX 4.21 and later,
+ and verified to work in both 16-bit and 32-bit versions. The 16-bit
+ version was dropped in C-Kermit 7.0 since it can no longer be built
+ successfully (after stripping most most features, I succeeded in
+ getting it to compile and link without complaint, but the executable
+ just beeps when you run it); for 16-bit QNX 4.2x, use C-Kermit 6.0 or
+ earlier, or else [355]G-Kermit.
+
+ The 32-bit version (and the 16-bit version prior to C-Kermit 7.0)
+ supports most of C-Kermit's advanced features including TCP/IP, high
+ serial speeds, hardware flow-control, modem-signal awareness, curses
+ support, etc.
+
+ BUG: In C-Kermit 6.0 on QNX 4.22 and earlier, the fullscreen file
+ transfer display worked fine the first time, but was fractured on
+ subsequent file transfers. Cause and cure unknown. In C-Kermit 7.0 and
+ QNX 4.25, this no longer occurs. It is not known if it would occur in
+ C-Kermit 7.0 or later on earlier QNX versions.
+
+ Dialout devices are normally /dev/ser1, /dev/ser2, ..., and can be
+ opened explicitly with SET LINE. Reportedly, "/dev/ser" (no unit
+ number) opens the first available /dev/sern device.
+
+ Like all other Unix C-Kermit implementations, QNX C-Kermit does not
+ provide any kind of terminal emulation. Terminal specific functions are
+ provided by your terminal, terminal window (e.g. QNX Terminal or
+ xterm), or emulator.
+
+ QNX C-Kermit, as distributed, does not include support for UUCP
+ line-locking; the QNX makefile entries (qnx32 and qnx16) include the
+ -DNOUUCP switch. This is because QNX, as distributed, does not include
+ UUCP, and its own communications software (e.g. qterm) does not use
+ UUCP line locking. If you have a UUCP product installed on your QNX
+ system, remove the -DNOUUCP switch from the makefile entry and rebuild.
+ Then check to see that Kermit's UUCP lockfile conventions are the same
+ as those of your UUCP package; if not, read the [356]UUCP lockfile
+ section of the [357]Installation Instructions and make the necessary
+ changes to the makefile entry (e.g. add -DHDBUUCP).
+
+ QNX does, however, allow a program to get the device open count. This
+ can not be a reliable form of locking unless all applications do it, so
+ by default, Kermit uses this information only for printing a warning
+ message such as:
+
+ C-Kermit>set line /dev/ser1
+ WARNING - "/dev/ser1" looks busy...
+
+ However, if you want to use it as a lock, you can do so with:
+
+ SET QNX-PORT-LOCK { ON, OFF }
+
+ This is OFF by default; if you set in ON, C-Kermit will fail to open
+ any dialout device when its open count indicates that another process
+ has it open. SHOW COMM (in QNX only) displays the setting, and if you
+ have a port open, it also shows the open count.
+
+ As of C-Kermit 8.0, C-Kermit's "open-count" form of line locking works
+ only in QNX4, not in QNX6 (this might change in a future C-Kermit
+ release).
+
+3.6. C-KERMIT AND SCO
+
+ [ [358]Top ] [ [359]Contents ] [ [360]Section Contents ] [ [361]Next ]
+ [ [362]Previous ]
+
+ SECTION CONTENTS
+
+3.6.1. [363]SCO XENIX
+3.6.2. [364]SCO UNIX and OSR5
+3.6.3. [365]Unixware
+3.6.4. [366]Open UNIX 8
+
+ REFERENCES
+
+ * The comp.unix.sco.* newsgroups.
+ * [367]Section 3.10 below for Unixware.
+ * The following FAQs:
+
+ The comp.sco.misc FAQ:
+ [368]http://aplawrence.com/SCOFAQ/
+
+ Caldera (SCO) comp.unix.sco.programmer FAQ:
+ [369]http://www.zenez.com/cgi-bin/scoprogfaq/faq.pl
+
+ The UnixWare 7/OpenUNIX 8 FAQ:
+ [370]http://www.zenez.com/cgi-bin/scouw7faq/faq.pl
+ [371]http://zenez.pcunix.com/cgi-bin/scouw7faq/faq.pl
+
+ High Speed Modems for SCO Unix:
+ [372]http://pcunix.com/Unixart/modems.html
+
+ The UnixWare FAQ
+ [373]http://www.freebird.org/faq/
+
+ The UnixWare 1.x and 2.0 Programmer FAQ
+ [374]http://www.freebird.org/faq/developer.html
+
+ Caldera Support Knowledge Base
+ [375]http://support.caldera.com/caldera
+
+ [376]http://stage.caldera.com/ta/
+ Caldera (SCO) Technical Article Search Center
+
+ [377]http://aplawrence.com/newtosco.html
+ New to SCO (Tony Lawrence)
+
+ The same comments regarding terminal emulation and key mapping apply to
+ SCO operating systems as to all other Unixes. C-Kermit is not a
+ terminal emulator, and you can't use it to map F-keys, Arrow keys, etc.
+ The way to do this is with xmodmap (xterm) or loadkeys (console). For a
+ brief explanation, see [378]Section 3.0.5. For a fuller explanation,
+ [379]ClICK HERE.
+
+ Also see general comments on PC-based Unixes in [380]Section 3.0.
+
+3.6.1. SCO XENIX
+
+ [ [381]Top ] [ [382]Contents ] [ [383]Section Contents ] [ [384]Next ]
+
+ Old Xenix versions... Did you know: Xenix 3.0 is *older* than Xenix
+ 2.0?
+
+ In Xenix 2.3.4 and probably other Xenix versions, momentarily dropping
+ DTR to hang up a modem does not work. DTR goes down but does not come
+ up again. Workaround: Use SET MODEM HANGUP-METHOD MODEM-COMMAND.
+ Anybody who would like to fix this is welcome to take a look at
+ tthang() in [385]ckutio.c. Also: modem signals can not be read in
+ Xenix, and the maximum serial speed is 38400.
+
+ There is all sorts of confusion among SCO versions, particularly when
+ third- party communications boards and drivers are installed, regarding
+ lockfile naming conventions, as well as basic functionality. As far as
+ lockfiles go, all bets are off if you are using a third-party multiport
+ board. At least you have the source code. Hopefully you also have a C
+ compiler :-)
+
+ Xenix 2.3.0 and later claim to support RTSFLOW and CTSFLOW, but this is
+ not modern bidirectional hardware flow control; rather it implements
+ the original RS-232 meanings of these signals for unidirectional
+ half-duplex line access: If both RTSFLOW and CTSFLOW bits are set,
+ Xenix asserts RTS when it wants to send data and waits for CTS
+ assertion before it actually starts sending data (also, reportedly,
+ even this is broken in Xenix 2.3.0 and 2.3.1).
+
+3.6.2. SCO UNIX AND OSR5
+
+ [ [386]Top ] [ [387]Contents ] [ [388]Section Contents ] [ [389]Next ]
+ [ [390]Previous ]
+
+ SCO systems tend to use different names (i.e. drivers) for the same
+ device. Typically /dev/tty1a refers to a terminal device that has no
+ modem control; open, read, write, and close operations do not depend on
+ carrier. On the other hand, /dev/tty1A (same name, but with final
+ letter upper case), is the same device with modem control, in which
+ carrier is required (the SET LINE command does not complete until
+ carrier appears, read/write operations fail if there is no carrier,
+ etc).
+
+ SCO OpenServer 5.0.5 and earlier do not support the reading of modem
+ signals. Thus "show comm" does not list modem signals, and C-Kermit
+ does not automatically pop back to its prompt when the modem hangs up
+ the connection (drops CD). The ioctl() call for this is simply not
+ implemented, at least not in the standard drivers. OSR5.0.6 attempts to
+ deal with modem signals but fails; however OSR5.0.6a appears to
+ function properly.
+
+ Dialing is likely not to work well in SCO OpenServer 5.0.x because many
+ of the serial-port APIs simply do not operate when using the standard
+ drivers. For example, if DTR is dropped by the recommended method
+ (setting speed to 0 for half a seconds, then restoring the speed), DTR
+ and RTS go down but never come back up. When in doubt SET MODEM
+ HANGUP-METHOD MODEM-COMMAND or SET DIAL HANGUP OFF.
+
+ On the other hand, certain functions that might not (do not) work right
+ or at all when using SCO drivers (e.g. high serial speeds, hardware
+ flow control, and/or reading of modem signals) might work right when
+ using third-party drivers. (Example: hardware flow control works,
+ reportedly, only on uppercase device like tty1A -- not tty1a -- and
+ only when CLOCAL is clear when using the SCO sio driver, but there are
+ no such restrictions in, e.g., [391]Digiboard drivers).
+
+ One user reports that he can't transfer large files with C-Kermit under
+ SCO OSR5.0.0 and 5.0.4 -- after the first 5K, everything falls apart.
+ Same thing without Kermit -- e.g. with ftp over a PPP connection.
+ Later, he said that replacing SCO's SIO driver with FAS, an alternative
+ communications driver, made the problem go away:
+
+ [392]ftp://ftp.fu-berlin.de/pub/unix/driver/fas
+
+ With regard to bidirectional serial ports on OpenServer 5.0.4, the
+ following advice appeared on an SCO-related newsgroup:
+
+ No amount of configuration information is going to help you on 5.0.4
+ unless it includes the kludge for the primary problem. With almost
+ every modem, the 5.0.4 getty will barf messages and may or may not
+ connect. There are 2 solutions and only one works on 5.0.4. Get the
+ atdialer binary from a 5.0.0 system and substitute it for the native
+ 5.0.4 atdialer. The other solution is to upgrade to 5.0.5. And, most
+ of all, on any OpenServer products, do NOT run the badly broken
+ Modem Manager. Configure the modems in the time honored way that
+ dates back to Xenix.
+
+ Use SCO-provided utilities for switching the directionality of a modem
+ line, such as "enable" and "disable" commands. For example, to dial out
+ on tty1a, which is normally set up for logins:
+
+ disable tty1a
+ kermit -l /dev/tty1a
+ enable tty1a
+
+ If a tty device is listed as an ACU in /usr/lib/uucp/Devices and is
+ enabled, getty resets the ownership and permissions to uucp.uucp and
+ 640 every time the device is released. If you want to use the device
+ only for dialout, and you want to specify other owners or permissions,
+ you should disable it in /usr/lib/uucp/Devices; this will prevent getty
+ from doing things to it. You should also changes the device's file
+ modes in /etc/conf/node.d/sio by changing fields 5-7 for the desired
+ device(s); this determines how the devices are set if you relink the
+ kernel.
+
+ One SCO user of C-Kermit 5A(190) reported that only one copy of Kermit
+ can run at a time when a Stallion Technologies multiport boards are
+ installed. Cause, cure, and present status unknown (see [393]Section 14
+ for more info regarding Stallion).
+
+ Prior to SCO OpenServer 5.0.4, the highest serial port speed supported
+ by SCO was 38400. However, in some SCO versions (e.g. OSR5) it is
+ possible to map rarely-used lower speeds (like 600 and 1800) to higher
+ ones like 57600 and 115200. To find out how, go to
+ [394]http://www.sco.com/ and search for "115200". In OSR5.0.4, serial
+ speeds up to 921600 are supported through the POSIX interface; C-Kermit
+ 6.1.193 or later, when built for OSR5.0.4 using /bin/cc (NOT the UDK,
+ which hides the high-speed definitions from CPP), supports these
+ speeds, but you might be able to run this binary on earlier releases to
+ get the high serial speeds, depending on various factors, described by
+ Bela Lubkin of SCO:
+
+ Serial speeds under SCO Unix / Open Desktop / OpenServer
+ ========================================================
+ Third party drivers (intelligent serial boards) may provide any speeds
+ they desire; most support up to 115.2Kbps.
+
+ SCO's "sio" driver, which is used to drive standard serial ports with
+ 8250/16450/16550 and similar UARTs, was limited to 38400bps in older
+ releases. Support for rates through 115.2Kbps was added in the
+ following releases:
+
+ SCO OpenServer Release 5.0.0 (requires supplement "rs40b")
+ SCO OpenServer Release 5.0.2 (requires supplement "rs40a" or "rs40b")
+ SCO OpenServer Release 5.0.4 or later
+ SCO Internet FastStart Release 1.0.0 or later
+
+ SCO supplements are at [395]ftp://ftp.sco.com/; the "rs40" series are
+ under directory /Supplements/internet
+
+ Kermit includes the high serial speeds in all OSR5 builds, but that
+ does not necessarily mean they work. For example, on our in-house 5.0.5
+ system, SET SPEED 57600 or higher seems to succeed (no error occurs)
+ but when we read the speed back the driver says it is 50. Similarly,
+ 76800 becomes 75, and 115200 becomes 110. Testing shows the resulting
+ speed is indeed the low one we read back, not the high one we asked
+ for. Moral: Use speeds higher than 38400 with caution on SCO OSR5.
+
+ Reportedly, if you have a script that makes a TCP/IP SET HOST (e.g.
+ Telnet) connection to SCO 3.2v4.2 with TCP/IP 1.2.1, and then does the
+ following:
+
+ script $ exit
+ hangup
+
+ this causes a pseudoterminal (pty) to be consumed on the SCO system; if
+ you do it enough times, it will run out of ptys. An "exit" command is
+ being sent to the SCO shell, and a HANGUP command is executed locally,
+ so the chances are good that both sides are trying to close the
+ connection at once, perhaps inducing a race condition in which the
+ remote pty is not released. It was speculated that this would be fixed
+ by applying SLS net382e, but it did not. Meanwhile, the workaround is
+ to insert a "pause" between the SCRIPT and HANGUP commands. (The
+ situation with later SCO releases is not known.)
+
+ SCO UNIX and OpenServer allow their console and/or terminal drivers to
+ be configured to translate character sets for you. DON'T DO THIS WHEN
+ USING KERMIT! First of all, you don't need it -- Kermit itself already
+ does this for you. And second, it will (a) probably ruin the formatting
+ of your screens (depending on which emulation you are using); and (b)
+ interfere with all sorts of other things -- legibility of non-ASCII
+ text on the terminal screen, file transfer, etc. Use:
+
+ mapchan -n
+
+ to turn off this feature.
+
+ Note that there is a multitude of SCO entries in the makefile, many of
+ them exhibiting an unusually large number of compiler options. Some
+ people actually understand all of this. Reportedly, things are settling
+ down with SCO OpenServer 5.x and Unixware 7 (and Open UNIX 8 and who
+ knows what the next one will be -- Linux probably) -- the SCO UDK
+ compiler is said to generate binaries that will run on either platform,
+ by default, automatically. When using gcc or egcs, on the other hand,
+ differences persist, plus issues regarding the type of binary that is
+ generated (COFF, ELF, etc), and where and how it can run. All of this
+ could stand further clarification by SCO experts.
+
+3.6.3. Unixware
+
+ [ [396]Top ] [ [397]Contents ] [ [398]Section Contents ] [ [399]Next ]
+ [ [400]Previous ]
+
+ Unixware changed hands several times before landing at SCO, and so has
+ its [401]own section in this document. (Briefly: AT&T UNIX Systems
+ Laboratories sold the rights to the UNIX name and to System V R4 (or
+ R5?) to Novell; later Novell spun its UNIX division off into a new
+ company called Univel, which eventually was bought by SCO, which later
+ was bought by Caldera, which later sort of semi-spun-off SCO...)
+
+3.6.4. Open UNIX 8
+
+ [ [402]Top ] [ [403]Contents ] [ [404]Section Contents ] [
+ [405]Previous ]
+
+ SCO was bought by Caldera in 2000 or 2001 and evolved Unixware 7.1 into
+ Caldera Open UNIX 8.00. It's just like Unixware 7.1 as far as Kermit is
+ concerned (the Unixware 7.1 makefile target works for Open UNIX 8.00,
+ and in fact a Unixware 7.1 Kermit binary built on Unixware 7.1 runs
+ under OU8; a separate OU8 makefile target exists simply to generate an
+ appropriate program startup herald). Open Unix is now defunct;
+ subsequent releases are called UnixWare again (e.g. UnixWare 7.1.3).
+
+3.7. C-KERMIT AND SOLARIS
+
+ [ [406]Top ] [ [407]Contents ] [ [408]Section Contents ] [ [409]Next ]
+ [ [410]Previous ]
+
+ SECTION CONTENTS
+
+3.7.1. [411]Serial Port Configuration
+3.7.2. [412]Serial Port Problems
+3.7.3. [413]SunLink X.25
+3.7.4. [414]Sun Workstation Keyboard Mapping
+3.7.5. [415]Solaris 2.4 and Earlier
+
+ REFERENCES
+
+ * The [416]comp.unix.solaris newsgroup
+ * [417]http://access1.sun.com/
+ * [418]http://docs.sun.com/
+ * [419]http://www.sunhelp.com/
+ * [420]http://www.wins.uva.nl/pub/solaris/solaris2/
+ * [421]http://www.wins.uva.nl/cgi-bin/sfaq.cgi
+ * [422]ftp://ftp.wins.uva.nl/pub/solaris
+ * [423]http://www.science.uva.nl/pub/solaris/solaris2.html
+
+ And about serial communications in particular, see "Celeste's Tutorial
+ on Solaris 2.x Modems and Terminals":
+
+ [424]http://www.stokely.com/
+
+ In particular:
+
+ [425]http://www.stokely.com/unix.sysadm.resources/faqs.sun.html
+
+ For PC-based Solaris, also see general comments on PC-based Unixes in
+ [426]Section 3.0. Don't expect Solaris or any other kind of Unix to
+ work right on a PC until you resolve all interrupt conflicts. Don't
+ expect to be able to use COM3 or COM4 (or even COM2) until you have
+ configured their addresses and interrupts.
+
+3.7.1. Serial Port Configuration
+
+ [ [427]Top ] [ [428]Contents ] [ [429]Section Contents ] [ [430]Section
+ Contents ] [ [431]Next ]
+
+ Your serial port can't be used -- or at least won't work right -- until
+ it is enabled in Solaris. For example, you get a message like "SERIAL:
+ Operation would block" when attempting to dial. This probably indicates
+ that the serial port has not been enabled for use with modems. You'll
+ need to follow the instructions in your system setup or management
+ manual, such as (e.g.) the Desktop SPARC Sun System & Network Manager's
+ Guide, which should contain a section "Setting up Modem Software"; read
+ it and follow the instructions. These might (or might not) include
+ running a program called "eeprom", editing some system configuration
+ file (such as, for example:
+
+ /platform/i86pc/kernel/drv/asy.conf
+
+ and then doing a configuration reboot, or running some other programs
+ like drvconfig and devlinks. "man eeprom" for details.
+
+ Also, on certain Sun models like IPC, the serial port hardware might
+ need to have a jumper changed to make it an RS-232 port rather than
+ RS-423.
+
+ eeprom applies only to real serial ports, not to "Spiff" devices
+ (serial port expander), in which case setup with Solaris' admintool is
+ required.
+
+ Another command you might need to use is pmadm, e.g.:
+
+ pmadm -d -p zsmon -s tty3
+ pmadm -e -p zsmon -s tty3
+
+ You can use the following command to check if a process has the device
+ open:
+
+ fuser -f /dev/term/3
+
+ In some cases, however (according to Sun support, May 2001) "It is
+ still possible that a zombie process has hold of the port EVEN IF there
+ is no lock file and the fuser command comes up empty. In that case, the
+ only way to resolve the problem is by rebooting."
+
+ If you can't establish communication through a serial port to a device
+ that is not asserting CD (Carrier Detect), try setting the environment
+ variable "ttya-ignore-cd" to "true" (replace "ttya" with the port
+ name).
+
+3.7.2. Serial Port Problems
+
+ [ [432]Top ] [ [433]Contents ] [ [434]Section Contents ] [ [435]Next ]
+ [ [436]Previous ]
+
+ Current advice from Sun is to always the /dev/cua/x devices for dialing
+ out, rather than the /dev/term/x. Nevertheless, if you have trouble
+ dialing out with one, try the other.
+
+ Reportedly, if you start C-Kermit and "set line" to a port that has a
+ modem connected to it that is not turned on, and then "set flow
+ rts/cts", there might be some (unspecified) difficulties closing the
+ device because the CTS signal is not coming in from the modem.
+
+3.7.3. SunLink X.25
+
+ [ [437]Top ] [ [438]Contents ] [ [439]Section Contents ] [ [440]Next ]
+ [ [441]Previous ]
+
+ The built-in SunLink X.25 support for Solaris 2.3/2.4./25 and SunLink
+ 8.01 or 9.00 works OK provided the X.25 system has been installed and
+ initialized properly. Packet sizes might need to be reduced to 256,
+ maybe even less, depending on the configuration of the X.25
+ installation. On one connection where C-Kermit 6.0 was tested, very
+ large packets and window sizes could be used in one direction, but only
+ very small ones would work in the other.
+
+ In any case, according to Sun, C-Kermit's X.25 support is superfluous
+ with SunLink 8.x / Solaris 2.3. Quoting an anonymous Sun engineer:
+
+ ... there is now no need to include any X.25 code within kermit. As
+ of X.25 8.0.1 we support the use of kermit, uucp and similar
+ protocols over devices of type /dev/xty. This facility was there in
+ 8.0, and should also work on the 8.0 release if patch 101524 is
+ applied, but I'm not 100% sure it will work in all cases, which is
+ why we only claim support from 8.0.1 onwards.
+
+ When configuring X.25, on the "Advanced Configuration->Parameters"
+ screen of the x25tool you can select a number of XTY devices. If you
+ set this to be > 1, press Apply, and reboot, you will get a number
+ of /dev/xty entries created.
+
+ Ignore /dev/xty0, it is a special case. All the others can be used
+ exactly as if they were a serial line (e.g. /dev/tty) connected to a
+ modem, except that instead of using Hayes-style commands, you use
+ PAD commands.
+
+ From kermit you can do a 'set line' command to, say, /dev/xty1, then
+ set your dialing command to be "CALL 12345678", etc. All the usual
+ PAD commands will work (SET, PAR, etc).
+
+ I know of one customer in Australia who is successfully using this,
+ with kermit scripts, to manage some X.25-connected switches. He used
+ standard kermit, compiled for Solaris 2, with X.25 8.0 xty devices.
+
+3.7.4. Sun Workstation Keyboard Mapping
+
+ [ [442]Top ] [ [443]Contents ] [ [444]Section Contents ] [ [445]Next ]
+ [ [446]Previous ]
+
+ Hints for using a Sun workstation keyboard for VT emulation when
+ accessing VMS, from the [447]comp.os.vms newsgroup:
+
+ From: Jerry Leichter <leichter@smarts.com>
+ Newsgroups: comp.os.vms
+ Subject: Re: VT100 keyboard mapping to Sun X server
+ Date: Mon, 19 Aug 1996 12:44:21 -0400
+
+ > I am stuck right now using a Sun keyboard (type 5) on systems
+ running SunOS
+ > and Solaris. I would like to use EVE on an OpenVMS box with
+ display back to
+ > the Sun. Does anyone know of a keyboard mapping (or some other
+ procedure)
+ > which will allow the Sun keyboard to approximate a VT100/VT220?
+
+ You can't get it exactly - because the keypad has one fewer key -
+ but you can come pretty close. Here's a set of keydefs I use:
+
+ keycode 101=KP_0
+ keycode 119=KP_1
+ keycode 120=KP_2
+ keycode 121=KP_3
+ keycode 98=KP_4
+ keycode 99=KP_5
+ keycode 100=KP_6
+ keycode 75=KP_7
+ keycode 76=KP_8
+ keycode 77=KP_9
+ keycode 52=KP_F1
+ keycode 53=KP_F2
+ keycode 54=KP_F3
+ keycode 57=KP_Decimal
+ keycode 28=Left
+ keycode 29=Right
+ keycode 30=KP_Separator
+ keycode 105=KP_F4
+ keycode 78=KP_Subtract
+ keycode 8=Left
+ keycode 10=Right
+ keycode 32=Up
+ keycode 33=Down
+ keycode 97=KP_Enter
+
+ Put this in a file - I use "keydefs" in my home directory and feed
+ it into xmodmap:
+
+ xmodmap - <$HOME/keydefs
+
+ This takes care of the arrow keys and the "calculator" key cluster.
+ The "+" key will play the role of the DEC "," key. The Sun "-" key
+ will be like the DEC "-" key, though it's in a physically different
+ position - where the DEC PF4 key is. The PF4 key is ... damn, I'm
+ not sure where "key 105" is. I *think* it may be on the leftmost key
+ of the group of four just above the "calculator" key cluster.
+
+ I also execute the following (this is all in my xinitrc file):
+
+ xmodmap -e 'keysym KP_Decimal = KP_Decimal'
+ xmodmap -e 'keysym BackSpace = Delete BackSpace' \
+ -e 'keysym Delete = BackSpace Delete'
+ xmodmap -e 'keysym KP_Decimal = Delete Delete KP_Decimal'
+ xmodmap -e 'add mod1 = Meta_R'
+ xmodmap -e 'add mod1 = Meta_L'
+
+ Beware of one thing about xmodmap: Keymap changes are applied to the
+ *whole workstation*, not just to individual windows. There is, in
+ fact, no way I know of to apply them to individual windows. These
+ definitions *may* confuse some Unix programs (and/or some Unix
+ users).
+
+ If you're using Motif, you may also need to apply bindings at the
+ Motif level. If just using xmodmap doesn't work, I can try and dig
+ that stuff up for you.
+
+3.7.5. Solaris PPP Connections
+
+ [ [448]Top ] [ [449]Contents ] [ [450]Section Contents ] [ [451]Next ]
+ [ [452]Previous ]
+
+ The following is a report from a user of C-Kermit 8.0 on Solaris 8 and
+ 9, who had complained that while Kermit file transfers worked perfectly
+ on direct (non-PPP) dialout connections, they failed miserably on PPP
+ connections. We suggested that the PPP dialer probably was not setting
+ the port and/or modem up in the same way that Kermit did:
+
+ I want to get back on this and tell you what the resolution was. You
+ pointed me in the direction of flow control, which turned out to be
+ the key.
+
+ Some discussion on the comp.unix.solaris newsgroup led to some
+ comments from Greg Andrews about the need to use the uucp driver to
+ talk to the modem (/dev/cua/a). I had to remind Greg that no matter
+ what the manpages for the zs and se drivers say, the ppp that Sun
+ released with Solaris 8 7/01, and has in Solaris 9, is a setuid root
+ program, and simply trying to make a pppd call from user space
+ specifying /dev/cua/a would fail because of permissions. Greg
+ finally put the question to the ppp people, who came back with
+ information that is not laid out anywhere in the docs available for
+ Solaris users. Namely, put /dev/cua/a in one of the privileged
+ options files in the /etc/ppp directory. That, plus resetting the
+ OBP ttya-ignore-cd flag (this is Sun hardware) to false, seems to
+ have solved the problems.
+
+ While I note that I had installed Kermit suid to uucp to use
+ /dev/cua/a on this particular box, it seems to run fine through
+ /dev/term/a. Not so with pppd.
+
+ With this change in place, I seem to be able to upload and download
+ through telnet run on Kermit with the maximum length packets. I note
+ that the window allocation display does show STREAMING, using
+ telnet. Running ssh on Kermit, I see the standard 1 of 30 windows
+ display, and note that there appears to be a buffer length limit
+ between 1000 and 2000 bytes. Run with 1000, and it's tick-tock,
+ solid as a rock. With 2000 I see timeout errors and RTS/CTS action
+ on the modem.
+
+ Kermit's packet-length and other controls let you make adjustments like
+ this to get around whatever obstacles might be thrown up -- in this
+ case (running Kermit over ssh), the underling Solaris PTY driver.
+
+3.7.6. Solaris 2.4 and Earlier
+
+ [ [453]Top ] [ [454]Contents ] [ [455]Section Contents ] [
+ [456]Previous ]
+
+ C-Kermit can't be compiled successfully under Solaris 2.3 using
+ SUNWspro cc 2.0.1 unless at least some of the following patches are
+ applied to cc (it is not known which one(s), if any, fix the problem):
+
+ * 100935-01 SparcCompiler C 2.0.1: bad code generated when addresses
+ of two double arguments are involved
+ * 100961-05 SPARCcompilers C 2.0.1: conditional expression with
+ function returning structure gives wrong value
+ * 100974-01 SparcWorks 2.0.1: dbx jumbo patch
+ * 101424-01 SPARCworks 2.0.1 maketool SEGV's instantly on Solaris 2.3
+
+ With unpatched cc 2.0.1, the symptom is that certain modules generate
+ truncated object files, resulting in many unresolved references at link
+ time.
+
+ The rest of the problems in this section have to do with
+ bidirectional terminal ports and the Solaris Port Monitor. A bug in
+ C-Kermit 5A ticked a bug in Solaris. The C-Kermit bug was fixed in
+ version 6.0, and the Solaris bug was fixed in 2.4 (I think, or maybe
+ 2.5).
+
+ Reportedly, "C-Kermit ... causes a SPARCstation running Solaris 2.3 to
+ panic after the modem connects. I have tried compiling C-Kermit with
+ Sun's unbundled C compiler, with GCC Versions 2.4.5 and 2.5.3, with
+ make targets 'sunos51', 'sunos51tcp', 'sunos51gcc', and even 'sys5r4',
+ and each time it compiles and starts up cleanly, but without fail, as
+ soon as I dial the number and get a 'CONNECT' message from the modem, I
+ get:
+
+ BAD TRAP
+ kermit: Data fault
+ kernel read fault at addr=0x45c, pme=0x0
+ Sync Error Reg 80 <INVALID>
+ ...
+ panic: Data Fault.
+ ...
+ Rebooting...
+
+ The same modem works fine for UUCP/tip calling." Also (reportedly),
+ this only happens if the dialout port is configured as in/out via
+ admintool. If it is configured as out-only, no problem. This is the
+ same dialing code that works on hundreds of other System-V based Unix
+ OS's. Since it should be impossible for a user program to crash the
+ operating system, this problem must be chalked up to a Solaris bug.
+ Even if you SET CARRIER OFF, CONNECT, and dial manually by typing
+ ATDTnnnnnnn, the system panics as soon as the modem issues its CONNECT
+ message. (Clearly, when you are dialing manually, C-Kermit does not
+ know a thing about the CONNECT message, and so the panic is almost
+ certainly caused by the transition of the Carrier Detect (CD) line from
+ off to on.) This problem was reported by many users, all of whom say
+ that C-Kermit worked fine on Solaris 2.1 and 2.2. If the speculation
+ about CD is true, then a possible workaround might be to configure the
+ modem to leave CD on (or off) all the time. Perhaps by the time you
+ read this, a patch will have been issued for Solaris 2.3.
+
+ The following is from Karl S. Marsh, Systems & Networks Administrator,
+ AMBIX Systems Corp, Rochester, NY:
+
+ Environment: Solaris 2.3 Patch 101318-45 C-Kermit 5A(189) (and
+ presumably this applies to 188 and 190 also). eeprom setting:
+
+ ttya-rts-dtr-off=false
+ ttya-ignore-cd=false
+ ttya-mode=19200,8,n,8,-
+
+ To use C-Kermit on a bidirectional port in this environment, do not
+ use admintool to configure the port. Use admintool to delete any
+ services running on the port and then quit admintool and issue the
+ following command:
+
+ pmadm -a -p zsmon -s ttyb -i root -fu -v 1 -m "`ttyadm -b -d /dev/term/b \
+ -l conttyH -m ldterm,ttcompat -s /usr/bin/login -S n`"
+
+ [NOTE: This was copied from a blurry fax, so please check it
+ carefully] where:
+
+ -a = Add service
+ -p = pmtag (zsmon)
+ -s = service tag (ttyb)
+ -i = id to be associated with service tag (root)
+ -fu = create utmp entry
+ -v = version of ttyadm
+ -m = port monitor-specific portion of the port monitor administrative file
+ entry for the service
+ -b = set up port for bidirectional use
+ -d = full path name of device
+ -l = which ttylabel in the /etc/ttydefs file to use
+ -m = a list of pushable STREAMS modules
+ -s = pathname of service to be invoked when connection request received
+ -S = software carrier detect on or off (n = off)
+
+ "This is exactly how I was able to get Kermit to work on a
+ bi-directional port without crashing the system."
+
+ On the Solaris problem, also see SunSolve Bug ID 1150457 ("Using
+ C-Kermit, get Bad Trap on receiving prompt from remote system").
+ Another user reported "So, I have communicated with the Sun tech
+ support person that submitted this bug report [1150457]. Apparently,
+ this bug was fixed under one of the jumbo kernel patches. It would seem
+ that the fix did not live on into 101318-45, as this is EXACTLY the
+ error that I see when I attempt to use kermit on my system."
+
+ Later (Aug 94)... C-Kermit dialout successfully tested on a Sun4m with
+ a heavily patched Solaris 2.3. The patches most likely to have been
+ relevant:
+
+ * 101318-50: SunOS 5.3: Jumbo patch for kernel (includes libc, lockd)
+ * 101720-01: SunOS 5.3: ttymon - prompt not always visible on a modem
+ connection
+ * 101815-01: SunOS 5.3: Data fault in put() NULL queue passed from
+ ttycommon_qfull()
+ * 101328-01: SunOS 5.3: Automation script to properly setup tty ports
+ prior to PCTS execution
+
+ Still later (Nov 94): another user (Bo Kullmar in Sweden) reports that
+ after using C-Kermit to dial out on a bidirectional port, the port
+ might not answer subsequent incoming calls, and says "the problem is
+ easy enough to fix with the Serial Port Manager; I just delete the
+ service and install it again using the graphical interface, which
+ underneath uses commands like sacadm and pmadm." Later Bo reports, "I
+ have found that if I run Kermit with the following script then it
+ works. This script is for /dev/cua/a, "-s a" is the last a in
+ /dev/cua/a:
+
+ #! /bin/sh
+ kermit
+ sleep 2
+ surun pmadm -e -p zsmon -s a
+
+3.8. C-KERMIT AND SUNOS
+
+ [ [457]Top ] [ [458]Contents ] [ [459]Section Contents ] [ [460]Next ]
+ [ [461]Previous ]
+
+ For additional information, see "Celeste's Tutorial on SunOS 4.1.3+
+ Modems and Terminals":
+
+ [462]http://www.stokely.com/
+
+ For FAQs, etc, from Sun, see:
+ * [463]http://access1.sun.com/
+
+ For history of Sun models and SunOS versions, see (should be all the
+ same):
+ * [464]http://www.ludd.luth.se/~bear/project/sun/sun.hardware.txt
+ * [465]ftp://ftp.netcom.com/pub/ru/rubicon/sun.hdwr.ref
+ * [466]ftp://ftp.intnet.net/pub/SUN/Sun-Hardware-Ref
+
+ Sun SPARCstation users should read the section "Setting up Modem
+ Software" in the Desktop SPARC Sun System & Network Manager's Guide. If
+ you don't set up your serial ports correctly, Kermit (and other
+ communications software) won't work right.
+
+ Also, on certain Sun models like IPC, the serial port hardware might
+ need to have a jumper changed to make it an RS-232 port rather than
+ RS-423.
+
+ Reportedly, C-Kermit does not work correctly on a Sun SPARCstation in
+ an Open Windows window with scrolling enabled. Disable scrolling, or
+ else invoke Kermit in a terminal emulation window (xterm, crttool,
+ vttool) under SunView (this might be fixed in later SunOS releases).
+
+ On the Sun with Open Windows, an additional symptom has been reported:
+ outbound SunLink X.25 connections "magically" translate CR typed at the
+ keyboard into LF before transmission to the remote host. This doesn't
+ happen under SunView.
+
+ SET CARRIER ON, when used on the SunOS 4.1 version of C-Kermit
+ (compiled in the BSD universe), causes the program to hang
+ uninterruptibly when SET LINE is issued for a device that is not
+ asserting carrier. When Kermit is built in the Sys V universe on the
+ same computer, there is no problem (it can be interrupted with Ctrl-C).
+ This is apparently a limitation of the BSD-style tty driver.
+
+ SunOS 4.1 C-Kermit has been observed to dump core when running a
+ complicated script program under cron. The dump invariably occurs in
+ ttoc(), while trying to output a character to a TCP/IP TELNET
+ connection. ttoc() contains a write() call, and when the system or the
+ network is very busy, the write() call can get stuck for long periods
+ of time. To break out of deadlocks caused by stuck write() calls, there
+ is an alarm around the write(). It is possible that the core dump
+ occurs when this alarm signal is caught. (This one has not been
+ observed recently -- possibly fixed in edit 190.)
+
+ On Sun computers with SunOS 4.0 or 4.1, SET FLOW RTS/CTS works only if
+ the carrier signal is present from the communication device at the time
+ when C-Kermit enters packet mode or CONNECT mode. If carrier is not
+ sensed (e.g. when dialing), C-Kermit does not attempt to turn on
+ RTS/CTS flow control. This is because the SunOS serial device driver
+ does not allow characters to be output if RTS/CTS is set (CRTSCTS) but
+ carrier (and DSR) are not present. Workaround (maybe): SET CARRIER OFF
+ before giving the SET LINE command, establish the connection, then SET
+ FLOW RTS/CTS
+
+ It has also been reported that RTS/CTS flow control under SunOS 4.1
+ through 4.1.3 works only on INPUT, not on output, and that there is a
+ patch from Sun to correct this problem: Patch-ID# T100513-04, 20 July
+ 1993 (this patch might apply only to SunOS 4.1.3). It might also be
+ necessary to configure the eeprom parameters of the serial port; e.g.
+ do the following as root at the shell prompt:
+
+ eeprom ttya-ignore-cd=false
+ eeprom ttya-rts-dtr-off=true
+
+ There have been reports of file transfer failures on Sun-3 systems when
+ using long packets and/or large window sizes. One user says that when
+ this happens, the console issues many copies of this message:
+
+ chaos vmunix: zs1: ring buffer overflow
+
+ This means that SunOS is not scheduling Kermit frequently enough to
+ service interrupts from the zs serial device (Zilog 8350 SCC serial
+ communication port) before its input silo overflows. Workaround: use
+ smaller packets and/or a smaller window size, or use "nice" to increase
+ Kermit's priority. Use hardware flow control if available, or remove
+ other active processes before running Kermit.
+
+ SunLink X.25 support in C-Kermit 5A(190) was built and tested
+ successfully under SunOS 4.1.3b and SunLink X.25 7.00.
+
+3.9. C-KERMIT AND ULTRIX
+
+ [ [467]Top ] [ [468]Contents ] [ [469]Section Contents ] [ [470]Next ]
+ [ [471]Previous ]
+
+ See also: The [472]comp.unix.ultrix and [473]comp.sys.dec newsgroups.
+
+ There is no hardware flow control in Ultrix. That's not a Kermit
+ deficiency, but an Ultrix one.
+
+ When sending files to C-Kermit on a Telnet connection to a remote
+ Ultrix system, you must SET PREFIXING ALL (or at least prefix more
+ control characters than are selected by SET PREFIXING CAUTIOUS).
+
+ Reportedly, DEC ULTRIX 4.3 is immune to C-Kermit's disabling of
+ SIGQUIT, which is the signal that is generated when the user types
+ Ctrl-\, which kills the current process (i.e. C-Kermit) and dumps core.
+ Diagnosis and cure unknown. Workaround: before starting C-Kermit -- or
+ for that matter, when you first log in because this applies to all
+ processes, not just Kermit -- give the following Unix command:
+
+ stty quit undef
+
+ Certain operations driven by RS-232 modem signal do not work on
+ DECstations or other DEC platforms whose serial interfaces use MMP
+ connectors (DEC version of RJ45 telephone jack with offset tab). These
+ connectors convey only the DSR and DTR modem signals, but not carrier
+ (CD), RTS, CTS, or RI. Use SET CARRIER OFF to enable communication, or
+ "hotwire" DSR to CD.
+
+ The maximum serial speed on the DECstation 5000 is normally 19200, but
+ various tricks are available (outside Kermit) to enable higher rates.
+ For example, on the 5000/200, 19200 can be remapped (somehow, something
+ to do with "a bit in the SIR", whatever that is) to 38400, but in
+ software you must still refer to this speed as 19200; you can't have
+ 19200 and 38400 available at the same time.
+
+ 19200, reportedly, is also the highest speed supported by Ultrix, but
+ NetBSD reportedly supports speeds up to 57600 on the DECstation,
+ although whether and how well this works is another question.
+
+ In any case, given the lack of hardware flow control in Ultrix, high
+ serial speeds are problematic at best.
+
+3.10. C-KERMIT AND UNIXWARE
+
+ [ [474]Top ] [ [475]Contents ] [ [476]Section Contents ] [ [477]Next ]
+ [ [478]Previous ]
+
+ See also:
+ * The Freebird Project (Unixware software repository)
+ [479]http://www.freebird.org/
+ * The UnixWare FAQ: [480]http://www.freebird.org/faq/
+ * The following newsgroups:
+ + [481]comp.unix.unixware.misc
+ + [482]comp.unix.sco.misc.
+
+ Also see general comments on PC-based Unixes in [483]Section 3.0. By
+ the way, this section is separate from the SCO (Caldera) section
+ because at the time this section was started, Unixware was owned by a
+ company called Univel. Later it was sold to Novell, and then to SCO.
+ Still later, SCO was sold to Caldera.
+
+ In Unixware 2.0 and later, the preferred serial device names (drivers)
+ are /dev/term/00 (etc), rather than /dev/tty00 (etc). Note the
+ following correspondence of device names and driver characteristics:
+
+ New name Old name Description
+ /dev/term/00 /dev/tty00 ???
+ /dev/term/00h /dev/tty00h Modem signals and hardware flow control
+ /dev/term/00m /dev/tty00m Modem signals(?)
+ /dev/term/00s /dev/tty00s Modem signals and software flow control
+ /dev/term/00t /dev/tty00t ???
+
+ Lockfile names use device.major.minor numbers, e.g.:
+
+ /var/spool/locks/LK.7679.003.005
+
+ The minor number varies according to the device name suffix (none, h,
+ m, s, or t). Only the device and major number are compared, and thus
+ all of the different names for the same physical device (e.g. all of
+ those shown in the table above) interlock effectively.
+
+ Prior to UnixWare 7, serial speeds higher than 38400 are not supported.
+ In UnixWare 7, we also support 57600 and 115200, plus some unexpected
+ ones like 14400, 28800, and 76800, by virtue of a strange new
+ interface, evidently peculiar to UnixWare 7, discovered while digging
+ through the header files: tcsetspeed(). Access to this interface is
+ allowed only in POSIX builds, and thus the UnixWare 7 version of
+ C-Kermit is POSIX-based, unlike C-Kermit for Unixware 1.x and 2.x
+ (since the earlier UnixWare versions did not support high serial
+ speeds, period).
+
+ HOWEVER, turning on POSIX features engages all of the "#if
+ (!_POSIX_SOURCE)" clauses in the UnixWare header files, which in turn
+ prevent us from having modem signals, access to the hardware flow
+ control APIs, select(), etc -- in short, all the other things we need
+ in communications software, especially when high speeds are used. Oh
+ the irony. And so C-Kermit must be shamelessly butchered -- as it has
+ been so many times before -- to allow us to have the needed features
+ from the POSIX and non-POSIX worlds. See the UNIXWAREPOSIX sections of
+ [484]ckutio.c.
+
+ After the butchery, we wind up with Unixware 2.x having full
+ modem-signal capability, but politically-correct Unixware 7.x lacking
+ the ability to automatically detect a broken connection when carrier
+ drops.
+
+ Meanwhile the Unixware tcsetspeed() function allows any number at all
+ (any long, 0 or positive) as an argument and succeeds if the number is
+ a legal bit rate for the serial device, and fails otherwise. There is
+ no list anywhere of legal speeds. Thus the SET SPEED keyword table
+ ("set speed ?" to see it) is hardwired based on trial and error with
+ all known serial speeds, the maximum being 115200. However, to allow
+ for the possibility that other speeds might be allowed in the future
+ (or with different port drivers), the SET SPEED command for UnixWare 7
+ only allows you to specify any number at all; a warning is printed if
+ the number is not in the list, but the number is accepted anyway; the
+ command succeeds if tcsetspeed() accepts the number, and fails
+ otherwise.
+
+ In C-Kermit 8.0 testing, it was noticed that the POSIX method for
+ hanging up the phone by dropping DTR (set speed 0, pause, restore
+ speed) did not actually drop DTR. The APIs do not return any error
+ indication, but nothing happens. I changed tthang() to skip the special
+ case I had made for Unixware and instead follow the normal path: if
+ TIOCSDTR is defined use that, otherwise blah blah... It turns out
+ TIOCSDTR *is* defined, and it works.
+
+ So in Unixware (at least in 2.1.3) we can read modem signals, hangup by
+ toggling DTR, and so on, BUT... But once the remote hangs up and
+ Carrier drops, the API for reading modem signals ceases to function;
+ although the device is still open, the TIOCMGET ioctl always raises
+ errno 6 = ENXIO, "No such device or address".
+
+ Old business:
+
+ Using C-Kermit 6.0 on the UnixWare 1.1 Application Server, one user
+ reported a system panic when the following script program is executed:
+
+ set line /dev/tty4
+ set speed 9600
+ output \13
+ connect
+
+ The panic does not happen if a PAUSE is inserted:
+
+ set line /dev/tty4
+ set speed 9600
+ pause 1
+ output \13
+ connect
+
+ This is using a Stallion EasyIO card installed as board 0 on IRQ 12 on
+ a Gateway 386 with the Stallion-supplied driver. The problem was
+ reported to Novell and Stallion and (reportedly) is now fixed.
+
+3.11. C-KERMIT AND APOLLO SR10
+
+ [ [485]Top ] [ [486]Contents ] [ [487]Section Contents ] [ [488]Next ]
+ [ [489]Previous ]
+
+ Reportedly, version 5A(190), when built under Apollo SR10 using "make
+ sr10-bsd", compiles, links, and executes OK, but leaves the terminal
+ unusable after it exits -- the "cs7" or "cs8" (character size)
+ parameter has become cs5. The terminal must be reset from another
+ terminal. Cause and cure unknown. Suggested workaround: Wrap Kermit in
+ a shell script something like:
+
+ kermit @*
+ stty sane
+
+3.12. C-KERMIT AND TANDY XENIX 3.0
+
+ [ [490]Top ] [ [491]Contents ] [ [492]Section Contents ] [ [493]Next ]
+ [ [494]Previous ]
+
+ C-Kermit 7.0 was too big to be built on Tandy Xenix, even in a minimum
+ configuration; version 6.0 is the last one that fits.
+
+ Reportedly, in C-Kermit 6.0, if you type lots of Ctrl-C's during
+ execution of the initialization file, ghost Kermit processes will be
+ created, and will compete for the keyboard. They can only be removed
+ via "kill -9" from another terminal, or by rebooting. Diagnosis --
+ something strange happening with the SIGINT handler while the process
+ is reading the directory (it seems to occur during the SET PROMPT
+ [\v(dir)] ... sequence). Cure: unknown. Workaround: don't interrupt
+ C-Kermit while it is executing its init file on the Tandy 16/6000.
+
+3.13. C-KERMIT AND OSF/1 (DIGITAL UNIX) (TRU64 UNIX)
+
+ [ [495]Top ] [ [496]Contents ] [ [497]Section Contents ] [ [498]Next ]
+ [ [499]Previous ]
+
+ While putting together and testing C-Kermit 8.0, it was discovered that
+ binaries built for one version of Tru64 Unix (e.g. 4.0G) might exhibit
+ very strange behavior if run on a different version of Tru64 Unix (e.g.
+ 5.1A). The typical symptom was that a section of the initialization
+ file would be skipped, notably locating the dialing and/or network
+ directory as well as finding and executing the customization file,
+ ~/.mykermrc. This problem also is reported to occur on Tru64 Unix 5.0
+ (Rev 732) even when running a C-Kermit binary that was built there.
+ However, the Tru64 5.1A binary works correctly on 5.0. Go figure.
+
+ When making Telnet connections to a Digital Unix or Tru64 system, and
+ your Telnet client forwards your user name, the Telnet server evidently
+ stuffs the username into login's standard input, and you see:
+
+ login: ivan
+ Password:
+
+ This is clearly going to play havoc with scripts that look for
+ "login:". Workaround (when Kermit is your Telnet client): SET LOGIN
+ USER to nothing, to prevent Kermit from sending your user ID.
+
+ Before you can use a serial port on a new Digital Unix system, you must
+ run uucpsetup to enable or configure the port. Evidently the /dev/tty00
+ and 01 devices that appear in the configuration are not usable;
+ uucpsetup turns them into /dev/ttyd00 and 01, which are. Note that
+ uucpsetup and other uucp-family programs are quite primitive -- they
+ only know about speeds up to 9600 bps and their selection of modems
+ dates from the early 1980s. None of this affects Kermit, though -- with
+ C-Kermit, you can use speeds up to 115200 bps (at least in DU4.0 and
+ later) and modern modems with hardware flow control and all the rest.
+
+ Reportedly, if a modem is set for &S0 (assert DSR at all times), the
+ system resets or drops DTR every 30 seconds; reportedly DEC says to set
+ &S1.
+
+ Digital Unix 3.2 evidently wants to believe your terminal is one line
+ longer than you say it is, e.g. when a "more" or "man" command is
+ given. This is has nothing to do with C-Kermit, but tends to annoy
+ those who use Kermit or other terminal emulators to access Digital Unix
+ systems. Workaround: tell Unix to "stty rows 23" (or whatever).
+
+ Reportedly, there is some bizarre behavior when trying to use a version
+ of C-Kermit built on one Digital Unix 4.0 system on another one,
+ possibly due to differing OS or library revision levels; for example,
+ the inability to connect to certain TCP/IP hosts. Solution: rebuild
+ C-Kermit from source code on the system where you will be using it.
+
+ Digital Unix tgetstr() causes a segmentation fault. C-Kermit 7.0 added
+ #ifdefs to avoid calling this routine in Digital Unix. As a result, the
+ SCREEN commands always send ANSI escape sequences -- even though curses
+ knows your actual terminal type.
+
+ Reportedly the Tru64 Unix 4.0E 1091 Telnet server does not tolerate
+ streaming transfers into itself, at least not when the sending Kermit
+ is on the same local network. Solution: tell one Kermit or the other
+ (or both) to "set streaming off". This might or might be the case with
+ earlier and/or later Tru64, Digital Unix, and OSF/1 releases.
+
+3.14. C-KERMIT AND SGI IRIX
+
+ [ [500]Top ] [ [501]Contents ] [ [502]Section Contents ] [ [503]Next ]
+ [ [504]Previous ]
+
+ See also:
+ * The [505]comp.sys.sgi.misc and [506]comp.sys.sgi.admin newsgroups.
+ [507]The SGI website
+ * The SGI FAQ:
+ + [508]http://www-viz.tamu.edu/~sgi-faq/
+ + [509]ftp://viz.tamu.edu/pub/sgi/faq/
+
+ About IRIX version numbers: "uname -a" tells the "two-digit" version
+ number, such as "5.3" or "6.5". The three-digit form can be seen with
+ "uname -R". (this information is unavailable at the simple API level).
+ Supposedly all three-digit versions within the same two-digit version
+ (e.g. 6.5.2, 6.5.3) are binary compatible; i.e. a binary built on any
+ one of them should run on all others. The "m" suffix denotes just
+ patches; the "f" suffix indicates that features were added.
+
+ An IRIX binary built on lower MIPS model (Instruction Set Architecture,
+ ISA) can run on higher models, but not vice versa:
+
+ MIPS1 R3000 and below
+ MIPS2 R4000
+ MIPS3 R4x00
+ MIPS4 R5000 and above
+
+ Furthermore, there are different Application Binary Interfaces (ABIs):
+
+ COFF 32 bits, IRIX 5.3, 5.2, 5.1, 4.x and below
+ o32 ELF 32 bits, IRIX 5.3, 6.0 - 6.5
+ N32 ELF 32 bits, IRIX 6.2 - 6.5
+ N64 ELF 64 bits, IRIX 6.2 - 6.5
+
+ Thus a prebuilt IRIX binary works on a particular machine only if (a)
+ the machine's IRIX version (to one decimal place) is equal to or
+ greater than the version under which the binary was built; (b) the
+ machine's MIPS level is greater or equal to that of the binary; and (c)
+ the machine supports the ABI of the binary. If all three conditions are
+ not satisfied, of course, you can build a binary yourself from source
+ code since, unlike some other Unix vendors, SGI does supply a C
+ compiler and libraries.
+
+ SGI did not supply an API for hardware flow control prior to IRIX 5.2.
+ C-Kermit 6.1 and higher for IRIX 5.2 and higher supports hardware flow
+ control in the normal way, via "set flow rts/cts".
+
+ For hardware flow control on earlier IRIX and/or C-Kermit versions, use
+ the ttyf* (modem control AND hardware flow control) devices and not the
+ ttyd* (direct) or ttym* (modem control but no hardware flow control)
+ ones, and obtain the proper "hardware handshaking" cable from SGI,
+ which is incompatible with the ones for the Macintosh and NeXT even
+ though they look the same ("man serial" for further info) and tell
+ Kermit to "set flow keep" and "set modem flow rts/cts".
+
+ Serial speeds higher than 38400 are available in IRIX 6.2 and later, on
+ O-class machines (e.g. Origin, Octane) only, and are supported by
+ C-Kermit 7.0 and later. Commands such as "set speed 115200" may be
+ given on other models (e.g. Iris, Indy, Indigo) but will fail because
+ the OS reports an invalid speed for the device.
+
+ Experimentation with both IRIX 5.3 and 6.2 shows that when logged in to
+ IRIX via Telnet, that remote-mode C-Kermit can't send files if the
+ packet length is greater than 4096; the Telnet server evidently has
+ this restriction (or bug), since there is no problem sending long
+ packets on serial or rlogin connections. However, it can receive files
+ with no problem if the packet length is greater than 4096. As a
+ workaround, the FAST macro for IRIX includes "set send packet-length
+ 4000". IRIX 6.5.1 does not have this problem, so evidently it was fixed
+ some time after IRIX 6.2. Tests show file-transfer speeds are better
+ (not worse) with 8K packets than with 4K packets from IRIX 6.5.1.
+
+ Reportedly some Indys have bad serial port hardware. IRIX 5.2, for
+ example, needs patch 151 to work around this; or upgrade to a later
+ release. Similarly, IRIX 5.2 has several problems with serial i/o, flow
+ control, etc. Again, patch or upgrade.
+
+ Reportedly on machines with IRIX 4.0, Kermit cannot be suspended by
+ typing the suspend ("swtch") character if it was started from csh, even
+ though other programs can be suspended this way, and even though the Z
+ and SUSPEND commands still work correctly. This is evidently because
+ IRIX's csh does not deliver the SIGTSTP signal to Kermit. The reason
+ other programs can be suspended in the same environment is probably
+ that they do not trap SIGTSTP themselves, so the shell is doing the
+ suspending rather than the application.
+
+ Also see notes about IRIX 3.x in the [510]C-Kermit for Unix
+ Installation Instructions.
+
+ If you have problems making TCP/IP connections in versions of IRIX
+ built with GCC 2.95.2, see the bugs section of:
+
+ [511]http://freeware.sgi.com/Installable/gcc-2.95.2.html.
+
+ Reportedly, if you allow gcc to compile C-Kermit on Irix you should be
+ aware that there might be problems with some of the network code. The
+ specifics are at
+ [512]http://freeware.sgi.com/Installable/gcc-2.95.2.html; scroll down
+ to the "known bugs" section at the end of the document.
+
+3.15. C-KERMIT AND THE BEBOX
+
+ [ [513]Top ] [ [514]Contents ] [ [515]Section Contents ] [ [516]Next ]
+ [ [517]Previous ]
+
+ See also: The [518]comp.sys.be newsgroup.
+
+ The BeBox has been discontinued and BeOS repositioned for PC platforms.
+ The POSIX parts of BeOS are not finished, nor is the sockets library,
+ therefore a fully functional version of C-Kermit is not possible. In
+ version 6.0 of C-Kermit, written for BeOS DR7, it was possible to:
+
+ * set line /dev/serial2 (and probably the other serial ports)
+ * set speed 115200 (and at least some of the lower baud rates)
+ * connect
+ * set modem type hayes (and likely others, too)
+ * dial phone-number
+ * set send packet-length 2048 (other lengths for both send and
+ receive)
+ * set receive packet length 2048
+ * set file type binary (text mode works, too) (with remote kermit
+ session in server mode)
+ * put bedrop.jpg
+ * get bedrop.jpg
+ * get bedrop.jpg bedrop.jpg2
+ * finish, bye
+
+ The following do not work:
+ * kermit does not detect modem hangup
+ * !/RUN/PUSH [commandline command]
+ * Running kermit in remote mode
+ * Using other protocols (x/y/zmodem)
+ * TCP networking interface (Be's TCP/IP API has a ways to go, still)
+
+ C-Kermit does not work on BeOS DR8 because of changes in the underlying
+ APIs. Unfortunately not enough changes were made to allow the regular
+ POSIX-based C-Kermit to work either. Note: the lack of a fork() service
+ requires the select()-based CONNECT module, but there is no select().
+ There is a select() in DR8, but it doesn't work.
+
+ C-Kermit 7.0 was built for BeOS 4.5 and works in remote mode. It does
+ not include networking support since the APIs are still not there. It
+ is not known if dialing out works, but probably not. Be experts are
+ welcome to lend a hand.
+
+3.16. C-KERMIT AND DG/UX
+
+ [ [519]Top ] [ [520]Contents ] [ [521]Section Contents ] [ [522]Next ]
+ [ [523]Previous ]
+
+ Somebody downloaded the C-Kermit 6.0 binary built under DG/UX 5.40 and
+ ran it under DG/UX 5.4R3.10 -- it worked OK except that file dates for
+ incoming files were all written as 1 Jan 1970. Cause and cure unknown.
+ Workaround: SET ATTRIBUTE DATE OFF. Better: Use a version of C-Kermit
+ built under and for DG/UX 5.4R3.10.
+
+3.17. C-KERMIT AND SEQUENT DYNIX
+
+ [ [524]Top ] [ [525]Contents ] [ [526]Section Contents ] [ [527]Next ]
+ [ [528]Previous ]
+
+ Reportedly, when coming into a Sequent Unix (DYNIX) system through an
+ X.25 connection, Kermit doesn't work right because the Sequent's
+ FIONREAD ioctl returns incorrect data. To work around, use the
+ 1-character-at-a-time version of myread() in ckutio.c (i.e. undefine
+ MYREAD in ckutio.c and rebuild the program). This is unsatisfying
+ because two versions of the program would be needed -- one for use over
+ X.25, and the other for serial and TCP/IP connections.
+
+3.18. C-KERMIT AND FREEBSD, OPENBSD, and NETBSD
+
+ [ [529]Top ] [ [530]Contents ] [ [531]Section Contents ] [ [532]Next ]
+ [ [533]Previous ]
+
+ Some NebBSD users have reported difficulty escaping back from CONNECT
+ mode, usually when running NetBSD on non-PC hardware. Probably a
+ keyboard issue.
+
+ NetBSD users have also reported that C-Kermit doesn't pop back to the
+ prompt if the modem drops carrier. This needs to be checked out & fixed
+ if possible.
+
+ (All the above seems to work properly in C-Kermit 7.0 and later.)
+
+3.19. C-KERMIT AND MAC OS X
+
+ [ [534]Top ] [ [535]Contents ] [ [536]Section Contents ] [ [537]Next ]
+ [ [538]Previous ]
+
+ Mac OS X is Apple's 4.4BSD Unix variety, closely related to FreeBSD,
+ but different. "uname -a" is singularly uninformative, as in Linux,
+ giving only the Darwin kernel version number. The way to find out the
+ actual Mac OS X version is with
+
+ /usr/bin/sw_vers -productName
+ /usr/bin/sw_vers -productVersion
+
+ or:
+
+ fgrep -A 1 'ProductVersion'
+ /System/Library/CoreServices/SystemVersion.plist
+
+ Here are some points to be aware of:
+
+ * A big gotcha for Kermit users is that Mac OS X does not support
+ serial ports and, as far as I can tell, doesn't support its
+ built-in modem either, for anything other than making Internet
+ connections. Macintoshes capable of running Mac OS X, such as the
+ G5 and later, come without serial ports and without any APIs to
+ support them, and also without the UUCP family of programs
+ (including cu), nor any standard for serial-port lockfile
+ directory.
+ * Early versions of Mac OS X came without Curses, Termlib, or
+ Terminfo libraries. Later versions seem to have ncurses (it would
+ seem that Mac OS X 10.3.9 was the first mature and complete version
+ of Mac OS X). Kermit uses curses for its file-transfer display. See
+ elsewhere about curses-vs-ncurses confusion.
+ * In the HFS+ file system, filenames are case-folded. Thus "makefile"
+ and "Makefile" are the same file. So, for example, suppose you are
+ sending two distinct files, Foo and FOO, from (say) Linux to Mac OS
+ X. This will produce a file collision that will be handled
+ according to Mac OS X C-Kermit's FILE COLLISION setting, which by
+ default is BACKUP, so the Mac will wind up with files called FOO
+ and Foo.~1~.
+ * HSF+ files that are composed of a resource fork and a data fork...
+ I doubt that C-Kermit does anything useful with them. There is no
+ code in C-Kermit for traditional two-forked Macintosh files, but it
+ could be added if there is any demand (code for this existed in
+ [539]Mac Kermit, the old pre-Mac-OS-X Macintosh version of
+ C-Kermit).
+ * In case you want to transfer a traditional Macintosh text file (or
+ data fork of a file that is plain text), you can use these C-Kermit
+ commands:
+
+set file eol cr
+set file character-set apple-quickdraw
+send /text filename
+
+ * File or pathnames that include spaces must be enclosed in either
+ doublequotes or curly braces in C-Kermit commands.
+ * Mac OS X can use a third-party package manager called "fink".
+ Various fink packages for C-Kermit are floating around that are not
+ standard releases. For example, there's a C-Kermit 8.0.201 package
+ in which C-Kermit was modified (at least) to use a UUCP lockfile
+ directory that does not exist on vanilla Mac OS X systems.
+
+Mac OS X and Serial Ports
+
+ Apple is in the forefront of companies that believe serial ports have
+ no use in the modern world and so has simply eliminated all traces of
+ them from its machines and OS. But of course serial ports are still
+ needed to connect not only to external modems, but also to the control
+ ports of hubs, routers, terminal servers, PBXs, and similar devices,
+ not to mention barcode readers, POS systems and components, speaking
+ devices, hand calculators such as the HP48, automated factory-floor
+ equipment, and scientific, medical, and lab equipment (to name a few).
+ Among workers in these areas, there is a need to add serial ports back
+ onto this platform, which is being filled by third-party products such
+ as the [540]Keyspan High Speed USB Serial Adapter USA-19HS, which has a
+ DB-9 male connector. To use the Keyspan device, you must install the
+ accompanying device drivers, which winds up giving you serial ports
+ with names like /dev/cu.USA19H3b1P1.1, /dev/cu.KeySerial1,
+ /dev/tty.KeySerial1.
+
+ C-Kermit 9.0 works "out of the box" with third-party serial ports on
+ Mac OS X, because it is built by default ("make macosx") without the
+ "UUCP lockfile" feature. If you have C-Kermit 9.0 on a personal
+ Macintosh, you can skip the next section.
+
+Mac OS X Serial Ports with C-Kermit 8.0 and earlier
+
+ In earlier versions of C-Kermit, you'll need to either build a special
+ -DNOUUCP version, or deal with the UUCP port contention sytem in
+ [541]all its glory (this is usually an exercise in futility because any
+ other applications on your Mac that use the serial port will not
+ necessarily follow the same conventions):
+
+ 1. su (or sudo -s)
+ chgrp xxxx /var/spool/lock
+ chmod g+w /var/spool/lock
+ chgrp xxxx /dev/cu.*
+ (where xxxx is the name of the group for users to whom serial-port
+ access is to be granted). Use "admin" or other existing group, or
+ create a new group if desired. NB:
+
+ In the absence of official guidance from Apple or anyone else, we
+ choose /var/spool/lock as the lockfile directory because this
+ directory (a) already exists on vanilla Mac OS X installations, and
+ (b) it is the directory used for serial-port lockfiles on many other
+ platforms.
+ 2. Put all users who need access to the serial port in the same group.
+ 3. Make sure the serial device files that are to be used by C-Kermit
+ have group read-write permission and (if you care) lack world
+ read-write permission, e.g.:
+
+ chmod g+rw,o-rw /dev/cu.*
+
+ If you do the above, then there's no need to become root to use Kermit,
+ or to make Kermit suid or sgid. Just do this:
+
+chmod 775 wermit
+mv wermit /usr/local/kermit
+
+ (or whatever spot is more appropriate, e.g. /usr/bin/). For greater
+ detail about installation, [542]CLICK HERE.
+
+ Alternatively, to build a pre-9.0 version of C-Kermit without UUCP
+ lockfile support, set the NOUUCP flag; e.g. (for Mac OS 10.4):
+
+ make macosx10.4 KFLAGS=-DNOUUCP
+
+ This circumvents the SET PORT failure "?Access to lockfile directory
+ denied". But it also sacrifices Kermit's ability to ensure that only
+ one copy of Kermit can have the device open at a time, since Mac OS X
+ is the same as all other varieties of Unix in that exclusive access to
+ serial ports is not enforced in any way. But if it's for your own
+ desktop machine that nobody else uses, a -DNOUUCP version might be
+ adequate and preferable to the alternatives.
+
+ To build C-Kermit 9.0 with UUCP support, do:
+
+ make macosx KFLAGS=-UNOUUCP
+
+ (note: "-U", not "-D).
+
+RS-232 versus RS-422
+
+ Meanwhile, back when Macs had serial ports, they were not RS-232 (the
+ standard for connecting computers with nearby modems) but rather RS-422
+ or -423 (a standard for connecting serial devices over longer
+ distances). Macintosh serial ports do not support modems well because
+ they do not have enough wires (or more properly in the case RS-422/423,
+ wire pairs) to convey a useful subset of modem signals.
+
+ Keyspan also sells a [543]USB Twin Serial Adapter that gives you two
+ Mini-Din8 RS-422 ports, that are no better (or worse) for communicating
+ with modems or serial devices than a real Mac Din-8 port was. In
+ essence, you get Data In, Data Out, and two modem signals. It looks to
+ me as if the signals chosen by Keyspan are RTS and CTS. This gives you
+ hardware flow control, but at the expense of Carrier Detect. Thus to
+ use C-Kermit with a Keyspan USB serial port, you must tell C-Kermit to:
+
+set modem type none ; (don't expect a modem)
+set carrier-watch off ; (ignore carrier signal)
+set port /dev/cu.USA19H3b1P1.1 ; (open the port)
+set flow rts/cts ; (this is the default)
+set speed 57600 ; (or whatever)
+connect ; (or DIAL or whatever)
+
+ Use Ctrl-\C in the normal manner to escape back to the C-Kermit>
+ prompt. Kermit can't pop back to its prompt automatically when Carrier
+ drops because there is no Carrier signal in the physical interface.
+
+ Here's a typical sequence for connecting to Cisco devices (using a
+ mixture of command-line options and interactive commands at the
+ prompt):
+
+$ ckermit -l /dev/cu.USA19H3b1P1.1 -b 9600
+C-Kermit> set carrier-watch off
+C-Kermit> connect
+
+ Instructions for the built-in modem (if any) remain to be written due
+ to lack of knowledge. If you can contribute instructions, hints, or
+ tips, please [544]send them in.
+
+3.20. C-KERMIT AND COHERENT
+
+ [ [545]Top ] [ [546]Contents ] [ [547]Section Contents ] [
+ [548]Previous ]
+
+ Also see:
+
+ [549]http://www.uni-giessen.de/faq/archiv/coherent-faq.general/msg000
+ 00.html
+
+ Mark Williams COHERENT was perhaps the first commercial Unix-based
+ operating system for PCs, first appearing about 1983 or -84 for the
+ PC/XT (?), and popular until about 1993, when Linux took over.
+ C-Kermit, as of version 8.0, is still current for COHERENT 386 4.2
+ (i.e. only for i386 and above). Curses is included, but lots of other
+ features are omitted due to lack of the appropriate OS features, APIs,
+ libraries, hardware, or just space: e.g. TCP/IP, floating-point
+ arithmetic, learned scripts. Earlier versions of COHERENT ran on 8086
+ and 80286, but these are to small to build or run C-Kermit, but
+ G-Kermit should be OK (as might be ancient versions of C-Kermit).
+
+ You can actually build a version with floating point support -- just
+ take -DNOFLOAT out of CFLAGS and add -lm to LIBS; NOFLOAT is the
+ default because COHERENT tends to run on old PCs that don't have
+ floating-point hardware. You can also add "-f" to CFLAGS to have it
+ link in the floating-point emulation library. Also I'm not sure why
+ -DNOLEARN is included, since it depends on select(), which COHERENT
+ has.
+
+4. GENERAL UNIX-SPECIFIC HINTS, LIMITATIONS, AND BUGS
+
+ [ [550]Top ] [ [551]Contents ] [ [552]Next ] [ [553]Previous ]
+
+4.1. Modem Signals
+
+ There seems to be an escalating demand for the ability to control "dumb
+ serial devices" (such as "smartcard readers", barcode readers, etc) by
+ explicitly manipulating modem signals, particularly RTS. This might
+ have been easy to do in DOS, where there is no operating system
+ standing between the application and the serial device, but it is
+ problematic in Unix, where modem signals are controlled by the serial
+ device driver. If the driver does not provide an API for doing this,
+ then the application can't do it. If it does provide an API, expect it
+ to be totally different on each Unix platform, since there is no
+ standard for this.
+
+4.2. NFS Troubles
+
+ Beginning with C-Kermit 6.0, the default C-Kermit prompt includes your
+ current (working) directory; for example:
+
+ [/usr/olga] C-Kermit>
+
+ (In C-Kermit 7.0 the square braces were replaced by round parentheses
+ to avoid conflicts with ISO 646 national character sets.)
+
+ If that directory is on an NFS-mounted disk, and NFS stops working or
+ the disk becomes unavailable, C-Kermit will hang waiting for NFS and/or
+ the disk to come back. Whether you can interrupt C-Kermit when it is
+ hung this way depends on the specific OS. Kermit has called the
+ operating systems's getcwd() function, and is waiting for it to return.
+ Some versions of Unix (e.g. HP-UX 9.x) allow this function to be
+ interrupted with SIGINT (Ctrl-C), others (such as HP-UX 8.x) do not. To
+ avoid this effect, you can always use SET PROMPT to change your prompt
+ to something that does not involve calling getcwd(), but if NFS is not
+ responding, C-Kermit will still hang any time you give a command that
+ refers to an NFS-mounted directory. Also note that in some cases, the
+ uninterruptibility of NFS-dependent system or library calls is
+ considered a bug, and sometimes there are patches. For HP-UX, for
+ example:
+
+ replaced by:
+ HP-UX 10.20 libc PHCO_8764 PHCO_14891/PHCO_16723
+ HP-UX 10.10 libc PHCO_8763 PHCO_14254/PHCO_16722
+ HP-UX 9.x libc PHCO_7747 S700 PHCO_13095
+ HP-UX 9.x libc PHCO_6779 S800 PHCO_11162
+
+4.3. C-Kermit as Login Shell
+
+ You might have reason to make C-Kermit the login shell for a specific
+ user, by entering the pathname of Kermit (possibly with command-line
+ switches, such as -x to put it in server mode) into the shell field of
+ the /etc/passwd file. This works pretty well. In some cases, for
+ "ultimate security", you might want to use a version built with
+ -DNOPUSH (see the [554]Configurations Options document for this, but
+ even if you don't, then PUSHing or shelling out from C-Kermit just
+ brings up a new copy of C-Kermit (but warning: this does not prevent
+ the user from explicitly running a shell; e.g. "run /bin/sh"; use
+ NOPUSH to prevent this).
+
+4.4. C-Kermit versus screen and splitvt
+
+ C-Kermit file transfers will probably not work if attempted through the
+ "splitvt" or GNU "screen" programs because the screen optimization (or
+ at least, line wrapping, control-character absorption) done by this
+ package interferes with Kermit's packets.
+
+ The same can apply to any other environment in which the user's session
+ is captured, monitored, recorded, or manipulated. Examples include the
+ 'script' program (for making a typescript of a session), the
+ Computronics PEEK package and pksh (at least versions of it prior to
+ 1.9K), and so on.
+
+ You might try the following -- what we call "doomsday Kermit" --
+ settings to push packets through even the densest and most obstructive
+ connections, such as "screen" and "splitvt" (and certain kinds of 3270
+ protocol emulators): Give these commands to BOTH Kermit programs:
+
+ SET FLOW NONE
+ SET CONTROL PREFIX ALL
+ SET RECEIVE PACKET-LENGTH 70
+ SET RECEIVE START 62
+ SET SEND START 62
+ SET SEND PAUSE 100
+ SET BLOCK B
+
+ If it works, it will be slow.
+
+4.5. C-Kermit versus DOS Emulators
+
+ On Unix workstations equipped with DOS emulators like SoftPC, watch out
+ for what these emulators do to the serial port drivers. After using a
+ DOS emulator, particularly if you use it to run DOS communications
+ software, you might have to reconfigure the serial ports for use by
+ Unix.
+
+4.6. C-Kermit versus Job Control
+
+ Interruption by Ctrl-Z makes Unix C-Kermit try to suspend itself with
+ kill(0,SIGTSTP), but only on platforms that support job control, as
+ determined by whether the symbol SIGTSTP is defined (or on POSIX or
+ SVR4 systems, if syconf(_SC_JOB_CONTROL) or _POSIX_JOB_CONTROL in
+ addition to SIGTSTP). However, if Kermit is running under a login shell
+ (such as the original Bourne shell) that does not support job control,
+ the user's session hangs and must be logged out from another terminal,
+ or hung up on. There is no way Kermit can defend itself against this.
+ If you use a non-job control shell on a computer that supports job
+ control, give a command like "stty susp undef" to fix it so the suspend
+ signal is not attached to any particular key, or give the command SET
+ SUSPEND OFF to C-Kermit, or build C-Kermit with -DNOJC.
+
+4.7. Dates and Times
+
+ Unix time conversion functions typically apply locale rules to return
+ local time in terms of any seasonal time zone change in effect for the
+ given date. The diffdate function assumes that the same timezone rules
+ are in effect for both dates, but a date with timezone information will
+ be converted to the local time zone in effect at the given time, e.g.,
+ a GMT specification will produce either a Standard Time or Daylight
+ Savings Time, depending on which applies at the given time. An example
+ using the 2001 seasonal change from EDT (-0400) to EST (-0500):
+
+ C-Kermit> DATE 20011028 05:01:02 GMT ; EDT
+ 20011028 01:01:02
+ C-Kermit> DATE 20011028 06:01:02 GMT ; EST
+ 20011028 01:01:02
+ C-Kermit>
+
+ but the implicit change in timezone offset is not recognized:
+
+ C-Kermit> echo \fdiffdate(20011028 05:01:02 GMT, 20011028 06:01:02 GMT)
+ +0:00
+ C-Kermit>
+
+ Date/time arithmetic, offsets, delta times, and timezone support are
+ new to C-Kermit 8.0, and might be expected to evolve and improve in
+ subsequent releases.
+
+ On some platforms, files downloaded with HTTP receive the current
+ timestamp, rather than the HTTP "Last Modified" time (this can be fixed
+ by including utime.h, e.g. in SunOS and Tru64...).
+
+4.8. Pseudoterminals
+
+ The SSH and PTY commands work by assigning a pseudoterminal and reading
+ and writing from it. Performance varies according to the specific
+ platform ranging from very fast to very flow.
+
+ SSH and PTY commands can fail if (a) all pseudoterminals are in use; or
+ (b) you do not have read/write access to the pseudoterminal that was
+ assigned. An example of (b) was reported with the Zipslack Slackware
+ Linux distribution, in which the pseudoterminals were created with
+ crw-r--r-- permission, instead of crw-rw-rw-.
+
+4.9. Miscellaneous
+
+ * Reportedly, the Unix C-Kermit server, under some conditions, on
+ certain particular systems, fails to log out its login session upon
+ receipt of a BYE command. Before relying on the BYE command
+ working, test it a few times to make sure it works on your system:
+ there might be system configuration or security mechanisms to
+ prevent an inferior process (like Kermit) from killing a superior
+ one (like the login shell).
+ * On AT&T 7300 (3B1) machines, you might have to "stty nl1" before
+ starting C-Kermit. Do this if characters are lost during
+ communications operations.
+ * Under the bash shell (versions prior to 1.07 from CWRU), "pushing"
+ to an inferior shell and then exiting back to Kermit leaves Kermit
+ in the background such that it must be explicitly fg'd. This is
+ reportedly fixed in version 1.07 of bash (and definitely in modern
+ bash versions).
+
+5. INITIALIZATION AND COMMAND FILES
+
+ [ [555]Top ] [ [556]Contents ] [ [557]Next ] [ [558]Previous ]
+
+ C-Kermit's initialization file for Unix is .kermrc (lowercase, starts
+ with period) in your home directory, unless Kermit was built with the
+ system-wide initialization-file option (see the [559]C-Kermit for Unix
+ Installation Instructions).
+
+ C-Kermit identifies your home directory based on the environment
+ variable, HOME. Most Unix systems set this variable automatically when
+ you log in. If C-Kermit can't find your initialization file, check your
+ HOME variable:
+
+ echo $HOME (at the Unix prompt)
+
+ or:
+
+ echo \$(HOME) (at the C-Kermit prompt)
+
+ If HOME is not defined, or is defined incorrectly, add the appropriate
+ definition to your Unix .profile or .login file, depending on your
+ shell:
+
+ setenv HOME full-pathname-of-your-home-directory (C-Shell, .login file)
+
+ or:
+
+ HOME=full-pathname-of-your-home-directory (sh, ksh, .profile file)
+ export HOME
+
+ NOTE: Various other operations depend on the correct definition of
+ HOME. These include the "tilde-expansion" feature, which allows you to
+ refer to your home directory as "~" in filenames used in C-Kermit
+ commands, e.g.:
+
+ send ~/.kermrc
+
+ as well as the \v(home) variable.
+
+ Prior to version 5A(190), C-Kermit would look for its initialization
+ file in the current directory if it was not found in the home
+ directory. This feature was removed from 5A(190) because it was a
+ security risk. Some people, however, liked this behavior and had
+ .kermrc files in all their directories that would set up things
+ appropriately for the files therein. If you want this behavior, you can
+ accomplish it in various ways, for example:
+
+ * Create a shell alias, for example:
+ alias kd="kermit -Y ./.kermrc"
+
+ * Create a .kermrc file in your home directory, whose contents are:
+ take ./.kermrc
+
+ Suppose you need to pass a password from the Unix command line to a
+ C-Kermit script program, in such a way that it does not show up in "ps"
+ or "w" listings. Here is a method (not guaranteed to be 100% secure,
+ but definitely more secure than the more obvious methods):
+
+ echo mypassword | kermit myscript
+
+ The "myscript" file contains all the commands that need to be executed
+ during the Kermit session, up to and including EXIT, and also includes
+ an ASK or ASKQ command to read the password from standard input, which
+ has been piped in from the Unix 'echo' command, but it must not include
+ a CONNECT command. Only "kermit myscript" shows up in the ps listing.
+
+6. COMMUNICATION SPEED SELECTION
+
+ [ [560]Top ] [ [561]Contents ] [ [562]Next ] [ [563]Previous ]
+
+ Version-7 based Unix implementations, including 4.3 BSD and earlier and
+ Unix systems based upon BSD, use a 4-bit field to record a serial
+ device's terminal speed. This leaves room for 16 speeds, of which the
+ first 14 are normally:
+
+ 0, 50, 75, 110, 134.5, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ and 9600
+
+ The remaining two are usually called EXTA and EXTB, and are defined by
+ the particular Unix implementation. C-Kermit determines which speeds
+ are available on your system based on whether symbols for them are
+ defined in your terminal device header files. EXTA is generally assumed
+ to be 19200 and EXTB 38400, but these assumptions might be wrong, or
+ they might not apply to a particular device that does not support these
+ speeds. Presumably, if you try to set a speed that is not legal on a
+ particular device, the driver will return an error, but this can not be
+ guaranteed.
+
+ On these systems, it is usually not possible to select a speed of 14400
+ bps for use with V.32bis modems. In that case, use 19200 or 38400 bps,
+ configure your modem to lock its interface speed and to use RTS/CTS
+ flow control, and tell C-Kermit to SET FLOW RTS/CTS and SET DIAL
+ SPEED-MATCHING OFF.
+
+ The situation is similar, but different, in System V. SVID Third
+ Edition lists the same speeds, 0 through 38400.
+
+ Some versions of Unix, and/or terminal device drivers that come with
+ certain third-party add-in high-speed serial communication interfaces,
+ use the low "baud rates" to stand for higher ones. For example, SET
+ SPEED 50 gets you 57600 bps; SET SPEED 75 gets you 76800; SET SPEED 110
+ gets 115200.
+
+ SCO ODT 3.0 is an example where a "baud-rate-table patch" can be
+ applied that can rotate the tty driver baud rate table such that
+ 600=57600 and 1800=115k baud. Similarly for Digiboard
+ multiport/portservers, which have a "fastbaud" setting that does this.
+ Linux has a "setserial" command that can do it, etc.
+
+ More modern Unixes support POSIX-based speed setting, in which the
+ selection of speeds is not limited by a 4-bit field. C-Kermit 6.1
+ incorporates a new mechanism for finding out (at compile time) which
+ serial speeds are supported by the operating system that does not
+ involve editing of source code by hand; on systems like Solaris 5.1,
+ IRIX 6.2, and SCO OSR5.0.4, "set speed ?" will list speeds up to 460800
+ or 921600. In C-Kermit 7.0 and later:
+
+ 1. If a symbol for a particular speed (say B230400 for 230400 bps)
+ appears in whatever header file defines acceptable serial speeds
+ (e.g. <termbits.h> or <sys/termios.h> or <sys/ttydev.h>, etc), the
+ corresponding speed will appear in C-Kermit's "set speed ?" list.
+ 2. The fact that a given speed is listed in the header files and
+ appears in C-Kermit's list does not mean the driver will accept it.
+ For example, a computer might have some standard serial ports plus
+ some add-on ones with different drivers that accept a different
+ repertoire of speeds.
+ 3. The fact that a given speed is accepted by the driver does not
+ guarantee the underlying hardware can accept it.
+
+ When Kermit is given a "set speed" command for a particular device, the
+ underlying system service is called to set the speed; its return code
+ is checked and the SET SPEED command fails if the return code indicates
+ failure. Regardless of the system service return status, the device's
+ speed is then read back and if it does not match the speed that was
+ requested, an error message is printed and the command fails.
+
+ Even when the command succeeds, this does not guarantee successful
+ operation at a particular speed, especially a high one. That depends on
+ electricity, information theory, etc. How long is the cable, what is
+ its capacitance, how well is it shielded, etc, not to mention that
+ every connection has two ends and its success depends on both of them.
+ (With the obvious caveats about internal modems, is the cable really
+ connected, interrupt conflicts, etc etc etc).
+
+ Note, in particular, that there is a certain threshold above which
+ modems can not "autobaud" -- i.e. detect the serial interface speed
+ when you type AT (or whatever else the modem's recognition sequence
+ might be). Such modems need to be engaged at a lower speed (say 2400 or
+ 9600 or even 115200 -- any speed below their autobaud threshold) and
+ then must be given a modem-specific command (which can be found in the
+ modem manual) to change their interface speed to the desired higher
+ speed, and then the software must also be told to change to the new,
+ higher speed.
+
+ For additional information, read [564]Section 9.5 of the Installation
+ Instructions, plus any platform-specific notes in [565]Section 3 above.
+
+7. COMMUNICATIONS AND DIALING
+
+ [ [566]Top ] [ [567]Contents ] [ [568]Next ] [ [569]Previous ]
+
+7.1. Serial Ports and Modems
+
+ If you SET LINE to a serial port modem-control device that has nothing
+ plugged in to it, or has a modem connected that is powered off, and you
+ have not given a prior SET MODEM TYPE or SET CARRIER-WATCH OFF command,
+ the SET LINE command is likely to hang. In most cases, you can Ctrl-C
+ out. If not, you'll have to kill C-Kermit from another terminal.
+
+ Similarly, if you give a SET MODEM TYPE HAYES (or USR, or any other
+ modem type besides DIRECT, NONE, or UNKNOWN) and then SET LINE to an
+ empty port, the subsequent close (implicit or explicit) is liable to
+ hang or even crash (through no fault of Kermit's -- the hanging or
+ crashing is inside a system call such as cfsetospeed() or close()).
+
+ The SET CARRIER-WATCH command works as advertised only if the
+ underlying operating system and device drivers support this feature; in
+ particular only if a read() operation returns immediately with an error
+ code if the carrier signal goes away or, failing that, if C-Kermit can
+ obtain the modem signals from the device driver (you can tell by giving
+ a "set line" command to a serial device, and then a "show
+ communications" command -- if modem signals are not listed, C-Kermit
+ won't be able to detect carrier loss, the WAIT command will not work,
+ etc). Of course, the device itself (e.g. modem) must be configured
+ appropriately and the cables convey the carrier and other needed
+ signals, etc.
+
+ If you dial out from Unix system, but then notice a lot of weird
+ character strings being stuck into your session at random times
+ (especially if they look like +++ATQ0H0 or login banners or prompts),
+ that means that getty is also trying to control the same device. You'll
+ need to dial out on a device that is not waiting for a login, or else
+ disable getty on the device.
+
+ As of version 7.0, C-Kermit makes explicit checks for the Carrier
+ Detect signal, and so catches hung-up connections much better than 6.0
+ and earlier. However, it still can not be guaranteed to catch every
+ ever CD on-to-off transition. For example, when the HP-UX version of
+ C-Kermit is in CONNECT mode on a dialed connection and CARRIER-WATCH ON
+ or AUTO, and you turn off the modem, HP-UX is stuck in a read() that
+ never returns. (C-Kermit does not pop back to its prompt automatically,
+ but you can still escape back.)
+
+ If, on the other hand, you log out from the remote system, and it hangs
+ up, and CD drops on the local modem, C-Kermit detects this and pops
+ back to the prompt as it should. (Evidently there can be a difference
+ between CD and DSR turning off at the same time, versus CD turning off
+ while DSR stays on; experimentation with &S0/&S1/&S2 on your modem
+ might produce the desired results).
+
+ When Unix C-Kermit exits, it closes (and must close) the communications
+ device. If you were dialed out, this will most likely hang up the
+ connection. If you want to get out of Kermit and still use Kermit's
+ communication device, you have several choices:
+
+ 1. Shell out from Kermit or suspend Kermit, and refer to the device
+ literally (as in "term -blah -blah < /dev/cua > /dev/cua").
+ 2. Shell out from Kermit and use the device's file descriptor which
+ Kermit makes available to you in the \v(ttyfd) variable.
+ 3. Use C-Kermit's REDIRECT command.
+ 4. Use C-Kermit new EXEC /REDIRECT command.
+
+ If you are having trouble dialing:
+
+ 1. Make sure the dialout line is configured correctly. More about this
+ below.
+ 2. Make sure all necessary patches are installed for your operating
+ system.
+ 3. If you can't dial on a "bidirectional" line, then configure it for
+ outbound-only (remove the getty) and try again. (The mechanisms --
+ if any -- for grabbing bidirectional lines for dialout vary wildly
+ among Unix implementations and releases, and C-Kermit -- which runs
+ on well over 300 different Unix variations -- makes no effort to
+ keep up with them; the recommended method for coping with this
+ situation is to wrap C-Kermit in a shell script that takes the
+ appropriate actions.)
+ 4. Make sure C-Kermit's SET DIAL and SET MODEM parameters agree with
+ the modem you are actually using -- pay particular attention to SET
+ DIAL SPEED-MATCHING.
+ 5. If MODEM HANGUP-METHOD is set to RS232-SIGNAL, change it to
+ MODEM-COMMAND. Or vice-versa.
+ 6. Try SET DIAL HANGUP OFF before the DIAL command. Also, SET DIAL
+ DISPLAY ON to watch what's happening. See [570]Section 8 of the
+ [571]Installation Instructions.
+ 7. Read pages 50-67 of [572]Using C-Kermit.
+ 8. As a last resort, don't use the DIAL command at all; SET CARRIER
+ OFF and CONNECT to the modem and dial interactively, or write a
+ script program to dial the modem.
+
+ Make sure your dialout line is correctly configured for dialing out (as
+ opposed to login). The method for doing this is different for each kind
+ of Unix system. Consult your system documentation for configuring lines
+ for dialing out (for example, Sun SparcStation IPC users should read
+ the section "Setting up Modem Software" in the Desktop SPARC Sun System
+ & Network Manager's Guide; HP-9000 workstation users should consult the
+ manual Configuring HP-UX for Peripherals, etc).
+
+ Symptom: DIAL works, but a subsequent CONNECT command does not.
+ Diagnosis: the modem is not asserting Carrier Detect (CD) after the
+ connection is made, or the cable does not convey the CD signal. Cure:
+ Reconfigure the modem, replace the cable. Workaround: SET CARRIER OFF
+ (at least in System-V based Unix versions).
+
+ For Berkeley-Unix-based systems (4.3BSD and earlier), Kermit includes
+ code to use LPASS8 mode when parity is none, which is supposed to allow
+ 8-bit data and Xon/Xoff flow control at the same time. However, as of
+ edit 174, this code is entirely disabled because it is unreliable: even
+ though the host operating system might (or might not) support LPASS8
+ mode correctly, the host access protocols (terminal servers, telnet,
+ rlogin, etc) generally have no way of finding out about it and
+ therefore render it ineffective, causing file transfer failures. So as
+ of edit 174, Kermit once again uses rawmode for 8-bit data, and so
+ there is no Xon/Xoff flow control during file transfer or terminal
+ emulation in the Berkeley-based versions (4.3 and earlier, not 4.4).
+
+ Also on Berkeley-based systems (4.3 and earlier), there is apparently
+ no way to configure a dialout line for proper carrier handling, i.e.
+ ignore carrier during dialing, require carrier thereafter, get a fatal
+ error on any attempt to read from the device after carrier drops (this
+ is handled nicely in System V by manipulation of the CLOCAL flag). The
+ symptom is that carrier loss does not make C-Kermit pop back to the
+ prompt automatically. This is evident on the NeXT, for example, but not
+ on SunOS, which supports the CLOCAL flag. This is not a Kermit problem,
+ but a limitation of the underlying operating system. For example, the
+ cu program on the NeXT doesn't notice carrier loss either, whereas cu
+ on the Sun does.
+
+ On certain AT&T Unix systems equipped with AT&T modems, DIAL and HANGUP
+ don't work right. Workarounds: (1) SET DIAL HANGUP OFF before
+ attempting to dial; (2) If HANGUP doesn't work, SET LINE, and then SET
+ LINE <device> to totally close and reopen the device. If all else
+ fails, SET CARRIER OFF.
+
+ C-Kermit does not contain any particular support for AT&T DataKit
+ devices. You can use Kermit software to dial in to a DataKit line, but
+ C-Kermit does not contain the specialized code required to dial out
+ from a DataKit line. If the Unix system is connected to DataKit via
+ serial ports, dialout should work normally (e.g. set line /dev/ttym1,
+ set speed 19200, connect, and then see the DESTINATION: prompt, from
+ which you can connect to another computer on the DataKit network or to
+ an outgoing modem pool, etc). But if the Unix system is connected to
+ the DataKit network through the special DataKit interface board, then
+ SET LINE to a DataKit pseudodevice (such as /dev/dk031t) will not work
+ (you must use the DataKit "dk" or "dkcu" program instead). In C-Kermit
+ 7.0 and later, you can make Kermit connections "though" dk or dkcu
+ using "set line /pty".
+
+ In some BSD-based Unix C-Kermit versions, SET LINE to a port that has
+ nothing plugged in to it with SET CARRIER ON will hang the program (as
+ it should), but it can't be interrupted with Ctrl-C. The interrupt trap
+ is correctly armed, but apparently the Unix open() call cannot be
+ interrupted in this case. When SET CARRIER is OFF or AUTO, the SET LINE
+ will eventually return, but then the program hangs (uninterruptibly)
+ when the EXIT or QUIT command (or, presumably, another SET LINE
+ command) is given. The latter is probably because of the attempt to
+ hang up the modem. (In edit 169, a timeout alarm was placed around this
+ operation.)
+
+ With SET DIAL HANGUP OFF in effect, the DIAL command might work only
+ once, but not again on the same device. In that case, give a CLOSE
+ command to close the device, and then another SET LINE command to
+ re-open the same device. Or rebuild your version of Kermit with the
+ -DCLSOPN compile-time switch.
+
+ The DIAL command says "To cancel: Type your interrupt character
+ (normally Ctrl-C)." This is just one example of where program messages
+ and documentation assume your interrupt character is Ctrl-C. But it
+ might be something else. In most (but not necessarily all) cases, the
+ character referred to is the one that generates the SIGINT signal. If
+ Ctrl-C doesn't act as an interrupt character for you, type the Unix
+ command "stty -a" or "stty all" or "stty everything" to see what your
+ interrupt character is. (Kermit could be made to find out what the
+ interrupt character is, but this would require a lot of
+ platform-dependent coding and #ifdefs, and a new routine and interface
+ between the platform-dependent and platform-independent parts of the
+ program.)
+
+ In general, the hangup operation on a serial communication device is
+ prone to failure. C-Kermit tries to support many, many different kinds
+ of computers, and there seems to be no portable method for hanging up a
+ modem connection (i.e. turning off the RS-232 DTR signal and then
+ turning it back on again). If HANGUP, DIAL, and/or Ctrl-\H do not work
+ for you, and you are a programmer, look at the tthang() function in
+ ckutio.c and see if you can add code to make it work correctly for your
+ system, and send the code to the address above. (NOTE: This problem has
+ been largely sidestepped as of edit 188, in which Kermit first attempts
+ to hang up the modem by "escaping back" via +++ and then giving the
+ modem's hangup command, e.g. ATH0, when DIAL MODEM-HANGUP is ON, which
+ is the default setting.)
+
+ Even when Kermit's modem-control software is configured correctly for
+ your computer, it can only work right if your modem is also configured
+ to assert the CD signal when it is connected to the remote modem and to
+ hang up the connection when your computer drops the DTR signal. So
+ before deciding Kermit doesn't work with your modem, check your modem
+ configuration AND the cable (if any) connecting your modem to the
+ computer -- it should be a straight-through [573]modem cable conducting
+ the signals FG, SG, TD, RD, RTS, CTS, DSR, DTR, CD, and RI.
+
+ Many Unix systems keep aliases for dialout devices; for example,
+ /dev/acu might be an alias for /dev/tty00. But most of these Unix
+ systems also use UUCP lockfile conventions that do not take this
+ aliasing into account, so if one user assigns (e.g.) /dev/acu, then
+ another user can still assign the same device by referring to its other
+ name. This is not a Kermit problem -- Kermit must follow the lockfile
+ conventions used by the vendor-supplied software (cu, tip, uucp).
+
+ The SET FLOW-CONTROL KEEP option should be given *before* any
+ communication (dialing, terminal emulation, file transfer,
+ INPUT/OUTPUT/TRANSMIT, etc) is attempted, if you want C-Kermit to use
+ all of the device's preexisting flow-control related settings. The
+ default flow-control setting is XON/XOFF, and it will take effect when
+ the first communication-related command is given, and a subsequent SET
+ FLOW KEEP command will not necessarily know how to restore *all* of the
+ device's original flow-control settings.
+
+7.2. Network Connections
+
+ C-Kermit tries to use the 8th bit for data when parity is NONE, and
+ this generally works on real Unix terminal (tty) devices, but it often
+ does not work when the Unix system is accessed over a network via
+ telnet or rlogin protocols, including (in many cases) through terminal
+ servers. For example, an Encore computer with Annex terminal servers
+ only gives a 7-bit path if the rlogin protocol is selected in the
+ terminal server but it gives the full 8 bits if the proprietary RDP
+ protocol is used.
+
+ If file transfer does not work through a host to which you have
+ rlogin'd, use "rlogin -8" rather than "rlogin". If that doesn't work,
+ tell both Kermit programs to "set parity space".
+
+ The Encore TELNET server does not allow long bursts of input. When you
+ have a TELNET connection to an Encore, tell C-Kermit on the Encore to
+ SET RECEIVE PACKET-LENGTH 200 or thereabouts.
+
+8. HARDWARE FLOW CONTROL
+
+ [ [574]Top ] [ [575]Contents ] [ [576]Next ] [ [577]Previous ]
+
+ SET FLOW RTS/CTS is available in Unix C-Kermit only when the underlying
+ operating system provides an Application Program Interface (API) for
+ turning this feature on and off under program control, which turns out
+ to be a rather rare feature among Unix systems. To see if your Unix
+ C-Kermit version supports hardware flow control, type "set flow ?" at
+ the C-Kermit prompt, and look for "rts/cts" among the options. Other
+ common situations include:
+
+ 1. The API is available, so "set flow rts/cts" appears as a valid
+ C-Kermit command, but it doesn't do anything because the device
+ driver (part of the operating system) was never coded to do
+ hardware flow control. This is common among System V R4
+ implementations (details below).
+ 2. The API is not available, so "set flow rts/cts" does NOT appear as
+ a valid C-Kermit command, but you can still get RTS/CTS flow
+ control by selecting a specially named device in your SET LINE
+ command. Examples:
+ + NeXTSTEP: /dev/cufa instead of /dev/cua, /dev/cufb instead of
+ /dev/cub (68040 only; "man zs" for further info).
+ + IRIX: /dev/ttyf2 instead of /dev/ttyd2 or /dev/ttym2 ("man 7
+ serial").
+ 3. The API is available, doesn't work, but a workaround as in (2) can
+ be used.
+ 4. The API is available, but Kermit doesn't know about it. In these
+ cases, you can usually use an stty command to enable RTS/CTS on the
+ device, e.g. "stty crtscts" or "stty ctsflow", "stty rtsflow",
+ before starting Kermit, and then tell Kermit to SET FLOW KEEP.
+ 5. No API and no special device drivers. Hardware flow control is
+ completely unavailable.
+
+ System V R4 based Unixes are supposed to supply a <termiox.h> file,
+ which gives Kermit the necessary interface to command the terminal
+ driver to enable/disable hardware flow control. Unfortunately, but
+ predictably, many implementations of SVR4 whimsically place this file
+ in /usr/include/sys rather than /usr/include (where SVID clearly
+ specifies it should be; see SVID, Third Edition, V1, termiox(BA_DEV).
+ Thus if you build C-Kermit with any of the makefile entries that
+ contain -DTERMIOX or -DSTERMIOX (the latter to select <sys/termiox.h>),
+ C-Kermit will have "set flow rts/cts" and possibly other hardware
+ flow-control related commands. BUT... That does not necessarily mean
+ that they will work. In some cases, the underlying functions are simply
+ not coded into the operating system.
+
+ WARNING: When hardware flow control is available, and you enable in
+ Kermit on a device that is not receiving the CTS signal, Kermit can
+ hang waiting for CTS to come up. This is most easily seen when the
+ local serial port has nothing plugged in to it, or is connected to an
+ external modem that is powered off.
+
+9. TERMINAL CONNECTION AND KEY MAPPING
+
+ [ [578]Top ] [ [579]Contents ] [ [580]Next ] [ [581]Previous ]
+
+ C-Kermit is not a terminal emulator. Refer to page 147 of [582]Using
+ C-Kermit, 2nd Edition: "Most versions of C-Kermit -- Unix, VMS, AOS/VS,
+ VOS, etc -- provide terminal connection without emulation. These
+ versions act as a 'semitransparent pipe' between the remote computer
+ and your terminal, terminal emulator, console driver, or window, which
+ in turn emulates (or is) a specific kind of terminal." The environment
+ in which you run C-Kermit is up to you.
+
+ If you are an X Windows user, you should be aware of an alternative to
+ xterm that supports VT220 emulation, from Thomas E. Dickey:
+
+ [583]http://dickey.his.com/xterm/xterm.html
+
+ Unix C-Kermit's SET KEY command currently can not be used with keys
+ that generate "wide" scan codes or multibyte sequences, such as
+ workstation function or arrow keys, because Unix C-Kermit does not have
+ direct access to the keyboard.
+
+ However, many Unix workstations and/or console drivers provide their
+ own key mapping feature. With xterm, for example, you can use 'xmodmap'
+ ("man xmodmap" for details); here is an xterm mapping to map the Sun
+ keyboard to DEC VT200 values for use with VT-terminal oriented
+ applications like VMS EVE:
+
+ keycode 101=KP_0
+ keycode 119=KP_1
+ keycode 120=KP_2
+ keycode 121=KP_3
+ keycode 98=KP_4
+ keycode 99=KP_5
+ keycode 100=KP_6
+ keycode 75=KP_7
+ keycode 76=KP_8
+ keycode 77=KP_9
+ keycode 52=KP_F1
+ keycode 53=KP_F2
+ keycode 54=KP_F3
+ keycode 57=KP_Decimal
+ keycode 28=Left
+ keycode 29=Right
+ keycode 30=KP_Separator
+ keycode 105=KP_F4
+ keycode 78=KP_Subtract
+ keycode 8=Left
+ keycode 10=Right
+ keycode 32=Up
+ keycode 33=Down
+ keycode 97=KP_Enter
+
+ Users of Linux consoles can use loadkeys ("man dumpkeys loadkeys
+ keytables" for details. The format used by loadkeys is compatible with
+ that used by Xmodmap, although it is not definitely certain that the
+ keycodes are compatible for different keyboard types (e.g. Sun vs HP vs
+ PC, etc).
+
+10. FILE TRANSFER
+
+ [ [584]Top ] [ [585]Contents ] [ [586]Next ] [ [587]Previous ]
+
+ On most platforms, C-Kermit can not handle files longer than 2^31 or
+ 2^32 bytes long, because it uses the traditional file i/o APIs that use
+ 32-bit words to represent the file size. To accommodate longer files,
+ we would have to switch to a new and different API. Unfortunately, each
+ platform has a different one, a nightmare to handle in portable code.
+ The C-Kermit file code was written in the days long before files longer
+ than 2GB were supported or even contemplated in the operating systems
+ where C-Kermit ran.
+
+ If uploads (or downloads) fail immediately, give the CAUTIOUS command
+ to Kermit and try again. If they still fail, then try SET PREFIXING
+ ALL. If they still fail, try SET PARITY SPACE. If they still fail, try
+ ROBUST.
+
+ If reception (particularly of large files and/or binary files) begins
+ successfully but then fail consistently after a certain amount of bytes
+ have been sent, check:
+
+ * Your ulimit ("ulimit -a")
+ * The amount of available space on the target disk ("df ." or "df -k
+ .")
+ * Your personal disk quota (platform- and site-dependent)
+ * The maximum file size on the receiver's file system (e.g. 2GB in
+ old versions the Linux VFS file system, and/or in applications that
+ have not been recoded to use new "large file" APIs).
+ * If it's an NFS-mounted disk (if so, try uploading to a local disk)
+ * Is there an "idle limit" on the receiving end?
+
+ If none of these seem to explain it, then the problem is not size
+ related, but reflects some clash between the file contents and the
+ characteristics of the connection, in which case follow the
+ instructions in the first paragraph of this section.
+
+ Suppose two copies of Kermit are receiving files into the same
+ directory, and the files have the same name, e.g. "foo.bar". Whichever
+ one starts first opens an output file called "foo.bar". The second one
+ sees there is already a foo.bar file, and so renames the existing
+ foo.bar to foo.bar.~1~ (or whatever). When the first file has been
+ received completely, Kermit goes to change its modification time and
+ permissions to those given by the file sender in the Attribute packet.
+ But in Unix, the APIs for doing this take a filename, not a file
+ descriptor. Since the first Kermit's file has been renamed, and the
+ second Kermit is using the original name, the first Kermit changes the
+ modtime and permissions of the second Kermit's file, not its own.
+ Although there might be a way to work around this in the code, e.g.
+ using inode numbers to keep track of which file is which, this would be
+ tricky and most likely not very portable. It's better to set up your
+ application to prevent such things from happening, which is easy enough
+ using the script language, filename templates, etc.
+
+ Suppose you start C-Kermit with a command-line argument to send or
+ receive a file (e.g. "kermit -r") and then type Ctrl-\c immediately
+ afterwards to escape back and initiate the other end of the transfer,
+ BUT your local Kermit's escape character is not Ctrl-\. In this case,
+ the local Kermit passes the Ctrl-\ to the remote system, and if this is
+ Unix, Ctrl-\ is likely to be its SIGQUIT character, which causes the
+ current program to halt and dump core. Well, just about the first thing
+ C-Kermit does when it starts is to disable the SIGQUIT signal. However,
+ it is still possible for SIGQUIT to cause Kermit to quit and dump core
+ if it is delivered while Kermit is being loaded or started, before the
+ signal can be disabled. There's nothing Kermit itself can do about
+ this, but you can prevent it from happening by disabling SIGQUIT in
+ your Unix session. The command is usually something like:
+
+ stty quit undef
+
+ Unix C-Kermit does not reject incoming files on the basis of size.
+ There appears to be no good (reliable, portable) way to determine in
+ advance how much disk space is available, either on the device, or
+ (when quotas or other limits are involved) to the user.
+
+ Unix C-Kermit discards all carriage returns from incoming files when in
+ text mode.
+
+ If C-Kermit has problems creating files in writable directories when it
+ is installed setuid or setgid on BSD-based versions of Unix such as
+ NeXTSTEP 3.0, it probably needs to be rebuilt with the -DSW_ACC_ID
+ compilation switch.
+
+ If you SET FILE DISPLAY FULLSCREEN, and C-Kermit complains "Sorry,
+ terminal type not supported", it means that the terminal library
+ (termcap or termlib) that C-Kermit was built with does not know about a
+ terminal whose name is the current value of your TERM environment
+ variable. If this happens, but you want to have the fullscreen file
+ transfer display, EXIT from C-Kermit and set a Unix terminal type from
+ among the supported values that is also supported by your terminal
+ emulator, or else have an entry for your terminal type added to the
+ system termcap and/or terminfo database.
+
+ If you attempt to suspend C-Kermit during local-mode file transfer and
+ then continue it in the background (via bg), it will block for "tty
+ output" if you are using the FULLSCREEN file transfer display. This is
+ apparently a problem with curses. Moving a local-mode file transfer
+ back and forth between foreground and background works correctly,
+ however, with the SERIAL, CRT, BRIEF, or NONE file transfer displays.
+
+ If C-Kermit's command parser no longer echoes, or otherwise acts
+ strangely, after returning from a file transfer with the fullscreen
+ (curses) display, and the curses library for your version of Unix
+ includes the newterm() function, then try rebuilding your version of
+ C-Kermit with -DCK_NEWTERM. Similarly if it echoes doubly, which might
+ even happen during a subsequent CONNECT session. If rebuilding with
+ -DCK_NEWTERM doesn't fix it, then there is something very strange about
+ your system's curses library, and you should probably not use it. Tell
+ C-Kermit to SET FILE DISPLAY CRT, BRIEF, or anything else other than
+ FULLSCREEN, and/or rebuild without -DCK_CURSES, and without linking
+ with (termlib and) curses. Note: This problem seemed to have escalated
+ in C-Kermit 7.0, and -DCK_NEWTERM had to be added to many builds that
+ previously worked without it: Linux, AIX 4.1, DG/UX, etc. In the Linux
+ case, it is obviously because of changes in the (n)curses library; the
+ cause in the other cases is not known.
+
+ C-Kermit creates backup-file names (such as "oofa.txt.~1~") based on
+ its knowledge of the maximum filename length on the platform where it
+ is running, which is learned at compile time, based on MAXNAMLEN or
+ equivalent symbols from the system header files. But suppose C-Kermit
+ is receiving files on a Unix platform that supports long filenames, but
+ the incoming files are being stored on an NFS-mounted file system that
+ supports only short names. NFS maps the external system to the local
+ APIs, so C-Kermit has no way of knowing that long names will be
+ truncated. Or that C-Kermit is running on a version of Unix that
+ supports both long-name and short-name file systems simultaneously
+ (such as HP-UX 7.00). This can cause unexpected behavior when creating
+ backup files, or worse. For example, you are sending a group of files
+ whose names are differentiated only by characters past the point at
+ which they would be truncated, each file will overwrite the previous
+ one upon arrival.
+
+11. EXTERNAL FILE TRANSFER PROTOCOLS
+
+ [ [588]Top ] [ [589]Contents ] [ [590]Next ] [ [591]Previous ]
+
+ SECTION CONTENTS
+
+ 11.1. [592]C-Kermit as an External Protocol
+ 11.2. [593]Invoking External Protocols from C-Kermit
+
+ Unix C-Kermit can be used in conjunction with other communications
+ software in various ways. C-Kermit can be invoked from another
+ communications program as an "external protocol", and C-Kermit can also
+ invoke other communication software to perform external protocols.
+
+ This sort of operation makes sense only when you are dialing out from
+ your Unix system (or making a network connection from it). If the Unix
+ system is the one you have dialed in to, you don't need any of these
+ tricks. Just run the desired software on your Unix system instead of
+ Kermit. When dialing out from a Unix system, the difficulty is getting
+ two programs to share the same communication device in spite of the
+ Unix UUCP lockfile mechanism, which would normally prevent any sharing,
+ and preventing the external protocol from closing (and therefore
+ hanging up) the device when it exits back to the program that invoked
+ it.
+
+11.1. C-KERMIT AS AN EXTERNAL PROTOCOL
+
+ [ [594]Top ] [ [595]Contents ] [ [596]Section Contents ] [ [597]Next ]
+
+ (This section deleted; see [598]Using C-Kermit, 2nd Ed, Chapter 14.)
+
+ "pcomm" is a general-purpose terminal program that provides file
+ transfer capabilities itself (X- and YMODEM variations) and the ability
+ to call on external programs to do file transfers (ZMODEM and Kermit,
+ for example). You can tell pcomm the command to send or receive a file
+ with an external protocol:
+ Send Receive
+ ZMODEM sz filename rz
+ Kermit kermit -s filename kermit -r
+
+ pcomm runs external programs for file transfer by making stdin and
+ stdout point to the modem port, and then exec-ing "/bin/sh -c xxx"
+ (where xxx is the appropriate command). However, C-Kermit does not
+ treat stdin and stdout as the communication device unless you instruct
+ it:
+
+
+ Send Receive
+ Kermit kermit -l 0 -s filename kermit -l 0 -r
+
+ The "-l 0" option means to use file descriptor 0 for the communication
+ device.
+
+ In general, any program can pass any open file descriptor to C-Kermit
+ for the communication device in the "-l" command-line option. When
+ Kermit is given a number as the argument to the "-l" option, it simply
+ uses it as a file descriptor, and it does not attempt to close it upon
+ exit.
+
+ Here's another example, for Seyon (a Linux communication program).
+ First try the technique above. If that works, fine; otherwise... If
+ Seyon does not give you a way to access and pass along the file
+ descriptor, but it starts up the Kermit program with its standard i/o
+ redirected to its (Seyon's) communications file descriptor, you can
+ also experiment with the following method, which worked here in brief
+ tests on SunOS. Instead of having Seyon use "kermit -r" or "kermit -s
+ filename" as its Kermit protocol commands, use something like this
+ (examples assume C-Kermit 6.0):
+
+ For serial connections:
+
+ kermit -YqQl 0 -r <-- to receive
+ kermit -YqQl 0 -s filename(s) <-- to send one or more files
+
+ For Telnet connections:
+
+ kermit -YqQF 0 -r <-- to receive
+ kermit -YqQF 0 -s filename(s) <-- to send one or more files
+
+ Command line options:
+
+ Y - skip executing the init file
+ Q - use fast file transfer settings (default in 8.0)
+ l 0 - transfer files using file descriptor 0 for a serial connection
+ F 0 - transfer files using file descriptor 0 for a Telnet connection
+ q - quiet - no messages
+ r - receive
+ s - send
+
+11.2. INVOKING EXTERNAL PROTOCOLS FROM C-KERMIT
+
+ [ [599]Top ] [ [600]Contents ] [ [601]Section Contents ] [
+ [602]Previous ]
+
+ (This section is obsolete, but not totally useless. See Chapter 14
+ of [603]Using C-Kermit, 2nd Edition).
+
+ After you have opened a communication link with C-Kermit's SET LINE
+ (SET PORT) or SET HOST (TELNET) command, C-Kermit makes its file
+ descriptor available to you in the \v(ttyfd) variable so you can pass
+ it along to other programs that you RUN from C-Kermit. Here, for
+ example, C-Kermit runs itself as an external protocol:
+
+ C-Kermit>set modem type hayes
+ C-Kermit>set line /dev/acu
+ C-Kermit>set speed 2400
+ C-Kermit>dial 7654321
+ Call complete.
+ C-Kermit>echo \v(ttyfd)
+ 3
+ C-Kermit>run kermit -l \v(ttyfd)
+
+ Other programs that accept open file descriptors on the command line
+ can be started in the same way.
+
+ You can also use your shell's i/o redirection facilities to assign
+ C-Kermit's open file descriptor (ttyfd) to stdin or stdout. For
+ example, old versions of the Unix ZMODEM programs, sz and rz, when
+ invoked as external protocols, expect to find the communication device
+ assigned to stdin and stdout with no option for specifying any other
+ file descriptor on the sz or rz command line. However, you can still
+ invoke sz and rz as exterior protocols from C-Kermit if your current
+ shell ($SHELL variable) is ksh (the Korn shell) or bash (the
+ Bourne-Again shell), which allows assignment of arbitrary file
+ descriptors to stdin and stdout:
+
+ C-Kermit> run rz <&\v(ttyfd) >&\v(ttyfd)
+
+ or:
+
+ C-Kermit> run sz oofa.zip <&\v(ttyfd) >&\v(ttyfd)
+
+ In version 5A(190) and later, you can use C-Kermit's REDIRECT command,
+ if it is available in your version of C-Kermit, to accomplish the same
+ thing without going through the shell:
+
+ C-Kermit> redirect rz
+
+ or:
+
+ C-Kermit> redirect sz oofa.zip
+
+ A complete set of rz,sz,rb,sb,rx,sx macros for Unix C-Kermit is defined
+ in the file ckurzsz.ini. It automatically chooses the best redirection
+ method (but is redundant since C-Kermit 6.0, which now has built-in
+ support for external protocols via its SET PROTOCOL command).
+
+ Note that external protocols can be used on C-Kermit SET LINE or SET
+ HOST connections only if they operate through standard input and
+ standard output. If they open their own connections, Kermit can't
+ redirect them over its own connection.
+
+12. SECURITY
+
+ [ [604]Top ] [ [605]Contents ] [ [606]Next ] [ [607]Previous ]
+
+ As of version 7.0, C-Kermit supports a wide range of security options
+ for authentication and encryption: Kerberos 4, Kerberos 5 / GSSAPI,
+ SSL/TLS, and SRP. See the separate [608]security document for details.
+
+13. MISCELLANEOUS USER REPORTS
+
+ [ [609]Top ] [ [610]Contents ] [ [611]Next ] [ [612]Previous ]
+
+Date: Thu, 12 Mar 92 1:59:25 MEZ
+From: Walter Mecky <walter@rent-a-guru.de>
+Subject: Help.Unix.sw
+To: svr4@pcsbst.pcs.com, source@usl.com
+
+PRODUCT: Unix
+RELEASE: Dell SVR4 V2.1 (is USL V3.0)
+MACHINE: AT-386
+PATHNAME: /usr/lib/libc.so.1
+ /usr/ccs/lib/libc.a
+ABSTRACT: Function ttyname() does not close its file descriptor
+DESCRIPTION:
+ ttyname(3C) opens /dev but never closes it. So if it is called
+ often enough the open(2) in ttyname() fails. Because the broken
+ ttyname() is in the shared lib too all programs using it can
+ fail if they call it often enough. One important program is
+ uucico which calls ttyname for every file it transfers.
+
+
+ Here is a little test program if your system has the bug:
+
+#include <stdlib.h>
+#include <stdio.h>
+main() {
+ int i = 0;
+ while (ttyname(0) != NULL)
+ i++;
+ perror("ttyname");
+ printf("i=%d\n", i);
+}
+
+ If this program runs longer than some seconds you don't have the bug.
+
+ WORKAROUND: None FIX: Very easy if you have source code.
+
+ Another user reports some more explicit symptoms and recoveries:
+
+> What happens is when invoking ckermit we get one of the following
+> error messages:
+> You must set line
+> Not a tty
+> No more processes.
+> One of the following three actions clears the problem:
+> shutdown -y -g0 -i6
+> kill -9 the ttymon with the highest PID
+> Invoke sysadm and disable then enable the line you want to use.
+> Turning off respawn of sac -t 300 and going to getty's and uugetty's
+> does not help.
+>
+> Also C-Kermit reports "?timed out closing /dev/ttyxx".
+> If this happens all is well.
+
+------------------------------
+
+ (Note: the following problem also occurs on SGI and probably many other
+ Unix systems):
+
+ From: James Spath <spath@jhunix.hcf.jhu.edu>
+ To: Info-Kermit-Request@cunixf.cc.columbia.edu
+ Date: Wed, 9 Sep 1992 20:20:28 -0400
+ Subject: C-Kermit vs uugetty (or init) on Sperry 5000
+
+ We have successfully compiled the above release on a Unisys/Sperry
+ 5000/95. We used the sys5r3 option, rather than sys5r2 since we have
+ VR3 running on our system. In order to allow dialout access to
+ non-superusers, we had to do "chmod 666 /dev/tty###, where it had been
+ -rw--w--w- (owned by uucp), and to do "chmod +w /usr/spool/locks". We
+ have done text and binary file transfers through local and remote
+ connections.
+
+ The problem concerning uucp ownership and permissions is worse than I
+ thought at first. Apparently init or uugetty changes the file
+ permissions after each session. So I wrote the following C program to
+ open a set of requested tty lines. I run this for any required outgoing
+ line prior to a Kermit session.
+
+ ------ cut here -------
+/* opentty.c -- force allow read on tty lines for modem i/o */
+/* idea from: restrict.c -- System 5 Admin book Thomas/Farrow p. 605 */
+/* /jes jim spath {spath@jhunix.hcj.jhu.edu } */
+/* 08-Sep-92 NO COPYRIGHT. */
+/* this must be suid to open other tty lines */
+
+/* #define DEBUG */
+#define TTY "/dev/tty"
+#define LOK "/usr/spool/locks/LCK..tty"
+#include <stdio.h>
+
+/* allowable lines: */
+#define TOTAL_LINES 3
+static char allowable[TOTAL_LINES][4] = { "200", "201", "300" };
+static int total=TOTAL_LINES;
+int allow;
+
+/* states: */
+#define TTY_UNDEF 0
+#define TTY_LOCK 1
+#define TTY_OKAY 2
+
+main(argc, argv)
+int argc; char *argv[]; {
+ char device[512];
+ char lockdev[512];
+ int i;
+ if (argc == 1) {
+ fprintf(stderr, "usage: open 200 [...]\n");
+ }
+ while (--argc > 0 && (*++argv) != NULL ) {
+#ifdef DEBUG
+ fprintf(stderr, "TRYING: %s%s\n", TTY, *argv);
+#endif
+ sprintf(device, "%s%s", TTY, *argv);
+ sprintf(lockdev, "%s%s", LOK, *argv);
+ allow = TTY_UNDEF; i = 0;
+ while (i <= total) { /* look at all defined lines */
+#ifdef DEBUG
+ fprintf(stderr, "LOCKFILE? %s?\n", lockdev);
+#endif
+ if (access(lockdev, 00) == 0) {
+ allow=TTY_LOCK;
+ break;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "DOES:%s==%s?\n", allowable[i], *argv);
+#endif
+ if (strcmp(allowable[i], *argv) == 0)
+ allow=TTY_OKAY;
+ i++;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "allow=%d\n", allow);
+#endif
+ switch (allow) {
+ case TTY_UNDEF:
+ fprintf (stderr, "open: not allowed on %s\n", *argv);
+ break;
+ case TTY_LOCK:
+ fprintf (stderr, "open: device locked: %s\n", lockdev);
+ break;
+ case TTY_OKAY:
+ /* attempt to change mode on device */
+ if (chmod (device, 00666) < 0)
+ fprintf (stderr, "open: cannot chmod on %s\n", device);
+ break;
+ default:
+ fprintf (stderr, "open: FAULT\n");
+ }
+ }
+ exit (0);
+}
+
+14. THIRD-PARTY DRIVERS
+
+ [ [613]Top ] [ [614]Contents ] [ [615]Next ] [ [616]Previous ]
+
+ Unix versions, especially those for PCs (SCO, Unixware, etc) might be
+ augmented by third-party communication-board drivers from Digiboard,
+ Stallion, etc. These can sometimes complicate matters for Kermit
+ considerably since Kermit has no way of knowing that it is going
+ through a possibly nonstandard driver. Various examples are listed in
+ the earlier sections of this document; search for Stallion, Digiboard,
+ etc. Additionally:
+
+ * The Stallion Technologies EasyConnection serial board driver does
+ not always report the state of DSR as low. From Stallion (October
+ 1997): "Unfortunately, this is a bug in our driver. We have
+ implemented all of the other TIOMC functions, eg DTR, DCD, RTS and
+ CTS, but not DSR. Our driver should report the actual state of DSR
+ on those of our cards that have a DSR signal. That the driver
+ always reports DSR as not asserted (0), is a bug in the driver. The
+ driver should be either reporting the state of DSR correctly on
+ those cards that support DSR or as always asserted (1) on those
+ cards that do not have a DSR signal. This will be fixed in a future
+ version of our drivers; at this time I cannot say when this will
+ be." And later, "As far as I can tell, we don't support the
+ termios/termiox ioctls that relate specifically to DSR and RI; all
+ the rest are supported. This will, as I mentioned earlier, be fixed
+ in the next release of our ATA software."
+ - World Wide Escalation Support, Stallion Technologies, Toowong
+ QLD, [617]support@stallion.oz.au.
+
+ Later (December 1997, from the same source):
+
+ * We have now released a new version of the ATA software, version
+ 5.4.0. This version fixes the problem with the states of the DSR
+ and RI signals and how they were being reported by the driver. This
+ is the problem that you reported in October. The DSR signal is
+ reported correctly on those cards that support the DSR signal, such
+ as the early revision of the EasyIO card and the EasyConnection 8D4
+ panel, and as always asserted on those cards that do not support
+ the DSR signal in the hardware. The new driver is available from
+ our Web site, [618]www.stallion.com, in the /drivers/ata5/UnixWare
+ directory.
+
+ [ [619]Top ] [ [620]Contents ] [ [621]C-Kermit Home ] [ [622]C-Kermit
+ 8.0 Overview ] [ [623]Kermit Home ]
+ __________________________________________________________________
+
+ C-Kermit 8.0 Unix Hints and Tips / [624]The Kermit Project /
+ [625]Columbia University / [626]kermit@columbia.edu
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/
+ 12. http://www.columbia.edu/
+ 13. http://www.columbia.edu/kermit/ckubwr.html
+ 14. http://www.columbia.edu/kermit/ckdaily.html
+ 15. http://www.columbia.edu/kermit/ckdaily.html
+ 16. http://www.columbia.edu/kermit/ckdaily.html
+ 17. http://www.columbia.edu/kermit/ckermit.html
+ 18. http://www.columbia.edu/kermit/ckuins.html
+ 19. http://www.columbia.edu/kermit/ckututor.html
+ 20. http://www.columbia.edu/kermit/ckubwr.html#x1
+ 21. http://www.columbia.edu/kermit/ckubwr.html#x2
+ 22. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 23. http://www.columbia.edu/kermit/ckubwr.html#x4
+ 24. http://www.columbia.edu/kermit/ckubwr.html#x5
+ 25. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 26. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 27. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 28. http://www.columbia.edu/kermit/ckubwr.html#x9
+ 29. http://www.columbia.edu/kermit/ckubwr.html#x10
+ 30. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 31. http://www.columbia.edu/kermit/ckubwr.html#x12
+ 32. http://www.columbia.edu/kermit/ckubwr.html#x13
+ 33. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 34. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 35. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+ 36. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+ 37. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 38. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 39. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 40. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 41. http://www.columbia.edu/kermit/ckubwr.html#top
+ 42. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 43. http://www.columbia.edu/kermit/ckubwr.html#x2
+ 44. http://www.columbia.edu/kermit/ckubwr.html#x1.1
+ 45. http://www.columbia.edu/kermit/ckubwr.html#x1.2
+ 46. http://www.columbia.edu/kermit/ckubwr.html#x1.3
+ 47. http://www.columbia.edu/kermit/ckubwr.html#x1.4
+ 48. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 49. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 50. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 51. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 52. http://www.columbia.edu/kermit/ckcbwr.html
+ 53. mailto:kermit-support@columbia.edu
+ 54. http://www.columbia.edu/kermit/ckubwr.html#top
+ 55. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 56. http://www.columbia.edu/kermit/ckubwr.html#x1.2
+ 57. http://www.columbia.edu/kermit/ck60manual.html
+ 58. http://www.columbia.edu/kermit/ckermit70.html
+ 59. http://www.columbia.edu/kermit/ckermit80.html
+ 60. http://www.columbia.edu/kermit/ckermit90.html
+ 61. http://www.columbia.edu/kermit/ckubwr.html#top
+ 62. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 63. http://www.columbia.edu/kermit/ckubwr.html#x1
+ 64. http://www.columbia.edu/kermit/ckubwr.html#x1.3
+ 65. http://www.columbia.edu/kermit/ckubwr.html#x1.1
+ 66. http://www.columbia.edu/kermit/support.html
+ 67. http://www.columbia.edu/kermit/ckubwr.html#top
+ 68. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 69. http://www.columbia.edu/kermit/ckubwr.html#x1
+ 70. http://www.columbia.edu/kermit/ckubwr.html#x1.4
+ 71. http://www.columbia.edu/kermit/ckubwr.html#x1.2
+ 72. http://www.columbia.edu/kermit/ckubwr.html#top
+ 73. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 74. http://www.columbia.edu/kermit/ckubwr.html#x1
+ 75. http://www.columbia.edu/kermit/ckubwr.html#x1.3
+ 76. http://www.columbia.edu/kermit/ckubwr.html#top
+ 77. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 78. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 79. http://www.columbia.edu/kermit/ckubwr.html#x1
+ 80. http://www.columbia.edu/kermit/ckubwr.html#top
+ 81. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 82. http://www.columbia.edu/kermit/ckubwr.html#x4
+ 83. http://www.columbia.edu/kermit/ckubwr.html#x2
+ 84. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 85. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 86. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 87. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 88. http://www.columbia.edu/kermit/ckubwr.html#x3.4
+ 89. http://www.columbia.edu/kermit/ckubwr.html#x3.5
+ 90. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 91. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 92. http://www.columbia.edu/kermit/ckubwr.html#x3.8
+ 93. http://www.columbia.edu/kermit/ckubwr.html#x3.9
+ 94. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 95. http://www.columbia.edu/kermit/ckubwr.html#x3.11
+ 96. http://www.columbia.edu/kermit/ckubwr.html#x3.12
+ 97. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+ 98. http://www.columbia.edu/kermit/ckubwr.html#x3.14
+ 99. http://www.columbia.edu/kermit/ckubwr.html#x3.15
+ 100. http://www.columbia.edu/kermit/ckubwr.html#x3.16
+ 101. http://www.columbia.edu/kermit/ckubwr.html#x3.17
+ 102. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+ 103. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+ 104. http://www.columbia.edu/kermit/ckubwr.html#x3.20
+ 105. http://www.faqs.org/
+ 106. http://aplawrence.com/Unixart/newtounix.html
+ 107. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 108. mailto:kermit-support@columbia.edu
+ 109. http://www.columbia.edu/kermit/support.html
+ 110. http://www.columbia.edu/kermit/ckubwr.html#top
+ 111. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 112. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 113. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 114. http://www.pcunix.com/
+ 115. http://www.columbia.edu/kermit/ckubwr.html#x3.0.1
+ 116. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 117. http://www.columbia.edu/kermit/ckubwr.html#x3.0.3
+ 118. http://www.columbia.edu/kermit/ckubwr.html#x3.0.4
+ 119. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 120. http://www.columbia.edu/kermit/ckubwr.html#x3.0.6
+ 121. http://www.columbia.edu/kermit/ckubwr.html#top
+ 122. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 123. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 124. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 125. http://www.columbia.edu/kermit/ckubwr.html#top
+ 126. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 127. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 128. http://www.columbia.edu/kermit/ckubwr.html#x3.0.3
+ 129. http://www.columbia.edu/kermit/ckubwr.html#x3.0.1
+ 130. http://www.linmodems.org/
+ 131. http://www.microsoft.com/hwdev/platform/PCdesign/LR/default.asp
+ 132. http://www.columbia.edu/kermit/ckubwr.html#top
+ 133. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 134. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 135. http://www.columbia.edu/kermit/ckubwr.html#x3.0.4
+ 136. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 137. http://www.idir.net/~gromitkc/winmodem.html
+ 138. http://www.digi.com/
+ 139. http://www.columbia.edu/kermit/ckubwr.html#top
+ 140. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 141. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 142. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 143. http://www.columbia.edu/kermit/ckubwr.html#x3.0.3
+ 144. http://www.columbia.edu/kermit/ckubwr.html#top
+ 145. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 146. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 147. http://www.columbia.edu/kermit/ckubwr.html#x3.0.6
+ 148. http://www.columbia.edu/kermit/ckubwr.html#x3.0.4
+ 149. http://www.columbia.edu/kermit/ckubwr.html#top
+ 150. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 151. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 152. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 153. http://www.columbia.edu/kermit/ckubwr.html#top
+ 154. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 155. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 156. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 157. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 158. http://www.columbia.edu/kermit/ckubwr.html#x3.1.1
+ 159. http://www.columbia.edu/kermit/ckubwr.html#x3.1.2
+ 160. http://www.columbia.edu/kermit/ckubwr.html#x3.1.3
+ 161. http://www.columbia.edu/kermit/ckubwr.html#x3.1.4
+ 162. http://www.columbia.edu/kermit/ckubwr.html#x3.1.5
+ 163. http://www.emerson.emory.edu/services/aix-faq/
+ 164. http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.aix.html
+ 165. http://www.cis.ohio-state.edu/hypertext/faq/usenet/aix-faq/top.html
+ 166. http://aixpdslib.seas.ucla.edu/
+ 167. http://www.rootvg.net(AIXhistory)/
+ 168. ftp://rtfm.mit.edu/pub/usenet/news.answers/aix-faq/part1
+ 169. ftp://mirrors.aol.com/pub/rtfm/usenet-by-hierarchy/comp/unix/aix
+ 170. news:comp.unix.aix
+ 171. http://www.columbia.edu/kermit/ckubwr.html#top
+ 172. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 173. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 174. http://www.columbia.edu/kermit/ckubwr.html#x3.1.2
+ 175. http://www.columbia.edu/kermit/ckubwr.html#top
+ 176. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 177. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 178. http://www.columbia.edu/kermit/ckubwr.html#x3.1.3
+ 179. http://www.columbia.edu/kermit/ckubwr.html#x3.1.1
+ 180. http://www.columbia.edu/kermit/security.html#servers
+ 181. http://www.columbia.edu/kermit/ckubwr.html#top
+ 182. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 183. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 184. http://www.columbia.edu/kermit/ckubwr.html#x3.1.4
+ 185. http://www.columbia.edu/kermit/ckubwr.html#x3.1.2
+ 186. http://service.software.ibm.com/rs6000/
+ 187. http://www.columbia.edu/kermit/ckubwr.html#top
+ 188. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 189. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 190. http://www.columbia.edu/kermit/ckubwr.html#x3.1.5
+ 191. http://www.columbia.edu/kermit/ckubwr.html#x3.1.3
+ 192. http://www.columbia.edu/kermit/ckubwr.html#top
+ 193. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 194. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 195. http://www.columbia.edu/kermit/ckubwr.html#x3.1.4
+ 196. http://www.columbia.edu/kermit/ckubwr.html#top
+ 197. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 198. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 199. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 200. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 201. http://www.columbia.edu/kermit/ckubwr.html#x3.2.0
+ 202. http://www.columbia.edu/kermit/ckubwr.html#x3.2.1
+ 203. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 204. http://www.columbia.edu/kermit/ckubwr.html#x3.2.3
+ 205. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 206. http://www.columbia.edu/kermit/ckubwr.html#x3.2.5
+ 207. news:comp.sys.hp.hpux
+ 208. http://www.columbia.edu/kermit/ckubwr.html#top
+ 209. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 210. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 211. http://www.columbia.edu/kermit/ckubwr.html#x3.2.1
+ 212. http://www.columbia.edu/kermit/ckubwr.html#top
+ 213. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 214. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 215. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 216. http://www.columbia.edu/kermit/ckubwr.html#x3.2.0
+ 217. ftp://kermit.columbia.edu/kermit/f/makefile
+ 218. http://www.columbia.edu/kermit/ckubwr.html#top
+ 219. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 220. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 221. http://www.columbia.edu/kermit/ckubwr.html#x3.2.3
+ 222. http://www.columbia.edu/kermit/ckubwr.html#x3.2.1
+ 223. http://www.columbia.edu/kermit/ckubwr.html#top
+ 224. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 225. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 226. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 227. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 228. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.1
+ 229. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.2
+ 230. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.3
+ 231. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.4
+ 232. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.5
+ 233. http://www.columbia.edu/kermit/ckubwr.html#top
+ 234. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 235. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 236. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.2
+ 237. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 238. http://www.columbia.edu/kermit/ckubwr.html#top
+ 239. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 240. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 241. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.3
+ 242. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.1
+ 243. http://www.columbia.edu/kermit/ckubwr.html#top
+ 244. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 245. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 246. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.4
+ 247. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.2
+ 248. http://www.columbia.edu/kermit/ckubwr.html#top
+ 249. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 250. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 251. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.5
+ 252. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.3
+ 253. http://www.columbia.edu/kermit/ckubwr.html#top
+ 254. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 255. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 256. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.4
+ 257. http://www.columbia.edu/kermit/ckubwr.html#top
+ 258. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 259. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 260. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 261. http://www.columbia.edu/kermit/ckubwr.html#top
+ 262. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 263. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 264. http://www.columbia.edu/kermit/ckubwr.html#x3.4
+ 265. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 266. http://www.columbia.edu/kermit/ckubwr.html#x3.3.1
+ 267. http://www.columbia.edu/kermit/ckubwr.html#x3.3.2
+ 268. http://www.columbia.edu/kermit/ckubwr.html#x3.3.3
+ 269. http://www.columbia.edu/kermit/ckubwr.html#x3.3.4
+ 270. http://www.columbia.edu/kermit/ckubwr.html#x3.3.5
+ 271. http://www.columbia.edu/kermit/ckubwr.html#x3.3.6
+ 272. http://en.wikipedia.org/wiki/Avahi_(software)
+ 273. news:comp.os.linux.misc
+ 274. news:comp.os.linux.answers
+ 275. http://www.tldp.org/
+ 276. http://www.tldp.org/FAQ/Linux-FAQ.html
+ 277. http://www.tldp.org/HOWTO/Serial-HOWTO.html
+ 278. http://tldp.org/HOWTO/Modem-HOWTO.html
+ 279. ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO
+ 280. ftp://tsx-11.mit.edu/pub/linux/docs/HOWTO
+ 281. http://www.tldp.org/HOWTO/
+ 282. http://www.tldp.org/hmirrors.html
+ 283. http://www.redhat.com/apps/support/
+ 284. http://www.debian.org/support
+ 285. http://www.slackware.com/support/
+ 286. http://www.caldera.com/support/
+ 287. http://www.novell.com/support/microsites/microsite.do
+ 288. http://www.mandrake.com/support/
+ 289. http://www.turbolinux.com/support/
+ 290. http://www.linmodems.org/
+ 291. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 292. http://linux.dreamtime.org/decnet/
+ 293. mailto:kermit-support@columbia.edu
+ 294. http://www.linmodems.org/
+ 295. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 296. http://www.columbia.edu/kermit/security.html#servers
+ 297. http://www.columbia.edu/kermit/sshclient.html
+ 298. http://www.columbia.edu/kermit/ckubwr.html#top
+ 299. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 300. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 301. http://www.columbia.edu/kermit/ckubwr.html#x3.3.2
+ 302. http://www.columbia.edu/kermit/ckubwr.html#top
+ 303. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 304. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 305. http://www.columbia.edu/kermit/ckubwr.html#x3.3.3
+ 306. http://www.columbia.edu/kermit/ckubwr.html#x3.3.1
+ 307. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 308. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 309. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 310. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 311. http://www.columbia.edu/kermit/ckuins.html#x10
+ 312. http://www.columbia.edu/kermit/ckuins.html#x11
+ 313. http://www.columbia.edu/kermit/ckuins.html
+ 314. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 315. http://linuxwww.db.erau.edu/mail_archives/linux-kernel/Mar_98/1441.html
+ 316. http://www.columbia.edu/kermit/ckubwr.html#top
+ 317. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 318. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 319. http://www.columbia.edu/kermit/ckubwr.html#x3.3.4
+ 320. http://www.columbia.edu/kermit/ckubwr.html#x3.3.2
+ 321. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 322. http://www.columbia.edu/kermit/ckfaq.html#term
+ 323. http://dickey.his.com/xterm/xterm.html
+ 324. http://dickey.his.com/xterm/xterm.html
+ 325. ftp://kermit.columbia.edu/kermit/f/xmodmap.txt
+ 326. http://www.columbia.edu/kermit/ckubwr.html#top
+ 327. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 328. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 329. http://www.columbia.edu/kermit/ckubwr.html#x3.3.5
+ 330. http://www.columbia.edu/kermit/ckubwr.html#x3.3.3
+ 331. http://www.columbia.edu/kermit/ckubwr.html#top
+ 332. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 333. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 334. http://www.columbia.edu/kermit/ckubwr.html#x3.3.6
+ 335. http://www.columbia.edu/kermit/ckubwr.html#x3.3.4
+ 336. http://www.columbia.edu/kermit/ckermit.html
+ 337. mailto:kermit-support@columbia.edu
+ 338. http://www.redhat.com/support/errata/RHBA-2001-153.html
+ 339. news:comp.protocols.kermit.misc
+ 340. http://www.columbia.edu/kermit/ckubwr.html#top
+ 341. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 342. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 343. http://www.columbia.edu/kermit/ckubwr.html#x3.3.5
+ 344. http://www.columbia.edu/kermit/ckubwr.html#top
+ 345. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 346. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 347. http://www.columbia.edu/kermit/ckubwr.html#x3.5
+ 348. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 349. http://www.columbia.edu/kermit/ckubwr.html#top
+ 350. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 351. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 352. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 353. http://www.columbia.edu/kermit/ckubwr.html#x3.4
+ 354. news:comp.os.qnx
+ 355. http://www.columbia.edu/kermit/gkermit.html
+ 356. http://www.columbia.edu/kermit/ckuins.html#x10
+ 357. http://www.columbia.edu/kermit/ckuins.html
+ 358. http://www.columbia.edu/kermit/ckubwr.html#top
+ 359. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 360. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 361. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 362. http://www.columbia.edu/kermit/ckubwr.html#x3.5
+ 363. http://www.columbia.edu/kermit/ckubwr.html#x3.6.1
+ 364. http://www.columbia.edu/kermit/ckubwr.html#x3.6.2
+ 365. http://www.columbia.edu/kermit/ckubwr.html#x3.6.3
+ 366. http://www.columbia.edu/kermit/ckubwr.html#x3.6.4
+ 367. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 368. http://aplawrence.com/SCOFAQ/
+ 369. http://www.zenez.com/cgi-bin/scoprogfaq/faq.pl
+ 370. http://www.zenez.com/cgi-bin/scouw7faq/faq.pl
+ 371. http://zenez.pcunix.com/cgi-bin/scouw7faq/faq.pl
+ 372. http://pcunix.com/Unixart/modems.html
+ 373. http://www.freebird.org/faq/
+ 374. http://www.freebird.org/faq/developer.html
+ 375. http://support.caldera.com/caldera
+ 376. http://stage.caldera.com/ta/
+ 377. http://aplawrence.com/newtosco.html
+ 378. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 379. http://www.columbia.edu/kermit/ckfaq.html#term
+ 380. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 381. http://www.columbia.edu/kermit/ckubwr.html#top
+ 382. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 383. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 384. http://www.columbia.edu/kermit/ckubwr.html#x3.6.1
+ 385. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 386. http://www.columbia.edu/kermit/ckubwr.html#top
+ 387. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 388. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 389. http://www.columbia.edu/kermit/ckubwr.html#x3.6.3
+ 390. http://www.columbia.edu/kermit/ckubwr.html#x3.6.1
+ 391. http://www.digi.com/
+ 392. ftp://ftp.fu-berlin.de/pub/unix/driver/fas
+ 393. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 394. http://www.sco.com/
+ 395. ftp://ftp.sco.com/
+ 396. http://www.columbia.edu/kermit/ckubwr.html#top
+ 397. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 398. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 399. http://www.columbia.edu/kermit/ckubwr.html#x3.6.4
+ 400. http://www.columbia.edu/kermit/ckubwr.html#x3.6.2
+ 401. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 402. http://www.columbia.edu/kermit/ckubwr.html#top
+ 403. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 404. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 405. http://www.columbia.edu/kermit/ckubwr.html#x3.6.3
+ 406. http://www.columbia.edu/kermit/ckubwr.html#top
+ 407. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 408. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 409. http://www.columbia.edu/kermit/ckubwr.html#x3.8
+ 410. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 411. http://www.columbia.edu/kermit/ckubwr.html#x3.7.1
+ 412. http://www.columbia.edu/kermit/ckubwr.html#x3.7.2
+ 413. http://www.columbia.edu/kermit/ckubwr.html#x3.7.3
+ 414. http://www.columbia.edu/kermit/ckubwr.html#x3.7.4
+ 415. http://www.columbia.edu/kermit/ckubwr.html#x3.7.5
+ 416. news:comp.unix.solaris
+ 417. http://access1.sun.com/
+ 418. http://docs.sun.com/
+ 419. http://www.sunhelp.com/
+ 420. http://www.wins.uva.nl/pub/solaris/solaris2/
+ 421. http://www.wins.uva.nl/cgi-bin/sfaq.cgi
+ 422. ftp://ftp.wins.uva.nl/pub/solaris
+ 423. http://www.science.uva.nl/pub/solaris/solaris2.html
+ 424. http://www.stokely.com/
+ 425. http://www.stokely.com/unix.sysadm.resources/faqs.sun.html
+ 426. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 427. http://www.columbia.edu/kermit/ckubwr.html#top
+ 428. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 429. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 430. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 431. http://www.columbia.edu/kermit/ckubwr.html#x3.7.2
+ 432. http://www.columbia.edu/kermit/ckubwr.html#top
+ 433. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 434. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 435. http://www.columbia.edu/kermit/ckubwr.html#x3.7.3
+ 436. http://www.columbia.edu/kermit/ckubwr.html#x3.7.1
+ 437. http://www.columbia.edu/kermit/ckubwr.html#top
+ 438. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 439. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 440. http://www.columbia.edu/kermit/ckubwr.html#x3.7.4
+ 441. http://www.columbia.edu/kermit/ckubwr.html#x3.7.2
+ 442. http://www.columbia.edu/kermit/ckubwr.html#top
+ 443. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 444. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 445. http://www.columbia.edu/kermit/ckubwr.html#x3.7.5
+ 446. http://www.columbia.edu/kermit/ckubwr.html#x3.7.3
+ 447. news:comp.os.vms
+ 448. http://www.columbia.edu/kermit/ckubwr.html#top
+ 449. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 450. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 451. http://www.columbia.edu/kermit/ckubwr.html#x3.7.6
+ 452. http://www.columbia.edu/kermit/ckubwr.html#x3.7.4
+ 453. http://www.columbia.edu/kermit/ckubwr.html#top
+ 454. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 455. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 456. http://www.columbia.edu/kermit/ckubwr.html#x3.7.5
+ 457. http://www.columbia.edu/kermit/ckubwr.html#top
+ 458. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 459. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 460. http://www.columbia.edu/kermit/ckubwr.html#x3.9
+ 461. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 462. http://www.stokely.com/
+ 463. http://access1.sun.com/
+ 464. http://www.ludd.luth.se/~bear/project/sun/sun.hardware.txt
+ 465. ftp://ftp.netcom.com/pub/ru/rubicon/sun.hdwr.ref
+ 466. ftp://ftp.intnet.net/pub/SUN/Sun-Hardware-Ref
+ 467. http://www.columbia.edu/kermit/ckubwr.html#top
+ 468. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 469. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 470. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 471. http://www.columbia.edu/kermit/ckubwr.html#x3.8
+ 472. news:comp.unix.ultrix
+ 473. news:comp.sys.dec
+ 474. http://www.columbia.edu/kermit/ckubwr.html#top
+ 475. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 476. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 477. http://www.columbia.edu/kermit/ckubwr.html#x3.11
+ 478. http://www.columbia.edu/kermit/ckubwr.html#x3.9
+ 479. http://www.freebird.org/
+ 480. http://www.freebird.org/faq/
+ 481. news:comp.unix.unixware.misc
+ 482. news:comp.unix.sco.misc
+ 483. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 484. ftp://kermit.columbia.edu/kermit/f/ckutio.c
+ 485. http://www.columbia.edu/kermit/ckubwr.html#top
+ 486. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 487. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 488. http://www.columbia.edu/kermit/ckubwr.html#x3.12
+ 489. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 490. http://www.columbia.edu/kermit/ckubwr.html#top
+ 491. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 492. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 493. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+ 494. http://www.columbia.edu/kermit/ckubwr.html#x3.11
+ 495. http://www.columbia.edu/kermit/ckubwr.html#top
+ 496. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 497. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 498. http://www.columbia.edu/kermit/ckubwr.html#x3.14
+ 499. http://www.columbia.edu/kermit/ckubwr.html#x3.12
+ 500. http://www.columbia.edu/kermit/ckubwr.html#top
+ 501. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 502. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 503. http://www.columbia.edu/kermit/ckubwr.html#x3.15
+ 504. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+ 505. news:comp.sys.sgi.misc
+ 506. news:comp.sys.sgi.admin
+ 507. http://www.sgi.com/
+ 508. http://www-viz.tamu.edu/~sgi-faq/
+ 509. ftp://viz.tamu.edu/pub/sgi/faq/
+ 510. http://www.columbia.edu/kermit/ckuins.html
+ 511. http://freeware.sgi.com/Installable/gcc-2.95.2.html
+ 512. http://freeware.sgi.com/Installable/gcc-2.95.2.html
+ 513. http://www.columbia.edu/kermit/ckubwr.html#top
+ 514. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 515. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 516. http://www.columbia.edu/kermit/ckubwr.html#x3.16
+ 517. http://www.columbia.edu/kermit/ckubwr.html#x3.14
+ 518. news:comp.sys.be
+ 519. http://www.columbia.edu/kermit/ckubwr.html#top
+ 520. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 521. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 522. http://www.columbia.edu/kermit/ckubwr.html#x3.17
+ 523. http://www.columbia.edu/kermit/ckubwr.html#x3.15
+ 524. http://www.columbia.edu/kermit/ckubwr.html#top
+ 525. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 526. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 527. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+ 528. http://www.columbia.edu/kermit/ckubwr.html#x3.16
+ 529. http://www.columbia.edu/kermit/ckubwr.html#top
+ 530. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 531. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 532. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+ 533. http://www.columbia.edu/kermit/ckubwr.html#x3.17
+ 534. http://www.columbia.edu/kermit/ckubwr.html#top
+ 535. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 536. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 537. http://www.columbia.edu/kermit/ckubwr.html#x3.20
+ 538. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+ 539. http://www.columbia.edu/kermit/mac.html
+ 540. http://www.amazon.com/gp/product/B0000VYJRY?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=B0000VYJRY
+ 541. http://www.columbia.edu/kermit/ckuins.html#x10
+ 542. http://www.columbia.edu/kermit/ckuins.html
+ 543. http://www.amazon.com/gp/product/B000FX61MS?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=B000FX61MS
+ 544. mailto:kermit@columbia.edu
+ 545. http://www.columbia.edu/kermit/ckubwr.html#top
+ 546. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 547. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 548. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+ 549. http://www.uni-giessen.de/faq/archiv/coherent-faq.general/msg00000.html
+ 550. http://www.columbia.edu/kermit/ckubwr.html#top
+ 551. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 552. http://www.columbia.edu/kermit/ckubwr.html#x5
+ 553. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 554. http://www.columbia.edu/kermit/ckccfg.html
+ 555. http://www.columbia.edu/kermit/ckubwr.html#top
+ 556. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 557. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 558. http://www.columbia.edu/kermit/ckubwr.html#x4
+ 559. http://www.columbia.edu/kermit/ckuins.html
+ 560. http://www.columbia.edu/kermit/ckubwr.html#top
+ 561. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 562. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 563. http://www.columbia.edu/kermit/ckubwr.html#x5
+ 564. http://www.columbia.edu/kermit/ckuins.html#9.5
+ 565. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 566. http://www.columbia.edu/kermit/ckubwr.html#top
+ 567. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 568. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 569. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 570. http://www.columbia.edu/kermit/ckuins.html#x8
+ 571. http://www.columbia.edu/kermit/ckuins.html
+ 572. http://www.columbia.edu/kermit/ck60manual.html
+ 573. http://www.columbia.edu/kermit/cable.html
+ 574. http://www.columbia.edu/kermit/ckubwr.html#top
+ 575. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 576. http://www.columbia.edu/kermit/ckubwr.html#x9
+ 577. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 578. http://www.columbia.edu/kermit/ckubwr.html#top
+ 579. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 580. http://www.columbia.edu/kermit/ckubwr.html#x10
+ 581. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 582. http://www.columbia.edu/kermit/ck60manual.html
+ 583. http://dickey.his.com/xterm/xterm.html
+ 584. http://www.columbia.edu/kermit/ckubwr.html#top
+ 585. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 586. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 587. http://www.columbia.edu/kermit/ckubwr.html#x9
+ 588. http://www.columbia.edu/kermit/ckubwr.html#top
+ 589. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 590. http://www.columbia.edu/kermit/ckubwr.html#x12
+ 591. http://www.columbia.edu/kermit/ckubwr.html#x10
+ 592. http://www.columbia.edu/kermit/ckubwr.html#x11.1
+ 593. http://www.columbia.edu/kermit/ckubwr.html#x11.2
+ 594. http://www.columbia.edu/kermit/ckubwr.html#top
+ 595. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 596. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 597. http://www.columbia.edu/kermit/ckubwr.html#x11.2
+ 598. http://www.columbia.edu/kermit/ck60manual.html
+ 599. http://www.columbia.edu/kermit/ckubwr.html#top
+ 600. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 601. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 602. http://www.columbia.edu/kermit/ckubwr.html#x11.1
+ 603. http://www.columbia.edu/kermit/ck60manual.html
+ 604. http://www.columbia.edu/kermit/ckubwr.html#top
+ 605. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 606. http://www.columbia.edu/kermit/ckubwr.html#x13
+ 607. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 608. http://www.columbia.edu/kermit/security.html
+ 609. http://www.columbia.edu/kermit/ckubwr.html#top
+ 610. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 611. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 612. http://www.columbia.edu/kermit/ckubwr.html#x12
+ 613. http://www.columbia.edu/kermit/ckubwr.html#top
+ 614. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 615. http://www.columbia.edu/kermit/ckubwr.html#x15
+ 616. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 617. mailto:support@stallion.oz.au
+ 618. http://www.stallion.com/
+ 619. http://www.columbia.edu/kermit/ckubwr.html#top
+ 620. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 621. http://www.columbia.edu/kermit/ckermit.html
+ 622. http://www.columbia.edu/kermit/ck80.html
+ 623. http://www.columbia.edu/kermit/index.html
+ 624. http://www.columbia.edu/kermit/index.html
+ 625. http://www.columbia.edu/
+ 626. mailto:kermit@columbia.edu
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.c
new file mode 100644
index 0000000..d70770e
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.c
@@ -0,0 +1,7919 @@
+#include "ckcsym.h"
+
+char *cmdv = "Command package 9.0.168, 12 March 2010";
+
+/* C K U C M D -- Interactive command package for Unix */
+
+/* (In reality, it's for all platforms, not just Unix) */
+
+/*
+ Author: Frank da Cruz (fdc@columbia.edu),
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+#define TOKPRECHECK
+
+#define DOCHKVAR
+
+/* Command-terminal-to-C-Kermit character mask */
+
+#ifdef OS2 /* K95 */
+int cmdmsk = 255; /* (always was 255) */
+#else /* All others... */
+int cmdmsk = 255; /* 31 Dec 2000 (was 127) */
+#endif /* OS2 */
+
+#ifdef BS_DIRSEP /* Directory separator is backslash */
+#undef BS_DIRSEP
+#endif /* BS_DIRSEP */
+
+#ifdef OS2
+#define BS_DIRSEP
+#endif /* BS_DIRSEP */
+
+#define CKUCMD_C
+
+#include "ckcdeb.h" /* Formats for debug(), etc. */
+#include "ckcker.h" /* Needed for BIGBUFOK definition */
+#include "ckcnet.h" /* Needed for server-side Telnet */
+#include "ckucmd.h" /* Needed for everything */
+#include "ckuusr.h" /* Needed for prompt length */
+
+#ifndef NOARROWKEYS
+#ifndef NOESCSEQ
+#ifdef VMSORUNIX
+#define USE_ARROWKEYS /* Use arrow keys for command recall */
+#endif /* VMSORUNIX */
+#endif /* NOESCSEQ */
+#endif /* NOARROWKEYS */
+
+#undef CKUCMD_C
+
+_PROTOTYP( int unhex, (char) );
+_PROTOTYP( static VOID cmdclrscn, (void) );
+
+#ifdef CKLEARN
+_PROTOTYP( VOID learncmd, (char *) );
+#endif /* CKLEARN */
+
+static char *moname[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+struct keytab cmonths[] = {
+ { "april", 4, 0 },
+ { "august", 8, 0 },
+ { "december", 12, 0 },
+ { "february", 2, 0 },
+ { "january", 1, 0 },
+ { "july", 7, 0 },
+ { "june", 6, 0 },
+ { "march", 3, 0 },
+ { "may", 5, 0 },
+ { "november", 11, 0 },
+ { "october", 10, 0 },
+ { "september", 9, 0 }
+};
+
+#ifndef NOICP /* The rest only if interactive command parsing selected */
+
+#ifndef NOSPL
+_PROTOTYP( int chkvar, (char *) );
+extern int askflag, echostars;
+#endif /* NOSPL */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+#ifdef IKSD
+extern int inserver;
+#endif /* IKSD */
+
+int cmfldflgs = 0; /* Flags for cmfld() */
+int cmkwflgs = 0; /* Flags from last keyword parse */
+static int nomsg = 0;
+static int blocklvl = 0; /* Block nesting level */
+static int linebegin = 0; /* Flag for at start of a line */
+static int quoting = 1; /* Quoting is allowed */
+static int swarg = 0; /* Parsing a switch argument */
+static int xcmfdb = 0; /* Flag for parsing chained fdbs... */
+static int chsrc = 0; /* Source of character, 1 = tty */
+static int newcmd = 0; /* See addcmd() */
+
+#ifdef BS_DIRSEP
+static int dirnamflg = 0;
+#endif /* BS_DIRSEP */
+
+/*
+Modeled after the DECSYSTEM-20 command parser (the COMND JSYS), RIP. Features:
+
+ . parses and verifies keywords, filenames, text strings, numbers, other data
+ . displays appropriate menu or help message when user types "?"
+ . does keyword and filename completion when user types ESC or TAB
+ . does partial keyword and filename completion
+ . accepts any unique abbreviation for a keyword
+ . allows keywords to have attributes, like "invisible" and "abbreviation"
+ . can supply defaults for fields omitted by user
+ . provides command retry and recall
+ . provides character, word, and line deletion (but only from the end)
+ . accepts input from keyboard, command files, macros, or redirected stdin
+ . allows for full or half duplex operation, character or line input
+ . allows \-escapes for special characters
+ . allows specification of a user exit to expand variables, etc.
+ . settable prompt, protected from deletion, dynamically re-evaluated each time
+ . allows chained parse functions.
+
+Functions:
+ cmsetp - Set prompt (cmprom is prompt string)
+ cmsavp - Save current prompt
+ cmgetp = Get current prompt
+ prompt - Issue prompt
+ cmini - Clear the command buffer (before parsing a new command)
+ cmres - Reset command buffer pointers (before reparsing)
+ cmkey - Parse a keyword or token (also cmkey2)
+ cmswi - Parse a switch
+ cmnum - Parse a number
+ cmifi - Parse an input file name
+ cmofi - Parse an output file name (also cmifip, cmifi2, ...)
+ cmdir - Parse a directory name (also cmdirp)
+ cmfld - Parse an arbitrary field
+ cmtxt - Parse a text string
+ cmdate - Parse a date-time string
+ cmcfm - Parse command confirmation (end of line)
+ cmfdb - Parse any of a list of the foregoing (chained parse functions)
+
+Return codes:
+ -9: like -2 except this module already printed the error message
+ -3: no input provided when required
+ -2: input was invalid (e.g. not a number when a number was required)
+ -1: reparse required (user deleted into a preceding field)
+ 0 or greater: success
+See individual functions for greater detail.
+
+Before using these routines, the caller should #include "ckucmd.h" and set the
+program's prompt by calling cmsetp(). If the file parsing functions cmifi,
+cmofi, or cmdir are to be used, this module must be linked with a ck?fio file
+system support module for the appropriate system, e.g. ckufio for Unix. If
+the caller puts the terminal in character wakeup ("cbreak") mode with no echo,
+then these functions will provide line editing -- character, word, and line
+deletion, as well as keyword and filename completion upon ESC and help
+strings, keyword, or file menus upon '?'. If the caller puts the terminal
+into character wakeup/noecho mode, care should be taken to restore it before
+exit from or interruption of the program. If the character wakeup mode is not
+set, the system's own line editor may be used.
+
+NOTE: Contrary to expectations, many #ifdef's have been added to this module.
+Any operation requiring an #ifdef (like clear screen, get character from
+keyboard, erase character from screen, etc) should eventually be turned into a
+call to a function that is defined in ck?tio.c, but then all the ck?tio.c
+modules would have to be changed...
+*/
+
+/* Includes */
+
+#include "ckcker.h"
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckucmd.h" /* Command parsing definitions */
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#endif /* NT */
+#include "ckocon.h"
+#include <io.h>
+#endif /* OS2 */
+
+#ifdef OSK
+#define cc ccount /* OS-9/68K compiler bug */
+#endif /* OSK */
+
+#ifdef GEMDOS /* Atari ST */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#endif /* GEMDOS */
+
+#ifdef CK_AUTODL
+extern int cmdadl, justone;
+#endif /* CK_AUTODL */
+
+extern int timelimit, nzxopts, nopush, nolocal, xcmdsrc, keepallchars;
+
+#ifdef CKSYSLOG
+#ifdef UNIX
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in syslog.h */
+#endif /* CKXPRINTF */
+#ifdef RTAIX
+#include <sys/syslog.h>
+#else /* RTAIX */
+#include <syslog.h>
+#endif /* RTAIX */
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#endif /* UNIX */
+#endif /* CKSYSLOG */
+
+/* Local variables */
+
+static
+int psetf = 0, /* Flag that prompt has been set */
+ cc = 0, /* Character count */
+ dpx = 0, /* Duplex (0 = full) */
+ inword = 0; /* In the middle of getting a word */
+
+char *dfprom = "Command? "; /* Default prompt */
+#ifndef NOLASTFILE
+char *lastfile = NULL; /* Last filespec */
+static char *tmplastfile = NULL; /* Last filespec candidate */
+#endif /* NOLASTFILE */
+
+int cmflgs; /* Command flags */
+int cmfsav; /* A saved version of them */
+
+static char pushc = NUL;
+static char brkchar = NUL;
+
+#define CMDEFAULT 1023
+static char cmdefault[CMDEFAULT+1];
+
+#ifdef DCMDBUF
+char *cmdbuf = NULL; /* Command buffer */
+char *savbuf = NULL; /* Buffer to save copy of command */
+char *atmbuf = NULL; /* Atom buffer - for current field */
+char *atxbuf = NULL; /* For expanding the atom buffer */
+char *prevcmd = NULL;
+static char *atybuf = NULL; /* For copying atom buffer */
+static char *filbuf = NULL; /* File name buffer */
+static char *cmprom = NULL; /* Program's prompt */
+static char *cmprxx = NULL; /* Program's prompt, unevaluated */
+
+#ifdef CK_RECALL
+/*
+ Command recall is available only if we can make profligate use of malloc().
+*/
+#define R_MAX 10 /* How many commands to save */
+int cm_recall = R_MAX; /* Size of command recall buffer */
+int on_recall = 1; /* Recall feature is ON */
+static int no_recall = 0; /* Recall OFF for this cmd only */
+static int force_add = 0; /* Force cmd into recall buffer */
+static int last_recall = -1; /* Last recall-related action */
+/*
+ -1 = none
+ 0 = CR (a command was entered)
+ 1 = Up
+ 2 = Down
+*/
+int in_recall = 0; /* Recall buffers are init'd */
+static int
+ current = -1, /* Pointer to current command */
+ rlast = -1; /* Index of last command in buffer */
+static char **recall = NULL; /* Array of recall buffer pointers */
+#endif /* CK_RECALL */
+#else /* !DCMDBUF */
+char cmdbuf[CMDBL+4]; /* Command buffer */
+char savbuf[CMDBL+4]; /* Buffer to save copy of command */
+char atmbuf[ATMBL+4]; /* Atom buffer */
+char atxbuf[CMDBL+4]; /* For expanding the atom buffer */
+char prevcmd[CMDBL+4]; /* For displaying the last command */
+static char atybuf[ATMBL+4]; /* For copying atom buffer */
+static char filbuf[ATMBL+4]; /* File name buffer */
+static char cmprom[PROMPTL+1]; /* Program's prompt */
+static char cmprxx[PROMPTL+1]; /* Program's prompt, unevaluated */
+#endif /* DCMDBUF */
+
+/* Command buffer pointers */
+
+#define PPVLEN VNAML /* 20080305 Wolfram Sang (was 24) */
+char ppvnambuf[PPVLEN+1] = { NUL, NUL };
+
+char * cmbptr = NULL; /* Current position (for export) */
+
+static char *bp, /* Current command buffer position */
+ *pp, /* Start of current field */
+ *np; /* Start of next field */
+
+static int ungw, /* For ungetting words */
+ atxn; /* Expansion buffer (atxbuf) length */
+
+#ifdef OS2
+extern int wideresult;
+#endif /* OS2 */
+
+extern int cmd_cols, cmd_rows, local, quiet;
+
+#ifdef TNCODE
+#ifdef IAC
+#undef IAC
+#endif /* IAC */
+#define IAC 255
+#endif /* TNCODE */
+
+_PROTOTYP( static int gtword, (int) );
+_PROTOTYP( static int addbuf, (char *) );
+_PROTOTYP( static int setatm, (char *, int) );
+_PROTOTYP( static VOID cmdnewl, (char) );
+_PROTOTYP( static VOID cmdchardel, (void) );
+_PROTOTYP( static VOID cmdecho, (char, int) );
+_PROTOTYP( static int test, (int, int) );
+#ifdef GEMDOS
+_PROTOTYP( extern char *strchr, (char *, int) );
+#endif /* GEMDOS */
+
+extern char * dftty;
+
+/* The following are for use with chained FDB's */
+
+static int crflag = 0; /* Carriage return was typed */
+static int qmflag = 0; /* Question mark was typed */
+static int esflag = 0; /* Escape was typed */
+
+/* Directory separator */
+
+#ifdef GEMDOS
+static char dirsep = '\\';
+#else
+#ifdef datageneral
+static char dirsep = ':';
+#else
+#ifdef MAC
+static char dirsep = ':';
+#else
+#ifdef VMS
+static char dirsep = '.';
+#else
+#ifdef STRATUS
+static char dirsep = '>';
+#else
+static char dirsep = '/'; /* UNIX, OS/2, OS-9, Amiga, etc. */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* MAC */
+#endif /* datageneral */
+#endif /* GEMDOS */
+
+/* H A S N O P A T H */
+
+/* Returns 0 if filespec s includes any path segments; 1 if it doesn't. */
+
+int
+hasnopath(s) char * s; {
+ char * p = NULL;
+ if (!s) return(0);
+ if (!*s) return(0);
+ zstrip(s,&p);
+ return(ckstrcmp(s,p,CKMAXPATH,filecase) == 0 ? 1 : 0);
+}
+
+/* C K S P R E A D -- Print string double-spaced */
+
+static char * sprptr = NULL;
+
+static char *
+ckspread(s) char * s; {
+ int n = 0;
+ char * p;
+ n = strlen(s);
+ if (sprptr)
+ free(sprptr);
+ sprptr = malloc(n + n + 3);
+ if (sprptr) {
+ p = sprptr;
+ while (*s) {
+ *p++ = *s++;
+ *p++ = SP;
+ }
+ *p = NUL;
+ }
+ return(sprptr ? sprptr : "");
+}
+
+/* T E S T -- Bit test */
+
+static int
+test(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */
+ return((x & m) ? 1 : 0);
+}
+
+/* K W D H E L P -- Given a keyword table, print keywords in columns. */
+/*
+ Call with:
+ s - keyword table
+ n - number of entries
+ pat - pattern (left substring) that must match for each keyword
+ pre - prefix to add to each keyword
+ post - suffix to add to each keyword
+ off - offset on first screenful, allowing room for introductory text
+ xhlp - 1 to print any CM_INV keywords that are not also abbreviations.
+ 2 to print CM_INV keywords if CM_HLP also set
+ 4 if it's a switch table (to show ':' if CM_ARG)
+
+ Arranges keywords in columns with width based on longest keyword.
+ Does "more?" prompting at end of screen.
+ Uses global cmd_rows and cmd_cols for screen size.
+*/
+VOID
+kwdhelp(s,n,pat,pre,post,off,xhlp)
+ struct keytab s[]; int n, off, xhlp; char *pat, *pre, *post;
+/* kwdhelp */ {
+
+ int width = 0;
+ int cc;
+ int cols, height, i, j, k, lc, n2 = 0;
+ char *b = NULL, *p, *q;
+ char *pa, *px;
+ char **s2 = NULL;
+ char *tmpbuf = NULL;
+
+ cc = strlen(pat);
+
+ if (!s) return; /* Nothing to do */
+ if (n < 1) return; /* Ditto */
+ if (off < 0) off = 0; /* Offset for first page */
+ if (!pre) pre = ""; /* Handle null string pointers */
+ if (!post) post = "";
+ lc = off; /* Screen-line counter */
+
+ if (xhlp & 4) /* For switches */
+ tmpbuf = (char *)malloc(TMPBUFSIZ+1);
+
+ if ((s2 = (char **) malloc(n * sizeof(char *)))) {
+ for (i = 0; i < n; i++) { /* Find longest keyword */
+ s2[i] = NULL;
+ if (ckstrcmp(s[i].kwd,pat,cc,0))
+ continue;
+
+ if (s[i].flgs & CM_PSH /* NOPUSH or nopush screening */
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ )
+ continue;
+ if (s[i].flgs & CM_LOC /* NOLOCAL or nolocal screening */
+#ifndef NOLOCAL
+ && nolocal
+#endif /* NOLOCAL */
+ )
+ continue;
+
+ if (s[i].flgs & CM_INV) {
+#ifdef COMMENT
+/* This code does not show invisible keywords at all except for "help ?" */
+/* and then only help topics (CM_HLP) in the top-level keyword list. */
+
+ if ((xhlp & 2) == 0)
+ continue;
+ else if ((s[i].flgs & CM_HLP) == 0)
+ continue;
+#else
+/* This code shows invisible keywords that are not also abbreviations when */
+/* ? was typed AFTER the beginning of the field so the user can find out */
+/* what they are and (for example) why completion doesn't work at this point */
+
+ if (s[i].flgs & CM_ABR)
+ continue;
+ else if ((xhlp & 3) == 0)
+ continue;
+ else if ((xhlp & 2) && ((s[i].flgs & CM_HLP) == 0))
+ continue;
+#endif /* COMMENT */
+ }
+ j = strlen(s[i].kwd);
+ if (!(xhlp & 4) || !tmpbuf) { /* Regular keyword table */
+ s2[n2++] = s[i].kwd; /* Copy pointers to visible ones */
+ } else { /* Switches */
+ ckmakmsg(tmpbuf, /* Make a copy that shows ":" if */
+ TMPBUFSIZ, /* the switch takes an argument. */
+ s[i].kwd,
+ (s[i].flgs & CM_ARG) ? ":" : "",
+ NULL,
+ NULL
+ );
+ makestr(&(s2[n2]),tmpbuf);
+ if (s[i].flgs & CM_ARG) j++;
+ n2++;
+ }
+ if (j > width)
+ width = j;
+ }
+ /* Column width */
+ n = n2;
+ }
+ if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
+ char * bx;
+ bx = b + cmd_cols;
+ width += (int)strlen(pre) + (int)strlen(post) + 2;
+ cols = cmd_cols / width; /* How many columns? */
+ if (cols < 1) cols = 1;
+ height = n / cols; /* How long is each column? */
+ if (n % cols) height++; /* Add one for remainder, if any */
+
+ for (i = 0; i < height; i++) { /* Loop for each row */
+ for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */
+ b[j] = SP;
+ for (j = 0; j < cols; j++) { /* Loop for each column in row */
+ k = i + (j * height); /* Index of next keyword */
+ if (k < n) { /* In range? */
+ pa = pre;
+ px = post;
+ p = s2[k]; /* Point to verb name */
+ q = b + (j * width) + 1; /* Where to copy it to */
+ while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
+ if (j < cols - 1) {
+ q--;
+ *q = SP; /* Replace the space */
+ }
+ }
+ }
+ p = b + cmd_cols - 1; /* Last char in line */
+ while (*p-- == SP) ; /* Trim */
+ *(p+2) = NUL;
+ printf("%s\n",b); /* Print the line */
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) /* Do more-prompting... */
+ goto xkwdhelp;
+ else
+ lc = 0;
+ }
+ }
+ /* printf("\n"); */ /* Blank line at end of report */
+ } else { /* Malloc failure, no columns */
+ for (i = 0; i < n; i++) {
+ if (s[i].flgs & CM_INV) /* Use original keyword table */
+ continue; /* skipping invisible entries */
+ printf("%s%s%s\n",pre,s[i].kwd,post);
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) /* Do more-prompting... */
+ goto xkwdhelp;
+ else
+ lc = 0;
+ }
+ }
+ }
+ xkwdhelp:
+ if (xhlp & 4) {
+ if (tmpbuf) free((char *)tmpbuf);
+ for (i = 0; i < n; i++)
+ if (s2[i]) free(s2[i]);
+ }
+ if (s2) free(s2); /* Free array copy */
+ if (b) free(b); /* Free line buffer */
+ return;
+}
+
+/* X F I L H E L P -- Given a file list, print names in columns. */
+/*
+ Call with:
+ n - number of entries
+ pre - prefix to add to each filename
+ post - suffix to add to each filename
+ off - offset on first screenful, allowing room for introductory text
+ cmdirflg - 1 if only directory names should be listed, 0 to list all files
+ fs - call fileselect() to decide whether to include each file.
+ The rest of the args are the same as for fileselect().
+
+ Arranges filenames in columns with width based on longest filename.
+ Does "more?" prompting at end of screen.
+ Uses global cmd_rows and cmd_cols for screen size.
+*/
+
+int
+#ifdef CK_ANSIC
+xfilhelp(
+ int n, char *pre, char *post, int off, int cmdirflag,
+ int fs, char *sa, char *sb, char *sna, char *snb,
+ CK_OFF_T minsiz, CK_OFF_T maxsiz,
+ int nbu, int nxlist,
+ char ** xlist
+)
+#else
+xfilhelp(n,pre,post,off,cmdirflg,
+ fs,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
+ int n, off; char *pre, *post; int cmdirflg;
+ int fs; char *sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
+ int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+ {
+ char filbuf[CKMAXPATH + 1]; /* Temp buffer for one filename */
+ int width = 0;
+ int cols, height, i, j, k, lc, n2 = 0, rc = 0, itsadir = 0;
+ char *b = NULL, *p, *q;
+ char *pa, *px;
+ char **s2 = NULL;
+#ifdef VMS
+ char * cdp = zgtdir();
+#endif /* VMS */
+
+ if (n < 1) return(0);
+ if (off < 0) off = 0; /* Offset for first page */
+ if (!pre) pre = ""; /* Handle null string pointers */
+ if (!post) post = "";
+
+ lc = off; /* Screen-line counter */
+
+ if ((s2 = (char **) malloc(n * sizeof(char *)))) {
+ for (i = 0; i < n; i++) { /* Loop through filenames */
+ itsadir = 0;
+ s2[i] = NULL; /* Initialize each pointer to NULL */
+ znext(filbuf); /* Get next filename */
+ if (!filbuf[0]) /* Shouldn't happen */
+ break;
+#ifdef COMMENT
+ itsadir = isdir(filbuf); /* Is it a directory? */
+ if (cmdirflg && !itsadir) /* No, listing directories only? */
+ continue; /* So skip this one. */
+#endif /* COMMENT */
+ if (fs) if (fileselect(filbuf,
+ sa,sb,sna,snb,
+ minsiz,maxsiz,nbu,nxlist,xlist) < 1) {
+ continue;
+ }
+#ifdef VMS
+ ckstrncpy(filbuf,zrelname(filbuf,cdp),CKMAXPATH);
+#endif /* VMS */
+ j = strlen(filbuf);
+#ifndef VMS
+ if (itsadir && j < CKMAXPATH - 1 && j > 0) {
+ if (filbuf[j-1] != dirsep) {
+ filbuf[j++] = dirsep;
+ filbuf[j] = NUL;
+ }
+ }
+#endif /* VMS */
+ if (!(s2[n2] = malloc(j+1))) {
+ printf("?Memory allocation failure\n");
+ rc = -9;
+ goto xfilhelp;
+ }
+ if (j <= CKMAXPATH) {
+ strcpy(s2[n2],filbuf);
+ n2++;
+ } else {
+ printf("?Name too long - %s\n", filbuf);
+ rc = -9;
+ goto xfilhelp;
+ }
+ if (j > width) /* Get width of widest one */
+ width = j;
+ }
+ n = n2; /* How many we actually got */
+ }
+ sh_sort(s2,NULL,n,0,0,filecase); /* Alphabetize the list */
+
+ rc = 1;
+ if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
+ char * bx;
+ bx = b + cmd_cols;
+ width += (int)strlen(pre) + (int)strlen(post) + 2;
+ cols = cmd_cols / width; /* How many columns? */
+ if (cols < 1) cols = 1;
+ height = n / cols; /* How long is each column? */
+ if (n % cols) height++; /* Add one for remainder, if any */
+
+ for (i = 0; i < height; i++) { /* Loop for each row */
+ for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */
+ b[j] = SP;
+ for (j = 0; j < cols; j++) { /* Loop for each column in row */
+ k = i + (j * height); /* Index of next filename */
+ if (k < n) { /* In range? */
+ pa = pre;
+ px = post;
+ p = s2[k]; /* Point to filename */
+ q = b + (j * width) + 1; /* and destination */
+ while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
+ if (j < cols - 1) {
+ q--;
+ *q = SP; /* Replace the space */
+ }
+ }
+ }
+ p = b + cmd_cols - 1; /* Last char in line */
+ while (*p-- == SP) ; /* Trim */
+ *(p+2) = NUL;
+ printf("%s\n",b); /* Print the line */
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) { /* Do more-prompting... */
+ rc = 0;
+ goto xfilhelp;
+ } else
+ lc = 0;
+ }
+ }
+ printf("\n"); /* Blank line at end of report */
+ goto xfilhelp;
+ } else { /* Malloc failure, no columns */
+ for (i = 0; i < n; i++) {
+ znext(filbuf);
+ if (!filbuf[0]) break;
+ printf("%s%s%s\n",pre,filbuf,post);
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) { /* Do more-prompting... */
+ rc = 0;
+ goto xfilhelp;
+ } else lc = 0;
+ }
+ }
+xfilhelp:
+ if (b) free(b);
+ for (i = 0; i < n2; i++)
+ if (s2[i]) free(s2[i]);
+ if (s2) free((char *)s2);
+ return(rc);
+ }
+}
+
+/*
+ Simpler front end for xfilhelp() with shorter arg list when no
+ file selection is needed.
+*/
+int
+filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
+ return(xfilhelp(n,pre,post,off,cmdirflg,
+ 0,NULL,NULL,NULL,NULL,
+ (CK_OFF_T)0,(CK_OFF_T)0,0,0,(char **)NULL));
+}
+
+/* C M S E T U P -- Set up command buffers */
+
+#ifdef DCMDBUF
+int
+cmsetup() {
+ if (!(cmdbuf = malloc(CMDBL + 4))) return(-1);
+ if (!(savbuf = malloc(CMDBL + 4))) return(-1);
+ savbuf[0] = '\0';
+ if (!(prevcmd = malloc(CMDBL + 4))) return(-1);
+ prevcmd[0] = '\0';
+ if (!(atmbuf = malloc(ATMBL + 4))) return(-1);
+ if (!(atxbuf = malloc(CMDBL + 4))) return(-1);
+ if (!(atybuf = malloc(ATMBL + 4))) return(-1);
+ if (!(filbuf = malloc(ATMBL + 4))) return(-1);
+ if (!(cmprom = malloc(PROMPTL + 4))) return(-1);
+ if (!(cmprxx = malloc(PROMPTL + 4))) return(-1);
+#ifdef CK_RECALL
+ cmrini(cm_recall);
+#endif /* CK_RECALL */
+ return(0);
+}
+#endif /* DCMDBUF */
+
+/* C M S E T P -- Set the program prompt. */
+
+VOID
+cmsetp(s) char *s; {
+ if (!s) s = "";
+ ckstrncpy(cmprxx,s,PROMPTL);
+ psetf = 1; /* Flag that prompt has been set. */
+}
+
+/* C M S A V P -- Save a copy of the current prompt. */
+
+VOID
+#ifdef CK_ANSIC
+cmsavp(char s[], int n)
+#else
+cmsavp(s,n) char s[]; int n;
+#endif /* CK_ANSIC */
+/* cmsavp */ {
+ if (psetf) /* But not if no prompt is set. */
+ ckstrncpy(s,cmprxx,n);
+}
+
+char *
+cmgetp() {
+ return(cmprxx);
+}
+
+int
+cmgbrk() {
+ return(brkchar);
+}
+
+int
+cmgkwflgs() {
+ return(cmkwflgs);
+}
+
+/* P R O M P T -- Issue the program prompt. */
+
+VOID
+prompt(f) xx_strp f; {
+ char *sx, *sy; int n;
+#ifdef CK_SSL
+ extern int ssl_active_flag, tls_active_flag;
+#endif /* CK_SSL */
+#ifdef OS2
+ extern int display_demo;
+
+ /* If there is a demo screen to be displayed, display it */
+ if (display_demo && xcmdsrc == 0) {
+ demoscrn(VCMD);
+ display_demo = 0;
+ }
+#endif /* OS2 */
+
+ if (psetf == 0) /* If no prompt set, set default. */
+ cmsetp(dfprom);
+
+ sx = cmprxx; /* Unevaluated copy */
+ if (f) { /* If conversion function given */
+ sy = cmprom; /* Evaluate it */
+#ifdef COMMENT
+ debug(F101,"prompt sx","",sx);
+ debug(F101,"prompt sy","",sy);
+#endif /* COMMENT */
+ n = PROMPTL;
+ if ((*f)(sx,&sy,&n) < 0) /* If evaluation failed */
+ sx = cmprxx; /* revert to unevaluated copy */
+ else if (!*cmprom) /* ditto if it came up empty */
+ sx = cmprxx;
+ else
+ sx = cmprom;
+ } else
+ ckstrncpy(cmprom,sx,PROMPTL);
+ cmprom[PROMPTL-1] = NUL;
+ if (!*sx) /* Don't print if empty */
+ return;
+
+#ifdef OSK
+ fputs(sx, stdout);
+#else
+#ifdef MAC
+ printf("%s", sx);
+#else
+#ifdef IKSD
+ if (inserver) { /* Print the prompt. */
+ ttoc(CR); /* If TELNET Server */
+ ttoc(NUL); /* must folloW CR by NUL */
+ printf("%s",sx);
+ } else
+#endif /* IKSD */
+ printf("\r%s",sx);
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ fflush(stdout); /* Now! */
+#endif /* MAC */
+#endif /* OSK */
+}
+
+#ifndef NOSPL
+VOID
+pushcmd(s) char * s; { /* For use with IF command. */
+ if (!s) s = np;
+ ckstrncpy(savbuf,s,CMDBL); /* Save the dependent clause, */
+ cmres(); /* and clear the command buffer. */
+ debug(F110, "pushcmd savbuf", savbuf, 0);
+}
+
+VOID
+pushqcmd(s) char * s; { /* For use with ELSE command. */
+ char c, * p = savbuf; /* Dest */
+ if (!s) s = np; /* Source */
+ while (*s) { /* Get first nonwhitespace char */
+ if (*s != SP)
+ break;
+ else
+ s++;
+ }
+ if (*s != '{') { /* If it's not "{" */
+ pushcmd(s); /* do regular pushcmd */
+ return;
+ }
+ while ((c = *s++)) { /* Otherwise insert quotes */
+ if (c == CMDQ)
+ *p++ = CMDQ;
+ *p++ = c;
+ }
+ cmres(); /* and clear the command buffer. */
+ debug(F110, "pushqcmd savbuf", savbuf, 0);
+}
+#endif /* NOSPL */
+
+#ifdef COMMENT
+/* no longer used... */
+VOID
+popcmd() {
+ ckstrncpy(cmdbuf,savbuf,CMDBL); /* Put back the saved material */
+ *savbuf = '\0'; /* and clear the save buffer */
+ cmres();
+}
+#endif /* COMMENT */
+
+/* C M R E S -- Reset pointers to beginning of command buffer. */
+
+VOID
+cmres() {
+ inword = 0; /* We're not in a word */
+ cc = 0; /* Character count is zero */
+
+/* Initialize pointers */
+
+ pp = cmdbuf; /* Beginning of current field */
+ bp = cmdbuf; /* Current position within buffer */
+ np = cmdbuf; /* Where to start next field */
+
+ cmfldflgs = 0;
+ cmflgs = -5; /* Parse not yet started. */
+ ungw = 0; /* Don't need to unget a word. */
+}
+
+/* C M I N I -- Clear the command and atom buffers, reset pointers. */
+
+/*
+The argument specifies who is to echo the user's typein --
+ 1 means the cmd package echoes
+ 0 somebody else (system, front end, terminal) echoes
+*/
+VOID
+cmini(d) int d; {
+#ifdef DCMDBUF
+ if (!atmbuf)
+ if (cmsetup()<0)
+ fatal("fatal error: unable to allocate command buffers");
+#endif /* DCMDBUF */
+#ifdef USE_MEMCPY
+ memset(cmdbuf,0,CMDBL);
+ memset(atmbuf,0,ATMBL);
+#else
+ for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL;
+ for (bp = atmbuf; bp < atmbuf+ATMBL; bp++) *bp = NUL;
+#endif /* USE_MEMCPY */
+
+ *atmbuf = *savbuf = *atxbuf = *atybuf = *filbuf = NUL;
+ blocklvl = 0; /* Block level is 0 */
+ linebegin = 1; /* At the beginning of a line */
+ dpx = d; /* Global copy of the echo flag */
+ debug(F101,"cmini dpx","",dpx);
+ crflag = 0; /* Reset flags */
+ qmflag = 0;
+ esflag = 0;
+#ifdef CK_RECALL
+ no_recall = 0; /* Start out with recall enabled */
+#endif /* CK_RECALL */
+ cmres(); /* Sets bp etc */
+ newcmd = 1; /* See addcmd() */
+}
+
+#ifndef NOSPL
+/*
+ The following bits are to allow the command package to call itself
+ in the middle of a parse. To do this, begin by calling cmpush, and
+ end by calling cmpop. As you can see, this is rather expensive.
+*/
+#ifdef DCMDBUF
+struct cmp {
+ int i[5]; /* stack for integers */
+ char *c[3]; /* stack for pointers */
+ char *b[8]; /* stack for buffer contents */
+};
+struct cmp *cmp = 0;
+#else
+int cmp_i[CMDDEP+1][5]; /* Stack for integers */
+char *cmp_c[CMDDEP+1][5]; /* for misc pointers */
+char *cmp_b[CMDDEP+1][7]; /* for buffer contents pointers */
+#endif /* DCMDBUF */
+
+int cmddep = -1; /* Current stack depth */
+
+int
+cmpush() { /* Save the command environment */
+ char *cp; /* Character pointer */
+
+ if (cmddep >= CMDDEP) /* Enter a new command depth */
+ return(-1);
+ cmddep++;
+ debug(F101,"&cmpush to depth","",cmddep);
+
+#ifdef DCMDBUF
+ /* allocate memory for cmp if not already done */
+ if (!cmp && !(cmp = (struct cmp *) malloc(sizeof(struct cmp)*(CMDDEP+1))))
+ fatal("cmpush: no memory for cmp");
+ cmp[cmddep].i[0] = cmflgs; /* First do the global ints */
+ cmp[cmddep].i[1] = cmfsav;
+ cmp[cmddep].i[2] = atxn;
+ cmp[cmddep].i[3] = ungw;
+
+ cmp[cmddep].c[0] = bp; /* Then the global pointers */
+ cmp[cmddep].c[1] = pp;
+ cmp[cmddep].c[2] = np;
+#else
+ cmp_i[cmddep][0] = cmflgs; /* First do the global ints */
+ cmp_i[cmddep][1] = cmfsav;
+ cmp_i[cmddep][2] = atxn;
+ cmp_i[cmddep][3] = ungw;
+
+ cmp_c[cmddep][0] = bp; /* Then the global pointers */
+ cmp_c[cmddep][1] = pp;
+ cmp_c[cmddep][2] = np;
+#endif /* DCMDBUF */
+
+ /* Now the buffers themselves. A lot of repititious code... */
+
+#ifdef DCMDBUF
+ cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
+ if (cp) strcpy(cp,cmdbuf);
+ cmp[cmddep].b[0] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
+ if (cp) strcpy(cp,savbuf);
+ cmp[cmddep].b[1] = cp;
+ if (cp == NULL) return(-1);
+
+ cmp[cmddep].b[2] = NULL;
+
+ cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
+ if (cp) strcpy(cp,atmbuf);
+ cmp[cmddep].b[3] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
+ if (cp) strcpy(cp,atxbuf);
+ cmp[cmddep].b[4] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
+ if (cp) strcpy(cp,atybuf);
+ cmp[cmddep].b[5] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
+ if (cp) strcpy(cp,filbuf);
+ cmp[cmddep].b[6] = cp;
+ if (cp == NULL) return(-1);
+#else
+ cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
+ if (cp) strcpy(cp,cmdbuf);
+ cmp_b[cmddep][0] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
+ if (cp) strcpy(cp,savbuf);
+ cmp_b[cmddep][1] = cp;
+ if (cp == NULL) return(-1);
+
+ cmp_b[cmddep][2] = NULL;
+
+ cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
+ if (cp) strcpy(cp,atmbuf);
+ cmp_b[cmddep][3] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
+ if (cp) strcpy(cp,atxbuf);
+ cmp_b[cmddep][4] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
+ if (cp) strcpy(cp,atybuf);
+ cmp_b[cmddep][5] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
+ if (cp) strcpy(cp,filbuf);
+ cmp_b[cmddep][6] = cp;
+ if (cp == NULL) return(-1);
+#endif /* DCMDBUF */
+
+ cmini(dpx); /* Initize the command parser */
+ return(0);
+}
+
+int
+cmpop() { /* Restore the command environment */
+ if (cmddep < 0) {
+ debug(F100,"&cmpop called from top level","",0);
+ return(-1); /* Don't pop too much! */
+ }
+#ifdef DCMDBUF
+ cmflgs = cmp[cmddep].i[0]; /* First do the global ints */
+ cmfsav = cmp[cmddep].i[1];
+ atxn = cmp[cmddep].i[2];
+ ungw = cmp[cmddep].i[3];
+
+ bp = cmp[cmddep].c[0]; /* Then the global pointers */
+ pp = cmp[cmddep].c[1];
+ np = cmp[cmddep].c[2];
+#else
+ cmflgs = cmp_i[cmddep][0]; /* First do the global ints */
+ cmfsav = cmp_i[cmddep][1];
+ atxn = cmp_i[cmddep][2];
+ ungw = cmp_i[cmddep][3];
+
+ bp = cmp_c[cmddep][0]; /* Then the global pointers */
+ pp = cmp_c[cmddep][1];
+ np = cmp_c[cmddep][2];
+#endif /* DCMDBUF */
+
+ /* Now the buffers themselves. */
+ /* Note: strncpy(), not ckstrncpy() -- Here we WANT the NUL padding... */
+
+#ifdef DCMDBUF
+ if (cmp[cmddep].b[0]) {
+
+ strncpy(cmdbuf,cmp[cmddep].b[0],CMDBL); /* 0: Command buffer */
+ free(cmp[cmddep].b[0]);
+ cmp[cmddep].b[0] = NULL;
+ }
+ if (cmp[cmddep].b[1]) {
+ strncpy(savbuf,cmp[cmddep].b[1],CMDBL); /* 1: Save buffer */
+ free(cmp[cmddep].b[1]);
+ cmp[cmddep].b[1] = NULL;
+ }
+ if (cmp[cmddep].b[3]) {
+ strncpy(atmbuf,cmp[cmddep].b[3],ATMBL); /* 3: Atomic buffer! */
+ free(cmp[cmddep].b[3]);
+ cmp[cmddep].b[3] = NULL;
+ }
+ if (cmp[cmddep].b[4]) {
+ strncpy(atxbuf,cmp[cmddep].b[4],ATMBL); /* 4: eXpansion buffer */
+ free(cmp[cmddep].b[4]);
+ cmp[cmddep].b[4] = NULL;
+ }
+ if (cmp[cmddep].b[5]) {
+ strncpy(atybuf,cmp[cmddep].b[5],ATMBL); /* 5: Atom buffer copY */
+ free(cmp[cmddep].b[5]);
+ cmp[cmddep].b[5] = NULL;
+ }
+ if (cmp[cmddep].b[6]) {
+ strncpy(filbuf,cmp[cmddep].b[6],ATMBL); /* 6: Filename buffer */
+ free(cmp[cmddep].b[6]);
+ cmp[cmddep].b[6] = NULL;
+ }
+#else
+ if (cmp_b[cmddep][0]) {
+ strncpy(cmdbuf,cmp_b[cmddep][0],CMDBL); /* 0: Command buffer */
+ free(cmp_b[cmddep][0]);
+ cmp_b[cmddep][0] = NULL;
+ }
+ if (cmp_b[cmddep][1]) {
+ strncpy(savbuf,cmp_b[cmddep][1],CMDBL); /* 1: Save buffer */
+ free(cmp_b[cmddep][1]);
+ cmp_b[cmddep][1] = NULL;
+ }
+ if (cmp_b[cmddep][3]) {
+ strncpy(atmbuf,cmp_b[cmddep][3],ATMBL); /* 3: Atomic buffer! */
+ free(cmp_b[cmddep][3]);
+ cmp_b[cmddep][3] = NULL;
+ }
+ if (cmp_b[cmddep][4]) {
+ strncpy(atxbuf,cmp_b[cmddep][4],ATMBL); /* 4: eXpansion buffer */
+ free(cmp_b[cmddep][4]);
+ cmp_b[cmddep][4] = NULL;
+ }
+ if (cmp_b[cmddep][5]) {
+ strncpy(atybuf,cmp_b[cmddep][5],ATMBL); /* 5: Atom buffer copY */
+ free(cmp_b[cmddep][5]);
+ cmp_b[cmddep][5] = NULL;
+ }
+ if (cmp_b[cmddep][6]) {
+ strncpy(filbuf,cmp_b[cmddep][6],ATMBL); /* 6: Filename buffer */
+ free(cmp_b[cmddep][6]);
+ cmp_b[cmddep][6] = NULL;
+ }
+#endif /* DCMDBUF */
+
+ cmddep--; /* Rise, rise */
+ debug(F101,"&cmpop to depth","",cmddep);
+ return(cmddep);
+}
+#endif /* NOSPL */
+
+#ifdef COMMENT
+VOID /* Not used */
+stripq(s) char *s; { /* Function to strip '\' quotes */
+ char *t;
+ while (*s) {
+ if (*s == CMDQ) {
+ for (t = s; *t != '\0'; t++) *t = *(t+1);
+ }
+ s++;
+ }
+}
+#endif /* COMMENT */
+
+/* Convert tabs to spaces, one for one */
+VOID
+untab(s) char *s; {
+ while (*s) {
+ if (*s == HT) *s = SP;
+ s++;
+ }
+}
+
+/* C M N U M -- Parse a number in the indicated radix */
+
+/*
+ The radix is specified in the arg list.
+ Parses unquoted numeric strings in the given radix.
+ Parses backslash-quoted numbers in the radix indicated by the quote:
+ \nnn = \dnnn = decimal, \onnn = octal, \xnn = Hexadecimal.
+ If these fail, then if a preprocessing function is supplied, that is applied
+ and then a second attempt is made to parse an unquoted decimal string.
+ And if that fails, the preprocessed string is passed to an arithmetic
+ expression evaluator.
+
+ Returns:
+ -3 if no input present when required,
+ -2 if user typed an illegal number,
+ -1 if reparse needed,
+ 0 otherwise, with argument n set to the number that was parsed
+*/
+/* This is the traditional cmnum() that gets an int */
+int
+cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
+ CK_OFF_T z = (CK_OFF_T)0, check;
+ int x;
+ x = cmnumw(xhlp,xdef,radix,&z,f);
+ *n = z;
+ check = *n;
+ if (check != z) {
+ printf("?Magnitude of result too large for integer - %s\n",ckfstoa(z));
+ return(-9);
+ }
+ return(x);
+}
+
+/*
+ This is the new cmnum() that gets a "wide" result, whatever CK_OFF_T
+ is defined to be, normally 32 or 64 bits, depending on the platform.
+ fdc, 24 Dec 2005.
+*/
+int
+cmnumw(xhlp,xdef,radix,n,f)
+ char *xhlp, *xdef; int radix; CK_OFF_T *n; xx_strp f; {
+ int x; char *s, *zp, *zq;
+#ifdef COMMENT
+ char lbrace, rbrace;
+#endif /* COMMENT */
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+#ifdef COMMENT
+ if (cmfldflgs & 1) {
+ lbrace = '(';
+ rbrace = ')';
+ } else {
+ lbrace = '{';
+ rbrace = '}';
+ }
+#endif /* COMMENT */
+
+ if (radix != 10 && radix != 8) { /* Just do bases 8 and 10 */
+ printf("cmnum: illegal radix - %d\n",radix);
+ return(-2);
+ } /* Easy to add others but there has never been a need for it. */
+ x = cmfld(xhlp,xdef,&s,(xx_strp)0);
+ debug(F101,"cmnum: cmfld","",x);
+ if (x < 0) return(x); /* Parse a field */
+ zp = atmbuf;
+/*
+ Edit 192 - Allow any number field to be braced. This lets us include
+ spaces in expressions, but perhaps more important lets us have user-defined
+ functions in numeric fields.
+*/
+ zp = brstrip(zp); /* Strip braces */
+ if (cmfldflgs & 1 && *zp == '(') { /* Parens too.. */
+ x = (int) strlen(atmbuf);
+ if (x > 0) {
+ if (*(atmbuf+x-1) == ')') {
+ *(atmbuf+x-1) = NUL;
+ zp++;
+ }
+ }
+ }
+ if (chknum(zp)) { /* Check for number */
+ if (radix == 8) { /* If it's supposed to be octal */
+ zp = ckradix(zp,8,10); /* convert to decimal */
+ if (!zp) return(-2);
+ if (!strcmp(zp,"-1")) return(-2);
+ }
+ errno = 0; /* Got one, we're done. */
+ *n = ckatofs(zp);
+ if (errno) {
+ perror(zp);
+ return(-9);
+ }
+ debug(F101,"cmnum 1st chknum ok","",*n);
+ return(0);
+ } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
+
+#ifndef OS2
+ *n = x;
+#else
+ *n = wideresult;
+#endif /* OS2 */
+
+ debug(F101,"cmnum xxesc ok","",*n);
+ return(*zp ? -2 : 0);
+ } else if (f) { /* If conversion function given */
+ zq = atxbuf; /* Try that */
+ atxn = CMDBL;
+ if ((*f)(zp,&zq,&atxn) < 0) /* Convert */
+ return(-2);
+ zp = atxbuf;
+ }
+ debug(F110,"cmnum zp 1",zp,0);
+ if (!*zp) zp = xdef; /* Result empty, substitute default */
+ debug(F110,"cmnum zp 2",zp,0);
+ if (chknum(zp)) { /* Check again for decimal number */
+ if (radix == 8) { /* If it's supposed to be octal */
+ zp = ckradix(zp,8,10); /* convert to decimal */
+ if (!zp) return(-2);
+ if (!strcmp(zp,"-1")) return(-2);
+ }
+ errno = 0;
+ *n = ckatofs(zp);
+ if (errno) {
+ perror(zp);
+ return(-9);
+ }
+ debug(F101,"cmnum 2nd chknum ok","",*n);
+ return(0);
+#ifndef NOSPL
+ } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
+#ifndef OS2
+ *n = x;
+#else
+ *n = wideresult;
+#endif /* OS2 */
+ debug(F101,"cmnum xxesc 2 ok","",*n);
+ return(*zp ? -2 : 0);
+ } else if (f) { /* Not numeric, maybe an expression */
+ char * p;
+ p = evala(zp);
+ if (chknum(p)) {
+ if (radix == 8) { /* If it's supposed to be octal */
+ zp = ckradix(zp,8,10); /* convert to decimal */
+ if (!zp) return(-2);
+ if (!strcmp(zp,"-1")) return(-2);
+ }
+ errno = 0;
+ *n = ckatofs(p);
+ if (errno) {
+ perror(p);
+ return(-9);
+ }
+ debug(F101,"cmnum exp eval ok","",*n);
+ return(0);
+ } else return(-2);
+#endif /* NOSPL */
+ } else { /* Not numeric */
+ return(-2);
+ }
+}
+
+#ifdef CKCHANNELIO
+extern int z_error;
+#endif /* CKCHANNELIO */
+
+/* C M O F I -- Parse the name of an output file */
+
+/*
+ Depends on the external function zchko(); if zchko() not available, use
+ cmfld() to parse output file names.
+
+ Returns:
+ -9 like -2, except message already printed,
+ -3 if no input present when required,
+ -2 if permission would be denied to create the file,
+ -1 if reparse needed,
+ 0 or 1 if file can be created, with xp pointing to name.
+ 2 if given the name of an existing directory.
+*/
+int
+cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+ int x; char *s, *zq;
+#ifdef DOCHKVAR
+ int tries;
+#endif /* DOCHKVAR */
+#ifdef DTILDE
+ char *dirp;
+#endif /* DTILDE */
+
+ cmfldflgs = 0;
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+ if (*xhlp == NUL) xhlp = "Output file";
+ *xp = "";
+
+ debug(F110,"cmofi xdef",xdef,0);
+ x = cmfld(xhlp,xdef,&s,(xx_strp)0);
+ debug(F111,"cmofi cmfld returns",s,x);
+ if (x < 0)
+ return(x);
+
+ s = brstrip(s); /* Strip enclosing braces */
+ debug(F110,"cmofi 1.5",s,0);
+
+#ifdef DOCHKVAR
+ tries = 0;
+ {
+ char *p = s;
+ /*
+ This is really ugly. If we skip conversion the first time through,
+ then variable names like \%a will be used as filenames (e.g. creating
+ a file called %A in the root directory). If we DON'T skip conversion
+ the first time through, then single backslashes used as directory
+ separators in filenames will be misinterpreted as variable lead-ins.
+ So we prescan to see if it has any variable references. But this
+ module is not supposed to know anything about variables, functions,
+ etc, so this code does not really belong here, but rather it should
+ be at the same level as zzstring().
+ */
+/*
+ Hmmm, this looks a lot like chkvar() except it that includes \nnn number
+ escapes. But why? This makes commands like "mkdir c:\123" impossible.
+ And in fact, "mkdir c:\123" creates a directory called "c:{". What's worse,
+ rmdir(), which *does* call chkvar(), won't let us remove it. So let's at
+ least try making cmofi() symmetrical with cmifi()...
+*/
+#ifdef COMMENT
+ char * q;
+ while ( (tries == 0) && (p = strchr(p,CMDQ)) ) {
+ q = *(p+1); /* Char after backslash */
+ if (!q) /* None, quit */
+ break;
+ if (isupper(q)) /* If letter, convert to lowercase */
+ q = tolower(q);
+ if (isdigit(q)) { /* If it's a digit, */
+ tries = 1; /* assume it's a backslash code */
+ break;
+ }
+ switch (q) {
+ case CMDQ: /* Double backslash */
+ tries = 1; /* so call the conversion function */
+ break;
+ case '%': /* Variable or array reference */
+ case '&': /* must be followed by letter */
+ if (isalpha(*(p+2)) || (*(p+2) >= '0' && *(p+2) <= '9'))
+ tries = 1;
+ break;
+ case 'm': case 'v': case '$': /* \m(), \v(), \$() */
+ if (*(p+2) == '(')
+ if (strchr(p+2,')'))
+ tries = 1;
+ break;
+ case 'f': /* \Fname() */
+ if (strchr(p+2,'('))
+ if (strchr(p+2,')'))
+ tries = 1;
+ break;
+ case '{': /* \{...} */
+ if (strchr(p+2,'}'))
+ tries = 1;
+ break;
+ case 'd': case 'o': /* Decimal or Octal number */
+ if (isdigit(*(p+2)))
+ tries = 1;
+ break;
+ case 'x': /* Hex number */
+ if (isdigit(*(p+2)) ||
+ ((*(p+2) >= 'a' && *(p+2) <= 'f') ||
+ ((*(p+2) >= 'A' && *(p+2) <= 'F'))))
+ tries = 1;
+ default:
+ break;
+ }
+ p++;
+ }
+#else
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+ char *s = p; /* See if there are any variables in */
+ while (*s) { /* the string and if so, expand them */
+ if (chkvar(s)) {
+ tries = 1;
+ break;
+ }
+ s++;
+ }
+ }
+#endif /* NOSPL */
+#endif /* COMMENT */
+ }
+#ifdef OS2
+o_again:
+#endif /* OS2 */
+ if (tries == 1)
+#endif /* DOCHKVAR */
+ if (f) { /* If a conversion function is given */
+ zq = atxbuf; /* do the conversion. */
+ atxn = CMDBL;
+ if ((x = (*f)(s,&zq,&atxn)) < 0)
+ return(-2);
+ s = atxbuf;
+ if (!*s) /* Result empty, substitute default */
+ s = xdef;
+ }
+ debug(F111,"cmofi 2",s,x);
+
+#ifdef DTILDE
+ dirp = tilde_expand(s); /* Expand tilde, if any, */
+ if (*dirp != '\0') { /* right in the atom buffer. */
+ if (setatm(dirp,1) < 0) {
+ printf("?Name too long\n");
+ return(-9);
+ }
+ }
+ s = atmbuf;
+ debug(F110,"cmofi 3",s,0);
+#endif /* DTILDE */
+
+ if (iswild(s)) {
+ printf("?Wildcards not allowed - %s\n",s);
+ return(-2);
+ }
+ debug(F110,"cmofi 4",s,0);
+
+#ifdef CK_TMPDIR
+ /* isdir() function required for this! */
+ if (isdir(s)) {
+ debug(F110,"cmofi 5: is directory",s,0);
+ *xp = s;
+ return(2);
+ }
+#endif /* CK_TMPDIR */
+
+ if (strcmp(s,CTTNAM) && (zchko(s) < 0)) { /* OK to write to console */
+#ifdef COMMENT
+#ifdef OS2
+/*
+ We don't try again because we already prescanned the string to see if
+ if it contained anything that could be used by zzstring().
+*/
+ if (tries++ < 1)
+ goto o_again;
+#endif /* OS2 */
+#endif /* COMMENT */
+/*
+ Note: there are certain circumstances where zchko() can give a false
+ positive, so don't rely on it to catch every conceivable situation in
+ which the given output file can't be created. In other words, we print
+ a message and fail here if we KNOW the file can't be created. If we
+ succeed but the file can't be opened, the code that tries to open the file
+ has to print a message.
+*/
+ debug(F110,"cmofi 6: failure",s,0);
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",s);
+ else
+#endif /* CKROOT */
+ printf("?Write permission denied - %s\n",s);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(-9);
+ } else {
+ debug(F110,"cmofi 7: ok",s,0);
+ *xp = s;
+ return(x);
+ }
+}
+
+/* C M I F I -- Parse the name of an existing file */
+
+/*
+ This function depends on the external functions:
+ zchki() - Check if input file exists and is readable.
+ zxpand() - Expand a wild file specification into a list.
+ znext() - Return next file name from list.
+ If these functions aren't available, then use cmfld() to parse filenames.
+*/
+/*
+ Returns
+ -4 EOF
+ -3 if no input present when required,
+ -2 if file does not exist or is not readable,
+ -1 if reparse needed,
+ 0 or 1 otherwise, with:
+ xp pointing to name,
+ wild = 1 if name contains '*' or '?', 0 otherwise.
+*/
+
+#ifdef COMMENT /* This horrible hack has been replaced - see further down */
+/*
+ C M I O F I -- Parse an input file OR the name of a nonexistent file.
+
+ Use this when an existing file is wanted (so we get help, completion, etc),
+ but if a file of the given name does not exist, the name of a new file is
+ accepted. For example, with the EDIT command (edit an existing file, or
+ create a new file). Returns -9 if file does not exist. It is up to the
+ caller to check creatability.
+*/
+static int nomsg = 0;
+int
+cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+ int msgsave, x;
+ msgsave = nomsg;
+ nomsg = 1;
+ x = cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0);
+ nomsg = msgsave;
+ return(x);
+}
+#endif /* COMMENT */
+
+int
+cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+ return(cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0));
+}
+/*
+ cmifip() is called when we want to supply a path or path list to search
+ in case the filename that the user gives is (a) not absolute, and (b) can't
+ be found as given. The path string can be the name of a single directory,
+ or a list of directories separated by the PATHSEP character, defined in
+ ckucmd.h. Look in ckuusr.c and ckuus3.c for examples of usage.
+*/
+int
+cmifip(xhlp,xdef,xp,wild,d,path,f)
+ char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; {
+ return(cmifi2(xhlp,xdef,xp,wild,0,path,f,0));
+}
+
+/* C M D I R -- Parse a directory name */
+
+/*
+ This function depends on the external functions:
+ isdir(s) - Check if string s is the name of a directory
+ zchki(s) - Check if input file s exists and what type it is.
+ If these functions aren't available, then use cmfld() to parse dir names.
+
+ Returns
+ -9 For all sorts of reasons, after printing appropriate error message.
+ -4 EOF
+ -3 if no input present when required,
+ -2 if out of space or other internal error,
+ -1 if reparse needed,
+ 0 or 1, with xp pointing to name, if directory specified,
+*/
+int
+cmdir(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+ int wild;
+ return(cmifi2(xhlp,xdef,xp,&wild,0,NULL,f,1));
+}
+
+/* Like CMDIR but includes PATH search */
+
+int
+cmdirp(xhlp,xdef,xp,path,f) char *xhlp, *xdef, **xp; char * path; xx_strp f; {
+ int wild;
+ return(cmifi2(xhlp,xdef,xp,&wild,0,path,f,1));
+}
+
+/*
+ cmifi2() is the base filename parser called by cmifi, cmifip, cmdir, etc.
+ Use it directly when you also want to parse a directory or device
+ name as an input file, as in the DIRECTORY command. Call with:
+ xhlp -- help message on ?
+ xdef -- default response
+ xp -- pointer to result (in our space, must be copied from here)
+ wild -- flag set upon return to indicate if filespec was wild
+ d -- 0 to parse files, 1 to parse files or directories
+ Add 2 to inhibit following of symlinks.
+ path -- search path for files
+ f -- pointer to string processing function (e.g. to evaluate variables)
+ dirflg -- 1 to parse *only* directories, 0 otherwise
+*/
+int
+cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
+ char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; int dirflg; {
+ extern int recursive, diractive, cdactive, dblquo;
+ int i, x, itsadir, xc, expanded = 0, nfiles = 0, children = -1;
+ int qflag = 0;
+ long y;
+ CK_OFF_T filesize;
+ char *sp = NULL, *zq, *np = NULL;
+ char *sv = NULL, *p = NULL;
+#ifdef DTILDE
+ char *dirp;
+#endif /* DTILDE */
+
+#ifndef NOPARTIAL
+#ifndef OS2
+#ifdef OSK
+ /* This large array is dynamic for OS-9 -- should do for others too... */
+ extern char **mtchs;
+#else
+#ifdef UNIX
+ /* OK, for UNIX too */
+ extern char **mtchs;
+#else
+#ifdef VMS
+ extern char **mtchs;
+#else
+ extern char *mtchs[];
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* NOPARTIAL */
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+#ifndef NOLASTFILE
+ makestr(&tmplastfile,NULL);
+#endif /* NOLASTFILE */
+ nzxopts = 0; /* zxpand() options */
+ debug(F101,"cmifi d","",d);
+ if (d & 2) { /* d & 2 means don't follow symlinks */
+ d ^= 2;
+ nzxopts = ZX_NOLINKS;
+ }
+ debug(F101,"cmifi nzxopts","",nzxopts);
+ cmfldflgs = 0;
+ if (path)
+ if (!*path)
+ path = NULL;
+ if (path) { /* Make a copy we can poke */
+ x = strlen(path);
+ np = (char *) malloc(x + 1);
+ if (np) {
+ strcpy(np, path);
+ path = sp = np;
+ }
+ }
+ debug(F110,"cmifi2 path",path,0);
+
+ ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
+ xdef = cmdefault;
+
+ inword = 0; /* Initialize counts & pointers */
+ cc = 0;
+ xc = 0;
+ *xp = ""; /* Pointer to result string */
+ if ((x = cmflgs) != 1) { /* Already confirmed? */
+#ifdef BS_DIRSEP
+ dirnamflg = 1;
+ x = gtword(0); /* No, get a word */
+ dirnamflg = 0;
+#else
+ x = gtword(0); /* No, get a word */
+#endif /* BS_DIRSEP */
+ } else { /* If so, use default, if any. */
+ if (setatm(xdef,1) < 0) {
+ printf("?Default name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ }
+ i_path:
+ *xp = atmbuf; /* Point to result. */
+
+ while (1) {
+ xc += cc; /* Count this character. */
+ debug(F111,"cmifi gtword",atmbuf,xc);
+ debug(F101,"cmifi switch x","",x);
+ switch (x) { /* x = gtword() return code */
+ case -10:
+ if (gtimer() > timelimit) {
+#ifdef IKSD
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit);
+ doexit(GOOD_EXIT,0);
+ }
+#endif /* IKSD */
+ /* if (!quiet) printf("?Timed out\n"); */
+ return(-10);
+ } else {
+ x = gtword(0);
+ continue;
+ }
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -2: /* Out of space. */
+ case -1: /* Reparse needed */
+ if (np) free(np);
+ return(x);
+ case 1: /* CR */
+ case 0: /* SP */
+ if (xc == 0) /* If no input... */
+ *xp = xdef; /* substitute the default */
+#ifndef NOLASTFILE
+ makestr(&tmplastfile,*xp); /* Make a copy before bstripping */
+#endif /* #ifndef NOLASTFILE */
+ *xp = brstrip(*xp); /* Strip braces */
+ if (**xp == NUL) { /* 12 mar 2001 */
+ if (np) free(np);
+ return(-3);
+ }
+ debug(F110,"cmifi brstrip",*xp,0);
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+#ifdef DOCHKVAR
+ char *s = *xp; /* See if there are any variables in */
+ int x;
+ while (*s) { /* the string and if so, expand them */
+ x = chkvar(s);
+ /* debug(F111,"cmifi chkvar",*xp,x); */
+ if (x) {
+#endif /* DOCHKVAR */
+ zq = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(*xp,&zq,&atxn) < 0) {
+ if (np) free(np);
+ return(-2);
+ }
+ *xp = atxbuf;
+ if (!atxbuf[0])
+ *xp = xdef;
+#ifdef DOCHKVAR
+ break;
+ }
+ s++;
+ }
+#endif /* DOCHKVAR */
+ }
+#endif /* NOSPL */
+ if (**xp == NUL) { /* 12 mar 2001 */
+ if (np) free(np);
+ return(-3);
+ }
+#ifdef DTILDE
+ if (dirflg) {
+ dirp = tilde_expand(*xp); /* Expand tilde, if any, */
+ if (*dirp != '\0') { /* in the atom buffer. */
+ if (setatm(dirp,1) < 0) {
+ printf("Expanded name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ }
+ *xp = atmbuf;
+ debug(F110,"cmifi tilde_expand",*xp,0);
+ }
+#endif /* DTILDE */
+ if (!sv) { /* Only do this once */
+ sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */
+ if (!sv) {
+ printf("?cmifi: malloc error\n");
+ if (np) free(np);
+ return(-9);
+ }
+ strcpy(sv,*xp);
+ debug(F110,"cmifi sv",sv,0);
+ }
+
+/* This is to get around "cd /" failing because "too many directories match" */
+
+ expanded = 0; /* Didn't call zxpand */
+#ifdef datageneral
+ debug(F110,"cmifi isdir 1",*xp,0);
+ {
+ int y; char *s;
+ s = *xp;
+ y = strlen(s);
+ if (y > 1 &&
+ (s[y-1] == ':' ||
+ s[y-1] == '^' ||
+ s[y-1] == '=')
+ )
+ s[y-1] = NUL;
+ }
+ debug(F110,"cmifi isdir 2",*xp,0);
+#endif /* datageneral */
+
+#ifdef VMS
+ if (dirflg) {
+ if (!strcmp(*xp,"..")) { /* For UNIXers... */
+ setatm("-",0);
+ *xp = atmbuf;
+ } else if (!strcmp(*xp,".")) {
+ setatm("[]",0);
+ *xp = atmbuf;
+ }
+ }
+#endif /* VMS */
+ itsadir = isdir(*xp); /* Is it a directory? */
+ debug(F111,"cmifi itsadir",*xp,itsadir);
+#ifdef VMS
+ /* If they said "blah" where "blah.dir" is a directory... */
+ /* change it to [.blah]. */
+ if (!itsadir) {
+ char tmpbuf[600];
+ int flag = 0; char c, * p;
+ p = *xp;
+ while ((c = *p++) && !flag)
+ if (ckstrchr(".[]:*?<>",c))
+ flag = 1;
+ debug(F111,"cmifi VMS dirname flag",*xp,flag);
+ if (!flag) {
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"[.",*xp,"]",NULL);
+ itsadir = isdir(tmpbuf);
+ if (itsadir) {
+ setatm(tmpbuf,0);
+ *xp = atmbuf;
+ }
+ debug(F111,"cmifi VMS dirname flag itsadir",*xp,itsadir);
+ }
+ } else if (itsadir == 1 && *(xp[0]) == '.' && *(xp[1])) {
+ char *p;
+ if (p = malloc(cc + 4)) {
+ ckmakmsg(p,cc+4,"[",*xp,"]",NULL);
+ setatm(p,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir .foo",*xp,0);
+ free(p);
+ }
+ } else if (itsadir == 2 && !diractive) {
+ int x; /* [FOO]BAR.DIR instead of [FOO.BAR] */
+ char *p;
+ p = malloc(cc + 4);
+ if (p) {
+ x = cvtdir(*xp,p,ATMBL); /* Convert to [FOO.BAR] */
+ if (x > 0) {
+ setatm(p,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir cvtdir",*xp,0);
+ }
+ free(p);
+ }
+ }
+#endif /* VMS */
+
+ debug(F101,"cmifi dirflg","",dirflg);
+ if (dirflg) { /* Parsing a directory name? */
+ /* Yes, does it contain wildcards? */
+ if (iswild(*xp) ||
+ (diractive && (!strcmp(*xp,".") || !strcmp(*xp,"..")))
+ ) {
+ nzxopts |= ZX_DIRONLY; /* Match only directory names */
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ debug(F111,"cmifi nzxopts 2",*xp,nzxopts);
+ y = nzxpand(*xp,nzxopts);
+ debug(F111,"cmifi nzxpand 2",*xp,y);
+ nfiles = y;
+ expanded = 1;
+ } else {
+#ifdef VMS
+/*
+ This is to allow (e.g.) "cd foo", where FOO.DIR;1 is in the
+ current directory.
+*/
+ debug(F111,"cmdir itsadir",*xp,itsadir);
+ if (!itsadir) {
+ char *s;
+ int n;
+ s = *xp;
+ n = strlen(s);
+ if (n > 0 &&
+#ifdef COMMENT
+ *s != '[' && s[n-1] != ']' &&
+ *s != '<' && s[n-1] != '>' &&
+#else
+ ckindex("[",s,0,0,1) == 0 &&
+ ckindex("<",s,0,0,1) == 0 &&
+#endif /* COMMENT */
+ s[n-1] != ':') {
+ char * dirbuf = NULL;
+ dirbuf = (char *)malloc(n+4);
+ if (dirbuf) {
+ if (*s == '.')
+ ckmakmsg(dirbuf,n+4,"[",s,"]",NULL);
+ else
+ ckmakmsg(dirbuf,n+4,"[.",s,"]",NULL);
+ itsadir = isdir(dirbuf);
+ debug(F111,"cmdir dirbuf",dirbuf,itsadir);
+ if (itsadir) {
+ setatm(dirbuf,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir new *xp",*xp,0);
+ }
+ free(dirbuf);
+ }
+
+/* This is to allow CDPATH to work in VMS... */
+
+ } else if (n > 0) {
+ char * p; int i, j, k, d;
+ char rb[2] = "]";
+ if (p = malloc(x + 8)) {
+ ckstrncpy(p,*xp,x+8);
+ i = ckindex(".",p,-1,1,1);
+ d = ckindex(".dir",p,0,0,0);
+ j = ckindex("]",p,-1,1,1);
+ if (j == 0) {
+ j = ckindex(">",p,-1,1,1);
+ rb[0] = '>';
+ }
+ k = ckindex(":",p,-1,1,1);
+ if (i < j || i < k) i = 0;
+ if (d < j || d < k) d = 0;
+ /* Change [FOO]BAR or [FOO]BAR.DIR */
+ /* to [FOO.BAR] */
+ if (j > 0 && j < n) {
+ p[j-1] = '.';
+ if (d > 0) p[d-1] = NUL;
+ ckstrncat(p,rb,x+8);
+ debug(F110,"cmdir xxx",p,0);
+ }
+ itsadir = isdir(p);
+ debug(F111,"cmdir p",p,itsadir);
+ if (itsadir) {
+ setatm(p,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir new *xp",*xp,0);
+ }
+ free(p);
+ }
+ }
+ }
+#endif /* VMS */
+ y = (!itsadir) ? 0 : 1;
+ debug(F111,"cmifi y itsadir",*xp,y);
+ }
+ } else { /* Parsing a filename. */
+ debug(F110,"cmifi *xp pre-zxpand",*xp,0);
+#ifndef COMMENT
+ nzxopts |= (d == 0) ? ZX_FILONLY : 0; /* So always expand. */
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+#else
+/* Here we're trying to fix a problem in which a directory name is accepted */
+/* as a filename, but this breaks too many other things. */
+ /* nzxopts = 0; */
+ if (!d) {
+ if (itsadir & !iswild(*xp)) {
+ debug(F100,"cmifi dir when filonly","",0);
+ printf("?Not a regular file: \"%s\"\n",*xp);
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ } else {
+ nzxopts |= ZX_FILONLY;
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ }
+ }
+#endif /* COMMENT */
+ nfiles = y;
+ debug(F111,"cmifi y nzxpand",*xp,y);
+ debug(F111,"cmifi y atmbuf",atmbuf,itsadir);
+ expanded = 1;
+ }
+ /* domydir() calls zxrewind() so we MUST call nzxpand() here */
+ if (!expanded && diractive) {
+ debug(F110,"cmifi diractive catch-all zxpand",*xp,0);
+ nzxopts |= (d == 0) ? ZX_FILONLY : (dirflg ? ZX_DIRONLY : 0);
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ debug(F111,"cmifi diractive nzxpand",*xp,y);
+ nfiles = y;
+ expanded = 1;
+ }
+ *wild = (iswild(sv) || (y > 1)) && (itsadir == 0);
+
+#ifdef RECURSIVE
+ if (!*wild) *wild = recursive;
+#endif /* RECURSIVE */
+
+ debug(F111,"cmifi sv wild",sv,*wild);
+ debug(F101,"cmifi y","",y);
+ if (dirflg && *wild && cdactive) {
+ if (y > 1) {
+ printf("?Wildcard matches more than one directory\n");
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ } else {
+ znext(*xp);
+ }
+ }
+ if (itsadir && d && !dirflg) { /* It's a directory and not wild */
+ if (sv) free(sv); /* and it's ok to parse directories */
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(x);
+ }
+ if (y == 0) { /* File was not found */
+ int dosearch = 0;
+ dosearch = (path != NULL); /* A search path was given */
+ if (dosearch) {
+ dosearch = hasnopath(sv); /* Filename includes no path */
+ debug(F111,"cmifip hasnopath",sv,dosearch);
+ }
+ if (dosearch) { /* Search the path... */
+ char * ptr = path;
+ char c;
+ while (1) {
+ c = *ptr;
+ if (c == PATHSEP || c == NUL) {
+ if (!*path) {
+ path = NULL;
+ break;
+ }
+ *ptr = NUL;
+#ifdef UNIX
+/* By definition of CDPATH, an empty member denotes the current directory */
+ if (!*path)
+ ckstrncpy(atmbuf,".",ATMBL);
+ else
+#endif /* UNIX */
+ ckstrncpy(atmbuf,path,ATMBL);
+#ifdef VMS
+ atmbuf[ATMBL] = NUL;
+/* If we have a logical name, evaluate it recursively */
+ if (*(ptr-1) == ':') { /* Logical name ends in : */
+ char *p; int n;
+ while (((n = strlen(atmbuf)) > 0) &&
+ atmbuf[n-1] == ':') {
+ atmbuf[n-1] = NUL;
+ for (p = atmbuf; *p; p++)
+ if (islower(*p)) *p = toupper(*p);
+ debug(F111,"cmdir CDPATH LN 1",atmbuf,n);
+ p = getenv(atmbuf);
+ debug(F110,"cmdir CDPATH LN 2",p,0);
+ if (!p)
+ break;
+ strncpy(atmbuf,p,ATMBL);
+ atmbuf[ATMBL] = NUL;
+ }
+ }
+#else
+#ifdef OS2
+ if (*(ptr-1) != '\\' && *(ptr-1) != '/')
+ ckstrncat(atmbuf,"\\",ATMBL);
+#else
+#ifdef UNIX
+ if (*(ptr-1) != '/')
+ ckstrncat(atmbuf,"/",ATMBL);
+#else
+#ifdef datageneral
+ if (*(ptr-1) != ':')
+ ckstrncat(atmbuf,":",ATMBL);
+#endif /* datageneral */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* VMS */
+ ckstrncat(atmbuf,sv,ATMBL);
+ debug(F110,"cmifip add path",atmbuf,0);
+ if (c == PATHSEP) ptr++;
+ path = ptr;
+ break;
+ }
+ ptr++;
+ }
+ x = 1;
+ inword = 0;
+ cc = 0;
+ xc = (int) strlen(atmbuf);
+ *xp = "";
+ goto i_path;
+ }
+ if (d) {
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-2);
+ } else {
+ if (!nomsg) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",sv);
+ else
+#endif /* CKROOT */
+ if (!quiet)
+ printf("?No %s match - %s\n",
+ dirflg ? "directories" : "files", sv);
+ }
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ }
+ } else if (y < 0) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",sv);
+ else
+#endif /* CKROOT */
+ printf("?Too many %s match - %s\n",
+ dirflg ? "directories" : "files", sv);
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ } else if (*wild || y > 1) {
+ if (sv) free(sv);
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(x);
+ }
+
+ /* If not wild, see if it exists and is readable. */
+
+ debug(F111,"cmifi sv not wild",sv,*wild);
+ if (expanded)
+ znext(*xp); /* Get first (only?) matching file */
+ if (dirflg) /* Maybe wild and expanded */
+ itsadir = isdir(*xp); /* so do this again. */
+ filesize = dirflg ? itsadir : zchki(*xp); /* Check accessibility */
+ if (expanded) {
+#ifdef ZXREWIND
+ nfiles = zxrewind(); /* Rewind so next znext() gets 1st */
+#else
+
+ nzxopts |= dirflg ? ZX_DIRONLY : 0;
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ nfiles = nzxpand(*xp,nzxopts);
+#endif /* ZXREWIND */
+ }
+ debug(F111,"cmifi nfiles",*xp,nfiles);
+ debug(F101,"cmifi filesize","",filesize);
+ free(sv); /* done with this */
+ sv = NULL;
+ if (dirflg && !filesize) {
+ printf("?Not a directory - %s\n",*xp);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(-9);
+ } else if (filesize == (CK_OFF_T)-3) {
+ if (!xcmfdb) {
+ if (diractive)
+ /* Don't show filename if we're not allowed to see it */
+ printf("?Read permission denied\n");
+ else
+ printf("?Read permission denied - %s\n",*xp);
+ }
+ if (np) free(np);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(xcmfdb ? -6 : -9);
+ } else if (filesize == (CK_OFF_T)-2) {
+ if (!recursive) {
+ if (np) free(np);
+ if (d) {
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(0);
+ }
+ if (!xcmfdb)
+ printf("?File not readable - %s\n",*xp);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(xcmfdb ? -6 : -9);
+ }
+ } else if (filesize < (CK_OFF_T)0) {
+ if (np) free(np);
+ if (!nomsg && !xcmfdb)
+ printf("?File not found - %s\n",*xp);
+#ifdef CKCHANNELIO
+ z_error = FX_FNF;
+#endif /* CKCHANNELIO */
+ return(xcmfdb ? -6 : -9);
+ }
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(x);
+
+#ifndef MAC
+ case 2: /* ESC */
+ debug(F101,"cmifi esc, xc","",xc);
+ if (xc == 0) {
+ if (*xdef) {
+ printf("%s ",xdef); /* If at beginning of field */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ inword = cmflgs = 0;
+ addbuf(xdef); /* Supply default. */
+ if (setatm(xdef,0) < 0) {
+ printf("Default name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ } else { /* No default */
+ bleep(BP_WARN);
+ }
+ break;
+ }
+ if (**xp == '{') { /* Did user type opening brace... */
+ *xp = *xp + 1;
+ xc--;
+ cc--;
+ qflag = '}';
+ } else if (dblquo && **xp == '"') { /* or doublequote? */
+ *xp = *xp + 1; /* If so ignore it and space past it */
+ xc--;
+ cc--;
+ qflag = '"';
+ }
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+#ifdef DOCHKVAR
+ char *s = *xp; /* See if there are any variables in */
+ while (*s) { /* the string and if so, expand it. */
+ if (chkvar(s)) {
+#endif /* DOCHKVAR */
+ zq = atxbuf;
+ atxn = CMDBL;
+ if ((x = (*f)(*xp,&zq,&atxn)) < 0) {
+ if (np) free(np);
+ return(-2);
+ }
+#ifdef DOCHKVAR
+ /* reduce cc by number of \\ consumed by conversion */
+ /* function (needed for OS/2, where \ is path separator) */
+ cc -= (strlen(*xp) - strlen(atxbuf));
+#endif /* DOCHKVAR */
+ *xp = atxbuf;
+ if (!atxbuf[0]) { /* Result empty, use default */
+ *xp = xdef;
+ cc = strlen(xdef);
+ }
+#ifdef DOCHKVAR
+ break;
+ }
+ s++;
+ }
+#endif /* DOCHKVAR */
+ }
+#endif /* NOSPL */
+
+#ifdef DTILDE
+ if (dirflg && *(*xp) == '~') {
+ debug(F111,"cmifi tilde_expand A",*xp,cc);
+ dirp = tilde_expand(*xp); /* Expand tilde, if any... */
+ if (!dirp) dirp = "";
+ if (*dirp) {
+ int i, xx;
+ char * sp;
+ xc = cc; /* Length of ~thing */
+ xx = setatm(dirp,0); /* Copy expansion to atom buffer */
+ debug(F111,"cmifi tilde_expand B",atmbuf,cc);
+ if (xx < 0) {
+ printf("Expanded name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ debug(F111,"cmifi tilde_expand xc","",xc);
+ for (i = 0; i < xc; i++) {
+ cmdchardel(); /* Back up over ~thing */
+ bp--;
+ }
+ xc = cc; /* How many new ones we just got */
+ sp = atmbuf;
+ printf("%s",sp); /* Print them */
+ while ((*bp++ = *sp++)) ; /* Copy to command buffer */
+ bp--; /* Back up over NUL */
+ }
+ *xp = atmbuf;
+ }
+#endif /* DTILDE */
+
+ sp = *xp + cc;
+
+#ifdef UNIXOROSK
+ if (!strcmp(atmbuf,"..")) {
+ printf(" ");
+ ckstrncat(cmdbuf," ",CMDBL);
+ cc++;
+ bp++;
+ *wild = 0;
+ *xp = atmbuf;
+ break;
+ } else if (!strcmp(atmbuf,".")) {
+ bleep(BP_WARN);
+ if (np) free(np);
+ return(-1);
+ } else {
+ /* This patches a glitch when user types "./foo<ESC>" */
+ /* in which the next two chars are omitted from the */
+ /* expansion. There should be a better fix, however, */
+ /* since there is no problem with "../foo<ESC>". */
+ char *p = *xp;
+ if (*p == '.' && *(p+1) == '/')
+ cc -= 2;
+ }
+#endif /* UNIXOROSK */
+
+#ifdef datageneral
+ *sp++ = '+'; /* Data General AOS wildcard */
+#else
+ *sp++ = '*'; /* Others */
+#endif /* datageneral */
+ *sp-- = '\0';
+#ifdef GEMDOS
+ if (!strchr(*xp, '.')) /* abde.e -> abcde.e* */
+ strcat(*xp, ".*"); /* abc -> abc*.* */
+#endif /* GEMDOS */
+ /* Add wildcard and expand list. */
+#ifdef COMMENT
+ /* This kills partial completion when ESC given in path segment */
+ nzxopts |= dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY);
+#else
+ /* nzxopts = 0; */
+#endif /* COMMENT */
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ nfiles = y;
+ debug(F111,"cmifi nzxpand",*xp,y);
+ if (y > 0) {
+#ifdef OS2
+ znext(filbuf); /* Get first */
+#ifdef ZXREWIND
+ zxrewind(); /* Must "rewind" */
+#else
+ nzxpand(*xp,nxzopts);
+#endif /* ZXREWIND */
+#else /* Not OS2 */
+ ckstrncpy(filbuf,mtchs[0],CKMAXPATH);
+#endif /* OS2 */
+ } else
+ *filbuf = '\0';
+ filbuf[CKMAXPATH] = NUL;
+ *sp = '\0'; /* Remove wildcard. */
+ debug(F111,"cmifi filbuf",filbuf,y);
+ debug(F111,"cmifi *xp",*xp,cc);
+
+ *wild = (y > 1);
+ if (y == 0) {
+ if (!nomsg) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?No %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ } else {
+ bleep(BP_WARN);
+ if (np) free(np);
+ return(-1);
+ }
+ } else if (y < 0) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?Too many %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ } else if (y > 1 /* Not unique */
+#ifndef VMS
+ || (y == 1 && isdir(filbuf)) /* Unique directory */
+#endif /* VMS */
+ ) {
+#ifndef NOPARTIAL
+/* Partial filename completion */
+ int j, k; char c;
+ k = 0;
+ debug(F111,"cmifi partial",filbuf,cc);
+#ifdef OS2
+ {
+ int cur = 0,
+ len = 0,
+ len2 = 0,
+ min = strlen(filbuf),
+ found = 0;
+ char localfn[CKMAXPATH+1];
+
+ len = min;
+ for (j = 1; j <= y; j++) {
+ znext(localfn);
+ if (dirflg && !isdir(localfn))
+ continue;
+ found = 1;
+ len2 = strlen(localfn);
+ for (cur = cc;
+ cur < len && cur < len2 && cur <= min;
+ cur++
+ ) {
+ /* OS/2 or Windows, case doesn't matter */
+ if (tolower(filbuf[cur]) != tolower(localfn[cur]))
+ break;
+ }
+ if (cur < min)
+ min = cur;
+ }
+ if (!found)
+ min = cc;
+ filbuf[min] = NUL;
+ if (min > cc)
+ k++;
+ }
+#else /* OS2 */
+ for (i = cc; (c = filbuf[i]); i++) {
+ for (j = 1; j < y; j++)
+ if (mtchs[j][i] != c) break;
+ if (j == y) k++;
+ else filbuf[i] = filbuf[i+1] = NUL;
+ }
+#endif /* OS2 */
+
+
+#ifndef VMS
+ /* isdir() function required for this! */
+ if (y == 1 && isdir(filbuf)) { /* Dont we already know this? */
+ int len;
+ len = strlen(filbuf);
+ if (len > 0 && len < ATMBL - 1) {
+ if (filbuf[len-1] != dirsep) {
+ filbuf[len] = dirsep;
+ filbuf[len+1] = NUL;
+ }
+ }
+/*
+ At this point, before just doing partial completion, we should look first to
+ see if the given directory does indeed have any subdirectories (dirflg) or
+ files (!dirflg); if it doesn't we should do full completion. Otherwise, the
+ result looks funny to the user and "?" blows up the command for no good
+ reason.
+*/
+ {
+ int flags = 0;
+ filbuf[len+1] = '*';
+ filbuf[len+2] = NUL;
+ if (dirflg) flags = ZX_DIRONLY;
+ children = nzxpand(filbuf,flags);
+ debug(F111,"cmifi children",filbuf,children);
+ filbuf[len+1] = NUL;
+ nzxpand(filbuf,flags); /* Restore previous list */
+ if (children == 0)
+ goto NOSUBDIRS;
+ }
+ if (len + 1 > cc)
+ k++;
+ }
+ /* Add doublequotes if there are spaces in the name */
+ {
+ int x;
+ if (qflag) {
+ x = (qflag == '}'); /* (or braces) */
+ } else {
+ x = !dblquo;
+ }
+ if (filbuf[0] != '"' && filbuf[0] != '{')
+ k = dquote(filbuf,ATMBL,x);
+ }
+#endif /* VMS */
+ debug(F111,"cmifi REPAINT filbuf",filbuf,k);
+ if (k > 0) { /* Got more characters */
+ debug(F101,"cmifi REPAINT cc","",cc);
+ debug(F101,"cmifi REPAINT xc","",xc);
+ debug(F110,"cmifi REPAINT bp-cc",bp-cc,0);
+ debug(F110,"cmifi REPAINT bp-xc",bp-xc,0);
+ sp = filbuf + cc; /* Point to new ones */
+ if (qflag || strncmp(filbuf,bp-cc,cc)) { /* Repaint? */
+ int x;
+ x = cc;
+ if (qflag) x++;
+ for (i = 0; i < x; i++) {
+ cmdchardel(); /* Back up over old partial spec */
+ bp--;
+ }
+ sp = filbuf; /* Point to new word start */
+ debug(F110,"cmifi erase ok",sp,0);
+ }
+ cc = k; /* How many new ones we just got */
+ printf("%s",sp); /* Print them */
+ while ((*bp++ = *sp++)) ; /* Copy to command buffer */
+ bp--; /* Back up over NUL */
+ debug(F110,"cmifi partial cmdbuf",cmdbuf,0);
+ if (setatm(filbuf,0) < 0) {
+ printf("?Partial name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ debug(F111,"cmifi partial atmbuf",atmbuf,cc);
+ *xp = atmbuf;
+ }
+#endif /* NOPARTIAL */
+ bleep(BP_WARN);
+ } else { /* Unique, complete it. */
+#ifndef VMS
+#ifdef CK_TMPDIR
+ /* isdir() function required for this! */
+ NOSUBDIRS:
+ debug(F111,"cmifi unique",filbuf,children);
+ if (isdir(filbuf) && children > 0) {
+ int len;
+ len = strlen(filbuf);
+ if (len > 0 && len < ATMBL - 1) {
+ if (filbuf[len-1] != dirsep) {
+ filbuf[len] = dirsep;
+ filbuf[len+1] = NUL;
+ }
+ }
+ sp = filbuf + cc;
+ bleep(BP_WARN);
+ printf("%s",sp);
+ cc++;
+ while ((*bp++ = *sp++)) ;
+ bp--;
+ if (setatm(filbuf,0) < 0) {
+ printf("?Directory name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ debug(F111,"cmifi directory atmbuf",atmbuf,cc);
+ *xp = atmbuf;
+ } else { /* Not a directory or dirflg */
+#endif /* CK_TMPDIR */
+#endif /* VMS */
+#ifndef VMS /* VMS dir names are special */
+#ifndef datageneral /* VS dirnames must not end in ":" */
+ if (dirflg) {
+ int len;
+ len = strlen(filbuf);
+ if (len > 0 && len < ATMBL - 1) {
+ if (filbuf[len-1] != dirsep) {
+ filbuf[len] = dirsep;
+ filbuf[len+1] = NUL;
+ }
+ }
+ }
+#endif /* datageneral */
+#endif /* VMS */
+ sp = filbuf + cc; /* Point past what user typed. */
+ {
+ int x;
+ if (qflag) {
+ x = (qflag == '}');
+ } else {
+ x = !dblquo;
+ }
+ if (filbuf[0] != '"' && filbuf[0] != '{')
+ dquote(filbuf,ATMBL,x);
+ }
+ if (qflag || strncmp(filbuf,bp-cc,cc)) { /* Repaint? */
+ int x;
+ x = cc;
+ if (qflag) x++;
+ for (i = 0; i < x; i++) {
+ cmdchardel(); /* Back up over old partial spec */
+ bp--;
+ }
+ sp = filbuf; /* Point to new word start */
+ debug(F111,"cmifi after erase sp=",sp,cc);
+ }
+ printf("%s ",sp); /* Print the completed name. */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(sp); /* Add the characters to cmdbuf. */
+ if (setatm(filbuf,0) < 0) { /* And to atmbuf. */
+ printf("?Completed name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ inword = cmflgs = 0;
+ *xp = brstrip(atmbuf); /* Return pointer to atmbuf. */
+ if (dirflg && !isdir(*xp)) {
+ printf("?Not a directory - %s\n", filbuf);
+ if (np) free(np);
+ return(-9);
+ }
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(0);
+#ifndef VMS
+#ifdef CK_TMPDIR
+ }
+#endif /* CK_TMPDIR */
+#endif /* VMS */
+ }
+ break;
+
+ case 3: /* Question mark - file menu wanted */
+ if (*xhlp == NUL)
+ printf(dirflg ? " Directory name" : " Input file specification");
+ else
+ printf(" %s",xhlp);
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ /* If user typed an opening quote or brace, just skip past it */
+
+ if (**xp == '"' || **xp == '{') {
+ *xp = *xp + 1;
+ xc--;
+ cc--;
+ }
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+#ifdef DOCHKVAR
+ char *s = *xp; /* See if there are any variables in */
+ while (*s) { /* the string and if so, expand them */
+ if (chkvar(s)) {
+#endif /* DOCHKVAR */
+ zq = atxbuf;
+ atxn = CMDBL;
+ if ((x = (*f)(*xp,&zq,&atxn)) < 0) {
+ if (np) free(np);
+ return(-2);
+ }
+#ifdef DOCHKVAR
+ /* reduce cc by number of \\ consumed by conversion */
+ /* function (needed for OS/2, where \ is path separator) */
+ cc -= (strlen(*xp) - strlen(atxbuf));
+#endif /* DOCHKVAR */
+ *xp = atxbuf;
+#ifdef DOCHKVAR
+ break;
+ }
+ s++;
+ }
+#endif /* DOCHKVAR */
+ }
+#endif /* NOSPL */
+ debug(F111,"cmifi ? *xp, cc",*xp,cc);
+ sp = *xp + cc; /* Insert "*" at end */
+#ifdef datageneral
+ *sp++ = '+'; /* Insert +, the DG wild card */
+#else
+ *sp++ = '*';
+#endif /* datageneral */
+ *sp-- = '\0';
+#ifdef GEMDOS
+ if (! strchr(*xp, '.')) /* abde.e -> abcde.e* */
+ strcat(*xp, ".*"); /* abc -> abc*.* */
+#endif /* GEMDOS */
+ debug(F110,"cmifi ? wild",*xp,0);
+
+ nzxopts |= dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY);
+
+ debug(F101,"cmifi matchdot","",matchdot);
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ nfiles = y;
+ *sp = '\0';
+ if (y == 0) {
+ if (nomsg) {
+ printf(": %s\n",atmbuf);
+ printf("%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ if (np) free(np);
+ return(-1);
+ } else {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?No %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ }
+ } else if (y < 0) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?Too many %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ } else {
+ printf(", one of the following:\n");
+ if (filhelp((int)y,"","",1,dirflg) < 0) {
+ if (np) free(np);
+ return(-9);
+ }
+ }
+ printf("%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ break;
+#endif /* MAC */
+ }
+#ifdef BS_DIRSEP
+ dirnamflg = 1;
+ x = gtword(0); /* No, get a word */
+ dirnamflg = 0;
+#else
+ x = gtword(0); /* No, get a word */
+#endif /* BS_DIRSEP */
+ *xp = atmbuf;
+ }
+}
+
+/* C M F L D -- Parse an arbitrary field */
+/*
+ Returns:
+ -3 if no input present when required,
+ -2 if field too big for buffer,
+ -1 if reparse needed,
+ 0 otherwise, xp pointing to string result.
+
+ NOTE: Global flag keepallchars says whether this routine should break on CR
+ or LF: needed for MINPUT targets and DECLARE initializers, where we want to
+ keep control characters if the user specifies them (March 2003). It might
+ have been better to change the calling sequence but that was not practical.
+*/
+int
+cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+ int x, xc;
+ char *zq;
+
+ inword = 0; /* Initialize counts & pointers */
+ cc = 0;
+ xc = 0;
+ *xp = "";
+
+ debug(F110,"cmfld xdef 1",xdef,0);
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+ ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
+ xdef = cmdefault;
+
+ debug(F111,"cmfld xdef 2",xdef,cmflgs);
+ debug(F111,"cmfld atmbuf 1",atmbuf,xc);
+
+ if ((x = cmflgs) != 1) { /* Already confirmed? */
+ x = gtword(0); /* No, get a word */
+ } else {
+ if (setatm(xdef,0) < 0) { /* If so, use default, if any. */
+ printf("?Default too long\n");
+ return(-9);
+ }
+ }
+ *xp = atmbuf; /* Point to result. */
+ debug(F111,"cmfld atmbuf 2",atmbuf,cmflgs);
+
+ while (1) {
+ xc += cc; /* Count the characters. */
+ debug(F111,"cmfld gtword",atmbuf,xc);
+ debug(F101,"cmfld x","",x);
+ switch (x) {
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -3: /* Empty. */
+ case -2: /* Out of space. */
+ case -1: /* Reparse needed */
+ return(x);
+ case 1: /* CR */
+ case 0: /* SP */
+ debug(F111,"cmfld 1",atmbuf,xc);
+ if (xc == 0) { /* If no input, return default. */
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ }
+ *xp = atmbuf; /* Point to what we got. */
+ debug(F111,"cmfld 2",atmbuf,((f) ? 1 : 0));
+ if (f) { /* If a conversion function is given */
+ zq = atxbuf; /* employ it now. */
+ atxn = CMDBL;
+ if ((*f)(*xp,&zq,&atxn) < 0)
+ return(-2);
+ debug(F111,"cmfld 3",atxbuf,xc);
+ /* Replace by new value -- for MINPUT only keep all chars */
+ if (setatm(atxbuf,keepallchars ? 3:1) < 0) { /* 16 Mar 2003 */
+ printf("Value too long\n");
+ return(-9);
+ }
+ *xp = atmbuf;
+ }
+ debug(F111,"cmfld 4",atmbuf,xc);
+ if (**xp == NUL) { /* If variable evaluates to null */
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ if (**xp == NUL) x = -3; /* If still empty, return -3. */
+ }
+ debug(F111,"cmfld returns",*xp,x);
+ return(x);
+ case 2: /* ESC */
+ if (xc == 0 && *xdef) {
+ printf("%s ",xdef); /* If at beginning of field, */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(xdef); /* Supply default. */
+ inword = cmflgs = 0;
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ } else /* Return as if whole field */
+ return(0); /* typed, followed by space. */
+ } else {
+ bleep(BP_WARN);
+ }
+ break;
+ case 3: /* Question mark */
+ debug(F110,"cmfld QUESTIONMARK",cmdbuf,0);
+ if (*xhlp == NUL)
+ printf(" Please complete this field");
+ else
+ printf(" %s",xhlp);
+ printf("\n%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ break;
+ }
+ debug(F111,"cmfld gtword A x",cmdbuf,x);
+ x = gtword(0);
+ debug(F111,"cmfld gtword B x",cmdbuf,x);
+ }
+}
+
+
+/* C M T X T -- Get a text string, including confirmation */
+
+/*
+ Print help message 'xhlp' if ? typed, supply default 'xdef' if null
+ string typed. Returns:
+
+ -1 if reparse needed or buffer overflows.
+ 1 otherwise.
+
+ with cmflgs set to return code, and xp pointing to result string.
+*/
+int
+cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
+
+ int x, i;
+ char *xx, *zq;
+ static int xc;
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+ cmfldflgs = 0;
+
+ cmdefault[0] = NUL;
+ if (*xdef)
+ ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
+ xdef = cmdefault;
+
+ debug(F101,"cmtxt cmflgs","",cmflgs);
+ inword = 0; /* Start atmbuf counter off at 0 */
+ cc = 0;
+ if (cmflgs == -1) { /* If reparsing, */
+ *xp = pp;
+ xc = (int)strlen(*xp); /* get back the total text length, */
+ bp = *xp; /* and back up the pointers. */
+ np = *xp;
+ pp = *xp;
+ } else { /* otherwise, */
+ /* debug(F100,"cmtxt: fresh start","",0); */
+ *xp = ""; /* start fresh. */
+ xc = 0;
+ }
+ *atmbuf = NUL; /* And empty the atom buffer. */
+ rtimer(); /* Reset timer */
+ if ((x = cmflgs) != 1) {
+ int done = 0;
+ while (!done) {
+ x = gtword(0); /* Get first word. */
+ *xp = pp; /* Save pointer to it. */
+ /* debug(F111,"cmtxt:",*xp,cc); */
+ if (x == -10) {
+ if (gtimer() > timelimit) {
+ /* if (!quiet) printf("?Timed out\n"); */
+ return(x);
+ }
+ } else
+ done = 1;
+ }
+ }
+ while (1) { /* Loop for each word in text. */
+ xc += cc; /* Char count for all words. */
+ /* debug(F111,"cmtxt gtword",atmbuf,xc); */
+ /* debug(F101,"cmtxt x","",x); */
+ switch (x) {
+ case -10:
+ if (gtimer() > timelimit) {
+#ifdef IKSD
+ extern int inserver;
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit);
+ doexit(GOOD_EXIT,0);
+ }
+#endif /* IKSD */
+ /* if (!quiet) printf("?Timed out\n"); */
+ return(-10);
+ } else {
+ x = gtword(0);
+ continue;
+ }
+ case -9: /* Buffer overflow */
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+#ifdef MAC
+ case -3: /* Quit/Timeout */
+#endif /* MAC */
+ case -2: /* Overflow */
+ case -1: /* Deletion */
+ return(x);
+ case 0: /* Space */
+ xc++; /* Just count it */
+ break;
+ case 1: /* CR or LF */
+ if (xc == 0) *xp = xdef;
+ if (f) { /* If a conversion function is given */
+ char * sx = atxbuf;
+ zq = atxbuf; /* Point to the expansion buffer */
+ atxn = CMDBL; /* specify its length */
+ /* debug(F111,"cmtxt calling (*f)",*xp,atxbuf); */
+ if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
+ sx = atxbuf;
+#ifndef COMMENT
+ cc = 0;
+ while (*sx++) cc++; /* (faster than calling strlen) */
+#else
+ cc = (int)strlen(atxbuf);
+#endif /* COMMENT */
+ /* Should be equal to (CMDBL - atxn) but isn't always. */
+ /* Why not? */
+ if (cc < 1) { /* Nothing in expansion buffer? */
+ *xp = xdef; /* Point to default string instead. */
+#ifndef COMMENT
+ sx = xdef;
+ while (*sx++) cc++; /* (faster than calling strlen) */
+#else
+ cc = strlen(xdef);
+#endif /* COMMENT */
+ } else { /* Expansion function got something */
+ *xp = atxbuf; /* return pointer to it. */
+ }
+ debug(F111,"cmtxt (*f)",*xp,cc);
+ } else { /* No expansion function */
+#ifndef COMMENT
+ /* Avoid a strlen() call */
+ xx = *xp;
+ cc = 0;
+ while (*xx++) cc++;
+#else
+ /* NO! xc is apparently not always set appropriately */
+ cc = xc;
+#endif /* COMMENT */
+ }
+ xx = *xp;
+#ifdef COMMENT
+ /* strlen() no longer needed */
+ for (i = (int)strlen(xx) - 1; i > 0; i--)
+#else
+ for (i = cc - 1; i > 0; i--)
+#endif /* COMMENT */
+ if (xx[i] != SP) /* Trim trailing blanks */
+ break;
+ else
+ xx[i] = NUL;
+ return(x);
+ case 2: /* ESC */
+ if (xc == 0) { /* Nothing typed yet */
+ if (*xdef) { /* Have a default for this field? */
+ printf("%s ",xdef); /* Yes, supply it */
+ inword = cmflgs = 0;
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ cc = addbuf(xdef);
+ } else bleep(BP_WARN); /* No default */
+ } else { /* Already in field */
+ int x; char *p;
+ x = strlen(atmbuf);
+ if (ckstrcmp(atmbuf,xdef,x,0)) { /* Matches default? */
+ bleep(BP_WARN); /* No */
+ } else if ((int)strlen(xdef) > x) { /* Yes */
+ p = xdef + x;
+ printf("%s ", p);
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(p);
+ inword = cmflgs = 0;
+ debug(F110,"cmtxt: addbuf",cmdbuf,0);
+ } else {
+ bleep(BP_WARN);
+ }
+ }
+ break;
+ case 3: /* Question Mark */
+ if (*xhlp == NUL)
+ printf(" Text string");
+ else
+ printf(" %s",xhlp);
+ printf("\n%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ break;
+ default:
+ printf("?Unexpected return code from gtword() - %d\n",x);
+ return(-2);
+ }
+ x = gtword(0);
+ }
+}
+
+/* C M K E Y -- Parse a keyword */
+
+/*
+ Call with:
+ table -- keyword table, in 'struct keytab' format;
+ n -- number of entries in table;
+ xhlp -- pointer to help string;
+ xdef -- pointer to default keyword;
+ f -- string preprocessing function (e.g. to evaluate variables)
+ pmsg -- 0 = don't print error messages
+ 1 = print error messages
+ 2 = include CM_HLP keywords even if invisible
+ 3 = 1+2
+ 4 = parse a switch (keyword possibly ending in : or =)
+ 8 = don't strip comments (used, e.g., for "help #")
+ Returns:
+ -3 -- no input supplied and no default available
+ -2 -- input doesn't uniquely match a keyword in the table
+ -1 -- user deleted too much, command reparse required
+ n >= 0 -- value associated with keyword
+*/
+
+/*
+ Front ends for cmkey2():
+ cmkey() - The normal keyword parser
+ cmkeyx() - Like cmkey() but suppresses error messages
+ cmswi() - Switch parser
+*/
+int
+cmkey(table,n,xhlp,xdef,f)
+/* cmkey */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+ return(cmkey2(table,n,xhlp,xdef,"",f,1));
+}
+int
+cmkeyx(table,n,xhlp,xdef,f)
+/* cmkeyx */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+ return(cmkey2(table,n,xhlp,xdef,"",f,0));
+}
+int
+cmswi(table,n,xhlp,xdef,f)
+/* cmswi */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+ return(cmkey2(table,n,xhlp,xdef,"",f,4));
+}
+
+int
+cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
+ struct keytab table[];
+ int n;
+ char *xhlp, *xdef;
+ char *tok;
+ xx_strp f;
+ int pmsg;
+{ /* cmkey2 */
+ extern int havetoken;
+ int i, tl, y, z = 0, zz, xc, wordlen = 0, cmswitch;
+ char *xp, *zq;
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+ cmfldflgs = 0;
+ if (!table) {
+ printf("?Keyword table missing\n");
+ return(-9);
+ }
+ tl = (int)strlen(tok);
+
+ inword = xc = cc = 0; /* Clear character counters. */
+ cmswitch = pmsg & 4; /* Flag for parsing a switch */
+
+ debug(F101,"cmkey: pmsg","",pmsg);
+ debug(F101,"cmkey: cmflgs","",cmflgs);
+ debug(F101,"cmkey: cmswitch","",cmswitch);
+ /* debug(F101,"cmkey: cmdbuf","",cmdbuf);*/
+
+ ppvnambuf[0] = NUL;
+
+ if ((zz = cmflgs) == 1) { /* Command already entered? */
+ if (setatm(xdef,0) < 0) { /* Yes, copy default into atom buf */
+ printf("?Default too long\n");
+ return(-9);
+ }
+ rtimer(); /* Reset timer */
+ } else { /* Otherwise get a command word */
+ rtimer(); /* Reset timer */
+ if (pmsg & 8) /* 8 is for parsing HELP tokens */
+ zz = gtword(4);
+ else
+ zz = gtword((pmsg == 4) ? 1 : 0);
+ }
+
+ debug(F101,"cmkey table length","",n);
+ debug(F101,"cmkey cmflgs","",cmflgs);
+ debug(F101,"cmkey cc","",cc);
+
+ while (1) {
+ xc += cc;
+ debug(F111,"cmkey gtword xc",atmbuf,xc);
+ debug(F101,"cmkey gtword zz","",zz);
+
+ switch (zz) {
+ case -10: /* Timeout */
+ if (gtimer() < timelimit) {
+ if (pmsg & 8) /* 8 is for parsing HELP tokens */
+ zz = gtword(4);
+ else
+ zz = gtword((pmsg == 4) ? 1 : 0);
+ continue;
+ } else {
+#ifdef IKSD
+ extern int inserver;
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit);
+ doexit(GOOD_EXIT,0);
+ }
+#endif /* IKSD */
+ return(-10);
+ }
+ case -5:
+ return(cmflgs = 0);
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -3: /* Null Command/Quit/Timeout */
+ case -2: /* Buffer overflow */
+ case -1: /* Or user did some deleting. */
+ return(cmflgs = zz);
+
+
+ case 1: /* CR */
+ case 0: /* User terminated word with space */
+ case 4: /* or switch ending in : or = */
+ wordlen = cc; /* Length if no conversion */
+ if (cc == 0) { /* Supply default if we got nothing */
+ if ((wordlen = setatm(xdef,(zz == 4) ? 2 : 0)) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ }
+ if (zz == 1 && cc == 0) /* Required field missing */
+ return(-3);
+
+ if (f) { /* If a conversion function is given */
+ char * p2;
+ zq = atxbuf; /* apply it */
+ p2 = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2);
+ debug(F110,"cmkey atxbuf after *f",atxbuf,0);
+ if (!*p2) /* Supply default if we got nothing */
+ p2 = xdef;
+ ckstrncpy(ppvnambuf,atmbuf,PPVLEN);
+ if ((wordlen = setatm(p2,(zz == 4) ? 2 : 0)) < 0) {
+ printf("Evaluated keyword too long\n");
+ return(-9);
+ }
+#ifdef M_UNGW
+ /*
+ This bit lets us save more than one "word".
+ For example, "define \%x echo one two three", "\%x".
+ It works too, but it breaks labels, and therefore
+ WHILE and FOR loops, etc.
+ */
+ if (p2[wordlen] >= SP) {
+ p2 += wordlen;
+ while (*p2 == SP) p2++;
+ if (*p2) {
+ ungword();
+ pp = p2;
+ }
+ }
+#endif /* M_UNGW */
+ }
+#ifdef COMMENT /* ^^^ */
+ if (cmswitch && *atmbuf != '/') {
+ if (pmsg & 1) {
+ bleep(BP_FAIL);
+ printf("?Not a switch - %s\n",atmbuf);
+ }
+ cmflgs = -2;
+ return(-6);
+ }
+#endif /* COMMENT */
+ if (cmswitch) {
+ int i;
+ for (i = 0; i < wordlen; i++) {
+ if (atmbuf[i] == ':' || atmbuf[i] == '=') {
+ brkchar = atmbuf[i];
+ atmbuf[i] = NUL;
+ break;
+ }
+ }
+ }
+
+#ifdef TOKPRECHECK
+/* This was an effective optimization but it breaks sometimes on labels. */
+ if (tl && !isalpha(atmbuf[0])) { /* Precheck for token */
+ for (i = 0; i < tl; i++) { /* Save function call to ckstrchr */
+ if (tok[i] == atmbuf[0]) {
+ debug(F000,"cmkey token:",atmbuf,*atmbuf);
+ ungword(); /* Put back the following word */
+ return(-5); /* Special return code for token */
+ }
+ }
+ }
+#endif /* TOKPRECHECK */
+
+ y = lookup(table,atmbuf,n,&z); /* Look up word in the table */
+ debug(F111,"cmkey lookup",atmbuf,y);
+ debug(F101,"cmkey zz","",zz);
+ debug(F101,"cmkey cmflgs","",cmflgs);
+ debug(F101,"cmkey crflag","",crflag);
+ switch (y) {
+ case -3: /* Nothing to look up */
+ break;
+ case -2: /* Ambiguous */
+ cmflgs = -2;
+ if (pmsg & 1) {
+ bleep(BP_FAIL);
+ printf("?Ambiguous - %s\n",atmbuf);
+ return(-9);
+ }
+ return(-2);
+ case -1: /* Not found at all */
+#ifndef TOKPRECHECK
+ if (tl) {
+ for (i = 0; i < tl; i++) /* Check for token */
+ if (tok[i] == *atmbuf) { /* Got one */
+ debug(F000,"cmkey token:",atmbuf,*atmbuf);
+ ungword(); /* Put back the following word */
+ return(-5); /* Special return code for token */
+ }
+ }
+#endif /* TOKPRECHECK */
+
+ if (tl == 0) { /* No tokens were included */
+#ifdef OS2
+ /* In OS/2 and Windows, allow for a disk letter like DOS */
+ if (isalpha(*atmbuf) && *(atmbuf+1) == ':')
+ return(-7);
+#endif /* OS2 */
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf("?No keywords match - %s\n",atmbuf); /* cmkey */
+ }
+ return(cmflgs = -9);
+ } else {
+ if (cmflgs == 1 || cmswitch) /* cmkey2 or cmswi */
+ return(cmflgs = -6);
+ else
+ return(cmflgs = -2);
+ /* The -6 code is to let caller try another table */
+ }
+ break;
+ default:
+#ifdef CK_RECALL
+ if (test(table[z].flgs,CM_NOR)) no_recall = 1;
+#endif /* CK_RECALL */
+ if (zz == 4)
+ swarg = 1;
+ cmkwflgs = table[z].flgs;
+ break;
+ }
+ return(y);
+
+ case 2: /* User terminated word with ESC */
+ debug(F101,"cmkey Esc cc","",cc);
+ if (cc == 0) {
+ if (*xdef != NUL) { /* Nothing in atmbuf */
+ printf("%s ",xdef); /* Supply default if any */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(xdef);
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ inword = cmflgs = 0;
+ debug(F111,"cmkey: default",atmbuf,cc);
+ } else {
+ debug(F101,"cmkey Esc pmsg","",0);
+#ifdef COMMENT
+/*
+ Chained FDBs... The idea is that this function might not have a default,
+ but the next one might. But if it doesn't, there is no way to come back to
+ this one. To be revisited later...
+*/
+ if (xcmfdb) /* Chained fdb -- try next one */
+ return(-3);
+#endif /* COMMENT */
+ if (pmsg & (1|4)) { /* So for now just beep */
+ bleep(BP_WARN);
+ }
+ break;
+ }
+ }
+ if (f) { /* If a conversion function is given */
+ char * pp;
+ zq = atxbuf; /* apply it */
+ pp = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(atmbuf,&zq,&atxn) < 0)
+ return(-2);
+ if (!*pp)
+ pp = xdef;
+ if (setatm(pp,0) < 0) {
+ printf("Evaluated keyword too long\n");
+ return(-9);
+ }
+ }
+ y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */
+ debug(F111,"cmkey lookup y",atmbuf,y);
+ debug(F111,"cmkey lookup z",atmbuf,z);
+ if (y == -2 && z >= 0 && z < n) { /* Ambiguous */
+#ifndef NOPARTIAL
+ int j, k, len = 9999; /* Do partial completion */
+ /* Skip past any abbreviations in the table */
+ for ( ; z < n; z++) {
+ if ((table[z].flgs & CM_ABR) == 0)
+ break;
+ if (!(table[z].flgs & CM_HLP) || (pmsg & 2))
+ break;
+ }
+ debug(F111,"cmkey partial z",atmbuf,z);
+ debug(F111,"cmkey partial n",atmbuf,n);
+ for (j = z+1; j < n; j++) {
+ debug(F111,"cmkey partial j",table[j].kwd,j);
+ if (ckstrcmp(atmbuf,table[j].kwd,cc,0))
+ break;
+ if (table[j].flgs & CM_ABR)
+ continue;
+ if ((table[j].flgs & CM_HLP) && !(pmsg & 2))
+ continue;
+ k = ckstrpre(table[z].kwd,table[j].kwd);
+ debug(F111,"cmkey partial k",table[z].kwd,k);
+ if (k < len)
+ len = k; /* Length of longest common prefix */
+ }
+ debug(F111,"cmkey partial len",table[z].kwd,len);
+ if (len != 9999 && len > cc) {
+ ckstrncat(atmbuf,table[z].kwd+cc,ATMBL);
+ atmbuf[len] = NUL;
+ printf("%s",atmbuf+cc);
+ ckstrncat(cmdbuf,atmbuf+cc,CMDBL);
+ xc += (len - cc);
+ cc = len;
+ }
+#endif /* NOPARTIAL */
+ bleep(BP_WARN);
+ break;
+ } else if (y == -3) {
+ bleep(BP_WARN);
+ break;
+ } else if (y == -1) { /* Not found */
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf("?No keywords match - \"%s\"\n",atmbuf);
+ }
+ cmflgs = -2;
+ return(-9);
+ }
+/*
+ If we found it, but it's a help-only keyword and the "help" bit is not
+ set in pmsg, then not found.
+*/
+ debug(F101,"cmkey flgs","",table[z].flgs);
+ if (test(table[z].flgs,CM_HLP) && ((pmsg & 2) == 0)) {
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf("?No keywords match - %s\n",atmbuf);
+ }
+ cmflgs = -2;
+ return(-9);
+ }
+/*
+ See if the keyword just found has the CM_ABR bit set in its flgs field, and
+ if so, search forwards in the table for a keyword that has the same kwval
+ but does not have CM_ABR (or CM_INV?) set, and then expand using the full
+ keyword. WARNING: This assumes that (a) keywords are in alphabetical order,
+ and (b) the CM_ABR bit is set only if the the abbreviated keyword is a true
+ abbreviation (left substring) of the full keyword.
+*/
+ if (test(table[z].flgs,CM_ABR)) {
+ int zz;
+ for (zz = z+1; zz < n; zz++)
+ if ((table[zz].kwval == table[z].kwval) &&
+ (!test(table[zz].flgs,CM_ABR)) &&
+ (!test(table[zz].flgs,CM_INV))) {
+ z = zz;
+ break;
+ }
+ }
+ xp = table[z].kwd + cc;
+ if (cmswitch && test(table[z].flgs,CM_ARG)) {
+#ifdef VMS
+ printf("%s=",xp);
+ brkchar = '=';
+#else
+ printf("%s:",xp);
+ brkchar = ':';
+#endif /* VMS */
+ } else {
+ printf("%s ",xp);
+ brkchar = SP;
+ }
+#ifdef CK_RECALL
+ if (test(table[z].flgs,CM_NOR)) no_recall = 1;
+#endif /* CK_RECALL */
+ cmkwflgs = table[z].flgs;
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(xp);
+ if (cmswitch && test(table[z].flgs,CM_ARG)) {
+ bp--; /* Replace trailing space with : */
+#ifdef VMS
+ *bp++ = '=';
+#else
+ *bp++ = ':';
+#endif /* VMS */
+ *bp = NUL;
+ np = bp;
+ swarg = 1;
+ }
+ inword = 0;
+ cmflgs = 0;
+ debug(F110,"cmkey: addbuf",cmdbuf,0);
+ return(y);
+
+ case 3: /* User typed "?" */
+ if (f) { /* If a conversion function is given */
+ char * pp;
+ zq = atxbuf; /* do the conversion now. */
+ pp = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2);
+ if (setatm(pp,0) < 0) {
+ printf("?Evaluated keyword too long\n");
+ return(-9);
+ }
+ }
+ y = lookup(table,atmbuf,n,&z); /* Look up what we have so far. */
+ if (y == -1) {
+ /*
+ Strictly speaking if the main keyword table search fails,
+ then we should look in the token table if one is given.
+ But in practice, tokens are also included in the main
+ keyword table.
+ */
+ cmflgs = -2;
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf(" No keywords match\n");
+ return(-9);
+ }
+ return(-2);
+ }
+#ifndef COMMENT
+ /* This is to allow ?-help to work immediately after a token */
+ /* without having to type an intermediate space */
+ if (tl) {
+ for (i = 0; i < tl; i++) /* Check for token */
+ if (tok[i] == *atmbuf) { /* Got one */
+ debug(F000,"cmkey token:",atmbuf,*atmbuf);
+ ungword(); /* Put back the following word */
+ cmflgs = 3; /* Force help next time around */
+ return(-5); /* Special return code for token */
+ }
+ }
+#endif /* COMMENT */
+
+ if (*xhlp == NUL)
+ printf(" One of the following:\n");
+ else
+ printf(" %s, one of the following:\n",xhlp);
+ {
+ int x;
+ x = pmsg & (2|4); /* See kwdhelp() comments */
+ if (atmbuf[0]) /* If not at beginning of field */
+ x |= 1; /* also show invisibles */
+ kwdhelp(table,n,atmbuf,"","",1,x);
+ }
+#ifndef NOSPL
+ if (!havetoken) {
+ extern int topcmd;
+ if (tl > 0 && topcmd != XXHLP) /* This is bad... */
+ printf("or a macro name (\"do ?\" for a list) ");
+ }
+#endif /* NOSPL */
+ if (*atmbuf == NUL && !havetoken) {
+ if (tl == 1)
+ printf("or the token %c\n",*tok);
+ else if (tl > 1)
+ printf("or one of the tokens: %s\n",ckspread(tok));
+ }
+ printf("%s%s", cmprom, cmdbuf);
+ fflush(stdout);
+ break;
+
+ default:
+ printf("\n%d - Unexpected return code from gtword\n",zz);
+ return(cmflgs = -2);
+ }
+ zz = (pmsg & 8) ? gtword(4) : gtword((pmsg == 4) ? 1 : 0);
+ debug(F111,"cmkey gtword zz",atmbuf,zz);
+ }
+}
+
+int
+chktok(tlist) char *tlist; {
+ char *p;
+ p = tlist;
+ while (*p != NUL && *p != *atmbuf) p++;
+ return((*p) ? (int) *p : 0);
+}
+
+/* Routines for parsing and converting dates and times */
+
+#define isdatesep(c) (ckstrchr(" -/._",c))
+
+#define CMDATEBUF 1024
+char cmdatebuf[CMDATEBUF+4] = { NUL, NUL };
+static char * cmdatebp = cmdatebuf;
+char * cmdatemsg = NULL;
+
+static struct keytab timeunits[] = {
+ { "days", TU_DAYS, 0 },
+ { "months", TU_MONTHS, 0 },
+ { "weeks", TU_WEEKS, 0 },
+ { "wks", TU_WEEKS, 0 },
+ { "years", TU_YEARS, 0 },
+ { "yrs", TU_YEARS, 0 }
+};
+static int nunits = (sizeof(timeunits) / sizeof(struct keytab));
+
+#define SYM_NOW 0
+#define SYM_TODA 1
+#define SYM_TOMO 2
+#define SYM_YEST 3
+
+static struct keytab symdaytab[] = {
+ { "now", SYM_NOW, 0 },
+ { "today", SYM_TODA, 0 },
+ { "tomorrow", SYM_TOMO, 0 },
+ { "yesterday", SYM_YEST, 0 }
+};
+static int nsymdays = (sizeof(symdaytab) / sizeof(struct keytab));
+
+static struct keytab daysofweek[] = {
+ { "Friday", 5, 0 },
+ { "Monday", 1, 0 },
+ { "Saturday", 6, 0 },
+ { "Sunday", 0, 0 },
+ { "Thursday", 4, 0 },
+ { "Tuesday", 2, 0 },
+ { "Wednesday", 3, 0 }
+};
+
+static struct keytab usatz[] = { /* RFC 822 timezones */
+ { "cdt", 5, 0 }, /* Values are GMT offsets */
+ { "cst", 6, 0 },
+ { "edt", 4, 0 },
+ { "est", 5, 0 },
+ { "gmt", 0, 0 },
+ { "mdt", 6, 0 },
+ { "mst", 7, 0 },
+ { "pdt", 7, 0 },
+ { "pst", 8, 0 },
+ { "utc", 0, 0 },
+ { "zulu", 0, 0 }
+};
+static int nusatz = (sizeof(usatz) / sizeof(struct keytab));
+
+
+/* C M C V T D A T E -- Converts free-form date to standard form. */
+
+/*
+ Call with
+ s = pointer to free-format date, time, or date and time.
+ t = 0: return time only if time was given in s.
+ t = 1: always return time (00:00:00 if no time given in s).
+ t = 2: allow time to be > 24:00:00.
+ Returns:
+ NULL on failure;
+ Pointer to "yyyymmdd hh:mm:ss" (local date-time) on success.
+*/
+
+/*
+ Before final release the following long lines should be wrapped.
+ Until then we leave them long since wrapping them wrecks EMACS's
+ C indentation.
+*/
+
+/* asctime pattern */
+static char * atp1 = "[A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]";
+
+/* asctime pattern with timezone */
+static char * atp2 = "[A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [A-Z][A-Z][A-Z] [0-9][0-9][0-9][0-9]";
+
+#define DATEBUFLEN 127
+#define YYYYMMDD 12
+
+#define isleap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+static int mdays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+#define NEED_DAYS 1
+#define NEED_HRS 2
+#define NEED_MINS 3
+#define NEED_SECS 4
+#define NEED_FRAC 5
+
+#define DELTABUF 256
+static char deltabuf[DELTABUF];
+static char * deltabp = deltabuf;
+
+char *
+cmdelta(yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss)
+ int yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss;
+/* cmdelta */ {
+ int zyy, zmo, zdd, zhh, zmm, zss;
+ long t1, t2, t3, t4;
+ long d1 = 0, d2, d3;
+ char datebuf[DATEBUFLEN+1];
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmdelta yy","",yy);
+ debug(F101,"cmdelta mo","",mo);
+ debug(F101,"cmdelta dd","",dd);
+ debug(F101,"cmdelta hh","",hh);
+ debug(F101,"cmdelta mm","",mm);
+ debug(F101,"cmdelta ss","",ss);
+ debug(F101,"cmdelta sign","",sign);
+ debug(F101,"cmdelta dyy","",dyy);
+ debug(F101,"cmdelta dmo","",dmo);
+ debug(F101,"cmdelta ddd","",ddd);
+ debug(F101,"cmdelta dhh","",dhh);
+ debug(F101,"cmdelta dmm","",dmm);
+ debug(F101,"cmdelta dss","",dss);
+ }
+#endif /* DEBLOG */
+
+ if (yy < 0 || yy > 9999) {
+ makestr(&cmdatemsg,"Base year out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (mo < 1 || mo > 12) {
+ makestr(&cmdatemsg,"Base month out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (dd < 1 || dd > mdays[mo]) {
+ makestr(&cmdatemsg,"Base day out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (hh < 0 || hh > 23) {
+ makestr(&cmdatemsg,"Base hour out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (mm < 0 || mm > 59) {
+ makestr(&cmdatemsg,"Base minute out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (ss < 0 || ss > 60) {
+ makestr(&cmdatemsg,"Base second out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ sign = (sign < 0) ? -1 : 1;
+ if (dmo != 0) {
+ if (sign > 0) {
+ mo += (sign * dmo);
+ if (mo > 12) {
+ yy += mo / 12;
+ mo = mo % 12;
+ }
+ } else if (sign < 0) {
+ while (dmo > 12) {
+ yy--;
+ dmo -= 12;
+ }
+ if (dmo < mo) {
+ mo -= dmo;
+ } else {
+ yy--;
+ mo = 12 - (dmo - mo);
+ }
+ }
+ }
+ if (dyy != 0) {
+ yy += (sign * dyy);
+ if (yy > 9999 || yy < 0) {
+ makestr(&cmdatemsg,"Result year out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+ sprintf(datebuf,"%04d%02d%02d %02d:%02d:%02d",yy,mo,dd,hh,mm,ss);
+ d1 = mjd(datebuf);
+ debug(F111,"cmdelta mjd",datebuf,d1);
+
+ t1 = hh * 3600 + mm * 60 + ss; /* Base time to secs since midnight */
+ t2 = dhh * 3600 + dmm * 60 + dss; /* Delta time, ditto */
+ t3 = t1 + (sign * t2); /* Get sum (or difference) */
+
+ d2 = (sign * ddd); /* Delta days */
+ d2 += t3 / 86400L;
+
+ t4 = t3 % 86400L; /* Fractional part of day */
+ if (t4 < 0) { /* If negative */
+ d2--; /* one less delta day */
+ t4 += 86400L; /* get positive seconds */
+ }
+ hh = (int) (t4 / 3600L);
+ mm = (int) (t4 % 3600L) / 60;
+ ss = (int) (t4 % 3600L) % 60;
+
+ sprintf(datebuf,"%s %02d:%02d:%02d", mjd2date(d1+d2),hh,mm,ss);
+ {
+ int len, k, n;
+ char * p;
+ len = strlen(datebuf);
+ k = deltabp - (char *)deltabuf; /* Space used */
+ n = DELTABUF - k - 1; /* Space left */
+ if (n < len) { /* Not enough? */
+ deltabp = deltabuf; /* Wrap around */
+ n = DELTABUF;
+ }
+ ckstrncpy(deltabp,datebuf,n);
+ p = deltabp;
+ deltabp += len + 1;
+ return(p);
+ }
+}
+
+
+/* Convert Delta Time to Seconds */
+
+int
+delta2sec(s,result) char * s; long * result; {
+ long ddays = 0L, zz;
+ int dsign = 1, dhours = 0, dmins = 0, dsecs = 0, units;
+ int state = NEED_DAYS;
+ char *p, *p2, *p3, c = 0;
+ char buf[64];
+
+ if (!s) s = "";
+ if (!*s)
+ return(-1);
+ if ((int)strlen(s) > 63)
+ return(-1);
+ ckstrncpy(buf,s,64);
+ p = buf;
+
+ if (*p != '+' && *p != '-')
+ return(-1);
+
+ if (*p++ == '-')
+ dsign = -1;
+ while (*p == SP) /* Skip intervening spaces */
+ p++;
+
+ while (state) { /* FSA to parse delta time */
+ if (state < 0 || !isdigit(*p))
+ return(-1);
+ p2 = p; /* Get next numeric field */
+ while (isdigit(*p2))
+ p2++;
+ c = *p2; /* And break character */
+ *p2 = NUL; /* Terminate the number */
+ switch (state) { /* Interpret according to state */
+ case NEED_DAYS: /* Initial */
+ if ((c == '-') || /* VMS format */
+ ((c == 'd' || c == 'D')
+ && !isalpha(*(p2+1)))) { /* Days */
+ ddays = atol(p);
+ if (!*(p2+1))
+ state = 0;
+ else /* if anything is left */
+ state = NEED_HRS; /* now we want hours. */
+ } else if (c == ':') { /* delimiter is colon */
+ dhours = atoi(p); /* so it's hours */
+ state = NEED_MINS; /* now we want minutes */
+ } else if (!c) { /* end of string */
+ dhours = atoi(p); /* it's still hours */
+ state = 0; /* and we're done */
+ } else if (isalpha(c) || c == SP) {
+ if (c == SP) { /* It's a keyword? */
+ p2++; /* Skip spaces */
+ while (*p2 == SP)
+ p2++;
+ } else { /* or replace first letter */
+ *p2 = c;
+ }
+ p3 = p2; /* p2 points to beginning of keyword */
+ while (isalpha(*p3)) /* Find end of keyword */
+ p3++;
+ c = *p3; /* NUL it out so we can look it up */
+ if (*p3) /* p3 points to keyword terminator */
+ *p3 = NUL;
+ if ((units = lookup(timeunits,p2,nunits,NULL)) < 0)
+ return(-1);
+ *p2 = NUL; /* Re-terminate the number */
+ *p3 = c;
+ while (*p3 == SP) /* Point at field after units */
+ p3++;
+ p2 = p3;
+ switch (units) {
+ case TU_DAYS:
+ ddays = atol(p);
+ break;
+ default:
+ return(-1);
+ }
+ if (*p2) {
+ state = NEED_HRS;
+ p2--;
+ } else
+ state = 0;
+ } else { /* Anything else */
+ state = -1; /* is an error */
+ }
+ break;
+ case NEED_HRS: /* Looking for hours */
+ if (c == ':') {
+ dhours = atoi(p);
+ state = NEED_MINS;
+ } else if (!c) {
+ dhours = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_MINS: /* Looking for minutes */
+ if (c == ':') {
+ dmins = atoi(p);
+ state = NEED_SECS;
+ } else if (!c) {
+ dmins = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_SECS: /* Looking for seconds */
+ if (c == '.') {
+ dsecs = atoi(p);
+ state = NEED_FRAC;
+ } else if (!c) {
+ dsecs = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_FRAC: /* Fraction of second */
+ if (!c && rdigits(p)) {
+ if (*p > '4')
+ dsecs++;
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ }
+ if (c) /* next field if any */
+ p = p2 + 1;
+ }
+ if (state < 0)
+ return(-1);
+
+ /* if days > 24854 and sizeof(long) == 32 we overflow */
+
+ zz = ddays * 86400L;
+ if (zz < 0L) /* This catches it */
+ return(-2);
+ zz += dhours * 3600L + dmins * 60L + dsecs;
+ zz *= dsign;
+ *result = zz;
+ return(0);
+}
+
+
+char *
+cmcvtdate(s,t) char * s; int t; {
+ int x, i, j, k, hh, mm, ss, ff, pmflag = 0, nodate = 0, len, dow;
+ int units, isgmt = 0, gmtsign = 0, d = 0, state = 0, nday;
+ int kn = 0, ft[8], isletter = 0, f2len = 0;
+
+ int zhh = 0; /* Timezone adjustments */
+ int zmm = 0;
+ int zdd = 0;
+
+ int dsign = 1; /* Delta-time adjustments */
+ int ddays = 0;
+ int dmonths = 0;
+ int dyears = 0;
+ int dhours = 0;
+ int dmins = 0;
+ int dsecs = 0;
+ int havedelta = 0;
+
+ char * fld[8], * p = "", * p2, * p3; /* Assorted buffers and pointers */
+ char * s2, * s3;
+ char * year = NULL, * month = NULL, * day = NULL;
+ char * hour = "00", * min = "00", * sec = "00";
+ char datesep = 0;
+ char tmpbuf[8];
+ char xbuf[DATEBUFLEN+1];
+ char ybuf[DATEBUFLEN+1];
+ char zbuf[DATEBUFLEN+1];
+ char yyyymmdd[YYYYMMDD];
+ char dbuf[26];
+ char daybuf[3];
+ char monbuf[3];
+ char yearbuf[5];
+ char timbuf[16], *tb, cc;
+ char * dp = NULL; /* Result pointer */
+
+ if (!s) s = "";
+ tmpbuf[0] = NUL;
+
+ while (*s == SP) s++; /* Gobble any leading blanks */
+ if (isalpha(*s)) /* Remember if 1st char is a letter */
+ isletter = 1;
+
+ len = strlen(s);
+ debug(F110,"cmcvtdate",s,len);
+ if (len == 0) { /* No arg - return current date-time */
+ dp = ckdate();
+ goto xcvtdate;
+ }
+ if (len > DATEBUFLEN) { /* Check length of arg */
+ makestr(&cmdatemsg,"Date-time string too long");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ hh = 0; /* Init time to 00:00:00.0 */
+ mm = 0;
+ ss = 0;
+ ff = 0;
+ ztime(&p);
+ if (!p)
+ p = "";
+ if (*p) { /* Init time to current time */
+ x = ckstrncpy(dbuf,p,26);
+ if (x > 17) {
+ hh = atoi(&dbuf[11]);
+ mm = atoi(&dbuf[14]);
+ ss = atoi(&dbuf[17]);
+ }
+ }
+ ckstrncpy(yyyymmdd,zzndate(),YYYYMMDD); /* Init date to current date */
+ ckstrncpy(yearbuf,yyyymmdd,5);
+ ckstrncpy(monbuf,&yyyymmdd[4],3);
+ ckstrncpy(daybuf,&yyyymmdd[6],3);
+ year = yearbuf;
+ month = monbuf;
+ day = daybuf;
+ nday = atoi(daybuf);
+ ckstrncpy(xbuf,s,DATEBUFLEN); /* Make a local copy we can poke */
+ s = xbuf; /* Point to it */
+ s[len] = NUL;
+ if (s[0] == ':') {
+ p = s;
+ goto dotime;
+ }
+ /* Special preset formats... */
+
+ if (len >= 14) { /* FTP MDTM all-numeric date */
+ char c;
+ c = s[14]; /* e.g. 19980615100045.014 */
+ s[14] = NUL;
+ x = rdigits(s);
+ s[14] = c;
+ if (x) {
+ ckstrncpy(yyyymmdd,s,8+1);
+ year = NULL;
+ p = &s[8];
+ goto dotime;
+ }
+ }
+ x = 0; /* Becomes > 0 for asctime format */
+ if (isalpha(s[0])) {
+ if (len == 24) { /* Asctime format? */
+ /* Sat Jul 14 15:57:32 2001 */
+ x = ckmatch(atp1,s,0,0);
+ debug(F111,"cmcvtdate asctime",s,x);
+ } else if (len == 28) { /* Or Asctime plus timezone? */
+ /* Sat Jul 14 15:15:39 EDT 2001 */
+ x = ckmatch(atp2,s,0,0);
+ debug(F111,"cmcvtdate asctime+timezone",s,x);
+ }
+ }
+ if (x > 0) { /* Asctime format */
+ int xx;
+ strncpy(yearbuf,s + len - 4,4);
+ yearbuf[4] = NUL;
+ for (i = 0; i < 3; i++)
+ tmpbuf[i] = s[i+4];
+ tmpbuf[3] = NUL;
+ if ((xx = lookup(cmonths,tmpbuf,12,NULL)) < 0) {
+ makestr(&cmdatemsg,"Invalid month");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ debug(F101,"cmcvtdate asctime month","",xx);
+ monbuf[0] = (xx / 10) + '0';
+ monbuf[1] = (xx % 10) + '0';
+ monbuf[2] = NUL;
+ daybuf[0] = (s[8] == ' ' ? '0' : s[8]);
+ daybuf[1] = s[9];
+ daybuf[2] = NUL;
+ xbuf[0] = SP;
+ for (i = 11; i < 19; i++)
+ xbuf[i-10] = s[i];
+ xbuf[9] = NUL;
+ ckmakmsg(zbuf,18,yearbuf,monbuf,daybuf,xbuf);
+ debug(F110,"cmcvtdate asctime ok",zbuf,0);
+ if (len == 24) {
+ dp = zbuf;
+ goto xcvtdate;
+ } else {
+ int n;
+ n = ckmakmsg(ybuf,DATEBUFLEN-4,zbuf," ",NULL,NULL);
+ ybuf[n++] = s[20];
+ ybuf[n++] = s[21];
+ ybuf[n++] = s[22];
+ ybuf[n++] = NUL;
+ ckstrncpy(xbuf,ybuf,DATEBUFLEN);
+ s = xbuf;
+ isletter = 0;
+ }
+ }
+
+/* Check for day of week */
+
+ p = s;
+ while (*p == SP) p++;
+ dow = -1;
+ if (*p) {
+ p2 = p;
+ cc = NUL;
+ while (1) {
+ if (*p2 == ',' || *p2 == SP || !*p2) {
+ cc = *p2; /* Save break char */
+ *p2 = NUL; /* NUL it out */
+ p3 = p2; /* Remember this spot */
+ if ((dow = lookup(daysofweek,p,7,NULL)) > -1) {
+ debug(F111,"cmcvtdate dow",p,dow);
+ s = p2;
+ if (cc == ',' || cc == SP) { /* Point to next field */
+ s++;
+ while (*s == SP) s++;
+ }
+ p = s;
+ debug(F111,"cmcvtdate dow new p",p,dow);
+ break;
+ } else if (isalpha(*p) && cc == ',') {
+ makestr(&cmdatemsg,"Unrecognized day of week");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else {
+ *p3 = cc;
+ break;
+ }
+ }
+ p2++;
+ }
+ }
+ len = strlen(s); /* Update length */
+ debug(F111,"cmcvtdate s",s,len);
+
+ debug(F111,"cmcvtdate dow",s,dow);
+ if (dow > -1) { /* Have a day-of-week number */
+ long zz; int n, j;
+ zz = mjd(zzndate()); /* Get today's MJD */
+ debug(F111,"cmcvtdate zz","",zz);
+ j = (((int)(zz % 7L)) + 3) % 7; /* Today's day-of-week number */
+ debug(F111,"cmcvtdate j","",j);
+ hh = 0; /* Init time to midnight */
+ mm = 0;
+ ss = 0;
+ if (j == dow) {
+ ckstrncpy(yyyymmdd,zzndate(),YYYYMMDD);
+ year = NULL;
+ } else {
+ n = dow - j; /* Days from now */
+ if (dow < j)
+ n += 7;
+ if (n < 0) n += 7; /* Add to MJD */
+ zz += n;
+ ckstrncpy(yyyymmdd,mjd2date(zz),YYYYMMDD); /* New date */
+ year = NULL;
+ }
+ debug(F111,"cmcvtdate A",yyyymmdd,len);
+ if (len == 0) { /* No more fields after this */
+ ckmakmsg(zbuf,18,yyyymmdd," 00:00:00",NULL,NULL);
+ dp = zbuf;
+ goto xcvtdate;
+ }
+ isletter = 0;
+ if (rdigits(p) && len < 8) /* Next field is time? */
+ goto dotime; /* If so go straight to time section */
+ if (isdigit(*p)) {
+ if (*(p+1) == ':')
+ goto dotime;
+ else if (isdigit(*(p+1)) && (*(p+2) == ':'))
+ goto dotime;
+ }
+ }
+ debug(F111,"cmcvtdate B s",s,dow);
+ debug(F111,"cmcvtdate B p",p,dow);
+
+ if (*s == '+' || *s == '-') { /* Delta time only - skip ahead. */
+ p = s;
+ goto delta;
+ }
+#ifdef COMMENT
+/*
+ What is the purpose of this? It breaks parsing of email dates like
+ "Wed, 13 Feb 2002 17:43:02 -0800 (PST)". Removing this code fixes the
+ problem and Kermit still passes the 'dates' script.
+ - fdc, Sat Nov 26 10:52:45 2005.
+*/
+ if (dow > -1) {
+ /* Day of week given followed by something that is not a time */
+ /* or a delta so it can't be valid */
+ makestr(&cmdatemsg,"Invalid tokens after day of week");
+ debug(F111,"cmcvtdate fail",cmdatemsg,-1);
+ return(NULL);
+ }
+#endif /* COMMENT */
+
+ /* Handle "today", "yesterday", "tomorrow", and +/- n units */
+
+ if (ckstrchr("TtYyNn",s[0])) {
+ int i, k, n, minus = 0;
+ char c;
+ long jd;
+ jd = mjd(ckdate());
+ debug(F111,"cmcvtdate mjd",s,jd);
+
+ /* Symbolic date: TODAY, TOMORROW, etc...? */
+
+ s2 = s; /* Find end of keyword */
+ i = 0;
+ while (isalpha(*s2)) { /* and get its length */
+ i++;
+ s2++;
+ }
+ c = *s2; /* Zap but save delimiter */
+ *s2 = NUL;
+ k = lookup(symdaytab,s,nsymdays,NULL); /* Look up keyword */
+ *s2 = c; /* Replace delimiter */
+ if (k < 0) /* Keyword not found */
+ goto normal;
+ s3 = &s[i];
+ while (*s3 == SP) /* Skip whitespace */
+ s3++;
+ if (*s3 == '_' || *s3 == ':')
+ s3++;
+
+ switch (k) { /* Have keyword */
+ case SYM_NOW: /* NOW */
+ ckstrncpy(ybuf,ckdate(),DATEBUFLEN);
+ ckstrncpy(yyyymmdd,ybuf,YYYYMMDD);
+ year = NULL;
+ if (*s3) { /* No overwriting current time. */
+ ckstrncat(ybuf," ",DATEBUFLEN);
+ ckstrncat(ybuf,s3,DATEBUFLEN);
+ }
+ break;
+ default: /* Yesterday, Today, and Tomorrow */
+ if (k == SYM_TOMO) { /* TOMORROW */
+ strncpy(ybuf,mjd2date(jd+1),8);
+ } else if (k == SYM_YEST) { /* YESTERDAY */
+ strncpy(ybuf,mjd2date(jd-1),8);
+ } else { /* TODAY */
+ strncpy(ybuf,ckdate(),8);
+ }
+ strncpy(ybuf+8," 00:00:00",DATEBUFLEN-8); /* Default time is 0 */
+ ckstrncpy(yyyymmdd,ybuf,YYYYMMDD);
+ year = NULL;
+ if (*s3) { /* If something follows keyword... */
+ if (isdigit(*s3)) { /* Time - overwrite default time */
+ strncpy(ybuf+8,s+i,DATEBUFLEN-8);
+ } else { /* Something else, keep default time */
+ ckstrncat(ybuf," ",DATEBUFLEN); /* and append */
+ ckstrncat(ybuf,s3,DATEBUFLEN); /* whatever we have */
+ }
+ }
+ }
+ s = ybuf; /* Point to rewritten date-time */
+ len = strlen(s); /* Update length */
+ isletter = 0; /* Cancel this */
+ }
+
+/* Regular free-format non-symbolic date */
+
+ normal:
+
+ debug(F111,"cmcvtdate NORMAL",s,len);
+ debug(F111,"cmcvtdate dow",s,dow);
+ if (yyyymmdd[0] && !year) {
+ ckstrncpy(yearbuf,yyyymmdd,5);
+ ckstrncpy(monbuf,&yyyymmdd[4],3);
+ ckstrncpy(daybuf,&yyyymmdd[6],3);
+ year = yearbuf;
+ month = monbuf;
+ day = daybuf;
+ nday = atoi(daybuf);
+ }
+ if (isdigit(s[0])) { /* Time without date? */
+ p = s;
+ if (s[1] == ':') {
+ debug(F111,"cmcvtdate NORMAL X1",s,len);
+ goto dotime;
+ } else if (len > 1 && isdigit(s[1]) && s[2] == ':') {
+ debug(F111,"cmcvtdate NORMAL X2",s,len);
+ goto dotime;
+ } else if (rdigits(s) && len < 8) {
+ debug(F111,"cmcvtdate NORMAL X3",s,len);
+ goto dotime;
+ }
+ }
+ if (len >= 8 && isdigit(*s)) { /* Check first for yyyymmdd* */
+ debug(F111,"cmcvtdate NORMAL A",s,len);
+ cc = s[8];
+ s[8] = NUL; /* Isolate first 8 characters */
+ if (rdigits(s)) {
+ /* Have valid time separator? */
+ p2 = cc ? ckstrchr(" Tt_-:",cc) : NULL;
+ if (!cc || p2) {
+ ckstrncpy(yyyymmdd,s,YYYYMMDD); /* Valid separator */
+ year = NULL;
+ s += 8; /* or time not given */
+ if (cc) s++; /* Keep date */
+ p = s; /* and go handle time */
+ goto dotime;
+ } else if (!p2) {
+ if (isdigit(cc))
+ makestr(&cmdatemsg,"Numeric date too long");
+ else
+ makestr(&cmdatemsg,"Invalid date-time separator");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+ s[8] = cc; /* Put this back! */
+ }
+ debug(F111,"cmcvtdate NORMAL non-yyyymmdd",s,len);
+
+ /* Free-format date -- figure it out */
+
+#ifdef COMMENT
+ if (*s && !isdigit(*s)) {
+ makestr(&cmdatemsg,"Unrecognized word in date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+#endif /* COMMENT */
+ for (i = 0; i < 8; i++) /* Field types */
+ ft[i] = -1;
+ fld[i = 0] = (p = s); /* First field */
+ while (*p) { /* Get next two fields */
+ if (isdatesep(*p)) { /* Have a date separator */
+ if (i == 0) {
+ datesep = *p;
+ } else if (i == 1 && *p != datesep) {
+ makestr(&cmdatemsg,"Inconsistent date separators");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ *p++ = NUL; /* Replace by NUL */
+ if (*p) { /* Now we're at the next field */
+ while (*p == SP) p++; /* Skip leading spaces */
+ if (!*p) break; /* Make sure we still have something */
+ if (i == 2) /* Last one? */
+ break;
+ fld[++i] = p; /* No, record pointer to this one */
+ } else {
+ break;
+ }
+ } else if ((*p == 'T' || *p == 't') && isdigit(*(p+1))) { /* Time */
+ *p++ = NUL;
+ break;
+ } else if (*p == ':') {
+ if (i == 0 && p == s) {
+ nodate = 1;
+ break;
+ } else if (i != 0) { /* After a date */
+ if (i == 2) { /* OK as date-time separator (VMS) */
+ *p++ = NUL;
+ break;
+ }
+ if (i < 2)
+ makestr(&cmdatemsg,"Too few fields in date");
+ else
+ makestr(&cmdatemsg,"Misplaced time separator");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ nodate = 1; /* Or without a date */
+ break;
+ }
+ p++;
+ }
+ if (p > s && i == 0) /* Make sure we have a date */
+ nodate = 1; /* No date. */
+
+ if (nodate && dow > -1) { /* Have implied date from DOW? */
+ goto dotime; /* Use, use that, go do time. */
+
+ } else if (nodate) { /* No date and no implied date */
+ char *tmp = NULL; /* Substitute today's date */
+ ztime(&tmp);
+ if (!tmp)
+ tmp = "";
+ if (!*tmp) {
+ makestr(&cmdatemsg,"Problem supplying current date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ ckstrncpy(dbuf,tmp,26); /* Reformat */
+ if (dbuf[8] == SP) dbuf[8] = '0';
+ fld[0] = dbuf+8; /* dd */
+ dbuf[10] = NUL;
+ fld[1] = dbuf+4; /* mmm */
+ dbuf[7] = NUL;
+ fld[2] = dbuf+20; /* yyyy */
+ dbuf[24] = NUL;
+ hh = atoi(&dbuf[11]);
+ mm = atoi(&dbuf[14]);
+ ss = atoi(&dbuf[17]);
+ p = s; /* Back up source pointer to reparse */
+ } else if (i < 2) {
+ makestr(&cmdatemsg,"Too few fields in date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ /* Have three date fields - see what they are */
+
+ for (k = 0, j = 0; j < 3; j++) { /* Get number of non-numeric fields */
+ ft[j] = rdigits(fld[j]);
+ debug(F111,"cmcvtdate fld",fld[j],j);
+ if (ft[j] == 0)
+ k++;
+ }
+ kn = k; /* How many numeric fields */
+ month = NULL; /* Strike out default values */
+ year = NULL;
+ day = NULL;
+
+ if (k == 2 && ft[2] > 0) { /* Jul 20, 2001 */
+ int xx;
+ xx = strlen(fld[1]);
+ p3 = fld[1];
+ if (xx > 0) if (p3[xx-1] == ',') {
+ p3[xx-1] = NUL;
+ if (rdigits(p3)) {
+ k = 1;
+ ft[1] = 1;
+ } else p3[xx-1] = ',';
+ }
+ }
+ if (k > 1) { /* We can have only one non-numeric */
+ if (nodate)
+ makestr(&cmdatemsg,"Unrecognized word in date");
+ else if (!ft[2] && isdigit(*(fld[2])))
+ makestr(&cmdatemsg,"Invalid date-time separator");
+ else
+ makestr(&cmdatemsg,"Too many non-numeric fields in date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (!ft[0]) {
+ k = 0;
+ } else if (!ft[1]) {
+ k = 1;
+ } else if (!ft[2]) {
+ makestr(&cmdatemsg,"Non-digit in third date field");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else
+ k = -1;
+
+ if (k > -1) {
+ if ((x = lookup(cmonths,fld[k],12,NULL)) < 0) {
+ makestr(&cmdatemsg,"Unknown month");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ sprintf(tmpbuf,"%02d",x);
+ month = tmpbuf;
+ }
+ f2len = strlen(fld[2]); /* Length of 3rd field */
+
+ if (k == 0) { /* monthname dd, yyyy */
+ day = fld[1];
+ year = fld[2];
+ } else if (((int)strlen(fld[0]) == 4)) { /* yyyy-xx-dd */
+ year = fld[0];
+ day = fld[2];
+ if (!month)
+ month = fld[1]; /* yyyy-mm-dd */
+ } else if (f2len == 4) { /* xx-xx-yyyy */
+ year = fld[2];
+ if (month) { /* dd-name-yyyy */
+ day = fld[0];
+ } else { /* xx-xx-yyyy */
+ int f0, f1;
+ f0 = atoi(fld[0]);
+ f1 = atoi(fld[1]);
+ if (((f0 > 12) && (f1 <= 12)) || (f1 <= 12 && f0 == f1)) {
+ day = fld[0]; /* mm-dd-yyyy */
+ month = fld[1];
+ } else if ((f0 <= 12) && (f1 > 12)) {
+ if (!rdigits(fld[1])) {
+ makestr(&cmdatemsg,"Day not numeric");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else {
+ day = fld[1]; /* dd-mm-yyyy */
+ }
+ month = fld[0];
+ } else {
+ if (!f0 || !f1)
+ makestr(&cmdatemsg,"Day or month out of range");
+ else
+ makestr(&cmdatemsg,"Day and month are ambiguous");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+ } else if ((f2len < 4) && /* dd mmm yy (RFC822) */
+ !rdigits(fld[1]) && /* middle field is monthname */
+ rdigits(fld[2])) {
+ int tmpyear;
+ day = fld[0];
+ if (!fld[2][1]) {
+ makestr(&cmdatemsg,"Too few digits in year");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ tmpyear = atoi(fld[2]);
+ if (tmpyear < 50) /* RFC 2822 windowing */
+ tmpyear += 2000;
+ else /* This includes 3-digit years. */
+ tmpyear += 1900;
+ year = ckitoa(tmpyear);
+
+ } else if ((f2len < 4) && (k < 0) && ((int)strlen(fld[0]) < 4)) {
+ makestr(&cmdatemsg,"Ambiguous numeric date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else if ((f2len > 4) && ft[2]) {
+ makestr(&cmdatemsg,"Too many digits in year");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else {
+ makestr(&cmdatemsg,"Unexpected date format");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ x = atoi(month);
+ sprintf(tmpbuf,"%02d",x); /* 2-digit numeric month */
+
+/*
+ state = 1 = hours
+ state = 2 = minutes
+ state = 3 = seconds
+ state = 4 = fractions of seconds
+*/
+
+ dotime:
+ if (isletter && (s == p)) {
+ makestr(&cmdatemsg,"Unknown date-time word");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (!year && yyyymmdd[0]) {
+ debug(F110,"cmcvtdate dotime yyyymmdd",yyyymmdd,0);
+ for (i = 0; i < 4; i++)
+ yearbuf[i] = yyyymmdd[i];
+ yearbuf[4] = NUL;
+ monbuf[0] = yyyymmdd[4];
+ monbuf[1] = yyyymmdd[5];
+ monbuf[2] = NUL;
+ daybuf[0] = yyyymmdd[6];
+ daybuf[1] = yyyymmdd[7];
+ daybuf[2] = NUL;
+ day = daybuf;
+ nday = atoi(daybuf);
+ month = monbuf;
+ year = yearbuf;
+ }
+ if (!year) {
+ makestr(&cmdatemsg,"Internal error - date not defaulted");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ /* Get here with day, month, and year set */
+ debug(F110,"cmcvtdate dotime day",day,0);
+ debug(F110,"cmcvtdate dotime month",month,0);
+ debug(F110,"cmcvtdate dotime year",year,0);
+ debug(F110,"cmcvtdate dotime s",s,0);
+ debug(F110,"cmcvtdate dotime p",p,0);
+ x = atoi(month);
+ if (x > 12 || x < 1) {
+ makestr(&cmdatemsg,"Month out of range");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ nday = atoi(day);
+ i = mdays[x];
+ if (x == 2) if (isleap(atoi(year))) i++;
+ if (nday > i || nday < 1) {
+ makestr(&cmdatemsg,"Day out of range");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (!*p && t == 0) {
+ sprintf(zbuf,"%04d%02d%02d",atoi(year),atoi(month),nday);
+ dp = zbuf;
+ goto xcvtdate;
+ }
+ if (*p == '+' || *p == '-') { /* GMT offset without a time */
+ hh = 0; /* so default time to 00:00:00 */
+ mm = 0;
+ ss = 0;
+ goto cmtimezone; /* and go do timezone */
+ }
+ if (*p && !isdigit(*p) && *p != ':') {
+ makestr(&cmdatemsg,"Invalid time");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ sprintf(yyyymmdd,"%s%s%02d",year,month,nday); /* for tz calculations... */
+
+ state = 1; /* Initialize time-parsing FSA */
+ hh = 0; /* hours */
+ mm = 0; /* minutes */
+ ss = 0; /* seconds */
+ ff = -1; /* fraction */
+ d = 0; /* Digit counter */
+ p2 = p; /* Preliminary digit count... */
+ while (isdigit(*p2)) {
+ d++;
+ p2++;
+ }
+ if (d > 6) {
+ makestr(&cmdatemsg,"Too many time digits");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ d = (d & 1 && *p2 != ':') ? 1 : 0; /* Odd implies leading '0' */
+
+ while (*p) { /* Get the time, if any */
+ if (isdigit(*p)) { /* digit */
+ if (d++ > 1) {
+ state++;
+ d = 1;
+ }
+ switch (state) {
+ case 1: /* Hours */
+ hh = hh * 10 + (*p - '0');
+ break;
+ case 2: /* Minutes */
+ mm = mm * 10 + (*p - '0');
+ break;
+ case 3: /* Seconds */
+ ss = ss * 10 + (*p - '0');
+ break;
+ case 4: /* Fraction of second */
+ if (ff < 0)
+ ff = (*p > '4') ? 1 : 0;
+ break;
+ }
+ } else if (*p == ':') { /* Colon */
+ state++;
+ d = 0;
+ if (state > 3) {
+ makestr(&cmdatemsg,"Too many time fields");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ } else if (*p == '.') {
+ if (state == 3) {
+ state = 4;
+ d = 0;
+ } else {
+ makestr(&cmdatemsg,"Improper fraction");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ } else if (*p == SP) { /* Space */
+ while (*p && (*p == SP)) /* position to first nonspace */
+ p++;
+ break;
+ } else if (isalpha(*p)) { /* AM/PM/Z or timezone */
+ break;
+ } else if (*p == '+' || *p == '-') { /* GMT offset */
+ break;
+ } else {
+ makestr(&cmdatemsg,"Invalid time characters");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ p++;
+ }
+ if (!*p) /* If nothing left */
+ goto xcmdate; /* go finish up */
+
+ /* At this point we have HH, MM, SS, and FF */
+ /* Now handle the rest: AM, PM, and/or timezone info */
+
+ if (!ckstrcmp(p,"am",2,0)) { /* AM/PM... */
+ pmflag = 0;
+ p += 2;
+ } else if (!ckstrcmp(p,"a.m.",4,0)) {
+ pmflag = 0;
+ p += 4;
+ } else if (!ckstrcmp(p,"pm",2,0)) {
+ pmflag = 1;
+ p += 2;
+ } else if (!ckstrcmp(p,"p.m.",4,0)) {
+ pmflag = 1;
+ p += 4;
+ }
+ if (pmflag && hh < 12) /* If PM was given */
+ hh += 12; /* add 12 to the hour */
+
+ /* Now handle timezone */
+
+ cmtimezone:
+ debug(F110,"cmcvtdate timezone",p,0);
+
+ zhh = 0; /* GMT offset HH */
+ zmm = 0; /* GMT offset MM */
+ gmtsign = 0; /* Sign of GMT offset */
+ isgmt = 0; /* 1 if time is GMT */
+
+ while (*p && *p == SP) /* Gobble spaces */
+ p++;
+ if (!*p) /* If nothing left */
+ goto xcmdate; /* we're done */
+
+ if (isalpha(*p)) { /* Something left */
+ int zone = 0; /* Alphabetic must be timezone */
+ p2 = p; /* Isolate timezone */
+ p++;
+ while (isalpha(*p))
+ p++;
+ p3 = p;
+ cc = *p;
+ *p = NUL;
+ p = p2; /* Have timezone, look it up */
+ zone = lookup(usatz,p,nusatz,NULL);
+ debug(F111,"cmcvtdate timezone alpha",p,zone);
+
+ if (zone < 0) { /* Not found */
+ makestr(&cmdatemsg,"Unknown timezone");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ isgmt++; /* All dates are GMT from here down */
+ if (zone != 0) { /* But not this one so make it GMT */
+ hh += zone; /* RFC 822 timezone: EST etc */
+ debug(F101,"cmcvtdate hh + zone","",hh);
+ if (hh > 23) { /* Offset crosses date boundary */
+ int i;
+ long jd;
+ jd = mjd(yyyymmdd); /* Get MJD */
+ jd += hh / 24; /* Add new day(s) */
+ hh = hh % 24; /* and convert back to yyyymmdd */
+ ckstrncpy(yyyymmdd,mjd2date(jd),YYYYMMDD);
+ debug(F111,"cmcvtdate zone-adjusted date",yyyymmdd,hh);
+ for (i = 0; i < 4; i++)
+ yearbuf[i] = yyyymmdd[i];
+ yearbuf[4] = NUL;
+ monbuf[0] = yyyymmdd[4];
+ monbuf[1] = yyyymmdd[5];
+ monbuf[2] = NUL;
+ daybuf[0] = yyyymmdd[6];
+ daybuf[1] = yyyymmdd[7];
+ daybuf[2] = NUL;
+ day = daybuf;
+ nday = atoi(daybuf);
+ month = monbuf;
+ year = yearbuf;
+ }
+ }
+ p = p3; /* Put back whatever we poked above */
+ *p = cc;
+
+ } else if (*p == '+' || *p == '-') { /* GMT/UTC offset */
+ p3 = p;
+ debug(F110,"cmcvtdate timezone GMT offset",p,0);
+ gmtsign = (*p == '+') ? -1 : 1;
+ isgmt++;
+ p++;
+ while (*p == SP) p++;
+ d = 0;
+ p2 = p;
+ while (isdigit(*p)) { /* Count digits */
+ d++;
+ p++;
+ }
+ if (d != 4) { /* Strict RFC [2]822 */
+ isgmt = 0; /* If not exactly 4 digits */
+ p = p3; /* it's not a GMT offset. */
+ goto delta; /* So treat it as a delta time. */
+ }
+ d = (d & 1 && *p != ':') ? 1 : 0; /* Odd implies leading '0' */
+ p = p2;
+ debug(F111,"cmcvtdate GMT offset sign",p,gmtsign);
+ debug(F101,"cmcvtdate GMT offset d","",d);
+ state = 1;
+ while (*p) {
+ if (isdigit(*p)) { /* digit */
+ if (d++ > 1) {
+ state++;
+ d = 1;
+ }
+ switch (state) {
+ case 1:
+ zhh = zhh * 10 + (*p - '0');
+ break;
+ case 2:
+ zmm = zmm * 10 + (*p - '0');
+ break;
+ default: /* Ignore seconds or fractions */
+ break;
+ }
+ } else if (*p == ':') { /* Colon */
+ state++;
+ d = 0;
+ } else if (*p == SP || *p == '(') {
+ break;
+ } else {
+ p = p3; /* Maybe it's not a GMT offset. */
+ goto delta; /* So treat it as a delta time. */
+ }
+ p++;
+ }
+ }
+ debug(F110,"cmcvtdate source string after timezone",p,0);
+
+ if (*p) { /* Anything left? */
+ p2 = p;
+ while (*p2 == SP) /* Skip past spaces */
+ p2++;
+ if (*p2 == '(') { /* RFC-822 comment? */
+ int pc = 1; /* paren counter */
+ p2++;
+ while (*p2) {
+ if (*p2 == ')') {
+ if (--pc == 0) {
+ p2++;
+ break;
+ }
+ } else if (*p2 == ')') {
+ pc++;
+ }
+ p2++;
+ }
+ while (*p2 == SP) /* Skip past spaces */
+ p2++;
+ if (!*p2) /* Anything left? */
+ *p = NUL; /* No, erase comment */
+ }
+ if (!*p2) /* Anything left? */
+ goto xcmdate; /* No, done. */
+ p = p2;
+
+ delta:
+ debug(F110,"cmcvtdate delta yyyymmdd",yyyymmdd,0);
+ debug(F110,"cmcvtdate delta year",year,0);
+ debug(F110,"cmcvtdate delta p",p,0);
+
+ if (*p == '+' || *p == '-') { /* Delta time */
+ int state = NEED_DAYS; /* Start off looking for days */
+ char c = 0;
+ dsign = 1; /* Get sign */
+ if (*p++ == '-')
+ dsign = -1;
+ while (*p == SP) /* Skip intervening spaces */
+ p++;
+ while (state) { /* FSA to parse delta time */
+ if (state < 0 || !isdigit(*p)) {
+ makestr(&cmdatemsg,"Invalid delta time");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ p2 = p; /* Get next numeric field */
+ while (isdigit(*p2))
+ p2++;
+ c = *p2; /* And break character */
+ *p2 = NUL; /* Terminate the number */
+
+ switch (state) { /* Interpret according to state */
+ case NEED_DAYS: /* Initial */
+ if ((c == '-') || /* VMS format */
+ ((c == 'd' || c == 'D')
+ && !isalpha(*(p2+1)))) { /* Days */
+ ddays = atoi(p);
+ if (!*(p2+1))
+ state = 0;
+ else /* if anything is left */
+ state = NEED_HRS; /* now we want hours. */
+ } else if ((c == 'W' || c == 'w') && !isalpha(*(p2+1))) {
+ ddays = atoi(p) * 7; /* weeks... */
+ if (!*(p2+1))
+ state = 0;
+ else
+ state = NEED_HRS;
+ } else if ((c == 'M' || c == 'm') && !isalpha(*(p2+1))) {
+ dmonths = atoi(p); /* months... */
+ if (!*(p2+1))
+ state = 0;
+ else
+ state = NEED_HRS;
+ } else if ((c == 'Y' || c == 'y') && !isalpha(*(p2+1))) {
+ dyears = atoi(p); /* years... */
+ if (!*(p2+1))
+ state = 0;
+ else
+ state = NEED_HRS;
+ } else if (c == ':') { /* delimiter is colon */
+ dhours = atoi(p); /* so it's hours */
+ state = NEED_MINS; /* now we want minutes */
+ } else if (!c) { /* end of string */
+ dhours = atoi(p); /* it's still hours */
+ state = 0; /* and we're done */
+ } else if (isalpha(c) || c == SP) {
+ if (c == SP) { /* It's a keyword? */
+ p2++; /* Skip spaces */
+ while (*p2 == SP)
+ p2++;
+ } else { /* or replace first letter */
+ *p2 = c;
+ }
+ p3 = p2; /* p2 points to beginning of keyword */
+ while (isalpha(*p3)) /* Find end of keyword */
+ p3++;
+ c = *p3; /* NUL it out so we can look it up */
+ if (*p3) /* p3 points to keyword terminator */
+ *p3 = NUL;
+ units = lookup(timeunits,p2,nunits,NULL);
+ if (units < 0) {
+ makestr(&cmdatemsg,"Invalid units in delta time");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ *p2 = NUL; /* Re-terminate the number */
+ *p3 = c;
+ while (*p3 == SP) /* Point at field after units */
+ p3++;
+ p2 = p3;
+ switch (units) {
+ case TU_DAYS:
+ ddays = atoi(p);
+ break;
+ case TU_WEEKS:
+ ddays = atoi(p) * 7;
+ break;
+ case TU_MONTHS:
+ dmonths = atoi(p);
+ break;
+ case TU_YEARS:
+ dyears = atoi(p);
+ break;
+ }
+ if (*p2) {
+ state = NEED_HRS;
+ p2--;
+ } else
+ state = 0;
+
+ } else { /* Anything else */
+ state = -1; /* is an error */
+ }
+ break;
+ case NEED_HRS: /* Looking for hours */
+ debug(F000,"cmcvtdate NEED_HRS",p,c);
+ if (c == ':') {
+ dhours = atoi(p);
+ state = NEED_MINS;
+ } else if (!c) {
+ dhours = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_MINS: /* Looking for minutes */
+ if (c == ':') {
+ dmins = atoi(p);
+ state = NEED_SECS;
+ } else if (!c) {
+ dmins = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_SECS: /* Looking for seconds */
+ if (c == '.') {
+ dsecs = atoi(p);
+ state = NEED_FRAC;
+ } else if (!c) {
+ dsecs = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_FRAC: /* Fraction of second */
+ if (!c && rdigits(p)) {
+ if (*p > '4')
+ dsecs++;
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ }
+ if (c) /* next field if any */
+ p = p2 + 1;
+ }
+ havedelta = 1;
+
+ } else {
+ makestr(&cmdatemsg,"Extraneous material at end");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+
+ xcmdate:
+
+ if ((t != 2 && hh > 24) || hh < 0) { /* Hour range check */
+ makestr(&cmdatemsg,"Invalid hours");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (mm > 59) { /* Minute range check */
+ makestr(&cmdatemsg,"Invalid minutes");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (ff > 0) { /* Fraction of second? */
+ if (ss < 59) {
+ ss++;
+ ff = 0;
+ } else if (mm < 59) {
+ ss = 0;
+ mm++;
+ ff = 0;
+ } else if (hh < 24) {
+ ss = 0;
+ mm = 0;
+ hh++;
+ ff = 0;
+ }
+ /* Must add a day -- leave ff at 1... */
+ /* (DO SOMETHING ABOUT THIS LATER) */
+ }
+ if (ss > 60) { /* Seconds range check */
+ makestr(&cmdatemsg,"Invalid seconds"); /* 60 is ok because of */
+ debug(F111,"cmcvtdate",cmdatemsg,-1); /* Leap Second. */
+ return(NULL);
+ }
+ if ((mm < 0 || ss < 0) ||
+ (t != 2 && (ss > 0 || mm > 0) && hh > 23)) {
+ makestr(&cmdatemsg,"Invalid minutes or seconds");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ debug(F110,"cmcvtdate year",year,0);
+ debug(F110,"cmcvtdate month",month,0);
+ debug(F101,"cmcvtdate nday","",nday);
+ debug(F101,"cmcvtdate hh","",hh);
+ debug(F101,"cmcvtdate mm","",mm);
+ debug(F101,"cmcvtdate ss","",ss);
+ debug(F101,"cmcvtdate gmtsign","",gmtsign);
+ debug(F101,"cmcvtdate zhh","",zhh);
+ debug(F101,"cmcvtdate zmm","",zmm);
+ debug(F101,"cmcvtdate isgmt","",isgmt);
+
+#ifdef ZLOCALTIME
+/* Handle timezone -- first convert to GMT */
+
+ zdd = 0; /* Days changed */
+ if (isgmt && (zmm || zhh)) { /* If GMT offset given */
+ long sec1, sec2, zz;
+ sec1 = ss + 60 * mm + 3600 * hh;
+ sec2 = gmtsign * (60 * zmm + 3600 * zhh);
+ sec1 += sec2;
+ if (sec1 < 0) {
+ sec1 = 0 - sec1;
+ zdd = 0L - (sec1 / 86400L);
+ sec1 = sec1 % 86400L;
+ } else if (sec1 > 86400L) {
+ zdd = sec1 / 86400L;
+ sec1 = sec1 % 86400L;
+ }
+ ss = sec1 % 60;
+ zz = sec1 / 60;
+ mm = zz % 60;
+ hh = zz / 60;
+ debug(F101,"cmcvtdate NEW hh","",hh);
+ debug(F101,"cmcvtdate NEW mm","",mm);
+ debug(F101,"cmcvtdate NEW dd","",zdd);
+
+/* At this point hh:mm:ss is in GMT and zdd is the calendar adjustment */
+
+ }
+#endif /* ZLOCALTIME */
+
+ if (yyyymmdd[0] && !year) {
+ ckstrncpy(yearbuf,yyyymmdd,5);
+ ckstrncpy(monbuf,&yyyymmdd[4],3);
+ ckstrncpy(daybuf,&yyyymmdd[6],3);
+ year = yearbuf;
+ month = monbuf;
+ day = daybuf;
+ nday = atoi(daybuf);
+ }
+ sprintf(zbuf,"%04d%02d%02d %02d:%02d:%02d", /* SAFE */
+ atoi(year),atoi(month),nday,hh,mm,ss
+ );
+ dp = zbuf;
+
+#ifdef ZLOCALTIME
+ /* Now convert from GMT to local time */
+
+ if (isgmt) { /* If GMT convert to local time */
+ debug(F110,"cmcvtdate GMT 1",dp,0);
+ if (zdd) { /* Apply any calendar adjustment */
+ long zz;
+ zz = mjd(dp) + zdd;
+ sprintf(zbuf,"%s %02d:%02d:%02d",mjd2date(zz),hh,mm,ss);
+ }
+ debug(F110,"cmcvtdate GMT 2",dp,0);
+ if ((p = zlocaltime(dp))) {
+ debug(F110,"cmcvtdate asctime zlocaltime",p,0);
+ if (p) ckstrncpy(zbuf,p,18);
+ }
+ debug(F110,"cmcvtdate GMT 3",dp,0);
+ for (i = 0; i < 4; i++)
+ yearbuf[i] = dp[i];
+ yearbuf[4] = NUL;
+ monbuf[0] = dp[4];
+ monbuf[1] = dp[5];
+ monbuf[2] = NUL;
+ daybuf[0] = dp[6];
+ daybuf[1] = dp[7];
+ daybuf[2] = NUL;
+ day = daybuf;
+ nday = atoi(daybuf);
+ month = monbuf;
+ year = yearbuf;
+ hh = atoi(&dp[9]);
+ mm = atoi(&dp[12]);
+ ss = atoi(&dp[15]);
+ }
+#endif /* ZLOCALTIME */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmcvtdate hour","",hh);
+ debug(F101,"cmcvtdate minute","",mm);
+ debug(F101,"cmcvtdate second","",ss);
+ }
+#endif /* DEBLOG */
+
+ makestr(&cmdatemsg,NULL);
+ if (havedelta) {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"cmcvtdate base ",dp,0);
+ debug(F101,"cmcvtdate delta sign","",dsign);
+ debug(F101,"cmcvtdate delta yrs ","",dyears);
+ debug(F101,"cmcvtdate delta mos ","",dmonths);
+ debug(F101,"cmcvtdate delta days","",ddays);
+ debug(F101,"cmcvtdate delta hrs ","",dhours);
+ debug(F101,"cmcvtdate delta mins","",dmins);
+ debug(F101,"cmcvtdate delta secs","",dsecs);
+ }
+#endif /* DEBLOG */
+ if (!(dp = cmdelta(atoi(year),
+ atoi(month),
+ nday, hh, mm, ss,
+ dsign, dyears, dmonths, ddays, dhours, dmins, dsecs))) {
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+
+ xcvtdate: /* Exit point for success */
+ {
+ int len, k, n;
+ char * p;
+ debug(F110,"cmcvtdate xcvtdate dp",dp,0);
+ if (!dp) dp = ""; /* Shouldn't happen */
+ if (!*dp) return(NULL); /* ... */
+ len = strlen(dp);
+ debug(F111,"cmcvtdate result",dp,len);
+ k = cmdatebp - (char *)cmdatebuf; /* Space used */
+ n = CMDATEBUF - k - 1; /* Space left */
+ if (n < len) { /* Not enough? */
+ cmdatebp = cmdatebuf; /* Wrap around */
+ n = CMDATEBUF;
+ }
+ ckstrncpy(cmdatebp,dp,n);
+ p = cmdatebp;
+ cmdatebp += len + 1;
+ return(p);
+ }
+}
+
+int
+cmvdate(d) char * d; { /* Verify date-time */
+ int i;
+ if (!d) return(0);
+ if ((int)strlen(d) != 17) return(0);
+ for (i = 0; i < 8; i++) { if (!isdigit(d[i])) return(0); }
+ if (!isdigit(d[9]) || !isdigit(d[10]) ||
+ !isdigit(d[12]) || !isdigit(d[13]) ||
+ !isdigit(d[15]) || !isdigit(d[16]))
+ return(0);
+ if (!ckstrchr(" Tt_-:",d[8])) return(0);
+ if (d[11] != ':' && d[14] != ':') return(0);
+ return(1);
+}
+
+/* c m d i f f d a t e -- Get difference between two date-times */
+
+char *
+cmdiffdate(d1,d2) char * d1, * d2; {
+ char d1buf[9], d2buf[9];
+ char x1buf[18], x2buf[18];
+ char * p;
+
+ int hh1 = 0, mm1 = 0, ss1 = 0;
+ int hh2 = 0, mm2 = 0, ss2 = 0;
+ int hh, mm, ss;
+ int sign;
+ long jd1, jd2, jd, f1, f2, fx;
+ static char result[24], *rp;
+
+ debug(F110,"cmdiffdate d1 A",d1,0);
+ debug(F110,"cmdiffdate d2 A",d2,0);
+
+ if (!(p = cmcvtdate(d1,1))) /* Convert dates to standard format */
+ return(NULL);
+ ckstrncpy(x1buf,p,18);
+ d1 = x1buf;
+
+ if (!(p = cmcvtdate(d2,1)))
+ return(NULL);
+ ckstrncpy(x2buf,p,18);
+ d2 = x2buf;
+
+ debug(F110,"cmdiffdate d1 B",d1,0);
+ debug(F110,"cmdiffdate d2 B",d2,0);
+ if (!cmvdate(d1) || !cmvdate(d2))
+ return(NULL);
+
+ hh1 = atoi(&d1[9]); /* Get hours, minutes, and seconds */
+ mm1 = atoi(&d1[12]); /* for first date */
+ ss1 = atoi(&d1[15]);
+ ckstrncpy(d1buf,d1,9);
+
+ hh2 = atoi(&d2[9]); /* ditto for second date */
+ mm2 = atoi(&d2[12]);
+ ss2 = atoi(&d2[15]);
+ ckstrncpy(d2buf,d2,9);
+
+ jd1 = mjd(d1buf); /* Get the two Julian dates */
+ jd2 = mjd(d2buf);
+ f1 = ss1 + 60 * mm1 + 3600 * hh1; /* Convert first time to seconds */
+
+ f2 = ss2 + 60 * mm2 + 3600 * hh2; /* Ditto for second time */
+ debug(F101,"cmdiffdate jd1","",jd1);
+ debug(F101,"cmdiffdate f1","",f1);
+ debug(F101,"cmdiffdate jd2","",jd2);
+ debug(F101,"cmdiffdate f2","",f2);
+
+ if (jd2 > jd1 || (jd1 == jd2 && f2 > f1)) {
+ sign = -1;
+ if (f1 > f2) {jd2--; f2 += 86400L;}
+ jd = jd2 - jd1;
+ fx = f2 - f1;
+ } else {
+ sign = 1;
+ if (f2 > f1) {jd1--; f1 += 86400L;}
+ jd = jd1 - jd2;
+ fx = f1 - f2;
+ }
+ debug(F111,"cmdiffdate sign jd",sign<0?"-":"+",jd);
+ debug(F101,"cmdiffdate fx","",fx);
+
+ hh = (int) (fx / 3600L); /* Convert seconds to hh:mm:ss */
+
+ mm = (int) (fx % 3600L) / 60L;
+ ss = (int) (fx % 3600L) % 60L;
+
+ rp = result; /* Format the result */
+ *rp++ = (sign < 0) ? '-' : '+';
+ if (jd != 0 && hh+mm+ss == 0) {
+ sprintf(rp,"%ldd",jd);
+ } else if (jd == 0) {
+ if (ss == 0)
+ sprintf(rp,"%d:%02d",hh,mm);
+ else
+ sprintf(rp,"%d:%02d:%02d",hh,mm,ss);
+ } else {
+ if (ss == 0)
+ sprintf(rp,"%ldd%d:%02d",jd,hh,mm);
+ else
+ sprintf(rp,"%ldd%d:%02d:%02d",jd,hh,mm,ss);
+ }
+ debug(F110,"cmdiffdate result",result,0);
+ return((char *)result);
+}
+
+#ifndef NOSPL
+/* s h u f f l e d a t e -- Rearrange date string */
+
+/*
+ Call with:
+ A date string in standard format: yyyymmdd hh:mm:ss (time optional).
+ Options:
+ 1: Reformat date to yyyy-mmm-dd (mmm = English month abbreviation).
+ 2: Reformat date to dd-mmm-yyyy (mmm = English month abbreviation).
+ 3: Reformat as numeric yyyymmddhhmmss.
+ 4: Reformat in asctime() format Sat Nov 26 11:10:34 2005
+ Returns:
+ Pointer to result if args valid, otherwise original arg pointer.
+*/
+char *
+shuffledate(p,opt) char * p; int opt; {
+ extern char * wkdays[];
+ int len;
+ char ibuf[32];
+ static char obuf[48];
+ char c;
+ int yy, dd, mm;
+
+ if (!p) p = "";
+ if (!*p) p = ckdate();
+ if (opt < 1 || opt > 4)
+ return(p);
+ len = strlen(p);
+ if (len < 8 || len > 31) return(p);
+ if (opt == 4) { /* Asctime format (26 Nov 2005) */
+ char c, * s;
+ long z; int k;
+ ckstrncpy(ibuf,p,31);
+ k = len;
+ while (k >= 0 && ibuf[k] == CR || ibuf[k] == LF)
+ ibuf[k--] = NUL;
+ while (k >= 0 && ibuf[k] == SP || ibuf[k] == HT)
+ ibuf[k--] = NUL;
+ if (k < 9) ckstrncpy(&ibuf[8]," 00:00:00",9);
+ p = ibuf;
+ z = mjd(p); /* Convert to modified Julian date */
+ z = z % 7L;
+ if (z < 0) {
+ z = 0 - z;
+ k = 6 - ((int)z + 3) % 7;
+ } else {
+ k = ((int)z + 3) % 7; /* Day of week */
+ }
+ s = wkdays[k];
+ obuf[0] = s[0]; /* Day of week */
+ obuf[1] = s[1];
+ obuf[2] = s[2];
+ obuf[3] = SP; /* Space */
+ c = p[6];
+ p[6] = NUL;
+ mm = atoi(&ibuf[4]); /* Month */
+ s = moname[mm-1]; /* Name of month */
+ p[6] = c;
+
+ obuf[4] = s[0]; /* Month */
+ obuf[5] = s[1];
+ obuf[6] = s[2];
+ obuf[7] = SP; /* Space */
+ if (p[6] == '0') /* Date of month */
+ obuf[8] = SP;
+ else
+ obuf[8] = p[6];
+ obuf[9] = p[7];
+ ckstrncpy(&obuf[10],&p[8],10); /* Time */
+ obuf[19] = SP; /* Space */
+ obuf[20] = p[0]; /* Year */
+ obuf[21] = p[1];
+ obuf[22] = p[2];
+ obuf[23] = p[3];
+ obuf[24] = NUL;
+ return((char *)obuf);
+ }
+ if (opt == 3) {
+ ckstrncpy(obuf,p,48);
+ /* yyyymmdd hh:mm:ss */
+ /* 01234567890123456 */
+ /* yyyymmddhhmmss */
+ obuf[8] = obuf[9];
+ obuf[9] = obuf[10];
+ obuf[10] = obuf[12];
+ obuf[11] = obuf[13];
+ obuf[12] = obuf[15];
+ obuf[13] = obuf[16];
+ obuf[14] = NUL;
+ return((char *)obuf);
+ }
+ ckstrncpy(ibuf,p,32);
+ c = ibuf[4]; /* Warning: not Y10K compliant */
+ ibuf[4] = NUL;
+ if (!rdigits(ibuf))
+ return(p);
+ yy = atoi(ibuf);
+ if (yy < 1 || yy > 9999)
+ return(p);
+ ibuf[4] = c;
+ c = ibuf[6];
+ ibuf[6] = NUL;
+ if (!rdigits(&ibuf[4]))
+ return(p);
+ mm = atoi(&ibuf[4]);
+ if (mm < 1 || mm > 12)
+ return(p);
+ ibuf[6] = c;
+ c = ibuf[8];
+ ibuf[8] = NUL;
+ if (!rdigits(&ibuf[6]))
+ return(p);
+ dd = atoi(&ibuf[6]);
+ ibuf[8] = c;
+ if (dd < 1 || mm > 31)
+ return(p);
+ /* IGNORE WARNINGS ABOUT moname[] REFS OUT OF RANGE - it's prechecked. */
+ switch (opt) {
+ case 1:
+ sprintf(obuf,"%04d-%s-%02d%s",yy,moname[mm-1],dd,&ibuf[8]);
+ break;
+ case 2:
+ sprintf(obuf,"%02d-%s-%04d%s",dd,moname[mm-1],yy,&ibuf[8]);
+ }
+ return((char *)obuf);
+}
+#endif /* NOSPL */
+
+/* C K C V T D A T E -- Like cmcvtdate(), but returns string. */
+/* For use by date-related functions */
+/* See calling conventions for cmcvtdate() above. */
+
+char *
+ckcvtdate(p,t) char * p; int t; {
+ char * s;
+ if (!(s = cmcvtdate(p,t)))
+ return("<BAD_DATE_OR_TIME>"); /* \fblah() error message */
+ else
+ return(s);
+}
+
+
+/* C M D A T E -- Parse a date and/or time */
+
+/*
+ Accepts date in various formats. If the date is recognized,
+ this routine returns 0 or greater with the result string pointer
+ pointing to a buffer containing the date as "yyyymmdd hh:mm:ss".
+*/
+int
+cmdate(xhlp,xdef,xp,quiet,f) char *xhlp, *xdef, **xp; int quiet; xx_strp f; {
+ int x, rc;
+ char *o, *s, *zq, *dp;
+
+ cmfldflgs = 0;
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+ if (!*xhlp) xhlp = "Date and/or time";
+ *xp = "";
+
+ rc = cmfld(xhlp,xdef,&s,(xx_strp)0);
+ debug(F101,"cmdate cmfld rc","",rc);
+ if (rc < 0)
+ return(rc);
+ debug(F110,"cmdate 1",s,0);
+ o = s; /* Remember what they typed. */
+ s = brstrip(s);
+ debug(F110,"cmdate 2",s,0);
+
+ x = 0;
+ if (f) { /* If a conversion function is given */
+ char * pp;
+ zq = atxbuf; /* do the conversion. */
+ pp = atxbuf;
+ atxn = CMDBL;
+ if ((x = (*f)(s,&zq,&atxn)) < 0) return(-2);
+ if (!*pp)
+ pp = xdef;
+ if (setatm(pp,0) < 0) {
+ if (!quiet) printf("?Evaluated date too long\n");
+ return(-9);
+ }
+ s = atxbuf;
+ }
+ dp = cmcvtdate(s,1);
+ if (!dp) {
+ if (!quiet) printf("?%s\n",cmdatemsg);
+ return(-9);
+ }
+ *xp = dp;
+ return(0);
+}
+
+#ifdef CK_RECALL /* Command-recall functions */
+
+/* C M R I N I -- Initialize or change size of command recall buffer */
+
+int
+cmrini(n) int n; {
+ int i;
+ if (recall && in_recall) { /* Free old storage, if any */
+ for (i = 0; i < cm_recall; i++) {
+ if (recall[i]) {
+ free(recall[i]);
+ recall[i] = NULL;
+ }
+ }
+ free(recall);
+ recall = NULL;
+ }
+ cm_recall = n; /* Set new size */
+ rlast = current = -1; /* Initialize pointers */
+ if (n > 0) {
+ recall = (char **)malloc((cm_recall + 1) * sizeof(char *));
+ if (!recall)
+ return(1);
+ for (i = 0; i < cm_recall; i++) {
+ recall[i] = NULL;
+ }
+ in_recall = 1; /* Recall buffers init'd */
+ }
+ return(0);
+}
+
+/* C M A D D N E X T -- Force addition of next command */
+
+VOID
+cmaddnext() {
+ if (on_recall && in_recall) { /* Even if it doesn't come */
+ force_add = 1; /* from the keyboard */
+ newcmd = 1;
+ no_recall = 0;
+ }
+}
+
+/* C M G E T C M D -- Find most recent matching command */
+
+char *
+cmgetcmd(s) char * s; {
+ int i;
+ for (i = current; i >= 0; i--) { /* Search backward thru history list */
+ if (!recall[i]) continue; /* This one's null, skip it */
+ if (ckmatch(s,recall[i],0,1)) /* Match? */
+ return(recall[i]); /* Yes, return pointer */
+ }
+ return(NULL); /* No match, return NULL pointer */
+}
+#endif /* CK_RECALL */
+
+/* A D D C M D -- Add a command to the recall buffer */
+
+VOID
+addcmd(s) char * s; {
+ int len = 0, nq = 0;
+ char * p;
+#ifdef CKLEARN
+ extern int learning;
+#endif /* CKLEARN */
+
+ if (xcmdsrc) /* Only for interactive commands */
+ return;
+
+ if (!newcmd) /* The command has been here already */
+ return; /* so ignore it. */
+ newcmd = 0; /* It's new but do this only once. */
+
+ if (!s) s = cmdbuf;
+ if (s[0])
+ len = strlen(s);
+
+ if (len < 1) /* Don't save empty commands */
+ return;
+
+ p = s;
+ while (*p) { if (*p++ == '?') nq++; } /* Count question marks */
+
+#ifdef CKLEARN
+ if (learning) /* If a learned script is active */
+ learncmd(s); /* record this command. */
+#endif /* CKLEARN */
+
+ debug(F010,"CMD(P)",s,0); /* Maybe record it in the debug log */
+
+#ifdef CKSYSLOG
+ if (ckxlogging) { /* Maybe record it in syslog */
+ if (ckxsyslog >= SYSLG_CX || ckxsyslog >= SYSLG_CM)
+ cksyslog(SYSLG_CX, 1, "command", s, NULL);
+ }
+#endif /* CKSYSLOG */
+
+#ifdef CK_RECALL
+ last_recall = 0;
+
+ if (on_recall && /* Command recall is on? */
+ cm_recall > 0 && /* Recall buffer size is > 0? */
+ !no_recall) { /* Not not saving this command? */
+
+ if (!force_add && rlast > -1) /* If previous command was identical */
+ if (!strcmp(s,recall[rlast])) /* don't add another copy */
+ return;
+
+ force_add = 0; /* Reset now in case it was set */
+
+ if (rlast >= cm_recall - 1) { /* Recall buffer full? */
+ int i;
+ if (recall[0]) { /* Discard oldest command */
+ free(recall[0]);
+ recall[0] = NULL;
+ }
+ for (i = 0; i < rlast; i++) { /* The rest */
+ recall[i] = recall[i+1]; /* move back */
+ }
+ rlast--; /* Now we have one less */
+ }
+ rlast++; /* Index of last command in buffer */
+ current = rlast; /* Also now the current command */
+ if (current >= cm_recall) { /* Shouldn't happen */
+ printf("?Command history error\n"); /* but if it does */
+ on_recall = 0; /* turn off command saving */
+#ifdef COMMENT
+ } else if (nq > 0) { /* Have at least one question mark */
+ recall[current] = malloc(len+nq+1);
+ if (recall[current]) {
+ p = recall[current];
+ while (*s) {
+ if (*s == '?')
+ *p++ = '\\';
+ *p++ = *s++;
+ }
+ *p = NUL;
+ }
+#endif /* COMMENT */
+ } else { /* Normal case, just copy */
+ recall[current] = malloc(len+1);
+ if (recall[current])
+ ckstrncpy(recall[current],s,len+1);
+ }
+ }
+#endif /* CK_RECALL */
+}
+
+
+#ifdef CK_RECALL
+
+/* C M H I S T O R Y */
+
+VOID
+cmhistory() {
+ int i, lc = 1;
+ for (i = 0; i <= current; i++) {
+ printf(" %s\n", recall[i]);
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) /* Do more-prompting... */
+ break;
+ else
+ lc = 0;
+ }
+ }
+}
+
+int
+savhistory(s,disp) char *s; int disp; {
+ FILE * fp;
+ int i;
+
+ fp = fopen(s, disp ? "a" : "w");
+ if (!fp) {
+ perror(s);
+ return(0);
+ }
+ for (i = 0; i <= current; i++)
+ fprintf(fp,"%s\n", recall[i]);
+ fclose(fp);
+ return(1);
+}
+#endif /* CK_RECALL */
+
+#ifdef COMMENT
+/* apparently not used */
+int
+cmgetlc(s) char * s; { /* Get leading char */
+ char c;
+ while ((c = *s++) <= SP) {
+ if (!c)
+ break;
+ }
+ return(c);
+}
+#endif /* COMMENT */
+
+
+/* C M C F M -- Parse command confirmation (end of line) */
+
+/*
+ Returns
+ -2: User typed anything but whitespace or newline
+ -1: Reparse needed
+ 0: Confirmation was received
+*/
+int
+cmcfm() {
+ int x, xc;
+ debug(F101,"cmcfm: cmflgs","",cmflgs);
+ debug(F110,"cmcfm: atmbuf",atmbuf,0);
+ inword = xc = cc = 0;
+
+ setatm("",0); /* (Probably unnecessary) */
+
+ while (cmflgs != 1) {
+ x = gtword(0);
+ xc += cc;
+
+ switch (x) {
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -2:
+ case -1:
+ return(x);
+ case 1: /* End of line */
+ if (xc > 0) {
+ if (xcmfdb) {
+ return(-6);
+ } else {
+ printf("?Not confirmed - %s\n",atmbuf);
+ return(-9);
+ }
+ } else
+ break; /* Finish up below */
+ case 2: /* ESC */
+ if (xc == 0) {
+ bleep(BP_WARN);
+ continue; /* or fall thru. */
+ }
+ case 0: /* Space */
+ if (xc == 0) /* If no chars typed, continue, */
+ continue; /* else fall thru. */
+ /* else fall thru... */
+
+ case 3: /* Question mark */
+ if (xc > 0) {
+ if (xcmfdb) {
+ return(-6);
+ } else {
+ printf("?Not confirmed - %s\n",atmbuf);
+ return(-9);
+ }
+ }
+ printf(
+ "\n Press the Return or Enter key to confirm the command\n");
+ printf("%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ continue;
+ }
+ }
+ debok = 1;
+ return(0);
+}
+
+
+/* The following material supports chained parsing functions. */
+/* See ckucmd.h for FDB and OFDB definitions. */
+
+struct OFDB cmresult = { /* Universal cmfdb result holder */
+ NULL, /* Address of succeeding FDB struct */
+ 0, /* Function code */
+ NULL, /* String result */
+ 0, /* Integer result */
+ (CK_OFF_T)0 /* Wide result */
+};
+
+VOID
+cmfdbi(p,fc,s1,s2,s3,n1,n2,f,k,nxt) /* Initialize an FDB */
+ struct FDB * p;
+ int fc;
+ char * s1, * s2, * s3;
+ int n1, n2;
+ xx_strp f;
+ struct keytab * k;
+ struct FDB * nxt; {
+
+ p->fcode = fc;
+ p->hlpmsg = s1;
+ p->dflt = s2;
+ p->sdata = s3;
+ p->ndata1 = n1;
+ p->ndata2 = n2;
+ p->spf = f;
+ p->kwdtbl = k;
+ p->nxtfdb = nxt;
+}
+
+/* C M F D B -- Parse a field with several possible functions */
+
+int
+cmfdb(fdbin) struct FDB * fdbin; {
+#ifndef NOSPL
+ extern int x_ifnum; /* IF NUMERIC - disables warnings */
+#endif /* NOSPL */
+ struct FDB * in = fdbin;
+ struct OFDB * out = &cmresult;
+ int x = 0, n, r;
+ CK_OFF_T w = (CK_OFF_T)0;
+ char *s, *xp, *m = NULL;
+ int errbits = 0;
+
+ xp = bp;
+
+ out->fcode = -1; /* Initialize output struct */
+ out->fdbaddr = NULL;
+ out->sresult = NULL;
+ out->nresult = 0;
+/*
+ Currently we make one trip through the FDBs. So if the user types Esc or
+ Tab at the beginning of a field, only the first FDB is examined for a
+ default. If the user types ?, help is given only for one FDB. We should
+ search through the FDBs for all matching possibilities -- and in particular
+ display the pertinent context-sensitive help for each function, rather than
+ the only the first one that works, and then rewind the FDB pointer so we
+ are not locked out of the earlier ones.
+*/
+ cmfldflgs = 0;
+ while (1) { /* Loop through the chain of FDBs */
+ nomsg = 1;
+ xcmfdb = 1;
+ s = NULL;
+ n = 0;
+ debug(F101,"cmfdb in->fcode","",in->fcode);
+ switch (in->fcode) { /* Current parsing function code */
+ case _CMNUM:
+ r = in->ndata1;
+ if (r != 10 && r != 8) r = 10;
+#ifndef NOSPL
+ x_ifnum = 1; /* Disables warning messages */
+#endif /* NOSPL */
+ x = cmnum(in->hlpmsg,in->dflt,r,&n,in->spf);
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ debug(F101,"cmfdb cmnum","",x);
+ if (x < 0) errbits |= 1;
+ break;
+ case _CMNUW: /* Wide cmnum - 24 Dec 2005 */
+ r = in->ndata1;
+ if (r != 10 && r != 8) r = 10;
+#ifndef NOSPL
+ x_ifnum = 1; /* Disables warning messages */
+#endif /* NOSPL */
+ x = cmnumw(in->hlpmsg,in->dflt,r,&w,in->spf);
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ debug(F101,"cmfdb cmnumw","",w);
+ if (x < 0) errbits |= 1;
+ break;
+ case _CMOFI:
+ x = cmofi(in->hlpmsg,in->dflt,&s,in->spf);
+ debug(F101,"cmfdb cmofi","",x);
+ if (x < 0) errbits |= 2;
+ break;
+ case _CMIFI:
+ x = cmifi2(in->hlpmsg,
+ in->dflt,
+ &s,
+ &n,
+ in->ndata1,
+ in->sdata,
+ in->spf,
+ in->ndata2
+ );
+ debug(F101,"cmfdb cmifi2 x","",x);
+ debug(F101,"cmfdb cmifi2 n","",n);
+ if (x < 0) errbits |= 4;
+ break;
+ case _CMFLD:
+ cmfldflgs = in->ndata1;
+ x = cmfld(in->hlpmsg,in->dflt,&s,in->spf);
+ debug(F101,"cmfdb cmfld","",x);
+ if (x < 0) errbits |= 8;
+ break;
+ case _CMTXT:
+ x = cmtxt(in->hlpmsg,in->dflt,&s,in->spf);
+ debug(F101,"cmfdb cmtxt","",x);
+ if (x < 0) errbits |= 16;
+ break;
+ case _CMKEY:
+ x = cmkey2(in->kwdtbl,
+ in->ndata1,
+ in->hlpmsg,in->dflt,in->sdata,in->spf,in->ndata2);
+ debug(F101,"cmfdb cmkey","",x);
+ if (x < 0) errbits |= ((in->ndata2 & 4) ? 32 : 64);
+ break;
+ case _CMCFM:
+ x = cmcfm();
+ debug(F101,"cmfdb cmcfm","",x);
+ if (x < 0) errbits |= 128;
+ break;
+ default:
+ debug(F101,"cmfdb - unexpected function code","",in->fcode);
+ printf("?cmfdb - unexpected function code: %d\n",in->fcode);
+ }
+ debug(F101,"cmfdb x","",x);
+ debug(F101,"cmfdb cmflgs","",cmflgs);
+ debug(F101,"cmfdb crflag","",crflag);
+ debug(F101,"cmfdb qmflag","",qmflag);
+ debug(F101,"cmfdb esflag","",esflag);
+
+ if (x > -1) { /* Success */
+ out->fcode = in->fcode; /* Fill in output struct */
+ out->fdbaddr = in;
+ out->sresult = s;
+ out->nresult = (in->fcode == _CMKEY) ? x : n;
+ out->wresult = w;
+ out->kflags = (in->fcode == _CMKEY) ? cmkwflgs : 0;
+ debug(F111,"cmfdb out->nresult",out->sresult,out->nresult);
+ debug(F111,"cmfdb out->wresult",out->sresult,out->wresult);
+ nomsg = 0;
+ xcmfdb = 0;
+ /* debug(F111,"cmfdb cmdbuf & crflag",cmdbuf,crflag); */
+ if (crflag) {
+ cmflgs = 1;
+ }
+ return(x); /* and return */
+ }
+ in = in->nxtfdb; /* Failed, get next parsing function */
+ nomsg = 0;
+ xcmfdb = 0;
+ if (!in) { /* No more */
+ debug(F101,"cmfdb failure x","",x);
+ debug(F101,"cmfdb failure errbits","",errbits);
+ if (x == -6)
+ x = -9;
+ if (x == -9) {
+#ifdef CKROOT
+ if (ckrooterr)
+ m = "Off Limits";
+ else
+#endif /* CKROOT */
+ /* Make informative messages for a few common cases */
+ switch (errbits) {
+ case 4+32: m = "Does not match filename or switch"; break;
+ case 4+64: m = "Does not match filename or keyword"; break;
+ case 1+32: m = "Not a number or valid keyword"; break;
+ case 1+64: m = "Not a number or valid switch"; break;
+ default: m = "Not valid in this position";
+ }
+ printf("?%s: \"%s\"\n",m, atmbuf);
+ }
+ return(x);
+ }
+ if (x != -2 && x != -6 && x != -9 && x != -3) /* Editing or somesuch */
+ return(x); /* Go back and reparse */
+ pp = np = bp = xp; /* Back up pointers */
+ cmflgs = -1; /* Force a reparse */
+
+#ifndef NOSPL
+ if (!askflag) { /* If not executing ASK-class cmd... */
+#endif /* NOSPL */
+ if (crflag) { /* If CR was typed, put it back */
+ pushc = LF; /* But as a linefeed */
+ } else if (qmflag) { /* Ditto for Question mark */
+ pushc = '?';
+ } else if (esflag) { /* and Escape or Tab */
+ pushc = ESC;
+ }
+#ifndef NOSPL
+ }
+#endif /* NOSPL */
+ }
+}
+
+/*
+ C M I O F I -- Parse an input file OR the name of a nonexistent file.
+
+ Replaces the commented-out version above. This one actually works and
+ has the expected straightforward interface.
+*/
+int
+cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+ int x;
+ struct FDB f1, f2;
+ cmfdbi(&f1,_CMIFI,xhlp,xdef,"",0,0,f,NULL,&f2);
+ cmfdbi(&f2,_CMOFI,"","","",0,0,f,NULL,NULL);
+ x = cmfdb(&f1);
+ if (x < 0) {
+ if (x == -3) {
+ x = -9;
+ printf("?Filename required\n");
+ }
+ }
+ *wild = cmresult.nresult;
+ *xp = cmresult.sresult;
+ return(x);
+}
+
+/* G T W O R D -- Gets a "word" from the command input stream */
+
+/*
+Usage: retcode = gtword(brk);
+ brk = 0 for normal word breaks (space, CR, Esc, ?)
+ brk = 1 to add ':' and '=' (for parsing switches). These characters
+ act as break characters only if the first character of the field
+ is slash ('/'), i.e. switch introducer.
+ brk = 4 to not strip comments (used only for "help #" and "help ;").
+
+Returns:
+-10 Timelimit set and timed out
+ -9 if input was too long
+ -4 if end of file (e.g. pipe broken)
+ -3 if null field
+ -2 if command buffer overflows
+ -1 if user did some deleting
+ 0 if word terminates with SP or tab
+ 1 if ... CR
+ 2 if ... ESC
+ 3 if ... ? (question mark)
+ 4 if ... : or = and called with brk != 0
+
+With:
+ pp pointing to beginning of word in buffer
+ bp pointing to after current position
+ atmbuf containing a copy of the word
+ cc containing the number of characters in the word copied to atmbuf
+*/
+
+int
+ungword() { /* Unget a word */
+ debug(F101,"ungword cmflgs","",cmflgs);
+ if (ungw) return(0);
+ cmfsav = cmflgs;
+ ungw = 1;
+ cmflgs = 0;
+ return(0);
+}
+
+/* Un-un-get word. Undo ungword() if it has been done. */
+
+VOID
+unungw() {
+ debug(F010,"unungw atmbuf",atmbuf,0);
+ if (ungw) {
+ ungw = 0;
+ cmflgs = cmfsav;
+ atmbuf[0] = NUL;
+ }
+}
+
+static int
+gtword(brk) int brk; {
+ int c; /* Current char */
+ int quote = 0; /* Flag for quote character */
+ int echof = 0; /* Flag for whether to echo */
+ int comment = 0; /* Flag for in comment */
+ char *cp = NULL; /* Comment pointer */
+ int eintr = 0; /* Flag for syscall interrupted */
+ int bracelvl = 0; /* nested brace counter [jrs] */
+ int iscontd = 0; /* Flag for continuation */
+ int realtty = 0; /* Stdin is really a tty */
+ char firstnb = NUL;
+ char lastchar = NUL;
+ char prevchar = NUL;
+ char lbrace, rbrace;
+ int dq = 0; /* Doublequote flag */
+ int dqn = 0; /* and count */
+ int isesc = 0;
+
+#ifdef RTU
+ extern int rtu_bug;
+#endif /* RTU */
+
+#ifdef IKSD
+ extern int inserver;
+#endif /* IKSD */
+ extern int kstartactive;
+
+#ifdef datageneral
+ extern int termtype; /* DG terminal type flag */
+ extern int con_reads_mt; /* Console read asynch is active */
+ if (con_reads_mt) connoi_mt(); /* Task would interfere w/cons read */
+#endif /* datageneral */
+
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"gtword brk","",brk);
+ debug(F101,"gtword cmfldflgs","",cmfldflgs);
+ debug(F101,"gtword swarg","",swarg);
+ debug(F101,"gtword dpx","",dpx);
+ debug(F101,"gtword echof","",echof);
+#ifndef NOSPL
+ debug(F101,"gtword askflag","",askflag);
+ debug(F101,"gtword timelimit","",timelimit);
+#ifndef NOLOCAL
+#ifndef NOXFER
+#ifdef CK_AUTODL
+ debug(F101,"gtword cmdadl","",cmdadl);
+#endif /* CK_AUTODL */
+#endif /* NOXFER */
+#endif /* NOLOCAL */
+#endif /* NOSPL */
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+
+ realtty = is_a_tty(0); /* Stdin is really a tty? */
+
+ if (cmfldflgs & 1) {
+ lbrace = '(';
+ rbrace = ')';
+ } else {
+ lbrace = '{';
+ rbrace = '}';
+ }
+ crflag = 0;
+ qmflag = 0;
+ esflag = 0;
+
+ if (swarg) { /* No leading space for switch args */
+ inword = 1;
+ swarg = 0;
+ }
+ if (ungw) { /* Have a word saved? */
+#ifdef M_UNGW
+ /* Experimental code to allow ungetting multiple words. */
+ /* See comments in ckmkey2() above. */
+ int x;
+ if (np > pp) pp = np;
+ while (*pp == SP) pp++;
+ if (!*pp) {
+ ungw = 0;
+ cmflgs = cmfsav;
+ } else {
+ if ((x = setatm(pp,2)) < 0) {
+ printf("?Saved word too long\n");
+ return(-9);
+ }
+ if (pp[x] >= SP) {
+ char *p2;
+ p2 = pp;
+ p2 += x;
+ while (*p2 == SP) p2++;
+ if (*p2) {
+ np = p2;
+ ungword();
+ }
+ } else {
+ ungw = 0;
+ cmflgs = cmfsav;
+ debug(F010,"gtword ungw return atmbuf",atmbuf,0);
+ }
+ }
+ return(cmflgs);
+#else
+ /*
+ You would think the following should be:
+ while (*pp == SP) pp++;
+ but you would be wrong -- making this change breaks GOTO.
+ */
+ while (*pp++ == SP) ;
+ if (setatm(pp,2) < 0) {
+ printf("?Saved word too long\n");
+ return(-9);
+ }
+ ungw = 0;
+ cmflgs = cmfsav;
+ debug(F010,"gtword ungw return atmbuf",atmbuf,0);
+ return(cmflgs);
+#endif /* M_UNGW */
+ }
+ pp = np; /* Start of current field */
+
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"gtword cmdbuf",cmdbuf,0);
+ debug(F110,"gtword bp",bp,0);
+ debug(F110,"gtword pp",pp,0);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ {
+ /* If we are reparsing we have to recount any braces or doublequotes */
+ char * p = pp;
+ char c;
+ if (*p == '"')
+ dq++;
+ while ((c = *p++))
+ if (c == lbrace)
+ bracelvl++;
+ else if (c == rbrace)
+ bracelvl--;
+ else if (dq && c == '"')
+ dqn++;
+ }
+ while (bp < cmdbuf+CMDBL) { /* Big get-a-character loop */
+ echof = 0; /* Assume we don't echo because */
+ chsrc = 0; /* character came from reparse buf. */
+#ifdef BS_DIRSEP
+CMDIRPARSE:
+#endif /* BS_DIRSEP */
+
+ c = *bp;
+ if (!c) { /* If no char waiting in reparse buf */
+ if ((dpx
+#ifndef NOSPL
+ || echostars
+#endif /* NOSPL */
+ ) && (!pushc
+#ifndef NOSPL
+ || askflag
+#endif /* NOSPL */
+ )) /* Get from tty, set echo flag */
+ echof = 1;
+ c = cmdgetc(timelimit); /* Read a command character. */
+#ifdef DEBUG
+ debug(F101,"gtword c","",c);
+#endif /* DEBUG */
+
+ if (timelimit && c < -1) { /* Timed out */
+ return(-10);
+ }
+
+#ifndef NOXFER
+/*
+ The following allows packet recognition in the command parser.
+ Presently it works only for Kermit packets, and if our current protocol
+ happens to be anything besides Kermit, we simply force it to Kermit.
+ We don't use the APC mechanism here for mechanical reasons, and also
+ because this way, it works even with minimally configured interactive
+ versions. Add Zmodem later...
+*/
+#ifdef CK_AUTODL
+ if ((!local && cmdadl) /* Autodownload enabled? */
+#ifdef IKS_OPTION
+ || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+#endif /* IKS_OPTION */
+ ) {
+ int k;
+ k = kstart((CHAR)c); /* Kermit S or I packet? */
+ if (k) {
+ int ksign = 0;
+ if (k < 0) { /* Minus-Protocol? */
+#ifdef NOSERVER
+ goto noserver; /* Need server mode for this */
+#else
+ ksign = 1; /* Remember */
+ k = 0 - k; /* Convert to actual protocol */
+ justone = 1; /* Flag for protocol module */
+#endif /* NOSERVER */
+ } else
+ justone = 0;
+ k--; /* Adjust kstart's return value */
+ if (k == PROTO_K) {
+ extern int protocol, g_proto;
+ extern CHAR sstate;
+ g_proto = protocol;
+ protocol = PROTO_K; /* Crude... */
+ sstate = ksign ? 'x' : 'v';
+ cmdbuf[0] = NUL;
+ return(-3);
+ }
+ }
+ }
+#ifdef NOSERVER
+ noserver:
+#endif /* NOSERVER */
+#endif /* CK_AUTODL */
+#endif /* NOXFER */
+
+ chsrc = 1; /* Remember character source is tty. */
+ brkchar = c;
+
+#ifdef IKSD
+ if (inserver && c < 0) { /* End of session? */
+ debug(F111,"gtword c < 0","exiting",c);
+ return(-4); /* Cleanup and terminate */
+ }
+#endif /* IKSD */
+
+#ifdef OS2
+ if (c < 0) { /* Error */
+ if (c == -3) { /* Empty word? */
+ if (blocklvl > 0) /* In a block */
+ continue; /* so keep looking for block end */
+ else
+ return(-3); /* Otherwise say we got nothing */
+ } else { /* Not empty word */
+ return(-4); /* So some kind of i/o error */
+ }
+ }
+#else
+#ifdef MAC
+ if (c == -3) /* Empty word... */
+ if (blocklvl > 0)
+ continue;
+ else
+ return(-3);
+#endif /* MAC */
+#endif /* OS2 */
+ if (c == EOF) { /* This can happen if stdin not tty. */
+#ifdef EINTR
+/*
+ Some operating and/or C runtime systems return EINTR for no good reason,
+ when the end of the standard input "file" is encountered. In cases like
+ this, we get into an infinite loop; hence the eintr counter, which is reset
+ to 0 upon each call to this routine.
+*/
+ debug(F101,"gtword EOF","",errno);
+ if (errno == EINTR && ++eintr < 4) /* When bg'd process is */
+ continue; /* fg'd again. */
+#endif /* EINTR */
+ return(-4);
+ }
+ c &= cmdmsk; /* Strip any parity bit */
+ } /* if desired. */
+
+/* Now we have the next character */
+
+ isesc = (c == ESC); /* A real ESC? */
+
+ if (!firstnb && c > SP) { /* First nonblank */
+ firstnb = c;
+ if (c == '"') /* Starts with doublequote */
+ dq = 1;
+ }
+ if (c == '"') /* Count doublequotes */
+ dqn++;
+
+ if (quote && (c == CR || c == LF)) { /* Enter key following quote */
+ *bp++ = CMDQ; /* Double it */
+ *bp = NUL;
+ quote = 0;
+ }
+ if (quote == 0) { /* If this is not a quoted character */
+ switch (c) {
+ case CMDQ: /* Got the quote character itself */
+ if (!comment && quoting)
+ quote = 1; /* Flag it if not in a comment */
+ break;
+ case FF: /* Formfeed. */
+ c = NL; /* Replace with newline */
+ cmdclrscn(); /* Clear the screen */
+ break;
+ case HT: /* Horizontal Tab */
+ if (comment) /* If in comment, */
+ c = SP; /* substitute space */
+ else /* otherwise */
+ c = ESC; /* substitute ESC (for completion) */
+ break;
+ case ';': /* Trailing comment */
+ case '#':
+ if (! (brk & 4) ) { /* If not keeping comments */
+ if (inword == 0 && quoting) { /* If not in a word */
+ comment = 1; /* start a comment. */
+ cp = bp; /* remember where it starts. */
+ }
+ }
+ break;
+ }
+ if (!kstartactive && /* Not in possible Kermit packet */
+ !comment && c == SP) { /* Space not in comment */
+ *bp++ = (char) c; /* deposit in buffer if not already */
+ /* debug(F101,"gtword echof 2","",echof); */
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ fflush(stdout);
+ fflush(stderr);
+ }
+#else
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ if (timelimit)
+ fflush(stdout);
+ }
+#endif /* BEBOX */
+ if (inword == 0) { /* If leading, gobble it. */
+ pp++;
+ continue;
+ } else { /* If terminating, return. */
+ if ((!dq && ((*pp != lbrace) || (bracelvl == 0))) ||
+ (dq && dqn > 1 && *(bp-2) == '"')) {
+ np = bp;
+ cmbptr = np;
+ if (setatm(pp,0) < 0) {
+ printf("?Field too long error 1\n");
+ debug(F111,"gtword too long #1",pp,strlen(pp));
+ return(-9);
+ }
+ brkchar = c;
+ inword = cmflgs = 0;
+ return(0);
+ }
+ continue;
+ }
+ }
+ if (c == lbrace) {
+ bracelvl++;
+ /* debug(F101,"gtword bracelvl++","",bracelvl); */
+ }
+ if (c == rbrace && bracelvl > 0) {
+ bracelvl--;
+ /* debug(F101,"gtword bracelvl--","",bracelvl); */
+ if (linebegin)
+ blocklvl--;
+ }
+ if ((c == '=' || c == ':') &&
+ /* ^^^ */
+ !kstartactive && !comment && brk /* && (firstnb == '/') */
+ ) {
+ *bp++ = (char) c; /* Switch argument separator */
+ /* debug(F111,"gtword switch argsep",cmdbuf,brk); */
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ fflush(stdout);
+ fflush(stderr);
+ }
+#else
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ if (timelimit)
+ fflush(stdout);
+ }
+#endif /* BEBOX */
+ if ((*pp != lbrace) || (bracelvl == 0)) {
+ np = bp;
+ cmbptr = np;
+ if (setatm(pp,2) < 0) { /* ^^^ */
+ printf("?Field too long error 1\n");
+ debug(F111,"gtword too long #1",pp,strlen(pp));
+ return(-9);
+ }
+ inword = cmflgs = 0;
+ brkchar = c;
+ return(4);
+ }
+ }
+ if (c == LF || c == CR) { /* CR or LF. */
+ if (echof) {
+ cmdnewl((char)c); /* echo it. */
+#ifdef BEBOX
+ fflush(stdout);
+ fflush(stderr);
+#endif /* BEBOX */
+ }
+ {
+ /* Trim trailing comment and whitespace */
+ char *qq;
+ if (comment) { /* Erase comment */
+ while (bp >= cp) /* Back to comment pointer */
+ *bp-- = NUL;
+ bp++;
+ pp = bp; /* Adjust other pointers */
+ inword = 0; /* and flags */
+ comment = 0;
+ cp = NULL;
+ }
+ qq = inword ? pp : (char *)cmdbuf;
+ /* Erase trailing whitespace */
+ while (bp > qq && (*(bp-1) == SP || *(bp-1) == HT)) {
+ bp--;
+ /* debug(F000,"erasing","",*bp); */
+ *bp = NUL;
+ }
+ lastchar = (bp > qq) ? *(bp-1) : NUL;
+ prevchar = (bp > qq+1) ? *(bp-2) : NUL;
+ }
+ if (linebegin && blocklvl > 0) /* Blank line in {...} block */
+ continue;
+
+ linebegin = 1; /* At beginning of next line */
+ iscontd = prevchar != CMDQ &&
+ (lastchar == '-' || lastchar == lbrace);
+ debug(F101,"gtword iscontd","",iscontd);
+
+ if (iscontd) { /* If line is continued... */
+ if (chsrc) { /* If reading from tty, */
+ if (*(bp-1) == lbrace) { /* Check for "begin block" */
+ *bp++ = SP; /* Insert a space for neatness */
+ blocklvl++; /* Count block nesting level */
+ } else { /* Or hyphen */
+ bp--; /* Overwrite the hyphen */
+ }
+ *bp = NUL; /* erase the dash, */
+ continue; /* and go back for next char now. */
+ }
+ } else if (blocklvl > 0) { /* No continuation character */
+ if (chsrc) { /* But we're in a "block" */
+ *bp++ = ','; /* Add comma */
+ *bp = NUL;
+ continue;
+ }
+ } else { /* No continuation, end of command. */
+ *bp = NUL; /* Terminate the command string. */
+ if (comment) { /* If we're in a comment, */
+ comment = 0; /* Say we're not any more, */
+ *cp = NUL; /* cut it off. */
+ }
+ np = bp; /* Where to start next field. */
+ cmbptr = np;
+ if (setatm(pp,0) < 0) { /* Copy field to atom buffer */
+ debug(F111,"gtword too long #2",pp,strlen(pp));
+ printf("?Field too long error 2\n");
+ return(-9);
+ }
+ inword = 0; /* Not in a word any more. */
+ crflag = 1;
+ /* debug(F110,"gtword","crflag is set",0); */
+#ifdef CK_RECALL
+ current = rlast;
+#endif /* CK_RECALL */
+ cmflgs = 1;
+ if (!xcmdsrc
+#ifdef CK_RECALL
+ || force_add
+#endif /* CK_RECALL */
+ )
+ addcmd(cmdbuf);
+ return(cmflgs);
+ }
+ }
+/*
+ This section handles interactive help, completion, editing, and history.
+ Rearranged as a switch statement executed only if we're at top level since
+ there is no need for any of this within command files and macros: Aug 2000.
+ Jun 2001: Even if at top level, skip this if the character was fetched from
+ the reparse or recall buffer, or if stdin is redirected.
+*/
+ if ((xcmdsrc == 0 /* Only at top level */
+#ifndef NOSPL
+ || askflag /* or user is typing ASK response */
+#endif /* NOSPL */
+ ) && chsrc != 0 && realtty) { /* from the real keyboard */
+
+/* Use ANSI / VT100 up and down arrow keys for command recall. */
+
+ if (isesc && (
+#ifdef IKSD
+ inserver
+#else
+ 0
+#endif /* IKSD */
+#ifdef USE_ARROWKEYS
+ || 1
+#endif /* USE_ARROWKEYS */
+ )
+ ) { /* A real ESC was typed */
+ int x;
+ msleep(200); /* Wait 1/5 sec */
+ x = cmdconchk(); /* Was it followed by anything? */
+ debug(F101,"Arrowkey ESC cmdconchk","",x);
+
+ if (x > 1) { /* If followed by at least 2 chars */
+ int c2;
+ c2 = cmdgetc(0); /* Get the first one */
+ debug(F101,"Arrowkey ESC c2","",c2);
+
+ if (c2 != '[' && c2 != 'O') { /* If not [ or O */
+ pushc = c2; /* Push it and take the ESC solo */
+ } else {
+ c2 = cmdgetc(0); /* Get the second one */
+ debug(F101,"Arrowkey ESC c3","",c2);
+ switch (c2) {
+#ifndef NORECALL
+ case 'A': /* Up */
+ c = BEL;
+ c = C_UP;
+ break;
+ case 'B': /* Down */
+ c = BEL;
+ c = C_DN;
+ break;
+ case 'C': /* Right */
+ case 'D': /* Left */
+#else
+ default:
+#endif /* NORECALL */
+ c = BEL; /* We don't use these yet */
+ break;
+ }
+ }
+ }
+ }
+
+ switch (c) {
+ case '?': /* ?-Help */
+#ifndef NOSPL
+ if (askflag) /* No help in ASK response */
+ break;
+#endif /* NOSPL */
+ if (quoting
+ && !kstartactive
+ && !comment
+ ) {
+ cmdecho((char) c, 0);
+ *bp = NUL;
+ if (setatm(pp,0) < 0) {
+ debug(F111,"gtword too long ?",pp,strlen(pp));
+ printf("?Too long\n");
+ return(-9);
+ }
+ qmflag = 1;
+ return(cmflgs = 3);
+ }
+
+ case ESC: /* Esc or Tab completion */
+ if (!comment) {
+ *bp = NUL;
+ if (setatm(pp,0) < 0) {
+ debug(F111,"gtword too long Esc",pp,strlen(pp));
+ printf("?Too long\n");
+ return(-9);
+ }
+ esflag = 1;
+ return(cmflgs = 2);
+ } else {
+ bleep(BP_WARN);
+ continue;
+ }
+
+ case BS: /* Character deletion */
+ case RUB:
+ if (bp > cmdbuf) { /* If still in buffer... */
+ cmdchardel(); /* erase it. */
+ bp--; /* point behind it, */
+ if (*bp == lbrace) bracelvl--; /* Adjust brace count */
+ if (*bp == rbrace) bracelvl++;
+ if ((*bp == SP) && /* Flag if current field gone */
+ (*pp != lbrace || bracelvl == 0))
+ inword = 0;
+ *bp = NUL; /* Erase character from buffer. */
+ } else { /* Otherwise, */
+ bleep(BP_WARN);
+ cmres(); /* and start parsing a new command. */
+ *bp = *atmbuf = NUL;
+ }
+ if (pp < bp)
+ continue;
+ else
+ return(cmflgs = -1);
+
+ case LDEL: /* ^U, line deletion */
+ while ((bp--) > cmdbuf) {
+ cmdchardel();
+ *bp = NUL;
+ }
+ cmres(); /* Restart the command. */
+ *bp = *atmbuf = NUL;
+ inword = 0;
+ return(cmflgs = -1);
+
+ case WDEL: /* ^W, word deletion */
+ if (bp <= cmdbuf) { /* Beep if nothing to delete */
+ bleep(BP_WARN);
+ cmres();
+ *bp = *atmbuf = NUL;
+ return(cmflgs = -1);
+ }
+ bp--;
+ /* Back up over any trailing nonalphanums */
+ /* This is dependent on ASCII collating sequence */
+ /* but isalphanum() is not available everywhere. */
+ for ( ;
+ (bp >= cmdbuf) &&
+ ((*bp < '0') ||
+ ((*bp > '9') && (*bp < '@')) ||
+ ((*bp > 'Z') && (*bp < 'a')) ||
+ (*bp > 'z'));
+ bp--
+ ) {
+ cmdchardel();
+ *bp = NUL;
+ }
+ /* Now delete back to rightmost remaining nonalphanum */
+ for ( ; (bp >= cmdbuf) && (*bp) ; bp--) {
+ if ((*bp < '0') ||
+ (*bp > '9' && *bp < '@') ||
+ (*bp > 'Z' && *bp < 'a') ||
+ (*bp > 'z'))
+ break;
+ cmdchardel();
+ *bp = NUL;
+ }
+ bp++;
+ inword = 0;
+ return(cmflgs = -1);
+
+ case RDIS: { /* ^R, redisplay */
+ char *cpx; char cx;
+ *bp = NUL;
+ printf("\n%s",cmprom);
+ cpx = cmdbuf;
+ while ((cx = *cpx++)) {
+ cmdecho(cx,0);
+ }
+ fflush(stdout);
+ continue;
+ }
+#ifndef NOLASTFILE
+ case VT:
+ if (lastfile) {
+ printf("%s ",lastfile);
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ inword = cmflgs = 0;
+ addbuf(lastfile); /* Supply default. */
+ if (setatm(lastfile,0) < 0) {
+ printf("Last name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ } else { /* No default */
+ bleep(BP_WARN);
+ }
+ return(0);
+#endif /* NOLASTFILE */
+ }
+
+#ifdef CK_RECALL
+ if (on_recall && /* Reading commands from keyboard? */
+ (cm_recall > 0) && /* Saving commands? */
+ (c == C_UP || c == C_UP2)) { /* Go up one */
+ if (last_recall == 2 && current > 0)
+ current--;
+ if (current < 0) { /* Nowhere to go, */
+ bleep(BP_WARN);
+ continue;
+ }
+ if (recall[current]) { /* We have a previous command */
+ while ((bp--) > cmdbuf) { /* Erase current line */
+ cmdchardel();
+ *bp = NUL;
+ }
+ ckstrncpy(cmdbuf,recall[current],CMDBL);
+#ifdef OSK
+ fflush(stdout);
+ write(fileno(stdout), "\r", 1);
+ printf("%s%s",cmprom,cmdbuf);
+#else
+ printf("\r%s%s",cmprom,cmdbuf);
+#endif /* OSK */
+ current--;
+ }
+ last_recall = 1;
+ return(cmflgs = -1); /* Force a reparse */
+ }
+ if (on_recall && /* Reading commands from keyboard? */
+ (cm_recall > 0) && /* Saving commands? */
+ (c == C_DN)) { /* Down one */
+ int x = 1;
+ if (last_recall == 1)
+ x++;
+ if (current + x > rlast) { /* Already at bottom, beep */
+ bleep(BP_WARN);
+ continue;
+ }
+ current += x; /* OK to go down */
+ if (recall[current]) {
+ while ((bp--) > cmdbuf) { /* Erase current line */
+ cmdchardel();
+ *bp = NUL;
+ }
+ ckstrncpy(cmdbuf,recall[current],CMDBL);
+#ifdef OSK
+ fflush(stdout);
+ write(fileno(stdout), "\r", 1);
+ printf("%s%s",cmprom,cmdbuf);
+#else
+ printf("\r%s%s",cmprom,cmdbuf);
+#endif /* OSK */
+ last_recall = 2;
+ return(cmflgs = -1); /* Force reparse */
+ }
+ }
+#endif /* CK_RECALL */
+ }
+
+ if (c < SP && quote == 0) { /* Any other unquoted control char */
+ if (!chsrc) { /* If cmd file, point past it */
+ bp++;
+ } else {
+ bleep(BP_WARN);
+ }
+ continue; /* continue, don't put in buffer */
+ }
+ linebegin = 0; /* Not at beginning of line */
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ fflush (stdout);
+ fflush(stderr);
+ }
+#else
+#ifdef NOSPL
+ if (echof || chsrc)
+#else
+ if (echof || (echostars && chsrc))
+#endif /* NOSPL */
+ cmdecho((char) c, 0); /* Echo what was typed. */
+#endif /* BEBOX */
+ } else { /* This character was quoted. */
+ int qf = 1;
+ quote = 0; /* Unset the quote flag. */
+ /* debug(F000,"gtword quote 0","",c); */
+ /* Quote character at this level is only for SP, ?, and controls */
+ /* If anything else was quoted, leave quote in, and let */
+ /* the command-specific parsing routines handle it, e.g. \007 */
+ if (c > 32 && c != '?' && c != RUB && chsrc != 0) {
+ /* debug(F000,"gtword quote 1","",c); */
+ *bp++ = CMDQ; /* Deposit \ if it came from tty */
+ qf = 0; /* and don't erase it from screen */
+ linebegin = 0; /* Not at beginning of line */
+#ifdef BS_DIRSEP
+/*
+ This is a hack to handle "cd \" or "cd foo\" on OS/2 and similar systems.
+ If we were called from cmdir() and the previous character was the quote
+ character, i.e. backslash, and this character is the command terminator,
+ then we stuff an extra backslash into the buffer without echoing, then
+ we stuff the carriage return back in again, and go back and process it,
+ this time with the quote flag off.
+*/
+ } else if (dirnamflg && (c == CR || c == LF || c == SP)) {
+ /* debug(F000,"gtword quote 2","",c); */
+ *bp++ = CMDQ;
+ linebegin = 0; /* Not at beginning of line */
+ *bp = (c == SP ? SP : CR);
+ goto CMDIRPARSE;
+#endif /* BS_DIRSEP */
+ }
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, qf); /* Echo what was typed. */
+ fflush (stdout);
+ fflush(stderr);
+ }
+#else
+ if (echof) cmdecho((char) c, qf); /* Now echo quoted character */
+#endif /* BEBOX */
+ /* debug(F111,"gtword quote",cmdbuf,c); */
+ }
+#ifdef COMMENT
+ if (echof) cmdecho((char) c,quote); /* Echo what was typed. */
+#endif /* COMMENT */
+ if (!comment) inword = 1; /* Flag we're in a word. */
+ if (quote) continue; /* Don't deposit quote character. */
+ if (c != NL) { /* Deposit command character. */
+ *bp++ = (char) c; /* and make sure there is a NUL */
+#ifdef COMMENT
+ *bp = NUL; /* after it */
+#endif /* COMMENT */
+ }
+ } /* End of big while */
+ bleep(BP_WARN);
+ printf("?Command too long, maximum length: %d.\n",CMDBL);
+ cmflgs = -2;
+ return(-9);
+}
+
+/* Utility functions */
+
+/* A D D B U F -- Add the string pointed to by cp to the command buffer */
+
+static int
+addbuf(cp) char *cp; {
+ int len = 0;
+ while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) {
+ *bp++ = *cp++; /* Copy and */
+ len++; /* count the characters. */
+ }
+ *bp++ = SP; /* Put a space at the end */
+ *bp = NUL; /* Terminate with a null */
+ np = bp; /* Update the next-field pointer */
+ cmbptr = np;
+ return(len); /* Return the length */
+}
+
+/* S E T A T M -- Deposit a token in the atom buffer. */
+/*
+ Break on space, newline, carriage return, or NUL.
+ Call with:
+ cp = Pointer to string to copy to atom buffer.
+ fcode = 0 means break on whitespace or EOL.
+ fcode = 1 means don't break on space.
+ fcode = 2 means break on space, ':', or '='.
+ fcode = 3 means copy the whole string.
+ Null-terminate the result.
+ Return length of token, and also set global "cc" to this length.
+ Return -1 if token was too long.
+*/
+static int
+setatm(cp,fcode) char *cp; int fcode; {
+ char *ap, *xp, *dqp = NULL, lbrace, rbrace;
+ int bracelvl = 0, dq = 0;
+
+ register char * s;
+ register int n = 0;
+
+ if (cmfldflgs & 1) { /* Handle grouping */
+ lbrace = '(';
+ rbrace = ')';
+ } else {
+ lbrace = '{';
+ rbrace = '}';
+ }
+ cc = 0; /* Character counter */
+ ap = atmbuf; /* Address of atom buffer */
+
+ s = cp;
+
+ while (*s++) n++; /* Save a call to strlen */
+
+ if (n > ATMBL) {
+ printf("?Command buffer overflow\n");
+ return(-1);
+ }
+ /* debug(F111,"setatm",cp,n); */
+ if (cp == ap) { /* In case source is atom buffer */
+ xp = atybuf; /* make a copy */
+#ifdef COMMENT
+ strncpy(xp,ap,ATMBL); /* so we can copy it back, edited. */
+ cp = xp;
+#else
+ s = ap;
+ while ((*xp++ = *s++)) ; /* We already know it's big enough */
+ cp = xp = atybuf;
+#endif /* COMMENT */
+ }
+ *ap = NUL; /* Zero the atom buffer */
+ if (fcode == 1) { /* Trim trailing blanks */
+ while (--n >= 0 && cp[n] == SP)
+ ;
+ cp[n+1] = NUL;
+ }
+ while (*cp == SP) { /* Trim leading spaces */
+ cp++;
+ n--;
+ }
+ if (*cp == '"') { /* Starts with doublequote? */
+ dq = 1;
+ dqp = cp;
+ }
+ while (*cp) {
+ if (*cp == lbrace)
+ bracelvl++;
+ else if (*cp == rbrace)
+ bracelvl--;
+ if (bracelvl < 0)
+ bracelvl = 0;
+ if (bracelvl == 0) {
+ if (dq) {
+ if (*cp == SP || *cp == HT) {
+ if (cp > dqp+1) {
+ if (*(cp-1) == '"' && *(cp-2) != CMDQ) {
+ break;
+ }
+ }
+ }
+ } else if ((*cp == SP || *cp == HT) && fcode != 1 && fcode != 3)
+ break;
+ if ((fcode == 2) && (*cp == '=' || *cp == ':')) break;
+ if ((fcode != 3) && (*cp == LF || *cp == CR)) break;
+ }
+ *ap++ = *cp++;
+ cc++;
+ }
+ *ap = NUL; /* Terminate the string. */
+ /* debug(F111,"setatm result",atmbuf,cc); */
+ return(cc); /* Return length. */
+}
+
+/*
+ These functions attempt to hide system dependencies from the mainline
+ code in gtword(). Dummy arg for cmdgetc() needed for compatibility with
+ coninc(), ttinc(), etc, since a pointer to this routine can be passed in
+ place of those to tn_doop().
+
+ No longer static. Used by askmore(). Fri Aug 20 15:03:34 1999.
+*/
+#define CMD_CONINC /* How we get keyboard chars */
+
+int
+cmdgetc(timelimit) int timelimit; { /* Get a character from the tty. */
+ int c;
+#ifdef IKSD
+ extern int inserver;
+#endif /* IKSD */
+#ifdef CK_LOGIN
+ extern int x_logged;
+#endif /* CK_LOGIN */
+#ifdef TNCODE
+ static int got_cr = 0;
+ extern int ckxech;
+ int tx = 0, is_tn = 0;
+#endif /* TNCODE */
+
+ if (pushc
+#ifndef NOSPL
+ && !askflag
+#endif /* NOSPL */
+ ) {
+ debug(F111,"cmdgetc()","pushc",pushc);
+ c = pushc;
+ pushc = NUL;
+ if (xcmfdb && c == '?') /* Don't echo ? twice if chaining. */
+ cmdchardel();
+ return(c);
+ }
+#ifdef datageneral
+ {
+ char ch;
+ c = dgncinb(0,&ch,1); /* -1 is EOF, -2 TO,
+ * -c is AOS/VS error */
+ if (c == -2) { /* timeout was enabled? */
+ resto(channel(0)); /* reset timeouts */
+ c = dgncinb(0,&ch,1); /* retry this now! */
+ }
+ if (c < 0) return(-4); /* EOF or some error */
+ else c = (int) ch & 0177; /* Get char without parity */
+/* echof = 1; */
+ }
+#else /* Not datageneral */
+#ifndef MINIX2
+ if (
+#ifdef IKSD
+ (!local && inserver) ||
+#endif /* IKSD */
+ timelimit > 0) {
+#ifdef TNCODE
+ GETNEXTCH:
+ is_tn = !pushc && !local && sstelnet;
+#endif /* TNCODE */
+#ifdef COMMENT
+ c = coninc(timelimit > 0 ? 1 : 0);
+#else /* COMMENT */
+ /* This is likely to break the asktimeout... */
+ c = coninc(timelimit);
+#endif /* COMMENT */
+ /* debug(F101,"cmdgetc coninc","",c); */
+#ifdef TNCODE
+ if (c >= 0 && is_tn) { /* Server-side Telnet */
+ switch (c) {
+ case IAC:
+ /* debug(F111,"gtword IAC","c",c); */
+ got_cr = 0;
+ if ((tx = tn_doop((CHAR)(c & 0xff),ckxech,coninc)) == 0) {
+ goto GETNEXTCH;
+ } else if (tx <= -1) { /* I/O error */
+ /* If there was a fatal I/O error then ttclos() */
+ /* has been called and the next GETNEXTCH attempt */
+ /* will be !is_tn since ttclos() sets sstelnet = 0 */
+ doexit(BAD_EXIT,-1); /* (or return(-4)? */
+ } else if (tx == 1) { /* ECHO change */
+ ckxech = dpx = 1; /* Get next char */
+ goto GETNEXTCH;
+ } else if (tx == 2) { /* ECHO change */
+ ckxech = dpx = 0; /* Get next char */
+ goto GETNEXTCH;
+ } else if (tx == 3) { /* Quoted IAC */
+ c = 255; /* proceeed with it. */
+ }
+#ifdef IKS_OPTION
+ else if (tx == 4) { /* IKS State Change */
+ goto GETNEXTCH;
+ }
+#endif /* IKS_OPTION */
+ else if (tx == 6) { /* Remote Logout */
+ doexit(GOOD_EXIT,0);
+ } else {
+ goto GETNEXTCH; /* Unknown, get next char */
+ }
+ break;
+#ifdef COMMENT
+ case CR:
+ if (!TELOPT_U(TELOPT_BINARY)) {
+ if (got_cr) {
+ /* This means the sender is violating Telnet */
+ /* protocol because we received two CRs in a */
+ /* row without getting either LF or NUL. */
+ /* This will not solve the problem but it */
+ /* will at least allow two CRs to do something */
+ /* whereas before the user would have to guess */
+ /* to send LF or NUL after the CR. */
+ debug(F100,"gtword CR telnet error","",0);
+ c = LF;
+ } else {
+ debug(F100,"gtword skipping CR","",0);
+ got_cr = 1; /* Remember a CR was received */
+ goto GETNEXTCH;
+ }
+ } else {
+ debug(F100,"gtword CR to LF","",0);
+ c = LF;
+ }
+ break;
+ case LF:
+ if (!TELOPT_U(TELOPT_BINARY)) {
+ got_cr = 0;
+ debug(F100,"gtword LF","",0);
+ } else {
+ if (got_cr) {
+ got_cr = 0;
+ debug(F100,"gtword skipping LF","",0);
+ goto GETNEXTCH;
+ }
+ }
+ break;
+ case NUL:
+ if (!TELOPT_U(TELOPT_BINARY) && got_cr) {
+ c = LF;
+ debug(F100,"gtword NUL to LF","",0);
+ } else {
+ debug(F100,"gtword NUL","",0);
+ }
+ got_cr = 0;
+ break;
+#else /* COMMENT */
+ case CR:
+ if ( !TELOPT_U(TELOPT_BINARY) && got_cr ) {
+ /* This means the sender is violating Telnet */
+ /* protocol because we received two CRs in a */
+ /* row without getting either LF or NUL. */
+ /* This will not solve the problem but it */
+ /* will at least allow two CRs to do something */
+ /* whereas before the user would have to guess */
+ /* to send LF or NUL after the CR. */
+ debug(F100,"gtword CR telnet error","",0);
+ } else {
+ got_cr = 1; /* Remember a CR was received */
+ }
+ /* debug(F100,"gtword CR to LF","",0); */
+ c = LF;
+ break;
+ case LF:
+ if (got_cr) {
+ got_cr = 0;
+ /* debug(F100,"gtword skipping LF","",0); */
+ goto GETNEXTCH;
+ }
+ break;
+ case NUL:
+ if (got_cr) {
+ got_cr = 0;
+ /* debug(F100,"gtword skipping NUL","",0); */
+ goto GETNEXTCH;
+#ifdef COMMENT
+ } else {
+ debug(F100,"gtword NUL","",0);
+#endif /* COMMENT */
+ }
+ break;
+#endif /* COMMENT */
+#ifdef IKSD
+ case ETX: /* Ctrl-C... */
+ case EOT: /* EOT = EOF */
+ if (inserver
+#ifdef CK_LOGIN
+ && !x_logged
+#endif /* CK_LOGIN */
+ )
+ return(-4);
+ break;
+#endif /* IKSD */
+ default:
+ got_cr = 0;
+ }
+ }
+#endif /* TNCODE */
+ } else {
+#ifdef OS2
+ c = coninc(0);
+#else /* OS2 */
+#ifdef CMD_CONINC
+#undef CMD_CONINC
+#endif /* CMD_CONINC */
+ c = getchar();
+#endif /* OS2 */
+ }
+#else /* MINIX2 */
+#undef getc
+#ifdef CMD_CONINC
+#undef CMD_CONINC
+#endif /* CMD_CONINC */
+ c = getc(stdin);
+ /* debug(F101,"cmdgetc getc","",c); */
+#endif /* MINIX2 */
+#ifdef RTU
+ if (rtu_bug) {
+#ifdef CMD_CONINC
+#undef CMD_CONINC
+#endif /* CMD_CONINC */
+ c = getchar(); /* RTU doesn't discard the ^Z */
+ rtu_bug = 0;
+ }
+#endif /* RTU */
+#endif /* datageneral */
+ return(c); /* Return what we got */
+}
+
+/* #ifdef USE_ARROWKEYS */
+
+/* Mechanism to use for peeking into stdin buffer */
+
+#ifndef USE_FILE_CNT /* stdin->__cnt */
+#ifndef USE_FILE__CNT /* Note: two underscores */
+#ifdef HPUX /* HPUX 7-11 */
+#ifndef HPUX5
+#ifndef HPUX6
+#define USE_FILE__CNT
+#endif /* HPUX6 */
+#endif /* HPUX5 */
+#else
+#ifdef ANYSCO /* SCO UNIX, OSR5, Unixware, etc */
+#ifndef OLD_UNIXWARE /* But not Unixware 1.x or 2.0 */
+#ifndef UNIXWARE2 /* or 2.1.0 */
+#define USE_FILE__CNT
+#endif /* UNIXWARE2 */
+#endif /* OLD_UNIXWARE */
+#endif /* ANYSCO */
+#endif /* HPUX */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+
+#ifndef USE_FILE_R /* stdin->_r */
+#ifndef USE_FILE_CNT
+#ifndef USE_FILE__CNT
+#ifdef BSD44 /* {Free,Open,Net}BSD, BSDI */
+#define USE_FILE_R
+#endif /* BSD44 */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+#endif /* USE_FILE_R */
+
+#ifndef USE_FILE_R /* stdin->_cnt */
+#ifndef USE_FILE_CNT
+#ifndef USE_FILE__CNT
+#define USE_FILE_CNT /* Everybody else (but Linux) */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+#endif /* USE_FILE_R */
+
+
+/*
+ c m d c o n c h k
+
+ How many characters are waiting to be read at the console? Normally
+ conchk() would tell us, but in Unix and VMS cmdgetc() uses stdio getchar(),
+ thus bypassing coninc()/conchk(), so we have to peek into the stdin buffer,
+ which is totally nonportable. Which is why this routine is, at least for
+ now, used only for checking for arrow-key sequences from the keyboard after
+ an ESC was read. Wouldn't it be nice if the stdio package had a function
+ that returned the number of bytes waiting to be read from its buffer?
+ Returns 0 or greater always.
+*/
+int
+cmdconchk() {
+ int x = 0, y;
+ y = pushc ? 1 : 0; /* Have command character pushed? */
+#ifdef OS2
+ x = conchk(); /* Check device-driver buffer */
+ if (x < 0) x = 0;
+#else /* OS2 */
+#ifdef CMD_CONINC /* See cmdgetc() */
+ x = conchk(); /* Check device-driver buffer */
+ if (x < 0) x = 0;
+#else /* CMD_CONINC */
+
+/* Here we must look inside the stdin buffer - highly platform dependent */
+
+#ifdef _IO_EOF_SEEN /* Linux */
+ x = (int) ((stdin->_IO_read_end) - (stdin->_IO_read_ptr));
+ debug(F101,"cmdconchk _IO_file_flags","",x);
+#else /* _IO_file_flags */
+#ifdef USE_FILE_CNT /* Traditional */
+#ifdef VMS
+ debug(F101,"cmdconchk (*stdin)->_cnt","",(*stdin)->_cnt);
+ x = (*stdin)->_cnt;
+#else
+#ifdef NOARROWKEYS
+ debug(F101,"cmdconchk NOARROWKEYS x","",0);
+#else
+ debug(F101,"cmdconchk stdin->_cnt","",stdin->_cnt);
+ x = stdin->_cnt;
+#endif /* NOARROWKEYS */
+#endif /* VMS */
+ if (x == 0) x = conchk();
+ if (x < 0) x = 0;
+#else /* USE_FILE_CNT */
+#ifdef USE_FILE__CNT /* HP-UX */
+ debug(F101,"cmdconchk stdin->__cnt","",stdin->__cnt);
+ x = stdin->__cnt;
+ if (x == 0) x = conchk();
+ if (x < 0) x = 0;
+#else /* USE_FILE_CNT */
+#ifdef USE_FILE_R /* FreeBSD, OpenBSD, etc */
+ debug(F101,"cmdconchk stdin->_r","",stdin->_r);
+ x = stdin->_r;
+ if (x == 0) x = conchk();
+ if (x < 0) x = 0;
+
+ /* Fill in any others here... */
+
+#endif /* USE_FILE_R */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+#endif /* _IO_file_flags */
+#endif /* CMD_CONINC */
+#endif /* OS2 */
+ return(x + y);
+}
+/* #endif */ /* USE_ARROWKEYS */
+
+
+static VOID
+cmdclrscn() { /* Clear the screen */
+ ck_cls();
+}
+
+static VOID /* What to echo at end of command */
+#ifdef CK_ANSIC
+cmdnewl(char c)
+#else
+cmdnewl(c) char c;
+#endif /* CK_ANSIC */
+/* cmdnewl */ {
+#ifdef OS2
+#ifdef IKSD
+ extern int inserver;
+ if (inserver && c == LF)
+ putchar(CR);
+#endif /* IKSD */
+#endif /* OS2 */
+
+ putchar(c); /* c is the terminating character */
+
+#ifdef WINTCP /* what is this doing here? */
+ if (c == CR) putchar(NL);
+#endif /* WINTCP */
+
+/*
+ A.A. Chernov, who sent in changes for FreeBSD, said we also needed this
+ for SVORPOSIX because "setup terminal by termios and curses does
+ not convert \r to \n, so additional \n needed in newline function." But
+ it is also very likely to result in unwanted blank lines.
+*/
+#ifdef BSD44
+ if (c == CR) putchar(NL);
+#endif /* BSD44 */
+
+#ifdef COMMENT
+ /* OS2 no longer needs this as all CR are converted to NL in coninc() */
+ /* This eliminates the ugly extra blank lines discussed above. */
+#ifdef OS2
+ if (c == CR) putchar(NL);
+#endif /* OS2 */
+#endif /* COMMENT */
+#ifdef aegis
+ if (c == CR) putchar(NL);
+#endif /* aegis */
+#ifdef AMIGA
+ if (c == CR) putchar(NL);
+#endif /* AMIGA */
+#ifdef datageneral
+ if (c == CR) putchar(NL);
+#endif /* datageneral */
+#ifdef GEMDOS
+ if (c == CR) putchar(NL);
+#endif /* GEMDOS */
+#ifdef STRATUS
+ if (c == CR) putchar(NL);
+#endif /* STRATUS */
+}
+
+static VOID
+cmdchardel() { /* Erase a character from the screen */
+#ifndef NOSPL
+ if (!echostars)
+#endif /* NOSPL */
+ if (!dpx) return;
+#ifdef datageneral
+ /* DG '\b' is EM (^y or \031) */
+ if (termtype == 1)
+ /* Erase a character from non-DG screen, */
+ dgncoub(1,"\010 \010",3);
+ else
+#endif /* datageneral */
+ printf("\b \b");
+#ifdef GEMDOS
+ fflush(stdout);
+#else
+#ifdef BEBOX
+ fflush(stdout);
+#endif /* BEBOX */
+#endif /* GEMDOS */
+}
+
+static VOID
+#ifdef CK_ANSIC
+cmdecho(char c, int quote)
+#else
+cmdecho(c,quote) char c; int quote;
+#endif /* CK_ANSIC */
+{ /* cmdecho */
+#ifdef NOSPL
+ if (!dpx) return;
+#else
+ if (!echostars) {
+ if (!dpx) return;
+ } else {
+ c = (char)echostars;
+ }
+#endif /* NOSPL */
+ /* Echo tty input character c */
+ if (quote) {
+ putchar(BS);
+ putchar(SP);
+ putchar(BS);
+#ifdef isprint
+ putchar((CHAR) (isprint(c) ? c : '^' ));
+#else
+ putchar((CHAR) ((c >= SP && c < DEL) ? c : '^'));
+#endif /* isprint */
+ } else {
+ putchar(c);
+ }
+#ifdef OS2
+ if (quote==1 && c==CR) putchar((CHAR) NL);
+#endif /* OS2 */
+ if (timelimit)
+ fflush(stdout);
+}
+
+/* Return pointer to current position in command buffer. */
+
+char *
+cmpeek() {
+ return(np);
+}
+#endif /* NOICP */
+
+
+#ifdef NOICP
+#include "ckcdeb.h"
+#include "ckucmd.h"
+#include "ckcasc.h"
+#endif /* NOICP */
+
+/* X X E S C -- Interprets backslash codes */
+/* Returns the int value of the backslash code if it is > -1 and < 256 */
+/* and updates the string pointer to first character after backslash code. */
+/* If the argument is invalid, leaves pointer unchanged and returns -1. */
+
+int
+xxesc(s) char **s; { /* Expand backslash escapes */
+ int x, y, brace, radix; /* Returns the int value */
+ char hd = '9'; /* Highest digit in radix */
+ char *p;
+
+ p = *s; /* pointer to beginning */
+ if (!p) return(-1); /* watch out for null pointer */
+ x = *p++; /* character at beginning */
+ if (x != CMDQ) return(-1); /* make sure it's a backslash code */
+
+ x = *p; /* it is, get the next character */
+ if (x == '{') { /* bracketed quantity? */
+ p++; /* begin past bracket */
+ x = *p;
+ brace = 1;
+ } else brace = 0;
+ switch (x) { /* Start interpreting */
+ case 'd': /* Decimal radix indicator */
+ case 'D':
+ p++; /* Just point past it and fall thru */
+ case '0': /* Starts with digit */
+ case '1':
+ case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ radix = 10; /* Decimal */
+ hd = '9'; /* highest valid digit */
+ break;
+ case 'o': /* Starts with o or O */
+ case 'O':
+ radix = 8; /* Octal */
+ hd = '7'; /* highest valid digit */
+ p++; /* point past radix indicator */
+ break;
+ case 'x': /* Starts with x or X */
+ case 'X':
+ radix = 16; /* Hexadecimal */
+ p++; /* point past radix indicator */
+ break;
+ default: /* All others */
+#ifdef COMMENT
+ *s = p+1; /* Treat as quote of next char */
+ return(*p);
+#else
+ return(-1);
+#endif /* COMMENT */
+ }
+ /* For OS/2, there are "wide" characters required for the keyboard
+ * binding, i.e \644 and similar codes larger than 255 (byte).
+ * For this purpose, give up checking for < 256. If someone means
+ * \266 should result in \26 followed by a "6" character, he should
+ * always write \{26}6 anyway. Now, return only the lower byte of
+ * the result, i.e. 10, but eat up the whole \266 sequence and
+ * put the wide result 266 into a global variable. Yes, that's not
+ * the most beautiful programming style but requires the least
+ * amount of changes to other routines.
+ */
+ if (*p == '{') { /* Sun May 11 20:00:40 2003 */
+ brace = 1; /* Allow {} after radix indicator */
+ p++;
+ }
+ if (radix <= 10) { /* Number in radix 8 or 10 */
+ for ( x = y = 0;
+ (*p) && (*p >= '0') && (*p <= hd)
+#ifdef OS2
+ && (y < 5) && (x*radix < KMSIZE);
+ /* the maximum needed value \8196 is 4 digits long */
+ /* while as octal it requires \1377, i.e. 5 digits */
+#else
+ && (y < 3) && (x*radix < 256);
+#endif /* OS2 */
+ p++,y++) {
+ x = x * radix + (int) *p - 48;
+ }
+#ifdef OS2
+ wideresult = x; /* Remember wide result */
+ x &= 255;
+#endif /* OS2 */
+ if (y == 0 || x > 255) { /* No valid digits? */
+ *s = p; /* point after it */
+ return(-1); /* return failure. */
+ }
+ } else if (radix == 16) { /* Special case for hex */
+ if ((x = unhex(*p++)) < 0) { *s = p - 1; return(-1); }
+ if ((y = unhex(*p++)) < 0) { *s = p - 2; return(-1); }
+ x = ((x << 4) & 0xF0) | (y & 0x0F);
+#ifdef OS2
+ wideresult = x;
+ if ((y = unhex(*p)) >= 0) {
+ p++;
+ wideresult = ((x << 4) & 0xFF0) | (y & 0x0F);
+ x = wideresult & 255;
+ }
+#endif /* OS2 */
+ } else x = -1;
+ if (brace && *p == '}' && x > -1) /* Point past closing brace, if any */
+ p++;
+ *s = p; /* Point to next char after sequence */
+ return(x); /* Return value of sequence */
+}
+
+int /* Convert hex string to int */
+#ifdef CK_ANSIC
+unhex(char x)
+#else
+unhex(x) char x;
+#endif /* CK_ANSIC */
+/* unhex */ {
+
+ if (x >= '0' && x <= '9') /* 0-9 is offset by hex 30 */
+ return(x - 0x30);
+ else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */
+ return(x - 0x37);
+ else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */
+ return(x - 0x57); /* (obviously ASCII dependent) */
+ else return(-1);
+}
+
+/* L O O K U P -- Lookup the string in the given array of strings */
+
+/*
+ Call this way: v = lookup(table,word,n,&x);
+
+ table - a 'struct keytab' table.
+ word - the target string to look up in the table.
+ n - the number of elements in the table.
+ x - address of an integer for returning the table array index,
+ or NULL if you don't need a table index.
+
+ The keyword table must be arranged in ascending alphabetical order;
+ alphabetic case doesn't matter but letters are treated as lowercase
+ for purposes of ordering; thus "^" and "_" come *before* the letters,
+ not after them.
+
+ Returns the keyword's associated value (zero or greater) if found,
+ with the variable x set to the keyword-table index. If is lookup()
+ is not successful, it returns:
+
+ -3 if nothing to look up (target was null),
+ -2 if ambiguous,
+ -1 if not found.
+
+ A match is successful if the target matches a keyword exactly, or if
+ the target is a prefix of exactly one keyword. It is ambiguous if the
+ target matches two or more keywords from the table.
+
+ Lookup() is the critical routine in scripts and so is optimized with a
+ simple static cache plus some other tricks. Maybe it could be improved
+ further with binary search or hash techniques but I doubt it since most
+ keyword tables are fairly short.
+*/
+
+#ifdef USE_LUCACHE /* Lookup cache */
+extern int lusize; /* (initialized in ckuus5.c) */
+extern char * lucmd[];
+extern int luval[];
+extern int luidx[];
+extern struct keytab * lutab[];
+long luhits = 0L;
+long lucalls = 0L;
+long xxhits = 0L;
+long luloop = 0L;
+#endif /* USE_LUCACHE */
+
+int
+lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; {
+
+ register int i, m;
+ int v, len, cmdlen = 0;
+ char c = NUL, c1, *s;
+
+/* Get 1st char of search object, if it's null return -3. */
+
+ if (!cmd || n < 1) /* Defense de nullarg */
+ return(-3);
+ c1 = *cmd; /* First character */
+ if (!c1) /* Make sure there is one */
+ return(-3);
+ if (isupper(c1)) /* If letter make it lowercase */
+ c1 = tolower(c1);
+
+#ifdef USE_LUCACHE /* lookup() cache */
+ m = lusize;
+ lucalls++; /* Count this lookup() call */
+ for (i = 0; i < m; i++) { /* Loop thru cache */
+ if (*(lucmd[i]) == c1) { /* Same as 1st char of search item? */
+ if (lutab[i] == table) { /* Yes - same table too? */
+ if (!strcmp(cmd,lucmd[i])) { /* Yes - compare */
+ if (x) *x = luidx[i]; /* Match - return index */
+ luhits++; /* Count cache hit */
+ return(luval[i]); /* Return associated value */
+ }
+ }
+ }
+ }
+#endif /* USE_LUCACHE */
+
+/* Not null, not in cache, look it up */
+
+ s = cmd;
+ while (*s++) cmdlen++; /* Length of target */
+/*
+ Quick binary search to find last table entry whose first character is
+ lexically less than the first character of the search object. This is
+ the starting point of the next loop, which must go in sequence since it
+ compares adjacent table entries.
+*/
+ if (n < 5) { /* Not worth it for small tables */
+ i = 0;
+ } else {
+ int lo = 0;
+ int hi = n;
+ int count = 0;
+ while (lo+2 < hi && ++count < 12) {
+ i = lo + ((hi - lo) / 2);
+ c = *(table[i].kwd);
+ if (isupper(c)) c = tolower(c);
+ if (c < c1) {
+ lo = i;
+ } else {
+ hi = i;
+ }
+ }
+ i = (c < c1) ? lo+1 : lo;
+#ifdef USE_LUCACHE
+ if (i > 0) xxhits++;
+#endif /* USE_LUCACHE */
+ }
+ for ( ; i < n-1; i++) {
+#ifdef USE_LUCACHE
+ luloop++;
+#endif /* USE_LUCACHE */
+ v = 0;
+ c = *(table[i].kwd);
+ if (c) {
+ if (isupper(c)) c = tolower(c);
+
+ /* The following is a big performance booster but makes it */
+ /* absolutely essential that all lookup() tables are in order. */
+
+ if (c > c1) /* Leave early if past our mark */
+ return(-1);
+
+#ifdef DEBUG
+ /* Use LOG DEBUG to check */
+
+ if (deblog) {
+ if (ckstrcmp(table[i].kwd,table[i+1].kwd,0,0) > 0) {
+ printf("TABLE OUT OF ORDER [%s] [%s]\n",
+ table[i].kwd,table[i+1].kwd);
+
+ }
+ }
+#endif /* DEBUG */
+
+ if (c == c1) {
+ len = 0;
+ s = table[i].kwd;
+ while (*s++) len++;
+ if ((len == cmdlen && !ckstrcmp(table[i].kwd,cmd,len,0)) ||
+ ((v = !ckstrcmp(table[i].kwd,cmd,cmdlen,0)) &&
+ ckstrcmp(table[i+1].kwd,cmd,cmdlen,0))) {
+ if (x) *x = i;
+ return(table[i].kwval);
+ }
+ } else v = 0;
+ }
+ if (v) { /* Ambiguous */
+ if (x) *x = i; /* Set index of first match */
+ return(-2);
+ }
+ }
+
+/* Last (or only) element */
+
+ if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0)) {
+ if (x) *x = n-1;
+ /* debug(F111,"lookup",table[i].kwd,table); */
+ return(table[n-1].kwval);
+ } else return(-1);
+}
+
+/*
+ x l o o k u p
+
+ Like lookup, but requires a full (but case-independent) match
+ and does NOT require the table to be in order.
+*/
+int
+xlookup(table,cmd,n,x) struct keytab table[]; char *cmd; int n, *x; {
+ register int i;
+ int len, cmdlen, one = 0;
+ register char c, c2, * s, * s2;
+
+ if (!cmd) cmd = ""; /* Check args */
+ if (!*cmd || n < 1) return(-3);
+
+ c = *cmd; /* First char of string to look up */
+ if (!*(cmd+1)) { /* Special handling for 1-char names */
+ cmdlen = 1;
+ if (isupper(c))
+ c = tolower(c);
+ one = 1;
+ } else {
+ cmdlen = 0;
+ s = cmd;
+ while (*s++) cmdlen++;
+ c = *cmd;
+ if (isupper(c))
+ c = tolower(c);
+ }
+ if (cmdlen < 1)
+ return(-3);
+
+ for (i = 0; i < n; i++) {
+ s = table[i].kwd; /* This entry */
+ if (!s) s = "";
+ if (!*s) continue; /* Empty table entry */
+ c2 = *s;
+ if (isupper(c2)) c2 = tolower(c2);
+ if (c != c2) continue; /* First char doesn't match */
+ if (one) { /* Name is one char long */
+ if (!*(s+1)) {
+ if (x) *x = i;
+ *cmd = c;
+ return(table[i].kwval); /* So is table entry */
+ }
+ } else { /* Otherwise do string comparison */
+ s2 = s;
+ len = 0;
+ while (*s2++) len++;
+ if (len == cmdlen && !ckstrcmp(s,cmd,-1,0)) {
+ if (x) *x = i;
+ return(table[i].kwval);
+ }
+ }
+ }
+ return(-1);
+}
+
+/* Reverse lookup */
+
+char *
+rlookup(table,n,x) struct keytab table[]; int n, x; {
+ int i;
+ for (i = 0; i < n; i++) {
+ if (table[i].kwval == x)
+ return(table[i].kwd);
+ }
+ return(NULL);
+}
+
+#ifndef NOICP
+int
+cmdsquo(x) int x; {
+ quoting = x;
+ return(1);
+}
+
+int
+cmdgquo() {
+ return(quoting);
+}
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.c.glibc2_28 b/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.c.glibc2_28
new file mode 100644
index 0000000..274dc2d
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.c.glibc2_28
@@ -0,0 +1,7919 @@
+#include "ckcsym.h"
+
+char *cmdv = "Command package 9.0.168, 12 March 2010";
+
+/* C K U C M D -- Interactive command package for Unix */
+
+/* (In reality, it's for all platforms, not just Unix) */
+
+/*
+ Author: Frank da Cruz (fdc@columbia.edu),
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+#define TOKPRECHECK
+
+#define DOCHKVAR
+
+/* Command-terminal-to-C-Kermit character mask */
+
+#ifdef OS2 /* K95 */
+int cmdmsk = 255; /* (always was 255) */
+#else /* All others... */
+int cmdmsk = 255; /* 31 Dec 2000 (was 127) */
+#endif /* OS2 */
+
+#ifdef BS_DIRSEP /* Directory separator is backslash */
+#undef BS_DIRSEP
+#endif /* BS_DIRSEP */
+
+#ifdef OS2
+#define BS_DIRSEP
+#endif /* BS_DIRSEP */
+
+#define CKUCMD_C
+
+#include "ckcdeb.h" /* Formats for debug(), etc. */
+#include "ckcker.h" /* Needed for BIGBUFOK definition */
+#include "ckcnet.h" /* Needed for server-side Telnet */
+#include "ckucmd.h" /* Needed for everything */
+#include "ckuusr.h" /* Needed for prompt length */
+
+#ifndef NOARROWKEYS
+#ifndef NOESCSEQ
+#ifdef VMSORUNIX
+#define USE_ARROWKEYS /* Use arrow keys for command recall */
+#endif /* VMSORUNIX */
+#endif /* NOESCSEQ */
+#endif /* NOARROWKEYS */
+
+#undef CKUCMD_C
+
+_PROTOTYP( int unhex, (char) );
+_PROTOTYP( static VOID cmdclrscn, (void) );
+
+#ifdef CKLEARN
+_PROTOTYP( VOID learncmd, (char *) );
+#endif /* CKLEARN */
+
+static char *moname[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+struct keytab cmonths[] = {
+ { "april", 4, 0 },
+ { "august", 8, 0 },
+ { "december", 12, 0 },
+ { "february", 2, 0 },
+ { "january", 1, 0 },
+ { "july", 7, 0 },
+ { "june", 6, 0 },
+ { "march", 3, 0 },
+ { "may", 5, 0 },
+ { "november", 11, 0 },
+ { "october", 10, 0 },
+ { "september", 9, 0 }
+};
+
+#ifndef NOICP /* The rest only if interactive command parsing selected */
+
+#ifndef NOSPL
+_PROTOTYP( int chkvar, (char *) );
+extern int askflag, echostars;
+#endif /* NOSPL */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+#ifdef IKSD
+extern int inserver;
+#endif /* IKSD */
+
+int cmfldflgs = 0; /* Flags for cmfld() */
+int cmkwflgs = 0; /* Flags from last keyword parse */
+static int nomsg = 0;
+static int blocklvl = 0; /* Block nesting level */
+static int linebegin = 0; /* Flag for at start of a line */
+static int quoting = 1; /* Quoting is allowed */
+static int swarg = 0; /* Parsing a switch argument */
+static int xcmfdb = 0; /* Flag for parsing chained fdbs... */
+static int chsrc = 0; /* Source of character, 1 = tty */
+static int newcmd = 0; /* See addcmd() */
+
+#ifdef BS_DIRSEP
+static int dirnamflg = 0;
+#endif /* BS_DIRSEP */
+
+/*
+Modeled after the DECSYSTEM-20 command parser (the COMND JSYS), RIP. Features:
+
+ . parses and verifies keywords, filenames, text strings, numbers, other data
+ . displays appropriate menu or help message when user types "?"
+ . does keyword and filename completion when user types ESC or TAB
+ . does partial keyword and filename completion
+ . accepts any unique abbreviation for a keyword
+ . allows keywords to have attributes, like "invisible" and "abbreviation"
+ . can supply defaults for fields omitted by user
+ . provides command retry and recall
+ . provides character, word, and line deletion (but only from the end)
+ . accepts input from keyboard, command files, macros, or redirected stdin
+ . allows for full or half duplex operation, character or line input
+ . allows \-escapes for special characters
+ . allows specification of a user exit to expand variables, etc.
+ . settable prompt, protected from deletion, dynamically re-evaluated each time
+ . allows chained parse functions.
+
+Functions:
+ cmsetp - Set prompt (cmprom is prompt string)
+ cmsavp - Save current prompt
+ cmgetp = Get current prompt
+ prompt - Issue prompt
+ cmini - Clear the command buffer (before parsing a new command)
+ cmres - Reset command buffer pointers (before reparsing)
+ cmkey - Parse a keyword or token (also cmkey2)
+ cmswi - Parse a switch
+ cmnum - Parse a number
+ cmifi - Parse an input file name
+ cmofi - Parse an output file name (also cmifip, cmifi2, ...)
+ cmdir - Parse a directory name (also cmdirp)
+ cmfld - Parse an arbitrary field
+ cmtxt - Parse a text string
+ cmdate - Parse a date-time string
+ cmcfm - Parse command confirmation (end of line)
+ cmfdb - Parse any of a list of the foregoing (chained parse functions)
+
+Return codes:
+ -9: like -2 except this module already printed the error message
+ -3: no input provided when required
+ -2: input was invalid (e.g. not a number when a number was required)
+ -1: reparse required (user deleted into a preceding field)
+ 0 or greater: success
+See individual functions for greater detail.
+
+Before using these routines, the caller should #include "ckucmd.h" and set the
+program's prompt by calling cmsetp(). If the file parsing functions cmifi,
+cmofi, or cmdir are to be used, this module must be linked with a ck?fio file
+system support module for the appropriate system, e.g. ckufio for Unix. If
+the caller puts the terminal in character wakeup ("cbreak") mode with no echo,
+then these functions will provide line editing -- character, word, and line
+deletion, as well as keyword and filename completion upon ESC and help
+strings, keyword, or file menus upon '?'. If the caller puts the terminal
+into character wakeup/noecho mode, care should be taken to restore it before
+exit from or interruption of the program. If the character wakeup mode is not
+set, the system's own line editor may be used.
+
+NOTE: Contrary to expectations, many #ifdef's have been added to this module.
+Any operation requiring an #ifdef (like clear screen, get character from
+keyboard, erase character from screen, etc) should eventually be turned into a
+call to a function that is defined in ck?tio.c, but then all the ck?tio.c
+modules would have to be changed...
+*/
+
+/* Includes */
+
+#include "ckcker.h"
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckucmd.h" /* Command parsing definitions */
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#endif /* NT */
+#include "ckocon.h"
+#include <io.h>
+#endif /* OS2 */
+
+#ifdef OSK
+#define cc ccount /* OS-9/68K compiler bug */
+#endif /* OSK */
+
+#ifdef GEMDOS /* Atari ST */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#endif /* GEMDOS */
+
+#ifdef CK_AUTODL
+extern int cmdadl, justone;
+#endif /* CK_AUTODL */
+
+extern int timelimit, nzxopts, nopush, nolocal, xcmdsrc, keepallchars;
+
+#ifdef CKSYSLOG
+#ifdef UNIX
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in syslog.h */
+#endif /* CKXPRINTF */
+#ifdef RTAIX
+#include <sys/syslog.h>
+#else /* RTAIX */
+#include <syslog.h>
+#endif /* RTAIX */
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#endif /* UNIX */
+#endif /* CKSYSLOG */
+
+/* Local variables */
+
+static
+int psetf = 0, /* Flag that prompt has been set */
+ cc = 0, /* Character count */
+ dpx = 0, /* Duplex (0 = full) */
+ inword = 0; /* In the middle of getting a word */
+
+char *dfprom = "Command? "; /* Default prompt */
+#ifndef NOLASTFILE
+char *lastfile = NULL; /* Last filespec */
+static char *tmplastfile = NULL; /* Last filespec candidate */
+#endif /* NOLASTFILE */
+
+int cmflgs; /* Command flags */
+int cmfsav; /* A saved version of them */
+
+static char pushc = NUL;
+static char brkchar = NUL;
+
+#define CMDEFAULT 1023
+static char cmdefault[CMDEFAULT+1];
+
+#ifdef DCMDBUF
+char *cmdbuf = NULL; /* Command buffer */
+char *savbuf = NULL; /* Buffer to save copy of command */
+char *atmbuf = NULL; /* Atom buffer - for current field */
+char *atxbuf = NULL; /* For expanding the atom buffer */
+char *prevcmd = NULL;
+static char *atybuf = NULL; /* For copying atom buffer */
+static char *filbuf = NULL; /* File name buffer */
+static char *cmprom = NULL; /* Program's prompt */
+static char *cmprxx = NULL; /* Program's prompt, unevaluated */
+
+#ifdef CK_RECALL
+/*
+ Command recall is available only if we can make profligate use of malloc().
+*/
+#define R_MAX 10 /* How many commands to save */
+int cm_recall = R_MAX; /* Size of command recall buffer */
+int on_recall = 1; /* Recall feature is ON */
+static int no_recall = 0; /* Recall OFF for this cmd only */
+static int force_add = 0; /* Force cmd into recall buffer */
+static int last_recall = -1; /* Last recall-related action */
+/*
+ -1 = none
+ 0 = CR (a command was entered)
+ 1 = Up
+ 2 = Down
+*/
+int in_recall = 0; /* Recall buffers are init'd */
+static int
+ current = -1, /* Pointer to current command */
+ rlast = -1; /* Index of last command in buffer */
+static char **recall = NULL; /* Array of recall buffer pointers */
+#endif /* CK_RECALL */
+#else /* !DCMDBUF */
+char cmdbuf[CMDBL+4]; /* Command buffer */
+char savbuf[CMDBL+4]; /* Buffer to save copy of command */
+char atmbuf[ATMBL+4]; /* Atom buffer */
+char atxbuf[CMDBL+4]; /* For expanding the atom buffer */
+char prevcmd[CMDBL+4]; /* For displaying the last command */
+static char atybuf[ATMBL+4]; /* For copying atom buffer */
+static char filbuf[ATMBL+4]; /* File name buffer */
+static char cmprom[PROMPTL+1]; /* Program's prompt */
+static char cmprxx[PROMPTL+1]; /* Program's prompt, unevaluated */
+#endif /* DCMDBUF */
+
+/* Command buffer pointers */
+
+#define PPVLEN VNAML /* 20080305 Wolfram Sang (was 24) */
+char ppvnambuf[PPVLEN+1] = { NUL, NUL };
+
+char * cmbptr = NULL; /* Current position (for export) */
+
+static char *bp, /* Current command buffer position */
+ *pp, /* Start of current field */
+ *np; /* Start of next field */
+
+static int ungw, /* For ungetting words */
+ atxn; /* Expansion buffer (atxbuf) length */
+
+#ifdef OS2
+extern int wideresult;
+#endif /* OS2 */
+
+extern int cmd_cols, cmd_rows, local, quiet;
+
+#ifdef TNCODE
+#ifdef IAC
+#undef IAC
+#endif /* IAC */
+#define IAC 255
+#endif /* TNCODE */
+
+_PROTOTYP( static int gtword, (int) );
+_PROTOTYP( static int addbuf, (char *) );
+_PROTOTYP( static int setatm, (char *, int) );
+_PROTOTYP( static VOID cmdnewl, (char) );
+_PROTOTYP( static VOID cmdchardel, (void) );
+_PROTOTYP( static VOID cmdecho, (char, int) );
+_PROTOTYP( static int test, (int, int) );
+#ifdef GEMDOS
+_PROTOTYP( extern char *strchr, (char *, int) );
+#endif /* GEMDOS */
+
+extern char * dftty;
+
+/* The following are for use with chained FDB's */
+
+static int crflag = 0; /* Carriage return was typed */
+static int qmflag = 0; /* Question mark was typed */
+static int esflag = 0; /* Escape was typed */
+
+/* Directory separator */
+
+#ifdef GEMDOS
+static char dirsep = '\\';
+#else
+#ifdef datageneral
+static char dirsep = ':';
+#else
+#ifdef MAC
+static char dirsep = ':';
+#else
+#ifdef VMS
+static char dirsep = '.';
+#else
+#ifdef STRATUS
+static char dirsep = '>';
+#else
+static char dirsep = '/'; /* UNIX, OS/2, OS-9, Amiga, etc. */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* MAC */
+#endif /* datageneral */
+#endif /* GEMDOS */
+
+/* H A S N O P A T H */
+
+/* Returns 0 if filespec s includes any path segments; 1 if it doesn't. */
+
+int
+hasnopath(s) char * s; {
+ char * p = NULL;
+ if (!s) return(0);
+ if (!*s) return(0);
+ zstrip(s,&p);
+ return(ckstrcmp(s,p,CKMAXPATH,filecase) == 0 ? 1 : 0);
+}
+
+/* C K S P R E A D -- Print string double-spaced */
+
+static char * sprptr = NULL;
+
+static char *
+ckspread(s) char * s; {
+ int n = 0;
+ char * p;
+ n = strlen(s);
+ if (sprptr)
+ free(sprptr);
+ sprptr = malloc(n + n + 3);
+ if (sprptr) {
+ p = sprptr;
+ while (*s) {
+ *p++ = *s++;
+ *p++ = SP;
+ }
+ *p = NUL;
+ }
+ return(sprptr ? sprptr : "");
+}
+
+/* T E S T -- Bit test */
+
+static int
+test(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */
+ return((x & m) ? 1 : 0);
+}
+
+/* K W D H E L P -- Given a keyword table, print keywords in columns. */
+/*
+ Call with:
+ s - keyword table
+ n - number of entries
+ pat - pattern (left substring) that must match for each keyword
+ pre - prefix to add to each keyword
+ post - suffix to add to each keyword
+ off - offset on first screenful, allowing room for introductory text
+ xhlp - 1 to print any CM_INV keywords that are not also abbreviations.
+ 2 to print CM_INV keywords if CM_HLP also set
+ 4 if it's a switch table (to show ':' if CM_ARG)
+
+ Arranges keywords in columns with width based on longest keyword.
+ Does "more?" prompting at end of screen.
+ Uses global cmd_rows and cmd_cols for screen size.
+*/
+VOID
+kwdhelp(s,n,pat,pre,post,off,xhlp)
+ struct keytab s[]; int n, off, xhlp; char *pat, *pre, *post;
+/* kwdhelp */ {
+
+ int width = 0;
+ int cc;
+ int cols, height, i, j, k, lc, n2 = 0;
+ char *b = NULL, *p, *q;
+ char *pa, *px;
+ char **s2 = NULL;
+ char *tmpbuf = NULL;
+
+ cc = strlen(pat);
+
+ if (!s) return; /* Nothing to do */
+ if (n < 1) return; /* Ditto */
+ if (off < 0) off = 0; /* Offset for first page */
+ if (!pre) pre = ""; /* Handle null string pointers */
+ if (!post) post = "";
+ lc = off; /* Screen-line counter */
+
+ if (xhlp & 4) /* For switches */
+ tmpbuf = (char *)malloc(TMPBUFSIZ+1);
+
+ if ((s2 = (char **) malloc(n * sizeof(char *)))) {
+ for (i = 0; i < n; i++) { /* Find longest keyword */
+ s2[i] = NULL;
+ if (ckstrcmp(s[i].kwd,pat,cc,0))
+ continue;
+
+ if (s[i].flgs & CM_PSH /* NOPUSH or nopush screening */
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ )
+ continue;
+ if (s[i].flgs & CM_LOC /* NOLOCAL or nolocal screening */
+#ifndef NOLOCAL
+ && nolocal
+#endif /* NOLOCAL */
+ )
+ continue;
+
+ if (s[i].flgs & CM_INV) {
+#ifdef COMMENT
+/* This code does not show invisible keywords at all except for "help ?" */
+/* and then only help topics (CM_HLP) in the top-level keyword list. */
+
+ if ((xhlp & 2) == 0)
+ continue;
+ else if ((s[i].flgs & CM_HLP) == 0)
+ continue;
+#else
+/* This code shows invisible keywords that are not also abbreviations when */
+/* ? was typed AFTER the beginning of the field so the user can find out */
+/* what they are and (for example) why completion doesn't work at this point */
+
+ if (s[i].flgs & CM_ABR)
+ continue;
+ else if ((xhlp & 3) == 0)
+ continue;
+ else if ((xhlp & 2) && ((s[i].flgs & CM_HLP) == 0))
+ continue;
+#endif /* COMMENT */
+ }
+ j = strlen(s[i].kwd);
+ if (!(xhlp & 4) || !tmpbuf) { /* Regular keyword table */
+ s2[n2++] = s[i].kwd; /* Copy pointers to visible ones */
+ } else { /* Switches */
+ ckmakmsg(tmpbuf, /* Make a copy that shows ":" if */
+ TMPBUFSIZ, /* the switch takes an argument. */
+ s[i].kwd,
+ (s[i].flgs & CM_ARG) ? ":" : "",
+ NULL,
+ NULL
+ );
+ makestr(&(s2[n2]),tmpbuf);
+ if (s[i].flgs & CM_ARG) j++;
+ n2++;
+ }
+ if (j > width)
+ width = j;
+ }
+ /* Column width */
+ n = n2;
+ }
+ if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
+ char * bx;
+ bx = b + cmd_cols;
+ width += (int)strlen(pre) + (int)strlen(post) + 2;
+ cols = cmd_cols / width; /* How many columns? */
+ if (cols < 1) cols = 1;
+ height = n / cols; /* How long is each column? */
+ if (n % cols) height++; /* Add one for remainder, if any */
+
+ for (i = 0; i < height; i++) { /* Loop for each row */
+ for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */
+ b[j] = SP;
+ for (j = 0; j < cols; j++) { /* Loop for each column in row */
+ k = i + (j * height); /* Index of next keyword */
+ if (k < n) { /* In range? */
+ pa = pre;
+ px = post;
+ p = s2[k]; /* Point to verb name */
+ q = b + (j * width) + 1; /* Where to copy it to */
+ while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
+ if (j < cols - 1) {
+ q--;
+ *q = SP; /* Replace the space */
+ }
+ }
+ }
+ p = b + cmd_cols - 1; /* Last char in line */
+ while (*p-- == SP) ; /* Trim */
+ *(p+2) = NUL;
+ printf("%s\n",b); /* Print the line */
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) /* Do more-prompting... */
+ goto xkwdhelp;
+ else
+ lc = 0;
+ }
+ }
+ /* printf("\n"); */ /* Blank line at end of report */
+ } else { /* Malloc failure, no columns */
+ for (i = 0; i < n; i++) {
+ if (s[i].flgs & CM_INV) /* Use original keyword table */
+ continue; /* skipping invisible entries */
+ printf("%s%s%s\n",pre,s[i].kwd,post);
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) /* Do more-prompting... */
+ goto xkwdhelp;
+ else
+ lc = 0;
+ }
+ }
+ }
+ xkwdhelp:
+ if (xhlp & 4) {
+ if (tmpbuf) free((char *)tmpbuf);
+ for (i = 0; i < n; i++)
+ if (s2[i]) free(s2[i]);
+ }
+ if (s2) free(s2); /* Free array copy */
+ if (b) free(b); /* Free line buffer */
+ return;
+}
+
+/* X F I L H E L P -- Given a file list, print names in columns. */
+/*
+ Call with:
+ n - number of entries
+ pre - prefix to add to each filename
+ post - suffix to add to each filename
+ off - offset on first screenful, allowing room for introductory text
+ cmdirflg - 1 if only directory names should be listed, 0 to list all files
+ fs - call fileselect() to decide whether to include each file.
+ The rest of the args are the same as for fileselect().
+
+ Arranges filenames in columns with width based on longest filename.
+ Does "more?" prompting at end of screen.
+ Uses global cmd_rows and cmd_cols for screen size.
+*/
+
+int
+#ifdef CK_ANSIC
+xfilhelp(
+ int n, char *pre, char *post, int off, int cmdirflag,
+ int fs, char *sa, char *sb, char *sna, char *snb,
+ CK_OFF_T minsiz, CK_OFF_T maxsiz,
+ int nbu, int nxlist,
+ char ** xlist
+)
+#else
+xfilhelp(n,pre,post,off,cmdirflg,
+ fs,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
+ int n, off; char *pre, *post; int cmdirflg;
+ int fs; char *sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
+ int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+ {
+ char filbuf[CKMAXPATH + 1]; /* Temp buffer for one filename */
+ int width = 0;
+ int cols, height, i, j, k, lc, n2 = 0, rc = 0, itsadir = 0;
+ char *b = NULL, *p, *q;
+ char *pa, *px;
+ char **s2 = NULL;
+#ifdef VMS
+ char * cdp = zgtdir();
+#endif /* VMS */
+
+ if (n < 1) return(0);
+ if (off < 0) off = 0; /* Offset for first page */
+ if (!pre) pre = ""; /* Handle null string pointers */
+ if (!post) post = "";
+
+ lc = off; /* Screen-line counter */
+
+ if ((s2 = (char **) malloc(n * sizeof(char *)))) {
+ for (i = 0; i < n; i++) { /* Loop through filenames */
+ itsadir = 0;
+ s2[i] = NULL; /* Initialize each pointer to NULL */
+ znext(filbuf); /* Get next filename */
+ if (!filbuf[0]) /* Shouldn't happen */
+ break;
+#ifdef COMMENT
+ itsadir = isdir(filbuf); /* Is it a directory? */
+ if (cmdirflg && !itsadir) /* No, listing directories only? */
+ continue; /* So skip this one. */
+#endif /* COMMENT */
+ if (fs) if (fileselect(filbuf,
+ sa,sb,sna,snb,
+ minsiz,maxsiz,nbu,nxlist,xlist) < 1) {
+ continue;
+ }
+#ifdef VMS
+ ckstrncpy(filbuf,zrelname(filbuf,cdp),CKMAXPATH);
+#endif /* VMS */
+ j = strlen(filbuf);
+#ifndef VMS
+ if (itsadir && j < CKMAXPATH - 1 && j > 0) {
+ if (filbuf[j-1] != dirsep) {
+ filbuf[j++] = dirsep;
+ filbuf[j] = NUL;
+ }
+ }
+#endif /* VMS */
+ if (!(s2[n2] = malloc(j+1))) {
+ printf("?Memory allocation failure\n");
+ rc = -9;
+ goto xfilhelp;
+ }
+ if (j <= CKMAXPATH) {
+ strcpy(s2[n2],filbuf);
+ n2++;
+ } else {
+ printf("?Name too long - %s\n", filbuf);
+ rc = -9;
+ goto xfilhelp;
+ }
+ if (j > width) /* Get width of widest one */
+ width = j;
+ }
+ n = n2; /* How many we actually got */
+ }
+ sh_sort(s2,NULL,n,0,0,filecase); /* Alphabetize the list */
+
+ rc = 1;
+ if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
+ char * bx;
+ bx = b + cmd_cols;
+ width += (int)strlen(pre) + (int)strlen(post) + 2;
+ cols = cmd_cols / width; /* How many columns? */
+ if (cols < 1) cols = 1;
+ height = n / cols; /* How long is each column? */
+ if (n % cols) height++; /* Add one for remainder, if any */
+
+ for (i = 0; i < height; i++) { /* Loop for each row */
+ for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */
+ b[j] = SP;
+ for (j = 0; j < cols; j++) { /* Loop for each column in row */
+ k = i + (j * height); /* Index of next filename */
+ if (k < n) { /* In range? */
+ pa = pre;
+ px = post;
+ p = s2[k]; /* Point to filename */
+ q = b + (j * width) + 1; /* and destination */
+ while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */
+ q--; /* Back up over NUL */
+ while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
+ if (j < cols - 1) {
+ q--;
+ *q = SP; /* Replace the space */
+ }
+ }
+ }
+ p = b + cmd_cols - 1; /* Last char in line */
+ while (*p-- == SP) ; /* Trim */
+ *(p+2) = NUL;
+ printf("%s\n",b); /* Print the line */
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) { /* Do more-prompting... */
+ rc = 0;
+ goto xfilhelp;
+ } else
+ lc = 0;
+ }
+ }
+ printf("\n"); /* Blank line at end of report */
+ goto xfilhelp;
+ } else { /* Malloc failure, no columns */
+ for (i = 0; i < n; i++) {
+ znext(filbuf);
+ if (!filbuf[0]) break;
+ printf("%s%s%s\n",pre,filbuf,post);
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) { /* Do more-prompting... */
+ rc = 0;
+ goto xfilhelp;
+ } else lc = 0;
+ }
+ }
+xfilhelp:
+ if (b) free(b);
+ for (i = 0; i < n2; i++)
+ if (s2[i]) free(s2[i]);
+ if (s2) free((char *)s2);
+ return(rc);
+ }
+}
+
+/*
+ Simpler front end for xfilhelp() with shorter arg list when no
+ file selection is needed.
+*/
+int
+filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
+ return(xfilhelp(n,pre,post,off,cmdirflg,
+ 0,NULL,NULL,NULL,NULL,
+ (CK_OFF_T)0,(CK_OFF_T)0,0,0,(char **)NULL));
+}
+
+/* C M S E T U P -- Set up command buffers */
+
+#ifdef DCMDBUF
+int
+cmsetup() {
+ if (!(cmdbuf = malloc(CMDBL + 4))) return(-1);
+ if (!(savbuf = malloc(CMDBL + 4))) return(-1);
+ savbuf[0] = '\0';
+ if (!(prevcmd = malloc(CMDBL + 4))) return(-1);
+ prevcmd[0] = '\0';
+ if (!(atmbuf = malloc(ATMBL + 4))) return(-1);
+ if (!(atxbuf = malloc(CMDBL + 4))) return(-1);
+ if (!(atybuf = malloc(ATMBL + 4))) return(-1);
+ if (!(filbuf = malloc(ATMBL + 4))) return(-1);
+ if (!(cmprom = malloc(PROMPTL + 4))) return(-1);
+ if (!(cmprxx = malloc(PROMPTL + 4))) return(-1);
+#ifdef CK_RECALL
+ cmrini(cm_recall);
+#endif /* CK_RECALL */
+ return(0);
+}
+#endif /* DCMDBUF */
+
+/* C M S E T P -- Set the program prompt. */
+
+VOID
+cmsetp(s) char *s; {
+ if (!s) s = "";
+ ckstrncpy(cmprxx,s,PROMPTL);
+ psetf = 1; /* Flag that prompt has been set. */
+}
+
+/* C M S A V P -- Save a copy of the current prompt. */
+
+VOID
+#ifdef CK_ANSIC
+cmsavp(char s[], int n)
+#else
+cmsavp(s,n) char s[]; int n;
+#endif /* CK_ANSIC */
+/* cmsavp */ {
+ if (psetf) /* But not if no prompt is set. */
+ ckstrncpy(s,cmprxx,n);
+}
+
+char *
+cmgetp() {
+ return(cmprxx);
+}
+
+int
+cmgbrk() {
+ return(brkchar);
+}
+
+int
+cmgkwflgs() {
+ return(cmkwflgs);
+}
+
+/* P R O M P T -- Issue the program prompt. */
+
+VOID
+prompt(f) xx_strp f; {
+ char *sx, *sy; int n;
+#ifdef CK_SSL
+ extern int ssl_active_flag, tls_active_flag;
+#endif /* CK_SSL */
+#ifdef OS2
+ extern int display_demo;
+
+ /* If there is a demo screen to be displayed, display it */
+ if (display_demo && xcmdsrc == 0) {
+ demoscrn(VCMD);
+ display_demo = 0;
+ }
+#endif /* OS2 */
+
+ if (psetf == 0) /* If no prompt set, set default. */
+ cmsetp(dfprom);
+
+ sx = cmprxx; /* Unevaluated copy */
+ if (f) { /* If conversion function given */
+ sy = cmprom; /* Evaluate it */
+#ifdef COMMENT
+ debug(F101,"prompt sx","",sx);
+ debug(F101,"prompt sy","",sy);
+#endif /* COMMENT */
+ n = PROMPTL;
+ if ((*f)(sx,&sy,&n) < 0) /* If evaluation failed */
+ sx = cmprxx; /* revert to unevaluated copy */
+ else if (!*cmprom) /* ditto if it came up empty */
+ sx = cmprxx;
+ else
+ sx = cmprom;
+ } else
+ ckstrncpy(cmprom,sx,PROMPTL);
+ cmprom[PROMPTL-1] = NUL;
+ if (!*sx) /* Don't print if empty */
+ return;
+
+#ifdef OSK
+ fputs(sx, stdout);
+#else
+#ifdef MAC
+ printf("%s", sx);
+#else
+#ifdef IKSD
+ if (inserver) { /* Print the prompt. */
+ ttoc(CR); /* If TELNET Server */
+ ttoc(NUL); /* must folloW CR by NUL */
+ printf("%s",sx);
+ } else
+#endif /* IKSD */
+ printf("\r%s",sx);
+#ifdef CK_SSL
+ if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+ fflush(stdout); /* Now! */
+#endif /* MAC */
+#endif /* OSK */
+}
+
+#ifndef NOSPL
+VOID
+pushcmd(s) char * s; { /* For use with IF command. */
+ if (!s) s = np;
+ ckstrncpy(savbuf,s,CMDBL); /* Save the dependent clause, */
+ cmres(); /* and clear the command buffer. */
+ debug(F110, "pushcmd savbuf", savbuf, 0);
+}
+
+VOID
+pushqcmd(s) char * s; { /* For use with ELSE command. */
+ char c, * p = savbuf; /* Dest */
+ if (!s) s = np; /* Source */
+ while (*s) { /* Get first nonwhitespace char */
+ if (*s != SP)
+ break;
+ else
+ s++;
+ }
+ if (*s != '{') { /* If it's not "{" */
+ pushcmd(s); /* do regular pushcmd */
+ return;
+ }
+ while ((c = *s++)) { /* Otherwise insert quotes */
+ if (c == CMDQ)
+ *p++ = CMDQ;
+ *p++ = c;
+ }
+ cmres(); /* and clear the command buffer. */
+ debug(F110, "pushqcmd savbuf", savbuf, 0);
+}
+#endif /* NOSPL */
+
+#ifdef COMMENT
+/* no longer used... */
+VOID
+popcmd() {
+ ckstrncpy(cmdbuf,savbuf,CMDBL); /* Put back the saved material */
+ *savbuf = '\0'; /* and clear the save buffer */
+ cmres();
+}
+#endif /* COMMENT */
+
+/* C M R E S -- Reset pointers to beginning of command buffer. */
+
+VOID
+cmres() {
+ inword = 0; /* We're not in a word */
+ cc = 0; /* Character count is zero */
+
+/* Initialize pointers */
+
+ pp = cmdbuf; /* Beginning of current field */
+ bp = cmdbuf; /* Current position within buffer */
+ np = cmdbuf; /* Where to start next field */
+
+ cmfldflgs = 0;
+ cmflgs = -5; /* Parse not yet started. */
+ ungw = 0; /* Don't need to unget a word. */
+}
+
+/* C M I N I -- Clear the command and atom buffers, reset pointers. */
+
+/*
+The argument specifies who is to echo the user's typein --
+ 1 means the cmd package echoes
+ 0 somebody else (system, front end, terminal) echoes
+*/
+VOID
+cmini(d) int d; {
+#ifdef DCMDBUF
+ if (!atmbuf)
+ if (cmsetup()<0)
+ fatal("fatal error: unable to allocate command buffers");
+#endif /* DCMDBUF */
+#ifdef USE_MEMCPY
+ memset(cmdbuf,0,CMDBL);
+ memset(atmbuf,0,ATMBL);
+#else
+ for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL;
+ for (bp = atmbuf; bp < atmbuf+ATMBL; bp++) *bp = NUL;
+#endif /* USE_MEMCPY */
+
+ *atmbuf = *savbuf = *atxbuf = *atybuf = *filbuf = NUL;
+ blocklvl = 0; /* Block level is 0 */
+ linebegin = 1; /* At the beginning of a line */
+ dpx = d; /* Global copy of the echo flag */
+ debug(F101,"cmini dpx","",dpx);
+ crflag = 0; /* Reset flags */
+ qmflag = 0;
+ esflag = 0;
+#ifdef CK_RECALL
+ no_recall = 0; /* Start out with recall enabled */
+#endif /* CK_RECALL */
+ cmres(); /* Sets bp etc */
+ newcmd = 1; /* See addcmd() */
+}
+
+#ifndef NOSPL
+/*
+ The following bits are to allow the command package to call itself
+ in the middle of a parse. To do this, begin by calling cmpush, and
+ end by calling cmpop. As you can see, this is rather expensive.
+*/
+#ifdef DCMDBUF
+struct cmp {
+ int i[5]; /* stack for integers */
+ char *c[3]; /* stack for pointers */
+ char *b[8]; /* stack for buffer contents */
+};
+struct cmp *cmp = 0;
+#else
+int cmp_i[CMDDEP+1][5]; /* Stack for integers */
+char *cmp_c[CMDDEP+1][5]; /* for misc pointers */
+char *cmp_b[CMDDEP+1][7]; /* for buffer contents pointers */
+#endif /* DCMDBUF */
+
+int cmddep = -1; /* Current stack depth */
+
+int
+cmpush() { /* Save the command environment */
+ char *cp; /* Character pointer */
+
+ if (cmddep >= CMDDEP) /* Enter a new command depth */
+ return(-1);
+ cmddep++;
+ debug(F101,"&cmpush to depth","",cmddep);
+
+#ifdef DCMDBUF
+ /* allocate memory for cmp if not already done */
+ if (!cmp && !(cmp = (struct cmp *) malloc(sizeof(struct cmp)*(CMDDEP+1))))
+ fatal("cmpush: no memory for cmp");
+ cmp[cmddep].i[0] = cmflgs; /* First do the global ints */
+ cmp[cmddep].i[1] = cmfsav;
+ cmp[cmddep].i[2] = atxn;
+ cmp[cmddep].i[3] = ungw;
+
+ cmp[cmddep].c[0] = bp; /* Then the global pointers */
+ cmp[cmddep].c[1] = pp;
+ cmp[cmddep].c[2] = np;
+#else
+ cmp_i[cmddep][0] = cmflgs; /* First do the global ints */
+ cmp_i[cmddep][1] = cmfsav;
+ cmp_i[cmddep][2] = atxn;
+ cmp_i[cmddep][3] = ungw;
+
+ cmp_c[cmddep][0] = bp; /* Then the global pointers */
+ cmp_c[cmddep][1] = pp;
+ cmp_c[cmddep][2] = np;
+#endif /* DCMDBUF */
+
+ /* Now the buffers themselves. A lot of repititious code... */
+
+#ifdef DCMDBUF
+ cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
+ if (cp) strcpy(cp,cmdbuf);
+ cmp[cmddep].b[0] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
+ if (cp) strcpy(cp,savbuf);
+ cmp[cmddep].b[1] = cp;
+ if (cp == NULL) return(-1);
+
+ cmp[cmddep].b[2] = NULL;
+
+ cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
+ if (cp) strcpy(cp,atmbuf);
+ cmp[cmddep].b[3] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
+ if (cp) strcpy(cp,atxbuf);
+ cmp[cmddep].b[4] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
+ if (cp) strcpy(cp,atybuf);
+ cmp[cmddep].b[5] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
+ if (cp) strcpy(cp,filbuf);
+ cmp[cmddep].b[6] = cp;
+ if (cp == NULL) return(-1);
+#else
+ cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
+ if (cp) strcpy(cp,cmdbuf);
+ cmp_b[cmddep][0] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
+ if (cp) strcpy(cp,savbuf);
+ cmp_b[cmddep][1] = cp;
+ if (cp == NULL) return(-1);
+
+ cmp_b[cmddep][2] = NULL;
+
+ cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
+ if (cp) strcpy(cp,atmbuf);
+ cmp_b[cmddep][3] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
+ if (cp) strcpy(cp,atxbuf);
+ cmp_b[cmddep][4] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
+ if (cp) strcpy(cp,atybuf);
+ cmp_b[cmddep][5] = cp;
+ if (cp == NULL) return(-1);
+
+ cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
+ if (cp) strcpy(cp,filbuf);
+ cmp_b[cmddep][6] = cp;
+ if (cp == NULL) return(-1);
+#endif /* DCMDBUF */
+
+ cmini(dpx); /* Initize the command parser */
+ return(0);
+}
+
+int
+cmpop() { /* Restore the command environment */
+ if (cmddep < 0) {
+ debug(F100,"&cmpop called from top level","",0);
+ return(-1); /* Don't pop too much! */
+ }
+#ifdef DCMDBUF
+ cmflgs = cmp[cmddep].i[0]; /* First do the global ints */
+ cmfsav = cmp[cmddep].i[1];
+ atxn = cmp[cmddep].i[2];
+ ungw = cmp[cmddep].i[3];
+
+ bp = cmp[cmddep].c[0]; /* Then the global pointers */
+ pp = cmp[cmddep].c[1];
+ np = cmp[cmddep].c[2];
+#else
+ cmflgs = cmp_i[cmddep][0]; /* First do the global ints */
+ cmfsav = cmp_i[cmddep][1];
+ atxn = cmp_i[cmddep][2];
+ ungw = cmp_i[cmddep][3];
+
+ bp = cmp_c[cmddep][0]; /* Then the global pointers */
+ pp = cmp_c[cmddep][1];
+ np = cmp_c[cmddep][2];
+#endif /* DCMDBUF */
+
+ /* Now the buffers themselves. */
+ /* Note: strncpy(), not ckstrncpy() -- Here we WANT the NUL padding... */
+
+#ifdef DCMDBUF
+ if (cmp[cmddep].b[0]) {
+
+ strncpy(cmdbuf,cmp[cmddep].b[0],CMDBL); /* 0: Command buffer */
+ free(cmp[cmddep].b[0]);
+ cmp[cmddep].b[0] = NULL;
+ }
+ if (cmp[cmddep].b[1]) {
+ strncpy(savbuf,cmp[cmddep].b[1],CMDBL); /* 1: Save buffer */
+ free(cmp[cmddep].b[1]);
+ cmp[cmddep].b[1] = NULL;
+ }
+ if (cmp[cmddep].b[3]) {
+ strncpy(atmbuf,cmp[cmddep].b[3],ATMBL); /* 3: Atomic buffer! */
+ free(cmp[cmddep].b[3]);
+ cmp[cmddep].b[3] = NULL;
+ }
+ if (cmp[cmddep].b[4]) {
+ strncpy(atxbuf,cmp[cmddep].b[4],ATMBL); /* 4: eXpansion buffer */
+ free(cmp[cmddep].b[4]);
+ cmp[cmddep].b[4] = NULL;
+ }
+ if (cmp[cmddep].b[5]) {
+ strncpy(atybuf,cmp[cmddep].b[5],ATMBL); /* 5: Atom buffer copY */
+ free(cmp[cmddep].b[5]);
+ cmp[cmddep].b[5] = NULL;
+ }
+ if (cmp[cmddep].b[6]) {
+ strncpy(filbuf,cmp[cmddep].b[6],ATMBL); /* 6: Filename buffer */
+ free(cmp[cmddep].b[6]);
+ cmp[cmddep].b[6] = NULL;
+ }
+#else
+ if (cmp_b[cmddep][0]) {
+ strncpy(cmdbuf,cmp_b[cmddep][0],CMDBL); /* 0: Command buffer */
+ free(cmp_b[cmddep][0]);
+ cmp_b[cmddep][0] = NULL;
+ }
+ if (cmp_b[cmddep][1]) {
+ strncpy(savbuf,cmp_b[cmddep][1],CMDBL); /* 1: Save buffer */
+ free(cmp_b[cmddep][1]);
+ cmp_b[cmddep][1] = NULL;
+ }
+ if (cmp_b[cmddep][3]) {
+ strncpy(atmbuf,cmp_b[cmddep][3],ATMBL); /* 3: Atomic buffer! */
+ free(cmp_b[cmddep][3]);
+ cmp_b[cmddep][3] = NULL;
+ }
+ if (cmp_b[cmddep][4]) {
+ strncpy(atxbuf,cmp_b[cmddep][4],ATMBL); /* 4: eXpansion buffer */
+ free(cmp_b[cmddep][4]);
+ cmp_b[cmddep][4] = NULL;
+ }
+ if (cmp_b[cmddep][5]) {
+ strncpy(atybuf,cmp_b[cmddep][5],ATMBL); /* 5: Atom buffer copY */
+ free(cmp_b[cmddep][5]);
+ cmp_b[cmddep][5] = NULL;
+ }
+ if (cmp_b[cmddep][6]) {
+ strncpy(filbuf,cmp_b[cmddep][6],ATMBL); /* 6: Filename buffer */
+ free(cmp_b[cmddep][6]);
+ cmp_b[cmddep][6] = NULL;
+ }
+#endif /* DCMDBUF */
+
+ cmddep--; /* Rise, rise */
+ debug(F101,"&cmpop to depth","",cmddep);
+ return(cmddep);
+}
+#endif /* NOSPL */
+
+#ifdef COMMENT
+VOID /* Not used */
+stripq(s) char *s; { /* Function to strip '\' quotes */
+ char *t;
+ while (*s) {
+ if (*s == CMDQ) {
+ for (t = s; *t != '\0'; t++) *t = *(t+1);
+ }
+ s++;
+ }
+}
+#endif /* COMMENT */
+
+/* Convert tabs to spaces, one for one */
+VOID
+untab(s) char *s; {
+ while (*s) {
+ if (*s == HT) *s = SP;
+ s++;
+ }
+}
+
+/* C M N U M -- Parse a number in the indicated radix */
+
+/*
+ The radix is specified in the arg list.
+ Parses unquoted numeric strings in the given radix.
+ Parses backslash-quoted numbers in the radix indicated by the quote:
+ \nnn = \dnnn = decimal, \onnn = octal, \xnn = Hexadecimal.
+ If these fail, then if a preprocessing function is supplied, that is applied
+ and then a second attempt is made to parse an unquoted decimal string.
+ And if that fails, the preprocessed string is passed to an arithmetic
+ expression evaluator.
+
+ Returns:
+ -3 if no input present when required,
+ -2 if user typed an illegal number,
+ -1 if reparse needed,
+ 0 otherwise, with argument n set to the number that was parsed
+*/
+/* This is the traditional cmnum() that gets an int */
+int
+cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
+ CK_OFF_T z = (CK_OFF_T)0, check;
+ int x;
+ x = cmnumw(xhlp,xdef,radix,&z,f);
+ *n = z;
+ check = *n;
+ if (check != z) {
+ printf("?Magnitude of result too large for integer - %s\n",ckfstoa(z));
+ return(-9);
+ }
+ return(x);
+}
+
+/*
+ This is the new cmnum() that gets a "wide" result, whatever CK_OFF_T
+ is defined to be, normally 32 or 64 bits, depending on the platform.
+ fdc, 24 Dec 2005.
+*/
+int
+cmnumw(xhlp,xdef,radix,n,f)
+ char *xhlp, *xdef; int radix; CK_OFF_T *n; xx_strp f; {
+ int x; char *s, *zp, *zq;
+#ifdef COMMENT
+ char lbrace, rbrace;
+#endif /* COMMENT */
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+#ifdef COMMENT
+ if (cmfldflgs & 1) {
+ lbrace = '(';
+ rbrace = ')';
+ } else {
+ lbrace = '{';
+ rbrace = '}';
+ }
+#endif /* COMMENT */
+
+ if (radix != 10 && radix != 8) { /* Just do bases 8 and 10 */
+ printf("cmnum: illegal radix - %d\n",radix);
+ return(-2);
+ } /* Easy to add others but there has never been a need for it. */
+ x = cmfld(xhlp,xdef,&s,(xx_strp)0);
+ debug(F101,"cmnum: cmfld","",x);
+ if (x < 0) return(x); /* Parse a field */
+ zp = atmbuf;
+/*
+ Edit 192 - Allow any number field to be braced. This lets us include
+ spaces in expressions, but perhaps more important lets us have user-defined
+ functions in numeric fields.
+*/
+ zp = brstrip(zp); /* Strip braces */
+ if (cmfldflgs & 1 && *zp == '(') { /* Parens too.. */
+ x = (int) strlen(atmbuf);
+ if (x > 0) {
+ if (*(atmbuf+x-1) == ')') {
+ *(atmbuf+x-1) = NUL;
+ zp++;
+ }
+ }
+ }
+ if (chknum(zp)) { /* Check for number */
+ if (radix == 8) { /* If it's supposed to be octal */
+ zp = ckradix(zp,8,10); /* convert to decimal */
+ if (!zp) return(-2);
+ if (!strcmp(zp,"-1")) return(-2);
+ }
+ errno = 0; /* Got one, we're done. */
+ *n = ckatofs(zp);
+ if (errno) {
+ perror(zp);
+ return(-9);
+ }
+ debug(F101,"cmnum 1st chknum ok","",*n);
+ return(0);
+ } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
+
+#ifndef OS2
+ *n = x;
+#else
+ *n = wideresult;
+#endif /* OS2 */
+
+ debug(F101,"cmnum xxesc ok","",*n);
+ return(*zp ? -2 : 0);
+ } else if (f) { /* If conversion function given */
+ zq = atxbuf; /* Try that */
+ atxn = CMDBL;
+ if ((*f)(zp,&zq,&atxn) < 0) /* Convert */
+ return(-2);
+ zp = atxbuf;
+ }
+ debug(F110,"cmnum zp 1",zp,0);
+ if (!*zp) zp = xdef; /* Result empty, substitute default */
+ debug(F110,"cmnum zp 2",zp,0);
+ if (chknum(zp)) { /* Check again for decimal number */
+ if (radix == 8) { /* If it's supposed to be octal */
+ zp = ckradix(zp,8,10); /* convert to decimal */
+ if (!zp) return(-2);
+ if (!strcmp(zp,"-1")) return(-2);
+ }
+ errno = 0;
+ *n = ckatofs(zp);
+ if (errno) {
+ perror(zp);
+ return(-9);
+ }
+ debug(F101,"cmnum 2nd chknum ok","",*n);
+ return(0);
+#ifndef NOSPL
+ } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
+#ifndef OS2
+ *n = x;
+#else
+ *n = wideresult;
+#endif /* OS2 */
+ debug(F101,"cmnum xxesc 2 ok","",*n);
+ return(*zp ? -2 : 0);
+ } else if (f) { /* Not numeric, maybe an expression */
+ char * p;
+ p = evala(zp);
+ if (chknum(p)) {
+ if (radix == 8) { /* If it's supposed to be octal */
+ zp = ckradix(zp,8,10); /* convert to decimal */
+ if (!zp) return(-2);
+ if (!strcmp(zp,"-1")) return(-2);
+ }
+ errno = 0;
+ *n = ckatofs(p);
+ if (errno) {
+ perror(p);
+ return(-9);
+ }
+ debug(F101,"cmnum exp eval ok","",*n);
+ return(0);
+ } else return(-2);
+#endif /* NOSPL */
+ } else { /* Not numeric */
+ return(-2);
+ }
+}
+
+#ifdef CKCHANNELIO
+extern int z_error;
+#endif /* CKCHANNELIO */
+
+/* C M O F I -- Parse the name of an output file */
+
+/*
+ Depends on the external function zchko(); if zchko() not available, use
+ cmfld() to parse output file names.
+
+ Returns:
+ -9 like -2, except message already printed,
+ -3 if no input present when required,
+ -2 if permission would be denied to create the file,
+ -1 if reparse needed,
+ 0 or 1 if file can be created, with xp pointing to name.
+ 2 if given the name of an existing directory.
+*/
+int
+cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+ int x; char *s, *zq;
+#ifdef DOCHKVAR
+ int tries;
+#endif /* DOCHKVAR */
+#ifdef DTILDE
+ char *dirp;
+#endif /* DTILDE */
+
+ cmfldflgs = 0;
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+ if (*xhlp == NUL) xhlp = "Output file";
+ *xp = "";
+
+ debug(F110,"cmofi xdef",xdef,0);
+ x = cmfld(xhlp,xdef,&s,(xx_strp)0);
+ debug(F111,"cmofi cmfld returns",s,x);
+ if (x < 0)
+ return(x);
+
+ s = brstrip(s); /* Strip enclosing braces */
+ debug(F110,"cmofi 1.5",s,0);
+
+#ifdef DOCHKVAR
+ tries = 0;
+ {
+ char *p = s;
+ /*
+ This is really ugly. If we skip conversion the first time through,
+ then variable names like \%a will be used as filenames (e.g. creating
+ a file called %A in the root directory). If we DON'T skip conversion
+ the first time through, then single backslashes used as directory
+ separators in filenames will be misinterpreted as variable lead-ins.
+ So we prescan to see if it has any variable references. But this
+ module is not supposed to know anything about variables, functions,
+ etc, so this code does not really belong here, but rather it should
+ be at the same level as zzstring().
+ */
+/*
+ Hmmm, this looks a lot like chkvar() except it that includes \nnn number
+ escapes. But why? This makes commands like "mkdir c:\123" impossible.
+ And in fact, "mkdir c:\123" creates a directory called "c:{". What's worse,
+ rmdir(), which *does* call chkvar(), won't let us remove it. So let's at
+ least try making cmofi() symmetrical with cmifi()...
+*/
+#ifdef COMMENT
+ char * q;
+ while ( (tries == 0) && (p = strchr(p,CMDQ)) ) {
+ q = *(p+1); /* Char after backslash */
+ if (!q) /* None, quit */
+ break;
+ if (isupper(q)) /* If letter, convert to lowercase */
+ q = tolower(q);
+ if (isdigit(q)) { /* If it's a digit, */
+ tries = 1; /* assume it's a backslash code */
+ break;
+ }
+ switch (q) {
+ case CMDQ: /* Double backslash */
+ tries = 1; /* so call the conversion function */
+ break;
+ case '%': /* Variable or array reference */
+ case '&': /* must be followed by letter */
+ if (isalpha(*(p+2)) || (*(p+2) >= '0' && *(p+2) <= '9'))
+ tries = 1;
+ break;
+ case 'm': case 'v': case '$': /* \m(), \v(), \$() */
+ if (*(p+2) == '(')
+ if (strchr(p+2,')'))
+ tries = 1;
+ break;
+ case 'f': /* \Fname() */
+ if (strchr(p+2,'('))
+ if (strchr(p+2,')'))
+ tries = 1;
+ break;
+ case '{': /* \{...} */
+ if (strchr(p+2,'}'))
+ tries = 1;
+ break;
+ case 'd': case 'o': /* Decimal or Octal number */
+ if (isdigit(*(p+2)))
+ tries = 1;
+ break;
+ case 'x': /* Hex number */
+ if (isdigit(*(p+2)) ||
+ ((*(p+2) >= 'a' && *(p+2) <= 'f') ||
+ ((*(p+2) >= 'A' && *(p+2) <= 'F'))))
+ tries = 1;
+ default:
+ break;
+ }
+ p++;
+ }
+#else
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+ char *s = p; /* See if there are any variables in */
+ while (*s) { /* the string and if so, expand them */
+ if (chkvar(s)) {
+ tries = 1;
+ break;
+ }
+ s++;
+ }
+ }
+#endif /* NOSPL */
+#endif /* COMMENT */
+ }
+#ifdef OS2
+o_again:
+#endif /* OS2 */
+ if (tries == 1)
+#endif /* DOCHKVAR */
+ if (f) { /* If a conversion function is given */
+ zq = atxbuf; /* do the conversion. */
+ atxn = CMDBL;
+ if ((x = (*f)(s,&zq,&atxn)) < 0)
+ return(-2);
+ s = atxbuf;
+ if (!*s) /* Result empty, substitute default */
+ s = xdef;
+ }
+ debug(F111,"cmofi 2",s,x);
+
+#ifdef DTILDE
+ dirp = tilde_expand(s); /* Expand tilde, if any, */
+ if (*dirp != '\0') { /* right in the atom buffer. */
+ if (setatm(dirp,1) < 0) {
+ printf("?Name too long\n");
+ return(-9);
+ }
+ }
+ s = atmbuf;
+ debug(F110,"cmofi 3",s,0);
+#endif /* DTILDE */
+
+ if (iswild(s)) {
+ printf("?Wildcards not allowed - %s\n",s);
+ return(-2);
+ }
+ debug(F110,"cmofi 4",s,0);
+
+#ifdef CK_TMPDIR
+ /* isdir() function required for this! */
+ if (isdir(s)) {
+ debug(F110,"cmofi 5: is directory",s,0);
+ *xp = s;
+ return(2);
+ }
+#endif /* CK_TMPDIR */
+
+ if (strcmp(s,CTTNAM) && (zchko(s) < 0)) { /* OK to write to console */
+#ifdef COMMENT
+#ifdef OS2
+/*
+ We don't try again because we already prescanned the string to see if
+ if it contained anything that could be used by zzstring().
+*/
+ if (tries++ < 1)
+ goto o_again;
+#endif /* OS2 */
+#endif /* COMMENT */
+/*
+ Note: there are certain circumstances where zchko() can give a false
+ positive, so don't rely on it to catch every conceivable situation in
+ which the given output file can't be created. In other words, we print
+ a message and fail here if we KNOW the file can't be created. If we
+ succeed but the file can't be opened, the code that tries to open the file
+ has to print a message.
+*/
+ debug(F110,"cmofi 6: failure",s,0);
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",s);
+ else
+#endif /* CKROOT */
+ printf("?Write permission denied - %s\n",s);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(-9);
+ } else {
+ debug(F110,"cmofi 7: ok",s,0);
+ *xp = s;
+ return(x);
+ }
+}
+
+/* C M I F I -- Parse the name of an existing file */
+
+/*
+ This function depends on the external functions:
+ zchki() - Check if input file exists and is readable.
+ zxpand() - Expand a wild file specification into a list.
+ znext() - Return next file name from list.
+ If these functions aren't available, then use cmfld() to parse filenames.
+*/
+/*
+ Returns
+ -4 EOF
+ -3 if no input present when required,
+ -2 if file does not exist or is not readable,
+ -1 if reparse needed,
+ 0 or 1 otherwise, with:
+ xp pointing to name,
+ wild = 1 if name contains '*' or '?', 0 otherwise.
+*/
+
+#ifdef COMMENT /* This horrible hack has been replaced - see further down */
+/*
+ C M I O F I -- Parse an input file OR the name of a nonexistent file.
+
+ Use this when an existing file is wanted (so we get help, completion, etc),
+ but if a file of the given name does not exist, the name of a new file is
+ accepted. For example, with the EDIT command (edit an existing file, or
+ create a new file). Returns -9 if file does not exist. It is up to the
+ caller to check creatability.
+*/
+static int nomsg = 0;
+int
+cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+ int msgsave, x;
+ msgsave = nomsg;
+ nomsg = 1;
+ x = cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0);
+ nomsg = msgsave;
+ return(x);
+}
+#endif /* COMMENT */
+
+int
+cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+ return(cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0));
+}
+/*
+ cmifip() is called when we want to supply a path or path list to search
+ in case the filename that the user gives is (a) not absolute, and (b) can't
+ be found as given. The path string can be the name of a single directory,
+ or a list of directories separated by the PATHSEP character, defined in
+ ckucmd.h. Look in ckuusr.c and ckuus3.c for examples of usage.
+*/
+int
+cmifip(xhlp,xdef,xp,wild,d,path,f)
+ char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; {
+ return(cmifi2(xhlp,xdef,xp,wild,0,path,f,0));
+}
+
+/* C M D I R -- Parse a directory name */
+
+/*
+ This function depends on the external functions:
+ isdir(s) - Check if string s is the name of a directory
+ zchki(s) - Check if input file s exists and what type it is.
+ If these functions aren't available, then use cmfld() to parse dir names.
+
+ Returns
+ -9 For all sorts of reasons, after printing appropriate error message.
+ -4 EOF
+ -3 if no input present when required,
+ -2 if out of space or other internal error,
+ -1 if reparse needed,
+ 0 or 1, with xp pointing to name, if directory specified,
+*/
+int
+cmdir(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+ int wild;
+ return(cmifi2(xhlp,xdef,xp,&wild,0,NULL,f,1));
+}
+
+/* Like CMDIR but includes PATH search */
+
+int
+cmdirp(xhlp,xdef,xp,path,f) char *xhlp, *xdef, **xp; char * path; xx_strp f; {
+ int wild;
+ return(cmifi2(xhlp,xdef,xp,&wild,0,path,f,1));
+}
+
+/*
+ cmifi2() is the base filename parser called by cmifi, cmifip, cmdir, etc.
+ Use it directly when you also want to parse a directory or device
+ name as an input file, as in the DIRECTORY command. Call with:
+ xhlp -- help message on ?
+ xdef -- default response
+ xp -- pointer to result (in our space, must be copied from here)
+ wild -- flag set upon return to indicate if filespec was wild
+ d -- 0 to parse files, 1 to parse files or directories
+ Add 2 to inhibit following of symlinks.
+ path -- search path for files
+ f -- pointer to string processing function (e.g. to evaluate variables)
+ dirflg -- 1 to parse *only* directories, 0 otherwise
+*/
+int
+cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
+ char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; int dirflg; {
+ extern int recursive, diractive, cdactive, dblquo;
+ int i, x, itsadir, xc, expanded = 0, nfiles = 0, children = -1;
+ int qflag = 0;
+ long y;
+ CK_OFF_T filesize;
+ char *sp = NULL, *zq, *np = NULL;
+ char *sv = NULL, *p = NULL;
+#ifdef DTILDE
+ char *dirp;
+#endif /* DTILDE */
+
+#ifndef NOPARTIAL
+#ifndef OS2
+#ifdef OSK
+ /* This large array is dynamic for OS-9 -- should do for others too... */
+ extern char **mtchs;
+#else
+#ifdef UNIX
+ /* OK, for UNIX too */
+ extern char **mtchs;
+#else
+#ifdef VMS
+ extern char **mtchs;
+#else
+ extern char *mtchs[];
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* NOPARTIAL */
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+#ifndef NOLASTFILE
+ makestr(&tmplastfile,NULL);
+#endif /* NOLASTFILE */
+ nzxopts = 0; /* zxpand() options */
+ debug(F101,"cmifi d","",d);
+ if (d & 2) { /* d & 2 means don't follow symlinks */
+ d ^= 2;
+ nzxopts = ZX_NOLINKS;
+ }
+ debug(F101,"cmifi nzxopts","",nzxopts);
+ cmfldflgs = 0;
+ if (path)
+ if (!*path)
+ path = NULL;
+ if (path) { /* Make a copy we can poke */
+ x = strlen(path);
+ np = (char *) malloc(x + 1);
+ if (np) {
+ strcpy(np, path);
+ path = sp = np;
+ }
+ }
+ debug(F110,"cmifi2 path",path,0);
+
+ ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
+ xdef = cmdefault;
+
+ inword = 0; /* Initialize counts & pointers */
+ cc = 0;
+ xc = 0;
+ *xp = ""; /* Pointer to result string */
+ if ((x = cmflgs) != 1) { /* Already confirmed? */
+#ifdef BS_DIRSEP
+ dirnamflg = 1;
+ x = gtword(0); /* No, get a word */
+ dirnamflg = 0;
+#else
+ x = gtword(0); /* No, get a word */
+#endif /* BS_DIRSEP */
+ } else { /* If so, use default, if any. */
+ if (setatm(xdef,1) < 0) {
+ printf("?Default name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ }
+ i_path:
+ *xp = atmbuf; /* Point to result. */
+
+ while (1) {
+ xc += cc; /* Count this character. */
+ debug(F111,"cmifi gtword",atmbuf,xc);
+ debug(F101,"cmifi switch x","",x);
+ switch (x) { /* x = gtword() return code */
+ case -10:
+ if (gtimer() > timelimit) {
+#ifdef IKSD
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit);
+ doexit(GOOD_EXIT,0);
+ }
+#endif /* IKSD */
+ /* if (!quiet) printf("?Timed out\n"); */
+ return(-10);
+ } else {
+ x = gtword(0);
+ continue;
+ }
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -2: /* Out of space. */
+ case -1: /* Reparse needed */
+ if (np) free(np);
+ return(x);
+ case 1: /* CR */
+ case 0: /* SP */
+ if (xc == 0) /* If no input... */
+ *xp = xdef; /* substitute the default */
+#ifndef NOLASTFILE
+ makestr(&tmplastfile,*xp); /* Make a copy before bstripping */
+#endif /* #ifndef NOLASTFILE */
+ *xp = brstrip(*xp); /* Strip braces */
+ if (**xp == NUL) { /* 12 mar 2001 */
+ if (np) free(np);
+ return(-3);
+ }
+ debug(F110,"cmifi brstrip",*xp,0);
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+#ifdef DOCHKVAR
+ char *s = *xp; /* See if there are any variables in */
+ int x;
+ while (*s) { /* the string and if so, expand them */
+ x = chkvar(s);
+ /* debug(F111,"cmifi chkvar",*xp,x); */
+ if (x) {
+#endif /* DOCHKVAR */
+ zq = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(*xp,&zq,&atxn) < 0) {
+ if (np) free(np);
+ return(-2);
+ }
+ *xp = atxbuf;
+ if (!atxbuf[0])
+ *xp = xdef;
+#ifdef DOCHKVAR
+ break;
+ }
+ s++;
+ }
+#endif /* DOCHKVAR */
+ }
+#endif /* NOSPL */
+ if (**xp == NUL) { /* 12 mar 2001 */
+ if (np) free(np);
+ return(-3);
+ }
+#ifdef DTILDE
+ if (dirflg) {
+ dirp = tilde_expand(*xp); /* Expand tilde, if any, */
+ if (*dirp != '\0') { /* in the atom buffer. */
+ if (setatm(dirp,1) < 0) {
+ printf("Expanded name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ }
+ *xp = atmbuf;
+ debug(F110,"cmifi tilde_expand",*xp,0);
+ }
+#endif /* DTILDE */
+ if (!sv) { /* Only do this once */
+ sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */
+ if (!sv) {
+ printf("?cmifi: malloc error\n");
+ if (np) free(np);
+ return(-9);
+ }
+ strcpy(sv,*xp);
+ debug(F110,"cmifi sv",sv,0);
+ }
+
+/* This is to get around "cd /" failing because "too many directories match" */
+
+ expanded = 0; /* Didn't call zxpand */
+#ifdef datageneral
+ debug(F110,"cmifi isdir 1",*xp,0);
+ {
+ int y; char *s;
+ s = *xp;
+ y = strlen(s);
+ if (y > 1 &&
+ (s[y-1] == ':' ||
+ s[y-1] == '^' ||
+ s[y-1] == '=')
+ )
+ s[y-1] = NUL;
+ }
+ debug(F110,"cmifi isdir 2",*xp,0);
+#endif /* datageneral */
+
+#ifdef VMS
+ if (dirflg) {
+ if (!strcmp(*xp,"..")) { /* For UNIXers... */
+ setatm("-",0);
+ *xp = atmbuf;
+ } else if (!strcmp(*xp,".")) {
+ setatm("[]",0);
+ *xp = atmbuf;
+ }
+ }
+#endif /* VMS */
+ itsadir = isdir(*xp); /* Is it a directory? */
+ debug(F111,"cmifi itsadir",*xp,itsadir);
+#ifdef VMS
+ /* If they said "blah" where "blah.dir" is a directory... */
+ /* change it to [.blah]. */
+ if (!itsadir) {
+ char tmpbuf[600];
+ int flag = 0; char c, * p;
+ p = *xp;
+ while ((c = *p++) && !flag)
+ if (ckstrchr(".[]:*?<>",c))
+ flag = 1;
+ debug(F111,"cmifi VMS dirname flag",*xp,flag);
+ if (!flag) {
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"[.",*xp,"]",NULL);
+ itsadir = isdir(tmpbuf);
+ if (itsadir) {
+ setatm(tmpbuf,0);
+ *xp = atmbuf;
+ }
+ debug(F111,"cmifi VMS dirname flag itsadir",*xp,itsadir);
+ }
+ } else if (itsadir == 1 && *(xp[0]) == '.' && *(xp[1])) {
+ char *p;
+ if (p = malloc(cc + 4)) {
+ ckmakmsg(p,cc+4,"[",*xp,"]",NULL);
+ setatm(p,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir .foo",*xp,0);
+ free(p);
+ }
+ } else if (itsadir == 2 && !diractive) {
+ int x; /* [FOO]BAR.DIR instead of [FOO.BAR] */
+ char *p;
+ p = malloc(cc + 4);
+ if (p) {
+ x = cvtdir(*xp,p,ATMBL); /* Convert to [FOO.BAR] */
+ if (x > 0) {
+ setatm(p,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir cvtdir",*xp,0);
+ }
+ free(p);
+ }
+ }
+#endif /* VMS */
+
+ debug(F101,"cmifi dirflg","",dirflg);
+ if (dirflg) { /* Parsing a directory name? */
+ /* Yes, does it contain wildcards? */
+ if (iswild(*xp) ||
+ (diractive && (!strcmp(*xp,".") || !strcmp(*xp,"..")))
+ ) {
+ nzxopts |= ZX_DIRONLY; /* Match only directory names */
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ debug(F111,"cmifi nzxopts 2",*xp,nzxopts);
+ y = nzxpand(*xp,nzxopts);
+ debug(F111,"cmifi nzxpand 2",*xp,y);
+ nfiles = y;
+ expanded = 1;
+ } else {
+#ifdef VMS
+/*
+ This is to allow (e.g.) "cd foo", where FOO.DIR;1 is in the
+ current directory.
+*/
+ debug(F111,"cmdir itsadir",*xp,itsadir);
+ if (!itsadir) {
+ char *s;
+ int n;
+ s = *xp;
+ n = strlen(s);
+ if (n > 0 &&
+#ifdef COMMENT
+ *s != '[' && s[n-1] != ']' &&
+ *s != '<' && s[n-1] != '>' &&
+#else
+ ckindex("[",s,0,0,1) == 0 &&
+ ckindex("<",s,0,0,1) == 0 &&
+#endif /* COMMENT */
+ s[n-1] != ':') {
+ char * dirbuf = NULL;
+ dirbuf = (char *)malloc(n+4);
+ if (dirbuf) {
+ if (*s == '.')
+ ckmakmsg(dirbuf,n+4,"[",s,"]",NULL);
+ else
+ ckmakmsg(dirbuf,n+4,"[.",s,"]",NULL);
+ itsadir = isdir(dirbuf);
+ debug(F111,"cmdir dirbuf",dirbuf,itsadir);
+ if (itsadir) {
+ setatm(dirbuf,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir new *xp",*xp,0);
+ }
+ free(dirbuf);
+ }
+
+/* This is to allow CDPATH to work in VMS... */
+
+ } else if (n > 0) {
+ char * p; int i, j, k, d;
+ char rb[2] = "]";
+ if (p = malloc(x + 8)) {
+ ckstrncpy(p,*xp,x+8);
+ i = ckindex(".",p,-1,1,1);
+ d = ckindex(".dir",p,0,0,0);
+ j = ckindex("]",p,-1,1,1);
+ if (j == 0) {
+ j = ckindex(">",p,-1,1,1);
+ rb[0] = '>';
+ }
+ k = ckindex(":",p,-1,1,1);
+ if (i < j || i < k) i = 0;
+ if (d < j || d < k) d = 0;
+ /* Change [FOO]BAR or [FOO]BAR.DIR */
+ /* to [FOO.BAR] */
+ if (j > 0 && j < n) {
+ p[j-1] = '.';
+ if (d > 0) p[d-1] = NUL;
+ ckstrncat(p,rb,x+8);
+ debug(F110,"cmdir xxx",p,0);
+ }
+ itsadir = isdir(p);
+ debug(F111,"cmdir p",p,itsadir);
+ if (itsadir) {
+ setatm(p,0);
+ *xp = atmbuf;
+ debug(F110,"cmdir new *xp",*xp,0);
+ }
+ free(p);
+ }
+ }
+ }
+#endif /* VMS */
+ y = (!itsadir) ? 0 : 1;
+ debug(F111,"cmifi y itsadir",*xp,y);
+ }
+ } else { /* Parsing a filename. */
+ debug(F110,"cmifi *xp pre-zxpand",*xp,0);
+#ifndef COMMENT
+ nzxopts |= (d == 0) ? ZX_FILONLY : 0; /* So always expand. */
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+#else
+/* Here we're trying to fix a problem in which a directory name is accepted */
+/* as a filename, but this breaks too many other things. */
+ /* nzxopts = 0; */
+ if (!d) {
+ if (itsadir & !iswild(*xp)) {
+ debug(F100,"cmifi dir when filonly","",0);
+ printf("?Not a regular file: \"%s\"\n",*xp);
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ } else {
+ nzxopts |= ZX_FILONLY;
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ }
+ }
+#endif /* COMMENT */
+ nfiles = y;
+ debug(F111,"cmifi y nzxpand",*xp,y);
+ debug(F111,"cmifi y atmbuf",atmbuf,itsadir);
+ expanded = 1;
+ }
+ /* domydir() calls zxrewind() so we MUST call nzxpand() here */
+ if (!expanded && diractive) {
+ debug(F110,"cmifi diractive catch-all zxpand",*xp,0);
+ nzxopts |= (d == 0) ? ZX_FILONLY : (dirflg ? ZX_DIRONLY : 0);
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ debug(F111,"cmifi diractive nzxpand",*xp,y);
+ nfiles = y;
+ expanded = 1;
+ }
+ *wild = (iswild(sv) || (y > 1)) && (itsadir == 0);
+
+#ifdef RECURSIVE
+ if (!*wild) *wild = recursive;
+#endif /* RECURSIVE */
+
+ debug(F111,"cmifi sv wild",sv,*wild);
+ debug(F101,"cmifi y","",y);
+ if (dirflg && *wild && cdactive) {
+ if (y > 1) {
+ printf("?Wildcard matches more than one directory\n");
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ } else {
+ znext(*xp);
+ }
+ }
+ if (itsadir && d && !dirflg) { /* It's a directory and not wild */
+ if (sv) free(sv); /* and it's ok to parse directories */
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(x);
+ }
+ if (y == 0) { /* File was not found */
+ int dosearch = 0;
+ dosearch = (path != NULL); /* A search path was given */
+ if (dosearch) {
+ dosearch = hasnopath(sv); /* Filename includes no path */
+ debug(F111,"cmifip hasnopath",sv,dosearch);
+ }
+ if (dosearch) { /* Search the path... */
+ char * ptr = path;
+ char c;
+ while (1) {
+ c = *ptr;
+ if (c == PATHSEP || c == NUL) {
+ if (!*path) {
+ path = NULL;
+ break;
+ }
+ *ptr = NUL;
+#ifdef UNIX
+/* By definition of CDPATH, an empty member denotes the current directory */
+ if (!*path)
+ ckstrncpy(atmbuf,".",ATMBL);
+ else
+#endif /* UNIX */
+ ckstrncpy(atmbuf,path,ATMBL);
+#ifdef VMS
+ atmbuf[ATMBL] = NUL;
+/* If we have a logical name, evaluate it recursively */
+ if (*(ptr-1) == ':') { /* Logical name ends in : */
+ char *p; int n;
+ while (((n = strlen(atmbuf)) > 0) &&
+ atmbuf[n-1] == ':') {
+ atmbuf[n-1] = NUL;
+ for (p = atmbuf; *p; p++)
+ if (islower(*p)) *p = toupper(*p);
+ debug(F111,"cmdir CDPATH LN 1",atmbuf,n);
+ p = getenv(atmbuf);
+ debug(F110,"cmdir CDPATH LN 2",p,0);
+ if (!p)
+ break;
+ strncpy(atmbuf,p,ATMBL);
+ atmbuf[ATMBL] = NUL;
+ }
+ }
+#else
+#ifdef OS2
+ if (*(ptr-1) != '\\' && *(ptr-1) != '/')
+ ckstrncat(atmbuf,"\\",ATMBL);
+#else
+#ifdef UNIX
+ if (*(ptr-1) != '/')
+ ckstrncat(atmbuf,"/",ATMBL);
+#else
+#ifdef datageneral
+ if (*(ptr-1) != ':')
+ ckstrncat(atmbuf,":",ATMBL);
+#endif /* datageneral */
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* VMS */
+ ckstrncat(atmbuf,sv,ATMBL);
+ debug(F110,"cmifip add path",atmbuf,0);
+ if (c == PATHSEP) ptr++;
+ path = ptr;
+ break;
+ }
+ ptr++;
+ }
+ x = 1;
+ inword = 0;
+ cc = 0;
+ xc = (int) strlen(atmbuf);
+ *xp = "";
+ goto i_path;
+ }
+ if (d) {
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-2);
+ } else {
+ if (!nomsg) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",sv);
+ else
+#endif /* CKROOT */
+ if (!quiet)
+ printf("?No %s match - %s\n",
+ dirflg ? "directories" : "files", sv);
+ }
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ }
+ } else if (y < 0) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",sv);
+ else
+#endif /* CKROOT */
+ printf("?Too many %s match - %s\n",
+ dirflg ? "directories" : "files", sv);
+ if (sv) free(sv);
+ if (np) free(np);
+ return(-9);
+ } else if (*wild || y > 1) {
+ if (sv) free(sv);
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(x);
+ }
+
+ /* If not wild, see if it exists and is readable. */
+
+ debug(F111,"cmifi sv not wild",sv,*wild);
+ if (expanded)
+ znext(*xp); /* Get first (only?) matching file */
+ if (dirflg) /* Maybe wild and expanded */
+ itsadir = isdir(*xp); /* so do this again. */
+ filesize = dirflg ? itsadir : zchki(*xp); /* Check accessibility */
+ if (expanded) {
+#ifdef ZXREWIND
+ nfiles = zxrewind(); /* Rewind so next znext() gets 1st */
+#else
+
+ nzxopts |= dirflg ? ZX_DIRONLY : 0;
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ nfiles = nzxpand(*xp,nzxopts);
+#endif /* ZXREWIND */
+ }
+ debug(F111,"cmifi nfiles",*xp,nfiles);
+ debug(F101,"cmifi filesize","",filesize);
+ free(sv); /* done with this */
+ sv = NULL;
+ if (dirflg && !filesize) {
+ printf("?Not a directory - %s\n",*xp);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(-9);
+ } else if (filesize == (CK_OFF_T)-3) {
+ if (!xcmfdb) {
+ if (diractive)
+ /* Don't show filename if we're not allowed to see it */
+ printf("?Read permission denied\n");
+ else
+ printf("?Read permission denied - %s\n",*xp);
+ }
+ if (np) free(np);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(xcmfdb ? -6 : -9);
+ } else if (filesize == (CK_OFF_T)-2) {
+ if (!recursive) {
+ if (np) free(np);
+ if (d) {
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(0);
+ }
+ if (!xcmfdb)
+ printf("?File not readable - %s\n",*xp);
+#ifdef CKCHANNELIO
+ z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+ return(xcmfdb ? -6 : -9);
+ }
+ } else if (filesize < (CK_OFF_T)0) {
+ if (np) free(np);
+ if (!nomsg && !xcmfdb)
+ printf("?File not found - %s\n",*xp);
+#ifdef CKCHANNELIO
+ z_error = FX_FNF;
+#endif /* CKCHANNELIO */
+ return(xcmfdb ? -6 : -9);
+ }
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(x);
+
+#ifndef MAC
+ case 2: /* ESC */
+ debug(F101,"cmifi esc, xc","",xc);
+ if (xc == 0) {
+ if (*xdef) {
+ printf("%s ",xdef); /* If at beginning of field */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ inword = cmflgs = 0;
+ addbuf(xdef); /* Supply default. */
+ if (setatm(xdef,0) < 0) {
+ printf("Default name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ } else { /* No default */
+ bleep(BP_WARN);
+ }
+ break;
+ }
+ if (**xp == '{') { /* Did user type opening brace... */
+ *xp = *xp + 1;
+ xc--;
+ cc--;
+ qflag = '}';
+ } else if (dblquo && **xp == '"') { /* or doublequote? */
+ *xp = *xp + 1; /* If so ignore it and space past it */
+ xc--;
+ cc--;
+ qflag = '"';
+ }
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+#ifdef DOCHKVAR
+ char *s = *xp; /* See if there are any variables in */
+ while (*s) { /* the string and if so, expand it. */
+ if (chkvar(s)) {
+#endif /* DOCHKVAR */
+ zq = atxbuf;
+ atxn = CMDBL;
+ if ((x = (*f)(*xp,&zq,&atxn)) < 0) {
+ if (np) free(np);
+ return(-2);
+ }
+#ifdef DOCHKVAR
+ /* reduce cc by number of \\ consumed by conversion */
+ /* function (needed for OS/2, where \ is path separator) */
+ cc -= (strlen(*xp) - strlen(atxbuf));
+#endif /* DOCHKVAR */
+ *xp = atxbuf;
+ if (!atxbuf[0]) { /* Result empty, use default */
+ *xp = xdef;
+ cc = strlen(xdef);
+ }
+#ifdef DOCHKVAR
+ break;
+ }
+ s++;
+ }
+#endif /* DOCHKVAR */
+ }
+#endif /* NOSPL */
+
+#ifdef DTILDE
+ if (dirflg && *(*xp) == '~') {
+ debug(F111,"cmifi tilde_expand A",*xp,cc);
+ dirp = tilde_expand(*xp); /* Expand tilde, if any... */
+ if (!dirp) dirp = "";
+ if (*dirp) {
+ int i, xx;
+ char * sp;
+ xc = cc; /* Length of ~thing */
+ xx = setatm(dirp,0); /* Copy expansion to atom buffer */
+ debug(F111,"cmifi tilde_expand B",atmbuf,cc);
+ if (xx < 0) {
+ printf("Expanded name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ debug(F111,"cmifi tilde_expand xc","",xc);
+ for (i = 0; i < xc; i++) {
+ cmdchardel(); /* Back up over ~thing */
+ bp--;
+ }
+ xc = cc; /* How many new ones we just got */
+ sp = atmbuf;
+ printf("%s",sp); /* Print them */
+ while ((*bp++ = *sp++)) ; /* Copy to command buffer */
+ bp--; /* Back up over NUL */
+ }
+ *xp = atmbuf;
+ }
+#endif /* DTILDE */
+
+ sp = *xp + cc;
+
+#ifdef UNIXOROSK
+ if (!strcmp(atmbuf,"..")) {
+ printf(" ");
+ ckstrncat(cmdbuf," ",CMDBL);
+ cc++;
+ bp++;
+ *wild = 0;
+ *xp = atmbuf;
+ break;
+ } else if (!strcmp(atmbuf,".")) {
+ bleep(BP_WARN);
+ if (np) free(np);
+ return(-1);
+ } else {
+ /* This patches a glitch when user types "./foo<ESC>" */
+ /* in which the next two chars are omitted from the */
+ /* expansion. There should be a better fix, however, */
+ /* since there is no problem with "../foo<ESC>". */
+ char *p = *xp;
+ if (*p == '.' && *(p+1) == '/')
+ cc -= 2;
+ }
+#endif /* UNIXOROSK */
+
+#ifdef datageneral
+ *sp++ = '+'; /* Data General AOS wildcard */
+#else
+ *sp++ = '*'; /* Others */
+#endif /* datageneral */
+ *sp-- = '\0';
+#ifdef GEMDOS
+ if (!strchr(*xp, '.')) /* abde.e -> abcde.e* */
+ strcat(*xp, ".*"); /* abc -> abc*.* */
+#endif /* GEMDOS */
+ /* Add wildcard and expand list. */
+#ifdef COMMENT
+ /* This kills partial completion when ESC given in path segment */
+ nzxopts |= dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY);
+#else
+ /* nzxopts = 0; */
+#endif /* COMMENT */
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ nfiles = y;
+ debug(F111,"cmifi nzxpand",*xp,y);
+ if (y > 0) {
+#ifdef OS2
+ znext(filbuf); /* Get first */
+#ifdef ZXREWIND
+ zxrewind(); /* Must "rewind" */
+#else
+ nzxpand(*xp,nxzopts);
+#endif /* ZXREWIND */
+#else /* Not OS2 */
+ ckstrncpy(filbuf,mtchs[0],CKMAXPATH);
+#endif /* OS2 */
+ } else
+ *filbuf = '\0';
+ filbuf[CKMAXPATH] = NUL;
+ *sp = '\0'; /* Remove wildcard. */
+ debug(F111,"cmifi filbuf",filbuf,y);
+ debug(F111,"cmifi *xp",*xp,cc);
+
+ *wild = (y > 1);
+ if (y == 0) {
+ if (!nomsg) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?No %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ } else {
+ bleep(BP_WARN);
+ if (np) free(np);
+ return(-1);
+ }
+ } else if (y < 0) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?Too many %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ } else if (y > 1 /* Not unique */
+#ifndef VMS
+ || (y == 1 && isdir(filbuf)) /* Unique directory */
+#endif /* VMS */
+ ) {
+#ifndef NOPARTIAL
+/* Partial filename completion */
+ int j, k; char c;
+ k = 0;
+ debug(F111,"cmifi partial",filbuf,cc);
+#ifdef OS2
+ {
+ int cur = 0,
+ len = 0,
+ len2 = 0,
+ min = strlen(filbuf),
+ found = 0;
+ char localfn[CKMAXPATH+1];
+
+ len = min;
+ for (j = 1; j <= y; j++) {
+ znext(localfn);
+ if (dirflg && !isdir(localfn))
+ continue;
+ found = 1;
+ len2 = strlen(localfn);
+ for (cur = cc;
+ cur < len && cur < len2 && cur <= min;
+ cur++
+ ) {
+ /* OS/2 or Windows, case doesn't matter */
+ if (tolower(filbuf[cur]) != tolower(localfn[cur]))
+ break;
+ }
+ if (cur < min)
+ min = cur;
+ }
+ if (!found)
+ min = cc;
+ filbuf[min] = NUL;
+ if (min > cc)
+ k++;
+ }
+#else /* OS2 */
+ for (i = cc; (c = filbuf[i]); i++) {
+ for (j = 1; j < y; j++)
+ if (mtchs[j][i] != c) break;
+ if (j == y) k++;
+ else filbuf[i] = filbuf[i+1] = NUL;
+ }
+#endif /* OS2 */
+
+
+#ifndef VMS
+ /* isdir() function required for this! */
+ if (y == 1 && isdir(filbuf)) { /* Dont we already know this? */
+ int len;
+ len = strlen(filbuf);
+ if (len > 0 && len < ATMBL - 1) {
+ if (filbuf[len-1] != dirsep) {
+ filbuf[len] = dirsep;
+ filbuf[len+1] = NUL;
+ }
+ }
+/*
+ At this point, before just doing partial completion, we should look first to
+ see if the given directory does indeed have any subdirectories (dirflg) or
+ files (!dirflg); if it doesn't we should do full completion. Otherwise, the
+ result looks funny to the user and "?" blows up the command for no good
+ reason.
+*/
+ {
+ int flags = 0;
+ filbuf[len+1] = '*';
+ filbuf[len+2] = NUL;
+ if (dirflg) flags = ZX_DIRONLY;
+ children = nzxpand(filbuf,flags);
+ debug(F111,"cmifi children",filbuf,children);
+ filbuf[len+1] = NUL;
+ nzxpand(filbuf,flags); /* Restore previous list */
+ if (children == 0)
+ goto NOSUBDIRS;
+ }
+ if (len + 1 > cc)
+ k++;
+ }
+ /* Add doublequotes if there are spaces in the name */
+ {
+ int x;
+ if (qflag) {
+ x = (qflag == '}'); /* (or braces) */
+ } else {
+ x = !dblquo;
+ }
+ if (filbuf[0] != '"' && filbuf[0] != '{')
+ k = dquote(filbuf,ATMBL,x);
+ }
+#endif /* VMS */
+ debug(F111,"cmifi REPAINT filbuf",filbuf,k);
+ if (k > 0) { /* Got more characters */
+ debug(F101,"cmifi REPAINT cc","",cc);
+ debug(F101,"cmifi REPAINT xc","",xc);
+ debug(F110,"cmifi REPAINT bp-cc",bp-cc,0);
+ debug(F110,"cmifi REPAINT bp-xc",bp-xc,0);
+ sp = filbuf + cc; /* Point to new ones */
+ if (qflag || strncmp(filbuf,bp-cc,cc)) { /* Repaint? */
+ int x;
+ x = cc;
+ if (qflag) x++;
+ for (i = 0; i < x; i++) {
+ cmdchardel(); /* Back up over old partial spec */
+ bp--;
+ }
+ sp = filbuf; /* Point to new word start */
+ debug(F110,"cmifi erase ok",sp,0);
+ }
+ cc = k; /* How many new ones we just got */
+ printf("%s",sp); /* Print them */
+ while ((*bp++ = *sp++)) ; /* Copy to command buffer */
+ bp--; /* Back up over NUL */
+ debug(F110,"cmifi partial cmdbuf",cmdbuf,0);
+ if (setatm(filbuf,0) < 0) {
+ printf("?Partial name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ debug(F111,"cmifi partial atmbuf",atmbuf,cc);
+ *xp = atmbuf;
+ }
+#endif /* NOPARTIAL */
+ bleep(BP_WARN);
+ } else { /* Unique, complete it. */
+#ifndef VMS
+#ifdef CK_TMPDIR
+ /* isdir() function required for this! */
+ NOSUBDIRS:
+ debug(F111,"cmifi unique",filbuf,children);
+ if (isdir(filbuf) && children > 0) {
+ int len;
+ len = strlen(filbuf);
+ if (len > 0 && len < ATMBL - 1) {
+ if (filbuf[len-1] != dirsep) {
+ filbuf[len] = dirsep;
+ filbuf[len+1] = NUL;
+ }
+ }
+ sp = filbuf + cc;
+ bleep(BP_WARN);
+ printf("%s",sp);
+ cc++;
+ while ((*bp++ = *sp++)) ;
+ bp--;
+ if (setatm(filbuf,0) < 0) {
+ printf("?Directory name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ debug(F111,"cmifi directory atmbuf",atmbuf,cc);
+ *xp = atmbuf;
+ } else { /* Not a directory or dirflg */
+#endif /* CK_TMPDIR */
+#endif /* VMS */
+#ifndef VMS /* VMS dir names are special */
+#ifndef datageneral /* VS dirnames must not end in ":" */
+ if (dirflg) {
+ int len;
+ len = strlen(filbuf);
+ if (len > 0 && len < ATMBL - 1) {
+ if (filbuf[len-1] != dirsep) {
+ filbuf[len] = dirsep;
+ filbuf[len+1] = NUL;
+ }
+ }
+ }
+#endif /* datageneral */
+#endif /* VMS */
+ sp = filbuf + cc; /* Point past what user typed. */
+ {
+ int x;
+ if (qflag) {
+ x = (qflag == '}');
+ } else {
+ x = !dblquo;
+ }
+ if (filbuf[0] != '"' && filbuf[0] != '{')
+ dquote(filbuf,ATMBL,x);
+ }
+ if (qflag || strncmp(filbuf,bp-cc,cc)) { /* Repaint? */
+ int x;
+ x = cc;
+ if (qflag) x++;
+ for (i = 0; i < x; i++) {
+ cmdchardel(); /* Back up over old partial spec */
+ bp--;
+ }
+ sp = filbuf; /* Point to new word start */
+ debug(F111,"cmifi after erase sp=",sp,cc);
+ }
+ printf("%s ",sp); /* Print the completed name. */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(sp); /* Add the characters to cmdbuf. */
+ if (setatm(filbuf,0) < 0) { /* And to atmbuf. */
+ printf("?Completed name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ inword = cmflgs = 0;
+ *xp = brstrip(atmbuf); /* Return pointer to atmbuf. */
+ if (dirflg && !isdir(*xp)) {
+ printf("?Not a directory - %s\n", filbuf);
+ if (np) free(np);
+ return(-9);
+ }
+ if (np) free(np);
+#ifndef NOLASTFILE
+ makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+ return(0);
+#ifndef VMS
+#ifdef CK_TMPDIR
+ }
+#endif /* CK_TMPDIR */
+#endif /* VMS */
+ }
+ break;
+
+ case 3: /* Question mark - file menu wanted */
+ if (*xhlp == NUL)
+ printf(dirflg ? " Directory name" : " Input file specification");
+ else
+ printf(" %s",xhlp);
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ /* If user typed an opening quote or brace, just skip past it */
+
+ if (**xp == '"' || **xp == '{') {
+ *xp = *xp + 1;
+ xc--;
+ cc--;
+ }
+#ifndef NOSPL
+ if (f) { /* If a conversion function is given */
+#ifdef DOCHKVAR
+ char *s = *xp; /* See if there are any variables in */
+ while (*s) { /* the string and if so, expand them */
+ if (chkvar(s)) {
+#endif /* DOCHKVAR */
+ zq = atxbuf;
+ atxn = CMDBL;
+ if ((x = (*f)(*xp,&zq,&atxn)) < 0) {
+ if (np) free(np);
+ return(-2);
+ }
+#ifdef DOCHKVAR
+ /* reduce cc by number of \\ consumed by conversion */
+ /* function (needed for OS/2, where \ is path separator) */
+ cc -= (strlen(*xp) - strlen(atxbuf));
+#endif /* DOCHKVAR */
+ *xp = atxbuf;
+#ifdef DOCHKVAR
+ break;
+ }
+ s++;
+ }
+#endif /* DOCHKVAR */
+ }
+#endif /* NOSPL */
+ debug(F111,"cmifi ? *xp, cc",*xp,cc);
+ sp = *xp + cc; /* Insert "*" at end */
+#ifdef datageneral
+ *sp++ = '+'; /* Insert +, the DG wild card */
+#else
+ *sp++ = '*';
+#endif /* datageneral */
+ *sp-- = '\0';
+#ifdef GEMDOS
+ if (! strchr(*xp, '.')) /* abde.e -> abcde.e* */
+ strcat(*xp, ".*"); /* abc -> abc*.* */
+#endif /* GEMDOS */
+ debug(F110,"cmifi ? wild",*xp,0);
+
+ nzxopts |= dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY);
+
+ debug(F101,"cmifi matchdot","",matchdot);
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ y = nzxpand(*xp,nzxopts);
+ nfiles = y;
+ *sp = '\0';
+ if (y == 0) {
+ if (nomsg) {
+ printf(": %s\n",atmbuf);
+ printf("%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ if (np) free(np);
+ return(-1);
+ } else {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?No %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ }
+ } else if (y < 0) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off Limits: %s\n",atmbuf);
+ else
+#endif /* CKROOT */
+ printf("?Too many %s match - %s\n",
+ dirflg ? "directories" : "files", atmbuf);
+ if (np) free(np);
+ return(-9);
+ } else {
+ printf(", one of the following:\n");
+ if (filhelp((int)y,"","",1,dirflg) < 0) {
+ if (np) free(np);
+ return(-9);
+ }
+ }
+ printf("%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ break;
+#endif /* MAC */
+ }
+#ifdef BS_DIRSEP
+ dirnamflg = 1;
+ x = gtword(0); /* No, get a word */
+ dirnamflg = 0;
+#else
+ x = gtword(0); /* No, get a word */
+#endif /* BS_DIRSEP */
+ *xp = atmbuf;
+ }
+}
+
+/* C M F L D -- Parse an arbitrary field */
+/*
+ Returns:
+ -3 if no input present when required,
+ -2 if field too big for buffer,
+ -1 if reparse needed,
+ 0 otherwise, xp pointing to string result.
+
+ NOTE: Global flag keepallchars says whether this routine should break on CR
+ or LF: needed for MINPUT targets and DECLARE initializers, where we want to
+ keep control characters if the user specifies them (March 2003). It might
+ have been better to change the calling sequence but that was not practical.
+*/
+int
+cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+ int x, xc;
+ char *zq;
+
+ inword = 0; /* Initialize counts & pointers */
+ cc = 0;
+ xc = 0;
+ *xp = "";
+
+ debug(F110,"cmfld xdef 1",xdef,0);
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+ ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
+ xdef = cmdefault;
+
+ debug(F111,"cmfld xdef 2",xdef,cmflgs);
+ debug(F111,"cmfld atmbuf 1",atmbuf,xc);
+
+ if ((x = cmflgs) != 1) { /* Already confirmed? */
+ x = gtword(0); /* No, get a word */
+ } else {
+ if (setatm(xdef,0) < 0) { /* If so, use default, if any. */
+ printf("?Default too long\n");
+ return(-9);
+ }
+ }
+ *xp = atmbuf; /* Point to result. */
+ debug(F111,"cmfld atmbuf 2",atmbuf,cmflgs);
+
+ while (1) {
+ xc += cc; /* Count the characters. */
+ debug(F111,"cmfld gtword",atmbuf,xc);
+ debug(F101,"cmfld x","",x);
+ switch (x) {
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -3: /* Empty. */
+ case -2: /* Out of space. */
+ case -1: /* Reparse needed */
+ return(x);
+ case 1: /* CR */
+ case 0: /* SP */
+ debug(F111,"cmfld 1",atmbuf,xc);
+ if (xc == 0) { /* If no input, return default. */
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ }
+ *xp = atmbuf; /* Point to what we got. */
+ debug(F111,"cmfld 2",atmbuf,((f) ? 1 : 0));
+ if (f) { /* If a conversion function is given */
+ zq = atxbuf; /* employ it now. */
+ atxn = CMDBL;
+ if ((*f)(*xp,&zq,&atxn) < 0)
+ return(-2);
+ debug(F111,"cmfld 3",atxbuf,xc);
+ /* Replace by new value -- for MINPUT only keep all chars */
+ if (setatm(atxbuf,keepallchars ? 3:1) < 0) { /* 16 Mar 2003 */
+ printf("Value too long\n");
+ return(-9);
+ }
+ *xp = atmbuf;
+ }
+ debug(F111,"cmfld 4",atmbuf,xc);
+ if (**xp == NUL) { /* If variable evaluates to null */
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ if (**xp == NUL) x = -3; /* If still empty, return -3. */
+ }
+ debug(F111,"cmfld returns",*xp,x);
+ return(x);
+ case 2: /* ESC */
+ if (xc == 0 && *xdef) {
+ printf("%s ",xdef); /* If at beginning of field, */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(xdef); /* Supply default. */
+ inword = cmflgs = 0;
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ } else /* Return as if whole field */
+ return(0); /* typed, followed by space. */
+ } else {
+ bleep(BP_WARN);
+ }
+ break;
+ case 3: /* Question mark */
+ debug(F110,"cmfld QUESTIONMARK",cmdbuf,0);
+ if (*xhlp == NUL)
+ printf(" Please complete this field");
+ else
+ printf(" %s",xhlp);
+ printf("\n%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ break;
+ }
+ debug(F111,"cmfld gtword A x",cmdbuf,x);
+ x = gtword(0);
+ debug(F111,"cmfld gtword B x",cmdbuf,x);
+ }
+}
+
+
+/* C M T X T -- Get a text string, including confirmation */
+
+/*
+ Print help message 'xhlp' if ? typed, supply default 'xdef' if null
+ string typed. Returns:
+
+ -1 if reparse needed or buffer overflows.
+ 1 otherwise.
+
+ with cmflgs set to return code, and xp pointing to result string.
+*/
+int
+cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
+
+ int x, i;
+ char *xx, *zq;
+ static int xc;
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+ cmfldflgs = 0;
+
+ cmdefault[0] = NUL;
+ if (*xdef)
+ ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
+ xdef = cmdefault;
+
+ debug(F101,"cmtxt cmflgs","",cmflgs);
+ inword = 0; /* Start atmbuf counter off at 0 */
+ cc = 0;
+ if (cmflgs == -1) { /* If reparsing, */
+ *xp = pp;
+ xc = (int)strlen(*xp); /* get back the total text length, */
+ bp = *xp; /* and back up the pointers. */
+ np = *xp;
+ pp = *xp;
+ } else { /* otherwise, */
+ /* debug(F100,"cmtxt: fresh start","",0); */
+ *xp = ""; /* start fresh. */
+ xc = 0;
+ }
+ *atmbuf = NUL; /* And empty the atom buffer. */
+ rtimer(); /* Reset timer */
+ if ((x = cmflgs) != 1) {
+ int done = 0;
+ while (!done) {
+ x = gtword(0); /* Get first word. */
+ *xp = pp; /* Save pointer to it. */
+ /* debug(F111,"cmtxt:",*xp,cc); */
+ if (x == -10) {
+ if (gtimer() > timelimit) {
+ /* if (!quiet) printf("?Timed out\n"); */
+ return(x);
+ }
+ } else
+ done = 1;
+ }
+ }
+ while (1) { /* Loop for each word in text. */
+ xc += cc; /* Char count for all words. */
+ /* debug(F111,"cmtxt gtword",atmbuf,xc); */
+ /* debug(F101,"cmtxt x","",x); */
+ switch (x) {
+ case -10:
+ if (gtimer() > timelimit) {
+#ifdef IKSD
+ extern int inserver;
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit);
+ doexit(GOOD_EXIT,0);
+ }
+#endif /* IKSD */
+ /* if (!quiet) printf("?Timed out\n"); */
+ return(-10);
+ } else {
+ x = gtword(0);
+ continue;
+ }
+ case -9: /* Buffer overflow */
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+#ifdef MAC
+ case -3: /* Quit/Timeout */
+#endif /* MAC */
+ case -2: /* Overflow */
+ case -1: /* Deletion */
+ return(x);
+ case 0: /* Space */
+ xc++; /* Just count it */
+ break;
+ case 1: /* CR or LF */
+ if (xc == 0) *xp = xdef;
+ if (f) { /* If a conversion function is given */
+ char * sx = atxbuf;
+ zq = atxbuf; /* Point to the expansion buffer */
+ atxn = CMDBL; /* specify its length */
+ /* debug(F111,"cmtxt calling (*f)",*xp,atxbuf); */
+ if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
+ sx = atxbuf;
+#ifndef COMMENT
+ cc = 0;
+ while (*sx++) cc++; /* (faster than calling strlen) */
+#else
+ cc = (int)strlen(atxbuf);
+#endif /* COMMENT */
+ /* Should be equal to (CMDBL - atxn) but isn't always. */
+ /* Why not? */
+ if (cc < 1) { /* Nothing in expansion buffer? */
+ *xp = xdef; /* Point to default string instead. */
+#ifndef COMMENT
+ sx = xdef;
+ while (*sx++) cc++; /* (faster than calling strlen) */
+#else
+ cc = strlen(xdef);
+#endif /* COMMENT */
+ } else { /* Expansion function got something */
+ *xp = atxbuf; /* return pointer to it. */
+ }
+ debug(F111,"cmtxt (*f)",*xp,cc);
+ } else { /* No expansion function */
+#ifndef COMMENT
+ /* Avoid a strlen() call */
+ xx = *xp;
+ cc = 0;
+ while (*xx++) cc++;
+#else
+ /* NO! xc is apparently not always set appropriately */
+ cc = xc;
+#endif /* COMMENT */
+ }
+ xx = *xp;
+#ifdef COMMENT
+ /* strlen() no longer needed */
+ for (i = (int)strlen(xx) - 1; i > 0; i--)
+#else
+ for (i = cc - 1; i > 0; i--)
+#endif /* COMMENT */
+ if (xx[i] != SP) /* Trim trailing blanks */
+ break;
+ else
+ xx[i] = NUL;
+ return(x);
+ case 2: /* ESC */
+ if (xc == 0) { /* Nothing typed yet */
+ if (*xdef) { /* Have a default for this field? */
+ printf("%s ",xdef); /* Yes, supply it */
+ inword = cmflgs = 0;
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ cc = addbuf(xdef);
+ } else bleep(BP_WARN); /* No default */
+ } else { /* Already in field */
+ int x; char *p;
+ x = strlen(atmbuf);
+ if (ckstrcmp(atmbuf,xdef,x,0)) { /* Matches default? */
+ bleep(BP_WARN); /* No */
+ } else if ((int)strlen(xdef) > x) { /* Yes */
+ p = xdef + x;
+ printf("%s ", p);
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(p);
+ inword = cmflgs = 0;
+ debug(F110,"cmtxt: addbuf",cmdbuf,0);
+ } else {
+ bleep(BP_WARN);
+ }
+ }
+ break;
+ case 3: /* Question Mark */
+ if (*xhlp == NUL)
+ printf(" Text string");
+ else
+ printf(" %s",xhlp);
+ printf("\n%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ break;
+ default:
+ printf("?Unexpected return code from gtword() - %d\n",x);
+ return(-2);
+ }
+ x = gtword(0);
+ }
+}
+
+/* C M K E Y -- Parse a keyword */
+
+/*
+ Call with:
+ table -- keyword table, in 'struct keytab' format;
+ n -- number of entries in table;
+ xhlp -- pointer to help string;
+ xdef -- pointer to default keyword;
+ f -- string preprocessing function (e.g. to evaluate variables)
+ pmsg -- 0 = don't print error messages
+ 1 = print error messages
+ 2 = include CM_HLP keywords even if invisible
+ 3 = 1+2
+ 4 = parse a switch (keyword possibly ending in : or =)
+ 8 = don't strip comments (used, e.g., for "help #")
+ Returns:
+ -3 -- no input supplied and no default available
+ -2 -- input doesn't uniquely match a keyword in the table
+ -1 -- user deleted too much, command reparse required
+ n >= 0 -- value associated with keyword
+*/
+
+/*
+ Front ends for cmkey2():
+ cmkey() - The normal keyword parser
+ cmkeyx() - Like cmkey() but suppresses error messages
+ cmswi() - Switch parser
+*/
+int
+cmkey(table,n,xhlp,xdef,f)
+/* cmkey */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+ return(cmkey2(table,n,xhlp,xdef,"",f,1));
+}
+int
+cmkeyx(table,n,xhlp,xdef,f)
+/* cmkeyx */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+ return(cmkey2(table,n,xhlp,xdef,"",f,0));
+}
+int
+cmswi(table,n,xhlp,xdef,f)
+/* cmswi */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+ return(cmkey2(table,n,xhlp,xdef,"",f,4));
+}
+
+int
+cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
+ struct keytab table[];
+ int n;
+ char *xhlp, *xdef;
+ char *tok;
+ xx_strp f;
+ int pmsg;
+{ /* cmkey2 */
+ extern int havetoken;
+ int i, tl, y, z = 0, zz, xc, wordlen = 0, cmswitch;
+ char *xp, *zq;
+
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+
+ cmfldflgs = 0;
+ if (!table) {
+ printf("?Keyword table missing\n");
+ return(-9);
+ }
+ tl = (int)strlen(tok);
+
+ inword = xc = cc = 0; /* Clear character counters. */
+ cmswitch = pmsg & 4; /* Flag for parsing a switch */
+
+ debug(F101,"cmkey: pmsg","",pmsg);
+ debug(F101,"cmkey: cmflgs","",cmflgs);
+ debug(F101,"cmkey: cmswitch","",cmswitch);
+ /* debug(F101,"cmkey: cmdbuf","",cmdbuf);*/
+
+ ppvnambuf[0] = NUL;
+
+ if ((zz = cmflgs) == 1) { /* Command already entered? */
+ if (setatm(xdef,0) < 0) { /* Yes, copy default into atom buf */
+ printf("?Default too long\n");
+ return(-9);
+ }
+ rtimer(); /* Reset timer */
+ } else { /* Otherwise get a command word */
+ rtimer(); /* Reset timer */
+ if (pmsg & 8) /* 8 is for parsing HELP tokens */
+ zz = gtword(4);
+ else
+ zz = gtword((pmsg == 4) ? 1 : 0);
+ }
+
+ debug(F101,"cmkey table length","",n);
+ debug(F101,"cmkey cmflgs","",cmflgs);
+ debug(F101,"cmkey cc","",cc);
+
+ while (1) {
+ xc += cc;
+ debug(F111,"cmkey gtword xc",atmbuf,xc);
+ debug(F101,"cmkey gtword zz","",zz);
+
+ switch (zz) {
+ case -10: /* Timeout */
+ if (gtimer() < timelimit) {
+ if (pmsg & 8) /* 8 is for parsing HELP tokens */
+ zz = gtword(4);
+ else
+ zz = gtword((pmsg == 4) ? 1 : 0);
+ continue;
+ } else {
+#ifdef IKSD
+ extern int inserver;
+ if (inserver) {
+ printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit);
+ doexit(GOOD_EXIT,0);
+ }
+#endif /* IKSD */
+ return(-10);
+ }
+ case -5:
+ return(cmflgs = 0);
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -3: /* Null Command/Quit/Timeout */
+ case -2: /* Buffer overflow */
+ case -1: /* Or user did some deleting. */
+ return(cmflgs = zz);
+
+
+ case 1: /* CR */
+ case 0: /* User terminated word with space */
+ case 4: /* or switch ending in : or = */
+ wordlen = cc; /* Length if no conversion */
+ if (cc == 0) { /* Supply default if we got nothing */
+ if ((wordlen = setatm(xdef,(zz == 4) ? 2 : 0)) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ }
+ if (zz == 1 && cc == 0) /* Required field missing */
+ return(-3);
+
+ if (f) { /* If a conversion function is given */
+ char * p2;
+ zq = atxbuf; /* apply it */
+ p2 = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2);
+ debug(F110,"cmkey atxbuf after *f",atxbuf,0);
+ if (!*p2) /* Supply default if we got nothing */
+ p2 = xdef;
+ ckstrncpy(ppvnambuf,atmbuf,PPVLEN);
+ if ((wordlen = setatm(p2,(zz == 4) ? 2 : 0)) < 0) {
+ printf("Evaluated keyword too long\n");
+ return(-9);
+ }
+#ifdef M_UNGW
+ /*
+ This bit lets us save more than one "word".
+ For example, "define \%x echo one two three", "\%x".
+ It works too, but it breaks labels, and therefore
+ WHILE and FOR loops, etc.
+ */
+ if (p2[wordlen] >= SP) {
+ p2 += wordlen;
+ while (*p2 == SP) p2++;
+ if (*p2) {
+ ungword();
+ pp = p2;
+ }
+ }
+#endif /* M_UNGW */
+ }
+#ifdef COMMENT /* ^^^ */
+ if (cmswitch && *atmbuf != '/') {
+ if (pmsg & 1) {
+ bleep(BP_FAIL);
+ printf("?Not a switch - %s\n",atmbuf);
+ }
+ cmflgs = -2;
+ return(-6);
+ }
+#endif /* COMMENT */
+ if (cmswitch) {
+ int i;
+ for (i = 0; i < wordlen; i++) {
+ if (atmbuf[i] == ':' || atmbuf[i] == '=') {
+ brkchar = atmbuf[i];
+ atmbuf[i] = NUL;
+ break;
+ }
+ }
+ }
+
+#ifdef TOKPRECHECK
+/* This was an effective optimization but it breaks sometimes on labels. */
+ if (tl && !isalpha(atmbuf[0])) { /* Precheck for token */
+ for (i = 0; i < tl; i++) { /* Save function call to ckstrchr */
+ if (tok[i] == atmbuf[0]) {
+ debug(F000,"cmkey token:",atmbuf,*atmbuf);
+ ungword(); /* Put back the following word */
+ return(-5); /* Special return code for token */
+ }
+ }
+ }
+#endif /* TOKPRECHECK */
+
+ y = lookup(table,atmbuf,n,&z); /* Look up word in the table */
+ debug(F111,"cmkey lookup",atmbuf,y);
+ debug(F101,"cmkey zz","",zz);
+ debug(F101,"cmkey cmflgs","",cmflgs);
+ debug(F101,"cmkey crflag","",crflag);
+ switch (y) {
+ case -3: /* Nothing to look up */
+ break;
+ case -2: /* Ambiguous */
+ cmflgs = -2;
+ if (pmsg & 1) {
+ bleep(BP_FAIL);
+ printf("?Ambiguous - %s\n",atmbuf);
+ return(-9);
+ }
+ return(-2);
+ case -1: /* Not found at all */
+#ifndef TOKPRECHECK
+ if (tl) {
+ for (i = 0; i < tl; i++) /* Check for token */
+ if (tok[i] == *atmbuf) { /* Got one */
+ debug(F000,"cmkey token:",atmbuf,*atmbuf);
+ ungword(); /* Put back the following word */
+ return(-5); /* Special return code for token */
+ }
+ }
+#endif /* TOKPRECHECK */
+
+ if (tl == 0) { /* No tokens were included */
+#ifdef OS2
+ /* In OS/2 and Windows, allow for a disk letter like DOS */
+ if (isalpha(*atmbuf) && *(atmbuf+1) == ':')
+ return(-7);
+#endif /* OS2 */
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf("?No keywords match - %s\n",atmbuf); /* cmkey */
+ }
+ return(cmflgs = -9);
+ } else {
+ if (cmflgs == 1 || cmswitch) /* cmkey2 or cmswi */
+ return(cmflgs = -6);
+ else
+ return(cmflgs = -2);
+ /* The -6 code is to let caller try another table */
+ }
+ break;
+ default:
+#ifdef CK_RECALL
+ if (test(table[z].flgs,CM_NOR)) no_recall = 1;
+#endif /* CK_RECALL */
+ if (zz == 4)
+ swarg = 1;
+ cmkwflgs = table[z].flgs;
+ break;
+ }
+ return(y);
+
+ case 2: /* User terminated word with ESC */
+ debug(F101,"cmkey Esc cc","",cc);
+ if (cc == 0) {
+ if (*xdef != NUL) { /* Nothing in atmbuf */
+ printf("%s ",xdef); /* Supply default if any */
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(xdef);
+ if (setatm(xdef,0) < 0) {
+ printf("?Default too long\n");
+ return(-9);
+ }
+ inword = cmflgs = 0;
+ debug(F111,"cmkey: default",atmbuf,cc);
+ } else {
+ debug(F101,"cmkey Esc pmsg","",0);
+#ifdef COMMENT
+/*
+ Chained FDBs... The idea is that this function might not have a default,
+ but the next one might. But if it doesn't, there is no way to come back to
+ this one. To be revisited later...
+*/
+ if (xcmfdb) /* Chained fdb -- try next one */
+ return(-3);
+#endif /* COMMENT */
+ if (pmsg & (1|4)) { /* So for now just beep */
+ bleep(BP_WARN);
+ }
+ break;
+ }
+ }
+ if (f) { /* If a conversion function is given */
+ char * pp;
+ zq = atxbuf; /* apply it */
+ pp = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(atmbuf,&zq,&atxn) < 0)
+ return(-2);
+ if (!*pp)
+ pp = xdef;
+ if (setatm(pp,0) < 0) {
+ printf("Evaluated keyword too long\n");
+ return(-9);
+ }
+ }
+ y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */
+ debug(F111,"cmkey lookup y",atmbuf,y);
+ debug(F111,"cmkey lookup z",atmbuf,z);
+ if (y == -2 && z >= 0 && z < n) { /* Ambiguous */
+#ifndef NOPARTIAL
+ int j, k, len = 9999; /* Do partial completion */
+ /* Skip past any abbreviations in the table */
+ for ( ; z < n; z++) {
+ if ((table[z].flgs & CM_ABR) == 0)
+ break;
+ if (!(table[z].flgs & CM_HLP) || (pmsg & 2))
+ break;
+ }
+ debug(F111,"cmkey partial z",atmbuf,z);
+ debug(F111,"cmkey partial n",atmbuf,n);
+ for (j = z+1; j < n; j++) {
+ debug(F111,"cmkey partial j",table[j].kwd,j);
+ if (ckstrcmp(atmbuf,table[j].kwd,cc,0))
+ break;
+ if (table[j].flgs & CM_ABR)
+ continue;
+ if ((table[j].flgs & CM_HLP) && !(pmsg & 2))
+ continue;
+ k = ckstrpre(table[z].kwd,table[j].kwd);
+ debug(F111,"cmkey partial k",table[z].kwd,k);
+ if (k < len)
+ len = k; /* Length of longest common prefix */
+ }
+ debug(F111,"cmkey partial len",table[z].kwd,len);
+ if (len != 9999 && len > cc) {
+ ckstrncat(atmbuf,table[z].kwd+cc,ATMBL);
+ atmbuf[len] = NUL;
+ printf("%s",atmbuf+cc);
+ ckstrncat(cmdbuf,atmbuf+cc,CMDBL);
+ xc += (len - cc);
+ cc = len;
+ }
+#endif /* NOPARTIAL */
+ bleep(BP_WARN);
+ break;
+ } else if (y == -3) {
+ bleep(BP_WARN);
+ break;
+ } else if (y == -1) { /* Not found */
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf("?No keywords match - \"%s\"\n",atmbuf);
+ }
+ cmflgs = -2;
+ return(-9);
+ }
+/*
+ If we found it, but it's a help-only keyword and the "help" bit is not
+ set in pmsg, then not found.
+*/
+ debug(F101,"cmkey flgs","",table[z].flgs);
+ if (test(table[z].flgs,CM_HLP) && ((pmsg & 2) == 0)) {
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf("?No keywords match - %s\n",atmbuf);
+ }
+ cmflgs = -2;
+ return(-9);
+ }
+/*
+ See if the keyword just found has the CM_ABR bit set in its flgs field, and
+ if so, search forwards in the table for a keyword that has the same kwval
+ but does not have CM_ABR (or CM_INV?) set, and then expand using the full
+ keyword. WARNING: This assumes that (a) keywords are in alphabetical order,
+ and (b) the CM_ABR bit is set only if the the abbreviated keyword is a true
+ abbreviation (left substring) of the full keyword.
+*/
+ if (test(table[z].flgs,CM_ABR)) {
+ int zz;
+ for (zz = z+1; zz < n; zz++)
+ if ((table[zz].kwval == table[z].kwval) &&
+ (!test(table[zz].flgs,CM_ABR)) &&
+ (!test(table[zz].flgs,CM_INV))) {
+ z = zz;
+ break;
+ }
+ }
+ xp = table[z].kwd + cc;
+ if (cmswitch && test(table[z].flgs,CM_ARG)) {
+#ifdef VMS
+ printf("%s=",xp);
+ brkchar = '=';
+#else
+ printf("%s:",xp);
+ brkchar = ':';
+#endif /* VMS */
+ } else {
+ printf("%s ",xp);
+ brkchar = SP;
+ }
+#ifdef CK_RECALL
+ if (test(table[z].flgs,CM_NOR)) no_recall = 1;
+#endif /* CK_RECALL */
+ cmkwflgs = table[z].flgs;
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ addbuf(xp);
+ if (cmswitch && test(table[z].flgs,CM_ARG)) {
+ bp--; /* Replace trailing space with : */
+#ifdef VMS
+ *bp++ = '=';
+#else
+ *bp++ = ':';
+#endif /* VMS */
+ *bp = NUL;
+ np = bp;
+ swarg = 1;
+ }
+ inword = 0;
+ cmflgs = 0;
+ debug(F110,"cmkey: addbuf",cmdbuf,0);
+ return(y);
+
+ case 3: /* User typed "?" */
+ if (f) { /* If a conversion function is given */
+ char * pp;
+ zq = atxbuf; /* do the conversion now. */
+ pp = atxbuf;
+ atxn = CMDBL;
+ if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2);
+ if (setatm(pp,0) < 0) {
+ printf("?Evaluated keyword too long\n");
+ return(-9);
+ }
+ }
+ y = lookup(table,atmbuf,n,&z); /* Look up what we have so far. */
+ if (y == -1) {
+ /*
+ Strictly speaking if the main keyword table search fails,
+ then we should look in the token table if one is given.
+ But in practice, tokens are also included in the main
+ keyword table.
+ */
+ cmflgs = -2;
+ if ((pmsg & 1) && !quiet) {
+ bleep(BP_FAIL);
+ printf(" No keywords match\n");
+ return(-9);
+ }
+ return(-2);
+ }
+#ifndef COMMENT
+ /* This is to allow ?-help to work immediately after a token */
+ /* without having to type an intermediate space */
+ if (tl) {
+ for (i = 0; i < tl; i++) /* Check for token */
+ if (tok[i] == *atmbuf) { /* Got one */
+ debug(F000,"cmkey token:",atmbuf,*atmbuf);
+ ungword(); /* Put back the following word */
+ cmflgs = 3; /* Force help next time around */
+ return(-5); /* Special return code for token */
+ }
+ }
+#endif /* COMMENT */
+
+ if (*xhlp == NUL)
+ printf(" One of the following:\n");
+ else
+ printf(" %s, one of the following:\n",xhlp);
+ {
+ int x;
+ x = pmsg & (2|4); /* See kwdhelp() comments */
+ if (atmbuf[0]) /* If not at beginning of field */
+ x |= 1; /* also show invisibles */
+ kwdhelp(table,n,atmbuf,"","",1,x);
+ }
+#ifndef NOSPL
+ if (!havetoken) {
+ extern int topcmd;
+ if (tl > 0 && topcmd != XXHLP) /* This is bad... */
+ printf("or a macro name (\"do ?\" for a list) ");
+ }
+#endif /* NOSPL */
+ if (*atmbuf == NUL && !havetoken) {
+ if (tl == 1)
+ printf("or the token %c\n",*tok);
+ else if (tl > 1)
+ printf("or one of the tokens: %s\n",ckspread(tok));
+ }
+ printf("%s%s", cmprom, cmdbuf);
+ fflush(stdout);
+ break;
+
+ default:
+ printf("\n%d - Unexpected return code from gtword\n",zz);
+ return(cmflgs = -2);
+ }
+ zz = (pmsg & 8) ? gtword(4) : gtword((pmsg == 4) ? 1 : 0);
+ debug(F111,"cmkey gtword zz",atmbuf,zz);
+ }
+}
+
+int
+chktok(tlist) char *tlist; {
+ char *p;
+ p = tlist;
+ while (*p != NUL && *p != *atmbuf) p++;
+ return((*p) ? (int) *p : 0);
+}
+
+/* Routines for parsing and converting dates and times */
+
+#define isdatesep(c) (ckstrchr(" -/._",c))
+
+#define CMDATEBUF 1024
+char cmdatebuf[CMDATEBUF+4] = { NUL, NUL };
+static char * cmdatebp = cmdatebuf;
+char * cmdatemsg = NULL;
+
+static struct keytab timeunits[] = {
+ { "days", TU_DAYS, 0 },
+ { "months", TU_MONTHS, 0 },
+ { "weeks", TU_WEEKS, 0 },
+ { "wks", TU_WEEKS, 0 },
+ { "years", TU_YEARS, 0 },
+ { "yrs", TU_YEARS, 0 }
+};
+static int nunits = (sizeof(timeunits) / sizeof(struct keytab));
+
+#define SYM_NOW 0
+#define SYM_TODA 1
+#define SYM_TOMO 2
+#define SYM_YEST 3
+
+static struct keytab symdaytab[] = {
+ { "now", SYM_NOW, 0 },
+ { "today", SYM_TODA, 0 },
+ { "tomorrow", SYM_TOMO, 0 },
+ { "yesterday", SYM_YEST, 0 }
+};
+static int nsymdays = (sizeof(symdaytab) / sizeof(struct keytab));
+
+static struct keytab daysofweek[] = {
+ { "Friday", 5, 0 },
+ { "Monday", 1, 0 },
+ { "Saturday", 6, 0 },
+ { "Sunday", 0, 0 },
+ { "Thursday", 4, 0 },
+ { "Tuesday", 2, 0 },
+ { "Wednesday", 3, 0 }
+};
+
+static struct keytab usatz[] = { /* RFC 822 timezones */
+ { "cdt", 5, 0 }, /* Values are GMT offsets */
+ { "cst", 6, 0 },
+ { "edt", 4, 0 },
+ { "est", 5, 0 },
+ { "gmt", 0, 0 },
+ { "mdt", 6, 0 },
+ { "mst", 7, 0 },
+ { "pdt", 7, 0 },
+ { "pst", 8, 0 },
+ { "utc", 0, 0 },
+ { "zulu", 0, 0 }
+};
+static int nusatz = (sizeof(usatz) / sizeof(struct keytab));
+
+
+/* C M C V T D A T E -- Converts free-form date to standard form. */
+
+/*
+ Call with
+ s = pointer to free-format date, time, or date and time.
+ t = 0: return time only if time was given in s.
+ t = 1: always return time (00:00:00 if no time given in s).
+ t = 2: allow time to be > 24:00:00.
+ Returns:
+ NULL on failure;
+ Pointer to "yyyymmdd hh:mm:ss" (local date-time) on success.
+*/
+
+/*
+ Before final release the following long lines should be wrapped.
+ Until then we leave them long since wrapping them wrecks EMACS's
+ C indentation.
+*/
+
+/* asctime pattern */
+static char * atp1 = "[A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]";
+
+/* asctime pattern with timezone */
+static char * atp2 = "[A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [A-Z][A-Z][A-Z] [0-9][0-9][0-9][0-9]";
+
+#define DATEBUFLEN 127
+#define YYYYMMDD 12
+
+#define isleap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+static int mdays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+#define NEED_DAYS 1
+#define NEED_HRS 2
+#define NEED_MINS 3
+#define NEED_SECS 4
+#define NEED_FRAC 5
+
+#define DELTABUF 256
+static char deltabuf[DELTABUF];
+static char * deltabp = deltabuf;
+
+char *
+cmdelta(yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss)
+ int yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss;
+/* cmdelta */ {
+ int zyy, zmo, zdd, zhh, zmm, zss;
+ long t1, t2, t3, t4;
+ long d1 = 0, d2, d3;
+ char datebuf[DATEBUFLEN+1];
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmdelta yy","",yy);
+ debug(F101,"cmdelta mo","",mo);
+ debug(F101,"cmdelta dd","",dd);
+ debug(F101,"cmdelta hh","",hh);
+ debug(F101,"cmdelta mm","",mm);
+ debug(F101,"cmdelta ss","",ss);
+ debug(F101,"cmdelta sign","",sign);
+ debug(F101,"cmdelta dyy","",dyy);
+ debug(F101,"cmdelta dmo","",dmo);
+ debug(F101,"cmdelta ddd","",ddd);
+ debug(F101,"cmdelta dhh","",dhh);
+ debug(F101,"cmdelta dmm","",dmm);
+ debug(F101,"cmdelta dss","",dss);
+ }
+#endif /* DEBLOG */
+
+ if (yy < 0 || yy > 9999) {
+ makestr(&cmdatemsg,"Base year out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (mo < 1 || mo > 12) {
+ makestr(&cmdatemsg,"Base month out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (dd < 1 || dd > mdays[mo]) {
+ makestr(&cmdatemsg,"Base day out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (hh < 0 || hh > 23) {
+ makestr(&cmdatemsg,"Base hour out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (mm < 0 || mm > 59) {
+ makestr(&cmdatemsg,"Base minute out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (ss < 0 || ss > 60) {
+ makestr(&cmdatemsg,"Base second out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ sign = (sign < 0) ? -1 : 1;
+ if (dmo != 0) {
+ if (sign > 0) {
+ mo += (sign * dmo);
+ if (mo > 12) {
+ yy += mo / 12;
+ mo = mo % 12;
+ }
+ } else if (sign < 0) {
+ while (dmo > 12) {
+ yy--;
+ dmo -= 12;
+ }
+ if (dmo < mo) {
+ mo -= dmo;
+ } else {
+ yy--;
+ mo = 12 - (dmo - mo);
+ }
+ }
+ }
+ if (dyy != 0) {
+ yy += (sign * dyy);
+ if (yy > 9999 || yy < 0) {
+ makestr(&cmdatemsg,"Result year out of range");
+ debug(F111,"cmdelta",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+ sprintf(datebuf,"%04d%02d%02d %02d:%02d:%02d",yy,mo,dd,hh,mm,ss);
+ d1 = mjd(datebuf);
+ debug(F111,"cmdelta mjd",datebuf,d1);
+
+ t1 = hh * 3600 + mm * 60 + ss; /* Base time to secs since midnight */
+ t2 = dhh * 3600 + dmm * 60 + dss; /* Delta time, ditto */
+ t3 = t1 + (sign * t2); /* Get sum (or difference) */
+
+ d2 = (sign * ddd); /* Delta days */
+ d2 += t3 / 86400L;
+
+ t4 = t3 % 86400L; /* Fractional part of day */
+ if (t4 < 0) { /* If negative */
+ d2--; /* one less delta day */
+ t4 += 86400L; /* get positive seconds */
+ }
+ hh = (int) (t4 / 3600L);
+ mm = (int) (t4 % 3600L) / 60;
+ ss = (int) (t4 % 3600L) % 60;
+
+ sprintf(datebuf,"%s %02d:%02d:%02d", mjd2date(d1+d2),hh,mm,ss);
+ {
+ int len, k, n;
+ char * p;
+ len = strlen(datebuf);
+ k = deltabp - (char *)deltabuf; /* Space used */
+ n = DELTABUF - k - 1; /* Space left */
+ if (n < len) { /* Not enough? */
+ deltabp = deltabuf; /* Wrap around */
+ n = DELTABUF;
+ }
+ ckstrncpy(deltabp,datebuf,n);
+ p = deltabp;
+ deltabp += len + 1;
+ return(p);
+ }
+}
+
+
+/* Convert Delta Time to Seconds */
+
+int
+delta2sec(s,result) char * s; long * result; {
+ long ddays = 0L, zz;
+ int dsign = 1, dhours = 0, dmins = 0, dsecs = 0, units;
+ int state = NEED_DAYS;
+ char *p, *p2, *p3, c = 0;
+ char buf[64];
+
+ if (!s) s = "";
+ if (!*s)
+ return(-1);
+ if ((int)strlen(s) > 63)
+ return(-1);
+ ckstrncpy(buf,s,64);
+ p = buf;
+
+ if (*p != '+' && *p != '-')
+ return(-1);
+
+ if (*p++ == '-')
+ dsign = -1;
+ while (*p == SP) /* Skip intervening spaces */
+ p++;
+
+ while (state) { /* FSA to parse delta time */
+ if (state < 0 || !isdigit(*p))
+ return(-1);
+ p2 = p; /* Get next numeric field */
+ while (isdigit(*p2))
+ p2++;
+ c = *p2; /* And break character */
+ *p2 = NUL; /* Terminate the number */
+ switch (state) { /* Interpret according to state */
+ case NEED_DAYS: /* Initial */
+ if ((c == '-') || /* VMS format */
+ ((c == 'd' || c == 'D')
+ && !isalpha(*(p2+1)))) { /* Days */
+ ddays = atol(p);
+ if (!*(p2+1))
+ state = 0;
+ else /* if anything is left */
+ state = NEED_HRS; /* now we want hours. */
+ } else if (c == ':') { /* delimiter is colon */
+ dhours = atoi(p); /* so it's hours */
+ state = NEED_MINS; /* now we want minutes */
+ } else if (!c) { /* end of string */
+ dhours = atoi(p); /* it's still hours */
+ state = 0; /* and we're done */
+ } else if (isalpha(c) || c == SP) {
+ if (c == SP) { /* It's a keyword? */
+ p2++; /* Skip spaces */
+ while (*p2 == SP)
+ p2++;
+ } else { /* or replace first letter */
+ *p2 = c;
+ }
+ p3 = p2; /* p2 points to beginning of keyword */
+ while (isalpha(*p3)) /* Find end of keyword */
+ p3++;
+ c = *p3; /* NUL it out so we can look it up */
+ if (*p3) /* p3 points to keyword terminator */
+ *p3 = NUL;
+ if ((units = lookup(timeunits,p2,nunits,NULL)) < 0)
+ return(-1);
+ *p2 = NUL; /* Re-terminate the number */
+ *p3 = c;
+ while (*p3 == SP) /* Point at field after units */
+ p3++;
+ p2 = p3;
+ switch (units) {
+ case TU_DAYS:
+ ddays = atol(p);
+ break;
+ default:
+ return(-1);
+ }
+ if (*p2) {
+ state = NEED_HRS;
+ p2--;
+ } else
+ state = 0;
+ } else { /* Anything else */
+ state = -1; /* is an error */
+ }
+ break;
+ case NEED_HRS: /* Looking for hours */
+ if (c == ':') {
+ dhours = atoi(p);
+ state = NEED_MINS;
+ } else if (!c) {
+ dhours = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_MINS: /* Looking for minutes */
+ if (c == ':') {
+ dmins = atoi(p);
+ state = NEED_SECS;
+ } else if (!c) {
+ dmins = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_SECS: /* Looking for seconds */
+ if (c == '.') {
+ dsecs = atoi(p);
+ state = NEED_FRAC;
+ } else if (!c) {
+ dsecs = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_FRAC: /* Fraction of second */
+ if (!c && rdigits(p)) {
+ if (*p > '4')
+ dsecs++;
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ }
+ if (c) /* next field if any */
+ p = p2 + 1;
+ }
+ if (state < 0)
+ return(-1);
+
+ /* if days > 24854 and sizeof(long) == 32 we overflow */
+
+ zz = ddays * 86400L;
+ if (zz < 0L) /* This catches it */
+ return(-2);
+ zz += dhours * 3600L + dmins * 60L + dsecs;
+ zz *= dsign;
+ *result = zz;
+ return(0);
+}
+
+
+char *
+cmcvtdate(s,t) char * s; int t; {
+ int x, i, j, k, hh, mm, ss, ff, pmflag = 0, nodate = 0, len, dow;
+ int units, isgmt = 0, gmtsign = 0, d = 0, state = 0, nday;
+ int kn = 0, ft[8], isletter = 0, f2len = 0;
+
+ int zhh = 0; /* Timezone adjustments */
+ int zmm = 0;
+ int zdd = 0;
+
+ int dsign = 1; /* Delta-time adjustments */
+ int ddays = 0;
+ int dmonths = 0;
+ int dyears = 0;
+ int dhours = 0;
+ int dmins = 0;
+ int dsecs = 0;
+ int havedelta = 0;
+
+ char * fld[8], * p = "", * p2, * p3; /* Assorted buffers and pointers */
+ char * s2, * s3;
+ char * year = NULL, * month = NULL, * day = NULL;
+ char * hour = "00", * min = "00", * sec = "00";
+ char datesep = 0;
+ char tmpbuf[8];
+ char xbuf[DATEBUFLEN+1];
+ char ybuf[DATEBUFLEN+1];
+ char zbuf[DATEBUFLEN+1];
+ char yyyymmdd[YYYYMMDD];
+ char dbuf[26];
+ char daybuf[3];
+ char monbuf[3];
+ char yearbuf[5];
+ char timbuf[16], *tb, cc;
+ char * dp = NULL; /* Result pointer */
+
+ if (!s) s = "";
+ tmpbuf[0] = NUL;
+
+ while (*s == SP) s++; /* Gobble any leading blanks */
+ if (isalpha(*s)) /* Remember if 1st char is a letter */
+ isletter = 1;
+
+ len = strlen(s);
+ debug(F110,"cmcvtdate",s,len);
+ if (len == 0) { /* No arg - return current date-time */
+ dp = ckdate();
+ goto xcvtdate;
+ }
+ if (len > DATEBUFLEN) { /* Check length of arg */
+ makestr(&cmdatemsg,"Date-time string too long");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ hh = 0; /* Init time to 00:00:00.0 */
+ mm = 0;
+ ss = 0;
+ ff = 0;
+ ztime(&p);
+ if (!p)
+ p = "";
+ if (*p) { /* Init time to current time */
+ x = ckstrncpy(dbuf,p,26);
+ if (x > 17) {
+ hh = atoi(&dbuf[11]);
+ mm = atoi(&dbuf[14]);
+ ss = atoi(&dbuf[17]);
+ }
+ }
+ ckstrncpy(yyyymmdd,zzndate(),YYYYMMDD); /* Init date to current date */
+ ckstrncpy(yearbuf,yyyymmdd,5);
+ ckstrncpy(monbuf,&yyyymmdd[4],3);
+ ckstrncpy(daybuf,&yyyymmdd[6],3);
+ year = yearbuf;
+ month = monbuf;
+ day = daybuf;
+ nday = atoi(daybuf);
+ ckstrncpy(xbuf,s,DATEBUFLEN); /* Make a local copy we can poke */
+ s = xbuf; /* Point to it */
+ s[len] = NUL;
+ if (s[0] == ':') {
+ p = s;
+ goto dotime;
+ }
+ /* Special preset formats... */
+
+ if (len >= 14) { /* FTP MDTM all-numeric date */
+ char c;
+ c = s[14]; /* e.g. 19980615100045.014 */
+ s[14] = NUL;
+ x = rdigits(s);
+ s[14] = c;
+ if (x) {
+ ckstrncpy(yyyymmdd,s,8+1);
+ year = NULL;
+ p = &s[8];
+ goto dotime;
+ }
+ }
+ x = 0; /* Becomes > 0 for asctime format */
+ if (isalpha(s[0])) {
+ if (len == 24) { /* Asctime format? */
+ /* Sat Jul 14 15:57:32 2001 */
+ x = ckmatch(atp1,s,0,0);
+ debug(F111,"cmcvtdate asctime",s,x);
+ } else if (len == 28) { /* Or Asctime plus timezone? */
+ /* Sat Jul 14 15:15:39 EDT 2001 */
+ x = ckmatch(atp2,s,0,0);
+ debug(F111,"cmcvtdate asctime+timezone",s,x);
+ }
+ }
+ if (x > 0) { /* Asctime format */
+ int xx;
+ strncpy(yearbuf,s + len - 4,4);
+ yearbuf[4] = NUL;
+ for (i = 0; i < 3; i++)
+ tmpbuf[i] = s[i+4];
+ tmpbuf[3] = NUL;
+ if ((xx = lookup(cmonths,tmpbuf,12,NULL)) < 0) {
+ makestr(&cmdatemsg,"Invalid month");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ debug(F101,"cmcvtdate asctime month","",xx);
+ monbuf[0] = (xx / 10) + '0';
+ monbuf[1] = (xx % 10) + '0';
+ monbuf[2] = NUL;
+ daybuf[0] = (s[8] == ' ' ? '0' : s[8]);
+ daybuf[1] = s[9];
+ daybuf[2] = NUL;
+ xbuf[0] = SP;
+ for (i = 11; i < 19; i++)
+ xbuf[i-10] = s[i];
+ xbuf[9] = NUL;
+ ckmakmsg(zbuf,18,yearbuf,monbuf,daybuf,xbuf);
+ debug(F110,"cmcvtdate asctime ok",zbuf,0);
+ if (len == 24) {
+ dp = zbuf;
+ goto xcvtdate;
+ } else {
+ int n;
+ n = ckmakmsg(ybuf,DATEBUFLEN-4,zbuf," ",NULL,NULL);
+ ybuf[n++] = s[20];
+ ybuf[n++] = s[21];
+ ybuf[n++] = s[22];
+ ybuf[n++] = NUL;
+ ckstrncpy(xbuf,ybuf,DATEBUFLEN);
+ s = xbuf;
+ isletter = 0;
+ }
+ }
+
+/* Check for day of week */
+
+ p = s;
+ while (*p == SP) p++;
+ dow = -1;
+ if (*p) {
+ p2 = p;
+ cc = NUL;
+ while (1) {
+ if (*p2 == ',' || *p2 == SP || !*p2) {
+ cc = *p2; /* Save break char */
+ *p2 = NUL; /* NUL it out */
+ p3 = p2; /* Remember this spot */
+ if ((dow = lookup(daysofweek,p,7,NULL)) > -1) {
+ debug(F111,"cmcvtdate dow",p,dow);
+ s = p2;
+ if (cc == ',' || cc == SP) { /* Point to next field */
+ s++;
+ while (*s == SP) s++;
+ }
+ p = s;
+ debug(F111,"cmcvtdate dow new p",p,dow);
+ break;
+ } else if (isalpha(*p) && cc == ',') {
+ makestr(&cmdatemsg,"Unrecognized day of week");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else {
+ *p3 = cc;
+ break;
+ }
+ }
+ p2++;
+ }
+ }
+ len = strlen(s); /* Update length */
+ debug(F111,"cmcvtdate s",s,len);
+
+ debug(F111,"cmcvtdate dow",s,dow);
+ if (dow > -1) { /* Have a day-of-week number */
+ long zz; int n, j;
+ zz = mjd(zzndate()); /* Get today's MJD */
+ debug(F111,"cmcvtdate zz","",zz);
+ j = (((int)(zz % 7L)) + 3) % 7; /* Today's day-of-week number */
+ debug(F111,"cmcvtdate j","",j);
+ hh = 0; /* Init time to midnight */
+ mm = 0;
+ ss = 0;
+ if (j == dow) {
+ ckstrncpy(yyyymmdd,zzndate(),YYYYMMDD);
+ year = NULL;
+ } else {
+ n = dow - j; /* Days from now */
+ if (dow < j)
+ n += 7;
+ if (n < 0) n += 7; /* Add to MJD */
+ zz += n;
+ ckstrncpy(yyyymmdd,mjd2date(zz),YYYYMMDD); /* New date */
+ year = NULL;
+ }
+ debug(F111,"cmcvtdate A",yyyymmdd,len);
+ if (len == 0) { /* No more fields after this */
+ ckmakmsg(zbuf,18,yyyymmdd," 00:00:00",NULL,NULL);
+ dp = zbuf;
+ goto xcvtdate;
+ }
+ isletter = 0;
+ if (rdigits(p) && len < 8) /* Next field is time? */
+ goto dotime; /* If so go straight to time section */
+ if (isdigit(*p)) {
+ if (*(p+1) == ':')
+ goto dotime;
+ else if (isdigit(*(p+1)) && (*(p+2) == ':'))
+ goto dotime;
+ }
+ }
+ debug(F111,"cmcvtdate B s",s,dow);
+ debug(F111,"cmcvtdate B p",p,dow);
+
+ if (*s == '+' || *s == '-') { /* Delta time only - skip ahead. */
+ p = s;
+ goto delta;
+ }
+#ifdef COMMENT
+/*
+ What is the purpose of this? It breaks parsing of email dates like
+ "Wed, 13 Feb 2002 17:43:02 -0800 (PST)". Removing this code fixes the
+ problem and Kermit still passes the 'dates' script.
+ - fdc, Sat Nov 26 10:52:45 2005.
+*/
+ if (dow > -1) {
+ /* Day of week given followed by something that is not a time */
+ /* or a delta so it can't be valid */
+ makestr(&cmdatemsg,"Invalid tokens after day of week");
+ debug(F111,"cmcvtdate fail",cmdatemsg,-1);
+ return(NULL);
+ }
+#endif /* COMMENT */
+
+ /* Handle "today", "yesterday", "tomorrow", and +/- n units */
+
+ if (ckstrchr("TtYyNn",s[0])) {
+ int i, k, n, minus = 0;
+ char c;
+ long jd;
+ jd = mjd(ckdate());
+ debug(F111,"cmcvtdate mjd",s,jd);
+
+ /* Symbolic date: TODAY, TOMORROW, etc...? */
+
+ s2 = s; /* Find end of keyword */
+ i = 0;
+ while (isalpha(*s2)) { /* and get its length */
+ i++;
+ s2++;
+ }
+ c = *s2; /* Zap but save delimiter */
+ *s2 = NUL;
+ k = lookup(symdaytab,s,nsymdays,NULL); /* Look up keyword */
+ *s2 = c; /* Replace delimiter */
+ if (k < 0) /* Keyword not found */
+ goto normal;
+ s3 = &s[i];
+ while (*s3 == SP) /* Skip whitespace */
+ s3++;
+ if (*s3 == '_' || *s3 == ':')
+ s3++;
+
+ switch (k) { /* Have keyword */
+ case SYM_NOW: /* NOW */
+ ckstrncpy(ybuf,ckdate(),DATEBUFLEN);
+ ckstrncpy(yyyymmdd,ybuf,YYYYMMDD);
+ year = NULL;
+ if (*s3) { /* No overwriting current time. */
+ ckstrncat(ybuf," ",DATEBUFLEN);
+ ckstrncat(ybuf,s3,DATEBUFLEN);
+ }
+ break;
+ default: /* Yesterday, Today, and Tomorrow */
+ if (k == SYM_TOMO) { /* TOMORROW */
+ strncpy(ybuf,mjd2date(jd+1),8);
+ } else if (k == SYM_YEST) { /* YESTERDAY */
+ strncpy(ybuf,mjd2date(jd-1),8);
+ } else { /* TODAY */
+ strncpy(ybuf,ckdate(),8);
+ }
+ strncpy(ybuf+8," 00:00:00",DATEBUFLEN-8); /* Default time is 0 */
+ ckstrncpy(yyyymmdd,ybuf,YYYYMMDD);
+ year = NULL;
+ if (*s3) { /* If something follows keyword... */
+ if (isdigit(*s3)) { /* Time - overwrite default time */
+ strncpy(ybuf+8,s+i,DATEBUFLEN-8);
+ } else { /* Something else, keep default time */
+ ckstrncat(ybuf," ",DATEBUFLEN); /* and append */
+ ckstrncat(ybuf,s3,DATEBUFLEN); /* whatever we have */
+ }
+ }
+ }
+ s = ybuf; /* Point to rewritten date-time */
+ len = strlen(s); /* Update length */
+ isletter = 0; /* Cancel this */
+ }
+
+/* Regular free-format non-symbolic date */
+
+ normal:
+
+ debug(F111,"cmcvtdate NORMAL",s,len);
+ debug(F111,"cmcvtdate dow",s,dow);
+ if (yyyymmdd[0] && !year) {
+ ckstrncpy(yearbuf,yyyymmdd,5);
+ ckstrncpy(monbuf,&yyyymmdd[4],3);
+ ckstrncpy(daybuf,&yyyymmdd[6],3);
+ year = yearbuf;
+ month = monbuf;
+ day = daybuf;
+ nday = atoi(daybuf);
+ }
+ if (isdigit(s[0])) { /* Time without date? */
+ p = s;
+ if (s[1] == ':') {
+ debug(F111,"cmcvtdate NORMAL X1",s,len);
+ goto dotime;
+ } else if (len > 1 && isdigit(s[1]) && s[2] == ':') {
+ debug(F111,"cmcvtdate NORMAL X2",s,len);
+ goto dotime;
+ } else if (rdigits(s) && len < 8) {
+ debug(F111,"cmcvtdate NORMAL X3",s,len);
+ goto dotime;
+ }
+ }
+ if (len >= 8 && isdigit(*s)) { /* Check first for yyyymmdd* */
+ debug(F111,"cmcvtdate NORMAL A",s,len);
+ cc = s[8];
+ s[8] = NUL; /* Isolate first 8 characters */
+ if (rdigits(s)) {
+ /* Have valid time separator? */
+ p2 = cc ? ckstrchr(" Tt_-:",cc) : NULL;
+ if (!cc || p2) {
+ ckstrncpy(yyyymmdd,s,YYYYMMDD); /* Valid separator */
+ year = NULL;
+ s += 8; /* or time not given */
+ if (cc) s++; /* Keep date */
+ p = s; /* and go handle time */
+ goto dotime;
+ } else if (!p2) {
+ if (isdigit(cc))
+ makestr(&cmdatemsg,"Numeric date too long");
+ else
+ makestr(&cmdatemsg,"Invalid date-time separator");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+ s[8] = cc; /* Put this back! */
+ }
+ debug(F111,"cmcvtdate NORMAL non-yyyymmdd",s,len);
+
+ /* Free-format date -- figure it out */
+
+#ifdef COMMENT
+ if (*s && !isdigit(*s)) {
+ makestr(&cmdatemsg,"Unrecognized word in date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+#endif /* COMMENT */
+ for (i = 0; i < 8; i++) /* Field types */
+ ft[i] = -1;
+ fld[i = 0] = (p = s); /* First field */
+ while (*p) { /* Get next two fields */
+ if (isdatesep(*p)) { /* Have a date separator */
+ if (i == 0) {
+ datesep = *p;
+ } else if (i == 1 && *p != datesep) {
+ makestr(&cmdatemsg,"Inconsistent date separators");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ *p++ = NUL; /* Replace by NUL */
+ if (*p) { /* Now we're at the next field */
+ while (*p == SP) p++; /* Skip leading spaces */
+ if (!*p) break; /* Make sure we still have something */
+ if (i == 2) /* Last one? */
+ break;
+ fld[++i] = p; /* No, record pointer to this one */
+ } else {
+ break;
+ }
+ } else if ((*p == 'T' || *p == 't') && isdigit(*(p+1))) { /* Time */
+ *p++ = NUL;
+ break;
+ } else if (*p == ':') {
+ if (i == 0 && p == s) {
+ nodate = 1;
+ break;
+ } else if (i != 0) { /* After a date */
+ if (i == 2) { /* OK as date-time separator (VMS) */
+ *p++ = NUL;
+ break;
+ }
+ if (i < 2)
+ makestr(&cmdatemsg,"Too few fields in date");
+ else
+ makestr(&cmdatemsg,"Misplaced time separator");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ nodate = 1; /* Or without a date */
+ break;
+ }
+ p++;
+ }
+ if (p > s && i == 0) /* Make sure we have a date */
+ nodate = 1; /* No date. */
+
+ if (nodate && dow > -1) { /* Have implied date from DOW? */
+ goto dotime; /* Use, use that, go do time. */
+
+ } else if (nodate) { /* No date and no implied date */
+ char *tmp = NULL; /* Substitute today's date */
+ ztime(&tmp);
+ if (!tmp)
+ tmp = "";
+ if (!*tmp) {
+ makestr(&cmdatemsg,"Problem supplying current date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ ckstrncpy(dbuf,tmp,26); /* Reformat */
+ if (dbuf[8] == SP) dbuf[8] = '0';
+ fld[0] = dbuf+8; /* dd */
+ dbuf[10] = NUL;
+ fld[1] = dbuf+4; /* mmm */
+ dbuf[7] = NUL;
+ fld[2] = dbuf+20; /* yyyy */
+ dbuf[24] = NUL;
+ hh = atoi(&dbuf[11]);
+ mm = atoi(&dbuf[14]);
+ ss = atoi(&dbuf[17]);
+ p = s; /* Back up source pointer to reparse */
+ } else if (i < 2) {
+ makestr(&cmdatemsg,"Too few fields in date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ /* Have three date fields - see what they are */
+
+ for (k = 0, j = 0; j < 3; j++) { /* Get number of non-numeric fields */
+ ft[j] = rdigits(fld[j]);
+ debug(F111,"cmcvtdate fld",fld[j],j);
+ if (ft[j] == 0)
+ k++;
+ }
+ kn = k; /* How many numeric fields */
+ month = NULL; /* Strike out default values */
+ year = NULL;
+ day = NULL;
+
+ if (k == 2 && ft[2] > 0) { /* Jul 20, 2001 */
+ int xx;
+ xx = strlen(fld[1]);
+ p3 = fld[1];
+ if (xx > 0) if (p3[xx-1] == ',') {
+ p3[xx-1] = NUL;
+ if (rdigits(p3)) {
+ k = 1;
+ ft[1] = 1;
+ } else p3[xx-1] = ',';
+ }
+ }
+ if (k > 1) { /* We can have only one non-numeric */
+ if (nodate)
+ makestr(&cmdatemsg,"Unrecognized word in date");
+ else if (!ft[2] && isdigit(*(fld[2])))
+ makestr(&cmdatemsg,"Invalid date-time separator");
+ else
+ makestr(&cmdatemsg,"Too many non-numeric fields in date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (!ft[0]) {
+ k = 0;
+ } else if (!ft[1]) {
+ k = 1;
+ } else if (!ft[2]) {
+ makestr(&cmdatemsg,"Non-digit in third date field");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else
+ k = -1;
+
+ if (k > -1) {
+ if ((x = lookup(cmonths,fld[k],12,NULL)) < 0) {
+ makestr(&cmdatemsg,"Unknown month");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ sprintf(tmpbuf,"%02d",x);
+ month = tmpbuf;
+ }
+ f2len = strlen(fld[2]); /* Length of 3rd field */
+
+ if (k == 0) { /* monthname dd, yyyy */
+ day = fld[1];
+ year = fld[2];
+ } else if (((int)strlen(fld[0]) == 4)) { /* yyyy-xx-dd */
+ year = fld[0];
+ day = fld[2];
+ if (!month)
+ month = fld[1]; /* yyyy-mm-dd */
+ } else if (f2len == 4) { /* xx-xx-yyyy */
+ year = fld[2];
+ if (month) { /* dd-name-yyyy */
+ day = fld[0];
+ } else { /* xx-xx-yyyy */
+ int f0, f1;
+ f0 = atoi(fld[0]);
+ f1 = atoi(fld[1]);
+ if (((f0 > 12) && (f1 <= 12)) || (f1 <= 12 && f0 == f1)) {
+ day = fld[0]; /* mm-dd-yyyy */
+ month = fld[1];
+ } else if ((f0 <= 12) && (f1 > 12)) {
+ if (!rdigits(fld[1])) {
+ makestr(&cmdatemsg,"Day not numeric");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else {
+ day = fld[1]; /* dd-mm-yyyy */
+ }
+ month = fld[0];
+ } else {
+ if (!f0 || !f1)
+ makestr(&cmdatemsg,"Day or month out of range");
+ else
+ makestr(&cmdatemsg,"Day and month are ambiguous");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+ } else if ((f2len < 4) && /* dd mmm yy (RFC822) */
+ !rdigits(fld[1]) && /* middle field is monthname */
+ rdigits(fld[2])) {
+ int tmpyear;
+ day = fld[0];
+ if (!fld[2][1]) {
+ makestr(&cmdatemsg,"Too few digits in year");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ tmpyear = atoi(fld[2]);
+ if (tmpyear < 50) /* RFC 2822 windowing */
+ tmpyear += 2000;
+ else /* This includes 3-digit years. */
+ tmpyear += 1900;
+ year = ckitoa(tmpyear);
+
+ } else if ((f2len < 4) && (k < 0) && ((int)strlen(fld[0]) < 4)) {
+ makestr(&cmdatemsg,"Ambiguous numeric date");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else if ((f2len > 4) && ft[2]) {
+ makestr(&cmdatemsg,"Too many digits in year");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ } else {
+ makestr(&cmdatemsg,"Unexpected date format");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ x = atoi(month);
+ sprintf(tmpbuf,"%02d",x); /* 2-digit numeric month */
+
+/*
+ state = 1 = hours
+ state = 2 = minutes
+ state = 3 = seconds
+ state = 4 = fractions of seconds
+*/
+
+ dotime:
+ if (isletter && (s == p)) {
+ makestr(&cmdatemsg,"Unknown date-time word");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (!year && yyyymmdd[0]) {
+ debug(F110,"cmcvtdate dotime yyyymmdd",yyyymmdd,0);
+ for (i = 0; i < 4; i++)
+ yearbuf[i] = yyyymmdd[i];
+ yearbuf[4] = NUL;
+ monbuf[0] = yyyymmdd[4];
+ monbuf[1] = yyyymmdd[5];
+ monbuf[2] = NUL;
+ daybuf[0] = yyyymmdd[6];
+ daybuf[1] = yyyymmdd[7];
+ daybuf[2] = NUL;
+ day = daybuf;
+ nday = atoi(daybuf);
+ month = monbuf;
+ year = yearbuf;
+ }
+ if (!year) {
+ makestr(&cmdatemsg,"Internal error - date not defaulted");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ /* Get here with day, month, and year set */
+ debug(F110,"cmcvtdate dotime day",day,0);
+ debug(F110,"cmcvtdate dotime month",month,0);
+ debug(F110,"cmcvtdate dotime year",year,0);
+ debug(F110,"cmcvtdate dotime s",s,0);
+ debug(F110,"cmcvtdate dotime p",p,0);
+ x = atoi(month);
+ if (x > 12 || x < 1) {
+ makestr(&cmdatemsg,"Month out of range");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ nday = atoi(day);
+ i = mdays[x];
+ if (x == 2) if (isleap(atoi(year))) i++;
+ if (nday > i || nday < 1) {
+ makestr(&cmdatemsg,"Day out of range");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (!*p && t == 0) {
+ sprintf(zbuf,"%04d%02d%02d",atoi(year),atoi(month),nday);
+ dp = zbuf;
+ goto xcvtdate;
+ }
+ if (*p == '+' || *p == '-') { /* GMT offset without a time */
+ hh = 0; /* so default time to 00:00:00 */
+ mm = 0;
+ ss = 0;
+ goto cmtimezone; /* and go do timezone */
+ }
+ if (*p && !isdigit(*p) && *p != ':') {
+ makestr(&cmdatemsg,"Invalid time");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ sprintf(yyyymmdd,"%s%s%02d",year,month,nday); /* for tz calculations... */
+
+ state = 1; /* Initialize time-parsing FSA */
+ hh = 0; /* hours */
+ mm = 0; /* minutes */
+ ss = 0; /* seconds */
+ ff = -1; /* fraction */
+ d = 0; /* Digit counter */
+ p2 = p; /* Preliminary digit count... */
+ while (isdigit(*p2)) {
+ d++;
+ p2++;
+ }
+ if (d > 6) {
+ makestr(&cmdatemsg,"Too many time digits");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ d = (d & 1 && *p2 != ':') ? 1 : 0; /* Odd implies leading '0' */
+
+ while (*p) { /* Get the time, if any */
+ if (isdigit(*p)) { /* digit */
+ if (d++ > 1) {
+ state++;
+ d = 1;
+ }
+ switch (state) {
+ case 1: /* Hours */
+ hh = hh * 10 + (*p - '0');
+ break;
+ case 2: /* Minutes */
+ mm = mm * 10 + (*p - '0');
+ break;
+ case 3: /* Seconds */
+ ss = ss * 10 + (*p - '0');
+ break;
+ case 4: /* Fraction of second */
+ if (ff < 0)
+ ff = (*p > '4') ? 1 : 0;
+ break;
+ }
+ } else if (*p == ':') { /* Colon */
+ state++;
+ d = 0;
+ if (state > 3) {
+ makestr(&cmdatemsg,"Too many time fields");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ } else if (*p == '.') {
+ if (state == 3) {
+ state = 4;
+ d = 0;
+ } else {
+ makestr(&cmdatemsg,"Improper fraction");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ } else if (*p == SP) { /* Space */
+ while (*p && (*p == SP)) /* position to first nonspace */
+ p++;
+ break;
+ } else if (isalpha(*p)) { /* AM/PM/Z or timezone */
+ break;
+ } else if (*p == '+' || *p == '-') { /* GMT offset */
+ break;
+ } else {
+ makestr(&cmdatemsg,"Invalid time characters");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ p++;
+ }
+ if (!*p) /* If nothing left */
+ goto xcmdate; /* go finish up */
+
+ /* At this point we have HH, MM, SS, and FF */
+ /* Now handle the rest: AM, PM, and/or timezone info */
+
+ if (!ckstrcmp(p,"am",2,0)) { /* AM/PM... */
+ pmflag = 0;
+ p += 2;
+ } else if (!ckstrcmp(p,"a.m.",4,0)) {
+ pmflag = 0;
+ p += 4;
+ } else if (!ckstrcmp(p,"pm",2,0)) {
+ pmflag = 1;
+ p += 2;
+ } else if (!ckstrcmp(p,"p.m.",4,0)) {
+ pmflag = 1;
+ p += 4;
+ }
+ if (pmflag && hh < 12) /* If PM was given */
+ hh += 12; /* add 12 to the hour */
+
+ /* Now handle timezone */
+
+ cmtimezone:
+ debug(F110,"cmcvtdate timezone",p,0);
+
+ zhh = 0; /* GMT offset HH */
+ zmm = 0; /* GMT offset MM */
+ gmtsign = 0; /* Sign of GMT offset */
+ isgmt = 0; /* 1 if time is GMT */
+
+ while (*p && *p == SP) /* Gobble spaces */
+ p++;
+ if (!*p) /* If nothing left */
+ goto xcmdate; /* we're done */
+
+ if (isalpha(*p)) { /* Something left */
+ int zone = 0; /* Alphabetic must be timezone */
+ p2 = p; /* Isolate timezone */
+ p++;
+ while (isalpha(*p))
+ p++;
+ p3 = p;
+ cc = *p;
+ *p = NUL;
+ p = p2; /* Have timezone, look it up */
+ zone = lookup(usatz,p,nusatz,NULL);
+ debug(F111,"cmcvtdate timezone alpha",p,zone);
+
+ if (zone < 0) { /* Not found */
+ makestr(&cmdatemsg,"Unknown timezone");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ isgmt++; /* All dates are GMT from here down */
+ if (zone != 0) { /* But not this one so make it GMT */
+ hh += zone; /* RFC 822 timezone: EST etc */
+ debug(F101,"cmcvtdate hh + zone","",hh);
+ if (hh > 23) { /* Offset crosses date boundary */
+ int i;
+ long jd;
+ jd = mjd(yyyymmdd); /* Get MJD */
+ jd += hh / 24; /* Add new day(s) */
+ hh = hh % 24; /* and convert back to yyyymmdd */
+ ckstrncpy(yyyymmdd,mjd2date(jd),YYYYMMDD);
+ debug(F111,"cmcvtdate zone-adjusted date",yyyymmdd,hh);
+ for (i = 0; i < 4; i++)
+ yearbuf[i] = yyyymmdd[i];
+ yearbuf[4] = NUL;
+ monbuf[0] = yyyymmdd[4];
+ monbuf[1] = yyyymmdd[5];
+ monbuf[2] = NUL;
+ daybuf[0] = yyyymmdd[6];
+ daybuf[1] = yyyymmdd[7];
+ daybuf[2] = NUL;
+ day = daybuf;
+ nday = atoi(daybuf);
+ month = monbuf;
+ year = yearbuf;
+ }
+ }
+ p = p3; /* Put back whatever we poked above */
+ *p = cc;
+
+ } else if (*p == '+' || *p == '-') { /* GMT/UTC offset */
+ p3 = p;
+ debug(F110,"cmcvtdate timezone GMT offset",p,0);
+ gmtsign = (*p == '+') ? -1 : 1;
+ isgmt++;
+ p++;
+ while (*p == SP) p++;
+ d = 0;
+ p2 = p;
+ while (isdigit(*p)) { /* Count digits */
+ d++;
+ p++;
+ }
+ if (d != 4) { /* Strict RFC [2]822 */
+ isgmt = 0; /* If not exactly 4 digits */
+ p = p3; /* it's not a GMT offset. */
+ goto delta; /* So treat it as a delta time. */
+ }
+ d = (d & 1 && *p != ':') ? 1 : 0; /* Odd implies leading '0' */
+ p = p2;
+ debug(F111,"cmcvtdate GMT offset sign",p,gmtsign);
+ debug(F101,"cmcvtdate GMT offset d","",d);
+ state = 1;
+ while (*p) {
+ if (isdigit(*p)) { /* digit */
+ if (d++ > 1) {
+ state++;
+ d = 1;
+ }
+ switch (state) {
+ case 1:
+ zhh = zhh * 10 + (*p - '0');
+ break;
+ case 2:
+ zmm = zmm * 10 + (*p - '0');
+ break;
+ default: /* Ignore seconds or fractions */
+ break;
+ }
+ } else if (*p == ':') { /* Colon */
+ state++;
+ d = 0;
+ } else if (*p == SP || *p == '(') {
+ break;
+ } else {
+ p = p3; /* Maybe it's not a GMT offset. */
+ goto delta; /* So treat it as a delta time. */
+ }
+ p++;
+ }
+ }
+ debug(F110,"cmcvtdate source string after timezone",p,0);
+
+ if (*p) { /* Anything left? */
+ p2 = p;
+ while (*p2 == SP) /* Skip past spaces */
+ p2++;
+ if (*p2 == '(') { /* RFC-822 comment? */
+ int pc = 1; /* paren counter */
+ p2++;
+ while (*p2) {
+ if (*p2 == ')') {
+ if (--pc == 0) {
+ p2++;
+ break;
+ }
+ } else if (*p2 == ')') {
+ pc++;
+ }
+ p2++;
+ }
+ while (*p2 == SP) /* Skip past spaces */
+ p2++;
+ if (!*p2) /* Anything left? */
+ *p = NUL; /* No, erase comment */
+ }
+ if (!*p2) /* Anything left? */
+ goto xcmdate; /* No, done. */
+ p = p2;
+
+ delta:
+ debug(F110,"cmcvtdate delta yyyymmdd",yyyymmdd,0);
+ debug(F110,"cmcvtdate delta year",year,0);
+ debug(F110,"cmcvtdate delta p",p,0);
+
+ if (*p == '+' || *p == '-') { /* Delta time */
+ int state = NEED_DAYS; /* Start off looking for days */
+ char c = 0;
+ dsign = 1; /* Get sign */
+ if (*p++ == '-')
+ dsign = -1;
+ while (*p == SP) /* Skip intervening spaces */
+ p++;
+ while (state) { /* FSA to parse delta time */
+ if (state < 0 || !isdigit(*p)) {
+ makestr(&cmdatemsg,"Invalid delta time");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ p2 = p; /* Get next numeric field */
+ while (isdigit(*p2))
+ p2++;
+ c = *p2; /* And break character */
+ *p2 = NUL; /* Terminate the number */
+
+ switch (state) { /* Interpret according to state */
+ case NEED_DAYS: /* Initial */
+ if ((c == '-') || /* VMS format */
+ ((c == 'd' || c == 'D')
+ && !isalpha(*(p2+1)))) { /* Days */
+ ddays = atoi(p);
+ if (!*(p2+1))
+ state = 0;
+ else /* if anything is left */
+ state = NEED_HRS; /* now we want hours. */
+ } else if ((c == 'W' || c == 'w') && !isalpha(*(p2+1))) {
+ ddays = atoi(p) * 7; /* weeks... */
+ if (!*(p2+1))
+ state = 0;
+ else
+ state = NEED_HRS;
+ } else if ((c == 'M' || c == 'm') && !isalpha(*(p2+1))) {
+ dmonths = atoi(p); /* months... */
+ if (!*(p2+1))
+ state = 0;
+ else
+ state = NEED_HRS;
+ } else if ((c == 'Y' || c == 'y') && !isalpha(*(p2+1))) {
+ dyears = atoi(p); /* years... */
+ if (!*(p2+1))
+ state = 0;
+ else
+ state = NEED_HRS;
+ } else if (c == ':') { /* delimiter is colon */
+ dhours = atoi(p); /* so it's hours */
+ state = NEED_MINS; /* now we want minutes */
+ } else if (!c) { /* end of string */
+ dhours = atoi(p); /* it's still hours */
+ state = 0; /* and we're done */
+ } else if (isalpha(c) || c == SP) {
+ if (c == SP) { /* It's a keyword? */
+ p2++; /* Skip spaces */
+ while (*p2 == SP)
+ p2++;
+ } else { /* or replace first letter */
+ *p2 = c;
+ }
+ p3 = p2; /* p2 points to beginning of keyword */
+ while (isalpha(*p3)) /* Find end of keyword */
+ p3++;
+ c = *p3; /* NUL it out so we can look it up */
+ if (*p3) /* p3 points to keyword terminator */
+ *p3 = NUL;
+ units = lookup(timeunits,p2,nunits,NULL);
+ if (units < 0) {
+ makestr(&cmdatemsg,"Invalid units in delta time");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ *p2 = NUL; /* Re-terminate the number */
+ *p3 = c;
+ while (*p3 == SP) /* Point at field after units */
+ p3++;
+ p2 = p3;
+ switch (units) {
+ case TU_DAYS:
+ ddays = atoi(p);
+ break;
+ case TU_WEEKS:
+ ddays = atoi(p) * 7;
+ break;
+ case TU_MONTHS:
+ dmonths = atoi(p);
+ break;
+ case TU_YEARS:
+ dyears = atoi(p);
+ break;
+ }
+ if (*p2) {
+ state = NEED_HRS;
+ p2--;
+ } else
+ state = 0;
+
+ } else { /* Anything else */
+ state = -1; /* is an error */
+ }
+ break;
+ case NEED_HRS: /* Looking for hours */
+ debug(F000,"cmcvtdate NEED_HRS",p,c);
+ if (c == ':') {
+ dhours = atoi(p);
+ state = NEED_MINS;
+ } else if (!c) {
+ dhours = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_MINS: /* Looking for minutes */
+ if (c == ':') {
+ dmins = atoi(p);
+ state = NEED_SECS;
+ } else if (!c) {
+ dmins = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_SECS: /* Looking for seconds */
+ if (c == '.') {
+ dsecs = atoi(p);
+ state = NEED_FRAC;
+ } else if (!c) {
+ dsecs = atoi(p);
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ case NEED_FRAC: /* Fraction of second */
+ if (!c && rdigits(p)) {
+ if (*p > '4')
+ dsecs++;
+ state = 0;
+ } else {
+ state = -1;
+ }
+ break;
+ }
+ if (c) /* next field if any */
+ p = p2 + 1;
+ }
+ havedelta = 1;
+
+ } else {
+ makestr(&cmdatemsg,"Extraneous material at end");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+
+ xcmdate:
+
+ if ((t != 2 && hh > 24) || hh < 0) { /* Hour range check */
+ makestr(&cmdatemsg,"Invalid hours");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (mm > 59) { /* Minute range check */
+ makestr(&cmdatemsg,"Invalid minutes");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ if (ff > 0) { /* Fraction of second? */
+ if (ss < 59) {
+ ss++;
+ ff = 0;
+ } else if (mm < 59) {
+ ss = 0;
+ mm++;
+ ff = 0;
+ } else if (hh < 24) {
+ ss = 0;
+ mm = 0;
+ hh++;
+ ff = 0;
+ }
+ /* Must add a day -- leave ff at 1... */
+ /* (DO SOMETHING ABOUT THIS LATER) */
+ }
+ if (ss > 60) { /* Seconds range check */
+ makestr(&cmdatemsg,"Invalid seconds"); /* 60 is ok because of */
+ debug(F111,"cmcvtdate",cmdatemsg,-1); /* Leap Second. */
+ return(NULL);
+ }
+ if ((mm < 0 || ss < 0) ||
+ (t != 2 && (ss > 0 || mm > 0) && hh > 23)) {
+ makestr(&cmdatemsg,"Invalid minutes or seconds");
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ debug(F110,"cmcvtdate year",year,0);
+ debug(F110,"cmcvtdate month",month,0);
+ debug(F101,"cmcvtdate nday","",nday);
+ debug(F101,"cmcvtdate hh","",hh);
+ debug(F101,"cmcvtdate mm","",mm);
+ debug(F101,"cmcvtdate ss","",ss);
+ debug(F101,"cmcvtdate gmtsign","",gmtsign);
+ debug(F101,"cmcvtdate zhh","",zhh);
+ debug(F101,"cmcvtdate zmm","",zmm);
+ debug(F101,"cmcvtdate isgmt","",isgmt);
+
+#ifdef ZLOCALTIME
+/* Handle timezone -- first convert to GMT */
+
+ zdd = 0; /* Days changed */
+ if (isgmt && (zmm || zhh)) { /* If GMT offset given */
+ long sec1, sec2, zz;
+ sec1 = ss + 60 * mm + 3600 * hh;
+ sec2 = gmtsign * (60 * zmm + 3600 * zhh);
+ sec1 += sec2;
+ if (sec1 < 0) {
+ sec1 = 0 - sec1;
+ zdd = 0L - (sec1 / 86400L);
+ sec1 = sec1 % 86400L;
+ } else if (sec1 > 86400L) {
+ zdd = sec1 / 86400L;
+ sec1 = sec1 % 86400L;
+ }
+ ss = sec1 % 60;
+ zz = sec1 / 60;
+ mm = zz % 60;
+ hh = zz / 60;
+ debug(F101,"cmcvtdate NEW hh","",hh);
+ debug(F101,"cmcvtdate NEW mm","",mm);
+ debug(F101,"cmcvtdate NEW dd","",zdd);
+
+/* At this point hh:mm:ss is in GMT and zdd is the calendar adjustment */
+
+ }
+#endif /* ZLOCALTIME */
+
+ if (yyyymmdd[0] && !year) {
+ ckstrncpy(yearbuf,yyyymmdd,5);
+ ckstrncpy(monbuf,&yyyymmdd[4],3);
+ ckstrncpy(daybuf,&yyyymmdd[6],3);
+ year = yearbuf;
+ month = monbuf;
+ day = daybuf;
+ nday = atoi(daybuf);
+ }
+ sprintf(zbuf,"%04d%02d%02d %02d:%02d:%02d", /* SAFE */
+ atoi(year),atoi(month),nday,hh,mm,ss
+ );
+ dp = zbuf;
+
+#ifdef ZLOCALTIME
+ /* Now convert from GMT to local time */
+
+ if (isgmt) { /* If GMT convert to local time */
+ debug(F110,"cmcvtdate GMT 1",dp,0);
+ if (zdd) { /* Apply any calendar adjustment */
+ long zz;
+ zz = mjd(dp) + zdd;
+ sprintf(zbuf,"%s %02d:%02d:%02d",mjd2date(zz),hh,mm,ss);
+ }
+ debug(F110,"cmcvtdate GMT 2",dp,0);
+ if ((p = zlocaltime(dp))) {
+ debug(F110,"cmcvtdate asctime zlocaltime",p,0);
+ if (p) ckstrncpy(zbuf,p,18);
+ }
+ debug(F110,"cmcvtdate GMT 3",dp,0);
+ for (i = 0; i < 4; i++)
+ yearbuf[i] = dp[i];
+ yearbuf[4] = NUL;
+ monbuf[0] = dp[4];
+ monbuf[1] = dp[5];
+ monbuf[2] = NUL;
+ daybuf[0] = dp[6];
+ daybuf[1] = dp[7];
+ daybuf[2] = NUL;
+ day = daybuf;
+ nday = atoi(daybuf);
+ month = monbuf;
+ year = yearbuf;
+ hh = atoi(&dp[9]);
+ mm = atoi(&dp[12]);
+ ss = atoi(&dp[15]);
+ }
+#endif /* ZLOCALTIME */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmcvtdate hour","",hh);
+ debug(F101,"cmcvtdate minute","",mm);
+ debug(F101,"cmcvtdate second","",ss);
+ }
+#endif /* DEBLOG */
+
+ makestr(&cmdatemsg,NULL);
+ if (havedelta) {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"cmcvtdate base ",dp,0);
+ debug(F101,"cmcvtdate delta sign","",dsign);
+ debug(F101,"cmcvtdate delta yrs ","",dyears);
+ debug(F101,"cmcvtdate delta mos ","",dmonths);
+ debug(F101,"cmcvtdate delta days","",ddays);
+ debug(F101,"cmcvtdate delta hrs ","",dhours);
+ debug(F101,"cmcvtdate delta mins","",dmins);
+ debug(F101,"cmcvtdate delta secs","",dsecs);
+ }
+#endif /* DEBLOG */
+ if (!(dp = cmdelta(atoi(year),
+ atoi(month),
+ nday, hh, mm, ss,
+ dsign, dyears, dmonths, ddays, dhours, dmins, dsecs))) {
+ debug(F111,"cmcvtdate",cmdatemsg,-1);
+ return(NULL);
+ }
+ }
+
+ xcvtdate: /* Exit point for success */
+ {
+ int len, k, n;
+ char * p;
+ debug(F110,"cmcvtdate xcvtdate dp",dp,0);
+ if (!dp) dp = ""; /* Shouldn't happen */
+ if (!*dp) return(NULL); /* ... */
+ len = strlen(dp);
+ debug(F111,"cmcvtdate result",dp,len);
+ k = cmdatebp - (char *)cmdatebuf; /* Space used */
+ n = CMDATEBUF - k - 1; /* Space left */
+ if (n < len) { /* Not enough? */
+ cmdatebp = cmdatebuf; /* Wrap around */
+ n = CMDATEBUF;
+ }
+ ckstrncpy(cmdatebp,dp,n);
+ p = cmdatebp;
+ cmdatebp += len + 1;
+ return(p);
+ }
+}
+
+int
+cmvdate(d) char * d; { /* Verify date-time */
+ int i;
+ if (!d) return(0);
+ if ((int)strlen(d) != 17) return(0);
+ for (i = 0; i < 8; i++) { if (!isdigit(d[i])) return(0); }
+ if (!isdigit(d[9]) || !isdigit(d[10]) ||
+ !isdigit(d[12]) || !isdigit(d[13]) ||
+ !isdigit(d[15]) || !isdigit(d[16]))
+ return(0);
+ if (!ckstrchr(" Tt_-:",d[8])) return(0);
+ if (d[11] != ':' && d[14] != ':') return(0);
+ return(1);
+}
+
+/* c m d i f f d a t e -- Get difference between two date-times */
+
+char *
+cmdiffdate(d1,d2) char * d1, * d2; {
+ char d1buf[9], d2buf[9];
+ char x1buf[18], x2buf[18];
+ char * p;
+
+ int hh1 = 0, mm1 = 0, ss1 = 0;
+ int hh2 = 0, mm2 = 0, ss2 = 0;
+ int hh, mm, ss;
+ int sign;
+ long jd1, jd2, jd, f1, f2, fx;
+ static char result[24], *rp;
+
+ debug(F110,"cmdiffdate d1 A",d1,0);
+ debug(F110,"cmdiffdate d2 A",d2,0);
+
+ if (!(p = cmcvtdate(d1,1))) /* Convert dates to standard format */
+ return(NULL);
+ ckstrncpy(x1buf,p,18);
+ d1 = x1buf;
+
+ if (!(p = cmcvtdate(d2,1)))
+ return(NULL);
+ ckstrncpy(x2buf,p,18);
+ d2 = x2buf;
+
+ debug(F110,"cmdiffdate d1 B",d1,0);
+ debug(F110,"cmdiffdate d2 B",d2,0);
+ if (!cmvdate(d1) || !cmvdate(d2))
+ return(NULL);
+
+ hh1 = atoi(&d1[9]); /* Get hours, minutes, and seconds */
+ mm1 = atoi(&d1[12]); /* for first date */
+ ss1 = atoi(&d1[15]);
+ ckstrncpy(d1buf,d1,9);
+
+ hh2 = atoi(&d2[9]); /* ditto for second date */
+ mm2 = atoi(&d2[12]);
+ ss2 = atoi(&d2[15]);
+ ckstrncpy(d2buf,d2,9);
+
+ jd1 = mjd(d1buf); /* Get the two Julian dates */
+ jd2 = mjd(d2buf);
+ f1 = ss1 + 60 * mm1 + 3600 * hh1; /* Convert first time to seconds */
+
+ f2 = ss2 + 60 * mm2 + 3600 * hh2; /* Ditto for second time */
+ debug(F101,"cmdiffdate jd1","",jd1);
+ debug(F101,"cmdiffdate f1","",f1);
+ debug(F101,"cmdiffdate jd2","",jd2);
+ debug(F101,"cmdiffdate f2","",f2);
+
+ if (jd2 > jd1 || (jd1 == jd2 && f2 > f1)) {
+ sign = -1;
+ if (f1 > f2) {jd2--; f2 += 86400L;}
+ jd = jd2 - jd1;
+ fx = f2 - f1;
+ } else {
+ sign = 1;
+ if (f2 > f1) {jd1--; f1 += 86400L;}
+ jd = jd1 - jd2;
+ fx = f1 - f2;
+ }
+ debug(F111,"cmdiffdate sign jd",sign<0?"-":"+",jd);
+ debug(F101,"cmdiffdate fx","",fx);
+
+ hh = (int) (fx / 3600L); /* Convert seconds to hh:mm:ss */
+
+ mm = (int) (fx % 3600L) / 60L;
+ ss = (int) (fx % 3600L) % 60L;
+
+ rp = result; /* Format the result */
+ *rp++ = (sign < 0) ? '-' : '+';
+ if (jd != 0 && hh+mm+ss == 0) {
+ sprintf(rp,"%ldd",jd);
+ } else if (jd == 0) {
+ if (ss == 0)
+ sprintf(rp,"%d:%02d",hh,mm);
+ else
+ sprintf(rp,"%d:%02d:%02d",hh,mm,ss);
+ } else {
+ if (ss == 0)
+ sprintf(rp,"%ldd%d:%02d",jd,hh,mm);
+ else
+ sprintf(rp,"%ldd%d:%02d:%02d",jd,hh,mm,ss);
+ }
+ debug(F110,"cmdiffdate result",result,0);
+ return((char *)result);
+}
+
+#ifndef NOSPL
+/* s h u f f l e d a t e -- Rearrange date string */
+
+/*
+ Call with:
+ A date string in standard format: yyyymmdd hh:mm:ss (time optional).
+ Options:
+ 1: Reformat date to yyyy-mmm-dd (mmm = English month abbreviation).
+ 2: Reformat date to dd-mmm-yyyy (mmm = English month abbreviation).
+ 3: Reformat as numeric yyyymmddhhmmss.
+ 4: Reformat in asctime() format Sat Nov 26 11:10:34 2005
+ Returns:
+ Pointer to result if args valid, otherwise original arg pointer.
+*/
+char *
+shuffledate(p,opt) char * p; int opt; {
+ extern char * wkdays[];
+ int len;
+ char ibuf[32];
+ static char obuf[48];
+ char c;
+ int yy, dd, mm;
+
+ if (!p) p = "";
+ if (!*p) p = ckdate();
+ if (opt < 1 || opt > 4)
+ return(p);
+ len = strlen(p);
+ if (len < 8 || len > 31) return(p);
+ if (opt == 4) { /* Asctime format (26 Nov 2005) */
+ char c, * s;
+ long z; int k;
+ ckstrncpy(ibuf,p,31);
+ k = len;
+ while (k >= 0 && ibuf[k] == CR || ibuf[k] == LF)
+ ibuf[k--] = NUL;
+ while (k >= 0 && ibuf[k] == SP || ibuf[k] == HT)
+ ibuf[k--] = NUL;
+ if (k < 9) ckstrncpy(&ibuf[8]," 00:00:00",9);
+ p = ibuf;
+ z = mjd(p); /* Convert to modified Julian date */
+ z = z % 7L;
+ if (z < 0) {
+ z = 0 - z;
+ k = 6 - ((int)z + 3) % 7;
+ } else {
+ k = ((int)z + 3) % 7; /* Day of week */
+ }
+ s = wkdays[k];
+ obuf[0] = s[0]; /* Day of week */
+ obuf[1] = s[1];
+ obuf[2] = s[2];
+ obuf[3] = SP; /* Space */
+ c = p[6];
+ p[6] = NUL;
+ mm = atoi(&ibuf[4]); /* Month */
+ s = moname[mm-1]; /* Name of month */
+ p[6] = c;
+
+ obuf[4] = s[0]; /* Month */
+ obuf[5] = s[1];
+ obuf[6] = s[2];
+ obuf[7] = SP; /* Space */
+ if (p[6] == '0') /* Date of month */
+ obuf[8] = SP;
+ else
+ obuf[8] = p[6];
+ obuf[9] = p[7];
+ ckstrncpy(&obuf[10],&p[8],10); /* Time */
+ obuf[19] = SP; /* Space */
+ obuf[20] = p[0]; /* Year */
+ obuf[21] = p[1];
+ obuf[22] = p[2];
+ obuf[23] = p[3];
+ obuf[24] = NUL;
+ return((char *)obuf);
+ }
+ if (opt == 3) {
+ ckstrncpy(obuf,p,48);
+ /* yyyymmdd hh:mm:ss */
+ /* 01234567890123456 */
+ /* yyyymmddhhmmss */
+ obuf[8] = obuf[9];
+ obuf[9] = obuf[10];
+ obuf[10] = obuf[12];
+ obuf[11] = obuf[13];
+ obuf[12] = obuf[15];
+ obuf[13] = obuf[16];
+ obuf[14] = NUL;
+ return((char *)obuf);
+ }
+ ckstrncpy(ibuf,p,32);
+ c = ibuf[4]; /* Warning: not Y10K compliant */
+ ibuf[4] = NUL;
+ if (!rdigits(ibuf))
+ return(p);
+ yy = atoi(ibuf);
+ if (yy < 1 || yy > 9999)
+ return(p);
+ ibuf[4] = c;
+ c = ibuf[6];
+ ibuf[6] = NUL;
+ if (!rdigits(&ibuf[4]))
+ return(p);
+ mm = atoi(&ibuf[4]);
+ if (mm < 1 || mm > 12)
+ return(p);
+ ibuf[6] = c;
+ c = ibuf[8];
+ ibuf[8] = NUL;
+ if (!rdigits(&ibuf[6]))
+ return(p);
+ dd = atoi(&ibuf[6]);
+ ibuf[8] = c;
+ if (dd < 1 || mm > 31)
+ return(p);
+ /* IGNORE WARNINGS ABOUT moname[] REFS OUT OF RANGE - it's prechecked. */
+ switch (opt) {
+ case 1:
+ sprintf(obuf,"%04d-%s-%02d%s",yy,moname[mm-1],dd,&ibuf[8]);
+ break;
+ case 2:
+ sprintf(obuf,"%02d-%s-%04d%s",dd,moname[mm-1],yy,&ibuf[8]);
+ }
+ return((char *)obuf);
+}
+#endif /* NOSPL */
+
+/* C K C V T D A T E -- Like cmcvtdate(), but returns string. */
+/* For use by date-related functions */
+/* See calling conventions for cmcvtdate() above. */
+
+char *
+ckcvtdate(p,t) char * p; int t; {
+ char * s;
+ if (!(s = cmcvtdate(p,t)))
+ return("<BAD_DATE_OR_TIME>"); /* \fblah() error message */
+ else
+ return(s);
+}
+
+
+/* C M D A T E -- Parse a date and/or time */
+
+/*
+ Accepts date in various formats. If the date is recognized,
+ this routine returns 0 or greater with the result string pointer
+ pointing to a buffer containing the date as "yyyymmdd hh:mm:ss".
+*/
+int
+cmdate(xhlp,xdef,xp,quiet,f) char *xhlp, *xdef, **xp; int quiet; xx_strp f; {
+ int x, rc;
+ char *o, *s, *zq, *dp;
+
+ cmfldflgs = 0;
+ if (!xhlp) xhlp = "";
+ if (!xdef) xdef = "";
+ if (!*xhlp) xhlp = "Date and/or time";
+ *xp = "";
+
+ rc = cmfld(xhlp,xdef,&s,(xx_strp)0);
+ debug(F101,"cmdate cmfld rc","",rc);
+ if (rc < 0)
+ return(rc);
+ debug(F110,"cmdate 1",s,0);
+ o = s; /* Remember what they typed. */
+ s = brstrip(s);
+ debug(F110,"cmdate 2",s,0);
+
+ x = 0;
+ if (f) { /* If a conversion function is given */
+ char * pp;
+ zq = atxbuf; /* do the conversion. */
+ pp = atxbuf;
+ atxn = CMDBL;
+ if ((x = (*f)(s,&zq,&atxn)) < 0) return(-2);
+ if (!*pp)
+ pp = xdef;
+ if (setatm(pp,0) < 0) {
+ if (!quiet) printf("?Evaluated date too long\n");
+ return(-9);
+ }
+ s = atxbuf;
+ }
+ dp = cmcvtdate(s,1);
+ if (!dp) {
+ if (!quiet) printf("?%s\n",cmdatemsg);
+ return(-9);
+ }
+ *xp = dp;
+ return(0);
+}
+
+#ifdef CK_RECALL /* Command-recall functions */
+
+/* C M R I N I -- Initialize or change size of command recall buffer */
+
+int
+cmrini(n) int n; {
+ int i;
+ if (recall && in_recall) { /* Free old storage, if any */
+ for (i = 0; i < cm_recall; i++) {
+ if (recall[i]) {
+ free(recall[i]);
+ recall[i] = NULL;
+ }
+ }
+ free(recall);
+ recall = NULL;
+ }
+ cm_recall = n; /* Set new size */
+ rlast = current = -1; /* Initialize pointers */
+ if (n > 0) {
+ recall = (char **)malloc((cm_recall + 1) * sizeof(char *));
+ if (!recall)
+ return(1);
+ for (i = 0; i < cm_recall; i++) {
+ recall[i] = NULL;
+ }
+ in_recall = 1; /* Recall buffers init'd */
+ }
+ return(0);
+}
+
+/* C M A D D N E X T -- Force addition of next command */
+
+VOID
+cmaddnext() {
+ if (on_recall && in_recall) { /* Even if it doesn't come */
+ force_add = 1; /* from the keyboard */
+ newcmd = 1;
+ no_recall = 0;
+ }
+}
+
+/* C M G E T C M D -- Find most recent matching command */
+
+char *
+cmgetcmd(s) char * s; {
+ int i;
+ for (i = current; i >= 0; i--) { /* Search backward thru history list */
+ if (!recall[i]) continue; /* This one's null, skip it */
+ if (ckmatch(s,recall[i],0,1)) /* Match? */
+ return(recall[i]); /* Yes, return pointer */
+ }
+ return(NULL); /* No match, return NULL pointer */
+}
+#endif /* CK_RECALL */
+
+/* A D D C M D -- Add a command to the recall buffer */
+
+VOID
+addcmd(s) char * s; {
+ int len = 0, nq = 0;
+ char * p;
+#ifdef CKLEARN
+ extern int learning;
+#endif /* CKLEARN */
+
+ if (xcmdsrc) /* Only for interactive commands */
+ return;
+
+ if (!newcmd) /* The command has been here already */
+ return; /* so ignore it. */
+ newcmd = 0; /* It's new but do this only once. */
+
+ if (!s) s = cmdbuf;
+ if (s[0])
+ len = strlen(s);
+
+ if (len < 1) /* Don't save empty commands */
+ return;
+
+ p = s;
+ while (*p) { if (*p++ == '?') nq++; } /* Count question marks */
+
+#ifdef CKLEARN
+ if (learning) /* If a learned script is active */
+ learncmd(s); /* record this command. */
+#endif /* CKLEARN */
+
+ debug(F010,"CMD(P)",s,0); /* Maybe record it in the debug log */
+
+#ifdef CKSYSLOG
+ if (ckxlogging) { /* Maybe record it in syslog */
+ if (ckxsyslog >= SYSLG_CX || ckxsyslog >= SYSLG_CM)
+ cksyslog(SYSLG_CX, 1, "command", s, NULL);
+ }
+#endif /* CKSYSLOG */
+
+#ifdef CK_RECALL
+ last_recall = 0;
+
+ if (on_recall && /* Command recall is on? */
+ cm_recall > 0 && /* Recall buffer size is > 0? */
+ !no_recall) { /* Not not saving this command? */
+
+ if (!force_add && rlast > -1) /* If previous command was identical */
+ if (!strcmp(s,recall[rlast])) /* don't add another copy */
+ return;
+
+ force_add = 0; /* Reset now in case it was set */
+
+ if (rlast >= cm_recall - 1) { /* Recall buffer full? */
+ int i;
+ if (recall[0]) { /* Discard oldest command */
+ free(recall[0]);
+ recall[0] = NULL;
+ }
+ for (i = 0; i < rlast; i++) { /* The rest */
+ recall[i] = recall[i+1]; /* move back */
+ }
+ rlast--; /* Now we have one less */
+ }
+ rlast++; /* Index of last command in buffer */
+ current = rlast; /* Also now the current command */
+ if (current >= cm_recall) { /* Shouldn't happen */
+ printf("?Command history error\n"); /* but if it does */
+ on_recall = 0; /* turn off command saving */
+#ifdef COMMENT
+ } else if (nq > 0) { /* Have at least one question mark */
+ recall[current] = malloc(len+nq+1);
+ if (recall[current]) {
+ p = recall[current];
+ while (*s) {
+ if (*s == '?')
+ *p++ = '\\';
+ *p++ = *s++;
+ }
+ *p = NUL;
+ }
+#endif /* COMMENT */
+ } else { /* Normal case, just copy */
+ recall[current] = malloc(len+1);
+ if (recall[current])
+ ckstrncpy(recall[current],s,len+1);
+ }
+ }
+#endif /* CK_RECALL */
+}
+
+
+#ifdef CK_RECALL
+
+/* C M H I S T O R Y */
+
+VOID
+cmhistory() {
+ int i, lc = 1;
+ for (i = 0; i <= current; i++) {
+ printf(" %s\n", recall[i]);
+ if (++lc > (cmd_rows - 2)) { /* Screen full? */
+ if (!askmore()) /* Do more-prompting... */
+ break;
+ else
+ lc = 0;
+ }
+ }
+}
+
+int
+savhistory(s,disp) char *s; int disp; {
+ FILE * fp;
+ int i;
+
+ fp = fopen(s, disp ? "a" : "w");
+ if (!fp) {
+ perror(s);
+ return(0);
+ }
+ for (i = 0; i <= current; i++)
+ fprintf(fp,"%s\n", recall[i]);
+ fclose(fp);
+ return(1);
+}
+#endif /* CK_RECALL */
+
+#ifdef COMMENT
+/* apparently not used */
+int
+cmgetlc(s) char * s; { /* Get leading char */
+ char c;
+ while ((c = *s++) <= SP) {
+ if (!c)
+ break;
+ }
+ return(c);
+}
+#endif /* COMMENT */
+
+
+/* C M C F M -- Parse command confirmation (end of line) */
+
+/*
+ Returns
+ -2: User typed anything but whitespace or newline
+ -1: Reparse needed
+ 0: Confirmation was received
+*/
+int
+cmcfm() {
+ int x, xc;
+ debug(F101,"cmcfm: cmflgs","",cmflgs);
+ debug(F110,"cmcfm: atmbuf",atmbuf,0);
+ inword = xc = cc = 0;
+
+ setatm("",0); /* (Probably unnecessary) */
+
+ while (cmflgs != 1) {
+ x = gtword(0);
+ xc += cc;
+
+ switch (x) {
+ case -9:
+ printf("Command or field too long\n");
+ case -4: /* EOF */
+ case -2:
+ case -1:
+ return(x);
+ case 1: /* End of line */
+ if (xc > 0) {
+ if (xcmfdb) {
+ return(-6);
+ } else {
+ printf("?Not confirmed - %s\n",atmbuf);
+ return(-9);
+ }
+ } else
+ break; /* Finish up below */
+ case 2: /* ESC */
+ if (xc == 0) {
+ bleep(BP_WARN);
+ continue; /* or fall thru. */
+ }
+ case 0: /* Space */
+ if (xc == 0) /* If no chars typed, continue, */
+ continue; /* else fall thru. */
+ /* else fall thru... */
+
+ case 3: /* Question mark */
+ if (xc > 0) {
+ if (xcmfdb) {
+ return(-6);
+ } else {
+ printf("?Not confirmed - %s\n",atmbuf);
+ return(-9);
+ }
+ }
+ printf(
+ "\n Press the Return or Enter key to confirm the command\n");
+ printf("%s%s",cmprom,cmdbuf);
+ fflush(stdout);
+ continue;
+ }
+ }
+ debok = 1;
+ return(0);
+}
+
+
+/* The following material supports chained parsing functions. */
+/* See ckucmd.h for FDB and OFDB definitions. */
+
+struct OFDB cmresult = { /* Universal cmfdb result holder */
+ NULL, /* Address of succeeding FDB struct */
+ 0, /* Function code */
+ NULL, /* String result */
+ 0, /* Integer result */
+ (CK_OFF_T)0 /* Wide result */
+};
+
+VOID
+cmfdbi(p,fc,s1,s2,s3,n1,n2,f,k,nxt) /* Initialize an FDB */
+ struct FDB * p;
+ int fc;
+ char * s1, * s2, * s3;
+ int n1, n2;
+ xx_strp f;
+ struct keytab * k;
+ struct FDB * nxt; {
+
+ p->fcode = fc;
+ p->hlpmsg = s1;
+ p->dflt = s2;
+ p->sdata = s3;
+ p->ndata1 = n1;
+ p->ndata2 = n2;
+ p->spf = f;
+ p->kwdtbl = k;
+ p->nxtfdb = nxt;
+}
+
+/* C M F D B -- Parse a field with several possible functions */
+
+int
+cmfdb(fdbin) struct FDB * fdbin; {
+#ifndef NOSPL
+ extern int x_ifnum; /* IF NUMERIC - disables warnings */
+#endif /* NOSPL */
+ struct FDB * in = fdbin;
+ struct OFDB * out = &cmresult;
+ int x = 0, n, r;
+ CK_OFF_T w = (CK_OFF_T)0;
+ char *s, *xp, *m = NULL;
+ int errbits = 0;
+
+ xp = bp;
+
+ out->fcode = -1; /* Initialize output struct */
+ out->fdbaddr = NULL;
+ out->sresult = NULL;
+ out->nresult = 0;
+/*
+ Currently we make one trip through the FDBs. So if the user types Esc or
+ Tab at the beginning of a field, only the first FDB is examined for a
+ default. If the user types ?, help is given only for one FDB. We should
+ search through the FDBs for all matching possibilities -- and in particular
+ display the pertinent context-sensitive help for each function, rather than
+ the only the first one that works, and then rewind the FDB pointer so we
+ are not locked out of the earlier ones.
+*/
+ cmfldflgs = 0;
+ while (1) { /* Loop through the chain of FDBs */
+ nomsg = 1;
+ xcmfdb = 1;
+ s = NULL;
+ n = 0;
+ debug(F101,"cmfdb in->fcode","",in->fcode);
+ switch (in->fcode) { /* Current parsing function code */
+ case _CMNUM:
+ r = in->ndata1;
+ if (r != 10 && r != 8) r = 10;
+#ifndef NOSPL
+ x_ifnum = 1; /* Disables warning messages */
+#endif /* NOSPL */
+ x = cmnum(in->hlpmsg,in->dflt,r,&n,in->spf);
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ debug(F101,"cmfdb cmnum","",x);
+ if (x < 0) errbits |= 1;
+ break;
+ case _CMNUW: /* Wide cmnum - 24 Dec 2005 */
+ r = in->ndata1;
+ if (r != 10 && r != 8) r = 10;
+#ifndef NOSPL
+ x_ifnum = 1; /* Disables warning messages */
+#endif /* NOSPL */
+ x = cmnumw(in->hlpmsg,in->dflt,r,&w,in->spf);
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ debug(F101,"cmfdb cmnumw","",w);
+ if (x < 0) errbits |= 1;
+ break;
+ case _CMOFI:
+ x = cmofi(in->hlpmsg,in->dflt,&s,in->spf);
+ debug(F101,"cmfdb cmofi","",x);
+ if (x < 0) errbits |= 2;
+ break;
+ case _CMIFI:
+ x = cmifi2(in->hlpmsg,
+ in->dflt,
+ &s,
+ &n,
+ in->ndata1,
+ in->sdata,
+ in->spf,
+ in->ndata2
+ );
+ debug(F101,"cmfdb cmifi2 x","",x);
+ debug(F101,"cmfdb cmifi2 n","",n);
+ if (x < 0) errbits |= 4;
+ break;
+ case _CMFLD:
+ cmfldflgs = in->ndata1;
+ x = cmfld(in->hlpmsg,in->dflt,&s,in->spf);
+ debug(F101,"cmfdb cmfld","",x);
+ if (x < 0) errbits |= 8;
+ break;
+ case _CMTXT:
+ x = cmtxt(in->hlpmsg,in->dflt,&s,in->spf);
+ debug(F101,"cmfdb cmtxt","",x);
+ if (x < 0) errbits |= 16;
+ break;
+ case _CMKEY:
+ x = cmkey2(in->kwdtbl,
+ in->ndata1,
+ in->hlpmsg,in->dflt,in->sdata,in->spf,in->ndata2);
+ debug(F101,"cmfdb cmkey","",x);
+ if (x < 0) errbits |= ((in->ndata2 & 4) ? 32 : 64);
+ break;
+ case _CMCFM:
+ x = cmcfm();
+ debug(F101,"cmfdb cmcfm","",x);
+ if (x < 0) errbits |= 128;
+ break;
+ default:
+ debug(F101,"cmfdb - unexpected function code","",in->fcode);
+ printf("?cmfdb - unexpected function code: %d\n",in->fcode);
+ }
+ debug(F101,"cmfdb x","",x);
+ debug(F101,"cmfdb cmflgs","",cmflgs);
+ debug(F101,"cmfdb crflag","",crflag);
+ debug(F101,"cmfdb qmflag","",qmflag);
+ debug(F101,"cmfdb esflag","",esflag);
+
+ if (x > -1) { /* Success */
+ out->fcode = in->fcode; /* Fill in output struct */
+ out->fdbaddr = in;
+ out->sresult = s;
+ out->nresult = (in->fcode == _CMKEY) ? x : n;
+ out->wresult = w;
+ out->kflags = (in->fcode == _CMKEY) ? cmkwflgs : 0;
+ debug(F111,"cmfdb out->nresult",out->sresult,out->nresult);
+ debug(F111,"cmfdb out->wresult",out->sresult,out->wresult);
+ nomsg = 0;
+ xcmfdb = 0;
+ /* debug(F111,"cmfdb cmdbuf & crflag",cmdbuf,crflag); */
+ if (crflag) {
+ cmflgs = 1;
+ }
+ return(x); /* and return */
+ }
+ in = in->nxtfdb; /* Failed, get next parsing function */
+ nomsg = 0;
+ xcmfdb = 0;
+ if (!in) { /* No more */
+ debug(F101,"cmfdb failure x","",x);
+ debug(F101,"cmfdb failure errbits","",errbits);
+ if (x == -6)
+ x = -9;
+ if (x == -9) {
+#ifdef CKROOT
+ if (ckrooterr)
+ m = "Off Limits";
+ else
+#endif /* CKROOT */
+ /* Make informative messages for a few common cases */
+ switch (errbits) {
+ case 4+32: m = "Does not match filename or switch"; break;
+ case 4+64: m = "Does not match filename or keyword"; break;
+ case 1+32: m = "Not a number or valid keyword"; break;
+ case 1+64: m = "Not a number or valid switch"; break;
+ default: m = "Not valid in this position";
+ }
+ printf("?%s: \"%s\"\n",m, atmbuf);
+ }
+ return(x);
+ }
+ if (x != -2 && x != -6 && x != -9 && x != -3) /* Editing or somesuch */
+ return(x); /* Go back and reparse */
+ pp = np = bp = xp; /* Back up pointers */
+ cmflgs = -1; /* Force a reparse */
+
+#ifndef NOSPL
+ if (!askflag) { /* If not executing ASK-class cmd... */
+#endif /* NOSPL */
+ if (crflag) { /* If CR was typed, put it back */
+ pushc = LF; /* But as a linefeed */
+ } else if (qmflag) { /* Ditto for Question mark */
+ pushc = '?';
+ } else if (esflag) { /* and Escape or Tab */
+ pushc = ESC;
+ }
+#ifndef NOSPL
+ }
+#endif /* NOSPL */
+ }
+}
+
+/*
+ C M I O F I -- Parse an input file OR the name of a nonexistent file.
+
+ Replaces the commented-out version above. This one actually works and
+ has the expected straightforward interface.
+*/
+int
+cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+ int x;
+ struct FDB f1, f2;
+ cmfdbi(&f1,_CMIFI,xhlp,xdef,"",0,0,f,NULL,&f2);
+ cmfdbi(&f2,_CMOFI,"","","",0,0,f,NULL,NULL);
+ x = cmfdb(&f1);
+ if (x < 0) {
+ if (x == -3) {
+ x = -9;
+ printf("?Filename required\n");
+ }
+ }
+ *wild = cmresult.nresult;
+ *xp = cmresult.sresult;
+ return(x);
+}
+
+/* G T W O R D -- Gets a "word" from the command input stream */
+
+/*
+Usage: retcode = gtword(brk);
+ brk = 0 for normal word breaks (space, CR, Esc, ?)
+ brk = 1 to add ':' and '=' (for parsing switches). These characters
+ act as break characters only if the first character of the field
+ is slash ('/'), i.e. switch introducer.
+ brk = 4 to not strip comments (used only for "help #" and "help ;").
+
+Returns:
+-10 Timelimit set and timed out
+ -9 if input was too long
+ -4 if end of file (e.g. pipe broken)
+ -3 if null field
+ -2 if command buffer overflows
+ -1 if user did some deleting
+ 0 if word terminates with SP or tab
+ 1 if ... CR
+ 2 if ... ESC
+ 3 if ... ? (question mark)
+ 4 if ... : or = and called with brk != 0
+
+With:
+ pp pointing to beginning of word in buffer
+ bp pointing to after current position
+ atmbuf containing a copy of the word
+ cc containing the number of characters in the word copied to atmbuf
+*/
+
+int
+ungword() { /* Unget a word */
+ debug(F101,"ungword cmflgs","",cmflgs);
+ if (ungw) return(0);
+ cmfsav = cmflgs;
+ ungw = 1;
+ cmflgs = 0;
+ return(0);
+}
+
+/* Un-un-get word. Undo ungword() if it has been done. */
+
+VOID
+unungw() {
+ debug(F010,"unungw atmbuf",atmbuf,0);
+ if (ungw) {
+ ungw = 0;
+ cmflgs = cmfsav;
+ atmbuf[0] = NUL;
+ }
+}
+
+static int
+gtword(brk) int brk; {
+ int c; /* Current char */
+ int quote = 0; /* Flag for quote character */
+ int echof = 0; /* Flag for whether to echo */
+ int comment = 0; /* Flag for in comment */
+ char *cp = NULL; /* Comment pointer */
+ int eintr = 0; /* Flag for syscall interrupted */
+ int bracelvl = 0; /* nested brace counter [jrs] */
+ int iscontd = 0; /* Flag for continuation */
+ int realtty = 0; /* Stdin is really a tty */
+ char firstnb = NUL;
+ char lastchar = NUL;
+ char prevchar = NUL;
+ char lbrace, rbrace;
+ int dq = 0; /* Doublequote flag */
+ int dqn = 0; /* and count */
+ int isesc = 0;
+
+#ifdef RTU
+ extern int rtu_bug;
+#endif /* RTU */
+
+#ifdef IKSD
+ extern int inserver;
+#endif /* IKSD */
+ extern int kstartactive;
+
+#ifdef datageneral
+ extern int termtype; /* DG terminal type flag */
+ extern int con_reads_mt; /* Console read asynch is active */
+ if (con_reads_mt) connoi_mt(); /* Task would interfere w/cons read */
+#endif /* datageneral */
+
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"gtword brk","",brk);
+ debug(F101,"gtword cmfldflgs","",cmfldflgs);
+ debug(F101,"gtword swarg","",swarg);
+ debug(F101,"gtword dpx","",dpx);
+ debug(F101,"gtword echof","",echof);
+#ifndef NOSPL
+ debug(F101,"gtword askflag","",askflag);
+ debug(F101,"gtword timelimit","",timelimit);
+#ifndef NOLOCAL
+#ifndef NOXFER
+#ifdef CK_AUTODL
+ debug(F101,"gtword cmdadl","",cmdadl);
+#endif /* CK_AUTODL */
+#endif /* NOXFER */
+#endif /* NOLOCAL */
+#endif /* NOSPL */
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+
+ realtty = is_a_tty(0); /* Stdin is really a tty? */
+
+ if (cmfldflgs & 1) {
+ lbrace = '(';
+ rbrace = ')';
+ } else {
+ lbrace = '{';
+ rbrace = '}';
+ }
+ crflag = 0;
+ qmflag = 0;
+ esflag = 0;
+
+ if (swarg) { /* No leading space for switch args */
+ inword = 1;
+ swarg = 0;
+ }
+ if (ungw) { /* Have a word saved? */
+#ifdef M_UNGW
+ /* Experimental code to allow ungetting multiple words. */
+ /* See comments in ckmkey2() above. */
+ int x;
+ if (np > pp) pp = np;
+ while (*pp == SP) pp++;
+ if (!*pp) {
+ ungw = 0;
+ cmflgs = cmfsav;
+ } else {
+ if ((x = setatm(pp,2)) < 0) {
+ printf("?Saved word too long\n");
+ return(-9);
+ }
+ if (pp[x] >= SP) {
+ char *p2;
+ p2 = pp;
+ p2 += x;
+ while (*p2 == SP) p2++;
+ if (*p2) {
+ np = p2;
+ ungword();
+ }
+ } else {
+ ungw = 0;
+ cmflgs = cmfsav;
+ debug(F010,"gtword ungw return atmbuf",atmbuf,0);
+ }
+ }
+ return(cmflgs);
+#else
+ /*
+ You would think the following should be:
+ while (*pp == SP) pp++;
+ but you would be wrong -- making this change breaks GOTO.
+ */
+ while (*pp++ == SP) ;
+ if (setatm(pp,2) < 0) {
+ printf("?Saved word too long\n");
+ return(-9);
+ }
+ ungw = 0;
+ cmflgs = cmfsav;
+ debug(F010,"gtword ungw return atmbuf",atmbuf,0);
+ return(cmflgs);
+#endif /* M_UNGW */
+ }
+ pp = np; /* Start of current field */
+
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"gtword cmdbuf",cmdbuf,0);
+ debug(F110,"gtword bp",bp,0);
+ debug(F110,"gtword pp",pp,0);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ {
+ /* If we are reparsing we have to recount any braces or doublequotes */
+ char * p = pp;
+ char c;
+ if (*p == '"')
+ dq++;
+ while ((c = *p++))
+ if (c == lbrace)
+ bracelvl++;
+ else if (c == rbrace)
+ bracelvl--;
+ else if (dq && c == '"')
+ dqn++;
+ }
+ while (bp < cmdbuf+CMDBL) { /* Big get-a-character loop */
+ echof = 0; /* Assume we don't echo because */
+ chsrc = 0; /* character came from reparse buf. */
+#ifdef BS_DIRSEP
+CMDIRPARSE:
+#endif /* BS_DIRSEP */
+
+ c = *bp;
+ if (!c) { /* If no char waiting in reparse buf */
+ if ((dpx
+#ifndef NOSPL
+ || echostars
+#endif /* NOSPL */
+ ) && (!pushc
+#ifndef NOSPL
+ || askflag
+#endif /* NOSPL */
+ )) /* Get from tty, set echo flag */
+ echof = 1;
+ c = cmdgetc(timelimit); /* Read a command character. */
+#ifdef DEBUG
+ debug(F101,"gtword c","",c);
+#endif /* DEBUG */
+
+ if (timelimit && c < -1) { /* Timed out */
+ return(-10);
+ }
+
+#ifndef NOXFER
+/*
+ The following allows packet recognition in the command parser.
+ Presently it works only for Kermit packets, and if our current protocol
+ happens to be anything besides Kermit, we simply force it to Kermit.
+ We don't use the APC mechanism here for mechanical reasons, and also
+ because this way, it works even with minimally configured interactive
+ versions. Add Zmodem later...
+*/
+#ifdef CK_AUTODL
+ if ((!local && cmdadl) /* Autodownload enabled? */
+#ifdef IKS_OPTION
+ || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+#endif /* IKS_OPTION */
+ ) {
+ int k;
+ k = kstart((CHAR)c); /* Kermit S or I packet? */
+ if (k) {
+ int ksign = 0;
+ if (k < 0) { /* Minus-Protocol? */
+#ifdef NOSERVER
+ goto noserver; /* Need server mode for this */
+#else
+ ksign = 1; /* Remember */
+ k = 0 - k; /* Convert to actual protocol */
+ justone = 1; /* Flag for protocol module */
+#endif /* NOSERVER */
+ } else
+ justone = 0;
+ k--; /* Adjust kstart's return value */
+ if (k == PROTO_K) {
+ extern int protocol, g_proto;
+ extern CHAR sstate;
+ g_proto = protocol;
+ protocol = PROTO_K; /* Crude... */
+ sstate = ksign ? 'x' : 'v';
+ cmdbuf[0] = NUL;
+ return(-3);
+ }
+ }
+ }
+#ifdef NOSERVER
+ noserver:
+#endif /* NOSERVER */
+#endif /* CK_AUTODL */
+#endif /* NOXFER */
+
+ chsrc = 1; /* Remember character source is tty. */
+ brkchar = c;
+
+#ifdef IKSD
+ if (inserver && c < 0) { /* End of session? */
+ debug(F111,"gtword c < 0","exiting",c);
+ return(-4); /* Cleanup and terminate */
+ }
+#endif /* IKSD */
+
+#ifdef OS2
+ if (c < 0) { /* Error */
+ if (c == -3) { /* Empty word? */
+ if (blocklvl > 0) /* In a block */
+ continue; /* so keep looking for block end */
+ else
+ return(-3); /* Otherwise say we got nothing */
+ } else { /* Not empty word */
+ return(-4); /* So some kind of i/o error */
+ }
+ }
+#else
+#ifdef MAC
+ if (c == -3) /* Empty word... */
+ if (blocklvl > 0)
+ continue;
+ else
+ return(-3);
+#endif /* MAC */
+#endif /* OS2 */
+ if (c == EOF) { /* This can happen if stdin not tty. */
+#ifdef EINTR
+/*
+ Some operating and/or C runtime systems return EINTR for no good reason,
+ when the end of the standard input "file" is encountered. In cases like
+ this, we get into an infinite loop; hence the eintr counter, which is reset
+ to 0 upon each call to this routine.
+*/
+ debug(F101,"gtword EOF","",errno);
+ if (errno == EINTR && ++eintr < 4) /* When bg'd process is */
+ continue; /* fg'd again. */
+#endif /* EINTR */
+ return(-4);
+ }
+ c &= cmdmsk; /* Strip any parity bit */
+ } /* if desired. */
+
+/* Now we have the next character */
+
+ isesc = (c == ESC); /* A real ESC? */
+
+ if (!firstnb && c > SP) { /* First nonblank */
+ firstnb = c;
+ if (c == '"') /* Starts with doublequote */
+ dq = 1;
+ }
+ if (c == '"') /* Count doublequotes */
+ dqn++;
+
+ if (quote && (c == CR || c == LF)) { /* Enter key following quote */
+ *bp++ = CMDQ; /* Double it */
+ *bp = NUL;
+ quote = 0;
+ }
+ if (quote == 0) { /* If this is not a quoted character */
+ switch (c) {
+ case CMDQ: /* Got the quote character itself */
+ if (!comment && quoting)
+ quote = 1; /* Flag it if not in a comment */
+ break;
+ case FF: /* Formfeed. */
+ c = NL; /* Replace with newline */
+ cmdclrscn(); /* Clear the screen */
+ break;
+ case HT: /* Horizontal Tab */
+ if (comment) /* If in comment, */
+ c = SP; /* substitute space */
+ else /* otherwise */
+ c = ESC; /* substitute ESC (for completion) */
+ break;
+ case ';': /* Trailing comment */
+ case '#':
+ if (! (brk & 4) ) { /* If not keeping comments */
+ if (inword == 0 && quoting) { /* If not in a word */
+ comment = 1; /* start a comment. */
+ cp = bp; /* remember where it starts. */
+ }
+ }
+ break;
+ }
+ if (!kstartactive && /* Not in possible Kermit packet */
+ !comment && c == SP) { /* Space not in comment */
+ *bp++ = (char) c; /* deposit in buffer if not already */
+ /* debug(F101,"gtword echof 2","",echof); */
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ fflush(stdout);
+ fflush(stderr);
+ }
+#else
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ if (timelimit)
+ fflush(stdout);
+ }
+#endif /* BEBOX */
+ if (inword == 0) { /* If leading, gobble it. */
+ pp++;
+ continue;
+ } else { /* If terminating, return. */
+ if ((!dq && ((*pp != lbrace) || (bracelvl == 0))) ||
+ (dq && dqn > 1 && *(bp-2) == '"')) {
+ np = bp;
+ cmbptr = np;
+ if (setatm(pp,0) < 0) {
+ printf("?Field too long error 1\n");
+ debug(F111,"gtword too long #1",pp,strlen(pp));
+ return(-9);
+ }
+ brkchar = c;
+ inword = cmflgs = 0;
+ return(0);
+ }
+ continue;
+ }
+ }
+ if (c == lbrace) {
+ bracelvl++;
+ /* debug(F101,"gtword bracelvl++","",bracelvl); */
+ }
+ if (c == rbrace && bracelvl > 0) {
+ bracelvl--;
+ /* debug(F101,"gtword bracelvl--","",bracelvl); */
+ if (linebegin)
+ blocklvl--;
+ }
+ if ((c == '=' || c == ':') &&
+ /* ^^^ */
+ !kstartactive && !comment && brk /* && (firstnb == '/') */
+ ) {
+ *bp++ = (char) c; /* Switch argument separator */
+ /* debug(F111,"gtword switch argsep",cmdbuf,brk); */
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ fflush(stdout);
+ fflush(stderr);
+ }
+#else
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ if (timelimit)
+ fflush(stdout);
+ }
+#endif /* BEBOX */
+ if ((*pp != lbrace) || (bracelvl == 0)) {
+ np = bp;
+ cmbptr = np;
+ if (setatm(pp,2) < 0) { /* ^^^ */
+ printf("?Field too long error 1\n");
+ debug(F111,"gtword too long #1",pp,strlen(pp));
+ return(-9);
+ }
+ inword = cmflgs = 0;
+ brkchar = c;
+ return(4);
+ }
+ }
+ if (c == LF || c == CR) { /* CR or LF. */
+ if (echof) {
+ cmdnewl((char)c); /* echo it. */
+#ifdef BEBOX
+ fflush(stdout);
+ fflush(stderr);
+#endif /* BEBOX */
+ }
+ {
+ /* Trim trailing comment and whitespace */
+ char *qq;
+ if (comment) { /* Erase comment */
+ while (bp >= cp) /* Back to comment pointer */
+ *bp-- = NUL;
+ bp++;
+ pp = bp; /* Adjust other pointers */
+ inword = 0; /* and flags */
+ comment = 0;
+ cp = NULL;
+ }
+ qq = inword ? pp : (char *)cmdbuf;
+ /* Erase trailing whitespace */
+ while (bp > qq && (*(bp-1) == SP || *(bp-1) == HT)) {
+ bp--;
+ /* debug(F000,"erasing","",*bp); */
+ *bp = NUL;
+ }
+ lastchar = (bp > qq) ? *(bp-1) : NUL;
+ prevchar = (bp > qq+1) ? *(bp-2) : NUL;
+ }
+ if (linebegin && blocklvl > 0) /* Blank line in {...} block */
+ continue;
+
+ linebegin = 1; /* At beginning of next line */
+ iscontd = prevchar != CMDQ &&
+ (lastchar == '-' || lastchar == lbrace);
+ debug(F101,"gtword iscontd","",iscontd);
+
+ if (iscontd) { /* If line is continued... */
+ if (chsrc) { /* If reading from tty, */
+ if (*(bp-1) == lbrace) { /* Check for "begin block" */
+ *bp++ = SP; /* Insert a space for neatness */
+ blocklvl++; /* Count block nesting level */
+ } else { /* Or hyphen */
+ bp--; /* Overwrite the hyphen */
+ }
+ *bp = NUL; /* erase the dash, */
+ continue; /* and go back for next char now. */
+ }
+ } else if (blocklvl > 0) { /* No continuation character */
+ if (chsrc) { /* But we're in a "block" */
+ *bp++ = ','; /* Add comma */
+ *bp = NUL;
+ continue;
+ }
+ } else { /* No continuation, end of command. */
+ *bp = NUL; /* Terminate the command string. */
+ if (comment) { /* If we're in a comment, */
+ comment = 0; /* Say we're not any more, */
+ *cp = NUL; /* cut it off. */
+ }
+ np = bp; /* Where to start next field. */
+ cmbptr = np;
+ if (setatm(pp,0) < 0) { /* Copy field to atom buffer */
+ debug(F111,"gtword too long #2",pp,strlen(pp));
+ printf("?Field too long error 2\n");
+ return(-9);
+ }
+ inword = 0; /* Not in a word any more. */
+ crflag = 1;
+ /* debug(F110,"gtword","crflag is set",0); */
+#ifdef CK_RECALL
+ current = rlast;
+#endif /* CK_RECALL */
+ cmflgs = 1;
+ if (!xcmdsrc
+#ifdef CK_RECALL
+ || force_add
+#endif /* CK_RECALL */
+ )
+ addcmd(cmdbuf);
+ return(cmflgs);
+ }
+ }
+/*
+ This section handles interactive help, completion, editing, and history.
+ Rearranged as a switch statement executed only if we're at top level since
+ there is no need for any of this within command files and macros: Aug 2000.
+ Jun 2001: Even if at top level, skip this if the character was fetched from
+ the reparse or recall buffer, or if stdin is redirected.
+*/
+ if ((xcmdsrc == 0 /* Only at top level */
+#ifndef NOSPL
+ || askflag /* or user is typing ASK response */
+#endif /* NOSPL */
+ ) && chsrc != 0 && realtty) { /* from the real keyboard */
+
+/* Use ANSI / VT100 up and down arrow keys for command recall. */
+
+ if (isesc && (
+#ifdef IKSD
+ inserver
+#else
+ 0
+#endif /* IKSD */
+#ifdef USE_ARROWKEYS
+ || 1
+#endif /* USE_ARROWKEYS */
+ )
+ ) { /* A real ESC was typed */
+ int x;
+ msleep(200); /* Wait 1/5 sec */
+ x = cmdconchk(); /* Was it followed by anything? */
+ debug(F101,"Arrowkey ESC cmdconchk","",x);
+
+ if (x > 1) { /* If followed by at least 2 chars */
+ int c2;
+ c2 = cmdgetc(0); /* Get the first one */
+ debug(F101,"Arrowkey ESC c2","",c2);
+
+ if (c2 != '[' && c2 != 'O') { /* If not [ or O */
+ pushc = c2; /* Push it and take the ESC solo */
+ } else {
+ c2 = cmdgetc(0); /* Get the second one */
+ debug(F101,"Arrowkey ESC c3","",c2);
+ switch (c2) {
+#ifndef NORECALL
+ case 'A': /* Up */
+ c = BEL;
+ c = C_UP;
+ break;
+ case 'B': /* Down */
+ c = BEL;
+ c = C_DN;
+ break;
+ case 'C': /* Right */
+ case 'D': /* Left */
+#else
+ default:
+#endif /* NORECALL */
+ c = BEL; /* We don't use these yet */
+ break;
+ }
+ }
+ }
+ }
+
+ switch (c) {
+ case '?': /* ?-Help */
+#ifndef NOSPL
+ if (askflag) /* No help in ASK response */
+ break;
+#endif /* NOSPL */
+ if (quoting
+ && !kstartactive
+ && !comment
+ ) {
+ cmdecho((char) c, 0);
+ *bp = NUL;
+ if (setatm(pp,0) < 0) {
+ debug(F111,"gtword too long ?",pp,strlen(pp));
+ printf("?Too long\n");
+ return(-9);
+ }
+ qmflag = 1;
+ return(cmflgs = 3);
+ }
+
+ case ESC: /* Esc or Tab completion */
+ if (!comment) {
+ *bp = NUL;
+ if (setatm(pp,0) < 0) {
+ debug(F111,"gtword too long Esc",pp,strlen(pp));
+ printf("?Too long\n");
+ return(-9);
+ }
+ esflag = 1;
+ return(cmflgs = 2);
+ } else {
+ bleep(BP_WARN);
+ continue;
+ }
+
+ case BS: /* Character deletion */
+ case RUB:
+ if (bp > cmdbuf) { /* If still in buffer... */
+ cmdchardel(); /* erase it. */
+ bp--; /* point behind it, */
+ if (*bp == lbrace) bracelvl--; /* Adjust brace count */
+ if (*bp == rbrace) bracelvl++;
+ if ((*bp == SP) && /* Flag if current field gone */
+ (*pp != lbrace || bracelvl == 0))
+ inword = 0;
+ *bp = NUL; /* Erase character from buffer. */
+ } else { /* Otherwise, */
+ bleep(BP_WARN);
+ cmres(); /* and start parsing a new command. */
+ *bp = *atmbuf = NUL;
+ }
+ if (pp < bp)
+ continue;
+ else
+ return(cmflgs = -1);
+
+ case LDEL: /* ^U, line deletion */
+ while ((bp--) > cmdbuf) {
+ cmdchardel();
+ *bp = NUL;
+ }
+ cmres(); /* Restart the command. */
+ *bp = *atmbuf = NUL;
+ inword = 0;
+ return(cmflgs = -1);
+
+ case WDEL: /* ^W, word deletion */
+ if (bp <= cmdbuf) { /* Beep if nothing to delete */
+ bleep(BP_WARN);
+ cmres();
+ *bp = *atmbuf = NUL;
+ return(cmflgs = -1);
+ }
+ bp--;
+ /* Back up over any trailing nonalphanums */
+ /* This is dependent on ASCII collating sequence */
+ /* but isalphanum() is not available everywhere. */
+ for ( ;
+ (bp >= cmdbuf) &&
+ ((*bp < '0') ||
+ ((*bp > '9') && (*bp < '@')) ||
+ ((*bp > 'Z') && (*bp < 'a')) ||
+ (*bp > 'z'));
+ bp--
+ ) {
+ cmdchardel();
+ *bp = NUL;
+ }
+ /* Now delete back to rightmost remaining nonalphanum */
+ for ( ; (bp >= cmdbuf) && (*bp) ; bp--) {
+ if ((*bp < '0') ||
+ (*bp > '9' && *bp < '@') ||
+ (*bp > 'Z' && *bp < 'a') ||
+ (*bp > 'z'))
+ break;
+ cmdchardel();
+ *bp = NUL;
+ }
+ bp++;
+ inword = 0;
+ return(cmflgs = -1);
+
+ case RDIS: { /* ^R, redisplay */
+ char *cpx; char cx;
+ *bp = NUL;
+ printf("\n%s",cmprom);
+ cpx = cmdbuf;
+ while ((cx = *cpx++)) {
+ cmdecho(cx,0);
+ }
+ fflush(stdout);
+ continue;
+ }
+#ifndef NOLASTFILE
+ case VT:
+ if (lastfile) {
+ printf("%s ",lastfile);
+#ifdef GEMDOS
+ fflush(stdout);
+#endif /* GEMDOS */
+ inword = cmflgs = 0;
+ addbuf(lastfile); /* Supply default. */
+ if (setatm(lastfile,0) < 0) {
+ printf("Last name too long\n");
+ if (np) free(np);
+ return(-9);
+ }
+ } else { /* No default */
+ bleep(BP_WARN);
+ }
+ return(0);
+#endif /* NOLASTFILE */
+ }
+
+#ifdef CK_RECALL
+ if (on_recall && /* Reading commands from keyboard? */
+ (cm_recall > 0) && /* Saving commands? */
+ (c == C_UP || c == C_UP2)) { /* Go up one */
+ if (last_recall == 2 && current > 0)
+ current--;
+ if (current < 0) { /* Nowhere to go, */
+ bleep(BP_WARN);
+ continue;
+ }
+ if (recall[current]) { /* We have a previous command */
+ while ((bp--) > cmdbuf) { /* Erase current line */
+ cmdchardel();
+ *bp = NUL;
+ }
+ ckstrncpy(cmdbuf,recall[current],CMDBL);
+#ifdef OSK
+ fflush(stdout);
+ write(fileno(stdout), "\r", 1);
+ printf("%s%s",cmprom,cmdbuf);
+#else
+ printf("\r%s%s",cmprom,cmdbuf);
+#endif /* OSK */
+ current--;
+ }
+ last_recall = 1;
+ return(cmflgs = -1); /* Force a reparse */
+ }
+ if (on_recall && /* Reading commands from keyboard? */
+ (cm_recall > 0) && /* Saving commands? */
+ (c == C_DN)) { /* Down one */
+ int x = 1;
+ if (last_recall == 1)
+ x++;
+ if (current + x > rlast) { /* Already at bottom, beep */
+ bleep(BP_WARN);
+ continue;
+ }
+ current += x; /* OK to go down */
+ if (recall[current]) {
+ while ((bp--) > cmdbuf) { /* Erase current line */
+ cmdchardel();
+ *bp = NUL;
+ }
+ ckstrncpy(cmdbuf,recall[current],CMDBL);
+#ifdef OSK
+ fflush(stdout);
+ write(fileno(stdout), "\r", 1);
+ printf("%s%s",cmprom,cmdbuf);
+#else
+ printf("\r%s%s",cmprom,cmdbuf);
+#endif /* OSK */
+ last_recall = 2;
+ return(cmflgs = -1); /* Force reparse */
+ }
+ }
+#endif /* CK_RECALL */
+ }
+
+ if (c < SP && quote == 0) { /* Any other unquoted control char */
+ if (!chsrc) { /* If cmd file, point past it */
+ bp++;
+ } else {
+ bleep(BP_WARN);
+ }
+ continue; /* continue, don't put in buffer */
+ }
+ linebegin = 0; /* Not at beginning of line */
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, 0); /* Echo what was typed. */
+ fflush (stdout);
+ fflush(stderr);
+ }
+#else
+#ifdef NOSPL
+ if (echof || chsrc)
+#else
+ if (echof || (echostars && chsrc))
+#endif /* NOSPL */
+ cmdecho((char) c, 0); /* Echo what was typed. */
+#endif /* BEBOX */
+ } else { /* This character was quoted. */
+ int qf = 1;
+ quote = 0; /* Unset the quote flag. */
+ /* debug(F000,"gtword quote 0","",c); */
+ /* Quote character at this level is only for SP, ?, and controls */
+ /* If anything else was quoted, leave quote in, and let */
+ /* the command-specific parsing routines handle it, e.g. \007 */
+ if (c > 32 && c != '?' && c != RUB && chsrc != 0) {
+ /* debug(F000,"gtword quote 1","",c); */
+ *bp++ = CMDQ; /* Deposit \ if it came from tty */
+ qf = 0; /* and don't erase it from screen */
+ linebegin = 0; /* Not at beginning of line */
+#ifdef BS_DIRSEP
+/*
+ This is a hack to handle "cd \" or "cd foo\" on OS/2 and similar systems.
+ If we were called from cmdir() and the previous character was the quote
+ character, i.e. backslash, and this character is the command terminator,
+ then we stuff an extra backslash into the buffer without echoing, then
+ we stuff the carriage return back in again, and go back and process it,
+ this time with the quote flag off.
+*/
+ } else if (dirnamflg && (c == CR || c == LF || c == SP)) {
+ /* debug(F000,"gtword quote 2","",c); */
+ *bp++ = CMDQ;
+ linebegin = 0; /* Not at beginning of line */
+ *bp = (c == SP ? SP : CR);
+ goto CMDIRPARSE;
+#endif /* BS_DIRSEP */
+ }
+#ifdef BEBOX
+ if (echof) {
+ cmdecho((char) c, qf); /* Echo what was typed. */
+ fflush (stdout);
+ fflush(stderr);
+ }
+#else
+ if (echof) cmdecho((char) c, qf); /* Now echo quoted character */
+#endif /* BEBOX */
+ /* debug(F111,"gtword quote",cmdbuf,c); */
+ }
+#ifdef COMMENT
+ if (echof) cmdecho((char) c,quote); /* Echo what was typed. */
+#endif /* COMMENT */
+ if (!comment) inword = 1; /* Flag we're in a word. */
+ if (quote) continue; /* Don't deposit quote character. */
+ if (c != NL) { /* Deposit command character. */
+ *bp++ = (char) c; /* and make sure there is a NUL */
+#ifdef COMMENT
+ *bp = NUL; /* after it */
+#endif /* COMMENT */
+ }
+ } /* End of big while */
+ bleep(BP_WARN);
+ printf("?Command too long, maximum length: %d.\n",CMDBL);
+ cmflgs = -2;
+ return(-9);
+}
+
+/* Utility functions */
+
+/* A D D B U F -- Add the string pointed to by cp to the command buffer */
+
+static int
+addbuf(cp) char *cp; {
+ int len = 0;
+ while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) {
+ *bp++ = *cp++; /* Copy and */
+ len++; /* count the characters. */
+ }
+ *bp++ = SP; /* Put a space at the end */
+ *bp = NUL; /* Terminate with a null */
+ np = bp; /* Update the next-field pointer */
+ cmbptr = np;
+ return(len); /* Return the length */
+}
+
+/* S E T A T M -- Deposit a token in the atom buffer. */
+/*
+ Break on space, newline, carriage return, or NUL.
+ Call with:
+ cp = Pointer to string to copy to atom buffer.
+ fcode = 0 means break on whitespace or EOL.
+ fcode = 1 means don't break on space.
+ fcode = 2 means break on space, ':', or '='.
+ fcode = 3 means copy the whole string.
+ Null-terminate the result.
+ Return length of token, and also set global "cc" to this length.
+ Return -1 if token was too long.
+*/
+static int
+setatm(cp,fcode) char *cp; int fcode; {
+ char *ap, *xp, *dqp = NULL, lbrace, rbrace;
+ int bracelvl = 0, dq = 0;
+
+ register char * s;
+ register int n = 0;
+
+ if (cmfldflgs & 1) { /* Handle grouping */
+ lbrace = '(';
+ rbrace = ')';
+ } else {
+ lbrace = '{';
+ rbrace = '}';
+ }
+ cc = 0; /* Character counter */
+ ap = atmbuf; /* Address of atom buffer */
+
+ s = cp;
+
+ while (*s++) n++; /* Save a call to strlen */
+
+ if (n > ATMBL) {
+ printf("?Command buffer overflow\n");
+ return(-1);
+ }
+ /* debug(F111,"setatm",cp,n); */
+ if (cp == ap) { /* In case source is atom buffer */
+ xp = atybuf; /* make a copy */
+#ifdef COMMENT
+ strncpy(xp,ap,ATMBL); /* so we can copy it back, edited. */
+ cp = xp;
+#else
+ s = ap;
+ while ((*xp++ = *s++)) ; /* We already know it's big enough */
+ cp = xp = atybuf;
+#endif /* COMMENT */
+ }
+ *ap = NUL; /* Zero the atom buffer */
+ if (fcode == 1) { /* Trim trailing blanks */
+ while (--n >= 0 && cp[n] == SP)
+ ;
+ cp[n+1] = NUL;
+ }
+ while (*cp == SP) { /* Trim leading spaces */
+ cp++;
+ n--;
+ }
+ if (*cp == '"') { /* Starts with doublequote? */
+ dq = 1;
+ dqp = cp;
+ }
+ while (*cp) {
+ if (*cp == lbrace)
+ bracelvl++;
+ else if (*cp == rbrace)
+ bracelvl--;
+ if (bracelvl < 0)
+ bracelvl = 0;
+ if (bracelvl == 0) {
+ if (dq) {
+ if (*cp == SP || *cp == HT) {
+ if (cp > dqp+1) {
+ if (*(cp-1) == '"' && *(cp-2) != CMDQ) {
+ break;
+ }
+ }
+ }
+ } else if ((*cp == SP || *cp == HT) && fcode != 1 && fcode != 3)
+ break;
+ if ((fcode == 2) && (*cp == '=' || *cp == ':')) break;
+ if ((fcode != 3) && (*cp == LF || *cp == CR)) break;
+ }
+ *ap++ = *cp++;
+ cc++;
+ }
+ *ap = NUL; /* Terminate the string. */
+ /* debug(F111,"setatm result",atmbuf,cc); */
+ return(cc); /* Return length. */
+}
+
+/*
+ These functions attempt to hide system dependencies from the mainline
+ code in gtword(). Dummy arg for cmdgetc() needed for compatibility with
+ coninc(), ttinc(), etc, since a pointer to this routine can be passed in
+ place of those to tn_doop().
+
+ No longer static. Used by askmore(). Fri Aug 20 15:03:34 1999.
+*/
+#define CMD_CONINC /* How we get keyboard chars */
+
+int
+cmdgetc(timelimit) int timelimit; { /* Get a character from the tty. */
+ int c;
+#ifdef IKSD
+ extern int inserver;
+#endif /* IKSD */
+#ifdef CK_LOGIN
+ extern int x_logged;
+#endif /* CK_LOGIN */
+#ifdef TNCODE
+ static int got_cr = 0;
+ extern int ckxech;
+ int tx = 0, is_tn = 0;
+#endif /* TNCODE */
+
+ if (pushc
+#ifndef NOSPL
+ && !askflag
+#endif /* NOSPL */
+ ) {
+ debug(F111,"cmdgetc()","pushc",pushc);
+ c = pushc;
+ pushc = NUL;
+ if (xcmfdb && c == '?') /* Don't echo ? twice if chaining. */
+ cmdchardel();
+ return(c);
+ }
+#ifdef datageneral
+ {
+ char ch;
+ c = dgncinb(0,&ch,1); /* -1 is EOF, -2 TO,
+ * -c is AOS/VS error */
+ if (c == -2) { /* timeout was enabled? */
+ resto(channel(0)); /* reset timeouts */
+ c = dgncinb(0,&ch,1); /* retry this now! */
+ }
+ if (c < 0) return(-4); /* EOF or some error */
+ else c = (int) ch & 0177; /* Get char without parity */
+/* echof = 1; */
+ }
+#else /* Not datageneral */
+#ifndef MINIX2
+ if (
+#ifdef IKSD
+ (!local && inserver) ||
+#endif /* IKSD */
+ timelimit > 0) {
+#ifdef TNCODE
+ GETNEXTCH:
+ is_tn = !pushc && !local && sstelnet;
+#endif /* TNCODE */
+#ifdef COMMENT
+ c = coninc(timelimit > 0 ? 1 : 0);
+#else /* COMMENT */
+ /* This is likely to break the asktimeout... */
+ c = coninc(timelimit);
+#endif /* COMMENT */
+ /* debug(F101,"cmdgetc coninc","",c); */
+#ifdef TNCODE
+ if (c >= 0 && is_tn) { /* Server-side Telnet */
+ switch (c) {
+ case IAC:
+ /* debug(F111,"gtword IAC","c",c); */
+ got_cr = 0;
+ if ((tx = tn_doop((CHAR)(c & 0xff),ckxech,coninc)) == 0) {
+ goto GETNEXTCH;
+ } else if (tx <= -1) { /* I/O error */
+ /* If there was a fatal I/O error then ttclos() */
+ /* has been called and the next GETNEXTCH attempt */
+ /* will be !is_tn since ttclos() sets sstelnet = 0 */
+ doexit(BAD_EXIT,-1); /* (or return(-4)? */
+ } else if (tx == 1) { /* ECHO change */
+ ckxech = dpx = 1; /* Get next char */
+ goto GETNEXTCH;
+ } else if (tx == 2) { /* ECHO change */
+ ckxech = dpx = 0; /* Get next char */
+ goto GETNEXTCH;
+ } else if (tx == 3) { /* Quoted IAC */
+ c = 255; /* proceeed with it. */
+ }
+#ifdef IKS_OPTION
+ else if (tx == 4) { /* IKS State Change */
+ goto GETNEXTCH;
+ }
+#endif /* IKS_OPTION */
+ else if (tx == 6) { /* Remote Logout */
+ doexit(GOOD_EXIT,0);
+ } else {
+ goto GETNEXTCH; /* Unknown, get next char */
+ }
+ break;
+#ifdef COMMENT
+ case CR:
+ if (!TELOPT_U(TELOPT_BINARY)) {
+ if (got_cr) {
+ /* This means the sender is violating Telnet */
+ /* protocol because we received two CRs in a */
+ /* row without getting either LF or NUL. */
+ /* This will not solve the problem but it */
+ /* will at least allow two CRs to do something */
+ /* whereas before the user would have to guess */
+ /* to send LF or NUL after the CR. */
+ debug(F100,"gtword CR telnet error","",0);
+ c = LF;
+ } else {
+ debug(F100,"gtword skipping CR","",0);
+ got_cr = 1; /* Remember a CR was received */
+ goto GETNEXTCH;
+ }
+ } else {
+ debug(F100,"gtword CR to LF","",0);
+ c = LF;
+ }
+ break;
+ case LF:
+ if (!TELOPT_U(TELOPT_BINARY)) {
+ got_cr = 0;
+ debug(F100,"gtword LF","",0);
+ } else {
+ if (got_cr) {
+ got_cr = 0;
+ debug(F100,"gtword skipping LF","",0);
+ goto GETNEXTCH;
+ }
+ }
+ break;
+ case NUL:
+ if (!TELOPT_U(TELOPT_BINARY) && got_cr) {
+ c = LF;
+ debug(F100,"gtword NUL to LF","",0);
+ } else {
+ debug(F100,"gtword NUL","",0);
+ }
+ got_cr = 0;
+ break;
+#else /* COMMENT */
+ case CR:
+ if ( !TELOPT_U(TELOPT_BINARY) && got_cr ) {
+ /* This means the sender is violating Telnet */
+ /* protocol because we received two CRs in a */
+ /* row without getting either LF or NUL. */
+ /* This will not solve the problem but it */
+ /* will at least allow two CRs to do something */
+ /* whereas before the user would have to guess */
+ /* to send LF or NUL after the CR. */
+ debug(F100,"gtword CR telnet error","",0);
+ } else {
+ got_cr = 1; /* Remember a CR was received */
+ }
+ /* debug(F100,"gtword CR to LF","",0); */
+ c = LF;
+ break;
+ case LF:
+ if (got_cr) {
+ got_cr = 0;
+ /* debug(F100,"gtword skipping LF","",0); */
+ goto GETNEXTCH;
+ }
+ break;
+ case NUL:
+ if (got_cr) {
+ got_cr = 0;
+ /* debug(F100,"gtword skipping NUL","",0); */
+ goto GETNEXTCH;
+#ifdef COMMENT
+ } else {
+ debug(F100,"gtword NUL","",0);
+#endif /* COMMENT */
+ }
+ break;
+#endif /* COMMENT */
+#ifdef IKSD
+ case ETX: /* Ctrl-C... */
+ case EOT: /* EOT = EOF */
+ if (inserver
+#ifdef CK_LOGIN
+ && !x_logged
+#endif /* CK_LOGIN */
+ )
+ return(-4);
+ break;
+#endif /* IKSD */
+ default:
+ got_cr = 0;
+ }
+ }
+#endif /* TNCODE */
+ } else {
+#ifdef OS2
+ c = coninc(0);
+#else /* OS2 */
+#ifdef CMD_CONINC
+#undef CMD_CONINC
+#endif /* CMD_CONINC */
+ c = getchar();
+#endif /* OS2 */
+ }
+#else /* MINIX2 */
+#undef getc
+#ifdef CMD_CONINC
+#undef CMD_CONINC
+#endif /* CMD_CONINC */
+ c = getc(stdin);
+ /* debug(F101,"cmdgetc getc","",c); */
+#endif /* MINIX2 */
+#ifdef RTU
+ if (rtu_bug) {
+#ifdef CMD_CONINC
+#undef CMD_CONINC
+#endif /* CMD_CONINC */
+ c = getchar(); /* RTU doesn't discard the ^Z */
+ rtu_bug = 0;
+ }
+#endif /* RTU */
+#endif /* datageneral */
+ return(c); /* Return what we got */
+}
+
+/* #ifdef USE_ARROWKEYS */
+
+/* Mechanism to use for peeking into stdin buffer */
+
+#ifndef USE_FILE_CNT /* stdin->__cnt */
+#ifndef USE_FILE__CNT /* Note: two underscores */
+#ifdef HPUX /* HPUX 7-11 */
+#ifndef HPUX5
+#ifndef HPUX6
+#define USE_FILE__CNT
+#endif /* HPUX6 */
+#endif /* HPUX5 */
+#else
+#ifdef ANYSCO /* SCO UNIX, OSR5, Unixware, etc */
+#ifndef OLD_UNIXWARE /* But not Unixware 1.x or 2.0 */
+#ifndef UNIXWARE2 /* or 2.1.0 */
+#define USE_FILE__CNT
+#endif /* UNIXWARE2 */
+#endif /* OLD_UNIXWARE */
+#endif /* ANYSCO */
+#endif /* HPUX */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+
+#ifndef USE_FILE_R /* stdin->_r */
+#ifndef USE_FILE_CNT
+#ifndef USE_FILE__CNT
+#ifdef BSD44 /* {Free,Open,Net}BSD, BSDI */
+#define USE_FILE_R
+#endif /* BSD44 */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+#endif /* USE_FILE_R */
+
+#ifndef USE_FILE_R /* stdin->_cnt */
+#ifndef USE_FILE_CNT
+#ifndef USE_FILE__CNT
+#define USE_FILE_CNT /* Everybody else (but Linux) */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+#endif /* USE_FILE_R */
+
+
+/*
+ c m d c o n c h k
+
+ How many characters are waiting to be read at the console? Normally
+ conchk() would tell us, but in Unix and VMS cmdgetc() uses stdio getchar(),
+ thus bypassing coninc()/conchk(), so we have to peek into the stdin buffer,
+ which is totally nonportable. Which is why this routine is, at least for
+ now, used only for checking for arrow-key sequences from the keyboard after
+ an ESC was read. Wouldn't it be nice if the stdio package had a function
+ that returned the number of bytes waiting to be read from its buffer?
+ Returns 0 or greater always.
+*/
+int
+cmdconchk() {
+ int x = 0, y;
+ y = pushc ? 1 : 0; /* Have command character pushed? */
+#ifdef OS2
+ x = conchk(); /* Check device-driver buffer */
+ if (x < 0) x = 0;
+#else /* OS2 */
+#ifdef CMD_CONINC /* See cmdgetc() */
+ x = conchk(); /* Check device-driver buffer */
+ if (x < 0) x = 0;
+#else /* CMD_CONINC */
+
+/* Here we must look inside the stdin buffer - highly platform dependent */
+
+#ifdef _IO_file_flags /* Linux */
+ x = (int) ((stdin->_IO_read_end) - (stdin->_IO_read_ptr));
+ debug(F101,"cmdconchk _IO_file_flags","",x);
+#else /* _IO_file_flags */
+#ifdef USE_FILE_CNT /* Traditional */
+#ifdef VMS
+ debug(F101,"cmdconchk (*stdin)->_cnt","",(*stdin)->_cnt);
+ x = (*stdin)->_cnt;
+#else
+#ifdef NOARROWKEYS
+ debug(F101,"cmdconchk NOARROWKEYS x","",0);
+#else
+ debug(F101,"cmdconchk stdin->_cnt","",stdin->_cnt);
+ x = stdin->_cnt;
+#endif /* NOARROWKEYS */
+#endif /* VMS */
+ if (x == 0) x = conchk();
+ if (x < 0) x = 0;
+#else /* USE_FILE_CNT */
+#ifdef USE_FILE__CNT /* HP-UX */
+ debug(F101,"cmdconchk stdin->__cnt","",stdin->__cnt);
+ x = stdin->__cnt;
+ if (x == 0) x = conchk();
+ if (x < 0) x = 0;
+#else /* USE_FILE_CNT */
+#ifdef USE_FILE_R /* FreeBSD, OpenBSD, etc */
+ debug(F101,"cmdconchk stdin->_r","",stdin->_r);
+ x = stdin->_r;
+ if (x == 0) x = conchk();
+ if (x < 0) x = 0;
+
+ /* Fill in any others here... */
+
+#endif /* USE_FILE_R */
+#endif /* USE_FILE__CNT */
+#endif /* USE_FILE_CNT */
+#endif /* _IO_file_flags */
+#endif /* CMD_CONINC */
+#endif /* OS2 */
+ return(x + y);
+}
+/* #endif */ /* USE_ARROWKEYS */
+
+
+static VOID
+cmdclrscn() { /* Clear the screen */
+ ck_cls();
+}
+
+static VOID /* What to echo at end of command */
+#ifdef CK_ANSIC
+cmdnewl(char c)
+#else
+cmdnewl(c) char c;
+#endif /* CK_ANSIC */
+/* cmdnewl */ {
+#ifdef OS2
+#ifdef IKSD
+ extern int inserver;
+ if (inserver && c == LF)
+ putchar(CR);
+#endif /* IKSD */
+#endif /* OS2 */
+
+ putchar(c); /* c is the terminating character */
+
+#ifdef WINTCP /* what is this doing here? */
+ if (c == CR) putchar(NL);
+#endif /* WINTCP */
+
+/*
+ A.A. Chernov, who sent in changes for FreeBSD, said we also needed this
+ for SVORPOSIX because "setup terminal by termios and curses does
+ not convert \r to \n, so additional \n needed in newline function." But
+ it is also very likely to result in unwanted blank lines.
+*/
+#ifdef BSD44
+ if (c == CR) putchar(NL);
+#endif /* BSD44 */
+
+#ifdef COMMENT
+ /* OS2 no longer needs this as all CR are converted to NL in coninc() */
+ /* This eliminates the ugly extra blank lines discussed above. */
+#ifdef OS2
+ if (c == CR) putchar(NL);
+#endif /* OS2 */
+#endif /* COMMENT */
+#ifdef aegis
+ if (c == CR) putchar(NL);
+#endif /* aegis */
+#ifdef AMIGA
+ if (c == CR) putchar(NL);
+#endif /* AMIGA */
+#ifdef datageneral
+ if (c == CR) putchar(NL);
+#endif /* datageneral */
+#ifdef GEMDOS
+ if (c == CR) putchar(NL);
+#endif /* GEMDOS */
+#ifdef STRATUS
+ if (c == CR) putchar(NL);
+#endif /* STRATUS */
+}
+
+static VOID
+cmdchardel() { /* Erase a character from the screen */
+#ifndef NOSPL
+ if (!echostars)
+#endif /* NOSPL */
+ if (!dpx) return;
+#ifdef datageneral
+ /* DG '\b' is EM (^y or \031) */
+ if (termtype == 1)
+ /* Erase a character from non-DG screen, */
+ dgncoub(1,"\010 \010",3);
+ else
+#endif /* datageneral */
+ printf("\b \b");
+#ifdef GEMDOS
+ fflush(stdout);
+#else
+#ifdef BEBOX
+ fflush(stdout);
+#endif /* BEBOX */
+#endif /* GEMDOS */
+}
+
+static VOID
+#ifdef CK_ANSIC
+cmdecho(char c, int quote)
+#else
+cmdecho(c,quote) char c; int quote;
+#endif /* CK_ANSIC */
+{ /* cmdecho */
+#ifdef NOSPL
+ if (!dpx) return;
+#else
+ if (!echostars) {
+ if (!dpx) return;
+ } else {
+ c = (char)echostars;
+ }
+#endif /* NOSPL */
+ /* Echo tty input character c */
+ if (quote) {
+ putchar(BS);
+ putchar(SP);
+ putchar(BS);
+#ifdef isprint
+ putchar((CHAR) (isprint(c) ? c : '^' ));
+#else
+ putchar((CHAR) ((c >= SP && c < DEL) ? c : '^'));
+#endif /* isprint */
+ } else {
+ putchar(c);
+ }
+#ifdef OS2
+ if (quote==1 && c==CR) putchar((CHAR) NL);
+#endif /* OS2 */
+ if (timelimit)
+ fflush(stdout);
+}
+
+/* Return pointer to current position in command buffer. */
+
+char *
+cmpeek() {
+ return(np);
+}
+#endif /* NOICP */
+
+
+#ifdef NOICP
+#include "ckcdeb.h"
+#include "ckucmd.h"
+#include "ckcasc.h"
+#endif /* NOICP */
+
+/* X X E S C -- Interprets backslash codes */
+/* Returns the int value of the backslash code if it is > -1 and < 256 */
+/* and updates the string pointer to first character after backslash code. */
+/* If the argument is invalid, leaves pointer unchanged and returns -1. */
+
+int
+xxesc(s) char **s; { /* Expand backslash escapes */
+ int x, y, brace, radix; /* Returns the int value */
+ char hd = '9'; /* Highest digit in radix */
+ char *p;
+
+ p = *s; /* pointer to beginning */
+ if (!p) return(-1); /* watch out for null pointer */
+ x = *p++; /* character at beginning */
+ if (x != CMDQ) return(-1); /* make sure it's a backslash code */
+
+ x = *p; /* it is, get the next character */
+ if (x == '{') { /* bracketed quantity? */
+ p++; /* begin past bracket */
+ x = *p;
+ brace = 1;
+ } else brace = 0;
+ switch (x) { /* Start interpreting */
+ case 'd': /* Decimal radix indicator */
+ case 'D':
+ p++; /* Just point past it and fall thru */
+ case '0': /* Starts with digit */
+ case '1':
+ case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ radix = 10; /* Decimal */
+ hd = '9'; /* highest valid digit */
+ break;
+ case 'o': /* Starts with o or O */
+ case 'O':
+ radix = 8; /* Octal */
+ hd = '7'; /* highest valid digit */
+ p++; /* point past radix indicator */
+ break;
+ case 'x': /* Starts with x or X */
+ case 'X':
+ radix = 16; /* Hexadecimal */
+ p++; /* point past radix indicator */
+ break;
+ default: /* All others */
+#ifdef COMMENT
+ *s = p+1; /* Treat as quote of next char */
+ return(*p);
+#else
+ return(-1);
+#endif /* COMMENT */
+ }
+ /* For OS/2, there are "wide" characters required for the keyboard
+ * binding, i.e \644 and similar codes larger than 255 (byte).
+ * For this purpose, give up checking for < 256. If someone means
+ * \266 should result in \26 followed by a "6" character, he should
+ * always write \{26}6 anyway. Now, return only the lower byte of
+ * the result, i.e. 10, but eat up the whole \266 sequence and
+ * put the wide result 266 into a global variable. Yes, that's not
+ * the most beautiful programming style but requires the least
+ * amount of changes to other routines.
+ */
+ if (*p == '{') { /* Sun May 11 20:00:40 2003 */
+ brace = 1; /* Allow {} after radix indicator */
+ p++;
+ }
+ if (radix <= 10) { /* Number in radix 8 or 10 */
+ for ( x = y = 0;
+ (*p) && (*p >= '0') && (*p <= hd)
+#ifdef OS2
+ && (y < 5) && (x*radix < KMSIZE);
+ /* the maximum needed value \8196 is 4 digits long */
+ /* while as octal it requires \1377, i.e. 5 digits */
+#else
+ && (y < 3) && (x*radix < 256);
+#endif /* OS2 */
+ p++,y++) {
+ x = x * radix + (int) *p - 48;
+ }
+#ifdef OS2
+ wideresult = x; /* Remember wide result */
+ x &= 255;
+#endif /* OS2 */
+ if (y == 0 || x > 255) { /* No valid digits? */
+ *s = p; /* point after it */
+ return(-1); /* return failure. */
+ }
+ } else if (radix == 16) { /* Special case for hex */
+ if ((x = unhex(*p++)) < 0) { *s = p - 1; return(-1); }
+ if ((y = unhex(*p++)) < 0) { *s = p - 2; return(-1); }
+ x = ((x << 4) & 0xF0) | (y & 0x0F);
+#ifdef OS2
+ wideresult = x;
+ if ((y = unhex(*p)) >= 0) {
+ p++;
+ wideresult = ((x << 4) & 0xFF0) | (y & 0x0F);
+ x = wideresult & 255;
+ }
+#endif /* OS2 */
+ } else x = -1;
+ if (brace && *p == '}' && x > -1) /* Point past closing brace, if any */
+ p++;
+ *s = p; /* Point to next char after sequence */
+ return(x); /* Return value of sequence */
+}
+
+int /* Convert hex string to int */
+#ifdef CK_ANSIC
+unhex(char x)
+#else
+unhex(x) char x;
+#endif /* CK_ANSIC */
+/* unhex */ {
+
+ if (x >= '0' && x <= '9') /* 0-9 is offset by hex 30 */
+ return(x - 0x30);
+ else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */
+ return(x - 0x37);
+ else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */
+ return(x - 0x57); /* (obviously ASCII dependent) */
+ else return(-1);
+}
+
+/* L O O K U P -- Lookup the string in the given array of strings */
+
+/*
+ Call this way: v = lookup(table,word,n,&x);
+
+ table - a 'struct keytab' table.
+ word - the target string to look up in the table.
+ n - the number of elements in the table.
+ x - address of an integer for returning the table array index,
+ or NULL if you don't need a table index.
+
+ The keyword table must be arranged in ascending alphabetical order;
+ alphabetic case doesn't matter but letters are treated as lowercase
+ for purposes of ordering; thus "^" and "_" come *before* the letters,
+ not after them.
+
+ Returns the keyword's associated value (zero or greater) if found,
+ with the variable x set to the keyword-table index. If is lookup()
+ is not successful, it returns:
+
+ -3 if nothing to look up (target was null),
+ -2 if ambiguous,
+ -1 if not found.
+
+ A match is successful if the target matches a keyword exactly, or if
+ the target is a prefix of exactly one keyword. It is ambiguous if the
+ target matches two or more keywords from the table.
+
+ Lookup() is the critical routine in scripts and so is optimized with a
+ simple static cache plus some other tricks. Maybe it could be improved
+ further with binary search or hash techniques but I doubt it since most
+ keyword tables are fairly short.
+*/
+
+#ifdef USE_LUCACHE /* Lookup cache */
+extern int lusize; /* (initialized in ckuus5.c) */
+extern char * lucmd[];
+extern int luval[];
+extern int luidx[];
+extern struct keytab * lutab[];
+long luhits = 0L;
+long lucalls = 0L;
+long xxhits = 0L;
+long luloop = 0L;
+#endif /* USE_LUCACHE */
+
+int
+lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; {
+
+ register int i, m;
+ int v, len, cmdlen = 0;
+ char c = NUL, c1, *s;
+
+/* Get 1st char of search object, if it's null return -3. */
+
+ if (!cmd || n < 1) /* Defense de nullarg */
+ return(-3);
+ c1 = *cmd; /* First character */
+ if (!c1) /* Make sure there is one */
+ return(-3);
+ if (isupper(c1)) /* If letter make it lowercase */
+ c1 = tolower(c1);
+
+#ifdef USE_LUCACHE /* lookup() cache */
+ m = lusize;
+ lucalls++; /* Count this lookup() call */
+ for (i = 0; i < m; i++) { /* Loop thru cache */
+ if (*(lucmd[i]) == c1) { /* Same as 1st char of search item? */
+ if (lutab[i] == table) { /* Yes - same table too? */
+ if (!strcmp(cmd,lucmd[i])) { /* Yes - compare */
+ if (x) *x = luidx[i]; /* Match - return index */
+ luhits++; /* Count cache hit */
+ return(luval[i]); /* Return associated value */
+ }
+ }
+ }
+ }
+#endif /* USE_LUCACHE */
+
+/* Not null, not in cache, look it up */
+
+ s = cmd;
+ while (*s++) cmdlen++; /* Length of target */
+/*
+ Quick binary search to find last table entry whose first character is
+ lexically less than the first character of the search object. This is
+ the starting point of the next loop, which must go in sequence since it
+ compares adjacent table entries.
+*/
+ if (n < 5) { /* Not worth it for small tables */
+ i = 0;
+ } else {
+ int lo = 0;
+ int hi = n;
+ int count = 0;
+ while (lo+2 < hi && ++count < 12) {
+ i = lo + ((hi - lo) / 2);
+ c = *(table[i].kwd);
+ if (isupper(c)) c = tolower(c);
+ if (c < c1) {
+ lo = i;
+ } else {
+ hi = i;
+ }
+ }
+ i = (c < c1) ? lo+1 : lo;
+#ifdef USE_LUCACHE
+ if (i > 0) xxhits++;
+#endif /* USE_LUCACHE */
+ }
+ for ( ; i < n-1; i++) {
+#ifdef USE_LUCACHE
+ luloop++;
+#endif /* USE_LUCACHE */
+ v = 0;
+ c = *(table[i].kwd);
+ if (c) {
+ if (isupper(c)) c = tolower(c);
+
+ /* The following is a big performance booster but makes it */
+ /* absolutely essential that all lookup() tables are in order. */
+
+ if (c > c1) /* Leave early if past our mark */
+ return(-1);
+
+#ifdef DEBUG
+ /* Use LOG DEBUG to check */
+
+ if (deblog) {
+ if (ckstrcmp(table[i].kwd,table[i+1].kwd,0,0) > 0) {
+ printf("TABLE OUT OF ORDER [%s] [%s]\n",
+ table[i].kwd,table[i+1].kwd);
+
+ }
+ }
+#endif /* DEBUG */
+
+ if (c == c1) {
+ len = 0;
+ s = table[i].kwd;
+ while (*s++) len++;
+ if ((len == cmdlen && !ckstrcmp(table[i].kwd,cmd,len,0)) ||
+ ((v = !ckstrcmp(table[i].kwd,cmd,cmdlen,0)) &&
+ ckstrcmp(table[i+1].kwd,cmd,cmdlen,0))) {
+ if (x) *x = i;
+ return(table[i].kwval);
+ }
+ } else v = 0;
+ }
+ if (v) { /* Ambiguous */
+ if (x) *x = i; /* Set index of first match */
+ return(-2);
+ }
+ }
+
+/* Last (or only) element */
+
+ if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0)) {
+ if (x) *x = n-1;
+ /* debug(F111,"lookup",table[i].kwd,table); */
+ return(table[n-1].kwval);
+ } else return(-1);
+}
+
+/*
+ x l o o k u p
+
+ Like lookup, but requires a full (but case-independent) match
+ and does NOT require the table to be in order.
+*/
+int
+xlookup(table,cmd,n,x) struct keytab table[]; char *cmd; int n, *x; {
+ register int i;
+ int len, cmdlen, one = 0;
+ register char c, c2, * s, * s2;
+
+ if (!cmd) cmd = ""; /* Check args */
+ if (!*cmd || n < 1) return(-3);
+
+ c = *cmd; /* First char of string to look up */
+ if (!*(cmd+1)) { /* Special handling for 1-char names */
+ cmdlen = 1;
+ if (isupper(c))
+ c = tolower(c);
+ one = 1;
+ } else {
+ cmdlen = 0;
+ s = cmd;
+ while (*s++) cmdlen++;
+ c = *cmd;
+ if (isupper(c))
+ c = tolower(c);
+ }
+ if (cmdlen < 1)
+ return(-3);
+
+ for (i = 0; i < n; i++) {
+ s = table[i].kwd; /* This entry */
+ if (!s) s = "";
+ if (!*s) continue; /* Empty table entry */
+ c2 = *s;
+ if (isupper(c2)) c2 = tolower(c2);
+ if (c != c2) continue; /* First char doesn't match */
+ if (one) { /* Name is one char long */
+ if (!*(s+1)) {
+ if (x) *x = i;
+ *cmd = c;
+ return(table[i].kwval); /* So is table entry */
+ }
+ } else { /* Otherwise do string comparison */
+ s2 = s;
+ len = 0;
+ while (*s2++) len++;
+ if (len == cmdlen && !ckstrcmp(s,cmd,-1,0)) {
+ if (x) *x = i;
+ return(table[i].kwval);
+ }
+ }
+ }
+ return(-1);
+}
+
+/* Reverse lookup */
+
+char *
+rlookup(table,n,x) struct keytab table[]; int n, x; {
+ int i;
+ for (i = 0; i < n; i++) {
+ if (table[i].kwval == x)
+ return(table[i].kwd);
+ }
+ return(NULL);
+}
+
+#ifndef NOICP
+int
+cmdsquo(x) int x; {
+ quoting = x;
+ return(1);
+}
+
+int
+cmdgquo() {
+ return(quoting);
+}
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.h
new file mode 100644
index 0000000..7cd4ced
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckucmd.h
@@ -0,0 +1,312 @@
+/* C K U C M D . H -- Header file for Unix cmd package */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>
+ Columbia University Kermit Project, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+#ifndef CKUCMD_H
+#define CKUCMD_H
+
+/* Command recall */
+
+#ifdef pdp11 /* Not enough room for this */
+#ifndef NORECALL
+#define NORECALL
+#endif /* NORECALL */
+#endif /* pdp11 */
+
+#ifdef DYNAMIC /* Dynamic command buffers */
+/*
+ Use malloc() to allocate the many command-related buffers in ckucmd.c.
+*/
+#ifndef DCMDBUF
+#ifndef NORECALL
+#define NORECALL
+#endif /* NORECALL */
+#endif /* DCMDBUF */
+
+#ifndef NORECALL
+#define CK_RECALL
+#else
+#ifdef CK_RECALL
+#undef CK_RECALL
+#endif /* CK_RECALL */
+#endif /* NORECALL */
+#else
+#ifndef NORECALL
+#define NORECALL
+#endif /* NORECALL */
+#endif /* DYNAMIC */
+
+#ifdef NORECALL
+#ifdef CK_RECALL
+#undef CK_RECALL
+#endif /* CK_RECALL */
+#endif /* NORECALL */
+
+#ifdef NORECALL
+#ifndef NOARROWKEYS
+#define NOARROWKEYS
+#endif /* NOARROWKEYS */
+#endif /* NORECALL */
+
+/* Special getchars */
+
+#ifdef VMS
+#ifdef getchar /* This is for VMS GCC */
+#undef getchar
+#endif /* getchar */
+#define getchar() vms_getchar()
+int vms_getchar(void);
+#endif /* VMS */
+
+#ifdef aegis
+#undef getchar
+#define getchar() coninc(0)
+#endif /* aegis */
+
+#ifdef AMIGA
+#undef getchar
+#define getchar() coninc(0)
+#endif /* AMIGA */
+
+#ifdef Plan9
+#undef getchar
+#define getchar() coninc(0)
+#undef putchar
+#define putchar(c) conoc(c)
+#undef printf
+#define printf conprint
+#endif /* Plan9 */
+
+/* Sizes of things */
+
+#ifndef CMDDEP
+#ifdef BIGBUFOK
+#define CMDDEP 64 /* Maximum command recursion depth */
+#else
+#define CMDDEP 20
+#endif /* BIGBUFOK */
+#endif /* CMDDEP */
+#define HLPLW 78 /* Width of ?-help line */
+#define HLPCW 19 /* Width of ?-help column */
+#define HLPBL 100 /* Help string buffer length */
+#ifdef BIGBUFOK
+#define ATMBL 10238 /* Command atom buffer length*/
+#else
+#ifdef NOSPL
+#define ATMBL 256
+#else
+#define ATMBL 1024
+#endif /* NOSPL */
+#endif /* BIGBUFOK */
+
+#ifndef CMDBL
+#ifdef NOSPL
+/* No script programming language, save some space */
+#define CMDBL 608 /* Command buffer length */
+#else
+#ifdef BIGBUFOK
+#define CMDBL 32763
+#else
+#define CMDBL 4092
+#endif /* OS2 */
+#endif /* NOSPL */
+#endif /* CMDBL */
+
+/* Special characters */
+
+#define RDIS 0022 /* Redisplay (^R) */
+#define LDEL 0025 /* Delete line (^U) */
+#define WDEL 0027 /* Delete word (^W) */
+#ifdef CK_RECALL
+#define C_UP 0020 /* Go Up in recall buffer (^P) */
+#define C_UP2 0002 /* Alternate Go Up (^B) for VMS */
+#define C_DN 0016 /* Go Down in recall buffer (^N) */
+#endif /* CK_RECALL */
+
+/* Keyword flags (bits, powers of 2) */
+
+#define CM_INV 1 /* Invisible keyword */
+#define CM_ABR 2 /* Abbreviation for another keyword */
+#define CM_HLP 4 /* Help-only keyword */
+#define CM_ARG 8 /* An argument is required */
+#define CM_NOR 16 /* No recall for this command */
+#define CM_PRE 32 /* Long-form cmdline arg for prescan */
+#define CM_PSH 64 /* Command disabled if nopush */
+#define CM_LOC 128 /* Command disabled if nolocal */
+
+/*
+ A long-form command line option is a keyword using the regular struct keytab
+ and lookup mechanisms. Flags that make sense in this context are CM_ARG,
+ indicating this option requires an argument (operand), and CM_PRE, which
+ means this option must be processed before the initialization file. The
+ absence of CM_PRE means the option is to be processed after the
+ initialization file in the normal manner.
+*/
+
+/* Token flags (numbers) */
+
+#define CMT_COM 0 /* Comment (; or #) */
+#define CMT_SHE 1 /* Shell escape (!) */
+#define CMT_LBL 2 /* Label (:) */
+#define CMT_FIL 3 /* Indirect filespec (@) (not used) */
+
+/* Path separator for path searches */
+
+#ifdef OS2
+#define PATHSEP ';'
+#else
+#ifdef UNIX
+#define PATHSEP ':'
+#else
+#define PATHSEP ','
+#endif /* UNIX */
+#endif /* OS2 */
+
+#ifndef CK_KEYTAB
+#define CK_KEYTAB
+
+/* Keyword Table Template perhaps already defined in ckcdeb.h */
+
+struct keytab { /* Keyword table */
+ char *kwd; /* Pointer to keyword string */
+ int kwval; /* Associated value */
+ int flgs; /* Flags (as defined above) */
+};
+#endif /* CK_KEYTAB */
+
+/* String preprocessing function */
+
+#ifdef CK_ANSIC /* ANSI C */
+#ifdef M_SYSV /* SCO Microsoft C wants no args */
+typedef int (*xx_strp)();
+#else
+typedef int (*xx_strp)(char *, char **, int *);
+#endif /* M_SYSV */
+#else /* Not ANSI C */
+typedef int (*xx_strp)();
+#endif /* CK_ANSIC */
+
+/* FLDDB struct */
+
+typedef struct FDB {
+ int fcode; /* Function code */
+ char * hlpmsg; /* Help message */
+ char * dflt; /* Default */
+ char * sdata; /* Additional string data */
+ int ndata1; /* Additional numeric data 1 */
+ int ndata2; /* Additional numeric data 2 */
+ xx_strp spf; /* String processing function */
+ struct keytab * kwdtbl; /* Keyword table */
+ struct FDB * nxtfdb; /* Pointer to next alternative */
+} fdb;
+
+typedef struct OFDB {
+ struct FDB * fdbaddr; /* Address of succeeding FDB struct */
+ int fcode; /* Function code */
+ char * sresult; /* String result */
+ int nresult; /* Integer result */
+ int kflags; /* Keyword flags if any */
+ CK_OFF_T wresult; /* Long integer ("wide") result */
+} ofdb;
+
+#ifndef CKUCMD_C
+extern struct OFDB cmresult;
+#endif /* CKUCMD_C */
+
+/* Codes for primary parsing function */
+
+#define _CMNUM 0 /* Number */
+#define _CMOFI 1 /* Output file */
+#define _CMIFI 2 /* Input file */
+#define _CMFLD 3 /* Arbitrary field */
+#define _CMTXT 4 /* Text string */
+#define _CMKEY 5 /* Keyword */
+#define _CMCFM 6 /* Confirmation */
+#define _CMDAT 7 /* Date/time */
+#define _CMNUW 8 /* Wide version of cmnum */
+
+/* Function prototypes */
+
+_PROTOTYP( int xxesc, (char **) );
+_PROTOTYP( int cmrini, (int) );
+_PROTOTYP( VOID cmsetp, (char *) );
+_PROTOTYP( VOID cmsavp, (char [], int) );
+_PROTOTYP( char * cmgetp, (void) );
+_PROTOTYP( VOID prompt, (xx_strp) );
+_PROTOTYP( VOID pushcmd, (char *) );
+_PROTOTYP( VOID cmres, (void) );
+_PROTOTYP( VOID cmini, (int) );
+_PROTOTYP( int cmgbrk, (void) );
+_PROTOTYP( int cmgkwflgs, (void) );
+_PROTOTYP( int cmpush, (void) );
+_PROTOTYP( int cmpop, (void) );
+_PROTOTYP( VOID untab, (char *) );
+_PROTOTYP( int cmnum, (char *, char *, int, int *, xx_strp ) );
+_PROTOTYP( int cmnumw, (char *, char *, int, CK_OFF_T *, xx_strp ) );
+_PROTOTYP( int cmofi, (char *, char *, char **, xx_strp ) );
+_PROTOTYP( int cmifi, (char *, char *, char **, int *, xx_strp ) );
+_PROTOTYP( int cmiofi, (char *, char *, char **, int *, xx_strp ) );
+_PROTOTYP( int cmifip,(char *, char *, char **, int *, int, char *, xx_strp ));
+_PROTOTYP( int cmifi2,(char *,char *,char **,int *,int,char *,xx_strp,int ));
+_PROTOTYP( int cmdir, (char *, char *, char **, xx_strp ) );
+_PROTOTYP( int cmdirp, (char *, char *, char **, char *, xx_strp ) );
+_PROTOTYP( int cmfld, (char *, char *, char **, xx_strp ) );
+_PROTOTYP( int cmtxt, (char *, char *, char **, xx_strp ) );
+_PROTOTYP( int cmkey, (struct keytab [], int, char *, char *, xx_strp) );
+_PROTOTYP( int cmkeyx, (struct keytab [], int, char *, char *, xx_strp) );
+_PROTOTYP( int cmkey2,(struct keytab [],int,char *,char *,char *,xx_strp,int));
+_PROTOTYP( int cmswi, (struct keytab [], int, char *, char *, xx_strp) );
+_PROTOTYP( int cmdate,(char *, char *, char **, int, xx_strp) );
+_PROTOTYP( char * cmpeek, (void) );
+_PROTOTYP( int cmfdb, (struct FDB *) );
+_PROTOTYP( VOID cmfdbi, (struct FDB *,
+ int, char *, char *, char *, int, int, xx_strp,
+ struct keytab *, struct FDB *) );
+_PROTOTYP( int chktok, (char *) );
+_PROTOTYP( int cmcfm, (void) );
+_PROTOTYP( int lookup, (struct keytab [], char *, int, int *) );
+_PROTOTYP( VOID kwdhelp, (struct keytab[],int,char *,char *,char *,int,int) );
+_PROTOTYP( int ungword, (void) );
+_PROTOTYP( VOID unungw, (void) );
+_PROTOTYP( int cmdsquo, (int) );
+_PROTOTYP( int cmdgquo, (void) );
+_PROTOTYP( char * ckcvtdate, (char *, int) );
+_PROTOTYP( int cmdgetc, (int));
+#ifndef NOARROWKEYS
+_PROTOTYP( int cmdconchk, (void) );
+#endif /* NOARROWKEYS */
+
+#ifdef CK_RECALL
+_PROTOTYP( char * cmgetcmd, (char *) );
+_PROTOTYP( VOID addcmd, (char *) );
+_PROTOTYP( VOID cmaddnext, (void) );
+#endif /* CK_RECALL */
+_PROTOTYP( char * cmcvtdate, (char *, int) );
+_PROTOTYP( char * cmdiffdate, (char *, char *) );
+_PROTOTYP( char * cmdelta, (int,
+ int,int,int,int,int,int,int,int,int,int,int,int ));
+_PROTOTYP( char * shuffledate, (char *, int) );
+_PROTOTYP( int filhelp, (int, char *, char *, int, int) );
+_PROTOTYP( int xfilhelp, (int, char *, char *, int, int,
+ int,
+ char *, char *, char *, char *,
+ CK_OFF_T, CK_OFF_T,
+ int, int,
+ char **) );
+_PROTOTYP( int delta2sec, (char *, long *) );
+
+#ifdef DCMDBUF
+_PROTOTYP( int cmsetup, (void) );
+#endif /* DCMDBUF */
+
+#endif /* CKUCMD_H */
+
+/* End of ckucmd.h */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckucns.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckucns.c
new file mode 100644
index 0000000..337197c
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckucns.c
@@ -0,0 +1,2720 @@
+#include "ckcsym.h"
+char *connv = "CONNECT Command for UNIX:select(), 9.0.139, 1 Mar 2010";
+
+/* C K U C N S -- Terminal connection to remote system, for UNIX */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ This version of the UNIX CONNECT module uses select(), which is required for
+ Kerberos encryption. Thus it can be used only on UNIX systems that support
+ select() on both TCP/IP and serial connections. A separate module that uses
+ a completely portable fork() structure can be used on systems where select()
+ is not available or does not work as required.
+*/
+
+#include "ckcdeb.h" /* Common things first */
+
+#ifndef NOLOCAL
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#include <errno.h> /* Error numbers */
+
+#ifndef NOTIMEH
+#include <time.h> /* For FD_blah */
+#ifdef SYSTIMEH /* (IRIX 5.3) */
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOTIMEH */
+
+#ifdef BSD42HACK /* Why is this necessary? */
+#ifndef DCLTIMEVAL
+#define DCLTIMEVAL
+#endif /* DCLTIMEVAL */
+#endif /* BSD42HACK */
+
+/* Kermit-specific includes */
+
+#include "ckcasc.h" /* ASCII characters */
+#include "ckcker.h" /* Kermit things */
+#include "ckucmd.h" /* For xxesc() prototype */
+#include "ckcnet.h" /* Network symbols */
+#ifndef NOCSETS
+#include "ckcxla.h" /* Character set translation */
+#endif /* NOCSETS */
+
+#ifdef BEBOX
+#include <kernel/OS.h>
+#include <socket.h>
+#include <stdio.h>
+#endif /* BEBOX */
+
+#include <signal.h> /* Signals */
+
+/* All the following is for select()... */
+
+#ifdef CKTIDLE /* Timeouts only for SET TERM IDLE */
+
+#ifndef DCLTIMEVAL
+#ifdef UNIXWARE
+#ifndef UW7
+#define DCLTIMEVAL
+#endif /* UW7 */
+#endif /* UNIXWARE */
+#endif /* DCLTIMEVAL */
+
+#ifdef DCLTIMEVAL /* Declare timeval ourselves */
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#else /* !DCLTIMEVAL */
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+#endif /* DCLTIMEVAL */
+#endif /* CKTIDLE */
+
+#ifndef SCO_OSR504
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* SCO_OSR504 */
+
+#ifndef FD_SETSIZE
+#ifdef CK_FORWARD_X
+#define FD_SETSIZE 256
+#else
+#define FD_SETSIZE 32
+#endif /* CK_FORWARD_X */
+#endif /* FD_SETSIZE */
+
+#ifdef HPUX
+#ifndef HPUX10
+#ifndef HPUX1100
+/* The three interior args to select() are (int *) rather than (fd_set *) */
+#ifndef INTSELECT
+#define INTSELECT
+#endif /* INTSELECT */
+#endif /* HPUX1100 */
+#endif /* HPUX10 */
+#endif /* HPUX */
+
+/* Internal function prototypes */
+
+#ifdef NEWFTP
+#endif /* NEWFTP */
+_PROTOTYP( VOID ttflux, (void) );
+_PROTOTYP( VOID doesc, (char) );
+_PROTOTYP( int hconne, (void) );
+#ifndef NOSHOW
+_PROTOTYP( VOID shomdm, (void) );
+#endif /* NOSHOW */
+_PROTOTYP( static int kbget, (void) );
+_PROTOTYP( static int ckcputf, (void) );
+
+/* External variables */
+
+extern struct ck_p ptab[];
+
+extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
+ mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, sosi, tnlm,
+ xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tt_lfd,
+ tn_nlm, ttfdflg,
+ tt_escape, justone, carrier, ttpty, hwparity;
+
+#ifndef NODIAL
+extern int dialmhu, dialsta;
+#endif /* NODIAL */
+
+#ifdef CKLEARN
+extern FILE * learnfp;
+extern int learning;
+static ULONG learnt1;
+static char learnbuf[LEARNBUFSIZ] = { NUL, NUL };
+static int learnbc = 0;
+static int learnbp = 0;
+static int learnst = 0;
+#endif /* CKLEARN */
+
+extern long speed;
+extern char ttname[], sesfil[], myhost[], *ccntab[];
+#ifdef TNCODE
+extern int tn_b_nlm, tn_rem_echo;
+#endif /* TNCODE */
+
+#ifdef CK_TRIGGER
+extern char * tt_trigger[], * triggerval;
+#endif /* CK_TRIGGER */
+
+#ifdef CKTIDLE
+extern int tt_idlelimit, tt_idleact;
+extern char * tt_idlestr;
+static int idlelimit = 0;
+#endif /* CKTIDLE */
+extern int cx_status; /* CONNECT status code */
+
+extern int nopush;
+
+#ifdef CK_APC
+extern int apcactive; /* Application Program Command (APC) */
+extern int apcstatus; /* items ... */
+static int apclength = 0;
+#ifdef DCMDBUF
+extern char *apcbuf;
+#else
+extern char apcbuf[];
+#endif /* DCMDBUF */
+static int apcbuflen = APCBUFLEN - 2;
+extern int protocol;
+#endif /* CK_APC */
+#ifndef NOXFER
+extern int autodl; /* Auto download */
+#endif /* NOXFER */
+
+#ifdef CK_AUTODL
+extern CHAR ksbuf[];
+extern CHAR stchr;
+extern int kstartactive;
+#endif /* CK_AUTODL */
+
+#ifdef CK_ENCRYPTION
+extern int me_auth;
+#endif /* CK_ENCRYPTION */
+
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+static int zmdlok = 1; /* Zmodem autodownloads available */
+#else
+static int zmdlok = 0; /* Depends on external protocol def */
+#endif /* XYZ_INTERNAL */
+#else
+static int zmdlok = 0; /* Not available at all */
+#endif /* CK_XYZ */
+
+#ifndef NOSETKEY /* Keyboard mapping */
+extern KEY *keymap; /* Single-character key map */
+extern MACRO *macrotab; /* Key macro pointer table */
+static MACRO kmptr = NULL; /* Pointer to current key macro */
+#endif /* NOSETKEY */
+
+/* Global variables local to this module */
+
+static int
+ active = 0,
+ quitnow = 0, /* <esc-char>Q was typed */
+ dohangup = 0, /* <esc-char>H was typed */
+ inshift = 0, /* SO/SI shift states */
+ outshift = 0;
+
+static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
+
+#ifdef CK_SMALL
+#define IBUFL 1536 /* Input buffer length */
+#else
+#define IBUFL 4096
+#endif /* CK_SMALL */
+
+static int obc = 0; /* Output buffer count */
+
+#ifndef OXOS
+#define OBUFL 1024 /* Output buffer length */
+#else
+#define OBUFL IBUFL
+#endif /* OXOS */
+
+#ifdef BIGBUFOK
+#define TMPLEN 4096 /* Temporary message buffer length */
+#else
+#define TMPLEN 200
+#endif /* BIGBUFOK */
+
+#ifdef DYNAMIC
+static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
+#else
+static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
+#endif /* DYNAMIC */
+
+#ifdef TNCODE
+static char tnopt[4];
+#endif /* TNCODE */
+
+#ifdef DYNAMIC
+static char *ibp; /* Input buffer pointer */
+#else
+static char *ibp = ibuf; /* Input buffer pointer */
+#endif /*DYNAMIC */
+static int ibc = 0; /* Input buffer count */
+
+#ifdef DYNAMIC
+static char *obp; /* Output buffer pointer */
+#else
+static char *obp = obuf; /* Output buffer pointer */
+#endif /* DYNAMIC */
+
+/* Character-set items */
+
+static int unicode = 0;
+
+#ifndef NOCSETS
+#ifdef CK_ANSIC /* ANSI C prototypes... */
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
+static CHAR (*sxo)(CHAR); /* Local translation functions */
+static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
+static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
+static CHAR (*rxi)(CHAR);
+#else /* Not ANSI C... */
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
+static CHAR (*sxo)(); /* Local translation functions */
+static CHAR (*rxo)(); /* for output (sending) terminal chars */
+static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */
+static CHAR (*rxi)();
+#endif /* CK_ANSIC */
+extern int language; /* Current language. */
+static int langsv; /* For remembering language setting. */
+extern struct csinfo fcsinfo[]; /* File character set info. */
+extern int tcsr, tcsl; /* Terminal character sets, remote & local. */
+static int tcs; /* Intermediate ("transfer") character set. */
+static int tcssize = 0; /* Size of tcs */
+#ifdef UNICODE /* UTF-8 support */
+#ifdef CK_ANSIC
+extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
+extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
+extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
+extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
+#else
+extern int (*xl_ufc[MAXFCSETS+1])();
+extern USHORT (*xl_fcu[MAXFCSETS+1])();
+extern int (*xuf)();
+extern USHORT (*xfu)();
+#endif /* CK_ANSIC */
+#endif /* UNICODE */
+#endif /* NOCSETS */
+
+static int printing = 0;
+
+/*
+ We do not need to parse and recognize escape sequences if we are being built
+ without character-set support AND without APC support.
+*/
+#ifdef NOESCSEQ
+#ifdef XPRINT
+#undef XPRINT
+#endif /* XPRINT */
+
+#else /* NOESCSEQ not defined from outside */
+
+#ifdef NOCSETS /* No character sets */
+#ifndef CK_APC /* No APC */
+#ifndef XPRINT /* No transparent printing */
+#define NOESCSEQ /* So no escape sequence recognizer */
+#endif /* XPRINT */
+#endif /* CK_APC */
+#endif /* NOCSETS */
+#endif /* NOESCSEQ */
+
+/* inesc[] and oldesc[] made global 2010/03/01 for INPUT command */
+
+static int escseq = 0; /* 1 = Recognizer is active */
+/* static */ int inesc[2] = { 0, 0 }; /* State of sequence recognizer */
+/* static */ int oldesc[2] = { -1, -1 }; /* Previous state of recognizer */
+
+#ifdef NOESCSEQ
+#define ES_NORMAL 0 /* Normal, not in an escape sequence */
+#define chkaes(x,y) 0
+#else
+/*
+ As of C-Kermit 5A(178), the CONNECT command skips past ANSI escape sequences
+ to avoid translating the characters within them. This allows the CONNECT
+ command to work correctly with a host that uses a 7-bit ISO 646 national
+ character set, in which characters like '[' would normally be converted to
+ accented letters, ruining the terminal's interpretation (and generation)
+ of escape sequences.
+
+ As of 5A(190), the CONNECT command responds to APC escape sequences
+ (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
+ program was built with CK_APC defined.
+
+ Non-ANSI/ISO-compliant escape sequences are not handled. */
+
+/* States for the escape-sequence recognizer. */
+
+#define ES_NORMAL 0 /* Normal, not in an escape sequence */
+#define ES_GOTESC 1 /* Current character is ESC */
+#define ES_ESCSEQ 2 /* Inside an escape sequence */
+#define ES_GOTCSI 3 /* Inside a control sequence */
+#define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */
+#define ES_TERMIN 5 /* 1st char of string terminator */
+
+/*
+ ANSI escape sequence handling. Only the 7-bit form is treated, because
+ translation is not a problem in the 8-bit environment, in which all GL
+ characters are ASCII and no translation takes place. So we don't check
+ for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
+ Here is the ANSI sequence recognizer state table, followed by the code
+ that implements it.
+
+ Definitions:
+ CAN = Cancel 01/08 Ctrl-X
+ SUB = Substitute 01/10 Ctrl-Z
+ DCS = Device Control Sequence 01/11 05/00 ESC P
+ CSI = Control Sequence Introducer 01/11 05/11 ESC [
+ ST = String Terminator 01/11 05/12 ESC \
+ OSC = Operating System Command 01/11 05/13 ESC ]
+ PM = Privacy Message 01/11 05/14 ESC ^
+ APC = Application Program Command 01/11 05/15 ESC _
+
+ ANSI escape sequence recognizer:
+
+ State Input New State ; Commentary
+
+ NORMAL (start) ; Start in NORMAL state
+
+ (any) CAN NORMAL ; ^X cancels
+ (any) SUB NORMAL ; ^Z cancels
+
+ NORMAL ESC GOTESC ; Begin escape sequence
+ NORMAL other ; NORMAL control or graphic character
+
+ GOTESC ESC ; Start again
+ GOTESC [ GOTCSI ; CSI
+ GOTESC P STRING ; DCS introducer, consume through ST
+ GOTESC ] STRING ; OSC introducer, consume through ST
+ GOTESC ^ STRING ; PM introducer, consume through ST
+ GOTESC _ STRING ; APC introducer, consume through ST
+ GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character
+ GOTESC other ESCSEQ ; Intermediate or ignored control character
+
+ ESCSEQ ESC GOTESC ; Start again
+ ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character
+ ESCSEQ other ; Intermediate or ignored control character
+
+ GOTCSI ESC GOTESC ; Start again
+ GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character
+ GOTCSI other ; Intermediate char or ignored control char
+
+ STRING ESC TERMIN ; Maybe have ST
+ STRING other ; Consume all else
+
+ TERMIN \ NORMAL ; End of string
+ TERMIN other STRING ; Still in string
+*/
+
+#ifdef XPRINT /* Transparent print support */
+/*
+ We can't just print each byte as it comes in because then the printer-off
+ sequence would be sent to the printer. Thus we have to buffer up escape
+ sequences and print them only when they are complete AND we know they are
+ not the printer-off sequence. All printing is done via zsoutx(ZMFILE,s,n).
+ This allows for strings that contain NULs. Don't mix calls to zsoutx() with
+ calls to zchout(), or the output will be scrambled. Also note that when
+ printing a saved-up escape sequence, we never print its final character
+ because that will be printed in the mainline code, upon return from
+ chkaes(). Note that the printer-on sequence is passed to the screen; this
+ is unavoidable, since we don't know what it is until after we get to the
+ end, and for screen display purposes we can't buffer up escape sequences
+ for numerous reasons. Therefore we also must output the printer-off
+ sequence, otherwise a real terminal or emulator will be stuck in print mode.
+*/
+extern int tt_print;
+#define ESCBUFLEN 63
+static char escbuf[ESCBUFLEN+1] = { NUL, NUL };
+static int escbufc = 0;
+static int dontprint = 0;
+
+VOID
+printon() { /* Turn printing on */
+ int x, pp;
+ char * p;
+ extern int printpipe, noprinter;
+ extern char * printername;
+
+ if (noprinter) {
+ debug(F110,"PRINTER ON NOPRINTER","",0);
+ return;
+ }
+ p = printername;
+ pp = printpipe;
+ if (!p) p = "";
+ if (!*p) {
+#ifdef ANYBSD
+ p = "lpr";
+#else
+ p = "lp";
+#endif /* ANYBSD */
+ pp = 1;
+ debug(F110,"PRINTER DEFAULT",p,0);
+ }
+ debug(F111,"PRINTER ON",p,pp);
+ if (pp) { /* Printing to pipe */
+ x = zxcmd(ZMFILE,p);
+ } else { /* Append to file */
+ struct filinfo xx;
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = NUL;
+ xx.lblopts = 0;
+ x = zopeno(ZMFILE,p,NULL,&xx);
+ }
+ debug(F101,"PRINTER OPEN","",x);
+ printing = 1;
+}
+
+VOID
+printoff() { /* Turn printing off */
+ int x;
+ extern int noprinter;
+ if (noprinter) {
+ printing = 0;
+ debug(F100,"PRINTER OFF NOPRINTER","",0);
+ return;
+ }
+ debug(F100,"PRINTER OFF","",0);
+ if (printing) {
+ x = zclose(ZMFILE);
+ debug(F101,"PRINTER CLOSE","",x);
+ printing = 0;
+ }
+}
+#endif /* XPRINT */
+
+/*
+ C H K A E S -- Check ANSI Escape Sequence.
+
+ Call with EACH character in input stream.
+ src = 0 means c is incoming from remote; 1 = char from keyboard.
+ Sets global inesc[src] variable according to escape sequence state.
+ Returns 0 normally, 1 if an APC sequence is to be executed.
+ Handles transparent printing internally.
+*/
+int
+#ifdef CK_ANSIC
+chkaes(char c, int src)
+#else
+chkaes(c,src) char c; int src;
+#endif /* CK_ANSIC */
+/* chkaes */ {
+
+ debug(F111,"chkaes entry inesc",ckitoa(src),inesc[src]);
+ debug(F101,"chkaes c","",c);
+
+ if (src < 0 || src > 1) /* Don't allow bad args. */
+ return(0);
+
+ oldesc[src] = inesc[src]; /* Remember previous state */
+
+#ifdef XPRINT
+ if (inesc[src] && !src) { /* Save up escape seq for printing */
+ if (!c) return(0); /* Ignore NULs */
+ if (escbufc < ESCBUFLEN) {
+ escbuf[escbufc++] = c;
+ escbuf[escbufc] = NUL;
+ debug(F111,"ESCBUF 1",escbuf,escbufc);
+ } else { /* Buffer overrun */
+ if (printing && escbufc) /* Print what's there so far */
+ zsoutx(ZMFILE,escbuf,escbufc);
+ escbufc = 1; /* clear it out */
+ escbuf[0] = c; /* and start off fresh buffer */
+ escbuf[1] = NUL; /* with this character. */
+ }
+ }
+#endif /* XPRINT */
+
+ if (c == CAN || c == SUB) { /* CAN and SUB cancel any sequence */
+#ifdef XPRINT
+ if (!src) {
+ if (printing && escbufc > 1)
+ zsoutx(ZMFILE,escbuf,escbufc-1);
+ escbufc = 0; /* Clear buffer */
+ escbuf[0] = NUL;
+ }
+#endif /* XPRINT */
+ inesc[src] = ES_NORMAL;
+ } else /* Otherwise */
+
+ switch (inesc[src]) { /* enter state switcher */
+ case ES_NORMAL: /* NORMAL state */
+ if (c == ESC) { /* Got an ESC */
+ inesc[src] = ES_GOTESC; /* Change state to GOTESC */
+#ifdef XPRINT
+ if (!src) {
+ escbufc = 1; /* Clear escape sequence buffer */
+ escbuf[0] = c; /* and deposit the ESC */
+ escbuf[1] = NUL;
+ debug(F111,"ESCBUF 2",escbuf,escbufc);
+ }
+#endif /* XPRINT */
+ }
+ break; /* Otherwise stay in NORMAL state */
+
+ case ES_GOTESC: /* GOTESC state - prev char was ESC*/
+ if (c == '[') { /* Left bracket after ESC is CSI */
+ inesc[src] = ES_GOTCSI; /* Change to GOTCSI state */
+ } else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, ], ^, or _ */
+ inesc[src] = ES_STRING; /* Switch to STRING-absorption state */
+#ifdef XPRINT
+ debug(F111,"ESCBUF STRING",escbuf,escbufc);
+#endif /* XPRINT */
+#ifdef CK_APC
+ /* If APC not disabled */
+ if (!src && c == '_' && (apcstatus & APC_ON)) {
+ debug(F100,"CONNECT APC begin","",0);
+ apcactive = APC_REMOTE; /* Set APC-Active flag */
+ apclength = 0; /* and reset APC buffer pointer */
+ }
+#endif /* CK_APC */
+ } else if (c > 057 && c < 0177) { /* Final character '0' thru '~' */
+ inesc[src] = ES_NORMAL; /* Back to normal */
+#ifdef XPRINT
+ if (!src) {
+ if (printing && escbufc > 1) {
+ /* Dump esc seq buf to printer */
+ zsoutx(ZMFILE,escbuf,escbufc-1);
+ debug(F111,"ESCBUF PRINT 1",escbuf,escbufc);
+ }
+
+ escbufc = 0; /* Clear parameter buffer */
+ escbuf[0] = NUL;
+ }
+#endif /* XPRINT */
+ } else if (c != ESC) { /* ESC in an escape sequence... */
+ inesc[src] = ES_ESCSEQ; /* starts a new escape sequence */
+ }
+ break; /* Intermediate or ignored ctrl char */
+
+ case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */
+ if (c > 057 && c < 0177) { /* Final character '0' thru '~' */
+ inesc[src] = ES_NORMAL; /* Return to NORMAL state. */
+#ifdef XPRINT
+ if (!src) {
+ if (printing && escbufc > 1) {
+ zsoutx(ZMFILE,escbuf,escbufc-1);
+ debug(F111,"ESCBUF PRINT 2",escbuf,escbufc);
+ }
+ escbufc = 0; /* Clear escseq buffer */
+ escbuf[0] = NUL;
+ }
+#endif /* XPRINT */
+ } else if (c == ESC) { /* ESC ... */
+ inesc[src] = ES_GOTESC; /* starts a new escape sequence */
+ }
+ break; /* Intermediate or ignored ctrl char */
+
+ case ES_GOTCSI: /* GOTCSI -- In a control sequence */
+ if (c > 077 && c < 0177) { /* Final character '@' thru '~' */
+#ifdef XPRINT
+ if (!src && tt_print) { /* Printer enabled? */
+ if (c == 'i') { /* Final char is "i"? */
+ char * p = (char *) (escbuf + escbufc - 4);
+ if (!strncmp(p, "\033[5i", 4)) { /* Turn printer on */
+ printon();
+ } else if (!strncmp(p, "\033[4i", 4)) { /* Or off... */
+ int i;
+ printoff(); /* Turn off printer. */
+ dontprint = 1;
+ for (i = 0; i < escbufc; i++) /* And output the */
+ ckcputc(escbuf[i]); /* sequence. */
+ } else if (printing && escbufc > 1) {
+ zsoutx(ZMFILE,escbuf,escbufc-1);
+ debug(F011,"ESCBUF PRINT 3",escbuf,escbufc);
+ }
+ } else if (printing && escbufc > 1) {
+ zsoutx(ZMFILE,escbuf,escbufc-1);
+ debug(F111,"ESCBUF PRINT 4",escbuf,escbufc);
+ }
+ }
+ if (!src) {
+ escbufc = 0; /* Clear esc sequence buffer */
+ escbuf[0] = NUL;
+ }
+#endif /* XPRINT */
+ inesc[src] = ES_NORMAL; /* Return to NORMAL. */
+ } else if (c == ESC) { /* ESC ... */
+ inesc[src] = ES_GOTESC; /* starts over. */
+ }
+ break;
+
+ case ES_STRING: /* Inside a string */
+ if (c == ESC) /* ESC may be 1st char of terminator */
+ inesc[src] = ES_TERMIN; /* Go see. */
+#ifdef CK_APC
+ else if (apcactive) { /* If in APC */
+ if (apclength < apcbuflen) { /* and there is room... */
+ apcbuf[apclength++] = c; /* deposit this character. */
+ } else { /* Buffer overrun */
+ apcactive = 0; /* Discard what we got */
+ apclength = 0; /* and go back to normal */
+ apcbuf[0] = 0; /* Not pretty, but what else */
+ inesc[src] = ES_NORMAL; /* can we do? (ST might not come) */
+ }
+ }
+#endif /* CK_APC */
+ break; /* Absorb all other characters. */
+
+ case ES_TERMIN: /* Maybe a string terminator */
+ if (c == '\\') { /* which must be backslash */
+ inesc[src] = ES_NORMAL; /* If so, back to NORMAL */
+#ifdef XPRINT
+ if (!src) {
+ if (printing && escbufc > 1) { /* If printing... */
+ /* Print esc seq buffer */
+ zsoutx(ZMFILE,escbuf,escbufc-1);
+ debug(F111,"ESCBUF PRINT 5",escbuf,escbufc);
+ }
+ escbufc = 0; /* Clear escseq buffer */
+ escbuf[0] = NUL;
+ }
+#endif /* XPRINT */
+#ifdef CK_APC
+ if (!src && apcactive) { /* If it was an APC string, */
+ debug(F101,"CONNECT APC terminated","",c);
+ apcbuf[apclength] = NUL; /* terminate it and then ... */
+ return(1);
+ }
+#endif /* CK_APC */
+ } else { /* It's not a backslash so... */
+ inesc[src] = ES_STRING; /* back to string absorption. */
+#ifdef CK_APC
+ if (apcactive) { /* In APC string */
+ if (apclength+1 < apcbuflen) { /* If enough room */
+ apcbuf[apclength++] = ESC; /* deposit the Esc */
+ apcbuf[apclength++] = c; /* and this character too. */
+ } else { /* Buffer overrun */
+ apcactive = 0;
+ apclength = 0;
+ apcbuf[0] = 0;
+ inesc[src] = ES_NORMAL;
+ }
+ }
+#endif /* CK_APC */
+ }
+ } /* switch() */
+ debug(F111,"chkaes exit inesc",ckitoa(src),inesc[src]);
+ return(0);
+}
+#endif /* NOESCSEQ */
+
+VOID
+#ifdef CK_ANSIC
+LOGCHAR(char c)
+#else
+LOGCHAR(c) char c;
+#endif /* CK_ANSIC */
+/* LOGCHAR */ { /* Log character c to session log */
+ /* but skip over escape sequences if session log is text */
+ if (escseq) {
+ if ((sessft == XYFT_T) && (debses == 0) &&
+ (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL))
+ return;
+ }
+ logchar(c);
+}
+
+/* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
+/*
+ Output is buffered to avoid slow screen writes on fast connections.
+*/
+static int
+ckcputf() { /* Dump the console output buffer */
+ int x = 0;
+ if (obc > 0) /* If we have any characters, */
+ x = conxo(obc,obuf); /* dump them, */
+ obp = obuf; /* reset the pointer */
+ obc = 0; /* and the counter. */
+ return(x); /* Return conxo's return code */
+}
+
+/*
+ NOTE: This is probably the right place for character-set translation,
+ rather than down below in the mainline code. ckcputc() would act like
+ xpnbyte() in ckcfns.c, and ckcgetc() would act like xgnbyte(). This
+ would shield the rest of the code from all the complexities of many-to-one
+ and one-to-many conversions, and would allow handling of Kanji and other
+ CJK sets along with UTF-8 and the rest.
+*/
+int
+ckcputc(c) int c; {
+ int x;
+
+ *obp++ = c & 0xff; /* Deposit the character */
+ obc++; /* Count it */
+ if (ibc == 0 || /* If input buffer about empty */
+ obc == OBUFL) { /* or output buffer full */
+ debug(F101,"CONNECT CKCPUTC obc","",obc);
+ x = conxo(obc,obuf); /* dump the buffer, */
+ obp = obuf; /* reset the pointer */
+ obc = 0; /* and the counter. */
+ return(x); /* Return conxo's return code */
+ } else return(0);
+}
+
+/* C K C G E T C -- C-Kermit CONNECT Get Character */
+/*
+ Buffered read from communication device.
+ Returns the next character, refilling the buffer if necessary.
+ On error, returns ttinc's return code (see ttinc() description).
+ Dummy argument for compatible calling conventions with ttinc()
+ so a pointer to this function can be passed to tn_doop().
+*/
+int
+ckcgetc(dummy) int dummy; {
+ int c, n;
+#ifdef CK_SSL
+ extern int ssl_active_flag, tls_active_flag;
+#endif /* CK_SSL */
+
+#ifdef CK_ENCRYPTION
+ /* No buffering for possibly encrypted connections */
+ if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
+ return(ttinc(0));
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag)
+ return(ttinc(0));
+#endif /* CK_SSL */
+
+ if (ibc < 1) { /* Need to refill buffer? */
+ ibc = 0; /* Yes, reset count */
+ ibp = ibuf; /* and buffer pointer */
+ c = ttinc(0); /* Read one character, blocking */
+ if (c < 0) { /* If error, return error code */
+ return(c);
+ } else { /* Otherwise, got one character */
+ *ibp++ = c; /* Advance buffer pointer */
+ ibc++; /* and count. */
+ }
+ if ((n = ttchk()) > 0) { /* Any more waiting? */
+ if (n > (IBUFL - ibc)) /* Get them all at once. */
+ n = IBUFL - ibc; /* Don't overflow buffer */
+ if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
+ ibc += n; /* Advance counter */
+ }
+ } else if (n < 0) { /* Error? */
+ return(n); /* Return the error code */
+ }
+ ibp = ibuf; /* Point to beginning of buffer */
+ }
+ c = *ibp++ & 0xff; /* Get next character from buffer */
+ ibc--; /* Reduce buffer count */
+ /* debug(F000,"CKCGETC","",c); */
+ return(c); /* Return the character */
+}
+
+/*
+ Keyboard handling, buffered for speed, which is needed when C-Kermit is
+ in CONNECT mode between two other computers that are transferring data.
+*/
+static char *kbp; /* Keyboard input buffer pointer */
+static int kbc; /* Keyboard input buffer count */
+
+#ifdef CK_SMALL /* Keyboard input buffer length */
+#define KBUFL 32 /* Small for PDP-11 UNIX */
+#else
+#define KBUFL 257 /* Regular kernel size for others */
+#endif /* CK_SMALL */
+
+#ifdef DYNAMIC
+static char *kbuf = NULL;
+#else
+static char kbuf[KBUFL];
+#endif /* DYNAMIC */
+
+/* Macro for reading keystrokes. */
+
+#define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
+
+/*
+ Note that we call read() directly here, normally a no-no, but in this case
+ we know it's UNIX and we're only doing what coninc(0) would have done,
+ except we're reading a block of characters rather than just one. There is,
+ at present, no conxin() analog to ttxin() for chunk reads, and instituting
+ one would only add function-call overhead as it would only be a wrapper for
+ a read() call anyway.
+
+ Another note: We stick in this read() till the user types something.
+ But we know they already did, since select() said so. Therefore something
+ would need to be mighty wrong before we get stuck here.
+*/
+static int /* Keyboard buffer filler */
+kbget() {
+#ifdef EINTR
+ int tries = 10; /* If read() is interrupted, */
+ int ok = 0;
+ while (tries-- > 0) { /* try a few times... */
+#endif /* EINTR */
+ kbc = conchk(); /* How many chars waiting? */
+ debug(F101,"kbget kbc","",kbc);
+ if (kbc < 1)
+ kbc = 1; /* If none or dunno, wait for one. */
+ else if (kbc > KBUFL) /* If too many, */
+ kbc = KBUFL; /* only read this many. */
+ if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */
+ debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */
+#ifdef EINTR
+ if (errno == EINTR) /* Interrupted system call. */
+ continue; /* Try again, up to limit. */
+ else /* Something else. */
+#endif /* EINTR */
+ return(-1); /* Pass along read() error. */
+ }
+#ifdef EINTR
+ else { ok = 1; break; }
+ }
+ if (!ok) return(-1);
+#endif /* EINTR */
+ kbp = kbuf; /* Adjust buffer pointer, */
+ kbc--; /* count, */
+ return((int)(*kbp++) & 0377); /* and return first character. */
+}
+
+#ifdef BEBOX
+/*
+ * CreateSocketPair --
+ *
+ * This procedure creates a connected socket pair
+ *
+ * Results:
+ * 0 if OK, the error if not OK.
+ *
+ * Side effects:
+ * None
+ */
+int
+socketpair(int *pair) {
+ int servsock;
+ int val;
+ struct sockaddr_in serv_addr, cli_addr;
+ extern char myipaddr[];
+
+ debug(F110,"socketpair",myipaddr,0);
+
+ if (myipaddr[0] == 0)
+ getlocalipaddr();
+
+ servsock = socket(AF_INET, SOCK_STREAM, 0);
+ if (servsock == 0) {
+ return h_errno;
+ }
+ debug(F111,"socketpair","socket",servsock);
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(0);
+
+ val = sizeof(serv_addr);
+ if (bind(servsock, (struct sockaddr *) &serv_addr, val) < 0) {
+ closesocket(servsock);
+ return h_errno;
+ }
+ debug(F111,"socketpair","bind",0);
+
+ listen(servsock, 1);
+ debug(F111,"socketpair","listen",0);
+
+ if (getsockname(servsock, (struct sockaddr *) &serv_addr, &val) < 0) {
+ closesocket(servsock);
+ return h_errno;
+ }
+ debug(F111,"socketpair","getsockname",0);
+
+ pair[0] = socket(AF_INET, SOCK_STREAM, 0);
+ if (pair[0] == 0) {
+ closesocket(servsock);
+ return h_errno;
+ }
+ debug(F111,"socketpair","socket",pair[0]);
+
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ cli_addr.sin_family = AF_INET;
+ cli_addr.sin_addr.s_addr = inet_addr(myipaddr[0]?myipaddr:"127.0.0.1");
+ cli_addr.sin_port = serv_addr.sin_port;
+
+ if (connect(pair[0],(struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
+ closesocket(pair[0]);
+ closesocket(servsock);
+ return h_errno;
+ }
+ debug(F111,"socketpair","connect",0);
+
+ pair[1] = accept(servsock, (struct sockaddr *) &serv_addr, &val);
+ if (pair[1] == 0) {
+ closesocket(pair[0]);
+ closesocket(servsock);
+ return h_errno;
+ }
+ debug(F111,"socketpair","accept",pair[1]);
+
+ closesocket(servsock);
+ debug(F111,"socketpair","closesocket",0);
+ return 0;
+}
+
+long
+kbdread(void * param) {
+ int sock = (int) param;
+ char ch;
+ int rc = 0;
+
+ debug(F111,"kbdread","sock",sock);
+
+ while (rc >= 0) {
+ rc = read(fileno(stdin), &ch, 1); /* Read a character. */
+ if (rc > 0) {
+ rc = send(sock,&ch,1,0);
+ /* debug(F000,"kbdread","send()",ch); */
+ printf("\r\ngot: %c rc = %d\r\n",ch,rc);
+ } else
+ msleep(100);
+ }
+ debug(F110,"kbdread","terminating",0);
+ return(rc);
+}
+#endif /* BEBOX */
+
+#ifdef CKLEARN
+static VOID
+learnchar(c) int c; { /* Learned script keyboard character */
+ int cc;
+ char xbuf[8];
+
+ if (!learning || !learnfp)
+ return;
+
+ switch (learnst) { /* Learn state... */
+ case 0: /* Neutral */
+ case 1: /* Net */
+ if (learnbc > 0) { /* Have net characters? */
+ char buf[LEARNBUFSIZ];
+ int i, j, n;
+ ULONG t;
+
+ t = (ULONG) time(0); /* Calculate INPUT timeout */
+ j = t - learnt1;
+ j += (j / 4) > 0 ? (j / 4) : 1; /* Add some slop */
+ if (j < 2) j = 2; /* 2 seconds minimum */
+
+ fputs("\nINPUT ",learnfp); /* Give INPUT command for them */
+ fputs(ckitoa(j),learnfp);
+ fputs(" {",learnfp);
+ learnt1 = t;
+
+ n = LEARNBUFSIZ;
+ if (learnbc < LEARNBUFSIZ) { /* Circular buffer */
+ n = learnbc; /* hasn't wrapped yet. */
+ learnbp = 0;
+ }
+ j = 0; /* Copy to linear buffer */
+ for (i = 0; i < n; i++) { /* Number of chars in circular buf */
+
+ cc = learnbuf[(learnbp + i) % LEARNBUFSIZ];
+
+ /* Later account for prompts that end with a newline? */
+
+ if (cc == CR && j > 0) {
+ if (buf[j-1] != LF)
+ j = 0;
+ }
+ buf[j++] = cc;
+ }
+ for (i = 0; i < j; i++) { /* Now copy out the buffer */
+ cc = buf[i]; /* interpreting control chars */
+ if (cc == 0) { /* We don't INPUT NULs */
+ continue;
+ } else if (cc < SP || /* Controls need quoting */
+ (cc > 126 && cc < 160)) {
+ ckmakmsg(xbuf,8,"\\{",ckitoa((int)cc),"}",NULL);
+ fputs(xbuf,learnfp);
+ } else { /* Plain character */
+ putc(cc,learnfp);
+ }
+ }
+ fputs("}\nIF FAIL STOP 1 INPUT timeout",learnfp);
+ learnbc = 0;
+ }
+ learnbp = 0;
+ fputs("\nPAUSE 1\nOUTPUT ",learnfp); /* Emit OUTPUT and fall thru */
+
+ case 2: /* Already in Keyboard state */
+ if (c == 0) {
+ fputs("\\N",learnfp);
+ } else if (c == -7) {
+ fputs("\\B",learnfp);
+ } else if (c == -8) {
+ fputs("\\L",learnfp);
+ } else if (c < SP || (c > 126 && c < 160)) {
+ ckmakmsg(xbuf,8,"\\{",ckitoa((int)c),"}",NULL);
+ fputs(xbuf,learnfp);
+ } else {
+ putc(c,learnfp);
+ }
+ }
+}
+#endif /* CKLEARN */
+
+static int printbar = 0;
+
+#define OUTXBUFSIZ 15
+static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */
+static int inxcount = 0; /* and count */
+static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */
+static int outxcount = 0; /* and count */
+
+int
+conect() {
+ int rc = 0; /* Return code: 0 = fail, 1 = OK */
+ int i, x = 0, prev = -1; /* Reason code in cx_status */
+#ifdef CKLEARN
+ int crflag = 0;
+#endif /* CKLEARN */
+ register int c = -1, c2, csave; /* Characters */
+#ifdef TNCODE
+ int tx; /* For Telnet negotiations */
+#endif /* TNCODE */
+ int apcrc = 0; /* For APC and transparent print */
+ int n, kbin, scrnout; /* select() items... */
+ fd_set in, out, err; /* File descriptor sets */
+ int gotnet = 0; /* Flag for net ready to read */
+ int gotkbd = 0; /* Flag for keyboard ready to read */
+ int oldprt = 0; /* Used with printing */
+ int msgflg = 0;
+ char cbuf[2]; /* Ditto */
+
+#ifdef BEBOX
+ int tid = 0; /* Thread ID */
+ int pair[2]; /* Socket Pair */
+ CHAR ch;
+ CHAR buf[64];
+#endif /* BEBOX */
+
+ cx_status = CSX_INTERNAL;
+ debok = 1;
+
+#ifdef BEBOX
+ {
+ /* Create a socket pair to be used for the keyboard input */
+ if (socketpair(pair)) {
+ debug(F110,"conect","unable to create socket pair",0);
+ return(-1);
+ }
+ debug(F111,"connect","socket pair[0]",pair[0]);
+ debug(F111,"connect","socket pair[1]",pair[1]);
+
+ /* Assign one end of the socket to kbin */
+ kbin = pair[0];
+ tid = spawn_thread(kbdread,
+ "Kbd to Socket Pair",
+ B_NORMAL_PRIORITY,
+ (void *)pair[1]
+ );
+ resume_thread(tid);
+ debug(F110,"connect","tid",tid);
+ }
+#else /* BEBOX */
+ kbin = fileno(stdin); /* stdin file descriptor */
+#endif /* BEBOX */
+
+ scrnout = fileno(stdout); /* stdout file descriptor */
+
+#ifdef CK_TRIGGER
+ makestr(&triggerval,NULL); /* Reset trigger */
+#endif /* CK_TRIGGER */
+
+#ifdef XPRINT
+ escbufc = 0; /* Reset esc-sequence buffer */
+ escbuf[0] = NUL;
+#endif /* XPRINT */
+ cbuf[1] = NUL;
+
+ ttimoff(); /* Turn off any timer interrupts */
+ if (!local) { /* Be sure we're not in remote mode */
+#ifdef NETCONN
+#ifdef NEWFTP
+ if (ftpisconnected())
+ printf("Sorry, you can't CONNECT to an FTP server\n");
+ else
+#endif /* NEWFTP */
+ printf("Sorry, you must SET LINE or SET HOST first\n");
+#else
+ printf("Sorry, you must SET LINE first\n");
+#endif /* NETCONN */
+ return(0);
+ }
+ if (speed < 0L && network == 0 && ttfdflg == 0) {
+ printf("Sorry, you must SET SPEED first\n");
+ return(0);
+ }
+#ifdef TCPSOCKET
+ if (network && !ttpipe && (nettype != NET_TCPB && nettype != NET_PTY)) {
+ printf("Sorry, network type not supported\n");
+ return(0);
+ }
+#endif /* TCPSOCKET */
+
+#ifdef DYNAMIC
+ if (!ibuf) {
+ if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
+ printf("Sorry, CONNECT input buffer can't be allocated\n");
+ return(0);
+ } else {
+ ibp = ibuf;
+ ibc = 0;
+ }
+ }
+ if (!obuf) {
+ if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
+ printf("Sorry, CONNECT output buffer can't be allocated\n");
+ return(0);
+ } else {
+ obp = obuf;
+ obc = 0;
+ }
+ }
+ if (!kbuf) {
+ if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
+ printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
+ return(0);
+ }
+ }
+ if (!temp) {
+ if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
+ printf("Sorry, CONNECT temporary buffer can't be allocated\n");
+ return(0);
+ }
+ }
+#else
+ obp = obuf;
+ obc = 0;
+#endif /* DYNAMIC */
+
+ kbp = kbuf; /* Always clear these. */
+ *kbp = NUL; /* No need to preserve them between */
+ kbc = 0; /* CONNECT sessions. */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
+ debug(F101,"CONNECT conect entry ibc","",ibc);
+ debug(F101,"CONNECT conect entry obc","",obc);
+ debug(F101,"CONNECT conect entry kbc","",kbc);
+#ifdef CK_TRIGGER
+ debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
+#endif /* CK_TRIGGER */
+ if (ttyfd > -1) {
+ n = ttchk();
+ debug(F101,"CONNECT conect entry ttchk","",n);
+ }
+ }
+#endif /* DEBUG */
+
+ if (ttyfd < 0) { /* If communication device not open */
+#ifdef TTLEBUF
+ int n = le_inbuf();
+ debug(F111,"CONNECT le_inbuf()","ttyfd < 0",n);
+ if (n > 0) {
+ while (n--) {
+ CHAR ch;
+ le_getchar(&ch);
+ conoc(ch);
+ }
+ return(0);
+ }
+#endif /* TTLEBUF */
+
+ debug(F101,"CONNECT ttnproto","",ttnproto);
+ debug(F111,"CONNECT opening",ttname,0); /* Open it now */
+ if (ttopen(ttname,
+ &local,
+ network ? -nettype : mdmtyp,
+ 0
+ ) < 0) {
+ ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
+ perror(temp);
+ debug(F110,"CONNECT open failure",ttname,0);
+ return(0);
+ }
+
+#ifdef IKS_OPTION
+ /* If peer is in Kermit server mode, return now. */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ cx_status = CSX_IKSD;
+ return(0);
+ }
+#endif /* IKS_OPTION */
+ }
+ dohangup = 0; /* Hangup not requested yet */
+
+ msgflg = !quiet
+#ifdef CK_APC
+ && !apcactive
+#endif /* CK_APC */
+ ;
+
+ if (msgflg) {
+#ifdef NETCONN
+ if (network) {
+#ifdef CK_ENCRYPTION
+ extern int me_encrypt, u_encrypt;
+ if (ck_tn_encrypting() && ck_tn_decrypting())
+ printf("SECURE connection to host %s",ttname);
+ else
+#endif /* CK_ENCRYPTION */
+ if (ttpipe || ttpty)
+ printf("Connecting via command \"%s\"",ttname);
+ else
+ printf("Connecting to host %s",ttname);
+ } else {
+#endif /* NETCONN */
+ printf("Connecting to %s",ttname);
+ if (speed > -1L) printf(", speed %ld",speed);
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+ if (tt_escape) {
+ printf("\r\n");
+ shoesc(escape);
+ printf("Type the escape character followed by C to get back,\r\n");
+ printf("or followed by ? to see other options.\r\n");
+ } else {
+ printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
+ }
+ if (seslog) {
+ extern int slogts;
+ char * s = "";
+ switch (sessft) {
+ case XYFT_D:
+ s = "debug"; break;
+ case XYFT_T:
+ s = slogts ? "timestamped-text" : "text"; break;
+ default:
+ s = "binary";
+ }
+ printf("Session Log: %s, %s (%d) \r\n",sesfil,s,sessft);
+ }
+ if (debses) printf("Debugging Display...)\r\n");
+ }
+
+/* Condition console terminal and communication line */
+
+ if (conbin((char)escape) < 0) {
+ printf("Sorry, can't condition console terminal\n");
+ fflush(stdout);
+ return(0);
+ }
+ debug(F101,"CONNECT cmask","",cmask);
+ debug(F101,"CONNECT cmdmsk","",cmdmsk);
+ debug(F101,"CONNECT speed before ttvt","",speed);
+ if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */
+ if (!network) {
+ debug(F101,"CONNECT ttvt","",n);
+ tthang(); /* Hang up and close the device. */
+ ttclos(0);
+ dologend();
+ if (ttopen(ttname, /* Open it again... */
+ &local,
+ network ? -nettype : mdmtyp,
+ 0
+ ) < 0) {
+ cx_status = CSX_INTERNAL;
+ ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
+ perror(temp);
+ return(0);
+ }
+#ifdef IKS_OPTION
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
+ cx_status = CSX_IKSD;
+ return(0);
+ }
+#endif /* IKS_OPTION */
+
+ if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
+ conres(); /* Failure this time is fatal. */
+ printf("Sorry, Can't condition communication line\n");
+ cx_status = CSX_INTERNAL;
+ return(0);
+ }
+ }
+ }
+ debug(F101,"CONNECT ttvt ok, escape","",escape);
+
+ /* Despite ttvt() this is still needed in HP-UX */
+ /* because of the HP-9000 <RESET> key.*/
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+
+ debug(F101,"CONNECT carrier-watch","",carrier);
+ if ((!network
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) && (carrier != CAR_OFF)) {
+ int x;
+ x = ttgmdm();
+ debug(F100,"CONNECT ttgmdm","",x);
+ if ((x > -1) && !(x & BM_DCD)) {
+#ifndef NOHINTS
+ extern int hints;
+#endif /* NOHINTS */
+ debug(F100,"CONNECT ttgmdm CD test fails","",x);
+ conres();
+ printf("?Carrier required but not detected.\n");
+#ifndef NOHINTS
+ cx_status = CSX_CARRIER;
+ if (!hints)
+ return(0);
+ printf("***********************************\n");
+ printf(" Hint: To CONNECT to a serial device that\n");
+ printf(" is not presenting the Carrier Detect signal,\n");
+ printf(" first tell C-Kermit to:\n\n");
+ printf(" SET CARRIER-WATCH OFF\n\n");
+ printf("***********************************\n\n");
+#endif /* NOHINTS */
+ return(0);
+ }
+ debug(F100,"CONNECT ttgmdm ok","",0);
+ }
+
+ /* Now we are connected. */
+
+ if (msgflg || printbar)
+ printf("----------------------------------------------------\r\n");
+ fflush(stdout);
+
+#ifndef NOCSETS
+/* Set up character set translations */
+
+ unicode = 0; /* Assume Unicode won't be involved */
+ tcs = 0; /* "Transfer" or "Other" charset */
+ sxo = rxo = NULL; /* Initialize byte-to-byte functions */
+ sxi = rxi = NULL;
+
+ if (tcsr != tcsl) { /* Remote and local sets differ... */
+#ifdef UNICODE
+ if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */
+ tcsl == FC_UTF8) { /* or local one is. */
+ xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */
+ if (xuf || tcsl == FC_UTF8) {
+ tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
+ xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */
+ if (xfu)
+ unicode = (tcsr == FC_UTF8) ? 1 : 2;
+ }
+ tcssize = fcsinfo[tcs].size; /* Size of other character set. */
+ } else {
+#endif /* UNICODE */
+ tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
+ sxo = xls[tcs][tcsl]; /* translation function */
+ rxo = xlr[tcs][tcsr]; /* pointers for output functions */
+ sxi = xls[tcs][tcsr]; /* and for input functions. */
+ rxi = xlr[tcs][tcsl];
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ }
+/*
+ This is to prevent use of zmstuff() and zdstuff() by translation functions.
+ They only work with disk i/o, not with communication i/o. Luckily Russian
+ translation functions don't do any stuffing...
+*/
+ langsv = language;
+#ifndef NOCYRIL
+ if (language != L_RUSSIAN)
+#endif /* NOCYRIL */
+ language = L_USASCII;
+
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"CONNECT tcs","",tcs);
+ debug(F101,"CONNECT tcsl","",tcsl);
+ debug(F101,"CONNECT tcsr","",tcsr);
+ debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
+ debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
+ debug(F101,"CONNECT unicode","",unicode);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+
+#ifdef CK_XYZ
+#ifndef XYZ_INTERNAL
+ {
+ extern int binary; /* See about ZMODEM autodownloads */
+ char * s;
+ s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
+ if (!s) s = "";
+ zmdlok = (*s != NUL); /* OK if we have external commands */
+ }
+#endif /* XYZ_INTERNAL */
+#endif /* CK_XYZ */
+
+#ifndef NOESCSEQ
+/*
+ We need to activate the escape-sequence recognition feature when:
+ (a) translation is elected, AND
+ (b) the local and/or remote set is a 7-bit set other than US ASCII;
+ Or:
+ SET SESSION-LOG is TEXT (so we can strip escape sequences out of the log);
+ Or:
+ SET TERMINAL APC is not OFF (handled in the next statement).
+*/
+ escseq = (tcs != TC_TRANSP) && /* Not transparent */
+ (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
+ (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
+#endif /* NOESCSEQ */
+#endif /* NOCSETS */
+
+#ifndef NOESCSEQ
+ if (!escseq) { /* 2009/10/22 */
+ if (seslog && !sessft)
+ escseq = 1;
+ }
+#ifdef CK_APC
+ escseq = escseq || (apcstatus & APC_ON);
+ apcactive = 0; /* An APC command is not active */
+ apclength = 0; /* ... */
+#endif /* CK_APC */
+#ifdef XPRINT
+ escseq |= tt_print;
+#endif /* XPRINT */
+ /* Initial state of recognizer */
+ inesc[0] = ES_NORMAL; /* Remote to screen */
+ inesc[1] = ES_NORMAL; /* Keyboard to remote */
+ debug(F101,"CONNECT escseq","",escseq);
+#endif /* NOESCSEQ */
+
+ if (ttyfd > -1) { /* (just in case...) */
+ what = W_CONNECT; /* Keep track of what we're doing */
+ active = 1;
+ }
+#ifdef CKLEARN
+ if (learning) { /* Learned script active... */
+ learnbp = 0; /* INPUT buffer pointer */
+ learnbc = 0; /* INPUT buffer count */
+ learnst = 0; /* State (0 = neutral, none) */
+ learnt1 = (ULONG) time(0);
+ }
+#endif /* CKLEARN */
+
+#ifdef CKTIDLE
+ idlelimit = tt_idlelimit;
+#endif /* CKTIDLE */
+
+ while (active) { /* Big loop... */
+ debug(F100,"CONNECT top of loop","",0);
+ FD_ZERO(&in); /* Clear select() structs */
+ FD_ZERO(&out);
+ FD_ZERO(&err);
+ gotkbd = 0;
+ gotnet = ttpeek(); /* Something sitting in ckutio buf */
+ debug(F101,"CONNECT ttpeek","",gotnet);
+
+ if (
+#ifndef NOSETKEY
+ !kmptr /* Check for key macro active */
+#else
+ 1
+#endif /* NOSETKEY */
+ ) {
+ if (obc) { /* No key macro - set up for select */
+ FD_SET(ttyfd, &out); /* Have stuff to send to net */
+ } else {
+ FD_SET(kbin, &in); /* Need to read stuff from keyboard */
+ }
+#ifdef BEBOX
+ if (!(ibc || gotnet > 0))
+ FD_SET(ttyfd, &in); /* Need to read stuff from net */
+#else /* BEBOX */
+ if (ibc || gotnet > 0) {
+ FD_SET(scrnout, &out); /* Have stuff to put on screen */
+ } else {
+ FD_SET(ttyfd, &in); /* Need to read stuff from net */
+ }
+#endif /* BEBOX */
+ FD_SET(ttyfd, &err);
+#ifdef CK_FORWARD_X
+ fwdx_init_fd_set(&in);
+#endif /* CK_FORWARD_X */
+
+ /* Wait till the first one of the above is ready for i/o */
+ /* or TERM IDLE-SEND is active and we time out. */
+
+ errno = 0;
+#ifdef CKTIDLE
+ /* This really could be moved out of the loop... */
+ if (idlelimit) { /* Idle timeout set */
+ struct timeval tv;
+ if (idlelimit > 0) { /* Positive = sec */
+ tv.tv_sec = (long) idlelimit;
+ tv.tv_usec = 0L;
+ } else { /* Negative = millisec */
+ long u = (0 - idlelimit);
+ tv.tv_sec = u / 1000L;
+ tv.tv_usec = ((u % 1000L) * 1000L);
+ }
+#ifdef INTSELECT
+ c = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err, &tv);
+#else
+ c = select(FD_SETSIZE, &in, &out, &err, &tv);
+#endif /* INTSELECT */
+ } else
+#endif /* CKTIDLE */
+#ifdef INTSELECT
+ c = select(FD_SETSIZE, (int *)&in, (int *)&out, (int *)&err, 0);
+#else
+ c = select(FD_SETSIZE, &in, &out, &err, 0);
+#endif /* INTSELECT */
+ if (c < 1) {
+#ifdef CKTIDLE
+ if (c == 0) { /* Timeout */
+ debug(F101,"CONNECT select() timeout","",tt_idleact);
+ switch (tt_idleact) {
+ case IDLE_HANG: { /* Hang up */
+ int x = 0;
+#ifndef NODIAL
+ if (dialmhu)
+ x = mdmhup();
+ if (x < 1)
+#endif /* NODIAL */
+ tthang(); /* fall thru deliberately... */
+ }
+ case IDLE_RET: /* Return to command mode */
+ cx_status = CSX_IDLE;
+ active = 0;
+ continue;
+ case IDLE_OUT: /* OUTPUT a string */
+ if (tt_idlestr) {
+ int len = strlen(tt_idlestr);
+ if (len > 0)
+ ttol((CHAR *)tt_idlestr,len);
+ else
+ ttoc(NUL); /* No string, send a NUL */
+ } else
+ ttoc(NUL); /* No string, send a NUL */
+ continue;
+ case IDLE_EXIT: /* Exit from Kermit */
+ doexit(GOOD_EXIT,xitsta);
+#ifdef TNCODE
+ case IDLE_TAYT: /* Send Telnet Are You There? */
+ if (network && IS_TELNET()) {
+ tnopt[0] = (CHAR) IAC;
+ tnopt[1] = (CHAR) TN_AYT;
+ tnopt[2] = NUL;
+ if (ttol((CHAR *)tnopt,2) < 0)
+ active = 0;
+ }
+ continue;
+
+ case IDLE_TNOP: /* Send Telnet NOP */
+ if (network && IS_TELNET()) {
+ tnopt[0] = (CHAR) IAC;
+ tnopt[1] = (CHAR) TN_NOP;
+ tnopt[2] = NUL;
+ if (ttol((CHAR *)tnopt,2) < 0)
+ active = 0;
+ }
+ continue;
+#endif /* TNCODE */
+ }
+ }
+#endif /* CKTIDLE */
+
+ debug(F101,"CONNECT select() errno","",errno);
+ /* A too-big first arg to select() gets EBADF */
+#ifdef EINTR
+ if (c == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ }
+#endif /* EINTR */
+ sleep(1);
+ continue;
+ }
+#ifndef BEBOX
+#ifdef DEBUG
+ if (FD_ISSET(scrnout, &out)) {
+ debug(F100,"CONNECT SELECT scrnout","",0);
+ }
+#endif /* DEBUG */
+#endif /* BEBOX */
+
+#ifdef CK_FORWARD_X
+ fwdx_check_sockets(&in);
+#endif /* CK_FORWARD_X */
+
+ if (FD_ISSET(ttyfd, &in)) { /* Read from net? */
+ debug(F110,"CONNECT SELECT ttyfd","in",0);
+ FD_CLR(ttyfd, &in);
+ gotnet = 1; /* Net is ready */
+ }
+ if (FD_ISSET(kbin, &in)) { /* Read from keyboard? */
+ debug(F100,"CONNECT SELECT kbin","",0);
+ FD_CLR(kbin, &in);
+ gotkbd = 1; /* Keyboard is ready */
+ }
+ if (FD_ISSET(ttyfd, &err)) {
+ debug(F110,"CONNECT SELECT ttyfd","err",0);
+ FD_CLR(ttyfd, &err);
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* Special handling for HP-UX pty i/o */
+ if (ttpty) {
+ if (pty_trap_handler(ttyfd) > 0) {
+ ttclos(0);
+ goto conret1;
+ }
+ continue;
+ }
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+ gotnet = 1; /* Net is ready (don't set if pty) */
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"CONNECT gotkbd","",gotkbd);
+ debug(F101,"CONNECT kbc","",kbc);
+#ifdef COMMENT
+#ifndef NOSETKEY
+ debug(F101,"CONNECT kmptr","",kmptr);
+#endif /* NOSETKEY */
+#endif /* COMMENT */
+ }
+#endif /* DEBUG */
+
+ while (gotkbd || kbc > 0 /* If we have keyboard chars */
+#ifndef NOSETKEY
+ || kmptr
+#endif /* NOSETKEY */
+ ) {
+#ifndef NOSETKEY
+ if (kmptr) { /* Have current macro? */
+ debug(F100,"CONNECT kmptr non NULL","",0);
+ if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
+ debug(F100,"CONNECT macro empty, continuing","",0);
+ kmptr = NULL; /* If no more chars, */
+ continue; /* Reset pointer and continue */
+ }
+ debug(F000,"CONNECT char from macro","",c);
+ } else { /* No macro... */
+#endif /* NOSETKEY */
+#ifdef BEBOX
+ {
+ int rc = 0;
+ if ((rc = recv(kbin,buf,1,0)) > 0)
+ c = buf[0];
+ else
+ c = -1;
+ debug(F111,"recv","rc",rc);
+ printf("\r\nrecv: %c rc=%d\r\n",buf[0],rc);
+ }
+#else /* BEBOX */
+ c = CONGKS(); /* Yes, read from keyboard */
+#endif /* BEBOX */
+ gotkbd = 0; /* Turn off select() result flag */
+#ifndef NOSETKEY
+ }
+#endif /* NOSETKEY */
+ if (c == -1) {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif /* EINTR */
+ cx_status = CSX_IOERROR;
+ conoc(BEL);
+ goto conret0;
+ }
+ c &= cmdmsk; /* Do any requested masking */
+
+#ifndef NOSETKEY
+/*
+ Note: kmptr is NULL if we got character c from the keyboard, and it is
+ not NULL if it came from a macro. In the latter case, we must avoid
+ expanding it again.
+*/
+ if (!kmptr && macrotab[c]) { /* Macro definition for c? */
+ debug(F000,"CONNECT macro key",macrotab[c],c);
+ kmptr = macrotab[c]; /* Yes, set up macro pointer */
+ continue; /* and restart the loop, */
+ } else c = keymap[c]; /* else use single-char keymap */
+#endif /* NOSETKEY */
+ if (
+#ifndef NOSETKEY
+ !kmptr &&
+#endif /* NOSETKEY */
+ (tt_escape && ((c & 0xff) == escape))) { /* Escape char? */
+ debug(F000,"CONNECT got escape","",c);
+#ifdef BEBOX
+ if (recv(kbin,buf,1,0)>=0)
+ c = buf[0];
+ else
+ c = -1;
+#else /* BEBOX */
+ c = CONGKS() & 0x7f; /* Read argument */
+#endif /* BEBOX */
+ doesc((char) c); /* Handle it */
+ continue; /* Back to loop */
+ }
+ csave = c; /* Save it before translation */
+ /* for local echoing. */
+#ifdef CKLEARN
+ crflag = (c == CR); /* Remember if it was CR. */
+#endif /* CKLEARN */
+
+#ifndef NOCSETS
+ if (inesc[1] == ES_NORMAL) { /* If not inside escape seq.. */
+ /* Translate character sets */
+#ifdef UNICODE
+ int x;
+ if (unicode == 1) { /* Remote is UTF-8 */
+ outxcount = b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
+ outxbuf[outxcount] = NUL;
+ } else if (unicode == 2) { /* Local is UTF-8 */
+
+ x = u_to_b((CHAR)c);
+ if (x < 0)
+ continue;
+ outxbuf[0] = (unsigned)(x & 0xff);
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+ } else {
+#endif /* UNICODE */
+ if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
+ if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
+ outxbuf[0] = c;
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ } else {
+ outxbuf[0] = c;
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+ }
+ if (escseq)
+ apcrc = chkaes((char)c,1);
+#else /* NOCSETS */
+ outxbuf[0] = c;
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+#endif /* NOCSETS */
+
+ debug(F111,"OUTXBUF",outxbuf,outxcount);
+
+ for (i = 0; i < outxcount; i++) {
+ c = outxbuf[i];
+/*
+ If Shift-In/Shift-Out is selected and we have a 7-bit connection,
+ handle shifting here.
+*/
+ if (sosi) { /* Shift-In/Out selected? */
+ if (cmask == 0177) { /* In 7-bit environment? */
+ if (c & 0200) { /* 8-bit character? */
+ if (outshift == 0) { /* If not shifted, */
+ ttoc(dopar(SO)); /* shift. */
+ outshift = 1;
+ }
+ } else {
+ if (outshift == 1) { /* 7-bit character */
+ ttoc(dopar(SI)); /* If shifted, */
+ outshift = 0; /* unshift. */
+ }
+ }
+ }
+ if (c == SO) outshift = 1; /* User typed SO */
+ if (c == SI) outshift = 0; /* User typed SI */
+ }
+ c &= cmask; /* Apply Kermit-to-host mask now. */
+ if (c == '\015') { /* Carriage Return */
+ int stuff = -1;
+ if (tnlm) { /* TERMINAL NEWLINE ON */
+ stuff = LF; /* Stuff LF */
+#ifdef TNCODE
+ } else if (network && /* TELNET NEWLINE ON/OFF/RAW */
+ IS_TELNET()) {
+ switch (!TELOPT_ME(TELOPT_BINARY) ? tn_nlm : tn_b_nlm){
+ case TNL_CRLF:
+ stuff = LF;
+ break;
+ case TNL_CRNUL:
+ stuff = NUL;
+ break;
+ }
+#endif /* TNCODE */
+ }
+ if (stuff > -1) {
+ ttoc(dopar('\015')); /* Send CR */
+ if (duplex) conoc('\015'); /* Maybe echo CR */
+ c = stuff; /* Char to stuff */
+ csave = c;
+ }
+ }
+#ifdef TNCODE
+/* If user types the 0xff character (TELNET IAC), it must be doubled. */
+ else /* Not CR */
+ if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
+ network && IS_TELNET()) { /* Send one now */
+ ttoc((char)IAC); /* and the other one just below. */
+ }
+#endif /* TNCODE */
+ /* Send the character */
+
+ x = ttoc((char)dopar((CHAR) c));
+ if (x > -1) {
+#ifdef CKLEARN
+ if (learning) { /* Learned script active */
+ if (crflag) { /* User typed CR */
+ learnchar(CR); /* Handle CR */
+ learnst = 0; /* Shift to Neutral */
+ } else {
+ learnchar(c); /* Not CR */
+ learnst = 2; /* Change state to Keyboard */
+ }
+ }
+#endif /* CKLEARN */
+ if (duplex) { /* If half duplex, must echo */
+ if (debses)
+ conol(dbchr(csave)); /* the original char */
+ else /* not the translated one */
+ conoc((char)csave);
+ if (seslog) { /* And maybe log it too */
+ c2 = csave;
+ if (sessft == 0 && csave == '\r')
+ c2 = '\n';
+ LOGCHAR((char)c2);
+ }
+ }
+ } else {
+ perror("\r\nCan't send character");
+ cx_status = CSX_IOERROR;
+ active = 0;
+ break;
+ }
+ }
+ }
+ if (FD_ISSET(ttyfd, &out)) {
+ FD_CLR(ttyfd, &out);
+ }
+ while (gotnet > 0 || ibc > 0) {
+ gotnet = 0;
+ prev = c;
+ c = ckcgetc(0); /* Get next character */
+ if (c < 0) { /* Failed... */
+ ckcputf(); /* Flush CONNECT output buffer */
+ if (msgflg) {
+ printf("\r\nCommunications disconnect ");
+#ifdef COMMENT
+ if (c == -3
+#ifdef ultrix
+/* This happens on Ultrix if there's no carrier */
+ && errno != EIO
+#endif /* ultrix */
+#ifdef UTEK
+/* This happens on UTEK if there's no carrier */
+ && errno != EWOULDBLOCK
+#endif /* UTEK */
+ )
+ perror("\r\nCan't read character");
+#endif /* COMMENT */
+ }
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ tthang(); /* Hang up the connection */
+ debug(F111,"CONNECT i/o error 1",ck_errstr(),errno);
+ cx_status = CSX_HOSTDISC;
+ goto conret0;
+ }
+#ifdef TNCODE
+ tx = 0;
+ if ((c == NUL) && network && IS_TELNET()) {
+ if (prev == CR) { /* Discard <NUL> of <CR><NUL> if peer */
+ if (!TELOPT_U(TELOPT_BINARY)) { /* not in binary mode */
+ debug(F111,"CONNECT NUL",ckitoa(prev),c);
+ ckcputf(); /* Flush screen output buffer */
+ break;
+ }
+ }
+ }
+ debug(F111,"CONNECT","c",c);
+ debug(F111,"CONNECT","network",network);
+ debug(F111,"CONNECT","IS_TELNET",IS_TELNET());
+ if ((c == IAC) && network && IS_TELNET()) {
+#ifdef CK_ENCRYPTION
+ int x_auth = TELOPT_ME(TELOPT_AUTHENTICATION);
+#else
+ int x_auth = 0;
+#endif /* CK_ENCRYPTION */
+ int me_bin = TELOPT_ME(TELOPT_BINARY);
+ int u_bin = TELOPT_U(TELOPT_BINARY);
+ debug(F100,"CONNECT got IAC","",0);
+ ckcputf(); /* Dump screen-output buffer */
+ if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
+ if (me_bin != TELOPT_ME(TELOPT_BINARY)) {
+ me_bin = TELOPT_ME(TELOPT_BINARY);
+ } else if (u_bin != TELOPT_U(TELOPT_BINARY)) {
+ u_bin = TELOPT_U(TELOPT_BINARY);
+#ifdef CK_ENCRYPTION
+/*
+ Here we have to push back any bytes we have read using block reads, so we
+ can read them again using single-character reads, so they can be decrypted
+ in case there was a switch to encryption in the block. Note that we can't
+ handle switches in the encryption state itself this way -- which would be
+ nice, since it would eliminate the need for single-character reads. Why?
+ Because if a series of characters has already been decrypted that shouldn't
+ have been, then (a) it's ruined, and (b) so is the state of the decryption
+ machine. Too bad.
+*/
+ } else if (TELOPT_ME(TELOPT_AUTHENTICATION) != 0 &&
+ TELOPT_ME(TELOPT_AUTHENTICATION) != x_auth
+ ) {
+ if (ttpushback((CHAR *)ibp,ibc) > -1) {
+ ibc = 0;
+ ibp = ibuf;
+ }
+#endif /* CK_ENCRYPTION */
+ }
+ continue;
+ } else if (tx == -1) { /* I/O error */
+ if (msgflg)
+ printf("\r\nCommunications disconnect ");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ debug(F111,"CONNECT i/o error 2",ck_errstr(),errno);
+ cx_status = CSX_IOERROR;
+ goto conret0;
+ } else if (tx == -2) { /* I/O error */
+ if (msgflg)
+ printf("\r\nConnection closed by peer");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ debug(F111,"CONNECT i/o error 3",ck_errstr(),errno);
+ cx_status = CSX_IOERROR;
+ goto conret0;
+ } else if (tx == -3) { /* I/O error */
+ if (msgflg)
+ printf("\r\nConnection closed due to telnet policy");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ debug(F111,"CONNECT i/o error 4",ck_errstr(),errno);
+ cx_status = CSX_IOERROR;
+ goto conret0;
+ } else if ((tx == 1) && (!duplex)) { /* ECHO change */
+ duplex = 1; /* Turn on local echo */
+ continue;
+ } else if ((tx == 2) && (duplex)) { /* ECHO change */
+ duplex = 0;
+ continue;
+ } else if (tx == 3) { /* Quoted IAC */
+ c = parity ? 127 : 255;
+ }
+#ifdef IKS_OPTION
+ else if (tx == 4) { /* IKS State Change */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
+ !tcp_incoming
+ ) {
+ /* here we need to print a msg that the other */
+ /* side is in SERVER mode and that REMOTE */
+ /* commands should be used. And CONNECT mode */
+ /* should be ended. */
+ cx_status = CSX_IKSD;
+ active = 0;
+ }
+ }
+#endif /* IKS_OPTION */
+ else if (tx == 6) {
+ /* DO LOGOUT was received */
+ if (msgflg)
+ printf("\r\nRemote Logout ");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ debug(F100,"CONNECT Remote Logout","",0);
+ cx_status = CSX_TRIGGER;
+ goto conret0;
+ } else
+ continue; /* Negotiation OK, get next char. */
+ } else if (parity)
+ c &= 0x7f;
+
+ /* I'm echoing for the remote */
+ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
+ ttoc((char)c);
+#endif /* TNCODE */
+
+#ifdef CKLEARN
+ /* Learned script: Record incoming chars if not in Keyboard state */
+
+ if (learning && learnst != 2) { /* Learned script active */
+ learnbuf[learnbp++] = c; /* Save for INPUT command */
+ if (learnbp >= LEARNBUFSIZ) /* in circular buffer */
+ learnbp = 0; /* wrapping if at end. */
+ learnbc++; /* Count this byte. */
+ learnst = 1; /* State is Net. */
+ }
+#endif /* CKLEARN */
+
+ if (debses) { /* Output character to screen */
+ char *s; /* Debugging display... */
+ s = dbchr(c); /* Make char into string */
+ while (*s) { /* Output each char from string */
+ ckcputc(*s);
+ if (seslog) /* And maybe log it. */
+ LOGCHAR((char)*s);
+ s++;
+ }
+ } else { /* Regular display ... */
+ c &= cmask; /* Apply Kermit-to-remote mask */
+ if (seslog && sessft) /* If binary session log */
+ LOGCHAR((char)c); /* log the character now. */
+#ifndef NOXFER
+#ifdef CK_AUTODL
+/*
+ Autodownload. Check for Kermit S packet prior to translation, since that
+ can change the packet and make it unrecognizable (as when the terminal
+ character set is an ISO 646 one)... Ditto for Zmodem start packet.
+*/
+ if (autodl /* Autodownload enabled? */
+#ifdef IKS_OPTION
+ || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+#endif /* IKS_OPTION */
+ ) {
+ int k = 0;
+
+ if (kstartactive || c == stchr /* Kermit S or I packet? */
+#ifdef COMMENT
+ || adl_kmode == ADLSTR /* Not used in C-Kermit */
+#endif /* COMMENT */
+ )
+ k = kstart((CHAR)c);
+#ifdef CK_XYZ
+ if (!k && zmdlok) /* Or an "sz" start? */
+ k = zstart((CHAR)c);
+#endif /* CK_XYZ */
+ if (k) {
+ int ksign = 0;
+ debug(F101,"CONNECT autodownload k","",k);
+ if (k < 0) { /* Minus-Protocol? */
+#ifdef NOSERVER
+ goto noserver; /* Need server mode for this */
+#else
+ ksign = 1; /* Remember */
+ k = 0 - k; /* Convert to actual protocol */
+ justone = 1; /* Flag for protocol module */
+#endif /* NOSERVER */
+ } else
+ justone = 0;
+ k--; /* Adjust [kz]start's return value */
+ if (k == PROTO_K
+#ifdef CK_XYZ
+ || k == PROTO_Z
+#endif /* CK_XYZ */
+ ) {
+ /* Damage the packet so that it doesn't trigger */
+ /* autodownload detection downstream. */
+ if (k == PROTO_K) {
+ int i, len = strlen((char *)ksbuf);
+ for (i = 0; i < len; i++)
+ ckcputc(BS);
+ }
+#ifdef CK_XYZ
+ else {
+ int i;
+ for (i = 0; i < 3; i++)
+ ckcputc(CAN);
+ }
+#endif /* CK_XYZ */
+
+#ifndef NOICP
+ /* sprintf is safe here (builtin keywords) */
+ sprintf(apcbuf,
+ "set proto %s, %s, set proto %s",
+ ptab[k].p_name,
+ ksign ? "server" : "receive",
+ ptab[protocol].p_name
+ );
+ apclength = strlen(apcbuf);
+ debug(F111,"CONNECT ksbuf",ksbuf,k);
+ debug(F110,"CONNECT autodownload",apcbuf,0);
+ apcactive = APC_LOCAL;
+ ckcputf(); /* Force screen update */
+ cx_status = CSX_APC;
+ goto conret1;
+#else
+/*
+ Here's another way that doesn't require APC, but then we'll have to change
+ all the other CONNECT modules, and then the mainline code that calls them.
+*/
+ {
+ extern char sstate;
+ sstate = ksign ? 'x' : 'v';
+ proto();
+ }
+#endif /* NOICP */
+ }
+ }
+ }
+#ifdef NOSERVER
+ noserver:
+#endif /* NOSERVER */
+
+#endif /* CK_AUTODL */
+#endif /* NOXFER */
+ if (sosi) { /* Handle SI/SO */
+ if (c == SO) { /* Shift Out */
+ inshift = 1;
+ continue;
+ } else if (c == SI) { /* Shift In */
+ inshift = 0;
+ continue;
+ }
+ if (inshift) c |= 0200;
+ }
+ inxbuf[0] = c; /* In case there is no translation */
+ inxcount = 1; /* ... */
+#ifndef NOCSETS
+ if (inesc[0] == ES_NORMAL /* If not in an escape sequence */
+ && !printing /* and not in transparent print */
+ ) { /* Translate character sets */
+#ifdef UNICODE
+ int x;
+ if (unicode == 1) { /* Remote is UTF-8 */
+ x = u_to_b((CHAR)c);
+ if (x == -1)
+ continue;
+ else if (x == -2) { /* LS or PS */
+ inxbuf[0] = CR;
+ inxbuf[1] = LF;
+ inxcount = 2;
+ } else if (x == -9) { /* UTF-8 error */
+ inxbuf[0] = '?';
+ inxbuf[1] = u_to_b2();
+ inxcount = 2;
+ } else {
+ inxbuf[0] = (unsigned)(x & 0xff);
+ }
+ c = inxbuf[0];
+ } else if (unicode == 2) { /* Local is UTF-8 */
+ inxcount = b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
+ c = inxbuf[0];
+ } else {
+#endif /* UNICODE */
+ if (sxi) c = (*sxi)((CHAR)c);
+ if (rxi) c = (*rxi)((CHAR)c);
+ inxbuf[0] = c;
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ }
+#endif /* NOCSETS */
+
+#ifndef NOESCSEQ
+ if (escseq) { /* If handling escape sequences */
+ oldprt = printing; /* remember printer state */
+ apcrc = chkaes((char)c,0); /* and update escseq state. */
+ if (printing && !oldprt) /* If printer was turned on */
+ continue; /* don't print final char of escseq */
+ }
+#ifdef CK_APC
+/*
+ If we are handling APCs, we have several possibilities at this point:
+ 1. Ordinary character to be written to the screen.
+ 2. An Esc; we can't write it because it might be the beginning of an APC.
+ 3. The character following an Esc, in which case we write Esc, then char,
+ but only if we have not just entered an APC sequence.
+*/
+ if (escseq && (apcstatus & APC_ON)) {
+ if (inesc[0] == ES_GOTESC) /* Don't write ESC yet */
+ continue;
+ else if (oldesc[0] == ES_GOTESC && !apcactive) {
+ ckcputc(ESC); /* Write saved ESC */
+ if (seslog && !sessft) LOGCHAR((char)ESC);
+ } else if (apcrc) { /* We have an APC */
+ debug(F111,"CONNECT APC complete",apcbuf,apclength);
+ ckcputf(); /* Force screen update */
+ cx_status = CSX_APC;
+ goto conret1;
+ }
+ }
+#endif /* CK_APC */
+#endif /* NOESCSEQ */
+
+ debug(F111,"INXBUF",inxbuf,inxcount);
+ for (i = 0; i < inxcount; i++) { /* Loop thru */
+ c = inxbuf[i]; /* input expansion buffer... */
+ if (
+#ifdef CK_APC
+ !apcactive && /* Don't display APC sequences */
+#endif /* CK_APC */
+ !printing /* or transparent print material */
+
+ ) {
+ c &= cmdmsk; /* Apply command mask. */
+
+ /* Handle bare carriage returns and linefeeds */
+
+ if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
+ ckcputc(c); /* Yes, output CR */
+ if (seslog && !sessft) LOGCHAR((char)c);
+ c = LF; /* and insert a linefeed */
+ }
+ if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */
+ ckcputc(CR); /* Yes, output CR */
+ if (seslog && !sessft) LOGCHAR((char)CR);
+ }
+#ifndef NOESCSEQ
+ if (dontprint) { /* Do transparent printing. */
+ dontprint = 0;
+ continue;
+ } else
+#endif /* NOESCSEQ */
+ ckcputc(c); /* Write character to screen */
+ }
+ if (seslog && !sessft) { /* Handle session log. */
+ LOGCHAR((char)c);
+ }
+#ifdef XPRINT
+ if (printing && !inesc[0]) {
+ /* zchout() can't be used because */
+ /* it's buffered differently. */
+ cbuf[0] = c;
+ zsoutx(ZMFILE,(char *)cbuf,1);
+ }
+#endif /* XPRINT */
+
+#ifdef CK_TRIGGER
+ /* Check for trigger string */
+ if (tt_trigger[0]) {
+ int i;
+ if ((i = autoexitchk((CHAR)c)) > -1) {
+ makestr(&triggerval,tt_trigger[i]);
+ ckcputf(); /* Force screen update */
+#ifdef NOSETBUF
+ fflush(stdout); /* I mean really force it */
+#endif /* NOSETBUF */
+ cx_status = CSX_TRIGGER;
+ goto conret1;
+ }
+ }
+#endif /* CK_TRIGGER */
+ }
+ }
+ }
+#ifndef BEBOX
+ if (FD_ISSET(scrnout, &out)) {
+ FD_CLR(scrnout, &out);
+ }
+#endif /* BEBOX */
+ } /* End of big loop */
+ conret1: /* Come here to succeed */
+ rc = 1;
+ conret0: /* Common exit point */
+#ifdef BEBOX
+ {
+ long ret_val;
+ closesocket(pair[0]);
+ closesocket(pair[1]);
+ x = kill(tid,SIGKILLTHR); /* Kill thread */
+ wait_for_thread (tid, &ret_val);
+ }
+#endif /* BEBOX */
+
+#ifdef CKLEARN
+ if (learning && learnfp)
+ fputs("\n",learnfp);
+#endif /* CKLEARN */
+
+ conres();
+ if (dohangup > 0) {
+#ifdef NETCONN
+ if (network
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_COMPORT)
+#endif /* TNCODE */
+ )
+ ttclos(0);
+#endif /* NETCONN */
+
+#ifndef COMMENT
+/*
+ This is bad because if they said SET MODEM HANGUP-METHOD MODEM-COMMAND,
+ they mean it -- we shouldn't fall back on tthang() if mdmhup() fails,
+ because maybe they have some special kind of connection. On the other
+ hand, making this change prevents dialing from working at all in some
+ cases. Further study needed.
+*/
+#ifndef NODIAL
+ if (dohangup > 1) /* User asked for it */
+ if (mdmhup() < 1) /* Maybe hang up via modem */
+#endif /* NODIAL */
+ tthang(); /* And make sure we don't hang up */
+#else
+ if (!network) { /* Serial connection. */
+#ifndef NODIAL
+ if (dialmhu) /* Hang up the way they said to. */
+ mdmhup();
+ else
+#endif /* NODIAL */
+ tthang();
+ }
+#endif /* COMMENT */
+ dologend();
+ dohangup = 0; /* again unless requested again. */
+ }
+ if (quitnow) /* Exit now if requested. */
+ doexit(GOOD_EXIT,xitsta);
+ if (msgflg
+#ifdef CK_APC
+ && !apcactive
+#endif /* CK_APC */
+ )
+ printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
+#ifdef CK_APC
+ if (!apcactive)
+#endif /* CK_APC */
+ printf("\n");
+ what = W_NOTHING; /* So console modes set right. */
+#ifndef NOCSETS
+ language = langsv; /* Restore language */
+#endif /* NOCSETS */
+#ifdef CK_APC
+ debug(F101,"CONNECT exit apcactive","",apcactive);
+ debug(F101,"CONNECT exit justone","",justone);
+#endif /* CK_APC */
+ if (msgflg) {
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL)
+ printf("\n");
+#endif /* CK_APC */
+ printf("----------------------------------------------------\n");
+ printbar = 1;
+ } else
+ printbar = 0;
+ fflush(stdout);
+ return(rc);
+}
+
+/* H C O N N E -- Give help message for connect. */
+
+#define CXM_SER 1 /* Serial connections only */
+#define CXM_NET 2 /* Network only (but not Telnet) */
+#define CXM_TEL 4 /* Telnet only */
+
+static struct hmsgtab {
+ char * hmsg;
+ int hflags;
+} hlpmsg[] = {
+ {" ? or H for this message", 0},
+ {" 0 (zero) to send the NUL (0) character", 0},
+ {" B to send a BREAK signal (0.275sec)", CXM_SER},
+#ifdef NETCONN
+ {" B to send a network BREAK", CXM_NET},
+ {" B to send a Telnet BREAK", CXM_TEL},
+#endif /* NETCONN */
+#ifdef CK_LBRK
+ {" L to send a Long BREAK (1.5sec)", CXM_SER},
+#endif /* CK_LBRK */
+#ifdef NETCONN
+ {" I to send a network interrupt packet", CXM_NET},
+ {" I to send a Telnet Interrupt request", CXM_TEL},
+#ifdef TNCODE
+ {" A to send Telnet Are-You-There?", CXM_TEL},
+#endif /* TNCODE */
+#endif /* NETCONN */
+ {" U to hangup and close the connection", 0},
+ {" Q to hangup and quit Kermit", 0},
+ {" S for status", 0},
+#ifdef NOPUSH
+ {" ! to push to local shell (disabled)", 0},
+ {" Z to suspend (disabled)", 0},
+#else
+ {" ! to push to local shell", 0},
+#ifdef NOJC
+ {" Z to suspend (disabled)", 0},
+#else
+ {" Z to suspend", 0},
+#endif /* NOJC */
+#endif /* NOPUSH */
+ {" \\ backslash code:", 0},
+ {" \\nnn decimal character code", 0},
+ {" \\Onnn octal character code", 0},
+ {" \\Xhh hexadecimal character code;", 0},
+ {" terminate with Carriage Return.", 0},
+ {" Type the escape character again to send the escape character itself,",
+ 0},
+ {" or press the space-bar to resume the CONNECT session.", 0},
+ {NULL, 0}
+};
+
+int
+hconne() {
+ int c, i, cxtype;
+ if (network)
+ cxtype = IS_TELNET() ? CXM_TEL : CXM_NET;
+ else
+ cxtype = CXM_SER;
+
+ conol("\r\n----------------------------------------------------\r\n");
+ conoll("Press:");
+ conol(" C to return to ");
+ conoll(*myhost ? myhost : "the C-Kermit prompt");
+ for (i = 0; hlpmsg[i].hmsg; i++) {
+ if (!(hlpmsg[i].hflags) || (hlpmsg[i].hflags == cxtype))
+ conoll(hlpmsg[i].hmsg);
+ }
+ conol("Press a key>"); /* Prompt for command. */
+ c = CONGKS() & 0177; /* Get character, strip any parity. */
+ /* No key mapping or translation here */
+ if (c != CMDQ)
+ conoll("");
+ conoll("----------------------------------------------------");
+ return(c); /* Return it. */
+}
+
+
+/* D O E S C -- Process an escape character argument */
+
+VOID
+#ifdef CK_ANSIC
+doesc(char c)
+#else
+doesc(c) char c;
+#endif /* CK_ANSIC */
+/* doesc */ {
+ CHAR d;
+
+ debug(F101,"CONNECT doesc","",c);
+ while (1) {
+ if (c == escape) { /* Send escape character */
+ d = dopar((CHAR) c); ttoc((char) d); return;
+ } else /* Or else look it up below. */
+ if (isupper(c)) c = tolower(c);
+
+ switch(c) {
+
+ case 'c': /* Escape back to prompt */
+ case '\03':
+ cx_status = CSX_ESCAPE;
+#ifdef NOICP
+ conoll("");
+ conoll("");
+ conoll(
+" WARNING: This version of C-Kermit has no command processor to escape"
+ );
+ conoll(
+" back to. To return to your local system, log out from the remote and/or"
+ );
+ conoll(
+" use the escape character followed by the letter U to close (hang Up) the"
+ );
+ conoll(
+" connection. Resuming your session..."
+ );
+ conoll("");
+ return;
+#else
+ active = 0; conol("\r\n"); return;
+#endif /* NOICP */
+
+ case 'b': /* Send a BREAK signal */
+ case '\02':
+#ifdef CKLEARN
+ learnchar(-7);
+#endif /* CKLEARN */
+ ttsndb(); return;
+
+#ifdef NETCONN
+ case 'i': /* Send Interrupt */
+ case '\011':
+#ifdef TCPSOCKET
+ if (network && IS_TELNET()) { /* TELNET */
+ temp[0] = (CHAR) IAC; /* I Am a Command */
+ temp[1] = (CHAR) TN_IP; /* Interrupt Process */
+ temp[2] = NUL;
+ ttol((CHAR *)temp,2);
+ } else
+#endif /* TCPSOCKET */
+ conoc(BEL);
+ return;
+
+#ifdef TCPSOCKET
+ case 'a': /* "Are You There?" */
+ case '\01':
+ if (network && IS_TELNET()) {
+ temp[0] = (CHAR) IAC; /* I Am a Command */
+ temp[1] = (CHAR) TN_AYT; /* Are You There? */
+ temp[2] = NUL;
+ ttol((CHAR *)temp,2);
+ } else conoc(BEL);
+ return;
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+
+#ifdef CK_LBRK
+ case 'l': /* Send a Long BREAK signal */
+#ifdef CKLEARN
+ learnchar(-8);
+#endif /* CKLEARN */
+ ttsndlb(); return;
+#endif /* CK_LBRK */
+
+ case 'u': /* Hangup */
+ /* case '\010': */ /* No, too dangerous */
+ cx_status = CSX_USERDISC;
+ dohangup = 2; active = 0; conol("\r\nHanging up "); return;
+
+ case 'q': /* Quit */
+ cx_status = CSX_USERDISC;
+ dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
+
+ case 's': /* Status */
+ conoll("");
+ conoll("----------------------------------------------------");
+#ifdef PTYORPIPE
+ if (ttpipe)
+ ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
+ else if (ttpty)
+ ckmakmsg(temp,TMPLEN," Pty: \"",ttname,"\"",NULL);
+ else
+#endif /* PTYORPIPE */
+ ckmakmsg(temp,
+ TMPLEN,
+ " ",
+ (network ? "Host" : "Device"),
+ ": ",
+ ttname
+ );
+ conoll(temp);
+
+ /* The following sprintf's are safe, temp[] size is at least 200 */
+
+ if (!network && speed >= 0L) {
+ sprintf(temp,"Speed %ld", speed);
+ conoll(temp);
+ }
+ sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
+ conoll(temp);
+ sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
+ conoll(temp);
+ sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8);
+ conoll(temp);
+ if (hwparity)
+ sprintf(temp," Parity[hardware]: %s",parnam(hwparity));
+ else
+ sprintf(temp," Parity: %s", parnam(parity));
+ conoll(temp);
+#ifndef NOXFER
+ sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
+ conoll(temp);
+#endif /* NOXFER */
+ ckmakmsg(temp, /* (would not be safe for sprintf) */
+ TMPLEN,
+ " Session log: ",
+ *sesfil ? sesfil : "(none)",
+ NULL,
+ NULL
+ );
+ conoll(temp);
+#ifndef NOSHOW
+ if (!network) shomdm();
+#endif /* NOSHOW */
+#ifdef CKLOGDIAL
+ {
+ long z;
+ z = dologshow(0);
+ if (z > -1L) {
+ sprintf(temp," Elapsed time: %s",hhmmss(z));
+ conoll(temp);
+ }
+ }
+#endif /* CKLOGDIAL */
+ conoll("----------------------------------------------------");
+ return;
+
+ case 'h': /* Help */
+ case '?': /* Help */
+ c = hconne(); continue;
+
+ case '0': /* Send a null */
+ c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
+
+ case 'z': case '\032': /* Suspend */
+#ifndef NOPUSH
+ if (!nopush)
+ stptrap(0);
+ else
+ conoc(BEL);
+#else
+ conoc(BEL);
+#endif /* NOPUSH */
+ return;
+
+ case '@': /* Start inferior command processor */
+ case '!':
+#ifndef NOPUSH
+ if (!nopush) {
+ conres(); /* Put console back to normal */
+ zshcmd(""); /* Fork a shell. */
+ if (conbin((char)escape) < 0) {
+ cx_status = CSX_INTERNAL;
+ printf("Error resuming CONNECT session\n");
+ active = 0;
+ }
+ } else conoc(BEL);
+#else
+ conoc(BEL);
+#endif /* NOPUSH */
+ return;
+
+ case SP: /* Space, ignore */
+ return;
+
+ default: /* Other */
+ if (c == CMDQ) { /* Backslash escape */
+ int x;
+ ecbp = ecbuf;
+ *ecbp++ = c;
+ while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
+ *ecbp++ = c;
+ *ecbp = NUL; ecbp = ecbuf;
+ x = xxesc(&ecbp); /* Interpret it */
+ if (x >= 0) { /* No key mapping here */
+ c = dopar((CHAR) x);
+ ttoc((char) c);
+ return;
+ } else { /* Invalid backslash code. */
+ conoc(BEL);
+ return;
+ }
+ }
+ conoc(BEL); return; /* Invalid esc arg, beep */
+ }
+ }
+}
+#endif /* NOLOCAL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckucon.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckucon.c
new file mode 100644
index 0000000..50ceb7e
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckucon.c
@@ -0,0 +1,2690 @@
+#include "ckcsym.h"
+
+char *connv = "CONNECT Command for UNIX:fork(), 9.0.117, 14 Jul 2011";
+
+/* C K U C O N -- Terminal connection to remote system, for UNIX */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ NOTE: This module has been superseded on most platforms by ckucns.c, which
+ uses select() rather than fork() for multiplexing its i/o. This module
+ is still needed for platforms that do not support select(), and also for
+ its X.25 support. Although the two modules share large amounts of code,
+ their structure is radically different and therefore attempts at merging
+ them have so far been unsuccessful. (November 1998.)
+
+ Special thanks to Eduard Vopicka, Prague University of Economics,
+ Czech Republic, for valuable contributions to this module in July 1994,
+ and to Neal P. Murphy of the Motorola Cellular Infrastructure Group in 1996
+ for rearranging the code to allow operation on the BeBox, yet still work
+ in regular UNIX.
+*/
+#include "ckcdeb.h" /* Common things first */
+
+#ifndef NOLOCAL
+
+#ifdef BEOSORBEBOX
+static double time_started = 0.0;
+#include <kernel/OS.h>
+_PROTOTYP( static long concld, (void *) );
+#else
+_PROTOTYP( static VOID concld, (void) );
+#endif /* BEOSORBEBOX */
+
+#ifdef NEXT
+#undef NSIG
+#include <sys/wait.h> /* For wait() */
+#endif /* NEXT */
+
+#include <signal.h> /* Signals */
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#ifdef ZILOG /* Longjumps */
+#include <setret.h>
+#else
+#include <setjmp.h>
+#endif /* ZILOG */
+#include "ckcsig.h"
+
+/* Kermit-specific includes */
+
+#include "ckcasc.h" /* ASCII characters */
+#include "ckcker.h" /* Kermit things */
+#include "ckucmd.h" /* For xxesc() prototype */
+#include "ckcnet.h" /* Network symbols */
+#ifndef NOCSETS
+#include "ckcxla.h" /* Character set translation */
+#endif /* NOCSETS */
+
+/* Internal function prototypes */
+
+_PROTOTYP( VOID ttflux, (void) );
+_PROTOTYP( VOID doesc, (char) );
+_PROTOTYP( VOID logchar, (char) );
+_PROTOTYP( int hconne, (void) );
+#ifndef NOSHOW
+_PROTOTYP( VOID shomdm, (void) );
+#endif /* NOSHOW */
+_PROTOTYP( static int kbget, (void) );
+_PROTOTYP( static int pipemsg, (int) );
+_PROTOTYP( static int ckcputf, (void) );
+_PROTOTYP( static VOID ck_sndmsg, (void) );
+/*
+ For inter-fork signaling. Normally we use SIGUSR1, except on SCO, where
+ we use SIGUSR2 because SIGUSR1 is used by the system. You can define
+ CK_FORK_SIG to be whatever other signal you might want to use at compile
+ time. We don't use SIGUSR2 everywhere because in some systems, like
+ UnixWare, the default action for SIGUSR2 is to kill the process that gets it.
+*/
+#ifndef CK_FORK_SIG
+
+#ifndef SIGUSR1 /* User-defined signals */
+#define SIGUSR1 30
+#endif /* SIGUSR1 */
+
+#ifndef SIGUSR2
+#define SIGUSR2 31
+#endif /* SIGUSR2 */
+
+#ifdef M_UNIX
+#define CK_FORK_SIG SIGUSR2 /* SCO - use SIGUSR2 */
+#else
+#define CK_FORK_SIG SIGUSR1 /* Others - use SIGUSR1 */
+#endif /* M_UNIX */
+
+#endif /* CK_FORK_SIG */
+
+/* External variables */
+
+extern struct ck_p ptab[];
+
+extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
+ mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
+ xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tt_lfd,
+ tn_nlm, ttfdflg,
+ tt_escape, justone, carrier, hwparity;
+
+extern long speed;
+extern char ttname[], sesfil[], myhost[], *ccntab[];
+#ifdef TNCODE
+extern int tn_b_nlm, tn_rem_echo;
+#endif /* TNCODE */
+
+#ifdef CK_TRIGGER
+extern char * tt_trigger[], * triggerval;
+#endif /* CK_TRIGGER */
+
+extern int nopush;
+
+#ifdef CK_APC
+extern int apcactive; /* Application Program Command (APC) */
+extern int apcstatus; /* items ... */
+static int apclength = 0;
+#ifdef DCMDBUF
+extern char *apcbuf;
+#else
+extern char apcbuf[];
+#endif /* DCMDBUF */
+static int apcbuflen = APCBUFLEN - 2;
+extern int protocol; /* Auto download */
+#endif /* CK_APC */
+
+extern int autodl;
+#ifdef CK_AUTODL
+extern CHAR ksbuf[];
+#endif /* CK_AUTODL */
+
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+static int zmdlok = 1; /* Zmodem autodownloads available */
+#else
+static int zmdlok = 0; /* Depends on external protocol def */
+#endif /* XYZ_INTERNAL */
+#else
+static int zmdlok = 0; /* Not available at all */
+#endif /* CK_XYZ */
+
+#ifndef NOSETKEY /* Keyboard mapping */
+extern KEY *keymap; /* Single-character key map */
+extern MACRO *macrotab; /* Key macro pointer table */
+static MACRO kmptr = NULL; /* Pointer to current key macro */
+#endif /* NOSETKEY */
+
+/* Global variables local to this module */
+
+static int
+ quitnow = 0, /* <esc-char>Q was typed */
+ jbset = 0, /* Flag whether jmp buf is set. */
+ dohangup = 0, /* <esc-char>H was typed */
+ sjval, /* Setjump return value */
+ goterr = 0, /* Fork/pipe creation error flag */
+ inshift = 0, /* SO/SI shift states */
+ outshift = 0;
+
+int active = 0; /* Lower fork active flag */
+
+static PID_T parent_id = (PID_T)0; /* Process ID of keyboard fork */
+
+static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
+
+#ifdef CK_SMALL
+#define IBUFL 1536 /* Input buffer length */
+#else
+#define IBUFL 4096
+#endif /* CK_SMALL */
+
+static int obc = 0; /* Output buffer count */
+
+#ifndef OXOS
+#define OBUFL 1024 /* Output buffer length */
+#else
+#define OBUFL IBUFL
+#endif /* OXOS */
+
+#ifdef BIGBUFOK
+#define TMPLEN 4096 /* Temporary message buffer length */
+#else
+#define TMPLEN 200
+#endif /* BIGBUFOK */
+
+#ifdef DYNAMIC
+static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
+#else
+static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
+#endif /* DYNAMIC */
+
+#ifdef DYNAMIC
+static char *ibp; /* Input buffer pointer */
+#else
+static char *ibp = ibuf; /* Input buffer pointer */
+#endif /*DYNAMIC */
+static int ibc = 0; /* Input buffer count */
+
+#ifdef DYNAMIC
+static char *obp; /* Output buffer pointer */
+#else
+static char *obp = obuf; /* Output buffer pointer */
+#endif /* DYNAMIC */
+
+/* X.25 items */
+
+#ifdef ANYX25
+static char *p; /* General purpose pointer */
+char x25ibuf[MAXIX25]; /* Input buffer */
+char x25obuf[MAXOX25]; /* Output buffer */
+int ibufl; /* Length of input buffer */
+int obufl; /* Length of output buffer */
+unsigned char tosend = 0;
+int linkid, lcn;
+static int dox25clr = 0;
+#ifndef IBMX25
+extern CHAR padparms[];
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+static int xpipe[2] = {-1, -1}; /* Pipe descriptor for child-parent messages */
+static PID_T pid = (PID_T) 0; /* Process ID of child */
+
+/* Character-set items */
+
+static int unicode = 0;
+
+static int escseq = 0; /* 1 = Recognizer is active */
+int inesc = 0; /* State of sequence recognizer */
+int oldesc = -1; /* Previous state of recognizer */
+
+#define OUTXBUFSIZ 15
+static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */
+static int inxcount = 0; /* and count */
+static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */
+static int outxcount = 0; /* and count */
+
+#ifndef NOCSETS
+#ifdef CK_ANSIC /* ANSI C prototypes... */
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
+static CHAR (*sxo)(CHAR); /* Local translation functions */
+static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
+static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
+static CHAR (*rxi)(CHAR);
+#else /* Not ANSI C... */
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
+static CHAR (*sxo)(); /* Local translation functions */
+static CHAR (*rxo)(); /* for output (sending) terminal chars */
+static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */
+static CHAR (*rxi)();
+#endif /* CK_ANSIC */
+extern int language; /* Current language. */
+static int langsv; /* For remembering language setting. */
+extern struct csinfo fcsinfo[]; /* File character set info. */
+extern int tcsr, tcsl; /* Terminal character sets, remote & local. */
+static int tcs; /* Intermediate ("transfer") character set. */
+static int tcssize = 0; /* Size of tcs */
+#ifdef UNICODE /* UTF-8 support */
+#ifdef CK_ANSIC
+extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
+extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
+extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
+extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
+#else
+extern int (*xl_ufc[MAXFCSETS+1])();
+extern USHORT (*xl_fcu[MAXFCSETS+1])();
+extern int (*xuf)();
+extern USHORT (*xfu)();
+#endif /* CK_ANSIC */
+#endif /* UNICODE */
+#endif /* NOCSETS */
+
+/*
+ We do not need to parse and recognize escape sequences if we are being built
+ without character-set support AND without APC support.
+*/
+#ifdef NOCSETS /* No character sets */
+#ifndef CK_APC /* No APC */
+#ifndef NOESCSEQ
+#define NOESCSEQ /* So no escape sequence recognizer */
+#endif /* NOESCSEQ */
+#endif /* CK_APC */
+#endif /* NOCSETS */
+
+/* Child process events and messages */
+
+#define CEV_NO 0 /* No event */
+#define CEV_HUP 1 /* Communications hangup */
+#define CEV_PAD 2 /* X.25 - change PAD parameters */
+#define CEV_DUP 3 /* Toggle duplex */
+#define CEV_APC 4 /* Execute APC */
+#ifdef TNCODE
+#define CEV_MEBIN 5 /* Change of me_binary */
+#define CEV_UBIN 6 /* Change of u_binary */
+#endif /* TNCODE */
+#define CEV_ADL 7 /* Autodownload */
+#define CEV_AUL 8 /* Autoupload */
+#define CEV_TRI 9 /* Trigger string */
+
+#ifdef NOESCSEQ
+#define chkaes(x) 0
+#else
+/*
+ As of edit 178, the CONNECT command skips past ANSI escape sequences to
+ avoid translating the characters within them. This allows the CONNECT
+ command to work correctly with a host that uses a 7-bit ISO 646 national
+ character set, in which characters like '[' would normally be translated
+ into accented characters, ruining the terminal's interpretation (and
+ generation) of escape sequences.
+
+ As of edit 190, the CONNECT command responds to APC escape sequences
+ (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
+ program was built with CK_APC defined.
+
+ Non-ANSI/ISO-compliant escape sequences are not handled.
+*/
+
+/* States for the escape-sequence recognizer. */
+
+#define ES_NORMAL 0 /* Normal, not in an escape sequence */
+#define ES_GOTESC 1 /* Current character is ESC */
+#define ES_ESCSEQ 2 /* Inside an escape sequence */
+#define ES_GOTCSI 3 /* Inside a control sequence */
+#define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */
+#define ES_TERMIN 5 /* 1st char of string terminator */
+
+/*
+ ANSI escape sequence handling. Only the 7-bit form is treated, because
+ translation is not a problem in the 8-bit environment, in which all GL
+ characters are ASCII and no translation takes place. So we don't check
+ for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
+ Here is the ANSI sequence recognizer state table, followed by the code
+ that implements it.
+
+ Definitions:
+ CAN = Cancel 01/08 Ctrl-X
+ SUB = Substitute 01/10 Ctrl-Z
+ DCS = Device Control Sequence 01/11 05/00 ESC P
+ CSI = Control Sequence Introducer 01/11 05/11 ESC [
+ ST = String Terminator 01/11 05/12 ESC \
+ OSC = Operating System Command 01/11 05/13 ESC ]
+ PM = Privacy Message 01/11 05/14 ESC ^
+ APC = Application Program Command 01/11 05/15 ESC _
+
+ ANSI escape sequence recognizer:
+
+ State Input New State ; Commentary
+
+ NORMAL (start) ; Start in NORMAL state
+
+ (any) CAN NORMAL ; ^X cancels
+ (any) SUB NORMAL ; ^Z cancels
+
+ NORMAL ESC GOTESC ; Begin escape sequence
+ NORMAL other ; NORMAL control or graphic character
+
+ GOTESC ESC ; Start again
+ GOTESC [ GOTCSI ; CSI
+ GOTESC P STRING ; DCS introducer, consume through ST
+ GOTESC ] STRING ; OSC introducer, consume through ST
+ GOTESC ^ STRING ; PM introducer, consume through ST
+ GOTESC _ STRING ; APC introducer, consume through ST
+ GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character
+ GOTESC other ESCSEQ ; Intermediate or ignored control character
+
+ ESCSEQ ESC GOTESC ; Start again
+ ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character
+ ESCSEQ other ; Intermediate or ignored control character
+
+ GOTCSI ESC GOTESC ; Start again
+ GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character
+ GOTCSI other ; Intermediate char or ignored control char
+
+ STRING ESC TERMIN ; Maybe have ST
+ STRING other ; Consume all else
+
+ TERMIN \ NORMAL ; End of string
+ TERMIN other STRING ; Still in string
+*/
+/*
+ chkaes() -- Check ANSI Escape Sequence.
+ Call with EACH character in input stream.
+ Sets global inesc variable according to escape sequence state.
+ Returns 0 normally, 1 if an APC sequence is to be executed.
+*/
+int
+#ifdef CK_ANSIC
+chkaes(char c)
+#else
+chkaes(c) char c;
+#endif /* CK_ANSIC */
+/* chkaes */ {
+
+ oldesc = inesc; /* Remember previous state */
+ if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */
+ inesc = ES_NORMAL;
+ else /* Otherwise */
+ switch (inesc) { /* enter state switcher */
+
+ case ES_NORMAL: /* NORMAL state */
+ if (c == ESC) /* Got an ESC */
+ inesc = ES_GOTESC; /* Change state to GOTESC */
+ break; /* Otherwise stay in NORMAL state */
+
+ case ES_GOTESC: /* GOTESC state */
+ if (c == '[') /* Left bracket after ESC is CSI */
+ inesc = ES_GOTCSI; /* Change to GOTCSI state */
+ else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, [, ^, or _ */
+ inesc = ES_STRING; /* Switch to STRING-absorption state */
+#ifdef CK_APC
+ if (c == '_' && pid == 0 && /* APC handled in child only */
+ (apcstatus & APC_ON)) { /* and only if not disabled. */
+ debug(F100,"CONNECT APC begin","",0);
+ apcactive = APC_REMOTE; /* Set APC-Active flag */
+ apclength = 0; /* and reset APC buffer pointer */
+ }
+#endif /* CK_APC */
+ } else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
+ inesc = ES_NORMAL; /* Back to normal */
+ else if (c != ESC) /* ESC in an escape sequence... */
+ inesc = ES_ESCSEQ; /* starts a new escape sequence */
+ break; /* Intermediate or ignored ctrl char */
+
+ case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */
+ if (c > 057 && c < 0177) /* Final character '0' thru '~' */
+ inesc = ES_NORMAL; /* Return to NORMAL state. */
+ else if (c == ESC) /* ESC ... */
+ inesc = ES_GOTESC; /* starts a new escape sequence */
+ break; /* Intermediate or ignored ctrl char */
+
+ case ES_GOTCSI: /* GOTCSI -- In a control sequence */
+ if (c > 077 && c < 0177) /* Final character '@' thru '~' */
+ inesc = ES_NORMAL; /* Return to NORMAL. */
+ else if (c == ESC) /* ESC ... */
+ inesc = ES_GOTESC; /* starts over. */
+ break; /* Intermediate or ignored ctrl char */
+
+ case ES_STRING: /* Inside a string */
+ if (c == ESC) /* ESC may be 1st char of terminator */
+ inesc = ES_TERMIN; /* Go see. */
+#ifdef CK_APC
+ else if (apcactive && (apclength < apcbuflen)) /* If in APC, */
+ apcbuf[apclength++] = c; /* deposit this character. */
+ else { /* Buffer overrun */
+ apcactive = 0; /* Discard what we got */
+ apclength = 0; /* and go back to normal */
+ apcbuf[0] = 0; /* Not pretty, but what else */
+ inesc = ES_NORMAL; /* can we do? (ST might not come) */
+ }
+#endif /* CK_APC */
+ break; /* Absorb all other characters. */
+
+ case ES_TERMIN: /* May have a string terminator */
+ if (c == '\\') { /* which must be backslash */
+ inesc = ES_NORMAL; /* If so, back to NORMAL */
+#ifdef CK_APC
+ if (apcactive) { /* If it was an APC string, */
+ debug(F101,"CONNECT APC terminated","",c);
+ apcbuf[apclength] = NUL; /* terminate it and then ... */
+ return(1);
+ }
+#endif /* CK_APC */
+ } else { /* Otherwise */
+ inesc = ES_STRING; /* Back to string absorption. */
+#ifdef CK_APC
+ if (apcactive && (apclength+1 < apcbuflen)) { /* In APC string */
+ apcbuf[apclength++] = ESC; /* deposit the Esc character */
+ apcbuf[apclength++] = c; /* and this character too */
+ }
+#endif /* CK_APC */
+ }
+ }
+ return(0);
+}
+#endif /* NOESCSEQ */
+
+/* Connect state parent/child communication signal handlers */
+
+/* Routines used by the child process */
+
+static int
+pipemsg(n) int n; { /* Send message ID to parent */
+ int code = n & 255;
+ return(write(xpipe[1], &code, sizeof(code)));
+}
+
+/* Environment pointer for CK_FORK_SIG signal handling in child... */
+
+#ifdef CK_POSIX_SIG
+static sigjmp_buf sig_env;
+#else
+static jmp_buf sig_env;
+#endif /* CK_POSIX_SIG */
+
+static SIGTYP /* CK_FORK_SIG handling in child ... */
+forkint(foo) int foo; {
+ /* It is important to disable CK_FORK_SIG before longjmp */
+ signal(CK_FORK_SIG, SIG_IGN); /* Set to ignore CK_FORK_SIG */
+ debug(F100,"CONNECT forkint - CK_FORK_SIG", "", 0);
+ /* Force return from ck_sndmsg() */
+ cklongjmp(sig_env, 1);
+ /* NOTREACHED */
+}
+
+static VOID
+ck_sndmsg() { /* Executed by child only ... */
+ debug(F100,"CONNECT ck_sndmsg, active", "", active);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sig_env,1)
+#else
+ setjmp(sig_env)
+#endif /* CK_POSIX_SIG */
+ == 0) {
+ debug(F100,"CONNECT ck_sndmsg signaling parent","",0);
+ signal(CK_FORK_SIG, forkint); /* Set up signal handler */
+ kill(parent_id, CK_FORK_SIG); /* Kick the parent */
+ debug(F100,"ck_sndmsg pausing","",0);
+ for (;;) pause(); /* Wait for CK_FORK_SIG or SIGKILL */
+ /* NOTREACHED */
+ }
+ /* We come here from forkint() via [sig]cklongjmp(sig_env,1) */
+ debug(F100,"CONNECT ck_sndmsg is parent - returning", "", 0);
+}
+
+/* Routines used by the parent process */
+
+#ifdef CK_POSIX_SIG /* Environment pointer for CONNECT errors */
+static sigjmp_buf con_env;
+#else
+static jmp_buf con_env;
+#endif /* CK_POSIX_SIG */
+/*
+ pipeint() handles CK_FORK_SIG signals from the lower (port) fork.
+ It reads a function code from the pipe that connects the two forks,
+ then reads additional data from the pipe, then handles it.
+*/
+static SIGTYP
+pipeint(arg) int arg; { /* Dummy argument */
+ int code, cx, x, i /* , n */ ;
+
+#ifndef NOCCTRAP
+ extern ckjmpbuf cmjbuf;
+#endif /* NOCCTRAP */
+ /*
+ IMPORTANT: At this point, the child fork is waiting for CK_FORK_SIG
+ (eventually for SIGKILL) inside of ck_sndmsg(). So we can't get any
+ subsequent CK_FORK_SIG from child before we send it CK_FORK_SIG.
+ */
+ signal(CK_FORK_SIG, SIG_IGN); /* Ignore CK_FORK_SIG now */
+ debug(F101,"CONNECT pipeint arg","",arg);
+
+ read(xpipe[0], &code, sizeof(code)); /* Get function code from pipe */
+ debug(F101,"CONNECT pipeint code","",code);
+ cx = code & 255; /* 8-bit version of function code */
+
+#ifndef NOCCTRAP
+#ifndef NOICP
+#define USECCJMPBUF
+#endif /* NOICP */
+#endif /* NOCCTRAP */
+/*
+ Read info passed back up to us by the lower fork, depending on the function
+ requested. The same number of items must be read from the pipe in the same
+ order as the lower fork put them there. Trying to read something that's not
+ there makes the program hang uninterruptibly. Pay close attention -- notice
+ how we fall through some of the cases rather than break; that's deliberate.
+*/
+ switch (cx) {
+#ifdef CK_TRIGGER
+ case CEV_TRI: /* Trigger string */
+ debug(F100,"CONNECT trigger","",0);
+ read(xpipe[0], (char *)&i, sizeof(i)); /* Trigger index */
+ debug(F101,"CONNECT trigger index","",i);
+ makestr(&triggerval,tt_trigger[i]); /* Make a copy of the trigger */
+ debug(F110,"CONNECT triggerval",triggerval,0);
+ read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */
+ debug(F101,"CONNECT trigger ibc (upper)","",ibc); /* input buffer. */
+ if (ibc > 0) {
+ read(xpipe[0], (char *)&ibp, sizeof(ibp));
+ read(xpipe[0], ibp, ibc);
+ }
+ /* Fall thru... */
+
+#endif /* CK_TRIGGER */
+
+ case CEV_HUP:
+/*
+ The CEV_HUP case is executed when the other side has hung up on us.
+ In some cases, this happens before we have had a chance to execute the
+ setjmp(con_env,1) call, and in that case we'd better not take the longjmp!
+ A good example is when you TELNET to port 13 on the local host; it prints
+ its asctime() string (26 chars) and then closes the connection.
+*/
+#ifdef CK_TRIGGER
+ if (cx == CEV_TRI)
+ sjval = CEV_TRI; /* Set global variable. */
+ else
+#endif /* CK_TRIGGER */
+ sjval = CEV_HUP;
+ if (jbset) { /* jmp_buf is initialized */
+ cklongjmp(con_env,sjval); /* so do the right thing. */
+ } else {
+ int x = 0;
+#ifdef USECCJMPBUF
+ /* jmp_buf not init'd yet a close approximation... */
+#ifdef CK_TRIGGER
+ if (cx == CEV_HUP)
+#endif /* CK_TRIGGER */
+ ttclos(0); /* Close our end of the connection */
+ if (pid) {
+ debug(F101,"CONNECT trigger killing pid","",pid);
+#ifdef BEOSORBEBOX
+ {
+ long ret_val;
+ x = kill(pid,SIGKILLTHR); /* Kill lower fork */
+ wait_for_thread (pid, &ret_val);
+ }
+#else
+#ifdef Plan9
+ x = kill(pid, SIGKILL); /* (should always use this really) */
+#else
+ x = kill(pid,9); /* Kill lower fork (history) */
+#endif /* Plan9 */
+ wait((WAIT_T *)0); /* Wait till gone. */
+ if (x < 0) {
+ printf("ERROR: Failure to kill pid %ld: %s, errno=%d\n",
+ (long) pid, ck_errstr(), errno);
+ debug(F111,"CONNECT error killing stale pid",
+ ck_errstr(),errno);
+ }
+ pid = (PID_T) 0;
+#endif /* BEOSORBEBOX */
+ }
+ conres(); /* Reset the console. */
+ if (!quiet) {
+ printf("\r\n(Back at %s)\r\n",
+ *myhost ? myhost :
+#ifdef UNIX
+ "local UNIX system"
+#else
+ "local system"
+#endif /* UNIX */
+ );
+ }
+ what = W_NOTHING; /* So console modes are set right. */
+ printf("\r\n"); /* prevent prompt-stomping */
+ cklongjmp(cmjbuf,0); /* Do what the Ctrl-C handler does */
+#else
+ printf("\r\nLongjump failure - fatal\r\n");
+ doexit(GOOD_EXIT,-1); /* Better than dumping core... */
+#endif /* USECCJMPBUF */
+ }
+#ifdef USECCJMPBUF
+#undef USECCJMPBUF
+#endif /* USECCJMPBUF */
+
+ case CEV_DUP: /* Child sends duplex change */
+ read(xpipe[0], (char *)&duplex, sizeof(duplex));
+ debug(F101,"CONNECT pipeint duplex","",duplex);
+ break;
+#ifdef TNCODE
+ case CEV_MEBIN: /* Child sends me_binary change */
+ read(xpipe[0],
+ (char *)&TELOPT_ME(TELOPT_BINARY),
+ sizeof(TELOPT_ME(TELOPT_BINARY))
+ );
+ debug(F101,"CONNECT pipeint me_binary","",TELOPT_ME(TELOPT_BINARY));
+ break;
+ case CEV_UBIN: /* Child sends u_binary change */
+ read(xpipe[0],
+ (char *)&TELOPT_U(TELOPT_BINARY),
+ sizeof(TELOPT_U(TELOPT_BINARY))
+ );
+ debug(F101,"CONNECT pipeint u_binary","",TELOPT_U(TELOPT_BINARY));
+ break;
+#endif /* TNCODE */
+
+#ifdef CK_APC
+ case CEV_AUL: /* Autoupload */
+ justone = 1;
+ debug(F100,"CONNECT autoupload at parent","",0);
+#ifdef CK_AUTODL
+ case CEV_ADL: /* Autodownload */
+ apcactive = APC_LOCAL;
+ if (!justone) debug(F100,"CONNECT autodownload at parent","",0);
+ /* Copy child's Kermit packet if any */
+ read(xpipe[0], (char *)&x, sizeof(x));
+ debug(F101,"CONNECT trigger ibc (upper)","",ibc);
+ if (x > 0)
+ read(xpipe[0], (char *)ksbuf, x+1);
+#endif /* CK_AUTODL */
+ case CEV_APC: /* Application Program Command */
+ read(xpipe[0], (char *)&apclength, sizeof(apclength));
+ read(xpipe[0], apcbuf, apclength+1); /* Include trailing zero byte */
+ debug(F111,"CONNECT APC at parent",apcbuf,apclength);
+ read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */
+ if (ibc > 0) { /* input buffer. */
+ read(xpipe[0], (char *)&ibp, sizeof(ibp));
+ read(xpipe[0], ibp, ibc);
+ }
+ obc = 0; obp = obuf; *obuf = NUL; /* Because port fork flushed */
+ sjval = CEV_APC;
+ cklongjmp(con_env,sjval);
+ /* NOTREACHED */
+#endif /* CK_APC */
+
+#ifdef SUNX25
+ case CEV_PAD: /* X.25 PAD parameter change */
+ debug(F100,"CONNECT pipeint PAD change","",0);
+ read(xpipe[0],padparms,MAXPADPARMS);
+ sjval = CEV_PAD; /* Set global variable. */
+#ifdef COMMENT /* We might not need to do this... */
+ cklongjmp(con_env,sjval);
+ /* NOTREACHED */
+#else /* COMMENT */
+ break;
+#endif /* COMMENT */
+#endif /* SUNX25 */
+ }
+ signal(CK_FORK_SIG, pipeint); /* Set up signal handler */
+ kill(pid, CK_FORK_SIG); /* Signal the port fork ... */
+}
+
+/* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
+/*
+ Output is buffered to avoid slow screen writes on fast connections.
+ NOTE: These could (easily?) become macros ...
+*/
+static int
+ckcputf() { /* Dump the output buffer */
+ int x = 0;
+ if (obc > 0) /* If we have any characters, */
+ x = conxo(obc,obuf); /* dump them, */
+ obp = obuf; /* reset the pointer */
+ obc = 0; /* and the counter. */
+ return(x); /* Return conxo's return code */
+}
+
+int
+ckcputc(c) int c; {
+ int x;
+
+ *obp++ = c & 0xff; /* Deposit the character */
+ obc++; /* Count it */
+ if (ibc == 0 || /* If input buffer about empty */
+ obc == OBUFL) { /* or output buffer full */
+ debug(F101,"CONNECT CKCPUTC obc","",obc);
+ x = conxo(obc,obuf); /* dump the buffer, */
+ obp = obuf; /* reset the pointer */
+ obc = 0; /* and the counter. */
+ return(x); /* Return conxo's return code */
+ } else return(0);
+}
+
+/* C K C G E T C -- C-Kermit CONNECT Get Character */
+/*
+ Buffered read from communication device.
+ Returns the next character, refilling the buffer if necessary.
+ On error, returns ttinc's return code (see ttinc() description).
+ Dummy argument for compatible calling conventions with ttinc().
+ NOTE: We don't have a macro for this because we have to pass
+ a pointer to this function as an argument to tn_doop().
+*/
+int
+ckcgetc(dummy) int dummy; {
+ int c, n;
+#ifdef CK_SSL
+ extern int ssl_active_flag, tls_active_flag;
+#endif /* CK_SSL */
+
+#ifdef CK_ENCRYPTION
+ /* No buffering for possibly encrypted connections */
+ if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
+ return(ttinc(0));
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag)
+ return(ttinc(0));
+#endif /* CK_SSL */
+#ifdef COMMENT
+/* too much */
+ debug(F101,"CONNECT CKCGETC 1 ibc","",ibc); /* Log */
+#endif /* COMMENT */
+ if (ibc < 1) { /* Need to refill buffer? */
+ ibc = 0; /* Yes, reset count */
+ ibp = ibuf; /* and buffer pointer */
+ /* debug(F100,"CONNECT CKCGETC 1 calling ttinc(0)","",0); */
+#ifdef COMMENT
+/*
+ This check is not worth the overhead. Scenario: ttchk() returns 0, so we
+ fall through to the blocking ttinc(). While in ttinc(), the connection is
+ lost. But the read() that ttinc() calls does not notice, and never returns.
+ This happens at least in HP-UX, and can be seen when we turn off the modem.
+*/
+ if (!network && (carrier != CAR_OFF))
+ if ((n = ttchk()) < 0) /* Make sure connection is not lost */
+ return(n);
+#endif /* COMMENT */
+ c = ttinc(0); /* Read one character, blocking */
+ /* debug(F101,"CONNECT CKCGETC 1 ttinc(0)","",c); */
+ if (c < 0) { /* If error, return error code */
+ return(c);
+ } else { /* Otherwise, got one character */
+ *ibp++ = c; /* Advance buffer pointer */
+ ibc++; /* and count. */
+ }
+ if ((n = ttchk()) > 0) { /* Any more waiting? */
+ if (n > (IBUFL - ibc)) /* Get them all at once. */
+ n = IBUFL - ibc; /* Don't overflow buffer */
+ if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt(ibp,n);
+#endif /* CK_ENCRYPTION */
+ ibc += n; /* Advance counter */
+ }
+ } else if (n < 0) { /* Error? */
+ return(n); /* Return the error code */
+ }
+ debug(F101,"CONNECT CKCGETC 2 ibc","",ibc); /* Log how many */
+ ibp = ibuf; /* Point to beginning of buffer */
+ }
+ c = *ibp++ & 0xff; /* Get next character from buffer */
+ ibc--; /* Reduce buffer count */
+ return(c); /* Return the character */
+}
+
+/*
+ Keyboard handling, buffered for speed, which is needed when C-Kermit is
+ in CONNECT mode between two other computers that are transferring data.
+*/
+static char *kbp; /* Keyboard input buffer pointer */
+static int kbc; /* Keyboard input buffer count */
+
+#ifdef CK_SMALL /* Keyboard input buffer length */
+#define KBUFL 32 /* Small for PDP-11 UNIX */
+#else
+#define KBUFL 257 /* Regular kernel size for others */
+#endif /* CK_SMALL */
+
+#ifdef DYNAMIC
+static char *kbuf = NULL;
+#else
+static char kbuf[KBUFL];
+#endif /* DYNAMIC */
+
+/* Macro for reading keystrokes. */
+
+#define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
+
+/*
+ Note that we call read() directly here, normally a no-no, but in this case
+ we know it's UNIX and we're only doing what coninc(0) would have done,
+ except we're reading a block of characters rather than just one. There is,
+ at present, no conxin() analog to ttxin() for chunk reads, and instituting
+ one would only add function-call overhead as it would only be a wrapper for
+ a read() call anyway.
+*/
+/*
+ Another note: We stick in this read() till the user types something.
+ But the other (lower) fork is running too, and on TELNET connections,
+ it will signal us to indicate echo-change negotiations, and this can
+ interrupt the read(). Some UNIXes automatically restart the interrupted
+ system call, others return from it with errno == EINTR.
+*/
+static int /* Keyboard buffer filler */
+kbget() {
+#ifdef EINTR
+ int tries = 10; /* If read() is interrupted, */
+ int ok = 0;
+ while (tries-- > 0) { /* try a few times... */
+#endif /* EINTR */
+ if ((kbc = conchk()) < 1) /* How many chars waiting? */
+ kbc = 1; /* If none or dunno, wait for one. */
+ else if (kbc > KBUFL) /* If too many, */
+ kbc = KBUFL; /* only read this many. */
+ if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */
+ debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */
+#ifdef EINTR
+ if (errno == EINTR) /* Interrupted system call. */
+ continue; /* Try again, up to limit. */
+ else /* Something else. */
+#endif /* EINTR */
+ return(-1); /* Pass along read() error. */
+ }
+#ifdef EINTR
+ else { ok = 1; break; }
+ }
+ if (!ok) return(-1);
+#endif /* EINTR */
+ kbp = kbuf; /* Adjust buffer pointer, */
+ kbc--; /* count, */
+ return((int)(*kbp++) & 0377); /* and return first character. */
+}
+
+/* C O N C L D -- Interactive terminal connection child function */
+
+static
+#ifdef BEOSORBEBOX
+long
+#else
+VOID
+#endif /* BEOSORBEBOX */
+concld (
+#ifdef BEOSORBEBOX
+ void *bevoid
+#endif /* BEOSORBEBOX */
+ ) {
+ int n; /* General purpose counter */
+ int i; /* For loops... */
+ int c = -1; /* c is a character, but must be signed
+ integer to pass thru -1, which is the
+ modem disconnection signal, and is
+ different from the character 0377 */
+ int prev;
+#ifdef TNCODE
+ int tx; /* tn_doop() return code */
+#endif /* TNCODE */
+#ifdef CK_TRIGGER
+ int ix; /* Trigger index */
+#endif /* CK_TRIGGER */
+#ifndef NOESCSEQ
+ int apcrc;
+#endif /* NOESCSEQ */
+
+#ifdef COMMENT
+ int conret = 0; /* Return value from conect() */
+ jbchksum = -1L;
+#endif /* COMMENT */
+ jbset = 0; /* jmp_buf not set yet, don't use it */
+ debug(F101,"CONNECT concld entry","",CK_FORK_SIG);
+ /* *** */ /* Inferior reads, prints port input */
+
+ if (priv_can()) { /* Cancel all privs */
+ printf("?setuid error - fatal\n");
+ doexit(BAD_EXIT,-1);
+ }
+ signal(SIGINT, SIG_IGN); /* In case these haven't been */
+ signal(SIGQUIT, SIG_IGN); /* inherited from above... */
+ signal(CK_FORK_SIG, SIG_IGN); /* CK_FORK_SIG not expected yet */
+
+ inshift = outshift = 0; /* Initial SO/SI shift state. */
+ { /* Wait for parent's setup */
+ int i;
+ while ((i = read(xpipe[0], &c, 1)) <= 0) {
+ if (i < 0) {
+ debug(F101,"CONNECT concld setup error","",i);
+ debug(F111,"CONNECT concld setup error",ck_errstr(),errno);
+ pipemsg(CEV_HUP); /* Read error - hangup */
+ ck_sndmsg(); /* Send and wait to be killed */
+ /* NOTREACHED */
+ } /* Restart interrupted read() */
+ }
+ }
+ close(xpipe[0]); xpipe[0] = -1; /* Child - prevent future reads */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"CONNECT starting port fork","",0);
+ debug(F101,"CONNECT port fork ibc","",ibc);
+ debug(F101,"CONNECT port fork obc","",obc);
+ }
+#endif /* DEBUG */
+ what = W_CONNECT;
+
+ while (1) { /* Fresh read, wait for a character. */
+#ifdef ANYX25
+ if (network && (nettype == NET_SX25)) {
+ bzero(x25ibuf,sizeof(x25ibuf)) ;
+ if ((ibufl = ttxin(MAXIX25,(CHAR *)x25ibuf)) < 0) {
+#ifndef IBMX25
+ if (ibufl == -2) { /* PAD parms changes */
+ pipemsg(CEV_PAD);
+ write(xpipe[1],padparms,MAXPADPARMS);
+ ck_sndmsg();
+ } else {
+#endif /* IBMX25 */
+ if (!quiet)
+ printf("\r\nCommunications disconnect ");
+ dologend();
+ pipemsg(CEV_HUP);
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+#ifndef IBMX25
+ }
+#endif /* IBMX25 */
+ /* pause(); <--- SHOULD BE OBSOLETE NOW! */
+ /* BECAUSE pause() is done inside of ck_sndmsg() */
+ }
+ if (debses) { /* Debugging output */
+ p = x25ibuf ;
+ while (ibufl--) { c = *p++; conol(dbchr(c)); }
+ } else {
+ if (seslog && sessft) /* Binary session log */
+ logchar((char)c); /* Log char before translation */
+
+ if (sosi
+#ifndef NOCSETS
+ || tcsl != tcsr
+#endif /* NOCSETS */
+ ) { /* Character at a time */
+ for (i = 1; i < ibufl; i++) {
+ c = x25ibuf[i] & cmask;
+ if (sosi) { /* Handle SI/SO */
+ if (c == SO) {
+ inshift = 1;
+ continue;
+ } else if (c == SI) {
+ inshift = 0;
+ continue;
+ }
+ if (inshift)
+ c |= 0200;
+ }
+#ifndef NOCSETS
+ if (inesc == ES_NORMAL) {
+#ifdef UNICODE
+ int x;
+ if (unicode == 1) { /* Remote is UTF-8 */
+ x = u_to_b((CHAR)c);
+ if (x == -1)
+ continue;
+ else if (x == -2) { /* LS or PS */
+ inxbuf[0] = CR;
+ inxbuf[1] = LF;
+ inxcount = 2;
+ } else {
+ inxbuf[0] = (unsigned)(x & 0xff);
+ }
+ c = inxbuf[0];
+ } else if (unicode == 2) { /* Local is UTF-8 */
+ inxcount =
+ b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
+ c = inxbuf[0];
+ } else {
+#endif /* UNICODE */
+ if (sxi) c = (*sxi)((CHAR)c);
+ if (rxi) c = (*rxi)((CHAR)c);
+ inxbuf[0] = c;
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ }
+#endif /* NOCSETS */
+ c &= cmdmsk; /* Apply command mask. */
+ conoc(c); /* Output to screen */
+ if (seslog && !sessft) /* and session log */
+ logchar(c);
+ }
+ } else { /* All at once */
+ for (i = 1; i < ibufl; i++)
+ x25ibuf[i] &= (cmask & cmdmsk);
+ conxo(ibufl,x25ibuf);
+ if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl);
+ }
+ }
+ continue;
+
+ } else { /* Not X.25... */
+#endif /* ANYX25 */
+/*
+ Get the next communication line character from our internal buffer.
+ If the buffer is empty, refill it.
+*/
+ prev = c; /* Remember previous character */
+ c = ckcgetc(0); /* Get next character */
+ /* debug(F101,"CONNECT c","",c); */
+ if (c < 0) { /* Failed... */
+ debug(F101,"CONNECT disconnect ibc","",ibc);
+ debug(F101,"CONNECT disconnect obc","",obc);
+ ckcputf(); /* Flush CONNECT output buffer */
+ if (!quiet) {
+ printf("\r\nCommunications disconnect ");
+#ifdef COMMENT
+ if ( c == -3
+#ifdef ultrix
+/* This happens on Ultrix if there's no carrier */
+ && errno != EIO
+#endif /* ultrix */
+#ifdef UTEK
+/* This happens on UTEK if there's no carrier */
+ && errno != EWOULDBLOCK
+#endif /* UTEK */
+ )
+ perror("\r\nCan't read character");
+#endif /* COMMENT */
+ }
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ tthang(); /* Hang up the connection */
+ debug(F111,"CONNECT concld i/o error",ck_errstr(),errno);
+ pipemsg(CEV_HUP);
+ ck_sndmsg(); /* Wait to be killed */
+ }
+#ifdef COMMENT
+/* too much... */
+ debug(F101,"CONNECT ** PORT","",c); /* Got character c OK. */
+#endif /* COMMENT */
+#ifdef TNCODE
+ /* Handle TELNET negotiations... */
+
+ if ((c == NUL) && network && IS_TELNET()) {
+ if (prev == CR) /* Discard <NUL> of <CR><NUL> */
+ if (!TELOPT_U(TELOPT_BINARY))
+ continue;
+ }
+ if ((c == IAC) && network && IS_TELNET()) {
+ int me_bin = TELOPT_ME(TELOPT_BINARY);
+ int u_bin = TELOPT_U(TELOPT_BINARY);
+ debug(F100,"CONNECT got IAC","",0);
+ ckcputf(); /* Dump screen-output buffer */
+ if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
+ if (me_bin != TELOPT_ME(TELOPT_BINARY)) {
+ debug(F101,
+ "CONNECT TELNET me_bin",
+ "",
+ TELOPT_ME(TELOPT_BINARY)
+ );
+ pipemsg(CEV_MEBIN); /* Tell parent */
+ write(xpipe[1],
+ &TELOPT_ME(TELOPT_BINARY),
+ sizeof(TELOPT_ME(TELOPT_BINARY))
+ );
+ ck_sndmsg(); /* Tell the parent fork */
+ } else if (u_bin != TELOPT_U(TELOPT_BINARY)) {
+ debug(F101,
+ "CONNECT TELNET u_bin",
+ "",
+ TELOPT_U(TELOPT_BINARY)
+ );
+ pipemsg(CEV_UBIN); /* Tell parent */
+ write(xpipe[1],
+ &TELOPT_U(TELOPT_BINARY),
+ sizeof(TELOPT_U(TELOPT_BINARY))
+ );
+ ck_sndmsg(); /* Tell the parent fork */
+ }
+ continue;
+ } else if (tx == -1) { /* I/O error */
+ if (!quiet)
+ printf("\r\nCommunications disconnect ");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
+ pipemsg(CEV_HUP);
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+ } else if (tx == -3) { /* I/O error */
+ if (!quiet)
+ printf("\r\nConnection closed due to telnet policy ");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
+ pipemsg(CEV_HUP);
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+ } else if (tx == -2) { /* I/O error */
+ if (!quiet)
+ printf("\r\nConnection closed by peer ");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ dologend();
+ debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
+ pipemsg(CEV_HUP);
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+ } else if ((tx == 1) && (!duplex)) { /* ECHO change */
+ duplex = 1; /* Turn on local echo */
+ debug(F101,"CONNECT TELNET duplex change","",duplex);
+ pipemsg(CEV_DUP); /* Tell parent */
+ write(xpipe[1], &duplex, sizeof(duplex));
+ ck_sndmsg(); /* Tell the parent fork */
+ continue;
+ } else if ((tx == 2) && (duplex)) { /* ECHO change */
+ duplex = 0;
+ debug(F101,"CONNECT TELNET duplex change","",duplex);
+ pipemsg(CEV_DUP);
+ write(xpipe[1], &duplex, sizeof(duplex));
+ ck_sndmsg();
+ continue;
+ } else if (tx == 3) { /* Quoted IAC */
+ c = parity ? 127 : 255;
+ }
+#ifdef IKS_OPTION
+ else if (tx == 4) { /* IKS State Change */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
+ !tcp_incoming
+ ) {
+ /* here we need to print a msg that the other */
+ /* side is in SERVER mode and that REMOTE */
+ /* commands should be used. And CONNECT mode */
+ /* should be ended. */
+ active = 0;
+ }
+ }
+#endif /* IKS_OPTION */
+ else if (tx == 6) {
+ /* DO LOGOUT received */
+ if (!quiet)
+ printf("\r\nRemote Logout ");
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+ debug(F100,"CONNECT Remote Logout","",0);
+ pipemsg(CEV_HUP);
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+ } else
+ continue; /* Negotiation OK, get next char. */
+
+ } else if (parity)
+ c &= 0x7f;
+
+ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
+ ttoc(c); /* I'm echoing for the remote */
+#endif /* TNCODE */
+
+ if (debses) { /* Output character to screen */
+ char *s; /* Debugging display... */
+ s = dbchr(c);
+ while (*s)
+ ckcputc(*s++);
+ } else { /* Regular display ... */
+ c &= cmask; /* Apply Kermit-to-remote mask */
+#ifdef CK_AUTODL
+/*
+ Autodownload. Check for Kermit S packet prior to translation, since that
+ can change the packet and make it unrecognizable (as when the terminal
+ character set is an ISO 646 one)... Ditto for Zmodem start packet.
+*/
+ if (autodl /* Autodownload enabled? */
+#ifdef IKS_OPTION
+ || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+#endif /* IKS_OPTION */
+ ) {
+ int k;
+ k = kstart((CHAR)c); /* Kermit S or I packet? */
+#ifdef CK_XYZ
+ if (!k && zmdlok) /* Or an "sz" start? */
+ k = zstart((CHAR)c);
+#endif /* CK_XYZ */
+ if (k) {
+ int ksign = 0;
+ debug(F101,"CONNECT autodownload k","",k);
+ if (k < 0) { /* Minus-Protocol? */
+#ifdef NOSERVER
+ goto noserver; /* Need server mode for this */
+#else
+ ksign = 1; /* Remember */
+ k = 0 - k; /* Convert to actual protocol */
+ justone = 1; /* Flag for protocol module */
+#endif /* NOSERVER */
+ } else
+ justone = 0;
+ k--; /* Adjust [kz]start's return value */
+ if (k == PROTO_K
+#ifdef CK_XYZ
+ || k == PROTO_Z
+#endif /* CK_XYZ */
+ ) {
+
+ /* Now damage the packet so that it does not */
+ /* trigger autodownload detection on subsquent */
+ /* links. */
+
+ if (k == PROTO_K) {
+ int i, len = strlen((char*)ksbuf);
+ for (i = 0; i < len; i++)
+ ckcputc(BS);
+ }
+#ifdef CK_XYZ
+ else {
+ int i;
+ for (i = 0; i < 3; i++)
+ ckcputc(CAN);
+ }
+#endif /* CK_XYZ */
+ /* Notify parent */
+ pipemsg(justone ? CEV_AUL : CEV_ADL);
+/*
+ Send our memory back up to the top fork thru the pipe.
+ CAREFUL -- Write this stuff in the same order it is to be read!
+*/
+ /* Copy our Kermit packet to the parent fork */
+ n = (int) strlen((char *)ksbuf);
+ write(xpipe[1], (char *)&n, sizeof(n));
+ if (n > 0)
+ write(xpipe[1], (char *)ksbuf, n+1);
+ debug(F111,"CONNECT autodownload ksbuf",ksbuf,n);
+ debug(F101,"CONNECT autodownload justone","",
+ justone);
+ /* Construct the APC command */
+ sprintf(apcbuf,
+ "set proto %s, %s, set proto %s",
+ ptab[k].p_name,
+ ksign ? "server" : "receive",
+ ptab[protocol].p_name
+ );
+ apclength = strlen(apcbuf);
+ debug(F111,"CONNECT ksbuf",ksbuf,k);
+ debug(F110,"CONNECT autodownload",apcbuf,0);
+ apcactive = APC_LOCAL;
+ ckcputf(); /* Force screen update */
+
+ /* Write buffer including trailing NUL byte */
+ debug(F101,"CONNECT write xpipe apclength","",
+ apclength);
+ write(xpipe[1],
+ (char *)&apclength,
+ sizeof(apclength)
+ );
+ debug(F110,"CONNECT write xpipe apcbuf",apcbuf,0);
+ write(xpipe[1], apcbuf, apclength+1);
+
+ /* Copy our input buffer to the parent fork */
+
+ debug(F101,"CONNECT autodownload complete ibc",
+ "",ibc);
+ debug(F101,"CONNECT autodownload complete obc",
+ "",obc);
+ write(xpipe[1], (char *)&ibc, sizeof(ibc));
+ if (ibc > 0) {
+ write(xpipe[1], (char *)&ibp, sizeof(ibp));
+ write(xpipe[1], ibp, ibc);
+ }
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+ }
+ }
+ }
+#ifdef NOSERVER
+ noserver:
+#endif /* NOSERVER */
+#endif /* CK_AUTODL */
+ if (sosi) { /* Handle SI/SO */
+ if (c == SO) { /* Shift Out */
+ inshift = 1;
+ continue;
+ } else if (c == SI) { /* Shift In */
+ inshift = 0;
+ continue;
+ }
+ if (inshift) c |= 0200;
+ }
+ inxbuf[0] = c; /* In case there is no translation */
+ inxcount = 1; /* ... */
+#ifndef NOCSETS
+ if (inesc == ES_NORMAL) { /* If not in an escape sequence */
+#ifdef UNICODE
+ int x; /* Translate character sets */
+ CHAR ch;
+ ch = c;
+ if (unicode == 1) { /* Remote is UTF-8 */
+ x = u_to_b(ch);
+ if (x < 0)
+ continue;
+ inxbuf[0] = (unsigned)(x & 0xff);
+ c = inxbuf[0];
+ } else if (unicode == 2) { /* Local is UTF-8 */
+ inxcount = b_to_u(ch,inxbuf,OUTXBUFSIZ,tcssize);
+ c = inxbuf[0];
+ } else {
+#endif /* UNICODE */
+ if (sxi) c = (*sxi)((CHAR)c);
+ if (rxi) c = (*rxi)((CHAR)c);
+ inxbuf[0] = c;
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ }
+#endif /* NOCSETS */
+
+#ifndef NOESCSEQ
+ if (escseq) /* If handling escape sequences */
+ apcrc = chkaes((char)c); /* update our state */
+#ifdef CK_APC
+/*
+ If we are handling APCs, we have several possibilities at this point:
+ 1. Ordinary character to be written to the screen.
+ 2. An Esc; we can't write it because it might be the beginning of an APC.
+ 3. The character following an Esc, in which case we write Esc, then char,
+ but only if we have not just entered an APC sequence.
+*/
+ if (escseq && (apcstatus & APC_ON)) {
+ if (inesc == ES_GOTESC) /* Don't write ESC yet */
+ continue;
+ else if (oldesc == ES_GOTESC && !apcactive) {
+ ckcputc(ESC); /* Write saved ESC */
+ if (seslog && !sessft)
+ logchar((char)ESC);
+ } else if (apcrc) { /* We have an APC */
+ debug(F111,"CONNECT APC complete",apcbuf,apclength);
+ ckcputf(); /* Force screen update */
+ pipemsg(CEV_APC); /* Notify parent */
+ write(xpipe[1],
+ (char *)&apclength,
+ sizeof(apclength)
+ );
+ /* Write buffer including trailing NUL byte */
+
+ write(xpipe[1], apcbuf, apclength+1);
+
+ /* Copy our input buffer to the parent fork */
+
+ debug(F101,"CONNECT APC complete ibc","",ibc);
+ debug(F101,"CONNECT APC complete obc","",obc);
+ write(xpipe[1], (char *)&ibc, sizeof(ibc));
+ if (ibc > 0) {
+ write(xpipe[1], (char *)&ibp, sizeof(ibp));
+ write(xpipe[1], ibp, ibc);
+ }
+ ck_sndmsg(); /* Wait to be killed */
+ /* NOTREACHED */
+ }
+ }
+#endif /* CK_APC */
+#endif /* NOESCSEQ */
+
+ for (i = 0; i < inxcount; i++) { /* Loop thru */
+ c = inxbuf[i]; /* input expansion buffer... */
+ if (
+#ifdef CK_APC
+ !apcactive /* Ignore APC sequences */
+#else
+ 1
+#endif /* CK_APC */
+ ) {
+ c &= cmdmsk; /* Apply command mask. */
+ if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
+ ckcputc(c); /* Yes, output CR */
+ if (seslog && !sessft)
+ logchar((char)c);
+ c = LF; /* and insert a linefeed */
+ }
+ if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */
+ ckcputc(CR); /* Yes, output CR */
+ if (seslog && !sessft) logchar((char)CR);
+ }
+ ckcputc(c); /* Write character to screen */
+ }
+ if (seslog && !sessft) /* Handle session log */
+ logchar((char)c);
+#ifdef CK_TRIGGER
+ /* Check for trigger string */
+ if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) {
+ ckcputf(); /* Force screen update */
+#ifdef NOSETBUF
+ fflush(stdout); /* I mean really force it */
+#endif /* NOSETBUF */
+ pipemsg(CEV_TRI); /* Send up trigger indication */
+ write(xpipe[1], (char *)&ix, sizeof(ix)); /* index */
+ write(xpipe[1], (char *)&ibc, sizeof(ibc));
+ if (ibc > 0) {
+ write(xpipe[1], (char *)&ibp, sizeof(ibp));
+ write(xpipe[1], ibp, ibc);
+ }
+ debug(F100,"CONNECT concld trigger","",0);
+ ck_sndmsg(); /* Wait to be killed */
+ active = 0; /* Shouldn't be necessary... */
+ break;
+ }
+ /* NOTREACHED */
+#endif /* CK_TRIGGER */
+ }
+ }
+#ifdef ANYX25
+ }
+#endif /* ANYX25 */
+ }
+}
+
+
+/* C O N E C T -- Interactive terminal connection */
+
+int
+conect() {
+ int n; /* General purpose counter */
+ int i; /* For loops... */
+ int c; /* c is a character, but must be signed
+ integer to pass thru -1, which is the
+ modem disconnection signal, and is
+ different from the character 0377 */
+ int c2; /* A copy of c */
+ int csave; /* Another copy of c */
+#ifndef NOESCSEQ
+ int apcrc;
+#endif /* NOESCSEQ */
+
+ int conret = 0; /* Return value from conect() */
+ int msgflg = 0;
+ /* jbchksum = -1L; */
+ jbset = 0; /* jmp_buf not set yet, don't use it */
+ debok = 1;
+
+ debug(F101,"CONNECT fork signal","",CK_FORK_SIG);
+ debug(F101,"CONNECT entry pid","",pid);
+
+ msgflg = !quiet
+#ifdef CK_APC
+ && !apcactive
+#endif /* CK_APC */
+ ;
+/*
+ The following is to handle a fork left behind if we exit CONNECT mode
+ without killing it, and then return to CONNECT mode. This happened in
+ HP-UX, where the Reset key would raise SIGINT even though SIGINT was set to
+ SIG_IGN. The code below fixes the symptom; the real fix is in the main
+ SIGINT handler (if SIGINT shows up during CONNECT, just return rather than
+ taking the longjmp).
+*/
+ if (pid) { /* This should be 0 */
+ int x = 0;
+ debug(F101,"CONNECT entry killing stale pid","",pid);
+ printf("WARNING: Old CONNECT fork seems to be active.\n");
+ printf("Attempting to remove it...");
+#ifdef BEOSORBEBOX
+ {
+ long ret_val;
+ x = kill(pid,SIGKILLTHR); /* Kill lower fork */
+ wait_for_thread (pid, &ret_val);
+ }
+#else
+#ifdef Plan9
+ x = kill(pid,SIGKILL); /* Kill lower fork */
+#else
+ x = kill(pid,9);
+#endif /* Plan9 */
+#endif /* BEOSORBEBOX */
+ wait((WAIT_T *)0); /* Wait till gone. */
+ if (x < 0) {
+ printf("ERROR: Failure to kill pid %d: %s, errno=%d\n",
+ (int) pid, ck_errstr(), errno);
+ debug(F111,"CONNECT error killing stale pid",ck_errstr(),pid);
+ }
+ pid = (PID_T) 0;
+ printf("\n");
+ }
+ signal(CK_FORK_SIG, SIG_IGN); /* Initial CK_FORK_SIG handling, */
+/*
+ The following ttimoff() call should not be necessary, but evidently there
+ are cases where a timer is left active and then goes off, taking a longjmp
+ to nowhere after the program's stack has changed. In any case, this is
+ safe because the CONNECT module uses no timer of any kind, and no other timer
+ should be armed while Kermit is in CONNECT mode.
+*/
+ ttimoff(); /* Turn off any timer interrupts */
+
+#ifdef CK_TRIGGER
+ makestr(&triggerval,NULL); /* Reset trigger */
+#endif /* CK_TRIGGER */
+
+ if (!local) {
+#ifdef NETCONN
+ printf("Sorry, you must SET LINE or SET HOST first\n");
+#else
+ printf("Sorry, you must SET LINE first\n");
+#endif /* NETCONN */
+ goto conret0;
+ }
+ if (speed < 0L && network == 0 && ttfdflg == 0) {
+ printf("Sorry, you must SET SPEED first\n");
+ goto conret0;
+ }
+#ifdef TCPSOCKET
+ if (network && (nettype != NET_TCPB)
+#ifdef SUNX25
+ && (nettype != NET_SX25)
+#endif /* SUNX25 */
+#ifdef IBMX25
+ && (nettype != NET_IX25)
+#endif /* IBMX25 */
+#ifdef NETCMD
+ && (nettype != NET_CMD)
+#endif /* NETCMD */
+#ifdef NETPTY
+ && (nettype != NET_PTY)
+#endif /* NETPTY */
+ ) {
+ printf("Sorry, network type not supported\n");
+ goto conret0;
+ }
+#endif /* TCPSOCKET */
+
+#ifdef DYNAMIC
+ if (!ibuf) {
+ if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
+ printf("Sorry, CONNECT input buffer can't be allocated\n");
+ goto conret0;
+ } else {
+ ibp = ibuf;
+ ibc = 0;
+ }
+ }
+ if (!obuf) {
+ if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
+ printf("Sorry, CONNECT output buffer can't be allocated\n");
+ goto conret0;
+ } else {
+ obp = obuf;
+ obc = 0;
+ }
+ }
+ if (!kbuf) {
+ if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
+ printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
+ goto conret0;
+ }
+ }
+ if (!temp) {
+ if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
+ printf("Sorry, CONNECT temporary buffer can't be allocated\n");
+ goto conret0;
+ }
+ }
+#else
+#ifdef COMMENT
+ ibp = ibuf;
+ ibc = 0;
+#endif /* COMMENT */
+ obp = obuf;
+ obc = 0;
+#endif /* DYNAMIC */
+
+ kbp = kbuf; /* Always clear these. */
+ *kbp = NUL; /* No need to preserve them between */
+ kbc = 0; /* CONNECT sessions. */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
+ debug(F101,"CONNECT conect entry ibc","",ibc);
+ debug(F101,"CONNECT conect entry obc","",obc);
+ debug(F101,"CONNECT conect entry kbc","",kbc);
+#ifdef CK_TRIGGER
+ debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
+#endif /* CK_TRIGGER */
+ if (ttyfd > -1) {
+ n = ttchk();
+ debug(F101,"CONNECT conect entry ttchk","",n);
+ }
+ }
+#endif /* DEBUG */
+
+ if (ttyfd < 0) { /* If communication device not open */
+ debug(F101,"CONNECT ttnproto","",ttnproto);
+ debug(F111,"CONNECT opening",ttname,0); /* Open it now */
+ if (ttopen(ttname,
+ &local,
+ network ? -nettype : mdmtyp,
+ 0
+ ) < 0) {
+ ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
+ perror(temp);
+ debug(F110,"CONNECT open failure",ttname,0);
+ goto conret0;
+ }
+#ifdef IKS_OPTION
+ /* If peer is in Kermit server mode, return now. */
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
+ return(0);
+#endif /* IKS_OPTION */
+ }
+ dohangup = 0; /* Hangup not requested yet */
+#ifdef ANYX25
+ dox25clr = 0; /* X.25 clear not requested yet */
+#endif /* ANYX25 */
+
+ if (msgflg) {
+#ifdef NETCONN
+ if (network) {
+ if (ttpipe)
+ printf("Connecting via command \"%s\"",ttname);
+ else
+ printf("Connecting to host %s",ttname);
+#ifdef ANYX25
+ if (nettype == NET_SX25 || nettype == NET_IX25)
+ printf(", Link ID %d, LCN %d",linkid,lcn);
+#endif /* ANYX25 */
+ } else {
+#endif /* NETCONN */
+ printf("Connecting to %s",ttname);
+ if (speed > -1L) printf(", speed %ld",speed);
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+ if (tt_escape) {
+ printf("\r\n");
+ shoesc(escape);
+ printf("Type the escape character followed by C to get back,\r\n");
+ printf("or followed by ? to see other options.\r\n");
+ } else {
+ printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
+ }
+ if (seslog) {
+ extern int slogts;
+ char * s = "";
+ switch (sessft) {
+ case XYFT_D:
+ s = "debug"; break;
+ case XYFT_T:
+ s = slogts ? "timestamped-text" : "text"; break;
+ default:
+ s = "binary";
+ }
+ printf("Session Log: %s, %s\r\n",sesfil,s);
+ }
+ if (debses) printf("Debugging Display...)\r\n");
+ printf("----------------------------------------------------\r\n");
+ fflush(stdout);
+ }
+
+/* Condition console terminal and communication line */
+
+ if (conbin((char)escape) < 0) {
+ printf("Sorry, can't condition console terminal\n");
+ goto conret0;
+ }
+ debug(F101,"CONNECT cmask","",cmask);
+ debug(F101,"CONNECT cmdmsk","",cmdmsk);
+ debug(F101,"CONNECT speed before ttvt","",speed);
+ if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */
+ if (!network) {
+ debug(F101,"CONNECT ttvt","",n);
+ tthang(); /* Hang up and close the device. */
+ ttclos(0);
+ dologend();
+ if (ttopen(ttname, /* Open it again... */
+ &local,
+ network ? -nettype : mdmtyp,
+ 0
+ ) < 0) {
+ ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
+ perror(temp);
+ goto conret0;
+ }
+#ifdef IKS_OPTION
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
+ return(0);
+#endif /* IKS_OPTION */
+ if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
+ conres(); /* Failure this time is fatal. */
+ printf("Sorry, Can't condition communication line\n");
+ goto conret0;
+ }
+ }
+ }
+ debug(F101,"CONNECT ttvt ok, escape","",escape);
+
+ debug(F101,"CONNECT carrier-watch","",carrier);
+ if ((!network
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) && (carrier != CAR_OFF)) {
+ int x;
+ x = ttgmdm();
+ debug(F100,"CONNECT ttgmdm","",x);
+ if ((x > -1) && !(x & BM_DCD)) {
+#ifndef NOHINTS
+ extern int hints;
+#endif /* NOHINTS */
+ debug(F100,"CONNECT ttgmdm CD test fails","",x);
+ conres();
+ printf("?Carrier required but not detected.\n");
+#ifndef NOHINTS
+ if (!hints)
+ return(0);
+ printf("***********************************\n");
+ printf(" Hint: To CONNECT to a serial device that\n");
+ printf(" is not presenting the Carrier Detect signal,\n");
+ printf(" first tell C-Kermit to:\n\n");
+ printf(" SET CARRIER-WATCH OFF\n\n");
+ printf("***********************************\n\n");
+#endif /* NOHINTS */
+ goto conret0;
+ }
+ debug(F100,"CONNECT ttgmdm ok","",0);
+ }
+#ifndef NOCSETS
+/* Set up character set translations */
+
+ unicode = 0; /* Assume Unicode won't be involved */
+ tcs = 0; /* "Transfer" or "Other" charset */
+ sxo = rxo = NULL; /* Initialize byte-to-byte functions */
+ sxi = rxi = NULL;
+ if (tcsr != tcsl) { /* Remote and local sets differ... */
+#ifdef UNICODE
+ if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */
+ tcsl == FC_UTF8) { /* or local one is. */
+ xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */
+ if (xuf || tcsl == FC_UTF8) {
+ tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
+ xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */
+ if (xfu)
+ unicode = (tcsr == FC_UTF8) ? 1 : 2;
+ }
+ tcssize = fcsinfo[tcs].size; /* Size of other character set. */
+ } else {
+#endif /* UNICODE */
+ tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
+ sxo = xls[tcs][tcsl]; /* translation function */
+ rxo = xlr[tcs][tcsr]; /* pointers for output functions */
+ sxi = xls[tcs][tcsr]; /* and for input functions. */
+ rxi = xlr[tcs][tcsl];
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ }
+/*
+ This is to prevent use of zmstuff() and zdstuff() by translation functions.
+ They only work with disk i/o, not with communication i/o. Luckily Russian
+ translation functions don't do any stuffing...
+*/
+ langsv = language;
+#ifndef NOCYRIL
+ if (language != L_RUSSIAN)
+#endif /* NOCYRIL */
+ language = L_USASCII;
+
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"CONNECT tcs","",tcs);
+ debug(F101,"CONNECT tcsl","",tcsl);
+ debug(F101,"CONNECT tcsr","",tcsr);
+ debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
+ debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
+ debug(F101,"CONNECT unicode","",unicode);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+
+#ifdef CK_XYZ
+#ifndef XYZ_INTERNAL
+ {
+ extern int binary; /* See about ZMODEM autodownloads */
+ char * s;
+ s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
+ if (!s) s = "";
+ zmdlok = (*s != NUL); /* OK if we have external commands */
+ }
+#endif /* XYZ_INTERNAL */
+#endif /* CK_XYZ */
+
+#ifndef NOESCSEQ
+/*
+ We need to activate the escape-sequence recognition feature when:
+ (a) translation is elected, AND
+ (b) the local and/or remote set is a 7-bit set other than US ASCII.
+ Or:
+ SET TERMINAL APC is not OFF (handled in the next statement).
+*/
+ escseq = (tcs != TC_TRANSP) && /* Not transparent */
+ (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
+ (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
+#endif /* NOESCSEQ */
+#endif /* NOCSETS */
+
+#ifndef NOESCSEQ
+#ifdef CK_APC
+ escseq = escseq || (apcstatus & APC_ON);
+ apcactive = 0; /* An APC command is not active */
+ apclength = 0; /* ... */
+#endif /* CK_APC */
+ inesc = ES_NORMAL; /* Initial state of recognizer */
+ debug(F101,"CONNECT escseq","",escseq);
+#endif /* NOESCSEQ */
+
+ parent_id = getpid(); /* Get parent's pid for signalling */
+ debug(F101,"CONNECT parent pid","",parent_id);
+
+ if (xpipe[0] > -1) /* If old pipe hanging around, close */
+ close(xpipe[0]);
+ xpipe[0] = -1;
+ if (xpipe[1] > -1)
+ close(xpipe[1]);
+ xpipe[1] = -1;
+ goterr = 0; /* Error flag for pipe & fork */
+ if (pipe(xpipe) != 0) { /* Create new pipe to pass info */
+ perror("Can't make pipe"); /* between forks. */
+ debug(F101,"CONNECT pipe error","",errno);
+ goterr = 1;
+ } else
+#ifdef BEOSORBEBOX
+ {
+ pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL);
+ resume_thread(pid);
+ }
+#else
+ if ((pid = fork()) == (PID_T) -1) { /* Pipe OK, make port fork. */
+ perror("Can't make port fork");
+ debug(F101,"CONNECT fork error","",errno);
+ goterr = 1;
+ }
+#endif /* BEOSORBEBOX */
+ debug(F101,"CONNECT created fork, pid","",pid);
+ if (goterr) { /* Failed to make pipe or fork */
+ conres(); /* Reset the console. */
+ if (msgflg) {
+ printf("\r\nCommunications disconnect (Back at %s)\r\n",
+ *myhost ?
+ myhost :
+#ifdef UNIX
+ "local UNIX system"
+#else
+ "local system"
+#endif /* UNIX */
+ );
+ }
+ printf("\n");
+ what = W_NOTHING; /* So console modes are set right. */
+#ifndef NOCSETS
+ language = langsv; /* Restore language */
+#endif /* NOCSETS */
+ parent_id = (PID_T) 0; /* Clean up */
+ goto conret1;
+ }
+ debug(F101,"CONNECT fork pid","",pid);
+
+/* Upper fork (KEYB fork) reads keystrokes and sends them out. */
+
+ if (pid) { /* pid != 0, so I am the upper fork. */
+/*
+ Before doing anything significant, the child fork must wait for a go-ahead
+ character from xpipe[0]. Before starting to wait, we have enough time to
+ clear buffers and set up the signal handler. When done with this, we will
+ allow the child to continue by satisfying its pending read.
+
+ Remember the child and parent have separate address space. The child has
+ its own copy of input buffers, so we must clear the input buffers in the
+ parent. Otherwise strange effects may occur, like chunks of characters
+ repeatedly echoed on terminal screen. The child process is designed to
+ empty its input buffers by reading all available characters and either
+ echoing them on the terminal screen or saving them for future use in the
+ parent. The latter case happens during APC processing - see the code around
+ CEV_APC occurrences to see how the child passes its ibuf etc to parent via
+ xpipe, for preservation until the next entry to this module, to ensure that
+ no characters are lost between CONNECT sessions.
+*/
+
+/*
+ This one needs a bit of extra explanation... In addition to the CONNECT
+ module's own buffers, which are communicated and synchronized via xpipe,
+ the low-level UNIX communication routines (ttinc, ttxin, etc) are also
+ buffered, statically, in the ckutio.c module. But when the two CONNECT
+ forks split off, the lower fork is updating this buffer's pointers and
+ counts, but the upper fork never finds out about it and still has the old
+ ones. The following UNIX-specific call to the ckutio.c module takes care
+ of this... Without it, we get dual echoing of incoming characters.
+*/
+ ttflux();
+/*
+ At this point, perhaps you are wondering why we use forks at all. It is
+ simply because there is no other method portable among all UNIX variations.
+ Not threads, not select(), ... (Yes, select() is more common now; it might
+ actually be worth writing a variation of this module that works like BSD
+ Telnet, one fork, driven by select()).
+*/
+ ibp = ibuf; /* Clear ibuf[]. */
+ ibc = 0; /* Child now has its own copy */
+ signal(CK_FORK_SIG, pipeint); /* Handler for messages from child. */
+ write(xpipe[1], ibuf, 1); /* Allow child to proceed */
+ close(xpipe[1]); xpipe[1] = -1; /* Parent - prevent future writes */
+
+ what = W_CONNECT; /* Keep track of what we're doing */
+ active = 1;
+ debug(F101,"CONNECT keyboard fork duplex","",duplex);
+/*
+ Catch communication errors or mode changes in lower fork.
+
+ Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
+ about setjmp() in a way that disallows constructions like:
+
+ if ((var = [sig]setjmp(env)) == 0) ...
+
+ which prevents the value returned by cklongjmp() from being used at all.
+ So the signal handlers set a global variable, sjval, instead.
+*/
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(con_env,1)
+#else
+ setjmp(con_env)
+#endif /* CK_POSIX_SIG */
+ == 0) { /* Normal entry... */
+ jbset = 1; /* Now we have a longjmp buffer */
+ sjval = CEV_NO; /* Initialize setjmp return code. */
+
+ debug(F101,"CONNECT setjmp normal entry","",sjval);
+
+#ifdef ANYX25
+ if (network && (nettype == NET_SX25 || nettype == NET_IX25)) {
+ obufl = 0;
+ bzero (x25obuf,sizeof(x25obuf));
+ }
+#endif /* ANYX25 */
+/*
+ Here is the big loop that gets characters from the keyboard and sends them
+ out the communication device. There are two components to the communication
+ path: the connection from the keyboard to C-Kermit, and from C-Kermit to
+ the remote computer. The treatment of the 8th bit of keyboard characters
+ is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit
+ of characters sent to the remote is governed by SET TERMINAL BYTESIZE
+ (cmask). This distinction was introduced in edit 5A(164).
+*/
+ while (active) {
+#ifndef NOSETKEY
+ if (kmptr) { /* Have current macro? */
+ debug(F100,"CONNECT kmptr non NULL","",0);
+ if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
+ kmptr = NULL; /* If no more chars, */
+ debug(F100,"CONNECT macro empty, continuing","",0);
+ continue; /* reset pointer and continue */
+ }
+ debug(F000,"CONNECT char from macro","",c);
+ } else /* No macro... */
+#endif /* NOSETKEY */
+ c = CONGKS(); /* Read from keyboard */
+
+#ifdef COMMENT
+/* too much... */
+ debug(F101,"CONNECT ** KEYB","",c);
+#endif /* COMMENT */
+ if (c == -1) { /* If read() got an error... */
+ debug(F101,"CONNECT keyboard read errno","",errno);
+#ifdef COMMENT
+/*
+ This seems to cause problems. If read() returns -1, the signal has already
+ been delivered, and nothing will wake up the pause().
+*/
+ pause(); /* Wait for transmitter to finish. */
+#else
+#ifdef A986
+/*
+ On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
+ here (reason unknown). The console line discipline at this point has
+ intr = ^C. The communications tty has intr = DEL but we get here after
+ pressing DEL on the keyboard, even when the remote system has been set not
+ to echo. With A986 defined, we stay in the read loop and beep only if the
+ offending character is not DEL.
+*/
+ if ((c & 127) != 127) conoc(BEL);
+#else
+#ifdef EINTR
+/*
+ This can be caused by the other fork signalling this one about
+ an echoing change during TELNET negotiations.
+*/
+ if (errno == EINTR)
+ continue;
+#endif /* EINTR */
+ conoc(BEL); /* Otherwise, beep */
+ active = 0; /* and terminate the read loop */
+ continue;
+#endif /* A986 */
+#endif /* COMMENT */
+ }
+ c &= cmdmsk; /* Do any requested masking */
+#ifndef NOSETKEY
+/*
+ Note: kmptr is NULL if we got character c from the keyboard, and it is
+ not NULL if it came from a macro. In the latter case, we must avoid
+ expanding it again.
+*/
+ if (!kmptr && macrotab[c]) { /* Macro definition for c? */
+ kmptr = macrotab[c]; /* Yes, set up macro pointer */
+ continue; /* and restart the loop, */
+ } else c = keymap[c]; /* else use single-char keymap */
+#endif /* NOSETKEY */
+ if (
+#ifndef NOSETKEY
+ !kmptr &&
+#endif /* NOSETKEY */
+ (tt_escape && (c & 0xff) == escape)) { /* Escape char? */
+ debug(F000,"CONNECT got escape","",c);
+ c = CONGKS() & 0177; /* Got esc, get its arg */
+ /* No key mapping here */
+ doesc((char) c); /* Now process it */
+
+ } else { /* It's not the escape character */
+ csave = c; /* Save it before translation */
+ /* for local echoing. */
+#ifndef NOCSETS
+ if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
+ /* Translate character sets */
+#ifdef UNICODE
+ int x;
+ CHAR ch;
+ ch = c;
+ if (unicode == 1) { /* Remote is UTF-8 */
+ outxcount = b_to_u(ch,outxbuf,OUTXBUFSIZ,tcssize);
+ outxbuf[outxcount] = NUL;
+ } else if (unicode == 2) { /* Local is UTF-8 */
+ x = u_to_b(ch); /* So translate to remote byte */
+ if (x < 0)
+ continue;
+ outxbuf[0] = (unsigned)(x & 0xff);
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+ } else {
+#endif /* UNICODE */
+ /* Local-to-intermediate */
+ if (sxo) c = (*sxo)((char)c);
+ /* Intermediate-to-remote */
+ if (rxo) c = (*rxo)((char)c);
+ outxbuf[0] = c;
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+#ifdef UNICODE
+ }
+#endif /* UNICODE */
+ }
+ if (escseq)
+ apcrc = chkaes((char)c);
+#else
+ outxbuf[0] = c;
+ outxcount = 1;
+ outxbuf[outxcount] = NUL;
+#endif /* NOCSETS */
+ for (i = 0; i < outxcount; i++) {
+ c = outxbuf[i];
+/*
+ If Shift-In/Shift-Out is selected and we have a 7-bit connection,
+ handle shifting here.
+*/
+ if (sosi) { /* Shift-In/Out selected? */
+ if (cmask == 0177) { /* In 7-bit environment? */
+ if (c & 0200) { /* 8-bit character? */
+ if (outshift == 0) { /* If not shifted, */
+ ttoc(dopar(SO)); /* shift. */
+ outshift = 1;
+ }
+ } else {
+ if (outshift == 1) { /* 7-bit character */
+ ttoc(dopar(SI)); /* If shifted, */
+ outshift = 0; /* unshift. */
+ }
+ }
+ }
+ if (c == SO) outshift = 1; /* User typed SO */
+ if (c == SI) outshift = 0; /* User typed SI */
+ }
+ c &= cmask; /* Apply Kermit-to-host mask now. */
+#ifdef SUNX25
+ if (network && nettype == NET_SX25) {
+ if (padparms[PAD_ECHO]) {
+ if (debses)
+ conol(dbchr(c)) ;
+ else
+ if ((c != padparms[PAD_CHAR_DELETE_CHAR]) &&
+ (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
+ (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
+ conoc(c) ;
+ if (seslog && !sessft)
+ logchar(c);
+ }
+ if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
+ padparms[PAD_LF_AFTER_CR] == 5)) {
+ if (debses)
+ conol(dbchr(LF)) ;
+ else
+ conoc(LF) ;
+ if (seslog && !sessft)
+ logchar(LF);
+ }
+ if (c == padparms[PAD_BREAK_CHARACTER]) {
+ breakact();
+ } else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
+ tosend = 1;
+ x25obuf [obufl++] = c;
+ } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])||
+ (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
+ (c == padparms[PAD_BUFFER_DISPLAY_CHAR]))
+ && (padparms[PAD_EDITING])) {
+ if (c == padparms[PAD_CHAR_DELETE_CHAR]) {
+ if (obufl > 0) {
+ conol("\b \b"); obufl--;
+ } else {}
+ } else if
+ (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
+ conol ("\r\nPAD Buffer Deleted\r\n");
+ obufl = 0;
+ } else if
+ (c==padparms[PAD_BUFFER_DISPLAY_CHAR]) {
+ conol("\r\n");
+ conol(x25obuf);
+ conol("\r\n");
+ } else {}
+ } else {
+ x25obuf [obufl++] = c;
+ if (obufl == MAXOX25) tosend = 1;
+ else if (c == CR) tosend = 1;
+ }
+ if (tosend) {
+ if (ttol((CHAR *)x25obuf,obufl) < 0) {
+ perror ("\r\nCan't send characters");
+ active = 0;
+ } else {
+ bzero (x25obuf,sizeof(x25obuf));
+ obufl = 0;
+ tosend = 0;
+ }
+ } else {};
+ } else {
+#endif /* SUNX25 */
+ if (c == '\015') { /* Carriage Return */
+ int stuff = -1;
+ if (tnlm) { /* TERMINAL NEWLINE ON */
+ stuff = LF; /* Stuff LF */
+#ifdef TNCODE
+ } else if (network && /* TELNET NEWLINE */
+ IS_TELNET()) {
+ switch (!TELOPT_ME(TELOPT_BINARY) ?
+ tn_nlm :
+ tn_b_nlm
+ ) {
+ case TNL_CRLF:
+ stuff = LF;
+ break;
+ case TNL_CRNUL:
+ stuff = NUL;
+ break;
+ }
+#endif /* TNCODE */
+ }
+ if (stuff > -1) {
+ ttoc(dopar('\015')); /* Send CR */
+ if (duplex) conoc('\015'); /* Echo CR */
+ c = stuff; /* Char to stuff */
+ csave = c;
+ }
+ }
+#ifdef TNCODE
+/* If user types the 0xff character (TELNET IAC), it must be doubled. */
+ else /* Not CR */
+ if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
+ network && IS_TELNET()) {
+ /* Send one copy now */
+ /* and the other one just below. */
+ ttoc((char)IAC);
+ }
+#endif /* TNCODE */
+ /* Send the character */
+
+ if (ttoc((char)dopar((CHAR) c)) > -1) {
+ if (duplex) { /* If half duplex, must echo */
+ if (debses)
+ conol(dbchr(csave)); /* original char */
+ else /* not the translated one */
+ conoc((char)csave);
+ if (seslog) { /* And maybe log it too */
+ c2 = csave;
+ if (sessft == 0 && csave == '\r')
+ c2 = '\n';
+ logchar((char)c2);
+ }
+ }
+ } else {
+ perror("\r\nCan't send character");
+ active = 0;
+ }
+#ifdef SUNX25
+ }
+#endif /* SUNX25 */
+ } /* for... */
+ }
+ }
+
+ /* now active == 0 */
+ signal(CK_FORK_SIG, SIG_IGN); /* Turn off CK_FORK_SIG */
+ sjval = CEV_NO; /* Set to hangup */
+ } /* Come here on termination of child */
+
+/* cklongjmp() executed in pipeint() (parent only!) comes here */
+
+/*
+ Now the child fork is gone or is waiting for CK_FORK_SIG in ck_sndmsg().
+ So we can't get (in the parent) any subsequent CK_FORK_SIG signals until
+ we signal the child with CK_FORK_SIG.
+*/
+ debug(F100,"CONNECT signaling port fork","",0);
+ signal(CK_FORK_SIG, SIG_IGN); /* Turn this off */
+ debug(F101,"CONNECT killing port fork","",pid);
+ if (pid) {
+ int x = 0;
+#ifdef BEOSORBEBOX
+ {
+ long ret_val;
+ x = kill(pid,SIGKILLTHR); /* Kill lower fork */
+ wait_for_thread(pid, &ret_val);
+ }
+#else
+#ifdef Plan9
+ x = kill(pid,SIGKILL); /* Kill lower fork */
+#else
+ x = kill(pid,9);
+#endif /* Plan9 */
+#endif /* BEOSORBEBOX */
+ wait((WAIT_T *)0); /* Wait till gone. */
+ if (x < 0) {
+ printf("WARNING: Failure to kill fork, pid %d: %s, errno=%d\n",
+ (int) pid, ck_errstr(), errno);
+ debug(F111,"CONNECT error killing pid",ck_errstr(),errno);
+ }
+ debug(F101,"CONNECT killed port fork","",pid);
+ pid = (PID_T) 0;
+ }
+ if (sjval == CEV_HUP) { /* Read error on comm device */
+ dohangup = 1; /* so we want to hang up our side */
+#ifdef NETCONN
+ if (network) { /* and/or close network connection */
+ ttclos(0);
+ dologend();
+#ifdef SUNX25
+ if (nettype == NET_SX25) /* If X.25, restore the PAD params */
+ initpad();
+#endif /* SUNX25 */
+ }
+#endif /* NETCONN */
+ }
+#ifdef CK_APC
+ if (sjval == CEV_APC) { /* Application Program Command rec'd */
+ apcactive = APC_REMOTE; /* Flag APC as active */
+ active = 0; /* Flag CONNECT as inactive */
+ }
+#endif /* CK_APC */
+ conres(); /* Reset the console. */
+ if (dohangup > 0) { /* If hangup requested, do that. */
+#ifndef NODIAL
+ if (dohangup > 1) /* User asked for it */
+ if (mdmhup() < 1) /* Maybe hang up via modem */
+#endif /* NODIAL */
+ tthang(); /* And make sure we don't hang up */
+ dohangup = 0; /* again unless requested again. */
+ }
+
+#ifdef COMMENT
+#ifdef NETCONN
+#ifdef SIGPIPE
+ if (network && sigpiph) /* Restore previous SIGPIPE handler */
+ (VOID) signal(SIGPIPE, sigpiph);
+#endif /* SIGPIPE */
+#endif /* NETCONN */
+#endif /* COMMENT */
+
+#ifdef ANYX25
+ if (dox25clr) { /* If X.25 Clear requested */
+ x25clear(); /* do that. */
+#ifndef IBMX25
+ initpad();
+#endif /* IBMX25 */
+ dox25clr = 0; /* But only once. */
+ }
+#endif /* ANYX25 */
+
+ if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
+ if (msgflg)
+ printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
+#ifdef CK_APC
+ if (!apcactive)
+#endif /* CK_APC */
+ printf("\n");
+ what = W_NOTHING; /* So console modes set right. */
+#ifndef NOCSETS
+ language = langsv; /* Restore language */
+#endif /* NOCSETS */
+ parent_id = (PID_T) 0;
+ goto conret1;
+
+ }
+#ifndef BEOSORBEBOX
+ else { /* *** */ /* Inferior reads, prints port input */
+ concld(/* (void *)&pid */);
+ }
+#endif /* BEOSORBEBOX */
+
+conret1:
+ conret = 1;
+conret0:
+ signal(CK_FORK_SIG, SIG_IGN); /* In case this wasn't done already */
+ debug(F101,"CONNECT conect exit ibc","",ibc);
+ debug(F101,"CONNECT conect exit obc","",obc);
+ close(xpipe[0]); xpipe[0] = -1; /* Close the pipe */
+ close(xpipe[1]); xpipe[1] = -1;
+ if (msgflg) {
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL)
+ printf("\n");
+#endif /* CK_APC */
+ printf("----------------------------------------------------\r\n");
+ }
+ fflush(stdout);
+ return(conret);
+}
+
+
+/* H C O N N E -- Give help message for connect. */
+
+int
+hconne() {
+ int c;
+ static char *hlpmsg[] = {
+"\r\n ? for this message",
+"\r\n 0 (zero) to send a null",
+"\r\n B to send a BREAK",
+#ifdef CK_LBRK
+"\r\n L to send a Long BREAK",
+#endif /* CK_LBRK */
+#ifdef NETCONN
+"\r\n I to send a network interrupt packet",
+#ifdef TCPSOCKET
+"\r\n A to send Are You There?",
+#endif /* TCPSOCKET */
+#ifdef ANYX25
+"\r\n R to reset X.25 virtual circuit",
+#endif /* ANYX25 */
+#endif /* NETCONN */
+"\r\n U to hangup and close the connection",
+"\r\n Q to hangup and quit Kermit",
+"\r\n S for status",
+#ifdef NOPUSH
+"\r\n ! to push to local shell (disabled)",
+"\r\n Z to suspend (disabled)",
+#else
+"\r\n ! to push to local shell",
+#ifdef NOJC
+"\r\n Z to suspend (disabled)",
+#else
+"\r\n Z to suspend",
+#endif /* NOJC */
+#endif /* NOPUSH */
+"\r\n \\ backslash code:",
+"\r\n \\nnn decimal character code",
+"\r\n \\Onnn octal character code",
+"\r\n \\Xhh hexadecimal character code",
+"\r\n terminate with carriage return.",
+"\r\n Type the escape character again to send the escape character, or",
+"\r\n press the space-bar to resume the CONNECT command.\r\n",
+"" };
+
+ conol("\r\n----------------------------------------------------");
+ conol("\r\nPress C to return to ");
+ conol(*myhost ? myhost : "the C-Kermit prompt");
+ conol(", or:");
+ conola(hlpmsg); /* Print the help message. */
+ conol("Command>"); /* Prompt for command. */
+ c = CONGKS() & 0177; /* Get character, strip any parity. */
+ /* No key mapping or translation here */
+ if (c != CMDQ)
+ conoll("");
+ conoll("----------------------------------------------------");
+ return(c); /* Return it. */
+}
+
+
+/* D O E S C -- Process an escape character argument */
+
+VOID
+#ifdef CK_ANSIC
+doesc(char c)
+#else
+doesc(c) char c;
+#endif /* CK_ANSIC */
+/* doesc */ {
+ CHAR d;
+
+ debug(F101,"CONNECT doesc","",c);
+ while (1) {
+ if (c == escape) { /* Send escape character */
+ d = dopar((CHAR) c); ttoc((char) d); return;
+ } else /* Or else look it up below. */
+ if (isupper(c)) c = tolower(c);
+
+ switch(c) {
+
+ case 'c': /* Escape back to prompt */
+ case '\03':
+ active = 0; conol("\r\n"); return;
+
+ case 'b': /* Send a BREAK signal */
+ case '\02':
+ ttsndb(); return;
+
+#ifdef NETCONN
+ case 'i': /* Send Interrupt */
+ case '\011':
+#ifdef TCPSOCKET
+#ifndef IP
+#define IP 244
+#endif /* IP */
+ if (network && IS_TELNET()) { /* TELNET */
+ temp[0] = (CHAR) IAC; /* I Am a Command */
+ temp[1] = (CHAR) IP; /* Interrupt Process */
+ temp[2] = NUL;
+ ttol((CHAR *)temp,2);
+ } else
+#endif /* TCPSOCKET */
+#ifdef SUNX25
+ if (network && (nettype == NET_SX25)) {
+ (VOID) x25intr(0); /* X.25 interrupt packet */
+ conol("\r\n");
+ } else
+#endif /* SUNX25 */
+ conoc(BEL);
+ return;
+
+#ifdef TCPSOCKET
+ case 'a': /* "Are You There?" */
+ case '\01':
+#ifndef AYT
+#define AYT 246
+#endif /* AYT */
+ if (network && IS_TELNET()) {
+ temp[0] = (CHAR) IAC; /* I Am a Command */
+ temp[1] = (CHAR) AYT; /* Are You There? */
+ temp[2] = NUL;
+ ttol((CHAR *)temp,2);
+ } else conoc(BEL);
+ return;
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+
+#ifdef CK_LBRK
+ case 'l': /* Send a Long BREAK signal */
+ ttsndlb(); return;
+#endif /* CK_LBRK */
+
+ case 'u': /* Hangup */
+ /* case '\010': */ /* No, too dangerous */
+#ifdef ANYX25
+ if (network && (nettype == NET_SX25 || nettype == NET_IX25))
+ dox25clr = 1;
+ else
+#endif /* ANYX25 */
+ dohangup = 2; active = 0; conol("\r\nHanging up "); return;
+
+#ifdef ANYX25
+ case 'r': /* Reset the X.25 virtual circuit */
+ case '\022':
+ if (network && (nettype == NET_SX25 || nettype == NET_IX25))
+ (VOID) x25reset(0,0);
+ conol("\r\n");
+ return;
+#endif /* ANYX25 */
+
+ case 'q': /* Quit */
+ dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
+
+ case 's': /* Status */
+ conoll("");
+ conoll("----------------------------------------------------");
+#ifdef NETCMD
+ if (ttpipe)
+ ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
+ else
+#endif /* NETCMD */
+ ckmakmsg(temp,
+ TMPLEN,
+ " ",
+ (network ? "Host" : "Device"),
+ ": ",
+ ttname
+ );
+ conoll(temp);
+ if (!network && speed >= 0L) {
+ sprintf(temp,"Speed %ld", speed);
+ conoll(temp);
+ }
+ sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
+ conoll(temp);
+ sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
+ conoll(temp);
+ sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8 );
+ conoll(temp);
+ if (hwparity)
+ sprintf(temp," Parity[hardware]: %s",parnam((char)hwparity));
+ else
+ sprintf(temp," Parity: %s", parnam((char)parity));
+ conoll(temp);
+ sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
+ conoll(temp);
+ ckmakmsg(temp, /* (would not be safe for sprintf) */
+ TMPLEN,
+ " Session log: ",
+ *sesfil ? sesfil : "(none)",
+ NULL,
+ NULL
+ );
+ conoll(temp);
+#ifndef NOSHOW
+ if (!network) shomdm();
+#endif /* NOSHOW */
+#ifdef CKLOGDIAL
+ {
+ long z;
+ z = dologshow(0);
+ if (z > -1L) {
+ sprintf(temp," Elapsed time: %s",hhmmss(z));
+ conoll(temp);
+ }
+ }
+#endif /* CKLOGDIAL */
+ conoll("----------------------------------------------------");
+ return;
+
+ case 'h': /* Help */
+ case '?': /* Help */
+ c = hconne(); continue;
+
+ case '0': /* Send a null */
+ c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
+
+ case 'z': case '\032': /* Suspend */
+#ifndef NOPUSH
+ if (!nopush)
+ stptrap(0);
+ else
+ conoc(BEL);
+#else
+ conoc(BEL);
+#endif /* NOPUSH */
+ return;
+
+ case '@': /* Start inferior command processor */
+ case '!':
+#ifndef NOPUSH
+ if (!nopush) {
+ conres(); /* Put console back to normal */
+ zshcmd(""); /* Fork a shell. */
+ if (conbin((char)escape) < 0) {
+ printf("Error resuming CONNECT session\n");
+ active = 0;
+ }
+ } else conoc(BEL);
+#else
+ conoc(BEL);
+#endif /* NOPUSH */
+ return;
+
+ case SP: /* Space, ignore */
+ return;
+
+ default: /* Other */
+ if (c == CMDQ) { /* Backslash escape */
+ int x;
+ ecbp = ecbuf;
+ *ecbp++ = c;
+ while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
+ *ecbp++ = c;
+ *ecbp = NUL; ecbp = ecbuf;
+ x = xxesc(&ecbp); /* Interpret it */
+ if (x >= 0) { /* No key mapping here */
+ c = dopar((CHAR) x);
+ ttoc((char) c);
+ return;
+ } else { /* Invalid backslash code. */
+ conoc(BEL);
+ return;
+ }
+ }
+ conoc(BEL); return; /* Invalid esc arg, beep */
+ }
+ }
+}
+#endif /* NOLOCAL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckudia.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckudia.c
new file mode 100644
index 0000000..587a0d1
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckudia.c
@@ -0,0 +1,8249 @@
+#include "ckcsym.h"
+char *dialv = "Dial Command, 9.0.160, 16 Oct 2009";
+
+/* C K U D I A -- Module for automatic modem dialing. */
+
+/*
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ Authors:
+
+ Original (version 1, 1985) author: Herm Fischer, Encino, CA.
+ Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0.
+ Author and maintainer since 1985: Frank da Cruz, Columbia University,
+ fdc@columbia.edu.
+
+ Contributions by many others throughout the years, including: Jeffrey
+ Altman, Mark Berryman, Fernando Cabral, John Chmielewski, Joe Doupnik,
+ Richard Hill, Larry Jacobs, Eric Jones, Tom Kloos, Bob Larson, Peter Mauzey,
+ Joe Orost, Kevin O'Gorman, Kai Uwe Rommel, Dan Schullman, Warren Tucker, and
+ many others.
+*/
+
+/*
+ Entry points:
+ ckdial(char * number) Dial a number or answer a call
+ dialhup() Hang up a dialed connection
+ mdmhup() Use modem commands to hang up
+
+ All other routines are static.
+ Don't call dialhup() or mdmhup() without first calling ckdial().
+*/
+
+/*
+ This module calls externally defined system-dependent functions for
+ communications i/o, as described in CKCPLM.DOC, the C-Kermit Program Logic
+ Manual, and thus should be portable to all systems that implement those
+ functions, and where alarm() and signal() work.
+
+ HOW TO ADD SUPPORT FOR ANOTHER MODEM:
+
+ 1. In ckuusr.h, define a modem-type number symbol (n_XXX) for the new modem,
+ the next highest one.
+
+ 2. In ckuusr.h, adjust MAX_MDM to the new number of modem types.
+
+The remaining steps are in this module:
+
+ 3. Create a MDMINF structure for it. NOTE: The wake_str should include
+ all invariant setup info, e.g. enable result codes, BREAK transparency,
+ modulation negotiation, etc. See ckcker.h for MDMINF struct definition.
+
+ 4. Add the address of the MDMINF structure to the modemp[] array,
+ according to the numerical value of the modem-type number.
+
+ 5. Add the user-visible (SET MODEM) name and corresponding modem number
+ to the mdmtab[] array, in alphabetical order by modem-name string.
+
+ 6. If this falls into a class like is_rockwell, is_supra, etc, add the new
+ one to the definition of the class.
+
+ 7. Adjust the gethrn() routine to account for any special numeric result
+ codes (if it's a Hayes compatible modem).
+
+ 8. Read through the code and add any modem-specific sections as necessary.
+ For most modern Hayes-compatible modems, no specific code will be
+ needed.
+
+ NOTE: The MINIDIAL symbol is used to build this module to include support
+ for only a minimum number of standard and/or generally useful modem types,
+ namely Hayes 1200 and 2400, ITU-T (CCITT) V.25bis and V.25ter (V.250),
+ Generic-High-Speed, "Unknown", and None. When adding support for a new
+ modem type, keep it outside of the MINIDIAL sections unless it deserves to
+ be in it.
+*/
+
+#include "ckcdeb.h"
+#ifndef NOLOCAL
+#ifndef NODIAL
+#ifndef NOICP
+
+#ifndef CK_ATDT
+#define CK_ATDT
+#endif /* CK_ATDT */
+
+#ifndef NOOLDMODEMS /* Unless instructed otherwise, */
+#define OLDMODEMS /* keep support for old modems. */
+#endif /* NOOLDMODEMS */
+
+#ifndef M_OLD /* Hide old modem keywords in SET MODEM table. */
+#define M_OLD 0 /* Define as CM_INV to make them invisible. */
+#endif /* M_OLD */
+
+#ifndef M_ALIAS
+#define M_ALIAS 64
+#endif /* M_ALIAS */
+
+#ifndef MAC
+#include <signal.h>
+#endif /* MAC */
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckucmd.h"
+#include "ckcnet.h"
+#include "ckuusr.h"
+
+#ifdef OS2ONLY
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#include "ckocon.h"
+#endif /* OS2ONLY */
+
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.h"
+#endif /* NT */
+#ifdef OS2
+#include "ckowin.h"
+#endif /* OS2 */
+
+#ifndef ZILOG
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#else
+#include <setret.h>
+#endif /* ZILOG */
+
+#include "ckcsig.h" /* C-Kermit signal processing */
+
+#ifdef MAC
+#define signal msignal
+#define SIGTYP long
+#define alarm malarm
+#define SIG_IGN 0
+#define SIGALRM 1
+#define SIGINT 2
+SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int);
+#endif /* MAC */
+
+#ifdef AMIGA
+#define signal asignal
+#define alarm aalarm
+#define SIGALRM (_NUMSIG+1)
+#define SIGTYP void
+SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
+unsigned aalarm(unsigned);
+#endif /* AMIGA */
+
+#ifdef STRATUS
+/*
+ VOS doesn't have alarm(), but it does have some things we can work with.
+ However, we have to catch all the signals in one place to do this, so
+ we intercept the signal() routine and call it from our own replacement.
+*/
+#define signal vsignal
+#define alarm valarm
+SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
+int valarm(int interval);
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef getchar
+#undef getchar
+#endif /* getchar */
+#define getchar(x) coninc(0)
+#endif /* STRATUS */
+
+#ifdef OS2
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#endif /* OS2 */
+
+#ifndef NOHINTS
+extern int hints;
+#endif /* NOHINTS */
+
+#ifdef CK_TAPI
+extern int tttapi;
+extern int tapipass;
+#endif /* CK_TAPI */
+
+#ifdef CKLOGDIAL
+extern int dialog;
+#endif /* CKLOGDIAL */
+
+char * dialmsg[] = { /* DIAL status strings */
+
+ /* Keyed to numbers defined in ckcker.h -- keep in sync! */
+
+ "DIAL succeeded", /* 0 DIA_OK */
+ "Modem type not specified", /* 1 DIA_NOMO */
+ "Communication device not specified", /* 2 DIA_NOLI */
+ "Communication device can't be opened", /* 3 DIA_OPEN */
+ "Speed not specified", /* 4 DIA_NOSP */
+ "Pre-DIAL hangup failed", /* 5 DIA_HANG */
+ "Internal error", /* 6 DIA_IE */
+ "Device input/output error", /* 7 DIA_IO */
+ "DIAL TIMEOUT expired", /* 8 DIA_TIMO */
+ "Interrupted by user", /* 9 DIA_INTR */
+ "Modem not ready", /* 10 DIA_NRDY */
+ "Partial dial OK", /* 11 DIA_PART */
+ "Dial directory lookup error", /* 12 DIA_DIR */
+ "Hangup OK", /* 13 DIA_HUP */
+ NULL, /* 14 (undef) */
+ NULL, /* 15 (undef) */
+ NULL, /* 16 (undef) */
+ NULL, /* 17 (undef) */
+ NULL, /* 18 (undef) */
+ "No response from modem", /* 19 DIA_NRSP */
+ "Modem command error", /* 20 DIA_ERR */
+ "Failure to initialize modem", /* 21 DIA_NOIN */
+ "Phone busy", /* 22 DIA_BUSY */
+ "No carrier", /* 23 DIA_NOCA */
+ "No dialtone", /* 24 DIA_NODT */
+ "Incoming call", /* 25 DIA_RING */
+ "No answer", /* 26 DIA_NOAN */
+ "Disconnected", /* 27 DIA_DISC */
+ "Answered by voice", /* 28 DIA_VOIC */
+ "Access denied / forbidden call", /* 29 DIA_NOAC */
+ "Blacklisted", /* 30 DIA_BLCK */
+ "Delayed", /* 31 DIA_DELA */
+ "Fax connection", /* 32 DIA_FAX */
+ "Digital line", /* 33 DIA_DIGI */
+ "TAPI dialing failure", /* 34 DIA_TAPI */
+ NULL /* 34 */
+};
+
+#ifdef COMMENT
+#ifdef NOSPL
+static
+#endif /* NOSPL */
+char modemmsg[128] = { NUL, NUL }; /* DIAL response from modem */
+#endif /* COMMENT */
+
+#ifdef NTSIG
+extern int TlsIndex;
+#endif /* NTSIG */
+
+int mdmtyp = n_GENERIC; /* Default modem type */
+int mdmset = 0; /* User explicitly set a modem type */
+
+int /* SET DIAL parameters */
+ dialhng = 1, /* DIAL HANGUP, default is ON */
+ dialdpy = 0, /* DIAL DISPLAY, default is OFF */
+ mdmspd = 0, /* DIAL SPEED-MATCHING (0 = OFF) */
+ mdmspk = 1, /* MODEM SPEAKER */
+ mdmvol = 2, /* MODEM VOLUME */
+ dialtmo = 0, /* DIAL TIMEOUT */
+ dialatmo = -1, /* ANSWER TIMEOUT */
+ dialksp = 0, /* DIAL KERMIT-SPOOF, 0 = OFF */
+ dialidt = 0, /* DIAL IGNORE-DIALTONE */
+#ifndef CK_RTSCTS
+ /* If we can't do RTS/CTS then there's no flow control at first. */
+ /* So we might easily lose the echo to the init string and the OK */
+ /* and then give "No response from modem" errors. */
+ dialpace = 150, /* DIAL PACING */
+#else
+ dialpace = -1,
+#endif /* CK_RTSCTS */
+
+ /* 0 = RS232 (drop DTR); 1 = MODEM-COMMAND (e.g. <sec>+++<sec>ATH0) */
+ dialmhu = DEFMDMHUP; /* MODEM HANGUP-METHOD */
+
+int
+ dialec = 1, /* DIAL ERROR-CORRECTION */
+ dialdc = 1, /* DIAL COMPRESSION */
+#ifdef VMS
+ /* VMS can only use Xon/Xoff */
+ dialfc = FLO_XONX, /* DIAL FLOW-CONTROL */
+#else
+ dialfc = FLO_AUTO,
+#endif /* VMS */
+ dialmth = XYDM_D, /* DIAL METHOD (Tone, Pulse, Defalt) */
+ dialmauto = 1, /* DIAL METHOD is AUTO */
+ dialesc = 0; /* DIAL ESCAPE */
+
+int telephony = 0; /* Command-line '-T' option */
+
+long dialmax = 0L, /* Modem's max interface speed */
+ dialcapas = 0L; /* Modem's capabilities */
+
+int dialsta = DIA_UNK; /* Detailed return code (ckuusr.h) */
+
+#ifdef COMMENT
+int ans_cid = 0; /* SET ANSWER parameters */
+int ans_rings = 0; /* (not used yet...) */
+#endif /* COMMENT */
+
+int is_rockwell = 0;
+int is_motorola = 0;
+int is_supra = 0;
+int is_hayeshispd = 0;
+
+/* Dialing directory list */
+
+char *dialdir[MAXDDIR]; /* DIAL DIRECTORY filename array */
+int ndialdir = 0; /* How many dial directories */
+
+/* User overrides for built-in modem commands */
+
+char *dialini = NULL; /* MODEM INIT-STRING none */
+char *dialmstr = NULL; /* MODEM DIALMODE-STRING */
+char *dialmprmt = NULL; /* MODEM DIALMODE-PROMPT */
+char *dialcmd = NULL; /* MODEM DIAL-COMMAND, default none */
+char *dialname = NULL; /* Descriptive name for modem */
+char *dialdcon = NULL; /* DC ON command */
+char *dialdcoff = NULL; /* DC OFF command */
+char *dialecon = NULL; /* EC ON command */
+char *dialecoff = NULL; /* EC OFF command */
+char *dialaaon = NULL; /* Autoanswer ON command */
+char *dialaaoff = NULL; /* Autoanswer OFF command */
+char *dialhcmd = NULL; /* Hangup command */
+char *dialhwfc = NULL; /* Hardware flow control command */
+char *dialswfc = NULL; /* (Local) software f.c. command */
+char *dialnofc = NULL; /* No (Local) flow control command */
+char *dialtone = NULL; /* Command to force tone dialing */
+char *dialpulse = NULL; /* ..to force pulse dialing */
+char *dialx3 = NULL; /* Ignore dialtone */
+char *mdmname = NULL;
+char *dialspon = NULL; /* Speaker On command */
+char *dialspoff = NULL; /* Speaker Off command */
+char *dialvol1 = NULL; /* Volume Low command */
+char *dialvol2 = NULL; /* Volume Medium command */
+char *dialvol3 = NULL; /* Volume High command */
+char *dialini2 = NULL; /* Second init string */
+
+/* Phone number options */
+
+char *dialnpr = NULL; /* DIAL PREFIX, ditto */
+char *diallac = NULL; /* DIAL LOCAL-AREA-CODE, ditto */
+char *diallcc = NULL; /* DIAL LOCAL-COUNTRY-CODE, ditto */
+char *dialixp = NULL; /* DIAL INTL-PREFIX */
+char *dialixs = NULL; /* DIAL INTL-SUFFIX */
+char *dialldp = NULL; /* DIAL LD-PREFIX */
+char *diallds = NULL; /* DIAL LD-SUFFIX */
+char *diallcp = NULL; /* DIAL LOCAL-PREFIX */
+char *diallcs = NULL; /* DIAL LOCAL-SUFFIX */
+char *dialpxi = NULL; /* DIAL PBX-INTERNAL-PREFIX */
+char *dialpxo = NULL; /* DIAL PBX-OUTSIDE-PREFIX */
+char *dialsfx = NULL; /* DIAL SUFFIX */
+char *dialtfp = NULL; /* DIAL TOLL-FREE-PREFIX */
+
+char *callid_date = NULL; /* Caller ID strings */
+char *callid_time = NULL;
+char *callid_name = NULL;
+char *callid_nmbr = NULL;
+char *callid_mesg = NULL;
+
+extern char * d_name;
+extern char * dialtfc[]; /* DIAL TOLL-FREE-AREA-CODE */
+extern char * dialpxx[]; /* DIAL PBX-EXCHANGE */
+extern int ntollfree;
+extern int ndialpxx;
+
+extern char * dialpucc[]; /* DIAL Pulse countries */
+extern int ndialpucc;
+extern char * dialtocc[]; /* DIAL Tone countries */
+extern int ndialtocc;
+
+char *dialmac = NULL; /* DIAL macro */
+
+/* Countries where pulse dialing must be used (tone is not available) */
+static char * pulsecc[] = { NULL }; /* (Unknown at present) */
+
+/* Countries where tone dialing may safely be the default. */
+/* "+" marks countries where pulse is also allowed. */
+/* Both Pulse and Tone are allowed in Austria & Switzerland but it is not */
+/* yet known if Tone is universally in those countries. */
+static char * tonecc[] = {
+ "1", /* + North American Numbering Plan */
+ "31", /* Netherlands */
+ "32", /* Belgium */
+ "33", /* France */
+ "352", /* Luxembourg */
+ "353", /* Ireland */
+ "354", /* Iceland */
+ "358", /* Finland */
+ "39", /* Italy */
+ "44", /* + UK */
+ "45", /* Denmark */
+ "46", /* Sweden */
+ "47", /* Norway */
+ "49", /* + Germany */
+ NULL
+};
+
+#ifndef MINIDIAL
+/*
+ Telebit model codes:
+
+ ATI Model Numbers Examples
+ --- ------------- --------
+ 123 Telebit in "total Hayes-1200" emulation mode
+ 960 Telebit in Conventional Command (Hayes) mode
+ 961 RA12C IBM PC internal original Trailblazer
+ 962 RA12E External original Trailblazer
+ 963 RM12C Rackmount original Trailblazer
+ 964 T18PC IBM PC internal Trailblazer-Plus (TB+)
+ 965 T18SA, T2SAA, T2SAS External TB+, T1600, T2000, T3000, WB, and later
+ 966 T18RMM Rackmount TB+
+ 967 T2MC IBM PS/2 internal TB+
+ 968 T1000 External T1000
+ 969 ? Qblazer
+ 970 Qblazer Plus
+ 971 T2500 External T2500
+ 972 T2500 Rackmount T2500
+*/
+
+/* Telebit model codes */
+
+#define TB_UNK 0 /* Unknown Telebit model */
+#define TB_BLAZ 1 /* Original TrailBlazer */
+#define TB_PLUS 2 /* TrailBlazer Plus */
+#define TB_1000 3 /* T1000 */
+#define TB_1500 4 /* T1500 */
+#define TB_1600 5 /* T1600 */
+#define TB_2000 6 /* T2000 */
+#define TB_2500 7 /* T2500 */
+#define TB_3000 8 /* T3000 */
+#define TB_QBLA 9 /* Qblazer */
+#define TB_WBLA 10 /* WorldBlazer */
+#define TB__MAX 10 /* Highest number */
+
+char *tb_name[] = { /* Array of model names */
+ "Unknown", /* TB_UNK */
+ "TrailBlazer", /* TB_BLAZ */
+ "TrailBlazer-Plus", /* TB_PLUS */
+ "T1000", /* TB_1000 */
+ "T1500", /* TB_1500 */
+ "T1600", /* TB_1600 */
+ "T2000", /* TB_2000 */
+ "T2500", /* TB_2500 */
+ "T3000", /* TB_3000 */
+ "Qblazer", /* TB_QBLA */
+ "WorldBlazer", /* TB_WBLA */
+ ""
+};
+#endif /* MINIDIAL */
+
+extern int flow, local, mdmtyp, quiet, backgrd, parity, seslog, network;
+extern int carrier, duplex, mdmsav, reliable, setreliable;
+extern int ttnproto, nettype;
+extern long speed;
+extern char ttname[], sesfil[];
+#ifndef NOXFER
+extern CHAR stchr;
+extern int interrupted;
+#endif /* NOXFER */
+
+/* Failure codes */
+
+#define F_TIME 1 /* timeout */
+#define F_INT 2 /* interrupt */
+#define F_MODEM 3 /* modem-detected failure */
+#define F_MINIT 4 /* cannot initialize modem */
+
+#ifndef CK_TAPI
+static
+#endif /* CK_TAPI */
+#ifdef OS2
+ volatile
+#endif /* OS2 */
+ int fail_code = 0; /* Default failure reason. */
+
+static int xredial = 0;
+static int func_code; /* 0 = dialing, nonzero = answering */
+static int partial;
+static int mymdmtyp = 0;
+
+#define DW_NOTHING 0 /* What we are doing */
+#define DW_INIT 1
+#define DW_DIAL 2
+
+static int dial_what = DW_NOTHING; /* Nothing at first. */
+static int nonverbal = 0; /* Hayes in numeric response mode */
+static MDMINF * mp;
+static CHAR escbuf[6];
+static long mdmcapas;
+
+_PROTOTYP (static VOID dreset, (void) );
+_PROTOTYP (static int (*xx_ok), (int,int) );
+_PROTOTYP (static int ddinc, (int) );
+_PROTOTYP (int dialhup, (void) );
+_PROTOTYP (int getok, (int,int) );
+_PROTOTYP (char * ck_time, (void) );
+_PROTOTYP (static VOID ttslow, (char *, int) );
+#ifdef COMMENT
+_PROTOTYP (static VOID xcpy, (char *, char *, unsigned int) );
+#endif /* COMMENT */
+_PROTOTYP (static VOID waitfor, (char *) );
+_PROTOTYP (static VOID dialoc, (char) );
+_PROTOTYP (static int didweget, (char *, char *) );
+_PROTOTYP (static VOID spdchg, (long) );
+_PROTOTYP (static int dialfail, (int) );
+_PROTOTYP (static VOID gethrw, (void) );
+_PROTOTYP (static VOID gethrn, (void) );
+
+int dialudt = n_UDEF; /* Number of user-defined type */
+
+/* BEGIN MDMINF STRUCT DEFINITIONS */
+
+/*
+ Declare structures containing modem-specific information.
+ REMEMBER that only the first SEVEN characters of these names are
+ guaranteed to be unique.
+
+ First declare the three types that are allowed for MINIDIAL versions.
+*/
+static
+MDMINF CCITT = /* CCITT / ITU-T V.25bis autodialer */
+/*
+ According to V.25bis:
+ . Even parity is required for giving commands to the modem.
+ . Commands might or might not echo.
+ . Responses ("Indications") from the modem are terminated by CR and LF.
+ . Call setup is accomplished by:
+ - DTE raises DTR (V.24 circuit 108) [ttopen() does this]
+ - Modem raises CTS (V.24 circuit 106) [C-Kermit ignores this]
+ - DTE issues a call request command ("CRN")
+ - Modem responds with "VAL" ("command accepted")
+ - If the call is completed:
+ modem responds with "CNX" ("call connected");
+ modem turns CTS (106) OFF;
+ modem turns DSR (107) ON;
+ else:
+ modem responds with "CFI <parameter>" ("call failure indication").
+ . To clear a call, the DTE turns DTR (108) OFF.
+ . There is no mention of the Carrier Detect circuit (109) in the standard.
+ . There is no provision for "escaping back" to the modem's command mode.
+
+ It is not known whether there exists in real life a pure V.25bis modem.
+ If there is, this code has never been tested on it. See the Digitel entry.
+*/
+ {
+ "Any CCITT / ITU-T V.25bis conformant modem",
+ "", /* pulse command */
+ "", /* tone command */
+ 40, /* dial_time -- programmable -- */
+ ",:", /* pause_chars -- "," waits for programmable time */
+ /* ":" waits for dial tone */
+ 10, /* pause_time (seconds, just a guess) */
+ "", /* wake_str (none) */
+ 200, /* wake_rate (msec) */
+ "VAL", /* wake_prompt */
+ "", /* dmode_str (none) */
+ "", /* dmode_prompt (none) */
+ "CRN%s\015", /* dial_str */
+ 200, /* dial_rate (msec) */
+ 0, /* No esc_time */
+ 0, /* No esc_char */
+ "", /* No hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "CIC\015", /* aa_on_str */
+ "DIC\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ CKD_V25, /* capas */
+ NULL /* No ok_fn */
+};
+
+static
+MDMINF HAYES = /* Hayes 2400 and compatible modems */
+ {
+ "Hayes Smartmodem 2400 and compatibles",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1&S0&C1&D2\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0&S1\015", /* wake_str */
+#else
+ "ATQ0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str, user supplies D or T */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 2400L, /* max_speed */
+ CKD_AT, /* capas */
+ getok /* ok_fn */
+};
+
+/*
+ The intent of the "unknown" modem is to allow KERMIT to support
+ unknown modems by having the user type the entire autodial sequence
+ (possibly including control characters, etc.) as the "phone number".
+ The protocol and other characteristics of this modem are unknown, with
+ some "reasonable" values being chosen for some of them. The only way to
+ detect if a connection is made is to look for carrier.
+*/
+static
+MDMINF UNKNOWN = /* Information for "Unknown" modem */
+ {
+ "Unknown", /* name */
+ "", /* pulse command */
+ "", /* tone command */
+ 30, /* dial_time */
+ "", /* pause_chars */
+ 0, /* pause_time */
+ "", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+#ifndef MINIDIAL
+static
+MDMINF ATTISN = /* AT&T ISN Network */
+ {
+ "", /* pulse command */
+ "", /* tone command */
+ "AT&T ISN Network",
+ 30, /* Dial time */
+ "", /* Pause characters */
+ 0, /* Pause time */
+ "\015\015\015\015", /* Wake string */
+ 900, /* Wake rate */
+ "DIAL", /* Wake prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF ATTMODEM = /* information for AT&T switched-network modems */
+ /* "Number" following "dial" can include: p's and
+ * t's to indicate pulse or tone (default) dialing,
+ * + for wait for dial tone, , for pause, r for
+ * last number dialed, and, except for 2224B, some
+ * comma-delimited options like o12=y, before number.
+
+ * "Important" options for the modems:
+ *
+ * All: Except for 2224B, enable option 12 for "transparent
+ * data," o12=y. If a computer port used for both
+ * incoming and outgoing calls is connected to the
+ * modem, disable "enter interactive mode on carriage
+ * return," EICR. The Kermit "dial" command can
+ * function with EIA leads standard, EIAS.
+ *
+ * 2212C: Internal hardware switches at their default
+ * positions (four rockers down away from numbers)
+ * unless EICR is not wanted (rocker down at the 4).
+ * For EIAS, rocker down at the 1.
+ *
+ * 2224B: Front-panel switch position 1 must be up (at the 1,
+ * closed). Disable EICR with position 2 down.
+ * For EIAS, position 4 down.
+ * All switches on the back panel down.
+ *
+ * 2224CEO: All front-panel switches down except either 5 or 6.
+ * Enable interactive flow control with o16=y.
+ * Select normal asynchronous mode with o34=0 (zero).
+ * Disable EICR with position 3 up. For EIAS, 1 up.
+ * Reset the modem after changing switches.
+ *
+ * 2296A: If option 00 (zeros) is present, use o00=0.
+ * Enable interactive flow control with o16=y.
+ * Select normal asynchronous mode with o34=0 (zero).
+ * (available in Microcom Networking version, but
+ * not necessarily other models of the 2296A).
+ * Enable modem-port flow control (if available) with
+ * o42=y. Enable asynchronous operation with o50=y.
+ * Disable EICR with o69=n. For EIAS, o66=n, using
+ * front panel.
+ */
+ {
+ "AT&T switched-network modems",
+ "", /* pulse command */
+ "", /* tone command */
+ 20, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+ "+", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "at%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ CKD_AT, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF ATTDTDM = /* AT&T Digital Terminal Data Module */
+ /* For dialing: KYBD switch down, others usually up. */
+ {
+ "AT&T Digital Terminal Data Module",
+ "", /* pulse command */
+ "", /* tone command */
+ 20, /* dial_time */
+ "", /* pause_chars */
+ 0, /* pause_time */
+ "", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF DIGITEL = /* Digitel DT-22 CCITT variant used in Brazil */
+/*
+ Attempts to adhere strictly to the V.25bis specification do not produce good
+ results in real life. The modem for which this code was developed: (a)
+ ignores parity; (b) sometimes terminates responses with LF CR instead of CR
+ LF; (c) has a Hayes-like escape sequence; (d) supports a hangup ("HUP")
+ command. Information from Fernando Cabral in Brasilia.
+*/
+ {
+ "Digitel DT-22 CCITT dialer",
+ "", /* pulse command */
+ "", /* tone command */
+ 40, /* dial_time -- programmable -- */
+ ",:", /* pause_chars -- "," waits for programmable time */
+ /* ":" waits for dial tone */
+ 10, /* pause_time (seconds, just a guess) */
+ "HUP\015", /* wake_str (Not Standard CCITT) */
+ 200, /* wake_rate (msec) */
+ "VAL", /* wake_prompt */
+ "", /* dmode_str (none) */
+ "", /* dmode_prompt (none) */
+ "CRN%s\015", /* dial_str */
+ 200, /* dial_rate (msec) */
+ 1100, /* esc_time (Not Standard CCITT) */
+ 43, /* esc_char (Not Standard CCITT) */
+ "HUP\015", /* hup_str (Not Standard CCITT) */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "CIC\015", /* aa_on_str */
+ "DIC\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ CKD_V25, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF H_1200 = /* Hayes 1200 and compatible modems */
+ {
+ "Hayes Smartmodem 1200 and compatibles",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1\015", /* wake_str */
+#else
+ "ATQ0\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 1200L, /* max_speed */
+ CKD_AT, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF H_ULTRA = /* Hayes high-speed */
+ {
+ "Hayes Ultra/Optima/Accura 96/144/288", /* U,O,A */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1X4N1Y0&S0&C1&D2S37=0S82=128\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4N1Y0&S1S37=0S82=128\015", /* wake_str */
+#else
+ "ATQ0X4N1Y0S37=0S82=128\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */ /* OK for U,O */
+ "AT&K4\015", /* swfc_str */ /* OK for U,O */
+ "AT&K0\015", /* nofc_str */ /* OK for U,O */
+ "AT&Q5S36=7S48=7\015", /* ec_on_str */ /* OK for U,O */
+ "AT&Q0\015", /* ec_off_str */ /* OK for U,O */
+ "ATS46=2\015", /* dc_on_str */
+ "ATS46=0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */ /* (varies) */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF H_ACCURA = /* Hayes Accura */
+ { /* GUESSING IT'S LIKE ULTRA & OPTIMA */
+ "Hayes Accura",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1X4N1Y0&S0&C1&D2S37=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4N1Y0&S1S37=0\015", /* wake_str */
+#else
+ "ATQ0X4N1Y0S37=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5S36=7S48=7\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "ATS46=2\015", /* dc_on_str */
+ "ATS46=0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */ /* (varies) */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF PPI = /* Practical Peripherals */
+ {
+ "Practical Peripherals V.22bis or higher with V.42 and V.42bis",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef COMMENT
+/* In newer models S82 (BREAK handling) was eliminated, causing an error. */
+#ifdef OS2
+ "ATQ0X4N1&S0&C1&D2S37=0S82=128\015", /* wake_str */
+#else
+ "ATQ0X4N1S37=0S82=128\015", /* wake_str */
+#endif /* OS2 */
+#else /* So now we use Y0 instead */
+#ifdef OS2
+ "ATE1Q0V1X4N1&S0&C1&D2Y0S37=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4N1Y0&S1S37=0\015", /* wake_str */
+#else
+ "ATQ0X4N1Y0S37=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* COMMENT */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5S36=7S48=7\015", /* ec_on_str */
+ "AT&Q0S36=0S48=128\015", /* ec_off_str */
+ "ATS46=2\015", /* dc_on_str */
+ "ATS46=0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF DATAPORT = /* AT&T Dataport */
+ {
+ "AT&T / Paradyne DataPort V.32 or higher",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+ /*
+ Note: S41=0 (use highest modulation) omitted, since it is not
+ supported on the V.32 and lower models. So let's not touch it.
+ */
+#ifdef OS2
+ "ATQ0E1V1X6&S0&C1&D2&Q0Y0\\K5S78=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X6&S1&Q0Y0\\K5S78=0\015", /* wake_str */
+#else
+ "ATQ0E1X6&Q0Y0\\K5S78=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\\X0\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N7\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF UCOM_AT = /* Microcom DeskPorte FAST ES 28.8 */
+ {
+ "Microcom DeskPorte FAST 28.8",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1X4\\N0F0&S0&C1&D2\\K5\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4F0&S1\\K5\015", /* wake_str */
+#else
+ "ATQ0X4F0\\K5\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\015", /* swfc_str */
+ "AT\\H0\\Q0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C3\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT-J0\015", /* sb_on_str */
+ "AT-J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ZOOM = /* Zoom Telephonics V.32bis */
+ {
+ "Zoom Telephonics V.32bis",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1N1W1X4&S0&C1&D2S82=128S95=47\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1N1W1X4&S1S82=128S95=47\015", /* wake_str */
+#else
+ "ATQ0E1N1W1X4S82=128S95=47\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5S36=7S48=7\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "ATS46=138\015", /* dc_on_str */
+ "ATS46=136\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ZYXEL = /* ZyXEL U-Series */
+ {
+ "ZyXEL U-Series V.32bis or higher",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1&S0&C1&D2&N0X5&Y1\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1&S1&N0X5&Y1\015", /* wake_str */
+#else
+ "ATQ0E1&N0X5&Y1\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&H3\015", /* hwfc_str */
+ "AT&H4\015", /* swfc_str */
+ "AT&H0\015", /* nofc_str */
+ "AT&K3\015", /* ec_on_str */
+ "AT&K0\015", /* ec_off_str */
+ "AT&K4\015", /* dc_on_str */
+ "AT&K3\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ZOLTRIX = /* Zoltrix */
+ {
+ "Zoltrix V.32bis and V.34 modems with Rockwell ACI chipset",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1F0W1X4Y0&S0&C1&D2\\K5S82=128S95=41\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1F0W1X4Y0&S1\\K5S82=128S95=41\015", /* wake_str */
+#else
+ "ATQ0E1F0W1X4Y0\\K5S82=128S95=41\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "ATS46=138%C3\015", /* dc_on_str */
+ "ATS46=136%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\N0\015", /* sb_on_str */
+ "AT&Q0\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MOTOROLA = { /* Motorola FasTalk II or Lifestyle */
+/*
+ "\E" and "\X" commands removed - Motorola Lifestyle doesn't have them.
+ \E0 = Don't echo while online
+ \X0 = Process Xon/Xoff but don't pass through
+*/
+ "Motorola FasTalk II or Lifestyle", /* Name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1X4&S0&C1&D2\\K5\\V1\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1\\K5\\V1\015", /* wake_str */
+#else
+ "ATQ0E1X4\\K5\\V1\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N6\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\J0\015", /* sb_on_str */
+ "AT\\J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF BOCA = /* Boca */
+ {
+ "BOCA 14.4 Faxmodem",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1F1N1W1&S0&C1&D2\\K5S37=11S82=128S95=47X4\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1F1N1W1&S1\\K5S37=11S82=128S95=47X4\015", /* wake_str */
+#else
+ "ATQ0E1F1N1W1\\K5S37=11S82=128S95=47X4\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3S36=7S48=7\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "ATS46=138\015", /* dc_on_str */
+ "ATS46=136\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF INTEL = /* Intel */
+ {
+ "Intel High-Speed Faxmodem",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1Y0X4&S0&C1&D2\\K1\\V2S25=50\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1Y0X4&S1\\K1\\V2S25=50\015", /* wake_str */
+#else
+ "ATQ0E1Y0X4\\K1\\V2S25=50\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "ATB1+FCLASS=0\015", /* dmode_str */
+ "OK\015", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\G1\\Q3\015", /* hwfc_str */
+ "AT\\G1\\Q1\\X0\015", /* swfc_str */
+ "AT\\G0\015", /* nofc_str */
+ "AT\\J0\\N3\"H3\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MULTITECH = /* Multitech */
+ {
+ "Multitech MT1432 or MT2834 Series",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+/* #P0 (= no parity) is not listed in the manual for newer models */
+/* so it has been removed from all three copies of the Multitech wake_str */
+#ifdef OS2
+ "ATE1Q0V1X4&S0&C1&D2&E8&Q0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1&E8&Q0\015", /* wake_str */
+#else
+ "ATQ0E1X4&E8&Q0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&E4&E7&E8&E11&E13\015", /* hwfc_str */
+ "AT&E5&E6&E8&E11&E13\015", /* swfc_str */
+ "AT&E3&E7&E8&E10&E12\015", /* nofc_str */
+ "AT&E1\015", /* ec_on_str */
+ "AT&E0\015", /* ec_off_str */
+ "AT&E15\015", /* dc_on_str */
+ "AT&E14\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT$BA0\015", /* sb_on_str (= "baud adjust off") */
+ "AT$BA1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF SUPRA = /* Supra */
+ {
+ "SupraFAXModem 144 or 288",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1N1W0X4Y0&S0&C1&D2\\K5S82=128\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1N1W0X4Y0&S1\\K5S82=128\015", /* wake_str */
+#else
+ "ATQ0E1N1W0X4Y0\\K5S82=128\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\\N3S48=7\015", /* ec_on_str */
+ "AT&Q0\\N1\015", /* ec_off_str */
+ "AT%C1S46=138\015", /* dc_on_str */
+ "AT%C0S46=136\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM\015", /* sp_off_str */
+ "ATL\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF SUPRAX = /* Supra Express */
+ {
+ "Diamond Supra Express V.90",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1W0X4&C1&D2&S0\\K5\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1W0X4&S1\\K5\015", /* wake_str */
+#else
+ "ATQ0E1W0X4\\K5\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C2\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM\015", /* sp_off_str */
+ "ATL\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 230400L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MAXTECH = /* MaxTech */
+ {
+ "MaxTech XM288EA or GVC FAXModem",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4Y0&S0&C1&D2&L0&M0\\K5\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4Y0&L0&M0&S1\\K5\015", /* wake_str */
+#else
+ "ATQ0E1X4Y0&L0&M0\\K5\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\\X0\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N6\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT\\N6%C1\015", /* dc_on_str */
+ "AT\\N6%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ROLM = /* IBM / Siemens / Rolm 8000, 9000, 9751 CBX DCM */
+ {
+ "IBM/Siemens/Rolm CBX Data Communications Module",
+ "", /* pulse command */
+ "", /* tone command */
+ 60, /* dial_time */
+ "", /* pause_chars */
+ 0, /* pause_time */
+ "\015\015", /* wake_str */
+ 50, /* wake_rate */
+ "MODIFY?", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "CALL %s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 19200L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF USR = /* USR Courier and Sportster modems */
+ {
+ "US Robotics Courier, Sportster, or compatible",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&A3&S0&C1&D2&N0&Y3S14=0\015", /* wake_str */
+#else
+#ifdef SUNOS4
+ "ATQ0X4&A3&S0&N0&Y3S14=0\015", /* wake_str -- needs &S0 in SunOS */
+#else
+#ifdef VMS
+ "ATQ0X4&A3&S1&N0&Y3S14=0\015", /* wake_str -- needs &S1 in VMS */
+#else
+ "ATQ0X4&A3&N0&Y3S14=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* SUNOS4 */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&H1&R2&I0\015", /* hwfc_str */
+ "AT&H2&R1&I2\015", /* swfc_str */
+ "AT&H0&R1&I0\015", /* nofc_str */
+ "AT&M4&B1\015", /* ec_on_str */
+ "AT&M0\015", /* ec_off_str */
+ "AT&K1\015", /* dc_on_str */
+ "AT&K0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+
+static
+MDMINF USRX2 = /* USR XJ-CC1560 X2 56K */
+ {
+ "US Robotics / Megahertz CC/XJ-CC1560 X2",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&A3&S0&B2&C1&D2&N0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4&A3&B2&N0&S1\015", /* wake_str */
+#else
+ "ATQ0X4&A3&B2&N0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&H1&I0\015", /* hwfc_str */
+ "AT&H2&I2\015", /* swfc_str */
+ "AT&H0&I0\015", /* nofc_str */
+ "AT&M4\015", /* ec_on_str */
+ "AT&M0\015", /* ec_off_str */
+ "AT&K1\015", /* dc_on_str */
+ "AT&K0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT&B1\015", /* sb_on_str */
+ "AT&B0\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF OLDTB = /* Old Telebits */
+ {
+ "Telebit TrailBlazer, T1000, T1500, T2000, T2500",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 60, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "\021AAAAATQ0E1V1X1&S0&C1&D2S12=50S50=0S54=3\015", /* wake_str. */
+#else
+#ifdef VMS
+ "\021AAAAATQ0X1S12=50S50=0S54=3\015", /* wake_str. */
+#else
+ "\021AAAAATQ0X1&S1S12=50S50=0S54=3\015", /* wake_str. */
+#endif /* VMS */
+#endif /* OS2 */
+ 100, /* wake_rate = 100 msec */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str, Note: no T or P */
+ 80, /* dial_rate */
+ 1100, /* esc_time (guard time) */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "ATS58=2S68=2\015", /* hwfc_str */
+ "ATS58=3S68=3S69=0\015", /* swfc_str */
+ "ATS58=0S68=0\015", /* nofc_str */
+ "ATS66=1S95=2\015", /* ec_on_str */
+ "ATS95=0\015", /* ec_off_str */
+ "ATS110=1S96=1\015", /* dc_on_str */
+ "ATS110=0S96=0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 19200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW|CKD_TB|CKD_KS, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF NEWTB = /* New Telebits */
+ {
+ "Telebit T1600, T3000, QBlazer, WorldBlazer, etc.",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 60, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "\021AAAAATQ0E1V1X2&S0&C1&D2S12=50S50=0S61=0S63=0\015", /* wake_str. */
+#else
+#ifdef VMS
+ "\021AAAAATQ0X2&S1S12=50S50=0S61=0S63=0\015", /* wake_str. */
+#else
+ "\021AAAAATQ0X2S12=50S50=0S61=0S63=0\015", /* wake_str. */
+#endif /* VMS */
+#endif /* OS2 */
+ 100, /* wake_rate = 100 msec */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str, Note: no T or P */
+ 80, /* dial_rate */
+ 1100, /* esc_time (guard time) */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "ATS58=2S68=2\015", /* hwfc_str */
+ "ATS58=3S68=3\015", /* swfc_str */
+ "ATS58=0S68=0\015", /* nofc_str */
+ "ATS180=3\015", /* ec_on_str */
+ "ATS180=0\015", /* ec_off_str */
+ "ATS190=1\015", /* dc_on_str */
+ "ATS190=0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 38400L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW|CKD_TB|CKD_KS, /* capas */
+ getok /* ok_fn */
+};
+#endif /* MINIDIAL */
+
+static
+MDMINF DUMMY = /* dummy information for modems that are handled elsewhere */
+ {
+ "(dummy)",
+ "", /* pulse command */
+ "", /* tone command */
+ 30, /* dial_time */
+ "", /* pause_chars */
+ 0, /* pause_time */
+ "", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+#ifndef MINIDIAL
+static
+MDMINF RWV32 = /* Generic Rockwell V.32 */
+ {
+ "Generic Rockwell V.32 modem", /* ATI3, ATI4, and ATI6 for details */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4Y0&S0&C1&D2%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4Y0&S1%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */
+#else
+ "ATQ0X4Y0%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q6\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF RWV32B = /* Generic Rockwell V.32bis */
+ {
+ "Generic Rockwell V.32bis modem", /* ATI3, ATI4, and ATI6 for details */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4Y0&S0&C1&D2%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4Y0&S1%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */
+#else
+ "ATQ0X4Y0%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "ATS%C1\015", /* dc_on_str */
+ "ATS%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF RWV34 = /* Generic Rockwell V.34 Data/Fax */
+ {
+ "Generic Rockwell V.34 modem", /* ATI3, ATI4, and ATI6 for details */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0V1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0\015", /* wake_str */
+#else
+ "ATQ0V1X4Y0&C1&D2%E2\\K5+FCLASS=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "ATS%C3\015", /* dc_on_str */
+ "ATS%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF RWV90 = /* Generic Rockwell V.90 Data/Fax */
+ {
+ "Generic Rockwell V.90 56K modem", /* ATI3, ATI4, and ATI6 for details */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0\015", /* K95 */
+#else
+#ifdef VMS
+ "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0\015", /* wake_str */
+#else
+ "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "AT%C3\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MWAVE = /* IBM Mwave */
+ {
+ "IBM Mwave Adapter",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4Y0&S0&C1&D2&M0&Q0&N1\\K3\\T0%E2S28=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4Y0&M0&S1&Q0&N1&S0\\K3\\T0%E2S28=0\015", /* wake_str */
+#else
+ "ATQ0X4Y0&M0&Q0&N1&S0\\K3\\T0%E2S28=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "", /* swfc_str (it doesn't!) */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N7\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C1\"H3\015", /* dc_on_str */
+ "AT%C0\"H0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF TELEPATH = /* Gateway 2000 Telepath */
+ {
+ "Gateway 2000 Telepath II 28.8",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&S0&C1&D2&N0&Y2#CLS=0S13=0S15=0S19=0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4&N0&S1&Y1#CLS=0S13=0S15=0S19=0\015", /* wake_str */
+#else
+ "ATQ0X4&N0&Y1#CLS=0S13=0S15=0S19=0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&H1&R2\015", /* hwfc_str */
+ "AT&H2&I2S22=17S23=19\015", /* swfc_str */
+ "AT&H0&I0&R1\015", /* nofc_str */
+ "AT&M4&B1\015", /* ec_on_str -- also fixes speed */
+ "AT&M0\015", /* ec_off_str */
+ "AT&K1\015", /* dc_on_str */
+ "AT&K0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF CARDINAL = /* Cardinal - based on Rockwell V.34 */
+ {
+ "Cardinal MVP288X Series", /* ATI3, ATI4, and ATI6 for details */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4W1Y0%E2&S0&C1&D2\\K5+FCLASS=0+MS=11,1\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4W1Y0&S1%E2\\K5+FCLASS=0+MS=11,1\015", /* wake_str */
+#else
+ "ATQ0X4W1Y0%E2\\K5+FCLASS=0+MS=11,1\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5S36=7S48=7\\N3\015", /* ec_on_str */
+ "AT&Q0S48=128\\N1\015", /* ec_off_str */
+ "ATS46=138%C1\015", /* dc_on_str */
+ "ATS46=136%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF LUCENT = /* Lucent Venus or Data/Fax modem */
+ {
+ "Lucent Venus chipset",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0\015", /* K95 */
+#else
+#ifdef VMS
+ "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0\015", /* VMS */
+#else
+ "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0\015", /* All others */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF CONEXANT = /* Conexant family */
+ {
+ "Conexant family of modems",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1X4&C1&D2&S0%E1+FCLASS=0\015", /* K95 */
+#else
+#ifdef VMS
+ "ATQ0V1X4&C1&D2&S1%E1+FCLASS=0\015", /* VMS */
+#else
+ "ATQ0V1X4&C1&D2%E1+FCLASS=0\015", /* UNIX etc */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "AT%C3\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF PCTEL = /* PCTel chipset */
+ {
+ "PCTel chipset",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5S37=0\015", /* K95 */
+#else
+#ifdef VMS
+ "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5S37=0\015", /* VMS */
+#else
+ "ATQ0V1N1X4Y0&C1&D2%E2\\K5S37=0\015", /* UNIX etc */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ZOOMV34 = /* Zoom Telephonics V.34 */
+ {
+ "Zoom Telephonics V.34",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1N1W1X4&S0&C1&D2S82=128\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0V1N1W1X4&S1S82=128\015", /* wake_str */
+#else
+ "ATQ0V1N1W1X4S82=128S015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015S32=17S33=19", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "ATS%C3\015", /* dc_on_str */
+ "ATS%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ZOOMV90 = /* ZOOM V.90 */
+ {
+ "Zoom V.90 56K",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0\015", /* K95 */
+#else
+#ifdef VMS
+ "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0\015", /* VMS */
+#else
+ "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0\015", /* All others */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ZOOMV92 = /* ZOOM V.92 */
+ {
+ "Zoom V.92 with V.44 compression",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0+MS=V92\015", /* K95 */
+#else
+#ifdef VMS
+ "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0+MS=V92\015", /* VMS */
+#else
+ "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0+MS=V92\015", /* All others */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4S32=17S33=19\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT&Q5\015", /* ec_on_str */
+ "AT&Q0\015", /* ec_off_str */
+ "AT%C1+DCS=1,1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+
+/*
+ Now the "old" modems, all grouped together, and also within
+ "if not defined MINIDIAL"...
+*/
+#ifdef OLDMODEMS
+
+static
+MDMINF CERMETEK = /* Information for "Cermetek Info-Mate 212 A" modem */
+ {
+ "Cermetek Info-Mate 212 A",
+ "", /* pulse command */
+ "", /* tone command */
+ 20, /* dial_time */
+ "BbPpTt", /* pause_chars */
+ 0, /* pause_time */
+ " XY\016R\015", /* wake_str */
+ 200, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "\016D '%s'\015", /* dial_str */
+ 200, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 1200L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF DF03 = /* information for "DEC DF03-AC" modem */
+ {
+ "Digital DF03-AC",
+ "", /* pulse command */
+ "", /* tone command */
+ 27, /* dial_time */
+ "=", /* pause_chars */
+ 15, /* pause_time */
+ "\001\002", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "%s", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF DF100 = /* information for "DEC DF100-series" modem */
+ /*
+ * The telephone "number" can include "P"s and/or "T"s
+ * within it to indicate that subsequent digits are
+ * to be dialed using pulse or tone dialing. The
+ * modem defaults to pulse dialing. You may modify
+ * the dial string below to explicitly default all
+ * dialing to pulse or tone, but doing so prevents
+ * the use of phone numbers that you may have stored
+ * in the modem's memory.
+ */
+ {
+ "Digital DF-100",
+ "", /* pulse command */
+ "", /* tone command */
+ 30, /* dial_time */
+ "=", /* pause_chars */
+ 15, /* pause_time */
+ "\001", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "%s#", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF DF200 = /* information for "DEC DF200-series" modem */
+ /*
+ * The telephone "number" can include "P"s and/or "T"s
+ * within it to indicate that subsequent digits are
+ * to be dialed using pulse or tone dialing. The
+ * modem defaults to pulse dialing. You may modify
+ * the dial string below to explicitly default all
+ * dialing to pulse or tone, but doing so prevents
+ * the use of phone numbers that you may have stored
+ * in the modem's memory.
+ */
+ {
+ "Digital DF-200",
+ "", /* pulse command */
+ "", /* tone command */
+ 30, /* dial_time */
+ "=W", /* pause_chars */ /* =: second tone; W: 5 secs */
+ 15, /* pause_time */ /* worst case */
+ "\002", /* wake_str */ /* allow stored number usage */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+#ifdef COMMENT
+ "%s!", /* dial_str */
+#else
+ " d %s\015",
+#endif /* COMMENT */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF GDC = /* information for "GeneralDataComm 212A/ED" modem */
+ {
+ "GeneralDataComm 212A/ED",
+ "", /* pulse command */
+ "", /* tone command */
+ 32, /* dial_time */
+ "%", /* pause_chars */
+ 3, /* pause_time */
+ "\015\015", /* wake_str */
+ 500, /* wake_rate */
+ "$", /* wake_prompt */
+ "D\015", /* dmode_str */
+ ":", /* dmode_prompt */
+ "T%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 1200L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF PENRIL = /* information for "Penril" modem */
+ {
+ "Penril modem",
+ "", /* pulse command */
+ "", /* tone command */
+ 50, /* dial_time */
+ "", /* pause_chars */
+ 0, /* pause_time */
+ "\015\015", /* wake_str */
+ 300, /* wake_rate */
+ ">", /* wake_prompt */
+ "k\015", /* dmode_str */
+ ":", /* dmode_prompt */
+ "%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF RACAL = /* Racal Vadic VA4492E */
+ {
+ "Racal Vadic VA4492E",
+ "", /* pulse command */
+ "", /* tone command */
+ 35, /* dial_time (manual says modem is hardwired to 60) */
+ "Kk", /* pause_chars */
+ 5, /* pause_time */
+ "\005\015", /* wake_str, ^E^M */
+ 50, /* wake_rate */
+ "*", /* wake_prompt */
+ "D\015", /* dmode_str */
+ "?", /* dmode_prompt */
+ "%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 5, /* esc_char, ^E */
+ "\003\004", /* hup_str, ^C^D */
+ 0, /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF VENTEL = /* Information for Ven-Tel modem */
+ {
+ "Ven-Tel",
+ "", /* pulse command */
+ "", /* tone command */
+ 20, /* dial_time */
+ "%", /* pause_chars */
+ 5, /* pause_time */
+ "\015\015\015", /* wake_str */
+ 300, /* wake_rate */
+ "$", /* wake_prompt */
+ "K\015", /* dmode_str (was "") */
+ "Number to call: ", /* dmode_prompt (was NULL) */
+ "%s\015", /* dial_str (was "<K%s\r>") */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+
+static
+MDMINF CONCORD = /* Info for Condor CDS 220 2400b modem */
+ {
+ "Concord Condor CDS 220 2400b",
+ "", /* pulse command */
+ "", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+ "\015\015", /* wake_str */
+ 20, /* wake_rate */
+ "CDS >", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "<D M%s\015>", /* dial_str */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char */
+ "", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_off_str */
+ "", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 2400L, /* max_speed */
+ 0, /* capas */
+ NULL /* ok_fn */
+};
+#endif /* OLDMODEMS */
+
+static
+MDMINF MICROCOM = /* Microcom modems in native SX mode */
+ /* (long answer only) */
+{
+ "Microcom MNP modems in SX command mode",
+ "DP\015", /* pulse command */
+ "DT\015", /* tone command */
+ 35, /* dial_time */
+ ",!@", /* pause_chars (! and @ aren't pure pauses) */
+ 3, /* pause_time */
+/*
+ The following sets 8 bits, no parity, BREAK passthru, and SE0 disables the
+ escape character, which is a single character with no guard time, totally
+ unsafe, so we have no choice but to disable it. Especially since, by
+ default, it is Ctrl-A, which is Kermit's packet-start character. We would
+ change it to something else, which would enable "mdmhup()", but the user
+ wouldn't know about it. Very bad. Note: SE1 sets it to Ctrl-A, SE2
+ sets it to Ctrl-B, etc (1..31 allowed). Also SE/Q sets it to "Q".
+*/
+ "SE0;S1P4;SBRK5\015", /* wake_str */
+ 100, /* wake_rate */
+ "!", /* wake_prompt */
+ "", /* dmode_str */
+ NULL, /* dmode_prompt */
+ "D%s\015", /* dial_str - number up to 39 chars */
+ 0, /* dial_rate */
+ 0, /* esc_time */
+ 0, /* esc_char - we can't use this */
+ "", /* hup_str - it's "H" but can't use */
+ "SF13\015", /* hwfc_str */
+ "SF11\015", /* swfc_str */
+ "SF10\015", /* nofc_str */
+ "BAOFF;SMAUT\015", /* ec_on_str */
+ "BAON;SMDIR\015", /* ec_off_str */
+ "COMP1\015", /* dc_on_str */
+ "COMP0\015", /* dc_off_str */
+ "AA", /* aa_on_str */
+ "", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "SA2", /* sp_off_str */
+ "SA0", /* sp_on_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 0L, /* max_speed */
+ CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW|CKD_KS, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MICROLINK = /* MicroLink ... */
+ { /* 14.4TQ,TL,PC;28.8TQ,TQV;2440T/TR */
+ "ELSA MicroLink 14.4, 28.8, 33.6 or 56K", /* ELSA GmbH, Aachen */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&S0\\D0&C1&D2\\K5\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4&S1\\K5\015", /* wake_str */
+#else
+ "ATQ0X4\\K5\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\\X0\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C3\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "\\J0", /* sb_on_str (?) */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ULINKV250 = /* MicroLink V.250 */
+ { /* 56Kflex, V.90; V.250 command set */
+ "ELSA MicroLink 56K V.250", /* ELSA GmbH, Aachen */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ /* \D0 = DSR & CTS always on but hwfc overrides on CTS. */
+ "ATQ0E1V1X4&S0\\D0&C1&D2\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0X4&S1\015", /* wake_str */
+#else
+ "ATQ0X4\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT+IFC=2,2\015", /* hwfc_str */
+ "AT+IFC=1,1\015", /* swfc_str */
+ "AT+IFC=0,0\015", /* nofc_str */
+ "AT+ES=3,0\015", /* ec_on_str */
+ "AT+ES=1,0\015", /* ec_off_str */
+ "AT+DS=3,0,2048,32\015", /* dc_on_str */
+ "AT+DS=0,0\015", /* dc_off_str */
+
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str (?) */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+#endif /* MINIDIAL */
+
+static
+MDMINF ITUTV250 = /* ITU-T V.250 conforming modem */
+{
+ "Any ITU-T V.25ter/V.250 conformant modem",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+ "ATQ0E1V1X4&C1&D2\015", /* wake_str (no &Sn in V.25) */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT+IFC=2,2\015", /* hwfc_str */
+ "AT+IFC=1,1\015", /* swfc_str */
+ "AT+IFC=0,0\015", /* nofc_str */
+ "AT+ES=3,0,2;+EB=1,0,30\015", /* ec_on_str */
+ "AT+ES=0\015", /* ec_off_str */
+ "AT+DS=3,0\015", /* dc_on_str */
+ "AT+DS=0,0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+#ifndef CK_TAPI
+static
+#endif /* CK_TAPI */
+MDMINF GENERIC = /* Generic high speed ... */
+ {
+ "Generic high-speed AT command set",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+ "", /* wake_str */
+ 0, /* wake_rate */
+ "", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_on_str */
+ "", /* sp_off_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW, /* capas */
+ getok /* ok_fn */
+};
+
+#ifndef MINIDIAL
+static
+MDMINF XJACK = /* Megahertz X-Jack */
+ {
+ "Megahertz X-Jack XJ3144 / CC6144",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4N1&C1&D2\\K5\015", /* wake_str */
+#else
+ "ATQ0X4N1\\K5\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3&Q5\015", /* ec_on_str */
+ "AT\\N1&Q0\015", /* ec_off_str */
+ "AT%C3\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF SPIRITII = /* QuickComm Spirit II */
+ {
+ "QuickComm Spirit II",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+ "AT&F\015", /* wake_str */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H\015", /* hup_str */
+ "AT*F3\015", /* hwfc_str */
+ "AT*F2\015", /* swfc_str */
+ "AT*F0\015", /* nofc_str */
+ "AT*E6\015", /* ec_on_str */
+ "AT*E0\015", /* ec_off_str */
+ "AT*E9\015", /* dc_on_str */
+ "AT*E0\015", /* dc_off_str */
+ "ATS0=2\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MONTANA = { /* Motorola Montana */
+ "Motorola Montana", /* Name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&S0&C1&D2\\K5\\V1\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1\\K5\\V1\015", /* wake_str */
+#else
+ "ATQ0E1X4\\K5\\V1\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N4\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\J0\015", /* sb_on_str */
+ "AT\\J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF COMPAQ = { /* Compaq Data+Fax Modem */
+ "Compaq Data+Fax Modem", /* Name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&S0&C1&D2\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1\015", /* wake_str */
+#else
+ "ATQ0E1X4\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str (same as &K3) */
+ "AT\\Q1\015", /* swfc_str (same as &K4) */
+ "AT\\Q0\015", /* nofc_str (same as &K0) */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\N3\015", /* sb_on_str */
+ "AT\\N1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL0\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+
+static
+MDMINF FUJITSU = { /* Fujitsu */
+ "Fujitsu Fax/Modem Adapter", /* Name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4&S0&C1&D2\\K5\\N3\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1\\K5\\N3\015", /* wake_str */
+#else
+ "ATQ0E1X4\\K5\\N3\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\\Q3\015", /* hwfc_str */
+ "AT&K4\\Q1\015", /* swfc_str */
+ "AT&K0\\Q0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C1", /* dc_on_str */
+ "AT%C0", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\J0\015", /* sb_on_str */
+ "AT\\J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MHZATT = /* Megahertz AT&T V.34 */
+ {
+ "Megahertz AT&T V.34",
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4N1&C1&D2\\K5\015", /* wake_str */
+#else
+ "ATQ0X4N1\\K5\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N0\015", /* ec_off_str */
+ "AT%C1\"H3\015", /* dc_on_str */
+ "AT%C0\"H0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\J0\015", /* sb_on_str */
+ "AT\\J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF SUPRASON = /* SupraSonic */
+ {
+ "Diamond SupraSonic 288V+", /* Diamond Multimedia Systems Inc */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1N1W0X4Y0&S0&C1&D2\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1N1W0X4Y0&S1\015", /* wake_str */
+#else
+ "ATQ0E1N1W0X4Y0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K\015", /* nofc_str */
+ "AT&Q5\\N3S48=7\015", /* ec_on_str */
+ "AT&Q0\\N1\015", /* ec_off_str */
+ "AT%C3S46=138\015", /* dc_on_str */
+ "AT%C0S46=136\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM\015", /* sp_off_str */
+ "ATL\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF BESTDATA = /* Best Data */
+ {
+ "Best Data Fax Modem", /* Best Data Fax Modem */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1N1W0X4Y0&S0&C1&D2\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1N1W0X4Y0&S1\015", /* wake_str */
+#else
+ "ATQ0E1N1W0X4Y0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K\015", /* nofc_str */
+ "AT&Q6\\N3\015", /* ec_on_str */
+ "AT&Q0\\N1\015", /* ec_off_str */
+ "AT%C3\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\N3\015", /* sb_on_str */
+ "AT\\N0\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ATT1900 = /* AT&T Secure Data STU III 1900 */
+ {
+ "AT&T Secure Data STU III Model 1900", /* name */
+ "", /* pulse command */
+ "", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4\015", /* wake_str */
+#else
+ "ATQ0E1X4\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_on_str */
+ "", /* sp_off_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 9600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_HW, /* capas */
+ getok /* ok_fn */
+};
+
+/*
+ Experimentation showed that hardly any of the documented commands did
+ anything other that print ERROR. At first there was no communication at
+ all at 9600 bps -- turns out the interface speed was stuck at 2400.
+ ATS28=130 (given at 2400 bps) allowed it to work at 9600.
+*/
+static
+MDMINF ATT1910 = /* AT&T Secure Data STU III 1910 */
+ { /* Adds V.32bis, V.42, V.42bis */
+ "AT&T Secure Data STU III Model 1910", /* name */
+
+/* Believe it or not, "ATT" and "ATP" result in ERROR */
+
+ "", /* pulse command */
+ "", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0E1V1X4\015", /* wake_str */
+#else
+ "ATQ0E1X4\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+#ifdef COMMENT
+/* These are evidently read-only registers */
+ "ATS46=138S47=0\015", /* ec_on_str */
+ "ATS46=138S47=128\015", /* ec_off_str */
+ "ATS46=138S47=0\015", /* dc_on_str */
+ "ATS46=138S47=128\015", /* dc_off_str */
+#else
+ "",
+ "",
+ "",
+ "",
+#endif /* COMMENT */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_on_str */
+ "", /* sp_off_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 9600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF KEEPINTOUCH = /* AT&T KeepinTouch Card Modem */
+ {
+ "AT&T KeepinTouch V.32bis Card Modem", /* Name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+/* This used to include &C1&S0&D2+Q0 but that gives ERROR */
+ "ATQ0E1V1X4&S0&C1&D2\\K5\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1\\K5\015", /* wake_str */
+#else
+ "ATQ0E1X4\\K5\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\\X0\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N3-J1\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C3\"H3\015", /* dc_on_str */
+ "AT%C0\"H0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "ATN0\\J0\015", /* sb_on_str */
+ "ATN1\\J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 57600L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ROLM_AT = /* Rolm data phone with AT command set */
+ {
+ "Rolm 244PC or 600 Series with AT Command Set",
+ "", /* pulse command */
+ "", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1\015", /* wake_str */
+#else
+ "ATQ0\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATDT%s\015", /* dial_str -- always Tone */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "", /* hwfc_str */
+ "", /* swfc_str */
+ "", /* nofc_str */
+ "", /* ec_on_str */
+ "", /* ec_off_str */
+ "", /* dc_on_str */
+ "", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "", /* sb_on_str */
+ "", /* sb_off_str */
+ "", /* sp_on_str */
+ "", /* sp_off_str */
+ "", /* vol1_str */
+ "", /* vol2_str */
+ "", /* vol3_str */
+ "", /* ignoredt */
+ "", /* ini2 */
+ 19200L, /* max_speed */
+ CKD_AT, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF ATLAS = /* Atlas / Newcom ixfC 33.6 */
+ {
+ "Atlas / Newcom 33600ixfC Data/Fax Modem", /* Name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATZ0&FQ0V1&C1&D2\015", /* wake_str */
+#else
+ "ATZ0&FQ0V1\015", /* wake_str */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\"H3\015", /* ec_on_str */
+ "AT\"H0\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "ATN0\\J0\015", /* sb_on_str */
+ "ATN1\\J1\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF CODEX = { /* Motorola Codex */
+ "Motorola Codex 326X Series", /* Name - AT&V to see settings */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ /* &M0=Async (not sync) */
+ /* *MM0=Automatic modulation negotiation */
+ /* *DE22=Automatic data rate */
+ "ATZQ0E1V1X4Y0*DE22*MM0&C1&M0&S0&D2\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATZQ0E1V1X4Y0*DE22*MM0&C1&M0&S1\015", /* wake_str */
+#else
+ "ATZQ0E1V1X4Y0*DE22*MM0&C1&M0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT*MF1*FL3\015", /* hwfc_str */
+ "AT*MF1*FL1\015", /* swfc_str */
+ "AT*MF0*FL0\015", /* nofc_str */
+ "AT*EC0*SM3*SC0\015", /* ec_on_str */
+ "AT*SM0\015", /* ec_off_str */
+ "AT*DC1\015", /* dc_on_str */
+ "AT*DC0\015", /* dc_off_str */
+ "AT*AA5S0=1\015", /* aa_on_str */
+ "AT*AA5S0=0\015", /* aa_off_str */
+ "AT*SC1\015", /* sb_on_str */
+ "AT*SC0\015", /* sb_off_str */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3*BD2\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MT5634ZPX = /* Multitech */
+ {
+ "Multitech MT5634ZPX", /* name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATE1Q0V1X4&S0&C1&D2&Q0\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0E1X4&S1&Q0\015", /* wake_str */
+#else
+ "ATQ0E1X4&Q0\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT&K3\015", /* hwfc_str */
+ "AT&K4\015", /* swfc_str */
+ "AT&K0\015", /* nofc_str */
+ "AT\\N3\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\J0\015", /* sb_on_str */
+ "AT\\J1\015", /* sb_off_str (NOT SUPPORTED) */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+
+static
+MDMINF MOTSM56 = /* Motorola SM56 Chipset */
+ {
+ "Motorola SM56 V.90 chipset", /* name */
+ "ATP\015", /* pulse command */
+ "ATT\015", /* tone command */
+ 35, /* dial_time */
+ ",", /* pause_chars */
+ 2, /* pause_time */
+#ifdef OS2
+ "ATQ0V1X4&S0&C1&D2*MM16\015", /* wake_str */
+#else
+#ifdef VMS
+ "ATQ0V1X4&S1&C1&D2*MM16\015", /* wake_str */
+#else
+ "ATQ0V1X4&C1&D2*MM16\015", /* wake_str */
+#endif /* VMS */
+#endif /* OS2 */
+ 0, /* wake_rate */
+ "OK\015", /* wake_prompt */
+ "", /* dmode_str */
+ "", /* dmode_prompt */
+ "ATD%s\015", /* dial_str */
+ 0, /* dial_rate */
+ 1100, /* esc_time */
+ 43, /* esc_char */
+ "ATQ0H0\015", /* hup_str */
+ "AT\\Q3\015", /* hwfc_str */
+ "AT\\Q1\015", /* swfc_str */
+ "AT\\Q0\015", /* nofc_str */
+ "AT\\N7\015", /* ec_on_str */
+ "AT\\N1\015", /* ec_off_str */
+ "AT%C1\015", /* dc_on_str */
+ "AT%C0\015", /* dc_off_str */
+ "ATS0=1\015", /* aa_on_str */
+ "ATS0=0\015", /* aa_off_str */
+ "AT\\J0\015", /* sb_on_str */
+ "AT\\J1\015", /* sb_off_str (NOT SUPPORTED) */
+ "ATM1\015", /* sp_on_str */
+ "ATM0\015", /* sp_off_str */
+ "ATL1\015", /* vol1_str */
+ "ATL2\015", /* vol2_str */
+ "ATL3\015", /* vol3_str */
+ "ATX3\015", /* ignoredt */
+ "", /* ini2 */
+ 115200L, /* max_speed */
+ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */
+ getok /* ok_fn */
+};
+#endif /* MINIDIAL */
+
+/* END MDMINF STRUCT DEFINITIONS */
+
+/*
+ Table to convert modem numbers to MDMINF struct pointers.
+ The entries MUST be in ascending order by modem number, without any
+ "gaps" in the numbers, and starting from one (1).
+*/
+
+MDMINF *modemp[] = {
+#ifdef MINIDIAL
+ NULL, /* 0 */
+ &CCITT, /* 1 */
+ &HAYES, /* 2 */
+ &UNKNOWN, /* 3 */
+ &DUMMY, /* 4 */
+ &GENERIC, /* 5 */
+ &ITUTV250 /* 6 */
+#else /* Not MINIDIAL */
+ NULL, /* 0 */
+ &ATTDTDM, /* 1 */
+ &ATTISN, /* 2 */
+ &ATTMODEM, /* 3 */
+ &CCITT, /* 4 */
+#ifdef OLDMODEMS
+ &CERMETEK, /* 5 */
+ &DF03, /* 6 */
+ &DF100, /* 7 */
+ &DF200, /* 8 */
+ &GDC, /* 9 */
+#else
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#endif /* OLDMODEMS */
+ &HAYES, /* 10 */
+#ifdef OLDMODEMS
+ &PENRIL, /* 11 */
+ &RACAL, /* 12 */
+#else
+ NULL,
+ NULL,
+#endif /* OLDMODEMS */
+ &UNKNOWN, /* 13 */
+#ifdef OLDMODEMS
+ &VENTEL, /* 14 */
+ &CONCORD, /* 15 */
+#else
+ NULL,
+ NULL,
+#endif /* OLDMODEMS */
+ &DUMMY, /* 16 */
+ &ROLM, /* 17 */
+#ifdef OLDMODEMS
+ &MICROCOM, /* 18 */
+#else
+ NULL,
+#endif /* OLDMODEMS */
+ &USR, /* 19 USR Courier and Sportster */
+ &OLDTB, /* 20 Old Telebits */
+ &DIGITEL, /* 21 Digitel CCITT */
+ &H_1200, /* 22 Hayes 1200 */
+ &H_ULTRA, /* 23 Hayes Ultra */
+ &H_ACCURA, /* 24 Hayes Optima */
+ &PPI, /* 25 PPI */
+ &DATAPORT, /* 26 Dataport */
+ &BOCA, /* 27 Boca */
+ &MOTOROLA, /* 28 Motorola UDS MOTOROLA */
+ NULL, /* 29 Digicomm */
+ NULL, /* 30 Dynalink */
+ &INTEL, /* 31 Intel */
+ &UCOM_AT, /* 32 Microcom in AT mode */
+ &MULTITECH, /* 33 Multitech */
+ &SUPRA, /* 34 Supra */
+ &ZOLTRIX, /* 35 Zoltrix */
+ &ZOOM, /* 36 Zoom */
+ &ZYXEL, /* 37 ZyXEL */
+ &DUMMY, /* 38 TAPI */
+ &NEWTB, /* 39 New-Telebit */
+ &MAXTECH, /* 40 MaxTech */
+ &DUMMY, /* 41 User-defined */
+ &RWV32, /* 42 Rockwell V.32 */
+ &RWV32B, /* 43 Rockwell V.32bis */
+ &RWV34, /* 44 Rockwell V.34 */
+ &MWAVE, /* 45 IBM Mwave */
+ &TELEPATH, /* 46 Gateway 2000 Telepath II 28.8 */
+ &MICROLINK, /* 47 MicroLink modems */
+ &CARDINAL, /* 48 Cardinal */
+ &GENERIC, /* 49 Generic high-speed */
+ &XJACK, /* 50 Megahertz-Xjack */
+ &SPIRITII, /* 51 QuickComm Spirit II */
+ &MONTANA, /* 52 Motorola Montana */
+ &COMPAQ, /* 53 Compaq Data+Fax */
+ &FUJITSU, /* 54 Fujitsu */
+ &MHZATT, /* 55 Megahertz AT&T V.34 */
+ &SUPRASON, /* 56 Suprasonic */
+ &BESTDATA, /* 57 Best Data */
+ &ATT1900, /* 58 AT&T Secure Data STU III 1900 */
+ &ATT1910, /* 59 AT&T Secure Data STU III 1910 */
+ &KEEPINTOUCH, /* 60 AT&T KeepinTouch */
+ &USRX2, /* 61 USR XJ-1560 X2 */
+ &ROLM_AT, /* 62 Rolm with AT command set */
+ &ATLAS, /* 63 Atlas / Newcom */
+ &CODEX, /* 64 Motorola Codex */
+ &MT5634ZPX, /* 65 Multitech MT5634ZPX */
+ &ULINKV250, /* 66 Microlink V.250 56K */
+ &ITUTV250, /* 67 Generic ITU-T V.250 */
+ &RWV90, /* 68 Rockwell V.90 56K */
+ &SUPRAX, /* 69 Diamond Supra Express V.90 */
+ &LUCENT, /* 70 Lucent Venus chipset */
+ &PCTEL, /* 71 PCTel */
+ &CONEXANT, /* 72 Conexant */
+ &ZOOMV34, /* 73 Zoom V.34 */
+ &ZOOMV90, /* 74 Zoom V.90 */
+ &ZOOMV92, /* 75 Zoom V.92 */
+ &MOTSM56 /* 76 Motorola SM56 chipset */
+#endif /* MINIDIAL */
+};
+/*
+ * Declare modem names and associated numbers for command parsing,
+ * and also for doing number-to-name translation.
+ *
+ * The entries must be in alphabetical order by modem name.
+ */
+struct keytab mdmtab[] = {
+#ifndef MINIDIAL
+ "3com-usr-megahertz-56k", n_USRX2, CM_INV,
+ "acer-v90", n_RWV90, M_ALIAS,
+ "atlas-newcom-33600ifxC", n_ATLAS, 0,
+ "att-1900-stu-iii", n_ATT1900, 0,
+ "att-1910-stu-iii", n_ATT1910, 0,
+ "att-7300", n_ATTUPC, 0,
+ "att-dataport", n_DATAPORT, 0,
+ "att-dtdm", n_ATTDTDM, 0,
+ "att-isn", n_ATTISN, 0,
+ "att-keepintouch", n_KEEPINTOUCH, 0,
+ "att-switched-net", n_ATTMODEM, 0,
+
+ "att7300", n_ATTUPC, CM_INV, /* old name */
+ "attdtdm", n_ATTDTDM, CM_INV, /* old name */
+ "attisn", n_ATTISN, CM_INV, /* old name */
+ "attmodem", n_ATTMODEM, CM_INV, /* old name */
+
+ "bestdata", n_BESTDATA, 0,
+ "boca", n_BOCA, 0,
+ "cardinal", n_CARDINAL, 0,
+#endif /* MINIDIAL */
+ "ccitt-v25bis", n_CCITT, CM_INV, /* Name changed to ITU-T */
+#ifndef MINIDIAL
+#ifdef OLDMODEMS
+ "cermetek", n_CERMETEK, M_OLD,
+#endif /* OLDMODEMS */
+ "compaq", n_COMPAQ, 0,
+#ifdef OLDMODEMS
+ "concord", n_CONCORD, M_OLD,
+#endif /* OLDMODEMS */
+ "conexant", n_CONEXANT, 0,
+ "courier", n_USR, CM_INV,
+ "dataport", n_DATAPORT, CM_INV, /* == att-dataport */
+#ifdef OLDMODEMS
+ "df03-ac", n_DF03, M_OLD,
+ "df100-series", n_DF100, M_OLD,
+ "df200-series", n_DF200, M_OLD,
+#endif /* OLDMODEMS */
+ "digitel-dt22", n_DIGITEL, 0,
+#endif /* MINIDIAL */
+ "direct", 0, CM_INV, /* Synonym for NONE */
+#ifndef MINIDIAL
+ "fujitsu", n_FUJITSU, 0,
+ "gateway-telepath", n_TELEPATH, 0,
+#ifdef OLDMODEMS
+ "gdc-212a/ed", n_GDC, M_OLD,
+ "ge", n_GENERIC, CM_INV|CM_ABR,
+ "gen", n_GENERIC, CM_INV|CM_ABR,
+ "gendatacomm", n_GDC, CM_INV, /* Synonym for GDC */
+#endif /* OLDMODEMS */
+#endif /* MINIDIAL */
+ "gene", n_GENERIC, CM_INV|CM_ABR,
+ "generic", n_GENERIC, 0,
+ "generic-high-speed",n_GENERIC, CM_INV,
+ "h", n_HAYES, CM_INV|CM_ABR,
+ "ha", n_HAYES, CM_INV|CM_ABR,
+ "hay", n_HAYES, CM_INV|CM_ABR,
+ "haye", n_HAYES, CM_INV|CM_ABR,
+ "hayes", n_HAYES, CM_INV|CM_ABR, /* Hayes 2400 */
+#ifndef MINIDIAL
+ "hayes-1200", n_H_1200, 0,
+#endif /* MINIDIAL */
+ "hayes-2400", n_HAYES, 0,
+#ifndef MINIDIAL
+ "hayes-high-speed", n_H_ACCURA, 0,
+ "hayes-accura", n_H_ACCURA, CM_INV,
+ "hayes-optima", n_H_ACCURA, CM_INV,
+ "hayes-ultra", n_H_ULTRA, CM_INV,
+ "hst-courier", n_USR, CM_INV, /* Synonym for COURIER */
+ "intel", n_INTEL, 0,
+#endif /* MINIDIAL */
+
+ "itu-t-v250", n_ITUTV250, 0,
+ "itu-t-v25bis", n_CCITT, 0, /* New name for CCITT */
+ "itu-t-v25ter/v250",n_ITUTV250, CM_INV,
+
+#ifndef MINIDIAL
+ "lucent", n_LUCENT, 0,
+ "maxtech", n_MAXTECH, 0,
+
+ "megahertz-att-v34", n_MHZATT, 0, /* Megahertzes */
+ "megahertz-xjack", n_XJACK, CM_INV|CM_ABR,
+ "megahertz-xjack-33.6", n_XJACK, 0,
+ "megahertz-xjack-56k", n_USRX2, 0, /* 3COM/USR/Megahertz 33.6 PC Card */
+
+ "mi", n_MICROCOM, CM_INV|CM_ABR,
+ "mic", n_MICROCOM, CM_INV|CM_ABR,
+ "micr", n_MICROCOM, CM_INV|CM_ABR,
+ "micro", n_MICROCOM, CM_INV|CM_ABR,
+ "microc", n_MICROCOM, CM_INV|CM_ABR,
+ "microco", n_MICROCOM, CM_INV|CM_ABR,
+ "microcom", n_MICROCOM, CM_INV|CM_ABR,
+ "microcom-at-mode", n_UCOM_AT, 0, /* Microcom DeskPorte, etc */
+ "microcom-sx-mode", n_MICROCOM, 0, /* Microcom AX,QX,SX, native mode */
+ "microlink", n_MICROLINK, 0,
+ "microlink-v250", n_ULINKV250, 0,
+ "motorola-codex", n_CODEX, 0,
+ "motorola-fastalk", n_MOTOROLA, 0,
+ "motorola-lifestyle",n_MOTOROLA, 0,
+ "motorola-montana", n_MONTANA, 0,
+ "motorola-sm56-v90",n_MOTSM56, 0,
+ "mt5634zpx", n_MT5634ZPX, 0,
+ "multitech", n_MULTI, 0,
+ "mwave", n_MWAVE, 0,
+#endif /* MINIDIAL */
+ "none", 0, 0,
+#ifndef MINIDIAL
+#ifndef OLDTBCODE
+ "old-telebit", n_TELEBIT, 0,
+#endif /* OLDTBCODE */
+ "pctel", n_PCTEL, 0,
+#ifdef OLDMODEMS
+ "penril", n_PENRIL, M_OLD,
+#endif /* OLDMODEMS */
+ "ppi", n_PPI, 0,
+#ifdef OLDMODEMS
+ "racalvadic", n_RACAL, M_OLD,
+#endif /* OLDMODEMS */
+ "rockwell-v32", n_RWV32, 0,
+ "rockwell-v32bis", n_RWV32B, 0,
+ "rockwell-v34", n_RWV34, 0,
+ "rockwell-v90", n_RWV90, 0,
+ "rolm", n_ROLM, CM_INV|CM_ABR,
+ "rolm-244pc", n_ROLMAT, 0,
+ "rolm-600-series", n_ROLMAT, 0,
+ "rolm-dcm", n_ROLM, 0,
+ "smartlink-v90", n_USR, M_ALIAS,
+ "spirit-ii", n_SPIRITII, 0,
+ "sportster", n_USR, M_ALIAS,
+ "sup", n_SUPRA, CM_INV|CM_ABR,
+ "supr", n_SUPRA, CM_INV|CM_ABR,
+ "supra", n_SUPRA, CM_INV|CM_ABR,
+ "supra-express-v90",n_SUPRAX, 0,
+ "suprafaxmodem", n_SUPRA, 0,
+ "suprasonic", n_SUPRASON, 0,
+#ifdef CK_TAPI
+ "tapi", n_TAPI, 0,
+#endif /* CK_TAPI */
+ "te", n_TBNEW, CM_INV|CM_ABR,
+ "tel", n_TBNEW, CM_INV|CM_ABR,
+ "telebit", n_TBNEW, 0,
+ "telepath", n_TELEPATH, CM_INV,
+#endif /* MINIDIAL */
+ "unknown", n_UNKNOWN, 0,
+ "user-defined", n_UDEF, 0,
+#ifndef MINIDIAL
+
+ "usr", n_USR, CM_INV|CM_ABR,
+ "usr-212a", n_HAYES, CM_INV|M_ALIAS,
+ "usr-courier", n_USR, CM_INV,
+ "usr-megahertz-56k", n_USRX2, 0,
+ "usr-sportster", n_USR, CM_INV,
+ "usr-xj1560-x2", n_USRX2, CM_INV,
+ "usrobotics", n_USR, 0,
+
+ "v25bis", n_CCITT, CM_INV, /* Name changed to ITU-T */
+#ifdef OLDMODEMS
+ "ventel", n_VENTEL, M_OLD,
+#endif /* OLDMODEMS */
+ "zoltrix-v34", n_ZOLTRIX, 0,
+ "zoltrix-hsp-v90", n_PCTEL, M_ALIAS,
+ "zoltrix-hcf-v90", n_ITUTV250, 0,
+ "zoo", n_ZOOM, CM_INV|CM_ABR,
+ "zoom", n_ZOOM, CM_INV|CM_ABR,
+ "zoom-v32bis", n_ZOOM, 0,
+ "zoom-v34", n_ZOOMV34, 0,
+ "zoom-v90", n_ZOOMV90, 0,
+ "zoom-v92", n_ZOOMV92, 0,
+ "zyxel", n_ZYXEL, 0,
+#endif /* MINIDIAL */
+ "", 0, 0
+};
+int nmdm = (sizeof(mdmtab) / sizeof(struct keytab)) - 1; /* Number of modems */
+
+#define CONNECTED 1 /* For completion status */
+#define D_FAILED 2
+#define D_PARTIAL 3
+
+static int tries = 0;
+static int mdmecho = 0; /* Assume modem does not echo */
+
+static char *p; /* For command strings & messages */
+
+#define LBUFL 200
+static char lbuf[LBUFL+4];
+char modemmsg[LBUFL+4] = { NUL, NUL }; /* DIAL response from modem */
+
+#ifdef DYNAMIC
+#define RBUFL 256
+static char *rbuf = NULL;
+#else
+#define RBUFL 63
+static char rbuf[RBUFL+1];
+#endif /* DYNAMIC */
+
+#ifdef DYNAMIC
+#define FULLNUML 256
+char *fbuf = NULL; /* For full (prefixed) phone number */
+#else
+#define FULLNUML 100
+char fbuf[FULLNUML];
+#endif /* DYNAMIC */
+
+static ckjmpbuf sjbuf;
+
+#ifdef CK_ANSIC
+static SIGTYP (*savalrm)(int); /* For saving alarm handler */
+static SIGTYP (*savint)(int); /* For saving interrupt handler */
+#else
+static SIGTYP (*savalrm)(); /* For saving alarm handler */
+static SIGTYP (*savint)(); /* For saving interrupt handler */
+#endif /* CK_ANSIC */
+
+#ifdef CKLOGDIAL
+static VOID
+dologdial(s) char *s; {
+ char buf2[16];
+ char * r = NULL;
+ int x, m, n;
+ extern char cxlogbuf[], uidbuf[], myhost[];
+
+ if (!s) s = "";
+ if ((x = strlen(s)) > 0) { /* Replace spaces by underscores */
+ r = (char *)malloc(x+1);
+ if (r) {
+ int i;
+ for (i = 0; i <= x; i++) {
+ if (s[i] != 0 && s[i] <= SP)
+ r[i] = '_';
+ else
+ r[i] = s[i];
+ }
+ s = r;
+ }
+ }
+ p = ckdate();
+ n = ckstrncpy(cxlogbuf,p,CXLOGBUFL);
+ if (!uidbuf[0]) {
+ debug(F100,"dologdial uidbuf empty","",0);
+ ckstrncpy(uidbuf,(char *)whoami(),UIDBUFLEN);
+ }
+ m = strlen(uidbuf)+strlen(myhost)+strlen(ttname)+strlen(s)+strlen(buf2)+32;
+ if (n+m < CXLOGBUFL-1) {
+ p = cxlogbuf+n;
+ if (diallcc && diallac) {
+ buf2[0] = '+';
+ ckmakmsg(&buf2[1],15,diallcc,"(",diallac,")");
+ } else {
+ ckstrncpy(buf2,"Unknown",16);
+ }
+ sprintf(p," %s %s T=DIAL H=%s D=%s N=%s O=%s ", /* safe (prechecked) */
+ uidbuf,
+ ckgetpid(),
+ myhost,
+ ttname,
+ s,
+ buf2
+ );
+ debug(F110,"dologdial cxlogbuf",cxlogbuf,0);
+ } else
+ sprintf(p,"LOGDIAL BUFFER OVERFLOW");
+ if (r) free(r);
+}
+#endif /* CKLOGDIAL */
+
+#ifndef MINIDIAL
+
+#ifdef COMMENT
+static VOID
+xcpy(to,from,len) /* Copy the given number of bytes */
+ register char *to, *from;
+ register unsigned int len; {
+ while (len--) *to++ = *from++;
+}
+#endif /* COMMENT */
+#endif /* MINIDIAL */
+
+static SIGTYP
+#ifdef CK_ANSIC
+dialtime(int foo) /* Timer interrupt handler */
+#else
+dialtime(foo) int foo; /* Timer interrupt handler */
+#endif /* CK_ANSIC */
+/* dialtime */ {
+
+ fail_code = F_TIME; /* Failure reason = timeout */
+ debug(F100,"dialtime caught SIGALRM","",0);
+#ifdef BEBOX
+#ifdef BE_DR_7
+ alarm_expired();
+#endif /* BE_DR_7 */
+#endif /* BEBOX */
+#ifdef OS2
+ signal(SIGALRM, dialtime);
+#endif /* OS2 */
+#ifdef __EMX__
+ signal(SIGALRM, SIG_ACK); /* Needed for OS/2 */
+#endif /* __EMX__ */
+
+#ifdef OSK /* OS-9 */
+/*
+ We are in an intercept routine but do not perform a F$RTE (done implicitly
+ by RTS), so we have to decrement the sigmask as F$RTE does. Warning:
+ longjump only restores the CPU registers, NOT the FPU registers. So, don't
+ use FPU at all or at least don't use common FPU (double or float) register
+ variables.
+*/
+ sigmask(-1);
+#endif /* OSK */
+
+#ifdef NTSIG
+ if (foo == SIGALRM)
+ PostAlarmSigSem();
+ else
+ PostCtrlCSem();
+#else /* NTSIG */
+#ifdef NT
+ cklongjmp(ckjaddr(sjbuf),1);
+#else /* NT */
+ cklongjmp(sjbuf,1);
+#endif /* NT */
+#endif /* NTSIG */
+ /* NOTREACHED */
+ SIGRETURN;
+}
+
+static SIGTYP
+#ifdef CK_ANSIC
+dialint(int foo) /* Keyboard interrupt handler */
+#else
+dialint(foo) int foo;
+#endif /* CK_ANSIC */
+/* dialint */ {
+ fail_code = F_INT;
+ debug(F100,"dialint caught SIGINT","",0);
+#ifdef OS2
+ signal(SIGINT, dialint);
+ debug(F100,"dialint() SIGINT caught -- dialint restored","",0) ;
+#endif /* OS2 */
+#ifdef __EMX__
+ signal(SIGINT, SIG_ACK); /* Needed for OS/2 */
+#endif /* __EMX__ */
+#ifdef OSK /* OS-9, see comment in dialtime() */
+ sigmask(-1);
+#endif /* OSK */
+#ifdef NTSIG
+ PostCtrlCSem() ;
+#ifdef CK_TAPI
+ PostTAPIConnectSem();
+ PostTAPIAnswerSem();
+#endif /* CK_TAPI */
+#else /* NTSIG */
+#ifdef NT
+ cklongjmp(ckjaddr(sjbuf),1);
+#else /* NT */
+ cklongjmp(sjbuf,1);
+#endif /* NT */
+#endif /* NT */
+ SIGRETURN;
+}
+
+/*
+ Routine to read a character from communication device, handling TELNET
+ protocol negotiations in case we're connected to the modem through a
+ TCP/IP TELNET modem server.
+*/
+static int
+ddinc(n) int n; {
+#ifdef TNCODE
+ int c = 0;
+ int done = 0;
+ debug(F101,"ddinc entry n","",n);
+ while (!done) {
+ c = ttinc(n);
+ /* debug(F000,"ddinc","",c); */
+ if (c < 0) return(c);
+#ifndef OS2
+ if ((c == IAC) && network && IS_TELNET()) {
+ switch (tn_doop((CHAR)(c & 0xff),duplex,ttinc)) {
+ case 2: duplex = 0; continue;
+ case 1: duplex = 1;
+ default: continue;
+ }
+ } else done = 1;
+#else /* OS2 */
+ done = !(c == IAC && network && IS_TELNET());
+ scriptwrtbuf(c); /* TELNET negotiations handled by emulator */
+#endif /* OS2 */
+ }
+ return(c & 0xff);
+#else /* TNCODE */
+ return(ttinc(n));
+#endif /* TNCODE */
+}
+
+static VOID
+ttslow(s,millisec) char *s; int millisec; { /* Output s-l-o-w-l-y */
+#ifdef TCPSOCKET
+ extern int tn_nlm, tn_b_nlm;
+#endif /* TCPSOCKET */
+ debug(F111,"ttslow",s,millisec);
+ if (dialdpy && (duplex || !mdmecho)) { /* Echo the command in case modem */
+ printf("%s\n",s); /* isn't echoing commands. */
+#ifdef OS2
+ {
+ char *s2 = s; /* Echo to emulator */
+ while (*s2) {
+ scriptwrtbuf((USHORT)*s2++);
+ }
+ scriptwrtbuf((USHORT)CR);
+ scriptwrtbuf((USHORT)LF);
+ }
+#endif /* OS2 */
+ }
+ for (; *s; s++) {
+ ttoc(*s);
+#ifdef TCPSOCKET
+ if (*s == CR && network && IS_TELNET()) {
+ if (!TELOPT_ME(TELOPT_BINARY) && tn_nlm != TNL_CR)
+ ttoc((char)((tn_nlm == TNL_CRLF) ? LF : NUL));
+ else if (TELOPT_ME(TELOPT_BINARY) &&
+ (tn_b_nlm == TNL_CRLF || tn_b_nlm == TNL_CRNUL))
+ ttoc((char)((tn_b_nlm == TNL_CRLF) ? LF : NUL));
+ }
+#endif /* TCPSOCKET */
+ if (millisec > 0)
+ msleep(millisec);
+ }
+}
+
+/*
+ * Wait for a string of characters.
+ *
+ * The characters are waited for individually, and other characters may
+ * be received "in between". This merely guarantees that the characters
+ * ARE received, and in the order specified.
+ */
+static VOID
+waitfor(s) char *s; {
+ CHAR c, x;
+ while ((c = *s++)) { /* while more characters remain... */
+ do { /* wait for the character */
+ x = (CHAR) (ddinc(0) & 0177);
+ debug(F000,"dial waitfor got","",x);
+ if (dialdpy) {
+ if (x != LF) conoc(x);
+ if (x == CR) conoc(LF);
+ }
+ } while (x != c);
+ }
+}
+
+static int
+didweget(s,r) char *s, *r; { /* Looks in string s for response r */
+ int lr = (int)strlen(r); /* 0 means not found, 1 means found it */
+ int i;
+ debug(F110,"didweget",r,0);
+ debug(F110," in",s,0);
+ for (i = (int)strlen(s)-lr; i >= 0; i--)
+ if ( s[i] == r[0] ) if ( !strncmp(s+i,r,lr) ) return( 1 );
+ return( 0 );
+}
+
+
+/* R E S E T -- Reset alarms, etc. on exit. */
+
+static VOID
+dreset() {
+ debug(F100,"dreset resetting alarm and signal handlers","",0);
+ alarm(0);
+ signal(SIGALRM,savalrm); /* restore alarm handler */
+ signal(SIGINT,savint); /* restore interrupt handler */
+ debug(F100,"dreset alarm and signal handlers reset","",0);
+}
+
+/*
+ Call this routine when the modem reports that it has connected at a certain
+ speed, giving that speed as the argument. If the connection speed is not
+ the same as Kermit's current communication speed, AND the modem interface
+ speed is not locked (i.e. DIAL SPEED-MATCHING is not ON), then change the
+ device speed to the one given.
+*/
+static VOID
+#ifdef CK_ANSIC
+spdchg(long s)
+#else
+spdchg(s) long s;
+#endif /* CK_ANSIC */
+/* spdchg */ {
+ int s2;
+ if (!mdmspd) /* If modem interface speed locked, */
+ return; /* don't do this. */
+ if (speed != s) { /* Speeds differ? */
+ s2 = s / 10L; /* Convert to cps expressed as int */
+ if (ttsspd(s2) < 0) { /* Change speed. */
+ printf(" WARNING - speed change to %ld failed.\r\n",s);
+ } else {
+ printf(" Speed changed to %ld.\r\n",s);
+ speed = s; /* Update global speed variable */
+ }
+ }
+}
+
+/*
+ Display all characters received from modem dialer through this routine,
+ for consistent handling of carriage returns and linefeeds.
+*/
+static VOID
+#ifdef CK_ANSIC
+dialoc(char c)
+#else
+dialoc(c) char c;
+#endif /* CK_ANSIC */
+{ /* dialoc */ /* Dial Output Character */
+ if (dialdpy) {
+ if (c != LF) conoc(c); /* Don't echo LF */
+ if (c == CR) conoc(LF); /* Echo CR as CRLF */
+ }
+}
+
+#ifndef NOSPL
+char *
+getdm(x) int x; { /* Return dial modifier */
+ MDMINF * mp;
+ int m;
+ int ishayes = 0;
+ m = mdmtyp;
+ if (m < 1)
+ if (mdmsav > -1)
+ m = mdmsav;
+ if (m < 1)
+ return("");
+#ifndef MINIDIAL
+ if (m == n_TAPI)
+ m = n_HAYES;
+#endif /* MINIDIAL */
+ mp = modemp[m];
+ ishayes = (dialcapas ? dialcapas : mp->capas) & CKD_AT;
+ switch (x) {
+ case VN_DM_LP:
+ return(ishayes ? "," : "");
+ case VN_DM_SP:
+#ifdef MINIDIAL
+ return("");
+#else
+ return(m == n_USR ? "/" : "");
+#endif /* MINIDIAL */
+ case VN_DM_PD:
+ return(ishayes ? "P" : "");
+ case VN_DM_TD:
+ return(ishayes ? "T" : "");
+ case VN_DM_WA:
+ return(ishayes ? "@" : "");
+ case VN_DM_WD:
+ return(ishayes ? "W" : "");
+ case VN_DM_RC:
+ return(ishayes ? ";" : "");
+ case VN_DM_HF:
+ return(ishayes ? "!" : "");
+ case VN_DM_WB:
+ return(ishayes ? "$" : "");
+ }
+ return("");
+}
+#endif /* NOSPL */
+
+static VOID
+getdialmth() {
+ if (dialmauto && diallcc) { /* If DIAL METHOD AUTO... */
+ int i; /* and we know our area code... */
+ for (i = 0; i < ndialtocc; i++) { /* First check Tone countries list */
+ if (!strcmp(dialtocc[i],diallcc)) {
+ dialmth = XYDM_T;
+ break;
+ }
+ }
+ for (i = 0; i < ndialpucc; i++) { /* Then Pulse countries list */
+ if (!strcmp(dialpucc[i],diallcc)) {
+ dialmth = XYDM_P;
+ break;
+ }
+ }
+ }
+}
+
+VOID /* Get dialing defaults from environment */
+getdialenv() {
+ char *p = NULL;
+ int i, x;
+
+ makestr(&p,getenv("K_DIAL_DIRECTORY"));
+ if (p) {
+ int i;
+ xwords(p,(MAXDDIR - 2),dialdir,0);
+ for (i = 0; i < (MAXDDIR - 1); i++) {
+ if (!dialdir[i+1])
+ break;
+ else
+ dialdir[i] = dialdir[i+1];
+ }
+ ndialdir = i;
+ }
+ xmakestr(&diallcc,getenv("K_COUNTRYCODE")); /* My country code */
+ xmakestr(&dialixp,getenv("K_LD_PREFIX")); /* My long-distance prefix */
+ xmakestr(&dialldp,getenv("K_INTL_PREFIX")); /* My international prefix */
+ xmakestr(&dialldp,getenv("K_TF_PREFIX")); /* Ny Toll-free prefix */
+
+#ifndef NOICP
+ p = getenv("K_DIAL_METHOD"); /* Local dial method */
+ if (p) if (*p) {
+ extern struct keytab dial_m[];
+ extern int ndial_m;
+ i = lookup(dial_m,p,ndial_m,&x);
+ if (i > -1) {
+ if (i == XYDM_A) {
+ dialmauto = 1;
+ dialmth = XYDM_D;
+ } else {
+ dialmauto = 0;
+ dialmth = i;
+ }
+ }
+ }
+#endif /* NOICP */
+
+ p = NULL;
+ xmakestr(&p,getenv("K_TF_AREACODE")); /* Toll-free areacodes */
+ if (p) {
+ int i;
+ xwords(p,7,dialtfc,0);
+ for (i = 0; i < 8; i++) {
+ if (!dialtfc[i+1])
+ break;
+ else
+ dialtfc[i] = dialtfc[i+1];
+ }
+ ntollfree = i;
+ free(p);
+ }
+ for (i = 0; i < MAXTPCC; i++) { /* Clear Tone/Pulse country lists */
+ dialtocc[i] = NULL;
+ dialpucc[i] = NULL;
+ }
+ for (i = 0; i < MAXTPCC; i++) { /* Init Tone country list */
+ if (tonecc[i])
+ makestr(&(dialtocc[i]),tonecc[i]);
+ else
+ break;
+ }
+ ndialtocc = i;
+ for (i = 0; i < MAXTPCC; i++) { /* Init Pulse country list */
+ if (pulsecc[i])
+ makestr(&(dialpucc[i]),pulsecc[i]);
+ else
+ break;
+ }
+ ndialpucc = i;
+
+ if (diallcc) { /* Have country code */
+ if (!strcmp(diallcc,"1")) { /* If it's 1 */
+ if (!dialldp) /* Set these prefixes... */
+ makestr(&dialldp,"1");
+ if (!dialtfp)
+ makestr(&dialtfp,"1");
+ if (!dialixp)
+ makestr(&dialixp,"011");
+ if (ntollfree == 0) { /* Toll-free area codes */
+ if ((dialtfc[0] = malloc(4))) {
+ ckstrncpy(dialtfc[0],"800",4); /* 1970-something */
+ ntollfree++;
+ if ((dialtfc[1] = malloc(4))) {
+ ckstrncpy(dialtfc[1],"888",4); /* 1996 */
+ ntollfree++;
+ if ((dialtfc[2] = malloc(4))) {
+ ckstrncpy(dialtfc[2],"877",4); /* 5 April 1998 */
+ ntollfree++;
+ if ((dialtfc[3] = malloc(4))) {
+ ckstrncpy(dialtfc[3],"866",4); /* 2000? */
+ ntollfree++;
+ }
+ }
+ }
+ }
+ }
+ } else if (!strcmp(diallcc,"358") &&
+ ((int) strcmp(zzndate(),"19961011") > 0)
+ ) { /* Finland */
+ if (!dialldp) /* Long-distance prefix */
+ makestr(&dialldp,"9");
+ if (!dialixp) /* International dialing prefix */
+ makestr(&dialixp,"990");
+ } else { /* Not NANP or Finland */
+ if (!dialldp)
+ makestr(&dialldp,"0");
+ if (!dialixp)
+ makestr(&dialixp,"00");
+ }
+ }
+ xmakestr(&diallac,getenv("K_AREACODE"));
+ xmakestr(&dialpxo,getenv("K_PBX_OCP"));
+ xmakestr(&dialpxi,getenv("K_PBX_ICP"));
+ p = getenv("K_PBX_XCH");
+#ifdef COMMENT
+ xmakestr(&dialpxx,p);
+#else
+ if (p) if (*p) {
+ char * s = NULL;
+ char * pp[MAXPBXEXCH+2];
+ makestr(&s,p); /* Make a copy for poking */
+ if (s) {
+ xwords(s,MAXPBXEXCH+1,pp,0); /* Note: pp[] is 1-based. */
+ for (i = 0; i <= MAXPBXEXCH; i++) {
+ if (!pp[i+1]) break;
+ makestr(&(dialpxx[i]),pp[i+1]);
+ ndialpxx++;
+ }
+ makestr(&s,NULL); /* Free poked copy */
+ }
+ }
+#endif /* COMMENT */
+}
+
+static int
+dialfail(x) int x; {
+ char * s;
+
+ fail_code = x;
+ debug(F101,"ckudial dialfail","",x);
+ dreset(); /* Reset alarm and signal handlers */
+
+ printf("%s Failure: ", func_code == 0 ? "DIAL" : "ANSWER");
+ if (dialdpy) { /* If showing progress */
+ debug(F100,"dial display is on","",0);
+ p = ck_time(); /* get current time; */
+ if (*p) printf("%s: ",p);
+ }
+ switch (fail_code) { /* Type of failure */
+ case F_TIME: /* Timeout */
+ if (dial_what == DW_INIT)
+ printf ("Timed out while trying to initialize modem.\n");
+ else if (dial_what == DW_DIAL)
+ printf ("%s interval expired.\n",
+ func_code == 0 ? "DIAL TIMEOUT" : "ANSWER timeout");
+ else
+ printf("Timeout.\n");
+ fflush(stdout);
+ if (mdmcapas & CKD_AT)
+ ttoc('\015'); /* Send CR to interrupt dialing */
+ /* Some Hayes modems don't fail with BUSY on busy lines */
+ dialsta = DIA_TIMO;
+ debug(F110,"dial","timeout",0);
+ break;
+
+ case F_INT: /* Dialing interrupted */
+ printf ("Interrupted.\n");
+ fflush(stdout);
+#ifndef NOXFER
+ interrupted = 1;
+#endif /* NOXFER */
+ debug(F111,"dial","interrupted",mdmcapas & CKD_AT);
+ if (mdmcapas & CKD_AT)
+ ttoc('\015'); /* Send CR to interrupt dialing */
+ dialsta = DIA_INTR;
+ break;
+
+ case F_MODEM: /* Modem detected a failure */
+ debug(F111,"dialfail()","lbuf",lbuf);
+ if (lbuf && *lbuf) {
+ printf(" \"");
+ for (s = lbuf; *s; s++)
+ if (isprint(*s))
+ putchar(*s); /* Display printable reason */
+ printf ("\"");
+ } else printf(func_code == 0 ?
+ " Call not completed." :
+ " Call did not come in."
+ );
+ printf("\n");
+ debug(F110,"dial",lbuf,0);
+ if (dialsta < 0) dialsta = DIA_UNSP;
+ break;
+
+ case F_MINIT: /* Failure to initialize modem */
+ printf ("Error initializing modem.\n");
+ debug(F110,"dial","modem init",0);
+ dialsta = DIA_NOIN;
+ break;
+
+ default:
+ printf("unknown\n");
+ debug(F110,"dial","unknown",0);
+ fflush(stdout);
+ if (mdmcapas & CKD_AT)
+ ttoc('\015'); /* Send CR to interrupt dialing */
+ dialsta = DIA_INTR;
+ }
+
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+
+ if (dialsta < 0) dialsta = DIA_UERR; /* Set failure code */
+ return(0); /* Return zero (important) */
+}
+
+/* C K D I A L -- Dial up the remote system */
+
+/* Returns 1 if call completed, 0 otherwise */
+
+static int mdmwait, mdmstat = 0;
+#ifndef CK_TAPI
+static
+#endif /* CK_TAPI */
+int waitct;
+int mdmwaitd = 10 ; /* dialtmo / mdmwait difference */
+static char c;
+static char *telnbr;
+
+static int wr = 0; /* wr = wake rate */
+static char * ws; /* ws = wake string */
+static char * xnum = NULL;
+static int inited = 0;
+
+static SIGTYP
+#ifdef CK_ANSIC
+_dodial(void * threadinfo)
+#else /* CK_ANSIC */
+_dodial(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* _dodial */ {
+ char c2;
+ char *dcmd, *s, *flocmd = NULL;
+ int x = 0, n = F_TIME;
+
+#ifdef NTSIG
+ signal( SIGINT, dialint );
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ }
+#endif /* NTSIG */
+
+ dcmd = dialcmd ? dialcmd : mp->dial_str;
+ if ((int)strlen(dcmd) + (int)strlen(telnbr) > (LBUFL - 2)) {
+ printf("DIAL command + phone number too long!\n");
+ dreset();
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN; /* No conversation with modem to complete dialing */
+ }
+ makestr(&xnum,telnbr);
+
+ getdialmth(); /* Get dial method */
+
+#ifdef CK_ATDT
+ /* Combine the SET DIAL METHOD command with the DIAL command string */
+ if (!dialcmd && /* Using default DIAL command */
+ (mdmcapas & CKD_AT) && /* AT command set only */
+ ((dialmth == XYDM_T && !dialtone) || /* and using default */
+ (dialmth == XYDM_P && !dialpulse))) { /* modem commands... */
+ char c;
+ debug(F110,"dial atdt xnum 1",xnum,0);
+ s = dcmd;
+ debug(F110,"dial atdt s",s,0);
+ if (*telnbr != 'T' &&
+ *telnbr != 'P' &&
+ *telnbr != 't' &&
+ *telnbr != 'p' &&
+ !ckstrcmp(s,"atd",3,0) &&
+ s[3] != 'T' &&
+ s[3] != 'P' &&
+ s[3] != 't' &&
+ s[3] != 'p') {
+ char xbuf[200];
+ c = (dialmth == XYDM_T) ? 'T' : 'P';
+ if (islower(s[0]))
+ c = tolower(c);
+ if ((int)strlen(telnbr) < 199) {
+ sprintf(xbuf,"%c%s",c,telnbr);
+ makestr(&xnum,xbuf);
+ }
+ }
+ }
+#endif /* CK_ATDT */
+ debug(F111,"_dodial",xnum,xredial);
+
+ /* Hang up the modem (in case it wasn't "on hook") */
+ /* But only if SET DIAL HANGUP ON... */
+
+ if (!xredial) { /* Modem not initalized yet. */
+ inited = 0;
+ }
+ if (!xredial || !inited) {
+ if (dialhup() < 0) { /* Hangup first */
+ debug(F100,"_dodial dialhup failed","",0);
+#ifndef MINIDIAL
+ if (mdmcapas & CKD_TB) /* Telebits might need a BREAK */
+ ttsndb(); /* first. */
+#endif /* MINIDIAL */
+ if (dialhng && dialsta != DIA_PART) { /* If hangup failed, */
+ ttclos(0); /* close and reopen the device. */
+ if (ttopen(ttname,&local,mymdmtyp,0) < 0) {
+ printf("Sorry, Can't hang up communication device.\n");
+ printf("Try 'set line %s' again.\n",ttname);
+ dialsta = DIA_HANG;
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ dreset();
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+ }
+ }
+ }
+ inited = 0; /* We hung up so must reinit */
+ }
+#ifndef MINIDIAL
+ /* Don't start talking to Rolm too soon */
+ if (mymdmtyp == n_ROLM && dialsta != DIA_PART)
+ msleep(500);
+#endif /* MINIDIAL */
+
+ if (dialsta != DIA_PART /* Some initial setups. */
+#ifndef MINIDIAL
+ && mymdmtyp != n_ATTUPC
+#endif /* MINIDIAL */
+ ) {
+ fail_code = F_MINIT; /* Default failure code */
+ dial_what = DW_INIT; /* What I'm Doing Now */
+ if (dialdpy) { /* If showing progress, */
+ p = ck_time(); /* get timestamp. */
+ if (!inited)
+ if (*p)
+ printf(" Initializing: %s...\n",p);
+ }
+ }
+#ifndef MINIDIAL
+#ifdef ATT7300
+ if (mymdmtyp == n_ATTUPC) {
+/*
+ For ATT7300/Unix PC's with their special internal modem. Whole dialing
+ process is handled right here, an exception to the normal structure.
+ Timeout and user interrupts are enabled during dialing. attdial() is in
+ file ckutio.c. - jrd
+*/
+ _PROTOTYP( int attdial, (char *, long, char *) );
+ fail_code = F_MODEM; /* Default failure code */
+ dial_what = DW_DIAL;
+ if (dialdpy) { /* If showing progress */
+ p = ck_time(); /* get current time; */
+ if (*p)
+ printf(" Dialing: %s...\n",p);
+ }
+ alarm(waitct); /* Set alarm */
+ if (attdial(ttname,speed,telnbr)) { /* dial internal modem */
+ dreset(); /* reset alarms, etc. */
+ printf(" Call failed.\r\n");
+ dialhup(); /* Hangup the call */
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ dialsta = DIA_UERR;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN; /* return failure */
+ }
+ dreset(); /* reset alarms, etc. */
+ ttpkt(speed,FLO_DIAX,parity); /* cancel dialing ioctl */
+ if (!quiet && !backgrd) {
+ if (dialdpy) {
+ printf("\n");
+ printf(" Call complete.\r\n");
+ } else if (modemmsg[0])
+ printf(" Call complete: \"%s\".\r\n",(char *)modemmsg);
+ else
+ printf(" Call complete.\r\n");
+ }
+#ifdef CKLOGDIAL
+ dologdial(telnbr);
+#endif /* CKLOGDIAL */
+
+ dialsta = DIA_OK;
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN; /* No conversation with modem to complete dialing */
+ } else
+#endif /* ATT7300 */
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) { /* TAPI Dialing */
+ switch (func_code) {
+ case 0: /* Dial */
+ if (cktapidial(telnbr)) {
+ fail_code = 0;
+ if (partial) {
+ dialsta = DIA_PART;
+ } else {
+ dialsta = DIA_OK;
+ speed = ttgspd();
+ }
+ } else {
+ if (dialsta == DIA_PART)
+ cktapihangup();
+ if (!fail_code)
+ fail_code = F_MODEM;
+ dialsta = DIA_TAPI;
+ }
+ break;
+ case 1: { /* Answer */
+ long strttime = time((long *)NULL);
+ long diff = 0;
+ do {
+ if (dialatmo > 0) {
+ strttime += diff;
+ waitct -= diff;
+ }
+ fail_code = 0;
+ if (cktapianswer()) { /* SUCCESS */
+ dialsta = DIA_OK;
+ speed = ttgspd();
+ break;
+ } else { /* FAILURE */
+ if (fail_code) {
+ dialsta = DIA_TAPI;
+ break;
+ } else {
+ fail_code = F_MODEM;
+ dialsta = DIA_TAPI;
+ }
+ }
+ if (dialatmo > 0) {
+ diff = time((long *)NULL) - strttime;
+ }
+ } while ((dialatmo > 0) ? (diff < waitct) : 1);
+ break;
+ }
+ }
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+ } else
+#endif /* CK_TAPI */
+#endif /* MINIDIAL */
+
+/* Modems with AT command set... */
+
+ if ((mdmcapas & CKD_AT) && dialsta != DIA_PART) {
+
+ if (dialpace > -1) /* Set intercharacter pacing */
+ wr = dialpace;
+ else
+ wr = mp->wake_rate;
+
+ if (dialini) /* Get wakeup/init string */
+ ws = dialini;
+ else
+ ws = mp->wake_str;
+#ifdef COMMENT
+ if (!ws) ws = "\015"; /* If none, use CR */
+#endif /* COMMENT */
+
+ /* First get the modem's attention and enable result codes */
+
+ for (tries = 0; tries < 5; tries++) { /* Send short command */
+ if (tries > 0) {
+ ttoc('\015'); /* AT must go first for speed */
+ msleep(wr); /* detection. */
+ }
+ if (mymdmtyp == n_GENERIC) /* Force word result codes */
+ ttslow("ATQ0V1\015",wr); /* for generic modem type */
+ else
+ ttslow("ATQ0\015",wr);
+ mdmstat = getok(tries < 2 ? 2 : tries, 1); /* Get response */
+ if (mdmstat > 0) break; /* OK - done */
+ if (dialdpy && tries > 0) {
+ printf("\r\n No response from modem");
+ if (tries == 4) {
+ printf(".\r\n");
+ dialsta = DIA_NRSP;
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN; /* return failure */
+ }
+ printf(", retrying%s...\r\n",
+ (tries > 1) ? " again" : "");
+ fflush(stdout);
+ }
+ ttflui();
+ switch (tries) {
+ case 0: msleep(100); break;
+ case 1: ttsndb(); break;
+ default:
+ if (network) {
+ ttsndb();
+ } else {
+ if (tries == 2) {
+ tthang();
+ ttflui();
+ } else {
+ mdmhup();
+ }
+ inited = 0;
+ }
+ }
+ fflush(stdout);
+ }
+ debug(F101,"_dodial ATQ0 mdmstat","",mdmstat);
+
+ if (xredial && inited) { /* Redialing... */
+ ttoc('\015'); /* Cancel previous */
+ msleep(250); /* Wait a bit */
+#ifdef COMMENT
+/* This wasn't the problem... */
+ ttflui(); /* Clear out stuff from modem setup */
+ ttslow("ATS7=60\015",wr); /* Redo carrier wait */
+ getok(4,1); /* Get response */
+#endif /* COMMENT */
+ alarm(0); /* Just in case... */
+ ttflui(); /* Clear out stuff from modem setup */
+ goto REDIAL; /* Skip setup - we already did it */
+ }
+/*
+ Do flow control next because a long init string echoing back could
+ cause data overruns, causing us to miss the OK, or (worse) to get out
+ of sync entirely.
+*/
+ x = 0; /* User said SET DIAL FLOW RTS/CTS */
+ if (dialfc == FLO_RTSC || /* Even if Kermit's FLOW isn't... */
+ (dialfc == FLO_AUTO && flow == FLO_RTSC)) {
+ if (dialhwfc) { /* User-defined HWFC string */
+ if (*dialhwfc) {
+ x = 1;
+ flocmd = dialhwfc;
+ }
+ } else if ((mdmcapas & CKD_HW) && *(mp->hwfc_str)) {
+ x = 1;
+ flocmd = mp->hwfc_str;
+ }
+ } else if (dialfc == FLO_XONX || /* User said SET DIAL FLOW SOFT */
+ (dialfc == FLO_AUTO && flow == FLO_XONX)) {
+ if (dialswfc) {
+ if (*dialswfc) {
+ x = 1;
+ flocmd = dialswfc;
+ }
+ } else if ((mdmcapas & CKD_SW) && *(mp->swfc_str)) {
+ x = 1;
+ flocmd = mp->swfc_str;
+ }
+ } else if (dialfc == FLO_NONE) { /* User said SET DIAL FLOW NONE */
+ if (dialnofc) {
+ if (*dialnofc) {
+ x = 1;
+ flocmd = dialnofc;
+ }
+ } else if (mp->nofc_str && *(mp->nofc_str)) {
+ x = 1;
+ flocmd = mp->nofc_str;
+ }
+ }
+ if (x) { /* Send the flow control command */
+ debug(F110,"_dodial flocmd",flocmd,0);
+ for (tries = 4; tries > 0; tries--) { /* Send the command */
+ ttslow(flocmd,wr);
+ mdmstat = getok(5,1);
+ if (mdmstat > 0) break;
+ if (dialdpy && tries > 1)
+ printf(" No response from modem, retrying%s...\n",
+ (tries < 4) ? " again" : "");
+ }
+
+#ifdef CK_TTSETFLOW
+#ifdef CK_RTSCTS
+/*
+ So far only ckutio.c has ttsetflow().
+ We have just told the modem to turn on RTS/CTS flow control and the modem
+ has said OK. But we ourselves have not turned it on yet because of the
+ disgusting ttpkt(...FLO_DIAL...) hack. So now, if the computer does not
+ happen to be asserting RTS, the modem will no longer send characters to it.
+ So at EXACTLY THIS POINT, we must enable RTS/CTS in the device driver.
+*/
+ if (dialfc == FLO_RTSC ||
+ (dialfc == FLO_AUTO && flow == FLO_RTSC)) {
+ ttsetflow(FLO_RTSC);
+ }
+#endif /* CK_RTSCTS */
+#endif /* CK_TTSETFLOW */
+ }
+ ttflui(); /* Clear out stuff from modem setup */
+ msleep(250);
+
+ if (!ws) goto xdialec; /* No init string */
+ if (!*ws) goto xdialec;
+
+ for (tries = 4; tries > 0; tries--) { /* Send init string */
+ ttslow(ws,wr);
+ mdmstat = getok(4,1); /* Get response */
+ if (mdmstat > 0) break;
+ if (dialdpy && tries > 1)
+ printf(" No response from modem, retrying%s...\n",
+ (tries < 4) ? " again" : "");
+ }
+ debug(F101,"_dodial wake_str mdmstat","",mdmstat);
+
+ if (mdmstat < 1) { /* Initialized OK? */
+ dialfail(F_MINIT); /* No, fail. */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+ }
+
+#ifndef MINIDIAL
+ } else if (mymdmtyp == n_ATTDTDM && dialsta != DIA_PART) { /* AT&T ... */
+ ttsndb(); /* Send BREAK */
+#endif /* MINIDIAL */
+
+ } else if (dialsta != DIA_PART) { /* All others */
+
+ /* Place modem into command mode */
+
+ ws = dialini ? dialini : mp->wake_str;
+ if (ws && (int)strlen(ws) > 0) {
+ debug(F111,"_dodial default, wake string", ws, wr);
+ ttslow(ws, wr);
+ } else debug(F100,"_dodial no wake_str","",0);
+ if (mp->wake_prompt && (int)strlen(mp->wake_prompt) > 0) {
+ debug(F110,"_dodial default, waiting for wake_prompt",
+ mp->wake_prompt,0);
+ alarm(10);
+ waitfor(mp->wake_prompt);
+ alarm(0);
+ } else debug(F100,"_dodial no wake_prompt","",0);
+ }
+
+/* Handle error correction, data compression, and flow control... */
+
+ xdialec:
+
+ if (dialsta != DIA_PART) {
+ alarm(0); /* Turn off alarm */
+ debug(F100,"_dodial got wake prompt","",0);
+ msleep(500); /* Allow settling time */
+
+ /* Enable/disable error-correction */
+
+ x = 0;
+ if (dialec) { /* DIAL ERROR-CORRECTION is ON */
+ if (dialecon) { /* SET DIAL STRING ERROR-CORRECTION */
+ if (*dialecon) {
+ x = 1;
+ ttslow(dialecon, wr);
+ }
+ } else if ((mdmcapas & CKD_EC) && *(mp->ec_on_str)) {
+ x = 1;
+ ttslow(mp->ec_on_str, wr);
+ }
+#ifdef COMMENT
+ else printf(
+ "WARNING - I don't know how to turn on EC for this modem\n"
+ );
+#endif /* COMMENT */
+ } else {
+ if (dialecoff) { /* DIAL ERROR-CORRECTION OFF */
+ if (*dialecoff) {
+ x = 1;
+ ttslow(dialecoff, wr);
+ }
+ } else if ((mdmcapas & CKD_EC) && *(mp->ec_off_str)) {
+ x = 1;
+ ttslow(mp->ec_off_str, wr);
+ }
+#ifdef COMMENT
+ else printf(
+ "WARNING - I don't know how to turn off EC for this modem\n"
+ );
+#endif /* COMMENT */
+ }
+ /* debug(F101,"ckudia xx_ok","",xx_ok); */
+ if (x && xx_ok) { /* Look for OK response */
+ debug(F100,"ckudia calling xx_ok for EC","",0);
+ x = (*xx_ok)(5,1);
+ debug(F101,"ckudia xx_ok","",x);
+ if (x < 0) {
+ printf("WARNING - Trouble enabling error-correction.\n");
+ printf(
+" Likely cause: Your modem is an RPI model, which does not have built-in\n");
+ printf(" error correction and data compression.");
+ }
+ }
+
+ /* Enable/disable data compression */
+
+ if (x > 0) x = 0;
+ if (dialdc) {
+ if (x < 0 || !dialec) {
+ printf(
+"WARNING - You can't have compression without error correction.\n");
+ } else if (dialdcon) { /* SET DIAL STRING ... */
+ if (*dialdcon) {
+ x = 1;
+ ttslow(dialdcon, wr);
+ }
+ } else if ((mdmcapas & CKD_DC) && *(mp->dc_on_str)) {
+ x = 1;
+ ttslow(mp->dc_on_str, wr);
+ }
+#ifdef COMMENT
+ else printf(
+ "WARNING - I don't know how to turn on DC for this modem\n"
+ );
+#endif /* COMMENT */
+ } else {
+ if (dialdcoff) {
+ if (*dialdcoff) {
+ x = 1;
+ ttslow(dialdcoff, wr);
+ }
+ } else if ((mdmcapas & CKD_DC) && *(mp->dc_off_str)) {
+ x = 1;
+ ttslow(mp->dc_off_str, wr);
+ }
+#ifdef COMMENT
+ else printf(
+"WARNING - I don't know how to turn off compression for this modem\n"
+ );
+#endif /* COMMENT */
+ }
+ if (x && xx_ok) { /* Look for OK response */
+ x = (*xx_ok)(5,1);
+ if (x < 0) printf("WARNING - Trouble enabling compression\n");
+ }
+ }
+
+#ifndef NOXFER
+#ifndef MINIDIAL
+ if (mdmcapas & CKD_KS && dialsta != DIA_PART) { /* Kermit spoof */
+ int r; /* Register */
+ char tbcmdbuf[64]; /* Command buffer */
+ switch (mymdmtyp) {
+
+ case n_MICROCOM: /* Microcoms in SX mode */
+ if (dialksp)
+ sprintf(tbcmdbuf,"APM1;KMC%d\015",stchr); /* safe */
+ else
+ sprintf(tbcmdbuf,"APM0\015"); /* safe */
+ ttslow(tbcmdbuf, MICROCOM.wake_rate);
+ alarm(3);
+ waitfor(mp->wake_prompt);
+ alarm(0);
+ break;
+
+ case n_TELEBIT: /* Old and new Telebits */
+ case n_TBNEW:
+ if (!dialksp) {
+ sprintf(tbcmdbuf,"ATS111=0\015"); /* safe */
+ } else {
+ switch (parity) { /* S111 value depends on parity */
+ case 'e': r = 12; break;
+ case 'm': r = 13; break;
+ case 'o': r = 11; break;
+ case 's': r = 14; break;
+ case 0:
+ default: r = 10; break;
+ }
+ sprintf(tbcmdbuf,"ATS111=%d S112=%d\015",r,stchr); /* safe */
+ }
+ ttslow(tbcmdbuf, wr);
+
+/* Not all Telebit models have the Kermit spoof, so ignore response. */
+
+ if (xx_ok) { /* Get modem's response */
+ x = (*xx_ok)(5,1);
+ }
+ }
+ }
+#endif /* MINIDIAL */
+#endif /* NOXFER */
+
+ /* Speaker */
+
+ if (mymdmtyp != n_GENERIC &&
+ (mdmcapas & CKD_AT) && (dialsta != DIA_PART) &&
+ !dialspon && !dialspoff &&
+ !dialvol1 && !dialvol2 &&!dialvol3) {
+ /* AT command set and commands have not been customized */
+ /* so combine speaker and volume commands. */
+ if (mdmspk)
+ sprintf(lbuf,"ATM1L%d%c",mdmvol,13); /* safe */
+ else
+ sprintf(lbuf,"ATM0%c",13); /* safe */
+ ttslow(lbuf,wr); /* Send command */
+ getok(5,1); /* Get but ignore response */
+ } else if (dialsta != DIA_PART) { /* Customized or not AT commands */
+ x = 0; /* Do it the hard way */
+ if (mdmspk) {
+ if (dialspon) {
+ if (*dialspon) {
+ x = 1;
+ ttslow(dialspon,wr);
+ }
+ } else {
+ if (mp->sp_on_str[0]) {
+ x = 1;
+ ttslow(mp->sp_on_str,wr);
+ }
+ }
+ } else {
+ /* s = dialspoff ? dialspoff : mp->sp_off_str; */
+ if (dialspoff) {
+ if (*dialspoff) {
+ x = 1;
+ ttslow(dialspoff,wr);
+ }
+ } else {
+ if (mp->sp_off_str[0]) {
+ x = 1;
+ ttslow(mp->sp_off_str,wr);
+ }
+ }
+ }
+ if (x) {
+ if (xx_ok) /* Get response */
+ x = (*xx_ok)(5,1);
+ if (x && mdmspk) { /* Good response and speaker on? */
+ switch (mdmvol) { /* Yes, send volume command. */
+ case 0:
+ case 1:
+ s = dialvol1 ? dialvol1 : mp->vol1_str; break;
+ case 2:
+ s = dialvol2 ? dialvol2 : mp->vol2_str; break;
+ case 3:
+ s = dialvol3 ? dialvol3 : mp->vol3_str; break;
+ default:
+ s = NULL;
+ }
+ if (s) if (*s) { /* Send volume command. */
+ ttslow(s, wr);
+ if (xx_ok) /* Get response but ignore it */
+ (*xx_ok)(5,1);
+ }
+ }
+ }
+ }
+
+#ifndef CK_ATDT
+ /* Dialing Method */
+
+ if (dialmth && dialsta != DIA_PART) { /* If dialing method specified... */
+ char *s = ""; /* Do it here... */
+
+ if (dialmth == XYDM_T && dialtone) /* Tone */
+ s = dialtone;
+ else if (dialmth == XYDM_P && dialpulse) /* Pulse */
+ s = dialpulse;
+ if (s) if (*s) {
+ ttslow(s, wr);
+ if (xx_ok) /* Get modem's response */
+ (*xx_ok)(5,1); /* (but ignore it...) */
+ }
+ }
+#endif /* CK_ATDT */
+
+ if (dialidt) { /* Ignore dialtone? */
+ char *s = "";
+ s = dialx3 ? dialx3 : mp->ignoredt;
+ if (s) if (*s) {
+ ttslow(s, wr);
+ if (xx_ok) /* Get modem's response */
+ (*xx_ok)(5,1); /* (but ignore it...) */
+ }
+ }
+ {
+ char *s = ""; /* Last-minute init string? */
+ s = dialini2 ? dialini2 : mp->ini2;
+ if (s) if (*s) {
+ ttslow(s, wr);
+ if (xx_ok) /* Get modem's response */
+ (*xx_ok)(5,1); /* (but ignore it...) */
+ }
+ }
+ if (func_code == 1) { /* ANSWER (not DIAL) */
+ char *s;
+ s = dialaaon ? dialaaon : mp->aa_on_str;
+ if (!s) s = "";
+ if (*s) {
+ /* Here we would handle caller ID */
+ ttslow(s, (dialpace > -1) ? wr : mp->dial_rate);
+ if (xx_ok) /* Get modem's response */
+ (*xx_ok)(5,1); /* (but ignore it...) */
+ } else {
+ printf(
+"WARNING - I don't know how to enable autoanswer for this modem.\n"
+ );
+ } /* And skip all the phone-number & dialing stuff... */
+ alarm(waitct); /* This much time allowed. */
+ debug(F101,"_dodial ANSWER waitct","",waitct);
+
+ } else { /* DIAL (not ANSWER) */
+
+ if (dialsta != DIA_PART) { /* Last dial was not partial */
+
+ char *s = "";
+#ifdef COMMENT
+ s = dialaaoff ? dialaaoff : mp->aa_off_str;
+#endif /* COMMENT */
+ if (s) if (*s) {
+ ttslow(s, (dialpace > -1) ? wr : mp->dial_rate);
+ if (xx_ok) /* Get modem's response */
+ (*xx_ok)(5,1); /* (but ignore it...) */
+ }
+
+ /* Put modem into dialing mode, if the modem requires it. */
+
+ if (mp->dmode_str && *(mp->dmode_str)) {
+ ttslow(mp->dmode_str, (dialpace > -1) ? wr : mp->dial_rate);
+ savalrm = signal(SIGALRM,dialtime);
+ alarm(10);
+ /* Wait for prompt, if any expected */
+ if (mp->dmode_prompt && *(mp->dmode_prompt)) {
+ waitfor(mp->dmode_prompt);
+ msleep(300);
+ }
+ alarm(0); /* Turn off alarm on dialing prompts */
+ signal(SIGALRM,savalrm); /* Restore alarm */
+ }
+ }
+ /* AT-Command-Set non-Generic modem */
+ if (mdmcapas & CKD_AT && mymdmtyp != n_GENERIC &&
+ dialsta != DIA_PART) {
+ if (mdmwait > 255) /* If larger than maximum, */
+ mdmwait = 255; /* make it maximum. */
+ if (dialesc > 0 && /* Modem escape character is set */
+ dialmhu > 0) { /* Hangup method is modem command */
+ int x = dialesc;
+ if (dialesc < 0 || dialesc > 127)
+ x = 128;
+ sprintf(lbuf,
+ "ATS2=%dS7=%d\015",
+ dialesc ? x : mp->esc_char, mdmwait); /* safe */
+ } else
+ sprintf(lbuf,"ATS7=%d%c",mdmwait,13); /* safe */
+ ttslow(lbuf,wr); /* Set it. */
+ mdmstat = getok(5,1); /* Get response from modem */
+ /* If it gets an error, go ahead anyway */
+ debug(F101,"_dodial S7 mdmstat","",mdmstat);
+ }
+ ttflui(); /* Clear out stuff from modem setup */
+ inited = 1; /* Remember modem is initialized */
+
+ REDIAL:
+ if ((int)strlen(dcmd) + (int)strlen(xnum) > LBUFL)
+ ckstrncpy(lbuf,"NUMBER TOO LONG!",LBUFL);
+ else
+ sprintf(lbuf, dcmd, xnum); /* safe (prechecked) */
+ debug(F110,"dialing",lbuf,0);
+ /* Send the dialing string */
+ ttslow(lbuf,dialpace > -1 ? wr : mp->dial_rate);
+
+ fail_code = F_MODEM; /* New default failure code changes */
+ dial_what = DW_DIAL; /* and our state, too. */
+ if (dialdpy) { /* If showing progress */
+ p = ck_time(); /* get current time; */
+ if (*p) printf(" Dialing: %s...\n",p);
+#ifdef VMS
+ printf(" \n");
+ fflush(stdout);
+#endif /* VMS */
+ }
+ alarm(waitct); /* This much time allowed. */
+ debug(F101,"_dodial waitct","",waitct);
+
+#ifndef MINIDIAL
+#ifdef OLDMODEMS
+ switch (mymdmtyp) {
+ case n_RACAL: /* Acknowledge dialing string */
+ sleep(3);
+ ttflui();
+ ttoc('\015');
+ break;
+ case n_VENTEL:
+ waitfor("\012\012"); /* Ignore the first two strings */
+ break;
+ default:
+ break;
+ }
+#endif /* OLDMODEMS */
+#endif /* MINIDIAL */
+ }
+
+/* Check for connection */
+
+ mdmstat = 0; /* No status yet */
+ lbuf[0] = NUL; /* Default reason for failure */
+ debug(F101,"dial awaiting response, mymdmtyp","",mymdmtyp);
+
+#ifndef NOSPL
+ modemmsg[0] = NUL;
+#endif /* NOSPL */
+ while (mdmstat == 0) { /* Till we get a result or time out */
+
+ if ((mdmcapas & CKD_AT) && nonverbal) { /* AT command set */
+ gethrn(); /* In digit result mode */
+ if (partial && dialsta == DIA_ERR) {
+ /*
+ If we get an error here, the phone is still
+ off hook so we have to hang it up.
+ */
+ dialhup();
+ dialsta = DIA_ERR; /* (because dialhup() changes it) */
+ }
+ continue;
+
+ } else if (mymdmtyp == n_UNKNOWN) { /* Unknown modem type */
+ int x, y = waitct;
+ mdmstat = D_FAILED; /* Assume failure. */
+ while (y-- > -1) {
+ x = ttchk();
+ if (x > 0) {
+ if (x > LBUFL) x = LBUFL;
+ x = ttxin(x,(CHAR *)lbuf);
+ if ((x > 0) && dialdpy) conol(lbuf);
+ } else if (network
+#ifdef TN_COMPORT
+ && !istncomport()
+#endif /* TN_COMPORT */
+ && x < 0) { /* Connection dropped */
+ inited = 0;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ dialsta = DIA_IO; /* Call it an I/O error */
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ SIGRETURN;
+ }
+ x = ttgmdm(); /* Try to read modem signals */
+ if (x < 0) break; /* Can't, fail. */
+ if (x & BM_DCD) { /* Got signals OK. Carrier present? */
+ mdmstat = CONNECTED; /* Yes, done. */
+ break;
+ } /* No, keep waiting. */
+ sleep(1);
+ }
+ continue;
+ }
+
+ for (n = -1; n < LBUFL-1; ) { /* Accumulate modem response */
+ int xx;
+ c2 = (char) (xx = ddinc(0)); /* Read a character, blocking */
+ if (xx < 1) /* Ignore NULs and errors */
+ continue; /* (Timeout will handle errors) */
+ else /* Real character, keep it */
+ lbuf[++n] = (char) (c2 & 0177);
+ dialoc(lbuf[n]); /* Maybe echo it */
+ if (mdmcapas & CKD_V25) { /* V.25bis dialing... */
+/*
+ This assumes that V.25bis indications are all at least 3 characters long
+ and are terminated by either CRLF or LFCR.
+*/
+ if (mymdmtyp == n_CCITT) {
+ if (n < 3) continue;
+ if ((lbuf[n] == CR) && (lbuf[n-1] == LF)) break;
+ if ((lbuf[n] == LF) && (lbuf[n-1] == CR)) break;
+ }
+#ifndef MINIDIAL
+ else if (mymdmtyp == n_DIGITEL) {
+ if (((lbuf[n] == CR) && (lbuf[n-1] == LF)) ||
+ ((lbuf[n] == LF) && (lbuf[n-1] == CR)))
+ break;
+ else
+ continue;
+ }
+#endif /* MINIDIAL */
+ } else { /* All others, break on CR or LF */
+ if ( lbuf[n] == CR || lbuf[n] == LF ) break;
+ }
+ }
+ lbuf[++n] = '\0'; /* Terminate response from modem */
+ debug(F111,"_dodial modem response",lbuf,n);
+#ifndef NOSPL
+ ckstrncpy(modemmsg,lbuf,LBUFL); /* Call result message */
+ lbuf[79] = NUL;
+ {
+ int x; /* Strip junk from end */
+ x = (int)strlen(modemmsg) - 1;
+ while (x > -1) {
+ if (modemmsg[x] < (char) 33)
+ modemmsg[x] = NUL;
+ else
+ break;
+ x--;
+ }
+ }
+#endif /* NOSPL */
+ if (mdmcapas & CKD_AT) { /* Hayes AT command set */
+ gethrw(); /* in word result mode */
+ if (partial && dialsta == DIA_ERR) {
+ dialhup();
+ dialsta = DIA_ERR; /* (because dialhup() changes it) */
+ }
+ continue;
+ } else if (mdmcapas & CKD_V25) { /* CCITT command set */
+ if (didweget(lbuf,"VAL")) { /* Dial command confirmation */
+#ifndef MINIDIAL
+ if (mymdmtyp == n_CCITT)
+#endif /* MINIDIAL */
+ continue; /* Go back and read more */
+#ifndef MINIDIAL
+/* Digitel doesn't give an explicit connect confirmation message */
+ else {
+ int n;
+ for (n = -1; n < LBUFL-1; ) {
+ lbuf[++n] = c2 = (char) (ddinc(0) & 0177);
+ dialoc(lbuf[n]);
+ if (((lbuf[n] == CR) && (lbuf[n-1] == LF)) ||
+ ((lbuf[n] == LF) && (lbuf[n-1] == CR)))
+ break;
+ }
+ mdmstat = CONNECTED; /* Assume we're connected */
+ if (dialdpy && carrier != CAR_OFF) {
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ debug(F100,"TN Com Port DCD wait...","",0);
+ if ((n = ttgmdm()) >= 0) {
+ if ((n & BM_DCD))
+ break;
+ msleep(500);
+ tnc_wait(
+ (CHAR *)"_dodial waiting for DCD",1);
+ }
+ }
+ } else
+#endif /* TN_COMPORT */
+ sleep(1); /* Wait a second */
+ n = ttgmdm(); /* Try to read modem signals */
+ if ((n > -1) && ((n & BM_DCD) == 0))
+ printf("WARNING - no carrier\n");
+ }
+ }
+#endif /* MINIDIAL */
+
+ /* Standard V.25bis stuff */
+
+ } else if (didweget(lbuf,"CNX")) { /* Connected */
+ mdmstat = CONNECTED;
+ } else if (didweget(lbuf, "INV")) {
+ mdmstat = D_FAILED; /* Command error */
+ dialsta = DIA_ERR;
+ ckstrncpy(lbuf,"INV",LBUFL);
+
+ } else if (didweget(lbuf,"CFI")) { /* Call Failure */
+
+ if (didweget(lbuf,"AB")) { /* Interpret reason code */
+ ckstrncpy(lbuf,"AB: Timed out",LBUFL);
+ dialsta = DIA_TIMO;
+ } else if (didweget(lbuf,"CB")) {
+ ckstrncpy(lbuf,"CB: Local DCE Busy",LBUFL);
+ dialsta = DIA_NRDY;
+ } else if (didweget(lbuf,"ET")) {
+ ckstrncpy(lbuf,"ET: Busy",LBUFL);
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf, "NS")) {
+ ckstrncpy(lbuf,"NS: Number not stored",LBUFL);
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"NT")) {
+ ckstrncpy(lbuf,"NT: No answer",LBUFL);
+ dialsta = DIA_NOAN;
+ } else if (didweget(lbuf,"RT")) {
+ ckstrncpy(lbuf,"RT: Ring tone",LBUFL);
+ dialsta = DIA_RING;
+ } else if (didweget(lbuf,"PV")) {
+ ckstrncpy(lbuf,"PV: Parameter value error",LBUFL);
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"PS")) {
+ ckstrncpy(lbuf,"PS: Parameter syntax error",LBUFL);
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"MS")) {
+ ckstrncpy(lbuf,"MS: Message syntax error",LBUFL);
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"CU")) {
+ ckstrncpy(lbuf,"CU: Command unknown",LBUFL);
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"FC")) {
+ ckstrncpy(lbuf,"FC: Forbidden call",LBUFL);
+ dialsta = DIA_NOAC;
+ }
+ mdmstat = D_FAILED;
+ } else if (didweget(lbuf,"INC")) { /* Incoming Call */
+ ckstrncpy(lbuf,"INC: Incoming call",LBUFL);
+ dialsta = DIA_RING;
+ mdmstat = D_FAILED;
+ } else if (didweget(lbuf,"DLC")) { /* Delayed Call */
+ ckstrncpy(lbuf,"DLC: Delayed call",LBUFL);
+ dialsta = DIA_NOAN;
+ mdmstat = D_FAILED;
+ } else /* Response was probably an echo. */
+#ifndef MINIDIAL
+ if (mymdmtyp == n_CCITT)
+#endif /* MINIDIAL */
+ continue;
+#ifndef MINIDIAL
+ else /* Digitel: If no error, connect. */
+ mdmstat = CONNECTED;
+#endif /* MINIDIAL */
+ break;
+
+ } else if (n) { /* Non-Hayes-compatibles... */
+ switch (mymdmtyp) {
+#ifndef MINIDIAL
+ case n_ATTMODEM:
+ /* Careful - "Connected" / "Not Connected" */
+ if (didweget(lbuf,"Busy")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"Not connected") ||
+ didweget(lbuf,"Not Connected")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ } else if (didweget(lbuf,"No dial tone") ||
+ didweget(lbuf,"No Dial Tone")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ } else if (didweget(lbuf,"No answer") ||
+ didweget(lbuf,"No Answer")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN;
+ } else if (didweget(lbuf,"Answered") ||
+ didweget(lbuf,"Connected")) {
+ mdmstat = CONNECTED;
+ dialsta = DIA_OK;
+ }
+ break;
+
+ case n_ATTISN:
+ if (didweget(lbuf,"ANSWERED")) {
+ mdmstat = CONNECTED;
+ dialsta = DIA_OK;
+ } else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"DISCONNECT")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DISC;
+ } else if (didweget(lbuf,"NO ANSWER")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN;
+ } else if (didweget(lbuf,"WRONG ADDRESS")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAC;
+ }
+ break;
+
+ case n_ATTDTDM:
+ if (didweget(lbuf,"ANSWERED")) {
+ mdmstat = CONNECTED;
+ } else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"CHECK OPTIONS")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"DISCONNECTED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DISC;
+ } else if (didweget(lbuf,"DENIED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAC;
+ }
+#ifdef DEBUG
+#ifdef ATT6300
+ /* Horrible hack lost in history. */
+ else if (deblog && didweget(lbuf,"~~"))
+ mdmstat = CONNECTED;
+#endif /* ATT6300 */
+#endif /* DEBUG */
+ break;
+
+#ifdef OLDMODEMS
+ case n_CERMETEK:
+ if (didweget(lbuf,"\016A")) {
+ mdmstat = CONNECTED;
+ ttslow("\016U 1\015",200); /* Make transparent*/
+ }
+ break;
+
+ case n_DF03:
+ /* Because response lacks CR or NL . . . */
+ c = (char) (ddinc(0) & 0177);
+ dialoc(c);
+ debug(F000,"dial df03 got","",c);
+ if ( c == 'A' ) mdmstat = CONNECTED;
+ if ( c == 'B' ) mdmstat = D_FAILED;
+ break;
+
+ case n_DF100: /* DF100 has short response codes */
+ if (strcmp(lbuf,"A") == 0) {
+ mdmstat = CONNECTED; /* Attached */
+ dialsta = DIA_OK;
+ } else if (strcmp(lbuf,"N") == 0) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN; /* No answer or no dialtone */
+ } else if (strcmp(lbuf,"E") == 0 || /* Error */
+ strcmp(lbuf,"R") == 0) { /* "Ready" (?) */
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR; /* Command error */
+ }
+ /* otherwise fall thru... */
+
+ case n_DF200:
+ if (didweget(lbuf,"Attached")) {
+ mdmstat = CONNECTED;
+ dialsta = DIA_OK;
+ /*
+ * The DF100 will respond with "Attached" even if DTR
+ * and/or carrier are not present. Another reason to
+ * (also) wait for carrier?
+ */
+ } else if (didweget(lbuf,"Busy")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"Disconnected")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DISC;
+ } else if (didweget(lbuf,"Error")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"No answer")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN;
+ } else if (didweget(lbuf,"No dial tone")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ } else if (didweget(lbuf,"Speed:)")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ }
+ /*
+ * It appears that the "Speed:..." response comes after an
+ * "Attached" response, so this is never seen. HOWEVER,
+ * it would be very handy to detect this and temporarily
+ * reset the speed, since it's a nuisance otherwise.
+ * If we wait for some more input from the modem, how do
+ * we know if it's from the remote host or the modem?
+ * Carrier reportedly doesn't get set until after the
+ * "Speed:..." response (if any) is sent. Another reason
+ * to (also) wait for carrier.
+ */
+ break;
+
+ case n_GDC:
+ if (didweget(lbuf,"ON LINE"))
+ mdmstat = CONNECTED;
+ else if (didweget(lbuf,"NO CONNECT"))
+ mdmstat = D_FAILED;
+ break;
+
+ case n_PENRIL:
+ if (didweget(lbuf,"OK")) {
+ mdmstat = CONNECTED;
+ } else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"NO RING")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ }
+ break;
+
+ case n_RACAL:
+ if (didweget(lbuf,"ON LINE"))
+ mdmstat = CONNECTED;
+ else if (didweget(lbuf,"FAILED CALL"))
+ mdmstat = D_FAILED;
+ break;
+#endif /* OLDMODEMS */
+
+ case n_ROLM:
+ if (didweget(lbuf,"CALLING"))
+ mdmstat = 0;
+ else if (didweget(lbuf,"COMPLETE"))
+ mdmstat = CONNECTED;
+ else if (didweget(lbuf,"FAILED") ||
+ didweget(lbuf,"ABANDONDED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ } else if (didweget(lbuf,"NOT AVAILABLE") ||
+ didweget(lbuf,"LACKS PERMISSION") ||
+ didweget(lbuf,"NOT A DATALINE") ||
+ didweget(lbuf,"INVALID DATA LINE NUMBER") ||
+ didweget(lbuf,"INVALID GROUP NAME")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAC;
+ } else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"DOES NOT ANSWER")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN;
+ }
+ break;
+
+#ifdef OLDMODEMS
+ case n_VENTEL:
+ if (didweget(lbuf,"ONLINE!") ||
+ didweget(lbuf,"Online!")) {
+ mdmstat = CONNECTED;
+ } else if (didweget(lbuf,"BUSY") ||
+ didweget(lbuf,"Busy")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"DEAD PHONE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DISC;
+ }
+ break;
+
+ case n_CONCORD:
+ if (didweget(lbuf,"INITIATING"))
+ mdmstat = CONNECTED;
+ else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"CALL FAILED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ }
+ break;
+#endif /* OLDMODEMS */
+
+ case n_MICROCOM:
+ /* "RINGBACK" means phone line ringing, continue */
+ if (didweget(lbuf,"NO CONNECT")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ } else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"NO DIALTONE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ } else if (didweget(lbuf,"COMMAND ERROR")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"IN USE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAC;
+ } else if (didweget(lbuf,"CONNECT")) {
+ mdmstat = CONNECTED;
+ /* trailing speed ignored */
+ }
+ break;
+
+#endif /* MINIDIAL */
+ default:
+ printf(
+ "PROGRAM ERROR - No response handler for modem type %d\n",
+ mymdmtyp);
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ }
+ }
+ } /* while (mdmstat == 0) */
+
+ debug(F101,"_dodial alarm off","",x);
+ alarm(0);
+ if (mdmstat == D_FAILED) { /* Failure detected by modem */
+ dialfail(F_MODEM);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+ } else if (mdmstat == D_PARTIAL ) { /* Partial dial command OK */
+ msleep(500);
+ debug(F100,"dial partial","",0);
+ } else { /* Call was completed */
+ int x;
+ msleep(700); /* In case modem signals blink */
+ debug(F100,"dial succeeded","",0);
+ if (
+#ifndef MINIDIAL
+ mymdmtyp != n_ROLM /* Rolm has weird modem signaling */
+#else
+ 1
+#endif /* MINIDIAL */
+ ) {
+ alarm(3); /* In case ttpkt() gets stuck... */
+ ttpkt(speed,FLO_DIAX,parity); /* Cancel dialing state ioctl */
+ alarm(0);
+ }
+/*
+ In case CD went off in the interval between call completion and return
+ from ttpkt()...
+*/
+ if (carrier != CAR_OFF) {
+ if ((x = ttgmdm()) >= 0) {
+#ifdef TN_COMPORT
+ if (istncomport() && !(x & BM_DCD)) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ msleep(500);
+ tnc_wait((CHAR *)"_dodial waiting for DCD",1);
+ if ((x = ttgmdm()) >= 0) {
+ if ((x & BM_DCD))
+ break;
+ }
+ }
+ }
+#endif /* TN_COMPORT */
+ if (!(x & BM_DCD))
+ printf("WARNING: Carrier seems to have dropped...\n");
+ }
+ }
+ }
+ dreset(); /* Reset alarms and signals. */
+ if (!quiet && !backgrd) {
+ if (dialdpy && (p = ck_time())) { /* If DIAL DISPLAY ON, */
+ printf(" %sall complete: %s.\n", /* include timestamp. */
+ (mdmstat == D_PARTIAL) ?
+ "Partial c" :
+ "C",
+ p );
+ } else if (modemmsg[0]) {
+ printf (" %sall complete: \"%s\".\n",
+ (mdmstat == D_PARTIAL) ? "Partial c" : "C",
+ (char *)modemmsg
+ );
+ } else {
+ printf (" %sall complete.\n",
+ (mdmstat == D_PARTIAL) ?
+ "Partial c" :
+ "C"
+ );
+ }
+ }
+#ifdef CKLOGDIAL
+ dologdial(telnbr);
+#endif /* CKLOGDIAL */
+
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ dialsta = (mdmstat == D_PARTIAL) ? DIA_PART : DIA_OK;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+}
+
+static SIGTYP
+#ifdef CK_ANSIC
+faildial(void * threadinfo)
+#else /* Not CK_ANSIC */
+faildial(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* faildial */ {
+ debug(F100,"longjmp returns to dial routine","",0);
+ dialfail(fail_code);
+ SIGRETURN;
+}
+
+/*
+ nbr = number to dial (string)
+ x1 = Retry counter
+ x2 = Number counter
+ fc = Function code:
+ 0 == DIAL
+ 1 == ANSWER
+ 2 == INIT/CONFIG
+ 3 == PARTIAL DIAL
+*/
+
+int
+#ifdef OLD_DIAL
+ckdial(nbr) char *nbr;
+#else
+ckdial(nbr, x1, x2, fc, redial) char *nbr; int x1, x2, fc, redial;
+#endif /* OLD_DIAL */
+/* ckdial */ {
+#define ERMSGL 50
+ char errmsg[ERMSGL], *erp; /* For error messages */
+ int n = F_TIME;
+ char *s;
+ long spdmax;
+#ifdef OS2
+ extern int term_io;
+ int term_io_sav = term_io;
+#endif /* OS2 */
+
+ char *mmsg = "Sorry, DIAL memory buffer can't be allocated\n";
+ /*
+ A DIAL command implies a SET MODEM TYPE command and therefore enables
+ hanging up by modem commands rather than dropping DTR.
+ */
+ mdmset = 1; /* See mdmhup() */
+
+ partial = 0;
+ if (fc == 3) { /* Partial dial requested */
+ partial = 1; /* Set flag */
+ fc = 0; /* Treat like regular dialing */
+ }
+ func_code = fc; /* Make global to this module */
+ telnbr = nbr;
+ xredial = redial;
+ debug(F111,"ckdial entry partial",ckitoa(fc),partial);
+ debug(F111,"ckdial entry number",nbr,redial);
+
+ if (fc == 1) { /* ANSWER command? */
+ /* Reset caller ID strings */
+ if (callid_date) makestr(&callid_date,NULL);
+ if (callid_time) makestr(&callid_time,NULL);
+ if (callid_name) makestr(&callid_name,NULL);
+ if (callid_nmbr) makestr(&callid_nmbr,NULL);
+ if (callid_mesg) makestr(&callid_mesg,NULL);
+ }
+
+#ifdef CK_TAPI_X
+ if (tttapi && tapipass) {
+ if (modemp[n_TAPI] = cktapiGetModemInf()) {
+ mymdmtyp = n_TAPI;
+ } else {
+ mymdmtyp = mdmtyp;
+ modemp[n_TAPI] = &GENERIC;
+ }
+ } else
+#endif /* CK_TAPI */
+ mymdmtyp = mdmtyp;
+ if (mymdmtyp < 0) { /* Whoa, network dialing... */
+ if (mdmsav > -1)
+ mymdmtyp = mdmsav;
+ }
+ if (mymdmtyp < 0) {
+ printf("Invalid modem type %d - internal error.\n",mymdmtyp);
+ dialsta = DIA_NOMO;
+ return(0);
+ }
+ dial_what = DW_NOTHING; /* Doing nothing at first. */
+ nonverbal = 0;
+
+/* These are ONLY for the purpose of interpreting numeric result codes. */
+
+ is_motorola =
+#ifdef MINIDIAL
+ 0
+#else
+ mymdmtyp == n_SUPRA || mymdmtyp == n_SUPRASON;
+#endif /* MINIDIAL */
+ ;
+
+ is_motorola =
+#ifdef MINIDIAL
+ 0
+#else
+ mymdmtyp == n_MOTOROLA || mymdmtyp == n_MONTANA;
+#endif /* MINIDIAL */
+ ;
+
+ is_rockwell =
+#ifdef MINIDIAL
+ 0
+#else
+ mymdmtyp == n_RWV32 || mymdmtyp == n_RWV32B ||
+ mymdmtyp == n_RWV34 || mymdmtyp == n_RWV90 ||
+ mymdmtyp == n_BOCA || mymdmtyp == n_TELEPATH ||
+ mymdmtyp == n_CARDINAL || mymdmtyp == n_BESTDATA ||
+ mymdmtyp == n_CONEXANT || mymdmtyp == n_PCTEL
+#endif /* MINIDIAL */
+ ;
+
+ is_hayeshispd =
+#ifdef MINIDIAL
+ 0
+#else
+ mymdmtyp == n_H_ULTRA || mymdmtyp == n_H_ACCURA || n_PPI
+#endif /* MINIDIAL */
+ ;
+
+ is_supra =
+#ifdef MINIDIAL
+ 0
+#else
+ mymdmtyp == n_SUPRA || mymdmtyp == n_SUPRAX || n_SUPRASON
+#endif /* MINIDIAL */
+ ;
+
+ mp = modemp[mymdmtyp]; /* Set pointer to modem info */
+ if (!mp) {
+ printf("Sorry, handler for this modem type not yet filled in.\n");
+ dialsta = DIA_NOMO;
+ return 0;
+ }
+ debug(F110,"dial number",telnbr,0);
+#ifdef COMMENT
+ debug(F110,"dial prefix",(dialnpr ? dialnpr : ""), 0);
+#endif /* COMMENT */
+
+#ifdef DYNAMIC
+ *lbuf = NUL;
+ debug(F101,"DIAL lbuf malloc ok","",LBUFL+1);
+
+ if (!rbuf) { /* This one might already have been allocated by getok() */
+ if (!(rbuf = malloc(RBUFL+1))) { /* Allocate input line buffer */
+ printf("%s", mmsg);
+ dialsta = DIA_IE;
+ return 0;
+ } else
+ debug(F101,"DIAL rbuf malloc ok","",RBUFL+1);
+ }
+ if (!(fbuf = malloc(FULLNUML+1))) { /* Allocate input line buffer */
+ printf("%s", mmsg);
+ dialsta = DIA_IE;
+ if (rbuf) free(rbuf); rbuf = NULL;
+ return 0;
+ }
+ debug(F101,"DIAL fbuf malloc ok","",FULLNUML+1);
+#endif /* DYNAMIC */
+
+ /* NOTE: mdmtyp, not mymdmtyp */
+
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) { /* Open, no carrier wait */
+ erp = errmsg;
+ if ((int)strlen(ttname) < (ERMSGL - 18)) /* safe, checked */
+ sprintf(erp,"Sorry, can't open %s",ttname);
+ else
+ sprintf(erp,"Sorry, can't open device");
+ perror(errmsg);
+ dialsta = DIA_OPEN;
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ return 0;
+ }
+
+#ifdef CK_TAPI
+ if (!tttapi) {
+#endif /* CK_TAPI */
+
+/* Condition console terminal and communication line */
+
+ /* Place line into "clocal" dialing state, */
+ /* important mainly for System V UNIX. */
+
+ if (ttpkt(speed,FLO_DIAL,parity) < 0) {
+ ttclos(0); /* If ttpkt fails do all this... */
+ if (ttopen(ttname,&local,mymdmtyp,0) < 0) {
+ erp = errmsg;
+ if ((int)strlen(ttname) < (ERMSGL - 18)) /* safe, checked */
+ sprintf(erp,"Sorry, can't reopen %s",ttname);
+ else
+ sprintf(erp,"Sorry, can't reopen device");
+ perror(errmsg);
+ dialsta = DIA_OPEN;
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ return 0;
+ } /* And try again. */
+ if ((ttpkt(speed,FLO_DIAL,parity) < 0)
+#ifdef UNIX
+ && (strcmp(ttname,"/dev/null"))
+#else
+#ifdef OSK
+ && (strcmp(ttname,"/nil"))
+#endif /* OSK */
+#endif /* UNIX */
+#ifdef CK_TAPI
+ && !tttapi
+#endif /* CK_TAPI */
+ ) {
+ printf("Sorry, Can't condition communication line\n");
+ printf("Try 'set line %s' again\n",ttname);
+ dialsta = DIA_OPEN;
+#ifdef DYNAMIC
+ if (rbuf) free(rbuf); rbuf = NULL;
+ if (fbuf) free(fbuf); fbuf = NULL;
+#endif /* DYNAMIC */
+ return 0;
+ }
+ }
+#ifdef CK_TAPI
+ }
+#endif /* CK_TAPI */
+
+ /* Modem's escape sequence... */
+
+ if (dialesc < 0 || dialesc > 127)
+ c = NUL;
+ else
+ c = (char) (dialesc ? dialesc : mp->esc_char);
+ mdmcapas = dialcapas ? dialcapas : mp->capas;
+
+ xx_ok = mp->ok_fn; /* Pointer to response reader */
+
+ if (mdmcapas & CKD_AT) { /* Hayes compatible */
+ escbuf[0] = c;
+ escbuf[1] = c;
+ escbuf[2] = c;
+ escbuf[3] = NUL;
+ /* In case this modem type is user-defined */
+ if (!xx_ok) xx_ok = getok;
+ } else { /* Other */
+ escbuf[0] = c;
+ escbuf[1] = NUL;
+ /* In case user-defined */
+ if (mdmcapas & CKD_V25) if (!xx_ok) xx_ok = getok;
+ }
+
+ /* Partial dialing */
+
+ if (mdmcapas & CKD_AT
+#ifndef MINIDIAL
+ || mymdmtyp == n_MICROCOM
+#endif /* MINIDIAL */
+ ) {
+ int x;
+ x = (int) strlen(telnbr);
+ if (x > 0) {
+ if (telnbr[x-1] == ';') {
+ partial = 1;
+ debug(F110,"ckdial sets partial=1:",telnbr,0);
+ } else if (partial) {
+ ckmakmsg(fbuf,FULLNUML,telnbr,";",NULL,NULL); /* add one */
+ telnbr = fbuf;
+ }
+ }
+ }
+ msleep(500);
+
+ debug(F101,"ckdial dialtmo","",dialtmo); /* Timeout */
+
+ if (fc == 1) { /* ANSWER */
+ waitct = (dialatmo > -1) ? dialatmo : 0;
+ } else { /* DIAL */
+ if (dialtmo < 1) { /* Automatic computation. */
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) {
+ waitct = 1 * (int)strlen(telnbr) ; /* Worst case dial time */
+ waitct += 60; /* dialtone + completion wait times */
+ for (s = telnbr; *s; s++) { /* add in pause characters time */
+ if (*s == ',') {
+ waitct += 2; /* unless it was changed in the modem */
+ } else if (*s == 'W' ||
+ *s == 'w' ||
+ *s == '$' ||
+ *s == '@'
+ ) {
+ waitct += 8;
+ }
+ }
+ } else {
+#endif /* CK_TAPI */
+ waitct = 1 * (int)strlen(telnbr) ;
+ /* dialtone + completion wait times */
+ waitct += mp->dial_time;
+ for (s = telnbr; *s; s++) {
+ for (p = mp->pause_chars; *p; p++)
+ if (*s == *p) {
+ waitct += mp->pause_time;
+ break;
+ }
+ }
+#ifdef CK_TAPI
+ }
+#endif /* CK_TAPI */
+ } else {
+ waitct = dialtmo; /* User-specified timeout */
+ }
+ debug(F101,"ckdial waitct A","",waitct);
+ }
+
+/*
+ waitct is our alarm() timer.
+ mdmwait is how long we tell the modem to wait for carrier.
+ We set mdmwait to be 5 seconds less than waitct, to increase the
+ chance that we get a response from the modem before timing out.
+*/
+ if (waitct <= 0) { /* 0 or negative means wait forever */
+#ifdef COMMENT
+ waitct = 254; /* These were backwards in 7.0.196 */
+ mdmwait = 0;
+#else
+ waitct = 0; /* Fixed in 7.0.198. */
+ mdmwait = 254;
+#endif /* COMMENT */
+ } else {
+ if (dialtmo < 1) { /* Automatic computation. */
+#ifdef XWAITCT
+ /* Addtl wait slop can be defined at compile time */
+ waitct += XWAITCT;
+#endif /* XWAITCT */
+ if (waitct < 60 + mdmwaitd)
+ waitct = 60 + mdmwaitd;
+ }
+ if (mdmcapas & CKD_AT) { /* AT command-set modems */
+ mdmwait = waitct; /* S7 timeout = what user asked for */
+ waitct += mdmwaitd; /* Kermit timeout a bit later */
+ } else { /* Non-AT */
+ mdmwait = waitct; /* no difference */
+ }
+ }
+ debug(F101,"ckdial waitct B","",waitct);
+ if (fc == 1) { /* ANSWER */
+#ifdef COMMENT
+/*
+ This is wrong. mdmwait is the value given to S7 in Hayeslike modems.
+ When in autoanswer mode, this is the amount of time the modem waits for
+ carrier once ringing starts. Whereas waitct is the timeout given to the
+ ANSWER command, which is an entirely different thing. Since the default
+ ANSWER timeout is 0 (meaning "wait forever"), the following statement sets
+ S7 to 0, which, on some modems (like the USR Sportster) makes it hang up
+ and report NO CARRIER the instant the phone rings.
+*/
+ mdmwait = waitct;
+#else
+ if (mdmwait <= 0)
+ mdmwait = 60; /* Always wait 60 seconds. */
+#endif /* COMMENT */
+
+ }
+ if (!quiet && !backgrd) { /* Print information messages. */
+#ifdef VMS
+ printf(" \n");
+ fflush(stdout);
+#endif /* VMS */
+ if (fc == 1)
+ printf(" Waiting for phone call...\n");
+ else
+ printf(" %srying: %s...\n", x1 > 0 ? "Ret" : "T", telnbr);
+ if (x1 == 0 && x2 == 0 && dialsta != DIA_PART) {
+ if (network) {
+ printf(" Via modem server: %s, modem: %s\n",
+ ttname, gmdmtyp() );
+ } else {
+#ifdef CK_TAPI
+ if (tttapi && !tapipass)
+ printf(" Device: %s, modem: %s", ttname, "TAPI" );
+ else
+#endif /* CK_TAPI */
+ printf(" Device: %s, modem: %s",
+ ttname, gmdmtyp() );
+ if (speed > -1L)
+ printf(", speed: %ld\n", speed);
+ else
+ printf(", speed: (unknown)\n");
+ }
+ spdmax = dialmax > 0L ? dialmax : mp->max_speed;
+
+#ifndef NOHINTS
+ if (hints && !quiet &&
+ !network && spdmax > 0L && speed > spdmax
+#ifdef CK_TAPI
+ && (!tttapi || tapipass)
+#endif /* CK_TAPI */
+ ) {
+ printf("\n*************************\n");
+ printf(
+ "Interface speed %ld might be too high for this modem type.\n",
+ speed
+ );
+ printf(
+ "If dialing fails, SET SPEED to %ld or less and try again.\n",
+ spdmax
+ );
+ printf("(Use SET HINTS OFF to suppress future hints.)\n");
+ printf("*************************\n");
+ printf("\n");
+ }
+#endif /* NOHINTS */
+ printf(" %s timeout: ", fc == 0 ? "Dial" : "Answer");
+ if (waitct > 0)
+ printf("%d seconds\n",mdmwait);
+ else
+ printf(" (none)\n");
+ printf(
+#ifdef MAC
+ " Type Command-. to cancel.\n"
+#else
+#ifdef UNIX
+ " To cancel: type your interrupt character (normally Ctrl-C).\n"
+#else
+ " To cancel: type Ctrl-C (hold down Ctrl, press C).\n"
+#endif /* UNIX */
+#endif /* MAC */
+ );
+ }
+ }
+ debug(F111,"ckdial",ttname,(int) (speed / 10L));
+ debug(F101,"ckdial timeout","",waitct);
+#ifdef OS2
+ term_io = 0;
+#endif /* OS2 */
+
+/* Set timer and interrupt handlers. */
+ savint = signal( SIGINT, dialint ) ; /* And terminal interrupt handler. */
+ cc_alrm_execute(ckjaddr(sjbuf), 0, dialtime, _dodial, faildial);
+
+ signal(SIGINT, savint);
+#ifdef OS2
+ if (dialsta == DIA_OK) /* Dialing is completed */
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+ term_io = term_io_sav;
+#endif /* OS2 */
+ if (dialsta == DIA_PART || dialsta == DIA_OK) {
+ /* This is needed, e.g., for Telnet modem servers */
+ if (reliable != SET_OFF || !setreliable) {
+ reliable = SET_OFF; /* Transport is not reliable */
+ debug(F101,"ckdial reliable","",reliable);
+ }
+ return(1); /* Dial attempt succeeded */
+ } else {
+ return(0); /* Dial attempt failed */
+ }
+} /* ckdial */
+
+/*
+ getok() - wait up to n seconds for OK (0) or ERROR (4) response from modem.
+ Use with Hayeslike or CCITT modems for reading the reply to a nondialing
+ command.
+
+ Second argument says whether to be strict about numeric result codes, i.e.
+ to require they be preceded by CR or else be the first character in the
+ response, e.g. to prevent the ATH0<CR> echo from looking like a valid
+ response. Strict == 0 is needed for ATI on Telebit, which can return the
+ model number concatenated with the numeric response code, e.g. "9620"
+ ("962" is the model number, "0" is the response code). getok() Returns:
+
+ 0 if it timed out,
+ 1 if it succeeded,
+ -1 on modem command, i/o, or other error.
+*/
+static ckjmpbuf okbuf;
+
+static SIGTYP
+#ifdef CK_ANSIC
+oktimo(int foo) /* Alarm handler for getok(). */
+#else
+oktimo(foo) int foo; /* Alarm handler for getok(). */
+#endif /* CK_ANSIC */
+/* oktimo */ {
+
+#ifdef OS2
+ alarm(0);
+ /* signal(SIGALRM,SIG_IGN); */
+ debug(F100,"oktimo() SIGALRM caught -- SIG_IGN set","",0) ;
+#endif /* OS2 */
+
+#ifdef OSK /* OS-9, see comment in dialtime(). */
+ sigmask(-1);
+#endif /* OSK */
+#ifdef NTSIG
+ if ( foo == SIGALRM )
+ PostAlarmSigSem();
+ else
+ PostCtrlCSem();
+#else /* NTSIG */
+#ifdef NT
+ cklongjmp(ckjaddr(okbuf),1);
+#else /* NT */
+ cklongjmp(okbuf,1);
+#endif /* NTSIG */
+#endif /* NT */
+ /* NOTREACHED */
+ SIGRETURN;
+}
+
+static int okstatus, okn, okstrict;
+
+static SIGTYP
+#ifdef CK_ANSIC
+dook(void * threadinfo)
+#else /* CK_ANSIC */
+dook(threadinfo) VOID * threadinfo ;
+#endif /* CK_ANSIC */
+/* dook */ {
+ CHAR c;
+#ifdef DEBUG
+ char * mdmmsg = "";
+#endif /* DEBUG */
+
+ int i, x;
+#ifdef IKSD
+ extern int inserver;
+#endif /* IKSD */
+#ifdef NTSIG
+ signal(SIGINT,oktimo);
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ }
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+
+ if (mdmcapas & CKD_V25) { /* CCITT, easy... */
+ waitfor("VAL");
+ okstatus = 1;
+ debug(F111,"Modem_Response(V25)","VAL",okstatus);
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+#ifndef MINIDIAL
+ } else if (mymdmtyp == n_MICROCOM) { /* Microcom in SX mode, also easy */
+ waitfor(MICROCOM.wake_prompt); /* (I think...) */
+ debug(F111,"Modem_Response(Microcom)",MICROCOM.wake_prompt,okstatus);
+ okstatus = 1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+#endif /* MINIDIAL */
+ } else { /* Hayes & friends, start here... */
+ okstatus = 0; /* No status yet. */
+ for (x = 0; x < RBUFL; x++) /* Initialize response buffer */
+ rbuf[x] = SP; /* to all spaces */
+ rbuf[RBUFL] = NUL; /* and terminate with NUL. */
+ while (okstatus == 0) { /* While no status... */
+ x = ddinc(okn); /* Read a character */
+ if (x < 0) { /* I/O error */
+ okstatus = -1;
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+ }
+#ifdef COMMENT
+ /* too much */
+ debug(F101,"getok ddinc","",x); /* Got a character. */
+#endif /* COMMENT */
+ c = (char) (x & 0x7f); /* Get low order 7 bits */
+ if (!c) /* Don't deposit NULs */
+ continue; /* or else didweget() won't work */
+ if (dialdpy) conoc((char)c); /* Echo it if requested */
+ for (i = 0; i < RBUFL-1; i++) /* Rotate buffer */
+ rbuf[i] = rbuf[i+1];
+ rbuf[RBUFL-1] = c; /* Deposit character at end */
+#ifdef COMMENT
+ /* too much */
+ debug(F000,"getok:",rbuf,(int) c); /* Log it */
+#endif /* COMMENT */
+ switch (c) { /* Interpret it. */
+ case CR: /* Got a carriage return. */
+ switch(rbuf[RBUFL-2]) { /* Look at character before it. */
+ case '0': /* 0 = OK numeric response */
+ if (!okstrict ||
+ rbuf[RBUFL-3] == CR || rbuf[RBUFL-3] == SP) {
+ nonverbal = 1;
+ okstatus = 1; /* Good response */
+ }
+ debug(F111,"Modem_Response(Hayes)","0",okstatus);
+ break;
+ case '4': /* 4 = ERROR numeric response */
+#ifndef MINIDIAL
+ /* Or Telebit model number 964! */
+ if (mymdmtyp == n_TELEBIT &&
+ isdigit(rbuf[RBUFL-3]) &&
+ isdigit(rbuf[RBUFL-4]))
+ break;
+ else
+#endif /* MINIDIAL */
+ if (!okstrict ||
+ rbuf[RBUFL-3] == CR || rbuf[RBUFL-3] == SP) {
+ nonverbal = 1;
+ okstatus = -1; /* Bad command */
+ }
+ debug(F111,"Modem_Response(Hayes)","4",okstatus);
+ break;
+ }
+ if (dialdpy && nonverbal) /* If numeric results, */
+ conoc(LF); /* echo a linefeed too. */
+ break;
+ case LF: /* Got a linefeed. */
+ /*
+ Note use of explicit octal codes in the string for
+ CR and LF. We want real CR and LF here, not whatever
+ the compiler happens to replace \r and \n with...
+ */
+ if (!strcmp(rbuf+RBUFL-4,"OK\015\012")) { /* Good response */
+ okstatus = 1;
+ debug(F111,"Modem_Response(Hayes)","OK",okstatus);
+ }
+ if (!strcmp(rbuf+RBUFL-3,"OK\012")) { /* Good response */
+ okstatus = 1;
+ debug(F111,"Modem_Response(Hayes)","OK",okstatus);
+ } else if (!strcmp(rbuf+RBUFL-7,"ERROR\015\012")) { /* Error */
+ okstatus = -1;
+ debug(F111,"Modem_Response(Hayes)","ERROR",okstatus);
+ } else if (!strcmp(rbuf+RBUFL-6,"ERROR\012")) { /* Error */
+ okstatus = -1;
+ debug(F111,"Modem_Response(Hayes)","ERROR",okstatus);
+ }
+ break;
+ /* Check whether modem echoes its commands... */
+ case 't': /* Got little t */
+ if (!strcmp(rbuf+RBUFL-3,"\015at") || /* See if it's "at" */
+ !strcmp(rbuf+RBUFL-3," at"))
+ mdmecho = 1;
+ /* debug(F111,"MDMECHO-t",rbuf+RBUFL-2,mdmecho); */
+ break;
+ case 'T': /* Got Big T */
+ if (!strcmp(rbuf+RBUFL-3,"\015AT") || /* See if it's "AT" */
+ !strcmp(rbuf+RBUFL-3," AT"))
+ mdmecho = 1;
+ /* debug(F111,"MDMECHO-T",rbuf+RBUFL-3,mdmecho); */
+ break;
+ default: /* Other characters, accumulate. */
+ okstatus = 0;
+ break;
+ }
+ }
+ }
+ debug(F101,"getok","",okstatus); /* <-- It's a lie (why?) */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+}
+
+static SIGTYP
+#ifdef CK_ANSIC
+failok(void * threadinfo)
+#else /* CK_ANSIC */
+failok(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failok */ {
+ debug(F100,"longjmp returned to getok()","",0);
+ debug(F100,"getok timeout","",0);
+ SIGRETURN;
+}
+
+int
+getok(n, strict) int n, strict; {
+ debug(F101,"getok entry n","",n);
+ okstatus = 0;
+ okn = n;
+ okstrict = strict;
+
+#ifdef DYNAMIC
+ if (!rbuf) {
+ if (!(rbuf = malloc(RBUFL+1))) { /* Allocate input line buffer */
+ dialsta = DIA_IE;
+ return(-1);
+ }
+ debug(F101,"GETOK rbuf malloc ok","",RBUFL+1);
+ }
+#endif /* DYNAMIC */
+
+ mdmecho = 0; /* Assume no echoing of commands */
+
+ debug(F100,"about to alrm_execute dook()","",0);
+ alrm_execute( ckjaddr(okbuf), n, oktimo, dook, failok ) ;
+ debug(F100,"returning from alrm_execute dook()","",0);
+
+ ttflui(); /* Flush input buffer */
+ return(okstatus); /* Return status */
+}
+
+/* G E T H R N -- Get Hayes Result Numeric */
+
+static VOID
+gethrn() {
+ char c;
+ int x;
+/*
+ Hayes numeric result codes (Hayes 1200 and higher):
+ 0 = OK
+ 1 = CONNECT at 300 bps (or 1200 bps on Hayes 1200 with basic code set)
+ 2 = RING
+ 3 = NO CARRIER
+ 4 = ERROR (in command line)
+ 5 = CONNECT 1200 (extended code set)
+ Hayes 2400 and higher:
+ 6 = NO DIALTONE
+ 7 = BUSY
+ 8 = NO ANSWER
+ 9 = (there is no 9)
+ 10 = CONNECT 2400
+ Reportedly, the codes for Hayes V.32 modems are:
+ 1x = CONNECT <suffix>
+ 5x = CONNECT 1200 <suffix>
+ 9x = CONNECT 2400 <suffix>
+ 11x = CONNECT 4800 <suffix>
+ 12x = CONNECT 9600 <suffix>
+ Where:
+ x: suffix:
+ R = RELIABLE
+ RC = RELIABLE COMPRESSED
+ L = LAPM
+ LC = LAPM COMPRESSED
+ And for Telebits, all the above, except no suffix in numeric mode, plus:
+ 11 = CONNECT 4800
+ 12 = CONNECT 9600
+ 13 = CONNECT 14400
+ 14 = CONNECT 19200
+ 15 = CONNECT 38400
+ 16 = CONNECT 57600
+ 20 = CONNECT 300/REL (= MNP)
+ 22 = CONNECT 1200/REL (= MNP)
+ 23 = CONNECT 2400/REL (= MNP)
+ 46 = CONNECT 7512 (i.e. 75/1200)
+ 47 = CONNECT 1275 (i.e. 1200/75)
+ 48 = CONNECT 7200
+ 49 = CONNECT 12000
+ 50 = CONNECT FAST (not on T1600/3000)
+ 52 = RRING
+ 53 = DIALING
+ 54 = NO PROMPTTONE
+ 61 = CONNECT FAST/KERM (Kermit spoof)
+ 70 = CONNECT FAST/COMP (PEP + compression)
+ 71 = CONNECT FAST/KERM/COMP (PEP + compression + Kermit spoof)
+
+ And for others, lots of special cases below...
+*/
+#define NBUFL 8
+ char nbuf[NBUFL+1]; /* Response buffer */
+ int i = 0, j = 0; /* Buffer pointers */
+
+ debug(F101,"RESPONSE mdmecho","",mdmecho);
+ if (mdmecho) { /* Sponge up dialing string echo. */
+ while (1) {
+ c = (char) (ddinc(0) & 0x7f);
+ debug(F000,"SPONGE","",c);
+ dialoc(c);
+ if (c == CR) break;
+ }
+ }
+ while (mdmstat == 0) { /* Read response */
+ for (i = 0; i < NBUFL; i++) /* Clear the buffer */
+ nbuf[i] = '\0';
+ i = 0; /* Reset the buffer pointer. */
+ c = (char) (ddinc(0) & 0177); /* Get first digit of response. */
+ /* using an untimed, blocking read. */
+ debug(F000,"RESPONSE-A","",c);
+ dialoc(c); /* Echo it if requested. */
+ if (!isdigit(c)) /* If not a digit, keep looking. */
+ continue;
+ nbuf[i++] = c; /* Got first digit, save it. */
+ while (c != CR && i < 8) { /* Read chars up to CR */
+ x = ddinc(0) & 0177; /* Get a character. */
+ c = (char) x; /* Got it OK. */
+ debug(F000,"RESPONSE-C","",c);
+ if (c != CR) /* If it's not a carriage return, */
+ nbuf[i++] = c; /* save it. */
+ dialoc(c); /* Echo it. */
+ }
+ nbuf[i] = '\0'; /* Done, terminate the buffer. */
+ debug(F110,"dial hayesnv lbuf",lbuf,0);
+ debug(F111,"dial hayesnv got",nbuf,i);
+ /*
+ Separate any non-numeric suffix from the numeric
+ result code with a null.
+ */
+ for (j = i-1; (j > -1) && !isdigit(nbuf[j]); j--)
+ nbuf[j+1] = nbuf[j];
+ j++;
+ nbuf[j++] = '\0';
+ debug(F110,"dial hayesnv numeric",nbuf,0);
+ debug(F111,"dial hayesnv suffix ",nbuf+j,j);
+ /* Probably phone number echoing. */
+ if ((int)strlen(nbuf) > 3)
+ continue;
+
+ /* Now read and interpret the results... */
+
+ i = atoi(nbuf); /* Convert to integer */
+ switch (i) {
+ case 0:
+ mdmstat = D_PARTIAL; /* OK response */
+ break;
+ case 1: /* CONNECT */
+ mdmstat = CONNECTED; /* Could be any speed */
+ break;
+ case 2: /* RING */
+ if (dialdpy)
+ printf("\r\n Local phone is ringing!\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_RING;
+ break;
+ case 3: /* NO CARRIER */
+ if (dialdpy) printf("\r\n No Carrier.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ break;
+ case 4: /* ERROR */
+ if (dialdpy)
+ printf("\r\n Modem Command Error.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ break;
+ case 5: /* CONNECT 1200 */
+ spdchg(1200L); /* Change speed if necessary. */
+ mdmstat = CONNECTED;
+ break;
+ case 6: /* NO DIALTONE */
+#ifndef MINIDIAL
+ if (mymdmtyp == n_MICROLINK && atoi(diallcc) == 49 && dialdpy)
+ printf("\r\n Dial Locked.\r\n"); /* Germany */
+ else
+#endif /* MINIDIAL */
+ if (dialdpy)
+ printf("\r\n No Dialtone.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ break;
+ case 7: /* BUSY */
+ if (dialdpy) printf("\r\n Busy.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ break;
+ case 8: /* NO ANSWER */
+#ifndef MINIDIAL
+ if (mymdmtyp == n_MICROLINK && atoi(diallcc) == 41 && dialdpy)
+ printf("\r\n Dial Locked.\r\n"); /* Switzerland */
+ else
+#endif /* MINIDIAL */
+ if (dialdpy)
+ printf("\r\n No Answer.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN;
+ break;
+
+ case 9:
+#ifndef MINIDIAL
+ if (mymdmtyp == n_XJACK || mymdmtyp == n_SUPRAX) {
+ spdchg(600);
+ break;
+ } /* fall thru */
+#endif /* MINIDIAL */
+ case 10: /* CONNECT 2400 */
+ spdchg(2400L); /* Change speed if necessary. */
+ mdmstat = CONNECTED;
+ break;
+
+#ifndef MINIDIAL
+
+/* Starting here, we get different meanings from different manufacturers */
+
+ case 11:
+ if (mymdmtyp == n_USR) {
+ if (dialdpy) printf(" Ringing...\r\n");
+ } else {
+ spdchg(4800L); /* CONNECT 4800 */
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 12:
+ if (mymdmtyp == n_USR) {
+ if (dialdpy)
+ printf("\r\n Answered by voice.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_VOIC;
+ } else if (mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ } else {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 13:
+ if (mymdmtyp == n_ATT1900 || mymdmtyp == n_ATT1910) {
+ if (dialdpy) printf(" Wait...\r\n");
+ break;
+ } else if (mymdmtyp == n_USR || mymdmtyp == n_USRX2)
+ spdchg(9600L);
+ else if (is_rockwell || is_supra ||
+ mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK)
+ spdchg(7200L);
+ else if (mymdmtyp != n_MICROLINK)
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ break;
+ case 14:
+ if (is_rockwell || is_supra || mymdmtyp == n_XJACK)
+ spdchg(12000L);
+ else if (mymdmtyp == n_DATAPORT || mymdmtyp == n_MICROLINK)
+ spdchg(14400L);
+ else if (mymdmtyp == n_KEEPINTOUCH)
+ spdchg(9600L);
+ else if (mymdmtyp != n_USR && mymdmtyp != n_ZOLTRIX)
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ break;
+ case 15:
+ if (is_rockwell || is_supra ||
+ mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK)
+ spdchg(14400L);
+ else if (mymdmtyp == n_USR)
+ spdchg(1200L);
+ else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL)
+ spdchg(7200L);
+ else if (mymdmtyp == n_DATAPORT)
+ spdchg(19200L);
+ else
+ spdchg(38400L);
+ mdmstat = CONNECTED;
+ break;
+ case 16:
+ if (is_rockwell || is_supra ||
+ mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK)
+ spdchg(19200L);
+ else if (mymdmtyp == n_USR)
+ spdchg(2400L);
+ else if (mymdmtyp == n_DATAPORT)
+ spdchg(7200L);
+ else if (mymdmtyp != n_ZYXEL && mymdmtyp != n_INTEL) /* 12000 */
+ spdchg(57600L);
+ mdmstat = CONNECTED;
+ break;
+ case 17:
+ if (mymdmtyp != n_DATAPORT || mymdmtyp == n_XJACK) /* 16800 */
+ spdchg(38400L);
+ else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL)
+ spdchg(14400L);
+ else if (mymdmtyp == n_KEEPINTOUCH)
+ spdchg(14400L);
+ else if (mymdmtyp == n_USR)
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ break;
+ case 18:
+ if (is_rockwell || is_supra ||
+ mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK ||
+ mymdmtyp == n_MHZATT || mymdmtyp == n_LUCENT)
+ spdchg(57600L);
+ else if (mymdmtyp == n_INTEL)
+ spdchg(19200L);
+ else if (mymdmtyp == n_USR || mymdmtyp == n_USRX2)
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ break;
+ case 19:
+ if (mymdmtyp == n_DATAPORT)
+ spdchg(300L);
+ else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL)
+ spdchg(38400L);
+ else
+ spdchg(115200L);
+ mdmstat = CONNECTED;
+ break;
+ case 20:
+ if (mymdmtyp == n_USR || mymdmtyp == n_USRX2)
+ spdchg(7200L);
+ else if (mymdmtyp == n_DATAPORT)
+ spdchg(2400L);
+ else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL)
+ spdchg(57600L);
+ else
+ spdchg(300L);
+ mdmstat = CONNECTED;
+ break;
+ case 21:
+ if (mymdmtyp == n_DATAPORT)
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ break;
+ case 22:
+ if (is_rockwell || is_supra || mymdmtyp == n_XJACK)
+ spdchg(8880L);
+ else if (mymdmtyp == n_DATAPORT)
+ spdchg(9600L);
+ else if (mymdmtyp == n_KEEPINTOUCH)
+ spdchg(300L);
+ else if (!is_hayeshispd)
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ break;
+ case 23:
+ if (is_hayeshispd || is_supra ||
+ mymdmtyp == n_MULTI || mymdmtyp == n_XJACK)
+ spdchg(8880L);
+ else if (mymdmtyp != n_DATAPORT && !is_rockwell) /* 12000 */
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ break;
+ case 24:
+ if (is_rockwell || is_supra || mymdmtyp == n_XJACK) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DELA; /* Delayed */
+ break;
+ } else if (is_hayeshispd || mymdmtyp == n_LUCENT)
+ spdchg(7200L);
+ else if (mymdmtyp == n_DATAPORT)
+ spdchg(14400L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ break;
+ case 25:
+ if (mymdmtyp == n_USR || mymdmtyp == n_USRX2)
+ spdchg(14400L);
+ else if (mymdmtyp == n_LUCENT)
+ spdchg(12000L);
+ else if (is_motorola)
+ spdchg(9600L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ break;
+ case 26:
+ if (mymdmtyp == n_DATAPORT)
+ spdchg(19200L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ break;
+ case 27:
+ if (mymdmtyp == n_DATAPORT)
+ spdchg(38400L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(7200L);
+ else if (mymdmtyp == n_MHZATT)
+ spdchg(8880L);
+ mdmstat = CONNECTED;
+ break;
+ case 28:
+ if (mymdmtyp == n_DATAPORT)
+ spdchg(7200L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(9600L);
+ else if (mymdmtyp == n_MHZATT || mymdmtyp == n_LUCENT)
+ spdchg(38400L);
+ mdmstat = CONNECTED;
+ break;
+ case 29:
+ if (is_motorola)
+ spdchg(4800L);
+ else if (mymdmtyp == n_DATAPORT)
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ break;
+ case 30:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ } /* fall thru on purpose... */
+ case 31:
+ if (mymdmtyp == n_UCOM_AT || mymdmtyp == n_MICROLINK) {
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(57600L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 32:
+ if (is_rockwell || is_supra || mymdmtyp == n_XJACK) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BLCK; /* Blacklisted */
+ } else if (mymdmtyp == n_UCOM_AT || mymdmtyp == n_MICROLINK) {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(300L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL) {
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 33: /* FAX connection */
+ if (is_rockwell || is_supra ||
+ mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_FAX;
+ } else if (mymdmtyp == n_UCOM_AT ||
+ is_motorola ||
+ mymdmtyp == n_MICROLINK
+ ) {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_MHZATT) {
+ spdchg(115200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 34:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_MICROLINK) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 35:
+ if (is_rockwell) {
+ spdchg(300L);
+ dialsta = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_MICROLINK) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) /* DATA */
+ mdmstat = CONNECTED;
+ break;
+ case 36:
+ if (mymdmtyp == n_UCOM_AT) {
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 37:
+ if (mymdmtyp == n_UCOM_AT) {
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 38:
+ if (is_motorola) {
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ } /* fall thru on purpose... */
+ case 39:
+ if (mymdmtyp == n_UCOM_AT) {
+ spdchg(38400L);
+ mdmstat = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_MICROLINK) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 40:
+ if (mymdmtyp == n_UCOM_AT) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ } else if (is_motorola || mymdmtyp == n_INTEL ||
+ mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 41:
+ if (is_motorola) {
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 42:
+ if (mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(300L);
+ mdmstat = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(38400L);
+ mdmstat = CONNECTED;
+ } /* fall thru on purpose... */
+ case 43:
+ if (mymdmtyp == n_UCOM_AT) {
+ spdchg(57600L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_USRX2)
+ mdmstat = CONNECTED; /* 168000 */
+ break;
+ case 44:
+ if (is_rockwell) {
+ spdchg(8800L);
+ dialsta = CONNECTED;
+ } else if (is_motorola) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 45:
+ if (is_motorola) {
+ spdchg(57600L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ } else if (n_USR) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 46:
+ if (is_rockwell)
+ spdchg(1200L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(4800L);
+ else
+ spdchg(8880L); /* 75/1200 split speed */
+ mdmstat = CONNECTED;
+ break;
+ case 47:
+ if (is_rockwell)
+ spdchg(2400L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(7200L);
+ else
+ printf("CONNECT 1200/75 - Not supported by C-Kermit\r\n");
+ mdmstat = CONNECTED;
+ break;
+ case 48:
+ if (is_rockwell)
+ spdchg(4800L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(9600L);
+ else
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ break;
+ case 49:
+ if (is_rockwell)
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ break;
+ case 50: /* CONNECT FAST */
+ if (is_rockwell)
+ spdchg(9600L);
+ else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH)
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ break;
+ case 51:
+ if (mymdmtyp == n_UCOM_AT) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ }
+ break;
+ case 52: /* RRING */
+ if (mymdmtyp == n_TELEBIT)
+ if (dialdpy) printf(" Ringing...\r\n");
+ break;
+ case 53: /* DIALING */
+ if (mymdmtyp == n_TELEBIT)
+ if (dialdpy) printf(" Dialing...\r\n");
+ break;
+ case 54:
+ if (is_rockwell) {
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ } else if (mymdmtyp == n_TELEBIT) {
+ if (dialdpy) printf("\r\n No Prompttone.\r\n");
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ }
+ break;
+ case 55:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 56:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 57:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 58:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 59:
+ if (mymdmtyp == n_INTEL) /* 12000 */
+ mdmstat = CONNECTED;
+ break;
+ case 60:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 64:
+ if (mymdmtyp == n_INTEL) {
+ spdchg(1200L);
+ mdmstat = CONNECTED;
+ } else if (is_supra) {
+ spdchg(28800L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 65:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(2400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 66:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(4800L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 67:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(7200L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 68:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(9600L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 69:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) /* 12000 */
+ mdmstat = CONNECTED;
+ break;
+ case 70:
+ if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) {
+ spdchg(14400L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 73:
+ if (mymdmtyp == n_UCOM_AT) {
+ spdchg(115200L);
+ mdmstat = CONNECTED;
+ break;
+ } /* else fall thru */
+ if (mymdmtyp == n_TELEBIT) /* Early models only */
+ mdmstat = CONNECTED;
+ break;
+ case 85:
+ if (mymdmtyp == n_USR || mymdmtyp == n_USRX2)
+ spdchg(19200L);
+ mdmstat = CONNECTED;
+ break;
+ case 91: /* 21600 */
+ case 99: /* 24000 */
+ case 103: /* 26400 */
+ if (mymdmtyp == n_USRX2)
+ mdmstat = CONNECTED;
+ break;
+ case 107:
+ if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) {
+ spdchg(28800L);
+ mdmstat = CONNECTED;
+ }
+ break;
+ case 151: /* 312000 */
+ case 155: /* 336000 */
+ if (mymdmtyp == n_USRX2)
+ mdmstat = CONNECTED;
+ break;
+
+#endif /* MINIDIAL */
+ default:
+#ifndef MINIDIAL
+ if (mymdmtyp == n_USR || mymdmtyp == n_USRX2 ||
+ is_hayeshispd || is_rockwell)
+#endif /* MINIDIAL */
+ if (i > 12) /* There are hundreds of them... */
+ mdmstat = CONNECTED;
+ break;
+ }
+ }
+ if (mdmstat == CONNECTED && nbuf[j] != '\0') {
+ if (dialdpy) {
+ printf("\r\n");
+ if (nbuf[j] == 'R') printf(" RELIABLE");
+ if (nbuf[j] == 'L') printf(" LAPM");
+ if (nbuf[j+1] == 'C') printf(" COMPRESSED");
+ printf("\r\n");
+ }
+ ckstrncpy(lbuf,nbuf,LBUFL); /* (for messages...) */
+ }
+}
+
+static VOID /* Get Hayes Result in Word mode */
+gethrw() {
+ char *cptr, *s;
+ long conspd;
+
+ if (mdmspd && !network) {
+ s = lbuf;
+ while (*s != '\0' && *s != 'C') s++;
+ cptr = (*s == 'C') ? s : NULL;
+ conspd = 0L;
+ if ((cptr != NULL) && !strncmp(cptr,"CONNECT ",8)) {
+ if ((int)strlen(cptr) < 9) /* Just CONNECT, */
+ conspd = 300L; /* use 300 bps */
+ else if (isdigit(*(cptr+8))) /* not CONNECT FAST */
+ conspd = atol(cptr + 8); /* CONNECT nnnn */
+ if (conspd != speed) {
+ if ((conspd / 10L) > 0) {
+ if (ttsspd((int) (conspd / 10L)) < 0) {
+ printf(" Can't change speed to %ld\r\n",
+ conspd);
+ } else {
+ speed = conspd;
+ mdmstat = CONNECTED;
+ if ( !quiet && !backgrd )
+ printf(" Speed changed to %ld\r\n",
+ conspd);
+ }
+ }
+ } /* Expanded to handle any conceivable speed */
+ }
+ }
+#ifndef MINIDIAL
+ if (mymdmtyp == n_TELEBIT) {
+ if (didweget(lbuf,"CONNECT FAST/KERM")) {
+ mdmstat = CONNECTED;
+ if (dialdpy) printf("FAST/KERM ");
+ return;
+ }
+ }
+#endif /* MINIDIAL */
+ if (didweget(lbuf,"RRING") ||
+ didweget(lbuf,"RINGING") ||
+ didweget(lbuf,"DIALING")) {
+ mdmstat = 0;
+ } else if (didweget(lbuf,"CONNECT")) {
+ mdmstat = CONNECTED;
+ } else if (didweget(lbuf,"OK")) {
+ if (partial) {
+ mdmstat = D_PARTIAL;
+ } else {
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ }
+ } else if (didweget(lbuf,"NO CARRIER")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ } else if (didweget(lbuf,"NO DIALTONE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ } else if (didweget(lbuf,"NO DIAL TONE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ } else if (didweget(lbuf,"BUSY")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BUSY;
+ } else if (didweget(lbuf,"NO ANSWER")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOAN;
+ } else if (didweget(lbuf,"VOICE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_VOIC;
+ } else if (didweget(lbuf,"VCON")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_VOIC;
+ } else if (didweget(lbuf,"NO PROMPT TONE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NODT;
+ } else if (didweget(lbuf,"REMOTE ACCESS FAILED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_NOCA;
+ } else if (didweget(lbuf,"FAX")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_FAX;
+ } else if (didweget(lbuf,"WAIT - CONNECTING") ||
+ didweget(lbuf,"WAIT-CONNECTING")) { /* AT&T STU-III 19xx */
+ mdmstat = 0;
+ } else if (didweget(lbuf,"DELAYED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DELA;
+ } else if (didweget(lbuf,"BLACKLISTED")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_BLCK;
+ } else if (didweget(lbuf,"COMPRESSION")) {
+ mdmstat = 0;
+ } else if (didweget(lbuf,"PROTOCOL")) {
+ mdmstat = 0;
+ } else if (didweget(lbuf,"DIAL LOCKED")) { /* Germany, Austria, Schweiz */
+ mdmstat = D_FAILED;
+ dialsta = DIA_BLCK;
+ } else if ( didweget(lbuf,"RING") ||
+ didweget(lbuf,"RING1") || /* Distinctive Ring 1 */
+ didweget(lbuf,"RING2") || /* Distinctive Ring 2 */
+ didweget(lbuf,"RING3") ) {
+ mdmstat = (func_code == 0) ? D_FAILED : 0;
+ dialsta = DIA_RING;
+ } else if (didweget(lbuf,"ERROR")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_ERR;
+ } else if (didweget(lbuf,"CARRIER")) { /* Boca / Rockwell family */
+#ifdef COMMENT
+ if (is_rockwell)
+#endif /* COMMENT */
+ mdmstat = 0;
+#ifdef COMMENT
+ /* Does CARRIER ever mean the same as CONNECT? */
+ else
+ mdmstat = CONNECTED;
+#endif /* COMMENT */
+ } else if (didweget(lbuf,"DATA")) { /* Boca / Rockwell family */
+ /* This message is sent when the modem is in FAX mode */
+ /* So setting this to CONNECTED may not be appropriate */
+ /* We must send ATO\015 to the modem in response */
+ /* Then we will get a CONNECTED message */
+ mdmstat = CONNECTED;
+ } else if (didweget(lbuf,"DIGITAL LINE")) {
+ mdmstat = D_FAILED;
+ dialsta = DIA_DIGI;
+ } else if (didweget(lbuf,"DATE")) { /* Caller ID Date */
+ debug(F110,"CALLID DATE",lbuf,0);
+ /* Format is "DATE = MMDD" */
+ makestr(&callid_date,lbuf);
+ } else if (didweget(lbuf,"TIME")) { /* Caller ID Time */
+ /* Format is "TIME = HHMM" */
+ debug(F110,"CALLID TIME",lbuf,0);
+ makestr(&callid_time,lbuf);
+ } else if (didweget(lbuf,"NAME")) { /* Caller ID Name */
+ /* Format is "NAME = <listing name>" */
+ debug(F110,"CALLID NAME",lbuf,0);
+ makestr(&callid_name,lbuf);
+ } else if (didweget(lbuf,"NMBR")) { /* Caller ID Number */
+ /* Format is "NMBR = <number>, 'P' or 'O'" */
+ /* 'P' means Privacy Requested */
+ /* 'O' means Out of Service or Not available */
+ debug(F110,"CALLID NMBR",lbuf,0);
+ makestr(&callid_nmbr,lbuf);
+ } else if (didweget(lbuf,"MESG")) { /* Caller ID Unrecognized Message */
+ /* Format is "MESG = <tag><length><data><checksum>" */
+ debug(F110,"CALLID MESG",lbuf,0);
+ makestr(&callid_mesg,lbuf);
+ }
+}
+
+/* Maybe hang up the phone, depending on various SET DIAL parameters. */
+
+int
+dialhup() {
+ int x = 0;
+ if (dialhng && dialsta != DIA_PART) { /* DIAL HANGUP ON? */
+ x = mdmhup(); /* Try modem-specific method first */
+ debug(F101,"dialhup mdmhup","",x);
+ if (x > 0) { /* If it worked, */
+ dialsta = DIA_HUP;
+ if (dialdpy)
+ printf(" Modem hangup OK\r\n"); /* fine. */
+ } else if (network /* If we're telnetted to */
+#ifdef TN_COMPORT
+ && !istncomport() /* (without RFC 2217) */
+#endif /* TN_COMPORT */
+ ) {
+ dialsta = DIA_HANG;
+ if (dialdpy) /* a modem server, just print a msg */
+ printf(" WARNING - modem hangup failed\r\n"); /* don't hangup! */
+ return(0);
+ } else { /* Otherwise */
+ x = tthang(); /* Tell the OS to turn off DTR. */
+ if (x > 0) { /* Yes, tell results from tthang() */
+ dialsta = DIA_HUP;
+ if (dialdpy) printf(" Hangup OK\r\n");
+ } else if (x == 0) {
+ if (dialdpy) printf(" Hangup skipped\r\n");
+ } else {
+ dialsta = DIA_HANG;
+ if (dialdpy) perror(" Hangup error");
+ }
+ ttflui();
+ }
+ } else if (dialdpy) printf(" Hangup skipped\r\n"); /* DIAL HANGUP OFF */
+ return(x);
+}
+
+/*
+ M D M H U P --
+
+ Sends escape sequence to modem, then sends its hangup command. Returns:
+ 0: If modem type is 0 (direct serial connection),
+ or if modem type is < 0 (network connection),
+ or if no action taken because DIAL MODEM-HANGUP is OFF)
+ or because no hangup string for current modem type,
+ or C-Kermit is in remote mode,
+ or if action taken but there was no positive response from modem;
+ 1: Success: modem is in command state and acknowledged the hangup command;
+ -1: On modem command error.
+*/
+int
+mdmhup() {
+#ifdef MDMHUP
+ int m, x = 0;
+ int xparity;
+ int savcarr;
+ extern int ttcarr;
+ char *s, *p, c;
+ MDMINF * mp = NULL;
+
+ debug(F101,"mdmhup dialmhu","",dialmhu); /* MODEM-HANGUP METHOD */
+ debug(F101,"mdmhup local","",local);
+
+ if (dialmhu == 0 || local == 0) /* If DIAL MODEM-HANGUP is OFF, */
+ return(0); /* or not in local mode, fail. */
+
+ debug(F101,"mdmhup dialsta","",dialsta);
+ debug(F101,"mdmhup mdmset","",mdmset);
+
+ if (dialsta != DIA_OK && !mdmset) /* It's not a dialed connection */
+ return(0);
+
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) /* Don't hangup if using TAPI */
+ return(0);
+#endif /* CK_TAPI */
+
+#ifdef COMMENT
+ /* No, we still need this for modems that ignore DTR */
+ if (mymdmtyp == n_GENERIC && !network)
+ return(0);
+#endif /* COMMENT */
+
+ debug(F101,"mdmhup dialesc","",dialesc);
+ if (dialesc < 0)
+ return(0); /* No modem escape-character, fail. */
+
+ savcarr = ttcarr;
+ ttcarr = CAR_OFF;
+ x = ttchk();
+ ttcarr = savcarr;
+ debug(F101,"mdmhup ttchk","",x);
+ if (x < 0) /* There appears to be no connection */
+ return(0);
+ x = 0;
+
+#ifdef OS2
+/*
+ In OS/2, if CARRIER is OFF, and there is indeed no carrier signal, any
+ attempt to do i/o at this point can hang the program. This might be true
+ for other operating systems too.
+*/
+ if (!network /* Not a network connection */
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) {
+ m = ttgmdm(); /* Get modem signals */
+ if ((m > -1) && (m & BM_DCD == 0)) /* Check for carrier */
+ return(0); /* No carrier, skip the rest */
+ }
+#endif /* OS2 */
+
+ debug(F111,"mdmhup network",ttname,network);
+ debug(F101,"mdmhup mymdmtyp","",mymdmtyp);
+ debug(F101,"mdmhup mdmtyp","",mdmtyp);
+ /* In case of HANGUP before DIAL */
+ if (network && mdmtyp < 1) /* SET HOST but no subsequent */
+ return(0); /* SET MODEM TYPE... */
+ if (mymdmtyp == 0 && mdmtyp > 0)
+ mymdmtyp = mdmtyp;
+ if (mymdmtyp < 1) /* Not using a modem */
+ return(0);
+ if (mymdmtyp > 0) /* An actual modem... */
+ mp = modemp[mymdmtyp];
+ if (!mp) { /* Get pointer to its MDMINF struct */
+ debug(F100,"mdmhup no MDMINF","",0);
+ return(0);
+ }
+ mdmcapas = dialcapas ? dialcapas : mp->capas;
+ xx_ok = mp->ok_fn; /* Pointer to response reader */
+
+ s = dialhcmd ? dialhcmd : mp->hup_str; /* Get hangup command */
+ if (!s) s = "";
+ debug(F110,"mdmhup hup_str",s,0);
+ if (!*s) return(0); /* If none, fail. */
+
+ if (ttpkt(speed,FLO_DIAL,parity) < 0) /* Condition line for dialing */
+ return(-1);
+
+ xparity = parity; /* Set PARITY to NONE temporarily */
+ parity = 0;
+
+ /* In case they gave a SET MODEM ESCAPE command recently... */
+
+ if (dialesc < 0 || dialesc > 127)
+ c = NUL;
+ else
+ c = (char) (dialesc ? dialesc : mp->esc_char);
+
+ if (mdmcapas & CKD_AT) { /* Hayes compatible */
+ escbuf[0] = c;
+ escbuf[1] = c;
+ escbuf[2] = c;
+ escbuf[3] = NUL;
+ } else { /* Other */
+ escbuf[0] = c;
+ escbuf[1] = NUL;
+ }
+ debug(F110,"mdmhup escbuf",escbuf,0);
+ if (escbuf[0]) { /* Have escape sequence? */
+ debug(F101,"mdmhup esc_time",0,mp->esc_time);
+ if (mp->esc_time) /* If we have a guard time */
+ msleep(mp->esc_time); /* Pause for guard time */
+ debug(F100,"mdmhup pause 1 OK","",0);
+
+#ifdef NETCONN /* Send modem's escape sequence */
+ if (network) { /* Must catch errors here. */
+ if (ttol((CHAR *)escbuf,(int)strlen((char *)escbuf)) < 0) {
+ parity = xparity;
+ return(-1);
+ }
+ debug(F110,"mdmhup ttslow net ok",escbuf,0);
+ } else {
+#endif /* NETCONN */
+ ttslow((char *)escbuf,wr); /* Send escape sequence */
+ debug(F110,"mdmhup ttslow ok",escbuf,0);
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+
+ if (mp->esc_time) /* Pause for guard time again */
+ msleep(mp->esc_time);
+ else
+ msleep(500); /* Wait half a sec for echoes. */
+ debug(F100,"mdmhup pause 1 OK","",0);
+#ifdef COMMENT
+ ttflui(); /* Flush response or echo, if any */
+ debug(F100,"mdmhup ttflui OK","",0);
+#endif /* COMMENT */
+ }
+ ttslow(s,wr); /* Now Send hangup string */
+ debug(F110,"mdmhup ttslow ok",s,0);
+/*
+ This is not exactly right, but it works.
+ If we are online:
+ the modem says OK when it gets the escape sequence,
+ and it says NO CARRIER when it gets the hangup command.
+ If we are offline:
+ the modem does NOT say OK (or anything else) when it gets the esc sequence,
+ but it DOES say OK (and not NO CARRIER) when it gets the hangup command.
+ So the following function should read the OK in both cases.
+ Of course, this is somewhat Hayes-specific...
+*/
+ if (xx_ok) { /* Look for OK response */
+ debug(F100,"mdmhup calling response function","",0);
+ x = (*xx_ok)(3,1); /* Give it 3 seconds, be strict. */
+ debug(F101,"mdmhup hangup response","",x);
+ msleep(500); /* Wait half a sec */
+ ttflui(); /* Get rid of NO CARRIER, if any */
+ } else { /* No OK function, */
+ x = 1; /* so assume it worked */
+ debug(F101,"mdmhup no ok_fn","",x);
+ }
+ parity = xparity; /* Restore prevailing parity */
+ return(x); /* Return OK function's return code. */
+
+#else /* MDMHUP not defined. */
+
+ debug(F100,"mdmhup MDMHUP not defined","",0);
+ return(0); /* Always fail. */
+
+#endif /* MDMHUP */
+}
+
+#endif /* NOICP */
+#else /* NODIAL */
+
+int mdmtyp = 0; /* Default modem type */
+
+int /* To allow NODIAL versions to */
+mdmhup() { /* call mdmhup(), so calls to */
+ return(0); /* mdmhup() need not be within */
+} /* #ifndef NODIAL conditionals */
+#endif /* NODIAL */
+#else
+int mdmtyp = 0; /* Default modem type */
+#endif /* NOLOCAL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckufio.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckufio.c
new file mode 100644
index 0000000..b5bfaae
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckufio.c
@@ -0,0 +1,8545 @@
+/* C K U F I O -- Kermit file system support for UNIX, Aegis, and Plan 9 */
+
+#define CK_NONBLOCK /* See zoutdump() */
+
+#ifdef aegis
+char *ckzv = "Aegis File support, 9.0.216, 20 Aug 2011";
+#else
+#ifdef Plan9
+char *ckzv = "Plan 9 File support, 9.0.216, 20 Aug 2011";
+#else
+char *ckzv = "UNIX File support, 9.0.216, 20 Aug 2011";
+#endif /* Plan9 */
+#endif /* aegis */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City,
+ and others noted in the comments below. Note: CUCCA = Previous name of
+ Columbia University Academic Information Systems. Note: AcIS = Previous
+ of Columbia University Information Technology.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
+ compatible with C preprocessors that support only #ifdef, #else, #endif,
+ #define, and #undef. Please do not use #if, logical operators, or other
+ preprocessor features in any of the portable C-Kermit modules. You can,
+ of course, use these constructions in platform-specific modules where you
+ know they are supported.
+*/
+/* Include Files */
+
+#ifdef MINIX2
+#define _MINIX
+#endif /* MINIX2 */
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+
+#ifndef NOCSETS
+#include "ckcxla.h"
+#endif /* NOCSETS */
+
+/* To avoid pulling in all of ckuusr.h so we copy the few needed prototypes */
+
+struct mtab { /* Macro table, like keyword table */
+ char *kwd; /* But with pointers for vals */
+ char *mval; /* instead of ints. */
+ short flgs;
+};
+_PROTOTYP( int mlook, (struct mtab [], char *, int) );
+_PROTOTYP( int dodo, (int, char *, int) );
+_PROTOTYP( int parser, ( int ) );
+
+#ifdef COMMENT
+/* This causes trouble in C-Kermit 8.0. I don't remember the original */
+/* reason for this being here but it must have been needed at the time... */
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+#endif /* COMMENT */
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#include <signal.h>
+
+#ifdef MINIX2
+#undef MINIX
+#undef CKSYSLOG
+#include <limits.h>
+#include <time.h>
+#define NOFILEH
+#endif /* MINIX2 */
+
+#ifdef MINIX
+#include <limits.h>
+#include <sys/types.h>
+#include <time.h>
+#else
+#ifdef POSIX
+#include <limits.h>
+#else
+#ifdef SVR3
+#include <limits.h>
+#endif /* SVR3 */
+#endif /* POSIX */
+#endif /* MINIX */
+/*
+ Directory Separator macros, to allow this module to work with both UNIX and
+ OS/2: Because of ambiguity with the command line editor escape \ character,
+ the directory separator is currently left as / for OS/2 too, because the
+ OS/2 kernel also accepts / as directory separator. But this is subject to
+ change in future versions to conform to the normal OS/2 style.
+*/
+#ifndef DIRSEP
+#define DIRSEP '/'
+#endif /* DIRSEP */
+#ifndef ISDIRSEP
+#define ISDIRSEP(c) ((c)=='/')
+#endif /* ISDIRSEP */
+
+#ifdef SDIRENT
+#define DIRENT
+#endif /* SDIRENT */
+
+#ifdef XNDIR
+#include <sys/ndir.h>
+#else /* !XNDIR */
+#ifdef NDIR
+#include <ndir.h>
+#else /* !NDIR, !XNDIR */
+#ifdef RTU
+#include "/usr/lib/ndir.h"
+#else /* !RTU, !NDIR, !XNDIR */
+#ifdef DIRENT
+#ifdef SDIRENT
+#include <sys/dirent.h>
+#else
+#include <dirent.h>
+#endif /* SDIRENT */
+#else
+#include <sys/dir.h>
+#endif /* DIRENT */
+#endif /* RTU */
+#endif /* NDIR */
+#endif /* XNDIR */
+
+#ifdef UNIX /* Pointer arg to wait() allowed */
+#define CK_CHILD /* Assume this is safe in all UNIX */
+#endif /* UNIX */
+
+extern int binary, recursive, stathack;
+#ifdef CK_CTRLZ
+extern int eofmethod;
+#endif /* CK_CTRLZ */
+
+#include <pwd.h> /* Password file for shell name */
+#ifdef CK_SRP
+#include <t_pwd.h> /* SRP Password file */
+#endif /* CK_SRP */
+
+#ifdef HPUX10_TRUSTED
+#include <hpsecurity.h>
+#include <prot.h>
+#endif /* HPUX10_TRUSTED */
+
+#ifdef COMMENT
+/* Moved to ckcdeb.h */
+#ifdef POSIX
+#define UTIMEH
+#else
+#ifdef HPUX9
+#define UTIMEH
+#endif /* HPUX9 */
+#endif /* POSIX */
+#endif /* COMMENT */
+
+#ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
+#include <sys/utime.h> /* for extra fields required by */
+#else /* 88Open spec. */
+#ifdef UTIMEH /* or <utime.h> if requested */
+#include <utime.h> /* (SVR4, POSIX) */
+#ifndef BSD44
+#ifndef V7
+/* Not sure why this is here. What it implies is that the code bracketed
+ by SYSUTIMEH is valid on all platforms on which we support time
+ functionality. But we know that is not true because the BSD44 and V7
+ platforms do not support sys/utime.h and the data structures which
+ are defined in them. Now this worked before because prior to today's
+ changes the UTIMEH definition for BSD44 and V7 did not take place
+ until after SYSUTIMEH was defined. It also would not have been a
+ problem if the ordering of all the time blocks was consistent. All but
+ one of the blocks were BSD44, V7, SYSUTIMEH, <OTHER>. That one case
+ is where this problem was triggered.
+*/
+#define SYSUTIMEH /* Use this for both cases. */
+#endif /* V7 */
+#endif /* BSD44 */
+#endif /* UTIMEH */
+#endif /* SYSUTIMEH */
+
+#ifndef NOTIMESTAMP
+#ifdef POSIX
+#ifndef AS400
+#define TIMESTAMP
+#endif /* AS400 */
+#endif /* POSIX */
+
+#ifdef BSD44 /* BSD 4.4 */
+#ifndef TIMESTAMP
+#define TIMESTAMP /* Can do file dates */
+#endif /* TIMESTAMP */
+#include <sys/time.h>
+#include <sys/timeb.h>
+
+#else /* Not BSD44 */
+
+#ifdef BSD4 /* BSD 4.3 and below */
+#define TIMESTAMP /* Can do file dates */
+#include <time.h> /* Need this */
+#include <sys/timeb.h> /* Need this if really BSD */
+
+#else /* Not BSD 4.3 and below */
+
+#ifdef SVORPOSIX /* System V or POSIX */
+#ifndef TIMESTAMP
+#define TIMESTAMP
+#endif /* TIMESTAMP */
+#include <time.h>
+
+/* void tzset(); (the "void" type upsets some compilers) */
+#ifndef IRIX60
+#ifndef ultrix
+#ifndef CONVEX9
+/* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
+#ifndef Plan9
+extern long timezone;
+#endif /* Plan9 */
+#endif /* CONVEX9 */
+#endif /* ultrix */
+#endif /* IRIX60 */
+#endif /* SVORPOSIX */
+#endif /* BSD4 */
+#endif /* BSD44 */
+
+#ifdef COHERENT
+#include <time.h>
+#endif /* COHERENT */
+
+/* Is `y' a leap year? */
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from 1970 to `y' (not including `y' itself). */
+#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+
+#endif /* NOTIMESTAMP */
+
+#ifdef CIE
+#include <stat.h> /* File status */
+#else
+#include <sys/stat.h>
+#endif /* CIE */
+
+
+
+/* Macro to alleviate isdir() calls internal to this module */
+
+static struct stat STATBUF;
+#define xisdir(a) ((stat(a,&STATBUF)==-1)?0:(S_ISDIR(STATBUF.st_mode)?1:0))
+
+extern char uidbuf[];
+extern int xferlog;
+extern char * xferfile;
+int iklogopen = 0;
+static time_t timenow;
+
+#define IKSDMSGLEN CKMAXPATH+512
+
+static char iksdmsg[IKSDMSGLEN];
+
+extern int local;
+
+extern int server, en_mkd, en_cwd, en_del;
+
+/*
+ Functions (n is one of the predefined file numbers from ckcker.h):
+
+ zopeni(n,name) -- Opens an existing file for input.
+ zopeno(n,name,attr,fcb) -- Opens a new file for output.
+ zclose(n) -- Closes a file.
+ zchin(n,&c) -- Gets the next character from an input file.
+ zsinl(n,&s,x) -- Read a line from file n, max len x, into address s.
+ zsout(n,s) -- Write a null-terminated string to output file, buffered.
+ zsoutl(n,s) -- Like zsout, but appends a line terminator.
+ zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
+ zchout(n,c) -- Add a character to an output file, unbuffered.
+ zchki(name) -- Check if named file exists and is readable, return size.
+ zchko(name) -- Check if named file can be created.
+ zchkspa(name,n) -- Check if n bytes available to create new file, name.
+ znewn(name,s) -- Make a new unique file name based on the given name.
+ zdelet(name) -- Delete the named file.
+ zxpand(string) -- Expands the given wildcard string into a list of files.
+ znext(string) -- Returns the next file from the list in "string".
+ zxrewind() -- Rewind zxpand list.
+ zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
+ zclosf() -- Close input file associated with zxcmd()'s lower fork.
+ zrtol(n1,n2) -- Convert remote filename into local form.
+ zltor(n1,n2) -- Convert local filename into remote form.
+ zchdir(dirnam) -- Change working directory.
+ zhome() -- Return pointer to home directory name string.
+ zkself() -- Kill self, log out own job.
+ zsattr(struct zattr *) -- Return attributes for file which is being sent.
+ zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
+ zrename(old, new) -- Rename a file.
+ zcopy(source,destination) -- Copy a file.
+ zmkdir(path) -- Create the directory path if possible
+ zfnqfp(fname,len,fullpath) - Determine full path for file name.
+ zgetfs(name) -- return file size regardless of accessibility
+ zchkpid(pid) -- tell if PID is valid and active
+*/
+
+/* Kermit-specific includes */
+/*
+ Definitions here supersede those from system include files.
+ ckcdeb.h is included above.
+*/
+#include "ckcker.h" /* Kermit definitions */
+#include "ckucmd.h" /* For keyword tables */
+#include "ckuver.h" /* Version herald */
+
+char *ckzsys = HERALD;
+
+/*
+ File access checking ... There are two calls to access() in this module.
+ If this program is installed setuid or setgid on a Berkeley-based UNIX
+ system that does NOT incorporate the saved-original-effective-uid/gid
+ feature, then, when we have swapped the effective and original uid/gid,
+ access() fails because it uses what it thinks are the REAL ids, but we have
+ swapped them. This occurs on systems where ANYBSD is defined, NOSETREU
+ is NOT defined, and SAVEDUID is NOT defined. So, in theory, we should take
+ care of this situation like so:
+
+ ifdef ANYBSD
+ ifndef NOSETREU
+ ifndef SAVEDUID
+ define SW_ACC_ID
+ endif
+ endif
+ endif
+
+ But we can't test such a general scheme everywhere, so let's only do this
+ when we know we have to...
+*/
+#ifdef NEXT /* NeXTSTEP 1.0-3.0 */
+#define SW_ACC_ID
+#endif /* NEXT */
+
+/* Support for tilde-expansion in file and directory names */
+
+#ifdef POSIX
+#define NAMEENV "LOGNAME"
+#else
+#ifdef BSD4
+#define NAMEENV "USER"
+#else
+#ifdef ATTSV
+#define NAMEENV "LOGNAME"
+#endif /* ATTSV */
+#endif /* BSD4 */
+#endif /* POSIX */
+
+/* Berkeley Unix Version 4.x */
+/* 4.1bsd support from Charles E Brooks, EDN-VAX */
+
+#ifdef BSD4
+#ifdef MAXNAMLEN
+#define BSD42
+#endif /* MAXNAMLEN */
+#endif /* BSD4 */
+
+/* Definitions of some system commands */
+
+char *DELCMD = "rm -f "; /* For file deletion */
+char *CPYCMD = "cp "; /* For file copy */
+char *RENCMD = "mv "; /* For file rename */
+char *PWDCMD = "pwd "; /* For saying where I am */
+
+#ifdef COMMENT
+#ifdef HPUX10
+char *DIRCMD = "/usr/bin/ls -l "; /* For directory listing */
+char *DIRCM2 = "/usr/bin/ls -l "; /* For directory listing, no args */
+#else
+char *DIRCMD = "/bin/ls -l "; /* For directory listing */
+char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */
+#endif /* HPUX10 */
+#else
+char *DIRCMD = "ls -l "; /* For directory listing */
+char *DIRCM2 = "ls -l "; /* For directory listing, no args */
+#endif /* COMMENT */
+
+char *TYPCMD = "cat "; /* For typing a file */
+
+#ifdef HPUX
+char *MAILCMD = "mailx"; /* For sending mail */
+#else
+#ifdef DGUX540
+char *MAILCMD = "mailx";
+#else
+#ifdef UNIX
+#ifdef CK_MAILCMD
+char *MAILCMD = CK_MAILCMD; /* CFLAGS override */
+#else
+char *MAILCMD = "Mail"; /* Default */
+#endif /* CK_MAILCMD */
+#else
+char *MAILCMD = "";
+#endif /* UNIX */
+#endif /* HPUX */
+#endif /* DGUX40 */
+
+#ifdef UNIX
+#ifdef ANYBSD /* BSD uses lpr to spool */
+#ifdef DGUX540 /* And DG/UX */
+char * PRINTCMD = "lp";
+#else
+char * PRINTCMD = "lpr";
+#endif /* DGUX540 */
+#else /* Sys V uses lp */
+#ifdef TRS16 /* except for Tandy-16/6000... */
+char * PRINTCMD = "lpr";
+#else
+char * PRINTCMD = "lp";
+#endif /* TRS16 */
+#endif /* ANYBSD */
+#else /* Not UNIX */
+#define PRINTCMD ""
+#endif /* UNIX */
+
+#ifdef FT18 /* Fortune For:Pro 1.8 */
+#undef BSD4
+#endif /* FT18 */
+
+#ifdef BSD4
+char *SPACMD = "pwd ; df ."; /* Space in current directory */
+#else
+#ifdef FT18
+char *SPACMD = "pwd ; du ; df .";
+#else
+char *SPACMD = "df ";
+#endif /* FT18 */
+#endif /* BSD4 */
+
+char *SPACM2 = "df "; /* For space in specified directory */
+
+#ifdef FT18
+#define BSD4
+#endif /* FT18 */
+
+#ifdef BSD4
+char *WHOCMD = "finger ";
+#else
+char *WHOCMD = "who ";
+#endif /* BSD4 */
+
+/* More system-dependent includes, which depend on symbols defined */
+/* in the Kermit-specific includes. Oh what a tangled web we weave... */
+
+#ifdef COHERENT /* <sys/file.h> */
+#define NOFILEH
+#endif /* COHERENT */
+
+#ifdef MINIX
+#define NOFILEH
+#endif /* MINIX */
+
+#ifdef aegis
+#define NOFILEH
+#endif /* aegis */
+
+#ifdef unos
+#define NOFILEH
+#endif /* unos */
+
+#ifndef NOFILEH
+#include <sys/file.h>
+#endif /* NOFILEH */
+
+#ifndef is68k /* Whether to include <fcntl.h> */
+#ifndef BSD41 /* All but a couple UNIXes have it. */
+#ifndef FT18
+#ifndef COHERENT
+#include <fcntl.h>
+#endif /* COHERENT */
+#endif /* FT18 */
+#endif /* BSD41 */
+#endif /* is68k */
+
+#ifdef COHERENT
+#ifdef _I386
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#endif /* _I386 */
+#endif /* COHERENT */
+
+extern int inserver; /* I am IKSD */
+int guest = 0; /* Anonymous user */
+
+#ifdef IKSD
+extern int isguest;
+extern char * anonroot;
+#endif /* IKSD */
+
+#ifdef CK_LOGIN
+#define GUESTPASS 256
+static char guestpass[GUESTPASS] = { NUL, NUL }; /* Anonymous "password" */
+static int logged_in = 0; /* Set when user is logged in */
+static int askpasswd = 0; /* Have OK user, must ask for passwd */
+#ifdef CK_PAM
+extern int gotemptypasswd;
+#endif /* CK_PAM */
+#endif /* CK_LOGIN */
+
+#ifdef CKROOT
+static char ckroot[CKMAXPATH+1] = { NUL, NUL };
+static int ckrootset = 0;
+int ckrooterr = 0;
+#endif /* CKROOT */
+
+_PROTOTYP( VOID ignorsigs, (void) );
+_PROTOTYP( VOID restorsigs, (void) );
+#ifdef SELECT
+_PROTOTYP( int ttwait, (int, int) ); /* ckutio.c */
+#endif /* SELECT */
+
+/*
+ Change argument to "(const char *)" if this causes trouble.
+ Or... if it causes trouble, then maybe it was already declared
+ in a header file after all, so you can remove this prototype.
+*/
+#ifndef NDGPWNAM /* If not defined No Declare getpwnam... */
+#ifndef _POSIX_SOURCE
+#ifndef NEXT
+#ifndef SVR4
+/* POSIX <pwd.h> already gave prototypes for these. */
+#ifdef IRIX40
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef IRIX51
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef M_UNIX
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef HPUX9
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef HPUX10
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef DCGPWNAM
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+_PROTOTYP( struct passwd * getpwnam, (char *) );
+#endif /* DCGPWNAM */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* M_UNIX */
+#endif /* IRIX51 */
+#endif /* IRIX40 */
+#ifndef SUNOS4
+#ifndef HPUX9
+#ifndef HPUX10
+#ifndef _SCO_DS
+_PROTOTYP( struct passwd * getpwuid, (PWID_T) );
+#endif /* _SCO_DS */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* SUNOS4 */
+_PROTOTYP( struct passwd * getpwent, (void) );
+#endif /* SVR4 */
+#endif /* NEXT */
+#endif /* _POSIX_SOURCE */
+#endif /* NDGPWNAM */
+
+#ifdef CK_SHADOW /* Shadow Passwords... */
+#include <shadow.h>
+#endif /* CK_SHADOW */
+#ifdef CK_PAM /* PAM... */
+#ifdef MACOSX
+#include <pam/pam_appl.h>
+#else /* MACOSX */
+#include <security/pam_appl.h>
+#endif /* MACOSX */
+#ifndef PAM_SERVICE_TYPE /* Defines which PAM service we are */
+#define PAM_SERVICE_TYPE "kermit"
+#endif /* PAM_SERVICE_TYPE */
+
+#ifdef SOLARIS
+#define PAM_CONST
+#else /* SOLARIS */
+#define PAM_CONST CONST
+#endif
+
+static char * pam_pw = NULL;
+
+int
+#ifdef CK_ANSIC
+pam_cb(int num_msg,
+ PAM_CONST struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr
+ )
+#else /* CK_ANSIC */
+pam_cb(num_msg, msg, resp, appdata_ptr)
+ int num_msg;
+ PAM_CONST struct pam_message **msg;
+ struct pam_response **resp;
+ void *appdata_ptr;
+#endif /* CK_ANSIC */
+{
+ int i;
+
+ debug(F111,"pam_cb","num_msg",num_msg);
+
+ for (i = 0; i < num_msg; i++) {
+ char message[PAM_MAX_MSG_SIZE];
+
+ /* Issue prompt and get response */
+ debug(F111,"pam_cb","Message",i);
+ debug(F111,"pam_cb",msg[i]->msg,msg[i]->msg_style);
+ if (msg[i]->msg_style == PAM_ERROR_MSG) {
+ debug(F111,"pam_cb","PAM ERROR",0);
+ fprintf(stdout,"%s\n", msg[i]->msg);
+ return(0);
+ } else if (msg[i]->msg_style == PAM_TEXT_INFO) {
+ debug(F111,"pam_cb","PAM TEXT INFO",0);
+ fprintf(stdout,"%s\n", msg[i]->msg);
+ return(0);
+ } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) {
+ debug(F111,"pam_cb","Reading response, no echo",0);
+ /* Ugly hack. We check to see if a password has been pushed */
+ /* into zvpasswd(). This would be true if the password was */
+ /* received by REMOTE LOGIN. */
+ if (pam_pw) {
+ ckstrncpy(message,pam_pw,PAM_MAX_MSG_SIZE);
+ } else
+ readpass((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE);
+ } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
+ debug(F111,"pam_cb","Reading response, with echo",0);
+ readtext((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE);
+ } else {
+ debug(F111,"pam_cb","unknown style",0);
+ return(0);
+ }
+
+ /* Allocate space for this message's response structure */
+ resp[i] = (struct pam_response *) malloc(sizeof (struct pam_response));
+ if (!resp[i]) {
+ int j;
+ debug(F110,"pam_cb","malloc failure",0);
+ for (j = 0; j < i; j++) {
+ free(resp[j]->resp);
+ free(resp[j]);
+ }
+ return(0);
+ }
+
+ /* Allocate a buffer for the response */
+ resp[i]->resp = (char *) malloc((int)strlen(message) + 1);
+ if (!resp[i]->resp) {
+ int j;
+ debug(F110,"pam_cb","malloc failure",0);
+ for (j = 0; j < i; j++) {
+ free(resp[j]->resp);
+ free(resp[j]);
+ }
+ free(resp[i]);
+ return(0);
+ }
+ /* Return the results back to PAM */
+ strcpy(resp[i]->resp, message); /* safe (prechecked) */
+ resp[i]->resp_retcode = 0;
+ }
+ debug(F110,"pam_cb","Exiting",0);
+ return(0);
+}
+#endif /* CK_PAM */
+
+/* Define macros for getting file type */
+
+#ifdef OXOS
+/*
+ Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
+ incorrectly, so we force their redefinition.
+*/
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* OXOS */
+
+#ifdef UTSV /* Same deal for Amdahl UTSV */
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* UTSV */
+
+#ifdef UNISYS52 /* And for UNISYS UTS V 5.2 */
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* UNISYS52 */
+
+#ifdef ICLSVR3 /* And for old ICL versions */
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* ICLSVR3 */
+
+#ifdef ISDIRBUG /* Also allow this from command line */
+#ifdef S_ISREG
+#undef S_ISREG
+#endif /* S_ISREG */
+#ifdef S_ISDIR
+#undef S_ISDIR
+#endif /* S_ISDIR */
+#endif /* ISDIRBUG */
+
+#ifndef _IFMT
+#ifdef S_IFMT
+#define _IFMT S_IFMT
+#else
+#define _IFMT 0170000
+#endif /* S_IFMT */
+#endif /* _IFMT */
+
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif /* S_ISREG */
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif /* S_ISDIR */
+
+/* The following mainly for NeXTSTEP... */
+
+#ifndef S_IWUSR
+#define S_IWUSR 0000200
+#endif /* S_IWUSR */
+
+#ifndef S_IRGRP
+#define S_IRGRP 0000040
+#endif /* S_IRGRP */
+
+#ifndef S_IWGRP
+#define S_IWGRP 0000020
+#endif /* S_IWGRP */
+
+#ifndef S_IXGRP
+#define S_IXGRP 0000010
+#endif /* S_IXGRP */
+
+#ifndef S_IROTH
+#define S_IROTH 0000004
+#endif /* S_IROTH */
+
+#ifndef S_IWOTH
+#define S_IWOTH 0000002
+#endif /* S_IWOTH */
+
+#ifndef S_IXOTH
+#define S_IXOTH 0000001
+#endif /* S_IXOTH */
+/*
+ Define maximum length for a file name if not already defined.
+ NOTE: This applies to a path segment (directory or file name),
+ not the entire path string, which can be CKMAXPATH bytes long.
+*/
+#ifdef QNX
+#ifdef _MAX_FNAME
+#define MAXNAMLEN _MAX_FNAME
+#else
+#define MAXNAMLEN 48
+#endif /* _MAX_FNAME */
+#else
+#ifndef MAXNAMLEN
+#ifdef sun
+#define MAXNAMLEN 255
+#else
+#ifdef FILENAME_MAX
+#define MAXNAMLEN FILENAME_MAX
+#else
+#ifdef NAME_MAX
+#define MAXNAMLEN NAME_MAX
+#else
+#ifdef _POSIX_NAME_MAX
+#define MAXNAMLEN _POSIX_NAME_MAX
+#else
+#ifdef _D_NAME_MAX
+#define MAXNAMLEN _D_NAME_MAX
+#else
+#ifdef DIRSIZ
+#define MAXNAMLEN DIRSIZ
+#else
+#define MAXNAMLEN 14
+#endif /* DIRSIZ */
+#endif /* _D_NAME_MAX */
+#endif /* _POSIX_NAME_MAX */
+#endif /* NAME_MAX */
+#endif /* FILENAME_MAX */
+#endif /* sun */
+#endif /* MAXNAMLEN */
+#endif /* QNX */
+
+#ifdef COMMENT
+/* As of 2001-11-03 this is handled in ckcdeb.h */
+/* Longest pathname ... */
+/*
+ Beware: MAXPATHLEN is one of UNIX's dirty little secrets. Where is it
+ defined? Who knows... <param.h>, <mod.h>, <unistd.h>, <limits.h>, ...
+ There is not necessarily even a definition for it anywhere, or it might have
+ another name. If you get it wrong, bad things happen with getcwd() and/or
+ getwd(). If you allocate a buffer that is too short, getwd() might write
+ over memory and getcwd() will fail with ERANGE. The definitions of these
+ functions (e.g. in SVID or POSIX.1) do not tell you how to determine the
+ maximum path length in order to allocate a buffer that is the right size.
+*/
+#ifdef BSD44
+#include <sys/param.h> /* For MAXPATHLEN */
+#endif /* BSD44 */
+#ifdef COHERENT
+#include <sys/param.h> /* for MAXPATHLEN, needed for -DDIRENT */
+#endif /* COHERENT */
+#endif /* COMMENT */
+
+#ifdef MAXPATHLEN
+#ifdef MAXPATH
+#undef MAXPATH
+#endif /* MAXPATH */
+#define MAXPATH MAXPATHLEN
+#else
+#ifdef PATH_MAX
+#define MAXPATH PATH_MAX
+#else
+#ifdef _POSIX_PATH_MAX
+#define MAXPATH _POSIX_PATH_MAX
+#else
+#ifdef BSD42
+#define MAXPATH 1024
+#else
+#ifdef SVR4
+#define MAXPATH 1024
+#else
+#define MAXPATH 255
+#endif /* SVR4 */
+#endif /* BSD42 */
+#endif /* _POSIX_PATH_MAX */
+#endif /* PATH_MAX */
+#endif /* MAXPATHLEN */
+
+/* Maximum number of filenames for wildcard expansion */
+
+#ifndef MAXWLD
+/* Already defined in ckcdeb.h so the following is superfluous. */
+/* Don't expect changing them to have any effect. */
+#ifdef CK_SMALL
+#define MAXWLD 50
+#else
+#ifdef BIGBUFOK
+#define MAXWLD 102400
+#else
+#define MAXWLD 8192
+#endif /* BIGBUFOK */
+#endif /* CK_SMALL */
+#endif /* MAXWLD */
+
+static int maxnames = MAXWLD;
+
+/* Define the size of the string space for filename expansion. */
+
+#ifndef DYNAMIC
+#ifdef PROVX1
+#define SSPACE 500
+#else
+#ifdef BSD29
+#define SSPACE 500
+#else
+#ifdef pdp11
+#define SSPACE 500
+#else
+#ifdef aegis
+#define SSPACE 10000 /* Size of string-generating buffer */
+#else /* Default static buffer size */
+#ifdef BIGBUFOK
+#define SSPACE 65000 /* Size of string-generating buffer */
+#else
+#define SSPACE 2000 /* size of string-generating buffer */
+#endif /* BIGBUFOK */
+#endif /* aegis */
+#endif /* pdp11 */
+#endif /* BSD29 */
+#endif /* PROVX1 */
+static char sspace[SSPACE]; /* Buffer for generating filenames */
+#else /* is DYNAMIC */
+#ifdef CK_64BIT
+#define SSPACE 2000000000 /* Two billion bytes */
+#else
+#ifdef BIGBUFOK
+#define SSPACE 10000000 /* Ten million */
+#else
+#define SSPACE 10000 /* Ten thousand */
+#endif /* BIGBUFOK */
+#endif /* CK_64BIT */
+char *sspace = (char *)0;
+#endif /* DYNAMIC */
+static int ssplen = SSPACE; /* Length of string space buffer */
+
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * popen, (char *, char *) );
+#endif /* DCLPOPEN */
+
+extern int nopush;
+
+/* More internal function prototypes */
+/*
+ * The path structure is used to represent the name to match.
+ * Each slash-separated segment of the name is kept in one
+ * such structure, and they are linked together, to make
+ * traversing the name easier.
+ */
+struct path {
+ char npart[MAXNAMLEN+4]; /* name part of path segment */
+ struct path *fwd; /* forward ptr */
+};
+#ifndef NOPUSH
+_PROTOTYP( int shxpand, (char *, char *[], int ) );
+#endif /* NOPUSH */
+_PROTOTYP( static int fgen, (char *, char *[], int ) );
+_PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
+_PROTOTYP( static VOID addresult, (char *, int) );
+#ifdef COMMENT
+/* Replaced by ckmatch() */
+_PROTOTYP( static int match, (char *, char *) );
+#endif /* COMMENT */
+_PROTOTYP( char * whoami, (void) );
+_PROTOTYP( UID_T real_uid, (void) );
+_PROTOTYP( static struct path *splitpath, (char *p) );
+_PROTOTYP( char * zdtstr, (time_t) );
+_PROTOTYP( time_t zstrdt, (char *, int) );
+
+/* Some systems define these symbols in include files, others don't... */
+
+#ifndef R_OK
+#define R_OK 4 /* For access */
+#endif /* R_OK */
+
+#ifndef W_OK
+#define W_OK 2
+#endif /* W_OK */
+
+#ifndef X_OK
+#define X_OK 1
+#endif /* X_OK */
+
+#ifndef O_RDONLY
+#define O_RDONLY 000
+#endif /* O_RDONLY */
+
+/* syslog and wtmp items for Internet Kermit Service */
+
+extern char * clienthost; /* From ckcmai.c. */
+
+static char fullname[CKMAXPATH+1];
+static char tmp2[CKMAXPATH+1];
+
+extern int ckxlogging;
+
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in syslog.h */
+#endif /* CKXPRINTF */
+#ifdef CKSYSLOG
+#ifdef RTAIX
+#include <sys/syslog.h>
+#else /* RTAIX */
+#include <syslog.h>
+#endif /* RTAIX */
+#endif /* CKSYSLOG */
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+
+int ckxanon = 1; /* Anonymous login ok */
+int ckxperms = 0040; /* Anonymous file permissions */
+int ckxpriv = 1; /* Priv'd login ok */
+
+#ifndef XFERFILE
+#define XFERFILE "/var/log/iksd.log"
+#endif /* XFERFILE */
+
+/* wtmp logging for IKSD... */
+
+#ifndef CKWTMP /* wtmp logging not selected */
+int ckxwtmp = 0; /* Know this at runtime */
+#else /* wtmp file details */
+int ckxwtmp = 1;
+#ifdef UTMPBUG /* Unfortunately... */
+/*
+ Some versions of Linux have a <utmp.h> file that contains
+ "enum utlogin { local, telnet, rlogin, screen, ... };" This clobbers
+ any program that uses any of these words as variable names, function
+ names, macro names, etc. (Other versions of Linux have this declaration
+ within #if 0 ... #endif.) There is nothing we can do about this other
+ than to not include the stupid file. But we need stuff from it, so...
+*/
+#include <features.h>
+#include <sys/types.h>
+#define UT_LINESIZE 32
+#define UT_NAMESIZE 32
+#define UT_HOSTSIZE 256
+
+struct timeval {
+ time_t tv_sec;
+ time_t tv_usec;
+};
+
+struct exit_status {
+ short int e_termination; /* Process termination status. */
+ short int e_exit; /* Process exit status. */
+};
+
+struct utmp {
+ short int ut_type; /* Type of login */
+ pid_t ut_pid; /* Pid of login process */
+ char ut_line[UT_LINESIZE]; /* NUL-terminated devicename of tty */
+ char ut_id[4]; /* Inittab id */
+ char ut_user[UT_NAMESIZE]; /* Username (not NUL terminated) */
+
+ char ut_host[UT_HOSTSIZE]; /* Hostname for remote login */
+ struct exit_status ut_exit; /* Exit status */
+ long ut_session; /* Session ID, used for windowing */
+ struct timeval ut_tv; /* Time entry was made */
+ int32_t ut_addr_v6[4]; /* Internet address of remote host */
+ char pad[20]; /* Reserved */
+};
+
+#define ut_time ut_tv.tv_sec /* Why should Linux be like anything else? */
+#define ut_name ut_user /* ... */
+
+extern void
+logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
+ __const char *__ut_host));
+
+#else /* Not UTMPBUG */
+
+#ifndef HAVEUTMPX /* Who has <utmpx.h> */
+#ifdef SOLARIS
+#define HAVEUTMPX
+#else
+#ifdef IRIX60
+#define HAVEUTMPX
+#else
+#ifdef CK_SCOV5
+#define HAVEUTMPX
+#else
+#ifdef HPUX100
+#define HAVEUTMPX
+#else
+#ifdef UNIXWARE
+#define HAVEUTMPX
+#endif /* UNIXWARE */
+#endif /* HPUX100 */
+#endif /* CK_SCOV5 */
+#endif /* IRIX60 */
+#endif /* SOLARIS */
+#endif /* HAVEUTMPX */
+
+#ifdef HAVEUTMPX
+#include <utmpx.h>
+#else
+#ifdef OSF50
+/* Because the time_t in the utmp struct is 64 bits but time() wants 32 */
+#define __V40_OBJ_COMPAT 1
+#endif /* OSF50 */
+#include <utmp.h>
+#ifdef OSF50
+#undef __V40_OBJ_COMPAT
+#endif /* OSF50 */
+#endif /* HAVEUTMPX */
+#endif /* UTMPBUG */
+
+#ifdef HAVEUTMPX
+#define UTMPSTRUCT utmpx
+#else
+#define UTMPSTRUCT utmp
+#endif /* HAVEUTMPX */
+
+#ifndef WTMPFILE
+#ifdef QNX
+#define WTMPFILE "/usr/adm/wtmp.1"
+#else
+#ifdef LINUX
+#define WTMPFILE "/var/log/wtmp"
+#else
+#define WTMPFILE "/usr/adm/wtmp"
+#endif /* QNX */
+#endif /* LINUX */
+#endif /* WTMPFILE */
+char * wtmpfile = NULL;
+
+static int wtmpfd = 0;
+static char cksysline[32] = { NUL, NUL };
+
+#ifndef HAVEUTHOST /* Does utmp include ut_host[]? */
+#ifdef HAVEUTMPX /* utmpx always does */
+#define HAVEUTHOST
+#else
+#ifdef LINUX /* Linux does */
+#define HAVEUTHOST
+#else
+#ifdef SUNOS4 /* SunOS does */
+#define HAVEUTHOST
+#else
+#ifdef AIX41 /* AIX 4.1 and later do */
+#define HAVEUTHOST
+#endif /* AIX41 */
+#endif /* SUNOS4 */
+#endif /* LINUX */
+#endif /* HAVEUTMPX */
+#endif /* HAVEUTHOST */
+
+#ifdef UW200
+PID_T _vfork() { /* To satisfy a library foulup */
+ return(fork()); /* in Unixware 2.0.x */
+}
+#endif /* UW200 */
+
+VOID
+#ifdef CK_ANSIC
+logwtmp(const char * line, const char * name, const char * host)
+#else
+logwtmp(line, name, host) char *line, *name, *host;
+#endif /* CK_ANSIC */
+/* logwtmp */ {
+ struct UTMPSTRUCT ut;
+ struct stat buf;
+ /* time_t time(); */
+
+ if (!ckxwtmp)
+ return;
+
+ if (!wtmpfile)
+ makestr(&wtmpfile,WTMPFILE);
+
+ if (!line) line = "";
+ if (!name) name = "";
+ if (!host) host = "";
+
+ if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) {
+ ckxwtmp = 0;
+ debug(F110,"WTMP open failed",line,0);
+ return;
+ }
+ if (!fstat(wtmpfd, &buf)) {
+ ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
+#ifdef FREEBSD9
+ ckstrncpy(ut.ut_user, name, sizeof(ut.ut_user));
+#else
+ ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
+#endif /* FREEBSD9 */
+#ifdef HAVEUTHOST
+ /* Not portable */
+ ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif /* HAVEUTHOST */
+#ifdef HAVEUTMPX
+ time(&ut.ut_tv.tv_sec);
+#else
+#ifdef LINUX
+/* In light of the following comment perhaps the previous line should */
+/* be "#ifndef COMMENT". */
+ {
+ /*
+ * On 64-bit platforms sizeof(time_t) and sizeof(ut.ut_time)
+ * are not the same and attempt to use an address of
+ * ut.ut_time as an argument to time() call may cause
+ * "unaligned access" trap.
+ */
+ time_t zz;
+ time(&zz);
+ ut.ut_time = zz;
+ }
+#else
+#ifdef CK_64BIT
+ {
+ /* Now (Jan 2006) we can do this for any 64-bit build */
+ time_t zz;
+ time(&zz);
+ ut.ut_time = zz;
+ }
+#else
+ time(&ut.ut_time);
+#endif /* CK_64BIT */
+#endif /* LINUX */
+#endif /* HAVEUTMPX */
+ if (write(wtmpfd, (char *)&ut, sizeof(struct UTMPSTRUCT)) !=
+ sizeof(struct UTMPSTRUCT)) {
+#ifndef NOFTRUNCATE
+#ifndef COHERENT
+ ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */
+#else
+ chsize(wtmpfd, buf.st_size); /* Error, undo any partial write */
+#endif /* COHERENT */
+#endif /* NOFTRUNCATE */
+ debug(F110,"WTMP write error",line,0);
+ } else {
+ debug(F110,"WTMP record OK",line,0);
+ return;
+ }
+ }
+}
+#endif /* CKWTMP */
+
+#ifdef CKSYSLOG
+/*
+ C K S Y S L O G -- C-Kermit system logging function,
+
+ For use by other modules.
+ This module can, but doesn't have to, use it.
+ Call with:
+ n = SYSLG_xx values defined in ckcdeb.h
+ s1, s2, s3: strings.
+*/
+VOID
+cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; {
+ int level;
+
+ if (!ckxlogging) /* syslogging */
+ return;
+ if (!s1) s1 = ""; /* Fix null args */
+ if (!s2) s2 = "";
+ if (!s3) s3 = "";
+ switch (n) { /* Translate Kermit level */
+ case SYSLG_DB: /* to syslog level */
+ level = LOG_DEBUG;
+ break;
+ default:
+ level = m ? LOG_INFO : LOG_ERR;
+ }
+ debug(F110,"cksyslog s1",s1,0);
+ debug(F110,"cksyslog s2",s2,0);
+ debug(F110,"cksyslog s3",s3,0);
+ errno = 0;
+ syslog(level, "%s: %s %s", s1, s2, s3); /* Write syslog record */
+ debug(F101,"cksyslog errno","",errno);
+}
+#endif /* CKSYSLOG */
+
+
+/* Declarations */
+
+int maxnam = MAXNAMLEN; /* Available to the outside */
+int maxpath = MAXPATH;
+int ck_znewn = -1;
+
+#ifdef UNIX
+char startupdir[MAXPATH+1];
+#endif /* UNIX */
+
+int pexitstat = -2; /* Process exit status */
+
+FILE *fp[ZNFILS] = { /* File pointers */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* Flags for each file indicating whether it was opened with popen() */
+int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* Buffers and pointers used in buffered file input and output. */
+#ifdef DYNAMIC
+extern char *zinbuffer, *zoutbuffer;
+#else
+extern char zinbuffer[], zoutbuffer[];
+#endif /* DYNAMIC */
+extern char *zinptr, *zoutptr;
+extern int zincnt, zoutcnt;
+extern int wildxpand, wildena; /* Wildcard handling */
+
+static CK_OFF_T iflen = (CK_OFF_T)-1; /* Input file length */
+
+static PID_T pid = 0; /* pid of child fork */
+static int fcount = 0; /* Number of files in wild group */
+static int nxpand = 0; /* Copy of fcount */
+static char nambuf[CKMAXPATH+4]; /* Buffer for a pathname */
+
+#ifndef NOFRILLS
+#define ZMBUFLEN 200
+static char zmbuf[ZMBUFLEN]; /* For mail, remote print strings */
+#endif /* NOFRILLS */
+
+char **mtchs = NULL; /* Matches found for filename */
+char **mtchptr = NULL; /* Pointer to current match */
+
+/* Z K S E L F -- Kill Self: log out own job, if possible. */
+
+/* Note, should get current pid, but if your system doesn't have */
+/* getppid(), then just kill(0,9)... */
+
+#ifndef SVR3
+#ifndef POSIX
+#ifndef OSFPC
+/* Already declared in unistd.h for SVR3 and POSIX */
+#ifdef CK_ANSIC
+extern PID_T getppid(void);
+#else
+#ifndef PS2AIX10
+#ifndef COHERENT
+extern PID_T getppid();
+#endif /* COHERENT */
+#endif /* PS2AIX10 */
+#endif /* CK_ANSIC */
+#endif /* OSFPC */
+#endif /* POSIX */
+#endif /* SVR3 */
+
+int
+zkself() { /* For "bye", but no guarantee! */
+#ifdef PROVX1
+ return(kill(0,9));
+#else
+#ifdef V7
+ return(kill(0,9));
+#else
+#ifdef TOWER1
+ return(kill(0,9));
+#else
+#ifdef FT18
+ return(kill(0,9));
+#else
+#ifdef aegis
+ return(kill(0,9));
+#else
+#ifdef COHERENT
+ return(kill((PID_T)getpid(),1));
+#else
+#ifdef PID_T
+ exit(kill((PID_T)getppid(),1));
+ return(0);
+#else
+ exit(kill(getppid(),1));
+ return(0);
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+}
+
+static VOID
+getfullname(name) char * name; {
+ char *p = (char *)fullname;
+ int len = 0;
+ fullname[0] = '\0';
+ /* If necessary we could also chase down symlinks here... */
+#ifdef COMMENT
+ /* This works but is incompatible with wuftpd */
+ if (isguest && anonroot) {
+ ckstrncpy(fullname,anonroot,CKMAXPATH);
+ len = strlen(fullname);
+ if (len > 0)
+ if (fullname[len-1] == '/')
+ len--;
+ }
+ p += len;
+#endif /* COMMENT */
+ zfnqfp(name, CKMAXPATH - len, p);
+ while (*p) {
+ if (*p < '!') *p = '_';
+ p++;
+ }
+}
+
+/* D O I K L O G -- Open Kermit-specific ftp-like transfer log. */
+
+VOID /* Called in ckcmai.c */
+doiklog() {
+ if (iklogopen) /* Already open? */
+ return;
+ if (xferlog) { /* Open iksd log if requested */
+ if (!xferfile) /* If no pathname given */
+ makestr(&xferfile,XFERFILE); /* use this default */
+ if (*xferfile) {
+ xferlog = open(xferfile, O_WRONLY | O_APPEND | O_CREAT, 0660);
+ debug(F101,"doiklog open","",xferlog);
+ if (xferlog < 0) {
+#ifdef CKSYSLOG
+ syslog(LOG_ERR, "xferlog open failure %s: %m", xferfile);
+#endif /* CKSYSLOG */
+ debug(F101,"doiklog open errno","",errno);
+ xferlog = 0;
+ } else
+ iklogopen = 1;
+ } else
+ xferlog = 0;
+#ifdef CKSYSLOG
+ if (xferlog && ckxlogging)
+ syslog(LOG_INFO, "xferlog: %s open ok", xferfile);
+#endif /* CKSYSLOG */
+ }
+}
+
+/* Z O P E N I -- Open an existing file for input. */
+
+/* Returns 1 on success, 0 on failure */
+
+int
+zopeni(n,name) int n; char *name; {
+ int x;
+
+ debug(F111,"zopeni",name,n);
+ if ((x = chkfn(n)) != 0) {
+ debug(F111,"zopeni chkfn",ckitoa(n),x);
+ return(0);
+ }
+ zincnt = 0; /* Reset input buffer */
+ if (n == ZSYSFN) { /* Input from a system function? */
+#ifdef COMMENT
+/*** Note, this function should not be called with ZSYSFN ***/
+/*** Always call zxcmd() directly, and give it the real file number ***/
+/*** you want to use. ***/
+ return(zxcmd(n,name)); /* Try to fork the command */
+#else
+ debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
+ *nambuf = '\0'; /* No filename. */
+ return(0); /* fail. */
+#endif /* COMMENT */
+ }
+ if (n == ZSTDIO) { /* Standard input? */
+ if (is_a_tty(0)) {
+ fprintf(stderr,"Terminal input not allowed");
+ debug(F110,"zopeni: attempts input from unredirected stdin","",0);
+ return(0);
+ }
+ fp[ZIFILE] = stdin;
+ ispipe[ZIFILE] = 0;
+ return(1);
+ }
+#ifdef CKROOT
+ debug(F111,"zopeni setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zopeni setroot violation",name,0);
+ return(0);
+ }
+#endif /* CKROOT */
+ fp[n] = fopen(name,"r"); /* Real file, open it. */
+ /* debug(F111,"zopeni fopen", name, fp[n]); */
+#ifdef ZDEBUG
+ /* printf("ZOPENI fp[%d]=%ld\n",n,fp[n]); */
+#endif /* ZDEBUG */
+ ispipe[n] = 0;
+
+ if (xferlog
+#ifdef CKSYSLOG
+ || ((ckxsyslog >= SYSLG_FA) && ckxlogging)
+#endif /* CKSYSLOG */
+ ) {
+ getfullname(name);
+ debug(F110,"zopeni fullname",fullname,0);
+ }
+ if (fp[n] == NULL) {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FA && ckxlogging) {
+ syslog(LOG_INFO, "file[%d] %s: open failed (%m)", n, fullname);
+ perror(fullname);
+ } else
+#endif /* CKSYSLOG */
+ perror(name);
+ return(0);
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FA && ckxlogging)
+ syslog(LOG_INFO, "file[%d] %s: open read ok", n, fullname);
+#endif /* CKSYSLOG */
+ clearerr(fp[n]);
+ return(1);
+ }
+}
+
+#ifdef QNX
+#define DONDELAY
+#else
+#ifdef O_NDELAY
+#define DONDELAY
+#endif /* O_NDELAY */
+#endif /* QNX */
+
+/* Z O P E N O -- Open a new file for output. */
+
+/*ARGSUSED*/ /* zz not used */
+int
+zopeno(n,name,zz,fcb)
+/* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; {
+
+ char p[8];
+ int append = 0;
+ int istty = 0, filefd = 0;
+
+/* As of Version 5A, the attribute structure and the file information */
+/* structure are included in the arglist. */
+
+#ifdef DEBUG
+ debug(F111,"zopeno",name,n);
+ if (fcb) {
+ debug(F101,"zopeno fcb disp","",fcb->dsp);
+ debug(F101,"zopeno fcb type","",fcb->typ);
+ debug(F101,"zopeno fcb char","",fcb->cs);
+ } else {
+ debug(F100,"zopeno fcb is NULL","",0);
+ }
+#endif /* DEBUG */
+
+ if (chkfn(n) != 0) /* Already open? */
+ return(0); /* Nothing to do. */
+
+ if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
+ fp[ZOFILE] = stdout;
+ ispipe[ZOFILE] = 0;
+#ifdef COMMENT
+ /* This seems right but it breaks client server ops */
+ fp[n] = stdout;
+ ispipe[n] = 0;
+#endif /* COMMENT */
+#ifdef COMMENT
+#ifdef DEBUG
+ if (n != ZDFILE)
+ debug(F101,"zopeno fp[n]=stdout","",fp[n]);
+#endif /* DEBUG */
+#endif /* COMMENT */
+ zoutcnt = 0;
+ zoutptr = zoutbuffer;
+ return(1);
+ }
+
+/* A real file. Open it in desired mode (create or append). */
+
+#ifdef CKROOT
+ debug(F111,"zopeno setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zopeno setroot violation",name,0);
+ return(0);
+ }
+#endif /* CKROOT */
+
+ ckstrncpy(p,"w",8); /* Assume write/create mode */
+ if (fcb) { /* If called with an FCB... */
+ if (fcb->dsp == XYFZ_A) { /* Does it say Append? */
+ ckstrncpy(p,"a",8); /* Yes. */
+ debug(F100,"zopeno append","",0);
+ append = 1;
+ }
+ }
+ if (xferlog
+#ifdef CKSYSLOG
+ || ((ckxsyslog >= SYSLG_FC) && ckxlogging)
+#endif /* CKSYSLOG */
+ ) {
+ getfullname(name);
+ debug(F110,"zopeno fullname",fullname,0);
+ }
+ {
+ /* Allow tty devices to opened as output files 2009/10/20 */
+ int fd, mode = 0;
+ debug(F110,"zopeno attempting to open",name,0);
+#ifdef O_NONBLOCK
+ mode = O_NONBLOCK;
+#else
+#ifdef O_NDELAY
+ mode = O_NDELAY;
+#else
+#ifdef FNDELAY
+ mode = FNDELAY;
+#endif /* FNDELAY */
+#endif /* O_NDELAY */
+#endif /* O_NONBLOCK */
+ debug(F111,"zopeno open mode",name,mode);
+ fd = open(name,O_WRONLY,mode);
+ debug(F111,"zopeno open",name,fd);
+ if (fd > -1) {
+ if (isatty(fd)) {
+ filefd = fd;
+ istty++;
+ }
+ }
+ }
+ debug(F111,"zopeno istty",name,istty);
+ debug(F110,"zopeno fopen arg",p,0);
+ if (istty)
+ fp[n] = fdopen(filefd,p);
+ else
+ fp[n] = fopen(name,p); /* Try to open the file */
+ ispipe[ZIFILE] = 0;
+
+#ifdef ZDEBUG
+ printf("ZOPENO fp[%d]=%ld\n",n,fp[n]);
+#endif /* ZDEBUG */
+
+ if (fp[n] == NULL) { /* Failed */
+ debug(F101,"zopeno failed errno","",errno);
+ if (istty) close(filefd);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging)
+ syslog(LOG_INFO, "file[%d] %s: %s failed (%m)",
+ n,
+ fullname,
+ append ? "append" : "create"
+ );
+#endif /* CKSYSLOG */
+#ifdef COMMENT /* Let upper levels print message. */
+ perror("Can't open output file");
+#endif /* COMMENT */
+ } else { /* Succeeded */
+ extern int zofbuffer, zofblock, zobufsize;
+ debug(F101, "zopeno zobufsize", "", zobufsize);
+ if (n == ZDFILE || n == ZTFILE) { /* If debug or transaction log */
+ setbuf(fp[n],NULL); /* make it unbuffered. */
+#ifdef DONDELAY
+ } else if (n == ZOFILE && !zofblock) { /* blocking or nonblocking */
+ int flags;
+ if ((flags = fcntl(fileno(fp[n]),F_GETFL,0)) > -1)
+ fcntl(fileno(fp[n]),F_SETFL, flags |
+#ifdef QNX
+ O_NONBLOCK
+#else
+ O_NDELAY
+#endif /* QNX */
+ );
+ debug(F100,"zopeno ZOFILE nonblocking","",0);
+#endif /* DONDELAY */
+ } else if (n == ZOFILE && !zofbuffer) { /* buffered or unbuffered */
+ setbuf(fp[n],NULL);
+ debug(F100,"zopeno ZOFILE unbuffered","",0);
+ }
+
+#ifdef CK_LOGIN
+ /* Enforce anonymous file-creation permission */
+ if (isguest)
+ if (n == ZWFILE || n == ZMFILE ||
+ n == ZOFILE || n == ZDFILE ||
+ n == ZTFILE || n == ZPFILE ||
+ n == ZSFILE)
+ chmod(name,ckxperms);
+#endif /* CK_LOGIN */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging)
+ syslog(LOG_INFO, "file[%d] %s: %s ok",
+ n,
+ fullname,
+ append ? "append" : "create"
+ );
+#endif /* CKSYSLOG */
+ debug(F100, "zopeno ok", "", 0);
+ }
+ zoutcnt = 0; /* (PWP) reset output buffer */
+ zoutptr = zoutbuffer;
+ return((fp[n] != NULL) ? 1 : 0);
+}
+
+/* Z C L O S E -- Close the given file. */
+
+/* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
+
+int
+zclose(n) int n; {
+ int x = 0, x2 = 0;
+ extern CK_OFF_T ffc;
+
+ debug(F101,"zclose file number","",n);
+ if (chkfn(n) < 1) return(0); /* Check range of n */
+ if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
+ x2 = zoutdump();
+
+ if (fp[ZSYSFN] || ispipe[n]) { /* If file is really pipe */
+#ifndef NOPUSH
+ x = zclosf(n); /* do it specially */
+#else
+ x = EOF;
+#endif /* NOPUSH */
+ debug(F101,"zclose zclosf","",x);
+ /* debug(F101,"zclose zclosf fp[n]","",fp[n]); */
+ } else {
+ if ((fp[n] != stdout) && (fp[n] != stdin))
+ x = fclose(fp[n]);
+ fp[n] = NULL;
+#ifdef COMMENT
+ if (n == ZCTERM || n == ZSTDIO) /* See zopeno() */
+ if (fp[ZOFILE] == stdout)
+ fp[ZOFILE] = NULL;
+#endif /* COMMENT */
+ }
+ iflen = -1L; /* Invalidate file length */
+ if (x == EOF) { /* if we got a close error */
+ debug(F101,"zclose fclose fails","",x);
+ return(-1);
+ } else if (x2 < 0) { /* or error flushing last buffer */
+ debug(F101,"zclose error flushing last buffer","",x2);
+ return(-1); /* then return an error */
+ } else {
+ /* Print log record compatible with wu-ftpd */
+ if (xferlog && (n == ZIFILE || n == ZOFILE)) {
+ char * s, *p;
+ extern char ttname[];
+ if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */
+ debug(F101,"zclose iklogopen","",iklogopen);
+ if (iklogopen) {
+ int len;
+ char * fnam;
+
+ timenow = time(NULL);
+#ifdef CK_LOGIN
+ if (logged_in)
+ s = clienthost;
+ else
+#endif /* CK_LOGIN */
+ s = (char *)ttname;
+ if (!s) s = "";
+ if (!*s) s = "*";
+#ifdef CK_LOGIN
+ if (logged_in) {
+ p = guestpass;
+ if (!*p) p = "*";
+ } else
+#endif /* CK_LOGIN */
+ p = whoami();
+
+ len = 24 + 12 + (int)strlen(s) + 16
+ + (int)strlen(fullname) + 1 + 1 + 1 + 1
+ + (int)strlen(p) + 6 + 2 + 12;
+ fnam = fullname;
+ if (!*fnam) fnam = "(pipe)";
+
+ if (len > IKSDMSGLEN)
+ sprintf(iksdmsg, /* SAFE */
+ "%.24s [BUFFER WOULD OVERFLOW]\n",ctime(&timenow));
+ else
+ sprintf(iksdmsg, /* SAFE */
+ "%.24s %d %s %s %s %c %s %c %c %s %s %d %s\n",
+ ctime(&timenow), /* date/time */
+ gtimer(), /* elapsed secs */
+ s, /* peer name */
+ ckfstoa(ffc), /* byte count */
+ fnam, /* full pathname of file */
+ (binary ? 'b' : 'a'), /* binary or ascii */
+ "_", /* options = none */
+ n == ZIFILE ? 'o' : 'i', /* in/out */
+#ifdef CK_LOGIN
+ (isguest ? 'a' : 'r'), /* User type */
+#else
+ 'r',
+#endif /* CK_LOGIN */
+ p, /* Username or guest passwd */
+#ifdef CK_LOGIN
+ logged_in ? "iks" : "kermit", /* Record ID */
+#else
+ "kermit",
+#endif /* CK_LOGIN */
+ 0, /* User ID on client system unknown */
+ "*" /* Ditto */
+ );
+ debug(F110,"zclose iksdmsg",iksdmsg,0);
+ write(xferlog, iksdmsg, (int)strlen(iksdmsg));
+ }
+ }
+ debug(F101,"zclose returns","",1);
+ return(1);
+ }
+}
+
+/* Z C H I N -- Get a character from the input file. */
+
+/* Returns -1 if EOF, 0 otherwise with character returned in argument */
+
+int
+zchin(n,c) int n; int *c; {
+ int a;
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+ a = coninc(0);
+ if (*c < 0)
+ return(-1);
+ } else
+#endif /* IKSD */
+ /* (PWP) Just in case this gets called when it shouldn't. */
+ if (n == ZIFILE) {
+ a = zminchar(); /* Note: this catches Ctrl-Z */
+ if (a < 0) /* (See zinfill()...) */
+ return(-1);
+ } else {
+ a = getc(fp[n]);
+ if (a == EOF) return(-1);
+#ifdef CK_CTRLZ
+ /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
+ if (!binary && a == 0x1A && eofmethod == XYEOF_Z)
+ return(-1);
+#endif /* CK_CTRLZ */
+ }
+ *c = (CHAR) a & 0377;
+ return(0);
+}
+
+/* Z S I N L -- Read a line from a file */
+
+/*
+ Writes the line into the address provided by the caller.
+ n is the Kermit "channel number".
+ Writing terminates when newline is encountered, newline is not copied.
+ Writing also terminates upon EOF or if length x is exhausted.
+ Returns 0 on success, -1 on EOF or error.
+*/
+int
+zsinl(n,s,x) int n, x; char *s; {
+ int a, z = 0; /* z is return code. */
+ int count = 0;
+ int len = 0;
+ char *buf;
+ extern CHAR feol; /* Line terminator */
+
+ if (!s || chkfn(n) < 1) /* Make sure file is open, etc */
+ return(-1);
+ buf = s;
+ s[0] = '\0'; /* Don't return junk */
+
+ a = -1; /* Current character, none yet. */
+ while (x--) { /* Up to given length */
+ int old = 0;
+ if (feol) /* Previous character */
+ old = a;
+ if (zchin(n,&a) < 0) { /* Read a character from the file */
+ debug(F101,"zsinl zchin fail","",count);
+ if (count == 0)
+ z = -1; /* EOF or other error */
+ break;
+ } else
+ count++;
+ if (feol) { /* Single-character line terminator */
+ if (a == feol)
+ break;
+ } else { /* CRLF line terminator */
+ if (a == '\015') /* CR, get next character */
+ continue;
+ if (old == '\015') { /* Previous character was CR */
+ if (a == '\012') { /* This one is LF, so we have a line */
+ break;
+ } else { /* Not LF, deposit CR */
+ *s++ = '\015';
+ x--;
+ len++;
+ }
+ }
+ }
+ *s = a; /* Deposit character */
+ s++;
+ len++;
+ }
+ *s = '\0'; /* Terminate the string */
+ debug(F011,"zsinl",buf,len);
+ return(z);
+}
+
+/* Z X I N -- Read x bytes from a file */
+
+/*
+ Reads x bytes (or less) from channel n and writes them
+ to the address provided by the caller.
+ Returns number of bytes read on success, 0 on EOF or error.
+*/
+int
+zxin(n,s,x) int n, x; char *s; {
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+ int a, i;
+ a = ttchk();
+ if (a < 1) return(0);
+ for (i = 0; i < a && i < x; i++)
+ s[i] = coninc(0);
+ return(i);
+ }
+#endif /* IKSD */
+
+ return(fread(s, sizeof (char), x, fp[n]));
+}
+
+/*
+ Z I N F I L L -- Buffered file input.
+
+ (re)fill the file input buffer with data. All file input
+ should go through this routine, usually by calling the zminchar()
+ macro defined in ckcker.h. Returns:
+
+ Value 0..255 on success, the character that was read.
+ -1 on end of file.
+ -2 on any kind of error other than end of file.
+ -3 timeout when reading from pipe (Kermit packet mode only).
+*/
+int
+zinfill() {
+ extern int kactive, srvping;
+ errno = 0;
+
+#ifdef ZDEBUG
+ printf("ZINFILL fp[%d]=%ld\n",ZIFILE,fp[ZIFILE]);
+#endif /* ZDEBUG */
+
+#ifdef IKSD
+ if (inserver && !local && fp[ZIFILE] == stdin) {
+ int a, i;
+ a = ttchk();
+ if (a < 0) return(-2);
+ for (i = 0; i < a && i < INBUFSIZE; i++) {
+ zinbuffer[i] = coninc(0);
+ }
+ zincnt = i;
+ /* set pointer to beginning, (== &zinbuffer[0]) */
+ zinptr = zinbuffer;
+ if (zincnt == 0) return(-1);
+ zincnt--; /* One less char in buffer */
+ return((int)(*zinptr++) & 0377); /* because we return the first */
+ }
+#endif /* IKSD */
+
+ debug(F101,"zinfill kactive","",kactive);
+
+ if (!(kactive && ispipe[ZIFILE])) {
+ if (feof(fp[ZIFILE])) {
+ debug(F100,"ZINFILL feof","",0);
+#ifdef ZDEBUG
+ printf("ZINFILL EOF\n");
+#endif /* ZDEBUG */
+ return(-1);
+ }
+ }
+ clearerr(fp[ZIFILE]);
+
+#ifdef SELECT
+ /* Here we can call select() to get a timeout... */
+ if (kactive && ispipe[ZIFILE]) {
+ int secs, z = 0;
+#ifndef NOXFER
+ if (srvping) {
+ secs = 1;
+ debug(F101,"zinfill calling ttwait","",secs);
+ z = ttwait(fileno(fp[ZIFILE]),secs);
+ debug(F101,"zinfill ttwait","",z);
+ }
+#endif /* NOXFER */
+ if (z == 0)
+ return(-3);
+ }
+#endif /* SELECT */
+
+#ifdef DEBUG
+ if (deblog) {
+ int i;
+ debug(F101,"ZINFILL INBUFSIZE","",INBUFSIZE);
+#ifdef USE_MEMCPY
+ memset(zinbuffer, 0xFF, INBUFSIZE);
+#else
+ for (i = 0; i < INBUFSIZE; i++) {
+ zinbuffer[i] = 0xFF;
+#ifdef COMMENT /* Too much! */
+ debug(F101,"ZINFILL zinbuffer[i]","",i);
+#endif /* COMMENT */
+ }
+#endif /* USE_MEMCPY */
+ ckstrncpy(zinbuffer,"zinbuffer is a valid buffer",INBUFSIZE);
+ /* debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer); */
+ }
+#endif /* DEBUG */
+
+/*
+ Note: The following read MUST be nonblocking when reading from a pipe
+ and we want timeouts to work. See zxcmd().
+*/
+ zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
+ debug(F101,"ZINFILL fread","",zincnt); /* Just the size */
+#ifdef ZDEBUG
+ printf("FREAD=%d\n",zincnt);
+#endif /* ZDEBUG */
+#ifdef CK_CTRLZ
+ /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
+ if (zincnt > 0 && !binary && eofmethod == XYEOF_Z) {
+ register int i;
+ for (i = 0; i < zincnt; i++) {
+ if (zinbuffer[i] == SUB) {
+ zincnt = i; /* Stop at first Ctrl-Z */
+ if (i == 0)
+ return(-1);
+ break;
+ }
+ }
+ }
+#endif /* CK_CTRLZ */
+
+ if (zincnt == 0) { /* Got nothing? */
+ if (ferror(fp[ZIFILE])) {
+ debug(F100,"ZINFILL ferror","",0);
+ debug(F101,"ZINFILL errno","",errno);
+#ifdef ZDEBUG
+ printf("ZINFILL errno=%d\n",errno);
+#endif /* ZDEBUG */
+#ifdef EWOULDBLOCK
+ return((errno == EWOULDBLOCK) ? -3 : -2);
+#else
+ return(-2);
+#endif /* EWOULDBLOCK */
+ }
+
+ /* In case feof() didn't work just above -- sometimes it doesn't... */
+
+ if (feof(fp[ZIFILE]) ) {
+ debug(F100,"ZINFILL count 0 EOF return -1","",0);
+ return (-1);
+ } else {
+ debug(F100,"ZINFILL count 0 not EOF return -2","",0);
+ return(-2);
+ }
+ }
+ zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
+ zincnt--; /* One less char in buffer */
+ return((int)(*zinptr++) & 0377); /* because we return the first */
+}
+
+/* Z S O U T -- Write a string out to the given file, buffered. */
+
+/* Returns 0 on success, -1 on failure */
+
+int
+zsout(n,s) int n; char *s; {
+ int rc = 0;
+ rc = chkfn(n);
+ if (rc < 1) return(-1); /* Keep this, prevents memory faults */
+ if (!s) return(0); /* Null pointer, do nothing, succeed */
+ if (!*s) return(0); /* empty string, ditto */
+
+#ifdef IKSD
+ /*
+ This happens with client-side Kermit server when a REMOTE command
+ was sent from the server to the client and the server is supposed to
+ display the text, but of course there is no place to display it
+ since it is in remote mode executing Kermit protocol.
+ */
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttol(s,((int)strlen(s)) < 0) ? -1 : 0);
+#else
+ return(0);
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if (n == ZSFILE) {
+ int k;
+ k = strlen(s);
+ rc = write(fileno(fp[n]),s,k);
+ return((rc == k) ? 0 : -1);
+ }
+ rc = fputs(s,fp[n]) == EOF ? -1 : 0;
+ if (n == ZWFILE)
+ fflush(fp[n]);
+ return(rc);
+}
+
+/* Z S O U T L -- Write string to file, with line terminator, buffered */
+
+/* Returns 0 on success, -1 on failure */
+
+int
+zsoutl(n,s) int n; char *s; {
+ if (zsout(n,s) < 0)
+ return(-1);
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttoc(LF));
+#else
+ return(0); /* See comments in zsout() */
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if (n == ZSFILE) /* Session log is unbuffered */
+ return(write(fileno(fp[n]),"\n",1) == 1 ? 0 : -1);
+ else if (fputs("\n",fp[n]) == EOF)
+ return(-1);
+ if (n == ZDIFIL || n == ZWFILE) /* Flush connection log records */
+ fflush(fp[n]);
+ return(0);
+}
+
+/* Z S O U T X -- Write x characters to file, unbuffered. */
+
+/* Returns number of characters written on success, -1 on failure */
+
+int
+zsoutx(n,s,x) int n, x; char *s; {
+ int k;
+ if (!s) return(0);
+ if (!*s) return(0);
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttol(s,x)); /* See comments in zsout() */
+#else
+ return(x);
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if ((k = (int)strlen(s)) > x) x = k; /* Nothing else would make sense */
+#ifdef COMMENT
+ if (chkfn(n) < 1) return(-1);
+ return(write(fp[n]->_file,s,x));
+#endif /* COMMENT */
+ return(write(fileno(fp[n]),s,x) == x ? x : -1);
+}
+
+/* Z C H O U T -- Add a character to the given file. */
+
+/* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
+
+int
+#ifdef CK_ANSIC
+zchout(register int n, char c)
+#else
+zchout(n,c) register int n; char c;
+#endif /* CK_ANSIC */
+/* zchout() */ {
+ /* if (chkfn(n) < 1) return(-1); */
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttoc(c));
+#else
+ return(0); /* See comments in zsout() */
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if (n == ZSFILE) /* Use unbuffered for session log */
+ return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
+ /* Buffered for everything else */
+ if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
+ return(ferror(fp[n])?-1:0); /* Check to make sure */
+ else /* Otherwise... */
+ return(0); /* There was no error. */
+}
+
+/* (PWP) buffered character output routine to speed up file IO */
+
+int
+zoutdump() {
+ int x;
+ char * zp;
+ zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
+#ifdef DEBUG
+ if (deblog)
+ debug(F101,"zoutdump zoutcnt","",zoutcnt);
+#endif /* DEBUG */
+ if (zoutcnt == 0) { /* Nothing to output */
+ return(0);
+ } else if (zoutcnt < 0) { /* Unexpected negative argument */
+ zoutcnt = 0; /* Reset output buffer count */
+ return(-1); /* and fail. */
+ }
+
+#ifdef IKSD
+ if (inserver && !local && fp[ZOFILE] == stdout) {
+#ifdef COMMENT
+ x = ttol(zoutbuffer,zoutcnt);
+#else
+ x = 1; /* See comments in zsout() */
+#endif /* COMMENT */
+ zoutcnt = 0;
+ return(x > 0 ? 0 : -1);
+ }
+#endif /* IKSD */
+
+/*
+ Frank Prindle suggested that replacing this fwrite() by an fflush()
+ followed by a write() would improve the efficiency, especially when
+ writing to stdout. Subsequent tests showed a 5-fold improvement.
+*/
+#ifdef COMMENT
+ if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) ...
+#endif /* COMMENT */
+
+#ifndef CK_NONBLOCK
+ fflush(fp[ZOFILE]);
+#endif /* CK_NONBLOCK */
+ zp = zoutbuffer;
+ while (zoutcnt > 0) {
+ if ((x = write(fileno(fp[ZOFILE]),zp,zoutcnt)) > -1) {
+#ifdef DEBUG
+ if (deblog) /* Save a function call... */
+ debug(F101,"zoutdump wrote","",x);
+#endif /* DEBUG */
+ zoutcnt -= x; /* Adjust output buffer count */
+ zp += x; /* and pointer */
+ } else {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"zoutdump write error","",errno);
+ debug(F101,"zoutdump write returns","",x);
+ }
+#endif /* DEBUG */
+ zoutcnt = 0; /* Reset output buffer count */
+ return(-1); /* write() failed */
+ }
+ }
+ return(0);
+}
+
+/* C H K F N -- Internal function to verify file number is ok */
+
+/*
+ Returns:
+ -1: File number n is out of range
+ 0: n is in range, but file is not open
+ 1: n in range and file is open
+*/
+int
+chkfn(n) int n; {
+ /* if (n != ZDFILE) debug(F101,"chkfn","",n); */
+ if (n < 0 || n >= ZNFILS) {
+ if (n != ZDFILE) debug(F101,"chkfn out of range","",n);
+ return(-1);
+ } else {
+ /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */
+ return((fp[n] == NULL) ? 0 : 1);
+ }
+}
+
+/* Z G E T F S -- Return file size regardless of accessibility */
+/*
+ Used for directory listings, etc.
+ Returns:
+ The size of the file in bytes, 0 or greater, if the size can be learned.
+ -1 if the file size can not be obtained.
+ Also (and this is a hack just for UNIX):
+ If the argument is the name of a symbolic link,
+ the global variable issymlink is set to 1,
+ and the global buffer linkname[] gets the link value.
+ And it sets zgfs_dir to 1 if it's a directory, otherwise 0.
+ This lets us avoid numerous redundant calls to stat().
+*/
+int zgfs_link = 0;
+int zgfs_dir = 0;
+time_t zgfs_mtime = 0;
+unsigned int zgfs_mode = 0;
+
+#ifdef CKSYMLINK
+char linkname[CKMAXPATH+1];
+#ifndef _IFLNK
+#define _IFLNK 0120000
+#endif /* _IFLNK */
+#endif /* CKSYMLINK */
+
+CK_OFF_T
+zgetfs(name) char *name; {
+ struct stat buf;
+ char fnam[CKMAXPATH+4];
+ CK_OFF_T size = (CK_OFF_T)-1;
+ int x;
+ int needrlink = 0;
+ char * s;
+
+ if (!name) name = "";
+ if (!*name) return(-1);
+
+#ifdef UNIX
+ x = strlen(name);
+ if (x == 9 && !strcmp(name,"/dev/null"))
+ return(0);
+#endif /* UNIX */
+
+ s = name;
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ }
+#endif /* DTILDE */
+ x = ckstrncpy(fnam,s,CKMAXPATH);
+ s = fnam;
+ debug(F111,"zgetfs fnam",s,x);
+ if (x > 0 && s[x-1] == '/')
+ s[x-1] = '\0';
+
+ zgfs_dir = 0; /* Assume it's not a directory */
+ zgfs_link = 0; /* Assume it's not a symlink */
+ zgfs_mtime = 0; /* No time yet */
+ zgfs_mode = 0; /* No permission bits yet */
+
+#ifdef CKSYMLINK /* We're doing symlinks? */
+#ifdef USE_LSTAT /* OK to use lstat()? */
+ x = lstat(s,&buf);
+ debug(F101,"STAT","",1);
+ if (x < 0) /* stat() failed */
+ return(-1);
+ if ( /* Now see if it's a symlink */
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ ) {
+ zgfs_link = 1; /* It's a symlink */
+ linkname[0] = '\0'; /* Get the name */
+ x = readlink(s,linkname,CKMAXPATH);
+ debug(F101,"zgetfs readlink",s,x);
+ if (x > -1 && x < CKMAXPATH) { /* It's a link */
+ linkname[x] = '\0';
+ size = buf.st_size; /* Remember size of link */
+ x = stat(s,&buf); /* Now stat the linked-to file */
+ debug(F101,"STAT","",2);
+ if (x < 0) /* so we can see if it's a directory */
+ return(-1);
+ } else {
+ ckstrncpy(linkname,"(lookup failed)",CKMAXPATH);
+ }
+ }
+#else /* !USE_LSTAT */
+ x = stat(s,&buf); /* No lstat(), use stat() instead */
+ debug(F101,"STAT","",3);
+ if (x < 0)
+ return(-1);
+#endif /* USE_LSTAT */
+
+ /* Do we need to call readlink()? */
+
+#ifdef NOLINKBITS
+/*
+ lstat() does not work in SCO operating systems. From "man NS lstat":
+
+ lstat obtains information about the file named by path. In the case of a
+ symbolic link, lstat returns information about the link, and not the file
+ named by the link. It is only used by the NFS automount daemon and should
+ not be utilized by users.
+*/
+ needrlink = 1;
+ debug(F101,"zgetfs forced needrlink","",needrlink);
+#else
+#ifdef S_ISLNK
+ needrlink = S_ISLNK(buf.st_mode);
+ debug(F101,"zgetfs S_ISLNK needrlink","",needrlink);
+#else
+#ifdef _IFLNK
+ needrlink = (_IFMT & buf.st_mode) == _IFLNK;
+ debug(F101,"zgetfs _IFLNK needrlink","",needrlink);
+#else
+ needrlink = 1;
+ debug(F101,"zgetfs default needrlink","",needrlink);
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+#endif /* NOLINKBITS */
+
+ if (needrlink) {
+ linkname[0] = '\0';
+ errno = 0;
+ x = readlink(s,linkname,CKMAXPATH);
+#ifdef DEBUG
+ debug(F111,"zgetfs readlink",s,x);
+ if (x < 0)
+ debug(F101,"zgetfs readlink errno","",errno);
+ else
+ debug(F110,"zgetfs readlink result",linkname,0);
+#endif /* DEBUG */
+ if (x > -1 && x < CKMAXPATH) {
+ zgfs_link = 1;
+ linkname[x] = '\0';
+ }
+ }
+#else /* !CKSYMLINK */
+ x = stat(s,&buf); /* Just stat the file */
+ debug(F111,"zgetfs stat",s,x);
+ if (x < 0) /* and get the size */
+ return(-1);
+#endif /* CKSYMLINK */
+
+ zgfs_mtime = buf.st_mtime;
+ zgfs_mode = buf.st_mode;
+ zgfs_dir = (S_ISDIR(buf.st_mode)) ? 1 : 0; /* Set "is directory" flag */
+ debug(F111,"zgetfs size",s,size);
+ debug(F111,"zgetfs st_size",s,buf.st_size);
+ return((size < 0L) ? buf.st_size : size); /* Return the size */
+}
+
+
+/* Z C H K I -- Check if input file exists and is readable */
+
+/*
+ Returns:
+ >= 0 if the file can be read (returns the size).
+ -1 if file doesn't exist or can't be accessed,
+ -2 if file exists but is not readable (e.g. a directory file).
+ -3 if file exists but protected against read access.
+
+ For Berkeley Unix, a file must be of type "regular" to be readable.
+ Directory files, special files, and symbolic links are not readable.
+*/
+CK_OFF_T
+zchki(name) char *name; {
+ struct stat buf;
+ char * s;
+ int x, itsadir = 0;
+ extern int zchkid, diractive, matchfifo;
+
+ if (!name)
+ return(-1);
+ x = strlen(name);
+ if (x < 1)
+ return(-1);
+ s = name;
+
+#ifdef UNIX
+ if (x == 9 && !strcmp(s,"/dev/null"))
+ return(0);
+ if (x == 8 && !strcmp(s,"/dev/tty"))
+ return(0);
+#endif /* UNIX */
+
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ }
+#endif /* DTILDE */
+
+#ifdef CKROOT
+ debug(F111,"zchki setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zchki setroot violation",name,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = stat(s,&buf);
+ debug(F101,"STAT","",5);
+ if (x < 0) {
+ debug(F111,"zchki stat fails",s,errno);
+ return(-1);
+ }
+ if (S_ISDIR (buf.st_mode))
+ itsadir = 1;
+
+ if (!(itsadir && zchkid)) { /* Unless this... */
+ if (!S_ISREG (buf.st_mode) /* Must be regular file */
+#ifdef S_ISFIFO
+ && (!matchfifo || !S_ISFIFO (buf.st_mode)) /* or FIFO */
+#endif /* S_ISFIFO */
+ ) {
+ debug(F111,"zchki not regular file (or fifo)",s,matchfifo);
+ return(-2);
+ }
+ }
+ debug(F111,"zchki stat ok:",s,x);
+
+ if (diractive) { /* If listing don't check access */
+ x = 1;
+ } else {
+#ifdef SW_ACC_ID
+ debug(F100,"zchki swapping ids for access()","",0);
+ priv_on();
+#endif /* SW_ACC_ID */
+ if ((x = access(s,R_OK)) < 0)
+ x = access(s,X_OK); /* For RUN-class commands */
+#ifdef SW_ACC_ID
+ priv_off();
+ debug(F100,"zchki swapped ids restored","",0);
+#endif /* SW_ACC_ID */
+ }
+ if (x < 0) { /* Is the file accessible? */
+ debug(F111,"zchki access failed:",s,x); /* No */
+ return(-3);
+ } else {
+ iflen = buf.st_size; /* Yes, remember size */
+ ckstrncpy(nambuf,s,CKMAXPATH); /* and name globally. */
+ debug(F111,"zchki access ok:",s,iflen);
+ return((iflen > -1L) ? iflen : 0L);
+ }
+}
+
+/* Z C H K O -- Check if output file can be created */
+
+/*
+ Returns -1 if write permission for the file would be denied, 0 otherwise.
+
+ NOTE: The design is flawed. There is no distinction among:
+ . Can I overwrite an existing file?
+ . Can I create a file (or directory) in an existing directory?
+ . Can I create a file (or directory) and its parent(s)?
+*/
+int
+zchko(name) char *name; {
+ int i, x, itsadir = 0;
+ char *s = NULL;
+ char * oname;
+ extern int zchkod; /* Used by IF WRITEABLE */
+
+ debug(F110,"zchko entry",name,0);
+
+ if (!name) return(-1); /* Watch out for null pointer. */
+
+ oname = name;
+
+#ifdef CKROOT
+ debug(F111,"zchko setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zchko setroot violation",name,0);
+ errno = EACCES;
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = (int)strlen(name); /* Get length of filename */
+ debug(F111,"zchko len",name,x);
+ debug(F111,"zchko zchkod",name,zchkod);
+
+#ifdef UNIX
+/*
+ Writing to null device is OK.
+*/
+ if (x == 9 && !strcmp(name,"/dev/null"))
+ return(0);
+ if (x == 8 && !strcmp(name,"/dev/tty"))
+ return(0);
+#endif /* UNIX */
+
+ s = name;
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ x = strlen(s);
+ }
+#endif /* DTILDE */
+ name = s;
+ s = NULL;
+/*
+ zchkod is a global flag meaning we're checking not to see if the directory
+ file is writeable, but if it's OK to create files IN the directory.
+*/
+ if (!zchkod && isdir(name)) { /* Directories are not writeable */
+ debug(F111,"zchko isdir",name,1);
+ return(-1);
+ }
+ s = malloc(x+3); /* Must copy because we can't */
+ if (!s) { /* write into our argument. */
+ fprintf(stderr,"zchko: Malloc error 46\n");
+ return(-1);
+ }
+ ckstrncpy(s,name,x+3);
+#ifdef UNIX
+#ifdef NOUUCP
+ { /* 2009/10/20 */
+ /* Allow tty devices to opened as output files */
+ int fd, istty = 0, mode = 0;
+ debug(F110,"zchko attempting to open",name,0);
+ /* Don't block on lack of Carrier or other modem signals */
+#ifdef O_NONBLOCK
+ mode = O_NONBLOCK;
+#else
+#ifdef O_NDELAY
+ mode = O_NDELAY;
+#else
+#ifdef FNDELAY
+ mode = FNDELAY;
+#endif /* FNDELAY */
+#endif /* O_NDELAY */
+#endif /* O_NONBLOCK */
+ debug(F111,"zchko open mode",name,mode);
+ fd = open(name,O_WRONLY,mode); /* Must attempt to open it */
+ debug(F111,"zchko open",name,fd);
+ if (fd > -1) { /* to get a file descriptor */
+ if (isatty(fd)) /* for isatty() */
+ istty++;
+ debug(F111,"zchko isatty",name,istty);
+ fd = close(fd);
+ if (istty) {
+ goto doaccess;
+ }
+ } else {
+ debug(F101,"zchko open errno","",errno);
+ x = -1;
+ }
+ }
+#endif /* NOUUCP */
+#endif /* UNIX */
+ for (i = x; i > 0; i--) { /* Strip filename from right. */
+ if (ISDIRSEP(s[i-1])) {
+ itsadir = 1;
+ break;
+ }
+ }
+ debug(F101,"zchko i","",i);
+ debug(F101,"zchko itsadir","",itsadir);
+
+#ifdef COMMENT
+/* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */
+ if (i == 0) /* If no path, use current directory */
+ strcpy(s,"./");
+ else /* Otherwise, use given one. */
+ s[i] = '\0';
+#else
+#ifdef COMMENT
+/*
+ The following does not work for "foo/bar" where the foo directory does
+ not exist even though we could create it: access("foo/.") fails, but
+ access("foo") works OK.
+*/
+/* So now we use "path/." if path given, or "." if no path given. */
+ s[i++] = '.'; /* Append "." to path. */
+ s[i] = '\0';
+#else
+/* So NOW we strip path segments from the right as long as they don't */
+/* exist -- we only call access() for path segments that *do* exist.. */
+/* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */
+/* succeeds when I have write access to foo and bar but baz doesn't exit.) */
+
+ if (itsadir && i > 0) {
+ s[i-1] = '\0';
+ while (s[0] && !isdir(s)) {
+ for (i = (int)strlen(s); i > 0; i--) {
+ if (ISDIRSEP(s[i-1])) {
+ s[i-1] = '\0';
+ break;
+ }
+ }
+ if (i == 0)
+ s[0] = '\0';
+ }
+ } else {
+ s[i++] = '.'; /* Append "." to path. */
+ s[i] = '\0';
+ }
+#endif /* COMMENT */
+#endif /* COMMENT */
+
+ if (!s[0])
+ ckstrncpy(s,".",x+3);
+
+ doaccess:
+
+#ifdef SW_ACC_ID
+ debug(F100,"zchko swapping ids for access()","",0);
+ priv_on();
+#endif /* SW_ACC_ID */
+
+ x = access(s,W_OK); /* Check access of path. */
+
+#ifdef SW_ACC_ID
+ priv_off();
+ debug(F100,"zchko swapped ids restored","",0);
+#endif /* SW_ACC_ID */
+
+ if (x < 0)
+ debug(F111,"zchko access failed:",s,errno);
+ else
+ debug(F111,"zchko access ok:",s,x);
+ if (s) free(s); /* Free temporary storage */
+
+ return((x < 0) ? -1 : 0); /* and return. */
+}
+
+/* Z D E L E T -- Delete the named file. */
+
+/* Returns: -1 on error, 0 on success */
+
+int
+zdelet(name) char *name; {
+ int x;
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-1);
+#endif /* CK_LOGIN */
+
+#ifdef CKROOT
+ debug(F111,"zdelet setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zdelet setroot violation",name,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = unlink(name);
+ debug(F111,"zdelet",name,x);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging) {
+ fullname[0] = '\0';
+ zfnqfp(name,CKMAXPATH,fullname);
+ debug(F110,"zdelet fullname",fullname,0);
+ if (x < 0)
+ syslog(LOG_INFO, "file[] %s: delete failed (%m)", fullname);
+ else
+ syslog(LOG_INFO, "file[] %s: delete ok", fullname);
+ }
+#endif /* CKSYSLOG */
+ return(x);
+}
+
+/* Z R T O L -- Convert remote filename into local form */
+
+VOID
+zrtol(name,name2) char *name, *name2; {
+ nzrtol(name,name2,1,0,CKMAXPATH);
+}
+
+VOID
+nzrtol(name,name2,fncnv,fnrpath,max)
+ char *name, *name2; int fncnv, fnrpath, max;
+{ /* nzrtol */
+ char *s, *p;
+ int flag = 0, n = 0;
+ char fullname[CKMAXPATH+1];
+ int devnull = 0;
+ int acase = 0;
+ if (!name2) return;
+ if (!name) name = "";
+
+ debug(F111,"nzrtol name",name,fncnv);
+
+#ifdef DTILDE
+ s = name;
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (*s) name = s;
+ }
+#endif /* DTILDE */
+
+ /* Handle the path -- we don't have to convert its format, since */
+ /* the standard path format and our (UNIX) format are the same. */
+
+ fullname[0] = NUL;
+ devnull = !strcmp(name,"/dev/null");
+
+ if (!devnull && fnrpath == PATH_OFF) { /* RECEIVE PATHNAMES OFF */
+ zstrip(name,&p);
+ strncpy(fullname,p,CKMAXPATH);
+ } else if (!devnull && fnrpath == PATH_ABS) { /* REC PATHNAMES ABSOLUTE */
+ strncpy(fullname,name,CKMAXPATH);
+ } else if (!devnull && isabsolute(name)) { /* RECEIVE PATHNAMES RELATIVE */
+ ckmakmsg(fullname,CKMAXPATH,".",name,NULL,NULL);
+ } else { /* Ditto */
+ ckstrncpy(fullname,name,CKMAXPATH);
+ }
+ fullname[CKMAXPATH] = NUL;
+ debug(F110,"nzrtol fullname",fullname,0);
+
+#ifndef NOTRUNCATE
+/*
+ The maximum length for any segment of a filename is MAXNAMLEN, defined
+ above. On some platforms (at least QNX) if a segment exceeds this limit,
+ the open fails with ENAMETOOLONG, so we must prevent it by truncating each
+ overlong name segment to the maximum segment length before passing the
+ name to open(). This must be done even when file names are literal, so as
+ not to halt a file transfer unnecessarily.
+*/
+ {
+ char buf[CKMAXPATH+1]; /* New temporary buffer on stack */
+ char *p = fullname; /* Source and */
+ char *s = buf; /* destination pointers */
+ int i = 0, n = 0;
+ debug(F101,"nzrtol sizing MAXNAMLEN","",MAXNAMLEN);
+ while (*p && n < CKMAXPATH) { /* Copy name to new buffer */
+ if (++i > MAXNAMLEN) { /* If this segment too long */
+ while (*p && *p != '/') /* skip past the rest... */
+ p++;
+ i = 0; /* and reset counter. */
+ } else if (*p == '/') { /* End of this segment. */
+ i = 0; /* Reset counter. */
+ }
+ *s++ = *p++; /* Copy this character. */
+ n++;
+ }
+ *s = NUL;
+ ckstrncpy(fullname,buf,CKMAXPATH); /* Copy back to original buffer. */
+ debug(F111,"nzrtol sizing",fullname,n);
+ }
+#endif /* NOTRUNCATE */
+
+ if (!fncnv || devnull) { /* Not converting */
+ ckstrncpy(name2,fullname,max); /* We're done. */
+ return;
+ }
+ name = fullname; /* Converting */
+
+ p = name2;
+ for (; *name != '\0' && n < maxnam; name++) {
+ if (*name > SP) flag = 1; /* Strip leading blanks and controls */
+ if (flag == 0 && *name < '!')
+ continue;
+ if (fncnv > 0) {
+ if (*name == SP) {
+ *p++ = '_';
+ n++;
+ continue;
+ }
+ if (isupper(*name)) /* Check for mixed case */
+ acase |= 1;
+ else if (islower(*name))
+ acase |= 2;
+ }
+ *p++ = *name;
+ n++;
+ }
+ *p-- = '\0'; /* Terminate */
+ while (*p < '!' && p > name2) /* Strip trailing blanks & controls */
+ *p-- = '\0';
+
+ if (*name2 == '\0') { /* Nothing left? */
+ ckstrncpy(name2,"NONAME",max); /* do this... */
+ } else if (acase == 1) { /* All uppercase? */
+ p = name2; /* So convert all letters to lower */
+ while (*p) {
+ if (isupper(*p))
+ *p = tolower(*p);
+ p++;
+ }
+ }
+ debug(F110,"nzrtol new name",name2,0);
+}
+
+
+/* Z S T R I P -- Strip device & directory name from file specification */
+
+/* Strip pathname from filename "name", return pointer to result in name2 */
+
+static char work[CKMAXPATH+1];
+
+VOID
+zstrip(name,name2) char *name, **name2; {
+ char *cp, *pp;
+ int n = 0;
+
+ debug(F110,"zstrip before",name,0);
+ if (!name) { *name2 = ""; return; }
+ pp = work;
+#ifdef DTILDE
+ /* Strip leading tilde */
+ if (*name == '~') name++;
+ debug(F110,"zstrip after tilde-stripping",name,0);
+#endif /* DTILDE */
+ for (cp = name; *cp; cp++) {
+ if (ISDIRSEP(*cp)) {
+ pp = work;
+ n = 0;
+ } else {
+ *pp++ = *cp;
+ if (n++ >= CKMAXPATH)
+ break;
+ }
+ }
+ *pp = '\0'; /* Terminate the string */
+ *name2 = work;
+ debug(F110,"zstrip after",*name2,0);
+}
+
+/* Z L T O R -- Local TO Remote */
+
+VOID
+zltor(name,name2) char *name, *name2; {
+ nzltor(name,name2,1,0,CKMAXPATH);
+}
+
+/* N Z L T O R -- New Local TO Remote */
+
+/*
+ fncnv = 0 for no conversion, > 0 for regular conversion, < 0 for minimal.
+*/
+VOID
+nzltor(name,name2,fncnv,fnspath,max)
+ char *name, *name2; int fncnv, fnspath, max;
+{ /* nzltor */
+ char *cp, *pp;
+#ifdef COMMENT
+ int dc = 0;
+#endif /* COMMENT */
+ int n = 0;
+ char *dotp = NULL;
+ char *dirp = NULL;
+ char fullname[CKMAXPATH+1];
+ char *p;
+ CHAR c;
+
+#ifndef NOCSETS
+ extern int fcharset, /* tcharset, */ language;
+ int langsv;
+ _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
+#ifdef CK_ANSIC
+ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
+#else
+ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
+#endif /* CK_ANSIC */
+ langsv = language;
+ language = L_USASCII;
+#ifdef COMMENT
+ /* Proper translation of filenames must be done elsewhere */
+ n = tcharset ? tcharset : TC_USASCII;
+ sxo = xls[n][fcharset];
+#else
+ sxo = xls[TC_USASCII][fcharset];
+#endif /* COMMENT */
+#endif /* NOCSETS */
+
+ debug(F110,"nzltor name",name,0);
+
+ /* Handle pathname */
+
+ fullname[0] = NUL;
+ if (fnspath == PATH_OFF) { /* PATHNAMES OFF */
+ zstrip(name,&p);
+ ckstrncpy(fullname,p,CKMAXPATH);
+ } else { /* PATHNAMES RELATIVE or ABSOLUTE */
+ char * p = name;
+ while (1) {
+ if (!strncmp(p,"../",3))
+ p += 3;
+ else if (!strncmp(p,"./",2))
+ p += 2;
+ else
+ break;
+ }
+ if (fnspath == PATH_ABS) { /* ABSOLUTE */
+ zfnqfp(p,CKMAXPATH,fullname);
+ } else { /* RELATIVE */
+ ckstrncpy(fullname,p,CKMAXPATH);
+ }
+ }
+ debug(F110,"nzltor fullname",fullname,0);
+
+ if (!fncnv) { /* Not converting */
+ ckstrncpy(name2,fullname,max); /* We're done. */
+#ifndef NOCSETS
+ langsv = language;
+#endif /* NOCSETS */
+ return;
+ }
+ name = fullname; /* Converting */
+
+#ifdef aegis
+ char *namechars;
+ int tilde = 0, bslash = 0;
+
+ if ((namechars = getenv("NAMECHARS")) != NULL) {
+ if (ckstrchr(namechars, '~' ) != NULL) tilde = '~';
+ if (ckstrchr(namechars, '\\') != NULL) bslash = '\\';
+ } else {
+ tilde = '~';
+ bslash = '\\';
+ }
+#endif /* aegis */
+
+ pp = work; /* Output buffer */
+ for (cp = name, n = 0; *cp && n < max; cp++,n++) { /* Convert name chars */
+ c = *cp;
+#ifndef NOCSETS
+ if (sxo) c = (*sxo)(c); /* Convert to ASCII */
+#endif /* NOCSETS */
+ if (fncnv > 0 && islower(c)) /* Uppercase letters */
+ *pp++ = toupper(c); /* Change tilde to hyphen */
+ else if (c == '~')
+ *pp++ = '-';
+ else if (fncnv > 0 && c == '#') /* Change number sign to 'X' */
+ *pp++ = 'X';
+ else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */
+ *pp++ = 'X';
+ else if (c == ' ') /* Change space to underscore */
+ *pp++ = '_';
+ else if (c < ' ') /* Change controls to 'X' */
+ *pp++ = 'X';
+ else if (fncnv > 0 && c == '.') { /* Change dot to underscore */
+ dotp = pp; /* Remember where we last did this */
+ *pp++ = '_';
+ } else {
+ if (c == '/')
+ dirp = pp;
+ *pp++ = c;
+ }
+ }
+ *pp = NUL; /* Tie it off. */
+#ifdef COMMENT
+ if (dotp) *dotp = '.'; /* Restore last dot (if any) */
+#else
+ if (dotp > dirp) *dotp = '.'; /* Restore last dot in file name */
+#endif /* COMMENT */
+ cp = name2; /* If nothing before dot, */
+ if (*work == '.') *cp++ = 'X'; /* insert 'X' */
+ ckstrncpy(cp,work,max);
+#ifndef NOCSETS
+ language = langsv;
+#endif /* NOCSETS */
+ debug(F110,"nzltor name2",name2,0);
+}
+
+
+/* Z C H D I R -- Change directory */
+/*
+ Call with:
+ dirnam = pointer to name of directory to change to,
+ which may be "" or NULL to indicate user's home directory.
+ Returns:
+ 0 on failure
+ 1 on success
+*/
+int
+zchdir(dirnam) char *dirnam; {
+ char *hd, *sp;
+#ifdef IKSDB
+ _PROTOTYP (int slotdir,(char *,char *));
+#endif /* IKSDB */
+#ifndef NOSPL
+ extern struct mtab *mactab; /* Main macro table */
+ extern int nmac; /* Number of macros */
+#endif /* NOSPL */
+
+ debug(F110,"zchdir",dirnam,0);
+ if (!dirnam) dirnam = "";
+ if (!*dirnam) /* If argument is null or empty, */
+ dirnam = zhome(); /* use user's home directory. */
+ sp = dirnam;
+ debug(F110,"zchdir 2",dirnam,0);
+
+#ifdef DTILDE
+ hd = tilde_expand(dirnam); /* Attempt to expand tilde */
+ if (!hd) hd = "";
+ if (*hd == '\0') hd = dirnam; /* in directory name. */
+#else
+ hd = dirnam;
+#endif /* DTILDE */
+ debug(F110,"zchdir 3",hd,0);
+
+#ifdef CKROOT
+ debug(F111,"zchdir setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(hd)) {
+ debug(F110,"zchdir setroot violation",hd,0);
+ return(0);
+ }
+#endif /* CKROOT */
+
+#ifdef pdp11
+ /* Just to save some space */
+ return((chdir(hd) == 0) ? 1 : 0);
+#else
+ if (chdir(hd) == 0) { /* Try to cd */
+#ifdef IKSDB
+#ifdef CK_LOGIN
+ if (inserver && ikdbopen)
+ slotdir(isguest ? anonroot : "", zgtdir());
+#endif /* CK_LOGIN */
+#endif /* IKSDB */
+
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ static int on_cd = 0;
+ if (!on_cd) {
+ on_cd = 1;
+ k = mlook(mactab,"on_cd",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,zgtdir(),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ on_cd = 0;
+ }
+ }
+#endif /* NOSPL */
+ return(1);
+ }
+ return(0);
+#endif /* pdp11 */
+}
+
+int
+#ifdef CK_ANSIC
+zchkpid(unsigned long xpid)
+#else
+zchkpid(xpid) unsigned long xpid;
+#endif /* CK_ANSIC */
+{
+ return((kill((PID_T)xpid,0) < 0) ? 0 : 1);
+}
+
+
+/* Z H O M E -- Return pointer to user's home directory */
+
+static char * zhomdir = NULL;
+
+char *
+zhome() {
+ char * home;
+
+#ifdef CKROOT
+ if (ckrootset)
+ return((char *)ckroot);
+#endif /* CKROOT */
+
+#ifdef Plan9
+ home = getenv("home");
+#else
+ home = getenv("HOME");
+#endif /* Plan9 */
+ makestr(&zhomdir,home);
+ return(home ? zhomdir : ".");
+}
+
+/* Z G T D I R -- Returns a pointer to the current directory */
+
+/*
+ The "preferred" interface for getting the current directory in modern UNIX
+ is getcwd() [POSIX 1003.1 5.2.2]. However, on certain platforms (such as
+ SunOS), it is implemented by forking a shell, feeding it the pwd command,
+ and returning the result, which is not only inefficient but also can result
+ in stray messages to the terminal. In such cases -- as well as when
+ getcwd() is not available at all -- getwd() can be used instead by defining
+ USE_GETWD. However, note that getwd() provides no buffer-length argument
+ and therefore no safeguard against memory leaks.
+*/
+#ifndef USE_GETWD
+#ifdef BSD42
+#define USE_GETWD
+#else
+#ifdef SUNOS4
+#define USE_GETWD
+#endif /* SUNOS4 */
+#endif /* BSD42 */
+#endif /* USE_GETWD */
+
+#ifdef pdp11
+#define CWDBL 80 /* Save every byte we can... */
+#else
+#define CWDBL CKMAXPATH
+#endif /* pdp11 */
+static char cwdbuf[CWDBL+2];
+/*
+ NOTE: The getcwd() prototypes are commented out on purpose. If you get
+ compile-time warnings, search through your system's header files to see
+ which one has the needed prototype, and #include it. Usually it is
+ <unistd.h>. See the section for including <unistd.h> in ckcdeb.h and
+ make any needed adjustments there (and report them).
+*/
+char *
+zgtdir() {
+ char * buf = cwdbuf;
+ char * s;
+
+#ifdef USE_GETWD
+ extern char *getwd();
+ s = getwd(buf);
+ debug(F110,"zgtdir BSD4 getwd()",s,0);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef BSD44
+#ifdef DCLGETCWD
+_PROTOTYP( char * getcwd, (char *, SIZE_T) );
+#endif /* DCLGETCWD */
+ debug(F101,"zgtdir BSD44 CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef MINIX2
+#ifdef DCLGETCWD
+ _PROTOTYP( char * getcwd, (char *, SIZE_T) );
+#endif /* DCLGETCWD */
+ debug(F101,"zgtdir MINIX2 CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef SVORPOSIX
+#ifdef COMMENT
+/* This non-ANSI prototype can be fatal at runtime! (e.g. in SCO3.2v5.0.5). */
+/* Anyway it's already prototyped in some header file that we have included. */
+ extern char *getcwd();
+#else
+#ifdef DCLGETCWD
+ _PROTOTYP( char * getcwd, (char *, SIZE_T) );
+#endif /* DCLGETCWD */
+#endif /* COMMENT */
+ debug(F101,"zgtdir SVORPOSIX CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef COHERENT
+#ifdef _I386
+#ifdef DCLGETCWD
+ extern char *getcwd();
+#endif /* DCLGETCWD */
+ debug(F101,"zgtdir COHERENT _I386 CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+ extern char *getwd();
+ debug(F101,"zgtdir COHERENT CWDBL","",CWDBL);
+ s = getwd(buf);
+ if (!s) s = "./";
+ return(s);
+#endif /* _I386 */
+#else
+#ifdef SUNOS4
+ debug(F101,"zgtdir SUNOS CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+ return("./");
+#endif /* SUNOS4 */
+#endif /* COHERENT */
+#endif /* SYSVORPOSIX */
+#endif /* MINIX2 */
+#endif /* BSD44 */
+#endif /* USE_GETWD */
+}
+
+/* Z X C M D -- Run a system command so its output can be read like a file */
+
+#ifndef NOPUSH
+int
+zxcmd(filnum,comand) int filnum; char *comand; {
+ int out;
+ int pipes[2];
+ extern int kactive; /* From ckcpro.w and ckcmai.c */
+
+ if (nopush) {
+ debug(F100,"zxcmd fails: nopush","",0);
+ return(-1);
+ }
+ debug(F111,"zxcmd",comand,filnum);
+ if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
+ if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
+ return(0);
+
+ out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
+ debug(F101,"zxcmd out",comand,out);
+
+/* Output to a command */
+
+ if (out) { /* Need popen() to do this. */
+ ckstrncpy(fullname,"(pipe)",CKMAXPATH);
+#ifdef NOPOPEN
+ return(0); /* no popen(), fail. */
+#else
+/* Use popen() to run the command. */
+
+#ifdef _POSIX_SOURCE
+/* Strictly speaking, popen() is not available in POSIX.1 */
+#define DCLPOPEN
+#endif /* _POSIX_SOURCE */
+
+ debug(F110,"zxcmd out",comand,0);
+
+ if (priv_chk()) {
+ debug(F100,"zxcmd priv_chk failed","",0);
+ return(0);
+ }
+ errno = 0;
+ fp[filnum] = popen(comand,"w");
+ debug(F111,"zxcmd popen",fp[filnum] ? "OK" : "Failed", errno);
+ if (fp[filnum] == NULL)
+ return(0);
+#ifdef COMMENT
+/* I wonder what this is all about... */
+ close(pipes[0]); /* Don't need the input side */
+ fp[filnum] = fdopen(pipes[1],"w"); /* Open output stream. */
+ fp[ZSYSFN] = fp[filnum]; /* Remember. */
+#endif /* COMMENT */
+ ispipe[filnum] = 1;
+ zoutcnt = 0; /* (PWP) reset input buffer */
+ zoutptr = zoutbuffer;
+ return(1);
+#endif /* NOPOPEN */
+ }
+
+/* Input from a command */
+
+#ifdef SNI541
+ /* SINIX-L 5.41 does not like fdopen() */
+ return(0);
+#else
+ if (pipe(pipes) != 0) {
+ debug(F100,"zxcmd pipe failure","",0);
+ return(0); /* can't make pipe, fail */
+ }
+
+/* Create a fork in which to run the named process */
+
+ if ((
+#ifdef aegis
+ pid = vfork() /* child */
+#else
+ pid = fork() /* child */
+#endif /* aegis */
+ ) == 0) {
+
+/* We're in the fork. */
+
+ char *shpath, *shname, *shptr; /* Find user's preferred shell */
+#ifndef aegis
+ struct passwd *p;
+ char *defshell;
+#ifdef HPUX10 /* Default shell */
+ defshell = "/usr/bin/sh";
+#else
+#ifdef Plan9
+ defshell = "/bin/rc";
+#else
+ defshell = "/bin/sh";
+#endif /* Plan9 */
+#endif /* HPUX10 */
+#endif /* aegis */
+ if (priv_can()) exit(1); /* Turn off any privileges! */
+ debug(F101,"zxcmd pid","",pid);
+ close(pipes[0]); /* close input side of pipe */
+ close(0); /* close stdin */
+ if (open("/dev/null",0) < 0) return(0); /* replace input by null */
+#ifndef OXOS
+#ifndef SVORPOSIX
+ dup2(pipes[1],1); /* BSD: replace stdout & stderr */
+ dup2(pipes[1],2); /* by the pipe */
+#else
+ close(1); /* AT&T: close stdout */
+ if (dup(pipes[1]) != 1) /* Send stdout to the pipe */
+ return(0);
+ close(2); /* Send stderr to the pipe */
+ if (dup(pipes[1]) != 2)
+ return(0);
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ dup2(pipes[1],1);
+ dup2(pipes[1],2);
+#endif /* OXOS */
+ close(pipes[1]); /* Don't need this any more. */
+
+#ifdef aegis
+ if ((shpath = getenv("SERVERSHELL")) == NULL)
+ shpath = "/bin/sh";
+#else
+ shpath = getenv("SHELL"); /* What shell? */
+ if (shpath == NULL) {
+ p = getpwuid( real_uid() ); /* Get login data */
+ /* debug(F111,"zxcmd shpath","getpwuid()",p); */
+ if (p == (struct passwd *)NULL || !*(p->pw_shell))
+ shpath = defshell;
+ else shpath = p->pw_shell;
+ }
+#endif /* aegis */
+ shptr = shname = shpath;
+ while (*shptr != '\0')
+ if (*shptr++ == '/')
+ shname = shptr;
+ debug(F110,shpath,shname,0);
+ restorsigs(); /* Restore ignored signals */
+ execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
+ exit(0); /* just punt if it failed. */
+ } else if (pid == (PID_T) -1) {
+ debug(F100,"zxcmd fork failure","",0);
+ return(0);
+ }
+ debug(F101,"zxcmd pid","",pid);
+ close(pipes[1]); /* Don't need the output side */
+ ispipe[filnum] = 1; /* Remember it's a pipe */
+ fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
+
+#ifdef DONDELAY
+#ifdef SELECT
+ if (filnum == ZIFILE && kactive) { /* Make pipe reads nonblocking */
+ int flags, x;
+ if ((flags = fcntl(fileno(fp[filnum]),F_GETFL,0)) > -1) {
+ debug(F101,"zxcmd fcntl 1 pipe flags","",flags);
+ x = fcntl(fileno(fp[filnum]),F_SETFL, flags |
+#ifdef QNX
+ O_NONBLOCK
+#else
+ O_NDELAY
+#endif /* QNX */
+ );
+ debug(F101,"zxcmd fcntl 2 result","",x);
+ }
+ }
+#endif /* SELECT */
+#endif /* DONDELAY */
+#endif /* SNI541 */
+ fp[ZSYSFN] = fp[filnum]; /* Remember. */
+ zincnt = 0; /* (PWP) reset input buffer */
+ zinptr = zinbuffer;
+ fullname[0] = '\0';
+ return(1);
+} /* zxcmd */
+
+/* Z C L O S F - wait for the child fork to terminate and close the pipe. */
+
+/* Used internally by zclose - returns -1 on failure, 1 on success. */
+
+int
+zclosf(filnum) int filnum; {
+ int wstat, out;
+ int statusp;
+
+ debug(F101,"zclosf filnum","",filnum);
+ out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
+ debug(F101,"zclosf out","",out);
+
+#ifndef NOPOPEN
+ if (ispipe[filnum]
+ /* In UNIX we use popen() only for output files */
+ && out
+ ) {
+ int x;
+ x = pclose(fp[filnum]);
+ pexitstat = x >> 8;
+ debug(F101,"zclosf pclose","",x);
+ debug(F101,"zclosf pexitstat","",pexitstat);
+ fp[filnum] = fp[ZSYSFN] = NULL;
+ ispipe[filnum] = 0;
+ return((x != 0) ? -1 : 1);
+ }
+#endif /* NOPOPEN */
+ /* debug(F101,"zclosf fp[filnum]","", fp[filnum]); */
+ /* debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]); */
+
+ if (pid != (PID_T) 0) {
+ debug(F101,"zclosf killing pid","",pid);
+#ifdef Plan9
+ kill(pid, SIGKILL);
+#else
+ kill(pid,9);
+#endif /* Plan9 */
+
+#ifndef CK_CHILD
+/*
+ This is the original code (before 20 April 1997) and has proven totally
+ portable. But it does not give us the process's return code.
+*/
+ while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
+#else
+/* Here we try to get the return code. Let's hope this is portable too. */
+ while ((wstat = wait(&statusp)) != pid && wstat != -1) ;
+ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
+ debug(F101,"zclosf wait statusp","",statusp);
+ debug(F101,"zclosf wait pexitstat","",pexitstat);
+#endif /* CK_CHILD */
+ pid = 0;
+ }
+ fclose(fp[filnum]);
+ fp[filnum] = fp[ZSYSFN] = NULL;
+
+ ispipe[filnum] = 0;
+ /* debug(F101,"zclosf fp[filnum]","",fp[filnum]); */
+#ifdef CK_CHILD
+ return(pexitstat == 0 ? 1 : -1);
+#else
+ return(1);
+#endif /* CK_CHILD */
+}
+
+#else /* NOPUSH */
+
+int
+zxcmd(filnum,comand) int filnum; char *comand; {
+ return(0);
+}
+int
+zclosf(filnum) int filnum; {
+ return(EOF);
+}
+#endif /* NOPUSH */
+
+
+/* Z X P A N D -- Expand a wildcard string into an array of strings */
+/*
+ As of C-Kermit 7.0, this API is obsolete, replaced by nzxpand(), and this
+ function is only used internally. See nzxpand() below.
+
+ Returns the number of files that match fnarg, with data structures set up
+ so that first file (if any) will be returned by the next znext() call.
+
+ Depends on external variable wildxpand: 0 means we expand wildcards
+ internally, nonzero means we call the shell to do it.
+
+ AND in C-Kermit 8.0.212 and later, on extern wildena: 1 means wildcards
+ are enabled, 0 means disabled, the characters are taken literally.
+*/
+static int xdironly = 0;
+static int xfilonly = 0;
+static int xmatchdot = 0;
+static int xrecursive = 0;
+static int xnobackup = 0;
+static int xnolinks = 0;
+
+static char *freeptr = NULL, **resptr = NULL; /* Copies of caller's args */
+static int remlen; /* Remaining space in caller's array */
+static int numfnd = 0; /* Number of matches found */
+
+#define MINSPACE 1024
+
+static int
+initspace(resarry,len) char * resarry[]; int len; {
+#ifdef DYNAMIC
+ if (len < MINSPACE) len = MINSPACE;
+ if (!sspace) { /* Need to allocate string space? */
+ while (len >= MINSPACE) {
+ if ((sspace = malloc(len+2))) { /* Got it. */
+ debug(F101,"fgen string space","",len);
+ break;
+ }
+ len = (len / 2) + (len / 4); /* Didn't, reduce by 3/4 */
+ }
+ if (len <= MINSPACE) { /* Did we get it? */
+ fprintf(stderr,"fgen can't malloc string space\n");
+ return(-1);
+ }
+ ssplen = len;
+ }
+#endif /* DYNAMIC */
+
+ freeptr = sspace; /* This is where matches are copied. */
+ resptr = resarry; /* Static copies of these so */
+ remlen = len; /* recursive calls can alter them. */
+ debug(F101,"initspace ssplen","",ssplen);
+ return(0);
+}
+
+/*
+ Z S E T F I L -- Query or change the size of file list buffers.
+
+ fc = 1: Change current string space to n, return new size.
+ fc = 2: Return current string space size.
+ fc = 3: Change current maxnames to n, return new maxnames.
+ fc = 4: Return current maxnames.
+ Returns < 0 on error.
+*/
+int
+zsetfil(n, fc) int n, fc; {
+#ifdef DYNAMIC
+ switch (fc) {
+ case 1: /* Stringspace */
+ if (sspace) {
+ free(sspace);
+ sspace = NULL;
+ }
+ if (initspace(mtchs,n) < 0)
+ return(-1);
+ case 2: /* Fall thru deliberately */
+ return(ssplen);
+ case 3: /* Listsize */
+ if (mtchs) {
+ free((char *)mtchs);
+ mtchs = NULL;
+ }
+ mtchs = (char **)malloc(n * sizeof(char *));
+ if (!mtchs)
+ return(-1);
+ maxnames = n;
+ case 4: /* Fall thru deliberately */
+ return(maxnames);
+ }
+#endif /* DYNAMIC */
+ return(-1);
+}
+
+
+
+#ifndef NONZXPAND
+#ifndef pdp11
+static
+#endif /* pdp11 */
+#endif /* NONZXPAND */
+int
+zxpand(fnarg) char *fnarg; {
+ extern int diractive;
+ char fnbuf[CKMAXPATH+8], * fn, * p;
+
+#ifdef DTILDE /* Built with tilde-expansion? */
+ char *tnam;
+#endif /* DTILDE */
+ int x;
+ int haveonedir = 0;
+
+ if (!fnarg) { /* If no argument provided */
+ nxpand = fcount = 0;
+ return(0); /* Return zero files found */
+ }
+ debug(F110,"zxpand entry",fnarg,0);
+ debug(F101,"zxpand xdironly","",xdironly);
+ debug(F101,"zxpand xfilonly","",xfilonly);
+
+ if (!*fnarg) { /* If no argument provided */
+ nxpand = fcount = 0;
+ return(0); /* Return zero files found */
+ }
+
+#ifdef CKROOT
+ debug(F111,"zxpand setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(fnarg)) {
+ debug(F110,"zxpand setroot violation",fnarg,0);
+ nxpand = fcount = 0;
+ return(0);
+ }
+#endif /* CKROOT */
+
+#ifdef COMMENT
+/*
+ This would have been perfect, except it makes us return fully qualified
+ pathnames for all files.
+*/
+ zfnqfp(fnarg,CKMAXPATH,fnbuf);
+ debug(F110,"zxpand zfnqfp",fnbuf,0);
+ s = zgtdir();
+ debug(F110,"zxpand zgtdir",s,0);
+ p = fnbuf;
+ while (*p && *s) /* Make it relative */
+ if (*s++ != *p++)
+ break;
+ fn = (*s) ? fnbuf : p;
+ debug(F110,"zxpand fn 0",fn,0);
+ if (!*fn) {
+ fn = fnbuf;
+ fnbuf[0] = '*';
+ fnbuf[1] = '\0';
+ }
+ debug(F110,"zxpand fn 0.5",fn,0);
+#else
+#ifdef DTILDE /* Built with tilde-expansion? */
+ if (*fnarg == '~') { /* Starts with tilde? */
+ tnam = tilde_expand(fnarg); /* Try to expand it. */
+ ckstrncpy(fnbuf,tnam,CKMAXPATH);
+ } else
+#endif /* DTILDE */
+ ckstrncpy(fnbuf,fnarg,CKMAXPATH);
+ fn = fnbuf; /* Point to what we'll work with */
+#endif /* COMMENT */
+ debug(F110,"zxpand fn 1",fn,0);
+
+ if (!*fn) /* But make sure something is there */
+ return(0);
+
+ p = fn + (int)strlen(fn) - 1;
+ if (*p == '/') { /* If last char = / it must be a dir */
+ if (!xfilonly && !iswild(p)) haveonedir++;
+ ckstrncat(fn, "*", CKMAXPATH+8); /* so append '*' */
+ } else if (p > fn) { /* If ends in "/." */
+ if (*(p-1) == '/' && *p == '.') /* change '.' to '*' */
+ *p = '*';
+ } else if (p == fn) { /* If it's '.' alone */
+ if (*p == '.') /* change '.' to '*' */
+ *p = '*';
+ }
+ debug(F110,"zxpand fn 2",fn,0);
+ x = isdir(fn); /* Is it a directory? */
+ debug(F111,"zxpand isdir 1",fn,x);
+ if (x) { /* If so, make it into a wildcard */
+ if (!xfilonly && !iswild(p))
+ haveonedir++;
+ if ((x = strlen(fn)) > 0) {
+ if (!ISDIRSEP(fn[x-1]))
+ fn[x++] = DIRSEP;
+ fn[x++] = '*';
+ fn[x] = '\0';
+ }
+ }
+ debug(F111,"zxpand fn 3 haveonedir",fn,haveonedir);
+/*
+ The following allows us to parse a single directory name without opening
+ the directory and looking at its contents. The diractive flag is a horrible
+ hack (especially since DIR /NORECURSIVE turns it off), but otherwise we'd
+ have to change the API.
+*/
+ debug(F111,"zxpand fn 3 diractive",fn,diractive);
+ if (!diractive && haveonedir) {
+ fcount = 0;
+ if (!mtchs) {
+ mtchs = (char **)malloc(maxnames * sizeof(*mtchs));
+ if (!mtchs)
+ return(nxpand = fcount);
+ }
+ fcount = 1;
+ debug(F110,"zxpand haveonedir A1",fnarg,0);
+ initspace(mtchs,ssplen);
+ addresult(fnarg,1);
+ if (numfnd < 0) return(-1);
+ mtchptr = mtchs; /* Save pointer for next. */
+ debug(F111,"zxpand haveonedir A2",*mtchptr,numfnd);
+ return(nxpand = fcount);
+ }
+
+#ifndef NOPUSH
+ if (!nopush && wildxpand) /* Who is expanding wildcards? */
+ fcount = (mtchs == NULL && /* Shell */
+ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
+ ? 0
+ : shxpand(fn,mtchs,maxnames);
+ else
+#endif /* NOPUSH */
+ fcount = (mtchs == NULL && /* Kermit */
+ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
+ ? 0
+ : fgen(fn,mtchs,maxnames); /* Look up the file. */
+
+ if (fcount == 0 && haveonedir) {
+ fcount = 1;
+ debug(F110,"zxpand haveonedir B",fnarg,0);
+ addresult(fnarg,1);
+ if (numfnd < 0) return(-1);
+ }
+ mtchptr = mtchs; /* Save pointer for next. */
+ nxpand = fcount;
+
+#ifdef DEBUG
+ if (deblog) {
+ if (fcount > 1)
+ debug(F111,"zxpand ok",mtchs[0],fcount);
+ else
+ debug(F101,"zxpand fcount","",fcount);
+ }
+#endif /* DEBUG */
+ return(fcount);
+}
+
+#ifndef NONZXPAND
+/* N Z X P A N D -- Expand a file list, with options. */
+/*
+ Call with:
+ s = pointer to filename or pattern.
+ flags = option bits:
+
+ flags & ZX_FILONLY Match regular files
+ flags & ZX_DIRONLY Match directories
+ flags & ZX_RECURSE Descend through directory tree
+ flags & ZX_MATCHDOT Match "dot files"
+ flags & ZX_NOBACKUP Don't match "backup files"
+ flags & ZX_NOLINKS Don't follow symlinks.
+
+ Returns the number of files that match s, with data structures set up
+ so that first file (if any) will be returned by the next znext() call.
+*/
+int
+nzxpand(s,flags) char * s; int flags; {
+ char * p;
+ int x;
+
+ debug(F111,"nzxpand",s,flags);
+ x = flags & (ZX_DIRONLY|ZX_FILONLY);
+ xdironly = (x == ZX_DIRONLY);
+ xfilonly = (x == ZX_FILONLY);
+ if (xdironly && xfilonly) {
+ xdironly = 0;
+ xfilonly = 0;
+ }
+ xmatchdot = (flags & ZX_MATCHDOT);
+ debug(F111,"nzxpand xmatchdot 1",s,xmatchdot);
+ /* If xmatchdot not set by caller but pattern implies it, set it anyway */
+ if (!xmatchdot && ((p = ckstrchr(s,'.')))) {
+ if (p == s && p[1] != '/') {
+ xmatchdot = 1;
+ debug(F111,"nzxpand xmatchdot 2",s,xmatchdot);
+ } else if (p > s) {
+ xmatchdot = (*(p-1) == ',') || (*(p-1) == '{') || (*(p-1) == '/');
+ debug(F111,"nzxpand xmatchdot 3",s,xmatchdot);
+ }
+ }
+ xrecursive = (flags & ZX_RECURSE);
+ xnobackup = (flags & ZX_NOBACKUP);
+ xnolinks = (flags & ZX_NOLINKS);
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"nzxpand xdironly","",xdironly);
+ debug(F101,"nzxpand xfilonly","",xfilonly);
+ debug(F101,"nzxpand xmatchdot","",xmatchdot);
+ debug(F101,"nzxpand xrecursive","",xrecursive);
+ debug(F101,"nzxpand xnobackup","",xnobackup);
+ debug(F101,"nzxpand xnolinks","",xnolinks);
+ }
+#endif /* DEBUG */
+
+ x = zxpand(s);
+ if (x > 1)
+ sh_sort(mtchs,NULL,x,0,0,1); /* Alphabetize the list */
+ xdironly = 0;
+ xfilonly = 0;
+ xmatchdot = 0;
+ xrecursive = 0;
+ xnobackup = 0;
+ xnolinks = 0;
+ return(x);
+}
+#endif /* NONZXPAND */
+
+#ifndef NOZXREWIND
+/* Z X R E W I N D -- Rewinds the zxpand() list */
+
+int
+zxrewind() {
+ /* if (!mtchs) return(-1); */
+ fcount = nxpand;
+ mtchptr = mtchs;
+ return(nxpand);
+}
+#endif /* NOZXREWIND */
+
+/* Z N E X T -- Get name of next file from list created by zxpand(). */
+/*
+ Returns >0 if there's another file, with its name copied into the arg string,
+ or 0 if no more files in list.
+*/
+int
+znext(fn) char *fn; {
+ if (fcount-- > 0) {
+ ckstrncpy(fn,*mtchptr++,CKMAXPATH);
+ } else {
+ fn[0] = '\0';
+ }
+#ifndef COMMENT
+ debug(F111,"znext",fn,fcount+1);
+ return(fcount+1);
+#else
+ debug(F111,"znext",fn,fcount); /* Return 0 if no filename to return */
+ return(fcount);
+#endif /* COMMENT */
+}
+
+/* Z C H K S P A -- Check if there is enough space to store the file */
+
+/*
+ Call with file specification f, size n in bytes.
+ Returns -1 on error, 0 if not enough space, 1 if enough space.
+*/
+/*ARGSUSED*/
+int
+#ifdef CK_ANSIC
+zchkspa(char *f, CK_OFF_T n)
+#else
+zchkspa(f,n) char *f; CK_OFF_T n;
+#endif /* CK_ANSIC */
+/* zchkspa() */ {
+ /* In UNIX there is no good (and portable) way. */
+ return(1); /* Always say OK. */
+}
+
+#ifdef COMMENT /* (not used) */
+
+/* I S B A C K U P -- Tells if given file has a backup suffix */
+/*
+ Returns:
+ -1: Invalid argument
+ 0: File does not have a backup suffix
+ >0: Backup suffix number
+*/
+int
+isbackup(fn) char * fn; { /* Get backup suffix number */
+ int i, j, k, x, state, flag;
+
+ if (!fn) /* Watch out for null pointers. */
+ return(-1);
+ if (!*fn) /* And empty names. */
+ return(-1);
+
+ flag = state = 0;
+ for (i = (int)strlen(fn) - 1; (!flag && (i > 0)); i--) {
+ switch (state) {
+ case 0: /* State 0 - final char */
+ if (fn[i] == '~') /* Is tilde */
+ state = 1; /* Switch to next state */
+ else /* Otherwise */
+ flag = 1; /* Quit - no backup suffix. */
+ break;
+ case 1: /* State 1 - digits */
+ if (fn[i] == '~' && fn[i-1] == '.') { /* Have suffix */
+ return(atoi(&fn[i+1]));
+ } else if (fn[i] >= '0' && fn[i] <= '9') { /* In number part */
+ continue; /* Keep going */
+ } else { /* Something else */
+ flag = 1; /* Not a backup suffix - quit. */
+ }
+ break;
+ }
+ }
+ return(0);
+}
+#endif /* COMMENT */
+
+
+/* Z N E W N -- Make a new name for the given file */
+
+/*
+ Given the name, fn, of a file that already exists, this function builds a
+ new name of the form "<oldname>.~<n>~", where <oldname> is argument name
+ (fn), and <n> is a version number, one higher than any existing version
+ number for that file, up to 99999. This format is consistent with that used
+ by GNU EMACS. If the constructed name is too long for the system's maximum,
+ enough characters are truncated from the end of <fn> to allow the version
+ number to fit. If no free version numbers exist between 1 and 99999, a
+ version number of "xxxx" is used. Returns a pointer to the new name in
+ argument s.
+*/
+#ifdef pdp11
+#define ZNEWNBL 63 /* Name buffer length */
+#define ZNEWNMD 3 /* Max digits for version number */
+#else
+#define ZNEWNBL CKMAXPATH
+#define ZNEWNMD 4
+#endif /* pdp11 */
+
+#define MAXBUDIGITS 5
+
+static char znewbuf[ZNEWNBL+12];
+
+VOID
+znewn(fn,s) char *fn, **s; {
+ char * buf; /* Pointer to buffer for new name */
+ char * xp, * namepart = NULL; /* Pointer to filename part */
+ struct zfnfp * fnfp; /* znfqfp() result struct pointer */
+ int d = 0, t, fnlen, buflen;
+ int n, i, k, flag, state;
+ int max = MAXNAMLEN; /* Maximum name length */
+ char * dname = NULL;
+
+ buf = znewbuf;
+ *s = NULL; /* Initialize return value */
+ if (!fn) fn = ""; /* Check filename argument */
+ i = strlen(fn);
+
+/* If incoming file already has a backup suffix, remove it. */
+/* Then we'll tack a new on later, which will be the highest for this file. */
+
+ if (i <= max && i > 0 && fn[i-1] == '~') {
+ char * p;
+ i--;
+ debug(F111,"znewn suffix removal",fn,i);
+ if ((dname = (char *)malloc(i+1))) {
+ ckstrncpy(dname,fn,i+1);
+ p = dname;
+ for (flag = state = 0; (!flag && (i > 0)); i--) {
+ switch (state) {
+ case 0: /* State 0 - final char */
+ if (p[i] == '~') /* Is tilde */
+ state = 1; /* Switch to next state */
+ else /* Otherwise */
+ flag = 1; /* Quit - no backup suffix. */
+ break;
+ case 1: /* State 1 - digits */
+ if (p[i] == '~' && p[i-1] == '.') { /* Have suffix */
+ p[i-1] = NUL; /* Trim it */
+ fn = dname;
+ debug(F111,"znewn suffix removal 2",fn,i);
+ flag = 1; /* done */
+ } else if (p[i] >= '0' && p[i] <= '9') { /* Number part */
+ continue; /* Keep going */
+ } else { /* Something else */
+ flag = 1; /* Not a backup suffix - quit. */
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ((fnlen = strlen(fn)) < 1) { /* Get length */
+ if (dname) free(dname);
+ return;
+ }
+ debug(F111,"znewn",fn,fnlen);
+
+ debug(F101,"znewn max 1","",max);
+ if (max < 14) max = 14; /* Make max reasonable for any UNIX */
+ if (max > ZNEWNBL) max = ZNEWNBL;
+ debug(F101,"znewn max 2","",max);
+
+ if ((fnfp = zfnqfp(fn, ZNEWNBL, buf))) { /* Get fully qualified name */
+ namepart = fnfp->fname; /* Isolate the filename */
+ k = strlen(fn); /* Length of name part */
+ debug(F111,"znewn namepart",namepart,k);
+ } else {
+ if (dname) free(dname);
+ return;
+ }
+ buflen = fnfp->len; /* Length of fully qualified name */
+ debug(F111,"znewn len",buf,buflen);
+
+ if (k + MAXBUDIGITS + 3 < max) { /* Backup name fits - no overflow */
+ /* Make pattern for backup names */
+ ckstrncpy(buf+buflen,".~*~",ZNEWNBL+12-buflen);
+ n = nzxpand(buf,ZX_FILONLY); /* Expand the pattern */
+ debug(F111,"znewn A matches",buf,n);
+ while (n-- > 0) { /* Find any existing name.~n~ files */
+ xp = *mtchptr++; /* Point at matching name */
+ t = atoi(xp+buflen+2); /* Get number */
+ if (t > d) d = t; /* Save d = highest version number */
+ }
+ sprintf(buf+buflen,".~%d~",d+1); /* Yes, make "name.~<d+1>~" */
+ debug(F110,"znewn A newname",buf,0);
+ } else { /* Backup name would be too long */
+ int xlen; /* So we have to eat back into it */
+ int delta;
+ char buf2[ZNEWNBL+12];
+
+ delta = max - k;
+ debug(F101,"znewn B delta","",delta);
+
+ for (i = MAXBUDIGITS; i > 0; i--) { /* In this case the format of */
+ ckstrncpy(buf2,buf,ZNEWNBL+12); /* the backup name depends on */
+ xlen = buflen - i - 3 + delta; /* how many digits are in the */
+ ckstrncpy(buf2+xlen,".~*~",ZNEWNBL+12-xlen); /* backup number */
+ n = nzxpand(buf2,ZX_FILONLY);
+ debug(F111,"znewn B matches",buf2,n);
+ if (n > 0)
+ break;
+ }
+ while (n-- > 0) { /* Find any existing name.~n~ files */
+ xp = *mtchptr++; /* Point at matching name */
+ t = atoi(xp+xlen+2); /* Get number */
+ if (t > d) d = t; /* Save d = highest version number */
+ }
+ if (d > 0) /* If the odometer turned over... */
+ if ((d % 10) == 9) /* back up one space. */
+ xlen--;
+ sprintf(buf2+xlen,".~%d~",d+1); /* This just fits */
+ ckstrncpy(buf,buf2,ZNEWNBL+12); /* (we could be more clever here...) */
+ debug(F110,"znewn B new name",buf,0);
+ }
+ *s = buf; /* Point to new name */
+ ck_znewn = d+1; /* Also make it available globally */
+ if (dname) free(dname);
+ return;
+}
+
+/* Z R E N A M E -- Rename a file */
+/*
+ Call with old and new names.
+ If new name is the name of a directory, the 'old' file is moved to
+ that directory.
+ Returns 0 on success, -1 on failure.
+*/
+int
+zrename(old,new) char *old, *new; {
+ char *p, *s;
+ int x;
+
+ if (!old) old = "";
+ if (!new) new = "";
+ debug(F110,"zrename old",old,0);
+ debug(F110,"zrename new",new,0);
+ if (!*old) return(-1);
+ if (!*new) return(-1);
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return(-1);
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+#ifdef CKROOT
+ debug(F111,"zrename setroot",ckroot,ckrootset);
+ if (ckrootset) {
+ if (!zinroot(old)) {
+ debug(F110,"zrename old: setroot violation",old,0);
+ return(-1);
+ }
+ if (!zinroot(new)) {
+ debug(F110,"zrename new: setroot violation",new,0);
+ return(-1);
+ }
+ }
+#endif /* CKROOT */
+
+ p = NULL;
+ s = new;
+
+ if (isdir(new)) {
+ char *q = NULL;
+ x = strlen(new);
+ if (!(p = malloc(strlen(new) + strlen(old) + 2)))
+ return(-1);
+ strcpy(p,new); /* (safe) Directory part */
+ if (!ISDIRSEP(*(new+x-1))) /* Separator, if needed */
+ strcat(p,"/"); /* (safe) */
+ zstrip(old,&q); /* Strip path part from old name */
+ strcat(p,q); /* cat to new directory (safe) */
+ s = p;
+ debug(F110,"zrename dir",s,0);
+ }
+#ifdef DEBUG
+ else debug(F110,"zrename no dir",s,0);
+#endif /* DEBUG */
+
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_del))) {
+ if (zchki(s) > -1) /* Destination file exists? */
+ return(-1);
+ }
+#endif /* IKSD */
+
+ x = -1; /* Return code. */
+#ifdef RENAME
+/* Atomic, preferred, uses a single system call, rename(), if available. */
+ x = rename(old,s);
+ debug(F111,"zrename rename()",old,x);
+ if (x) x = -1;
+#endif /* RENAME */
+
+ /* If rename() failed or not available try link()/unlink() */
+
+ if (x < 0) {
+ if (zchko(old) > -1) { /* Requires write access to orignal */
+ x = link(old,s);
+ debug(F111,"zrename link()",old,x);
+ if (x > -1) { /* Make a link with the new name. */
+ x = unlink(old);
+ debug(F111,"zrename unlink()",old,x);
+ }
+ /* If link/unlink failed copy and delete */
+ if (x < 0) {
+ x = zcopy(old,s);
+ debug(F111,"zrename zcopy()",old,x);
+ if (x > -1) {
+ x = zdelet(old);
+ debug(F111,"zrename zdelet()",old,x);
+ }
+ }
+ }
+ }
+ fullname[0] = '\0'; /* Clear this out for next time. */
+
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging) {
+ zfnqfp(old,CKMAXPATH,fullname);
+ tmp2[0] = '\0';
+ zfnqfp(s,CKMAXPATH,tmp2);
+ if (x > -1)
+ syslog(LOG_INFO,"file[] %s: renamed to %s ok", fullname, tmp2);
+ else
+ syslog(LOG_INFO,"file[] %s: rename to %s failed (%m)",fullname,tmp2);
+ }
+#endif /* CKSYSLOG */
+
+ if (p) free(p);
+ return(x);
+}
+
+/* Z C O P Y -- Copy a single file. */
+/*
+ Call with source and destination names.
+ If destination is a directory, the source file is
+ copied to that directory with its original name.
+ Returns:
+ 0 on success.
+ <0 on failure:
+ -2 = source file is not a regular file.
+ -3 = source file not found.
+ -4 = permission denied.
+ -5 = source and destination are the same file.
+ -6 = i/o error.
+ -1 = other error.
+*/
+int
+zcopy(source,destination) char *source, *destination; {
+ char *src, *dst; /* Local pointers to filenames */
+ int x, y, rc; /* Workers */
+ int in = -1, out = -1; /* i/o file descriptors */
+ struct stat srcbuf; /* Source file info buffer */
+ int perms; /* Output file permissions */
+ char buf[1024]; /* File copying buffer */
+
+ if (!source) source = "";
+ if (!destination) destination = "";
+
+ debug(F110,"zcopy src arg",source,0);
+ debug(F110,"zcopy dst arg",destination,0);
+
+ if (!*source) return(-1);
+ if (!*destination) return(-1);
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return(-4);
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+#ifdef CKROOT
+ debug(F111,"zcopy setroot",ckroot,ckrootset);
+ if (ckrootset) {
+ if (!zinroot(source)) {
+ debug(F110,"zcopy source: setroot violation",source,0);
+ return(-1);
+ }
+ if (!zinroot(destination)) {
+ debug(F110,"zcopy destination: setroot violation",destination,0);
+ return(-1);
+ }
+ }
+#endif /* CKROOT */
+
+ src = source;
+ dst = destination;
+
+ if (stat(src,&srcbuf) == 0) { /* Get source file info */
+ struct stat dstbuf; /* Destination file info buffer */
+ debug(F101,"STAT","",6);
+ if (stat(dst,&dstbuf) == 0) {
+ debug(F101,"STAT","",7);
+ if (srcbuf.st_dev == dstbuf.st_dev)
+ if (srcbuf.st_ino == dstbuf.st_ino) {
+ debug(F100,"zcopy files identical: stat()","",0);
+ return(-5);
+ }
+ }
+ } else { /* stat() failed... */
+ debug(F101,"STAT","",8);
+ debug(F111,"source file not found",src,errno);
+ return(-3);
+ }
+ fullname[0] = '\0'; /* Get full pathnames */
+ if (zfnqfp(source,CKMAXPATH,fullname))
+ src = fullname;
+ debug(F110,"zcopy src",src,0);
+ tmp2[0] = '\0';
+ if (zfnqfp(destination,CKMAXPATH,tmp2))
+ dst = tmp2;
+ debug(F110,"zcopy dst 1",dst,0);
+ if (!strcmp(src,dst)) { /* Src and dst are same file? */
+ debug(F100,"zcopy files identical: strcmp()","",0); /* This... */
+ return(-5); /* should not happen. */
+ }
+ if (isdir(src)) { /* Source file is a directory? */
+ debug(F110,"zcopy source is directory",src,0);
+ return(-2); /* Fail */
+ }
+ if (isdir(dst)) { /* Destination is a directory? */
+ char *q = NULL; /* Yes, add filename to it. */
+ x = strlen(dst);
+ if (x < 1) return(-1);
+ if (!ISDIRSEP(*(dst+x-1))) { /* Add separator if needed */
+ tmp2[x++] = '/';
+ tmp2[x] = '\0';
+ }
+ debug(F111,"zcopy dst 2",dst,x);
+ zstrip(src,&q); /* Strip path part from old name */
+ ckstrncpy(tmp2+x,q,CKMAXPATH-x); /* Concatenate it to new name */
+ }
+ debug(F110,"zcopy dst 3",dst,0);
+
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_del))) {
+ if (zchki(dst) > -1) /* Destination file exists? */
+ return(-4);
+ }
+#endif /* IKSD */
+
+ perms = umask(0); /* Get user's umask */
+ umask(perms); /* Put it back! */
+ perms ^= 0777; /* Flip the bits */
+ perms &= 0666; /* Zero execute bits from umask */
+ perms |= (srcbuf.st_mode & 0111); /* OR in source file's execute bits */
+ rc = -1; /* Default return code */
+ errno = 0; /* Reset errno */
+ in = open(src, O_RDONLY, 0); /* Open source file */
+ debug(F111,"zcopy open source",src,in);
+ if (in > -1) { /* If open... */
+ /* Open destination file */
+#ifdef O_TRUNC
+ out = open(dst, O_WRONLY|O_CREAT|O_TRUNC, perms);
+#else
+ out = open(dst, O_WRONLY|O_CREAT, perms);
+#endif /* O_TRUNC */
+ debug(F111,"zcopy open dest",dst,out);
+ if (out > -1) { /* If open... */
+ while ((x = read(in,buf,1024)) > 0) { /* Copy in 1K blocks */
+ y = write(out,buf,x);
+ if (y < 0) { /* On write failure */
+ x = -1;
+ rc = -6; /* Indicate i/o error */
+ break;
+ }
+ }
+ debug(F101,"zcopy final read","",x);
+ debug(F101,"zcopy errno","",errno);
+ rc = (x == 0) ? 0 : -6; /* In case of read failure */
+ }
+ }
+ if (in > -1) close(in); /* Close files */
+ if (out > -1) close(out);
+ if (rc == -1) { /* Set return code */
+ switch (errno) {
+ case ENOENT: rc = -3; break;
+ case EACCES: rc = -4; break;
+ case EIO: rc = -6;
+ }
+ }
+
+#ifdef CKSYSLOG
+ if (rc > -1 && ckxsyslog >= SYSLG_FC && ckxlogging) {
+ if (rc)
+ syslog(LOG_INFO,"file[] %s: copy to %s failed (%m)", fullname, tmp2);
+ else
+ syslog(LOG_INFO,"file[] %s: copy to %s ok", fullname, tmp2);
+ }
+#endif /* CKSYSLOG */
+
+ return(rc);
+}
+
+/* Z S A T T R */
+/*
+ Fills in a Kermit file attribute structure for the file which is to be sent.
+ Returns 0 on success with the structure filled in, or -1 on failure.
+ If any string member is null, then it should be ignored.
+ If any numeric member is -1, then it should be ignored.
+*/
+#ifdef CK_PERMS
+
+#ifdef CK_GPERMS
+#undef CK_GPERMS
+#endif /* CK_GPERMS */
+
+#ifdef UNIX
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif /* S_IRUSR */
+#ifndef S_IWUSR
+#define S_IXUSR 0200
+#endif /* S_IWUSR */
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif /* S_IXUSR */
+#endif /* UNIX */
+
+#ifdef S_IRUSR
+#ifdef S_IWUSR
+#ifdef S_IXUSR
+#define CK_GPERMS
+#endif /* S_IXUSR */
+#endif /* S_IWUSR */
+#endif /* S_IRUSR */
+
+static char gperms[2];
+
+#endif /* CK_GPERMS */
+
+static char lperms[24];
+
+#ifdef CK_PERMS
+static char xlperms[24];
+
+/* Z S E T P E R M -- Set permissions of a file */
+
+int
+zsetperm(f,code) char * f; int code; {
+ int x;
+#ifdef CK_SCO32V4
+ mode_t mask;
+#else
+ int mask;
+#endif /* CK_SCO32V4 */
+ mask = code;
+ if (inserver && guest) {
+ debug(F110,"zsetperm guest",f,0);
+ return(0);
+ }
+ x = chmod(f,mask);
+ if (x < 0) {
+ debug(F111,"zsetperm error",f,errno);
+ return(0);
+ }
+ debug(F111,"zsetperm ok",f,mask);
+ return(1);
+}
+
+/* Z G P E R M -- Get permissions of a file as an octal string */
+
+char *
+zgperm(f) char *f; {
+ extern int diractive;
+ int x; char *s = (char *)xlperms;
+ struct stat buf;
+ debug(F110,"zgperm",f,0);
+ if (!f) return("----------");
+ if (!*f) return("----------");
+
+#ifdef CKROOT
+ debug(F111,"zgperm setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zgperm setroot violation",f,0);
+ return("----------");
+ }
+#endif /* CKROOT */
+
+#ifdef USE_LSTAT
+ if (diractive)
+ x = lstat(f,&buf);
+ else
+#endif /* USE_LSTAT */
+ x = stat(f,&buf);
+ debug(F101,"STAT","",9);
+ if (x < 0)
+ return("----------");
+ sprintf(s,"%o",buf.st_mode);
+ debug(F110,"zgperm",s,0);
+ return(s);
+}
+
+/* Like zgperm() but returns permissions in "ls -l" string format */
+
+static char xsperms[24];
+
+char *
+ziperm(f) char * f; {
+ extern int diractive;
+ int x; char *s = (char *)xsperms;
+ struct stat buf;
+ unsigned int perms = 0;
+
+ debug(F110,"ziperm",f,0);
+
+ if (!f) return(NULL);
+ if (!*f) return(NULL);
+
+ if (diractive && zgfs_mode != 0) {
+ perms = zgfs_mode; /* zgetfs() already got them */
+ } else {
+#ifdef USE_LSTAT
+ if (diractive)
+ x = lstat(f,&buf);
+ else
+#endif /* USE_LSTAT */
+ x = stat(f,&buf);
+ debug(F101,"STAT","",10);
+ if (x < 0)
+ return("----------");
+ perms = buf.st_mode;
+ }
+ switch (perms & S_IFMT) {
+ case S_IFDIR:
+ *s++ = 'd';
+ break;
+ case S_IFCHR: /* Character special */
+ *s++ = 'c';
+ break;
+ case S_IFBLK: /* Block special */
+ *s++ = 'b';
+ break;
+ case S_IFREG: /* Regular */
+ *s++ = '-';
+ break;
+#ifdef S_IFLNK
+ case S_IFLNK: /* Symbolic link */
+ *s++ = 'l';
+ break;
+#endif /* S_IFLNK */
+#ifdef S_IFSOCK
+ case S_IFSOCK: /* Socket */
+ *s++ = 's';
+ break;
+#endif /* S_IFSOCK */
+#ifdef S_IFIFO
+#ifndef Plan9
+#ifndef COHERENT
+ case S_IFIFO: /* FIFO */
+ *s++ = 'p';
+ break;
+#endif /* COHERENT */
+#endif /* Plan9 */
+#endif /* S_IFIFO */
+#ifdef S_IFWHT
+ case S_IFWHT: /* Whiteout */
+ *s++ = 'w';
+ break;
+#endif /* S_IFWHT */
+ default: /* Unknown */
+ *s++ = '?';
+ break;
+ }
+ if (perms & S_IRUSR) /* Owner's permissions */
+ *s++ = 'r';
+ else
+ *s++ = '-';
+ if (perms & S_IWUSR)
+ *s++ = 'w';
+ else
+ *s++ = '-';
+ switch (perms & (S_IXUSR | S_ISUID)) {
+ case 0:
+ *s++ = '-';
+ break;
+ case S_IXUSR:
+ *s++ = 'x';
+ break;
+ case S_ISUID:
+ *s++ = 'S';
+ break;
+ case S_IXUSR | S_ISUID:
+ *s++ = 's';
+ break;
+ }
+ if (perms & S_IRGRP) /* Group permissions */
+ *s++ = 'r';
+ else
+ *s++ = '-';
+ if (perms & S_IWGRP)
+ *s++ = 'w';
+ else
+ *s++ = '-';
+ switch (perms & (S_IXGRP | S_ISGID)) {
+ case 0:
+ *s++ = '-';
+ break;
+ case S_IXGRP:
+ *s++ = 'x';
+ break;
+ case S_ISGID:
+ *s++ = 'S';
+ break;
+ case S_IXGRP | S_ISGID:
+ *s++ = 's';
+ break;
+ }
+ if (perms & S_IROTH) /* World permissions */
+ *s++ = 'r';
+ else
+ *s++ = '-';
+ if (perms & S_IWOTH)
+ *s++ = 'w';
+ else
+ *s++ = '-';
+ switch (
+#ifdef Plan9
+ perms & (S_IXOTH)
+#else
+ perms & (S_IXOTH | S_ISVTX)
+#endif
+ ) {
+ case 0:
+ *s++ = '-';
+ break;
+ case S_IXOTH:
+ *s++ = 'x';
+ break;
+#ifndef Plan9
+ case S_ISVTX:
+ *s++ = 'T';
+ break;
+ case S_IXOTH | S_ISVTX:
+ *s++ = 't';
+ break;
+#endif /* Plan9 */
+ }
+ *s = '\0';
+ debug(F110,"ziperm",xsperms,0);
+ return((char *)xsperms);
+}
+
+#else
+
+char *
+zgperm(f) char *f; {
+ return("----------");
+}
+char *
+ziperms(f) char *f; {
+ return("----------");
+}
+#endif /* CK_PERMS */
+
+int
+zsattr(xx) struct zattr *xx; {
+ CK_OFF_T k; int x;
+ struct stat buf;
+
+ k = iflen % 1024; /* File length in K */
+ if (k) k = 1L;
+ xx->lengthk = (iflen / 1024) + k;
+ xx->type.len = 0; /* File type can't be filled in here */
+ xx->type.val = "";
+ if (*nambuf) {
+ xx->date.val = zfcdat(nambuf); /* File creation date */
+ xx->date.len = (int)strlen(xx->date.val);
+ } else {
+ xx->date.len = 0;
+ xx->date.val = "";
+ }
+ xx->creator.len = 0; /* File creator */
+ xx->creator.val = "";
+ xx->account.len = 0; /* File account */
+ xx->account.val = "";
+ xx->area.len = 0; /* File area */
+ xx->area.val = "";
+ xx->password.len = 0; /* Area password */
+ xx->password.val = "";
+ xx->blksize = -1L; /* File blocksize */
+ xx->xaccess.len = 0; /* File access */
+ xx->xaccess.val = "";
+ xx->encoding.len = 0; /* Transfer syntax */
+ xx->encoding.val = 0;
+ xx->disp.len = 0; /* Disposition upon arrival */
+ xx->disp.val = "";
+ xx->lprotect.len = 0; /* Local protection */
+ xx->lprotect.val = "";
+ xx->gprotect.len = 0; /* Generic protection */
+ xx->gprotect.val = "";
+ x = -1;
+ if (*nambuf) x = stat(nambuf,&buf);
+ debug(F101,"STAT","",11);
+ if (x >= 0) {
+ debug(F111,"zsattr buf.st_mode & 0777",nambuf,buf.st_mode & 0777);
+ /* UNIX filemode as an octal string without filetype bits */
+ sprintf(lperms,"%o",buf.st_mode & 0777);
+ xx->lprotect.len = (int)strlen(lperms);
+ xx->lprotect.val = (char *)lperms;
+ x = 0;
+#ifdef CK_GPERMS
+ /* Generic permissions only if we have stat.h symbols defined */
+ if (buf.st_mode & S_IRUSR) x |= 1; /* Read */
+ if (buf.st_mode & S_IWUSR) x |= (2+16); /* Write and Delete */
+ if (buf.st_mode & S_IXUSR) x |= 4; /* Execute */
+ gperms[0] = tochar(x);
+ gperms[1] = NUL;
+ xx->gprotect.len = 1;
+ xx->gprotect.val = (char *)gperms;
+#endif /* CK_GPERMS */
+ }
+ debug(F111,"zsattr lperms",xx->lprotect.val,xx->lprotect.len);
+ debug(F111,"zsattr gperms",xx->gprotect.val,xx->gprotect.len);
+ xx->systemid.val = "U1"; /* U1 = UNIX */
+ xx->systemid.len = 2; /* System ID */
+ xx->recfm.len = 0; /* Record format */
+ xx->recfm.val = "";
+ xx->sysparam.len = 0; /* System-dependent parameters */
+ xx->sysparam.val = "";
+ xx->length = iflen; /* Length */
+ return(0);
+}
+
+/* Z F C D A T -- Get file creation date */
+/*
+ Call with pointer to filename.
+ On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
+ On failure, returns pointer to null string.
+*/
+static char datbuf[40];
+
+char *
+#ifdef CK_ANSIC
+zdtstr(time_t timearg)
+#else
+zdtstr(timearg) time_t timearg;
+#endif /* CK_ANSIC */
+/* zdtstr */ {
+#ifndef TIMESTAMP
+ return("");
+#else
+ struct tm * time_stamp;
+ struct tm * localtime();
+ int yy, ss;
+
+ debug(F101,"zdtstr timearg","",timearg);
+ if (timearg < 0)
+ return("");
+ time_stamp = localtime(&(timearg));
+ if (!time_stamp) {
+ debug(F100,"localtime returns null","",0);
+ return("");
+ }
+/*
+ We assume that tm_year is ALWAYS years since 1900.
+ Any platform where this is not the case will have problems
+ starting in 2000.
+*/
+ yy = time_stamp->tm_year; /* Year - 1900 */
+ debug(F101,"zdtstr tm_year","",time_stamp->tm_year);
+ if (yy > 1000) {
+ debug(F101,"zstrdt YEAR-2000 ALERT 1: localtime year","",yy);
+ }
+ yy += 1900;
+ debug(F101,"zdatstr year","",yy);
+
+ if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
+ return("");
+ if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
+ return("");
+ if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
+ return("");
+ if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59)
+ return("");
+ ss = time_stamp->tm_sec; /* Seconds */
+ if (ss < 0 || ss > 59) /* Some systems give a BIG number */
+ ss = 0;
+ sprintf(datbuf,
+#ifdef pdp11
+/* For some reason, 2.1x BSD sprintf gets the last field wrong. */
+ "%04d%02d%02d %02d:%02d:00",
+#else
+ "%04d%02d%02d %02d:%02d:%02d",
+#endif /* pdp11 */
+ yy,
+ time_stamp->tm_mon + 1,
+ time_stamp->tm_mday,
+ time_stamp->tm_hour,
+ time_stamp->tm_min
+#ifndef pdp11
+ , ss
+#endif /* pdp11 */
+ );
+ yy = (int)strlen(datbuf);
+ debug(F111,"zdatstr",datbuf,yy);
+ if (yy > 17) datbuf[17] = '\0';
+ return(datbuf);
+#endif /* TIMESTAMP */
+}
+
+char *
+zfcdat(name) char *name; {
+#ifdef TIMESTAMP
+ struct stat buffer;
+ extern int diractive;
+ unsigned int mtime;
+ int x;
+ char * s;
+
+ if (!name)
+ return("");
+ s = name;
+ if (!*s)
+ return("");
+
+#ifdef CKROOT
+ debug(F111,"zfcdat setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zfcdat setroot violation",name,0);
+ return("");
+ }
+#endif /* CKROOT */
+
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ }
+#endif /* DTILDE */
+
+ datbuf[0] = '\0';
+ x = 0;
+ debug(F111,"zfcdat",s,diractive);
+
+ if (diractive && zgfs_mtime) {
+ mtime = zgfs_mtime;
+ } else {
+#ifdef USE_LSTAT
+ if (diractive) {
+ x = lstat(s,&buffer);
+ debug(F101,"STAT","",12);
+ debug(F101,"zfcdat lstat","",x);
+ } else {
+#endif /* USE_LSTAT */
+ x = stat(s,&buffer);
+ debug(F101,"STAT","",13);
+ debug(F101,"zfcdat stat","",x);
+#ifdef USE_LSTAT
+ }
+#endif /* USE_LSTAT */
+ if (x != 0) {
+#ifdef USE_LSTAT
+ debug(F111,"zfcdat stat failed",s,errno);
+#else
+ debug(F111,"zfcdat lstat failed",s,errno);
+#endif /* USE_LSTAT */
+ return("");
+ }
+ debug(F101,"zfcdat buffer.st_mtime","",buffer.st_mtime);
+ mtime = buffer.st_mtime;
+ }
+ return(zdtstr(mtime));
+#else
+ return("");
+#endif /* TIMESTAMP */
+}
+
+#ifndef NOTIMESTAMP
+
+/* Z S T R D T -- Converts local date string to internal representation */
+/*
+ In our case (UNIX) this is seconds since midnite 1 Jan 1970 UTC,
+ suitable for comparison with UNIX file dates. As far as I know, there is
+ no library or system call -- at least nothing reasonably portable -- to
+ convert local time to UTC.
+*/
+time_t
+zstrdt(date,len) char * date; int len; {
+#ifdef M_UNIX
+/*
+ SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
+ ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
+ dependence on the XPG4 supplement presence. So always use
+ what the system header file supplies in ODT 3.0...
+*/
+#ifndef ODT30
+#ifndef _SCO_DS
+ extern void ftime(); /* extern void ftime(struct timeb *) */
+#endif /* _SCO_DS */
+#endif /* ODT30 */
+#else
+#ifndef M_XENIX
+ extern int ftime();
+#endif /* M_XENIX */
+#endif /* M_UNIX */
+ extern struct tm * localtime();
+
+ /* And this should have been declared always through a header file */
+#ifdef HPUX10
+ time_t tmx;
+ long days;
+#else
+#ifdef BSD44
+ time_t tmx;
+ long days;
+#else
+ long tmx, days;
+#endif /* BSD44 */
+#endif /* HPUX10 */
+ int i, n, isleapyear;
+ /* J F M A M J J A S O N D */
+ /* 31 28 31 30 31 30 31 31 30 31 30 31 */
+ static
+ int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
+ char s[5];
+ struct tm *time_stamp;
+
+#ifdef BSD44
+ struct timeval tp[2];
+ long xtimezone = 0L;
+#else
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2]; /* New access and modificaton time */
+ } tp;
+ char *tz;
+ long timezone; /* In case timezone not defined in .h file */
+#else
+#ifdef SYSUTIMEH
+ struct utimbuf tp;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+#ifdef ANYBSD
+ long timezone = 0L;
+ static struct timeb tbp;
+#endif /* ANYBSD */
+
+#ifdef BEBOX
+ long timezone = 0L;
+#endif /* BEBOX */
+
+ debug(F111,"zstrdt",date,len);
+
+ if ((len == 0)
+ || (len != 17)
+ || (date[8] != ' ')
+ || (date[11] != ':')
+ || (date[14] != ':') ) {
+ debug(F111,"Bad creation date ",date,len);
+ return(-1);
+ }
+ debug(F111,"zstrdt date check 1",date,len);
+ for(i = 0; i < 8; i++) {
+ if (!isdigit(date[i])) {
+ debug(F111,"Bad creation date ",date,len);
+ return(-1);
+ }
+ }
+ debug(F111,"zstrdt date check 2",date,len);
+ i++;
+
+ for (; i < 16; i += 3) {
+ if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
+ debug(F111,"Bad creation date ",date,len);
+ return(-1);
+ }
+ }
+ debug(F111,"zstrdt date check 3",date,len);
+
+
+#ifdef COMMENT /* was BSD44 */
+/*
+ man gettimeofday on BSDI 3.1 says:
+ "The timezone field is no longer used; timezone information is stored out-
+ side the kernel. See ctime(3) for more information." So this chunk of
+ code is effectively a no-op, at least in BSDI 3.x.
+*/
+ {
+ int x;
+ struct timezone tzp;
+ x = gettimeofday(NULL, &tzp);
+ debug(F101,"zstrdt BSD44 gettimeofday","",x);
+ if (x > -1)
+ xtimezone = tzp.tz_minuteswest * 60L;
+ else
+ xtimezone = 0L;
+ debug(F101,"zstrdt BSD44 timezone","",xtimezone);
+ }
+#else
+#ifdef ANYBSD
+ debug(F100,"zstrdt BSD calling ftime","",0);
+ ftime(&tbp);
+ debug(F100,"zstrdt BSD back from ftime","",0);
+ timezone = tbp.timezone * 60L;
+ debug(F101,"zstrdt BSD timezone","",timezone);
+#else
+#ifdef SVORPOSIX
+ tzset(); /* Set timezone */
+#else
+#ifdef V7
+ if ((tz = getenv("TZ")) == NULL)
+ timezone = 0; /* UTC/GMT */
+ else
+ timezone = atoi(&tz[3]); /* Set 'timezone'. */
+ timezone *= 60L;
+#endif /* V7 */
+#endif /* SVORPOSIX */
+#endif /* ANYBSD */
+#endif /* COMMENT (was BSD44) */
+
+ debug(F100,"zstrdt so far so good","",0);
+
+ s[4] = '\0';
+ for (i = 0; i < 4; i++) /* Fix the year */
+ s[i] = date[i];
+
+ n = atoi(s);
+ debug(F111,"zstrdt year",s,n);
+ if (n < 1970) {
+ debug(F100,"zstrdt fails - year","",n);
+ return(-1);
+ }
+
+/* Previous year's leap days. This won't work after year 2100. */
+
+ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
+ days = (long) (n - 1970) * 365;
+ days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
+
+ s[2] = '\0';
+
+ for (i = 4; i < 16; i += 2) {
+ s[0] = date[i];
+ s[1] = date[i + 1];
+ n = atoi(s);
+ switch (i) {
+ case 4: /* MM: month */
+ if ((n < 1 ) || ( n > 12)) {
+ debug(F111,"zstrdt 4 bad date ",date,len);
+ return(-1);
+ }
+ days += monthdays [n];
+ if (isleapyear && n > 2)
+ ++days;
+ continue;
+
+ case 6: /* DD: day */
+ if ((n < 1 ) || ( n > 31)) {
+ debug(F111,"zstrdt 6 bad date ",date,len);
+ return(-1);
+ }
+ tmx = (days + n - 1) * 24L * 60L * 60L;
+ i++; /* Skip the space */
+ continue;
+
+ case 9: /* hh: hour */
+ if ((n < 0 ) || ( n > 23)) {
+ debug(F111,"zstrdt 9 bad date ",date,len);
+ return(-1);
+ }
+ tmx += n * 60L * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 12: /* mm: minute */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zstrdt 12 bad date ",date,len);
+ return(-1);
+ }
+#ifdef COMMENT /* (was BSD44) */ /* Correct for time zone */
+ tmx += xtimezone;
+ debug(F101,"zstrdt BSD44 tmx","",tmx);
+#else
+#ifdef ANYBSD
+ tmx += timezone;
+#else
+#ifndef CONVEX9 /* Don't yet know how to do this here */
+#ifdef ultrix
+ tmx += (long) timezone;
+#else
+#ifdef Plan9
+ {
+ extern time_t tzoffset;
+ tmx += tzoffset;
+ }
+#else
+#ifndef BSD44
+#ifndef NOTIMEZONE
+ tmx += timezone;
+#endif /* NOTIMEZONE */
+#endif /* BSD44 */
+#endif /* Plan9 */
+#endif /* ultrix */
+#endif /* CONVEX9 */
+#endif /* ANYBSD */
+#endif /* COMMENT (was BSD44) */
+ tmx += n * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 15: /* ss: second */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zstrdt 15 bad date ",date,len);
+ return(-1);
+ }
+ tmx += n;
+ }
+ time_stamp = localtime(&tmx);
+ debug(F101,"zstrdt tmx 1","",tmx);
+ if (!time_stamp)
+ return(-1);
+#ifdef COMMENT
+ /* Why was this here? */
+ time_stamp = localtime(&tmx);
+ debug(F101,"zstrdt tmx 2","",tmx);
+#endif /* COMMENT */
+#ifdef BSD44
+ { /* New to 7.0 - Works in at at least BSDI 3.1 and FreeBSD 2.2.7 */
+ long zz;
+ zz = time_stamp->tm_gmtoff; /* Seconds away from Zero Meridian */
+ debug(F101,"zstrdt BSD44 tm_gmtoff","",zz);
+ tmx -= zz;
+ debug(F101,"zstrdt BSD44 tmx 3 (GMT)","",tmx);
+ }
+#else
+ /*
+ Daylight Savings Time adjustment.
+ Do this everywhere BUT in BSD44 because in BSD44,
+ tm_gmtoff also includes the DST adjustment.
+ */
+ if (time_stamp->tm_isdst) {
+ tmx -= 60L * 60L;
+ debug(F101,"zstrdt tmx 3 (DST)","",tmx);
+ }
+#endif /* BSD44 */
+ n = time_stamp->tm_year;
+ if (n < 300) {
+ n += 1900;
+ }
+ }
+ return(tmx);
+}
+
+
+#ifdef ZLOCALTIME
+/* Z L O C A L T I M E -- GMT/UTC time string to local time string */
+
+/*
+ Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time.
+ Returns: "yyyymmdd hh:mm:ss" local date-time on success, NULL on failure.
+*/
+static char zltimbuf[64];
+
+char *
+zlocaltime(gmtstring) char * gmtstring; {
+#ifdef M_UNIX
+/*
+ SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
+ ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
+ dependence on the XPG4 supplement presence. So always use
+ what the system header file supplies in ODT 3.0...
+*/
+#ifndef ODT30
+#ifndef _SCO_DS
+ extern void ftime(); /* extern void ftime(struct timeb *) */
+#endif /* _SCO_DS */
+#endif /* ODT30 */
+#else
+#ifndef M_XENIX
+ extern int ftime();
+#endif /* M_XENIX */
+#endif /* M_UNIX */
+ extern struct tm * localtime();
+
+ /* And this should have been declared always through a header file */
+#ifdef HPUX10
+ time_t tmx;
+ long days;
+#else
+#ifdef BSD44
+ time_t tmx;
+ long days;
+#else
+ long tmx, days;
+#endif /* BSD44 */
+#endif /* HPUX10 */
+ int i, n, x, isleapyear;
+ /* J F M A M J J A S O N D */
+ /* 31 28 31 30 31 30 31 31 30 31 30 31 */
+ static
+ int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
+ char s[5];
+ struct tm *time_stamp;
+
+#ifdef BSD44
+ struct timeval tp[2];
+#else
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2]; /* New access and modificaton time */
+ } tp;
+#else
+#ifdef SYSUTIMEH
+ struct utimbuf tp;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+#ifdef ANYBSD
+ static struct timeb tbp;
+#endif /* ANYBSD */
+
+ char * date = gmtstring;
+ int len;
+
+ len = strlen(date);
+ debug(F111,"zlocaltime",date,len);
+
+ if ((len == 0)
+ || (len != 17)
+ || (date[8] != ' ')
+ || (date[11] != ':')
+ || (date[14] != ':') ) {
+ debug(F111,"Bad creation date ",date,len);
+ return(NULL);
+ }
+ debug(F111,"zlocaltime date check 1",date,len);
+ for(i = 0; i < 8; i++) {
+ if (!isdigit(date[i])) {
+ debug(F111,"Bad creation date ",date,len);
+ return(NULL);
+ }
+ }
+ debug(F111,"zlocaltime date check 2",date,len);
+ i++;
+
+ for (; i < 16; i += 3) {
+ if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
+ debug(F111,"Bad creation date ",date,len);
+ return(NULL);
+ }
+ }
+ debug(F111,"zlocaltime date check 3",date,len);
+
+ debug(F100,"zlocaltime so far so good","",0);
+
+ s[4] = '\0';
+ for (i = 0; i < 4; i++) /* Fix the year */
+ s[i] = date[i];
+
+ n = atoi(s);
+ debug(F111,"zlocaltime year",s,n);
+ if (n < 1970) {
+ debug(F100,"zlocaltime fails - year","",n);
+ return(NULL);
+ }
+
+/* Previous year's leap days. This won't work after year 2100. */
+
+ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
+ days = (long) (n - 1970) * 365;
+ days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
+
+ s[2] = '\0';
+
+ for (i = 4; i < 16; i += 2) {
+ s[0] = date[i];
+ s[1] = date[i + 1];
+ n = atoi(s);
+ switch (i) {
+ case 4: /* MM: month */
+ if ((n < 1 ) || ( n > 12)) {
+ debug(F111,"zlocaltime 4 bad date ",date,len);
+ return(NULL);
+ }
+ days += monthdays [n];
+ if (isleapyear && n > 2)
+ ++days;
+ continue;
+
+ case 6: /* DD: day */
+ if ((n < 1 ) || ( n > 31)) {
+ debug(F111,"zlocaltime 6 bad date ",date,len);
+ return(NULL);
+ }
+ tmx = (days + n - 1) * 24L * 60L * 60L;
+ i++; /* Skip the space */
+ continue;
+
+ case 9: /* hh: hour */
+ if ((n < 0 ) || ( n > 23)) {
+ debug(F111,"zlocaltime 9 bad date ",date,len);
+ return(NULL);
+ }
+ tmx += n * 60L * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 12: /* mm: minute */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zlocaltime 12 bad date ",date,len);
+ return(NULL);
+ }
+ tmx += n * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 15: /* ss: second */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zlocaltime 15 bad date ",date,len);
+ return(NULL);
+ }
+ tmx += n;
+ }
+
+/*
+ At this point tmx is the time_t representation of the argument date-time
+ string without any timezone or DST adjustments. Therefore it should be
+ the same as the time_t representation of the GMT/UTC time. Now we should
+ be able to feed it to localtime() and have it converted to a struct tm
+ representing the local time equivalent of the given UTC time.
+*/
+ time_stamp = localtime(&tmx);
+ if (!time_stamp)
+ return(NULL);
+ }
+
+/* Now we simply reformat the struct tm to a string */
+
+ x = time_stamp->tm_year;
+ if (time_stamp->tm_year < 70 || time_stamp->tm_year > 8099)
+ return(NULL);
+ if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
+ return(NULL);
+ if (time_stamp->tm_mday < 1 || time_stamp->tm_mday > 31)
+ return(NULL);
+ if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 24)
+ return(NULL);
+ if (time_stamp->tm_min < 0 || time_stamp->tm_min > 60)
+ return(NULL);
+ if (time_stamp->tm_sec < 0 || time_stamp->tm_sec > 60)
+ return(NULL);
+ sprintf(zltimbuf,"%04d%02d%02d %02d:%02d:%02d",
+ time_stamp->tm_year + 1900,
+ time_stamp->tm_mon + 1,
+ time_stamp->tm_mday,
+ time_stamp->tm_hour,
+ time_stamp->tm_min,
+ time_stamp->tm_sec
+ );
+ return((char *)zltimbuf);
+}
+#endif /* ZLOCALTIME */
+#endif /* NOTIMESTAMP */
+
+/* Z S T I M E -- Set modification date/time+permissions for incoming file */
+/*
+ Call with:
+ f = pointer to name of existing file.
+ yy = pointer to a Kermit file attribute structure in which yy->date.val
+ is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
+ yy->lprotect.val & yy->gprotect.val are permission/protection values.
+ x = is a function code: 0 means to set the file's attributes as given.
+ 1 means compare the date in struct yy with the file creation date.
+ Returns:
+ -1 on any kind of error.
+ 0 if x is 0 and the attributes were set successfully.
+ 0 if x is 1 and date from attribute structure <= file creation date.
+ 1 if x is 1 and date from attribute structure > file creation date.
+*/
+int
+zstime(f,yy,x)
+ char *f; struct zattr *yy; int x;
+/* zstime */ {
+ int r = -1; /* Return code */
+#ifdef CK_PERMS
+ int setperms = 0;
+#endif /* CK_PERMS */
+ int setdate = 0;
+
+/* It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se. */
+
+#ifdef TIMESTAMP
+#ifdef BSD44
+ extern int utimes();
+#else
+ extern int utime();
+#endif /* BSD44 */
+
+ struct stat sb;
+
+/* At least, the declarations for int functions are not needed anyway */
+
+#ifdef BSD44
+ struct timeval tp[2];
+ long xtimezone;
+#else
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2]; /* New access and modificaton time */
+ } tp;
+ char *tz;
+ long timezone; /* In case not defined in .h file */
+#else
+#ifdef SYSUTIMEH
+ struct utimbuf tp;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+ long tm = 0L;
+
+ if (!f) f = "";
+ if (!*f) return(-1);
+ if (!yy) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zstime setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zstime setroot violation",f,0);
+ return(0);
+ }
+#endif /* CKROOT */
+
+ if (yy->date.len == 0) { /* No date in struct */
+ if (yy->lprotect.len != 0) { /* So go do permissions */
+ goto zsperms;
+ } else {
+ debug(F100,"zstime: nothing to do","",0);
+ return(0);
+ }
+ }
+ if ((tm = zstrdt(yy->date.val,yy->date.len)) < 0) {
+ debug(F101,"zstime: zstrdt fails","",0);
+ return(-1);
+ }
+ debug(F101,"zstime: tm","",tm);
+ debug(F111,"zstime: A-pkt date ok ",yy->date.val,yy->date.len);
+
+ if (stat(f,&sb)) { /* Get the time for the file */
+ debug(F101,"STAT","",14);
+ debug(F111,"zstime: Can't stat file:",f,errno);
+ return(-1);
+ }
+ debug(F101,"STAT","",15);
+ setdate = 1;
+
+ zsperms:
+#ifdef CK_PERMS
+ {
+ int i, x = 0, xx, flag = 0;
+ char * s;
+#ifdef DEBUG
+ char obuf[24];
+ if (deblog) {
+ debug(F111,"zstime lperms",yy->lprotect.val,yy->lprotect.len);
+ debug(F111,"zstime gperms",yy->gprotect.val,yy->gprotect.len);
+ debug(F110,"zstime system id",yy->systemid.val,0);
+ sprintf(obuf,"%o",sb.st_mode);
+ debug(F110,"zstime file perms before",obuf,0);
+ }
+#endif /* DEBUG */
+
+#ifdef CK_LOGIN
+ debug(F101,"zstime isguest","",isguest);
+ debug(F101,"zstime ckxperms","",ckxperms);
+ if (isguest) {
+#ifdef COMMENT
+ /* Clear owner permissions */
+ sb.st_mode &= (unsigned) 0177077; /* (16 bits) */
+#else
+ /* Set permissions from ckxperms variable */
+ sb.st_mode = ckxperms;
+#endif /* COMMENT */
+ debug(F101,"zstime isguest sb.st_mode","",sb.st_mode);
+#ifdef COMMENT
+ /* We already set them in zopeno() */
+ setperms = 1;
+#endif /* COMMENT */
+ flag = 0;
+ } else
+#endif /* CK_LOGIN */
+ if ((yy->lprotect.len > 0 && /* Have local-format permissions */
+ yy->systemid.len > 0 && /* from A-packet... */
+#ifdef UNIX
+ !strcmp(yy->systemid.val,"U1") /* AND you are same as me */
+#else
+ 0
+#endif /* UNIX */
+ ) || (yy->lprotect.len < 0) /* OR by inheritance from old file */
+ ) {
+ flag = 1;
+ s = yy->lprotect.val; /* UNIX filemode */
+ xx = yy->lprotect.len;
+ if (xx < 0) /* len < 0 means inheritance */
+ xx = 0 - xx;
+ for (i = 0; i < xx; i++) { /* Decode octal string */
+ if (*s <= '7' && *s >= '0') {
+ x = 8 * x + (int)(*s) - '0';
+ } else {
+ flag = 0;
+ break;
+ }
+ s++;
+ }
+#ifdef DEBUG
+ sprintf(obuf,"%o",x);
+ debug(F110,"zstime octal lperm",obuf,0);
+#endif /* DEBUG */
+ } else if (!flag && yy->gprotect.len > 0) {
+ int g;
+#ifdef CK_SCO32V4
+ mode_t mask;
+#else
+ int mask;
+#endif /* CK_SCO32V4 */
+ mask = umask(0); /* Get umask */
+ debug(F101,"zstime mask 1","",mask);
+ umask(mask); /* Put it back */
+ mask ^= 0777; /* Flip the bits */
+ debug(F101,"zstime mask 2","",mask);
+ g = xunchar(*(yy->gprotect.val)); /* Decode generic protection */
+ debug(F101,"zstime gprotect","",g);
+#ifdef S_IRUSR
+ debug(F100,"zstime S_IRUSR","",0);
+ if (g & 1) x |= S_IRUSR; /* Read permission */
+ flag = 1;
+#endif /* S_IRUSR */
+#ifdef S_IWUSR
+ debug(F100,"zstime S_IWUSR","",0);
+ if (g & 2) x |= S_IWUSR; /* Write permission */
+ if (g & 16) x |= S_IWUSR; /* Delete permission */
+ flag = 1;
+#endif /* S_IWUSR */
+#ifdef S_IXUSR
+ debug(F100,"zstime S_IXUSR","",0);
+ if (g & 4) /* Has execute permission bit */
+ x |= S_IXUSR;
+ else /* Doesn't have it */
+ mask &= 0666; /* so also clear it out of mask */
+ flag = 1;
+#endif /* S_IXUSR */
+ debug(F101,"zstime mask x","",x);
+ x |= mask;
+ debug(F101,"zstime mask x|mask","",x);
+ }
+ debug(F101,"zstime flag","",flag);
+ if (flag) {
+#ifdef S_IFMT
+ debug(F101,"zstime S_IFMT x","",x);
+ sb.st_mode = (sb.st_mode & S_IFMT) | x;
+ setperms = 1;
+#else
+#ifdef _IFMT
+ debug(F101,"zstime _IFMT x","",x);
+ sb.st_mode = (sb.st_mode & _IFMT) | x;
+ setperms = 1;
+#endif /* _IFMT */
+#endif /* S_IFMT */
+ }
+#ifdef DEBUG
+ sprintf(obuf,"%04o",sb.st_mode);
+ debug(F111,"zstime file perms after",obuf,setperms);
+#endif /* DEBUG */
+ }
+#endif /* CK_PERMS */
+
+ debug(F101,"zstime: sb.st_atime","",sb.st_atime);
+
+#ifdef BSD44
+ tp[0].tv_sec = sb.st_atime; /* Access time first */
+ tp[1].tv_sec = tm; /* Update time second */
+ debug(F100,"zstime: BSD44 modtime","",0);
+#else
+#ifdef V7
+ tp.timep[0] = tm; /* Set modif. time to creation date */
+ tp.timep[1] = sb.st_atime; /* Don't change the access time */
+ debug(F100,"zstime: V7 modtime","",0);
+#else
+#ifdef SYSUTIMEH
+ tp.modtime = tm; /* Set modif. time to creation date */
+ tp.actime = sb.st_atime; /* Don't change the access time */
+ debug(F100,"zstime: SYSUTIMEH modtime","",0);
+#else
+ tp.mtime = tm; /* Set modif. time to creation date */
+ tp.atime = sb.st_atime; /* Don't change the access time */
+ debug(F100,"zstime: default modtime","",0);
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+ switch (x) { /* Execute desired function */
+ case 0: /* Set the creation date of the file */
+#ifdef CK_PERMS /* And permissions */
+/*
+ NOTE: If we are inheriting permissions from a previous file, and the
+ previous file was a directory, this would turn the new file into a directory
+ too, but it's not, so we try to unset the right bit. Luckily, this code
+ will probably never be executed since the upper level modules do not allow
+ reception of a file that has the same name as a directory.
+
+ NOTE 2: We change the permissions *before* we change the modification time,
+ otherwise changing the permissions would set the mod time to the present
+ time.
+*/
+ {
+ int x;
+ debug(F101,"zstime setperms","",setperms);
+ if (S_ISDIR(sb.st_mode)) {
+ debug(F101,"zstime DIRECTORY bit on","",sb.st_mode);
+ sb.st_mode ^= 0040000;
+ debug(F101,"zstime DIRECTORY bit off","",sb.st_mode);
+ }
+ if (setperms) {
+ x = chmod(f,sb.st_mode);
+ debug(F101,"zstime chmod","",x);
+ }
+ }
+ if (x < 0) return(-1);
+#endif /* CK_PERMS */
+
+ if (!setdate) /* We don't have a date */
+ return(0); /* so skip the following... */
+
+ if (
+#ifdef BSD44
+ utimes(f,tp)
+#else
+ utime(f,&tp)
+#endif /* BSD44 */
+ ) { /* Fix modification time */
+ debug(F111,"zstime 0: can't set modtime for file",f,errno);
+ r = -1;
+ } else {
+ /* Including the modtime here is not portable */
+ debug(F110,"zstime 0: modtime set for file",f,0);
+ r = 0;
+ }
+ break;
+
+ case 1: /* Compare the dates */
+/*
+ This was st_atime, which was wrong. We want the file-data modification
+ time, st_mtime.
+*/
+ debug(F111,"zstime 1: compare",f,sb.st_mtime);
+ debug(F111,"zstime 1: compare","packet",tm);
+
+ r = (sb.st_mtime < tm) ? 0 : 1;
+ break;
+
+ default: /* Error */
+ r = -1;
+ }
+#endif /* TIMESTAMP */
+ return(r);
+}
+
+/* Find initialization file. */
+
+#ifdef NOTUSED
+int
+zkermini() {
+/* nothing here for Unix. This function added for benefit of VMS Kermit. */
+ return(0);
+}
+#endif /* NOTUSED */
+
+#ifndef UNIX
+/* Historical -- not used in Unix any more (2001-11-03) */
+#ifndef NOFRILLS
+int
+zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */
+/*
+ Returns 0 on success
+ 2 if mail delivered but temp file can't be deleted
+ -2 if mail can't be delivered
+ -1 on file access error
+ The UNIX version always returns 0 because it can't get a good return
+ code from zsyscmd.
+*/
+ int n;
+
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-2);
+#endif /* CK_LOGIN */
+
+ if (!f) f = "";
+ if (!*f) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zmail setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zmail setroot violation",f,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+#ifdef BSD4
+/* The idea is to use /usr/ucb/mail, rather than regular mail, so that */
+/* a subject line can be included with -s. Since we can't depend on the */
+/* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
+/* and even if Mail has been moved to somewhere else, this should still */
+/* find it... The search could be made more reliable by actually using */
+/* access() to see if /usr/ucb/Mail exists. */
+
+ n = strlen(f);
+ n = n + n + 15 + (int)strlen(p);
+
+ if (n > ZMBUFLEN)
+ return(-2);
+
+#ifdef DGUX540
+ sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
+#else
+ sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
+#endif /* DGUX540 */
+ zsyscmd(zmbuf);
+#else
+#ifdef SVORPOSIX
+#ifndef OXOS
+ sprintf(zmbuf,"mail %s < %s", p, f);
+#else /* OXOS */
+ sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
+#endif /* OXOS */
+ zsyscmd(zmbuf);
+#else
+ *zmbuf = '\0';
+#endif
+#endif
+ return(0);
+}
+#endif /* NOFRILLS */
+#endif /* UNIX */
+
+#ifndef NOFRILLS
+int
+zprint(p,f) char *p; char *f; { /* Print file f with options p */
+ extern char * printername; /* From ckuus3.c */
+ extern int printpipe;
+ int n;
+
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-2);
+#endif /* CK_LOGIN */
+
+ if (!f) f = "";
+ if (!*f) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zprint setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zprint setroot violation",f,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ debug(F110,"zprint file",f,0);
+ debug(F110,"zprint flags",p,0);
+ debug(F110,"zprint printername",printername,0);
+ debug(F101,"zprint printpipe","",printpipe);
+
+#ifdef UNIX
+/*
+ Note use of standard input redirection. In some systems, lp[r] runs
+ setuid to lp (or ...?), so if user has sent a file into a directory
+ that lp does not have read access to, it can't be printed unless it is
+ fed to lp[r] as standard input.
+*/
+ if (printpipe && printername) {
+ n = 8 + (int)strlen(f) + (int)strlen(printername);
+ if (n > ZMBUFLEN)
+ return(-2);
+ sprintf(zmbuf,"cat %s | %s", f, printername);
+ } else if (printername) {
+ n = 8 + (int)strlen(f) + (int)strlen(printername);
+ if (n > ZMBUFLEN)
+ return(-2);
+ sprintf(zmbuf,"cat %s >> %s", f, printername);
+ } else {
+ n = 4 + (int)strlen(PRINTCMD) + (int)strlen(p) + (int)strlen(f);
+ if (n > ZMBUFLEN)
+ return(-2);
+ sprintf(zmbuf,"%s %s < %s", PRINTCMD, p, f);
+ }
+ debug(F110,"zprint command",zmbuf,0);
+ zsyscmd(zmbuf);
+#else /* Not UNIX */
+ *zmbuf = '\0';
+#endif /* UNIX */
+ return(0);
+}
+#endif /* NOFRILLS */
+
+/* Wildcard expansion functions... */
+
+static char scratch[MAXPATH+4]; /* Used by both methods */
+
+static int oldmtchs = 0; /* Let shell (ls) expand them. */
+#ifdef COMMENT
+static char *lscmd = "/bin/ls -d"; /* Command to use. */
+#else
+static char *lscmd = "echo"; /* Command to use. */
+#endif /* COMMENT */
+
+#ifndef NOPUSH
+int
+shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
+ char *fgbuf = NULL; /* Buffer for forming ls command */
+ char *p, *q; /* Workers */
+
+ int i, x, retcode, itsadir;
+ char c;
+
+ x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
+ for (i = 0; i < oldmtchs; i++) { /* Free previous file list */
+ if (namlst[i] ) { /* If memory is allocated */
+ free(namlst[i]); /* Free the memory */
+ namlst[i] = NULL ; /* Remember no memory is allocated */
+ }
+ }
+ oldmtchs = 0 ; /* Remember there are no matches */
+ fgbuf = malloc(x); /* Get buffer for command */
+ if (!fgbuf) return(-1); /* Fail if cannot */
+ ckmakmsg(fgbuf,x,lscmd," ",pat,NULL); /* Form the command */
+ zxcmd(ZIFILE,fgbuf); /* Start the command */
+ i = 0; /* File counter */
+ p = scratch; /* Point to scratch area */
+ retcode = -1; /* Assume failure */
+ while ((x = zminchar()) != -1) { /* Read characters from command */
+ c = (char) x;
+ if (c == ' ' || c == '\n') { /* Got newline or space? */
+ *p = '\0'; /* Yes, terminate string */
+ p = scratch; /* Point back to beginning */
+ if (zchki(p) == -1) /* Does file exist? */
+ continue; /* No, continue */
+ itsadir = isdir(p); /* Yes, is it a directory? */
+ if (xdironly && !itsadir) /* Want only dirs but this isn't */
+ continue; /* so skip. */
+ if (xfilonly && itsadir) /* It's a dir but want only files */
+ continue; /* so skip. */
+ x = (int)strlen(p); /* Keep - get length of name */
+ q = malloc(x+1); /* Allocate space for it */
+ if (!q) goto shxfin; /* Fail if space can't be obtained */
+ strcpy(q,scratch); /* (safe) Copy name to space */
+ namlst[i++] = q; /* Copy pointer to name into array */
+ if (i >= len) goto shxfin; /* Fail if too many */
+ } else { /* Regular character */
+ *p++ = c; /* Copy it into scratch area */
+ }
+ }
+ retcode = i; /* Return number of matching files */
+shxfin: /* Common exit point */
+ free(fgbuf); /* Free command buffer */
+ fgbuf = NULL;
+ zclosf(ZIFILE); /* Delete the command fork. */
+ oldmtchs = i; /* Remember how many files */
+ return(retcode);
+}
+#endif /* NOPUSH */
+
+/*
+ Directory-reading functions for UNIX originally written for C-Kermit 4.0
+ by Jeff Damens, CUCCA, 1984.
+*/
+static char * xpat = NULL; /* Global copy of fgen() pattern */
+static char * xpatlast = NULL; /* Rightmost segment of pattern*/
+static int xpatslash = 0; /* Slash count in pattern */
+static int xpatwild = 0; /* Original pattern is wild */
+static int xleafwild = 0; /* Last segment of pattern is wild */
+static int xpatabsolute = 0;
+
+#ifdef aegis
+static char bslash;
+#endif /* aegis */
+
+
+/* S P L I T P A T H */
+
+/*
+ Splits the slash-separated portions of the argument string into
+ a list of path structures. Returns the head of the list. The
+ structures are allocated by malloc, so they must be freed.
+ Splitpath is used internally by the filename generator.
+
+ Input:
+ A path string.
+
+ Returns:
+ A linked list of the slash-separated segments of the input.
+*/
+static struct path *
+splitpath(p) char *p; {
+ struct path *head,*cur,*prv;
+ int i;
+
+ debug(F111,"splitpath",p,xrecursive);
+ head = prv = NULL;
+
+ if (!p) return(NULL);
+ if (!*p) return(NULL);
+
+ if (!strcmp(p,"**")) { /* Fix this */
+ p = "*";
+ }
+ if (ISDIRSEP(*p)) p++; /* Skip leading slash if any */
+
+ /* Make linked list of path segments from pattern */
+
+ while (*p) {
+ cur = (struct path *) malloc(sizeof (struct path));
+ /* debug(F101,"splitpath malloc","",cur); */
+ if (cur == NULL) {
+ debug(F100,"splitpath malloc failure","",0);
+ prv -> fwd = NULL;
+ return((struct path *)NULL);
+ }
+ cur -> fwd = NULL;
+ if (head == NULL) /* First, make list head */
+ head = cur;
+ else /* Not first, link into chain */
+ prv -> fwd = cur;
+ prv = cur; /* Link from previous to this one */
+
+#ifdef aegis
+ /* treat backslash as "../" */
+ if (bslash && *p == bslash) {
+ strcpy(cur->npart, ".."); /* safe */
+ ++p;
+ } else {
+ for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
+ cur -> npart[i] = *p++;
+ cur -> npart[i] = '\0'; /* end this segment */
+ if (i >= MAXNAMLEN)
+ while (*p && *p != '/' && *p != bslash)
+ p++;
+ }
+ if (*p == '/') p++;
+#else
+ /* General case (UNIX) */
+ for (i = 0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
+ cur -> npart[i] = *p++;
+ }
+
+ cur -> npart[i] = '\0'; /* End this path segment */
+ if (i >= MAXNAMLEN)
+ while (!ISDIRSEP(*p) && *p != '\0') p++;
+ if (ISDIRSEP(*p))
+ p++;
+
+#endif /* aegis */
+ }
+ if (prv) {
+ makestr(&xpatlast,prv -> npart);
+ debug(F110,"splitpath xpatlast",xpatlast,0);
+ }
+#ifdef DEBUG
+ /* Show original path list */
+ if (deblog) {
+ for (i = 0, cur = head; cur; i++) {
+ debug(F111,"SPLITPATH",cur -> npart, i);
+ cur = cur -> fwd;
+ }
+ }
+#endif /* DEBUG */
+ return(head);
+}
+
+/* F G E N -- Generate File List */
+
+/*
+ File name generator. It is passed a string, possibly containing wildcards,
+ and an array of character pointers. It finds all the matching filenames and
+ stores pointers to them in the array. The returned strings are allocated
+ from a static buffer local to this module (so the caller doesn't have to
+ worry about deallocating them); this means that successive calls to fgen
+ will wipe out the results of previous calls.
+
+ Input:
+ A wildcard string, an array to write names to, the length of the array.
+
+ Returns:
+ The number of matches.
+ The array is filled with filenames that matched the pattern.
+ If there wasn't enough room in the array, -1 is returned.
+
+ Originally by: Jeff Damens, CUCCA, 1984. Many changes since then.
+*/
+static int
+fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
+ struct path *head;
+ char *sptr, *s;
+ int n;
+
+#ifdef aegis
+ char *namechars;
+ int tilde = 0, bquote = 0;
+
+ if ((namechars = getenv("NAMECHARS")) != NULL) {
+ if (ckstrchr(namechars, '~' ) != NULL) tilde = '~';
+ if (ckstrchr(namechars, '\\') != NULL) bslash = '\\';
+ if (ckstrchr(namechars, '`' ) != NULL) bquote = '`';
+ } else {
+ tilde = '~'; bslash = '\\'; bquote = '`';
+ }
+ sptr = scratch;
+
+ /* copy "`node_data", etc. anchors */
+ if (bquote && *pat == bquote)
+ while (*pat && *pat != '/' && *pat != bslash)
+ *sptr++ = *pat++;
+ else if (tilde && *pat == tilde)
+ *sptr++ = *pat++;
+ while (*pat == '/')
+ *sptr++ = *pat++;
+ if (sptr == scratch) {
+ strcpy(scratch,"./"); /* safe */
+ sptr = scratch+2;
+ }
+ if (!(head = splitpath(pat))) return(-1);
+
+#else /* not aegis */
+
+ debug(F111,"fgen pat",pat,len);
+ debug(F110,"fgen current directory",zgtdir(),0);
+ debug(F101,"fgen stathack","",stathack);
+
+ scratch[0] = '\0';
+ xpatwild = 0;
+ xleafwild = 0;
+ xpatabsolute = 0;
+
+ if (!(head = splitpath(pat))) /* Make the path segment list */
+ return(-1);
+
+ sptr = scratch;
+
+#ifdef COMMENT
+ if (strncmp(pat,"./",2) && strncmp(pat,"../",3)) {
+#endif /* COMMENT */
+ if (!ISDIRSEP(*pat)) /* If name is not absolute */
+ *sptr++ = '.'; /* put "./" in front. */
+ *sptr++ = DIRSEP;
+#ifdef COMMENT
+ }
+#endif /* COMMENT */
+ *sptr = '\0';
+#endif /* aegis */
+
+ makestr(&xpat,pat); /* Save copy of original pattern */
+ debug(F110,"fgen scratch",scratch,0);
+
+ for (n = 0, s = xpat; *s; s++) /* How many slashes in the pattern */
+ if (*s == DIRSEP) /* since these are fences for */
+ n++; /* pattern matching */
+ xpatslash = n;
+ debug(F101,"fgen xpatslash","",xpatslash);
+
+ numfnd = 0; /* None found yet */
+
+ if (initspace(resarry,ssplen) < 0)
+ return(-1);
+
+ xpatwild = iswild(xpat); /* Original pattern is wild? */
+ xpatabsolute = isabsolute(xpat);
+ xleafwild = iswild(xpatlast);
+
+ debug(F111,"fgen xpat",xpat,xpatwild);
+ debug(F111,"fgen xpatlast",xpatlast,xleafwild);
+ debug(F101,"fgen xpatabsolute","",xpatabsolute);
+
+ traverse(head,scratch,sptr); /* Go walk the directory tree. */
+ while (head != NULL) { /* Done - free path segment list. */
+ struct path *next = head -> fwd;
+ free((char *)head);
+ head = next;
+ }
+ debug(F101,"fgen","",numfnd);
+ return(numfnd); /* Return the number of matches */
+}
+
+/* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
+/* LONGFN can also be defined on the cc command line. */
+
+#ifdef BSD29
+#ifndef LONGFN
+#define LONGFN
+#endif
+#endif
+
+#ifdef BSD42
+#ifndef LONGFN
+#define LONGFN
+#endif
+#endif
+
+/*
+ T R A V E R S E -- Traverse a directory tree.
+
+ Walks the directory tree looking for matches to its arguments.
+ The algorithm is, briefly:
+
+ If the current pattern segment contains no wildcards, that
+ segment is added to what we already have. If the name so far
+ exists, we call ourselves recursively with the next segment
+ in the pattern string; otherwise, we just return.
+
+ If the current pattern segment contains wildcards, we open the name
+ we've accumulated so far (assuming it is really a directory), then read
+ each filename in it, and, if it matches the wildcard pattern segment, add
+ that filename to what we have so far and call ourselves recursively on
+ the next segment.
+
+ Finally, when no more pattern segments remain, we add what's accumulated
+ so far to the result array and increment the number of matches.
+
+ Inputs:
+ A pattern path list (as generated by splitpath), a string pointer that
+ points to what we've traversed so far (this can be initialized to "/"
+ to start the search at the root directory, or to "./" to start the
+ search at the current directory), and a string pointer to the end of
+ the string in the previous argument, plus the global "recursive",
+ "xmatchdot", and "xdironly" flags.
+
+ Returns: void, with:
+ mtchs[] containing the array of filename string pointers, and:
+ numfnd containing the number of filenames.
+
+ Although it might be poor practice, the mtchs[] array is revealed to the
+ outside in case it needs it; for example, to be sorted prior to use.
+ (It is poor practice because not all platforms implement file lists the
+ same way; some don't use an array at all.)
+
+ Note that addresult() acts as a second-level filter; due to selection
+ criteria outside of the pattern, it might decline to add files that
+ this routine asks it to, e.g. because we are collecting only directory
+ names but not the names of regular files.
+
+ WARNING: In the course of C-Kermit 7.0 development, this routine became
+ ridiculously complex, in order to meet approximately sixty specific
+ requirements. DON'T EVEN THINK ABOUT MODIFYING THIS ROUTINE! Trust me;
+ it is not possible to fix anything in it without breaking something else.
+ This routine badly needs a total redesign and rewrite. Note: There may
+ be some good applications for realpath() and/or scandir() and/or fts_blah()
+ here, on platforms where they are available.
+*/
+static VOID
+traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
+
+/* Appropriate declarations for directory routines and structures */
+/* #define OPENDIR means to use opendir(), readdir(), closedir() */
+/* If OPENDIR not defined, we use open(), read(), close() */
+
+#ifdef DIRENT /* New way, <dirent.h> */
+#define OPENDIR
+ DIR *fd, *opendir();
+ struct dirent *dirbuf;
+ struct dirent *readdir();
+#else /* !DIRENT */
+#ifdef LONGFN /* Old way, <dir.h> with opendir() */
+#define OPENDIR
+ DIR *fd, *opendir();
+ struct direct *dirbuf;
+#else /* !LONGFN */
+ int fd; /* Old way, <dir.h> with open() */
+ struct direct dir_entry;
+ struct direct *dirbuf = &dir_entry;
+#endif /* LONGFN */
+#endif /* DIRENT */
+ int mopts = 0; /* ckmatch() opts */
+ int depth = 0; /* Directory tree depth */
+
+ char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */
+ int itsadir = 0, segisdir = 0, itswild = 0, mresult, n, x /* , y */ ;
+ struct stat statbuf; /* For file info. */
+
+ debug(F101,"STAT","",16);
+ if (pl == NULL) { /* End of path-segment list */
+ *--endcur = '\0'; /* Terminate string, overwrite trailing slash */
+ debug(F110,"traverse add: end of path segment",sofar,0);
+ addresult(sofar,-1);
+ return;
+ }
+ if (stathack) {
+ /* This speeds up the search a lot and we still get good results */
+ /* but it breaks the tagging of directory names done in addresult */
+ if (xrecursive || xfilonly || xdironly || xpatslash) {
+ itsadir = xisdir(sofar);
+ debug(F101,"STAT","",17);
+ } else
+ itsadir = (strncmp(sofar,"./",2) == 0);
+ } else {
+ itsadir = xisdir(sofar);
+ debug(F101,"STAT","",18);
+ }
+ debug(F111,"traverse entry sofar",sofar,itsadir);
+
+#ifdef CKSYMLINK /* We're doing symlinks? */
+#ifdef USE_LSTAT /* OK to use lstat()? */
+ if (itsadir && xnolinks) { /* If not following symlinks */
+ int x;
+ struct stat buf;
+ x = lstat(sofar,&buf);
+ debug(F111,"traverse lstat 1",sofar,x);
+ if (x > -1 &&
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ )
+ itsadir = 0;
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+
+ if (!xmatchdot && xpatlast[0] == '.')
+ xmatchdot = 1;
+ if (!xmatchdot && xpat[0] == '.' && xpat[1] != '/' && xpat[1] != '.')
+ xmatchdot = 1;
+
+ /* ckmatch() options */
+
+ if (xmatchdot) mopts |= 1; /* Match dot */
+ if (!xrecursive) mopts |= 2; /* Dirsep is fence */
+
+ debug(F111,"traverse entry xpat",xpat,xpatslash);
+ debug(F111,"traverse entry xpatlast",xpatlast,xmatchdot);
+ debug(F110,"traverse entry pl -> npart",pl -> npart,0);
+
+#ifdef RECURSIVE
+ if (xrecursive > 0 && !itsadir) {
+ char * s; /* Recursive descent and this is a regular file */
+ *--endcur = '\0'; /* Terminate string, overwrite trailing slash */
+
+ /* Find the nth slash from the right and match from there... */
+ /* (n == the number of slashes in the original pattern - see fgen) */
+ if (*sofar == '/') {
+ debug(F110,"traverse xpatslash absolute",sofar,0);
+ s = sofar;
+ } else {
+ debug(F111,"traverse xpatslash relative",sofar,xpatslash);
+ for (s = endcur - 1, n = 0; s >= sofar; s--) {
+ if (*s == '/') {
+ if (++n >= xpatslash) {
+ s++;
+ break;
+ }
+ }
+ }
+ }
+#ifndef NOSKIPMATCH
+ /* This speeds things up a bit. */
+ /* If it causes trouble define NOSKIPMATCH and rebuild. */
+ if (xpat[0] == '*' && !xpat[1])
+ x = xmatchdot ? 1 : (s[0] != '.');
+ else
+#endif /* NOSKIPMATCH */
+ x = ckmatch(xpat, s, 1, mopts); /* Match with original pattern */
+ debug(F111,"traverse xpatslash ckmatch",s,x);
+ if (x > 0) {
+ debug(F110,"traverse add: recursive, match, && !isdir",sofar,0);
+ addresult(sofar,itsadir);
+ }
+ return;
+ }
+#endif /* RECURSIVE */
+
+ debug(F111,"traverse sofar 2",sofar,0);
+
+ segisdir = ((pl -> fwd) == NULL) ? 0 : 1;
+ itswild = wildena ? (iswild(pl -> npart)) : 0; /* 15 Jun 2005 */
+
+ debug(F111,"traverse segisdir",sofar,segisdir);
+ debug(F111,"traverse itswild ",pl -> npart,itswild);
+
+#ifdef RECURSIVE
+ if (xrecursive > 0) { /* If recursing and... */
+ if (segisdir && itswild) /* this is a dir and npart is wild */
+ goto blah; /* or... */
+ else if (!xpatabsolute && !xpatwild) /* search object is nonwild */
+ goto blah; /* then go recurse */
+ }
+#endif /* RECURSIVE */
+
+ if (!itswild) { /* This path segment not wild? */
+#ifdef COMMENT
+ strcpy(endcur,pl -> npart); /* (safe) Append next part. */
+ endcur += (int)strlen(pl -> npart); /* Advance end pointer */
+#else
+/*
+ strcpy() does not account for quoted metacharacters.
+ We must remove the quotes before doing the stat().
+*/
+ {
+ int quote = 0;
+ char c, * s;
+ s = pl -> npart;
+ while ((c = *s++)) {
+ if (!quote) {
+ if (c == CMDQ) {
+ quote = 1;
+ continue;
+ }
+ }
+ *endcur++ = c;
+ quote = 0;
+ }
+ }
+#endif /* COMMENT */
+ *endcur = '\0'; /* End new current string. */
+
+ if (stat(sofar,&statbuf) == 0) { /* If this piece exists... */
+ debug(F110,"traverse exists",sofar,0);
+ *endcur++ = DIRSEP; /* add slash to end */
+ *endcur = '\0'; /* and end the string again. */
+ traverse(pl -> fwd, sofar, endcur);
+ }
+#ifdef DEBUG
+ else debug(F110,"traverse not found", sofar, 0);
+#endif /* DEBUG */
+ return;
+ }
+
+ *endcur = '\0'; /* End current string */
+ debug(F111,"traverse sofar 3",sofar,0);
+
+ if (!itsadir)
+ return;
+
+ /* Search is recursive or ... */
+ /* path segment contains wildcards, have to open and search directory. */
+
+ blah:
+
+ debug(F110,"traverse opening directory", sofar, 0);
+
+#ifdef OPENDIR
+ debug(F110,"traverse opendir()",sofar,0);
+ if ((fd = opendir(sofar)) == NULL) { /* Can't open, fail. */
+ debug(F101,"traverse opendir() failed","",errno);
+ return;
+ }
+ while ((dirbuf = readdir(fd)))
+#else /* !OPENDIR */
+ debug(F110,"traverse directory open()",sofar,0);
+ if ((fd = open(sofar,O_RDONLY)) < 0) {
+ debug(F101,"traverse directory open() failed","",errno);
+ return;
+ }
+ while (read(fd, (char *)dirbuf, sizeof dir_entry) > 0)
+#endif /* OPENDIR */
+ { /* Read each entry in this directory */
+ int exists;
+ char *eos, *s;
+ exists = 0;
+
+ /* On some platforms, the read[dir]() can return deleted files, */
+ /* e.g. HP-UX 5.00. There is no point in grinding through this */
+ /* routine when the file doesn't exist... */
+
+ if ( /* There actually is an inode... */
+#ifdef BSD42
+ dirbuf->d_ino != -1
+#else
+#ifdef unos
+ dirbuf->d_ino != -1
+#else
+#ifdef QNX
+ dirbuf->d_stat.st_ino != 0
+#else
+#ifdef SOLARIS
+ dirbuf->d_ino != 0
+#else
+#ifdef sun
+ dirbuf->d_fileno != 0
+#else
+#ifdef bsdi
+ dirbuf->d_fileno != 0
+#else
+#ifdef __386BSD__
+ dirbuf->d_fileno != 0
+#else
+#ifdef __FreeBSD__
+ dirbuf->d_fileno != 0
+#else
+#ifdef ultrix
+ dirbuf->gd_ino != 0
+#else
+#ifdef Plan9
+ 1
+#else
+ dirbuf->d_ino != 0
+#endif /* Plan9 */
+#endif /* ultrix */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#endif /* bsdi */
+#endif /* sun */
+#endif /* SOLARIS */
+#endif /* QNX */
+#endif /* unos */
+#endif /* BSD42 */
+ )
+ exists = 1;
+ if (!exists)
+ continue;
+
+ ckstrncpy(nambuf, /* Copy the name */
+ dirbuf->d_name,
+ MAXNAMLEN
+ );
+ if (nambuf[0] == '.') {
+ if (!nambuf[1] || (nambuf[1] == '.' && !nambuf[2])) {
+ debug(F110,"traverse skipping",nambuf,0);
+ continue; /* skip "." and ".." */
+ }
+ }
+ s = nambuf; /* Copy name to end of sofar */
+ eos = endcur;
+ while ((*eos = *s)) {
+ s++;
+ eos++;
+ }
+/*
+ Now we check the file for (a) whether it is a directory, and (b) whether
+ its name matches our pattern. If it is a directory, and if we have been
+ told to build a recursive list, then we must descend regardless of whether
+ it matches the pattern. If it is not a directory and it does not match
+ our pattern, we skip it. Note: sofar is the full pathname, nambuf is
+ the name only.
+*/
+ /* Do this first to save pointless function calls */
+ if (nambuf[0] == '.' && !xmatchdot) /* Dir name starts with '.' */
+ continue;
+ if (stathack) {
+ if (xrecursive || xfilonly || xdironly || xpatslash) {
+ itsadir = xisdir(sofar); /* See if it's a directory */
+ debug(F101,"STAT","",19);
+ } else {
+ itsadir = 0;
+ }
+ } else {
+ itsadir = xisdir(sofar);
+ debug(F101,"STAT","",20);
+ }
+
+#ifdef CKSYMLINK
+#ifdef USE_LSTAT
+ if (itsadir && xnolinks) { /* If not following symlinks */
+ int x;
+ struct stat buf;
+ x = lstat(sofar,&buf);
+ debug(F111,"traverse lstat 2",sofar,x);
+ if (x > -1 &&
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ )
+ itsadir = 0;
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+
+#ifdef RECURSIVE
+ if (xrecursive > 0 && itsadir &&
+ (xpatlast[0] == '*') && !xpatlast[1]
+ ) {
+ debug(F110,
+ "traverse add: recursive && isdir && segisdir or match",
+ sofar,
+ segisdir
+ );
+ addresult(sofar,itsadir);
+ if (numfnd < 0) return;
+ }
+#endif /* RECURSIVE */
+
+ debug(F111,"traverse mresult xpat",xpat,xrecursive);
+ debug(F111,"traverse mresult pl -> npart",
+ pl -> npart,
+ ((pl -> fwd) ? 9999 : 0)
+ );
+ debug(F111,"traverse mresult sofar segisdir",sofar,segisdir);
+ debug(F111,"traverse mresult sofar itsadir",sofar,itsadir);
+ debug(F101,"traverse mresult xmatchdot","",xmatchdot);
+/*
+ Match the path so far with the pattern after stripping any leading "./"
+ from either or both. The pattern chosen is the full original pattern if
+ the match candidate (sofar) is not a directory, or else just the name part
+ (pl->npart) if it is.
+*/
+ {
+ char * s1; /* The pattern */
+ char * s2 = sofar; /* The path so far */
+ char * s3; /* Worker */
+ int opts; /* Match options */
+
+ s1 = itsadir ? pl->npart : xpat;
+
+#ifndef COMMENT
+ /* I can't explain this but it unbreaks "cd blah/sub<Esc>" */
+ if (itsadir && !xrecursive && xpatslash > 0 &&
+ segisdir == 0 && itswild) {
+ s1 = xpat;
+ debug(F110,"traverse mresult s1 kludge",s1,0);
+ }
+#endif /* COMMENT */
+
+ if (xrecursive && xpatslash == 0)
+ s2 = nambuf;
+ while ((s1[0] == '.') && (s1[1] == '/')) /* Strip "./" */
+ s1 += 2;
+ while ((s2[0] == '.') && (s2[1] == '/')) /* Ditto */
+ s2 += 2;
+ opts = mopts; /* Match options */
+ if (itsadir) /* Current segment is a directory */
+ opts = mopts & 1; /* No fences */
+ s3 = s2; /* Get segment depth */
+ depth = 0;
+ while (*s3) { if (*s3++ == '/') depth++; }
+#ifndef NOSKIPMATCH
+ /* This speeds things up a bit. */
+ /* If it causes trouble define NOSKIPMATCH and rebuild. */
+ if (depth == 0 && (s1[0] == '*') && !s1[1])
+ mresult = xmatchdot ? 1 : (s2[0] != '.');
+ else
+#endif /* NOSKIPMATCH */
+ mresult = ckmatch(s1,s2,1,opts); /* Match */
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"traverse mresult depth",sofar,depth);
+ debug(F101,"traverse mresult xpatslash","",xpatslash);
+ debug(F111,"traverse mresult nambuf",nambuf,mresult);
+ debug(F111,"traverse mresult itswild",pl -> npart,itswild);
+ debug(F111,"traverse mresult segisdir",pl -> npart,segisdir);
+ }
+#endif /* DEBUG */
+ if (mresult || /* If match succeeded */
+ xrecursive || /* Or search is recursive */
+ depth < xpatslash /* Or not deep enough to match... */
+ ) {
+ if ( /* If it's not a directory... */
+/*
+ The problem here is that segisdir is apparently not set appropriately.
+ If I leave in the !segisdir test, then "dir /recursive blah" (where blah is
+ a directory name) misses some regular files because sometimes segisdir
+ is set and sometimes it's not. But if I comment it out, then
+ "dir <star>/<star>.txt lists every file in * and does not even open up the
+ subdirectories. However, "dir /rec <star>/<star>.txt" works right.
+*/
+#ifdef COMMENT
+ mresult && (!itsadir && !segisdir)
+#else
+ mresult && /* Matched */
+ !itsadir && /* sofar is not a directory */
+ ((!xrecursive && !segisdir) || xrecursive)
+#endif /* COMMENT */
+ ) {
+ debug(F110,
+ "traverse add: match && !itsadir",sofar,0);
+ addresult(sofar,itsadir);
+ if (numfnd < 0) return;
+ } else if (itsadir && (xrecursive || mresult)) {
+ struct path * xx = NULL;
+ *eos++ = DIRSEP; /* Add directory separator */
+ *eos = '\0'; /* to end of segment */
+#ifdef RECURSIVE
+ /* Copy previous pattern segment to this new directory */
+
+ if (xrecursive > 0 && !(pl -> fwd)) {
+ xx = (struct path *) malloc(sizeof (struct path));
+ pl -> fwd = xx;
+ if (xx) {
+ xx -> fwd = NULL;
+ strcpy(xx -> npart, pl -> npart); /* safe */
+ }
+ }
+#endif /* RECURSIVE */
+ traverse(pl -> fwd, sofar, eos); /* Traverse new directory */
+ }
+ }
+ }
+#ifdef OPENDIR
+ closedir(fd);
+#else /* !OPENDIR */
+ close(fd);
+#endif /* OPENDIR */
+}
+
+/*
+ * addresult:
+ * Adds a result string to the result array. Increments the number
+ * of matches found, copies the found string into our string
+ * buffer, and puts a pointer to the buffer into the caller's result
+ * array. Our free buffer pointer is updated. If there is no
+ * more room in the caller's array, the number of matches is set to -1.
+ * Input: a result string.
+ * Returns: nothing.
+ */
+static VOID
+addresult(str,itsadir) char *str; int itsadir; {
+ int len;
+
+ if (!freeptr) {
+ debug(F100,"addresult string space not init'd","",0);
+ initspace(mtchs,ssplen);
+ }
+ if (!str) str = "";
+ debug(F111,"addresult",str,itsadir);
+ if (!*str)
+ return;
+
+ if (itsadir < 0) {
+ itsadir = xisdir(str);
+ }
+ if ((xdironly && !itsadir) || (xfilonly && itsadir)) {
+ debug(F111,"addresult skip",str,itsadir);
+ return;
+ }
+ while (str[0] == '.' && ISDIRSEP(str[1])) /* Strip all "./" from front */
+ str += 2;
+ if (--remlen < 0) { /* Elements left in array of names */
+ debug(F111,"addresult ARRAY FULL",str,numfnd);
+ numfnd = -1;
+ return;
+ }
+ len = (int)strlen(str); /* Space this will use */
+ debug(F111,"addresult len",str,len);
+
+ if (len < 1)
+ return;
+
+ if ((freeptr + len + itsadir + 1) > (sspace + ssplen)) {
+ debug(F111,"addresult OUT OF SPACE",str,numfnd);
+#ifdef DYNAMIC
+ printf(
+"?String space %d exhausted - use SET FILE STRINGSPACE to increase\n",ssplen);
+#else
+ printf("?String space %d exhausted\n",ssplen);
+#endif /* DYNAMIC */
+ numfnd = -1; /* Do not record if not enough space */
+ return;
+ }
+ strcpy(freeptr,str); /* safe */
+
+ /* Tag directory names by putting '/' at the end */
+
+ if (itsadir && (freeptr[len-1] == '/')) {
+ freeptr[len++] = DIRSEP;
+ freeptr[len] = '\0';
+ }
+ if (numfnd >= maxnames) {
+#ifdef DYNAMIC
+ printf(
+"?Too many files (%d max) - use SET FILE LISTSIZE to increase\n",maxnames);
+#else
+ printf("?Too many files - %d max\n",maxnames);
+#endif /* DYNAMIC */
+ numfnd = -1;
+ return;
+ }
+ str = freeptr;
+ *resptr++ = freeptr;
+ freeptr += (len + 1);
+ numfnd++;
+ debug(F111,"addresult ADD",str,numfnd);
+}
+
+#ifdef COMMENT
+/*
+ * match(pattern,string):
+ * pattern matcher. Takes a string and a pattern possibly containing
+ * the wildcard characters '*' and '?'. Returns true if the pattern
+ * matches the string, false otherwise.
+ * Orignally by: Jeff Damens, CUCCA, 1984
+ * No longer used as of C-Kermit 7.0, now we use ckmatch() instead (ckclib.c).
+ *
+ * Input: a string and a wildcard pattern.
+ * Returns: 1 if match, 0 if no match.
+ */
+static int
+match(pattern, string) char *pattern, *string; {
+ char *psave = NULL, *ssave = NULL; /* Backup pointers for failure */
+ int q = 0; /* Quote flag */
+
+ if (*string == '.' && *pattern != '.' && !xmatchdot) {
+ debug(F110,"match skip",string,0);
+ return(0);
+ }
+ while (1) {
+ for (; *pattern == *string; pattern++,string++) /* Skip first */
+ if (*string == '\0') return(1); /* End of strings, succeed */
+
+ if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
+ q = 1; /* metacharacters */
+ pattern++; /* advance past quote */
+ if (*pattern != *string) return(0);
+ continue;
+ } else q = 0;
+
+ if (q) {
+ return(0);
+ } else {
+ if (*string != '\0' && *pattern == '?') {
+ pattern++; /* '?', let it match */
+ string++;
+ } else if (*pattern == '*') { /* '*' ... */
+ psave = ++pattern; /* remember where we saw it */
+ ssave = string; /* let it match 0 chars */
+ } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
+ /* ...have seen a star */
+ string = ++ssave; /* skip 1 char from string */
+ pattern = psave; /* and back up pattern */
+ } else return(0); /* otherwise just fail */
+ }
+ }
+}
+#endif /* COMMENT */
+
+/*
+ The following two functions are for expanding tilde in filenames
+ Contributed by Howie Kaye, CUCCA, developed for CCMD package.
+*/
+
+/* W H O A M I -- Get user's username. */
+
+/*
+ 1) Get real uid
+ 2) See if the $USER environment variable is set ($LOGNAME on AT&T)
+ 3) If $USER's uid is the same as ruid, realname is $USER
+ 4) Otherwise get logged in user's name
+ 5) If that name has the same uid as the real uid realname is loginname
+ 6) Otherwise, get a name for ruid from /etc/passwd
+*/
+char *
+whoami() {
+#ifdef DTILDE
+#ifdef pdp11
+#define WHOLEN 100
+#else
+#define WHOLEN 257
+#endif /* pdp11 */
+ static char realname[UIDBUFLEN+1]; /* user's name */
+ static int ruid = -1; /* user's real uid */
+ char loginname[UIDBUFLEN+1], envname[256]; /* temp storage */
+ char *c;
+ struct passwd *p;
+ _PROTOTYP(extern char * getlogin, (void) );
+
+ debug(F111,"whoami ruid A",realname,ruid);
+
+ if (ruid != -1)
+ return(realname);
+
+ ruid = real_uid(); /* get our uid */
+ debug(F101,"whoami ruid B","",ruid);
+ if (ruid < 0) ruid = getuid();
+ debug(F101,"whoami ruid C","",ruid);
+
+ /* how about $USER or $LOGNAME? */
+ if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
+ ckstrncpy(envname, c, 255);
+ debug(F110,"whoami envname",envname,0);
+ if ((p = getpwnam(envname)) != NULL) {
+ if (p->pw_uid == ruid) { /* get passwd entry for envname */
+ ckstrncpy(realname, envname, UIDBUFLEN); /* uid's are same */
+ debug(F110,"whoami realname",realname,0);
+ return(realname);
+ }
+ }
+ }
+
+ /* can we use loginname() ? */
+
+ if ((c = getlogin()) != NULL) { /* name from utmp file */
+ ckstrncpy (loginname, c, UIDBUFLEN);
+ debug(F110,"whoami loginname",loginname,0);
+ if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
+ if (p->pw_uid == ruid) /* for loginname */
+ ckstrncpy(realname, envname, UIDBUFLEN); /* if uid's are same */
+ }
+
+ /* Use first name we get for ruid */
+
+ if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
+ debug(F101,"whoami no username for ruid","",ruid);
+ realname[0] = '\0'; /* no user name */
+ ruid = -1;
+ return(NULL);
+ }
+ ckstrncpy(realname, p->pw_name, UIDBUFLEN);
+ debug(F110,"whoami realname from getpwuid",realname,0);
+ return(realname);
+#else
+ return(NULL);
+#endif /* DTILDE */
+}
+
+/* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */
+
+char *
+tilde_expand(dirname) char *dirname; {
+#ifdef DTILDE
+#ifdef pdp11
+#define BUFLEN 100
+#else
+#define BUFLEN 257
+#endif /* pdp11 */
+ struct passwd *user;
+ static char olddir[BUFLEN+1];
+ static char oldrealdir[BUFLEN+1];
+ static char temp[BUFLEN+1];
+ int i, j;
+
+ debug(F111,"tilde_expand",dirname,dirname[0]);
+
+ if (dirname[0] != '~') { /* Not a tilde...return param */
+ debug(F000,"tilde_expand NOT TILDE","",dirname[0]);
+ return(dirname);
+ }
+ if (!strcmp(olddir,dirname)) { /* Same as last time */
+ debug(F110,"tilde_expand same as previous",oldrealdir,0);
+ return(oldrealdir); /* so return old answer. */
+ } else {
+ debug(F110,"tilde_expand working...","",0);
+ j = (int)strlen(dirname);
+ for (i = 0; i < j; i++) /* find username part of string */
+ if (!ISDIRSEP(dirname[i]))
+ temp[i] = dirname[i];
+ else break;
+ temp[i] = '\0'; /* tie off with a NULL */
+ debug(F111,"tilde_expand first part",temp,i);
+ if (i == 1) { /* if just a "~" */
+#ifdef IKSD
+ if (inserver)
+ user = getpwnam(uidbuf); /* Get info on current user */
+ else
+#endif /* IKSD */
+ {
+ char * p = whoami();
+ debug(F110,"tilde_expand p",p,0);
+ if (p) {
+ user = getpwnam(p);
+ debug(F110,"tilde_expand getpwpam ~",user,0);
+ } else {
+ user = NULL;
+ }
+ }
+ } else {
+ debug(F110,"tilde_expand ~user",&temp[1],0);
+ user = getpwnam(&temp[1]); /* otherwise on the specified user */
+ debug(F110,"tilde_expand getpwpam user",user,0);
+ }
+
+ }
+ if (user != NULL) { /* valid user? */
+ ckstrncpy(olddir, dirname, BUFLEN); /* remember the directory */
+ ckstrncpy(oldrealdir,user->pw_dir, BUFLEN); /* and home directory */
+ ckstrncat(oldrealdir,&dirname[i], BUFLEN);
+ oldrealdir[BUFLEN] = '\0';
+ return(oldrealdir);
+ } else { /* invalid? */
+ ckstrncpy(olddir, dirname, BUFLEN); /* remember for next time */
+ ckstrncpy(oldrealdir, dirname, BUFLEN);
+ return(oldrealdir);
+ }
+#else
+ return(NULL);
+#endif /* DTILDE */
+}
+
+/*
+ Functions for executing system commands.
+ zsyscmd() executes the system command in the normal, default way for
+ the system. In UNIX, it does what system() does. Thus, its results
+ are always predictable.
+ zshcmd() executes the command using the user's preferred shell.
+*/
+int
+zsyscmd(s) char *s; {
+#ifdef aegis
+ if (nopush) return(-1);
+ if (!priv_chk()) return(system(s));
+#else
+ PID_T shpid;
+#ifdef COMMENT
+/* This doesn't work... */
+ WAIT_T status;
+#else
+ int status;
+#endif /* COMMENT */
+
+ if (nopush) return(-1);
+ if ((shpid = fork())) {
+ if (shpid < (PID_T)0) return(-1); /* Parent */
+ while (shpid != (PID_T) wait(&status))
+ ;
+ return(status);
+ }
+ if (priv_can()) { /* Child: cancel any priv's */
+ printf("?Privilege cancellation failure\n");
+ _exit(255);
+ }
+ restorsigs(); /* Restore ignored signals */
+#ifdef HPUX10
+ execl("/usr/bin/sh","sh","-c",s,NULL);
+ perror("/usr/bin/sh");
+#else
+#ifdef Plan9
+ execl("/bin/rc", "rc", "-c", s, NULL);
+ perror("/bin/rc");
+#else
+ execl("/bin/sh","sh","-c",s,NULL);
+ perror("/bin/sh");
+#endif /* Plan9 */
+#endif /* HPUX10 */
+ _exit(255);
+ return(0); /* Shut up ANSI compilers. */
+#endif /* aegis */
+}
+
+
+/* Z _ E X E C -- Overlay ourselves with another program */
+
+#ifndef NOZEXEC
+#ifdef HPUX5
+#define NOZEXEC
+#else
+#ifdef ATT7300
+#define NOZEXEC
+#endif /* ATT7300 */
+#endif /* HPUX5 */
+#endif /* NOZEXEC */
+
+VOID
+z_exec(p,s,t) char * p, ** s; int t; { /* Overlay ourselves with "p s..." */
+#ifdef NOZEXEC
+ printf("EXEC /REDIRECT NOT IMPLEMENTED IN THIS VERSION OF C-KERMIT\n");
+ debug(F110,"z_exec NOT IMPLEMENTED",p,0);
+#else
+ int x;
+ extern int ttyfd;
+ debug(F110,"z_exec command",p,0);
+ debug(F110,"z_exec arg 0",s[0],0);
+ debug(F110,"z_exec arg 1",s[1],0);
+ debug(F101,"z_exec t","",t);
+ errno = 0;
+ if (t) {
+ if (ttyfd > 2) {
+ dup2(ttyfd, 0);
+ dup2(ttyfd, 1);
+ /* dup2(ttyfd, 2); */
+ close(ttyfd);
+ }
+ }
+ restorsigs(); /* Restore ignored signals */
+ x = execvp(p,s);
+ if (x < 0) debug(F101,"z_exec errno","",errno);
+#endif /* NOZEXEC */
+}
+
+/*
+ Z S H C M D -- Execute a shell command (or program thru the shell).
+
+ Original UNIX code by H. Fischer; copyright rights assigned to Columbia U.
+ Adapted to use getpwuid to find login shell because many systems do not
+ have SHELL in environment, and to use direct calling of shell rather
+ than intermediate system() call. -- H. Fischer (1985); many changes since
+ then. Call with s pointing to command to execute. Returns:
+ -1 on failure to start the command (can't find, can't fork, can't run).
+ 1 if command ran and gave an exit status of 0.
+ 0 if command ran and gave a nonzero exit status.
+ with pexitstatus containing the command's exit status.
+*/
+int
+zshcmd(s) char *s; {
+ PID_T pid;
+
+#ifdef NOPUSH
+ return(0);
+#else
+ if (nopush) return(-1);
+ if (!s) return(-1);
+ while (*s == ' ') s++;
+
+ debug(F110,"zshcmd command",s,0);
+
+#ifdef aegis
+ if ((pid = vfork()) == 0) { /* Make child quickly */
+ char *shpath, *shname, *shptr; /* For finding desired shell */
+
+ if (priv_can()) exit(1); /* Turn off privs. */
+ if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
+
+#else /* All Unix systems */
+ if ((pid = fork()) == 0) { /* Make child */
+ char *shpath, *shname, *shptr; /* For finding desired shell */
+ struct passwd *p;
+#ifdef HPUX10 /* Default */
+ char *defshell = "/usr/bin/sh";
+#else
+#ifdef Plan9
+ char *defshell = "/bin/rc";
+#else
+ char *defshell = "/bin/sh";
+#endif /* Plan9 */
+#endif /* HPUX10 */
+ if (priv_can()) exit(1); /* Turn off privs. */
+#ifdef COMMENT
+/* Old way always used /etc/passwd shell */
+ p = getpwuid(real_uid()); /* Get login data */
+ if (p == (struct passwd *) NULL || !*(p->pw_shell))
+ shpath = defshell;
+ else
+ shpath = p->pw_shell;
+#else
+/* New way lets user override with SHELL variable, but does not rely on it. */
+/* This allows user to specify a different shell. */
+ shpath = getenv("SHELL"); /* What shell? */
+ debug(F110,"zshcmd SHELL",shpath,0);
+ {
+ int x = 0;
+ if (!shpath) {
+ x++;
+ } else if (!*shpath) {
+ x++;
+ }
+ if (x) {
+ debug(F100,"zshcmd SHELL not defined","",0);
+ p = getpwuid( real_uid() ); /* Get login data */
+ if (p == (struct passwd *)NULL || !*(p->pw_shell)) {
+ shpath = defshell;
+ } else {
+ shpath = p->pw_shell;
+ }
+ debug(F110,"zshcmd shpath from getpwuid",shpath,0);
+ }
+ }
+#endif /* COMMENT */
+#endif /* aegis */
+ shptr = shname = shpath;
+ while (*shptr != '\0')
+ if (*shptr++ == DIRSEP)
+ shname = shptr;
+ restorsigs(); /* Restore ignored signals */
+ debug(F110,"zshcmd execl shpath",shpath,0);
+ debug(F110,"zshcmd execl shname",shname,0);
+ if (s == NULL || *s == '\0') { /* Interactive shell requested? */
+ debug(F100,"zshcmd execl interactive","",0);
+ execl(shpath,shname,"-i",NULL); /* Yes, do that */
+ } else { /* Otherwise, */
+ debug(F110,"zshcmd execl command",s,0);
+ execl(shpath,shname,"-c",s,NULL); /* exec the given command */
+ } /* If execl() failed, */
+ debug(F101,"zshcmd errno","",errno);
+ perror(shpath); /* print reason and */
+ exit(BAD_EXIT); /* return bad return code. */
+
+ } else { /* Parent */
+
+ int wstat; /* ... must wait for child */
+#ifdef CK_CHILD
+ int child; /* Child's exit status */
+#endif /* CK_CHILD */
+ SIGTYP (*istat)(), (*qstat)();
+
+ if (pid == (PID_T) -1) return(-1); /* fork() failed? */
+
+ istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
+ qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
+
+ debug(F110,"zshcmd parent waiting for child",s,0);
+#ifdef CK_CHILD
+ while (((wstat = wait(&child)) != pid) && (wstat != -1))
+#else
+ while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
+#endif /* CK_CHILD */
+ ; /* Wait for fork */
+ signal(SIGINT,istat); /* Restore interrupts */
+ signal(SIGQUIT,qstat);
+#ifdef CK_CHILD
+ pexitstat = (child & 0xff) ? child : child >> 8;
+ debug(F101,"zshcmd exit status","",pexitstat);
+ return(child == 0 ? 1 : 0); /* Return child's status */
+#endif /* CK_CHILD */
+ }
+ return(1);
+#endif /* NOPUSH */
+}
+
+/* I S W I L D -- Check if filespec is "wild" */
+
+/*
+ Returns:
+ 0 wildcards disabled or argument is empty or is the name of a single file;
+ 1 if it contains wildcard characters.
+ Note: must match the algorithm used by match(), hence no [a-z], etc.
+*/
+int
+iswild(filespec) char *filespec; {
+ char c, *p, *f; int x;
+ int quo = 0;
+ if (!filespec) /* Safety */
+ return(0);
+ if (!wildena) /* Wildcards disabled - 12 Jun 2005 */
+ return(0);
+ f = filespec;
+ if (wildxpand) { /* Shell handles wildcarding */
+ if ((x = nzxpand(filespec,0)) > 1)
+ return(1);
+ if (x == 0) return(0); /* File does not exist */
+ p = malloc(MAXNAMLEN + 20);
+ znext(p);
+ x = (strcmp(filespec,p) != 0);
+ free(p);
+ p = NULL;
+ return(x);
+ } else { /* We do it ourselves */
+ while ((c = *filespec++) != '\0') {
+ if (c == '\\' && quo == 0) {
+ quo = 1;
+ continue;
+ }
+ if (!quo && (c == '*' || c == '?'
+#ifdef CKREGEX
+#ifndef VMS
+ || c == '['
+#endif /* VMS */
+ || c == '{'
+#endif /* CKREGEX */
+ )) {
+ debug(F111,"iswild",f,1);
+ return(1);
+ }
+ quo = 0;
+ }
+ debug(F111,"iswild",f,0);
+ return(0);
+ }
+}
+
+/*
+ I S D I R -- Is a Directory.
+
+ Tell if string pointer s is the name of an existing directory. Returns 1 if
+ directory, 0 if not a directory.
+
+ The following no longer applies:
+
+ If the file is a symlink, we return 1 if
+ it is a directory OR if it is a link to a directory and the "xrecursive" flag
+ is NOT set. This is to allow parsing a link to a directory as if it were a
+ directory (e.g. in the CD or IF DIRECTORY command) but still prevent
+ recursive traversal from visiting the same directory twice.
+*/
+
+#ifdef ISDIRCACHE
+/* This turns out to be unsafe and gives little benefit anyway. */
+/* See notes 28 Sep 2003. Thus ISDIRCACHE is not defined. */
+
+static char prevpath[CKMAXPATH+4] = { '\0', '\0' };
+static int prevstat = -1;
+int
+clrdircache() {
+ debug(F100,"CLEAR ISDIR CACHE","",0);
+ prevstat = -1;
+ prevpath[0] = NUL;
+}
+#endif /* ISDIRCACHE */
+
+int
+isalink(s) char *s; {
+#ifndef CKSYMLINK
+ return(0);
+#else
+ int r = 0;
+ char filbuf[CKMAXPATH+4];
+ if (readlink(s,filbuf,CKMAXPATH) > -1)
+ r = 1;
+ debug(F110,"isalink readlink",s,r);
+ return(r);
+#endif /* CKSYMLINK */
+}
+
+int
+isdir(s) char *s; {
+ int x, needrlink = 0, islink = 0;
+ struct stat statbuf;
+ char fnam[CKMAXPATH+4];
+
+ if (!s) return(0);
+ debug(F110,"isdir entry",s,0);
+#ifdef DTILDE /* 2005-08-13 */
+ if (*s == '~') { /* Starts with tilde? */
+ s = tilde_expand(s); /* Attempt to expand tilde */
+ if (!s) s = "";
+ debug(F110,"isdir tilde_expand",s,0);
+ }
+#endif /* DTILDE */
+ if (!*s) return(0);
+
+#ifdef ISDIRCACHE
+ if (prevstat > -1) {
+ if (s[0] == prevpath[0]) {
+ if (!strcmp(s,prevpath)) {
+ debug(F111,"isdir cache hit",s,prevstat);
+ return(prevstat);
+ }
+ }
+ }
+#endif /* ISDIRCACHE */
+
+#ifdef CKSYMLINK
+#ifdef COMMENT
+/*
+ The following over-clever bit has been commented out because it presumes
+ to know when a symlink might be redundant, which it can't possibly know.
+ Using plain old stat() gives Kermit the same results as ls and ls -R, which
+ is just fine: no surprises.
+*/
+#ifdef USE_LSTAT
+ if (xrecursive) {
+ x = lstat(s,&statbuf);
+ debug(F111,"isdir lstat",s,x);
+ } else {
+#endif /* USE_LSTAT */
+ x = stat(s,&statbuf);
+ debug(F111,"isdir stat",s,x);
+#ifdef USE_LSTAT
+ }
+#endif /* USE_LSTAT */
+#else
+ x = stat(s,&statbuf);
+ debug(F111,"isdir stat",s,x);
+#endif /* COMMENT */
+ if (x == -1) {
+ debug(F101,"isdir errno","",errno);
+ return(0);
+ }
+ islink = 0;
+ if (xrecursive) {
+#ifdef NOLINKBITS
+ needrlink = 1;
+#else
+#ifdef S_ISLNK
+ islink = S_ISLNK(statbuf.st_mode);
+ debug(F101,"isdir S_ISLNK islink","",islink);
+#else
+#ifdef _IFLNK
+ islink = (_IFMT & statbuf.st_mode) == _IFLNK;
+ debug(F101,"isdir _IFLNK islink","",islink);
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+#endif /* NOLINKBITS */
+ if (needrlink) {
+ if (readlink(s,fnam,CKMAXPATH) > -1)
+ islink = 1;
+ }
+ }
+#else
+ x = stat(s,&statbuf);
+ if (x == -1) {
+ debug(F101,"isdir errno","",errno);
+ return(0);
+ }
+ debug(F111,"isdir stat",s,x);
+#endif /* CKSYMLINK */
+ debug(F101,"isdir islink","",islink);
+ debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode);
+ x = islink ? 0 : (S_ISDIR (statbuf.st_mode) ? 1 : 0);
+#ifdef ISDIRCACHE
+ prevstat = x;
+ ckstrncpy(prevpath,s,CKMAXPATH+1);
+#endif /* ISDIRCACHE */
+ return(x);
+}
+
+#ifdef CK_MKDIR
+/* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */
+
+/* Z M K D I R -- Create directory(s) if necessary */
+/*
+ Call with:
+ A pointer to a file specification that might contain directory
+ information. The filename is expected to be included.
+ If the file specification does not include any directory separators,
+ then it is assumed to be a plain file.
+ If one or more directories are included in the file specification,
+ this routine tries to create them if they don't already exist.
+ Returns:
+ 0 or greater on success, i.e. the number of directories created.
+ -1 on failure to create the directory
+*/
+int
+zmkdir(path) char *path; {
+ char *xp, *tp, c;
+ int x, count = 0;
+
+ if (!path) path = "";
+ if (!*path) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zmkdir setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(path)) {
+ debug(F110,"zmkdir setroot violation",path,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = strlen(path);
+ debug(F111,"zmkdir",path,x);
+ if (x < 1 || x > MAXPATH) /* Check length */
+ return(-1);
+ if (!(tp = malloc(x+1))) /* Make a temporary copy */
+ return(-1);
+ strcpy(tp,path); /* safe (prechecked) */
+#ifdef DTILDE
+ if (*tp == '~') { /* Starts with tilde? */
+ xp = tilde_expand(tp); /* Attempt to expand tilde */
+ if (!xp) xp = "";
+ if (*xp) {
+ char *zp;
+ debug(F110,"zmkdir tilde_expand",xp,0);
+ if (!(zp = malloc(strlen(xp) + 1))) { /* Make a place for it */
+ free(tp);
+ tp = NULL;
+ return(-1);
+ }
+ free(tp); /* Free previous buffer */
+ tp = zp; /* Point to new one */
+ strcpy(tp,xp); /* Copy expanded name to new buffer */
+ }
+ }
+#endif /* DTILDE */
+ debug(F110,"zmkdir tp after tilde_expansion",tp,0);
+ xp = tp;
+ if (ISDIRSEP(*xp)) /* Don't create root directory! */
+ xp++;
+
+ /* Go thru filespec from left to right... */
+
+ for (; *xp; xp++) { /* Create parts that don't exist */
+ if (!ISDIRSEP(*xp)) /* Find next directory separator */
+ continue;
+ c = *xp; /* Got one. */
+ *xp = NUL; /* Make this the end of the string. */
+ if (!isdir(tp)) { /* This directory exists already? */
+#ifdef CK_LOGIN
+ if (isguest) /* Not allowed for guests */
+ return(-1);
+#ifndef NOXFER
+ /* Nor if MKDIR and/or CD are disabled */
+ else
+#endif /* CK_LOGIN */
+ if ((server
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) && (!ENABLED(en_mkd) || !ENABLED(en_cwd)))
+ return(-1);
+#endif /* IKSD */
+
+ debug(F110,"zmkdir making",tp,0);
+ x = /* No, try to create it */
+#ifdef NOMKDIR
+ -1 /* Systems without mkdir() */
+#else
+ mkdir(tp,0777) /* UNIX */
+#endif /* NOMKDIR */
+ ;
+ if (x < 0) {
+ debug(F101,"zmkdir failed, errno","",errno);
+ free(tp); /* Free temporary buffer. */
+ tp = NULL;
+ return(-1); /* Return failure code. */
+ } else
+ count++;
+ }
+ *xp = c; /* Replace the separator. */
+ }
+ free(tp); /* Free temporary buffer. */
+ return(count); /* Return success code. */
+}
+#endif /* CK_MKDIR */
+
+int
+zrmdir(path) char *path; {
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-1);
+#endif /* CK_LOGIN */
+
+ if (!path) path = "";
+ if (!*path) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zrmdir setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(path)) {
+ debug(F110,"zrmdir setroot violation",path,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+#ifndef NOMKDIR
+ return(rmdir(path));
+#else
+ return(-1);
+#endif /* NOMKDIR */
+}
+
+/* Z F S E E K -- Position input file pointer */
+/*
+ Call with:
+ CK_OFF_T (32 or 64 bits), 0-based, indicating desired position.
+ Returns:
+ 0 on success.
+ -1 on failure.
+*/
+#ifndef NORESEND
+int
+#ifdef CK_ANSIC
+zfseek(CK_OFF_T pos)
+#else
+zfseek(pos) CK_OFF_T pos;
+#endif /* CK_ANSIC */
+/* zfseek */ {
+ zincnt = -1; /* Must empty the input buffer */
+ debug(F101,"zfseek","",pos);
+ return(CKFSEEK(fp[ZIFILE], pos, 0)?-1:0);
+}
+#endif /* NORESEND */
+
+/* Z F N Q F P -- Convert filename to fully qualified absolute pathname */
+
+/*
+ Given a possibly unqualified or relative file specification fn, zfnqfp()
+ returns the fully qualified filespec for the same file, returning a struct
+ that contains the length (len) of the result, a pointer (fpath) to the
+ whole result, and a pointer (fname) to where the filename starts.
+*/
+static struct zfnfp fnfp = { 0, NULL, NULL };
+
+struct zfnfp *
+zfnqfp(fname, buflen, buf) char * fname; int buflen; char * buf; {
+ char * s;
+ int len;
+#ifdef MAXPATHLEN
+ char zfntmp[MAXPATHLEN+4];
+#else
+ char zfntmp[CKMAXPATH+4];
+#endif /* MAXPATHLEN */
+
+ char sb[32], * tmp;
+ int i = 0, j = 0, k = 0, x = 0, y = 0;
+ int itsadir = 0;
+
+ s = fname;
+ if (!s)
+ return(NULL);
+ if (!*s)
+ return(NULL);
+ if (!buf)
+ return(NULL);
+
+ /* Initialize the data structure */
+
+ fnfp.len = ckstrncpy(buf,fname,buflen);
+ fnfp.fpath = buf;
+ fnfp.fname = NULL;
+ len = buflen;
+ debug(F111,"zfnqfp fname",fname,len);
+
+#ifdef DTILDE
+ if (*s == '~') { /* Starts with tilde? */
+ char * xp;
+ xp = tilde_expand(s); /* Attempt to expand tilde */
+ debug(F110,"zfnqfp xp",xp,0); /* (realpath() doesn't do this) */
+ if (!xp) xp = "";
+ if (*xp)
+ s = xp;
+ }
+#endif /* DTILDE */
+
+#ifdef CKREALPATH
+
+/* N.B.: The realpath() result buffer MUST be MAXPATHLEN bytes long */
+/* otherwise we write over memory. */
+
+ if (!realpath(s,zfntmp)) {
+ debug(F111,"zfnqfp realpath fails",s,errno);
+#ifdef COMMENT
+ if (errno != ENOENT)
+ return(NULL);
+#else
+ /* If realpath() fails use the do-it-yourself method */
+ /* 16 Jan 2002 */
+ goto norealpath;
+#endif /* COMMENT */
+ }
+ len = strlen(zfntmp);
+ if (len > buflen) {
+ debug(F111,"zfnqfp result too long",ckitoa(buflen),len);
+ return(NULL);
+ } else {
+ ckstrncpy(buf,zfntmp,buflen);
+ }
+ if (buf[len-1] != '/') {
+ if ((itsadir = isdir(buf)) && len < (buflen - 1)) {
+ buf[len++] = '/';
+ buf[len] = NUL;
+ }
+ }
+ fnfp.len = len;
+ fnfp.fpath = buf;
+ debug(F110,"zfnqfp realpath path",fnfp.fpath,0);
+ tmp = buf + fnfp.len - 1;
+ if (!itsadir) {
+ while (tmp >= buf) {
+ if (*tmp == '/') {
+ fnfp.fname = tmp + 1;
+ debug(F110,"zfnqfp realpath name",fnfp.fname,0);
+ break;
+ }
+ tmp--;
+ }
+ }
+ return(&fnfp);
+
+#endif /* CKREALPATH */
+
+ norealpath:
+
+ tmp = zfntmp;
+ while (*s) { /* Remove leading "./" (0 or more) */
+ debug(F110,"zfnqfp while *s",s,0);
+ if (*s == '.' && *(s+1) == '/') {
+ s += 2;
+ while (*s == '/') s++;
+ } else
+ break;
+ }
+ if (!*s) return(NULL);
+ if (*s == '/') { /* Pathname is absolute */
+ ckstrncpy(buf,s,len);
+ x = strlen(buf);
+ y = 0;
+ } else { /* Pathname is relative */
+ char * p;
+ if (p = zgtdir()) { /* So get current directory */
+ debug(F110,"zfnqfp zgtdir",p,0);
+ x = ckstrncpy(buf,p,len);
+ buf[x++] = '/';
+ debug(F110,"zfnqfp buf 1",buf,0);
+ len -= x; /* How much room left in buffer */
+ if ((y = (int)strlen(s)) > len) /* If enough room... */
+ return(NULL);
+ ckstrncpy(buf+x,s,len); /* ... append the filename */
+ debug(F110,"zfnqfp buf 2",buf,0);
+ } else {
+ return(NULL);
+ }
+ }
+
+ /* Buf now holds full path but maybe containing some . or .. tricks */
+
+ j = x + y; /* Length of what's in buf */
+ len = j;
+ debug(F101,"zfnqfp len","",len);
+
+ /* Catch dangling "/." or "/.." */
+ if ((j > 1 && buf[j-1] == '.' && buf[j-2] == '/') ||
+ (j > 2 && buf[j-1] == '.' && buf[j-2] == '.' && buf[j-3] == '/')) {
+ if (j < buflen - 2) {
+ buf[j] = '/';
+ buf[j+1] = NUL;
+ }
+ }
+ j = -1; /* j = position of rightmost "/" */
+ i = 0; /* i = destination index */
+ tmp[i] = NUL; /* destination is temporary buffer */
+
+ for (x = 0; x < len; x++) { /* x = source index */
+ if (buf[x] == '/') {
+ for (k = 0; k < 4; k++) {
+ sb[k] = buf[x+k];
+ sb[k+1] = '\0';
+ if (!sb[k]) break;
+ }
+ if (!strncmp(sb,"/./",3)) { /* Eliminate "./" in "/./" */
+ x += 1;
+ continue;
+ } else if (!strncmp(sb,"//",2)) { /* Change "//" to "/" */
+ continue;
+ } else if (!strncmp(sb,"/../",4)) { /* ".." in path */
+ for (k = i - 1; k >= 0; k--) { /* Back up one level */
+ if (tmp[k] == '/') {
+ i = k;
+ tmp[i] = NUL;
+ break;
+ }
+ }
+ x += 2;
+ continue;
+ }
+ }
+ if (i >= (buflen - 1)) {
+ debug(F111,"zfnqfp overflow",tmp,i);
+ return(NULL);
+ }
+ tmp[i++] = buf[x]; /* Regular character, copy */
+ tmp[i] = NUL;
+ if (buf[x] == '/') /* Remember rightmost "/" */
+ j = i;
+ }
+ ckstrncpy(buf,tmp,buflen-1); /* Copy the result back */
+
+ buf[buflen-1] = NUL;
+ if (!buf[0]) { /* If empty, say root */
+ buf[0] = '/';
+ buf[2] = NUL;
+ j = 0;
+ i = 1;
+ }
+ if ((itsadir = isdir(buf))) {
+ if (buf[i-1] != '/' && i < (buflen - 1)) {
+ buf[i++] = '/';
+ buf[i] = NUL;
+ }
+ }
+ if (!itsadir && (j > -1)) { /* Set pointer to basename */
+ fnfp.fname = (char *)(buf + j);
+ fnfp.fpath = (char *)buf;
+ fnfp.len = i;
+ debug(F111,"zfnqfp path",fnfp.fpath,i);
+ debug(F110,"zfnqfp name",fnfp.fname,0);
+ return(&fnfp);
+ }
+ return(NULL);
+}
+
+/* Z C M P F N -- Compare two filenames */
+
+/* Returns 1 if the two names refer to the same existing file, 0 otherwise. */
+
+int
+zcmpfn(s1,s2) char * s1, * s2; {
+ char buf1[CKMAXPATH+1];
+ char buf2[CKMAXPATH+1];
+
+#ifdef USE_LSTAT
+ char linkname[CKMAXPATH+1];
+ struct stat buf;
+#endif /* USE_LSTAT */
+ int x, rc = 0;
+
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ if (!*s1 || !*s2) return(0);
+
+#ifdef CKSYMLINK /* We're doing symlinks? */
+#ifdef USE_LSTAT /* OK to use lstat()? */
+ x = lstat(s1,&buf);
+ if (x > -1 && /* Now see if it's a symlink */
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ ) {
+ linkname[0] = '\0'; /* Get the name */
+ x = readlink(s1,linkname,CKMAXPATH);
+ if (x > -1 && x < CKMAXPATH) { /* It's a link */
+ linkname[x] = '\0';
+ s1 = linkname;
+ }
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+
+ if (zfnqfp(s1,CKMAXPATH,buf1)) { /* Convert to full pathname */
+
+#ifdef CKSYMLINK /* Same deal for second name... */
+#ifdef USE_LSTAT
+ x = lstat(s2,&buf);
+ if (x > -1 &&
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ ) {
+ linkname[0] = '\0';
+ x = readlink(s2,linkname,CKMAXPATH);
+ if (x > -1 && x < CKMAXPATH) {
+ linkname[x] = '\0';
+ s2 = linkname;
+ }
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+ if (zfnqfp(s2,CKMAXPATH,buf2)) {
+ debug(F110,"zcmpfn s1",buf1,0);
+ debug(F110,"zcmpfn s2",buf2,0);
+ if (!strncmp(buf1,buf2,CKMAXPATH))
+ rc = 1;
+ }
+ }
+ debug(F101,"zcmpfn result","",rc);
+ return(rc);
+}
+
+#ifdef CKROOT
+
+/* User-mode chroot() implementation */
+
+int
+zsetroot(s) char * s; { /* Sets the root */
+ char buf[CKMAXPATH+1];
+ if (!s) return(-1);
+ if (!*s) return(-1);
+ debug(F110,"zsetroot",s,0);
+ if (!isdir(s)) return(-2);
+ if (!zfnqfp(s,CKMAXPATH,buf)) /* Get full, real path */
+ return(-3);
+ if (access(buf,R_OK) < 0) { /* Check access */
+ debug(F110,"zsetroot access denied",buf,0);
+ return(-4);
+ }
+ s = buf;
+ if (ckrootset) { /* If root already set */
+ if (!zinroot(s)) { /* make sure new root is in it */
+ debug(F110,"zsetroot new root not in root",ckroot,0);
+ return(-5);
+ }
+ }
+ if (zchdir(buf) < 1) return(-4); /* Change directory to new root */
+ ckrootset = ckstrncpy(ckroot,buf,CKMAXPATH); /* Now set the new root */
+ if (ckroot[ckrootset-1] != '/') {
+ ckroot[ckrootset++] = '/';
+ ckroot[ckrootset] = '\0';
+ }
+ debug(F111,"zsetroot rootset",ckroot,ckrootset);
+ ckrooterr = 0; /* Reset error flag */
+ return(1);
+}
+
+char *
+zgetroot() { /* Returns the root */
+ if (!ckrootset)
+ return(NULL);
+ return((char *)ckroot);
+}
+
+int
+zinroot(s) char * s; { /* Checks if file s is in the root */
+ int x, n;
+ struct zfnfp * f = NULL;
+ char buf[CKMAXPATH+2];
+
+ debug(F111,"zinroot setroot",ckroot,ckrootset);
+ ckrooterr = 0; /* Reset global error flag */
+ if (!ckrootset) /* Root not set */
+ return(1); /* so it's ok - no need to check */
+ if (!(f = zfnqfp(s,CKMAXPATH,buf))) /* Get full and real pathname */
+ return(0); /* Fail if we can't */
+ n = f->len; /* Length of full pathname */
+ debug(F111,"zinroot n",buf,n);
+ if (n < (ckrootset - 1) || n > CKMAXPATH) { /* Bad length */
+ ckrooterr = 1; /* Fail */
+ return(0);
+ }
+ if (isdir(buf) && buf[n-1] != '/') { /* If it's a directory name */
+ buf[n++] = '/'; /* make sure it ends with '/' */
+ buf[n] = '\0';
+ }
+ x = strncmp(buf,ckroot,ckrootset); /* Compare, case-sensitive */
+ debug(F111,"zinroot checked",buf,x);
+ if (x == 0) /* OK */
+ return(1);
+ ckrooterr = 1; /* Not OK */
+ return(0);
+}
+#endif /* CKROOT */
+
+#ifdef CK_LOGIN
+/*
+ The following code provides support for user login and logout
+ including anonymous accounts. If this feature is to be supported
+ outside of UNIX, it should be spread out among the ck?fio.c modules...
+*/
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/usr/bin/bash"
+#endif /* _PATH_BSHELL */
+#ifndef _PATH_FTPUSERS
+#define _PATH_FTPUSERS "/etc/ftpusers"
+#endif /* _PATH_FTPUSERS */
+
+/*
+ * Helper function for sgetpwnam().
+ */
+char *
+sgetsave(s) char *s; {
+ char *new = malloc((unsigned) strlen(s) + 1);
+ if (new == NULL) {
+ printf("?Local resource failure: malloc\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ (void) strcpy(new, s); /* safe */
+ return (new);
+}
+
+/*
+ * Save the result of getpwnam(). Used for USER command, since
+ * the data returned must not be clobbered by any other command
+ * (e.g., globbing).
+ */
+struct passwd *
+sgetpwnam(name) char *name; {
+ static struct passwd save;
+ register struct passwd *p;
+#ifdef CK_SHADOW
+ register struct spwd *sp;
+#endif /* CK_SHADOW */
+ char *sgetsave();
+
+#ifdef HPUX10_TRUSTED
+ struct pr_passwd *pr;
+#endif /* HPUX10_TRUSTED */
+
+#ifdef CK_SHADOW
+ sp = getspnam(name);
+ if (sp == NULL) {
+ debug(F110,"sgetpwnam","getspnam() fails",0);
+ return (NULL);
+ }
+#endif /* CK_SHADOW */
+
+#ifdef HPUX10_TRUSTED
+ if ((pr = getprpwnam(name)) == NULL)
+ return(NULL);
+#endif /* HPUX10_TRUSTED */
+
+ p = getpwnam(name);
+ /* debug(F111,"sgetpwnam","getpwnam()",p); */
+ if (p == NULL)
+ return(NULL);
+ if (save.pw_name) {
+ free(save.pw_name);
+ free(save.pw_passwd);
+ free(save.pw_gecos);
+ free(save.pw_dir);
+ free(save.pw_shell);
+ }
+ save = *p;
+ save.pw_name = sgetsave(p->pw_name);
+#ifdef CK_SHADOW
+ save.pw_passwd = sgetsave(sp->sp_pwdp);
+#else /* CK_SHADOW */
+#ifdef HPUX10_TRUSTED
+ if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
+ save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
+ else
+ save.pw_passwd = sgetsave("");
+#else /* HPUX10_TRUSTED */
+ save.pw_passwd = sgetsave(p->pw_passwd);
+#endif /* HPUX10_TRUSTED */
+#endif /* CK_SHADOW */
+ save.pw_gecos = sgetsave(p->pw_gecos);
+ save.pw_dir = sgetsave(p->pw_dir);
+ save.pw_shell = sgetsave(p->pw_shell);
+ return(&save);
+}
+
+#define CKXLOGBSIZ 256
+
+struct passwd * pw = NULL;
+char * home = NULL; /* Home directory pointer for glob */
+#ifdef CMASK
+#undef CMASK
+#endif /* CMASK */
+
+#define CMASK 027
+
+int defumask = CMASK; /* Default umask value */
+
+/* Z V U S E R -- Verify user, Returns 1 if user OK, 0 otherwise. */
+
+/* Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected. If logged in previously,
+ * need to reset state. If name is "ftp" or "anonymous", the name is not in
+ * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway. Otherwise, check user
+ * requesting login privileges. Disallow anyone who does not have a standard
+ * shell as returned by getusershell(). Disallow anyone mentioned in the file
+ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
+ */
+_PROTOTYP(static int checkuser, (char *) );
+
+char zvuname[64] = { NUL, NUL };
+char zvhome[CKMAXPATH+1] = { NUL, NUL };
+#define ZENVUSER 70
+#define ZENVHOME CKMAXPATH+12
+#define ZENVLOGNAME 74
+static char zenvuser[ZENVUSER];
+static char zenvhome[ZENVHOME];
+static char zenvlogname[ZENVLOGNAME];
+
+#ifdef CK_PAM
+static char pam_data[500];
+struct pam_conv pam_conv = {pam_cb, pam_data}; /* PAM structure */
+struct pam_handle * pamh = NULL; /* PAM reference handle */
+#endif /* CK_PAM */
+
+int
+zvuser(name) char *name; {
+ register char *cp = NULL;
+ int x;
+ char *shell;
+#ifdef GETUSERSHELL
+_PROTOTYP(char * getusershell, (void) );
+#endif /* GETUSERSHELL */
+#ifndef NODCLENDUSERSHELL
+_PROTOTYP(VOID endusershell, (void) );
+#endif /* NODCLENDUSERSHELL */
+
+#ifdef CK_PAM
+ int pam_status;
+ const char * reply = NULL;
+#endif /* CK_PAM */
+
+ debug(F111,"user",name,logged_in);
+
+ if (!name) name = "";
+ zvuname[0] = NUL;
+
+ debug(F101,"zvuser ckxsyslog","",ckxsyslog);
+
+#ifdef CKSYSLOG
+ debug(F100,"zvuser CKSYSLOG defined","",0);
+#endif /* CKSYSLOG */
+
+ if (logged_in) /* Should not be called if logged in */
+ return(0);
+
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: user %s",name
+ );
+ }
+#endif /* CKSYSLOG */
+
+ guest = 0; /* Assume not guest */
+ askpasswd = 0;
+
+ if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
+ debug(F101,"zvuser anonymous ckxanon","",ckxanon);
+ if (!ckxanon) { /* Anonymous login not allowed */
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous login not allowed: %s",
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+ if (checkuser("ftp") || checkuser("anonymous")) {
+ debug(F100,"zvuser anon forbidden by ftpusers file","",0);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous login forbidden by ftpusers file: %s",
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ } else if ((pw = sgetpwnam("ftp")) != NULL) {
+ debug(F100,"zvuser anon sgetpwnam(ftp) OK","",0);
+ guest = 1;
+ askpasswd = 1;
+ ckstrncpy(zvuname,"anonymous",64);
+ return(1);
+ } else {
+ debug(F100,"zvuser anon sgetpwnam(ftp) FAILED","",0);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous getpwnam(ftp) failed: %s",
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+ }
+ pw = sgetpwnam(name);
+ if (pw) {
+/*
+ Of course some UNIX platforms (like AIX) don't have getusershell().
+ In that case we can't check if the user's account has been "turned off"
+ or somesuch, e.g. by setting their shell to "/etc/nologin" or somesuch,
+ which runs (usually just printing a message and exiting), but which is
+ not listed in /etc/shells. For that matter, if getusershell() is not
+ available, then probably neither is /etc/shells.
+*/
+ debug(F100,"zvuser sgetpwnam ok","",0);
+ shell = pw->pw_shell;
+ if (!shell) shell = "";
+ if (!*shell)
+ shell = _PATH_BSHELL;
+ debug(F110,"zvuser shell",shell,0);
+#ifdef GETUSERSHELL
+ while ((cp = getusershell()) != NULL) {
+ debug(F110,"zvuser getusershell",cp,0);
+ if ((int)strcmp(cp, shell) == 0)
+ break;
+ }
+ debug(F100,"zvuser endusershell 1","",0);
+#ifndef NODCLENDUSERSHELL
+ (VOID) endusershell();
+#else
+ endusershell();
+#endif /* NODCLENDUSERSHELL */
+ debug(F100,"zvuser endusershell 2","",0);
+#else /* GETUSERSHELL */
+ cp = ""; /* Do not refuse if we cannot check */
+#endif /* GETUSERSHELL */
+ x = checkuser(name);
+ debug(F101,"zvuser checkuser","",x);
+ if (cp == NULL) {
+ debug(F100,"zvuser refused 1","",0);
+ pw = (struct passwd *) NULL;
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: invalid shell %s for %s %s",shell, name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ } else if (x) {
+ debug(F100,"zvuser refused 2","",0);
+ pw = (struct passwd *) NULL;
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: %s login forbidden by ftpusers file: %s",
+ name, clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ } else {
+ x = 0;
+#ifdef CK_PAM
+ /* Get PAM authentication details */
+ debug(F110,"zvuser","calling pam_start",0);
+ if ((pam_status =
+ pam_start(PAM_SERVICE_TYPE,name,&pam_conv,&pamh))
+ != PAM_SUCCESS) {
+ reply = pam_strerror(NULL, pam_status);
+ debug(F110,"zvuser PAM failure",reply,0);
+ printf("%s\n",reply);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: %s refused by PAM \"%s\": %s",
+ name,reply,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+#endif /* CK_PAM */
+ askpasswd = 1;
+ ckstrncpy(zvuname,name,64);
+ return(1);
+ }
+ } else {
+ x = 0;
+ debug(F100,"zvuser sgetpwnam NULL","",0);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: getpwnam(%s) failed: %s",name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+
+#ifdef FTP_KERBEROS
+ if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) {
+#ifdef COMMENT
+ /* Why sprintf and then printf? */
+ /* Also, what is kerb_ok? And is the test on it right? */
+ char buf[CKXLOGBSIZ];
+ sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s%s",
+ kdata.pname, *kdata.pinst ? "." : "",
+ kdata.pinst, kdata.prealm,
+ (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not",
+ name, kerb_ok ? "" : "; Password required.");
+ printf("%s", buf);
+#else
+ printf("Kerberos user %s%s%s@%s is%s authorized as %s%s",
+ kdata.pname, *kdata.pinst ? "." : "",
+ kdata.pinst, kdata.prealm,
+ (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not",
+ name, kerb_ok ? "" : "; Password required.");
+#endif /* COMMENT */
+ if (kerb_ok) return(1);
+ } else
+ return(0);
+#endif /* FTP_KERBEROS */
+}
+
+/* Check if the given user is in the forbidden-user file */
+
+static int
+checkuser(name) char *name; {
+ extern char * userfile;
+ FILE *fd;
+ int i;
+ char line[CKXLOGBSIZ+1];
+
+ if (!name)
+ name = "";
+ i = strlen(name);
+ debug(F111,"checkuser name",name,i);
+ if (!*name)
+ return(1);
+
+ fd = fopen(userfile ? userfile : _PATH_FTPUSERS, "r");
+ /* debug(F111,"checkuser userfile",userfile,fd); */
+ if (fd) {
+ line[0] = '\0';
+ while (fgets(line, sizeof(line), fd)) {
+ debug(F110,"checkuser line",line,0);
+ if (line[0] <= '#')
+ continue;
+ if (strncmp(line, name, i) == 0) {
+ debug(F110,"checkuser REFUSED",name,0);
+ return(1);
+ }
+ line[0] = '\0';
+ }
+ (VOID) fclose(fd);
+ }
+ debug(F110,"checkuser OK",name,0);
+ return(0);
+}
+
+/* Z V L O G O U T -- Log out from Internet Kermit Service */
+
+VOID
+zvlogout() {
+#ifdef COMMENT
+ /* This could be dangerous */
+ if (setuid((UID_T)0) < 0) {
+ debug(F100,"zvlogout setuid FAILED","",0);
+ goto bad;
+ }
+ debug(F100,"zvlogout setuid OK","",0);
+#endif /* COMMENT */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ cksyslog(SYSLG_LI, 1, "logout",(char *) uidbuf, clienthost);
+ }
+#endif /* CKSYSLOG */
+#ifdef CKWTMP
+ debug(F110,"WTMP logout",cksysline,logged_in);
+ if (logged_in)
+ logwtmp(cksysline, "", "");
+#endif /* CKWTMP */
+ pw = NULL;
+ logged_in = 0;
+ guest = 0;
+ isguest = 0;
+}
+
+#ifdef FTP_KERBEROS
+kpass(name, p) char *name, *p; {
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ char tkt_file[20];
+ KTEXT_ST ticket;
+ AUTH_DAT authdata;
+ unsigned long faddr;
+ struct hostent *hp;
+
+ if (krb_get_lrealm(realm, 1) != KSUCCESS)
+ return(0);
+
+ ckstrncpy(tkt_file, TKT_ROOT, 20);
+ ckstrncat(tkt_file, "_ftpdXXXXXX", 20);
+ krb_set_tkt_string(mktemp(tkt_file));
+
+ (VOID) ckstrncpy(instance, krb_get_phost(hostname), sizeof(instance));
+
+ if ((hp = gethostbyname(instance)) == NULL)
+ return(0);
+
+#ifdef HADDRLIST
+ hp = ck_copyhostent(hp); /* safe copy that won't change */
+#endif /* HADDRLIST */
+ bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
+
+ if (krb_get_pw_in_tkt(name, "", realm, "krbtgt", realm, 1, p) ||
+ krb_mk_req(&ticket, "rcmd", instance, realm, 33) ||
+ krb_rd_req(&ticket, "rcmd", instance, faddr, &authdata, "") ||
+ kuserok(&authdata, name)) {
+ dest_tkt();
+ return(0);
+ }
+ dest_tkt();
+ return(1);
+}
+#endif /* FTP_KERBEROS */
+
+VOID
+zsyslog() {
+#ifdef CKSYSLOG
+ if (ckxsyslog && !ckxlogging) {
+#ifdef LOG_DAEMON
+ openlog(inserver ? "iksd" : "ckermit", LOG_PID, LOG_DAEMON);
+#else
+ openlog(inserver ? "iksd" : "ckermit", LOG_PID);
+#endif /* LOG_DAEMON */
+ ckxlogging = 1;
+ debug(F100,"zsyslog syslog opened","",0);
+ }
+#endif /* CKSYSLOG */
+}
+
+/* Z V P A S S -- Verify password; returns 1 if OK, 0 otherwise */
+
+#ifndef AUTH_USER
+#define AUTH_USER 3
+#endif /* AUTH_USER */
+#ifndef AUTH_VALID
+#define AUTH_VALID 4
+#endif /* AUTH_VALID */
+
+#ifdef __FreeBSD__ /* 299 This was necessary in */
+#ifndef NODCLINITGROUPS /* FreeBSD 4.4, don't know */
+#define NODCLINITGROUPS /* about other versions... */
+#endif /* NODCLINITGROUPS */
+#endif /* __FreeBSD__ */
+
+int
+zvpass(p) char *p; {
+#ifndef NODCLINITGROUPS
+_PROTOTYP(int initgroups, (const char *, gid_t) );
+#endif /* NODCLINITGROUPS */
+
+ char *xpasswd, *salt;
+ char * dir = NULL;
+#ifdef CK_PAM
+ int pam_status;
+ const char * reply = NULL;
+#endif /* CK_PAM */
+
+ if (logged_in || askpasswd == 0) {
+ return(0);
+ }
+ debug(F111,"zvpass",p ? (guest ? p : "xxxxxx") : "(null)",guest);
+ if (!p) p = "";
+ askpasswd = 0;
+ if (guest && !*p) { /* Guests must specify a password */
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous guests must specify a password"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+ if (!guest
+#ifdef CK_AUTHENTICATION
+ && ck_tn_auth_valid() != AUTH_VALID
+#endif /* CK_AUTHENTICATION */
+ ) { /* "ftp" is only account allowed no password */
+#ifdef CK_PAM
+ debug(F110,"zvpass","calling pam_set_item(AUTHTOK)",0);
+ if ((pam_status = pam_set_item(pamh,PAM_AUTHTOK,p)) != PAM_SUCCESS) {
+ reply = pam_strerror(pamh, pam_status);
+ debug(F110,"zvpass PAM failure",reply,0);
+ /* if no password given treat as non-fatal error */
+ /* pam will prompt for password in pam_authenticate() */
+ if (!p) {
+ printf("%s\n",reply);
+ pam_end(pamh, 0);
+ debug(F100,"zvpass denied","",0);
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+ }
+ debug(F110,"zvpass","calling pam_authenticate",0);
+#ifdef COMMENT
+ if (*p)
+ pam_pw = p;
+#else
+/*
+ Make IKSD authentication (using PAM) ask for a password when an
+ invalid username has been given, to avoid disclosing which account
+ names are valid. See #417247 (Debian).
+*/
+ if (*p
+#ifdef CK_LOGIN
+ || gotemptypasswd
+#endif /* CK_LOGIN */
+ )
+ pam_pw = p;
+#endif /* COMMENT */
+ if ((pam_status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
+ reply = pam_strerror(pamh, pam_status);
+ debug(F110,"zvpass PAM failure",reply,0);
+ printf("%s\n",reply);
+ pam_end(pamh, 0);
+ debug(F100,"zvpass denied","",0);
+ pam_pw = NULL;
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+ pam_pw = NULL;
+ debug(F110,"zvpass","calling pam_acct_mgmt",0);
+ if ((pam_status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
+ reply = pam_strerror(pamh, pam_status);
+ debug(F110,"zvpass PAM failure",reply,0);
+ printf("%s\n",reply);
+ pam_end(pamh, 0);
+ debug(F100,"zvpass denied","",0);
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+ debug(F110,"zvpass","PAM validates OK",0);
+ pam_end(pamh,0);
+#else /* CK_PAM */
+ if (pw == NULL)
+ salt = "xx";
+ else
+ salt = pw->pw_passwd;
+
+#ifdef HPUX10_TRUSTED
+ xpasswd = bigcrypt(p, salt);
+#else
+/*
+ On 64-bit platforms this can give "cast to pointer from integer of
+ different size" warning, but I'm not sure what the effect is at runtime,
+ or what to do about it.
+ */
+ xpasswd = (char *)crypt(p, salt);
+#endif /* HPUX10_TRUSTED */
+
+ if (
+#ifdef FTP_KERBEROS
+ /* null pw_passwd ok if Kerberos password ok */
+ pw == NULL ||
+ ((*pw->pw_passwd != '\0' ||
+ strcmp(xpasswd, pw->pw_passwd))
+ && !kpass(pw->pw_name, p))
+#else
+#ifdef CK_SRP
+ /* check with tpasswd first if there */
+ pw == NULL || *pw->pw_passwd == '\0' ||
+ t_verifypw (pw->pw_name, p) == 0 ||
+ (t_verifypw (pw->pw_name, p) < 0 &&
+ strcmp (xpasswd, pw->pw_passwd))
+#else /* CK_SRP */
+ /* The strcmp does not catch null passwords! */
+ (pw == NULL) || (*pw->pw_passwd == '\0') ||
+ strcmp(xpasswd, pw->pw_passwd)
+#endif /* CK_SRP */
+#endif /* FTP_KERBEROS */
+ ) {
+ debug(F100,"zvpass denied","",0);
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+#endif /* CK_PAM */
+ }
+
+ (VOID) setgid((GID_T)pw->pw_gid); /* Set group ID */
+
+#ifndef NOINITGROUPS
+ (VOID) initgroups(pw->pw_name, pw->pw_gid);
+#endif /* NOINITGROUPS */
+
+ logged_in = 1;
+ dir = pw->pw_dir;
+
+#ifdef CKWTMP
+ /* Open wtmp before chroot */
+ if (ckxwtmp) {
+ sprintf(cksysline,"iks_%04x", getpid()); /* safe */
+ logwtmp(cksysline, pw->pw_name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ debug(F110,"WTMP login",cksysline,logged_in);
+ }
+#endif /* CKWTMP */
+/*
+ For anonymous users, we chroot to user ftp's home directory unless
+ started with --anonroot:xxx, in which case we chroot to xxx. We must
+ immediately chdir() to the same directory we chroot() to or else the
+ old current directory remains accessible as "." outside the new root.
+*/
+ if (guest) {
+ if (anonroot) /* Non-default anonymous root */
+ dir = anonroot;
+ else
+ makestr(&anonroot,dir);
+ errno = 0;
+ debug(F110,"zvpass anon chroot",dir,0);
+ if (chroot(dir) < 0) {
+ debug(F111,"zvpass anon chroot FAILED",dir,errno);
+ goto bad;
+ }
+ errno = 0;
+ if (chdir("/") < 0) {
+ debug(F111,"zvpass anon chdir FAILED",dir,errno);
+ goto bad;
+ }
+ debug(F110,"zvpass anon chroot/chdir OK",dir,0);
+ } else if (chdir(dir) < 0) { /* Not guest */
+#ifdef COMMENT
+ if (chdir("/") < 0) {
+ debug(F110,"Non-guest chdir FAILED",dir,0);
+ goto bad;
+ } else
+ printf("?No directory! Logging in with home=/\n");
+#else
+ debug(F110,"zvpass non-guest chdir FAILED",dir,0);
+ goto bad; /* Be conservative at first */
+#endif /* COMMENT */
+ }
+ debug(F110,"zvpass non-guest chdir OK",dir,0);
+ if (setuid((UID_T)pw->pw_uid) < 0) {
+ debug(F101,"zvpass setuid FAILED","",pw->pw_uid);
+ goto bad;
+ }
+ debug(F101,"zvpass setuid OK","",pw->pw_uid);
+
+ guestpass[0] = '\0';
+ if (guest) {
+ extern int fncact;
+ isguest = 1;
+ fncact = XYFX_R; /* FILE COLLISION = RENAME */
+ debug(F110,"GUEST fncact=R",p,0);
+ lset(guestpass,"anonymous:",10,32);
+ ckstrncpy(&guestpass[10],p,GUESTPASS-10);
+ home = "/";
+ printf("Anonymous login.\r\n");
+
+#ifdef SETPROCTITLE
+ /* proctitle declared where? Obviously this code is never compiled. */
+ sprintf(proctitle, "%s: anonymous/%.*s",
+ clienthost ? clienthost : "(unk)",
+ sizeof(proctitle) - sizeof(clienthost) -
+ sizeof(": anonymous/"), p);
+ setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous %s %s",
+ clienthost ? clienthost : "(unknown host)",
+ p
+ );
+ }
+#endif /* CKSYSLOG */
+
+ } else { /* Real user */
+ isguest = 0;
+ home = dir;
+ ckstrncpy(guestpass,zvuname,GUESTPASS);
+
+ printf("User %s logged in.\r\n", pw->pw_name);
+#ifdef SETPROCTITLE
+ /* not used */
+ sprintf(proctitle, "%s: %s",
+ clienthost ? clienthost : "(unk)",
+ pw->pw_name
+ );
+ setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging)
+ syslog(LOG_INFO, "login: %s %s",
+ pw->pw_name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+#endif /* CKSYSLOG */
+ }
+ ckstrncpy(zvhome,home,CKMAXPATH); /* Set environment variables */
+#ifndef NOPUTENV
+
+ ckmakmsg(zenvuser,ZENVUSER,"USER=",zvuname,NULL,NULL);
+ putenv((char *)zenvuser);
+ ckmakmsg(zenvlogname,ZENVLOGNAME,"LOGNAME=",zvuname,NULL,NULL);
+ putenv((char *)zenvlogname);
+ ckmakmsg(zenvhome,ZENVHOME,"HOME=",zvhome,NULL,NULL);
+ putenv((char *)zenvhome);
+#endif /* NOPUTENV */
+ /* homdir = (char *)zvhome; */
+ ckstrncpy((char *)uidbuf,(char *)zvuname,64);
+ (VOID) umask(defumask);
+#ifdef IKSDB
+ if (ikdbopen) {
+ char * p2;
+ int k;
+ extern char dbrec[];
+ extern unsigned long myflags;
+ extern unsigned int mydbslot;
+ extern struct iksdbfld dbfld[];
+#ifdef CK_AUTHENTICATION
+ extern unsigned long myamode, myatype;
+#endif /* CK_AUTHENTICATION */
+ myflags |= DBF_LOGGED;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"zvpass guest","",guest);
+ debug(F111,"zvpass zvuname",zvuname,0);
+ debug(F110,"zvpass guestpass",guestpass,0);
+ debug(F110,"zvpass dir",dir,0);
+ debug(F110,"zvpass home",home,0);
+ debug(F110,"zvpass anonroot",anonroot,0);
+ }
+#endif /* DEBUG */
+ p2 = guest ? guestpass : zvuname;
+ if (guest) {
+ p2 = (char *)guestpass;
+ myflags &= ~DBF_USER;
+ } else {
+ p2 = (char *)zvuname;
+ myflags |= DBF_USER;
+ }
+ k = strlen(p2);
+ strncpy(&dbrec[DB_ULEN],ulongtohex((unsigned long)k,4),4);
+ lset(&dbrec[dbfld[db_USER].off],p2,1024,32);
+ strncpy(&dbrec[DB_FLAGS],ulongtohex(myflags,4),4);
+#ifdef CK_AUTHENTICATION
+ myamode = ck_tn_auth_valid();
+ strncpy(&dbrec[DB_AMODE],ulongtohex(myamode,4),4);
+ myatype = ck_tn_authenticated();
+ strncpy(&dbrec[DB_ATYPE],ulongtohex(myatype,4),4);
+#endif /* CK_AUTHENTICATION */
+ if (guest) {
+ p2 = dir;
+ } else {
+ p2 = zgtdir();
+ if (!p2) p2 = "";
+ if (!*p2) p2 = home;
+ }
+ strncpy(&dbrec[DB_DLEN],
+ ulongtohex((unsigned long)strlen(p2),4),
+ 4
+ );
+ lset(&dbrec[dbfld[db_DIR].off],p2,1024,32);
+ updslot(mydbslot);
+ }
+#endif /* IKSDB */
+ return(1);
+
+bad: /* Common failure exit */
+ zvuname[0] = NUL;
+ zvlogout();
+ return(0);
+}
+#endif /* CK_LOGIN */
+
+/* Buggy Xenix 2.3.4 cc needs this line after the endif */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuins.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckuins.txt
new file mode 100644
index 0000000..08cfedb
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuins.txt
@@ -0,0 +1,3588 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+C-Kermit 9.0 Installation Instructions and Options for Unix
+
+ [ [11]Contents ] [ [12]C-Kermit ] [ [13]Kermit Home ]
+
+ Frank da Cruz
+ The Kermit Project
+ Columbia University
+
+ As of C-Kermit version: 9.0.302, 20 August 2011
+ This file last updated: Sun Aug 21 12:08:29 2011 (New York City
+ time)
+
+ IF YOU ARE READING A PLAIN-TEXT version of this document, it is a
+ plain-text copy of a Web page. You can visit the original (and possibly
+ more up-to-date) Web page here:
+
+[14]http://www.columbia.edu/kermit/ckuins.html
+
+CONTENTS
+
+ [15]OVERVIEW
+ 1. [16]INTERNET QUICK START
+ 2. [17]INSTALLING FROM PACKAGES
+ 3. [18]INSTALLING PREBUILT BINARIES
+ 4. [19]BUILDING FROM SOURCE CODE
+ 5. [20]INSTALLING THE KERMIT FILES
+ 6. [21]INSTALLING UNIX C-KERMIT FROM DOS-FORMAT DISKETTES
+ 7. [22]CHECKING THE RESULTS
+ 8. [23]REDUCING THE SIZE OF THE EXECUTABLE PROGRAM IMAGE
+ 9. [24]UNIX VERSIONS
+ 10. [25]DIALING OUT AND COORDINATING WITH UUCP
+ 11. [26]RUNNING UNIX C-KERMIT SETUID OR SETGID
+ 12. [27]CONFIGURING UNIX WORKSTATIONS
+ 13. [28]BIZARRE BEHAVIOR AT RUNTIME
+ 14. [29]CRASHES AND CORE DUMPS
+ 15. [30]SYSLOGGING
+ 16. [31]BUILDING SECURE VERSIONS OF C-KERMIT 9.0
+ 17. [32]INSTALLING C-KERMIT AS AN SSH SERVER SUBSYSTEM
+
+OVERVIEW
+
+ [ [33]Top ] [ [34]Contents ] [ [35]Next ]
+
+ WARNING: This document contains notes that have been accumulating
+ since the mid 1980s. Many of the products and Unix versions
+ mentioned here have not been heard of in a long while, but that does
+ not necessarily mean they are not still running in some obscure
+ nook.
+
+ This file contains Unix-specific information. A lot of it. Unlike most
+ other packages, C-Kermit tries very hard to be portable to every Unix
+ variety (and every release of each one) known to exist, including many
+ that are quite old, as well as to other platforms like VMS, AOS/VS,
+ VOS, OS-9, the BeBox, the Amiga, etc.
+
+ Since C-Kermit gets so deeply into the file system, i/o system, and
+ other areas that differ radically from one Unix platform to the next,
+ this means that a lot can go wrong when you try to install C-Kermit on
+ (for example) a new release of a particular variety of Unix, in which
+ certain things might have changed that C-Kermit depended upon.
+
+ This file concentrates on installation. For a description of general
+ configuration options for C-Kermit, please read the [36]Configurations
+ Options document. For troubleshooting after installation, see the
+ [37]General Hints and Tips and [38]Unix-Specific Hints and Tips
+ documents. The latter, in particular, contains lots of information on
+ lots of specific Unix platforms. If you want to work on the source
+ code, see the [39]C-Kermit Program Logic Manual
+
+ You may install C-Kermit:
+
+ * From an "[40]install package", if one is available.
+ * As a [41]prebuilt binary, if available, plus accompanying text
+ files.
+ * By building from [42]source code.
+
+1. INTERNET QUICK START
+
+ [ [43]Top ] [ [44]Contents ] [ [45]Next ] [ [46]Previous ]
+
+ If your Unix computer is on the Internet and it has a C compiler,
+ here's how to download, build, and install C-Kermit directly from the
+ "tarballs" or Zip archives:
+
+ 1. Make a fresh directory and cd to it.
+ 2. Download the C-Kermit source code:
+ [47]ftp://www.columbia.edu/kermit/archives/cku211.tar.Z (compress
+ format) or [48]ftp://www.columbia.edu/kermit/archives/cku211.tar.gz
+ (gunzip format). If those links don't work, FTP transfers are being
+ blocked; try these HTTP links instead:
+ [49]http://kermit.columbia.edu/ftp/archives/cku211.tar.Z (compress
+ format) or
+ [50]http://kermit.columbia.edu/ftp/archives/cku211.tar.gz (gunzip
+ format).
+ 3. Uncompress the compressed tar file with "uncompress" or "gunzip",
+ according to which type of compressed file you downloaded. (If you
+ don't understand this, you could download a (much larger)
+ uncompressed tar archive directly:
+ [51]ftp://www.columbia.edu/kermit/archives/cku211.tar or
+ [52]http://kermit.columbia.edu/ftp/archives/cku211.tar
+ 4. Now type "tar xvf cku211.tar" to unpack the individual files from
+ the tar archive.
+ 5. Type "rm cku211.tar" to get rid of the tar archive, which is no
+ longer needed.
+ 6. Read the comments at the top of the makefile to find out which
+ target to use and then type the appropriate "make" command, such as
+ "make linux", "make solaris8", etc.
+ 7. This produces a binary in your current directory called "wermit".
+ Start it by typing "./wermit" and [53]try it out to make sure it
+ works. Then read [54]Section 5 for how to install it, or simply
+ copy the wermit binary to the desired public directory, rename it
+ to kermit, and give it the needed permissions (and, if it is going
+ to be used to dial out, give it the same group and owner and
+ permissions as the cu, tip, or minicom program).
+
+ For secure installations, see [55]Sections 5 and [56]16.
+
+2. INSTALLING FROM PACKAGES
+
+ [ [57]Top ] [ [58]Contents ] [ [59]Next ] [ [60]Previous ]
+
+ Various Unix varieties -- Linux, Solaris, AIX, etc -- now incorporate
+ the idea of "install packages", and many users expect to find all new
+ applications in this format. A selection of install packages might be
+ available for any given release of C-Kermit, but there is a tradeoff
+ between convenience and safety. Unix presents several notable problems
+ to the builder of install packages:
+
+ a. Since C-Kermit is portable to many non-Unix platforms (VMS, VOS,
+ AOS/VS, etc), some of the files in the C-Kermit distribution do not
+ fit into the Unix application model. In particular, C-Kermit
+ includes some plain text files (described in [61]Section 5) and
+ Unix has no standard place to put such files. Typical Unix package
+ managers do not allow for them. Where should they go, and how will
+ the user know where to find them?
+ b. Installation of any program that will be used to make modem calls
+ requires some important decisions from the installer regarding
+ security and privilege.
+
+ Item (b) is discussed at length in [62]Sections 10 and [63]11 of this
+ document, but the package-related aspects are also given here. The
+ basic problem is that Unix dialout devices and the UUCP "lock files"
+ that regulate contention for them (described in [64]Section 10) are
+ usually protected against "world". Therefore, the install procedure
+ must either run as root in order to give the Kermit binary the required
+ permissions, group, and/or owner, or else the dialout devices and
+ associated directories must be open for group or world reading and
+ writing. Otherwise, the Kermit program just installed WILL NOT WORK for
+ dialing out.
+
+ Thus, a well-crafted installation procedure should present the options
+ and allow the installer to choose the method, if any, for regulating
+ access to the dialout devices:
+
+ a. Check the permissions of the lockfile directory and the dialout
+ devices. If they do not allow group or world R/W access, then:
+ b. "Your UUCP lockfile directory and/or dialout devices require
+ privilege to access. You must either change their permissions or
+ install Kermit with privileges."
+ c. "If you wish to install Kermit with privileges, it will be given
+ the same owner, group, and permissions as the cu program so it can
+ use the dialout devices." (This is increasingly problematic as some
+ newer Unix systems like Mac OS X don't have a cu program, or even a
+ serial port!)
+ d. If they choose (c) but the user is not root, give a message that
+ the install procedure can be run only by root and then quit.
+
+ It should go without saying, of course, that any binaries that are to
+ be included in an install package should be built fresh on the exact
+ platform (e.g. Red Hat 8.0 on Intel) for which the package is targeted;
+ prebuilt binaries ([65]next section) from other sites are likely to
+ have library mismatches. [66]CLICK HERE for more about building
+ C-Kermit install packages.
+
+ The Kermit Project does not have the resources or the expertise to make
+ install packages for every platform. Most install packages, therefore,
+ are contributed by others, and they do not necessarily follow the
+ guidelines given above. Pay attention to what they do.
+
+ If you are an end user who has obtained a C-Kermit install package for
+ a particular platform, you should be aware that some additional steps
+ might needed if you want to use Kermit to dial out. Read [67]Section 10
+ for details.
+
+3. INSTALLING PREBUILT BINARIES
+
+ [ [68]Top ] [ [69]Contents ] [ [70]Next ] [ [71]Previous ]
+
+ Hundreds of prebuilt C-Kermit binaries are available on the CDROM in
+ the BINARY tree [NOTE: The C-Kermit CDROM is still for version 7.0],
+ and at our ftp site in the [72]kermit/bin area (with names starting
+ with "ck"), also accessible on the [73]C-Kermit website. To install a
+ prebuilt binary:
+
+ a. Rename the binary to "wermit".
+ b. Make sure it works; some tests are suggested in [74]Section 7.
+ c. Follow steps (b) through (e) in [75]Section 4.
+ d. Install related files as described in [76]Section 5.
+
+ But first... Please heed the following cautions:
+
+ a. If you pick the wrong binary, it won't work (or worse).
+ b. Even when you pick the appropriate binary, it still might not work
+ due to shared-library mismatches, etc. (see [77]Section 4.0).
+ c. Don't expect a binary built on or for version n of your OS to work
+ on version n - x (where x > 0). However, it is supposed to be safe
+ to run a binary built on (or for) an older OS release on a newer
+ one (but is [78]increasingly less so as time-honored principles of
+ stability and backwards compatibility go fading into obscurity).
+
+ Therefore, it is always better to build your own binary from source
+ code ([79]next section) if you can. But since it is increasingly common
+ for Unix systems (not to mention VMS and other OS's) to be delivered
+ without C compilers, it is sometimes not possible. In such cases, try
+ the most appropriate prebuilt binary or binaries, and if none of them
+ work, [80]contact us and we'll see what we can do to help.
+
+4. BUILDING FROM SOURCE CODE
+
+ [ [81]Top ] [ [82]Contents ] [ [83]Next ] [ [84]Previous ]
+
+ Also see: [85]Section 8 and [86]Section 9.
+
+ C-Kermit is designed to be built and used on as many platforms as
+ possible: Unix and non-Unix, old and new (and ancient), ANSI C and K&R.
+ The Unix version does not use or depend on any external tools for
+ building except the "make" utility, the C compiler, the linker, and the
+ shell. It does not use any external automated configuration tools such
+ as configure, autoconf, automake, libtool, etc. Everything in C-Kermit
+ has been built by hand based on direct experience or reports or
+ contributions from users of each platform.
+
+ The [87]C-Kermit makefile contains the rules for building the program
+ for each of the hundreds of different kinds of Unix systems that
+ C-Kermit attempts to support. It covers all Unix variations since about
+ 1980 -- pretty much everything after Unix V6. Separate makefiles are
+ used for [88]Plan 9 and [89]2.x BSD.
+
+ Prerequisites:
+
+ * The C compiler, linker, and make program must be installed.
+ * The C libraries and header files must be installed (*).
+ * The C-Kermit source code and makefile in your current directory.
+ * The C-Kermit text files ([90]Section 5) in your current directory.
+
+ * This is becoming problematic in this new age of "selective
+ installs" e.g. of Linux packages. C-Kermit builds will often fail
+ because replying "no" to some obscure Linux installation option
+ will result in missing libraries or header files. Ditto on
+ platforms like AIX and Solaris that don't come with C compilers,
+ and then later have gcc installed, but are still missing crucial
+ libraries, like libm (math).
+
+ Plus:
+
+ * For TCP/IP networking support, the sockets library and related
+ header files must be installed.
+ * The math library for floating-point arithmetic support (can be
+ deselected by adding -DNOFLOAT to CFLAGS and removing -lm from
+ LIBS).
+ * Many and varied security libraries for building a secure version
+ (Kerberos, SSL/TLS, SRP, Zlib,...) These are required only if you
+ select a secure target.
+ * For the curses-based fullscreen file-transfer display, the curses
+ or ncurses header file(s) and library, and probably also the
+ termcap and/or termlib library. Note that the names and locations
+ of these files and libraries are likely to change capriciously with
+ every new release of your Unix product. If you discover that the
+ C-Kermit build procedure fails because your curses and/or termxxx
+ headers or libraries are not named or located as expected, please
+ [91]let us know. In the meantime, work around by installing
+ symlinks.
+ * IMPORTANT: Modern Linux distributions might give you the choice
+ during installation of whether to install the "ncurses development
+ package" (perhaps called "ncurses-devel"). If you did not install
+ it, you won't be able to build C-Kermit with curses support
+ included. In this case, either go back and install ncurses, or else
+ choose (or create) a non-curses makefile target for your platform.
+ To install the ncurses developers tools in Red Hat Linux, do
+ "apt-get install ncurses-developer" or if you have the CD:
+
+mount redhat cdrom
+goto RedHat/RPMS
+rpm -ivh ncurses-devel*.rpm
+or to have the exact name ls ncurse* and load as
+rpm -ivh filename
+then leave the cdrom and unmount it.
+
+ * In AIX you might have to go back and install any or all of:
+
+bos.adt.base
+bos.adt.include
+bos.adt.lib
+bos.adt.libm
+bos.adt.utils
+
+ from the first installation CD.
+
+ Depending on where you got it, the makefile might need to be renamed
+ from ckuker.mak to makefile. Directions:
+
+ a. Type "make xxx" where xxx is the name of the makefile target most
+ appropriate to your platform, e.g. "make linux", "make aix43", etc.
+ Read the [92]comments at the top of the makefile for a complete
+ list of available targets (it's a long list).
+ b. Test the resulting 'wermit' file (see [93]Section 7 for
+ suggestions). If it's OK, proceed; otherwise [94]notify us.
+
+ NOTE: steps (c) through (e) can be accomplished using the
+ [95]makefile 'install' target as described in [96]Section 5.4.
+ c. Rename the 'wermit' file to 'kermit', copy it to the desired binary
+ directory (such as /usr/local/bin or /opt/something), and if it is
+ to be used for dialing out, give it the same owner, group, and
+ permissions as the 'cu' program (IMPORTANT: read [97]Sections 10
+ and [98]11 for details).
+ d. Install the man page, ckuker.nr, with your other man pages.
+ e. Install the accompanying text files (see [99]Section 5).
+ f. If you want C-Kermit to also offer a Telnet command-line
+ personality, make a symbolic link as follows:
+
+cd directory-where-kermit-binary-is
+ln -s kermit telnet
+
+ If you want C-Kermit to be the default Telnet client, make sure the
+ directory in which you created the symlink is in the PATH ahead of
+ the where the regular Telnet client is.
+ g. If you want C-Kermit to also offer an FTP command-line personality,
+ make a symlink called "ftp" as in (f).
+ h. If you want C-Kermit to also offer an FTTP command-line
+ personality, make a symlink called "http" as in (f).
+ i. If you want to offer an Internet Kermit Service, follow the
+ directions in the [100]IKSD Administrator's Guide.
+
+4.0. Special Considerations for C-Kermit 8.0-9.0
+
+ [ [101]Top ] [ [102]Contents ] [ [103]Next ]
+
+ Also see: [104]C-Kermit Configuration Options
+
+ SECTION CONTENTS
+
+4.1. [105]The Unix Makefile
+4.2. [106]The C-Kermit Initialization File
+4.3. [107]The 2.x BSD Makefile
+4.4. [108]The Plan 9 Makefile
+4.5. [109]Makefile Failures
+
+ (Also see the [110]Configurations Options document, [111]Section 8).
+
+ Lots of new features have been added in versions 7.0 and 8.0 that
+ require access to new symbols, APIs, libraries, etc, and this will no
+ doubt cause problems in compiling, linking, or execution on platforms
+ where 6.0 and earlier built without incident. This section contains
+ what we know as of the date of this file.
+
+ The first category concerns the new Kermit Service Daemon (IKSD; see
+ the [112]IKSD Administrator's Guide for details):
+
+ The wtmp File
+ When C-Kermit is started as an IKSD (under inetd), it makes
+ syslog and wtmp entries, and also keeps its own ftpd-like log.
+ The code assumes the wtmp log is /var/log/wtmp on Linux and
+ /usr/adm/wtmp elsewhere. No doubt this assumption will need
+ adjustment. Use -DWTMPFILE=path to override at compile time
+ (there is also a runtime override). See [113]iksd.html for
+ details.
+
+ UTMP, utsname(), etc
+ C-Kermit 7.0 gets as much info as it can about its job -- mainly
+ for IKSD logging -- from utmp. But of course utmp formats and
+ fields differ, and for that matter, there can be two different
+ header files, <utmp.h> and <utmpx.h>. Look for HAVEUTMPX and
+ HAVEUTHOST in [114]ckufio.c and let me know of any needed
+ adjustments.
+
+ Password lookup
+ IKSD needs to authenticate incoming users against the password
+ list. In some cases, this requires the addition of -lcrypt (e.g.
+ in Unixware 2.x). In most others, the crypt functions are in the
+ regular C library. If you get "crypt" as an unresolved symbol at
+ link time, add -lcrypt to LIBS. If your site has local
+ replacement libraries for authentication, you might need a
+ special LIBS clause such as "LIBS=-L/usr/local/lib -lpwent".
+
+ These days most Unix systems take advantage of shadow password
+ files or Pluggable Authentication Modules (PAM). If your system
+ uses shadow passwords you must add -DCK_SHADOW to the CFLAGS
+ list. If your system requires PAM you must add -DCK_PAM to the
+ CFLAGS and -lpam -ldl to LIBS.
+
+ getusershell()
+ This is called by the IKSD at login time to see if a user has
+ been "turned off". But many Unix platforms lack this function.
+ In that case, you will get unresolved symbol reports at link
+ time for _getusershell, _endusershell; to work around, add
+ -DNOGETUSERSHELL.
+
+ initgroups()
+ This is called by IKSD after successful authentication. But some
+ platforms do not have this function, so obviously it can't be
+ called there, in which case add -DNOINITGROUPS.
+
+ setreuid(), setreuid(), setregid() not found or "deprecated"
+ Find out what your Unix variety wants you to use instead, and
+ make appropriate substitutions in routine zvpass(), module
+ [115]ckufio.c, and [116]let us know.
+
+ printf()
+ IKSD installs a printf() substitute to allow redirection of
+ printf-like output to the connection. However, this can conflict
+ with some curses libraries. In this case, separate binaries must
+ be built for IKSD and non-IKSD use.
+
+ If you encounter difficulties with any of the above, and you are not
+ interested in running C-Kermit as an IKSD, then simply add NOIKSD to
+ CFLAGS and rebuild. Example:
+
+make sco286
+(get lots of errors)
+make clean
+make sco286 "KFLAGS=-DNOIKSD"
+
+ Some non-IKSD things to watch out for:
+
+ Return type of main()
+ The main() routine is in [117]ckcmai.c. If you get complaints
+ about "main: return type is not blah", define MAINTYPE on the CC
+ command line, e.g.:
+
+make xxx "KFLAGS=-DMAINTYPE=blah
+
+ (where blah is int, long, or whatever). If the complaint is
+ "Attempt to return a value from a function of type void" then
+ add -DMAINISVOID:
+
+make xxx "KFLAGS=-DMAINISVOID=blah
+
+ DNS Service Records
+ This feature allows a remote host to redirect C-Kermit to the
+ appropriate socket for the requested service; e.g. if C-Kermit
+ requests service "telnet" and the host offers Telnet service on
+ port 999 rather than the customary port 23. If you get
+ compile-time complaints about not being able to find <resolv.h>,
+ <netdb.h>, or <arpa/nameser.h>, add -DNO_DNS_SRV to CFLAGS. If
+ you get link-time complaints about unresolved symbols res_search
+ or dn_expand, try adding -lresolve to LIBS.
+
+ \v(ipaddress)
+ If "echo \v(ipaddress)" shows an empty string rather than your
+ local IP address, add -DCKGHNLHOST to CFLAGS and rebuild.
+
+ <sys/wait.h>
+ If this file can't be found at compile time, add -DNOREDIRECT to
+ CFLAGS. This disables the REDIRECT and PIPE commands and
+ anything else that needs the wait() system service.
+
+ syslog()
+ C-Kermit can now write syslog records. Some older platforms
+ might not have the syslog facility. In that case, add
+ -DNOSYSLOG. Others might have it, but require addition of
+ -lsocket to LIBS (SCO OSR5 is an example). See [118]Section 15.
+
+ putenv()
+ If "_putenv" comes up as an undefined symbol, add -DNOPUTENV to
+ CFLAGS and rebuild.
+
+ "Passing arg1 of 'time' from incompatible pointer"
+ This is a mess. See the mass of #ifdefs in the appropriate
+ module, [119]ckutio.c or [120]ckufio.c.
+
+ gettimeofday()
+ Wrong number of arguments. On most platforms, gettimeofday()
+ takes two arguments, but on a handful of others (e.g. Motorola
+ System V/88 V4, SNI Reliant UNIX 5.43, etc) it takes one. If
+ your version of gettimeofday() is being called with two args but
+ wants one, add -DGTODONEARG.
+
+ "Assignment makes pointer from integer without a cast"
+ This warning might appear in [121]ckutio.c or [122]ckufio.c. (or
+ elsewhere), and usually can be traced to the use of a system or
+ library function that returns a pointer but that is not declared
+ in the system header files even though it should be. Several
+ functions are commonly associated with this error:
+
+ + getcwd(): Add -DDCLGETCWD to CFLAGS and rebuild.
+ + popen() : Add -DDCLPOPEN to CFLAGS and rebuild.
+ + fdopen(): Add -DDCLFDOPEN to CFLAGS and rebuild.
+
+ "Operands of = have incompatible types"
+ "Incompatible types in assignment"
+ If this comes from [123]ckcnet.c and comes from a statement
+ involving inet_addr(), try adding -DINADDRX to CFLAGS. If that
+ doesn't help, then try adding -DNOMHHOST.
+
+ Complaints about args to get/setsockopt(), getpeername(), getsockname()
+ These are all in [124]ckcnet.c. Different platforms and OS's and
+ versions of the same OS change this all the time: int, size_t,
+ unsigned long, etc. All the affected variables are declared
+ according to #ifdefs within ckcnet.c, so find the declarations
+ and adjust the #ifdefs accordingly.
+
+ size_t
+ In case of complaints about "unknown type size_t", add
+ -DSIZE_T=int (or other appropriate type) to CFLAGS.
+
+ 'tz' undefined
+ Use of undefined enum/struct/union 'timezone'
+ Left of 'tv_sec' specifies undefined struct/union 'timeval' And
+ similar complaints in [125]ckutio.c: Add -DNOGFTIMER and/or
+ -DNOTIMEVAL.
+
+ Symlinks
+ The new built-in DIRECTORY command should show symlinks like "ls
+ -l" does. If it does not, check to see if your platform has the
+ lstat() and readlink() functions. If so, add -DUSE_LSTAT and
+ -DCKSYMLINK to CFLAGS and rebuild. On the other hand, if lstat()
+ is unresolved at link time, add -DNOLSTAT to CFLAGS. If
+ readlink() is also unresolved, add -DNOSYMLINK.
+
+ realpath()
+ Link-time complains about realpath() -- find the library in
+ which it resides and add it to LIBS (example for Unixware 7.1:
+ "-lcudk70") or add -DNOREALPATH to CFLAGS and rebuild. If built
+ with realpath() but debug log file is truncated or mangled,
+ ditto (some realpath() implementations behave differently from
+ others). If built with realpath() and seemingly random core
+ dumps occur during file path resolution, ditto.
+
+ Failure to locate header file <term.h>
+ Usually happens on Linux systems that have the C compiler
+ installed, but not the ncurses package (see comments about
+ selective installs above). Go back and install ncurses, or use
+ "make linuxnc" (Linux No Curses).
+
+ "Can't find shared library libc.so.2.1"
+ "Can't find shared library libncurses.so.3.0", etc...
+ You are trying to run a binary that was built on a computer that
+ has different library versions than your computer, and your
+ computer's loader is picky about library version numbers.
+ Rebuild from source on your computer.
+
+ Time (struct tm) related difficulties:
+ Errors like the following:
+
+"ckutio.c", line 11994: incomplete struct/union/enum tm: _tm
+"ckutio.c", line 11995: error: cannot dereference non-pointer type
+"ckutio.c", line 11995: error: assignment type mismatch
+"ckutio.c", line 11997: warning: using out of scope declaration: localtime
+"ckutio.c", line 11997: error: unknown operand size: op "="
+"ckutio.c", line 11997: error: assignment type mismatch
+"ckutio.c", line 11998: error: undefined struct/union member: tm_year
+"ckutio.c", line 12000: error: undefined struct/union member: tm_mon
+"ckutio.c", line 12001: error: undefined struct/union member: tm_mday
+"ckutio.c", line 12002: error: undefined struct/union member: tm_hour
+"ckutio.c", line 12003: error: undefined struct/union member: tm_min
+"ckutio.c", line 12004: error: undefined struct/union member: tm_sec
+
+ are due to failure to include the appropriate time.h header
+ files. Unix platforms generally have one or more of the
+ following: <time.h>, <sys/time.h>, and <sys/timeb.h>. Any
+ combination of these might be required. Defaults are set up for
+ each makefile target. The defaults can be corrected on the CC
+ command line by adding the appropriate definition from the
+ following list to CFLAGS:
+
+-DTIMEH Include <time.h>
+-DNOTIMEH Don't include <time.h>
+-DSYSTIMEH Include <sys/time.h>
+-DNOSYSTIMEH Don't include <sys/time.h>
+-DSYSTIMEBH Include <sys/timeb.h>
+-DNOSYSTIMEBH Don't include <sys/timeb.h>
+
+ Note that <sys/timeb.h> is relatively scarce in the System V and
+ POSIX environments; the only platform of recent vintage where it
+ was/is used is OSF/1 and its derivatives (Digital Unix and Tru64
+ Unix).
+
+ Struct timeval and/or timezone not declared:
+ In some cases, merely including the appropriate time.h header
+ files is still not enough. POSIX.1 does not define the timeval
+ struct, and so the items we need from the header are protected
+ against us by #ifndef _POSIX_SOURCE or somesuch. In this case,
+ we have to declare the timeval (and timezone) structs ourselves.
+ To force this, include -DDCLTIMEVAL in CFLAGS.
+
+ Warnings about dn_expand() Argument #4
+ WARNING: argument is incompatible with prototyp. It's the old
+ char versus unsigned char stupidity again. Try to find a
+ compiler switch like GCC's "-funsigned-char". Failing that, add
+ -DCKQUERYTYPE=xxx to CFLAGS, where xxx is whatever 'man
+ dn_expand' tells you the type of the 4th argument should be
+ (presumably either char or unsigned char; in the latter case use
+ CHAR to avoid confusion caused by multiple words.
+
+ Switch Table Overflow (in [126]ckcuni.c)
+ Add -DNOUNICODE to CFLAGS.
+
+ Compile-time warnings about ck_out() or tgetstr() or tputs():
+ Easy solution: Add -DNOTERMCAP to CFLAGS. But then you lose the
+ SCREEN function. Real solution: Try all different combinations
+ of the following CFLAGS:
+
+-DTPUTSARGTYPE=char -DTPUTSFNTYPE=int
+-DTPUTSARGTYPE=int -DTPUTSFNTYPE=void
+
+ Until the warnings go away, except maybe "ck_outc: return with a
+ value in a function returning void", and in that case also add
+ -DTPUTSISVOID.
+
+ "Passing arg 1 of to tputs() makes pointer from integer without a
+ cast":
+ Add -DTPUTSARG1CONST to CFLAGS.
+
+ "Undefined symbol: dup2"
+ Add -DNOZEXEC to CFLAGS.
+
+ "header file 'termcap.h' not found"
+ Add -DNOHTERMCAP to CFLAGS.
+
+ Other difficulties are generally of the "where is curses.h and what is
+ it called this week?" variety (most easily solved by making symlinks in
+ the include and lib directories), or overzealous complaints regarding
+ type mismatches in function calls because of the totally needless and
+ silly signed versus unsigned char conflict (*), etc. In any case,
+ please send any compilation or linking warnings or errors to the
+ author, preferably along with fixes.
+
+ * C-Kermit does not use the signed property of chars at all anywhere,
+ ever. So if all chars and char *'s can be made unsigned at compile
+ time, as they can in gcc with "-funsigned-char", they should be.
+
+ IMPORTANT: If you find any of these hints necessary for a particular
+ make target (or you hit upon others not listed here), PLEASE SEND A
+ REPORT TO:
+
+[127]kermit-support@columbia.edu
+
+4.1. The Unix Makefile
+
+ [ [128]Top ] [ [129]Contents ] [ [130]Section Contents ] [ [131]Next ]
+ [ [132]Previous ]
+
+ If your distribution does not contain a file with the name "makefile"
+ or "Makefile", then rename the file called ckuker.mak to makefile:
+
+mv ckuker.mak makefile
+
+ Then type "make xxx", where xxx is the platform you want to build
+ C-Kermit for. These are listed in the [133]comments at the top of the
+ makefile. For example, to build C-Kermit for Linux, type:
+
+make linux
+
+ Here are some typical examples:
+
+ Target Description
+ linux Linux, any version on any hardware platform
+ openbsd OpenBSD, any version on any hardware platform
+ aix43 AIX 4.3
+ aix43g AIX 4.3, built with gcc
+ solaris9 Solaris 9
+ solaris9g Solaris 9 built with gcc
+ hpux1100 HP-UX 11-point-anything
+
+ The makefile is quite long, and at least two versions of Unix, SCO
+ Xenix/286 and 2.x BSD, cannot cope with its length. An attempt to "make
+ sco286" gives the message "Make: Cannot alloc mem for env.. Stop".
+ Solution: edit away some or all of the nonrelevant material from the
+ makefile. (A separate version of the makefile is provided for BSD 2.x:
+ ckubs2.mak but C-Kermit 8.0 can't be built for BSD 2.x -- it has simply
+ grown too large.)
+
+ Some make programs reportedly cannot handle continued lines (lines
+ ending in backslash (\)). If you have a problem with the makefile, try
+ editing the makefile to join the continued lines (remove the
+ backslashes and the following linefeed).
+
+ Other makefile troubles may occur because tabs in the makefile have
+ somehow been converted to spaces. Spaces and tabs are distinct in Unix
+ makefiles.
+
+ Similarly, carriage returns might have been added to the end of each
+ line, which also proves confusing to most Unix versions of make.
+
+ Check to see if there are comments about your particular version in its
+ makefile target itself. In a text editor such as EMACS or VI, search
+ for the make entry name followed by a colon, e.g. "linux:" (if you
+ really are building C-Kermit for Linux, do this now).
+
+ Check to see if there are comments about your particular version in the
+ [134]ckubwr.txt file ([135]CLICK HERE for the Web version).
+
+ If you have trouble with building [136]ckwart.c, or running the
+ resulting wart preprocessor program on [137]ckcpro.w:
+
+ 1. Just "touch" the [138]ckcpro.c file that comes in the distribution
+ and then give the "make" command again, or:
+ 2. Compile ckwart.c "by hand": cc -o wart ckwart.c, or:
+ 3. Try various other tricks. E.g. one Linux user reported that that
+ adding the "static" switch to the rule for building wart fixed
+ everything:
+
+wart: ckwart.$(EXT)
+ $(CC) -static -o wart ckwart.$(EXT) $(LIBS)
+
+ If your compiler supports a compile-time option to treat ALL chars (and
+ char *'s, etc) as unsigned, by all means use it -- and send me email to
+ let me know what it is (I already know about gcc -funsigned-char).
+
+ To add compilation options (which are explained later in this document)
+ to your makefile target without editing the makefile, include
+ "KFLAGS=..." on the make command line, for example:
+
+make linux KFLAGS=-DNODEBUG
+make bsd "KFLAGS=-DKANJI -DNODEBUG -DNOTLOG -DDYNAMIC -UTCPSOCKET"
+
+ Multiple options must be separated by spaces. Quotes are necessary if
+ the KFLAGS= clause includes spaces. The KFLAGS are added to the end of
+ the CFLAGS that are defined in the selected makefile target. For
+ example, the "bsd" entry includes -DBSD4 -DTCPSOCKET, so the second
+ example above compiles Kermit with the following options:
+
+-DBSD4 -DTCPSOCKET -DKANJI -DNODEBUG -DNOTLOG -DDYNAMIC -UTCPSOCKET
+
+ (Notice how "-UTCPSOCKET" is used to negate the effect of the
+ "-DTCPSOCKET" option that is included in the makefile target.)
+
+ WARNING: Be careful with KFLAGS. If you build C-Kermit, change some
+ files, and then run make again using the same make entry but specifying
+ different KFLAGS than last time, make won't detect it and you could
+ easily wind up with inconsistent object modules, e.g. some of them
+ built with a certain option, others not. When in doubt, "make clean"
+ first to make sure all your object files are consistent. Similarly, if
+ you change CFLAGS, LIBS, or any other items in the makefile, or you
+ rebuild using a different makefile target, "make clean" first.
+
+ If you create a new makefile target, use static linking if possible.
+ Even though this makes your C-Kermit binary bigger, the resulting
+ binary will be more portable. Dynamically linked binaries tend to run
+ only on the exact configuration and version where they were built; on
+ others, invocation tends to fail with a message like:
+
+Can't find shared library "libc.so.2.1"
+
+4.2. The C-Kermit Initialization File
+
+ [ [139]Top ] [ [140]Contents ] [ [141]Section Contents ] [ [142]Next ]
+ [ [143]Previous ]
+
+ (This section is obsolete.) Read [144]Section 5 about the
+ initialization file.
+
+4.3. The 2.x BSD Makefile
+
+ [ [145]Top ] [ [146]Contents ] [ [147]Section Contents ] [ [148]Next ]
+ [ [149]Previous ]
+
+ This section is obsolete. C-Kermit 6.0 was the last release that
+ could be built on PDP-11 based BSD versions.
+
+4.4. The Plan 9 Makefile
+
+ [ [150]Top ] [ [151]Contents ] [ [152]Section Contents ] [ [153]Next ]
+ [ [154]Previous ]
+
+ Use the separate makefile [155]ckpker.mk. NOTE: The Plan 9 version of
+ C-Kermit 8.0 has not yet been built. There should be no impediment to
+ building it. However, even when built successfully, certain key
+ features are missing, notably TCP/IP networking.
+
+4.5. Makefile Failures
+
+ [ [156]Top ] [ [157]Contents ] [ [158]Section Contents ] [
+ [159]Previous ]
+
+ First, be sure the source files are stored on your current disk and
+ directory with the right names (in lowercase). Second, make sure that
+ the makefile itself does not contain any lines with leading spaces:
+ indented lines must all start with horizontal TAB, and no spaces.
+
+ Then make sure that your Unix PATH is defined to find the appropriate
+ compiler for your makefile target. For example, on SunOS systems, "make
+ sunos41" builds C-Kermit for the BSD environment, and assumes that
+ /usr/ucb/cc will be used for compilation and linking. If your PATH has
+ /usr/5bin ahead of /usr/ucb, you can have problems at compile or link
+ time (a commonly reported symptom is the inability to find "ftime"
+ during linking). Fix such problems by redefining your Unix PATH, or by
+ specifying the appropriate "cc" in CC= and CC2= statements in your
+ makefile target.
+
+ During edits 166-167, considerable effort went into making C-Kermit
+ compilable by ANSI C compilers. This includes prototyping all of
+ C-Kermit's functions, and including the ANSI-defined system header
+ files for system and library functions, as defined in K&R, second
+ edition: <string.h>, <stdlib.h>, <unistd.h> (except in NeXTSTEP this is
+ <libc.h>), and <sys/stdtypes.h>. If you get warnings about any of these
+ header files not being found, or about argument mismatches involving
+ pid_t, uid_t, or gid_t, look in ckcdeb.h and make amendments. C-Kermit
+ assumes it is being compiled by an ANSI-compliant C compiler if
+ __STDC__ is defined, normally defined by the compiler itself. You can
+ force ANSI compilation without defining __STDC__ (which some compilers
+ won't let you define) by including -DCK_ANSIC on the cc command line.
+
+ On the other hand, if your compiler defines __STDC__ but still
+ complains about the syntax of Kermit's function prototypes, you can
+ disable the ANSI-style function prototyping by including -DNOANSI on
+ the command line.
+
+ For SCO OpenServer, UNIX, ODT, and XENIX compilations, be sure to pick
+ the most appropriate [160]makefile target, and be sure you have
+ installed an SCO development system that is keyed to your exact SCO
+ operating system release, down to the minor version (like 2.3.1).
+
+ Also note that SCO distributes some of its libraries in encrypted form,
+ and they must be decrypted before C-Kermit can be linked with them. If
+ not, you might see a message like:
+
+ld: file /usr/lib/libsocket.a is of unknown type: magic number = 6365
+
+ To decrypt, you must supply a key (password) that came with your
+ license. Call SCO for further info.
+
+ If your compiler uses something other than int for the pid (process id)
+ data type, put -DPID_T=pid_t or whatever in your CFLAGS.
+
+ If you get complaints about unknown data types uid_t and gid_t, put
+ -DUID_T=xxx -DGID_T=yyy in your CFLAGS, where xxx and yyy are the
+ appropriate types.
+
+ If your compilation fails because of conflicting or duplicate
+ declarations for sys_errlist, add -DUSE_STRERROR or -DNDSYSERRLIST to
+ CFLAGS.
+
+ If your compilation dies because getpwnam() is being redeclared (or
+ because of "conflicting types for getwpnam"), add -DNDGPWNAM to your
+ CFLAGS. If that doesn't work, then add -DDCGPWNAM to your CFLAGS (see
+ ckufio.c around line 440).
+
+ If the compiler complains about the declaration of getpwnam() during an
+ ANSI C compilation, remove the declaration from ckufio.c or change the
+ argument in the prototype from (char *) to (const char *).
+
+ If you get complaints that getpwuid() is being called with an improper
+ type, put -DPWID_T=xx in your CFLAGS.
+
+ If you get compile-time warnings that t_brkc or t_eofc (tchars
+ structure members, used in BSD-based versions) are undefined, or
+ structure-member- related warnings that might be traced to this fact,
+ add -DNOBRKC to CFLAGS.
+
+ If you get a linker message to the effect that _setreuid or _setregid
+ is not defined, add -DNOSETREU to CFLAGS, or add -DCKTYP_H=blah to
+ CFLAGS to make C-Kermit read the right <types.h>-kind-of-file to pick
+ up these definitions.
+
+ If you get a message that _popen is undefined, add -DNOPOPEN to CFLAGS.
+
+ If you get a complaint at compile time about an illegal pointer-integer
+ combination in ckufio.c involving popen(), or at link time that _popen
+ is an undefined symbol, add the declaration "FILE *popen();" to the
+ function zxcmd() in ckufio.c (this declaration is supposed to be in
+ <stdio.h>). If making this change does not help, then apparently your
+ Unix does not have the popen() function, so you should add -DNOPOPEN to
+ your make entry, in which case certain functions involving "file" i/o
+ to the standard input and output of subprocesses will not be available.
+
+ If your linker complains that _getcwd is undefined, you can add a
+ getcwd() function to ckufio.c, or add it to your libc.a library using
+ ar:
+
+#include <stdio.h>
+
+char *
+getcwd(buf,size) char *buf; int size; {
+#ifndef NOPOPEN
+#ifdef DCLPOPEN
+ FILE *popen();
+#endif
+ FILE *pfp;
+
+ if (!buf) return(NULL);
+ if (!(pfp = popen("pwd","r"))) return(NULL);
+ fgets(buf,size-2,pfp);
+ pclose(pfp);
+ buf[strlen(buf)-1] = '\0';
+ return((char *)buf);
+#else
+ buf[0] = '\0';
+ return(NULL);
+#endif /* NOPOPEN */
+}
+
+#ifdef NOPOPEN
+FILE *popen(s,t) char *s,*t; {
+ return(NULL);
+}
+#endif /* NOPOPEN */
+
+ If you get complaints about NPROC having an invalid value, add a valid
+ definition for it (depends on your system), as in the cray entry.
+
+ If you get some symbol that's multiply defined, it probably means that
+ a variable name used by Kermit is also used in one of your system
+ libraries that Kermit is linked with. For example, under PC/IX some
+ library has a variable or function called "data", and the variable
+ "data" is also used extensively by Kermit. Rather than edit the Kermit
+ source files, just put a -D in the make entry CFLAGS to change the
+ Kermit symbol at compile time. In this example, it might be
+ -Ddata=xdata.
+
+ Some symbol is defined in your system's header files, but it produces
+ conflicts with, or undesired results from, Kermit. Try undefining the
+ symbol in the makefile target's CFLAGS, for example -UFIONREAD.
+
+ Some well-known symbol is missing from your system header files. Try
+ defining in the makefile target's CFLAGS, for example -DFREAD=1.
+
+ You get many warnings about pointer mismatches. This probably means
+ that Kermit is assuming an int type for signal() when it should be
+ void, or vice-versa. Try adding -DSIG_I (for integer signal()) or
+ -DSIG_V (for void) to CFLAGS. Or just include KFLAGS=-DSIG_V (or
+ whatever) in your "make" command, for example:
+
+make bsd KFLAGS=-DSIG_V
+
+ You get many messages about variables that are declared and/or set but
+ never used. It is difficult to avoid these because of all the
+ conditional compilation in the program. Ignore these messages.
+
+ Some of C-Kermit's modules are so large, or contain so many character
+ string constants, or are so offensive in some other way, that some C
+ compilers give up and refuse to compile them. This is usually because
+ the -O (optimize) option is included in the make entry. If this happens
+ to you, you can (a) remove the -O option from the make entry, which
+ will turn off the optimizer for ALL modules; or (b) compile the
+ offending module(s) by hand, including all the switches from make entry
+ except for -O, and then give the appropriate "make" command again; or
+ (c) increase the value of the -Olimit option, if your compiler supports
+ this option; or (d) change the [161]makefile target to first compile
+ each offending module explicitly without optimization, then compile the
+ others normally (with optimization), for example:
+
+#Fortune 32:16, For:Pro 2.1 (mostly like 4.1bsd)
+ft21:
+ @echo 'Making C-Kermit $(CKVER) for Fortune 32:16 For:Pro 2.1...'
+ $(MAKE) ckuusx.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+ -SYM 800 \ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short"
+ $(MAKE) ckuxla.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+ -SYM 800 \ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short"
+ $(MAKE) ckudia.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+ -SYM 800 \ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short"
+ $(MAKE) wermit "CFLAGS= -O -DNODEBUG -DBSD4 -DFT21 -DNOFILEH -SYM 800 \
+ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short" \
+ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet"
+
+ As an extreme example, some compilers (e.g. gcc on the DG AViiON) have
+ been known to dump core when trying to compile ckwart.c with
+ optimization. So just do this one "by hand":
+
+cc -o wart ckwart.c
+
+ or:
+
+touch ckcpro.c
+
+ and then give the "make" command again.
+
+ Speaking of wart, it is unavoidable that some picky compilers might
+ generate "statement unreachable" messages when compiling ckcpro.c.
+ Unreachable statements can be generated by the wart program, which
+ generates ckcpro.c automatically from [162]ckcpro.w, which translates
+ lex-like state/input constructions into a big switch/case construction.
+
+ Some function in Kermit wreaks havoc when it is called. Change all
+ invocations of the function into a macro that evaluates to the
+ appropriate return code that would have been returned by the function
+ had it been called and failed, for example: -Dzkself()=0. Obviously not
+ a good idea if the function is really needed.
+
+ If you have just installed SunOS 4.1.2 or 4.1.3, you might find that
+ C-Kermit (and any other C program) fails to link because of unresolved
+ references from within libc. This is because of a mistake in Sun's
+ /usr/lib/shlib.etc files for building the new libc. Change the libc
+ Makefile so that the "ld" lines have "-ldl" at the end. Change the
+ README file to say "mv xccs.multibyte. xccs.multibyte.o" and follow
+ that instruction.
+
+5. INSTALLING THE KERMIT FILES
+
+ [ [163]Top ] [ [164]Contents ] [ [165]Next ] [ [166]Previous ]
+
+ SECTION CONTENTS
+
+5.1. [167]The C-Kermit Initialization File
+5.2. [168]Text Files
+5.3. [169]Installing the Kermit Files
+5.4. [170]The Makefile Install Target
+
+ The C-Kermit executable does not need any external files to run.
+ Unlike, say, the cu program, which on most platforms is useless unless
+ you (as root) edit the /usr/spool/uucp/Systems and
+ /usr/spool/uucp/Devices files to supply whatever obscure and
+ undocumented syntax is required to match some supposedly user-friendly
+ mnemonic to the real pathname of whatever device you want to use,
+ Kermit runs on its own without needing any external configuration
+ files, and lets you refer to device (and network hosts and services) by
+ their own natural undisguised names.
+
+ Nevertheless, a number of external files can be installed along with
+ the C-Kermit executable if you wish. These include configuration and
+ customization files that are read by Kermit as well as documentation
+ files to be read by people. All of this material is (a) optional, and
+ (b) available on the Kermit website:
+
+[171]http://www.columbia.edu/kermit/
+
+ and usually in a more pleasant form, perhaps also with updated content.
+ So if your computer is on the Internet, there is no need to install
+ anything but the Kermit executable if users know how to find the Kermit
+ website (and if they don't, Kermit's "help" command tells them).
+
+5.1. The C-Kermit Initialization File
+
+ In C-Kermit 7.0 and earlier, the standard initialization file was a key
+ C-Kermit component because:
+
+ a. It "loaded" the dialing and network directories.
+ b. It defined all the macros and variables for the services directory.
+ c. It defined macros for quickly changing Kermit's file-transfer
+ performance tuning.
+
+ The standard initialization file is quite long (more than 600 lines)
+ and requires noticeable processing time (the slower the computer, the
+ more noticeable), yet few people actually use the services directory,
+ whose definition takes up most of its bulk. Meanwhile, in C-Kermit 8.0,
+ many of the remaining functions of the standard initialization file are
+ now built in; for example, the FAST, CAUTIOUS, and ROBUST commands.
+
+ More to the point, many of the settings that could be made only in the
+ initialization and customization files can now be picked up from
+ environment variables. The first group identifies initialization and
+ directory files:
+
+ CKERMIT_INI
+ The path of your Kermit initialization file, if any. This
+ overrides the built-in search for $HOME/.kermrc.
+
+ K_CHARSET
+ The character set used for encoding local text files. Equivalent
+ to SET FILE CHARACTER-SET.
+
+ K_DIAL_DIRECTORY
+ The full pathname of one or more Kermit dialing directory files.
+ Equivalent to SET DIAL DIRECTORY.
+
+ K_NET_DIRECTORY
+ The full pathname of one or more Kermit network directory files.
+ Equivalent to SET NETWORK DIRECTORY.
+
+ K_INFO_DIRECTORY
+ K_INFO_DIR
+ The full pathname of a directory containing Kermit (if any)
+ containing ckubwr.txt and other Kermit text files. Overrides
+ Kermit's built-in search for this directory.
+
+ The next group is related to dialing modems:
+
+ K_COUNTRYCODE
+ The telephonic numeric country code for this location, e.g. 1
+ for North America or 39 for Italy. It is recommended that this
+ one be set for all users, system-wide. Not only is it used to
+ process portable-format dialing directory entries, but it is
+ also compared against Kermit's built-in list of "tone countries"
+ to see if tone dialing can be used. Equivalent to Kermit's SET
+ DIAL COUNTRY-CODE command.
+
+ K_AREACODE
+ The telephonic numeric area code for this location, e.g. 212 for
+ Manhattan, New York, USA. Recommend this one also be set
+ system-wide, so shared portable-format dialing directories will
+ work automatically for everybody. Equivalent to Kermit's SET
+ DIAL AREA-CODE command.
+
+ K_DIAL_METHOD
+ TONE or PULSE. Equivalent to Kermit's SET DIAL METHOD command.
+ If a dial method is not set explicitly (or implicitly from the
+ country code), Kermit does not specify a dialing method, and
+ uses the modem's default method, which tends to be pulse.
+
+ K_INTL_PREFIX
+ The telephonic numeric international dialing prefix for this
+ location. Equivalent to Kermit's SET DIAL INTL-PREFIX command.
+
+ K_LD_PREFIX
+ The telephonic numeric long-distance dialing prefix for this
+ location. Equivalent to Kermit's SET DIAL LD-PREFIX command.
+
+ K_PBX_ICP
+ The telephonic numeric PBX internal call prefix for this
+ location. Equivalent to Kermit's SET DIAL PBX-INSIDE-PREFIX
+ command.
+
+ K_PBX_OCP
+ The telephonic numeric PBX external call prefix for this
+ location. Equivalent to Kermit's SET DIAL PBX-OUTSIDE-PREFIX
+ command.
+
+ K_PBX_XCH
+ The telephonic numeric PBX exchange (first part of the
+ subscriber number). Equivalent to Kermit's SET DIAL PBX-EXCHANGE
+ command.
+
+ K_TF_AREACODE
+ A list of one or more telephonic numeric toll-free area codes.
+
+ K_TF_PREFIX
+ The telephonic numeric toll-free dialing prefix, in case it is
+ different from the long-distance prefix. Equivalent to Kermit's
+ SET DIAL TF-PREFIX command.
+
+ The final group includes well-known environment variables that are also
+ used by Kermit:
+
+ CDPATH
+ Where the CD command should look for relative directory names.
+
+ SHELL
+ The path of your Unix shell. Used by the RUN (!) command to
+ choose the shell to execute its arguments.
+
+ USER
+ Your Unix username.
+
+ EDITOR
+ The name or path of your preferred editor (used by the EDIT
+ command). Equivalent to SET EDITOR.
+
+ BROWSER
+ The name or path of your preferred web browser (used by the
+ BROWSE command). Equivalent to Kermit's SET BROWSER command.
+
+ Does this mean the initialization file can be abolished? I think so.
+ Here's why:
+
+ * Kermit already does everything most people want it to do without
+ one.
+ * Important site-specific customizations can be done with global
+ environment variables.
+ * There is no longer any need for everybody to have to use the
+ standard initialization file.
+ * This means that your initialization file, if you want one, can
+ contain your own personal settings, definitions, and preferences,
+ rather than 600 lines of "standard" setups.
+ * If you still want the services directory, you can either TAKE the
+ standard initialization file (which must be named anything other
+ than $HOME/.kermrc to avoid being executed automatically every time
+ you start Kermit), or you can make it a kerbang script and execute
+ it "directly" (the [172]makefile install target does this for you
+ by putting ckermit.ini in the same directory as the Kermit binary,
+ adding the appropriate Kerbang line to the top, and giving it
+ execute permission).
+
+ In fact, you can put any number of kerbang scripts in your PATH to
+ start up C-Kermit in different ways, to have it adopt certain settings,
+ make particular connections, execute complicated scripts, whatever you
+ want.
+
+ And in C-Kermit 9.0 the initialization has indeed been "retired" by
+ renaming it to okermit.ini, and replaced by a stub ckermit.ini that
+ doesn't do anything but print a message. Ditto for ckermod.ini.
+
+5.2. Text Files
+
+ These are entirely optional. Many of them are to be found at the Kermit
+ website in HTML form (i.e. as Web pages with clickable links, etc), and
+ very likely also more up to date. Plain-text files that correspond to
+ Web pages were simply "dumped" by Lynx from the website to plain ASCII
+ text. The format is whatever Lynx uses for this purpose. If you wish,
+ you can install them on your computer as described in the [173]next
+ section.
+
+ [174]COPYING.TXT
+ Copyright notice, permissions, and disclaimer.
+
+ [175]ckermit.ini
+ The standard initialization file, intended more for reference
+ (in most cases) than actual use; see [176]Section 5.1.
+
+ [177]ckermod.ini
+ A sample customization file.
+
+ [178]ckermit70.txt
+ Supplement to [179]Using C-Kermit for version 7.0. Available on
+ the Kermit website as:
+ [180]http://www.columbia.edu/kermit/ckermit70.html
+
+ [181]ckermit80.txt
+ Supplement to [182]Using C-Kermit for version 8.0. Available on
+ the Kermit website as:
+ [183]http://www.columbia.edu/kermit/ckermit80.html
+
+ [184]ckermit90.txt
+ Supplement to [185]Using C-Kermit for version 9.0. Available on
+ the Kermit website as:
+ [186]http://www.columbia.edu/kermit/ckermit90.html
+
+ [187]ckcbwr.txt
+ The general C-Kermit hints and tips ("beware") file. Available
+ on the Kermit website as:
+ [188]http://www.columbia.edu/kermit/ckcbwr.html
+
+ [189]ckubwr.txt
+ The Unix-specific C-Kermit hints and tips file. Available on the
+ Kermit website as:
+ [190]http://www.columbia.edu/kermit/ckubwr.html
+
+ [191]ckuins.txt
+ Unix C-Kermit Installation Instructions (this file). Available
+ on the Kermit website as:
+ [192]http://www.columbia.edu/kermit/ckuins.html
+
+ [193]ckccfg.txt
+ C-Kermit compile-time configuration options. Available on the
+ Kermit website as:
+ [194]http://www.columbia.edu/kermit/ckccfg.html
+
+ [195]ckcplm.txt
+ The C-Kermit program logic manual. Available on the Kermit
+ website as:
+ [196]http://www.columbia.edu/kermit/ckcplm.html
+
+ [197]ca_certs.pem
+ Certificate Authority certificates for secure connections (see
+ [198]Section 16).
+
+5.3. Installing the Kermit Files
+
+ There is an "install" target in the [199]makefile that you can use if
+ you wish. However, since every site has its own layout and
+ requirements, it is often better to install the Kermit files by hand.
+ You don't have to use the makefile install target to install C-Kermit.
+ This is especially true since not all sites build C-Kermit from source,
+ and therefore might not even have the makefile. But you should read
+ this section in any case.
+
+ If your computer already has an older version of C-Kermit installed,
+ you should rename it (e.g. to "kermit6" or "kermit7") so in case you
+ have any trouble with the new version, the old one is still
+ available.
+
+ In most cases, you need to be root to install C-Kermit, if only to gain
+ write access to directories in which the binary and manual page are to
+ be copied. The C-Kermit binary should be installed in a directory that
+ is in the users' PATH, but that is not likely to be overwritten when
+ you install a new version of the operating system. A good candidate
+ would be the /usr/local/bin/ directory, but the specific choice is site
+ dependent. Example (assuming the appropriate Kermit binary is stored in
+ your current directory as "wermit", e.g. because you just built it from
+ source and that's the name the makefile gave it):
+
+mv wermit /usr/local/bin/kermit
+chmod 755 /usr/local/bin/kermit
+
+ or (only after you finish reading this section!) simply:
+
+make install
+
+ IMPORTANT: IF C-KERMIT IS TO BE USED FOR DIALING OUT, you must also do
+ something to give it access to the dialout devices and lockfile
+ directories. The 'install' target does not attempt to set Kermit's
+ owner, group, and permissions to allow dialing out. This requires
+ privileges, open eyes, and human decision-making. Please read
+ [200]Sections 10 and [201]11 below, make the necessary decisions, and
+ then implement them by hand as described in those sections.
+
+ You should also install the man page, which is called ckuker.nr, in the
+ man page directory for local commands, such as /usr/man/man1/, renamed
+ appropriately, e.g. to kermit.1. This is also taken care of by "make
+ install".
+
+ Optionally, the text files listed in the [202]previous section can be
+ placed in a publicly readable directory. Suggested directory names are:
+
+/usr/local/doc/kermit/
+/usr/local/lib/kermit/
+/usr/share/lib/kermit/
+/opt/kermit/doc/
+
+ (or any of these without the "/kermit"). Upon startup, C-Kermit checks
+ the following environment variables whose purpose is to specify the
+ directory where the C-Kermit text files are, in the following order:
+
+K_INFO_DIRECTORY
+K_INFO_DIR
+
+ If either of these is defined, C-Kermit checks for the existence of the
+ ckubwr.txt file (Unix C-Kermit Hints and Tips). If not found, it checks
+ the directories listed above (both with and without the "/kermit") plus
+ several others to see if they contain the ckubwr.txt file. If found,
+ various C-Kermit messages can refer the user to this directory.
+
+ Finally, if you want to put the source code files somewhere for people
+ to look at, you can do that too.
+
+5.4. The Makefile Install Target
+
+ The makefile "install" target does almost everything for you if you
+ give it the information it needs by setting the variables described
+ below. You can use this target if:
+
+ * You downloaded the [203]complete C-Kermit archive and built
+ C-Kermit from source; or:
+ * You downloaded an [204]individual C-Kermit binary and the
+ [205]C-Kermit text-file archive, and your computer has a "make"
+ command.
+
+ Here are the parameters you need to know:
+
+ BINARY
+ Name of the binary you want to install as "kermit". Default:
+ "wermit".
+
+ prefix
+ (lower case) If you define this variable, its value is prepended
+ to all the following xxxDIR variables (8.0.211 and later).
+
+ DESTDIR
+ If you want to install the Kermit files in a directory structure
+ like /opt/kermit/bin/, /opt/kermit/doc/, /opt/kermit/src/, then
+ define DESTIR as the root of this structure; for example,
+ /opt/kermit. The DESTDIR string should not end with a slash. By
+ default, DESTDIR is not defined. If it is defined, but the
+ directory does not exist, the makefile attempts to create it,
+ which might require you to be root. Even so, this can fail if
+ any segments in the path except the last one do not already
+ exist. WARNING: If the makefile creates any directories, it
+ gives them a mode of 755, and the default owner and group.
+ Modify these by hand if necessary.
+
+ BINDIR
+ Directory in which to install the Kermit binary (and the
+ standard C-Kermit initialization file, if it is found, as a
+ Kerbang script). If DESTDIR is defined, BINDIR must start with a
+ slash. BINDIR must not end with a slash. If DESTDIR is defined,
+ BINDIR is a subdirectory of DESTDIR. If BINDIR does not exist,
+ the makefile attempts to create it as with DESTDIR. Default:
+ /usr/local/bin.
+
+ MANDIR
+ Directory in which to install the C-Kermit manual page as
+ "kermit" followed by the manual-chapter extension (next item).
+ Default: /usr/man/man1. If MANDIR is defined, the directory must
+ already exist.
+
+ MANEXT
+ Extension for the manual page. Default: 1 (digit one).
+
+ SRCDIR
+ Directory in which to install the C-Kermit source code. If
+ DESTDIR is defined, this is a subdirectory of DESTDIR. Default:
+ None.
+
+ CERTDIR
+ For secure builds only: Directory in which to install the
+ ca_certs.pem file. This must be the verification directory used
+ by programs that use the SSL libraries at your site. Default:
+ none. Possibilities include: /usr/local/ssl, /opt/ssl,
+ /usr/lib/ssl, . . . If CERTDIR is defined, the directory
+ must already exist.
+
+ INFODIR
+ Directory in which to install the C-Kermit text files. If
+ DESTDIR is defined, this is a subdirectory of DESTDIR. Default:
+ None. If INFODIR is defined but does not exist, the makefile
+ attempts to create it, as with DESTDIR.
+
+ Examples:
+
+ make install
+ Installs "wermit" as /usr/local/bin/kermit with permissions 755,
+ the default owner and group, and no special privileges. The
+ manual page is installed as /usr/man/man1/kermit.1. Text files
+ are not copied anywhere, nor are the sources.
+
+ make MANDIR= install
+ Just like "make install" but does not attempt to install the
+ manual page.
+
+ make DESTDIR=/opt/kermit BINDIR=/bin SRCDIR=/src INFODIR=/doc install
+ Installs the Kermit binary "wermit" as /opt/kermit/bin/kermit,
+ puts the source code in /opt/kermit/src, and puts the text files
+ in /opt/kermit/doc, creating the directories if they don't
+ already exist, and puts the man page in the default location.
+
+ make BINDIR=/usr/local/bin CERTDIR=/usr/local/ssl install
+ Installs the Kerberized Kermit binary "wermit" as
+ /usr/local/bin/kermit, puts the CA Certificates file in
+ /usr/local/ssl/, and the man page in the normal place.
+
+ For definitive information, see the makefile. The following is
+ excerpted from the 8.0.211 makefile:
+
+# The following symbols are used to specify library and header file locations
+# Redefine them to the values used on your system by:
+# . editing this file
+# . defining the values on the command line
+# . defining the values in the environment and use the -e option
+#
+prefix = /usr/local
+srproot = $(prefix)
+sslroot = $(prefix)
+manroot = $(prefix)
+
+K4LIB=-L/usr/kerberos/lib
+K4INC=-I/usr/kerberos/include
+K5LIB=-L/usr/kerberos/lib
+K5INC=-I/usr/kerberos/include
+SRPLIB=-L$(srproot)/lib
+SRPINC=-I$(srproot)/include
+SSLLIB=-L$(sslroot)/ssl/lib
+SSLINC=-I$(sslroot)/ssl/include
+...
+WERMIT = makewhat
+BINARY = wermit
+DESTDIR =
+BINDIR = $(prefix)/bin
+MANDIR = $(manroot)/man/man1
+MANEXT = 1
+SRCDIR =
+INFODIR =
+CERTDIR =
+
+6. INSTALLING UNIX C-KERMIT FROM DOS-FORMAT DISKETTES
+
+ [ [206]Top ] [ [207]Contents ] [ [208]Next ] [ [209]Previous ]
+
+ This section is obsolete. We don't distribute C-Kermit on diskettes
+ any more because (a)there is no demand, and (b) it no longer fits.
+
+ If you received a DOS-format diskette containing a binary executable
+ C-Kermit program plus supporting text files, be sure to chmod +x the
+ executable before attempting to run it.
+
+ In version 5A(190) and later, all the text files on the C-Kermit
+ DOS-format diskettes are in Unix format: LF at the end of each line
+ rather than CRLF. This means that no conversions are necessary when
+ copying to your Unix file system, and that all the files on the
+ diskette, text and binary, can be copied together. The following
+ comments apply to the DOS-format diskettes furnished with version
+ 5A(189) and earlier or to other DOS-format diskettes you might have
+ obtained from other sources.
+
+ If you have received C-Kermit on MS-DOS format diskettes (such as those
+ distributed by Columbia University), you should make sure that your
+ DOS-to-Unix conversion utility (such as "dosread") both: (1) changes
+ line terminators in all files from carriage-return linefeed (CRLF) to
+ just linefeed (LF) (such as "dosread -a") and remove any Ctrl-Z's, and
+ (2) that all filenames are converted from uppercase to lowercase. If
+ these conversions were not done, you can use the following shell script
+ on your Unix system to do them:
+
+---(cut here)---
+#!/bin/sh
+#
+# Shell script to convert C-Kermit DOS-format files into Unix format.
+# Lowercases the filenames, strips out carriage returns and Ctrl-Z's.
+#
+x=$1 # the name of the source directory
+y=$2 # the name of the target directory if [ $# -lt 2 ]; then
+ echo "usage: $0 source-directory target-directory"
+ exit 1
+fi
+if cd $1 ; then
+ echo "Converting files from $1 to $2"
+else
+ echo "$0: cannot cd to $1"
+ exit 1
+fi
+for i in *; do
+ j=`echo $i | tr 'A-Z' 'a-z'`
+ echo $x/$i =\> $y/$j
+ tr -d '\015\032' < $i > $y/$j
+done
+---(cut here)---
+
+ Cut out this shell script, save it as "convert.sh" (or any other name
+ you prefer), then "chmod +x convert.sh". Then, create a new, empty
+ directory to put the converted files in, and then "convert.sh /xxx
+ /yyy" where /xxx is the name of the directory where the PC-format files
+ are, and /yyy is the name of the new, empty directory. The converted
+ files will appear in the new directory.
+
+7. CHECKING THE RESULTS
+
+ [ [210]Top ] [ [211]Contents ] [ [212]Next ] [ [213]Previous ]
+
+ First some quick checks for problems that can be easily corrected by
+ recompiling with different options:
+
+ DIRECTORY listing is garbage
+ Permissions, size, and date are random garbage (but the
+ filenames are correct) in a C-Kermit DIRECTORY listing. On some
+ platforms, the lstat() function is present but simply doesn't
+ work; try adding -DNOLSTAT to CFLAGS and rebuild. If that
+ doesn't fix it, also add -DNOLINKBITS. If it's still not fixed,
+ remove -DNOLSTAT and -DNOLINKBITS and add -DNOSYMLINK.
+
+ curses
+ When you make a connection with C-Kermit and transfer files
+ using the fullscreen (curses) file-transfer display, and then
+ get the C-Kermit> prompt back afterwards, do characters echo
+ when you type them? If not, the curses library has altered the
+ buffering of /dev/tty. Try rebuilding with KFLAGS=-DCK_NEWTERM.
+ If it already has -DCK_NEWTERM in CFLAGS, try removing it. If
+ that doesn't help, then rebuild with -DNONOSETBUF (yes, two
+ NO's). If none of this works (and you can't fix the code), then
+ either don't use the fullscreen display, or rebuild with
+ -DNOCURSES.
+
+ Ctrl-L or any SCREEN command crashes C-Kermit:
+ Rebuild with -DNOTERMCAP.
+
+ No prompt after CONNECT:
+ After escaping back from CONNECT mode, does your C-Kermit>
+ prompt disappear? (Yet, typing "?" still produces a command
+ list, etc) In that case, add -DCKCONINTB4CB to CFLAGS and
+ rebuild.
+
+ Here is a more thorough checklist can use to tell whether your version
+ of C-Kermit was built correctly for your Unix system, with hints on how
+ to fix or work around problems:
+
+ a. Start C-Kermit (usually by typing "./wermit" in the directory where
+ you ran the makefile). Do you see the C-Kermit> prompt? If not,
+ C-Kermit incorrectly deduced that it was running in the background.
+ The test is in conbgt() in [214]ckutio.c. If you can fix it for
+ your system, please send in the fix (Hint: read about "PID_T"
+ below). Otherwise, you can force C-Kermit to foreground mode by
+ starting it with the -z command line option, as in "kermit -z", or
+ giving the interactive command SET BACKGROUND OFF.
+ b. When you type characters at the C-Kermit prompt, do they echo
+ immediately? If not, something is wrong with concb() and probably
+ the other terminal mode settings routines in [215]ckutio.c. Be sure
+ you have used the most appropriate make entry.
+ c. At the C-Kermit> prompt, type "send ./?". C-Kermit should list all
+ the files in the current directory. If not, it was built for the
+ wrong type of Unix file system. Details below. In the meantime, try
+ SET WILDCARD-EXPANSION SHELL as a workaround.
+ d. CD to a directory that contains a variety of files, symlinks, and
+ subdirectories and give a DIRECTORY command at the C-Kermit>
+ prompt. Do the permissions, size, and date appear correct? If not
+ see [216]Section 4.0.
+ e. Assuming your platform supports long file names, create a file with
+ a long name in your current directory, e.g.:
+
+$ touch thisisafilewithaveryveryveryveryveryveryveryverylooooooooongname
+
+ (you might need to make it longer than this, perhaps as long as 257
+ or even 1025 characters).
+ Check with ls to see if your version of Unix truncated the name.
+ Now start C-Kermit and type "send thisis<ESC>". Does Kermit
+ complete the name, showing the same name as ls did? If not, wrong
+ filesystem. Read on.
+ f. Make sure that Kermit has the maximum path length right. Just type
+ SHOW FILE and see what it says about this. If it is too short,
+ there could be some problems at runtime. To correct, look in
+ [217]ckcdeb.h to see how the symbol CKMAXPATH is set and make any
+ needed adjustments.
+ g. Send a file to your new Kermit program from a different Kermit
+ program that is known to work. Is the date/timestamp of the new
+ file identical to the original? If not, adjustments are needed in
+ zstrdt() in [218]ckufio.c.
+ h. Go to another computer (Computer B) from which you can send files
+ to C-Kermit. Connect Computer B to the computer (A) where you are
+ testing C-Kermit. Then:
+ i. Send a file from B to A. Make sure it transferred OK and was
+ created with the right name.
+ j. Send a file from B to A, specifying an "as-name" that is very, very
+ long (longer than the maximum name length on computer A). Check to
+ make sure that the file was received OK and that its name was
+ truncated to Computer A's maximum length. If not, check the
+ MAXNAMLEN definition in [219]ckufio.c.
+ k. Tell C-Kermit on Computer A to "set receive pathnames relative" and
+ then send it a file from Computer B specifying an as-name that
+ contains several directory segments:
+
+send foo dir1/dir2/dir3/foo
+
+ Check to make sure that dir1/dir2/dir3/foo was created in Computer
+ A's current directory (i.e. that three levels of directories were
+ created).
+ l. Repeat step k, but make each path segment in the pathname longer
+ than Computer A's maximum name length. Make sure each directory
+ name, and the final filename, were truncated properly.
+ m. Type Ctrl-C (or whatever your Unix interrupt character is) at the
+ prompt. Do you get "^C..." and a new prompt? If instead, you get a
+ core dump (this shouldn't happen any more) "rm core" and then
+ rebuild with -DNOCCTRAP added to your CFLAGS. If it did work, then
+ type another Ctrl-C. If this does the same thing as the first one,
+ then Ctrl-C handling is OK. Otherwise, the SIGINT signal is either
+ not getting re-armed (shouldn't happen) or is being masked off
+ after the first time it is caught, in which case, if your Unix is
+ POSIX-based, try rebuilding C-Kermit with -DCK_POSIX_SIG.
+ n. Type Ctrl-Z (or whatever your Unix suspend character is) to put
+ C-Kermit in the background. Did it work? If nothing happened, then
+ (a)your version of Unix does not support job control, or (b) your
+ version of C-Kermit was probably built with -DNOJC. If your session
+ became totally frozen, then you are probably running C-Kermit on a
+ Unix version that supports job control, but under a shell that
+ doesn't. If that's not the case, look in the congm() and psuspend()
+ routines in [220]ckutio.c and see if you can figure out what's
+ wrong. If you can't, rebuild with -DNOJC.
+ o. Give a SET LINE command for a dialout device, e.g. "set line
+ /dev/tty00". If you got some kind of permission or access denied
+ message, go read [221]Section 10 and then come back here.
+ p. After giving a successful SET LINE command, type "show comm" to see
+ the communication parameters. Do they make sense?
+ q. Type "set speed ?" and observe the list of available speeds. Is it
+ what you expected? If not, see [222]Section 2) of the
+ [223]Configurations Options document.
+ r. Give a SET SPEED command to change the device's speed. Did it work?
+ (Type "show comm" again to check.)
+ s. Try dialing out: SET MODEM TYPE , SET LINE , SET SPEED , DIAL . If
+ it doesn't work, keep reading. After dialing, can you REDIAL?
+ t. If your version was built with TCP/IP network support, try the
+ TELNET command.
+ u. Transfer some files in remote mode on incoming asynchronous serial
+ (direct or modem) connections, and on incoming network (telnet,
+ rlogin, terminal server) connections. If you get lots of errors,
+ try different SET FLOW settings on the remote Kermit program.
+ v. Establish a serial connection from C-Kermit to another computer
+ (direct or dialed) and transfer some files. If you have network
+ support, do the same with a network connection.
+ w. If your version was built with fullscreen file transfer display
+ support, check that it works during local-mode file transfer. Also,
+ check C-Kermit's operation afterwards: is the echoing funny? etc
+ etc. If there are problems, see [224]Section 4.
+ x. If your version was built with script programming language support,
+ TAKE the ckedemo.ksc file to give it a workout.
+ y. Does C-Kermit interlock correctly with UUCP-family programs (cu,
+ tip, uucp, etc)? If not, read the section [225]DIALING OUT AND
+ COORDINATING WITH UUCP below.
+ z. Modem signals... Give a SET LINE command to a serial device and
+ then type the SHOW MODEM command. If it says "Modem signals
+ unavailable in this version of Kermit", then you might want to look
+ at the ttgmdm() routine in [226]ckutio.c and add the needed code --
+ if indeed your version of Unix provides a way to get modem signals
+ (some don't; e.g. modem signals are a foreign concept to POSIX,
+ requiring politically incorrect workarounds).
+ aa. If it says "Modem signals unavailable", then it is likely that the
+ API for getting modem signals is provided, but it doesn't actually
+ do anything (e.g. ioctl(ttyfd,TIOCMGET,&x) returns EINVAL).
+ ab. In any case, it still should be able to manipulate the DTR signal.
+ To test, SET LINE , SET MODEM NONE, and HANGUP. The DTR light
+ should go out momentarily. If it doesn't, see if you can add the
+ needed code for your system to the tthang() routine in
+ [227]ckutio.c.
+ ac. If your version of Kermit has the SET FLOW RTS/CTS command, check
+ to see if it works: give Kermit this command, set your modem for
+ RTS/CTS, transfer some files (using big packet and window sizes)
+ and watch the RTS and CTS lights on the modem. If they go on and
+ off (and Kermit does not get packet errors), then it works. If your
+ version of Kermit does not have this command, but your version of
+ Unix does support hardware flow control, take a look at the
+ tthflow() command in [228]ckutio.c and see if you can add the
+ needed code (see the section on [229]HARDWARE FLOW CONTROL below).
+ (And please [230]send back any added code, so that others can
+ benefit from it and it can be carried forward into future
+ releases.)
+ ad. If C-Kermit starts normally and issues its prompt, echoing is
+ normal, etc, but then after returning from a CONNECT session, the
+ prompt no longer appears, try rebuilding with -DCKCONINTB4CB.
+ ae. (8.0.206 or later) Type some commands at the C-Kermit prompt. Can
+ you use the Up-arrow and Down-arrow keys on your keyboard to access
+ Kermit's command history? If not, and you're a programmer, take a
+ look at the USE_ARROWKEYS sections of ckucmd.c.
+
+8. REDUCING THE SIZE OF THE EXECUTABLE PROGRAM IMAGE
+
+ [ [231]Top ] [ [232]Contents ] [ [233]Next ] [ [234]Previous ]
+
+ Also see: [235]C-Kermit Configuration Options
+
+ a. Many of C-Kermit's options and features can be deselected at
+ compile time. The greatest savings at the least sacrifice in
+ functionality is to disable the logging of debug information by
+ defining NODEBUG during compilation. See the [236]Configurations
+ Options document for further information.
+ b. Use shared libraries rather than static linking. This is the
+ default on many Unix systems anyway. However, executables built for
+ dynamic linking with shared libraries are generally not portable
+ away from the machine they were built on, so this is recommended if
+ the binary is for your use only.
+ c. Most Unix systems have a "strip" command to remove symbol table
+ information from an executable program image. "man strip" for
+ further information. The same effect can be achieved by including
+ "-s" among the link flags when building C-Kermit.
+ d. SCO, Interactive, and some other Unix versions have an "mcs"
+ command. "mcs -d wermit" can be used to delete the contents of the
+ ".comment" section from the executable program image.
+ e. Many modern optimizers can be instructed to optimize for space
+ rather than execution efficiency. Check the CFLAGS in the makefile
+ target, adjust as desired.
+
+9. UNIX VERSIONS
+
+ [ [237]Top ] [ [238]Contents ] [ [239]Next ] [ [240]Previous ]
+
+ SECTION CONTENTS
+
+9.1 [241]Standards
+ 9.1.1. [242]POSIX
+ 9.1.2. [243]ANSI C
+ 9.1.3. [244]Other Standards
+9.2. [245]Library Issues
+9.3. [246]Unix File System Peculiarities
+9.4. [247]Hardware Flow Control
+9.5. [248]Terminal Speeds
+9.6. [249]Millisecond Sleeps
+9.7. [250]Nondestructive Input Buffer Peeking
+9.8. [251]Other System-Dependent Features
+9.9. [252]Terminal Interruption
+
+ There are several major varieties of Unix: Bell Laboratories Seventh
+ Edition, AT&T System V, Berkeley Standard Distribution (BSD), and
+ POSIX. Each has many, many subvarieties and descendents, and there are
+ also hybrids that exhibit symptoms of two or more varieties, plus
+ special quirks of their own.
+
+ Seventh edition versions of C-Kermit include the compile-time option
+ -DV7 in the CFLAGS string in the makefile target. Various V7-based
+ implementations are also supported: -DCOHERENT, -DMINIX, etc.
+
+ AT&T-based versions of Unix Kermit include the compile-time option
+ -DATTSV (standing for AT∓T Unix System V). This applies to System
+ III and to System V up to and including Release 2. For System V Release
+ 3, the flag -DSVR3 should be used instead (which also implies -DATTSV).
+ This is because the data type of signal() and several other functions
+ was changed between SVR2 and SVR3. For System V Release 4, include
+ -DSVR4 because of changes in UUCP lockfile conventions; this also
+ implies -DSVR3 and -DATTSV.
+
+ For BSD, the flag -BSDxx must be included, where xx is the BSD version
+ number, for example BSD4 (for version 4.2 or later, using only 4.2
+ features), -DBSD41 (for BSD 4.1 only), -DBSD43 (for 4.3), -DBSD29 (BSD
+ 2.9 for DEC PDP-11s). -DBSD44 is for 4.4BSD, which is the basis of
+ FreeBSD, NetBSD, OpenBSD, BSDI, and Mac OS X, and which contains many
+ POSIX features, and has little relation to 4.3BSD and earlier.
+
+ For POSIX, include the flag -DPOSIX. POSIX defines a whole new set of
+ terminal i/o functions that are not found in traditional AT&T or
+ Berkeley implementations, and also defines the symbol _POSIX_SOURCE,
+ which is used in many system and library header files, mainly to
+ disable non-POSIX (i.e. useful) features.
+
+ Note (circa 1997): In order to enable serial speeds higher than 38400
+ bps, it is generally necessary to add -DPOSIX (among other things),
+ since the older terminal APIs can not accommodate the new speeds -- out
+ o' bits. But this often also means wholesale conversion to POSIX APIs.
+ In general, just try adding -DPOSIX and then see what goes wrong. Be
+ wary of features disappearing: when _POSIX_SOURCE is defined, all sorts
+ of things that were perfectly OK before suddenly become politically
+ incorrect -- like reading modem signals, doing hardware flow control,
+ etc. POSIX was evidently not designed with serial communication in
+ mind!
+
+ Case in point: In UnixWare 7.0, #define'ing POSIX causes strictness
+ clauses in the header files to take effect. These prevent <sys/time.h>
+ from defining the timeval and timezone structs, which are needed for
+ all sorts of things (like select()). Thus, if we want the high serial
+ speeds, we have to circumvent the POSIX clauses.
+
+ Similarly in SCO OpenServer R5.0.4 where, again, we must use the POSIX
+ APIs to get at serial speeds higher than 38400, but then doing so
+ removes hardware flow control -- just when we need it most! In cases
+ like this, dirty tricks are the only recourse (search for SCO_OSR504 in
+ [253]ckutio.c for examples).
+
+ For reasons like this, Unix implementations tend to be neither pure
+ AT&T nor pure BSD nor pure POSIX, but a mixture of two or more of
+ these, with "compatibility features" allowing different varieties of
+ programs to be built on the same computer. In general, Kermit tries not
+ to mix and match but to keep a consistent repertoire throughout.
+ However, there are certain Unix implementations that only work when you
+ mix and match. For example, the Silicon Graphics IRIX operating system
+ (prior to version 3.3) is an AT&T Unix but with a BSD file system. The
+ only way you can build Kermit successfully for this configuration is to
+ include -DSVR3 plus the special option -DLONGFN, meaning "pretend I was
+ built with -DBSDxx when it's time to compile file-related code". See
+ the "iris" makefile target.
+
+9.1. Standards
+
+ [ [254]Top ] [ [255]Section Contents ] [ [256]Contents ] [ [257]Next ]
+
+ SUBSECTION CONTENTS
+
+9.1.1. [258]POSIX
+9.1.2. [259]ANSI C
+9.1.3. [260]Other Standards
+
+ In edits 166-167 (1988-89), C-Kermit was heavily modified to try to
+ keep abreast of new standards while still remaining compatible with old
+ versions of C and Unix. There are two new standards of interest: ANSI C
+ (as described in Kernighan and Ritchie, "The C Programming Language",
+ Second Edition, Prentice Hall, 1988) and POSIX.1 (IEEE Standard 1003.1
+ and ISO/IEC 9945-1, 1990, "Portable Operating System Interface"). These
+ two standards have nothing to do with each other: you can build
+ C-Kermit with a non-ANSI compiler for a POSIX system, or for a
+ non-POSIX system with with an ANSI compiler.
+
+9.1.1. POSIX
+
+ POSIX.1 defines a repertoire of system functions and header files for
+ use by C language programs. Most notably, the ioctl() function is not
+ allowed in POSIX; all ioctl() functions have been replaced by
+ device-specific functions like tcsetattr(), tcsendbreak(), etc.
+
+ Computer systems that claim some degree of POSIX compliance have made
+ some attempt to put their header files in the right places and give
+ them the right names, and to provide system library functions with the
+ right names and calling conventions. Within the header files,
+ POSIX-compliant functions are supposed to be within #ifdef
+ _POSIX_SOURCE..#endif conditionals, and non-POSIX items are not within
+ these conditionals.
+
+ If Kermit is built with neither -D_POSIX_SOURCE nor -DPOSIX, the
+ functions and header files of the selected version of Unix (or VMS,
+ etc) are used according to the CFLAGS Kermit was built with.
+
+ If Kermit is built with -D_POSIX_SOURCE but not -DPOSIX, then one of
+ the -DBSD or -DATTSV flags (or one that implies them) must also be
+ defined, but it still uses only the POSIX features in the system header
+ files. This allows C-Kermit to be built on BSD or AT&T systems that
+ have some degree of POSIX compliance, but still use BSD or AT&T
+ specific features.
+
+ The dilemma is this: it is often necessary to define _POSIX_SOURCE to
+ get at new or modern features, such as high serial speeds and the APIs
+ to deal with them. But defining _POSIX_SOURCE also hides other APIs
+ that Kermit needs, for example the ones dealing with modem signals
+ (others are listed just below). Thus all sorts of hideous contortions
+ are often required to get a full set of features.
+
+ The POSIX standard does not define anything about uucp lockfiles. "make
+ posix" uses NO (repeat, NO) lockfile conventions. If your
+ POSIX-compliant Unix version uses a lockfile convention such as HDBUUCP
+ (see below), use the "posix" entry, but include the appropriate
+ lockfile option in your KFLAGS on the "make" command line, for example:
+
+make posix "KFLAGS=-DHDBUUCP"
+
+ POSIX.1 also lacks certain other features that Kermit needs. For
+ example:
+
+ * There is no defined way for an application to do wildcard matching
+ of filenames. Kermit uses the inode in the directory structure, but
+ POSIX.1 does not include this concept. (Later POSIX revisions
+ include functions named (I think) glob() and fnmatch(), but these
+ functions are not yet in Kermit, and might not be appropriate in
+ any case.)
+ * There is no POSIX mechanism for sensing or controlling modem
+ signals, nor to enable RTS/CTS or other hardware flow control.
+ * There is no select() for multiplexing i/o, and therefore no TCP/IP.
+ * There is no way to check if characters are waiting in a
+ communications device (or console) input buffer, short of trying to
+ read them -- no select(), ioctl(fd,FIONREAD,blah), rdchk(), etc.
+ This is bad for CONNECT mode and bad for sliding windows.
+ * No way to do a millisecond sleep (no nap(), usleep(), select(),
+ etc).
+ * There is no popen().
+
+ So at this point, there cannot be one single fully functional POSIX
+ form of C-Kermit unless it also has "extensions", as do Linux, QNX,
+ etc.
+
+ More on POSIX (quoting from a newsgroup posting by Dave Butenhof):
+
+ Standards tend to look at themselves as "enabling". So POSIX
+ standards say that, in order to use POSIX functions, a program must
+ define some macro that will put the development environment in
+ "POSIX mode". For the ancient POSIX 1003.1-1990, the symbol is
+ _POSIX_SOURCE. For recent revisions, it's _POSIX_C_SOURCE with an
+ appropriate value. POSIX 1003.1-1996 says that, to use its features
+ in a portable manner, you must define _POSIX_C_SOURCE=199506L before
+ including any header files.
+
+ But for Solaris, or Digital Unix, the picture is different. POSIX is
+ one important but small part of the universe. Yet POSIX
+ unconditionally and unambiguously REQUIRES that, when
+ _POSIX_C_SOURCE=199506L, ALL of the functions and definitions
+ required by the standard, and NO others (except in specific
+ restricted namespaces, specifically "_" followed by an uppercase
+ letter or "__" followed by a lowercase letter) shall be visible.
+ That kinda puts a cramp on BSD and SVID support, because those
+ require names that are not in the "protected" POSIX namespaces. It's
+ ILLEGAL to make those symbols visible, unless you've done something
+ else that's beyond the scope of POSIX to allow the system to infer
+ that you didn't really mean it.
+
+ In most cases, you should just compile, with no standards-related
+ macros defined. The system will make available every interface and
+ definition that isn't incompatible with the "main stream". There may
+ indeed be cases where two standards cross, and you really can't use
+ both together. But, in general, they play nicely together as long as
+ you don't do anything rash -- like telling the system that it's not
+ allowed to let them.
+
+ In the area of threads, both Solaris and Digital Unix support
+ incompatible thread APIs. We have POSIX and DCE, they have POSIX and
+ UI. The nasty areas are in the _r routines and in some aspects of
+ signal behavior. You cannot compile a single source file that uses
+ both semantics. That's life. It sounds as if Solaris defaults to the
+ UI variants, but allows you to define this _POSIX_THREAD_SEMANTICS
+ to get around it. We default to POSIX, and allow you to define
+ _PTHREAD_USE_D4 (automatically defined by the cc "-threads" switch)
+ to select the DCE thread variants. That default, because you're
+ operating outside of any individual standard, is really just a
+ marketing decision.
+
+9.1.2. ANSI C
+
+ [ [261]Top ] [ [262]Contents ] [ [263]Section Contents ] [
+ [264]Subsection Contents ] [ [265]Next ] [ [266]Previous ]
+
+ The major difference between ANSI C and earlier C compilers is function
+ prototyping. ANSI C allows function arguments to be checked for type
+ agreement, and (when possible) type coercion in the event of a
+ mismatch. For this to work, functions and their arguments must be
+ declared before they are called. The form for function declarations is
+ different in ANSI C and non-ANSI C (ANSI C also accepts the earlier
+ form, but then does not do type checking).
+
+ As of edit 167, C-Kermit tries to take full advantage of ANSI C
+ features, especially function prototyping. This removes many bugs
+ introduced by differing data types used or returned by the same
+ functions on different computers. ANSI C features are automatically
+ enabled when the symbol __STDC__ is defined. Most ANSI C compilers,
+ such as GNU CC and the new DEC C compiler define this symbol
+ internally.
+
+ On the downside, ANSI C compilation increases the
+ administrative/bureaucratic burden, spewing out countless unneeded
+ warnings about mismatched types, especially when we are dealing with
+ signed and unsigned characters, requiring casts everywhere to shut up
+ the mindless complaints -- there is no use for signed chars in Kermit
+ (or probably anywhere else). Some compilers, mercifully, include a
+ "treat all chars as unsigned" option, and when available it should be
+ used -- not only to stop the warnings, but also to avoid unhelpful sign
+ extension on high-bit characters.
+
+ To force use of ANSI C prototypes, include -DCK_ANSIC on the cc command
+ line. To disable the use of ANSI prototypes, include -DNOANSI.
+
+9.1.3. Other Standards
+
+ [ [267]Top ] [ [268]Contents ] [ [269]Section Contents ] [
+ [270]Subsection Contents ] [ [271]Next ] [ [272]Previous ]
+
+ As the years go by, standards with-which-all-must-comply continue to
+ pile up: AES, XPG2, XPG3, XPG4, FIPS 151-2, successive generations of
+ POSIX, OSF/1, X/Open, Spec 1170, UNIX95, Open Group UNIX98, ISO/IEC
+ 9945 parts 1-4, ISO 9899, 88Open, OS 99, Single Unix Specification
+ (SUS, [273]IEEE 1003.1-2001, not to mention "mature standards" like V7,
+ 4.2/4.3BSD, System V R3 and R4 (SVID2 and SVID3), 4.4BSD (the basis for
+ BSDI, OpenBSD, NetBSD, FreeBSD, Mac OS X etc), /usr/group, plus
+ assorted seismic pronouncements of the neverending series of ephemeral
+ corporate consortia, not to mention the libc-vs-glibc turmoil in the
+ Linux arena and who knows what else.
+
+ None of these standards simplifies life for portable applications like
+ C-Kermit -- each one is simply one more environment to support (or
+ circumvent, as in many cases these standards do more harm than good by
+ denying access to facilities we need, e.g. as noted in above in
+ [274]9.1.1).
+
+9.2. Library Issues
+
+ [ [275]Top ] [ [276]Contents ] [ [277]Section Contents ] [
+ [278]Subsection Contents ] [ [279]Next ] [ [280]Previous ]
+
+ On most modern platforms, applications are -- and often must be --
+ dynamically linked. This has numerous advantages (smaller executables,
+ ability to patch a library and thereby patch all applications that use
+ it, etc), but also causes some headaches: most commonly, the library ID
+ built into the executable at link time does not match the ID of the
+ corresponding library on the target system, and so the loader refuses
+ to let the application run.
+
+ This problem only gets worse over time. In the Linux and *BSD world, we
+ also have totally different libraries (each with their own names and
+ numbering systems) that cover the same territory; for example, curses
+ vs ncurses, libc versus glibc. Combinations proliferate and any given
+ Unix computer might have any combination. For this reason it is
+ becoming increasingly difficult to produce a "Linux binary" for a given
+ architecture (e.g. PC or Alpha). There has to be a separate binary for
+ (at least) every combination of curses vs ncurses and libc vs glibc.
+
+ In such cases, the best advice is for every user to build C-Kermit from
+ source code on the system where it will run. Too bad most commercial
+ Unix vendors have stopped including C compilers with the operating
+ system!
+
+9.3. Unix File System Peculiarities
+
+ [ [281]Top ] [ [282]Contents ] [ [283]Section Contents ] [ [284]Next ]
+ [ [285]Previous ]
+
+ Normally, including a BSD, System-V, POSIX, or DIRENT flag in the make
+ entry selects the right file system code. But some versions of Unix are
+ inconsistent in this regard, and building in the normal way either
+ gives compiler or linker errors, or results in problems at runtime,
+ typically failure to properly expand wildcard file specifications when
+ you do something like "send *.*", or failure to recognize long
+ filenames, as in "send filewithaveryveryveryveryverylongname".
+
+ C-Kermit is supposed to know about all the various styles of Unix file
+ systems, but it has to be told which one to use when you build it,
+ usually in the makefile target CFLAGS as shown below, but you might
+ also have to add something like -I/usr/include/bsd to CFLAGS, or
+ something like -lbsd to LIBS.
+
+ C-Kermit gives you the following CFLAGS switches to adapt to your file
+ system's peculiarities:
+
+-DDIRENT - #include <dirent.h>
+-DSDIRENT - #include <sys/dirent.h>
+-DNDIR - #include <ndir.h>
+-DXNDIR - #include <sys/ndir.h>
+-DRTU - #include "/usr/lib/ndir.h", only if NDIR and XNDIR not defined.
+-DSYSUTIMH - #include <sys/utime.h> for setting file creation dates.
+-DUTIMEH - #include <utime.h> for setting file creation dates.
+
+ (Note, RTU should only be used for Masscomp RTU systems, because it
+ also selects certain other RTU-specific features.)
+
+ If none of these is defined, then <sys/dir.h> is used. IMPORTANT: If
+ your system has the file /usr/include/dirent.h then be sure to add
+ -DDIRENT to your makefile target's CFLAGS. "dirent" should be used in
+ preference to any of the others, because it supports all the features
+ of your file system, and the others probably don't.
+
+ Having selected the appropriate directory header file, you might also
+ need to tell Kermit how to declare the routines and variables it needs
+ to read the directory. This happens most commonly on AT&T System-V
+ based UNIXes, particularly System V R3 and earlier, that provide long
+ file and directory names (longer than 14 characters). Examples include
+ certain releases of HP-UX, DIAB DNIX, older versions of Silicon
+ Graphics IRIX, and perhaps also MIPS. In this case, try adding -DLONGFN
+ to your makefile target.
+
+ Another problem child is <sys/file.h>. Most Unix C-Kermit versions need
+ to #include this file from within [286]ckufio.c and [287]ckutio.c, but
+ some not only do not need to include it, but MUST not include it
+ because (a) it doesn't exist, or (b) it has already been included by
+ some other header file and it doesn't protect itself against multiple
+ inclusion, or (c) some other reason that prevents successful
+ compilation. If you have compilation problems that seem to stem from
+ including this file, then add the following switch to CFLAGS in your
+ makefile target:
+
+-DNOFILEH
+
+ There are a few odd cases where <sys/file.h> must be included in one of
+ the cku[ft]io.c files, but not the other. In that case, add the
+ aforementioned switch, but go into the file that needs <sys/file.h> and
+ add something like this:
+
+#ifdef XXX /* (where XXX is a symbol unique to your system) */
+#undef NOFILEH
+#endif /* XXX */
+
+ before the section that includes <sys/file.h>.
+
+ Kermit's SEND command expands wildcard characters "?" and "*" itself.
+ Before version 5A, commands like "send *" would send all regular
+ (non-directory) files, including "hidden files" (whose names start with
+ "."). In version 5A, the default behavior is to match like the Bourne
+ shell or the ls command, and not include files whose names start with
+ dot. Such files can still be sent if the dot is included explicitly in
+ the SEND command: "send .oofa, send .*". To change back to the old way
+ and let leading wildcard characters match dot files, include the
+ following in your CFLAGS:
+
+-DMATCHDOT
+
+ (In C-Kermit 6.0, there is also a command to control this at runtime.)
+
+ Complaints about data-type mismatches:
+
+ * If you get compile-time complaints about data type mismatches for
+ process-ID related functions like getpid(), add -DPID_T=pid_t.
+ * If you get compile-time complaints about data type mismatches for
+ user ID related functions like getuid(), add -DUID_T=uid_t.
+ * If you get compile-time complaints about data type mismatches for
+ user-ID related functions like getgid(), add -DGID_T=gid_t.
+ * If you get compile-time complaints about data type mismatches for
+ getpwuid(), add -DPWID_T=uid_t (or whatever it should be).
+
+ File creation dates: C-Kermit attempts to set the creation date/time of
+ an incoming file according to the date/time given in the file's
+ attribute packet, if any. If you find that the dates are set
+ incorrectly, you might need to build Kermit with the -DSYSUTIMEH flag,
+ to tell it to include <sys/utime.h>. If that doesn't help, look at the
+ code in zstrdt() in [288]ckufio.c.
+
+9.4. Hardware Flow Control
+
+ [ [289]Top ] [ [290]Contents ] [ [291]Section Contents ] [ [292]Next ]
+ [ [293]Previous ]
+
+ Hardware flow control is a problematic concept in many popular Unix
+ implementations. Often it is lacking altogether, and when available,
+ the application program interface (API) to it is inconsistent from
+ system to system. Here are some examples:
+
+ a. POSIX does not support hardware flow control.
+ b. RTS/CTS flow control support MIGHT be available for System V R3 and
+ later if /usr/include/termiox.h exists (its successful operation
+ also depends on the device driver, and the device itself, not to
+ mention the [294]cable, etc, actually supporting it). If your
+ SVR3-or-later Unix system does have this file, add:
+
+-DTERMIOX
+
+ to your CFLAGS. If the file is in /usr/include/sys instead, add:
+
+-DSTERMIOX
+
+ Note that the presence of this file does not guarantee that RTS/CTS
+ will actually work -- that depends on the device-driver
+ implementation (reportedly, many Unix versions treat
+ hardware-flow-control related ioctl's as no-ops).
+ c. Search ("grep -i") through /usr/include/*.h and
+ /usr/include/sys/*.h for RTS or CTS and see what turns up. For
+ example, in SunOS 4.x we find "CRTSCTS". Figuring out how to use it
+ is another question entirely! In IBM AIX RS/6000 3.x, we have to
+ "add" a new "line discipline" (and you won't find uppercase RTS or
+ CTS symbols in the header files).
+ d. NeXTSTEP and IRIX, and possibly others, support hardware flow
+ control, but do not furnish an API to control it, and thus on these
+ systems Kermit has no command to select it -- instead, a special
+ device name must be used. (NeXTSTEP: /dev/cufa instead of /dev/cua;
+ IRIX: /dev/ttyf00)
+
+ See the routine tthflow() in [295]ckutio.c for details. If you find
+ that your system offers hardware flow control selection under program
+ control, you can add this capability to C-Kermit as follows:
+
+ a. See if it agrees with one of the methods already used in tthflow().
+ if not, add new code, appropriately #ifdef'd.
+ b. Add -DCK_RTSCTS to the compiler CFLAGS in your makefile target or
+ define this symbol within the appropriate #ifdefs in [296]ckcdeb.h.
+
+ To illustrate the difficulties with RTS/CTS, here is a tale from Jamie
+ Watson <jw@adasoft.ch>, who added the RTS/CTS code for the RS/6000,
+ about his attempts to do the same for DEC ULTRIX:
+
+ "The number and type of hardware signals available to/from a serial
+ port vary between different machines and different types of serial
+ interfaces on each machine. This means that, for example, there are
+ virtually no hardware signals in or out available on the DECsystem
+ 3000/3100 series; on the DECsystem 5000/2xx series all modem signals
+ in/out are present on both built-in serial ports; on the DECsystem
+ 5100 some ports have all signals and some only have some; and so
+ on... It looks to me as if this pretty well rules out any attempt to
+ use hardware flow control on these platforms, even if we could
+ figure out how to do it. The confusion on the user level about
+ whether or not it should work for any given platform or port would
+ be tremendous. And then it isn't clear how to use the hardware
+ signals even in the cases where the device supports them."
+
+ 9.5. Terminal Speeds
+
+ [ [297]Top ] [ [298]Contents ] [ [299]Section Contents ] [ [300]Next ]
+ [ [301]Previous ]
+
+ The allowable speeds for the SET SPEED command are defined in
+ [302]ckcdeb.h. If your system supports speeds that are not listed in
+ "set speed ?", you can add definitions for them to ckcdeb.h.
+
+ Then if the speed you are adding is one that was never used before in
+ Kermit, such as 921600, you'll also need to add the appropriate
+ keywords to spdtab[] in [303]ckuus3.c, and the corresponding case to
+ ttsspd() in [304]ckutio.c.
+
+ 9.6. Millisecond Sleeps
+
+ [ [305]Top ] [ [306]Contents ] [ [307]Section Contents ] [ [308]Next ]
+ [ [309]Previous ]
+
+ There is no standard for millisecond sleeps, but at least five
+ different functions have appeared in various Unix versions that can be
+ used for this purpose: nap() (mostly in System V), usleep() (found at
+ least in SunOS and NeXT OS), select() (found in 4.2BSD and later, and
+ part of any TCP/IP sockets library), nanosleep(), and sginap(). If you
+ have any of these available, pick one (in this order of preference, if
+ you have more than one):
+
+-DSELECT: Include this in CFLAGS if your system has the select() function.
+-DNAP: Include this in CFLAGS if your system has the nap() function.
+-USLEEP: Include this in CFLAGS if your system has the usleep() function.
+
+ NOTE: The nap() function is assumed to be a function that puts the
+ process to sleep for the given number of milliseconds. If your system's
+ nap() function does something else or uses some other units of time
+ (like the NCR Tower 32, which uses clock-ticks), do not include -DNAP.
+
+ Reportedly, all versions of System V R4 for Intel-based computers, and
+ possibly also SVR3.2, include nap() as a kernel call, but it's not in
+ the library. To include code to use it via syscall(3112,x), without
+ having to include Xenix compatibility features, include the following
+ compile-time option:
+
+-DNAPHACK
+
+ 9.7. Nondestructive Input Buffer Peeking
+
+ [ [310]Top ] [ [311]Contents ] [ [312]Section Contents ] [ [313]Next ]
+ [ [314]Previous ]
+
+ Some AT&T Unix versions have no way to check if input is waiting on a
+ tty device, but this is a very important feature for Kermit. Without
+ it, sliding windows might not work very well (or at all), and you also
+ have to type your escape character to get Kermit's attention in order
+ to interrupt a local-mode file transfer. If your system offers an
+ FIONREAD ioctl, the build procedure should pick that up automatically
+ and use it, which is ideal.
+
+ If your system lacks FIONREAD but has a select() function, this can be
+ used instead. If the build procedure fails to include it (SHOW FEATURES
+ will list SELECT), then you can add it to your CFLAGS:
+
+-DSELECT
+
+ Conversely, if the build procedure tries to use select() when it really
+ is not there, add:
+
+-DNOSELECT
+
+ Note: select() is not part of System V nor of POSIX, but it has been
+ added to various System-V- and POSIX-based systems as an extension.
+
+ Some System-V variations (SCO Xenix/UNIX/ODT and DIAB DNIX) include a
+ rdchk() function that can be used for buffer peeking. It returns 0 if
+ no characters are waiting and 1 if characters are waiting (but unlike
+ FIONREAD, it does not tell the actual number). If your system has
+ rdchk(), add:
+
+-DRDCHK: Include this in CFLAGS if your system has the rdchk() function.
+
+ Otherwise, if your version of Unix has the poll() function (and the
+ /usr/include/poll.h file) -- which appears to be a standard part of
+ System V going back to at least SVR3, include:
+
+-DCK_POLL
+
+ 9.8. Other System-Dependent Features
+
+ [ [315]Top ] [ [316]Contents ] [ [317]Section Contents ] [ [318]Next ]
+ [ [319]Previous ]
+
+ Systems with <termios.h> might have the symbol IEXTEN defined. This is
+ used to turn "extended features" in the tty device driver on and off,
+ such as Ctrl-O to toggle output flushing, Ctrl-V to quote input
+ characters, etc.
+
+ In most Unix implementations, it should be turned off during Kermit
+ operation, so if [320]ckutio.c finds this symbol, it uses it. This is
+ necessary, at least, on BSDI. On some systems, however, IEXTEN is
+ either misdefined or misimplemented. The symptom is that CR, when typed
+ to the command processor, is echoed as LF, rather than CRLF. This
+ happens (at least) on Convex/OS 9.1. The solution is to add the
+ following symbol to the makefile target's CFLACS:
+
+-DNOIEXTEN
+
+ However, in at least one Unix implementation, QNX 4.21, IEXTEN must be
+ set before hardware flow control can be used.
+
+ In edits 177 and earlier, workstation users noticed a "slow screen
+ writing" phenomenon during interactive command parsing. This was traced
+ to a setbuf() call in [321]ckutio.c that made console (stdout) writes
+ unbuffered. This setbuf() call has been there forever, and could not be
+ removed without some risk. Kermit's operation was tested on the NeXT in
+ edit 178 with the setbuf() call removed, and the slow-writing symptom
+ was cured, and everything else (command parsing, proper wakeup on ?,
+ ESC, Ctrl-U, and other editing characters, terminal emulation,
+ remote-mode and local-mode file transfer, etc) seemed to work as well
+ as or better than before. In subsequent edits, this change was made to
+ many other versions too, with no apparent ill effects. To remove the
+ setbuf() call for your version of Kermit, add:
+
+-DNOSETBUF
+
+ Later reports indicate that adding -DNOSETBUF has other beneficial
+ effects, like cutting down on swapping when Kermit is run on
+ workstations with small memories. But BEWARE: on certain small Unix
+ systems, notably the AT&T 6300 and 3B1 (the very same ones that benefit
+ from NOSETBUF), NOSETBUF seems to conflict with CK_CURSES. The program
+ builds and runs OK, but after once using the curses display, echoing is
+ messed up. In this case, we use a System-V specific variation in the
+ curses code, using newterm() to prevent System V from altering the
+ buffering. See makefile entries for AT&T 6300 and 3B1.
+
+ The Unix version of C-Kermit includes code to switch to file descriptor
+ zero (stdin) for remote-mode file transfer. This code is necessary to
+ prevent Kermit from giving the impression that it is "idle" during file
+ transfers, which, at some sites, can result in the job being logged out
+ in the middle of an active file transfer by idle-job monitors.
+
+ However, this feature can interfere with certain setups; for example,
+ there is a package which substitutes a pty/tty pair for /dev/tty and
+ sets file descriptor 0 to be read-only, preventing Kermit from sending
+ packets. Or... When a Unix shell is invoked under the PICK environment,
+ file descriptor 0 is inoperative.
+
+ To remove this feature and allow Kermit to work in such environments,
+ add the compile-time option:
+
+-DNOFDZERO
+
+ On some versions of Unix, earlier releases of C-Kermit were reported to
+ render a tty device unusable after a hangup operation. Examples include
+ IBM AIX on the RT PC and RS/6000. A typical symptom of this phenomenon
+ is that the DIAL command doesn't work, but CONNECTing to the device and
+ dialing manually do work. A further test is to SET DIAL HANGUP OFF,
+ which should make dialing work once by skipping the pre-dial hangup.
+ However, after the connection is broken, it can't be used any more:
+ subsequent attempts to DIAL the same device don't work. The cure is
+ usually to close and reopen the device as part of the hangup operation.
+ To do this, include the following compile-time option:
+
+-DCLSOPN
+
+ Similarly, there is a section of code in ttopen(), which does another
+ close(open()) to force the O_NDELAY mode change. On some systems, the
+ close(open()) is required to make the mode change take effect, and
+ apparently on most others it does no harm. But reportedly on at least
+ one System V R4 implementation, and on SCO Xenix 3.2, the close(open())
+ operation hangs if the device lacks carrier, EVEN THOUGH the CLOCAL
+ characteristic has just been set to avoid this very problem. If this
+ happens to you, add this to your CFLAGS:
+
+-DNOCOTFMC
+
+ or, equivalently, in your KFLAGS on the make command line. It stands
+ for NO Close(Open()) To Force Mode Change.
+
+ C-Kermit renames files when you give a RENAME command and also
+ according to the current SET FILE COLLISION option when receiving
+ files. The normal Unix way to rename a file is via two system calls:
+ link() and unlink(). But this leaves open a window of vulnerability.
+ Some Unix systems also offer an atomic rename(oldname,newname)
+ function. If your version of Unix has this function, add the following
+ to your CFLAGS:
+
+-DRENAME
+
+ C-Kermit predefines the RENAME for several Unix versions in
+ [322]ckcdeb.h (SVR4, SUNOS41, BSD44, AIXRS, etc). You can tell if
+ rename() is being used if the SHOW FEATURES command includes RENAME in
+ the compiler options list. If the predefined RENAME symbol causes
+ trouble, then add NORENAME to your CFLAGS. Trouble includes:
+
+ a. Linker complains that _rename is an unresolved symbol.
+ b. Linking works, but Kermit's RENAME command doesn't work (which
+ happens because older versions of rename() might have their
+ arguments reversed).
+
+ If rename() is not used, then Kermit uses link()/unlink(), which is
+ equivalent except it is not atomic: there is a tiny interval in which
+ some other process might "do something" to one of the files or links.
+
+ Some Unix systems (Olivetti X/OS, Amdahl UTS/V, ICL SVR3, etc) define
+ the S_ISREG and S_ISDIR macros incorrectly. This is compensated for
+ automatically in [323]ckufio.c. Other systems might have this same
+ problem. If you get a compile-time error message regarding S_ISREG
+ and/or S_ISDIR, add the following to your CFLAGS:
+
+-DISDIRBUG
+
+ Finally, here's a symbol you should NEVER define:
+
+-DCOMMENT
+
+ It's used for commenting out blocks of code. If for some reason you
+ find that your compiler has COMMENT defined, then add -UCOMMENT to
+ CFLAGS or KFLAGS! Similarly, some header files have been known to
+ define COMMENT, in which case you must add "#undef COMMENT" to each
+ C-Kermit source module, after all the #includes.
+
+ 9.9. Terminal Interruption
+
+ [ [324]Top ] [ [325]Contents ] [ [326]Section Contents ] [ [327]Next ]
+ [ [328]Previous ]
+
+ When C-Kermit enters interactive command mode, it sets a Control-C
+ (terminal keyboard interrupt = SIGINT) trap to allow it to return to
+ the command prompt whenever the user types Control-C (or whatever is
+ assigned to be the interrupt character). This is implemented using
+ setjmp() and longjmp(). On some systems, depending on the machine
+ architecture and C compiler and who knows what else, you might get
+ "Memory fault (coredump)" or "longjmp botch" instead of the desired
+ effect (this should not happen in 5A(190) and later). In that case, add
+ -DNOCCTRAP to your CFLAGS and rebuild the program.
+
+ Job control -- the ability to "suspend" C-Kermit on a Unix system by
+ typing the "susp" character (normally Ctrl-Z) and then resume execution
+ later (with the "fg" command) -- is a tricky business. C-Kermit must
+ trap suspend signals so it can put the terminal back into normal mode
+ when you suspend it (Kermit puts the terminal into various strange
+ modes during interactive command parsing, CONNECT, and file transfer).
+ Supporting code is compiled into C-Kermit automatically if <signal.h>
+ includes a definition for the SIGTSTP signal. HOWEVER... some systems
+ define this signal without supporting job control correctly. You can
+ build Kermit to ignore SIGTSTP signals by including the -DNOJC option
+ in CFLAGS. (You can also do this at runtime by giving the command SET
+ SUSPEND OFF.)
+
+ NOTE: As of version 5A(190), C-Kermit makes another safety check.
+ Even if job control is available in the operating system (according
+ to the numerous checks made in congm()), it will still disable the
+ catching of SIGTSTP signals if SIGTSTP was set to SIG_IGN at the
+ time C-Kermit was started.
+
+ System V R3 and earlier systems normally do not support job control. If
+ you have an SVR3 system that does, include the following option in your
+ CFLAGS:
+
+-DSVR3JC
+
+ On systems that correctly implement POSIX signal handling, signals can
+ be handled more reliably than in Bell, Berkeley, or AT&T Unixes. On
+ systems (such as QNX) that are "strictly POSIX", POSIX signal handling
+ *must* be used, otherwise no signal will work more than once. If you
+ have POSIX-based system and you find that your version of Kermit
+ responds to Ctrl-C (SIGINT) or Ctrl-Z (SIGTSTP) only once, then you
+ should add the following option to your CFLAGS:
+
+-DCK_POSIX_SIG
+
+ But be careful; some POSIX implementations, notably 4.4BSD, include
+ POSIX signal handling symbols and functions as "stubs" only, which do
+ nothing. Look in <signal.h> for sigsetjmp and siglongjmp and read the
+ comments.
+
+10. DIALING OUT AND COORDINATING WITH UUCP
+
+ [ [329]Top ] [ [330]Contents ] [ [331]Next ] [ [332]Previous ]
+
+ The short version (general):
+
+ In order for C-Kermit to be able to dial out from your Unix
+ computer, you need to give it the same owner, group, and permissions
+ as your other dialout programs, such as cu, tip, minicom, uucp,
+ seyon, etc.
+
+ The short version for Linux only:
+
+ Since Red Hat 7.2, about 2002, Linux does not leave the lockfile
+ handling to each application, but instead provides an external
+ application, /usr/sbin/lockdev, that all applications should invoke
+ when they need to access a serial port; lockdev locks and unlocks
+ the port without requiring the application to have privileges, since
+ the privileges on the lockfile directory are assigned to lockdev.
+ C-Kermit 8.0.211 and later support this method. But C-Kermit still
+ needs to be able to open the port itself, and therefore if the
+ port's permissions do not allow read/write access to the general
+ public, the general rule must still be followed: in the most common
+ case, it must be SETGID to the group uucp (explained below). If a
+ pre-8.0.211 version of C-Kermit is to be installed for use with
+ serial ports on any version of Linux, it must still be installed as
+ described in the following sections.
+
+ The long version:
+
+ Make sure your dialout line is correctly configured for dialing out (as
+ opposed to login). The method for doing this is different for each kind
+ of Unix. Consult your system documentation for configuring lines for
+ dialing out (for example, Sun SPARCstation IPC users should read the
+ section "Setting up Modem Software" in the Desktop SPARC Sun System and
+ Network Manager's Guide, or the Terminals and Modems section of the HP
+ manual, "Configuring HP-UX for Peripherals" (e.g. /usr/sbin/sam =>
+ Peripheral Devices => Terminals and Modems => Add Modem).
+
+ Unlike most other multiuser, multitasking operating systems, Unix
+ allows multiple users to access the same serial device at the same
+ time, even though there is no earthly reason why two users should do
+ this. When they do, user A will read some of the incoming characters,
+ and user B will read the others. In all likelihood, neither user will
+ see them all. Furthermore, User B can hang up User A's call, and so
+ one.
+
+ Rather than change Unix to enforce exclusive access to serial devices
+ such as ttys, when it might still have been possible, Unix developers
+ opted for a "lock file" mechanism. Any process that wants to open a tty
+ device should first check to see if a file of a certain name exists,
+ and if so, not to open the device. If the file does not exist, the
+ process creates the file and then opens the device. When the process
+ closes the device, it destroys the lockfile. This procedure was
+ originated for use with Unix's UUCP, CU, and TIP programs, and so these
+ lockfiles are commonly called "UUCP lockfiles" (UUCP = Unix-to-Unix
+ Copy Program).
+
+ As you can imagine, this method is riddled with pitfalls:
+
+ * If a process does not observe the prevailing lockfile convention,
+ then it can interfere with other "polite" processes. And in fact,
+ very few Unix applications or commands handle lockfiles at all; an
+ original design goal of Unix was that "everything is a file", and
+ countless utilities operate on files directly (by opening them) or
+ indirectly through redirection of standard i/o, without creating or
+ looking for lockfiles.
+ * If a process crashes while it has the device open, the lockfile is
+ left behind, preventing further processes from using the device.
+ * Various versions of Unix use different names for the lockfiles, put
+ them in different directories, with different owners and groups and
+ permissions, and specify their contents differently.
+ * On a given platform, the lockfile conventions may change from one
+ Unix release to the next (for example, SunOS 4.0 to 4.1) or, in the
+ case of Linux, across different distributions.
+ * The same tty device might have more than one name, and most
+ lockfile conventions don't allow for this. Similarly for symbolic
+ links.
+
+ In an attempt to address the problem of "stale" lockfiles, most UUCP
+ implementations put the PID (Process ID) of the creating process in the
+ lockfile. Thus, another process that wants to open the corresponding
+ device can check not only for the lockfile itself, but also can check
+ the PID for validity. But this doesn't work well either:
+
+ * PIDs are stored in diverse formats that change with every new
+ release (short, integer, long, or string in any of various
+ formats). If the reading program does not follow the same
+ convention as the writing program, it can diagnose a valid PID to
+ be invalid, and therefore not honor the lock.
+ * PIDs recycle. If the lockfile was created by PID 1234, which later
+ crashed without removing the lockfile, and then a new process 1234
+ exists a the time the lockfile is checked, the lockfile will be
+ improperly taken as valid, and access to the device denied
+ unnecessarily.
+
+ Several techniques address the problem of multiple names for the same
+ device:
+
+ * Multiple lockfiles. For example, if the user opens a device through
+ a symlink, a lockfile is created for both the symlink name and the
+ true name (obtained from readlink()). However, when multiple
+ drivers are installed for the same device (e.g. /dev/cua,
+ /dev/cufa, etc), this approach won't work unless all applications
+ *know* all the different names for the same device and make
+ lockfiles for all of them, which is obviously not practical.
+ * Lockfiles whose names are not based on the device name. These
+ lockfiles generally have names like LK.inode/major/minor, where
+ inode, major, and minor are numbers, which will always be the same
+ for any physical device, no matter what its name. This form of
+ lockfile is used in System V R4 and its derivatives, such as
+ Solaris, UnixWare, etc. If lockfiles must be used (as opposed to,
+ say, kernel-based locks), this would seem to be the most effective
+ form.
+
+ Most versions of Unix were not designed to accommodate third-party
+ communications software; thus vendors of these Unix products feel no
+ compunction about changing lockfile conventions from release to
+ release, since they also change their versions of the cu, uucp, tip,
+ etc, programs at the same time to match. And since the source code to
+ these programs might not be published, it is difficult for makers of
+ third-party products like C-Kermit to find out what the new conventions
+ are. It also forces release of new versions of C-Kermit whenever the OS
+ vendor makes a change like this.
+
+ Some Unix vendors have taken a small step to simplify communications
+ application development for their products: the inclusion of lockfile
+ routines in the standard system C runtime libraries to shield the
+ application from the details of lockfile management (IBM AIX is an
+ example). When such routines are used, communications applications do
+ not need modification when lockfile conventions change (although they
+ will need recompiling if the routines are statically linked into the
+ application). In the AIX example, the simple function calls ttylock(),
+ ttyunlock(), and ttylocked() replace hundreds of lines of ugly code in
+ C-Kermit that attempts to keep pace with every release of every Unix
+ product over the last 20 years. Inclusion of ttylock() code occurs
+ when:
+
+-DUSETTYLOCK
+
+ is included in the CFLAGS.
+
+ If such routines are available, they should be used. The rest of this
+ section applies when they are not.
+
+ To fit in with UUCP and other Unix-based serial-port communication
+ software, C-Kermit must have the same idea as your system's uucp, cu,
+ and tip programs about what the UUCP lock directory is called, what the
+ lockfile itself is called, and what its contents should be. In most
+ cases, C-Kermit preprocessor flags create the appropriate configuration
+ at compile time if the appropriate makefile target was used (see
+ [333]ckutio.c). The following CFLAGS options can be used to override
+ the built-in configuration:
+
+ -DLCKDIR
+ Tells Kermit that the UUCP lock directory is
+ /usr/spool/uucp/LCK.
+
+ -DACUCNTRL
+ Tells Kermit to use the BSD 4.3 acucntrl() program to turn off
+ getty (login) on the line before using it, and restore getty
+ when done.
+
+ -DHDBUUCP
+ Include this if your system uses Honey DanBer UUCP, in which the
+ lockfile directory and format are relatively standardized.
+
+ -DLOCK_DIR=\\\"/xxx/yyy\\\"
+ Gives the lock directory name explicitly. The triple quoting is
+ necessary. For example:
+
+CFLAGS= -DBSD4 -DLOCK_DIR=\\\"/usr/local/locks\\\" -DNODEBUG
+
+ (NOTE: The triple quoting assumes this is a "top-level" make
+ entry, and not a make entry that calls another one.)
+
+ -DLFDEVNO The lockfile name uses the tty device inode and major and
+ minor
+ numbers: LK.dev.maj.min, as in Sys V R4, e.g. LK.035.044.008.
+
+ When the LK.inode.major.minor form is used, a single lockfile is
+ enough. Otherwise, a single lockfile rarely suffices. For example, in
+ Linux, it is common to have a /dev/modem symbolic link to an actual
+ dialout device, like /dev/cua0 or /dev/ttyS0, whose purpose is to hide
+ the details of the actual driver from the user. So if one user opens
+ /dev/modem, a lockfile called LCK..modem is created, which does not
+ prevent another user from simultaneously opening the same device by its
+ real name.
+
+ On SCO Unix platforms, we have a slightly different problem: the same
+ device is, by convention, known by "lowercase" and "uppercase" names,
+ depending on whether it has modem control. So by convention,
+ communications programs are supposed to create the lockfiles based on
+ the lowercase name. But some programs don't follow this convention. In
+ HP-UX, we have several different names for each serial device. And so
+ on.
+
+ For this reason, on platforms where the LK.inode.major.minor form is
+ not used, C-Kermit also creates a secondary lockfile (which is simply a
+ link to the first) if:
+
+ a. The given device name is a symbolic link. The secondary link is
+ based on the device's real name.
+ b. On SCO: The device name is not a symbolic link, but it contains
+ uppercase letters. The primary link is based on the lowercase name;
+ the secondary link is based on the name that was given.
+ c. On HP-UX: The device name starts with "cu". The primary link is
+ based on the name that was given; the secondary link is based on
+ the corresponding "ttyd" device, e.g. "LCK..cua0p0" and
+ "LCK..ttyd0p0".
+
+ NOTE: symlinks are not handled in HP-UX.
+
+ Honey DanBer (HDB) UUCP, the basis of many UUCP implementations, has
+ two characteristics:
+
+ a. Lockfiles are kept in /usr/spool/locks/ (usually).
+ b. A lockfile contains the process id (pid) in ASCII, rather than as
+ an int.
+
+ Non-HDB selections assume the lockfile contains the pid in int form
+ (or, more precisely, in PID_T form, where PID_T is either int or pid_t,
+ depending on your system's C library and header files). (b), by the
+ way, is subject to interpretation: the numeric ASCII string may or may
+ not be terminated by a newline, it may or may not have leading spaces
+ (or zeros), and the number of leading spaces or zeros can differ, and
+ the differences can be significant.
+
+ Even if you build the program with the right lockfile option, you can
+ still have problems when you try to open the device. Here are the error
+ messages you can get from SET LINE, and what they mean:
+
+ a. "Timed out, no carrier." This one is not related to lockfiles. It
+ means that you have SET CARRIER ON xx, where xx is the number of
+ seconds to wait for carrier, and carrier did not appear within xx
+ seconds. Solution: SET CARRIER AUTO or OFF.
+ b. "Sorry, access to lock denied." Kermit has been configured to use
+ lockfiles, but (a)the lockfile directory is write-protected against
+ you, or (b) it does not exist. The "access to lock denied" message
+ will tell you the reason. If the directory does not exist, check to
+ make sure Kermit is using the right name. Just because version n of
+ your Unix used a certain lockfile directory is no guarantee that
+ version n.1 does not use a different one. Workaround: ask the
+ system administrator to install a symbolic link from the old name
+ to the new name. Other solutions: (see below)
+ c. "Sorry, access to tty device denied." The tty device that you
+ specified in your SET LINE command is read/write protected against
+ you. Solution: (see below)
+ d. "Sorry, device is in use." The tty device you have specified is
+ currently being used by another user. A prefatory message gives you
+ an "ls -l" listing of the lockfile, which should show the username
+ of the person who created it, plus a message "pid = nnn" to show
+ you the process id of the user's program. Solutions: try another
+ device, wait until the other user is finished, ask the other user
+ to hurry up, or ask the system manager for help.
+ e. "Sorry, can't open connection: reason". The device cannot be opened
+ for some other reason, which is listed.
+ f. "sh: /usr/lib/uucp/acucntrl: not found". This means your Kermit
+ program was built with the -DACUCNTRL switch, but your computer
+ system does not have the BSD 4.3 acucntrl program. Solution:
+ install the acucntrl program if you have it, or rebuild Kermit
+ without the -DACUCNTRL switch.
+
+ There are two solutions for problems (b) and (c), both of which involve
+ intervention by your Unix system administrator (superuser):
+
+ a. Have the superuser change the permission of the lockfile directory
+ and to the tty devices so that everyone on the system has
+ read/write permission.
+
+su% chmod 777 /usr/spool/locks (or whatever the path is)
+su% chmod 666 /dev/ttyXX
+
+ One risk here is that people can write lots of junk into the
+ lockfile directory, delete other people's files in the lockfile
+ directory, and intercept other people's data as it goes in and out
+ of the tty device. The major danger here would be intercepting a
+ privileged password. Of course, any user could write a short,
+ ordinary, unprivileged program to do exactly the same thing if the
+ tty device was world read/writeable. The other risk as that
+ telephone calls are not controlled -- anybody on your system can
+ make them, without having to belong to any particular group, and
+ this could run up your phone bill.
+ b. Use groups to regulate access. Normally the lockfile directory and
+ and the dialout devices will have the same group (such as uucp). If
+ so, then put everybody who's allowed to dial out into that group,
+ and make sure that the lockfile directory and the tty devices have
+ group read AND write permission. Example:
+
+su% chmod 770 /usr/spool/locks (or whatever the path is)
+su% chmod 660 /dev/ttyXX
+
+ User whatever tool is available on your platform to add users to
+ the appropriate group (e.g. edit the /etc/group file).
+ c. Have the superuser change Kermit to run setuid and/or setgid to the
+ owner and/or group of the lockfile directory and the tty devices if
+ necessary), typically uucp (see [334]next section), but NOT root.
+ Example:
+
+su% chown uucp kermit - or - chgrp uucp kermit
+su% chmod u+s kermit (setuid) - or - chmod g+s kermit (setgid)
+
+ and then make sure the lockfile directory, and the tty devices,
+ have owner (setuid) and/or group (setgid) write permission. For
+ example:
+
+su% chmod o+rwx /usr/spool/uucp
+su% chown uucp /dev/ttyXX ; chmod 600 /dev/ttyXX
+
+ In some cases, the owner and group must be distinct; the key point
+ is that read/write access is required to both the UUCP lockfile
+ directory and the tty itself.
+
+ If you make C-Kermit setuid or setgid to root, it refuses to run:
+
+Fatal: C-Kermit setuid to root!
+
+ Example:
+
+crw-r----- 1 uucp uucp 5, 67 Feb 11 06:23 /dev/cua3
+drwxrwxr-x 3 root uucp 1024 Feb 11 06:22 /var/lock
+
+ requires suid uucp to get read/write access on /dev/cua3 and sgid to
+ get read/write access on /var/lock (since you can't set Kermit's uid or
+ gid to root).
+
+ The reason Kermit can't be setuid or setgid to root has to do with
+ the fact that some Unix OS's can't switch user or group IDs in that
+ case. Unfortunately, the prohibition against making Kermit setuid or
+ setgid to root means that Unix C-Kermit can't be used to make rlogin
+ connections by non-root users. (The rlogin port is privileged, which
+ is why the regular rlogin command is setuid root -- which is safe
+ because the rlogin program never has to create or access files like
+ Kermit does.)
+
+ For the lockfile mechanism to achieve its desired purpose -- prevention
+ of access to the same tty device by more than one process at a time --
+ ALL programs on a given computer that open, read or write, and close
+ tty devices must use the SAME lockfile conventions. Unfortunately, this
+ is often not the case. Here is a typical example of how this can go
+ wrong: In SunOS 4.0 and earler, the lockfile directory was
+ /usr/spool/uucp; in 4.1 it was changed to /var/spool/locks in the quest
+ for political correctness. Consequently, any third-party programs (such
+ as C-Kermit) that were not modified to account for this change,
+ recompiled, and reinstalled, did not use the same lockfiles as uucp,
+ tip, etc, and so the entire purpose of the lockfile is defeated.
+
+ What if your Unix system does not have UUCP installed? For example, you
+ have a Unix workstation, and you do not use uucp, cu, or tip, or UUCP
+ was not even supplied with your version of Unix (QNX is an example). In
+ this case, you have two choices:
+
+ a. If there may be more than one person running Kermit at the same
+ time, competing for the same tty device, then create a special
+ lockfile directory just for Kermit, for example, /usr/spool/kermit,
+ and make sure you have read/write access to it. Then add the
+ following to your makefile target CFLAGS, as shown earlier:
+
+-DLOCK_DIR=\\\"/usr/spool/kermit\\\"
+
+ b. If you are the only user on your workstation, and no other
+ processes will ever be competing with Kermit for the dialout tty
+ device, then add -DNOUUCP to your makefile target's CFLAGS and
+ rebuild Kermit.
+
+11. RUNNING UNIX C-KERMIT SETUID OR SETGID
+
+ [ [335]Top ] [ [336]Contents ] [ [337]Next ] [ [338]Previous ]
+
+ Even if you don't intend to run C-Kermit setuid, somebody else might
+ come along and chown and chmod it after it has been built. You should
+ be sure that it is built correctly to run setuid on your system. For
+ POSIX and AT&T Unix based versions, you don't have to do anything
+ special.
+
+ For 4.2 and 4.3 BSD-based Unix versions, you normally need not add
+ anything special to the makefile. The program assumes that the
+ setreuid() and setregid() functions are available, without which we
+ cannot switch back and forth between real and effective uids. If "make"
+ complains that _setreuid or _setregid is/are not defined, add
+ -DNOSETREU to CFLAGS. In this case it is very likely (but not certain)
+ that you cannot protect ttys and lockfiles against people and have them
+ run Kermit setuid.
+
+ If make does not complain about this, you should find out whether your
+ BSD version (4.3 or other systems like SunOS 4.x that claim to include
+ BSD 4.3 compatibility) includes the saved-setuid feature (see long
+ notes under edit 146 in ckc178.upd). If it does, then add -DSAVEDUID to
+ CFLAGS.
+
+ IMPORTANT NOTE: Most Unix system documentation will not give you the
+ required information. To determine whether your Unix system supplies
+ the saved-original-effective-user/group-id feature, use the ckuuid.c
+ program. Read and follow the instructions in the comments at the
+ beginning.
+
+ C-Kermit for 4.4BSD-based systems automatically use sete[ug]id(). See
+ [339]ckutio.c.
+
+ If you have a version of Unix that is not BSD-based, but which supplies
+ the setreuid() and setregid() functions, and these are the only way to
+ switch between real and effective uid, add -DSETREUID to your makefile
+ target.
+
+ WARNING: There are two calls to access() in [340]ckufio.c, by which
+ Kermit checks to see if it can create an output file. These calls
+ will not work correctly when (a)you have installed C-Kermit setuid
+ or setgid on a BSD-based Unix system, and (b) the
+ saved-original-effective-uid/gid feature is not present, and (c) the
+ access() function always checks what it believes to be the real ID
+ rather than the effective ID. This is the case, for example, in
+ Olivetti X/OS and in NeXTSTEP. In such cases, you can force correct
+ operation of access() calls by defining the symbol SW_ACC_ID at
+ compile time in CFLAGS.
+
+ If you have a version of Unix that does not allow a process to switch
+ back and forth between its effective and real user and group ids
+ multiple times, you probably should not attempt to run Kermit setuid,
+ because once having given up its effective uid or gid (which it must do
+ in order to transfer files, fork a shell, etc) it can never get it
+ back, and so it can not use the original effective uid or gid to create
+ or delete uucp lockfiles. In this case, you'll either have to set the
+ permissions on your lockfile directory to make them publicly
+ read/writable, or dispense with locking altogether.
+
+ MORAL: Are you thoroughly sickened and/or frightened by all that you
+ have just read? You should be. What is the real answer? Simple. Serial
+ devices -- such as ttys and magnetic tapes -- in Unix should be opened
+ with exclusive access only, enforced by the Unix kernel. Shared access
+ has no conceivable purpose, legitimate or otherwise, except by
+ privileged system programs such as getty. The original design dates
+ from the late 1960s, when Unix was developed for laboratory use under a
+ philosophy of trust by people within shouting distance of each other --
+ but even then, no useful purpose was served by this particular form of
+ openness; it was probably more of a political statement. Since the
+ emergence of Unix from the laboratory into the commercial market, we
+ have seen every vestige of openness -- but this one -- stripped away.
+ I'd like to see some influential Unix maker take the bold step of
+ making the simple kernel change required to enforce exclusive access to
+ serial devices. (Well, perhaps not so simple when bidirectionality must
+ also be a goal -- but then other OS's like VMS solved this problem
+ decades ago.)
+
+12. CONFIGURING UNIX WORKSTATIONS
+
+ [ [341]Top ] [ [342]Contents ] [ [343]Next ] [ [344]Previous ]
+
+ On desktop workstations that are used by only the user at the console
+ keyboard, C-Kermit is always used in local mode. But as delivered,
+ C-Kermit runs in remote mode by default. To put it in local mode at
+ startup, you can put a SET LINE command in your .mykermrc.
+
+ You can also build C-Kermit to start up in local mode by default. To do
+ this, include the following in the CFLAGS in your makefile target:
+
+-DDFTTY=\\\"/dev/ttyxx\\\"
+
+ where ttyxx is the name of the device you will be using for
+ communications. Presently there is no way of setting the default modem
+ type at compile time, so use this option only for direct lines.
+
+ C-Kermit does not work well on certain workstations if it is not run
+ from within a terminal window. For example, you cannot start C-Kermit
+ on a NeXT by launching it directly from NeXTstep. Similarly for Sun
+ workstations in the Open Windows environment. Run Kermit in a terminal
+ window.
+
+13. BIZARRE BEHAVIOR AT RUNTIME
+
+ [ [345]Top ] [ [346]Contents ] [ [347]Next ] [ [348]Previous ]
+
+ See the "beware file",
+
+ [349]ckubwr.txt, for hints about runtime misbehavior. This section
+ lists some runtime problems that can be cured by rebuilding C-Kermit.
+
+ The program starts, but there is no prompt, and certain operations
+ don't work (you see error messages like "Kermit command error in
+ background execution"). This is because Kermit thinks it is running in
+ the background. See conbgt() in [350]ckutio.c. Try rebuilding Kermit
+ with:
+
+ -DPID_T=pid_t
+
+ added to your CFLAGS. If that doesn't help, find out the actual data
+ type for pids (look in types.h or similar file) and use it in place of
+ "pid_t", for example:
+
+ -DPID_T=short
+
+ Unexplainable and inappropriate error messages ("Sockets not supported
+ on this device", etc) have been traced in at least one case to a lack
+ of agreement between the system header files and the actual kernel.
+ This happened because the GNU C compiler (gcc) was being used. gcc
+ wants to have ANSI-C-compliant header files, and so part of the
+ installation procedure for gcc is (or was) to run a shell script called
+ "fixincludes", which translates the system's header files into a
+ separate set of headers that gcc likes. So far so good. Later, a new
+ version of the operating system is installed and nobody remembers to
+ run fixincludes again. From that point, any program compiled with gcc
+ that makes use of header files (particularly ioctl.h) is very likely to
+ misbehave. Solution: run fixincludes again, or use your system's
+ regular C compiler, libraries, and header files instead of gcc.
+
+14. CRASHES AND CORE DUMPS
+
+ [ [351]Top ] [ [352]Contents ] [ [353]Next ] [ [354]Previous ]
+
+ If C-Kermit consistently dumps core at the beginning of a file
+ transfer, look in SHOW FEATURES for CKREALPATH. If found, rebuild with
+ -DNOREALPATH and see if that fixes the problem (some UNIXes have
+ realpath() but it doesn't work).
+
+ Total failure of the Kermit program can occur because of bad memory
+ references, bad system calls, or problems with dynamic memory
+ allocation. First, try to reproduce the problem with debugging turned
+ on: run Kermit with the -d command-line option (for example, "wermit
+ -d") and then examine the resulting debug.log file. The last entry
+ should be in the vicinity of the crash. In VMS, a crash automatically
+ produces a "stack dump" which shows the routine where the crash occurs.
+ In some versions of Unix, you can get a stack dump with "adb" -- just
+ type "adb wermit core" and then give the command "$c", then Ctrl-D to
+ quit (note: replace "wermit" by "kermit" or by the full pathname of the
+ executable that crashed if it is not in the current directory). Or use
+ gdb to get a backtrace, etc.
+
+ In edit 186, one implementation, UNISYS 5000/95 built with "make
+ sys5r3", has been reported to run out of memory very quickly (e.g.
+ while executing a short initialization file that contains a SET DIAL
+ DIRECTORY command). Debug logs show that malloc calls are failing,
+ reason unknown. For this and any other implementation that gives error
+ messages about "malloc failure" or "memory allocation failure", rebuild
+ the program *without* the -DDYNAMIC CFLAGS definition, for example:
+
+make sys5r3 KFLAGS=-UDYNAMIC
+
+ As of edit 169, C-Kermit includes a malloc() debugging package which
+ you may link with the Kermit program to catch runtime malloc errors.
+ See the makefile entries for sunos41md and nextmd for examples of how
+ to select malloc debugging. Once you have linked Kermit with the malloc
+ debugger, it will halt with an informative message if a malloc-related
+ error occurs and, if possible, dump core. For this reason,
+ malloc-debugging versions of Kermit should be built without the "-s"
+ link option (which removes symbols, preventing analysis of the core
+ dump). You have several ways to track down the malloc error: Analyze
+ the core dump with adb. Or reproduce the problem with "log debug" and
+ then look at the code around the last debug.log entry. If you have gcc,
+ build the program with "-g" added to CFLAGS and then debug it with gdb,
+ e.g.
+
+gdb wermit
+break main
+run
+.. set other breakpoints or watchpoints
+continue
+
+ Watchpoints are especially useful for finding memory leaks, but they
+ make the program run about a thousand times slower than usual, so don't
+ set them until the last possible moment. When a watchpoint is hit, you
+ can use the "where" command to find out which C-Kermit source statement
+ triggered it.
+
+ If you have the Pure Software Inc "Purify" product, see the sunos41cp
+ makefile entry for an example of how to use it to debug C-Kermit.
+
+15. SYSLOGGING
+
+ [ [355]Top ] [ [356]Contents ] [ [357]Next ] [ [358]Previous ]
+
+ "Syslogging" means recording selected information in the system log via
+ the Unix syslog() facility, which is available in most Unix versions.
+ Syslogging is not done unless C-Kermit is started with:
+
+--syslog:n
+
+ on the command-line, where n is a number greater than 0 to indicate the
+ level of syslogging. See [359]Section 4.2 of the [360]IKSD
+ Administrator's Guide for details.
+
+ Obviously you can't depend on users to include --syslog:3 (or whatever)
+ on the command line every time they start C-Kermit, so if you want
+ certain kinds of records to be recorded in the system log, you can
+ build C-Kermit with forced syslogging at the desired level; for
+ example, to record logins and dialouts:
+
+make linux KFLAGS=-DSYSLOGLEVEL=2
+
+ Levels 2 and 3 are the most likely candidates for this treatment. Level
+ 2 forces logging of all successful dialout calls (e.g. for checking
+ against or phone bills), and level 3 records all connections (SET LINE
+ or SET HOST / TELNET / RLOGIN, etc) so you can see who is connecting
+ out from your system, and to where, e.g. for security auditing.
+
+ Level 2 and 3 records are equivalent to those in the connection log;
+ see the [361]C-Kermit 7.0 Supplement) for a detailed description of the
+ connection log.
+
+16. BUILDING SECURE VERSIONS OF C-KERMIT 8.0
+
+ [ [362]Top ] [ [363]Contents ] [ [364]Next ] [ [365]Previous ]
+
+ C-Kermit 7.0 and later may be built with Kerberos(TM) and/or SRP(TM)
+ (Secure Remote Password) and/or SSL/TLS security for strong
+ authentication and encryption of Internet connections. These security
+ methods require external libraries that, in their binary forms, are
+ restricted from export by USA law. See the [366]Kermit Security
+ Reference) for details. C-Kermit binaries themselves are likewise
+ restricted; the C-Kermit binaries that are available for public
+ download on the Internet are not allowed to contain the security
+ options.
+
+ Sample makefile entries are provided for Linux and many other operating
+ systems. A list of secure makefile entries is included in the Makefile.
+ Complete instructions on building C-Kermit 8.0 with MIT Kerberos;
+ Secure Remote Password; and/or OpenSSL can be found in the [367]Kermit
+ Security Reference.
+
+ SSL/TLS and Kerberos builds are increasingly problematic with the
+ "deprecation" of DES. There is code to detect the presence or absence
+ of DES in the OpenSSL builds, but it doesn't always work because
+ sometimes the SSL libraries are present but routines are missing from
+ them.
+
+ * First of all remember that if your SSL and/or Kerberos header files
+ and libraries are not in the default place, you'll need to override
+ the assumed paths. To find out what the default places are type
+ "make show", e.g.:
+
+[~/kermit] make show
+prefix=/usr/local
+srproot=/usr/local
+sslroot=/usr/local
+manroot=/usr/local
+K4LIB=-L/usr/kerberos/lib
+K4INC=-I/usr/kerberos/include
+K5LIB=-L/usr/kerberos/lib
+K5INC=-I/usr/kerberos/include
+SRPLIB=-L/usr/local/lib
+SRPINC=-I/usr/local/include
+SSLLIB=-L/usr/local/ssl/lib
+SSLINC=-I/usr/local/ssl/include
+[~/kermit]
+
+ * You can override any or all of these by putting assignments on the
+ 'make' command line; examples:
+
+make linux+krb5 \
+ "K5INC=-I/usr/include/" \
+ "K5LIB=-L/usr/lib64/"
+
+make solaris9g+ssl \
+ "SSLLIB=-L/opt/openssl-0.9.8q/lib" \
+ "SSLINC=-I/opt/openssl-0.9.8q/include"
+
+ Or by setting and exporting environment variables prior to giving
+ the 'make' command, as in this example in which (after Beta.01 was
+ uploaded) C-Kermit was successfully linked with OpenSSL 1.0.0d,
+ which was installed alongside OpenSSL 0.9.8r on the same computer.
+ Note the use of the '-i' option instead of '-I' to force gcc to
+ include the right header files (thanks to Nelson Beebe for this):
+
+export PATH=/usr/bin:$PATH
+export SSLINC=-isystem/usr/include
+export "SSLLIB=-L/usr/lib -Wl,-rpath,/usr/lib"
+make linux+ssl
+
+ -i is explained in 'man gcc'; there is a change in what -I does
+ that could have ramifications for many makefile targets, not just
+ Kermit. And -Wl and -rpath are explained in 'man ld'; the idea is
+ build a binary from which useful reports can be obtained with ldd.
+ * Building with OpenSSL versions prior to 0.9.7 doesn't work, even
+ though C-Kermit is designed to work with both the old and new
+ versions. This could probably be fixed if anybody cares.
+ * If a Kerberos or SSL build fails at link time because
+ des_ecb3_encrypt, des_random_seed, and/or des_set_odd_parity come
+ up missing, redo the build with -UCK_DES:
+
+make netbsd+krb5+ssl \
+ "K5INC=-I/usr/local/include" \
+ "K5LIB=-L/usr/local/kerblib" KFLAGS=-UCK_DES
+
+ I suppose all the SSL and Kerberos targets could be recoded to
+ figure this out automatically (i.e. that DES is installed but with
+ some entry points missing), but it wouldn't be pretty.
+ * Different Kerberos and OpenSSL distributions can be installed with
+ different options; certain libraries might be missing or named
+ differently (for example, libgssapi vs libgssapi_krb5). Some, but
+ not all, of the C-Kermit makefile targets have been fixed to take
+ some of these variations into account by testing for them, most
+ notably the linux ones, linux+ssl, linux+krb5, and linux+krb5+ssl.
+ Probably every target that builds with OpenSSL or Kerberos needs
+ the same treatment but I won't have time.
+ * Why doesn't C-Kermit just use Autoconf? Mainly because the makefile
+ is full of targets for platforms that don't have Autoconf or any
+ other tool like it. (Another reason is that I've always preferred
+ that Kermit have the least dependencies possible on external
+ toolsets.) Perhaps certain targets could be converted to use them,
+ especially Linux because there are so many variations among
+ distributions and versions. Anybody who wants to make, say, an
+ Autoconf-based Linux target, be my guest, but bear in mind that one
+ Linux target is supposed to work for all versions and distributions
+ of Linux on all platforms. Well, one target for Linux by itself,
+ another for Linux with OpenSSL, another for Linux with Kerberos 5,
+ and another for Linux with Kerberos 5 and OpenSSL. Each of these is
+ supposed to work on any Linux version with any version of
+ Kerberos 5 or OpenSSL.
+
+ Also note that Kerberos support is for the MIT version only, Heimdal
+ and others are not supported (never have been). Of course anybody can
+ pitch in and add or improve support for whatever they want.
+
+17. INSTALLING C-KERMIT AS AN SSH SERVER SUBSYSTEM
+
+ [ [368]Top ] [ [369]Contents ] [ [370]Previous ]
+
+ This requires C-Kermit 8.0.206 or later and an SSH v2 server. If you
+ list C-Kermit as a Subsystem in the SSH v2 server configuration file
+ (as, for example, SFTP is listed), users can make SSH connections
+ direct to a Kermit server as explained here:
+
+[371]http://www.columbia.edu/kermit/skermit.html
+
+ The name and location of the SSH server configuration file depends on
+ your platform, which SSH product(s) you have, etc. C-Kermit itself must
+ be referred to in this file as "kermit-sshsub". On the host, install
+ the C-Kermit 8.0.211 binary in the normal way. Then, in the same
+ directory as the C-Kermit binary, make a symbolic link:
+
+ln -s kermit kermit-sshsub
+
+ (Note: the "make install" makefile target does this for you.) Then in
+ the sshd configuration file, add a line:
+
+Subsystem kermit /some/path/kermit-sshsub
+
+ (where /some/path is the fully specified directory where the symlink
+ is.) This is similar to the line that sets up the SFTP subsystem.
+ Example:
+
+Subsystem sftp /usr/local/libexec/sftp-server
+Subsystem kermit /usr/local/bin/kermit-sshsub
+
+ The mechanics might vary for other SSH servers; "man sshd" for details.
+ The method shown here is used because the OpenSSH server does not
+ permit the subsystem invocation to include command-line options.
+ C-Kermit would have no way of knowing that it should enter Server mode
+ if it were not called by a special name.
+
+ [ [372]Top ] [ [373]Contents ] [ [374]C-Kermit Home ] [ [375]C-Kermit
+ 9.0 Overview ] [ [376]Kermit Home ]
+ __________________________________________________________________
+
+
+ C-Kermit 9.0 Unix Installation Instructions / The Kermit Project /
+ Columbia University / 30 June 2011
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/faq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/ckuins.html#contents
+ 12. http://www.columbia.edu/kermit/ckermit.html
+ 13. http://www.columbia.edu/kermit/index.html
+ 14. http://www.columbia.edu/kermit/ckuins.html
+ 15. http://www.columbia.edu/kermit/ckuins.html#x0
+ 16. http://www.columbia.edu/kermit/ckuins.html#x1
+ 17. http://www.columbia.edu/kermit/ckuins.html#x2
+ 18. http://www.columbia.edu/kermit/ckuins.html#x3
+ 19. http://www.columbia.edu/kermit/ckuins.html#x4
+ 20. http://www.columbia.edu/kermit/ckuins.html#x5
+ 21. http://www.columbia.edu/kermit/ckuins.html#x6
+ 22. http://www.columbia.edu/kermit/ckuins.html#x7
+ 23. http://www.columbia.edu/kermit/ckuins.html#x8
+ 24. http://www.columbia.edu/kermit/ckuins.html#x9
+ 25. http://www.columbia.edu/kermit/ckuins.html#x10
+ 26. http://www.columbia.edu/kermit/ckuins.html#x11
+ 27. http://www.columbia.edu/kermit/ckuins.html#x12
+ 28. http://www.columbia.edu/kermit/ckuins.html#x13
+ 29. http://www.columbia.edu/kermit/ckuins.html#x14
+ 30. http://www.columbia.edu/kermit/ckuins.html#x15
+ 31. http://www.columbia.edu/kermit/ckuins.html#x16
+ 32. http://www.columbia.edu/kermit/ckuins.html#x17
+ 33. http://www.columbia.edu/kermit/ckuins.html#top
+ 34. http://www.columbia.edu/kermit/ckuins.html#contents
+ 35. http://www.columbia.edu/kermit/ckuins.html#x1
+ 36. http://www.columbia.edu/kermit/ckccfg.html
+ 37. http://www.columbia.edu/kermit/ckcbwr.html
+ 38. http://www.columbia.edu/kermit/ckubwr.html
+ 39. http://www.columbia.edu/kermit/ckcplm.html
+ 40. http://www.columbia.edu/kermit/ckuins.html#x2
+ 41. http://www.columbia.edu/kermit/ckuins.html#x3
+ 42. http://www.columbia.edu/kermit/ckuins.html#x4
+ 43. http://www.columbia.edu/kermit/ckuins.html#top
+ 44. http://www.columbia.edu/kermit/ckuins.html#contents
+ 45. http://www.columbia.edu/kermit/ckuins.html#x2
+ 46. http://www.columbia.edu/kermit/ckuins.html#x0
+ 47. ftp://www.columbia.edu/kermit/archives/cku211.tar.Z
+ 48. ftp://www.columbia.edu/kermit/archives/cku211.tar.gz
+ 49. http://kermit.columbia.edu/ftp/archives/cku211.tar.Z
+ 50. http://kermit.columbia.edu/ftp/archives/cku211.tar.gz
+ 51. ftp://www.columbia.edu/kermit/archives/cku211.tar
+ 52. http://kermit.columbia.edu/ftp/archives/cku211.tar
+ 53. http://www.columbia.edu/kermit/ckuins.html#x7
+ 54. http://www.columbia.edu/kermit/ckuins.html#x5
+ 55. http://www.columbia.edu/kermit/ckuins.html#x5
+ 56. http://www.columbia.edu/kermit/ckuins.html#x16
+ 57. http://www.columbia.edu/kermit/ckuins.html#top
+ 58. http://www.columbia.edu/kermit/ckuins.html#contents
+ 59. http://www.columbia.edu/kermit/ckuins.html#x3
+ 60. http://www.columbia.edu/kermit/ckuins.html#x1
+ 61. http://www.columbia.edu/kermit/ckuins.html#x5
+ 62. http://www.columbia.edu/kermit/ckuins.html#X10
+ 63. http://www.columbia.edu/kermit/ckuins.html#x11
+ 64. http://www.columbia.edu/kermit/ckuins.html#x10
+ 65. http://www.columbia.edu/kermit/ckuins.html#x3
+ 66. http://www.columbia.edu/kermit/ck80packages.html
+ 67. http://www.columbia.edu/kermit/ckuins.html#x10
+ 68. http://www.columbia.edu/kermit/ckuins.html#top
+ 69. http://www.columbia.edu/kermit/ckuins.html#contents
+ 70. http://www.columbia.edu/kermit/ckuins.html#x4
+ 71. http://www.columbia.edu/kermit/ckuins.html#x2
+ 72. ftp://www.columbia.edu/kermit/bin/
+ 73. http://www.columbia.edu/kermit/ck80binaries.html
+ 74. http://www.columbia.edu/kermit/ckuins.html#x7
+ 75. http://www.columbia.edu/kermit/ckuins.html#build
+ 76. http://www.columbia.edu/kermit/ckuins.html#x5
+ 77. http://www.columbia.edu/kermit/ckuins.html#x4
+ 78. http://www.columbia.edu/kermit/ckfaq.html#version
+ 79. http://www.columbia.edu/kermit/ckuins.html#x4
+ 80. mailto:kermit@columbia.edu
+ 81. http://www.columbia.edu/kermit/ckuins.html#top
+ 82. http://www.columbia.edu/kermit/ckuins.html#contents
+ 83. http://www.columbia.edu/kermit/ckuins.html#x5
+ 84. http://www.columbia.edu/kermit/ckuins.html#x3
+ 85. http://www.columbia.edu/kermit/ckuins.html#x8
+ 86. http://www.columbia.edu/kermit/ckuins.html#x9
+ 87. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 88. ftp://kermit.columbia.edu/kermit/c-kermit/ckpker.mk
+ 89. ftp://kermit.columbia.edu/kermit/c-kermit/ckubsd.mak
+ 90. http://www.columbia.edu/kermit/ckuins.html#x5
+ 91. mailto:kermit-support@columbia.edu
+ 92. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 93. http://www.columbia.edu/kermit/ckuins.html#x7
+ 94. mailto:kermit-support@columbia.edu
+ 95. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 96. http://www.columbia.edu/kermit/ckuins.html#x5.4
+ 97. http://www.columbia.edu/kermit/ckuins.html#x10
+ 98. http://www.columbia.edu/kermit/ckuins.html#x11
+ 99. http://www.columbia.edu/kermit/ckuins.html#x5
+ 100. http://www.columbia.edu/kermit/iksd.html
+ 101. http://www.columbia.edu/kermit/ckuins.html#top
+ 102. http://www.columbia.edu/kermit/ckuins.html#contents
+ 103. http://www.columbia.edu/kermit/ckuins.html#x4.1
+ 104. http://www.columbia.edu/kermit/ckccfg.html
+ 105. http://www.columbia.edu/kermit/ckuins.html#x4.1
+ 106. http://www.columbia.edu/kermit/ckuins.html#x4.2
+ 107. http://www.columbia.edu/kermit/ckuins.html#x4.3
+ 108. http://www.columbia.edu/kermit/ckuins.html#x4.4
+ 109. http://www.columbia.edu/kermit/ckuins.html#x4.5
+ 110. http://www.columbia.edu/kermit/ckccfg.html
+ 111. http://www.columbia.edu/kermit/ckccfg.html#x8
+ 112. http://www.columbia.edu/kermit/iksd.html
+ 113. http://www.columbia.edu/kermit/iksd.html
+ 114. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 115. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 116. mailto:kermit-support@columbia.edu
+ 117. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 118. http://www.columbia.edu/kermit/ckuins.html#x15
+ 119. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 120. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 121. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 122. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 123. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 124. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 125. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 126. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c
+ 127. mailto:kermit-support@columbia.edu
+ 128. http://www.columbia.edu/kermit/ckuins.html#top
+ 129. http://www.columbia.edu/kermit/ckuins.html#contents
+ 130. http://www.columbia.edu/kermit/ckuins.html#x4
+ 131. http://www.columbia.edu/kermit/ckuins.html#x4.2
+ 132. http://www.columbia.edu/kermit/ckuins.html#x4.0
+ 133. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 134. ftp://kermit.columbia.edu/kermit/c-kermit/ckubwr.txt
+ 135. http://www.columbia.edu/kermit/ckubwr.html
+ 136. ftp://kermit.columbia.edu/kermit/c-kermit/ckwart.c
+ 137. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+ 138. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.c
+ 139. http://www.columbia.edu/kermit/ckuins.html#top
+ 140. http://www.columbia.edu/kermit/ckuins.html#contents
+ 141. http://www.columbia.edu/kermit/ckuins.html#x4
+ 142. http://www.columbia.edu/kermit/ckuins.html#x4.3
+ 143. http://www.columbia.edu/kermit/ckuins.html#x4.1
+ 144. http://www.columbia.edu/kermit/ckuins.html#x5
+ 145. http://www.columbia.edu/kermit/ckuins.html#top
+ 146. http://www.columbia.edu/kermit/ckuins.html#contents
+ 147. http://www.columbia.edu/kermit/ckuins.html#x4
+ 148. http://www.columbia.edu/kermit/ckuins.html#x4.4
+ 149. http://www.columbia.edu/kermit/ckuins.html#x4.2
+ 150. http://www.columbia.edu/kermit/ckuins.html#top
+ 151. http://www.columbia.edu/kermit/ckuins.html#contents
+ 152. http://www.columbia.edu/kermit/ckuins.html#x4
+ 153. http://www.columbia.edu/kermit/ckuins.html#x4.5
+ 154. http://www.columbia.edu/kermit/ckuins.html#x4.3
+ 155. ftp://kermit.columbia.edu/kermit/c-kermit/ckpker.mk
+ 156. http://www.columbia.edu/kermit/ckuins.html#top
+ 157. http://www.columbia.edu/kermit/ckuins.html#contents
+ 158. http://www.columbia.edu/kermit/ckuins.html#x4
+ 159. http://www.columbia.edu/kermit/ckuins.html#x4.4
+ 160. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 161. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 162. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+ 163. http://www.columbia.edu/kermit/ckuins.html#top
+ 164. http://www.columbia.edu/kermit/ckuins.html#contents
+ 165. http://www.columbia.edu/kermit/ckuins.html#x6
+ 166. http://www.columbia.edu/kermit/ckuins.html#x4
+ 167. http://www.columbia.edu/kermit/ckuins.html#x5.1
+ 168. http://www.columbia.edu/kermit/ckuins.html#x5.2
+ 169. http://www.columbia.edu/kermit/ckuins.html#x5.3
+ 170. http://www.columbia.edu/kermit/ckuins.html#x5.4
+ 171. http://www.columbia.edu/kermit/
+ 172. http://www.columbia.edu/kermit/ckuins.html#x5.4
+ 173. http://www.columbia.edu/kermit/ckuins.html#x5.3
+ 174. ftp://kermit.columbia.edu/kermit/c-kermit/COPYING.TXT
+ 175. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit.ini
+ 176. http://www.columbia.edu/kermit/ckuins.html#x5.1
+ 177. ftp://kermit.columbia.edu/kermit/c-kermit/ckermod.ini
+ 178. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit70.txt
+ 179. http://www.columbia.edu/kermit/ck60manual.html
+ 180. http://www.columbia.edu/kermit/ckermit70.html
+ 181. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit80.txt
+ 182. http://www.columbia.edu/kermit/ck60manual.html
+ 183. http://www.columbia.edu/kermit/ckermit80.html
+ 184. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit90.txt
+ 185. http://www.columbia.edu/kermit/ck60manual.html
+ 186. http://www.columbia.edu/kermit/ckermit90.html
+ 187. ftp://kermit.columbia.edu/kermit/c-kermit/ckcbwr.txt
+ 188. http://www.columbia.edu/kermit/ckcbwr.html
+ 189. ftp://kermit.columbia.edu/kermit/c-kermit/ckubwr.txt
+ 190. http://www.columbia.edu/kermit/ckubwr.html
+ 191. ftp://kermit.columbia.edu/kermit/c-kermit/ckuins.txt
+ 192. http://www.columbia.edu/kermit/ckuins.html
+ 193. ftp://kermit.columbia.edu/kermit/c-kermit/ckccfg.txt
+ 194. http://www.columbia.edu/kermit/ckccfg.html
+ 195. ftp://kermit.columbia.edu/kermit/c-kermit/ckcplm.txt
+ 196. http://www.columbia.edu/kermit/ckcplm.html
+ 197. ftp://kermit.columbia.edu/kermit/c-kermit/ca_certs.pem
+ 198. http://www.columbia.edu/kermit/ckuins.html#x16"
+ 199. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 200. http://www.columbia.edu/kermit/ckuins.html#x?
+ 201. http://www.columbia.edu/kermit/ckuins.html#x11
+ 202. http://www.columbia.edu/kermit/ckuins.html#x5.2
+ 203. http://www.columbia.edu/kermit/ckermit.html#download
+ 204. http://www.columbia.edu/kermit/ckbinaries.html
+ 205. http://www.columbia.edu/kermit/ckermit.html#download
+ 206. http://www.columbia.edu/kermit/ckuins.html#top
+ 207. http://www.columbia.edu/kermit/ckuins.html#contents
+ 208. http://www.columbia.edu/kermit/ckuins.html#x7
+ 209. http://www.columbia.edu/kermit/ckuins.html#x5
+ 210. http://www.columbia.edu/kermit/ckuins.html#top
+ 211. http://www.columbia.edu/kermit/ckuins.html#contents
+ 212. http://www.columbia.edu/kermit/ckuins.html#x8
+ 213. http://www.columbia.edu/kermit/ckuins.html#x6
+ 214. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 215. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 216. http://www.columbia.edu/kermit/ckuins.html#x4.0
+ 217. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 218. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 219. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 220. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 221. http://www.columbia.edu/kermit/ckuins.html#x10
+ 222. http://www.columbia.edu/kermit/ckccfg.html#x2
+ 223. http://www.columbia.edu/kermit/ckccfg.html
+ 224. http://www.columbia.edu/kermit/ckuins.html#x4
+ 225. http://www.columbia.edu/kermit/ckuins.html#x10
+ 226. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 227. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 228. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 229. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 230. mailto:kermit-support@columbia.edu
+ 231. http://www.columbia.edu/kermit/ckuins.html#top
+ 232. http://www.columbia.edu/kermit/ckuins.html#contents
+ 233. http://www.columbia.edu/kermit/ckuins.html#x9
+ 234. http://www.columbia.edu/kermit/ckuins.html#x7
+ 235. http://www.columbia.edu/kermit/ckccfg.html
+ 236. http://www.columbia.edu/kermit/ckccfg.html
+ 237. http://www.columbia.edu/kermit/ckuins.html#top
+ 238. http://www.columbia.edu/kermit/ckuins.html#contents
+ 239. http://www.columbia.edu/kermit/ckuins.html#x10
+ 240. http://www.columbia.edu/kermit/ckuins.html#x8
+ 241. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 242. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 243. http://www.columbia.edu/kermit/ckuins.html#x9.1.2
+ 244. http://www.columbia.edu/kermit/ckuins.html#x9.1.3
+ 245. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 246. http://www.columbia.edu/kermit/ckuins.html#x9.3
+ 247. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 248. http://www.columbia.edu/kermit/ckuins.html#x9.5
+ 249. http://www.columbia.edu/kermit/ckuins.html#x9.6
+ 250. http://www.columbia.edu/kermit/ckuins.html#x9.7
+ 251. http://www.columbia.edu/kermit/ckuins.html#x9.8
+ 252. http://www.columbia.edu/kermit/ckuins.html#x9.9
+ 253. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 254. http://www.columbia.edu/kermit/ckuins.html#top
+ 255. http://www.columbia.edu/kermit/ckuins.html#x9
+ 256. http://www.columbia.edu/kermit/ckuins.html#contents
+ 257. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 258. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 259. http://www.columbia.edu/kermit/ckuins.html#x9.1.2
+ 260. http://www.columbia.edu/kermit/ckuins.html#x9.1.3
+ 261. http://www.columbia.edu/kermit/ckuins.html#top
+ 262. http://www.columbia.edu/kermit/ckuins.html#contents
+ 263. http://www.columbia.edu/kermit/ckuins.html#x9
+ 264. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 265. http://www.columbia.edu/kermit/ckuins.html#x9.1.3
+ 266. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 267. http://www.columbia.edu/kermit/ckuins.html#top
+ 268. http://www.columbia.edu/kermit/ckuins.html#contents
+ 269. http://www.columbia.edu/kermit/ckuins.html#x9
+ 270. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 271. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 272. http://www.columbia.edu/kermit/ckuins.html#x9.1.2
+ 273. http://www.opengroup.org/onlinepubs/007904975/
+ 274. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 275. http://www.columbia.edu/kermit/ckuins.html#top
+ 276. http://www.columbia.edu/kermit/ckuins.html#contents
+ 277. http://www.columbia.edu/kermit/ckuins.html#x9
+ 278. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 279. http://www.columbia.edu/kermit/ckuins.html#x9.3
+ 280. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 281. http://www.columbia.edu/kermit/ckuins.html#top
+ 282. http://www.columbia.edu/kermit/ckuins.html#contents
+ 283. http://www.columbia.edu/kermit/ckuins.html#x9
+ 284. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 285. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 286. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 287. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 288. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 289. http://www.columbia.edu/kermit/ckuins.html#top
+ 290. http://www.columbia.edu/kermit/ckuins.html#contents
+ 291. http://www.columbia.edu/kermit/ckuins.html#x9
+ 292. http://www.columbia.edu/kermit/ckuins.html#x9.5
+ 293. http://www.columbia.edu/kermit/ckuins.html#x9.3
+ 294. http://www.columbia.edu/kermit/cable.html
+ 295. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 296. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 297. http://www.columbia.edu/kermit/ckuins.html#top
+ 298. http://www.columbia.edu/kermit/ckuins.html#contents
+ 299. http://www.columbia.edu/kermit/ckuins.html#x9
+ 300. http://www.columbia.edu/kermit/ckuins.html#x9.6
+ 301. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 302. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 303. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+ 304. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 305. http://www.columbia.edu/kermit/ckuins.html#top
+ 306. http://www.columbia.edu/kermit/ckuins.html#contents
+ 307. http://www.columbia.edu/kermit/ckuins.html#x9
+ 308. http://www.columbia.edu/kermit/ckuins.html#x9.7
+ 309. http://www.columbia.edu/kermit/ckuins.html#x9.5
+ 310. http://www.columbia.edu/kermit/ckuins.html#top
+ 311. http://www.columbia.edu/kermit/ckuins.html#contents
+ 312. http://www.columbia.edu/kermit/ckuins.html#x9
+ 313. http://www.columbia.edu/kermit/ckuins.html#x9.8
+ 314. http://www.columbia.edu/kermit/ckuins.html#x9.6
+ 315. http://www.columbia.edu/kermit/ckuins.html#top
+ 316. http://www.columbia.edu/kermit/ckuins.html#contents
+ 317. http://www.columbia.edu/kermit/ckuins.html#x9
+ 318. http://www.columbia.edu/kermit/ckuins.html#x9.9
+ 319. http://www.columbia.edu/kermit/ckuins.html#x9.7
+ 320. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 321. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 322. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 323. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 324. http://www.columbia.edu/kermit/ckuins.html#top
+ 325. http://www.columbia.edu/kermit/ckuins.html#contents
+ 326. http://www.columbia.edu/kermit/ckuins.html#x9
+ 327. http://www.columbia.edu/kermit/ckuins.html#x10
+ 328. http://www.columbia.edu/kermit/ckuins.html#x9.8
+ 329. http://www.columbia.edu/kermit/ckuins.html#top
+ 330. http://www.columbia.edu/kermit/ckuins.html#contents
+ 331. http://www.columbia.edu/kermit/ckuins.html#x11
+ 332. http://www.columbia.edu/kermit/ckuins.html#x9
+ 333. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 334. http://www.columbia.edu/kermit/ckuins.html#x11
+ 335. http://www.columbia.edu/kermit/ckuins.html#top
+ 336. http://www.columbia.edu/kermit/ckuins.html#contents
+ 337. http://www.columbia.edu/kermit/ckuins.html#x12
+ 338. http://www.columbia.edu/kermit/ckuins.html#x10
+ 339. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 340. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 341. http://www.columbia.edu/kermit/ckuins.html#top
+ 342. http://www.columbia.edu/kermit/ckuins.html#contents
+ 343. http://www.columbia.edu/kermit/ckuins.html#x13
+ 344. http://www.columbia.edu/kermit/ckuins.html#x11
+ 345. http://www.columbia.edu/kermit/ckuins.html#top
+ 346. http://www.columbia.edu/kermit/ckuins.html#contents
+ 347. http://www.columbia.edu/kermit/ckuins.html#x14
+ 348. http://www.columbia.edu/kermit/ckuins.html#x12
+ 349. ftp://kermit.columbia.edu/kermit/c-kermit/ckubwr.txt
+ 350. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 351. http://www.columbia.edu/kermit/ckuins.html#top
+ 352. http://www.columbia.edu/kermit/ckuins.html#contents
+ 353. http://www.columbia.edu/kermit/ckuins.html#x15
+ 354. http://www.columbia.edu/kermit/ckuins.html#x13
+ 355. http://www.columbia.edu/kermit/ckuins.html#top
+ 356. http://www.columbia.edu/kermit/ckuins.html#contents
+ 357. http://www.columbia.edu/kermit/ckuins.html#x16
+ 358. http://www.columbia.edu/kermit/ckuins.html#x14
+ 359. http://www.columbia.edu/kermit/uiksd.html#x4.2
+ 360. http://www.columbia.edu/kermit/uiksd.html
+ 361. http://www.columbia.edu/kermit/ckermit2.html
+ 362. http://www.columbia.edu/kermit/ckuins.html#top
+ 363. http://www.columbia.edu/kermit/ckuins.html#contents
+ 364. http://www.columbia.edu/kermit/ckuins.html#x17
+ 365. http://www.columbia.edu/kermit/ckuins.html#x15
+ 366. http://www.columbia.edu/kermit/security.html
+ 367. http://www.columbia.edu/kermit/security80.html
+ 368. http://www.columbia.edu/kermit/ckuins.html#top
+ 369. http://www.columbia.edu/kermit/ckuins.html#contents
+ 370. http://www.columbia.edu/kermit/ckuins.html#x16
+ 371. http://www.columbia.edu/kermit/skermit.html
+ 372. http://www.columbia.edu/kermit/ckuins.html#top
+ 373. http://www.columbia.edu/kermit/ckuins.html#contents
+ 374. http://www.columbia.edu/kermit/ckermit.html
+ 375. http://www.columbia.edu/kermit/ck90updates.html
+ 376. http://www.columbia.edu/kermit/index.html
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuker.nr b/ckermit-9.0.302-build/ckermit-9.0.302/ckuker.nr
new file mode 100644
index 0000000..03b30e7
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuker.nr
@@ -0,0 +1,1831 @@
+.\" @(#) kermit.1 9.0.302 2011/08/20 Columbia University
+.TH KERMIT 1 "JULY 2011" "User Manuals"
+.na
+.SH NAME
+kermit \-
+.B C\(hyKermit 9.0:
+transport\(hy and platform\(hyindependent
+interactive and scriptable communications software.
+.IP
+
+This document is intended to give the beginner sufficient information to
+make basic (if not advanced) use of C\(hyKermit 9.0. Although it might be
+rather long for a Unix manual page, it's still far shorter than the
+C\(hyKermit manual, which should be consulted for advanced topics such as
+customization, character\(hysets, scripting, etc. We also attempt to provide
+a clear structural overview of C\(hyKermit's many capabilities, functional
+areas, states, and modes and their interrelation, that should be helpful to
+beginners and veterans alike, as well as to those upgrading to version 9.0
+from earlier releases.
+.PP
+This document is also available as a Web page at:
+.IP
+http://www.columbia.edu/kermit/ckututor.html
+.SH DESCRIPTION
+C\(hyKermit is an all\(hypurpose communications software package from the Kermit
+Project at Columbia University that:
+.PP
+.nf
+\(bu Is portable to many platforms, Unix and non\(hyUnix alike.
+.br
+\(bu Can make both serial and network connections.
+.br
+\(bu Can conduct interactive terminal sessions over its connection.
+.br
+\(bu Can transfer text or binary files over the same connection.
+.br
+\(bu Can convert character sets in the terminal session.
+.br
+\(bu Can convert character sets during text\(hyfile file transfer.
+.br
+\(bu Is customizable in every aspect of its operation.
+.fi
+.PP
+C\(hyKermit is a modem program, a Telnet client, an Rlogin client, an FTP
+client, an HTTP client, and on selected platforms, also an X.25 client. It
+can make its own secure Internet connections using IETF\(hyapproved security
+methods including Kerberos IV, Kerberos V, SSL/TLS, and SRP and it can also
+make SSH connections through your external SSH client application. It can
+be the far\(hyend file\(hytransfer or client/server partner of your desktop
+Kermit client. It can also accept incoming dialed and network connections.
+It can even be installed as an Internet service on its own standard TCP
+socket, 1649 [RFC2839, RFC2840].
+.PP
+And perhaps most important, everything you can do "by hand" (interactively)
+with C\(hyKermit, can be "scripted" (automated) using its built\(hyin
+cross\(hyplatform transport\(hyindependent script programming language, which
+happens to be identical to its interactive command language.
+.PP
+This manual page offers an overview of C\(hyKermit 9.0 for Unix ("Unix" is an
+operating system family that includes AIX, DG/UX, FreeBSD, HP\(hyUX, IRIX,
+Linux, Mac OS X, NetBSD, OpenBSD, Open Server, Open Unix, QNX, Solaris,
+SunOS, System V R3, System V R4, Tru64 Unix, Unixware, Xenix, and many
+others). For thorough coverage, please consult the published C\(hyKermit
+manual and supplements (see DOCUMENTATION below). For further information
+about C\(hyKermit, Kermit software for other platforms, and Kermit manuals,
+visit the Kermit Project website:
+.PP
+ http://www.columbia.edu/kermit/
+.PP
+This is a longer\(hythan\(hyaverage manual page, and yet it barely scratches the
+surface. Don't be daunted. C\(hyKermit is a large and complex package,
+evolving over decades of practice and experience, but that doesn't mean
+it's hard to learn or use. Its most commonly used functions are explained
+here with pointers to additional information elsewhere.
+.SH SYNOPSIS
+.B kermit [
+.I filename
+.B ] [
+.I options
+.B ] [ {=,\-\-,+}
+.I text
+.B ] ]
+.PP
+or:
+.PP
+.B kermit
+.I URL
+.PP
+If the first command\(hyline argument is the name of a file, interactive\(hymode
+commands are executed from the file. The '=' (or "\-\-") argument tells
+Kermit not to parse the remainder of the command line, but to make the
+words following '=' available as \e%1, \e%2, ... \e%9. The "+" argument is
+like "=" but for use in "kerbang scripts" (explained below). A second
+command\(hyline format allows the one and only argument to be a Telnet, FTP,
+HTTP, or IKSD URL.
+.PP
+Order of execution:
+.TP
+ 1.
+The command file (if any).
+.TP
+.nf
+ 2.
+The initialization file, if any, unless suppressed with \-Y.
+.fi
+.TP
+ 3.
+The customization file (if it is executed by the initialization file).
+.TP
+ 4.
+The command\(hyline URL (if any, and if so, execution stops here).
+.TP
+ 5.
+Command\(hyline options (if any).
+.TP
+ 6.
+Interactive commands.
+.PP
+Some command\(hyline options can cause actions (such as \-s to send a file);
+others just set parameters. If any action options are included on the
+command line, Kermit exits when finished unless also given the \-S ("stay")
+option. If no action options are given, no initialization or command files
+contained an EXIT or QUIT command, and no fatal errors occurred, Kermit
+issues its prompt and waits for you to type commands.
+.IP
+Bear in mind that C\(hyKermit can be built with selected features
+disabled, and also that certain features are not available on all
+platforms. For example, C\(hyKermit can't be built with TCP/IP
+support on a platform that does not have TCP/IP header files and
+libraries (and even if Kermit does include TCP/IP support, it
+can't be used to make TCP/IP connections on a computer that does
+not have a TCP/IP stack installed). If your version of
+C\(hyKermit lacks a feature mentioned here, use its SHOW FEATURES command to
+see what might have been excluded.
+.PP
+C\(hyKermit has three kinds of commands: regular single\(hyletter command\(hyline
+options, extended\(hyformat command\(hyline options, and interactive commands.
+.PP
+Like most Unix commands, C\(hyKermit can be be given options on the command
+line. But C\(hyKermit also can be used interactively by giving it commands
+composed of words, which are more intuitive than cryptic command\(hyline
+options, and more flexible too. In other words, you don't have to use
+C\(hyKermit's command\(hyline options, but they are available if you want to. (By
+the same token, you don't have to use its interactive commands either \(hy\(hy
+you can use either or both in any combination.)
+.PP
+C\(hyKermit is generally installed in the PATH as "kermit", and therefore is
+invoked by typing the word "kermit" (lowercase) at the shell prompt, and
+then pressing the Return or Enter key. If you wish to include command\(hyline
+options, put them after the word "kermit" but before pressing Return or
+Enter, separated by spaces, for example:
+.PP
+ $ kermit \-s ckermit.tar.gz
+.PP
+('$' is the shell prompt; "kermit \-s ckermit.tar.gz" is what you type,
+followed by Return or Enter.)
+.SH OPTIONS
+Here is a list of C\(hyKermit's single\(hyletter command\(hyline options, which
+start with a single dash (\-), in ASCII ("alphabetical") order. Alphabetic
+case is significant (\-A is not the same as \-a). Action options are
+tagged "ACTION".
+.TP
+\-0
+(digit zero) 100% transparent Connect state for
+"in\(hythe\(hymiddle" operation: 8 bits, no parity, no
+escape character, everything passes through.
+.TP
+\-8
+(digit eight) Connection is 8\(hybit clean (this is the
+default in C\(hyKermit 8.0 and later). Equivalent to the EIGHTBIT
+command, which in turn is a shortcut for SET TERMINAL
+BYTESIZE 8, SET COMMAND BYTESIZE 8, SET PARITY NONE.
+.TP
+\-9 arg
+(digit nine) Make a connection to an FTP server.
+Equivalent to the FTP OPEN command.
+Argument: IP\(hyaddress\(hyor\(hyhostname[:optional\(hyTCP\(hyport].
+NOTE: C\(hyKermit also has a separate FTP command\(hyline
+personality, with regular FTP\(hylike command\(hyline
+syntax. More about this below.
+.TP
+\-A
+Kermit is to be started as an Internet service (IKSD)
+(only from inetd.conf).
+.TP
+\-B
+Kermit is running in Batch or Background (no
+controlling terminal). To be used in case Kermit
+doesn't automatically sense its background status.
+Equivalent to the SET BACKGROUND ON command.
+.TP
+\-C arg
+Interactive\(hymode Commands to be executed.
+Argument: Commands separated by commas, list in
+doublequotes.
+.TP
+\-D arg
+Delay before starting to send in Remote mode.
+Equivalent to the SET DELAY command.
+Argument: Number of seconds.
+.TP
+\-E
+Exit automatically when connection closes. Equivalent
+to SET EXIT ON\-DISCONNECT ON.
+.TP
+\-F arg
+Use an open TCP connection.
+Argument: Numeric file descriptor of open TCP
+connection.
+Also see: \-j, \-J.
+.TP
+\-G arg
+(ACTION) Get file(s) from server, send contents to standard
+output, which normally would be piped to another
+process.
+Argument: Remote file specification, in quotes if it
+contains metacharacters.
+Also see: \-g, \-k.
+.TP
+\-H
+Suppress program startup Herald and greeting.
+.TP
+\-I
+Tell Kermit it has a reliable connection, to force streaming to be used where
+it normally would not be. Equivalent to the SET RELIABLE ON command.
+.TP
+\-J arg
+(ACTION) "Be like Telnet." Like \-j but implies \-E. Argument: IP
+hostname/address optionally followed by service. NOTE: C\(hyKermit also has a
+separate Telnet command\(hyline personality, with regular Telnet\(hylike
+command\(hyline syntax. More about this below.
+.TP
+\-L
+Recursive directory descent for files in \-s option.
+.TP
+\-M arg
+My user name (for use with Telnet, Rlogin, FTP, etc).
+Equivalent to the SET LOGIN USER command.
+Argument: Username string.
+.TP
+\-O
+(ACTION) (Uppercase letter O) Be a server for One command only.
+Also see: \-x.
+.TP
+\-P
+Don't convert file (Path) names of transferred files.
+Equivalent to SET FILE NAMES LITERAL.
+.TP
+\-Q
+Quick Kermit protocol settings. Equivalent to the FAST
+command. This is the default in C\(hyKermit 7.0 and later.
+.TP
+\-R
+Remote\(hyonly (this just makes IF REMOTE true).
+.TP
+\-S
+Stay (enter command parser after action options).
+.TP
+\-T
+Force Text mode for file transfer; implies \-V.
+Equivalent to SET TRANSFER MODE MANUAL, SET FILE TYPE TEXT.
+.TP
+\-V
+Disable automatic per\(hyfile text/binary switching.
+Equivalent to SET TRANSFER MODE MANUAL.
+.TP
+\-Y
+Skip (don't execute) the initialization file.
+.TP
+\-a arg
+As\(hyname for file(s) in \-s, \-r, or \-g.
+Argument: As\(hyname string (alternative filename). When
+receiving files, this can be a directory name.
+.TP
+\-b arg
+Speed for serial device. Equivalent to SET SPEED.
+Argument: Numeric Bits per second for serial
+connections.
+.TP
+\-c
+(ACTION) Enter Connect state before transferring files.
+.TP
+\-d
+Create a debug.log file with detailed debugging
+information (a second \-d adds timestamps). Equivalent
+to LOG DEBUG but takes effect sooner.
+.TP
+\-e arg
+Maximum length for incoming Kermit file\(hytransfer
+packets. Equivalent to SET RECEIVE PACKET\-LENGTH.
+Argument: Length in bytes.
+.TP
+\-f
+(ACTION) Send a FINISH command to a Kermit server.
+.TP
+\-g arg
+Get file(s) from a Kermit server.
+Argument: File specification on other computer, in
+quotes if it contains metacharacters. Equivalent to
+GET. Also see: \-a, \-G, \-r.
+.TP
+\-h
+(ACTION) Print Help text for single\(hyletter command\(hyline options
+(pipe thru 'more' to prevent scrolling).
+.TP
+\-i
+Force binary (Image) mode for file transfer; implies
+\-V. Equivalent to SET TRANSFER MODE MANUAL, SET FILE
+TYPE BINARY.
+.TP
+\-j arg
+Make a TCP/IP connection.
+Argument: IP host name/address and optional service
+name or number. Equivalent to the TELNET command.
+Also see: \-J, \-F.
+.TP
+\-k
+(ACTION) Receive file(s) to standard output, which normally
+would be piped to another process.
+Also see: \-r, \-G.
+.TP
+\-l arg
+(Lowercase letter L) Make a connection on the given
+serial communications device. Equivalent to the SET
+LINE (SET PORT) command.
+Argument: Serial device name, e.g. /dev/ttyS0.
+.TP
+\-m arg
+Modem type for use with the \-l device. Equivalent to
+the SET MODEM TYPE command.
+Argument: Modem name as in SET MODEM TYPE command,
+e.g. "usrobotics".
+.TP
+\-n
+(ACTION) Enter Connect state after transferring files (historical).
+.TP
+\-p arg
+Parity. Equivalent to the SET PARITY command.
+Argument: One of the following: e(ven), o(dd), m(ark),
+n(one), s(pace).
+.TP
+\-q
+Quiet (suppress most messages). Equivalent to SET QUIET ON.
+.TP
+\-r
+(ACTION) Receive file(s). Equivalent to the RECEIVE command.
+Argument: (none, but see \-a)
+.TP
+\-s arg
+Send file(s).
+Argument: One or more local file specifications.
+Equivalent to the SEND command.
+Also see: \-a.
+.TP
+\-t
+(Historical) Xon (Ctrl\-Q) Turnaround character for
+half\(hyduplex connections (used on serial linemode
+connections to old mainframes). Equivalent to SET
+DUPLEX HALF, SET HANDSHAKE XON.
+.TP
+\-v arg
+Window size for Kermit protocol (ignored when
+streaming). Equivalanet to SET WINDOW\-SIZE.
+Argument: Number, 1 to 32.
+.TP
+\-w
+Incoming files Write over existing files. Equivalent
+to SET FILE COLLISION OVERWRITE.
+.TP
+\-x
+(ACTION) Enter server mode. Equivalent to the SERVER command.
+Also see: \-O.
+.TP
+\-y arg
+Alternative initialization file.
+Argument: Filename.
+.TP
+\-z
+Force foreground behavior. To be used in case Kermit
+doesn't automatically sense its foreground status.
+Equivalent to the SET BACKGROUND OFF command.
+.PP
+Extended command\(hyline options (necessary because single\(hyletter ones are
+about used up) start with two dashes (\-\-), with words rather than single
+letters as option names. If an extended option takes an argument, it is
+separated from the option word by a colon (:). Extended options include:
+
+.TP
+ \-\-bannerfile:filename
+File to display upon startup or IKSD login.
+.TP
+ \-\-cdfile:filename
+File to be sent for display to the client when
+server changes directory (filename is relative to
+the changed\(hyto directory).
+.TP
+ \-\-cdmessage:{on,off}
+Enable/disable the server CD message feature.
+.TP
+ \-\-help
+Prints usage message for extended options.
+.TP
+ \-\-helpfile:filename
+Designates a file containing custom text to
+replace the top\(hylevel HELP command.
+.TP
+ \-\-nointerrupts
+Disables keyboard interrupts.
+.TP
+ \-\-noperms
+Disables the Kermit protocol file Permissions
+attribute, to prevent transmission of file
+permissions (protection) from sender to receiver.
+.TP
+ \-\-version
+(ACTION) C\(hyKermit prints its version number.
+.PP
+Plus several other IKSD\(hyOnly options described at:
+.PP
+ http://www.columbia.edu/kermit/iksd.html
+.PP
+See the file\(hytransfer section for examples of command\(hyline invocation.
+.SH COMMAND LANGUAGE
+C\(hyKermit's interactive command language is the subject of a 622\(hypage book
+and another several hundred pages of updates, far too much for a manual
+page. But it's not hard to get started. At the shell prompt, just type
+"kermit" to get C\(hyKermit's interactive command prompt:
+.PP
+.nf
+ $ kermit
+ (/current/directory) C\-Kermit>
+.fi
+.PP
+Begin by typing "help" (and then press the Return or Enter key) for a
+top\(hylevel overview, read it, and go from there. Your second command should
+probably be "intro" (introduction). Note the prompt shows your current
+directory (unless you tell Kermit to prompt you with something else).
+.PP
+Interactive commands are composed mainly of regular English words, usually
+in the form of imperative sentences, such as:
+.PP
+ send oofa.txt
+.PP
+which tells Kermit to send (transfer) the file whose name is oofa.txt, or:
+.PP
+ set transfer mode automatic
+.PP
+which sets Kermit's "transfer mode" to "automatic" (whatever that means).
+.PP
+While typing commands, you can abbreviate, ask for help (by pressing the
+"?" key anywhere in a command), complete keywords or filenames (with the
+Tab or Esc key), and edit your typing with Backspace or Delete, Ctrl\-W,
+Ctrl\-U, etc. You can also recall previous commands, save your command
+history, and who knows what else. Give the INTRO command for details.
+.PP
+C\(hyKermit has hundreds of commands, and they can be issued in infinite
+variety and combinations, including commands for:
+.nf
+.PP
+\(bu Making connections (SET LINE, DIAL, TELNET, SSH, FTP, ...)
+.br
+\(bu Breaking connections (HANGUP, CLOSE)
+.br
+\(bu Transferring files (SEND, GET, RECEIVE, MOVE, RESEND, ...)
+.br
+\(bu Establishing preferences (SET)
+.br
+\(bu Displaying preferences (SHOW)
+.br
+\(bu Managing local files (CD, DELETE, MKDIR, DIR, RENAME, TYPE, ...)
+.br
+\(bu Managing remote files (RCD, RDEL, RMKDIR, RDIR, ...)
+.br
+\(bu Using local files (FOPEN, FCLOSE, FREAD, FWRITE)
+.br
+\(bu Programming (TAKE, DEFINE, IF, FOR, WHILE, SWITCH, DECLARE, ...)
+.br
+\(bu Interacting with the user (ECHO, ASK, ...)
+.br
+\(bu Interacting with a remote computer (INPUT, OUTPUT, ...)
+.br
+\(bu Interacting with local programs (RUN, EXEC, PTY, ...)
+.br
+\(bu Logging things (LOG SESSION, LOG PACKETS, LOG DEBUG, ...)
+.PP
+.fi
+And of course QUIT or EXIT to get out and HELP to get help, and for
+programmers: loops, decision making, variables, arrays, associative arrays,
+integer and floating point arithmetic, macros, built\(hyin and user\(hydefined
+functions, string manipulation, pattern matching, block structure, scoping,
+recursion, and all the rest. To get a list of all C\(hyKermit's commands, type
+a question mark (?) at the prompt. To get a description of any command,
+type HELP followed by the name of the command, for example:
+.PP
+ help send
+.PP
+The command interruption character is Ctrl\-C (hold down the Ctrl key and
+press the C key).
+.PP
+The command language "escape character", used to introduce variable names,
+function invocations, and so on, is backslash (\). If you need to include a
+literal backslash in a command, type two of them, e.g.:
+.PP
+ get c:\ek95\ek95custom.ini
+.SS Command Files, Macros, and Scripts
+A file containing Kermit commands is called a Kermit command file or Kermit
+script. It can be executed with Kermit's TAKE command:
+.PP
+ (/current/dir) C\-Kermit> take commandfile
+.PP
+(where "commandfile" is the name of the command file). Please don't pipe a
+command file into Kermit's standard input (which might or might not work);
+if you have Kermit commands in a file, tell Kermit to TAKE the file.
+.PP
+In Unix only, a Kermit command file can also be executed directly by
+including a "kerbang" line as the first line of the file:
+.PP
+ #!/usr/local/bin/kermit +
+.PP
+That is, a top line that starts with "#!", followed immediately by the full
+path of the Kermit executable, and then, if the Kermit script is to be
+given arguments on the command line, a space and a plus sign. The script
+file must also have execute permission:
+.PP
+ chmod +x commandfile
+.PP
+Except for the " +" part, this is exactly the same as you would do for a
+shell script, a Perl script, etc. Here's a simple but useless example
+script that regurgitates its arguments (up to three of them):
+.PP
+ #!/usr/local/bin/kermit +
+ if defined \e%1 echo "Argument 1: \e%1"
+ if defined \e%2 echo "Argument 2: \e%2"
+ if defined \e%3 echo "Argument 3: \e%3"
+ if defined \e%4 echo "etc..."
+ exit
+.PP
+If this file is stored in your current directory as "commandfile", then:
+.PP
+ ./commandfile one two three four five
+.PP
+prints:
+.PP
+ Argument 1: one
+ Argument 2: two
+ Argument 3: three
+ etc...
+.PP
+This illustrates the basic structure of a standalone Kermit script: the
+"kerbang line", then some commands. It should end with "exit" unless you
+want the Kermit prompt to appear when it is finished. \e%1 is the first
+argument, \e%2 the second, and so on.
+.PP
+You can also create your own commands by defining named macros composed of
+other Kermit commands (or macros). For example:
+.PP
+.nf
+ define mydelete {
+ local trash
+ assign trash \ev(home)trashcan/
+ if not defined \e%1 end 1 "Delete what?"
+ if wild \e%1 {
+ end 1 "Deleting multiple files is too scary"
+ }
+ if not exist \e%1 end 1 "I can't find \e%1"
+ if not directory \em(trash) {
+ mkdir \em(trash)
+ if fail end 1 "No trash can"
+ }
+ rename /list \e%1 \em(trash)
+ }
+ define myundelete {
+ local trash
+ assign trash \ev(home)trashcan/
+ if not defined \e%1 end 1 "Undelete what?"
+ if wild \e%1 {
+ end 1 "Undeleting multiple files is too hard"
+ }
+ if not directory \em(trash) end 1 "No trash can"
+ if not exist \em(trash)\e%1 {
+ end 1 "I can't find \e%1 in trash can"
+ }
+ rename /list \em(trash)\e%1 .
+ }
+.PP
+.fi
+These sample macros are not exactly production quality (they don't handle
+filenames that include path segments, they don't handle multiple files,
+etc), but you get the idea: you can pass arguments to macros, and they can
+check them and make other kinds of decisions. If you put the above lines
+into your initialization or customization file (explained below), you'll
+have MYDELETE and MYUNDELETE commands available every time you start
+Kermit, at least as long as you don't suppress execution of the
+initialization file. (Exercise for the reader: Make these macros generally
+useful: remove limitations, add trashcan display, browsing, emptying, etc.)
+.PP
+Kerbang scripts execute without the initialization file. This to keep them
+portable and also to make them start faster. If you want to write Kerbang
+scripts that depend on the initialization file, include the command
+.PP
+ take \ev(home).kermrc
+.PP
+at the desired spot in the script. By the way, \ev(xxx) is a built\(hyin
+variable (xxx is the variable name, "home" in this case). To see what
+built\(hyin variables are available, type "show variables" at the C\(hyKermit
+prompt. To see what else you can show, type "show ?". \em(xxx) is a user
+defined variable (strictly speaking, it is a macro used as a variable).
+.SS Command List
+C\(hyKermit has more than 200 top\(hylevel commands, and some of these, such as
+SET, branch off into hundreds of subcommands of their own, so it's not
+practical to describe them all here. Instead, here's a concise list of the
+most commonly used top\(hylevel commands, grouped by category. To learn about
+each command, type "help" followed by the command name, e.g. "help set".
+Terms such as Command state and Connect state are explained in subsequent
+sections.
+.PP
+Optional fields are shown in [ brackets ]. "filename" means the
+name of a single file. filespec means a file specification that is allowed
+to contain wildcard characters like '*' to match groups of files. options
+are (optional) switches like /PAGE, /NOPAGE, /QUIET, etc, listed in the
+HELP text for each command. Example:
+.PP
+.nf
+ send /recursive /larger:10000 /after:\-1week /except:*.txt *
+.fi
+.PP
+which can be read as "send all the files in this directory and all the ones
+underneath it that are larger than 10000 bytes, no more than one week old,
+and whose names don't end with ".txt".
+.SS
+Basic Commands
+.RS
+.TP
+HELP
+Requests top\(hylevel help.
+.TP
+HELP command
+Requests help about the given command.
+.TP
+INTRODUCTION
+Requests a brief introduction to C\(hyKermit.
+.TP
+LICENSE
+Displays the C\(hyKermit software copyright and license.
+.TP
+VERSION
+Displays C\(hyKermit's version number.
+.TP
+EXIT [ number ]
+Exits from Kermit with the given
+status code. Synonyms: QUIT, E, Q.
+.TP
+TAKE filename [ parameters... ]
+Executes commands from the given
+.TP
+LOG item [ filename ]
+Keeps a log of the given item in the given file.
+.TP
+[ DO ] macro [ parameters... ]
+Executes commands from the given macro.
+.TP
+SET parameter value
+Sets the given parameter to the given value.
+.TP
+SHOW category
+Shows settings in a given category.
+.TP
+STATUS
+Tells whether previous command succeeded or failed.
+.TP
+DATE [ date\(hyand/or\(hytime ]
+Shows current date\(hytime or interprets given date\(hytime.
+.TP
+RUN [ extern\(hycommand [ parameters... ]
+Runs the given external command. Synonym: !.
+.TP
+EXEC [ extern\(hycommand [ params... ]
+Kermit overlays itself with the given command.
+.TP
+SUSPEND
+Stops Kermit and puts it in the background. Synonym: Z.
+.RE
+.SS
+Local File Management
+.RS
+.TP
+TYPE [ options ] filename
+Displays the contents of the given file.
+.TP
+MORE [ options ] filename
+Equivalent to TYPE /PAGE (pause after each screenful).
+.TP
+CAT [ options ] filename
+Equivalent to TYPE /NOPAGE.
+.TP
+HEAD [ options ] filename
+Displays the first few lines of a given file.
+.TP
+TAIL [ options ] filename
+Displays the last few lines of a given file.
+.TP
+GREP [ options ] pattern filespec
+Displays lines from files that match
+the pattern. Synonym: FIND.
+.TP
+DIRECTORY [ options ] [filespec ]
+Lists files (built\(hyin, many options).
+.TP
+LS [ options ] [ filespec ]
+Lists files (runs external "ls" command).
+.TP
+DELETE [ options ] [ filespec ]
+Deletes files. Synonym: RM.
+.TP
+PURGE [ options ] [ filespec ]
+Removes backup (*.~n~) files.
+.TP
+COPY [ options ] [ filespecs... ]
+Copies files. Synonym: CP.
+.TP
+RENAME [ options ] [ filespecs... ]
+Renames files. Synonym: MV.
+.TP
+CHMOD [ options ] [ filespecs... ]
+Changes permissions of files.
+.TP
+TRANSLATE filename charsets [ filename ]
+Converts file's character set. Synonym: XLATE.
+.TP
+CD
+Changes your working directory to your home directory.
+.TP
+CD directory
+Changes your working directory to the one given.
+.TP
+CDUP
+Changes your working directory one level up.
+.TP
+PWD
+Displays your working directory.
+.TP
+BACK
+Returns to your previous working directory.
+.TP
+MKDIR [ directory ]
+Creates a directory.
+.TP
+RMDIR [ directory ]
+Removes a directory.
+.RE
+.SS
+Making Connections
+.RS
+.TP
+SET LINE [ options ] devicename
+Opens the named serial port. Synonym: SET PORT.
+.TP
+OPEN LINE [ options ] devicename
+Same as SET LINE. Synonym: OPEN PORT.
+.TP
+SET MODEM TYPE [ name ]
+Tells Kermit what kind of modem is on the port.
+.TP
+DIAL [ number ]
+Tells Kermit to dial the given phone number with the modem.
+.TP
+REDIAL
+Redials the most recently dialed phone number.
+.TP
+ANSWER
+Waits for and answers an incoming call on the modem.
+.TP
+AUTHENTICATE [ parameters... ]
+Performs secure authentication on a TCP/IP connection.
+.TP
+SET NETWORK TYPE { TCP/IP, X.25, ... }
+Selects network type for subsequent SET HOST commands.
+.TP
+SET HOST [ options ] host [ port ]
+Opens a network connection to the given host and port.
+.TP
+SET HOST * port
+Waits for an incoming TCP/IP connection on the given port.
+.TP
+TELNET [ options ] host
+Opens a Telnet connection to the host and enters Connect state.
+.TP
+RLOGIN [ options ] host
+Opens an Rlogin connection to the host and enters Connect state.
+.TP
+IKSD [ options ] host
+Opens a connection to an Internet Kermit Service.
+.TP
+SSH [ options ] host
+Opens an SSH connection to the host and enters Connect state.
+.TP
+FTP OPEN host [ options ]
+Opens an FTP connection to the host.
+.TP
+HTTP [ options ] OPEN host
+Opens an HTTP connection to the host.
+.TP
+PTY external\(hycommand
+Runs the command on a pseudoterminal as if it were a connection.
+.TP
+PIPE external\(hycommand
+Runs the command through a pipe as if it were a connection.
+.RE
+.SS
+Using Connections
+.RS
+.TP
+CONNECT [ options ]
+Enters Connect (terminal) state. Synonym: C.
+.TP
+REDIRECT command
+Redirects the given external command over the connection.
+.TP
+TELOPT command
+Sends a Telnet protocol command (Telnet connections only).
+.TP
+Ctrl\-\eC
+"Escapes back" from Connect state to Command state.
+.TP
+Ctrl\-\eB
+(In Connect state) Sends a BREAK signal (serial or Telnet).
+.TP
+Ctrl\-\e!
+(In Connect state) Enters inferior shell; "exit" to return.
+.TP
+Ctrl\-\e?
+(In Connect state) Shows a menu of other escape\(hylevel options.
+.TP
+Ctrl\-\eCtrl\-\e
+(In Connect state) Type two
+Ctrl\-Backslashes to send one of them.
+.TP
+SET ESCAPE [ character ]
+Changes Kermit's Connect\(hystate escape character.
+.RE
+.SS
+Closing Connections
+.RS
+.TP
+HANGUP
+Hangs up the currently open
+serial\(hyport or network connection.
+.TP
+CLOSE
+Closes the currently open
+serial\(hyport or network connection.
+.TP
+SET LINE (with no devicename)
+Closes the currently open
+serial\(hyport or network connection.
+.TP
+SET HOST (with no hostname)
+Closes the currently open serial\(hyport or network connection.
+.TP
+FTP CLOSE
+Closes the currently open FTP connection.
+.TP
+HTTP CLOSE
+Closes the currently open HTTP connection.
+.TP
+EXIT
+Also closes all connections. Synonym: QUIT.
+.TP
+SET EXIT WARNING OFF
+Suppresses warning about open connections on exit or close.
+.RE
+.SS
+File Transfer
+.RS
+.TP
+SEND [ options ] filename [ as\(hyname ]
+Sends the given file. Synonym: S.
+.TP
+SEND [ options ] filespec
+Sends all files that match.
+.TP
+RESEND [ options ] filespec
+Resumes an interrupted SEND from the point of failure.
+.TP
+RECEIVE [ options ] [ as\(hyname ]
+Waits passively for files to arrive. Synonym: R.
+.TP
+LOG TRANSACTIONS [ filename ]
+Keeps a record of file transfers.
+.TP
+FAST
+Use fast file\(hytransfer settings (default).
+.TP
+CAUTIOUS
+Use cautious and less fast file\(hytransfer settings.
+.TP
+ROBUST
+Use ultra\(hyconservative and slow file\(hytransfer settings.
+.TP
+STATISTICS [ options ]
+Gives statistics about the most recent file transfer.
+.TP
+WHERE
+After transfer: "Where did my files go?".
+.TP
+TRANSMIT [ options ] [ofilename ]
+Sends file without protocol. Synonym: XMIT.
+.TP
+LOG SESSION [ filename ]
+Captures remote text or files without protocol.
+.TP
+SET PROTOCOL [ name... ]
+Tells Kermit to use an external file\(hytransfer protocol.
+.TP
+FTP { PUT, MPUT, GET, MGET, ... }
+FTP client commands.
+.TP
+HTTP { PUT, GET, HEAD, POST, ... }
+HTTP client commands.
+.RE
+.SS
+Kermit Server
+.RS
+.TP
+ENABLE, DISABLE
+Controls which server features can be used by clients.
+.TP
+SET SERVER
+Sets parameters prior to entering Server state.
+.TP
+SERVER
+Enters Server state.
+.RE
+.SS
+Client of Kermit or FTP Server
+.RS
+.TP
+[ REMOTE ] LOGIN [ user password ]
+Logs in to a Kermit server or IKSD that requires it.
+.TP
+[ REMOTE ] LOGOUT
+Logs out from a Kermit server or IKSD.
+.TP
+SEND [ options ] filename [ as\(hyname ]
+Sends the given file to the server. Synonyms: S, PUT.
+.TP
+SEND [ options ] filespec
+Sends all files that match.
+.TP
+RESEND [ options ] filespec
+Resumes an interrupted SEND from the point of failure.
+.TP
+GET [ options ] remote\(hyfilespec
+Asks the server to send the given files. Synonym: G.
+.TP
+REGET [ options ] remote\(hyfilespec
+Resumes an interrupted GET from the point of failure.
+.TP
+REMOTE CD [ directory ]
+Asks server to change its working
+directory. Synonym: RCD.
+.TP
+REMOTE PWD [ directory ]
+Asks server to display its working directory. Synonym: RPWD.
+.TP
+REMOTE DIRECTORY [ filespec... ]
+Asks server to send a directory listing. Synonym: RDIR.
+.TP
+REMOTE DELETE [ filespec... ]
+Asks server to delete files. Synonym: RDEL.
+.TP
+REMOTE [ command... ]
+(Many other commands: "remote ?" for a list).
+.TP
+MAIL [ options ] filespec
+Sends file(s) to be delivered as e\(hymail (Kermit only).
+.TP
+FINISH
+Asks the server to exit server state (Kermit only).
+.TP
+BYE
+Asks the server to log out and close the connection.
+.RE
+.SS
+Script Programming
+.PP
+.RS
+DEFINE, DECLARE, UNDEFINE, UNDECLARE, ASSIGN, EVALUATE, SEXPRESSION,
+ARRAY, SORT, INPUT, OUTPUT, IF, FOR, WHILE, SWITCH, GOTO, ECHO, ASK,
+GETC, GETOK, ASSERT, WAIT, SLEEP, FOPEN, FREAD, FWRITE, FCLOSE, STOP,
+END, RETURN, LEARN, SHIFT, TRACE, VOID, INCREMENT, DECREMENT, ... For
+these and many more you'll need to consult the manual and supplements,
+and/or visit the Kermit Script Library, which also includes a brief
+tutorial. Hint: HELP LEARN to find out how to get Kermit to write
+simple scripts for you.
+.RE
+.PP
+Many of Kermit's commands have synonyms, variants, relatives, and so on.
+For example, MSEND is a version of SEND that accepts a list of file
+specifications to be sent, rather than just one file specification, and
+MPUT is a synonym of MSEND. MOVE means to SEND and then DELETE the source
+file if successful. MMOVE is like MOVE, but accepts a list of filespecs,
+and so on. These are described in the full documentation.
+.PP
+Use question mark to feel your way through an unfamiliar command, as in
+this example:
+.PP
+.nf
+ C\-Kermit> remote ? One of the following:
+ assign directory kermit print rmdir
+ cd exit login pwd set
+ copy help logout query space
+ delete host mkdir rename type
+ C\-Kermit> remote set ? One of the following:
+ attributes file retry transfer
+ block\-check receive server window
+ C\-Kermit> remote set file ? One of the following:
+ character\-set incomplete record\-length
+ collision names type
+ C\-Kermit> remote set file names ? One of the following:
+ converted literal
+ C\-Kermit> remote set file names literal
+ C\-Kermit>
+.PP
+.fi
+This is called menu on demand: you get a menu when you want one, but menus
+are not forced on you even when know what you're doing. Note that you can
+also abbreviate most keywords, and you can complete them with the Tab or
+Esc key. Also note that ? works for filenames too, and that you can use it
+in the middle of a keyword or filename, not just at the beginning. For
+example, "send x?" lists all the files in the current directory whose names
+start with 'x'.
+.SH INITIALIZATION FILE
+In its default configuration, C\(hyKermit executes commands from a file
+called .kermrc in your home directory when it starts, unless it is given the
+\-Y or \-y command\(hyline option. Custom configurations might substitute a shared
+system\(hywide initialization file. The SHOW FILE command tells what
+initialization file, if any, was used. The standard initialization file
+"chains" to an individual customization file, .mykermc, in the home directory,
+in which each user can establish her/his own preferences, define macros, and
+so on.
+.PP
+Since execution of the initialization file (at least the standard one)
+makes C\(hyKermit take longer to start, it might be better not to have an
+initialization file, especially now that Kermit's default startup
+configuration is well attuned to modern computing and networking \(hy\(hy in
+other words, you no longer have do anything special to make Kermit
+transfers go fast. So instead of having an initialization file that is
+executed every time Kermit starts, you might consider making one or more
+kerbang scripts (with names other that .kermrc) that do NOT include an
+"exit" command, and invoke those when you need the settings, macro
+definitions, and/or scripted actions they contain, and invoke C\(hyKermit
+directly when you don't.
+.PP
+To put it another way... We still distribute the standard initialization
+file since it's featured in the manual and backwards compatibility is
+important to us. But there's no harm in not using it if you don't need the
+stuff that's in it (services directory, dialing directory, network
+directory, and associated macro definitions). On the other hand, if there
+are settings or macros you want in effect EVERY time you use Kermit, the
+initialization file (or the customization file it chains to) is the place
+to put them, because that's the only place Kermit looks for them
+automatically each time you start it.
+.SH MODES OF OPERATION
+Kermit is said to be in Local mode if it has made a connection to another
+computer, e.g. by dialing it or establishing a Telnet connection to it. The
+other computer is remote, so if you start another copy of Kermit on the
+remote computer, it is said to be in Remote mode (as long as it has not
+made any connections of its own). The local Kermit communicates over the
+communications device or network connection, acting as a conduit between
+the the remote computer and your keyboard and screen. The remote Kermit is
+the file\(hytransfer partner to the local Kermit and communicates only through
+its standard input and output.
+.PP
+At any moment, a Kermit program can be in any of the following states. It's
+important to know what they are and how to change from one to the other.
+.TP
+Command state
+In this state, Kermit reads commands from:
+.sp
+\(bu Your keyboard; or:
+.br
+\(bu A file, or:
+.br
+\(bu A macro definition.
+.sp
+You can exit from Command state back to Unix with the EXIT or QUIT
+command (same thing). You can enter Connect state with any of various
+commands (CONNECT, DIAL, TELNET, etc). You can enter file transfer
+state with commands like SEND, RECEIVE, and GET. You can enter Server
+state with the SERVER command. The TAKE command tells Kermit to read
+and execute commands from a file. The (perhaps implied) DO command
+tells Kermit to read and execute commands from a macro definition.
+While in Command state, you can interrupt any command, macro, or
+command file by typing Ctrl\-C (hold down the Ctrl key and press the C
+key); this normally brings you back to the prompt.
+.TP
+Shell state
+You can invoke an inferior shell or external command from the Kermit
+command prompt by using the PUSH, RUN (!), EDIT, or BROWSE command.
+While the inferior shell or command is active, Kermit is suspended and
+does nothing. Return to Kermit Command state by exiting from the
+inferior shell or application.
+.TP
+Connect state
+In this state, which can be entered only when in Local mode (i.e. when
+Kermit has made a connection to another computer), Kermit is acting as
+a terminal to the remote computer. Your keystrokes are sent to the
+remote computer and characters that arrive over the communication
+connection are displayed on your screen. This state is entered when
+you give a CONNECT, DIAL, TELNET, RLOGIN, or IKSD command. You can
+return to command state by logging out of the remote computer, or by
+typing:
+.sp
+ Ctrl\-\ec
+.sp
+That is: Hold down the Ctrl key and press the backslash key, then let
+go of the Ctrl key and press the C key. This is called escaping back.
+Certain other escape\(hylevel commands are also provided; type Ctrl\-\e?
+for a list. For example, you can enter Shell state with:
+.sp
+ Ctrl\-\e!
+.sp
+To send a Ctrl\-\e to the host while in Connect state, type two of them
+in a row. See HELP CONNECT and HELP SET ESCAPE for more info.
+.TP
+Local file\(hytransfer state
+In this state, Kermit is sending packets back and forth with the other
+computer in order to transfer a file or accomplish some other
+file\(hyrelated task. And at the same time, it is displaying its progress
+on your screen and watching your keyboard for interruptions. In this
+state, the following single\(hykeystroke commands are accepted:
+.sp
+.RS
+.TP
+X
+Interrupt the current file and go on to the next (if any).
+.TP
+Z
+Interrupt the current file and skip all the rest.
+.TP
+E
+Like Z but uses a "stronger" protocol (use if X or Z don't work).
+.TP
+Ctrl\-C
+Interrupt file\(hytransfer mode (use if Z or E don't work).
+.sp
+.RE
+Kermit returns to its previous state (Command or Connect) when the
+transfer is complete or when interrupted successfully by X, Z, E, or
+Ctrl\-C (hold down the Ctrl key and press the C key).
+.TP
+Remote file\(hytransfer state
+In this state, Kermit is exchanging file\(hytransfer packets with its
+local partner over its standard i/o. It leaves this state
+automatically when the transfer is complete. In case you find your
+local Kermit in Connect state and the remote one in File\(hytransfer
+state (in which it seems to ignore your keystrokes), you can usually
+return it to command state by typing three Ctrl\-C's in a row. If that
+doesn't work, return your local Kermit to Command state (Ctrl\-\e C) and
+type "e\(hypacket" and then press the Return or Enter key; this forces a
+fatal Kermit protocol error.
+.TP
+Remote Server state
+This is like Remote File\(hytransfer state, except it never returns
+automatically to Command state. Rather, it awaits further instructions
+from the client program; that is, from your Local Kermit program. You
+can return the Remote Server to its previous state by issuing a
+"finish" command to the client, or if you are in Connect state, by
+typing three Ctrl\-C's in a row. You can tell the server job to log out
+and break the connection by issuing a "bye" command to the client.
+.TP
+Local Server state
+Like Remote\(hyServer state, but in local mode, and therefore with its
+file\(hytransfer display showing, and listening for single\(hykey commands,
+as in Local File\(hytransfer state. Usually this state is entered
+automatically when a remote Kermit program gives a GET command.
+.sp
+C\(hyKermit, Kermit 95, and MS\(hyDOS Kermit all can switch automatically from
+Connect state to Local File\(hytransfer state when you initiate a file
+transfer from the remote computer by starting Kermit and telling it to send
+or get a file, in which case, Connect state is automatically resumed after
+the file transfer is finished.
+.sp
+Note that C\(hyKermit is not a terminal emulator. It is a communications
+application that you run in a terminal window (e.g. console or Xterm). The
+specific emulation, such as VT100, VT220, Linux Console, or Xterm, is
+provided by the terminal window in which you are running C\(hyKermit. Kermit
+95 and MS\(hyDOS Kermit, on the other hand, are true terminal emulators. Why
+is C\(hyKermit not a terminal emulator? CLICK HERE to read about it.
+.SH MAKING CONNECTIONS
+Here is how to make different kinds of connections using interactive Kermit
+commands (as noted above, you can also make connections with command\(hyline
+options). Note that you don't have to make connections with Kermit. It can
+also be used on the far end of a connection as the remote file transfer and
+management partner of your local communications software.
+.TP
+Making a Telnet Connection
+At the C\(hyKermit command prompt, simply type:
+.sp
+.nf
+ telnet foo.bar.com
+.fi
+.sp
+(substituting desired hostname or address).
+You can also include a port number:
+.sp
+.nf
+ telnet xyzcorp.com 3000 ;
+.fi
+.sp
+If the connection is successful, Kermit automically enters Connect
+state. When you logout from the remote host, Kermit automatically
+returns to its prompt. More info: HELP TELNET, HELP SET TELNET, HELP
+SET TELOPT. Also see the IKSD section below.
+.TP
+Making an Rlogin connection
+This is just like Telnet, except you have to be root to do it because
+Rlogin uses a privileged TCP port:
+.sp
+.nf
+ rlogin foo.bar.com
+.fi
+.sp
+More info: HELP RLOGIN.
+.TP
+Making an SSH Connection
+Unlike Telnet and Rlogin, SSH connections are not built\(hyin, but
+handled by running your external SSH client through a pseudoterminal.
+Using C\(hyKermit to control the SSH client gives you all of Kermit's
+features (file transfer, character\(hyset conversion, scripting, etc)
+over SSH.
+.sp
+ ssh foo.bar.com
+.sp
+More info: HELP SSH, HELP SET SSH.
+.TP
+Dialing with a Modem
+If it's an external modem, make sure it is connected to a usable
+serial port on your computer with a regular (straight\(hythrough) modem
+cable, and to the telephone jack with a telephone cable, and that it's
+turned on. Then use these commands:
+.sp
+.nf
+ set modem type usrobotics ; Or other supported type
+ set line /dev/ttyS0 ; Specify device name
+ set speed 57600 ; Or other desired speed
+ set flow rts/cts ; Most modern modems support this
+ set dial method tone ; (or pulse)
+ dial 7654321 ; Dial the desired number
+.fi
+.sp
+Type "set modem type ?" for a list of supported modem types. If you
+omit the SET MODEM TYPE command, the default type is
+"generic\(hyhigh\(hyspeed", which should work for most modern AT\(hycommand\(hyset
+modems. If the line is busy, Kermit redials automatically. If the call
+does not succeed, use "set dial display on" and try it again to watch
+what happens. If the call succeeds, Kermit enters Connect state
+automatically and returns to its prompt automatically when you log out
+from the remote computer or the connection is otherwise lost.
+.sp
+You can also dial from a modem that is accessible by Telnet, e.g. to a
+reverse terminal server. In this case the command sequence is:
+.sp
+.nf
+ set host ts.xxx.com 2000 ; Terminal\(hyserver and port
+ set modem type usrobotics ; Or other supported type
+ set dial method tone ; (or pulse)
+ dial 7654321 ; Dial the desired number
+.fi
+.sp
+If the terminal server supports the Telnet Com Port Option, RFC 2217,
+you can also give serial\(hyport related commands such as SET SPEED, SET
+PARITY, and so on, and Kermit relays them to the terminal server using
+the protocol specified in the RFC.
+.sp
+More info: HELP SET MODEM, HELP SET LINE, HELP SET SPEED, HELP SET
+FLOW, HELP DIAL, HELP SET DIAL, HELP SET MODEM, HELP SET
+CARRIER\-WATCH, SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL.
+.TP
+Direct Serial Port
+Connect the two computers, A and B, with a null modem cable (or two
+modem cables interconnected with a null\(hymodem adapter or modem
+eliminator). From Computer A:
+.sp
+.nf
+ set modem type none ; There is no modem
+ set line /dev/ttyS0 ; Specify device name
+ set carrier\-watch off ; If DTR CD are not cross\(hyconnected
+ set speed 57600 ; Or other desired speed
+ set flow rts/cts ; If RTS and CTS are cross\(hyconnected
+ set parity even ; (or "mark" or "space", if necessary)
+ set stop\-bits 2 ; (rarely necessary)
+ set flow xon/xoff ; If you can't use RTS/CTS
+ connect ; Enter Connect (terminal) state
+.fi
+.sp
+This assumes Computer B is set up to let you log in. If it isn't, you
+can run a copy of Kermit on Computer B and follow approximately the
+same directions. More info: As above plus HELP CONNECT.
+.PP
+With modems or direct serial connections, you might also have to "set
+parity even" (or "mark" or "space") if it's a 7\(hybit connection.
+.PP
+Of the connection types listed above, only one can be open at a time.
+However, any one of these can be open concurrently with an FTP or HTTP
+session. Each connection type can be customized to any desired degree,
+scripted, logged, you name it. See the manual.
+.PP
+NOTE: On selected platforms, C\(hyKermit also can make X.25 connections. See
+the manual for details.
+.SH TRANSFERRING FILES WITH KERMIT
+There is a widespread and persistent belief that Kermit is a slow protocol.
+This is because, until recently, it used conservative tuning by default to
+make sure file transfers succeeded, rather than failing because they
+overloaded the connection. Some extra commands (or command\(hyline options,
+like \-Q) were needed to make it go fast, but nobody bothered to find out
+about them. Also, it takes two to tango: most non\(hyKermit\(hyProject Kermit
+protocol implementations really ARE slow. The best file\(hytransfer partners
+for C\(hyKermit are: another copy of C\(hyKermit (7.0 or later) and Kermit 95.
+These combinations work well and they work fast by default. MS\(hyDOS Kermit
+is good too, but you have to tell it to go fast (by giving it the FAST
+command).
+.PP
+Furthermore, all three of these Kermit programs support "autodownload" and
+"autoupload", meaning that when they are in Connect state and a Kermit
+packet comes in from the remote, they automatically switch into file
+transfer mode.
+.PP
+And plus, C\(hyKermit and K95 also switch automatically between text and
+binary mode for each file, so there is no need to "set file type binary" or
+"set file type text", or to worry about files being corrupted because they
+were transferred in the wrong mode.
+.PP
+What all of these words add up to is that now, when you use up\(hyto\(hydate
+Kermit software from the Kermit Project, file transfer is not only fast,
+it's ridiculously easy. You barely have to give any commands at all.
+.TP
+Downloading Files
+Let's say you have Kermit 95, C\(hyKermit, or MS\(hyDOS Kermit on your
+desktop computer, with a connection to a Unix computer that has
+C\(hyKermit installed as "kermit". To download a file (send it from Unix
+to your desktop computer), just type the following command at your
+Unix shell prompt:
+.sp
+ kermit \-s oofa.txt
+.sp
+(where oofa.txt is the filename). If you want to send more than one
+file, you can put as many filenames as you want on the command line,
+and they can be any combination of text and binary:
+.sp
+ kermit \-s oofa.txt oofa.zip oofa.html oofa.tar.gz
+.sp
+and/or you can use wildcards to send groups of files:
+.sp
+ kermit \-s oofa.*
+.sp
+If you want to send a file under an assumed name, use:
+.sp
+ kermit \-s friday.txt \-a today.txt
+.sp
+This sends the file friday.txt but tells the receiving Kermit that its
+name is today.txt. In all cases, as noted, when the file transfer is
+finished, your desktop Kermit returns automatically to Connect state.
+No worries about escaping back, re\(hyconnecting, text/binary mode
+switching. Almost too easy, right?
+.TP
+Uploading Files
+To upload files (send them from your desktop computer to the remote
+Unix computer) do the same thing, but use the \-g (GET) option instead
+of \-s:
+.sp
+ kermit \-g oofa.txt
+.sp
+This causes your local Kermit to enter server mode; then the remote
+Kermit program requests the named file and the local Kermit sends it
+and returns automatically to Connect state when done.
+.sp
+If you want to upload multiple files, you have have use shell quoting
+rules, since these aren't local files:
+.sp
+.nf
+ kermit \-g "oofa.txt oofa.zip oofa.html oofa.tar.gz"
+ kermit \-g "oofa.*"
+.fi
+.sp
+If you want to upload a file but store it under a different name, use:
+.sp
+ kermit \-g friday.txt \-a today.txt
+.TP
+Kermit Transfers the Old\(hyFashioned Way
+If your desktop communications software does not support autoupload or
+autodownload, or it does not include Kermit server mode, the procedure
+requires more steps.
+.sp
+To download a file, type:
+.sp
+ kermit \-s filename
+.sp
+on the host as before, but if nothing happens automatically in
+response to this command, you have to switch your desktop
+communications software into Kermit Receive state. This might be done
+by escaping back using keyboard characters or hot keys (Alt\-x is
+typical) and/or with a command (like RECEIVE) or a menu. When the file
+transfer is complete, you have to go back to Connect state, Terminal
+emulation, or whatever terminology applies to your desktop
+communications software.
+.sp
+To upload a file, type:
+.sp
+ kermit \-r
+.sp
+on the host (rather than "kermit \-g"). This tells C\(hyKermit to wait
+passively for a file to start arriving. Then regain the attention of
+your desktop software (Alt\-x or whatever) and instruct it to send the
+desired file(s) with Kermit protocol. When the transfer is finished,
+return to the Connect or Terminal screen.
+.TP
+If File Transfer Fails
+Although every aspect of Kermit's operation can be finely tuned, there
+are also three short and simple "omnibus tuning" commands you can use
+for troubleshooting:
+.RS
+.TP
+FAST
+Use fast file\(hytransfer settings. This has been the default since
+C\(hyKermit 7.0 now that most modern computers and connections
+support it. If transfers fail with fast settings, try . . .
+.TP
+CAUTIOUS
+Use cautious but not paranoid settings. File transfers, if they
+work, will go at medium speed. If not, try . . .
+.TP
+ROBUST
+Use the most robust, resilient, conservative, safe, and reliable
+settings. File transfers will almost certainly work, but they
+will be quite slow (of course this is a classic tradeoff; ROBUST
+was C\(hyKermit's default tuning in versions 6.0 and earlier, which
+made everybody think Kermit protocol was slow). If ROBUST doesn't
+do the trick, try again with SET PARITY SPACE first in case it's
+not an 8\(hybit connection.
+.RE
+.sp
+Obviously the success and performance of a file transfer also depends
+on C\(hyKermit's file transfer partner. Up\(hyto\(hydate, real Kermit Project
+partners are recommended because they contain the best Kermit protocol
+implementations and because we can support them in case of trouble.
+.sp
+If you still have trouble, consult Chapter 10 of Using C\(hyKermit, or
+send email to kermit\(hysupport@columbia.edu.
+.TP
+Advanced Kermit File\(hyTransfer Features
+Obviously there is a lot more to Kermit file transfer, including all
+sorts of interactive commands, preferences, options, logging,
+debugging, troubleshooting, and anything else you can imagine but
+that's what the manual and updates are for. Here are a few topics you
+can explore if you're interested by Typing HELP for the listed
+commands:
+.RS
+.TP
+Logging transfers:
+LOG TRANSACTIONS (HELP LOG)
+.TP
+Automatic per\(hyfile text/binary mode switching:
+SET TRANSFER MODE { AUTOMATIC, MANUAL } (HELP SET TRANSFER).
+.TP
+Cross\(hyplatform recursive directory tree transfer:
+SEND /RECURSIVE, GET /RECURSIVE (HELP SEND, HELP GET).
+.TP
+File collision options:
+SET FILE COLLISION { OVERWRITE, BACKUP, DISCARD, ... } (HELP SET FILE).
+.TP
+Update: Transfer only files that changed since last time:
+SET FILE COLLISION UPDATE (HELP SET FILE).
+.TP
+Filename selection patterns:
+(HELP WILDCARD).
+.TP
+Flexible file selection:
+SEND (or GET) /BEFORE /AFTER /LARGER /SMALLER /TYPE /EXCEPT, ...
+.TP
+Character\(hyset conversion:
+SET { FILE, TRANSFER } CHARACTER\-SET, ASSOCIATE, ...
+.TP
+File/Pathname control:
+SET { SEND, RECEIVE } PATHNAMES, SET FILE NAMES.
+.TP
+Atomic file movement:
+SEND (or GET) /DELETE /RENAME /MOVE\-TO
+.TP
+Transferring to/from standard i/o of other commands:
+SEND (or GET) /COMMAND
+.TP
+Recovery of interrupted transfer from point of failure:
+RESEND, REGET (HELP RESEND, HELP REGET).
+.RE
+.TP
+Non\(hyKermit File Transfer
+You can also use C\(hyKermit to transfer files with FTP or HTTP Internet
+protocols; see below.
+.sp
+On a regular serial or Telnet connection where the other computer
+doesn't support Kermit protocol at all, you have several options. For
+example, if your desktop communications software supports Zmodem, use
+"rz" and "sz" on the host rather than Kermit. But if Kermit is your
+desktop software, and you are using it to make calls or network
+connections to other computers that don't support Kermit protocol (or
+that don't have a good implementation of it), then if your computer
+also has external X, Y, or Zmodem programs that are redirectable,
+Kermit can use them as external protocols. HELP SET PROTOCOL for
+details.
+.sp
+You can also capture "raw" data streams from the other computer with
+LOG SESSION (HELP LOG and HELP SET SESSION\-LOG for details), and you
+can upload files without any protocol at all with TRANSMIT (HELP
+TRANSMIT, HELP SET TRANSMIT).
+.SH KERMIT'S BUILT\(hyIN FTP AND HTTP CLIENTS
+Kermit's FTP client is like the regular Unix FTP client that you're used
+to, but with some differences:
+.TP
+\(bu
+It has lots more commands and features.
+.TP
+\(bu
+Each FTP command must be prefixed with "ftp", for example "ftp open",
+"ftp get", "ftp bye", etc (this is not strictly true, but until you're
+more familiar with it, it's best to follow this rule).
+.TP
+\(bu
+Commands like "cd", "directory", etc, execute locally, not on the
+server. Use "ftp cd", "ftp dir", etc, to have them act on the server.
+.TP
+\(bu
+You can have an FTP session and a regular Kermit serial or Telnet
+session open at the same time.
+.TP
+\(bu
+FTP sessions can be fully automated.
+.PP
+Pending publication of the next edition of the manual, the Kermit FTP
+client is thoroughly documented at the Kermit Project website:
+.sp
+ http://www.columbia.edu/kermit/ftpclient.html
+.sp
+You also can use HELP FTP and HELP SET FTP to get descriptions of Kermit's
+FTP\(hyrelated commands.
+.PP
+The HTTP client is similar to the FTP one, except you prefix each command
+with HTTP instead of FTP: HTTP OPEN, HTTP GET, HTTP PUT, HTTP CLOSE, etc.
+Type HELP HTTP for details, or visit the to view the manual supplements.
+HTTP connections can be open at the same time as regular serial or Telnet
+connections and FTP connections. So Kermit can manage up to three types
+connections simultaneously.
+.SH INTERNET KERMIT SERVICE
+C\(hyKermit can be configured and run as an Internet service (called IKSD),
+similar to an FTP server (FTPD) except you can (but need not) interact with
+it directly, plus it does a lot more than an FTP server can do. The TCP
+port for IKSD is 1649. It uses Telnet protocol. C\(hyKermit can be an Internet
+Kermit Server, or it can be a client of an IKSD. You can make connections
+from C\(hyKermit to an IKSD with any of the following commands:
+.sp
+.nf
+ telnet foo.bar.edu 1649
+ telnet foo.bar.edu kermit ; if "kermit" is listed in /etc/services
+ iksd foo.bar.edu
+.fi
+.sp
+The IKSD command is equivalent to a TELNET command specifying port 1649.
+For more information about making and using connections to an IKSD, see:
+.sp
+ http://www.columbia.edu/kermit/cuiksd.html
+.sp
+You can run an Internet Kermit Service on your own computer too (if you are
+the system administrator). For instructions, see:
+.sp
+ http://www.columbia.edu/kermit/iksd.html
+.SH SECURITY
+All of C\(hyKermit's built\(hyin TCP/IP networking methods (Telnet, Rlogin, IKSD,
+FTP, and HTTP) can be secured by one or more of the following IETF\(hyapproved
+methods:
+.PP
+\(bu MIT Kerberos IV
+.br
+\(bu MIT Kerberos V
+.br
+\(bu SSL/TLS
+.br
+\(bu Stanford SRP
+.PP
+For complete instructions see:
+.PP
+ http://www.columbia.edu/kermit/security.html
+.PP
+And as noted previously, you can also make SSH connections with C\(hyKermit if
+you already have an SSH client installed.
+.SH ALTERNATIVE COMMAND\(hyLINE PERSONALITIES
+When invoked as "kermit" or any other name besides "ftp" or "telnet",
+C\(hyKermit has the command\(hyline options described above in the OPTIONS
+section. However, if you invoke C\(hyKermit as "telnet" or "ftp", it changes
+its command\(hyline personality to match. This can be done (among other ways)
+with symbolic links (symlinks). For example, if you want C\(hyKermit to be
+your regular Telnet client, or the Telnet helper of your Web browser, you
+can create a link like the following in a directory that lies in your PATH
+ahead of the regular telnet program:
+.sp
+ ln \-s /usr/local/bin/kermit telnet
+.sp
+Now when you give a "telnet" command, you are invoking Kermit instead, but
+with its Telnet command\(hyline personality so, for example:
+.sp
+ telnet xyzcorp.com
+.sp
+Makes a Telnet connection to xyzcorp.com, and Kermit exits automatically
+when the connection is closed (just like the regular Telnet client). Type
+"telnet \-h" to get a list of Kermit's Telnet\(hypersonality command\(hyline
+options, which are intended to be as compatible as possible with the
+regular Telnet client.
+.PP
+Similarly for FTP:
+.sp
+ ln \-s /usr/local/bin/kermit ftp
+.sp
+And now type "ftp \-h" to see its command\(hyline options, and command lines
+just like you would give your regular FTP client:
+.sp
+ ftp xyzcorp.com
+.sp
+but with additional options allowing an entire session to be specified on
+the command line. Finally, if Kermit's
+first command\(hyline option is a Telnet, FTP, IKSD, or HTTP URL, Kermit
+automatically makes the appropriate kind of connection and, if indicated by
+the URL, takes the desired action:
+.TP
+kermit telnet:xyzcorp.com
+Opens a Telnet session
+.TP
+kermit telnet://olga@xyzcorp.com
+Ditto for user olga
+.TP
+kermit ftp://olga@xyzcorp.com/public/oofa.zip
+Downloads a file
+.TP
+kermit kermit://kermit.columbia.edu/kermit/f/READ.ME
+Ditto for IKSD
+.TP
+kermit iksd://kermit.columbia.edu/kermit/f/READ.ME
+(This works too)
+.TP
+kermit http://www.columbia.edu/kermit/index.html
+Grabs a web page
+.fi
+.SH LICENSE
+C\(hyKermit has an unusual license, but a fair and sensible one since the
+Kermit Project must support itself out of revenue: it's not a BSD license,
+not GPL, not Artistic, not commercial, not shareware, not freeware. It can
+be summed up like this: if you want C\(hyKermit for your own use, you can
+download and use it without cost or license (but we'd appreciate it if you
+would purchase the manual). But if you want to sell C\(hyKermit or bundle it
+with a product or otherwise distribute it in a commercial setting EXCEPT
+WITH AN OPEN\(hySOURCE OPERATING SYSTEM DISTRIBUTION such as Linux, FreeBSD,
+NetBSD, or OpenBSD, you must license it. To see the complete license, give
+the LICENSE command at the prompt, or see the COPYING.TXT file distributed
+with C\(hyKermit 7.0 or later, or download it from
+.sp
+ ftp://kermit.columbia.edu/kermit/c\-kermit/COPYING.TXT
+.sp
+Send licensing inquiries to kermit@columbia.edu.
+.SH BUGS
+See the following files for listings of known bugs, limitations,
+workarounds, hints and tips:
+.TP
+ckcbwr.txt
+General C\(hyKermit bugs, hints, tips.
+.TP
+ckubwr.txt
+Unix\(hyspecific C\(hyKermit bugs, hints, tips.
+.PP
+Report bugs and problems by email to:
+.sp
+ kermit\-support@columbia.edu.
+.sp
+Before requesting technical support, please read the hints here:
+.sp
+ http://www.columbia.edu/kermit/support.html
+.sp
+and also read the C\(hyKermit Frequently Asked Questions:
+.sp
+ http://www.columbia.edu/kermit/ckfaq.html
+.SH OTHER TOPICS
+There's way more to C\(hyKermit than we've touched on here \(hy\(hy troubleshooting,
+customization, character sets, dialing directories, sending pages, script
+writing, and on and on, all of which are covered in the manual and updates
+and supplements. For the most up\(hyto\(hydate information on documentation (or
+updated documentation itself) visit the Kermit Project website:
+.sp
+ http://www.columbia.edu/kermit/
+.PP
+There you will also find Kermit software packages for other platforms:
+different Unix varieties, Windows, DOS, VMS, IBM mainframes, and many
+others: 20+ years' worth.
+.SH DOCUMENTATION AND UPDATES
+The manual for C\(hyKermit is:
+.TP
+.I
+Using C\(hyKermit
+Frank da Cruz and Christine M. Gianone,
+Second Edition, Digital Press / Butterworth\(hyHeinemann, Woburn, MA, 1997, 622
+pages, ISBN 1\-55558\-164\-1. This is a printed book. It covers C\(hyKermit 6.0.
+.TP
+The C\(hyKermit 7.0 Supplement
+http://www.columbia.edu/kermit/ckermit70.html
+.TP
+The C\(hyKermit 8.0 Supplement
+http://www.columbia.edu/kermit/ckermit80.html
+.TP
+The C\(hyKermit 9.0 Supplement
+http://www.columbia.edu/kermit/ckermit90.html
+.PP
+Visit C\(hyKermit home page:
+.sp
+ http://www.columbia.edu/kermit/ckermit.html
+.sp
+to learn about new versions, Beta tests, and other news; to
+read case studies and tutorials; to download source code, install packages,
+and prebuilt binaries for many platforms. Also visit:
+.TP
+http://www.columbia.edu/kermit/scriptlib.html
+The Kermit script library and tutorial
+.TP
+http://www.columbia.edu/kermit/newfaq.html
+The Kermit FAQ (Frequently Asked Questions about Kermit)
+.TP
+http://www.columbia.edu/kermit/ckfaq.html
+The C\(hyKermit FAQ (Frequently Asked Questions about C\(hyKermit)
+.TP
+http://www.columbia.edu/kermit/telnet.html
+C\(hyKermit Telnet client documentation
+.TP
+http://www.columbia.edu/kermit/security.html
+C\(hyKermit security documentation (Kerberos, SSL/TLS, etc)
+.TP
+http://www.columbia.edu/kermit/cuiksd.html
+Internet Kermit Service user documentation
+.TP
+http://www.columbia.edu/kermit/iksd.html
+Internet Kermit Service administrator documentation
+.TP
+http://www.columbia.edu/kermit/studies.html
+Case studies.
+.TP
+http://www.columbia.edu/kermit/support.html
+Technical support.
+.TP
+http://www.columbia.edu/kermit/k95tutorial.html
+Kermit 95 tutorial.
+.TP
+comp.protocols.kermit.misc
+The Kermit newsgroup (unmoderated).
+.SH FILES
+.TP
+COPYING.TXT
+C\(hyKermit license.
+.TP
+~/.kermrc
+Initialization file.
+.TP
+~/.mykermrc
+Customization file.
+.TP
+~/.kdd
+Kermit dialing directory (see manual).
+.TP
+~/.knd
+Kermit network directory (see manual).
+.TP
+~/.ksd
+Kermit services directory (see manual).
+.TP
+ca_certs.pem
+Certificate Authority certifcates used for SSL connections.
+.TP
+ckuins.txt
+Installation instructions for Unix. Also at
+http://www.columbia.edu/kermit/ckuins.html.
+.TP
+ckcbwr.txt
+General C\(hyKermit bugs, hints, tips.
+.TP
+ckubwr.txt
+Unix\(hyspecific C\(hyKermit bugs, hints, tips.
+.TP
+ckcplm.txt
+C\(hyKermit program logic manual.
+.TP
+ckccfg.txt
+C\(hyKermit compile\(hytime configuration options.
+.TP
+ssh
+(in your PATH) SSH connection helper.
+.TP
+rz, sz, etc.
+(in your PATH) external protocols for XYZmodem.
+.TP
+/var/spool/locks (or whatever)
+UUCP lockfile for dialing out (see installation instructions).
+.SH AUTHORS
+.TP
+Software
+Frank da Cruz and Jeffrey E Altman,
+.br
+1985\(hypresent, with contributions from hundreds of others all over the
+world.
+.TP
+Documentation
+Frank da Cruz
+.TP
+Address
+.nf
+The Kermit Project \(hy Columbia Univerity
+612 West 115th Street
+New York NY 10025\-7799
+USA
+.fi
+.TP
+E\(hyMail
+kermit@columbia.edu
+.TP
+Web
+http://www.columbia.edu/kermit/
+.fi
+.br
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.c
new file mode 100644
index 0000000..8e0476b
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.c
@@ -0,0 +1,1983 @@
+char *ckptyv = "Pseudoterminal support, 9.0.101, 13 Jun 2011";
+
+/* C K U P T Y -- C-Kermit pseudoterminal control functions for UNIX */
+
+/* Last update: Mon Jun 13 11:32:52 2011 */
+
+/*
+ Copyright 1995 by the Massachusetts Institute of Technology.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of M.I.T. not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission. Furthermore if you modify this software you must
+ label your software as modified software and not distribute it in such a
+ fashion that it might be confused with the original M.I.T. software.
+ M.I.T. makes no representations about the suitability of this software for
+ any purpose. It is provided "as is" without express or implied warranty.
+
+ Modified for use in C-Kermit, and new material added, by:
+
+ Jeffrey Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+ November 1999
+
+ Parameterized for pty file descriptor and function code,
+ Frank da Cruz, Columbia University, New York City
+ Dec 2006 - Sep 2009
+*/
+
+/*
+ Built and tested successully on:
+ . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X
+ . AIX 4.1 and later
+ . DG/UX 5.4R4.11
+ . Digital UNIX 3.2 and 4.0
+ . HP-UX 9.00 and later
+ . IRIX 6.0 and later
+ . Linux
+ . Mac OS X 10.4
+ . NeXTSTEP 3.x
+ . OpenBSD
+ . QNX 4.25 (except PTY process termination not detected)
+ . SCO OSR5.0.5
+ . SCO Unixware 7
+ . SINIX 5.42
+ . Solaris 2.x and 7
+ . SunOS 4.1.3
+
+ Failures include:
+ . SCO UNIX 3.2v4.2 (compile fails with syntax error in <memory.h>)
+ . HP-UX 8.00 and earlier (no vhangup or ptsname routines)
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h" /* To pick up NETPTY definition */
+
+#ifndef NETPTY /* Selector for PTY support */
+
+char * ptyver = "No PTY support";
+
+#else /* (rest of this module...) */
+
+char * ptyver = "PTY support 8.0.016, 22 Aug 2007";
+
+/* These will no doubt need adjustment... */
+
+#ifndef NEXT
+#define HAVE_SETSID
+#endif /* NEXT */
+#define HAVE_KILLPG
+#define HAVE_TTYNAME
+#define HAVE_WAITPID
+
+#ifdef SUNOS41
+#define BSD44ORPOSIX
+#endif /* SUNOS41 */
+
+#ifndef USE_TERMIO
+#ifdef LINUX
+#define USE_TERMIO
+#else
+#ifdef ATTSV
+#define USE_TERMIO
+#else
+#ifdef HPUX
+#define USE_TERMIO
+#else
+#ifdef AIX
+#define USE_TERMIO
+#else
+#ifdef BSD44ORPOSIX
+#define USE_TERMIO
+#else
+#ifdef IRIX60
+#define USE_TERMIO
+#else
+#ifdef QNX
+#define USE_TERMIO
+#endif /* QNX */
+#endif /* IRIX60 */
+#endif /* BSD44ORPOSIX */
+#endif /* AIX */
+#endif /* HPUX */
+#endif /* ATTSV */
+#endif /* LINUX */
+#endif /* USE_TERMIO */
+
+#ifdef QNX
+#include <fcntl.h>
+#endif /* QNX */
+
+#ifdef USE_TERMIO
+#define POSIX_TERMIOS /* Seems to be a misnomer */
+#endif /* USE_TERMIO */
+
+#ifdef NEXT
+#ifndef GETPGRP_ONEARG
+#define GETPGRP_ONEARG
+#endif /* GETPGRP_ONEARG */
+#endif /* NEXT */
+
+#ifdef WANT_UTMP /* See ckupty.h */
+/*
+ WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most
+ nonportable part of this module, and (b) we're not logging anybody
+ in, we're just running a process, and don't need to write utmp/wtmp records.
+*/
+#ifndef HAVE_SETUTXENT /* Who has <utmpx.h> */
+#ifdef SOLARIS
+#define HAVE_SETUTXENT
+#else
+#ifdef IRIX60
+#define HAVE_SETUTXENT
+#else
+#ifdef CK_SCOV5
+#define HAVE_SETUTXENT
+#else
+#ifdef HPUX10
+#define HAVE_SETUTXENT
+#else
+#ifdef UNIXWARE
+#define HAVE_SETUTXENT
+#else
+#ifdef IRIX60
+#define HAVE_SETUTXENT
+#endif /* IRIX60 */
+#endif /* UNIXWARE */
+#endif /* HPUX10 */
+#endif /* CK_SCOV5 */
+#endif /* IRIX60 */
+#endif /* SOLARIS */
+#endif /* HAVE_SETUTXENT */
+
+#ifndef HAVE_UTHOST /* Does utmp include ut_host[]? */
+#ifdef HAVE_SETUTXENT /* utmpx always does */
+#define HAVE_UTHOST
+#else
+#ifdef LINUX /* Linux does */
+#define HAVE_UTHOST
+#else
+#ifdef SUNOS4 /* SunOS does */
+#define HAVE_UTHOST
+#else
+#ifdef AIX41 /* AIX 4.1 and later do */
+#define HAVE_UTHOST
+#endif /* AIX41 */
+#endif /* SUNOS4 */
+#endif /* LINUX */
+#endif /* HAVE_SETUTXENT */
+#endif /* HAVE_UTHOST */
+
+#ifndef HAVE_UT_HOST
+#ifndef NO_UT_HOST
+#define NO_UT_HOST
+#endif /* NO_UT_HOST */
+#endif /* HAVE_UT_HOST */
+
+#endif /* WANT_UTMP */
+
+#ifdef LINUX
+#define CK_VHANGUP
+#define HAVE_SYS_SELECT_H
+#define HAVE_GETUTENT
+#define HAVE_SETUTENT
+#define HAVE_UPDWTMP
+#endif /* LINUX */
+
+#ifdef HPUX10
+#define CK_VHANGUP
+#define VHANG_FIRST
+#define HAVE_PTSNAME
+#ifndef HAVE_PTYTRAP
+#define HAVE_PTYTRAP
+#endif /* HAVE_PTYTRAP */
+#else
+#ifdef HPUX9
+#define CK_VHANGUP
+#define VHANG_FIRST
+#define HAVE_PTSNAME
+#ifndef HAVE_PTYTRAP
+#define HAVE_PTYTRAP
+#endif /* HAVE_PTYTRAP */
+#endif /* HPUX9 */
+#endif /* HPUX10 */
+
+#ifdef SUNOS4
+#define CK_VHANGUP
+#define NO_UT_PID
+#define VHANG_FIRST
+#endif /* SUNOS4 */
+
+#ifdef IRIX60
+#define CK_VHANGUP
+#define HAVE__GETPTY
+#endif /* IRIX60 */
+
+#ifdef SINIX
+#define HAVE_STREAMS
+#define HAVE_GRANTPT
+#define HAVE_PTSNAME
+#define PUSH_PTEM
+#define PUSH_LDTERM
+#define PUSH_TTCOMPAT
+#endif /* SINIX */
+
+#ifdef ultrix
+#define MUST_SETPGRP
+#endif /* ultrix */
+
+#ifdef QNX
+#define MUST_SETPGRP
+#define NO_DEVTTY
+#define INIT_SPTY
+#endif /* QNX */
+
+#ifdef LINUX
+#ifdef HAVE_PTMX
+#define HAVE_GRANTPT
+#define HAVE_PTSNAME
+#endif /* HAVE_PTMX */
+#else
+#ifdef HAVE_STREAMS
+#define HAVE_PTMX
+#endif /* HAVE_STREAMS */
+#endif /* LINUX */
+
+#include "ckupty.h"
+
+#ifdef PTYNOBLOCK
+#ifndef O_NDELAY
+#ifdef O_NONBLOCK
+#define O_NDELAY O_NONBLOCK
+#endif /* O_NONBLOCK */
+#endif /* O_NDELAY */
+#else /* PTYNOBLOCK */
+#ifdef O_NDELAY
+#undef O_NDELAY
+#endif /* O_NDELAY */
+#define O_NDELAY 0
+#endif /* PTYNOBLOCK */
+
+#ifndef ONLCR
+#define ONLCR 0
+#endif /* ONLCR */
+
+#ifdef CK_WAIT_H
+#include <sys/wait.h>
+#endif /* CK_WAIT_H */
+
+#ifdef STREAMSPTY
+#ifndef INIT_SPTY
+#define INIT_SPTY
+#endif /* INIT_SPTY */
+
+#include <sys/stream.h>
+#include <stropts.h>
+#include <termio.h>
+
+/* Make sure we don't get the BSD version */
+
+#ifdef HAVE_SYS_TTY_H
+#include "/usr/include/sys/tty.h"
+#endif /* HAVE_SYS_TTY_H */
+
+#ifdef HAS_PTYVAR /* Where is this set? */
+
+#include <sys/ptyvar.h>
+
+#else /* HAS_PTYVAR */
+
+#ifndef TIOCPKT_FLUSHWRITE
+#define TIOCPKT_FLUSHWRITE 0x02
+#define TIOCPKT_NOSTOP 0x10
+#define TIOCPKT_DOSTOP 0x20
+#define TIOCPKT_IOCTL 0x40
+#endif /* TIOCPKT_FLUSHWRITE */
+
+#endif /* HAS_PTYVAR */
+
+#ifdef HAVE_TTY_H
+#include <tty.h>
+#endif /* HAVE_TTY_H */
+
+/*
+ Because of the way ptyibuf is used with streams messages, we need
+ ptyibuf+1 to be on a full-word boundary. The following weirdness
+ is simply to make that happen.
+*/
+long ptyibufbuf[BUFSIZ/sizeof(long)+1];
+char *ptyibuf = ((char *)&ptyibufbuf[1])-1;
+char *ptyip = ((char *)&ptyibufbuf[1])-1;
+char ptyibuf2[BUFSIZ];
+unsigned char ctlbuf[BUFSIZ];
+struct strbuf strbufc, strbufd;
+
+int readstream();
+
+#else /* ! STREAMSPTY */
+
+/* I/O data buffers, pointers, and counters. */
+
+char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char ptyibuf2[BUFSIZ];
+
+#endif /* ! STREAMSPTY */
+
+#ifndef USE_TERMIO
+struct termbuf {
+ struct sgttyb sg;
+ struct tchars tc;
+ struct ltchars ltc;
+ int state;
+ int lflags;
+} termbuf, termbuf2;
+
+#define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val)
+#define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val)
+#define cfgetospeed(tp) (tp)->sg.sg_ospeed
+#define cfgetispeed(tp) (tp)->sg.sg_ispeed
+
+#else /* USE_TERMIO */
+
+#ifdef SYSV_TERMIO
+#define termios termio
+#endif /* SYSV_TERMIO */
+
+#ifndef TCSANOW
+
+#ifdef TCSETS
+
+#define TCSANOW TCSETS
+#define TCSADRAIN TCSETSW
+#define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+
+#else /* TCSETS */
+
+#ifdef TCSETA
+#define TCSANOW TCSETA
+#define TCSADRAIN TCSETAW
+#define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t)
+#else /* TCSETA */
+#define TCSANOW TIOCSETA
+#define TCSADRAIN TIOCSETAW
+#define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t)
+#endif /* TCSETA */
+
+#endif /* TCSETS */
+
+#define tcsetattr(f,a,t) ioctl(f,a,t)
+#define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val)
+#define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
+
+#ifdef CIBAUD
+#define cfsetispeed(tp,val) \
+ (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<<IBSHIFT)
+#define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
+#else /* CIBAUD */
+#define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val)
+#define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
+#endif /* CIBAUD */
+
+#endif /* TCSANOW */
+
+#ifdef HAVE_OPENPTY
+#include <pty.h>
+#endif
+
+struct termios termbuf, termbuf2; /* pty control structure */
+
+#ifdef INIT_SPTY
+static int spty = -1;
+#endif /* INIT_SPTY */
+
+#endif /* USE_TERMIO */
+
+#ifdef QNX /* 299 */
+#ifndef IXANY
+#define IXANY 0
+#endif /* IXANY */
+#endif /* QNX */
+
+static int msg = 0;
+
+/* Variables available to other modules */
+
+int pty_fork_active = 0; /* pty fork is active */
+PID_T pty_fork_pid = -1; /* pty fork pid */
+int pty_slave_fd = -1; /* pty slave file descriptor */
+int pty_master_fd = -1; /* pty master file descriptor */
+
+/* termbuf routines (begin) */
+/*
+ init_termbuf()
+ copy_termbuf(cp)
+ set_termbuf()
+
+ These three routines are used to get and set the "termbuf" structure
+ to and from the kernel. init_termbuf() gets the current settings.
+ copy_termbuf() hands in a new "termbuf" to write to the kernel, and
+ set_termbuf() writes the structure into the kernel.
+*/
+VOID
+init_termbuf(fd) int fd; {
+ int ttyfd;
+ int rc = 0;
+
+ ttyfd = fd;
+
+#ifdef HAVE_STREAMS
+ debug(F100,"init_termbuf HAVE_STREAMS","",0);
+#else
+ debug(F100,"init_termbuf HAVE_STREAMS NOT DEFINED","",0);
+#endif /* HAVE_STREAMS */
+#ifdef STREAMSPTY
+ debug(F100,"init_termbuf STREAMSPTY","",0);
+#else
+ debug(F100,"init_termbuf STREAMSPTY NOT DEFINED","",0);
+#endif /* STREAMSPTY */
+#ifdef INIT_SPTY
+ debug(F100,"init_termbuf INIT_SPTY","",0);
+#else
+ debug(F100,"init_termbuf INIT_SPTY NOT DEFINED","",0);
+#endif /* INIT_SPTY */
+
+ debug(F101,"init_termbuf ttyfd","",ttyfd);
+#ifdef INIT_SPTY
+ debug(F101,"init_termbuf spty","",spty);
+#endif /* INIT_SPTY */
+
+ memset(&termbuf,0,sizeof(termbuf));
+ memset(&termbuf2,0,sizeof(termbuf2));
+#ifndef USE_TERMIO
+ rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg);
+ rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc);
+ rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc);
+#ifdef TIOCGSTATE
+ rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state);
+#endif /* TIOCGSTATE */
+#else /* USE_TERMIO */
+ errno = 0;
+#ifdef INIT_SPTY
+ rc = tcgetattr(spty, &termbuf);
+ debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno);
+#else
+ rc = tcgetattr(ttyfd, &termbuf);
+ debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno);
+#endif /* INIT_SPTY */
+#endif /* USE_TERMIO */
+ if (!rc)
+ termbuf2 = termbuf;
+}
+
+#ifdef TIOCPKT_IOCTL
+VOID
+copy_termbuf(cp, len) char *cp; int len; {
+ if (len > sizeof(termbuf))
+ len = sizeof(termbuf);
+ memcpy((char *)&termbuf, cp, len);
+ termbuf2 = termbuf;
+}
+#endif /* TIOCPKT_IOCTL */
+
+VOID
+set_termbuf(fd) int fd; { /* Only make the necessary changes. */
+ int x;
+ int ttyfd;
+ ttyfd = fd;
+
+ debug(F101,"set_termbuf ttyfd","",ttyfd);
+#ifdef INIT_SPTY
+ debug(F101,"set_termbuf spty","",spty);
+#endif /* INIT_SPTY */
+
+#ifndef USE_TERMIO
+ debug(F100,"set_termbuf USE_TERMIO","",0);
+ if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
+ ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg);
+ if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
+ ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc);
+ if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+ sizeof(termbuf.ltc)))
+ ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc);
+ if (termbuf.lflags != termbuf2.lflags)
+ ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags);
+#else /* USE_TERMIO */
+ x = memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf));
+ debug(F101,"set_termbuf !USE_TERMIO memcmp","",x);
+ x = 1; /* Force this */
+ if (x) {
+ int x;
+ errno = 0;
+#ifdef INIT_SPTY
+ debug(F100,"set_termbuf INIT_SPTY","",0);
+ x = tcsetattr(spty, TCSANOW, &termbuf);
+ debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
+#else
+ debug(F100,"set_termbuf !INIT_SPTY","",0);
+ x = tcsetattr(ttyfd, TCSANOW, &termbuf);
+ debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno);
+#endif /* INIT_SPTY */
+ }
+#endif /* USE_TERMIO */
+}
+/* termbuf routines (end) */
+
+VOID
+ptyint_vhangup() {
+#ifdef CK_VHANGUP
+#ifdef CK_POSIX_SIG
+ struct sigaction sa;
+ /* Initialize "sa" structure. */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGHUP, &sa, (struct sigaction *)0);
+ vhangup();
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGHUP, &sa, (struct sigaction *)0);
+#else /* CK_POSIX_SIG */
+ signal(SIGHUP,SIG_IGN);
+ vhangup();
+ signal(SIGHUP,SIG_DFL);
+#endif /* CK_POSIX_SIG */
+#endif /* CK_VHANGUP */
+}
+
+/*
+ This routine is called twice. It's not particularly important that the
+ setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
+ rather that we have a controlling terminal at the end. It is assumed that
+ vhangup doesn't exist and confuse the process's notion of controlling
+ terminal on any system without TIOCNOTTY. That is, either vhangup() leaves
+ the controlling terminal in tact, breaks the association completely, or the
+ system provides TIOCNOTTY to get things back into a reasonable state. In
+ practice, vhangup() either breaks the association completely or doesn't
+ effect controlling terminals, so this condition is met.
+*/
+long
+ptyint_void_association() {
+ int con_fd;
+#ifdef HAVE_SETSID
+ debug(F110,
+ "ptyint_void_association()",
+ "setsid()",
+ 0
+ );
+ setsid();
+#endif /* HAVE_SETSID */
+
+#ifndef NO_DEVTTY
+ /* Void tty association first */
+#ifdef TIOCNOTTY
+ con_fd = open("/dev/tty", O_RDWR);
+ debug(F111,
+ "ptyint_void_association() open(/dev/tty,O_RDWR)",
+ "/dev/tty",
+ con_fd);
+ if (con_fd >= 0) {
+ ioctl(con_fd, TIOCNOTTY, 0);
+ close(con_fd);
+ }
+#ifdef DEBUG
+ else debug(F101, "ptyint_void_association() open() errno","",errno);
+#endif /* DEBUG */
+#endif /* TIOCNOTTY */
+#endif /* NO_DEVTTY */
+ return(0);
+}
+
+/* PID may be zero for unknown.*/
+
+long
+pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
+#ifdef VHANG_LAST
+ int retval, fd;
+#endif /* VHANG_LAST */
+
+ debug(F111,"pty_cleanup()",slave,pid);
+#ifdef WANT_UTMP
+ if (update_utmp)
+ pty_update_utmp(PTY_DEAD_PROCESS,
+ 0,
+ "",
+ slave,
+ (char *)0,
+ PTY_UTMP_USERNAME_VALID
+ );
+#endif /* WANT_UTMP */
+
+#ifdef SETUID
+ chmod(slave, 0666);
+ chown(slave, 0, 0);
+#endif /* SETUID */
+
+#ifdef HAVE_REVOKE
+ revoke(slave);
+ /*
+ Revoke isn't guaranteed to send a SIGHUP to the processes it
+ dissociates from the terminal. The best solution without a Posix
+ mechanism for forcing a hangup is to killpg() the process group of the
+ pty. This will at least kill the shell and hopefully, the child
+ processes. This is not always the case, however. If the shell puts
+ each job in a process group and doesn't pass along SIGHUP, all
+ processes may not die.
+ */
+ if (pid > 0) {
+#ifdef HAVE_KILLPG
+ killpg(pid, SIGHUP);
+#else
+ kill(-(pid), SIGHUP);
+#endif /*HAVE_KILLPG*/
+ }
+#else /* HAVE_REVOKE*/
+#ifdef VHANG_LAST
+ {
+ int status;
+#ifdef CK_POSIX_SIG
+ sigset_t old, new;
+ sigemptyset(&new);
+ sigaddset(&new, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &new, &old);
+#else /*CK_POSIX_SIG*/
+ int mask = sigblock(sigmask(SIGCHLD));
+#endif /*CK_POSIX_SIG*/
+ switch (retval = fork()) {
+ case -1:
+#ifdef CK_POSIX_SIG
+ sigprocmask(SIG_SETMASK, &old, 0);
+#else /*CK_POSIX_SIG*/
+ sigsetmask(mask);
+#endif /*CK_POSIX_SIG*/
+ return errno;
+ case 0:
+ ptyint_void_association();
+ if (retval = (pty_open_ctty(slave, &fd, -1)))
+ exit(retval);
+ ptyint_vhangup();
+ exit(0);
+ break;
+ default:
+#ifdef HAVE_WAITPID
+ waitpid(retval, &status, 0);
+#else /*HAVE_WAITPID*/
+ wait(&status);
+#endif /* HAVE_WAITPID */
+#ifdef CK_POSIX_SIG
+ sigprocmask(SIG_SETMASK, &old, 0);
+#else /*CK_POSIX_SIG*/
+ sigsetmask(mask);
+#endif /*CK_POSIX_SIG*/
+ break;
+ }
+ }
+#endif /*VHANG_LAST*/
+#endif /* HAVE_REVOKE*/
+#ifndef HAVE_STREAMS
+ slave[strlen("/dev/")] = 'p';
+#ifdef SETUID
+ chmod(slave, 0666);
+ chown(slave, 0, 0);
+#endif /* SETUID */
+#endif /* HAVE_STREAMS */
+ return(0);
+}
+
+long
+pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
+ char *cp;
+ char *p;
+ int i, ptynum;
+ struct stat stb;
+#ifndef HAVE_OPENPTY
+#ifndef HAVE__GETPTY
+ char slavebuf[1024];
+#endif /* HAVE__GETPTY */
+#endif /* HAVE_OPENPTY */
+#ifdef HAVE__GETPTY
+ char *slaveret; /* Temp to hold pointer to slave */
+#endif /*HAVE__GETPTY*/
+
+#ifdef HAVE_OPENPTY
+ int slavefd;
+
+ pty_master_fd = -1;
+ debug(F100,"HAVE_OPENPTY","",0);
+ if (openpty(fd,
+ &slavefd,
+ slave,
+ (struct termios *)0,
+ (struct winsize *)0
+ )
+ ) {
+ pty_master_fd = *fd;
+ return(1);
+ }
+ close(slavefd);
+ return(0);
+
+#else /* HAVE_OPENPTY */
+
+#ifdef HAVE__GETPTY
+/*
+ This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but
+ it fails to work properly; even after calling unlockpt, root gets permission
+ denied opening the pty. The code to support _getpty should be removed if
+ Irix gets working streams ptys in favor of maintaining the least needed code
+ paths.
+*/
+ debug(F100,"HAVE__GETPTY","",0);
+ if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) {
+ *fd = -1;
+ return(PTY_GETPTY_NOPTY);
+ }
+ if (strlen(slaveret) > slavelength - 1) {
+ close(*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ } else {
+ ckstrncpy(slave, slaveret, slavelength);
+ }
+ return(0);
+
+#else /* HAVE__GETPTY */
+
+ *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */
+ if (*fd >= 0) {
+ debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0);
+ goto have_fd;
+ }
+
+#ifdef HAVE_PTMX
+ debug(F100,"HAVE_PTMX","",0);
+ *fd = open("/dev/ptmx",O_RDWR|O_NDELAY);
+ if (*fd >= 0) {
+ debug(F110,"pty_getpty()","open(/dev/ptmx) success",0);
+ goto have_fd;
+ }
+#endif /* HAVE_PTMX */
+
+ *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
+ if (*fd >= 0) {
+ debug(F110,"pty_getpty()","open(/dev/ptc) success",0);
+ goto have_fd;
+ }
+ *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
+ if (*fd >= 0)
+ debug(F110,"pty_getpty()","open(/dev/pty) success",0);
+
+ have_fd:
+ /* This would be the pty master */
+ debug(F101,"pty_getpty fd(A)","",*fd);
+ if (*fd >= 0) {
+ pty_master_fd = *fd;
+
+#ifdef HAVE_GRANTPT
+#ifdef HAVE_PTMX
+ debug(F100,"HAVE_GRANTPT","",0);
+ if (grantpt(*fd) || unlockpt(*fd))
+ return(PTY_GETPTY_STREAMS);
+#endif /* HAVE_PTMX */
+#endif /* HAVE_GRANTPT */
+
+#ifdef HAVE_PTSNAME
+ debug(F100,"HAVE_PTSNAME","",0);
+ p = (char *)ptsname(*fd);
+ debug(F110,"pty_getpty() ptsname()",p,0);
+#else
+#ifdef HAVE_TTYNAME
+ debug(F100,"HAVE_TTYNAME","",0);
+ p = ttyname(*fd);
+ debug(F110,"pty_getpty() ttyname()",p,0);
+#else
+ /* If we don't have either what do we do? */
+ return(PTY_GETPTY_NOPTY); /* punt */
+#endif /* HAVE_TTYNAME */
+#endif /* HAVE_PTSNAME */
+ if (p) {
+ if (strlen(p) > slavelength - 1) {
+ close (*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ }
+ ckstrncpy(slave, p, slavelength);
+ return(0);
+ }
+ if (fstat(*fd, &stb) < 0) {
+ close(*fd);
+ return(PTY_GETPTY_FSTAT);
+ }
+ ptynum = (int)(stb.st_rdev&0xFF);
+ sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */
+ if (strlen(slavebuf) > slavelength - 1) {
+ close(*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ }
+ debug(F110,"pty_getpty() slavebuf",slavebuf,0);
+ ckstrncpy(slave, slavebuf, slavelength);
+ return(0);
+ } else {
+ for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
+ sprintf(slavebuf,"/dev/ptyXX"); /* safe */
+ slavebuf[sizeof("/dev/pty") - 1] = *cp;
+ slavebuf[sizeof("/dev/ptyp") - 1] = '0';
+ if (stat(slavebuf, &stb) < 0)
+ break;
+ for (i = 0; i < 16; i++) {
+ slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
+ errno = 0;
+ *fd = open(slavebuf, O_RDWR|O_NDELAY);
+ if (*fd < 0) {
+ debug(F111,"pty_getpty() pty master open error",
+ slavebuf,errno);
+ continue;
+ }
+ debug(F111,"pty_getpty() found pty master",slavebuf,*fd);
+ slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
+ if (strlen(slavebuf) > slavelength -1) {
+ close(*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ }
+ ckstrncpy(slave, slavebuf, slavelength);
+ debug(F110,"pty_getpty slave name",slave,0);
+ pty_master_fd = *fd;
+ return(0);
+ }
+ }
+ return(PTY_GETPTY_NOPTY);
+ }
+#endif /*HAVE__GETPTY*/
+#endif /* HAVE_OPENPTY */
+}
+
+long
+pty_init() {
+#ifdef HAVE_PTYM
+ static char dummy;
+ debug(F100,"HAVE_PTYM","",0);
+ tty_bank = &master_name[strlen("/dev/ptym/pty")];
+ tty_num = &master_name[strlen("/dev/ptym/ptyX")];
+ slave_bank = &slave_name[strlen("/dev/pty/tty")];
+ slave_num = &slave_name[strlen("/dev/pty/ttyX")];
+#endif
+ return(0L);
+}
+
+/*
+ The following is an array of modules that should be pushed on the stream.
+ See configure.in for caviats and notes about when this array is used and not
+ used.
+*/
+#ifdef HAVE_STREAMS
+#ifndef HAVE_LINE_PUSH
+static char *push_list[] = {
+#ifdef PUSH_PTEM
+ "ptem",
+#endif
+#ifdef PUSH_LDTERM
+ "ldterm",
+#endif
+#ifdef PUSH_TTCOMPAT
+ "ttcompat",
+#endif
+ 0
+};
+#endif /* HAVE_LINE_PUSH */
+#endif /* HAVE_STREAMS */
+
+long
+pty_initialize_slave (fd) int fd; {
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+ struct termios new_termio;
+#else
+ struct sgttyb b;
+#endif /* ultrix */
+#else
+ struct sgttyb b;
+#endif /* POSIX_TERMIOS */
+ int pid;
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+ int rc;
+#endif /* ultrix */
+#endif /* POSIX_TERMIOS */
+
+ debug(F111,"pty_initialize_slave()","fd",fd);
+
+#ifdef HAVE_STREAMS
+#ifdef HAVE_LINE_PUSH
+ while (ioctl(fd,I_POP,0) == 0) ; /* Clear out any old lined's */
+
+ if (line_push(fd) < 0) {
+ debug(F110,"pty_initialize_slave()","line_push() failed",0);
+ close(fd);
+ fd = -1;
+ return(PTY_OPEN_SLAVE_LINE_PUSHFAIL);
+ }
+#else /*No line_push */
+ {
+ char **module = &push_list[0];
+ while (*module) {
+ if (ioctl(fd, I_PUSH, *(module++)) < 0) {
+ debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0);
+ return(PTY_OPEN_SLAVE_PUSH_FAIL);
+ }
+ }
+ }
+#endif /*LINE_PUSH*/
+#endif /*HAVE_STREAMS*/
+/*
+ Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set
+ explicitly. Why rlogind works at all without this on 4.3BSD is a mystery.
+*/
+#ifdef GETPGRP_ONEARG
+ pid = getpgrp(getpid());
+#else
+ pid = getpgrp();
+#endif /* GETPGRP_ONEARG */
+
+ debug(F111,"pty_initialize_slave()","pid",pid);
+
+#ifdef TIOCSPGRP
+ ioctl(fd, TIOCSPGRP, &pid);
+#endif /* TIOCSPGRP */
+
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+ tcsetpgrp(fd, pid);
+ errno = 0;
+ rc = tcgetattr(fd,&new_termio);
+ debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno);
+ if (rc == 0) {
+ new_termio.c_cc[VMIN] = 1;
+ new_termio.c_cc[VTIME] = 0;
+ rc = tcsetattr(fd,TCSANOW,&new_termio);
+ debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno);
+ }
+#endif /* ultrix */
+#endif /* POSIX_TERMIOS */
+ return(0L);
+}
+
+#ifdef WANT_UTMP
+long
+pty_logwtmp (tty, user, host) char *user, *tty, *host; {
+#ifdef HAVE_LOGWTMP
+ logwtmp(tty,user,host);
+ return(0);
+#else
+ struct utmp ut;
+ char *tmpx;
+ char utmp_id[5];
+ int loggingin = user[0]; /* Will be empty for logout */
+
+#ifndef NO_UT_HOST
+ strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif /* NO_UT_HOST */
+
+ strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
+ ut.ut_time = time(0);
+
+#ifndef NO_UT_PID
+ ut.ut_pid = getpid();
+ strncpy(ut.ut_user, user, sizeof(ut.ut_user));
+
+ tmpx = tty + strlen(tty) - 2;
+ ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL);
+ strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
+ ut.ut_pid = (loggingin ? getpid() : 0);
+ ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
+#else
+ strncpy(ut.ut_name, user, sizeof(ut.ut_name));
+#endif /* NO_UT_PID */
+
+ return(ptyint_update_wtmp(&ut, host, user));
+
+#endif /* HAVE_LOGWTMP */
+}
+#endif /* WANT_UTMP */
+
+/*
+ This routine is called twice. It's not particularly important that the
+ setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
+ rather that we have a controlling terminal at the end. It is assumed that
+ vhangup doesn't exist and confuse the process's notion of controlling
+ terminal on any system without TIOCNOTTY. That is, either vhangup() leaves
+ the controlling terminal in tact, breaks the association completely, or the
+ system provides TIOCNOTTY to get things back into a reasonable state. In
+ practice, vhangup() either breaks the association completely or doesn't
+ effect controlling terminals, so this condition is met.
+*/
+long
+pty_open_ctty(slave, fd, fc) char * slave; int *fd; int fc; {
+ int retval;
+
+ debug(F110,"pty_open_ctty() slave",slave,0);
+
+/* First, dissociate from previous terminal */
+
+ if ((retval = ptyint_void_association()) != 0) {
+ debug(F111,
+ "pty_open_ctty()",
+ "ptyint_void_association() failed",
+ retval
+ );
+ return(retval);
+ }
+#ifdef MUST_SETPGRP
+/*
+ The Ultrix (and other BSD tty drivers) require the process group
+ to be zero in order to acquire the new tty as a controlling tty.
+*/
+ setpgrp(0,0);
+ debug(F101,"pty_open_ctty MUST_SETPGRP setpgrp(0,0)","",errno);
+#endif /* MUST_SETPGRP */
+
+ errno = 0;
+ *fd = open(slave, O_RDWR);
+ debug(F111,"pty_open_ctty open(slave) fd",slave,*fd);
+ if (*fd < 0) {
+ debug(F111,"pty_open_ctty() open failure", slave, errno);
+ return(PTY_OPEN_SLAVE_OPENFAIL);
+ }
+#ifdef SOLARIS
+ /* This forces the job to have a controlling terminal. */
+ close(*fd);
+ *fd = open(slave, O_RDWR);
+ debug(F111,"pty_open_ctty close/open(slave) fd",slave,*fd);
+#ifdef DEBUG
+ /* This shows that /dev/tty exists */
+if (deblog) {
+ int x;
+ x = open("/dev/tty", O_RDWR);
+ debug(F111,"pty_open_ctty open(/dev/tty) fd",slave,x);
+ if (x < 0) debug(F111,"pty_open_ctty open(/dev/tty) errno","",errno);
+ debug(F110,"pty_open_ctty ttyname(/dev/tty)",ttyname(x),0);
+ if (x > -1) close(x);
+ }
+#endif /* DEBUG */
+#endif /* SOLARIS */
+
+#ifdef MUST_SETPGRP
+ setpgrp(0, getpid());
+#endif /* MUST_SETPGRP */
+
+#ifdef TIOCSCTTY
+ if (
+#ifdef COMMENT
+ fc == 0
+#else
+ 1
+#endif /* COMMENT */
+ ) {
+ /* TIOCSCTTY = Make this the job's controlling terminal */
+ errno = 0;
+ retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
+ debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
+ }
+#endif /* TIOCSCTTY */
+ return(0L);
+}
+
+long
+pty_open_slave(slave, fd, fc) char *slave; int *fd; int fc; {
+ int vfd, testfd;
+ long retval;
+#ifdef CK_POSIX_SIG
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask); /* Initialize "sa" structure. */
+ sa.sa_flags = 0;
+#endif /* CK_POSIX_SIG */
+
+/*
+ First, chmod and chown the slave. If we have vhangup then we really need
+ pty_open_ctty to make sure our controlling terminal is the pty we're
+ opening. However, if we are using revoke or nothing then we just need a
+ file descriiptor for the pty. Considering some OSes in this category break
+ on the second call to open_ctty (currently OSF but others may), we simply
+ use a descriptor if we can.
+*/
+#ifdef VHANG_FIRST
+ if ((retval = pty_open_ctty(slave, &vfd, fc)) != 0) {
+ debug(F111,
+ "pty_open_slave() VHANG_FIRST",
+ "pty_open_ctty() failed",
+ retval
+ );
+ return(retval);
+ }
+ if (vfd < 0) {
+ debug(F111,
+ "pty_open_slave() VHANG_FIRST",
+ "PTY_OPEN_SLAVE_OPENFAIL",
+ vfd
+ );
+ return(PTY_OPEN_SLAVE_OPENFAIL);
+ }
+#endif /* VHANG_FIRST */
+
+ if (slave == NULL || *slave == '\0') {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0);
+ return(PTY_OPEN_SLAVE_TOOSHORT);
+ }
+
+#ifdef SETUID
+ if (chmod(slave, 0)) {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0);
+ return(PTY_OPEN_SLAVE_CHMODFAIL);
+ }
+ if (chown(slave, 0, 0 ) == -1 ) {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0);
+ return(PTY_OPEN_SLAVE_CHOWNFAIL);
+ }
+#endif /* SETUID */
+#ifdef VHANG_FIRST
+ ptyint_vhangup();
+ close(vfd);
+#endif /* VHANG_FIRST */
+
+ if ((retval = ptyint_void_association()) != 0) {
+ debug(F111,
+ "pty_open_slave()",
+ "ptyint_void_association() failed",
+ retval
+ );
+ return(retval);
+ }
+
+#ifdef HAVE_REVOKE
+ if (revoke (slave) < 0 ) {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0);
+ return(PTY_OPEN_SLAVE_REVOKEFAIL);
+ }
+#endif /* HAVE_REVOKE */
+
+/* Open the pty for real. */
+
+ retval = pty_open_ctty(slave, fd, fc);
+ debug(F111,"pty_open_slave retval",slave,retval);
+ debug(F111,"pty_open_slave fd",slave,*fd);
+ if (retval != 0) {
+ debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
+ return(PTY_OPEN_SLAVE_OPENFAIL);
+ }
+ pty_slave_fd = *fd; /* This is not visible to the upper fork */
+ debug(F111,"pty_open_slave fd ctty'd",slave,pty_slave_fd);
+ retval = pty_initialize_slave(*fd);
+ debug(F111,"pty_open_slave fd init'd",slave,pty_slave_fd);
+ if (retval) {
+ debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
+ return(retval);
+ }
+ /* (VOID)pty_make_raw(*fd); */
+
+ debug(F100,"pty_open_slave OK","",*fd);
+ return(0L);
+}
+
+#ifdef WANT_UTMP
+
+#ifndef UTMP_FILE
+#ifdef _PATH_UTMP
+#define UTMP_FILE _PATH_UTMP
+#endif /* _PATH_UTMP */
+#endif /* UTMP_FILE */
+
+/* If it is *still* missing, assume /etc/utmp */
+
+#ifndef UTMP_FILE
+#define UTMP_FILE "/etc/utmp"
+#endif /* UTMP_FILE */
+
+#ifndef NO_UT_PID
+#define WTMP_REQUIRES_USERNAME
+#endif /* NO_UT_PID */
+
+long
+pty_update_utmp(process_type, pid, username, line, host, flags)
+ int process_type;
+ int pid;
+ char *username, *line, *host;
+ int flags;
+/* pty_update_utmp */ {
+ struct utmp ent, ut;
+#ifndef HAVE_SETUTENT
+ struct stat statb;
+ int tty;
+#endif /* HAVE_SETUTENT */
+#ifdef HAVE_SETUTXENT
+ struct utmpx utx;
+#endif /* HAVE_SETUTXENT */
+#ifndef NO_UT_PID
+ char *tmpx;
+ char utmp_id[5];
+#endif /* NO_UT_PID */
+ char userbuf[32];
+ int fd;
+
+ debug(F100,"pty_update_utmp()","",0);
+ strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
+ ent.ut_time = time(0);
+
+#ifdef NO_UT_PID
+ if (process_type == PTY_LOGIN_PROCESS)
+ return(0L);
+#else /* NO_UT_PID */
+
+ ent.ut_pid = pid;
+
+ switch (process_type) {
+ case PTY_LOGIN_PROCESS:
+ ent.ut_type = LOGIN_PROCESS;
+ break;
+ case PTY_USER_PROCESS:
+ ent.ut_type = USER_PROCESS;
+ break;
+ case PTY_DEAD_PROCESS:
+ ent.ut_type = DEAD_PROCESS;
+ break;
+ default:
+ return(PTY_UPDATE_UTMP_PROCTYPE_INVALID);
+ }
+#endif /*NO_UT_PID*/
+
+#ifndef NO_UT_HOST
+ if (host)
+ strncpy(ent.ut_host, host, sizeof(ent.ut_host));
+ else
+ ent.ut_host[0] = '\0';
+#endif /* NO_UT_HOST */
+
+#ifndef NO_UT_PID
+ if (!strcmp (line, "/dev/console")) {
+ char * s = NULL;
+
+#ifdef sun
+#ifdef __SVR4
+ s = "co";
+#else
+ s = "cons";
+#endif /* __SVR4 */
+#else
+ s = "cons";
+#endif /* sun */
+
+ strncpy(ent.ut_id, s, 4);
+
+ } else {
+
+ tmpx = line + strlen(line)-1;
+ if (*(tmpx-1) != '/') tmpx--; /* last 2 chars unless it's a '/' */
+#ifdef __hpux
+ ckstrncpy(utmp_id, tmpx, 5);
+#else
+ ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL);
+#endif /* __hpux */
+ strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
+ }
+ strncpy(ent.ut_user, username, sizeof(ent.ut_user));
+
+#else
+
+ strncpy(ent.ut_name, username, sizeof(ent.ut_name));
+
+#endif /* NO_UT_PID */
+
+ if (username[0])
+ strncpy(userbuf, username, sizeof(userbuf));
+ else
+ userbuf[0] = '\0';
+
+#ifdef HAVE_SETUTENT
+
+ utmpname(UTMP_FILE);
+ setutent();
+/*
+ If we need to preserve the user name in the wtmp structure and Our flags
+ tell us we can obtain it from the utmp and we succeed in obtaining it, we
+ then save the utmp structure we obtain, write out the utmp structure and
+ change the username pointer so it is used by update_wtmp.
+*/
+
+#ifdef WTMP_REQUIRES_USERNAME
+ if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) {
+ struct utmp *utptr;
+ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ utptr = getutline(&ut);
+ if (utptr)
+ strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
+ }
+#endif /* WTMP_REQUIRES_USERNAME */
+
+ pututline(&ent);
+ endutent();
+
+#ifdef HAVE_SETUTXENT
+ setutxent();
+#ifdef HAVE_GETUTMPX
+ getutmpx(&ent, &utx);
+#else /* HAVE_GETUTMPX */
+ /* For platforms like HPUX and Dec Unix which don't have getutmpx */
+ strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
+ strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
+ strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
+ utx.ut_pid = pid; /* kludge for Irix, etc. to avoid trunc. */
+ utx.ut_type = ent.ut_type;
+#ifdef UT_EXIT_STRUCTURE_DIFFER
+ utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
+#else /* UT_EXIT_STRUCTURE_DIFFER */
+/* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
+#ifdef __hpux
+ utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
+ utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
+#else /* __hpux */
+ /* XXX do nothing for now; we don't even know the struct member exists */
+#endif /* __hpux */
+#endif /* UT_EXIT_STRUCTURE_DIFFER */
+ utx.ut_tv.tv_sec = ent.ut_time;
+ utx.ut_tv.tv_usec = 0;
+#endif /* HAVE_GETUTMPX */
+ if (host)
+ strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+ else
+ utx.ut_host[0] = 0;
+ pututxline(&utx);
+ endutxent();
+#endif /* HAVE_SETUTXENT */
+
+#else /* HAVE_SETUTENT */
+ if (flags&PTY_TTYSLOT_USABLE) {
+ tty = ttyslot();
+ } else {
+ int lc;
+ tty = -1;
+ if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
+ return(errno);
+ for (lc = 0;
+ lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
+ lc++
+ ) {
+ if (read(fd,
+ (char *)&ut,
+ sizeof(struct utmp)
+ ) != sizeof(struct utmp)
+ )
+ break;
+ if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
+ tty = lc;
+#ifdef WTMP_REQUIRES_USERNAME
+ if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
+ strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
+#endif /* WTMP_REQUIRES_USERNAME */
+ break;
+ }
+ }
+ close(fd);
+ }
+ if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
+ lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
+ write(fd, (char *)&ent, sizeof(struct utmp));
+ close(fd);
+ }
+#endif /* HAVE_SETUTENT */
+
+ /* Don't record LOGIN_PROCESS entries. */
+ if (process_type == PTY_LOGIN_PROCESS)
+ return(0);
+ else
+ return(ptyint_update_wtmp(&ent, host, userbuf));
+}
+#ifndef WTMP_FILE
+#ifdef _PATH_WTMP
+#define WTMP_FILE _PATH_WTMP
+#endif /* _PATH_WTMP */
+#endif /* WTMP_FILE */
+
+#ifndef WTMPX_FILE
+#ifdef _PATH_WTMPX
+#ifdef HAVE_UPDWTMPX
+#define WTMPX_FILE _PATH_WTMPX
+#endif /* HAVE_UPDWTMPX */
+#endif /* _PATH_WTMPX */
+#endif /* WTMPX_FILE */
+
+/* If it is *still* missing, assume /usr/adm/wtmp */
+
+#ifndef WTMP_FILE
+#define WTMP_FILE "/usr/adm/wtmp"
+#endif /* WTMP_FILE */
+
+#ifdef COMMENT
+/* The following test can not be made portably */
+
+/* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */
+/*
+ This is ugly, but the lack of standardization in the utmp/utmpx space, and
+ what glibc implements and doesn't make available, is even worse.
+*/
+/* #undef HAVE_UPDWTMPX */ /* Don't use updwtmpx for glibc 2.1 */
+/* #endif */ /* __GLIBC__ etc */
+
+#else /* COMMENT */
+
+#ifdef __GLIBC__
+#undef HAVE_UPDWTMPX /* Don't use updwtmpx for glibc period */
+#endif /* __GLIBC__ */
+#endif /* COMMENT */
+
+long
+ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; {
+ struct utmp ut;
+ struct stat statb;
+ int fd;
+ time_t uttime;
+#ifdef HAVE_UPDWTMPX
+ struct utmpx utx;
+
+ getutmpx(ent, &utx);
+ if (host)
+ strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
+ else
+ utx.ut_host[0] = 0;
+ if (user)
+ strncpy(utx.ut_user, user, sizeof(utx.ut_user));
+ updwtmpx(WTMPX_FILE, &utx);
+#endif /* HAVE_UPDWTMPX */
+
+#ifdef HAVE_UPDWTMP
+#ifndef HAVE_UPDWTMPX
+ /* This is already performed byupdwtmpx if present.*/
+ updwtmp(WTMP_FILE, ent);
+#endif /* HAVE_UPDWTMPX*/
+#else /* HAVE_UPDWTMP */
+
+ if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
+ if (!fstat(fd, &statb)) {
+ memset((char *)&ut, 0, sizeof(ut));
+#ifdef __hpux
+ strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
+#endif /* __hpux */
+ strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
+ strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
+#ifndef NO_UT_HOST
+ strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
+#endif /* NO_UT_HOST */
+
+ time(&uttime);
+ ut.ut_time = uttime;
+
+#ifdef HAVE_GETUTENT
+#ifdef USER_PROCESS
+ if (ent->ut_name) {
+ if (!ut.ut_pid)
+ ut.ut_pid = getpid();
+#ifndef __hpux
+ ut.ut_type = USER_PROCESS;
+#else /* __hpux */
+ ut.ut_type = ent->ut_type;
+#endif /* __hpux */
+
+ } else {
+
+#ifdef EMPTY
+ ut.ut_type = EMPTY;
+#else
+ ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
+#endif /* EMPTY */
+
+ }
+#endif /* USER_PROCESS */
+#endif /* HAVE_GETUTENT */
+
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+#ifndef COHERENT
+ ftruncate(fd, statb.st_size);
+#else
+ chsize(fd, statb.st_size);
+#endif /* COHERENT */
+ }
+ close(fd);
+ }
+#endif /* HAVE_UPDWTMP */
+ return(0); /* no current failure cases; file not found is not failure! */
+}
+#endif /* WANT_UTMP */
+
+/* This is for ancient Unixes that don't have these tty symbols defined. */
+
+#ifndef PENDIN
+#define PENDIN ICANON
+#endif /* PENDIN */
+#ifndef FLUSHO
+#define FLUSHO ICANON
+#endif /* FLUSHO */
+#ifndef IMAXBEL
+#define IMAXBEL ICANON
+#endif /* IMAXBEL */
+#ifndef EXTPROC
+#define EXTPROC ICANON
+#endif /* EXTPROC */
+
+static char Xline[17] = { 0, 0 };
+/*
+ getptyslave()
+ Open the slave side of the pty, and do any initialization that is necessary.
+ The return value fd is a file descriptor for the slave side.
+ fc = function code from do_pty() (q.v.)
+*/
+int
+getptyslave(fd, fc) int * fd, fc; {
+ int ttyfd;
+ int t = -1;
+ long retval;
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ extern int cmd_rows, cmd_cols;
+#endif /* TIOCGWINSZ */
+
+ ttyfd = *fd;
+ debug(F111,"getptyslave()","ttyfd",ttyfd);
+ /*
+ * Opening the slave side may cause initilization of the
+ * kernel tty structure. We need remember the state of:
+ * if linemode was turned on
+ * terminal window size
+ * terminal speed
+ * so that we can reset them if we need to.
+ */
+ if ((retval = pty_open_slave(Xline, &t, fc)) != 0) {
+ perror(Xline);
+ msg++;
+ debug(F111,"getptyslave()","Unable to open slave",retval);
+ return(-1);
+ }
+ debug(F111,"getptyslave","t",t);
+#ifdef INIT_SPTY
+ spty = t;
+ debug(F111,"getptyslave","spty",spty);
+#endif /* INIT_SPTY */
+#ifdef STREAMSPTY
+ if (ioctl(t,I_PUSH,"pckt") < 0) {
+ debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno);
+#ifndef _AIX
+ fatal("I_PUSH pckt");
+#endif /* _AIX */
+ }
+#endif /* STREAMSPTY */
+
+ /* Set up the tty modes as we like them to be. */
+#ifdef COMMENT
+ /* Originally like this... But this is the master - we want the slave */
+ /* Anyway, this fails on Solaris and probably other System V OS's */
+ init_termbuf(ttyfd);
+#else
+ init_termbuf(t);
+#endif /* COMMENT */
+#ifdef TIOCGWINSZ
+ if (cmd_rows || cmd_cols) {
+ memset((char *)&ws, 0, sizeof(ws));
+ ws.ws_col = cmd_cols;
+ ws.ws_row = cmd_rows;
+ debug(F101,"getptyslave() doing TIOCSWINSZ...","",t);
+ ioctl(t, TIOCSWINSZ, (char *)&ws);
+ }
+#endif /* TIOCGWINSZ */
+
+ /* For external protocols, put the pty in no-echo mode */
+ if (fc == 1) {
+ debug(F100,"getptyslave() setting rawmode","",0);
+ /* iflags */
+ termbuf.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
+ termbuf.c_iflag &= ~(INPCK|IGNPAR|IMAXBEL|IXANY|IXON|IXOFF);
+ termbuf.c_iflag |= IGNBRK;
+#ifdef IUCLC
+ termbuf.c_iflag &= ~IUCLC;
+#endif /* IUCLC */
+
+ /* oflags */
+ termbuf.c_oflag &= ~OPOST;
+#ifdef OXTABS
+ termbuf.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+#ifdef ONOCR
+ termbuf.c_oflag &= ~ONOCR;
+#endif /* ONOCR */
+#ifdef ONLRET
+ termbuf.c_oflag &= ~ONLRET;
+#endif /* ONLRET */
+#ifdef ONLCR
+ termbuf.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+
+ /* lflags */
+ termbuf.c_lflag &= ~ECHO;
+#ifdef ECHOE
+ termbuf.c_lflag &= ~ECHOE;
+#endif /* ECHOE */
+#ifdef ECHONL
+ termbuf.c_lflag &= ~ECHONL;
+#endif /* ECHONL */
+#ifdef ECHOPRT
+ termbuf.c_lflag &= ~ECHOPRT;
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ termbuf.c_lflag &= ~ECHOKE;
+#endif /* ECHOKE */
+#ifdef ECHOCTL
+ termbuf.c_lflag &= ~ECHOCTL;
+#endif /* ECHOCTL */
+#ifdef ALTWERASE
+ termbuf.c_lflag &= ~ALTWERASE;
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ termbuf.c_lflag &= ~EXTPROC;
+#endif /* EXTPROC */
+ termbuf.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
+
+#ifdef NOKERNINFO
+ termbuf.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+ /* termbuf.c_lflag |= NOFLSH; */
+ termbuf.c_lflag &= ~NOFLSH;
+
+ /* cflags */
+ termbuf.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ termbuf.c_cflag |= CS8|CREAD;
+#ifdef VMIN
+ termbuf.c_cc[VMIN] = 1;
+#endif /* VMIN */
+ } else { /* Regular interactive use */
+ debug(F100,"getptyslave() setting cooked mode","",0);
+
+ /* Settings for sgtty based systems */
+
+#ifndef USE_TERMIO
+ termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
+#endif /* USE_TERMIO */
+
+#ifndef OXTABS
+#define OXTABS 0
+#endif /* OXTABS */
+
+ /* Settings for UNICOS and HPUX */
+
+#ifdef CRAY
+ termbuf.c_oflag = OPOST|ONLCR|TAB3;
+ termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
+ termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+ termbuf.c_cflag = EXTB|HUPCL|CS8;
+#else /* CRAY */
+#ifdef HPUX
+ termbuf.c_oflag = OPOST|ONLCR|TAB3;
+ termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
+ termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+ termbuf.c_cflag = EXTB|HUPCL|CS8;
+#else /* HPUX */
+#ifdef USE_TERMIO
+ /*
+ Settings for all other termios/termio based systems, other than
+ 4.4BSD. In 4.4BSD the kernel does the initial terminal setup.
+ */
+#ifdef BSD42
+#ifndef BSD44
+ termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
+ termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
+ termbuf.c_iflag |= ICRNL|IGNPAR;
+ termbuf.c_cflag |= HUPCL;
+ termbuf.c_iflag &= ~IXOFF;
+#endif /* BSD44 */
+#else /* BSD42 */
+ termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
+ termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
+ termbuf.c_iflag |= ICRNL|IGNPAR;
+ termbuf.c_cflag |= HUPCL;
+ termbuf.c_iflag &= ~IXOFF;
+#endif /* BSD42 */
+#endif /* USE_TERMIO */
+#endif /* HPUX */
+#endif /* CRAY */
+ }
+
+ /* Set the tty modes, and make this our controlling tty. */
+#ifdef COMMENT
+ /* But this is the master - we want the slave */
+ set_termbuf(ttyfd);
+#else
+ set_termbuf(t);
+#endif /* COMMENT */
+
+ if (t != 0)
+ dup2(t, 0);
+ if (t != 1)
+ dup2(t, 1);
+ if (t != 2) {
+ if (fc == 0) {
+ dup2(t, 2);
+ } else if (fc == 1) {
+ /* For external protocols, send stderr to /dev/null */
+#ifdef COMMENT
+ int xx;
+#ifndef COMMENT
+ char * s = "/dev/null";
+ errno = 0;
+ xx = open(s, O_WRONLY);
+#else
+ char * s = "pty.log";
+ errno = 0;
+ xx = open(s, O_CREAT, 0644);
+#endif /* COMMENT */
+ debug(F111,"getptyslave redirect stderr",s,errno);
+ dup2(xx,2);
+#endif /* COMMENT */
+ }
+ }
+ if (t > 2)
+ close(t);
+
+ if (ttyfd > 2) {
+ close(ttyfd);
+ ttyfd = -1;
+ *fd = ttyfd;
+ }
+ return(0);
+}
+
+#ifdef HAVE_PTYTRAP
+/*
+ To be called to determine if a trap is pending on a pty
+ if and only if select() cannot be used.
+*/
+int
+pty_trap_pending(fd) int fd; {
+ int pending;
+ int rc;
+
+ rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending));
+ if (rc == 0) {
+ debug(F101,"pty_trap_pending()","",pending);
+ return(pending);
+ } else {
+ debug(F111,"pty_trap_pending()","ioctl() failed",rc);
+ return(-1);
+ }
+}
+
+/*
+ To be called after select() has returned indicating that an exception is
+ waiting on a pty. It should be called with the file descriptor of the pty.
+ Returns -1 on error; 0 if pty is still open; 1 if pty has closed.
+*/
+int
+pty_trap_handler(fd) int fd; {
+ struct request_info ri;
+
+ memset(&ri,0,sizeof(ri));
+ if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) {
+ debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno);
+ return(-1);
+ }
+ switch (ri.request) {
+ case TIOCOPEN:
+ debug(F110,"pty_trap_handler()","an open() call",0);
+ break;
+ case TIOCCLOSE:
+ debug(F110,"pty_trap_handler()","a close() call",0);
+ break;
+ default:
+ debug(F110,"pty_trap_handler()","an ioctl() call",0);
+ ri.errno_error = EINVAL;
+ }
+ if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) {
+ debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno);
+ return(-1);
+ }
+ if (ri.request == TIOCCLOSE)
+ return(1);
+ else
+ return(0);
+}
+#endif /* HAVE_PTYTRAP */
+
+VOID
+exec_cmd(s) char * s; {
+ struct stringarray * q;
+ char ** args = NULL;
+
+ if (!s) return;
+ if (!*s) return;
+
+ q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
+ if (!q) return;
+
+ args = q->a_head + 1;
+
+#ifdef DEBUG
+ {
+ int i, n;
+ n = q->a_size;
+ for (i = 0; i <= n; i++) {
+ if (!args[i]) {
+ debug(F111,"exec_cmd arg","NULL",i);
+ break;
+ } else {
+ debug(F111,"exec_cmd arg",args[i],i);
+ if (i == n && args[i]) {
+ debug(F101,"exec_cmd SUBSTITUTING NULL","",i);
+ if (strlen(args[i]) == 0)
+ makestr(&(args[i]),NULL);
+ }
+
+ }
+ }
+ }
+#endif /* DEBUG */
+
+ execvp(args[0],args);
+}
+
+/* Get a pty, scan input lines. */
+/* fc = 0 for interactive access; fc = 1 for running external protocols */
+
+static int pty_fc = -1; /* Global copy of fc */
+
+int
+do_pty(fd, cmd, fc) int * fd; char * cmd; int fc; {
+ long retval;
+ int syncpipe[2];
+ int i, ttyfd;
+#ifdef HAVE_PTYTRAP
+ int x;
+#endif /* HAVE_PTYTRAP */
+
+ debug(F101,"CKUPTY.C do_pty fc","",fc);
+
+ ttyfd = *fd;
+
+ pty_master_fd = -2;
+ pty_slave_fd = -2;
+ pty_fork_pid = -2;
+
+ msg = 0; /* Message counter */
+ pty_init(); /* Find an available pty to use. */
+ errno = 0;
+
+ if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) {
+ if (msg++ == 0)
+ perror(Xline);
+ debug(F111,"do_pty()","pty_getpty() fails",retval);
+ *fd = ttyfd;
+ return(-1);
+ }
+ *fd = ttyfd;
+ debug(F111,"do_pty() Xline",Xline,ttyfd);
+
+#ifdef SIGTTOU
+/*
+ Ignoring SIGTTOU keeps the kernel from blocking us. we tweak the tty with
+ an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel)
+*/
+ signal(SIGTTOU, SIG_IGN);
+#endif /* SIGTTOU */
+
+/* Start up the command on the slave side of the terminal */
+
+ if (pipe(syncpipe) < 0) {
+ debug(F110,"do_pty()","pipe() fails",0);
+ perror("pipe() failed");
+ msg++;
+ debug(F111,"do_pty()","pipe fails",errno);
+ return(-1);
+ }
+ if ((i = fork()) < 0) {
+ /* XXX - need to clean up the allocated pty */
+ perror("fork() failed");
+ msg++;
+ debug(F111,"do_pty()","fork fails",errno);
+ return(-1);
+ }
+ if (i) { /* Wait for child before writing to parent side of pty. */
+ char c;
+#ifdef HAVE_PTYTRAP
+ int on = 1;
+#endif /* HAVE_PTYTRAP */
+ close(syncpipe[1]);
+ errno = 0;
+ if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */
+ perror("Pipe read() failed");
+ msg++;
+ debug(F110,"do_pty()","Slave fails to initialize",0);
+ close(syncpipe[0]);
+ return(-1);
+ }
+ pty_fork_pid = i; /* So we can clean it up later */
+ pty_fork_active = 1;
+ debug(F101,"do_pty pty_fork_pid","",pty_fork_pid);
+#ifdef HAVE_PTYTRAP
+ /* HPUX does not allow the master to read end of file. */
+ /* Therefore, we must determine that the slave has been */
+ /* closed by trapping the call to close(). */
+ errno = 0;
+ x = ioctl(ttyfd, TIOCTRAP, (char *)&on);
+ debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno);
+#endif /* HAVE_PTYTRAP */
+ debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid);
+ close(syncpipe[0]);
+ } else {
+ int x;
+ debug(F101,"do_pty getptyslave ttyfd A","",ttyfd);
+ debug(F110,"do_pty()","Slave starts",0);
+ x = getptyslave(&ttyfd,fc);
+ debug(F101,"do_pty getptyslave","",x);
+ if (x == 0) {
+ debug(F101,"do_pty getptyslave ttyfd B","",ttyfd);
+#ifdef WANT_UTMP
+ pty_update_utmp(PTY_USER_PROCESS,
+ getpid(),
+ "KERMIT",
+ Xline,
+ cmd,
+ PTY_TTYSLOT_USABLE
+ );
+#endif /* WANT_UTMP */
+ /* Notify our parent we're ready to continue.*/
+ debug(F110,"do_pty()","slave synchronizing",0);
+ write(syncpipe[1],"y",1);
+ close(syncpipe[0]);
+ close(syncpipe[1]);
+
+ debug(F110,"do_pty cmd",cmd,"");
+ exec_cmd(cmd);
+ debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
+ }
+ *fd = ttyfd;
+ debug(F110,"do_pty()","getptyslave() fails - exiting",0);
+ exit(1);
+ }
+ *fd = ttyfd;
+ pty_fc = fc;
+ return(getpid());
+} /* end of do_pty() */
+
+
+VOID
+end_pty() {
+ msg = 0; /* Message counter */
+ debug(F101,"end_pty pty_fork_pid","",pty_fork_pid);
+ if (Xline[0] && pty_fork_pid >= 0) {
+ pty_cleanup(Xline,pty_fork_pid,1);
+ Xline[0] = '\0';
+ pty_fork_pid = -1;
+ pty_fork_active = 0;
+ debug(F101,"end_pty pty_fork_active","",pty_fork_active);
+ }
+ pty_fc = -1;
+}
+#endif /* NETPTY */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.c.c99 b/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.c.c99
new file mode 100644
index 0000000..9906555
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.c.c99
@@ -0,0 +1,1979 @@
+char *ckptyv = "Pseudoterminal support, 9.0.101, 13 Jun 2011";
+
+/* C K U P T Y -- C-Kermit pseudoterminal control functions for UNIX */
+
+/* Last update: Mon Jun 13 11:32:52 2011 */
+
+/*
+ Copyright 1995 by the Massachusetts Institute of Technology.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of M.I.T. not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission. Furthermore if you modify this software you must
+ label your software as modified software and not distribute it in such a
+ fashion that it might be confused with the original M.I.T. software.
+ M.I.T. makes no representations about the suitability of this software for
+ any purpose. It is provided "as is" without express or implied warranty.
+
+ Modified for use in C-Kermit, and new material added, by:
+
+ Jeffrey Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+ November 1999
+
+ Parameterized for pty file descriptor and function code,
+ Frank da Cruz, Columbia University, New York City
+ Dec 2006 - Sep 2009
+*/
+
+/*
+ Built and tested successully on:
+ . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X
+ . AIX 4.1 and later
+ . DG/UX 5.4R4.11
+ . Digital UNIX 3.2 and 4.0
+ . HP-UX 9.00 and later
+ . IRIX 6.0 and later
+ . Linux
+ . Mac OS X 10.4
+ . NeXTSTEP 3.x
+ . OpenBSD
+ . QNX 4.25 (except PTY process termination not detected)
+ . SCO OSR5.0.5
+ . SCO Unixware 7
+ . SINIX 5.42
+ . Solaris 2.x and 7
+ . SunOS 4.1.3
+
+ Failures include:
+ . SCO UNIX 3.2v4.2 (compile fails with syntax error in <memory.h>)
+ . HP-UX 8.00 and earlier (no vhangup or ptsname routines)
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h" /* To pick up NETPTY definition */
+
+#ifndef NETPTY /* Selector for PTY support */
+
+char * ptyver = "No PTY support";
+
+#else /* (rest of this module...) */
+
+char * ptyver = "PTY support 8.0.016, 22 Aug 2007";
+
+/* These will no doubt need adjustment... */
+
+#ifndef NEXT
+#define HAVE_SETSID
+#endif /* NEXT */
+#define HAVE_KILLPG
+#define HAVE_TTYNAME
+#define HAVE_WAITPID
+
+#ifdef SUNOS41
+#define BSD44ORPOSIX
+#endif /* SUNOS41 */
+
+#ifndef USE_TERMIO
+#ifdef LINUX
+#define USE_TERMIO
+#else
+#ifdef ATTSV
+#define USE_TERMIO
+#else
+#ifdef HPUX
+#define USE_TERMIO
+#else
+#ifdef AIX
+#define USE_TERMIO
+#else
+#ifdef BSD44ORPOSIX
+#define USE_TERMIO
+#else
+#ifdef IRIX60
+#define USE_TERMIO
+#else
+#ifdef QNX
+#define USE_TERMIO
+#endif /* QNX */
+#endif /* IRIX60 */
+#endif /* BSD44ORPOSIX */
+#endif /* AIX */
+#endif /* HPUX */
+#endif /* ATTSV */
+#endif /* LINUX */
+#endif /* USE_TERMIO */
+
+#ifdef QNX
+#include <fcntl.h>
+#endif /* QNX */
+
+#ifdef USE_TERMIO
+#define POSIX_TERMIOS /* Seems to be a misnomer */
+#endif /* USE_TERMIO */
+
+#ifdef NEXT
+#ifndef GETPGRP_ONEARG
+#define GETPGRP_ONEARG
+#endif /* GETPGRP_ONEARG */
+#endif /* NEXT */
+
+#ifdef WANT_UTMP /* See ckupty.h */
+/*
+ WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most
+ nonportable part of this module, and (b) we're not logging anybody
+ in, we're just running a process, and don't need to write utmp/wtmp records.
+*/
+#ifndef HAVE_SETUTXENT /* Who has <utmpx.h> */
+#ifdef SOLARIS
+#define HAVE_SETUTXENT
+#else
+#ifdef IRIX60
+#define HAVE_SETUTXENT
+#else
+#ifdef CK_SCOV5
+#define HAVE_SETUTXENT
+#else
+#ifdef HPUX10
+#define HAVE_SETUTXENT
+#else
+#ifdef UNIXWARE
+#define HAVE_SETUTXENT
+#else
+#ifdef IRIX60
+#define HAVE_SETUTXENT
+#endif /* IRIX60 */
+#endif /* UNIXWARE */
+#endif /* HPUX10 */
+#endif /* CK_SCOV5 */
+#endif /* IRIX60 */
+#endif /* SOLARIS */
+#endif /* HAVE_SETUTXENT */
+
+#ifndef HAVE_UTHOST /* Does utmp include ut_host[]? */
+#ifdef HAVE_SETUTXENT /* utmpx always does */
+#define HAVE_UTHOST
+#else
+#ifdef LINUX /* Linux does */
+#define HAVE_UTHOST
+#else
+#ifdef SUNOS4 /* SunOS does */
+#define HAVE_UTHOST
+#else
+#ifdef AIX41 /* AIX 4.1 and later do */
+#define HAVE_UTHOST
+#endif /* AIX41 */
+#endif /* SUNOS4 */
+#endif /* LINUX */
+#endif /* HAVE_SETUTXENT */
+#endif /* HAVE_UTHOST */
+
+#ifndef HAVE_UT_HOST
+#ifndef NO_UT_HOST
+#define NO_UT_HOST
+#endif /* NO_UT_HOST */
+#endif /* HAVE_UT_HOST */
+
+#endif /* WANT_UTMP */
+
+#ifdef LINUX
+#define CK_VHANGUP
+#define HAVE_SYS_SELECT_H
+#define HAVE_GETUTENT
+#define HAVE_SETUTENT
+#define HAVE_UPDWTMP
+#endif /* LINUX */
+
+#ifdef HPUX10
+#define CK_VHANGUP
+#define VHANG_FIRST
+#define HAVE_PTSNAME
+#ifndef HAVE_PTYTRAP
+#define HAVE_PTYTRAP
+#endif /* HAVE_PTYTRAP */
+#else
+#ifdef HPUX9
+#define CK_VHANGUP
+#define VHANG_FIRST
+#define HAVE_PTSNAME
+#ifndef HAVE_PTYTRAP
+#define HAVE_PTYTRAP
+#endif /* HAVE_PTYTRAP */
+#endif /* HPUX9 */
+#endif /* HPUX10 */
+
+#ifdef SUNOS4
+#define CK_VHANGUP
+#define NO_UT_PID
+#define VHANG_FIRST
+#endif /* SUNOS4 */
+
+#ifdef IRIX60
+#define CK_VHANGUP
+#define HAVE__GETPTY
+#endif /* IRIX60 */
+
+#ifdef SINIX
+#define HAVE_STREAMS
+#define HAVE_GRANTPT
+#define HAVE_PTSNAME
+#define PUSH_PTEM
+#define PUSH_LDTERM
+#define PUSH_TTCOMPAT
+#endif /* SINIX */
+
+#ifdef ultrix
+#define MUST_SETPGRP
+#endif /* ultrix */
+
+#ifdef QNX
+#define MUST_SETPGRP
+#define NO_DEVTTY
+#define INIT_SPTY
+#endif /* QNX */
+
+#ifdef LINUX
+#ifdef HAVE_PTMX
+#define HAVE_GRANTPT
+#define HAVE_PTSNAME
+#endif /* HAVE_PTMX */
+#else
+#ifdef HAVE_STREAMS
+#define HAVE_PTMX
+#endif /* HAVE_STREAMS */
+#endif /* LINUX */
+
+#include "ckupty.h"
+
+#ifdef PTYNOBLOCK
+#ifndef O_NDELAY
+#ifdef O_NONBLOCK
+#define O_NDELAY O_NONBLOCK
+#endif /* O_NONBLOCK */
+#endif /* O_NDELAY */
+#else /* PTYNOBLOCK */
+#ifdef O_NDELAY
+#undef O_NDELAY
+#endif /* O_NDELAY */
+#define O_NDELAY 0
+#endif /* PTYNOBLOCK */
+
+#ifndef ONLCR
+#define ONLCR 0
+#endif /* ONLCR */
+
+#ifdef CK_WAIT_H
+#include <sys/wait.h>
+#endif /* CK_WAIT_H */
+
+#ifdef STREAMSPTY
+#ifndef INIT_SPTY
+#define INIT_SPTY
+#endif /* INIT_SPTY */
+
+#include <sys/stream.h>
+#include <stropts.h>
+#include <termio.h>
+
+/* Make sure we don't get the BSD version */
+
+#ifdef HAVE_SYS_TTY_H
+#include "/usr/include/sys/tty.h"
+#endif /* HAVE_SYS_TTY_H */
+
+#ifdef HAS_PTYVAR /* Where is this set? */
+
+#include <sys/ptyvar.h>
+
+#else /* HAS_PTYVAR */
+
+#ifndef TIOCPKT_FLUSHWRITE
+#define TIOCPKT_FLUSHWRITE 0x02
+#define TIOCPKT_NOSTOP 0x10
+#define TIOCPKT_DOSTOP 0x20
+#define TIOCPKT_IOCTL 0x40
+#endif /* TIOCPKT_FLUSHWRITE */
+
+#endif /* HAS_PTYVAR */
+
+#ifdef HAVE_TTY_H
+#include <tty.h>
+#endif /* HAVE_TTY_H */
+
+/*
+ Because of the way ptyibuf is used with streams messages, we need
+ ptyibuf+1 to be on a full-word boundary. The following weirdness
+ is simply to make that happen.
+*/
+long ptyibufbuf[BUFSIZ/sizeof(long)+1];
+char *ptyibuf = ((char *)&ptyibufbuf[1])-1;
+char *ptyip = ((char *)&ptyibufbuf[1])-1;
+char ptyibuf2[BUFSIZ];
+unsigned char ctlbuf[BUFSIZ];
+struct strbuf strbufc, strbufd;
+
+int readstream();
+
+#else /* ! STREAMSPTY */
+
+/* I/O data buffers, pointers, and counters. */
+
+char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char ptyibuf2[BUFSIZ];
+
+#endif /* ! STREAMSPTY */
+
+#ifndef USE_TERMIO
+struct termbuf {
+ struct sgttyb sg;
+ struct tchars tc;
+ struct ltchars ltc;
+ int state;
+ int lflags;
+} termbuf, termbuf2;
+
+#define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val)
+#define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val)
+#define cfgetospeed(tp) (tp)->sg.sg_ospeed
+#define cfgetispeed(tp) (tp)->sg.sg_ispeed
+
+#else /* USE_TERMIO */
+
+#ifdef SYSV_TERMIO
+#define termios termio
+#endif /* SYSV_TERMIO */
+
+#ifndef TCSANOW
+
+#ifdef TCSETS
+
+#define TCSANOW TCSETS
+#define TCSADRAIN TCSETSW
+#define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+
+#else /* TCSETS */
+
+#ifdef TCSETA
+#define TCSANOW TCSETA
+#define TCSADRAIN TCSETAW
+#define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t)
+#else /* TCSETA */
+#define TCSANOW TIOCSETA
+#define TCSADRAIN TIOCSETAW
+#define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t)
+#endif /* TCSETA */
+
+#endif /* TCSETS */
+
+#define tcsetattr(f,a,t) ioctl(f,a,t)
+#define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val)
+#define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
+
+#ifdef CIBAUD
+#define cfsetispeed(tp,val) \
+ (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<<IBSHIFT)
+#define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
+#else /* CIBAUD */
+#define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val)
+#define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
+#endif /* CIBAUD */
+
+#endif /* TCSANOW */
+
+struct termios termbuf, termbuf2; /* pty control structure */
+
+#ifdef INIT_SPTY
+static int spty = -1;
+#endif /* INIT_SPTY */
+
+#endif /* USE_TERMIO */
+
+#ifdef QNX /* 299 */
+#ifndef IXANY
+#define IXANY 0
+#endif /* IXANY */
+#endif /* QNX */
+
+static int msg = 0;
+
+/* Variables available to other modules */
+
+int pty_fork_active = 0; /* pty fork is active */
+PID_T pty_fork_pid = -1; /* pty fork pid */
+int pty_slave_fd = -1; /* pty slave file descriptor */
+int pty_master_fd = -1; /* pty master file descriptor */
+
+/* termbuf routines (begin) */
+/*
+ init_termbuf()
+ copy_termbuf(cp)
+ set_termbuf()
+
+ These three routines are used to get and set the "termbuf" structure
+ to and from the kernel. init_termbuf() gets the current settings.
+ copy_termbuf() hands in a new "termbuf" to write to the kernel, and
+ set_termbuf() writes the structure into the kernel.
+*/
+VOID
+init_termbuf(fd) int fd; {
+ int ttyfd;
+ int rc = 0;
+
+ ttyfd = fd;
+
+#ifdef HAVE_STREAMS
+ debug(F100,"init_termbuf HAVE_STREAMS","",0);
+#else
+ debug(F100,"init_termbuf HAVE_STREAMS NOT DEFINED","",0);
+#endif /* HAVE_STREAMS */
+#ifdef STREAMSPTY
+ debug(F100,"init_termbuf STREAMSPTY","",0);
+#else
+ debug(F100,"init_termbuf STREAMSPTY NOT DEFINED","",0);
+#endif /* STREAMSPTY */
+#ifdef INIT_SPTY
+ debug(F100,"init_termbuf INIT_SPTY","",0);
+#else
+ debug(F100,"init_termbuf INIT_SPTY NOT DEFINED","",0);
+#endif /* INIT_SPTY */
+
+ debug(F101,"init_termbuf ttyfd","",ttyfd);
+#ifdef INIT_SPTY
+ debug(F101,"init_termbuf spty","",spty);
+#endif /* INIT_SPTY */
+
+ memset(&termbuf,0,sizeof(termbuf));
+ memset(&termbuf2,0,sizeof(termbuf2));
+#ifndef USE_TERMIO
+ rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg);
+ rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc);
+ rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc);
+#ifdef TIOCGSTATE
+ rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state);
+#endif /* TIOCGSTATE */
+#else /* USE_TERMIO */
+ errno = 0;
+#ifdef INIT_SPTY
+ rc = tcgetattr(spty, &termbuf);
+ debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno);
+#else
+ rc = tcgetattr(ttyfd, &termbuf);
+ debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno);
+#endif /* INIT_SPTY */
+#endif /* USE_TERMIO */
+ if (!rc)
+ termbuf2 = termbuf;
+}
+
+#ifdef TIOCPKT_IOCTL
+VOID
+copy_termbuf(cp, len) char *cp; int len; {
+ if (len > sizeof(termbuf))
+ len = sizeof(termbuf);
+ memcpy((char *)&termbuf, cp, len);
+ termbuf2 = termbuf;
+}
+#endif /* TIOCPKT_IOCTL */
+
+VOID
+set_termbuf(fd) int fd; { /* Only make the necessary changes. */
+ int x;
+ int ttyfd;
+ ttyfd = fd;
+
+ debug(F101,"set_termbuf ttyfd","",ttyfd);
+#ifdef INIT_SPTY
+ debug(F101,"set_termbuf spty","",spty);
+#endif /* INIT_SPTY */
+
+#ifndef USE_TERMIO
+ debug(F100,"set_termbuf USE_TERMIO","",0);
+ if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
+ ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg);
+ if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
+ ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc);
+ if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+ sizeof(termbuf.ltc)))
+ ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc);
+ if (termbuf.lflags != termbuf2.lflags)
+ ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags);
+#else /* USE_TERMIO */
+ x = memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf));
+ debug(F101,"set_termbuf !USE_TERMIO memcmp","",x);
+ x = 1; /* Force this */
+ if (x) {
+ int x;
+ errno = 0;
+#ifdef INIT_SPTY
+ debug(F100,"set_termbuf INIT_SPTY","",0);
+ x = tcsetattr(spty, TCSANOW, &termbuf);
+ debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
+#else
+ debug(F100,"set_termbuf !INIT_SPTY","",0);
+ x = tcsetattr(ttyfd, TCSANOW, &termbuf);
+ debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno);
+#endif /* INIT_SPTY */
+ }
+#endif /* USE_TERMIO */
+}
+/* termbuf routines (end) */
+
+VOID
+ptyint_vhangup() {
+#ifdef CK_VHANGUP
+#ifdef CK_POSIX_SIG
+ struct sigaction sa;
+ /* Initialize "sa" structure. */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGHUP, &sa, (struct sigaction *)0);
+ vhangup();
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGHUP, &sa, (struct sigaction *)0);
+#else /* CK_POSIX_SIG */
+ signal(SIGHUP,SIG_IGN);
+ vhangup();
+ signal(SIGHUP,SIG_DFL);
+#endif /* CK_POSIX_SIG */
+#endif /* CK_VHANGUP */
+}
+
+/*
+ This routine is called twice. It's not particularly important that the
+ setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
+ rather that we have a controlling terminal at the end. It is assumed that
+ vhangup doesn't exist and confuse the process's notion of controlling
+ terminal on any system without TIOCNOTTY. That is, either vhangup() leaves
+ the controlling terminal in tact, breaks the association completely, or the
+ system provides TIOCNOTTY to get things back into a reasonable state. In
+ practice, vhangup() either breaks the association completely or doesn't
+ effect controlling terminals, so this condition is met.
+*/
+long
+ptyint_void_association() {
+ int con_fd;
+#ifdef HAVE_SETSID
+ debug(F110,
+ "ptyint_void_association()",
+ "setsid()",
+ 0
+ );
+ setsid();
+#endif /* HAVE_SETSID */
+
+#ifndef NO_DEVTTY
+ /* Void tty association first */
+#ifdef TIOCNOTTY
+ con_fd = open("/dev/tty", O_RDWR);
+ debug(F111,
+ "ptyint_void_association() open(/dev/tty,O_RDWR)",
+ "/dev/tty",
+ con_fd);
+ if (con_fd >= 0) {
+ ioctl(con_fd, TIOCNOTTY, 0);
+ close(con_fd);
+ }
+#ifdef DEBUG
+ else debug(F101, "ptyint_void_association() open() errno","",errno);
+#endif /* DEBUG */
+#endif /* TIOCNOTTY */
+#endif /* NO_DEVTTY */
+ return(0);
+}
+
+/* PID may be zero for unknown.*/
+
+long
+pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
+#ifdef VHANG_LAST
+ int retval, fd;
+#endif /* VHANG_LAST */
+
+ debug(F111,"pty_cleanup()",slave,pid);
+#ifdef WANT_UTMP
+ if (update_utmp)
+ pty_update_utmp(PTY_DEAD_PROCESS,
+ 0,
+ "",
+ slave,
+ (char *)0,
+ PTY_UTMP_USERNAME_VALID
+ );
+#endif /* WANT_UTMP */
+
+#ifdef SETUID
+ chmod(slave, 0666);
+ chown(slave, 0, 0);
+#endif /* SETUID */
+
+#ifdef HAVE_REVOKE
+ revoke(slave);
+ /*
+ Revoke isn't guaranteed to send a SIGHUP to the processes it
+ dissociates from the terminal. The best solution without a Posix
+ mechanism for forcing a hangup is to killpg() the process group of the
+ pty. This will at least kill the shell and hopefully, the child
+ processes. This is not always the case, however. If the shell puts
+ each job in a process group and doesn't pass along SIGHUP, all
+ processes may not die.
+ */
+ if (pid > 0) {
+#ifdef HAVE_KILLPG
+ killpg(pid, SIGHUP);
+#else
+ kill(-(pid), SIGHUP);
+#endif /*HAVE_KILLPG*/
+ }
+#else /* HAVE_REVOKE*/
+#ifdef VHANG_LAST
+ {
+ int status;
+#ifdef CK_POSIX_SIG
+ sigset_t old, new;
+ sigemptyset(&new);
+ sigaddset(&new, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &new, &old);
+#else /*CK_POSIX_SIG*/
+ int mask = sigblock(sigmask(SIGCHLD));
+#endif /*CK_POSIX_SIG*/
+ switch (retval = fork()) {
+ case -1:
+#ifdef CK_POSIX_SIG
+ sigprocmask(SIG_SETMASK, &old, 0);
+#else /*CK_POSIX_SIG*/
+ sigsetmask(mask);
+#endif /*CK_POSIX_SIG*/
+ return errno;
+ case 0:
+ ptyint_void_association();
+ if (retval = (pty_open_ctty(slave, &fd, -1)))
+ exit(retval);
+ ptyint_vhangup();
+ exit(0);
+ break;
+ default:
+#ifdef HAVE_WAITPID
+ waitpid(retval, &status, 0);
+#else /*HAVE_WAITPID*/
+ wait(&status);
+#endif /* HAVE_WAITPID */
+#ifdef CK_POSIX_SIG
+ sigprocmask(SIG_SETMASK, &old, 0);
+#else /*CK_POSIX_SIG*/
+ sigsetmask(mask);
+#endif /*CK_POSIX_SIG*/
+ break;
+ }
+ }
+#endif /*VHANG_LAST*/
+#endif /* HAVE_REVOKE*/
+#ifndef HAVE_STREAMS
+ slave[strlen("/dev/")] = 'p';
+#ifdef SETUID
+ chmod(slave, 0666);
+ chown(slave, 0, 0);
+#endif /* SETUID */
+#endif /* HAVE_STREAMS */
+ return(0);
+}
+
+long
+pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
+ char *cp;
+ char *p;
+ int i, ptynum;
+ struct stat stb;
+#ifndef HAVE_OPENPTY
+#ifndef HAVE__GETPTY
+ char slavebuf[1024];
+#endif /* HAVE__GETPTY */
+#endif /* HAVE_OPENPTY */
+#ifdef HAVE__GETPTY
+ char *slaveret; /* Temp to hold pointer to slave */
+#endif /*HAVE__GETPTY*/
+
+#ifdef HAVE_OPENPTY
+ int slavefd;
+
+ pty_master_fd = -1;
+ debug(F100,"HAVE_OPENPTY","",0);
+ if (openpty(fd,
+ &slavefd,
+ slave,
+ (struct termios *)0,
+ (struct winsize *)0
+ )
+ ) {
+ pty_master_fd = *fd;
+ return(1);
+ }
+ close(slavefd);
+ return(0);
+
+#else /* HAVE_OPENPTY */
+
+#ifdef HAVE__GETPTY
+/*
+ This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but
+ it fails to work properly; even after calling unlockpt, root gets permission
+ denied opening the pty. The code to support _getpty should be removed if
+ Irix gets working streams ptys in favor of maintaining the least needed code
+ paths.
+*/
+ debug(F100,"HAVE__GETPTY","",0);
+ if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) {
+ *fd = -1;
+ return(PTY_GETPTY_NOPTY);
+ }
+ if (strlen(slaveret) > slavelength - 1) {
+ close(*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ } else {
+ ckstrncpy(slave, slaveret, slavelength);
+ }
+ return(0);
+
+#else /* HAVE__GETPTY */
+
+ *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */
+ if (*fd >= 0) {
+ debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0);
+ goto have_fd;
+ }
+
+#ifdef HAVE_PTMX
+ debug(F100,"HAVE_PTMX","",0);
+ *fd = open("/dev/ptmx",O_RDWR|O_NDELAY);
+ if (*fd >= 0) {
+ debug(F110,"pty_getpty()","open(/dev/ptmx) success",0);
+ goto have_fd;
+ }
+#endif /* HAVE_PTMX */
+
+ *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
+ if (*fd >= 0) {
+ debug(F110,"pty_getpty()","open(/dev/ptc) success",0);
+ goto have_fd;
+ }
+ *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
+ if (*fd >= 0)
+ debug(F110,"pty_getpty()","open(/dev/pty) success",0);
+
+ have_fd:
+ /* This would be the pty master */
+ debug(F101,"pty_getpty fd(A)","",*fd);
+ if (*fd >= 0) {
+ pty_master_fd = *fd;
+
+#ifdef HAVE_GRANTPT
+#ifdef HAVE_PTMX
+ debug(F100,"HAVE_GRANTPT","",0);
+ if (grantpt(*fd) || unlockpt(*fd))
+ return(PTY_GETPTY_STREAMS);
+#endif /* HAVE_PTMX */
+#endif /* HAVE_GRANTPT */
+
+#ifdef HAVE_PTSNAME
+ debug(F100,"HAVE_PTSNAME","",0);
+ p = (char *)ptsname(*fd);
+ debug(F110,"pty_getpty() ptsname()",p,0);
+#else
+#ifdef HAVE_TTYNAME
+ debug(F100,"HAVE_TTYNAME","",0);
+ p = ttyname(*fd);
+ debug(F110,"pty_getpty() ttyname()",p,0);
+#else
+ /* If we don't have either what do we do? */
+ return(PTY_GETPTY_NOPTY); /* punt */
+#endif /* HAVE_TTYNAME */
+#endif /* HAVE_PTSNAME */
+ if (p) {
+ if (strlen(p) > slavelength - 1) {
+ close (*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ }
+ ckstrncpy(slave, p, slavelength);
+ return(0);
+ }
+ if (fstat(*fd, &stb) < 0) {
+ close(*fd);
+ return(PTY_GETPTY_FSTAT);
+ }
+ ptynum = (int)(stb.st_rdev&0xFF);
+ sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */
+ if (strlen(slavebuf) > slavelength - 1) {
+ close(*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ }
+ debug(F110,"pty_getpty() slavebuf",slavebuf,0);
+ ckstrncpy(slave, slavebuf, slavelength);
+ return(0);
+ } else {
+ for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
+ sprintf(slavebuf,"/dev/ptyXX"); /* safe */
+ slavebuf[sizeof("/dev/pty") - 1] = *cp;
+ slavebuf[sizeof("/dev/ptyp") - 1] = '0';
+ if (stat(slavebuf, &stb) < 0)
+ break;
+ for (i = 0; i < 16; i++) {
+ slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
+ errno = 0;
+ *fd = open(slavebuf, O_RDWR|O_NDELAY);
+ if (*fd < 0) {
+ debug(F111,"pty_getpty() pty master open error",
+ slavebuf,errno);
+ continue;
+ }
+ debug(F111,"pty_getpty() found pty master",slavebuf,*fd);
+ slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
+ if (strlen(slavebuf) > slavelength -1) {
+ close(*fd);
+ *fd = -1;
+ return(PTY_GETPTY_SLAVE_TOOLONG);
+ }
+ ckstrncpy(slave, slavebuf, slavelength);
+ debug(F110,"pty_getpty slave name",slave,0);
+ pty_master_fd = *fd;
+ return(0);
+ }
+ }
+ return(PTY_GETPTY_NOPTY);
+ }
+#endif /*HAVE__GETPTY*/
+#endif /* HAVE_OPENPTY */
+}
+
+long
+pty_init() {
+#ifdef HAVE_PTYM
+ static char dummy;
+ debug(F100,"HAVE_PTYM","",0);
+ tty_bank = &master_name[strlen("/dev/ptym/pty")];
+ tty_num = &master_name[strlen("/dev/ptym/ptyX")];
+ slave_bank = &slave_name[strlen("/dev/pty/tty")];
+ slave_num = &slave_name[strlen("/dev/pty/ttyX")];
+#endif
+ return(0L);
+}
+
+/*
+ The following is an array of modules that should be pushed on the stream.
+ See configure.in for caviats and notes about when this array is used and not
+ used.
+*/
+#ifdef HAVE_STREAMS
+#ifndef HAVE_LINE_PUSH
+static char *push_list[] = {
+#ifdef PUSH_PTEM
+ "ptem",
+#endif
+#ifdef PUSH_LDTERM
+ "ldterm",
+#endif
+#ifdef PUSH_TTCOMPAT
+ "ttcompat",
+#endif
+ 0
+};
+#endif /* HAVE_LINE_PUSH */
+#endif /* HAVE_STREAMS */
+
+long
+pty_initialize_slave (fd) int fd; {
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+ struct termios new_termio;
+#else
+ struct sgttyb b;
+#endif /* ultrix */
+#else
+ struct sgttyb b;
+#endif /* POSIX_TERMIOS */
+ int pid;
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+ int rc;
+#endif /* ultrix */
+#endif /* POSIX_TERMIOS */
+
+ debug(F111,"pty_initialize_slave()","fd",fd);
+
+#ifdef HAVE_STREAMS
+#ifdef HAVE_LINE_PUSH
+ while (ioctl(fd,I_POP,0) == 0) ; /* Clear out any old lined's */
+
+ if (line_push(fd) < 0) {
+ debug(F110,"pty_initialize_slave()","line_push() failed",0);
+ close(fd);
+ fd = -1;
+ return(PTY_OPEN_SLAVE_LINE_PUSHFAIL);
+ }
+#else /*No line_push */
+ {
+ char **module = &push_list[0];
+ while (*module) {
+ if (ioctl(fd, I_PUSH, *(module++)) < 0) {
+ debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0);
+ return(PTY_OPEN_SLAVE_PUSH_FAIL);
+ }
+ }
+ }
+#endif /*LINE_PUSH*/
+#endif /*HAVE_STREAMS*/
+/*
+ Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set
+ explicitly. Why rlogind works at all without this on 4.3BSD is a mystery.
+*/
+#ifdef GETPGRP_ONEARG
+ pid = getpgrp(getpid());
+#else
+ pid = getpgrp();
+#endif /* GETPGRP_ONEARG */
+
+ debug(F111,"pty_initialize_slave()","pid",pid);
+
+#ifdef TIOCSPGRP
+ ioctl(fd, TIOCSPGRP, &pid);
+#endif /* TIOCSPGRP */
+
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+ tcsetpgrp(fd, pid);
+ errno = 0;
+ rc = tcgetattr(fd,&new_termio);
+ debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno);
+ if (rc == 0) {
+ new_termio.c_cc[VMIN] = 1;
+ new_termio.c_cc[VTIME] = 0;
+ rc = tcsetattr(fd,TCSANOW,&new_termio);
+ debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno);
+ }
+#endif /* ultrix */
+#endif /* POSIX_TERMIOS */
+ return(0L);
+}
+
+#ifdef WANT_UTMP
+long
+pty_logwtmp (tty, user, host) char *user, *tty, *host; {
+#ifdef HAVE_LOGWTMP
+ logwtmp(tty,user,host);
+ return(0);
+#else
+ struct utmp ut;
+ char *tmpx;
+ char utmp_id[5];
+ int loggingin = user[0]; /* Will be empty for logout */
+
+#ifndef NO_UT_HOST
+ strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif /* NO_UT_HOST */
+
+ strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
+ ut.ut_time = time(0);
+
+#ifndef NO_UT_PID
+ ut.ut_pid = getpid();
+ strncpy(ut.ut_user, user, sizeof(ut.ut_user));
+
+ tmpx = tty + strlen(tty) - 2;
+ ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL);
+ strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
+ ut.ut_pid = (loggingin ? getpid() : 0);
+ ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
+#else
+ strncpy(ut.ut_name, user, sizeof(ut.ut_name));
+#endif /* NO_UT_PID */
+
+ return(ptyint_update_wtmp(&ut, host, user));
+
+#endif /* HAVE_LOGWTMP */
+}
+#endif /* WANT_UTMP */
+
+/*
+ This routine is called twice. It's not particularly important that the
+ setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
+ rather that we have a controlling terminal at the end. It is assumed that
+ vhangup doesn't exist and confuse the process's notion of controlling
+ terminal on any system without TIOCNOTTY. That is, either vhangup() leaves
+ the controlling terminal in tact, breaks the association completely, or the
+ system provides TIOCNOTTY to get things back into a reasonable state. In
+ practice, vhangup() either breaks the association completely or doesn't
+ effect controlling terminals, so this condition is met.
+*/
+long
+pty_open_ctty(slave, fd, fc) char * slave; int *fd; int fc; {
+ int retval;
+
+ debug(F110,"pty_open_ctty() slave",slave,0);
+
+/* First, dissociate from previous terminal */
+
+ if ((retval = ptyint_void_association()) != 0) {
+ debug(F111,
+ "pty_open_ctty()",
+ "ptyint_void_association() failed",
+ retval
+ );
+ return(retval);
+ }
+#ifdef MUST_SETPGRP
+/*
+ The Ultrix (and other BSD tty drivers) require the process group
+ to be zero in order to acquire the new tty as a controlling tty.
+*/
+ setpgrp(0,0);
+ debug(F101,"pty_open_ctty MUST_SETPGRP setpgrp(0,0)","",errno);
+#endif /* MUST_SETPGRP */
+
+ errno = 0;
+ *fd = open(slave, O_RDWR);
+ debug(F111,"pty_open_ctty open(slave) fd",slave,*fd);
+ if (*fd < 0) {
+ debug(F111,"pty_open_ctty() open failure", slave, errno);
+ return(PTY_OPEN_SLAVE_OPENFAIL);
+ }
+#ifdef SOLARIS
+ /* This forces the job to have a controlling terminal. */
+ close(*fd);
+ *fd = open(slave, O_RDWR);
+ debug(F111,"pty_open_ctty close/open(slave) fd",slave,*fd);
+#ifdef DEBUG
+ /* This shows that /dev/tty exists */
+if (deblog) {
+ int x;
+ x = open("/dev/tty", O_RDWR);
+ debug(F111,"pty_open_ctty open(/dev/tty) fd",slave,x);
+ if (x < 0) debug(F111,"pty_open_ctty open(/dev/tty) errno","",errno);
+ debug(F110,"pty_open_ctty ttyname(/dev/tty)",ttyname(x),0);
+ if (x > -1) close(x);
+ }
+#endif /* DEBUG */
+#endif /* SOLARIS */
+
+#ifdef MUST_SETPGRP
+ setpgrp(0, getpid());
+#endif /* MUST_SETPGRP */
+
+#ifdef TIOCSCTTY
+ if (
+#ifdef COMMENT
+ fc == 0
+#else
+ 1
+#endif /* COMMENT */
+ ) {
+ /* TIOCSCTTY = Make this the job's controlling terminal */
+ errno = 0;
+ retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
+ debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
+ }
+#endif /* TIOCSCTTY */
+ return(0L);
+}
+
+long
+pty_open_slave(slave, fd, fc) char *slave; int *fd; int fc; {
+ int vfd, testfd;
+ long retval;
+#ifdef CK_POSIX_SIG
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask); /* Initialize "sa" structure. */
+ sa.sa_flags = 0;
+#endif /* CK_POSIX_SIG */
+
+/*
+ First, chmod and chown the slave. If we have vhangup then we really need
+ pty_open_ctty to make sure our controlling terminal is the pty we're
+ opening. However, if we are using revoke or nothing then we just need a
+ file descriiptor for the pty. Considering some OSes in this category break
+ on the second call to open_ctty (currently OSF but others may), we simply
+ use a descriptor if we can.
+*/
+#ifdef VHANG_FIRST
+ if ((retval = pty_open_ctty(slave, &vfd, fc)) != 0) {
+ debug(F111,
+ "pty_open_slave() VHANG_FIRST",
+ "pty_open_ctty() failed",
+ retval
+ );
+ return(retval);
+ }
+ if (vfd < 0) {
+ debug(F111,
+ "pty_open_slave() VHANG_FIRST",
+ "PTY_OPEN_SLAVE_OPENFAIL",
+ vfd
+ );
+ return(PTY_OPEN_SLAVE_OPENFAIL);
+ }
+#endif /* VHANG_FIRST */
+
+ if (slave == NULL || *slave == '\0') {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0);
+ return(PTY_OPEN_SLAVE_TOOSHORT);
+ }
+
+#ifdef SETUID
+ if (chmod(slave, 0)) {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0);
+ return(PTY_OPEN_SLAVE_CHMODFAIL);
+ }
+ if (chown(slave, 0, 0 ) == -1 ) {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0);
+ return(PTY_OPEN_SLAVE_CHOWNFAIL);
+ }
+#endif /* SETUID */
+#ifdef VHANG_FIRST
+ ptyint_vhangup();
+ close(vfd);
+#endif /* VHANG_FIRST */
+
+ if ((retval = ptyint_void_association()) != 0) {
+ debug(F111,
+ "pty_open_slave()",
+ "ptyint_void_association() failed",
+ retval
+ );
+ return(retval);
+ }
+
+#ifdef HAVE_REVOKE
+ if (revoke (slave) < 0 ) {
+ debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0);
+ return(PTY_OPEN_SLAVE_REVOKEFAIL);
+ }
+#endif /* HAVE_REVOKE */
+
+/* Open the pty for real. */
+
+ retval = pty_open_ctty(slave, fd, fc);
+ debug(F111,"pty_open_slave retval",slave,retval);
+ debug(F111,"pty_open_slave fd",slave,*fd);
+ if (retval != 0) {
+ debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
+ return(PTY_OPEN_SLAVE_OPENFAIL);
+ }
+ pty_slave_fd = *fd; /* This is not visible to the upper fork */
+ debug(F111,"pty_open_slave fd ctty'd",slave,pty_slave_fd);
+ retval = pty_initialize_slave(*fd);
+ debug(F111,"pty_open_slave fd init'd",slave,pty_slave_fd);
+ if (retval) {
+ debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
+ return(retval);
+ }
+ /* (VOID)pty_make_raw(*fd); */
+
+ debug(F100,"pty_open_slave OK","",*fd);
+ return(0L);
+}
+
+#ifdef WANT_UTMP
+
+#ifndef UTMP_FILE
+#ifdef _PATH_UTMP
+#define UTMP_FILE _PATH_UTMP
+#endif /* _PATH_UTMP */
+#endif /* UTMP_FILE */
+
+/* If it is *still* missing, assume /etc/utmp */
+
+#ifndef UTMP_FILE
+#define UTMP_FILE "/etc/utmp"
+#endif /* UTMP_FILE */
+
+#ifndef NO_UT_PID
+#define WTMP_REQUIRES_USERNAME
+#endif /* NO_UT_PID */
+
+long
+pty_update_utmp(process_type, pid, username, line, host, flags)
+ int process_type;
+ int pid;
+ char *username, *line, *host;
+ int flags;
+/* pty_update_utmp */ {
+ struct utmp ent, ut;
+#ifndef HAVE_SETUTENT
+ struct stat statb;
+ int tty;
+#endif /* HAVE_SETUTENT */
+#ifdef HAVE_SETUTXENT
+ struct utmpx utx;
+#endif /* HAVE_SETUTXENT */
+#ifndef NO_UT_PID
+ char *tmpx;
+ char utmp_id[5];
+#endif /* NO_UT_PID */
+ char userbuf[32];
+ int fd;
+
+ debug(F100,"pty_update_utmp()","",0);
+ strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
+ ent.ut_time = time(0);
+
+#ifdef NO_UT_PID
+ if (process_type == PTY_LOGIN_PROCESS)
+ return(0L);
+#else /* NO_UT_PID */
+
+ ent.ut_pid = pid;
+
+ switch (process_type) {
+ case PTY_LOGIN_PROCESS:
+ ent.ut_type = LOGIN_PROCESS;
+ break;
+ case PTY_USER_PROCESS:
+ ent.ut_type = USER_PROCESS;
+ break;
+ case PTY_DEAD_PROCESS:
+ ent.ut_type = DEAD_PROCESS;
+ break;
+ default:
+ return(PTY_UPDATE_UTMP_PROCTYPE_INVALID);
+ }
+#endif /*NO_UT_PID*/
+
+#ifndef NO_UT_HOST
+ if (host)
+ strncpy(ent.ut_host, host, sizeof(ent.ut_host));
+ else
+ ent.ut_host[0] = '\0';
+#endif /* NO_UT_HOST */
+
+#ifndef NO_UT_PID
+ if (!strcmp (line, "/dev/console")) {
+ char * s = NULL;
+
+#ifdef sun
+#ifdef __SVR4
+ s = "co";
+#else
+ s = "cons";
+#endif /* __SVR4 */
+#else
+ s = "cons";
+#endif /* sun */
+
+ strncpy(ent.ut_id, s, 4);
+
+ } else {
+
+ tmpx = line + strlen(line)-1;
+ if (*(tmpx-1) != '/') tmpx--; /* last 2 chars unless it's a '/' */
+#ifdef __hpux
+ ckstrncpy(utmp_id, tmpx, 5);
+#else
+ ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL);
+#endif /* __hpux */
+ strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
+ }
+ strncpy(ent.ut_user, username, sizeof(ent.ut_user));
+
+#else
+
+ strncpy(ent.ut_name, username, sizeof(ent.ut_name));
+
+#endif /* NO_UT_PID */
+
+ if (username[0])
+ strncpy(userbuf, username, sizeof(userbuf));
+ else
+ userbuf[0] = '\0';
+
+#ifdef HAVE_SETUTENT
+
+ utmpname(UTMP_FILE);
+ setutent();
+/*
+ If we need to preserve the user name in the wtmp structure and Our flags
+ tell us we can obtain it from the utmp and we succeed in obtaining it, we
+ then save the utmp structure we obtain, write out the utmp structure and
+ change the username pointer so it is used by update_wtmp.
+*/
+
+#ifdef WTMP_REQUIRES_USERNAME
+ if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) {
+ struct utmp *utptr;
+ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ utptr = getutline(&ut);
+ if (utptr)
+ strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
+ }
+#endif /* WTMP_REQUIRES_USERNAME */
+
+ pututline(&ent);
+ endutent();
+
+#ifdef HAVE_SETUTXENT
+ setutxent();
+#ifdef HAVE_GETUTMPX
+ getutmpx(&ent, &utx);
+#else /* HAVE_GETUTMPX */
+ /* For platforms like HPUX and Dec Unix which don't have getutmpx */
+ strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
+ strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
+ strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
+ utx.ut_pid = pid; /* kludge for Irix, etc. to avoid trunc. */
+ utx.ut_type = ent.ut_type;
+#ifdef UT_EXIT_STRUCTURE_DIFFER
+ utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
+#else /* UT_EXIT_STRUCTURE_DIFFER */
+/* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
+#ifdef __hpux
+ utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
+ utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
+#else /* __hpux */
+ /* XXX do nothing for now; we don't even know the struct member exists */
+#endif /* __hpux */
+#endif /* UT_EXIT_STRUCTURE_DIFFER */
+ utx.ut_tv.tv_sec = ent.ut_time;
+ utx.ut_tv.tv_usec = 0;
+#endif /* HAVE_GETUTMPX */
+ if (host)
+ strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+ else
+ utx.ut_host[0] = 0;
+ pututxline(&utx);
+ endutxent();
+#endif /* HAVE_SETUTXENT */
+
+#else /* HAVE_SETUTENT */
+ if (flags&PTY_TTYSLOT_USABLE) {
+ tty = ttyslot();
+ } else {
+ int lc;
+ tty = -1;
+ if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
+ return(errno);
+ for (lc = 0;
+ lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
+ lc++
+ ) {
+ if (read(fd,
+ (char *)&ut,
+ sizeof(struct utmp)
+ ) != sizeof(struct utmp)
+ )
+ break;
+ if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
+ tty = lc;
+#ifdef WTMP_REQUIRES_USERNAME
+ if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
+ strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
+#endif /* WTMP_REQUIRES_USERNAME */
+ break;
+ }
+ }
+ close(fd);
+ }
+ if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
+ lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
+ write(fd, (char *)&ent, sizeof(struct utmp));
+ close(fd);
+ }
+#endif /* HAVE_SETUTENT */
+
+ /* Don't record LOGIN_PROCESS entries. */
+ if (process_type == PTY_LOGIN_PROCESS)
+ return(0);
+ else
+ return(ptyint_update_wtmp(&ent, host, userbuf));
+}
+#ifndef WTMP_FILE
+#ifdef _PATH_WTMP
+#define WTMP_FILE _PATH_WTMP
+#endif /* _PATH_WTMP */
+#endif /* WTMP_FILE */
+
+#ifndef WTMPX_FILE
+#ifdef _PATH_WTMPX
+#ifdef HAVE_UPDWTMPX
+#define WTMPX_FILE _PATH_WTMPX
+#endif /* HAVE_UPDWTMPX */
+#endif /* _PATH_WTMPX */
+#endif /* WTMPX_FILE */
+
+/* If it is *still* missing, assume /usr/adm/wtmp */
+
+#ifndef WTMP_FILE
+#define WTMP_FILE "/usr/adm/wtmp"
+#endif /* WTMP_FILE */
+
+#ifdef COMMENT
+/* The following test can not be made portably */
+
+/* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */
+/*
+ This is ugly, but the lack of standardization in the utmp/utmpx space, and
+ what glibc implements and doesn't make available, is even worse.
+*/
+/* #undef HAVE_UPDWTMPX */ /* Don't use updwtmpx for glibc 2.1 */
+/* #endif */ /* __GLIBC__ etc */
+
+#else /* COMMENT */
+
+#ifdef __GLIBC__
+#undef HAVE_UPDWTMPX /* Don't use updwtmpx for glibc period */
+#endif /* __GLIBC__ */
+#endif /* COMMENT */
+
+long
+ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; {
+ struct utmp ut;
+ struct stat statb;
+ int fd;
+ time_t uttime;
+#ifdef HAVE_UPDWTMPX
+ struct utmpx utx;
+
+ getutmpx(ent, &utx);
+ if (host)
+ strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
+ else
+ utx.ut_host[0] = 0;
+ if (user)
+ strncpy(utx.ut_user, user, sizeof(utx.ut_user));
+ updwtmpx(WTMPX_FILE, &utx);
+#endif /* HAVE_UPDWTMPX */
+
+#ifdef HAVE_UPDWTMP
+#ifndef HAVE_UPDWTMPX
+ /* This is already performed byupdwtmpx if present.*/
+ updwtmp(WTMP_FILE, ent);
+#endif /* HAVE_UPDWTMPX*/
+#else /* HAVE_UPDWTMP */
+
+ if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
+ if (!fstat(fd, &statb)) {
+ memset((char *)&ut, 0, sizeof(ut));
+#ifdef __hpux
+ strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
+#endif /* __hpux */
+ strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
+ strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
+#ifndef NO_UT_HOST
+ strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
+#endif /* NO_UT_HOST */
+
+ time(&uttime);
+ ut.ut_time = uttime;
+
+#ifdef HAVE_GETUTENT
+#ifdef USER_PROCESS
+ if (ent->ut_name) {
+ if (!ut.ut_pid)
+ ut.ut_pid = getpid();
+#ifndef __hpux
+ ut.ut_type = USER_PROCESS;
+#else /* __hpux */
+ ut.ut_type = ent->ut_type;
+#endif /* __hpux */
+
+ } else {
+
+#ifdef EMPTY
+ ut.ut_type = EMPTY;
+#else
+ ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
+#endif /* EMPTY */
+
+ }
+#endif /* USER_PROCESS */
+#endif /* HAVE_GETUTENT */
+
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+#ifndef COHERENT
+ ftruncate(fd, statb.st_size);
+#else
+ chsize(fd, statb.st_size);
+#endif /* COHERENT */
+ }
+ close(fd);
+ }
+#endif /* HAVE_UPDWTMP */
+ return(0); /* no current failure cases; file not found is not failure! */
+}
+#endif /* WANT_UTMP */
+
+/* This is for ancient Unixes that don't have these tty symbols defined. */
+
+#ifndef PENDIN
+#define PENDIN ICANON
+#endif /* PENDIN */
+#ifndef FLUSHO
+#define FLUSHO ICANON
+#endif /* FLUSHO */
+#ifndef IMAXBEL
+#define IMAXBEL ICANON
+#endif /* IMAXBEL */
+#ifndef EXTPROC
+#define EXTPROC ICANON
+#endif /* EXTPROC */
+
+static char Xline[17] = { 0, 0 };
+/*
+ getptyslave()
+ Open the slave side of the pty, and do any initialization that is necessary.
+ The return value fd is a file descriptor for the slave side.
+ fc = function code from do_pty() (q.v.)
+*/
+int
+getptyslave(fd, fc) int * fd, fc; {
+ int ttyfd;
+ int t = -1;
+ long retval;
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ extern int cmd_rows, cmd_cols;
+#endif /* TIOCGWINSZ */
+
+ ttyfd = *fd;
+ debug(F111,"getptyslave()","ttyfd",ttyfd);
+ /*
+ * Opening the slave side may cause initilization of the
+ * kernel tty structure. We need remember the state of:
+ * if linemode was turned on
+ * terminal window size
+ * terminal speed
+ * so that we can reset them if we need to.
+ */
+ if ((retval = pty_open_slave(Xline, &t, fc)) != 0) {
+ perror(Xline);
+ msg++;
+ debug(F111,"getptyslave()","Unable to open slave",retval);
+ return(-1);
+ }
+ debug(F111,"getptyslave","t",t);
+#ifdef INIT_SPTY
+ spty = t;
+ debug(F111,"getptyslave","spty",spty);
+#endif /* INIT_SPTY */
+#ifdef STREAMSPTY
+ if (ioctl(t,I_PUSH,"pckt") < 0) {
+ debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno);
+#ifndef _AIX
+ fatal("I_PUSH pckt");
+#endif /* _AIX */
+ }
+#endif /* STREAMSPTY */
+
+ /* Set up the tty modes as we like them to be. */
+#ifdef COMMENT
+ /* Originally like this... But this is the master - we want the slave */
+ /* Anyway, this fails on Solaris and probably other System V OS's */
+ init_termbuf(ttyfd);
+#else
+ init_termbuf(t);
+#endif /* COMMENT */
+#ifdef TIOCGWINSZ
+ if (cmd_rows || cmd_cols) {
+ memset((char *)&ws, 0, sizeof(ws));
+ ws.ws_col = cmd_cols;
+ ws.ws_row = cmd_rows;
+ debug(F101,"getptyslave() doing TIOCSWINSZ...","",t);
+ ioctl(t, TIOCSWINSZ, (char *)&ws);
+ }
+#endif /* TIOCGWINSZ */
+
+ /* For external protocols, put the pty in no-echo mode */
+ if (fc == 1) {
+ debug(F100,"getptyslave() setting rawmode","",0);
+ /* iflags */
+ termbuf.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
+ termbuf.c_iflag &= ~(INPCK|IGNPAR|IMAXBEL|IXANY|IXON|IXOFF);
+ termbuf.c_iflag |= IGNBRK;
+#ifdef IUCLC
+ termbuf.c_iflag &= ~IUCLC;
+#endif /* IUCLC */
+
+ /* oflags */
+ termbuf.c_oflag &= ~OPOST;
+#ifdef OXTABS
+ termbuf.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+#ifdef ONOCR
+ termbuf.c_oflag &= ~ONOCR;
+#endif /* ONOCR */
+#ifdef ONLRET
+ termbuf.c_oflag &= ~ONLRET;
+#endif /* ONLRET */
+#ifdef ONLCR
+ termbuf.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+
+ /* lflags */
+ termbuf.c_lflag &= ~ECHO;
+#ifdef ECHOE
+ termbuf.c_lflag &= ~ECHOE;
+#endif /* ECHOE */
+#ifdef ECHONL
+ termbuf.c_lflag &= ~ECHONL;
+#endif /* ECHONL */
+#ifdef ECHOPRT
+ termbuf.c_lflag &= ~ECHOPRT;
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ termbuf.c_lflag &= ~ECHOKE;
+#endif /* ECHOKE */
+#ifdef ECHOCTL
+ termbuf.c_lflag &= ~ECHOCTL;
+#endif /* ECHOCTL */
+#ifdef ALTWERASE
+ termbuf.c_lflag &= ~ALTWERASE;
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ termbuf.c_lflag &= ~EXTPROC;
+#endif /* EXTPROC */
+ termbuf.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
+
+#ifdef NOKERNINFO
+ termbuf.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+ /* termbuf.c_lflag |= NOFLSH; */
+ termbuf.c_lflag &= ~NOFLSH;
+
+ /* cflags */
+ termbuf.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ termbuf.c_cflag |= CS8|CREAD;
+#ifdef VMIN
+ termbuf.c_cc[VMIN] = 1;
+#endif /* VMIN */
+ } else { /* Regular interactive use */
+ debug(F100,"getptyslave() setting cooked mode","",0);
+
+ /* Settings for sgtty based systems */
+
+#ifndef USE_TERMIO
+ termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
+#endif /* USE_TERMIO */
+
+#ifndef OXTABS
+#define OXTABS 0
+#endif /* OXTABS */
+
+ /* Settings for UNICOS and HPUX */
+
+#ifdef CRAY
+ termbuf.c_oflag = OPOST|ONLCR|TAB3;
+ termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
+ termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+ termbuf.c_cflag = EXTB|HUPCL|CS8;
+#else /* CRAY */
+#ifdef HPUX
+ termbuf.c_oflag = OPOST|ONLCR|TAB3;
+ termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
+ termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+ termbuf.c_cflag = EXTB|HUPCL|CS8;
+#else /* HPUX */
+#ifdef USE_TERMIO
+ /*
+ Settings for all other termios/termio based systems, other than
+ 4.4BSD. In 4.4BSD the kernel does the initial terminal setup.
+ */
+#ifdef BSD42
+#ifndef BSD44
+ termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
+ termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
+ termbuf.c_iflag |= ICRNL|IGNPAR;
+ termbuf.c_cflag |= HUPCL;
+ termbuf.c_iflag &= ~IXOFF;
+#endif /* BSD44 */
+#else /* BSD42 */
+ termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
+ termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
+ termbuf.c_iflag |= ICRNL|IGNPAR;
+ termbuf.c_cflag |= HUPCL;
+ termbuf.c_iflag &= ~IXOFF;
+#endif /* BSD42 */
+#endif /* USE_TERMIO */
+#endif /* HPUX */
+#endif /* CRAY */
+ }
+
+ /* Set the tty modes, and make this our controlling tty. */
+#ifdef COMMENT
+ /* But this is the master - we want the slave */
+ set_termbuf(ttyfd);
+#else
+ set_termbuf(t);
+#endif /* COMMENT */
+
+ if (t != 0)
+ dup2(t, 0);
+ if (t != 1)
+ dup2(t, 1);
+ if (t != 2) {
+ if (fc == 0) {
+ dup2(t, 2);
+ } else if (fc == 1) {
+ /* For external protocols, send stderr to /dev/null */
+#ifdef COMMENT
+ int xx;
+#ifndef COMMENT
+ char * s = "/dev/null";
+ errno = 0;
+ xx = open(s, O_WRONLY);
+#else
+ char * s = "pty.log";
+ errno = 0;
+ xx = open(s, O_CREAT, 0644);
+#endif /* COMMENT */
+ debug(F111,"getptyslave redirect stderr",s,errno);
+ dup2(xx,2);
+#endif /* COMMENT */
+ }
+ }
+ if (t > 2)
+ close(t);
+
+ if (ttyfd > 2) {
+ close(ttyfd);
+ ttyfd = -1;
+ *fd = ttyfd;
+ }
+ return(0);
+}
+
+#ifdef HAVE_PTYTRAP
+/*
+ To be called to determine if a trap is pending on a pty
+ if and only if select() cannot be used.
+*/
+int
+pty_trap_pending(fd) int fd; {
+ int pending;
+ int rc;
+
+ rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending));
+ if (rc == 0) {
+ debug(F101,"pty_trap_pending()","",pending);
+ return(pending);
+ } else {
+ debug(F111,"pty_trap_pending()","ioctl() failed",rc);
+ return(-1);
+ }
+}
+
+/*
+ To be called after select() has returned indicating that an exception is
+ waiting on a pty. It should be called with the file descriptor of the pty.
+ Returns -1 on error; 0 if pty is still open; 1 if pty has closed.
+*/
+int
+pty_trap_handler(fd) int fd; {
+ struct request_info ri;
+
+ memset(&ri,0,sizeof(ri));
+ if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) {
+ debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno);
+ return(-1);
+ }
+ switch (ri.request) {
+ case TIOCOPEN:
+ debug(F110,"pty_trap_handler()","an open() call",0);
+ break;
+ case TIOCCLOSE:
+ debug(F110,"pty_trap_handler()","a close() call",0);
+ break;
+ default:
+ debug(F110,"pty_trap_handler()","an ioctl() call",0);
+ ri.errno_error = EINVAL;
+ }
+ if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) {
+ debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno);
+ return(-1);
+ }
+ if (ri.request == TIOCCLOSE)
+ return(1);
+ else
+ return(0);
+}
+#endif /* HAVE_PTYTRAP */
+
+VOID
+exec_cmd(s) char * s; {
+ struct stringarray * q;
+ char ** args = NULL;
+
+ if (!s) return;
+ if (!*s) return;
+
+ q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
+ if (!q) return;
+
+ args = q->a_head + 1;
+
+#ifdef DEBUG
+ {
+ int i, n;
+ n = q->a_size;
+ for (i = 0; i <= n; i++) {
+ if (!args[i]) {
+ debug(F111,"exec_cmd arg","NULL",i);
+ break;
+ } else {
+ debug(F111,"exec_cmd arg",args[i],i);
+ if (i == n && args[i]) {
+ debug(F101,"exec_cmd SUBSTITUTING NULL","",i);
+ if (strlen(args[i]) == 0)
+ makestr(&(args[i]),NULL);
+ }
+
+ }
+ }
+ }
+#endif /* DEBUG */
+
+ execvp(args[0],args);
+}
+
+/* Get a pty, scan input lines. */
+/* fc = 0 for interactive access; fc = 1 for running external protocols */
+
+static int pty_fc = -1; /* Global copy of fc */
+
+int
+do_pty(fd, cmd, fc) int * fd; char * cmd; int fc; {
+ long retval;
+ int syncpipe[2];
+ int i, ttyfd;
+#ifdef HAVE_PTYTRAP
+ int x;
+#endif /* HAVE_PTYTRAP */
+
+ debug(F101,"CKUPTY.C do_pty fc","",fc);
+
+ ttyfd = *fd;
+
+ pty_master_fd = -2;
+ pty_slave_fd = -2;
+ pty_fork_pid = -2;
+
+ msg = 0; /* Message counter */
+ pty_init(); /* Find an available pty to use. */
+ errno = 0;
+
+ if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) {
+ if (msg++ == 0)
+ perror(Xline);
+ debug(F111,"do_pty()","pty_getpty() fails",retval);
+ *fd = ttyfd;
+ return(-1);
+ }
+ *fd = ttyfd;
+ debug(F111,"do_pty() Xline",Xline,ttyfd);
+
+#ifdef SIGTTOU
+/*
+ Ignoring SIGTTOU keeps the kernel from blocking us. we tweak the tty with
+ an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel)
+*/
+ signal(SIGTTOU, SIG_IGN);
+#endif /* SIGTTOU */
+
+/* Start up the command on the slave side of the terminal */
+
+ if (pipe(syncpipe) < 0) {
+ debug(F110,"do_pty()","pipe() fails",0);
+ perror("pipe() failed");
+ msg++;
+ debug(F111,"do_pty()","pipe fails",errno);
+ return(-1);
+ }
+ if ((i = fork()) < 0) {
+ /* XXX - need to clean up the allocated pty */
+ perror("fork() failed");
+ msg++;
+ debug(F111,"do_pty()","fork fails",errno);
+ return(-1);
+ }
+ if (i) { /* Wait for child before writing to parent side of pty. */
+ char c;
+#ifdef HAVE_PTYTRAP
+ int on = 1;
+#endif /* HAVE_PTYTRAP */
+ close(syncpipe[1]);
+ errno = 0;
+ if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */
+ perror("Pipe read() failed");
+ msg++;
+ debug(F110,"do_pty()","Slave fails to initialize",0);
+ close(syncpipe[0]);
+ return(-1);
+ }
+ pty_fork_pid = i; /* So we can clean it up later */
+ pty_fork_active = 1;
+ debug(F101,"do_pty pty_fork_pid","",pty_fork_pid);
+#ifdef HAVE_PTYTRAP
+ /* HPUX does not allow the master to read end of file. */
+ /* Therefore, we must determine that the slave has been */
+ /* closed by trapping the call to close(). */
+ errno = 0;
+ x = ioctl(ttyfd, TIOCTRAP, (char *)&on);
+ debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno);
+#endif /* HAVE_PTYTRAP */
+ debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid);
+ close(syncpipe[0]);
+ } else {
+ int x;
+ debug(F101,"do_pty getptyslave ttyfd A","",ttyfd);
+ debug(F110,"do_pty()","Slave starts",0);
+ x = getptyslave(&ttyfd,fc);
+ debug(F101,"do_pty getptyslave","",x);
+ if (x == 0) {
+ debug(F101,"do_pty getptyslave ttyfd B","",ttyfd);
+#ifdef WANT_UTMP
+ pty_update_utmp(PTY_USER_PROCESS,
+ getpid(),
+ "KERMIT",
+ Xline,
+ cmd,
+ PTY_TTYSLOT_USABLE
+ );
+#endif /* WANT_UTMP */
+ /* Notify our parent we're ready to continue.*/
+ debug(F110,"do_pty()","slave synchronizing",0);
+ write(syncpipe[1],"y",1);
+ close(syncpipe[0]);
+ close(syncpipe[1]);
+
+ debug(F110,"do_pty cmd",cmd,"");
+ exec_cmd(cmd);
+ debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
+ }
+ *fd = ttyfd;
+ debug(F110,"do_pty()","getptyslave() fails - exiting",0);
+ exit(1);
+ }
+ *fd = ttyfd;
+ pty_fc = fc;
+ return(getpid());
+} /* end of do_pty() */
+
+
+VOID
+end_pty() {
+ msg = 0; /* Message counter */
+ debug(F101,"end_pty pty_fork_pid","",pty_fork_pid);
+ if (Xline[0] && pty_fork_pid >= 0) {
+ pty_cleanup(Xline,pty_fork_pid,1);
+ Xline[0] = '\0';
+ pty_fork_pid = -1;
+ pty_fork_active = 0;
+ debug(F101,"end_pty pty_fork_active","",pty_fork_active);
+ }
+ pty_fc = -1;
+}
+#endif /* NETPTY */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.h
new file mode 100644
index 0000000..374c508
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckupty.h
@@ -0,0 +1,193 @@
+/* C K U P T Y . H -- Includes and definitions for ckupty.c */
+
+/*
+ Copyright 1995 by the Massachusetts Institute of Technology.
+
+ Modified for use in C-Kermit by:
+
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+ November 1999
+*/
+#ifndef __PTY_INT_H__
+#include <sys/types.h>
+
+/* #define WANT_UTMP */
+/* We don't want all the utmp/wtmp stuff */
+
+#ifdef WANT_UTMP
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif /* HAVE_UTMP_H */
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif /* HAVE_UTMPX_H */
+#endif /* WANT_UTMP */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef __SCO__
+#include <sys/unistd.h>
+#endif /* __SCO__ */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+#include <sys/stat.h>
+#ifndef SUNOS41
+#include <sys/ioctl.h>
+#endif /* SUNOS41 */
+#include <sys/file.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <pwd.h>
+
+#ifdef HAVE_SYS_LABEL_H
+/* only SunOS 4? */
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif /* HAVE_SYS_LABEL_H */
+
+#include <signal.h>
+
+#ifdef HPUX
+#include <sys/ptyio.h>
+#endif /* HPUX */
+#ifdef sysvimp
+#include <compat.h>
+#endif /* sysvimp */
+
+#ifdef COMMENT
+/* I don't think we actually use this for anything */
+/* and it kills Slackware builds, where there is no select.h. */
+#ifndef NO_SYS_SELECT_H
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#endif /* NO_SYS_SELECT_H */
+#endif /* COMMENT */
+
+#ifdef HAVE_STREAMS
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif /* HAVE_STREAMS */
+
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+#include <termios.h>
+#else
+#include <sgtty.h>
+#endif /* ultrix */
+#else /* POSIX_TERMIOS */
+#include <sgtty.h>
+#endif /* POSIX_TERMIOS */
+
+#include <netdb.h>
+/* #include <syslog.h> */
+#ifndef ultrix
+#include <string.h>
+#endif /* ultrix */
+/* #include <sys/param.h> */ /* (now done in ckcdeb.h) */
+
+#ifdef HAVE_STREAMS
+/* krlogin doesn't test sys/tty... */
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif /* HAVE_SYS_TTY_H */
+
+#ifdef HAVE_SYS_PTYVAR_H
+/* Solaris actually uses packet mode, so the real macros are needed too */
+#include <sys/ptyvar.h>
+#endif /* HAVE_SYS_PTYVAR_H */
+#endif /* HAVE_STREAMS */
+
+#ifdef COMMENT
+/* This block moved to ckcdeb.h */
+#ifndef NO_OPENPTY
+/* For NetBSD, see makefile */
+#ifndef HAVE_OPENPTY
+#ifdef __FreeBSD__
+#define HAVE_OPENPTY
+#else
+#ifdef MACOSX10
+#define HAVE_OPENPTY
+#endif /* MACOSX10 */
+#endif /* __FreeBSD__ */
+#endif /* HAVE_OPENPTY */
+#endif /* NO_OPENPTY */
+#endif /* COMMENT */
+
+#ifdef HAVE_VHANGUP
+#ifndef OPEN_CTTY_ONLY_ONCE
+/*
+ Breaks under Ultrix and others where you cannot get controlling
+ terminal twice.
+*/
+#define VHANG_first
+#define VHANG_LAST
+#endif /* OPEN_CTTY_ONLY_ONCE */
+#endif /* HAVE_VHANGUP */
+
+/* Internal functions */
+_PROTOTYP(long ptyint_void_association,(void));
+_PROTOTYP(long ptyint_open_ctty ,(char *, int *));
+_PROTOTYP(VOID ptyint_vhangup, (void));
+
+#ifdef WANT_UTMP
+_PROTOTYP(long ptyint_update_wtmp, (struct utmp *, char *, char *));
+#endif /* WANT_UTMP */
+
+#define __PTY_INT_H__
+#endif /* __PTY_INT_H__ */
+
+#ifndef __LIBPTY_H__
+
+#ifdef WANT_UTMP
+/* Constants for pty_update_utmp */
+#define PTY_LOGIN_PROCESS 0
+#define PTY_USER_PROCESS 1
+#define PTY_DEAD_PROCESS 2
+#define PTY_TTYSLOT_USABLE (0x1) /* flags to update_utmp*/
+#define PTY_UTMP_USERNAME_VALID (0x2)
+#endif /* WANT_UTMP */
+
+_PROTOTYP(long pty_init,(void));
+_PROTOTYP(long pty_getpty, ( int *, char *, int));
+_PROTOTYP(long pty_open_slave, (char *, int *, int));
+_PROTOTYP(long pty_open_ctty, (char *, int *, int));
+_PROTOTYP(long pty_initialize_slave, (int));
+#ifdef WANT_UTMP
+_PROTOTYP(long pty_update_utmp, (int, int, char *, char *, char *, int));
+_PROTOTYP(long pty_logwtmp, (char *, char *, char *));
+#endif /* WANT_UTMP */
+_PROTOTYP(long pty_cleanup, (char *, int, int));
+
+#define PTY_GETPTY_STREAMS (44806912L)
+#define PTY_GETPTY_FSTAT (44806913L)
+#define PTY_GETPTY_NOPTY (44806914L)
+#define PTY_GETPTY_SLAVE_TOOLONG (44806915L)
+#define PTY_OPEN_SLAVE_OPENFAIL (44806916L)
+#define PTY_OPEN_SLAVE_CHMODFAIL (44806917L)
+#define PTY_OPEN_SLAVE_NOCTTY (44806918L)
+#define PTY_OPEN_SLAVE_CHOWNFAIL (44806919L)
+#define PTY_OPEN_SLAVE_LINE_PUSHFAIL (44806920L)
+#define PTY_OPEN_SLAVE_PUSH_FAIL (44806921L)
+#define PTY_OPEN_SLAVE_REVOKEFAIL (44806922L)
+#ifdef WANT_UTMP
+#define PTY_UPDATE_UTMP_PROCTYPE_INVALID (44806923L)
+#endif /* WANT_UTMP */
+#define PTY_OPEN_SLAVE_TOOSHORT (44806924L)
+#define ERROR_TABLE_BASE_pty (44806912L)
+
+extern struct error_table et_pty_error_table;
+
+#define __LIBPTY_H__
+#endif /* __LIBPTY_H__ */
+
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuscr.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuscr.c
new file mode 100644
index 0000000..7a2d9b7
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuscr.c
@@ -0,0 +1,688 @@
+#include "ckcsym.h"
+
+#ifndef NOICP
+#ifndef NOSCRIPT
+char *loginv = "Script Command, 9.0.032, 16 Oct 2009";
+
+/* C K U S C R -- expect-send script implementation */
+
+/*
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+ Original (version 1, 1985) author: Herm Fischer, Encino, CA.
+ Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0.
+ Maintained since 1985 by Frank da Cruz, Columbia University,
+ fdc@columbia.edu.
+
+ The module takes a UUCP-style script of the "expect send [expect send] ..."
+ format. It is intended to operate similarly to the way the common
+ UUCP L.sys login entries work. Conditional responses are supported:
+ expect[-send-expect[...]], as with UUCP. The send keyword EOT sends a
+ Control-d, and the keyword BREAK sends a break. Letters prefixed
+ by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return, '~x' xon,
+ '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'',
+ '~"', '~c' don't append return, '~o[o[o]]' octal character. As with
+ some uucp systems, sent strings are followed by ~r (not ~n) unless they
+ end with ~c. Null expect strings (e.g., ~0 or --) cause a short
+ delay, and are useful for sending sequences requiring slight pauses.
+
+ This module calls externally defined system-dependent functions for
+ communications i/o, as defined in ckcplm.txt, the C-Kermit Program Logic
+ Manual, and thus should be portable to all systems that implement those
+ functions, and where alarm() and signal() work as they do in UNIX.
+*/
+#include "ckcdeb.h"
+#include <signal.h>
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcnet.h"
+#include "ckcsig.h"
+
+_PROTOTYP( VOID flushi, (void) );
+_PROTOTYP( static VOID myflsh, (void) );
+_PROTOTYP( static int sequenc, (void) );
+_PROTOTYP( static VOID recvseq, (void) );
+_PROTOTYP( static int outseq, (void) );
+
+#ifdef MAC
+#define signal msignal
+#define SIGTYP long
+#define alarm malarm
+#define SIG_IGN 0
+#define SIGALRM 1
+#define SIGINT 2
+SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int);
+#endif /* MAC */
+
+#ifdef AMIGA
+#define signal asignal
+#define alarm aalarm
+#define SIGALRM (_NUMSIG+1)
+#define SIGTYP void
+SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
+unsigned aalarm(unsigned);
+#endif /* AMIGA */
+
+#ifdef STRATUS
+/* VOS doesn't have alarm(), but it does have some things we can work with. */
+/* however, we have to catch all the signals in one place to do this, so */
+/* we intercept the signal() routine and call it from our own replacement. */
+#define signal vsignal
+#define alarm valarm
+SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
+int valarm(int interval);
+#endif /* STRATUS */
+
+extern int sessft;
+extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet;
+extern int network, nettype, ttnproto;
+extern long speed;
+extern char ttname[];
+
+#ifdef NTSIG
+extern int TlsIndex;
+#endif /* NTSIG */
+#ifdef IKSD
+extern int inserver;
+#endif /* IKSD */
+
+static int is_tn = 0; /* Do Telnet negotiations */
+
+#ifndef NOSPL
+#ifdef DCMDBUF
+extern struct cmdptr *cmdstk;
+#else
+extern struct cmdptr cmdstk[];
+#endif /* DCMDBUF */
+extern int techo, cmdlvl;
+extern int mecho;
+#endif /* NOSPL */
+
+static int scr_echo; /* Whether to echo script commands */
+
+static int exp_alrm = 15; /* Time to wait for expect string */
+#define SND_ALRM 15 /* Time to allow for sending string */
+#define NULL_EXP 2 /* Time to pause on null expect strg*/
+#define DEL_MSEC 300 /* Milliseconds to pause on ~d */
+
+#define SBUFL 512
+static char seq_buf[SBUFL+2], *s; /* expect-send sequence buffer */
+static int got_it, no_cr;
+
+/* Connect state parent/child communication signal handlers */
+
+#ifdef COMMENT
+#ifdef CK_POSIX_SIG
+static sigjmp_buf alrmrng;
+#else
+static jmp_buf alrmrng;
+#endif /* CK_POSIX_SIG */
+#else
+static ckjmpbuf alrmrng;
+#endif /* COMMENT */
+
+static SIGTYP
+#ifdef CK_ANSIC
+scrtime(int foo) /* modem read failure handler, */
+#else
+scrtime(foo) int foo; /* Alarm handler */
+#endif /* CK_ANSIC */
+/* scrtime */ {
+
+#ifdef BEBOX
+#ifdef BE_DR_7
+ alarm_expired();
+#endif /* BE_DR_7 */
+#endif /* BEBOX */
+#ifdef NTSIG
+ if (foo == SIGALRM)
+ PostAlarmSigSem();
+ else
+ PostCtrlCSem();
+#else /* NTSIG */
+#ifdef NT
+ cklongjmp(ckjaddr(alrmrng),1);
+#else /* NT */
+ cklongjmp(alrmrng,1);
+#endif /* NT */
+#endif /* NTSIG */
+ SIGRETURN;
+}
+
+/*
+ Sequence interpreter -- pick up next sequence from command string,
+ decode escapes and place into seq_buf.
+
+ If string contains a ~d (delay) then sequenc() returns a 1 expecting
+ to be called again after the ~d executes.
+*/
+static int
+sequenc() {
+ int i;
+ char c, oct_char;
+
+ no_cr = 0; /* output needs cr appended */
+ for (i = 0; i < SBUFL; ) {
+ if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */
+ seq_buf[i] = '\0';
+ return(0) ;
+ }
+ if (*s == '~') { /* escape character */
+ s++;
+ switch (c = *s) {
+ case 'n': seq_buf[i++] = LF; break;
+ case 'r': seq_buf[i++] = CR; break;
+ case 't': seq_buf[i++] = '\t'; break;
+ case 'b': seq_buf[i++] = '\b'; break;
+ case 'q': seq_buf[i++] = '?'; break;
+#ifdef COMMENT
+/* The default case should catch these now... */
+ case '~': seq_buf[i++] = '~'; break;
+ case '-': seq_buf[i++] = '-'; break;
+#endif /* COMMENT */
+ case '\'': seq_buf[i++] = '\''; break;
+ case '\"': seq_buf[i++] = '\"'; break;
+ case 's': seq_buf[i++] = ' '; break;
+ case 'x': seq_buf[i++] = '\021'; break;
+ case 'c': no_cr = 1; break;
+ case 'd': { /* send what we have & then */
+ seq_buf[i] = '\0'; /* expect to send rest after */
+ no_cr = 1; /* sender delays a little */
+ s++;
+ return(1);
+ }
+ case 'w': { /* wait count */
+ exp_alrm = 15; /* default to 15 sec */
+ if (isdigit(*(s+1))) {
+ s++;
+ exp_alrm = *s & 15;
+ if (isdigit(*(s+1)) ) {
+ s++;
+ exp_alrm = exp_alrm * 10 + (*s & 15);
+ }
+ }
+ break;
+ }
+ default:
+ if ( isdigit(c) ) { /* octal character */
+ oct_char = (char) (c & 7); /* most significant digit */
+ if (isdigit( *(s+1) ) ) {
+ s++;
+ oct_char = (char) ((oct_char<<3) | ( *s & 7 ));
+ if (isdigit( *(s+1) ) ) {
+ s++;
+ oct_char = (char) ((oct_char<<3) | ( *s & 7 ));
+ }
+ }
+ seq_buf[i++] = oct_char;
+ break;
+ } else seq_buf[i++] = *s; /* Treat ~ as quote */
+ }
+ } else seq_buf[i++] = *s; /* Plain old character */
+ s++;
+ }
+ seq_buf[i] = '\0';
+ return(0); /* end of space, return anyway */
+}
+
+
+/* Output buffering for "recvseq" and "flushi" */
+
+#define MAXBURST 256 /* maximum size of input burst */
+static CHAR conbuf[MAXBURST]; /* buffer to hold output for console */
+static int concnt = 0; /* number of characters buffered */
+static CHAR sesbuf[MAXBURST]; /* buffer to hold output for session log */
+static int sescnt = 0; /* number of characters buffered */
+
+static VOID
+myflsh() {
+ if (concnt > 0) {
+ conxo(concnt, (char *) conbuf);
+ concnt = 0;
+ }
+ if (sescnt > 0) {
+ logstr((char *) sesbuf, sescnt);
+ sescnt = 0;
+ }
+}
+
+/* these variables are used to pass data between the recvseq() */
+/* and the dorseq(). They are necessary because in some versions */
+/* dorseq() is executed in a separate thread and data cannot be */
+/* passed by parameter. */
+
+static char *rseqe, * rseqgot, * rseqtrace ;
+static int rseql;
+
+static SIGTYP
+#ifdef CK_ANSIC
+dorseq(void * threadinfo)
+#else /* CK_ANSIC */
+dorseq(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* dorseq */ {
+ int i, x;
+ int burst = 0; /* chars remaining in input burst */
+
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ }
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+
+ while (!got_it) {
+ for (i = 0; i < rseql-1; i++) rseqgot[i] = rseqgot[i+1];
+ x = ttinc(0); /* Read a character */
+ debug(F101,"recvseq","",x);
+ if (x < 0) {
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN; /* Check for error */
+ }
+#ifdef NETCONN
+#ifdef TNCODE
+/* Check for telnet protocol negotiation */
+ if (((x & 0xff) == IAC) && is_tn) { /* Telnet negotiation */
+ myflsh();
+ burst = 0;
+ switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
+ case 2: duplex = 0; continue;
+ case 1: duplex = 1;
+ default: continue;
+ }
+ }
+#endif /* TNCODE */
+#endif /* NETCONN */
+ rseqgot[rseql-1] = (char) (x & 0x7f); /* Got a character */
+ burst--; /* One less waiting */
+ if (scr_echo) conbuf[concnt++] = rseqgot[rseql-1]; /* Buffer it */
+ if (seslog) /* Log it in session log */
+#ifdef UNIX
+ if (sessft != 0 || rseqgot[rseql-1] != '\r')
+#else
+#ifdef OSK
+ if (sessft != 0 || rseqgot[rseql-1] != '\012')
+#endif /* OSK */
+#endif /* UNIX */
+ if (rseqgot[rseql-1]) /* Filter out NULs */
+ sesbuf[sescnt++] = rseqgot[rseql-1];
+ if ((int)strlen(rseqtrace) < SBUFL-2 )
+ strcat(rseqtrace,dbchr(rseqgot[rseql-1]));
+ got_it = (!strncmp(rseqe, rseqgot, rseql));
+ if (burst <= 0) { /* Flush buffered output */
+ myflsh();
+ if ((burst = ttchk()) < 0) { /* Get size of next input burst */
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+ }
+ /* prevent overflow of "conbuf" and "sesbuf" */
+ if (burst > MAXBURST)
+ burst = MAXBURST;
+ }
+ }
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+}
+
+static SIGTYP
+#ifdef CK_ANSIC
+failrseq(void * threadinfo)
+#else /* CK_ANSIC */
+failrseq(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failrseq */ {
+ got_it = 0; /* Timed out here */
+ SIGRETURN;
+}
+
+/*
+ Receive sequence -- see if expected response comes,
+ return success (or failure) in got_it.
+*/
+static VOID
+recvseq() {
+ char *e, got[7], trace[SBUFL];
+ int i, l;
+
+ sequenc();
+ l = (int)strlen(e=seq_buf); /* no more than 7 chars allowed */
+ if (l > 7) {
+ e += l-7;
+ l = 7;
+ }
+ tlog(F111,"expecting sequence",e,(long) l);
+ if (l == 0) { /* null sequence, delay a little */
+ sleep (NULL_EXP);
+ got_it = 1;
+ tlog(F100,"got it (null sequence)","",0L);
+ return;
+ }
+ *trace = '\0';
+ for (i = 0; i < 7; i++) got[i]='\0';
+
+ rseqtrace = trace;
+ rseqe = e;
+ rseqgot = got;
+ rseql = l;
+
+ alrm_execute(ckjaddr(alrmrng), exp_alrm, scrtime, dorseq, failrseq);
+
+ tlog(F110,"received sequence: ",trace,0L);
+ tlog(F101,"returning with got-it code","",(long) got_it);
+ myflsh(); /* Flush buffered output */
+ return;
+}
+
+/*
+ Output A Sequence starting at pointer s,
+ return 0 if okay,
+ 1 if failed to read (modem hangup or whatever)
+*/
+static int oseqret = 0; /* Return code for outseq */
+ /* Out here to prevent clobbering */
+ /* by longjmp. */
+
+static SIGTYP
+#ifdef CK_ANSIC
+dooseq(void * threadinfo)
+#else /* CK_ANSIC */
+dooseq(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+{
+ int l;
+ char *sb;
+#ifdef TCPSOCKET
+ extern int tn_nlm, tn_b_nlm;
+#endif /* TCPSOCKET */
+
+#ifdef NTSIG
+ setint();
+ if (threadinfo) { /* Thread local storage... */
+ TlsSetValue(TlsIndex,threadinfo);
+ }
+#endif /* NTSIG */
+#ifdef CK_LOGIN
+#ifdef NT
+#ifdef IKSD
+ if (inserver)
+ setntcreds();
+#endif /* IKSD */
+#endif /* NT */
+#endif /* CK_LOGIN */
+
+ l = (int)strlen(seq_buf);
+ tlog(F111,"sending sequence ",seq_buf,(long) l);
+
+ if (!strcmp(seq_buf,"EOT")) {
+ ttoc(dopar('\004'));
+ if (scr_echo) conol("<EOT>");
+ if (seslog && duplex)
+ logstr("<EOT>",5);
+ } else if (!strcmp(seq_buf,"BREAK") ||
+ !strcmp(seq_buf,"\\b") ||
+ !strcmp(seq_buf,"\\B")) {
+ ttsndb();
+ if (scr_echo) conol("<BREAK>");
+ if (seslog)
+ logstr("{BREAK}",7);
+ } else {
+ if (l > 0) {
+ for ( sb = seq_buf; *sb; sb++)
+ *sb = dopar(*sb); /* add parity */
+ ttol((CHAR *)seq_buf,l); /* send it */
+ if (scr_echo && duplex) {
+#ifndef NOLOCAL
+#ifdef OS2
+ { /* Echo to emulator */
+ char *s = seq_buf;
+ while (*s) {
+ scriptwrtbuf((USHORT)*s);
+ }
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ conxo(l,seq_buf);
+ }
+ if (seslog && duplex) /* log it */
+ logstr(seq_buf,strlen(seq_buf));
+ }
+ if (!no_cr) {
+ ttoc( dopar(CR) );
+#ifdef TCPSOCKET
+ if (is_tn) {
+ if (!TELOPT_ME(TELOPT_BINARY) && tn_nlm != TNL_CR)
+ ttoc((char)((tn_nlm == TNL_CRLF) ?
+ dopar(LF) : dopar(NUL)));
+ else if (TELOPT_ME(TELOPT_BINARY) &&
+ (tn_b_nlm == TNL_CRLF || tn_b_nlm == TNL_CRNUL))
+ ttoc((char)((tn_b_nlm == TNL_CRLF) ?
+ dopar(LF) : dopar(NUL)));
+ }
+#endif /* TCPSOCKET */
+ if (seslog && duplex)
+ logchar(dopar(CR));
+ }
+ }
+#ifdef NTSIG
+ ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+ SIGRETURN;
+}
+
+SIGTYP
+#ifdef CK_ANSIC
+failoseq(void * threadinfo)
+#else /* CK_ANSIC */
+failoseq(threadinfo) VOID * threadinfo;
+#endif /* CK_ANSIC */
+/* failoseq */ {
+ oseqret = -1; /* else -- alarm rang */
+ SIGRETURN;
+}
+
+static int
+outseq() {
+ int delay;
+
+ oseqret = 0; /* Initialize return code */
+ while(1) {
+ delay = sequenc();
+ alrm_execute( ckjaddr(alrmrng), SND_ALRM, scrtime, dooseq, failoseq ) ;
+
+ if (!delay)
+ return(oseqret);
+#ifndef MAC
+ msleep(DEL_MSEC); /* delay, loop to next send */
+#endif /* MAC */
+ }
+}
+
+
+/* L O G I N -- (historical misnomer) Execute the SCRIPT command */
+
+int
+dologin(cmdstr) char *cmdstr; {
+
+#ifdef OS2
+#ifdef NT
+ SIGTYP (* savealm)(int); /* Save incoming alarm function */
+#else /* NT */
+ SIGTYP (* volatile savealm)(int); /* Save incoming alarm function */
+#endif /* NT */
+#else /* OS2 */
+ SIGTYP (*savealm)(); /* Save incoming alarm function */
+#endif /* OS2 */
+ char *e;
+
+ s = cmdstr; /* Make global to this module */
+
+ tlog(F100,loginv,"",0L);
+
+ if (speed < 0L) speed = ttgspd();
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) {
+ ckmakmsg(seq_buf,SBUFL,"Sorry, can't open ",ttname,NULL,NULL);
+ perror(seq_buf);
+ return(0);
+ }
+ /* Whether to echo script commands ... */
+ scr_echo = (!quiet && !backgrd && secho);
+#ifndef NOSPL
+ if (scr_echo && cmdlvl > 1) {
+ if (cmdstk[cmdlvl].src == CMD_TF)
+ scr_echo = techo;
+ if (cmdstk[cmdlvl].src == CMD_MD)
+ scr_echo = mecho;
+ }
+#endif /* NOSPL */
+ if (scr_echo) {
+#ifdef NETCONN
+ if (network)
+ printf("Executing SCRIPT to host %s.\n",ttname);
+ else
+#endif /* NETCONN */
+ printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed);
+ }
+#ifdef TNCODE
+ /* TELNET input must be scanned for IAC */
+ is_tn = (local && network && IS_TELNET()) ||
+ (!local && sstelnet);
+#endif /* TNCODE */
+
+ *seq_buf = 0;
+ for (e = s; *e; e++) ckstrncat(seq_buf,dbchr(*e),SBUFL);
+#ifdef COMMENT
+/* Skip this because it tends to contain a password... */
+ if (scr_echo) printf("SCRIPT string: %s\n",seq_buf);
+#endif /* COMMENT */
+ tlog(F110,"SCRIPT string: ",seq_buf, 0L);
+
+/* Condition console terminal and communication line... */
+
+ if (ttvt(speed,flow) < 0) {
+ printf("Sorry, Can't condition communication line\n");
+ return(0);
+ }
+ /* Save initial timer interrupt value */
+ savealm = signal(SIGALRM,SIG_IGN);
+
+ flushi(); /* Flush stale input */
+
+/* start expect - send sequence */
+
+ while (*s) { /* While not done with buffer */
+
+ while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
+ /* Gather up expect sequence */
+ got_it = 0;
+ recvseq();
+
+ while (!got_it) { /* Have it yet? */
+ if (*s++ != '-') /* No, is there a conditional send? */
+ goto failret; /* No, return failure */
+ flushi(); /* Yes, flush out input buffer */
+ if (outseq()) /* If unable to send, */
+ goto failret; /* return failure. */
+ if (*s++ != '-') /* If no conditional response here, */
+ goto failret; /* return failure. */
+ recvseq(); /* All OK, read response from host. */
+ } /* Loop back and check got_it */
+
+ while (*s && !isspace(*s++) ) ; /* Skip over conditionals */
+ while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
+ flushi(); /* Flush */
+ if (*s) if (outseq()) goto failret; /* If any */
+ }
+ signal(SIGALRM,savealm);
+ if (scr_echo) printf("Script successful.\n");
+ tlog(F100,"Script successful.","",0L);
+ return(1);
+
+failret:
+ signal(SIGALRM,savealm);
+ if (scr_echo) printf("Sorry, script failed\n");
+ tlog(F100,"Script failed","",0L);
+ return(0);
+}
+
+/* F L U S H I -- Flush, but log, SCRIPT input buffer */
+
+VOID
+flushi() {
+ int n, x;
+ if (
+ seslog /* Logging session? */
+ || scr_echo /* Or console echoing? */
+#ifdef NETCONN
+#ifdef TNCODE
+ /* TELNET input must be scanned for IAC */
+ || is_tn
+#endif /* TNCODE */
+#endif /* NETCONN */
+ ) {
+ if ((n = ttchk()) < 0) /* Yes, anything in buffer? */
+ return;
+ if (n > MAXBURST) n = MAXBURST; /* Make sure not too much, */
+ myflsh(); /* and that buffers are empty. */
+ while (n-- > 0) {
+ x = ttinc(0); /* Collect a character */
+#ifdef NETCONN
+#ifdef TNCODE
+/* Check for telnet protocol negotiation */
+ if (is_tn && ((x & 0xff) == IAC) ) {
+ myflsh(); /* Sync output */
+ switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
+ case 2: duplex = 0; break;
+ case 1: duplex = 1;
+ default: break;
+ }
+
+ /* Recalculate flush count */
+ if ((n = ttchk()) < 0)
+ return;
+ if (n > MAXBURST) n = MAXBURST;
+ continue;
+ }
+#endif /* TNCODE */
+#endif /* NETCONN */
+ if (scr_echo) conbuf[concnt++] = (CHAR) x; /* buffer for console */
+ if (seslog)
+#ifdef UNIX
+ if (sessft != 0 || x != '\r')
+#else
+#ifdef OSK
+ if (sessft != 0 || x != '\012')
+#endif /* OSK */
+#endif /* UNIX */
+ sesbuf[sescnt++] = (CHAR) x; /* buffer for session log */
+ }
+ myflsh();
+ } else ttflui(); /* Otherwise just flush. */
+}
+
+#else /* NOSCRIPT */
+char *loginv = "Script Command Disabled";
+#endif /* NOSCRIPT */
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckusig.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckusig.c
new file mode 100644
index 0000000..e4556e5
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckusig.c
@@ -0,0 +1,354 @@
+char *ckusigv = "Signal support, 9.0.100, 16 Oct 2009";
+
+/* C K U S I G -- Kermit signal handling for Unix and OS/2 systems */
+
+/*
+ Author: Jeffrey Altman (jaltman@secure-endpoints.com),
+ Secure Endpoints Inc., New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#include "ckcsym.h"
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckcdeb.h" /* Debug & other symbols */
+#include "ckcker.h" /* Kermit symbols */
+#include "ckcnet.h" /* Network symbols */
+#ifndef NOSPL
+#include "ckuusr.h"
+#endif /* NOSPL */
+
+#include <signal.h>
+#ifdef NT
+#include <setjmpex.h>
+#include <excpt.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcsig.h"
+
+#ifdef NOCCTRAP
+extern ckjmpbuf cmjbuf;
+#endif /* NOCCTRAP */
+
+#ifdef MAC
+#define signal msignal
+#define SIGTYP long
+#define alarm malarm
+#define SIG_IGN 0
+#define SIGALRM 1
+#define SIGINT 2
+SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int);
+#endif /* MAC */
+
+#ifdef STRATUS
+/* We know these are set here. MUST unset them before the definitions. */
+#define signal vsignal
+#define alarm valarm
+SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
+int valarm(int interval);
+#endif /* STRATUS */
+
+#ifdef AMIGA
+#define signal asignal
+#define alarm aalarm
+#define SIGALRM (_NUMSIG+1)
+#define SIGTYP void
+SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
+unsigned aalarm(unsigned);
+#endif /* AMIGA */
+
+#ifdef NTASM
+DWORD
+ckgetIP(void)
+{
+ __asm
+ {
+ mov eax, dword ptr [esp+0x10]
+ jmp ckgetIP + 0x18
+ }
+ return 1;
+
+}
+#endif /* NTASM */
+
+#ifdef NT
+DWORD
+exception_filter( void )
+{
+ GetExceptionInformation ;
+ return( EXCEPTION_EXECUTE_HANDLER ) ;
+}
+void
+crash( void )
+{
+ int x = 0, y = 0 ;
+ x / y ;
+}
+#endif /* NT */
+
+#ifndef NOCCTRAP
+int
+#ifdef CK_ANSIC
+cc_execute( ckjptr(sj_buf), ck_sigfunc dofunc, ck_sigfunc failfunc )
+#else
+cc_execute( sj_buf, dofunc, failfunc)
+ ckjptr(sj_buf);
+ ck_sigfunc dofunc;
+ ck_sigfunc failfunc;
+#endif /* CK_ANSIC */
+/* cc_execute */ {
+ int rc = 0 ;
+#ifdef NTASM
+ DWORD Eip, Esp ;
+ isinterrupted = 0;
+ sj_buf->retcode = 0 ;
+ sj_buf->Id = GetCurrentThreadId() ;
+ memset( &sj_buf->context, 0, sizeof(CONTEXT) );
+ sj_buf->context.ContextFlags = CONTEXT_FULL ;
+#ifndef COMMENT
+ GetThreadContext(GetCurrentThread(), &(sj_buf->context) ) ;
+ __asm
+ {
+ mov ecx,dword ptr [sj_buf]
+ mov dword ptr [ecx+0xc4],esp
+ }
+ sj_buf->context.EFlags = 530 ;
+ sj_buf->context.Eip = ckgetIP()+0x0C ;
+#else /* COMMENT */
+ __asm
+ {
+ mov eax, dword ptr [sj_buf]
+ push eax
+ mov eax, 0xfffffffe
+ push eax
+ mov eax, 0x00000039
+ mov edx,esp
+ int 0x2e
+ pop eax
+ pop eax
+ }
+#endif /* COMMENT */
+#endif /* NTASM */
+ if (
+#ifdef NTASM
+ isinterrupted
+#else
+ cksetjmp(ckjdref(sj_buf))
+#endif /* NTASM */
+ ) {
+#ifdef NTASM
+ __asm
+ {
+ mov esp, ESPToRestore
+ }
+ isinterrupted = 0 ;
+#endif /* NTASM */
+ (*failfunc)(NULL) ;
+#ifdef NTASM
+ rc = sj_buf->retcode ;
+#else /* NTASM */
+ rc = -1 ;
+#endif /* NTASM */
+ } else {
+#ifdef NT
+ __try {
+ (*dofunc)(NULL);
+ }
+ __except(exception_filter())
+ {
+ debug(F100,"cc_execute __except","",0);
+ debug(F111,
+ "exception_filter",
+ "_exception_code",
+ etExceptionCode()
+ );
+ longjmp(ckjdref(sj_buf),SIGINT);
+ }
+#else /* NT */
+ (*dofunc)(NULL);
+#endif /* NT */
+ }
+ return rc ;
+}
+#endif /* NOCCTRAP */
+
+int
+#ifdef CK_ANSIC /* ANSIC C declaration... */
+alrm_execute(ckjptr(sj_buf),
+ int timo,
+ ck_sighand handler,
+ ck_sigfunc dofunc,
+ ck_sigfunc failfunc
+ )
+
+#else /* Not ANSIC C ... */
+
+alrm_execute(sj_buf,
+ timo,
+ handler,
+ dofunc,
+ failfunc
+ )
+ ckjptr(sj_buf);
+ int timo;
+ ck_sighand handler;
+ ck_sigfunc dofunc;
+ ck_sigfunc failfunc;
+#endif /* CK_ANSIC */
+
+/* alrm_execute */ {
+
+ int rc = 0;
+ int savalrm = 0;
+_PROTOTYP(SIGTYP (*savhandler), (int));
+
+ savalrm = alarm(timo);
+ savhandler = signal(SIGALRM, handler);
+
+#ifdef NTASM
+ sj_buf->retcode = 0 ;
+ sj_buf->Id = GetCurrentThreadId();
+ memset(&sj_buf->context, 0, sizeof(CONTEXT));
+ sj_buf->context.ContextFlags = CONTEXT_FULL;
+#ifndef COMMENT
+ GetThreadContext(GetCurrentThread(), &(sj_buf->context));
+#else
+ __asm
+ {
+ mov eax, dword ptr [sj_buf]
+ push eax
+ mov eax, 0xfffffffe
+ push eax
+ mov eax, 0x00000039
+ mov edx,esp
+ int 0x2e
+ pop eax
+ pop eax
+ }
+#endif
+ isinterrupted = 0;
+#endif /* NTASM */
+ if (
+#ifdef NTASM
+ sj_buf->retcode
+#else
+ cksetjmp(ckjdref(sj_buf))
+#endif /* NTASM */
+ ) {
+ (*failfunc)(NULL) ;
+ rc = -1 ;
+ } else {
+#ifdef NT
+ __try {
+ (*dofunc)(NULL) ;
+ }
+ __except( exception_filter() )
+ {
+ debug(F100,"alrm_execute __except","",0);
+ debug(F111,"exception_filter",
+ "_exception_code",
+ GetExceptionCode()
+ );
+ longjmp(ckjdref(sj_buf),SIGINT);
+ }
+#else /* NT */
+ (*dofunc)(NULL) ;
+#endif /* NT */
+ }
+ alarm(savalrm) ;
+ if ( savhandler )
+ signal( SIGALRM, savhandler ) ;
+ return rc ;
+}
+
+int
+#ifdef CK_ANSIC /* ANSIC C declaration... */
+cc_alrm_execute(ckjptr(sj_buf),
+ int timo,
+ ck_sighand handler,
+ ck_sigfunc dofunc,
+ ck_sigfunc failfunc
+ )
+
+#else /* Not ANSIC C ... */
+
+cc_alrm_execute(sj_buf,
+ timo,
+ handler,
+ dofunc,
+ failfunc
+ )
+ ckjptr(sj_buf);
+ int timo;
+ ck_sighand handler;
+ ck_sigfunc dofunc;
+ ck_sigfunc failfunc;
+#endif /* CK_ANSIC */
+
+/* cc_alrm_execute */ {
+
+ int rc = 0;
+ int savalrm = 0;
+_PROTOTYP(SIGTYP (*savhandler), (int));
+ savalrm = alarm(timo);
+ savhandler = signal( SIGALRM, handler );
+
+#ifdef NTASM
+ sj_buf->retcode = 0 ;
+ sj_buf->Id = GetCurrentThreadId() ;
+ memset( &sj_buf->context, 0, sizeof(CONTEXT) );
+ sj_buf->context.ContextFlags = CONTEXT_FULL ;
+#ifndef COMMENT
+ GetThreadContext( GetCurrentThread(), &(sj_buf->context) ) ;
+#else
+ __asm
+ {
+ mov eax, dword ptr [sj_buf]
+ push eax
+ mov eax, 0xfffffffe
+ push eax
+ mov eax, 0x00000039
+ mov edx,esp
+ int 0x2e
+ pop eax
+ pop eax
+ }
+#endif
+ isinterrupted = 0;
+#endif /* NTASM */
+ if (
+#ifdef NTASM
+ sj_buf->retcode
+#else
+ cksetjmp(ckjdref(sj_buf))
+#endif /* NTASM */
+ ) {
+ (*failfunc)(NULL) ;
+ rc = -1 ;
+ } else {
+#ifdef NT
+ __try {
+ (*dofunc)(NULL) ;
+ }
+ __except( exception_filter() )
+ {
+ debug(F100,"cc_alrm_execute __except","",0);
+ debug(F111,
+ "exception_filter",
+ "_exception_code",
+ GetExceptionCode()
+ );
+ longjmp(ckjdref(sj_buf),SIGINT) ;
+ }
+#else /* NT */
+ (*dofunc)(NULL) ;
+#endif /* NT */
+ }
+ alarm(savalrm);
+ if (savhandler)
+ signal(SIGALRM,savhandler);
+ return(rc);
+}
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckusig.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckusig.h
new file mode 100644
index 0000000..3482900
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckusig.h
@@ -0,0 +1,79 @@
+/* C K U S I G . H */
+
+/* Definitions and prototypes for signal handling */
+
+/*
+ Author: Jeffrey E Altman (jaltman@secure-endpoints.com),
+ Secure Endpoints Inc., New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+#ifdef CK_ANSIC
+typedef void (*ck_sigfunc)(void *);
+typedef void (*ck_sighand)(int);
+#else
+typedef VOID (*ck_sigfunc)();
+typedef VOID (*ck_sighand)();
+#endif /* CK_ANSIC */
+
+/* Macros for POSIX vs old-style signal handling. */
+
+#ifdef CK_POSIX_SIG
+typedef sigjmp_buf ckjmpbuf;
+#else
+typedef jmp_buf ckjmpbuf;
+#endif /* CK_POSIX_SIG */
+/*
+ Suppose you want to pass the address of a jmp_buf bar to a function foo.
+ Since jmp_buf is normally defined (typedef'd) as an array, you would do
+ it like this: foo(bar), where foo = foo(jmp_buf bar). But suppose a
+ jmp_buf is (say) a struct rather than an array. Then you must do
+ foo(&bar) where foo is foo(jmp_buf * bar). This is controlled here in
+ the traditional fashion, by ifdefs. By default, we assume that jmp_buf
+ is an array. Define the symbol JBNOTARRAY if jmp_buf is not an array.
+*/
+#ifndef JBNOTARRAY
+#ifdef NT
+#define JBNOTARRAY
+#endif /* NT */
+#endif /* JBNOTARRAY */
+
+#ifdef JBNOTARRAY
+typedef ckjmpbuf * ckjptr;
+#define ckjaddr(x) & x
+#define ckjdref(x) * x
+#ifdef CK_POSIX_SIG
+#define cksetjmp(x) sigsetjmp(x,1)
+#else
+#define cksetjmp(x) setjmp(x,1)
+#endif /* CK_POSIX_SIG */
+#else /* jmp_buf is an array */
+typedef ckjmpbuf ckjptr;
+#define ckjaddr(x) x
+#define ckjdref(x) x
+#ifdef CK_POSIX_SIG
+#define cksetjmp sigsetjmp
+#else
+#define cksetjmp setjmp
+#endif /* CK_POSIX_SIG */
+#endif /* JBNOTARRAY */
+
+_PROTOTYP( int cc_execute, (ckjptr, ck_sigfunc, ck_sigfunc) );
+_PROTOTYP( int alrm_execute,
+ (ckjptr,
+ int timo,
+ ck_sighand handler,
+ ck_sigfunc, ck_sigfunc) );
+_PROTOTYP( int cc_alrm_execute,
+ (ckjptr,
+ int timo,
+ ck_sighand handler,
+ ck_sigfunc,
+ ck_sigfunc) );
+
+/* End of ckusig.h */
+
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckutio.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckutio.c
new file mode 100644
index 0000000..0d79e0c
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckutio.c
@@ -0,0 +1,16054 @@
+#define CKUTIO_C
+
+#ifdef aegis
+char *ckxv = "Aegis Communications support, 9.0.326, 20 August 2011";
+#else
+#ifdef Plan9
+char *ckxv = "Plan 9 Communications support, 9.0.326, 20 August 2011";
+#else
+char *ckxv = "UNIX Communications support, 9.0.326, 20 August 2011";
+#endif /* Plan9 */
+#endif /* aegis */
+
+/* C K U T I O */
+
+/* C-Kermit interrupt, communications control and I/O functions for UNIX */
+
+/*
+ Author: Frank da Cruz (fdc@columbia.edu),
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
+ compatible with C preprocessors that support only #ifdef, #else, #endif,
+ #define, and #undef. Please do not use #if, logical operators, or other
+ preprocessor features in any of the portable C-Kermit modules. You can,
+ of course, use these constructions in platform-specific modules when they
+ are supported by all compilers/preprocessors that could be used on that
+ platform.
+*/
+
+extern int nettype; /* Defined in ckcmai.c */
+extern int duplex;
+
+/* Includes */
+
+#include "ckcsym.h" /* This must go first */
+#include "ckcdeb.h" /* This must go second */
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#ifdef __386BSD__
+#define ENOTCONN 57
+#else
+#ifdef __bsdi__
+#define ENOTCONN 57
+#else
+#ifdef __FreeBSD__
+#define ENOTCONN 57
+#endif /* __FreeBSD__ */
+#endif /* __bsdi__ */
+#endif /* __386BSD__ */
+
+#ifdef SCO_OSR504
+#define NBBY 8
+#endif /* SCO_OSR504 */
+
+#ifdef Plan9
+#define SELECT
+#include <sys/time.h>
+#include <select.h>
+#define FD_SETSIZE (3 * sizeof(long) * 8)
+static struct timeval tv;
+#endif /* Plan9 */
+
+#ifdef CLIX
+#include <sys/time.h>
+#endif /* CLIX */
+
+#include "ckcnet.h" /* Symbols for network types. */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+/*
+ The directory-related includes are here because we need to test some
+ file-system-related symbols to find out which system we're being compiled
+ under. For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
+*/
+#ifdef SDIRENT /* Directory bits... */
+#define DIRENT
+#endif /* SDIRENT */
+
+#ifdef XNDIR
+#include <sys/ndir.h>
+#else /* !XNDIR */
+#ifdef NDIR
+#include <ndir.h>
+#else /* !NDIR, !XNDIR */
+#ifdef RTU
+#include "/usr/lib/ndir.h"
+#else /* !RTU, !NDIR, !XNDIR */
+#ifdef DIRENT
+#ifdef SDIRENT
+#include <sys/dirent.h>
+#else
+#include <dirent.h>
+#endif /* SDIRENT */
+#else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
+#include <sys/dir.h>
+#endif /* DIRENT */
+#endif /* RTU */
+#endif /* NDIR */
+#endif /* XNDIR */
+
+#ifdef QNX
+#include <sys/dev.h>
+#endif /* QNX */
+
+#ifdef HPUX5
+#ifndef TCPSOCKET
+/* I don't know why this is needed here since we never reference bzero(). */
+/* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
+void
+bzero(s,n) char *s; int n; {
+ extern char * memset();
+ memset(s,0,n);
+}
+#endif /* TCPSOCKET */
+#endif /* HPUX5 */
+
+/* Definition of HZ, used in msleep() */
+
+#ifdef MIPS
+#define HZ ( 1000 / CLOCK_TICK )
+#else /* MIPS */
+#ifdef ATTSV
+#ifndef NAP
+#ifdef TRS16
+#define HZ ( 1000 / CLOCK_TICK )
+#endif /* TRS16 */
+#ifdef NAPHACK
+#define nap(x) (void)syscall(3112, (x))
+#define NAP
+#endif /* NAPHACK */
+#endif /* NAP */
+#endif /* ATTSV */
+#endif /* MIPS */
+
+#ifdef M_UNIX
+#undef NGROUPS_MAX /* Prevent multiple definition warnings */
+#endif /* M_UNIX */
+
+/*
+ NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
+ library routine, so _poll comes up undefined at link time.
+*/
+#ifdef CK_POLL
+#ifndef AIXRS /* IBM AIX needs special handling */
+#include <poll.h> /* "standard" (SVID) i/o multiplexing, etc */
+#else /* AIXRS */
+#ifdef SVR4 /* AIX 3.2 is like SVID... */
+#include <poll.h>
+#else /* But AIX 3.1 is not ... */
+#include <sys/poll.h> /* The include file is in include/sys */
+#define events reqevents /* And it does not map IBM-specific member */
+#define revents rtnevents /* names to the System V equivalents */
+#endif /* SVR4 */
+#endif /* AIXRS */
+#endif /* CK_POLL */
+
+#include <signal.h> /* Signals */
+
+/* For setjmp and longjmp */
+
+#ifndef ZILOG
+#include <setjmp.h>
+#else
+#include <setret.h>
+#endif /* ZILOG */
+
+/*
+ The following test differentiates between 4.1 BSD and 4.2 & later.
+ If you have a 4.1BSD system with the DIRENT library, this test could
+ mistakenly diagnose 4.2BSD and then later enable the use of system calls
+ that aren't defined. If indeed there are such systems, we can use some
+ other way of testing for 4.1BSD, or add yet another compile-time switch.
+*/
+#ifdef BSD4
+#ifdef MAXNAMLEN
+#ifndef FT21 /* Except for Fortune. */
+#ifndef FT18
+#ifndef BELLV10 /* And Bell Labs Research UNIX V10 */
+#define BSD42
+#endif /* BELLV10 */
+#endif /* FT18 */
+#endif /* FT21 */
+#endif /* MAXNAMLEN */
+#endif /* BSD4 */
+
+#ifdef SUNOS41 /* From Christian Corti */
+#define BSD44ORPOSIX /* Uni Stuttgart */
+#define SVORPOSIX /* February 2010 */
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <limits.h>
+#endif /* SUNOS41 */
+
+#ifdef SNI542
+#include <sys/filio.h> /* 299 for FIONREAD */
+#endif /* SNI542 */
+
+/*
+ Minix 2.0 support added by Terry McConnell,
+ Syracuse University <tmc@barnyard.syr.edu>
+ No more sgtty interface, posix compliant.
+*/
+#ifdef MINIX2
+#define _MINIX /* Needed for some Minix header files */
+#define BSD44ORPOSIX
+#define SVORPOSIX
+#ifndef MINIX3
+#define DCLTIMEVAL
+#endif /* MINIX3 */
+#define NOFILEH
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <limits.h>
+#undef TIOCGETC /* defined in sys/ioctl.h, but not really supported */
+#define TANDEM 0
+#endif /* MINIX2 */
+
+/*
+ MINIX 1.0 support added by Charles Hedrick,
+ Rutgers University <hedrick@aramis.rutgers.edu>.
+ MINIX also has V7 enabled.
+*/
+#ifdef MINIX
+#define TANDEM 0
+#define MYREAD
+#define NOSYSIOCTLH
+#include <limits.h>
+#endif /* MINIX */
+
+#ifdef CK_REDIR /* <sys/wait.h> needed only for REDIRECT command. */
+/*
+ If anybody can figure out how to make this work with NeXTSTEP, be
+ my guest! (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
+*/
+#ifndef CK_WAIT_H /* If wait.h not already included... */
+#ifdef OSF /* force OSF to select POSIX wait */
+#ifdef _BSD /* instead of BSD (see ckcdeb.h) */
+#define CK_OSF_BSD
+#undef _BSD
+#endif /* _BSD */
+#endif /* OSF */
+#include <sys/wait.h> /* Include it */
+#ifdef OSF
+#ifdef CK_OSF_BSD
+#define _BSD /* Restore it */
+#undef CK_OSF_BSD
+#endif /* CK_OSF_BSD */
+#endif /* OSF */
+#endif /* CK_WAIT_H */
+#endif /* CK_REDIR */
+
+#include "ckuver.h" /* Version herald */
+char *ckxsys = HERALD;
+
+#ifdef CK_UTSNAME
+#include <sys/utsname.h>
+
+#ifdef TRU64 /* Tru64 UNIX 4.0 and later */
+/* Verified on Tru64 4.0F - might break on 4.0E or earlier */
+#include <sys/sysinfo.h> /* (don't know about OSF/1 or DU) */
+#include <machine/hal_sysinfo.h>
+#endif /* TRU64 */
+
+#ifdef SOLARIS25 /* Solaris 2.5 and later */
+#include <sys/systeminfo.h> /* (don't know about earlier ones) */
+#endif /* SOLARIS25 */
+
+#ifdef UW7
+#ifndef SYS_NMLN
+#define SYS_NMLN 257
+#endif /* NMLN */
+#endif /* UW7 */
+#ifdef HPUX9PLUS
+static int hpis800 = 0;
+#endif /* HPUX9PLUS */
+#ifdef SYS_NMLN
+#define CK_SYSNMLN SYS_NMLN
+#else
+#ifdef _SYS_NMLN
+#define CK_SYSNMLN _SYS_NMLN
+#else
+#ifdef UTSLEN
+#define CK_SYSNMLN UTSLEN
+#else
+#define CK_SYSNMLN 31
+#endif /* UTSLEN */
+#endif /* _SYS_NMLN */
+#endif /* SYS_NMLN */
+char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
+#endif /* CK_UTSNAME */
+
+#ifdef CIE
+#include <stat.h> /* For chasing symlinks, etc. */
+#else
+#include <sys/stat.h>
+#endif /* CIE */
+
+#ifdef QNX /* 299 */
+#ifndef IXANY
+#define IXANY 0
+#endif /* IXANY */
+#endif /* QNX */
+
+/* UUCP lockfile material... */
+
+#ifndef NOUUCP
+#ifdef USETTYLOCK
+#ifdef HAVE_LOCKDEV /* Red Hat baudboy/lockdev */
+/*
+ Watch out: baudboy.h references open() without making sure it has been
+ declared, resulting in warnings on at least Red Hat 7.3. It's declared in
+ fcntl.h, but we don't include that until later. In this case only, we
+ include it here, and then the second include is harmless because in Red Hat
+ Linux (the only place where you find baudboy.h) fcntl.h is protected from
+ multiple inclusion by _FCNTL_H. - fdc, 10 May 2004.
+
+ NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or
+ setgid bits to access the lockfile, C-Kermit will still need them to access
+ the serial port itself unless the port is open for world read/write.
+ Normally setgid uucp does the trick.
+
+ Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy
+ but ttylock. - jb, 26 Jul 2010
+*/
+#include <fcntl.h> /* This has to come before baudboy */
+#ifdef HAVE_BAUDBOY /* Red Hat baudboy/lockdev */
+#include <baudboy.h>
+#else /* !HAVE_BAUDBOY */ /* openSuSE lock via ttylock */
+#include <ttylock.h>
+#endif /* HAVE_BAUDBOY */
+#define LOCK_DIR "/var/lock" /* (even though we don't care) */
+
+#else /* !HAVE_LOCKDEV */
+
+#ifdef USE_UU_LOCK
+#ifdef __FreeBSD__
+#include <libutil.h> /* FreeBSD */
+#else
+#include <util.h> /* OpenBSD */
+#endif /* HAVE_LOCKDEV */
+#endif /* __FreeBSD */
+#endif /* USE_UU_LOCK */
+#else /* USETTYLOCK */
+
+/* Name of UUCP tty device lockfile */
+
+#ifdef LINUXFSSTND
+#ifndef HDBUUCP
+#define HDBUUCP
+#endif /* HDBUUCP */
+#endif /* LINUXFSSTND */
+
+#ifdef ACUCNTRL
+#define LCKDIR
+#endif /* ACUCNTRL */
+
+/*
+ PIDSTRING means use ASCII string to represent pid in lockfile.
+*/
+#ifndef PIDSTRING
+#ifdef HDBUUCP
+#define PIDSTRING
+#else
+#ifdef BSD44
+#define PIDSTRING
+#else
+#ifdef RTAIX
+#define PIDSTRING
+#else
+#ifdef AIXRS
+#define PIDSTRING
+#else
+#ifdef COHERENT
+#define PIDSTRING
+#endif /* COHERENT */
+#endif /* AIXRS */
+#endif /* RTAIX */
+#endif /* BSD44 */
+#endif /* HDBUUCP */
+#endif /* PIDSTRING */
+
+/* Now the PIDSTRING exceptions... */
+
+#ifdef PIDSTRING
+#ifdef HPUX
+#undef PIDSTRING
+#endif /* HPUX */
+#endif /* PIDSTRING */
+
+#ifdef __bsdi__ /* BSDI (at least thru 1.1) */
+#ifdef PIDSTRING
+#undef PIDSTRING
+#endif /* PIDSTRING */
+#endif /* __bsdi__ */
+
+#ifdef OSF32 /* Digital UNIX (OSF/1) 3.2 */
+#ifdef PIDSTRING
+#undef PIDSTRING
+#endif /* PIDSTRING */
+#endif /* OSF32 */
+
+/*
+ LOCK_DIR is the name of the lockfile directory.
+ If LOCK_DIR is already defined (e.g. on command line), we don't change it.
+*/
+
+#ifndef LOCK_DIR
+#ifdef MACOSX
+#define LOCK_DIR "/var/spool/lock"
+#endif /* MACOSX */
+#endif/* LOCK_DIR */
+
+#ifndef LOCK_DIR
+#ifdef BSD44
+#ifdef __386BSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+#ifdef __FreeBSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+#ifdef __NetBSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+#ifdef __OpenBSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+/* So which ones is this for? */
+/* Probably original 4.4BSD on Vangogh */
+/* Plus who knows about Mac OS X... It doesn't even have a cu program */
+#define LOCK_DIR "/var/spool/uucp"
+#endif /* __OpenBSD__ */
+#endif /* __NetBSD__ */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#else
+#ifdef DGUX430
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef HPUX10
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef RTAIX /* IBM RT PC AIX 2.2.1 */
+#define LOCK_DIR "/etc/locks"
+#else
+#ifdef AIXRS
+#define LOCK_DIR "/etc/locks"
+#else
+#ifdef ISIII
+#define LOCK_DIR "/etc/locks"
+#else
+#ifdef HDBUUCP
+#ifdef M_SYS5
+#define LOCK_DIR "/usr/spool/uucp"
+#else
+#ifdef M_UNIX
+#define LOCK_DIR "/usr/spool/uucp"
+#else
+#ifdef SVR4
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef SUNOS4
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef LINUXFSSTND
+#define LOCK_DIR "/var/lock";
+#else
+#define LOCK_DIR "/usr/spool/locks"
+#endif /* LINUXFSSTND */
+#endif /* SUNOS4 */
+#endif /* SVR4 */
+#endif /* M_UNIX */
+#endif /* M_SYS5 */
+#else
+#ifdef LCKDIR
+#define LOCK_DIR "/usr/spool/uucp/LCK"
+#else
+#ifdef COHERENT
+#define LOCK_DIR "/usr/spool/uucp"
+#else
+#define LOCK_DIR "/usr/spool/uucp"
+#endif /* COHERENT */
+#endif /* LCKDIR */
+#endif /* HDBUUCP */
+#endif /* ISIII */
+#endif /* AIXRS */
+#endif /* RTAIX */
+#endif /* HPUX10 */
+#endif /* DGUX430 */
+#endif /* BSD44 */
+#endif /* !LOCK_DIR (outside ifndef) */
+
+#ifdef OSF2 /* OSF/1 2.0 or later */
+#ifdef LOCK_DIR /* (maybe 1.x too, who knows...) */
+#undef LOCK_DIR
+#define LOCK_DIR "/var/spool/locks"
+#endif /* LOCK_DIR */
+#endif /* OSF2 */
+
+#ifdef COMMENT
+/* Sorry no more lockf() -- we lock first and THEN open the device. */
+#ifdef SVR4
+#ifndef BSD44
+#ifndef LOCKF
+#define LOCKF /* Use lockf() on tty device in SVR4 */
+#endif /* LOCKF */
+#endif /* BSD44 */
+#endif /* SVR4 */
+#endif /* COMMENT */
+
+#ifdef NOLOCKF /* But NOLOCKF cancels LOCKF */
+#ifdef LOCKF
+#undef LOCKF
+#endif /* LOCKF */
+#endif /* NOLOCKF */
+
+/* More about this below... */
+
+#endif /* USETTYLOCK */
+#endif /* NOUUCP */
+
+/*
+ MYREAD means use our internally defined nonblocking buffered read routine.
+*/
+#ifdef ATTSV
+#define MYREAD
+#endif /* ATTSV */
+
+#ifdef ATT7300
+#ifndef MYREAD
+#define MYREAD
+#endif /* MYREAD */
+/* bits for attmodem: internal modem in use, restart getty */
+#define ISMODEM 1
+#define DOGETY 512
+#endif /* ATT7300 */
+
+#ifdef BSD42
+#define MYREAD
+#endif /* BSD42 */
+
+#ifdef POSIX
+#define MYREAD
+#endif /* POSIX */
+#ifdef __bsdi__
+#ifndef O_NDELAY
+#define O_NDELAY O_NONBLOCK
+#endif /* O_NDELAY */
+#endif /* __bsdi__ */
+
+/*
+ Variables available to outside world:
+
+ dftty -- Pointer to default tty name string, like "/dev/tty".
+ dfloc -- 0 if dftty is console, 1 if external line.
+ dfprty -- Default parity
+ dfflow -- Default flow control
+ ckxech -- Flag for who echoes console typein:
+ 1 - The program (system echo is turned off)
+ 0 - The system (or front end, or terminal).
+ functions that want to do their own echoing should check this flag
+ before doing so.
+
+ flfnam -- Name of lock file, including its path, e.g.,
+ "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
+ lkflfn -- Name of link to lock file, including its paths
+ haslock -- Flag set if this kermit established a uucp lock.
+ lockpid -- PID of other process that has desired line open, as string.
+ backgrd -- Flag indicating program executing in background ( & on
+ end of shell command). Used to ignore INT and QUIT signals.
+ rtu_bug -- Set by stptrap(). RTU treats ^Z as EOF (but only when we handle
+ SIGTSTP)
+
+ Functions for assigned communication line (either external or console tty):
+
+ sysinit() -- System dependent program initialization
+ syscleanup() -- System dependent program shutdown
+ ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
+ ttclos() -- Close & reset the tty, releasing any access lock.
+ ttsspd(cps) -- Set the transmission speed of the tty.
+ ttgspd() -- Get (read) the the transmission speed of the tty.
+ ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
+ ttvt(speed,flow) -- Put the tty in virtual terminal mode.
+ or in DIALING or CONNECTED modem control state.
+ ttres() -- Restore original tty modes.
+ ttscarr(carrier) -- Set carrier control mode, on/off/auto.
+ ttinl(dest,max,timo) -- Timed read line from the tty.
+ ttinc(timo) -- Timed read character from tty.
+ myread() -- Raw mode bulk buffer read, gives subsequent
+ chars one at a time and simulates FIONREAD.
+ myunrd(c) -- Places c back in buffer to be read (one only)
+ ttchk() -- See how many characters in tty input buffer.
+ ttxin(n,buf) -- Read n characters from tty (untimed).
+ ttol(string,length) -- Write a string to the tty.
+ ttoc(c) -- Write a character to the tty.
+ ttflui() -- Flush tty input buffer.
+ ttsndb() -- Send BREAK signal.
+ ttsndlb() -- Send Long BREAK signal.
+
+ ttlock(ttname) -- "Lock" tty device against uucp collisions.
+ ttunlck() -- Unlock tty device.
+
+ For ATT7300/Unix PC, System V:
+ attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
+ offgetty(ttname) -- Turns off getty(1m) for comms line
+ ongetty(ttname) -- Restores getty() to comms line
+*/
+
+/*
+Functions for console terminal:
+
+ congm() -- Get console terminal modes.
+ concb(esc) -- Put the console in single-character wakeup mode with no echo.
+ conbin(esc) -- Put the console in binary (raw) mode.
+ conres() -- Restore the console to mode obtained by congm().
+ conoc(c) -- Unbuffered output, one character to console.
+ conol(s) -- Unbuffered output, null-terminated string to the console.
+ conola(s) -- Unbuffered output, array of strings to the console.
+ conxo(n,s) -- Unbuffered output, n characters to the console.
+ conchk() -- Check if characters available at console (bsd 4.2).
+ Check if escape char (^\) typed at console (System III/V).
+ coninc(timo) -- Timed get a character from the console.
+ congks(timo) -- Timed get keyboard scan code.
+ conint() -- Enable terminal interrupts on the console if not background.
+ connoi() -- Disable terminal interrupts on the console if not background.
+
+Time functions
+
+ msleep(m) -- Millisecond sleep
+ ztime(&s) -- Return pointer to date/time string
+ rtimer() -- Reset timer
+ gtimer() -- Get elapsed time since last call to rtimer()
+*/
+
+/* Conditional Includes */
+
+/* Whether to include <sys/file.h> */
+
+#ifdef RTU /* RTU doesn't */
+#define NOFILEH
+#endif /* RTU */
+
+#ifdef CIE /* CIE does. */
+#undef NOFILEH
+#endif /* CIE */
+
+#ifdef BSD41 /* 4.1 BSD doesn't */
+#define NOFILEH
+#endif /* BSD41 */
+
+#ifdef is68k /* Integrated Solutions 68000 UNIX */
+#define NOFILEH /* e.g. on Plexux P60 and Sun-1 */
+#endif /* is68k */
+
+#ifdef MINIX /* MINIX */
+#define NOFILEH
+#endif /* MINIX */
+
+#ifdef COHERENT /* Coherent */
+#define NOFILEH
+#endif /* COHERENT */
+
+#ifndef NOFILEH /* Now include if selected. */
+#include <sys/file.h>
+#endif /* NOFILEH */
+
+/* POSIX */
+
+#ifdef BSD44ORPOSIX /* POSIX uses termios.h */
+#define TERMIOS
+#ifdef __bsdi__
+#ifdef POSIX
+#undef _POSIX_SOURCE /* Get extra stuff from termios.h */
+#endif /* POSIX */
+#endif /* __bsdi__ */
+#include <termios.h>
+#ifdef LINUX
+#include <sys/ioctl.h>
+#endif /* LINUX */
+#ifdef QNX16
+#include <ioctl.h>
+#else
+#ifdef QNX6
+#include <ioctl.h>
+#endif /* QNX6 */
+#endif /* QNX16 */
+#ifdef __bsdi__
+#ifdef POSIX
+#define _POSIX_SOURCE
+#endif /* POSIX */
+#endif /* __bsdi__ */
+#ifndef BSD44 /* Really POSIX */
+#ifndef CK_QNX32 /* was CK_QNX32 */
+#define NOSYSIOCTLH /* No ioctl's allowed. */
+#undef ultrix /* Turn off any ultrix features. */
+#endif /* CK_QNX32 */
+#endif /* BSD44 */
+#endif /* POSIX */
+
+/* System III, System V */
+
+#ifdef ATTSV
+#ifndef BSD44
+#ifndef POSIX
+#include <termio.h>
+#endif /* POSIX */
+#endif /* BSD44 */
+#ifdef TERMIOX
+/* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
+#include <termiox.h>
+ struct termiox rctsx;
+#else
+#ifdef STERMIOX
+#ifdef SCO_OSR504
+/* Sorry, this is truly disgusting but it's SCO's fault. */
+#ifndef _SVID3
+#define _CK_SVID3_X
+#define _SVID3
+#endif /* _SVID3 */
+#endif /* SCO_OSR504 */
+#include <sys/termiox.h>
+ struct termiox rctsx;
+#ifdef CK_SVID3_X
+#undef _SVID3
+#undef CK_SVID3_X
+#endif /* CK_SVID3_X */
+#endif /* STERMIOX */
+#endif /* TERMIOX */
+#endif /* ATTSV */
+
+#ifdef COHERENT /* Use termio.h, not sgtty.h for Coherent */
+#include <termio.h>
+#endif /* COHERENT */
+
+#ifdef MINIX /* MINIX uses ioctl's */
+#define NOSYSIOCTLH /* but has no <sys/ioctl.h> */
+#endif /* MINIX */
+
+/* Others */
+
+#ifndef NOSYSIOCTLH /* Others use ioctl() */
+#ifdef SUN4S5
+/*
+ This is to get rid of cpp warning messages that occur because all of
+ these symbols are defined by both termios.h and ioctl.h on the SUN.
+*/
+#undef ECHO
+#undef NL0
+#undef NL1
+#undef TAB0
+#undef TAB1
+#undef TAB2
+#undef XTABS
+#undef CR0
+#undef CR1
+#undef CR2
+#undef CR3
+#undef FF0
+#undef FF1
+#undef BS0
+#undef BS1
+#undef TOSTOP
+#undef FLUSHO
+#undef PENDIN
+#undef NOFLSH
+#endif /* SUN4S5 */
+#include <sys/ioctl.h>
+#endif /* NOSYSIOCTLH */
+/*
+ We really, really, REALLY want FIONREAD, because it is the only way to find
+ out not just *if* stuff is waiting to be read, but how much, which is
+ critical to our sliding-window and streaming procedures, not to mention
+ efficiency of CONNECT, etc.
+*/
+#ifdef BELLV10
+#include <sys/filio.h> /* For FIONREAD */
+#ifdef FIONREAD
+#define MYREAD
+#endif /* MYREAD */
+#endif /* BELLV10 */
+
+#ifndef FIONREAD
+/* It wasn't found in ioctl.h or term*.h - try these places: */
+#ifdef UNIXWARE
+#include <sys/filio.h>
+#else
+#ifdef SOLARIS
+#include <sys/filio.h>
+#endif /* SOLARIS */
+#endif /* UNIXWARE */
+#endif /* FIONREAD */
+
+#ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
+/*
+ <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
+ something. Due to this, in_chk() uses the FIONREAD instead of RDCHK
+ and the hot keys during file transfer (X to cancel file etc) do not
+ work because FIONREAD doesn't work even though it is defined.
+
+ NOTE: This might also be true elsewhere.
+*/
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+#endif /* XENIX */
+
+#ifdef CK_SCOV5 /* Ditto for SCO OpenServer 5.0 */
+#ifndef SCO_OSR507 /* 299 */
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+#endif /* SCO_OSR507 */
+#endif /* CK_SCOV5 */
+
+#ifdef SCO_OSR507 /* 299 */
+#ifdef RDCHK
+#undef RDCHK
+#endif /* RDCHK */
+#endif /* SCO_OSR507 */
+
+/* Whether to include <fcntl.h> */
+
+#ifndef is68k /* Only a few don't have this one. */
+#ifndef BSD41
+#ifndef FT21
+#ifndef FT18
+#ifndef COHERENT
+#include <fcntl.h>
+#endif /* COHERENT */
+#endif /* FT18 */
+#endif /* FT21 */
+#endif /* BSD41 */
+#endif /* not is68k */
+
+#ifdef COHERENT
+#ifdef _I386
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#endif /* _I386 */
+#endif /* COHERENT */
+
+#ifdef ATT7300 /* Unix PC, internal modem dialer */
+#include <sys/phone.h>
+#endif /* ATT7300 */
+
+#ifdef HPUX /* HP-UX variations. */
+#define HPUXJOBCTL
+#include <sys/modem.h> /* HP-UX modem signals */
+#ifdef hp9000s500 /* Model 500 */
+#undef HPUXJOBCTL
+#endif /* hp9000s500 */
+#ifdef HPUXPRE65
+#undef HPUXJOBCTL
+typedef long mflag;
+#endif /* HPUXPRE65 */
+#ifdef HPUXJOBCTL
+#include <sys/bsdtty.h> /* HP-UX Berkeley tty support */
+#endif /* HPUXJOBCTL */
+#endif /* HPUX */
+
+/*
+ Which time.h files to include... See ckcdeb.h for defaults.
+ Note that 0, 1, 2, or all 3 of these can be included according to
+ the symbol definitions.
+*/
+#ifndef NOTIMEH
+#ifdef TIMEH
+#include <time.h>
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+
+#ifndef NODCLTIMEVAL
+#ifdef DCLTIMEVAL
+/*
+ In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
+ define the structs we need to access the higher speeds, so we have to
+ do it ourselves.
+*/
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif /* DCLTIMEVAL */
+#endif /* NODCLTIMEVAL */
+
+#ifdef __linux__
+/* THIS IS OBSOLETE since about Linux 0.92 */
+#ifdef OLINUXHISPEED
+#include <linux/serial.h>
+#endif /* OLINUXHISPEED */
+#ifdef __alpha__ /* Linux on DEC Alpha */
+#ifndef __GLIBC__ /* But not with glibc */
+#include <asm/termios.h>
+#endif /* __GLIBC__ */
+#endif /* __alpha__ */
+#endif /* __linux__ */
+
+#ifdef NOIEXTEN /* This is broken on some systems */
+#undef IEXTEN /* like Convex/OS 9.1 */
+#endif /* NOIEXTEN */
+#ifndef IEXTEN /* Turn off ^O/^V processing. */
+#define IEXTEN 0 /* Needed, at least, on BSDI. */
+#endif /* IEXTEN */
+/*
+ Pick up definitions needed for select() if we don't have them already.
+ Normally they come from <sys/types.h> but some systems get them from
+ <sys/select.h>... Rather than hardwire all of them into the source, we
+ include it if SELECT_H is defined in compile-time CFLAGS.
+*/
+#ifndef SCO_OSR504
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* SCO_OSR504 */
+
+#ifdef aegis
+#include "/sys/ins/base.ins.c"
+#include "/sys/ins/error.ins.c"
+#include "/sys/ins/ios.ins.c"
+#include "/sys/ins/sio.ins.c"
+#include "/sys/ins/pad.ins.c"
+#include "/sys/ins/time.ins.c"
+#include "/sys/ins/pfm.ins.c"
+#include "/sys/ins/pgm.ins.c"
+#include "/sys/ins/ec2.ins.c"
+#include "/sys/ins/type_uids.ins.c"
+#include <default_acl.h>
+#undef TIOCEXCL
+#undef FIONREAD
+#endif /* aegis */
+
+#ifdef sxaE50 /* PFU Compact A SX/A TISP V10/L50 */
+#undef FIONREAD
+#endif /* sxaE50 */
+
+/* The following #defines are catch-alls for those systems */
+/* that didn't have or couldn't find <file.h>... */
+
+#ifndef FREAD
+#define FREAD 0x01
+#endif /* FREAD */
+
+#ifndef FWRITE
+#define FWRITE 0x10
+#endif /* FWRITE */
+
+#ifndef O_RDONLY
+#define O_RDONLY 000
+#endif /* O_RDONLY */
+
+/* This is for ancient Unixes that don't have these tty symbols defined. */
+
+#ifndef PENDIN
+#define PENDIN ICANON
+#endif /* PENDIN */
+#ifndef FLUSHO
+#define FLUSHO ICANON
+#endif /* FLUSHO */
+#ifndef EXTPROC
+#define EXTPROC ICANON
+#endif /* EXTPROC */
+
+#ifdef SVORPOSIX
+/*
+ Modem signals are also forbidden in the POSIX world. But some POSIX-based
+ platforms let us at them anyway if we know where to look.
+*/
+#ifndef NEEDMDMDEFS
+/* Doesn't work for Linux */
+#ifdef UNIXWARE7
+#define NEEDMDMDEFS
+#endif /* UNIXWARE7 */
+#endif /* NEEDMDMDEFS */
+
+#ifdef NEEDMDMDEFS
+#ifndef TIOCMGET
+#define TIOCMGET (('t'<<8)|29)
+#endif /* TIOCMGET */
+
+#ifndef TIOCM_DTR
+#define TIOCM_DTR 0x0002
+#endif /* TIOCM_DTR */
+#ifndef TIOCM_RTS
+#define TIOCM_RTS 0x0004
+#endif /* TIOCM_RTS */
+#ifndef TIOCM_CTS
+#define TIOCM_CTS 0x0020
+#endif /* TIOCM_CTS */
+#ifndef TIOCM_CAR
+#define TIOCM_CAR 0x0040
+#endif /* TIOCM_CAR */
+#ifndef TIOCM_RNG
+#define TIOCM_RNG 0x0080
+#endif /* TIOCM_RNG */
+#ifndef TIOCM_DSR
+#define TIOCM_DSR 0x0100
+#endif /* TIOCM_DSR */
+#endif /* NEEDMDMDEFS */
+#endif /* SVORPOSIX */
+
+/* Declarations */
+
+#ifdef OXOS
+#undef TCGETA
+#undef TCSETA
+#undef TCSETAW
+#undef TCSETAF
+#define TCGETA TCGETS
+#define TCSETA TCSETS
+#define TCSETAW TCSETSW
+#define TCSETAF TCSETSF
+#define termio termios
+#endif /* OXOS */
+
+#ifdef SVORPOSIX /* AT&T Sys V or POSIX */
+#ifdef UNIXWAREPOSIX /* UnixWare 7 POSIX build */
+/*
+ In Unixware POSIX builds, <[sys/]time.h> refuses to define the
+ structs we need to access the higher speeds, so we have to do it
+ ourselves.
+*/
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif /* UNIXWAREPOSIX */
+#endif /* SVORPOSIX */
+
+#ifdef __GNUC__
+#ifdef XENIX
+/*
+ Because Xenix <time.h> doesn't declare time() if we're using gcc.
+*/
+time_t time();
+#endif /* XENIX */
+#endif /* __GNUC__ */
+
+/* Special stuff for V7 input buffer peeking */
+
+#ifdef V7
+int kmem[2] = { -1, -1};
+char *initrawq(), *qaddr[2]={0,0};
+#define CON 0
+#define TTY 1
+#endif /* V7 */
+
+/* dftty is the device name of the default device for file transfer */
+/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
+
+#ifdef BEOS
+ char * dftty = NULL;
+ char * dfmdm = "none";
+ int dfloc = 0; /* that goes in local mode by default */
+#else
+#ifndef DFTTY
+#ifdef PROVX1
+ char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
+ char *dfmdm = "none";
+ int dfloc = 1; /* that goes in local mode by default */
+#else
+ char *dftty = CTTNAM; /* Remote by default, use normal */
+ char *dfmdm = "none";
+ int dfloc = 0; /* controlling terminal name. */
+#endif /* PROVX1 */
+#else
+ char *dftty = DFTTY; /* Default location specified on */
+ char *dfmdm = "none"; /* command line. */
+ int dfloc = 1; /* controlling terminal name. */
+#endif /* DFTTY */
+#endif /* BEOS */
+
+#define CON_RES 0 /* Console state is "reset" */
+#define CON_CB 1 /* Console state is CBREAK */
+#define CON_BIN 2 /* Console state is binary */
+ static int constate = CON_RES;
+
+#define CONI_RES 0 /* Console interrupts are "reset" */
+#define CONI_INT 1 /* Console intterupts are set */
+#define CONI_NOI 2 /* Console intterupts are disabled */
+ static int conistate = CONI_RES;
+
+#ifdef CK_SMALL
+#define CONBUFSIZ 15
+#else
+#define CONBUFSIZ 255
+#endif /* CK_SMALL */
+ static char conbuf[CONBUFSIZ]; /* Console readahead buffer */
+ static int conbufn = 0; /* Chars in readahead buffer */
+ static char *conbufp = conbuf; /* Next char in readahead buffer */
+
+ char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
+
+#ifdef RTU
+ int rtu_bug = 0; /* set to 1 when returning from SIGTSTP */
+#endif /* RTU */
+
+ int dfprty = DEFPAR; /* Default parity (0 = none) */
+ int ttprty = 0; /* The parity that is in use. */
+ static int ttpmsk = 0xff; /* Parity stripping mask. */
+ int ttmdm = 0; /* Modem in use. */
+ int ttcarr = CAR_AUT; /* Carrier handling mode. */
+ int dfflow = FLO_NONE; /* Default flow control is NONE */
+ int backgrd = 0; /* Assume in foreground (no '&' ) */
+#ifdef F_SETFL
+ int iniflags = -1; /* fcntl flags for ttyfd */
+#endif /* F_SETFL */
+ int fdflag = 0; /* Flag for redirected stdio */
+ int ttfdflg = 0; /* Open File descriptor was given */
+ int tvtflg = 0; /* Flag that ttvt has been called */
+ long ttspeed = -1L; /* For saving speed */
+ int ttflow = -9; /* For saving flow */
+ int ttld = -1; /* Line discipline */
+
+#ifdef sony_news
+ static int km_con = -1; /* Kanji mode for console tty */
+ static int km_ext = -1; /* Kanji mode for external device */
+#endif /* sony_news */
+
+#ifdef PARSENSE
+ static int needpchk = 1; /* Need parity check */
+#else
+ static int needpchk = 0;
+#endif /* PARSENSE */
+
+ extern int stopbits; /* Stop bits */
+#ifdef HWPARITY
+/*
+ Unfortunately we must do this with global variables rather than through the
+ tt...() APIs to avoid changing the APIs and the many modules that use them.
+ If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
+ bits + parity or 8 data bits and no parity, and overrides the regular parity
+ variable, which is communicated to this module thru ttpkt(), and represented
+ locally by the ttprty variable.
+*/
+ extern int hwparity; /* Hardware parity */
+#endif /* HWPARITY */
+
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+static int nodelay_sav = -1;
+#endif /* TCP_NODELAY */
+#endif /* TCPSOCKET */
+
+static int sigint_ign = 0; /* SIGINT is ignored */
+
+/*
+ Having this module rely on external globals is bad, but fixing this
+ requires overhaul of the ck*tio.c modules for all the different operating
+ systems supported by C-Kermit. Left for a future release.
+*/
+extern int ttnproto; /* Defined in ckcnet.c */
+extern int ttnet; /* Defined in ckcnet.c */
+extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
+extern int xsuspend, wasclosed;
+extern int inserver, local;
+
+int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
+
+int ckmaxfiles = 0; /* Max number of open files */
+
+#ifdef CK_ENCRYPTION /* Kerberos */
+#include "ckuath.h"
+extern int me_encrypt, u_encrypt;
+#endif /* CK_ENCRYPTION */
+
+/* Declarations of variables global within this module */
+
+#ifdef TTLEBUF /* See ckcnet.h */
+int ttpush = -1;
+#define LEBUFSIZ 4096
+static CHAR le_buf[LEBUFSIZ];
+static int le_start = 0, le_end = 0, le_data = 0;
+#endif /* TTLEBUF */
+
+#define MSGBUF_SIZE 1024 /* For debugging */
+static char msgbuf[MSGBUF_SIZE];
+
+static int gotsigs = 0;
+
+static time_t tcount = (time_t)0; /* Elapsed time counter */
+
+static SIGTYP (*saval)() = NULL; /* For saving alarm() handler */
+static SIGTYP (*savquit)() = NULL; /* and other signal handlers */
+#ifdef SIGUSR1
+static SIGTYP (*savusr1)() = NULL;
+#endif /* SIGUSR1 */
+#ifdef SIGUSR2
+static SIGTYP (*savusr2)() = NULL;
+#endif /* SIGUSR2 */
+#ifdef SIGPIPE
+static SIGTYP (*savpipe)() = NULL;
+#endif /* SIGPIPE */
+#ifdef SIGDANGER
+static SIGTYP (*savdanger)() = NULL;
+#endif /* SIGDANGER */
+
+#ifndef NOJC
+static SIGTYP (*jchdlr)() = NULL; /* For checking suspend handler */
+#endif /* NOJC */
+static int jcshell = -1; /* And flag for result */
+
+/*
+ BREAKNULS is defined for systems that simulate sending a BREAK signal
+ by sending a bunch of NUL characters at low speed.
+*/
+#ifdef PROVX1
+#ifndef BREAKNULS
+#define BREAKNULS
+#endif /* BREAKNULS */
+#endif /* PROVX1 */
+
+#ifdef V7
+#ifndef BREAKNULS
+#define BREAKNULS
+#endif /* BREAKNULS */
+#endif /* V7 */
+
+#ifdef BREAKNULS
+static char /* A string of nulls */
+*brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+#endif /* BREAKNULS */
+
+#ifdef CK_POSIX_SIG /* Longjump buffers */
+static sigjmp_buf sjbuf; /* POSIX signal handling */
+#else
+static jmp_buf sjbuf;
+#endif /* CK_POSIX_SIG */
+
+#ifdef V7
+static jmp_buf jjbuf;
+#endif /* V7 */
+
+/* static */ /* (Not static any more) */
+int ttyfd = -1; /* TTY file descriptor */
+
+int ttpipe = 0; /* NETCMD: Use pipe instead of ttyfd */
+int ttpty = 0; /* NETPTY: Use pty instead of ttfyd */
+
+#ifdef NETPTY /* These are in ckupty.c */
+extern PID_T pty_fork_pid;
+extern int pty_master_fd, pty_slave_fd;
+#endif /* NETPTY */
+
+#ifdef NETCMD
+#ifdef NETCONN
+static int pipe0[2], pipe1[2]; /* Pipes for net i/o */
+#endif /* NETCONN */
+static PID_T ttpid = 0; /* Process ID for fork */
+static int fdin, fdout; /* File descriptors for pipe */
+static FILE * ttout = NULL; /* File pointer for output pipe */
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+#endif /* NETCMD */
+
+extern int pexitstat, quiet;
+
+#ifdef Plan9
+int ttyctlfd = -1; /* TTY control channel - What? UNIX doesn't have one? */
+int consctlfd = -1; /* Console control channel */
+int noisefd = -1; /* tone channel */
+static int ttylastspeed = -1; /* So we can lie about the speed */
+#endif /* Plan9 */
+
+int telnetfd = 0; /* File descriptor is for telnet */
+#ifdef NETCONN
+int x25fd = 0; /* File descriptor is for X.25 */
+#endif /* NETCONN */
+
+char lockpid[16] = { '\0', '\0' }; /* PID stored in lockfile, as string */
+
+static int lkf = 0, /* Line lock flag */
+ cgmf = 0, /* Flag that console modes saved */
+ xlocal = 0, /* Flag for tty local or remote */
+ curcarr = 0; /* Carrier mode: require/ignore. */
+
+static int netconn = 0; /* 1 if network connection active */
+
+static char escchr; /* Escape or attn character */
+
+#ifdef CK_SCO32V4
+#include <sys/time.h>
+#endif /* CK_SCO32V4 */
+
+#ifdef HAVE_TV
+ static struct timeval tv; /* For getting time, from sys/time.h */
+#endif /* HAVE_TV */
+#ifdef HAVE_TZ
+ static struct timezone tz;
+#endif /* HAVE_TZ */
+
+#ifdef OSF
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* OSF */
+
+#ifdef BSD29
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* BSD29 */
+
+#ifdef BSD41
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* BSD41 */
+
+#ifdef BELLV10
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* BELLV10 */
+
+#ifdef FT21
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* FT21 */
+
+#ifdef TOWER1
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* TOWER1 */
+
+#ifdef COHERENT
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* COHERENT */
+
+#ifdef V7
+ static long xclock;
+#endif /* V7 */
+
+/* sgtty/termio information... */
+
+#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
+ static struct termios
+ ttold, ttraw, tttvt, ttcur,
+ ccold, ccraw, cccbrk;
+#else /* BSD, V7, etc */
+
+#ifdef COHERENT /* Hack alert... */
+#define ATTSV
+#endif /* COHERENT */
+
+#ifdef ATTSV
+ static struct termio ttold = {0}; /* Init'd for word alignment, */
+ static struct termio ttraw = {0}; /* which is important for some */
+ static struct termio tttvt = {0}; /* systems, like Zilog... */
+ static struct termio ttcur = {0};
+ static struct termio ccold = {0};
+ static struct termio ccraw = {0};
+ static struct termio cccbrk = {0};
+#else
+ static struct sgttyb /* sgtty info... */
+ ttold, ttraw, tttvt, ttcur, /* for communication line */
+ ccold, ccraw, cccbrk; /* and for console */
+#ifdef BELLV10
+ static struct ttydevb /* Device info... */
+ tdold, tdcur; /* for communication device */
+#endif /* BELLV10 */
+#ifdef TIOCGETC
+ static struct tchars tchold, tchnoi;
+
+ static int tcharf;
+#endif /* TIOCGETC */
+#ifdef TIOCGLTC
+ static struct ltchars ltchold, ltchnoi;
+ static int ltcharf;
+#endif /* TIOCGLTC */
+ int lmodef = 0; /* Local modes */
+ int lmode = 0;
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+#ifdef COMMENT
+/* It picks up the speeds but they don't work */
+#ifdef UNIXWARE /* For higher serial speeds */
+#ifdef UW7 /* in Unixware 7.0 */
+#include <sys/asyc.h> /* This picks up 57600 and 115200 */
+#endif /* UW7 */
+#endif /* UNIXWARE */
+#endif /* COMMENT */
+
+#ifdef PROVX1
+ static struct sgttyb ttbuf;
+#endif /* PROVX1 */
+
+#ifdef ultrix
+/* do we really need this? */
+ static struct sgttyb vanilla;
+#endif /* ultrix */
+
+#ifdef ATT7300
+static int attmodem = 0; /* ATT7300 internal-modem status */
+struct updata dialer = {0}; /* Condition dialer for data call */
+#endif /* ATT7300 */
+
+#ifndef NOUUCP
+#define FLFNAML 128
+#ifndef USETTYLOCK
+#ifdef RTAIX
+char lkflfn[FLFNAML] = { '\0', '\0' }; /* and possible link to it */
+#endif /* RTAIX */
+char lock2[FLFNAML] = { '\0', '\0' }; /* Name of second lockfile */
+#endif /* USETTYLOCK */
+#else
+#define FLFNAML 7
+#endif /* NOUUCP */
+char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
+
+int haslock = 0; /* =1 if this kermit locked uucp */
+
+#ifndef OXOS
+#ifdef SVORPOSIX
+static int conesc = 0; /* set to 1 if esc char (^\) typed */
+#else
+#ifdef V7
+static int conesc = 0;
+#else
+#ifdef C70
+static int conesc = 0;
+#endif /* C70 */
+#endif /* V7 */
+#endif /* SVORPOSIX */
+#endif /* OXOS */
+
+/* Local copy of comm device name or network host */
+static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
+#ifdef USETTYLOCK
+static char lockname[DEVNAMLEN+1]; /* Ditto, the part after "/dev/". */
+#endif /* USETTYLOCK */
+
+#ifdef aegis
+static status_$t st; /* error status return value */
+static short concrp = 0; /* true if console is CRP pad */
+static uid_$t ttyuid; /* tty type uid */
+static uid_$t conuid; /* stdout type uid */
+
+/* APOLLO Aegis main()
+ * establish acl usage and cleanup handling
+ * this makes sure that CRP pads
+ * get restored to a usable mode
+ */
+main(argc,argv) int argc; char **argv; {
+ status_$t status;
+ pfm_$cleanup_rec dirty;
+
+ PID_T pid = getpid();
+
+ /* acl usage according to invoking environment */
+ default_acl(USE_DEFENV);
+
+ /* establish a cleanup continuation */
+ status = pfm_$cleanup(dirty);
+ if (status.all != pfm_$cleanup_set) {
+ /* only handle faults for the original process */
+ if (pid == getpid() && status.all > pgm_$max_severity) {
+ /* blew up in main process */
+ status_$t quo;
+ pfm_$cleanup_rec clean;
+
+ /* restore the console in any case */
+ conres();
+
+ /* attempt a clean exit */
+ debug(F101, "cleanup fault status", "", status.all);
+
+ /* doexit(), then send status to continuation */
+ quo = pfm_$cleanup(clean);
+ if (quo.all == pfm_$cleanup_set)
+ doexit(pgm_$program_faulted,-1);
+ else if (quo.all > pgm_$max_severity)
+ pfm_$signal(quo); /* blew up in doexit() */
+ }
+ /* send to the original continuation */
+ pfm_$signal(status);
+ /*NOTREACHED*/
+ }
+ return(ckcmai(argc, argv));
+}
+#endif /* aegis */
+
+/* ANSI-style prototypes for internal functions. */
+/* Functions used outside this module are prototyped in ckcker.h. */
+
+#ifdef apollo
+_PROTOTYP( SIGTYP timerh, () );
+_PROTOTYP( SIGTYP cctrap, () );
+_PROTOTYP( SIGTYP esctrp, () );
+_PROTOTYP( SIGTYP sig_ign, () );
+#else
+_PROTOTYP( SIGTYP timerh, (int) );
+_PROTOTYP( SIGTYP cctrap, (int) );
+_PROTOTYP( SIGTYP esctrp, (int) );
+#endif /* apollo */
+_PROTOTYP( int do_open, (char *) );
+_PROTOTYP( static int in_chk, (int, int) );
+_PROTOTYP( static int ttrpid, (char *) );
+_PROTOTYP( static int ttchkpid, (char *) );
+_PROTOTYP( static int ttlock, (char *) );
+_PROTOTYP( static int ttunlck, (void) );
+_PROTOTYP( static VOID sigchld_handler, (int) );
+_PROTOTYP( int mygetbuf, (void) );
+_PROTOTYP( int myfillbuf, (void) );
+_PROTOTYP( VOID conbgt, (int) );
+#ifdef ACUCNTRL
+_PROTOTYP( VOID acucntrl, (char *, char *) );
+#endif /* ACUCNTRL */
+
+#ifdef BSD44ORPOSIX
+_PROTOTYP( int carrctl, (struct termios *, int) );
+#else
+#ifdef ATTSV
+_PROTOTYP( int carrctl, (struct termio *, int) );
+#else
+_PROTOTYP( int carrctl, (struct sgttyb *, int) );
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+#ifdef ATT7300
+_PROTOTYP( int attdial, (char *, long, char *) );
+_PROTOTYP( int offgetty, (char *) );
+_PROTOTYP( int ongetty, (char *) );
+#endif /* ATT7300 */
+
+#ifdef BEOSORBEBOX
+#ifdef SELECT
+ /* BeOS is not capable of using SELECT on anything but sockets */
+#undef SELECT
+#endif /* SELECT */
+#include <kernel/OS.h>
+/* #ifdef BE_DR_7 */
+static double time_started = 0.0;
+struct ALARM_STRUCT {
+ thread_id thread;
+ int time;
+};
+static thread_id alarm_thread = -1;
+static struct ALARM_STRUCT alarm_struct;
+_PROTOTYP( long do_alarm, (void *) );
+_PROTOTYP( unsigned int alarm, (unsigned int) );
+_PROTOTYP( void alarm_expired, (void) );
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+
+#ifndef xunchar
+#define xunchar(ch) (((ch) - 32 ) & 0xFF ) /* Character to number */
+#endif /* xunchar */
+
+#ifdef CK_ANSIC
+static char *
+xxlast(char *s, char c)
+#else
+static char *
+xxlast(s,c) char *s; char c;
+#endif /* CK_ANSIC */
+/* xxlast */ { /* Last occurrence of character c in string s. */
+ int i;
+ for (i = (int)strlen(s); i > 0; i--)
+ if (s[i-1] == c ) return(s + (i - 1));
+ return(NULL);
+}
+
+/* Timeout handler for communication line input functions */
+
+/*ARGSUSED*/
+SIGTYP
+timerh(foo) int foo; {
+ ttimoff();
+#ifdef BEOSORBEBOX
+/* #ifdef BE_DR_7 */
+ alarm_expired();
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+#ifdef CK_POSIX_SIG
+ siglongjmp(sjbuf,1);
+#else
+ longjmp(sjbuf,1);
+#endif /* CK_POSIX_SIG */
+}
+
+/*ARGSUSED*/
+SIGTYP
+xtimerh(foo) int foo; { /* Like timerh() but does */
+#ifdef BEOSORBEBOX /* not reset the timer itself */
+/* #ifdef BE_DR_7 */
+ alarm_expired();
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+#ifdef CK_POSIX_SIG
+ siglongjmp(sjbuf,1);
+#else
+ longjmp(sjbuf,1);
+#endif /* CK_POSIX_SIG */
+}
+
+
+/* Control-C trap for communication line input functions */
+
+int cc_int; /* Flag */
+SIGTYP (* occt)(); /* For saving old SIGINT handler */
+
+/*ARGSUSED*/
+SIGTYP
+cctrap(foo) int foo; { /* Needs arg for ANSI C */
+ cc_int = 1; /* signal() prototype. */
+ return;
+}
+
+/* S Y S I N I T -- System-dependent program initialization. */
+
+/*
+ * ttgwsiz() returns:
+ * 1 tt_rows and tt_cols are known, both altered, both > 0
+ * 0 tt_rows and/or tt_cols are known, both altered, one or both <= 0
+ * -1 tt_rows and tt_cols are unknown and unaltered
+ */
+
+extern int tt_rows, tt_cols;
+
+static int
+xttgwsiz() {
+ char *p;
+ int rows = 0, cols = 0;
+ p = getenv("LINES");
+ debug(F110,"xttgwsiz LINES",p,0);
+ if (p) {
+ rows = atol(p);
+ if (rows > 0) {
+ p = getenv("COLUMNS");
+ debug(F110,"xttgwsiz COLUMNS",p,0);
+ if (p) {
+ cols = atol(p);
+ if (cols > 0) {
+ tt_rows = rows;
+ tt_cols = cols;
+ return(1);
+ }
+ return(0);
+ }
+ }
+ }
+ return(-1);
+}
+
+#ifdef TTLEBUF
+VOID
+le_init() { /* LocalEchoInit() */
+ int i;
+ for (i = 0; i < LEBUFSIZ; i++)
+ le_buf[i] = '\0';
+ le_start = 0;
+ le_end = 0;
+ le_data = 0;
+}
+
+VOID
+le_clean() { /* LocalEchoCleanup() */
+ le_init();
+ return;
+}
+
+int
+le_inbuf() {
+ int rc = 0;
+ if (le_start != le_end) {
+ rc = (le_end -
+ le_start +
+ LEBUFSIZ) % LEBUFSIZ;
+ }
+ debug(F111,"le_inbuf","chars waiting",rc);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_putchar(CHAR ch)
+#else
+le_putchar(ch) CHAR ch;
+#endif /* CK_ANSIC */
+/* le_putchar */ {
+#ifdef COMMENT
+ /* In UNIX we do not have another thread taking chars out of the buffer */
+ while ((le_start - le_end == 1) ||
+ (le_start == 0 && le_end == LEBUFSIZ - 1)) {
+ /* Buffer is full */
+ debug(F111,"le_putchar","Buffer is Full",ch);
+ ReleaseLocalEchoMutex() ;
+ msleep(250);
+ RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
+ }
+#else
+ if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
+ debug(F110,"le_putchar","buffer is full",0);
+ return(-1);
+ }
+#endif /* COMMENT */
+ le_buf[le_end++] = ch;
+ if (le_end == LEBUFSIZ)
+ le_end = 0;
+ le_data = 1;
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+le_puts(CHAR * s, int n)
+#else
+le_puts(s,n) CHAR * s; int n;
+#endif /* CK_ANSIC */
+/* le_puts */ {
+ int rc = 0;
+ int i = 0;
+ CHAR * p = (CHAR *)"le_puts";
+ ckhexdump(p,s,n);
+ for (i = 0; i < n; i++)
+ rc = le_putchar((char)s[i]);
+ debug(F101,"le_puts","",rc);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_putstr(CHAR * s)
+#else
+le_putstr(s) CHAR * s;
+#endif /* CK_ANSIC */
+/* le_puts */ {
+ CHAR * p;
+ int rc = 0;
+ p = (CHAR *)"le_putstr";
+ ckhexdump(p,s,(int)strlen((char *)s));
+ for (p = s; *p && !rc; p++)
+ rc = le_putchar(*p);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_getchar(CHAR * pch)
+#else /* CK_ANSIC */
+le_getchar(pch) CHAR * pch;
+#endif /* CK_ANSIC */
+/* le_gatchar */ {
+ int rc = 0;
+ if (le_start != le_end) {
+ *pch = le_buf[le_start];
+ le_buf[le_start] = 0;
+ le_start++;
+
+ if (le_start == LEBUFSIZ)
+ le_start = 0;
+
+ if (le_start == le_end) {
+ le_data = 0;
+ }
+ rc++;
+ } else {
+ *pch = 0;
+ }
+ return(rc);
+}
+#endif /* TTLEBUF */
+
+#ifdef COMMENT
+/*
+ Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
+ But as far as I know, whenever TIOCGSIZE is defined, it is
+ equated to TIOCGWINSZ. For cases where this is not done, try this:
+*/
+#ifndef TIOCGWINSZ
+#ifdef TIOCGSIZE
+#define TIOCGWINSZ TIOCGSIZE
+#endif /* TIOCGSIZE */
+#endif /* TIOCGWINSZ */
+#endif /* COMMENT */
+
+static int tt_xpixel = 0, tt_ypixel = 0;
+
+int
+ttgwsiz() {
+ int x = 0;
+#ifndef NONAWS
+#ifdef QNX
+/*
+ NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
+ This code works for both the 16- and 32-bit versions.
+*/
+ extern int dev_size(int, int, int, int *, int *);
+ int r, c;
+
+ if (dev_size(0, -1, -1, &r, &c) == 0) {
+ debug(F101,"ttgwsiz QNX r","",r);
+ debug(F101,"ttgwsiz QNX c","",c);
+ tt_rows = r;
+ tt_cols = c;
+ return ((r > 0 && c > 0) ? 1 : 0);
+ } else return(xttgwsiz());
+#else /* QNX */
+#ifdef TIOCGWINSZ
+
+/* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
+#ifdef XENIX /* SCO UNIX 3.2v4.0 */
+#include <sys/stream.h> /* typedef mblk_t needed by ptem.h */
+#include <sys/ptem.h> /* for ttgwsiz() */
+#endif /* XENIX */
+
+#ifdef I386IX /* Ditto for Interactive */
+#include <sys/stream.h>
+#include <sys/ptem.h>
+#endif /* I386IX */
+
+/* Note, the above might be needed for some other older SVR3 Intel makes... */
+
+ struct winsize w;
+ tt_xpixel = 0;
+ tt_ypixel = 0;
+
+#ifdef IKSD
+ if (inserver)
+ return(xttgwsiz());
+#endif /* IKSD */
+ x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
+ debug(F101,"ttgwsiz TIOCGWINSZ","",x);
+ if (x < 0) {
+ return(xttgwsiz());
+ } else if (w.ws_row > 0 && w.ws_col > 0) {
+ tt_rows = w.ws_row;
+ tt_cols = w.ws_col;
+ tt_xpixel = w.ws_xpixel;
+ tt_ypixel = w.ws_ypixel;
+ debug(F101,"ttgwsiz tt_rows","",tt_rows);
+ debug(F101,"ttgwsiz tt_cols","",tt_cols);
+ return(1);
+ } else {
+ debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
+ return(xttgwsiz());
+ }
+#else
+ return(xttgwsiz());
+#endif /* TIOCGWINSZ */
+#endif /* QNX */
+#endif /* NONAWS */
+}
+
+
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_naws, (void) );
+#endif /* RLOGCODE */
+
+#ifndef NOSIGWINCH
+#ifdef SIGWINCH
+SIGTYP
+winchh(foo) int foo; { /* SIGWINCH handler */
+ int x = 0;
+#ifdef CK_TTYFD
+#ifndef VMS
+ extern int ttyfd;
+#endif /* VMS */
+#endif /* CK_TTYFD */
+ extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"***************","",0);
+ debug(F100,"SIGWINCH caught","",0);
+ debug(F100,"***************","",0);
+#ifdef NETPTY
+ debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
+#endif /* NETPTY */
+ }
+#endif /* DEUB */
+ signal(SIGWINCH,winchh); /* Re-arm the signal */
+ x = ttgwsiz(); /* Get new window size */
+ cmd_rows = tt_rows; /* Adjust command screen too */
+ cmd_cols = tt_cols;
+
+#ifdef CK_TTYFD
+ if /* If we don't have a connection */
+#ifdef VMS /* we're done. */
+ (vmsttyfd() == -1)
+#else
+ (ttyfd == -1)
+#endif /* VMS */
+#else
+ (!local)
+#endif /* CK_TTYFD */
+ return;
+
+#ifdef NETPTY
+ if (pty_fork_pid > -1) { /* "set host" to a PTY? */
+ int x;
+
+#ifdef TIOCSWINSZ
+ struct winsize w; /* Resize the PTY */
+ errno = 0;
+ w.ws_col = tt_cols;
+ w.ws_row = tt_rows;
+ w.ws_xpixel = tt_xpixel;
+ w.ws_ypixel = tt_ypixel;
+ x = ioctl(ttyfd,TIOCSWINSZ,&w);
+ debug(F101,"winchh TIOCSWINSZ","",x);
+ debug(F101,"winchh TIOCSWINSZ errno","",errno);
+#endif /* TIOCSWINSZ */
+
+ errno = 0;
+ x = kill(pty_fork_pid,SIGWINCH);
+ debug(F101,"winchh kill","",x);
+ debug(F101,"winchh kill errno","",errno);
+ }
+#endif /* NETPTY */
+
+/*
+ This should be OK. It might seem that sending this from
+ interrupt level could interfere with another TELNET IAC string
+ that was in the process of being sent. But we always send
+ TELNET strings with a single write(), which should prevent mixups.
+ blah_snaws() should protect themselves from being called on the
+ wrong kind of connection.
+*/
+#ifdef TCPSOCKET
+#ifndef NOTTGWSIZ
+ if (x > 0 && tt_rows > 0 && tt_cols > 0) {
+ tn_snaws();
+#ifdef RLOGCODE
+ rlog_naws();
+#endif /* RLOGCODE */
+ }
+#endif /* NOTTGWSIZ */
+#endif /* TCPSOCKET */
+ SIGRETURN;
+}
+#endif /* SIGWINCH */
+#endif /* NOSIGWINCH */
+
+SIGTYP
+sighup(foo) int foo; { /* SIGHUP handler */
+ backgrd = 1;
+ debug(F100,"***************","",0);
+ debug(F100,"SIGHUP received","",0);
+ debug(F100,"***************","",0);
+ doexit(BAD_EXIT,-1);
+ /*NOTREACHED*/
+ SIGRETURN; /* Shut picky compilers up... */
+}
+
+#ifdef CK_SCO32V4
+/* Exists but there is no prototype in the header files */
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef SV68R3V6
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef ultrix
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef HPUX6
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef HPUX5
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef PS2AIX10
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef BSD42
+_PROTOTYP( char * ttyname, (int) );
+#endif /* BSD42 */
+#endif /* PS2AIX10 */
+#endif /* HPUX5 */
+#endif /* HPUX6 */
+#endif /* ultrix */
+#endif /* SV68R3V6 */
+#endif /* CK_SCO32V4 */
+
+#ifndef SIGUSR1 /* User-defined signals */
+#define SIGUSR1 30
+#endif /* SIGUSR1 */
+
+#ifndef SIGUSR2
+#define SIGUSR2 31
+#endif /* SIGUSR2 */
+
+/*
+ ignorsigs() sets certain signals to SIG_IGN. But when a signal is
+ ignored, it remains ignored across exec(), so we have to restore these
+ signals before exec(), which is the purpose of restorsigs().
+*/
+static VOID
+ignorsigs() { /* Ignore these signals */
+ savquit = signal(SIGQUIT,SIG_IGN); /* Ignore Quit signal */
+
+#ifdef SIGDANGER /* Ignore danger signals */
+/*
+ This signal is sent when the system is low on swap space. Processes
+ that don't handle it are candidates for termination. If swap space doesn't
+ clear out enough, we still might be terminated via kill() -- nothing we can
+ do about that! Conceivably, this could be improved by installing a real
+ signal handler that warns the user, but that would be pretty complicated,
+ since we are not always in control of the screen -- e.g. during remote-mode
+ file transfer.
+*/
+ savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
+#endif /* SIGDANGER */
+#ifdef SIGPIPE
+/*
+ This one comes when a TCP/IP connection is broken by the remote.
+ We prefer to catch this situation by examining error codes from write().
+*/
+ savpipe = signal(SIGPIPE,SIG_IGN);
+#endif /* SIGPIPE */
+ savusr1 = signal(SIGUSR1,SIG_IGN); /* Ignore user-defined signals */
+ savusr2 = signal(SIGUSR2,SIG_IGN);
+}
+
+VOID
+restorsigs() { /* Restore these signals */
+ (VOID) signal(SIGQUIT,savquit); /* (used in ckufio.c) */
+#ifdef SIGDANGER
+ (VOID) signal(SIGDANGER,savdanger);
+#endif /* SIGDANGER */
+#ifdef SIGPIPE
+ (VOID) signal(SIGPIPE,savpipe);
+#endif /* SIGPIPE */
+ (VOID) signal(SIGUSR1,savusr1);
+ (VOID) signal(SIGUSR2,savusr2);
+}
+
+int
+sysinit() {
+ int x;
+ char * s;
+#ifdef CK_UTSNAME
+ struct utsname name;
+#endif /* CK_UTSNAME */
+
+ extern char startupdir[];
+/*
+ BEFORE ANYTHING ELSE: Initialize the setuid package.
+ Change to the user's real user and group ID.
+ If this can't be done, don't run at all.
+*/
+ x = priv_ini();
+#ifdef SUIDDEBUG
+ fprintf(stderr,"PRIV_INI=%d\n",x);
+#endif /* SUIDDEBUG */
+ if (x) {
+ if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
+ if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
+ if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
+ exit(1);
+ }
+ signal(SIGINT,SIG_IGN); /* Ignore interrupts at first */
+ signal(SIGFPE,SIG_IGN); /* Ignore floating-point exceptions */
+ signal(SIGHUP,sighup); /* Catch SIGHUP */
+#ifndef NOSIGWINCH
+#ifdef SIGWINCH
+ signal(SIGWINCH,winchh); /* Catch window-size change */
+#endif /* SIGWINCH */
+#endif /* NOSIGWINCH */
+
+#ifdef SIGXFSZ
+ signal(SIGXFSZ,SIG_IGN); /* Ignore writing past file limit */
+#endif /* SIGXFSZ */
+
+#ifndef NOJC
+/*
+ Get the initial job control state.
+ If it is SIG_IGN, that means the shell does not support job control,
+ and so we'd better not suspend ourselves.
+*/
+#ifdef SIGTSTP
+ jchdlr = signal(SIGTSTP,SIG_IGN);
+ if (jchdlr == SIG_IGN) {
+ jcshell = 0;
+ debug(F100,"sysinit jchdlr: SIG_IGN","",0);
+ } else if (jchdlr == SIG_DFL) {
+ debug(F100,"sysinit jchdlr: SIG_DFL","",0);
+ jcshell = 1;
+ } else {
+ debug(F100,"sysinit jchdlr: other","",0);
+ jcshell = 3;
+ }
+ (VOID) signal(SIGTSTP,jchdlr); /* Put it back... */
+#endif /* SIGTSTP */
+#endif /* NOJC */
+
+ conbgt(0); /* See if we're in the background */
+ congm(); /* Get console modes */
+
+ (VOID) signal(SIGALRM,SIG_IGN); /* Ignore alarms */
+
+ ignorsigs(); /* Ignore some other signals */
+
+#ifdef F_SETFL
+ iniflags = fcntl(0,F_GETFL,0); /* Get stdin flags */
+#endif /* F_SETFL */
+
+#ifdef ultrix
+ gtty(0,&vanilla); /* Get sgtty info */
+#else
+#ifdef AUX
+ set42sig(); /* Don't ask! (hakanson@cs.orst.edu) */
+#endif /* AUX */
+#endif /* ultrix */
+/*
+ Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
+ never closes it. If it is called often enough, we run out of file
+ descriptors and subsequent open()'s of other devices or files can fail.
+*/
+ s = NULL;
+#ifndef MINIX
+ if (isatty(0)) /* Name of controlling terminal */
+ s = ttyname(0);
+ else if (isatty(1))
+ s = ttyname(1);
+ else if (isatty(2))
+ s = ttyname(2);
+ debug(F110,"sysinit ttyname(0)",s,0);
+#endif /* MINIX */
+
+#ifdef BEOS
+ if (!dftty)
+ makestr(&dftty,s);
+#endif /* BEOS */
+
+ if (s)
+ ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
+#ifdef SVORPOSIX
+ if (!cttnam[0])
+ ctermid(cttnam);
+#endif /* SVORPOSIX */
+ if (!cttnam[0])
+ ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
+ debug(F110,"sysinit CTTNAM",CTTNAM,0);
+ debug(F110,"sysinit cttnam",cttnam,0);
+
+ ttgwsiz(); /* Get window (screen) dimensions. */
+
+#ifndef NOSYSCONF
+#ifdef _SC_OPEN_MAX
+ ckmaxfiles = sysconf(_SC_OPEN_MAX);
+#endif /* _SC_OPEN_MAX */
+#endif /* NOSYSCONF */
+
+#ifdef Plan9
+ if (!backgrd) {
+ consctlfd = open("/dev/consctl", O_WRONLY);
+ /*noisefd = open("/dev/noise", O_WRONLY)*/
+ }
+ ckxech = 1;
+#endif /* Plan9 */
+
+#ifdef CK_UTSNAME
+ if (uname(&name) > -1) {
+ ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
+ ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
+ ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
+ ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"sysinit uname machine",unm_mch,0);
+ debug(F110,"sysinit uname sysname",unm_nam,0);
+ debug(F110,"sysinit uname release",unm_rel,0);
+ debug(F110,"sysinit uname version",unm_ver,0);
+ }
+#endif /* DEBUG */
+
+#ifdef HPUX9PLUS
+ if (name.machine[5] == '8')
+ hpis800 = 1;
+ else
+ hpis800 = 0;
+ debug(F101,"sysinit hpis800","",hpis800);
+#endif /* HPUX9PLUS */
+#ifdef TRU64
+ getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
+ debug(F110,"sysinit getsysinfo model",unm_mod,0);
+#endif /* TRU64 */
+#ifdef SOLARIS25
+ sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
+ debug(F110,"sysinit sysinfo model",unm_mod,0);
+#endif /* SOLARIS25 */
+ }
+#endif /* CK_UTSNAME */
+
+#ifdef CK_ENVIRONMENT
+ {
+#ifdef TNCODE
+ extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
+ tn_env_prnt[], tn_env_sys[];
+#endif /* TNCODE */
+ extern char uidbuf[];
+ extern char * whoami();
+ char *p;
+#ifdef CKSENDUID
+ uidbuf[0] = '\0';
+#ifdef IKSD
+ if (!inserver) {
+#endif /* IKSD */
+ p = getenv("USER");
+ debug(F110,"sysinit uidbuf from USER",uidbuf,0);
+ if (!p) p = "";
+ if (!*p) {
+ p = getenv("LOGNAME");
+ debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
+ }
+ if (!p) p = "";
+ if (!*p) {
+ p = whoami();
+ debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
+ }
+ if (!p) p = "";
+ ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
+#ifdef IKSD
+ }
+#endif /* IKSD */
+ debug(F110,"sysinit final uidbuf",uidbuf,0);
+#endif /* CKSENDUID */
+
+#ifdef TNCODE
+ if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
+ if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
+ if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
+ if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
+#ifdef aegis
+ ckstrncpy(tn_env_sys,"Aegis",64);
+#else
+#ifdef Plan9
+ ckstrncpy(tn_env_sys,"Plan9",64);
+#else
+ ckstrncpy(tn_env_sys,"UNIX",64);
+#endif /* Plan9 */
+#endif /* aegis */
+#endif /* TNCODE */
+ }
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ {
+ extern char * tn_loc;
+ char *p;
+ if (p = getenv("LOCATION"))
+ if (tn_loc = (char *)malloc((int)strlen(p)+1))
+ strcpy(tn_loc,p); /* safe */
+ }
+#endif /* CK_SNDLOC */
+
+ ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
+ startupdir[CKMAXPATH] = '\0';
+ x = strlen(startupdir);
+ if (x <= 0) {
+ startupdir[0] = '/';
+ startupdir[1] = '\0';
+ } else if (startupdir[x-1] != '/') {
+ startupdir[x] = '/';
+ startupdir[x+1] = '\0';
+ }
+ debug(F110,"sysinit startupdir",startupdir,0);
+#ifdef TTLEBUF
+ le_init();
+#endif /* TTLEBUF */
+#ifdef BSD44ORPOSIX
+ /* This should catch the ncurses platforms */
+ /* Some platforms don't have putenv(), like NeXTSTEP */
+ putenv("NCURSES_NO_SETBUF=1");
+#endif /* BSD44ORPOSIX */
+ return(0);
+}
+
+/* S Y S C L E A N U P -- System-dependent program cleanup. */
+
+int
+syscleanup() {
+#ifdef F_SETFL
+ if (iniflags > -1)
+ fcntl(0,F_SETFL,iniflags); /* Restore stdin flags */
+#endif /* F_SETFL */
+#ifdef ultrix
+ stty(0,&vanilla); /* Get sgtty info */
+#endif /* ultrix */
+#ifdef NETCMD
+ if (ttpid) kill(ttpid,9);
+#endif /* NETCMD */
+ return(0);
+}
+
+/* T T O P E N -- Open a tty for exclusive access. */
+
+/*
+ Call with:
+ ttname: character string - device name or network host name.
+ lcl:
+ If called with lcl < 0, sets value of lcl as follows:
+ 0: the terminal named by ttname is the job's controlling terminal.
+ 1: the terminal named by ttname is not the job's controlling terminal.
+ But watch out: if a line is already open, or if requested line can't
+ be opened, then lcl remains (and is returned as) -1.
+ modem:
+ Less than zero: ttname is a network host name.
+ Zero or greater: ttname is a terminal device name.
+ Zero means a local connection (don't use modem signals).
+ Positive means use modem signals.
+ timo:
+ 0 = no timer.
+ nonzero = number of seconds to wait for open() to return before timing out.
+
+ Returns:
+ 0 on success
+ -5 if device is in use
+ -4 if access to device is denied
+ -3 if access to lock directory denied
+ -2 upon timeout waiting for device to open
+ -1 on other error
+*/
+static int ttotmo = 0; /* Timeout flag */
+/* Flag kept here to avoid being clobbered by longjmp. */
+
+int
+ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
+
+#ifdef BSD44
+#define ctermid(x) strcpy(x,"")
+#else
+#ifdef SVORPOSIX
+#ifndef CIE
+ extern char *ctermid(); /* Wish they all had this! */
+#else /* CIE Regulus */
+#define ctermid(x) strcpy(x,"")
+#endif /* CIE */
+#endif /* SVORPOSIX */
+#endif /* BSD44 */
+
+#ifdef ultrix
+ int temp = 0;
+#endif /* ultrix */
+
+#ifndef OPENFIRST
+ char fullname[DEVNAMLEN+1];
+#endif /* OPENFIRST */
+
+ char * fnam; /* Full name after expansion */
+
+ int y;
+
+#ifndef pdp11
+#define NAMEFD /* Feature to allow name to be an open file descriptor */
+#endif /* pdp11 */
+
+#ifdef NAMEFD
+ char *p;
+ debug(F101,"ttopen telnetfd","",telnetfd);
+#endif /* NAMEFD */
+
+ debug(F110,"ttopen ttname",ttname,0);
+ debug(F110,"ttopen ttnmsv",ttnmsv,0);
+ debug(F101,"ttopen modem","",modem);
+ debug(F101,"ttopen netconn","",netconn);
+ debug(F101,"ttopen ttyfd","",ttyfd);
+ debug(F101,"ttopen *lcl","",*lcl);
+ debug(F101,"ttopen ttmdm","",ttmdm);
+ debug(F101,"ttopen ttnet","",ttnet);
+
+ ttpmsk = 0xff;
+ lockpid[0] = '\0';
+
+ if (ttyfd > -1) { /* If device already opened */
+ if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
+ return(0); /* Yes, nothing to do - just return */
+ ttnmsv[0] = '\0'; /* No, clear out old name */
+ ttclos(ttyfd); /* close old connection. */
+ }
+ wasclosed = 0; /* New connection, not closed yet. */
+ ttpipe = 0; /* Assume it's not a pipe */
+ ttpty = 0; /* or a pty... */
+
+#ifdef NETCONN
+/*
+ This is a bit tricky... Suppose that previously Kermit had dialed a telnet
+ modem server ("set host xxx:2001, set modem type usr, dial ..."). Then the
+ connection was closed (ttyfd = -1), and then a REDIAL command was given. At
+ this point we've obliterated the negative modem type hack, and so would
+ treat the IP hostname as a device name, and would then fail because of "No
+ such device or directory". But the previous connection has left behind some
+ clues, so let's use them...
+*/
+ if (ttyfd < 0) { /* Connection is not open */
+ if (!strcmp(ttname,ttnmsv)) { /* Old and new names the same? */
+ if (((netconn > 0) && (ttmdm < 0)) ||
+ ((ttnet > 0) &&
+ (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
+ ) {
+ int x, rc;
+ x = (ttmdm < 0) ? -ttmdm : ttnet;
+ rc = netopen(ttname, lcl, x);
+ debug(F111,"ttopen REOPEN netopen",ttname,rc);
+ if (rc > -1) {
+ netconn = 1;
+ xlocal = *lcl = 1;
+ } else {
+ netconn = 0;
+ }
+ gotsigs = 0;
+ return(rc);
+ }
+ }
+ }
+#endif /* NETCONN */
+
+#ifdef MAXNAMLEN
+ debug(F100,"ttopen MAXNAMLEN defined","",0);
+#else
+ debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
+#endif
+
+#ifdef BSD4
+ debug(F100,"ttopen BSD4 defined","",0);
+#else
+ debug(F100,"ttopen BSD4 *NOT* defined","",0);
+#endif /* BSD4 */
+
+#ifdef BSD42
+ debug(F100,"ttopen BSD42 defined","",0);
+#else
+ debug(F100,"ttopen BSD42 *NOT* defined","",0);
+#endif /* BSD42 */
+
+#ifdef MYREAD
+ debug(F100,"ttopen MYREAD defined","",0);
+#else
+ debug(F100,"ttopen MYREAD *NOT* defined","",0);
+#endif /* MYREAD */
+
+#ifdef NETCONN
+ if (modem < 0) { /* modem < 0 = code for network */
+ int x;
+ ttmdm = modem;
+ modem = -modem; /* Positive network type number */
+ fdflag = 0; /* Stdio not redirected. */
+ netconn = 1; /* And it's a network connection */
+ debug(F111,"ttopen net",ttname,modem);
+#ifdef NAMEFD
+ for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
+ if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
+ ttyfd = atoi(ttname); /* Is there a way to test it's open? */
+ ttfdflg = 1; /* We got an open file descriptor */
+ debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
+ debug(F101,"ttopen net ttyfd","",ttyfd);
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
+ x = 1; /* Return code is "good". */
+ if (telnetfd) {
+ ttnet = NET_TCPB;
+ if (ttnproto != NP_TCPRAW)
+ ttnproto = NP_TELNET;
+#ifdef SUNX25
+ } else if (x25fd) {
+ ttnet = NET_SX25;
+ ttnproto = NP_NONE;
+#endif /* SUNX25 */
+ }
+ } else { /* Host name or address given */
+#ifdef NETPTY
+ if (modem == NET_PTY) {
+ int x;
+ if (nopush) {
+ debug(F100,"ttopen PTY: nopush","",0);
+ return(-1);
+ }
+ ttnet = NET_PTY;
+ ttnproto = NP_NONE;
+ netconn = 1; /* but we don't use network i/o */
+ ttpty = 1;
+ debug(F110,"ttopen PTY",ttname,0);
+ x = do_pty(&ttyfd,ttname,0);
+ if (x > -1) {
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
+ xlocal = *lcl = 1; /* It's local */
+ } else {
+ ttpty = 0;
+ netconn = 0;
+ }
+ gotsigs = 0;
+ return(x);
+ }
+#endif /* NETPTY */
+#ifdef NETCMD
+/*
+ dup2() is not available on older System V platforms like AT&T 3Bx. For
+ those systems we punt by not defining NETCMD, but we might be able to do
+ better -- see workarounds for this problem in ckufio.c (search for dup2).
+*/
+ if (modem == NET_CMD) {
+ if (nopush) {
+ debug(F100,"ttopen pipe: nopush","",0);
+ return(-1);
+ }
+ if (pipe(pipe0) || pipe(pipe1)) {
+ perror("Pipe error");
+ return(-1);
+ }
+ ttpid = fork(); /* Make a fork */
+
+ switch (ttpid) {
+ case -1: /* Error making fork */
+ close(pipe0[0]);
+ close(pipe0[1]);
+ close(pipe1[0]);
+ close(pipe1[1]);
+ perror("Fork error");
+ return(-1);
+ case 0: /* Child. */
+ close(pipe0[0]);
+ close(pipe1[1]);
+ dup2(pipe0[1], 1);
+ close(pipe0[1]);
+ dup2(pipe1[0], 0);
+ close(pipe1[0]);
+ system(ttname);
+ _exit(0);
+ default: /* Parent */
+ close(pipe0[1]);
+ close(pipe1[0]);
+ fdin = pipe0[0]; /* Read from pipe */
+ fdout = pipe1[1]; /* Write to pipe */
+ ttout = fdopen(fdout,"w"); /* Get stream so we can */
+ if (!ttout) { /* make it unbuffered. */
+ perror("fdopen failure");
+ return(-1);
+ }
+ setbuf(ttout,NULL);
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
+ xlocal = *lcl = 1; /* It's local */
+ netconn = 1; /* Call it a network connection */
+ ttmdm = modem; /* Remember network type */
+ ttyfd = fdin;
+ ttpipe = 1;
+ gotsigs = 0;
+ return(0);
+ }
+ }
+#endif /* NETCMD */
+#endif /* NAMEFD */
+ x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
+ if (x > -1) {
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
+ } else netconn = 0;
+#ifdef NAMEFD
+ }
+#endif /* NAMEFD */
+
+#ifdef sony_news /* Sony NEWS */
+ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
+ perror("ttopen error getting Kanji mode (network)");
+ debug(F111,"ttopen error getting Kanji mode","network",0);
+ km_ext = -1; /* Make sure this stays undefined. */
+ }
+#endif /* sony_news */
+
+ xlocal = *lcl = 1; /* Network connections are local. */
+ debug(F101,"ttopen net x","",x);
+#ifdef COMMENT
+/* Let netopen() do this */
+ if (x > -1 && !x25fd)
+ x = tn_ini(); /* Initialize TELNET protocol */
+#endif /* COMMENT */
+ gotsigs = 0;
+ return(x);
+ } else { /* Terminal device */
+#endif /* NETCONN */
+
+#ifdef NAMEFD
+/*
+ This code lets you give Kermit an open file descriptor for a serial
+ communication device, rather than a device name. Kermit assumes that the
+ line is already open, locked, conditioned with the right parameters, etc.
+*/
+ for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
+ if (*p == '\0') {
+ ttyfd = atoi(ttname); /* Is there a way to test it's open? */
+ debug(F111,"ttopen got open fd",ttname,ttyfd);
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
+ if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
+ xlocal = *lcl = 0; /* we're in remote mode */
+ else /* otherwise */
+ xlocal = *lcl = 1; /* local mode. */
+ netconn = 0; /* Assume it's not a network. */
+ tvtflg = 0; /* Might need to initialize modes. */
+ ttmdm = modem; /* Remember modem type. */
+ fdflag = 0; /* Stdio not redirected. */
+ ttfdflg = 1; /* Flag we were opened this way. */
+ debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
+ debug(F101,"ttopen non-net ttyfd","",ttyfd);
+
+#ifdef sony_news /* Sony NEWS */
+ /* Get device Kanji mode */
+ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
+ perror("ttopen error getting Kanji mode");
+ debug(F101,"ttopen error getting Kanji mode","",0);
+ km_ext = -1; /* Make sure this stays undefined. */
+ }
+#endif /* sony_news */
+ gotsigs = 0;
+ return(0); /* Return success */
+ }
+#endif /* NAMEFD */
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+
+/* Here we have to open a serial device of the given name. */
+
+ netconn = 0; /* So it's not a network connection */
+ occt = signal(SIGINT, cctrap); /* Set Control-C trap, save old one */
+ sigint_ign = 0;
+
+ tvtflg = 0; /* Flag for use by ttvt(). */
+ /* 0 = ttvt not called yet for this device */
+
+ fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
+ debug(F101,"ttopen fdflag","",fdflag);
+
+ ttmdm = modem; /* Make this available to other fns */
+ xlocal = *lcl; /* Make this available to other fns */
+
+/* Code for handling bidirectional tty lines goes here. */
+/* Use specified method for turning off logins and suppressing getty. */
+
+#ifdef ACUCNTRL
+ /* Should put call to priv_on() here, but that would be very risky! */
+ acucntrl("disable",ttname); /* acucntrl() program. */
+ /* and priv_off() here... */
+#else
+#ifdef ATT7300
+ if ((attmodem & DOGETY) == 0) /* offgetty() program. */
+ attmodem |= offgetty(ttname); /* Remember response. */
+#endif /* ATT7300 */
+#endif /* ACUCNTRL */
+
+#ifdef OPENFIRST
+/*
+ 1985-2001: opens device first then gets lock; reason:
+ Kermit usually has to run setuid or setgid in order to create a lockfile.
+ If you give a SET LINE command for a device that happens to be your job's
+ controlling terminal, Kermit doesn't have to create a lockfile, and in fact
+ should not create one, and would fail if it tried to if it did not have the
+ required privileges. But you can't find out if two tty device names are
+ equivalent until you have a file descriptor that you can give to ttyname().
+ But this can cause a race condition between Kermit and [m]getty. So see
+ the [#]else part...
+*/
+
+/*
+ In the following section, we open the tty device for read/write.
+ If a modem has been specified via "set modem" prior to "set line"
+ then the O_NDELAY parameter is used in the open, provided this symbol
+ is defined (e.g. in fcntl.h), so that the program does not hang waiting
+ for carrier (which in most cases won't be present because a connection
+ has not been dialed yet). O_NDELAY is removed later on in ttopen(). It
+ would make more sense to first determine if the line is local before
+ doing this, but because ttyname() requires a file descriptor, we have
+ to open it first. See do_open().
+
+ Now open the device using the desired treatment of carrier.
+ If carrier is REQUIRED, then open could hang forever, so an optional
+ timer is provided. If carrier is not required, the timer should never
+ go off, and should do no harm...
+*/
+ ttotmo = 0; /* Flag no timeout */
+ debug(F101,"ttopen timo","",timo);
+ debug(F101,"ttopen xlocal","",xlocal);
+ if (timo > 0) {
+ int xx;
+ saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
+ xx = alarm(timo); /* Timed open() */
+ debug(F101,"ttopen alarm","",xx);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) {
+ ttotmo = 1; /* Flag timeout. */
+ } else ttyfd = do_open(ttname);
+ ttimoff();
+ debug(F111,"ttopen","modem",modem);
+ debug(F101,"ttopen ttyfd","",ttyfd);
+ debug(F101,"ttopen alarm return","",ttotmo);
+ } else {
+ errno = 0;
+ ttyfd = do_open(ttname);
+ }
+ debug(F111,"ttopen ttyfd",ttname,ttyfd);
+ if (ttyfd < 0) { /* If couldn't open, fail. */
+ debug(F101,"ttopen errno","",errno);
+ if (errno > 0 && !quiet)
+ perror(ttname); /* Print message */
+
+#ifdef ATT7300
+ if (attmodem & DOGETY) /* was getty(1m) running before us? */
+ ongetty(ttnmsv); /* yes, restart on tty line */
+ attmodem &= ~DOGETY; /* no phone in use, getty restored */
+#else
+#ifdef ACUCNTRL
+ /* Should put call to priv_on() here, but that would be risky! */
+ acucntrl("enable",ttname); /* acucntrl() program. */
+ /* and priv_off() here... */
+#endif /* ACUNTRL */
+#endif /* ATT7300 */
+
+ signal(SIGINT,occt); /* Put old Ctrl-C trap back. */
+ if (errno == EACCES) { /* Device is protected against user */
+ debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
+ return(-4);
+ } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
+ }
+
+#ifdef QNX
+ {
+ extern int qnxportlock;
+ x = qnxopencount();
+ debug(F101,"ttopen qnxopencount","",x);
+ debug(F101,"ttopen qnxportlock","",qnxportlock);
+ if (x < 0 && qnxportlock) {
+ ttclos(0);
+ printf("?Can't get port open count\n");
+ printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
+ return(-1); /* Indicate device is in use */
+ }
+ if (x > 1) { /* 1 == me */
+ if (qnxportlock)
+ ttclos(0);
+ return(-2); /* Indicate device is in use */
+ else if (!quiet)
+ printf("WARNING: \"%s\" looks busy...\n",ttdev);
+ }
+ }
+#endif /* QNX */
+
+#ifdef Plan9
+ /* take this opportunity to open the control channel */
+ if (p9openttyctl(ttname) < 0)
+#else
+ /* Make sure it's a real tty. */
+ if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
+#endif /* Plan9 */
+ {
+ fprintf(stderr,"%s is not a terminal device\n",ttname);
+ debug(F111,"ttopen not a tty",ttname,errno);
+ close(ttyfd);
+ ttyfd = -1;
+ wasclosed = 1;
+ signal(SIGINT,occt);
+ return(-1);
+ }
+
+#ifdef aegis
+ /* Apollo C runtime claims that console pads are tty devices, which
+ * is reasonable, but they aren't any good for packet transfer. */
+ ios_$inq_type_uid((short)ttyfd, ttyuid, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "problem getting tty object type: ");
+ error_$print(st);
+ } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
+ close(ttyfd); ttyfd = -1;
+ wasclosed = 1;
+ errno = ENOTTY; perror(ttname);
+ signal(SIGINT,occt);
+ return(-1);
+ }
+#endif /* aegis */
+
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
+
+/* Caller wants us to figure out if line is controlling tty */
+
+ if (*lcl < 0) {
+ if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
+ xlocal = 0;
+ debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
+ } else if (strcmp(ttname,cttnam) == 0) {
+ xlocal = 0;
+ debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
+ } else if (cttnam[0]) {
+#ifdef BEBOX_DR7
+ x = ttnmsv; /* ttyname() is broken */
+#else
+ x = ttyname(ttyfd); /* Get real name of ttname. */
+#endif /* BEBOX_DR7 */
+ if (!x) x = "";
+ if (*x)
+ xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
+ else
+ xlocal = 1;
+ debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
+ }
+ }
+
+#ifndef NOFDZERO
+/* Note, the following code was added so that Unix "idle-line" snoopers */
+/* would not think Kermit was idle when it was transferring files, and */
+/* maybe log people out. */
+ if (xlocal == 0) { /* Remote mode */
+ if (fdflag == 0) { /* Standard i/o is not redirected */
+ debug(F100,"ttopen setting ttyfd = 0","",0);
+#ifdef LYNXOS
+ /* On Lynx OS, fd 0 is open for read only. */
+ dup2(ttyfd,0);
+#endif /* LYNXOS */
+ close(ttyfd); /* Use file descriptor 0 */
+ ttyfd = 0;
+ } else { /* Standard i/o is redirected */
+ debug(F101,"ttopen stdio redirected","",ttyfd);
+ }
+ }
+#endif /* NOFDZERO */
+
+/* Now check if line is locked -- if so fail, else lock for ourselves */
+/* Note: After having done this, don't forget to delete the lock if you */
+/* leave ttopen() with an error condition. */
+
+ lkf = 0; /* Check lock */
+ if (xlocal > 0) {
+ int xx; int xpid;
+ if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
+ debug(F111,"ttopen ttlock fails",ttname,xx);
+ /* WARNING - This close() can hang if tty is an empty socket... */
+ close(ttyfd); /* Close the device. */
+ ttyfd = -1; /* Erase its file descriptor. */
+ wasclosed = 1;
+ signal(SIGINT,occt); /* Put old SIGINT back. */
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+ if (xx == -2) { /* If lockfile says device in use, */
+#ifndef NOUUCP
+ debug(F111,"ttopen reading lockfile pid",flfnam,xx);
+ xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
+ if (xpid > -1) { /* If we got a pid */
+ if (!quiet)
+ printf("Locked by process %d\n",xpid); /* tell them. */
+ sprintf(lockpid,"%d",xpid); /* Record it too */
+ debug(F110,"ttopen lockpid",lockpid,0);
+ } else if (*flfnam) {
+ extern char *DIRCMD;
+ char *p = NULL;
+ int x;
+ x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
+ p = malloc(x); /* Print a directory listing. */
+/*
+ Note: priv_on() won't help here, because we do not pass privs along to
+ to inferior processes, in this case ls. So if the real user does not have
+ directory-listing access to the lockfile directory, this will result in
+ something like "not found". That's why we try this only as a last resort.
+*/
+ if (p) { /* If we got the space... */
+ ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
+ zsyscmd(p); /* Get listing. */
+ if (p) { /* free the space */
+ free(p);
+ p = NULL;
+ }
+ }
+ }
+#endif /* NOUUCP */
+ return(-5); /* Code for device in use */
+ } else return(-3); /* Access denied */
+ } else lkf = 1;
+ }
+#else /* OPENFIRST */
+
+/*
+ 27 Oct 2001: New simpler code that gets the lock first and then opens the
+ device, which eliminates the race condition. The downside is you can no
+ longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
+ terminal, without trying to create a lockfile, which fails if C-Kermit lacks
+ privs, and if it succeeds, it has created a lockfile where it didn't create
+ one before.
+*/
+ xlocal = *lcl; /* Is the device my login terminal? */
+ debug(F111,"ttopen xlocal","A",xlocal);
+ fnam = ttname;
+ if (strcmp(ttname,CTTNAM) && netconn == 0) {
+ if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
+ if ((int)strlen(fullname) > 0)
+ fnam = fullname;
+ }
+ }
+ debug(F110,"ttopen fnam",fnam,0);
+ if (xlocal < 0) {
+ xlocal = (strcmp(fnam,CTTNAM) != 0);
+ }
+ debug(F111,"ttopen xlocal","B",xlocal);
+
+ lkf = 0; /* No lock yet */
+ if (xlocal > 0) { /* If not... */
+ int xx; int xpid;
+ xx = ttlock(fnam); /* Try to lock it. */
+ debug(F101,"ttopen ttlock","",xx);
+ if (xx < 0) { /* Can't lock it. */
+ debug(F111,"ttopen ttlock fails",fnam,xx);
+ if (xx == -2) { /* If lockfile says device in use, */
+#ifndef NOUUCP
+ debug(F111,"ttopen reading lockfile pid",flfnam,xx);
+ xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
+ if (xpid > -1) { /* If we got a pid */
+ if (!quiet)
+ printf("Locked by process %d\n",xpid); /* tell them. */
+ ckstrncpy(lockpid,ckitoa(xpid),16);
+ debug(F110,"ttopen lockpid",lockpid,0);
+#ifndef NOPUSH
+ } else if (flfnam[0] && !nopush) {
+ extern char *DIRCMD;
+ char *p = NULL;
+ int x;
+ x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
+ p = malloc(x); /* Print a directory listing. */
+/*
+ Note: priv_on() won't help here, because we do not pass privs along to
+ to inferior processes, in this case ls. So if the real user does not have
+ directory-listing access to the lockfile directory, this will result in
+ something like "not found". That's why we try this only as a last resort.
+*/
+ if (p) { /* If we got the space... */
+ ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
+ zsyscmd(p); /* Get listing. */
+ if (p) { /* free the space */
+ free(p);
+ p = NULL;
+ }
+ }
+#endif /* NOPUSH */
+ }
+#endif /* NOUUCP */
+ return(-5); /* Code for device in use */
+ } else return(-3); /* Access denied */
+ } else lkf = 1;
+ }
+ /* Have lock -- now it's safe to open the device */
+
+ debug(F101,"ttopen lkf","",lkf);
+ debug(F101,"ttopen timo","",timo);
+
+ ttotmo = 0; /* Flag no timeout */
+ if (timo > 0) {
+ int xx;
+ saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
+ xx = alarm(timo); /* Timed open() */
+ debug(F101,"ttopen alarm","",xx);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) {
+ ttotmo = 1; /* Flag timeout. */
+ } else {
+ ttyfd = do_open(fnam);
+ }
+ ttimoff();
+ debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
+ } else {
+ errno = 0;
+ ttyfd = do_open(fnam);
+ debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
+ }
+ if (ttyfd < 0) { /* If couldn't open, fail. */
+ debug(F111,"ttopen errno",fnam,errno);
+ debug(F111,"ttopen xlocal","C",xlocal);
+ if (xlocal == 0) {
+ debug(F100,"ttopen substituting 0","",0);
+ ttyfd = 0;
+ } else {
+ if (errno > 0 && !quiet) {
+ debug(F111,"ttopen perror",fnam,errno);
+ perror(fnam); /* Print message */
+ }
+ if (ttunlck()) /* Release the lock file */
+ fprintf(stderr,"Warning, problem releasing lock\r\n");
+ }
+ }
+
+ if (ttyfd < 0) { /* ttyfd is still < 0? */
+#ifdef ATT7300
+ if (attmodem & DOGETY) /* was getty(1m) running before us? */
+ ongetty(ttnmsv); /* yes, restart on tty line */
+ attmodem &= ~DOGETY; /* no phone in use, getty restored */
+#else
+#ifdef ACUCNTRL
+ /* Should put call to priv_on() here, but that would be risky! */
+ acucntrl("enable",fnam); /* acucntrl() program. */
+ /* and priv_off() here... */
+#endif /* ACUNTRL */
+#endif /* ATT7300 */
+
+ signal(SIGINT,occt); /* Put old Ctrl-C trap back. */
+ if (errno == EACCES) { /* Device is protected against user */
+ debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
+ return(-4);
+ } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
+ }
+
+/* Make sure it's a real tty. */
+
+#ifdef Plan9
+ /* take this opportunity to open the control channel */
+ if (p9openttyctl(fnam) < 0)
+#else
+ if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
+#endif /* Plan9 */
+ {
+ fprintf(stderr,"%s is not a terminal device\n",fnam);
+ debug(F111,"ttopen not a tty",fnam,errno);
+ if (ttunlck()) /* Release the lock file */
+ fprintf(stderr,"Warning, problem releasing lock\r\n");
+ close(ttyfd);
+ ttyfd = -1;
+ wasclosed = 1;
+ signal(SIGINT,occt);
+ return(-1);
+ }
+
+#ifdef aegis
+ /*
+ Apollo C runtime claims that console pads are tty devices, which
+ is reasonable, but they aren't any good for packet transfer.
+ */
+ ios_$inq_type_uid((short)ttyfd, ttyuid, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "problem getting tty object type: ");
+ error_$print(st);
+ } else if (ttyuid != sio_$uid) { /* Reject non-SIO lines */
+ close(ttyfd); ttyfd = -1;
+ wasclosed = 1;
+ errno = ENOTTY; perror(fnam);
+ signal(SIGINT,occt);
+ return(-1);
+ }
+#endif /* aegis */
+
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
+
+/* Caller wants us to figure out if line is controlling tty */
+
+ if (*lcl < 0) {
+ char * s;
+ if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
+ xlocal = 0;
+ debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
+ } else if (strcmp(fnam,cttnam) == 0) {
+ xlocal = 0;
+ debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
+ } else if (cttnam[0]) {
+#ifdef BEBOX_DR7
+ s = ttnmsv; /* ttyname() is broken */
+#else
+ s = ttyname(ttyfd); /* Get real name of ttname. */
+#endif /* BEBOX_DR7 */
+ if (!s) s = "";
+ if (*s)
+ xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
+ else
+ xlocal = 1;
+ debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
+ }
+ }
+
+#ifndef NOFDZERO
+/* Note, the following code was added so that Unix "idle-line" snoopers */
+/* would not think Kermit was idle when it was transferring files, and */
+/* maybe log people out. */
+ if (xlocal == 0) { /* Remote mode */
+ if (fdflag == 0) { /* Standard i/o is not redirected */
+ debug(F100,"ttopen setting ttyfd = 0","",0);
+#ifdef LYNXOS
+ /* On Lynx OS, fd 0 is open for read only. */
+ dup2(ttyfd,0);
+#endif /* LYNXOS */
+ close(ttyfd); /* Use file descriptor 0 */
+ ttyfd = 0;
+ } else { /* Standard i/o is redirected */
+ debug(F101,"ttopen stdio redirected","",ttyfd);
+ }
+ }
+#endif /* NOFDZERO */
+#endif /* OPENFIRST */
+
+/* Got the line, now set the desired value for local. */
+
+ if (*lcl != 0) *lcl = xlocal;
+
+/* Some special stuff for v7... */
+
+#ifdef V7
+#ifndef MINIX
+ if (kmem[TTY] < 0) { /* If open, then skip this. */
+ qaddr[TTY] = initrawq(ttyfd); /* Init the queue. */
+ if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
+ fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
+ perror("/dev/kmem");
+ exit(1);
+ }
+ }
+#endif /* !MINIX */
+#endif /* V7 */
+
+/* No failure returns after this point */
+
+#ifdef ultrix
+ ioctl(ttyfd, TIOCMODEM, &temp);
+#ifdef TIOCSINUSE
+ if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
+ if (!quiet)
+ perror(fnam);
+ }
+#endif /* TIOCSINUSE */
+#endif /* ultrix */
+
+/* Get tty device settings */
+
+#ifdef BSD44ORPOSIX /* POSIX */
+ tcgetattr(ttyfd,&ttold);
+ debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
+ tcgetattr(ttyfd,&ttraw);
+ debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
+ tcgetattr(ttyfd,&tttvt);
+ debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
+#else /* BSD, V7, and all others */
+#ifdef ATTSV /* AT&T UNIX */
+ ioctl(ttyfd,TCGETA,&ttold);
+ debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
+ ioctl(ttyfd,TCGETA,&ttraw);
+ ioctl(ttyfd,TCGETA,&tttvt);
+#else
+#ifdef BELLV10
+ ioctl(ttyfd,TIOCGETP,&ttold);
+ debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
+ ioctl(ttyfd,TIOCGDEV,&tdold);
+ debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
+#else
+ gtty(ttyfd,&ttold);
+ debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
+#endif /* BELLV10 */
+
+#ifdef sony_news /* Sony NEWS */
+ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
+ perror("ttopen error getting Kanji mode");
+ debug(F101,"ttopen error getting Kanji mode","",0);
+ km_ext = -1; /* Make sure this stays undefined. */
+ }
+#endif /* sony_news */
+
+#ifdef TIOCGETC
+ debug(F100,"ttopen TIOCGETC","",0);
+ tcharf = 0; /* In remote mode, also get */
+ if (xlocal == 0) { /* special characters */
+ if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
+ debug(F100,"ttopen TIOCGETC failed","",0);
+ } else {
+ tcharf = 1; /* It worked. */
+ ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
+ debug(F100,"ttopen TIOCGETC ok","",0);
+ }
+ }
+#else
+ debug(F100,"ttopen TIOCGETC not defined","",0);
+#endif /* TIOCGETC */
+
+#ifdef TIOCGLTC
+ debug(F100,"ttopen TIOCGLTC","",0);
+ ltcharf = 0; /* In remote mode, also get */
+ if (xlocal == 0) { /* local special characters */
+ if (ioctl(ttyfd,TIOCGLTC,<chold) < 0) {
+ debug(F100,"ttopen TIOCGLTC failed","",0);
+ } else {
+ ltcharf = 1; /* It worked. */
+ ioctl(ttyfd,TIOCGLTC,<chnoi); /* Get another copy */
+ debug(F100,"ttopen TIOCGLTC ok","",0);
+ }
+ }
+#else
+ debug(F100,"ttopen TIOCGLTC not defined","",0);
+#endif /* TIOCGLTC */
+
+#ifdef TIOCLGET
+ debug(F100,"ttopen TIOCLGET","",0);
+ lmodef = 0;
+ if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
+ debug(F100,"ttopen TIOCLGET failed","",0);
+ } else {
+ lmodef = 1;
+ debug(F100,"ttopen TIOCLGET ok","",0);
+ }
+#endif /* TIOCLGET */
+
+#ifdef BELLV10
+ ioctl(ttyfd,TIOCGETP,&ttraw);
+ ioctl(ttyfd,TIOCGETP,&tttvt);
+#else
+ gtty(ttyfd,&ttraw); /* And a copy of it for packets*/
+ gtty(ttyfd,&tttvt); /* And one for virtual tty service */
+#endif /* BELLV10 */
+
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+/* Section for changing line discipline. It's restored in ttres(). */
+
+#ifdef AIXRS
+#ifndef AIX41
+ { union txname ld_name; int ld_idx = 0;
+ ttld = 0;
+ do {
+ ld_name.tx_which = ld_idx++;
+ ioctl(ttyfd, TXGETCD, &ld_name);
+ if (!strncmp(ld_name.tx_name, "rts", 3))
+ ttld |= 1;
+ } while (*ld_name.tx_name);
+ debug(F101,"AIX line discipline","",ttld);
+ }
+#endif /* AIX41 */
+#endif /* AIXRS */
+
+#ifdef BSD41
+/* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
+ { int k;
+ ioctl(ttyfd, TIOCGETD, &ttld); /* Get and save line discipline */
+ debug(F101,"4.1bsd line discipline","",ttld);
+ k = OTTYDISC; /* Switch to "old" discipline */
+ k = ioctl(ttyfd, TIOCSETD, &k);
+ debug(F101,"4.1bsd tiocsetd","",k);
+ }
+#endif /* BSD41 */
+
+#ifdef aegis
+ /* This was previously done before the last two TCGETA or gtty above,
+ * in both the ATTSV and not-ATTSV case. If it is not okay to have only
+ * one copy if it here instead, give us a shout!
+ */
+ sio_$control((short)ttyfd, sio_$raw_nl, false, st);
+ if (xlocal) { /* ignore breaks from local line */
+ sio_$control((short)ttyfd, sio_$int_enable, false, st);
+ sio_$control((short)ttyfd, sio_$quit_enable, false, st);
+ }
+#endif /* aegis */
+
+#ifdef VXVE
+ ttraw.c_line = 0; /* STTY line 0 for VX/VE */
+ tttvt.c_line = 0; /* STTY line 0 for VX/VE */
+ ioctl(ttyfd,TCSETA,&ttraw);
+#endif /* vxve */
+
+/* If O_NDELAY was used during open(), then remove it now. */
+
+#ifdef O_NDELAY
+ debug(F100,"ttopen O_NDELAY","",0);
+ if (xlocal > 0) {
+ if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
+ debug(F100,"ttopen fcntl O_NDELAY","",0);
+#ifndef aegis
+ if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
+ debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
+ perror("Can't unset O_NDELAY");
+ }
+#endif /* aegis */
+ /* Some systems, notably Xenix (don't know how common this is in
+ * other systems), need special treatment to get rid of the O_NDELAY
+ * behaviour on read() with respect to carrier presence (i.e. read()
+ * returning 0 when carrier absent), even though the above fcntl()
+ * is enough to make read() wait for input when carrier is present.
+ * This magic, in turn, requires CLOCAL for working when the carrier
+ * is absent. But if xlocal == 0, presumably you already have CLOCAL
+ * or you have a carrier, otherwise you wouldn't be running this.
+ */
+ debug(F101,"ttopen xlocal","",xlocal);
+#ifdef ATTSV
+#ifdef BSD44ORPOSIX
+#ifdef COMMENT /* 12 Aug 1997 */
+#ifdef __bsdi__
+ if (xlocal)
+ ttraw.c_cflag |= CLOCAL;
+#else
+#ifdef __FreeBSD__
+ if (xlocal)
+ ttraw.c_cflag |= CLOCAL;
+#endif /* __FreeBSD__ */
+#endif /* __bsdi__ */
+#else /* Not COMMENT */
+#ifdef CLOCAL
+ if (xlocal) /* Unset this if it's defined. */
+ ttraw.c_cflag |= CLOCAL;
+#endif /* CLOCAL */
+#endif /* COMMENT */
+ debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
+ if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
+ debug(F100,"ttopen POSIX tcseattr fails","",0);
+ perror("tcsetattr");
+ }
+#else /* !BSD44ORPOSIX */
+ if (xlocal) {
+ ttraw.c_cflag |= CLOCAL;
+ debug(F100,"ttopen calling ioctl(TCSETA)","",0);
+ errno = 0;
+ if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
+ debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
+ perror("ioctl(TCSETA)");
+ }
+ }
+#endif /* BSD44ORPOSIX */
+#endif /* ATTSV */
+#ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
+/* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
+ debug(F100,"ttopen executing close/open","",0);
+ close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
+#endif /* NOCOTFMC */
+ }
+ }
+#endif /* O_NDELAY */
+
+/* Instruct the system how to treat the carrier, and set a few other tty
+ * parameters.
+ *
+ * This also undoes the temporary setting of CLOCAL that may have been done
+ * for the close(open()) above (except in Xenix). Also throw in ~ECHO, to
+ * prevent the other end of the line from sitting there talking to itself,
+ * producing garbage when the user performs a connect.
+ *
+ * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
+ * Now it thinks CLOCAL is always on. It seems the only real solution for
+ * Xenix is to switch between the lower and upper case device names.
+ *
+ * This section may at some future time expand into setting a complete
+ * collection of tty parameters, or call a function shared with ttpkt()/
+ * ttvt() that does so. On the other hand, the initial parameters are not
+ * that important, since ttpkt() or ttvt() should always fix that before
+ * any communication is done. Well, we'll see...
+ */
+ if (xlocal) {
+ curcarr = -2;
+ debug(F100,"ttopen calling carrctl","",0);
+ carrctl(&ttraw, ttcarr == CAR_ON);
+ debug(F100,"ttopen carrctl ok","",0);
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef SVORPOSIX
+ ttraw.c_lflag &= ~ECHO;
+ ttold.c_lflag &= ~ECHO;
+#ifdef BSD44ORPOSIX
+ y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
+ debug(F101,"ttopen tcsetattr","",y);
+#else
+ y = ioctl(ttyfd, TCSETA, &ttraw);
+ debug(F100,"ttopen ioctl","",y);
+#endif /* BSD44ORPOSIX */
+
+#else /* BSD, etc */
+ ttraw.sg_flags &= ~ECHO;
+ ttold.sg_flags &= ~ECHO;
+#ifdef BELLV10
+ y = ioctl(ttyfd,TIOCSETP,&ttraw);
+ debug(F100,"ttopen ioctl","",y);
+#else
+ y = stty(ttyfd,&ttraw);
+ debug(F100,"ttopen stty","",y);
+#endif /* BELLV10 */
+#endif /* SVORPOSIX */
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+ /* ttflui(); */ /* This fails for some reason. */
+ }
+
+ /* Get current speed */
+
+#ifndef BEBOX
+ ttspeed = ttgspd();
+#else
+ ttspeed = 19200;
+#endif /* !BEBOX */
+ debug(F101,"ttopen ttspeed","",ttspeed);
+
+ /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
+
+ debug(F101,"ttopen ttyfd","",ttyfd);
+ debug(F101,"ttopen *lcl","",*lcl);
+ debug(F111,"ttopen lock file",flfnam,lkf);
+ signal(SIGINT,occt);
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+ gotsigs = 0;
+ return(0);
+}
+
+
+/* D O _ O P E N -- Do the right kind of open() call for the tty. */
+
+int
+do_open(ttname) char *ttname; {
+ int flags;
+
+#ifdef QNX6
+ /* O_NONBLOCK on /dev/tty makes open() fail */
+ return(priv_opn(ttname, O_RDWR |
+ (
+ ((int)strcmp(ttname,"/dev/tty") == 0) ?
+ 0 :
+ (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
+ )
+ );
+#else /* !QNX6 */
+
+#ifndef O_NDELAY /* O_NDELAY not defined */
+ return(priv_opn(ttname,2));
+#else /* O_NDELAY defined */
+
+#ifdef ATT7300
+/*
+ Open comms line without waiting for carrier so initial call does not hang
+ because state of "modem" is likely unknown at the initial call -jrd.
+ If this is needed for the getty stuff to work, and the open would not work
+ without O_NDELAY when getty is still on, then this special case is ok.
+ Otherwise, get rid of it. -ske
+*/
+ return(priv_opn(ttname, O_RDWR | O_NDELAY));
+
+#else /* !ATT7300 */
+
+ /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
+ flags = O_RDWR;
+ debug(F101,"do_open xlocal","",xlocal);
+ debug(F111,"do_open flags A",ttname,flags);
+ if (xlocal && (ttcarr != CAR_ON))
+ flags |= O_NDELAY;
+ debug(F111,"do_open flags B",ttname,flags);
+ return(priv_opn(ttname, flags));
+#endif /* !ATT7300 */
+#endif /* O_NDELAY */
+#endif /* QNX6 */
+}
+
+/* T T C L O S -- Close the TTY, releasing any lock. */
+
+static int ttc_state = 0; /* ttclose() state */
+static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
+
+int
+ttclos(foo) int foo; { /* Arg req'd for signal() prototype */
+ int xx, x = 0;
+ extern int exithangup;
+
+ debug(F101,"ttclos ttyfd","",ttyfd);
+ debug(F101,"ttclos netconn","",netconn);
+ debug(F101,"ttclos xlocal","",xlocal);
+#ifdef NOFDZERO
+ debug(F100,"ttclos NOFDZERO","",0);
+#endif /* NOFDZERO */
+
+#ifdef COMMENT
+#ifdef TTLEBUF
+ le_init(); /* No need for any of this */
+#endif /* TTLEBUF */
+#endif /* COMMENT */
+
+ if (ttyfd < 0) /* Wasn't open. */
+ return(0);
+
+ if (ttfdflg) /* If we inherited ttyfd from */
+ return(0); /* another process, don't close it. */
+
+ tvtflg = 0; /* (some day get rid of this...) */
+ gotsigs = 0;
+
+#ifdef IKSD
+ if (inserver) {
+#ifdef TNCODE
+ tn_push(); /* Place any waiting data into input*/
+ tn_sopt(DO,TELOPT_LOGOUT); /* Send LOGOUT option before close */
+ TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
+ tn_reset(); /* The Reset Telnet Option table. */
+#endif /* TNCODE */
+#ifdef CK_SSL
+ if (ssl_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
+ SSL_shutdown(ssl_con);
+ SSL_free(ssl_con);
+ ssl_con = NULL;
+ ssl_active_flag = 0;
+ }
+ if (tls_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
+ SSL_shutdown(tls_con);
+ SSL_free(tls_con);
+ tls_con = NULL;
+ tls_active_flag = 0;
+ }
+#endif /* CK_SSL */
+ }
+#endif /* IKSD */
+#ifdef NETCMD
+ if (ttpipe) { /* We've been using a pipe */
+ /* ttpipe = 0; */
+ if (ttpid > 0) {
+ int wstat;
+ int statusp;
+ close(fdin); /* Close these. */
+ close(fdout);
+ fdin = fdout = -1;
+ kill(ttpid,1); /* Kill fork with SIGHUP */
+ while (1) {
+ wstat = wait(&statusp);
+ if (wstat == ttpid || wstat == -1)
+ break;
+ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
+ }
+ ttpid = 0;
+ }
+ netconn = 0;
+ wasclosed = 1;
+ ttyfd = -1;
+ return(0);
+ }
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) {
+#ifndef NODOPTY
+ end_pty();
+#endif /* NODOPTY */
+ close(ttyfd);
+ netconn = 0;
+ wasclosed = 1;
+ ttpty = 0;
+ ttyfd = -1;
+ return(0);
+ }
+#endif /* NETPTY */
+
+#ifdef NETCONN
+ if (netconn) { /* If it's a network connection. */
+ debug(F100,"ttclos closing net","",0);
+ netclos(); /* Let the network module close it. */
+ netconn = 0; /* No more network connection. */
+ debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
+ return(0);
+ }
+#endif /* NETCONN */
+
+ if (xlocal) { /* We're closing a SET LINE device */
+#ifdef FT21 /* Fortune 2.1-specific items ... */
+ ioctl(ttyfd,TIOCHPCL, NULL);
+#endif /* FT21 */
+#ifdef ultrix /* Ultrix-specific items ... */
+#ifdef TIOCSINUSE
+ /* Unset the INUSE flag that we set in ttopen() */
+ ioctl(ttyfd, TIOCSINUSE, NULL);
+#endif /* TIOCSINUSE */
+ ioctl(ttyfd, TIOCNMODEM, &x);
+#ifdef COMMENT
+ /* What was this? */
+ ioctl(ttyfd, TIOCNCAR, NULL);
+#endif /* COMMENT */
+#endif /* ultrix */
+ }
+
+ /* This is to prevent us from sticking in tthang() or close(). */
+
+#ifdef O_NDELAY
+#ifndef aegis
+ if (ttyfd > 0) { /* But skip it on stdin. */
+ debug(F100,"ttclos setting O_NDELAY","",0);
+ x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
+#ifdef DEBUG
+ if (deblog && x == -1) {
+ perror("Warning - Can't set O_NDELAY");
+ debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
+ }
+#endif /* DEBUG */
+ }
+#endif /* aegis */
+#endif /* O_NDELAY */
+
+ x = 0;
+ ttc_state = 0;
+ if (xlocal
+#ifdef NOFDZERO
+ || ttyfd > 0
+#endif /* NOFDZERO */
+ ) {
+ saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
+ xx = alarm(8); /* Allow 8 seconds. */
+ debug(F101,"ttclos alarm","",xx);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer went off? */
+ x = -1;
+#ifdef DEBUG
+ debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
+ printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
+#endif /* DEBUG */
+ }
+ /* Hang up the device (drop DTR) */
+
+ errno = 0;
+ debug(F111,"ttclos A",ckitoa(x),ttc_state);
+ if (ttc_state < 1) {
+ ttc_state = 1;
+ debug(F101,"ttclos exithangup","",exithangup);
+ if (exithangup) {
+ alarm(8); /* Re-arm the timer */
+ debug(F101,"ttclos calling tthang()","",x);
+ x = tthang(); /* Hang up first, then... */
+ debug(F101,"ttclos tthang()","",x);
+ }
+#ifndef CK_NOHUPCL
+/*
+ Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
+ Suggested by Soewono Effendi.
+*/
+#ifdef HUPCL
+ else {
+ ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
+#ifdef BSD44ORPOSIX
+ tcsetattr(ttyfd,TCSANOW,&ttold);
+#else /* !BSD44ORPOSIX */
+#ifdef ATTSV
+ ioctl(ttyfd,TCSETAW,&ttold);
+#else /* !ATTSV */
+ stty(ttyfd,&ttold);
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ }
+#endif /* HUPCL */
+#endif /* CK_NOHUPCL */
+ }
+ /* Put back device modes as we found them */
+
+ errno = 0;
+ debug(F111,"ttclos B",ckitoa(x),ttc_state);
+ if (ttc_state < 2) {
+ ttc_state = 2;
+ /* Don't try to mess with tty modes if tthang failed() */
+ /* since it probably won't work. */
+ if (x > -1) {
+ debug(F101,"ttclos calling ttres()","",x);
+ signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
+ alarm(8); /* Re-arm the timer */
+ x = ttres(); /* Reset device modes. */
+ debug(F101,"ttclos ttres()","",x);
+ alarm(0);
+ }
+ }
+ /* Close the device */
+
+ errno = 0;
+ debug(F101,"ttclos C","",ttc_state);
+ if (ttc_state < 3) {
+ ttc_state = 3;
+ errno = 0;
+ debug(F101,"ttclos calling close","",x);
+ signal(SIGALRM,xtimerh); /* Re-enable alarm. */
+ alarm(8); /* Re-arm the timer */
+ x = close(ttyfd); /* Close the device. */
+ debug(F101,"ttclos close()","",x);
+ if (x > -1)
+ ttc_state = 3;
+ }
+ debug(F101,"ttclos D","",ttc_state);
+ ttimoff(); /* Turn off timer. */
+ if (x < 0) {
+ printf("?WARNING - close failed: %s\n",ttnmsv);
+#ifdef DEBUG
+ if (deblog) {
+ printf("errno = %d\n", errno);
+ debug(F101,"ttclos failed","",errno);
+ }
+#endif /* DEBUG */
+ }
+ /* Unlock after closing but before any getty mumbo jumbo */
+
+ debug(F100,"ttclos about to call ttunlck","",0);
+ if (ttunlck()) /* Release uucp-style lock */
+ fprintf(stderr,"Warning, problem releasing lock\r\n");
+ }
+
+/* For bidirectional lines, restore getty if it was there before. */
+
+#ifdef ACUCNTRL /* 4.3BSD acucntrl() method. */
+ if (xlocal) {
+ debug(F100,"ttclos ACUCNTRL","",0);
+ acucntrl("enable",ttnmsv); /* Enable getty on the device. */
+ }
+#else
+#ifdef ATT7300 /* ATT UNIX PC (3B1, 7300) method. */
+ if (xlocal) {
+ debug(F100,"ttclos ATT7300 ongetty","",0);
+ if (attmodem & DOGETY) /* Was getty(1m) running before us? */
+ ongetty(ttnmsv); /* Yes, restart getty on tty line */
+ attmodem &= ~DOGETY; /* No phone in use, getty restored */
+ }
+#endif /* ATT7300 */
+#endif /* System-dependent getty-restoring methods */
+
+#ifdef sony_news
+ km_ext = -1; /* Invalidate device's Kanji-mode */
+#endif /* sony_news */
+
+ ttyfd = -1; /* Invalidate the file descriptor. */
+ wasclosed = 1;
+ debug(F100,"ttclos done","",0);
+ return(0);
+}
+
+/* T T H A N G -- Hangup phone line or network connection. */
+/*
+ Returns:
+ 0 if it does nothing.
+ 1 if it believes that it hung up successfully.
+ -1 if it believes that the hangup attempt failed.
+*/
+
+#define HUPTIME 500 /* Milliseconds for hangup */
+
+#ifdef COMMENT
+/* The following didn't work but TIOCSDTR does work */
+#ifdef UNIXWARE
+/* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
+#ifndef POSIX /* Such as Unixware 1.x, 2.x */
+#ifndef HUP_POSIX
+#define HUP_POSIX
+#endif /* HUP_POSIX */
+#endif /* POSIX */
+#endif /* UNIXWARE */
+#endif /* COMMENT */
+
+#ifndef USE_TIOCSDTR
+#ifdef __NetBSD__
+/* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
+#ifdef TIOCSDTR
+#ifdef TIOCCDTR
+#define USE_TIOCSDTR
+#endif /* TIOCCDTR */
+#endif /* TIOCSDTR */
+#endif /* __NetBSD__ */
+#endif /* USE_TIOCSDTR */
+
+#ifndef HUP_CLOSE_POSIX
+#ifdef OU8
+#define HUP_CLOSE_POSIX
+#else
+#ifdef CK_SCOV5
+#define HUP_CLOSE_POSIX
+#endif /* CK_SCOV5 */
+#endif /* OU8 */
+#endif /* HUP_CLOSE_POSIX */
+
+#ifdef NO_HUP_CLOSE_POSIX
+#ifdef HUP_CLOSE_POSIX
+#undef HUP_CLOSE_POSIX
+#endif /* HUP_CLOSE_POSIX */
+#endif /* NO_HUP_CLOSE_POSIX */
+
+int
+tthang() {
+#ifdef NOLOCAL
+ return(0);
+#else
+ int x = 0; /* Sometimes used as return code. */
+#ifndef POSIX
+ int z; /* worker */
+#endif /* POSIX */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef SVORPOSIX /* AT&T, POSIX, HPUX declarations. */
+ int spdsav; /* for saving speed */
+#ifdef HUP_POSIX
+ int spdsavi;
+#else
+#ifdef BSD44ORPOSIX
+ int spdsavi;
+#endif /* BSD44ORPOSIX */
+#endif /* HUP_POSIX */
+#ifdef HPUX
+/*
+ Early versions of HP-UX omitted the mflag typedef. If you get complaints
+ about it, just change it to long (or better still, unsigned long).
+*/
+ mflag
+ dtr_down = 00000000000,
+ modem_rtn,
+ modem_sav;
+ char modem_state[64];
+#endif /* HPUX */
+ int flags; /* fcntl flags */
+ unsigned short ttc_save;
+#endif /* SVORPOSIX */
+
+ if (ttyfd < 0) return(0); /* Don't do this if not open */
+ if (xlocal < 1) return(0); /* Don't do this if not local */
+
+#ifdef NETCMD
+ if (ttpipe)
+ return((ttclos(0) < 0) ? -1 : 1);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty)
+ return((ttclos(0) < 0) ? -1 : 1);
+#endif /* NETPTY */
+#ifdef NETCONN
+ if (netconn) { /* Network connection. */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = tnc_set_dtr_state(0);
+ if (rc >= 0) {
+ msleep(HUPTIME);
+ rc = tnc_set_dtr_state(1);
+ }
+ return(rc >= 0 ? 1 : -1);
+ } else
+#endif /* TN_COMPORT */
+ return((netclos() < 0) ? -1 : 1); /* Just close it. */
+ }
+#endif /* NETCONN */
+
+/* From here down, we handle real tty devices. */
+#ifdef HUP_POSIX
+/*
+ e.g. for Unixware 2, where we don't have a full POSIX build, we
+ still have to use POSIX-style hangup. Thus the duplication of this
+ and the next case, the only difference being we use a local termios
+ struct here, since a different model is used elsewhere.
+
+ NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
+ even though it compiles and executes without error, doesn't actually
+ work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
+*/
+ {
+ struct termios ttcur;
+ int x;
+ debug(F100,"tthang HUP_POSIX style","",0);
+ x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */
+ debug(F111,"tthang tcgetattr",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ spdsav = cfgetospeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
+ spdsavi = cfgetispeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
+ x = cfsetospeed(&ttcur,B0); /* Replace by 0 */
+ debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = cfsetispeed(&ttcur,B0);
+ debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ msleep(HUPTIME); /* Sleep 0.5 sec */
+ x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
+ if (x < 0) return(-1);
+ debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
+ x = cfsetispeed(&ttcur,spdsavi);
+ debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ return(1);
+ }
+#else
+#ifdef BSD44ORPOSIX
+#ifdef QNX
+ {
+ int x;
+ x = tcdropline(ttyfd,500);
+ debug(F101,"tthang QNX tcdropline","",x);
+ ttcur.c_cflag |= CLOCAL;
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F101,"tthang QNX tcsetattr restore","",x);
+ if (x < 0) {
+ debug(F101,"tthang QNX tcsetattr restore errno","",errno);
+ return(-1);
+ }
+ /* Fix flags - ensure O_NONBLOCK is off */
+
+ errno = 0;
+ debug(F101,"tthang QNX iniflags","",iniflags);
+ if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
+ debug(F101,"tthang QNX F_SETFL errno","",errno);
+ return(-1);
+ }
+ return(x);
+ }
+#else /* QNX */
+ {
+ int x;
+#ifdef USE_TIOCSDTR
+ debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
+ errno = 0;
+ x = ioctl(ttyfd, TIOCCDTR, NULL);
+ debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ msleep(HUPTIME); /* Sleep 0.5 sec */
+ errno = 0;
+ x = ioctl(ttyfd, TIOCSDTR, NULL);
+ debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
+ if (x < 0) return(-1);
+#else /* USE_TIOCSDTR */
+
+#ifdef HUP_CLOSE_POSIX
+/*
+ In OSR5 versions where TIOCSDTR is not defined (up to and including at
+ least 5.0.6a) the POSIX APIs in the "#else" part below are available but
+ don't work, and no other APIs are available that do work. In this case
+ we have to drop DTR by brute force: close and reopen the port. This
+ code actually works, but all the steps are crucial: setting CLOCAL, the
+ O_NDELAY manipulations, etc.
+*/
+ debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
+ debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
+ debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
+ errno = 0;
+ x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */
+ debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
+ if (x < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
+ return(-1);
+ }
+ errno = 0;
+
+ x = close(ttyfd); /* Close without releasing lock */
+ if (x < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
+ return(-1);
+ }
+ errno = 0;
+ x = msleep(500); /* Pause half a second */
+ if (x < 0) { /* Or if that doesn't work, 1 sec */
+ debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
+ sleep(1);
+ }
+ errno = 0;
+ ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
+ debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
+ if (ttyfd < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
+ return(-1);
+ }
+ debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
+
+ /* Restore previous attributes */
+
+ errno = 0;
+ tvtflg = 0;
+ ttcur.c_cflag |= CLOCAL;
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
+ if (x < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
+ "",errno);
+ return(-1);
+ }
+ /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
+
+ errno = 0;
+ if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
+ debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
+ return(-1);
+ }
+ debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
+ errno = 0;
+ x &= ~(O_NONBLOCK|O_NDELAY);
+ debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
+ debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
+ if (fcntl(ttyfd, F_SETFL, x) == -1) {
+ debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
+ return(-1);
+ }
+#ifdef DEBUG
+ if (deblog) {
+ if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
+ debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
+ debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
+ "",x&O_NONBLOCK);
+ debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
+ "",x&O_NDELAY);
+ }
+ }
+#endif /* DEBUG */
+
+#else /* HUP_CLOSE_POSIX */
+
+ /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
+
+ debug(F100,"tthang BSD44ORPOSIX B0","",0);
+ x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */
+ debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ spdsav = cfgetospeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
+ spdsavi = cfgetispeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
+ x = cfsetospeed(&ttcur,B0); /* Replace by 0 */
+ debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = cfsetispeed(&ttcur,B0);
+ debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ msleep(HUPTIME); /* Sleep 0.5 sec */
+ debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
+ x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
+ debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
+ x = cfsetispeed(&ttcur,spdsavi);
+ debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ ttcur.c_cflag |= CLOCAL; /* Don't expect CD after hangup */
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
+ if (x < 0) return(-1);
+
+#endif /* HUP_CLOSE_POSIX */
+#endif /* USE_TIOCSDTR */
+
+ return(1);
+ }
+
+#endif /* QNX */
+#else /* BSD44ORPOSIX */
+
+#ifdef aegis /* Apollo Aegis */
+ sio_$control((short)ttyfd, sio_$dtr, false, st); /* DTR down */
+ msleep(HUPTIME); /* pause */
+ sio_$control((short)ttyfd, sio_$dtr, true, st); /* DTR up */
+ return(1);
+#endif /* aegis */
+
+#ifdef ANYBSD /* Any BSD version. */
+#ifdef TIOCCDTR /* Except those that don't have this */
+ debug(F100,"tthang BSD style","",0);
+ if (ioctl(ttyfd,TIOCCDTR,0) < 0) { /* Clear DTR. */
+ debug(F101,"tthang TIOCCDTR fails","",errno);
+ return(-1);
+ }
+ msleep(HUPTIME); /* For about 1/2 sec */
+ errno = 0;
+ x = ioctl(ttyfd,TIOCSDTR,0); /* Restore DTR */
+ if (x < 0) {
+ /*
+ For some reason, this tends to fail with "no such device or address"
+ but the operation still works, probably because of the close/open
+ later on. So let's not scare the user unnecessarily here.
+ */
+ debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
+ x = 1; /* Pretend we succeeded */
+ } else if (x == 0) x = 1; /* Success */
+#ifdef COMMENT
+#ifdef FT21
+ ioctl(ttyfd, TIOCSAVEMODES, 0);
+ ioctl(ttyfd, TIOCHPCL, 0);
+ close(ttyfd); /* Yes, must do this twice */
+ if ((ttyfd = open(ttnmsv,2)) < 0) /* on Fortune computers... */
+ return(-1); /* (but why?) */
+ else x = 1;
+#endif /* FT21 */
+#endif /* COMMENT */
+#endif /* TIOCCDTR */
+ close(do_open(ttnmsv)); /* Clear i/o error condition */
+ errno = 0;
+#ifdef COMMENT
+/* This is definitely dangerous. Why was it here? */
+ z = ttvt(ttspeed,ttflow); /* Restore modes. */
+ debug(F101,"tthang ttvt returns","",z);
+ return(z < 0 ? -1 : 1);
+#else
+ return(x);
+#endif /* COMMENT */
+#endif /* ANYBSD */
+
+#ifdef ATTSV
+/* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
+
+#ifdef HPUX
+/* Hewlett Packard allows explicit manipulation of modem signals. */
+
+#ifdef COMMENT
+/* Old way... */
+ debug(F100,"tthang HP-UX style","",0);
+ if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0) /* lower DTR */
+ return(-1); /* oops, can't. */
+ msleep(HUPTIME); /* Pause half a second. */
+ x = 1; /* Set return code */
+ if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
+ if ((modem_rtn & MDCD) != 0) /* Check if CD is low. */
+ x = -1; /* CD didn't drop, fail. */
+ } else x = -1;
+
+ /* Even if above calls fail, RTS & DTR should be turned back on. */
+ modem_rtn = MRTS | MDTR;
+ if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
+ return(x);
+#else
+/* New way, from Hellmuth Michaelis */
+ debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
+ if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
+ debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
+ return(-1);
+ }
+ sprintf(modem_state,"%#lx",modem_rtn);
+ debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
+ modem_sav = modem_rtn; /* Save current modem signals */
+ modem_rtn &= ~MDTR; /* Turn DTR bit off */
+ sprintf(modem_state,"%#lx",modem_rtn);
+ debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
+ if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
+ debug(F100,"tthang HP-UX: can't lower DTR!","",0);
+ return(-1); /* oops, can't. */
+ }
+ msleep(HUPTIME); /* Pause half a second. */
+ x = 1; /* Set return code */
+ if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
+ sprintf(modem_state,"%#lx",modem_rtn);
+ debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
+ if ((modem_rtn & MDCD) != 0) { /* Check if CD is low. */
+ debug(F100,"tthang HP-UX: DCD not down","",0);
+ x = -1; /* CD didn't drop, fail. */
+ } else {
+ debug(F100,"tthang HP-UX: DCD down","",0);
+ }
+ } else {
+ x = -1;
+ debug(F100,"tthang HP-UX: can't get DCD status !","",0);
+ }
+
+ /* Even if above calls fail, DTR should be turned back on. */
+
+ modem_sav |= MDTR;
+ if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
+ x = -1;
+ debug(F100,"tthang HP-UX: can't set saved state","",0);
+ } else {
+ sprintf(modem_state,"%#lx",modem_sav);
+ debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
+ }
+ return(x);
+#endif /* COMMENT */
+
+#else /* AT&T but not HP-UX */
+
+/* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
+/* It is not known how many, if any, systems actually implement them, */
+/* so we include them here in ifdef's. */
+
+/*
+ Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
+ gives error 22 (invalid argument).
+*/
+#ifndef _IBMR2
+/*
+ No modem-signal twiddling for IBM RT PC or RS/6000.
+ In AIX 3.1 and earlier, the ioctl() call is broken.
+ This code could be activated for AIX 3.1 with PTF 2006 or later
+ (e.g. AIX 3.2), but close/open does the job too, so why bother.
+*/
+#ifdef TIOCMBIS /* Bit Set */
+#ifdef TIOCMBIC /* Bit Clear */
+#ifdef TIOCM_DTR /* DTR */
+
+/* Clear DTR, sleep 300 msec, turn it back on. */
+/* If any of the ioctl's return failure, go on to the next section. */
+
+ z = TIOCM_DTR; /* Code for DTR. */
+#ifdef COMMENT
+/*
+ This was the cause of the troubles with the Solaris Port Monitor.
+ The problem is: RTS never comes back on. Moral: Don't do it!
+ (But why doesn't it come back on? See the TIOCMBIS call...)
+*/
+#ifdef TIOCM_RTS /* Lower RTS too if symbol is known. */
+ z |= TIOCM_RTS;
+#endif /* TIOCM_RTS */
+#endif /* COMMENT */
+
+ debug(F101,"tthang TIOCM signal mask","",z);
+ if (ioctl(ttyfd,TIOCMBIC,&z) > -1) { /* Try to lower DTR. */
+ debug(F100,"tthang TIOCMBIC ok","",0);
+ msleep(HUPTIME); /* Pause half a second. */
+ if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
+ debug(F100,"tthang TIOCMBIS ok","",0);
+#ifndef CLSOPN
+ return(1); /* Success, done. */
+#endif /* CLSOPN */
+ } else { /* Couldn't raise, continue. */
+ debug(F101,"tthang TIOCMBIS errno","",errno);
+ }
+ } else { /* Couldn't lower, continue. */
+ debug(F101,"tthang TIOCMBIC errno","",errno);
+ }
+#endif /* TIOCM_DTR */
+#endif /* TIOCMBIC */
+#endif /* TIOCMBIS */
+#endif /* _IBMR2 */
+
+/*
+ General AT&T UNIX case, not HPUX. The following code is highly suspect. No
+ two AT&T-based systems seem to do this the same way. The object is simply
+ to turn off DTR and then turn it back on. SVID says the universal method
+ for turning off DTR is to set the speed to zero, and this does seem to do
+ the trick in all cases. But neither SVID nor any known man pages say how to
+ turn DTR back on again. Some variants, like most Xenix implementations,
+ raise DTR again when the speed is restored to a nonzero value. Others
+ require the device to be closed and opened again, but this is risky because
+ getty could seize the device during the instant it is closed.
+*/
+
+/* Return code for ioctl failures... */
+#ifdef ATT6300
+ x = 1; /* ATT6300 doesn't want to fail... */
+#else
+ x = -1;
+#endif /* ATT6300 */
+
+ debug(F100,"tthang get settings","",0);
+ if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
+ return(x); /* Fail if this doesn't work. */
+ if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
+ return(x);
+ ttc_save = ttcur.c_cflag; /* Remember current speed. */
+ spdsav = ttc_save & CBAUD;
+ debug(F101,"tthang speed","",spdsav);
+
+#ifdef O_NDELAY
+ debug(F100,"tthang turning O_NDELAY on","",0);
+ fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
+#endif /* O_NDELAY */
+
+#ifdef ATT7300 /* This is the way it is SUPPOSED to work */
+ ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */
+#else
+#ifdef RTAIX
+ ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */
+#else /* This way really works but may be dangerous */
+#ifdef u3b2
+ ttcur.c_cflag = ~(CBAUD|CLOCAL); /* Special for AT&T 3B2s */
+ /* (CLOCAL must be OFF) */
+#else
+#ifdef SCO3R2 /* SCO UNIX 3.2 */
+/*
+ This is complete nonsense, but an SCO user claimed this change made
+ hanging up work. Comments from other SCO UNIX 3.2 users would be
+ appreciated.
+*/
+ ttcur.c_cflag = CBAUD|B0;
+#else
+#ifdef AIXRS /* AIX on RS/6000 */
+/*
+ Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
+ even though you can do it on the built-in port and the 8- and 16-port
+ adapters. (Untested on 128-port adapter.)
+*/
+ ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
+#else /* None of the above */
+/*
+ Set everything, including the speed, to zero, except for the CLOCAL
+ and HUPCL bits.
+*/
+ ttcur.c_cflag = CLOCAL|HUPCL;
+#endif /* AIXRS */
+#endif /* SCO3R2 */
+#endif /* u3b2 */
+#endif /* RTAIX */
+#endif /* ATT7300 */
+
+#ifdef COMMENT
+ /* and if none of those work, try one of these... */
+ ttcur.c_cflag = 0;
+ ttcur.c_cflag = CLOCAL;
+ ttcur.c_cflag &= ~(CBAUD|HUPCL);
+ ttcur.c_cflag &= ~(CBAUD|CREAD);
+ ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
+ /* or other combinations */
+#endif /* COMMENT */
+
+#ifdef TCXONC
+ debug(F100,"tthang TCXONC","",0);
+ if (ioctl(ttyfd, TCXONC, 1) < 0) {
+ debug(F101,"tthang TCXONC failed","",errno);
+ }
+#endif /* TCXONC */
+
+#ifdef TIOCSTART
+ debug(F100,"tthang TIOCSTART","",0);
+ if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
+ debug(F101,"tthang TIOCSTART failed","",errno);
+ }
+#endif /* TIOCSTART */
+
+ if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
+ debug(F101,"tthang TCSETAF failed","",errno);
+ fcntl(ttyfd, F_SETFL, flags); /* Restore flags */
+ return(-1); /* before returning. */
+ }
+ msleep(300); /* Give modem time to notice. */
+
+#ifndef NOCOTFMC
+
+/* Now, even though it doesn't say this in SVID or any man page, we have */
+/* to close and reopen the device. This is not necessary for all systems, */
+/* but it's impossible to predict which ones need it and which ones don't. */
+
+#ifdef ATT7300
+/*
+ Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
+ related ioctl's for their internal modems. attmodem has getty status and
+ modem-in-use bit. Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
+ but also ruins the file descriptor, and no other phone(7) ioctl call can fix
+ it. Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
+ The only way to undo the damage is to close the fd and then reopen it.
+*/
+ if (attmodem & ISMODEM) {
+ debug(F100,"tthang attmodem close/open","",0);
+ ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
+ ioctl(ttyfd,PIOCDISC,&dialer); /* Disconnect phone. */
+ close(ttyfd); /* Close and reopen the fd. */
+ ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
+ attmodem &= ~ISMODEM; /* Phone no longer in use. */
+ }
+#else /* !ATT7300 */
+/* It seems we have to close and open the device for other AT&T systems */
+/* too, and this is the place to do it. The following code does the */
+/* famous close(open(...)) magic by default. If that doesn't work for you, */
+/* then try uncommenting the following statement or putting -DCLSOPN in */
+/* the makefile CFLAGS. */
+
+/* #define CLSOPN */
+
+#ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
+
+#ifdef O_NDELAY
+#define OPENFLGS O_RDWR | O_NDELAY
+#else
+#define OPENFLGS O_RDWR
+#endif
+
+#ifndef CLSOPN
+/* This method is used by default, i.e. unless CLSOPN is defined. */
+/* It is thought to be safer because there is no window where getty */
+/* can seize control of the device. The drawback is that it might not work. */
+
+ debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
+ close(priv_opn(ttnmsv, OPENFLGS));
+
+#else
+/* This method is used if you #define CLSOPN. It is more likely to work */
+/* than the previous method, but it's also more dangerous. */
+
+ debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
+ close(ttyfd);
+ msleep(10);
+ ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
+#endif /* CLSOPN */
+#undef OPENFLGS
+
+#endif /* SCO32 */
+#endif /* ATT7300 */
+
+#endif /* NOCOTFMC */
+
+/* Now put all flags & modes back the way we found them. */
+/* (Does the order of ioctl & fcntl matter ? ) */
+
+ debug(F100,"tthang restore settings","",0);
+ ttcur.c_cflag = ttc_save; /* Get old speed back. */
+ if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
+ return(-1);
+#ifdef O_NDELAY
+/*
+ This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
+ After closing a modem line, the modem will probably not be asserting
+ carrier any more, so we should not require carrier any more. If this
+ causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
+ than O_NDELAY.
+*/
+ flags &= ~O_NDELAY; /* Don't require carrier on reopen */
+#endif /* O_NDELAY */
+ if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
+ return(-1);
+
+ return(1);
+#endif /* not HPUX */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#endif /* HUP_POSIX */
+#endif /* NOLOCAL */
+}
+
+/*
+ Major change in 5A(174). We used to use LPASS8, if it was defined, to
+ allow 8-bit data and Xon/Xoff flow control at the same time. But this
+ LPASS8 business seems to have been causing trouble for everybody but me!
+ For example, Annex terminal servers, commonly used with Encore computers,
+ do not support LPASS8 even though the Encore itself does. Ditto for many
+ other terminal servers, TELNET connections, rlogin connections, etc etc.
+ Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
+ serial lines, even though LPASS8 is a feature of 4.3BSD. So let's turn it
+ off for everybody. That means we goes back to using raw mode, with no
+ flow control. Phooey.
+
+ NOTE: This must be done before the first reference to LPASS8 in this file,
+ and after the last #include statment.
+*/
+#ifdef LPASS8
+#undef LPASS8
+#endif /* LPASS8 */
+
+/* T T R E S -- Restore terminal to "normal" mode. */
+
+/* ske@pkmab.se: There are two choices for what this function should do.
+ * (1) Restore the tty to current "normal" mode, with carrier treatment
+ * according to ttcarr, to be used after every kermit command. (2) Restore
+ * the tty to the state it was in before kermit opened it. These choices
+ * conflict, since ttold can't hold both choices of tty parameters. ttres()
+ * is currently being called as in choice (1), but ttold basically holds
+ * the initial parameters, as in (2), and the description at the beginning
+ * of this file says (2).
+ *
+ * I don't think restoring tty parameters after all kermit commands makes
+ * much of a difference. Restoring them upon exit from kermit may be of
+ * some use in some cases (when the line is not restored automatically on
+ * close, by the operating system).
+ *
+ * I can't choose which one it should be, so I haven't changed it. It
+ * probably works as it is, too. It would probably even work even with
+ * ttres() entirely deleted...
+ *
+ * (from fdc: Actually, this function operates in remote mode too, so
+ * it restores the console (command) terminal to whatever mode it was
+ * in before packet operations began, so that commands work right again.)
+ */
+int
+ttres() { /* Restore the tty to normal. */
+ int x;
+
+ if (ttyfd < 0) return(-1); /* Not open. */
+
+ if (ttfdflg) return(0); /* Don't mess with terminal modes if */
+ /* we got ttyfd from another process */
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+ tvtflg = 0;
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+ {
+ extern int tcp_nodelay; /* Just put this back if necessary */
+ if (ttnet == NET_TCPB) {
+ if (nodelay_sav > -1) {
+ no_delay(ttyfd,nodelay_sav);
+ nodelay_sav = -1;
+ }
+ }
+ }
+#endif /* TCP_NODELAY */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = -1;
+ if ((rc = tnsetflow(ttflow)) < 0)
+ return(rc);
+ if (ttspeed <= 0)
+ ttspeed = tnc_get_baud();
+ else if ((rc = tnc_set_baud(ttspeed)) < 0)
+ return(rc);
+ tnc_set_datasize(8);
+ tnc_set_stopsize(stopbits);
+
+#ifdef HWPARITY
+ if (hwparity) {
+ switch (hwparity) {
+ case 'e': /* Even */
+ debug(F100,"ttres 8 bits + even parity","",0);
+ tnc_set_parity(3);
+ break;
+ case 'o': /* Odd */
+ debug(F100,"ttres 8 bits + odd parity","",0);
+ tnc_set_parity(2);
+ break;
+ case 'm': /* Mark */
+ debug(F100,"ttres 8 bits + invalid parity: mark","",0);
+ tnc_set_parity(4);
+ break;
+ case 's': /* Space */
+ debug(F100,"ttres 8 bits + invalid parity: space","",0);
+ tnc_set_parity(5);
+ break;
+ }
+ } else
+#endif /* HWPARITY */
+ {
+ tnc_set_parity(1); /* None */
+ }
+ tvtflg = 0;
+ return(0);
+ }
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+ return(0);
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+/* Real terminal device, so restore its original modes */
+
+#ifdef BSD44ORPOSIX /* For POSIX like this */
+ debug(F100,"ttres BSD44ORPOSIX","",0);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
+#else /* For all others... */
+#ifdef ATTSV /* For AT&T versions... */
+ debug(F100,"ttres ATTSV","",0);
+ x = ioctl(ttyfd,TCSETAW,&ttold); /* Restore tty modes this way. */
+#else
+/* Here we restore the modes for BSD */
+
+#ifdef LPASS8 /* Undo "pass8" if it were done */
+ if (lmodef) {
+ if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
+ debug(F100,"ttres TIOCLSET failed","",0);
+ else
+ debug(F100,"ttres TIOCLSET ok","",0);
+ }
+#endif /* LPASS8 */
+
+#ifdef CK_DTRCTS /* Undo hardware flow if it were done */
+ if (lmodef) {
+ if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
+ debug(F100,"ttres TIOCLSET failed","",0);
+ else
+ debug(F100,"ttres TIOCLSET ok","",0);
+ }
+#endif /* CK_DTRCTS */
+
+#ifdef TIOCGETC /* Put back special characters */
+ if (tcharf && (xlocal == 0)) {
+ if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
+ debug(F100,"ttres TIOCSETC failed","",0);
+ else
+ debug(F100,"ttres TIOCSETC ok","",0);
+ }
+#endif /* TIOCGETC */
+
+#ifdef TIOCGLTC /* Put back local special characters */
+ if (ltcharf && (xlocal == 0)) {
+ if (ioctl(ttyfd,TIOCSLTC,<chold) < 0)
+ debug(F100,"ttres TIOCSLTC failed","",0);
+ else
+ debug(F100,"ttres TIOCSLTC ok","",0);
+ }
+#endif /* TIOCGLTC */
+
+#ifdef BELLV10
+ debug(F100,"ttres BELLV10","",0);
+ x = ioctl(ttyfd,TIOCSETP,&ttold); /* Restore both structs */
+ x = ioctl(ttyfd,TIOCSDEV,&tdold);
+#else
+ debug(F100,"ttres stty","",0);
+ x = stty(ttyfd,&ttold); /* Restore tty modes the old way. */
+#endif /* BELLV10 */
+
+ if (!xlocal)
+ msleep(100); /* This replaces sleep(1)... */
+ /* Put back sleep(1) if tty is */
+ /* messed up after close. */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+ debug(F101,"ttres result","",x);
+#ifndef QNX
+ if (x < 0) debug(F101,"ttres errno","",errno);
+#endif /* QNX */
+
+#ifdef AIXRS
+#ifndef AIX41
+ x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
+ debug(F101,"ttres AIX line discipline rts restore","",x);
+#endif /* AIX41 */
+#endif /* AIXRS */
+
+#ifdef BSD41
+ if (ttld > -1) { /* Put back line discipline */
+ x = ioctl(ttyfd, TIOCSETD, &ttld);
+ debug(F101,"ttres BSD41 line discipline restore","",x);
+ if (x < 0) debug(F101,"...ioctl errno","",errno);
+ ttld = -1;
+ }
+#endif /* BSD41 */
+
+#ifdef sony_news
+ x = xlocal ? km_ext : km_con; /* Restore Kanji mode. */
+ if (x != -1) { /* Make sure we know original modes. */
+ if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
+ perror("ttres can't set Kanji mode");
+ debug(F101,"ttres error setting Kanji mode","",x);
+ return(-1);
+ }
+ }
+ debug(F100,"ttres set Kanji mode ok","",0);
+#endif /* sony_news */
+
+ tvtflg = 0; /* Invalidate terminal mode settings */
+ debug(F101,"ttres return code","",x);
+ return(x);
+}
+
+#ifndef NOUUCP
+
+/* T T C H K P I D -- Check lockfile pid */
+/*
+ Read pid from lockfile named f, check that it's still valid.
+ If so, return 1.
+ On failure to read pid, return 1.
+ Otherwise, try to delete lockfile f and return 0 if successful, else 1.
+*/
+static int
+ttchkpid(f) char *f; {
+ int pid, mypid, x;
+ pid = ttrpid(f); /* Read pid from file. */
+ if (pid > -1) { /* If we were able to read the pid.. */
+ debug(F101,"ttchkpid lock pid","",pid);
+ errno = 0; /* See if process still exists. */
+ mypid = (int)getpid(); /* Get my own pid. */
+ debug(F101,"ttchkpid my pid","",mypid);
+ if (pid == mypid) { /* It's me! */
+ x = -1; /* So I can delete it */
+ errno = ESRCH; /* pretend it's invalid */
+ } else { /* It's not me */
+ x = kill((PID_T)pid, 0); /* See if it's a live process */
+ debug(F101,"ttchkpid kill errno","",errno);
+ }
+ debug(F101,"ttchkpid pid test","",x);
+ if (x < 0 && errno == ESRCH) { /* pid is invalid */
+ debug(F111,"removing stale lock",f,pid);
+ if (!backgrd)
+ printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
+ priv_on();
+ x = unlink(f); /* Remove the lockfile. */
+ priv_off();
+ debug(F111,"ttchkpid unlink",f,x);
+ if (x > -1)
+ return(0); /* Device is not locked after all */
+ else if (!backgrd)
+ perror(f);
+ }
+ return(1);
+ }
+ return(1); /* Failure to read pid */
+}
+
+#ifdef HPUX
+
+/* Aliases (different drivers) for HP-UX dialout devices: */
+
+static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
+static int ttydexists = 0;
+
+#endif /* HPUX */
+
+/* T T R P I D -- Read pid from lockfile "name" */
+
+static int
+ttrpid(name) char *name; {
+ long len;
+ int x, fd, pid;
+ short spid;
+ char buf[32];
+
+ debug(F110,"ttrpid",name,0);
+ if (!name) return(-1);
+ if (!*name) return(-1);
+ priv_on();
+ len = zchki(name); /* Get file length */
+ priv_off();
+ debug(F101,"ttrpid zchki","",len);
+ if (len < 0)
+ return(-1);
+ if (len > 31)
+ return(-1);
+ priv_on();
+ fd = open(name,O_RDONLY); /* Try to open lockfile. */
+ priv_off();
+ debug(F101,"ttrpid fd","",fd);
+ if (fd <= 0)
+ return(-1);
+/*
+ Here we try to be flexible and allow for all different binary and string
+ formats at runtime, rather than a specific format for each configuration
+ hardwired at compile time.
+*/
+ pid = -1;
+#ifndef COHERENT
+/*
+ COHERENT uses a string PID but without leading spaces or 0's, so there is
+ no way to tell from the file's length whether it contains a string or binary
+ pid. So for COHERENT only, we only allow string pids. For all others, we
+ decide based on the size of the lockfile.
+*/
+ if (len > 4) { /* If file > 4 bytes it's a string */
+#endif /* COHERENT */
+ x = read(fd,buf,(int)len);
+ debug(F111,"ttrpid string read",buf,x);
+ if (x < 0) {
+ pid = -1;
+ } else {
+ buf[31] = '\0';
+ x = sscanf(buf,"%d",&pid); /* Get the integer pid from it. */
+ }
+#ifndef COHERENT
+ } else if (len == 4) { /* 4 bytes so binary */
+ x = read(fd, (char *)&pid, 4); /* Read the bytes into an int */
+ debug(F101,"ttrpid integer read","",x);
+ if (x < 4)
+ pid = -1;
+ } else if (len == 2) { /* 2 bytes binary */
+ x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
+ debug(F101,"ttrpid short read","",x);
+ if (x < 2)
+ pid = -1;
+ else
+ pid = spid;
+ } else
+ pid = -1;
+#endif /* COHERENT */
+ close(fd); /* Close the lockfile */
+ debug(F101,"ttrpid pid","",pid);
+ return(pid);
+}
+#endif /* NOUUCP */
+
+/* T T L O C K */
+
+/*
+ This function attempts to coordinate use of the communication device with
+ other copies of Kermit and any other program that follows the UUCP
+ device-locking conventions, which, unfortunately, vary among different UNIX
+ implementations. The idea is to look for a file of a certain name, the
+ "lockfile", in a certain directory. If such a file is found, then the line
+ is presumed to be in use, and Kermit should not use it. If no such file is
+ found, Kermit attempts to create one so that other programs will not use the
+ same line at the same time. Because the lockfile and/or the directory it's
+ in might lack write permission for the person running Kermit, Kermit could
+ find itself running setuid to uucp or other user that does have the
+ necessary permissions. At startup, Kermit has changed its effective uid to
+ the user's real uid, and so ttlock() must switch back to the original
+ effective uid in order to create the lockfile, and then back again to the
+ real uid to prevent unauthorized access to other directories or files owned
+ by the user the program is setuid to.
+
+ Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
+ based on suggestions from Warren Tucker. Call with pointer to name of
+ tty device. Returns:
+
+ 0 on success
+ -1 on failure
+
+ Note: Once privileges are turned on using priv_on(), it is essential that
+ they are turned off again before this function returns.
+*/
+#ifdef SVR4 /* Lockfile uses device numbers. */
+/*
+ Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
+ it is the behavior of the "reference version" of SVR4, i.e. the Intel
+ port from UNIX Systems Laboratories, then called Univel UnixWare,
+ then called Novell UnixWare, then called SCO Unixware, then called Caldera
+ Open UNIX... It also makes much more sense than device-name-based lockfiles
+ since there can be multiple names for the same device, symlinks, etc.
+*/
+#ifndef NOLFDEVNO
+#ifndef LFDEVNO /* Define this for SVR4 */
+#ifndef AIXRS /* But not for RS/6000 AIX 3.2, etc. */
+#ifndef BSD44 /* If anybody else needs it... */
+#ifndef __386BSD__
+#ifndef __FreeBSD__
+#ifndef HPUX10
+#ifndef IRIX51 /* SGI IRIX 5.1 or later */
+#ifndef CK_SCOV5 /* SCO Open Server 5.0 */
+#define LFDEVNO
+#endif /* CK_SCOV5 */
+#endif /* IRIX51 */
+#endif /* HPUX10 */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#endif /* BSD44 */
+#endif /* AIXRS */
+#endif /* LFDEVNO */ /* ... define it here or on CC */
+#endif /* NOLFDEVNO */
+#endif /* SVR4 */ /* command line. */
+
+#ifdef COHERENT
+#define LFDEVNO
+#endif /* COHERENT */
+
+/*
+ For platforms where the lockfile name is made from device/major/minor
+ device number, as in SVR4. Which, if we must have lockfiles at all, is
+ by far the best format, since it eliminates all the confusion that stems
+ from multiple names (or drivers) for the same port, not to mention
+ symlinks. It might even be a good idea to start using this form even
+ on platforms where it's not supported, alongside the normal forms for those
+ platforms, in order to get people used to it...
+*/
+#ifdef LFDEVNO
+#ifndef major /* If we didn't find it */
+#ifdef SVR4 /* then for Sys V R4 */
+#include <sys/mkdev.h> /* look here */
+#else /* or for SunOS versions */
+#ifdef SUNOS4 /* ... */
+#include <sys/sysmacros.h> /* look here */
+#else /* Otherwise take a chance: */
+#define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
+#define minor(dev) ( (int) ( (dev) & 0xff))
+#endif /* SUNOS4 */
+#endif /* SVR4 */
+#endif /* major */
+#endif /* LFDEVNO */
+
+/* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
+
+#ifdef LOCKF
+#ifndef F_TLOCK
+#undef LOCKF
+#ifndef NOLOCKF
+#define NOLOCKF
+#endif /* NOLOCKF */
+#endif /* F_TLOCK */
+#endif /* LOCKF */
+
+#ifdef LOCKF
+#ifndef F_ULOCK
+#undef LOCKF
+#ifndef NOLOCKF
+#define NOLOCKF
+#endif /* NOLOCKF */
+#endif /* F_ULOCK */
+#endif /* LOCKF */
+
+static char linkto[DEVNAMLEN+1];
+static char * linkdev = NULL;
+
+#ifndef NOUUCP
+#ifdef USETTYLOCK
+#ifdef LOCK_DIR
+char * uucplockdir = LOCK_DIR;
+#else
+char * uucplockdir = "";
+#endif /* LOCK_DIR */
+#else
+#ifdef LOCK_DIR
+char * uucplockdir = LOCK_DIR;
+#else
+char * uucplockdir = "";
+#endif /* LOCK_DIR */
+#endif /* USETTYLOCK */
+#else
+char * uucplockdir = "";
+#endif /* NOUUCP */
+
+#ifdef QNX /* Only for QNX4 */
+int /* Visible to outside world */
+qnxopencount() { /* Get QNX device open count */
+ struct _dev_info_entry info;
+ int x;
+
+ x = -1; /* Unknown */
+ if (ttyfd > -1) {
+ if (!dev_info(ttyfd, &info)) {
+ debug(F101,"ttlock QNX open_count","",info.open_count);
+ x = info.open_count;
+ }
+ }
+ return(x);
+}
+#endif /* QNX */
+
+char *
+ttglckdir() { /* Get Lockfile directory name */
+#ifdef __OpenBSD__
+ return("/var/spool/lock");
+#else /* __OpenBSD__ */
+#ifdef __FreeBSD__
+ return("/var/spool/lock");
+#else /* __FreeBSD__ */
+#ifdef LOCK_DIR
+ char * s = LOCK_DIR;
+#endif /* LOCK_DIR */
+#ifdef NOUUCP
+ return("");
+#else /* NOUUCP */
+#ifdef LOCK_DIR
+ return(s);
+#else /* LOCK_DIR */
+ return("");
+#endif /* LOCK_DIR */
+#endif /* NOUUCP */
+#endif /* __FreeBSD__ */
+#endif /* __OpenBSD__ */
+}
+
+static int
+ttlock(ttdev) char *ttdev; {
+
+ int x, n;
+ int islink = 0;
+#ifdef __FreeBSD__
+ char *devname;
+#endif /* __FreeBSD__ */
+
+#ifdef NOUUCP
+ debug(F100,"ttlock NOUUCP","",0);
+ ckstrncpy(flfnam,"NOLOCK",FLFNAML);
+ haslock = 1;
+ return(0);
+#else /* !NOUUCP */
+
+#ifdef USETTYLOCK
+ haslock = 0; /* Not locked yet. */
+ *flfnam = '\0'; /* Lockfile name is empty. */
+#ifdef __FreeBSD__
+ if ((devname = xxlast(ttdev,'/')) != NULL)
+#ifdef FREEBSD8
+ ckstrncat(lockname,devname+1,DEVNAMLEN-ckstrncpy(lockname,"pts",4));
+#else
+ ckstrncpy(lockname,devname+1,DEVNAMLEN);
+#endif /* FREEBSD8 */
+#else
+ if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
+ ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
+#endif /* __FreeBSD__ */
+ else
+ ckstrncpy(lockname,ttdev,DEVNAMLEN);
+/*
+ This might be overkill, but it's not clear from the man pages whether
+ ttylock() can be called without calling ttylocked() first, since the doc
+ says that ttylocked() removes any stale lockfiles, but it does not say this
+ about ttylock(). Also the docs don't say what ttylocked() returns in the
+ case when it finds and removes a stale lockfile. So one or both calls to
+ to ttylocked() might be superfluous, but they should do no harm. Also I'm
+ assuming that we have to do all the same ID swapping, etc, with these
+ routines as we do without them. Thus the priv_on/off() sandwich.
+*/
+#ifdef USE_UU_LOCK
+ priv_on(); /* Turn on privs */
+ x = uu_lock(lockname); /* Try to set the lock */
+ priv_off(); /* Turn privs off */
+ debug(F111,"ttlock uu_lock",lockname,x);
+ switch (x) {
+ case UU_LOCK_INUSE:
+ return(-2);
+ case UU_LOCK_OK:
+#ifdef BSD44
+ ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
+#endif /* BSD44 */
+ haslock = 1;
+ return(0);
+ default:
+ return(-1);
+ }
+#else /* USE_UU_LOCK */
+ priv_on(); /* Turn on privs */
+ if (ttylocked(lockname)) { /* This should remove any stale lock */
+ if (ttylocked(lockname)) { /* so check again. */
+ priv_off();
+ return(-5); /* Still locked, fail. */
+ }
+ }
+ x = ttylock(lockname); /* Lock it. */
+ priv_off(); /* Turn off privs */
+
+ debug(F111,"ttlock lockname",lockname,x);
+ if (x > -1) {
+ /*
+ We don't really know the name of the lockfile, but
+ this is what the man page says it is. In USETTYLOCK
+ builds, it is used only for display by SHOW COMM.
+ */
+ ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
+ haslock = 1;
+ }
+ return(x);
+#endif /* USE_UU_LOCK */
+#else /* Systems that don't have ttylock()... */
+
+#ifndef HPUX
+
+ int lockfd; /* File descriptor for lock file. */
+ PID_T pid; /* Process id of this process. */
+ int tries; /* How many times we've tried... */
+ struct stat devbuf; /* For device numbers (SVR4). */
+
+#ifdef PIDSTRING
+ char pid_str[32]; /* My pid in string format. */
+#endif /* PIDSTRING */
+
+ char *device, *devname;
+
+#define LFNAML 256 /* Max length for lock file name. */
+ char lockfil[LFNAML]; /* Lock file name */
+#ifdef RTAIX
+ char lklockf[LFNAML]; /* Name for link to lock file */
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+ char symlock[LFNAML]; /* Name for symlink lockfile name */
+#endif /* CKSYMLINK */
+ char tmpnam[LFNAML+30]; /* Temporary lockfile name. */
+ char *lockdir = LOCK_DIR; /* Defined near top of this file, */
+ /* or on cc command line. */
+ haslock = 0; /* Not locked yet. */
+ *flfnam = '\0'; /* Lockfile name is empty. */
+ lock2[0] = '\0'; /* Clear secondary lockfile name. */
+ pid = getpid(); /* Get id of this process. */
+
+/* Construct name of lockfile and temporary file */
+
+/* device = name of tty device without the path, e.g. "ttyh8" */
+/* lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
+
+ device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
+
+ if (stat(ttdev,&devbuf) < 0)
+ return(-1);
+
+#ifdef CKSYMLINK
+ islink = 1; /* Assume it's a symlink */
+ linkto[0] = '\0'; /* But we don't know to what */
+#ifdef COMMENT
+/*
+ This is undependable. If it worked it would save the readlink call if
+ we knew the device name was not a link.
+*/
+#ifdef S_ISLNK
+ islink = S_ISLNK(devbuf.st_mode);
+ debug(F101,"ttlock stat S_ISLNK","",islink);
+#endif /* S_ISLNK */
+#endif /* COMMENT */
+ if (islink) {
+ n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
+ debug(F111,"ttlock readlink",ttdev,n);
+ if (n > -1) /* It is */
+ linkto[n] = '\0';
+ else /* It's not */
+ islink = 0;
+ debug(F111,"ttlock link",linkto,islink);
+ }
+ if (islink) {
+ linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
+ debug(F110,"ttlock linkdev",linkdev,0);
+ }
+#endif /* CKSYMLINK */
+
+/*
+ On SCO platforms, if we don't have a symlink, then let's pretend the
+ name given for the device is a symlink, because later we will change
+ the name if it contains any uppercase characters.
+*/
+#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
+ if (!islink) {
+ islink = 1;
+ ckstrncpy(linkto,ttdev,DEVNAMLEN);
+ linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
+ debug(F110,"ttlock linkdev",linkdev,0);
+ }
+#else
+#ifdef M_XENIX /* SCO Xenix or UNIX */
+ if (!islink) {
+ islink = 1;
+ ckstrncpy(linkto,ttdev,DEVNAMLEN);
+ linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
+ debug(F110,"ttlock linkdev",linkdev,0);
+ }
+#endif /* M_XENIX */
+#endif /* CK_SCOV5 */
+
+#ifdef ISIII /* Interactive System III, PC/IX */
+ ckstrncpy(lockfil, device, DEVNAMLEN);
+#else /* not ISIII */
+#ifdef LFDEVNO /* Lockfilename has device numbers. */
+#ifdef COHERENT
+ sprintf(lockfil,"LCK..%d.%d", /* SAFE */
+ major(devbuf.st_rdev), /* major device number */
+ 0x1f & minor(devbuf.st_rdev)); /* minor device number */
+#else
+ /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
+ /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
+ sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
+ major(devbuf.st_dev), /* device */
+ major(devbuf.st_rdev), /* major device number */
+ minor(devbuf.st_rdev)); /* minor device number */
+#endif /* COHERENT */
+#else /* Not LFDEVNO */
+#ifdef PTX /* Dynix PTX */
+ if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
+ if ((int)strlen(device) + 8 < LFNAML)
+ sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
+ else
+ ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
+ } else
+#endif /* PTX */
+ if ((int)strlen(device) + 5 < LFNAML)
+ sprintf(lockfil,"LCK..%s", device);
+ else
+ ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
+#ifdef RTAIX
+ ckstrncpy(lklockf,device,DEVNAMLEN);
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+ symlock[0] = '\0';
+ if (islink)
+ ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
+#endif /* CKSYMLINK */
+#endif /* LFDEVNO */
+#endif /* ISIII */
+
+#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
+ {
+ /* Lowercase the entire filename. */
+ /* SCO says we must do this in V5.0 and later. */
+ /* BUT... watch out for devices -- like Digiboard Portserver */
+ /* That can have hundreds of ports... */
+ char *p = (char *)(lockfil + 5);
+ while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
+ }
+#ifdef CKSYMLINK
+ if (islink) { /* If no change */
+ if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */
+ islink = 0;
+ symlock[0] = '\0';
+ }
+ }
+#endif /* CKSYMLINK */
+#else
+#ifdef M_XENIX /* SCO Xenix or UNIX */
+ {
+ int x; char c;
+ x = (int)strlen(lockfil) - 1; /* Get last letter of device name. */
+ if (x > 0) { /* If it's uppercase, lower it. */
+ c = lockfil[x];
+ if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
+ }
+ }
+#ifdef CKSYMLINK
+ if (islink) {
+ if (!strcmp(lockfil,symlock)) { /* No change */
+ islink = 0; /* so no second lockfile */
+ symlock[0] = '\0';
+ }
+ }
+#endif /* CKSYMLINK */
+#endif /* M_XENIX */
+#endif /* CK_SCOV5 */
+
+/* flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
+/* tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
+
+ ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
+
+#ifdef RTAIX
+ ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
+#endif /* RTAIX */
+
+#ifndef LFDEVNO
+#ifdef CKSYMLINK
+ /* If it's a link then also make a lockfile for the real name */
+ debug(F111,"ttlock link symlock",symlock,islink);
+ if (islink && symlock[0]) {
+ /* But only if the lockfile names would be different. */
+ /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
+ ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
+ debug(F110,"ttlock lock2",lock2,0);
+ if (!strcmp(lock2,flfnam)) { /* Are lockfile names the same? */
+ debug(F100,"ttlock lock2 cleared","",0);
+ lock2[0] = '\0'; /* Clear secondary lockfile name. */
+ }
+ }
+#endif /* CKSYMLINK */
+#endif /* LFDEVNO */
+
+ sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
+ debug(F110,"ttlock flfnam",flfnam,0);
+ debug(F110,"ttlock tmpnam",tmpnam,0);
+
+ priv_on(); /* Turn on privileges if possible. */
+ lockfd = creat(tmpnam, 0444); /* Try to create temp lock file. */
+ if (lockfd < 0) { /* Create failed. */
+ debug(F111,"ttlock creat failed",tmpnam,errno);
+ if (errno == ENOENT) {
+ perror(lockdir);
+ printf("UUCP not installed or Kermit misconfigured\n");
+ } else {
+ if (!quiet)
+ perror(lockdir);
+ unlink(tmpnam); /* Get rid of the temporary file. */
+ }
+ priv_off(); /* Turn off privileges!!! */
+ return(-1); /* Return failure code. */
+ }
+/* Now write the pid into the temp lockfile in the appropriate format */
+
+#ifdef PIDSTRING /* For Honey DanBer UUCP, */
+ sprintf( /* write PID as decimal string */
+ pid_str,
+#ifdef LINUXFSSTND /* The "Linux File System Standard" */
+#ifdef FSSTND10 /* Version 1.0 calls for */
+ "%010d\n", /* leading zeros */
+#else /* while version 1.2 calls for */
+ "%10d\n", /* leading spaces */
+#endif /* FSSTND10 */
+#else
+#ifdef COHERENT
+ "%d\n", /* with leading nothing */
+#else
+ "%10d\n", /* with leading blanks */
+#endif /* COHERENT */
+#endif /* LINUXFSSTND */
+ (int) pid
+ ); /* safe */
+ write(lockfd, pid_str, 11);
+ debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
+
+#else /* Not PIDSTRING, use integer PID */
+
+ write(lockfd, (char *)&pid, sizeof(pid) );
+ debug(F101,"ttlock pid","",(int) pid);
+
+#endif /* PIDSTRING */
+
+/* Now try to rename the temp file to the real lock file name. */
+/* This will fail if a lock file of that name already exists. */
+
+ close(lockfd); /* Close the temp lockfile. */
+ chmod(tmpnam,0444); /* Permission for a valid lock. */
+ tries = 0;
+ while (!haslock && tries++ < 2) {
+ haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
+ if (haslock) { /* If we got the lockfile */
+#ifdef RTAIX
+ link(flfnam,lkflfn);
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+#ifndef LFDEVNO
+ if (islink && lock2[0])
+ link(flfnam,lock2);
+#endif /* LFDEVNO */
+#endif /* CKSYMLINK */
+
+#ifdef COMMENT
+/* Can't do this any more because device is not open yet so no ttyfd. */
+#ifdef LOCKF
+/*
+ Advisory file locking works on SVR4, so we use it. In fact, it is
+ necessary in some cases, e.g. when SLIP is involved. But it still doesn't
+ seem to prevent multiple users accessing the same device by different names.
+*/
+ while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
+ debug(F111, "ttlock lockf returns errno", "", errno);
+ if ((++tries >= 3) || (errno != EAGAIN)) {
+ x = unlink(flfnam); /* remove the lockfile */
+#ifdef RTAIX
+ unlink(lkflfn); /* And any links to it... */
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+#ifndef LFDEVNO
+ if (islink && lock2[0])
+ unlink(lock2); /* ditto... */
+#endif /* LFDEVNO */
+#endif /* CKSYMLINK */
+ debug(F111,"ttlock unlink",flfnam,x);
+ haslock = 0;
+ break;
+ }
+ sleep(2);
+ }
+ if (haslock) /* If we got an advisory lock */
+#endif /* LOCKF */
+#endif /* COMMENT */
+ break; /* We're done. */
+
+ } else { /* We didn't create a new lockfile. */
+ priv_off();
+ if (ttchkpid(flfnam)) { /* Check existing lockfile */
+ priv_on(); /* cause ttchkpid turns priv_off... */
+ unlink(tmpnam); /* Delete the tempfile */
+ debug(F100,"ttlock found tty locked","",0);
+ priv_off(); /* Turn off privs */
+ return(-2); /* Code for device is in use. */
+ }
+ priv_on();
+ }
+ }
+ unlink(tmpnam); /* Unlink (remove) the temp file. */
+ priv_off(); /* Turn off privs */
+ return(haslock ? 0 : -1); /* Return link's return code. */
+
+#else /* HPUX */
+
+/*
+ HP-UX gets its own copy of this routine, modeled after the observed behavior
+ of the HP-UX 'cu' program. HP-UX serial device names consist of a base name
+ such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
+ designator which is a string of digits, possibly containing an imbedded
+ letter "p". Examples (for base name "tty"):
+
+ /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
+
+ According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
+ used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
+ on other models. In HP-UX 10.00, "0p0" notation was adopted for all models.
+ However, we make and enforce no such distinctions; either notation is
+ accepted on any model or HP-UX version as a valid unit designator.
+
+ If a valid unit is specified (as opposed to a designer name or symlink), we
+ check for all aliases of the given unit according to the devprefix[] array.
+ If no lockfiles are found for the given unit, we can have the device; we
+ create a lockfile LCK..name in the lockfile directory appropriate for the
+ HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
+ 9.xx and earlier). If it is a "cua" or "cul" device, a second lockfile is
+ created with the "ttyd" prefix. This is exactly what cu does.
+
+ If the "set line" device does not have a valid unit designator, then it is
+ used literally and no synomyms are searched for and only one lockfile is
+ created.
+
+ -fdc, March 1998.
+*/
+#define LFNAML 80 /* Max length for lock file name. */
+
+ int lockfd; /* File descriptor for lock file. */
+ PID_T pid; /* Process ID of this process. */
+ int fpid; /* pid found in existing lockfile. */
+ int tries; /* How many times we've tried... */
+ int i, k; /* Workers */
+
+ char *device, *devname; /* "/dev/xxx", "xxx" */
+ char *unit, *p; /* <instance>p<port> part of xxx */
+
+ char lockfil[LFNAML]; /* Lockfile name (no path) */
+ char tmpnam[LFNAML]; /* Temporary lockfile name. */
+
+#ifdef HPUX10 /* Lockfile directory */
+ char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
+#else /* HP-UX 9.xx and below */
+#ifdef LOCK_DIR
+ char *lockdir = LOCK_DIR; /* Defined near top of this file */
+#else
+ char *lockdir = "/usr/spool/uucp"; /* or not... */
+#endif /* LOCK_DIR */
+#endif /* HPUX10 */
+
+ haslock = 0; /* Not locked yet. */
+ *flfnam = '\0'; /* Lockfile name is empty. */
+ lock2[0] = '\0'; /* Second one too. */
+ pid = getpid(); /* Get my process ID */
+/*
+ Construct name of lockfile and temporary file...
+ device = name of tty device without the path, e.g. "tty0p0"
+ lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
+*/
+ device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
+ debug(F110,"TTLOCK device",device,0);
+ ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
+
+ k = 0; /* Assume device is not locked */
+ n = 0; /* Digit counter */
+ unit = device; /* Unit = <instance>p<port> */
+ while (*unit && !isdigit(*unit)) /* Search for digit... */
+ unit++;
+ p = unit; /* Verify <num>p<num> format... */
+ debug(F110,"TTLOCK unit 1",unit,0);
+/*
+ The unit number is recognized as:
+ (a) any sequence of digits that runs to the end of the string.
+ (b) any (a) that includes one and only one letter "p", with at least
+ one digit before and after it.
+*/
+ while (isdigit(*p)) p++, n++; /* Get a run of digits */
+ if (*p && n > 0) { /* Have a "p"? */
+ if (*p == 'p' && isdigit(*(p+1))) {
+ p++;
+ n = 0;
+ while (isdigit(*p)) p++, n++;
+ }
+ }
+ if (n == 0 || *p) unit = "";
+ debug(F110,"TTLOCK unit 2",unit,0);
+
+ if (*unit) { /* Device name has unit number. */
+ /* The following loop not only searches for the various lockfile */
+ /* synonyms, but also removes all -- not just one -- stale lockfile */
+ /* for the device, should there be more than one. See ttchkpid(). */
+ ttydexists = 0;
+ for (i = 0; *devprefix[i]; i++) { /* For each driver... */
+ /* Make device name */
+ ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
+ priv_on(); /* Privs on */
+ k = zchki(lock2) != -1; /* See if device exists */
+ priv_off(); /* Privs off */
+ debug(F111,"TTLOCK exist",lock2,k);
+ if (k) {
+ if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
+ ttydexists = 1;
+ /* Make lockfile name */
+ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
+ debug(F110,"TTLOCK checking",lock2,0);
+ priv_on(); /* Privs on */
+ k = zchki(lock2) != -1; /* See if lockfile exists */
+ priv_off(); /* Privs off */
+ debug(F111,"TTLOCK check for lock A",lock2,k);
+ if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
+ ckstrncpy(flfnam,lock2,FLFNAML);
+ return(-2);
+ }
+ }
+ }
+ } else { /* Some other device-name format */
+ /* This takes care of symbolic links, etc... */
+ /* But does not chase them down! */
+ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
+ priv_on();
+ k = zchki(lock2) != -1; /* Check for existing lockfile */
+ priv_off();
+ debug(F111,"TTLOCK check for lock B",lock2,k);
+ if (k) if (ttchkpid(lock2)) { /* Check pid from lockfile */
+ ckstrncpy(flfnam,lock2,FLFNAML);
+ debug(F110,"TTLOCK in use",device,0);
+ debug(F101,"TTLOCK returns","",-2);
+ return(-2);
+ }
+ }
+/*
+ Get here only if there is no (more) lockfile, so now we make one (or two)...
+ flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
+ tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
+*/
+ ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
+
+ /* If dialout device, also make one for corresponding dialin device */
+ lock2[0] = '\0';
+ if (!strncmp(device,"cu",2) && *unit && ttydexists)
+ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
+
+ if ((int)strlen(lockdir)+12 < LFNAML)
+ sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"TTLOCK flfnam",flfnam,0);
+ debug(F110,"TTLOCK lock2",lock2,0);
+ debug(F110,"TTLOCK tmpnam",tmpnam,0);
+ }
+#endif /* DEBUG */
+/*
+ Lockfile permissions...
+ 444 is standard, HP-UX 10.00 uses 664. It doesn't matter.
+ Kermit uses 444; the difference lets us tell whether Kermit created
+ the lock file.
+*/
+ priv_on(); /* Turn on privileges. */
+ lockfd = creat(tmpnam, 0444); /* Try to create temporary file. */
+ if (lockfd < 0) { /* Create failed. */
+ debug(F111,"TTLOCK creat failed",tmpnam,errno);
+ if (errno == ENOENT) {
+ perror(lockdir);
+ printf("UUCP not installed or Kermit misconfigured\n");
+ } else {
+ if (!quiet)
+ perror(lockdir);
+ unlink(tmpnam); /* Get rid of the temporary file. */
+ }
+ priv_off(); /* Turn off privileges!!! */
+ debug(F101,"TTLOCK returns","",-1);
+ return(-1); /* Return failure code. */
+ }
+ debug(F110,"TTLOCK temp ok",tmpnam,0);
+
+/* Now write our pid into the temp lockfile in integer format. */
+
+ i = write(lockfd, (char *)&pid, sizeof(pid));
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"TTLOCK pid","",pid);
+ debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
+ debug(F101,"TTLOCK write pid returns","",i);
+ }
+#endif /* DEBUG */
+
+/*
+ Now try to rename the temporary file to the real lockfile name.
+ This will fail if a lock file of that name already exists, which
+ will catch race conditions with other users.
+*/
+ close(lockfd); /* Close the temp lockfile. */
+ chmod(tmpnam,0444);
+
+ tries = 0;
+ while (!haslock && tries++ < 2) {
+ haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
+ debug(F101,"TTLOCK link","",haslock);
+ if (haslock) { /* If we made the lockfile... */
+
+#ifdef COMMENT
+/* We can't do this any more because we don't have a file descriptor yet. */
+#ifdef LOCKF /* Can be canceled with -DNOLOCKF */
+/*
+ Create an advisory lock on the device through its file descriptor.
+ This code actually seems to work. If it is executed, and then another
+ process tries to open the same device under a different name to circumvent
+ the lockfile, they get a "device busy" error.
+*/
+ debug(F100,"TTLOCK LOCKF code...","",0);
+ while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
+ debug(F111, "TTLOCK lockf error", "", errno);
+ if ((++tries >= 3) || (errno != EAGAIN)) {
+ x = unlink(flfnam); /* Remove the lockfile */
+ if (errno == EACCES && !quiet)
+ printf("Device already locked by another process\n");
+ haslock = 0;
+ break;
+ }
+ sleep(2);
+ }
+#endif /* LOCKF */
+#endif /* COMMENT */
+
+ if (haslock) { /* If we made the lockfile ... */
+ if (lock2[0]) { /* if there is to be a 2nd lockfile */
+ lockfd = creat(lock2, 0444); /* Create it */
+ debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
+ if (lockfd > -1) { /* Created OK, write pid. */
+ write(lockfd, (char *)&pid, sizeof(pid) );
+ close(lockfd); /* Close and */
+ chmod(lock2, 0444); /* set permissions. */
+ } else { /* Not OK, but don't fail. */
+ lock2[0] = '\0'; /* Just remember it's not there. */
+ }
+ }
+ break; /* and we're done. */
+ }
+ }
+ }
+ unlink(tmpnam); /* Unlink (remove) the temp file. */
+ priv_off(); /* Turn off privs */
+ i = haslock ? 0 : -1; /* Our return value */
+ debug(F101,"TTLOCK returns","",i);
+ return(i);
+#endif /* HPUX */
+#endif /* USETTYLOCK */
+#endif /* !NOUUCP */
+}
+
+/* T T U N L O C K */
+
+static int
+ttunlck() { /* Remove UUCP lockfile(s). */
+#ifndef NOUUCP
+ int x;
+
+ debug(F111,"ttunlck",flfnam,haslock);
+
+#ifdef USETTYLOCK
+
+ if (haslock && *flfnam) {
+ int x;
+ priv_on(); /* Turn on privs */
+#ifdef USE_UU_LOCK
+ x = uu_unlock(lockname);
+#else /* USE_UU_LOCK */
+ x = ttyunlock(lockname); /* Try to unlock */
+#endif /* USE_UU_LOCK */
+ priv_off(); /* Turn off privs */
+ if (x < 0 && !quiet)
+ printf("Warning - Can't remove lockfile: %s\n", flfnam);
+
+ *flfnam = '\0'; /* Erase the name. */
+ haslock = 0;
+ return(0);
+ }
+
+#else /* No ttylock()... */
+
+ if (haslock && *flfnam) {
+ /* Don't remove lockfile if we didn't make it ourselves */
+ if ((x = ttrpid(flfnam)) != (int)getpid()) {
+ debug(F111,"ttunlck lockfile seized",flfnam,x);
+ printf("Warning - Lockfile %s seized by pid %d\n",
+ flfnam,
+ x
+ );
+ return(0);
+ }
+ priv_on(); /* Turn privileges on. */
+ errno = 0;
+ x = unlink(flfnam); /* Remove the lockfile. */
+ debug(F111,"ttunlck unlink",flfnam,x);
+ if (x < 0) {
+ if (errno && !quiet)
+ perror(ttnmsv);
+ printf("Warning - Can't remove lockfile: %s\n", flfnam);
+ }
+ haslock = 0;
+ *flfnam = '\0'; /* Erase the name. */
+
+#ifdef RTAIX
+ errno = 0;
+ x = unlink(lkflfn); /* Remove link to lockfile */
+ debug(F111,"ttunlck AIX link unlink",lkflfn,x);
+ if (x < 0) {
+ if (errno && !quiet)
+ perror(ttnmsv);
+ printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
+ }
+ *lkflfn = '\0';
+#else
+ if (lock2[0]) { /* If there is a second lockfile, */
+ errno = 0;
+ x = unlink(lock2); /* remove it too. */
+ debug(F111,"ttunlck lock2 unlink",lock2,x);
+ if (x < 0) {
+ if (errno && !quiet)
+ perror(ttnmsv);
+ printf("Warning - Can't remove secondary lockfile: %s\n",
+ lock2
+ );
+ }
+ lock2[0] = '\0'; /* Forget its name. */
+ }
+#endif /* RTAIX */
+
+#ifdef COMMENT
+#ifdef LOCKF
+ (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
+#endif /* LOCKF */
+#endif /* COMMENT */
+
+ priv_off(); /* Turn privileges off. */
+ }
+#endif /* USETTYLOCK */
+#endif /* !NOUUCP */
+ return(0);
+}
+
+/*
+ 4.3BSD-style UUCP line direction control.
+ (Stan Barber, Rice U, 1980-something...)
+*/
+#ifndef NOUUCP
+#ifdef ACUCNTRL
+VOID
+acucntrl(flag,ttname) char *flag, *ttname; {
+ char x[DEVNAMLEN+32], *device, *devname;
+
+ if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
+ return; /* just return. */
+ device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
+ if (strncmp(device,"LCK..",4) == 0) device += 5;
+ ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
+ debug(F110,"called ",x,0);
+ zsyscmd(x);
+}
+#endif /* ACUCNTRL */
+#endif /* NOUUCP */
+
+/*
+ T T H F L O W -- Set or Reset hardware flow control.
+
+ This is an attempt to collect all hardware-flow-control related code
+ into a single module. Thanks to Rick Sladkey and John Kohl for lots of
+ help here. Overview:
+
+ Hardware flow control is not supported in many UNIX implementions. Even
+ when it is supported, there is no (ha ha) "standard" for the programming
+ interface. In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
+ SunOS, AIX, etc, have totally different methods. (And, not strictly
+ relevant here, the programming interface often brings one only to a no-op
+ in the device driver!)
+
+ Among all these, we have two major types of APIs: those in which hardware
+ flow control is determined by bits in the same termio/termios/sgtty mode
+ word(s) that are used for controlling such items as CBREAK vs RAW mode, and
+ which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
+ for changing terminal modes. And those that use entirely different
+ mechanisms.
+
+ In the first category, it is important that any change in the mode bits be
+ reflected in the relevant termio(s)/sgtty structure, so that subsequent
+ changes to that structure do not wipe out the effects of this routine. That
+ is why a pointer, attrs, to the appropriate structure is passed as a
+ parameter to this routine.
+
+ The second category should give us no worries, since any changes to hardware
+ flow control accomplished by this routine should not affect the termio(s)/
+ sgtty structures, and therefore will not be undone by later changes to them.
+
+ The second argument, status, means to turn on hardware flow control if
+ nonzero, and to turn it off if zero.
+
+ Returns: 0 on apparent success, -1 on probable failure.
+*/
+
+/*
+ The following business is for BSDI, where it was discovered that two
+ separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
+ but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
+ bits, so hwfc only works in one direction if you use CRTSCTS to control it.
+ Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
+ define CRTSCTS correctly.
+*/
+#ifdef FIXCRTSCTS
+#ifdef CRTSCTS
+#ifdef CCTS_OFLOW
+#ifdef CRTS_IFLOW
+#undef CRTSCTS
+#define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
+#endif /* CRTS_IFLOW */
+#endif /* CCTS_OFLOW */
+#endif /* CRTSCTS */
+#endif /* FIXCRTSCTS */
+
+static int
+tthflow(flow, status, attrs)
+ int flow, /* Type of flow control (ckcdeb.h) */
+ status; /* Nonzero = turn it on */
+ /* Zero = turn it off */
+#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
+ struct termios *attrs;
+#else /* System V */
+#ifdef ATTSV
+#ifdef ATT7300
+#ifdef UNIX351M
+/* AT&T UNIX 3.51m can set but not test for hardware flow control */
+#define RTSFLOW CTSCD
+#define CTSFLOW CTSCD
+#endif /* ATT7300 */
+#endif /* UNIX351M */
+ struct termio *attrs;
+#else /* BSD, V7, etc */
+ struct sgttyb *attrs; /* sgtty info... */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+/* tthflow */ {
+
+ int x = 0; /* tthflow() return code */
+
+#ifdef Plan9
+ return p9tthflow(flow, status);
+#else
+
+#ifndef OXOS /* NOT Olivetti X/OS... */
+/*
+ For SunOS 4.0 and later in the BSD environment ...
+
+ The declarations are copied and interpreted from the System V header files,
+ so we don't actually have to pull in all the System V junk when building
+ C-Kermit for SunOS in the BSD environment, which would be dangerous because
+ having those symbols defined would cause us to take the wrong paths through
+ the code. The code in this section is used in both the BSD and Sys V SunOS
+ versions.
+*/
+#ifdef SUNOS41
+/*
+ In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
+ because GNU CC uses different formats for the _IOxxx macros than regular CC;
+ the POSIX forms work for both. But the POSIX calls are not available in
+ SunOS 4.0.
+*/
+#define CRTSCTS 0x80000000 /* RTS/CTS flow control */
+#define TCSANOW 0 /* Do it now */
+
+ struct termios {
+ unsigned long c_iflag; /* Input modes */
+ unsigned long c_oflag; /* Output modes */
+ unsigned long c_cflag; /* Control modes */
+ unsigned long c_lflag; /* Line discipline modes */
+ char c_line;
+ CHAR c_cc[17];
+ };
+ struct termios temp;
+
+_PROTOTYP( int tcgetattr, (int, struct termios *) );
+_PROTOTYP( int tcsetattr, (int, int, struct termios *) );
+/*
+ When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
+ asserted. So we don't set CRTSCTS unless CD is up. This should be OK,
+ since we don't need RTS/CTS during dialing, and after dialing is complete,
+ we should have CD. If not, we still communicate, but without RTS/CTS.
+*/
+ int mflags; /* Modem signal flags */
+
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+ debug(F101,"tthflow SUNOS41 entry status","",status);
+ if (!status) { /* Turn hard flow off */
+ if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
+ (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
+ temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ }
+ } else { /* Turn hard flow on */
+ if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
+ (mflags & TIOCM_CAR)) { /* Check for CD */
+ debug(F100,"tthflow SunOS has CD","",0);
+ if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
+ !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
+ temp.c_cflag |= CRTSCTS; /* Not there, add it */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ }
+ } else {
+ x = -1;
+ debug(F100,"tthflow SunOS no CD","",0);
+ }
+ }
+#else
+#ifdef QNX
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow QNX entry status","",status);
+ if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
+ if (!status) { /* Turn hard flow off */
+ if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
+ temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
+ attrs->c_cflag &= ~(IHFLOW|OHFLOW);
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ }
+ } else { /* Turn hard flow on */
+ if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
+ temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
+ temp.c_iflag &= ~(IXON|IXOFF); /* Bye to IXON/IXOFF */
+ ttraw.c_lflag |= IEXTEN; /* Must be on */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ attrs->c_cflag |= (IHFLOW|OHFLOW);
+ attrs->c_iflag &= ~(IXON|IXOFF);
+ }
+ }
+ } else {
+ x = -1;
+ debug(F100, "tthflow QNX getattr fails", "", 0);
+ }
+#else
+#ifdef POSIX_CRTSCTS
+/*
+ POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
+ Note: Do not assume CRTSCTS is a one-bit field!
+*/
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
+ errno = 0;
+ x = tcgetattr(ttyfd, &temp);
+ debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
+ errno = 0;
+ if (x < 0) {
+ x = -1;
+ } else {
+ if (!status) { /* Turn hard flow off */
+ if (
+#ifdef COMMENT
+ /* This can fail because of sign extension */
+ /* e.g. in Linux where it's Bit 31 */
+ (temp.c_cflag & CRTSCTS) == CRTSCTS
+#else
+ (temp.c_cflag & CRTSCTS) != 0
+#endif /* COMMENT */
+ ) {
+ temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
+ attrs->c_cflag &= ~CRTSCTS;
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
+ ckitoa(x),errno);
+ } else { /* John Dunlap 2010-01-26 */
+ debug(F001,
+ "tthflow before forcing off attrs CRTSCTS",
+ "",
+ attrs->c_cflag&CRTSCTS
+ );
+ attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
+ debug(F001,
+ "tthflow after forcing off attrs CRTSCTS",
+ "",
+ attrs->c_cflag&CRTSCTS
+ );
+ }
+ } else { /* Turn hard flow on */
+ if (
+#ifdef COMMENT
+ /* This can fail because of sign extension */
+ (temp.c_cflag & CRTSCTS) != CRTSCTS
+#else
+ (temp.c_cflag & CRTSCTS) == 0
+#endif /* COMMENT */
+ ) {
+ temp.c_cflag |= CRTSCTS; /* Not there, add it */
+ temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
+ ckitoa(x),errno);
+ attrs->c_cflag |= CRTSCTS;
+ attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
+ }
+ }
+ }
+#else
+#ifdef SUNOS4
+/*
+ SunOS 4.0 (and maybe earlier?). This code is dangerous because it
+ prevents compilation with GNU gcc, which uses different formats for the
+ _IORxxx macros than regular cc. SunOS 4.1 and later can use the POSIX
+ routines above, which work for both cc and gcc.
+*/
+#define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
+#define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
+#define CRTSCTS 0x80000000 /* RTS/CTS flow control */
+
+ struct termios {
+ unsigned long c_iflag; /* Input modes */
+ unsigned long c_oflag; /* Output modes */
+ unsigned long c_cflag; /* Control modes */
+ unsigned long c_lflag; /* Line discipline modes */
+ char c_line;
+ CHAR c_cc[17];
+ };
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow entry status","",status);
+ if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
+ if (status) { /* Turn hard flow on */
+ temp.c_cflag |= CRTSCTS; /* Add RTS/CTS to them. */
+ x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
+ attrs->c_cflag |= CRTSCTS; /* Add to global info. */
+ } else { /* Turn hard flow off */
+ temp.c_cflag &= ~CRTSCTS;
+ x = ioctl(ttyfd,TCSETS,&temp);
+ attrs->c_cflag &= ~CRTSCTS;
+ }
+ }
+#else /* Not SunOS 4.0 or later */
+#ifdef AIXRS /* IBM AIX RS/6000 */
+#ifndef AIX41 /* But only pre-4.x == SVR4 */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ if (status) {
+ if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
+ debug(F100,"hardflow TXADDCD (rts) error", "", 0);
+ } else {
+ if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
+ debug(F100,"hardflow TXDELCD (rts) error", "", 0);
+ }
+#endif /* AIX41 */
+#else /* Not AIX RS/6000 */
+
+#ifdef ATTSV /* System V... */
+
+#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
+#define CK_SCOUNIX
+#else
+#ifdef M_UNIX /* SCO UNIX 3.2v4.x or earlier */
+#define CK_SCOUNIX
+#endif /* M_UNIX */
+#endif /* CK_SCOV5 */
+
+#ifdef SCO_FORCE_RTSXOFF
+#ifdef CK_SCOUNIX /* But not SCO OpenServer 5.0.4 */
+#ifdef SCO_OSR504 /* or later... */
+#undef CK_SCOUNIX
+#endif /* SCO_OSR504 */
+#endif /* CK_SCOUNIX */
+#endif /* SCO_FORCE_RTSXOFF */
+
+#ifdef CK_SCOUNIX
+#ifdef POSIX
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
+ errno = 0;
+ x = tcgetattr(ttyfd, &temp);
+ debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
+#else /* POSIX */
+ struct termio temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
+ x = ioctl(ttyfd, TCGETA, &temp);
+ debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
+#endif /* POSIX */
+/*
+ This is not really POSIX, since POSIX does not deal with hardware flow
+ control, but we are using the POSIX APIs. In fact, RTSFLOW and CTSFLOW
+ are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif. So
+ let's try forcing their definitions here.
+*/
+#ifndef CTSFLOW
+#define CTSFLOW 0020000
+ debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
+#else
+ debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
+#endif /* CTSFLOW */
+#ifndef RTSFLOW
+#define RTSFLOW 0040000
+ debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
+#else
+ debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
+#endif /* RTSFLOW */
+#ifndef ORTSFL
+#define ORTSFL 0100000
+ debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
+#else
+ debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
+#endif /* ORTSFL */
+
+ if (x != -1) {
+ if (status) { /* Turn it ON */
+ temp.c_cflag |= RTSFLOW|CTSFLOW;
+ attrs->c_cflag |= RTSFLOW|CTSFLOW;
+#ifdef ORTSFL
+ temp.c_cflag &= ~ORTSFL;
+ attrs->c_cflag &= ~ORTSFL;
+#endif /* ORTSFL */
+ temp.c_iflag &= ~(IXON|IXOFF|IXANY);
+ attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
+ } else { /* Turn it OFF */
+#ifdef ORTSFL
+ temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
+ attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
+#else /* ORTSFL */
+ temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
+ attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
+#endif /* ORTSFL */
+ }
+#ifdef POSIX
+ x = tcsetattr(ttyfd, TCSADRAIN, &temp);
+#else
+ x = ioctl(ttyfd, TCSETA, &temp);
+#endif /* POSIX */
+ debug(F101,"tthflow SCO set modes","",x);
+ }
+#else /* Not SCO UNIX */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ if (!status) { /* Turn it OFF */
+#ifdef RTSXOFF
+ debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
+ rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
+#ifdef TCSETX
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ debug(F101,"tthflow ATTSV TCSETX OFF","",x);
+#else
+ x = -1
+ debug(F100,"tthflow TCSETX not defined","",0);
+#endif /* TCSETX */
+#else
+ debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
+#endif /* RTSXOFF */
+#ifdef DTRXOFF
+ debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
+ rctsx.x_hflag &= ~(DTRXOFF|CDXON);
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
+#else
+ debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
+#endif /* DTRXOFF */
+ } else { /* Turn it ON. */
+ if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
+ debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
+#ifdef RTSXOFF
+ /* This is the preferred way, according to SVID3 */
+#ifdef TCGETX
+ x = ioctl(ttyfd,TCGETX,&rctsx);
+ debug(F101,"tthflow TCGETX","",x);
+ if (x > -1) {
+ rctsx.x_hflag |= RTSXOFF | CTSXON;
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ debug(F100,"tthflow ATTSV ioctl","",x);
+ }
+#else
+ debug(F100,"tthflow TCGETX not defined","",0);
+ x = -1
+#endif /* TCGETX */
+#else
+ debug(F100,"tthflow RTSXOFF not defined","",0);
+ x = -1;
+#endif /* RTSXOFF */
+ } else if (flow == FLO_DTRC) { /* DTR/CD Flow control... */
+ debug(F100,"tthflow ATTSV DTR/CD ON","",0);
+#ifdef DTRXOFF
+ /* This is straight out of SVID R4 */
+ if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
+ rctsx.x_hflag &= ~(DTRXOFF|CDXON);
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ }
+#else
+ debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
+ x = -1;
+#endif /* DTRXOFF */
+ }
+ }
+#endif /* CK_SCOUNIX */
+
+#else /* not System V... */
+
+#ifdef CK_DTRCTS
+#ifdef LDODTR
+#ifdef LDOCTS
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ x = LDODTR | LDOCTS; /* Found only on UTEK? */
+ if (flow == FLO_DTRT && status) { /* Use hardware flow control */
+ if (lmodef) {
+ x = ioctl(ttyfd,TIOCLBIS,&x);
+ if (x < 0) {
+ debug(F100,"hardflow TIOCLBIS error","",0);
+ } else {
+ lmodef++;
+ debug(F100,"hardflow TIOCLBIS ok","",0);
+ }
+ }
+ } else {
+ if (lmodef) {
+ x = ioctl(ttyfd,TIOCLBIC,&x);
+ if (x < 0) {
+ debug(F100,"hardflow TIOCLBIC error","",0);
+ } else {
+ lmodef++;
+ debug(F100,"hardflow TIOCLBIC ok","",0);
+ }
+ }
+ }
+#endif /* LDODTR */
+#endif /* LDOCTS */
+#endif /* CK_DTRCTS */
+#endif /* ATTSV */
+#endif /* AIXRS */
+#endif /* SUNOS4 */
+#endif /* QNX */
+#endif /* POSIX_CRTSCTS */
+#endif /* SUNOS41 */
+
+#else /* OXOS */
+
+ struct termios temp; /* Olivetti X/OS ... */
+
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ x = ioctl(ttyfd,TCGETS,&temp);
+ if (x == 0) {
+ temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
+ if (status) {
+ switch (flow) {
+ case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
+ break;
+ case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
+ break;
+ }
+ }
+ x = ioctl(ttyfd,TCSETS,&temp);
+ }
+#endif /* OXOS */
+ return(x);
+
+#endif /* Plan9 */
+}
+
+/* T T P K T -- Condition the communication line for packets */
+/* or for modem dialing */
+
+/*
+ If called with speed > -1, also set the speed.
+ Returns 0 on success, -1 on failure.
+
+ NOTE: the "xflow" parameter is supposed to be the currently selected
+ type of flow control, but for historical reasons, this parameter is also
+ used to indicate that we are dialing. Therefore, when the true flow
+ control setting is needed, we access the external variable "flow", rather
+ than trusting our "xflow" argument.
+*/
+int
+#ifdef CK_ANSIC
+ttpkt(long speed, int xflow, int parity)
+#else
+ttpkt(speed,xflow,parity) long speed; int xflow, parity;
+#endif /* CK_ANSIC */
+/* ttpkt */ {
+#ifndef NOLOCAL
+ int s2;
+ int s = -1;
+#endif /* NOLOCAL */
+ int x;
+ extern int flow; /* REAL flow-control setting */
+
+ if (ttyfd < 0) return(-1); /* Not open. */
+
+ debug(F101,"ttpkt parity","",parity);
+ debug(F101,"ttpkt xflow","",xflow);
+ debug(F101,"ttpkt speed","",(int) speed);
+
+ ttprty = parity; /* Let other tt functions see these. */
+ ttspeed = speed; /* Make global copy for this module */
+ ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */
+#ifdef PARSENSE
+ needpchk = ttprty ? 0 : 1; /* Parity check needed? */
+#else
+ needpchk = 0;
+#endif /* PARSENSE */
+
+ debug(F101,"ttpkt ttpmsk","",ttpmsk);
+ debug(F101,"ttpkt netconn","",netconn);
+
+#ifdef NETCONN /* No mode-changing for telnet */
+ if (netconn) {
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+ if (ttnet == NET_TCPB) { /* But turn off Nagle */
+ extern int tcp_nodelay;
+ nodelay_sav = tcp_nodelay;
+ no_delay(ttyfd,1);
+ }
+#endif /* TCP_NODELAY */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = -1;
+ if (tvtflg == 0 && speed == ttspeed && flow == ttflow
+ /* && ttcarr == curcarr */ ) {
+ debug(F100,"ttpkt modes already set, skipping...","",0);
+ return(0); /* Already been called. */
+ }
+ if (flow != ttflow) {
+ if ((rc = tnsetflow(flow)) < 0)
+ return(rc);
+ ttflow = flow;
+ }
+ if (speed != ttspeed) {
+ if (speed <= 0)
+ speed = tnc_get_baud();
+ else if ((rc = tnc_set_baud(speed)) < 0)
+ return(rc);
+ ttspeed = speed;
+ }
+ tnc_set_datasize(8);
+ tnc_set_stopsize(stopbits);
+
+#ifdef HWPARITY
+ if (hwparity) {
+ switch (hwparity) {
+ case 'e': /* Even */
+ debug(F100,"ttres 8 bits + even parity","",0);
+ tnc_set_parity(3);
+ break;
+ case 'o': /* Odd */
+ debug(F100,"ttres 8 bits + odd parity","",0);
+ tnc_set_parity(2);
+ break;
+ case 'm': /* Mark */
+ debug(F100,"ttres 8 bits + invalid parity: mark","",0);
+ tnc_set_parity(4);
+ break;
+ case 's': /* Space */
+ debug(F100,"ttres 8 bits + invalid parity: space","",0);
+ tnc_set_parity(5);
+ break;
+ }
+ } else
+#endif /* HWPARITY */
+ {
+ tnc_set_parity(1); /* None */
+ }
+ tvtflg = 0;
+ return(0);
+ }
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+ tvtflg = 0;
+ return(0);
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+#ifndef Plan9
+ if (ttfdflg && !isatty(ttyfd)) return(0);
+#endif /* Plan9 */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifndef SVORPOSIX /* Berkeley, V7, etc. */
+#ifdef LPASS8
+/*
+ For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
+ after having previously set it to NONE without closing and reopening the
+ device. Unless there's something I overlooked below...
+*/
+ if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
+ debug(F101,"ttpkt executing horrible flow kludge","",0);
+ ttclos(0); /* Close it */
+ x = 0;
+ ttopen(ttnmsv,&x,ttmdm,0); /* Open it again */
+ }
+#endif /* LPASS8 */
+#endif /* SVORPOSIX */
+
+#ifdef COHERENT /* This must be vestigial since we */
+#undef SVORPOSIX /* reverse it a few lines below... */
+#endif /* COHERENT */
+
+ if (xflow != FLO_DIAL && xflow != FLO_DIAX)
+ ttflow = xflow; /* Now make this available too. */
+
+#ifndef NOLOCAL
+ if (xlocal) {
+ s2 = (int) (speed / 10L); /* Convert bps to cps */
+ debug(F101,"ttpkt calling ttsspd","",s2);
+ s = ttsspd(s2); /* Check and set the speed */
+ debug(F101,"ttpkt ttsspd result","",s);
+ carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
+ && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
+ tvtflg = 0; /* So ttvt() will work next time */
+ }
+#endif /* NOLOCAL */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifndef SVORPOSIX /* BSD section */
+ if (flow == FLO_RTSC || /* Hardware flow control */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tthflow(flow, 1, &ttraw);
+ debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ ttraw.sg_flags |= RAW; /* Enter raw mode */
+ } else if (flow == FLO_NONE) { /* No flow control */
+ debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ tthflow(flow, 0, &ttraw); /* Turn off any hardware f/c too */
+ ttraw.sg_flags |= RAW; /* Enter raw mode */
+ } else if (flow == FLO_KEEP) { /* Keep device's original setting */
+ debug(F100,"ttpkt keeping original TANDEM","",0);
+ ttraw.sg_flags &= ~TANDEM;
+ ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
+ /* NOTE: We should also handle hardware flow control here! */
+ }
+
+/* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
+
+ if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
+ debug(F100,"ttpkt turning on TANDEM","",0);
+ ttraw.sg_flags |= TANDEM; /* So ask for it. */
+
+#ifdef LPASS8 /* Can pass 8-bit data through? */
+/* If the LPASS8 local mode is available, then flow control can always */
+/* be used, even if parity is none and we are transferring 8-bit data. */
+/* But we only need to do all this if Xon/Xoff is requested. */
+/* BUT... this tends not to work through IP or LAT connections, terminal */
+/* servers, telnet, rlogin, etc, so it is currently disabled. */
+ x = LPASS8; /* If LPASS8 defined, then */
+ debug(F100,"ttpkt executing LPASS8 code","",0);
+ if (lmodef) { /* TIOCLBIS must be too. */
+ x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
+ if (x < 0) {
+ debug(F100,"ttpkt TIOCLBIS error","",0);
+ } else {
+ lmodef++;
+ debug(F100,"ttpkt TIOCLBIS ok","",0);
+ }
+ }
+/*
+ But if we use LPASS8 mode, we must explicitly turn off
+ terminal interrupts of all kinds.
+*/
+#ifdef TIOCGETC /* Not rawmode, */
+ if (tcharf && (xlocal == 0)) { /* must turn off */
+ tchnoi.t_intrc = -1; /* interrupt character */
+ tchnoi.t_quitc = -1; /* and quit character. */
+ tchnoi.t_startc = 17; /* Make sure xon */
+ tchnoi.t_stopc = 19; /* and xoff not ignored. */
+#ifndef NOBRKC
+ tchnoi.t_eofc = -1; /* eof character. */
+ tchnoi.t_brkc = -1; /* brk character. */
+#endif /* NOBRKC */
+ if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSETC failed","",0);
+ } else {
+ tcharf = 1;
+ debug(F100,"ttpkt TIOCSETC ok","",0);
+ }
+#ifdef COMMENT
+/* only for paranoid debugging */
+ if (tcharf) {
+ struct tchars foo;
+ char tchbuf[100];
+ ioctl(0,TIOCGETC,&foo);
+ sprintf(tchbuf,
+ "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
+ foo.t_intrc, foo.t_quitc, foo.t_startc,
+ foo.t_stopc, foo.t_eofc, foo.t_brkc);
+ debug(F110,"ttpkt chars",tchbuf,0);
+ }
+#endif /* COMMENT */
+ }
+ ttraw.sg_flags |= CBREAK; /* Needed for unknown reason */
+#endif /* TIOCGETC */
+
+/* Prevent suspend during packet mode */
+#ifdef TIOCGLTC /* Not rawmode, */
+ if (ltcharf && (xlocal == 0)) { /* must turn off */
+ ltchnoi.t_suspc = -1; /* suspend character */
+ ltchnoi.t_dsuspc = -1; /* and delayed suspend character */
+ if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSLTC failed","",0);
+ } else {
+ ltcharf = 1;
+ debug(F100,"ttpkt TIOCSLTC ok","",0);
+ }
+ }
+#endif /* TIOCGLTC */
+
+#else /* LPASS8 not defined */
+
+/* Previously, BSD-based implementations always */
+/* used rawmode for packets. Now, we use rawmode only if parity is NONE. */
+/* This allows the flow control requested above to actually work, but only */
+/* if the user asks for parity (which also means they get 8th-bit quoting). */
+
+ if (parity) { /* If parity, */
+ ttraw.sg_flags &= ~RAW; /* use cooked mode */
+#ifdef COMMENT
+/* WHY??? */
+ if (xlocal)
+#endif /* COMMENT */
+ ttraw.sg_flags |= CBREAK;
+ debug(F101,"ttpkt cooked, cbreak, parity","",parity);
+#ifdef TIOCGETC /* Not rawmode, */
+ if (tcharf && (xlocal == 0)) { /* must turn off */
+ tchnoi.t_intrc = -1; /* interrupt character */
+ tchnoi.t_quitc = -1; /* and quit character. */
+ tchnoi.t_startc = 17; /* Make sure xon */
+ tchnoi.t_stopc = 19; /* and xoff not ignored. */
+#ifndef NOBRKC
+ tchnoi.t_eofc = -1; /* eof character. */
+ tchnoi.t_brkc = -1; /* brk character. */
+#endif /* NOBRKC */
+ if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSETC failed","",0);
+ } else {
+ tcharf = 1;
+ debug(F100,"ttpkt TIOCSETC ok","",0);
+ }
+ }
+#endif /* TIOCGETC */
+#ifdef TIOCGLTC /* Not rawmode, */
+/* Prevent suspend during packet mode */
+ if (ltcharf && (xlocal == 0)) { /* must turn off */
+ ltchnoi.t_suspc = -1; /* suspend character */
+ ltchnoi.t_dsuspc = -1; /* and delayed suspend character */
+ if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSLTC failed","",0);
+ } else {
+ ltcharf = 1;
+ debug(F100,"ttpkt TIOCSLTC ok","",0);
+ }
+ }
+#endif /* TIOCGLTC */
+ } else { /* If no parity, */
+ ttraw.sg_flags |= RAW; /* must use 8-bit raw mode. */
+ debug(F101,"ttpkt setting rawmode, parity","",parity);
+ }
+#endif /* LPASS8 */
+ } /* End of Xon/Xoff section */
+
+ /* Don't echo, don't map CR to CRLF on output, don't fool with case */
+#ifdef LCASE
+ ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
+#else
+ ttraw.sg_flags &= ~(ECHO|CRMOD);
+#endif /* LCASE */
+
+#ifdef TOWER1
+ ttraw.sg_flags &= ~ANYP; /* Must set this on old Towers */
+#endif /* TOWER1 */
+
+#ifdef BELLV10
+ if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
+ return(-1);
+#else
+ errno = 0;
+ if (stty(ttyfd,&ttraw) < 0) { /* Set the new modes. */
+ debug(F101,"ttpkt stty failed","",errno);
+ return(-1);
+ }
+#endif /* BELLV10 */
+ debug(F100,"ttpkt stty ok","",0);
+
+#ifdef sony_news
+ x = xlocal ? km_ext : km_con; /* Put line in ASCII mode. */
+ if (x != -1) { /* Make sure we know original modes. */
+ x &= ~KM_TTYPE;
+ x |= KM_ASCII;
+ if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
+ perror("ttpkt can't set ASCII mode");
+ debug(F101,"ttpkt error setting ASCII mode","",x);
+ return(-1);
+ }
+ }
+ debug(F100,"ttpkt set ASCII mode ok","",0);
+#endif /* sony_news */
+
+ if (xlocal == 0) { /* Turn this off so we can read */
+ signal(SIGINT,SIG_IGN); /* Ctrl-C chars typed at console */
+ sigint_ign = 1;
+ }
+ tvtflg = 0; /* So ttvt() will work next time */
+ debug(F100,"ttpkt success","",0);
+ return(0);
+
+#endif /* Not ATTSV or POSIX */
+
+/* AT&T UNIX and POSIX */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef SVORPOSIX
+ if (flow == FLO_XONX) { /* Xon/Xoff */
+ ttraw.c_iflag |= (IXON|IXOFF);
+ tthflow(flow, 0, &ttraw);
+ } else if (flow == FLO_NONE) { /* None */
+ /* NOTE: We should also turn off hardware flow control here! */
+ ttraw.c_iflag &= ~(IXON|IXOFF);
+ tthflow(flow, 0, &ttraw);
+ } else if (flow == FLO_KEEP) { /* Keep */
+ ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
+ ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
+ /* NOTE: We should also handle hardware flow control here! */
+#ifdef POSIX_CRTSCTS
+/* In Linux case, we do this, which is unlikely to be portable */
+ ttraw.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */
+ ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
+#endif /* POSIX_CRTSCTS */
+ } else if (flow == FLO_RTSC || /* Hardware */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
+ tthflow(flow, 1, &ttraw);
+ }
+ ttraw.c_lflag &= ~(ICANON|ECHO);
+ ttraw.c_lflag &= ~ISIG; /* Do NOT check for interrupt chars */
+
+#ifndef OXOS
+#ifdef QNX
+ if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
+#endif /* QNX */
+#ifndef COHERENT
+ ttraw.c_lflag &= ~IEXTEN; /* Turn off ^O/^V processing */
+#endif /* COHERENT */
+#else /* OXOS */
+ ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+ ttraw.c_lflag |= NOFLSH; /* Don't flush */
+ ttraw.c_iflag |= IGNPAR; /* Ignore parity errors */
+#ifdef ATTSV
+#ifdef BSD44
+ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
+#else
+ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
+#endif /* BSD44 */
+#else /* POSIX */
+ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
+#endif /* ATTSV */
+ ttraw.c_oflag &= ~OPOST;
+ ttraw.c_cflag &= ~(CSIZE);
+ ttraw.c_cflag |= (CS8|CREAD|HUPCL);
+
+#ifdef CSTOPB
+ if (xlocal) {
+ if (stopbits == 2) {
+ ttraw.c_cflag |= CSTOPB; /* 2 stop bits */
+ debug(F100,"ttpkt 2 stopbits","",0);
+ } else if (stopbits == 1) {
+ ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */
+ debug(F100,"ttpkt 1 stopbit","",0);
+ }
+ }
+#endif /* CSTOPB */
+
+#ifdef HWPARITY
+ if (hwparity && xlocal) { /* Hardware parity */
+ ttraw.c_cflag |= PARENB; /* Enable parity */
+#ifdef COMMENT
+/* Uncomment this only if needed -- I don't think it is */
+ ttraw.c_cflag &= ~(CSIZE); /* Clear out character-size mask */
+ ttraw.c_cflag |= CS8; /* And set it to 8 */
+#endif /* COMMENT */
+#ifdef IGNPAR
+ ttraw.c_iflag |= IGNPAR; /* Don't discard incoming bytes */
+ debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
+#endif /* IGNPAR */
+ switch (hwparity) {
+ case 'e': /* Even */
+ ttraw.c_cflag &= ~(PARODD);
+ debug(F100,"ttpkt 8 bits + even parity","",0);
+ break;
+ case 'o': /* Odd */
+ ttraw.c_cflag |= PARODD;
+ debug(F100,"ttpkt 8 bits + odd parity","",0);
+ break;
+ case 'm': /* Mark */
+ case 's': /* Space */
+ /* PAREXT is mentioned in SVID but the details are not given. */
+ /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
+ debug(F100,"ttpkt 8 bits + invalid parity","",0);
+ break;
+ }
+ } else { /* We handle parity ourselves */
+#endif /* HWPARITY */
+ ttraw.c_cflag &= ~(PARENB); /* Don't enable parity */
+#ifdef HWPARITY
+ }
+#endif /* HWPARITY */
+
+#ifdef IX370
+ ttraw.c_cc[4] = 48; /* So Series/1 doesn't interrupt on every char */
+ ttraw.c_cc[5] = 1;
+#else
+#ifndef VEOF /* for DGUX this is VEOF, not VMIN */
+ ttraw.c_cc[4] = 1; /* [VMIN] return max of this many characters or */
+#else
+#ifndef OXOS
+#ifdef VMIN
+ ttraw.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ ttraw.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+#ifndef VEOL /* for DGUX this is VEOL, not VTIME */
+ ttraw.c_cc[5] = 0; /* [VTIME] when this many secs/10 expire w/no input */
+#else
+#ifndef OXOS
+#ifdef VTIME
+ ttraw.c_cc[VTIME] = 0;
+#endif /* VTIME */
+#else /* OXOS */
+ ttraw.c_time = 0;
+#endif /* OXOS */
+#endif /* VEOL */
+#endif /* IX370 */
+
+#ifdef VINTR /* Turn off interrupt character */
+ if (xlocal == 0) /* so ^C^C can break us out of */
+ ttraw.c_cc[VINTR] = 0; /* packet mode. */
+#endif /* VINTR */
+
+#ifdef Plan9
+ if (p9ttyparity('n') < 0)
+ return -1;
+#else
+#ifdef BSD44ORPOSIX
+ errno = 0;
+#ifdef BEOSORBEBOX
+ ttraw.c_cc[VMIN] = 0; /* DR7 can only poll. */
+#endif /* BEOSORBEBOX */
+
+#define TESTING234
+#ifdef TESTING234
+ if (1) {
+ debug(F100,"ttpkt TESTING234 rawmode","",0);
+
+ /* iflags */
+ ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
+ ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
+ ttraw.c_iflag |= IGNBRK;
+#ifdef IMAXBEL
+ ttraw.c_iflag &= ~IMAXBEL;
+#endif /* IMAXBEL */
+#ifdef IXANY
+ ttraw.c_iflag &= ~IXANY;
+#endif /* IXANY */
+#ifdef IUCLC
+ ttraw.c_iflag &= ~IUCLC;
+#endif /* IUCLC */
+
+ /* oflags */
+ ttraw.c_oflag &= ~OPOST;
+#ifdef OXTABS
+ ttraw.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+#ifdef ONOCR
+ ttraw.c_oflag &= ~ONOCR;
+#endif /* ONOCR */
+#ifdef ONLRET
+ ttraw.c_oflag &= ~ONLRET;
+#endif /* ONLRET */
+#ifdef ONLCR
+ ttraw.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+
+ /* lflags */
+ ttraw.c_lflag &= ~ECHO;
+#ifdef ECHOE
+ ttraw.c_lflag &= ~ECHOE;
+#endif /* ECHOE */
+#ifdef ECHONL
+ ttraw.c_lflag &= ~ECHONL;
+#endif /* ECHONL */
+#ifdef ECHOPRT
+ ttraw.c_lflag &= ~ECHOPRT;
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ ttraw.c_lflag &= ~ECHOKE;
+#endif /* ECHOKE */
+#ifdef ECHOCTL
+ ttraw.c_lflag &= ~ECHOCTL;
+#endif /* ECHOCTL */
+#ifdef ALTWERASE
+ ttraw.c_lflag &= ~ALTWERASE;
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ ttraw.c_lflag &= ~EXTPROC;
+#endif /* EXTPROC */
+ ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
+#ifdef NOKERNINFO
+ ttraw.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+ /* ttraw.c_lflag |= NOFLSH; */
+ ttraw.c_lflag &= ~NOFLSH;
+
+ /* cflags */
+ ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ ttraw.c_cflag |= CS8|CREAD;
+#ifdef VMIN
+ ttraw.c_cc[VMIN] = 1; /* Supposedly needed for AIX */
+#endif /* VMIN */
+
+ }
+#endif /* TESTING234 */
+
+ debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
+ debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
+ if (x < 0) {
+ debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
+ return(-1);
+ }
+#else /* BSD44ORPOSIX */
+ x = ioctl(ttyfd,TCSETAW,&ttraw);
+ debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
+ if (x < 0) { /* set new modes . */
+ debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
+ return(-1);
+ }
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+ tvtflg = 0;
+ debug(F100,"ttpkt ok","",0);
+ return(0);
+#endif /* ATTSV */
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+}
+
+/* T T S E T F L O W -- Set flow control immediately. */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+int
+ttsetflow(flow) int flow; {
+ if (ttyfd < 0) /* A channel must be open */
+ return(-1);
+
+ debug(F101,"ttsetflow flow","",flow);
+
+#ifdef TN_COMPORT
+ if (netconn && istncomport()) {
+ debug(F101,"ttsetflow net modem","",ttmdm);
+ return(tnsetflow(flow));
+ }
+#endif /* TN_COMPORT */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+#ifdef COMMENT
+ /* This seems to hurt... */
+ if (flow == FLO_KEEP)
+ return(0);
+#endif /* COMMENT */
+
+ if (flow == FLO_RTSC || /* Hardware flow control... */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tthflow(flow, 1, &ttraw);
+#ifndef SVORPOSIX
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+#else
+ ttraw.c_iflag &= ~(IXON|IXOFF);
+#endif /* SVORPOSIX */
+
+ } else if (flow == FLO_XONX) { /* Xon/Xoff... */
+
+#ifndef SVORPOSIX
+ ttraw.sg_flags |= TANDEM;
+#else
+ ttraw.c_iflag |= (IXON|IXOFF);
+#endif /* SVORPOSIX */
+ tthflow(FLO_RTSC, 0, &ttraw); /* Turn off hardware flow control */
+
+ } else if (flow == FLO_NONE) { /* No flow control */
+
+#ifndef SVORPOSIX
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+#else
+ ttraw.c_iflag &= ~(IXON|IXOFF);
+#endif /* SVORPOSIX */
+ tthflow(FLO_RTSC, 0, &ttraw); /* Turn off any hardware f/c too */
+ }
+
+/* Set the new modes... */
+
+#ifndef SVORPOSIX /* BSD and friends */
+#ifdef BELLV10
+ if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
+ return(-1);
+#else
+#ifndef MINIX2
+ if (stty(ttyfd,&ttraw) < 0)
+ return(-1);
+#endif /* MINIX2 */
+#endif /* BELLV10 */
+#else
+#ifdef BSD44ORPOSIX /* POSIX */
+ if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
+ return(-1);
+#else /* System V */
+ if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
+ return(-1);
+#endif /* BSD44ORPOSIX */
+#endif /* SVORPOSIX */
+ return(0);
+}
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+/* T T V T -- Condition communication device for use as virtual terminal. */
+
+int
+#ifdef CK_ANSIC
+ttvt(long speed, int flow)
+#else
+ttvt(speed,flow) long speed; int flow;
+#endif /* CK_ANSIC */
+/* ttvt */ {
+ int s, s2, x;
+
+ debug(F101,"ttvt ttyfd","",ttyfd);
+ debug(F101,"ttvt tvtflg","",tvtflg);
+ debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
+ debug(F111,"ttvt flow",ckitoa(ttflow),flow);
+ debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
+
+/* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
+/* Maybe it would be simpler to use it... */
+
+ ttpmsk = 0xff;
+#ifdef NOLOCAL
+ return(conbin((char)escchr));
+#else
+ if (ttyfd < 0) { /* Not open. */
+ if (ttchk() < 0)
+ return(-1);
+ else /* But maybe something buffered. */
+ return(0);
+ }
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+#ifdef NETCONN
+ if (netconn) {
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+ {
+ extern int tcp_nodelay;
+ if (ttnet == NET_TCPB) {
+ if (nodelay_sav > -1) {
+ no_delay(ttyfd,nodelay_sav);
+ nodelay_sav = -1;
+ }
+ }
+ }
+#endif /* TCP_NODELAY */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = -1;
+ if (tvtflg != 0 && speed == ttspeed && flow == ttflow
+ /* && ttcarr == curcarr */ ) {
+ debug(F100,"ttvt modes already set, skipping...","",0);
+ return(0); /* Already been called. */
+ }
+ if (flow != ttflow) {
+ if ((rc = tnsetflow(flow)) < 0)
+ return(rc);
+ ttflow = flow;
+ }
+ if (speed != ttspeed) {
+ if (speed <= 0)
+ speed = tnc_get_baud();
+ else if ((rc = tnc_set_baud(speed)) < 0)
+ return(rc);
+ ttspeed = speed;
+ }
+ tnc_set_datasize(8);
+ tnc_set_stopsize(stopbits);
+
+#ifdef HWPARITY
+ if (hwparity) {
+ switch (hwparity) {
+ case 'e': /* Even */
+ debug(F100,"ttres 8 bits + even parity","",0);
+ tnc_set_parity(3);
+ break;
+ case 'o': /* Odd */
+ debug(F100,"ttres 8 bits + odd parity","",0);
+ tnc_set_parity(2);
+ break;
+ case 'm': /* Mark */
+ debug(F100,"ttres 8 bits + invalid parity: mark","",0);
+ tnc_set_parity(4);
+ break;
+ case 's': /* Space */
+ debug(F100,"ttres 8 bits + invalid parity: space","",0);
+ tnc_set_parity(5);
+ break;
+ }
+ } else
+#endif /* HWPARITY */
+ {
+ tnc_set_parity(1); /* None */
+ }
+ tvtflg = 1;
+ return(0);
+ }
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+ tvtflg = 1; /* Network connections... */
+ debug(F100,"ttvt network connection, skipping...","",0);
+ return(0); /* ... require no special setup */
+ }
+#endif /* NETCONN */
+
+ if (tvtflg != 0 && speed == ttspeed && flow == ttflow
+ /* && ttcarr == curcarr */ )
+ {
+ debug(F100,"ttvt modes already set, skipping...","",0);
+ return(0); /* Already been called. */
+ }
+
+ if (ttfdflg
+#ifndef Plan9
+ && !isatty(ttyfd)
+#endif /* Plan9 */
+ ) {
+ debug(F100,"ttvt using external fd, skipping...","",0);
+ return(0);
+ }
+
+ debug(F100,"ttvt setting modes...","",0);
+
+ if (xlocal) { /* For external lines... */
+ s2 = (int) (speed / 10L);
+ s = ttsspd(s2); /* Check/set the speed */
+ carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
+ && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
+ } else
+ s = s2 = -1;
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifndef SVORPOSIX
+ /* Berkeley, V7, etc */
+ if (flow == FLO_RTSC || /* Hardware flow control */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tthflow(flow, 1, &tttvt);
+ debug(F100,"ttvt hard flow, TANDEM off","",0);
+ tttvt.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ } else if (flow == FLO_XONX) { /* Xon/Xoff flow control */
+ debug(F100,"ttvt TANDEM on","",0);
+ tttvt.sg_flags |= TANDEM; /* Ask for it. */
+ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
+ } else if (flow == FLO_NONE) {
+ debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
+ tttvt.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ tthflow(flow, 0, &tttvt); /* Turn off any hardware f/c too */
+ tttvt.sg_flags |= RAW; /* Enter raw mode */
+ } else if (flow == FLO_KEEP) { /* Keep device's original setting */
+ debug(F100,"ttvt keeping original TANDEM","",0);
+ tttvt.sg_flags &= ~TANDEM;
+ tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
+ /* NOTE: We should also handle hardware flow control here! */
+ }
+ tttvt.sg_flags |= RAW; /* Raw mode in all cases */
+#ifdef TOWER1
+ tttvt.sg_flags &= ~(ECHO|ANYP); /* No echo or parity */
+#else
+ tttvt.sg_flags &= ~ECHO; /* No echo */
+#endif /* TOWER1 */
+
+#ifdef BELLV10
+ if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
+ return(-1);
+#else
+ if (stty(ttyfd,&tttvt) < 0) /* Set the new modes */
+ return(-1);
+#endif /* BELLV10 */
+
+#else /* It is ATTSV or POSIX */
+
+ if (flow == FLO_XONX) { /* Software flow control */
+ tttvt.c_iflag |= (IXON|IXOFF); /* On if requested. */
+ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
+ debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
+ } else if (flow == FLO_NONE) { /* NONE */
+ tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
+ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
+ debug(F100,"ttvt SVORPOSIX flow NONE","",0);
+ } else if (flow == FLO_KEEP) {
+ tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
+ tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
+#ifdef POSIX_CRTSCTS
+ tttvt.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */
+ tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
+#endif /* POSIX_CRTSCTS */
+ debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
+ } else if (flow == FLO_RTSC || /* Hardware flow control */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */
+ tthflow(flow, 1, &tttvt);
+ debug(F100,"ttvt SVORPOSIX flow HARD","",0);
+ }
+#ifndef OXOS
+#ifdef COHERENT
+ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
+#else
+ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
+#endif /* COHERENT */
+#ifdef QNX
+ /* Needed for hwfc */
+ if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
+ tttvt.c_lflag |= IEXTEN;
+#endif /* QNX */
+#else /* OXOS */
+ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
+ tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+
+ tttvt.c_iflag |= (IGNBRK|IGNPAR);
+
+/* Stop bits */
+
+#ifdef CSTOPB
+ if (xlocal) {
+ if (stopbits == 2) {
+ tttvt.c_cflag |= CSTOPB; /* 2 stop bits */
+ debug(F100,"ttvt 2 stopbits","",0);
+ } else if (stopbits == 1) {
+ tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */
+ debug(F100,"ttvt 1 stopbit","",0);
+ }
+ }
+#endif /* CSTOPB */
+
+/* Parity */
+
+#ifdef HWPARITY
+ if (hwparity && xlocal) { /* Hardware parity */
+#ifdef COMMENT
+/* Uncomment this only if needed -- I don't think it is */
+ ttraw.c_cflag &= ~(CSIZE); /* Clear out character-size mask */
+ ttraw.c_cflag |= CS8; /* And set it to 8 */
+#endif /* COMMENT */
+#ifdef IGNPAR
+ debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
+ tttvt.c_iflag |= IGNPAR; /* Don't discard incoming bytes */
+#endif /* IGNPAR */
+ tttvt.c_cflag |= PARENB; /* Enable parity */
+
+ switch (hwparity) {
+ case 'e': /* Even */
+ tttvt.c_cflag &= ~(PARODD);
+ debug(F100,"ttvt 8 bits + even parity","",0);
+ break;
+ case 'o': /* Odd */
+ tttvt.c_cflag |= PARODD;
+ debug(F100,"ttvt 8 bits + odd parity","",0);
+ break;
+ case 'm': /* Mark */
+ case 's': /* Space */
+ /* PAREXT is mentioned in SVID but the details are not given. */
+ /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
+ debug(F100,"ttvt 8 bits + invalid parity","",0);
+ break;
+ }
+ } else { /* We handle parity ourselves */
+#endif /* HWPARITY */
+ tttvt.c_cflag &= ~(PARENB); /* Don't enable parity */
+#ifdef HWPARITY
+ }
+#endif /* HWPARITY */
+
+#ifdef ATTSV
+#ifdef BSD44
+ /* Things not to do... */
+ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
+#else
+ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
+#endif /* BSD44 */
+#else /* POSIX */
+ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
+#endif /* ATTSV */
+ tttvt.c_cflag &= ~(CSIZE); /* Zero out the char size field */
+ tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */
+ tttvt.c_oflag &= ~OPOST; /* Don't postprocess output */
+#ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
+ tttvt.c_cc[4] = 1;
+#else
+#ifndef OXOS
+#ifdef VMIN
+ tttvt.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ tttvt.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+#ifndef VEOL /* DGUX termio has VEOL at entry 5, see comment above */
+ tttvt.c_cc[5] = 0;
+#else
+#ifndef OXOS
+#ifdef VTIME
+ tttvt.c_cc[VTIME] = 0;
+#endif /* VTIME */
+#else /* OXOS */
+ tttvt.c_time = 0;
+#endif /* OXOS */
+#endif /* VEOL */
+
+#ifdef Plan9
+ if (p9ttyparity('n') < 0)
+ return -1;
+#else
+#ifdef BSD44ORPOSIX
+ errno = 0;
+#ifdef BEOSORBEBOX
+ tttvt.c_cc[VMIN] = 0; /* DR7 can only poll. */
+#endif /* BEOSORBEBOX */
+
+ x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
+ debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
+ if (x < 0) {
+ debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
+ return(-1);
+ }
+#else /* ATTSV */
+ x = ioctl(ttyfd,TCSETAW,&tttvt);
+ debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
+ if (x < 0) { /* set new modes . */
+ debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
+ return(-1);
+ }
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+#endif /* ATTSV */
+
+ ttspeed = speed; /* Done, remember how we were */
+ ttflow = flow; /* called, so we can decide how to */
+ tvtflg = 1; /* respond next time. */
+ debug(F100,"ttvt ok","",0);
+ return(0);
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+#endif /* NOLOCAL */
+}
+
+#ifndef NOLOCAL
+
+/* Serial speed department . . . */
+
+/*
+ SCO OSR5.0.x might or might not support high speeds. Sometimes they are not
+ defined in the header files but they are supported (e.g. when building with
+ UDK compiler rather than /bin/cc), sometimes vice versa. Even though 5.0.4
+ was the first release that came with high serial speeds standard, releases
+ back to 5.0.0 could use them if certain patches (or "supplements") were
+ applied to the SIO driver. Plus a lot of SCO installations run third-party
+ drivers.
+*/
+#ifdef CK_SCOV5
+#ifndef B38400
+#define B38400 0000017
+#endif /* B38400 */
+#ifndef B57600
+#define B57600 0000021
+#endif /* B57600 */
+#ifndef B76800
+#define B76800 0000022
+#endif /* B76800 */
+#ifndef B115200
+#define B115200 0000023
+#endif /* B115200 */
+#ifndef B230400
+#define B230400 0000024
+#endif /* B230400 */
+#ifndef B460800
+#define B460800 0000025
+#endif /* B460800 */
+#ifndef B921600
+#define B921600 0000026
+#endif /* B921600 */
+#endif /* CK_SCOV5 */
+/*
+ Plan 9's native speed setting interface lets you set anything you like,
+ but will fail if the hardware doesn't like it, so we allow all the common
+ speeds.
+*/
+#ifdef Plan9
+#ifndef B50
+#define B50 50
+#endif /* B50 */
+#ifndef B75
+#define B75 75
+#endif /* B75 */
+#ifndef B110
+#define B110 110
+#endif /* B110 */
+#ifndef B134
+#define B134 134
+#endif /* B134 */
+#ifndef B200
+#define B200 200
+#endif /* B200 */
+#ifndef B300
+#define B300 300
+#endif /* B300 */
+#ifndef B1200
+#define B1200 1200
+#endif /* B1200 */
+#ifndef B1800
+#define B1800 1800
+#endif /* B1800 */
+#ifndef B2400
+#define B2400 2400
+#endif /* B2400 */
+#ifndef B4800
+#define B4800 4800
+#endif /* B4800 */
+#ifndef B9600
+#define B9600 9600
+#endif /* B9600 */
+#ifndef B14400
+#define B14400 14400
+#endif /* B14400 */
+#ifndef B19200
+#define B19200 19200
+#endif /* B19200 */
+#ifndef B28800
+#define B28800 28800
+#endif /* B28800 */
+#ifndef B38400
+#define B38400 38400
+#endif /* B38400 */
+#ifndef B57600
+#define B57600 57600
+#endif /* B57600 */
+#ifndef B76800
+#define B76800 76800
+#endif /* B76800 */
+#ifndef B115200
+#define B115200 115200
+#endif /* B115200 */
+#ifndef B230400
+#define B230400 230400
+#endif /* B230400 */
+#ifndef B460800
+#define B460800 460800
+#endif /* B460800 */
+#ifndef B921600
+#define B921600 921600
+#endif /* B921600 */
+#endif /* Plan9 */
+
+/* T T S S P D -- Checks and sets transmission rate. */
+
+/* Call with speed in characters (not bits!) per second. */
+/* Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
+
+#ifdef USETCSETSPEED
+/*
+ The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
+ to be used as a speed to be set, rather than forcing a choice from a
+ predefined list. It seems to be peculiar to UnixWare 7.
+
+ These are the function codes to be passed to tc[gs]etspeed(),
+ but for some reason they don't seem to be picked up from termios.h.
+*/
+#ifndef TCS_ALL
+#define TCS_ALL 0
+#endif /* TCS_ALL */
+#ifndef TCS_IN
+#define TCS_IN 1
+#endif /* TCS_IN */
+#ifndef TCS_OUT
+#define TCS_OUT 2
+#endif /* TCS_OUT */
+#endif /* USETCSETSPEED */
+
+int
+ttsspd(cps) int cps; {
+ int x;
+#ifdef POSIX
+/* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
+ speed_t
+#else
+ int
+#endif /* POSIX */
+ s, s2;
+ int ok = 1; /* Speed check result, assume ok */
+
+#ifdef OLINUXHISPEED
+ unsigned int spd_flags = 0;
+ struct serial_struct serinfo;
+#endif /* OLINUXHISPEED */
+
+ debug(F101,"ttsspd cps","",cps);
+ debug(F101,"ttsspd ttyfd","",ttyfd);
+ debug(F101,"ttsspd xlocal","",xlocal);
+
+ if (ttyfd < 0 || xlocal == 0) /* Don't set speed on console */
+ return(0);
+
+#ifdef NETCONN
+ if (netconn) {
+#ifdef TN_COMPORT
+ if (istncomport())
+ return(tnc_set_baud(cps * 10));
+ else
+#endif /* TN_COMPORT */
+ return(0);
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+ if (cps < 0) return(-1);
+ s = s2 = 0; /* NB: s and s2 might be unsigned */
+
+#ifdef USETCSETSPEED
+
+ s = cps * 10L;
+
+ x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
+ debug(F101,"ttsspd tcgetattr","",x);
+ if (x < 0)
+ return(-1);
+ debug(F101,"ttsspd TCSETSPEED speed","",s);
+
+ errno = 0;
+ if (s == 8880L) { /* 75/1200 split speed requested */
+ tcsetspeed(TCS_IN, &ttcur, 1200L);
+ tcsetspeed(TCS_OUT, &ttcur, 75L);
+ } else
+ tcsetspeed(TCS_ALL, &ttcur, s); /* Put new speed in structs */
+#ifdef DEBUG
+ if (errno & deblog) {
+ debug(F101,"ttsspd TCSETSPEED errno","",errno);
+ }
+#endif /* DEBUG */
+
+#ifdef COMMENT
+ tcsetspeed(TCS_ALL, &ttraw, s);
+ tcsetspeed(TCS_ALL, &tttvt, s);
+ tcsetspeed(TCS_ALL, &ttold, s);
+#else
+ if (s == 8880L) { /* 75/1200 split speed requested */
+ tcsetspeed(TCS_IN, &ttraw, 1200L);
+ tcsetspeed(TCS_OUT, &ttraw, 75L);
+ tcsetspeed(TCS_IN, &tttvt, 1200L);
+ tcsetspeed(TCS_OUT, &tttvt, 75L);
+ tcsetspeed(TCS_IN, &ttold, 1200L);
+ tcsetspeed(TCS_OUT, &ttold, 75L);
+ } else {
+ tcsetspeed(TCS_ALL, &ttraw, s);
+ tcsetspeed(TCS_ALL, &tttvt, s);
+ tcsetspeed(TCS_ALL, &ttold, s);
+ }
+#endif /* COMMENT */
+
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
+ debug(F101,"ttsspd tcsetattr","",x);
+ if (x < 0)
+ return(-1);
+
+#else /* Not USETCSETSPEED */
+
+ /* First check that the given speed is valid. */
+
+ switch (cps) {
+#ifndef MINIX
+ case 0: s = B0; break;
+ case 5: s = B50; break;
+ case 7: s = B75; break;
+#endif /* MINIX */
+ case 11: s = B110; break;
+#ifndef MINIX
+ case 13: s = B134; break;
+ case 15: s = B150; break;
+ case 20: s = B200; break;
+#endif /* MINIX */
+ case 30: s = B300; break;
+#ifndef MINIX
+ case 60: s = B600; break;
+#endif /* MINIX */
+ case 120: s = B1200; break;
+#ifndef MINIX
+ case 180: s = B1800; break;
+#endif /* MINIX */
+ case 240: s = B2400; break;
+ case 480: s = B4800; break;
+#ifndef MINIX
+ case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
+#endif /* MINIX */
+#ifdef B7200
+ case 720: s = B7200; break;
+#endif /* B7200 */
+ case 960: s = B9600; break;
+#ifdef B14400
+ case 1440: s = B14400; break;
+#endif /* B14400 */
+#ifdef B19200
+ case 1920: s = B19200; break;
+#else
+#ifdef EXTA
+ case 1920: s = EXTA; break;
+#endif /* EXTA */
+#endif /* B19200 */
+#ifdef B28800
+ case 2880: s = B28800; break;
+#endif /* B28800 */
+#ifdef B38400
+ case 3840: s = B38400;
+#ifdef OLINUXHISPEED
+ spd_flags = ~ASYNC_SPD_MASK; /* Nonzero, but zero flags */
+#endif /* OLINUXHISPEED */
+ break;
+#else /* B38400 not defined... */
+#ifdef EXTB
+ case 3840: s = EXTB; break;
+#endif /* EXTB */
+#endif /* B38400 */
+
+#ifdef HPUX
+#ifdef _B57600
+ case 5760: s = _B57600; break;
+#endif /* _B57600 */
+#ifdef _B115200
+ case 11520: s = _B115200; break;
+#endif /* _B115200 */
+#else
+#ifdef OLINUXHISPEED
+/*
+ This bit from <carlo@sg.tn.tudelft.nl>:
+ "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
+ setting the speed to 38400 will set the custom speed (and ttgspd returns
+ 38400), but speeds 57600 and 115200 won't work any more because I didn't
+ want to mess up the speed flags when someone is doing sophisticated stuff
+ like custom speeds..."
+*/
+ case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
+ case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
+#else
+#ifdef B57600
+ case 5760: s = B57600; break;
+#endif /* B57600 */
+#ifdef B76800
+ case 7680: s = B76800; break;
+#endif /* B76800 */
+#ifdef B115200
+ case 11520: s = B115200; break;
+#endif /* B115200 */
+#endif /* OLINUXHISPEED */
+#ifdef B153600
+ case 15360: s = B153600; break;
+#endif /* B153600 */
+#ifdef B230400
+ case 23040: s = B230400; break;
+#endif /* B230400 */
+#ifdef B307200
+ case 30720: s = B307200; break;
+#endif /* B307200 */
+#ifdef B460800
+ case 46080: s = B460800; break;
+#endif /* 460800 */
+#ifdef B921600
+ case 92160: s = B921600; break;
+#endif /* B921600 */
+#endif /* HPUX */
+ default:
+ ok = 0; /* Good speed not found, so not ok */
+ break;
+ }
+ debug(F101,"ttsspd ok","",ok);
+ debug(F101,"ttsspd s","",s);
+
+ if (!ok) {
+ debug(F100,"ttsspd fails","",0);
+ return(-1);
+ } else {
+ if (!s2) s2 = s; /* Set input speed */
+#ifdef Plan9
+ if (p9ttsspd(cps) < 0)
+ return(-1);
+#else
+#ifdef BSD44ORPOSIX
+ x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
+ debug(F101,"ttsspd tcgetattr","",x);
+ if (x < 0)
+ return(-1);
+#ifdef OLINUXHISPEED
+ debug(F101,"ttsspd spd_flags","",spd_flags);
+ if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
+ if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
+ debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
+ return(-1);
+ } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
+ serinfo.flags &= ~ASYNC_SPD_MASK;
+ serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
+ if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
+ return(-1);
+ }
+#endif /* OLINUXHISPEED */
+ cfsetospeed(&ttcur,s);
+ cfsetispeed(&ttcur,s2);
+ cfsetospeed(&ttraw,s);
+ cfsetispeed(&ttraw,s2);
+ cfsetospeed(&tttvt,s);
+ cfsetispeed(&tttvt,s2);
+ cfsetospeed(&ttold,s);
+ cfsetispeed(&ttold,s2);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F101,"ttsspd tcsetattr","",x);
+ if (x < 0) return(-1);
+#else
+#ifdef ATTSV
+ if (cps == 888) return(-1); /* No split speeds, sorry. */
+ x = ioctl(ttyfd,TCGETA,&ttcur);
+ debug(F101,"ttsspd TCGETA ioctl","",x);
+ if (x < 0) return(-1);
+ ttcur.c_cflag &= ~CBAUD;
+ ttcur.c_cflag |= s;
+ tttvt.c_cflag &= ~CBAUD;
+ tttvt.c_cflag |= s;
+ ttraw.c_cflag &= ~CBAUD;
+ ttraw.c_cflag |= s;
+ ttold.c_cflag &= ~CBAUD;
+ ttold.c_cflag |= s;
+ x = ioctl(ttyfd,TCSETAW,&ttcur);
+ debug(F101,"ttsspd TCSETAW ioctl","",x);
+ if (x < 0) return(-1);
+#else
+#ifdef BELLV10
+ x = ioctl(ttyfd,TIOCGDEV,&tdcur);
+ debug(F101,"ttsspd TIOCGDEV ioctl","",x);
+ if (x < 0) return(-1);
+ tdcur.ispeed = s2;
+ tdcur.ospeed = s;
+ errno = 0;
+ ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
+ debug(F101,"ttsspd BELLV10 ioctl","",ok);
+ if (ok < 0) {
+ perror(ttnmsv);
+ debug(F101,"ttsspd BELLV10 errno","",ok);
+ return(-1);
+ }
+#else
+ x = gtty(ttyfd,&ttcur);
+ debug(F101,"ttsspd gtty","",x);
+ if (x < 0) return(-1);
+ ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
+ tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
+ ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
+ ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
+ x = stty(ttyfd,&ttcur);
+ debug(F101,"ttsspd stty","",x);
+ if (x < 0) return(-1);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+ }
+ return(1); /* Return 1 = success. */
+#endif /* USETCSETSPEED */
+}
+
+#endif /* NOLOCAL */
+
+/* C O N G S P D - Get speed of console terminal */
+
+long
+congspd() {
+/*
+ This is a disgusting hack. The right way to do this would be to pass an
+ argument to ttgspd(), but then we'd need to change the Kermit API and
+ all of the ck?tio.c modules. (Currently used only for rlogin.)
+*/
+ int t1;
+ long spd;
+#ifdef NETCONN
+ int t2 = netconn;
+ netconn = 0;
+#endif /* NETCONN */
+ t1 = ttyfd;
+ ttyfd = -1;
+ spd = ttgspd();
+ debug(F101,"congspd","",spd);
+#ifdef NETCONN
+ netconn = t2;
+#endif /* NETCONN */
+ ttyfd = t1;
+ return(spd);
+}
+
+/* T T S P D L I S T -- Get list of serial speeds allowed on this platform */
+
+#define NSPDLIST 64
+static long spdlist[NSPDLIST];
+/*
+ As written, this picks up the speeds known at compile time, and thus
+ apply to the system where C-Kermit was built, rather than to the one where
+ it is running. Suggestions for improvement are always welcome.
+*/
+long *
+ttspdlist() {
+ int i;
+ for (i = 0; i < NSPDLIST; i++) /* Initialize the list */
+ spdlist[i] = -1L;
+ i = 1;
+
+#ifdef USETCSETSPEED /* No way to find out what's legal */
+ debug(F100,"ttspdlist USETCSETSPEED","",0);
+ spdlist[i++] = 50L;
+#ifndef UW7
+ spdlist[i++] = 75L;
+#endif /* UW7 */
+ spdlist[i++] = 110L;
+#ifndef UW7
+ spdlist[i++] = 134L;
+#endif /* UW7 */
+ spdlist[i++] = 150L;
+ spdlist[i++] = 200L;
+ spdlist[i++] = 300L;
+ spdlist[i++] = 600L;
+ spdlist[i++] = 1200L;
+ spdlist[i++] = 1800L;
+ spdlist[i++] = 2400L;
+ spdlist[i++] = 4800L;
+ spdlist[i++] = 8880L;
+ spdlist[i++] = 9600L;
+ spdlist[i++] = 14400L;
+ spdlist[i++] = 19200L;
+ spdlist[i++] = 28800L;
+#ifndef UW7
+ spdlist[i++] = 33600L;
+#endif /* UW7 */
+ spdlist[i++] = 38400L;
+ spdlist[i++] = 57600L;
+ spdlist[i++] = 76800L;
+ spdlist[i++] = 115200L;
+#ifndef UW7
+ spdlist[i++] = 153600L;
+ spdlist[i++] = 230400L;
+ spdlist[i++] = 307200L;
+ spdlist[i++] = 460800L;
+ spdlist[i++] = 921600L;
+#endif /* UW7 */
+
+#else /* USETCSETSPEED */
+
+ debug(F100,"ttspdlist no USETCSETSPEED","",0);
+
+#ifdef B50
+ debug(F101,"ttspdlist B50","",B50);
+ spdlist[i++] = 50L;
+#endif /* B50 */
+#ifdef B75
+ debug(F101,"ttspdlist B75","",B75);
+ spdlist[i++] = 75L;
+#endif /* B75 */
+#ifdef B110
+ debug(F101,"ttspdlist B110","",B110);
+ spdlist[i++] = 110L;
+#endif /* B110 */
+#ifdef B134
+ debug(F101,"ttspdlist B134","",B134);
+ spdlist[i++] = 134L;
+#endif /* B134 */
+#ifdef B150
+ debug(F101,"ttspdlist B150","",B150);
+ spdlist[i++] = 150L;
+#endif /* B150 */
+#ifdef B200
+ debug(F101,"ttspdlist B200","",B200);
+ spdlist[i++] = 200L;
+#endif /* B200 */
+#ifdef B300
+ debug(F101,"ttspdlist B300","",B300);
+ spdlist[i++] = 300L;
+#endif /* B300 */
+#ifdef B600
+ debug(F101,"ttspdlist B600","",B600);
+ spdlist[i++] = 600L;
+#endif /* B600 */
+#ifdef B1200
+ debug(F101,"ttspdlist B1200","",B1200);
+ spdlist[i++] = 1200L;
+#endif /* B1200 */
+#ifdef B1800
+ debug(F101,"ttspdlist B1800","",B1800);
+ spdlist[i++] = 1800L;
+#endif /* B1800 */
+#ifdef B2400
+ debug(F101,"ttspdlist B2400","",B2400);
+ spdlist[i++] = 2400L;
+#endif /* B2400 */
+#ifdef B4800
+ debug(F101,"ttspdlist B4800","",B4800);
+ spdlist[i++] = 4800L;
+#endif /* B4800 */
+#ifdef B9600
+ debug(F101,"ttspdlist B9600","",B9600);
+ spdlist[i++] = 9600L;
+#endif /* B9600 */
+#ifdef B14400
+ debug(F101,"ttspdlist B14400","",B14400);
+ spdlist[i++] = 14400L;
+#endif /* B14400 */
+#ifdef B19200
+ debug(F101,"ttspdlist B19200","",B19200);
+ spdlist[i++] = 19200L;
+#else
+#ifdef EXTA
+ debug(F101,"ttspdlist EXTA","",EXTA);
+ spdlist[i++] = 19200L;
+#endif /* EXTA */
+#endif /* B19200 */
+#ifdef B28800
+ debug(F101,"ttspdlist B28800","",B28800);
+ spdlist[i++] = 28800L;
+#endif /* B28800 */
+#ifdef B33600
+ debug(F101,"ttspdlist B33600","",B33600);
+ spdlist[i++] = 33600L;
+#endif /* B33600 */
+#ifdef B38400
+ debug(F101,"ttspdlist B38400","",B38400);
+ spdlist[i++] = 38400L;
+#else
+#ifdef EXTB
+ debug(F101,"ttspdlist EXTB","",EXTB);
+ spdlist[i++] = 38400L;
+#endif /* EXTB */
+#endif /* B38400 */
+#ifdef _B57600
+ debug(F101,"ttspdlist _B57600","",_B57600);
+ spdlist[i++] = 57600L;
+#else
+#ifdef B57600
+ debug(F101,"ttspdlist B57600","",B57600);
+ spdlist[i++] = 57600L;
+#endif /* B57600 */
+#endif /* _B57600 */
+#ifdef B76800
+ debug(F101,"ttspdlist B76800","",B76800);
+ spdlist[i++] = 76800L;
+#endif /* B76800 */
+#ifdef _B115200
+ debug(F101,"ttspdlist _B115200","",_B115200);
+ spdlist[i++] = 115200L;
+#else
+#ifdef B115200
+ debug(F101,"ttspdlist B115200","",B115200);
+ spdlist[i++] = 115200L;
+#endif /* B115200 */
+#endif /* _B115200 */
+#ifdef B153600
+ debug(F101,"ttspdlist B153600","",B153600);
+ spdlist[i++] = 153600L;
+#endif /* B153600 */
+#ifdef B230400
+ debug(F101,"ttspdlist B230400","",B230400);
+ spdlist[i++] = 230400L;
+#endif /* B230400 */
+#ifdef B307200
+ debug(F101,"ttspdlist B307200","",B307200);
+ spdlist[i++] = 307200L;
+#endif /* B307200 */
+#ifdef B460800
+ debug(F101,"ttspdlist B460800","",B460800);
+ spdlist[i++] = 460800L;
+#endif /* B460800 */
+#ifdef B921600
+ debug(F101,"ttspdlist B921600","",B921600);
+ spdlist[i++] = 921600L;
+#endif /* B921600 */
+#endif /* USETCSETSPEED */
+ spdlist[0] = i - 1; /* Return count in 0th element */
+ debug(F111,"ttspdlist spdlist","0",spdlist[0]);
+ return((long *)spdlist);
+}
+
+/* T T G S P D - Get speed of currently selected tty line */
+
+/*
+ Unreliable. After SET LINE, it returns an actual speed, but not necessarily
+ the real speed. On some systems, it returns the line's nominal speed, from
+ /etc/ttytab. Even if you SET SPEED to something else, this function might
+ not notice.
+*/
+long
+ttgspd() { /* Get current serial device speed */
+#ifdef NOLOCAL
+ return(-1L);
+#else
+#ifdef POSIX
+ speed_t /* Should be unsigned */
+#else
+ int /* Isn't unsigned */
+#endif /* POSIX */
+ s;
+ int x;
+ long ss;
+#ifdef OLINUXHISPEED
+ unsigned int spd_flags = 0;
+ struct serial_struct serinfo;
+#endif /* OLINUXHISPEED */
+
+#ifdef NETCONN
+ if (netconn) {
+#ifdef TN_COMPORT
+ if (istncomport())
+ return(tnc_get_baud());
+ else
+#endif /* TN_COMPORT */
+ return(-1); /* -1 if network connection */
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(-1);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-1);
+#endif /* NETPTY */
+
+ debug(F101,"ttgspd ttyfd","",ttyfd);
+
+#ifdef USETCSETSPEED
+
+ x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
+ debug(F101,"ttgspd tcgetattr","",x);
+ if (x < 0)
+ return(-1);
+ errno = 0;
+ s = tcgetspeed(TCS_ALL, &ttcur);
+ debug(F101,"ttsspd TCGETSPEED speed","",s);
+ if (s == 0) {
+ long s1, s2;
+ s1 = tcgetspeed(TCS_IN, &ttcur);
+ s2 = tcgetspeed(TCS_OUT, &ttcur);
+ if (s1 == 1200L && s2 == 75L)
+ return(8880L);
+ }
+#ifdef DEBUG
+ if (errno & deblog) {
+ debug(F101,"ttsspd TCGETSPEED errno","",errno);
+ }
+#endif /* DEBUG */
+ return(s);
+
+#else /* Not USETCSETSPEED */
+
+#ifdef Plan9
+ if (ttyfd < 0)
+ ss = -1;
+ else
+ ss = ttylastspeed;
+#else
+#ifdef OLINUXHISPEED
+ debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
+#endif /* OLINUXHISPEED */
+
+ if (ttyfd < 0) {
+#ifdef BSD44ORPOSIX
+ s = cfgetospeed(&ccold);
+ debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
+#else
+#ifdef ATTSV
+ s = ccold.c_cflag & CBAUD;
+ debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
+#else
+ s = ccold.sg_ospeed; /* (obtained by congm()) */
+ debug(F101,"ttgspd sg_ospeed 1","",s);
+#endif /* ATTSV */
+#endif /* BSD44POSIX */
+
+ } else {
+#ifdef BSD44ORPOSIX
+ if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
+ s = cfgetospeed(&ttcur);
+ debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
+#ifdef OLINUXHISPEED
+ if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
+ spd_flags = serinfo.flags & ASYNC_SPD_MASK;
+ debug(F101,"ttgspd spd_flags","",spd_flags);
+#endif /* OLINUXHISPEED */
+#else
+#ifdef ATTSV
+ x = ioctl(ttyfd,TCGETA,&ttcur);
+ debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
+ debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
+ if (x < 0) return(-1);
+ s = ttcur.c_cflag & CBAUD;
+ debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
+#else
+#ifdef BELLV10
+ x = ioctl(ttyfd,TIOCGDEV,&tdcur);
+ debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
+ if (x < 0) return(-1);
+ s = tdcur.ospeed;
+ debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
+#else
+ x = gtty(ttyfd,&ttcur);
+ debug(F101,"ttgspd gtty 2 x","",x);
+ debug(F101,"ttgspd gtty 2 errno","",errno);
+ if (x < 0) return(-1);
+ s = ttcur.sg_ospeed;
+ debug(F101,"ttgspd gtty 2 speed","",s);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ }
+ debug(F101,"ttgspd code","",s);
+#ifdef OLINUXHISPEED
+ debug(F101,"ttgspd spd_flags","",spd_flags);
+#endif /* OLINUXHISPEED */
+ switch (s) {
+#ifdef B0
+ case B0: ss = 0L; break;
+#endif /* B0 */
+
+#ifndef MINIX
+/*
+ MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
+ etc, making for many "duplicate case in switch" errors, which are fatal.
+*/
+#ifdef B50
+ case B50: ss = 50L; break;
+#endif /* B50 */
+#ifdef B75
+ case B75: ss = 75L; break;
+#endif /* B75 */
+#endif /* MINIX */
+
+#ifdef B110
+ case B110: ss = 110L; break;
+#endif /* B110 */
+
+#ifndef MINIX
+#ifdef B134
+ case B134: ss = 134L; break;
+#endif /* B134 */
+#ifdef B150
+ case B150: ss = 150L; break;
+#endif /* B150 */
+#endif /* MINIX */
+
+#ifdef B200
+ case B200: ss = 200L; break;
+#endif /* B200 */
+
+#ifdef B300
+ case B300: ss = 300L; break;
+#endif /* B300 */
+
+#ifdef B600
+ case B600: ss = 600L; break;
+#endif /* B600 */
+
+#ifdef B1200
+ case B1200: ss = 1200L; break;
+#endif /* B1200 */
+
+#ifdef B1800
+ case B1800: ss = 1800L; break;
+#endif /* B1800 */
+
+#ifdef B2400
+ case B2400: ss = 2400L; break;
+#endif /* B2400 */
+
+#ifdef B4800
+ case B4800: ss = 4800L; break;
+#endif /* B4800 */
+
+#ifdef B7200
+ case B7200: ss = 7200L; break;
+#endif /* B7200 */
+
+#ifdef B9600
+ case B9600: ss = 9600L; break;
+#endif /* B9600 */
+
+#ifdef B19200
+ case B19200: ss = 19200L; break;
+#else
+#ifdef EXTA
+ case EXTA: ss = 19200L; break;
+#endif /* EXTA */
+#endif /* B19200 */
+
+#ifndef MINIX
+#ifdef B38400
+ case B38400:
+ ss = 38400L;
+#ifdef OLINUXHISPEED
+ switch(spd_flags) {
+ case ASYNC_SPD_HI: ss = 57600L; break;
+ case ASYNC_SPD_VHI: ss = 115200L; break;
+ }
+#endif /* OLINUXHISPEED */
+ break;
+#else
+#ifdef EXTB
+ case EXTB: ss = 38400L; break;
+#endif /* EXTB */
+#endif /* B38400 */
+#endif /* MINIX */
+
+#ifdef HPUX
+#ifdef _B57600
+ case _B57600: ss = 57600L; break;
+#endif /* _B57600 */
+#ifdef _B115200
+ case _B115200: ss = 115200L; break;
+#endif /* _B115200 */
+#else
+#ifdef B57600
+ case B57600: ss = 57600L; break;
+#endif /* B57600 */
+#ifdef B76800
+ case B76800: ss = 76800L; break;
+#endif /* B76800 */
+#ifdef B115200
+ case B115200: ss = 115200L; break;
+#endif /* B115200 */
+#ifdef B153600
+ case B153600: ss = 153600L; break;
+#endif /* B153600 */
+#ifdef B230400
+ case B230400: ss = 230400L; break;
+#endif /* B230400 */
+#ifdef B307200
+ case B307200: ss = 307200L; break;
+#endif /* B307200 */
+#ifdef B460800
+ case B460800: ss = 460800L; break;
+#endif /* B460800 */
+#endif /* HPUX */
+#ifdef B921600
+ case B921600: ss = 921600L; break;
+#endif /* B921600 */
+ default:
+ ss = -1; break;
+ }
+#endif /* Plan9 */
+ debug(F101,"ttgspd speed","",ss);
+ return(ss);
+
+#endif /* USETCSETSPEED */
+#endif /* NOLOCAL */
+}
+#ifdef MINIX2 /* Another hack alert */
+#define MINIX
+#endif /* MINIX2 */
+
+/*
+ FIONREAD data type... This has been defined as "long" for many, many
+ years, and it worked OK until 64-bit platforms appeared. Thus we use
+ int for 64-bit platforms, but keep long for the others. If we changed
+ the default PEEKTYPE to int, this would probably break 16-bit builds
+ (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
+ of which we have no way of testing any more. Therefore, do not change
+ the default definition of PEEKTYPE -- only add exceptions to it as needed.
+*/
+#ifdef COHERENT
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+/* #define FIONREAD TIOCQUERY */
+/* #define PEEKTYPE int */
+#else /* Not COHERENT... */
+
+#ifdef OSF32 /* Digital UNIX 3.2 or higher */
+#define PEEKTYPE int
+#else
+#define PEEKTYPE long /* Elsewhere (see notes above) */
+#endif /* OSF32 */
+#endif /* COHERENT */
+
+/* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
+
+#ifdef MYREAD
+
+/* Private buffer for myread() and its companions. Not for use by anything
+ * else. ttflui() is allowed to reset them to initial values. ttchk() is
+ * allowed to read my_count.
+ *
+ * my_item is an index into mybuf[]. Increment it *before* reading mybuf[].
+ *
+ * A global parity mask variable could be useful too. We could use it to
+ * let myread() strip the parity on its own, instead of stripping sign
+ * bits as it does now.
+ */
+#ifdef BIGBUFOK
+#define MYBUFLEN 32768
+#else
+#ifdef pdp11
+#define MYBUFLEN 256
+#else
+#define MYBUFLEN 1024
+#endif /* pdp11 */
+#endif /* BIGBUFOK */
+
+#ifdef ANYX25
+#undef MYBUFLEN
+#define MYBUFLEN 256
+/*
+ On X.25 connections, there is an extra control byte at the beginning.
+*/
+static CHAR x25buf[MYBUFLEN+1]; /* Communication device input buffer */
+static CHAR *mybuf = x25buf+1;
+#else
+static CHAR mybuf[MYBUFLEN];
+#endif /* ANYX25 */
+
+static int my_count = 0; /* Number of chars still in mybuf */
+static int my_item = -1; /* Last index read from mybuf[] */
+
+/* T T P E E K -- Peek into our internal communications input buffers. */
+
+/*
+ NOTE: This routine is peculiar to UNIX, and is used only by the
+ select()-based CONNECT module, ckucns.c. It need not be replicated in
+ the ck?tio.c of other platforms.
+*/
+int
+ttpeek() {
+#ifdef TTLEBUF
+ int rc = 0;
+ if (ttpush >= 0)
+ rc++;
+ rc += le_inbuf();
+ if (rc > 0)
+ return(rc);
+ else
+#endif /* TTLEBUF */
+
+#ifdef MYREAD
+ return(my_count);
+#else
+ return(0);
+#endif /* MYREAD */
+}
+
+/* myread() -- Efficient read of one character from communications line.
+ *
+ * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
+ * bytes from connection, so when the connection is encrypted, these bytes
+ * must be decrypted.
+ *
+ * Uses a private buffer to minimize the number of expensive read() system
+ * calls. Essentially performs the equivalent of read() of 1 character, which
+ * is then returned. By reading all available input from the system buffers
+ * to the private buffer in one chunk, and then working from this buffer, the
+ * number of system calls is reduced in any case where more than one character
+ * arrives during the processing of the previous chunk, for instance high
+ * baud rates or network type connections where input arrives in packets.
+ * If the time needed for a read() system call approaches the time for more
+ * than one character to arrive, then this mechanism automatically compensates
+ * for that by performing bigger read()s less frequently. If the system load
+ * is high, the same mechanism compensates for that too.
+ *
+ * myread() is a macro that returns the next character from the buffer. If the
+ * buffer is empty, mygetbuf() is called. See mygetbuf() for possible error
+ * returns.
+ *
+ * This should be efficient enough for any one-character-at-a-time loops.
+ * For even better efficiency you might use memcpy()/bcopy() or such between
+ * buffers (since they are often better optimized for copying), but it may not
+ * be worth it if you have to take an extra pass over the buffer to strip
+ * parity and check for CTRL-C anyway.
+ *
+ * Note that if you have been using myread() from another program module, you
+ * may have some trouble accessing this macro version and the private variables
+ * it uses. In that case, just add a function in this module, that invokes the
+ * macro.
+ */
+#define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
+
+/* Specification: Push back up to one character onto myread()'s queue.
+ *
+ * This implementation: Push back characters into mybuf. At least one character
+ * must have been read through myread() before myunrd() may be used. After
+ * EOF or read error, again, myunrd() can not be used. Sometimes more than
+ * one character can be pushed back, but only one character is guaranteed.
+ * Since a previous myread() must have read its character out of mybuf[],
+ * that guarantees that there is space for at least one character. If push
+ * back was really needed after EOF, a small addition could provide that.
+ *
+ * As of 02/2007 myunrd() is used by ttinl().
+ */
+VOID
+#ifdef CK_ANSIC
+myunrd(CHAR ch)
+#else
+myunrd(ch) CHAR ch;
+#endif /* CK_ANSIC */
+{
+ if (my_item >= 0) {
+ mybuf[my_item--] = ch;
+ ++my_count;
+ }
+}
+
+/* T T P U S H B A C K -- Put n bytes back into the myread buffer */
+
+static CHAR * pushbuf = NULL;
+/* static int pushed = 0; */
+
+int
+ttpushback(s,n) CHAR * s; int n; {
+ debug(F101,"ttpushback n","",n);
+ if (pushbuf || n > MYBUFLEN || n < 1)
+ return(-1);
+ debug(F101,"ttpushback my_count","",my_count);
+ if (my_count > 0) {
+ if (!(pushbuf = (CHAR *)malloc(n+1)))
+ return(-1);
+ memcpy(pushbuf,mybuf,my_count);
+ /* pushed = my_count; */ /* (set but never used) */
+ }
+ memcpy(mybuf,s,n);
+ my_count = n;
+ my_item = -1;
+ return(0);
+}
+
+/* mygetbuf() -- Fill buffer for myread() and return first character.
+ *
+ * This function is what myread() uses when it can't get the next character
+ * directly from its buffer. First, it calls a system dependent myfillbuf()
+ * to read at least one new character into the buffer, and then it returns
+ * the first character just as myread() would have done. This function also
+ * is responsible for all error conditions that myread() can indicate.
+ *
+ * Returns: When OK => a positive character, 0 or greater.
+ * When EOF => -2.
+ * When error => -3, error code in errno.
+ *
+ * Older myread()s additionally returned -1 to indicate that there was nothing
+ * to read, upon which the caller would call myread() again until it got
+ * something. The new myread()/mygetbuf() always gets something. If it
+ * doesn't, then make it do so! Any program that actually depends on the old
+ * behaviour will break.
+ *
+ * The older version also used to return -2 both for EOF and other errors,
+ * and used to set errno to 9999 on EOF. The errno stuff is gone, EOF and
+ * other errors now return different results, although Kermit currently never
+ * checks to see which it was. It just disconnects in both cases.
+ *
+ * Kermit lets the user use the quit key to perform some special commands
+ * during file transfer. This causes read(), and thus also mygetbuf(), to
+ * finish without reading anything and return the EINTR error. This should
+ * be checked by the caller. Mygetbuf() could retry the read() on EINTR,
+ * but if there is nothing to read, this could delay Kermit's reaction to
+ * the command, and make Kermit appear unresponsive.
+ *
+ * The debug() call should be removed for optimum performance.
+ */
+int
+mygetbuf() {
+ int x;
+ errno = 0;
+#ifdef DEBUG
+ if (deblog && my_count > 0)
+ debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
+#endif /* DEBUG */
+ if (my_count <= 0)
+ my_count = myfillbuf();
+
+#ifdef DEBUG
+#ifdef COMMENT
+ if (deblog) debug(F101, "mygetbuf read", "", my_count);
+#else /* COMMENT */
+ ckhexdump("mygetbuf read", mybuf, my_count);
+#endif /* COMMENT */
+#endif /* DEBUG */
+ x = my_count;
+ if (my_count <= 0) {
+ my_count = 0;
+ my_item = -1;
+ debug(F101,"mygetbuf errno","",errno);
+#ifdef TCPSOCKET
+ if (netconn && ttnet == NET_TCPB && errno != 0) {
+ if (errno != EINTR) {
+ debug(F101,"mygetbuf TCP error","",errno);
+ ttclos(0); /* Close the connection. */
+ }
+ return(-3);
+ }
+#endif /* TCPSOCKET */
+ if (!netconn && xlocal && errno) {
+ if (errno != EINTR) {
+ debug(F101,"mygetbuf SERIAL error","",errno);
+ x = -3;
+ ttclos(0); /* Close the connection. */
+ }
+ }
+ return((x < 0) ? -3 : -2);
+ }
+ --my_count;
+ return((unsigned)(0xff & mybuf[my_item = 0]));
+}
+
+/* myfillbuf():
+ * System-dependent read() into mybuf[], as many characters as possible.
+ *
+ * Returns: OK => number of characters read, always more than zero.
+ * EOF => 0
+ * Error => -1, error code in errno.
+ *
+ * If there is input available in the system's buffers, all of it should be
+ * read into mybuf[] and the function return immediately. If no input is
+ * available, it should wait for a character to arrive, and return with that
+ * one in mybuf[] as soon as possible. It may wait somewhat past the first
+ * character, but be aware that any such delay lengthens the packet turnaround
+ * time during kermit file transfers. Should never return with zero characters
+ * unless EOF or irrecoverable read error.
+ *
+ * Correct functioning depends on the correct tty parameters being used.
+ * Better control of current parameters is required than may have been the
+ * case in older Kermit releases. For instance, O_NDELAY (or equivalent) can
+ * no longer be sometimes off and sometimes on like it used to, unless a
+ * special myfillbuf() is written to handle that. Otherwise the ordinary
+ * myfillbuf()s may think they have come to EOF.
+ *
+ * If your system has a facility to directly perform the functioning of
+ * myfillbuf(), then use it. If the system can tell you how many characters
+ * are available in its buffers, then read that amount (but not less than 1).
+ * If the system can return a special indication when you try to read without
+ * anything to read, while allowing you to read all there is when there is
+ * something, you may loop until there is something to read, but probably that
+ * is not good for the system load.
+ */
+
+#ifdef SVORPOSIX
+ /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
+ * and CLOCAL set any way you like. This way, read() will do exactly
+ * what is required by myfillbuf(): If there is data in the buffers
+ * of the O.S., all available data is read into mybuf, up to the size
+ * of mybuf. If there is none, the first character to arrive is
+ * awaited and returned.
+ */
+int
+myfillbuf() {
+ int fd, n;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef sxaE50
+ /* From S. Dezawa at Fujifilm in Japan. I don't know why this is */
+ /* necessary for the sxa E50, but it is. */
+ return read(fd, mybuf, 255);
+#else
+#ifdef BEOSORBEBOX
+ while (1) {
+#ifdef NETCONN
+ if (netconn) {
+ n = netxin(sizeof(mybuf), (char *)mybuf);
+ debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
+ }
+ else
+#endif /* NETCONN */
+ n = read(fd, mybuf, sizeof(mybuf));
+ debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
+ if (n > 0)
+ return(n);
+ snooze(1000.0);
+ }
+#else /* BEOSORBEBOX */
+ errno = 0;
+ /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
+#ifdef IBMX25
+ if (netconn && (nettype == NET_IX25)) {
+ /* can't use sizeof because mybuf is a pointer, and not an array! */
+ n = x25xin( MYBUFLEN, mybuf );
+ } else
+#endif /* IBMX25 */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, n = 0;
+ debug(F100,"myfillbuf calling SSL_read() fd","",0);
+ while (n == 0) {
+ if (ssl_active_flag)
+ n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
+ else if (tls_active_flag)
+ n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
+ else
+ break;
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
+ case SSL_ERROR_NONE:
+ if (n > 0)
+ return(n);
+ if (n < 0)
+ return(-2);
+ msleep(50);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if (n != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-3);
+ }
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
+ if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
+ return(-3);
+ else
+ return(n);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
+ if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
+ return(-3);
+ else
+ return(n);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
+ if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
+ return(-3);
+ else
+ return(n);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* Special handling for HP-UX pty i/o */
+ ptyread:
+ if (ttpty && pty_trap_pending(ttyfd) > 0) {
+ debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
+ if (pty_trap_handler(ttyfd) > 0) {
+ ttclos(0);
+ return(-3);
+ }
+ }
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+ debug(F101,"myfillbuf calling read() fd","",ttyfd);
+ n = read(fd, mybuf, sizeof(mybuf));
+ debug(F101,"SVORPOSIX myfillbuf read","",n);
+ debug(F101,"SVORPOSIX myfillbuf errno","",errno);
+ debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
+ if (n < 1) {
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* When we have a PTY trap in place the connection cannot */
+ /* be closed until the trap receives a close indication. */
+ if (n == 0 && ttpty)
+ goto ptyread;
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+ return(-3);
+ }
+ return(n);
+#endif /* BEOSORBEBOX */
+#endif /* sxaE50 */
+}
+
+#else /* not AT&T or POSIX */
+
+#ifdef aegis
+ /* This is quoted from the old myread(). The semantics seem to be
+ * alright, but maybe errno would not need to be set even when
+ * there is no error? I don't know aegis.
+ */
+int
+myfillbuf() {
+ int count;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+ count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
+ errno = EIO;
+ if (st.all == ios_$get_conditional_failed) /* get at least one */
+ count = ios_$get((short)fd, 0, mybuf, 1L, st);
+ if (st.all == ios_$end_of_file)
+ return(-3);
+ else if (st.all != status_$ok) {
+ errno = EIO;
+ return(-1);
+ }
+ return(count > 0 ? count : -3);
+}
+#else /* !aegis */
+
+#ifdef FIONREAD
+ /* This is for systems with FIONREAD. FIONREAD returns the number
+ * of characters available for reading. If none are available, wait
+ * until something arrives, otherwise return all there is.
+ */
+int
+myfillbuf() {
+ PEEKTYPE avail = 0;
+ int x, fd;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef SUNX25
+/*
+ SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
+ Depends on SunOS having FIONREAD, not because we use it, but just so this
+ code is grouped correctly within the #ifdefs. Let's hope Solaris keeps it.
+
+ We call x25xin() instead of read() so that Q-Bit packets, which contain
+ X.25 service-level information (e.g. PAD parameter changes), can be processed
+ transparently to the upper-level code. This is a blocking read, and so
+ we depend on higher-level code (such as ttinc()) to set any necessary alarms.
+*/
+ extern int nettype;
+ if (netconn && nettype == NET_SX25) {
+ while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
+ return(x - 1); /* "-1" compensates for extra status byte */
+ }
+#endif /* SUNX25 */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, n = 0;
+ while (n == 0) {
+ if (ssl_active_flag)
+ n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
+ else
+ n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
+ case SSL_ERROR_NONE:
+ if (n > 0)
+ return(n);
+ if (n < 0)
+ return(-2);
+ msleep(50);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if (n != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-2);
+ }
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(x);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
+ return(-1);
+ else
+ return(x);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(x);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+ errno = 0;
+ debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
+ x = ioctl(fd, FIONREAD, &avail);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"myfillbuf FIONREAD","",x);
+ debug(F101,"myfillbuf FIONREAD avail","",avail);
+ debug(F101,"myfillbuf FIONREAD errno","",errno);
+ }
+#endif /* DEBUG */
+ if (x < 0 || avail == 0)
+ avail = 1;
+
+ if (avail > MYBUFLEN)
+ avail = MYBUFLEN;
+
+ errno = 0;
+
+ x = read(fd, mybuf, (int) avail);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"myfillbuf avail","",avail);
+ debug(F101,"myfillbuf read","",x);
+ debug(F101,"myfillbuf read errno","",errno);
+ if (x > 0)
+ ckhexdump("myfillbuf mybuf",mybuf,x);
+ }
+#endif /* DEBUG */
+ if (x < 1) x = -3; /* read 0 == connection loss */
+ return(x);
+}
+
+#else /* !FIONREAD */
+/* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
+/* When there is no other possibility, read 1 character at a time. */
+int
+myfillbuf() {
+ int x;
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, n = 0;
+ while (n == 0) {
+ if (ssl_active_flag)
+ n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
+ else
+ count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
+ case SSL_ERROR_NONE:
+ if (n > 0)
+ return(n);
+ if (n < 0)
+ return(-2);
+ msleep(50);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if (n != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-2);
+ }
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+ x = read(fd, mybuf, 1);
+ return(x > 0 ? x : -3);
+}
+
+#endif /* !FIONREAD */
+#endif /* !aegis */
+#endif /* !ATTSV */
+
+#endif /* MYREAD */
+
+/* T T _ T N O P T -- Handle Telnet negotions in incoming data */
+/*
+ Call with the IAC that was encountered.
+ Returns:
+ -3: If connection has dropped or gone bad.
+ -2: On Telnet protocol error resulting in inconsistent states.
+ 0: If negotiation OK and caller has nothing to do.
+ 1: If packet start character has changed (new value is in global stchr).
+ 255: If there was a quoted IAC as data.
+ or: Not at all if we got a legitimate Telnet Logout request.
+*/
+#ifdef TCPSOCKET
+static int
+tt_tnopt(n) int n; { /* Handle Telnet options */
+ /* In case caller did not already check these conditions... */
+ if (n == IAC &&
+ ((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet))) {
+ extern int server;
+ int tx = 0;
+ debug(F100,"ttinl calling tn_doop()","",0);
+ tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
+ debug(F111,"ttinl tn_doop() returned","tx",tx);
+ switch (tx) {
+ case 0:
+ return(0);
+ case -1: /* I/O error */
+ ttimoff(); /* Turn off timer */
+ return(-3);
+ case -2: /* Connection failed. */
+ case -3:
+ ttimoff(); /* Turn off timer */
+ ttclos(0);
+ return(-3);
+ case 1: /* ECHO change */
+ duplex = 1;
+ return(0);
+ case 2: /* ECHO change */
+ duplex = 0;
+ return(0);
+ case 3: /* Quoted IAC */
+ n = 255;
+ return((unsigned)255);
+#ifdef IKS_OPTION
+ case 4: {
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) { /* Remote in Server mode */
+ ttimoff(); /* Turn off timer */
+ debug(F100,"u_start and !inserver","",0);
+ return(-2); /* End server mode */
+ } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
+ server
+ ) { /* I'm no longer in Server Mode */
+ debug(F100,"me_start and server","",0);
+ ttimoff();
+ return(-2);
+ }
+ return(0);
+ }
+ case 5: { /* Start character change */
+ /* extern CHAR stchr; */
+ /* start = stchr; */
+ return(1);
+ }
+#endif /* IKS_OPTION */
+ case 6: /* Remote Logout */
+ ttimoff();
+ ttclos(0);
+#ifdef IKSD
+ if (inserver && !local)
+ doexit(GOOD_EXIT,0);
+ else
+#endif /* IKSD */
+ return(-2);
+ default:
+ return(0);
+ }
+ } else
+ return(0);
+}
+#endif /* TCPSOCKET */
+
+/* T T F L U I -- Flush tty input buffer */
+
+void
+ttflux() { /* But first... */
+#ifdef MYREAD
+/*
+ Flush internal MYREAD buffer.
+*/
+#ifdef TCPSOCKET
+ int dotnopts, x;
+ dotnopts = (((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet)));
+#endif /* TCPSOCKET */
+ debug(F101,"ttflux my_count","",my_count);
+#ifdef TCPSOCKET
+ if (dotnopts) {
+ CHAR ch = '\0';
+ while (my_count > 0) {
+ ch = myread();
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt((char *)&ch,1);
+#endif /* CK_ENCRYPTION */
+ if (ch == IAC)
+ x = tt_tnopt(ch);
+ }
+ } else
+#endif /* TCPSOCKET */
+#ifdef COMMENT
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
+ ck_tn_decrypt(&mybuf[my_item+1],my_count);
+#endif /* CK_ENCRYPTION */
+#endif /* COMMENT */
+ my_count = 0; /* Reset count to zero */
+ my_item = -1; /* And buffer index to -1 */
+#endif /* MYREAD */
+}
+
+int
+ttflui() {
+ int n, fd;
+#ifdef TCPSOCKET
+ int dotnopts;
+ dotnopts = (((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet)));
+#endif /* TCPSOCKET */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef TTLEBUF
+ ttpush = -1; /* Clear the peek-ahead char */
+ while (le_data && (le_inbuf() > 0)) {
+ CHAR ch = '\0';
+ if (le_getchar(&ch) > 0) { /* Clear any more... */
+ debug(F101,"ttflui le_inbuf ch","",ch);
+ }
+ }
+#endif /* TTLEBUF */
+ debug(F101,"ttflui ttpipe","",ttpipe);
+
+#ifdef MYREAD
+/*
+ Flush internal MYREAD buffer *NEXT*, in all cases.
+*/
+ ttflux();
+#endif /* MYREAD */
+
+#ifdef NETCONN
+/* Network flush is done specially, in the network support module. */
+ if ((netconn || sstelnet) && !ttpipe && !ttpty) {
+ debug(F100,"ttflui netflui","",0);
+#ifdef COMMENT
+#ifdef TN_COMPORT
+ if (istncomport())
+ tnc_send_purge_data(TNC_PURGE_RECEIVE);
+#endif /* TN_COMPORT */
+#endif /* COMMENT */
+ return(netflui());
+ }
+#endif /* NETCONN */
+
+ debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
+ if (ttyfd < 0)
+ return(-1);
+
+#ifdef aegis
+ sio_$control((short)yfd, sio_$flush_in, true, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "flush failed: "); error_$print(st);
+ } else { /* sometimes the flush doesn't work */
+ for (;;) {
+ char buf[256];
+ /* eat all the characters that shouldn't be available */
+ ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
+ if (st.all == ios_$get_conditional_failed) break;
+ fprintf(stderr, "flush failed(2): "); error_$print(st);
+ }
+ }
+#else
+#ifdef BSD44 /* 4.4 BSD */
+ n = FREAD; /* Specify read queue */
+ debug(F100,"ttflui BSD44","",0);
+ ioctl(fd,TIOCFLUSH,&n);
+#else
+#ifdef Plan9
+#undef POSIX /* Uh oh... */
+#endif /* Plan9 */
+#ifdef POSIX /* POSIX */
+ debug(F100,"ttflui POSIX","",0);
+ tcflush(fd,TCIFLUSH);
+#else
+#ifdef ATTSV /* System V */
+#ifndef VXVE
+ debug(F100,"ttflui ATTSV","",0);
+ ioctl(fd,TCFLSH,0);
+#endif /* VXVE */
+#else /* Not BSD44, POSIX, or Sys V */
+#ifdef TIOCFLUSH /* Those with TIOCFLUSH defined */
+#ifdef ANYBSD /* Berkeley */
+ n = FREAD; /* Specify read queue */
+ debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
+ ioctl(fd,TIOCFLUSH,&n);
+#else /* Others (V7, etc) */
+ debug(F100,"ttflui TIOCFLUSH","",0);
+ ioctl(fd,TIOCFLUSH,0);
+#endif /* ANYBSD */
+#else /* All others... */
+/*
+ No system call (that we know about) for input buffer flushing.
+ So see how many there are and read them in a loop, using ttinc().
+ ttinc() is buffered, so we're not getting charged with a system call
+ per character, just a function call.
+*/
+ if ((n = ttchk()) > 0) {
+ debug(F101,"ttflui read loop","",n);
+ while ((n--) && ttinc(0) > 0) ;
+ }
+#endif /* TIOCFLUSH */
+#endif /* ATTSV */
+#endif /* POSIX */
+#ifdef Plan9
+#define POSIX
+#endif /* Plan9 */
+#endif /* BSD44 */
+#endif /* aegis */
+ return(0);
+}
+
+int
+ttfluo() { /* Flush output buffer */
+ int fd;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdout;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef Plan9
+ return 0;
+#else
+#ifdef POSIX
+ return(tcflush(fd,TCOFLUSH));
+#else
+#ifdef OXOS
+ return(ioctl(fd,TCFLSH,1));
+#else
+ return(0); /* All others, nothing */
+#endif /* OXOS */
+#endif /* POSIX */
+#endif /* Plan9 */
+}
+
+/* Interrupt Functions */
+
+/* Set up terminal interrupts on console terminal */
+
+#ifndef FIONREAD /* We don't need esctrp() */
+#ifndef SELECT /* if we have any of these... */
+#ifndef CK_POLL
+#ifndef RDCHK
+
+#ifndef OXOS
+#ifdef SVORPOSIX
+SIGTYP
+esctrp(foo) int foo; { /* trap console escapes (^\) */
+ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
+ conesc = 1;
+ debug(F101,"esctrp caught SIGQUIT","",conesc);
+}
+#endif /* SVORPOSIX */
+#endif /* OXOS */
+
+#ifdef V7
+#ifndef MINIX2
+SIGTYP
+esctrp(foo) int foo; { /* trap console escapes (^\) */
+ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
+ conesc = 1;
+ debug(F101,"esctrp caught SIGQUIT","",conesc);
+}
+#endif /* MINIX2 */
+#endif /* V7 */
+
+#ifdef C70
+SIGTYP
+esctrp(foo) int foo; { /* trap console escapes (^\) */
+ conesc = 1;
+ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
+}
+#endif /* C70 */
+
+#endif /* RDCHK */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* FIONREAD */
+
+/* C O N B G T -- Background Test */
+
+static int jc = 0; /* 0 = no job control */
+
+/*
+ Call with flag == 1 to prevent signal test, which can not be expected
+ to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
+
+ Call with flag == 0 to use the signal test, but only if the process-group
+ test fails, as it does on some UNIX systems, where getpgrp() is buggy,
+ requires an argument when the man page says it doesn't, or vice versa.
+
+ If flag == 0 and the process-group test fails, then we determine background
+ status simply (but not necessarily reliably) from isatty().
+
+ conbgt() sets the global backgrd = 1 if we appear to be in the background,
+ and to 0 if we seem to be in the foreground. conbgt() is highly prone to
+ misbehavior.
+*/
+VOID
+conbgt(flag) int flag; {
+ int x = -1, /* process group or SIGINT test */
+ y = 0; /* isatty() test */
+/*
+ Check for background operation, even if not running on real tty, so that
+ background flag can be set correctly. If background status is detected,
+ then Kermit will not issue its interactive prompt or most messages.
+ If your prompt goes away, you can blame (and fix?) this function.
+*/
+
+/* Use process-group test if possible. */
+
+#ifdef POSIX /* We can do it in POSIX */
+#define PGROUP_T
+#else
+#ifdef BSD4 /* and in BSD 4.x. */
+#define PGROUP_T
+#else
+#ifdef HPUXJOBCTL /* and in most HP-UX's */
+#define PGROUP_T
+#else
+#ifdef TIOCGPGRP /* and anyplace that has this ioctl. */
+#define PGROUP_T
+#endif /* TIOCGPGRP */
+#endif /* HPUXJOBCTL */
+#endif /* BSD4 */
+#endif /* POSIX */
+
+#ifdef MIPS /* Except if it doesn't work... */
+#undef PGROUP_T
+#endif /* MIPS */
+
+#ifdef MINIX
+#undef PGROUP_T
+#endif /* MINIX */
+
+#ifdef PGROUP_T
+/*
+ Semi-reliable process-group test. Check whether this process's group is
+ the same as the controlling terminal's process group. This works if the
+ getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
+*/
+ PID_T mypgrp = (PID_T)0; /* Kermit's process group */
+ PID_T ctpgrp = (PID_T)0; /* The terminal's process group */
+#ifndef _POSIX_SOURCE
+/*
+ The getpgrp() prototype is obtained from system header files for POSIX
+ and Sys V R4 compilations. Other systems, who knows. Some complain about
+ a duplicate declaration here, others don't, so it's safer to leave it in
+ if we don't know for certain.
+*/
+#ifndef SVR4
+#ifndef PS2AIX10
+#ifndef HPUX9
+ extern PID_T getpgrp();
+#endif /* HPUX9 */
+#endif /* PS2AIX10 */
+#endif /* SVR4 */
+#endif /* _POSIX_SOURCE */
+
+/* Get my process group. */
+
+#ifdef SVR3 /* Maybe this should be ATTSV? */
+/* This function is not described in SVID R2 */
+ mypgrp = getpgrp();
+ /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
+#else
+#ifdef POSIX
+ mypgrp = getpgrp();
+ /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
+#else
+#ifdef OSFPC
+ mypgrp = getpgrp();
+ /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
+#else
+#ifdef QNX
+ mypgrp = getpgrp();
+ /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
+#else
+#ifdef OSF32 /* (was OSF40) */
+ mypgrp = getpgrp();
+ /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
+#else /* BSD, V7, etc */
+#ifdef MINIX2
+ mypgrp = getpgrp();
+#else
+ mypgrp = getpgrp(0);
+#endif /* MINIX2 */
+ /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
+#endif /* OSF32 */
+#endif /* QNX */
+#endif /* OSFPC */
+#endif /* POSIX */
+#endif /* SVR3 */
+
+#ifdef MINIX
+ /* MINIX does not support job control so Kermit is always in foreground */
+ x = 0;
+
+#else /* Not MINIX */
+
+/* Now get controlling tty's process group */
+#ifdef BSD44ORPOSIX
+ ctpgrp = tcgetpgrp(1); /* The POSIX way */
+ /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
+#else
+ ioctl(1, TIOCGPGRP, &ctpgrp); /* Or the BSD way */
+ /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
+#endif /* BSD44ORPOSIX */
+
+ if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
+ x = (mypgrp == ctpgrp) ? 0 : 1; /* If they differ, then background. */
+ else x = -1; /* If error, remember. */
+ debug(F101,"conbgt process group test","",x);
+#endif /* PGROUP_T */
+#endif /* MINIX */
+
+/* Try to see if job control is available */
+
+#ifdef NOJC /* User override */
+ jc = 0; /* No job control allowed */
+ debug(F111,"NOJC","jc",jc);
+#else
+#ifdef BSD44
+ jc = 1;
+#else
+#ifdef SVR4ORPOSIX /* POSIX actually tells us */
+ debug(F100,"SVR4ORPOSIX jc test...","",0);
+#ifdef _SC_JOB_CONTROL
+#ifdef __bsdi__
+ jc = 1;
+#else
+#ifdef __386BSD__
+ jc = 1;
+#else
+ jc = sysconf(_SC_JOB_CONTROL); /* Whatever system says */
+ if (jc < 0) {
+ debug(F101,"sysconf fails, jcshell","",jcshell);
+ jc = (jchdlr == SIG_DFL) ? 1 : 0;
+ } else
+ debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
+#endif /* __386BSD__ */
+#endif /* __bsdi__ */
+#else
+#ifdef _POSIX_JOB_CONTROL
+ jc = 1; /* By definition */
+ debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
+#else
+ jc = 0; /* Assume job control not allowed */
+ debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* _SC_JOB_CONTROL */
+#else
+#ifdef BSD4
+ jc = 1; /* Job control allowed */
+ debug(F111,"BSD job control","jc",jc);
+#else
+#ifdef SVR3JC
+ jc = 1; /* JC allowed */
+ debug(F111,"SVR3 job control","jc",jc);
+#else
+#ifdef OXOS
+ jc = 1; /* JC allowed */
+ debug(F111,"X/OS job control","jc",jc);
+#else
+#ifdef HPUX9
+ jc = 1; /* JC allowed */
+ debug(F111,"HP-UX 9.0 job control","jc",jc);
+#else
+#ifdef HPUX10
+ jc = 1; /* JC allowed */
+ debug(F111,"HP-UX 10.0 job control","jc",jc);
+#else
+ jc = 0; /* JC not allowed */
+ debug(F111,"job control catch-all","jc",jc);
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* OXOS */
+#endif /* SVR3JC */
+#endif /* BSD4 */
+#endif /* SVR4ORPOSIX */
+#endif /* BSD44 */
+#endif /* NOJC */
+ debug(F101,"conbgt jc","",jc);
+#ifndef NOJC
+ debug(F101,"conbgt jcshell","",jcshell);
+/*
+ At this point, if jc == 1 but jcshell == 0, it means that the OS supports
+ job control, but the shell or other process we are running under does not
+ (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
+ will come of it. So...
+*/
+ if (jc < 0) jc = 0;
+ if (jc > 0 && jcshell == 0) jc = 0;
+#endif /* NOJC */
+
+/*
+ Another background test.
+ Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
+ which is done by the shell (sh) if the program is started with '&'.
+ Unfortunately, this is NOT done by csh or ksh so watch out!
+ Note, it's safe to set SIGINT to SIG_IGN here, because further down
+ we always set it to something else.
+ Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
+ SIG_IGN ourselves.
+*/
+ if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
+
+ SIGTYP (*osigint)();
+
+ osigint = signal(SIGINT,SIG_IGN); /* What is SIGINT set to? */
+ sigint_ign = 1;
+ x = (osigint == SIG_IGN) ? 1 : 0; /* SIG_IGN? */
+ /* debug(F101,"conbgt osigint","",osigint); */
+ /* debug(F101,"conbgt signal test","",x); */
+ }
+
+/* Also check to see if we're running with redirected stdio. */
+/* This is not really background operation, but we want to act as though */
+/* it were. */
+
+#ifdef IKSD
+ if (inserver) { /* Internet Kermit Server */
+ backgrd = 0; /* is not in the background */
+ return;
+ }
+#endif /* IKSD */
+
+ y = (isatty(0) && isatty(1)) ? 1 : 0;
+ debug(F101,"conbgt isatty test","",y);
+
+#ifdef BSD29
+/* The process group and/or signal test doesn't work under these... */
+ backgrd = !y;
+#else
+#ifdef sxaE50
+ backgrd = !y;
+#else
+#ifdef MINIX
+ backgrd = !y;
+#else
+#ifdef MINIX2
+ backgrd = !y;
+#else
+ if (x > -1)
+ backgrd = (x || !y) ? 1 : 0;
+ else backgrd = !y;
+#endif /* BSD29 */
+#endif /* sxaE50 */
+#endif /* MINIX */
+#endif /* MINIX2 */
+ debug(F101,"conbgt backgrd","",backgrd);
+}
+
+/* C O N I N T -- Console Interrupt setter */
+
+/*
+ First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
+ Second arg is pointer to function to handle SIGTSTP (suspend).
+*/
+
+VOID /* Set terminal interrupt traps. */
+#ifdef CK_ANSIC
+#ifdef apollo
+conint(f,s) SIGTYP (*f)(), (*s)();
+#else
+conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
+#endif /* apollo */
+#else
+conint(f,s) SIGTYP (*f)(), (*s)();
+#endif /* CK_ANSIC */
+/* conint */ {
+
+ debug(F101,"conint conistate","",conistate);
+
+ conbgt(0); /* Do background test. */
+
+/* Set the desired handlers for hangup and software termination. */
+
+#ifdef SIGTERM
+ signal(SIGTERM,f); /* Software termination */
+#endif /* SIGTERM */
+
+/*
+ Prior to July 1999 we used to call sighup() here but now it's called in
+ sysinit() so SIGHUP can be caught during execution of the init file or
+ a kerbang script.
+*/
+
+/* Now handle keyboard stop, quit, and interrupt signals. */
+/* Check if invoked in background -- if so signals set to be ignored. */
+/* However, if running under a job control shell, don't ignore them. */
+/* We won't be getting any, as we aren't in the terminal's process group. */
+
+ debug(F101,"conint backgrd","",backgrd);
+ debug(F101,"conint jc","",jc);
+
+ if (backgrd && !jc) { /* In background, ignore signals */
+ debug(F101,"conint background ignoring signals, jc","",jc);
+#ifdef SIGTSTP
+ signal(SIGTSTP,SIG_IGN); /* Keyboard stop */
+#endif /* SIGTSTP */
+ signal(SIGQUIT,SIG_IGN); /* Keyboard quit */
+ signal(SIGINT,SIG_IGN); /* Keyboard interrupt */
+ sigint_ign = 1;
+ conistate = CONI_NOI;
+ } else { /* Else in foreground or suspended */
+ debug(F101,"conint foreground catching signals, jc","",jc);
+ signal(SIGINT,f); /* Catch terminal interrupt */
+ sigint_ign = (f == SIG_IGN) ? 1 : 0;
+
+#ifdef SIGTSTP /* Keyboard stop (suspend) */
+ /* debug(F101,"conint SIGSTSTP","",s); */
+ if (s == NULL) s = SIG_DFL;
+#ifdef NOJC /* No job control allowed. */
+ signal(SIGTSTP,SIG_IGN);
+#else /* Job control allowed */
+ if (jc) /* if available. */
+ signal(SIGTSTP,s);
+ else
+ signal(SIGTSTP,SIG_IGN);
+#endif /* NOJC */
+#endif /* SIGTSTP */
+
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifndef FIONREAD /* Watch out, we don't know this... */
+#ifndef SELECT
+#ifndef CK_POLL
+#ifndef RDCHK
+ signal(SIGQUIT,esctrp); /* Quit signal, Sys III/V. */
+#endif /* RDCHK */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* FIONREAD */
+ if (conesc) conesc = 0; /* Clear out pending escapes */
+#else
+#ifdef V7
+ signal(SIGQUIT,esctrp); /* V7 like Sys III/V */
+ if (conesc) conesc = 0;
+#else
+#ifdef aegis
+ signal(SIGQUIT,f); /* Apollo, catch it like others. */
+#else
+ signal(SIGQUIT,SIG_IGN); /* Others, ignore like 4D & earlier. */
+#endif /* aegis */
+#endif /* V7 */
+#endif /* SVORPOSIX */
+#endif /* OXOS */
+ conistate = CONI_INT;
+ }
+}
+
+
+/* C O N N O I -- Reset console terminal interrupts */
+
+VOID
+connoi() { /* Console-no-interrupts */
+
+ debug(F101,"connoi conistate","",conistate);
+#ifdef SIGTSTP
+ signal(SIGTSTP,SIG_IGN); /* Suspend */
+#endif /* SIGTSTP */
+ conint(SIG_IGN,SIG_IGN); /* Interrupt */
+ sigint_ign = 1; /* Remember we did this ourselves */
+#ifdef SIGQUIT
+ signal(SIGQUIT,SIG_IGN); /* Quit */
+#endif /* SIGQUIT */
+#ifdef SIGTERM
+ signal(SIGTERM,SIG_IGN); /* Term */
+#endif /* SIGTERM */
+ conistate = CONI_NOI;
+}
+
+/* I N I T R A W Q -- Set up to read /dev/kmem for character count. */
+
+#ifdef V7
+/*
+ Used in Version 7 to simulate Berkeley's FIONREAD ioctl call. This
+ eliminates blocking on a read, because we can read /dev/kmem to get the
+ number of characters available for raw input. If your system can't
+ or you won't let the world read /dev/kmem then you must figure out a
+ different way to do the counting of characters available, or else replace
+ this by a dummy function that always returns 0.
+*/
+/*
+ * Call this routine as: initrawq(tty)
+ * where tty is the file descriptor of a terminal. It will return
+ * (as a char *) the kernel-mode memory address of the rawq character
+ * count, which may then be read. It has the side-effect of flushing
+ * input on the terminal.
+ */
+/*
+ * John Mackin, Physiology Dept., University of Sydney (Australia)
+ * ...!decvax!mulga!physiol.su.oz!john
+ *
+ * Permission is hereby granted to do anything with this code, as
+ * long as this comment is retained unmodified and no commercial
+ * advantage is gained.
+ */
+#ifndef MINIX
+#ifndef MINIX2
+#ifndef COHERENT
+#include <a.out.h>
+#include <sys/proc.h>
+#endif /* COHERENT */
+#endif /* MINIX2 */
+#endif /* MINIX */
+
+#ifdef COHERENT
+#include <l.out.h>
+#include <sys/proc.h>
+#endif /* COHERENT */
+
+char *
+initrawq(tty) int tty; {
+#ifdef MINIX
+ return(0);
+#else
+#ifdef MINIX2
+ return(0);
+#else
+#ifdef UTS24
+ return(0);
+#else
+#ifdef BSD29
+ return(0);
+#else
+ long lseek();
+ static struct nlist nl[] = {
+ {PROCNAME},
+ {NPROCNAME},
+ {""}
+ };
+ static struct proc *pp;
+ char *qaddr, *p, c;
+ int m;
+ PID_T pid, me;
+ NPTYPE xproc; /* Its type is defined in makefile. */
+ int catch();
+
+ me = getpid();
+ if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
+ nlist(BOOTNAME, nl);
+ if (nl[0].n_type == 0) err("proc array");
+
+ if (nl[1].n_type == 0) err("nproc");
+
+ lseek(m, (long)(nl[1].n_value), 0);
+ read (m, &xproc, sizeof(xproc));
+ saval = signal(SIGALRM, catch);
+ if ((pid = fork()) == 0) {
+ while(1)
+ read(tty, &c, 1);
+ }
+ alarm(2);
+
+ if(setjmp(jjbuf) == 0) {
+ while(1)
+ read(tty, &c, 1);
+ }
+ signal(SIGALRM, SIG_DFL);
+
+#ifdef DIRECT
+ pp = (struct proc *) nl[0].n_value;
+#else
+ if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
+ if (read(m, &pp, sizeof(pp)) != sizeof(pp)) err("no read of proc ptr");
+#endif
+ lseek(m, (long)(nl[1].n_value), 0);
+ read(m, &xproc, sizeof(xproc));
+
+ if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
+ if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
+ if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
+ err("read proc table");
+ for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
+ if (pp -> p_pid == (short) pid) goto iout;
+ }
+ err("no such proc");
+
+iout:
+ close(m);
+ qaddr = (char *)(pp -> p_wchan);
+ free (p);
+ kill(pid, SIGKILL);
+ wait((WAIT_T *)0);
+ return (qaddr);
+#endif
+#endif
+#endif
+#endif
+}
+
+/* More V7-support functions... */
+
+static VOID
+err(s) char *s; {
+ char buf[200];
+
+ ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
+ perror(buf);
+ doexit(1,-1);
+}
+
+static VOID
+catch(foo) int foo; {
+ longjmp(jjbuf, -1);
+}
+
+
+/* G E N B R K -- Simulate a modem break. */
+
+#ifdef MINIX
+#define BSPEED B110
+#else
+#ifdef MINIX2
+#define BSPEED B110
+#else
+#define BSPEED B150
+#endif /* MINIX2 */
+#endif /* MINIX */
+
+#ifndef MINIX2
+VOID
+genbrk(fn,msec) int fn, msec; {
+ struct sgttyb ttbuf;
+ int ret, sospeed, x, y;
+
+ ret = ioctl(fn, TIOCGETP, &ttbuf);
+ sospeed = ttbuf.sg_ospeed;
+ ttbuf.sg_ospeed = BSPEED;
+ ret = ioctl(fn, TIOCSETP, &ttbuf);
+ y = (int)strlen(brnuls);
+ x = ( BSPEED * 100 ) / msec;
+ if (x > y) x = y;
+ ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
+ ttbuf.sg_ospeed = sospeed;
+ ret = ioctl(fn, TIOCSETP, &ttbuf);
+ ret = write(fn, "@", 1);
+ return;
+}
+#endif /* MINIX2 */
+
+#ifdef MINIX2
+int
+genbrk(fn,msec) int fn, msec; {
+ struct termios ttbuf;
+ int ret, x, y;
+ speed_t sospeed;
+
+ ret = tcgetattr(fn, &ttbuf);
+ sospeed = ttbuf.c_ospeed;
+ ttbuf.c_ospeed = BSPEED;
+ ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
+ y = (int)strlen(brnuls);
+ x = ( BSPEED * 100 ) / msec;
+ if (x > y) x = y;
+ ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
+ ttbuf.c_ospeed = sospeed;
+ ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
+ ret = write(fn, "@", 1);
+ return ret;
+}
+#endif /* MINIX2 */
+#endif /* V7 */
+
+/*
+ I N C H K -- Check if chars waiting to be read on given file descriptor.
+
+ This routine is a merger of ttchk() and conchk().
+ Call with:
+ channel == 0 to check console.
+ channel == 1 to check communications connection.
+ and:
+ fd = file descriptor.
+ Returns:
+ >= 0: number of characters waiting, 0 or greater,
+ -1: on any kind of error,
+ -2: if there is (definitely) no connection.
+ Note: In UNIX we don't have to call nettchk() because a socket
+ file descriptor works just like in serial i/o, ioctls and all.
+ (But this will change if we add non-file-descriptor channels,
+ such as IBM X.25 for AIX...)
+*/
+static int
+in_chk(channel, fd) int channel, fd; {
+ int x, n = 0; /* Workers, n = return value */
+ extern int clsondisc; /* Close on disconnect */
+/*
+ The first section checks to make sure we have a connection,
+ but only if we're in local mode.
+*/
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"in_chk entry",ckitoa(fd),channel);
+ debug(F101,"in_chk ttyfd","",ttyfd);
+ debug(F101,"in_chk ttpty","",ttpty);
+ }
+#endif /* DEBUG */
+/*
+ But don't say connection is gone if we have any buffered-stuff.
+*/
+#ifdef TTLEBUF
+ debug(F101,"in_chk ttpush","",ttpush);
+ if (channel == 1) {
+ if (ttpush >= 0)
+ n++;
+ n += le_inbuf();
+ if (n > 0)
+ return(n);
+ }
+#endif /* TTLEBUF */
+
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* Special handling for HP-UX pty i/o */
+ if (ttpty && pty_trap_pending(ttyfd) > 0) {
+ if (pty_trap_handler(ttyfd) > 0) {
+ ttclos(0);
+ return(-2);
+ }
+ }
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+
+ if (channel) { /* Checking communications channel */
+ if (ttyfd < 0) { /* No connection */
+ return(-2); /* That's what this means */
+ } else if (xlocal && /* In local mode */
+ (!netconn /* Serial connection or */
+#ifdef TN_COMPORT
+ || istncomport() /* Telnet Com Port */
+#endif /* TN_COMPORT */
+ ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
+#ifdef COMMENT
+#ifdef MYREAD
+/*
+ Seems like this would be a good idea but it prevents C-Kermit from
+ popping back to the prompt automatically when carrier drops. However,
+ commenting this out prevents us from seeing the NO CARRIER message.
+ Needs more work...
+*/
+ && my_count < 1 /* Nothing in our internal buffer */
+#endif /* MYREAD */
+#endif /* COMMENT */
+ ) {
+ int x;
+ x = ttgmdm(); /* So get modem signals */
+ debug(F101,"in_chk close-on-disconnect","",clsondisc);
+ if (x > -1) { /* Check for carrier */
+ if (!(x & BM_DCD)) { /* No carrier */
+ debug(F101,"in_chk carrier lost","",x);
+ if (clsondisc) /* If "close-on-disconnect" */
+ ttclos(0); /* close device & release lock. */
+ return(-2); /* This means "disconnected" */
+ }
+ /* In case I/O to device after CD dropped always fails */
+ /* as in Debian Linux 2.1 and Unixware 2.1... */
+ } else {
+ debug(F101,"in_chk ttgmdm I/O error","",errno);
+ debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
+ if (gotsigs) { /* If we got signals before... */
+ if (errno == 5 || errno == 6) { /* I/O error etc */
+ if (clsondisc) /* like when modem hangs up */
+ ttclos(0);
+ return(-2);
+ }
+ }
+ /* If we never got modem signals successfully on this */
+ /* connection before, we can't conclude that THIS failure */
+ /* means the connection was lost. */
+ return(0);
+ }
+ }
+ }
+
+/* We seem to have a connection so now see if any bytes are waiting on it */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
+ debug(F101,"in_chk SSL_pending","",n);
+ if (n < 0) {
+ ttclos(0);
+ return(-1);
+ } else if (n > 0) {
+ return(n);
+ }
+ }
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+ /* It is not safe to read any data when using encrypted Klogin */
+ if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
+#ifdef KRB4
+ if (ttnproto == NP_EK4LOGIN) {
+ n += krb4_des_avail(ttyfd);
+ debug(F101,"in_chk krb4_des_avail","",n);
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (ttnproto == NP_EK5LOGIN) {
+ n += krb5_des_avail(ttyfd);
+ debug(F101,"in_chk krb5_des_avail","",n);
+ }
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ n += krb5_u2u_avail(ttyfd);
+ debug(F101,"in_chk krb5_des_avail","",n);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+ if (n < 0) /* Is this right? */
+ return(-1);
+ else
+ return(n);
+ }
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+
+ errno = 0; /* Reset this so we log good info */
+#ifdef FIONREAD
+ x = ioctl(fd, FIONREAD, &n); /* BSD and lots of others */
+#ifdef DEBUG /* (the more the better) */
+ if (deblog) {
+ debug(F101,"in_chk FIONREAD return code","",x);
+ debug(F101,"in_chk FIONREAD count","",n);
+ debug(F101,"in_chk FIONREAD errno","",errno);
+ }
+#endif /* DEBUG */
+#else /* FIONREAD not defined */
+/*
+ Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
+ with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
+ portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
+ that I looked at, but it is needed to prevent the call from blocking), and
+ the msghdr struct differs from place to place, so we would need another
+ avalanche of ifdefs. Still, when FIONREAD is not available, this is the
+ only other known method of asking the OS for the *number* of characters
+ available for reading.
+*/
+#ifdef V7 /* UNIX V7: look in kernel memory */
+#ifdef MINIX
+ n = 0; /* But not in MINIX */
+#else
+#ifdef MINIX2
+ n = 0;
+#else
+ lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
+ x = read(kmem[TTY], &n, sizeof(int));
+ if (x != sizeof(int))
+ n = 0;
+#endif /* MINIX2 */
+#endif /* MINIX */
+#else /* Not V7 */
+#ifdef PROVX1
+ x = ioctl(fd, TIOCQCNT, &ttbuf); /* DEC Pro/3xx Venix V.1 */
+ n = ttbuf.sg_ispeed & 0377; /* Circa 1984 */
+ if (x < 0) n = 0;
+#else
+#ifdef MYREAD
+/*
+ Here we skip all the undependable and expensive calls below if we
+ already have something in our internal buffer. This tends to work quite
+ nicely, so the only really bad case remaining is the one in which neither
+ FIONREAD or MYREAD are defined, which is increasingly rare these days.
+*/
+ if (channel != 0 && my_count > 0) {
+ debug(F101,"in_chk buf my_count","",my_count);
+ n = my_count; /* n was 0 before we got here */
+ return(n);
+ }
+#endif /* MYREAD */
+/*
+ rdchk(), select(), and poll() tell us *if* data is available to be read, but
+ not how much, so these should be used only as a final resort. Especially
+ since these calls tend to add a lot overhead.
+*/
+#ifdef RDCHK /* This mostly SCO-specific */
+ n = rdchk(fd);
+ debug(F101,"in_chk rdchk","",n);
+#else /* No RDCHK */
+#ifdef SELECT
+#ifdef Plan9
+ /* Only allows select on the console ... don't ask */
+ if (channel == 0)
+#endif /* Plan9 */
+ {
+ fd_set rfds; /* Read file descriptors */
+#ifdef BELLV10
+ FD_ZERO(rfds); /* Initialize them */
+ FD_SET(fd,rfds); /* We want to look at this fd */
+#else
+ FD_ZERO(&rfds); /* Initialize them */
+ FD_SET(fd,&rfds); /* We want to look at this fd */
+ tv.tv_sec = tv.tv_usec = 0L; /* A 0-valued timeval structure */
+#endif /* BELLV10 */
+#ifdef Plan9
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk Plan 9 select","",n);
+#else
+#ifdef BELLV10
+ n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
+ debug(F101,"in_chk BELLV10 select","",n);
+#else
+#ifdef BSD44
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk BSD44 select","",n);
+#else
+#ifdef BSD43
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk BSD43 select","",n);
+#else
+#ifdef SOLARIS
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk SOLARIS select","",n);
+#else
+#ifdef QNX6
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk QNX6 select","",n);
+#else
+#ifdef QNX
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk QNX select","",n);
+#else
+#ifdef COHERENT
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk COHERENT select","",n);
+#else
+#ifdef SVR4
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk SVR4 select","",n);
+#else
+#ifdef __linux__
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk LINUX select","",n);
+#ifdef OSF
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk OSF select","",n);
+#else
+ n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
+ debug(F101,"in_chk catchall select","",n);
+#endif /* OSF */
+#endif /* __linux__ */
+#endif /* SVR4 */
+#endif /* COHERENT */
+#endif /* QNX */
+#endif /* QNX6 */
+#endif /* SOLARIS */
+#endif /* BSD43 */
+#endif /* BSD44 */
+#endif /* BELLV10 */
+#endif /* Plan9 */
+ }
+#else /* Not SELECT */
+#ifdef CK_POLL
+ {
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ n = poll(&pfd, 1, 0);
+ debug(F101,"in_chk poll","",n);
+ if ((n > 0) && (pfd.revents & POLLIN))
+ n = 1;
+ }
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* RDCHK */
+#endif /* PROVX1 */
+#endif /* V7 */
+#endif /* FIONREAD */
+
+/* From here down, treat console and communication device differently... */
+
+ if (channel == 0) { /* Console */
+
+#ifdef SVORPOSIX
+#ifndef FIONREAD
+#ifndef SELECT
+#ifndef CK_POLL
+#ifndef RDCHK
+/*
+ This is the hideous hack used in System V and POSIX systems that don't
+ support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
+ CONNECT-mode escape character is attached to SIGQUIT. Used, obviously,
+ only on the console.
+*/
+ if (conesc) { /* Escape character typed == SIGQUIT */
+ debug(F100,"in_chk conesc","",conesc);
+ conesc = 0;
+ signal(SIGQUIT,esctrp); /* Restore signal */
+ n += 1;
+ }
+#endif /* RDCHK */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* FIONREAD */
+#endif /* SVORPOSIX */
+
+ return(n); /* Done with console */
+ }
+
+ if (channel != 0) { /* Communications connection */
+
+#ifdef MYREAD
+#ifndef FIONREAD
+/*
+ select() or rdchk(), etc, has told us that something is waiting, but we
+ don't know how much. So we do a read to get it and then we know. Note:
+ This read is NOT nonblocking if nothing is there (because of VMIN=1), but
+ it should be safe in this case since the OS tells us at least one byte is
+ waiting to be read, and MYREAD reads return as much as is there without
+ waiting for any more. Controlled tests on Solaris and Unixware (with
+ FIONREAD deliberately undefined) show this to be true.
+*/
+ debug(F101,"in_chk read my_count","",my_count);
+ debug(F101,"in_chk read n","",n);
+ if (n > 0 && my_count == 0) {
+ /* This also catches disconnects etc */
+ /* Do what mygetbuf does except don't grab a character */
+ my_count = myfillbuf();
+ my_item = -1; /* ^^^ */
+ debug(F101,"in_chk myfillbuf my_count","",my_count);
+ if (my_count < 0)
+ return(-1);
+ else
+ n = 0; /* NB: n is replaced by my_count */
+ }
+#endif /* FIONREAD */
+/*
+ Here we add whatever we think is unread to what is still in our
+ our internal buffer. Thus the importance of setting n to 0 just above.
+*/
+ debug(F101,"in_chk my_count","",my_count);
+ debug(F101,"in_chk n","",n);
+ if (my_count > 0)
+ n += my_count;
+#endif /* MYREAD */
+ }
+ debug(F101,"in_chk result","",n);
+
+ /* Errors here don't prove the connection has dropped so just say 0 */
+
+ return(n < 0 ? 0 : n);
+}
+
+
+/* T T C H K -- Tell how many characters are waiting in tty input buffer */
+
+int
+ttchk() {
+ int fd;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+ return(in_chk(1,fd));
+}
+
+/* T T X I N -- Get n characters from tty input buffer */
+
+/* Returns number of characters actually gotten, or -1 on failure */
+
+/* Intended for use only when it is known that n characters are actually */
+/* Available in the input buffer. */
+
+int
+ttxin(n,buf) int n; CHAR *buf; {
+ register int x = 0, c = -2;
+#ifdef TTLEBUF
+ register int i = 0;
+#endif /* TTLEBUF */
+ int fd;
+
+ if (n < 1) /* Nothing to do */
+ return(0);
+
+#ifdef TTLEBUF
+ if (ttpush >= 0) {
+ buf[0] = ttpush; /* Put pushed char in buffer*/
+ ttpush = -1; /* Clear the push buffer */
+ if (ttchk() > 0)
+ return(ttxin(n-1, &buf[1]) + 1);
+ else
+ return(1);
+ }
+ if (le_data) {
+ while (le_inbuf() > 0) {
+ if (le_getchar(&buf[i])) {
+ i++;
+ n--;
+ }
+ }
+ if (ttchk() > 0)
+ return(ttxin(n,&buf[i])+i);
+ else
+ return(i);
+ }
+#endif /* TTLEBUF */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef SUNX25
+ if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
+ return(x25xin(n,buf));
+#endif /* SUNX25 */
+
+#ifdef IBMX25
+ /* riehm: possibly not needed. Test worked with normal reads and writes */
+ if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
+ x = x25xin(n,buf);
+ if (x > 0) buf[x] = '\0';
+ return(x);
+ }
+#endif /* IBMX25 */
+
+#ifdef MYREAD
+ debug(F101,"ttxin MYREAD","",n);
+ while (x < n) {
+ c = myread();
+ if (c < 0) {
+ debug(F101,"ttxin myread returns","",c);
+ if (c == -3) x = -1;
+ break;
+ }
+ buf[x++] = c & ttpmsk;
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+ /* It is impossible to know how many characters are waiting */
+ /* to be read when you are using Encrypted Rlogin or SSL */
+ /* as the transport since the number of real data bytes */
+ /* can be greater or less than the number of bytes on the */
+ /* wire which is what ttchk() returns. */
+ if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
+ if (ttchk() <= 0)
+ break;
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag)
+ if (ttchk() <= 0)
+ break;
+#endif /* CK_SSL */
+ }
+#else
+ debug(F101,"ttxin READ","",n);
+ x = read(fd,buf,n);
+ for (c = 0; c < n; c++) /* Strip any parity */
+ buf[c] &= ttpmsk;
+#endif /* MYREAD */
+
+ debug(F101,"ttxin x","",x); /* Done */
+ if (x > 0) buf[x] = '\0';
+ if (x < 0) x = -1;
+ return(x);
+}
+
+/* T T O L -- Write string s, length n, to communication device. */
+/*
+ Returns:
+ >= 0 on success, number of characters actually written.
+ -1 on failure.
+*/
+#ifdef CK_ENCRYPTION
+CHAR * xpacket = NULL;
+int nxpacket = 0;
+#endif /* CK_ENCRYPTION */
+
+#define TTOLMAXT 5
+int
+ttol(s,n) int n; CHAR *s; {
+ int x, len, tries, fd;
+#ifdef CKXXCHAR
+ extern int dblflag; /* For SET SEND DOUBLE-CHARACTER */
+ extern short dblt[];
+ CHAR *p = NULL, *p2, *s2, c;
+ int n2 = 0;
+#endif /* CKXXCHAR */
+
+ if (ttyfd < 0) /* Not open? */
+ return(-3);
+#ifdef DEBUG
+ if (deblog) {
+ /* debug(F101,"ttol ttyfd","",ttyfd); */
+ ckhexdump("ttol s",s,n);
+ }
+#endif /* DEBUG */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdout;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef CKXXCHAR
+/* Double any characters that must be doubled. */
+ debug(F101,"ttol dblflag","",dblflag);
+ if (dblflag) {
+ p = (CHAR *) malloc(n + n + 1);
+ if (p) {
+ s2 = s;
+ p2 = p;
+ n2 = 0;
+ while (*s2) {
+ c = *s2++;
+ *p2++ = c;
+ n2++;
+ if (dblt[(unsigned) c] & 2) {
+ *p2++ = c;
+ n2++;
+ }
+ }
+ s = p;
+ n = n2;
+ s[n] = '\0';
+ }
+#ifdef DEBUG
+ ckhexdump("ttol doubled s",s,n);
+#endif /* DEBUG */
+ }
+#endif /* CKXXCHAR */
+
+ tries = TTOLMAXT; /* Allow up to this many tries */
+ len = n; /* Remember original length */
+
+#ifdef CK_ENCRYPTION
+/*
+ This is to avoid encrypting a packet that is already encrypted, e.g.
+ when we resend a packet directly out of the packet buffer, and also to
+ avoid encrypting a constant (literal) string, which can cause a memory
+ fault.
+*/
+ if (TELOPT_ME(TELOPT_ENCRYPTION)) {
+ int x;
+ if (nxpacket < n) {
+ if (xpacket) {
+ free(xpacket);
+ xpacket = NULL;
+ nxpacket = 0;
+ }
+ x = n > 10240 ? n : 10240;
+ xpacket = (CHAR *)malloc(x);
+ if (!xpacket) {
+ fprintf(stderr,"ttol malloc failure\n");
+ return(-1);
+ } else
+ nxpacket = x;
+ }
+ memcpy((char *)xpacket,(char *)s,n);
+ s = xpacket;
+ ck_tn_encrypt((char *)s,n);
+ }
+#endif /* CK_ENCRYPTION */
+
+ while (n > 0 &&
+ (tries-- > 0
+#ifdef CK_ENCRYPTION
+ /* keep trying if we are encrypting */
+ || TELOPT_ME(TELOPT_ENCRYPTION)
+#endif /* CK_ENCRYPTION */
+ )) { /* Be persistent */
+ debug(F101,"ttol try","",TTOLMAXT - tries);
+#ifdef BEOSORBEBOX
+ if (netconn && !ttpipe && !ttpty)
+ x = nettol((char *)s,n); /* Write string to device */
+ else
+#endif /* BEOSORBEBOX */
+#ifdef IBMX25
+ if (ttnet == NET_IX25)
+ /*
+ * this is a more controlled way of writing to X25
+ * STREAMS, however write should also work!
+ */
+ x = x25write(ttyfd, s, n);
+ else
+#endif /* IBMX25 */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error;
+ /* Write using SSL */
+ ssl_retry:
+ if (ssl_active_flag)
+ x = SSL_write(ssl_con, s, n);
+ else
+ x = SSL_write(tls_con, s, n);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
+ case SSL_ERROR_NONE:
+ if (x == n)
+ return(len);
+ s += x;
+ n -= x;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ x = 0;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (x != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-3);
+ }
+ } else
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ return(krb4_des_write(ttyfd,s,n));
+ } else
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ return(krb5_des_write(ttyfd,(char *)s,n,0));
+ } else
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ return(krb5_u2u_write(ttyfd,(char *)s,n));
+ } else
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+ x = write(fd,s,n); /* Write string to device */
+
+ if (x == n) { /* Worked? */
+ debug(F101,"ttol ok","",x); /* OK */
+#ifdef CKXXCHAR
+ if (p) free(p);
+#endif /* CKXXCHAR */
+ return(len); /* Done */
+ } else if (x < 0) { /* No, got error? */
+ debug(F101,"ttol write error","",errno);
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK) {
+ msleep(10);
+ continue;
+ } else
+#endif /* EWOULDBLOCK */
+#ifdef TCPSOCKET
+ if (netconn && ttnet == NET_TCPB) {
+ debug(F101,"ttol TCP error","",errno);
+ ttclos(0); /* Close the connection. */
+ x = -3;
+ }
+#endif /* TCPSOCKET */
+#ifdef CKXXCHAR
+ if (p) free(p);
+#endif /* CKXXCHAR */
+ return(x);
+ } else { /* No error, so partial success */
+ debug(F101,"ttol partial","",x); /* This never happens */
+ s += x; /* Point to part not written yet */
+ n -= x; /* Adjust length */
+ if (x > 0) msleep(10); /* Wait 10 msec */
+ } /* Go back and try again */
+ }
+#ifdef CKXXCHAR
+ if (p) free(p);
+#endif /* CKXXCHAR */
+ return(n < 1 ? len : -1); /* Return the results */
+}
+
+/* T T O C -- Output a character to the communication line */
+
+/*
+ This function should only be used for interactive, character-mode operations,
+ like terminal connection, script execution, dialer i/o, where the overhead
+ of the signals and alarms does not create a bottleneck.
+*/
+int
+#ifdef CK_ANSIC
+ttoc(char c)
+#else
+ttoc(c) char c;
+#endif /* CK_ANSIC */
+/* ttoc */ {
+#define TTOC_TMO 15 /* Timeout in case we get stuck */
+ int xx, fd;
+
+ if (ttyfd < 0) /* Check for not open. */
+ return(-1);
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdout;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+ c &= 0xff;
+ /* debug(F101,"ttoc","",(CHAR) c); */
+ saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
+ xx = alarm(TTOC_TMO); /* for this many seconds. */
+ if (xx < 0) xx = 0; /* Save old alarm value. */
+ /* debug(F101,"ttoc alarm","",xx); */
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer went off? */
+ ttimoff(); /* Yes, cancel this alarm. */
+ if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
+ /* debug(F100,"ttoc timeout","",0); */
+#ifdef NETCONN
+ if (!netconn) {
+#endif /* NETCONN */
+ debug(F101,"ttoc timeout","",c);
+ if (ttflow == FLO_XONX) {
+ debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
+#ifndef Plan9
+#ifdef POSIX
+ /* POSIX way to unstick. */
+ debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
+#else
+#ifdef BSD4 /* Berkeley way to do it. */
+#ifdef TIOCSTART
+/* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);". Who knows? */
+ {
+ int x = 0;
+ debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
+ }
+#endif /* TIOCSTART */
+#endif /* BSD4 */
+ /* Is there a Sys V way to do this? */
+#endif /* POSIX */
+#endif /* Plan9 */
+ }
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+ return(-1); /* Return failure code. */
+ } else {
+ int rc;
+#ifdef BEOSORBEBOX
+#ifdef NETCONN
+ if (netconn && !ttpipe && !ttpty)
+ rc = nettoc(c);
+ else
+#endif /* BEOSORBEBOX */
+#endif /* NETCONN */
+#ifdef CK_ENCRYPTION
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(&c,1);
+#endif /* CK_ENCRYPTION */
+#ifdef IBMX25
+ /* riehm: maybe this isn't necessary after all. Test program
+ * worked fine with data being sent and retrieved with normal
+ * read's and writes!
+ */
+ if (ttnet == NET_IX25)
+ rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
+ else
+#endif /* IBMX25 */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error;
+ /* Write using SSL */
+ if (ssl_active_flag)
+ rc = SSL_write(ssl_con, &c, 1);
+ else
+ rc = SSL_write(tls_con, &c, 1);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ rc = 0;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (rc != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-1);
+ }
+ } else
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
+ } else
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
+ } else
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
+ } else
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+ rc = write(fd,&c,1); /* Try to write the character. */
+ if (rc < 1) { /* Failed */
+ ttimoff(); /* Turn off the alarm. */
+ alarm(xx); /* Restore previous alarm. */
+ debug(F101,"ttoc errno","",errno); /* Log the error, */
+ return(-1); /* and return the error code. */
+ }
+ }
+ ttimoff(); /* Success, turn off the alarm. */
+ alarm(xx); /* Restore previous alarm. */
+ return(0); /* Return good code. */
+}
+
+/* T T I N L -- Read a record (up to break character) from comm line. */
+/*
+ Reads up to "max" characters from the connection, terminating on:
+ (a) the packet length field if the "turn" argument is zero, or
+ (b) on the packet-end character (eol) if the "turn" argument is nonzero
+ (c) a certain number of Ctrl-C's in a row
+
+ Returns:
+ >= 0, the number of characters read upon success;
+ -1 if "max" exceeded, timeout, or other correctable error;
+ -2 on user interruption (c);
+ -3 on fatal error like connection lost.
+
+ The name of this routine dates from the early days when Kermit packets
+ were, indeed, always lines of text. That was before control-character
+ unprefixing and length-driven packet framing were introduced, which this
+ version handle. NB: this routine is ONLY for reading incoming Kermit
+ packets, nothing else. To read other kinds of incoming material, use
+ ttinc() or ttxin().
+
+ The bytes that were input are copied into "dest" with their parity bits
+ stripped if parity was selected. Returns the number of bytes read.
+ Bytes after the eol are available upon the next call to this function.
+
+ The idea is to minimize the number of system calls per packet, and also to
+ minimize timeouts. This function is the inner loop of the protocol and must
+ be as efficient as possible. The current strategy is to use myread(), a
+ macro to manage buffered (and generally nonblocking) reads.
+
+ WARNING: This function calls parchk(), which is defined in another module.
+ Normally, ckutio.c does not depend on code from any other module, but there
+ is an exception in this case because all the other ck?tio.c modules also
+ need to call parchk(), so it's better to have it defined in a common place.
+*/
+#ifdef CTRLC
+#undef CTRLC
+#endif /* CTRLC */
+#define CTRLC '\03'
+/*
+ We have four different declarations here because:
+ (a) to allow Kermit to be built without the automatic parity sensing feature
+ (b) one of each type for ANSI C, one for non-ANSI.
+*/
+#ifndef NOXFER
+
+static int pushedback = 0;
+
+int
+#ifdef PARSENSE
+#ifdef CK_ANSIC
+ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
+#else
+ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
+#endif /* CK_ANSIC */
+#else /* not PARSENSE */
+#ifdef CK_ANSIC
+ttinl(CHAR *dest, int max,int timo, CHAR eol)
+#else
+ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
+#endif /* CK_ANSIC */
+#endif /* PARSENSE */
+/* ttinl */ {
+
+#ifndef MYREAD
+ CHAR ch, dum;
+#endif /* MYREAD */
+#ifdef PARSENSE
+ int pktlen = -1;
+ int lplen = 0;
+ int havelen = 0;
+#endif /* PARSENSE */
+ int fd;
+ int sopmask = 0xff; /* Start-Of-Packet mask */
+#ifdef CKXXCHAR
+ extern short dblt[]; /* Ignore-character table */
+ extern int ignflag;
+#endif /* CKXXCHAR */
+#ifdef TCPSOCKET
+ extern CHAR stchr;
+#endif /* TCPSOCKET */
+ int x;
+#ifdef STREAMING
+ extern int streaming;
+ extern int sndtyp;
+#endif /* STREAMING */
+
+ if (ttyfd < 0) return(-3); /* Not open. */
+/*
+ In February 2007 I fixed ttinl() to work better under the truly awful
+ conditions encountered by the AM-APEX oceanographic floats that gather
+ hurricane data and phone home using Iridium satellite modems, which under
+ certain conditions, can send two packets back to back after a long pause.
+ In this case the second packet would be ignored because the SOH was skipped
+ due to the ttflui() call. But the reworked lookahead/pushback logic broke
+ Kermit transfers on encrypted connections. This was fixed 12-13 August
+ 2007. All of this happened after 8.0.212 Dev.27 was released and before
+ Dev.28, so no harm done other than the delay.
+*/
+ debug(F101,"ttinl max","",max);
+ debug(F101,"ttinl timo","",timo);
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef COMMENT
+ if (xlocal && conchk() > 0) /* Allow for console interruptions */
+ return(-1);
+#endif /* COMMENT */
+
+ *dest = '\0'; /* Clear destination buffer */
+ if (timo < 0) timo = 0; /* Safety */
+ if (timo) { /* Don't time out if timo == 0 */
+ int xx;
+ saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
+ xx = alarm(timo); /* Set it. */
+ debug(F101,"ttinl alarm","",xx);
+ }
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer went off? */
+ debug(F100,"ttinl timout","",0); /* Get here on timeout. */
+ /* debug(F110," with",(char *) dest,0); */
+ ttimoff(); /* Turn off timer */
+ return(-1); /* and return error code. */
+ } else {
+ register int i, n = -1; /* local variables */
+ int ccn = 0;
+#ifdef PARSENSE
+ register int flag = 0;
+ debug(F000,"ttinl start","",start);
+#endif /* PARSENSE */
+
+ ttpmsk = ttprty ? 0177 : 0377; /* Set parity stripping mask. */
+ sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
+
+/* Now read into destination, stripping parity and looking for the */
+/* the packet terminator, and also for several Ctrl-C's typed in a row. */
+
+ i = 0; /* Destination index */
+ debug(F101,"ttinl eol","",eol);
+
+ while (i < max-1) {
+#ifdef MYREAD
+ errno = 0;
+ /* On encrypted connections myread returns encrypted bytes */
+ n = myread();
+ debug(F000,"TTINL myread char","",n);
+ if (n < 0) { /* Timeout or i/o error? */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"ttinl myread failure, n","",n);
+ debug(F101,"ttinl myread errno","",errno);
+ }
+#endif /* DEBUG */
+ /* Don't let EINTR break packets. */
+ if (n == -3) {
+ if (errno == EINTR && i > 0) {
+ debug(F111,"ttinl EINTR myread i","continuing",i);
+ continue;
+ } else {
+ debug(F110,"ttinl non-EINTR -3","closing",0);
+ wasclosed = 1;
+ ttimoff(); /* Turn off timer */
+ ttclos(0);
+ return(n);
+ }
+ } else if (n == -2 && netconn /* && timo == 0 */ ) {
+ /* Here we try to catch broken network connections */
+ /* even when ioctl() and read() do not catch them */
+ debug(F111,"ttinl network myread failure","closing",n);
+ wasclosed = 1;
+ ttimoff();
+ ttclos(0);
+ return(-3);
+ }
+#ifdef STREAMING
+ /* Streaming and no data to read */
+ else if (n == 0 && streaming && sndtyp == 'D')
+ return(0);
+#endif /* STREAMING */
+ break; /* Break out of while loop */
+ }
+
+#else /* not MYREAD (is this code used anywhere any more?) */
+/*
+ The non-MYREAD code dates from the 1980s and was needed on certain platforms
+ where there were no nonblocking reads. -fdc, 2007/02/22.
+*/
+ if ((n = read(fd, &n, 1)) < 1)
+ break; /* Error - break out of while loop */
+
+#endif /* MYREAD */
+
+ /* Get here with char in n */
+
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
+ CHAR ch = n;
+ ck_tn_decrypt((char *)&ch,1);
+ n = ch;
+ debug(F000,"TTINL decryp char","",n);
+ }
+ pushedback = 0;
+#endif /* CK_ENCRYPTION */
+
+#ifdef TCPSOCKET
+ if (n == IAC && /* Handle Telnet options */
+ ((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet))) {
+ n = tt_tnopt(n);
+ if (n < 0)
+ return(n);
+#ifndef NOPARSEN
+ else if (n == 1)
+ start = stchr;
+#endif /* NOPARSEN */
+ if (n != 255) /* No data - go back for next char */
+ continue;
+ } /* Quoted IAC - keep going */
+#endif /* TCPSOCKET */
+
+#ifdef CKXXCHAR
+ if (ignflag)
+ if (dblt[(unsigned) n] & 1) /* Character to ignore? */
+ continue;
+#endif /* CKXXCHAR */
+/*
+ Use parity mask, rather than always stripping parity, to check for
+ cancellation. Otherwise, runs like \x03\x83\x03 in a packet could cancel
+ the transfer when parity is NONE. (Note that \x03\x03\x03 is extremely
+ unlikely due to run-length encoding.)
+*/
+ /* Check cancellation */
+ if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
+ if (++ccn >= xfrnum) { /* If xfrnum in a row, bail out. */
+ if (timo) { /* Clear timer. */
+ ttimoff();
+ }
+ if (xfrchr < 32)
+ printf("^%c...\r\n",(char)(xfrchr+64));
+ else
+ printf("Canceled...\r\n");
+ return(-2);
+ }
+ } else ccn = 0; /* No cancellation, reset counter, */
+
+#ifdef PARSENSE
+/*
+ Restructured code allows for a new packet to appear somewhere in the
+ middle of a previous one. -fdc, 24 Feb 2007.
+*/
+ if ((n & sopmask) == start) { /* Start of Packet */
+ debug(F101,"ttinl SOP i","",i);
+ flag = 1; /* Flag that we are in a packet */
+ havelen = 0; /* Invalidate previous length */
+ pktlen = -1; /* (if any) in case we were */
+ lplen = 0; /* alread processand a packet */
+ i = 0; /* and reset the dest buffer pointer */
+ }
+ if (flag == 0) { /* No SOP yet... */
+ debug(F000,"ttinl skipping","",n);
+ continue;
+ }
+ dest[i++] = n & ttpmsk;
+/*
+ If we have not been instructed to wait for a turnaround character, we can go
+ by the packet length field. If turn != 0, we must wait for the end of line
+ (eol) character before returning. This is an egregious violation of all
+ principles of layering... (Less egregious in C-Kermit 9.0, in which we go
+ by the length field but also look for the eol in case it arrives early,
+ e.g. if the length field was corrupted upwards.)
+*/
+ if (!havelen) {
+ if (i == 2) {
+ if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
+ return(-1); /* fdc - 13 Apr 2010 */
+ pktlen = xunchar(dest[1] & 0x7f);
+ if (pktlen > 94) /* Rubout in length field */
+ return(-1); /* fdc - 13 Apr 2010 */
+ if (pktlen > 1) {
+ havelen = 1;
+ debug(F101,"ttinl pktlen value","",pktlen);
+ }
+ } else if (i == 5 && pktlen == 0) {
+ lplen = xunchar(dest[4] & 0x7f);
+ } else if (i == 6 && pktlen == 0) {
+ pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
+ havelen = 1;
+ debug(F101,"ttinl extended length","",pktlen);
+ }
+ }
+
+/*
+ Suppose we looked at the sequence number here and found it was out of
+ range? This would mean either (a) incoming packets had SOP unprefixed
+ and we are out of sync, or (b) the packet is damaged. Since (a) is bad
+ practice, let's ignore it. So what should we do here if we know the
+ packet is damaged?
+
+ 1. Nothing -- keep trying to read the packet till we find what we think
+ is the end, or we time out, and let the upper layer decide what to
+ do. But since either the packet is corrupt or we are out of sync,
+ our criterion for finding the end does not apply and we are likely
+ to time out (or swallow a piece of the next packet) if our assumed
+ length is too long. (This was the behavior prior to version 7.0.)
+
+ 2. set flag = 0 and continue? This would force us to wait for the
+ next packet to come in, and therefore (in the nonwindowing case),
+ would force a timeout in the other Kermit.
+
+ 3. set flag = 0 and continue, but only if the window size is > 1 and
+ the window is not blocked? Talk about cheating!
+
+ 4. Return a failure code and let the upper layer decide what to do.
+ This should be equivalent to 3, but without the cheating. So let's
+ do it that way... But note that we must ignore the parity bit
+ in case this is the first packet and we have not yet run parchk().
+*/
+ if (i == 3) { /* Peek at sequence number */
+ x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
+ if (x < 0 || x > 63) {
+ debug(F111,"ttinl bad seq",dest,x);
+ if (timo) ttimoff();
+ return(-1); /* return a nonfatal error */
+ }
+ }
+
+#else /* PARSENSE */
+ dest[i++] = n & ttpmsk;
+#endif /* PARSENSE */
+
+ /* Check for end of packet */
+
+ if (
+ ((n & ttpmsk) == eol) /* Always break on the eol char */
+#ifdef PARSENSE
+ || /* fdc - see notes of 13 Apr 2010 */
+/*
+ Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
+ This allows packet terminators and handshake characters to appear
+ literally inside a packet data field.
+*/
+ (havelen && (i > pktlen+1) &&
+ (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
+
+#endif /* PARSENSE */
+ ) {
+/*
+ Here we have either read the last byte of the packet based on its length
+ field, or else we have read the packet terminator (eol) or the half-duplex
+ line-turnaround char (turn).
+*/
+#ifndef PARSENSE
+ debug(F101,"ttinl got eol","",eol); /* (or turn) */
+ dest[i] = '\0'; /* Yes, terminate the string, */
+ /* debug(F101,"ttinl i","",i); */
+
+#else /* PARSENSE */
+
+#ifdef DEBUG
+ if (deblog) {
+ if ((n & ttpmsk) != eol) {
+ debug(F101,"ttinl EOP length","",pktlen);
+ debug(F000,"ttinl EOP current char","",n);
+ debug(F101,"ttinl EOP packet buf index","",i);
+ } else debug(F101,"ttinl got eol","",eol);
+ }
+#endif /* DEBUG */
+
+#ifdef MYREAD
+/*
+ The packet was read based on its length. This leaves the packet terminator
+ unread, and so ttchk() will always return at least 1 because of this,
+ possibly giving a false positive to the "is there another packet waiting?"
+ test. But if we know the terminator (or any other interpacket junk) is
+ there, we can safely get rid of it.
+
+ NOTE: This code reworked to (a) execute even if the debug log isn't active;
+ and (b) actually work. -fdc, 2007/02/22. And again 2007/08/12-13 to also
+ work on encrypted connections.
+*/
+ debug(F101,"TTINL my_count","",my_count);
+ if ((n & ttpmsk) != eol) { /* Not the packet terminator */
+ int x;
+ while (my_count > 0) {
+ x = myread(); /* (was ttinc(0) */
+ debug(F000,"TTINL lkread char","",x);
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ CHAR ch = x;
+ ck_tn_decrypt((char *)&ch,1);
+ x = ch;
+ debug(F000,"TTINL lkdecr char","",x);
+ }
+#endif /* CK_ENCRYPTION */
+ /*
+ Note: while it might seem more elegant to simply
+ push back the encrypted byte, that desynchronizes
+ the decryption stream; the flag is necessary so we
+ don't try to decrypt the same byte twice.
+ */
+ if ((x & ttpmsk) == start) { /* Start of next packet */
+ myunrd(x); /* Push back the decrypted byte */
+ pushedback = 1; /* And set flag */
+ debug(F000,"TTINL lkpush char","",x);
+ break;
+ }
+ }
+ }
+#endif /* MYREAD */
+
+ dest[i] = '\0'; /* Terminate the string, */
+ if (needpchk) { /* Parity checked yet? */
+ if (ttprty == 0) { /* No, check. */
+ if ((ttprty = parchk(dest,start,i)) > 0) {
+ int j;
+ debug(F101,"ttinl senses parity","",ttprty);
+ debug(F110,"ttinl packet before",dest,0);
+ ttpmsk = 0x7f;
+ for (j = 0; j < i; j++)
+ dest[j] &= 0x7f; /* Strip parity from packet */
+ debug(F110,"ttinl packet after ",dest,0);
+ } else ttprty = 0; /* Restore if parchk error */
+ }
+ sopmask = ttpmsk;
+ needpchk = 0;
+ }
+#endif /* PARSENSE */
+
+ if (timo) /* Turn off timer if it was on */
+ ttimoff();
+ ckhexdump("ttinl got",dest,i);
+
+#ifdef STREAMING
+ /* ttinl() was called because there was non-packet */
+ /* data sitting in the back channel. Ignore it. */
+ if (streaming && sndtyp == 'D')
+ return(-1);
+#endif /* STREAMING */
+ return(i);
+ }
+ } /* End of while() */
+ ttimoff();
+ return(n);
+ }
+}
+#endif /* NOXFER */
+
+/* T T I N C -- Read a character from the communication line */
+/*
+ On success, returns the character that was read, >= 0.
+ On failure, returns -1 or other negative myread error code,
+ or -2 if connection is broken or ttyfd < 0.
+ or -3 if session limit has expired,
+ or -4 if something or other...
+ NOTE: The API does not provide for ttinc() returning a special code
+ upon timeout, but we need it. So for this we have a global variable,
+ ttinctimo.
+*/
+static int ttinctimo = 0; /* Yuk */
+
+int
+ttinc(timo) int timo; {
+
+ int n = 0, fd;
+ int is_tn = 0;
+ CHAR ch = 0;
+
+ ttinctimo = 0;
+
+ if (ttyfd < 0) return(-2); /* Not open. */
+
+ is_tn = (xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet);
+
+#ifdef TTLEBUF
+ if (ttpush >= 0) {
+ debug(F111,"ttinc","ttpush",ttpush);
+ ch = ttpush;
+ ttpush = -1;
+ return(ch);
+ }
+ if (le_data) {
+ if (le_getchar(&ch) > 0) {
+ debug(F111,"ttinc le_getchar","ch",ch);
+ return(ch);
+ }
+ }
+#endif /* TTLEBUF */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+ if ((timo <= 0) /* Untimed. */
+#ifdef MYREAD
+ || (my_count > 0) /* Buffered char already waiting. */
+#endif /* MYREAD */
+ ) {
+#ifdef MYREAD
+ /* Comm line failure returns -1 thru myread, so no &= 0377 */
+ n = myread(); /* Wait for a character... */
+ /* debug(F000,"ttinc MYREAD n","",n); */
+#ifdef CK_ENCRYPTION
+ /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
+ if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
+ ch = n;
+ ck_tn_decrypt((char *)&ch,1);
+ n = ch;
+ }
+#endif /* CK_ENCRYPTION */
+
+#ifdef NETPTY
+ if (ttpty && n < 0) {
+ debug(F101,"ttinc error on pty","",n);
+ ttclos(0);
+ return(n);
+ }
+#endif /* NETPTY */
+
+#ifdef TNCODE
+ if ((n > -1) && is_tn)
+ return((unsigned)(n & 0xff));
+ else
+#endif /* TNCODE */
+ return(n < 0 ? n : (unsigned)(n & ttpmsk));
+
+#else /* MYREAD */
+
+ while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
+ /* Shouldn't have to loop in ver 5A. */
+#ifdef NETCONN
+ if (netconn) { /* Special handling for net */
+ netclos(); /* If read() returns 0 it means */
+ netconn = 0; /* the connection has dropped. */
+ errno = ENOTCONN;
+ return(-2);
+ }
+#endif /* NETCONN */
+ ;
+ /* debug(F101,"ttinc","",ch); */
+#ifdef TNCODE
+ if ((n > 0) && is_tn) {
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ ck_tn_decrypt(&ch,1);
+ n = ch;
+ }
+#endif /* CK_ENCRYPTION */
+ return((unsigned)(ch & 0xff));
+ } else
+#endif /* TNCODE */
+ return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
+#endif /* MYREAD */
+
+ } else { /* Timed read */
+
+ int oldalarm;
+ saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
+ oldalarm = alarm(timo); /* Set alarm, save old one. */
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer expired */
+ ttinctimo = 1;
+ n = -1; /* set flag */
+ } else {
+#ifdef MYREAD
+ n = myread(); /* If managing own buffer... */
+ debug(F101,"ttinc myread","",n);
+ ch = n;
+#else
+ n = read(fd,&ch,1); /* Otherwise call the system. */
+ if (n == 0) n = -1;
+ debug(F101,"ttinc read","",n);
+#endif /* MYREAD */
+
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
+ ck_tn_decrypt((char *)&ch,1);
+ }
+#endif /* CK_ENCRYPTION */
+ if (n >= 0)
+ n = (unsigned) (ch & 0xff);
+ else
+ n = (n < 0) ? -4 : -2; /* Special return codes. */
+ }
+ ttimoff(); /* Turn off the timer */
+ if (oldalarm > 0) {
+ if (n == -1) /* and restore any previous alarm */
+ oldalarm -= timo;
+ if (oldalarm < 0) /* adjusted by our timeout interval */
+ oldalarm = 0;
+ if (oldalarm) {
+ debug(F101,"ttinc restoring oldalarm","",oldalarm);
+ alarm(oldalarm);
+ }
+ }
+#ifdef NETCONN
+ if (netconn) {
+ if (n == -2) { /* read() returns 0 */
+ netclos(); /* on network read failure */
+ netconn = 0;
+ errno = ENOTCONN;
+ }
+ }
+#endif /* NETCONN */
+#ifdef TNCODE
+ if ((n > -1) && is_tn)
+ return((unsigned)(n & 0xff));
+ else
+#endif /* TNCODE */
+ /* Return masked char or neg. */
+ return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
+ }
+}
+
+/* S N D B R K -- Send a BREAK signal of the given duration */
+
+static int
+#ifdef CK_ANSIC
+sndbrk(int msec) { /* Argument is milliseconds */
+#else
+sndbrk(msec) int msec; {
+#endif /* CK_ANSIC */
+#ifndef POSIX
+ int x, n;
+#endif /* POSIX */
+
+#ifdef OXOS
+#define BSDBREAK
+#endif /* OXOS */
+
+#ifdef ANYBSD
+#define BSDBREAK
+#endif /* ANYBSD */
+
+#ifdef BSD44
+#define BSDBREAK
+#endif /* BSD44 */
+
+#ifdef COHERENT
+#ifdef BSDBREAK
+#undef BSDBREAK
+#endif /* BSDBREAK */
+#endif /* COHERENT */
+
+#ifdef BELLV10
+#ifdef BSDBREAK
+#undef BSDBREAK
+#endif /* BSDBREAK */
+#endif /* BELLV10 */
+
+#ifdef PROVX1
+ char spd;
+#endif /* PROVX1 */
+
+ debug(F101,"ttsndb ttyfd","",ttyfd);
+ if (ttyfd < 0) return(-1); /* Not open. */
+
+#ifdef Plan9
+ return p9sndbrk(msec);
+#else
+#ifdef NETCONN
+#ifdef NETCMD
+ if (ttpipe) /* Pipe */
+ return(ttoc('\0'));
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty)
+ return(ttoc('\0'));
+#endif /* NETPTY */
+ if (netconn) /* Send network BREAK */
+ return(netbreak());
+#endif /* NETCONN */
+
+ if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
+
+#ifdef POSIX /* Easy in POSIX */
+ {
+ int x;
+ debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
+ errno = 0;
+ x = tcsendbreak(ttyfd,msec / 375);
+ debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
+ return(x);
+ }
+#else
+#ifdef PROVX1
+ gtty(ttyfd,&ttbuf); /* Get current tty flags */
+ spd = ttbuf.sg_ospeed; /* Save speed */
+ ttbuf.sg_ospeed = B50; /* Change to 50 baud */
+ stty(ttyfd,&ttbuf); /* ... */
+ n = (int)strlen(brnuls); /* Send the right number of nulls */
+ x = msec / 91;
+ if (x > n) x = n;
+ write(ttyfd,brnuls,n);
+ ttbuf.sg_ospeed = spd; /* Restore speed */
+ stty(ttyfd,&ttbuf); /* ... */
+ return(0);
+#else
+#ifdef aegis
+ sio_$control((short)ttyfd, sio_$send_break, msec, st);
+ return(0);
+#else
+#ifdef BSDBREAK
+ n = FWRITE; /* Flush output queue. */
+/* Watch out for int vs long problems in &n arg! */
+ debug(F101,"sndbrk BSDBREAK","",msec);
+ ioctl(ttyfd,TIOCFLUSH,&n); /* Ignore any errors.. */
+ if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */
+ perror("Can't send BREAK");
+ return(-1);
+ }
+ x = msleep(msec); /* Sleep for so many milliseconds */
+ if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */
+ perror("BREAK stuck!!!");
+ doexit(BAD_EXIT,-1); /* Get out, closing the line. */
+ /* with bad exit status */
+ }
+ return(x);
+#else
+#ifdef ATTSV
+/*
+ No way to send a long BREAK in Sys V, so send a bunch of regular ones.
+ (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
+ but there's no way for this code to know for sure.)
+*/
+ debug(F101,"sndbrk ATTSV","",msec);
+ x = msec / 275;
+ for (n = 0; n < x; n++) {
+ /* Reportedly the cast breaks this function on some systems */
+ /* But then why was it here in the first place? */
+ if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
+ perror("Can't send BREAK");
+ return(-1);
+ }
+ }
+ return(0);
+#else
+#ifdef V7
+ debug(F101,"sndbrk V7","",msec);
+ return(genbrk(ttyfd,250)); /* Simulate a BREAK */
+#else
+ debug(F101,"sndbrk catchall","",msec);
+ ttoc(0);ttoc(0);ttoc(0);ttoc(0);
+ return(0);
+#endif /* V7 */
+#endif /* BSDBREAK */
+#endif /* ATTSV */
+#endif /* aegis */
+#endif /* PROVX1 */
+#endif /* POSIX */
+#endif /* Plan9 */
+}
+
+/* T T S N D B -- Send a BREAK signal */
+
+int
+ttsndb() {
+#ifdef TN_COMPORT
+ if (netconn && istncomport())
+ return((tnsndb(275L) >= 0) ? 0 : -1);
+ else
+#endif /* TN_COMPORT */
+ return(sndbrk(275));
+}
+
+/* T T S N D L B -- Send a Long BREAK signal */
+
+int
+ttsndlb() {
+#ifdef TN_COMPORT
+ if (netconn && istncomport())
+ return((tnsndb(1800L) >= 0) ? 0 : -1);
+ else
+#endif /* TN_COMPORT */
+ return(sndbrk(1500));
+}
+
+/* M S L E E P -- Millisecond version of sleep(). */
+
+/*
+ Call with number of milliseconds (thousandths of seconds) to sleep.
+ Intended only for small intervals. For big ones, just use sleep().
+ Highly system-dependent.
+ Returns 0 always, even if it didn't work.
+*/
+
+/* Define MSLFTIME for systems that must use an ftime() loop. */
+#ifdef ANYBSD /* For pre-4.2 BSD versions */
+#ifndef BSD4
+#define MSLFTIME
+#endif /* BSD4 */
+#endif /* ANYBSD */
+
+#ifdef TOWER1 /* NCR Tower OS 1.0 */
+#define MSLFTIME
+#endif /* TOWER1 */
+
+#ifdef COHERENT /* Coherent... */
+#ifndef _I386 /* Maybe Coherent/386 should get this, too */
+#define MSLFTIME /* Opinions are divided */
+#endif /* _I386 */
+#endif /* COHERENT */
+
+#ifdef COMMENT
+#ifdef GETMSEC
+
+/* Millisecond timer */
+
+static long msecbase = 0L; /* Unsigned long not portable */
+
+long
+getmsec() { /* Milliseconds since base time */
+ struct timeval xv;
+ struct timezone xz;
+ long secs, msecs;
+ if (
+#ifdef GTODONEARG
+ gettimeofday(&tv)
+#else
+#ifdef PTX
+ gettimeofday(&tv, NULL)
+#else
+ gettimeofday(&tv, &tz)
+#endif /* PTX */
+#endif /* GTODONEARG */
+ < 0)
+ return(-1);
+ if (msecbase == 0L) { /* First call, set base time. */
+ msecbase = tv.tv_sec;
+ debug(F101,"getmsec base","",msecbase);
+ }
+ return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
+}
+#endif /* GETMSEC */
+#endif /* COMMENT */
+
+#ifdef SELECT
+int
+ttwait(fd, secs) int fd, secs; {
+ int x;
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(fd,&rfds);
+ tv.tv_sec = secs;
+ tv.tv_usec = 0L;
+ errno = 0;
+ if ((x = select(FD_SETSIZE,
+#ifdef HPUX9
+ (int *)
+#else
+#ifdef HPUX1000
+ (int *)
+#endif /* HPUX1000 */
+#endif /* HPUX9 */
+ &rfds,
+ 0, 0, &tv)) < 0) {
+ debug(F101,"ttwait select errno","",errno);
+ return(0);
+ } else {
+ debug(F101,"ttwait OK","",errno);
+ x = FD_ISSET(fd, &rfds);
+ debug(F101,"ttwait select x","",x);
+ return(x ? 1 : 0);
+ }
+}
+#endif /* SELECT */
+
+int
+msleep(m) int m; {
+/*
+ Other possibilities here are:
+ nanosleep(), reportedly defined in POSIX.4.
+ sginap(), IRIX only (back to what IRIX version I don't know).
+*/
+#ifdef Plan9
+ return _SLEEP(m);
+#else
+#ifdef BEOSORBEBOX
+ snooze(m*1000);
+#else /* BEOSORBEBOX */
+#ifdef SELECT
+ int t1, x;
+ debug(F101,"msleep SELECT 1","",m);
+ if (m <= 0) return(0);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ debug(F101,"msleep SELECT 2","",m);
+#ifdef BELLV10
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
+ debug(F101,"msleep BELLV10 select","",x);
+#else /* BELLV10 */
+#ifdef HPUX9
+ gettimeofday(&tv, &tz);
+#else
+
+#ifndef COHERENT
+#ifdef GTODONEARG
+ if (gettimeofday(&tv) < 0)
+#else
+#ifdef PTX
+ if (gettimeofday(&tv,NULL) < 0)
+#else
+#ifdef NOTIMEZONE
+ if (gettimeofday(&tv, NULL) < 0) /* wonder what this does... */
+#else
+ if (gettimeofday(&tv, &tz) < 0)
+#endif /* NOTIMEZONE */
+#endif /* PTX */
+#endif /* GTODONEARG */
+ return(-1);
+ t1 = tv.tv_sec; /* Seconds */
+#endif /* COHERENT */
+#endif /* HPUX9 */
+ tv.tv_sec = 0; /* Use select() */
+ tv.tv_usec = m * 1000L;
+#ifdef BSD44
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep BSD44 select","",x);
+#else /* BSD44 */
+#ifdef __linux__
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep __linux__ select","",x);
+#else /* __linux__ */
+#ifdef BSD43
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep BSD43 select","",x);
+#else /* BSD43 */
+#ifdef QNX6
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep QNX6 select","",x);
+#else /* QNX6 */
+#ifdef QNX
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep QNX select","",x);
+#else /* QNX */
+#ifdef COHERENT
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep COHERENT select","",x);
+#else /* COHERENT */
+#ifdef HPUX1000 /* 10.00 only, not 10.10 or later */
+ x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
+ debug(F101,"msleep HP-UX 10.00 select","",x);
+#else /* HPUX1000 */
+#ifdef SVR4
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep SVR4 select","",x);
+#else /* SVR4 */
+#ifdef OSF40
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep OSF40 select","",x);
+#else /* OSF40 */
+#ifdef PTX
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep OSF40 select","",x);
+#else
+ x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
+ debug(F101,"msleep catch-all select","",x);
+#endif /* PTX */
+#endif /* OSF40 */
+#endif /* HP1000 */
+#endif /* SVR4 */
+#endif /* COHERENT */
+#endif /* QNX */
+#endif /* QNX6 */
+#endif /* BSD43 */
+#endif /* __linux__ */
+#endif /* BSD44 */
+#endif /* BELLV10 */
+ return(0);
+
+#else /* Not SELECT */
+#ifdef CK_POLL /* We have poll() */
+ struct pollfd pfd; /* Supply a valid address for poll() */
+
+#ifdef ODT30 /* But in SCO ODT 3.0 */
+#ifdef NAP /* we should use nap() instead */
+ debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
+ nap((long)m); /* seems to break dialing. */
+ return(0);
+#else
+ debug(F101,"msleep ODT 3.0 POLL","",m);
+ poll(&pfd, 0, m);
+ return(0);
+#endif /* NAP */
+#else
+ debug(F101,"msleep POLL","",m);
+ poll(&pfd, 0, m);
+ return(0);
+#endif /* ODT30 */
+
+/*
+ We could handle the above more cleanly by just letting nap() always
+ take precedence over poll() in this routine, but there is no way to know
+ whether that would break something else.
+*/
+
+#else /* Not POLL */
+#ifdef USLEEP
+/*
+ "This routine is implemented using setitimer(2); it requires eight
+ system calls...". In other words, it might take 5 minutes to sleep
+ 10 milliseconds...
+*/
+ debug(F101,"msleep USLEEP","",m);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ usleep((unsigned int)(m * 1000));
+ return(0);
+#else
+#ifdef aegis
+ time_$clock_t dur;
+ debug(F101,"msleep aegis","",m);
+ dur.c2.high16 = 0;
+ dur.c2.low32 = 250 * m; /* one millisecond = 250 four microsecond ticks */
+ time_$wait(time_$relative, dur, st);
+ return(0);
+#else
+#ifdef PROVX1
+ debug(F101,"msleep Venix","",m);
+ if (m <= 0) return(0);
+ sleep(-((m * 60 + 500) / 1000));
+ return(0);
+#else
+#ifdef NAP
+ debug(F101,"msleep NAP","",m);
+ nap((long)m);
+ return(0);
+#else
+#ifdef ATTSV
+#ifndef BSD44
+ extern long times(); /* Or #include <times.h> ? */
+#endif /* BSD44 */
+ long t1, t2, tarray[4];
+ int t3;
+ char *cp = getenv("HZ");
+ int CLOCK_TICK;
+ int hertz;
+
+ if (cp && (hertz = atoi(cp))) {
+ CLOCK_TICK = 1000 / hertz;
+ } else { /* probably single user mode */
+#ifdef HZ
+ CLOCK_TICK = 1000 / HZ;
+#else
+ static warned = 0;
+ /* HZ always exists in, for instance, SCO Xenix, so you don't have to
+ * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
+ * have Xenix, you have should have nap(), so the best is to use -DNAP
+ * in the makefile. Most systems have HZ.
+ */
+ CLOCK_TICK = 17; /* 1/60 sec */
+ if (!warned) {
+ printf("warning: environment variable HZ bad... using HZ=%d\r\n",
+ 1000 / CLOCK_TICK);
+ warned = 1;
+ }
+#endif /* !HZ */
+ }
+ debug(F101,"msleep ATTSV","",m);
+ if (m <= 0) return(0);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ if ((t1 = times(tarray)) < 0) return(-1);
+ while (1) {
+ if ((t2 = times(tarray)) < 0) return(-1);
+ t3 = ((int)(t2 - t1)) * CLOCK_TICK;
+ if (t3 > m) return(t3);
+ }
+#else /* Not ATTSV */
+#ifdef MSLFTIME /* Use ftime() loop... */
+ int t1, t3 = 0;
+ debug(F101,"msleep MSLFTIME","",m);
+ if (m <= 0) return(0);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+#ifdef QNX
+ ftime(&ftp); /* void ftime() in QNX */
+#else
+ if (ftime(&ftp) < 0) return(-1); /* Get base time. */
+#endif /* QNX */
+ t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
+ while (1) {
+ ftime(&ftp); /* Get current time and compare. */
+ t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
+ if (t3 > m) return(0);
+ }
+#else
+/* This includes true POSIX, which has no way to do this. */
+ debug(F101,"msleep busy loop","",m);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ if (m > 0) while (m > 0) m--; /* Just a dumb busy loop */
+ return(0);
+#endif /* MSLFTIME */
+#endif /* ATTSV */
+#endif /* NAP */
+#endif /* PROVX1 */
+#endif /* aegis */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* BEOSORBEBOX */
+#endif /* USLEEP */
+#endif /* Plan9 */
+}
+
+/* R T I M E R -- Reset elapsed time counter */
+
+VOID
+rtimer() {
+ tcount = time( (time_t *) 0 );
+}
+
+
+/* G T I M E R -- Get current value of elapsed time counter in seconds */
+
+int
+gtimer() {
+ int x;
+ x = (int) (time( (time_t *) 0 ) - tcount);
+ debug(F101,"gtimer","",x);
+ return( (x < 0) ? 0 : x );
+}
+
+#ifdef GFTIMER
+/*
+ Floating-point timers. Require not only floating point support, but
+ also gettimeofday().
+*/
+static struct timeval tzero;
+
+VOID
+rftimer() {
+#ifdef GTODONEARG /* Account for Mot's definition */
+ (VOID) gettimeofday(&tzero);
+#else
+ (VOID) gettimeofday(&tzero, (struct timezone *)0);
+#endif /* GTODONEARG */
+}
+
+CKFLOAT
+gftimer() {
+ struct timeval tnow, tdelta;
+ CKFLOAT s;
+#ifdef DEBUG
+ char fpbuf[64];
+#endif /* DEBUG */
+#ifdef GTODONEARG /* Account for Mot's definition */
+ (VOID) gettimeofday(&tnow);
+#else
+ (VOID) gettimeofday(&tnow, (struct timezone *)0);
+#endif /* GTODONEARG */
+
+ tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
+ tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
+
+ if (tdelta.tv_usec < 0) {
+ tdelta.tv_sec--;
+ tdelta.tv_usec += 1000000;
+ }
+ s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
+ if (s < GFMINTIME)
+ s = GFMINTIME;
+#ifdef DEBUG
+ if (deblog) {
+ sprintf(fpbuf,"%f",s);
+ debug(F110,"gftimer",fpbuf,0);
+ }
+#endif /* DEBUG */
+ return(s);
+}
+#endif /* GFTIMER */
+
+/* Z T I M E -- Return asctime()-format date/time string */
+/*
+ NOTE: as a side effect of calling this routine, we can also set the
+ following two variables, giving the micro- and milliseconds (fractions of
+ seconds) of the clock time. Currently this is done only in BSD-based builds
+ that use gettimeofday(). When these variables are not filled in, they are
+ left with a value of -1L.
+*/
+static char asctmbuf[64];
+
+VOID
+ztime(s) char **s; {
+
+#ifdef GFTIMER
+/*
+ The gettimeofday() method, which also sets ztmsec and ztusec, works for
+ all GFTIMER builds. NOTE: ztmsec and ztusec are defined in ckcmai.c,
+ and extern declarations for them are in ckcdeb.h; thus they are
+ declared in this file by inclusion of ckcdeb.h.
+*/
+ char *asctime();
+ struct tm *localtime();
+ struct tm *tp;
+ ztmsec = -1L;
+ ztusec = -1L;
+
+ if (!s)
+ debug(F100,"ztime s==NULL","",0);
+
+#ifdef GTODONEARG
+ /* No 2nd arg in Motorola SV88 and some others */
+ if (gettimeofday(&tv) > -1)
+#else
+#ifndef COHERENT
+#ifdef PTX
+ if (gettimeofday(&tv,NULL) > -1)
+#else
+#ifdef NOTIMEZONE
+ if (gettimeofday(&tv, NULL) > -1) /* wonder what this does... */
+#else
+ if (gettimeofday(&tv, &tz) > -1)
+#endif /* NOTIMEZONE */
+#endif /* PTX */
+#endif /* COHERENT */
+#endif /* GTODONEARG */
+ { /* Fill in tm struct */
+ ztusec = tv.tv_usec; /* Microseconds */
+ ztmsec = ztusec / 1000L; /* Milliseconds */
+#ifdef HPUX9
+ {
+ time_t zz;
+ zz = tv.tv_sec;
+ tp = localtime(&zz); /* Convert to local time */
+ }
+#else
+#ifdef HPUX1000
+ {
+ time_t zz;
+ zz = tv.tv_sec;
+ tp = localtime(&zz);
+ }
+#else
+#ifdef LINUX
+ { /* avoid unaligned access trap on 64-bit platforms */
+ time_t zz;
+ zz = tv.tv_sec;
+ tp = localtime(&zz);
+ }
+#else
+#ifdef MACOSX
+ tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
+#else
+ tp = localtime(&tv.tv_sec);
+#endif /* MACOSX */
+#endif /* LINUX */
+#endif /* HPUX1000 */
+#endif /* HPUX9 */
+ if (s) {
+ char * s2;
+ s2 = asctime(tp); /* Convert result to ASCII string */
+ asctmbuf[0] = '\0';
+ if (s2) ckstrncpy(asctmbuf,s2,64);
+ *s = asctmbuf;
+ debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
+ }
+ }
+#else /* Not GFTIMER */
+
+#undef ZTIMEV7 /* Which systems need to use */
+#ifdef COHERENT /* old UNIX Version 7 way... */
+#define ZTIMEV7
+#endif /* COHERENT */
+#ifdef TOWER1
+#define ZTIMEV7
+#endif /* TOWER1 */
+#ifdef ANYBSD
+#ifndef BSD42
+#define ZTIMEV7
+#endif /* BSD42 */
+#endif /* ANYBSD */
+#ifdef V7
+#ifndef MINIX
+#define ZTIMEV7
+#endif /* MINIX */
+#endif /* V7 */
+#ifdef POSIX
+#define ZTIMEV7
+#endif /* POSIX */
+
+#ifdef HPUX1020
+/*
+ Prototypes are in <time.h>, included above.
+*/
+ time_t clock_storage;
+ clock_storage = time((void *) 0);
+ if (s) {
+ *s = ctime(&clock_storage);
+ debug(F110,"ztime: HPUX 10.20",*s,0);
+ }
+#else
+#ifdef ATTSV /* AT&T way */
+/* extern long time(); */ /* Theoretically these should */
+ char *ctime(); /* already been dcl'd in <time.h> */
+ time_t clock_storage;
+ clock_storage = time(
+#ifdef IRIX60
+ (time_t *)
+#else
+#ifdef BSD44
+ (time_t *)
+#else
+ (long *)
+#endif /* BSD44 */
+#endif /* IRIX60 */
+ 0 );
+ if (s) {
+ *s = ctime( &clock_storage );
+ debug(F110,"ztime: ATTSV",*s,0);
+ }
+#else
+#ifdef PROVX1 /* Venix 1.0 way */
+ int utime[2];
+ time(utime);
+ if (s) {
+ *s = ctime(utime);
+ debug(F110,"ztime: PROVX1",*s,0);
+ }
+#else
+#ifdef BSD42 /* 4.2BSD way */
+ char *asctime();
+ struct tm *localtime();
+ struct tm *tp;
+ gettimeofday(&tv, &tz);
+ ztusec = tv.tv_usec;
+ ztmsec = tv.tv_usec / 1000L;
+ tp = localtime(&tv.tv_sec);
+ if (s) {
+ *s = asctime(tp);
+ debug(F111,"ztime: BSD42",*s,ztusec);
+ }
+#else
+#ifdef MINIX /* MINIX way */
+#ifdef COMMENT
+ extern long time(); /* Already got these from <time.h> */
+ extern char *ctime();
+#endif /* COMMENT */
+ time_t utime[2];
+ time(utime);
+ if (s) {
+ *s = ctime(utime);
+ debug(F110,"ztime: MINIX",*s,0);
+ }
+#else
+#ifdef ZTIMEV7 /* The regular way */
+ char *asctime();
+ struct tm *localtime();
+ struct tm *tp;
+ long xclock; /* or unsigned long for BeBox? */
+ time(&xclock);
+ tp = localtime(&xclock);
+ if (s) {
+ *s = asctime(tp);
+ debug(F110,"ztime: ZTIMEV7",*s,0);
+ }
+#else /* Catch-all for others... */
+ if (s) {
+ *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
+ debug(F110,"ztime: catch-all",*s,0);
+ }
+#endif /* ZTIMEV7 */
+#endif /* MINIX */
+#endif /* BSD42 */
+#endif /* PROVX1 */
+#endif /* ATTSV */
+#endif /* HPUX1020 */
+#endif /* GFTIMER */
+}
+
+/* C O N G M -- Get console terminal modes. */
+
+/*
+ Saves initial console mode, and establishes variables for switching
+ between current (presumably normal) mode and other modes.
+ Should be called when program starts, but only after establishing
+ whether program is in the foreground or background.
+ Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
+*/
+int
+congm() {
+ int fd;
+ if (backgrd || !isatty(0)) { /* If in background. */
+ cgmf = -1; /* Don't bother, modes are garbage. */
+ return(-1);
+ }
+ if (cgmf > 0) return(0); /* Already did this. */
+ debug(F100,"congm getting modes","",0); /* Need to do it. */
+#ifdef aegis
+ ios_$inq_type_uid(ios_$stdin, conuid, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "problem getting stdin objtype: ");
+ error_$print(st);
+ }
+ concrp = (conuid == mbx_$uid);
+ conbufn = 0;
+#endif /* aegis */
+
+#ifndef BEBOX
+ if ((fd = open(CTTNAM,2)) < 0) { /* Open controlling terminal */
+#ifdef COMMENT
+ fprintf(stderr,"Error opening %s\n", CTTNAM);
+ perror("congm");
+ return(-1);
+#else
+ fd = 0;
+#endif /* COMMENT */
+ }
+#else
+ fd = 0;
+#endif /* !BEBOX */
+#ifdef BSD44ORPOSIX
+ if (tcgetattr(fd,&ccold) < 0) return(-1);
+ if (tcgetattr(fd,&cccbrk) < 0) return(-1);
+ if (tcgetattr(fd,&ccraw) < 0) return(-1);
+#else
+#ifdef ATTSV
+ if (ioctl(fd,TCGETA,&ccold) < 0) return(-1);
+ if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
+ if (ioctl(fd,TCGETA,&ccraw) < 0) return(-1);
+#ifdef VXVE
+ cccbrk.c_line = 0; /* STTY line 0 for CDC VX/VE */
+ if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
+ ccraw.c_line = 0; /* STTY line 0 for CDC VX/VE */
+ if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
+#endif /* VXVE */
+#else
+#ifdef BELLV10
+ if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
+ if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
+ if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
+ debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
+#else
+ if (gtty(fd,&ccold) < 0) return(-1);
+ if (gtty(fd,&cccbrk) < 0) return(-1);
+ if (gtty(fd,&ccraw) < 0) return(-1);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#ifdef sony_news /* Sony NEWS */
+ if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
+ perror("congm error getting Kanji mode");
+ debug(F101,"congm error getting Kanji mode","",0);
+ km_con = -1; /* Make sure this stays undefined. */
+ return(-1);
+ }
+#endif /* sony_news */
+ if (fd > 0)
+ close(fd);
+ cgmf = 1; /* Flag that we got them. */
+ return(1);
+}
+
+
+static VOID
+congetbuf(x) int x; {
+ int n;
+ n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */
+ if (x > n) {
+ debug(F101,"congetbuf char loss","",x-n);
+ x = n;
+ }
+ x = read(0,conbufp,x);
+ conbufn += x;
+ debug(F111,"congetbuf readahead",conbuf,x);
+}
+
+
+/* C O N C B -- Put console in cbreak mode. */
+
+/* Returns 0 if ok, -1 if not */
+
+int
+#ifdef CK_ANSIC
+concb(char esc)
+#else
+concb(esc) char esc;
+#endif /* CK_ANSIC */
+/* concb */ {
+ int x, y = 0;
+ debug(F101,"concb constate","",constate);
+ debug(F101,"concb cgmf","",cgmf);
+ debug(F101,"concb backgrd","",backgrd);
+
+ if (constate == CON_CB)
+ return(0);
+
+ if (cgmf < 1) /* Did we get console modes yet? */
+ if (!backgrd) /* No, in background? */
+ congm(); /* No, try to get them now. */
+ if (cgmf < 1) /* Still don't have them? */
+ return(0); /* Give up. */
+ debug(F101,"concb ttyfd","",ttyfd);
+ debug(F101,"concb ttfdflg","",ttfdflg);
+#ifdef COMMENT
+ /* This breaks returning to prompt after protocol with "-l 0" */
+ /* Commented out July 1998 */
+ if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
+ return(0);
+#endif /* COMMENT */
+ x = isatty(0);
+ debug(F101,"concb isatty","",x);
+ if (!x) return(0); /* Only when running on real ttys */
+ debug(F101,"concb xsuspend","",xsuspend);
+ if (backgrd) /* Do nothing if in background. */
+ return(0);
+ escchr = esc; /* Make this available to other fns */
+ ckxech = 1; /* Program can echo characters */
+#ifdef aegis
+ conbufn = 0;
+ if (concrp) return(write(1, "\035\002", 2));
+ if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
+#endif /* aegis */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef Plan9
+ x = p9concb();
+#else
+#ifndef SVORPOSIX /* BSD, V7, etc */
+ debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
+ debug(F101,"concb stty CBREAK","",0);
+ cccbrk.sg_flags |= (CBREAK|CRMOD); /* Set to character wakeup, */
+ cccbrk.sg_flags &= ~ECHO; /* no echo. */
+ debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
+ errno = 0;
+/*
+ BSD stty() clears the console buffer. So if anything is waiting in it,
+ we have to read it now to avoid losing it.
+*/
+ x = conchk();
+ if (x > 0)
+ congetbuf(x);
+
+#ifdef BELLV10
+ x = ioctl(0,TIOCSETP,&cccbrk);
+#else
+ x = stty(0,&cccbrk);
+ debug(F101,"cccbrk.sg_flags concb x","", x);
+#endif /* BELLV10 */
+#else /* Sys V and POSIX */
+#ifndef OXOS
+ debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
+#ifdef QNX
+ /* Don't mess with IEXTEN */
+ cccbrk.c_lflag &= ~(ICANON|ECHO);
+#else
+#ifdef COHERENT
+ cccbrk.c_lflag &= ~(ICANON|ECHO);
+#else
+ cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
+#endif /* COHERENT */
+#endif /* QNX */
+ cccbrk.c_lflag |= ISIG; /* Allow signals in command mode. */
+ cccbrk.c_iflag |= IGNBRK; /* But ignore BREAK signal */
+ cccbrk.c_iflag &= ~BRKINT;
+
+#else /* OXOS */
+ debug(F100,"concb OXOS is defined","",0);
+ cccbrk.c_lflag &= ~(ICANON|ECHO);
+ cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+#ifdef COMMENT
+/*
+ Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
+ array reference is out of bounds. It's only a debug() call so who needs it.
+*/
+#ifdef VSUSP
+ debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
+#endif /* VSUSP */
+#endif /* COMMENT */
+#ifndef VINTR
+ debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
+ cccbrk.c_cc[0] = 003; /* Interrupt char is Control-C */
+#else
+ debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
+ cccbrk.c_cc[VINTR] = 003;
+#endif /* VINTR */
+#ifndef VQUIT
+ cccbrk.c_cc[1] = escchr; /* escape during packet modes */
+#else
+ cccbrk.c_cc[VQUIT] = escchr;
+#endif /* VQUIT */
+#ifndef VEOF
+ cccbrk.c_cc[4] = 1;
+#else
+#ifndef OXOS
+#ifdef VMIN
+ cccbrk.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ cccbrk.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+#ifdef ZILOG
+ cccbrk.c_cc[5] = 0;
+#else
+#ifndef VEOL
+ cccbrk.c_cc[5] = 1;
+#else
+#ifndef OXOS
+#ifdef VTIME
+ cccbrk.c_cc[VTIME] = 1;
+#endif /* VTIME */
+#else /* OXOS */
+ cccbrk.c_time = 1;
+#endif /* OXOS */
+#endif /* VEOL */
+#endif /* ZILOG */
+ errno = 0;
+#ifdef BSD44ORPOSIX /* Set new modes */
+ x = tcsetattr(0,TCSADRAIN,&cccbrk);
+#else /* ATTSV */ /* or the POSIX way */
+ x = ioctl(0,TCSETAW,&cccbrk); /* the Sys V way */
+#endif /* BSD44ORPOSIX */
+#endif /* SVORPOSIX */
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+ debug(F101,"concb x","",x);
+ debug(F101,"concb errno","",errno);
+
+#ifdef V7
+#ifndef MINIX
+ if (kmem[CON] < 0) {
+ qaddr[CON] = initrawq(0);
+ if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
+ fprintf(stderr, "Can't read /dev/kmem in concb.\n");
+ perror("/dev/kmem");
+ exit(1);
+ }
+ }
+#endif /* MINIX */
+#endif /* V7 */
+#endif /* Plan9 */
+
+ if (x > -1)
+ constate = CON_CB;
+
+ debug(F101,"concb returns","",x);
+ return(x);
+}
+
+/* C O N B I N -- Put console in binary mode */
+
+/* Returns 0 if ok, -1 if not */
+
+int
+#ifdef CK_ANSIC
+conbin(char esc)
+#else
+conbin(esc) char esc;
+#endif /* CK_ANSIC */
+/* conbin */ {
+
+ int x;
+
+ debug(F101,"conbin constate","",constate);
+
+ if (constate == CON_BIN)
+ return(0);
+
+ if (!isatty(0)) return(0); /* only for real ttys */
+ congm(); /* Get modes if necessary. */
+ debug(F100,"conbin","",0);
+ escchr = esc; /* Make this available to other fns */
+ ckxech = 1; /* Program can echo characters */
+#ifdef aegis
+ conbufn = 0;
+ if (concrp) return(write(1, "\035\002", 2));
+ if (conuid == input_pad_$uid) {
+ pad_$raw(ios_$stdin, st);
+ return(0);
+ }
+#endif /* aegis */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef Plan9
+ return p9conbin();
+#else
+#ifdef SVORPOSIX
+#ifndef OXOS
+#ifdef QNX
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
+#else
+#ifdef COHERENT
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
+#else
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
+#endif /* COHERENT */
+#endif /* QNX */
+#else /* OXOS */
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+ ccraw.c_iflag |= IGNPAR;
+/*
+ Note that for terminal sessions we disable Xon/Xoff flow control to allow
+ the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
+ transfers to work when C-Kermit is in the middle, etc. Hardware flow
+ control, if in use, is not affected.
+*/
+#ifdef ATTSV
+#ifdef BSD44
+ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
+ |INPCK|ISTRIP);
+#else
+ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
+ |INPCK|ISTRIP);
+#endif /* BSD44 */
+#else /* POSIX */
+ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
+#endif /* ATTSV */
+ ccraw.c_oflag &= ~OPOST;
+#ifdef COMMENT
+/*
+ WHAT THE HECK WAS THIS FOR?
+ The B9600 setting (obviously) prevents CONNECT from working at any
+ speed other than 9600 when you are logged in to the 7300 on a serial
+ line. Maybe some of the other flags are necessary -- if so, put back
+ the ones that are needed. This code is supposed to work the same, no
+ matter whether you are logged in to the 7300 on the real console device,
+ or through a serial port.
+*/
+#ifdef ATT7300
+ ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
+#endif /* ATT7300 */
+#endif /* COMMENT */
+
+/*** Kermit used to put the console in 8-bit raw mode, but some users have
+ *** pointed out that this should not be done, since some sites actually
+ *** use terminals with parity settings on their Unix systems, and if we
+ *** override the current settings and stop doing parity, then their terminals
+ *** will display blotches for characters whose parity is wrong. Therefore,
+ *** the following two lines are commented out (Larry Afrin, Clemson U):
+ ***
+ *** ccraw.c_cflag &= ~(PARENB|CSIZE);
+ *** ccraw.c_cflag |= (CS8|CREAD);
+ ***
+ *** Sys III/V sites that have trouble with this can restore these lines.
+ ***/
+#ifndef VINTR
+ ccraw.c_cc[0] = 003; /* Interrupt char is Ctrl-C */
+#else
+ ccraw.c_cc[VINTR] = 003;
+#endif /* VINTR */
+#ifndef VQUIT
+ ccraw.c_cc[1] = escchr; /* Escape during packet mode */
+#else
+ ccraw.c_cc[VQUIT] = escchr;
+#endif /* VQUIT */
+#ifndef VEOF
+ ccraw.c_cc[4] = 1;
+#else
+#ifndef OXOS
+#ifdef VMIN
+ ccraw.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ ccraw.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+
+#ifdef ZILOG
+ ccraw.c_cc[5] = 0;
+#else
+#ifndef VEOL
+ ccraw.c_cc[5] = 1;
+#else
+#ifndef OXOS
+#ifdef VTIME
+ ccraw.c_cc[VTIME] = 1;
+#endif /* VTIME */
+#else /* OXOS */
+ ccraw.c_time = 1;
+#endif /* OXOS */
+#endif /* VEOL */
+#endif /* ZILOG */
+
+#ifdef BSD44ORPOSIX
+ x = tcsetattr(0,TCSADRAIN,&ccraw); /* Set new modes. */
+#else
+ x = ioctl(0,TCSETAW,&ccraw);
+#endif /* BSD44ORPOSIX */
+#else /* Berkeley, etc. */
+ x = conchk(); /* Because stty() is destructive */
+ if (x > 0)
+ congetbuf(x);
+ ccraw.sg_flags |= (RAW|TANDEM); /* Set rawmode, XON/XOFF (ha) */
+ ccraw.sg_flags &= ~(ECHO|CRMOD); /* Set char wakeup, no echo */
+#ifdef BELLV10
+ x = ioctl(0,TIOCSETP,&ccraw);
+#else
+ x = stty(0,&ccraw);
+#endif /* BELLV10 */
+#endif /* SVORPOSIX */
+#endif /* Plan9 */
+
+ if (x > -1)
+ constate = CON_BIN;
+
+ debug(F101,"conbin returns","",x);
+ return(x);
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+}
+
+
+/* C O N R E S -- Restore the console terminal */
+
+int
+conres() {
+ int x;
+ debug(F101,"conres cgmf","",cgmf);
+ debug(F101,"conres constate","",constate);
+
+ if (cgmf < 1) /* Do nothing if modes unchanged */
+ return(0);
+ if (constate == CON_RES)
+ return(0);
+
+ if (!isatty(0)) return(0); /* only for real ttys */
+ debug(F100,"conres isatty ok","",0);
+ ckxech = 0; /* System should echo chars */
+
+#ifdef aegis
+ conbufn = 0;
+ if (concrp) return(write(1, "\035\001", 2));
+ if (conuid == input_pad_$uid) {
+ pad_$cooked(ios_$stdin, st);
+ constate = CON_RES;
+ return(0);
+ }
+#endif /* aegis */
+
+#ifdef Plan9
+ p9conres();
+#else
+#ifdef BSD44ORPOSIX
+ debug(F100,"conres restoring tcsetattr","",0);
+ x = tcsetattr(0,TCSADRAIN,&ccold);
+#else
+#ifdef ATTSV
+ debug(F100,"conres restoring ioctl","",0);
+ x = ioctl(0,TCSETAW,&ccold);
+#else /* BSD, V7, and friends */
+#ifdef sony_news /* Sony NEWS */
+ if (km_con != -1)
+ ioctl(0,TIOCKSET,&km_con); /* Restore console Kanji mode */
+#endif /* sony_news */
+ msleep(100);
+ debug(F100,"conres restoring stty","",0);
+ x = conchk(); /* Because stty() is destructive */
+ if (x > 0)
+ congetbuf(x);
+#ifdef BELLV10
+ x = ioctl(0,TIOCSETP,&ccold);
+#else
+ x = stty(0,&ccold);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+ if (x > -1)
+ constate = CON_RES;
+
+ debug(F101,"conres returns","",x);
+ return(x);
+}
+
+/* C O N O C -- Output a character to the console terminal */
+
+int
+#ifdef CK_ANSIC
+conoc(char c)
+#else
+conoc(c) char c;
+#endif /* CK_ANSIC */
+/* conoc */ {
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttoc(c));
+
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(&c,1);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return conwrite(&c,1);
+#else
+ return(write(1,&c,1));
+#endif /* Plan9 */
+}
+
+/* C O N X O -- Write x characters to the console terminal */
+
+int
+conxo(x,s) int x; char *s; {
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttol((CHAR *)s,x));
+
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(s,x);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return(conwrite(s,x));
+#else
+ return(write(1,s,x));
+#endif /* Plan9 */
+}
+
+/* C O N O L -- Write a line to the console terminal */
+
+int
+conol(s) char *s; {
+ int len;
+ if (!s) s = ""; /* Always do this! */
+ len = strlen(s);
+ if (len == 0)
+ return(0);
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttol((CHAR *)s,len));
+
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
+ if (nxpacket < len) {
+ if (xpacket) {
+ free(xpacket);
+ xpacket = NULL;
+ nxpacket = 0;
+ }
+ len = len > 10240 ? len : 10240;
+ xpacket = (CHAR *)malloc(len);
+ if (!xpacket) {
+ fprintf(stderr,"ttol malloc failure\n");
+ return(-1);
+ } else
+ nxpacket = len;
+ }
+ memcpy(xpacket,s,len);
+ s = (char *)xpacket;
+ ck_tn_encrypt(s,len);
+ }
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return(conwrite(s,len));
+#else
+ return(write(1,s,len));
+#endif /* Plan9 */
+}
+
+/* C O N O L A -- Write an array of lines to the console terminal */
+
+int
+conola(s) char *s[]; {
+ char * p;
+ int i, x;
+
+
+ if (!s) return(0);
+ for (i = 0; ; i++) {
+ p = s[i];
+ if (!p) p = ""; /* Let's not dump core shall we? */
+ if (!*p)
+ break;
+#ifdef IKSD
+ if (inserver && !local)
+ x = ttol((CHAR *)p,(int)strlen(p));
+ else
+#endif /* IKSD */
+ x = conol(p);
+ if (x < 0)
+ return(-1);
+ }
+ return(0);
+}
+
+/* C O N O L L -- Output a string followed by CRLF */
+
+int
+conoll(s) char *s; {
+ CHAR buf[3];
+ buf[0] = '\r';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ if (!s) s = "";
+
+#ifdef IKSD
+ if (inserver && !local) {
+ if (*s) ttol((CHAR *)s,(int)strlen(s));
+ return(ttol(buf,2));
+ }
+#endif /* IKSD */
+
+ if (*s) conol(s);
+#ifdef IKSD
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt((char *)buf,2);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return(conwrite(buf, 2));
+#else
+ return(write(1,buf,2));
+#endif /* Plan9 */
+}
+
+/* C O N C H K -- Return how many characters available at console */
+/*
+ We could also use select() here to cover a few more systems that are not
+ covered by any of the following, e.g. HP-UX 9.0x on the model 800.
+*/
+int
+conchk() {
+ static int contyp = 0; /* +1 for isatty, -1 otherwise */
+
+ if (contyp == 0) /* This prevents unnecessary */
+ contyp = (isatty(0) ? 1 : -1); /* duplicated calls to isatty() */
+ debug(F101,"conchk contyp","",contyp);
+ if (backgrd || (contyp < 0))
+ return(0);
+
+#ifdef aegis
+ if (conbufn > 0) return(conbufn); /* use old count if nonzero */
+
+ /* read in more characters */
+ conbufn = ios_$get(ios_$stdin,
+ ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
+ if (st.all != status_$ok) conbufn = 0;
+ conbufp = conbuf;
+ return(conbufn);
+#else
+#ifdef IKSD
+ if (inserver && !local)
+ return(in_chk(1,ttyfd));
+ else
+#endif /* IKSD */
+ return(in_chk(0,0));
+#endif /* aegis */
+}
+
+/* C O N I N C -- Get a character from the console */
+/*
+ Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
+ read. Upon success, returns the character. Upon failure, returns -1.
+ A timed read that does not complete within the timeout period returns -2.
+*/
+int
+coninc(timo) int timo; {
+ int n = 0; CHAR ch;
+ int xx;
+
+ if (conbufn > 0) { /* If something already buffered */
+ --conbufn;
+ return((unsigned)(*conbufp++ & 0xff));
+ }
+
+ errno = 0; /* Clear this */
+#ifdef IKSD
+ if (inserver && !local) {
+ xx = ttinc(timo);
+ if (xx < 0)
+ return(ttinctimo ? -2 : -1);
+ else
+ return(xx);
+ }
+#endif /* IKSD */
+
+#ifdef aegis /* Apollo Aegis only... */
+ debug(F101,"coninc timo","",timo);
+ fflush(stdout);
+ if (conchk() > 0) {
+ --conbufn;
+ return((unsigned)(*conbufp++ & 0xff));
+ }
+#endif /* aegis */
+
+#ifdef TTLEBUF
+ if (
+#ifdef IKSD
+ inserver &&
+#endif /* IKSD */
+ !xlocal
+ ) {
+ if (ttpush >= 0) {
+ debug(F111,"ttinc","ttpush",ttpush);
+ ch = ttpush;
+ ttpush = -1;
+ return(ch);
+ }
+ if (le_data) {
+ if (le_getchar(&ch) > 0) {
+ debug(F111,"ttinc LocalEchoInBuf","ch",ch);
+ return(ch);
+ }
+ }
+ }
+#endif /* TTLEBUF */
+
+ if (timo <= 0) { /* Untimed, blocking read. */
+ while (1) { /* Keep trying till we get one. */
+ n = read(0, &ch, 1); /* Read a character. */
+ if (n == 0) continue; /* Shouldn't happen. */
+ if (n > 0) { /* If read was successful, */
+#ifdef IKSD
+#ifdef CK_ENCRYPTION
+ debug(F100,"coninc decrypt 1","",0);
+ if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt((char *)&ch,1);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+ return((unsigned)(ch & 0xff)); /* return the character. */
+ }
+
+/* Come here if read() returned an error. */
+
+ debug(F101, "coninc(0) errno","",errno); /* Log the error. */
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifdef CIE /* CIE Regulus has no EINTR symbol? */
+#ifndef EINTR
+#define EINTR 4
+#endif /* EINTR */
+#endif /* CIE */
+/*
+ This routine is used for several different purposes. In CONNECT mode, it is
+ used to do an untimed, blocking read from the keyboard in the lower CONNECT
+ fork. During local-mode file transfer, it reads a character from the
+ console to interrupt the file transfer (like A for a status report, X to
+ cancel a file, etc). Obviously, we don't want the reads in the latter case
+ to be blocking, or the file transfer would stop until the user typed
+ something. Unfortunately, System V does not allow the console device input
+ buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
+ used instead. During local-mode file transfer, the SIGQUIT signal is armed
+ and trapped by esctrp(), and this routine pretends to have read the quit
+ character from the keyboard normally. But, kludge or no kludge, the read()
+ issued by this command, under System V only, can fail if a signal -- ANY
+ signal -- is caught while the read is pending. This can occur not only when
+ the user types the quit character, but also during telnet negotiations, when
+ the lower CONNECT fork signals the upper one about an echoing mode change.
+ When this happens, we have to post the read() again. This is apparently not
+ a problem in BSD-based UNIX versions.
+*/
+ if (errno == EINTR) /* Read interrupted. */
+ if (conesc) { /* If by SIGQUIT, */
+ conesc = 0; /* the conesc variable is set, */
+ return(escchr); /* so return the escape character. */
+ } else continue; /* By other signal, try again. */
+#else
+/*
+ This might be dangerous, but let's do this on non-System V versions too,
+ since at least one SunOS 4.1.2 user complains of immediate disconnections
+ upon first making a TELNET connection.
+*/
+ if (errno == EINTR) /* Read interrupted. */
+ continue;
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ if (errno == EINTR) /* Read interrupted. */
+ continue;
+#endif /* OXOS */
+ return(-1); /* Error */
+ }
+ }
+#ifdef DEBUG
+ if (deblog && timo <= 0) {
+ debug(F100,"coninc timeout logic error","",0);
+ timo = 1;
+ }
+#endif /* DEBUG */
+
+/* Timed read... */
+
+ saval = signal(SIGALRM,timerh); /* Set up timeout handler. */
+ xx = alarm(timo); /* Set the alarm. */
+ debug(F101,"coninc alarm set","",timo);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) /* The read() timed out. */
+ n = -2; /* Code for timeout. */
+ else
+ n = read(0, &ch, 1);
+ ttimoff(); /* Turn off timer */
+ if (n > 0) { /* Got character OK. */
+#ifdef IKSD
+#ifdef CK_ENCRYPTION
+ debug(F100,"coninc decrypt 2","",0);
+ if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt((char *)&ch,1);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+ return((unsigned)(ch & 0xff)); /* Return it. */
+ }
+/*
+ read() returned an error. Same deal as above, but without the loop.
+*/
+ debug(F101, "coninc(timo) n","",n);
+ debug(F101, "coninc(timo) errno","",errno);
+#ifndef OXOS
+#ifdef SVORPOSIX
+ if (n == -1 && errno == EINTR && conesc != 0) {
+ conesc = 0;
+ return(escchr); /* User entered escape character. */
+ }
+#endif /* SVORPOSIX */
+ if (n == 0 && errno > 0) { /* It's an error */
+ return(-1);
+ }
+#endif /* ! OXOS */
+ return(n);
+}
+
+/* C O N G K S -- Console Get Keyboard Scancode */
+
+#ifndef congks
+/*
+ This function needs to be filled in with the various system-dependent
+ system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
+ keyboard scan code. Unfortunately there aren't any.
+*/
+int
+congks(timo) int timo; {
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttinc(timo));
+#endif /* IKSD */
+
+ return(coninc(timo));
+}
+#endif /* congks */
+
+#ifdef ATT7300
+
+/* A T T D I A L -- Dial up the remote system using internal modem
+ * Purpose: to open and dial a number on the internal modem available on the
+ * ATT7300 UNIX PC. Written by Joe Doupnik. Superceeds version written by
+ * Richard E. Hill, Dickinson, TX. which employed dial(3c).
+ * Uses information in <sys/phone.h> and our status int attmodem.
+ */
+attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
+ char *telnum;
+
+ attmodem &= ~ISMODEM; /* modem not in use yet */
+ /* Ensure O_NDELAY is set, else i/o traffic hangs */
+ /* We turn this flag off once the dial is complete */
+ fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
+
+ /* Condition line, check availability & DATA mode, turn on speaker */
+ if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
+ printf("cannot access phone\n");
+ ttclos(0);
+ return (-2);
+ }
+ ioctl(ttyfd,PIOCGETP,&dialer); /* get phone dialer parameters */
+
+ if (dialer.c_lineparam & VOICE) { /* phone must be in DATA mode */
+ printf(" Should not dial with modem in VOICE mode.\n");
+ printf(" Exit Kermit, switch to DATA and retry call.\n");
+ ttclos(0);
+ return (-2);
+ }
+#ifdef ATTTONED /* Old way, tone dialing only. */
+ dialer.c_lineparam = DATA | DTMF; /* Dial with tones, */
+ dialer.c_lineparam &= ~PULSE; /* not with pulses. */
+#else
+ /* Leave current pulse/tone state alone. */
+ /* But what about DATA? Add it back if you have trouble. */
+ /* sys/phone says you get DATA automatically by opening device RDWR */
+#endif
+ dialer.c_waitdialtone = 5; /* wait 5 sec for dialtone */
+#ifdef COMMENT
+ dialer.c_feedback = SPEAKERON|NORMSPK|RINGON; /* control speaker */
+#else
+ /* sys/phone says RINGON used only for incoming voice calls */
+ dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
+ dialer.c_feedback |= SPEAKERON|NORMSPK;
+#endif
+ dialer.c_waitflash = 500; /* 0.5 sec flash hook */
+ if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) { /* set phone parameters */
+ printf("Cannot set modem characteristics\n");
+ ttclos(0);
+ return (-2);
+ }
+ ioctl(ttyfd,PIOCRECONN,0); /* Turns on speaker for pulse */
+
+#ifdef COMMENT
+ fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
+line_status:%o feedback:%o\n",
+ dialer.c_lineparam, dialer.c_waitdialtone,
+ dialer.c_linestatus, dialer.c_feedback);
+#endif
+
+ attmodem |= ISMODEM; /* modem is now in-use */
+ sleep(1);
+ for (telnum = telnbr; *telnum != '\0'; telnum++) /* dial number */
+#ifdef ATTTONED
+ /* Tone dialing only */
+ if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
+ perror("Error in dialing");
+ ttclos(0);
+ return(-2);
+ }
+#else /* Allow Pulse or Tone dialing */
+ switch (*telnum) {
+ case 't': case 'T': case '%': /* Tone dialing requested */
+ dialer.c_lineparam |= DTMF;
+ dialer.c_lineparam &= ~PULSE;
+ if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
+ printf("Cannot set modem to tone dialing\n");
+ ttclos(0);
+ return(-2);
+ }
+ break;
+ case 'd': case 'D': case 'p': case 'P': case '^':
+ dialer.c_lineparam |= PULSE;
+ dialer.c_lineparam &= ~DTMF;
+ if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
+ printf("Cannot set modem to pulse dialing\n");
+ ttclos(0);
+ return(-2);
+ }
+ break;
+ default:
+ if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
+ perror("Dialing error");
+ ttclos(0);
+ return(-2);
+ }
+ break;
+ }
+#endif
+
+ ioctl(ttyfd,PIOCDIAL,"@"); /* terminator for data call */
+ do { /* wait for modems to Connect */
+ if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
+ perror("Cannot get modems to connect");
+ ttclos(0);
+ return(-2);
+ }
+ } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
+ /* Turn off O_NDELAY flag now. */
+ fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
+ signal(SIGHUP, sighup); /* hangup on loss of carrier */
+ return(0); /* return success */
+}
+
+/*
+ Offgetty, ongetty functions. These function get the 'getty(1m)' off
+ and restore it to the indicated line. Shell's return codes are:
+ 0: Can't do it. Probably a user logged on.
+ 1: No need. No getty on that line.
+ 2: Done, you should restore the getty when you're done.
+ DOGETY System(3), however, returns them as 0, 256, 512, respectively.
+ Thanks to Kevin O'Gorman, Anarm Software Systems.
+
+ getoff.sh looks like: geton.sh looks like:
+ setgetty $1 0 setgetty $1 1
+ err=$? exit $?
+ sleep 2
+ exit $err
+*/
+
+/* O F F G E T T Y -- Turn off getty(1m) for the communications tty line
+ * and get status so it can be restarted after the line is hung up.
+ */
+int
+offgetty(ttname) char *ttname; {
+ char temp[30];
+ while (*ttname != '\0') ttname++; /* seek terminator of path */
+ ttname -= 3; /* get last 3 chars of name */
+ sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
+ return(zsyscmd(temp));
+}
+
+/* O N G E T T Y -- Turn on getty(1m) for the communications tty line */
+
+int
+ongetty(ttname) char *ttname; {
+ char temp[30];
+ while (*ttname != '\0') ttname++; /* comms tty path name */
+ ttname -= 3;
+ sprintf(temp,"/usr/bin/geton.sh %s",ttname);
+ return(zsyscmd(temp));
+}
+#endif /* ATT7300 */
+
+/* T T S C A R R -- Set ttcarr variable, controlling carrier handling.
+ *
+ * 0 = Off: Always ignore carrier. E.g. you can connect without carrier.
+ * 1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
+ * 2 = Auto: For "modem direct": The same as "Off".
+ * For real modem types: Heed carrier during connect, but ignore
+ * it anytime else. Compatible with pre-5A C-Kermit versions.
+ *
+ * As you can see, this setting does not affect dialing, which always ignores
+ * carrier (unless there is some special exception for some modem type). It
+ * does affect ttopen() if it is set before ttopen() is used. This setting
+ * takes effect on the next call to ttopen()/ttpkt()/ttvt(). And they are
+ * (or should be) always called before any communications is tried, which
+ * means that, practically speaking, the effect is immediate.
+ *
+ * Of course, nothing of this applies to remote mode (xlocal = 0).
+ *
+ * Someone has yet to uncover how to manipulate the carrier in the BSD
+ * environment (or any non-termio using environment). Until that time, this
+ * will simply be a no-op for BSD.
+ *
+ * Note that in previous versions, the carrier was most often left unchanged
+ * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX. This
+ * has changed. Now it is controlled by ttcarr in conjunction with these
+ * modes.
+ */
+int
+ttscarr(carrier) int carrier; {
+ ttcarr = carrier;
+ debug(F101, "ttscarr","",ttcarr);
+ return(ttcarr);
+}
+
+/* C A R R C T L -- Set tty modes for carrier treatment.
+ *
+ * Sets the appropriate bits in a termio or sgttyb struct for carrier control
+ * (actually, there are no bits in sgttyb for that), or performs any other
+ * operations needed to control this on the current system. The function does
+ * not do the actual TCSETA or stty, since often we want to set other bits too
+ * first. Don't call this function when xlocal is 0, or the tty is not opened.
+ *
+ * We don't know how to do anything like carrier control on non-ATTSV systems,
+ * except, apparently, ultrix. See above. It is also known that this doesn't
+ * have much effect on a Xenix system. For Xenix, one should switch back and
+ * forth between the upper and lower case device files. Maybe later.
+ * Presently, Xenix will stick to the mode it was opened with.
+ *
+ * carrier: 0 = ignore carrier, 1 = require carrier.
+ * The current state is saved in curcarr, and checked to save labour.
+ */
+#ifdef SVORPOSIX
+int
+#ifdef BSD44ORPOSIX
+carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
+#else /* ATTSV */
+carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
+#endif /* BSD44ORPOSIX */
+/* carrctl */ {
+ debug(F101, "carrctl","",carrier);
+ if (carrier)
+ ttpar->c_cflag &= ~CLOCAL;
+ else
+ ttpar->c_cflag |= CLOCAL;
+ return(0);
+}
+#else /* Berkeley, V7, et al... */
+int
+carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
+ debug(F101, "carrctl","",carrier);
+ if (carrier == curcarr)
+ return(0);
+ curcarr = carrier;
+#ifdef ultrix
+#ifdef COMMENT
+/*
+ Old code from somebody at DEC that tends to get stuck, time out, etc.
+*/
+ if (carrier) {
+ ioctl(ttyfd, TIOCMODEM, &temp);
+ ioctl(ttyfd, TIOCHPCL, 0);
+ } else {
+ /* (According to the manuals, TIOCNCAR should be preferred */
+ /* over TIOCNMODEM...) */
+ ioctl(ttyfd, TIOCNMODEM, &temp);
+ }
+#else
+/*
+ New code from Jamie Watson that, he says, eliminates the problems.
+*/
+ if (carrier) {
+ ioctl(ttyfd, TIOCCAR);
+ ioctl(ttyfd, TIOCHPCL);
+ } else {
+ ioctl(ttyfd, TIOCNCAR);
+ }
+#endif /* COMMENT */
+#endif /* ultrix */
+ return(0);
+}
+#endif /* SVORPOSIX */
+
+
+/* T T G M D M -- Get modem signals */
+/*
+ Looks for RS-232 modem signals, and returns those that are on in as its
+ return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
+ Returns:
+ -3 Not implemented
+ -2 if the communication device does not have modem control (e.g. telnet)
+ -1 on error.
+ >= 0 on success, with a bit mask containing the modem signals that are on.
+*/
+
+/*
+ Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
+ modem control, namely the TIOCMGET ioctl.
+*/
+
+#ifdef BSD43
+#define K_MDMCTL
+#endif /* BSD43 */
+
+#ifdef SUNOS4
+#define K_MDMCTL
+#endif /* SUNOS4 */
+
+/*
+ SCO OpenServer R5.0.4. The TIOCMGET definition is hardwired in because it
+ is skipped in termio.h when _POSIX_SOURCE is defined. But _POSIX_SOURCE
+ must be defined in order to get the high serial speeds that are new to
+ 5.0.4. However, the regular SCO drivers do not implement TIOCMGET, so the
+ ioctl() returns -1 with errno 22 (invalid function). But third-party
+ drivers, e.g. for Digiboard, do implement it, and so it should work on ports
+ driven by those drivers.
+*/
+#ifdef SCO_OSR504
+#ifndef TIOCMGET
+#define TIOCMGET (('t'<<8)|29)
+#endif /* TIOCMGET */
+#endif /* SCO_OSR504 */
+
+#ifdef CK_SCOV5
+/* Because POSIX strictness in <sys/termio.h> won't let us see these. */
+#ifndef TIOCM_DTR
+#define TIOCM_DTR 0x0002 /* data terminal ready */
+#define TIOCM_RTS 0x0004 /* request to send */
+#define TIOCM_CTS 0x0020 /* clear to send */
+#define TIOCM_CAR 0x0040 /* carrier detect */
+#define TIOCM_RNG 0x0080 /* ring */
+#define TIOCM_DSR 0x0100 /* data set ready */
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+#endif /* TIOCM_DTR */
+#endif /* CK_SCOV5 */
+
+#ifdef QNX
+#define K_MDMCTL
+#else
+#ifdef TIOCMGET
+#define K_MDMCTL
+#endif /* TIOCMGET */
+#endif /* QNX */
+/*
+ "A serial communication program that can't read modem signals
+ is like a car without windows."
+*/
+int
+ttgmdm() {
+
+#ifdef QNX
+#include <sys/qioctl.h>
+
+ unsigned long y, mdmbits[2];
+ int x, z = 0;
+
+ if (xlocal && ttyfd < 0)
+ return(-1);
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ mdmbits[0] = 0L;
+ mdmbits[1] = 0L;
+/*
+ * From <sys/qioctl.h>:
+ *
+ * SERIAL devices (all Dev.ser versions)
+ * 0 : DTR 8 = Data Bits 0 16 - reserved 24 - reserved
+ * 1 : RTS 9 = Data Bits 1 17 - reserved 25 - reserved
+ * 2 = Out 1 10 = Stop Bits 18 - reserved 26 - reserved
+ * 3 = Int Enable 11 = Par Enable 19 - reserved 27 - reserved
+ * 4 = Loop 12 = Par Even 20 = CTS 28 - reserved
+ * 5 - reserved 13 = Par Stick 21 = DSR 29 - reserved
+ * 6 - reserved 14 : Break 22 = RI 30 - reserved
+ * 7 - reserved 15 = 0 23 = CD 31 - reserved
+ */
+ errno = 0;
+ x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
+ debug(F101,"ttgmdm qnx_ioctl","",x);
+ debug(F101,"ttgmdm qnx_ioctl errno","",errno);
+ if (!x) {
+ debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
+ debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
+ y = mdmbits[0];
+ if (y & 0x000001L) z |= BM_DTR; /* Bit 0 */
+ if (y & 0x000002L) z |= BM_RTS; /* Bit 1 */
+ if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */
+ if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */
+ if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */
+ if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */
+ debug(F101,"ttgmdm qnx result","",z);
+ debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
+ gotsigs = 1;
+ return(z);
+ } else return(-1);
+#else /* QNX */
+#ifdef HPUX /* HPUX has its own way */
+ int x, z;
+
+#ifdef HPUX10 /* Modem flag word */
+ mflag y; /* mflag typedef'd in <sys/modem.h> */
+#else
+#ifdef HPUX9
+ mflag y;
+#else
+#ifdef HPUX8
+ mflag y;
+#else
+ unsigned long y; /* Not sure about pre-8.0... */
+#endif /* HPUX8 */
+#endif /* HPUX9 */
+#endif /* HPUX10 */
+
+ if (xlocal && ttyfd < 0)
+ return(-1);
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ if (xlocal) /* Get modem signals */
+ x = ioctl(ttyfd,MCGETA,&y);
+ else
+ x = ioctl(0,MCGETA,&y);
+ if (x < 0) return(-1);
+ debug(F101,"ttgmdm","",y);
+
+ z = 0; /* Initialize return value */
+
+/* Now set bits for each modem signal that is reported to be on. */
+
+#ifdef MCTS
+ /* Clear To Send */
+ debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
+ if (y & MCTS) z |= BM_CTS;
+#endif
+#ifdef MDSR
+ /* Data Set Ready */
+ debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
+ if (y & MDSR) z |= BM_DSR;
+#endif
+#ifdef MDCD
+ /* Carrier */
+ debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
+ if (y & MDCD) z |= BM_DCD;
+#endif
+#ifdef MRI
+ /* Ring Indicate */
+ debug(F101,"ttgmdm HPUX RI","",y & MRI);
+ if (y & MRI) z |= BM_RNG;
+#endif
+#ifdef MDTR
+ /* Data Terminal Ready */
+ debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
+ if (y & MDTR) z |= BM_DTR;
+#endif
+#ifdef MRTS
+ /* Request To Send */
+ debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
+ if (y & MRTS) z |= BM_RTS;
+#endif
+ gotsigs = 1;
+ return(z);
+
+#else /* ! HPUX */
+
+#ifdef K_MDMCTL
+/*
+ Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
+ If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
+ are needed.
+*/
+#ifndef TIOCMGET
+#include <sys/ttycom.h>
+#endif /* TIOCMGET */
+
+ int x, y, z;
+
+ debug(F100,"ttgmdm K_MDMCTL defined","",0);
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ if (xlocal && ttyfd < 0)
+ return(-1);
+
+ if (xlocal)
+ x = ioctl(ttyfd,TIOCMGET,&y); /* Get modem signals. */
+ else
+ x = ioctl(0,TIOCMGET,&y);
+ debug(F101,"ttgmdm TIOCMGET ioctl","",x);
+ if (x < 0) {
+ debug(F101,"ttgmdm errno","",errno);
+ return(-1);
+ }
+ debug(F101,"ttgmdm bits","",y);
+
+ z = 0; /* Initialize return value. */
+#ifdef TIOCM_CTS
+ /* Clear To Send */
+ if (y & TIOCM_CTS) z |= BM_CTS;
+ debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS);
+#else
+ debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
+#endif
+#ifdef TIOCM_DSR
+ /* Data Set Ready */
+ if (y & TIOCM_DSR) z |= BM_DSR;
+ debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR);
+#else
+ debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
+#endif
+#ifdef TIOCM_CAR
+ /* Carrier */
+ if (y & TIOCM_CAR) z |= BM_DCD;
+ debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR);
+#else
+ debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
+#endif
+#ifdef TIOCM_RNG
+ /* Ring Indicate */
+ if (y & TIOCM_RNG) z |= BM_RNG;
+ debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG);
+#else
+ debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
+#endif
+#ifdef TIOCM_DTR
+ /* Data Terminal Ready */
+ if (y & TIOCM_DTR) z |= BM_DTR;
+ debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR);
+#else
+ debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
+#endif
+#ifdef TIOCM_RTS
+ /* Request To Send */
+ if (y & TIOCM_RTS) z |= BM_RTS;
+ debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS);
+#else
+ debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
+#endif
+ gotsigs = 1;
+ return(z);
+
+#else /* !K_MDMCTL catch-All */
+
+ debug(F100,"ttgmdm K_MDMCTL not defined","",0);
+#ifdef TIOCMGET
+ debug(F100,"ttgmdm TIOCMGET defined","",0);
+#else
+ debug(F100,"ttgmdm TIOCMGET not defined","",0);
+#endif /* TIOCMGET */
+#ifdef _SVID3
+ debug(F100,"ttgmdm _SVID3 defined","",0);
+#else
+ debug(F100,"ttgmdm _SVID3 not defined","",0);
+#endif /* _SVID3 */
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ return(-3); /* Sorry, I don't know how... */
+
+#endif /* K_MDMCTL */
+#endif /* HPUX */
+#endif /* QNX */
+}
+
+/* P S U S P E N D -- Put this process in the background. */
+
+/*
+ Call with flag nonzero if suspending is allowed, zero if not allowed.
+ Returns 0 on apparent success, -1 on failure (flag was zero, or
+ kill() returned an error code.
+*/
+int
+psuspend(flag) int flag; {
+
+#ifdef RTU
+ extern int rtu_bug;
+#endif /* RTU */
+
+ if (flag == 0) return(-1);
+
+#ifdef NOJC
+ return(-1);
+#else
+#ifdef SIGTSTP
+/*
+ The big question here is whether job control is *really* supported.
+ There's no way Kermit can know for sure. The fact that SIGTSTP is
+ defined does not guarantee the Unix kernel supports it, and the fact
+ that the Unix kernel supports it doesn't guarantee that the user's
+ shell (or other process that invoked Kermit) supports it.
+*/
+#ifdef RTU
+ rtu_bug = 1;
+#endif /* RTU */
+ if (kill(0,SIGSTOP) < 0
+#ifdef MIPS
+/* Let's try this for MIPS too. */
+ && kill(getpid(),SIGSTOP) < 0
+#endif /* MIPS */
+ ) { /* If job control, suspend the job */
+ perror("suspend");
+ debug(F101,"psuspend error","",errno);
+ return(-1);
+ }
+ debug(F100,"psuspend ok","",0);
+ return(0);
+#else
+ return(-1);
+#endif /* SIGTSTP */
+#endif /* NOJC */
+}
+
+/*
+ setuid package, by Kristoffer Eriksson, with contributions from Dean
+ Long and fdc.
+*/
+
+/* The following is for SCO when CK_ANSILIBS is defined... */
+#ifdef M_UNIX
+#ifdef CK_ANSILIBS
+#ifndef NOGETID_PROTOS
+#define NOGETID_PROTOS
+#endif /* NOGETID_PROTOS */
+#endif /* CK_ANSILIBS */
+#endif /* M_UNIX */
+
+#ifndef _POSIX_SOURCE
+#ifndef SUNOS4
+#ifndef NEXT
+#ifndef PS2AIX10
+#ifndef sequent
+#ifndef HPUX9
+#ifndef HPUX10
+#ifndef COHERENT
+#ifndef NOGETID_PROTOS
+_PROTOTYP( UID_T getuid, (void) );
+_PROTOTYP( UID_T geteuid, (void) );
+_PROTOTYP( UID_T getreuid, (void) );
+_PROTOTYP( UID_T getgid, (void) );
+_PROTOTYP( UID_T getegid, (void) );
+_PROTOTYP( UID_T getregid, (void) );
+#endif /* NOGETID_PROTOS */
+#else
+_PROTOTYP( UID_T getreuid, (void) );
+_PROTOTYP( UID_T getregid, (void) );
+#endif /* COHERENT */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* sequent */
+#endif /* PS2AIX10 */
+#endif /* NEXT */
+#endif /* SUNOS4 */
+#endif /* _POSIX_SOURCE */
+
+/*
+Subject: Set-user-id
+To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
+Date: Sat, 21 Apr 90 4:48:25 MES
+From: Kristoffer Eriksson <ske@pkmab.se>
+
+This is a set of functions to be used in programs that may be run set-user-id
+and/or set-group-id. They handle both the case where the program is not run
+with such privileges (nothing special happens then), and the case where one
+or both of these set-id modes are used. The program is made to run with the
+user's real user and group ids most of the time, except for when more
+privileges are needed. Don't set-user-id to "root".
+
+This works on System V and POSIX. In BSD, it depends on the
+"saved-set-user-id" feature.
+*/
+
+#define UID_ROOT 0 /* Root user and group ids */
+#define GID_ROOT 0
+
+/*
+ The following code defines the symbol SETEUID for UNIX systems based
+ on BSD4.4 (either -Encumbered or -Lite). This program will then use
+ seteuid() and setegid() instead of setuid() and setgid(), which still
+ don't allow arbitrary switching. It also avoids setreuid() and
+ setregid(), which are included in BSD4.4 for compatibility only, are
+ insecure, and print warnings to stderr under at least one system (NetBSD
+ 1.0). Note that POSIX systems should still use setuid() and setgid();
+ the seteuid() and setegid() functions are BSD4.4 extensions to the
+ POSIX model. Mike Long <mike.long@analog.com>, 8/94.
+*/
+#ifdef BSD44
+#define SETEUID
+#endif /* BSD44 */
+
+/*
+ The following construction automatically defines the symbol SETREUID for
+ UNIX versions based on Berkeley Unix 4.2 and 4.3. If this symbol is
+ defined, then this program will use getreuid() and getregid() calls in
+ preference to getuid() and getgid(), which in Berkeley-based Unixes do
+ not allow arbitrary switching back and forth of real & effective uid.
+ This construction also allows -DSETREUID to be put on the cc command line
+ for any system that has and wants to use setre[ug]id(). It also prevents
+ automatic definition of SETREUID if -DNOSETREU is included on the cc
+ command line (or otherwise defined).
+*/
+#ifdef FT18 /* None of this for Fortune. */
+#define NOSETREU
+#endif /* FT18 */
+
+#ifdef ANYBSD
+#ifndef BSD29
+#ifndef BSD41
+#ifndef SETREUID
+#ifndef NOSETREU
+#ifndef SETEUID
+#define SETREUID
+#endif /* SETEUID */
+#endif /* NOSETREU */
+#endif /* SETREUID */
+#endif /* !BSD41 */
+#endif /* !BSD29 */
+#endif /* ANYBSD */
+
+/* Variables for user and group IDs. */
+
+static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
+static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
+
+
+/* P R I V _ I N I -- Initialize privileges package */
+
+/* Called as early as possible in a set-uid or set-gid program to store the
+ * set-to uid and/or gid and step down to the users real uid and gid. The
+ * stored id's can be temporarily restored (allowed in System V) during
+ * operations that require the privilege. Most of the time, the program
+ * should execute in unpriviliged state, to not impose any security threat.
+ *
+ * Note: Don't forget that access() always uses the real id:s to determine
+ * file access, even with privileges restored.
+ *
+ * Returns an error mask, with error values or:ed together:
+ * 1 if setuid() fails,
+ * 2 if setgid() fails, and
+ * 4 if the program is set-user-id to "root", which can't be handled.
+ *
+ * Only the return value 0 indicates real success. In case of failure,
+ * those privileges that could be reduced have been, at least, but the
+ * program should be aborted none-the-less.
+ *
+ * Also note that these functions do not expect the uid or gid to change
+ * without their knowing. It may work if it is only done temporarily, but
+ * you're on your own.
+ */
+int
+priv_ini() {
+ int err = 0;
+
+#ifndef HAVE_LOCKDEV
+
+ /* Save real ID:s. */
+ realuid = getuid();
+ realgid = getgid();
+
+ /* Save current effective ID:s, those set to at program exec. */
+ privuid = geteuid();
+ privgid = getegid();
+
+ /* If running set-uid, go down to real uid, otherwise remember that
+ * no privileged uid is available.
+ *
+ * Exceptions:
+ *
+ * 1) If the real uid is already "root" and the set-uid uid (the
+ * initial effective uid) is not "root", then we would have trouble
+ * if we went "down" to "root" here, and then temporarily back to the
+ * set-uid uid (not "root") and then again tried to become "root". I
+ * think the "saved set-uid" is lost when changing uid from effective
+ * uid "root", which changes all uid, not only the effective uid. But
+ * in this situation, we can simply go to "root" and stay there all
+ * the time. That should give sufficient privilege (understatement!),
+ * and give the right uids for subprocesses.
+ *
+ * 2) If the set-uid (the initial effective uid) is "root", and we
+ * change uid to the real uid, we can't change it back to "root" when
+ * we need the privilege, for the same reason as in 1). Thus, we can't
+ * handle programs that are set-user-id to "root" at all. The program
+ * should be stopped. Use some other uid. "root" is probably too
+ * privileged for such things, anyway. (The uid is reverted to the
+ * real uid until termination.)
+ *
+ * These two exceptions have the effect that the "root" uid will never
+ * be one of the two uids that are being switched between, which also
+ * means we don't have to check for such cases in the switching
+ * functions.
+ *
+ * Note that exception 1) is handled by these routines (by constantly
+ * running with uid "root", while exception 2) is a serious error, and
+ * is not provided for at all in the switching functions.
+ */
+ if (realuid == privuid)
+ privuid = (UID_T) -1; /* Not running set-user-id. */
+
+ /* If running set-gid, go down to real gid, otherwise remember that
+ * no privileged gid is available.
+ *
+ * There are no exception like there is for the user id, since there
+ * is no group id that is privileged in the manner of uid "root".
+ * There could be equivalent problems for group changing if the
+ * program sometimes ran with uid "root" and sometimes not, but
+ * that is already avoided as explained above.
+ *
+ * Thus we can expect always to be able to switch to the "saved set-
+ * gid" when we want, and back to the real gid again. You may also
+ * draw the conclusion that set-gid provides for fewer hassles than
+ * set-uid.
+ */
+
+#ifdef SUIDDEBUG
+ fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
+ fprintf(stderr,"realuid=%d\n",realuid);
+ fprintf(stderr,"privuid=%d\n",privuid);
+#endif /* SUIDDEBUG */
+
+ if (realgid == privgid) /* If not running set-user-id, */
+ privgid = (GID_T) -1; /* remember it this way. */
+
+ err = priv_off(); /* Turn off setuid privilege. */
+
+ if (privuid == UID_ROOT) /* If setuid to root, */
+ err |= 4; /* return this error. */
+
+ if (realuid == UID_ROOT) { /* If real id is root, */
+ privuid = (UID_T) -1; /* stay root at all times. */
+#ifdef ATT7300
+ /* If Kermit installed SUID uucp and user is running as root */
+ err &= ~1; /* System V R0 does not save UID */
+#endif /* ATT7300 */
+ }
+#endif /* HAVE_LOCKDEV */
+ return(err);
+}
+
+
+/* Macros for hiding the differences in UID/GID setting between various Unix
+ * systems. These macros should always be called with both the privileged ID
+ * and the non-privileged ID. The one in the second argument, will become the
+ * effective ID. The one in the first argument will be retained for later
+ * retrieval.
+ */
+#ifdef SETREUID
+#ifdef SAVEDUID
+/* On BSD systems with the saved-UID feature, we just juggle the effective
+ * UID back and forth, and leave the real UID at its true value. The kernel
+ * allows switching to both the current real UID, the effective UID, and the
+ * UID which the program is set-UID to. The saved set-UID always holds the
+ * privileged UID for us, and the real UID will always be the non-privileged,
+ * and we can freely choose one of them for the effective UID at any time.
+ */
+#define switchuid(hidden,active) setreuid( (UID_T) -1, active)
+#define switchgid(hidden,active) setregid( (GID_T) -1, active)
+
+#else /* SETREUID,!SAVEDUID */
+
+/* On systems with setreXid() but without the saved-UID feature, notably
+ * BSD 4.2, we swap the real and effective UIDs each time. It's
+ * the effective UID that we are interested in, but we have to retain the
+ * unused UID somewhere to enable us to restore it later, and we do this
+ * in the real UID. The kernel only allows switching to either the current
+ * real or the effective UID, unless you're "root".
+ */
+#define switchuid(hidden,active) setreuid(hidden,active)
+#define switchgid(hidden,active) setregid(hidden,active)
+#endif
+
+#else /* !SETREUID, !SAVEDUID */
+
+#ifdef SETEUID
+/*
+ BSD 4.4 works similarly to System V and POSIX (see below), but uses
+ seteXid() instead of setXid() to change effective IDs. In addition, the
+ seteXid() functions work the same for "root" as for other users.
+*/
+#define switchuid(hidden,active) seteuid(active)
+#define switchgid(hidden,active) setegid(active)
+
+#else /* !SETEUID */
+
+/* On System V and POSIX, the only thing we can change is the effective UID
+ * (unless the current effective UID is "root", but initsuid() avoids that for
+ * us). The kernel allows switching to the current real UID or to the saved
+ * set-UID. These are always set to the non-privileged UID and the privileged
+ * UID, respectively, and we only change the effective UID. This breaks if
+ * the current effective UID is "root", though, because for "root" setuid/gid
+ * becomes more powerful, which is why initsuid() treats "root" specially.
+ * Note: That special treatment maybe could be ignored for BSD? Note: For
+ * systems that don't fit any of these four cases, we simply can't support
+ * set-UID.
+ */
+#define switchuid(hidden,active) setuid(active)
+#define switchgid(hidden,active) setgid(active)
+
+#endif /* SETEUID */
+#endif /* SETREUID */
+
+
+/* P R I V _ O N -- Turn on the setuid and/or setgid */
+
+/* Go to the privileged uid (gid) that the program is set-user-id
+ * (set-group-id) to, unless the program is running unprivileged.
+ * If setuid() fails, return value will be 1. If getuid() fails it
+ * will be 2. Return immediately after first failure, and the function
+ * tries to restore any partial work done. Returns 0 on success.
+ * Group id is changed first, since it is less serious than user id.
+ */
+int
+priv_on() {
+#ifndef HAVE_LOCKDEV
+ if (privgid != (GID_T) -1)
+ if (switchgid(realgid,privgid))
+ return(2);
+
+ if (privuid != (UID_T) -1)
+ if (switchuid(realuid,privuid)) {
+ if (privgid != (GID_T) -1)
+ switchgid(privgid,realgid);
+ return(1);
+ }
+#endif /* HAVE_LOCKDEV */
+ return(0);
+}
+
+/* P R I V _ O F F -- Turn on the real uid and gid */
+
+/* Return to the unprivileged uid (gid) after an temporary visit to
+ * privileged status, unless the program is running without set-user-id
+ * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
+ * in setgid() or:ed together. The functions tries to return both uid
+ * and gid to unprivileged state, regardless of errors. Returns 0 on
+ * success.
+ */
+int
+priv_off() {
+ int err = 0;
+#ifndef HAVE_LOCKDEV
+ if (privuid != (UID_T) -1)
+ if (switchuid(privuid,realuid))
+ err |= 1;
+
+ if (privgid != (GID_T) -1)
+ if (switchgid(privgid,realgid))
+ err |= 2;
+#endif /* HAVE_LOCKDEV */
+ return(err);
+}
+
+/* Turn off privilege permanently. No going back. This is necessary before
+ * a fork() on BSD43 machines that don't save the setUID or setGID, because
+ * we swap the real and effective ids, and we don't want to let the forked
+ * process swap them again and get the privilege back. It will work on other
+ * machines too, such that you can rely on its effect always being the same,
+ * for instance, even when you're in priv_on() state when this is called.
+ * (Well, that part about "permanent" is on System V only true if you follow
+ * this with a call to exec(), but that's what we want it for anyway.)
+ * Added by Dean Long -- dlong@midgard.ucsc.edu
+ */
+int
+priv_can() {
+#ifndef HAVE_LOCKDEV
+#ifdef SETREUID
+ int err = 0;
+ if (privuid != (UID_T) -1)
+ if (setreuid(realuid,realuid))
+ err |= 1;
+
+ if (privgid != (GID_T) -1)
+ if (setregid(realgid,realgid))
+ err |= 2;
+
+ return(err);
+
+#else
+#ifdef SETEUID
+ int err = 0;
+ if (privuid != (UID_T) -1)
+ if (setuid(realuid)) {
+ debug(F101,"setuid failed","",errno);
+ err |= 1;
+ debug(F101,"ruid","",getuid());
+ debug(F101,"euid","",geteuid());
+ }
+ debug(F101,"setuid","",realuid);
+ if (privgid != (GID_T) -1)
+ if (setgid(realgid)) {
+ debug(F101,"setgid failed","",errno);
+ err |= 2;
+ debug(F101,"rgid","",getgid());
+ debug(F101,"egid","",getegid());
+ }
+ debug(F101,"setgid","",realgid);
+ return(err);
+#else
+ /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
+ return(priv_off());
+#endif /* SETEUID */
+#endif /* SETREUID */
+#else
+ return(0);
+#endif /* HAVE_LOCKDEV */
+}
+
+/* P R I V _ O P N -- For opening protected files or devices. */
+
+int
+priv_opn(name, modes) char *name; int modes; {
+ int x;
+ priv_on(); /* Turn privileges on */
+ debug(F111,"priv_opn",name,modes);
+ errno = 0;
+ x = open(name, modes); /* Try to open the device */
+ debug(F101,"priv_opn result","",x);
+ debug(F101,"priv_opn errno","",errno);
+ priv_off(); /* Turn privileges off */
+ return(x); /* Return open's return code */
+}
+
+/* P R I V _ C H K -- Check privileges. */
+
+/* Try to turn them off. If turning them off did not succeed, cancel them */
+
+int
+priv_chk() {
+ int x, y = 0;
+ x = priv_off(); /* Turn off privs. */
+ if (x != 0 || getuid() == privuid || geteuid() == privuid)
+ y = priv_can();
+ if (x != 0 || getgid() == privgid || getegid() == privgid)
+ y = y | priv_can();
+ return(y);
+}
+
+UID_T
+real_uid() {
+ return(realuid);
+}
+
+VOID
+ttimoff() { /* Turn off any timer interrupts */
+ /* int xx; */
+/*
+ As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
+ SIG_DFL (to catch alarms, or if there is no handler, to exit). This is to
+ cure (mask, really) a deeper problem with stray alarms that occurs on some
+ systems, possibly having to do with sleep(), that caused core dumps. It
+ should be OK to do this, because no code in this module uses nested alarms.
+ (But we still have to watch out for SCRIPT and DIAL...)
+*/
+ /* xx = */ alarm(0);
+ /* debug(F101,"ttimoff alarm","",xx); */
+ if (saval) { /* Restore any previous */
+ signal(SIGALRM,saval); /* alarm handler. */
+ /* debug(F101,"ttimoff alarm restoring saval","",saval); */
+ saval = NULL;
+ } else {
+ signal(SIGALRM,SIG_IGN); /* Used to be SIG_DFL */
+ /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
+ }
+}
+
+
+int
+tt_is_secure() { /* Tells whether the current connection is secure */
+
+ if (ttyfd == -1)
+ return(0);
+
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ )
+ return(1);
+ return(0);
+}
+
+#ifdef CK_REDIR
+
+/* External protocol handler parameters from ckuus3.c */
+extern int exp_handler, exp_stderr, exp_timo;
+
+#ifdef SELECT
+#ifdef NETPTY
+
+/* The right size is 24576 */
+
+#ifndef PTY_PBUF_SIZE /* Size of buffer to read from pty */
+#define PTY_PBUF_SIZE 24576 /* and write to net. */
+#endif /* PTY_PBUF_SIZE */
+
+#ifndef PTY_TBUF_SIZE /* Size of buffer to read from net */
+#define PTY_TBUF_SIZE 24576 /* and write to pty. */
+#endif /* PTY_TBUF_SIZE */
+
+#ifdef O_NDELAY /* Whether to use nonblocking */
+#ifndef PTY_NO_NDELAY /* reads on the pseudoterminal */
+#ifndef PTY_USE_NDELAY
+#define PTY_USE_NDELAY
+#endif /* PTY_USE_NDELAY */
+#endif /* PTY_NO_NDELAY */
+#endif /* O_NDELAY */
+
+#ifndef HAVE_OPENPTY
+#ifndef USE_CKUPTY_C
+#define USE_CKUPTY_C
+#endif /* USE_CKUPTY_C */
+#endif /* HAVE_OPENPTY */
+
+#ifdef HAVE_OPENPTY
+#include <pty.h>
+#endif
+
+VOID
+pty_make_raw(fd) int fd; {
+ int x = -23, i;
+
+#ifdef BSD44ORPOSIX /* POSIX */
+ struct termios tp;
+#else
+#ifdef ATTSV /* AT&T UNIX */
+#ifdef CK_ANSIC
+ struct termio tp = {0};
+#else
+ struct termio tp;
+#endif /* CK_ANSIC */
+#else
+ struct sgttyb tp; /* Traditional */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+ debug(F101,"pty_make_raw fd","",fd);
+ errno = 0;
+
+#ifdef BSD44ORPOSIX /* POSIX */
+ x = tcgetattr(fd,&tp);
+ debug(F101,"pty_make_raw tcgetattr","",x);
+#else
+#ifdef ATTSV /* AT&T UNIX */
+ x = ioctl(fd,TCGETA,&tp);
+ debug(F101,"pty_make_raw TCGETA ioctl","",x);
+#else
+ x = gtty(fd,&tp);
+ debug(F101,"pty_make_raw ttty","",x);
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ debug(F101,"pty_make_raw GET errno","",errno);
+
+#ifdef USE_CFMAKERAW
+ errno = 0;
+ cfmakeraw(&tp);
+ debug(F101,"pty_make_raw cfmakeraw errno","",errno);
+#else /* USE_CFMAKERAW */
+
+#ifdef COMMENT
+
+/* This very simple version recommended by Serg Iakolev doesn't work */
+
+ tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
+ tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
+ tp.c_cflag &= ~(CSIZE|PARENB);
+ tp.c_cflag |= CS8;
+ tp.c_oflag &= ~(OPOST);
+ tp.c_cc[VMIN] = 1;
+ tp.c_cc[VTIME] = 0;
+
+ debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
+ debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
+ debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
+ debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
+ debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
+
+#else
+#ifdef COMMENT
+/*
+ In this version we unset everything and then set only the
+ bits we know we need.
+*/
+ /* iflags */
+ tp.c_iflag = 0L;
+ tp.c_iflag |= IGNBRK;
+#ifdef IMAXBEL
+ tp.c_iflag |= IMAXBEL;
+#endif /* IMAXBEL */
+
+ /* oflags */
+ tp.c_oflag = 0L;
+
+ /* lflags */
+ tp.c_lflag = 0L;
+#ifdef NOKERNINFO
+ tp.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+
+ /* cflags */
+ tp.c_cflag = 0L;
+ tp.c_cflag |= CS8|CREAD;
+
+ for (i = 0; i < NCCS; i++) { /* No special characters */
+ tp.c_cc[i] = 0;
+ }
+#ifdef VMIN
+ tp.c_cc[VMIN] = 1; /* But always wait for input */
+#endif /* VMIN */
+ debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
+ debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
+ debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
+ debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
+ debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
+
+#else /* COMMENT */
+/*
+ In this version we set or unset every single flag explicitly. It works a
+ bit better than the simple version just above, but it's still far from
+ adequate.
+*/
+ /* iflags */
+ tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
+ tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
+ tp.c_iflag |= IGNBRK;
+#ifdef IMAXBEL
+#ifdef COMMENT
+ tp.c_iflag |= IMAXBEL;
+#else
+ tp.c_iflag &= ~IMAXBEL;
+#endif /* COMMENT */
+#endif /* IMAXBEL */
+#ifdef IUCLC
+ tp.c_iflag &= ~IUCLC;
+#endif /* IUCLC */
+
+ /* oflags */
+#ifdef BSDLY
+ tp.c_oflag &= ~BSDLY;
+#endif /* BSDLY */
+#ifdef CRDLY
+ tp.c_oflag &= ~CRDLY;
+#endif /* CRDLY */
+#ifdef FFDLY
+ tp.c_oflag &= ~FFDLY;
+#endif /* FFDLY */
+#ifdef NLDLY
+ tp.c_oflag &= ~NLDLY;
+#endif /* NLDLY */
+#ifdef TABDLY
+ tp.c_oflag &= ~TABDLY;
+#endif /* TABDLY */
+#ifdef VTDLY
+ tp.c_oflag &= ~VTDLY;
+#endif /* VTDLY */
+#ifdef OFDEL
+ tp.c_oflag &= ~OFDEL;
+#endif /* OFDEL */
+#ifdef OFILL
+ tp.c_oflag &= ~OFILL;
+#endif /* OFILL */
+#ifdef OLCUC
+ tp.c_oflag &= ~OLCUC;
+#endif /* OLCUC */
+#ifdef CMSPAR
+ tp.c_oflag &= ~CMSPAR;
+#endif /* CMSPAR */
+ tp.c_oflag &= ~OPOST;
+#ifdef OXTABS
+ tp.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+#ifdef COMMENT
+#ifdef ONOCR
+ tp.c_oflag &= ~ONOCR; /* Maybe should be |=? */
+ tp.c_oflag |= ONOCR; /* makes no difference either way */
+#endif /* ONOCR */
+#endif /* COMMENT */
+#ifdef ONOEOT
+ tp.c_oflag &= ~ONOEOT;
+#endif /* ONOEOT */
+#ifdef ONLRET
+ tp.c_oflag &= ~ONLRET;
+#endif /* ONLRET */
+#ifdef ONLCR
+ tp.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+#ifdef OCRNL
+ tp.c_oflag &= ~OCRNL;
+#endif /* OCRNL */
+
+ /* lflags */
+ tp.c_lflag &= ~ECHO;
+#ifdef ECHOE
+ tp.c_lflag &= ~ECHOE;
+#endif /* ECHOE */
+#ifdef ECHONL
+ tp.c_lflag &= ~ECHONL;
+#endif /* ECHONL */
+#ifdef ECHOPRT
+ tp.c_lflag &= ~ECHOPRT;
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ tp.c_lflag &= ~ECHOKE;
+#endif /* ECHOKE */
+#ifdef ECHOCTL
+ tp.c_lflag &= ~ECHOCTL;
+#endif /* ECHOCTL */
+#ifdef XCASE
+ tp.c_lflag &= ~XCASE;
+#endif /* XCASE */
+#ifdef ALTWERASE
+ tp.c_lflag &= ~ALTWERASE;
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
+#else
+ tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
+#endif /* EXTPROC */
+#ifdef NOKERNINFO
+ tp.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+#ifndef COMMENT
+ tp.c_lflag &= ~NOFLSH; /* TRY IT THE OTHER WAY? */
+#else
+ tp.c_lflag |= NOFLSH; /* No, this way is worse */
+#endif /* COMMENT */
+
+ /* cflags */
+ tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ tp.c_cflag |= CS8|CREAD;
+
+#ifdef MDMBUF
+ tp.c_cflag &= ~(MDMBUF);
+#else
+#ifdef CCAR_OFLOW
+ tp.c_cflag &= ~(CCAR_OFLOW); /* two names for the same thing */
+#endif /* CCAR_OFLOW */
+#endif /* MDMBUF */
+
+#ifdef CCTS_OFLOW
+ tp.c_cflag &= ~(CCTS_OFLOW);
+#endif /* CCTS_OFLOW */
+#ifdef CDSR_OFLOW
+ tp.c_cflag &= ~(CDSR_OFLOW);
+#endif /* CDSR_OFLOW */
+#ifdef CDTR_IFLOW
+ tp.c_cflag &= ~(CDTR_IFLOW);
+#endif /* CDTR_IFLOW */
+#ifdef CRTS_IFLOW
+ tp.c_cflag &= ~(CRTS_IFLOW);
+#endif /* CRTS_IFLOW */
+#ifdef CRTSXOFF
+ tp.c_cflag &= ~(CRTSXOFF);
+#endif /* CRTSXOFF */
+#ifdef CRTSCTS
+ tp.c_cflag &= ~(CRTSCTS);
+#endif /* CRTSCTS */
+#ifdef CLOCAL
+ tp.c_cflag &= ~(CLOCAL);
+#endif /* CLOCAL */
+#ifdef CSTOPB
+ tp.c_cflag &= ~(CSTOPB);
+#endif /* CSTOPB */
+#ifdef HUPCL
+ tp.c_cflag &= ~(HUPCL);
+#endif /* HUPCL */
+
+ for (i = 0; i < NCCS; i++) { /* No special characters */
+ tp.c_cc[i] = 0;
+ }
+#ifdef VMIN
+ tp.c_cc[VMIN] = 1; /* But always wait for input */
+#endif /* VMIN */
+ debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
+ debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
+ debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
+ debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
+ debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
+#endif /* COMMENT */
+#endif /* COMMENT */
+
+ errno = 0;
+#ifdef BSD44ORPOSIX /* POSIX */
+ x = tcsetattr(fd,TCSANOW,&tp);
+ debug(F101,"pty_make_raw tcsetattr","",x);
+#else
+#ifdef ATTSV /* AT&T UNIX */
+ x = ioctl(fd,TCSETA,&tp);
+ debug(F101,"pty_make_raw ioctl","",x);
+#else
+ x = stty(fd,&tp); /* Traditional */
+ debug(F101,"pty_make_raw stty","",x);
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ debug(F101,"pty_make_raw errno","",errno);
+
+#endif /* __NetBSD__ */
+}
+
+static int
+pty_chk(fd) int fd; {
+ int x, n = 0;
+ errno = 0;
+#ifdef FIONREAD
+ x = ioctl(fd, FIONREAD, &n); /* BSD and most others */
+ ckmakmsg(msgbuf,500,
+ "pty_chk ioctl FIONREAD errno=",
+ ckitoa(errno),
+ " count=",
+ ckitoa(n));
+ debug(F100,msgbuf,"",0);
+#else
+#ifdef RDCHK
+ n = rdchk(fd);
+ debug(F101,"pty_chk rdchk","",n);
+#else
+ n = 1;
+#endif /* RDCHK */
+#endif /* FIONREAD */
+ return((n > -1) ? n : 0);
+}
+
+static int
+pty_get_status(fd,pid) int fd; PID_T pid; {
+ int x, status = -1;
+ PID_T w;
+
+ debug(F101,"pty_get_status fd","",fd);
+ debug(F101,"pty_get_status pid","",pid);
+
+ if (pexitstat > -1)
+ return(pexitstat);
+
+#ifdef COMMENT
+ /* Not only unnecessary but harmful */
+ errno = 0;
+ x = kill(pty_fork_pid,0);
+ debug(F101,"pty_get_status kill value","",x);
+ debug(F101,"pty_get_status kill errno","",errno);
+ if (x > -1 && errno != ESRCH)
+ return(-1); /* Fork still there */
+ /* Fork seems to be gone */
+#endif /* COMMENT */
+
+ errno = 0;
+ x = waitpid(pty_fork_pid,&status,WNOHANG);
+ debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
+ if (x <= 0 && errno == 0) {
+ debug(F101,"pty_get_status waitpid return","",-1);
+ return(-1);
+ }
+ if (x > 0) {
+ if (x != pty_fork_pid)
+ debug(F101,
+ "pty_get_status waitpid pid doesn't match","",pty_fork_pid);
+ debug(F101,"pty_get_status waitpid status","",status);
+ debug(F101,"pty_get_status waitpid errno","",errno);
+ if (WIFEXITED(status)) {
+ debug(F100,"pty_get_status WIFEXITED","",0);
+ status = WEXITSTATUS(status);
+ debug(F101,"pty_get_status fork exit status","",status);
+#ifdef COMMENT
+ end_pty();
+#endif /* COMMENT */
+ close(fd);
+ pexitstat = status;
+ } else {
+ debug(F100,"pty_get_status waitpid unexpected status","",0);
+ }
+ }
+ debug(F101,"pty_get_status return status","",status);
+ return(status);
+}
+
+/* t t p t y c m d -- Run command on pty and forward to net */
+
+/*
+ Needed for running external protocols on secure connections.
+ For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
+ connection, and then needs to transfer a file with Zmodem, which is
+ an external program, this routine reads Zmodem's output, encrypts it,
+ and then forwards it out the connection, and reads the encrypted data
+ stream coming in from the connection, decrypts it, and forwards it to
+ Zmodem.
+
+ Works like a TCP/IP port forwarder except one end is a pty rather
+ than a socket, which introduces some complications:
+
+ . On most platforms, select() always indicates the output side of
+ the pty has characters waiting to be read, even when it doesn't,
+ even when the pty process has already exited.
+
+ . Nonblocking reads must be used on the pty, because there is no
+ way on certain platforms (e.g. NetBSD) to find out how many characters
+ are available to be read (the FIONREAD ioctl always says 0). The code
+ also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
+ defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
+ result in single-byte reads and writes (NetBSD again).
+
+ . Testing for "EOF" on the pty is problematic. select() never gives
+ any indication. After the pty process has exited and the fork has
+ disappeared, read() can still return with 0 bytes read but without an
+ error (NetBSD); no known test on the pty file descriptor will indicate
+ that it is no longer valid. The process ID of the pty fork can be
+ tested on some platforms (NetBSD, luckily) but not others (Solaris,
+ Linux).
+
+ On the network side, we use ttinc() and ttoc(), which, for network
+ connections, handle any active security methods.
+
+ Call with s = command.
+ Returns 0 on failure, 1 on success.
+ fdc - December 2006 - August 2007.
+
+ NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
+ defined in the header files, which should be true of every recent Unix
+ platform. If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
+ building C-Kermit:
+
+ touch ckutio.c
+ make platformname KFLAGS=-DPTY_NO_NODELAY
+*/
+static int have_pty = 0; /* Do we have a pty? */
+
+static SIGTYP (*save_sigchld)() = NULL; /* For catching SIGCHLD */
+
+static VOID
+sigchld_handler(sig) int sig; {
+ have_pty = 0; /* We don't have a pty */
+#ifdef DEBUG
+ if (save_sigchld) {
+ (VOID) signal(SIGCHLD,save_sigchld);
+ save_sigchld = NULL;
+ }
+ if (deblog) {
+ debug(F100,"**************","",0);
+ debug(F100,"SIGCHLD caught","",0);
+ debug(F100,"**************","",0);
+ }
+#endif /* DEBUG */
+}
+#define HAVE_IAC 1
+#define HAVE_CR 2
+
+int
+ttptycmd(s) char *s; {
+ CHAR tbuf[PTY_TBUF_SIZE]; /* Read from net, write to pty */
+ int tbuf_avail = 0; /* Pointers for tbuf */
+ int tbuf_written = 0;
+ static int in_state = 0; /* For TELNET IAC and NVT in */
+ static int out_prev = 0; /* Simpler scheme for out */
+
+ CHAR pbuf[PTY_PBUF_SIZE]; /* Read from pty, write to net */
+ CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
+ int pbuf_avail = 0; /* Pointers for pbuf */
+ int pbuf_written = 0;
+
+ int ptyfd = -1; /* Pty file descriptor */
+ int have_net = 0; /* We have a network connection */
+ int pty_err = 0; /* Got error on pty */
+ int net_err = 0; /* Got error on net */
+ int status = -1; /* Pty process exit status */
+ int rc = 0; /* Our return code */
+
+ int x1 = 0, x2 = 0; /* Workers... */
+ int c, n, m, t, x; /* Workers */
+
+ long seconds_to_wait = 0L; /* select() timeout */
+ struct timeval tv, *tv2; /* For select() */
+#ifdef INTSELECT
+ int in, out, err; /* For select() */
+#else
+ fd_set in, out, err;
+#endif /* INTSELECT */
+ int nfds = 0; /* For select() */
+
+ int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
+ int read_net_bytes = 0; /* Stats */
+ int write_net_bytes = 0; /* Stats */
+ int read_pty_bytes = 0; /* Stats */
+ int write_pty_bytes = 0; /* Stats */
+ int is_tn = 0; /* TELNET protocol is active */
+
+ int masterfd = -1;
+ int slavefd = -1;
+#ifndef USE_CKUPTY_C
+ struct termios term;
+ struct winsize twin;
+ struct stringarray * q;
+ char ** args = NULL;
+#endif /* USE_CKUPTY_C */
+
+ in_state = 0; /* No previous character yet */
+
+ if (ttyfd == -1) {
+ printf("?Sorry, communication channel is not open\n");
+ return(0);
+ } else {
+ have_net = 1;
+ }
+ if (nopush) {
+ debug(F100,"ttptycmd fail: nopush","",0);
+ return(0);
+ }
+ if (!s) s = ""; /* Defense de bogus arguments */
+ if (!*s) return(0);
+ pexitstat = -1; /* Fork process exit status */
+
+#ifdef TNCODE
+ is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
+ (!xlocal && sstelnet);
+#endif /* TNCODE */
+
+ debug(F110,"ttptycmd command",s,0);
+ debug(F101,"ttptycmd ttyfd","",ttyfd);
+ debug(F101,"ttptycmd is_tn","",is_tn);
+ debug(F101,"ttptycmd ckermit pid","",getpid());
+
+#ifdef USE_CKUPTY_C
+ /* Call ckupty.c module to get and set up the pty fork */
+ /* fc 1 == "run an external protocol" */
+ debug(F100,"ttptycmd using ckupty.c","",0);
+ if (do_pty(&ptyfd,s,1) < 0) { /* Start the command on a pty */
+ debug(F100,"ttptycmd do_pty fails","",0);
+ return(0);
+ }
+ masterfd = ptyfd;
+ pty_master_fd = ptyfd;
+#ifdef COMMENT
+ slavefd = pty_slave_fd; /* This is not visible to us */
+#endif /* COMMENT */
+ debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
+ debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
+ debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
+#ifndef SOLARIS
+ /* "ioctl inappropriate on device" for pty master */
+ pty_make_raw(masterfd);
+#endif /* SOLARIS */
+
+#else /* USE_CKUPTY_C */
+
+ debug(F100,"ttptycmd OPENPTY","",0);
+ if (tcgetattr(0, &term) == -1) { /* Get controlling terminal's modes */
+ perror("tcgetattr");
+ return(0);
+ }
+ if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
+ perror("ioctl TIOCGWINSZ");
+ return(0);
+ }
+ if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
+ debug(F101,"ttptycmd openpty failed errno","",errno);
+ perror("opentpy");
+ return(0);
+ }
+ debug(F101,"ttptycmd openpty masterfd","",masterfd);
+ debug(F101,"ttptycmd openpty slavefd","",slavefd);
+ pty_master_fd = masterfd;
+ pty_slave_fd = slavefd;
+ debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
+
+ /* Put pty master in raw mode but let forked app control the slave */
+ pty_make_raw(masterfd);
+
+#ifdef COMMENT
+#ifdef TIOCREMOTE
+ /* TIOCREMOTE,0 = disable all termio processing */
+ x = ioctl(masterfd, TIOCREMOTE, 1);
+ debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
+#endif /* TIOCREMOTE */
+#ifdef TIOCTTY
+ /* TIOCTTY,0 = disable all termio processing */
+ x = ioctl(masterfd, TIOCTTY, 0);
+ debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
+#endif /* TIOCTTY */
+#endif /* COMMENT */
+
+ have_pty = 1; /* We have an open pty */
+ save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
+
+ pty_fork_pid = fork(); /* Make fork for external protocol */
+ debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
+ if (pty_fork_pid == -1) {
+ perror("fork");
+ return(0);
+ } else if (pty_fork_pid == 0) { /* In new fork */
+ int x;
+ debug(F101,"ttptycmd new fork pid","",getpid());
+ close(masterfd); /* Slave quarters no masters allowed */
+ x = setsid();
+ debug(F101,"ttptycmd new fork setsid","",x);
+ if (x == -1) {
+ perror("ttptycmd setsid");
+ exit(1);
+ }
+ signal(SIGINT,SIG_IGN); /* Let upper fork catch this */
+
+#ifdef COMMENT
+#ifdef TIOCSCTTY
+ /* Make pty the controlling terminal for the process */
+ /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
+ x = ioctl(slavefd, TIOCSCTTY, NULL);
+ debug(F101,"ttptycmd TIOCSCTTY","",x);
+#endif /* TIOCSCTTY */
+#endif /* COMMENT */
+
+ /* Initialize slave pty modes and size to those of our terminal */
+ if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
+ perror("ttptycmd tcsetattr");
+ exit(1);
+ }
+ if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
+ perror("ttptycmd ioctl");
+ exit(1);
+ }
+#ifdef COMMENT
+#ifdef TIOCNOTTY
+ /* Disassociate this process from its terminal */
+ /* THIS HAS NO EFFECT */
+ x = ioctl(slavefd, TIOCNOTTY, NULL);
+ debug(F101,"ttptycmd TIOCNOTTY","",x);
+#endif /* TIOCNOTTY */
+#endif /* COMMENT */
+
+#ifdef COMMENT
+#ifdef SIGTTOU
+ /* Ignore terminal output interrupts */
+ /* THIS HAS NO EFFECT */
+ debug(F100,"ttptycmd ignoring SIGTTOU","",0);
+ signal(SIGTTOU, SIG_IGN);
+#endif /* SIGTTOU */
+#ifdef SIGTSTP
+ /* Ignore terminal output interrupts */
+ /* THIS HAS NO EFFECT */
+ debug(F100,"ttptycmd ignoring SIGTSTP","",0);
+ signal(SIGTSTP, SIG_IGN);
+#endif /* SIGTSTP */
+#endif /* COMMENT */
+
+ pty_make_raw(slavefd); /* Put it in rawmode */
+
+ errno = 0;
+ if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
+ dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
+ debug(F101,"ttptycmd new fork dup2 error","",errno);
+ perror("ttptycmd dup2");
+ exit(1);
+ }
+ debug(F100,"ttptycmd new fork dup2 ok","",0);
+
+ /* Parse external protocol command line */
+ q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
+ if (!q) {
+ debug(F100,"ttptycmd cksplit failed","",0);
+ exit(1);
+ } else {
+ int i, n;
+ debug(F100,"ttptycmd cksplit ok","",0);
+ n = q->a_size;
+ args = q->a_head + 1;
+ for (i = 0; i <= n; i++) {
+ if (!args[i]) {
+ break;
+ } else {
+ /* sometimes cksplit() doesn't terminate the list */
+ if ((i == n) && args[i]) {
+ if ((int)strlen(args[i]) == 0)
+ makestr(&(args[i]),NULL);
+ }
+ }
+ }
+ }
+#ifdef COMMENT
+/*
+ Putting the slave pty in rawmode should not be necessary because the
+ external protocol program is supposed to do that itself. Yet doing this
+ here cuts down on Zmodem binary-file transmission errors by 30-50% but
+ still doesn't eliminate them.
+*/
+ pty_make_raw(STDIN_FILENO);
+ pty_make_raw(STDOUT_FILENO);
+#endif /* COMMENT */
+
+ debug(F100,"ttptycmd execvp'ing external protocol","",0);
+ execvp(args[0],args);
+ perror("execvp failed");
+ debug(F101,"ttptycmd execvp failed","",errno);
+ close(slavefd);
+ exit(1);
+ }
+ /* (there are better ways to do this...) */
+ msleep(1000); /* Make parent wait for child to be ready */
+ ptyfd = masterfd; /* We talk to the master */
+
+#endif /* USE_CKUPTY_C */
+
+ debug(F101,"ttptycmd ptyfd","",ptyfd);
+ if (ptyfd < 0) {
+ printf("?Failure to get pty\n");
+ return(-9);
+ }
+ have_pty = 1; /* We have an open pty or we wouldn't he here */
+
+ debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
+ debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
+
+#ifdef PTY_USE_NDELAY
+ /*
+ NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
+ on the pty, we don't need nonblocking reads. Performance of either
+ method seems to be about the same, so use whatever works.
+ */
+ errno = 0;
+ x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
+ ckmakmsg(msgbuf,500,
+ "ttptycmd set O_NDELAY errno=",
+ ckitoa(errno),
+ " fcntl=",
+ ckitoa(x));
+ debug(F100,msgbuf,"",0);
+#endif /* PTY_USE_NDELAY */
+
+#ifdef COMMENT
+/* Not necessary, the protocol module already did this */
+
+#ifdef USE_CFMAKERAW
+ if (tcgetattr(ttyfd, &term) > -1) {
+ cfmakeraw(&term);
+ debug(F101,"ttptycmd net cfmakeraw errno","",errno);
+ x tcsetattr(ttyfd, TCSANOW, &term);
+ debug(F101,"ttptycmd net tcsetattr","",x);
+ debug(F101,"ttptycmd net tcsetattr","",errno);
+ }
+#else
+ if (local) /* Put network connection in */
+ ttpkt(ttspeed,ttflow,ttprty); /* "packet mode". */
+ else
+ conbin((char)escchr); /* OR... pty_make_raw(0) */
+#endif /* USE_CFMAKERAW */
+#endif /* COMMENT */
+
+#ifdef TNCODE
+ if (is_tn) {
+ debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
+ debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
+ }
+#endif /* TNCODE */
+
+ debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
+
+ while (have_pty || have_net) {
+ FD_ZERO(&in); /* Initialize select() structs */
+ FD_ZERO(&out);
+ FD_ZERO(&err); /* (not used because useless) */
+ nfds = -1;
+
+ debug(F101,"ttptycmd loop top have_pty","",have_pty);
+ debug(F101,"ttptycmd loop top have_net","",have_net);
+
+ /* Pty is open and we have room to read from it? */
+ if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
+ debug(F100,"ttptycmd FD_SET ptyfd in","",0);
+ FD_SET(ptyfd, &in);
+ nfds = ptyfd;
+ }
+ /* Network is open and we have room to read from it? */
+ if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
+ debug(F100,"ttptycmd FD_SET ttyfd in","",0);
+ FD_SET(ttyfd, &in);
+ if (ttyfd > nfds) nfds = ttyfd;
+ }
+ /* Pty is open and we have stuff to write to it? */
+ if (have_pty && tbuf_avail - tbuf_written > 0) {
+ debug(F100,"ttptycmd FD_SET ptyfd out","",0);
+ FD_SET (ptyfd, &out);
+ if (ptyfd > nfds) nfds = ptyfd;
+ }
+ /* Net is open and we have stuff to write to it? */
+ debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
+ pbuf_avail - pbuf_written);
+ if (have_net && pbuf_avail - pbuf_written > 0) {
+ debug(F100,"ttptycmd FD_SET ttyfd out","",0);
+ FD_SET (ttyfd, &out);
+ if (ttyfd > nfds) nfds = ttyfd;
+ }
+ /* We don't use err because it's not really for errors, */
+ /* but for out of band data on the TCP socket, which, if it is */
+ /* to be handled at all, is handled in the tt*() routines */
+
+ nfds++; /* 0-based to 1-based */
+ debug(F101,"ttptycmd nfds","",nfds);
+ if (!nfds) {
+ debug(F100,"ttptycmd NO FDs set for select","",0);
+ if (have_pty) {
+ /* This is not right -- sleeping won't accomplish anything */
+ debug(F101,"ttptycmd msleep","",100);
+ msleep(100);
+ } else {
+ debug(F100,"ttptycmd no pty - quitting loop","",0);
+ break;
+ }
+ }
+ errno = 0;
+
+ if (seconds_to_wait > 0L) { /* Timeout in case nothing happens */
+ tv.tv_sec = seconds_to_wait; /* for a long time */
+ tv.tv_usec = 0L;
+ tv2 = &tv;
+ } else {
+ tv2 = NULL;
+ }
+ x = select(nfds, &in, &out, NULL, tv2);
+ debug(F101,"ttptycmd select","",x);
+ if (x < 0) {
+ if (errno == EINTR)
+ continue;
+ debug(F101,"ttptycmd select error","",errno);
+ break;
+ }
+ if (x == 0) {
+ debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait);
+ if (have_pty) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status A","",status);
+ if (status > -1) pexitstat = status;
+ have_pty = 0;
+ }
+ break;
+ }
+ /* We want to handle any pending writes first to make room */
+ /* for new incoming. */
+
+ if (FD_ISSET(ttyfd, &out)) { /* Can write to net? */
+ CHAR * s;
+ s = pbuf + pbuf_written; /* Current spot for sending */
+#ifdef TNCODE
+ if (is_tn) { /* ttol() doesn't double IACs */
+ CHAR c; /* Rewrite string with IACs doubled */
+ int i;
+ s = pbuf + pbuf_written; /* Source */
+ x = 0; /* Count */
+ for (i = 0; i < pbuf_avail - pbuf_written; i++) {
+ c = s[i]; /* Next character */
+ if (c == IAC) { /* If it's IAC */
+ dbuf[x++] = c; /* put another one */
+ debug(F000,">>> QUOTED IAC","",c);
+ } else if (c != 0x0a && out_prev == 0x0d) { /* Bare CR */
+ if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
+ c = 0x00;
+ dbuf[x++] = c;
+ debug(F000,">>> CR-NUL","",c);
+ }
+ }
+ dbuf[x++] = c; /* Copy and count it */
+ debug(F000,">>> char",ckitoa(in_state),c);
+ out_prev = c;
+ }
+ s = dbuf; /* New source */
+ } else
+#endif /* TNCODE */
+ x = pbuf_avail - pbuf_written; /* How much to send */
+
+ debug(F101,"ttptycmd bytes to send","",x);
+ x = ttol(s, x);
+ debug(F101,">>> ttol","",x);
+ if (x < 0) {
+ net_err++;
+ debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
+ x = 0;
+ }
+ write_net_bytes += x;
+ pbuf_written += x;
+ }
+ if (FD_ISSET(ptyfd, &out)) { /* Can write to pty? */
+ debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
+ errno = 0;
+#ifndef COMMENT
+ x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
+#else
+ /* Byte loop to rule out data overruns in the pty */
+ /* (it makes no difference) */
+ {
+ char *p = tbuf+tbuf_written;
+ int n = tbuf_avail - tbuf_written;
+ for (x = 0; x < n; x++) {
+ msleep(10);
+ if (write(ptyfd,&(p[x]),1) < 0)
+ break;
+ }
+ }
+#endif /* COMMENT */
+ debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
+ if (x > 0) {
+ tbuf_written += x;
+ write_pty_bytes += x;
+ } else {
+ x = 0;
+ pty_err++;
+ if (pexitstat < 0) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status B","",status);
+ if (status > -1) pexitstat = status;
+ have_pty = 0;
+ }
+ debug(F100,"ttptycmd +++ ptyfd write error","",0);
+ }
+ }
+ if (FD_ISSET(ttyfd, &in)) { /* Can read from net? */
+ tset++;
+ debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
+ n = in_chk(1,ttyfd);
+ debug(F101,"ttptycmd in_chk(ttyfd)","",n);
+ if (n < 0 || ttyfd == -1) {
+ debug(F101,"ttptycmd +++ ttyfd errno","",errno);
+ net_err++;
+ } else if (n > 0) {
+ if (n > PTY_TBUF_SIZE - tbuf_avail)
+ n = PTY_TBUF_SIZE - tbuf_avail;
+ debug(F101,"ttptycmd net read size adjusted","",n);
+ if (xlocal && netconn) {
+ /*
+ We have to use a byte loop here because ttxin()
+ does not decrypt or, for that matter, handle Telnet.
+ */
+ int c;
+ CHAR * p;
+ p = tbuf + tbuf_avail;
+ for (x = 0; x < n; x++) {
+ if ((c = ttinc(0)) < 0)
+ break;
+ if (!is_tn) { /* Not Telnet - keep all bytes */
+ *p++ = (CHAR)c;
+ debug(F000,"<<< char","",c);
+#ifdef TNCODE
+ } else { /* Telnet - must handle IAC and NVT */
+ debug(F000,"<<< char",ckitoa(in_state),c);
+ switch (c) {
+ case 0x00: /* NUL */
+ if (in_state == HAVE_CR) {
+ debug(F000,"<<< SKIP","",c);
+ } else {
+ *p++ = c;
+ debug(F000,"<<< Keep","",c);
+ }
+ in_state = 0;
+ break;
+ case 0x0d: /* CR */
+ if (!TELOPT_U(TELOPT_BINARY))
+ in_state = HAVE_CR;
+ *p++ = c;
+ debug(F000,"<<< Keep","",c);
+ break;
+#ifdef COMMENT
+ case 0x0f: /* Ctrl-O */
+ case 0x16: /* Ctrl-V */
+ *p++ = 0x16;
+ *p++ = c;
+ debug(F000,"<<< QUOT","",c);
+ break;
+#endif /* COMMENT */
+ case 0xff: /* IAC */
+ if (in_state == HAVE_IAC) {
+ debug(F000,"<<< KEEP","",c);
+ *p++ = c;
+ in_state = 0;
+ } else {
+ debug(F000,"<<< SKIP","",c);
+ in_state = HAVE_IAC;
+ }
+ break;
+ default: /* All others */
+ if (in_state == HAVE_IAC) {
+#ifdef COMMENT
+/*
+ tn_doop() will consume an unknown number of bytes and we'll overshoot
+ the for-loop. The only Telnet command I've ever seen arrive here is
+ a Data Mark, which comes when the remote protocol exits and the remote
+ job returns to its shell prompt. On the assumption it's a 1-byte command,
+ we don't write out the IAC or the command, and we clear the state. If
+ we called tn_doop() we'd have no way of knowing how many bytes it took
+ from the input stream.
+*/
+ int xx;
+ xx = tn_doop((CHAR)c,duplex,ttinc);
+ debug(F111,"<<< DOOP",ckctoa(c),xx);
+#else
+ debug(F101,"<<< DOOP","",c);
+#endif /* COMMENT */
+ in_state = 0;
+ } else {
+ *p++ = c;
+ debug(F000,"<<< keep","",c);
+ in_state = 0;
+ }
+ }
+#endif /* TNCODE */
+ }
+ }
+ ckmakmsg(msgbuf,500,
+ "ttptycmd read net [ttinc loop] errno=",
+ ckitoa(errno),
+ " count=",
+ ckitoa(x));
+ debug(F100,msgbuf,"",0);
+ } else {
+ x = ttxin(n,tbuf+tbuf_avail);
+ debug(F101,"ttptycmd ttxin x","",x);
+ }
+
+ if (x < 0) {
+ debug(F101,"ttptycmd read net error","",x);
+ net_err++;
+ }
+ tbuf_avail += x;
+ read_net_bytes += x;
+ }
+
+ } else
+ tnotset++;
+
+ if (FD_ISSET(ptyfd, &in)) { /* Read from pty? */
+ pset++;
+ debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
+#ifdef PTY_USE_NDELAY
+ n = PTY_PBUF_SIZE;
+#else
+ /*
+ This does not work on nonblocking channels
+ on certain platforms such as NetBSD.
+ */
+ n = pty_chk(ptyfd);
+#endif /* PTY_USE_NDELAY */
+ debug(F101,"ttptycmd pty_chk() n","",n);
+
+ if (n < 0)
+ n = 0;
+ if (n > 0) {
+ if (n > PTY_PBUF_SIZE - pbuf_avail)
+ n = PTY_PBUF_SIZE - pbuf_avail;
+ debug(F101,"ttptycmd pty read size adjusted","",n);
+ errno = 0;
+ x = read(ptyfd,pbuf+pbuf_avail,n);
+#ifdef DEBUG
+ if (deblog) {
+ ckmakmsg(msgbuf,500,
+ "ttptycmd read pty errno=",
+ ckitoa(errno),
+ " count=",
+ ckitoa(x));
+ debug(F100,msgbuf,"",0);
+ }
+#endif /* DEBUG */
+
+ if (x < 0 && errno == EAGAIN)
+ x = 0;
+
+ if (x < 0) { /* This works on Solaris and Linux */
+ pty_err++; /* but not NetBSD */
+ debug(F100,"TERMINATION TEST A","",0);
+#ifdef COMMENT
+ if (errno == EIO)
+ rc = 1;
+#endif /* COMMENT */
+ if (pexitstat < 0) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status C","",status);
+ if (status > -1) pexitstat = status;
+ }
+ have_pty = 0;
+ x = 0;
+ }
+ if (x == 0 && !pty_err) { /* This works on NetBSD but */
+ debug(F100,"TERMINATION TEST B","",0);
+ status = pexitstat > -1 ? pexitstat :
+ pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status D","",status);
+ if (status > -1) {
+ pexitstat = status;
+ pty_err++;
+ have_pty = 0;
+ } else { /* Select() lied */
+ pty_err = 0; /* pty still there but has nothing */
+ msleep(100); /* sleep a bit */
+ }
+ x = 0;
+ }
+ /* Hopefully the next two are no longer needed... */
+ if (!pty_err && (
+#ifndef PTY_USE_NDELAY
+ x < 1 || errno
+#else
+ errno != 0 && errno != EAGAIN
+#endif /* PTY_USE_NDELAY */
+ )) {
+ debug(F100,"TERMINATION TEST C","",0);
+ pty_err++;
+ debug(F101,"ttptycmd SET pty_err","",pty_err);
+ if (errno == EIO) /* errno == EIO is like EOF */
+ rc = 1;
+ if (x < 0)
+ x = 0;
+ }
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ pbuf[pbuf_avail + x] = '\0';
+ debug(F111,"ttptycmd added to pty buffer",
+ pbuf+pbuf_avail,x);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ pbuf_avail += x;
+ read_pty_bytes += x;
+ } else { /* n == 0 with blocking reads */
+ debug(F100,
+ "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
+ "",0);
+ }
+ } else
+ pnotset++;
+
+ /* If writes have caught up to reads, reset the buffers */
+
+ if (pbuf_written == pbuf_avail)
+ pbuf_written = pbuf_avail = 0;
+ if (tbuf_written == tbuf_avail)
+ tbuf_written = tbuf_avail = 0;
+
+ /* See if we can exit */
+
+ x1 = pbuf_avail - pbuf_written;
+ x2 = tbuf_avail - tbuf_written;
+
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
+
+ if (net_err) { /* Net error? */
+ debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
+ if (have_net) {
+ if (local) {
+ ttclos(0);
+ printf("?Connection closed\n");
+ }
+ have_net = 0;
+ }
+ debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
+ if (x1 == 0)
+ break;
+ }
+ if (pty_err) { /* Pty error? */
+ if (have_pty) {
+ if (pexitstat < 0) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status E","",status);
+ if (status > -1) pexitstat = status;
+ }
+ have_pty = 0;
+ }
+ if (x1 == 0 && x2 == 0) { /* If buffers are caught up */
+ rc = 1; /* set preliminary return to success */
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
+ break; /* and exit the loop */
+ }
+ }
+ }
+ debug(F101,"ttptycmd +++ have_pty","",have_pty);
+ if (have_pty) { /* In case select() failed */
+#ifdef USE_CKUPTY_C
+ end_pty();
+ close(ptyfd);
+#else
+ close(slavefd);
+ close(masterfd);
+#endif /* USE_CKUPTY_C */
+ }
+ pty_master_fd = -1;
+ debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
+ if (pexitstat < 0) { /* Try one last time to get status */
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status F","",status);
+ if (status > -1) pexitstat = status;
+ }
+ debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
+ if (deblog) { /* Stats for debug log */
+ debug(F101,"ttptycmd +++ pset ","",pset);
+ debug(F101,"ttptycmd +++ pnotset","",pnotset);
+ debug(F101,"ttptycmd +++ tset ","",tset);
+ debug(F101,"ttptycmd +++ tnotset","",tnotset);
+
+ debug(F101,"ttptycmd +++ read_pty_bytes","",read_pty_bytes);
+ debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
+ debug(F101,"ttptycmd +++ read_net_bytes","",read_net_bytes);
+ debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
+ }
+/*
+ If we got the external protocol's exit status from waitpid(), we use that
+ to set our return code. If not, we fall back on whatever rc was previously
+ set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
+*/
+ if (save_sigchld) { /* Restore this if we changed it */
+ (VOID) signal(SIGCHLD,save_sigchld);
+ save_sigchld = NULL;
+ }
+ msleep(500);
+ x = kill(pty_fork_pid,SIGHUP); /* In case it's still there */
+ pty_fork_pid = -1;
+ debug(F101,"ttptycmd fork kill SIGHUP","",x);
+ if (pexitstat > -1)
+ rc = (pexitstat == 0 ? 1 : 0);
+ debug(F101,"ttptycmd +++ rc","",rc);
+ if (!local) { /* If in remote mode */
+ conres(); /* restore console to CBREAK mode */
+ concb((char)escchr);
+ }
+ return(rc);
+}
+#endif /* NETPTY */
+#endif /* SELECT */
+
+/* T T R U N C M D -- Redirect an external command over the connection. */
+
+/*
+ TTRUNCMD is the routine that was originally used for running external
+ protocols. It is very simple and works fine provided (a) the connection
+ is not encrypted, and (b) the external protocol uses standard i/o
+ (file descriptors 0 and 1) for file transfer.
+*/
+
+int
+ttruncmd(s) char *s; {
+ PID_T pid; /* pid of lower fork */
+ int wstat; /* for wait() */
+ int x;
+ int statusp;
+
+ if (ttyfd == -1) {
+ printf("?Sorry, device is not open\n");
+ return(0);
+ }
+ if (nopush) {
+ debug(F100,"ttruncmd fail: nopush","",0);
+ return(0);
+ }
+
+#ifdef NETPTY
+/***************
+ It might also be necessary to use the pty routine for other reasons,
+ e.g. because the external program does not use stdio.
+*/
+#ifdef NETCONN
+/*
+ If we have a network connection we use a different routine because
+ (a) if the connection is encrypted, the mechanism used here can't deal
+ with it; and (b) it won't handle any network protocols either, e.g.
+ Telnet, Rlogin, K5 U-to-U, etc. However, this routine works much
+ better (faster, more transparent) on serial connections and when
+ C-Kermit is in remote mode (i.e. is on the far end).
+*/
+ /* For testing always use this */
+ if (netconn)
+ return(ttptycmd(s));
+#endif /* NETCONN */
+
+/***************/
+#else /* NETPTY */
+ if (tt_is_secure()) {
+ printf("?Sorry, \
+external protocols over secure connections not supported in this OS.\n"
+ );
+ return(0);
+ }
+#endif /* NETPTY */
+
+ conres(); /* Make console normal */
+ pexitstat = -4;
+ if ((pid = fork()) == 0) { /* Make a child fork */
+ if (priv_can()) /* Child: turn off privs. */
+ exit(1);
+ dup2(ttyfd, 0); /* Give stdin/out to the line */
+ dup2(ttyfd, 1);
+ x = system(s);
+ debug(F101,"ttruncmd system",s,x);
+ _exit(x ? BAD_EXIT : 0);
+ } else {
+ SIGTYP (*istat)(), (*qstat)();
+ if (pid == (PID_T) -1) /* fork() failed? */
+ return(0);
+ istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
+ qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
+
+#ifdef COMMENT
+ while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
+#else /* Not COMMENT */
+ while (1) {
+ wstat = wait(&statusp);
+ debug(F101,"ttruncmd wait","",wstat);
+ if (wstat == pid || wstat == -1)
+ break;
+ }
+#endif /* COMMENT */
+
+ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
+ debug(F101,"ttruncmd wait statusp","",statusp);
+ debug(F101,"ttruncmd wait pexitstat","",pexitstat);
+ signal(SIGINT,istat); /* Restore interrupts */
+ signal(SIGQUIT,qstat);
+ }
+ concb((char)escchr); /* Restore console to CBREAK mode */
+ return(statusp == 0 ? 1 : 0);
+}
+#endif /* CK_REDIR */
+
+struct tm *
+#ifdef CK_ANSIC
+cmdate2tm(char * date, int gmt) /* date as "yyyymmdd hh:mm:ss" */
+#else
+cmdate2tm(date,gmt) char * date; int gmt;
+#endif
+{
+ /* date as "yyyymmdd hh:mm:ss" */
+ static struct tm _tm;
+ time_t now;
+
+ if (strlen(date) != 17 ||
+ date[8] != ' ' ||
+ date[11] != ':' ||
+ date[14] != ':')
+ return(NULL);
+
+ time(&now);
+ if (gmt)
+ _tm = *gmtime(&now);
+ else
+ _tm = *localtime(&now);
+ _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
+ (date[2]-'0')*10 + (date[3]-'0')-1900;
+ _tm.tm_mon = (date[4]-'0')*10 + (date[5]-'0')-1;
+ _tm.tm_mday = (date[6]-'0')*10 + (date[7]-'0');
+ _tm.tm_hour = (date[9]-'0')*10 + (date[10]-'0');
+ _tm.tm_min = (date[12]-'0')*10 + (date[13]-'0');
+ _tm.tm_sec = (date[15]-'0')*10 + (date[16]-'0');
+
+ /* Should we set _tm.tm_isdst to -1 here? */
+
+ _tm.tm_wday = 0;
+ _tm.tm_yday = 0;
+
+ return(&_tm);
+}
+
+#ifdef OXOS
+#undef kill
+#endif /* OXOS */
+
+#ifdef OXOS
+int
+priv_kill(pid, sig) int pid, sig; {
+ int i;
+
+ if (priv_on())
+ debug(F100,"priv_kill priv_on failed","",0);
+ i = kill(pid, sig);
+ if (priv_off())
+ debug(F100,"priv_kill priv_off failed","",0);
+ return(i);
+}
+#endif /* OXOS */
+
+#ifdef BEOSORBEBOX
+/* #ifdef BE_DR_7 */
+/*
+ alarm() function not supplied with Be OS DR7 - this one contributed by
+ Neal P. Murphy.
+*/
+
+/*
+ This should mimic the UNIX/POSIX alarm() function well enough, with the
+ caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
+ and wait for the alarm thread to finish.
+*/
+unsigned int
+alarm(unsigned int seconds) {
+ long time_left = 0;
+
+/* If an alarm is active, turn it off, saving the unused time */
+ if (alarm_thread != -1) {
+ /* We'll be generous and count partial seconds as whole seconds. */
+ time_left = alarm_struct.time -
+ ((system_time() - time_started) / 1000000.0);
+
+ /* Kill the alarm thread */
+ kill_thread (alarm_thread);
+
+ /* We need to clean up as though the alarm occured. */
+ time_started = 0;
+ alarm_struct.thread = -1;
+ alarm_struct.time = 0;
+ alarm_expired();
+ }
+
+/* Set a new alarm clock, if requested. */
+ if (seconds > 0) {
+ alarm_struct.thread = find_thread(NULL);
+ alarm_struct.time = seconds;
+ time_started = system_time();
+ alarm_thread = spawn_thread (do_alarm,
+ "alarm_thread",
+ B_NORMAL_PRIORITY,
+ (void *) &alarm_struct
+ );
+ resume_thread (alarm_thread);
+ }
+
+/* Now return [unused time | 0] */
+ return ((unsigned int) time_left);
+}
+
+/*
+ This function is the departure from UNIX/POSIX alarm handling. In the case
+ of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
+ handler. When Be implements alarm(), this function call can be eliminated
+ from user's SIGALRM signal handlers.
+*/
+
+void
+alarm_expired(void) {
+ long ret_val;
+
+ if (alarm_thread != -1) {
+ wait_for_thread (alarm_thread, &ret_val);
+ alarm_thread = -1;
+ }
+}
+
+/*
+ This is the function that snoozes the requisite number of seconds and then
+ SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
+ uses thread_id; currently they are both typdef'ed as long, but I'll do the
+ cast anyway. This function is run in a separate thread.
+*/
+
+long
+do_alarm (void *alarm_struct) {
+ snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
+ kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
+ time_started = 0;
+ ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
+ ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
+}
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+
+#ifdef Plan9
+
+int
+p9ttyctl(char letter, int num, int param) {
+ char cmd[20];
+ int len;
+
+ if (ttyctlfd < 0)
+ return -1;
+
+ cmd[0] = letter;
+ if (num)
+ len = sprintf(cmd + 1, "%d", param) + 1;
+ else {
+ cmd[1] = param;
+ len = 2;
+ }
+ if (write(ttyctlfd, cmd, len) == len) {
+ cmd[len] = 0;
+ /* fprintf(stdout, "wrote '%s'\n", cmd); */
+ return 0;
+ }
+ return -1;
+}
+
+int
+p9ttyparity(char l) {
+ return p9ttyctl('p', 0, l);
+}
+
+int
+p9tthflow(int flow, int status) {
+ return p9ttyctl('m', 1, status);
+}
+
+int
+p9ttsspd(int cps) {
+ if (p9ttyctl('b', 1, cps * 10) < 0)
+ return -1;
+ ttylastspeed = cps * 10;
+ return 0;
+}
+
+int
+p9openttyctl(char *ttname) {
+ char name[100];
+
+ if (ttyctlfd >= 0) {
+ close(ttyctlfd);
+ ttyctlfd = -1;
+ ttylastspeed = -1;
+ }
+ sprintf(name, "%sctl", ttname);
+ ttyctlfd = open(name, 1);
+ return ttyctlfd;
+}
+
+int
+p9concb() {
+ if (consctlfd >= 0) {
+ if (write(consctlfd, "rawon", 5) == 5)
+ return 0;
+ }
+ return -1;
+}
+
+int
+p9conbin() {
+ return p9concb();
+}
+
+int
+p9conres() {
+ if (consctlfd >= 0) {
+ if (write(consctlfd, "rawoff", 6) == 6)
+ return 0;
+ }
+ return -1;
+}
+
+int
+p9sndbrk(int msec) {
+ if (ttyctlfd >= 0) {
+ char cmd[20];
+ int i = sprintf(cmd, "k%d", msec);
+ if (write(ttyctlfd, cmd, i) == i)
+ return 0;
+ }
+ return -1;
+}
+
+int
+conwrite(char *buf, int n) {
+ int x;
+ static int length = 0;
+ static int holdingcr = 0;
+ int normal = 0;
+ for (x = 0; x < n; x++) {
+ char c = buf[x];
+ if (c == 007) {
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ normal = 0;
+ }
+ /* write(noisefd, "1000 300", 8); */
+ holdingcr = 0;
+ } else if (c == '\r') {
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ normal = 0;
+ }
+ holdingcr = 1;
+ } else if (c == '\n') {
+ write(1, buf + (x - normal), normal + 1);
+ normal = 0;
+ length = 0;
+ holdingcr = 0;
+ } else if (c == '\b') {
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ normal = 0;
+ }
+ if (length) {
+ write(1, &c, 1);
+ length--;
+ }
+ holdingcr = 0;
+ } else {
+ if (holdingcr) {
+ char b = '\b';
+ while (length-- > 0)
+ write(1, &b, 1);
+ length = 0; /* compiler bug */
+ }
+ holdingcr = 0;
+ normal++;
+ }
+ }
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ }
+ return n;
+}
+
+void
+conprint(char *fmt, ...) {
+ static char buf[1000]; /* not safe if on the stack */
+
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ i = vsprintf(buf, fmt, ap);
+ conwrite(buf, i);
+}
+#endif /* Plan9 */
+
+/* fprintf, printf, perror replacements... */
+
+/* f p r i n t f */
+
+#ifdef UNIX
+#ifdef CK_ANSIC
+#include <stdarg.h>
+#else /* CK_ANSIC */
+#ifdef __GNUC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif /* __GNUC__ */
+#endif /* CK_ANSIC */
+#ifdef fprintf
+#undef fprintf
+static char str1[4096];
+static char str2[4096];
+int
+#ifdef CK_ANSIC
+ckxfprintf(FILE * file, const char * format, ...)
+#else /* CK_ANSIC */
+ckxfprintf(va_alist) va_dcl
+#endif /* CK_ANSIC */
+/* ckxfprintf */ {
+ int i, j, len, got_cr;
+ va_list args;
+ int rc = 0;
+
+#ifdef CK_ANSIC
+ va_start(args, format);
+#else /* CK_ANSIC */
+ char * format;
+ FILE * file;
+ va_start(args);
+ file = va_arg(args,FILE *);
+ format = va_arg(args,char *);
+#endif /* CK_ANSIC */
+
+ if (!inserver || (file != stdout && file != stderr && file != stdin)) {
+ rc = vfprintf(file,format,args);
+ } else {
+ unsigned int c;
+ rc = vsprintf(str1, format, args);
+ len = strlen(str1);
+ if (len >= sizeof(str1)) {
+ debug(F101,"ckxfprintf() buffer overflow","",len);
+ doexit(BAD_EXIT,1);
+ }
+ for (i = 0, j = 0, got_cr = 0;
+ i < len && j < sizeof(str1)-2;
+ i++, j++ ) {
+ /* We can't use 255 as a case label because of signed chars */
+ c = (unsigned)(str1[i] & 0xff);
+#ifdef TNCODE
+ if (c == 255) {
+ if (got_cr && !TELOPT_ME(TELOPT_BINARY))
+ str2[j++] = '\0';
+ str2[j++] = IAC;
+ str2[j] = IAC;
+ got_cr = 0;
+ } else
+#endif /* TNCODE */
+ switch (c) {
+ case '\r':
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 1;
+ break;
+ case '\n':
+ if (!got_cr)
+ str2[j++] = '\r';
+ str2[j] = str1[i];
+ got_cr = 0;
+ break;
+ default:
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 0;
+ }
+ }
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+#ifdef CK_ENCRYPTION
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(str2,j);
+#endif /* TNCODE */
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (inserver && (ssl_active_flag || tls_active_flag)) {
+ /* Write using SSL */
+ char * p = str2;
+ ssl_retry:
+ if (ssl_active_flag)
+ rc = SSL_write(ssl_con, p, j);
+ else
+ rc = SSL_write(tls_con, p, j);
+ debug(F111,"ckxfprintf","SSL_write",rc);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
+ case SSL_ERROR_NONE:
+ if (rc == j)
+ break;
+ p += rc;
+ j -= rc;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_SYSCALL:
+ if (rc != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ rc = 0;
+ }
+ } else
+#endif /* CK_SSL */
+ fwrite(str2,sizeof(char),j,stdout);
+ }
+ va_end(args);
+ return(rc);
+}
+#endif /* fprintf */
+
+/* p r i n t f */
+
+#ifdef printf
+#undef printf
+int
+#ifdef CK_ANSIC
+ckxprintf(const char * format, ...)
+#else /* CK_ANSIC */
+ckxprintf(va_alist) va_dcl
+#endif /* CK_ANSIC */
+/* ckxprintf */ {
+ int i, j, len, got_cr;
+ va_list args;
+ int rc = 0;
+
+#ifdef CK_ANSIC
+ va_start(args, format);
+#else /* CK_ANSIC */
+ char * format;
+ va_start(args);
+ format = va_arg(args,char *);
+#endif /* CK_ANSIC */
+
+ if (!inserver) {
+ rc = vprintf(format, args);
+ } else {
+ unsigned int c;
+ rc = vsprintf(str1, format, args);
+ len = strlen(str1);
+ if (len >= sizeof(str1)) {
+ debug(F101,"ckxprintf() buffer overflow","",len);
+ doexit(BAD_EXIT,1);
+ }
+ for (i = 0, j = 0, got_cr=0;
+ i < len && j < sizeof(str1)-2;
+ i++, j++ ) {
+ c = (unsigned)(str1[i] & 0xff);
+#ifdef TNCODE
+ if (c == 255) {
+ if (got_cr && !TELOPT_ME(TELOPT_BINARY))
+ str2[j++] = '\0';
+ str2[j++] = IAC;
+ str2[j] = IAC;
+ got_cr = 0;
+ } else
+#endif /* TNCODE */
+ switch (c) {
+ case '\r':
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 1;
+ break;
+ case '\n':
+ if (!got_cr)
+ str2[j++] = '\r';
+ str2[j] = str1[i];
+ got_cr = 0;
+ break;
+ default:
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 0;
+ break;
+ }
+ }
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+#ifdef CK_ENCRYPTION
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(str2,j);
+#endif /* TNCODE */
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (inserver && (ssl_active_flag || tls_active_flag)) {
+ char * p = str2;
+ /* Write using SSL */
+ ssl_retry:
+ if (ssl_active_flag)
+ rc = SSL_write(ssl_con, p, j);
+ else
+ rc = SSL_write(tls_con, p, j);
+ debug(F111,"ckxprintf","SSL_write",rc);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
+ case SSL_ERROR_NONE:
+ if (rc == j)
+ break;
+ p += rc;
+ j -= rc;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_SYSCALL:
+ if (rc != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ rc = 0;
+ }
+ } else
+#endif /* CK_SSL */
+ rc = fwrite(str2,sizeof(char),j,stdout);
+ }
+ va_end(args);
+ return(rc);
+}
+#endif /* printf */
+
+/* p e r r o r */
+
+#ifdef perror
+#undef perror
+_PROTOTYP(char * ck_errstr,(VOID));
+#ifdef NEXT
+void
+#else
+#ifdef CK_SCOV5
+void
+#else
+int
+#endif /* CK_SCOV5 */
+#endif /* NEXT */
+#ifdef CK_ANSIC
+ckxperror(const char * str)
+#else /* CK_ANSIC */
+ckxperror(str) char * str;
+#endif /* CK_ANSIC */
+/* ckxperror */ {
+ char * errstr = ck_errstr();
+#ifndef NEXT
+#ifndef CK_SCOV5
+ return
+#endif /* CK_SCOV5 */
+#endif /* NEXT */
+ ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
+}
+#endif /* perror */
+#endif /* UNIX */
+
+#ifdef MINIX2
+
+/* Minix doesn't have a gettimeofday call (but MINIX3 does).
+ * We fake one here using time(2)
+ */
+
+#ifndef MINIX3
+int
+gettimeofday(struct timeval *tp, struct timezone *tzp) {
+ tp->tv_usec = 0L; /* Close enough for horseshoes */
+ if(time(&(tp->tv_sec))==-1)
+ return(-1);
+ return(0);
+}
+#endif /* MINIX3 */
+
+#ifndef MINIX3
+int
+readlink(const char *path, void *buf, size_t bufsiz) {
+ errno = ENOSYS;
+ return(-1);
+}
+#endif /* MINIX3 */
+
+#endif /* MINIX2 */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckutio.c.c99 b/ckermit-9.0.302-build/ckermit-9.0.302/ckutio.c.c99
new file mode 100644
index 0000000..05564de
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckutio.c.c99
@@ -0,0 +1,16050 @@
+#define CKUTIO_C
+
+#ifdef aegis
+char *ckxv = "Aegis Communications support, 9.0.326, 20 August 2011";
+#else
+#ifdef Plan9
+char *ckxv = "Plan 9 Communications support, 9.0.326, 20 August 2011";
+#else
+char *ckxv = "UNIX Communications support, 9.0.326, 20 August 2011";
+#endif /* Plan9 */
+#endif /* aegis */
+
+/* C K U T I O */
+
+/* C-Kermit interrupt, communications control and I/O functions for UNIX */
+
+/*
+ Author: Frank da Cruz (fdc@columbia.edu),
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
+ compatible with C preprocessors that support only #ifdef, #else, #endif,
+ #define, and #undef. Please do not use #if, logical operators, or other
+ preprocessor features in any of the portable C-Kermit modules. You can,
+ of course, use these constructions in platform-specific modules when they
+ are supported by all compilers/preprocessors that could be used on that
+ platform.
+*/
+
+extern int nettype; /* Defined in ckcmai.c */
+extern int duplex;
+
+/* Includes */
+
+#include "ckcsym.h" /* This must go first */
+#include "ckcdeb.h" /* This must go second */
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#ifndef HPUXPRE65
+#include <errno.h> /* Error number symbols */
+#else
+#ifndef ERRNO_INCLUDED
+#include <errno.h> /* Error number symbols */
+#endif /* ERRNO_INCLUDED */
+#endif /* HPUXPRE65 */
+
+#ifdef __386BSD__
+#define ENOTCONN 57
+#else
+#ifdef __bsdi__
+#define ENOTCONN 57
+#else
+#ifdef __FreeBSD__
+#define ENOTCONN 57
+#endif /* __FreeBSD__ */
+#endif /* __bsdi__ */
+#endif /* __386BSD__ */
+
+#ifdef SCO_OSR504
+#define NBBY 8
+#endif /* SCO_OSR504 */
+
+#ifdef Plan9
+#define SELECT
+#include <sys/time.h>
+#include <select.h>
+#define FD_SETSIZE (3 * sizeof(long) * 8)
+static struct timeval tv;
+#endif /* Plan9 */
+
+#ifdef CLIX
+#include <sys/time.h>
+#endif /* CLIX */
+
+#include "ckcnet.h" /* Symbols for network types. */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+/*
+ The directory-related includes are here because we need to test some
+ file-system-related symbols to find out which system we're being compiled
+ under. For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
+*/
+#ifdef SDIRENT /* Directory bits... */
+#define DIRENT
+#endif /* SDIRENT */
+
+#ifdef XNDIR
+#include <sys/ndir.h>
+#else /* !XNDIR */
+#ifdef NDIR
+#include <ndir.h>
+#else /* !NDIR, !XNDIR */
+#ifdef RTU
+#include "/usr/lib/ndir.h"
+#else /* !RTU, !NDIR, !XNDIR */
+#ifdef DIRENT
+#ifdef SDIRENT
+#include <sys/dirent.h>
+#else
+#include <dirent.h>
+#endif /* SDIRENT */
+#else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
+#include <sys/dir.h>
+#endif /* DIRENT */
+#endif /* RTU */
+#endif /* NDIR */
+#endif /* XNDIR */
+
+#ifdef QNX
+#include <sys/dev.h>
+#endif /* QNX */
+
+#ifdef HPUX5
+#ifndef TCPSOCKET
+/* I don't know why this is needed here since we never reference bzero(). */
+/* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
+void
+bzero(s,n) char *s; int n; {
+ extern char * memset();
+ memset(s,0,n);
+}
+#endif /* TCPSOCKET */
+#endif /* HPUX5 */
+
+/* Definition of HZ, used in msleep() */
+
+#ifdef MIPS
+#define HZ ( 1000 / CLOCK_TICK )
+#else /* MIPS */
+#ifdef ATTSV
+#ifndef NAP
+#ifdef TRS16
+#define HZ ( 1000 / CLOCK_TICK )
+#endif /* TRS16 */
+#ifdef NAPHACK
+#define nap(x) (void)syscall(3112, (x))
+#define NAP
+#endif /* NAPHACK */
+#endif /* NAP */
+#endif /* ATTSV */
+#endif /* MIPS */
+
+#ifdef M_UNIX
+#undef NGROUPS_MAX /* Prevent multiple definition warnings */
+#endif /* M_UNIX */
+
+/*
+ NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
+ library routine, so _poll comes up undefined at link time.
+*/
+#ifdef CK_POLL
+#ifndef AIXRS /* IBM AIX needs special handling */
+#include <poll.h> /* "standard" (SVID) i/o multiplexing, etc */
+#else /* AIXRS */
+#ifdef SVR4 /* AIX 3.2 is like SVID... */
+#include <poll.h>
+#else /* But AIX 3.1 is not ... */
+#include <sys/poll.h> /* The include file is in include/sys */
+#define events reqevents /* And it does not map IBM-specific member */
+#define revents rtnevents /* names to the System V equivalents */
+#endif /* SVR4 */
+#endif /* AIXRS */
+#endif /* CK_POLL */
+
+#include <signal.h> /* Signals */
+
+/* For setjmp and longjmp */
+
+#ifndef ZILOG
+#include <setjmp.h>
+#else
+#include <setret.h>
+#endif /* ZILOG */
+
+/*
+ The following test differentiates between 4.1 BSD and 4.2 & later.
+ If you have a 4.1BSD system with the DIRENT library, this test could
+ mistakenly diagnose 4.2BSD and then later enable the use of system calls
+ that aren't defined. If indeed there are such systems, we can use some
+ other way of testing for 4.1BSD, or add yet another compile-time switch.
+*/
+#ifdef BSD4
+#ifdef MAXNAMLEN
+#ifndef FT21 /* Except for Fortune. */
+#ifndef FT18
+#ifndef BELLV10 /* And Bell Labs Research UNIX V10 */
+#define BSD42
+#endif /* BELLV10 */
+#endif /* FT18 */
+#endif /* FT21 */
+#endif /* MAXNAMLEN */
+#endif /* BSD4 */
+
+#ifdef SUNOS41 /* From Christian Corti */
+#define BSD44ORPOSIX /* Uni Stuttgart */
+#define SVORPOSIX /* February 2010 */
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <limits.h>
+#endif /* SUNOS41 */
+
+#ifdef SNI542
+#include <sys/filio.h> /* 299 for FIONREAD */
+#endif /* SNI542 */
+
+/*
+ Minix 2.0 support added by Terry McConnell,
+ Syracuse University <tmc@barnyard.syr.edu>
+ No more sgtty interface, posix compliant.
+*/
+#ifdef MINIX2
+#define _MINIX /* Needed for some Minix header files */
+#define BSD44ORPOSIX
+#define SVORPOSIX
+#ifndef MINIX3
+#define DCLTIMEVAL
+#endif /* MINIX3 */
+#define NOFILEH
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <limits.h>
+#undef TIOCGETC /* defined in sys/ioctl.h, but not really supported */
+#define TANDEM 0
+#endif /* MINIX2 */
+
+/*
+ MINIX 1.0 support added by Charles Hedrick,
+ Rutgers University <hedrick@aramis.rutgers.edu>.
+ MINIX also has V7 enabled.
+*/
+#ifdef MINIX
+#define TANDEM 0
+#define MYREAD
+#define NOSYSIOCTLH
+#include <limits.h>
+#endif /* MINIX */
+
+#ifdef CK_REDIR /* <sys/wait.h> needed only for REDIRECT command. */
+/*
+ If anybody can figure out how to make this work with NeXTSTEP, be
+ my guest! (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
+*/
+#ifndef CK_WAIT_H /* If wait.h not already included... */
+#ifdef OSF /* force OSF to select POSIX wait */
+#ifdef _BSD /* instead of BSD (see ckcdeb.h) */
+#define CK_OSF_BSD
+#undef _BSD
+#endif /* _BSD */
+#endif /* OSF */
+#include <sys/wait.h> /* Include it */
+#ifdef OSF
+#ifdef CK_OSF_BSD
+#define _BSD /* Restore it */
+#undef CK_OSF_BSD
+#endif /* CK_OSF_BSD */
+#endif /* OSF */
+#endif /* CK_WAIT_H */
+#endif /* CK_REDIR */
+
+#include "ckuver.h" /* Version herald */
+char *ckxsys = HERALD;
+
+#ifdef CK_UTSNAME
+#include <sys/utsname.h>
+
+#ifdef TRU64 /* Tru64 UNIX 4.0 and later */
+/* Verified on Tru64 4.0F - might break on 4.0E or earlier */
+#include <sys/sysinfo.h> /* (don't know about OSF/1 or DU) */
+#include <machine/hal_sysinfo.h>
+#endif /* TRU64 */
+
+#ifdef SOLARIS25 /* Solaris 2.5 and later */
+#include <sys/systeminfo.h> /* (don't know about earlier ones) */
+#endif /* SOLARIS25 */
+
+#ifdef UW7
+#ifndef SYS_NMLN
+#define SYS_NMLN 257
+#endif /* NMLN */
+#endif /* UW7 */
+#ifdef HPUX9PLUS
+static int hpis800 = 0;
+#endif /* HPUX9PLUS */
+#ifdef SYS_NMLN
+#define CK_SYSNMLN SYS_NMLN
+#else
+#ifdef _SYS_NMLN
+#define CK_SYSNMLN _SYS_NMLN
+#else
+#ifdef UTSLEN
+#define CK_SYSNMLN UTSLEN
+#else
+#define CK_SYSNMLN 31
+#endif /* UTSLEN */
+#endif /* _SYS_NMLN */
+#endif /* SYS_NMLN */
+char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
+char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
+#endif /* CK_UTSNAME */
+
+#ifdef CIE
+#include <stat.h> /* For chasing symlinks, etc. */
+#else
+#include <sys/stat.h>
+#endif /* CIE */
+
+#ifdef QNX /* 299 */
+#ifndef IXANY
+#define IXANY 0
+#endif /* IXANY */
+#endif /* QNX */
+
+/* UUCP lockfile material... */
+
+#ifndef NOUUCP
+#ifdef USETTYLOCK
+#ifdef HAVE_LOCKDEV /* Red Hat baudboy/lockdev */
+/*
+ Watch out: baudboy.h references open() without making sure it has been
+ declared, resulting in warnings on at least Red Hat 7.3. It's declared in
+ fcntl.h, but we don't include that until later. In this case only, we
+ include it here, and then the second include is harmless because in Red Hat
+ Linux (the only place where you find baudboy.h) fcntl.h is protected from
+ multiple inclusion by _FCNTL_H. - fdc, 10 May 2004.
+
+ NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or
+ setgid bits to access the lockfile, C-Kermit will still need them to access
+ the serial port itself unless the port is open for world read/write.
+ Normally setgid uucp does the trick.
+
+ Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy
+ but ttylock. - jb, 26 Jul 2010
+*/
+#include <fcntl.h> /* This has to come before baudboy */
+#ifdef HAVE_BAUDBOY /* Red Hat baudboy/lockdev */
+#include <baudboy.h>
+#else /* !HAVE_BAUDBOY */ /* openSuSE lock via ttylock */
+#include <ttylock.h>
+#endif /* HAVE_BAUDBOY */
+#define LOCK_DIR "/var/lock" /* (even though we don't care) */
+
+#else /* !HAVE_LOCKDEV */
+
+#ifdef USE_UU_LOCK
+#ifdef __FreeBSD__
+#include <libutil.h> /* FreeBSD */
+#else
+#include <util.h> /* OpenBSD */
+#endif /* HAVE_LOCKDEV */
+#endif /* __FreeBSD */
+#endif /* USE_UU_LOCK */
+#else /* USETTYLOCK */
+
+/* Name of UUCP tty device lockfile */
+
+#ifdef LINUXFSSTND
+#ifndef HDBUUCP
+#define HDBUUCP
+#endif /* HDBUUCP */
+#endif /* LINUXFSSTND */
+
+#ifdef ACUCNTRL
+#define LCKDIR
+#endif /* ACUCNTRL */
+
+/*
+ PIDSTRING means use ASCII string to represent pid in lockfile.
+*/
+#ifndef PIDSTRING
+#ifdef HDBUUCP
+#define PIDSTRING
+#else
+#ifdef BSD44
+#define PIDSTRING
+#else
+#ifdef RTAIX
+#define PIDSTRING
+#else
+#ifdef AIXRS
+#define PIDSTRING
+#else
+#ifdef COHERENT
+#define PIDSTRING
+#endif /* COHERENT */
+#endif /* AIXRS */
+#endif /* RTAIX */
+#endif /* BSD44 */
+#endif /* HDBUUCP */
+#endif /* PIDSTRING */
+
+/* Now the PIDSTRING exceptions... */
+
+#ifdef PIDSTRING
+#ifdef HPUX
+#undef PIDSTRING
+#endif /* HPUX */
+#endif /* PIDSTRING */
+
+#ifdef __bsdi__ /* BSDI (at least thru 1.1) */
+#ifdef PIDSTRING
+#undef PIDSTRING
+#endif /* PIDSTRING */
+#endif /* __bsdi__ */
+
+#ifdef OSF32 /* Digital UNIX (OSF/1) 3.2 */
+#ifdef PIDSTRING
+#undef PIDSTRING
+#endif /* PIDSTRING */
+#endif /* OSF32 */
+
+/*
+ LOCK_DIR is the name of the lockfile directory.
+ If LOCK_DIR is already defined (e.g. on command line), we don't change it.
+*/
+
+#ifndef LOCK_DIR
+#ifdef MACOSX
+#define LOCK_DIR "/var/spool/lock"
+#endif /* MACOSX */
+#endif/* LOCK_DIR */
+
+#ifndef LOCK_DIR
+#ifdef BSD44
+#ifdef __386BSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+#ifdef __FreeBSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+#ifdef __NetBSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+#ifdef __OpenBSD__
+#define LOCK_DIR "/var/spool/lock"
+#else
+/* So which ones is this for? */
+/* Probably original 4.4BSD on Vangogh */
+/* Plus who knows about Mac OS X... It doesn't even have a cu program */
+#define LOCK_DIR "/var/spool/uucp"
+#endif /* __OpenBSD__ */
+#endif /* __NetBSD__ */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#else
+#ifdef DGUX430
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef HPUX10
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef RTAIX /* IBM RT PC AIX 2.2.1 */
+#define LOCK_DIR "/etc/locks"
+#else
+#ifdef AIXRS
+#define LOCK_DIR "/etc/locks"
+#else
+#ifdef ISIII
+#define LOCK_DIR "/etc/locks"
+#else
+#ifdef HDBUUCP
+#ifdef M_SYS5
+#define LOCK_DIR "/usr/spool/uucp"
+#else
+#ifdef M_UNIX
+#define LOCK_DIR "/usr/spool/uucp"
+#else
+#ifdef SVR4
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef SUNOS4
+#define LOCK_DIR "/var/spool/locks"
+#else
+#ifdef LINUXFSSTND
+#define LOCK_DIR "/var/lock";
+#else
+#define LOCK_DIR "/usr/spool/locks"
+#endif /* LINUXFSSTND */
+#endif /* SUNOS4 */
+#endif /* SVR4 */
+#endif /* M_UNIX */
+#endif /* M_SYS5 */
+#else
+#ifdef LCKDIR
+#define LOCK_DIR "/usr/spool/uucp/LCK"
+#else
+#ifdef COHERENT
+#define LOCK_DIR "/usr/spool/uucp"
+#else
+#define LOCK_DIR "/usr/spool/uucp"
+#endif /* COHERENT */
+#endif /* LCKDIR */
+#endif /* HDBUUCP */
+#endif /* ISIII */
+#endif /* AIXRS */
+#endif /* RTAIX */
+#endif /* HPUX10 */
+#endif /* DGUX430 */
+#endif /* BSD44 */
+#endif /* !LOCK_DIR (outside ifndef) */
+
+#ifdef OSF2 /* OSF/1 2.0 or later */
+#ifdef LOCK_DIR /* (maybe 1.x too, who knows...) */
+#undef LOCK_DIR
+#define LOCK_DIR "/var/spool/locks"
+#endif /* LOCK_DIR */
+#endif /* OSF2 */
+
+#ifdef COMMENT
+/* Sorry no more lockf() -- we lock first and THEN open the device. */
+#ifdef SVR4
+#ifndef BSD44
+#ifndef LOCKF
+#define LOCKF /* Use lockf() on tty device in SVR4 */
+#endif /* LOCKF */
+#endif /* BSD44 */
+#endif /* SVR4 */
+#endif /* COMMENT */
+
+#ifdef NOLOCKF /* But NOLOCKF cancels LOCKF */
+#ifdef LOCKF
+#undef LOCKF
+#endif /* LOCKF */
+#endif /* NOLOCKF */
+
+/* More about this below... */
+
+#endif /* USETTYLOCK */
+#endif /* NOUUCP */
+
+/*
+ MYREAD means use our internally defined nonblocking buffered read routine.
+*/
+#ifdef ATTSV
+#define MYREAD
+#endif /* ATTSV */
+
+#ifdef ATT7300
+#ifndef MYREAD
+#define MYREAD
+#endif /* MYREAD */
+/* bits for attmodem: internal modem in use, restart getty */
+#define ISMODEM 1
+#define DOGETY 512
+#endif /* ATT7300 */
+
+#ifdef BSD42
+#define MYREAD
+#endif /* BSD42 */
+
+#ifdef POSIX
+#define MYREAD
+#endif /* POSIX */
+#ifdef __bsdi__
+#ifndef O_NDELAY
+#define O_NDELAY O_NONBLOCK
+#endif /* O_NDELAY */
+#endif /* __bsdi__ */
+
+/*
+ Variables available to outside world:
+
+ dftty -- Pointer to default tty name string, like "/dev/tty".
+ dfloc -- 0 if dftty is console, 1 if external line.
+ dfprty -- Default parity
+ dfflow -- Default flow control
+ ckxech -- Flag for who echoes console typein:
+ 1 - The program (system echo is turned off)
+ 0 - The system (or front end, or terminal).
+ functions that want to do their own echoing should check this flag
+ before doing so.
+
+ flfnam -- Name of lock file, including its path, e.g.,
+ "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
+ lkflfn -- Name of link to lock file, including its paths
+ haslock -- Flag set if this kermit established a uucp lock.
+ lockpid -- PID of other process that has desired line open, as string.
+ backgrd -- Flag indicating program executing in background ( & on
+ end of shell command). Used to ignore INT and QUIT signals.
+ rtu_bug -- Set by stptrap(). RTU treats ^Z as EOF (but only when we handle
+ SIGTSTP)
+
+ Functions for assigned communication line (either external or console tty):
+
+ sysinit() -- System dependent program initialization
+ syscleanup() -- System dependent program shutdown
+ ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
+ ttclos() -- Close & reset the tty, releasing any access lock.
+ ttsspd(cps) -- Set the transmission speed of the tty.
+ ttgspd() -- Get (read) the the transmission speed of the tty.
+ ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
+ ttvt(speed,flow) -- Put the tty in virtual terminal mode.
+ or in DIALING or CONNECTED modem control state.
+ ttres() -- Restore original tty modes.
+ ttscarr(carrier) -- Set carrier control mode, on/off/auto.
+ ttinl(dest,max,timo) -- Timed read line from the tty.
+ ttinc(timo) -- Timed read character from tty.
+ myread() -- Raw mode bulk buffer read, gives subsequent
+ chars one at a time and simulates FIONREAD.
+ myunrd(c) -- Places c back in buffer to be read (one only)
+ ttchk() -- See how many characters in tty input buffer.
+ ttxin(n,buf) -- Read n characters from tty (untimed).
+ ttol(string,length) -- Write a string to the tty.
+ ttoc(c) -- Write a character to the tty.
+ ttflui() -- Flush tty input buffer.
+ ttsndb() -- Send BREAK signal.
+ ttsndlb() -- Send Long BREAK signal.
+
+ ttlock(ttname) -- "Lock" tty device against uucp collisions.
+ ttunlck() -- Unlock tty device.
+
+ For ATT7300/Unix PC, System V:
+ attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
+ offgetty(ttname) -- Turns off getty(1m) for comms line
+ ongetty(ttname) -- Restores getty() to comms line
+*/
+
+/*
+Functions for console terminal:
+
+ congm() -- Get console terminal modes.
+ concb(esc) -- Put the console in single-character wakeup mode with no echo.
+ conbin(esc) -- Put the console in binary (raw) mode.
+ conres() -- Restore the console to mode obtained by congm().
+ conoc(c) -- Unbuffered output, one character to console.
+ conol(s) -- Unbuffered output, null-terminated string to the console.
+ conola(s) -- Unbuffered output, array of strings to the console.
+ conxo(n,s) -- Unbuffered output, n characters to the console.
+ conchk() -- Check if characters available at console (bsd 4.2).
+ Check if escape char (^\) typed at console (System III/V).
+ coninc(timo) -- Timed get a character from the console.
+ congks(timo) -- Timed get keyboard scan code.
+ conint() -- Enable terminal interrupts on the console if not background.
+ connoi() -- Disable terminal interrupts on the console if not background.
+
+Time functions
+
+ msleep(m) -- Millisecond sleep
+ ztime(&s) -- Return pointer to date/time string
+ rtimer() -- Reset timer
+ gtimer() -- Get elapsed time since last call to rtimer()
+*/
+
+/* Conditional Includes */
+
+/* Whether to include <sys/file.h> */
+
+#ifdef RTU /* RTU doesn't */
+#define NOFILEH
+#endif /* RTU */
+
+#ifdef CIE /* CIE does. */
+#undef NOFILEH
+#endif /* CIE */
+
+#ifdef BSD41 /* 4.1 BSD doesn't */
+#define NOFILEH
+#endif /* BSD41 */
+
+#ifdef is68k /* Integrated Solutions 68000 UNIX */
+#define NOFILEH /* e.g. on Plexux P60 and Sun-1 */
+#endif /* is68k */
+
+#ifdef MINIX /* MINIX */
+#define NOFILEH
+#endif /* MINIX */
+
+#ifdef COHERENT /* Coherent */
+#define NOFILEH
+#endif /* COHERENT */
+
+#ifndef NOFILEH /* Now include if selected. */
+#include <sys/file.h>
+#endif /* NOFILEH */
+
+/* POSIX */
+
+#ifdef BSD44ORPOSIX /* POSIX uses termios.h */
+#define TERMIOS
+#ifdef __bsdi__
+#ifdef POSIX
+#undef _POSIX_SOURCE /* Get extra stuff from termios.h */
+#endif /* POSIX */
+#endif /* __bsdi__ */
+#include <termios.h>
+#ifdef LINUX
+#include <sys/ioctl.h>
+#endif /* LINUX */
+#ifdef QNX16
+#include <ioctl.h>
+#else
+#ifdef QNX6
+#include <ioctl.h>
+#endif /* QNX6 */
+#endif /* QNX16 */
+#ifdef __bsdi__
+#ifdef POSIX
+#define _POSIX_SOURCE
+#endif /* POSIX */
+#endif /* __bsdi__ */
+#ifndef BSD44 /* Really POSIX */
+#ifndef CK_QNX32 /* was CK_QNX32 */
+#define NOSYSIOCTLH /* No ioctl's allowed. */
+#undef ultrix /* Turn off any ultrix features. */
+#endif /* CK_QNX32 */
+#endif /* BSD44 */
+#endif /* POSIX */
+
+/* System III, System V */
+
+#ifdef ATTSV
+#ifndef BSD44
+#ifndef POSIX
+#include <termio.h>
+#endif /* POSIX */
+#endif /* BSD44 */
+#ifdef TERMIOX
+/* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
+#include <termiox.h>
+ struct termiox rctsx;
+#else
+#ifdef STERMIOX
+#ifdef SCO_OSR504
+/* Sorry, this is truly disgusting but it's SCO's fault. */
+#ifndef _SVID3
+#define _CK_SVID3_X
+#define _SVID3
+#endif /* _SVID3 */
+#endif /* SCO_OSR504 */
+#include <sys/termiox.h>
+ struct termiox rctsx;
+#ifdef CK_SVID3_X
+#undef _SVID3
+#undef CK_SVID3_X
+#endif /* CK_SVID3_X */
+#endif /* STERMIOX */
+#endif /* TERMIOX */
+#endif /* ATTSV */
+
+#ifdef COHERENT /* Use termio.h, not sgtty.h for Coherent */
+#include <termio.h>
+#endif /* COHERENT */
+
+#ifdef MINIX /* MINIX uses ioctl's */
+#define NOSYSIOCTLH /* but has no <sys/ioctl.h> */
+#endif /* MINIX */
+
+/* Others */
+
+#ifndef NOSYSIOCTLH /* Others use ioctl() */
+#ifdef SUN4S5
+/*
+ This is to get rid of cpp warning messages that occur because all of
+ these symbols are defined by both termios.h and ioctl.h on the SUN.
+*/
+#undef ECHO
+#undef NL0
+#undef NL1
+#undef TAB0
+#undef TAB1
+#undef TAB2
+#undef XTABS
+#undef CR0
+#undef CR1
+#undef CR2
+#undef CR3
+#undef FF0
+#undef FF1
+#undef BS0
+#undef BS1
+#undef TOSTOP
+#undef FLUSHO
+#undef PENDIN
+#undef NOFLSH
+#endif /* SUN4S5 */
+#include <sys/ioctl.h>
+#endif /* NOSYSIOCTLH */
+/*
+ We really, really, REALLY want FIONREAD, because it is the only way to find
+ out not just *if* stuff is waiting to be read, but how much, which is
+ critical to our sliding-window and streaming procedures, not to mention
+ efficiency of CONNECT, etc.
+*/
+#ifdef BELLV10
+#include <sys/filio.h> /* For FIONREAD */
+#ifdef FIONREAD
+#define MYREAD
+#endif /* MYREAD */
+#endif /* BELLV10 */
+
+#ifndef FIONREAD
+/* It wasn't found in ioctl.h or term*.h - try these places: */
+#ifdef UNIXWARE
+#include <sys/filio.h>
+#else
+#ifdef SOLARIS
+#include <sys/filio.h>
+#endif /* SOLARIS */
+#endif /* UNIXWARE */
+#endif /* FIONREAD */
+
+#ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
+/*
+ <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
+ something. Due to this, in_chk() uses the FIONREAD instead of RDCHK
+ and the hot keys during file transfer (X to cancel file etc) do not
+ work because FIONREAD doesn't work even though it is defined.
+
+ NOTE: This might also be true elsewhere.
+*/
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+#endif /* XENIX */
+
+#ifdef CK_SCOV5 /* Ditto for SCO OpenServer 5.0 */
+#ifndef SCO_OSR507 /* 299 */
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+#endif /* SCO_OSR507 */
+#endif /* CK_SCOV5 */
+
+#ifdef SCO_OSR507 /* 299 */
+#ifdef RDCHK
+#undef RDCHK
+#endif /* RDCHK */
+#endif /* SCO_OSR507 */
+
+/* Whether to include <fcntl.h> */
+
+#ifndef is68k /* Only a few don't have this one. */
+#ifndef BSD41
+#ifndef FT21
+#ifndef FT18
+#ifndef COHERENT
+#include <fcntl.h>
+#endif /* COHERENT */
+#endif /* FT18 */
+#endif /* FT21 */
+#endif /* BSD41 */
+#endif /* not is68k */
+
+#ifdef COHERENT
+#ifdef _I386
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#endif /* _I386 */
+#endif /* COHERENT */
+
+#ifdef ATT7300 /* Unix PC, internal modem dialer */
+#include <sys/phone.h>
+#endif /* ATT7300 */
+
+#ifdef HPUX /* HP-UX variations. */
+#define HPUXJOBCTL
+#include <sys/modem.h> /* HP-UX modem signals */
+#ifdef hp9000s500 /* Model 500 */
+#undef HPUXJOBCTL
+#endif /* hp9000s500 */
+#ifdef HPUXPRE65
+#undef HPUXJOBCTL
+typedef long mflag;
+#endif /* HPUXPRE65 */
+#ifdef HPUXJOBCTL
+#include <sys/bsdtty.h> /* HP-UX Berkeley tty support */
+#endif /* HPUXJOBCTL */
+#endif /* HPUX */
+
+/*
+ Which time.h files to include... See ckcdeb.h for defaults.
+ Note that 0, 1, 2, or all 3 of these can be included according to
+ the symbol definitions.
+*/
+#ifndef NOTIMEH
+#ifdef TIMEH
+#include <time.h>
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+
+#ifndef NODCLTIMEVAL
+#ifdef DCLTIMEVAL
+/*
+ In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
+ define the structs we need to access the higher speeds, so we have to
+ do it ourselves.
+*/
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif /* DCLTIMEVAL */
+#endif /* NODCLTIMEVAL */
+
+#ifdef __linux__
+/* THIS IS OBSOLETE since about Linux 0.92 */
+#ifdef OLINUXHISPEED
+#include <linux/serial.h>
+#endif /* OLINUXHISPEED */
+#ifdef __alpha__ /* Linux on DEC Alpha */
+#ifndef __GLIBC__ /* But not with glibc */
+#include <asm/termios.h>
+#endif /* __GLIBC__ */
+#endif /* __alpha__ */
+#endif /* __linux__ */
+
+#ifdef NOIEXTEN /* This is broken on some systems */
+#undef IEXTEN /* like Convex/OS 9.1 */
+#endif /* NOIEXTEN */
+#ifndef IEXTEN /* Turn off ^O/^V processing. */
+#define IEXTEN 0 /* Needed, at least, on BSDI. */
+#endif /* IEXTEN */
+/*
+ Pick up definitions needed for select() if we don't have them already.
+ Normally they come from <sys/types.h> but some systems get them from
+ <sys/select.h>... Rather than hardwire all of them into the source, we
+ include it if SELECT_H is defined in compile-time CFLAGS.
+*/
+#ifndef SCO_OSR504
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* SCO_OSR504 */
+
+#ifdef aegis
+#include "/sys/ins/base.ins.c"
+#include "/sys/ins/error.ins.c"
+#include "/sys/ins/ios.ins.c"
+#include "/sys/ins/sio.ins.c"
+#include "/sys/ins/pad.ins.c"
+#include "/sys/ins/time.ins.c"
+#include "/sys/ins/pfm.ins.c"
+#include "/sys/ins/pgm.ins.c"
+#include "/sys/ins/ec2.ins.c"
+#include "/sys/ins/type_uids.ins.c"
+#include <default_acl.h>
+#undef TIOCEXCL
+#undef FIONREAD
+#endif /* aegis */
+
+#ifdef sxaE50 /* PFU Compact A SX/A TISP V10/L50 */
+#undef FIONREAD
+#endif /* sxaE50 */
+
+/* The following #defines are catch-alls for those systems */
+/* that didn't have or couldn't find <file.h>... */
+
+#ifndef FREAD
+#define FREAD 0x01
+#endif /* FREAD */
+
+#ifndef FWRITE
+#define FWRITE 0x10
+#endif /* FWRITE */
+
+#ifndef O_RDONLY
+#define O_RDONLY 000
+#endif /* O_RDONLY */
+
+/* This is for ancient Unixes that don't have these tty symbols defined. */
+
+#ifndef PENDIN
+#define PENDIN ICANON
+#endif /* PENDIN */
+#ifndef FLUSHO
+#define FLUSHO ICANON
+#endif /* FLUSHO */
+#ifndef EXTPROC
+#define EXTPROC ICANON
+#endif /* EXTPROC */
+
+#ifdef SVORPOSIX
+/*
+ Modem signals are also forbidden in the POSIX world. But some POSIX-based
+ platforms let us at them anyway if we know where to look.
+*/
+#ifndef NEEDMDMDEFS
+/* Doesn't work for Linux */
+#ifdef UNIXWARE7
+#define NEEDMDMDEFS
+#endif /* UNIXWARE7 */
+#endif /* NEEDMDMDEFS */
+
+#ifdef NEEDMDMDEFS
+#ifndef TIOCMGET
+#define TIOCMGET (('t'<<8)|29)
+#endif /* TIOCMGET */
+
+#ifndef TIOCM_DTR
+#define TIOCM_DTR 0x0002
+#endif /* TIOCM_DTR */
+#ifndef TIOCM_RTS
+#define TIOCM_RTS 0x0004
+#endif /* TIOCM_RTS */
+#ifndef TIOCM_CTS
+#define TIOCM_CTS 0x0020
+#endif /* TIOCM_CTS */
+#ifndef TIOCM_CAR
+#define TIOCM_CAR 0x0040
+#endif /* TIOCM_CAR */
+#ifndef TIOCM_RNG
+#define TIOCM_RNG 0x0080
+#endif /* TIOCM_RNG */
+#ifndef TIOCM_DSR
+#define TIOCM_DSR 0x0100
+#endif /* TIOCM_DSR */
+#endif /* NEEDMDMDEFS */
+#endif /* SVORPOSIX */
+
+/* Declarations */
+
+#ifdef OXOS
+#undef TCGETA
+#undef TCSETA
+#undef TCSETAW
+#undef TCSETAF
+#define TCGETA TCGETS
+#define TCSETA TCSETS
+#define TCSETAW TCSETSW
+#define TCSETAF TCSETSF
+#define termio termios
+#endif /* OXOS */
+
+#ifdef SVORPOSIX /* AT&T Sys V or POSIX */
+#ifdef UNIXWAREPOSIX /* UnixWare 7 POSIX build */
+/*
+ In Unixware POSIX builds, <[sys/]time.h> refuses to define the
+ structs we need to access the higher speeds, so we have to do it
+ ourselves.
+*/
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif /* UNIXWAREPOSIX */
+#endif /* SVORPOSIX */
+
+#ifdef __GNUC__
+#ifdef XENIX
+/*
+ Because Xenix <time.h> doesn't declare time() if we're using gcc.
+*/
+time_t time();
+#endif /* XENIX */
+#endif /* __GNUC__ */
+
+/* Special stuff for V7 input buffer peeking */
+
+#ifdef V7
+int kmem[2] = { -1, -1};
+char *initrawq(), *qaddr[2]={0,0};
+#define CON 0
+#define TTY 1
+#endif /* V7 */
+
+/* dftty is the device name of the default device for file transfer */
+/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
+
+#ifdef BEOS
+ char * dftty = NULL;
+ char * dfmdm = "none";
+ int dfloc = 0; /* that goes in local mode by default */
+#else
+#ifndef DFTTY
+#ifdef PROVX1
+ char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
+ char *dfmdm = "none";
+ int dfloc = 1; /* that goes in local mode by default */
+#else
+ char *dftty = CTTNAM; /* Remote by default, use normal */
+ char *dfmdm = "none";
+ int dfloc = 0; /* controlling terminal name. */
+#endif /* PROVX1 */
+#else
+ char *dftty = DFTTY; /* Default location specified on */
+ char *dfmdm = "none"; /* command line. */
+ int dfloc = 1; /* controlling terminal name. */
+#endif /* DFTTY */
+#endif /* BEOS */
+
+#define CON_RES 0 /* Console state is "reset" */
+#define CON_CB 1 /* Console state is CBREAK */
+#define CON_BIN 2 /* Console state is binary */
+ static int constate = CON_RES;
+
+#define CONI_RES 0 /* Console interrupts are "reset" */
+#define CONI_INT 1 /* Console intterupts are set */
+#define CONI_NOI 2 /* Console intterupts are disabled */
+ static int conistate = CONI_RES;
+
+#ifdef CK_SMALL
+#define CONBUFSIZ 15
+#else
+#define CONBUFSIZ 255
+#endif /* CK_SMALL */
+ static char conbuf[CONBUFSIZ]; /* Console readahead buffer */
+ static int conbufn = 0; /* Chars in readahead buffer */
+ static char *conbufp = conbuf; /* Next char in readahead buffer */
+
+ char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
+
+#ifdef RTU
+ int rtu_bug = 0; /* set to 1 when returning from SIGTSTP */
+#endif /* RTU */
+
+ int dfprty = DEFPAR; /* Default parity (0 = none) */
+ int ttprty = 0; /* The parity that is in use. */
+ static int ttpmsk = 0xff; /* Parity stripping mask. */
+ int ttmdm = 0; /* Modem in use. */
+ int ttcarr = CAR_AUT; /* Carrier handling mode. */
+ int dfflow = FLO_NONE; /* Default flow control is NONE */
+ int backgrd = 0; /* Assume in foreground (no '&' ) */
+#ifdef F_SETFL
+ int iniflags = -1; /* fcntl flags for ttyfd */
+#endif /* F_SETFL */
+ int fdflag = 0; /* Flag for redirected stdio */
+ int ttfdflg = 0; /* Open File descriptor was given */
+ int tvtflg = 0; /* Flag that ttvt has been called */
+ long ttspeed = -1L; /* For saving speed */
+ int ttflow = -9; /* For saving flow */
+ int ttld = -1; /* Line discipline */
+
+#ifdef sony_news
+ static int km_con = -1; /* Kanji mode for console tty */
+ static int km_ext = -1; /* Kanji mode for external device */
+#endif /* sony_news */
+
+#ifdef PARSENSE
+ static int needpchk = 1; /* Need parity check */
+#else
+ static int needpchk = 0;
+#endif /* PARSENSE */
+
+ extern int stopbits; /* Stop bits */
+#ifdef HWPARITY
+/*
+ Unfortunately we must do this with global variables rather than through the
+ tt...() APIs to avoid changing the APIs and the many modules that use them.
+ If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
+ bits + parity or 8 data bits and no parity, and overrides the regular parity
+ variable, which is communicated to this module thru ttpkt(), and represented
+ locally by the ttprty variable.
+*/
+ extern int hwparity; /* Hardware parity */
+#endif /* HWPARITY */
+
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+static int nodelay_sav = -1;
+#endif /* TCP_NODELAY */
+#endif /* TCPSOCKET */
+
+static int sigint_ign = 0; /* SIGINT is ignored */
+
+/*
+ Having this module rely on external globals is bad, but fixing this
+ requires overhaul of the ck*tio.c modules for all the different operating
+ systems supported by C-Kermit. Left for a future release.
+*/
+extern int ttnproto; /* Defined in ckcnet.c */
+extern int ttnet; /* Defined in ckcnet.c */
+extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
+extern int xsuspend, wasclosed;
+extern int inserver, local;
+
+int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
+
+int ckmaxfiles = 0; /* Max number of open files */
+
+#ifdef CK_ENCRYPTION /* Kerberos */
+#include "ckuath.h"
+extern int me_encrypt, u_encrypt;
+#endif /* CK_ENCRYPTION */
+
+/* Declarations of variables global within this module */
+
+#ifdef TTLEBUF /* See ckcnet.h */
+int ttpush = -1;
+#define LEBUFSIZ 4096
+static CHAR le_buf[LEBUFSIZ];
+static int le_start = 0, le_end = 0, le_data = 0;
+#endif /* TTLEBUF */
+
+#define MSGBUF_SIZE 1024 /* For debugging */
+static char msgbuf[MSGBUF_SIZE];
+
+static int gotsigs = 0;
+
+static time_t tcount = (time_t)0; /* Elapsed time counter */
+
+static SIGTYP (*saval)() = NULL; /* For saving alarm() handler */
+static SIGTYP (*savquit)() = NULL; /* and other signal handlers */
+#ifdef SIGUSR1
+static SIGTYP (*savusr1)() = NULL;
+#endif /* SIGUSR1 */
+#ifdef SIGUSR2
+static SIGTYP (*savusr2)() = NULL;
+#endif /* SIGUSR2 */
+#ifdef SIGPIPE
+static SIGTYP (*savpipe)() = NULL;
+#endif /* SIGPIPE */
+#ifdef SIGDANGER
+static SIGTYP (*savdanger)() = NULL;
+#endif /* SIGDANGER */
+
+#ifndef NOJC
+static SIGTYP (*jchdlr)() = NULL; /* For checking suspend handler */
+#endif /* NOJC */
+static int jcshell = -1; /* And flag for result */
+
+/*
+ BREAKNULS is defined for systems that simulate sending a BREAK signal
+ by sending a bunch of NUL characters at low speed.
+*/
+#ifdef PROVX1
+#ifndef BREAKNULS
+#define BREAKNULS
+#endif /* BREAKNULS */
+#endif /* PROVX1 */
+
+#ifdef V7
+#ifndef BREAKNULS
+#define BREAKNULS
+#endif /* BREAKNULS */
+#endif /* V7 */
+
+#ifdef BREAKNULS
+static char /* A string of nulls */
+*brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+#endif /* BREAKNULS */
+
+#ifdef CK_POSIX_SIG /* Longjump buffers */
+static sigjmp_buf sjbuf; /* POSIX signal handling */
+#else
+static jmp_buf sjbuf;
+#endif /* CK_POSIX_SIG */
+
+#ifdef V7
+static jmp_buf jjbuf;
+#endif /* V7 */
+
+/* static */ /* (Not static any more) */
+int ttyfd = -1; /* TTY file descriptor */
+
+int ttpipe = 0; /* NETCMD: Use pipe instead of ttyfd */
+int ttpty = 0; /* NETPTY: Use pty instead of ttfyd */
+
+#ifdef NETPTY /* These are in ckupty.c */
+extern PID_T pty_fork_pid;
+extern int pty_master_fd, pty_slave_fd;
+#endif /* NETPTY */
+
+#ifdef NETCMD
+#ifdef NETCONN
+static int pipe0[2], pipe1[2]; /* Pipes for net i/o */
+#endif /* NETCONN */
+static PID_T ttpid = 0; /* Process ID for fork */
+static int fdin, fdout; /* File descriptors for pipe */
+static FILE * ttout = NULL; /* File pointer for output pipe */
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+#endif /* NETCMD */
+
+extern int pexitstat, quiet;
+
+#ifdef Plan9
+int ttyctlfd = -1; /* TTY control channel - What? UNIX doesn't have one? */
+int consctlfd = -1; /* Console control channel */
+int noisefd = -1; /* tone channel */
+static int ttylastspeed = -1; /* So we can lie about the speed */
+#endif /* Plan9 */
+
+int telnetfd = 0; /* File descriptor is for telnet */
+#ifdef NETCONN
+int x25fd = 0; /* File descriptor is for X.25 */
+#endif /* NETCONN */
+
+char lockpid[16] = { '\0', '\0' }; /* PID stored in lockfile, as string */
+
+static int lkf = 0, /* Line lock flag */
+ cgmf = 0, /* Flag that console modes saved */
+ xlocal = 0, /* Flag for tty local or remote */
+ curcarr = 0; /* Carrier mode: require/ignore. */
+
+static int netconn = 0; /* 1 if network connection active */
+
+static char escchr; /* Escape or attn character */
+
+#ifdef CK_SCO32V4
+#include <sys/time.h>
+#endif /* CK_SCO32V4 */
+
+#ifdef HAVE_TV
+ static struct timeval tv; /* For getting time, from sys/time.h */
+#endif /* HAVE_TV */
+#ifdef HAVE_TZ
+ static struct timezone tz;
+#endif /* HAVE_TZ */
+
+#ifdef OSF
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* OSF */
+
+#ifdef BSD29
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* BSD29 */
+
+#ifdef BSD41
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* BSD41 */
+
+#ifdef BELLV10
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* BELLV10 */
+
+#ifdef FT21
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* FT21 */
+
+#ifdef TOWER1
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* TOWER1 */
+
+#ifdef COHERENT
+ static long xclock; /* For getting time from sys/time.h */
+ static struct timeb ftp; /* And from sys/timeb.h */
+#endif /* COHERENT */
+
+#ifdef V7
+ static long xclock;
+#endif /* V7 */
+
+/* sgtty/termio information... */
+
+#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
+ static struct termios
+ ttold, ttraw, tttvt, ttcur,
+ ccold, ccraw, cccbrk;
+#else /* BSD, V7, etc */
+
+#ifdef COHERENT /* Hack alert... */
+#define ATTSV
+#endif /* COHERENT */
+
+#ifdef ATTSV
+ static struct termio ttold = {0}; /* Init'd for word alignment, */
+ static struct termio ttraw = {0}; /* which is important for some */
+ static struct termio tttvt = {0}; /* systems, like Zilog... */
+ static struct termio ttcur = {0};
+ static struct termio ccold = {0};
+ static struct termio ccraw = {0};
+ static struct termio cccbrk = {0};
+#else
+ static struct sgttyb /* sgtty info... */
+ ttold, ttraw, tttvt, ttcur, /* for communication line */
+ ccold, ccraw, cccbrk; /* and for console */
+#ifdef BELLV10
+ static struct ttydevb /* Device info... */
+ tdold, tdcur; /* for communication device */
+#endif /* BELLV10 */
+#ifdef TIOCGETC
+ static struct tchars tchold, tchnoi;
+
+ static int tcharf;
+#endif /* TIOCGETC */
+#ifdef TIOCGLTC
+ static struct ltchars ltchold, ltchnoi;
+ static int ltcharf;
+#endif /* TIOCGLTC */
+ int lmodef = 0; /* Local modes */
+ int lmode = 0;
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+#ifdef COMMENT
+/* It picks up the speeds but they don't work */
+#ifdef UNIXWARE /* For higher serial speeds */
+#ifdef UW7 /* in Unixware 7.0 */
+#include <sys/asyc.h> /* This picks up 57600 and 115200 */
+#endif /* UW7 */
+#endif /* UNIXWARE */
+#endif /* COMMENT */
+
+#ifdef PROVX1
+ static struct sgttyb ttbuf;
+#endif /* PROVX1 */
+
+#ifdef ultrix
+/* do we really need this? */
+ static struct sgttyb vanilla;
+#endif /* ultrix */
+
+#ifdef ATT7300
+static int attmodem = 0; /* ATT7300 internal-modem status */
+struct updata dialer = {0}; /* Condition dialer for data call */
+#endif /* ATT7300 */
+
+#ifndef NOUUCP
+#define FLFNAML 128
+#ifndef USETTYLOCK
+#ifdef RTAIX
+char lkflfn[FLFNAML] = { '\0', '\0' }; /* and possible link to it */
+#endif /* RTAIX */
+char lock2[FLFNAML] = { '\0', '\0' }; /* Name of second lockfile */
+#endif /* USETTYLOCK */
+#else
+#define FLFNAML 7
+#endif /* NOUUCP */
+char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
+
+int haslock = 0; /* =1 if this kermit locked uucp */
+
+#ifndef OXOS
+#ifdef SVORPOSIX
+static int conesc = 0; /* set to 1 if esc char (^\) typed */
+#else
+#ifdef V7
+static int conesc = 0;
+#else
+#ifdef C70
+static int conesc = 0;
+#endif /* C70 */
+#endif /* V7 */
+#endif /* SVORPOSIX */
+#endif /* OXOS */
+
+/* Local copy of comm device name or network host */
+static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
+#ifdef USETTYLOCK
+static char lockname[DEVNAMLEN+1]; /* Ditto, the part after "/dev/". */
+#endif /* USETTYLOCK */
+
+#ifdef aegis
+static status_$t st; /* error status return value */
+static short concrp = 0; /* true if console is CRP pad */
+static uid_$t ttyuid; /* tty type uid */
+static uid_$t conuid; /* stdout type uid */
+
+/* APOLLO Aegis main()
+ * establish acl usage and cleanup handling
+ * this makes sure that CRP pads
+ * get restored to a usable mode
+ */
+main(argc,argv) int argc; char **argv; {
+ status_$t status;
+ pfm_$cleanup_rec dirty;
+
+ PID_T pid = getpid();
+
+ /* acl usage according to invoking environment */
+ default_acl(USE_DEFENV);
+
+ /* establish a cleanup continuation */
+ status = pfm_$cleanup(dirty);
+ if (status.all != pfm_$cleanup_set) {
+ /* only handle faults for the original process */
+ if (pid == getpid() && status.all > pgm_$max_severity) {
+ /* blew up in main process */
+ status_$t quo;
+ pfm_$cleanup_rec clean;
+
+ /* restore the console in any case */
+ conres();
+
+ /* attempt a clean exit */
+ debug(F101, "cleanup fault status", "", status.all);
+
+ /* doexit(), then send status to continuation */
+ quo = pfm_$cleanup(clean);
+ if (quo.all == pfm_$cleanup_set)
+ doexit(pgm_$program_faulted,-1);
+ else if (quo.all > pgm_$max_severity)
+ pfm_$signal(quo); /* blew up in doexit() */
+ }
+ /* send to the original continuation */
+ pfm_$signal(status);
+ /*NOTREACHED*/
+ }
+ return(ckcmai(argc, argv));
+}
+#endif /* aegis */
+
+/* ANSI-style prototypes for internal functions. */
+/* Functions used outside this module are prototyped in ckcker.h. */
+
+#ifdef apollo
+_PROTOTYP( SIGTYP timerh, () );
+_PROTOTYP( SIGTYP cctrap, () );
+_PROTOTYP( SIGTYP esctrp, () );
+_PROTOTYP( SIGTYP sig_ign, () );
+#else
+_PROTOTYP( SIGTYP timerh, (int) );
+_PROTOTYP( SIGTYP cctrap, (int) );
+_PROTOTYP( SIGTYP esctrp, (int) );
+#endif /* apollo */
+_PROTOTYP( int do_open, (char *) );
+_PROTOTYP( static int in_chk, (int, int) );
+_PROTOTYP( static int ttrpid, (char *) );
+_PROTOTYP( static int ttchkpid, (char *) );
+_PROTOTYP( static int ttlock, (char *) );
+_PROTOTYP( static int ttunlck, (void) );
+_PROTOTYP( static VOID sigchld_handler, (int) );
+_PROTOTYP( int mygetbuf, (void) );
+_PROTOTYP( int myfillbuf, (void) );
+_PROTOTYP( VOID conbgt, (int) );
+#ifdef ACUCNTRL
+_PROTOTYP( VOID acucntrl, (char *, char *) );
+#endif /* ACUCNTRL */
+
+#ifdef BSD44ORPOSIX
+_PROTOTYP( int carrctl, (struct termios *, int) );
+#else
+#ifdef ATTSV
+_PROTOTYP( int carrctl, (struct termio *, int) );
+#else
+_PROTOTYP( int carrctl, (struct sgttyb *, int) );
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+#ifdef ATT7300
+_PROTOTYP( int attdial, (char *, long, char *) );
+_PROTOTYP( int offgetty, (char *) );
+_PROTOTYP( int ongetty, (char *) );
+#endif /* ATT7300 */
+
+#ifdef BEOSORBEBOX
+#ifdef SELECT
+ /* BeOS is not capable of using SELECT on anything but sockets */
+#undef SELECT
+#endif /* SELECT */
+#include <kernel/OS.h>
+/* #ifdef BE_DR_7 */
+static double time_started = 0.0;
+struct ALARM_STRUCT {
+ thread_id thread;
+ int time;
+};
+static thread_id alarm_thread = -1;
+static struct ALARM_STRUCT alarm_struct;
+_PROTOTYP( long do_alarm, (void *) );
+_PROTOTYP( unsigned int alarm, (unsigned int) );
+_PROTOTYP( void alarm_expired, (void) );
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+
+#ifndef xunchar
+#define xunchar(ch) (((ch) - 32 ) & 0xFF ) /* Character to number */
+#endif /* xunchar */
+
+#ifdef CK_ANSIC
+static char *
+xxlast(char *s, char c)
+#else
+static char *
+xxlast(s,c) char *s; char c;
+#endif /* CK_ANSIC */
+/* xxlast */ { /* Last occurrence of character c in string s. */
+ int i;
+ for (i = (int)strlen(s); i > 0; i--)
+ if (s[i-1] == c ) return(s + (i - 1));
+ return(NULL);
+}
+
+/* Timeout handler for communication line input functions */
+
+/*ARGSUSED*/
+SIGTYP
+timerh(foo) int foo; {
+ ttimoff();
+#ifdef BEOSORBEBOX
+/* #ifdef BE_DR_7 */
+ alarm_expired();
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+#ifdef CK_POSIX_SIG
+ siglongjmp(sjbuf,1);
+#else
+ longjmp(sjbuf,1);
+#endif /* CK_POSIX_SIG */
+}
+
+/*ARGSUSED*/
+SIGTYP
+xtimerh(foo) int foo; { /* Like timerh() but does */
+#ifdef BEOSORBEBOX /* not reset the timer itself */
+/* #ifdef BE_DR_7 */
+ alarm_expired();
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+#ifdef CK_POSIX_SIG
+ siglongjmp(sjbuf,1);
+#else
+ longjmp(sjbuf,1);
+#endif /* CK_POSIX_SIG */
+}
+
+
+/* Control-C trap for communication line input functions */
+
+int cc_int; /* Flag */
+SIGTYP (* occt)(); /* For saving old SIGINT handler */
+
+/*ARGSUSED*/
+SIGTYP
+cctrap(foo) int foo; { /* Needs arg for ANSI C */
+ cc_int = 1; /* signal() prototype. */
+ return;
+}
+
+/* S Y S I N I T -- System-dependent program initialization. */
+
+/*
+ * ttgwsiz() returns:
+ * 1 tt_rows and tt_cols are known, both altered, both > 0
+ * 0 tt_rows and/or tt_cols are known, both altered, one or both <= 0
+ * -1 tt_rows and tt_cols are unknown and unaltered
+ */
+
+extern int tt_rows, tt_cols;
+
+static int
+xttgwsiz() {
+ char *p;
+ int rows = 0, cols = 0;
+ p = getenv("LINES");
+ debug(F110,"xttgwsiz LINES",p,0);
+ if (p) {
+ rows = atol(p);
+ if (rows > 0) {
+ p = getenv("COLUMNS");
+ debug(F110,"xttgwsiz COLUMNS",p,0);
+ if (p) {
+ cols = atol(p);
+ if (cols > 0) {
+ tt_rows = rows;
+ tt_cols = cols;
+ return(1);
+ }
+ return(0);
+ }
+ }
+ }
+ return(-1);
+}
+
+#ifdef TTLEBUF
+VOID
+le_init() { /* LocalEchoInit() */
+ int i;
+ for (i = 0; i < LEBUFSIZ; i++)
+ le_buf[i] = '\0';
+ le_start = 0;
+ le_end = 0;
+ le_data = 0;
+}
+
+VOID
+le_clean() { /* LocalEchoCleanup() */
+ le_init();
+ return;
+}
+
+int
+le_inbuf() {
+ int rc = 0;
+ if (le_start != le_end) {
+ rc = (le_end -
+ le_start +
+ LEBUFSIZ) % LEBUFSIZ;
+ }
+ debug(F111,"le_inbuf","chars waiting",rc);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_putchar(CHAR ch)
+#else
+le_putchar(ch) CHAR ch;
+#endif /* CK_ANSIC */
+/* le_putchar */ {
+#ifdef COMMENT
+ /* In UNIX we do not have another thread taking chars out of the buffer */
+ while ((le_start - le_end == 1) ||
+ (le_start == 0 && le_end == LEBUFSIZ - 1)) {
+ /* Buffer is full */
+ debug(F111,"le_putchar","Buffer is Full",ch);
+ ReleaseLocalEchoMutex() ;
+ msleep(250);
+ RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
+ }
+#else
+ if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
+ debug(F110,"le_putchar","buffer is full",0);
+ return(-1);
+ }
+#endif /* COMMENT */
+ le_buf[le_end++] = ch;
+ if (le_end == LEBUFSIZ)
+ le_end = 0;
+ le_data = 1;
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+le_puts(CHAR * s, int n)
+#else
+le_puts(s,n) CHAR * s; int n;
+#endif /* CK_ANSIC */
+/* le_puts */ {
+ int rc = 0;
+ int i = 0;
+ CHAR * p = (CHAR *)"le_puts";
+ ckhexdump(p,s,n);
+ for (i = 0; i < n; i++)
+ rc = le_putchar((char)s[i]);
+ debug(F101,"le_puts","",rc);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_putstr(CHAR * s)
+#else
+le_putstr(s) CHAR * s;
+#endif /* CK_ANSIC */
+/* le_puts */ {
+ CHAR * p;
+ int rc = 0;
+ p = (CHAR *)"le_putstr";
+ ckhexdump(p,s,(int)strlen((char *)s));
+ for (p = s; *p && !rc; p++)
+ rc = le_putchar(*p);
+ return(rc);
+}
+
+int
+#ifdef CK_ANSIC
+le_getchar(CHAR * pch)
+#else /* CK_ANSIC */
+le_getchar(pch) CHAR * pch;
+#endif /* CK_ANSIC */
+/* le_gatchar */ {
+ int rc = 0;
+ if (le_start != le_end) {
+ *pch = le_buf[le_start];
+ le_buf[le_start] = 0;
+ le_start++;
+
+ if (le_start == LEBUFSIZ)
+ le_start = 0;
+
+ if (le_start == le_end) {
+ le_data = 0;
+ }
+ rc++;
+ } else {
+ *pch = 0;
+ }
+ return(rc);
+}
+#endif /* TTLEBUF */
+
+#ifdef COMMENT
+/*
+ Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
+ But as far as I know, whenever TIOCGSIZE is defined, it is
+ equated to TIOCGWINSZ. For cases where this is not done, try this:
+*/
+#ifndef TIOCGWINSZ
+#ifdef TIOCGSIZE
+#define TIOCGWINSZ TIOCGSIZE
+#endif /* TIOCGSIZE */
+#endif /* TIOCGWINSZ */
+#endif /* COMMENT */
+
+static int tt_xpixel = 0, tt_ypixel = 0;
+
+int
+ttgwsiz() {
+ int x = 0;
+#ifndef NONAWS
+#ifdef QNX
+/*
+ NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
+ This code works for both the 16- and 32-bit versions.
+*/
+ extern int dev_size(int, int, int, int *, int *);
+ int r, c;
+
+ if (dev_size(0, -1, -1, &r, &c) == 0) {
+ debug(F101,"ttgwsiz QNX r","",r);
+ debug(F101,"ttgwsiz QNX c","",c);
+ tt_rows = r;
+ tt_cols = c;
+ return ((r > 0 && c > 0) ? 1 : 0);
+ } else return(xttgwsiz());
+#else /* QNX */
+#ifdef TIOCGWINSZ
+
+/* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
+#ifdef XENIX /* SCO UNIX 3.2v4.0 */
+#include <sys/stream.h> /* typedef mblk_t needed by ptem.h */
+#include <sys/ptem.h> /* for ttgwsiz() */
+#endif /* XENIX */
+
+#ifdef I386IX /* Ditto for Interactive */
+#include <sys/stream.h>
+#include <sys/ptem.h>
+#endif /* I386IX */
+
+/* Note, the above might be needed for some other older SVR3 Intel makes... */
+
+ struct winsize w;
+ tt_xpixel = 0;
+ tt_ypixel = 0;
+
+#ifdef IKSD
+ if (inserver)
+ return(xttgwsiz());
+#endif /* IKSD */
+ x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
+ debug(F101,"ttgwsiz TIOCGWINSZ","",x);
+ if (x < 0) {
+ return(xttgwsiz());
+ } else if (w.ws_row > 0 && w.ws_col > 0) {
+ tt_rows = w.ws_row;
+ tt_cols = w.ws_col;
+ tt_xpixel = w.ws_xpixel;
+ tt_ypixel = w.ws_ypixel;
+ debug(F101,"ttgwsiz tt_rows","",tt_rows);
+ debug(F101,"ttgwsiz tt_cols","",tt_cols);
+ return(1);
+ } else {
+ debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
+ return(xttgwsiz());
+ }
+#else
+ return(xttgwsiz());
+#endif /* TIOCGWINSZ */
+#endif /* QNX */
+#endif /* NONAWS */
+}
+
+
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_naws, (void) );
+#endif /* RLOGCODE */
+
+#ifndef NOSIGWINCH
+#ifdef SIGWINCH
+SIGTYP
+winchh(foo) int foo; { /* SIGWINCH handler */
+ int x = 0;
+#ifdef CK_TTYFD
+#ifndef VMS
+ extern int ttyfd;
+#endif /* VMS */
+#endif /* CK_TTYFD */
+ extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"***************","",0);
+ debug(F100,"SIGWINCH caught","",0);
+ debug(F100,"***************","",0);
+#ifdef NETPTY
+ debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
+#endif /* NETPTY */
+ }
+#endif /* DEUB */
+ signal(SIGWINCH,winchh); /* Re-arm the signal */
+ x = ttgwsiz(); /* Get new window size */
+ cmd_rows = tt_rows; /* Adjust command screen too */
+ cmd_cols = tt_cols;
+
+#ifdef CK_TTYFD
+ if /* If we don't have a connection */
+#ifdef VMS /* we're done. */
+ (vmsttyfd() == -1)
+#else
+ (ttyfd == -1)
+#endif /* VMS */
+#else
+ (!local)
+#endif /* CK_TTYFD */
+ return;
+
+#ifdef NETPTY
+ if (pty_fork_pid > -1) { /* "set host" to a PTY? */
+ int x;
+
+#ifdef TIOCSWINSZ
+ struct winsize w; /* Resize the PTY */
+ errno = 0;
+ w.ws_col = tt_cols;
+ w.ws_row = tt_rows;
+ w.ws_xpixel = tt_xpixel;
+ w.ws_ypixel = tt_ypixel;
+ x = ioctl(ttyfd,TIOCSWINSZ,&w);
+ debug(F101,"winchh TIOCSWINSZ","",x);
+ debug(F101,"winchh TIOCSWINSZ errno","",errno);
+#endif /* TIOCSWINSZ */
+
+ errno = 0;
+ x = kill(pty_fork_pid,SIGWINCH);
+ debug(F101,"winchh kill","",x);
+ debug(F101,"winchh kill errno","",errno);
+ }
+#endif /* NETPTY */
+
+/*
+ This should be OK. It might seem that sending this from
+ interrupt level could interfere with another TELNET IAC string
+ that was in the process of being sent. But we always send
+ TELNET strings with a single write(), which should prevent mixups.
+ blah_snaws() should protect themselves from being called on the
+ wrong kind of connection.
+*/
+#ifdef TCPSOCKET
+#ifndef NOTTGWSIZ
+ if (x > 0 && tt_rows > 0 && tt_cols > 0) {
+ tn_snaws();
+#ifdef RLOGCODE
+ rlog_naws();
+#endif /* RLOGCODE */
+ }
+#endif /* NOTTGWSIZ */
+#endif /* TCPSOCKET */
+ SIGRETURN;
+}
+#endif /* SIGWINCH */
+#endif /* NOSIGWINCH */
+
+SIGTYP
+sighup(foo) int foo; { /* SIGHUP handler */
+ backgrd = 1;
+ debug(F100,"***************","",0);
+ debug(F100,"SIGHUP received","",0);
+ debug(F100,"***************","",0);
+ doexit(BAD_EXIT,-1);
+ /*NOTREACHED*/
+ SIGRETURN; /* Shut picky compilers up... */
+}
+
+#ifdef CK_SCO32V4
+/* Exists but there is no prototype in the header files */
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef SV68R3V6
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef ultrix
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef HPUX6
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef HPUX5
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef PS2AIX10
+_PROTOTYP( char * ttyname, (int) );
+#else
+#ifdef BSD42
+_PROTOTYP( char * ttyname, (int) );
+#endif /* BSD42 */
+#endif /* PS2AIX10 */
+#endif /* HPUX5 */
+#endif /* HPUX6 */
+#endif /* ultrix */
+#endif /* SV68R3V6 */
+#endif /* CK_SCO32V4 */
+
+#ifndef SIGUSR1 /* User-defined signals */
+#define SIGUSR1 30
+#endif /* SIGUSR1 */
+
+#ifndef SIGUSR2
+#define SIGUSR2 31
+#endif /* SIGUSR2 */
+
+/*
+ ignorsigs() sets certain signals to SIG_IGN. But when a signal is
+ ignored, it remains ignored across exec(), so we have to restore these
+ signals before exec(), which is the purpose of restorsigs().
+*/
+static VOID
+ignorsigs() { /* Ignore these signals */
+ savquit = signal(SIGQUIT,SIG_IGN); /* Ignore Quit signal */
+
+#ifdef SIGDANGER /* Ignore danger signals */
+/*
+ This signal is sent when the system is low on swap space. Processes
+ that don't handle it are candidates for termination. If swap space doesn't
+ clear out enough, we still might be terminated via kill() -- nothing we can
+ do about that! Conceivably, this could be improved by installing a real
+ signal handler that warns the user, but that would be pretty complicated,
+ since we are not always in control of the screen -- e.g. during remote-mode
+ file transfer.
+*/
+ savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
+#endif /* SIGDANGER */
+#ifdef SIGPIPE
+/*
+ This one comes when a TCP/IP connection is broken by the remote.
+ We prefer to catch this situation by examining error codes from write().
+*/
+ savpipe = signal(SIGPIPE,SIG_IGN);
+#endif /* SIGPIPE */
+ savusr1 = signal(SIGUSR1,SIG_IGN); /* Ignore user-defined signals */
+ savusr2 = signal(SIGUSR2,SIG_IGN);
+}
+
+VOID
+restorsigs() { /* Restore these signals */
+ (VOID) signal(SIGQUIT,savquit); /* (used in ckufio.c) */
+#ifdef SIGDANGER
+ (VOID) signal(SIGDANGER,savdanger);
+#endif /* SIGDANGER */
+#ifdef SIGPIPE
+ (VOID) signal(SIGPIPE,savpipe);
+#endif /* SIGPIPE */
+ (VOID) signal(SIGUSR1,savusr1);
+ (VOID) signal(SIGUSR2,savusr2);
+}
+
+int
+sysinit() {
+ int x;
+ char * s;
+#ifdef CK_UTSNAME
+ struct utsname name;
+#endif /* CK_UTSNAME */
+
+ extern char startupdir[];
+/*
+ BEFORE ANYTHING ELSE: Initialize the setuid package.
+ Change to the user's real user and group ID.
+ If this can't be done, don't run at all.
+*/
+ x = priv_ini();
+#ifdef SUIDDEBUG
+ fprintf(stderr,"PRIV_INI=%d\n",x);
+#endif /* SUIDDEBUG */
+ if (x) {
+ if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
+ if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
+ if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
+ exit(1);
+ }
+ signal(SIGINT,SIG_IGN); /* Ignore interrupts at first */
+ signal(SIGFPE,SIG_IGN); /* Ignore floating-point exceptions */
+ signal(SIGHUP,sighup); /* Catch SIGHUP */
+#ifndef NOSIGWINCH
+#ifdef SIGWINCH
+ signal(SIGWINCH,winchh); /* Catch window-size change */
+#endif /* SIGWINCH */
+#endif /* NOSIGWINCH */
+
+#ifdef SIGXFSZ
+ signal(SIGXFSZ,SIG_IGN); /* Ignore writing past file limit */
+#endif /* SIGXFSZ */
+
+#ifndef NOJC
+/*
+ Get the initial job control state.
+ If it is SIG_IGN, that means the shell does not support job control,
+ and so we'd better not suspend ourselves.
+*/
+#ifdef SIGTSTP
+ jchdlr = signal(SIGTSTP,SIG_IGN);
+ if (jchdlr == SIG_IGN) {
+ jcshell = 0;
+ debug(F100,"sysinit jchdlr: SIG_IGN","",0);
+ } else if (jchdlr == SIG_DFL) {
+ debug(F100,"sysinit jchdlr: SIG_DFL","",0);
+ jcshell = 1;
+ } else {
+ debug(F100,"sysinit jchdlr: other","",0);
+ jcshell = 3;
+ }
+ (VOID) signal(SIGTSTP,jchdlr); /* Put it back... */
+#endif /* SIGTSTP */
+#endif /* NOJC */
+
+ conbgt(0); /* See if we're in the background */
+ congm(); /* Get console modes */
+
+ (VOID) signal(SIGALRM,SIG_IGN); /* Ignore alarms */
+
+ ignorsigs(); /* Ignore some other signals */
+
+#ifdef F_SETFL
+ iniflags = fcntl(0,F_GETFL,0); /* Get stdin flags */
+#endif /* F_SETFL */
+
+#ifdef ultrix
+ gtty(0,&vanilla); /* Get sgtty info */
+#else
+#ifdef AUX
+ set42sig(); /* Don't ask! (hakanson@cs.orst.edu) */
+#endif /* AUX */
+#endif /* ultrix */
+/*
+ Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
+ never closes it. If it is called often enough, we run out of file
+ descriptors and subsequent open()'s of other devices or files can fail.
+*/
+ s = NULL;
+#ifndef MINIX
+ if (isatty(0)) /* Name of controlling terminal */
+ s = ttyname(0);
+ else if (isatty(1))
+ s = ttyname(1);
+ else if (isatty(2))
+ s = ttyname(2);
+ debug(F110,"sysinit ttyname(0)",s,0);
+#endif /* MINIX */
+
+#ifdef BEOS
+ if (!dftty)
+ makestr(&dftty,s);
+#endif /* BEOS */
+
+ if (s)
+ ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
+#ifdef SVORPOSIX
+ if (!cttnam[0])
+ ctermid(cttnam);
+#endif /* SVORPOSIX */
+ if (!cttnam[0])
+ ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
+ debug(F110,"sysinit CTTNAM",CTTNAM,0);
+ debug(F110,"sysinit cttnam",cttnam,0);
+
+ ttgwsiz(); /* Get window (screen) dimensions. */
+
+#ifndef NOSYSCONF
+#ifdef _SC_OPEN_MAX
+ ckmaxfiles = sysconf(_SC_OPEN_MAX);
+#endif /* _SC_OPEN_MAX */
+#endif /* NOSYSCONF */
+
+#ifdef Plan9
+ if (!backgrd) {
+ consctlfd = open("/dev/consctl", O_WRONLY);
+ /*noisefd = open("/dev/noise", O_WRONLY)*/
+ }
+ ckxech = 1;
+#endif /* Plan9 */
+
+#ifdef CK_UTSNAME
+ if (uname(&name) > -1) {
+ ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
+ ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
+ ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
+ ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"sysinit uname machine",unm_mch,0);
+ debug(F110,"sysinit uname sysname",unm_nam,0);
+ debug(F110,"sysinit uname release",unm_rel,0);
+ debug(F110,"sysinit uname version",unm_ver,0);
+ }
+#endif /* DEBUG */
+
+#ifdef HPUX9PLUS
+ if (name.machine[5] == '8')
+ hpis800 = 1;
+ else
+ hpis800 = 0;
+ debug(F101,"sysinit hpis800","",hpis800);
+#endif /* HPUX9PLUS */
+#ifdef TRU64
+ getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
+ debug(F110,"sysinit getsysinfo model",unm_mod,0);
+#endif /* TRU64 */
+#ifdef SOLARIS25
+ sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
+ debug(F110,"sysinit sysinfo model",unm_mod,0);
+#endif /* SOLARIS25 */
+ }
+#endif /* CK_UTSNAME */
+
+#ifdef CK_ENVIRONMENT
+ {
+#ifdef TNCODE
+ extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
+ tn_env_prnt[], tn_env_sys[];
+#endif /* TNCODE */
+ extern char uidbuf[];
+ extern char * whoami();
+ char *p;
+#ifdef CKSENDUID
+ uidbuf[0] = '\0';
+#ifdef IKSD
+ if (!inserver) {
+#endif /* IKSD */
+ p = getenv("USER");
+ debug(F110,"sysinit uidbuf from USER",uidbuf,0);
+ if (!p) p = "";
+ if (!*p) {
+ p = getenv("LOGNAME");
+ debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
+ }
+ if (!p) p = "";
+ if (!*p) {
+ p = whoami();
+ debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
+ }
+ if (!p) p = "";
+ ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
+#ifdef IKSD
+ }
+#endif /* IKSD */
+ debug(F110,"sysinit final uidbuf",uidbuf,0);
+#endif /* CKSENDUID */
+
+#ifdef TNCODE
+ if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
+ if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
+ if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
+ if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
+#ifdef aegis
+ ckstrncpy(tn_env_sys,"Aegis",64);
+#else
+#ifdef Plan9
+ ckstrncpy(tn_env_sys,"Plan9",64);
+#else
+ ckstrncpy(tn_env_sys,"UNIX",64);
+#endif /* Plan9 */
+#endif /* aegis */
+#endif /* TNCODE */
+ }
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ {
+ extern char * tn_loc;
+ char *p;
+ if (p = getenv("LOCATION"))
+ if (tn_loc = (char *)malloc((int)strlen(p)+1))
+ strcpy(tn_loc,p); /* safe */
+ }
+#endif /* CK_SNDLOC */
+
+ ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
+ startupdir[CKMAXPATH] = '\0';
+ x = strlen(startupdir);
+ if (x <= 0) {
+ startupdir[0] = '/';
+ startupdir[1] = '\0';
+ } else if (startupdir[x-1] != '/') {
+ startupdir[x] = '/';
+ startupdir[x+1] = '\0';
+ }
+ debug(F110,"sysinit startupdir",startupdir,0);
+#ifdef TTLEBUF
+ le_init();
+#endif /* TTLEBUF */
+#ifdef BSD44ORPOSIX
+ /* This should catch the ncurses platforms */
+ /* Some platforms don't have putenv(), like NeXTSTEP */
+ putenv("NCURSES_NO_SETBUF=1");
+#endif /* BSD44ORPOSIX */
+ return(0);
+}
+
+/* S Y S C L E A N U P -- System-dependent program cleanup. */
+
+int
+syscleanup() {
+#ifdef F_SETFL
+ if (iniflags > -1)
+ fcntl(0,F_SETFL,iniflags); /* Restore stdin flags */
+#endif /* F_SETFL */
+#ifdef ultrix
+ stty(0,&vanilla); /* Get sgtty info */
+#endif /* ultrix */
+#ifdef NETCMD
+ if (ttpid) kill(ttpid,9);
+#endif /* NETCMD */
+ return(0);
+}
+
+/* T T O P E N -- Open a tty for exclusive access. */
+
+/*
+ Call with:
+ ttname: character string - device name or network host name.
+ lcl:
+ If called with lcl < 0, sets value of lcl as follows:
+ 0: the terminal named by ttname is the job's controlling terminal.
+ 1: the terminal named by ttname is not the job's controlling terminal.
+ But watch out: if a line is already open, or if requested line can't
+ be opened, then lcl remains (and is returned as) -1.
+ modem:
+ Less than zero: ttname is a network host name.
+ Zero or greater: ttname is a terminal device name.
+ Zero means a local connection (don't use modem signals).
+ Positive means use modem signals.
+ timo:
+ 0 = no timer.
+ nonzero = number of seconds to wait for open() to return before timing out.
+
+ Returns:
+ 0 on success
+ -5 if device is in use
+ -4 if access to device is denied
+ -3 if access to lock directory denied
+ -2 upon timeout waiting for device to open
+ -1 on other error
+*/
+static int ttotmo = 0; /* Timeout flag */
+/* Flag kept here to avoid being clobbered by longjmp. */
+
+int
+ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
+
+#ifdef BSD44
+#define ctermid(x) strcpy(x,"")
+#else
+#ifdef SVORPOSIX
+#ifndef CIE
+ extern char *ctermid(); /* Wish they all had this! */
+#else /* CIE Regulus */
+#define ctermid(x) strcpy(x,"")
+#endif /* CIE */
+#endif /* SVORPOSIX */
+#endif /* BSD44 */
+
+#ifdef ultrix
+ int temp = 0;
+#endif /* ultrix */
+
+#ifndef OPENFIRST
+ char fullname[DEVNAMLEN+1];
+#endif /* OPENFIRST */
+
+ char * fnam; /* Full name after expansion */
+
+ int y;
+
+#ifndef pdp11
+#define NAMEFD /* Feature to allow name to be an open file descriptor */
+#endif /* pdp11 */
+
+#ifdef NAMEFD
+ char *p;
+ debug(F101,"ttopen telnetfd","",telnetfd);
+#endif /* NAMEFD */
+
+ debug(F110,"ttopen ttname",ttname,0);
+ debug(F110,"ttopen ttnmsv",ttnmsv,0);
+ debug(F101,"ttopen modem","",modem);
+ debug(F101,"ttopen netconn","",netconn);
+ debug(F101,"ttopen ttyfd","",ttyfd);
+ debug(F101,"ttopen *lcl","",*lcl);
+ debug(F101,"ttopen ttmdm","",ttmdm);
+ debug(F101,"ttopen ttnet","",ttnet);
+
+ ttpmsk = 0xff;
+ lockpid[0] = '\0';
+
+ if (ttyfd > -1) { /* If device already opened */
+ if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
+ return(0); /* Yes, nothing to do - just return */
+ ttnmsv[0] = '\0'; /* No, clear out old name */
+ ttclos(ttyfd); /* close old connection. */
+ }
+ wasclosed = 0; /* New connection, not closed yet. */
+ ttpipe = 0; /* Assume it's not a pipe */
+ ttpty = 0; /* or a pty... */
+
+#ifdef NETCONN
+/*
+ This is a bit tricky... Suppose that previously Kermit had dialed a telnet
+ modem server ("set host xxx:2001, set modem type usr, dial ..."). Then the
+ connection was closed (ttyfd = -1), and then a REDIAL command was given. At
+ this point we've obliterated the negative modem type hack, and so would
+ treat the IP hostname as a device name, and would then fail because of "No
+ such device or directory". But the previous connection has left behind some
+ clues, so let's use them...
+*/
+ if (ttyfd < 0) { /* Connection is not open */
+ if (!strcmp(ttname,ttnmsv)) { /* Old and new names the same? */
+ if (((netconn > 0) && (ttmdm < 0)) ||
+ ((ttnet > 0) &&
+ (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
+ ) {
+ int x, rc;
+ x = (ttmdm < 0) ? -ttmdm : ttnet;
+ rc = netopen(ttname, lcl, x);
+ debug(F111,"ttopen REOPEN netopen",ttname,rc);
+ if (rc > -1) {
+ netconn = 1;
+ xlocal = *lcl = 1;
+ } else {
+ netconn = 0;
+ }
+ gotsigs = 0;
+ return(rc);
+ }
+ }
+ }
+#endif /* NETCONN */
+
+#ifdef MAXNAMLEN
+ debug(F100,"ttopen MAXNAMLEN defined","",0);
+#else
+ debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
+#endif
+
+#ifdef BSD4
+ debug(F100,"ttopen BSD4 defined","",0);
+#else
+ debug(F100,"ttopen BSD4 *NOT* defined","",0);
+#endif /* BSD4 */
+
+#ifdef BSD42
+ debug(F100,"ttopen BSD42 defined","",0);
+#else
+ debug(F100,"ttopen BSD42 *NOT* defined","",0);
+#endif /* BSD42 */
+
+#ifdef MYREAD
+ debug(F100,"ttopen MYREAD defined","",0);
+#else
+ debug(F100,"ttopen MYREAD *NOT* defined","",0);
+#endif /* MYREAD */
+
+#ifdef NETCONN
+ if (modem < 0) { /* modem < 0 = code for network */
+ int x;
+ ttmdm = modem;
+ modem = -modem; /* Positive network type number */
+ fdflag = 0; /* Stdio not redirected. */
+ netconn = 1; /* And it's a network connection */
+ debug(F111,"ttopen net",ttname,modem);
+#ifdef NAMEFD
+ for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
+ if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
+ ttyfd = atoi(ttname); /* Is there a way to test it's open? */
+ ttfdflg = 1; /* We got an open file descriptor */
+ debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
+ debug(F101,"ttopen net ttyfd","",ttyfd);
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
+ x = 1; /* Return code is "good". */
+ if (telnetfd) {
+ ttnet = NET_TCPB;
+ if (ttnproto != NP_TCPRAW)
+ ttnproto = NP_TELNET;
+#ifdef SUNX25
+ } else if (x25fd) {
+ ttnet = NET_SX25;
+ ttnproto = NP_NONE;
+#endif /* SUNX25 */
+ }
+ } else { /* Host name or address given */
+#ifdef NETPTY
+ if (modem == NET_PTY) {
+ int x;
+ if (nopush) {
+ debug(F100,"ttopen PTY: nopush","",0);
+ return(-1);
+ }
+ ttnet = NET_PTY;
+ ttnproto = NP_NONE;
+ netconn = 1; /* but we don't use network i/o */
+ ttpty = 1;
+ debug(F110,"ttopen PTY",ttname,0);
+ x = do_pty(&ttyfd,ttname,0);
+ if (x > -1) {
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
+ xlocal = *lcl = 1; /* It's local */
+ } else {
+ ttpty = 0;
+ netconn = 0;
+ }
+ gotsigs = 0;
+ return(x);
+ }
+#endif /* NETPTY */
+#ifdef NETCMD
+/*
+ dup2() is not available on older System V platforms like AT&T 3Bx. For
+ those systems we punt by not defining NETCMD, but we might be able to do
+ better -- see workarounds for this problem in ckufio.c (search for dup2).
+*/
+ if (modem == NET_CMD) {
+ if (nopush) {
+ debug(F100,"ttopen pipe: nopush","",0);
+ return(-1);
+ }
+ if (pipe(pipe0) || pipe(pipe1)) {
+ perror("Pipe error");
+ return(-1);
+ }
+ ttpid = fork(); /* Make a fork */
+
+ switch (ttpid) {
+ case -1: /* Error making fork */
+ close(pipe0[0]);
+ close(pipe0[1]);
+ close(pipe1[0]);
+ close(pipe1[1]);
+ perror("Fork error");
+ return(-1);
+ case 0: /* Child. */
+ close(pipe0[0]);
+ close(pipe1[1]);
+ dup2(pipe0[1], 1);
+ close(pipe0[1]);
+ dup2(pipe1[0], 0);
+ close(pipe1[0]);
+ system(ttname);
+ _exit(0);
+ default: /* Parent */
+ close(pipe0[1]);
+ close(pipe1[0]);
+ fdin = pipe0[0]; /* Read from pipe */
+ fdout = pipe1[1]; /* Write to pipe */
+ ttout = fdopen(fdout,"w"); /* Get stream so we can */
+ if (!ttout) { /* make it unbuffered. */
+ perror("fdopen failure");
+ return(-1);
+ }
+ setbuf(ttout,NULL);
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
+ xlocal = *lcl = 1; /* It's local */
+ netconn = 1; /* Call it a network connection */
+ ttmdm = modem; /* Remember network type */
+ ttyfd = fdin;
+ ttpipe = 1;
+ gotsigs = 0;
+ return(0);
+ }
+ }
+#endif /* NETCMD */
+#endif /* NAMEFD */
+ x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
+ if (x > -1) {
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
+ } else netconn = 0;
+#ifdef NAMEFD
+ }
+#endif /* NAMEFD */
+
+#ifdef sony_news /* Sony NEWS */
+ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
+ perror("ttopen error getting Kanji mode (network)");
+ debug(F111,"ttopen error getting Kanji mode","network",0);
+ km_ext = -1; /* Make sure this stays undefined. */
+ }
+#endif /* sony_news */
+
+ xlocal = *lcl = 1; /* Network connections are local. */
+ debug(F101,"ttopen net x","",x);
+#ifdef COMMENT
+/* Let netopen() do this */
+ if (x > -1 && !x25fd)
+ x = tn_ini(); /* Initialize TELNET protocol */
+#endif /* COMMENT */
+ gotsigs = 0;
+ return(x);
+ } else { /* Terminal device */
+#endif /* NETCONN */
+
+#ifdef NAMEFD
+/*
+ This code lets you give Kermit an open file descriptor for a serial
+ communication device, rather than a device name. Kermit assumes that the
+ line is already open, locked, conditioned with the right parameters, etc.
+*/
+ for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
+ if (*p == '\0') {
+ ttyfd = atoi(ttname); /* Is there a way to test it's open? */
+ debug(F111,"ttopen got open fd",ttname,ttyfd);
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
+ if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
+ xlocal = *lcl = 0; /* we're in remote mode */
+ else /* otherwise */
+ xlocal = *lcl = 1; /* local mode. */
+ netconn = 0; /* Assume it's not a network. */
+ tvtflg = 0; /* Might need to initialize modes. */
+ ttmdm = modem; /* Remember modem type. */
+ fdflag = 0; /* Stdio not redirected. */
+ ttfdflg = 1; /* Flag we were opened this way. */
+ debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
+ debug(F101,"ttopen non-net ttyfd","",ttyfd);
+
+#ifdef sony_news /* Sony NEWS */
+ /* Get device Kanji mode */
+ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
+ perror("ttopen error getting Kanji mode");
+ debug(F101,"ttopen error getting Kanji mode","",0);
+ km_ext = -1; /* Make sure this stays undefined. */
+ }
+#endif /* sony_news */
+ gotsigs = 0;
+ return(0); /* Return success */
+ }
+#endif /* NAMEFD */
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+
+/* Here we have to open a serial device of the given name. */
+
+ netconn = 0; /* So it's not a network connection */
+ occt = signal(SIGINT, cctrap); /* Set Control-C trap, save old one */
+ sigint_ign = 0;
+
+ tvtflg = 0; /* Flag for use by ttvt(). */
+ /* 0 = ttvt not called yet for this device */
+
+ fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
+ debug(F101,"ttopen fdflag","",fdflag);
+
+ ttmdm = modem; /* Make this available to other fns */
+ xlocal = *lcl; /* Make this available to other fns */
+
+/* Code for handling bidirectional tty lines goes here. */
+/* Use specified method for turning off logins and suppressing getty. */
+
+#ifdef ACUCNTRL
+ /* Should put call to priv_on() here, but that would be very risky! */
+ acucntrl("disable",ttname); /* acucntrl() program. */
+ /* and priv_off() here... */
+#else
+#ifdef ATT7300
+ if ((attmodem & DOGETY) == 0) /* offgetty() program. */
+ attmodem |= offgetty(ttname); /* Remember response. */
+#endif /* ATT7300 */
+#endif /* ACUCNTRL */
+
+#ifdef OPENFIRST
+/*
+ 1985-2001: opens device first then gets lock; reason:
+ Kermit usually has to run setuid or setgid in order to create a lockfile.
+ If you give a SET LINE command for a device that happens to be your job's
+ controlling terminal, Kermit doesn't have to create a lockfile, and in fact
+ should not create one, and would fail if it tried to if it did not have the
+ required privileges. But you can't find out if two tty device names are
+ equivalent until you have a file descriptor that you can give to ttyname().
+ But this can cause a race condition between Kermit and [m]getty. So see
+ the [#]else part...
+*/
+
+/*
+ In the following section, we open the tty device for read/write.
+ If a modem has been specified via "set modem" prior to "set line"
+ then the O_NDELAY parameter is used in the open, provided this symbol
+ is defined (e.g. in fcntl.h), so that the program does not hang waiting
+ for carrier (which in most cases won't be present because a connection
+ has not been dialed yet). O_NDELAY is removed later on in ttopen(). It
+ would make more sense to first determine if the line is local before
+ doing this, but because ttyname() requires a file descriptor, we have
+ to open it first. See do_open().
+
+ Now open the device using the desired treatment of carrier.
+ If carrier is REQUIRED, then open could hang forever, so an optional
+ timer is provided. If carrier is not required, the timer should never
+ go off, and should do no harm...
+*/
+ ttotmo = 0; /* Flag no timeout */
+ debug(F101,"ttopen timo","",timo);
+ debug(F101,"ttopen xlocal","",xlocal);
+ if (timo > 0) {
+ int xx;
+ saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
+ xx = alarm(timo); /* Timed open() */
+ debug(F101,"ttopen alarm","",xx);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) {
+ ttotmo = 1; /* Flag timeout. */
+ } else ttyfd = do_open(ttname);
+ ttimoff();
+ debug(F111,"ttopen","modem",modem);
+ debug(F101,"ttopen ttyfd","",ttyfd);
+ debug(F101,"ttopen alarm return","",ttotmo);
+ } else {
+ errno = 0;
+ ttyfd = do_open(ttname);
+ }
+ debug(F111,"ttopen ttyfd",ttname,ttyfd);
+ if (ttyfd < 0) { /* If couldn't open, fail. */
+ debug(F101,"ttopen errno","",errno);
+ if (errno > 0 && !quiet)
+ perror(ttname); /* Print message */
+
+#ifdef ATT7300
+ if (attmodem & DOGETY) /* was getty(1m) running before us? */
+ ongetty(ttnmsv); /* yes, restart on tty line */
+ attmodem &= ~DOGETY; /* no phone in use, getty restored */
+#else
+#ifdef ACUCNTRL
+ /* Should put call to priv_on() here, but that would be risky! */
+ acucntrl("enable",ttname); /* acucntrl() program. */
+ /* and priv_off() here... */
+#endif /* ACUNTRL */
+#endif /* ATT7300 */
+
+ signal(SIGINT,occt); /* Put old Ctrl-C trap back. */
+ if (errno == EACCES) { /* Device is protected against user */
+ debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
+ return(-4);
+ } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
+ }
+
+#ifdef QNX
+ {
+ extern int qnxportlock;
+ x = qnxopencount();
+ debug(F101,"ttopen qnxopencount","",x);
+ debug(F101,"ttopen qnxportlock","",qnxportlock);
+ if (x < 0 && qnxportlock) {
+ ttclos(0);
+ printf("?Can't get port open count\n");
+ printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
+ return(-1); /* Indicate device is in use */
+ }
+ if (x > 1) { /* 1 == me */
+ if (qnxportlock)
+ ttclos(0);
+ return(-2); /* Indicate device is in use */
+ else if (!quiet)
+ printf("WARNING: \"%s\" looks busy...\n",ttdev);
+ }
+ }
+#endif /* QNX */
+
+#ifdef Plan9
+ /* take this opportunity to open the control channel */
+ if (p9openttyctl(ttname) < 0)
+#else
+ /* Make sure it's a real tty. */
+ if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
+#endif /* Plan9 */
+ {
+ fprintf(stderr,"%s is not a terminal device\n",ttname);
+ debug(F111,"ttopen not a tty",ttname,errno);
+ close(ttyfd);
+ ttyfd = -1;
+ wasclosed = 1;
+ signal(SIGINT,occt);
+ return(-1);
+ }
+
+#ifdef aegis
+ /* Apollo C runtime claims that console pads are tty devices, which
+ * is reasonable, but they aren't any good for packet transfer. */
+ ios_$inq_type_uid((short)ttyfd, ttyuid, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "problem getting tty object type: ");
+ error_$print(st);
+ } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
+ close(ttyfd); ttyfd = -1;
+ wasclosed = 1;
+ errno = ENOTTY; perror(ttname);
+ signal(SIGINT,occt);
+ return(-1);
+ }
+#endif /* aegis */
+
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
+
+/* Caller wants us to figure out if line is controlling tty */
+
+ if (*lcl < 0) {
+ if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
+ xlocal = 0;
+ debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
+ } else if (strcmp(ttname,cttnam) == 0) {
+ xlocal = 0;
+ debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
+ } else if (cttnam[0]) {
+#ifdef BEBOX_DR7
+ x = ttnmsv; /* ttyname() is broken */
+#else
+ x = ttyname(ttyfd); /* Get real name of ttname. */
+#endif /* BEBOX_DR7 */
+ if (!x) x = "";
+ if (*x)
+ xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
+ else
+ xlocal = 1;
+ debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
+ }
+ }
+
+#ifndef NOFDZERO
+/* Note, the following code was added so that Unix "idle-line" snoopers */
+/* would not think Kermit was idle when it was transferring files, and */
+/* maybe log people out. */
+ if (xlocal == 0) { /* Remote mode */
+ if (fdflag == 0) { /* Standard i/o is not redirected */
+ debug(F100,"ttopen setting ttyfd = 0","",0);
+#ifdef LYNXOS
+ /* On Lynx OS, fd 0 is open for read only. */
+ dup2(ttyfd,0);
+#endif /* LYNXOS */
+ close(ttyfd); /* Use file descriptor 0 */
+ ttyfd = 0;
+ } else { /* Standard i/o is redirected */
+ debug(F101,"ttopen stdio redirected","",ttyfd);
+ }
+ }
+#endif /* NOFDZERO */
+
+/* Now check if line is locked -- if so fail, else lock for ourselves */
+/* Note: After having done this, don't forget to delete the lock if you */
+/* leave ttopen() with an error condition. */
+
+ lkf = 0; /* Check lock */
+ if (xlocal > 0) {
+ int xx; int xpid;
+ if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
+ debug(F111,"ttopen ttlock fails",ttname,xx);
+ /* WARNING - This close() can hang if tty is an empty socket... */
+ close(ttyfd); /* Close the device. */
+ ttyfd = -1; /* Erase its file descriptor. */
+ wasclosed = 1;
+ signal(SIGINT,occt); /* Put old SIGINT back. */
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+ if (xx == -2) { /* If lockfile says device in use, */
+#ifndef NOUUCP
+ debug(F111,"ttopen reading lockfile pid",flfnam,xx);
+ xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
+ if (xpid > -1) { /* If we got a pid */
+ if (!quiet)
+ printf("Locked by process %d\n",xpid); /* tell them. */
+ sprintf(lockpid,"%d",xpid); /* Record it too */
+ debug(F110,"ttopen lockpid",lockpid,0);
+ } else if (*flfnam) {
+ extern char *DIRCMD;
+ char *p = NULL;
+ int x;
+ x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
+ p = malloc(x); /* Print a directory listing. */
+/*
+ Note: priv_on() won't help here, because we do not pass privs along to
+ to inferior processes, in this case ls. So if the real user does not have
+ directory-listing access to the lockfile directory, this will result in
+ something like "not found". That's why we try this only as a last resort.
+*/
+ if (p) { /* If we got the space... */
+ ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
+ zsyscmd(p); /* Get listing. */
+ if (p) { /* free the space */
+ free(p);
+ p = NULL;
+ }
+ }
+ }
+#endif /* NOUUCP */
+ return(-5); /* Code for device in use */
+ } else return(-3); /* Access denied */
+ } else lkf = 1;
+ }
+#else /* OPENFIRST */
+
+/*
+ 27 Oct 2001: New simpler code that gets the lock first and then opens the
+ device, which eliminates the race condition. The downside is you can no
+ longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
+ terminal, without trying to create a lockfile, which fails if C-Kermit lacks
+ privs, and if it succeeds, it has created a lockfile where it didn't create
+ one before.
+*/
+ xlocal = *lcl; /* Is the device my login terminal? */
+ debug(F111,"ttopen xlocal","A",xlocal);
+ fnam = ttname;
+ if (strcmp(ttname,CTTNAM) && netconn == 0) {
+ if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
+ if ((int)strlen(fullname) > 0)
+ fnam = fullname;
+ }
+ }
+ debug(F110,"ttopen fnam",fnam,0);
+ if (xlocal < 0) {
+ xlocal = (strcmp(fnam,CTTNAM) != 0);
+ }
+ debug(F111,"ttopen xlocal","B",xlocal);
+
+ lkf = 0; /* No lock yet */
+ if (xlocal > 0) { /* If not... */
+ int xx; int xpid;
+ xx = ttlock(fnam); /* Try to lock it. */
+ debug(F101,"ttopen ttlock","",xx);
+ if (xx < 0) { /* Can't lock it. */
+ debug(F111,"ttopen ttlock fails",fnam,xx);
+ if (xx == -2) { /* If lockfile says device in use, */
+#ifndef NOUUCP
+ debug(F111,"ttopen reading lockfile pid",flfnam,xx);
+ xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
+ if (xpid > -1) { /* If we got a pid */
+ if (!quiet)
+ printf("Locked by process %d\n",xpid); /* tell them. */
+ ckstrncpy(lockpid,ckitoa(xpid),16);
+ debug(F110,"ttopen lockpid",lockpid,0);
+#ifndef NOPUSH
+ } else if (flfnam[0] && !nopush) {
+ extern char *DIRCMD;
+ char *p = NULL;
+ int x;
+ x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
+ p = malloc(x); /* Print a directory listing. */
+/*
+ Note: priv_on() won't help here, because we do not pass privs along to
+ to inferior processes, in this case ls. So if the real user does not have
+ directory-listing access to the lockfile directory, this will result in
+ something like "not found". That's why we try this only as a last resort.
+*/
+ if (p) { /* If we got the space... */
+ ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
+ zsyscmd(p); /* Get listing. */
+ if (p) { /* free the space */
+ free(p);
+ p = NULL;
+ }
+ }
+#endif /* NOPUSH */
+ }
+#endif /* NOUUCP */
+ return(-5); /* Code for device in use */
+ } else return(-3); /* Access denied */
+ } else lkf = 1;
+ }
+ /* Have lock -- now it's safe to open the device */
+
+ debug(F101,"ttopen lkf","",lkf);
+ debug(F101,"ttopen timo","",timo);
+
+ ttotmo = 0; /* Flag no timeout */
+ if (timo > 0) {
+ int xx;
+ saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
+ xx = alarm(timo); /* Timed open() */
+ debug(F101,"ttopen alarm","",xx);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) {
+ ttotmo = 1; /* Flag timeout. */
+ } else {
+ ttyfd = do_open(fnam);
+ }
+ ttimoff();
+ debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
+ } else {
+ errno = 0;
+ ttyfd = do_open(fnam);
+ debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
+ }
+ if (ttyfd < 0) { /* If couldn't open, fail. */
+ debug(F111,"ttopen errno",fnam,errno);
+ debug(F111,"ttopen xlocal","C",xlocal);
+ if (xlocal == 0) {
+ debug(F100,"ttopen substituting 0","",0);
+ ttyfd = 0;
+ } else {
+ if (errno > 0 && !quiet) {
+ debug(F111,"ttopen perror",fnam,errno);
+ perror(fnam); /* Print message */
+ }
+ if (ttunlck()) /* Release the lock file */
+ fprintf(stderr,"Warning, problem releasing lock\r\n");
+ }
+ }
+
+ if (ttyfd < 0) { /* ttyfd is still < 0? */
+#ifdef ATT7300
+ if (attmodem & DOGETY) /* was getty(1m) running before us? */
+ ongetty(ttnmsv); /* yes, restart on tty line */
+ attmodem &= ~DOGETY; /* no phone in use, getty restored */
+#else
+#ifdef ACUCNTRL
+ /* Should put call to priv_on() here, but that would be risky! */
+ acucntrl("enable",fnam); /* acucntrl() program. */
+ /* and priv_off() here... */
+#endif /* ACUNTRL */
+#endif /* ATT7300 */
+
+ signal(SIGINT,occt); /* Put old Ctrl-C trap back. */
+ if (errno == EACCES) { /* Device is protected against user */
+ debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
+ return(-4);
+ } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
+ }
+
+/* Make sure it's a real tty. */
+
+#ifdef Plan9
+ /* take this opportunity to open the control channel */
+ if (p9openttyctl(fnam) < 0)
+#else
+ if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
+#endif /* Plan9 */
+ {
+ fprintf(stderr,"%s is not a terminal device\n",fnam);
+ debug(F111,"ttopen not a tty",fnam,errno);
+ if (ttunlck()) /* Release the lock file */
+ fprintf(stderr,"Warning, problem releasing lock\r\n");
+ close(ttyfd);
+ ttyfd = -1;
+ wasclosed = 1;
+ signal(SIGINT,occt);
+ return(-1);
+ }
+
+#ifdef aegis
+ /*
+ Apollo C runtime claims that console pads are tty devices, which
+ is reasonable, but they aren't any good for packet transfer.
+ */
+ ios_$inq_type_uid((short)ttyfd, ttyuid, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "problem getting tty object type: ");
+ error_$print(st);
+ } else if (ttyuid != sio_$uid) { /* Reject non-SIO lines */
+ close(ttyfd); ttyfd = -1;
+ wasclosed = 1;
+ errno = ENOTTY; perror(fnam);
+ signal(SIGINT,occt);
+ return(-1);
+ }
+#endif /* aegis */
+
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+
+ ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
+
+/* Caller wants us to figure out if line is controlling tty */
+
+ if (*lcl < 0) {
+ char * s;
+ if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
+ xlocal = 0;
+ debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
+ } else if (strcmp(fnam,cttnam) == 0) {
+ xlocal = 0;
+ debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
+ } else if (cttnam[0]) {
+#ifdef BEBOX_DR7
+ s = ttnmsv; /* ttyname() is broken */
+#else
+ s = ttyname(ttyfd); /* Get real name of ttname. */
+#endif /* BEBOX_DR7 */
+ if (!s) s = "";
+ if (*s)
+ xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
+ else
+ xlocal = 1;
+ debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
+ }
+ }
+
+#ifndef NOFDZERO
+/* Note, the following code was added so that Unix "idle-line" snoopers */
+/* would not think Kermit was idle when it was transferring files, and */
+/* maybe log people out. */
+ if (xlocal == 0) { /* Remote mode */
+ if (fdflag == 0) { /* Standard i/o is not redirected */
+ debug(F100,"ttopen setting ttyfd = 0","",0);
+#ifdef LYNXOS
+ /* On Lynx OS, fd 0 is open for read only. */
+ dup2(ttyfd,0);
+#endif /* LYNXOS */
+ close(ttyfd); /* Use file descriptor 0 */
+ ttyfd = 0;
+ } else { /* Standard i/o is redirected */
+ debug(F101,"ttopen stdio redirected","",ttyfd);
+ }
+ }
+#endif /* NOFDZERO */
+#endif /* OPENFIRST */
+
+/* Got the line, now set the desired value for local. */
+
+ if (*lcl != 0) *lcl = xlocal;
+
+/* Some special stuff for v7... */
+
+#ifdef V7
+#ifndef MINIX
+ if (kmem[TTY] < 0) { /* If open, then skip this. */
+ qaddr[TTY] = initrawq(ttyfd); /* Init the queue. */
+ if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
+ fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
+ perror("/dev/kmem");
+ exit(1);
+ }
+ }
+#endif /* !MINIX */
+#endif /* V7 */
+
+/* No failure returns after this point */
+
+#ifdef ultrix
+ ioctl(ttyfd, TIOCMODEM, &temp);
+#ifdef TIOCSINUSE
+ if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
+ if (!quiet)
+ perror(fnam);
+ }
+#endif /* TIOCSINUSE */
+#endif /* ultrix */
+
+/* Get tty device settings */
+
+#ifdef BSD44ORPOSIX /* POSIX */
+ tcgetattr(ttyfd,&ttold);
+ debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
+ tcgetattr(ttyfd,&ttraw);
+ debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
+ tcgetattr(ttyfd,&tttvt);
+ debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
+#else /* BSD, V7, and all others */
+#ifdef ATTSV /* AT&T UNIX */
+ ioctl(ttyfd,TCGETA,&ttold);
+ debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
+ ioctl(ttyfd,TCGETA,&ttraw);
+ ioctl(ttyfd,TCGETA,&tttvt);
+#else
+#ifdef BELLV10
+ ioctl(ttyfd,TIOCGETP,&ttold);
+ debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
+ ioctl(ttyfd,TIOCGDEV,&tdold);
+ debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
+#else
+ gtty(ttyfd,&ttold);
+ debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
+#endif /* BELLV10 */
+
+#ifdef sony_news /* Sony NEWS */
+ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
+ perror("ttopen error getting Kanji mode");
+ debug(F101,"ttopen error getting Kanji mode","",0);
+ km_ext = -1; /* Make sure this stays undefined. */
+ }
+#endif /* sony_news */
+
+#ifdef TIOCGETC
+ debug(F100,"ttopen TIOCGETC","",0);
+ tcharf = 0; /* In remote mode, also get */
+ if (xlocal == 0) { /* special characters */
+ if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
+ debug(F100,"ttopen TIOCGETC failed","",0);
+ } else {
+ tcharf = 1; /* It worked. */
+ ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
+ debug(F100,"ttopen TIOCGETC ok","",0);
+ }
+ }
+#else
+ debug(F100,"ttopen TIOCGETC not defined","",0);
+#endif /* TIOCGETC */
+
+#ifdef TIOCGLTC
+ debug(F100,"ttopen TIOCGLTC","",0);
+ ltcharf = 0; /* In remote mode, also get */
+ if (xlocal == 0) { /* local special characters */
+ if (ioctl(ttyfd,TIOCGLTC,<chold) < 0) {
+ debug(F100,"ttopen TIOCGLTC failed","",0);
+ } else {
+ ltcharf = 1; /* It worked. */
+ ioctl(ttyfd,TIOCGLTC,<chnoi); /* Get another copy */
+ debug(F100,"ttopen TIOCGLTC ok","",0);
+ }
+ }
+#else
+ debug(F100,"ttopen TIOCGLTC not defined","",0);
+#endif /* TIOCGLTC */
+
+#ifdef TIOCLGET
+ debug(F100,"ttopen TIOCLGET","",0);
+ lmodef = 0;
+ if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
+ debug(F100,"ttopen TIOCLGET failed","",0);
+ } else {
+ lmodef = 1;
+ debug(F100,"ttopen TIOCLGET ok","",0);
+ }
+#endif /* TIOCLGET */
+
+#ifdef BELLV10
+ ioctl(ttyfd,TIOCGETP,&ttraw);
+ ioctl(ttyfd,TIOCGETP,&tttvt);
+#else
+ gtty(ttyfd,&ttraw); /* And a copy of it for packets*/
+ gtty(ttyfd,&tttvt); /* And one for virtual tty service */
+#endif /* BELLV10 */
+
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+/* Section for changing line discipline. It's restored in ttres(). */
+
+#ifdef AIXRS
+#ifndef AIX41
+ { union txname ld_name; int ld_idx = 0;
+ ttld = 0;
+ do {
+ ld_name.tx_which = ld_idx++;
+ ioctl(ttyfd, TXGETCD, &ld_name);
+ if (!strncmp(ld_name.tx_name, "rts", 3))
+ ttld |= 1;
+ } while (*ld_name.tx_name);
+ debug(F101,"AIX line discipline","",ttld);
+ }
+#endif /* AIX41 */
+#endif /* AIXRS */
+
+#ifdef BSD41
+/* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
+ { int k;
+ ioctl(ttyfd, TIOCGETD, &ttld); /* Get and save line discipline */
+ debug(F101,"4.1bsd line discipline","",ttld);
+ k = OTTYDISC; /* Switch to "old" discipline */
+ k = ioctl(ttyfd, TIOCSETD, &k);
+ debug(F101,"4.1bsd tiocsetd","",k);
+ }
+#endif /* BSD41 */
+
+#ifdef aegis
+ /* This was previously done before the last two TCGETA or gtty above,
+ * in both the ATTSV and not-ATTSV case. If it is not okay to have only
+ * one copy if it here instead, give us a shout!
+ */
+ sio_$control((short)ttyfd, sio_$raw_nl, false, st);
+ if (xlocal) { /* ignore breaks from local line */
+ sio_$control((short)ttyfd, sio_$int_enable, false, st);
+ sio_$control((short)ttyfd, sio_$quit_enable, false, st);
+ }
+#endif /* aegis */
+
+#ifdef VXVE
+ ttraw.c_line = 0; /* STTY line 0 for VX/VE */
+ tttvt.c_line = 0; /* STTY line 0 for VX/VE */
+ ioctl(ttyfd,TCSETA,&ttraw);
+#endif /* vxve */
+
+/* If O_NDELAY was used during open(), then remove it now. */
+
+#ifdef O_NDELAY
+ debug(F100,"ttopen O_NDELAY","",0);
+ if (xlocal > 0) {
+ if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
+ debug(F100,"ttopen fcntl O_NDELAY","",0);
+#ifndef aegis
+ if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
+ debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
+ perror("Can't unset O_NDELAY");
+ }
+#endif /* aegis */
+ /* Some systems, notably Xenix (don't know how common this is in
+ * other systems), need special treatment to get rid of the O_NDELAY
+ * behaviour on read() with respect to carrier presence (i.e. read()
+ * returning 0 when carrier absent), even though the above fcntl()
+ * is enough to make read() wait for input when carrier is present.
+ * This magic, in turn, requires CLOCAL for working when the carrier
+ * is absent. But if xlocal == 0, presumably you already have CLOCAL
+ * or you have a carrier, otherwise you wouldn't be running this.
+ */
+ debug(F101,"ttopen xlocal","",xlocal);
+#ifdef ATTSV
+#ifdef BSD44ORPOSIX
+#ifdef COMMENT /* 12 Aug 1997 */
+#ifdef __bsdi__
+ if (xlocal)
+ ttraw.c_cflag |= CLOCAL;
+#else
+#ifdef __FreeBSD__
+ if (xlocal)
+ ttraw.c_cflag |= CLOCAL;
+#endif /* __FreeBSD__ */
+#endif /* __bsdi__ */
+#else /* Not COMMENT */
+#ifdef CLOCAL
+ if (xlocal) /* Unset this if it's defined. */
+ ttraw.c_cflag |= CLOCAL;
+#endif /* CLOCAL */
+#endif /* COMMENT */
+ debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
+ if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
+ debug(F100,"ttopen POSIX tcseattr fails","",0);
+ perror("tcsetattr");
+ }
+#else /* !BSD44ORPOSIX */
+ if (xlocal) {
+ ttraw.c_cflag |= CLOCAL;
+ debug(F100,"ttopen calling ioctl(TCSETA)","",0);
+ errno = 0;
+ if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
+ debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
+ perror("ioctl(TCSETA)");
+ }
+ }
+#endif /* BSD44ORPOSIX */
+#endif /* ATTSV */
+#ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
+/* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
+ debug(F100,"ttopen executing close/open","",0);
+ close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
+#endif /* NOCOTFMC */
+ }
+ }
+#endif /* O_NDELAY */
+
+/* Instruct the system how to treat the carrier, and set a few other tty
+ * parameters.
+ *
+ * This also undoes the temporary setting of CLOCAL that may have been done
+ * for the close(open()) above (except in Xenix). Also throw in ~ECHO, to
+ * prevent the other end of the line from sitting there talking to itself,
+ * producing garbage when the user performs a connect.
+ *
+ * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
+ * Now it thinks CLOCAL is always on. It seems the only real solution for
+ * Xenix is to switch between the lower and upper case device names.
+ *
+ * This section may at some future time expand into setting a complete
+ * collection of tty parameters, or call a function shared with ttpkt()/
+ * ttvt() that does so. On the other hand, the initial parameters are not
+ * that important, since ttpkt() or ttvt() should always fix that before
+ * any communication is done. Well, we'll see...
+ */
+ if (xlocal) {
+ curcarr = -2;
+ debug(F100,"ttopen calling carrctl","",0);
+ carrctl(&ttraw, ttcarr == CAR_ON);
+ debug(F100,"ttopen carrctl ok","",0);
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef SVORPOSIX
+ ttraw.c_lflag &= ~ECHO;
+ ttold.c_lflag &= ~ECHO;
+#ifdef BSD44ORPOSIX
+ y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
+ debug(F101,"ttopen tcsetattr","",y);
+#else
+ y = ioctl(ttyfd, TCSETA, &ttraw);
+ debug(F100,"ttopen ioctl","",y);
+#endif /* BSD44ORPOSIX */
+
+#else /* BSD, etc */
+ ttraw.sg_flags &= ~ECHO;
+ ttold.sg_flags &= ~ECHO;
+#ifdef BELLV10
+ y = ioctl(ttyfd,TIOCSETP,&ttraw);
+ debug(F100,"ttopen ioctl","",y);
+#else
+ y = stty(ttyfd,&ttraw);
+ debug(F100,"ttopen stty","",y);
+#endif /* BELLV10 */
+#endif /* SVORPOSIX */
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+ /* ttflui(); */ /* This fails for some reason. */
+ }
+
+ /* Get current speed */
+
+#ifndef BEBOX
+ ttspeed = ttgspd();
+#else
+ ttspeed = 19200;
+#endif /* !BEBOX */
+ debug(F101,"ttopen ttspeed","",ttspeed);
+
+ /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
+
+ debug(F101,"ttopen ttyfd","",ttyfd);
+ debug(F101,"ttopen *lcl","",*lcl);
+ debug(F111,"ttopen lock file",flfnam,lkf);
+ signal(SIGINT,occt);
+ sigint_ign = (occt == SIG_IGN) ? 1 : 0;
+ gotsigs = 0;
+ return(0);
+}
+
+
+/* D O _ O P E N -- Do the right kind of open() call for the tty. */
+
+int
+do_open(ttname) char *ttname; {
+ int flags;
+
+#ifdef QNX6
+ /* O_NONBLOCK on /dev/tty makes open() fail */
+ return(priv_opn(ttname, O_RDWR |
+ (
+ ((int)strcmp(ttname,"/dev/tty") == 0) ?
+ 0 :
+ (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
+ )
+ );
+#else /* !QNX6 */
+
+#ifndef O_NDELAY /* O_NDELAY not defined */
+ return(priv_opn(ttname,2));
+#else /* O_NDELAY defined */
+
+#ifdef ATT7300
+/*
+ Open comms line without waiting for carrier so initial call does not hang
+ because state of "modem" is likely unknown at the initial call -jrd.
+ If this is needed for the getty stuff to work, and the open would not work
+ without O_NDELAY when getty is still on, then this special case is ok.
+ Otherwise, get rid of it. -ske
+*/
+ return(priv_opn(ttname, O_RDWR | O_NDELAY));
+
+#else /* !ATT7300 */
+
+ /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
+ flags = O_RDWR;
+ debug(F101,"do_open xlocal","",xlocal);
+ debug(F111,"do_open flags A",ttname,flags);
+ if (xlocal && (ttcarr != CAR_ON))
+ flags |= O_NDELAY;
+ debug(F111,"do_open flags B",ttname,flags);
+ return(priv_opn(ttname, flags));
+#endif /* !ATT7300 */
+#endif /* O_NDELAY */
+#endif /* QNX6 */
+}
+
+/* T T C L O S -- Close the TTY, releasing any lock. */
+
+static int ttc_state = 0; /* ttclose() state */
+static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
+
+int
+ttclos(foo) int foo; { /* Arg req'd for signal() prototype */
+ int xx, x = 0;
+ extern int exithangup;
+
+ debug(F101,"ttclos ttyfd","",ttyfd);
+ debug(F101,"ttclos netconn","",netconn);
+ debug(F101,"ttclos xlocal","",xlocal);
+#ifdef NOFDZERO
+ debug(F100,"ttclos NOFDZERO","",0);
+#endif /* NOFDZERO */
+
+#ifdef COMMENT
+#ifdef TTLEBUF
+ le_init(); /* No need for any of this */
+#endif /* TTLEBUF */
+#endif /* COMMENT */
+
+ if (ttyfd < 0) /* Wasn't open. */
+ return(0);
+
+ if (ttfdflg) /* If we inherited ttyfd from */
+ return(0); /* another process, don't close it. */
+
+ tvtflg = 0; /* (some day get rid of this...) */
+ gotsigs = 0;
+
+#ifdef IKSD
+ if (inserver) {
+#ifdef TNCODE
+ tn_push(); /* Place any waiting data into input*/
+ tn_sopt(DO,TELOPT_LOGOUT); /* Send LOGOUT option before close */
+ TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
+ tn_reset(); /* The Reset Telnet Option table. */
+#endif /* TNCODE */
+#ifdef CK_SSL
+ if (ssl_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
+ SSL_shutdown(ssl_con);
+ SSL_free(ssl_con);
+ ssl_con = NULL;
+ ssl_active_flag = 0;
+ }
+ if (tls_active_flag) {
+ if (ssl_debug_flag)
+ BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
+ SSL_shutdown(tls_con);
+ SSL_free(tls_con);
+ tls_con = NULL;
+ tls_active_flag = 0;
+ }
+#endif /* CK_SSL */
+ }
+#endif /* IKSD */
+#ifdef NETCMD
+ if (ttpipe) { /* We've been using a pipe */
+ /* ttpipe = 0; */
+ if (ttpid > 0) {
+ int wstat;
+ int statusp;
+ close(fdin); /* Close these. */
+ close(fdout);
+ fdin = fdout = -1;
+ kill(ttpid,1); /* Kill fork with SIGHUP */
+ while (1) {
+ wstat = wait(&statusp);
+ if (wstat == ttpid || wstat == -1)
+ break;
+ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
+ }
+ ttpid = 0;
+ }
+ netconn = 0;
+ wasclosed = 1;
+ ttyfd = -1;
+ return(0);
+ }
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) {
+#ifndef NODOPTY
+ end_pty();
+#endif /* NODOPTY */
+ close(ttyfd);
+ netconn = 0;
+ wasclosed = 1;
+ ttpty = 0;
+ ttyfd = -1;
+ return(0);
+ }
+#endif /* NETPTY */
+
+#ifdef NETCONN
+ if (netconn) { /* If it's a network connection. */
+ debug(F100,"ttclos closing net","",0);
+ netclos(); /* Let the network module close it. */
+ netconn = 0; /* No more network connection. */
+ debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
+ return(0);
+ }
+#endif /* NETCONN */
+
+ if (xlocal) { /* We're closing a SET LINE device */
+#ifdef FT21 /* Fortune 2.1-specific items ... */
+ ioctl(ttyfd,TIOCHPCL, NULL);
+#endif /* FT21 */
+#ifdef ultrix /* Ultrix-specific items ... */
+#ifdef TIOCSINUSE
+ /* Unset the INUSE flag that we set in ttopen() */
+ ioctl(ttyfd, TIOCSINUSE, NULL);
+#endif /* TIOCSINUSE */
+ ioctl(ttyfd, TIOCNMODEM, &x);
+#ifdef COMMENT
+ /* What was this? */
+ ioctl(ttyfd, TIOCNCAR, NULL);
+#endif /* COMMENT */
+#endif /* ultrix */
+ }
+
+ /* This is to prevent us from sticking in tthang() or close(). */
+
+#ifdef O_NDELAY
+#ifndef aegis
+ if (ttyfd > 0) { /* But skip it on stdin. */
+ debug(F100,"ttclos setting O_NDELAY","",0);
+ x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
+#ifdef DEBUG
+ if (deblog && x == -1) {
+ perror("Warning - Can't set O_NDELAY");
+ debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
+ }
+#endif /* DEBUG */
+ }
+#endif /* aegis */
+#endif /* O_NDELAY */
+
+ x = 0;
+ ttc_state = 0;
+ if (xlocal
+#ifdef NOFDZERO
+ || ttyfd > 0
+#endif /* NOFDZERO */
+ ) {
+ saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
+ xx = alarm(8); /* Allow 8 seconds. */
+ debug(F101,"ttclos alarm","",xx);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer went off? */
+ x = -1;
+#ifdef DEBUG
+ debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
+ printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
+#endif /* DEBUG */
+ }
+ /* Hang up the device (drop DTR) */
+
+ errno = 0;
+ debug(F111,"ttclos A",ckitoa(x),ttc_state);
+ if (ttc_state < 1) {
+ ttc_state = 1;
+ debug(F101,"ttclos exithangup","",exithangup);
+ if (exithangup) {
+ alarm(8); /* Re-arm the timer */
+ debug(F101,"ttclos calling tthang()","",x);
+ x = tthang(); /* Hang up first, then... */
+ debug(F101,"ttclos tthang()","",x);
+ }
+#ifndef CK_NOHUPCL
+/*
+ Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
+ Suggested by Soewono Effendi.
+*/
+#ifdef HUPCL
+ else {
+ ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
+#ifdef BSD44ORPOSIX
+ tcsetattr(ttyfd,TCSANOW,&ttold);
+#else /* !BSD44ORPOSIX */
+#ifdef ATTSV
+ ioctl(ttyfd,TCSETAW,&ttold);
+#else /* !ATTSV */
+ stty(ttyfd,&ttold);
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ }
+#endif /* HUPCL */
+#endif /* CK_NOHUPCL */
+ }
+ /* Put back device modes as we found them */
+
+ errno = 0;
+ debug(F111,"ttclos B",ckitoa(x),ttc_state);
+ if (ttc_state < 2) {
+ ttc_state = 2;
+ /* Don't try to mess with tty modes if tthang failed() */
+ /* since it probably won't work. */
+ if (x > -1) {
+ debug(F101,"ttclos calling ttres()","",x);
+ signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
+ alarm(8); /* Re-arm the timer */
+ x = ttres(); /* Reset device modes. */
+ debug(F101,"ttclos ttres()","",x);
+ alarm(0);
+ }
+ }
+ /* Close the device */
+
+ errno = 0;
+ debug(F101,"ttclos C","",ttc_state);
+ if (ttc_state < 3) {
+ ttc_state = 3;
+ errno = 0;
+ debug(F101,"ttclos calling close","",x);
+ signal(SIGALRM,xtimerh); /* Re-enable alarm. */
+ alarm(8); /* Re-arm the timer */
+ x = close(ttyfd); /* Close the device. */
+ debug(F101,"ttclos close()","",x);
+ if (x > -1)
+ ttc_state = 3;
+ }
+ debug(F101,"ttclos D","",ttc_state);
+ ttimoff(); /* Turn off timer. */
+ if (x < 0) {
+ printf("?WARNING - close failed: %s\n",ttnmsv);
+#ifdef DEBUG
+ if (deblog) {
+ printf("errno = %d\n", errno);
+ debug(F101,"ttclos failed","",errno);
+ }
+#endif /* DEBUG */
+ }
+ /* Unlock after closing but before any getty mumbo jumbo */
+
+ debug(F100,"ttclos about to call ttunlck","",0);
+ if (ttunlck()) /* Release uucp-style lock */
+ fprintf(stderr,"Warning, problem releasing lock\r\n");
+ }
+
+/* For bidirectional lines, restore getty if it was there before. */
+
+#ifdef ACUCNTRL /* 4.3BSD acucntrl() method. */
+ if (xlocal) {
+ debug(F100,"ttclos ACUCNTRL","",0);
+ acucntrl("enable",ttnmsv); /* Enable getty on the device. */
+ }
+#else
+#ifdef ATT7300 /* ATT UNIX PC (3B1, 7300) method. */
+ if (xlocal) {
+ debug(F100,"ttclos ATT7300 ongetty","",0);
+ if (attmodem & DOGETY) /* Was getty(1m) running before us? */
+ ongetty(ttnmsv); /* Yes, restart getty on tty line */
+ attmodem &= ~DOGETY; /* No phone in use, getty restored */
+ }
+#endif /* ATT7300 */
+#endif /* System-dependent getty-restoring methods */
+
+#ifdef sony_news
+ km_ext = -1; /* Invalidate device's Kanji-mode */
+#endif /* sony_news */
+
+ ttyfd = -1; /* Invalidate the file descriptor. */
+ wasclosed = 1;
+ debug(F100,"ttclos done","",0);
+ return(0);
+}
+
+/* T T H A N G -- Hangup phone line or network connection. */
+/*
+ Returns:
+ 0 if it does nothing.
+ 1 if it believes that it hung up successfully.
+ -1 if it believes that the hangup attempt failed.
+*/
+
+#define HUPTIME 500 /* Milliseconds for hangup */
+
+#ifdef COMMENT
+/* The following didn't work but TIOCSDTR does work */
+#ifdef UNIXWARE
+/* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
+#ifndef POSIX /* Such as Unixware 1.x, 2.x */
+#ifndef HUP_POSIX
+#define HUP_POSIX
+#endif /* HUP_POSIX */
+#endif /* POSIX */
+#endif /* UNIXWARE */
+#endif /* COMMENT */
+
+#ifndef USE_TIOCSDTR
+#ifdef __NetBSD__
+/* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
+#ifdef TIOCSDTR
+#ifdef TIOCCDTR
+#define USE_TIOCSDTR
+#endif /* TIOCCDTR */
+#endif /* TIOCSDTR */
+#endif /* __NetBSD__ */
+#endif /* USE_TIOCSDTR */
+
+#ifndef HUP_CLOSE_POSIX
+#ifdef OU8
+#define HUP_CLOSE_POSIX
+#else
+#ifdef CK_SCOV5
+#define HUP_CLOSE_POSIX
+#endif /* CK_SCOV5 */
+#endif /* OU8 */
+#endif /* HUP_CLOSE_POSIX */
+
+#ifdef NO_HUP_CLOSE_POSIX
+#ifdef HUP_CLOSE_POSIX
+#undef HUP_CLOSE_POSIX
+#endif /* HUP_CLOSE_POSIX */
+#endif /* NO_HUP_CLOSE_POSIX */
+
+int
+tthang() {
+#ifdef NOLOCAL
+ return(0);
+#else
+ int x = 0; /* Sometimes used as return code. */
+#ifndef POSIX
+ int z; /* worker */
+#endif /* POSIX */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef SVORPOSIX /* AT&T, POSIX, HPUX declarations. */
+ int spdsav; /* for saving speed */
+#ifdef HUP_POSIX
+ int spdsavi;
+#else
+#ifdef BSD44ORPOSIX
+ int spdsavi;
+#endif /* BSD44ORPOSIX */
+#endif /* HUP_POSIX */
+#ifdef HPUX
+/*
+ Early versions of HP-UX omitted the mflag typedef. If you get complaints
+ about it, just change it to long (or better still, unsigned long).
+*/
+ mflag
+ dtr_down = 00000000000,
+ modem_rtn,
+ modem_sav;
+ char modem_state[64];
+#endif /* HPUX */
+ int flags; /* fcntl flags */
+ unsigned short ttc_save;
+#endif /* SVORPOSIX */
+
+ if (ttyfd < 0) return(0); /* Don't do this if not open */
+ if (xlocal < 1) return(0); /* Don't do this if not local */
+
+#ifdef NETCMD
+ if (ttpipe)
+ return((ttclos(0) < 0) ? -1 : 1);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty)
+ return((ttclos(0) < 0) ? -1 : 1);
+#endif /* NETPTY */
+#ifdef NETCONN
+ if (netconn) { /* Network connection. */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = tnc_set_dtr_state(0);
+ if (rc >= 0) {
+ msleep(HUPTIME);
+ rc = tnc_set_dtr_state(1);
+ }
+ return(rc >= 0 ? 1 : -1);
+ } else
+#endif /* TN_COMPORT */
+ return((netclos() < 0) ? -1 : 1); /* Just close it. */
+ }
+#endif /* NETCONN */
+
+/* From here down, we handle real tty devices. */
+#ifdef HUP_POSIX
+/*
+ e.g. for Unixware 2, where we don't have a full POSIX build, we
+ still have to use POSIX-style hangup. Thus the duplication of this
+ and the next case, the only difference being we use a local termios
+ struct here, since a different model is used elsewhere.
+
+ NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
+ even though it compiles and executes without error, doesn't actually
+ work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
+*/
+ {
+ struct termios ttcur;
+ int x;
+ debug(F100,"tthang HUP_POSIX style","",0);
+ x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */
+ debug(F111,"tthang tcgetattr",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ spdsav = cfgetospeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
+ spdsavi = cfgetispeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
+ x = cfsetospeed(&ttcur,B0); /* Replace by 0 */
+ debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = cfsetispeed(&ttcur,B0);
+ debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ msleep(HUPTIME); /* Sleep 0.5 sec */
+ x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
+ if (x < 0) return(-1);
+ debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
+ x = cfsetispeed(&ttcur,spdsavi);
+ debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ return(1);
+ }
+#else
+#ifdef BSD44ORPOSIX
+#ifdef QNX
+ {
+ int x;
+ x = tcdropline(ttyfd,500);
+ debug(F101,"tthang QNX tcdropline","",x);
+ ttcur.c_cflag |= CLOCAL;
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F101,"tthang QNX tcsetattr restore","",x);
+ if (x < 0) {
+ debug(F101,"tthang QNX tcsetattr restore errno","",errno);
+ return(-1);
+ }
+ /* Fix flags - ensure O_NONBLOCK is off */
+
+ errno = 0;
+ debug(F101,"tthang QNX iniflags","",iniflags);
+ if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
+ debug(F101,"tthang QNX F_SETFL errno","",errno);
+ return(-1);
+ }
+ return(x);
+ }
+#else /* QNX */
+ {
+ int x;
+#ifdef USE_TIOCSDTR
+ debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
+ errno = 0;
+ x = ioctl(ttyfd, TIOCCDTR, NULL);
+ debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ msleep(HUPTIME); /* Sleep 0.5 sec */
+ errno = 0;
+ x = ioctl(ttyfd, TIOCSDTR, NULL);
+ debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
+ if (x < 0) return(-1);
+#else /* USE_TIOCSDTR */
+
+#ifdef HUP_CLOSE_POSIX
+/*
+ In OSR5 versions where TIOCSDTR is not defined (up to and including at
+ least 5.0.6a) the POSIX APIs in the "#else" part below are available but
+ don't work, and no other APIs are available that do work. In this case
+ we have to drop DTR by brute force: close and reopen the port. This
+ code actually works, but all the steps are crucial: setting CLOCAL, the
+ O_NDELAY manipulations, etc.
+*/
+ debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
+ debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
+ debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
+ errno = 0;
+ x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */
+ debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
+ if (x < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
+ return(-1);
+ }
+ errno = 0;
+
+ x = close(ttyfd); /* Close without releasing lock */
+ if (x < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
+ return(-1);
+ }
+ errno = 0;
+ x = msleep(500); /* Pause half a second */
+ if (x < 0) { /* Or if that doesn't work, 1 sec */
+ debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
+ sleep(1);
+ }
+ errno = 0;
+ ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
+ debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
+ if (ttyfd < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
+ return(-1);
+ }
+ debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
+
+ /* Restore previous attributes */
+
+ errno = 0;
+ tvtflg = 0;
+ ttcur.c_cflag |= CLOCAL;
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
+ if (x < 0) {
+ debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
+ "",errno);
+ return(-1);
+ }
+ /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
+
+ errno = 0;
+ if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
+ debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
+ return(-1);
+ }
+ debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
+ errno = 0;
+ x &= ~(O_NONBLOCK|O_NDELAY);
+ debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
+ debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
+ if (fcntl(ttyfd, F_SETFL, x) == -1) {
+ debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
+ return(-1);
+ }
+#ifdef DEBUG
+ if (deblog) {
+ if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
+ debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
+ debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
+ "",x&O_NONBLOCK);
+ debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
+ "",x&O_NDELAY);
+ }
+ }
+#endif /* DEBUG */
+
+#else /* HUP_CLOSE_POSIX */
+
+ /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
+
+ debug(F100,"tthang BSD44ORPOSIX B0","",0);
+ x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */
+ debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ spdsav = cfgetospeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
+ spdsavi = cfgetispeed(&ttcur); /* Get current speed */
+ debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
+ x = cfsetospeed(&ttcur,B0); /* Replace by 0 */
+ debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ x = cfsetispeed(&ttcur,B0);
+ debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ msleep(HUPTIME); /* Sleep 0.5 sec */
+ debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
+ x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
+ debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
+ x = cfsetispeed(&ttcur,spdsavi);
+ debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
+ if (x < 0) return(-1);
+ ttcur.c_cflag |= CLOCAL; /* Don't expect CD after hangup */
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
+ if (x < 0) return(-1);
+
+#endif /* HUP_CLOSE_POSIX */
+#endif /* USE_TIOCSDTR */
+
+ return(1);
+ }
+
+#endif /* QNX */
+#else /* BSD44ORPOSIX */
+
+#ifdef aegis /* Apollo Aegis */
+ sio_$control((short)ttyfd, sio_$dtr, false, st); /* DTR down */
+ msleep(HUPTIME); /* pause */
+ sio_$control((short)ttyfd, sio_$dtr, true, st); /* DTR up */
+ return(1);
+#endif /* aegis */
+
+#ifdef ANYBSD /* Any BSD version. */
+#ifdef TIOCCDTR /* Except those that don't have this */
+ debug(F100,"tthang BSD style","",0);
+ if (ioctl(ttyfd,TIOCCDTR,0) < 0) { /* Clear DTR. */
+ debug(F101,"tthang TIOCCDTR fails","",errno);
+ return(-1);
+ }
+ msleep(HUPTIME); /* For about 1/2 sec */
+ errno = 0;
+ x = ioctl(ttyfd,TIOCSDTR,0); /* Restore DTR */
+ if (x < 0) {
+ /*
+ For some reason, this tends to fail with "no such device or address"
+ but the operation still works, probably because of the close/open
+ later on. So let's not scare the user unnecessarily here.
+ */
+ debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
+ x = 1; /* Pretend we succeeded */
+ } else if (x == 0) x = 1; /* Success */
+#ifdef COMMENT
+#ifdef FT21
+ ioctl(ttyfd, TIOCSAVEMODES, 0);
+ ioctl(ttyfd, TIOCHPCL, 0);
+ close(ttyfd); /* Yes, must do this twice */
+ if ((ttyfd = open(ttnmsv,2)) < 0) /* on Fortune computers... */
+ return(-1); /* (but why?) */
+ else x = 1;
+#endif /* FT21 */
+#endif /* COMMENT */
+#endif /* TIOCCDTR */
+ close(do_open(ttnmsv)); /* Clear i/o error condition */
+ errno = 0;
+#ifdef COMMENT
+/* This is definitely dangerous. Why was it here? */
+ z = ttvt(ttspeed,ttflow); /* Restore modes. */
+ debug(F101,"tthang ttvt returns","",z);
+ return(z < 0 ? -1 : 1);
+#else
+ return(x);
+#endif /* COMMENT */
+#endif /* ANYBSD */
+
+#ifdef ATTSV
+/* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
+
+#ifdef HPUX
+/* Hewlett Packard allows explicit manipulation of modem signals. */
+
+#ifdef COMMENT
+/* Old way... */
+ debug(F100,"tthang HP-UX style","",0);
+ if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0) /* lower DTR */
+ return(-1); /* oops, can't. */
+ msleep(HUPTIME); /* Pause half a second. */
+ x = 1; /* Set return code */
+ if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
+ if ((modem_rtn & MDCD) != 0) /* Check if CD is low. */
+ x = -1; /* CD didn't drop, fail. */
+ } else x = -1;
+
+ /* Even if above calls fail, RTS & DTR should be turned back on. */
+ modem_rtn = MRTS | MDTR;
+ if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
+ return(x);
+#else
+/* New way, from Hellmuth Michaelis */
+ debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
+ if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
+ debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
+ return(-1);
+ }
+ sprintf(modem_state,"%#lx",modem_rtn);
+ debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
+ modem_sav = modem_rtn; /* Save current modem signals */
+ modem_rtn &= ~MDTR; /* Turn DTR bit off */
+ sprintf(modem_state,"%#lx",modem_rtn);
+ debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
+ if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
+ debug(F100,"tthang HP-UX: can't lower DTR!","",0);
+ return(-1); /* oops, can't. */
+ }
+ msleep(HUPTIME); /* Pause half a second. */
+ x = 1; /* Set return code */
+ if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
+ sprintf(modem_state,"%#lx",modem_rtn);
+ debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
+ if ((modem_rtn & MDCD) != 0) { /* Check if CD is low. */
+ debug(F100,"tthang HP-UX: DCD not down","",0);
+ x = -1; /* CD didn't drop, fail. */
+ } else {
+ debug(F100,"tthang HP-UX: DCD down","",0);
+ }
+ } else {
+ x = -1;
+ debug(F100,"tthang HP-UX: can't get DCD status !","",0);
+ }
+
+ /* Even if above calls fail, DTR should be turned back on. */
+
+ modem_sav |= MDTR;
+ if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
+ x = -1;
+ debug(F100,"tthang HP-UX: can't set saved state","",0);
+ } else {
+ sprintf(modem_state,"%#lx",modem_sav);
+ debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
+ }
+ return(x);
+#endif /* COMMENT */
+
+#else /* AT&T but not HP-UX */
+
+/* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
+/* It is not known how many, if any, systems actually implement them, */
+/* so we include them here in ifdef's. */
+
+/*
+ Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
+ gives error 22 (invalid argument).
+*/
+#ifndef _IBMR2
+/*
+ No modem-signal twiddling for IBM RT PC or RS/6000.
+ In AIX 3.1 and earlier, the ioctl() call is broken.
+ This code could be activated for AIX 3.1 with PTF 2006 or later
+ (e.g. AIX 3.2), but close/open does the job too, so why bother.
+*/
+#ifdef TIOCMBIS /* Bit Set */
+#ifdef TIOCMBIC /* Bit Clear */
+#ifdef TIOCM_DTR /* DTR */
+
+/* Clear DTR, sleep 300 msec, turn it back on. */
+/* If any of the ioctl's return failure, go on to the next section. */
+
+ z = TIOCM_DTR; /* Code for DTR. */
+#ifdef COMMENT
+/*
+ This was the cause of the troubles with the Solaris Port Monitor.
+ The problem is: RTS never comes back on. Moral: Don't do it!
+ (But why doesn't it come back on? See the TIOCMBIS call...)
+*/
+#ifdef TIOCM_RTS /* Lower RTS too if symbol is known. */
+ z |= TIOCM_RTS;
+#endif /* TIOCM_RTS */
+#endif /* COMMENT */
+
+ debug(F101,"tthang TIOCM signal mask","",z);
+ if (ioctl(ttyfd,TIOCMBIC,&z) > -1) { /* Try to lower DTR. */
+ debug(F100,"tthang TIOCMBIC ok","",0);
+ msleep(HUPTIME); /* Pause half a second. */
+ if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
+ debug(F100,"tthang TIOCMBIS ok","",0);
+#ifndef CLSOPN
+ return(1); /* Success, done. */
+#endif /* CLSOPN */
+ } else { /* Couldn't raise, continue. */
+ debug(F101,"tthang TIOCMBIS errno","",errno);
+ }
+ } else { /* Couldn't lower, continue. */
+ debug(F101,"tthang TIOCMBIC errno","",errno);
+ }
+#endif /* TIOCM_DTR */
+#endif /* TIOCMBIC */
+#endif /* TIOCMBIS */
+#endif /* _IBMR2 */
+
+/*
+ General AT&T UNIX case, not HPUX. The following code is highly suspect. No
+ two AT&T-based systems seem to do this the same way. The object is simply
+ to turn off DTR and then turn it back on. SVID says the universal method
+ for turning off DTR is to set the speed to zero, and this does seem to do
+ the trick in all cases. But neither SVID nor any known man pages say how to
+ turn DTR back on again. Some variants, like most Xenix implementations,
+ raise DTR again when the speed is restored to a nonzero value. Others
+ require the device to be closed and opened again, but this is risky because
+ getty could seize the device during the instant it is closed.
+*/
+
+/* Return code for ioctl failures... */
+#ifdef ATT6300
+ x = 1; /* ATT6300 doesn't want to fail... */
+#else
+ x = -1;
+#endif /* ATT6300 */
+
+ debug(F100,"tthang get settings","",0);
+ if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
+ return(x); /* Fail if this doesn't work. */
+ if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
+ return(x);
+ ttc_save = ttcur.c_cflag; /* Remember current speed. */
+ spdsav = ttc_save & CBAUD;
+ debug(F101,"tthang speed","",spdsav);
+
+#ifdef O_NDELAY
+ debug(F100,"tthang turning O_NDELAY on","",0);
+ fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
+#endif /* O_NDELAY */
+
+#ifdef ATT7300 /* This is the way it is SUPPOSED to work */
+ ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */
+#else
+#ifdef RTAIX
+ ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */
+#else /* This way really works but may be dangerous */
+#ifdef u3b2
+ ttcur.c_cflag = ~(CBAUD|CLOCAL); /* Special for AT&T 3B2s */
+ /* (CLOCAL must be OFF) */
+#else
+#ifdef SCO3R2 /* SCO UNIX 3.2 */
+/*
+ This is complete nonsense, but an SCO user claimed this change made
+ hanging up work. Comments from other SCO UNIX 3.2 users would be
+ appreciated.
+*/
+ ttcur.c_cflag = CBAUD|B0;
+#else
+#ifdef AIXRS /* AIX on RS/6000 */
+/*
+ Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
+ even though you can do it on the built-in port and the 8- and 16-port
+ adapters. (Untested on 128-port adapter.)
+*/
+ ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
+#else /* None of the above */
+/*
+ Set everything, including the speed, to zero, except for the CLOCAL
+ and HUPCL bits.
+*/
+ ttcur.c_cflag = CLOCAL|HUPCL;
+#endif /* AIXRS */
+#endif /* SCO3R2 */
+#endif /* u3b2 */
+#endif /* RTAIX */
+#endif /* ATT7300 */
+
+#ifdef COMMENT
+ /* and if none of those work, try one of these... */
+ ttcur.c_cflag = 0;
+ ttcur.c_cflag = CLOCAL;
+ ttcur.c_cflag &= ~(CBAUD|HUPCL);
+ ttcur.c_cflag &= ~(CBAUD|CREAD);
+ ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
+ /* or other combinations */
+#endif /* COMMENT */
+
+#ifdef TCXONC
+ debug(F100,"tthang TCXONC","",0);
+ if (ioctl(ttyfd, TCXONC, 1) < 0) {
+ debug(F101,"tthang TCXONC failed","",errno);
+ }
+#endif /* TCXONC */
+
+#ifdef TIOCSTART
+ debug(F100,"tthang TIOCSTART","",0);
+ if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
+ debug(F101,"tthang TIOCSTART failed","",errno);
+ }
+#endif /* TIOCSTART */
+
+ if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
+ debug(F101,"tthang TCSETAF failed","",errno);
+ fcntl(ttyfd, F_SETFL, flags); /* Restore flags */
+ return(-1); /* before returning. */
+ }
+ msleep(300); /* Give modem time to notice. */
+
+#ifndef NOCOTFMC
+
+/* Now, even though it doesn't say this in SVID or any man page, we have */
+/* to close and reopen the device. This is not necessary for all systems, */
+/* but it's impossible to predict which ones need it and which ones don't. */
+
+#ifdef ATT7300
+/*
+ Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
+ related ioctl's for their internal modems. attmodem has getty status and
+ modem-in-use bit. Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
+ but also ruins the file descriptor, and no other phone(7) ioctl call can fix
+ it. Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
+ The only way to undo the damage is to close the fd and then reopen it.
+*/
+ if (attmodem & ISMODEM) {
+ debug(F100,"tthang attmodem close/open","",0);
+ ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
+ ioctl(ttyfd,PIOCDISC,&dialer); /* Disconnect phone. */
+ close(ttyfd); /* Close and reopen the fd. */
+ ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
+ attmodem &= ~ISMODEM; /* Phone no longer in use. */
+ }
+#else /* !ATT7300 */
+/* It seems we have to close and open the device for other AT&T systems */
+/* too, and this is the place to do it. The following code does the */
+/* famous close(open(...)) magic by default. If that doesn't work for you, */
+/* then try uncommenting the following statement or putting -DCLSOPN in */
+/* the makefile CFLAGS. */
+
+/* #define CLSOPN */
+
+#ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
+
+#ifdef O_NDELAY
+#define OPENFLGS O_RDWR | O_NDELAY
+#else
+#define OPENFLGS O_RDWR
+#endif
+
+#ifndef CLSOPN
+/* This method is used by default, i.e. unless CLSOPN is defined. */
+/* It is thought to be safer because there is no window where getty */
+/* can seize control of the device. The drawback is that it might not work. */
+
+ debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
+ close(priv_opn(ttnmsv, OPENFLGS));
+
+#else
+/* This method is used if you #define CLSOPN. It is more likely to work */
+/* than the previous method, but it's also more dangerous. */
+
+ debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
+ close(ttyfd);
+ msleep(10);
+ ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
+#endif /* CLSOPN */
+#undef OPENFLGS
+
+#endif /* SCO32 */
+#endif /* ATT7300 */
+
+#endif /* NOCOTFMC */
+
+/* Now put all flags & modes back the way we found them. */
+/* (Does the order of ioctl & fcntl matter ? ) */
+
+ debug(F100,"tthang restore settings","",0);
+ ttcur.c_cflag = ttc_save; /* Get old speed back. */
+ if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
+ return(-1);
+#ifdef O_NDELAY
+/*
+ This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
+ After closing a modem line, the modem will probably not be asserting
+ carrier any more, so we should not require carrier any more. If this
+ causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
+ than O_NDELAY.
+*/
+ flags &= ~O_NDELAY; /* Don't require carrier on reopen */
+#endif /* O_NDELAY */
+ if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
+ return(-1);
+
+ return(1);
+#endif /* not HPUX */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#endif /* HUP_POSIX */
+#endif /* NOLOCAL */
+}
+
+/*
+ Major change in 5A(174). We used to use LPASS8, if it was defined, to
+ allow 8-bit data and Xon/Xoff flow control at the same time. But this
+ LPASS8 business seems to have been causing trouble for everybody but me!
+ For example, Annex terminal servers, commonly used with Encore computers,
+ do not support LPASS8 even though the Encore itself does. Ditto for many
+ other terminal servers, TELNET connections, rlogin connections, etc etc.
+ Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
+ serial lines, even though LPASS8 is a feature of 4.3BSD. So let's turn it
+ off for everybody. That means we goes back to using raw mode, with no
+ flow control. Phooey.
+
+ NOTE: This must be done before the first reference to LPASS8 in this file,
+ and after the last #include statment.
+*/
+#ifdef LPASS8
+#undef LPASS8
+#endif /* LPASS8 */
+
+/* T T R E S -- Restore terminal to "normal" mode. */
+
+/* ske@pkmab.se: There are two choices for what this function should do.
+ * (1) Restore the tty to current "normal" mode, with carrier treatment
+ * according to ttcarr, to be used after every kermit command. (2) Restore
+ * the tty to the state it was in before kermit opened it. These choices
+ * conflict, since ttold can't hold both choices of tty parameters. ttres()
+ * is currently being called as in choice (1), but ttold basically holds
+ * the initial parameters, as in (2), and the description at the beginning
+ * of this file says (2).
+ *
+ * I don't think restoring tty parameters after all kermit commands makes
+ * much of a difference. Restoring them upon exit from kermit may be of
+ * some use in some cases (when the line is not restored automatically on
+ * close, by the operating system).
+ *
+ * I can't choose which one it should be, so I haven't changed it. It
+ * probably works as it is, too. It would probably even work even with
+ * ttres() entirely deleted...
+ *
+ * (from fdc: Actually, this function operates in remote mode too, so
+ * it restores the console (command) terminal to whatever mode it was
+ * in before packet operations began, so that commands work right again.)
+ */
+int
+ttres() { /* Restore the tty to normal. */
+ int x;
+
+ if (ttyfd < 0) return(-1); /* Not open. */
+
+ if (ttfdflg) return(0); /* Don't mess with terminal modes if */
+ /* we got ttyfd from another process */
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+ tvtflg = 0;
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+ {
+ extern int tcp_nodelay; /* Just put this back if necessary */
+ if (ttnet == NET_TCPB) {
+ if (nodelay_sav > -1) {
+ no_delay(ttyfd,nodelay_sav);
+ nodelay_sav = -1;
+ }
+ }
+ }
+#endif /* TCP_NODELAY */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = -1;
+ if ((rc = tnsetflow(ttflow)) < 0)
+ return(rc);
+ if (ttspeed <= 0)
+ ttspeed = tnc_get_baud();
+ else if ((rc = tnc_set_baud(ttspeed)) < 0)
+ return(rc);
+ tnc_set_datasize(8);
+ tnc_set_stopsize(stopbits);
+
+#ifdef HWPARITY
+ if (hwparity) {
+ switch (hwparity) {
+ case 'e': /* Even */
+ debug(F100,"ttres 8 bits + even parity","",0);
+ tnc_set_parity(3);
+ break;
+ case 'o': /* Odd */
+ debug(F100,"ttres 8 bits + odd parity","",0);
+ tnc_set_parity(2);
+ break;
+ case 'm': /* Mark */
+ debug(F100,"ttres 8 bits + invalid parity: mark","",0);
+ tnc_set_parity(4);
+ break;
+ case 's': /* Space */
+ debug(F100,"ttres 8 bits + invalid parity: space","",0);
+ tnc_set_parity(5);
+ break;
+ }
+ } else
+#endif /* HWPARITY */
+ {
+ tnc_set_parity(1); /* None */
+ }
+ tvtflg = 0;
+ return(0);
+ }
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+ return(0);
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+/* Real terminal device, so restore its original modes */
+
+#ifdef BSD44ORPOSIX /* For POSIX like this */
+ debug(F100,"ttres BSD44ORPOSIX","",0);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
+#else /* For all others... */
+#ifdef ATTSV /* For AT&T versions... */
+ debug(F100,"ttres ATTSV","",0);
+ x = ioctl(ttyfd,TCSETAW,&ttold); /* Restore tty modes this way. */
+#else
+/* Here we restore the modes for BSD */
+
+#ifdef LPASS8 /* Undo "pass8" if it were done */
+ if (lmodef) {
+ if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
+ debug(F100,"ttres TIOCLSET failed","",0);
+ else
+ debug(F100,"ttres TIOCLSET ok","",0);
+ }
+#endif /* LPASS8 */
+
+#ifdef CK_DTRCTS /* Undo hardware flow if it were done */
+ if (lmodef) {
+ if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
+ debug(F100,"ttres TIOCLSET failed","",0);
+ else
+ debug(F100,"ttres TIOCLSET ok","",0);
+ }
+#endif /* CK_DTRCTS */
+
+#ifdef TIOCGETC /* Put back special characters */
+ if (tcharf && (xlocal == 0)) {
+ if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
+ debug(F100,"ttres TIOCSETC failed","",0);
+ else
+ debug(F100,"ttres TIOCSETC ok","",0);
+ }
+#endif /* TIOCGETC */
+
+#ifdef TIOCGLTC /* Put back local special characters */
+ if (ltcharf && (xlocal == 0)) {
+ if (ioctl(ttyfd,TIOCSLTC,<chold) < 0)
+ debug(F100,"ttres TIOCSLTC failed","",0);
+ else
+ debug(F100,"ttres TIOCSLTC ok","",0);
+ }
+#endif /* TIOCGLTC */
+
+#ifdef BELLV10
+ debug(F100,"ttres BELLV10","",0);
+ x = ioctl(ttyfd,TIOCSETP,&ttold); /* Restore both structs */
+ x = ioctl(ttyfd,TIOCSDEV,&tdold);
+#else
+ debug(F100,"ttres stty","",0);
+ x = stty(ttyfd,&ttold); /* Restore tty modes the old way. */
+#endif /* BELLV10 */
+
+ if (!xlocal)
+ msleep(100); /* This replaces sleep(1)... */
+ /* Put back sleep(1) if tty is */
+ /* messed up after close. */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+ debug(F101,"ttres result","",x);
+#ifndef QNX
+ if (x < 0) debug(F101,"ttres errno","",errno);
+#endif /* QNX */
+
+#ifdef AIXRS
+#ifndef AIX41
+ x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
+ debug(F101,"ttres AIX line discipline rts restore","",x);
+#endif /* AIX41 */
+#endif /* AIXRS */
+
+#ifdef BSD41
+ if (ttld > -1) { /* Put back line discipline */
+ x = ioctl(ttyfd, TIOCSETD, &ttld);
+ debug(F101,"ttres BSD41 line discipline restore","",x);
+ if (x < 0) debug(F101,"...ioctl errno","",errno);
+ ttld = -1;
+ }
+#endif /* BSD41 */
+
+#ifdef sony_news
+ x = xlocal ? km_ext : km_con; /* Restore Kanji mode. */
+ if (x != -1) { /* Make sure we know original modes. */
+ if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
+ perror("ttres can't set Kanji mode");
+ debug(F101,"ttres error setting Kanji mode","",x);
+ return(-1);
+ }
+ }
+ debug(F100,"ttres set Kanji mode ok","",0);
+#endif /* sony_news */
+
+ tvtflg = 0; /* Invalidate terminal mode settings */
+ debug(F101,"ttres return code","",x);
+ return(x);
+}
+
+#ifndef NOUUCP
+
+/* T T C H K P I D -- Check lockfile pid */
+/*
+ Read pid from lockfile named f, check that it's still valid.
+ If so, return 1.
+ On failure to read pid, return 1.
+ Otherwise, try to delete lockfile f and return 0 if successful, else 1.
+*/
+static int
+ttchkpid(f) char *f; {
+ int pid, mypid, x;
+ pid = ttrpid(f); /* Read pid from file. */
+ if (pid > -1) { /* If we were able to read the pid.. */
+ debug(F101,"ttchkpid lock pid","",pid);
+ errno = 0; /* See if process still exists. */
+ mypid = (int)getpid(); /* Get my own pid. */
+ debug(F101,"ttchkpid my pid","",mypid);
+ if (pid == mypid) { /* It's me! */
+ x = -1; /* So I can delete it */
+ errno = ESRCH; /* pretend it's invalid */
+ } else { /* It's not me */
+ x = kill((PID_T)pid, 0); /* See if it's a live process */
+ debug(F101,"ttchkpid kill errno","",errno);
+ }
+ debug(F101,"ttchkpid pid test","",x);
+ if (x < 0 && errno == ESRCH) { /* pid is invalid */
+ debug(F111,"removing stale lock",f,pid);
+ if (!backgrd)
+ printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
+ priv_on();
+ x = unlink(f); /* Remove the lockfile. */
+ priv_off();
+ debug(F111,"ttchkpid unlink",f,x);
+ if (x > -1)
+ return(0); /* Device is not locked after all */
+ else if (!backgrd)
+ perror(f);
+ }
+ return(1);
+ }
+ return(1); /* Failure to read pid */
+}
+
+#ifdef HPUX
+
+/* Aliases (different drivers) for HP-UX dialout devices: */
+
+static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
+static int ttydexists = 0;
+
+#endif /* HPUX */
+
+/* T T R P I D -- Read pid from lockfile "name" */
+
+static int
+ttrpid(name) char *name; {
+ long len;
+ int x, fd, pid;
+ short spid;
+ char buf[32];
+
+ debug(F110,"ttrpid",name,0);
+ if (!name) return(-1);
+ if (!*name) return(-1);
+ priv_on();
+ len = zchki(name); /* Get file length */
+ priv_off();
+ debug(F101,"ttrpid zchki","",len);
+ if (len < 0)
+ return(-1);
+ if (len > 31)
+ return(-1);
+ priv_on();
+ fd = open(name,O_RDONLY); /* Try to open lockfile. */
+ priv_off();
+ debug(F101,"ttrpid fd","",fd);
+ if (fd <= 0)
+ return(-1);
+/*
+ Here we try to be flexible and allow for all different binary and string
+ formats at runtime, rather than a specific format for each configuration
+ hardwired at compile time.
+*/
+ pid = -1;
+#ifndef COHERENT
+/*
+ COHERENT uses a string PID but without leading spaces or 0's, so there is
+ no way to tell from the file's length whether it contains a string or binary
+ pid. So for COHERENT only, we only allow string pids. For all others, we
+ decide based on the size of the lockfile.
+*/
+ if (len > 4) { /* If file > 4 bytes it's a string */
+#endif /* COHERENT */
+ x = read(fd,buf,(int)len);
+ debug(F111,"ttrpid string read",buf,x);
+ if (x < 0) {
+ pid = -1;
+ } else {
+ buf[31] = '\0';
+ x = sscanf(buf,"%d",&pid); /* Get the integer pid from it. */
+ }
+#ifndef COHERENT
+ } else if (len == 4) { /* 4 bytes so binary */
+ x = read(fd, (char *)&pid, 4); /* Read the bytes into an int */
+ debug(F101,"ttrpid integer read","",x);
+ if (x < 4)
+ pid = -1;
+ } else if (len == 2) { /* 2 bytes binary */
+ x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
+ debug(F101,"ttrpid short read","",x);
+ if (x < 2)
+ pid = -1;
+ else
+ pid = spid;
+ } else
+ pid = -1;
+#endif /* COHERENT */
+ close(fd); /* Close the lockfile */
+ debug(F101,"ttrpid pid","",pid);
+ return(pid);
+}
+#endif /* NOUUCP */
+
+/* T T L O C K */
+
+/*
+ This function attempts to coordinate use of the communication device with
+ other copies of Kermit and any other program that follows the UUCP
+ device-locking conventions, which, unfortunately, vary among different UNIX
+ implementations. The idea is to look for a file of a certain name, the
+ "lockfile", in a certain directory. If such a file is found, then the line
+ is presumed to be in use, and Kermit should not use it. If no such file is
+ found, Kermit attempts to create one so that other programs will not use the
+ same line at the same time. Because the lockfile and/or the directory it's
+ in might lack write permission for the person running Kermit, Kermit could
+ find itself running setuid to uucp or other user that does have the
+ necessary permissions. At startup, Kermit has changed its effective uid to
+ the user's real uid, and so ttlock() must switch back to the original
+ effective uid in order to create the lockfile, and then back again to the
+ real uid to prevent unauthorized access to other directories or files owned
+ by the user the program is setuid to.
+
+ Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
+ based on suggestions from Warren Tucker. Call with pointer to name of
+ tty device. Returns:
+
+ 0 on success
+ -1 on failure
+
+ Note: Once privileges are turned on using priv_on(), it is essential that
+ they are turned off again before this function returns.
+*/
+#ifdef SVR4 /* Lockfile uses device numbers. */
+/*
+ Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
+ it is the behavior of the "reference version" of SVR4, i.e. the Intel
+ port from UNIX Systems Laboratories, then called Univel UnixWare,
+ then called Novell UnixWare, then called SCO Unixware, then called Caldera
+ Open UNIX... It also makes much more sense than device-name-based lockfiles
+ since there can be multiple names for the same device, symlinks, etc.
+*/
+#ifndef NOLFDEVNO
+#ifndef LFDEVNO /* Define this for SVR4 */
+#ifndef AIXRS /* But not for RS/6000 AIX 3.2, etc. */
+#ifndef BSD44 /* If anybody else needs it... */
+#ifndef __386BSD__
+#ifndef __FreeBSD__
+#ifndef HPUX10
+#ifndef IRIX51 /* SGI IRIX 5.1 or later */
+#ifndef CK_SCOV5 /* SCO Open Server 5.0 */
+#define LFDEVNO
+#endif /* CK_SCOV5 */
+#endif /* IRIX51 */
+#endif /* HPUX10 */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#endif /* BSD44 */
+#endif /* AIXRS */
+#endif /* LFDEVNO */ /* ... define it here or on CC */
+#endif /* NOLFDEVNO */
+#endif /* SVR4 */ /* command line. */
+
+#ifdef COHERENT
+#define LFDEVNO
+#endif /* COHERENT */
+
+/*
+ For platforms where the lockfile name is made from device/major/minor
+ device number, as in SVR4. Which, if we must have lockfiles at all, is
+ by far the best format, since it eliminates all the confusion that stems
+ from multiple names (or drivers) for the same port, not to mention
+ symlinks. It might even be a good idea to start using this form even
+ on platforms where it's not supported, alongside the normal forms for those
+ platforms, in order to get people used to it...
+*/
+#ifdef LFDEVNO
+#ifndef major /* If we didn't find it */
+#ifdef SVR4 /* then for Sys V R4 */
+#include <sys/mkdev.h> /* look here */
+#else /* or for SunOS versions */
+#ifdef SUNOS4 /* ... */
+#include <sys/sysmacros.h> /* look here */
+#else /* Otherwise take a chance: */
+#define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
+#define minor(dev) ( (int) ( (dev) & 0xff))
+#endif /* SUNOS4 */
+#endif /* SVR4 */
+#endif /* major */
+#endif /* LFDEVNO */
+
+/* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
+
+#ifdef LOCKF
+#ifndef F_TLOCK
+#undef LOCKF
+#ifndef NOLOCKF
+#define NOLOCKF
+#endif /* NOLOCKF */
+#endif /* F_TLOCK */
+#endif /* LOCKF */
+
+#ifdef LOCKF
+#ifndef F_ULOCK
+#undef LOCKF
+#ifndef NOLOCKF
+#define NOLOCKF
+#endif /* NOLOCKF */
+#endif /* F_ULOCK */
+#endif /* LOCKF */
+
+static char linkto[DEVNAMLEN+1];
+static char * linkdev = NULL;
+
+#ifndef NOUUCP
+#ifdef USETTYLOCK
+#ifdef LOCK_DIR
+char * uucplockdir = LOCK_DIR;
+#else
+char * uucplockdir = "";
+#endif /* LOCK_DIR */
+#else
+#ifdef LOCK_DIR
+char * uucplockdir = LOCK_DIR;
+#else
+char * uucplockdir = "";
+#endif /* LOCK_DIR */
+#endif /* USETTYLOCK */
+#else
+char * uucplockdir = "";
+#endif /* NOUUCP */
+
+#ifdef QNX /* Only for QNX4 */
+int /* Visible to outside world */
+qnxopencount() { /* Get QNX device open count */
+ struct _dev_info_entry info;
+ int x;
+
+ x = -1; /* Unknown */
+ if (ttyfd > -1) {
+ if (!dev_info(ttyfd, &info)) {
+ debug(F101,"ttlock QNX open_count","",info.open_count);
+ x = info.open_count;
+ }
+ }
+ return(x);
+}
+#endif /* QNX */
+
+char *
+ttglckdir() { /* Get Lockfile directory name */
+#ifdef __OpenBSD__
+ return("/var/spool/lock");
+#else /* __OpenBSD__ */
+#ifdef __FreeBSD__
+ return("/var/spool/lock");
+#else /* __FreeBSD__ */
+#ifdef LOCK_DIR
+ char * s = LOCK_DIR;
+#endif /* LOCK_DIR */
+#ifdef NOUUCP
+ return("");
+#else /* NOUUCP */
+#ifdef LOCK_DIR
+ return(s);
+#else /* LOCK_DIR */
+ return("");
+#endif /* LOCK_DIR */
+#endif /* NOUUCP */
+#endif /* __FreeBSD__ */
+#endif /* __OpenBSD__ */
+}
+
+static int
+ttlock(ttdev) char *ttdev; {
+
+ int x, n;
+ int islink = 0;
+#ifdef __FreeBSD__
+ char *devname;
+#endif /* __FreeBSD__ */
+
+#ifdef NOUUCP
+ debug(F100,"ttlock NOUUCP","",0);
+ ckstrncpy(flfnam,"NOLOCK",FLFNAML);
+ haslock = 1;
+ return(0);
+#else /* !NOUUCP */
+
+#ifdef USETTYLOCK
+ haslock = 0; /* Not locked yet. */
+ *flfnam = '\0'; /* Lockfile name is empty. */
+#ifdef __FreeBSD__
+ if ((devname = xxlast(ttdev,'/')) != NULL)
+#ifdef FREEBSD8
+ ckstrncat(lockname,devname+1,DEVNAMLEN-ckstrncpy(lockname,"pts",4));
+#else
+ ckstrncpy(lockname,devname+1,DEVNAMLEN);
+#endif /* FREEBSD8 */
+#else
+ if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
+ ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
+#endif /* __FreeBSD__ */
+ else
+ ckstrncpy(lockname,ttdev,DEVNAMLEN);
+/*
+ This might be overkill, but it's not clear from the man pages whether
+ ttylock() can be called without calling ttylocked() first, since the doc
+ says that ttylocked() removes any stale lockfiles, but it does not say this
+ about ttylock(). Also the docs don't say what ttylocked() returns in the
+ case when it finds and removes a stale lockfile. So one or both calls to
+ to ttylocked() might be superfluous, but they should do no harm. Also I'm
+ assuming that we have to do all the same ID swapping, etc, with these
+ routines as we do without them. Thus the priv_on/off() sandwich.
+*/
+#ifdef USE_UU_LOCK
+ priv_on(); /* Turn on privs */
+ x = uu_lock(lockname); /* Try to set the lock */
+ priv_off(); /* Turn privs off */
+ debug(F111,"ttlock uu_lock",lockname,x);
+ switch (x) {
+ case UU_LOCK_INUSE:
+ return(-2);
+ case UU_LOCK_OK:
+#ifdef BSD44
+ ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
+#endif /* BSD44 */
+ haslock = 1;
+ return(0);
+ default:
+ return(-1);
+ }
+#else /* USE_UU_LOCK */
+ priv_on(); /* Turn on privs */
+ if (ttylocked(lockname)) { /* This should remove any stale lock */
+ if (ttylocked(lockname)) { /* so check again. */
+ priv_off();
+ return(-5); /* Still locked, fail. */
+ }
+ }
+ x = ttylock(lockname); /* Lock it. */
+ priv_off(); /* Turn off privs */
+
+ debug(F111,"ttlock lockname",lockname,x);
+ if (x > -1) {
+ /*
+ We don't really know the name of the lockfile, but
+ this is what the man page says it is. In USETTYLOCK
+ builds, it is used only for display by SHOW COMM.
+ */
+ ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
+ haslock = 1;
+ }
+ return(x);
+#endif /* USE_UU_LOCK */
+#else /* Systems that don't have ttylock()... */
+
+#ifndef HPUX
+
+ int lockfd; /* File descriptor for lock file. */
+ PID_T pid; /* Process id of this process. */
+ int tries; /* How many times we've tried... */
+ struct stat devbuf; /* For device numbers (SVR4). */
+
+#ifdef PIDSTRING
+ char pid_str[32]; /* My pid in string format. */
+#endif /* PIDSTRING */
+
+ char *device, *devname;
+
+#define LFNAML 256 /* Max length for lock file name. */
+ char lockfil[LFNAML]; /* Lock file name */
+#ifdef RTAIX
+ char lklockf[LFNAML]; /* Name for link to lock file */
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+ char symlock[LFNAML]; /* Name for symlink lockfile name */
+#endif /* CKSYMLINK */
+ char tmpnam[LFNAML+30]; /* Temporary lockfile name. */
+ char *lockdir = LOCK_DIR; /* Defined near top of this file, */
+ /* or on cc command line. */
+ haslock = 0; /* Not locked yet. */
+ *flfnam = '\0'; /* Lockfile name is empty. */
+ lock2[0] = '\0'; /* Clear secondary lockfile name. */
+ pid = getpid(); /* Get id of this process. */
+
+/* Construct name of lockfile and temporary file */
+
+/* device = name of tty device without the path, e.g. "ttyh8" */
+/* lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
+
+ device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
+
+ if (stat(ttdev,&devbuf) < 0)
+ return(-1);
+
+#ifdef CKSYMLINK
+ islink = 1; /* Assume it's a symlink */
+ linkto[0] = '\0'; /* But we don't know to what */
+#ifdef COMMENT
+/*
+ This is undependable. If it worked it would save the readlink call if
+ we knew the device name was not a link.
+*/
+#ifdef S_ISLNK
+ islink = S_ISLNK(devbuf.st_mode);
+ debug(F101,"ttlock stat S_ISLNK","",islink);
+#endif /* S_ISLNK */
+#endif /* COMMENT */
+ if (islink) {
+ n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
+ debug(F111,"ttlock readlink",ttdev,n);
+ if (n > -1) /* It is */
+ linkto[n] = '\0';
+ else /* It's not */
+ islink = 0;
+ debug(F111,"ttlock link",linkto,islink);
+ }
+ if (islink) {
+ linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
+ debug(F110,"ttlock linkdev",linkdev,0);
+ }
+#endif /* CKSYMLINK */
+
+/*
+ On SCO platforms, if we don't have a symlink, then let's pretend the
+ name given for the device is a symlink, because later we will change
+ the name if it contains any uppercase characters.
+*/
+#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
+ if (!islink) {
+ islink = 1;
+ ckstrncpy(linkto,ttdev,DEVNAMLEN);
+ linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
+ debug(F110,"ttlock linkdev",linkdev,0);
+ }
+#else
+#ifdef M_XENIX /* SCO Xenix or UNIX */
+ if (!islink) {
+ islink = 1;
+ ckstrncpy(linkto,ttdev,DEVNAMLEN);
+ linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
+ debug(F110,"ttlock linkdev",linkdev,0);
+ }
+#endif /* M_XENIX */
+#endif /* CK_SCOV5 */
+
+#ifdef ISIII /* Interactive System III, PC/IX */
+ ckstrncpy(lockfil, device, DEVNAMLEN);
+#else /* not ISIII */
+#ifdef LFDEVNO /* Lockfilename has device numbers. */
+#ifdef COHERENT
+ sprintf(lockfil,"LCK..%d.%d", /* SAFE */
+ major(devbuf.st_rdev), /* major device number */
+ 0x1f & minor(devbuf.st_rdev)); /* minor device number */
+#else
+ /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
+ /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
+ sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
+ major(devbuf.st_dev), /* device */
+ major(devbuf.st_rdev), /* major device number */
+ minor(devbuf.st_rdev)); /* minor device number */
+#endif /* COHERENT */
+#else /* Not LFDEVNO */
+#ifdef PTX /* Dynix PTX */
+ if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
+ if ((int)strlen(device) + 8 < LFNAML)
+ sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
+ else
+ ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
+ } else
+#endif /* PTX */
+ if ((int)strlen(device) + 5 < LFNAML)
+ sprintf(lockfil,"LCK..%s", device);
+ else
+ ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
+#ifdef RTAIX
+ ckstrncpy(lklockf,device,DEVNAMLEN);
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+ symlock[0] = '\0';
+ if (islink)
+ ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
+#endif /* CKSYMLINK */
+#endif /* LFDEVNO */
+#endif /* ISIII */
+
+#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
+ {
+ /* Lowercase the entire filename. */
+ /* SCO says we must do this in V5.0 and later. */
+ /* BUT... watch out for devices -- like Digiboard Portserver */
+ /* That can have hundreds of ports... */
+ char *p = (char *)(lockfil + 5);
+ while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
+ }
+#ifdef CKSYMLINK
+ if (islink) { /* If no change */
+ if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */
+ islink = 0;
+ symlock[0] = '\0';
+ }
+ }
+#endif /* CKSYMLINK */
+#else
+#ifdef M_XENIX /* SCO Xenix or UNIX */
+ {
+ int x; char c;
+ x = (int)strlen(lockfil) - 1; /* Get last letter of device name. */
+ if (x > 0) { /* If it's uppercase, lower it. */
+ c = lockfil[x];
+ if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
+ }
+ }
+#ifdef CKSYMLINK
+ if (islink) {
+ if (!strcmp(lockfil,symlock)) { /* No change */
+ islink = 0; /* so no second lockfile */
+ symlock[0] = '\0';
+ }
+ }
+#endif /* CKSYMLINK */
+#endif /* M_XENIX */
+#endif /* CK_SCOV5 */
+
+/* flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
+/* tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
+
+ ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
+
+#ifdef RTAIX
+ ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
+#endif /* RTAIX */
+
+#ifndef LFDEVNO
+#ifdef CKSYMLINK
+ /* If it's a link then also make a lockfile for the real name */
+ debug(F111,"ttlock link symlock",symlock,islink);
+ if (islink && symlock[0]) {
+ /* But only if the lockfile names would be different. */
+ /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
+ ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
+ debug(F110,"ttlock lock2",lock2,0);
+ if (!strcmp(lock2,flfnam)) { /* Are lockfile names the same? */
+ debug(F100,"ttlock lock2 cleared","",0);
+ lock2[0] = '\0'; /* Clear secondary lockfile name. */
+ }
+ }
+#endif /* CKSYMLINK */
+#endif /* LFDEVNO */
+
+ sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
+ debug(F110,"ttlock flfnam",flfnam,0);
+ debug(F110,"ttlock tmpnam",tmpnam,0);
+
+ priv_on(); /* Turn on privileges if possible. */
+ lockfd = creat(tmpnam, 0444); /* Try to create temp lock file. */
+ if (lockfd < 0) { /* Create failed. */
+ debug(F111,"ttlock creat failed",tmpnam,errno);
+ if (errno == ENOENT) {
+ perror(lockdir);
+ printf("UUCP not installed or Kermit misconfigured\n");
+ } else {
+ if (!quiet)
+ perror(lockdir);
+ unlink(tmpnam); /* Get rid of the temporary file. */
+ }
+ priv_off(); /* Turn off privileges!!! */
+ return(-1); /* Return failure code. */
+ }
+/* Now write the pid into the temp lockfile in the appropriate format */
+
+#ifdef PIDSTRING /* For Honey DanBer UUCP, */
+ sprintf( /* write PID as decimal string */
+ pid_str,
+#ifdef LINUXFSSTND /* The "Linux File System Standard" */
+#ifdef FSSTND10 /* Version 1.0 calls for */
+ "%010d\n", /* leading zeros */
+#else /* while version 1.2 calls for */
+ "%10d\n", /* leading spaces */
+#endif /* FSSTND10 */
+#else
+#ifdef COHERENT
+ "%d\n", /* with leading nothing */
+#else
+ "%10d\n", /* with leading blanks */
+#endif /* COHERENT */
+#endif /* LINUXFSSTND */
+ (int) pid
+ ); /* safe */
+ write(lockfd, pid_str, 11);
+ debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
+
+#else /* Not PIDSTRING, use integer PID */
+
+ write(lockfd, (char *)&pid, sizeof(pid) );
+ debug(F101,"ttlock pid","",(int) pid);
+
+#endif /* PIDSTRING */
+
+/* Now try to rename the temp file to the real lock file name. */
+/* This will fail if a lock file of that name already exists. */
+
+ close(lockfd); /* Close the temp lockfile. */
+ chmod(tmpnam,0444); /* Permission for a valid lock. */
+ tries = 0;
+ while (!haslock && tries++ < 2) {
+ haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
+ if (haslock) { /* If we got the lockfile */
+#ifdef RTAIX
+ link(flfnam,lkflfn);
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+#ifndef LFDEVNO
+ if (islink && lock2[0])
+ link(flfnam,lock2);
+#endif /* LFDEVNO */
+#endif /* CKSYMLINK */
+
+#ifdef COMMENT
+/* Can't do this any more because device is not open yet so no ttyfd. */
+#ifdef LOCKF
+/*
+ Advisory file locking works on SVR4, so we use it. In fact, it is
+ necessary in some cases, e.g. when SLIP is involved. But it still doesn't
+ seem to prevent multiple users accessing the same device by different names.
+*/
+ while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
+ debug(F111, "ttlock lockf returns errno", "", errno);
+ if ((++tries >= 3) || (errno != EAGAIN)) {
+ x = unlink(flfnam); /* remove the lockfile */
+#ifdef RTAIX
+ unlink(lkflfn); /* And any links to it... */
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+#ifndef LFDEVNO
+ if (islink && lock2[0])
+ unlink(lock2); /* ditto... */
+#endif /* LFDEVNO */
+#endif /* CKSYMLINK */
+ debug(F111,"ttlock unlink",flfnam,x);
+ haslock = 0;
+ break;
+ }
+ sleep(2);
+ }
+ if (haslock) /* If we got an advisory lock */
+#endif /* LOCKF */
+#endif /* COMMENT */
+ break; /* We're done. */
+
+ } else { /* We didn't create a new lockfile. */
+ priv_off();
+ if (ttchkpid(flfnam)) { /* Check existing lockfile */
+ priv_on(); /* cause ttchkpid turns priv_off... */
+ unlink(tmpnam); /* Delete the tempfile */
+ debug(F100,"ttlock found tty locked","",0);
+ priv_off(); /* Turn off privs */
+ return(-2); /* Code for device is in use. */
+ }
+ priv_on();
+ }
+ }
+ unlink(tmpnam); /* Unlink (remove) the temp file. */
+ priv_off(); /* Turn off privs */
+ return(haslock ? 0 : -1); /* Return link's return code. */
+
+#else /* HPUX */
+
+/*
+ HP-UX gets its own copy of this routine, modeled after the observed behavior
+ of the HP-UX 'cu' program. HP-UX serial device names consist of a base name
+ such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
+ designator which is a string of digits, possibly containing an imbedded
+ letter "p". Examples (for base name "tty"):
+
+ /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
+
+ According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
+ used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
+ on other models. In HP-UX 10.00, "0p0" notation was adopted for all models.
+ However, we make and enforce no such distinctions; either notation is
+ accepted on any model or HP-UX version as a valid unit designator.
+
+ If a valid unit is specified (as opposed to a designer name or symlink), we
+ check for all aliases of the given unit according to the devprefix[] array.
+ If no lockfiles are found for the given unit, we can have the device; we
+ create a lockfile LCK..name in the lockfile directory appropriate for the
+ HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
+ 9.xx and earlier). If it is a "cua" or "cul" device, a second lockfile is
+ created with the "ttyd" prefix. This is exactly what cu does.
+
+ If the "set line" device does not have a valid unit designator, then it is
+ used literally and no synomyms are searched for and only one lockfile is
+ created.
+
+ -fdc, March 1998.
+*/
+#define LFNAML 80 /* Max length for lock file name. */
+
+ int lockfd; /* File descriptor for lock file. */
+ PID_T pid; /* Process ID of this process. */
+ int fpid; /* pid found in existing lockfile. */
+ int tries; /* How many times we've tried... */
+ int i, k; /* Workers */
+
+ char *device, *devname; /* "/dev/xxx", "xxx" */
+ char *unit, *p; /* <instance>p<port> part of xxx */
+
+ char lockfil[LFNAML]; /* Lockfile name (no path) */
+ char tmpnam[LFNAML]; /* Temporary lockfile name. */
+
+#ifdef HPUX10 /* Lockfile directory */
+ char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
+#else /* HP-UX 9.xx and below */
+#ifdef LOCK_DIR
+ char *lockdir = LOCK_DIR; /* Defined near top of this file */
+#else
+ char *lockdir = "/usr/spool/uucp"; /* or not... */
+#endif /* LOCK_DIR */
+#endif /* HPUX10 */
+
+ haslock = 0; /* Not locked yet. */
+ *flfnam = '\0'; /* Lockfile name is empty. */
+ lock2[0] = '\0'; /* Second one too. */
+ pid = getpid(); /* Get my process ID */
+/*
+ Construct name of lockfile and temporary file...
+ device = name of tty device without the path, e.g. "tty0p0"
+ lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
+*/
+ device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
+ debug(F110,"TTLOCK device",device,0);
+ ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
+
+ k = 0; /* Assume device is not locked */
+ n = 0; /* Digit counter */
+ unit = device; /* Unit = <instance>p<port> */
+ while (*unit && !isdigit(*unit)) /* Search for digit... */
+ unit++;
+ p = unit; /* Verify <num>p<num> format... */
+ debug(F110,"TTLOCK unit 1",unit,0);
+/*
+ The unit number is recognized as:
+ (a) any sequence of digits that runs to the end of the string.
+ (b) any (a) that includes one and only one letter "p", with at least
+ one digit before and after it.
+*/
+ while (isdigit(*p)) p++, n++; /* Get a run of digits */
+ if (*p && n > 0) { /* Have a "p"? */
+ if (*p == 'p' && isdigit(*(p+1))) {
+ p++;
+ n = 0;
+ while (isdigit(*p)) p++, n++;
+ }
+ }
+ if (n == 0 || *p) unit = "";
+ debug(F110,"TTLOCK unit 2",unit,0);
+
+ if (*unit) { /* Device name has unit number. */
+ /* The following loop not only searches for the various lockfile */
+ /* synonyms, but also removes all -- not just one -- stale lockfile */
+ /* for the device, should there be more than one. See ttchkpid(). */
+ ttydexists = 0;
+ for (i = 0; *devprefix[i]; i++) { /* For each driver... */
+ /* Make device name */
+ ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
+ priv_on(); /* Privs on */
+ k = zchki(lock2) != -1; /* See if device exists */
+ priv_off(); /* Privs off */
+ debug(F111,"TTLOCK exist",lock2,k);
+ if (k) {
+ if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
+ ttydexists = 1;
+ /* Make lockfile name */
+ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
+ debug(F110,"TTLOCK checking",lock2,0);
+ priv_on(); /* Privs on */
+ k = zchki(lock2) != -1; /* See if lockfile exists */
+ priv_off(); /* Privs off */
+ debug(F111,"TTLOCK check for lock A",lock2,k);
+ if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
+ ckstrncpy(flfnam,lock2,FLFNAML);
+ return(-2);
+ }
+ }
+ }
+ } else { /* Some other device-name format */
+ /* This takes care of symbolic links, etc... */
+ /* But does not chase them down! */
+ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
+ priv_on();
+ k = zchki(lock2) != -1; /* Check for existing lockfile */
+ priv_off();
+ debug(F111,"TTLOCK check for lock B",lock2,k);
+ if (k) if (ttchkpid(lock2)) { /* Check pid from lockfile */
+ ckstrncpy(flfnam,lock2,FLFNAML);
+ debug(F110,"TTLOCK in use",device,0);
+ debug(F101,"TTLOCK returns","",-2);
+ return(-2);
+ }
+ }
+/*
+ Get here only if there is no (more) lockfile, so now we make one (or two)...
+ flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
+ tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
+*/
+ ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
+
+ /* If dialout device, also make one for corresponding dialin device */
+ lock2[0] = '\0';
+ if (!strncmp(device,"cu",2) && *unit && ttydexists)
+ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
+
+ if ((int)strlen(lockdir)+12 < LFNAML)
+ sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"TTLOCK flfnam",flfnam,0);
+ debug(F110,"TTLOCK lock2",lock2,0);
+ debug(F110,"TTLOCK tmpnam",tmpnam,0);
+ }
+#endif /* DEBUG */
+/*
+ Lockfile permissions...
+ 444 is standard, HP-UX 10.00 uses 664. It doesn't matter.
+ Kermit uses 444; the difference lets us tell whether Kermit created
+ the lock file.
+*/
+ priv_on(); /* Turn on privileges. */
+ lockfd = creat(tmpnam, 0444); /* Try to create temporary file. */
+ if (lockfd < 0) { /* Create failed. */
+ debug(F111,"TTLOCK creat failed",tmpnam,errno);
+ if (errno == ENOENT) {
+ perror(lockdir);
+ printf("UUCP not installed or Kermit misconfigured\n");
+ } else {
+ if (!quiet)
+ perror(lockdir);
+ unlink(tmpnam); /* Get rid of the temporary file. */
+ }
+ priv_off(); /* Turn off privileges!!! */
+ debug(F101,"TTLOCK returns","",-1);
+ return(-1); /* Return failure code. */
+ }
+ debug(F110,"TTLOCK temp ok",tmpnam,0);
+
+/* Now write our pid into the temp lockfile in integer format. */
+
+ i = write(lockfd, (char *)&pid, sizeof(pid));
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"TTLOCK pid","",pid);
+ debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
+ debug(F101,"TTLOCK write pid returns","",i);
+ }
+#endif /* DEBUG */
+
+/*
+ Now try to rename the temporary file to the real lockfile name.
+ This will fail if a lock file of that name already exists, which
+ will catch race conditions with other users.
+*/
+ close(lockfd); /* Close the temp lockfile. */
+ chmod(tmpnam,0444);
+
+ tries = 0;
+ while (!haslock && tries++ < 2) {
+ haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
+ debug(F101,"TTLOCK link","",haslock);
+ if (haslock) { /* If we made the lockfile... */
+
+#ifdef COMMENT
+/* We can't do this any more because we don't have a file descriptor yet. */
+#ifdef LOCKF /* Can be canceled with -DNOLOCKF */
+/*
+ Create an advisory lock on the device through its file descriptor.
+ This code actually seems to work. If it is executed, and then another
+ process tries to open the same device under a different name to circumvent
+ the lockfile, they get a "device busy" error.
+*/
+ debug(F100,"TTLOCK LOCKF code...","",0);
+ while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
+ debug(F111, "TTLOCK lockf error", "", errno);
+ if ((++tries >= 3) || (errno != EAGAIN)) {
+ x = unlink(flfnam); /* Remove the lockfile */
+ if (errno == EACCES && !quiet)
+ printf("Device already locked by another process\n");
+ haslock = 0;
+ break;
+ }
+ sleep(2);
+ }
+#endif /* LOCKF */
+#endif /* COMMENT */
+
+ if (haslock) { /* If we made the lockfile ... */
+ if (lock2[0]) { /* if there is to be a 2nd lockfile */
+ lockfd = creat(lock2, 0444); /* Create it */
+ debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
+ if (lockfd > -1) { /* Created OK, write pid. */
+ write(lockfd, (char *)&pid, sizeof(pid) );
+ close(lockfd); /* Close and */
+ chmod(lock2, 0444); /* set permissions. */
+ } else { /* Not OK, but don't fail. */
+ lock2[0] = '\0'; /* Just remember it's not there. */
+ }
+ }
+ break; /* and we're done. */
+ }
+ }
+ }
+ unlink(tmpnam); /* Unlink (remove) the temp file. */
+ priv_off(); /* Turn off privs */
+ i = haslock ? 0 : -1; /* Our return value */
+ debug(F101,"TTLOCK returns","",i);
+ return(i);
+#endif /* HPUX */
+#endif /* USETTYLOCK */
+#endif /* !NOUUCP */
+}
+
+/* T T U N L O C K */
+
+static int
+ttunlck() { /* Remove UUCP lockfile(s). */
+#ifndef NOUUCP
+ int x;
+
+ debug(F111,"ttunlck",flfnam,haslock);
+
+#ifdef USETTYLOCK
+
+ if (haslock && *flfnam) {
+ int x;
+ priv_on(); /* Turn on privs */
+#ifdef USE_UU_LOCK
+ x = uu_unlock(lockname);
+#else /* USE_UU_LOCK */
+ x = ttyunlock(lockname); /* Try to unlock */
+#endif /* USE_UU_LOCK */
+ priv_off(); /* Turn off privs */
+ if (x < 0 && !quiet)
+ printf("Warning - Can't remove lockfile: %s\n", flfnam);
+
+ *flfnam = '\0'; /* Erase the name. */
+ haslock = 0;
+ return(0);
+ }
+
+#else /* No ttylock()... */
+
+ if (haslock && *flfnam) {
+ /* Don't remove lockfile if we didn't make it ourselves */
+ if ((x = ttrpid(flfnam)) != (int)getpid()) {
+ debug(F111,"ttunlck lockfile seized",flfnam,x);
+ printf("Warning - Lockfile %s seized by pid %d\n",
+ flfnam,
+ x
+ );
+ return(0);
+ }
+ priv_on(); /* Turn privileges on. */
+ errno = 0;
+ x = unlink(flfnam); /* Remove the lockfile. */
+ debug(F111,"ttunlck unlink",flfnam,x);
+ if (x < 0) {
+ if (errno && !quiet)
+ perror(ttnmsv);
+ printf("Warning - Can't remove lockfile: %s\n", flfnam);
+ }
+ haslock = 0;
+ *flfnam = '\0'; /* Erase the name. */
+
+#ifdef RTAIX
+ errno = 0;
+ x = unlink(lkflfn); /* Remove link to lockfile */
+ debug(F111,"ttunlck AIX link unlink",lkflfn,x);
+ if (x < 0) {
+ if (errno && !quiet)
+ perror(ttnmsv);
+ printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
+ }
+ *lkflfn = '\0';
+#else
+ if (lock2[0]) { /* If there is a second lockfile, */
+ errno = 0;
+ x = unlink(lock2); /* remove it too. */
+ debug(F111,"ttunlck lock2 unlink",lock2,x);
+ if (x < 0) {
+ if (errno && !quiet)
+ perror(ttnmsv);
+ printf("Warning - Can't remove secondary lockfile: %s\n",
+ lock2
+ );
+ }
+ lock2[0] = '\0'; /* Forget its name. */
+ }
+#endif /* RTAIX */
+
+#ifdef COMMENT
+#ifdef LOCKF
+ (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
+#endif /* LOCKF */
+#endif /* COMMENT */
+
+ priv_off(); /* Turn privileges off. */
+ }
+#endif /* USETTYLOCK */
+#endif /* !NOUUCP */
+ return(0);
+}
+
+/*
+ 4.3BSD-style UUCP line direction control.
+ (Stan Barber, Rice U, 1980-something...)
+*/
+#ifndef NOUUCP
+#ifdef ACUCNTRL
+VOID
+acucntrl(flag,ttname) char *flag, *ttname; {
+ char x[DEVNAMLEN+32], *device, *devname;
+
+ if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
+ return; /* just return. */
+ device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
+ if (strncmp(device,"LCK..",4) == 0) device += 5;
+ ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
+ debug(F110,"called ",x,0);
+ zsyscmd(x);
+}
+#endif /* ACUCNTRL */
+#endif /* NOUUCP */
+
+/*
+ T T H F L O W -- Set or Reset hardware flow control.
+
+ This is an attempt to collect all hardware-flow-control related code
+ into a single module. Thanks to Rick Sladkey and John Kohl for lots of
+ help here. Overview:
+
+ Hardware flow control is not supported in many UNIX implementions. Even
+ when it is supported, there is no (ha ha) "standard" for the programming
+ interface. In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
+ SunOS, AIX, etc, have totally different methods. (And, not strictly
+ relevant here, the programming interface often brings one only to a no-op
+ in the device driver!)
+
+ Among all these, we have two major types of APIs: those in which hardware
+ flow control is determined by bits in the same termio/termios/sgtty mode
+ word(s) that are used for controlling such items as CBREAK vs RAW mode, and
+ which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
+ for changing terminal modes. And those that use entirely different
+ mechanisms.
+
+ In the first category, it is important that any change in the mode bits be
+ reflected in the relevant termio(s)/sgtty structure, so that subsequent
+ changes to that structure do not wipe out the effects of this routine. That
+ is why a pointer, attrs, to the appropriate structure is passed as a
+ parameter to this routine.
+
+ The second category should give us no worries, since any changes to hardware
+ flow control accomplished by this routine should not affect the termio(s)/
+ sgtty structures, and therefore will not be undone by later changes to them.
+
+ The second argument, status, means to turn on hardware flow control if
+ nonzero, and to turn it off if zero.
+
+ Returns: 0 on apparent success, -1 on probable failure.
+*/
+
+/*
+ The following business is for BSDI, where it was discovered that two
+ separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
+ but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
+ bits, so hwfc only works in one direction if you use CRTSCTS to control it.
+ Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
+ define CRTSCTS correctly.
+*/
+#ifdef FIXCRTSCTS
+#ifdef CRTSCTS
+#ifdef CCTS_OFLOW
+#ifdef CRTS_IFLOW
+#undef CRTSCTS
+#define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
+#endif /* CRTS_IFLOW */
+#endif /* CCTS_OFLOW */
+#endif /* CRTSCTS */
+#endif /* FIXCRTSCTS */
+
+static int
+tthflow(flow, status, attrs)
+ int flow, /* Type of flow control (ckcdeb.h) */
+ status; /* Nonzero = turn it on */
+ /* Zero = turn it off */
+#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
+ struct termios *attrs;
+#else /* System V */
+#ifdef ATTSV
+#ifdef ATT7300
+#ifdef UNIX351M
+/* AT&T UNIX 3.51m can set but not test for hardware flow control */
+#define RTSFLOW CTSCD
+#define CTSFLOW CTSCD
+#endif /* ATT7300 */
+#endif /* UNIX351M */
+ struct termio *attrs;
+#else /* BSD, V7, etc */
+ struct sgttyb *attrs; /* sgtty info... */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+/* tthflow */ {
+
+ int x = 0; /* tthflow() return code */
+
+#ifdef Plan9
+ return p9tthflow(flow, status);
+#else
+
+#ifndef OXOS /* NOT Olivetti X/OS... */
+/*
+ For SunOS 4.0 and later in the BSD environment ...
+
+ The declarations are copied and interpreted from the System V header files,
+ so we don't actually have to pull in all the System V junk when building
+ C-Kermit for SunOS in the BSD environment, which would be dangerous because
+ having those symbols defined would cause us to take the wrong paths through
+ the code. The code in this section is used in both the BSD and Sys V SunOS
+ versions.
+*/
+#ifdef SUNOS41
+/*
+ In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
+ because GNU CC uses different formats for the _IOxxx macros than regular CC;
+ the POSIX forms work for both. But the POSIX calls are not available in
+ SunOS 4.0.
+*/
+#define CRTSCTS 0x80000000 /* RTS/CTS flow control */
+#define TCSANOW 0 /* Do it now */
+
+ struct termios {
+ unsigned long c_iflag; /* Input modes */
+ unsigned long c_oflag; /* Output modes */
+ unsigned long c_cflag; /* Control modes */
+ unsigned long c_lflag; /* Line discipline modes */
+ char c_line;
+ CHAR c_cc[17];
+ };
+ struct termios temp;
+
+_PROTOTYP( int tcgetattr, (int, struct termios *) );
+_PROTOTYP( int tcsetattr, (int, int, struct termios *) );
+/*
+ When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
+ asserted. So we don't set CRTSCTS unless CD is up. This should be OK,
+ since we don't need RTS/CTS during dialing, and after dialing is complete,
+ we should have CD. If not, we still communicate, but without RTS/CTS.
+*/
+ int mflags; /* Modem signal flags */
+
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+ debug(F101,"tthflow SUNOS41 entry status","",status);
+ if (!status) { /* Turn hard flow off */
+ if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
+ (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
+ temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ }
+ } else { /* Turn hard flow on */
+ if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
+ (mflags & TIOCM_CAR)) { /* Check for CD */
+ debug(F100,"tthflow SunOS has CD","",0);
+ if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
+ !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
+ temp.c_cflag |= CRTSCTS; /* Not there, add it */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ }
+ } else {
+ x = -1;
+ debug(F100,"tthflow SunOS no CD","",0);
+ }
+ }
+#else
+#ifdef QNX
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow QNX entry status","",status);
+ if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
+ if (!status) { /* Turn hard flow off */
+ if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
+ temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
+ attrs->c_cflag &= ~(IHFLOW|OHFLOW);
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ }
+ } else { /* Turn hard flow on */
+ if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
+ temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
+ temp.c_iflag &= ~(IXON|IXOFF); /* Bye to IXON/IXOFF */
+ ttraw.c_lflag |= IEXTEN; /* Must be on */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ attrs->c_cflag |= (IHFLOW|OHFLOW);
+ attrs->c_iflag &= ~(IXON|IXOFF);
+ }
+ }
+ } else {
+ x = -1;
+ debug(F100, "tthflow QNX getattr fails", "", 0);
+ }
+#else
+#ifdef POSIX_CRTSCTS
+/*
+ POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
+ Note: Do not assume CRTSCTS is a one-bit field!
+*/
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
+ errno = 0;
+ x = tcgetattr(ttyfd, &temp);
+ debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
+ errno = 0;
+ if (x < 0) {
+ x = -1;
+ } else {
+ if (!status) { /* Turn hard flow off */
+ if (
+#ifdef COMMENT
+ /* This can fail because of sign extension */
+ /* e.g. in Linux where it's Bit 31 */
+ (temp.c_cflag & CRTSCTS) == CRTSCTS
+#else
+ (temp.c_cflag & CRTSCTS) != 0
+#endif /* COMMENT */
+ ) {
+ temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
+ attrs->c_cflag &= ~CRTSCTS;
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
+ ckitoa(x),errno);
+ } else { /* John Dunlap 2010-01-26 */
+ debug(F001,
+ "tthflow before forcing off attrs CRTSCTS",
+ "",
+ attrs->c_cflag&CRTSCTS
+ );
+ attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
+ debug(F001,
+ "tthflow after forcing off attrs CRTSCTS",
+ "",
+ attrs->c_cflag&CRTSCTS
+ );
+ }
+ } else { /* Turn hard flow on */
+ if (
+#ifdef COMMENT
+ /* This can fail because of sign extension */
+ (temp.c_cflag & CRTSCTS) != CRTSCTS
+#else
+ (temp.c_cflag & CRTSCTS) == 0
+#endif /* COMMENT */
+ ) {
+ temp.c_cflag |= CRTSCTS; /* Not there, add it */
+ temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
+ x = tcsetattr(ttyfd,TCSANOW,&temp);
+ debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
+ ckitoa(x),errno);
+ attrs->c_cflag |= CRTSCTS;
+ attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
+ }
+ }
+ }
+#else
+#ifdef SUNOS4
+/*
+ SunOS 4.0 (and maybe earlier?). This code is dangerous because it
+ prevents compilation with GNU gcc, which uses different formats for the
+ _IORxxx macros than regular cc. SunOS 4.1 and later can use the POSIX
+ routines above, which work for both cc and gcc.
+*/
+#define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
+#define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
+#define CRTSCTS 0x80000000 /* RTS/CTS flow control */
+
+ struct termios {
+ unsigned long c_iflag; /* Input modes */
+ unsigned long c_oflag; /* Output modes */
+ unsigned long c_cflag; /* Control modes */
+ unsigned long c_lflag; /* Line discipline modes */
+ char c_line;
+ CHAR c_cc[17];
+ };
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow entry status","",status);
+ if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
+ if (status) { /* Turn hard flow on */
+ temp.c_cflag |= CRTSCTS; /* Add RTS/CTS to them. */
+ x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
+ attrs->c_cflag |= CRTSCTS; /* Add to global info. */
+ } else { /* Turn hard flow off */
+ temp.c_cflag &= ~CRTSCTS;
+ x = ioctl(ttyfd,TCSETS,&temp);
+ attrs->c_cflag &= ~CRTSCTS;
+ }
+ }
+#else /* Not SunOS 4.0 or later */
+#ifdef AIXRS /* IBM AIX RS/6000 */
+#ifndef AIX41 /* But only pre-4.x == SVR4 */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ if (status) {
+ if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
+ debug(F100,"hardflow TXADDCD (rts) error", "", 0);
+ } else {
+ if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
+ debug(F100,"hardflow TXDELCD (rts) error", "", 0);
+ }
+#endif /* AIX41 */
+#else /* Not AIX RS/6000 */
+
+#ifdef ATTSV /* System V... */
+
+#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
+#define CK_SCOUNIX
+#else
+#ifdef M_UNIX /* SCO UNIX 3.2v4.x or earlier */
+#define CK_SCOUNIX
+#endif /* M_UNIX */
+#endif /* CK_SCOV5 */
+
+#ifdef SCO_FORCE_RTSXOFF
+#ifdef CK_SCOUNIX /* But not SCO OpenServer 5.0.4 */
+#ifdef SCO_OSR504 /* or later... */
+#undef CK_SCOUNIX
+#endif /* SCO_OSR504 */
+#endif /* CK_SCOUNIX */
+#endif /* SCO_FORCE_RTSXOFF */
+
+#ifdef CK_SCOUNIX
+#ifdef POSIX
+ struct termios temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
+ errno = 0;
+ x = tcgetattr(ttyfd, &temp);
+ debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
+#else /* POSIX */
+ struct termio temp;
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
+ x = ioctl(ttyfd, TCGETA, &temp);
+ debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
+#endif /* POSIX */
+/*
+ This is not really POSIX, since POSIX does not deal with hardware flow
+ control, but we are using the POSIX APIs. In fact, RTSFLOW and CTSFLOW
+ are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif. So
+ let's try forcing their definitions here.
+*/
+#ifndef CTSFLOW
+#define CTSFLOW 0020000
+ debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
+#else
+ debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
+#endif /* CTSFLOW */
+#ifndef RTSFLOW
+#define RTSFLOW 0040000
+ debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
+#else
+ debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
+#endif /* RTSFLOW */
+#ifndef ORTSFL
+#define ORTSFL 0100000
+ debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
+#else
+ debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
+#endif /* ORTSFL */
+
+ if (x != -1) {
+ if (status) { /* Turn it ON */
+ temp.c_cflag |= RTSFLOW|CTSFLOW;
+ attrs->c_cflag |= RTSFLOW|CTSFLOW;
+#ifdef ORTSFL
+ temp.c_cflag &= ~ORTSFL;
+ attrs->c_cflag &= ~ORTSFL;
+#endif /* ORTSFL */
+ temp.c_iflag &= ~(IXON|IXOFF|IXANY);
+ attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
+ } else { /* Turn it OFF */
+#ifdef ORTSFL
+ temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
+ attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
+#else /* ORTSFL */
+ temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
+ attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
+#endif /* ORTSFL */
+ }
+#ifdef POSIX
+ x = tcsetattr(ttyfd, TCSADRAIN, &temp);
+#else
+ x = ioctl(ttyfd, TCSETA, &temp);
+#endif /* POSIX */
+ debug(F101,"tthflow SCO set modes","",x);
+ }
+#else /* Not SCO UNIX */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ if (!status) { /* Turn it OFF */
+#ifdef RTSXOFF
+ debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
+ rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
+#ifdef TCSETX
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ debug(F101,"tthflow ATTSV TCSETX OFF","",x);
+#else
+ x = -1
+ debug(F100,"tthflow TCSETX not defined","",0);
+#endif /* TCSETX */
+#else
+ debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
+#endif /* RTSXOFF */
+#ifdef DTRXOFF
+ debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
+ rctsx.x_hflag &= ~(DTRXOFF|CDXON);
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
+#else
+ debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
+#endif /* DTRXOFF */
+ } else { /* Turn it ON. */
+ if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
+ debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
+#ifdef RTSXOFF
+ /* This is the preferred way, according to SVID3 */
+#ifdef TCGETX
+ x = ioctl(ttyfd,TCGETX,&rctsx);
+ debug(F101,"tthflow TCGETX","",x);
+ if (x > -1) {
+ rctsx.x_hflag |= RTSXOFF | CTSXON;
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ debug(F100,"tthflow ATTSV ioctl","",x);
+ }
+#else
+ debug(F100,"tthflow TCGETX not defined","",0);
+ x = -1
+#endif /* TCGETX */
+#else
+ debug(F100,"tthflow RTSXOFF not defined","",0);
+ x = -1;
+#endif /* RTSXOFF */
+ } else if (flow == FLO_DTRC) { /* DTR/CD Flow control... */
+ debug(F100,"tthflow ATTSV DTR/CD ON","",0);
+#ifdef DTRXOFF
+ /* This is straight out of SVID R4 */
+ if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
+ rctsx.x_hflag &= ~(DTRXOFF|CDXON);
+ x = ioctl(ttyfd,TCSETX,&rctsx);
+ }
+#else
+ debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
+ x = -1;
+#endif /* DTRXOFF */
+ }
+ }
+#endif /* CK_SCOUNIX */
+
+#else /* not System V... */
+
+#ifdef CK_DTRCTS
+#ifdef LDODTR
+#ifdef LDOCTS
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ x = LDODTR | LDOCTS; /* Found only on UTEK? */
+ if (flow == FLO_DTRT && status) { /* Use hardware flow control */
+ if (lmodef) {
+ x = ioctl(ttyfd,TIOCLBIS,&x);
+ if (x < 0) {
+ debug(F100,"hardflow TIOCLBIS error","",0);
+ } else {
+ lmodef++;
+ debug(F100,"hardflow TIOCLBIS ok","",0);
+ }
+ }
+ } else {
+ if (lmodef) {
+ x = ioctl(ttyfd,TIOCLBIC,&x);
+ if (x < 0) {
+ debug(F100,"hardflow TIOCLBIC error","",0);
+ } else {
+ lmodef++;
+ debug(F100,"hardflow TIOCLBIC ok","",0);
+ }
+ }
+ }
+#endif /* LDODTR */
+#endif /* LDOCTS */
+#endif /* CK_DTRCTS */
+#endif /* ATTSV */
+#endif /* AIXRS */
+#endif /* SUNOS4 */
+#endif /* QNX */
+#endif /* POSIX_CRTSCTS */
+#endif /* SUNOS41 */
+
+#else /* OXOS */
+
+ struct termios temp; /* Olivetti X/OS ... */
+
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+ x = ioctl(ttyfd,TCGETS,&temp);
+ if (x == 0) {
+ temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
+ if (status) {
+ switch (flow) {
+ case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
+ break;
+ case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
+ break;
+ }
+ }
+ x = ioctl(ttyfd,TCSETS,&temp);
+ }
+#endif /* OXOS */
+ return(x);
+
+#endif /* Plan9 */
+}
+
+/* T T P K T -- Condition the communication line for packets */
+/* or for modem dialing */
+
+/*
+ If called with speed > -1, also set the speed.
+ Returns 0 on success, -1 on failure.
+
+ NOTE: the "xflow" parameter is supposed to be the currently selected
+ type of flow control, but for historical reasons, this parameter is also
+ used to indicate that we are dialing. Therefore, when the true flow
+ control setting is needed, we access the external variable "flow", rather
+ than trusting our "xflow" argument.
+*/
+int
+#ifdef CK_ANSIC
+ttpkt(long speed, int xflow, int parity)
+#else
+ttpkt(speed,xflow,parity) long speed; int xflow, parity;
+#endif /* CK_ANSIC */
+/* ttpkt */ {
+#ifndef NOLOCAL
+ int s2;
+ int s = -1;
+#endif /* NOLOCAL */
+ int x;
+ extern int flow; /* REAL flow-control setting */
+
+ if (ttyfd < 0) return(-1); /* Not open. */
+
+ debug(F101,"ttpkt parity","",parity);
+ debug(F101,"ttpkt xflow","",xflow);
+ debug(F101,"ttpkt speed","",(int) speed);
+
+ ttprty = parity; /* Let other tt functions see these. */
+ ttspeed = speed; /* Make global copy for this module */
+ ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */
+#ifdef PARSENSE
+ needpchk = ttprty ? 0 : 1; /* Parity check needed? */
+#else
+ needpchk = 0;
+#endif /* PARSENSE */
+
+ debug(F101,"ttpkt ttpmsk","",ttpmsk);
+ debug(F101,"ttpkt netconn","",netconn);
+
+#ifdef NETCONN /* No mode-changing for telnet */
+ if (netconn) {
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+ if (ttnet == NET_TCPB) { /* But turn off Nagle */
+ extern int tcp_nodelay;
+ nodelay_sav = tcp_nodelay;
+ no_delay(ttyfd,1);
+ }
+#endif /* TCP_NODELAY */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = -1;
+ if (tvtflg == 0 && speed == ttspeed && flow == ttflow
+ /* && ttcarr == curcarr */ ) {
+ debug(F100,"ttpkt modes already set, skipping...","",0);
+ return(0); /* Already been called. */
+ }
+ if (flow != ttflow) {
+ if ((rc = tnsetflow(flow)) < 0)
+ return(rc);
+ ttflow = flow;
+ }
+ if (speed != ttspeed) {
+ if (speed <= 0)
+ speed = tnc_get_baud();
+ else if ((rc = tnc_set_baud(speed)) < 0)
+ return(rc);
+ ttspeed = speed;
+ }
+ tnc_set_datasize(8);
+ tnc_set_stopsize(stopbits);
+
+#ifdef HWPARITY
+ if (hwparity) {
+ switch (hwparity) {
+ case 'e': /* Even */
+ debug(F100,"ttres 8 bits + even parity","",0);
+ tnc_set_parity(3);
+ break;
+ case 'o': /* Odd */
+ debug(F100,"ttres 8 bits + odd parity","",0);
+ tnc_set_parity(2);
+ break;
+ case 'm': /* Mark */
+ debug(F100,"ttres 8 bits + invalid parity: mark","",0);
+ tnc_set_parity(4);
+ break;
+ case 's': /* Space */
+ debug(F100,"ttres 8 bits + invalid parity: space","",0);
+ tnc_set_parity(5);
+ break;
+ }
+ } else
+#endif /* HWPARITY */
+ {
+ tnc_set_parity(1); /* None */
+ }
+ tvtflg = 0;
+ return(0);
+ }
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+ tvtflg = 0;
+ return(0);
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+#ifndef Plan9
+ if (ttfdflg && !isatty(ttyfd)) return(0);
+#endif /* Plan9 */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifndef SVORPOSIX /* Berkeley, V7, etc. */
+#ifdef LPASS8
+/*
+ For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
+ after having previously set it to NONE without closing and reopening the
+ device. Unless there's something I overlooked below...
+*/
+ if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
+ debug(F101,"ttpkt executing horrible flow kludge","",0);
+ ttclos(0); /* Close it */
+ x = 0;
+ ttopen(ttnmsv,&x,ttmdm,0); /* Open it again */
+ }
+#endif /* LPASS8 */
+#endif /* SVORPOSIX */
+
+#ifdef COHERENT /* This must be vestigial since we */
+#undef SVORPOSIX /* reverse it a few lines below... */
+#endif /* COHERENT */
+
+ if (xflow != FLO_DIAL && xflow != FLO_DIAX)
+ ttflow = xflow; /* Now make this available too. */
+
+#ifndef NOLOCAL
+ if (xlocal) {
+ s2 = (int) (speed / 10L); /* Convert bps to cps */
+ debug(F101,"ttpkt calling ttsspd","",s2);
+ s = ttsspd(s2); /* Check and set the speed */
+ debug(F101,"ttpkt ttsspd result","",s);
+ carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
+ && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
+ tvtflg = 0; /* So ttvt() will work next time */
+ }
+#endif /* NOLOCAL */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifndef SVORPOSIX /* BSD section */
+ if (flow == FLO_RTSC || /* Hardware flow control */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tthflow(flow, 1, &ttraw);
+ debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ ttraw.sg_flags |= RAW; /* Enter raw mode */
+ } else if (flow == FLO_NONE) { /* No flow control */
+ debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ tthflow(flow, 0, &ttraw); /* Turn off any hardware f/c too */
+ ttraw.sg_flags |= RAW; /* Enter raw mode */
+ } else if (flow == FLO_KEEP) { /* Keep device's original setting */
+ debug(F100,"ttpkt keeping original TANDEM","",0);
+ ttraw.sg_flags &= ~TANDEM;
+ ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
+ /* NOTE: We should also handle hardware flow control here! */
+ }
+
+/* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
+
+ if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
+ debug(F100,"ttpkt turning on TANDEM","",0);
+ ttraw.sg_flags |= TANDEM; /* So ask for it. */
+
+#ifdef LPASS8 /* Can pass 8-bit data through? */
+/* If the LPASS8 local mode is available, then flow control can always */
+/* be used, even if parity is none and we are transferring 8-bit data. */
+/* But we only need to do all this if Xon/Xoff is requested. */
+/* BUT... this tends not to work through IP or LAT connections, terminal */
+/* servers, telnet, rlogin, etc, so it is currently disabled. */
+ x = LPASS8; /* If LPASS8 defined, then */
+ debug(F100,"ttpkt executing LPASS8 code","",0);
+ if (lmodef) { /* TIOCLBIS must be too. */
+ x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
+ if (x < 0) {
+ debug(F100,"ttpkt TIOCLBIS error","",0);
+ } else {
+ lmodef++;
+ debug(F100,"ttpkt TIOCLBIS ok","",0);
+ }
+ }
+/*
+ But if we use LPASS8 mode, we must explicitly turn off
+ terminal interrupts of all kinds.
+*/
+#ifdef TIOCGETC /* Not rawmode, */
+ if (tcharf && (xlocal == 0)) { /* must turn off */
+ tchnoi.t_intrc = -1; /* interrupt character */
+ tchnoi.t_quitc = -1; /* and quit character. */
+ tchnoi.t_startc = 17; /* Make sure xon */
+ tchnoi.t_stopc = 19; /* and xoff not ignored. */
+#ifndef NOBRKC
+ tchnoi.t_eofc = -1; /* eof character. */
+ tchnoi.t_brkc = -1; /* brk character. */
+#endif /* NOBRKC */
+ if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSETC failed","",0);
+ } else {
+ tcharf = 1;
+ debug(F100,"ttpkt TIOCSETC ok","",0);
+ }
+#ifdef COMMENT
+/* only for paranoid debugging */
+ if (tcharf) {
+ struct tchars foo;
+ char tchbuf[100];
+ ioctl(0,TIOCGETC,&foo);
+ sprintf(tchbuf,
+ "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
+ foo.t_intrc, foo.t_quitc, foo.t_startc,
+ foo.t_stopc, foo.t_eofc, foo.t_brkc);
+ debug(F110,"ttpkt chars",tchbuf,0);
+ }
+#endif /* COMMENT */
+ }
+ ttraw.sg_flags |= CBREAK; /* Needed for unknown reason */
+#endif /* TIOCGETC */
+
+/* Prevent suspend during packet mode */
+#ifdef TIOCGLTC /* Not rawmode, */
+ if (ltcharf && (xlocal == 0)) { /* must turn off */
+ ltchnoi.t_suspc = -1; /* suspend character */
+ ltchnoi.t_dsuspc = -1; /* and delayed suspend character */
+ if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSLTC failed","",0);
+ } else {
+ ltcharf = 1;
+ debug(F100,"ttpkt TIOCSLTC ok","",0);
+ }
+ }
+#endif /* TIOCGLTC */
+
+#else /* LPASS8 not defined */
+
+/* Previously, BSD-based implementations always */
+/* used rawmode for packets. Now, we use rawmode only if parity is NONE. */
+/* This allows the flow control requested above to actually work, but only */
+/* if the user asks for parity (which also means they get 8th-bit quoting). */
+
+ if (parity) { /* If parity, */
+ ttraw.sg_flags &= ~RAW; /* use cooked mode */
+#ifdef COMMENT
+/* WHY??? */
+ if (xlocal)
+#endif /* COMMENT */
+ ttraw.sg_flags |= CBREAK;
+ debug(F101,"ttpkt cooked, cbreak, parity","",parity);
+#ifdef TIOCGETC /* Not rawmode, */
+ if (tcharf && (xlocal == 0)) { /* must turn off */
+ tchnoi.t_intrc = -1; /* interrupt character */
+ tchnoi.t_quitc = -1; /* and quit character. */
+ tchnoi.t_startc = 17; /* Make sure xon */
+ tchnoi.t_stopc = 19; /* and xoff not ignored. */
+#ifndef NOBRKC
+ tchnoi.t_eofc = -1; /* eof character. */
+ tchnoi.t_brkc = -1; /* brk character. */
+#endif /* NOBRKC */
+ if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSETC failed","",0);
+ } else {
+ tcharf = 1;
+ debug(F100,"ttpkt TIOCSETC ok","",0);
+ }
+ }
+#endif /* TIOCGETC */
+#ifdef TIOCGLTC /* Not rawmode, */
+/* Prevent suspend during packet mode */
+ if (ltcharf && (xlocal == 0)) { /* must turn off */
+ ltchnoi.t_suspc = -1; /* suspend character */
+ ltchnoi.t_dsuspc = -1; /* and delayed suspend character */
+ if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
+ debug(F100,"ttpkt TIOCSLTC failed","",0);
+ } else {
+ ltcharf = 1;
+ debug(F100,"ttpkt TIOCSLTC ok","",0);
+ }
+ }
+#endif /* TIOCGLTC */
+ } else { /* If no parity, */
+ ttraw.sg_flags |= RAW; /* must use 8-bit raw mode. */
+ debug(F101,"ttpkt setting rawmode, parity","",parity);
+ }
+#endif /* LPASS8 */
+ } /* End of Xon/Xoff section */
+
+ /* Don't echo, don't map CR to CRLF on output, don't fool with case */
+#ifdef LCASE
+ ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
+#else
+ ttraw.sg_flags &= ~(ECHO|CRMOD);
+#endif /* LCASE */
+
+#ifdef TOWER1
+ ttraw.sg_flags &= ~ANYP; /* Must set this on old Towers */
+#endif /* TOWER1 */
+
+#ifdef BELLV10
+ if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
+ return(-1);
+#else
+ errno = 0;
+ if (stty(ttyfd,&ttraw) < 0) { /* Set the new modes. */
+ debug(F101,"ttpkt stty failed","",errno);
+ return(-1);
+ }
+#endif /* BELLV10 */
+ debug(F100,"ttpkt stty ok","",0);
+
+#ifdef sony_news
+ x = xlocal ? km_ext : km_con; /* Put line in ASCII mode. */
+ if (x != -1) { /* Make sure we know original modes. */
+ x &= ~KM_TTYPE;
+ x |= KM_ASCII;
+ if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
+ perror("ttpkt can't set ASCII mode");
+ debug(F101,"ttpkt error setting ASCII mode","",x);
+ return(-1);
+ }
+ }
+ debug(F100,"ttpkt set ASCII mode ok","",0);
+#endif /* sony_news */
+
+ if (xlocal == 0) { /* Turn this off so we can read */
+ signal(SIGINT,SIG_IGN); /* Ctrl-C chars typed at console */
+ sigint_ign = 1;
+ }
+ tvtflg = 0; /* So ttvt() will work next time */
+ debug(F100,"ttpkt success","",0);
+ return(0);
+
+#endif /* Not ATTSV or POSIX */
+
+/* AT&T UNIX and POSIX */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef SVORPOSIX
+ if (flow == FLO_XONX) { /* Xon/Xoff */
+ ttraw.c_iflag |= (IXON|IXOFF);
+ tthflow(flow, 0, &ttraw);
+ } else if (flow == FLO_NONE) { /* None */
+ /* NOTE: We should also turn off hardware flow control here! */
+ ttraw.c_iflag &= ~(IXON|IXOFF);
+ tthflow(flow, 0, &ttraw);
+ } else if (flow == FLO_KEEP) { /* Keep */
+ ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
+ ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
+ /* NOTE: We should also handle hardware flow control here! */
+#ifdef POSIX_CRTSCTS
+/* In Linux case, we do this, which is unlikely to be portable */
+ ttraw.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */
+ ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
+#endif /* POSIX_CRTSCTS */
+ } else if (flow == FLO_RTSC || /* Hardware */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
+ tthflow(flow, 1, &ttraw);
+ }
+ ttraw.c_lflag &= ~(ICANON|ECHO);
+ ttraw.c_lflag &= ~ISIG; /* Do NOT check for interrupt chars */
+
+#ifndef OXOS
+#ifdef QNX
+ if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
+#endif /* QNX */
+#ifndef COHERENT
+ ttraw.c_lflag &= ~IEXTEN; /* Turn off ^O/^V processing */
+#endif /* COHERENT */
+#else /* OXOS */
+ ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+ ttraw.c_lflag |= NOFLSH; /* Don't flush */
+ ttraw.c_iflag |= IGNPAR; /* Ignore parity errors */
+#ifdef ATTSV
+#ifdef BSD44
+ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
+#else
+ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
+#endif /* BSD44 */
+#else /* POSIX */
+ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
+#endif /* ATTSV */
+ ttraw.c_oflag &= ~OPOST;
+ ttraw.c_cflag &= ~(CSIZE);
+ ttraw.c_cflag |= (CS8|CREAD|HUPCL);
+
+#ifdef CSTOPB
+ if (xlocal) {
+ if (stopbits == 2) {
+ ttraw.c_cflag |= CSTOPB; /* 2 stop bits */
+ debug(F100,"ttpkt 2 stopbits","",0);
+ } else if (stopbits == 1) {
+ ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */
+ debug(F100,"ttpkt 1 stopbit","",0);
+ }
+ }
+#endif /* CSTOPB */
+
+#ifdef HWPARITY
+ if (hwparity && xlocal) { /* Hardware parity */
+ ttraw.c_cflag |= PARENB; /* Enable parity */
+#ifdef COMMENT
+/* Uncomment this only if needed -- I don't think it is */
+ ttraw.c_cflag &= ~(CSIZE); /* Clear out character-size mask */
+ ttraw.c_cflag |= CS8; /* And set it to 8 */
+#endif /* COMMENT */
+#ifdef IGNPAR
+ ttraw.c_iflag |= IGNPAR; /* Don't discard incoming bytes */
+ debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
+#endif /* IGNPAR */
+ switch (hwparity) {
+ case 'e': /* Even */
+ ttraw.c_cflag &= ~(PARODD);
+ debug(F100,"ttpkt 8 bits + even parity","",0);
+ break;
+ case 'o': /* Odd */
+ ttraw.c_cflag |= PARODD;
+ debug(F100,"ttpkt 8 bits + odd parity","",0);
+ break;
+ case 'm': /* Mark */
+ case 's': /* Space */
+ /* PAREXT is mentioned in SVID but the details are not given. */
+ /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
+ debug(F100,"ttpkt 8 bits + invalid parity","",0);
+ break;
+ }
+ } else { /* We handle parity ourselves */
+#endif /* HWPARITY */
+ ttraw.c_cflag &= ~(PARENB); /* Don't enable parity */
+#ifdef HWPARITY
+ }
+#endif /* HWPARITY */
+
+#ifdef IX370
+ ttraw.c_cc[4] = 48; /* So Series/1 doesn't interrupt on every char */
+ ttraw.c_cc[5] = 1;
+#else
+#ifndef VEOF /* for DGUX this is VEOF, not VMIN */
+ ttraw.c_cc[4] = 1; /* [VMIN] return max of this many characters or */
+#else
+#ifndef OXOS
+#ifdef VMIN
+ ttraw.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ ttraw.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+#ifndef VEOL /* for DGUX this is VEOL, not VTIME */
+ ttraw.c_cc[5] = 0; /* [VTIME] when this many secs/10 expire w/no input */
+#else
+#ifndef OXOS
+#ifdef VTIME
+ ttraw.c_cc[VTIME] = 0;
+#endif /* VTIME */
+#else /* OXOS */
+ ttraw.c_time = 0;
+#endif /* OXOS */
+#endif /* VEOL */
+#endif /* IX370 */
+
+#ifdef VINTR /* Turn off interrupt character */
+ if (xlocal == 0) /* so ^C^C can break us out of */
+ ttraw.c_cc[VINTR] = 0; /* packet mode. */
+#endif /* VINTR */
+
+#ifdef Plan9
+ if (p9ttyparity('n') < 0)
+ return -1;
+#else
+#ifdef BSD44ORPOSIX
+ errno = 0;
+#ifdef BEOSORBEBOX
+ ttraw.c_cc[VMIN] = 0; /* DR7 can only poll. */
+#endif /* BEOSORBEBOX */
+
+#define TESTING234
+#ifdef TESTING234
+ if (1) {
+ debug(F100,"ttpkt TESTING234 rawmode","",0);
+
+ /* iflags */
+ ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
+ ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
+ ttraw.c_iflag |= IGNBRK;
+#ifdef IMAXBEL
+ ttraw.c_iflag &= ~IMAXBEL;
+#endif /* IMAXBEL */
+#ifdef IXANY
+ ttraw.c_iflag &= ~IXANY;
+#endif /* IXANY */
+#ifdef IUCLC
+ ttraw.c_iflag &= ~IUCLC;
+#endif /* IUCLC */
+
+ /* oflags */
+ ttraw.c_oflag &= ~OPOST;
+#ifdef OXTABS
+ ttraw.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+#ifdef ONOCR
+ ttraw.c_oflag &= ~ONOCR;
+#endif /* ONOCR */
+#ifdef ONLRET
+ ttraw.c_oflag &= ~ONLRET;
+#endif /* ONLRET */
+#ifdef ONLCR
+ ttraw.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+
+ /* lflags */
+ ttraw.c_lflag &= ~ECHO;
+#ifdef ECHOE
+ ttraw.c_lflag &= ~ECHOE;
+#endif /* ECHOE */
+#ifdef ECHONL
+ ttraw.c_lflag &= ~ECHONL;
+#endif /* ECHONL */
+#ifdef ECHOPRT
+ ttraw.c_lflag &= ~ECHOPRT;
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ ttraw.c_lflag &= ~ECHOKE;
+#endif /* ECHOKE */
+#ifdef ECHOCTL
+ ttraw.c_lflag &= ~ECHOCTL;
+#endif /* ECHOCTL */
+#ifdef ALTWERASE
+ ttraw.c_lflag &= ~ALTWERASE;
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ ttraw.c_lflag &= ~EXTPROC;
+#endif /* EXTPROC */
+ ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
+#ifdef NOKERNINFO
+ ttraw.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+ /* ttraw.c_lflag |= NOFLSH; */
+ ttraw.c_lflag &= ~NOFLSH;
+
+ /* cflags */
+ ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ ttraw.c_cflag |= CS8|CREAD;
+#ifdef VMIN
+ ttraw.c_cc[VMIN] = 1; /* Supposedly needed for AIX */
+#endif /* VMIN */
+
+ }
+#endif /* TESTING234 */
+
+ debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
+ debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
+ if (x < 0) {
+ debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
+ return(-1);
+ }
+#else /* BSD44ORPOSIX */
+ x = ioctl(ttyfd,TCSETAW,&ttraw);
+ debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
+ if (x < 0) { /* set new modes . */
+ debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
+ return(-1);
+ }
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+ tvtflg = 0;
+ debug(F100,"ttpkt ok","",0);
+ return(0);
+#endif /* ATTSV */
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+}
+
+/* T T S E T F L O W -- Set flow control immediately. */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+int
+ttsetflow(flow) int flow; {
+ if (ttyfd < 0) /* A channel must be open */
+ return(-1);
+
+ debug(F101,"ttsetflow flow","",flow);
+
+#ifdef TN_COMPORT
+ if (netconn && istncomport()) {
+ debug(F101,"ttsetflow net modem","",ttmdm);
+ return(tnsetflow(flow));
+ }
+#endif /* TN_COMPORT */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+#ifdef COMMENT
+ /* This seems to hurt... */
+ if (flow == FLO_KEEP)
+ return(0);
+#endif /* COMMENT */
+
+ if (flow == FLO_RTSC || /* Hardware flow control... */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tthflow(flow, 1, &ttraw);
+#ifndef SVORPOSIX
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+#else
+ ttraw.c_iflag &= ~(IXON|IXOFF);
+#endif /* SVORPOSIX */
+
+ } else if (flow == FLO_XONX) { /* Xon/Xoff... */
+
+#ifndef SVORPOSIX
+ ttraw.sg_flags |= TANDEM;
+#else
+ ttraw.c_iflag |= (IXON|IXOFF);
+#endif /* SVORPOSIX */
+ tthflow(FLO_RTSC, 0, &ttraw); /* Turn off hardware flow control */
+
+ } else if (flow == FLO_NONE) { /* No flow control */
+
+#ifndef SVORPOSIX
+ ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
+#else
+ ttraw.c_iflag &= ~(IXON|IXOFF);
+#endif /* SVORPOSIX */
+ tthflow(FLO_RTSC, 0, &ttraw); /* Turn off any hardware f/c too */
+ }
+
+/* Set the new modes... */
+
+#ifndef SVORPOSIX /* BSD and friends */
+#ifdef BELLV10
+ if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
+ return(-1);
+#else
+#ifndef MINIX2
+ if (stty(ttyfd,&ttraw) < 0)
+ return(-1);
+#endif /* MINIX2 */
+#endif /* BELLV10 */
+#else
+#ifdef BSD44ORPOSIX /* POSIX */
+ if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
+ return(-1);
+#else /* System V */
+ if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
+ return(-1);
+#endif /* BSD44ORPOSIX */
+#endif /* SVORPOSIX */
+ return(0);
+}
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+/* T T V T -- Condition communication device for use as virtual terminal. */
+
+int
+#ifdef CK_ANSIC
+ttvt(long speed, int flow)
+#else
+ttvt(speed,flow) long speed; int flow;
+#endif /* CK_ANSIC */
+/* ttvt */ {
+ int s, s2, x;
+
+ debug(F101,"ttvt ttyfd","",ttyfd);
+ debug(F101,"ttvt tvtflg","",tvtflg);
+ debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
+ debug(F111,"ttvt flow",ckitoa(ttflow),flow);
+ debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
+
+/* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
+/* Maybe it would be simpler to use it... */
+
+ ttpmsk = 0xff;
+#ifdef NOLOCAL
+ return(conbin((char)escchr));
+#else
+ if (ttyfd < 0) { /* Not open. */
+ if (ttchk() < 0)
+ return(-1);
+ else /* But maybe something buffered. */
+ return(0);
+ }
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+#ifdef NETCONN
+ if (netconn) {
+#ifdef TCPSOCKET
+#ifdef TCP_NODELAY
+ {
+ extern int tcp_nodelay;
+ if (ttnet == NET_TCPB) {
+ if (nodelay_sav > -1) {
+ no_delay(ttyfd,nodelay_sav);
+ nodelay_sav = -1;
+ }
+ }
+ }
+#endif /* TCP_NODELAY */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int rc = -1;
+ if (tvtflg != 0 && speed == ttspeed && flow == ttflow
+ /* && ttcarr == curcarr */ ) {
+ debug(F100,"ttvt modes already set, skipping...","",0);
+ return(0); /* Already been called. */
+ }
+ if (flow != ttflow) {
+ if ((rc = tnsetflow(flow)) < 0)
+ return(rc);
+ ttflow = flow;
+ }
+ if (speed != ttspeed) {
+ if (speed <= 0)
+ speed = tnc_get_baud();
+ else if ((rc = tnc_set_baud(speed)) < 0)
+ return(rc);
+ ttspeed = speed;
+ }
+ tnc_set_datasize(8);
+ tnc_set_stopsize(stopbits);
+
+#ifdef HWPARITY
+ if (hwparity) {
+ switch (hwparity) {
+ case 'e': /* Even */
+ debug(F100,"ttres 8 bits + even parity","",0);
+ tnc_set_parity(3);
+ break;
+ case 'o': /* Odd */
+ debug(F100,"ttres 8 bits + odd parity","",0);
+ tnc_set_parity(2);
+ break;
+ case 'm': /* Mark */
+ debug(F100,"ttres 8 bits + invalid parity: mark","",0);
+ tnc_set_parity(4);
+ break;
+ case 's': /* Space */
+ debug(F100,"ttres 8 bits + invalid parity: space","",0);
+ tnc_set_parity(5);
+ break;
+ }
+ } else
+#endif /* HWPARITY */
+ {
+ tnc_set_parity(1); /* None */
+ }
+ tvtflg = 1;
+ return(0);
+ }
+#endif /* TN_COMPORT */
+#endif /* TCPSOCKET */
+ tvtflg = 1; /* Network connections... */
+ debug(F100,"ttvt network connection, skipping...","",0);
+ return(0); /* ... require no special setup */
+ }
+#endif /* NETCONN */
+
+ if (tvtflg != 0 && speed == ttspeed && flow == ttflow
+ /* && ttcarr == curcarr */ )
+ {
+ debug(F100,"ttvt modes already set, skipping...","",0);
+ return(0); /* Already been called. */
+ }
+
+ if (ttfdflg
+#ifndef Plan9
+ && !isatty(ttyfd)
+#endif /* Plan9 */
+ ) {
+ debug(F100,"ttvt using external fd, skipping...","",0);
+ return(0);
+ }
+
+ debug(F100,"ttvt setting modes...","",0);
+
+ if (xlocal) { /* For external lines... */
+ s2 = (int) (speed / 10L);
+ s = ttsspd(s2); /* Check/set the speed */
+ carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
+ && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
+ } else
+ s = s2 = -1;
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifndef SVORPOSIX
+ /* Berkeley, V7, etc */
+ if (flow == FLO_RTSC || /* Hardware flow control */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tthflow(flow, 1, &tttvt);
+ debug(F100,"ttvt hard flow, TANDEM off","",0);
+ tttvt.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ } else if (flow == FLO_XONX) { /* Xon/Xoff flow control */
+ debug(F100,"ttvt TANDEM on","",0);
+ tttvt.sg_flags |= TANDEM; /* Ask for it. */
+ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
+ } else if (flow == FLO_NONE) {
+ debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
+ tttvt.sg_flags &= ~TANDEM; /* Turn off software flow control */
+ tthflow(flow, 0, &tttvt); /* Turn off any hardware f/c too */
+ tttvt.sg_flags |= RAW; /* Enter raw mode */
+ } else if (flow == FLO_KEEP) { /* Keep device's original setting */
+ debug(F100,"ttvt keeping original TANDEM","",0);
+ tttvt.sg_flags &= ~TANDEM;
+ tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
+ /* NOTE: We should also handle hardware flow control here! */
+ }
+ tttvt.sg_flags |= RAW; /* Raw mode in all cases */
+#ifdef TOWER1
+ tttvt.sg_flags &= ~(ECHO|ANYP); /* No echo or parity */
+#else
+ tttvt.sg_flags &= ~ECHO; /* No echo */
+#endif /* TOWER1 */
+
+#ifdef BELLV10
+ if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
+ return(-1);
+#else
+ if (stty(ttyfd,&tttvt) < 0) /* Set the new modes */
+ return(-1);
+#endif /* BELLV10 */
+
+#else /* It is ATTSV or POSIX */
+
+ if (flow == FLO_XONX) { /* Software flow control */
+ tttvt.c_iflag |= (IXON|IXOFF); /* On if requested. */
+ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
+ debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
+ } else if (flow == FLO_NONE) { /* NONE */
+ tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
+ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
+ debug(F100,"ttvt SVORPOSIX flow NONE","",0);
+ } else if (flow == FLO_KEEP) {
+ tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
+ tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
+#ifdef POSIX_CRTSCTS
+ tttvt.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */
+ tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
+#endif /* POSIX_CRTSCTS */
+ debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
+ } else if (flow == FLO_RTSC || /* Hardware flow control */
+ flow == FLO_DTRC ||
+ flow == FLO_DTRT) {
+ tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */
+ tthflow(flow, 1, &tttvt);
+ debug(F100,"ttvt SVORPOSIX flow HARD","",0);
+ }
+#ifndef OXOS
+#ifdef COHERENT
+ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
+#else
+ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
+#endif /* COHERENT */
+#ifdef QNX
+ /* Needed for hwfc */
+ if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
+ tttvt.c_lflag |= IEXTEN;
+#endif /* QNX */
+#else /* OXOS */
+ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
+ tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+
+ tttvt.c_iflag |= (IGNBRK|IGNPAR);
+
+/* Stop bits */
+
+#ifdef CSTOPB
+ if (xlocal) {
+ if (stopbits == 2) {
+ tttvt.c_cflag |= CSTOPB; /* 2 stop bits */
+ debug(F100,"ttvt 2 stopbits","",0);
+ } else if (stopbits == 1) {
+ tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */
+ debug(F100,"ttvt 1 stopbit","",0);
+ }
+ }
+#endif /* CSTOPB */
+
+/* Parity */
+
+#ifdef HWPARITY
+ if (hwparity && xlocal) { /* Hardware parity */
+#ifdef COMMENT
+/* Uncomment this only if needed -- I don't think it is */
+ ttraw.c_cflag &= ~(CSIZE); /* Clear out character-size mask */
+ ttraw.c_cflag |= CS8; /* And set it to 8 */
+#endif /* COMMENT */
+#ifdef IGNPAR
+ debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
+ tttvt.c_iflag |= IGNPAR; /* Don't discard incoming bytes */
+#endif /* IGNPAR */
+ tttvt.c_cflag |= PARENB; /* Enable parity */
+
+ switch (hwparity) {
+ case 'e': /* Even */
+ tttvt.c_cflag &= ~(PARODD);
+ debug(F100,"ttvt 8 bits + even parity","",0);
+ break;
+ case 'o': /* Odd */
+ tttvt.c_cflag |= PARODD;
+ debug(F100,"ttvt 8 bits + odd parity","",0);
+ break;
+ case 'm': /* Mark */
+ case 's': /* Space */
+ /* PAREXT is mentioned in SVID but the details are not given. */
+ /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
+ debug(F100,"ttvt 8 bits + invalid parity","",0);
+ break;
+ }
+ } else { /* We handle parity ourselves */
+#endif /* HWPARITY */
+ tttvt.c_cflag &= ~(PARENB); /* Don't enable parity */
+#ifdef HWPARITY
+ }
+#endif /* HWPARITY */
+
+#ifdef ATTSV
+#ifdef BSD44
+ /* Things not to do... */
+ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
+#else
+ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
+#endif /* BSD44 */
+#else /* POSIX */
+ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
+#endif /* ATTSV */
+ tttvt.c_cflag &= ~(CSIZE); /* Zero out the char size field */
+ tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */
+ tttvt.c_oflag &= ~OPOST; /* Don't postprocess output */
+#ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
+ tttvt.c_cc[4] = 1;
+#else
+#ifndef OXOS
+#ifdef VMIN
+ tttvt.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ tttvt.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+#ifndef VEOL /* DGUX termio has VEOL at entry 5, see comment above */
+ tttvt.c_cc[5] = 0;
+#else
+#ifndef OXOS
+#ifdef VTIME
+ tttvt.c_cc[VTIME] = 0;
+#endif /* VTIME */
+#else /* OXOS */
+ tttvt.c_time = 0;
+#endif /* OXOS */
+#endif /* VEOL */
+
+#ifdef Plan9
+ if (p9ttyparity('n') < 0)
+ return -1;
+#else
+#ifdef BSD44ORPOSIX
+ errno = 0;
+#ifdef BEOSORBEBOX
+ tttvt.c_cc[VMIN] = 0; /* DR7 can only poll. */
+#endif /* BEOSORBEBOX */
+
+ x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
+ debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
+ if (x < 0) {
+ debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
+ return(-1);
+ }
+#else /* ATTSV */
+ x = ioctl(ttyfd,TCSETAW,&tttvt);
+ debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
+ if (x < 0) { /* set new modes . */
+ debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
+ return(-1);
+ }
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+#endif /* ATTSV */
+
+ ttspeed = speed; /* Done, remember how we were */
+ ttflow = flow; /* called, so we can decide how to */
+ tvtflg = 1; /* respond next time. */
+ debug(F100,"ttvt ok","",0);
+ return(0);
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+#endif /* NOLOCAL */
+}
+
+#ifndef NOLOCAL
+
+/* Serial speed department . . . */
+
+/*
+ SCO OSR5.0.x might or might not support high speeds. Sometimes they are not
+ defined in the header files but they are supported (e.g. when building with
+ UDK compiler rather than /bin/cc), sometimes vice versa. Even though 5.0.4
+ was the first release that came with high serial speeds standard, releases
+ back to 5.0.0 could use them if certain patches (or "supplements") were
+ applied to the SIO driver. Plus a lot of SCO installations run third-party
+ drivers.
+*/
+#ifdef CK_SCOV5
+#ifndef B38400
+#define B38400 0000017
+#endif /* B38400 */
+#ifndef B57600
+#define B57600 0000021
+#endif /* B57600 */
+#ifndef B76800
+#define B76800 0000022
+#endif /* B76800 */
+#ifndef B115200
+#define B115200 0000023
+#endif /* B115200 */
+#ifndef B230400
+#define B230400 0000024
+#endif /* B230400 */
+#ifndef B460800
+#define B460800 0000025
+#endif /* B460800 */
+#ifndef B921600
+#define B921600 0000026
+#endif /* B921600 */
+#endif /* CK_SCOV5 */
+/*
+ Plan 9's native speed setting interface lets you set anything you like,
+ but will fail if the hardware doesn't like it, so we allow all the common
+ speeds.
+*/
+#ifdef Plan9
+#ifndef B50
+#define B50 50
+#endif /* B50 */
+#ifndef B75
+#define B75 75
+#endif /* B75 */
+#ifndef B110
+#define B110 110
+#endif /* B110 */
+#ifndef B134
+#define B134 134
+#endif /* B134 */
+#ifndef B200
+#define B200 200
+#endif /* B200 */
+#ifndef B300
+#define B300 300
+#endif /* B300 */
+#ifndef B1200
+#define B1200 1200
+#endif /* B1200 */
+#ifndef B1800
+#define B1800 1800
+#endif /* B1800 */
+#ifndef B2400
+#define B2400 2400
+#endif /* B2400 */
+#ifndef B4800
+#define B4800 4800
+#endif /* B4800 */
+#ifndef B9600
+#define B9600 9600
+#endif /* B9600 */
+#ifndef B14400
+#define B14400 14400
+#endif /* B14400 */
+#ifndef B19200
+#define B19200 19200
+#endif /* B19200 */
+#ifndef B28800
+#define B28800 28800
+#endif /* B28800 */
+#ifndef B38400
+#define B38400 38400
+#endif /* B38400 */
+#ifndef B57600
+#define B57600 57600
+#endif /* B57600 */
+#ifndef B76800
+#define B76800 76800
+#endif /* B76800 */
+#ifndef B115200
+#define B115200 115200
+#endif /* B115200 */
+#ifndef B230400
+#define B230400 230400
+#endif /* B230400 */
+#ifndef B460800
+#define B460800 460800
+#endif /* B460800 */
+#ifndef B921600
+#define B921600 921600
+#endif /* B921600 */
+#endif /* Plan9 */
+
+/* T T S S P D -- Checks and sets transmission rate. */
+
+/* Call with speed in characters (not bits!) per second. */
+/* Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
+
+#ifdef USETCSETSPEED
+/*
+ The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
+ to be used as a speed to be set, rather than forcing a choice from a
+ predefined list. It seems to be peculiar to UnixWare 7.
+
+ These are the function codes to be passed to tc[gs]etspeed(),
+ but for some reason they don't seem to be picked up from termios.h.
+*/
+#ifndef TCS_ALL
+#define TCS_ALL 0
+#endif /* TCS_ALL */
+#ifndef TCS_IN
+#define TCS_IN 1
+#endif /* TCS_IN */
+#ifndef TCS_OUT
+#define TCS_OUT 2
+#endif /* TCS_OUT */
+#endif /* USETCSETSPEED */
+
+int
+ttsspd(cps) int cps; {
+ int x;
+#ifdef POSIX
+/* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
+ speed_t
+#else
+ int
+#endif /* POSIX */
+ s, s2;
+ int ok = 1; /* Speed check result, assume ok */
+
+#ifdef OLINUXHISPEED
+ unsigned int spd_flags = 0;
+ struct serial_struct serinfo;
+#endif /* OLINUXHISPEED */
+
+ debug(F101,"ttsspd cps","",cps);
+ debug(F101,"ttsspd ttyfd","",ttyfd);
+ debug(F101,"ttsspd xlocal","",xlocal);
+
+ if (ttyfd < 0 || xlocal == 0) /* Don't set speed on console */
+ return(0);
+
+#ifdef NETCONN
+ if (netconn) {
+#ifdef TN_COMPORT
+ if (istncomport())
+ return(tnc_set_baud(cps * 10));
+ else
+#endif /* TN_COMPORT */
+ return(0);
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(0);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(0);
+#endif /* NETPTY */
+
+ if (cps < 0) return(-1);
+ s = s2 = 0; /* NB: s and s2 might be unsigned */
+
+#ifdef USETCSETSPEED
+
+ s = cps * 10L;
+
+ x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
+ debug(F101,"ttsspd tcgetattr","",x);
+ if (x < 0)
+ return(-1);
+ debug(F101,"ttsspd TCSETSPEED speed","",s);
+
+ errno = 0;
+ if (s == 8880L) { /* 75/1200 split speed requested */
+ tcsetspeed(TCS_IN, &ttcur, 1200L);
+ tcsetspeed(TCS_OUT, &ttcur, 75L);
+ } else
+ tcsetspeed(TCS_ALL, &ttcur, s); /* Put new speed in structs */
+#ifdef DEBUG
+ if (errno & deblog) {
+ debug(F101,"ttsspd TCSETSPEED errno","",errno);
+ }
+#endif /* DEBUG */
+
+#ifdef COMMENT
+ tcsetspeed(TCS_ALL, &ttraw, s);
+ tcsetspeed(TCS_ALL, &tttvt, s);
+ tcsetspeed(TCS_ALL, &ttold, s);
+#else
+ if (s == 8880L) { /* 75/1200 split speed requested */
+ tcsetspeed(TCS_IN, &ttraw, 1200L);
+ tcsetspeed(TCS_OUT, &ttraw, 75L);
+ tcsetspeed(TCS_IN, &tttvt, 1200L);
+ tcsetspeed(TCS_OUT, &tttvt, 75L);
+ tcsetspeed(TCS_IN, &ttold, 1200L);
+ tcsetspeed(TCS_OUT, &ttold, 75L);
+ } else {
+ tcsetspeed(TCS_ALL, &ttraw, s);
+ tcsetspeed(TCS_ALL, &tttvt, s);
+ tcsetspeed(TCS_ALL, &ttold, s);
+ }
+#endif /* COMMENT */
+
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
+ debug(F101,"ttsspd tcsetattr","",x);
+ if (x < 0)
+ return(-1);
+
+#else /* Not USETCSETSPEED */
+
+ /* First check that the given speed is valid. */
+
+ switch (cps) {
+#ifndef MINIX
+ case 0: s = B0; break;
+ case 5: s = B50; break;
+ case 7: s = B75; break;
+#endif /* MINIX */
+ case 11: s = B110; break;
+#ifndef MINIX
+ case 13: s = B134; break;
+ case 15: s = B150; break;
+ case 20: s = B200; break;
+#endif /* MINIX */
+ case 30: s = B300; break;
+#ifndef MINIX
+ case 60: s = B600; break;
+#endif /* MINIX */
+ case 120: s = B1200; break;
+#ifndef MINIX
+ case 180: s = B1800; break;
+#endif /* MINIX */
+ case 240: s = B2400; break;
+ case 480: s = B4800; break;
+#ifndef MINIX
+ case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
+#endif /* MINIX */
+#ifdef B7200
+ case 720: s = B7200; break;
+#endif /* B7200 */
+ case 960: s = B9600; break;
+#ifdef B14400
+ case 1440: s = B14400; break;
+#endif /* B14400 */
+#ifdef B19200
+ case 1920: s = B19200; break;
+#else
+#ifdef EXTA
+ case 1920: s = EXTA; break;
+#endif /* EXTA */
+#endif /* B19200 */
+#ifdef B28800
+ case 2880: s = B28800; break;
+#endif /* B28800 */
+#ifdef B38400
+ case 3840: s = B38400;
+#ifdef OLINUXHISPEED
+ spd_flags = ~ASYNC_SPD_MASK; /* Nonzero, but zero flags */
+#endif /* OLINUXHISPEED */
+ break;
+#else /* B38400 not defined... */
+#ifdef EXTB
+ case 3840: s = EXTB; break;
+#endif /* EXTB */
+#endif /* B38400 */
+
+#ifdef HPUX
+#ifdef _B57600
+ case 5760: s = _B57600; break;
+#endif /* _B57600 */
+#ifdef _B115200
+ case 11520: s = _B115200; break;
+#endif /* _B115200 */
+#else
+#ifdef OLINUXHISPEED
+/*
+ This bit from <carlo@sg.tn.tudelft.nl>:
+ "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
+ setting the speed to 38400 will set the custom speed (and ttgspd returns
+ 38400), but speeds 57600 and 115200 won't work any more because I didn't
+ want to mess up the speed flags when someone is doing sophisticated stuff
+ like custom speeds..."
+*/
+ case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
+ case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
+#else
+#ifdef B57600
+ case 5760: s = B57600; break;
+#endif /* B57600 */
+#ifdef B76800
+ case 7680: s = B76800; break;
+#endif /* B76800 */
+#ifdef B115200
+ case 11520: s = B115200; break;
+#endif /* B115200 */
+#endif /* OLINUXHISPEED */
+#ifdef B153600
+ case 15360: s = B153600; break;
+#endif /* B153600 */
+#ifdef B230400
+ case 23040: s = B230400; break;
+#endif /* B230400 */
+#ifdef B307200
+ case 30720: s = B307200; break;
+#endif /* B307200 */
+#ifdef B460800
+ case 46080: s = B460800; break;
+#endif /* 460800 */
+#ifdef B921600
+ case 92160: s = B921600; break;
+#endif /* B921600 */
+#endif /* HPUX */
+ default:
+ ok = 0; /* Good speed not found, so not ok */
+ break;
+ }
+ debug(F101,"ttsspd ok","",ok);
+ debug(F101,"ttsspd s","",s);
+
+ if (!ok) {
+ debug(F100,"ttsspd fails","",0);
+ return(-1);
+ } else {
+ if (!s2) s2 = s; /* Set input speed */
+#ifdef Plan9
+ if (p9ttsspd(cps) < 0)
+ return(-1);
+#else
+#ifdef BSD44ORPOSIX
+ x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
+ debug(F101,"ttsspd tcgetattr","",x);
+ if (x < 0)
+ return(-1);
+#ifdef OLINUXHISPEED
+ debug(F101,"ttsspd spd_flags","",spd_flags);
+ if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
+ if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
+ debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
+ return(-1);
+ } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
+ serinfo.flags &= ~ASYNC_SPD_MASK;
+ serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
+ if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
+ return(-1);
+ }
+#endif /* OLINUXHISPEED */
+ cfsetospeed(&ttcur,s);
+ cfsetispeed(&ttcur,s2);
+ cfsetospeed(&ttraw,s);
+ cfsetispeed(&ttraw,s2);
+ cfsetospeed(&tttvt,s);
+ cfsetispeed(&tttvt,s2);
+ cfsetospeed(&ttold,s);
+ cfsetispeed(&ttold,s2);
+ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+ debug(F101,"ttsspd tcsetattr","",x);
+ if (x < 0) return(-1);
+#else
+#ifdef ATTSV
+ if (cps == 888) return(-1); /* No split speeds, sorry. */
+ x = ioctl(ttyfd,TCGETA,&ttcur);
+ debug(F101,"ttsspd TCGETA ioctl","",x);
+ if (x < 0) return(-1);
+ ttcur.c_cflag &= ~CBAUD;
+ ttcur.c_cflag |= s;
+ tttvt.c_cflag &= ~CBAUD;
+ tttvt.c_cflag |= s;
+ ttraw.c_cflag &= ~CBAUD;
+ ttraw.c_cflag |= s;
+ ttold.c_cflag &= ~CBAUD;
+ ttold.c_cflag |= s;
+ x = ioctl(ttyfd,TCSETAW,&ttcur);
+ debug(F101,"ttsspd TCSETAW ioctl","",x);
+ if (x < 0) return(-1);
+#else
+#ifdef BELLV10
+ x = ioctl(ttyfd,TIOCGDEV,&tdcur);
+ debug(F101,"ttsspd TIOCGDEV ioctl","",x);
+ if (x < 0) return(-1);
+ tdcur.ispeed = s2;
+ tdcur.ospeed = s;
+ errno = 0;
+ ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
+ debug(F101,"ttsspd BELLV10 ioctl","",ok);
+ if (ok < 0) {
+ perror(ttnmsv);
+ debug(F101,"ttsspd BELLV10 errno","",ok);
+ return(-1);
+ }
+#else
+ x = gtty(ttyfd,&ttcur);
+ debug(F101,"ttsspd gtty","",x);
+ if (x < 0) return(-1);
+ ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
+ tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
+ ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
+ ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
+ x = stty(ttyfd,&ttcur);
+ debug(F101,"ttsspd stty","",x);
+ if (x < 0) return(-1);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+ }
+ return(1); /* Return 1 = success. */
+#endif /* USETCSETSPEED */
+}
+
+#endif /* NOLOCAL */
+
+/* C O N G S P D - Get speed of console terminal */
+
+long
+congspd() {
+/*
+ This is a disgusting hack. The right way to do this would be to pass an
+ argument to ttgspd(), but then we'd need to change the Kermit API and
+ all of the ck?tio.c modules. (Currently used only for rlogin.)
+*/
+ int t1;
+ long spd;
+#ifdef NETCONN
+ int t2 = netconn;
+ netconn = 0;
+#endif /* NETCONN */
+ t1 = ttyfd;
+ ttyfd = -1;
+ spd = ttgspd();
+ debug(F101,"congspd","",spd);
+#ifdef NETCONN
+ netconn = t2;
+#endif /* NETCONN */
+ ttyfd = t1;
+ return(spd);
+}
+
+/* T T S P D L I S T -- Get list of serial speeds allowed on this platform */
+
+#define NSPDLIST 64
+static long spdlist[NSPDLIST];
+/*
+ As written, this picks up the speeds known at compile time, and thus
+ apply to the system where C-Kermit was built, rather than to the one where
+ it is running. Suggestions for improvement are always welcome.
+*/
+long *
+ttspdlist() {
+ int i;
+ for (i = 0; i < NSPDLIST; i++) /* Initialize the list */
+ spdlist[i] = -1L;
+ i = 1;
+
+#ifdef USETCSETSPEED /* No way to find out what's legal */
+ debug(F100,"ttspdlist USETCSETSPEED","",0);
+ spdlist[i++] = 50L;
+#ifndef UW7
+ spdlist[i++] = 75L;
+#endif /* UW7 */
+ spdlist[i++] = 110L;
+#ifndef UW7
+ spdlist[i++] = 134L;
+#endif /* UW7 */
+ spdlist[i++] = 150L;
+ spdlist[i++] = 200L;
+ spdlist[i++] = 300L;
+ spdlist[i++] = 600L;
+ spdlist[i++] = 1200L;
+ spdlist[i++] = 1800L;
+ spdlist[i++] = 2400L;
+ spdlist[i++] = 4800L;
+ spdlist[i++] = 8880L;
+ spdlist[i++] = 9600L;
+ spdlist[i++] = 14400L;
+ spdlist[i++] = 19200L;
+ spdlist[i++] = 28800L;
+#ifndef UW7
+ spdlist[i++] = 33600L;
+#endif /* UW7 */
+ spdlist[i++] = 38400L;
+ spdlist[i++] = 57600L;
+ spdlist[i++] = 76800L;
+ spdlist[i++] = 115200L;
+#ifndef UW7
+ spdlist[i++] = 153600L;
+ spdlist[i++] = 230400L;
+ spdlist[i++] = 307200L;
+ spdlist[i++] = 460800L;
+ spdlist[i++] = 921600L;
+#endif /* UW7 */
+
+#else /* USETCSETSPEED */
+
+ debug(F100,"ttspdlist no USETCSETSPEED","",0);
+
+#ifdef B50
+ debug(F101,"ttspdlist B50","",B50);
+ spdlist[i++] = 50L;
+#endif /* B50 */
+#ifdef B75
+ debug(F101,"ttspdlist B75","",B75);
+ spdlist[i++] = 75L;
+#endif /* B75 */
+#ifdef B110
+ debug(F101,"ttspdlist B110","",B110);
+ spdlist[i++] = 110L;
+#endif /* B110 */
+#ifdef B134
+ debug(F101,"ttspdlist B134","",B134);
+ spdlist[i++] = 134L;
+#endif /* B134 */
+#ifdef B150
+ debug(F101,"ttspdlist B150","",B150);
+ spdlist[i++] = 150L;
+#endif /* B150 */
+#ifdef B200
+ debug(F101,"ttspdlist B200","",B200);
+ spdlist[i++] = 200L;
+#endif /* B200 */
+#ifdef B300
+ debug(F101,"ttspdlist B300","",B300);
+ spdlist[i++] = 300L;
+#endif /* B300 */
+#ifdef B600
+ debug(F101,"ttspdlist B600","",B600);
+ spdlist[i++] = 600L;
+#endif /* B600 */
+#ifdef B1200
+ debug(F101,"ttspdlist B1200","",B1200);
+ spdlist[i++] = 1200L;
+#endif /* B1200 */
+#ifdef B1800
+ debug(F101,"ttspdlist B1800","",B1800);
+ spdlist[i++] = 1800L;
+#endif /* B1800 */
+#ifdef B2400
+ debug(F101,"ttspdlist B2400","",B2400);
+ spdlist[i++] = 2400L;
+#endif /* B2400 */
+#ifdef B4800
+ debug(F101,"ttspdlist B4800","",B4800);
+ spdlist[i++] = 4800L;
+#endif /* B4800 */
+#ifdef B9600
+ debug(F101,"ttspdlist B9600","",B9600);
+ spdlist[i++] = 9600L;
+#endif /* B9600 */
+#ifdef B14400
+ debug(F101,"ttspdlist B14400","",B14400);
+ spdlist[i++] = 14400L;
+#endif /* B14400 */
+#ifdef B19200
+ debug(F101,"ttspdlist B19200","",B19200);
+ spdlist[i++] = 19200L;
+#else
+#ifdef EXTA
+ debug(F101,"ttspdlist EXTA","",EXTA);
+ spdlist[i++] = 19200L;
+#endif /* EXTA */
+#endif /* B19200 */
+#ifdef B28800
+ debug(F101,"ttspdlist B28800","",B28800);
+ spdlist[i++] = 28800L;
+#endif /* B28800 */
+#ifdef B33600
+ debug(F101,"ttspdlist B33600","",B33600);
+ spdlist[i++] = 33600L;
+#endif /* B33600 */
+#ifdef B38400
+ debug(F101,"ttspdlist B38400","",B38400);
+ spdlist[i++] = 38400L;
+#else
+#ifdef EXTB
+ debug(F101,"ttspdlist EXTB","",EXTB);
+ spdlist[i++] = 38400L;
+#endif /* EXTB */
+#endif /* B38400 */
+#ifdef _B57600
+ debug(F101,"ttspdlist _B57600","",_B57600);
+ spdlist[i++] = 57600L;
+#else
+#ifdef B57600
+ debug(F101,"ttspdlist B57600","",B57600);
+ spdlist[i++] = 57600L;
+#endif /* B57600 */
+#endif /* _B57600 */
+#ifdef B76800
+ debug(F101,"ttspdlist B76800","",B76800);
+ spdlist[i++] = 76800L;
+#endif /* B76800 */
+#ifdef _B115200
+ debug(F101,"ttspdlist _B115200","",_B115200);
+ spdlist[i++] = 115200L;
+#else
+#ifdef B115200
+ debug(F101,"ttspdlist B115200","",B115200);
+ spdlist[i++] = 115200L;
+#endif /* B115200 */
+#endif /* _B115200 */
+#ifdef B153600
+ debug(F101,"ttspdlist B153600","",B153600);
+ spdlist[i++] = 153600L;
+#endif /* B153600 */
+#ifdef B230400
+ debug(F101,"ttspdlist B230400","",B230400);
+ spdlist[i++] = 230400L;
+#endif /* B230400 */
+#ifdef B307200
+ debug(F101,"ttspdlist B307200","",B307200);
+ spdlist[i++] = 307200L;
+#endif /* B307200 */
+#ifdef B460800
+ debug(F101,"ttspdlist B460800","",B460800);
+ spdlist[i++] = 460800L;
+#endif /* B460800 */
+#ifdef B921600
+ debug(F101,"ttspdlist B921600","",B921600);
+ spdlist[i++] = 921600L;
+#endif /* B921600 */
+#endif /* USETCSETSPEED */
+ spdlist[0] = i - 1; /* Return count in 0th element */
+ debug(F111,"ttspdlist spdlist","0",spdlist[0]);
+ return((long *)spdlist);
+}
+
+/* T T G S P D - Get speed of currently selected tty line */
+
+/*
+ Unreliable. After SET LINE, it returns an actual speed, but not necessarily
+ the real speed. On some systems, it returns the line's nominal speed, from
+ /etc/ttytab. Even if you SET SPEED to something else, this function might
+ not notice.
+*/
+long
+ttgspd() { /* Get current serial device speed */
+#ifdef NOLOCAL
+ return(-1L);
+#else
+#ifdef POSIX
+ speed_t /* Should be unsigned */
+#else
+ int /* Isn't unsigned */
+#endif /* POSIX */
+ s;
+ int x;
+ long ss;
+#ifdef OLINUXHISPEED
+ unsigned int spd_flags = 0;
+ struct serial_struct serinfo;
+#endif /* OLINUXHISPEED */
+
+#ifdef NETCONN
+ if (netconn) {
+#ifdef TN_COMPORT
+ if (istncomport())
+ return(tnc_get_baud());
+ else
+#endif /* TN_COMPORT */
+ return(-1); /* -1 if network connection */
+ }
+#endif /* NETCONN */
+#ifdef NETCMD
+ if (ttpipe) return(-1);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-1);
+#endif /* NETPTY */
+
+ debug(F101,"ttgspd ttyfd","",ttyfd);
+
+#ifdef USETCSETSPEED
+
+ x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
+ debug(F101,"ttgspd tcgetattr","",x);
+ if (x < 0)
+ return(-1);
+ errno = 0;
+ s = tcgetspeed(TCS_ALL, &ttcur);
+ debug(F101,"ttsspd TCGETSPEED speed","",s);
+ if (s == 0) {
+ long s1, s2;
+ s1 = tcgetspeed(TCS_IN, &ttcur);
+ s2 = tcgetspeed(TCS_OUT, &ttcur);
+ if (s1 == 1200L && s2 == 75L)
+ return(8880L);
+ }
+#ifdef DEBUG
+ if (errno & deblog) {
+ debug(F101,"ttsspd TCGETSPEED errno","",errno);
+ }
+#endif /* DEBUG */
+ return(s);
+
+#else /* Not USETCSETSPEED */
+
+#ifdef Plan9
+ if (ttyfd < 0)
+ ss = -1;
+ else
+ ss = ttylastspeed;
+#else
+#ifdef OLINUXHISPEED
+ debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
+#endif /* OLINUXHISPEED */
+
+ if (ttyfd < 0) {
+#ifdef BSD44ORPOSIX
+ s = cfgetospeed(&ccold);
+ debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
+#else
+#ifdef ATTSV
+ s = ccold.c_cflag & CBAUD;
+ debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
+#else
+ s = ccold.sg_ospeed; /* (obtained by congm()) */
+ debug(F101,"ttgspd sg_ospeed 1","",s);
+#endif /* ATTSV */
+#endif /* BSD44POSIX */
+
+ } else {
+#ifdef BSD44ORPOSIX
+ if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
+ s = cfgetospeed(&ttcur);
+ debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
+#ifdef OLINUXHISPEED
+ if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
+ spd_flags = serinfo.flags & ASYNC_SPD_MASK;
+ debug(F101,"ttgspd spd_flags","",spd_flags);
+#endif /* OLINUXHISPEED */
+#else
+#ifdef ATTSV
+ x = ioctl(ttyfd,TCGETA,&ttcur);
+ debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
+ debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
+ if (x < 0) return(-1);
+ s = ttcur.c_cflag & CBAUD;
+ debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
+#else
+#ifdef BELLV10
+ x = ioctl(ttyfd,TIOCGDEV,&tdcur);
+ debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
+ if (x < 0) return(-1);
+ s = tdcur.ospeed;
+ debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
+#else
+ x = gtty(ttyfd,&ttcur);
+ debug(F101,"ttgspd gtty 2 x","",x);
+ debug(F101,"ttgspd gtty 2 errno","",errno);
+ if (x < 0) return(-1);
+ s = ttcur.sg_ospeed;
+ debug(F101,"ttgspd gtty 2 speed","",s);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ }
+ debug(F101,"ttgspd code","",s);
+#ifdef OLINUXHISPEED
+ debug(F101,"ttgspd spd_flags","",spd_flags);
+#endif /* OLINUXHISPEED */
+ switch (s) {
+#ifdef B0
+ case B0: ss = 0L; break;
+#endif /* B0 */
+
+#ifndef MINIX
+/*
+ MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
+ etc, making for many "duplicate case in switch" errors, which are fatal.
+*/
+#ifdef B50
+ case B50: ss = 50L; break;
+#endif /* B50 */
+#ifdef B75
+ case B75: ss = 75L; break;
+#endif /* B75 */
+#endif /* MINIX */
+
+#ifdef B110
+ case B110: ss = 110L; break;
+#endif /* B110 */
+
+#ifndef MINIX
+#ifdef B134
+ case B134: ss = 134L; break;
+#endif /* B134 */
+#ifdef B150
+ case B150: ss = 150L; break;
+#endif /* B150 */
+#endif /* MINIX */
+
+#ifdef B200
+ case B200: ss = 200L; break;
+#endif /* B200 */
+
+#ifdef B300
+ case B300: ss = 300L; break;
+#endif /* B300 */
+
+#ifdef B600
+ case B600: ss = 600L; break;
+#endif /* B600 */
+
+#ifdef B1200
+ case B1200: ss = 1200L; break;
+#endif /* B1200 */
+
+#ifdef B1800
+ case B1800: ss = 1800L; break;
+#endif /* B1800 */
+
+#ifdef B2400
+ case B2400: ss = 2400L; break;
+#endif /* B2400 */
+
+#ifdef B4800
+ case B4800: ss = 4800L; break;
+#endif /* B4800 */
+
+#ifdef B7200
+ case B7200: ss = 7200L; break;
+#endif /* B7200 */
+
+#ifdef B9600
+ case B9600: ss = 9600L; break;
+#endif /* B9600 */
+
+#ifdef B19200
+ case B19200: ss = 19200L; break;
+#else
+#ifdef EXTA
+ case EXTA: ss = 19200L; break;
+#endif /* EXTA */
+#endif /* B19200 */
+
+#ifndef MINIX
+#ifdef B38400
+ case B38400:
+ ss = 38400L;
+#ifdef OLINUXHISPEED
+ switch(spd_flags) {
+ case ASYNC_SPD_HI: ss = 57600L; break;
+ case ASYNC_SPD_VHI: ss = 115200L; break;
+ }
+#endif /* OLINUXHISPEED */
+ break;
+#else
+#ifdef EXTB
+ case EXTB: ss = 38400L; break;
+#endif /* EXTB */
+#endif /* B38400 */
+#endif /* MINIX */
+
+#ifdef HPUX
+#ifdef _B57600
+ case _B57600: ss = 57600L; break;
+#endif /* _B57600 */
+#ifdef _B115200
+ case _B115200: ss = 115200L; break;
+#endif /* _B115200 */
+#else
+#ifdef B57600
+ case B57600: ss = 57600L; break;
+#endif /* B57600 */
+#ifdef B76800
+ case B76800: ss = 76800L; break;
+#endif /* B76800 */
+#ifdef B115200
+ case B115200: ss = 115200L; break;
+#endif /* B115200 */
+#ifdef B153600
+ case B153600: ss = 153600L; break;
+#endif /* B153600 */
+#ifdef B230400
+ case B230400: ss = 230400L; break;
+#endif /* B230400 */
+#ifdef B307200
+ case B307200: ss = 307200L; break;
+#endif /* B307200 */
+#ifdef B460800
+ case B460800: ss = 460800L; break;
+#endif /* B460800 */
+#endif /* HPUX */
+#ifdef B921600
+ case B921600: ss = 921600L; break;
+#endif /* B921600 */
+ default:
+ ss = -1; break;
+ }
+#endif /* Plan9 */
+ debug(F101,"ttgspd speed","",ss);
+ return(ss);
+
+#endif /* USETCSETSPEED */
+#endif /* NOLOCAL */
+}
+#ifdef MINIX2 /* Another hack alert */
+#define MINIX
+#endif /* MINIX2 */
+
+/*
+ FIONREAD data type... This has been defined as "long" for many, many
+ years, and it worked OK until 64-bit platforms appeared. Thus we use
+ int for 64-bit platforms, but keep long for the others. If we changed
+ the default PEEKTYPE to int, this would probably break 16-bit builds
+ (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
+ of which we have no way of testing any more. Therefore, do not change
+ the default definition of PEEKTYPE -- only add exceptions to it as needed.
+*/
+#ifdef COHERENT
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+/* #define FIONREAD TIOCQUERY */
+/* #define PEEKTYPE int */
+#else /* Not COHERENT... */
+
+#ifdef OSF32 /* Digital UNIX 3.2 or higher */
+#define PEEKTYPE int
+#else
+#define PEEKTYPE long /* Elsewhere (see notes above) */
+#endif /* OSF32 */
+#endif /* COHERENT */
+
+/* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
+
+#ifdef MYREAD
+
+/* Private buffer for myread() and its companions. Not for use by anything
+ * else. ttflui() is allowed to reset them to initial values. ttchk() is
+ * allowed to read my_count.
+ *
+ * my_item is an index into mybuf[]. Increment it *before* reading mybuf[].
+ *
+ * A global parity mask variable could be useful too. We could use it to
+ * let myread() strip the parity on its own, instead of stripping sign
+ * bits as it does now.
+ */
+#ifdef BIGBUFOK
+#define MYBUFLEN 32768
+#else
+#ifdef pdp11
+#define MYBUFLEN 256
+#else
+#define MYBUFLEN 1024
+#endif /* pdp11 */
+#endif /* BIGBUFOK */
+
+#ifdef ANYX25
+#undef MYBUFLEN
+#define MYBUFLEN 256
+/*
+ On X.25 connections, there is an extra control byte at the beginning.
+*/
+static CHAR x25buf[MYBUFLEN+1]; /* Communication device input buffer */
+static CHAR *mybuf = x25buf+1;
+#else
+static CHAR mybuf[MYBUFLEN];
+#endif /* ANYX25 */
+
+static int my_count = 0; /* Number of chars still in mybuf */
+static int my_item = -1; /* Last index read from mybuf[] */
+
+/* T T P E E K -- Peek into our internal communications input buffers. */
+
+/*
+ NOTE: This routine is peculiar to UNIX, and is used only by the
+ select()-based CONNECT module, ckucns.c. It need not be replicated in
+ the ck?tio.c of other platforms.
+*/
+int
+ttpeek() {
+#ifdef TTLEBUF
+ int rc = 0;
+ if (ttpush >= 0)
+ rc++;
+ rc += le_inbuf();
+ if (rc > 0)
+ return(rc);
+ else
+#endif /* TTLEBUF */
+
+#ifdef MYREAD
+ return(my_count);
+#else
+ return(0);
+#endif /* MYREAD */
+}
+
+/* myread() -- Efficient read of one character from communications line.
+ *
+ * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
+ * bytes from connection, so when the connection is encrypted, these bytes
+ * must be decrypted.
+ *
+ * Uses a private buffer to minimize the number of expensive read() system
+ * calls. Essentially performs the equivalent of read() of 1 character, which
+ * is then returned. By reading all available input from the system buffers
+ * to the private buffer in one chunk, and then working from this buffer, the
+ * number of system calls is reduced in any case where more than one character
+ * arrives during the processing of the previous chunk, for instance high
+ * baud rates or network type connections where input arrives in packets.
+ * If the time needed for a read() system call approaches the time for more
+ * than one character to arrive, then this mechanism automatically compensates
+ * for that by performing bigger read()s less frequently. If the system load
+ * is high, the same mechanism compensates for that too.
+ *
+ * myread() is a macro that returns the next character from the buffer. If the
+ * buffer is empty, mygetbuf() is called. See mygetbuf() for possible error
+ * returns.
+ *
+ * This should be efficient enough for any one-character-at-a-time loops.
+ * For even better efficiency you might use memcpy()/bcopy() or such between
+ * buffers (since they are often better optimized for copying), but it may not
+ * be worth it if you have to take an extra pass over the buffer to strip
+ * parity and check for CTRL-C anyway.
+ *
+ * Note that if you have been using myread() from another program module, you
+ * may have some trouble accessing this macro version and the private variables
+ * it uses. In that case, just add a function in this module, that invokes the
+ * macro.
+ */
+#define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
+
+/* Specification: Push back up to one character onto myread()'s queue.
+ *
+ * This implementation: Push back characters into mybuf. At least one character
+ * must have been read through myread() before myunrd() may be used. After
+ * EOF or read error, again, myunrd() can not be used. Sometimes more than
+ * one character can be pushed back, but only one character is guaranteed.
+ * Since a previous myread() must have read its character out of mybuf[],
+ * that guarantees that there is space for at least one character. If push
+ * back was really needed after EOF, a small addition could provide that.
+ *
+ * As of 02/2007 myunrd() is used by ttinl().
+ */
+VOID
+#ifdef CK_ANSIC
+myunrd(CHAR ch)
+#else
+myunrd(ch) CHAR ch;
+#endif /* CK_ANSIC */
+{
+ if (my_item >= 0) {
+ mybuf[my_item--] = ch;
+ ++my_count;
+ }
+}
+
+/* T T P U S H B A C K -- Put n bytes back into the myread buffer */
+
+static CHAR * pushbuf = NULL;
+/* static int pushed = 0; */
+
+int
+ttpushback(s,n) CHAR * s; int n; {
+ debug(F101,"ttpushback n","",n);
+ if (pushbuf || n > MYBUFLEN || n < 1)
+ return(-1);
+ debug(F101,"ttpushback my_count","",my_count);
+ if (my_count > 0) {
+ if (!(pushbuf = (CHAR *)malloc(n+1)))
+ return(-1);
+ memcpy(pushbuf,mybuf,my_count);
+ /* pushed = my_count; */ /* (set but never used) */
+ }
+ memcpy(mybuf,s,n);
+ my_count = n;
+ my_item = -1;
+ return(0);
+}
+
+/* mygetbuf() -- Fill buffer for myread() and return first character.
+ *
+ * This function is what myread() uses when it can't get the next character
+ * directly from its buffer. First, it calls a system dependent myfillbuf()
+ * to read at least one new character into the buffer, and then it returns
+ * the first character just as myread() would have done. This function also
+ * is responsible for all error conditions that myread() can indicate.
+ *
+ * Returns: When OK => a positive character, 0 or greater.
+ * When EOF => -2.
+ * When error => -3, error code in errno.
+ *
+ * Older myread()s additionally returned -1 to indicate that there was nothing
+ * to read, upon which the caller would call myread() again until it got
+ * something. The new myread()/mygetbuf() always gets something. If it
+ * doesn't, then make it do so! Any program that actually depends on the old
+ * behaviour will break.
+ *
+ * The older version also used to return -2 both for EOF and other errors,
+ * and used to set errno to 9999 on EOF. The errno stuff is gone, EOF and
+ * other errors now return different results, although Kermit currently never
+ * checks to see which it was. It just disconnects in both cases.
+ *
+ * Kermit lets the user use the quit key to perform some special commands
+ * during file transfer. This causes read(), and thus also mygetbuf(), to
+ * finish without reading anything and return the EINTR error. This should
+ * be checked by the caller. Mygetbuf() could retry the read() on EINTR,
+ * but if there is nothing to read, this could delay Kermit's reaction to
+ * the command, and make Kermit appear unresponsive.
+ *
+ * The debug() call should be removed for optimum performance.
+ */
+int
+mygetbuf() {
+ int x;
+ errno = 0;
+#ifdef DEBUG
+ if (deblog && my_count > 0)
+ debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
+#endif /* DEBUG */
+ if (my_count <= 0)
+ my_count = myfillbuf();
+
+#ifdef DEBUG
+#ifdef COMMENT
+ if (deblog) debug(F101, "mygetbuf read", "", my_count);
+#else /* COMMENT */
+ ckhexdump("mygetbuf read", mybuf, my_count);
+#endif /* COMMENT */
+#endif /* DEBUG */
+ x = my_count;
+ if (my_count <= 0) {
+ my_count = 0;
+ my_item = -1;
+ debug(F101,"mygetbuf errno","",errno);
+#ifdef TCPSOCKET
+ if (netconn && ttnet == NET_TCPB && errno != 0) {
+ if (errno != EINTR) {
+ debug(F101,"mygetbuf TCP error","",errno);
+ ttclos(0); /* Close the connection. */
+ }
+ return(-3);
+ }
+#endif /* TCPSOCKET */
+ if (!netconn && xlocal && errno) {
+ if (errno != EINTR) {
+ debug(F101,"mygetbuf SERIAL error","",errno);
+ x = -3;
+ ttclos(0); /* Close the connection. */
+ }
+ }
+ return((x < 0) ? -3 : -2);
+ }
+ --my_count;
+ return((unsigned)(0xff & mybuf[my_item = 0]));
+}
+
+/* myfillbuf():
+ * System-dependent read() into mybuf[], as many characters as possible.
+ *
+ * Returns: OK => number of characters read, always more than zero.
+ * EOF => 0
+ * Error => -1, error code in errno.
+ *
+ * If there is input available in the system's buffers, all of it should be
+ * read into mybuf[] and the function return immediately. If no input is
+ * available, it should wait for a character to arrive, and return with that
+ * one in mybuf[] as soon as possible. It may wait somewhat past the first
+ * character, but be aware that any such delay lengthens the packet turnaround
+ * time during kermit file transfers. Should never return with zero characters
+ * unless EOF or irrecoverable read error.
+ *
+ * Correct functioning depends on the correct tty parameters being used.
+ * Better control of current parameters is required than may have been the
+ * case in older Kermit releases. For instance, O_NDELAY (or equivalent) can
+ * no longer be sometimes off and sometimes on like it used to, unless a
+ * special myfillbuf() is written to handle that. Otherwise the ordinary
+ * myfillbuf()s may think they have come to EOF.
+ *
+ * If your system has a facility to directly perform the functioning of
+ * myfillbuf(), then use it. If the system can tell you how many characters
+ * are available in its buffers, then read that amount (but not less than 1).
+ * If the system can return a special indication when you try to read without
+ * anything to read, while allowing you to read all there is when there is
+ * something, you may loop until there is something to read, but probably that
+ * is not good for the system load.
+ */
+
+#ifdef SVORPOSIX
+ /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
+ * and CLOCAL set any way you like. This way, read() will do exactly
+ * what is required by myfillbuf(): If there is data in the buffers
+ * of the O.S., all available data is read into mybuf, up to the size
+ * of mybuf. If there is none, the first character to arrive is
+ * awaited and returned.
+ */
+int
+myfillbuf() {
+ int fd, n;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef sxaE50
+ /* From S. Dezawa at Fujifilm in Japan. I don't know why this is */
+ /* necessary for the sxa E50, but it is. */
+ return read(fd, mybuf, 255);
+#else
+#ifdef BEOSORBEBOX
+ while (1) {
+#ifdef NETCONN
+ if (netconn) {
+ n = netxin(sizeof(mybuf), (char *)mybuf);
+ debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
+ }
+ else
+#endif /* NETCONN */
+ n = read(fd, mybuf, sizeof(mybuf));
+ debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
+ if (n > 0)
+ return(n);
+ snooze(1000.0);
+ }
+#else /* BEOSORBEBOX */
+ errno = 0;
+ /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
+#ifdef IBMX25
+ if (netconn && (nettype == NET_IX25)) {
+ /* can't use sizeof because mybuf is a pointer, and not an array! */
+ n = x25xin( MYBUFLEN, mybuf );
+ } else
+#endif /* IBMX25 */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, n = 0;
+ debug(F100,"myfillbuf calling SSL_read() fd","",0);
+ while (n == 0) {
+ if (ssl_active_flag)
+ n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
+ else if (tls_active_flag)
+ n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
+ else
+ break;
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
+ case SSL_ERROR_NONE:
+ if (n > 0)
+ return(n);
+ if (n < 0)
+ return(-2);
+ msleep(50);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if (n != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-3);
+ }
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
+ if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
+ return(-3);
+ else
+ return(n);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
+ if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
+ return(-3);
+ else
+ return(n);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
+ if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
+ return(-3);
+ else
+ return(n);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* Special handling for HP-UX pty i/o */
+ ptyread:
+ if (ttpty && pty_trap_pending(ttyfd) > 0) {
+ debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
+ if (pty_trap_handler(ttyfd) > 0) {
+ ttclos(0);
+ return(-3);
+ }
+ }
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+ debug(F101,"myfillbuf calling read() fd","",ttyfd);
+ n = read(fd, mybuf, sizeof(mybuf));
+ debug(F101,"SVORPOSIX myfillbuf read","",n);
+ debug(F101,"SVORPOSIX myfillbuf errno","",errno);
+ debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
+ if (n < 1) {
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* When we have a PTY trap in place the connection cannot */
+ /* be closed until the trap receives a close indication. */
+ if (n == 0 && ttpty)
+ goto ptyread;
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+ return(-3);
+ }
+ return(n);
+#endif /* BEOSORBEBOX */
+#endif /* sxaE50 */
+}
+
+#else /* not AT&T or POSIX */
+
+#ifdef aegis
+ /* This is quoted from the old myread(). The semantics seem to be
+ * alright, but maybe errno would not need to be set even when
+ * there is no error? I don't know aegis.
+ */
+int
+myfillbuf() {
+ int count;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+ count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
+ errno = EIO;
+ if (st.all == ios_$get_conditional_failed) /* get at least one */
+ count = ios_$get((short)fd, 0, mybuf, 1L, st);
+ if (st.all == ios_$end_of_file)
+ return(-3);
+ else if (st.all != status_$ok) {
+ errno = EIO;
+ return(-1);
+ }
+ return(count > 0 ? count : -3);
+}
+#else /* !aegis */
+
+#ifdef FIONREAD
+ /* This is for systems with FIONREAD. FIONREAD returns the number
+ * of characters available for reading. If none are available, wait
+ * until something arrives, otherwise return all there is.
+ */
+int
+myfillbuf() {
+ PEEKTYPE avail = 0;
+ int x, fd;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef SUNX25
+/*
+ SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
+ Depends on SunOS having FIONREAD, not because we use it, but just so this
+ code is grouped correctly within the #ifdefs. Let's hope Solaris keeps it.
+
+ We call x25xin() instead of read() so that Q-Bit packets, which contain
+ X.25 service-level information (e.g. PAD parameter changes), can be processed
+ transparently to the upper-level code. This is a blocking read, and so
+ we depend on higher-level code (such as ttinc()) to set any necessary alarms.
+*/
+ extern int nettype;
+ if (netconn && nettype == NET_SX25) {
+ while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
+ return(x - 1); /* "-1" compensates for extra status byte */
+ }
+#endif /* SUNX25 */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, n = 0;
+ while (n == 0) {
+ if (ssl_active_flag)
+ n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
+ else
+ n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
+ case SSL_ERROR_NONE:
+ if (n > 0)
+ return(n);
+ if (n < 0)
+ return(-2);
+ msleep(50);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if (n != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-2);
+ }
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(x);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
+ return(-1);
+ else
+ return(x);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(x);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+ errno = 0;
+ debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
+ x = ioctl(fd, FIONREAD, &avail);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"myfillbuf FIONREAD","",x);
+ debug(F101,"myfillbuf FIONREAD avail","",avail);
+ debug(F101,"myfillbuf FIONREAD errno","",errno);
+ }
+#endif /* DEBUG */
+ if (x < 0 || avail == 0)
+ avail = 1;
+
+ if (avail > MYBUFLEN)
+ avail = MYBUFLEN;
+
+ errno = 0;
+
+ x = read(fd, mybuf, (int) avail);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"myfillbuf avail","",avail);
+ debug(F101,"myfillbuf read","",x);
+ debug(F101,"myfillbuf read errno","",errno);
+ if (x > 0)
+ ckhexdump("myfillbuf mybuf",mybuf,x);
+ }
+#endif /* DEBUG */
+ if (x < 1) x = -3; /* read 0 == connection loss */
+ return(x);
+}
+
+#else /* !FIONREAD */
+/* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
+/* When there is no other possibility, read 1 character at a time. */
+int
+myfillbuf() {
+ int x;
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error, n = 0;
+ while (n == 0) {
+ if (ssl_active_flag)
+ n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
+ else
+ count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
+ case SSL_ERROR_NONE:
+ if (n > 0)
+ return(n);
+ if (n < 0)
+ return(-2);
+ msleep(50);
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return(-1);
+ case SSL_ERROR_SYSCALL:
+ if (n != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-2);
+ }
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+ return(-1);
+ else
+ return(len);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+ x = read(fd, mybuf, 1);
+ return(x > 0 ? x : -3);
+}
+
+#endif /* !FIONREAD */
+#endif /* !aegis */
+#endif /* !ATTSV */
+
+#endif /* MYREAD */
+
+/* T T _ T N O P T -- Handle Telnet negotions in incoming data */
+/*
+ Call with the IAC that was encountered.
+ Returns:
+ -3: If connection has dropped or gone bad.
+ -2: On Telnet protocol error resulting in inconsistent states.
+ 0: If negotiation OK and caller has nothing to do.
+ 1: If packet start character has changed (new value is in global stchr).
+ 255: If there was a quoted IAC as data.
+ or: Not at all if we got a legitimate Telnet Logout request.
+*/
+#ifdef TCPSOCKET
+static int
+tt_tnopt(n) int n; { /* Handle Telnet options */
+ /* In case caller did not already check these conditions... */
+ if (n == IAC &&
+ ((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet))) {
+ extern int server;
+ int tx = 0;
+ debug(F100,"ttinl calling tn_doop()","",0);
+ tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
+ debug(F111,"ttinl tn_doop() returned","tx",tx);
+ switch (tx) {
+ case 0:
+ return(0);
+ case -1: /* I/O error */
+ ttimoff(); /* Turn off timer */
+ return(-3);
+ case -2: /* Connection failed. */
+ case -3:
+ ttimoff(); /* Turn off timer */
+ ttclos(0);
+ return(-3);
+ case 1: /* ECHO change */
+ duplex = 1;
+ return(0);
+ case 2: /* ECHO change */
+ duplex = 0;
+ return(0);
+ case 3: /* Quoted IAC */
+ n = 255;
+ return((unsigned)255);
+#ifdef IKS_OPTION
+ case 4: {
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) { /* Remote in Server mode */
+ ttimoff(); /* Turn off timer */
+ debug(F100,"u_start and !inserver","",0);
+ return(-2); /* End server mode */
+ } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
+ server
+ ) { /* I'm no longer in Server Mode */
+ debug(F100,"me_start and server","",0);
+ ttimoff();
+ return(-2);
+ }
+ return(0);
+ }
+ case 5: { /* Start character change */
+ /* extern CHAR stchr; */
+ /* start = stchr; */
+ return(1);
+ }
+#endif /* IKS_OPTION */
+ case 6: /* Remote Logout */
+ ttimoff();
+ ttclos(0);
+#ifdef IKSD
+ if (inserver && !local)
+ doexit(GOOD_EXIT,0);
+ else
+#endif /* IKSD */
+ return(-2);
+ default:
+ return(0);
+ }
+ } else
+ return(0);
+}
+#endif /* TCPSOCKET */
+
+/* T T F L U I -- Flush tty input buffer */
+
+void
+ttflux() { /* But first... */
+#ifdef MYREAD
+/*
+ Flush internal MYREAD buffer.
+*/
+#ifdef TCPSOCKET
+ int dotnopts, x;
+ dotnopts = (((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet)));
+#endif /* TCPSOCKET */
+ debug(F101,"ttflux my_count","",my_count);
+#ifdef TCPSOCKET
+ if (dotnopts) {
+ CHAR ch = '\0';
+ while (my_count > 0) {
+ ch = myread();
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt((char *)&ch,1);
+#endif /* CK_ENCRYPTION */
+ if (ch == IAC)
+ x = tt_tnopt(ch);
+ }
+ } else
+#endif /* TCPSOCKET */
+#ifdef COMMENT
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
+ ck_tn_decrypt(&mybuf[my_item+1],my_count);
+#endif /* CK_ENCRYPTION */
+#endif /* COMMENT */
+ my_count = 0; /* Reset count to zero */
+ my_item = -1; /* And buffer index to -1 */
+#endif /* MYREAD */
+}
+
+int
+ttflui() {
+ int n, fd;
+#ifdef TCPSOCKET
+ int dotnopts;
+ dotnopts = (((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet)));
+#endif /* TCPSOCKET */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef TTLEBUF
+ ttpush = -1; /* Clear the peek-ahead char */
+ while (le_data && (le_inbuf() > 0)) {
+ CHAR ch = '\0';
+ if (le_getchar(&ch) > 0) { /* Clear any more... */
+ debug(F101,"ttflui le_inbuf ch","",ch);
+ }
+ }
+#endif /* TTLEBUF */
+ debug(F101,"ttflui ttpipe","",ttpipe);
+
+#ifdef MYREAD
+/*
+ Flush internal MYREAD buffer *NEXT*, in all cases.
+*/
+ ttflux();
+#endif /* MYREAD */
+
+#ifdef NETCONN
+/* Network flush is done specially, in the network support module. */
+ if ((netconn || sstelnet) && !ttpipe && !ttpty) {
+ debug(F100,"ttflui netflui","",0);
+#ifdef COMMENT
+#ifdef TN_COMPORT
+ if (istncomport())
+ tnc_send_purge_data(TNC_PURGE_RECEIVE);
+#endif /* TN_COMPORT */
+#endif /* COMMENT */
+ return(netflui());
+ }
+#endif /* NETCONN */
+
+ debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
+ if (ttyfd < 0)
+ return(-1);
+
+#ifdef aegis
+ sio_$control((short)yfd, sio_$flush_in, true, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "flush failed: "); error_$print(st);
+ } else { /* sometimes the flush doesn't work */
+ for (;;) {
+ char buf[256];
+ /* eat all the characters that shouldn't be available */
+ ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
+ if (st.all == ios_$get_conditional_failed) break;
+ fprintf(stderr, "flush failed(2): "); error_$print(st);
+ }
+ }
+#else
+#ifdef BSD44 /* 4.4 BSD */
+ n = FREAD; /* Specify read queue */
+ debug(F100,"ttflui BSD44","",0);
+ ioctl(fd,TIOCFLUSH,&n);
+#else
+#ifdef Plan9
+#undef POSIX /* Uh oh... */
+#endif /* Plan9 */
+#ifdef POSIX /* POSIX */
+ debug(F100,"ttflui POSIX","",0);
+ tcflush(fd,TCIFLUSH);
+#else
+#ifdef ATTSV /* System V */
+#ifndef VXVE
+ debug(F100,"ttflui ATTSV","",0);
+ ioctl(fd,TCFLSH,0);
+#endif /* VXVE */
+#else /* Not BSD44, POSIX, or Sys V */
+#ifdef TIOCFLUSH /* Those with TIOCFLUSH defined */
+#ifdef ANYBSD /* Berkeley */
+ n = FREAD; /* Specify read queue */
+ debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
+ ioctl(fd,TIOCFLUSH,&n);
+#else /* Others (V7, etc) */
+ debug(F100,"ttflui TIOCFLUSH","",0);
+ ioctl(fd,TIOCFLUSH,0);
+#endif /* ANYBSD */
+#else /* All others... */
+/*
+ No system call (that we know about) for input buffer flushing.
+ So see how many there are and read them in a loop, using ttinc().
+ ttinc() is buffered, so we're not getting charged with a system call
+ per character, just a function call.
+*/
+ if ((n = ttchk()) > 0) {
+ debug(F101,"ttflui read loop","",n);
+ while ((n--) && ttinc(0) > 0) ;
+ }
+#endif /* TIOCFLUSH */
+#endif /* ATTSV */
+#endif /* POSIX */
+#ifdef Plan9
+#define POSIX
+#endif /* Plan9 */
+#endif /* BSD44 */
+#endif /* aegis */
+ return(0);
+}
+
+int
+ttfluo() { /* Flush output buffer */
+ int fd;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdout;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef Plan9
+ return 0;
+#else
+#ifdef POSIX
+ return(tcflush(fd,TCOFLUSH));
+#else
+#ifdef OXOS
+ return(ioctl(fd,TCFLSH,1));
+#else
+ return(0); /* All others, nothing */
+#endif /* OXOS */
+#endif /* POSIX */
+#endif /* Plan9 */
+}
+
+/* Interrupt Functions */
+
+/* Set up terminal interrupts on console terminal */
+
+#ifndef FIONREAD /* We don't need esctrp() */
+#ifndef SELECT /* if we have any of these... */
+#ifndef CK_POLL
+#ifndef RDCHK
+
+#ifndef OXOS
+#ifdef SVORPOSIX
+SIGTYP
+esctrp(foo) int foo; { /* trap console escapes (^\) */
+ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
+ conesc = 1;
+ debug(F101,"esctrp caught SIGQUIT","",conesc);
+}
+#endif /* SVORPOSIX */
+#endif /* OXOS */
+
+#ifdef V7
+#ifndef MINIX2
+SIGTYP
+esctrp(foo) int foo; { /* trap console escapes (^\) */
+ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
+ conesc = 1;
+ debug(F101,"esctrp caught SIGQUIT","",conesc);
+}
+#endif /* MINIX2 */
+#endif /* V7 */
+
+#ifdef C70
+SIGTYP
+esctrp(foo) int foo; { /* trap console escapes (^\) */
+ conesc = 1;
+ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
+}
+#endif /* C70 */
+
+#endif /* RDCHK */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* FIONREAD */
+
+/* C O N B G T -- Background Test */
+
+static int jc = 0; /* 0 = no job control */
+
+/*
+ Call with flag == 1 to prevent signal test, which can not be expected
+ to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
+
+ Call with flag == 0 to use the signal test, but only if the process-group
+ test fails, as it does on some UNIX systems, where getpgrp() is buggy,
+ requires an argument when the man page says it doesn't, or vice versa.
+
+ If flag == 0 and the process-group test fails, then we determine background
+ status simply (but not necessarily reliably) from isatty().
+
+ conbgt() sets the global backgrd = 1 if we appear to be in the background,
+ and to 0 if we seem to be in the foreground. conbgt() is highly prone to
+ misbehavior.
+*/
+VOID
+conbgt(flag) int flag; {
+ int x = -1, /* process group or SIGINT test */
+ y = 0; /* isatty() test */
+/*
+ Check for background operation, even if not running on real tty, so that
+ background flag can be set correctly. If background status is detected,
+ then Kermit will not issue its interactive prompt or most messages.
+ If your prompt goes away, you can blame (and fix?) this function.
+*/
+
+/* Use process-group test if possible. */
+
+#ifdef POSIX /* We can do it in POSIX */
+#define PGROUP_T
+#else
+#ifdef BSD4 /* and in BSD 4.x. */
+#define PGROUP_T
+#else
+#ifdef HPUXJOBCTL /* and in most HP-UX's */
+#define PGROUP_T
+#else
+#ifdef TIOCGPGRP /* and anyplace that has this ioctl. */
+#define PGROUP_T
+#endif /* TIOCGPGRP */
+#endif /* HPUXJOBCTL */
+#endif /* BSD4 */
+#endif /* POSIX */
+
+#ifdef MIPS /* Except if it doesn't work... */
+#undef PGROUP_T
+#endif /* MIPS */
+
+#ifdef MINIX
+#undef PGROUP_T
+#endif /* MINIX */
+
+#ifdef PGROUP_T
+/*
+ Semi-reliable process-group test. Check whether this process's group is
+ the same as the controlling terminal's process group. This works if the
+ getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
+*/
+ PID_T mypgrp = (PID_T)0; /* Kermit's process group */
+ PID_T ctpgrp = (PID_T)0; /* The terminal's process group */
+#ifndef _POSIX_SOURCE
+/*
+ The getpgrp() prototype is obtained from system header files for POSIX
+ and Sys V R4 compilations. Other systems, who knows. Some complain about
+ a duplicate declaration here, others don't, so it's safer to leave it in
+ if we don't know for certain.
+*/
+#ifndef SVR4
+#ifndef PS2AIX10
+#ifndef HPUX9
+ extern PID_T getpgrp();
+#endif /* HPUX9 */
+#endif /* PS2AIX10 */
+#endif /* SVR4 */
+#endif /* _POSIX_SOURCE */
+
+/* Get my process group. */
+
+#ifdef SVR3 /* Maybe this should be ATTSV? */
+/* This function is not described in SVID R2 */
+ mypgrp = getpgrp();
+ /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
+#else
+#ifdef POSIX
+ mypgrp = getpgrp();
+ /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
+#else
+#ifdef OSFPC
+ mypgrp = getpgrp();
+ /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
+#else
+#ifdef QNX
+ mypgrp = getpgrp();
+ /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
+#else
+#ifdef OSF32 /* (was OSF40) */
+ mypgrp = getpgrp();
+ /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
+#else /* BSD, V7, etc */
+#ifdef MINIX2
+ mypgrp = getpgrp();
+#else
+ mypgrp = getpgrp(0);
+#endif /* MINIX2 */
+ /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
+#endif /* OSF32 */
+#endif /* QNX */
+#endif /* OSFPC */
+#endif /* POSIX */
+#endif /* SVR3 */
+
+#ifdef MINIX
+ /* MINIX does not support job control so Kermit is always in foreground */
+ x = 0;
+
+#else /* Not MINIX */
+
+/* Now get controlling tty's process group */
+#ifdef BSD44ORPOSIX
+ ctpgrp = tcgetpgrp(1); /* The POSIX way */
+ /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
+#else
+ ioctl(1, TIOCGPGRP, &ctpgrp); /* Or the BSD way */
+ /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
+#endif /* BSD44ORPOSIX */
+
+ if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
+ x = (mypgrp == ctpgrp) ? 0 : 1; /* If they differ, then background. */
+ else x = -1; /* If error, remember. */
+ debug(F101,"conbgt process group test","",x);
+#endif /* PGROUP_T */
+#endif /* MINIX */
+
+/* Try to see if job control is available */
+
+#ifdef NOJC /* User override */
+ jc = 0; /* No job control allowed */
+ debug(F111,"NOJC","jc",jc);
+#else
+#ifdef BSD44
+ jc = 1;
+#else
+#ifdef SVR4ORPOSIX /* POSIX actually tells us */
+ debug(F100,"SVR4ORPOSIX jc test...","",0);
+#ifdef _SC_JOB_CONTROL
+#ifdef __bsdi__
+ jc = 1;
+#else
+#ifdef __386BSD__
+ jc = 1;
+#else
+ jc = sysconf(_SC_JOB_CONTROL); /* Whatever system says */
+ if (jc < 0) {
+ debug(F101,"sysconf fails, jcshell","",jcshell);
+ jc = (jchdlr == SIG_DFL) ? 1 : 0;
+ } else
+ debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
+#endif /* __386BSD__ */
+#endif /* __bsdi__ */
+#else
+#ifdef _POSIX_JOB_CONTROL
+ jc = 1; /* By definition */
+ debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
+#else
+ jc = 0; /* Assume job control not allowed */
+ debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
+#endif /* _POSIX_JOB_CONTROL */
+#endif /* _SC_JOB_CONTROL */
+#else
+#ifdef BSD4
+ jc = 1; /* Job control allowed */
+ debug(F111,"BSD job control","jc",jc);
+#else
+#ifdef SVR3JC
+ jc = 1; /* JC allowed */
+ debug(F111,"SVR3 job control","jc",jc);
+#else
+#ifdef OXOS
+ jc = 1; /* JC allowed */
+ debug(F111,"X/OS job control","jc",jc);
+#else
+#ifdef HPUX9
+ jc = 1; /* JC allowed */
+ debug(F111,"HP-UX 9.0 job control","jc",jc);
+#else
+#ifdef HPUX10
+ jc = 1; /* JC allowed */
+ debug(F111,"HP-UX 10.0 job control","jc",jc);
+#else
+ jc = 0; /* JC not allowed */
+ debug(F111,"job control catch-all","jc",jc);
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* OXOS */
+#endif /* SVR3JC */
+#endif /* BSD4 */
+#endif /* SVR4ORPOSIX */
+#endif /* BSD44 */
+#endif /* NOJC */
+ debug(F101,"conbgt jc","",jc);
+#ifndef NOJC
+ debug(F101,"conbgt jcshell","",jcshell);
+/*
+ At this point, if jc == 1 but jcshell == 0, it means that the OS supports
+ job control, but the shell or other process we are running under does not
+ (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
+ will come of it. So...
+*/
+ if (jc < 0) jc = 0;
+ if (jc > 0 && jcshell == 0) jc = 0;
+#endif /* NOJC */
+
+/*
+ Another background test.
+ Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
+ which is done by the shell (sh) if the program is started with '&'.
+ Unfortunately, this is NOT done by csh or ksh so watch out!
+ Note, it's safe to set SIGINT to SIG_IGN here, because further down
+ we always set it to something else.
+ Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
+ SIG_IGN ourselves.
+*/
+ if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
+
+ SIGTYP (*osigint)();
+
+ osigint = signal(SIGINT,SIG_IGN); /* What is SIGINT set to? */
+ sigint_ign = 1;
+ x = (osigint == SIG_IGN) ? 1 : 0; /* SIG_IGN? */
+ /* debug(F101,"conbgt osigint","",osigint); */
+ /* debug(F101,"conbgt signal test","",x); */
+ }
+
+/* Also check to see if we're running with redirected stdio. */
+/* This is not really background operation, but we want to act as though */
+/* it were. */
+
+#ifdef IKSD
+ if (inserver) { /* Internet Kermit Server */
+ backgrd = 0; /* is not in the background */
+ return;
+ }
+#endif /* IKSD */
+
+ y = (isatty(0) && isatty(1)) ? 1 : 0;
+ debug(F101,"conbgt isatty test","",y);
+
+#ifdef BSD29
+/* The process group and/or signal test doesn't work under these... */
+ backgrd = !y;
+#else
+#ifdef sxaE50
+ backgrd = !y;
+#else
+#ifdef MINIX
+ backgrd = !y;
+#else
+#ifdef MINIX2
+ backgrd = !y;
+#else
+ if (x > -1)
+ backgrd = (x || !y) ? 1 : 0;
+ else backgrd = !y;
+#endif /* BSD29 */
+#endif /* sxaE50 */
+#endif /* MINIX */
+#endif /* MINIX2 */
+ debug(F101,"conbgt backgrd","",backgrd);
+}
+
+/* C O N I N T -- Console Interrupt setter */
+
+/*
+ First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
+ Second arg is pointer to function to handle SIGTSTP (suspend).
+*/
+
+VOID /* Set terminal interrupt traps. */
+#ifdef CK_ANSIC
+#ifdef apollo
+conint(f,s) SIGTYP (*f)(), (*s)();
+#else
+conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
+#endif /* apollo */
+#else
+conint(f,s) SIGTYP (*f)(), (*s)();
+#endif /* CK_ANSIC */
+/* conint */ {
+
+ debug(F101,"conint conistate","",conistate);
+
+ conbgt(0); /* Do background test. */
+
+/* Set the desired handlers for hangup and software termination. */
+
+#ifdef SIGTERM
+ signal(SIGTERM,f); /* Software termination */
+#endif /* SIGTERM */
+
+/*
+ Prior to July 1999 we used to call sighup() here but now it's called in
+ sysinit() so SIGHUP can be caught during execution of the init file or
+ a kerbang script.
+*/
+
+/* Now handle keyboard stop, quit, and interrupt signals. */
+/* Check if invoked in background -- if so signals set to be ignored. */
+/* However, if running under a job control shell, don't ignore them. */
+/* We won't be getting any, as we aren't in the terminal's process group. */
+
+ debug(F101,"conint backgrd","",backgrd);
+ debug(F101,"conint jc","",jc);
+
+ if (backgrd && !jc) { /* In background, ignore signals */
+ debug(F101,"conint background ignoring signals, jc","",jc);
+#ifdef SIGTSTP
+ signal(SIGTSTP,SIG_IGN); /* Keyboard stop */
+#endif /* SIGTSTP */
+ signal(SIGQUIT,SIG_IGN); /* Keyboard quit */
+ signal(SIGINT,SIG_IGN); /* Keyboard interrupt */
+ sigint_ign = 1;
+ conistate = CONI_NOI;
+ } else { /* Else in foreground or suspended */
+ debug(F101,"conint foreground catching signals, jc","",jc);
+ signal(SIGINT,f); /* Catch terminal interrupt */
+ sigint_ign = (f == SIG_IGN) ? 1 : 0;
+
+#ifdef SIGTSTP /* Keyboard stop (suspend) */
+ /* debug(F101,"conint SIGSTSTP","",s); */
+ if (s == NULL) s = SIG_DFL;
+#ifdef NOJC /* No job control allowed. */
+ signal(SIGTSTP,SIG_IGN);
+#else /* Job control allowed */
+ if (jc) /* if available. */
+ signal(SIGTSTP,s);
+ else
+ signal(SIGTSTP,SIG_IGN);
+#endif /* NOJC */
+#endif /* SIGTSTP */
+
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifndef FIONREAD /* Watch out, we don't know this... */
+#ifndef SELECT
+#ifndef CK_POLL
+#ifndef RDCHK
+ signal(SIGQUIT,esctrp); /* Quit signal, Sys III/V. */
+#endif /* RDCHK */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* FIONREAD */
+ if (conesc) conesc = 0; /* Clear out pending escapes */
+#else
+#ifdef V7
+ signal(SIGQUIT,esctrp); /* V7 like Sys III/V */
+ if (conesc) conesc = 0;
+#else
+#ifdef aegis
+ signal(SIGQUIT,f); /* Apollo, catch it like others. */
+#else
+ signal(SIGQUIT,SIG_IGN); /* Others, ignore like 4D & earlier. */
+#endif /* aegis */
+#endif /* V7 */
+#endif /* SVORPOSIX */
+#endif /* OXOS */
+ conistate = CONI_INT;
+ }
+}
+
+
+/* C O N N O I -- Reset console terminal interrupts */
+
+VOID
+connoi() { /* Console-no-interrupts */
+
+ debug(F101,"connoi conistate","",conistate);
+#ifdef SIGTSTP
+ signal(SIGTSTP,SIG_IGN); /* Suspend */
+#endif /* SIGTSTP */
+ conint(SIG_IGN,SIG_IGN); /* Interrupt */
+ sigint_ign = 1; /* Remember we did this ourselves */
+#ifdef SIGQUIT
+ signal(SIGQUIT,SIG_IGN); /* Quit */
+#endif /* SIGQUIT */
+#ifdef SIGTERM
+ signal(SIGTERM,SIG_IGN); /* Term */
+#endif /* SIGTERM */
+ conistate = CONI_NOI;
+}
+
+/* I N I T R A W Q -- Set up to read /dev/kmem for character count. */
+
+#ifdef V7
+/*
+ Used in Version 7 to simulate Berkeley's FIONREAD ioctl call. This
+ eliminates blocking on a read, because we can read /dev/kmem to get the
+ number of characters available for raw input. If your system can't
+ or you won't let the world read /dev/kmem then you must figure out a
+ different way to do the counting of characters available, or else replace
+ this by a dummy function that always returns 0.
+*/
+/*
+ * Call this routine as: initrawq(tty)
+ * where tty is the file descriptor of a terminal. It will return
+ * (as a char *) the kernel-mode memory address of the rawq character
+ * count, which may then be read. It has the side-effect of flushing
+ * input on the terminal.
+ */
+/*
+ * John Mackin, Physiology Dept., University of Sydney (Australia)
+ * ...!decvax!mulga!physiol.su.oz!john
+ *
+ * Permission is hereby granted to do anything with this code, as
+ * long as this comment is retained unmodified and no commercial
+ * advantage is gained.
+ */
+#ifndef MINIX
+#ifndef MINIX2
+#ifndef COHERENT
+#include <a.out.h>
+#include <sys/proc.h>
+#endif /* COHERENT */
+#endif /* MINIX2 */
+#endif /* MINIX */
+
+#ifdef COHERENT
+#include <l.out.h>
+#include <sys/proc.h>
+#endif /* COHERENT */
+
+char *
+initrawq(tty) int tty; {
+#ifdef MINIX
+ return(0);
+#else
+#ifdef MINIX2
+ return(0);
+#else
+#ifdef UTS24
+ return(0);
+#else
+#ifdef BSD29
+ return(0);
+#else
+ long lseek();
+ static struct nlist nl[] = {
+ {PROCNAME},
+ {NPROCNAME},
+ {""}
+ };
+ static struct proc *pp;
+ char *qaddr, *p, c;
+ int m;
+ PID_T pid, me;
+ NPTYPE xproc; /* Its type is defined in makefile. */
+ int catch();
+
+ me = getpid();
+ if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
+ nlist(BOOTNAME, nl);
+ if (nl[0].n_type == 0) err("proc array");
+
+ if (nl[1].n_type == 0) err("nproc");
+
+ lseek(m, (long)(nl[1].n_value), 0);
+ read (m, &xproc, sizeof(xproc));
+ saval = signal(SIGALRM, catch);
+ if ((pid = fork()) == 0) {
+ while(1)
+ read(tty, &c, 1);
+ }
+ alarm(2);
+
+ if(setjmp(jjbuf) == 0) {
+ while(1)
+ read(tty, &c, 1);
+ }
+ signal(SIGALRM, SIG_DFL);
+
+#ifdef DIRECT
+ pp = (struct proc *) nl[0].n_value;
+#else
+ if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
+ if (read(m, &pp, sizeof(pp)) != sizeof(pp)) err("no read of proc ptr");
+#endif
+ lseek(m, (long)(nl[1].n_value), 0);
+ read(m, &xproc, sizeof(xproc));
+
+ if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
+ if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
+ if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
+ err("read proc table");
+ for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
+ if (pp -> p_pid == (short) pid) goto iout;
+ }
+ err("no such proc");
+
+iout:
+ close(m);
+ qaddr = (char *)(pp -> p_wchan);
+ free (p);
+ kill(pid, SIGKILL);
+ wait((WAIT_T *)0);
+ return (qaddr);
+#endif
+#endif
+#endif
+#endif
+}
+
+/* More V7-support functions... */
+
+static VOID
+err(s) char *s; {
+ char buf[200];
+
+ ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
+ perror(buf);
+ doexit(1,-1);
+}
+
+static VOID
+catch(foo) int foo; {
+ longjmp(jjbuf, -1);
+}
+
+
+/* G E N B R K -- Simulate a modem break. */
+
+#ifdef MINIX
+#define BSPEED B110
+#else
+#ifdef MINIX2
+#define BSPEED B110
+#else
+#define BSPEED B150
+#endif /* MINIX2 */
+#endif /* MINIX */
+
+#ifndef MINIX2
+VOID
+genbrk(fn,msec) int fn, msec; {
+ struct sgttyb ttbuf;
+ int ret, sospeed, x, y;
+
+ ret = ioctl(fn, TIOCGETP, &ttbuf);
+ sospeed = ttbuf.sg_ospeed;
+ ttbuf.sg_ospeed = BSPEED;
+ ret = ioctl(fn, TIOCSETP, &ttbuf);
+ y = (int)strlen(brnuls);
+ x = ( BSPEED * 100 ) / msec;
+ if (x > y) x = y;
+ ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
+ ttbuf.sg_ospeed = sospeed;
+ ret = ioctl(fn, TIOCSETP, &ttbuf);
+ ret = write(fn, "@", 1);
+ return;
+}
+#endif /* MINIX2 */
+
+#ifdef MINIX2
+int
+genbrk(fn,msec) int fn, msec; {
+ struct termios ttbuf;
+ int ret, x, y;
+ speed_t sospeed;
+
+ ret = tcgetattr(fn, &ttbuf);
+ sospeed = ttbuf.c_ospeed;
+ ttbuf.c_ospeed = BSPEED;
+ ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
+ y = (int)strlen(brnuls);
+ x = ( BSPEED * 100 ) / msec;
+ if (x > y) x = y;
+ ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
+ ttbuf.c_ospeed = sospeed;
+ ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
+ ret = write(fn, "@", 1);
+ return ret;
+}
+#endif /* MINIX2 */
+#endif /* V7 */
+
+/*
+ I N C H K -- Check if chars waiting to be read on given file descriptor.
+
+ This routine is a merger of ttchk() and conchk().
+ Call with:
+ channel == 0 to check console.
+ channel == 1 to check communications connection.
+ and:
+ fd = file descriptor.
+ Returns:
+ >= 0: number of characters waiting, 0 or greater,
+ -1: on any kind of error,
+ -2: if there is (definitely) no connection.
+ Note: In UNIX we don't have to call nettchk() because a socket
+ file descriptor works just like in serial i/o, ioctls and all.
+ (But this will change if we add non-file-descriptor channels,
+ such as IBM X.25 for AIX...)
+*/
+static int
+in_chk(channel, fd) int channel, fd; {
+ int x, n = 0; /* Workers, n = return value */
+ extern int clsondisc; /* Close on disconnect */
+/*
+ The first section checks to make sure we have a connection,
+ but only if we're in local mode.
+*/
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"in_chk entry",ckitoa(fd),channel);
+ debug(F101,"in_chk ttyfd","",ttyfd);
+ debug(F101,"in_chk ttpty","",ttpty);
+ }
+#endif /* DEBUG */
+/*
+ But don't say connection is gone if we have any buffered-stuff.
+*/
+#ifdef TTLEBUF
+ debug(F101,"in_chk ttpush","",ttpush);
+ if (channel == 1) {
+ if (ttpush >= 0)
+ n++;
+ n += le_inbuf();
+ if (n > 0)
+ return(n);
+ }
+#endif /* TTLEBUF */
+
+#ifdef NETPTY
+#ifdef HAVE_PTYTRAP
+ /* Special handling for HP-UX pty i/o */
+ if (ttpty && pty_trap_pending(ttyfd) > 0) {
+ if (pty_trap_handler(ttyfd) > 0) {
+ ttclos(0);
+ return(-2);
+ }
+ }
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+
+ if (channel) { /* Checking communications channel */
+ if (ttyfd < 0) { /* No connection */
+ return(-2); /* That's what this means */
+ } else if (xlocal && /* In local mode */
+ (!netconn /* Serial connection or */
+#ifdef TN_COMPORT
+ || istncomport() /* Telnet Com Port */
+#endif /* TN_COMPORT */
+ ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
+#ifdef COMMENT
+#ifdef MYREAD
+/*
+ Seems like this would be a good idea but it prevents C-Kermit from
+ popping back to the prompt automatically when carrier drops. However,
+ commenting this out prevents us from seeing the NO CARRIER message.
+ Needs more work...
+*/
+ && my_count < 1 /* Nothing in our internal buffer */
+#endif /* MYREAD */
+#endif /* COMMENT */
+ ) {
+ int x;
+ x = ttgmdm(); /* So get modem signals */
+ debug(F101,"in_chk close-on-disconnect","",clsondisc);
+ if (x > -1) { /* Check for carrier */
+ if (!(x & BM_DCD)) { /* No carrier */
+ debug(F101,"in_chk carrier lost","",x);
+ if (clsondisc) /* If "close-on-disconnect" */
+ ttclos(0); /* close device & release lock. */
+ return(-2); /* This means "disconnected" */
+ }
+ /* In case I/O to device after CD dropped always fails */
+ /* as in Debian Linux 2.1 and Unixware 2.1... */
+ } else {
+ debug(F101,"in_chk ttgmdm I/O error","",errno);
+ debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
+ if (gotsigs) { /* If we got signals before... */
+ if (errno == 5 || errno == 6) { /* I/O error etc */
+ if (clsondisc) /* like when modem hangs up */
+ ttclos(0);
+ return(-2);
+ }
+ }
+ /* If we never got modem signals successfully on this */
+ /* connection before, we can't conclude that THIS failure */
+ /* means the connection was lost. */
+ return(0);
+ }
+ }
+ }
+
+/* We seem to have a connection so now see if any bytes are waiting on it */
+
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
+ debug(F101,"in_chk SSL_pending","",n);
+ if (n < 0) {
+ ttclos(0);
+ return(-1);
+ } else if (n > 0) {
+ return(n);
+ }
+ }
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+ /* It is not safe to read any data when using encrypted Klogin */
+ if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
+#ifdef KRB4
+ if (ttnproto == NP_EK4LOGIN) {
+ n += krb4_des_avail(ttyfd);
+ debug(F101,"in_chk krb4_des_avail","",n);
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (ttnproto == NP_EK5LOGIN) {
+ n += krb5_des_avail(ttyfd);
+ debug(F101,"in_chk krb5_des_avail","",n);
+ }
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ n += krb5_u2u_avail(ttyfd);
+ debug(F101,"in_chk krb5_des_avail","",n);
+ }
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+ if (n < 0) /* Is this right? */
+ return(-1);
+ else
+ return(n);
+ }
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+
+ errno = 0; /* Reset this so we log good info */
+#ifdef FIONREAD
+ x = ioctl(fd, FIONREAD, &n); /* BSD and lots of others */
+#ifdef DEBUG /* (the more the better) */
+ if (deblog) {
+ debug(F101,"in_chk FIONREAD return code","",x);
+ debug(F101,"in_chk FIONREAD count","",n);
+ debug(F101,"in_chk FIONREAD errno","",errno);
+ }
+#endif /* DEBUG */
+#else /* FIONREAD not defined */
+/*
+ Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
+ with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
+ portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
+ that I looked at, but it is needed to prevent the call from blocking), and
+ the msghdr struct differs from place to place, so we would need another
+ avalanche of ifdefs. Still, when FIONREAD is not available, this is the
+ only other known method of asking the OS for the *number* of characters
+ available for reading.
+*/
+#ifdef V7 /* UNIX V7: look in kernel memory */
+#ifdef MINIX
+ n = 0; /* But not in MINIX */
+#else
+#ifdef MINIX2
+ n = 0;
+#else
+ lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
+ x = read(kmem[TTY], &n, sizeof(int));
+ if (x != sizeof(int))
+ n = 0;
+#endif /* MINIX2 */
+#endif /* MINIX */
+#else /* Not V7 */
+#ifdef PROVX1
+ x = ioctl(fd, TIOCQCNT, &ttbuf); /* DEC Pro/3xx Venix V.1 */
+ n = ttbuf.sg_ispeed & 0377; /* Circa 1984 */
+ if (x < 0) n = 0;
+#else
+#ifdef MYREAD
+/*
+ Here we skip all the undependable and expensive calls below if we
+ already have something in our internal buffer. This tends to work quite
+ nicely, so the only really bad case remaining is the one in which neither
+ FIONREAD or MYREAD are defined, which is increasingly rare these days.
+*/
+ if (channel != 0 && my_count > 0) {
+ debug(F101,"in_chk buf my_count","",my_count);
+ n = my_count; /* n was 0 before we got here */
+ return(n);
+ }
+#endif /* MYREAD */
+/*
+ rdchk(), select(), and poll() tell us *if* data is available to be read, but
+ not how much, so these should be used only as a final resort. Especially
+ since these calls tend to add a lot overhead.
+*/
+#ifdef RDCHK /* This mostly SCO-specific */
+ n = rdchk(fd);
+ debug(F101,"in_chk rdchk","",n);
+#else /* No RDCHK */
+#ifdef SELECT
+#ifdef Plan9
+ /* Only allows select on the console ... don't ask */
+ if (channel == 0)
+#endif /* Plan9 */
+ {
+ fd_set rfds; /* Read file descriptors */
+#ifdef BELLV10
+ FD_ZERO(rfds); /* Initialize them */
+ FD_SET(fd,rfds); /* We want to look at this fd */
+#else
+ FD_ZERO(&rfds); /* Initialize them */
+ FD_SET(fd,&rfds); /* We want to look at this fd */
+ tv.tv_sec = tv.tv_usec = 0L; /* A 0-valued timeval structure */
+#endif /* BELLV10 */
+#ifdef Plan9
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk Plan 9 select","",n);
+#else
+#ifdef BELLV10
+ n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
+ debug(F101,"in_chk BELLV10 select","",n);
+#else
+#ifdef BSD44
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk BSD44 select","",n);
+#else
+#ifdef BSD43
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk BSD43 select","",n);
+#else
+#ifdef SOLARIS
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk SOLARIS select","",n);
+#else
+#ifdef QNX6
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk QNX6 select","",n);
+#else
+#ifdef QNX
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk QNX select","",n);
+#else
+#ifdef COHERENT
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk COHERENT select","",n);
+#else
+#ifdef SVR4
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk SVR4 select","",n);
+#else
+#ifdef __linux__
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk LINUX select","",n);
+#ifdef OSF
+ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"in_chk OSF select","",n);
+#else
+ n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
+ debug(F101,"in_chk catchall select","",n);
+#endif /* OSF */
+#endif /* __linux__ */
+#endif /* SVR4 */
+#endif /* COHERENT */
+#endif /* QNX */
+#endif /* QNX6 */
+#endif /* SOLARIS */
+#endif /* BSD43 */
+#endif /* BSD44 */
+#endif /* BELLV10 */
+#endif /* Plan9 */
+ }
+#else /* Not SELECT */
+#ifdef CK_POLL
+ {
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ n = poll(&pfd, 1, 0);
+ debug(F101,"in_chk poll","",n);
+ if ((n > 0) && (pfd.revents & POLLIN))
+ n = 1;
+ }
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* RDCHK */
+#endif /* PROVX1 */
+#endif /* V7 */
+#endif /* FIONREAD */
+
+/* From here down, treat console and communication device differently... */
+
+ if (channel == 0) { /* Console */
+
+#ifdef SVORPOSIX
+#ifndef FIONREAD
+#ifndef SELECT
+#ifndef CK_POLL
+#ifndef RDCHK
+/*
+ This is the hideous hack used in System V and POSIX systems that don't
+ support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
+ CONNECT-mode escape character is attached to SIGQUIT. Used, obviously,
+ only on the console.
+*/
+ if (conesc) { /* Escape character typed == SIGQUIT */
+ debug(F100,"in_chk conesc","",conesc);
+ conesc = 0;
+ signal(SIGQUIT,esctrp); /* Restore signal */
+ n += 1;
+ }
+#endif /* RDCHK */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* FIONREAD */
+#endif /* SVORPOSIX */
+
+ return(n); /* Done with console */
+ }
+
+ if (channel != 0) { /* Communications connection */
+
+#ifdef MYREAD
+#ifndef FIONREAD
+/*
+ select() or rdchk(), etc, has told us that something is waiting, but we
+ don't know how much. So we do a read to get it and then we know. Note:
+ This read is NOT nonblocking if nothing is there (because of VMIN=1), but
+ it should be safe in this case since the OS tells us at least one byte is
+ waiting to be read, and MYREAD reads return as much as is there without
+ waiting for any more. Controlled tests on Solaris and Unixware (with
+ FIONREAD deliberately undefined) show this to be true.
+*/
+ debug(F101,"in_chk read my_count","",my_count);
+ debug(F101,"in_chk read n","",n);
+ if (n > 0 && my_count == 0) {
+ /* This also catches disconnects etc */
+ /* Do what mygetbuf does except don't grab a character */
+ my_count = myfillbuf();
+ my_item = -1; /* ^^^ */
+ debug(F101,"in_chk myfillbuf my_count","",my_count);
+ if (my_count < 0)
+ return(-1);
+ else
+ n = 0; /* NB: n is replaced by my_count */
+ }
+#endif /* FIONREAD */
+/*
+ Here we add whatever we think is unread to what is still in our
+ our internal buffer. Thus the importance of setting n to 0 just above.
+*/
+ debug(F101,"in_chk my_count","",my_count);
+ debug(F101,"in_chk n","",n);
+ if (my_count > 0)
+ n += my_count;
+#endif /* MYREAD */
+ }
+ debug(F101,"in_chk result","",n);
+
+ /* Errors here don't prove the connection has dropped so just say 0 */
+
+ return(n < 0 ? 0 : n);
+}
+
+
+/* T T C H K -- Tell how many characters are waiting in tty input buffer */
+
+int
+ttchk() {
+ int fd;
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+ return(in_chk(1,fd));
+}
+
+/* T T X I N -- Get n characters from tty input buffer */
+
+/* Returns number of characters actually gotten, or -1 on failure */
+
+/* Intended for use only when it is known that n characters are actually */
+/* Available in the input buffer. */
+
+int
+ttxin(n,buf) int n; CHAR *buf; {
+ register int x = 0, c = -2;
+#ifdef TTLEBUF
+ register int i = 0;
+#endif /* TTLEBUF */
+ int fd;
+
+ if (n < 1) /* Nothing to do */
+ return(0);
+
+#ifdef TTLEBUF
+ if (ttpush >= 0) {
+ buf[0] = ttpush; /* Put pushed char in buffer*/
+ ttpush = -1; /* Clear the push buffer */
+ if (ttchk() > 0)
+ return(ttxin(n-1, &buf[1]) + 1);
+ else
+ return(1);
+ }
+ if (le_data) {
+ while (le_inbuf() > 0) {
+ if (le_getchar(&buf[i])) {
+ i++;
+ n--;
+ }
+ }
+ if (ttchk() > 0)
+ return(ttxin(n,&buf[i])+i);
+ else
+ return(i);
+ }
+#endif /* TTLEBUF */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef SUNX25
+ if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
+ return(x25xin(n,buf));
+#endif /* SUNX25 */
+
+#ifdef IBMX25
+ /* riehm: possibly not needed. Test worked with normal reads and writes */
+ if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
+ x = x25xin(n,buf);
+ if (x > 0) buf[x] = '\0';
+ return(x);
+ }
+#endif /* IBMX25 */
+
+#ifdef MYREAD
+ debug(F101,"ttxin MYREAD","",n);
+ while (x < n) {
+ c = myread();
+ if (c < 0) {
+ debug(F101,"ttxin myread returns","",c);
+ if (c == -3) x = -1;
+ break;
+ }
+ buf[x++] = c & ttpmsk;
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+ /* It is impossible to know how many characters are waiting */
+ /* to be read when you are using Encrypted Rlogin or SSL */
+ /* as the transport since the number of real data bytes */
+ /* can be greater or less than the number of bytes on the */
+ /* wire which is what ttchk() returns. */
+ if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
+ if (ttchk() <= 0)
+ break;
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag)
+ if (ttchk() <= 0)
+ break;
+#endif /* CK_SSL */
+ }
+#else
+ debug(F101,"ttxin READ","",n);
+ x = read(fd,buf,n);
+ for (c = 0; c < n; c++) /* Strip any parity */
+ buf[c] &= ttpmsk;
+#endif /* MYREAD */
+
+ debug(F101,"ttxin x","",x); /* Done */
+ if (x > 0) buf[x] = '\0';
+ if (x < 0) x = -1;
+ return(x);
+}
+
+/* T T O L -- Write string s, length n, to communication device. */
+/*
+ Returns:
+ >= 0 on success, number of characters actually written.
+ -1 on failure.
+*/
+#ifdef CK_ENCRYPTION
+CHAR * xpacket = NULL;
+int nxpacket = 0;
+#endif /* CK_ENCRYPTION */
+
+#define TTOLMAXT 5
+int
+ttol(s,n) int n; CHAR *s; {
+ int x, len, tries, fd;
+#ifdef CKXXCHAR
+ extern int dblflag; /* For SET SEND DOUBLE-CHARACTER */
+ extern short dblt[];
+ CHAR *p = NULL, *p2, *s2, c;
+ int n2 = 0;
+#endif /* CKXXCHAR */
+
+ if (ttyfd < 0) /* Not open? */
+ return(-3);
+#ifdef DEBUG
+ if (deblog) {
+ /* debug(F101,"ttol ttyfd","",ttyfd); */
+ ckhexdump("ttol s",s,n);
+ }
+#endif /* DEBUG */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdout;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef CKXXCHAR
+/* Double any characters that must be doubled. */
+ debug(F101,"ttol dblflag","",dblflag);
+ if (dblflag) {
+ p = (CHAR *) malloc(n + n + 1);
+ if (p) {
+ s2 = s;
+ p2 = p;
+ n2 = 0;
+ while (*s2) {
+ c = *s2++;
+ *p2++ = c;
+ n2++;
+ if (dblt[(unsigned) c] & 2) {
+ *p2++ = c;
+ n2++;
+ }
+ }
+ s = p;
+ n = n2;
+ s[n] = '\0';
+ }
+#ifdef DEBUG
+ ckhexdump("ttol doubled s",s,n);
+#endif /* DEBUG */
+ }
+#endif /* CKXXCHAR */
+
+ tries = TTOLMAXT; /* Allow up to this many tries */
+ len = n; /* Remember original length */
+
+#ifdef CK_ENCRYPTION
+/*
+ This is to avoid encrypting a packet that is already encrypted, e.g.
+ when we resend a packet directly out of the packet buffer, and also to
+ avoid encrypting a constant (literal) string, which can cause a memory
+ fault.
+*/
+ if (TELOPT_ME(TELOPT_ENCRYPTION)) {
+ int x;
+ if (nxpacket < n) {
+ if (xpacket) {
+ free(xpacket);
+ xpacket = NULL;
+ nxpacket = 0;
+ }
+ x = n > 10240 ? n : 10240;
+ xpacket = (CHAR *)malloc(x);
+ if (!xpacket) {
+ fprintf(stderr,"ttol malloc failure\n");
+ return(-1);
+ } else
+ nxpacket = x;
+ }
+ memcpy((char *)xpacket,(char *)s,n);
+ s = xpacket;
+ ck_tn_encrypt((char *)s,n);
+ }
+#endif /* CK_ENCRYPTION */
+
+ while (n > 0 &&
+ (tries-- > 0
+#ifdef CK_ENCRYPTION
+ /* keep trying if we are encrypting */
+ || TELOPT_ME(TELOPT_ENCRYPTION)
+#endif /* CK_ENCRYPTION */
+ )) { /* Be persistent */
+ debug(F101,"ttol try","",TTOLMAXT - tries);
+#ifdef BEOSORBEBOX
+ if (netconn && !ttpipe && !ttpty)
+ x = nettol((char *)s,n); /* Write string to device */
+ else
+#endif /* BEOSORBEBOX */
+#ifdef IBMX25
+ if (ttnet == NET_IX25)
+ /*
+ * this is a more controlled way of writing to X25
+ * STREAMS, however write should also work!
+ */
+ x = x25write(ttyfd, s, n);
+ else
+#endif /* IBMX25 */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error;
+ /* Write using SSL */
+ ssl_retry:
+ if (ssl_active_flag)
+ x = SSL_write(ssl_con, s, n);
+ else
+ x = SSL_write(tls_con, s, n);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
+ case SSL_ERROR_NONE:
+ if (x == n)
+ return(len);
+ s += x;
+ n -= x;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ x = 0;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (x != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-3);
+ }
+ } else
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ return(krb4_des_write(ttyfd,s,n));
+ } else
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ return(krb5_des_write(ttyfd,(char *)s,n,0));
+ } else
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ return(krb5_u2u_write(ttyfd,(char *)s,n));
+ } else
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+ x = write(fd,s,n); /* Write string to device */
+
+ if (x == n) { /* Worked? */
+ debug(F101,"ttol ok","",x); /* OK */
+#ifdef CKXXCHAR
+ if (p) free(p);
+#endif /* CKXXCHAR */
+ return(len); /* Done */
+ } else if (x < 0) { /* No, got error? */
+ debug(F101,"ttol write error","",errno);
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK) {
+ msleep(10);
+ continue;
+ } else
+#endif /* EWOULDBLOCK */
+#ifdef TCPSOCKET
+ if (netconn && ttnet == NET_TCPB) {
+ debug(F101,"ttol TCP error","",errno);
+ ttclos(0); /* Close the connection. */
+ x = -3;
+ }
+#endif /* TCPSOCKET */
+#ifdef CKXXCHAR
+ if (p) free(p);
+#endif /* CKXXCHAR */
+ return(x);
+ } else { /* No error, so partial success */
+ debug(F101,"ttol partial","",x); /* This never happens */
+ s += x; /* Point to part not written yet */
+ n -= x; /* Adjust length */
+ if (x > 0) msleep(10); /* Wait 10 msec */
+ } /* Go back and try again */
+ }
+#ifdef CKXXCHAR
+ if (p) free(p);
+#endif /* CKXXCHAR */
+ return(n < 1 ? len : -1); /* Return the results */
+}
+
+/* T T O C -- Output a character to the communication line */
+
+/*
+ This function should only be used for interactive, character-mode operations,
+ like terminal connection, script execution, dialer i/o, where the overhead
+ of the signals and alarms does not create a bottleneck.
+*/
+int
+#ifdef CK_ANSIC
+ttoc(char c)
+#else
+ttoc(c) char c;
+#endif /* CK_ANSIC */
+/* ttoc */ {
+#define TTOC_TMO 15 /* Timeout in case we get stuck */
+ int xx, fd;
+
+ if (ttyfd < 0) /* Check for not open. */
+ return(-1);
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdout;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+ c &= 0xff;
+ /* debug(F101,"ttoc","",(CHAR) c); */
+ saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
+ xx = alarm(TTOC_TMO); /* for this many seconds. */
+ if (xx < 0) xx = 0; /* Save old alarm value. */
+ /* debug(F101,"ttoc alarm","",xx); */
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer went off? */
+ ttimoff(); /* Yes, cancel this alarm. */
+ if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
+ /* debug(F100,"ttoc timeout","",0); */
+#ifdef NETCONN
+ if (!netconn) {
+#endif /* NETCONN */
+ debug(F101,"ttoc timeout","",c);
+ if (ttflow == FLO_XONX) {
+ debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
+#ifndef Plan9
+#ifdef POSIX
+ /* POSIX way to unstick. */
+ debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
+#else
+#ifdef BSD4 /* Berkeley way to do it. */
+#ifdef TIOCSTART
+/* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);". Who knows? */
+ {
+ int x = 0;
+ debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
+ }
+#endif /* TIOCSTART */
+#endif /* BSD4 */
+ /* Is there a Sys V way to do this? */
+#endif /* POSIX */
+#endif /* Plan9 */
+ }
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+ return(-1); /* Return failure code. */
+ } else {
+ int rc;
+#ifdef BEOSORBEBOX
+#ifdef NETCONN
+ if (netconn && !ttpipe && !ttpty)
+ rc = nettoc(c);
+ else
+#endif /* BEOSORBEBOX */
+#endif /* NETCONN */
+#ifdef CK_ENCRYPTION
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(&c,1);
+#endif /* CK_ENCRYPTION */
+#ifdef IBMX25
+ /* riehm: maybe this isn't necessary after all. Test program
+ * worked fine with data being sent and retrieved with normal
+ * read's and writes!
+ */
+ if (ttnet == NET_IX25)
+ rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
+ else
+#endif /* IBMX25 */
+#ifdef CK_SSL
+ if (ssl_active_flag || tls_active_flag) {
+ int error;
+ /* Write using SSL */
+ if (ssl_active_flag)
+ rc = SSL_write(ssl_con, &c, 1);
+ else
+ rc = SSL_write(tls_con, &c, 1);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ rc = 0;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (rc != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ ttclos(0);
+ return(-1);
+ }
+ } else
+#endif /* CK_SSL */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK4LOGIN) {
+ rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
+ } else
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+ if (ttnproto == NP_EK5LOGIN) {
+ rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
+ } else
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ if (ttnproto == NP_K5U2U) {
+ rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
+ } else
+#endif /* KRB5_U2U */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+ rc = write(fd,&c,1); /* Try to write the character. */
+ if (rc < 1) { /* Failed */
+ ttimoff(); /* Turn off the alarm. */
+ alarm(xx); /* Restore previous alarm. */
+ debug(F101,"ttoc errno","",errno); /* Log the error, */
+ return(-1); /* and return the error code. */
+ }
+ }
+ ttimoff(); /* Success, turn off the alarm. */
+ alarm(xx); /* Restore previous alarm. */
+ return(0); /* Return good code. */
+}
+
+/* T T I N L -- Read a record (up to break character) from comm line. */
+/*
+ Reads up to "max" characters from the connection, terminating on:
+ (a) the packet length field if the "turn" argument is zero, or
+ (b) on the packet-end character (eol) if the "turn" argument is nonzero
+ (c) a certain number of Ctrl-C's in a row
+
+ Returns:
+ >= 0, the number of characters read upon success;
+ -1 if "max" exceeded, timeout, or other correctable error;
+ -2 on user interruption (c);
+ -3 on fatal error like connection lost.
+
+ The name of this routine dates from the early days when Kermit packets
+ were, indeed, always lines of text. That was before control-character
+ unprefixing and length-driven packet framing were introduced, which this
+ version handle. NB: this routine is ONLY for reading incoming Kermit
+ packets, nothing else. To read other kinds of incoming material, use
+ ttinc() or ttxin().
+
+ The bytes that were input are copied into "dest" with their parity bits
+ stripped if parity was selected. Returns the number of bytes read.
+ Bytes after the eol are available upon the next call to this function.
+
+ The idea is to minimize the number of system calls per packet, and also to
+ minimize timeouts. This function is the inner loop of the protocol and must
+ be as efficient as possible. The current strategy is to use myread(), a
+ macro to manage buffered (and generally nonblocking) reads.
+
+ WARNING: This function calls parchk(), which is defined in another module.
+ Normally, ckutio.c does not depend on code from any other module, but there
+ is an exception in this case because all the other ck?tio.c modules also
+ need to call parchk(), so it's better to have it defined in a common place.
+*/
+#ifdef CTRLC
+#undef CTRLC
+#endif /* CTRLC */
+#define CTRLC '\03'
+/*
+ We have four different declarations here because:
+ (a) to allow Kermit to be built without the automatic parity sensing feature
+ (b) one of each type for ANSI C, one for non-ANSI.
+*/
+#ifndef NOXFER
+
+static int pushedback = 0;
+
+int
+#ifdef PARSENSE
+#ifdef CK_ANSIC
+ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
+#else
+ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
+#endif /* CK_ANSIC */
+#else /* not PARSENSE */
+#ifdef CK_ANSIC
+ttinl(CHAR *dest, int max,int timo, CHAR eol)
+#else
+ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
+#endif /* CK_ANSIC */
+#endif /* PARSENSE */
+/* ttinl */ {
+
+#ifndef MYREAD
+ CHAR ch, dum;
+#endif /* MYREAD */
+#ifdef PARSENSE
+ int pktlen = -1;
+ int lplen = 0;
+ int havelen = 0;
+#endif /* PARSENSE */
+ int fd;
+ int sopmask = 0xff; /* Start-Of-Packet mask */
+#ifdef CKXXCHAR
+ extern short dblt[]; /* Ignore-character table */
+ extern int ignflag;
+#endif /* CKXXCHAR */
+#ifdef TCPSOCKET
+ extern CHAR stchr;
+#endif /* TCPSOCKET */
+ int x;
+#ifdef STREAMING
+ extern int streaming;
+ extern int sndtyp;
+#endif /* STREAMING */
+
+ if (ttyfd < 0) return(-3); /* Not open. */
+/*
+ In February 2007 I fixed ttinl() to work better under the truly awful
+ conditions encountered by the AM-APEX oceanographic floats that gather
+ hurricane data and phone home using Iridium satellite modems, which under
+ certain conditions, can send two packets back to back after a long pause.
+ In this case the second packet would be ignored because the SOH was skipped
+ due to the ttflui() call. But the reworked lookahead/pushback logic broke
+ Kermit transfers on encrypted connections. This was fixed 12-13 August
+ 2007. All of this happened after 8.0.212 Dev.27 was released and before
+ Dev.28, so no harm done other than the delay.
+*/
+ debug(F101,"ttinl max","",max);
+ debug(F101,"ttinl timo","",timo);
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+#ifdef COMMENT
+ if (xlocal && conchk() > 0) /* Allow for console interruptions */
+ return(-1);
+#endif /* COMMENT */
+
+ *dest = '\0'; /* Clear destination buffer */
+ if (timo < 0) timo = 0; /* Safety */
+ if (timo) { /* Don't time out if timo == 0 */
+ int xx;
+ saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
+ xx = alarm(timo); /* Set it. */
+ debug(F101,"ttinl alarm","",xx);
+ }
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer went off? */
+ debug(F100,"ttinl timout","",0); /* Get here on timeout. */
+ /* debug(F110," with",(char *) dest,0); */
+ ttimoff(); /* Turn off timer */
+ return(-1); /* and return error code. */
+ } else {
+ register int i, n = -1; /* local variables */
+ int ccn = 0;
+#ifdef PARSENSE
+ register int flag = 0;
+ debug(F000,"ttinl start","",start);
+#endif /* PARSENSE */
+
+ ttpmsk = ttprty ? 0177 : 0377; /* Set parity stripping mask. */
+ sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
+
+/* Now read into destination, stripping parity and looking for the */
+/* the packet terminator, and also for several Ctrl-C's typed in a row. */
+
+ i = 0; /* Destination index */
+ debug(F101,"ttinl eol","",eol);
+
+ while (i < max-1) {
+#ifdef MYREAD
+ errno = 0;
+ /* On encrypted connections myread returns encrypted bytes */
+ n = myread();
+ debug(F000,"TTINL myread char","",n);
+ if (n < 0) { /* Timeout or i/o error? */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"ttinl myread failure, n","",n);
+ debug(F101,"ttinl myread errno","",errno);
+ }
+#endif /* DEBUG */
+ /* Don't let EINTR break packets. */
+ if (n == -3) {
+ if (errno == EINTR && i > 0) {
+ debug(F111,"ttinl EINTR myread i","continuing",i);
+ continue;
+ } else {
+ debug(F110,"ttinl non-EINTR -3","closing",0);
+ wasclosed = 1;
+ ttimoff(); /* Turn off timer */
+ ttclos(0);
+ return(n);
+ }
+ } else if (n == -2 && netconn /* && timo == 0 */ ) {
+ /* Here we try to catch broken network connections */
+ /* even when ioctl() and read() do not catch them */
+ debug(F111,"ttinl network myread failure","closing",n);
+ wasclosed = 1;
+ ttimoff();
+ ttclos(0);
+ return(-3);
+ }
+#ifdef STREAMING
+ /* Streaming and no data to read */
+ else if (n == 0 && streaming && sndtyp == 'D')
+ return(0);
+#endif /* STREAMING */
+ break; /* Break out of while loop */
+ }
+
+#else /* not MYREAD (is this code used anywhere any more?) */
+/*
+ The non-MYREAD code dates from the 1980s and was needed on certain platforms
+ where there were no nonblocking reads. -fdc, 2007/02/22.
+*/
+ if ((n = read(fd, &n, 1)) < 1)
+ break; /* Error - break out of while loop */
+
+#endif /* MYREAD */
+
+ /* Get here with char in n */
+
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
+ CHAR ch = n;
+ ck_tn_decrypt((char *)&ch,1);
+ n = ch;
+ debug(F000,"TTINL decryp char","",n);
+ }
+ pushedback = 0;
+#endif /* CK_ENCRYPTION */
+
+#ifdef TCPSOCKET
+ if (n == IAC && /* Handle Telnet options */
+ ((xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet))) {
+ n = tt_tnopt(n);
+ if (n < 0)
+ return(n);
+#ifndef NOPARSEN
+ else if (n == 1)
+ start = stchr;
+#endif /* NOPARSEN */
+ if (n != 255) /* No data - go back for next char */
+ continue;
+ } /* Quoted IAC - keep going */
+#endif /* TCPSOCKET */
+
+#ifdef CKXXCHAR
+ if (ignflag)
+ if (dblt[(unsigned) n] & 1) /* Character to ignore? */
+ continue;
+#endif /* CKXXCHAR */
+/*
+ Use parity mask, rather than always stripping parity, to check for
+ cancellation. Otherwise, runs like \x03\x83\x03 in a packet could cancel
+ the transfer when parity is NONE. (Note that \x03\x03\x03 is extremely
+ unlikely due to run-length encoding.)
+*/
+ /* Check cancellation */
+ if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
+ if (++ccn >= xfrnum) { /* If xfrnum in a row, bail out. */
+ if (timo) { /* Clear timer. */
+ ttimoff();
+ }
+ if (xfrchr < 32)
+ printf("^%c...\r\n",(char)(xfrchr+64));
+ else
+ printf("Canceled...\r\n");
+ return(-2);
+ }
+ } else ccn = 0; /* No cancellation, reset counter, */
+
+#ifdef PARSENSE
+/*
+ Restructured code allows for a new packet to appear somewhere in the
+ middle of a previous one. -fdc, 24 Feb 2007.
+*/
+ if ((n & sopmask) == start) { /* Start of Packet */
+ debug(F101,"ttinl SOP i","",i);
+ flag = 1; /* Flag that we are in a packet */
+ havelen = 0; /* Invalidate previous length */
+ pktlen = -1; /* (if any) in case we were */
+ lplen = 0; /* alread processand a packet */
+ i = 0; /* and reset the dest buffer pointer */
+ }
+ if (flag == 0) { /* No SOP yet... */
+ debug(F000,"ttinl skipping","",n);
+ continue;
+ }
+ dest[i++] = n & ttpmsk;
+/*
+ If we have not been instructed to wait for a turnaround character, we can go
+ by the packet length field. If turn != 0, we must wait for the end of line
+ (eol) character before returning. This is an egregious violation of all
+ principles of layering... (Less egregious in C-Kermit 9.0, in which we go
+ by the length field but also look for the eol in case it arrives early,
+ e.g. if the length field was corrupted upwards.)
+*/
+ if (!havelen) {
+ if (i == 2) {
+ if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
+ return(-1); /* fdc - 13 Apr 2010 */
+ pktlen = xunchar(dest[1] & 0x7f);
+ if (pktlen > 94) /* Rubout in length field */
+ return(-1); /* fdc - 13 Apr 2010 */
+ if (pktlen > 1) {
+ havelen = 1;
+ debug(F101,"ttinl pktlen value","",pktlen);
+ }
+ } else if (i == 5 && pktlen == 0) {
+ lplen = xunchar(dest[4] & 0x7f);
+ } else if (i == 6 && pktlen == 0) {
+ pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
+ havelen = 1;
+ debug(F101,"ttinl extended length","",pktlen);
+ }
+ }
+
+/*
+ Suppose we looked at the sequence number here and found it was out of
+ range? This would mean either (a) incoming packets had SOP unprefixed
+ and we are out of sync, or (b) the packet is damaged. Since (a) is bad
+ practice, let's ignore it. So what should we do here if we know the
+ packet is damaged?
+
+ 1. Nothing -- keep trying to read the packet till we find what we think
+ is the end, or we time out, and let the upper layer decide what to
+ do. But since either the packet is corrupt or we are out of sync,
+ our criterion for finding the end does not apply and we are likely
+ to time out (or swallow a piece of the next packet) if our assumed
+ length is too long. (This was the behavior prior to version 7.0.)
+
+ 2. set flag = 0 and continue? This would force us to wait for the
+ next packet to come in, and therefore (in the nonwindowing case),
+ would force a timeout in the other Kermit.
+
+ 3. set flag = 0 and continue, but only if the window size is > 1 and
+ the window is not blocked? Talk about cheating!
+
+ 4. Return a failure code and let the upper layer decide what to do.
+ This should be equivalent to 3, but without the cheating. So let's
+ do it that way... But note that we must ignore the parity bit
+ in case this is the first packet and we have not yet run parchk().
+*/
+ if (i == 3) { /* Peek at sequence number */
+ x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
+ if (x < 0 || x > 63) {
+ debug(F111,"ttinl bad seq",dest,x);
+ if (timo) ttimoff();
+ return(-1); /* return a nonfatal error */
+ }
+ }
+
+#else /* PARSENSE */
+ dest[i++] = n & ttpmsk;
+#endif /* PARSENSE */
+
+ /* Check for end of packet */
+
+ if (
+ ((n & ttpmsk) == eol) /* Always break on the eol char */
+#ifdef PARSENSE
+ || /* fdc - see notes of 13 Apr 2010 */
+/*
+ Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
+ This allows packet terminators and handshake characters to appear
+ literally inside a packet data field.
+*/
+ (havelen && (i > pktlen+1) &&
+ (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
+
+#endif /* PARSENSE */
+ ) {
+/*
+ Here we have either read the last byte of the packet based on its length
+ field, or else we have read the packet terminator (eol) or the half-duplex
+ line-turnaround char (turn).
+*/
+#ifndef PARSENSE
+ debug(F101,"ttinl got eol","",eol); /* (or turn) */
+ dest[i] = '\0'; /* Yes, terminate the string, */
+ /* debug(F101,"ttinl i","",i); */
+
+#else /* PARSENSE */
+
+#ifdef DEBUG
+ if (deblog) {
+ if ((n & ttpmsk) != eol) {
+ debug(F101,"ttinl EOP length","",pktlen);
+ debug(F000,"ttinl EOP current char","",n);
+ debug(F101,"ttinl EOP packet buf index","",i);
+ } else debug(F101,"ttinl got eol","",eol);
+ }
+#endif /* DEBUG */
+
+#ifdef MYREAD
+/*
+ The packet was read based on its length. This leaves the packet terminator
+ unread, and so ttchk() will always return at least 1 because of this,
+ possibly giving a false positive to the "is there another packet waiting?"
+ test. But if we know the terminator (or any other interpacket junk) is
+ there, we can safely get rid of it.
+
+ NOTE: This code reworked to (a) execute even if the debug log isn't active;
+ and (b) actually work. -fdc, 2007/02/22. And again 2007/08/12-13 to also
+ work on encrypted connections.
+*/
+ debug(F101,"TTINL my_count","",my_count);
+ if ((n & ttpmsk) != eol) { /* Not the packet terminator */
+ int x;
+ while (my_count > 0) {
+ x = myread(); /* (was ttinc(0) */
+ debug(F000,"TTINL lkread char","",x);
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ CHAR ch = x;
+ ck_tn_decrypt((char *)&ch,1);
+ x = ch;
+ debug(F000,"TTINL lkdecr char","",x);
+ }
+#endif /* CK_ENCRYPTION */
+ /*
+ Note: while it might seem more elegant to simply
+ push back the encrypted byte, that desynchronizes
+ the decryption stream; the flag is necessary so we
+ don't try to decrypt the same byte twice.
+ */
+ if ((x & ttpmsk) == start) { /* Start of next packet */
+ myunrd(x); /* Push back the decrypted byte */
+ pushedback = 1; /* And set flag */
+ debug(F000,"TTINL lkpush char","",x);
+ break;
+ }
+ }
+ }
+#endif /* MYREAD */
+
+ dest[i] = '\0'; /* Terminate the string, */
+ if (needpchk) { /* Parity checked yet? */
+ if (ttprty == 0) { /* No, check. */
+ if ((ttprty = parchk(dest,start,i)) > 0) {
+ int j;
+ debug(F101,"ttinl senses parity","",ttprty);
+ debug(F110,"ttinl packet before",dest,0);
+ ttpmsk = 0x7f;
+ for (j = 0; j < i; j++)
+ dest[j] &= 0x7f; /* Strip parity from packet */
+ debug(F110,"ttinl packet after ",dest,0);
+ } else ttprty = 0; /* Restore if parchk error */
+ }
+ sopmask = ttpmsk;
+ needpchk = 0;
+ }
+#endif /* PARSENSE */
+
+ if (timo) /* Turn off timer if it was on */
+ ttimoff();
+ ckhexdump("ttinl got",dest,i);
+
+#ifdef STREAMING
+ /* ttinl() was called because there was non-packet */
+ /* data sitting in the back channel. Ignore it. */
+ if (streaming && sndtyp == 'D')
+ return(-1);
+#endif /* STREAMING */
+ return(i);
+ }
+ } /* End of while() */
+ ttimoff();
+ return(n);
+ }
+}
+#endif /* NOXFER */
+
+/* T T I N C -- Read a character from the communication line */
+/*
+ On success, returns the character that was read, >= 0.
+ On failure, returns -1 or other negative myread error code,
+ or -2 if connection is broken or ttyfd < 0.
+ or -3 if session limit has expired,
+ or -4 if something or other...
+ NOTE: The API does not provide for ttinc() returning a special code
+ upon timeout, but we need it. So for this we have a global variable,
+ ttinctimo.
+*/
+static int ttinctimo = 0; /* Yuk */
+
+int
+ttinc(timo) int timo; {
+
+ int n = 0, fd;
+ int is_tn = 0;
+ CHAR ch = 0;
+
+ ttinctimo = 0;
+
+ if (ttyfd < 0) return(-2); /* Not open. */
+
+ is_tn = (xlocal && netconn && IS_TELNET()) ||
+ (!xlocal && sstelnet);
+
+#ifdef TTLEBUF
+ if (ttpush >= 0) {
+ debug(F111,"ttinc","ttpush",ttpush);
+ ch = ttpush;
+ ttpush = -1;
+ return(ch);
+ }
+ if (le_data) {
+ if (le_getchar(&ch) > 0) {
+ debug(F111,"ttinc le_getchar","ch",ch);
+ return(ch);
+ }
+ }
+#endif /* TTLEBUF */
+
+#ifdef NETCMD
+ if (ttpipe)
+ fd = fdin;
+ else
+#endif /* NETCMD */
+ fd = ttyfd;
+
+ if ((timo <= 0) /* Untimed. */
+#ifdef MYREAD
+ || (my_count > 0) /* Buffered char already waiting. */
+#endif /* MYREAD */
+ ) {
+#ifdef MYREAD
+ /* Comm line failure returns -1 thru myread, so no &= 0377 */
+ n = myread(); /* Wait for a character... */
+ /* debug(F000,"ttinc MYREAD n","",n); */
+#ifdef CK_ENCRYPTION
+ /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
+ if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
+ ch = n;
+ ck_tn_decrypt((char *)&ch,1);
+ n = ch;
+ }
+#endif /* CK_ENCRYPTION */
+
+#ifdef NETPTY
+ if (ttpty && n < 0) {
+ debug(F101,"ttinc error on pty","",n);
+ ttclos(0);
+ return(n);
+ }
+#endif /* NETPTY */
+
+#ifdef TNCODE
+ if ((n > -1) && is_tn)
+ return((unsigned)(n & 0xff));
+ else
+#endif /* TNCODE */
+ return(n < 0 ? n : (unsigned)(n & ttpmsk));
+
+#else /* MYREAD */
+
+ while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
+ /* Shouldn't have to loop in ver 5A. */
+#ifdef NETCONN
+ if (netconn) { /* Special handling for net */
+ netclos(); /* If read() returns 0 it means */
+ netconn = 0; /* the connection has dropped. */
+ errno = ENOTCONN;
+ return(-2);
+ }
+#endif /* NETCONN */
+ ;
+ /* debug(F101,"ttinc","",ch); */
+#ifdef TNCODE
+ if ((n > 0) && is_tn) {
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION)) {
+ ck_tn_decrypt(&ch,1);
+ n = ch;
+ }
+#endif /* CK_ENCRYPTION */
+ return((unsigned)(ch & 0xff));
+ } else
+#endif /* TNCODE */
+ return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
+#endif /* MYREAD */
+
+ } else { /* Timed read */
+
+ int oldalarm;
+ saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
+ oldalarm = alarm(timo); /* Set alarm, save old one. */
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) { /* Timer expired */
+ ttinctimo = 1;
+ n = -1; /* set flag */
+ } else {
+#ifdef MYREAD
+ n = myread(); /* If managing own buffer... */
+ debug(F101,"ttinc myread","",n);
+ ch = n;
+#else
+ n = read(fd,&ch,1); /* Otherwise call the system. */
+ if (n == 0) n = -1;
+ debug(F101,"ttinc read","",n);
+#endif /* MYREAD */
+
+#ifdef CK_ENCRYPTION
+ if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
+ ck_tn_decrypt((char *)&ch,1);
+ }
+#endif /* CK_ENCRYPTION */
+ if (n >= 0)
+ n = (unsigned) (ch & 0xff);
+ else
+ n = (n < 0) ? -4 : -2; /* Special return codes. */
+ }
+ ttimoff(); /* Turn off the timer */
+ if (oldalarm > 0) {
+ if (n == -1) /* and restore any previous alarm */
+ oldalarm -= timo;
+ if (oldalarm < 0) /* adjusted by our timeout interval */
+ oldalarm = 0;
+ if (oldalarm) {
+ debug(F101,"ttinc restoring oldalarm","",oldalarm);
+ alarm(oldalarm);
+ }
+ }
+#ifdef NETCONN
+ if (netconn) {
+ if (n == -2) { /* read() returns 0 */
+ netclos(); /* on network read failure */
+ netconn = 0;
+ errno = ENOTCONN;
+ }
+ }
+#endif /* NETCONN */
+#ifdef TNCODE
+ if ((n > -1) && is_tn)
+ return((unsigned)(n & 0xff));
+ else
+#endif /* TNCODE */
+ /* Return masked char or neg. */
+ return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
+ }
+}
+
+/* S N D B R K -- Send a BREAK signal of the given duration */
+
+static int
+#ifdef CK_ANSIC
+sndbrk(int msec) { /* Argument is milliseconds */
+#else
+sndbrk(msec) int msec; {
+#endif /* CK_ANSIC */
+#ifndef POSIX
+ int x, n;
+#endif /* POSIX */
+
+#ifdef OXOS
+#define BSDBREAK
+#endif /* OXOS */
+
+#ifdef ANYBSD
+#define BSDBREAK
+#endif /* ANYBSD */
+
+#ifdef BSD44
+#define BSDBREAK
+#endif /* BSD44 */
+
+#ifdef COHERENT
+#ifdef BSDBREAK
+#undef BSDBREAK
+#endif /* BSDBREAK */
+#endif /* COHERENT */
+
+#ifdef BELLV10
+#ifdef BSDBREAK
+#undef BSDBREAK
+#endif /* BSDBREAK */
+#endif /* BELLV10 */
+
+#ifdef PROVX1
+ char spd;
+#endif /* PROVX1 */
+
+ debug(F101,"ttsndb ttyfd","",ttyfd);
+ if (ttyfd < 0) return(-1); /* Not open. */
+
+#ifdef Plan9
+ return p9sndbrk(msec);
+#else
+#ifdef NETCONN
+#ifdef NETCMD
+ if (ttpipe) /* Pipe */
+ return(ttoc('\0'));
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty)
+ return(ttoc('\0'));
+#endif /* NETPTY */
+ if (netconn) /* Send network BREAK */
+ return(netbreak());
+#endif /* NETCONN */
+
+ if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
+
+#ifdef POSIX /* Easy in POSIX */
+ {
+ int x;
+ debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
+ errno = 0;
+ x = tcsendbreak(ttyfd,msec / 375);
+ debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
+ return(x);
+ }
+#else
+#ifdef PROVX1
+ gtty(ttyfd,&ttbuf); /* Get current tty flags */
+ spd = ttbuf.sg_ospeed; /* Save speed */
+ ttbuf.sg_ospeed = B50; /* Change to 50 baud */
+ stty(ttyfd,&ttbuf); /* ... */
+ n = (int)strlen(brnuls); /* Send the right number of nulls */
+ x = msec / 91;
+ if (x > n) x = n;
+ write(ttyfd,brnuls,n);
+ ttbuf.sg_ospeed = spd; /* Restore speed */
+ stty(ttyfd,&ttbuf); /* ... */
+ return(0);
+#else
+#ifdef aegis
+ sio_$control((short)ttyfd, sio_$send_break, msec, st);
+ return(0);
+#else
+#ifdef BSDBREAK
+ n = FWRITE; /* Flush output queue. */
+/* Watch out for int vs long problems in &n arg! */
+ debug(F101,"sndbrk BSDBREAK","",msec);
+ ioctl(ttyfd,TIOCFLUSH,&n); /* Ignore any errors.. */
+ if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */
+ perror("Can't send BREAK");
+ return(-1);
+ }
+ x = msleep(msec); /* Sleep for so many milliseconds */
+ if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */
+ perror("BREAK stuck!!!");
+ doexit(BAD_EXIT,-1); /* Get out, closing the line. */
+ /* with bad exit status */
+ }
+ return(x);
+#else
+#ifdef ATTSV
+/*
+ No way to send a long BREAK in Sys V, so send a bunch of regular ones.
+ (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
+ but there's no way for this code to know for sure.)
+*/
+ debug(F101,"sndbrk ATTSV","",msec);
+ x = msec / 275;
+ for (n = 0; n < x; n++) {
+ /* Reportedly the cast breaks this function on some systems */
+ /* But then why was it here in the first place? */
+ if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
+ perror("Can't send BREAK");
+ return(-1);
+ }
+ }
+ return(0);
+#else
+#ifdef V7
+ debug(F101,"sndbrk V7","",msec);
+ return(genbrk(ttyfd,250)); /* Simulate a BREAK */
+#else
+ debug(F101,"sndbrk catchall","",msec);
+ ttoc(0);ttoc(0);ttoc(0);ttoc(0);
+ return(0);
+#endif /* V7 */
+#endif /* BSDBREAK */
+#endif /* ATTSV */
+#endif /* aegis */
+#endif /* PROVX1 */
+#endif /* POSIX */
+#endif /* Plan9 */
+}
+
+/* T T S N D B -- Send a BREAK signal */
+
+int
+ttsndb() {
+#ifdef TN_COMPORT
+ if (netconn && istncomport())
+ return((tnsndb(275L) >= 0) ? 0 : -1);
+ else
+#endif /* TN_COMPORT */
+ return(sndbrk(275));
+}
+
+/* T T S N D L B -- Send a Long BREAK signal */
+
+int
+ttsndlb() {
+#ifdef TN_COMPORT
+ if (netconn && istncomport())
+ return((tnsndb(1800L) >= 0) ? 0 : -1);
+ else
+#endif /* TN_COMPORT */
+ return(sndbrk(1500));
+}
+
+/* M S L E E P -- Millisecond version of sleep(). */
+
+/*
+ Call with number of milliseconds (thousandths of seconds) to sleep.
+ Intended only for small intervals. For big ones, just use sleep().
+ Highly system-dependent.
+ Returns 0 always, even if it didn't work.
+*/
+
+/* Define MSLFTIME for systems that must use an ftime() loop. */
+#ifdef ANYBSD /* For pre-4.2 BSD versions */
+#ifndef BSD4
+#define MSLFTIME
+#endif /* BSD4 */
+#endif /* ANYBSD */
+
+#ifdef TOWER1 /* NCR Tower OS 1.0 */
+#define MSLFTIME
+#endif /* TOWER1 */
+
+#ifdef COHERENT /* Coherent... */
+#ifndef _I386 /* Maybe Coherent/386 should get this, too */
+#define MSLFTIME /* Opinions are divided */
+#endif /* _I386 */
+#endif /* COHERENT */
+
+#ifdef COMMENT
+#ifdef GETMSEC
+
+/* Millisecond timer */
+
+static long msecbase = 0L; /* Unsigned long not portable */
+
+long
+getmsec() { /* Milliseconds since base time */
+ struct timeval xv;
+ struct timezone xz;
+ long secs, msecs;
+ if (
+#ifdef GTODONEARG
+ gettimeofday(&tv)
+#else
+#ifdef PTX
+ gettimeofday(&tv, NULL)
+#else
+ gettimeofday(&tv, &tz)
+#endif /* PTX */
+#endif /* GTODONEARG */
+ < 0)
+ return(-1);
+ if (msecbase == 0L) { /* First call, set base time. */
+ msecbase = tv.tv_sec;
+ debug(F101,"getmsec base","",msecbase);
+ }
+ return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
+}
+#endif /* GETMSEC */
+#endif /* COMMENT */
+
+#ifdef SELECT
+int
+ttwait(fd, secs) int fd, secs; {
+ int x;
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(fd,&rfds);
+ tv.tv_sec = secs;
+ tv.tv_usec = 0L;
+ errno = 0;
+ if ((x = select(FD_SETSIZE,
+#ifdef HPUX9
+ (int *)
+#else
+#ifdef HPUX1000
+ (int *)
+#endif /* HPUX1000 */
+#endif /* HPUX9 */
+ &rfds,
+ 0, 0, &tv)) < 0) {
+ debug(F101,"ttwait select errno","",errno);
+ return(0);
+ } else {
+ debug(F101,"ttwait OK","",errno);
+ x = FD_ISSET(fd, &rfds);
+ debug(F101,"ttwait select x","",x);
+ return(x ? 1 : 0);
+ }
+}
+#endif /* SELECT */
+
+int
+msleep(m) int m; {
+/*
+ Other possibilities here are:
+ nanosleep(), reportedly defined in POSIX.4.
+ sginap(), IRIX only (back to what IRIX version I don't know).
+*/
+#ifdef Plan9
+ return _SLEEP(m);
+#else
+#ifdef BEOSORBEBOX
+ snooze(m*1000);
+#else /* BEOSORBEBOX */
+#ifdef SELECT
+ int t1, x;
+ debug(F101,"msleep SELECT 1","",m);
+ if (m <= 0) return(0);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ debug(F101,"msleep SELECT 2","",m);
+#ifdef BELLV10
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
+ debug(F101,"msleep BELLV10 select","",x);
+#else /* BELLV10 */
+#ifdef HPUX9
+ gettimeofday(&tv, &tz);
+#else
+
+#ifndef COHERENT
+#ifdef GTODONEARG
+ if (gettimeofday(&tv) < 0)
+#else
+#ifdef PTX
+ if (gettimeofday(&tv,NULL) < 0)
+#else
+#ifdef NOTIMEZONE
+ if (gettimeofday(&tv, NULL) < 0) /* wonder what this does... */
+#else
+ if (gettimeofday(&tv, &tz) < 0)
+#endif /* NOTIMEZONE */
+#endif /* PTX */
+#endif /* GTODONEARG */
+ return(-1);
+ t1 = tv.tv_sec; /* Seconds */
+#endif /* COHERENT */
+#endif /* HPUX9 */
+ tv.tv_sec = 0; /* Use select() */
+ tv.tv_usec = m * 1000L;
+#ifdef BSD44
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep BSD44 select","",x);
+#else /* BSD44 */
+#ifdef __linux__
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep __linux__ select","",x);
+#else /* __linux__ */
+#ifdef BSD43
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep BSD43 select","",x);
+#else /* BSD43 */
+#ifdef QNX6
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep QNX6 select","",x);
+#else /* QNX6 */
+#ifdef QNX
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep QNX select","",x);
+#else /* QNX */
+#ifdef COHERENT
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep COHERENT select","",x);
+#else /* COHERENT */
+#ifdef HPUX1000 /* 10.00 only, not 10.10 or later */
+ x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
+ debug(F101,"msleep HP-UX 10.00 select","",x);
+#else /* HPUX1000 */
+#ifdef SVR4
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep SVR4 select","",x);
+#else /* SVR4 */
+#ifdef OSF40
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep OSF40 select","",x);
+#else /* OSF40 */
+#ifdef PTX
+ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+ debug(F101,"msleep OSF40 select","",x);
+#else
+ x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
+ debug(F101,"msleep catch-all select","",x);
+#endif /* PTX */
+#endif /* OSF40 */
+#endif /* HP1000 */
+#endif /* SVR4 */
+#endif /* COHERENT */
+#endif /* QNX */
+#endif /* QNX6 */
+#endif /* BSD43 */
+#endif /* __linux__ */
+#endif /* BSD44 */
+#endif /* BELLV10 */
+ return(0);
+
+#else /* Not SELECT */
+#ifdef CK_POLL /* We have poll() */
+ struct pollfd pfd; /* Supply a valid address for poll() */
+
+#ifdef ODT30 /* But in SCO ODT 3.0 */
+#ifdef NAP /* we should use nap() instead */
+ debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
+ nap((long)m); /* seems to break dialing. */
+ return(0);
+#else
+ debug(F101,"msleep ODT 3.0 POLL","",m);
+ poll(&pfd, 0, m);
+ return(0);
+#endif /* NAP */
+#else
+ debug(F101,"msleep POLL","",m);
+ poll(&pfd, 0, m);
+ return(0);
+#endif /* ODT30 */
+
+/*
+ We could handle the above more cleanly by just letting nap() always
+ take precedence over poll() in this routine, but there is no way to know
+ whether that would break something else.
+*/
+
+#else /* Not POLL */
+#ifdef USLEEP
+/*
+ "This routine is implemented using setitimer(2); it requires eight
+ system calls...". In other words, it might take 5 minutes to sleep
+ 10 milliseconds...
+*/
+ debug(F101,"msleep USLEEP","",m);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ usleep((unsigned int)(m * 1000));
+ return(0);
+#else
+#ifdef aegis
+ time_$clock_t dur;
+ debug(F101,"msleep aegis","",m);
+ dur.c2.high16 = 0;
+ dur.c2.low32 = 250 * m; /* one millisecond = 250 four microsecond ticks */
+ time_$wait(time_$relative, dur, st);
+ return(0);
+#else
+#ifdef PROVX1
+ debug(F101,"msleep Venix","",m);
+ if (m <= 0) return(0);
+ sleep(-((m * 60 + 500) / 1000));
+ return(0);
+#else
+#ifdef NAP
+ debug(F101,"msleep NAP","",m);
+ nap((long)m);
+ return(0);
+#else
+#ifdef ATTSV
+#ifndef BSD44
+ extern long times(); /* Or #include <times.h> ? */
+#endif /* BSD44 */
+ long t1, t2, tarray[4];
+ int t3;
+ char *cp = getenv("HZ");
+ int CLOCK_TICK;
+ int hertz;
+
+ if (cp && (hertz = atoi(cp))) {
+ CLOCK_TICK = 1000 / hertz;
+ } else { /* probably single user mode */
+#ifdef HZ
+ CLOCK_TICK = 1000 / HZ;
+#else
+ static warned = 0;
+ /* HZ always exists in, for instance, SCO Xenix, so you don't have to
+ * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
+ * have Xenix, you have should have nap(), so the best is to use -DNAP
+ * in the makefile. Most systems have HZ.
+ */
+ CLOCK_TICK = 17; /* 1/60 sec */
+ if (!warned) {
+ printf("warning: environment variable HZ bad... using HZ=%d\r\n",
+ 1000 / CLOCK_TICK);
+ warned = 1;
+ }
+#endif /* !HZ */
+ }
+ debug(F101,"msleep ATTSV","",m);
+ if (m <= 0) return(0);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ if ((t1 = times(tarray)) < 0) return(-1);
+ while (1) {
+ if ((t2 = times(tarray)) < 0) return(-1);
+ t3 = ((int)(t2 - t1)) * CLOCK_TICK;
+ if (t3 > m) return(t3);
+ }
+#else /* Not ATTSV */
+#ifdef MSLFTIME /* Use ftime() loop... */
+ int t1, t3 = 0;
+ debug(F101,"msleep MSLFTIME","",m);
+ if (m <= 0) return(0);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+#ifdef QNX
+ ftime(&ftp); /* void ftime() in QNX */
+#else
+ if (ftime(&ftp) < 0) return(-1); /* Get base time. */
+#endif /* QNX */
+ t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
+ while (1) {
+ ftime(&ftp); /* Get current time and compare. */
+ t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
+ if (t3 > m) return(0);
+ }
+#else
+/* This includes true POSIX, which has no way to do this. */
+ debug(F101,"msleep busy loop","",m);
+ if (m >= 1000) { /* Catch big arguments. */
+ sleep(m/1000);
+ m = m % 1000;
+ if (m < 10) return(0);
+ }
+ if (m > 0) while (m > 0) m--; /* Just a dumb busy loop */
+ return(0);
+#endif /* MSLFTIME */
+#endif /* ATTSV */
+#endif /* NAP */
+#endif /* PROVX1 */
+#endif /* aegis */
+#endif /* CK_POLL */
+#endif /* SELECT */
+#endif /* BEOSORBEBOX */
+#endif /* USLEEP */
+#endif /* Plan9 */
+}
+
+/* R T I M E R -- Reset elapsed time counter */
+
+VOID
+rtimer() {
+ tcount = time( (time_t *) 0 );
+}
+
+
+/* G T I M E R -- Get current value of elapsed time counter in seconds */
+
+int
+gtimer() {
+ int x;
+ x = (int) (time( (time_t *) 0 ) - tcount);
+ debug(F101,"gtimer","",x);
+ return( (x < 0) ? 0 : x );
+}
+
+#ifdef GFTIMER
+/*
+ Floating-point timers. Require not only floating point support, but
+ also gettimeofday().
+*/
+static struct timeval tzero;
+
+VOID
+rftimer() {
+#ifdef GTODONEARG /* Account for Mot's definition */
+ (VOID) gettimeofday(&tzero);
+#else
+ (VOID) gettimeofday(&tzero, (struct timezone *)0);
+#endif /* GTODONEARG */
+}
+
+CKFLOAT
+gftimer() {
+ struct timeval tnow, tdelta;
+ CKFLOAT s;
+#ifdef DEBUG
+ char fpbuf[64];
+#endif /* DEBUG */
+#ifdef GTODONEARG /* Account for Mot's definition */
+ (VOID) gettimeofday(&tnow);
+#else
+ (VOID) gettimeofday(&tnow, (struct timezone *)0);
+#endif /* GTODONEARG */
+
+ tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
+ tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
+
+ if (tdelta.tv_usec < 0) {
+ tdelta.tv_sec--;
+ tdelta.tv_usec += 1000000;
+ }
+ s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
+ if (s < GFMINTIME)
+ s = GFMINTIME;
+#ifdef DEBUG
+ if (deblog) {
+ sprintf(fpbuf,"%f",s);
+ debug(F110,"gftimer",fpbuf,0);
+ }
+#endif /* DEBUG */
+ return(s);
+}
+#endif /* GFTIMER */
+
+/* Z T I M E -- Return asctime()-format date/time string */
+/*
+ NOTE: as a side effect of calling this routine, we can also set the
+ following two variables, giving the micro- and milliseconds (fractions of
+ seconds) of the clock time. Currently this is done only in BSD-based builds
+ that use gettimeofday(). When these variables are not filled in, they are
+ left with a value of -1L.
+*/
+static char asctmbuf[64];
+
+VOID
+ztime(s) char **s; {
+
+#ifdef GFTIMER
+/*
+ The gettimeofday() method, which also sets ztmsec and ztusec, works for
+ all GFTIMER builds. NOTE: ztmsec and ztusec are defined in ckcmai.c,
+ and extern declarations for them are in ckcdeb.h; thus they are
+ declared in this file by inclusion of ckcdeb.h.
+*/
+ char *asctime();
+ struct tm *localtime();
+ struct tm *tp;
+ ztmsec = -1L;
+ ztusec = -1L;
+
+ if (!s)
+ debug(F100,"ztime s==NULL","",0);
+
+#ifdef GTODONEARG
+ /* No 2nd arg in Motorola SV88 and some others */
+ if (gettimeofday(&tv) > -1)
+#else
+#ifndef COHERENT
+#ifdef PTX
+ if (gettimeofday(&tv,NULL) > -1)
+#else
+#ifdef NOTIMEZONE
+ if (gettimeofday(&tv, NULL) > -1) /* wonder what this does... */
+#else
+ if (gettimeofday(&tv, &tz) > -1)
+#endif /* NOTIMEZONE */
+#endif /* PTX */
+#endif /* COHERENT */
+#endif /* GTODONEARG */
+ { /* Fill in tm struct */
+ ztusec = tv.tv_usec; /* Microseconds */
+ ztmsec = ztusec / 1000L; /* Milliseconds */
+#ifdef HPUX9
+ {
+ time_t zz;
+ zz = tv.tv_sec;
+ tp = localtime(&zz); /* Convert to local time */
+ }
+#else
+#ifdef HPUX1000
+ {
+ time_t zz;
+ zz = tv.tv_sec;
+ tp = localtime(&zz);
+ }
+#else
+#ifdef LINUX
+ { /* avoid unaligned access trap on 64-bit platforms */
+ time_t zz;
+ zz = tv.tv_sec;
+ tp = localtime(&zz);
+ }
+#else
+#ifdef MACOSX
+ tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
+#else
+ tp = localtime(&tv.tv_sec);
+#endif /* MACOSX */
+#endif /* LINUX */
+#endif /* HPUX1000 */
+#endif /* HPUX9 */
+ if (s) {
+ char * s2;
+ s2 = asctime(tp); /* Convert result to ASCII string */
+ asctmbuf[0] = '\0';
+ if (s2) ckstrncpy(asctmbuf,s2,64);
+ *s = asctmbuf;
+ debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
+ }
+ }
+#else /* Not GFTIMER */
+
+#undef ZTIMEV7 /* Which systems need to use */
+#ifdef COHERENT /* old UNIX Version 7 way... */
+#define ZTIMEV7
+#endif /* COHERENT */
+#ifdef TOWER1
+#define ZTIMEV7
+#endif /* TOWER1 */
+#ifdef ANYBSD
+#ifndef BSD42
+#define ZTIMEV7
+#endif /* BSD42 */
+#endif /* ANYBSD */
+#ifdef V7
+#ifndef MINIX
+#define ZTIMEV7
+#endif /* MINIX */
+#endif /* V7 */
+#ifdef POSIX
+#define ZTIMEV7
+#endif /* POSIX */
+
+#ifdef HPUX1020
+/*
+ Prototypes are in <time.h>, included above.
+*/
+ time_t clock_storage;
+ clock_storage = time((void *) 0);
+ if (s) {
+ *s = ctime(&clock_storage);
+ debug(F110,"ztime: HPUX 10.20",*s,0);
+ }
+#else
+#ifdef ATTSV /* AT&T way */
+/* extern long time(); */ /* Theoretically these should */
+ char *ctime(); /* already been dcl'd in <time.h> */
+ time_t clock_storage;
+ clock_storage = time(
+#ifdef IRIX60
+ (time_t *)
+#else
+#ifdef BSD44
+ (time_t *)
+#else
+ (long *)
+#endif /* BSD44 */
+#endif /* IRIX60 */
+ 0 );
+ if (s) {
+ *s = ctime( &clock_storage );
+ debug(F110,"ztime: ATTSV",*s,0);
+ }
+#else
+#ifdef PROVX1 /* Venix 1.0 way */
+ int utime[2];
+ time(utime);
+ if (s) {
+ *s = ctime(utime);
+ debug(F110,"ztime: PROVX1",*s,0);
+ }
+#else
+#ifdef BSD42 /* 4.2BSD way */
+ char *asctime();
+ struct tm *localtime();
+ struct tm *tp;
+ gettimeofday(&tv, &tz);
+ ztusec = tv.tv_usec;
+ ztmsec = tv.tv_usec / 1000L;
+ tp = localtime(&tv.tv_sec);
+ if (s) {
+ *s = asctime(tp);
+ debug(F111,"ztime: BSD42",*s,ztusec);
+ }
+#else
+#ifdef MINIX /* MINIX way */
+#ifdef COMMENT
+ extern long time(); /* Already got these from <time.h> */
+ extern char *ctime();
+#endif /* COMMENT */
+ time_t utime[2];
+ time(utime);
+ if (s) {
+ *s = ctime(utime);
+ debug(F110,"ztime: MINIX",*s,0);
+ }
+#else
+#ifdef ZTIMEV7 /* The regular way */
+ char *asctime();
+ struct tm *localtime();
+ struct tm *tp;
+ long xclock; /* or unsigned long for BeBox? */
+ time(&xclock);
+ tp = localtime(&xclock);
+ if (s) {
+ *s = asctime(tp);
+ debug(F110,"ztime: ZTIMEV7",*s,0);
+ }
+#else /* Catch-all for others... */
+ if (s) {
+ *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
+ debug(F110,"ztime: catch-all",*s,0);
+ }
+#endif /* ZTIMEV7 */
+#endif /* MINIX */
+#endif /* BSD42 */
+#endif /* PROVX1 */
+#endif /* ATTSV */
+#endif /* HPUX1020 */
+#endif /* GFTIMER */
+}
+
+/* C O N G M -- Get console terminal modes. */
+
+/*
+ Saves initial console mode, and establishes variables for switching
+ between current (presumably normal) mode and other modes.
+ Should be called when program starts, but only after establishing
+ whether program is in the foreground or background.
+ Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
+*/
+int
+congm() {
+ int fd;
+ if (backgrd || !isatty(0)) { /* If in background. */
+ cgmf = -1; /* Don't bother, modes are garbage. */
+ return(-1);
+ }
+ if (cgmf > 0) return(0); /* Already did this. */
+ debug(F100,"congm getting modes","",0); /* Need to do it. */
+#ifdef aegis
+ ios_$inq_type_uid(ios_$stdin, conuid, st);
+ if (st.all != status_$ok) {
+ fprintf(stderr, "problem getting stdin objtype: ");
+ error_$print(st);
+ }
+ concrp = (conuid == mbx_$uid);
+ conbufn = 0;
+#endif /* aegis */
+
+#ifndef BEBOX
+ if ((fd = open(CTTNAM,2)) < 0) { /* Open controlling terminal */
+#ifdef COMMENT
+ fprintf(stderr,"Error opening %s\n", CTTNAM);
+ perror("congm");
+ return(-1);
+#else
+ fd = 0;
+#endif /* COMMENT */
+ }
+#else
+ fd = 0;
+#endif /* !BEBOX */
+#ifdef BSD44ORPOSIX
+ if (tcgetattr(fd,&ccold) < 0) return(-1);
+ if (tcgetattr(fd,&cccbrk) < 0) return(-1);
+ if (tcgetattr(fd,&ccraw) < 0) return(-1);
+#else
+#ifdef ATTSV
+ if (ioctl(fd,TCGETA,&ccold) < 0) return(-1);
+ if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
+ if (ioctl(fd,TCGETA,&ccraw) < 0) return(-1);
+#ifdef VXVE
+ cccbrk.c_line = 0; /* STTY line 0 for CDC VX/VE */
+ if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
+ ccraw.c_line = 0; /* STTY line 0 for CDC VX/VE */
+ if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
+#endif /* VXVE */
+#else
+#ifdef BELLV10
+ if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
+ if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
+ if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
+ debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
+#else
+ if (gtty(fd,&ccold) < 0) return(-1);
+ if (gtty(fd,&cccbrk) < 0) return(-1);
+ if (gtty(fd,&ccraw) < 0) return(-1);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#ifdef sony_news /* Sony NEWS */
+ if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
+ perror("congm error getting Kanji mode");
+ debug(F101,"congm error getting Kanji mode","",0);
+ km_con = -1; /* Make sure this stays undefined. */
+ return(-1);
+ }
+#endif /* sony_news */
+ if (fd > 0)
+ close(fd);
+ cgmf = 1; /* Flag that we got them. */
+ return(1);
+}
+
+
+static VOID
+congetbuf(x) int x; {
+ int n;
+ n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */
+ if (x > n) {
+ debug(F101,"congetbuf char loss","",x-n);
+ x = n;
+ }
+ x = read(0,conbufp,x);
+ conbufn += x;
+ debug(F111,"congetbuf readahead",conbuf,x);
+}
+
+
+/* C O N C B -- Put console in cbreak mode. */
+
+/* Returns 0 if ok, -1 if not */
+
+int
+#ifdef CK_ANSIC
+concb(char esc)
+#else
+concb(esc) char esc;
+#endif /* CK_ANSIC */
+/* concb */ {
+ int x, y = 0;
+ debug(F101,"concb constate","",constate);
+ debug(F101,"concb cgmf","",cgmf);
+ debug(F101,"concb backgrd","",backgrd);
+
+ if (constate == CON_CB)
+ return(0);
+
+ if (cgmf < 1) /* Did we get console modes yet? */
+ if (!backgrd) /* No, in background? */
+ congm(); /* No, try to get them now. */
+ if (cgmf < 1) /* Still don't have them? */
+ return(0); /* Give up. */
+ debug(F101,"concb ttyfd","",ttyfd);
+ debug(F101,"concb ttfdflg","",ttfdflg);
+#ifdef COMMENT
+ /* This breaks returning to prompt after protocol with "-l 0" */
+ /* Commented out July 1998 */
+ if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
+ return(0);
+#endif /* COMMENT */
+ x = isatty(0);
+ debug(F101,"concb isatty","",x);
+ if (!x) return(0); /* Only when running on real ttys */
+ debug(F101,"concb xsuspend","",xsuspend);
+ if (backgrd) /* Do nothing if in background. */
+ return(0);
+ escchr = esc; /* Make this available to other fns */
+ ckxech = 1; /* Program can echo characters */
+#ifdef aegis
+ conbufn = 0;
+ if (concrp) return(write(1, "\035\002", 2));
+ if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
+#endif /* aegis */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef Plan9
+ x = p9concb();
+#else
+#ifndef SVORPOSIX /* BSD, V7, etc */
+ debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
+ debug(F101,"concb stty CBREAK","",0);
+ cccbrk.sg_flags |= (CBREAK|CRMOD); /* Set to character wakeup, */
+ cccbrk.sg_flags &= ~ECHO; /* no echo. */
+ debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
+ errno = 0;
+/*
+ BSD stty() clears the console buffer. So if anything is waiting in it,
+ we have to read it now to avoid losing it.
+*/
+ x = conchk();
+ if (x > 0)
+ congetbuf(x);
+
+#ifdef BELLV10
+ x = ioctl(0,TIOCSETP,&cccbrk);
+#else
+ x = stty(0,&cccbrk);
+ debug(F101,"cccbrk.sg_flags concb x","", x);
+#endif /* BELLV10 */
+#else /* Sys V and POSIX */
+#ifndef OXOS
+ debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
+#ifdef QNX
+ /* Don't mess with IEXTEN */
+ cccbrk.c_lflag &= ~(ICANON|ECHO);
+#else
+#ifdef COHERENT
+ cccbrk.c_lflag &= ~(ICANON|ECHO);
+#else
+ cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
+#endif /* COHERENT */
+#endif /* QNX */
+ cccbrk.c_lflag |= ISIG; /* Allow signals in command mode. */
+ cccbrk.c_iflag |= IGNBRK; /* But ignore BREAK signal */
+ cccbrk.c_iflag &= ~BRKINT;
+
+#else /* OXOS */
+ debug(F100,"concb OXOS is defined","",0);
+ cccbrk.c_lflag &= ~(ICANON|ECHO);
+ cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+#ifdef COMMENT
+/*
+ Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
+ array reference is out of bounds. It's only a debug() call so who needs it.
+*/
+#ifdef VSUSP
+ debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
+#endif /* VSUSP */
+#endif /* COMMENT */
+#ifndef VINTR
+ debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
+ cccbrk.c_cc[0] = 003; /* Interrupt char is Control-C */
+#else
+ debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
+ cccbrk.c_cc[VINTR] = 003;
+#endif /* VINTR */
+#ifndef VQUIT
+ cccbrk.c_cc[1] = escchr; /* escape during packet modes */
+#else
+ cccbrk.c_cc[VQUIT] = escchr;
+#endif /* VQUIT */
+#ifndef VEOF
+ cccbrk.c_cc[4] = 1;
+#else
+#ifndef OXOS
+#ifdef VMIN
+ cccbrk.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ cccbrk.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+#ifdef ZILOG
+ cccbrk.c_cc[5] = 0;
+#else
+#ifndef VEOL
+ cccbrk.c_cc[5] = 1;
+#else
+#ifndef OXOS
+#ifdef VTIME
+ cccbrk.c_cc[VTIME] = 1;
+#endif /* VTIME */
+#else /* OXOS */
+ cccbrk.c_time = 1;
+#endif /* OXOS */
+#endif /* VEOL */
+#endif /* ZILOG */
+ errno = 0;
+#ifdef BSD44ORPOSIX /* Set new modes */
+ x = tcsetattr(0,TCSADRAIN,&cccbrk);
+#else /* ATTSV */ /* or the POSIX way */
+ x = ioctl(0,TCSETAW,&cccbrk); /* the Sys V way */
+#endif /* BSD44ORPOSIX */
+#endif /* SVORPOSIX */
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+ debug(F101,"concb x","",x);
+ debug(F101,"concb errno","",errno);
+
+#ifdef V7
+#ifndef MINIX
+ if (kmem[CON] < 0) {
+ qaddr[CON] = initrawq(0);
+ if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
+ fprintf(stderr, "Can't read /dev/kmem in concb.\n");
+ perror("/dev/kmem");
+ exit(1);
+ }
+ }
+#endif /* MINIX */
+#endif /* V7 */
+#endif /* Plan9 */
+
+ if (x > -1)
+ constate = CON_CB;
+
+ debug(F101,"concb returns","",x);
+ return(x);
+}
+
+/* C O N B I N -- Put console in binary mode */
+
+/* Returns 0 if ok, -1 if not */
+
+int
+#ifdef CK_ANSIC
+conbin(char esc)
+#else
+conbin(esc) char esc;
+#endif /* CK_ANSIC */
+/* conbin */ {
+
+ int x;
+
+ debug(F101,"conbin constate","",constate);
+
+ if (constate == CON_BIN)
+ return(0);
+
+ if (!isatty(0)) return(0); /* only for real ttys */
+ congm(); /* Get modes if necessary. */
+ debug(F100,"conbin","",0);
+ escchr = esc; /* Make this available to other fns */
+ ckxech = 1; /* Program can echo characters */
+#ifdef aegis
+ conbufn = 0;
+ if (concrp) return(write(1, "\035\002", 2));
+ if (conuid == input_pad_$uid) {
+ pad_$raw(ios_$stdin, st);
+ return(0);
+ }
+#endif /* aegis */
+
+#ifdef COHERENT
+#define SVORPOSIX
+#endif /* COHERENT */
+
+#ifdef Plan9
+ return p9conbin();
+#else
+#ifdef SVORPOSIX
+#ifndef OXOS
+#ifdef QNX
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
+#else
+#ifdef COHERENT
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
+#else
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
+#endif /* COHERENT */
+#endif /* QNX */
+#else /* OXOS */
+ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
+#endif /* OXOS */
+ ccraw.c_iflag |= IGNPAR;
+/*
+ Note that for terminal sessions we disable Xon/Xoff flow control to allow
+ the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
+ transfers to work when C-Kermit is in the middle, etc. Hardware flow
+ control, if in use, is not affected.
+*/
+#ifdef ATTSV
+#ifdef BSD44
+ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
+ |INPCK|ISTRIP);
+#else
+ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
+ |INPCK|ISTRIP);
+#endif /* BSD44 */
+#else /* POSIX */
+ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
+#endif /* ATTSV */
+ ccraw.c_oflag &= ~OPOST;
+#ifdef COMMENT
+/*
+ WHAT THE HECK WAS THIS FOR?
+ The B9600 setting (obviously) prevents CONNECT from working at any
+ speed other than 9600 when you are logged in to the 7300 on a serial
+ line. Maybe some of the other flags are necessary -- if so, put back
+ the ones that are needed. This code is supposed to work the same, no
+ matter whether you are logged in to the 7300 on the real console device,
+ or through a serial port.
+*/
+#ifdef ATT7300
+ ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
+#endif /* ATT7300 */
+#endif /* COMMENT */
+
+/*** Kermit used to put the console in 8-bit raw mode, but some users have
+ *** pointed out that this should not be done, since some sites actually
+ *** use terminals with parity settings on their Unix systems, and if we
+ *** override the current settings and stop doing parity, then their terminals
+ *** will display blotches for characters whose parity is wrong. Therefore,
+ *** the following two lines are commented out (Larry Afrin, Clemson U):
+ ***
+ *** ccraw.c_cflag &= ~(PARENB|CSIZE);
+ *** ccraw.c_cflag |= (CS8|CREAD);
+ ***
+ *** Sys III/V sites that have trouble with this can restore these lines.
+ ***/
+#ifndef VINTR
+ ccraw.c_cc[0] = 003; /* Interrupt char is Ctrl-C */
+#else
+ ccraw.c_cc[VINTR] = 003;
+#endif /* VINTR */
+#ifndef VQUIT
+ ccraw.c_cc[1] = escchr; /* Escape during packet mode */
+#else
+ ccraw.c_cc[VQUIT] = escchr;
+#endif /* VQUIT */
+#ifndef VEOF
+ ccraw.c_cc[4] = 1;
+#else
+#ifndef OXOS
+#ifdef VMIN
+ ccraw.c_cc[VMIN] = 1;
+#endif /* VMIN */
+#else /* OXOS */
+ ccraw.c_min = 1;
+#endif /* OXOS */
+#endif /* VEOF */
+
+#ifdef ZILOG
+ ccraw.c_cc[5] = 0;
+#else
+#ifndef VEOL
+ ccraw.c_cc[5] = 1;
+#else
+#ifndef OXOS
+#ifdef VTIME
+ ccraw.c_cc[VTIME] = 1;
+#endif /* VTIME */
+#else /* OXOS */
+ ccraw.c_time = 1;
+#endif /* OXOS */
+#endif /* VEOL */
+#endif /* ZILOG */
+
+#ifdef BSD44ORPOSIX
+ x = tcsetattr(0,TCSADRAIN,&ccraw); /* Set new modes. */
+#else
+ x = ioctl(0,TCSETAW,&ccraw);
+#endif /* BSD44ORPOSIX */
+#else /* Berkeley, etc. */
+ x = conchk(); /* Because stty() is destructive */
+ if (x > 0)
+ congetbuf(x);
+ ccraw.sg_flags |= (RAW|TANDEM); /* Set rawmode, XON/XOFF (ha) */
+ ccraw.sg_flags &= ~(ECHO|CRMOD); /* Set char wakeup, no echo */
+#ifdef BELLV10
+ x = ioctl(0,TIOCSETP,&ccraw);
+#else
+ x = stty(0,&ccraw);
+#endif /* BELLV10 */
+#endif /* SVORPOSIX */
+#endif /* Plan9 */
+
+ if (x > -1)
+ constate = CON_BIN;
+
+ debug(F101,"conbin returns","",x);
+ return(x);
+
+#ifdef COHERENT
+#undef SVORPOSIX
+#endif /* COHERENT */
+
+}
+
+
+/* C O N R E S -- Restore the console terminal */
+
+int
+conres() {
+ int x;
+ debug(F101,"conres cgmf","",cgmf);
+ debug(F101,"conres constate","",constate);
+
+ if (cgmf < 1) /* Do nothing if modes unchanged */
+ return(0);
+ if (constate == CON_RES)
+ return(0);
+
+ if (!isatty(0)) return(0); /* only for real ttys */
+ debug(F100,"conres isatty ok","",0);
+ ckxech = 0; /* System should echo chars */
+
+#ifdef aegis
+ conbufn = 0;
+ if (concrp) return(write(1, "\035\001", 2));
+ if (conuid == input_pad_$uid) {
+ pad_$cooked(ios_$stdin, st);
+ constate = CON_RES;
+ return(0);
+ }
+#endif /* aegis */
+
+#ifdef Plan9
+ p9conres();
+#else
+#ifdef BSD44ORPOSIX
+ debug(F100,"conres restoring tcsetattr","",0);
+ x = tcsetattr(0,TCSADRAIN,&ccold);
+#else
+#ifdef ATTSV
+ debug(F100,"conres restoring ioctl","",0);
+ x = ioctl(0,TCSETAW,&ccold);
+#else /* BSD, V7, and friends */
+#ifdef sony_news /* Sony NEWS */
+ if (km_con != -1)
+ ioctl(0,TIOCKSET,&km_con); /* Restore console Kanji mode */
+#endif /* sony_news */
+ msleep(100);
+ debug(F100,"conres restoring stty","",0);
+ x = conchk(); /* Because stty() is destructive */
+ if (x > 0)
+ congetbuf(x);
+#ifdef BELLV10
+ x = ioctl(0,TIOCSETP,&ccold);
+#else
+ x = stty(0,&ccold);
+#endif /* BELLV10 */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+#endif /* Plan9 */
+ if (x > -1)
+ constate = CON_RES;
+
+ debug(F101,"conres returns","",x);
+ return(x);
+}
+
+/* C O N O C -- Output a character to the console terminal */
+
+int
+#ifdef CK_ANSIC
+conoc(char c)
+#else
+conoc(c) char c;
+#endif /* CK_ANSIC */
+/* conoc */ {
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttoc(c));
+
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(&c,1);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return conwrite(&c,1);
+#else
+ return(write(1,&c,1));
+#endif /* Plan9 */
+}
+
+/* C O N X O -- Write x characters to the console terminal */
+
+int
+conxo(x,s) int x; char *s; {
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttol((CHAR *)s,x));
+
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(s,x);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return(conwrite(s,x));
+#else
+ return(write(1,s,x));
+#endif /* Plan9 */
+}
+
+/* C O N O L -- Write a line to the console terminal */
+
+int
+conol(s) char *s; {
+ int len;
+ if (!s) s = ""; /* Always do this! */
+ len = strlen(s);
+ if (len == 0)
+ return(0);
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttol((CHAR *)s,len));
+
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
+ if (nxpacket < len) {
+ if (xpacket) {
+ free(xpacket);
+ xpacket = NULL;
+ nxpacket = 0;
+ }
+ len = len > 10240 ? len : 10240;
+ xpacket = (CHAR *)malloc(len);
+ if (!xpacket) {
+ fprintf(stderr,"ttol malloc failure\n");
+ return(-1);
+ } else
+ nxpacket = len;
+ }
+ memcpy(xpacket,s,len);
+ s = (char *)xpacket;
+ ck_tn_encrypt(s,len);
+ }
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return(conwrite(s,len));
+#else
+ return(write(1,s,len));
+#endif /* Plan9 */
+}
+
+/* C O N O L A -- Write an array of lines to the console terminal */
+
+int
+conola(s) char *s[]; {
+ char * p;
+ int i, x;
+
+
+ if (!s) return(0);
+ for (i = 0; ; i++) {
+ p = s[i];
+ if (!p) p = ""; /* Let's not dump core shall we? */
+ if (!*p)
+ break;
+#ifdef IKSD
+ if (inserver && !local)
+ x = ttol((CHAR *)p,(int)strlen(p));
+ else
+#endif /* IKSD */
+ x = conol(p);
+ if (x < 0)
+ return(-1);
+ }
+ return(0);
+}
+
+/* C O N O L L -- Output a string followed by CRLF */
+
+int
+conoll(s) char *s; {
+ CHAR buf[3];
+ buf[0] = '\r';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ if (!s) s = "";
+
+#ifdef IKSD
+ if (inserver && !local) {
+ if (*s) ttol((CHAR *)s,(int)strlen(s));
+ return(ttol(buf,2));
+ }
+#endif /* IKSD */
+
+ if (*s) conol(s);
+#ifdef IKSD
+#ifdef CK_ENCRYPTION
+ if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt((char *)buf,2);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+
+#ifdef Plan9
+ return(conwrite(buf, 2));
+#else
+ return(write(1,buf,2));
+#endif /* Plan9 */
+}
+
+/* C O N C H K -- Return how many characters available at console */
+/*
+ We could also use select() here to cover a few more systems that are not
+ covered by any of the following, e.g. HP-UX 9.0x on the model 800.
+*/
+int
+conchk() {
+ static int contyp = 0; /* +1 for isatty, -1 otherwise */
+
+ if (contyp == 0) /* This prevents unnecessary */
+ contyp = (isatty(0) ? 1 : -1); /* duplicated calls to isatty() */
+ debug(F101,"conchk contyp","",contyp);
+ if (backgrd || (contyp < 0))
+ return(0);
+
+#ifdef aegis
+ if (conbufn > 0) return(conbufn); /* use old count if nonzero */
+
+ /* read in more characters */
+ conbufn = ios_$get(ios_$stdin,
+ ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
+ if (st.all != status_$ok) conbufn = 0;
+ conbufp = conbuf;
+ return(conbufn);
+#else
+#ifdef IKSD
+ if (inserver && !local)
+ return(in_chk(1,ttyfd));
+ else
+#endif /* IKSD */
+ return(in_chk(0,0));
+#endif /* aegis */
+}
+
+/* C O N I N C -- Get a character from the console */
+/*
+ Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
+ read. Upon success, returns the character. Upon failure, returns -1.
+ A timed read that does not complete within the timeout period returns -2.
+*/
+int
+coninc(timo) int timo; {
+ int n = 0; CHAR ch;
+ int xx;
+
+ if (conbufn > 0) { /* If something already buffered */
+ --conbufn;
+ return((unsigned)(*conbufp++ & 0xff));
+ }
+
+ errno = 0; /* Clear this */
+#ifdef IKSD
+ if (inserver && !local) {
+ xx = ttinc(timo);
+ if (xx < 0)
+ return(ttinctimo ? -2 : -1);
+ else
+ return(xx);
+ }
+#endif /* IKSD */
+
+#ifdef aegis /* Apollo Aegis only... */
+ debug(F101,"coninc timo","",timo);
+ fflush(stdout);
+ if (conchk() > 0) {
+ --conbufn;
+ return((unsigned)(*conbufp++ & 0xff));
+ }
+#endif /* aegis */
+
+#ifdef TTLEBUF
+ if (
+#ifdef IKSD
+ inserver &&
+#endif /* IKSD */
+ !xlocal
+ ) {
+ if (ttpush >= 0) {
+ debug(F111,"ttinc","ttpush",ttpush);
+ ch = ttpush;
+ ttpush = -1;
+ return(ch);
+ }
+ if (le_data) {
+ if (le_getchar(&ch) > 0) {
+ debug(F111,"ttinc LocalEchoInBuf","ch",ch);
+ return(ch);
+ }
+ }
+ }
+#endif /* TTLEBUF */
+
+ if (timo <= 0) { /* Untimed, blocking read. */
+ while (1) { /* Keep trying till we get one. */
+ n = read(0, &ch, 1); /* Read a character. */
+ if (n == 0) continue; /* Shouldn't happen. */
+ if (n > 0) { /* If read was successful, */
+#ifdef IKSD
+#ifdef CK_ENCRYPTION
+ debug(F100,"coninc decrypt 1","",0);
+ if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt((char *)&ch,1);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+ return((unsigned)(ch & 0xff)); /* return the character. */
+ }
+
+/* Come here if read() returned an error. */
+
+ debug(F101, "coninc(0) errno","",errno); /* Log the error. */
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifdef CIE /* CIE Regulus has no EINTR symbol? */
+#ifndef EINTR
+#define EINTR 4
+#endif /* EINTR */
+#endif /* CIE */
+/*
+ This routine is used for several different purposes. In CONNECT mode, it is
+ used to do an untimed, blocking read from the keyboard in the lower CONNECT
+ fork. During local-mode file transfer, it reads a character from the
+ console to interrupt the file transfer (like A for a status report, X to
+ cancel a file, etc). Obviously, we don't want the reads in the latter case
+ to be blocking, or the file transfer would stop until the user typed
+ something. Unfortunately, System V does not allow the console device input
+ buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
+ used instead. During local-mode file transfer, the SIGQUIT signal is armed
+ and trapped by esctrp(), and this routine pretends to have read the quit
+ character from the keyboard normally. But, kludge or no kludge, the read()
+ issued by this command, under System V only, can fail if a signal -- ANY
+ signal -- is caught while the read is pending. This can occur not only when
+ the user types the quit character, but also during telnet negotiations, when
+ the lower CONNECT fork signals the upper one about an echoing mode change.
+ When this happens, we have to post the read() again. This is apparently not
+ a problem in BSD-based UNIX versions.
+*/
+ if (errno == EINTR) /* Read interrupted. */
+ if (conesc) { /* If by SIGQUIT, */
+ conesc = 0; /* the conesc variable is set, */
+ return(escchr); /* so return the escape character. */
+ } else continue; /* By other signal, try again. */
+#else
+/*
+ This might be dangerous, but let's do this on non-System V versions too,
+ since at least one SunOS 4.1.2 user complains of immediate disconnections
+ upon first making a TELNET connection.
+*/
+ if (errno == EINTR) /* Read interrupted. */
+ continue;
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ if (errno == EINTR) /* Read interrupted. */
+ continue;
+#endif /* OXOS */
+ return(-1); /* Error */
+ }
+ }
+#ifdef DEBUG
+ if (deblog && timo <= 0) {
+ debug(F100,"coninc timeout logic error","",0);
+ timo = 1;
+ }
+#endif /* DEBUG */
+
+/* Timed read... */
+
+ saval = signal(SIGALRM,timerh); /* Set up timeout handler. */
+ xx = alarm(timo); /* Set the alarm. */
+ debug(F101,"coninc alarm set","",timo);
+ if (
+#ifdef CK_POSIX_SIG
+ sigsetjmp(sjbuf,1)
+#else
+ setjmp(sjbuf)
+#endif /* CK_POSIX_SIG */
+ ) /* The read() timed out. */
+ n = -2; /* Code for timeout. */
+ else
+ n = read(0, &ch, 1);
+ ttimoff(); /* Turn off timer */
+ if (n > 0) { /* Got character OK. */
+#ifdef IKSD
+#ifdef CK_ENCRYPTION
+ debug(F100,"coninc decrypt 2","",0);
+ if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
+ ck_tn_decrypt((char *)&ch,1);
+#endif /* CK_ENCRYPTION */
+#endif /* IKSD */
+ return((unsigned)(ch & 0xff)); /* Return it. */
+ }
+/*
+ read() returned an error. Same deal as above, but without the loop.
+*/
+ debug(F101, "coninc(timo) n","",n);
+ debug(F101, "coninc(timo) errno","",errno);
+#ifndef OXOS
+#ifdef SVORPOSIX
+ if (n == -1 && errno == EINTR && conesc != 0) {
+ conesc = 0;
+ return(escchr); /* User entered escape character. */
+ }
+#endif /* SVORPOSIX */
+ if (n == 0 && errno > 0) { /* It's an error */
+ return(-1);
+ }
+#endif /* ! OXOS */
+ return(n);
+}
+
+/* C O N G K S -- Console Get Keyboard Scancode */
+
+#ifndef congks
+/*
+ This function needs to be filled in with the various system-dependent
+ system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
+ keyboard scan code. Unfortunately there aren't any.
+*/
+int
+congks(timo) int timo; {
+
+#ifdef IKSD
+ if (inserver && !local)
+ return(ttinc(timo));
+#endif /* IKSD */
+
+ return(coninc(timo));
+}
+#endif /* congks */
+
+#ifdef ATT7300
+
+/* A T T D I A L -- Dial up the remote system using internal modem
+ * Purpose: to open and dial a number on the internal modem available on the
+ * ATT7300 UNIX PC. Written by Joe Doupnik. Superceeds version written by
+ * Richard E. Hill, Dickinson, TX. which employed dial(3c).
+ * Uses information in <sys/phone.h> and our status int attmodem.
+ */
+attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
+ char *telnum;
+
+ attmodem &= ~ISMODEM; /* modem not in use yet */
+ /* Ensure O_NDELAY is set, else i/o traffic hangs */
+ /* We turn this flag off once the dial is complete */
+ fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
+
+ /* Condition line, check availability & DATA mode, turn on speaker */
+ if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
+ printf("cannot access phone\n");
+ ttclos(0);
+ return (-2);
+ }
+ ioctl(ttyfd,PIOCGETP,&dialer); /* get phone dialer parameters */
+
+ if (dialer.c_lineparam & VOICE) { /* phone must be in DATA mode */
+ printf(" Should not dial with modem in VOICE mode.\n");
+ printf(" Exit Kermit, switch to DATA and retry call.\n");
+ ttclos(0);
+ return (-2);
+ }
+#ifdef ATTTONED /* Old way, tone dialing only. */
+ dialer.c_lineparam = DATA | DTMF; /* Dial with tones, */
+ dialer.c_lineparam &= ~PULSE; /* not with pulses. */
+#else
+ /* Leave current pulse/tone state alone. */
+ /* But what about DATA? Add it back if you have trouble. */
+ /* sys/phone says you get DATA automatically by opening device RDWR */
+#endif
+ dialer.c_waitdialtone = 5; /* wait 5 sec for dialtone */
+#ifdef COMMENT
+ dialer.c_feedback = SPEAKERON|NORMSPK|RINGON; /* control speaker */
+#else
+ /* sys/phone says RINGON used only for incoming voice calls */
+ dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
+ dialer.c_feedback |= SPEAKERON|NORMSPK;
+#endif
+ dialer.c_waitflash = 500; /* 0.5 sec flash hook */
+ if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) { /* set phone parameters */
+ printf("Cannot set modem characteristics\n");
+ ttclos(0);
+ return (-2);
+ }
+ ioctl(ttyfd,PIOCRECONN,0); /* Turns on speaker for pulse */
+
+#ifdef COMMENT
+ fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
+line_status:%o feedback:%o\n",
+ dialer.c_lineparam, dialer.c_waitdialtone,
+ dialer.c_linestatus, dialer.c_feedback);
+#endif
+
+ attmodem |= ISMODEM; /* modem is now in-use */
+ sleep(1);
+ for (telnum = telnbr; *telnum != '\0'; telnum++) /* dial number */
+#ifdef ATTTONED
+ /* Tone dialing only */
+ if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
+ perror("Error in dialing");
+ ttclos(0);
+ return(-2);
+ }
+#else /* Allow Pulse or Tone dialing */
+ switch (*telnum) {
+ case 't': case 'T': case '%': /* Tone dialing requested */
+ dialer.c_lineparam |= DTMF;
+ dialer.c_lineparam &= ~PULSE;
+ if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
+ printf("Cannot set modem to tone dialing\n");
+ ttclos(0);
+ return(-2);
+ }
+ break;
+ case 'd': case 'D': case 'p': case 'P': case '^':
+ dialer.c_lineparam |= PULSE;
+ dialer.c_lineparam &= ~DTMF;
+ if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
+ printf("Cannot set modem to pulse dialing\n");
+ ttclos(0);
+ return(-2);
+ }
+ break;
+ default:
+ if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
+ perror("Dialing error");
+ ttclos(0);
+ return(-2);
+ }
+ break;
+ }
+#endif
+
+ ioctl(ttyfd,PIOCDIAL,"@"); /* terminator for data call */
+ do { /* wait for modems to Connect */
+ if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
+ perror("Cannot get modems to connect");
+ ttclos(0);
+ return(-2);
+ }
+ } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
+ /* Turn off O_NDELAY flag now. */
+ fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
+ signal(SIGHUP, sighup); /* hangup on loss of carrier */
+ return(0); /* return success */
+}
+
+/*
+ Offgetty, ongetty functions. These function get the 'getty(1m)' off
+ and restore it to the indicated line. Shell's return codes are:
+ 0: Can't do it. Probably a user logged on.
+ 1: No need. No getty on that line.
+ 2: Done, you should restore the getty when you're done.
+ DOGETY System(3), however, returns them as 0, 256, 512, respectively.
+ Thanks to Kevin O'Gorman, Anarm Software Systems.
+
+ getoff.sh looks like: geton.sh looks like:
+ setgetty $1 0 setgetty $1 1
+ err=$? exit $?
+ sleep 2
+ exit $err
+*/
+
+/* O F F G E T T Y -- Turn off getty(1m) for the communications tty line
+ * and get status so it can be restarted after the line is hung up.
+ */
+int
+offgetty(ttname) char *ttname; {
+ char temp[30];
+ while (*ttname != '\0') ttname++; /* seek terminator of path */
+ ttname -= 3; /* get last 3 chars of name */
+ sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
+ return(zsyscmd(temp));
+}
+
+/* O N G E T T Y -- Turn on getty(1m) for the communications tty line */
+
+int
+ongetty(ttname) char *ttname; {
+ char temp[30];
+ while (*ttname != '\0') ttname++; /* comms tty path name */
+ ttname -= 3;
+ sprintf(temp,"/usr/bin/geton.sh %s",ttname);
+ return(zsyscmd(temp));
+}
+#endif /* ATT7300 */
+
+/* T T S C A R R -- Set ttcarr variable, controlling carrier handling.
+ *
+ * 0 = Off: Always ignore carrier. E.g. you can connect without carrier.
+ * 1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
+ * 2 = Auto: For "modem direct": The same as "Off".
+ * For real modem types: Heed carrier during connect, but ignore
+ * it anytime else. Compatible with pre-5A C-Kermit versions.
+ *
+ * As you can see, this setting does not affect dialing, which always ignores
+ * carrier (unless there is some special exception for some modem type). It
+ * does affect ttopen() if it is set before ttopen() is used. This setting
+ * takes effect on the next call to ttopen()/ttpkt()/ttvt(). And they are
+ * (or should be) always called before any communications is tried, which
+ * means that, practically speaking, the effect is immediate.
+ *
+ * Of course, nothing of this applies to remote mode (xlocal = 0).
+ *
+ * Someone has yet to uncover how to manipulate the carrier in the BSD
+ * environment (or any non-termio using environment). Until that time, this
+ * will simply be a no-op for BSD.
+ *
+ * Note that in previous versions, the carrier was most often left unchanged
+ * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX. This
+ * has changed. Now it is controlled by ttcarr in conjunction with these
+ * modes.
+ */
+int
+ttscarr(carrier) int carrier; {
+ ttcarr = carrier;
+ debug(F101, "ttscarr","",ttcarr);
+ return(ttcarr);
+}
+
+/* C A R R C T L -- Set tty modes for carrier treatment.
+ *
+ * Sets the appropriate bits in a termio or sgttyb struct for carrier control
+ * (actually, there are no bits in sgttyb for that), or performs any other
+ * operations needed to control this on the current system. The function does
+ * not do the actual TCSETA or stty, since often we want to set other bits too
+ * first. Don't call this function when xlocal is 0, or the tty is not opened.
+ *
+ * We don't know how to do anything like carrier control on non-ATTSV systems,
+ * except, apparently, ultrix. See above. It is also known that this doesn't
+ * have much effect on a Xenix system. For Xenix, one should switch back and
+ * forth between the upper and lower case device files. Maybe later.
+ * Presently, Xenix will stick to the mode it was opened with.
+ *
+ * carrier: 0 = ignore carrier, 1 = require carrier.
+ * The current state is saved in curcarr, and checked to save labour.
+ */
+#ifdef SVORPOSIX
+int
+#ifdef BSD44ORPOSIX
+carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
+#else /* ATTSV */
+carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
+#endif /* BSD44ORPOSIX */
+/* carrctl */ {
+ debug(F101, "carrctl","",carrier);
+ if (carrier)
+ ttpar->c_cflag &= ~CLOCAL;
+ else
+ ttpar->c_cflag |= CLOCAL;
+ return(0);
+}
+#else /* Berkeley, V7, et al... */
+int
+carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
+ debug(F101, "carrctl","",carrier);
+ if (carrier == curcarr)
+ return(0);
+ curcarr = carrier;
+#ifdef ultrix
+#ifdef COMMENT
+/*
+ Old code from somebody at DEC that tends to get stuck, time out, etc.
+*/
+ if (carrier) {
+ ioctl(ttyfd, TIOCMODEM, &temp);
+ ioctl(ttyfd, TIOCHPCL, 0);
+ } else {
+ /* (According to the manuals, TIOCNCAR should be preferred */
+ /* over TIOCNMODEM...) */
+ ioctl(ttyfd, TIOCNMODEM, &temp);
+ }
+#else
+/*
+ New code from Jamie Watson that, he says, eliminates the problems.
+*/
+ if (carrier) {
+ ioctl(ttyfd, TIOCCAR);
+ ioctl(ttyfd, TIOCHPCL);
+ } else {
+ ioctl(ttyfd, TIOCNCAR);
+ }
+#endif /* COMMENT */
+#endif /* ultrix */
+ return(0);
+}
+#endif /* SVORPOSIX */
+
+
+/* T T G M D M -- Get modem signals */
+/*
+ Looks for RS-232 modem signals, and returns those that are on in as its
+ return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
+ Returns:
+ -3 Not implemented
+ -2 if the communication device does not have modem control (e.g. telnet)
+ -1 on error.
+ >= 0 on success, with a bit mask containing the modem signals that are on.
+*/
+
+/*
+ Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
+ modem control, namely the TIOCMGET ioctl.
+*/
+
+#ifdef BSD43
+#define K_MDMCTL
+#endif /* BSD43 */
+
+#ifdef SUNOS4
+#define K_MDMCTL
+#endif /* SUNOS4 */
+
+/*
+ SCO OpenServer R5.0.4. The TIOCMGET definition is hardwired in because it
+ is skipped in termio.h when _POSIX_SOURCE is defined. But _POSIX_SOURCE
+ must be defined in order to get the high serial speeds that are new to
+ 5.0.4. However, the regular SCO drivers do not implement TIOCMGET, so the
+ ioctl() returns -1 with errno 22 (invalid function). But third-party
+ drivers, e.g. for Digiboard, do implement it, and so it should work on ports
+ driven by those drivers.
+*/
+#ifdef SCO_OSR504
+#ifndef TIOCMGET
+#define TIOCMGET (('t'<<8)|29)
+#endif /* TIOCMGET */
+#endif /* SCO_OSR504 */
+
+#ifdef CK_SCOV5
+/* Because POSIX strictness in <sys/termio.h> won't let us see these. */
+#ifndef TIOCM_DTR
+#define TIOCM_DTR 0x0002 /* data terminal ready */
+#define TIOCM_RTS 0x0004 /* request to send */
+#define TIOCM_CTS 0x0020 /* clear to send */
+#define TIOCM_CAR 0x0040 /* carrier detect */
+#define TIOCM_RNG 0x0080 /* ring */
+#define TIOCM_DSR 0x0100 /* data set ready */
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+#endif /* TIOCM_DTR */
+#endif /* CK_SCOV5 */
+
+#ifdef QNX
+#define K_MDMCTL
+#else
+#ifdef TIOCMGET
+#define K_MDMCTL
+#endif /* TIOCMGET */
+#endif /* QNX */
+/*
+ "A serial communication program that can't read modem signals
+ is like a car without windows."
+*/
+int
+ttgmdm() {
+
+#ifdef QNX
+#include <sys/qioctl.h>
+
+ unsigned long y, mdmbits[2];
+ int x, z = 0;
+
+ if (xlocal && ttyfd < 0)
+ return(-1);
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ mdmbits[0] = 0L;
+ mdmbits[1] = 0L;
+/*
+ * From <sys/qioctl.h>:
+ *
+ * SERIAL devices (all Dev.ser versions)
+ * 0 : DTR 8 = Data Bits 0 16 - reserved 24 - reserved
+ * 1 : RTS 9 = Data Bits 1 17 - reserved 25 - reserved
+ * 2 = Out 1 10 = Stop Bits 18 - reserved 26 - reserved
+ * 3 = Int Enable 11 = Par Enable 19 - reserved 27 - reserved
+ * 4 = Loop 12 = Par Even 20 = CTS 28 - reserved
+ * 5 - reserved 13 = Par Stick 21 = DSR 29 - reserved
+ * 6 - reserved 14 : Break 22 = RI 30 - reserved
+ * 7 - reserved 15 = 0 23 = CD 31 - reserved
+ */
+ errno = 0;
+ x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
+ debug(F101,"ttgmdm qnx_ioctl","",x);
+ debug(F101,"ttgmdm qnx_ioctl errno","",errno);
+ if (!x) {
+ debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
+ debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
+ y = mdmbits[0];
+ if (y & 0x000001L) z |= BM_DTR; /* Bit 0 */
+ if (y & 0x000002L) z |= BM_RTS; /* Bit 1 */
+ if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */
+ if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */
+ if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */
+ if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */
+ debug(F101,"ttgmdm qnx result","",z);
+ debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
+ gotsigs = 1;
+ return(z);
+ } else return(-1);
+#else /* QNX */
+#ifdef HPUX /* HPUX has its own way */
+ int x, z;
+
+#ifdef HPUX10 /* Modem flag word */
+ mflag y; /* mflag typedef'd in <sys/modem.h> */
+#else
+#ifdef HPUX9
+ mflag y;
+#else
+#ifdef HPUX8
+ mflag y;
+#else
+ unsigned long y; /* Not sure about pre-8.0... */
+#endif /* HPUX8 */
+#endif /* HPUX9 */
+#endif /* HPUX10 */
+
+ if (xlocal && ttyfd < 0)
+ return(-1);
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ if (xlocal) /* Get modem signals */
+ x = ioctl(ttyfd,MCGETA,&y);
+ else
+ x = ioctl(0,MCGETA,&y);
+ if (x < 0) return(-1);
+ debug(F101,"ttgmdm","",y);
+
+ z = 0; /* Initialize return value */
+
+/* Now set bits for each modem signal that is reported to be on. */
+
+#ifdef MCTS
+ /* Clear To Send */
+ debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
+ if (y & MCTS) z |= BM_CTS;
+#endif
+#ifdef MDSR
+ /* Data Set Ready */
+ debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
+ if (y & MDSR) z |= BM_DSR;
+#endif
+#ifdef MDCD
+ /* Carrier */
+ debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
+ if (y & MDCD) z |= BM_DCD;
+#endif
+#ifdef MRI
+ /* Ring Indicate */
+ debug(F101,"ttgmdm HPUX RI","",y & MRI);
+ if (y & MRI) z |= BM_RNG;
+#endif
+#ifdef MDTR
+ /* Data Terminal Ready */
+ debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
+ if (y & MDTR) z |= BM_DTR;
+#endif
+#ifdef MRTS
+ /* Request To Send */
+ debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
+ if (y & MRTS) z |= BM_RTS;
+#endif
+ gotsigs = 1;
+ return(z);
+
+#else /* ! HPUX */
+
+#ifdef K_MDMCTL
+/*
+ Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
+ If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
+ are needed.
+*/
+#ifndef TIOCMGET
+#include <sys/ttycom.h>
+#endif /* TIOCMGET */
+
+ int x, y, z;
+
+ debug(F100,"ttgmdm K_MDMCTL defined","",0);
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ if (xlocal && ttyfd < 0)
+ return(-1);
+
+ if (xlocal)
+ x = ioctl(ttyfd,TIOCMGET,&y); /* Get modem signals. */
+ else
+ x = ioctl(0,TIOCMGET,&y);
+ debug(F101,"ttgmdm TIOCMGET ioctl","",x);
+ if (x < 0) {
+ debug(F101,"ttgmdm errno","",errno);
+ return(-1);
+ }
+ debug(F101,"ttgmdm bits","",y);
+
+ z = 0; /* Initialize return value. */
+#ifdef TIOCM_CTS
+ /* Clear To Send */
+ if (y & TIOCM_CTS) z |= BM_CTS;
+ debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS);
+#else
+ debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
+#endif
+#ifdef TIOCM_DSR
+ /* Data Set Ready */
+ if (y & TIOCM_DSR) z |= BM_DSR;
+ debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR);
+#else
+ debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
+#endif
+#ifdef TIOCM_CAR
+ /* Carrier */
+ if (y & TIOCM_CAR) z |= BM_DCD;
+ debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR);
+#else
+ debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
+#endif
+#ifdef TIOCM_RNG
+ /* Ring Indicate */
+ if (y & TIOCM_RNG) z |= BM_RNG;
+ debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG);
+#else
+ debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
+#endif
+#ifdef TIOCM_DTR
+ /* Data Terminal Ready */
+ if (y & TIOCM_DTR) z |= BM_DTR;
+ debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR);
+#else
+ debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
+#endif
+#ifdef TIOCM_RTS
+ /* Request To Send */
+ if (y & TIOCM_RTS) z |= BM_RTS;
+ debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS);
+#else
+ debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
+#endif
+ gotsigs = 1;
+ return(z);
+
+#else /* !K_MDMCTL catch-All */
+
+ debug(F100,"ttgmdm K_MDMCTL not defined","",0);
+#ifdef TIOCMGET
+ debug(F100,"ttgmdm TIOCMGET defined","",0);
+#else
+ debug(F100,"ttgmdm TIOCMGET not defined","",0);
+#endif /* TIOCMGET */
+#ifdef _SVID3
+ debug(F100,"ttgmdm _SVID3 defined","",0);
+#else
+ debug(F100,"ttgmdm _SVID3 not defined","",0);
+#endif /* _SVID3 */
+
+#ifdef NETCONN
+ if (netconn) { /* Network connection */
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ gotsigs = 1;
+ return(tngmdm());
+ } else
+#endif /* TN_COMPORT */
+ return(-2); /* No modem signals */
+ }
+#endif /* NETCONN */
+
+#ifdef NETCMD
+ if (ttpipe) return(-2);
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (ttpty) return(-2);
+#endif /* NETPTY */
+
+ return(-3); /* Sorry, I don't know how... */
+
+#endif /* K_MDMCTL */
+#endif /* HPUX */
+#endif /* QNX */
+}
+
+/* P S U S P E N D -- Put this process in the background. */
+
+/*
+ Call with flag nonzero if suspending is allowed, zero if not allowed.
+ Returns 0 on apparent success, -1 on failure (flag was zero, or
+ kill() returned an error code.
+*/
+int
+psuspend(flag) int flag; {
+
+#ifdef RTU
+ extern int rtu_bug;
+#endif /* RTU */
+
+ if (flag == 0) return(-1);
+
+#ifdef NOJC
+ return(-1);
+#else
+#ifdef SIGTSTP
+/*
+ The big question here is whether job control is *really* supported.
+ There's no way Kermit can know for sure. The fact that SIGTSTP is
+ defined does not guarantee the Unix kernel supports it, and the fact
+ that the Unix kernel supports it doesn't guarantee that the user's
+ shell (or other process that invoked Kermit) supports it.
+*/
+#ifdef RTU
+ rtu_bug = 1;
+#endif /* RTU */
+ if (kill(0,SIGSTOP) < 0
+#ifdef MIPS
+/* Let's try this for MIPS too. */
+ && kill(getpid(),SIGSTOP) < 0
+#endif /* MIPS */
+ ) { /* If job control, suspend the job */
+ perror("suspend");
+ debug(F101,"psuspend error","",errno);
+ return(-1);
+ }
+ debug(F100,"psuspend ok","",0);
+ return(0);
+#else
+ return(-1);
+#endif /* SIGTSTP */
+#endif /* NOJC */
+}
+
+/*
+ setuid package, by Kristoffer Eriksson, with contributions from Dean
+ Long and fdc.
+*/
+
+/* The following is for SCO when CK_ANSILIBS is defined... */
+#ifdef M_UNIX
+#ifdef CK_ANSILIBS
+#ifndef NOGETID_PROTOS
+#define NOGETID_PROTOS
+#endif /* NOGETID_PROTOS */
+#endif /* CK_ANSILIBS */
+#endif /* M_UNIX */
+
+#ifndef _POSIX_SOURCE
+#ifndef SUNOS4
+#ifndef NEXT
+#ifndef PS2AIX10
+#ifndef sequent
+#ifndef HPUX9
+#ifndef HPUX10
+#ifndef COHERENT
+#ifndef NOGETID_PROTOS
+_PROTOTYP( UID_T getuid, (void) );
+_PROTOTYP( UID_T geteuid, (void) );
+_PROTOTYP( UID_T getreuid, (void) );
+_PROTOTYP( UID_T getgid, (void) );
+_PROTOTYP( UID_T getegid, (void) );
+_PROTOTYP( UID_T getregid, (void) );
+#endif /* NOGETID_PROTOS */
+#else
+_PROTOTYP( UID_T getreuid, (void) );
+_PROTOTYP( UID_T getregid, (void) );
+#endif /* COHERENT */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* sequent */
+#endif /* PS2AIX10 */
+#endif /* NEXT */
+#endif /* SUNOS4 */
+#endif /* _POSIX_SOURCE */
+
+/*
+Subject: Set-user-id
+To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
+Date: Sat, 21 Apr 90 4:48:25 MES
+From: Kristoffer Eriksson <ske@pkmab.se>
+
+This is a set of functions to be used in programs that may be run set-user-id
+and/or set-group-id. They handle both the case where the program is not run
+with such privileges (nothing special happens then), and the case where one
+or both of these set-id modes are used. The program is made to run with the
+user's real user and group ids most of the time, except for when more
+privileges are needed. Don't set-user-id to "root".
+
+This works on System V and POSIX. In BSD, it depends on the
+"saved-set-user-id" feature.
+*/
+
+#define UID_ROOT 0 /* Root user and group ids */
+#define GID_ROOT 0
+
+/*
+ The following code defines the symbol SETEUID for UNIX systems based
+ on BSD4.4 (either -Encumbered or -Lite). This program will then use
+ seteuid() and setegid() instead of setuid() and setgid(), which still
+ don't allow arbitrary switching. It also avoids setreuid() and
+ setregid(), which are included in BSD4.4 for compatibility only, are
+ insecure, and print warnings to stderr under at least one system (NetBSD
+ 1.0). Note that POSIX systems should still use setuid() and setgid();
+ the seteuid() and setegid() functions are BSD4.4 extensions to the
+ POSIX model. Mike Long <mike.long@analog.com>, 8/94.
+*/
+#ifdef BSD44
+#define SETEUID
+#endif /* BSD44 */
+
+/*
+ The following construction automatically defines the symbol SETREUID for
+ UNIX versions based on Berkeley Unix 4.2 and 4.3. If this symbol is
+ defined, then this program will use getreuid() and getregid() calls in
+ preference to getuid() and getgid(), which in Berkeley-based Unixes do
+ not allow arbitrary switching back and forth of real & effective uid.
+ This construction also allows -DSETREUID to be put on the cc command line
+ for any system that has and wants to use setre[ug]id(). It also prevents
+ automatic definition of SETREUID if -DNOSETREU is included on the cc
+ command line (or otherwise defined).
+*/
+#ifdef FT18 /* None of this for Fortune. */
+#define NOSETREU
+#endif /* FT18 */
+
+#ifdef ANYBSD
+#ifndef BSD29
+#ifndef BSD41
+#ifndef SETREUID
+#ifndef NOSETREU
+#ifndef SETEUID
+#define SETREUID
+#endif /* SETEUID */
+#endif /* NOSETREU */
+#endif /* SETREUID */
+#endif /* !BSD41 */
+#endif /* !BSD29 */
+#endif /* ANYBSD */
+
+/* Variables for user and group IDs. */
+
+static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
+static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
+
+
+/* P R I V _ I N I -- Initialize privileges package */
+
+/* Called as early as possible in a set-uid or set-gid program to store the
+ * set-to uid and/or gid and step down to the users real uid and gid. The
+ * stored id's can be temporarily restored (allowed in System V) during
+ * operations that require the privilege. Most of the time, the program
+ * should execute in unpriviliged state, to not impose any security threat.
+ *
+ * Note: Don't forget that access() always uses the real id:s to determine
+ * file access, even with privileges restored.
+ *
+ * Returns an error mask, with error values or:ed together:
+ * 1 if setuid() fails,
+ * 2 if setgid() fails, and
+ * 4 if the program is set-user-id to "root", which can't be handled.
+ *
+ * Only the return value 0 indicates real success. In case of failure,
+ * those privileges that could be reduced have been, at least, but the
+ * program should be aborted none-the-less.
+ *
+ * Also note that these functions do not expect the uid or gid to change
+ * without their knowing. It may work if it is only done temporarily, but
+ * you're on your own.
+ */
+int
+priv_ini() {
+ int err = 0;
+
+#ifndef HAVE_LOCKDEV
+
+ /* Save real ID:s. */
+ realuid = getuid();
+ realgid = getgid();
+
+ /* Save current effective ID:s, those set to at program exec. */
+ privuid = geteuid();
+ privgid = getegid();
+
+ /* If running set-uid, go down to real uid, otherwise remember that
+ * no privileged uid is available.
+ *
+ * Exceptions:
+ *
+ * 1) If the real uid is already "root" and the set-uid uid (the
+ * initial effective uid) is not "root", then we would have trouble
+ * if we went "down" to "root" here, and then temporarily back to the
+ * set-uid uid (not "root") and then again tried to become "root". I
+ * think the "saved set-uid" is lost when changing uid from effective
+ * uid "root", which changes all uid, not only the effective uid. But
+ * in this situation, we can simply go to "root" and stay there all
+ * the time. That should give sufficient privilege (understatement!),
+ * and give the right uids for subprocesses.
+ *
+ * 2) If the set-uid (the initial effective uid) is "root", and we
+ * change uid to the real uid, we can't change it back to "root" when
+ * we need the privilege, for the same reason as in 1). Thus, we can't
+ * handle programs that are set-user-id to "root" at all. The program
+ * should be stopped. Use some other uid. "root" is probably too
+ * privileged for such things, anyway. (The uid is reverted to the
+ * real uid until termination.)
+ *
+ * These two exceptions have the effect that the "root" uid will never
+ * be one of the two uids that are being switched between, which also
+ * means we don't have to check for such cases in the switching
+ * functions.
+ *
+ * Note that exception 1) is handled by these routines (by constantly
+ * running with uid "root", while exception 2) is a serious error, and
+ * is not provided for at all in the switching functions.
+ */
+ if (realuid == privuid)
+ privuid = (UID_T) -1; /* Not running set-user-id. */
+
+ /* If running set-gid, go down to real gid, otherwise remember that
+ * no privileged gid is available.
+ *
+ * There are no exception like there is for the user id, since there
+ * is no group id that is privileged in the manner of uid "root".
+ * There could be equivalent problems for group changing if the
+ * program sometimes ran with uid "root" and sometimes not, but
+ * that is already avoided as explained above.
+ *
+ * Thus we can expect always to be able to switch to the "saved set-
+ * gid" when we want, and back to the real gid again. You may also
+ * draw the conclusion that set-gid provides for fewer hassles than
+ * set-uid.
+ */
+
+#ifdef SUIDDEBUG
+ fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
+ fprintf(stderr,"realuid=%d\n",realuid);
+ fprintf(stderr,"privuid=%d\n",privuid);
+#endif /* SUIDDEBUG */
+
+ if (realgid == privgid) /* If not running set-user-id, */
+ privgid = (GID_T) -1; /* remember it this way. */
+
+ err = priv_off(); /* Turn off setuid privilege. */
+
+ if (privuid == UID_ROOT) /* If setuid to root, */
+ err |= 4; /* return this error. */
+
+ if (realuid == UID_ROOT) { /* If real id is root, */
+ privuid = (UID_T) -1; /* stay root at all times. */
+#ifdef ATT7300
+ /* If Kermit installed SUID uucp and user is running as root */
+ err &= ~1; /* System V R0 does not save UID */
+#endif /* ATT7300 */
+ }
+#endif /* HAVE_LOCKDEV */
+ return(err);
+}
+
+
+/* Macros for hiding the differences in UID/GID setting between various Unix
+ * systems. These macros should always be called with both the privileged ID
+ * and the non-privileged ID. The one in the second argument, will become the
+ * effective ID. The one in the first argument will be retained for later
+ * retrieval.
+ */
+#ifdef SETREUID
+#ifdef SAVEDUID
+/* On BSD systems with the saved-UID feature, we just juggle the effective
+ * UID back and forth, and leave the real UID at its true value. The kernel
+ * allows switching to both the current real UID, the effective UID, and the
+ * UID which the program is set-UID to. The saved set-UID always holds the
+ * privileged UID for us, and the real UID will always be the non-privileged,
+ * and we can freely choose one of them for the effective UID at any time.
+ */
+#define switchuid(hidden,active) setreuid( (UID_T) -1, active)
+#define switchgid(hidden,active) setregid( (GID_T) -1, active)
+
+#else /* SETREUID,!SAVEDUID */
+
+/* On systems with setreXid() but without the saved-UID feature, notably
+ * BSD 4.2, we swap the real and effective UIDs each time. It's
+ * the effective UID that we are interested in, but we have to retain the
+ * unused UID somewhere to enable us to restore it later, and we do this
+ * in the real UID. The kernel only allows switching to either the current
+ * real or the effective UID, unless you're "root".
+ */
+#define switchuid(hidden,active) setreuid(hidden,active)
+#define switchgid(hidden,active) setregid(hidden,active)
+#endif
+
+#else /* !SETREUID, !SAVEDUID */
+
+#ifdef SETEUID
+/*
+ BSD 4.4 works similarly to System V and POSIX (see below), but uses
+ seteXid() instead of setXid() to change effective IDs. In addition, the
+ seteXid() functions work the same for "root" as for other users.
+*/
+#define switchuid(hidden,active) seteuid(active)
+#define switchgid(hidden,active) setegid(active)
+
+#else /* !SETEUID */
+
+/* On System V and POSIX, the only thing we can change is the effective UID
+ * (unless the current effective UID is "root", but initsuid() avoids that for
+ * us). The kernel allows switching to the current real UID or to the saved
+ * set-UID. These are always set to the non-privileged UID and the privileged
+ * UID, respectively, and we only change the effective UID. This breaks if
+ * the current effective UID is "root", though, because for "root" setuid/gid
+ * becomes more powerful, which is why initsuid() treats "root" specially.
+ * Note: That special treatment maybe could be ignored for BSD? Note: For
+ * systems that don't fit any of these four cases, we simply can't support
+ * set-UID.
+ */
+#define switchuid(hidden,active) setuid(active)
+#define switchgid(hidden,active) setgid(active)
+
+#endif /* SETEUID */
+#endif /* SETREUID */
+
+
+/* P R I V _ O N -- Turn on the setuid and/or setgid */
+
+/* Go to the privileged uid (gid) that the program is set-user-id
+ * (set-group-id) to, unless the program is running unprivileged.
+ * If setuid() fails, return value will be 1. If getuid() fails it
+ * will be 2. Return immediately after first failure, and the function
+ * tries to restore any partial work done. Returns 0 on success.
+ * Group id is changed first, since it is less serious than user id.
+ */
+int
+priv_on() {
+#ifndef HAVE_LOCKDEV
+ if (privgid != (GID_T) -1)
+ if (switchgid(realgid,privgid))
+ return(2);
+
+ if (privuid != (UID_T) -1)
+ if (switchuid(realuid,privuid)) {
+ if (privgid != (GID_T) -1)
+ switchgid(privgid,realgid);
+ return(1);
+ }
+#endif /* HAVE_LOCKDEV */
+ return(0);
+}
+
+/* P R I V _ O F F -- Turn on the real uid and gid */
+
+/* Return to the unprivileged uid (gid) after an temporary visit to
+ * privileged status, unless the program is running without set-user-id
+ * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
+ * in setgid() or:ed together. The functions tries to return both uid
+ * and gid to unprivileged state, regardless of errors. Returns 0 on
+ * success.
+ */
+int
+priv_off() {
+ int err = 0;
+#ifndef HAVE_LOCKDEV
+ if (privuid != (UID_T) -1)
+ if (switchuid(privuid,realuid))
+ err |= 1;
+
+ if (privgid != (GID_T) -1)
+ if (switchgid(privgid,realgid))
+ err |= 2;
+#endif /* HAVE_LOCKDEV */
+ return(err);
+}
+
+/* Turn off privilege permanently. No going back. This is necessary before
+ * a fork() on BSD43 machines that don't save the setUID or setGID, because
+ * we swap the real and effective ids, and we don't want to let the forked
+ * process swap them again and get the privilege back. It will work on other
+ * machines too, such that you can rely on its effect always being the same,
+ * for instance, even when you're in priv_on() state when this is called.
+ * (Well, that part about "permanent" is on System V only true if you follow
+ * this with a call to exec(), but that's what we want it for anyway.)
+ * Added by Dean Long -- dlong@midgard.ucsc.edu
+ */
+int
+priv_can() {
+#ifndef HAVE_LOCKDEV
+#ifdef SETREUID
+ int err = 0;
+ if (privuid != (UID_T) -1)
+ if (setreuid(realuid,realuid))
+ err |= 1;
+
+ if (privgid != (GID_T) -1)
+ if (setregid(realgid,realgid))
+ err |= 2;
+
+ return(err);
+
+#else
+#ifdef SETEUID
+ int err = 0;
+ if (privuid != (UID_T) -1)
+ if (setuid(realuid)) {
+ debug(F101,"setuid failed","",errno);
+ err |= 1;
+ debug(F101,"ruid","",getuid());
+ debug(F101,"euid","",geteuid());
+ }
+ debug(F101,"setuid","",realuid);
+ if (privgid != (GID_T) -1)
+ if (setgid(realgid)) {
+ debug(F101,"setgid failed","",errno);
+ err |= 2;
+ debug(F101,"rgid","",getgid());
+ debug(F101,"egid","",getegid());
+ }
+ debug(F101,"setgid","",realgid);
+ return(err);
+#else
+ /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
+ return(priv_off());
+#endif /* SETEUID */
+#endif /* SETREUID */
+#else
+ return(0);
+#endif /* HAVE_LOCKDEV */
+}
+
+/* P R I V _ O P N -- For opening protected files or devices. */
+
+int
+priv_opn(name, modes) char *name; int modes; {
+ int x;
+ priv_on(); /* Turn privileges on */
+ debug(F111,"priv_opn",name,modes);
+ errno = 0;
+ x = open(name, modes); /* Try to open the device */
+ debug(F101,"priv_opn result","",x);
+ debug(F101,"priv_opn errno","",errno);
+ priv_off(); /* Turn privileges off */
+ return(x); /* Return open's return code */
+}
+
+/* P R I V _ C H K -- Check privileges. */
+
+/* Try to turn them off. If turning them off did not succeed, cancel them */
+
+int
+priv_chk() {
+ int x, y = 0;
+ x = priv_off(); /* Turn off privs. */
+ if (x != 0 || getuid() == privuid || geteuid() == privuid)
+ y = priv_can();
+ if (x != 0 || getgid() == privgid || getegid() == privgid)
+ y = y | priv_can();
+ return(y);
+}
+
+UID_T
+real_uid() {
+ return(realuid);
+}
+
+VOID
+ttimoff() { /* Turn off any timer interrupts */
+ /* int xx; */
+/*
+ As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
+ SIG_DFL (to catch alarms, or if there is no handler, to exit). This is to
+ cure (mask, really) a deeper problem with stray alarms that occurs on some
+ systems, possibly having to do with sleep(), that caused core dumps. It
+ should be OK to do this, because no code in this module uses nested alarms.
+ (But we still have to watch out for SCRIPT and DIAL...)
+*/
+ /* xx = */ alarm(0);
+ /* debug(F101,"ttimoff alarm","",xx); */
+ if (saval) { /* Restore any previous */
+ signal(SIGALRM,saval); /* alarm handler. */
+ /* debug(F101,"ttimoff alarm restoring saval","",saval); */
+ saval = NULL;
+ } else {
+ signal(SIGALRM,SIG_IGN); /* Used to be SIG_DFL */
+ /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
+ }
+}
+
+
+int
+tt_is_secure() { /* Tells whether the current connection is secure */
+
+ if (ttyfd == -1)
+ return(0);
+
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ )
+ return(1);
+ return(0);
+}
+
+#ifdef CK_REDIR
+
+/* External protocol handler parameters from ckuus3.c */
+extern int exp_handler, exp_stderr, exp_timo;
+
+#ifdef SELECT
+#ifdef NETPTY
+
+/* The right size is 24576 */
+
+#ifndef PTY_PBUF_SIZE /* Size of buffer to read from pty */
+#define PTY_PBUF_SIZE 24576 /* and write to net. */
+#endif /* PTY_PBUF_SIZE */
+
+#ifndef PTY_TBUF_SIZE /* Size of buffer to read from net */
+#define PTY_TBUF_SIZE 24576 /* and write to pty. */
+#endif /* PTY_TBUF_SIZE */
+
+#ifdef O_NDELAY /* Whether to use nonblocking */
+#ifndef PTY_NO_NDELAY /* reads on the pseudoterminal */
+#ifndef PTY_USE_NDELAY
+#define PTY_USE_NDELAY
+#endif /* PTY_USE_NDELAY */
+#endif /* PTY_NO_NDELAY */
+#endif /* O_NDELAY */
+
+#ifndef HAVE_OPENPTY
+#ifndef USE_CKUPTY_C
+#define USE_CKUPTY_C
+#endif /* USE_CKUPTY_C */
+#endif /* HAVE_OPENPTY */
+
+VOID
+pty_make_raw(fd) int fd; {
+ int x = -23, i;
+
+#ifdef BSD44ORPOSIX /* POSIX */
+ struct termios tp;
+#else
+#ifdef ATTSV /* AT&T UNIX */
+#ifdef CK_ANSIC
+ struct termio tp = {0};
+#else
+ struct termio tp;
+#endif /* CK_ANSIC */
+#else
+ struct sgttyb tp; /* Traditional */
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+
+ debug(F101,"pty_make_raw fd","",fd);
+ errno = 0;
+
+#ifdef BSD44ORPOSIX /* POSIX */
+ x = tcgetattr(fd,&tp);
+ debug(F101,"pty_make_raw tcgetattr","",x);
+#else
+#ifdef ATTSV /* AT&T UNIX */
+ x = ioctl(fd,TCGETA,&tp);
+ debug(F101,"pty_make_raw TCGETA ioctl","",x);
+#else
+ x = gtty(fd,&tp);
+ debug(F101,"pty_make_raw ttty","",x);
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ debug(F101,"pty_make_raw GET errno","",errno);
+
+#ifdef USE_CFMAKERAW
+ errno = 0;
+ cfmakeraw(&tp);
+ debug(F101,"pty_make_raw cfmakeraw errno","",errno);
+#else /* USE_CFMAKERAW */
+
+#ifdef COMMENT
+
+/* This very simple version recommended by Serg Iakolev doesn't work */
+
+ tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
+ tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
+ tp.c_cflag &= ~(CSIZE|PARENB);
+ tp.c_cflag |= CS8;
+ tp.c_oflag &= ~(OPOST);
+ tp.c_cc[VMIN] = 1;
+ tp.c_cc[VTIME] = 0;
+
+ debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
+ debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
+ debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
+ debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
+ debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
+
+#else
+#ifdef COMMENT
+/*
+ In this version we unset everything and then set only the
+ bits we know we need.
+*/
+ /* iflags */
+ tp.c_iflag = 0L;
+ tp.c_iflag |= IGNBRK;
+#ifdef IMAXBEL
+ tp.c_iflag |= IMAXBEL;
+#endif /* IMAXBEL */
+
+ /* oflags */
+ tp.c_oflag = 0L;
+
+ /* lflags */
+ tp.c_lflag = 0L;
+#ifdef NOKERNINFO
+ tp.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+
+ /* cflags */
+ tp.c_cflag = 0L;
+ tp.c_cflag |= CS8|CREAD;
+
+ for (i = 0; i < NCCS; i++) { /* No special characters */
+ tp.c_cc[i] = 0;
+ }
+#ifdef VMIN
+ tp.c_cc[VMIN] = 1; /* But always wait for input */
+#endif /* VMIN */
+ debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
+ debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
+ debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
+ debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
+ debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
+
+#else /* COMMENT */
+/*
+ In this version we set or unset every single flag explicitly. It works a
+ bit better than the simple version just above, but it's still far from
+ adequate.
+*/
+ /* iflags */
+ tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
+ tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
+ tp.c_iflag |= IGNBRK;
+#ifdef IMAXBEL
+#ifdef COMMENT
+ tp.c_iflag |= IMAXBEL;
+#else
+ tp.c_iflag &= ~IMAXBEL;
+#endif /* COMMENT */
+#endif /* IMAXBEL */
+#ifdef IUCLC
+ tp.c_iflag &= ~IUCLC;
+#endif /* IUCLC */
+
+ /* oflags */
+#ifdef BSDLY
+ tp.c_oflag &= ~BSDLY;
+#endif /* BSDLY */
+#ifdef CRDLY
+ tp.c_oflag &= ~CRDLY;
+#endif /* CRDLY */
+#ifdef FFDLY
+ tp.c_oflag &= ~FFDLY;
+#endif /* FFDLY */
+#ifdef NLDLY
+ tp.c_oflag &= ~NLDLY;
+#endif /* NLDLY */
+#ifdef TABDLY
+ tp.c_oflag &= ~TABDLY;
+#endif /* TABDLY */
+#ifdef VTDLY
+ tp.c_oflag &= ~VTDLY;
+#endif /* VTDLY */
+#ifdef OFDEL
+ tp.c_oflag &= ~OFDEL;
+#endif /* OFDEL */
+#ifdef OFILL
+ tp.c_oflag &= ~OFILL;
+#endif /* OFILL */
+#ifdef OLCUC
+ tp.c_oflag &= ~OLCUC;
+#endif /* OLCUC */
+#ifdef CMSPAR
+ tp.c_oflag &= ~CMSPAR;
+#endif /* CMSPAR */
+ tp.c_oflag &= ~OPOST;
+#ifdef OXTABS
+ tp.c_oflag &= ~OXTABS;
+#endif /* OXTABS */
+#ifdef COMMENT
+#ifdef ONOCR
+ tp.c_oflag &= ~ONOCR; /* Maybe should be |=? */
+ tp.c_oflag |= ONOCR; /* makes no difference either way */
+#endif /* ONOCR */
+#endif /* COMMENT */
+#ifdef ONOEOT
+ tp.c_oflag &= ~ONOEOT;
+#endif /* ONOEOT */
+#ifdef ONLRET
+ tp.c_oflag &= ~ONLRET;
+#endif /* ONLRET */
+#ifdef ONLCR
+ tp.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+#ifdef OCRNL
+ tp.c_oflag &= ~OCRNL;
+#endif /* OCRNL */
+
+ /* lflags */
+ tp.c_lflag &= ~ECHO;
+#ifdef ECHOE
+ tp.c_lflag &= ~ECHOE;
+#endif /* ECHOE */
+#ifdef ECHONL
+ tp.c_lflag &= ~ECHONL;
+#endif /* ECHONL */
+#ifdef ECHOPRT
+ tp.c_lflag &= ~ECHOPRT;
+#endif /* ECHOPRT */
+#ifdef ECHOKE
+ tp.c_lflag &= ~ECHOKE;
+#endif /* ECHOKE */
+#ifdef ECHOCTL
+ tp.c_lflag &= ~ECHOCTL;
+#endif /* ECHOCTL */
+#ifdef XCASE
+ tp.c_lflag &= ~XCASE;
+#endif /* XCASE */
+#ifdef ALTWERASE
+ tp.c_lflag &= ~ALTWERASE;
+#endif /* ALTWERASE */
+#ifdef EXTPROC
+ tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
+#else
+ tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
+#endif /* EXTPROC */
+#ifdef NOKERNINFO
+ tp.c_lflag |= NOKERNINFO;
+#endif /* NOKERNINFO */
+#ifndef COMMENT
+ tp.c_lflag &= ~NOFLSH; /* TRY IT THE OTHER WAY? */
+#else
+ tp.c_lflag |= NOFLSH; /* No, this way is worse */
+#endif /* COMMENT */
+
+ /* cflags */
+ tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ tp.c_cflag |= CS8|CREAD;
+
+#ifdef MDMBUF
+ tp.c_cflag &= ~(MDMBUF);
+#else
+#ifdef CCAR_OFLOW
+ tp.c_cflag &= ~(CCAR_OFLOW); /* two names for the same thing */
+#endif /* CCAR_OFLOW */
+#endif /* MDMBUF */
+
+#ifdef CCTS_OFLOW
+ tp.c_cflag &= ~(CCTS_OFLOW);
+#endif /* CCTS_OFLOW */
+#ifdef CDSR_OFLOW
+ tp.c_cflag &= ~(CDSR_OFLOW);
+#endif /* CDSR_OFLOW */
+#ifdef CDTR_IFLOW
+ tp.c_cflag &= ~(CDTR_IFLOW);
+#endif /* CDTR_IFLOW */
+#ifdef CRTS_IFLOW
+ tp.c_cflag &= ~(CRTS_IFLOW);
+#endif /* CRTS_IFLOW */
+#ifdef CRTSXOFF
+ tp.c_cflag &= ~(CRTSXOFF);
+#endif /* CRTSXOFF */
+#ifdef CRTSCTS
+ tp.c_cflag &= ~(CRTSCTS);
+#endif /* CRTSCTS */
+#ifdef CLOCAL
+ tp.c_cflag &= ~(CLOCAL);
+#endif /* CLOCAL */
+#ifdef CSTOPB
+ tp.c_cflag &= ~(CSTOPB);
+#endif /* CSTOPB */
+#ifdef HUPCL
+ tp.c_cflag &= ~(HUPCL);
+#endif /* HUPCL */
+
+ for (i = 0; i < NCCS; i++) { /* No special characters */
+ tp.c_cc[i] = 0;
+ }
+#ifdef VMIN
+ tp.c_cc[VMIN] = 1; /* But always wait for input */
+#endif /* VMIN */
+ debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
+ debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
+ debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
+ debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
+ debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
+#endif /* COMMENT */
+#endif /* COMMENT */
+
+ errno = 0;
+#ifdef BSD44ORPOSIX /* POSIX */
+ x = tcsetattr(fd,TCSANOW,&tp);
+ debug(F101,"pty_make_raw tcsetattr","",x);
+#else
+#ifdef ATTSV /* AT&T UNIX */
+ x = ioctl(fd,TCSETA,&tp);
+ debug(F101,"pty_make_raw ioctl","",x);
+#else
+ x = stty(fd,&tp); /* Traditional */
+ debug(F101,"pty_make_raw stty","",x);
+#endif /* ATTSV */
+#endif /* BSD44ORPOSIX */
+ debug(F101,"pty_make_raw errno","",errno);
+
+#endif /* __NetBSD__ */
+}
+
+static int
+pty_chk(fd) int fd; {
+ int x, n = 0;
+ errno = 0;
+#ifdef FIONREAD
+ x = ioctl(fd, FIONREAD, &n); /* BSD and most others */
+ ckmakmsg(msgbuf,500,
+ "pty_chk ioctl FIONREAD errno=",
+ ckitoa(errno),
+ " count=",
+ ckitoa(n));
+ debug(F100,msgbuf,"",0);
+#else
+#ifdef RDCHK
+ n = rdchk(fd);
+ debug(F101,"pty_chk rdchk","",n);
+#else
+ n = 1;
+#endif /* RDCHK */
+#endif /* FIONREAD */
+ return((n > -1) ? n : 0);
+}
+
+static int
+pty_get_status(fd,pid) int fd; PID_T pid; {
+ int x, status = -1;
+ PID_T w;
+
+ debug(F101,"pty_get_status fd","",fd);
+ debug(F101,"pty_get_status pid","",pid);
+
+ if (pexitstat > -1)
+ return(pexitstat);
+
+#ifdef COMMENT
+ /* Not only unnecessary but harmful */
+ errno = 0;
+ x = kill(pty_fork_pid,0);
+ debug(F101,"pty_get_status kill value","",x);
+ debug(F101,"pty_get_status kill errno","",errno);
+ if (x > -1 && errno != ESRCH)
+ return(-1); /* Fork still there */
+ /* Fork seems to be gone */
+#endif /* COMMENT */
+
+ errno = 0;
+ x = waitpid(pty_fork_pid,&status,WNOHANG);
+ debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
+ if (x <= 0 && errno == 0) {
+ debug(F101,"pty_get_status waitpid return","",-1);
+ return(-1);
+ }
+ if (x > 0) {
+ if (x != pty_fork_pid)
+ debug(F101,
+ "pty_get_status waitpid pid doesn't match","",pty_fork_pid);
+ debug(F101,"pty_get_status waitpid status","",status);
+ debug(F101,"pty_get_status waitpid errno","",errno);
+ if (WIFEXITED(status)) {
+ debug(F100,"pty_get_status WIFEXITED","",0);
+ status = WEXITSTATUS(status);
+ debug(F101,"pty_get_status fork exit status","",status);
+#ifdef COMMENT
+ end_pty();
+#endif /* COMMENT */
+ close(fd);
+ pexitstat = status;
+ } else {
+ debug(F100,"pty_get_status waitpid unexpected status","",0);
+ }
+ }
+ debug(F101,"pty_get_status return status","",status);
+ return(status);
+}
+
+/* t t p t y c m d -- Run command on pty and forward to net */
+
+/*
+ Needed for running external protocols on secure connections.
+ For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
+ connection, and then needs to transfer a file with Zmodem, which is
+ an external program, this routine reads Zmodem's output, encrypts it,
+ and then forwards it out the connection, and reads the encrypted data
+ stream coming in from the connection, decrypts it, and forwards it to
+ Zmodem.
+
+ Works like a TCP/IP port forwarder except one end is a pty rather
+ than a socket, which introduces some complications:
+
+ . On most platforms, select() always indicates the output side of
+ the pty has characters waiting to be read, even when it doesn't,
+ even when the pty process has already exited.
+
+ . Nonblocking reads must be used on the pty, because there is no
+ way on certain platforms (e.g. NetBSD) to find out how many characters
+ are available to be read (the FIONREAD ioctl always says 0). The code
+ also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
+ defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
+ result in single-byte reads and writes (NetBSD again).
+
+ . Testing for "EOF" on the pty is problematic. select() never gives
+ any indication. After the pty process has exited and the fork has
+ disappeared, read() can still return with 0 bytes read but without an
+ error (NetBSD); no known test on the pty file descriptor will indicate
+ that it is no longer valid. The process ID of the pty fork can be
+ tested on some platforms (NetBSD, luckily) but not others (Solaris,
+ Linux).
+
+ On the network side, we use ttinc() and ttoc(), which, for network
+ connections, handle any active security methods.
+
+ Call with s = command.
+ Returns 0 on failure, 1 on success.
+ fdc - December 2006 - August 2007.
+
+ NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
+ defined in the header files, which should be true of every recent Unix
+ platform. If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
+ building C-Kermit:
+
+ touch ckutio.c
+ make platformname KFLAGS=-DPTY_NO_NODELAY
+*/
+static int have_pty = 0; /* Do we have a pty? */
+
+static SIGTYP (*save_sigchld)() = NULL; /* For catching SIGCHLD */
+
+static VOID
+sigchld_handler(sig) int sig; {
+ have_pty = 0; /* We don't have a pty */
+#ifdef DEBUG
+ if (save_sigchld) {
+ (VOID) signal(SIGCHLD,save_sigchld);
+ save_sigchld = NULL;
+ }
+ if (deblog) {
+ debug(F100,"**************","",0);
+ debug(F100,"SIGCHLD caught","",0);
+ debug(F100,"**************","",0);
+ }
+#endif /* DEBUG */
+}
+#define HAVE_IAC 1
+#define HAVE_CR 2
+
+int
+ttptycmd(s) char *s; {
+ CHAR tbuf[PTY_TBUF_SIZE]; /* Read from net, write to pty */
+ int tbuf_avail = 0; /* Pointers for tbuf */
+ int tbuf_written = 0;
+ static int in_state = 0; /* For TELNET IAC and NVT in */
+ static int out_prev = 0; /* Simpler scheme for out */
+
+ CHAR pbuf[PTY_PBUF_SIZE]; /* Read from pty, write to net */
+ CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
+ int pbuf_avail = 0; /* Pointers for pbuf */
+ int pbuf_written = 0;
+
+ int ptyfd = -1; /* Pty file descriptor */
+ int have_net = 0; /* We have a network connection */
+ int pty_err = 0; /* Got error on pty */
+ int net_err = 0; /* Got error on net */
+ int status = -1; /* Pty process exit status */
+ int rc = 0; /* Our return code */
+
+ int x1 = 0, x2 = 0; /* Workers... */
+ int c, n, m, t, x; /* Workers */
+
+ long seconds_to_wait = 0L; /* select() timeout */
+ struct timeval tv, *tv2; /* For select() */
+#ifdef INTSELECT
+ int in, out, err; /* For select() */
+#else
+ fd_set in, out, err;
+#endif /* INTSELECT */
+ int nfds = 0; /* For select() */
+
+ int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
+ int read_net_bytes = 0; /* Stats */
+ int write_net_bytes = 0; /* Stats */
+ int read_pty_bytes = 0; /* Stats */
+ int write_pty_bytes = 0; /* Stats */
+ int is_tn = 0; /* TELNET protocol is active */
+
+ int masterfd = -1;
+ int slavefd = -1;
+#ifndef USE_CKUPTY_C
+ struct termios term;
+ struct winsize twin;
+ struct stringarray * q;
+ char ** args = NULL;
+#endif /* USE_CKUPTY_C */
+
+ in_state = 0; /* No previous character yet */
+
+ if (ttyfd == -1) {
+ printf("?Sorry, communication channel is not open\n");
+ return(0);
+ } else {
+ have_net = 1;
+ }
+ if (nopush) {
+ debug(F100,"ttptycmd fail: nopush","",0);
+ return(0);
+ }
+ if (!s) s = ""; /* Defense de bogus arguments */
+ if (!*s) return(0);
+ pexitstat = -1; /* Fork process exit status */
+
+#ifdef TNCODE
+ is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
+ (!xlocal && sstelnet);
+#endif /* TNCODE */
+
+ debug(F110,"ttptycmd command",s,0);
+ debug(F101,"ttptycmd ttyfd","",ttyfd);
+ debug(F101,"ttptycmd is_tn","",is_tn);
+ debug(F101,"ttptycmd ckermit pid","",getpid());
+
+#ifdef USE_CKUPTY_C
+ /* Call ckupty.c module to get and set up the pty fork */
+ /* fc 1 == "run an external protocol" */
+ debug(F100,"ttptycmd using ckupty.c","",0);
+ if (do_pty(&ptyfd,s,1) < 0) { /* Start the command on a pty */
+ debug(F100,"ttptycmd do_pty fails","",0);
+ return(0);
+ }
+ masterfd = ptyfd;
+ pty_master_fd = ptyfd;
+#ifdef COMMENT
+ slavefd = pty_slave_fd; /* This is not visible to us */
+#endif /* COMMENT */
+ debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
+ debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
+ debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
+#ifndef SOLARIS
+ /* "ioctl inappropriate on device" for pty master */
+ pty_make_raw(masterfd);
+#endif /* SOLARIS */
+
+#else /* USE_CKUPTY_C */
+
+ debug(F100,"ttptycmd OPENPTY","",0);
+ if (tcgetattr(0, &term) == -1) { /* Get controlling terminal's modes */
+ perror("tcgetattr");
+ return(0);
+ }
+ if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
+ perror("ioctl TIOCGWINSZ");
+ return(0);
+ }
+ if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
+ debug(F101,"ttptycmd openpty failed errno","",errno);
+ perror("opentpy");
+ return(0);
+ }
+ debug(F101,"ttptycmd openpty masterfd","",masterfd);
+ debug(F101,"ttptycmd openpty slavefd","",slavefd);
+ pty_master_fd = masterfd;
+ pty_slave_fd = slavefd;
+ debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
+
+ /* Put pty master in raw mode but let forked app control the slave */
+ pty_make_raw(masterfd);
+
+#ifdef COMMENT
+#ifdef TIOCREMOTE
+ /* TIOCREMOTE,0 = disable all termio processing */
+ x = ioctl(masterfd, TIOCREMOTE, 1);
+ debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
+#endif /* TIOCREMOTE */
+#ifdef TIOCTTY
+ /* TIOCTTY,0 = disable all termio processing */
+ x = ioctl(masterfd, TIOCTTY, 0);
+ debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
+#endif /* TIOCTTY */
+#endif /* COMMENT */
+
+ have_pty = 1; /* We have an open pty */
+ save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
+
+ pty_fork_pid = fork(); /* Make fork for external protocol */
+ debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
+ if (pty_fork_pid == -1) {
+ perror("fork");
+ return(0);
+ } else if (pty_fork_pid == 0) { /* In new fork */
+ int x;
+ debug(F101,"ttptycmd new fork pid","",getpid());
+ close(masterfd); /* Slave quarters no masters allowed */
+ x = setsid();
+ debug(F101,"ttptycmd new fork setsid","",x);
+ if (x == -1) {
+ perror("ttptycmd setsid");
+ exit(1);
+ }
+ signal(SIGINT,SIG_IGN); /* Let upper fork catch this */
+
+#ifdef COMMENT
+#ifdef TIOCSCTTY
+ /* Make pty the controlling terminal for the process */
+ /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
+ x = ioctl(slavefd, TIOCSCTTY, NULL);
+ debug(F101,"ttptycmd TIOCSCTTY","",x);
+#endif /* TIOCSCTTY */
+#endif /* COMMENT */
+
+ /* Initialize slave pty modes and size to those of our terminal */
+ if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
+ perror("ttptycmd tcsetattr");
+ exit(1);
+ }
+ if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
+ perror("ttptycmd ioctl");
+ exit(1);
+ }
+#ifdef COMMENT
+#ifdef TIOCNOTTY
+ /* Disassociate this process from its terminal */
+ /* THIS HAS NO EFFECT */
+ x = ioctl(slavefd, TIOCNOTTY, NULL);
+ debug(F101,"ttptycmd TIOCNOTTY","",x);
+#endif /* TIOCNOTTY */
+#endif /* COMMENT */
+
+#ifdef COMMENT
+#ifdef SIGTTOU
+ /* Ignore terminal output interrupts */
+ /* THIS HAS NO EFFECT */
+ debug(F100,"ttptycmd ignoring SIGTTOU","",0);
+ signal(SIGTTOU, SIG_IGN);
+#endif /* SIGTTOU */
+#ifdef SIGTSTP
+ /* Ignore terminal output interrupts */
+ /* THIS HAS NO EFFECT */
+ debug(F100,"ttptycmd ignoring SIGTSTP","",0);
+ signal(SIGTSTP, SIG_IGN);
+#endif /* SIGTSTP */
+#endif /* COMMENT */
+
+ pty_make_raw(slavefd); /* Put it in rawmode */
+
+ errno = 0;
+ if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
+ dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
+ debug(F101,"ttptycmd new fork dup2 error","",errno);
+ perror("ttptycmd dup2");
+ exit(1);
+ }
+ debug(F100,"ttptycmd new fork dup2 ok","",0);
+
+ /* Parse external protocol command line */
+ q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
+ if (!q) {
+ debug(F100,"ttptycmd cksplit failed","",0);
+ exit(1);
+ } else {
+ int i, n;
+ debug(F100,"ttptycmd cksplit ok","",0);
+ n = q->a_size;
+ args = q->a_head + 1;
+ for (i = 0; i <= n; i++) {
+ if (!args[i]) {
+ break;
+ } else {
+ /* sometimes cksplit() doesn't terminate the list */
+ if ((i == n) && args[i]) {
+ if ((int)strlen(args[i]) == 0)
+ makestr(&(args[i]),NULL);
+ }
+ }
+ }
+ }
+#ifdef COMMENT
+/*
+ Putting the slave pty in rawmode should not be necessary because the
+ external protocol program is supposed to do that itself. Yet doing this
+ here cuts down on Zmodem binary-file transmission errors by 30-50% but
+ still doesn't eliminate them.
+*/
+ pty_make_raw(STDIN_FILENO);
+ pty_make_raw(STDOUT_FILENO);
+#endif /* COMMENT */
+
+ debug(F100,"ttptycmd execvp'ing external protocol","",0);
+ execvp(args[0],args);
+ perror("execvp failed");
+ debug(F101,"ttptycmd execvp failed","",errno);
+ close(slavefd);
+ exit(1);
+ }
+ /* (there are better ways to do this...) */
+ msleep(1000); /* Make parent wait for child to be ready */
+ ptyfd = masterfd; /* We talk to the master */
+
+#endif /* USE_CKUPTY_C */
+
+ debug(F101,"ttptycmd ptyfd","",ptyfd);
+ if (ptyfd < 0) {
+ printf("?Failure to get pty\n");
+ return(-9);
+ }
+ have_pty = 1; /* We have an open pty or we wouldn't he here */
+
+ debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
+ debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
+
+#ifdef PTY_USE_NDELAY
+ /*
+ NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
+ on the pty, we don't need nonblocking reads. Performance of either
+ method seems to be about the same, so use whatever works.
+ */
+ errno = 0;
+ x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
+ ckmakmsg(msgbuf,500,
+ "ttptycmd set O_NDELAY errno=",
+ ckitoa(errno),
+ " fcntl=",
+ ckitoa(x));
+ debug(F100,msgbuf,"",0);
+#endif /* PTY_USE_NDELAY */
+
+#ifdef COMMENT
+/* Not necessary, the protocol module already did this */
+
+#ifdef USE_CFMAKERAW
+ if (tcgetattr(ttyfd, &term) > -1) {
+ cfmakeraw(&term);
+ debug(F101,"ttptycmd net cfmakeraw errno","",errno);
+ x tcsetattr(ttyfd, TCSANOW, &term);
+ debug(F101,"ttptycmd net tcsetattr","",x);
+ debug(F101,"ttptycmd net tcsetattr","",errno);
+ }
+#else
+ if (local) /* Put network connection in */
+ ttpkt(ttspeed,ttflow,ttprty); /* "packet mode". */
+ else
+ conbin((char)escchr); /* OR... pty_make_raw(0) */
+#endif /* USE_CFMAKERAW */
+#endif /* COMMENT */
+
+#ifdef TNCODE
+ if (is_tn) {
+ debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
+ debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
+ }
+#endif /* TNCODE */
+
+ debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
+
+ while (have_pty || have_net) {
+ FD_ZERO(&in); /* Initialize select() structs */
+ FD_ZERO(&out);
+ FD_ZERO(&err); /* (not used because useless) */
+ nfds = -1;
+
+ debug(F101,"ttptycmd loop top have_pty","",have_pty);
+ debug(F101,"ttptycmd loop top have_net","",have_net);
+
+ /* Pty is open and we have room to read from it? */
+ if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
+ debug(F100,"ttptycmd FD_SET ptyfd in","",0);
+ FD_SET(ptyfd, &in);
+ nfds = ptyfd;
+ }
+ /* Network is open and we have room to read from it? */
+ if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
+ debug(F100,"ttptycmd FD_SET ttyfd in","",0);
+ FD_SET(ttyfd, &in);
+ if (ttyfd > nfds) nfds = ttyfd;
+ }
+ /* Pty is open and we have stuff to write to it? */
+ if (have_pty && tbuf_avail - tbuf_written > 0) {
+ debug(F100,"ttptycmd FD_SET ptyfd out","",0);
+ FD_SET (ptyfd, &out);
+ if (ptyfd > nfds) nfds = ptyfd;
+ }
+ /* Net is open and we have stuff to write to it? */
+ debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
+ pbuf_avail - pbuf_written);
+ if (have_net && pbuf_avail - pbuf_written > 0) {
+ debug(F100,"ttptycmd FD_SET ttyfd out","",0);
+ FD_SET (ttyfd, &out);
+ if (ttyfd > nfds) nfds = ttyfd;
+ }
+ /* We don't use err because it's not really for errors, */
+ /* but for out of band data on the TCP socket, which, if it is */
+ /* to be handled at all, is handled in the tt*() routines */
+
+ nfds++; /* 0-based to 1-based */
+ debug(F101,"ttptycmd nfds","",nfds);
+ if (!nfds) {
+ debug(F100,"ttptycmd NO FDs set for select","",0);
+ if (have_pty) {
+ /* This is not right -- sleeping won't accomplish anything */
+ debug(F101,"ttptycmd msleep","",100);
+ msleep(100);
+ } else {
+ debug(F100,"ttptycmd no pty - quitting loop","",0);
+ break;
+ }
+ }
+ errno = 0;
+
+ if (seconds_to_wait > 0L) { /* Timeout in case nothing happens */
+ tv.tv_sec = seconds_to_wait; /* for a long time */
+ tv.tv_usec = 0L;
+ tv2 = &tv;
+ } else {
+ tv2 = NULL;
+ }
+ x = select(nfds, &in, &out, NULL, tv2);
+ debug(F101,"ttptycmd select","",x);
+ if (x < 0) {
+ if (errno == EINTR)
+ continue;
+ debug(F101,"ttptycmd select error","",errno);
+ break;
+ }
+ if (x == 0) {
+ debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait);
+ if (have_pty) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status A","",status);
+ if (status > -1) pexitstat = status;
+ have_pty = 0;
+ }
+ break;
+ }
+ /* We want to handle any pending writes first to make room */
+ /* for new incoming. */
+
+ if (FD_ISSET(ttyfd, &out)) { /* Can write to net? */
+ CHAR * s;
+ s = pbuf + pbuf_written; /* Current spot for sending */
+#ifdef TNCODE
+ if (is_tn) { /* ttol() doesn't double IACs */
+ CHAR c; /* Rewrite string with IACs doubled */
+ int i;
+ s = pbuf + pbuf_written; /* Source */
+ x = 0; /* Count */
+ for (i = 0; i < pbuf_avail - pbuf_written; i++) {
+ c = s[i]; /* Next character */
+ if (c == IAC) { /* If it's IAC */
+ dbuf[x++] = c; /* put another one */
+ debug(F000,">>> QUOTED IAC","",c);
+ } else if (c != 0x0a && out_prev == 0x0d) { /* Bare CR */
+ if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
+ c = 0x00;
+ dbuf[x++] = c;
+ debug(F000,">>> CR-NUL","",c);
+ }
+ }
+ dbuf[x++] = c; /* Copy and count it */
+ debug(F000,">>> char",ckitoa(in_state),c);
+ out_prev = c;
+ }
+ s = dbuf; /* New source */
+ } else
+#endif /* TNCODE */
+ x = pbuf_avail - pbuf_written; /* How much to send */
+
+ debug(F101,"ttptycmd bytes to send","",x);
+ x = ttol(s, x);
+ debug(F101,">>> ttol","",x);
+ if (x < 0) {
+ net_err++;
+ debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
+ x = 0;
+ }
+ write_net_bytes += x;
+ pbuf_written += x;
+ }
+ if (FD_ISSET(ptyfd, &out)) { /* Can write to pty? */
+ debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
+ errno = 0;
+#ifndef COMMENT
+ x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
+#else
+ /* Byte loop to rule out data overruns in the pty */
+ /* (it makes no difference) */
+ {
+ char *p = tbuf+tbuf_written;
+ int n = tbuf_avail - tbuf_written;
+ for (x = 0; x < n; x++) {
+ msleep(10);
+ if (write(ptyfd,&(p[x]),1) < 0)
+ break;
+ }
+ }
+#endif /* COMMENT */
+ debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
+ if (x > 0) {
+ tbuf_written += x;
+ write_pty_bytes += x;
+ } else {
+ x = 0;
+ pty_err++;
+ if (pexitstat < 0) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status B","",status);
+ if (status > -1) pexitstat = status;
+ have_pty = 0;
+ }
+ debug(F100,"ttptycmd +++ ptyfd write error","",0);
+ }
+ }
+ if (FD_ISSET(ttyfd, &in)) { /* Can read from net? */
+ tset++;
+ debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
+ n = in_chk(1,ttyfd);
+ debug(F101,"ttptycmd in_chk(ttyfd)","",n);
+ if (n < 0 || ttyfd == -1) {
+ debug(F101,"ttptycmd +++ ttyfd errno","",errno);
+ net_err++;
+ } else if (n > 0) {
+ if (n > PTY_TBUF_SIZE - tbuf_avail)
+ n = PTY_TBUF_SIZE - tbuf_avail;
+ debug(F101,"ttptycmd net read size adjusted","",n);
+ if (xlocal && netconn) {
+ /*
+ We have to use a byte loop here because ttxin()
+ does not decrypt or, for that matter, handle Telnet.
+ */
+ int c;
+ CHAR * p;
+ p = tbuf + tbuf_avail;
+ for (x = 0; x < n; x++) {
+ if ((c = ttinc(0)) < 0)
+ break;
+ if (!is_tn) { /* Not Telnet - keep all bytes */
+ *p++ = (CHAR)c;
+ debug(F000,"<<< char","",c);
+#ifdef TNCODE
+ } else { /* Telnet - must handle IAC and NVT */
+ debug(F000,"<<< char",ckitoa(in_state),c);
+ switch (c) {
+ case 0x00: /* NUL */
+ if (in_state == HAVE_CR) {
+ debug(F000,"<<< SKIP","",c);
+ } else {
+ *p++ = c;
+ debug(F000,"<<< Keep","",c);
+ }
+ in_state = 0;
+ break;
+ case 0x0d: /* CR */
+ if (!TELOPT_U(TELOPT_BINARY))
+ in_state = HAVE_CR;
+ *p++ = c;
+ debug(F000,"<<< Keep","",c);
+ break;
+#ifdef COMMENT
+ case 0x0f: /* Ctrl-O */
+ case 0x16: /* Ctrl-V */
+ *p++ = 0x16;
+ *p++ = c;
+ debug(F000,"<<< QUOT","",c);
+ break;
+#endif /* COMMENT */
+ case 0xff: /* IAC */
+ if (in_state == HAVE_IAC) {
+ debug(F000,"<<< KEEP","",c);
+ *p++ = c;
+ in_state = 0;
+ } else {
+ debug(F000,"<<< SKIP","",c);
+ in_state = HAVE_IAC;
+ }
+ break;
+ default: /* All others */
+ if (in_state == HAVE_IAC) {
+#ifdef COMMENT
+/*
+ tn_doop() will consume an unknown number of bytes and we'll overshoot
+ the for-loop. The only Telnet command I've ever seen arrive here is
+ a Data Mark, which comes when the remote protocol exits and the remote
+ job returns to its shell prompt. On the assumption it's a 1-byte command,
+ we don't write out the IAC or the command, and we clear the state. If
+ we called tn_doop() we'd have no way of knowing how many bytes it took
+ from the input stream.
+*/
+ int xx;
+ xx = tn_doop((CHAR)c,duplex,ttinc);
+ debug(F111,"<<< DOOP",ckctoa(c),xx);
+#else
+ debug(F101,"<<< DOOP","",c);
+#endif /* COMMENT */
+ in_state = 0;
+ } else {
+ *p++ = c;
+ debug(F000,"<<< keep","",c);
+ in_state = 0;
+ }
+ }
+#endif /* TNCODE */
+ }
+ }
+ ckmakmsg(msgbuf,500,
+ "ttptycmd read net [ttinc loop] errno=",
+ ckitoa(errno),
+ " count=",
+ ckitoa(x));
+ debug(F100,msgbuf,"",0);
+ } else {
+ x = ttxin(n,tbuf+tbuf_avail);
+ debug(F101,"ttptycmd ttxin x","",x);
+ }
+
+ if (x < 0) {
+ debug(F101,"ttptycmd read net error","",x);
+ net_err++;
+ }
+ tbuf_avail += x;
+ read_net_bytes += x;
+ }
+
+ } else
+ tnotset++;
+
+ if (FD_ISSET(ptyfd, &in)) { /* Read from pty? */
+ pset++;
+ debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
+#ifdef PTY_USE_NDELAY
+ n = PTY_PBUF_SIZE;
+#else
+ /*
+ This does not work on nonblocking channels
+ on certain platforms such as NetBSD.
+ */
+ n = pty_chk(ptyfd);
+#endif /* PTY_USE_NDELAY */
+ debug(F101,"ttptycmd pty_chk() n","",n);
+
+ if (n < 0)
+ n = 0;
+ if (n > 0) {
+ if (n > PTY_PBUF_SIZE - pbuf_avail)
+ n = PTY_PBUF_SIZE - pbuf_avail;
+ debug(F101,"ttptycmd pty read size adjusted","",n);
+ errno = 0;
+ x = read(ptyfd,pbuf+pbuf_avail,n);
+#ifdef DEBUG
+ if (deblog) {
+ ckmakmsg(msgbuf,500,
+ "ttptycmd read pty errno=",
+ ckitoa(errno),
+ " count=",
+ ckitoa(x));
+ debug(F100,msgbuf,"",0);
+ }
+#endif /* DEBUG */
+
+ if (x < 0 && errno == EAGAIN)
+ x = 0;
+
+ if (x < 0) { /* This works on Solaris and Linux */
+ pty_err++; /* but not NetBSD */
+ debug(F100,"TERMINATION TEST A","",0);
+#ifdef COMMENT
+ if (errno == EIO)
+ rc = 1;
+#endif /* COMMENT */
+ if (pexitstat < 0) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status C","",status);
+ if (status > -1) pexitstat = status;
+ }
+ have_pty = 0;
+ x = 0;
+ }
+ if (x == 0 && !pty_err) { /* This works on NetBSD but */
+ debug(F100,"TERMINATION TEST B","",0);
+ status = pexitstat > -1 ? pexitstat :
+ pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status D","",status);
+ if (status > -1) {
+ pexitstat = status;
+ pty_err++;
+ have_pty = 0;
+ } else { /* Select() lied */
+ pty_err = 0; /* pty still there but has nothing */
+ msleep(100); /* sleep a bit */
+ }
+ x = 0;
+ }
+ /* Hopefully the next two are no longer needed... */
+ if (!pty_err && (
+#ifndef PTY_USE_NDELAY
+ x < 1 || errno
+#else
+ errno != 0 && errno != EAGAIN
+#endif /* PTY_USE_NDELAY */
+ )) {
+ debug(F100,"TERMINATION TEST C","",0);
+ pty_err++;
+ debug(F101,"ttptycmd SET pty_err","",pty_err);
+ if (errno == EIO) /* errno == EIO is like EOF */
+ rc = 1;
+ if (x < 0)
+ x = 0;
+ }
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ pbuf[pbuf_avail + x] = '\0';
+ debug(F111,"ttptycmd added to pty buffer",
+ pbuf+pbuf_avail,x);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ pbuf_avail += x;
+ read_pty_bytes += x;
+ } else { /* n == 0 with blocking reads */
+ debug(F100,
+ "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
+ "",0);
+ }
+ } else
+ pnotset++;
+
+ /* If writes have caught up to reads, reset the buffers */
+
+ if (pbuf_written == pbuf_avail)
+ pbuf_written = pbuf_avail = 0;
+ if (tbuf_written == tbuf_avail)
+ tbuf_written = tbuf_avail = 0;
+
+ /* See if we can exit */
+
+ x1 = pbuf_avail - pbuf_written;
+ x2 = tbuf_avail - tbuf_written;
+
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
+
+ if (net_err) { /* Net error? */
+ debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
+ if (have_net) {
+ if (local) {
+ ttclos(0);
+ printf("?Connection closed\n");
+ }
+ have_net = 0;
+ }
+ debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
+ if (x1 == 0)
+ break;
+ }
+ if (pty_err) { /* Pty error? */
+ if (have_pty) {
+ if (pexitstat < 0) {
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status E","",status);
+ if (status > -1) pexitstat = status;
+ }
+ have_pty = 0;
+ }
+ if (x1 == 0 && x2 == 0) { /* If buffers are caught up */
+ rc = 1; /* set preliminary return to success */
+ debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
+ break; /* and exit the loop */
+ }
+ }
+ }
+ debug(F101,"ttptycmd +++ have_pty","",have_pty);
+ if (have_pty) { /* In case select() failed */
+#ifdef USE_CKUPTY_C
+ end_pty();
+ close(ptyfd);
+#else
+ close(slavefd);
+ close(masterfd);
+#endif /* USE_CKUPTY_C */
+ }
+ pty_master_fd = -1;
+ debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
+ if (pexitstat < 0) { /* Try one last time to get status */
+ status = pty_get_status(ptyfd,pty_fork_pid);
+ debug(F101,"ttptycmd pty_get_status F","",status);
+ if (status > -1) pexitstat = status;
+ }
+ debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
+ if (deblog) { /* Stats for debug log */
+ debug(F101,"ttptycmd +++ pset ","",pset);
+ debug(F101,"ttptycmd +++ pnotset","",pnotset);
+ debug(F101,"ttptycmd +++ tset ","",tset);
+ debug(F101,"ttptycmd +++ tnotset","",tnotset);
+
+ debug(F101,"ttptycmd +++ read_pty_bytes","",read_pty_bytes);
+ debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
+ debug(F101,"ttptycmd +++ read_net_bytes","",read_net_bytes);
+ debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
+ }
+/*
+ If we got the external protocol's exit status from waitpid(), we use that
+ to set our return code. If not, we fall back on whatever rc was previously
+ set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
+*/
+ if (save_sigchld) { /* Restore this if we changed it */
+ (VOID) signal(SIGCHLD,save_sigchld);
+ save_sigchld = NULL;
+ }
+ msleep(500);
+ x = kill(pty_fork_pid,SIGHUP); /* In case it's still there */
+ pty_fork_pid = -1;
+ debug(F101,"ttptycmd fork kill SIGHUP","",x);
+ if (pexitstat > -1)
+ rc = (pexitstat == 0 ? 1 : 0);
+ debug(F101,"ttptycmd +++ rc","",rc);
+ if (!local) { /* If in remote mode */
+ conres(); /* restore console to CBREAK mode */
+ concb((char)escchr);
+ }
+ return(rc);
+}
+#endif /* NETPTY */
+#endif /* SELECT */
+
+/* T T R U N C M D -- Redirect an external command over the connection. */
+
+/*
+ TTRUNCMD is the routine that was originally used for running external
+ protocols. It is very simple and works fine provided (a) the connection
+ is not encrypted, and (b) the external protocol uses standard i/o
+ (file descriptors 0 and 1) for file transfer.
+*/
+
+int
+ttruncmd(s) char *s; {
+ PID_T pid; /* pid of lower fork */
+ int wstat; /* for wait() */
+ int x;
+ int statusp;
+
+ if (ttyfd == -1) {
+ printf("?Sorry, device is not open\n");
+ return(0);
+ }
+ if (nopush) {
+ debug(F100,"ttruncmd fail: nopush","",0);
+ return(0);
+ }
+
+#ifdef NETPTY
+/***************
+ It might also be necessary to use the pty routine for other reasons,
+ e.g. because the external program does not use stdio.
+*/
+#ifdef NETCONN
+/*
+ If we have a network connection we use a different routine because
+ (a) if the connection is encrypted, the mechanism used here can't deal
+ with it; and (b) it won't handle any network protocols either, e.g.
+ Telnet, Rlogin, K5 U-to-U, etc. However, this routine works much
+ better (faster, more transparent) on serial connections and when
+ C-Kermit is in remote mode (i.e. is on the far end).
+*/
+ /* For testing always use this */
+ if (netconn)
+ return(ttptycmd(s));
+#endif /* NETCONN */
+
+/***************/
+#else /* NETPTY */
+ if (tt_is_secure()) {
+ printf("?Sorry, \
+external protocols over secure connections not supported in this OS.\n"
+ );
+ return(0);
+ }
+#endif /* NETPTY */
+
+ conres(); /* Make console normal */
+ pexitstat = -4;
+ if ((pid = fork()) == 0) { /* Make a child fork */
+ if (priv_can()) /* Child: turn off privs. */
+ exit(1);
+ dup2(ttyfd, 0); /* Give stdin/out to the line */
+ dup2(ttyfd, 1);
+ x = system(s);
+ debug(F101,"ttruncmd system",s,x);
+ _exit(x ? BAD_EXIT : 0);
+ } else {
+ SIGTYP (*istat)(), (*qstat)();
+ if (pid == (PID_T) -1) /* fork() failed? */
+ return(0);
+ istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
+ qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
+
+#ifdef COMMENT
+ while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
+#else /* Not COMMENT */
+ while (1) {
+ wstat = wait(&statusp);
+ debug(F101,"ttruncmd wait","",wstat);
+ if (wstat == pid || wstat == -1)
+ break;
+ }
+#endif /* COMMENT */
+
+ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
+ debug(F101,"ttruncmd wait statusp","",statusp);
+ debug(F101,"ttruncmd wait pexitstat","",pexitstat);
+ signal(SIGINT,istat); /* Restore interrupts */
+ signal(SIGQUIT,qstat);
+ }
+ concb((char)escchr); /* Restore console to CBREAK mode */
+ return(statusp == 0 ? 1 : 0);
+}
+#endif /* CK_REDIR */
+
+struct tm *
+#ifdef CK_ANSIC
+cmdate2tm(char * date, int gmt) /* date as "yyyymmdd hh:mm:ss" */
+#else
+cmdate2tm(date,gmt) char * date; int gmt;
+#endif
+{
+ /* date as "yyyymmdd hh:mm:ss" */
+ static struct tm _tm;
+ time_t now;
+
+ if (strlen(date) != 17 ||
+ date[8] != ' ' ||
+ date[11] != ':' ||
+ date[14] != ':')
+ return(NULL);
+
+ time(&now);
+ if (gmt)
+ _tm = *gmtime(&now);
+ else
+ _tm = *localtime(&now);
+ _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
+ (date[2]-'0')*10 + (date[3]-'0')-1900;
+ _tm.tm_mon = (date[4]-'0')*10 + (date[5]-'0')-1;
+ _tm.tm_mday = (date[6]-'0')*10 + (date[7]-'0');
+ _tm.tm_hour = (date[9]-'0')*10 + (date[10]-'0');
+ _tm.tm_min = (date[12]-'0')*10 + (date[13]-'0');
+ _tm.tm_sec = (date[15]-'0')*10 + (date[16]-'0');
+
+ /* Should we set _tm.tm_isdst to -1 here? */
+
+ _tm.tm_wday = 0;
+ _tm.tm_yday = 0;
+
+ return(&_tm);
+}
+
+#ifdef OXOS
+#undef kill
+#endif /* OXOS */
+
+#ifdef OXOS
+int
+priv_kill(pid, sig) int pid, sig; {
+ int i;
+
+ if (priv_on())
+ debug(F100,"priv_kill priv_on failed","",0);
+ i = kill(pid, sig);
+ if (priv_off())
+ debug(F100,"priv_kill priv_off failed","",0);
+ return(i);
+}
+#endif /* OXOS */
+
+#ifdef BEOSORBEBOX
+/* #ifdef BE_DR_7 */
+/*
+ alarm() function not supplied with Be OS DR7 - this one contributed by
+ Neal P. Murphy.
+*/
+
+/*
+ This should mimic the UNIX/POSIX alarm() function well enough, with the
+ caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
+ and wait for the alarm thread to finish.
+*/
+unsigned int
+alarm(unsigned int seconds) {
+ long time_left = 0;
+
+/* If an alarm is active, turn it off, saving the unused time */
+ if (alarm_thread != -1) {
+ /* We'll be generous and count partial seconds as whole seconds. */
+ time_left = alarm_struct.time -
+ ((system_time() - time_started) / 1000000.0);
+
+ /* Kill the alarm thread */
+ kill_thread (alarm_thread);
+
+ /* We need to clean up as though the alarm occured. */
+ time_started = 0;
+ alarm_struct.thread = -1;
+ alarm_struct.time = 0;
+ alarm_expired();
+ }
+
+/* Set a new alarm clock, if requested. */
+ if (seconds > 0) {
+ alarm_struct.thread = find_thread(NULL);
+ alarm_struct.time = seconds;
+ time_started = system_time();
+ alarm_thread = spawn_thread (do_alarm,
+ "alarm_thread",
+ B_NORMAL_PRIORITY,
+ (void *) &alarm_struct
+ );
+ resume_thread (alarm_thread);
+ }
+
+/* Now return [unused time | 0] */
+ return ((unsigned int) time_left);
+}
+
+/*
+ This function is the departure from UNIX/POSIX alarm handling. In the case
+ of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
+ handler. When Be implements alarm(), this function call can be eliminated
+ from user's SIGALRM signal handlers.
+*/
+
+void
+alarm_expired(void) {
+ long ret_val;
+
+ if (alarm_thread != -1) {
+ wait_for_thread (alarm_thread, &ret_val);
+ alarm_thread = -1;
+ }
+}
+
+/*
+ This is the function that snoozes the requisite number of seconds and then
+ SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
+ uses thread_id; currently they are both typdef'ed as long, but I'll do the
+ cast anyway. This function is run in a separate thread.
+*/
+
+long
+do_alarm (void *alarm_struct) {
+ snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
+ kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
+ time_started = 0;
+ ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
+ ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
+}
+/* #endif */ /* BE_DR_7 */
+#endif /* BEOSORBEBOX */
+
+#ifdef Plan9
+
+int
+p9ttyctl(char letter, int num, int param) {
+ char cmd[20];
+ int len;
+
+ if (ttyctlfd < 0)
+ return -1;
+
+ cmd[0] = letter;
+ if (num)
+ len = sprintf(cmd + 1, "%d", param) + 1;
+ else {
+ cmd[1] = param;
+ len = 2;
+ }
+ if (write(ttyctlfd, cmd, len) == len) {
+ cmd[len] = 0;
+ /* fprintf(stdout, "wrote '%s'\n", cmd); */
+ return 0;
+ }
+ return -1;
+}
+
+int
+p9ttyparity(char l) {
+ return p9ttyctl('p', 0, l);
+}
+
+int
+p9tthflow(int flow, int status) {
+ return p9ttyctl('m', 1, status);
+}
+
+int
+p9ttsspd(int cps) {
+ if (p9ttyctl('b', 1, cps * 10) < 0)
+ return -1;
+ ttylastspeed = cps * 10;
+ return 0;
+}
+
+int
+p9openttyctl(char *ttname) {
+ char name[100];
+
+ if (ttyctlfd >= 0) {
+ close(ttyctlfd);
+ ttyctlfd = -1;
+ ttylastspeed = -1;
+ }
+ sprintf(name, "%sctl", ttname);
+ ttyctlfd = open(name, 1);
+ return ttyctlfd;
+}
+
+int
+p9concb() {
+ if (consctlfd >= 0) {
+ if (write(consctlfd, "rawon", 5) == 5)
+ return 0;
+ }
+ return -1;
+}
+
+int
+p9conbin() {
+ return p9concb();
+}
+
+int
+p9conres() {
+ if (consctlfd >= 0) {
+ if (write(consctlfd, "rawoff", 6) == 6)
+ return 0;
+ }
+ return -1;
+}
+
+int
+p9sndbrk(int msec) {
+ if (ttyctlfd >= 0) {
+ char cmd[20];
+ int i = sprintf(cmd, "k%d", msec);
+ if (write(ttyctlfd, cmd, i) == i)
+ return 0;
+ }
+ return -1;
+}
+
+int
+conwrite(char *buf, int n) {
+ int x;
+ static int length = 0;
+ static int holdingcr = 0;
+ int normal = 0;
+ for (x = 0; x < n; x++) {
+ char c = buf[x];
+ if (c == 007) {
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ normal = 0;
+ }
+ /* write(noisefd, "1000 300", 8); */
+ holdingcr = 0;
+ } else if (c == '\r') {
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ normal = 0;
+ }
+ holdingcr = 1;
+ } else if (c == '\n') {
+ write(1, buf + (x - normal), normal + 1);
+ normal = 0;
+ length = 0;
+ holdingcr = 0;
+ } else if (c == '\b') {
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ normal = 0;
+ }
+ if (length) {
+ write(1, &c, 1);
+ length--;
+ }
+ holdingcr = 0;
+ } else {
+ if (holdingcr) {
+ char b = '\b';
+ while (length-- > 0)
+ write(1, &b, 1);
+ length = 0; /* compiler bug */
+ }
+ holdingcr = 0;
+ normal++;
+ }
+ }
+ if (normal) {
+ write(1, buf + (x - normal), normal);
+ length += normal;
+ }
+ return n;
+}
+
+void
+conprint(char *fmt, ...) {
+ static char buf[1000]; /* not safe if on the stack */
+
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ i = vsprintf(buf, fmt, ap);
+ conwrite(buf, i);
+}
+#endif /* Plan9 */
+
+/* fprintf, printf, perror replacements... */
+
+/* f p r i n t f */
+
+#ifdef UNIX
+#ifdef CK_ANSIC
+#include <stdarg.h>
+#else /* CK_ANSIC */
+#ifdef __GNUC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif /* __GNUC__ */
+#endif /* CK_ANSIC */
+#ifdef fprintf
+#undef fprintf
+static char str1[4096];
+static char str2[4096];
+int
+#ifdef CK_ANSIC
+ckxfprintf(FILE * file, const char * format, ...)
+#else /* CK_ANSIC */
+ckxfprintf(va_alist) va_dcl
+#endif /* CK_ANSIC */
+/* ckxfprintf */ {
+ int i, j, len, got_cr;
+ va_list args;
+ int rc = 0;
+
+#ifdef CK_ANSIC
+ va_start(args, format);
+#else /* CK_ANSIC */
+ char * format;
+ FILE * file;
+ va_start(args);
+ file = va_arg(args,FILE *);
+ format = va_arg(args,char *);
+#endif /* CK_ANSIC */
+
+ if (!inserver || (file != stdout && file != stderr && file != stdin)) {
+ rc = vfprintf(file,format,args);
+ } else {
+ unsigned int c;
+ rc = vsprintf(str1, format, args);
+ len = strlen(str1);
+ if (len >= sizeof(str1)) {
+ debug(F101,"ckxfprintf() buffer overflow","",len);
+ doexit(BAD_EXIT,1);
+ }
+ for (i = 0, j = 0, got_cr = 0;
+ i < len && j < sizeof(str1)-2;
+ i++, j++ ) {
+ /* We can't use 255 as a case label because of signed chars */
+ c = (unsigned)(str1[i] & 0xff);
+#ifdef TNCODE
+ if (c == 255) {
+ if (got_cr && !TELOPT_ME(TELOPT_BINARY))
+ str2[j++] = '\0';
+ str2[j++] = IAC;
+ str2[j] = IAC;
+ got_cr = 0;
+ } else
+#endif /* TNCODE */
+ switch (c) {
+ case '\r':
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 1;
+ break;
+ case '\n':
+ if (!got_cr)
+ str2[j++] = '\r';
+ str2[j] = str1[i];
+ got_cr = 0;
+ break;
+ default:
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 0;
+ }
+ }
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+#ifdef CK_ENCRYPTION
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(str2,j);
+#endif /* TNCODE */
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (inserver && (ssl_active_flag || tls_active_flag)) {
+ /* Write using SSL */
+ char * p = str2;
+ ssl_retry:
+ if (ssl_active_flag)
+ rc = SSL_write(ssl_con, p, j);
+ else
+ rc = SSL_write(tls_con, p, j);
+ debug(F111,"ckxfprintf","SSL_write",rc);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
+ case SSL_ERROR_NONE:
+ if (rc == j)
+ break;
+ p += rc;
+ j -= rc;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_SYSCALL:
+ if (rc != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ rc = 0;
+ }
+ } else
+#endif /* CK_SSL */
+ fwrite(str2,sizeof(char),j,stdout);
+ }
+ va_end(args);
+ return(rc);
+}
+#endif /* fprintf */
+
+/* p r i n t f */
+
+#ifdef printf
+#undef printf
+int
+#ifdef CK_ANSIC
+ckxprintf(const char * format, ...)
+#else /* CK_ANSIC */
+ckxprintf(va_alist) va_dcl
+#endif /* CK_ANSIC */
+/* ckxprintf */ {
+ int i, j, len, got_cr;
+ va_list args;
+ int rc = 0;
+
+#ifdef CK_ANSIC
+ va_start(args, format);
+#else /* CK_ANSIC */
+ char * format;
+ va_start(args);
+ format = va_arg(args,char *);
+#endif /* CK_ANSIC */
+
+ if (!inserver) {
+ rc = vprintf(format, args);
+ } else {
+ unsigned int c;
+ rc = vsprintf(str1, format, args);
+ len = strlen(str1);
+ if (len >= sizeof(str1)) {
+ debug(F101,"ckxprintf() buffer overflow","",len);
+ doexit(BAD_EXIT,1);
+ }
+ for (i = 0, j = 0, got_cr=0;
+ i < len && j < sizeof(str1)-2;
+ i++, j++ ) {
+ c = (unsigned)(str1[i] & 0xff);
+#ifdef TNCODE
+ if (c == 255) {
+ if (got_cr && !TELOPT_ME(TELOPT_BINARY))
+ str2[j++] = '\0';
+ str2[j++] = IAC;
+ str2[j] = IAC;
+ got_cr = 0;
+ } else
+#endif /* TNCODE */
+ switch (c) {
+ case '\r':
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 1;
+ break;
+ case '\n':
+ if (!got_cr)
+ str2[j++] = '\r';
+ str2[j] = str1[i];
+ got_cr = 0;
+ break;
+ default:
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+ str2[j] = str1[i];
+ got_cr = 0;
+ break;
+ }
+ }
+ if (got_cr
+#ifdef TNCODE
+ && !TELOPT_ME(TELOPT_BINARY)
+#endif /* TNCODE */
+ )
+ str2[j++] = '\0';
+#ifdef CK_ENCRYPTION
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_ENCRYPTION))
+ ck_tn_encrypt(str2,j);
+#endif /* TNCODE */
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (inserver && (ssl_active_flag || tls_active_flag)) {
+ char * p = str2;
+ /* Write using SSL */
+ ssl_retry:
+ if (ssl_active_flag)
+ rc = SSL_write(ssl_con, p, j);
+ else
+ rc = SSL_write(tls_con, p, j);
+ debug(F111,"ckxprintf","SSL_write",rc);
+ switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
+ case SSL_ERROR_NONE:
+ if (rc == j)
+ break;
+ p += rc;
+ j -= rc;
+ goto ssl_retry;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_SYSCALL:
+ if (rc != 0)
+ return(-1);
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ rc = 0;
+ }
+ } else
+#endif /* CK_SSL */
+ rc = fwrite(str2,sizeof(char),j,stdout);
+ }
+ va_end(args);
+ return(rc);
+}
+#endif /* printf */
+
+/* p e r r o r */
+
+#ifdef perror
+#undef perror
+_PROTOTYP(char * ck_errstr,(VOID));
+#ifdef NEXT
+void
+#else
+#ifdef CK_SCOV5
+void
+#else
+int
+#endif /* CK_SCOV5 */
+#endif /* NEXT */
+#ifdef CK_ANSIC
+ckxperror(const char * str)
+#else /* CK_ANSIC */
+ckxperror(str) char * str;
+#endif /* CK_ANSIC */
+/* ckxperror */ {
+ char * errstr = ck_errstr();
+#ifndef NEXT
+#ifndef CK_SCOV5
+ return
+#endif /* CK_SCOV5 */
+#endif /* NEXT */
+ ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
+}
+#endif /* perror */
+#endif /* UNIX */
+
+#ifdef MINIX2
+
+/* Minix doesn't have a gettimeofday call (but MINIX3 does).
+ * We fake one here using time(2)
+ */
+
+#ifndef MINIX3
+int
+gettimeofday(struct timeval *tp, struct timezone *tzp) {
+ tp->tv_usec = 0L; /* Close enough for horseshoes */
+ if(time(&(tp->tv_sec))==-1)
+ return(-1);
+ return(0);
+}
+#endif /* MINIX3 */
+
+#ifndef MINIX3
+int
+readlink(const char *path, void *buf, size_t bufsiz) {
+ errno = ENOSYS;
+ return(-1);
+}
+#endif /* MINIX3 */
+
+#endif /* MINIX2 */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckututor.txt b/ckermit-9.0.302-build/ckermit-9.0.302/ckututor.txt
new file mode 100644
index 0000000..ef2aebe
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckututor.txt
@@ -0,0 +1,1948 @@
+
+ [1]The Columbia Crown The Kermit Project | Columbia University
+ 612 West 115th Street, New York NY 10025 USA o [2]kermit@columbia.edu
+ ...since 1981
+ [3]Home [4]Kermit 95 [5]C-Kermit [6]Scripts [7]Current [8]New [9]FAQ
+ [10]Support
+
+ C-KERMIT 9.0 UNIX MANUAL PAGE AND TUTORIAL
+
+ Frank da Cruz
+ [11]The Kermit Project, [12]Columbia University
+
+ [ [13]PDF version ] [ [14]Nroff version ]
+
+ This document is intended to give the beginner sufficient
+ information to make basic (if not advanced) use of C-Kermit 9.0.
+ Although it might be rather long for a Unix manual page (about 1600
+ lines), it's still far shorter than the [15]C-Kermit manual, which
+ should be consulted for advanced topics such as customization,
+ character-sets, scripting, etc. We also attempt to provide a clear
+ structural overview of C-Kermit's many capabilities, functional
+ areas, states, and modes and their interrelation, that should be
+ helpful to beginners and veterans alike, as well as to those
+ upgrading to the new release. Thanks to Christine Gianone for her
+ work on this document before she was laid off in 2005.
+
+ Most recent update: Fri Jul 1 14:12:31 2011
+
+CONTENTS
+
+ * [16]DESCRIPTION
+ * [17]SYNOPSIS
+ * [18]OPTIONS
+ * [19]COMMAND LANGUAGE
+ * [20]INITIALIZATION FILE
+ * [21]MODES OF OPERATION
+ * [22]MAKING CONNECTIONS
+ * [23]TRANSFERRING FILES WITH KERMIT
+ * [24]KERMIT CLIENT/SERVER CONNECTIONS
+
+ * [25]KERMIT'S BUILT-IN FTP AND HTTP CLIENTS
+ * [26]INTERNET KERMIT SERVICE
+ * [27]SECURITY
+ * [28]ALTERNATIVE COMMAND-LINE PERSONALITIES
+ * [29]LICENSE
+ * [30]OTHER TOPICS
+ * [31]DOCUMENTATION AND UPDATES
+ * [32]FILES
+ * [33]AUTHORS
+
+DESCRIPTION
+
+ [34]Top [35]Contents [36]Next
+
+ [37]C-Kermit is an all-purpose communications software package from the
+ [38]Kermit Project at [39]Columbia University that:
+
+ * Is portable to many platforms, Unix and non-Unix alike.
+ * Can make both serial and network connections.
+ * Can conduct interactive terminal sessions over its connection.
+ * Can transfer text or binary files over the same connection.
+ * Can convert text-file character sets in terminal mode or file
+ transfer.
+ * Is customizable in every aspect of its operation.
+
+ C-Kermit is a modem program, a Telnet client, an Rlogin client, an FTP
+ client, an HTTP client, and on selected platforms, also an X.25 client.
+ It can make its own secure Internet connections using IETF-approved
+ security methods including Kerberos IV, Kerberos V, SSL/TLS, and SRP
+ and it can also make SSH (Secure Shell) connections through your
+ external SSH client application. It can be the far-end file-transfer or
+ client/server partner of your desktop Kermit client. It can also accept
+ incoming dialed and network connections. It can even be installed as an
+ Internet service on its own standard TCP socket, 1649 [[40]RFC2839,
+ [41]RFC2840].
+
+ And perhaps most important, everything you can do "by hand"
+ (interactively) with C-Kermit, can be "scripted" (automated) using its
+ built-in cross-platform transport-independent script programming
+ language, which happens to be identical to its interactive command
+ language.
+
+ This manual page offers an overview of C-Kermit 9.0 for Unix ("Unix" is
+ an operating system family that includes AIX, DG/UX, FreeBSD, HP-UX,
+ IRIX, Linux, Mac OS X, NetBSD, OpenBSD, Open Server, Open Unix, QNX,
+ Solaris, SunOS, System V R3, System V R4, Tru64 Unix, Unixware, Xenix,
+ and many others). For thorough coverage, please consult the published
+ C-Kermit manual and supplements (see [42]DOCUMENTATION below). For
+ further information about C-Kermit, Kermit software for other
+ platforms, and Kermit manuals, visit the Kermit Project website:
+
+ [43]http://www.columbia.edu/kermit/
+
+ This is a longer-than-average manual page, and yet it barely scratches
+ the surface. Don't be daunted. C-Kermit is a large and complex package,
+ evolving over decades of practice and experience, but that doesn't mean
+ it's hard to learn or use. Its most commonly used functions are
+ explained here with pointers to additional information elsewhere.
+
+ [44]Kermit Home [45]C-Kermit Home [46]C-Kermit FAQ
+
+SYNOPSIS
+
+ [47]Top [48]Contents [49]Next [50]Previous
+
+ Usage: kermit [filename] [-x arg [-x arg]...[-yyy]..] [ {=,--,+} text
+ ] ]
+ Or: kermit URL
+
+ * -x is an option requiring an argument;
+ * -y is an option with no argument.
+
+ If the first command-line argument is the name of a file,
+ interactive-mode commands are executed from the file. The '=' (or "--")
+ argument tells Kermit not to parse the remainder of the command line,
+ but to make the words following '=' available as \%1, \%2, ... \%9. The
+ "+" argument is like "=" but for use in "kerbang scripts" (explained
+ [51]below). A second command-line format allows the one and only
+ argument to be a [52]Telnet, FTP, HTTP, or IKSD URL.
+
+ Order of execution:
+
+ 1. [53]The command file (if any).
+ 2. [54]The initialization file, if any, unless suppressed with -Y.
+ 3. [55]The customization file (if it is executed by the initialization
+ file).
+ 4. [56]The command-line URL (if any, and if so, execution stops here).
+ 5. [57]Command-line options (if any).
+ 6. [58]Interactive commands.
+
+ Some command-line options can cause actions (such as -s to send a
+ file); others just set parameters. If any action options are included
+ on the command line, Kermit exits when finished unless also given the
+ -S ("stay") option. If no action options are given, no initialization
+ or command files contained an EXIT or QUIT command, and no fatal errors
+ occurred, Kermit issues its prompt and waits for you to type commands.
+
+ Bear in mind that C-Kermit can be built with selected features
+ disabled, and also that certain features are not available on all
+ platforms. For example, C-Kermit can't be built with TCP/IP support
+ on a platform that does not have TCP/IP header files and libraries
+ (and even if Kermit does include TCP/IP support, it can't be used to
+ make TCP/IP connections on a computer that does not have a TCP/IP
+ stack installed). If your version of C-Kermit lacks a feature
+ mentioned here, use its SHOW FEATURES command to see what might have
+ been excluded.
+
+ C-Kermit has three kinds of commands: regular single-letter
+ command-line options, extended-format command-line options, and
+ interactive commands.
+
+ [59]Kermit Home [60]C-Kermit Home [61]C-Kermit FAQ
+
+OPTIONS
+
+ [62]Top [63]Contents [64]Next [65]Previous <- (Most people should
+ click Next to skip around this section...)
+
+ Like most Unix commands, C-Kermit can be be given options on the
+ command line. But C-Kermit also can be used interactively by giving it
+ [66]commands composed of words, which are more intuitive than cryptic
+ command-line options, and more flexible too. In other words, you don't
+ have to use C-Kermit's command-line options, but they are available if
+ you want to. (By the same token, you don't have to use its interactive
+ commands either -- you can use either or both in any combination.)
+
+ C-Kermit is generally installed in the PATH as "kermit", and therefore
+ is invoked by typing the word "kermit" (lowercase) at the shell prompt,
+ and then pressing the Return or Enter key. If you wish to include
+ command-line options, put them after the word "kermit" but before
+ pressing Return or Enter, separated by spaces, for example:
+
+ $ kermit -s ckermit.tar.gz
+
+ ('$' is the shell prompt; "kermit -s ckermit.tar.gz" is what you type,
+ followed by Return or Enter.)
+
+ Here is a list of C-Kermit's single-letter command-line options, which
+ start with a single dash (-), in ASCII ("alphabetical") order.
+ Alphabetic case is significant (-A is not the same as -a). The Action?
+ column contains Y for action options and N for non-action options.
+
+ Option Action? Description
+ -0 N (digit zero) 100% transparent Connect state for "in-the-middle"
+ operation: 8 bits, no parity, no escape character, everything passes
+ through.
+ -8 N (digit eight) Connection is 8-bit clean (this is the default in
+ C-Kermit 9.0). Equivalent to the EIGHTBIT command, which in turn is a
+ shortcut for SET TERMINAL BYTESIZE 8, SET COMMAND BYTESIZE 8, SET
+ PARITY NONE.
+ -9 arg N (digit nine) Make a connection to an FTP server. Equivalent to
+ the FTP OPEN command.
+ Argument: IP-address-or-hostname[:optional-TCP-port].
+ NOTE: C-Kermit also has a separate FTP command-line personality, with
+ regular FTP-like command-line syntax. [67]More about this below.
+ -A N Kermit is to be started as an Internet service (IKSD) (only from
+ inetd.conf).
+ -B N Kermit is running in Batch or Background (no controlling
+ terminal). To be used in case Kermit doesn't automatically sense its
+ background status. Equivalent to the SET BACKGROUND ON command.
+ -C arg N Interactive-mode Commands to be executed.
+ Argument: Commands separated by commas, list in doublequotes.
+ -D arg N Delay before starting to send in Remote mode. Equivalent to
+ the SET DELAY command.
+ Argument: Number of seconds.
+ -E N Exit automatically when connection closes. Equivalent to SET EXIT
+ ON-DISCONNECT ON.
+ -F arg N Use an open TCP connection.
+ Argument: Numeric file descriptor of open TCP connection.
+ Also see: -j, -J.
+ -G arg Y Get file(s) from server, send contents to standard output,
+ which normally would be piped to another process.
+ Argument: Remote file specification, in quotes if it contains
+ metacharacters.
+ Also see: -g, -k.
+ -H N Suppress program startup Herald and greeting.
+ -I N Tell Kermit it has a reliable connection, to force streaming to be
+ used where it normally would not be. Equivalent to the SET RELIABLE ON
+ command.
+ -J arg N "Be like Telnet." Like -j but implies -E.
+ Argument: IP hostname/address optionally followed by service.
+ NOTE: C-Kermit also has a separate Telnet command-line personality,
+ with regular Telnet-like command-line syntax. [68]More about this
+ below.
+ -L N Recursive directory descent for files in -s option.
+ -M arg N My user name (for use with Telnet, Rlogin, FTP, etc).
+ Equivalent to the SET LOGIN USER command.
+ Argument: Username string.
+ -O Y (Uppercase letter O) Be a server for One command only. Also see:
+ -x.
+ -P N Don't convert file (Path) names of transferred files. Equivalent
+ to SET FILE NAMES LITERAL.
+ -Q N Quick Kermit protocol settings. Equivalent to the FAST command.
+ This is the default in C-Kermit 7.0 and later.
+ -R N Remote-only (this just makes IF REMOTE true).
+ -S N Stay (enter command parser after action options).
+ -T N Force Text mode for file transfer; implies -V. Equivalent to SET
+ TRANSFER MODE MANUAL, SET FILE TYPE TEXT.
+ -V N Disable automatic per-file text/binary switching. Equivalent to
+ SET TRANSFER MODE MANUAL.
+ -Y N Skip (don't execute) the initialization file.
+ -a arg N As-name for file(s) in -s, -r, or -g.
+ Argument: As-name string (alternative filename). When receiving files,
+ this can be a directory name.
+ -b arg N Speed for serial device. Equivalent to SET SPEED.
+ Argument: Numeric Bits per second for serial connections.
+ -c Y Enter Connect state before transferring files.
+ -d N Create a debug.log file with detailed debugging information (a
+ second -d adds timestamps). Equivalent to LOG DEBUG but takes effect
+ sooner.
+ -e arg N Maximum length for incoming Kermit file-transfer packets.
+ Equivalent to SET RECEIVE PACKET-LENGTH.
+ Argument: Length in bytes.
+ -f Y Send a FINISH command to a Kermit server.
+ -g arg N Get file(s) from a Kermit server.
+ Argument: File specification on other computer, in quotes if it
+ contains metacharacters. Equivalent to GET.
+ Also see: -a, -G, -r.
+ -h Y Print Help text for single-letter command-line options (pipe thru
+ 'more' to prevent scrolling).
+ -i N Force binary (Image) mode for file transfer; implies -V.
+ Equivalent to SET TRANSFER MODE MANUAL, SET FILE TYPE BINARY.
+ -j arg N Make a TCP/IP connection.
+ Argument: IP host name/address and optional service name or number.
+ Equivalent to the TELNET command.
+ Also see: -J, -F.
+ -k Y Receive file(s) to standard output, which normally would be piped
+ to another process.
+ Also see: -r, -G.
+ -l arg N (Lowercase letter L) Make a connection on the given serial
+ communications device. Equivalent to the SET LINE (SET PORT) command.
+ Argument: Serial device name, e.g. /dev/ttyS0.
+ -m arg N Modem type for use with the -l device. Equivalent to the SET
+ MODEM TYPE command.
+ Argument: Modem name as in SET MODEM TYPE command, e.g. "usrobotics".
+ -n Y Enter Connect state after transferring files (historical).
+ -p arg N Parity. Equivalent to the SET PARITY command.
+ Argument: One of the following: e(ven), o(dd), m(ark), n(one), s(pace).
+ -q N Quiet (suppress most messages). Equivalent to SET QUIET ON.
+ -r Y Receive file(s). Equivalent to the RECEIVE command.
+ Argument: (none, but see -a)
+ -s arg N Send file(s).
+ Argument: One or more local file specifications. Equivalent to the SEND
+ command.
+ Also see: -a.
+ -t N (Historical) Xon (Ctrl-Q) Turnaround character for half-duplex
+ connections (used on serial linemode connections to old mainframes).
+ Equivalent to SET DUPLEX HALF, SET HANDSHAKE XON.
+ -v arg N Window size for Kermit protocol (ignored when streaming).
+ Equivalent to SET WINDOW-SIZE.
+ Argument: Number, 1 to 32.
+ -w N Incoming files Write over existing files. Equivalent to SET FILE
+ COLLISION OVERWRITE.
+ -x Y Enter server mode. Equivalent to the SERVER command. Also see: -O.
+ -y arg N Alternative initialization file.
+ Argument: Filename.
+ -z N Force foreground behavior. To be used in case Kermit doesn't
+ automatically sense its foreground status. Equivalent to the SET
+ BACKGROUND OFF command.
+
+ Extended command-line options (necessary because single-letter ones are
+ about used up) start with two dashes (--), with words rather than
+ single letters as option names. If an extended option takes an
+ argument, it is separated from the option word by a colon (:). Extended
+ options include:
+
+ Option Description
+ --bannerfile:filename File to display upon startup or IKSD login.
+ --cdfile:filename File to be sent for display to the client when server
+ changes directory (filename is relative to the changed-to directory).
+ --cdmessage:{on,off} Enable/disable the server CD message feature.
+ --help Prints usage message for extended options.
+ --helpfile:filename Designates a file containing custom text to replace
+ the top-level HELP command.
+ --nointerrupts Disables keyboard interrupts.
+ --noperms Disables the Kermit protocol file Permissions attribute, to
+ prevent transmission of file permissions (protection) from sender to
+ receiver.
+
+ Plus several other [69]IKSD-Only options.
+
+ See the [70]file-transfer section for examples of command-line
+ invocation.
+
+COMMAND LANGUAGE
+
+ [71]Top [72]Contents [73]Next [74]Previous
+
+ * [75]Command Files, Macros, and Scripts
+ * [76]Command List
+
+ C-Kermit's interactive command language is the subject of a
+ [77]622-page book and another several hundred pages of updates, far too
+ much for a manual page. But it's not hard to get started. At the shell
+ prompt, just type "kermit" to get C-Kermit's interactive command
+ prompt:
+
+ $ kermit
+ (/current/directory) C-Kermit>
+
+ Begin by typing "help" (and then press the Return or Enter key) for a
+ top-level overview, read it, and go from there. Your second command
+ should probably be "intro" (introduction). Note the prompt shows your
+ current directory (unless you tell Kermit to prompt you with something
+ else).
+
+ Interactive commands are composed mainly of regular English words,
+ usually in the form of imperative sentences, such as:
+
+ send oofa.txt
+
+ which tells Kermit to send (transfer) the file whose name is oofa.txt,
+ or:
+
+ set transfer mode automatic
+
+ which sets Kermit's "transfer mode" to "automatic" (whatever that
+ means).
+
+ While typing commands, you can abbreviate, ask for help (by pressing
+ the "?" key anywhere in a command), complete keywords or filenames
+ (with the Tab or Esc key), and edit your typing with Backspace or
+ Delete, Ctrl-W, Ctrl-U, etc. You can also recall previous commands,
+ save your command history, and who knows what else. Give the INTRO
+ command for details.
+
+ C-Kermit has hundreds of commands, and they can be issued in infinite
+ variety and combinations, including commands for:
+
+ * Making connections (SET LINE, DIAL, TELNET, SSH, FTP, CONNECT, ...)
+ * Breaking connections (HANGUP, CLOSE)
+ * Transferring files (SEND, GET, RECEIVE, MOVE, RESEND, ...)
+ * Establishing preferences (SET)
+ * Displaying preferences (SHOW)
+ * Managing local files (CD, DELETE, MKDIR, DIRECTORY, RENAME, TYPE,
+ ...)
+ * Managing remote files (RCD, RDEL, RMKDIR, RDIR, ...)
+ * Using local files (FOPEN, FCLOSE, FREAD, FWRITE)
+ * Programming (TAKE, DEFINE, IF, FOR, WHILE, SWITCH, DECLARE, ...)
+ * Interacting with the user (ECHO, ASK, ...)
+ * Interacting with a remote computer (INPUT, OUTPUT, ...)
+ * Interacting with local programs (RUN, EXEC, PTY, ...)
+ * Logging things (LOG SESSION, LOG PACKETS, LOG DEBUG, ...)
+
+ And of course QUIT or EXIT to get out and HELP to get help, and for
+ programmers: loops, decision making, variables, arrays, associative
+ arrays, integer and floating point arithmetic, macros, built-in and
+ user-defined functions, string manipulation, pattern matching, block
+ structure, scoping, recursion, and all the rest. To get a list of all
+ C-Kermit's commands, type a question mark (?) at the prompt. To get a
+ description of any command, type HELP followed by the name of the
+ command, for example:
+
+ help send
+
+ The command interruption character is Ctrl-C (hold down the Ctrl key
+ and press the C key).
+
+ The command language "escape character", used to introduce variable
+ names, function invocations, and so on, is backslash (\). If you need
+ to include a literal backslash in a command, type two of them, e.g.:
+
+ get c:\\k95\\k95custom.ini
+
+Command Files, Macros, and Scripts
+
+ A file containing Kermit commands is called a Kermit command file or
+ Kermit script. It can be executed with Kermit's TAKE command:
+
+ (/current/dir) C-Kermit> take commandfile
+
+ (where "commandfile" is the name of the command file). Please don't
+ pipe a command file into Kermit's standard input (which might or might
+ not work); if you have Kermit commands in a file, tell Kermit to TAKE
+ the file.
+
+ In Unix only, a Kermit command file can also be executed directly by
+ including a "kerbang" line as the first line of the file:
+
+ #!/usr/local/bin/kermit +
+
+ That is, a top line that starts with "#!", followed immediately by the
+ full path of the Kermit executable, and then, if the Kermit script is
+ to be given arguments on the command line, a space and a plus sign. The
+ script file must also have execute permission:
+
+ chmod +x commandfile
+
+ Except for the " +" part, this is exactly the same as you would do for
+ a shell script, a Perl script, etc. Here's a simple but useless example
+ script that regurgitates its arguments (up to three of them):
+
+ #!/usr/local/bin/kermit +
+ if defined \%1 echo "Argument 1: \%1"
+ if defined \%2 echo "Argument 2: \%2"
+ if defined \%3 echo "Argument 3: \%3"
+ if defined \%4 echo "etc..."
+ exit
+
+ If this file is stored in your current directory as "commandfile",
+ then:
+
+ ./commandfile one two three four five
+
+ prints:
+
+ Argument 1: one
+ Argument 2: two
+ Argument 3: three
+ etc...
+
+ This illustrates the basic structure of a standalone Kermit script: the
+ "kerbang line", then some commands. It should end with "exit" unless
+ you want the Kermit prompt to appear when it is finished. \%1 is the
+ first argument, \%2 the second, and so on.
+
+ You can also create your own commands by defining named macros composed
+ of other Kermit commands (or macros). Here's a simple example:
+
+ define mydial {
+ set modem type usrobotics
+ set port /dev/ttyS0
+ if fail end 1
+ set speed 57600
+ dial \%1
+ if success connect
+ }
+
+ This shows how you can combine many commands into one command, "mydial"
+ in this case (you can use any name you like, provided it does not clash
+ with the name of a built-in command). When this macro definition is in
+ effect, you can type commands like:
+
+ mydial 7654321
+
+ and it executes all the commands in macro definition, substituting the
+ first operand ("7654321") for the formal parameter ("\%1") in the
+ definition. This saves you from having to type lots of commands every
+ time you want to make a modem call.
+
+ One way to have the macro definition in effect is to type the
+ definition at the Kermit prompt. Another way is to store the definition
+ in a file and TAKE the file. If you want the definition to be in effect
+ automatically every time you start Kermit, put the definition in your
+ initialization or customization file (explained [78]below).
+
+ Here's a somewhat more ambitious example:
+
+ define mydelete {
+ local trash
+ assign trash \v(home)trashcan/
+ if not defined \%1 end 1 "Delete what?"
+ if wild \%1 end 1 "Deleting multiple files is too scary"
+ if not exist \%1 end 1 "I can't find \%1"
+ if not directory \m(trash) {
+ mkdir \m(trash)
+ if fail end 1 "No trash can"
+ }
+ rename /list \%1 \m(trash)
+ }
+ define myundelete {
+ local trash
+ assign trash \v(home)trashcan/
+ if not defined \%1 end 1 "Undelete what?"
+ if wild \%1 end 1 "Undeleting multiple files is too hard"
+ if not directory \m(trash) end 1 "No trash can"
+ if not exist \m(trash)\%1 end 1 "I can't find \%1 in trash can"
+ rename /list \m(trash)\%1 .
+ }
+
+ These macros are not exactly production quality (they don't handle
+ filenames that include path segments, they don't handle multiple files,
+ etc), but you get the idea: you can pass arguments to macros, they can
+ check them and make other kinds of decisions, and the commands
+ themselves are relatively intuitive and intelligible.
+
+ If you put the above lines into your initialization or customization
+ file, you'll have MYDELETE and MYUNDELETE commands available every time
+ you start Kermit, at least as long as you don't suppress execution of
+ the initialization file. (Exercise for the reader: Make these macros
+ generally useful: remove limitations, add trashcan display, browsing,
+ emptying, etc.)
+
+ Kerbang scripts execute without the initialization file. This to keep
+ them portable and also to make them start faster. If you want to write
+ Kerbang scripts that depend on the initialization file, include the
+ command
+
+ take \v(home).kermrc
+
+ at the desired spot in the script. By the way, \v(xxx) is a built-in
+ variable (xxx is the variable name, "home" in this case). To see what
+ built-in variables are available, type "show variables" at the C-Kermit
+ prompt. To see what else you can show, type "show ?". \m(xxx) is a user
+ defined variable (strictly speaking, it is a macro used as a variable).
+
+Command List
+
+ C-Kermit has more than 200 top-level commands, and some of these, such
+ as SET, branch off into hundreds of subcommands of their own, so it's
+ not practical to describe them all here. Instead, here's a concise list
+ of the most commonly used top-level commands, grouped by category. To
+ learn about each command, type "help" followed by the command name,
+ e.g. "help set". Terms such as Command state and Connect state are
+ explained in subsequent sections.
+
+ Optional fields are shown in [ italicized brackets ]. filename means
+ the name of a single file. filespec means a file specification that is
+ allowed to contain wildcard characters like '*' to match groups of
+ files. options are (optional) switches like /PAGE, /NOPAGE, /QUIET,
+ etc, listed in the HELP text for each command. Example:
+
+ send /recursive /larger:10000 /after:-1week /except:*.txt *
+
+ which can be read as "send all the files in this directory and all the
+ ones underneath it that are larger than 10000 bytes, no more than one
+ week old, and whose names don't end with ".txt".
+
+ Basic Commands
+
+ HELP Requests top-level help.
+ HELP command Requests help about the given command.
+ INTRODUCTION Requests a brief introduction to C-Kermit.
+ LICENSE Displays the C-Kermit software copyright and license.
+ VERSION Displays C-Kermit's version number.
+ EXIT [ number ] Exits from Kermit with the given status code. Synonyms:
+ QUIT, E, Q.
+ TAKE filename [ parameters... ] Executes commands from the given file.
+ LOG item [ filename ] Keeps a log of the given item in the given file.
+ [ DO ] macro [ parameters... ] Executes commands from the given
+ macro.
+ SET parameter value Sets the given parameter to the given value.
+ SHOW category Shows settings in a given category.
+ STATUS Tells whether previous command succeeded or failed.
+ DATE [ date-and/or-time ] Shows current date-time or interprets given
+ date-time.
+ RUN [ extern-command [ parameters... ] Runs the given external command.
+ Synonym: !.
+ EXEC [ extern-command [ params... ] Kermit overlays itself with the
+ given command.
+ SUSPEND Stops Kermit and puts it in the background. Synonym: Z.
+
+ Local File Management
+
+ TYPE [ options ] filename Displays the contents of the given file.
+ MORE [ options ] filename Equivalent to TYPE /PAGE (pause after each
+ screenful).
+ CAT [ options ] filename Equivalent to TYPE /NOPAGE.
+ HEAD [ options ] filename Displays the first few lines of a given file.
+ TAIL [ options ] filename Displays the last few lines of a given file.
+ GREP [ options ] pattern filespec Displays lines from files that match
+ the pattern. Synonym: FIND.
+ DIRECTORY [ options ] [ filespec ] Lists files (built-in, many
+ options).
+ LS [ options ] [ filespec ] Lists files (runs external "ls" command).
+ DELETE [ options ] [ filespec ] Deletes files. Synonym: RM.
+ PURGE [ options ] [ filespec ] Removes backup (*.~n~) files.
+ COPY [ options ] [ filespecs... ] Copies files. Synonym: CP.
+ RENAME [ options ] [ filespecs... ] Renames files. Synonym: MV.
+ CHMOD [ options ] [ filespecs... ] Changes permissions of files.
+ TRANSLATE filename charsets filename ] Converts file's character set.
+ Synonym: XLATE.
+ CD Changes your working directory to your home directory.
+ CD directory Changes your working directory to the one given.
+ CDUP Changes your working directory one level up.
+ PWD Displays your working directory.
+ BACK Returns to your previous working directory.
+ MKDIR [ directory ] Creates a directory.
+ RMDIR [ directory ] Removes a directory.
+
+ Making Connections
+
+ SET LINE [ options ] devicename Opens the named serial port.
+ Synonym: SET PORT.
+ OPEN LINE [ options ] devicename Same as SET LINE. Synonym: OPEN PORT.
+ SET MODEM TYPE [ name ] Tells Kermit what kind of modem is on the port.
+ DIAL [ number ] Tells Kermit to dial the given phone number with the
+ modem.
+ REDIAL Redials the most recently dialed phone number.
+ ANSWER Waits for and answers an incoming call on the modem.
+ AUTHENTICATE [ parameters... ] Performs secure authentication on a
+ TCP/IP connection.
+ SET NETWORK TYPE { TCP/IP, X.25, ... } Selects network type for
+ subsequent SET HOST commands.
+ SET HOST [ options ] host [ port ] Opens a network connection to the
+ given host and port.
+ SET HOST [ options ] * port Waits for an incoming TCP/IP connection on
+ the given port.
+ TELNET [ options ] host Opens a Telnet connection to the host and
+ enters Connect state.
+ RLOGIN [ options ] host Opens an Rlogin connection to the host and
+ enters Connect state.
+ IKSD [ options ] host Opens a connection to an Internet Kermit Service.
+ SSH [ options ] host Opens an SSH connection to the host and enters
+ Connect state.
+ FTP OPEN host [ options ] Opens an FTP connection to the host.
+ HTTP [ options ] OPEN host Opens an HTTP connection to the host.
+ PTY external-command Runs the command on a pseudoterminal as if it were
+ a connection.
+ PIPE external-command Runs the command through a pipe as if it were a
+ connection.
+
+ Using Connections
+
+ CONNECT [ options ] Enters Connect (terminal) state.
+ Synonym: C.
+ REDIRECT command Redirects the given external command over the
+ connection.
+ TELOPT command Sends a Telnet protocol command (Telnet connections
+ only).
+ Ctrl-\C "Escapes back" from Connect state to Command state.
+ Ctrl-\B (In Connect state) Sends a BREAK signal (serial or Telnet).
+ Ctrl-\! (In Connect state) Enters inferior shell; "exit" to return.
+ Ctrl-\? (In Connect state) Shows a menu of other escape-level options.
+ Ctrl-\Ctrl-\ (In Connect state) Type two Ctrl-Backslashes to send one
+ of them.
+ SET ESCAPE [ character ] Changes Kermit's Connect-state escape
+ character.
+
+ Closing Connections
+
+ HANGUP Hangs up the currently open serial-port or network connection.
+ CLOSE Closes the currently open serial-port or network connection.
+ SET LINE (with no devicename) Closes the currently open
+ serial-port or network connection.
+ SET HOST (with no hostname) Closes the currently open serial-port or
+ network connection.
+ FTP CLOSE Closes the currently open FTP connection.
+ HTTP CLOSE Closes the currently open HTTP connection.
+ EXIT Also closes all connections. Synonym: QUIT.
+ SET EXIT WARNING OFF Suppresses warning about open connections on exit
+ or close.
+
+ File Transfer
+
+ SEND [ options ] filename [ as-name ] Sends the given file. Synonym:
+ S.
+ SEND [ options ] filespec Sends all files that match.
+ RESEND [ options ] filespec Resumes an interrupted SEND from the point
+ of failure.
+ RECEIVE [ options ] [ as-name ] Waits passively for files to arrive.
+ Synonym: R.
+ LOG TRANSACTIONS [ filename ] Keeps a record of file transfers.
+ FAST Use fast file-transfer settings (default).
+ CAUTIOUS Use cautious and less fast file-transfer settings.
+ ROBUST Use ultra-conservative and slow file-transfer settings.
+ STATISTICS [ options ] Gives statistics about the most recent file
+ transfer.
+ WHERE After transfer: "Where did my files go?".
+ TRANSMIT [ options ] [ filename ] Sends file without protocol. Synonym:
+ XMIT.
+ LOG SESSION [ filename ] Captures remote text or files without
+ protocol.
+ SET PROTOCOL [ name... ] Tells Kermit to use an external file-transfer
+ protocol.
+ FTP { PUT, MPUT, GET, MGET, ... } FTP client commands.
+ HTTP { PUT, GET, HEAD, POST, ... } HTTP client commands.
+
+ Kermit Server
+
+ ENABLE, DISABLE Controls which features can be
+ used by clients.
+ SET SERVER Sets parameters prior to entering Server state.
+ SERVER Enters Server state.
+
+ Client of Kermit or FTP Server
+
+ [ REMOTE ] LOGIN [ user password ] Logs in to a Kermit server or IKSD
+ that requires it.
+ [ REMOTE ] LOGOUT Logs out from a Kermit server or IKSD.
+ SEND [ options ] filename [ as-name ] Sends the given file to the
+ server. Synonyms: S, PUT.
+ SEND [ options ] filespec Sends all files that match.
+ RESEND [ options ] filespec Resumes an interrupted SEND from the point
+ of failure.
+ GET [ options ] remote-filespec Asks the server to send the given
+ files. Synonym: G.
+ REGET [ options ] remote-filespec Resumes an interrupted GET from the
+ point of failure.
+ REMOTE CD [ directory ] Asks server to change its working directory.
+ Synonym: RCD.
+ REMOTE PWD [ directory ] Asks server to display its working directory.
+ Synonym: RPWD.
+ REMOTE DIRECTORY [ filespec... ] Asks server to send a directory
+ listing. Synonym: RDIR.
+ REMOTE DELETE [ filespec... ] Asks server to delete files. Synonym:
+ RDEL.
+ REMOTE [ command... ] (Many other commands: "remote ?" for a list).
+ MAIL [ options ] filespec Sends file(s) to be delivered as e-mail
+ (Kermit only).
+ FINISH Asks the server to exit server state (Kermit only).
+ BYE Asks the server to log out and close the connection.
+
+ Script Programming
+ DEFINE, DECLARE, UNDEFINE, UNDECLARE, ASSIGN, EVALUATE,
+ SEXPRESSION, ARRAY, SORT, INPUT, OUTPUT, IF, FOR, WHILE, SWITCH,
+ GOTO, ECHO, ASK, GETC, GETOK, ASSERT, WAIT, SLEEP, FOPEN, FREAD,
+ FWRITE, FCLOSE, STOP, END, RETURN, LEARN, SHIFT, TRACE, VOID,
+ INCREMENT, DECREMENT, ... For these and many more you'll need to
+ consult the [79]manual and supplements, and/or visit the
+ [80]Kermit Script Library, which also includes a brief tutorial.
+ Hint: HELP LEARN to find out how to get Kermit to write simple
+ scripts for you.
+
+ Many of Kermit's commands have synonyms, variants, relatives, and so
+ on. For example, MSEND is a version of SEND that accepts a list of file
+ specifications to be sent, rather than just one file specification, and
+ MPUT is a synonym of MSEND. MOVE means to SEND and then DELETE the
+ source file if successful. MMOVE is like MOVE, but accepts a list of
+ filespecs, and so on. These are described in the [81]full
+ documentation.
+
+ Use question mark to feel your way through an unfamiliar command, as in
+ this example (the part you type is underlined):
+
+ C-Kermit> remote ? One of the following:
+ assign delete help login print rename space
+ cd directory host logout pwd rmdir type
+ copy exit kermit mkdir query set who
+ C-Kermit> remote set ? One of the following:
+ attributes file retry transfer
+ block-check receive server window
+ C-Kermit> remote set file ? One of the following:
+ character-set incomplete record-length
+ collision names type
+ C-Kermit> remote set file names ? One of the following:
+ converted literal
+ C-Kermit> remote set file names literal
+ C-Kermit>
+
+ This is called menu on demand: you get a menu when you want one, but
+ menus are not forced on you even when know what you're doing. Note that
+ you can also abbreviate most keywords, and you can complete them with
+ the Tab or Esc key. Also note that ? works for filenames too, and that
+ you can use it in the middle of a keyword or filename, not just at the
+ beginning. For example, "send x?" lists all the files in the current
+ directory whose names start with 'x'.
+
+ [82]Kermit Home [83]C-Kermit Home [84]C-Kermit FAQ
+
+INITIALIZATION FILE
+
+ [85]Top [86]Contents [87]Next [88]Previous
+
+ In its default configuration, C-Kermit executes commands from a file
+ called .kermrc in your home directory when it starts, unless it is
+ given the -Y or -y command-line option. Custom configurations might
+ substitute a shared system-wide initialization file. The SHOW FILE
+ command tells what initialization file, if any, was used. The standard
+ initialization file "chains" to an individual customization file,
+ .mykermc, in the home directory, in which each user can establish
+ her/his own preferences, define macros, and so on.
+
+ Since execution of the initialization file (at least the standard one)
+ makes C-Kermit take longer to start, it might be better not to have an
+ initialization file, especially now that Kermit's default startup
+ configuration is well attuned to modern computing and networking -- in
+ other words, you no longer have do anything special to make Kermit
+ transfers go fast. So instead of having an initialization file that is
+ executed every time Kermit starts, you might consider making one or
+ more kerbang scripts (with names other that .kermrc) that do NOT
+ include an "exit" command, and invoke those when you need the settings,
+ macro definitions, and/or scripted actions they contain, and invoke
+ C-Kermit directly when you don't.
+
+ To put it another way... We still distribute the standard
+ initialization file since it's featured in the manual and backwards
+ compatibility is important to us. But there's no harm in not using it
+ if you don't need the stuff that's in it (services directory, dialing
+ directory, network directory, and associated macro definitions). On the
+ other hand, if there are settings or macros you want in effect EVERY
+ time you use Kermit, the initialization file (or the customization file
+ it chains to) is the place to put them, because that's the only place
+ Kermit looks for them automatically each time you start it.
+
+ [89]Kermit Home [90]C-Kermit Home [91]C-Kermit FAQ
+
+MODES OF OPERATION
+
+ [92]Top [93]Contents [94]Next [95]Previous
+
+ Kermit is said to be in Local mode if it has made a connection to
+ another computer, e.g. by dialing it or establishing a Telnet
+ connection to it. The other computer is remote, so if you start another
+ copy of Kermit on the remote computer, it is said to be in Remote mode
+ (as long as it has not made any connections of its own). The local
+ Kermit communicates over the communications device or network
+ connection, acting as a conduit between the the remote computer and
+ your keyboard and screen. The remote Kermit is the file-transfer
+ partner to the local Kermit and communicates only through its standard
+ input and output.
+
+ At any moment, a Kermit program can be in any of the following states.
+ It's important to know what they are and how to change from one to the
+ other.
+
+ Command state
+ In this state, Kermit reads commands from:
+
+ + Your keyboard; or:
+ + A file, or:
+ + A macro definition.
+
+ You can exit from Command state back to Unix with the EXIT or
+ QUIT command (same thing). You can enter Connect state with any
+ of various commands (CONNECT, DIAL, TELNET, etc). You can enter
+ file transfer state with commands like SEND, RECEIVE, and GET.
+ You can enter Server state with the SERVER command. The TAKE
+ command tells Kermit to read and execute commands from a file.
+ The (perhaps implied) DO command tells Kermit to read and
+ execute commands from a macro definition. While in Command
+ state, you can interrupt any command, macro, or command file by
+ typing Ctrl-C (hold down the Ctrl key and press the C key); this
+ normally brings you back to the prompt.
+
+ Shell state
+ You can invoke an inferior shell or external command from the
+ Kermit command prompt by using the PUSH, RUN (!), EDIT, or
+ BROWSE command. While the inferior shell or command is active,
+ Kermit is suspended and does nothing. Return to Kermit Command
+ state by exiting from the inferior shell or application.
+
+ Connect state
+ In this state, which can be entered only when in Local mode
+ (i.e. when Kermit has made a connection to another computer),
+ Kermit is acting as a terminal to the remote computer. Your
+ keystrokes are sent to the remote computer and characters that
+ arrive over the communication connection are displayed on your
+ screen. This state is entered when you give a CONNECT, DIAL,
+ TELNET, RLOGIN, or IKSD command. You can return to command state
+ by logging out of the remote computer, or by typing:
+
+ Ctrl-\c
+
+ That is: Hold down the Ctrl key and press the backslash key,
+ then let go of the Ctrl key and press the C key. This is called
+ escaping back. Certain other escape-level commands are also
+ provided; type Ctrl-\? for a list. For example, you can enter
+ Shell state with:
+
+ Ctrl-\!
+
+ To send a Ctrl-\ to the host while in Connect state, type two of
+ them in a row. See HELP CONNECT and HELP SET ESCAPE for more
+ info.
+
+ Local file-transfer state
+ In this state, Kermit is sending packets back and forth with the
+ other computer in order to transfer a file or accomplish some
+ other file-related task. And at the same time, it is displaying
+ its progress on your screen and watching your keyboard for
+ interruptions. In this state, the following single-keystroke
+ commands are accepted:
+
+ X Interrupt the current file and go on to the next (if any).
+ Z Interrupt the current file and skip all the rest.
+ E Like Z but uses a "stronger" protocol (use if X or Z don't work).
+ Ctrl-C Interrupt file-transfer mode (use if Z or E don't work).
+
+ Kermit returns to its previous state (Command or Connect) when
+ the transfer is complete or when interrupted successfully by X,
+ Z, E, or Ctrl-C (hold down the Ctrl key and press the C key).
+
+ Remote file-transfer state
+ In this state, Kermit is exchanging file-transfer packets with
+ its local partner over its standard i/o. It leaves this state
+ automatically when the transfer is complete. In case you find
+ your local Kermit in Connect state and the remote one in
+ File-transfer state (in which it seems to ignore your
+ keystrokes), you can usually return it to command state by
+ typing three Ctrl-C's in a row. If that doesn't work, return
+ your local Kermit to Command state (Ctrl-\ C) and type
+ "e-packet" and then press the Return or Enter key; this forces a
+ fatal Kermit protocol error.
+
+ Remote Server state
+ This is like Remote File-transfer state, except it never returns
+ automatically to Command state. Rather, it awaits further
+ instructions from the client program; that is, from your Local
+ Kermit program. You can return the Remote Server to its previous
+ state by issuing a "finish" command to the client, or if you are
+ in Connect state, by typing three Ctrl-C's in a row. You can
+ tell the server job to log out and break the connection by
+ issuing a "bye" command to the client.
+
+ Local Server state
+ Like Remote-Server state, but in local mode, and therefore with
+ its file-transfer display showing, and listening for single-key
+ commands, as in Local File-transfer state. Usually this state is
+ entered automatically when a remote Kermit program gives a GET
+ command.
+
+ C-Kermit, Kermit 95, and MS-DOS Kermit all can switch automatically
+ from Connect state to Local File-transfer state when you initiate a
+ file transfer from the remote computer by starting Kermit and telling
+ it to send or get a file, in which case, Connect state is automatically
+ resumed after the file transfer is finished.
+
+ Note that C-Kermit is not a terminal emulator. It is a communications
+ application that you run in a terminal window (e.g. console or Xterm).
+ The specific emulation, such as VT100, VT220, Linux Console, or Xterm,
+ is provided by the terminal window in which you are running C-Kermit.
+ Kermit 95 and MS-DOS Kermit, on the other hand, are true terminal
+ emulators. Why is C-Kermit not a terminal emulator? [96]CLICK HERE to
+ read about it.
+
+ [97]Kermit Home [98]C-Kermit Home [99]C-Kermit FAQ
+
+MAKING CONNECTIONS
+
+ [100]Top [101]Contents [102]Next [103]Previous
+
+ Here is how to make different kinds of connections using interactive
+ Kermit commands (as noted above, you can also make connections with
+ command-line options). Note that you don't have to make connections
+ with Kermit. It can also be used on the far end of a connection as the
+ remote file transfer and management partner of your local
+ communications software.
+
+ Making a Telnet Connection
+ At the C-Kermit command prompt, simply type:
+
+ telnet foo.bar.com ; Substitute desired host name or address.
+ telnet xyzcorp.com 3000 ; You can also include a port number.
+
+ If the connection is successful, Kermit automatically enters
+ Connect state. When you logout from the remote host, Kermit
+ automatically returns to its prompt. More info: HELP TELNET,
+ HELP SET TELNET, HELP SET TELOPT. Also see the [104]IKSD section
+ below.
+
+ Making an Rlogin connection
+ This is just like Telnet, except you have to be root to do it
+ because Rlogin uses a privileged TCP port:
+
+ rlogin foo.bar.com ; Substitute desired host name or address.
+
+ More info: HELP RLOGIN.
+
+ Making an SSH Connection
+ Unlike Telnet and Rlogin, SSH connections are not built-in, but
+ handled by running your external SSH client through a
+ pseudoterminal. Using C-Kermit to control the SSH client gives
+ you all of Kermit's features (file transfer, character-set
+ conversion, scripting, etc) over SSH.
+
+ ssh foo.bar.com ; Substitute desired host name or address.
+
+ More info: HELP SSH, HELP SET SSH.
+
+ Dialing with a Modem
+ If it's an external modem, make sure it is connected to a usable
+ serial port on your computer with a regular (straight-through)
+ [105]modem cable, and to the telephone jack with a telephone
+ cable, and that it's turned on. Then use these commands:
+
+ set modem type usrobotics ; Or other supported type
+ set line /dev/ttyS0 ; Specify device name
+ set speed 57600 ; Or other desired speed
+ set flow rts/cts ; Most modern modems support this
+ set dial method tone ; (or pulse)
+ dial 7654321 ; Dial the desired number
+
+ Type "set modem type ?" for a list of supported modem types. If
+ you omit the SET MODEM TYPE command, the default type is
+ "generic-high-speed", which should work for most modern
+ AT-command-set modems. If the line is busy, Kermit redials
+ automatically. If the call does not succeed, use "set dial
+ display on" and try it again to watch what happens. If the call
+ succeeds, Kermit enters Connect state automatically and returns
+ to its prompt automatically when you log out from the remote
+ computer or the connection is otherwise lost.
+
+ You can also dial from a modem that is accessible by Telnet,
+ e.g. to a reverse terminal server. In this case the command
+ sequence is:
+
+ set host ts.xxx.com 2000 ; Terminal-server and port
+ set modem type usrobotics ; Or other supported type
+ set dial method tone ; (or pulse)
+ dial 7654321 ; Dial the desired number
+
+ If the terminal server supports the Telnet Com Port Option,
+ [106]RFC 2217, you can also give serial-port related commands
+ such as SET SPEED, SET PARITY, and so on, and Kermit relays them
+ to the terminal server using the protocol specified in the RFC.
+
+ More info: HELP SET MODEM, HELP SET LINE, HELP SET SPEED, HELP
+ SET FLOW, HELP DIAL, HELP SET DIAL, HELP SET MODEM, HELP SET
+ CARRIER-WATCH, SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL.
+
+ Direct Serial Port
+ Connect the two computers, A and B, with a [107]null modem cable
+ (or two modem cables interconnected with a null-modem adapter or
+ modem eliminator). From Computer A:
+
+ set modem type none ; There is no modem
+ set line /dev/ttyS0 ; Specify device name
+ set carrier-watch off ; If DTR and CD are not cross-connected
+ set speed 57600 ; Or other desired speed
+ set flow rts/cts ; If RTS and CTS are cross-connected
+ set flow xon/xoff ; If you can't use RTS/CTS
+ set parity even ; (or "mark" or "space", if necessary)
+ set stop-bits 2 ; (rarely necessary)
+ connect ; Enter Connect (terminal) state
+
+ This assumes Computer B is set up to let you log in. If it
+ isn't, you can run a copy of Kermit on Computer B and follow
+ approximately the same directions. More info: As above plus HELP
+ CONNECT.
+
+ With modems or direct serial connections, you might also have to "set
+ parity even" (or "mark" or "space") if it's a 7-bit connection.
+
+ Of the connection types listed above, only one can be open at a time.
+ However, any one of these can be open concurrently with an [108]FTP or
+ HTTP session. Each connection type can be customized to any desired
+ degree, scripted, logged, you name it. See the manual.
+
+ NOTE: On selected platforms, C-Kermit also can make X.25 connections.
+ See the manual for details.
+
+ [109]Kermit Home [110]C-Kermit Home [111]C-Kermit FAQ
+
+TRANSFERRING FILES WITH KERMIT
+
+ [112]Top [113]Contents [114]Next [115]Previous
+
+ * [116]Downloading Files
+ * [117]Uploading Files
+ * [118]Kermit Transfers the Old-Fashioned Way
+ * [119]If File Transfer Fails
+ * [120]Advanced Kermit File Transfer Features
+ * [121]Non-Kermit File Transfer
+
+ There is a [122]widespread and persistent belief that Kermit is a slow
+ protocol. This is because, until recently, it used conservative tuning
+ by default to make sure file transfers succeeded, rather than failing
+ because they overloaded the connection. Some extra commands (or
+ command-line options, like -Q) were needed to make it go fast, but
+ nobody bothered to find out about them. Also, it takes two to tango:
+ most non-Kermit-Project Kermit protocol implementations really ARE
+ slow. The best file-transfer partners for C-Kermit are: another copy of
+ [123]C-Kermit (7.0 or later) and [124]Kermit 95. These combinations
+ work well and they work fast by default. MS-DOS Kermit is good too, but
+ you have to tell it to go fast (by giving it the FAST command).
+
+ Furthermore, all three of these Kermit programs support "autodownload"
+ and "autoupload", meaning that when they are in Connect state and a
+ Kermit packet comes in from the remote, they automatically switch into
+ file transfer mode.
+
+ And plus, C-Kermit and K95 also switch automatically between text and
+ binary mode for each file, so there is no need to "set file type
+ binary" or "set file type text", or to worry about files being
+ corrupted because they were transferred in the wrong mode.
+
+ What all of these words add up to is that now, when you use up-to-date
+ Kermit software from the Kermit Project, file transfer is not only
+ fast, it's ridiculously easy. You barely have to give any commands at
+ all.
+
+ Downloading Files
+ Let's say you have [125]Kermit 95, [126]C-Kermit, or [127]MS-DOS
+ Kermit on your desktop computer, with a connection to a Unix
+ computer that has C-Kermit installed as "kermit". To download a
+ file (send it from Unix to your desktop computer), just type the
+ following command at your Unix shell prompt:
+
+ kermit -s oofa.txt
+
+ (where oofa.txt is the filename). If you want to send more than
+ one file, you can put as many filenames as you want on the
+ command line, and they can be any combination of text and
+ binary:
+
+ kermit -s oofa.txt oofa.zip oofa.html oofa.tar.gz
+
+ and/or you can use wildcards to send groups of files:
+
+ kermit -s oofa.*
+
+ If you want to send a file under an assumed name, use:
+
+ kermit -s friday.txt -a today.txt
+
+ This sends the file friday.txt but tells the receiving Kermit
+ that its name is today.txt. In all cases, as noted, when the
+ file transfer is finished, your desktop Kermit returns
+ automatically to Connect state. No worries about escaping back,
+ re-connecting, text/binary mode switching. Almost too easy,
+ right?
+
+ Uploading Files
+ To upload files (send them from your desktop computer to the
+ remote Unix computer) do the same thing, but use the -g (GET)
+ option instead of -s:
+
+ kermit -g oofa.txt
+
+ This causes your local Kermit to enter server mode; then the
+ remote Kermit program requests the named file and the local
+ Kermit sends it and returns automatically to Connect state when
+ done.
+
+ If you want to upload multiple files, you have have use shell
+ quoting rules, since these aren't local files:
+
+ kermit -g "oofa.txt oofa.zip oofa.html oofa.tar.gz"
+ kermit -g "oofa.*"
+
+ If you want to upload a file but store it under a different
+ name, use:
+
+ kermit -g friday.txt -a today.txt
+
+ Kermit Transfers the Old-Fashioned Way
+ If your desktop communications software does not support
+ autoupload or autodownload, or it does not include Kermit server
+ mode, the procedure requires more steps.
+
+ To download a file, type:
+
+ kermit -s filename
+
+ on the host as before, but if nothing happens automatically in
+ response to this command, you have to switch your desktop
+ communications software into Kermit Receive state. This might be
+ done by escaping back using keyboard characters or hot keys
+ (Alt-x is typical) and/or with a command (like RECEIVE) or a
+ menu. When the file transfer is complete, you have to go back to
+ Connect state, Terminal emulation, or whatever terminology
+ applies to your desktop communications software.
+
+ To upload a file, type:
+
+ kermit -r
+
+ on the host (rather than "kermit -g"). This tells C-Kermit to
+ wait passively for a file to start arriving. Then regain the
+ attention of your desktop software (Alt-x or whatever) and
+ instruct it to send the desired file(s) with Kermit protocol.
+ When the transfer is finished, return to the Connect or Terminal
+ screen.
+
+ If File Transfer Fails
+ Although every aspect of Kermit's operation can be finely tuned,
+ there are also three short and simple "omnibus tuning" commands
+ you can use for troubleshooting:
+
+ FAST
+ Use fast file-transfer settings. This has been the default
+ since C-Kermit 7.0 now that most modern computers and
+ connections support it. If transfers fail with fast
+ settings, try . . .
+
+ CAUTIOUS
+ Use cautious but not paranoid settings. File transfers, if
+ they work, will go at medium speed. If not, try . . .
+
+ ROBUST
+ Use the most robust, resilient, conservative, safe, and
+ reliable settings. File transfers will almost certainly
+ work, but they will be quite slow (of course this is a
+ classic tradeoff; ROBUST was C-Kermit's default tuning in
+ versions 6.0 and earlier, which made everybody think
+ Kermit protocol was slow). If ROBUST doesn't do the trick,
+ try again with SET PARITY SPACE first in case it's not an
+ 8-bit connection.
+
+ Obviously the success and performance of a file transfer also
+ depends on C-Kermit's file transfer partner. Up-to-date, real
+ [128]Kermit Project partners are recommended because they
+ contain the best Kermit protocol implementations and because
+ [129]we can support them in case of trouble.
+
+ If you still have trouble, consult Chapter 10 of [130]Using
+ C-Kermit, or send email to [131]kermit-support@columbia.edu.
+
+ Advanced Kermit File-Transfer Features
+ Obviously there is a lot more to Kermit file transfer, including
+ all sorts of interactive commands, preferences, options,
+ logging, debugging, troubleshooting, and anything else you can
+ imagine but that's what the [132]manual and updates are for.
+ Here are a few topics you can explore if you're interested by
+ Typing HELP for the listed commands:
+
+ Logging transfers:
+ LOG TRANSACTIONS (HELP LOG)
+
+ Automatic per-file text/binary mode switching:
+ SET TRANSFER MODE { AUTOMATIC, MANUAL } (HELP SET
+ TRANSFER).
+
+ Cross-platform recursive directory tree transfer:
+ SEND /RECURSIVE, GET /RECURSIVE (HELP SEND, HELP GET).
+
+ File collision options:
+ SET FILE COLLISION { OVERWRITE, BACKUP, DISCARD, ... }
+ (HELP SET FILE).
+
+ Update mode (only transfer files that changed since last time):
+ SET FILE COLLISION UPDATE (HELP SET FILE).
+
+ Filename selection patterns:
+ (HELP WILDCARD).
+
+ Flexible file selection:
+ SEND (or GET) /BEFORE /AFTER /LARGER /SMALLER /TYPE
+ /EXCEPT, ...
+
+ Character-set conversion:
+ SET { FILE, TRANSFER } CHARACTER-SET, ASSOCIATE, ...
+
+ File/Pathname control:
+ SET { SEND, RECEIVE } PATHNAMES, SET FILE NAMES.
+
+ Atomic file movement:
+ SEND (or GET) /DELETE /RENAME /MOVE-TO
+
+ Transferring to/from standard i/o of other commands:
+ SEND (or GET) /COMMAND
+
+ Recovery of interrupted transfer from point of failure:
+ RESEND, REGET (HELP RESEND, HELP REGET).
+
+ Non-Kermit File Transfer
+ You can also use C-Kermit to transfer files with FTP or HTTP
+ Internet protocols; [133]see below.
+
+ On a regular serial or Telnet connection where the other
+ computer doesn't support Kermit protocol at all, you have
+ several options. For example, if your desktop communications
+ software supports Zmodem, use "rz" and "sz" on the host rather
+ than Kermit. But if Kermit is your desktop software, and you are
+ using it to make calls or network connections to other computers
+ that don't support Kermit protocol (or that don't have a good
+ implementation of it), then if your computer also has external
+ X, Y, or Zmodem programs that are redirectable, Kermit can use
+ them as external protocols. HELP SET PROTOCOL for details.
+
+ You can also capture "raw" data streams from the other computer
+ with LOG SESSION (HELP LOG and HELP SET SESSION-LOG for
+ details), and you can upload files without any protocol at all
+ with TRANSMIT (HELP TRANSMIT, HELP SET TRANSMIT).
+
+ [134]Kermit Home [135]C-Kermit Home [136]C-Kermit FAQ
+
+KERMIT CLIENT/SERVER CONNECTIONS
+
+ [137]Top [138]Contents [139]Next [140]Previous
+
+ On any kind of connection you can make with Kermit -- serial, TCP/IP,
+ X.25, etc -- you can set up a convenient client/server relationship
+ between your Kermit client (the one that made the connection) and the
+ Kermit program on the far end of the connection (the remote Kermit) by
+ putting the remote Kermit in server mode. This is normally done by
+ giving it a SERVER command, or by starting it with the -x command-line
+ option. In some cases ([141]Internet Kermit Service, SSH connections to
+ a Kermit subsystem, or specially configured hosts), there is already a
+ Kermit server waiting on the far end. Here is a quick synopsis of the
+ commands you can give to the client for interacting with the server:
+
+ SEND [ switches ] filename
+ Sends the named file to the server. The filename can include
+ wildcards. Lots of switches are available for file selection,
+ etc. Type HELP SEND at the client prompt for details.
+
+ GET [ switches ] filename
+ Asks the server to send the named file. The filename can include
+ wildcards. Type HELP GET at the client prompt for details.
+
+ BYE
+ Terminates the server and closes your connection to it.
+
+ FINISH
+ Terminates the server. If you started the server yourself, this
+ leaves the remote host at its shell prompt. If it was a
+ dedicated server (such as IKSD or an SSH subsystem), FINISH is
+ equivalent to BYE.
+
+ SET LOCUS { LOCAL, REMOTE, AUTO }
+ (C-Kermit 8.0.201 and later, K95 1.1.21 and later) This tells
+ the client whether file-management commands like CD, PWD,
+ DIRECTORY, DELETE, MKDIR, etc, should be executed locally or by
+ the server. In this type of connection, the default is LOCAL.
+ Use SET LOCUS REMOTE if you want Kermit to behave like an FTP
+ client, in which case these commands are executed remotely, and
+ their local versions must have an L prefix: LCD, LPWD,
+ LDIRECTORY, etc. When LOCUS is LOCAL, then the remote versions
+ must have an R prefix: RCD, RPWD, RDIRECTORY, etc. HELP SET
+ LOCUS for details. SHOW COMMAND to see current locus.
+
+ The following commands are affected by SET LOCUS:
+
+ CD, LCD, RCD
+ Change (working, current) directory. HELP CD for details.
+
+ CDUP, LCDUP, RCDUP
+ CD one level up.
+
+ DIRECTORY, LDIRECTORY, RDIRECTORY
+ Produce a directory listing. Many options are available for
+ local listings. HELP DIRECTORY for details.
+
+ DELETE, LDELETE, RDELETE
+ Deletes files or directories. Many options available, HELP
+ DELETE.
+
+ RENAME, LRENAME, RRENAME
+ Renames files or directories. Many options available, HELP
+ RENAME.
+
+ MKDIR, LMKDIR, RMKDIR
+ Creates a directory. HELP MKDIR.
+
+ RMDIR, LRMDIR, RRMDIR
+ Removes a directory. HELP RMDIR.
+
+ There are dozens -- maybe hundreds -- of other commands, described in
+ the built-in help, on the website, and/or in the published or online
+ manuals. But even if you don't have access to documentation, you can
+ "set locus remote" and then use pretty much the same commands you would
+ use with any FTP client.
+
+ [142]Kermit Home [143]C-Kermit Home [144]C-Kermit FAQ
+
+KERMIT'S BUILT-IN FTP AND HTTP CLIENTS
+
+ [145]Top [146]Contents [147]Next [148]Previous
+
+ Kermit's FTP client is like the regular Unix FTP client that you're
+ used to, but with some differences:
+
+ * It has lots more commands and features.
+ * You can have an FTP session and a regular Kermit serial or Telnet
+ session open at the same time.
+ * FTP sessions can be fully automated.
+
+ By default Kermit's FTP client tries its best to present the same user
+ interface as a regular FTP client: PUT, GET, DIR, CD, BYE, etc, should
+ work the same, even though some of these commands have different
+ meaning in Kermit-to-Kermit connections; for example, CD, DIR, RENAME,
+ etc, in Kermit act locally, whereas in FTP they are commands for the
+ server. This might cause some confusion, but as in all things Kermit,
+ you have total control:
+
+ * The [149]SET LOCUS command lets you specify where file management
+ commands should be executed -- locally or remotely -- for any kind
+ of connection.
+ * Any FTP command can be prefixed with the word "FTP" to remove any
+ ambiguity.
+
+ Pending publication of the next edition of the manual, the Kermit FTP
+ client is thoroughly documented at the Kermit Project website:
+
+ [150]http://www.columbia.edu/kermit/ftpclient.html
+
+ You also can use HELP FTP and HELP SET FTP to get descriptions of
+ Kermit's FTP-related commands.
+
+ The HTTP client is similar to the FTP one, except you prefix each
+ command with HTTP instead of FTP: HTTP OPEN, HTTP GET, HTTP PUT, HTTP
+ CLOSE, etc. Type HELP HTTP for details, or visit the to view the
+ [151]manual supplements. HTTP connections can be open at the same time
+ as regular serial or Telnet connections and FTP connections. So Kermit
+ can manage up to three types connections simultaneously.
+
+ [152]Kermit Home [153]C-Kermit Home [154]C-Kermit FAQ [155]FTP Client
+ [156]HTTP Client
+
+INTERNET KERMIT SERVICE
+
+ [157]Top [158]Contents [159]Next [160]Previous
+
+ C-Kermit can be configured and run as an Internet service (called
+ IKSD), similar to an FTP server (FTPD) except you can (but need not)
+ interact with it directly, plus it does a lot more than an FTP server
+ can do. The TCP port for IKSD is 1649. It uses Telnet protocol.
+ C-Kermit can be an Internet Kermit Server, or it can be a client of an
+ IKSD. You can make connections from C-Kermit to an IKSD with any of the
+ following commands:
+
+ telnet foo.bar.edu 1649
+ telnet foo.bar.edu kermit ; if "kermit" is listed in /etc/services
+ iksd foo.bar.edu
+
+ The IKSD command is equivalent to a TELNET command specifying port
+ 1649. For more information about making and using connections to an
+ IKSD, see:
+
+ [161]http://www.columbia.edu/kermit/cuiksd.html
+
+ You can run an Internet Kermit Service on your own computer too (if you
+ are the system administrator). For instructions, see:
+
+ [162]http://www.columbia.edu/kermit/iksd.html
+
+ [163]Kermit Home [164]C-Kermit Home [165]C-Kermit FAQ
+
+SECURITY
+
+ [166]Top [167]Contents [168]Next [169]Previous
+
+ All of C-Kermit's built-in TCP/IP networking methods (Telnet, Rlogin,
+ IKSD, FTP, and HTTP) can be secured by one or more of the following
+ IETF-approved methods:
+
+ * MIT Kerberos IV
+ * MIT Kerberos V
+ * SSL/TLS
+ * Stanford SRP
+
+ For complete instructions see:
+
+ [170]http://www.columbia.edu/kermit/security.html
+
+ And as noted previously, you can also make SSH connections with
+ C-Kermit if you already have an SSH client installed.
+
+ [171]Kermit Home [172]C-Kermit Home [173]C-Kermit FAQ
+
+ALTERNATIVE COMMAND-LINE PERSONALITIES
+
+ [174]Top [175]Contents [176]Next [177]Previous
+
+ When invoked as "kermit" or any other name besides any of the special
+ ones, C-Kermit has the command-line options described above in the
+ [178]OPTIONS section. However, if you invoke C-Kermit using any of the
+ following names:
+
+ telnet Telnet client
+ ftp FTP client
+ http HTTP client
+ https Secure HTTP client
+
+ Kermit's command-line personality changes to match. This can be done
+ (among other ways) with symbolic links (symlinks). For example, if you
+ want C-Kermit to be your regular Telnet client, or the Telnet helper of
+ your Web browser, you can create a link like the following in a
+ directory that lies in your PATH ahead of the regular telnet program:
+
+ ln -s /usr/local/bin/kermit telnet
+
+ Now when you give a "telnet" command, you are invoking Kermit instead,
+ but with its Telnet command-line personality so, for example:
+
+ telnet xyzcorp.com
+
+ Makes a Telnet connection to xyzcorp.com, and Kermit exits
+ automatically when the connection is closed (just like the regular
+ Telnet client). Type "telnet -h" to get a list of Kermit's
+ Telnet-personality command-line options, which are intended to be as
+ compatible as possible with the regular Telnet client.
+
+ Similarly for FTP:
+
+ ln -s /usr/local/bin/kermit ftp
+
+ And now type "ftp -h" to see its command-line options, and use command
+ lines just like you would give your regular FTP client:
+
+ ftp -n xyzcorp.com
+
+ but with additional options allowing an entire session to be specified
+ on the command line, as explained in the C-Kermit [179]FTP client
+ documentation.
+
+ And similarly for HTTP:
+
+ ln -s /usr/local/bin/kermit http
+ ./http -h
+ ./http www.columbia.edu -g kermit/index.html
+
+ Finally, if Kermit's first command-line option is a Telnet, FTP, IKSD,
+ or HTTP URL, Kermit automatically makes the appropriate kind of
+ connection and, if indicated by the URL, takes the desired action:
+
+ kermit telnet:xyzcorp.com ; Opens a Telnet session
+ kermit telnet://olga@xyzcorp.com ; Ditto for user olga
+ kermit ftp://olga@xyzcorp.com/public/oofa.zip ; Downloads a file
+ kermit kermit://kermit.columbia.edu/kermit/f/READ.ME ; Ditto for IKSD
+ kermit iksd://kermit.columbia.edu/kermit/f/READ.ME ; (This works too)
+ kermit http://www.columbia.edu/kermit/index.html ; Grabs a web page
+ kermit https://wwws.xyzcorp.com/secret/plan.html ; Grabs a secure web page
+
+ [180]Kermit Home [181]C-Kermit Home [182]C-Kermit FAQ
+
+LICENSE
+
+ [183]Top [184]Contents [185]Next [186]Previous
+
+ On or before 30 June 2011, barring unforeseen circumstances,
+ [187]C-Kermit 9.0 will be released with the [188]Revised 3-Clause BSD
+ License. This is a certified [189]Open Source license, and it means
+ that C-Kermit no longer needs to be licensed for commercial
+ redistribution. Technical support for Kermit software will not be
+ available from Columbia University after June 30th.
+
+ [190]Kermit Home [191]C-Kermit Home [192]C-Kermit FAQ
+
+OTHER TOPICS
+
+ [193]Top [194]Contents [195]Next [196]Previous
+
+ There's way more to C-Kermit than we've touched on here --
+ troubleshooting, customization, character sets, dialing directories,
+ sending pages, script writing, and on and on, all of which are covered
+ in the manual and updates and supplements. For the most up-to-date
+ information on documentation (or updated documentation itself) visit
+ the Kermit Project website:
+
+ [197]http://www.columbia.edu/kermit/
+
+ There you will also find [198]Kermit software packages for other
+ platforms: different Unix varieties, Windows, DOS, VMS, IBM mainframes,
+ and many others: 20+ years' worth.
+
+ [199]Kermit Home [200]C-Kermit Home [201]C-Kermit FAQ
+
+DOCUMENTATION AND UPDATES
+
+ [202]Top [203]Contents [204]Next [205]Previous
+
+ The manual for C-Kermit is:
+
+ 1. Frank da Cruz and Christine M. Gianone, [206]Using C-Kermit, Second
+ Edition, Digital Press / Butterworth-Heinemann, Woburn, MA, 1997,
+ 622 pages, ISBN 1-55558-164-1. This is a printed book, now also
+ available as a [207]Kindle E-Book. It covers C-Kermit 6.0.
+ 2. The C-Kermit 7.0 Supplement:
+ [208]http://www.columbia.edu/kermit/ckermit70.html
+ 3. The C-Kermit 8.0 Supplement:
+ [209]http://www.columbia.edu/kermit/ckermit80.html
+ 4. The C-Kermit 9.0 Supplement:
+ [210]http://www.columbia.edu/kermit/ckermit90.html
+
+ The C-Kermit home page is here:
+
+ [211]http://www.columbia.edu/kermit/ckermit.html
+
+ Visit this page to learn about new versions, Beta tests, and other
+ news; to read case studies and tutorials; to download source code,
+ install packages, and [212]prebuilt binaries for many platforms. Also
+ visit:
+
+ [213]http://www.columbia.edu/kermit/scriptlib.html
+ The Kermit script library and tutorial
+
+ [214]http://www.columbia.edu/kermit/newfaq.html
+ The Kermit FAQ (Frequently Asked Questions about Kermit)
+
+ [215]http://www.columbia.edu/kermit/ckfaq.html
+ The C-Kermit FAQ (Frequently Asked Questions about C-Kermit)
+
+ [216]http://www.columbia.edu/kermit/security.html
+ The Kermit security reference.
+
+ [217]http://www.columbia.edu/kermit/telnet.html
+ C-Kermit Telnet client documentation.
+
+ [218]http://www.columbia.edu/kermit/studies.html
+ Case studies.
+
+ [219]http://www.columbia.edu/kermit/ckcbwr.html
+ General C-Kermit Hints and Tips.
+
+ [220]http://www.columbia.edu/kermit/ckubwr.html
+ Unix C-Kermit Hints and Tips.
+
+ [221]http://www.columbia.edu/kermit/ckvbwr.html
+ VMS C-Kermit Hints and Tips.
+
+ [222]http://www.columbia.edu/kermit/ckuins.html
+ Unix C-Kermit Installation Instructions
+
+ [223]http://www.columbia.edu/kermit/ckvins.html
+ VMS C-Kermit Installation Instructions
+
+ [224]http://www.columbia.edu/kermit/support.html
+ Technical support.
+
+ [225]http://www.columbia.edu/kermit/k95tutorial.html
+ Kermit 95 tutorial (this document).
+
+ [226]comp.protocols.kermit.misc
+ The Kermit newsgroup (unmoderated).
+
+ [227]Kermit Home [228]C-Kermit Home [229]C-Kermit FAQ
+
+FILES
+
+ [230]Top [231]Contents [232]Next [233]Previous
+
+ [234]The Revised 3-Clause License
+ C-Kermit license.
+
+ [235]~/.kermrc
+ Initialization file.
+
+ [236]~/.mykermrc
+ Customization file.
+
+ ~/.kdd
+ Kermit dialing directory (see manual).
+
+ ~/.knd
+ Kermit network directory (see manual).
+
+ ~/.ksd
+ Kermit services directory (see manual).
+
+ [237]ckuins.html
+ Installation instructions for Unix.
+
+ [238]ckcbwr.html
+ General C-Kermit bugs, hints, tips.
+
+ [239]ckubwr.html
+ Unix-specific C-Kermit bugs, hints, tips.
+
+ [240]ckcplm.html
+ C-Kermit program logic manual.
+
+ [241]ckccfg.html
+ C-Kermit compile-time configuration options.
+
+ ssh
+ (in your PATH) SSH connection helper.
+
+ rz, sz, etc.
+ (in your PATH) external protocols for XYZmodem.
+
+ /var/spool/locks (or whatever)
+ UUCP lockfile for dialing out (see [242]installation
+ instructions).
+
+ [243]Kermit Home [244]C-Kermit Home [245]C-Kermit FAQ
+
+AUTHORS
+
+ [246]Top [247]Contents [248]Previous
+
+ Frank da Cruz and Jeffrey E Altman
+ The Kermit Project - Columbia Univerity
+ 612 West 115th Street
+ New York NY 10025-7799
+ USA
+
+ 1985-present, with contributions from hundreds of others all over the
+ world.
+ __________________________________________________________________
+
+
+ C-Kermit 9.0 Unix Manual Page and Tutorial / [249]kermit@columbia.edu
+ / 1 July 2011
+
+References
+
+ 1. http://www.columbia.edu/
+ 2. mailto:kermit@columbia.edu
+ 3. http://www.columbia.edu/kermit/index.html
+ 4. http://www.columbia.edu/kermit/k95.html
+ 5. http://www.columbia.edu/kermit/ckermit.html
+ 6. http://www.columbia.edu/kermit/ckscripts.html
+ 7. http://www.columbia.edu/kermit/current.html
+ 8. http://www.columbia.edu/kermit/whatsnew.html
+ 9. http://www.columbia.edu/kermit/ckfaq.html
+ 10. http://www.columbia.edu/kermit/support.html
+ 11. http://www.columbia.edu/kermit/
+ 12. http://www.columbia.edu/
+ 13. http://www.columbia.edu/kermit/ckututor.pdf
+ 14. ftp://kermit.columbia.edu/kermit/test/text/ckuker.nr
+ 15. http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641
+ 16. http://www.columbia.edu/kermit/ckututor.html#description
+ 17. http://www.columbia.edu/kermit/ckututor.html#synopsis
+ 18. http://www.columbia.edu/kermit/ckututor.html#options
+ 19. http://www.columbia.edu/kermit/ckututor.html#commands
+ 20. http://www.columbia.edu/kermit/ckututor.html#initfile
+ 21. http://www.columbia.edu/kermit/ckututor.html#modes
+ 22. http://www.columbia.edu/kermit/ckututor.html#connections
+ 23. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 24. http://www.columbia.edu/kermit/ckututor.html#server
+ 25. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 26. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 27. http://www.columbia.edu/kermit/ckututor.html#security
+ 28. http://www.columbia.edu/kermit/ckututor.html#personae
+ 29. http://www.columbia.edu/kermit/ckututor.html#license
+ 30. http://www.columbia.edu/kermit/ckututor.html#other
+ 31. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 32. http://www.columbia.edu/kermit/ckututor.html#files
+ 33. http://www.columbia.edu/kermit/ckututor.html#authors
+ 34. http://www.columbia.edu/kermit/ckututor.html#top
+ 35. http://www.columbia.edu/kermit/ckututor.html#contents
+ 36. http://www.columbia.edu/kermit/ckututor.html#synopsis
+ 37. http://www.columbia.edu/kermit/ckermit.html
+ 38. http://www.columbia.edu/kermit/
+ 39. http://www.columbia.edu/
+ 40. ftp://ftp.isi.edu/in-notes/rfc2839.txt
+ 41. ftp://ftp.isi.edu/in-notes/rfc2840.txt
+ 42. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 43. http://www.columbia.edu/kermit/
+ 44. http://www.columbia.edu/kermit/
+ 45. http://www.columbia.edu/kermit/ckermit.html
+ 46. http://www.columbia.edu/kermit/ckfaq.html
+ 47. http://www.columbia.edu/kermit/ckututor.html#top
+ 48. http://www.columbia.edu/kermit/ckututor.html#contents
+ 49. http://www.columbia.edu/kermit/ckututor.html#options
+ 50. http://www.columbia.edu/kermit/ckututor.html#synopsis
+ 51. http://www.columbia.edu/kermit/ckututor.html#kerbang
+ 52. http://www.columbia.edu/kermit/ckututor.html#personae
+ 53. http://www.columbia.edu/kermit/ckututor.html#kerbang
+ 54. http://www.columbia.edu/kermit/ckututor.html#initfile
+ 55. http://www.columbia.edu/kermit/ckututor.html#initfile
+ 56. http://www.columbia.edu/kermit/ckututor.html#personae
+ 57. http://www.columbia.edu/kermit/ckututor.html#options
+ 58. http://www.columbia.edu/kermit/ckututor.html#commands
+ 59. http://www.columbia.edu/kermit/
+ 60. http://www.columbia.edu/kermit/ckermit.html
+ 61. http://www.columbia.edu/kermit/ckfaq.html
+ 62. http://www.columbia.edu/kermit/ckututor.html#top
+ 63. http://www.columbia.edu/kermit/ckututor.html#contents
+ 64. http://www.columbia.edu/kermit/ckututor.html#commands
+ 65. http://www.columbia.edu/kermit/ckututor.html#description
+ 66. http://www.columbia.edu/kermit/ckututor.html#commands
+ 67. http://www.columbia.edu/kermit/ckututor.html#personae
+ 68. http://www.columbia.edu/kermit/ckututor.html#personae
+ 69. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 70. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 71. http://www.columbia.edu/kermit/ckututor.html#top
+ 72. http://www.columbia.edu/kermit/ckututor.html#contents
+ 73. http://www.columbia.edu/kermit/ckututor.html#initfile
+ 74. http://www.columbia.edu/kermit/ckututor.html#options
+ 75. http://www.columbia.edu/kermit/ckututor.html#kerbang
+ 76. http://www.columbia.edu/kermit/ckututor.html#cmdlist
+ 77. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 78. http://www.columbia.edu/kermit/ckututor.html#initfile
+ 79. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 80. http://www.columbia.edu/kermit/ckscripts.html
+ 81. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 82. http://www.columbia.edu/kermit/
+ 83. http://www.columbia.edu/kermit/ckermit.html
+ 84. http://www.columbia.edu/kermit/ckfaq.html
+ 85. http://www.columbia.edu/kermit/ckututor.html#top
+ 86. http://www.columbia.edu/kermit/ckututor.html#contents
+ 87. http://www.columbia.edu/kermit/ckututor.html#modes
+ 88. http://www.columbia.edu/kermit/ckututor.html#commands
+ 89. http://www.columbia.edu/kermit/
+ 90. http://www.columbia.edu/kermit/ckermit.html
+ 91. http://www.columbia.edu/kermit/ckfaq.html
+ 92. http://www.columbia.edu/kermit/ckututor.html#top
+ 93. http://www.columbia.edu/kermit/ckututor.html#contents
+ 94. http://www.columbia.edu/kermit/ckututor.html#connections
+ 95. http://www.columbia.edu/kermit/ckututor.html#initfile
+ 96. http://www.columbia.edu/kermit/ckfaq.html#term
+ 97. http://www.columbia.edu/kermit/
+ 98. http://www.columbia.edu/kermit/ckermit.html
+ 99. http://www.columbia.edu/kermit/ckfaq.html
+ 100. http://www.columbia.edu/kermit/ckututor.html#top
+ 101. http://www.columbia.edu/kermit/ckututor.html#contents
+ 102. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 103. http://www.columbia.edu/kermit/ckututor.html#modes
+ 104. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 105. http://www.columbia.edu/kermit/cable.html
+ 106. ftp://ftp.isi.edu/in-notes/rfc2217.txt
+ 107. http://www.columbia.edu/kermit/cable.html
+ 108. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 109. http://www.columbia.edu/kermit/
+ 110. http://www.columbia.edu/kermit/ckermit.html
+ 111. http://www.columbia.edu/kermit/ckfaq.html
+ 112. http://www.columbia.edu/kermit/ckututor.html#top
+ 113. http://www.columbia.edu/kermit/ckututor.html#contents
+ 114. http://www.columbia.edu/kermit/ckututor.html#server
+ 115. http://www.columbia.edu/kermit/ckututor.html#connections
+ 116. http://www.columbia.edu/kermit/ckututor.html#download
+ 117. http://www.columbia.edu/kermit/ckututor.html#upload
+ 118. http://www.columbia.edu/kermit/ckututor.html#oldfashioned
+ 119. http://www.columbia.edu/kermit/ckututor.html#trouble
+ 120. http://www.columbia.edu/kermit/ckututor.html#advanced
+ 121. http://www.columbia.edu/kermit/ckututor.html#nonkermit
+ 122. http://www.columbia.edu/kermit/kermit.html#notslow
+ 123. http://www.columbia.edu/kermit/ckermit.html
+ 124. http://www.columbia.edu/kermit/k95.html
+ 125. http://www.columbia.edu/kermit/k95.html
+ 126. http://www.columbia.edu/kermit/ckermit.html
+ 127. http://www.columbia.edu/kermit/mskermit.html
+ 128. http://www.columbia.edu/kermit/
+ 129. http://www.columbia.edu/kermit/support.html
+ 130. http://www.columbia.edu/kermit/ckmanual.html
+ 131. mailto:kermit-support@columbia.edu
+ 132. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 133. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 134. http://www.columbia.edu/kermit/
+ 135. http://www.columbia.edu/kermit/ckermit.html
+ 136. http://www.columbia.edu/kermit/ckfaq.html
+ 137. http://www.columbia.edu/kermit/ckututor.html#top
+ 138. http://www.columbia.edu/kermit/ckututor.html#contents
+ 139. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 140. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 141. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 142. http://www.columbia.edu/kermit/
+ 143. http://www.columbia.edu/kermit/ckermit.html
+ 144. http://www.columbia.edu/kermit/ckfaq.html
+ 145. http://www.columbia.edu/kermit/ckututor.html#top
+ 146. http://www.columbia.edu/kermit/ckututor.html#contents
+ 147. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 148. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 149. http://www.columbia.edu/kermit/ckututor.html#server
+ 150. http://www.columbia.edu/kermit/ftpclient.html
+ 151. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 152. http://www.columbia.edu/kermit/
+ 153. http://www.columbia.edu/kermit/ckermit.html
+ 154. http://www.columbia.edu/kermit/ckfaq.html
+ 155. http://www.columbia.edu/kermit/ckermit3.html#x3
+ 156. http://www.columbia.edu/kermit/ckermit3.html#x2.2
+ 157. http://www.columbia.edu/kermit/ckututor.html#top
+ 158. http://www.columbia.edu/kermit/ckututor.html#contents
+ 159. http://www.columbia.edu/kermit/ckututor.html#security
+ 160. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 161. http://www.columbia.edu/kermit/cuiksd.html
+ 162. http://www.columbia.edu/kermit/iksd.html
+ 163. http://www.columbia.edu/kermit/
+ 164. http://www.columbia.edu/kermit/ckermit.html
+ 165. http://www.columbia.edu/kermit/ckfaq.html
+ 166. http://www.columbia.edu/kermit/ckututor.html#top
+ 167. http://www.columbia.edu/kermit/ckututor.html#contents
+ 168. http://www.columbia.edu/kermit/ckututor.html#personae
+ 169. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 170. http://www.columbia.edu/kermit/security.html
+ 171. http://www.columbia.edu/kermit/
+ 172. http://www.columbia.edu/kermit/ckermit.html
+ 173. http://www.columbia.edu/kermit/ckfaq.html
+ 174. http://www.columbia.edu/kermit/ckututor.html#top
+ 175. http://www.columbia.edu/kermit/ckututor.html#contents
+ 176. http://www.columbia.edu/kermit/ckututor.html#license
+ 177. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 178. http://www.columbia.edu/kermit/ckututor.html#options
+ 179. http://www.columbia.edu/kermit/ckermit3.html#x3.1.2
+ 180. http://www.columbia.edu/kermit/
+ 181. http://www.columbia.edu/kermit/ckermit.html
+ 182. http://www.columbia.edu/kermit/ckfaq.html
+ 183. http://www.columbia.edu/kermit/ckututor.html#top
+ 184. http://www.columbia.edu/kermit/ckututor.html#contents
+ 185. http://www.columbia.edu/kermit/ckututor.html#other
+ 186. http://www.columbia.edu/kermit/ckututor.html#personae
+ 187. http://www.columbia.edu/kermit/ck90.html
+ 188. http://www.columbia.edu/kermit/cu-bsd-license.html
+ 189. http://www.opensource.org/
+ 190. http://www.columbia.edu/kermit/
+ 191. http://www.columbia.edu/kermit/ckermit.html
+ 192. http://www.columbia.edu/kermit/ckfaq.html
+ 193. http://www.columbia.edu/kermit/ckututor.html#top
+ 194. http://www.columbia.edu/kermit/ckututor.html#contents
+ 195. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 196. http://www.columbia.edu/kermit/ckututor.html#license
+ 197. http://www.columbia.edu/kermit/
+ 198. http://www.columbia.edu/kermit/howtoget.html
+ 199. http://www.columbia.edu/kermit/
+ 200. http://www.columbia.edu/kermit/ckermit.html
+ 201. http://www.columbia.edu/kermit/ckfaq.html
+ 202. http://www.columbia.edu/kermit/ckututor.html#top
+ 203. http://www.columbia.edu/kermit/ckututor.html#contents
+ 204. http://www.columbia.edu/kermit/ckututor.html#files
+ 205. http://www.columbia.edu/kermit/ckututor.html#other
+ 206. http://www.columbia.edu/kermit/ckmanual.html
+ 207. http://www.amazon.com/gp/product/B002ACPF9M?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=B002ACPF9M
+ 208. http://www.columbia.edu/kermit/ckermit70.html
+ 209. http://www.columbia.edu/kermit/ckermit80.html
+ 210. http://www.columbia.edu/kermit/ckermit90.html
+ 211. http://www.columbia.edu/kermit/ckermit.html
+ 212. http://www.columbia.edu/kermit/ck80binaries.html
+ 213. http://www.columbia.edu/kermit/scriptlib.html
+ 214. http://www.columbia.edu/kermit/newfaq.html
+ 215. http://www.columbia.edu/kermit/ckfaq.html
+ 216. http://www.columbia.edu/kermit/security.html
+ 217. http://www.columbia.edu/kermit/telnet.html
+ 218. http://www.columbia.edu/kermit/studies.html
+ 219. http://www.columbia.edu/kermit/ckcbwr.html
+ 220. http://www.columbia.edu/kermit/ckubwr.html
+ 221. http://www.columbia.edu/kermit/ckvbwr.html
+ 222. http://www.columbia.edu/kermit/ckuins.html
+ 223. http://www.columbia.edu/kermit/ckvins.html
+ 224. http://www.columbia.edu/kermit/support.html
+ 225. http://www.columbia.edu/kermit/k95tutorial.html
+ 226. news:comp.protocols.kermit.misc
+ 227. http://www.columbia.edu/kermit/
+ 228. http://www.columbia.edu/kermit/ckermit.html
+ 229. http://www.columbia.edu/kermit/ckfaq.html
+ 230. http://www.columbia.edu/kermit/ckututor.html#top
+ 231. http://www.columbia.edu/kermit/ckututor.html#contents
+ 232. http://www.columbia.edu/kermit/ckututor.html#authors
+ 233. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 234. http://www.columbia.edu/kermit/cu-bsd-license.html
+ 235. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit.ini
+ 236. ftp://kermit.columbia.edu/kermit/c-kermit/ckermod.ini
+ 237. http://www.columbia.edu/kermit/ckuins.html
+ 238. http://www.columbia.edu/kermit/ckcbwr.html
+ 239. http://www.columbia.edu/kermit/ckubwr.html
+ 240. http://www.columbia.edu/kermit/ckcplm.html
+ 241. http://www.columbia.edu/kermit/ckccfg.html
+ 242. http://www.columbia.edu/kermit/ckuins.html
+ 243. http://www.columbia.edu/kermit/
+ 244. http://www.columbia.edu/kermit/ckermit.html
+ 245. http://www.columbia.edu/kermit/ckfaq.html
+ 246. http://www.columbia.edu/kermit/ckututor.html#top
+ 247. http://www.columbia.edu/kermit/ckututor.html#contents
+ 248. http://www.columbia.edu/kermit/ckututor.html#files
+ 249. mailto:kermit@columbia.edu
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuus2.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus2.c
new file mode 100644
index 0000000..db0dfe9
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus2.c
@@ -0,0 +1,14491 @@
+#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, 2011,
+ 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(). (This statement was true in the 1980s and
+ probably is not a big concern in the 21st Century, but you never know;
+ there still might exist some 16-bit platforms and C compilers that have
+ restrictions like this.
+*/
+#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 char * ck_cryear; /* For copyright notice */
+
+extern xx_strp xxstring;
+extern char * ccntab[];
+/*
+ hlptok contains the string for which the user requested help. This is
+ useful for distinguishing synonyms, in case different help text is needed
+ depending on which synonym was given.
+*/
+extern char * hlptok;
+
+#ifndef NOIKSD
+ extern int inserver;
+#endif /* IKSD */
+
+#ifndef NOICP
+extern int cmflgs;
+
+#ifdef DCMDBUF
+extern char *cmdbuf, *atmbuf;
+#else
+extern char cmdbuf[], atmbuf[];
+#endif /* DCMDBUF */
+#endif /* NOICP */
+
+extern char *xarg0;
+extern int nrmt, nprm, dfloc, local, parity, escape;
+extern int turn, flow;
+extern int binary, quiet, keep;
+extern int success, xaskmore;
+#ifdef OS2
+extern int tt_rows[], tt_cols[];
+#else /* OS2 */
+extern int tt_rows, tt_cols;
+#endif /* OS2 */
+extern int cmd_rows, cmd_cols;
+
+extern long speed;
+extern char *dftty, *versio, *ckxsys;
+#ifndef NOHELP
+extern char *helpfile;
+#endif /* NOHELP */
+extern struct keytab prmtab[];
+#ifndef NOXFER
+extern struct keytab remcmd[];
+#endif /* NOXFER */
+
+#ifndef NOICP
+
+/* Interactive help strings */
+
+/* Top-level HELP text. IMPORTANT: Also see tophlpi[] for IKSD. */
+
+static char *tophlp[] = {
+"Trustees of Columbia University in the City of New York.\n",
+
+#ifndef NOHELP
+" Type EXIT to exit.",
+#ifdef OS2
+" Type INTRO for a brief introduction to the 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",
+#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://kermit.columbia.edu/ckermit.html#doc.",
+#endif /* MAC */
+#endif /* OS2 */
+#ifdef MAC
+" ",
+"Also see the Mac Kermit Doc and Bwr files on the Mac Kermit diskette.\n",
+#else
+#ifdef HPUX10
+" ",
+"See the files in /usr/share/lib/kermit/ for additional information.",
+#endif /* HPUX10 */
+#endif /* MAC */
+""
+};
+
+#ifndef NOIKSD
+static char *tophlpi[] = { /* Top-level help for IKSD */
+
+"Trustees of Columbia University in the City of New York.\n",
+
+#ifndef NOHELP
+" Type INTRO for a brief introduction to Kermit commands.",
+" Type VERSION for version and copyright information.",
+" Type HELP followed by a command name for help about a specific command.",
+" Type SUPPORT to learn how to get technical support.",
+" Type LOGOUT (or EXIT) to log out.",
+" Press ? (question mark) at the prompt, or anywhere within a command,",
+" for a menu (context-sensitive help, menu on demand).",
+#else
+"Press ? for a list of commands; see documentation for detailed descriptions.",
+#endif /* NOHELP */
+" ",
+"DOCUMENTATION: \"Using C-Kermit\" by Frank da Cruz and Christine M. Gianone,",
+"2nd Edition, Digital Press (1997), ISBN 1-55558-164-1. More info at the",
+"Kermit Project website, http://kermit.columbia.edu/.",
+""
+};
+#endif /* NOIKSD */
+
+#ifndef NOHELP
+char *newstxt[] = {
+#ifdef OS2
+"Welcome to Kermit 95 3.x.x. Major new features since 2.1.3 include:",
+#else
+"Welcome to C-Kermit 9.0.300. New features since 8.0.211 include:",
+#endif /* OS2 */
+" . Open Source Simplified 3-Clause BSD License",
+" . Full 64-bit memory model on platforms that support it",
+" . Large file support (64-bit file size) on most platforms",
+" . Long integer variables and constants in commands and scripts",
+" . Bigger maximum command and macro lengths",
+" . Bigger filename expansion space",
+" . New super-flexible RENAME command",
+" . New COPY and DIRECTORY command options",
+" . New TOUCH command",
+" . Raw SSL/TLS connections for connecting to POP3 and similar services",
+" . At prompt, Ctrl-K recalls most recent filename",
+" . Scripting and performance improvements and bug fixes",
+" ",
+"Documentation:",
+" 1. http://kermit.columbia.edu/usingckermit.html",
+" \"Using C-Kermit\", second edition (1997), current with C-Kermit 6.0.",
+" ",
+" 2. http://kermit.columbia.edu/ckermit70.html",
+" which documents the new features of C-Kermit 7.0.",
+" ",
+" 3. http://kermit.columbia.edu/ckermit80.html",
+" which documents the new features of C-Kermit 8.0.",
+" ",
+" 4. http://kermit.columbia.edu/ckermit90.html",
+" which documents the new features of C-Kermit 9.0.",
+" ",
+"If the release date shown by the VERSION command is long past, be sure to",
+"check with the Kermit website to see if there have been updates:",
+" ",
+#ifdef OS2
+" http://kermit.columbia.edu/k95.html (Kermit 95 home page)",
+#else
+" http://kermit.columbia.edu/ckermit.html (C-Kermit home page)",
+#endif /* OS2 */
+" http://kermit.columbia.edu/ (Kermit Project home page)",
+""
+};
+#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 */
+#ifndef NOLASTFILE
+" . CTRL-K: Insert the most recently entered local file specifiction.",
+#endif /* NOLASTFILE */
+
+" . ? (question mark) Display a menu for the current command field."
+,
+" . ESC (or TAB or Ctrl-I) Attempt to complete the current field.",
+" . \\ (backslash) include the following character literally",
+#ifndef NOSPL
+" or introduce a backslash code, variable, or function.",
+#else
+" or introduce a numeric backslash code.",
+#endif /* NOSPL */
+" ",
+
+"IMPORTANT: Since backslash (\\) is Kermit's command-line escape character,",
+"you must enter DOS, Windows, or OS/2 pathnames using either forward slash (/)"
+,
+"or double backslash (\\\\) as the directory separator in most contexts.",
+"Examples: C:/TMP/README.TXT, C:\\\\TMP\\\\README.TXT.",
+" ",
+
+"Command words other than filenames can be abbreviated in most contexts.",
+" ",
+
+"Basic commands:",
+" EXIT Exit from Kermit",
+" HELP Request general help",
+" HELP command Request help about the given command",
+" TAKE Execute commands from a file",
+" TYPE Display a file on your screen",
+" ORIENTATION Explains directory structure",
+" ",
+
+#ifndef NOXFER
+"Commands for file transfer:",
+" SEND Send files",
+" RECEIVE Receive files",
+" GET Get files from a Kermit server",
+#ifdef CK_RESEND
+" RESEND Recover an interrupted send",
+" REGET Recover an interrupted get from a server",
+#endif /* CK_RESEND */
+#ifndef NOSERVER
+" SERVER Be a Kermit server",
+#endif /* NOSERVER */
+" ",
+"File-transfer speed selection:",
+" FAST Use fast settings -- THIS IS THE DEFAULT",
+" CAUTIOUS Use slower, more cautious settings",
+" ROBUST Use extremely slow and cautious settings",
+" ",
+"File-transfer performance fine tuning:",
+" SET RECEIVE PACKET-LENGTH Kermit packet size",
+" SET WINDOW Number of sliding window slots",
+" SET PREFIXING Amount of control-character prefixing",
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+" ",
+"To make a direct serial connection:",
+#ifdef OS2
+#ifdef NT
+#ifdef CK_TAPI
+" SET PORT TAPI Select TAPI communication device",
+#endif /* CK_TAPI */
+" SET PORT Select serial communication device",
+#else
+" SET PORT Select serial communication port or server",
+#endif /* NT */
+#else
+" SET LINE Select serial communication device",
+#endif /* OS2 */
+" SET SPEED Select communication speed",
+" SET PARITY Communications parity (if necessary)",
+#ifdef CK_RTSCTS
+" SET FLOW Communications flow control, such as RTS/CTS",
+#else
+" SET FLOW Communications flow control, such as XON/XOFF",
+#endif /* CK_RTSCTS */
+" CONNECT Begin terminal connection",
+
+#ifndef NODIAL
+" ",
+"To dial out with a modem:",
+" SET DIAL DIRECTORY Specify dialing directory file (optional)",
+" SET DIAL COUNTRY-CODE Country you are dialing from (*)",
+" SET DIAL AREA-CODE Area-code you are dialing from (*)",
+" LOOKUP Lookup entries in your dialing directory (*)",
+" SET MODEM TYPE Select modem type",
+#ifdef OS2
+#ifdef NT
+#ifdef CK_TAPI
+" SET PORT TAPI Select TAPI communication device",
+#endif /* CK_TAPI */
+" SET PORT Select serial communication device",
+#else
+" SET PORT Select serial communication port or server",
+#endif /* NT */
+#else
+" SET LINE Select serial communication device",
+#endif /* OS2 */
+" SET SPEED Select communication speed",
+" SET PARITY Communications parity (if necessary)",
+" DIAL Dial the phone number",
+" CONNECT Begin terminal connection",
+" ",
+#ifdef OS2
+"Further info: HELP DIAL, HELP SET MODEM, HELP SET PORT, HELP SET DIAL",
+#else
+"Further info: HELP DIAL, HELP SET MODEM, HELP SET LINE, HELP SET DIAL",
+#endif /* OS2 */
+"(*) (For use with optional dialing directory)",
+#endif /* NODIAL */
+
+#ifdef NETCONN
+" ",
+"To make a network connection:",
+#ifndef NODIAL
+" SET NETWORK DIRECTORY Specify a network services directory (optional)",
+" LOOKUP Lookup entries in your network directory",
+#endif /* NODIAL */
+" SET NETWORK TYPE Select network type (if more than one available)",
+" SET HOST Make a network connection but stay in command mode",
+" CONNECT Begin terminal connection",
+#ifdef TNCODE
+" TELNET Select a Telnet host and CONNECT to it",
+#endif /* TNCODE */
+#ifdef RLOGCODE
+" RLOGIN Select an Rlogin host and CONNECT to it",
+#endif /* RLOGCODE */
+#ifdef ANYSSH
+" SSH [ OPEN ] Select an SSH host and CONNECT to it",
+#endif /* ANYSSH */
+#ifdef NEWFTP
+" FTP [ OPEN ] Make an FTP connection",
+#endif /* NEWFTP */
+#ifdef CKHTTP
+" HTTP OPEN Make an HTTP connection",
+#endif /* CKHTTP */
+#endif /* NETCONN */
+
+#ifdef NT
+" ",
+"To return from the terminal window to the K-95> prompt:",
+#else
+#ifdef OS2
+" ",
+"To return from the terminal window to the K/2> prompt:",
+#else
+" ",
+"To return from a terminal connection to the C-Kermit prompt:",
+#endif /* OS2 */
+#endif /* NT */
+#ifdef OS2
+" \
+Press the key or key-combination shown after \"Command:\" in the status line",
+" (such as Alt-x) or type your escape character followed by the letter C.",
+#else
+" Type your escape character followed by the letter C.",
+#endif /* OS2 */
+" ",
+"To display your escape character:",
+" SHOW ESCAPE",
+" ",
+"To display other settings:",
+" SHOW COMMUNICATIONS, SHOW TERMINAL, SHOW FILE, SHOW PROTOCOL, etc.",
+#else /* !NOLOCAL */
+" ",
+"To display settings:",
+" SHOW COMMUNICATIONS, SHOW FILE, SHOW PROTOCOL, etc.",
+#endif /* NOLOCAL */
+" ",
+"The manual for C-Kermit is the book \"Using C-Kermit\". For information",
+"about the manual, visit:",
+" http://kermit.columbia.edu/usingckermit.html",
+" ",
+#ifdef OS2
+"For a Kermit 95 tutorial, visit:",
+" http://kermit.columbia.edu/k95tutor.html",
+" ",
+#endif /* OS2 */
+"For an online C-Kermit tutorial, visit:",
+" http://kermit.columbia.edu/ckututor.html",
+" ",
+"To learn about script programming and automation:",
+" http://kermit.columbia.edu/ckscripts.html",
+" ",
+"For further information about a particular command, type HELP xxx,",
+"where xxx is the name of the command. For documentation, news of new",
+"releases, and information about other Kermit software, visit the",
+"Kermit Project website:",
+" ",
+" http://kermit.columbia.edu/",
+" ",
+"For information about technical support please visit this page:",
+" ",
+" http://kermit.columbia.edu/support.html",
+""
+};
+
+static char * hmxymatch[] = {
+"SET MATCH { DOTFILE, FIFO } { ON, OFF }",
+" Tells whether wildcards should match dotfiles (files whose names begin",
+" with period) or UNIX FIFO special files. MATCH FIFO default is OFF.",
+" MATCH DOTFILE default is OFF in UNIX, ON elsewhere.",
+""
+};
+
+#ifndef NOSEXP
+static char * hmxysexp[] = {
+"SET SEXPRESSION { DEPTH-LIMIT, ECHO-RESULT, TRUNCATE-ALL-RESULTS }",
+" DEPTH-LIMIT sets a limit on the depth of nesting or recursion in",
+" S-Expressions to prevent the program from crashing from memory exhaustion.",
+" ECHO-RESULT tells whether S-Expression results should be displayed as",
+" a result of evaluating an expression; the default is to display only at",
+" top (interactive) level; OFF means never display; ON means always display.",
+" TRUNCATE-ALL-RESULTS ON means the results of all arithmetic operations",
+" should be forced to integers (whole numbers) by discarding any fractional",
+" part. The default is OFF. SHOW SEXPRESSION displays the current settings."
+,""
+};
+#endif /* NOSEXP */
+
+#ifdef OS2
+#ifdef KUI
+static char * hmxygui[] = {
+"SET GUI CLOSE OFF",
+" Disables the System Menu Close and File->Exit functions which could be",
+" used to exit Kermit. Once disabled these functions cannot be re-enabled",
+" and the only way to exit Kermit is via the Kermit Script EXIT command.",
+" ",
+"SET GUI DIALOGS { ON, OFF }",
+" ON means that popups, alerts, use GUI dialogs; OFF means to use",
+" text-mode popups or prompts. ON by default.",
+" ",
+"SET GUI FONT name size",
+" Chooses the font and size. Type \"set gui font ?\" to see the list of",
+" choices. The size can be a whole number or can contain a decimal point",
+" and a fraction (which is rounded to the nearest half point).",
+" ",
+"SET GUI MENUBAR OFF",
+" Disables menubar functions which could be used to modify the Kermit",
+" session configuration. Once disabled the menubar functions cannot be",
+" re-enabled.",
+" ",
+"SET GUI RGBCOLOR colorname redvalue greenvalue bluevalue",
+" Specifies the red-green-blue mixture to be used to render the given",
+" color name. Type \"set gui rgbcolor\" to see a list of colornames.",
+" the RGB values are whole numbers from 0 to 255.",
+" ",
+"SET GUI TOOLBAR OFF",
+" Disables toolbar functions which could be used to modify the Kermit",
+" session configuration. Once disabled the toolbar functions cannot be",
+" re-enabled.",
+" ",
+"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 */
+
+#ifdef UNIX
+#ifndef NOPUTENV
+static char *hmxxputenv[] = {
+"Syntax: PUTENV name value",
+" Creates or modifies the environment variable with the given name to have",
+" the given value. Purpose: to pass parameters to subprocesses without",
+" having them appear on the command line. If the value is blank (empty),",
+" the variable is deleted. The result is visible to this instantiation of",
+" C-Kermit via \\$(name) and to any inferior processes by whatever method",
+" they use to access environment variables. The value may be enclosed in",
+" doublequotes or braces, but it need not be; if it is the outermost",
+" doublequotes or braces are removed.",
+" ",
+" Note the syntax:",
+" PUTENV name value",
+" not:",
+" PUTENV name=value",
+" ",
+" There is no equal sign between name and value, and the name itself may",
+" not include an equal sign.",
+"",
+};
+#endif /* NOPUTENV */
+#endif /* UNIX */
+
+static char *hmxxtak[] = {
+"Syntax: TAKE filename [ arguments ]",
+" Tells Kermit to execute commands from the named file. Optional argument",
+" words, are automatically assigned to the macro argument variables \\%1",
+" through \\%9. Kermit command files may themselves contain TAKE commands,",
+" up to any reasonable depth of nesting.",
+""
+};
+
+#ifdef TCPSOCKET
+static char *hmxxfirew[] = {
+#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[] = {
+"Function \\fword(s1,n1,s2,s3,n2,n3) - Extracts a word from a string.",
+" s1 = source string.",
+" n1 = word number (1-based) counting from left; if negative, from right.",
+" s2 = optional break set.",
+" s3 = optional include set (or ALL, CSV, or TSV).",
+" n2 = optional grouping mask.",
+" n3 = optional separator flag:",
+" 0 = collapse adjacent separators;",
+" 1 = don't collapse adjacent separators.",
+" ",
+" \\fword() returns the n1th \"word\" of the string s1, according to the",
+" criteria specified by the other parameters.",
+" ",
+" The BREAK SET is the set of all characters that separate words. The",
+" default break set is all characters except ASCII letters and digits.",
+" ASCII (C0) control characters are treated as break characters by default,",
+" as are spacing and punctuation characters, brackets, and so on, and",
+" all 8-bit characters.",
+" ",
+" The INCLUDE SET is the set of characters that are to be treated as ",
+" parts of words even though they normally would be separators. The",
+" default include set is empty. Three special symbolic include sets are",
+" also allowed:",
+" ",
+" ALL (meaning include all bytes that are not in the break set)",
+" CSV (special treatment for Comma-Separated-Value records)",
+" TSV (special treatment for Tab-Separated-Value records)",
+" ",
+" For operating on 8-bit character sets, the include set should be ALL.",
+" ",
+" If the GROUPING MASK is given and is nonzero, words can be grouped by",
+" quotes or brackets selected by the sum of the following:",
+" ",
+" 1 = doublequotes: \"a b c\"",
+" 2 = braces: {a b c}",
+" 4 = apostrophes: 'a b c'",
+" 8 = parentheses: (a b c)",
+" 16 = square brackets: [a b c]",
+" 32 = angle brackets: <a b c>",
+" ",
+" Nesting is possible with {}()[]<> but not with quotes or apostrophes.",
+" ",
+"Returns string:",
+" Word number n1, if there is one, otherwise an empty string.",
+" ",
+"Also see:",
+" HELP FUNCTION SPLIT",
+""
+};
+
+static char *hmxxprompt[] = {
+"Syntax: PROMPT [ text ]",
+" Enters interactive command level from within a script in such a way that",
+" the script can be continued with an END or RETURN command. STOP, EXIT,",
+" SHOW STACK, TRACE, and Ctrl-C all have their normal effects. The PROMPT",
+" command allows variables to be examined or changed, or any other commands",
+" to be given, in any number, prior to returning to the script, allowing",
+" Kermit to serve as its own debugger; adding the PROMPT command to a script",
+" is like setting a breakpoint. If the optional text is included, it is",
+" used as the new prompt for this level, e.g. \"prompt Breakpoint_1>\".",
+""
+};
+
+static char *hxxinp[] = {
+"Syntax: INPUT [ /COUNT:n /CLEAR /NOMATCH /NOWRAP ] \
+{ number-of-seconds, time-of-day } [ text ]",
+" ",
+"Examples:",
+" INPUT 5 Login:",
+" INPUT 23:59:59 RING",
+" INPUT /NOMATCH 10",
+" INPUT /CLEAR 10 \\13\\10",
+" INPUT /CLEAR 10 \\13\\10$\32",
+" INPUT /COUNT:256 10",
+" INPUT 10 \\fpattern(<*@*.*>)",
+" ",
+" Waits up to the given number of seconds, or until the given time of day,",
+" for the given text to arrive on the connection. For use in script programs",
+" with IF FAILURE or IF SUCCESS, which tell whether the desired text arrived",
+" within the given amount of time.",
+" ",
+" The text, if given, can be a regular text or it can be a \\pattern()",
+" invocation, in which case it is treated as a pattern rather than a literal",
+" string (HELP PATTERNS for details).",
+" ",
+" If the /COUNT: switch is included, INPUT waits for the given number of",
+" characters to arrive.",
+" ",
+" If no text is specified, INPUT waits for the first character that arrives",
+" and makes it available in the \\v(inchar) variable. This is equivalent to",
+" including a /COUNT: switch with an argument of 1.",
+" ",
+" If the /NOMATCH switch is included, INPUT does not attempt to match any",
+" characters, but continues reading from the communication connection until",
+" the timeout interval expires. If the timeout interval is 0, the INPUT",
+" command does not wait; i.e. the given text must already be available for",
+" reading for the INPUT command to succeed. If the interval is negative,",
+" the INPUT command waits forever.",
+" ",
+" The INPUT buffer, \\v(input), is normally circular. Incoming material is",
+" appended to it until it reaches the end, and then it wraps around to the",
+" beginning. If the /CLEAR switch is given, INPUT clears its buffer before",
+" reading from the connection.",
+" ",
+" Typical example of use:",
+" ",
+" INPUT 10 login:",
+" IF FAIL EXIT 1 \"Timed out waiting for login prompt\"",
+" LINEOUT myuserid",
+" INPUT 10 Password:",
+" IF FAIL EXIT 1 \"Timed out waiting for Password prompt\"",
+" LINEOUT xxxxxxx",
+" ",
+" The /NOWRAP switch means that INPUT should return with failure status",
+" and with \\v(instatus) set to 6 if its internal buffer fills up before",
+" any of the other completion criteria are met. This allows for capture",
+" of the complete incoming data stream (except NUL bytes, which are",
+" discarded). CAUTION: if the search target (if any) spans the INPUT buffer",
+" boundary, INPUT will not succeed.",
+" ",
+" \
+\\v(instatus) values are: 0 (success), 1 (timed out), 2 (keyboard interrupt),",
+" 3 (internal error), 4 (I/O error or connection lost), 5 (INPUT disabled),",
+" and 6 (buffer filled and /NOWRAP set); these are shown by \\v(inmessage).",
+" ",
+" Also see OUTPUT, MINPUT, REINPUT, SET INPUT and CLEAR. See HELP PAUSE for",
+" details on time-of-day format and HELP PATTERNS for pattern syntax.",
+""};
+
+static char *hxxout[] = {
+"Syntax: OUTPUT text",
+" Sends the text out the communications connection, as if you had typed it",
+" during CONNECT mode. The text may contain backslash codes, variables,",
+" etc, plus the following special codes:",
+" ",
+" \\N - Send a NUL (ASCII 0) character (you can't use \\0 for this).",
+" \\B - Send a BREAK signal.",
+" \\L - Send a Long BREAK signal.",
+" ",
+"Also see SET OUTPUT.",
+"" };
+#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 \"%s\" in",
+" any of these strings to represent the filename(s). If the protocol is",
+" KERMIT, you may also specify a string s3, the command to start a Kermit",
+" server on the remote host when you give a GET, REGET, REMOTE, or other",
+" client command. Use { braces } if any command contains spaces. Examples:",
+" ",
+" set proto xmodem {rx %s} {rx -a %s}",
+" set proto kermit {kermit -YQir} {kermit -YQTr} {kermit -YQx}",
+
+#else /* This is for when non-Kermit protocols are external */
+
+"Syntax: \
+SET PROTOCOL { KERMIT, XMODEM, YMODEM, ZMODEM } [ s1 s2 s3 s4 s5 s6 ]",
+" Selects protocol to use for transferring files. s1 and s2 are commands to",
+" output prior to SENDing with this protocol, to automatically start the",
+" RECEIVE process on the other end in binary or text mode, respectively.",
+" If the protocol is KERMIT, s3 is the command to start a Kermit server on",
+" the remote computer, and there are no s4-s6 commands. Otherwise, s3 and",
+" s4 are commands used on this computer for sending files with this protocol",
+" in binary or text mode, respectively; s5 and s6 are the commands for",
+" receiving files with this protocol. Use \"%s\" in any of these strings",
+" to represent the filename(s). Use { braces } if any command contains",
+" spaces. Examples:",
+" ",
+" set proto kermit {kermit -YQir} {kermit -YQTr} {kermit -YQx}",
+" set proto ymodem rb {rb -a} {sb %s} {sb -a %s} rb rb",
+" ",
+"External protocols require REDIRECT and external file transfer programs that",
+"use redirectable standard input/output.",
+#endif /* XYZ_INTERNAL */
+#else
+"Syntax: \
+SET PROTOCOL KERMIT [ s1 [ s2 [ s3 ] ] ]",
+" Lets you specify the autoupload binary, autoupload text, and autoserver",
+" command strings to be sent to the remote system in advance of any SEND",
+" or GET commands. By default these are \"kermit -ir\", \"kermit -r\", and",
+" \"kermit -x\". Use { braces } around any command that contains spaces.",
+" Example:",
+" ",
+" set proto kermit {kermit -Yir} {kermit -YTr} {kermit -Yx}",
+#endif /* CK_XYZ */
+" ",
+" SHOW PROTOCOL displays the current settings.",
+""};
+
+static char *hmxxbye = "Syntax: BYE\n\
+ Shut down and log out a remote Kermit server";
+
+#ifdef CK_PERMS
+#ifdef UNIX
+static char *hmxxchmod[] = {
+"Syntax: CHMOD [ switches ] code filespec",
+" UNIX only. Changes permissions of the given file(s) to the given code,",
+" which must be an octal number such as 664 or 775. Optional switches:",
+" ",
+" /FILES Only change permissions of regular files.",
+" /DIRECTORIES Only change permissions of directory files.",
+" /TYPE:BINARY Only change permissions of binary files.",
+" /TYPE:TEXT Only change permissions of text files.",
+" /DOTFILES Include files whose names begin with dot (.).",
+" /RECURSIVE Change permissions in subdirectories too.",
+" /LIST List each file (synonym: /VERBOSE).",
+" /NOLIST Operate silently (synonym: /QUIET).",
+" /PAGE When listing, pause at end of each screen (implies /LIST).",
+" /NOPAGE When listing, don't pause at end of each screen.",
+" /SIMULATE Show what would be done but don't actually do it.",
+""
+};
+#endif /* UNIX */
+#endif /* CK_PERMS */
+
+#ifndef NOSPL
+#ifndef NOSEXP
+static char *hmxxsexp[] = {
+"Syntax: (operation operand [ operand [ ... ] ])",
+" ",
+" C-Kermit includes a simple LISP-like S-Expression parser operating on",
+" numbers only. An S-Expression is always enclosed in parentheses. The",
+" parentheses can contain (a) a number, (b) a variable, (c) a function that",
+" returns a number, or (d) an operator followed by one or more operands.",
+" Operands can be any of (a) through (c) or an S-Expression. Numbers can be",
+" integers or floating-point. Any operand that is not a number and does not",
+" start with backslash (\\) is treated as a Kermit macro name. Operators:",
+" ",
+" Operator Action Example Value",
+" EVAL (.) Returns the contained value (6) 6",
+" QUOTE (') Inhibits evaluation of following value (quote a) a",
+" SETQ Assigns a value to a global variable (setq a 2) 2",
+" LET Assigns a value to a local variable (let b -1.3) -1.3",
+" + Adds all operands (1 or more) (+ a b) 0.7",
+" - Subtracts all operands (1 or more) (- 9 5 2 1) 1",
+" * Multiplies all operands (1 or more) (* a (+ b 1) 3) -1.8",
+" / Divides all operands (1 or more) (/ b a 2) -0.325",
+" ^ Raise given number to given power (^ 3 2) 9",
+" ++ Increments a variable (++ a 1.2) 3.2",
+" -- Decrements a variable (-- a) 1",
+" ABS Absolute value of 1 operand (abs (* a b 3)) 7.8",
+" MAX Maximum of all operands (1 or more) (max 1 2 3 4) 4",
+" MIN Minimum of all operands (1 or more) (min 1 2 3 4) 1",
+" MOD Modulus of all operands (1 or more) (mod 7 4 2) 1",
+" TRUNCATE Integer part of floating-point operand (truncate 1.333) 1",
+" CEILING Ceiling of floating-point operand (ceiling 1.25) 2",
+" FLOOR Floor of floating-point operand (floor 1.25) 1",
+" ROUND Operand rounded to nearest integer (round 1.75) 2",
+" SQRT Square root of 1 operand (sqrt 2) 1.414..",
+" EXP e (2.71828..) to the given power (exp -1) 0.367..",
+" SIN Sine of angle expressed in radians (sin (/ pi 2)) 1.0",
+" COS Cosine of given number (cos pi) -1.0",
+" TAN Tangent of given number (tan pi) 0.0",
+" LOG Natural log (base e) of given number (log 2.7183) 1.000..",
+" LOG10 Log base 10 of given number (log10 1000) 3.0",
+" ",
+"Predicate operators return 0 if false, 1 if true, and if it is the outermost",
+"operator, sets SUCCESS or FAILURE accordingly:",
+" ",
+" < Operands in strictly descending order (< 6 5 4 3 2 1) 1",
+" <= Operands in descending order (<= 6 6 5 4 3 2) 1",
+" != Operands are not equal (!= 1 1 1.0) 0",
+" = (==) All operands are equal (= 3 3 3 3) 1",
+" > Operands in strictly ascending order (> 1 2 3 4 5 6) 1",
+" >= Operands in ascending order (> 1 1 2 3 4 5) 1",
+" AND (&&) Operands are all true (and 1 1 1 1 0) 0",
+" OR (||) At least one operand is true (or 1 1 1 1 0) 1",
+" XOR Logical Exclusive OR (xor 3 1) 0",
+" NOT (!) Reverses truth value of operand (not 3) 0",
+" ",
+"Bit-oriented operators:",
+" ",
+" & Bitwise AND (& 7 2) 2",
+" | Bitwise OR (| 1 2 3 4) 7",
+" # Bitwise Exclusive OR (# 3 1) 2",
+" ~ Reverses all bits (~ 3) -4",
+" ",
+"Operators that work on truth values:",
+" ",
+" IF Conditional evaluation (if (1) 2 3) 2",
+" ",
+"Operators can also be names of Kermit macros that return either numeric",
+"values or no value at all.",
+" ",
+"Built-in constants are:",
+" ",
+" t True (1)",
+" nil False (empty)",
+" pi The value of Pi (3.1415926...)",
+" ",
+"If SET SEXPRESSION TRUNCATE-ALL-RESULTS is ON, all results are trunctated",
+"to integer values by discarding any fractional part. Otherwise results",
+"are floating-point if there fractional part and integer otherwise.",
+"If SET SEXPRESSION ECHO-RESULT is AUTO (the default), the value of the",
+"S-Expression is printed if the S-Expression is given at top level; if ON,",
+"it is printed at any level; if OFF it is not printed. At all levels, the",
+"variable \\v(sexpression) is set to the most recent S-Expression, and",
+"\\v(svalue) is set to its value. You can use the \\fsexpresssion() function",
+"to evaluate an S-Expression anywhere in a Kermit command.",
+""
+};
+#endif /* NOSEXP */
+#endif /* NOSPL */
+
+static char *hmxxgrep[] = {
+#ifdef UNIXOROSK
+"Syntax: GREP [ options ] pattern filespec",
+#else
+"Syntax: FIND [ options ] pattern filespec",
+#endif /* UNIXOROSK */
+" Searches through the given file or files for the given character string",
+" or pattern. In the normal case, all lines containing any text that matches"
+,
+" the pattern are printed. Pattern syntax is as described in HELP PATTERNS",
+" except that '*' is implied at the beginning unless the pattern starts with",
+" '^' and also at the end unless the pattern ends with '$'. Therefore,",
+" \"grep something *.txt\" lists all lines in all *.txt files that contain",
+" the word \"something\", but \"grep ^something *.txt\" lists only the lines",
+" that START with \"something\". The command succeeds if any of the given",
+" files 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.",
+" /EXCEPT:pattern",
+" Exclude lines that match the main pattern that also match this 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.",
+" /TOP:n Only show the top n lines of the directory listing.",
+#ifdef UNIXOROSK
+" /DOTFILES Include files whose names start with dot (period).",
+" /NODOTFILES + Don't include files whose names start with dot.",
+" /FOLLOWLINKS Follow symbolic links.",
+" /NOFOLLOWLINKS + Don't follow symbolic links.",
+" /NOLINKS Don't list symbolic links at all.",
+" /BACKUP + Include backup files (names end with .~n~).",
+" /NOBACKUPFILES Don't include backup files.",
+#endif /* UNIXOROSK */
+" /OUTPUT:file Store directory listing in the given file.",
+" /HEADING Include heading and summary.",
+" /NOHEADING + Don't include heading or summary.",
+" /COUNT:var Put the number of matching files in the given variable.",
+" /SUMMARY Print only count and total size of matching files.",
+" /XFERMODE Show pattern-based transfer mode (T=Text, B=Binary).",
+" /TYPE: Show only files of the specified type (text or binary).",
+" /MESSAGE:text Add brief message to each listing line.",
+" /NOMESSAGE + Don't add message to each listing line.",
+" /NOXFERMODE + Don't show pattern-based transfer mode",
+" /ISODATE + In verbose listings, show date in ISO 8061 format.",
+" /ENGLISHDATE In verbose listings, show date in \"English\" format.",
+#ifdef RECURSIVE
+" /RECURSIVE Descend through subdirectories.",
+" /NORECURSIVE + Don't descend through subdirectories.",
+#endif /* RECURSIVE */
+" /SORT:key Sort by key, NAME, DATE, or SIZE; default key is NAME.",
+" /NOSORT + Don't sort.",
+" /ASCENDING + If sorting, sort in ascending order.",
+" /REVERSE If sorting, sort in reverse order.",
+" ",
+"Factory defaults are marked with +. Default for paging depends on SET",
+"COMMAND MORE-PROMPTING. Use SET OPTIONS DIRECTORY [ switches ] to change",
+"defaults; use SHOW OPTIONS to display customized defaults. Also see",
+"WDIRECTORY.",
+#else
+"Syntax: DIRECTORY [ filespec ]",
+" Lists the specified file or files. If no filespec is given, all files",
+" in the current directory are listed.",
+#endif /* DOMYDIR */
+""};
+
+static char *hmxxtouc[] = {
+"Syntax: TOUCH [ switches ] filespec",
+" Updates the modification time of the given file or files to the current",
+" date and time. If the filespec is the name of a single file that does not",
+" exist, the file is created. The optional switches are the same as for",
+" the DIRECTORY command. TOUCH operates silently unless the /VERBOSE",
+" switch is given, in which case it lists each file it affects.",
+""};
+
+#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 in interactive commands, which is to",
+" provide menus and file lists.",
+#endif /* VMS */
+" ",
+#ifdef OS2ORUNIX
+#ifdef CKREGEX
+"[abc]",
+" Square brackets enclosing a list of characters matches any character in",
+" the list. Example: h[aou]t matches hat, hot, and hut.",
+" ",
+"[a-z]",
+" Square brackets enclosing a range of characters matches any character in",
+" the range; a hyphen (-) separates the low and high elements of the range.",
+" For example, [a-z] matches any character from a to z.",
+" ",
+"[acdm-z]",
+" Lists and ranges may be combined. This example matches a, c, d, or any",
+" letter from m through z.",
+" ",
+"{string1,string2,...}",
+" Braces enclose a list of strings to be matched. For example:",
+" ker{mit,nel,beros} matches kermit, kernel, and kerberos. The strings",
+" may themselves contain *, ?, [abc], [a-z], or other lists of strings.",
+#endif /* CKREGEX */
+#endif /* OS2ORUNIX */
+#ifndef NOSPL
+" ",
+"To force a special pattern character to be taken literally, precede it with",
+"a backslash, e.g. [a\\-z] matches a, hyphen, or z rather than a through z.",
+" ",
+"A floating pattern can also include the following special characters:",
+" ",
+"^ (First character of pattern) Anchors the pattern at the beginning.",
+"$ (Last character of pattern) Anchors the pattern at the end.",
+" ",
+"If a floating pattern does not start with \"^\", the pattern can match",
+"anywhere in the string instead of only at the beginning; in other words, a",
+"leading \"*\" is assumed. Similarly, if the pattern doesn't end with \"$\",",
+"a trailing \"*\" is assumed.",
+" ",
+"The following commands and functions use floating patterns:",
+" GREP [ <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 use anchored patterns, meaning that ^ and $",
+"are not treated specially, and * is not assumed at the beginning or end of",
+"the pattern. This is true mainly of filename patterns (wildcards), since",
+"you would not want a command like \"delete x\" to delete all files whose",
+"names contained \"x\"!",
+
+" ",
+"You can use anchored patterns not only in filenames, but also in SWITCH",
+"case labels, in the INPUT and MINPUT commands, and in file binary- and",
+"text-patterns for filenames. The IF MATCH pattern is also anchored.",
+#endif /* NOSPL */
+"" };
+
+static char *hmxxwild[] = {
+
+"A \"wildcard\" is a notation used in a filename to match multiple files.",
+"For example, in \"send *.txt\" the asterisk is a wildcard. Kermit commands",
+"that accept filenames also accepts wildcards, except commands that are",
+"allowed to operate on only one file, such as TRANSMIT.",
+"This version of Kermit accepts the following wildcards:",
+" ",
+"* Matches any sequence of zero or more characters. For example, \"ck*.c\"",
+" matches all files whose names start with \"ck\" and end with \".c\"",
+" including \"ck.c\".",
+" ",
+#ifdef VMS
+"% Matches any single character. For example, \"ck%.c\" matches all files",
+#else
+"? Matches any single character. For example, \"ck?.c\" matches all files",
+#endif /* VMS */
+" whose names are exactly 5 characters long and start with \"ck\" and end",
+#ifdef VMS
+" with \".c\".",
+#else
+" with \".c\". When typing commands at the prompt, you must precede any",
+" question mark to be used for matching by a backslash (\\) to override the",
+" normal function of question mark in interactive commands, which is to",
+" provide menus and file lists. You don't, however, need to quote filename",
+" question marks in command files (script programs).",
+#endif /* VMS */
+" ",
+#ifdef OS2ORUNIX
+#ifdef CKREGEX
+"[abc]",
+" Square brackets enclosing a list of characters matches any character in",
+" the list. Example: ckuusr.[ch] matches ckuusr.c and ckuusr.h.",
+" ",
+"[a-z]",
+" Square brackets enclosing a range of characters matches any character in",
+" the range; a hyphen (-) separates the low and high elements of the range.",
+" For example, [a-z] matches any character from a to z.",
+" ",
+"[acdm-z]",
+" Lists and ranges may be combined. This example matches a, c, d, or any",
+" letter from m through z.",
+" ",
+"{string1,string2,...}",
+" Braces enclose a list of strings to be matched. For example:",
+" ck{ufio,vcon,cmai}.c matches ckufio.c, ckvcon.c, or ckcmai.c. The strings",
+" may themselves contain *, ?, [abc], [a-z], or other lists of strings.",
+#endif /* CKREGEX */
+#endif /* OS2ORUNIX */
+" ",
+"To force a special pattern character to be taken literally, precede it with",
+"a backslash, e.g. [a\\-z] matches a, hyphen, or z rather than a through z.",
+"Or tell Kermit to SET WILDCARD-EXPANSION OFF before entering or referring",
+"to the filename.",
+" ",
+#ifndef NOSPL
+"Similar notation can be used in general-purpose string matching. Type HELP",
+"PATTERNS for details. Also see HELP SET MATCH.",
+#endif /* NOSPL */
+"" };
+
+#ifndef NOXFER
+static char *hmxxfast[] = {
+"FAST, CAUTIOUS, and ROBUST are predefined macros that set several",
+"file-transfer parameters at once to achieve the desired file-transfer goal.",
+"FAST chooses a large packet size, a large window size, and a fair amount of",
+"control-character unprefixing at the risk of possible failure on some",
+"connections. FAST is the default tuning in C-Kermit 7.0 and later. In case",
+"FAST file transfers fail for you on a particular connection, try CAUTIOUS.",
+"If that fails too, try ROBUST. You can also change the definitions of each",
+"macro with the DEFINE command. To see the current definitions, type",
+"\"show macro fast\", \"show macro cautious\", or \"show macro robust\".",
+""
+};
+#endif /* NOXFER */
+
+#ifdef VMS
+static char * hmxxpurge[] = {
+"Syntax: PURGE [ switches ] [ filespec ]",
+" Runs the DCL PURGE command. Switches and filespec are not parsed or",
+" verified by Kermit, but passed directly to DCL.",
+""
+};
+#else
+#ifdef CKPURGE
+static char * hmxxpurge[] = {
+"Syntax: PURGE [ switches ] [ filespec ]",
+" Deletes backup files; that is, files whose names end in \".~n~\", where",
+" n is a number. PURGE by itself deletes all backup files in the current",
+" directory. Switches:",
+
+" ",
+"/AFTER:date-time",
+#ifdef VMS
+" Specifies that only those files created after the given date-time are",
+#else
+" Specifies that only those files modified after the given date-time are",
+#endif /* VMS */
+" to be purged. HELP DATE for info about date-time formats.",
+" ",
+"/BEFORE:date-time",
+#ifdef VMS
+" Specifies that only those files modified before the given date-time",
+#else
+" Specifies that only those files modified before the given date-time",
+#endif /* VMS */
+" are to be purged.",
+" ",
+"/NOT-AFTER:date-time",
+#ifdef VMS
+" Specifies that only those files modified at or before the given date-time",
+#else
+" Specifies that only those files modified at or before the given date-time",
+#endif /* VMS */
+" are to be purged.",
+" ",
+"/NOT-BEFORE:date-time",
+#ifdef VMS
+" Specifies that only those files modified at or after the given date-time",
+#else
+" Specifies that only those files modified at or after the given date-time",
+#endif /* VMS */
+" are to be purged.",
+" ",
+"/LARGER-THAN:number",
+" Specifies that only those files longer than the given number of bytes are",
+" to be purged.",
+" ",
+"/SMALLER-THAN:number",
+" Specifies that only those files smaller than the given number of bytes are",
+" to be purged.",
+" ",
+"/EXCEPT:pattern",
+" Specifies that any files whose names match the pattern, which can be a",
+" regular filename or may contain wildcards, are not to be purged. To",
+" specify multiple patterns (up to 8), use outer braces around the group",
+" and inner braces around each pattern:",
+" ",
+" /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+#ifdef UNIXOROSK
+"/DOTFILES",
+" Include (purge) files whose names begin with \".\".",
+" ",
+"/NODOTFILES",
+" Skip (don't purge) files whose names begin with \".\".",
+" ",
+#endif /* UNIXOROSK */
+#ifdef RECURSIVE
+"/RECURSIVE",
+" Descends through the current or specified directory tree.",
+" ",
+#endif /* RECURSIVE */
+"/KEEP:n",
+" Retain the 'n' most recent (highest-numbered) backup files for each file.",
+" By default, none are kept. If /KEEP is given without a number, 1 is used.",
+" ",
+"/LIST",
+" Display each file as it is processed and say whether it is purged or kept.",
+" Synonyms: /LOG, /VERBOSE.",
+" ",
+"/NOLIST",
+" The PURGE command should operate silently (default).",
+" Synonyms: /NOLOG, /QUIET.",
+" ",
+"/HEADING",
+" Print heading and summary information.",
+" ",
+"/NOHEADING",
+" Don't print heading and summary information.",
+" ",
+"/PAGE",
+" When /LIST is in effect, pause at the end of each screenful, even if",
+" COMMAND MORE-PROMPTING is OFF.",
+" ",
+"/NOPAGE",
+" Don't pause, even if COMMAND MORE-PROMPTING is ON.",
+" ",
+"/ASK",
+" Interactively ask permission to delete each backup file.",
+" ",
+"/NOASK",
+" Purge backup files without asking permission.",
+" ",
+"/SIMULATE",
+" Inhibits the actual deletion of files; use to preview which files would",
+" actually be deleted. Implies /LIST.",
+" ",
+"Use SET OPTIONS PURGE [ switches ] to change defaults; use SHOW OPTIONS to",
+"display customized defaults. Also see HELP DELETE, HELP WILDCARD.",
+""
+};
+#endif /* CKPURGE */
+#endif /* VMS */
+
+static char *hmxxclo[] = {
+"Syntax: CLOSE [ item ]",
+" Close the indicated item. The default item is CONNECTION, which is the",
+" current SET LINE or SET HOST connection. The other items are:",
+" ",
+#ifdef CKLOGDIAL
+" CX-LOG (connection log, opened with LOG CX)",
+#endif /* CKLOGDIAL */
+#ifndef NOLOCAL
+" SESSION-LOG (opened with LOG SESSION)",
+#endif /* NOLOCAL */
+#ifdef TLOG
+" TRANSACTION-LOG (opened with LOG TRANSACTIONS)",
+#endif /* TLOG */
+" PACKET-LOG (opened with LOG PACKETS)",
+#ifdef DEBUG
+" DEBUG-LOG (opened with LOG DEBUG)",
+#endif /* DEBUG */
+#ifndef NOSPL
+" READ-FILE (opened with OPEN READ)",
+" WRITE-FILE (opened with OPEN WRITE or OPEN APPEND)",
+#endif /* NOSPL */
+" ",
+"Type HELP LOG and HELP OPEN for further info.",
+""
+};
+
+#ifdef CKLEARN
+static char * hmxxlearn[] = {
+"Syntax: LEARN [ /ON /OFF /CLOSE ] [ filename ]",
+" Records a login script. If you give a filename, the file is opened for",
+" subsequent recording. If you don't give any switches, /ON is assumed.",
+" /ON enables recording to the current file (if any); /OFF disables",
+" recording. /CLOSE closes the current file (if any). After LEARN /CLOSE",
+" or exit from Kermit, your script is available for execution by the TAKE",
+" command.",
+""
+};
+#endif /* CKLEARN */
+
+#ifdef CK_MINPUT
+static char *hmxxminp[] = {
+"Syntax: MINPUT [ switches ] n [ string1 [ string2 [ ... ] ] ]",
+"Example: MINPUT 5 Login: {Username: } {NO CARRIER} BUSY RING",
+" For use in script programs. Waits up to n seconds for any one of the",
+" strings to arrive on the communication device. If no strings are given,",
+" the command waits for any character at all to arrive. Strings are",
+" separated by spaces; use {braces} or \"doublequotes\" for grouping. If",
+" any of the strings is encountered within the timeout interval, the command",
+" succeeds and the \\v(minput) variable is set to the number of the string",
+" that was matched: 1, 2, 3, etc. If none of the strings arrives, the",
+" command times out, fails, and \\v(minput) is set to 0. In all other",
+" respects, MINPUT is like INPUT. See HELP INPUT for the available switches",
+" and other details of operation.",
+"" };
+#endif /* CK_MINPUT */
+
+#ifndef NOLOCAL
+static char *hmxxcon[] = {
+"Syntax: CONNECT (or C, or CQ) [ switches ]",
+" Connect to a remote computer via the serial communications device given in",
+#ifdef OS2
+" the most recent SET PORT command, or to the network host named in the most",
+#else
+" the most recent SET LINE command, or to the network host named in the most",
+#endif /* OS2 */
+" recent SET HOST command. Type the escape character followed by C to get",
+" back to the C-Kermit prompt, or followed by ? for a list of CONNECT-mode",
+#ifdef OS2
+" escape commands. You can also assign the \\Kexit verb to the key or",
+" key-combination of your choice; by default it is assigned to Alt-x.",
+#else
+" escape commands.",
+" ",
+"Include the /QUIETLY switch to suppress the informational message that",
+"tells you how to escape back, etc. CQ is a synonym for CONNECT /QUIETLY.",
+#endif /* OS2 */
+" ",
+"Other switches include:",
+#ifdef CK_TRIGGER
+" ",
+"/TRIGGER:string",
+" One or more strings to look for that will cause automatic return to",
+" command mode. To specify one string, just put it right after the",
+" colon, e.g. \"/TRIGGER:Goodbye\". If the string contains any spaces, you",
+" must enclose it in braces, e.g. \"/TRIGGER:{READY TO SEND...}\". To",
+" specify more than one trigger, use the following format:",
+" ",
+" /TRIGGER:{{string1}{string2}...{stringn}}",
+" ",
+" Upon return from CONNECT mode, the variable \\v(trigger) is set to the",
+" trigger string, if any, that was actually encountered. This value, like",
+" all other CONNECT switches applies only to the CONNECT command with which",
+" it is given, and overrides (temporarily) any global SET TERMINAL TRIGGER",
+" string that might be in effect.",
+#endif /* CK_TRIGGER */
+#ifdef OS2
+" ",
+"/IDLE-LIMIT:number",
+" The number of seconds of idle time, after which Kermit returns",
+" automatically to command mode; default 0 (no limit).",
+" ",
+"/IDLE-INTERVAL:number",
+" The number of seconds of idle time, after which Kermit automatically",
+" transmits the idle string.",
+" ",
+"/IDLE-STRING:string",
+" The string to transmit whenever the idle interval has passed.",
+" ",
+"/TIME-LIMIT:number",
+" The maximum number of seconds for which the CONNECT session may last.",
+" The default is 0 (no limit). If a nonzero number is given, Kermit returns",
+" automatically to command mode after this many seconds.",
+#endif /* OS2 */
+"" };
+#endif /* NOLOCAL */
+
+static char *hmxxmget[] = {
+"Syntax: MGET [ switches... ] remote-filespec [ remote-filespec ... ]",
+" ",
+"Just like GET (q.v.) except allows a list of remote file specifications,",
+"separated by spaces.",
+""
+};
+
+static char *hmxxget[] = {
+"Syntax: GET [ switches... ] remote-filespec [ as-name ]",
+" Tells the other Kermit, which must be in (or support autoswitching into)",
+" server mode, to send the named file or files. If the remote-filespec or",
+" the as-name contain spaces, they must be enclosed in braces. If as-name",
+" is the name of an existing local directory, incoming files are placed in",
+" that directory; if it is the name of directory that does not exist, Kermit",
+" tries to create it. Optional switches include:",
+" ",
+"/AS-NAME:text",
+" Specifies \"text\" as the name to store the incoming file under, or",
+" directory to store it in. You can also specify the as-name as the second",
+" filename on the GET command line.",
+" ",
+"/BINARY",
+" Performs this transfer in binary mode without affecting the global",
+" transfer mode.",
+" ",
+"/COMMAND",
+" Receives the file into the standard input of a command, rather than saving",
+" it on disk. The /AS-NAME or the second \"filename\" on the GET command",
+" line is interpreted as the name of a command.",
+" ",
+"/DELETE",
+" Asks the other Kermit to delete the file (or each file in the group)",
+" after it has been transferred successfully.",
+" ",
+"/EXCEPT:pattern",
+" Specifies that any files whose names match the pattern, which can be a",
+" regular filename, or may contain \"*\" and/or \"?\" metacharacters,",
+" are to be refused. To specify multiple patterns (up to 8), use outer",
+" braces around the group, and inner braces around each pattern:",
+" ",
+" /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+"/FILENAMES:{CONVERTED,LITERAL}",
+" Overrides the global SET FILE NAMES setting for this transfer only.",
+" ",
+"/FILTER:command",
+" Causes the incoming file to passed through the given command (standard",
+" input/output filter) before being written to disk.",
+" ",
+#ifdef VMS
+"/IMAGE",
+" Transfer in image mode.",
+" ",
+#endif /* VMS */
+#ifdef CK_LABELED
+"/LABELED",
+" VMS and OS/2 only: Specifies labeled transfer mode.",
+" ",
+#endif /* CK_LABELED */
+
+"/MOVE-TO:directory-name",
+" Specifies that each file that arrives should be moved to the specified",
+" directory after, and only if, it has been received successfully.",
+" ",
+"/PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}",
+" Overrides the global SET RECEIVE PATHNAMES setting for this transfer.",
+" ",
+"/PIPES:{ON,OFF}",
+" Overrides the TRANSFER PIPES setting for this command only. ON allows",
+" reception of files with names like \"!tar xf -\" to be automatically",
+" directed to a pipeline.",
+" ",
+"/QUIET",
+" 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:",
+" ",
+" NOW",
+" Stands for the current date and time.",
+" ",
+" TODAY",
+" Today's date, optionally followed by a time; 00:00:00 if no time given.",
+" ",
+" YESTERDAY",
+" Yesterday's date, optionally followed by a time (default 00:00:00).",
+" ",
+" TOMORROW",
+" Tomorrows's date, optionally followed by a time (default 00:00:00).",
+" ",
+" Timezone specifications are similar to those used in e-mail and HTTP",
+" headers, either a USA timezone name, e.g. EST, or a signed four-digit",
+" timezone offset, {+,-}hhmm, e.g., -0500; it is used to convert date-time,"
+,
+" a local time in that timezone, to GMT which is then converted to the",
+" local time at the host. If no timezone is given, the date-time is local."
+," To convert local time (or a time in a specified timezone) to UTC (GMT),",
+" use the function \futcdate().",
+" ",
+" Delta times are given as {+,-}[number date-units][hh[:mm[:ss]]]",
+" A date in the future/past relative to the date-time; date-units may be",
+" DAYS, WEEKS, MONTHS, YEARS: +3days, -7weeks, +3:00, +1month 8:00.",
+" ",
+"All the formats shown above are acceptable as arguments to date-time switches"
+,
+"such as /AFTER: or /BEFORE:, and to functions such as \\fcvtdate(),",
+"\\fdiffdate(), and \\futcdate(), that take date-time strings as arguments.",
+""
+};
+
+
+#ifndef NOXFER
+static char * hmxxsen[] = {
+"Syntax: SEND (or S) [ switches...] [ filespec [ as-name ] ]",
+" Sends the file or files specified by filespec. If the filespec is omitted",
+" the SEND-LIST is used (HELP ADD for more info). The filespec may contain",
+" wildcard characters. An 'as-name' may be given to specify the name(s)",
+" the files(s) are sent under; if the as-name is omitted, each file is",
+" sent under its own name. Also see HELP MSEND, HELP WILDCARD.",
+" Optional switches include:",
+" ",
+#ifndef NOSPL
+"/ARRAY:<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\
+ Resends the file or files, whose previous transfer was interrupted.\n\
+ Picks up from where previous transfer left off, IF the receiver kept the\n\
+ partially received file. Works only for binary-mode transfers.\n\
+ Requires file-transfer partner to support recovery. Synonym: REPUT.";
+
+static char *hmxxrget = "\
+Syntax: REGET filespec\n\n\
+ Ask a server to RESEND a file to C-Kermit.";
+
+static char *hmxxpsen = "\
+Syntax: PSEND filespec position [name]\n\n\
+ Just like SEND, except sends the file starting at the given byte position.";
+#endif /* NORESEND */
+
+#ifndef NOMSEND
+static char *hmxxmse[] = {
+"Syntax: MSEND [ switches... ] filespec [ filespec [ ... ] ]",
+" Sends the files specified by the filespecs. One or more filespecs may be",
+" listed, separated by spaces. Any or all filespecs may contain wildcards",
+" and they may be in different directories. Alternative names cannot be",
+" given. Switches include /BINARY /DELETE /MAIL /PROTOCOL /QUIET /RECOVER",
+" /TEXT /TYPE; see HELP SEND for descriptions.",
+""
+};
+#endif /* NOMSEND */
+
+static char *hmxxadd[] = {
+#ifndef NOMSEND
+"ADD SEND-LIST filespec [ <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 number",
+" ",
+"Type of block check to be used for error detection on file-transfer",
+"packets: 1, 2, 3, 4, or 5. This command must be given to the file",
+"sender prior to the transfer.",
+" ",
+"Type 1 is standard and supported by all Kermit protocol implementations,",
+" but it's only a 6-bit checksum, represented in a single printable ASCII",
+" character. It's fine for reliable connections (error-correcting modems,",
+" TCP/IP, etc) but type 3 is recommended for connections where errors can",
+" occur.",
+" ",
+"Type 2 is a 12-bit checksum represented in two printable characters.",
+" ",
+"Type 3 is a 16-bit cyclic redundancy check, the strongest error",
+" detection method supported by Kermit protocol, represented in three",
+" printable characters.",
+" ",
+"Type 4 (alias \"BLANK-FREE-2\") is a 12-bit checksum guaranteed to",
+" contain no blanks in its representation; this is needed for connections",
+" where trailing blanks are stripped from incoming lines of text.",
+" ",
+"Type 5 (alias \"FORCE-3\") means to force a Type 3 block check on",
+" every packet, including the first packet, which normally has a type 1",
+" block check. This is for use in critical applications on noisy",
+" connections. As with types 2, 3, and 4, if the Kermit file",
+" transfer partner does not support this type, the transfer fails",
+" immediately at the beginning of the transfer.",
+"" };
+
+static char * hmxydeb[] = {
+"Syntax: SET DEBUG { SESSION, ON, OFF, TIMESTAMP, MESSAGES }",
+" ",
+"SET DEBUG ON",
+#ifdef DEBUG
+" Opens a debug log file named debug.log in the current directory.",
+" Use LOG DEBUG if you want specify a different log file name or path.",
+#else
+" (Has no effect in this version of Kermit.)",
+#endif /* DEBUG */
+" ",
+"SET DEBUG OFF",
+" Stops debug logging and session debugging.",
+" ",
+"SET DEBUG SESSION",
+#ifndef NOLOCAL
+" Displays control and 8-bit characters symbolically during CONNECT mode.",
+" Equivalent to SET TERMINAL DEBUG ON.",
+#else
+" (Has no effect in this version of Kermit.)",
+#endif /* NOLOCAL */
+" ",
+"SET DEBUG TIMESTAMP { ON, OFF }",
+" Enables/Disables timestamps on debug log entries.",
+" ",
+"SET DEBUG MESSAGES { ON, OFF, STDERR } [C-Kermit 9.0]",
+" Enables/Disables messages printed by the DEBUG command.",
+" SET DEBUG OFF causes DEBUG messages not to be printed.",
+" SET DEBUG ON sends DEBUG messages to standard output (stdout);",
+" SET DEBUG STDERR sends DEBUG messages to standard error (stderr);",
+"" };
+
+#ifdef CK_SPEED
+static char *hmxyqctl[] = {
+"Syntax: SET CONTROL-CHARACTER { PREFIXED, UNPREFIXED } { <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 successfully 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.",
+" REJECT - Refuse and/or discard the incoming file (= DISCARD).",
+" RENAME - Give the incoming file a unique name.",
+" UPDATE - Accept the incoming file only if newer than the existing file.",
+" ",
+
+"SET FILE DESTINATION { DISK, PRINTER, SCREEN, NOWHERE }",
+" DISK (default): Store incoming files on disk.",
+" PRINTER: Send incoming files to SET PRINTER device.",
+" SCREEN: Display incoming files on screen (local mode only).",
+" NOWHERE: Do not put incoming files anywhere (use for calibration).",
+" ",
+"SET FILE DISPLAY option",
+" Selects the format of the file transfer display for local-mode file",
+" transfer. The choices are:",
+" ",
+" BRIEF A line per file, showing size, mode, status, and throughput.",
+" SERIAL One dot is printed for every K bytes transferred.",
+" CRT Numbers are continuously updated on a single screen line.",
+" This format can be used on any video display terminal.",
+#ifdef CK_CURSES
+" FULLSCREEN A fully formatted 24x80 screen showing lots of information.",
+" This requires a terminal or terminal emulator.",
+#endif /* CK_CURSES */
+" NONE No file transfer display at all.",
+" ",
+
+"SET FILE DOWNLOAD-DIRECTORY [ <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 */
+#ifdef UNIX
+" LINK string - The string is a symbolic link",
+#endif /* UNIX */
+" READABLE filename - Succeeds if the file is readable",
+" WRITEABLE filename - Succeeds if the file is writeable",
+#ifdef ZFCDAT
+" NEWER file1 file2 - The 1st file is newer than the 2nd one",
+#endif /* ZFCDAT */
+" OPEN { READ-FILE,SESSION-LOG,...} - The given file or log is open",
+#ifndef NOLOCAL
+" OPEN CONNECTION - A connection is open",
+#endif /* NOLOCAL */
+" KBHIT - A key has been pressed",
+" ",
+" 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 or, if specified",
+" it echoes as asterisks or other specified character.",
+" ",
+"Switches:",
+" /DEFAULT:text",
+" Text to supply if the user enters a blank response or the /TIMEOUT",
+" limit expired with no response.",
+" ",
+" /ECHO:char",
+" (ASKQ only) Character to be echoed each time the user presses a key",
+" corresponding to a printable character. This lets users see what they are",
+" doing when they are typing (e.g.) passwords, and makes editing easier.",
+" ",
+#ifdef OS2
+" /POPUP",
+" The prompt and response dialog takes place in a text-mode popup.",
+" 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 is 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",
+" Copies 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.",
+" ",
+" /PRESERVE",
+" Copy timestamp and permissions from source file to destination file.",
+" ",
+" /OVERWRITE:{ALWAYS,NEVER,NEWER,OLDER}",
+" When copying from one directory to another, this tells what to do when",
+" the destination file already exists: overwrite it always; never; only if",
+" the source file is newer; or only if the source file is older.",
+" ",
+" /APPEND",
+" Append the source file to the destination file. In this case the source",
+" file specification can contain wildcards, and all the matching source",
+" files are appended, one after the other in alphabetical order by name,",
+" to the destination file.",
+" ",
+" /SWAP-BYTES",
+" Swap bytes while copying (e.g. for converting between Big-Endian and",
+" Little-Endian binary data formats).",
+#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. Switches:",
+" ",
+" /LIST",
+" Print the filenames and status while renaming. Synonyms: /LOG, /VERBOSE",
+" ",
+" /NOLIST",
+" Rename silently (default). Synonyms: /NOLOG, /QUIET",
+" ",
+" /COLLISION:{FAIL,SKIP,OVERWRITE}",
+" Tells what to do if a file with the given (or derived) new name already",
+" exists: fail (and stop without renaming any files); skip this file",
+" without renaming it and go on to the next one, if any; or overwrite (the",
+" existing file). PROCEED is a synonym for SKIP.",
+" ",
+" /SIMULATE",
+" Show what the effects of the RENAME command would be without actually",
+" renaming any files.",
+" ",
+" When any of the following switches is given, name2 must either be the",
+" the name of a directory, or else omitted, and name1 is allowed to contain",
+" contain wildcards, allowing multiple files to be renamed at once. If name2",
+" is given, then all files matching name1 are moved to the name2 directory",
+" after being renamed.",
+" ",
+" /LOWER:{ALL,UPPER}",
+" Converts letters in the filename to lowercase. ALL means to convert",
+" all matching filenames, UPPER means to convert only those filenames",
+" that contain no lowercase letters. The switch argument can be omitted,",
+" in which case ALL filenames are converted.",
+" ",
+" /UPPER:{ALL,LOWER}",
+" Converts letters in the filename to uppercase. ALL means to convert",
+" all matching filenames, LOWER means to convert only those filenames",
+" that contain no uppercase letters. As with /LOWER, ALL is the default",
+" switch argument.",
+" ",
+" /FIXSPACES:s",
+" Replaces all spaces in each matching filename by the string s, which may",
+" be empty, a single character, or a string of characters. The default",
+" replacement (if no argument is given) is underscore (_).",
+" ",
+" /REPLACE:{{string1}{string2}{options}}",
+" Replaces all or selected occurrences of string1 with string2 in the",
+" matching filenames. The braces are part of the command. The options",
+" string can contain the following characters:",
+" A: String matching is case-sensitive.",
+" a: String matching is case-insensitive.",
+" ^: String matching is anchored to the beginning of the filename.",
+" $: String matching is anchored to the end of the filename.",
+" 1: Only the first occurrence of the string (if any) will be changed.",
+" 2: Only the second occurrence, and so on for all digits up to 9.",
+" -: (before a digit) Occurrences are counted from the right.",
+" ~: (before occurrence) All occurences BUT the one given are changed.",
+" ",
+" /CONVERT:cset1:cset1",
+" Converts each matching filename from character-set 1 to character-set 2.",
+" Character sets are the same as for SET FILE CHARACTER-SET.",
+" ",
+" Global values for /LIST and COLLISION can be set with SET RENAME and",
+" displayed with SHOW RENAME.",
+""
+};
+#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 specified, 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, and /FIND:pattern.",
+" 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. If a /FIND: switch is included, Kermit seeks to the",
+" specified spot (e.g. 0 for the beginning) and then begins searching line",
+" by line for the first line that matches the given pattern. To start",
+" searching from the current file position specify a line number of +0.",
+" To start searching from the line after the current one, use +1 (etc).",
+" Synonym: FSEEK.",
+""
+};
+
+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, %s,",versio, ck_cryear);
+#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 */
+
+case XXMSG:
+ return(hmsg("Syntax: MESSAGE text-to-print-if-debugging\n\
+ Prints the given text to stdout if SET DEBUG MESSAGE is ON; prints it\n\
+ to stderr if SET DEBUG MESSAGE is STDERR; doesn't print it at all if SET\n\
+ DEBUG MESSAGE is OFF. Synonym: MSG."));
+
+#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 XXTOUC: /* TOUCH */
+ return(hmsga(hmxxtouc));
+
+case XXWDIR: /* WDIRECTORY */
+ return(hmsg(" WDIRECTORY is shorthand for DIRECTORY /SORT:DATE /REVERSE;\n\
+ it produces a listing in reverse chronological order. See the DIRECTORY\n\
+ command for further information."));
+
+case XXHDIR: /* HDIRECTORY */
+ return(hmsg(" HDIRECTORY is shorthand for DIRECTORY /SORT:SIZE /REVERSE;\n\
+ it produces a listing showing the biggest files first. See the DIRECTORY\n\
+ command for further information."));
+
+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, %s,\n\
+Trustees of Columbia University in the City of New York.\n\n",
+ versio,
+ ck_cryear
+ );
+ return(dotype(helpfile,xaskmore,3,0,NULL,0,NULL,0,0,NULL,0));
+ } else {
+ printf("\n%s, Copyright (C) 1985, %s,",versio,ck_cryear);
+ return(hmsga(tophlp));
+ }
+
+case XXINT:
+#ifdef OS2
+ return(hmsg("The INTRO command gives a brief introduction to Kermit 95."));
+#else
+ return(hmsg("The INTRO command gives a brief introduction to C-Kermit."));
+#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."));
+
+#ifdef NEWFTP
+case XXASC:
+ return(hmsg(
+"Inhibits automatic transfer-mode switching and forces TEXT (ASCII) transfer\n\
+mode for all files in both Kermit and FTP protocols."));
+case XXBIN:
+ return(hmsg(
+"Inhibits automatic transfer-mode switching and forces BINARY transfer mode\n\
+for all files in both Kermit and FTP protocols."));
+#else
+case XXASC:
+ return(hmsg(
+"Inhibits automatic transfer-mode switching and forces TEXT (ASCII) transfer\n\
+mode for all files."));
+case XXBIN:
+ return(hmsg(
+"Inhibits automatic transfer-mode switching and forces BINARY transfer mode\n\
+for all files."));
+#endif /* NEWFTP */
+
+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));
+
+#ifdef LOCUS
+case XXLOCU:
+ return(hmsga(hmxylocus));
+#endif /* LOCUS */
+
+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 XXRMSG:
+ return(hmsg(" RMESSAGE and RMSG are short forms of REMOTE MESSAGE."));
+ 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 XXREDO:
+ return(hmsg(" Syntax: REDO xxx (or) ^xxx\n\
+ Re-executes the most recent command starting with xxx."));
+
+#ifdef UNIX
+#ifndef NOPUTENV
+ case XXPUTE:
+ return(hmsga(hmxxputenv));
+#endif /* NOPUTENV */
+#endif /* UNIX */
+
+ 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 NOFRILLS
+static char * supporttext[] = {
+
+"Live technical support for Kermit software is no longer available",
+"from Columbia University, as it was from mid-1981 until mid-2011 when",
+
+#ifdef OS2
+
+"the Kermit Project was cancelled. Beginning with version 3.0, Kermit 95",
+
+#else
+
+"the Kermit Project was cancelled. Beginning with version 9.0, C-Kermit",
+
+#endif /* OS2 */
+
+"is Open Source software. The Kermit website is supposed remain open",
+"indefinitely at:",
+" ",
+" http://kermit.columbia.edu/",
+" ",
+
+#ifdef OS2
+
+"The Kermit 95 page is here:",
+" ",
+" http://kermit.columbia.edu/k95.html",
+" ",
+"The Kermit 95 manual is here:",
+" ",
+" http://kermit.columbia.edu/k95manual/",
+" ",
+"The Kermit 95 Frequently Asked Questions page is here:",
+" ",
+" http://kermit.columbia.edu/k95faq.html",
+" ",
+"and many other resources are listed on the Kermit 95 home page.",
+" ",
+
+#else
+
+"The C-Kermit home page is here:",
+" ",
+" http://kermit.columbia.edu/ckermit.html",
+" ",
+"The documentation for C-Kermit is listed here:",
+" ",
+" http://kermit.columbia.edu/ckermit.html#doc",
+" ",
+"The C-Kermit Frequently Asked Questions page is here:",
+" ",
+" http://kermit.columbia.edu/ckfaq.html",
+" ",
+"and many other resources are listed on the C-Kermit home page.",
+" ",
+
+#endif /* OS2 */
+
+"Time will tell what sort of development and support structures arise",
+"in the Open Source community.",
+""
+};
+
+/* Do the BUG command */
+int
+dobug() {
+ return(hmsga(supporttext));
+}
+#endif /* NOFRILLS */
+
+#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 */
+
+"SET COMMAND ERROR { 0,1,2,3 }",
+" Sets the verbosity level of command error messages; the higher the number,",
+" the more verbose the message. The default is 1. Higher values are",
+" useful only for debugging scripts.",
+" ",
+
+#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 */
+" ",
+#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 }",
+" 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 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
+" ",
+"SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }",
+" For TELNET connections only: 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.",
+" ",
+
+#endif /* OS2 */
+
+"SET TERMINAL LF-DISPLAY { CRLF, NORMAL }",
+" Specifies how incoming linefeed characters are to be displayed",
+" on your screen.",
+" ",
+
+#ifdef OS2
+
+#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, ON, OFF }",
+" 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 an 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.",
+" ",
+" The ON and OFF choices allow you to disable and renable wildcard",
+" processing independent of the KERMIT / SHELL choice. Disabling wildcards",
+" allows you to process an array or list of filenames without having to",
+" consider whether the names might contain literal wildcard characters.",
+" WARNING: SET WILD OFF also disables internal filename pattern-matching,",
+" used (for example) in creating backup files.",
+"" };
+#else
+static char *hxywild[] = {
+"Syntax: SET WILDCARD-EXPANSION { ON, OFF }",
+" ON (the default) means that filenames given to Kermit commands such as",
+" SEND and DIRECTORY are automatically expanded into lists of filenames if",
+" they contain special 'wildcard characters' such as '*'. You can reference",
+" files whose names contains such characters literally by preceding each",
+" such character with a backslash '\\'. When dealing programmatically with",
+" a file list, however, you should SET WILDCARD-EXPANSION OFF to force",
+" treat each name in the list as a literal name. See HELP WILDCARDS for",
+" details about wildcard syntax.",
+"" };
+#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.",
+" SET SEND TIMEOUT -1 FIXED means no timeouts.",
+#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) parameter 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 */
+""};
+
+#ifdef OS2
+static char *hmxymsk[] = {
+"SET MSKERMIT FILE-RENAMING { ON, OFF }",
+" ON enables the use of MS-DOS Kermit file renaming conventions instead of",
+" C-Kermit conventions. File renaming occurs during file transfers when",
+" there is a file name collision and either BACKUP or RENAME collision",
+" options are active. C-Kermit conventions preserve the original file name",
+" while appending .~num~ to the end. MS-DOS Kermit conventions restrict",
+" filenames to 8.3 notation and preserve the extension. Unique numeric",
+" values overwrite the right most portion of the file name's left hand side.",
+" ",
+"SET MSKERMIT KEYCODES { ON, OFF }",
+" ON enables the use of MS-DOS Kermit compatible keycodes to provide script",
+" portability.",
+""};
+#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 XY_REN:
+ return(hmsg("SET RENAME LIST { ON, OFF }\n\
+ Tells whether the RENAME command should list its results by default.\n\n\
+SET RENAME COLLISION { FAIL, PROCEED, OVERWRITE }\n\
+ Establishes the default action when renaming a file would destroy an\n\
+ existing file. See HELP RENAME."));
+
+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."));
+
+case XYMSK:
+ return(hmsga(hmxymsk));
+#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:\n\
+ SET SESSION-LOG { BINARY, DEBUG, NULL-PADDED, 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));
+
+#ifndef NOSEXP
+ case XYSEXP:
+ return(hmsga(hmxysexp));
+#endif /* NOSEXP */
+
+#ifndef NOSPL
+ case XYVAREV:
+ return(hmsg("Syntax: SET VARIABLE-EVALUATION { RECURSIVE, SIMPLE }\n\
+ Tells Kermit weather to evaluate \\%x and \\&x[] variables recursively\n\
+ (which is the default for historical reasons) or by simple string\n\
+ replacement, which lets you use these variables safely to store strings\n\
+ (such as Windows pathnames) that might contain backslashes."));
+#endif /* NOSPL */
+
+default:
+ printf("Not available - \"%s\"\n",cmdbuf);
+ return(0);
+ }
+}
+
+#ifndef NOSPL
+static char * hfsplit[] = {
+"Function \\fsplit(s1,&a,s2,s3,n2,n3) - Assigns string words to an array.",
+" s1 = source string.",
+" &a = array designator.",
+" s2 = optional break set.",
+" s3 = optional include set (or ALL, CSV, or TSV).",
+" n2 = optional grouping mask.",
+" n3 = optional separator flag:",
+" 0 = collapse adjacent separators;",
+" 1 = don't collapse adjacent separators.",
+" ",
+" \\fsplit() breaks the string s1 into \"words\" as indicated by the other",
+" parameters, assigning them to given array, if any. If the specified",
+" already exists, it is recycled; if no array is specified, the count is",
+" returned but no array is created. All arguments are optional",
+" (\\fsplit() with no arguments returns 0).",
+" ",
+" The BREAK SET is the set of all characters that separate words. The",
+" default break set is all characters except ASCII letters and digits.",
+" ASCII (C0) control characters are treated as break characters by default,",
+" as are spacing and punctuation characters, brackets, and so on, and",
+" all 8-bit characters.",
+" ",
+" The INCLUDE SET is the set of characters that are to be treated as ",
+" parts of words even though they normally would be separators. The",
+" default include set is empty. Three special symbolic include sets are",
+" also allowed:",
+" ",
+" ALL (meaning include all bytes that are not in the break set)",
+" CSV (special treatment for Comma-Separated-Value records)",
+" TSV (special treatment for Tab-Separated-Value records)",
+" ",
+" For operating on 8-bit character sets, the include set should be ALL.",
+" ",
+" If the grouping mask is given and is nonzero, words can be grouped by",
+" quotes or brackets selected by the sum of the following:",
+" ",
+" 1 = doublequotes: \"a b c\"",
+" 2 = braces: {a b c}",
+" 4 = apostrophes: 'a b c'",
+" 8 = parentheses: (a b c)",
+" 16 = square brackets: [a b c]",
+" 32 = angle brackets: <a b c>",
+" ",
+" Nesting is possible with {}()[]<> but not with quotes or apostrophes.",
+" ",
+"Returns integer:",
+" Number of words in source string.",
+" ",
+"Also see:",
+" HELP FUNCTION WORD",
+""
+};
+
+/* D O H F U N C -- Give help for a function */
+
+int
+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,n2)\n\
+ s1 = string to look for.\n\
+ s2 = string to look in.\n\
+ n1 = optional 1-based starting position, default = 1.\n\
+ n2 = optional desired occurrence number, default = 1.\n",
+ xx == FN_RIX ? "r" : ""
+ );
+ printf("Returns integer:\n\
+ 1-based position of %smost occurrence of s1 in s2, ignoring the %smost\n\
+ (n1-1) characters in s2; returns 0 if s1 not found in s2.\n",
+ xx == FN_IND ? "left" : "right",
+ xx == FN_IND ? "left" : "right"
+ );
+ break;
+ case FN_COUNT: /* Count occurrences of s1 in s2 */
+ printf("\\fcount(s1,s2,n1)\n\
+ s1 = string or character to look for.\n\
+ s2 = string to look in.\n\
+ n1 = optional 1-based starting position, default = 1.\n");
+ printf("Returns integer:\n\
+ Number of occurrences of s1 in s2, 0 or more.\n");
+ break;
+
+ case FN_SEARCH: /* Search for pattern */
+ case FN_RSEARCH: /* Search for pattern from right */
+ printf("\\f%ssearch(s1,s2,n1,n2)\n\
+ s1 = pattern to look for.\n\
+ s2 = string to look in.\n\
+ n1 = optional 1-based offset, default = 1.\n\
+ n2 = optional desired occurrence of match, default = 1.\n",
+ xx == FN_RSEARCH ? "r" : ""
+ );
+ printf("Returns integer:\n\
+ 1-based position of %smost match for s1 in s2, ignoring the %smost\n\
+ (n1-1) characters in s2; returns 0 if no match.\n",
+ xx == FN_SEARCH ? "left" : "right",
+ xx == FN_SEARCH ? "left" : "right"
+ );
+ printf(" 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[,n1]])\n\
+ s1 = string to look in.\n\
+ c1 = character to look for, default = \".\".\n\
+ n1 = occurrence of c1, default = 1.\n");
+ printf("Returns string:\n\
+ The part of s1 after the n1th leftmost occurrence of character c1.\n"
+ );
+ break;
+
+ case FN_LOPX: /* Strip from right */
+ printf("\\flopx(s1,c1)\n\
+ s1 = string to look in.\n\
+ c1 = character to look for, default = \".\".\n\
+ n1 = occurrence of c1, default = 1.\n");
+ printf("Returns string:\n\
+ The part of s1 after the n1th rightmost occurrence of character c1.\n"
+ );
+ break;
+
+ case FN_STN: /* Strip n chars */
+ printf("\\fstripn(s1,n1)\n\
+ s1 = string to look in.\n\
+ n1 = integer, default = 0.\n");
+ printf("Returns string:\n\
+ s1 with n1 characters removed from the right.\n"
+ );
+ break;
+
+ case FN_STB: /* Strip enclosing brackets */
+ printf("\\fstripb(s1[,c1[,c2]])\n\
+ s1 = original string.\n\
+ c1 = optional first character\n");
+ printf("\
+ c2 = optional final character.\n");
+ printf("Returns string:\n\
+ s1 with the indicated enclosing characters removed. If c1 and c2 not\n\
+ specified, any matching brackets, braces, parentheses, or quotes are\n");
+ printf("\
+ assumed. If c1 is given but not c2, the appropriate c2 is assumed.\n\
+ if both c1 and c2 are given, they are used as-is.\n"
+ );
+ printf(
+"Alternative format:\n\
+ Include a grouping mask number in place of c1 and omit c2 to specify more\n\
+ than one possibility at once; see \\fword() for details.\n"
+ );
+ break;
+
+#ifdef OS2
+ case FN_SCRN_CX: /* Screen Cursor X Pos */
+ printf("\\fscrncurx()\n");
+ printf("Returns integer:\n\
+ The 0-based X coordinate (column) of the Terminal screen cursor.\n");
+ break;
+ case FN_SCRN_CY: /* Screen Cursor Y Pos */
+ printf("\\fscrncury()\n");
+ printf("Returns integer:\n\
+ The 0-based Y coordinate (row) of the Terminal screen cursor.\n");
+ break;
+ case FN_SCRN_STR: /* Screen String */
+ printf("\\fscrnstr(ny,nx,n1)\n\
+ ny = integer.\n\
+ nx = integer.\n\
+ n1 = integer.\n");
+ printf("Returns string:\n\
+ The string at Terminal-screen coordinates (nx,ny), length n1,\n\
+ blanks included. Coordinates start at 0. Default values are\n\
+ 0 for ny and nx, and line width for n1.\n");
+ break;
+#endif /* OS2 */
+
+ case FN_2HEX: /* Num to hex */
+ printf("\\fn2hex(n1) - Number to hex\n n1 = integer.\n");
+ printf("Returns string:\n The hexadecimal representation of n1.\n");
+ break;
+
+ case FN_2OCT: /* Num to hex */
+ printf("\\fn2octal(n1) - Number to octal\n n1 = integer.\n");
+ printf("Returns string:\n The octal representation of n1.\n");
+ break;
+
+#ifdef RECURSIVE
+ case FN_DIR: /* Recursive directory count */
+ printf("\\fdirectories(f1) - Directory list.\n\
+ f1 = directory specification, possibly containing wildcards.\n\
+ &a = optional name of array to assign directory list to.\n");
+ printf("Returns integer:\n\
+ The number of directories that match f1; use with \\fnextfile().\n");
+ break;
+
+ case FN_RFIL: /* Recursive file count */
+ printf("\\frfiles(f1[,&a]) - Recursive file list.\n\
+ f1 = file specification, possibly containing wildcards.\n\
+ &a = optional name of array to assign file list to.\n");
+ printf("Returns integer:\n\
+ The number of files whose names match f1 in the current or given\n\
+ directory tree; use with \\fnextfile().\n");
+ break;
+
+ case FN_RDIR: /* Recursive directory count */
+ printf("\\frdirectories(f1) - Recursive directory list.\n\
+ f1 = directory specification, possibly containing wildcards.\n\
+ &a = optional name of array to assign directory list to.\n");
+ printf("Returns integer:\n\
+ The number of directories that match f1 in the current or given directory\n\
+ tree. Use with \\fnextfile().\n");
+ break;
+#endif /* RECURSIVE */
+
+ case FN_DNAM: /* Directory part of a filename */
+ printf("\\fdirname(f) - Directory part of a filename.\n\
+ f = a file specification.\n");
+ printf("Returns directory name:\n\
+ The full name of the directory that the file is in, or if the file is a\n\
+ directory, its full name.\n");
+ break;
+
+#ifndef NORANDOM
+ case FN_RAND: /* Random number */
+ printf("\\frandom(n) - Random number.\n\
+ n = a positive integer.\n");
+ printf("Returns integer:\n\
+ A random number between 0 and n-1.\n");
+ break;
+#endif /* NORANDOM */
+
+ case FN_SPLIT: /* Split */
+#ifdef COMMENT
+ printf("\\fsplit(s1,&a,s2,s3,n2,n3) - \
+Assign string words to an array.\n\
+ s1 = source string\n &a = array designator\n s2 = optional break set.\n");
+ printf(" s3 = optional include set.\n");
+ printf(" n2 = optional grouping mask.\n");
+ printf(" n3 = optional separator flag.\n");
+ printf(" s2, s3, n2, n3 are as in \\fword().\n");
+ printf(
+" All arguments are optional; if \\&a[] already exists, it is recycled;\n\
+ if array not specified, the count is returned but no array is created.\n");
+ printf("Returns integer:\n\
+ Number of words in source string.\n");
+#else
+ hmsga(hfsplit);
+#endif /* COMMENT */
+ break;
+
+ case FN_DTIM: /* CVTDATE */
+ printf("\\fcvtdate([date-time][,n1]) - Date/time conversion.\n");
+ printf(" Converts date and/or time to standard format.\n");
+ printf(" If no date/time given, returns current date/time.\n");
+ printf(" [date-time], if given, is free-format date and/or time.\n");
+ printf(" HELP DATE for info about date-time formats.\n");
+ printf("Returns string:\n\
+ Standard-format date and time: yyyymmdd hh:mm:ss (numeric)\n");
+ printf(" If n1 is given:\n\
+ n1 = 1: yyyy-mmm-dd hh:mm:ss (mmm = English 3-letter month abbreviation)\n\
+ n1 = 2: dd-mmm-yyyy hh:mm:ss (ditto)\n\
+ n1 = 3: yyyymmddhhmmss (all numeric)\n\
+ n1 = 4: Day Mon dd hh:mm:ss yyyy (asctime)\n\
+ Other: yyyymmdd hh:mm:dd");
+ 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_TOB64:
+ printf("\\b64encode(s)\n\
+ s = string containing no NUL bytes\n\
+ Returns Base-64 encoding of string.\n");
+ break;
+
+ case FN_FMB64:
+ printf("\\b64decode(s)\n\
+ s = string in Base-64 notation\n\
+ Returns the decoded string or an error code if s not valid.\n");
+ break;
+
+ case FN_RADIX:
+ printf("\\fradix(s,n1,n2)\n\
+ s = number in radix n1\n\
+ Returns the number's representation in radix n2.\n");
+ break;
+
+ case FN_JOIN:
+ printf("\\fjoin(&a[,s[,n1[,n2]]])\n\
+ &a = array designator, can include range specifier.\n\
+ s = optional separator.\n");
+ printf("\
+ n1 = nonzero to put grouping around elements that contain spaces;\n\
+ see \\fword() grouping mask for values of n.\n");
+ printf("\
+ n2 = 0 or omitted to put spaces between elements; nonzero to omit them.\n");
+ printf("\
+ Returns the (selected) elements of the array joined to together,\n\
+ separated by the separator.\n");
+ printf("\n\
+ If s is CSV (literally), that means the array is to be transformed into a\n\
+ comma-separated list. No other arguments are needed. If s is TSV, then\n\
+ a tab-separated list is created.\n");
+ break;
+
+ case FN_SUBST:
+ printf("\\fsubstitute(s1,s2,s3)\n\
+ s1 = Source string.\n\
+ s2 = List of characters to be translated.\n\
+ s3 = List of characters to translate them to.\n");
+ printf(
+" Returns: s1, with each character that is in s2 replaced by the\n\
+ corresponding character in s3. s2 and s3 can contain ASCII ranges,\n\
+ like [a-z]. Any characters in s2 that don't have corresponding\n\
+ characters in s3 (after range expansion) are removed from the result.\n\
+ This function works only with single-byte character-sets\n");
+ break;
+
+#ifndef NOSEXP
+ case FN_SEXP:
+ printf("\\fsexpression(s1)\n\
+ s1 = S-Expression.\n");
+ printf(" Returns: The result of evaluating s1.\n");
+ break;
+
+#endif /* NOSEXP */
+
+ case FN_CMDSTK:
+ printf("\\fcmdstack(n1,n2)\n\
+ n1 = Command-stack level, 0 to \\v(cmdlevel), default \\v(cmdlevel).\n\
+ n2 = Function code, 0 or 1.\n");
+ printf("Returns:\n");
+ printf(" n2 = 0: name of object at stack level n1\n\
+ n2 = 1: type of object at stack level n1:\n\
+ 0 = interactive prompt\n\
+ 1 = command file\n\
+ 2 = macro\n"
+ );
+ break;
+
+#ifdef CKFLOAT
+ case FN_DIFDATE:
+ printf("\\fdiffdates(d1,d2)\n\
+ d1 = free-format date and/or time (default = NOW).\n\
+ d2 = ditto.\n");
+ printf("Returns:\n");
+ printf(" Difference expressed as delta time:\n");
+ printf(" Negative if d2 is later than d1, otherwise positive.\n");
+ break;
+#endif /* CKFLOAT */
+
+ case FN_CMPDATE:
+ printf("\\fcmpdates(d1,d2)\n\
+ d1 = free-format date and/or time (default = NOW).\n\
+ d2 = ditto.\n");
+ printf("Returns:\n");
+ printf(" 0 if d1 is equal to d2;\n\
+ 1 if d1 is later than d2;\n\
+ -1 if d1 is earlier than d2.\n");
+ break;
+
+ case FN_TOGMT:
+ printf("\\futcdate(d1)\n\
+ d1 = free-format date and/or time (default = NOW).\n");
+ printf("Returns:\n");
+ printf(" Date-time converted to UTC (GMT) yyyymmdd hh:mm:ss.\n");
+ break;
+
+#ifdef TCPSOCKET
+ case FN_HSTADD:
+ printf("\\faddr2name(s)\n\
+ s = numeric IP address.\n");
+ printf("Returns:\n");
+ printf(" Corresponding IP hostname if found, otherwise null.\n");
+ break;
+ case FN_HSTNAM:
+ printf("\\fname2addr(s)\n\
+ s = IP host name.\n");
+ printf("Returns:\n");
+ printf(" Corresponding numeric IP address if found, else null.\n");
+ break;
+#endif /* TCPSOCKET */
+
+ case FN_DELSEC:
+ printf("\\fdelta2secs(dt)\n\
+ dt = Delta time, e.g. +3d14:27:52.\n");
+ printf("Returns:\n");
+ printf(" The corresponding number of seconds.\n");
+ break;
+
+ case FN_PC_DU:
+ printf("\\fdos2unixpath(p)\n\
+ p = string, DOS pathname.\n");
+ printf("Returns:\n");
+ printf(" The argument converted to a Unix pathname.\n");
+ break;
+
+ case FN_PC_UD:
+ printf("\\funix2dospath(p)\n\
+ p = string, Unix pathname.\n");
+ printf("Returns:\n");
+ printf(" The argument converted to a DOS pathname.\n");
+ break;
+
+#ifdef FN_ERRMSG
+ case FN_ERRMSG:
+ printf("\\ferrstring(n)\n\
+ n = platform-dependent numeric error code.\n");
+ printf("Returns:\n");
+ printf(" The corresponding error string.\n");
+ break;
+#endif /* FN_ERRMSG */
+
+ case FN_KWVAL:
+ printf("\\fkeywordvalue(s1[,s2])\n\
+ s1 = string of the form \"name=value\"\n\
+ s2 = one more separator characters (default separator is \"=\")\n");
+ printf(" Assigns the value, if any, to the named macro and sets\n");
+ printf(" the \\v(lastkeywordvalue) to the macro name.\n");
+ printf(" If no value is given, the macro is undefined.\n");
+ printf("Returns:\n");
+ printf(" -1 on error\n");
+ printf(" 0 if no keyword or value were found\n");
+ printf(" 1 if a keyword was found but no value\n");
+ printf(" 2 if a keyword and a value were found\n");
+ printf("Synonym: \\kwvalue(s1[,s2])\n");
+ break;
+
+#ifdef COMMENT
+ case FN_SLEEP:
+ printf("\\fsleep(n)\n\
+ n = number of seconds\n");
+ printf(" Pauses for the given number of seconds.\n");
+ printf("Returns: the empty string.\n");
+ break;
+
+ case FN_MSLEEP:
+ printf("\\fmsleep(n)\n\
+ n = number of milliseconds\n");
+ printf(" Pauses for the given number of milliseconds.\n");
+ printf("Returns: the empty string.\n");
+ break;
+#endif /* COMMENT */
+
+#ifdef NT
+ case FN_SNAME:
+ printf("\\fshortpathname(s)\n\
+ s = file or directory name string\n");
+ printf(" Returns the short path form of the given input.\n");
+ break;
+
+ case FN_LNAME:
+ printf("\\flongpathname(s)\n\
+ s = file or directory name string\n");
+ printf(" Returns the long path form of the given input.\n");
+ break;
+#else
+ case FN_SNAME:
+ printf("\\fshortpathname(s)\n\
+ Synonym for \fpathname()\n");
+ break;
+
+ case FN_LNAME:
+ printf("\\flongpathname(s)\n\
+ Synonym for \fpathname()\n");
+ break;
+#endif /* NT */
+
+ case FN_EMAIL:
+ printf("\\femailaddress(s)\n\
+ s = From: or Sender: header from an RFC2822-format email message\n");
+ printf(" Extracts and returns the email address.\n");
+ break;
+
+ case FN_PICTURE:
+ printf("\\fpictureinfo(s[,&a])\n\
+ s = File specification of a JPG or GIF picture file.\n\
+ &a = Optional array name.\n\n");
+ printf("Returns integer:\n\
+ 0 if file not found or not recognized;\n\
+ 1 if orientation is landscape;\n\
+ 2 if orientation is portrait.\n\n");
+ printf(" If an array name is included, element 1 is filled \
+in with the image width\n\
+ in pixels, and element 2 the image height.\n");
+ break;
+
+ case FN_PID:
+ printf("\\fgetpidinfo(n1)\n\
+ n1 = Numeric process ID\n");
+ printf("Returns integer:\n\
+ -1 on failure to get information;\n\
+ 1 if n1 is the ID of an active process;\n\
+ 0 if the process does not exist.\n");
+ break;
+
+ case FN_FUNC:
+ printf("\\ffunction(s1)\n\
+ s1 = name of function.\n");
+ printf("Returns integer:\n\
+ 1 if s1 is the name of an available built-in function;\n\
+ 0 otherwise.\n");
+ break;
+
+ case FN_RECURSE:
+ printf("\\frecurse(s1)\n\
+ s1 = name of \\&x or \\&x[] type variable\n");
+ printf("Returns the result of evaluating the variable recursively.\n");
+ break;
+
+ case FN_SQUEEZE:
+ printf("\\fsqueeze(s)\n\
+ s = string\n\
+ Returns string with leading and trailing whitespace removed, Tabs\n\
+ converted to Spaces, and multiple spaces converted to single spaces.\n");
+ break;
+
+#ifndef NOCSETS
+ case FN_XLATE:
+ printf("\\fcvtcset(s,cset1,cset2)\n\
+ s = string\n\
+ Returns string converted from character set cset1 to cset2, where cset1\n\
+ and cset2 are names of File Character-Sets \
+('set file char ?' for a list).\n");
+ break;
+#endif /* NOCSETS */
+
+ case FN_UNPCT:
+ printf("\\fdecodehex(s1[,s2])\n\
+ s1, s2 = strings\n\
+ Decodes a string s1 that contains prefixed hex bytes. s2 is the prefix;\n\
+ the default is %%%%. You can specify any other prefix one or two bytes\n\
+ long. If the prefix contains letters (such as 0x), case is ingored.\n\
+ Returns string s1 with hex escapes replaced by the bytes they \
+represent.\n");
+ break;
+
+ case FN_STRINGT:
+ printf("\\fstringtype(s)\n\
+ s = string\n\
+ Returns a string representing the type of its string argument s1:\n\
+ 7BIT, 8BIT, UTF8, TEXT, or BINARY. TEXT means some kind of text\n\
+ other than 7BIT, 8BIT, or UTF8 (this probably will never appear).\n");
+ break;
+
+ case FN_STRCMP:
+ printf("\\fstrcmp(s1,s2[,case[,start[,length]]])\n\
+ s1, s2 = strings\n\
+ case, start, length = numbers or arithmetic expressions.\n\
+ case = 0 [default] means to do a case-independent comparison;\n\
+ nonzero case requests a case-sensitive comparison.\n\
+ The optional start and length arguments apply to both s1 and s2\n\
+ and allow specification of substrings if it is not desired to compare\n\
+ the whole strings. Results for non-ASCII strings are implentation-\n\
+ and locale-dependent.\n\
+ Returns a number:\n\
+ -1: s1 is lexically less than s2;\n\
+ 0: s1 and s2 are lexically equal;\n\
+ 2: s1 is lexically greater than s2.\n");
+ break;
+
+ default:
+ printf("Sorry, help not available for \"%s\"\n",cmdbuf);
+ }
+ printf("\n");
+ return(0);
+}
+#endif /* NOSPL */
+
+#ifdef OS2
+#ifndef NOKVERBS
+
+/* D O H K V E R B -- Give help for a Kverb */
+
+int
+dohkverb(xx) int xx; {
+ int x,i,found,button,event;
+
+ if (xx == -3) {
+ printf("\n Type SHOW KVERBS to see a list of available Kverbs.\n"
+ );
+ printf(
+" Type HELP KVERB <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 XZMSG:
+ return(hmsg("Syntax: REMOTE MESSAGE text\n\
+ Sends a short text message to the remote Kermit server."));
+
+case XZPRI:
+ return(hmsg("Syntax: REMOTE PRINT filespec [ options ]\n\
+ Sends the specified file(s) to the remote Kermit and ask it to have the\n\
+ file printed on the remote system's printer, using any specified options.\n\
+ Synonym: RPRINT."));
+#endif /* NOFRILLS */
+
+case XZREN:
+#ifdef NEWFTP
+ return(hmsg("Syntax: REMOTE RENAME filespec newname\n\
+ Asks the Kermit or FTP server to rename the file. Synonym: RRENAME."));
+#else
+ return(hmsg("Syntax: REMOTE RENAME filespec newname\n\
+ Asks the Kermit server to rename the file. Synonym: RRENAME."));
+#endif /* NEWFTP */
+
+case XZSET:
+ return(hmsga(hrset));
+
+case XZSPA:
+ return(hmsg("Syntax: REMOTE SPACE [ name ]\n\
+ Asks the Kermit server to tell you about its disk space on the current\n\
+ disk or directory, or in the one that you name. Synonym: RSPACE."));
+
+#ifndef NOFRILLS
+case XZTYP:
+#ifdef NEWFTP
+ return(hmsg("Syntax: REMOTE TYPE file\n\
+ Asks the Kermit or FTP server to send the named file to your screen.\n\
+ Synonym: RTYPE."));
+#else
+ return(hmsg("Syntax: REMOTE TYPE file\n\
+ Asks the Kermit server to send the named file(s) to your screen.\n\
+ Synonym: RTYPE."));
+#endif /* NEWFTP */
+
+
+case XZWHO:
+ return(hmsg("Syntax: REMOTE WHO [ name ]\n\
+ Asks the Kermit server to list who's logged in, or to give information\n\
+ about the named user. Synonym: RWHO."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XZQUE:
+ return(hmsg(
+"Syntax: [ REMOTE ] QUERY { KERMIT, SYSTEM, USER } variable-name\n\
+ Asks the Kermit server to send the value of the named variable of the\n\
+ given type, and make it available in the \\v(query) variable. When the\n\
+ type is KERMIT functions may also be specified as if they were variables."));
+
+case XZASG:
+ return(hmsg(
+"Syntax: REMOTE ASSIGN variable-name [ value ]\n\
+ Assigns the given value to the named global variable on the server.\n\
+ Synonyms: RASG, RASSIGN."));
+#endif /* NOSPL */
+
+case XZPWD:
+ return(hmsg(
+#ifdef NEWFTP
+"Syntax: REMOTE PWD\n\
+ Asks the Kermit server to display its current working directory.\n\
+ Synonym: RPWD."));
+#else
+"Syntax: REMOTE PWD\n\
+ Asks the Kermit or FTP server to display its current working directory.\n\
+ Synonym: RPWD."));
+#endif /* NEWFTP */
+
+case XZXIT:
+#ifdef NEWFTP
+ return(hmsg("Syntax: REMOTE EXIT\n\
+ Asks the Kermit server to exit (without disconnecting), or closes an FTP\n\
+ connection. Synonym: REXIT, and (for FTP only) BYE, FTP BYE."));
+#else
+ return(hmsg("Syntax: REMOTE EXIT\n\
+ Asks the Kermit server to exit. Synonym: REXIT."));
+#endif /* NEWFTP */
+
+default:
+ if ((x = cmcfm()) < 0) return(x);
+ printf("?Sorry, no help available - \"%s\"\n",cmdbuf);
+ return(-9);
+ }
+}
+#endif /* NOXFER */
+#endif /* NOHELP */
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuus3.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus3.c
new file mode 100644
index 0000000..5887b34
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus3.c
@@ -0,0 +1,13629 @@
+#ifdef SSHTEST
+#define SSHBUILTIN
+#endif /* SSHTEST */
+
+#include "ckcsym.h" /* Symbol definitions */
+
+/* C K U U S 3 -- "User Interface" for C-Kermit, part 3 */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/* SET command (but much material has been split off into ckuus7.c). */
+
+/*
+ Kermit-specific includes.
+ Definitions here supersede those from system include files.
+*/
+#include "ckcdeb.h" /* Debugging & compiler things */
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckcker.h" /* Kermit application definitions */
+#include "ckcxla.h" /* Character set translation */
+#include "ckcnet.h" /* Network symbols */
+
+char pwbuf[PWBUFL+1] = { NUL, NUL };
+int pwflg = 0;
+int pwcrypt = 0;
+
+#ifndef NOICP
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+#include "ckuusr.h" /* User interface symbols */
+#ifdef OS2
+#include "ckcuni.h"
+#ifdef SSHBUILTIN
+#include "ckossh.h"
+#endif /* SSHBUILTIN */
+#ifdef CK_NETBIOS
+#include <os2.h>
+#ifdef COMMENT /* Would you believe */
+#undef COMMENT /* <os2.h> defines this ? */
+#endif /* COMMENT */
+#include "ckonbi.h"
+extern UCHAR NetBiosAdapter;
+#endif /* CK_NETBIOS */
+#include "ckocon.h"
+#include "ckokey.h"
+#ifndef NOTERM
+extern unsigned char colorcmd; /* Command-screen colors */
+extern struct keytab ttyclrtab[];
+extern int nclrs;
+extern int tt_cols[], tt_rows[], tt_szchng[], tt_status[];
+#endif /* NOTERM */
+_PROTOTYP(int setprty, (void));
+extern char startupdir[], exedir[];
+extern int tt_modechg;
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h" /* Microsoft TAPI */
+#endif /* NT */
+#endif /* OS2 */
+
+#ifndef OS2
+extern char * exedir;
+#endif /* OS2 */
+
+#ifdef CK_RECALL
+extern int cm_retry;
+#endif /* CK_RECALL */
+
+#ifdef NEWFTP
+extern int ftpisopen();
+#endif /* NEWFTP */
+
+extern int cmdint;
+extern int srvidl;
+
+#ifdef CKFLOAT
+extern CKFLOAT floatval; /* (see isfloat()) */
+#endif /* CKFLOAT */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+#ifdef VMS
+char editor[CKMAXPATH + 1] = "edit";
+#else
+char editor[CKMAXPATH + 1] = { NUL, NUL };
+#endif /* VMS */
+char editopts[128] = { NUL, NUL };
+char editfile[CKMAXPATH + 1] = { NUL, NUL };
+#ifdef BROWSER
+char browser[CKMAXPATH + 1] = { NUL, NUL };
+char browsopts[128] = { NUL, NUL };
+char browsurl[4096] = { NUL, NUL };
+#endif /* BROWSER */
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifndef NOFRILLS
+#ifndef NORENAME
+_PROTOTYP(int setrename, (void));
+#endif /* NORENAME */
+#endif /* NOFRILLS */
+
+/* Variables */
+
+int cmd_quoting = 1;
+int cmd_err = 1;
+extern int hints, xcmdsrc;
+
+#ifdef CK_KERBEROS
+char * k4pwprompt = NULL; /* Kerberos 4 password prompt */
+char * k4prprompt = NULL; /* Kerberos 4 principal prompt */
+char * k5pwprompt = NULL; /* Kerberos 5 password prompt */
+char * k5prprompt = NULL; /* Kerberos 5 principal prompt */
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+char * srppwprompt = NULL;
+#endif /* CK_SRP */
+
+extern char * ckprompt, * ikprompt; /* Default prompt */
+extern xx_strp xxstring;
+
+extern char * cdmsgfile[], * cdmsgstr;
+
+extern int
+ local, server, success, dest, sleepcan, inserver, flow, autoflow, binary,
+ parity, escape, what, turn, duplex, backgrd, hwparity, stopbits, turnch,
+ mdmtyp, network, quiet, nettype, carrier, debses, debtim, cdtimo, nlangs,
+ bgset, pflag, msgflg, cmdmsk, xsuspend, techo, pacing, xitwarn, xitsta,
+ outesc, cmd_cols, cmd_rows, ckxech, xaskmore, haveline, didsetlin, isguest,
+ mdmsav, clearrq, saveask, debmsg;
+
+extern int reliable, setreliable, matchdot, matchfifo, dir_dots;
+
+#ifndef NOSERVER
+ extern int en_pri;
+#endif /* NOSERVER */
+
+#ifdef IKSDCONF
+extern int iksdcf;
+#endif /* IKSDCONF */
+#ifdef TCPSOCKET
+ extern int tn_exit;
+#endif /* TCPSOCKET */
+#ifdef TNCODE
+ char * tn_pr_uid = NULL;
+#endif /* TNCODE */
+ extern int exitonclose;
+
+#ifndef NOKVERBS
+extern int nkverbs;
+extern struct keytab kverbs[];
+#endif /* NOKVERBS */
+
+extern int ttnproto; /* Network protocol */
+
+extern char *ccntab[]; /* Names of control chars */
+
+#ifdef CK_APC
+extern int apcactive, apcstatus;
+#endif /* CK_APC */
+
+#ifndef NOSCRIPT
+extern int secho; /* Whether SCRIPT cmd should echo */
+#endif /* NOSCRIPT */
+
+#ifdef DCMDBUF
+extern char *atmbuf, *atxbuf;
+#else
+extern char atmbuf[], atxbuf[];
+#endif /* DCMDBUF */
+extern int cmflgs;
+
+extern char psave[];
+extern char uidbuf[];
+extern int sl_uid_saved;
+int DeleteStartupFile = 0;
+
+extern int cmdlvl; /* Overall command level */
+
+#ifndef NOSPL
+_PROTOTYP( static int parsdir, (int) );
+char prmbuf[PWBUFL+1] = { NUL, NUL };
+int fndiags = 1; /* Function diagnostics on/off */
+int fnerror = 1; /* Function error treatment */
+
+#ifdef DCMDBUF
+extern int *count, *takerr, *merror, *inpcas;
+#else
+extern int count[], takerr[], merror[], inpcas[];
+#endif /* DCMDBUF */
+extern int mecho; /* Macro echo */
+extern long ck_alarm;
+extern char alrm_date[], alrm_time[];
+#else
+extern int takerr[];
+#endif /* NOSPL */
+
+extern int x_ifnum;
+extern int bigsbsiz, bigrbsiz; /* Packet buffers */
+
+extern long speed; /* Terminal speed */
+
+extern char ttname[]; /* Communication device name */
+extern char myhost[] ;
+extern char inidir[]; /* Ini File directory */
+
+#ifndef NOSETKEY
+extern KEY *keymap; /* Character map for SET KEY (1:1) */
+extern MACRO *macrotab; /* Macro map for SET KEY (1:string) */
+#endif /* NOSETKEY */
+#ifdef OS2
+int wideresult; /* For wide OS/2 scan codes/cmnum() */
+#endif /* OS2 */
+
+#ifndef NOLOCAL
+#ifdef OS2
+extern int tt_scrsize[]; /* Scrollback buffer Sizes */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+/* Printer settings */
+
+extern char * printername; /* NULL if printer not redirected */
+extern int printpipe;
+extern int noprinter;
+#ifdef PRINTSWI
+int printtimo = 0;
+char * printterm = NULL;
+char * printsep = NULL;
+int printertype = 0;
+#ifdef BPRINT
+int printbidi = 0; /* SET BPRINTER (bidirectional) */
+long pportspeed = 0L; /* Bidirection printer port speed, */
+int pportparity = 0; /* parity, */
+int pportflow = FLO_KEEP; /* and flow control */
+#endif /* BPRINT */
+#ifdef OS2
+extern int txt2ps; /* Text2PS conversion? */
+extern int ps_width, ps_length; /* Text2PS dimensions */
+#endif /* OS2 */
+#endif /* PRINTSWI */
+
+#ifdef OS2
+extern int tcp_avail; /* Nonzero if TCP/IP is available */
+#ifdef DECNET
+extern int dnet_avail; /* Ditto for DECnet */
+#endif /* DECNET */
+#ifdef SUPERLAT
+extern int slat_avail;
+#endif /* SUPERLAT */
+#endif /* OS2 */
+
+static struct keytab logintab[] = {
+ { "password", LOGI_PSW, CM_INV },
+ { "prompt", LOGI_PRM, CM_INV },
+ { "userid", LOGI_UID, 0 }
+};
+
+#ifndef NOCSETS
+/* system-independent character sets, defined in ckcxla.[ch] */
+extern struct csinfo tcsinfo[];
+extern struct langinfo langs[];
+
+/* Other character-set related variables */
+extern int tcharset, tslevel, language;
+#endif /* NOCSETS */
+
+/* File-transfer variable declarations */
+
+#ifndef NOXFER
+#ifdef CK_AUTODL
+extern int cmdadl;
+#endif /* CK_AUTODL */
+
+#ifndef NOSERVER
+extern int ngetpath;
+extern char * getpath[];
+#endif /* NOSERVER */
+
+extern struct ck_p ptab[];
+
+extern CHAR sstate; /* Protocol start state */
+extern CHAR myctlq; /* Control-character prefix */
+extern CHAR myrptq; /* Repeat-count prefix */
+
+extern int protocol, size, spsiz, spmax, urpsiz, srvtim, srvcdmsg, slostart,
+ srvdis, xfermode, ckdelay, keep, maxtry, unkcs, bctr, bctf, ebqflg, swcapr,
+ wslotr, lscapr, lscapu, spsizr, rptena, rptmin, docrc, xfrcan, xfrchr,
+ xfrnum, xfrbel, xfrint, srvping, g_xfermode, xfrxla;
+
+#ifdef PIPESEND
+extern int usepipes;
+#endif /* PIPESEND */
+
+#ifdef CKXXCHAR /* DOUBLE / IGNORE char table */
+extern int dblflag, ignflag, dblchar;
+extern short dblt[];
+#endif /* CKXXCHAR */
+
+#ifdef CK_SPEED
+extern short ctlp[]; /* Control-prefix table */
+extern int prefixing;
+static struct keytab pfxtab[] = {
+ "all", PX_ALL, 0,
+ "cautious", PX_CAU, 0,
+ "minimal", PX_WIL, 0,
+ "none", PX_NON, 0
+};
+#endif /* CK_SPEED */
+#endif /* NOXFER */
+
+/* Declarations from cmd package */
+
+#ifdef DCMDBUF
+extern char *cmdbuf; /* Command buffer */
+extern char *line;
+extern char *tmpbuf;
+#else
+extern char cmdbuf[]; /* Command buffer */
+extern char line[]; /* Character buffer for anything */
+extern char tmpbuf[];
+#endif /* DCMDBUF */
+
+/* From main ckuser module... */
+
+extern char *tp, *lp; /* Temporary buffer */
+
+extern int tlevel; /* Take Command file level */
+
+#ifndef NOLOCAL
+extern int sessft; /* Session-log file type */
+extern int slogts; /* Session-log timestamps on/off */
+extern int slognul; /* Lines null-terminated */
+#endif /* NOLOCAL */
+
+char * tempdir = NULL;
+
+#ifdef VMS
+int vms_msgs = 1; /* SET MESSAGES */
+extern int batch;
+#endif /* VMS */
+
+/* Keyword tables for SET commands */
+
+#ifdef CK_SPEED
+struct keytab ctltab[] = {
+ "prefixed", 1, 0, /* Note, the values are important. */
+ "unprefixed", 0, 0
+};
+#endif /* CK_SPEED */
+
+static struct keytab oldnew[] = {
+ "new", 0, 0,
+ "old", 1, 0
+};
+
+#define MCH_FIFO 1
+#define MCH_DOTF 2
+struct keytab matchtab[] = {
+ { "dotfile", MCH_DOTF, 0 },
+ { "fifo", MCH_FIFO, 0 }
+};
+int nmatchtab = (sizeof(matchtab) / sizeof(struct keytab));
+
+#ifndef NOSPL
+static struct keytab functab[] = {
+ "diagnostics", FUNC_DI, 0,
+ "error", FUNC_ER, 0
+};
+static int nfunctab = (sizeof(functab) / sizeof(struct keytab));
+
+struct keytab outptab[] = { /* SET OUTPUT parameters */
+ "pacing", 0, 0, /* only one so far... */
+ "special-escapes", 1, 0
+};
+int noutptab = (sizeof(outptab) / sizeof(struct keytab)); /* How many */
+#endif /* NOSPL */
+
+struct keytab chktab[] = { /* Block check types */
+ "1", 1, 0, /* 1 = 6-bit checksum */
+ "2", 2, 0, /* 2 = 12-bit checksum */
+ "3", 3, 0, /* 3 = 16-bit CRC */
+ "4", 4, 0, /* Same as B */
+ "5", 5, 0, /* Same as F */
+ "blank-free-2", 4, CM_INV, /* B = 12-bit checksum, no blanks */
+ "force-3", 5, CM_INV /* F = Force CRC on ALL packets */
+};
+static int nchkt = (sizeof(chktab) / sizeof(struct keytab));
+
+struct keytab rpttab[] = { /* SET REPEAT */
+ "counts", 0, 0, /* On or Off */
+#ifdef COMMENT
+ "minimum", 1, 0, /* Threshhold */
+#endif /* COMMENT */
+ "prefix", 2, 0 /* Repeat-prefix character value */
+};
+
+#ifndef NOLOCAL
+/* For SET [ MODEM ] CARRIER, and also for SET DIAL CONNECT */
+
+struct keytab crrtab[] = {
+ "automatic", CAR_AUT, 0, /* 2 */
+ "off", CAR_OFF, 0, /* 0 */
+ "on", CAR_ON, 0 /* 1 */
+};
+int ncrr = 3;
+#endif /* NOLOCAL */
+
+struct keytab ooatab[] = { /* On/Off/Auto table */
+ "automatic", SET_AUTO, 0, /* 2 */
+ "off", SET_OFF, 0, /* 0 */
+ "on", SET_ON, 0 /* 1 */
+};
+
+struct keytab ooetab[] = { /* On/Off/Stderr table 2010/03/12 */
+ "off", SET_OFF, 0, /* for SET DEBUG MESSAGES */
+ "on", SET_ON, 0,
+ "s", 2, CM_ABR|CM_INV,
+ "st", 2, CM_ABR|CM_INV,
+ "std", 2, CM_ABR|CM_INV,
+ "stderr", 2, 0,
+ "stdout", SET_ON, CM_INV
+};
+static int nooetab = (sizeof(ooetab) / sizeof(struct keytab));
+
+struct keytab ooktab[] = { /* On/Off/Ask table */
+ "ask", 2, 0, /* 2 */
+ "off", SET_OFF, 0, /* 0 */
+ "on", SET_ON, 0 /* 1 */
+};
+
+struct keytab qvtab[] = { /* Quiet/Verbose table */
+ "quiet", 1, 0,
+ "verbose", 0, 0
+};
+int nqvt = 2;
+
+/* For SET DEBUG */
+
+#define DEB_OFF 0
+#define DEB_ON 1
+#define DEB_SES 2
+#define DEB_TIM 3
+#define DEB_LEN 4
+#define DEB_MSG 5
+
+struct keytab dbgtab[] = {
+ "linelength", DEB_LEN, CM_INV,
+ "m", DEB_MSG, CM_ABR|CM_INV,
+ "message", DEB_MSG, 0,
+ "msg", DEB_MSG, CM_INV,
+ "off", DEB_OFF, 0,
+ "on", DEB_ON, 0,
+ "session", DEB_SES, 0,
+ "timestamps", DEB_TIM, 0
+};
+int ndbg = (sizeof(dbgtab) / sizeof(struct keytab));
+
+#ifndef NOLOCAL
+/* Transmission speeds */
+
+#ifdef TTSPDLIST /* Speed table constructed at runtime . . . */
+
+struct keytab * spdtab = NULL;
+int nspd = 0;
+
+#else
+/*
+ Note, the values are encoded in cps rather than bps because 19200 and higher
+ are too big for some ints. All but 75bps are multiples of ten. Result of
+ lookup in this table must be multiplied by 10 to get actual speed in bps.
+ If this number is 70, it must be changed to 75. If it is 888, this means
+ 75/1200 split speed.
+
+ The values are generic, rather than specific to UNIX. We can't use B75,
+ B1200, B9600, etc, because non-UNIX versions of C-Kermit will not
+ necessarily have these symbols defined. The BPS_xxx symbols are
+ Kermit-specific, and are defined in ckcdeb.h or on the CC command line.
+
+ Like all other keytabs, this one must be in "alphabetical" order,
+ rather than numeric order.
+*/
+struct keytab spdtab[] = {
+ "0", 0, CM_INV,
+ "110", 11, 0,
+#ifdef BPS_115K
+ "115200",11520, 0,
+#endif /* BPS_115K */
+ "1200", 120, 0,
+#ifdef BPS_134
+ "134.5", 134, 0,
+#endif /* BPS_134 */
+#ifdef BPS_14K
+ "14400", 1440, 0,
+#endif /* BPS_14K */
+#ifdef BPS_150
+ "150", 15, 0,
+#endif /* BPS_150 */
+#ifdef BPS_1800
+ "1800", 180, 0,
+#endif /* BPS_150 */
+#ifdef BPS_19K
+ "19200", 1920, 0,
+#endif /* BPS_19K */
+#ifdef BPS_200
+ "200", 20, 0,
+#endif /* BPS_200 */
+#ifdef BPS_230K
+ "230400", 23040, 0,
+#endif /* BPS_230K */
+ "2400", 240, 0,
+#ifdef BPS_28K
+ "28800", 2880, 0,
+#endif /* BPS_28K */
+ "300", 30, 0,
+#ifdef BPS_3600
+ "3600", 360, 0,
+#endif /* BPS_3600 */
+#ifdef BPS_38K
+ "38400", 3840, 0,
+#endif /* BPS_38K */
+#ifdef BPS_460K
+ "460800", 46080, 0, /* Need 32 bits for this... */
+#endif /* BPS_460K */
+ "4800", 480, 0,
+#ifdef BPS_50
+ "50", 5, 0,
+#endif /* BPS_50 */
+#ifdef BPS_57K
+ "57600", 5760, 0,
+#endif /* BPS_57K */
+ "600", 60, 0,
+#ifdef BPS_7200
+ "7200", 720, 0,
+#endif /* BPS_7200 */
+#ifdef BPS_75
+ "75", 7, 0,
+#endif /* BPS_75 */
+#ifdef BPS_7512
+ "75/1200",888, 0, /* Code "888" for split speed */
+#endif /* BPS_7512 */
+#ifdef BPS_76K
+ "76800", 7680, 0,
+#endif /* BPS_76K */
+#ifdef BPS_921K
+ "921600", 92160,0, /* Need 32 bits for this... */
+#endif /* BPS_921K */
+ "9600", 960, 0
+};
+int nspd = (sizeof(spdtab) / sizeof(struct keytab)); /* How many speeds */
+#endif /* TTSPDLIST */
+
+#ifdef TN_COMPORT
+struct keytab tnspdtab[] = { /* RFC 2217 TELNET COMPORT Option */
+ "115200", 11520, 0, /* (add any other defined speeds) */
+ "1200", 120, 0,
+ "14400", 1440, 0,
+ "19200", 1920, 0,
+ "230400", 23040, 0,
+ "2400", 240, 0,
+ "28800", 2880, 0,
+ "300", 30, 0,
+ "38400", 3840, 0,
+ "460800", 46080, 0,
+ "4800", 480, 0,
+ "57600", 5760, 0,
+ "600", 60, 0,
+ "9600", 960, 0
+};
+int ntnspd = (sizeof(tnspdtab) / sizeof(struct keytab)); /* How many speeds */
+#endif /* TN_COMPORT */
+#endif /* NOLOCAL */
+
+#ifndef NOCSETS
+extern struct keytab lngtab[]; /* Languages for SET LANGUAGE */
+extern int nlng;
+#endif /* NOCSETS */
+
+#ifndef NOLOCAL
+/* Duplex keyword table */
+
+struct keytab dpxtab[] = {
+ "full", 0, 0,
+ "half", 1, 0
+};
+#endif /* NOLOCAL */
+
+/* Flow Control */
+
+struct keytab cxtypesw[] = {
+#ifdef DECNET
+ "/decnet", CXT_DECNET, 0,
+#endif /* DECNET */
+ "/direct-serial", CXT_DIRECT, 0,
+#ifdef DECNET
+ "/lat", CXT_LAT, 0,
+#else
+#ifdef SUPERLAT
+ "/lat", CXT_LAT, 0,
+#endif /* SUPERLAT */
+#endif /* DECNET */
+ "/modem", CXT_MODEM, 0,
+#ifdef NPIPE
+ "/named-pipe", CXT_NPIPE, 0,
+#endif /* NPIPE */
+#ifdef NETBIOS
+ "/netbios", CXT_NETBIOS, 0,
+#endif /* NETBIOS */
+ "/remote", CXT_REMOTE, 0,
+#ifdef TCPSOCKET
+ "/tcpip", CXT_TCPIP, 0,
+#endif /* TCPSOCKET */
+#ifdef ANYX25
+ "/x.25", CXT_X25, 0,
+#endif /* ANYX25 */
+ "", 0, 0
+};
+int ncxtypesw = (sizeof(cxtypesw) / sizeof(struct keytab));
+
+#ifdef TN_COMPORT
+struct keytab tnflotab[] = { /* SET FLOW-CONTROL keyword table */
+ "dtr/cd", FLO_DTRC, 0, /* for RFC 2217 Telnet COMPORT */
+ "dtr/cts", FLO_DTRT, 0,
+ "keep", FLO_KEEP, 0,
+ "none", FLO_NONE, 0,
+ "rts/cts", FLO_RTSC, 0,
+ "xon/xoff", FLO_XONX, 0
+};
+int ntnflo = (sizeof(tnflotab) / sizeof(struct keytab));
+#endif /* TN_COMPORT */
+
+struct keytab flotab[] = { /* SET FLOW-CONTROL keyword table */
+ "automatic", FLO_AUTO, CM_INV, /* Not needed any more */
+#ifdef CK_DTRCD
+ "dtr/cd", FLO_DTRC, 0,
+#endif /* CK_DTRCD */
+#ifdef CK_DTRCTS
+ "dtr/cts", FLO_DTRT, 0,
+#endif /* CK_DTRCTS */
+ "keep", FLO_KEEP, 0,
+ "none", FLO_NONE, 0,
+#ifdef CK_RTSCTS
+ "rts/cts", FLO_RTSC, 0,
+#endif /* CK_RTSCTS */
+#ifndef Plan9
+ "xon/xoff", FLO_XONX, 0,
+#endif /* Plan9 */
+ "", 0, 0
+};
+int nflo = (sizeof(flotab) / sizeof(struct keytab)) - 1;
+
+/* Handshake characters */
+
+struct keytab hshtab[] = {
+ "bell", 007, 0,
+ "code", 998, 0,
+ "cr", 015, 0,
+ "esc", 033, 0,
+ "lf", 012, 0,
+ "none", 999, 0, /* (can't use negative numbers) */
+ "xoff", 023, 0,
+ "xon", 021, 0
+};
+int nhsh = (sizeof(hshtab) / sizeof(struct keytab));
+
+#ifndef NOLOCAL
+static struct keytab sfttab[] = { /* File types for SET SESSION-LOG */
+ "ascii", XYFT_T, CM_INV,
+ "binary", XYFT_B, 0,
+ "debug", XYFT_D, 0,
+ "null-padded-lines", 998, 0,
+ "text", XYFT_T, 0,
+ "timestamped-text", 999, 0
+};
+static int nsfttab = (sizeof(sfttab) / sizeof(struct keytab));
+#endif /* NOLOCAL */
+
+#ifndef NODIAL
+
+#ifdef NETCONN /* Networks directory depends */
+int nnetdir = 0; /* on DIAL code -- fix later... */
+char *netdir[MAXDDIR+2];
+#endif /* NETCONN */
+
+_PROTOTYP( static int setdial, (int) );
+_PROTOTYP( static int setdcd, (void) );
+_PROTOTYP( static int cklogin, (void) );
+
+#ifndef MINIDIAL
+#ifdef OLDTBCODE
+extern int tbmodel; /* Telebit model ID */
+#endif /* OLDTBCODE */
+#endif /* MINIDIAL */
+
+extern MDMINF *modemp[]; /* Pointers to modem info structs */
+extern struct keytab mdmtab[]; /* Modem types (in module ckudia.c) */
+extern int nmdm; /* Number of them */
+
+_PROTOTYP(static int dialstr,(char **, char *));
+
+extern int dialhng, dialtmo, dialksp, dialdpy, dialmhu, dialec, dialdc;
+extern int dialrtr, dialint, dialudt, dialsrt, dialrstr, mdmwaitd;
+extern int mdmspd, dialfc, dialmth, dialesc, dialfld, dialidt, dialpace;
+extern int mdmspk, mdmvol, dialtest;
+
+int dialcvt = 2; /* DIAL CONVERT-DIRECTORY */
+int dialcnf = 0; /* DIAL CONFIRMATION */
+int dialcon = 2; /* DIAL CONNECT */
+int dialcq = 0; /* DIAL CONNECT AUTO quiet/verbose */
+extern long dialmax, dialcapas;
+int usermdm = 0;
+extern int ndialdir;
+extern char *dialini, *dialmstr, *dialmprmt, *dialdir[], *dialcmd, *dialnpr,
+ *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *dialx3,
+ *dialhwfc, *dialswfc, *dialnofc, *dialtone, *dialpulse, *dialname, *diallac;
+extern char *diallcc, *dialixp, *dialixs, *dialldp, *diallds, *dialtfp,
+ *dialpxi, *dialpxo, *dialsfx, *dialaaon, *dialaaoff;
+extern char *diallcp, *diallcs, *dialini2, *dialmac;
+extern char *dialspoff, *dialspon, *dialvol1, *dialvol2, *dialvol3;
+
+char *dialtocc[MAXTPCC] = { NULL, NULL };
+int ndialtocc = 0;
+char *dialpucc[MAXTPCC] = { NULL, NULL };
+int ndialpucc = 0;
+
+char *dialtfc[MAXTOLLFREE] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+int ntollfree = 0;
+
+char *dialpxx[MAXPBXEXCH] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+int ndialpxx = 0;
+
+char *diallcac[MAXLOCALAC] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+int nlocalac = 0;
+
+static struct keytab drstrtab[] = {
+ "international", 5, 0,
+ "local", 2, 0,
+ "long-distance", 4, 0,
+ "none", 6, 0
+};
+
+static struct keytab dcnvtab[] = {
+ "ask", 2, 0,
+ "off", 0, 0,
+ "on", 1, 0
+};
+
+struct keytab setmdm[] = {
+ "capabilities", XYDCAP, 0,
+ "carrier-watch", XYDMCD, 0,
+ "command", XYDSTR, 0,
+ "compression", XYDDC, CM_INV,
+ "data-compression", XYDDC, 0,
+ "dial-command", XYDDIA, 0,
+ "error-correction", XYDEC, 0,
+ "escape-character", XYDESC, 0,
+ "flow-control", XYDFC, 0,
+ "hangup-method", XYDMHU, 0,
+#ifndef NOXFER
+ "kermit-spoof", XYDKSP, 0,
+#endif /* NOXFER */
+ "maximum-speed", XYDMAX, 0,
+ "name", XYDNAM, 0,
+ "speaker", XYDSPK, 0,
+ "speed-matching", XYDSPD, 0,
+ "type", XYDTYP, 0,
+ "volume", XYDVOL, 0
+};
+int nsetmdm = (sizeof(setmdm) / sizeof(struct keytab));
+
+struct keytab voltab[] = {
+ "high", 3, 0,
+ "low", 1, 0,
+ "medium", 2, 0
+};
+
+struct keytab mdmcap[] = {
+ "at-commands", CKD_AT, 0,
+ "compression", CKD_DC, 0,
+ "dc", CKD_DC, CM_INV,
+ "ec", CKD_EC, CM_INV,
+ "error-correction", CKD_EC, 0,
+ "hardware-flow", CKD_HW, 0,
+ "hwfc", CKD_HW, CM_INV,
+ "itu", CKD_V25, CM_INV,
+ "kermit-spoof", CKD_KS, 0,
+ "ks", CKD_KS, CM_INV,
+ "sb", CKD_SB, CM_INV,
+ "software-flow", CKD_SW, 0,
+ "speed-buffering", CKD_SB, 0,
+ "swfc", CKD_SW, CM_INV,
+ "tb", CKD_TB, CM_INV,
+ "telebit", CKD_TB, 0,
+ "v25bis-commands", CKD_V25, 0
+};
+int nmdmcap = (sizeof(mdmcap) / sizeof(struct keytab));
+
+#ifdef COMMENT /* SET ANSWER not implemented yet */
+static struct keytab answertab[] = {
+ { "caller-id", XYA_CID, 0 };
+ { "rings", XYA_RNG, 0 };
+ { "", 0, 0 }
+};
+static int nanswertab = (sizeof(answertab) / sizeof(struct keytab)) - 1;
+#endif /* COMMENT */
+
+struct keytab dialtab[] = { /* SET DIAL table */
+ "area-code", XYDLAC, 0, /* Also still includes items */
+ "compression", XYDDC, CM_INV, /* that were moved to SET MODEM, */
+ "confirmation", XYDCNF, 0, /* but they are CM_INVisible... */
+ "connect", XYDCON, 0,
+ "convert-directory",XYDCVT, 0,
+ "country-code", XYDLCC, 0,
+ "dial-command", XYDDIA, CM_INV,
+ "directory", XYDDIR, 0,
+ "display", XYDDPY, 0,
+ "escape-character", XYDESC, CM_INV,
+ "error-correction", XYDEC, CM_INV,
+ "flow-control", XYDFC, CM_INV,
+ "force-long-distance", XYDFLD, 0,
+ "hangup", XYDHUP, 0,
+ "ignore-dialtone", XYDIDT, 0,
+ "interval", XYDINT, 0,
+ "in", XYDINI, CM_INV|CM_ABR,
+ "init-string", XYDINI, CM_INV,
+ "intl-prefix", XYDIXP, 0,
+ "intl-suffix", XYDIXS, 0,
+#ifndef NOXFER
+ "kermit-spoof", XYDKSP, CM_INV,
+#endif /* NOXFER */
+ "lc-area-codes", XYDLLAC, 0,
+ "lc-prefix", XYDLCP, 0,
+ "lc-suffix", XYDLCS, 0,
+ "ld-prefix", XYDLDP, 0,
+ "ld-suffix", XYDLDS, 0,
+ "local-area-code", XYDLAC, CM_INV,
+ "local-prefix", XYDLCP, CM_INV,
+ "local-suffix", XYDLCS, CM_INV,
+ "m", XYDMTH, CM_INV|CM_ABR,
+#ifndef NOSPL
+ "macro", XYDMAC, 0, /* 195 */
+#endif /* NOSPL */
+#ifdef MDMHUP
+ "me", XYDMTH, CM_INV|CM_ABR,
+#endif /* MDMHUP */
+ "method", XYDMTH, 0,
+ "mnp-enable", XYDMNP, CM_INV, /* obsolete but still accepted */
+#ifdef MDMHUP
+ "modem-hangup", XYDMHU, CM_INV,
+#endif /* MDMHUP */
+ "pacing", XYDPAC, 0,
+ "pbx-exchange", XYDPXX, 0,
+ "pbx-inside-prefix",XYDPXI, 0,
+ "pbx-outside-prefix",XYDPXO, 0,
+ "prefix", XYDNPR, 0,
+ "pulse-countries", XYDPUCC, 0,
+ "restrict", XYDRSTR, 0,
+ "retries", XYDRTM, 0,
+ "sort", XYDSRT, 0,
+ "speed-matching", XYDSPD, CM_INV,
+ "string", XYDSTR, CM_INV,
+ "suffix", XYDSFX, 0,
+ "test", XYDTEST, 0,
+ "timeout", XYDTMO, 0,
+ "tf-area-code", XYDTFC, CM_INV,
+ "tf-prefix", XYDTFP, CM_INV,
+ "toll-free-area-code",XYDTFC,0,
+ "toll-free-prefix", XYDTFP, 0,
+ "tone-countries", XYDTOCC, 0
+};
+int ndial = (sizeof(dialtab) / sizeof(struct keytab));
+
+#ifdef MDMHUP
+struct keytab mdmhang[] = {
+ "dtr", 0, 0,
+ "modem-command", 1, 0,
+ "rs232-signal", 0, 0,
+ "v24-signal", 0, CM_INV
+};
+#endif /* MDMHUP */
+
+static struct keytab mdmcmd[] = {
+ "autoanswer", XYDS_AN, 0, /* autoanswer */
+ "compression", XYDS_DC, 0, /* data compression */
+ "dial-mode-prompt", XYDS_MP, 0, /* dial mode prompt */
+ "dial-mode-string", XYDS_MS, 0, /* dial mode string */
+ "error-correction", XYDS_EC, 0, /* error correction */
+ "hangup-command", XYDS_HU, 0, /* hangup command */
+ "hardware-flow", XYDS_HW, 0, /* hwfc */
+ "ignore-dialtone", XYDS_ID, 0, /* ignore dialtone */
+ "init-string", XYDS_IN, 0, /* init string */
+ "no-flow-control", XYDS_NF, 0, /* no flow control */
+ "predial-init", XYDS_I2, 0, /* last-minute setup commands */
+ "pulse", XYDS_DP, 0, /* pulse */
+ "software-flow", XYDS_SW, 0, /* swfc */
+ "speaker", XYDS_SP, 0, /* Speaker */
+ "tone", XYDS_DT, 0, /* tone */
+ "volume", XYDS_VO, 0 /* Volume */
+};
+static int nmdmcmd = (sizeof(mdmcmd) / sizeof(struct keytab));
+
+struct keytab dial_fc[] = {
+ "auto", FLO_AUTO, 0,
+ "none", FLO_NONE, 0,
+ "rts/cts", FLO_RTSC, 0,
+ "xon/xoff", FLO_XONX, 0
+};
+
+struct keytab dial_m[] = { /* DIAL METHOD */
+ "auto", XYDM_A, 0,
+ "default", XYDM_D, 0,
+ "pulse", XYDM_P, 0,
+ "tone", XYDM_T, 0
+};
+int ndial_m = (sizeof(dial_m)/sizeof(struct keytab));
+#endif /* NODIAL */
+
+#ifdef CK_TAPI
+struct keytab tapitab[] = { /* Top-Level Microsoft TAPI */
+ "configure-line", XYTAPI_CFG, 0,
+ "dialing-properties", XYTAPI_DIAL, 0
+};
+int ntapitab = (sizeof(tapitab)/sizeof(struct keytab));
+
+struct keytab settapitab[] = { /* SET Microsoft TAPI */
+ "inactivity-timeout", XYTAPI_INA, 0,
+ "line", XYTAPI_LIN, 0,
+ "location", XYTAPI_LOC, 0,
+ "manual-dialing", XYTAPI_MAN, 0,
+ "modem-dialing", XYTAPI_PASS, 0,
+ "modem-lights", XYTAPI_LGHT, 0,
+ "phone-number-conversions", XYTAPI_CON, 0,
+ "port", XYTAPI_LIN, CM_INV,
+ "post-dial-terminal", XYTAPI_PST, 0,
+ "pre-dial-terminal", XYTAPI_PRE, 0,
+ "use-windows-configuration", XYTAPI_USE, 0,
+ "wait-for-credit-card-tone", XYTAPI_BNG, 0
+};
+int nsettapitab = (sizeof(settapitab)/sizeof(struct keytab));
+
+struct keytab * tapiloctab = NULL; /* Microsoft TAPI Locations */
+int ntapiloc = 0;
+extern struct keytab * tapilinetab; /* Microsoft TAPI Line Devices */
+extern int ntapiline;
+extern int tttapi; /* TAPI in use */
+extern int tapipass; /* TAPI Passthrough mode */
+extern int tapiconv; /* TAPI Conversion mode */
+extern int tapilights;
+extern int tapipreterm;
+extern int tapipostterm;
+extern int tapimanual;
+extern int tapiinactivity;
+extern int tapibong;
+extern int tapiusecfg;
+#endif /* CK_TAPI */
+
+#ifndef NOPUSH
+extern int nopush;
+extern int wildena;
+#ifdef UNIX
+struct keytab wildtab[] = { /* SET WILDCARD-EXPANSION */
+#ifdef UNIX
+ "kermit", WILD_KER, 0, /* By Kermit */
+#endif /* UNIX */
+ "off", WILD_OFF, 0, /* Disabled */
+ "on", WILD_ON, 0, /* Enabled */
+#ifdef UNIX
+ "shell", WILD_SHE, 0, /* By Shell */
+#endif /* UNIX */
+ "", 0, 0
+};
+int nwild = (sizeof(wildtab) / sizeof(struct keytab)) - 1;
+
+struct keytab wdottab[] = { /* cont'd */
+ "/match-dot-files", 1, 0,
+ "/no-match-dot-files", 0, 0
+};
+extern int wildxpand;
+#endif /* UNIX */
+#endif /* NOPUSH */
+
+#ifdef NETCONN
+extern struct keytab netcmd[], netkey[];
+extern int nnets, nnetkey;
+#ifdef TCPSOCKET
+extern struct keytab tcpopt[];
+extern int ntcpopt;
+#endif /* TCPSOCKET */
+#ifdef NPIPE
+char pipename[PIPENAML+1] = { NUL, NUL };
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+extern unsigned char NetBiosName[];
+#endif /* CK_NETBIOS */
+#endif /* NETCONN */
+
+#ifdef ANYX25
+struct keytab x25tab[] = {
+ "call-user-data", XYUDAT, 0,
+ "closed-user-group", XYCLOS, 0,
+ "reverse-charge", XYREVC, 0
+};
+int nx25 = (sizeof(x25tab) / sizeof(struct keytab));
+
+#ifndef IBMX25
+struct keytab padx3tab[] = {
+ "break-action", PAD_BREAK_ACTION, 0,
+ "break-character", PAD_BREAK_CHARACTER, 0,
+ "character-delete", PAD_CHAR_DELETE_CHAR, 0,
+ "cr-padding", PAD_PADDING_AFTER_CR, 0,
+ "discard-output", PAD_SUPPRESSION_OF_DATA, 0,
+ "echo", PAD_ECHO, 0,
+ "editing", PAD_EDITING, 0,
+ "escape", PAD_ESCAPE, 0,
+ "forward", PAD_DATA_FORWARD_CHAR, 0,
+ "lf-padding", PAD_PADDING_AFTER_LF, 0,
+ "lf-insert", PAD_LF_AFTER_CR, 0,
+ "line-delete", PAD_BUFFER_DELETE_CHAR, 0,
+ "line-display", PAD_BUFFER_DISPLAY_CHAR, 0,
+ "line-fold", PAD_LINE_FOLDING, 0,
+ "pad-flow-control", PAD_FLOW_CONTROL_BY_PAD, 0,
+ "service-signals", PAD_SUPPRESSION_OF_SIGNALS, 0,
+ "timeout", PAD_DATA_FORWARD_TIMEOUT, 0,
+/* Speed is read-only */
+ "transmission-rate", PAD_LINE_SPEED, 0,
+ "user-flow-control", PAD_FLOW_CONTROL_BY_USER, 0
+};
+int npadx3 = (sizeof(padx3tab) / sizeof(struct keytab));
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifdef TLOG
+static struct keytab vbtab[] = {
+ "brief", 0, 0,
+#ifdef OS2ORUNIX
+ "ftp", 2, 0,
+#else
+#ifdef VMS
+ "ftp", 2, 0,
+#endif /* def VMS */
+#endif /* OS2ORUNIX */
+ "verbose", 1, 0
+};
+int nvb = (sizeof(vbtab) / sizeof(struct keytab));
+#endif /* TLOG */
+
+#ifdef CKSYSLOG
+static struct keytab syslogtab[] = {
+ "all", SYSLG_CX, 0,
+ "commands", SYSLG_CM, 0,
+ "connection", SYSLG_AC, 0,
+ "debug", SYSLG_DB, 0,
+ "dial", SYSLG_DI, 0,
+ "file-access", SYSLG_FA, 0,
+ "file-create", SYSLG_FC, 0,
+ "login", SYSLG_LI, 0,
+ "none", SYSLG_NO, 0,
+ "protocol", SYSLG_PR, 0
+};
+int nsyslog = (sizeof(syslogtab) / sizeof(struct keytab));
+#endif /* CKSYSLOG */
+
+/* Parity keyword table */
+
+struct keytab partbl[] = {
+ "even", 'e', 0,
+#ifdef HWPARITY
+ "hardware",'H', 0,
+#endif /* HWPARITY */
+ "mark", 'm', 0,
+ "none", 0 , 0,
+ "odd", 'o', 0,
+ "space", 's', 0
+};
+int npar = (sizeof(partbl) / sizeof(struct keytab));
+
+#ifdef HWPARITY
+struct keytab hwpartbl[] = {
+/* Add mark and space if needed and possible */
+ "even", 'e', 0,
+#ifdef OS2
+ "mark", 'm', 0,
+#endif /* OS2 */
+ "odd", 'o', 0,
+#ifdef OS2
+ "space", 's', 0,
+#endif /* OS2 */
+ "", 0, 0
+};
+int nhwpar = (sizeof(hwpartbl) / sizeof(struct keytab)) - 1;
+#endif /* HWPARITY */
+
+/* On/Off table */
+
+struct keytab onoff[] = {
+ "off", 0, 0,
+ "on", 1, 0
+};
+
+#define XYCD_M 0 /* CD MESSAGE */
+#define XYCD_P 1 /* CD PATH */
+#define XYCD_H 2 /* CD HOME */
+
+struct keytab cdtab[] = {
+ "home", XYCD_H, 0,
+ "message", XYCD_M, 0,
+ "path", XYCD_P, 0
+};
+int ncdtab = (sizeof(cdtab) / sizeof(struct keytab));
+
+struct keytab cdmsg[] = {
+ "file", 2, 0,
+ "off", 0, 0,
+ "on", 1, 0
+};
+int ncdmsg = (sizeof(cdmsg) / sizeof(struct keytab));
+
+static
+struct keytab xittab[] = { /* SET EXIT */
+ "hangup", 3, 0, /* ...HANGUP */
+ "on-disconnect", 2, 0, /* ...ON-DISCONNECT */
+ "status", 0, 0, /* ...STATUS */
+ "warning", 1, 0 /* ...WARNING */
+};
+int nexit = (sizeof(xittab) / sizeof(struct keytab));
+
+struct keytab xitwtab[] = { /* SET EXIT WARNING */
+ "always", 2, 0, /* even when not connected */
+ "off", 0, 0, /* no warning */
+ "on", 1, 0 /* when connected */
+};
+int nexitw = (sizeof(xitwtab) / sizeof(struct keytab));
+
+struct keytab rltab[] = {
+ "local", 1, 0, /* ECHO values */
+ "off", 0, CM_INV,
+ "on", 1, CM_INV,
+ "remote", 0, 0
+};
+int nrlt = (sizeof(rltab) / sizeof(struct keytab));
+
+/* Incomplete File Disposition table */
+
+struct keytab ifdtab[] = {
+ "discard", SET_OFF, 0,
+ "keep", SET_ON, 0
+};
+
+struct keytab ifdatab[] = {
+ "auto", SET_AUTO, 0,
+ "discard", SET_OFF, 0,
+ "keep", SET_ON, 0
+};
+
+char * ifdnam[] = { "discard", "keep", "auto" };
+
+/* SET TAKE parameters table */
+static
+struct keytab taktab[] = {
+ "echo", 0, 0,
+ "error", 1, 0,
+ "off", 2, CM_INV, /* For compatibility */
+ "on", 3, CM_INV /* with MS-DOS Kermit... */
+};
+
+#ifndef NOSPL
+#ifdef COMMENT
+/* not used */
+static
+struct keytab suftab[] = { /* (what to do with) STARTUP-FILE */
+ "delete", 1, 0,
+ "keep", 0, 0
+};
+#endif /* COMMENT */
+
+/* SET MACRO parameters table */
+static
+struct keytab smactab[] = {
+ "echo", 0, 0,
+ "error", 1, 0
+};
+#endif /* NOSPL */
+
+#ifndef NOSCRIPT
+static
+struct keytab scrtab[] = {
+ "echo", 0, 0
+};
+#endif /* NOSCRIPT */
+
+/* SET COMMAND table */
+
+/* SET COMMAND items... */
+
+#define SCMD_BSZ 0 /* BYTESIZE */
+#define SCMD_RCL 1 /* RECALL */
+#define SCMD_RTR 2 /* RETRY */
+#define SCMD_QUO 3 /* QUOTING */
+#define SCMD_COL 4 /* COLOR */
+#define SCMD_HIG 5 /* HEIGHT */
+#define SCMD_WID 6 /* WIDTH */
+#define SCMD_CUR 7 /* CURSOR-POSITION */
+#define SCMD_SCR 8 /* SCROLLBACK */
+#define SCMD_MOR 9 /* MORE-PROMPTING */
+#define SCMD_INT 10 /* INTERRUPTION */
+#define SCMD_ADL 11 /* AUTODOWNLOAD */
+#define SCMD_STA 12 /* STATUSLINE */
+#define SCMD_DBQ 13 /* DOUBLEQUOTING */
+#define SCMD_CBR 14 /* CBREAK */
+#define SCMD_BFL 15 /* BUFFER-SIZE (not used) */
+#define SCMD_ERR 16 /* ERROR */
+#define SCMD_VAR 17 /* VARIABLE-EVALUATION */
+
+static struct keytab scmdtab[] = {
+#ifdef CK_AUTODL
+ "autodownload", SCMD_ADL, 0,
+#endif /* CK_AUTODL */
+#ifdef COMMENT
+/*
+ To implement this requires that we change CMDBL and ATMBL
+ from compile-time symbols to runtime variables. Not a big deal,
+ but not trivial either.
+ */
+ "buffer-size", SCMD_BFL, 0,
+#endif /* COMMENT */
+ "bytesize", SCMD_BSZ, 0,
+ "cbreak", SCMD_CBR, CM_INV,
+#ifdef OS2
+ "color", SCMD_COL, 0,
+ "cursor-position", SCMD_CUR, 0,
+#endif /* OS2 */
+#ifdef DOUBLEQUOTING
+ "doublequoting", SCMD_DBQ, 0,
+#endif /* DOUBLEQUOTING */
+ "error-display", SCMD_ERR, 0,
+ "height", SCMD_HIG, 0,
+ "interruption", SCMD_INT, 0,
+ "more-prompting", SCMD_MOR, 0,
+ "quoting", SCMD_QUO, 0,
+#ifdef CK_RECALL
+ "recall-buffer-size", SCMD_RCL, 0,
+#endif /* CK_RECALL */
+#ifdef CK_RECALL
+ "retry", SCMD_RTR, 0,
+#endif /* CK_RECALL */
+#ifdef OS2
+#ifdef ONETERMUPD
+ "scrollback", SCMD_SCR, 0,
+ "statusline", SCMD_STA, 0,
+#endif /* ONETERMUPD */
+#endif /* OS2 */
+ "variable-evaluation", SCMD_VAR,0,
+ "width", SCMD_WID, 0
+};
+static int nbytt = (sizeof(scmdtab) / sizeof(struct keytab));
+
+#ifndef NOSERVER
+/* Server parameters table */
+static struct keytab srvtab[] = {
+ "cd-message", XYSERC, 0,
+ "display", XYSERD, 0,
+ "get-path", XYSERP, 0,
+ "idle-timeout", XYSERI, 0,
+ "keepalive", XYSERK, 0,
+ "login", XYSERL, 0,
+ "timeout", XYSERT, 0
+};
+static int nsrvt = (sizeof(srvtab) / sizeof(struct keytab));
+#endif /* NOSERVER */
+
+static struct keytab sleeptab[] = { /* SET SLEEP table */
+ "cancellation", 0, 0
+};
+
+static struct keytab tstab[] = { /* SET TRANSFER/XFER table */
+ "bell", XYX_BEL, 0,
+#ifdef XFRCAN
+ "cancellation", XYX_CAN, 0,
+#endif /* XFRCAN */
+#ifndef NOCSETS
+ "character-set", XYX_CSE, 0,
+#endif /* NOCSETS */
+#ifndef NOSPL
+ "crc-calculation", XYX_CRC, 0,
+#endif /* NOSPL */
+ "display", XYX_DIS, 0,
+ "interruption", XYX_INT, 0,
+ "locking-shift", XYX_LSH, 0,
+ "message", XYX_MSG, 0,
+ "mode", XYX_MOD, 0,
+ "msg", XYX_MSG, CM_INV,
+#ifdef PIPESEND
+ "pipes", XYX_PIP, 0,
+#endif /* PIPESEND */
+#ifdef CK_XYZ
+ "protocol", XYX_PRO, 0,
+#endif /* CK_XYZ */
+ "report", XYX_RPT, 0,
+ "slow-start", XYX_SLO, 0,
+#ifndef NOCSETS
+ "translation", XYX_XLA, 0,
+#else
+ "translation", XYX_XLA, CM_INV,
+#endif /* NOCSETS */
+ "xlation", XYX_XLA, CM_INV,
+ "", 0, 0
+};
+static int nts = (sizeof(tstab) / sizeof(struct keytab)) - 1;
+
+static struct keytab rtstab[] = { /* REMOTE SET TRANSFER/XFER table */
+#ifndef NOCSETS
+ "character-set", XYX_CSE, 0,
+#endif /* NOCSETS */
+ "mode", XYX_MOD, 0
+};
+static int nrts = (sizeof(rtstab) / sizeof(struct keytab));
+
+struct keytab xfrmtab[] = { /* TRANSFER MODE table */
+ "automatic", XMODE_A, 0,
+ "manual", XMODE_M, 0
+};
+
+#ifdef LOCUS
+extern int locus, autolocus;
+
+static struct keytab locustab[] = {
+#ifdef KUI
+ { "ask", 3, 0 }, /* Presently implemented in GUI only */
+#endif /* KUI */
+ { "auto", 2, 0 },
+ { "local", 1, 0 },
+ { "remote", 0, 0 }
+};
+static int nlocustab = (sizeof(locustab) / sizeof(struct keytab));
+
+#endif /* LOCUS */
+
+#ifndef NOCSETS
+/* SET TRANSFER CHARACTER-SET table */
+
+extern struct keytab tcstab[];
+extern int ntcs;
+#endif /* NOCSETS */
+
+/* SET TRANSFER LOCKING-SHIFT table */
+struct keytab lstab[] = {
+ "forced", 2, 0,
+ "off", 0, 0,
+ "on", 1, 0
+};
+int nls = (sizeof(lstab) / sizeof(struct keytab));
+
+/* SET TELNET tables */
+#ifdef TNCODE
+extern int tn_nlm, tn_b_nlm, tn_b_meu, tn_b_ume, tn_b_xfer, tn_sb_bug;
+extern int tn_no_encrypt_xfer, tn_auth_krb5_des_bug;
+extern int tn_wait_flg, tn_duplex, tn_delay_sb, tn_sfu;
+extern int sl_tn_saved;
+extern int tn_infinite;
+extern int tn_rem_echo;
+extern int tn_deb;
+extern int tn_auth_how;
+extern int tn_auth_enc;
+#ifdef CK_FORWARD_X
+extern char * tn_fwdx_xauthority;
+#endif /* CK_FORWARD_X */
+#ifdef CK_AUTHENTICATION
+static struct keytab setauth[] = {
+#ifdef CK_KERBEROS
+ "k4", AUTH_KRB4, CM_INV,
+ "k5", AUTH_KRB5, CM_INV,
+ "kerberos4", AUTH_KRB4, 0,
+ "kerberos5", AUTH_KRB5, 0,
+ "kerberos_iv",AUTH_KRB4, CM_INV,
+ "kerberos_v", AUTH_KRB5, CM_INV,
+ "krb4", AUTH_KRB4, CM_INV,
+ "krb5", AUTH_KRB5, CM_INV,
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+ "srp", AUTH_SRP, 0,
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ "ssl", AUTH_SSL, 0,
+ "tls", AUTH_TLS, 0,
+#endif /* CK_SSL */
+ "", 0, 0
+};
+static int nsetauth = sizeof(setauth)/sizeof(struct keytab) - 1;
+#ifdef CK_KERBEROS
+extern char * krb5_d_principal; /* Default principal */
+extern char * krb5_d_instance;
+extern char * krb5_d_realm; /* Default realm */
+extern char * krb5_d_cc; /* Default credentials cache */
+extern char * krb5_d_srv; /* Default service name */
+extern int krb5_d_lifetime; /* Default lifetime */
+extern int krb5_d_forwardable;
+extern int krb5_d_proxiable;
+extern int krb5_d_renewable;
+extern int krb5_autoget;
+extern int krb5_autodel;
+extern int krb5_d_getk4;
+extern int krb5_checkaddrs; /* Check TGT Addrs */
+extern int krb5_d_no_addresses;
+extern char * krb5_d_addrs[];
+extern char * k5_keytab; /* Keytab file */
+
+extern struct krb4_init_data krb4_init;
+extern char * krb4_d_principal; /* Default principal */
+extern char * krb4_d_realm; /* Default realm */
+extern char * krb4_d_srv; /* Default service name */
+extern int krb4_d_lifetime; /* Default lifetime */
+extern int krb4_d_preauth;
+extern char * krb4_d_instance;
+extern int krb4_autoget;
+extern int krb4_autodel;
+extern int krb4_checkaddrs; /* Check TGT Addrs */
+extern char * k4_keytab; /* Keytab file */
+#ifdef KRB4
+extern int k4debug;
+#endif /* KRB4 */
+static struct keytab krbver[] = {
+ "4", 4, 0,
+ "5", 5, 0,
+ "iv", 4, CM_INV,
+ "v", 5, CM_INV
+};
+static int nkrbver = sizeof(krbver)/sizeof(struct keytab);
+
+static struct keytab kdestab[] = {
+ "never", KRB_DEL_NO, 0,
+ "no", KRB_DEL_NO, CM_INV,
+ "on-close", KRB_DEL_CL, 0,
+ "on-exit", KRB_DEL_EX, 0
+};
+static int nkdestab = sizeof(kdestab)/sizeof(struct keytab);
+
+static struct keytab k4tab[] = {
+ "autodel", XYKRBDEL, CM_INV,
+ "autodestroy", XYKRBDEL, 0,
+ "autoget", XYKRBGET, 0,
+ "check-address", XYKRBADR, 0,
+ "debug", XYKRBDBG, CM_INV,
+ "instance", XYKRBINS, 0,
+ "keytab", XYKRBKTB, 0,
+ "lifetime", XYKRBLIF, 0,
+ "preauth", XYKRBPRE, 0,
+ "principal", XYKRBPR, 0,
+ "prompt", XYKRBPRM, 0,
+ "realm", XYKRBRL, 0,
+ "service-name", XYKRBSRV, 0
+};
+static int nk4tab = sizeof(k4tab)/sizeof(struct keytab);
+
+static struct keytab k5tab[] = {
+ "addresses", XYKRBADD, 0,
+ "autodelete", XYKRBDEL, CM_INV,
+ "autodestroy", XYKRBDEL, 0,
+ "autoget", XYKRBGET, 0,
+ "cc", XYKRBCC, CM_INV,
+ "check-address", XYKRBADR, 0,
+ "credentials-cache", XYKRBCC, 0,
+ "forwardable", XYKRBFWD, 0,
+ "get-k4-tgt", XYKRBK5K4,0,
+ "instance", XYKRBINS, 0,
+ "keytab", XYKRBKTB, 0,
+ "lifetime", XYKRBLIF, 0,
+ "no-addresses", XYKRBNAD, 0,
+ "principal", XYKRBPR, 0,
+ "prompt", XYKRBPRM, 0,
+ "proxiable", XYKRBPRX, 0,
+ "realm", XYKRBRL, 0,
+ "renewable", XYKRBRNW, 0,
+ "service-name", XYKRBSRV, 0
+};
+static int nk5tab = sizeof(k5tab)/sizeof(struct keytab);
+
+#define KRB_PW_PRM 1
+#define KRB_PR_PRM 2
+
+static struct keytab krbprmtab[] = {
+ "password", KRB_PW_PRM, 0,
+ "principal", KRB_PR_PRM, 0
+};
+
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+static struct keytab srptab[] = {
+ "prompt", XYSRPPRM, 0
+};
+static int nsrptab = sizeof(srptab)/sizeof(struct keytab);
+#define SRP_PW_PRM 1
+
+static struct keytab srpprmtab[] = {
+ "password", SRP_PW_PRM, 0
+};
+#endif /* CK_SRP */
+#ifdef CK_SSL
+static struct keytab ssltab[] = {
+ "certs-ok", XYSSLCOK, CM_INV,
+ "cipher-list", XYSSLCL, 0,
+ "crl-dir", XYSSLCRLD, 0,
+ "crl-file", XYSSLCRL, 0,
+ "debug", XYSSLDBG, 0,
+ "dh-key-file", XYSSLDKFL, CM_INV,
+ "dh-param-file", XYSSLDPFL, 0,
+ "dsa-cert-chain-file", XYSSLDCCF, 0,
+ "dsa-cert-file", XYSSLDCFL, 0,
+ "dsa-key-file", XYSSLDKFL, 0,
+ "dummy", XYSSLDUM, CM_INV,
+ "only", XYSSLON, CM_INV,
+ "random-file", XYSSLRND, 0,
+ "rsa-cert-chain-file", XYSSLRCCF, 0,
+ "rsa-cert-file", XYSSLRCFL, 0,
+ "rsa-key-file", XYSSLRKFL, 0,
+ "verbose", XYSSLVRB, 0,
+ "verify", XYSSLVRF, 0,
+ "verify-dir", XYSSLVRFD, 0,
+ "verify-file", XYSSLVRFF, 0
+};
+static int nssltab = sizeof(ssltab)/sizeof(struct keytab);
+static struct keytab sslvertab[] = {
+ "fail-if-no-peer-cert", SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0,
+ "no", SSL_VERIFY_NONE, 0,
+ "none", SSL_VERIFY_NONE, CM_INV,
+ "off", SSL_VERIFY_NONE, CM_INV,
+ "on", SSL_VERIFY_PEER, CM_INV,
+ "peer-cert", SSL_VERIFY_PEER, 0
+};
+static int nsslvertab = sizeof(sslvertab)/sizeof(struct keytab);
+#endif /* CK_SSL */
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+int cx_type = CX_AUTO;
+extern int sl_cx_type;
+#endif /* CK_ENCRYPTION */
+extern char *tcp_address;
+#ifndef NOHTTP
+extern char * tcp_http_proxy;
+extern char * tcp_http_proxy_user;
+extern char * tcp_http_proxy_pwd;
+extern char * tcp_http_proxy_agent;
+#endif /* NOHTTP */
+#ifdef NT
+#ifdef CK_SOCKS
+extern char *tcp_socks_svr;
+extern char *tcp_socks_user;
+#ifdef CK_SOCKS_NS
+extern char *tcp_socks_ns;
+#endif /* CK_SOCKS_NS */
+#endif /* CK_SOCKS */
+#endif /* NT */
+
+#define UPW_USER 1
+#define UPW_PASS 2
+#define UPW_AGENT 3
+
+static struct keytab userpass[] = {
+ { "/agent", UPW_AGENT, CM_ARG },
+ { "/password", UPW_PASS, CM_ARG },
+ { "/user", UPW_USER, CM_ARG },
+};
+static int nuserpass = sizeof(userpass)/sizeof(struct keytab);
+
+static struct keytab tnnegtab[] = { /* TELNET NEGOTIATION table */
+ "accepted", TN_NG_AC, 0,
+ "refused", TN_NG_RF, 0,
+ "req", TN_NG_RQ, CM_INV|CM_ABR,
+ "requ", TN_NG_RQ, CM_INV|CM_ABR,
+ "reque", TN_NG_RQ, CM_INV|CM_ABR,
+ "reques", TN_NG_RQ, CM_INV|CM_ABR,
+ "request", TN_NG_RQ, CM_INV|CM_ABR,
+ "requeste", TN_NG_RQ, CM_INV|CM_ABR,
+ "requested", TN_NG_RQ, 0,
+ "required", TN_NG_MU, 0
+};
+static int ntnnegtab = sizeof(tnnegtab)/sizeof(struct keytab);
+
+#ifdef CK_ENCRYPTION
+static struct keytab typkwd[] = {
+ "/type", 0, CM_ARG
+};
+
+static struct keytab tnenctab[] = { /* TELNET ENCRYPTION table */
+ "accepted", TN_NG_AC, CM_INV,
+ "refused", TN_NG_RF, CM_INV,
+ "req", TN_NG_RQ, CM_INV|CM_ABR,
+ "requ", TN_NG_RQ, CM_INV|CM_ABR,
+ "reque", TN_NG_RQ, CM_INV|CM_ABR,
+ "reques", TN_NG_RQ, CM_INV|CM_ABR,
+ "request", TN_NG_RQ, CM_INV|CM_ABR,
+ "requeste", TN_NG_RQ, CM_INV|CM_ABR,
+ "requested", TN_NG_RQ, CM_INV,
+ "required", TN_NG_MU, CM_INV,
+ "start", TN_EN_START, CM_INV,
+ "stop", TN_EN_STOP, CM_INV,
+ "type", TN_EN_TYP, 0
+};
+static int ntnenc = sizeof(tnenctab)/sizeof(struct keytab) ;
+#endif /* CK_ENCRYPTION */
+
+#ifdef CK_FORWARD_X
+static struct keytab tnfwdxtab[] = { /* TELNET FORWARD-X table */
+ "no-encryption", 1, CM_INV,
+ "xauthority-file", 0, 0
+};
+static int ntnfwdx = sizeof(tnfwdxtab)/sizeof(struct keytab) ;
+#endif /* CK_FORWARD_X */
+
+static struct keytab tnbugtab[] = { /* TELNET BUG table */
+ "auth-krb5-des", 4, 0,
+ "binary-me-means-u-too", 0, 0,
+ "binary-u-means-me-too", 1, 0,
+ "infinite-loop-check", 2, 0,
+ "sb-implies-will-do", 3, 0
+};
+
+#ifdef CK_ENVIRONMENT
+static struct keytab tnenvtab[] = { /* TELNET ENVIRONMENT table */
+ "acct", TN_ENV_ACCT, 0,
+ "display", TN_ENV_DISP, 0,
+ "job", TN_ENV_JOB, 0,
+ "location", TN_ENV_LOC, 0,
+ "off", TN_ENV_OFF, CM_INV,
+ "on", TN_ENV_ON, CM_INV,
+ "printer", TN_ENV_PRNT, 0,
+ "systemtype",TN_ENV_SYS, 0,
+ "user", TN_ENV_USR, 0,
+ "uservar", TN_ENV_UVAR, 0,
+ "", 0, 0
+};
+static int ntnenv = sizeof(tnenvtab)/sizeof(struct keytab) - 1;
+#endif /* CK_ENVIRONMENT */
+
+#ifdef CK_AUTHENTICATION
+static struct keytab tnauthtab[] = { /* TELNET AUTHENTICATION table */
+ "accepted", TN_NG_AC, CM_INV,
+ "encrypt-flag", TN_AU_ENC, 0,
+ "forwarding", TN_AU_FWD, 0,
+ "how-flag", TN_AU_HOW, 0,
+ "refused", TN_NG_RF, CM_INV,
+ "req", TN_NG_RQ, CM_INV|CM_ABR,
+ "requ", TN_NG_RQ, CM_INV|CM_ABR,
+ "reque", TN_NG_RQ, CM_INV|CM_ABR,
+ "reques", TN_NG_RQ, CM_INV|CM_ABR,
+ "request", TN_NG_RQ, CM_INV|CM_ABR,
+ "requeste", TN_NG_RQ, CM_INV|CM_ABR,
+ "requested", TN_NG_RQ, CM_INV,
+ "required", TN_NG_MU, CM_INV,
+ "type", TN_AU_TYP, 0
+};
+static int ntnauth = sizeof(tnauthtab)/sizeof(struct keytab) ;
+
+struct keytab autyptab[] = { /* TELNET AUTHENTICATION TYPE table */
+ "automatic", AUTH_AUTO, 0,
+#ifdef CK_KERBEROS
+ "k4", AUTH_KRB4, CM_INV,
+ "k5", AUTH_KRB5, CM_INV,
+ "kerberos4", AUTH_KRB4, 0,
+ "kerberos5", AUTH_KRB5, 0,
+ "kerberos_iv",AUTH_KRB4, CM_INV,
+ "kerberos_v", AUTH_KRB5, CM_INV,
+ "krb4", AUTH_KRB4, CM_INV,
+ "krb5", AUTH_KRB5, CM_INV,
+#endif /* CK_KERBEROS */
+ "none", AUTH_NONE, 0,
+#ifdef NT
+ "ntlm", AUTH_NTLM, 0,
+#endif /* NT */
+#ifdef CK_SRP
+ "srp", AUTH_SRP, 0,
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ "ssl", AUTH_SSL, 0,
+#endif /* CK_SSL */
+ "", 0, 0
+};
+int nautyp = sizeof(autyptab)/sizeof(struct keytab) - 1;
+
+struct keytab auhowtab[] = { /* TELNET AUTHENTICATION HOW table */
+ "any", TN_AUTH_HOW_ANY, 0,
+ "mutual", TN_AUTH_HOW_MUTUAL, 0,
+ "one-way", TN_AUTH_HOW_ONE_WAY, 0,
+ "", 0, 0
+};
+int nauhow = sizeof(auhowtab)/sizeof(struct keytab) - 1;
+
+struct keytab auenctab[] = { /* TELNET AUTHENTICATION ENCRYPT table */
+ "any", TN_AUTH_ENC_ANY, 0,
+ "none", TN_AUTH_ENC_NONE, 0,
+ "telopt", TN_AUTH_ENC_TELOPT, 0,
+#ifdef CK_SSL
+ "tls", TN_AUTH_ENC_TLS, 0,
+#endif /* CK_SSL */
+ "", 0, 0
+};
+int nauenc = sizeof(auenctab)/sizeof(struct keytab) - 1;
+#endif /* CK_AUTHENTICATION */
+
+#define TN_NL_BIN 3
+#define TN_NL_NVT 4
+static struct keytab tn_nlmtab[] = { /* TELNET NEWLINE-MODE table */
+ "binary-mode", TN_NL_BIN, 0, /* Binary mode */
+ "nvt", TN_NL_NVT, 0, /* NVT mode */
+ "off", TNL_CRNUL, CM_INV, /* CR-NUL (TELNET spec) */
+ "on", TNL_CRLF, CM_INV, /* CR-LF (TELNET spec) */
+ "raw", TNL_CR, CM_INV /* CR only (out of spec) */
+};
+static int ntn_nlm = (sizeof(tn_nlmtab) / sizeof(struct keytab));
+
+static struct keytab tnlmtab[] = { /* TELNET NEWLINE-MODE table */
+ "cr", TNL_CR, CM_INV, /* CR only (out of spec) */
+ "cr-lf", TNL_CRLF, CM_INV, /* CR-LF (TELNET spec) */
+ "cr-nul", TNL_CRNUL, CM_INV, /* CR-NUL (TELNET spec) */
+ "lf", TNL_LF, CM_INV, /* LF instead of CR-LF */
+ "off", TNL_CRNUL, 0, /* CR-NUL (TELNET spec) */
+ "on", TNL_CRLF, 0, /* CR-LF (TELNET spec) */
+ "raw", TNL_CR, 0 /* CR only (out of spec) */
+};
+static int ntnlm = (sizeof(tnlmtab) / sizeof(struct keytab));
+
+struct keytab tntab[] = {
+#ifdef CK_AUTHENTICATION
+ "authentication", CK_TN_AU, 0,
+#endif /* CK_AUTHENTICATION */
+ "b", CK_TN_BM, CM_INV|CM_ABR,
+ "bi", CK_TN_BM, CM_INV|CM_ABR,
+ "bin", CK_TN_BM, CM_INV|CM_ABR,
+ "bina", CK_TN_BM, CM_INV|CM_ABR,
+ "binar", CK_TN_BM, CM_INV|CM_ABR,
+ "binary", CK_TN_BM, CM_INV|CM_ABR,
+ "binary-", CK_TN_BM, CM_INV|CM_ABR,
+ "binary-mode", CK_TN_BM, CM_INV,
+ "binary-transfer-mode", CK_TN_XF, 0,
+ "binary-xfer-mode", CK_TN_XF, CM_INV,
+ "bug", CK_TN_BUG, 0,
+ "debug", CK_TN_DB, 0,
+ "delay-sb", CK_TN_DL, 0,
+ "echo", CK_TN_EC, 0,
+#ifdef CK_ENCRYPTION
+ "encryption", CK_TN_ENC, 0,
+#endif /* CK_ENCRYPTION */
+#ifdef CK_ENVIRONMENT
+ "environment", CK_TN_ENV, 0,
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_FORWARD_X
+ "forward-x", CK_TN_FX, 0,
+#endif /* CK_FORWARD_X */
+#ifdef IKS_OPTION
+ "kermit", CK_TN_IKS, CM_INV,
+#endif /* IKS_OPTION */
+#ifdef CK_SNDLOC
+ "location", CK_TN_LOC, 0,
+#endif /* CK_SNDLOC */
+#ifdef CK_NAWS
+ "naws", CK_TN_NAWS, CM_INV,
+#endif /* CK_NAWS */
+ "newline-mode", CK_TN_NL, 0,
+ "no-encrypt-during-xfer", CK_TN_NE, CM_INV,
+ "prompt-for-userid",CK_TN_PUID,0,
+ "remote-echo", CK_TN_RE, 0,
+#ifdef CK_SSL
+ "start-tls", CK_TN_TLS, CM_INV,
+#endif /* CK_SSL */
+#ifdef NT
+ "sfu-compatibility", CK_TN_SFU, 0,
+#else
+ "sfu-compatibility", CK_TN_SFU, CM_INV,
+#endif /* NT */
+ "terminal-type", CK_TN_TT, 0,
+ "wait-for-negotiations", CK_TN_WAIT, 0,
+#ifdef CK_ENVIRONMENT
+ "xdisplay-location",CK_TN_XD, CM_INV,
+#endif /* CK_ENVIRONMENT */
+ "", 0, 0
+};
+int ntn = (sizeof(tntab) / sizeof(struct keytab)) - 1;
+
+struct keytab tnopttab[] = {
+#ifdef CK_AUTHENTICATION
+ "authentication", CK_TN_AU, 0,
+#else
+ "authentication", CK_TN_AU, CM_INV,
+#endif /* CK_AUTHENTICATION */
+ "binary-mode", CK_TN_BM, 0,
+#ifdef TN_COMPORT
+ "c", CK_TN_CPC, CM_INV|CM_ABR,
+ "co", CK_TN_CPC, CM_INV|CM_ABR,
+ "com", CK_TN_CPC, CM_INV|CM_ABR,
+ "com-port-control",CK_TN_CPC, 0,
+ "comport-control", CK_TN_CPC, CM_INV,
+#else /* TN_COMPORT */
+ "com-port-control",CK_TN_CPC, CM_INV,
+ "comport-control", CK_TN_CPC, CM_INV,
+#endif /* TN_COMPORT */
+ "echo", CK_TN_EC, 0,
+#ifdef CK_ENCRYPTION
+ "encryption", CK_TN_ENC, 0,
+#else
+ "encryption", CK_TN_ENC, CM_INV,
+#endif /* CK_ENCRYPTION */
+#ifdef CK_FORWARD_X
+ "forward-x", CK_TN_FX, 0,
+#else /* CK_FORWARD_X */
+ "forward-x", CK_TN_FX, CM_INV,
+#endif /* CK_FORWARD_X */
+ "ibm-sak", CK_TN_SAK, CM_INV,
+#ifdef IKS_OPTION
+ "kermit", CK_TN_IKS, 0,
+#else
+ "kermit", CK_TN_IKS, CM_INV,
+#endif /* IKS_OPTION */
+ "lflow", CK_TN_FLW, CM_INV,
+ "logout", CK_TN_LOG, 0,
+#ifdef CK_NAWS
+ "naws", CK_TN_NAWS, 0,
+#else
+ "naws", CK_TN_NAWS, CM_INV,
+#endif /* CK_NAWS */
+#ifdef CK_ENVIRONMENT
+ "new-environment", CK_TN_ENV, 0,
+#else
+ "new-environment", CK_TN_ENV, CM_INV,
+#endif /* CK_ENVIRONMENT */
+ "pragma-heartbeat",CK_TN_PHR, CM_INV,
+ "pragma-logon", CK_TN_PLG, CM_INV,
+ "pragma-sspi", CK_TN_PSP, CM_INV,
+ "sak", CK_TN_SAK, CM_INV,
+#ifdef CK_SNDLOC
+ "send-location", CK_TN_LOC, 0,
+#else
+ "send-location", CK_TN_LOC, CM_INV,
+#endif /* CK_SNDLOC */
+ "sga", CK_TN_SGA, CM_INV|CM_ABR,
+#ifdef CK_SSL
+ "start-tls", CK_TN_TLS, 0,
+#else
+ "start-tls", CK_TN_TLS, CM_INV,
+#endif /* CK_SSL */
+ "suppress-go-aheads", CK_TN_SGA, 0,
+ "terminal-type", CK_TN_TT, 0,
+ "ttype", CK_TN_TT, CM_INV|CM_ABR,
+#ifdef CK_ENVIRONMENT
+ "xdisplay-location", CK_TN_XD, 0,
+#else
+ "xdisplay-location", CK_TN_XD, CM_INV,
+#endif /* CK_ENVIRONMENT */
+ "", 0, 0
+};
+int ntnopt = (sizeof(tnopttab) / sizeof(struct keytab)) - 1;
+
+struct keytab tnoptsw[] = {
+ "/client", CK_TN_CLIENT, 0,
+ "/server", CK_TN_SERVER, 0
+};
+int ntnoptsw = (sizeof(tnoptsw) / sizeof(struct keytab));
+#endif /* TNCODE */
+
+struct keytab ftrtab[] = { /* Feature table */
+#ifndef NOCSETS /* 0 = we have it, 1 = we don't */
+"character-sets", 0, 0,
+#else
+"character-sets", 1, 0,
+#endif /* NOCSETS */
+#ifndef NOCYRIL
+"cyrillic", 0, 0,
+#else
+"cyrillic", 1, 0,
+#endif /* NOCYRIL */
+
+#ifndef NOLOGDIAL
+"cx-log", 0, 0,
+#else
+"cx-log", 1, 0,
+#endif /* NOLOGDIAL */
+
+#ifndef NODEBUG
+"debug", 0, 0,
+#else
+"debug", 1, 0,
+#endif /* NODEBUG */
+
+#ifndef NODIAL
+"dial", 0, 0,
+#else
+"dial", 1, 0,
+#endif /* NODIAL */
+
+#ifdef DYNAMIC
+"dynamic-memory", 0, 0,
+#else
+"dynamic-memory", 1, 0,
+#endif /* DYNAMIC */
+
+#ifndef NOXFER
+"file-transfer", 0, 0,
+#else
+"file-transfer", 1, 0,
+#endif /* NOXFER */
+
+#ifdef XXFWD
+"forward", 0, 0,
+#else
+"forward", 1, 0,
+#endif /* XXFWD */
+
+#ifdef NEWFTP
+"ftp", 0, 0,
+#else
+"ftp", 1, 0,
+#endif /* NEWFTP */
+
+#ifdef CK_CURSES
+"fullscreen-display", 0, 0,
+#else
+"fullscreen-display", 1, 0,
+#endif /* CK_CURSES */
+#ifdef GREEK
+"greek", 0, 0,
+#else
+"greek", 1, 0,
+#endif /* GREEK */
+#ifdef HEBREW
+"hebrew", 0, 0,
+#else
+"hebrew", 1, 0,
+#endif /* HEBREW */
+#ifndef NOHELP
+"help", 0, 0,
+#else
+"help", 1, 0,
+#endif /* NOHELP */
+
+#ifndef NOIKSD
+"iksd", 0, 0,
+#else
+"iksd", 1, 0,
+#endif /* NOIKSD */
+
+#ifndef NOSPL
+"if-command", 0, 0,
+#else
+"if-command", 1, 0,
+#endif /* NOSPL */
+#ifndef NOJC
+#ifdef UNIX
+"job-control", 0, 0,
+#else
+"job-control", 1, 0,
+#endif /* UNIX */
+#else
+"job-control", 1, 0,
+#endif /* NOJC */
+#ifdef KANJI
+"kanji", 0, 0,
+#else
+"kanji", 1, 0,
+#endif /* KANJI */
+
+#ifndef NOXFER
+"kermit", 0, 0,
+#else
+"kermit", 1, 0,
+#endif /* NOXFER */
+
+#ifdef CK_KERBEROS
+"kerberos", 0, 0,
+#else
+"kerberos", 1, 0,
+#endif /* CK_KERBEROS */
+
+#ifndef NOCSETS
+"latin1", 0, 0,
+#else
+"latin1", 1, 0,
+#endif /* NOCSETS */
+#ifdef LATIN2
+"latin2", 0, 0,
+#else
+"latin2", 1, 0,
+#endif /* LATIN2 */
+
+#ifdef CKLEARN
+"learned-scripts", 0, 0,
+#else
+"learned-scripts", 1, 0,
+#endif /* CKLEARN */
+
+#ifndef NOLOCAL
+"making-connections", 0, 0,
+#else
+"making-connections", 1, 0,
+#endif /* NOLOCAL */
+
+#ifdef NETCONN
+"network", 0, 0,
+#else
+"network", 1, 0,
+#endif /* NETCONN */
+
+#ifdef NT
+#ifdef CK_AUTHENTICATION
+"ntlm", 1, 0,
+#else /* CK_AUTHENTICATION */
+"ntlm", 0, 0,
+#endif /* CK_AUTHENTICATION */
+#else /* NT */
+"ntlm", 0, 0,
+#endif /* NT */
+
+#ifdef PIPESEND
+"pipes", 0, 0,
+#else
+#ifdef NETCMD
+"pipes", 0, 0,
+#endif /* NETCMD */
+#endif /* PIPESEND */
+#ifndef PIPESEND
+#ifndef NETCMD
+"pipes", 1, 0,
+#endif /* PIPESEND */
+#endif /* NETCMD */
+
+#ifdef NETPTY
+"pty", 0, 0,
+#else
+"pty", 1, 0,
+#endif /* NETPTY */
+
+#ifndef NOPUSH
+"push", 0, 0,
+#else
+"push", 1, 0,
+#endif /* PUSH */
+
+#ifdef CK_REDIR
+"redirect", 0, 0,
+#else
+"redirect", 1, 0,
+#endif /* CK_REDIR */
+
+#ifdef CK_RTSCTS
+"rts/cts", 0, 0,
+#else
+"rts/cts", 1, 0,
+#endif /* RTS/CTS */
+
+#ifndef NOSCRIPT
+"script-command", 0, 0,
+#else
+"script-command", 1, 0,
+#endif /* NOSCRIPT */
+#ifndef NOSERVER
+"server-mode", 0, 0,
+#else
+"server-mode", 1, 0,
+#endif /* NOSERVER */
+
+#ifndef NOSEXP
+"sexpression", 0, 0,
+#else
+"sexpression", 1, 0,
+#endif /* NOSEXP */
+
+#ifdef SFTP_BUILTIN
+"sftp", 1, 0,
+#else
+"sftp", 0, 0,
+#endif /* SFTP_BUILTIN */
+
+#ifndef NOSHOW
+"show-command", 0, 0,
+#else
+"show-command", 1, 0,
+#endif /* NOSHOW */
+
+#ifdef CK_SRP
+"srp", 0, 0,
+#else
+"srp", 1, 0,
+#endif /* CK_SRP */
+
+#ifdef SSHBUILTIN
+"ssh", 0, 0,
+#else /* SSHBUILTIN */
+"ssh", 1, 0,
+#endif /* SSHBUILTIN */
+
+#ifdef CK_SSL
+"ssl/tls", 0, 0,
+#else
+"ssl/tls", 1, 0,
+#endif /* CK_SSL */
+
+#ifndef NOXMIT
+"transmit", 0, 0,
+#else
+"transmit", 1, 0,
+#endif /* NOXMIT */
+
+#ifdef UNICODE
+"unicode", 0, 0,
+#else
+"unicode", 1, 0,
+#endif /* UNICODE */
+
+#ifdef CK_XYZ
+"xyzmodem", 0, 0,
+#else
+"xyzmodem", 1, 0,
+#endif /* CK_XYZ */
+
+"", 0, 0
+};
+int nftr = (sizeof(ftrtab) / sizeof(struct keytab)) - 1;
+
+struct keytab desttab[] = { /* SET DESTINATION */
+#ifdef CALIBRATE
+ "calibrate", DEST_N, CM_INV,
+#endif /* CALIBRATE */
+ "disk", DEST_D, 0,
+#ifdef CALIBRATE
+ "nowhere", DEST_N, 0,
+#endif /* CALIBRATE */
+ "printer", DEST_P, 0,
+ "screen", DEST_S, 0
+};
+int ndests = (sizeof(desttab) / sizeof(struct keytab));
+
+#ifndef NOSPL /* Used only with script programming items... */
+
+#ifndef NOSERVER /* This is just to avoid some */
+#define CK_PARSDIR /* "statement not reached" */
+#else /* complaints... */
+#ifndef NODIAL
+#define CK_PARSDIR
+#endif /* NODIAL */
+#endif /* NOSERVER */
+
+/*
+ cx == 0 means dial directory
+ cx == 1 means network directory
+ cx == 2 means a directory path list
+*/
+static int
+parsdir(cx) int cx; {
+ int i, x, y, dd; /* Workers */
+ int nxdir;
+ char *s;
+ char ** xdir;
+ char *pp[MAXGETPATH]; /* Temporary name pointers */
+#ifdef ZFNQFP
+ struct zfnfp * fnp;
+#ifdef OS2
+ char * env;
+ char dirpath[4096];
+#else /* OS2 */
+ char dirpath[1024]; /* For fully qualified filenames */
+#endif /* OS2 */
+#endif /* ZFNQFP */
+
+ int max = 0; /* Maximum number of things to parse */
+ char c;
+
+#ifndef NODIAL
+ if (cx == 0) { /* Dialing */
+ nxdir = ndialdir;
+ xdir = dialdir;
+ max = MAXDDIR;
+ } else
+#ifdef NETCONN
+ if (cx == 1) { /* Network */
+ nxdir = nnetdir;
+ xdir = netdir;
+ max = MAXDDIR;
+ } else
+#endif /* NETCONN */
+#endif /* NODIAL */
+#ifndef NOSERVER
+ if (cx == 2) { /* GET path */
+ nxdir = ngetpath;
+ xdir = getpath;
+ max = MAXGETPATH;
+ } else /* Called with invalid function code */
+#endif /* NOSERVER */
+ return(-2);
+
+ for (i = 0; i < MAXGETPATH; i++) /* Init these. */
+ pp[i] = NULL;
+
+#ifdef CK_PARSDIR
+ dd = 0; /* Temporary name counter */
+ while (1) {
+ if (cx != 2) { /* Dialing or Network Directory */
+#ifdef OS2
+ int len;
+ char * appdata0 = NULL, * appdata1 = NULL;
+#ifdef NT
+ env = getenv("K95PHONES");
+ makestr(&appdata0,(char *)GetAppData(0));
+ makestr(&appdata1,(char *)GetAppData(1));
+#else /* NT */
+ env = getenv("K2PHONES");
+#endif /* NT */
+ if (!env)
+ env = getenv("K95PHONES");
+ if (!env)
+ env = "";
+
+ dirpath[0] = '\0';
+ len = strlen(env) + 2*strlen(startupdir) + 2*strlen(inidir)
+ + (appdata0?2*strlen(appdata0):0)
+ + (appdata1?2*strlen(appdata1):0)
+ + 2*strlen(zhome()) + 2*strlen(exedir) + 8*strlen("PHONES/")
+ + 12;
+ if (len < 4096) /* SAFE */
+ sprintf(dirpath,
+ "%s%s%s;%s%s;%s%s%s%s%s%s%s%s%s;%s%s;%s;%s%s",
+ /* Semicolon-separated path list */
+ env,
+ (env[0] && env[strlen(env)-1] == ';') ? "" : ";",
+ startupdir,
+ startupdir, "PHONES/",
+ appdata1 ? appdata1 : "",
+ appdata1 ? "Kermit 95;" : "",
+ appdata1 ? appdata1 : "",
+ appdata1 ? "Kermit 95/PHONES/;" : "",
+ appdata0 ? appdata0 : "",
+ appdata0 ? "Kermit 95;" : "",
+ appdata0 ? appdata0 : "",
+ appdata0 ? "Kermit 95/PHONES/;" : "",
+ inidir,
+ inidir, "PHONES/",
+ zhome(),
+ zhome(), "PHONES/",
+ exedir,
+ exedir, "PHONES/"
+ );
+#ifdef NT
+ makestr(&appdata0,NULL);
+ makestr(&appdata1,NULL);
+#endif /* NT */
+#else
+#ifdef UNIX
+ y = 1024;
+ s = dirpath;
+ zzstring("\\v(home)",&s,&y);
+#endif /* UNIX */
+#endif /* OS2 */
+ y = cmifip(
+ "Names of one or more directory files, separated by spaces",
+ "",&s,&x,0,
+#ifdef OS2ORUNIX
+ dirpath,
+#else
+ NULL,
+#endif /* OS2ORUNIX */
+ xxstring
+ );
+ } else { /* List of directory names */
+ x = 0;
+ y = cmdir("Directory name","",&s,xxstring);
+ }
+ if (y < 0) {
+ if (y == -3) { /* EOL or user typed <CR> */
+ if ((y = cmcfm()) < 0) return(y);
+ for (i = 0; i < max; i++) { /* Clear these */
+ if (i < nxdir && xdir[i]) {
+ free(xdir[i]);
+ }
+ xdir[i] = (i < dd) ? pp[i] : NULL;
+ }
+#ifndef NODIAL
+ if (cx == 0)
+ ndialdir = dd;
+#ifdef NETCONN
+ if (cx == 1)
+ nnetdir = dd;
+#endif /* NETCONN */
+#endif /* NODIAL */
+#ifndef NOSERVER
+ if (cx == 2)
+ ngetpath = dd;
+#endif /* NOSERVER */
+ return(success = 1);
+
+ } else { /* Parse error */
+ for (i = 0; i < dd; i++) { /* Free temp storage */
+ if (pp[i]) free(pp[i]); /* but don't change */
+ pp[i] = NULL; /* anything else */
+ }
+ return(y);
+ }
+ }
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+#ifdef CK_TMPDIR
+ if (cx == 2 && !isdir(s)) {
+ printf("?Not a directory - %s\n", s);
+ return(-9);
+ }
+#endif /* CK_TMPDIR */
+
+#ifdef ZFNQFP
+ if (cx < 2) {
+ if (!isabsolute(s)) { /* If not relative get full path */
+ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
+ if (fnp->fpath)
+ if ((int) strlen(fnp->fpath) > 0)
+ s = fnp->fpath;
+ }
+ }
+ }
+#endif /* ZFNQFP */
+ c = NUL;
+ x = strlen(s);
+ if (x > 0) /* Get last char */
+ c = s[x-1];
+ debug(F000,"parsdir s",s,c);
+ if ((pp[dd] = malloc(strlen(s)+2)) == NULL) {
+ printf("?Internal error - malloc\n");
+ for (i = 0; i < dd; i++) { /* Free temp storage */
+ if (pp[i]) free(pp[i]);
+ pp[i] = NULL;
+ }
+ return(-9);
+ } else { /* Have storage for name */
+ strcpy(pp[dd],s); /* Copy string into new storage */
+ debug(F111,"parsdir pp[dd] 1",pp[dd],dd);
+#ifndef NOXFER
+ if (cx == 2) { /* If we are parsing directories */
+ char dirsep[2];
+ extern int myindex; /* Append directory separator if */
+ extern struct sysdata sysidlist[]; /* it is missing... */
+ debug(F101,"parsdir myindex","",myindex);
+ if (myindex > -1)
+ if (sysidlist[myindex].sid_unixlike)
+ if (c != sysidlist[myindex].sid_dirsep) {
+ dirsep[0] = sysidlist[myindex].sid_dirsep;
+ dirsep[1] = NUL;
+ strcat(pp[dd], (char *) dirsep); /* safe */
+ }
+ }
+#endif /* NOXFER */
+ debug(F111,"parsdir pp[dd] 2",pp[dd],dd);
+ if (++dd > max) {
+ printf("?Too many directories - %d max\n", max);
+ for (i = 0; i < dd; i++) { /* Free temp storage */
+ if (pp[i]) free(pp[i]);
+ pp[i] = NULL;
+ }
+ }
+ }
+ }
+#endif /* CK_PARSDIR */
+}
+#endif /* NOSPL */
+
+#ifndef NOSERVER
+static int
+cklogin() {
+ int x;
+ char * s;
+ char username[LOGINLEN+1];
+ char password[LOGINLEN+1];
+ char account[LOGINLEN+1];
+ extern char * x_user, * x_passwd, * x_acct;
+ extern int x_login, x_logged;
+
+ username[0] = NUL;
+ password[0] = NUL;
+ account[0] = NUL;
+
+ x = cmfld("username", "", &s, xxstring);
+ if (x != -3) {
+ if (x < 0)
+ return(x);
+ if ((int)strlen(s) > LOGINLEN) {
+ printf("\"%s\" - too long, %d max\n", s, LOGINLEN);
+ return(-9);
+ }
+ ckstrncpy(username,s,LOGINLEN+1);
+ x = cmfld("password", "", &s, xxstring);
+ if (x != -3) {
+ if (x < 0)
+ return(x);
+ if ((int)strlen(s) > LOGINLEN) {
+ printf("\"%s\" - too long, %d max\n", s, LOGINLEN);
+ return(-9);
+ }
+ ckstrncpy(password,s,LOGINLEN+1);
+ x = cmfld("account", "", &s, xxstring);
+ if (x != -3) {
+ if (x < 0)
+ return(x);
+ if ((int)strlen(s) > LOGINLEN) {
+ printf("\"%s\" - too long, %d max\n", s, LOGINLEN);
+ return(-9);
+ }
+ ckstrncpy(account,s,LOGINLEN+1);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ }
+ }
+ }
+ makestr(&x_user,username);
+ makestr(&x_passwd,password);
+ makestr(&x_acct,account);
+ x_login = (x_user) ? 1 : 0;
+ x_logged = 0;
+ return(1);
+}
+#endif /* NOSERVER */
+
+#ifndef NOLOCAL
+static int
+setdcd() {
+ int x, y, z = 0;
+ if ((y = cmkey(crrtab,ncrr,"","automatic",xxstring)) < 0) return(y);
+ if (y == CAR_ON) {
+ x = cmnum("Carrier wait timeout, seconds","0",10,&z,xxstring);
+ if (x < 0) return(x);
+ }
+ if ((x = cmcfm()) < 0) return(x);
+ carrier = ttscarr(y);
+ cdtimo = z;
+ return(1);
+}
+#endif /* NOLOCAL */
+
+extern struct keytab yesno[];
+extern int nyesno;
+
+/* g e t y e s n o */
+
+static struct keytab q0yesno[] = { /* Yes/No/Quit keyword table */
+ "no", 0, 0,
+ "ok", 1, 0,
+ "yes", 1, 0
+};
+static int nq0yesno = (sizeof(q0yesno) / sizeof(struct keytab));
+
+static struct keytab q1yesno[] = { /* Yes/No/Quit keyword table */
+ "no", 0, 0,
+ "ok", 1, 0,
+ "quit", 2, 0,
+ "yes", 1, 0
+};
+static int nq1yesno = (sizeof(q1yesno) / sizeof(struct keytab));
+
+static struct keytab q2yesno[] = { /* Yes/No/Quit keyword table */
+ "go", 3, 0,
+ "no", 0, 0,
+ "ok", 1, 0,
+ "yes", 1, 0
+};
+static int nq2yesno = (sizeof(q2yesno) / sizeof(struct keytab));
+
+static struct keytab q3yesno[] = { /* Yes/No/Quit keyword table */
+ "go", 3, 0,
+ "no", 0, 0,
+ "ok", 1, 0,
+ "quit", 2, 0,
+ "yes", 1, 0
+};
+static int nq3yesno = (sizeof(q3yesno) / sizeof(struct keytab));
+
+
+/* Ask question, get yes/no answer */
+
+int
+getyesno(msg, flags) char * msg; int flags; {
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ int y, z;
+
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode, win95_popup, startflags;
+ int vmode_sav = vmode;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef CK_APC
+ if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
+ return(success = 0);
+ }
+#endif /* CK_APC */
+
+#ifndef NOLOCAL
+#ifdef OS2
+#ifdef COMMENT
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ )
+ return(popup_readyesno(vmode,NULL,msg,flags));
+#endif /* COMMENT */
+ if (vmode == VTERM) {
+ vmode = VCMD;
+ VscrnIsDirty(VTERM);
+ VscrnIsDirty(VCMD);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef VMS
+/*
+ In VMS, whenever a TAKE file or macro is active, we restore the
+ original console modes so Ctrl-C/Ctrl-Y can work. But here we
+ go interactive again, so we have to temporarily put them back.
+*/
+ if (!xcmdsrc)
+ concb((char)escape);
+#endif /* VMS */
+
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(msg); /* Make new prompt */
+ z = 0; /* Initialize answer to No. */
+ cmini(ckxech); /* Initialize parser. */
+ do {
+ prompt(NULL); /* Issue prompt. */
+ switch (flags) {
+ case 0: y = cmkey(q0yesno,nq0yesno,"","",NULL); break;
+ case 1: y = cmkey(q1yesno,nq1yesno,"","",NULL); break;
+ case 2: y = cmkey(q2yesno,nq2yesno,"","",NULL); break;
+ default: y = cmkey(q3yesno,nq3yesno,"","",NULL);
+ }
+ if (y < 0) {
+ if (y == -4) { /* EOF */
+ z = y;
+ break;
+ } else if (y == -3) /* No answer? */
+ printf(" Please respond; type '?' to see valid answers.\n");
+ cmini(ckxech);
+ } else {
+ z = y; /* Save answer */
+ y = cmcfm(); /* Get confirmation */
+ }
+ } while (y < 0); /* Continue till done */
+ cmsetp(psave); /* Restore real prompt */
+#ifdef VMS
+ if (cmdlvl > 0) /* In VMS and not at top level, */
+ conres(); /* restore console again. */
+#endif /* VMS */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode != vmode_sav) {
+ vmode = VTERM;
+ VscrnIsDirty(VCMD);
+ VscrnIsDirty(VTERM);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(z);
+}
+
+#ifdef KUI
+extern HWND hwndConsole;
+_PROTOTYP(int gui_txt_dialog,(char *,char *,int,char *,int,char *,int));
+_PROTOTYP(int gui_mtxt_dialog,(char *,int,struct txtbox []));
+_PROTOTYP(int gui_position,(int, int));
+_PROTOTYP(int gui_resize_mode,(int));
+_PROTOTYP(int gui_win_run_mode,(int));
+_PROTOTYP(int gui_saveas_dialog,(char *,char *, int, char *, char *, int));
+extern int gui_dialog;
+#endif /* KUI */
+
+/* u q _ o k -- User Query, get Yes/No or OK Cancel */
+/*
+ Call with:
+ preface: Explanatory text to print, or NULL.
+ prompt: Prompt.
+ mask: Bitmask for legal responses: 1 = OK or Yes; 2 = No or Cancel.
+ help: Help text (array of strings or NULL) [not used by parser].
+ dflt: Default response (1 or 2) [not used by parser].
+ Returns:
+ -1: Invalid argument(s).
+ 0: User said No or Cancel.
+ 1 User said Yes or OK.
+ Notes:
+ preface and prompt should not include final line terminator but may
+ include embedded ones. Help text is in case GUI dialog needs a Help
+ button; final element of help-string array is "". dflt is used by GUI
+ to highlight the default response button.
+*/
+int
+#ifdef CK_ANSIC
+uq_ok(char * preface, char * prompt, int mask,char ** help, int dflt)
+#else /* CK_ANSIC */
+uq_ok(preface,prompt,mask,help,dflt)
+ char * preface, * prompt, ** help;
+ int mask, dflt;
+#endif /* CK_ANSIC */
+/* uq_ok */ {
+ int rc, len;
+ char * text=NULL;
+
+ if (!prompt)
+ return(-1);
+
+ if ((mask & 3) == 1) { /* OK (GUI only) */
+#ifdef KUI
+ if ( gui_dialog ) {
+ /* This one is for popup help, alerts, etc */
+ if (preface) {
+ len = strlen(preface) + strlen(prompt) + 4;
+ text = (char *)malloc(len);
+ ckmakmsg(text,len,preface,"\n",prompt,NULL);
+ }
+ rc = MessageBox(hwndConsole,
+ text ? text : prompt,
+ prompt,
+ MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
+ ShowWindowAsync(hwndConsole,SW_SHOWNORMAL);
+ SetForegroundWindow(hwndConsole);
+ if (text)
+ free(text);
+ if (!rc)
+ return(-1);
+ else
+ return(1);
+ } else
+#endif /* KUI */
+ {
+ if (preface) /* Just display the text, if any */
+ printf("%s\n",preface);
+ if (prompt)
+ printf("%s\n",prompt);
+ return(1);
+ }
+ } else if ((mask & 3) == 3) { /* Yes/No or OK/Cancel */
+#ifdef KUI
+ if ( gui_dialog ) {
+ if (preface) {
+ len = strlen(preface) + strlen(prompt) + 4;
+ text = (char *)malloc(len);
+ ckmakmsg(text,len,preface,"\n",prompt,NULL);
+ }
+ rc = MessageBox(hwndConsole,
+ text ? text : prompt,
+ prompt,
+ MB_YESNO | MB_ICONINFORMATION | MB_TASKMODAL |
+ (dflt == 2 ? MB_DEFBUTTON2 : MB_DEFBUTTON1));
+ ShowWindowAsync(hwndConsole,SW_SHOWNORMAL);
+ SetForegroundWindow(hwndConsole);
+ if (text)
+ free(text);
+ if (!rc)
+ return(-1);
+ else if (rc == IDNO || rc == IDCANCEL)
+ return(0);
+ else
+ return(1);
+ } else
+#endif /* KUI */
+ {
+ if (preface)
+ printf("%s\n",preface);
+ return(getyesno(prompt,0));
+ }
+ } else {
+ printf("?Internal error: uq_ok()\n");
+ return(-1);
+ }
+}
+
+/* u q _ t x t -- User Query, get single text response */
+/*
+ Call with:
+ preface: Explanatory text to print, or NULL.
+ prompt: Prompt.
+ echo: 0 = don't echo; 1 = echo; 2 = echo with asterisks.
+ help: Help text (array of strings or NULL) [not used by parser].
+ buf: Pointer to result buffer.
+ buflen: Length of result buffer.
+ dflt: Default response text or NULL [not used by parser].
+ timer: Optional Timeout
+ Returns:
+ 0: User said No or Cancel.
+ 1 User said Yes or OK.
+ Notes:
+ preface, prompt, and help as for uq_ok().
+*/
+int
+#ifdef CK_ANSIC
+uq_txt(char * preface, char * prompt, int echo, char ** help, char * buf,
+ int buflen, char *dflt, int timer)
+#else /* CK_ANSIC */
+uq_txt(preface,prompt,echo,help,buf,buflen,dflt,timer)
+ char * preface, * prompt, ** help, * buf, * dflt;
+ int buflen, echo, timer;
+#endif /* CK_ANSIC */
+{
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode;
+ extern int startflags;
+ extern int win95_popup;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ int rc;
+
+ if (buflen < 1 || !buf)
+ return(0);
+#ifdef KUI
+ if ( gui_dialog ) {
+ rc = gui_txt_dialog(preface,prompt,echo,buf,buflen,dflt,timer);
+ if ( rc > -1 )
+ return(rc);
+ /* Otherwise, the dialog could not be created. Fallback to text mode */
+ }
+#endif /* KUI */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) {
+ debok = 0; /* Don't log */
+ if (echo == 1)
+ popup_readtext(vmode,preface,prompt,buf,buflen,0);
+ else
+ popup_readpass(vmode,preface,prompt,buf,buflen,0);
+ debok = 1;
+ return(1);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ if (preface)
+ printf("%s\n",preface);
+ if (echo == 1)
+ readtext(prompt,buf,buflen);
+ else
+ readpass(prompt,buf,buflen);
+ return(1); /* (no buttons in parser) */
+}
+
+/* u q _ m t x t -- User Query, get multiple text responses */
+/*
+ Call with:
+ preface: Explanatory text to print, or NULL.
+ help: Help text (array of strings or NULL) [not used by parser].
+ n: Number of responses wanted.
+ field: Array of struct txtbox, one element per field, see ckuusr.h.
+ Returns:
+ 0: User said No or Cancel.
+ 1 User said Yes or OK.
+ Notes:
+ preface and help as for uq_ok().
+*/
+int
+#ifdef CK_ANSIC
+uq_mtxt(char * preface,char **help, int n, struct txtbox field[])
+#else /* CK_ANSIC */
+uq_mtxt(preface,help,n,field)
+ char * preface; char ** help; int n; struct txtbox field[];
+#endif /* CK_ANSIC */
+{
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode;
+ extern int startflags;
+ extern int win95_popup;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ int i, rc;
+
+ if (n < 1 || !field)
+ return(0);
+#ifdef KUI
+ if ( gui_dialog ) {
+ rc = gui_mtxt_dialog(preface, n, field);
+ if ( rc > -1 )
+ return(rc);
+ /* Otherwise, the dialog could not be created. Fallback to text mode */
+ }
+#endif /* KUI */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) {
+ debok = 0; /* Don't log */
+ for (i = 0; i < n; i++) {
+ if (field[i].t_echo == 1)
+ popup_readtext(vmode,preface,field[i].t_lbl,field[i].t_buf,field[i].t_len,0);
+ else
+ popup_readpass(vmode,preface,field[i].t_lbl,field[i].t_buf,field[i].t_len,0);
+ }
+ debok = 1;
+ return(1);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ if (preface)
+ printf("%s\n",preface);
+ for (i = 0; i < n; i++) {
+ if (field[i].t_echo == 1)
+ readtext(field[i].t_lbl,field[i].t_buf,field[i].t_len);
+ else
+ readpass(field[i].t_lbl,field[i].t_buf,field[i].t_len);
+ }
+ return(1);
+}
+
+/* u q _ f i l e -- User Query, get file or directory name */
+/*
+ Call with:
+ preface: Explanatory text to print, or NULL.
+ prompt: Prompt string.
+ fc: Function code:
+ 1 = input (existing) file
+ 2 = existing directory
+ 3 = create new output file
+ 4 = output file allowing append access
+ help: Help text (array of strings or NULL) [not used by parser].
+ dflt: Default response.
+ result: Pointer to result buffer.
+ rlength: Length of result buffer.
+
+ Returns:
+ -1: Invalid argument, result too long, or other error.
+ 0: User Canceled.
+ 1: OK, with file/pathname copied to result buffer.
+ 2: Like 1, but for output file that is to be appended to.
+
+ Notes:
+ 1. preface and prompt should not include final line terminator but may
+ include embedded ones. Help text is in case GUI dialog needs a Help
+ button; final element of help-string array is "".
+
+ 2. The default might be a filename, a directory name, a relative
+ pathname, or an absolute pathname. This routine must convert it into
+ into a fully qualified (absolute) pathname so the user knows exactly
+ where the file is to be found or stored. In addition, the Windows
+ version of this routine must separate the directory part from the
+ name part, so it can display the given directory in the file dialog,
+ and put name in the filename box to be edited, replaced, or
+ accepted.
+
+ 3. When called with FC 4, the Windows version should include "New" and
+ "Append" buttons in the dialog. so the user can say whether the file
+ should overwrite any file of the same name, or be appended to it.
+*/
+
+int
+#ifdef CK_ANSIC
+uq_file(char * preface, char * fprompt, int fc, char ** help,
+ char * dflt, char * result, int rlength)
+#else /* CK_ANSIC */
+uq_file(preface,fprompt,fc,help,dflt,result,rlength)
+ char * preface, * fprompt, ** help, * dflt, * result;
+ int fc, rlength;
+#endif /* CK_ANSIC */
+/* uq_file */ {
+
+ int rc = -1, x, y, z;
+ char * s, * p, * fullpath;
+ char filebuf[CKMAXPATH+1];
+
+#ifdef CK_RECALL
+ extern int on_recall;
+#endif /* CK_RECALL */
+
+#ifdef KUI
+ if ( gui_dialog ) {
+ rc = gui_saveas_dialog(preface,fprompt,fc,dflt,result,rlength);
+ return rc;
+ }
+#endif /* KUI */
+
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+
+ if (preface) /* If prefatory text given... */
+ printf("%s\n",preface); /* display it. */
+
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+
+ /* We get the full pathname of the proposed output file just so */
+ /* we can show it to the user but we don't use it ourselves. */
+
+ p = NULL; /* Build new prompt */
+ if (!dflt) dflt = "";
+ if (*dflt) /* Have default filename */
+ zfnqfp(dflt,CKMAXPATH+1,filebuf); /* Get full path */
+ else
+ ckmakmsg(filebuf,CKMAXPATH+1,zgtdir(),"newfile",NULL,NULL);
+ fullpath = filebuf;
+ x = strlen(fullpath);
+
+ /* If no prompt given, build one that shows the proposed full pathname. */
+
+ if (!fprompt) fprompt = "";
+ if (!*fprompt) fprompt = x ? " Filename" : " Filename: ";
+ y = strlen(fprompt);
+ if (x > 0) { /* Have default pathname? */
+ p = (char *)malloc(x + y + 7); /* Get temp storage */
+ if (p) { /* Build prompt */
+ ckmakmsg(p,x+y+7,fprompt," [",fullpath,"]: ");
+ fprompt = p;
+ }
+ }
+ cmsetp(fprompt); /* Make new prompt */
+ if (p) free(p); /* Free temp storage */
+ cmini(ckxech); /* Initialize parser. */
+ x = -1;
+ do {
+ prompt(NULL); /* Issue prompt. */
+ switch (fc) { /* Parse depends on function code */
+ case 1: /* Input file */
+ x = cmifi("Name of existing file",dflt,&s,&y,xxstring);
+ rc = 1;
+ break;
+ case 2: /* Directory */
+ x = cmdir("Directory name",dflt,&s,xxstring);
+ rc = 1;
+ break;
+ case 3: /* New output file */
+ /* Fall thru... */
+ case 4: /* Output file - Append allowed */
+ x = cmofi("Output file specification",dflt,&s,xxstring);
+ rc = (fc == 4) ? 1 : 2;
+ break;
+ default: /* Bad function code */
+ goto x_uq_file;
+ }
+ if (x < 0) { /* Parse error */
+ filebuf[0] = NUL;
+ if (x == -4) { /* EOF */
+ break;
+ } else if (x == -3) /* No answer? */
+ printf(fc == 2 ?
+ " Please enter a directory name.\n" :
+ " Please enter a filename.\n"
+ );
+ cmini(ckxech);
+ } else {
+ z = strlen(s);
+ if (z > rlength || ckstrncpy(filebuf,brstrip(s),CKMAXPATH+1) < z) {
+ printf("?Name too long\n");
+ x = -9;
+ } else
+ x = cmcfm(); /* Get confirmation */
+ }
+ if (fc == 1 && x > -1 && y > 0) {
+ printf("?Wildcards not allowed\n");
+ x = -9;
+ }
+ } while (x < 0); /* Continue till done */
+
+ x_uq_file:
+ if (x < 0)
+ rc = -1;
+
+ cmsetp(psave); /* Restore real prompt */
+
+ if (rc > 0)
+ ckstrncpy(result,filebuf,rlength);
+ return(rc);
+}
+
+
+#ifdef CK_PERMS
+#ifdef UNIX
+
+_PROTOTYP( int zsetperm, (char *, int));
+
+/* CHMOD command for UNIX only */
+
+#define CHM_DIR 0
+#define CHM_DOT 1
+#define CHM_FIL 2
+#define CHM_LIS 3
+#define CHM_NOL 4
+#define CHM_QUI 5
+#define CHM_REC 6
+#define CHM_VRB 7
+#define CHM_PAG 8
+#define CHM_NOP 9
+#define CHM_TYP 10
+#define CHM_SIM 11
+
+static struct keytab uchmodsw[] = {
+ "/directories", CHM_DIR, 0,
+ "/dotfiles", CHM_DOT, 0,
+ "/files", CHM_FIL, 0,
+ "/list", CHM_LIS, 0,
+ "/nolist", CHM_NOL, 0,
+ "/nopage", CHM_NOP, 0,
+ "/page", CHM_PAG, 0,
+ "/quiet", CHM_QUI, CM_INV,
+ "/recursive", CHM_REC, 0,
+ "/simulate", CHM_SIM, 0,
+ "/type", CHM_TYP, CM_ARG,
+ "/verbose", CHM_VRB, CM_INV,
+};
+static int nchmodsw = (sizeof(uchmodsw) / sizeof(struct keytab));
+
+int
+douchmod() {
+ extern int recursive, nscanfile, diractive;
+#ifdef CK_TTGWSIZ
+ extern int tt_rows, tt_cols;
+ int n = 0;
+#endif /* CK_TTGWSIZ */
+ int i, files = 1, t1 = 1, t2 = 0, x, y, z, verbose = 0, rc = 1, paging;
+ int xmode = -1, fs = 0, getval = 0, simulate = 0, wild = 0;
+ char c, * s;
+ struct FDB sw, nu;
+
+ if (xaskmore < 0) {
+#ifdef CK_TTGWSIZ
+ xaskmore = 1;
+#else
+ xaskmore = 0;
+#endif /* CK_TTGWSIZ */
+ }
+ paging = xaskmore;
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Octal file permission code, or switch",
+ "", /* default */
+ "", /* addtl string data */
+ nchmodsw, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ uchmodsw, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu,
+ _CMNUM, /* Number */
+ "", /* Help message */
+ "", /* Default */
+ "", /* N/A */
+ 8, /* Radix = 8 */
+ 0, /* N/A */
+ xxstring, /* Processing function */
+ NULL, /* N/A */
+ NULL /* Next */
+ );
+
+ while (1) {
+ if ((x = cmfdb(&sw)) < 0) {
+ if (x == -3) {
+ x = -9;
+ printf("?Filename required\n");
+ }
+ return(x);
+ }
+ if (cmresult.fcode != _CMKEY)
+ break;
+ c = cmgbrk();
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case CHM_DIR:
+ t1 = 1;
+ t2 = 1;
+ break;
+ case CHM_DOT:
+ matchdot = 1;
+ break;
+ case CHM_FIL:
+ t1 = 0;
+ t2 = 0;
+ break;
+ case CHM_LIS:
+ case CHM_VRB:
+ verbose = 1;
+ break;
+ case CHM_NOL:
+ case CHM_QUI:
+ verbose = 0;
+ break;
+ case CHM_REC:
+ recursive = 1;
+ break;
+ case CHM_PAG:
+ verbose = 1;
+ paging = 1;
+ break;
+ case CHM_NOP:
+ paging = 0;
+ break;
+ case CHM_SIM:
+ simulate = 1;
+ break;
+ case CHM_TYP: {
+ extern struct keytab txtbin[];
+ if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
+ return(x);
+ if (x == 2) { /* ALL */
+ xmode = -1;
+ } else { /* TEXT or BINARY only */
+ xmode = x;
+ fs = 1;
+ }
+ break;
+ }
+ }
+ }
+ z = cmresult.nresult;
+ x = cmifi2("File specification","",&s,&wild,t1,NULL,xxstring,t2);
+ if (x < 0) {
+ if (x == -3) {
+ printf("?A file specification is required\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef ZXREWIND
+ if (wild) files = zxrewind();
+#else
+ if (wild) files = nzxpand(s,0);
+#endif /* ZXREWIND */
+
+ if (paging > -1)
+ xaskmore = paging;
+
+#ifdef CK_TTGWSIZ
+ if (verbose && paging) {
+#ifdef OS2
+ ttgcwsz();
+#else /* OS2 */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+ }
+#endif /* CK_TTGWSIZ */
+
+ for (i = 0; i < files; i++) {
+ if (files == 1 && wild == 0) { /* For "chmod 777 ." */
+ ckstrncpy(line,s,LINBUFSIZ);
+ } else {
+ x = znext(line);
+ if (x < 1) {
+ if (i == 0) {
+ printf("?No files match - \"%s\"\n",line);
+ return(-9);
+ }
+ return(1);
+ }
+ }
+ if (fs) {
+#ifdef VMSORUNIX
+ /* If /TYPE:TEXT or BINARY given, skip directories and links */
+ /* since they are neither text nor binary. */
+ extern int zgfs_dir, zgfs_link;
+ zgetfs(line);
+ if (zgfs_dir || zgfs_link)
+ continue;
+#else
+ if (zchki(line) < 0)
+ continue;
+#endif /* VMSORUNIX */
+ /* Regular file, scan it */
+ switch (scanfile(line,&y,nscanfile)) {
+ case FT_BIN:
+ if (xmode != 1)
+ continue;
+ break;
+ case FT_TEXT:
+ case FT_7BIT:
+ case FT_8BIT:
+#ifdef UNICODE
+ case FT_UTF8:
+ case FT_UCS2:
+#endif /* UNICODE */
+ if (xmode != 0)
+ continue;
+ }
+ }
+ if (simulate) {
+#ifdef UNIX
+ extern int zchkod; /* Unidentified Flying */
+ int xx = zchkod; /* API Extension... */
+ zchkod = 1;
+#endif /* UNIX */
+ if (zchko(line) < 0)
+ printf("%s - Access denied\n",line);
+ else
+ printf("%s - OK\n",line);
+#ifdef UNIX
+ zchkod = xx;
+#endif /* UNIX */
+ } else {
+ if (zsetperm(line,z) < 1) {
+ if (verbose || files < 2) {
+ printf("%s: %s\n",line,ck_errstr());
+ }
+ rc = 0;
+ } else if (verbose) {
+ printf("%s %s\n",ziperm(line),line);
+ }
+ }
+#ifdef CK_TTGWSIZ
+ if (verbose && paging) { /* Pause at end of screen */
+ if (cmd_rows > 0 && cmd_cols > 0) {
+ if (++n > cmd_rows - 3) {
+ if (!askmore())
+ break;
+ else
+ n = 0;
+ }
+ }
+ }
+#endif /* CK_TTGWSIZ */
+
+ }
+ return(success = rc);
+}
+#endif /* UNIX */
+#endif /* CK_PERMS */
+
+#ifndef NOSPL /* S-Expressions */
+#ifndef NOSEXP
+
+struct keytab sexptab[] = {
+ "depth-limit", 1, 0,
+ "echo-result", 0, 0,
+ "truncate-all-results", 2
+};
+
+static int sexpmaxdep = 1000; /* Maximum depth */
+
+#define xxfloat(s,x) \
+((isdigit(*s)||(*s=='-')||(*s=='+')||(*s=='.')||(*s=='\040'))?isfloat(s,x):0)
+
+#define SX_ADD 1 /* Symbols for built-in operators */
+#define SX_SUB 2
+#define SX_MUL 3
+#define SX_DIV 4
+#define SX_POW 5
+#define SX_SET 6
+#define SX_MOD 7
+#define SX_EVA 8
+#define SX_EXP 9
+#define SX_AEQ 10
+#define SX_ALT 11
+#define SX_AGT 12
+#define SX_ALE 13
+#define SX_AGE 14
+#define SX_MIN 15
+#define SX_MAX 16
+#define SX_SQR 17
+#define SX_FLR 18
+#define SX_CEI 19
+#define SX_TRU 20
+#define SX_ABS 21
+#define SX_ROU 22
+#define SX_LET 23
+#define SX_LGN 24
+#define SX_LGX 25
+#define SX_FLO 26
+#define SX_IFC 27
+#define SX_NOT 28
+#define SX_NEQ 29
+#define SX_AND 30
+#define SX_LOR 31
+#define SX_SIN 32
+#define SX_COS 33
+#define SX_TAN 34
+#define SX_BWA 35
+#define SX_BWO 36
+#define SX_BWX 37
+#define SX_BWN 38
+#define SX_XOR 39
+#define SX_INC 40
+#define SX_DEC 41
+#define SX_QUO 42
+#define SX_STR 43
+
+/* Operator flags */
+
+#define SXF_PRE 256 /* Predicate */
+#define SXF_ONE 512 /* Requires one arg */
+#define SXF_TWO 1024 /* Requires two args or more */
+#define SXF_FLO 2048 /* Coerce to floating-point */
+
+/* Built-in constants */
+
+#define SXC_NIL 1 /* NIL */
+#define SXC_PI 2 /* PI */
+#define SXC_T 3 /* T */
+
+/*
+ This is an xlookup() table and so need not be in "alhabetical" order.
+ Therefore entries are arranged to minimize search for most common
+ operators.
+*/
+static struct keytab sexpops[] = { /* Built-in operators */
+ "setq", SX_SET, 0, /* Global assignment */
+ "+", SX_ADD, 0, /* Simple arithmetic */
+ "-", SX_SUB, 0,
+ "*", SX_MUL, 0,
+ "/", SX_DIV, SXF_TWO,
+ "^", SX_POW, SXF_TWO,
+
+ "if", SX_IFC, SXF_TWO, /* IF */
+ "let", SX_LET, 0, /* Local assignment */
+ "not", SX_NOT, SXF_ONE, /* NOT */
+ "mod", SX_MOD, SXF_TWO, /* Modulus */
+
+ "<", SX_ALT, SXF_PRE, /* Comparisons */
+ ">", SX_AGT, SXF_PRE,
+ "<=", SX_ALE, SXF_PRE,
+ "=", SX_AEQ, SXF_PRE,
+ ">=", SX_AGE, SXF_PRE,
+ "!=", SX_NEQ, SXF_PRE,
+
+ "++", SX_INC, SXF_ONE|SXF_TWO, /* Increment */
+ "--", SX_DEC, SXF_ONE|SXF_TWO, /* Decrement */
+
+ "**", SX_POW, SXF_TWO, /* Common synonyms */
+ "==", SX_AEQ, SXF_PRE,
+ "!", SX_NOT, SXF_ONE,
+ ".", SX_EVA, 0,
+
+ "and", SX_AND, 0, /* Logical operators */
+ "or", SX_LOR, 0,
+ "xor", SX_XOR, SXF_TWO,
+
+ "max", SX_MAX, SXF_ONE|SXF_TWO, /* Max and min */
+ "min", SX_MIN, SXF_ONE|SXF_TWO,
+
+ "%", SX_MOD, SXF_TWO, /* More synonyms */
+ "||", SX_LOR, 0,
+ "&&", SX_AND, 0,
+
+ "quote", SX_QUO, SXF_ONE,
+ "string", SX_STR, SXF_ONE,
+
+ "eval", SX_EVA, 0, /* Assorted commands */
+ "abs", SX_ABS, SXF_ONE,
+ "truncate",SX_TRU, SXF_ONE|SXF_FLO,
+ "round", SX_ROU, SXF_ONE|SXF_TWO|SXF_FLO,
+ "ceiling", SX_CEI, SXF_ONE|SXF_FLO,
+ "floor", SX_FLR, SXF_ONE|SXF_FLO,
+ "float", SX_FLO, SXF_ONE|SXF_FLO,
+
+#ifdef FNFLOAT
+ "sqrt", SX_SQR, SXF_ONE|SXF_FLO, /* Floating point functions */
+ "exp", SX_EXP, SXF_ONE|SXF_FLO,
+ "sin", SX_SIN, SXF_ONE|SXF_FLO,
+ "cos", SX_COS, SXF_ONE|SXF_FLO,
+ "tan", SX_TAN, SXF_ONE|SXF_FLO,
+ "log", SX_LGN, SXF_ONE|SXF_FLO,
+ "log10", SX_LGX, SXF_ONE|SXF_FLO,
+#endif /* FNFLOAT */
+
+ "#", SX_BWX, SXF_TWO, /* Bitwise operators */
+ "&", SX_BWA, 0,
+ "|", SX_BWO, 0,
+ "~", SX_BWN, SXF_ONE,
+ "", 0, 0 /* (end) */
+};
+static int nsexpops = (sizeof(sexpops) / sizeof(struct keytab)) - 1;
+
+static struct keytab sexpconsts[] = { /* Built-in constants */
+ "nil", SXC_NIL, 0, /* NIL (false) */
+ "pi", SXC_PI, 0, /* Pi (3.1415926...) */
+ "t", SXC_T, 0, /* T (true) */
+ "", 0, 0
+};
+static int nsexpconsts = (sizeof(sexpconsts) / sizeof(struct keytab)) - 1;
+
+int sexprc = 0; /* S-Expression error flag */
+int sexppv = -1; /* Predicate value */
+static int sexptrunc = 0; /* Flag to force all results to int */
+
+#define SXMLEN 64 /* Macro arg list initial length */
+#include <math.h> /* Floating-point functions */
+
+_PROTOTYP( char * fpformat, (CKFLOAT, int, int) );
+_PROTOTYP( CKFLOAT ckround, (CKFLOAT, int, char *, int) );
+
+extern char math_pi[]; /* Value of Pi */
+extern int sexpecho; /* SET SEXPRESSION ECHO value */
+extern char * sexpval; /* Last top-level S-Expression value */
+extern char * lastsexp; /* Last S-Expression */
+int sexprmax = 0; /* Longest result (for stats) */
+int sexpdmax = 0; /* Max depth reached (for stats) */
+int sexpdep = 0; /* dosexp() recursion depth */
+static int * sxrlen = NULL; /* Result stack string sizes */
+static char ** sxresult = NULL; /* Result stack */
+
+/* s h o s e x p -- Show S-Expression info */
+
+VOID
+shosexp() {
+ printf("\n");
+ printf(" sexpression echo-result: %s\n",showooa(sexpecho));
+ printf(" sexpression depth-limit: %d\n",sexpmaxdep);
+ printf("\n");
+ printf(" maximum depth reached: %d\n",sexpdmax);
+ printf(" longest result returned: %d\n",sexprmax);
+ printf("\n");
+ printf(" truncate all results: %s\n",showoff(sexptrunc));
+ printf("\n");
+ printf(" last sexpression: %s\n",lastsexp ? lastsexp : "(none)");
+ printf(" last value: %s\n",sexpval ? sexpval : "(none)");
+ printf("\n");
+}
+
+
+static char *
+sexpdebug(s) char * s; {
+ /* For debugging -- includes recursion depth in each debug entry */
+ static char buf[64];
+ ckmakmsg(buf,64,"dosexp[",ckitoa(sexpdep),"] ",s);
+ return((char *)buf);
+}
+
+/* d o s e x p -- S-Expression Reader */
+
+/* Returns value as string (empty, numeric, or non-numeric) */
+
+static char sxroundbuf[32]; /* For ROUND result */
+
+char *
+dosexp(s) char *s; { /* s = S-Expression */
+ extern struct mtab *mactab; /* Macro table */
+ extern int maclvl, nmac;
+ extern char *mrval[];
+ extern int makestrlen; /* (see makestr()) */
+ struct stringarray * q = NULL; /* cksplit() return type */
+ char * p[SEXPMAX+1], ** p2; /* List items (must be on stack) */
+ char * line = NULL; /* For building macro argument list */
+ int nosplit = 0;
+ int linelen = 0;
+ int linepos = 0;
+ int quote = 0; /* LISP quote flag */
+ char * s2; /* Workers */
+ int kw, kwflags, mx = 0, x = 0;
+ int not = 0, truncate = 0, builtin = 0;
+ int fpflag = 0, quit = 0, macro = 0;
+ CK_OFF_T result = 0, i, j, k, n = 0;
+ CKFLOAT fpj, fpresult = 0.0; /* Floating-point results */
+ int pflag = 0; /* Have predicate */
+ int presult = 0; /* Predicate result */
+ int mustfree = 0; /* If we malloc'd we must free */
+
+ sexppv = -1; /* Predicate value */
+ s2 = ""; /* Default return value */
+
+ debug(F111,sexpdebug("entry 1"),s,sexprc);
+
+ if (++sexpdep > sexpmaxdep) { /* Keep track of depth */
+ printf("?S-Expression depth limit exceeded: %d\n",sexpmaxdep);
+ sexprc++;
+ debug(F111,sexpdebug("max depth exceeded"),s,sexprc);
+ }
+ if (sexpdep > sexpdmax) /* For stats */
+ sexpdmax = sexpdep;
+
+ if (sexprc) /* Error, quit all levels */
+ goto xdosexp; /* Always goto common exit point */
+
+ debug(F111,sexpdebug("entry 2"),s,sexprc);
+
+ if (!s) s = ""; /* Null or empty arg */
+
+ while (*s == SP) s++; /* Strip leading spaces */
+ if (!*s) /* so empty result */
+ goto xdosexp;
+/*
+ Allocate result stack upon first use, or after it has been resized with
+ SET SEXP DEPTH-LIMIT.
+*/
+ if (!sxresult) {
+ sxresult = (char **)malloc(sexpmaxdep * sizeof(char *));
+ if (!sxresult) {
+ printf("?Memory allocation failure - \"%s\"\n", s);
+ sexprc++;
+ goto xdosexp;
+ }
+ sxrlen = (int *)malloc(sexpmaxdep * sizeof(int));
+ if (!sxrlen) {
+ printf("?Memory allocation failure - \"%s\"\n", s);
+ sexprc++;
+ goto xdosexp;
+ }
+ for (i = 0; i < sexpmaxdep; i++) {
+ sxresult[i] = NULL; /* Result pointers */
+ sxrlen[i] = 0; /* Buffer sizes */
+ }
+ }
+ s2 = s; /* s2 is the result pointer */
+ k = 0; /* Length accumulator */
+ if (s[0] == '(') { /* Starts with open paren? */
+ while (*s2++) k++; /* Get length */
+ if (s[k-1] == ')') { /* Strip outer parens if any */
+ s[k-1] = NUL;
+ s++;
+ k -= 2;
+ while (*s == SP) { /* Strip leading spaces from result */
+ s++;
+ k--;
+ }
+ while (k > 0 && s[k-1] == SP) { /* And trailing spaces. */
+ s[k-1] = NUL;
+ k--;
+ }
+ }
+ if (!*s) { /* If nothing remains */
+ s2 = ""; /* return empty result. */
+ goto xdosexp;
+ }
+ }
+ /* Break result up into "words" (an SEXP counts as a word) */
+
+ for (i = 0; i < SEXPMAX+1; i++ ) { /* Clear the operands */
+ p[i] = NULL;
+ }
+ if (!*(s+1) || !*(s+2)) { /* No need to call cksplit() */
+ n = 1; /* if it's one or two chars. */
+ p[1] = s; /* No need to malloc this either. */
+ nosplit = 1;
+ debug(F101,sexpdebug("nosplit"),"",n);
+ if (s[0] == '(') { /* () empty */
+ s2 = "";
+ goto xdosexp;
+ }
+ } else {
+ nosplit = 0;
+ q = cksplit(1,SEXPMAX,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",8,39,0);
+ if (!q)
+ goto xdosexp;
+ n = q->a_size; /* Number of items */
+ debug(F101,sexpdebug("split"),"",n);
+ if (n < 0 || n > SEXPMAX) { /* Check for too many */
+ printf("?Too many operands: max = %d\n",SEXPMAX);
+ sexprc++;
+ goto xdosexp;
+ }
+ if (n == 0) /* None, result is NULL, done. */
+ goto xdosexp;
+ if (n == 1 && s[0] == '(') { /* One but it's another SEXP */
+ s2 = dosexp(s);
+ goto xdosexp;
+ }
+ p2 = q->a_head; /* Point to result array. */
+ for (i = 1; i <= n; i++) { /* We must copy it because */
+ p[i] = NULL; /* recursive calls to dosexp() */
+ if (p2[i]) /* write over the same array */
+ makestr(&(p[i]),p2[i]);
+ }
+ if (s[0] == '(') { /* Operator is an S-Expression */
+ s2 = dosexp(p[1]); /* Replace it by its value */
+ makestr(&(p[1]),s2);
+ }
+ mustfree++; /* Remember to free it */
+ }
+ debug(F110,sexpdebug("head"),p[1],0);
+
+ if (n == 1 && p[1]) {
+ if (*(p[1]) == '\047') { /* Apostrophe = LISP quote character */
+ s2 = p[1];
+ goto xdosexp;
+ }
+ }
+/*
+ This section sidesteps xlookup() of the most common operators.
+ It's not necessary but it speeds up SEXP-heavy loops by about 10%.
+*/
+ kwflags = 0;
+ if (n > 0) { /* Look up the operator */
+ s2 = p[1]; /* Prelookup optimization... */
+ if (!s2)
+ s2 = "";
+ if (!*s2)
+ goto xdosexp;
+ kw = 0;
+ x = 0;
+ if (isdigit(*s2)) { /* Digit */
+ x = -2;
+
+ } else if (isalpha(*s2) && !*(s2+1)) { /* Single letter */
+ x = -1;
+
+ } else if (*s2 == 's' || *s2 == 'S') { /* SETQ */
+ s2++;
+ if (*s2 == 'e' || *s2 == 'E') {
+ s2++;
+ if (*s2 == 't' || *s2 == 'T') {
+ s2++;
+ if (*s2 == 'q' || *s2 == 'Q') {
+ if (!*(s2+1)) {
+ x = SX_SET;
+ kwflags = 0;
+ builtin = 1;
+ }
+ }
+ }
+ }
+ }
+ if (!x) {
+ if (!*(s2+1)) { /* Common single-character ops */
+ if (*s2 == '+') {
+ x = SX_ADD;
+ kwflags = 0;
+ builtin = 1;
+ } else if (*s2 == '-') {
+ x = SX_SUB;
+ kwflags = 0;
+ builtin = 1;
+ } else if (*s2 == '*') {
+ x = SX_MUL;
+ kwflags = 0;
+ builtin = 1;
+ } else if (*s2 == '/') {
+ x = SX_DIV;
+ kwflags = SXF_TWO;
+ builtin = 1;
+ }
+ }
+ if (!x) { /* None of the above, look it up */
+ x = xlookup(sexpops,p[1],nsexpops,&kw);
+ if (x > 0) {
+ kwflags = sexpops[kw].flgs;
+ builtin = 1;
+ }
+ }
+ }
+ }
+ /* If none of the above, check built-in constants */
+
+ if (x == -1) {
+ x = xlookup(sexpconsts,p[1],nsexpconsts,&kw);
+ if (x > 0) {
+ switch (x) {
+ case SXC_NIL:
+ s2 = "";
+ goto xdosexp;
+ case SXC_PI:
+ s2 = math_pi;
+ goto xdosexp;
+ case SXC_T:
+ s2 = "1";
+ goto xdosexp;
+ }
+ }
+ }
+ if (n == 1) { /* Not an expression */
+ if (builtin) { /* Built-in operand? */
+ switch (x) { /* Operators with default values */
+ case SX_EVA:
+ s2 = "";
+ goto xdosexp;
+ case SX_MUL: /* (*) */
+ s2 = sexpval ? sexpval : "1";
+ goto xdosexp;
+ case SX_AND: /* (AND) */
+ case SX_BWA: /* Bitwise (&) */
+ result++;
+ case SX_LOR: /* (OR) */
+ case SX_BWO: /* Bitwise (|) */
+ case SX_ADD: /* (+) */
+ case SX_SUB: /* (-) */
+ s2 = result ? "1" : "0";
+ goto xdosexp;
+ }
+
+ } else { /* Not a built-in operand */
+ char * p1;
+ p1 = p[1];
+ while (*p1 == SP) p1++;
+ if (!isalpha(*p1)) {
+ if (xxfloat(p1,0) > 0) { /* Is it a number? */
+ s2 = p1;
+ while (*s2 == '+') s2++;
+ } else if (*p1 == '(') { /* An S-Expression? */
+
+#ifdef COMMENT
+ s2 = dosexp(s2);
+#else
+ s2 = dosexp(p1);
+#endif /* COMMENT */
+ }
+ goto xdosexp;
+ } else if (x < 1) { /* Is it a variable? */
+ j = mxlook(mactab,p[1],nmac); /* Look it up */
+ debug(F111,sexpdebug("n==1 mxlook"),p[1],j);
+ s2 = (j > -1) ? mactab[j].mval : "";
+ if (!s2) s2 = "";
+ if (xxfloat(s2,0) > 0) /* Macro value is a number */
+ goto xdosexp;
+ if (j > -1) { /* It's a macro */
+ mx = j;
+ x = j; /* whose definition is not numeric */
+ if (*s2 == '(') { /* Is it an S-Expression? */
+ /* We have to allocate memory on the stack */
+ /* to call ourselves recursively on it */
+ /* otherwise we'll wipe out the macro definition */
+ char * s3 = NULL;
+ /* int k = 0; */
+ s3 = s2;
+ while (*s3++) k++;
+ s3 = (char *)malloc(k + 4);
+ if (s3) {
+ strcpy(s3,s2); /* SAFE */
+ s2 = dosexp(s3); /* Evaluate it */
+ free(s3);
+ } else {
+ printf("?Memory allocation failure - \"%s\"\n",s2);
+ sexprc++;
+ }
+ goto xdosexp;
+ }
+ if (*s2 == '\047') {
+ s2++;
+#ifdef COMMENT
+ /* Dumps core if petty optimization was taken */
+ makestr(&(p[1]),s2);
+#else
+ if (!nosplit && p[1]) free(p[1]);
+ p[1] = (char *)malloc((int)strlen(s2) + 1);
+#endif /* COMMENT */
+ s2 = p[1];
+ if (!s2) s2 = "";
+ if (*s2 == '(') {
+ if (s2[makestrlen-1] == ')') {
+ s2[makestrlen-1] = NUL;
+ s2++;
+ }
+ }
+ debug(F110,sexpdebug("'A"),s2,0);
+ goto xdosexp;
+ }
+ macro++; /* Not an S-Expression */
+ } else { /* Not found in macro table */
+ printf("?Not defined - \"%s\"\n", p[1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ }
+ }
+ } else if (x < 1 && !macro) { /* n > 1 and not a built-in operator */
+ x = mxlook(mactab,p[1],nmac); /* See if it's a macro */
+ debug(F111,sexpdebug("n!=1 mxlook"),p[1],x);
+ if (x < 0) {
+ printf("?Invalid operand - \"%s\"\n",p[1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ mx = x;
+ macro++;
+ }
+ if (builtin) { /* Built-in operator... */
+ if (kwflags) {
+ int flgs;
+ if ((flgs = (kwflags & (SXF_ONE|SXF_TWO)))) {
+ switch (flgs) {
+ case (SXF_ONE|SXF_TWO):
+ if (n < 2) {
+ printf("?Too few operands - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ }
+ break;
+ case SXF_TWO:
+ if (n < 3) {
+ printf("?Too few operands - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ }
+ break;
+ case SXF_ONE:
+ if (n != 2) {
+ printf("?Too %s operands - \"%s\"\n",
+ (n > 2) ? "many" : "few", s);
+ sexprc++;
+ goto xdosexp;
+ }
+ }
+ }
+ if (kwflags & SXF_PRE) { /* Predicate? */
+ if (n < 2) {
+ printf("?Too few operands - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ }
+ pflag = 1;
+ presult = 1;
+ }
+ if (kwflags & SXF_FLO) /* Operator requires floating point */
+ fpflag++; /* Force it */
+
+ if (x == SX_ROU) { /* ROUND can have 1 or 2 arguments */
+ if (n < 2 || n > 3) {
+ printf("?Too %s operands - \"%s\"\n",
+ (n > 3) ? "many" : "few", s);
+ sexprc++;
+ goto xdosexp;
+ }
+ }
+ if (x == SX_ROU) {
+ /* But they are not "cumulative" like other SEXP args */
+ /* So this case is handled specially */
+ char buf1[32], buf2[32];
+ float r;
+ char * s0, * s1;
+ char * q0, * q1;
+
+ s0 = p[2];
+ if (!s0) s0 = "";
+ if (!*s0) s0 = "0";
+ q0 = dosexp(s0);
+ ckstrncpy(buf1,q0,32);
+ q0 = buf1;
+
+ s1 = p[3];
+ if (!s1) s1 = "";
+ if (!*s1) s1 = "0";
+ q1 = dosexp(s1);
+ if (!q1) q1 = "";
+ if (!*q1) q1 = "0";
+ ckstrncpy(buf2,q1,32);
+ q1 = buf2;
+
+ r = ckround(atof(q0),(int)(atof(q1)),sxroundbuf,31);
+ s2 = sxroundbuf;
+ sexprc = 0;
+ goto xdosexp;
+ }
+ }
+ if (x == SX_SET || x == SX_LET || /* Assignment is special */
+ x == SX_INC || x == SX_DEC) {
+ int rc;
+ char c, * m, * s3;
+ if (n == 1) {
+ s2 = "";
+ goto xdosexp;
+ }
+ s2 = NULL;
+ for (i = 1; i < n; i += 2) { /* Loop thru operand pairs */
+ rc = 0;
+ s3 = p[i+1];
+ c = *s3;
+ debug(F110,sexpdebug("target p"),s3,0);
+
+ /* Make sure target doesn't have multiple words */
+ while (*s3) { if (*s3 < '!') { rc = 1; break; }; s3++; }
+ s3 = p[i+1];
+ if (rc) { /* If it does it must have been */
+ char * s4; /* an SEXP so evaluate it */
+ s3 = dosexp(s3);
+ s4 = s3;
+ rc = 0;
+ while (*s4) { if (*s4 < '!') { rc = 1; break; }; s4++; }
+ if (rc == 0) makestr(&(p[i+1]),s3);
+ }
+
+ /* And that it's not a number, etc. */
+ if (rc > 0 || isdigit(c) || c == '(') {
+ printf("?Invalid assignment - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ } else if (isalpha(c)) {
+ rc = xlookup(sexpconsts,s3,nsexpconsts,NULL);
+ if (rc > 0) {
+ printf("?Assignment to constant - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ }
+ }
+
+ /* If ++ or --, get current value of variable */
+ if (x == SX_INC || x == SX_DEC) {
+ int ok = 1;
+ char buf[32];
+ if (c == CMDQ) { /* A backslash variable */
+ int n = 32;
+ char * s = buf;
+ buf[0] = NUL;
+ if (zzstring(s3,&s,&n) < 0 || !buf[0])
+ ok = 0;
+ s2 = buf;
+ } else { /* A macro */
+ if ((k = mxlook(mactab,s3,nmac)) < 0)
+ ok = 0;
+ else
+ s2 = mactab[k].mval;
+ }
+ if (!ok) {
+ printf("?Not defined - \"%s\"\n",p[i+1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ if (!s2) s2 = "";
+ k = xxfloat(s2,0);
+ if (k < 1) {
+ printf("?Not numeric - \"%s\"\n",p[i+1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ while (*s2 == '+') s2++;
+ result = ckatofs(s2);
+ fpresult = floatval;
+ if (k > 1 || fpresult != result)
+ fpflag++;
+ }
+ if (n < i+2) { /* Variable with no value */
+ s2 = "";
+ if (x == SX_SET || x == SX_LET) {
+ delmac(p[i+1],1); /* Delete the variable */
+ break;
+ } else {
+ s2 = "1";
+ }
+ } else { /* Variable with value */
+ k = xxfloat(p[i+2],0); /* Is it a number? */
+ if (k > 0) {
+ s2 = p[i+2];
+ while (*s2 == '+') s2++;
+ } else {
+ s2 = dosexp(p[i+2]); /* Have value, evaluate it */
+ if (sexprc) goto xdosexp;
+ if (!s2) s2 = "";
+ if (!*s2 && (x == SX_INC || x == SX_DEC))
+ continue;
+ }
+ }
+ if (x == SX_INC || x == SX_DEC) {
+ k = xxfloat(s2,0);
+ if (k < 1) {
+ printf("?Not numeric - \"%s\"\n",s2);
+ sexprc++;
+ goto xdosexp;
+ }
+ while (*s2 == '+') s2++;
+ j = ckatofs(s2);
+ if (k > 1) {
+ fpj = floatval;
+ fpflag++;
+ } else {
+ fpj = (CKFLOAT)j;
+ }
+ if (x == SX_INC) {
+ result += j;
+ fpresult += fpj;
+ } else if (x == SX_DEC) {
+ result -= j;
+ fpresult -= fpj;
+ }
+#ifdef FNFLOAT
+ if (result != fpresult) fpflag++;
+#endif /* FNFLOAT */
+ s2 = (fpflag && !sexptrunc) ?
+ fpformat(fpresult,0,0) : ckfstoa(result);
+ }
+ if (x == SX_LET && cmdlvl > 0) /* LET makes var local */
+ addlocal(p[i+1]);
+ if ((rc = addmac(p[i+1],s2)) < 0) { /* Add the value */
+ switch (rc) {
+ case -3: m = "Array not declared"; break;
+ case -2: m = "Subscript out of range"; break;
+ case -4: m = "Out of memory"; break;
+ default: m = "Error creating variable";
+ }
+ printf("?%s - \"%s\"\n",m,s);
+ sexprc++;
+ goto xdosexp;
+ }
+ if (s2) result = ckatofs(s2);
+ }
+ goto xdosexp;
+ } else if (x == SX_IFC) { /* Conditional expression */
+ int true = 0;
+ if (n > 4) {
+ printf("?Too many operands: IF - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ }
+ s2 = dosexp(p[2]);
+ if (sexprc) goto xdosexp;
+ if (s2) {
+ j = ckatofs(s2);
+ if (xxfloat(s2,0) == 2) {
+ fpflag++;
+ fpresult = (CKFLOAT)result;
+ fpj = floatval;
+ } else {
+ fpj = atof(s2);
+ }
+ true = ((fpj != 0.0) ? 1 : 0);
+ }
+ if (!true && n < 4) {
+ s2 = NULL;
+ } else {
+ s2 = dosexp(true ? p[3] : p[4]);
+ if (sexprc) goto xdosexp;
+ j = s2 ? ckatofs(s2) : 0;
+ if (xxfloat(s2,0) == 2) {
+ fpflag++;
+ fpresult = (CKFLOAT)result;
+ fpj = floatval;
+ } else {
+ fpj = s2 ? atof(s2) : 0.0;
+ }
+ fpresult = fpj;
+ result = j;
+ }
+ goto xdosexp;
+ } else if (x == SX_QUO) {
+#ifndef COMMENT
+ int xx;
+ xx = strlen(p[2]);
+ p[3] = (char *)malloc(xx+4);
+ s2 = p[3];
+ ckmakmsg(p[3],xx+4,"'(",p[2],")",NULL);
+ n++;
+#else
+ s2 = p[2];
+#endif /* COMMENT */
+ goto xdosexp;
+ } else if (x == SX_STR) {
+ int xx;
+ s2 = dosexp(p[2]);
+ if (sexprc) goto xdosexp;
+ xx = strlen(s2);
+ p[3] = (char *)malloc(xx+4);
+ ckmakmsg(p[3],xx+4,"'(",s2,")",NULL);
+ s2 = p[3];
+ n++;
+ goto xdosexp;
+ }
+ }
+ /* Arithmetic operator or macro - Loop thru operands */
+
+ quit = 0; /* Short-circuit flag. */
+ if (macro && n > 1) { /* If operator is a macro */
+ if (!line) { /* allocate local buffer for */
+ line = (char *)malloc(SXMLEN); /* the evaluated argument list. */
+ if (!line) {
+ printf("?Memory allocation failure - \"%s\"\n",p[1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ linelen = SXMLEN;
+ /* debug(F101,"dosexp macro arg buffer","",linelen); */
+ }
+ linepos = 0;
+ line[linepos] = NUL;
+ }
+ for (i = 1; ((i < n) && !sexprc && !quit); i++) { /* Loop thru operands */
+ quote = 0;
+ s2 = p[i+1]; /* Get operand */
+ if (!s2) s2 = "";
+
+#ifdef COMMENT
+ if (*s2 == '\047') { /* Is it quoted? */
+ debug(F110,sexpdebug("'B"),s2,0);
+ s2++; /* Space past the quote */
+ quote++;
+ if (*s2 == '(') { /* Quoted S-Expression? */
+ char c4, * s4 = s2+1; /* Strip outer parens */
+ while ((c4 = *s4++)) {
+ if (c4 == ')' && !*s4) {
+ s2++;
+ *(s4-1) = NUL;
+ break;
+ }
+ }
+ }
+ debug(F110,sexpdebug("'C"),s2,0);
+
+ } else { /* Not quoted */
+ s2 = dosexp(p[i+1]); /* evaluate it */
+ if (sexprc) goto xdosexp;
+ if (!s2) s2 = "";
+ if (!macro && x == SX_EVA)
+ continue;
+ }
+#else
+ if (*s2 != '\047') { /* Is it quoted? */
+ s2 = dosexp(p[i+1]); /* No, evaluate it */
+ if (sexprc) goto xdosexp;
+ if (!s2) s2 = "";
+ if (!macro && x == SX_EVA)
+ continue;
+ }
+ if (*s2 == '\047') { /* Is result quoted? */
+ debug(F110,sexpdebug("'B"),s2,0);
+ s2++; /* Space past the quote */
+ quote++;
+ if (*s2 == '(') { /* Quoted S-Expression? */
+ char c4, * s4 = s2+1; /* Strip outer parens */
+ while ((c4 = *s4++)) {
+ if (c4 == ')' && !*s4) {
+ s2++;
+ *(s4-1) = NUL;
+ break;
+ }
+ }
+ }
+ debug(F110,sexpdebug("'C"),s2,0);
+ }
+#endif /* COMMENT */
+ if (macro) {
+ debug(F111,sexpdebug("macro arg"),s2,i);
+ if (!*s2) quote++;
+ if (!quote) {
+ register char c4, * s4 = s2;
+ while ((c4 = *s4++)) if (c4 == SP) { quote++; break; }
+ }
+ if (quote) line[linepos++] = '{';
+ while ((line[linepos++] = *s2++)) {
+ if (linepos > linelen - 3) {
+ char * tmp = NULL;
+ line[linepos] = NUL;
+ linelen += SXMLEN;
+ tmp = (char *) malloc(linelen);
+ if (!tmp) {
+ printf("?Memory re-allocation failure - \"%s...\"\n",
+ line);
+ sexprc++;
+ goto xdosexp;
+ }
+ strcpy(tmp,line);
+ free(line);
+ line = tmp;
+ }
+ }
+ linepos--; /* Back up over NUL */
+ if (quote)
+ line[linepos++] = '}'; /* End quote group */
+ line[linepos++] = SP; /* add a space */
+ line[linepos] = NUL; /* and a NUL */
+ continue;
+ }
+ if (!quote) { /* Built-in operator... */
+ s2 = dosexp(s2);
+ if (sexprc) goto xdosexp;
+ if (!s2) s2 = "";
+ }
+ if (x == SX_EVA)
+ continue;
+
+ if (!*s2) {
+ /* An empty value is not a legal number */
+ /* but it is a legal truth value */
+ if (x != SX_AND && x != SX_LOR && x != SX_NOT) {
+ printf("?Not Numeric - \"%s\"\n",p[i+1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ j = 0;
+ fpj = 0.0;
+ } else {
+ j = ckatofs(s2);
+ /* Switch to floating-point upon encountering any f.p. arg */
+ /* OR... if integer is too big */
+ if (!fpflag) if (xxfloat(s2,0) == 2)
+ fpflag++;
+ fpj = atof(s2);
+ }
+ if (i == 1) { /* Initial result is first operand */
+ result = (n == 2 && x == SX_SUB) ? 0-j : j;
+ fpresult = (n == 2 && x == SX_SUB) ? -fpj : fpj;
+ if ((x == SX_AND && result == 0) || /* Short circuit */
+ (x == SX_LOR && result != 0))
+ quit++;
+ if (!(kwflags & SXF_ONE)) /* Command w/single arg */
+ continue;
+ }
+ if (x == SX_MOD || x == SX_DIV) {
+ if (!result)
+ fpflag++;
+ if (!fpj) {
+ printf("?Divide by zero - \"%s\"\n",cmdbuf);
+ sexprc++;
+ goto xdosexp;
+ }
+ }
+ switch (x) { /* Accumulate result */
+
+ case SX_EVA: /* EVAL */
+ result = j;
+ fpresult = fpj;
+ break;
+
+ case SX_ADD: /* + */
+ result += j;
+ fpresult += fpj;
+#ifdef FNFLOAT
+ if (result != fpresult)
+ fpflag++;
+#endif /* FNFLOAT */
+ break;
+
+ case SX_SUB: /* - */
+ result -= j;
+ fpresult -= fpj;
+#ifdef FNFLOAT
+ if (result != fpresult)
+ fpflag++;
+#endif /* FNFLOAT */
+ break;
+
+ case SX_MUL: /* * */
+ result *= j;
+ fpresult *= fpj;
+#ifdef FNFLOAT
+ if (result != fpresult)
+ fpflag++;
+#endif /* FNFLOAT */
+ break;
+
+ case SX_AND: /* AND */
+ result = result && j;
+ if (!result) quit++;
+ fpresult = fpresult && fpj;
+ break;
+
+ case SX_LOR: /* OR */
+ result = result || j;
+ if (!result) quit++;
+ fpresult = fpresult || fpj;
+ break;
+
+ case SX_MOD: /* Modulus */
+ result = result % j;
+#ifdef FNFLOAT
+ fpresult = (CKFLOAT)fmod(fpresult,fpj);
+ if (result != fpresult)
+ fpflag++;
+#else
+ fpresult = result;
+#endif /* FNFLOAT */
+ break;
+
+ case SX_DIV: /* / */
+ if (j) {
+ result /= j;
+ fpresult /= fpj;
+#ifdef FNFLOAT
+ if (result != fpresult)
+ fpflag++;
+#endif /* FNFLOAT */
+ } else {
+ fpresult /= fpj;
+ result = fpj;
+#ifdef FNFLOAT
+ fpflag++;
+#endif /* FNFLOAT */
+ }
+ break;
+
+ case SX_AEQ: /* Test for equality */
+ if (fpflag) {
+ if (fpresult != fpj)
+ presult = 0;
+ } else {
+ if (result != j)
+ presult = 0;
+ }
+ break;
+
+ case SX_NEQ: /* Test for ineqality */
+ if (fpflag) {
+ if (fpresult == fpj)
+ presult = 0;
+ } else {
+ if (result == j)
+ presult = 0;
+ }
+ break;
+
+ case SX_ALE: /* Arithmetic less-equal */
+ if (fpflag) {
+ if (fpj < fpresult)
+ presult = 0;
+ fpresult = fpj;
+ } else {
+ if (j < result)
+ presult = 0;
+ result = j;
+ }
+ break;
+
+ case SX_ALT: /* Arithmetic less-than */
+ if (fpflag) {
+ if (fpj <= fpresult)
+ presult = 0;
+ fpresult = fpj;
+ } else {
+ if (j <= result)
+ presult = 0;
+ result = j;
+ }
+ break;
+
+ case SX_AGT: /* Arithmetic greater-than */
+ if (fpflag) {
+ if (fpj >= fpresult)
+ presult = 0;
+ fpresult = fpj;
+ } else {
+ if (j >= result)
+ presult = 0;
+ result = j;
+ }
+ break;
+
+ case SX_AGE: /* Arithmetic greater-equal */
+ if (fpflag) {
+ if (fpj > fpresult)
+ presult = 0;
+ fpresult = fpj;
+ } else {
+ if (j > result)
+ presult = 0;
+ result = j;
+ }
+ break;
+
+ case SX_POW: /* Raise to power */
+#ifdef FNFLOAT
+ {
+ double dummy;
+ if (!fpj) {
+ fpresult = 1.0;
+ } else if ((!fpresult && fpj <= 0.0)) {
+ printf("?Divide by zero - \"%s\"\n",cmdbuf);
+ sexprc++;
+ goto xdosexp;
+ } else if (fpresult < 0.0 && modf(fpj,&dummy)) {
+ printf("?Domain error - \"%s\"\n",cmdbuf);
+ sexprc++;
+ goto xdosexp;
+ } else {
+ fpresult = (CKFLOAT)pow(fpresult,fpj);
+ }
+ }
+#endif /* FNFLOAT */
+ if (j == 0) {
+ result = 1;
+ } else {
+ CK_OFF_T z, sign = 0;
+ if (j < 0) {
+ if (result == 0) {
+ printf("?Divide by zero - \"%s\"\n",cmdbuf);
+ sexprc++;
+ goto xdosexp;
+ }
+ j = 0 - j;
+ sign++;
+ }
+ z = result;
+ while (--j > 0)
+ result *= z;
+ if (sign)
+ result = 1 / result;
+ }
+#ifdef FNFLOAT
+ if (result != fpresult)
+ fpflag++;
+#endif /* FNFLOAT */
+ break;
+
+#ifdef FNFLOAT
+ case SX_EXP: /* e to the given power */
+ fpresult = (CKFLOAT) exp(fpj);
+ break;
+
+ case SX_LGN: /* Natural log */
+ case SX_LGX: /* Log base 10 */
+ case SX_SQR: /* Square root */
+ if (fpj < 0.0) {
+ printf("?Argument out of range - \"%s\"\n",cmdbuf);
+ sexprc++;
+ goto xdosexp;
+ }
+ if (x == SX_SQR)
+ fpresult = (CKFLOAT) sqrt(fpj);
+ else if (x == SX_LGN)
+ fpresult = (CKFLOAT) log(fpj);
+ else
+ fpresult = (CKFLOAT) log10(fpj);
+ break;
+
+ case SX_SIN: /* sine */
+ fpresult = (CKFLOAT) sin(fpj);
+ break;
+
+ case SX_COS: /* cosine */
+ fpresult = (CKFLOAT) cos(fpj);
+ break;
+
+ case SX_TAN: /* tangent */
+ fpresult = (CKFLOAT) tan(fpj);
+ break;
+#endif /* FNFLOAT */
+
+ case SX_CEI: /* Ceiling */
+ if (j != fpj)
+ if (fpj > 0.0)
+ fpj += 1.0;
+ fpresult = fpj;
+ fpflag = 1;
+ truncate = 1;
+ break;
+
+ case SX_FLR: /* Floor */
+ if (j != fpj)
+ if (fpj < 0.0)
+ fpj -= 1.0;
+ fpresult = fpj;
+ fpflag = 1;
+ truncate = 1;
+ break;
+
+ case SX_TRU: /* Truncate */
+ fpresult = fpj;
+ fpflag = 1;
+ truncate = 1;
+ break;
+
+ case SX_ABS: /* Absolute value */
+ result = (j < 0) ? 0 - j : j;
+#ifdef FNFLOAT
+ fpresult = (fpj < 0.0) ? 0.0 - fpj : fpj;
+ if (result != fpresult)
+ fpflag++;
+#endif /* FNFLOAT */
+ break;
+
+ case SX_MAX: /* Max */
+ if (j != fpj)
+ fpflag++;
+ if (fpflag) {
+ if (fpj > fpresult)
+ fpresult = fpj;
+ } else
+ if (j > result)
+ result = j;
+ break;
+
+ case SX_MIN: /* Min */
+ if (j != fpj)
+ fpflag++;
+ if (fpflag) {
+ if (fpj < fpresult)
+ fpresult = fpj;
+ } else
+ if (j < result)
+ result = j;
+ break;
+
+ case SX_FLO: /* Float */
+ fpflag++;
+ fpresult = result;
+ fpj = j;
+ break;
+
+ case SX_NOT: /* NOT (reverse truth value) */
+ fpflag = 0;
+ not++;
+ break;
+
+ case SX_BWA: /* Bitwise AND */
+ fpflag = 0;
+ result &= j;
+ break;
+
+ case SX_BWO: /* Bitwise OR */
+ fpflag = 0;
+ result |= j;
+ break;
+
+ case SX_BWX: /* Bitwise XOR */
+ case SX_XOR: /* Logical XOR */
+ if (n > 3) {
+ printf("?Too many operands - \"%s\"\n",s);
+ sexprc++;
+ goto xdosexp;
+ }
+ fpflag = 0;
+ if (x == SX_BWX) {
+ result ^= j;
+ } else {
+ result = (result && !j) || (!result && j);
+ if (result) result = 1;
+ }
+ break;
+
+ case SX_BWN: /* Bitwise Not */
+ fpflag = 0;
+ result = ~result;
+ break;
+
+ default:
+ printf("BAD OP [%s]\n",p[1]);
+ sexprc++;
+ }
+ }
+ if (!pflag) /* Not a predicate */
+ sexppv = -1; /* So unset this */
+
+ /* domacro: */
+
+ if (macro) { /* User-defined macro */
+ extern int fsexpflag; /* (see fneval():ckuus4.c) */
+ int lookagain = 0; /* Maybe the macro table changed */
+ if (mactab[mx].kwd) { /* Check and see */
+ if (ckstrcmp(mactab[mx].kwd,p[1],-1,0))
+ lookagain++;
+ } else
+ lookagain++;
+ if (lookagain) { /* The table changed */
+ mx = mxlook(mactab,p[1],nmac); /* Get the macro's new index */
+ debug(F111,sexpdebug("macro moved"),p[1],mx);
+ if (mx < 0) { /* Yikes! */
+ printf("?Macro disappeared! - \"%s\"\n",p[1]);
+ sexprc++;
+ goto xdosexp;
+ }
+ }
+ debug(F111,sexpdebug("macro mx"),mactab[mx].kwd,mx);
+ if (fsexpflag) { /* If embedded in a function call */
+ if (cmpush() > -1) { /* get a new copy of the parsing */
+ extern int ifc; /* environment, */
+ int k, ifcsav = ifc; /* save the IF state */
+ dodo(mx,line,0); /* Set up the macro */
+ k = parser(1); /* Call the parser to execute it */
+ cmpop(); /* Pop back to previous level */
+ ifc = ifcsav; /* restore IF state */
+ if (k == 0) /* If no error */
+ s2 = mrval[maclvl+1]; /* get return value, if any */
+ if (!s2) s2 = "";
+ debug(F110,sexpdebug("macro return"),s2,0);
+ } else {
+ printf("?Resources exhausted - \"%s\"\n",s);
+ sexprc++;
+ }
+ } else { /* Not embedded in a function call */
+ dodo(mx,line,0); /* As above but without cmpush/pop() */
+ k = parser(1);
+ if (k == 0)
+ s2 = mrval[maclvl+1];
+ if (!s2) s2 = "";
+ }
+ } else if (pflag) { /* Predicate */
+ if (not) presult = presult ? 0 : 1;
+ sexppv = presult; /* So set predicate value (0 or 1) */
+ s2 = presult ? "1" : "0";
+ } else if (fpflag && !sexptrunc) { /* Result is floating-point */
+ if (not) fpresult = fpresult ? 0.0 : 1.0;
+ s2 = fpformat(fpresult,0,0);
+ } else if (x != SX_EVA) {
+ if (not) result = result ? 0 : 1;
+ s2 = ckfstoa(result);
+ }
+
+/* Common exit point. Always come here to exit. */
+
+ xdosexp:
+
+ if (!s2) s2 = "";
+ if (!sexprc && s2) { /* Have a result */
+ char * sx;
+ char * q2 = s2; int xx = 0;
+ if (*s2) {
+ while (*q2++) xx++; /* Get length */
+ if (xx > sexprmax) /* (stats) */
+ sexprmax = xx;
+ } else
+ xx = 0;
+ if (xx > sxrlen[sexpdep] || !sxresult[sexpdep]) {
+ int k;
+ k = xx + xx / 4;
+ if (k < 32) k = 32;
+ if (sxresult[sexpdep])
+ free(sxresult[sexpdep]);
+ if ((sxresult[sexpdep] = (char *)malloc(k))) {
+ sxrlen[sexpdep] = k;
+ } else {
+ printf("?Memory allocation failure - \"%s\"\n",s2);
+ sexprc++;
+ }
+ }
+ sx = sxresult[sexpdep]; /* Point to result buffer */
+ while ((*sx++ = *s2++)) ; /* copy result. */
+ if (fpflag && truncate) { /* Floating point + truncate */
+ sx = sxresult[sexpdep]; /* at decimal point */
+ for (i = xx - 1; i >= 0; i--) {
+ if (sx[i] == '.') {
+ sx[i] = NUL;
+ if (i == 0) { /* If nothing left */
+ sx[0] = '0'; /* put a zero. */
+ sx[1] = NUL;
+ }
+ }
+ }
+ }
+ }
+ if (line) /* If macro arg buffer allocated */
+ free(line); /* free it. */
+ if (mustfree) { /* And free local copy of split list */
+ for (i = 1; i <= n; i++) {
+ if (p[i]) free(p[i]);
+ }
+ }
+ debug(F111,sexpdebug("exit"),sxresult[sexpdep],sexprc);
+ return(sxresult[sexpdep--]);
+}
+#endif /* NOSEXP */
+#endif /* NOSPL */
+
+int /* CHECK command */
+dochk() {
+ int x, y;
+ if ((y = cmkey(ftrtab,nftr,"","",xxstring)) < 0)
+ return(y);
+ ckstrncpy(line,atmbuf,LINBUFSIZ);
+ if ((y = cmcfm()) < 0)
+ return(y);
+#ifndef NOPUSH
+ if (!ckstrcmp(line,"push",(int)strlen(line),0)) {
+ if (msgflg) /* If at top level... */
+ printf(" push%s available\n", nopush ? " not" : "");
+ else if (nopush && !backgrd)
+ printf(" CHECK: push not available\n");
+ return(success = 1 - nopush);
+ }
+#endif /* NOPUSH */
+#ifdef PIPESEND
+ if (!ckstrcmp(line,"pipes",(int)strlen(line),0)) {
+ if (msgflg) /* If at top level... */
+ printf(" pipes%s available\n",
+ (nopush || protocol != PROTO_K) ? " not" : "");
+ else if ((nopush || protocol != PROTO_K) && !backgrd)
+ printf(" CHECK: pipes not available\n");
+ return(success = 1 - nopush);
+ }
+#endif /* PIPESEND */
+ y = lookup(ftrtab,line,nftr,&x); /* Look it up */
+ debug(F111,"dochk",ftrtab[x].kwd,y);
+ if (msgflg) /* If at top level... */
+ printf(" %s%s available\n", ftrtab[x].kwd, y ? " not" : "");
+ else if (y && !backgrd)
+ printf(" CHECK: %s not available\n", ftrtab[x].kwd);
+ return(success = 1 - y);
+}
+
+#ifndef NOLOCAL
+#ifdef CKLOGDIAL
+
+/* Connection log and elapsed-time reporting */
+
+extern char cxlogbuf[]; /* Log record buffer */
+extern char diafil[]; /* Log file name */
+extern int dialog, cx_active; /* Flags */
+static long cx_prev = 0L; /* Elapsed time of previous session */
+
+#endif /* CKLOGDIAL */
+#endif /* NOLOCAL */
+
+VOID
+dologend() { /* Write record to connection log */
+#ifdef LOCUS
+ extern int locus, autolocus;
+#endif /* LOCUS */
+
+#ifndef NOLOCAL
+#ifdef CKLOGDIAL
+ long d1, d2, t1, t2;
+ char buf[32], * p;
+#endif /* CKLOGDIAL */
+#endif /* NOLOCAL */
+
+#ifdef LOCUS
+ if (autolocus) {
+ int x = locus;
+#ifdef NEWFTP
+ debug(F101,"dologend ftpisconnected","",ftpisconnected());
+ setlocus(ftpisconnected() ? 0 : 1, 1);
+#else
+ setlocus(1,1);
+#endif /* NEWFTP */
+ }
+#endif /* LOCUS */
+
+#ifndef NOLOCAL
+#ifdef CKLOGDIAL
+ debug(F101,"dologend dialog","",dialog);
+ debug(F101,"dologend cxlogbuf[0]","",cxlogbuf[0]);
+#ifdef CKSYSLOG
+ debug(F101,"dologend ckxlogging","",ckxlogging);
+#endif /* CKSYSLOG */
+
+ if (!cx_active || !cxlogbuf[0]) /* No active record */
+ return;
+
+ cx_active = 0; /* Record is not active */
+ debug(F111,"dologend cxlogbuf 1",cxlogbuf,cx_active);
+
+ d1 = mjd((char *)cxlogbuf); /* Get start date of this session */
+ ckstrncpy(buf,ckdate(),31); /* Get current date */
+ d2 = mjd(buf); /* Convert them to mjds */
+ p = cxlogbuf; /* Get start time */
+ p[11] = NUL;
+ p[14] = NUL; /* Convert to seconds */
+ t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
+ p[11] = ':';
+ p[14] = ':';
+ p = buf; /* Get end time */
+ p[11] = NUL;
+ p[14] = NUL;
+ t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
+ t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
+ debug(F101,"dologend t2","",t2);
+ if (t2 > -1L) {
+ cx_prev = t2;
+ p = hhmmss(t2);
+ debug(F110,"dologend hhmmss",p,0);
+ ckstrncat(cxlogbuf,"E=",CXLOGBUFL); /* Append to log record */
+ ckstrncat(cxlogbuf,p,CXLOGBUFL);
+ debug(F110,"dologend cxlogbuf 2",cxlogbuf,0);
+ } else
+ cx_prev = 0L;
+ debug(F101,"dologend cx_prev","",cx_prev);
+ if (dialog) { /* If logging */
+ int x;
+ x = diaopn(diafil,1,1); /* Open log in append mode */
+ debug(F101,"dologend diaopn","",x);
+ x = zsoutl(ZDIFIL,cxlogbuf); /* Write the record */
+ debug(F101,"dologend zsoutl","",x);
+ x = zclose(ZDIFIL); /* Close the log */
+ debug(F101,"dologend zclose","",x);
+ }
+#ifdef CKSYSLOG
+ debug(F101,"dologend ckxlogging","",ckxlogging);
+ if (ckxlogging) {
+ int x;
+ x = ckindex("T=DIAL",cxlogbuf,0,0,1);
+ debug(F111,"dologend ckxsyslog",cxlogbuf,ckxsyslog);
+ debug(F111,"dologend ckindex","T=DIAL",x);
+ if (x > 0) {
+ if (ckxsyslog >= SYSLG_DI) {
+ debug(F110,"dologend syslog",cxlogbuf+18,0);
+ cksyslog(SYSLG_DI,1,"CONNECTION",(char *)(cxlogbuf+18),"");
+ } else if (ckxsyslog >= SYSLG_AC) {
+ debug(F110,"dologend syslog",cxlogbuf+18,0);
+ cksyslog(SYSLG_AC,1,"CONNECTION",(char *)(cxlogbuf+18),"");
+ }
+ }
+ }
+#endif /* CKSYSLOG */
+#endif /* CKLOGDIAL */
+#endif /* NOLOCAL */
+}
+
+#ifndef NOLOCAL
+#ifdef CKLOGDIAL
+
+/* D O L O G S H O W -- Show session/connection info */
+
+/* Call with fc == 1 to show, fc == 0 to only calculate. */
+/* Returns session elapsed time in seconds. */
+/* If no session active, returns elapsed time of previous session, if any, */
+/* otherwise 0 */
+
+long
+dologshow(fc) int fc; { /* SHOW (current) CONNECTION */
+ long d1, d2, t1, t2 = 0, prev;
+ char c, buf1[32], buf2[32], * info[32], * p, * s;
+ char * xlogbuf, xbuf[CXLOGBUFL+1];
+ int i, x = 0, z, ftp = 0, active = 0;
+
+#ifdef NEWFTP
+ extern char ftplogbuf[];
+ extern long ftplogprev;
+ extern int ftplogactive;
+ if (fc & W_FTP) {
+ fc &= 63;
+ ftp = 1;
+ xlogbuf = ftplogbuf;
+ prev = ftplogprev;
+ active = ftplogactive;
+ } else {
+#endif /* NEWFTP */
+ ftp = 0;
+ xlogbuf = cxlogbuf;
+ prev = cx_prev;
+ active = cx_active;
+#ifdef NEWFTP
+ }
+#endif /* NEWFTP */
+
+ debug(F101,"dologshow local","",local);
+ debug(F101,"dologshow ftp","",ftp);
+ debug(F111,"dologshow active",xlogbuf,active);
+
+ if (!xlogbuf[0]) {
+ if (fc) {
+ if (didsetlin || ftp)
+ printf(" %s: No record.\n", ftp ? "FTP" : "Kermit");
+ else
+ printf(" %s: No connection.\n", ftp ? "FTP" : "Kermit");
+ }
+ return(prev);
+ }
+
+#ifdef NEWFTP
+ if (ftp) {
+ z = ftpisconnected() ? 1 : -1;
+ } else {
+#endif /* NEWFTP */
+ if (local) { /* See if we have an open connection */
+ z = ttchk();
+ debug(F101,"dologshow ttchk","",z);
+ z = (z > -1) ? 1 : -2;
+ } else {
+ z = active ? 1 : -2;
+ }
+#ifdef NEWFTP
+ }
+#endif /* NEWFTP */
+ if (z < 0L) {
+ if (!fc)
+ return(prev);
+ else
+ t2 = prev;
+ }
+ /* Note: NOT ckstrncpy! */
+ strncpy(buf1,xlogbuf,17); /* Copy of just the timestamp */
+ buf1[17] = NUL; /* Terminate it */
+ ckstrncpy(xbuf,xlogbuf+18,CXLOGBUFL); /* Copy that can be poked */
+ debug(F111,"dologshow prev",xbuf,prev);
+
+ xwords(xbuf,31,info,1); /* Break up into fields */
+ d1 = mjd(buf1); /* Convert start time to MJD */
+ ckstrncpy(buf2,ckdate(),31); /* Current date */
+ d2 = mjd(buf2); /* Convert to MJD */
+ p = buf1; /* Point to start time */
+ p[11] = NUL;
+ p[14] = NUL; /* Convert to seconds */
+ t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
+ p[11] = ':';
+ p[14] = ':';
+ p = buf2; /* Ditto for current time */
+ p[11] = NUL;
+ p[14] = NUL;
+ if (z > -1L) {
+ t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
+ t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Elapsed time so far */
+ }
+ if (fc) {
+ p = NULL;
+ if (t2 > -1L) /* Convert seconds to hh:mm:ss */
+ p = hhmmss(t2);
+ if (z > -1)
+ s = "Active";
+ else if (z == -2)
+ s = "Closed";
+ else
+ s = "Unknown";
+ printf("\n"); /* Show results */
+ printf(" Status: %s\n",s);
+ printf(" Opened: %s\n",buf1);
+ printf(" User: %s\n",info[1] ? info[1] : "");
+ printf(" PID: %s\n",info[2] ? info[2] : "");
+ for (i = 3; info[i]; i++) {
+ c = info[i][0];
+ s = (info[i]) ? info[i]+2 : "";
+ switch (c) {
+ case 'T': printf(" Type: %s\n", s); break;
+ case 'N': printf(" To: %s\n", s); break;
+ case 'P': printf(" Port: %s\n", s); break;
+ case 'H': printf(" From: %s\n", s); break;
+ case 'D': printf(" Device: %s\n", s); break;
+ case 'O': printf(" Origin: %s\n", s); break;
+ case 'E': break;
+ default: printf(" %s\n",info[i] ? info[i] : "");
+ }
+ }
+ if (z < 0L)
+ printf(" Elapsed time: %s\n", hhmmss(t2));
+ else
+ printf(" Elapsed time: %s\n", p ? p : "(unknown)");
+ x = 0;
+#ifdef NETCONN
+#ifdef SSHBUILTIN
+ if ( IS_SSH() ) x++;
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ if (ck_tn_encrypting() && ck_tn_decrypting()) x++;
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ if (tls_active_flag || ssl_active_flag) x++;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) x++;
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+#endif /* NETCONN */
+ if (z > 0)
+ printf(" Encrypted: %s\n", x ? "Yes" : "No");
+ printf(" Log: %s\n", dialog ? diafil : "(none)");
+ printf("\n");
+ }
+ return(t2 > -1L ? t2 : 0L);
+}
+
+VOID
+dologline() {
+ char * p;
+ int n, m = 0;
+
+ dologend(); /* Previous session not closed out? */
+ cx_active = 1; /* Record is active */
+ cx_prev = 0L;
+ p = ckdate(); /* Get timestamp */
+ n = ckstrncpy(cxlogbuf,p,CXLOGBUFL-1); /* Start record off with it */
+ if (!uidbuf[0]) {
+ debug(F100,"dologline uidbuf empty","",0);
+#ifdef UNIX /* Who has whoami()... */
+ ckstrncpy(uidbuf,(char *)whoami(),UIDBUFLEN);
+#else
+#ifdef STRATUS
+ ckstrncpy(uidbuf,(char *)whoami(),UIDBUFLEN);
+#else
+ ckstrncpy(uidbuf,"UNKNOWN",UIDBUFLEN);
+#endif /* STRATUS */
+#endif /* UNIX */
+ }
+ m = strlen(uidbuf) + strlen(myhost) + strlen(ttname) + 32;
+ if (n+m < CXLOGBUFL-1) { /* Add serial device info */
+ p = cxlogbuf+n;
+ sprintf(p," %s %s T=SERIAL H=%s D=%s ", /* SAFE */
+ uidbuf,
+ ckgetpid(),
+ myhost,
+ ttname
+ );
+ } else
+ ckstrncpy(cxlogbuf,"LOGLINE BUFFER OVERFLOW",CXLOGBUFL);
+ debug(F110,"dologline",cxlogbuf,0);
+}
+
+#ifdef NETCONN
+VOID
+dolognet() {
+ char * p, * s = "NET", * uu = uidbuf;
+ char * port = "";
+ int n, m, tcp = 0;
+ char * h = NULL;
+
+ dologend(); /* Previous session not closed out? */
+ cx_prev = 0L;
+ cx_active = 1; /* Record is active */
+ p = ckdate();
+ n = ckstrncpy(cxlogbuf,p,CXLOGBUFL);
+#ifdef TCPSOCKET
+ if (nettype == NET_TCPB || nettype == NET_TCPA) {
+ tcp++;
+ s = "TCP";
+ } else if (nettype == NET_SSH) {
+ s = "SSH";
+ tcp++;
+ }
+#endif /* TCPSOCKET */
+#ifdef ANYX25
+ if (nettype == NET_SX25 || nettype == NET_VX25 || nettype == NET_IX25)
+ s = "X25";
+#endif /* ANYX25 */
+#ifdef DECNET
+ if (nettype == NET_DEC)
+ s = "DECNET";
+#endif /* DECNET */
+#ifdef SUPERLAT
+ if (nettype == NET_SLAT)
+ s = "SUPERLAT";
+#endif /* SUPERLAT */
+#ifdef CK_NETBIOS
+ if (nettype == NET_BIOS)
+ s = "NETBIOS";
+#endif /* CK_NETBIOS */
+
+ if (!uu[0]) {
+ debug(F100,"dolognet uidbuf empty","",0);
+#ifdef OS2ORUNIX /* Who has whoami()... */
+ uu = (char *)whoami();
+#else
+#ifdef STRATUS
+ uu = (char *)whoami();
+#else
+ uu = "UNKNOWN";
+#endif /* STRATUS */
+#endif /* UNIX */
+ }
+#ifdef TCPSOCKET
+ if (tcp) {
+ int k;
+ makestr(&h,myhost);
+ if ((k = ckindex(":",h,0,0,0)) > 0) {
+ h[k-1] = NUL;
+ port = &h[k];
+ } else {
+ int svcnum = gettcpport();
+ if (svcnum > 0)
+ port = ckitoa(svcnum);
+ else
+ port = "unk";
+ }
+ }
+#endif /* TCPSOCKET */
+ m = strlen(uu) + strlen(myhost) + strlen(ttname) + strlen(s) + 32;
+ if (n+m < CXLOGBUFL-1) { /* SAFE */
+ p = cxlogbuf+n;
+ sprintf(p," %s %s T=%s N=%s H=%s P=%s ",
+ uu,
+ ckgetpid(),
+ s,
+ ttname,
+ myhost,
+ port
+ );
+ } else
+ ckstrncpy(cxlogbuf,"LOGNET BUFFER OVERFLOW",CXLOGBUFL);
+ debug(F110,"dolognet cxlogbuf",cxlogbuf,0);
+ if (h) makestr(&h,NULL);
+}
+#endif /* NETCONN */
+#endif /* CKLOGDIAL */
+
+#ifndef NODIAL
+/*
+ Parse a DIAL-related string, stripping enclosing braces, if any.
+*/
+static int
+dialstr(p,msg) char **p; char *msg; {
+ int x;
+ char *s;
+
+ if ((x = cmtxt(msg, "", &s, xxstring)) < 0)
+ return(x);
+ s = brstrip(s); /* Strip braces around. */
+ debug(F110,"dialstr",s,0);
+ makestr(p,*s?s:NULL);
+ return(success = 1);
+}
+
+VOID
+initmdm(x) int x; {
+ MDMINF * p;
+ int m;
+
+ mdmtyp = x; /* Set global modem type */
+ debug(F101,"initmdm mdmtyp","",mdmtyp);
+ debug(F101,"initmdm usermdm","",usermdm);
+ if (x < 1) return;
+
+ m = usermdm ? usermdm : mdmtyp;
+
+ p = modemp[m]; /* Point to modem info struct, and */
+ /* debug(F101,"initmdm p","",p); */
+ if (p) {
+ dialec = p->capas & CKD_EC; /* set DIAL ERROR-CORRECTION, */
+ dialdc = p->capas & CKD_DC; /* DIAL DATA-COMPRESSION, and */
+ mdmspd = p->capas & CKD_SB ? 0 : 1; /* DIAL SPEED-MATCHING from it. */
+ dialfc = FLO_AUTO; /* Modem's local flow control.. */
+ dialmax = p->max_speed;
+ dialcapas = p->capas;
+ dialesc = p->esc_char;
+ } else if (mdmtyp > 0) {
+ printf("WARNING: modem info for \"%s\" not filled in yet\n",
+ gmdmtyp()
+ );
+ }
+
+/* Reset or set the SET DIAL STRING items ... */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"initmdm dialini",dialini,0);
+ debug(F110,"initmdm dialmstr ",dialmstr,0);
+ debug(F110,"initmdm dialmprmt",dialmprmt,0);
+ debug(F110,"initmdm dialcmd",dialcmd,0);
+ debug(F110,"initmdm dialdcon",dialdcon,0);
+ debug(F110,"initmdm dialdcoff",dialdcoff,0);
+ debug(F110,"initmdm dialecon",dialecon,0);
+ debug(F110,"initmdm dialecoff",dialecoff,0);
+ debug(F110,"initmdm dialhcmd",dialhcmd,0);
+ debug(F110,"initmdm dialhwfc",dialhwfc,0);
+ debug(F110,"initmdm dialswfc",dialswfc,0);
+ debug(F110,"initmdm dialnofc",dialnofc,0);
+ debug(F110,"initmdm dialtone",dialtone,0);
+ debug(F110,"initmdm dialpulse",dialpulse,0);
+ debug(F110,"initmdm dialname",dialname,0);
+ debug(F110,"initmdm dialaaon",dialaaon,0);
+ debug(F110,"initmdm dialaaoff",dialaaoff,0);
+ debug(F110,"initmdm dialx3",dialx3,0);
+ debug(F110,"initmdm dialspon",dialspon,0);
+ debug(F110,"initmdm dialspoff",dialspoff,0);
+ debug(F110,"initmdm dialvol1",dialvol1,0);
+ debug(F110,"initmdm dialvol2",dialvol2,0);
+ debug(F110,"initmdm dialvol3",dialvol3,0);
+ debug(F110,"initmdm dialini2",dialini2,0);
+ }
+#endif /* DEBUG */
+
+ if (usermdm && p) { /* USER-DEFINED: copy info from specified template */
+
+ makestr(&dialini ,p->wake_str);
+ makestr(&dialmstr ,p->dmode_str);
+ makestr(&dialmprmt,p->dmode_prompt);
+ makestr(&dialcmd ,p->dial_str);
+ makestr(&dialdcon ,p->dc_on_str);
+ makestr(&dialdcoff,p->dc_off_str);
+ makestr(&dialecon ,p->ec_on_str);
+ makestr(&dialecoff,p->ec_off_str);
+ makestr(&dialhcmd ,p->hup_str);
+ makestr(&dialhwfc ,p->hwfc_str);
+ makestr(&dialswfc ,p->swfc_str);
+ makestr(&dialnofc ,p->nofc_str);
+ makestr(&dialtone ,p->tone);
+ makestr(&dialpulse,p->pulse);
+ makestr(&dialname ,"This space available (use SET MODEM NAME)");
+ makestr(&dialaaon ,p->aa_on_str);
+ makestr(&dialaaoff,p->aa_off_str);
+ makestr(&dialx3 ,p->ignoredt);
+ makestr(&dialspon ,p->sp_on_str);
+ makestr(&dialspoff,p->sp_off_str);
+ makestr(&dialvol1 ,p->vol1_str);
+ makestr(&dialvol2 ,p->vol2_str);
+ makestr(&dialvol3 ,p->vol3_str);
+ makestr(&dialini2 ,p->ini2);
+
+ } else { /* Not user-defined, so wipe out overrides */
+
+ if (dialini) makestr(&dialini,NULL); /* Init-string */
+ if (dialmstr) makestr(&dialmstr,NULL); /* Dial-mode-str */
+ if (dialmprmt) makestr(&dialmprmt,NULL); /* Dial-mode-pro */
+ if (dialcmd) makestr(&dialcmd,NULL); /* Dial-command */
+ if (dialdcon) makestr(&dialdcon,NULL); /* DC ON command */
+ if (dialdcoff) makestr(&dialdcoff,NULL); /* DC OFF command */
+ if (dialecon) makestr(&dialecon,NULL); /* EC ON command */
+ if (dialecoff) makestr(&dialecoff,NULL); /* EC OFF command */
+ if (dialhcmd) makestr(&dialhcmd,NULL); /* Hangup command */
+ if (dialhwfc) makestr(&dialhwfc,NULL); /* Flow control... */
+ if (dialswfc) makestr(&dialswfc,NULL); /* */
+ if (dialnofc) makestr(&dialnofc,NULL); /* */
+ if (dialtone) makestr(&dialtone,NULL); /* Dialing method */
+ if (dialpulse) makestr(&dialpulse,NULL); /* */
+ if (dialname) makestr(&dialname,NULL); /* Modem name */
+ if (dialaaon) makestr(&dialaaon,NULL); /* Autoanswer On */
+ if (dialaaoff) makestr(&dialaaoff,NULL); /* Autoanswer Off */
+ if (dialx3) makestr(&dialx3,NULL); /* Ignore dialtone */
+ if (dialspon) makestr(&dialspon,NULL); /* Speaker On */
+ if (dialspoff) makestr(&dialspoff,NULL); /* Speaker Off */
+ if (dialvol1) makestr(&dialvol1,NULL); /* Low volume */
+ if (dialvol2) makestr(&dialvol2,NULL); /* Medium volume */
+ if (dialvol3) makestr(&dialvol3,NULL); /* High volume */
+ if (dialini2) makestr(&dialini2,NULL); /* Init string 2 */
+ }
+ if (autoflow) /* Maybe change flow control */
+ setflow();
+
+#ifndef MINIDIAL
+#ifdef OLDTBCODE
+ tbmodel = 0; /* If it's a Telebit, we don't know the model yet */
+#endif /* OLDTBCODE */
+#endif /* MINIDIAL */
+}
+
+#ifdef COMMENT
+/* Not implemented yet */
+int
+setanswer() {
+ int x, y;
+ extern int ans_cid, ans_ring;
+ if ((x = cmkey(answertab,nanswertab,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case XYA_CID:
+ return(seton(&ans_cid));
+ case XYA_RNG:
+ y = cmnum("How many rings before answering","1",10,&x,xxstring);
+ y = setnum(&ans_rings,x,y,254);
+ return(y);
+ }
+}
+#endif /* COMMENT */
+
+int
+setmodem() { /* SET MODEM */
+
+ int x, y, z;
+ long zz;
+ struct FDB k1, k2;
+ extern int mdmset;
+
+ cmfdbi(&k1,_CMKEY,
+ "Modem parameter","","",nsetmdm, 0, xxstring, setmdm, &k2);
+ cmfdbi(&k2,_CMKEY,"","","",nmdm,0,xxstring,mdmtab,NULL);
+ x = cmfdb(&k1);
+ if (x < 0) { /* Error */
+ if (x == -2 || x == -9)
+ printf("?No keywords match: \"%s\"\n",atmbuf);
+ return(x);
+ }
+ y = cmresult.nresult; /* Keyword value */
+ if (cmresult.fdbaddr == &k2) { /* Modem-type keyword table */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ usermdm = 0;
+ initmdm(cmresult.nresult); /* Set the modem type. */
+ return(success = 1); /* Done */
+ }
+ switch (cmresult.nresult) { /* SET MODEM keyword table. */
+#ifdef MDMHUP
+ case XYDMHU: /* DIAL MODEM-HANGUP */
+ if ((y = cmkey(mdmhang,4,"how to hang up modem",
+ "modem-command", xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ dialmhu = y;
+#ifdef COMMENT
+/* Nope, I fixed it (2001 11 08) */
+#ifdef CK_SCOV5
+ if (dialmhu == 0 && !quiet) {
+ printf(
+"\n WARNING: RS-232 signal sampling and manipulation do not work\n"
+ );
+ printf(
+" in the standard SCO OSR5 serial i/o drivers. SET MODEM HANGUP-METHOD\n"
+ );
+ printf(
+" MODEM-COMMAND is recommended for OSR5.\n\n"
+ );
+ }
+#endif /* CK_SCOV5 */
+#endif /* COMMENT */
+ return(success = 1);
+#endif /* MDMHUP */
+
+ case XYDCAP:
+ zz = 0L;
+ y = 0;
+ while (y != -3) {
+ if ((y = cmkey(mdmcap,nmdmcap,
+ "capability of modem", "", xxstring)) < 0) {
+ if (y == -3)
+ break;
+ else
+ return(y);
+ }
+ zz |= y;
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ dialcapas = zz;
+ debug(F101,"setmodem autoflow","",autoflow);
+ debug(F101,"setmodem flow 1","",flow);
+ if (autoflow) /* Maybe change flow control */
+ setflow();
+ debug(F101,"setmodem flow 2","",flow);
+ mdmspd = zz & CKD_SB ? 0 : 1; /* Set MODEM SPEED-MATCHING from it. */
+ return(success = 1);
+
+ case XYDMAX:
+#ifdef TN_COMPORT
+ if (network && istncomport())
+ x = cmkey(tnspdtab,ntnspd,line,"",xxstring);
+ else
+#endif /* TN_COMPORT */
+ x = cmkey(spdtab,nspd,line,"",xxstring);
+ if (x < 0) {
+ if (x == -3) printf("?value required\n");
+ return(x);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ dialmax = (long) x * 10L;
+ if (dialmax == 70) dialmax = 75;
+ return(success = 1);
+
+ case XYDSTR: /* These moved from SET DIAL */
+ case XYDDC:
+ case XYDEC:
+ case XYDESC:
+ case XYDFC:
+ case XYDKSP:
+ case XYDSPD:
+ case XYDDIA:
+ return(setdial(x));
+
+ case XYDTYP:
+ if ((y = cmkey(mdmtab,nmdm,"modem type","none", xxstring)) < 0)
+ return(y);
+ if (y == dialudt) { /* User-defined modem type */
+ if ((x = cmkey(mdmtab,nmdm,"based on existing modem type",
+ "unknown", xxstring)) < 0)
+ return(x);
+ }
+ if ((z = cmcfm()) < 0)
+ return(z);
+ usermdm = 0;
+ usermdm = (y == dialudt) ? x : 0;
+ initmdm(y);
+ mdmset = (mdmtyp > 0);
+ return(success = 1);
+
+ case XYDNAM:
+ return(dialstr(&dialname,"Descriptive name for modem"));
+
+ case XYDMCD: /* SET MODEM CARRIER-WATCH */
+ return(setdcd());
+
+ case XYDSPK: /* SET MODEM SPEAKER */
+ return(seton(&mdmspk));
+
+ case XYDVOL: /* SET MODEM VOLUME */
+ if ((x = cmkey(voltab,3,"","medium",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ mdmvol = x;
+ return(success = 1);
+
+ default:
+ printf("Unexpected SET MODEM parameter\n");
+ return(-9);
+ }
+}
+
+static int /* Set DIAL command options */
+setdial(y) int y; {
+ int x = 0, z = 0;
+ char *s = NULL;
+
+ if (y < 0)
+ if ((y = cmkey(dialtab,ndial,"","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case XYDHUP: /* DIAL HANGUP */
+ return(seton(&dialhng));
+ case XYDINI: /* DIAL INIT-STRING */
+ return(dialstr(&dialini,"Modem initialization string"));
+ case XYDNPR: /* DIAL PREFIX */
+ return(dialstr(&dialnpr,"Telephone number prefix"));
+ case XYDDIA: /* DIAL DIAL-COMMAND */
+ x = cmtxt("Dialing command for modem,\n\
+ include \"%s\" to stand for phone number,\n\
+ for example, \"set dial dial-command ATDT%s\\13\"",
+ "",
+ &s,
+ xxstring);
+ if (x < 0 && x != -3) /* Handle parse errors */
+ return(x);
+ s = brstrip(s); /* Strip braces or quotes */
+ y = x = strlen(s); /* Get length of text */
+ if (y > 0) { /* If there is any text (left), */
+ for (x = 0; x < y; x++) { /* make sure they included "%s" */
+ if (s[x] != '%') continue;
+ if (s[x+1] == 's') break;
+ }
+ if (x == y) {
+ printf(
+"?Dial-command must contain \"%cs\" for phone number.\n",'%');
+ return(-9);
+ }
+ }
+ if (dialcmd) { /* Free any previous string. */
+ free(dialcmd);
+ dialcmd = (char *) 0;
+ }
+ if (y > 0) {
+ dialcmd = malloc(y + 1); /* Allocate space for it */
+ if (dialcmd)
+ strcpy(dialcmd,s); /* and make a safe copy. */
+ }
+ return(success = 1);
+#ifndef NOXFER
+ case XYDKSP: /* DIAL KERMIT-SPOOF */
+ return(seton(&dialksp));
+#endif /* NOXFER */
+ case XYDTMO: /* DIAL TIMEOUT */
+ y = cmnum("Seconds to wait for call completion","0",10,&x,xxstring);
+ if (y < 0) return(y);
+ y = cmnum("Kermit/modem timeout differential","10",10,&z,xxstring);
+ if (y < 0) return(y);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ dialtmo = x;
+ mdmwaitd = z;
+ case XYDESC: /* DIAL ESCAPE-CHARACTER */
+ y = cmnum("ASCII value of character to escape back to modem",
+ "43",10,&x,xxstring);
+ y = setnum(&dialesc,x,y,128);
+ if (y > -1 && dialesc < 0) /* No escape character */
+ dialmhu = 0; /* So no hangup by modem command */
+ return(y);
+ case XYDDPY: /* DIAL DISPLAY */
+ return(seton(&dialdpy));
+ case XYDSPD: /* DIAL SPEED-MATCHING */
+ /* used to be speed-changing */
+ if ((y = seton(&mdmspd)) < 0) return(y);
+#ifdef COMMENT
+ mdmspd = 1 - mdmspd; /* so here we reverse the meaning */
+#endif /* COMMENT */
+ return(success = 1);
+ case XYDMNP: /* DIAL MNP-ENABLE */
+ case XYDEC: /* DIAL ERROR-CORRECTION */
+ x = seton(&dialec);
+ if (x > 0)
+ if (!dialec) dialdc = 0; /* OFF also turns off compression */
+ return(x);
+
+ case XYDDC: /* DIAL COMPRESSION */
+ x = seton(&dialdc);
+ if (x > 0)
+ if (dialdc) dialec = 1; /* ON also turns on error correction */
+ return(x);
+
+#ifdef MDMHUP
+ case XYDMHU: /* DIAL MODEM-HANGUP */
+ return(seton(&dialmhu));
+#endif /* MDMHUP */
+
+#ifndef NOSPL
+ case XYDDIR: /* DIAL DIRECTORY (zero or more) */
+ return(parsdir(0)); /* 0 means DIAL */
+#endif /* NOSPL */
+
+ case XYDSTR: /* DIAL STRING */
+ if ((y = cmkey(mdmcmd,nmdmcmd,"","",xxstring)) < 0) return(y);
+ switch (y) {
+ case XYDS_AN: /* Autoanswer ON/OFF */
+ case XYDS_DC: /* Data compression ON/OFF */
+ case XYDS_EC: /* Error correction ON/OFF */
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(x);
+ sprintf(tmpbuf,"Modem's command to %sable %s", /* SAFE */
+ x ? "en" : "dis",
+ (y == XYDS_DC) ? "compression" :
+ ((y == XYDS_EC) ? "error-correction" :
+ "autoanswer")
+ );
+ if (x) {
+ if (y == XYDS_DC)
+ return(dialstr(&dialdcon,tmpbuf));
+ else if (y == XYDS_EC)
+ return(dialstr(&dialecon,tmpbuf));
+ else
+ return(dialstr(&dialaaon,tmpbuf));
+ } else {
+ if (y == XYDS_DC)
+ return(dialstr(&dialdcoff,tmpbuf));
+ else if (y == XYDS_EC)
+ return(dialstr(&dialecoff,tmpbuf));
+ else
+ return(dialstr(&dialaaoff,tmpbuf));
+ }
+ case XYDS_HU: /* hangup command */
+ return(dialstr(&dialhcmd,"Modem's hangup command"));
+ case XYDS_HW: /* hwfc */
+ return(dialstr(&dialhwfc,
+ "Modem's command to enable hardware flow control"));
+ case XYDS_IN: /* init */
+ return(dialstr(&dialini,"Modem's initialization string"));
+ case XYDS_NF: /* no flow control */
+ return(dialstr(&dialnofc,
+ "Modem's command to disable local flow control"));
+ case XYDS_PX: /* prefix */
+ return(dialstr(&dialnpr,"Telephone number prefix for dialing"));
+ case XYDS_SW: /* swfc */
+ return(dialstr(&dialswfc,
+ "Modem's command to enable local software flow control"));
+ case XYDS_DT: /* tone dialing */
+ return(dialstr(&dialtone,
+ "Command to configure modem for tone dialing"));
+ case XYDS_DP: /* pulse dialing */
+ return(dialstr(&dialpulse,
+ "Command to configure modem for pulse dialing"));
+ case XYDS_MS: /* dial mode string */
+ return(dialstr(&dialmstr,
+ "Command to enter dial mode"));
+ case XYDS_MP: /* dial mode prompt */
+ return(dialstr(&dialmprmt,
+ "Modem response upon entering dial mode"));
+ case XYDS_SP: /* SPEAKER OFF */
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x);
+ if (x)
+ return(dialstr(&dialspon,"Command to turn modem speaker on"));
+ else
+ return(dialstr(&dialspoff,"Command to turn modem speaker off"));
+
+ case XYDS_VO: /* VOLUME LOW */
+ if ((x = cmkey(voltab,3,"","medium",xxstring)) < 0) return(x);
+ switch (x) {
+ case 0:
+ case 1:
+ return(dialstr(&dialvol1,
+ "Command for low modem speaker volume"));
+ case 2:
+ return(dialstr(&dialvol2,
+ "Command for medium modem speaker volume"));
+
+ case 3:
+ return(dialstr(&dialvol3,
+ "Command for high modem speaker volume"));
+ default:
+ return(-2);
+ }
+
+ case XYDS_ID: /* IGNORE-DIALTONE */
+ return(dialstr(&dialx3,
+ "Command to tell modem to ignore dialtone"));
+
+ case XYDS_I2: /* PREDIAL-INIT */
+ return(dialstr(&dialini2,
+ "Command to send to modem just prior to dialing"));
+
+ default:
+ printf("?Unexpected SET DIAL STRING parameter\n");
+ }
+
+ case XYDFC: /* DIAL FLOW-CONTROL */
+ if ((y = cmkey(dial_fc,4,"","auto",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ dialfc = y;
+ return(success = 1);
+
+ case XYDMTH: { /* DIAL METHOD */
+ extern int dialmauto;
+ if ((y = cmkey(dial_m,ndial_m,"","default",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (y == XYDM_A) { /* AUTO */
+ dialmauto = 1; /* local country code, if known. */
+ dialmth = XYDM_D;
+ } else {
+ dialmauto = 0; /* use the method specified */
+ dialmth = y;
+ }
+ return(success = 1);
+ }
+ case XYDRTM:
+ y = cmnum("Number of times to try dialing a number",
+ "1",10,&x,xxstring);
+ z = setnum(&dialrtr,x,y,-1);
+ if (z > -1 && dialrtr < 0) {
+ printf("?Sorry, negative dial retries not valid: %d\n",dialrtr);
+ return(-9);
+ }
+ return(z);
+
+ case XYDINT:
+ y = cmnum("Seconds to wait between redial attempts",
+ "30",10,&x,xxstring);
+ z = setnum(&dialint,x,y,-1);
+ if (z > -1 && dialint < 0) {
+ printf("?Sorry, negative dial interval not valid: %d\n",dialint);
+ return(-9);
+ }
+ return(z);
+
+ case XYDLAC: /* DIAL AREA-CODE */
+ if ((x = dialstr(&diallac,"Area code you are calling from")) < 0)
+ return(x);
+ if (diallac) {
+ if (!rdigits(diallac)) {
+ printf("?Sorry, area code must be numeric\n");
+ if (*diallac == '(')
+ printf("(please omit the parentheses)\n");
+ if (*diallac == '/')
+ printf("(no slashes, please)\n");
+ if (diallac) free(diallac);
+ diallac = NULL;
+ return(-9);
+ }
+ }
+ return(x);
+
+ case XYDCNF: /* CONFIRMATION */
+ return(success = seton(&dialcnf));
+
+ case XYDCVT: /* CONVERT-DIRECTORY */
+ if ((y = cmkey(dcnvtab,3,"","ask",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ dialcvt = y;
+ return(success = 1);
+
+ case XYDLCC: /* DIAL COUNTRY-CODE */
+ x = dialstr(&diallcc,"Country code you are calling from");
+ if (x < 1) return(x);
+ if (diallcc) {
+ if (!rdigits(diallcc)) {
+ printf("?Sorry, country code must be numeric\n");
+ if (*diallcc == '+')
+ printf("(please omit the plus sign)\n");
+ if (diallcc) free(diallcc);
+ diallcc = NULL;
+ return(-9);
+ }
+ if (!strcmp(diallcc,"1")) { /* Set defaults for USA and Canada */
+ if (!dialldp) /* Long-distance prefix */
+ makestr(&dialldp,"1");
+ if (!dialixp) /* International dialing prefix */
+ makestr(&dialixp,"011");
+ if (ntollfree == 0) { /* Toll-free area codes */
+ if ((dialtfc[0] = malloc(4))) {
+ strcpy(dialtfc[0],"800"); /* 1970-something */
+ ntollfree++;
+ if ((dialtfc[1] = malloc(4))) {
+ strcpy(dialtfc[1],"888"); /* 1996 */
+ ntollfree++;
+ if ((dialtfc[2] = malloc(4))) {
+ strcpy(dialtfc[2],"877"); /* 5 April 1998 */
+ ntollfree++;
+ if ((dialtfc[3] = malloc(4))) {
+ strcpy(dialtfc[3],"866"); /* 2000? */
+ ntollfree++;
+ }
+ }
+ }
+ }
+ }
+ if (!dialtfp) /* Toll-free dialing prefix */
+ makestr(&dialtfp,"1");
+#ifdef COMMENT
+/* The time for this is past */
+ } else if (!strcmp(diallcc,"358") &&
+ ((int) strcmp(zzndate(),"19961011") > 0)
+ ) { /* Finland */
+ if (!dialldp) /* Long-distance prefix */
+ makestr(&dialldp,"9");
+ if (!dialixp) /* International dialing prefix */
+ makestr(&dialixp,"990");
+#endif /* COMMENT */
+ } else { /* Everywhere else ... */
+ if (!dialldp) {
+ if ((dialldp = malloc(4)))
+ strcpy(dialldp,"0");
+ }
+ if (!dialixp) {
+ if ((dialixp = malloc(4)))
+ strcpy(dialixp,"00");
+ }
+ }
+ if (!strcmp(diallcc,"33")) /* France */
+ dialfld = 1; /* Long-distance dialing is forced */
+ }
+ return(success = 1);
+
+ case XYDIXP: /* DIAL INTL-PREFIX */
+ return(dialstr(&dialixp,"International dialing prefix"));
+
+ case XYDIXS: /* DIAL INTL-SUFFIX */
+ return(dialstr(&dialixs,"International dialing suffix"));
+
+ case XYDLDP: /* DIAL LD-PREFIX */
+ return(dialstr(&dialldp,"Long-distance dialing prefix"));
+
+ case XYDLDS: /* DIAL LD-SUFFIX */
+ return(dialstr(&diallds,"Long-distance dialing suffix"));
+
+ case XYDLCP: /* DIAL LC-PREFIX */
+ return(dialstr(&diallcp,"Local dialing prefix"));
+
+ case XYDLCS: /* DIAL LC-SUFFIX */
+ return(dialstr(&diallcs,"Local dialing suffix"));
+
+#ifdef COMMENT
+ case XYDPXX: /* DIAL PBX-EXCHANGE */
+ return(dialstr(&dialpxx,"Exchange of PBX you are calling from"));
+#endif /* COMMENT */
+
+ case XYDPXI: { /* DIAL PBX-INTERNAL-PREFIX */
+#ifdef COMMENT
+ return(dialstr(&dialpxi,
+ "Internal-call prefix of PBX you are calling from"));
+#else
+ int x;
+ if ((x = cmtxt("Internal-call prefix of PBX you are calling from",
+ "",&s,NULL)) < 0) /* Don't evaluate */
+ return(x);
+#ifndef NOSPL
+ if (*s) {
+ char c, * p = tmpbuf;
+ if (*s == '\\') {
+ c = *(s+1);
+ if (isupper(c)) c = tolower(c);
+ if (c != 'f' &&
+ ckstrcmp(s,"\\v(d$px)",8,0) &&
+ ckstrcmp(s,"\\v(d$pxx)",9,0) &&
+ ckstrcmp(s,"\\v(d$p)",7,0)) {
+ x = TMPBUFSIZ;
+ zzstring(s,&p,&x);
+ s = tmpbuf;
+ }
+ }
+ }
+#endif /* NOSPL */
+ makestr(&dialpxi,s);
+ return(1);
+ }
+#endif /* COMMENT */
+
+ case XYDPXO: /* DIAL PBX-OUTSIDE-PREFIX */
+ return(dialstr(&dialpxo,
+ "Outside-line prefix of PBX you are calling from"));
+
+ case XYDSFX: /* DIAL INTL-SUFFIX */
+ return(dialstr(&dialsfx," Telephone number suffix for dialing"));
+
+ case XYDSRT: /* DIAL SORT */
+ return(success = seton(&dialsrt));
+
+ case XYDPXX: /* DIAL PBX-EXCHANGE */
+ case XYDTFC: { /* DIAL TOLL-FREE-AREA-CODE */
+ int n, i; /* (zero or more of them...) */
+ char * p[MAXTOLLFREE]; /* Temporary pointers */
+ char * m;
+ for (n = 0; n < MAXTOLLFREE; n++) {
+ if (n == 0) {
+ m = (y == XYDTFC) ?
+ "Toll-free area code(s) in the country you are calling from"
+ : "Exchange(s) of PBX you are calling from";
+ } else {
+ m = (y == XYDTFC) ?
+ "Another toll-free area code"
+ : "Another PBX exchange";
+ }
+ if ((x = cmfld(m,"",&s,xxstring)) < 0)
+ break;
+ if (s) {
+ int k;
+ k = (int) strlen(s);
+ if (k > 0) {
+ if ((p[n] = malloc(k + 1)))
+ strcpy(p[n], s); /* safe */
+ } else break;
+ } else break;
+ }
+ if (x == -3) { /* Command was successful */
+ int m;
+ m = (y == XYDTFC) ? ntollfree : ndialpxx;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ x = 1;
+ for (i = 0; i < m; i++) { /* Remove old list, if any */
+ if (y == XYDTFC)
+ makestr(&(dialtfc[i]),NULL);
+ else
+ makestr(&(dialpxx[i]),NULL);
+ }
+ if (y == XYDTFC)
+ ntollfree = n; /* New count */
+ else
+ ndialpxx = n;
+ for (i = 0; i < n; i++) { /* New list */
+ if (y == XYDTFC)
+ makestr(&(dialtfc[i]),p[i]);
+ else
+ makestr(&(dialpxx[i]),p[i]);
+ }
+ x = 1;
+ }
+ for (i = 0; i < n; i++)
+ if (p[i]) free(p[i]);
+ return(x);
+ }
+
+ case XYDTFP: /* TOLL-FREE-PREFIX */
+ return(dialstr(&dialtfp,
+ " Long-distance prefix for toll-free dialing"));
+
+ case XYDCON: /* CONNECT */
+ z = -1;
+ if ((y = cmkey(crrtab,ncrr,"","auto",xxstring)) < 0) return(y);
+ if (y != CAR_OFF) /* AUTO or ON? */
+ if ((z = cmkey(qvtab,nqvt,"","verbose",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (z > -1)
+ dialcq = z;
+ dialcon = y;
+ return(success = 1);
+
+ case XYDRSTR: /* RESTRICT */
+ if ((y = cmkey(drstrtab,4,"","none",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ dialrstr = y;
+ return(success = 1);
+
+ case XYDLLAC: { /* Local area-code list */
+ int n, i; /* (zero or more of them...) */
+ char * p[MAXLOCALAC]; /* Temporary pointers */
+ for (n = 0; n < MAXLOCALAC; n++) {
+ if ((x = cmfld(
+ "Area code to which calls from your area are local",
+ "",&s,xxstring)) < 0)
+ break;
+ if (s) {
+ int k;
+ k = (int) strlen(s);
+ if (k > 0) {
+ if ((p[n] = malloc(k + 1)))
+ strcpy(p[n], s); /* safe */
+ } else break;
+ } else break;
+ }
+ if (x == -3) { /* Command was successful */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ for (i = 0; i < nlocalac; i++) /* Remove old list, if any */
+ if (diallcac[i]) {
+ free(diallcac[i]);
+ diallcac[i] = NULL;
+ }
+ nlocalac = n; /* New count */
+ for (i = 0; i < nlocalac; i++) /* New list */
+ diallcac[i] = p[i];
+ return(success = 1);
+ } else { /* Parse error, undo everything */
+ for (i = 0; i < n; i++)
+ if (p[i]) free(p[i]);
+ return(x);
+ }
+ }
+
+ case XYDFLD:
+ return(success = seton(&dialfld));
+
+ case XYDIDT: /* DIAL IGNORE-DIALTONE */
+ return(seton(&dialidt));
+
+ case XYDPAC:
+ y = cmnum(
+ "Milliseconds to pause between each character sent to dialer",
+ "",10,&x,xxstring);
+ return(setnum(&dialpace,x,y,9999));
+
+#ifndef NOSPL
+ case XYDMAC:
+ if ((x = cmfld("Name of macro to execute just prior to dialing",
+ "",&s,xxstring)) < 0) {
+ if (x == -3)
+ s = NULL;
+ else
+ return(x);
+ }
+ if (s) {
+ if (!*s) {
+ s = NULL;
+ } else {
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ }
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ makestr(&dialmac,s);
+ return(success = 1);
+#endif /* NOSPL */
+
+ case XYDPUCC: /* Pulse country codes */
+ case XYDTOCC: { /* Tone country codes */
+ int n, i;
+ char * p[MAXTPCC];
+ char * m;
+ for (n = 0; n < MAXTPCC; n++) {
+ if (n == 0) {
+ m = (y == XYDPUCC) ?
+ "Country code where Pulse dialing is required"
+ : "Country code where Tone dialing is available";
+ } else
+ m = "Another country code";
+ if ((x = cmfld(m,"",&s,xxstring)) < 0)
+ break;
+ if (s) {
+ int k;
+ k = (int) strlen(s);
+ if (k > 0) {
+ if ((p[n] = malloc(k + 1)))
+ strcpy(p[n], s); /* safe */
+ } else break;
+ } else break;
+ }
+ if (x == -3) { /* Command was successful */
+ int m;
+ m = (y == XYDPUCC) ? ndialpucc : ndialtocc;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ x = 1;
+ for (i = 0; i < m; i++) { /* Remove old list, if any */
+ if (y == XYDPUCC)
+ makestr(&(dialpucc[i]),NULL);
+ else
+ makestr(&(dialtocc[i]),NULL);
+ }
+ if (y == XYDPUCC) {
+ ndialpucc = n; /* New count */
+ } else {
+ ndialtocc = n;
+ }
+ for (i = 0; i < n; i++) { /* New list */
+ if (y == XYDPUCC) {
+ makestr(&(dialpucc[i]),p[i]);
+ } else {
+ makestr(&(dialtocc[i]),p[i]);
+ }
+ }
+ x = 1;
+ }
+ for (i = 0; i < n; i++)
+ if (p[i]) free(p[i]);
+ return(x);
+ }
+ case XYDTEST:
+ return(seton(&dialtest));
+
+ default:
+ printf("?Unexpected SET DIAL parameter\n");
+ return(-9);
+ }
+}
+
+#ifndef NOSHOW
+int /* SHOW MODEM */
+shomodem() {
+ MDMINF * p;
+ int x, n, mdm;
+ char c;
+ long zz;
+
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ shmdmlin();
+ printf("\n");
+
+ mdm = (mdmtyp > 0) ? mdmtyp : mdmsav;
+ p = (mdm > 0) ? modemp[mdm] : NULL;
+
+ if (p) {
+ printf(" %s\n\n", dialname ? dialname : p->name);
+
+ printf(" Modem capabilities: ");
+ zz = dialcapas ? dialcapas : p->capas;
+ if (!zz) {
+ printf(" (none)");
+ } else {
+ if (zz & CKD_AT) printf(" AT");
+ if (zz & CKD_V25) printf(" ITU");
+ if (zz & CKD_SB) printf(" SB");
+ if (zz & CKD_EC) printf(" EC");
+ if (zz & CKD_DC) printf(" DC");
+ if (zz & CKD_HW) printf(" HWFC");
+ if (zz & CKD_SW) printf(" SWFC");
+ if (zz & CKD_KS) printf(" KS");
+ if (zz & CKD_TB) printf(" TB");
+ }
+ printf("\n Modem carrier-watch: ");
+ if (carrier == CAR_OFF) printf("off\n");
+ else if (carrier == CAR_ON) printf("on\n");
+ else if (carrier == CAR_AUT) printf("auto\n");
+ else printf("unknown\n");
+
+ printf(" Modem maximum-speed: ");
+ zz = (dialmax > 0L) ? dialmax : p->max_speed;
+ if (zz > 0)
+ printf("%ld bps\n", zz);
+ else
+ printf("(unknown)\n");
+ printf(" Modem error-correction: %s\n", dialec ? "on" : "off");
+ printf(" Modem compression: %s\n", dialdc ? "on" : "off");
+ printf(" Modem speed-matching: %s", mdmspd ? "on" : "off");
+ printf(" (interface speed %s)\n", mdmspd ? "changes" : "is locked");
+ printf(" Modem flow-control: ");
+ if (dialfc == FLO_NONE) printf("none\n");
+ else if (dialfc == FLO_XONX) printf("xon/xoff\n");
+ else if (dialfc == FLO_RTSC) printf("rts/cts\n");
+ else if (dialfc == FLO_AUTO) printf("auto\n");
+ printf(" Modem hangup-method: %s\n",
+ dialmhu ?
+ "modem-command" :
+ "rs232-signal"
+ );
+ printf(" Modem speaker: %s\n", showoff(mdmspk));
+ printf(" Modem volume: %s\n",
+ (mdmvol == 2) ? "medium" : ((mdmvol <= 1) ? "low" : "high"));
+ printf(" Modem kermit-spoof: %s\n", dialksp ? "on" : "off");
+ c = (char) (x = (dialesc ? dialesc : p->esc_char));
+ printf(" Modem escape-character: %d", x);
+ if (isprint(c))
+ printf(" (= \"%c\")",c);
+ printf(
+"\n\nMODEM COMMANDs (* = set automatically by SET MODEM TYPE):\n\n");
+ debug(F110,"show dialini",dialini,0);
+ printf(" %c Init-string: ", dialini ? ' ' : '*' );
+ shods(dialini ? dialini : p->wake_str);
+ printf(" %c Dial-mode-string: ", dialmstr ? ' ' : '*' );
+ shods(dialmstr ? dialmstr : p->dmode_str);
+ n = local ? 19 : 20;
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Dial-mode-prompt: ", dialmprmt ? ' ' : '*' );
+ shods(dialmprmt ? dialmprmt : p->dmode_prompt);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Dial-command: ", dialcmd ? ' ' : '*' );
+ shods(dialcmd ? dialcmd : p->dial_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Compression on: ", dialdcon ? ' ' : '*' );
+ if (!dialdcon)
+ debug(F110,"dialdcon","(null)",0);
+ else
+ debug(F110,"dialdcon",dialdcon,0);
+ shods(dialdcon ? dialdcon : p->dc_on_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Compression off: ", dialdcoff ? ' ' : '*' );
+ shods(dialdcoff ? dialdcoff : p->dc_off_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Error-correction on: ", dialecon ? ' ' : '*' );
+ shods(dialecon ? dialecon : p->ec_on_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Error-correction off: ", dialecoff ? ' ' : '*' );
+ shods(dialecoff ? dialecoff : p->ec_off_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Autoanswer on: ", dialaaon ? ' ' : '*' );
+ shods(dialaaon ? dialaaon : p->aa_on_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Autoanswer off: ", dialaaoff ? ' ' : '*' );
+ shods(dialaaoff ? dialaaoff : p->aa_off_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(" %c Speaker on: ", dialspon ? ' ' : '*' );
+ shods(dialspon ? dialspon : p->sp_on_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Speaker off: ", dialspoff ? ' ' : '*' );
+ shods(dialspoff ? dialspoff : p->sp_off_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Volume low: ", dialvol1 ? ' ' : '*' );
+ shods(dialvol1 ? dialvol1 : p->vol1_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Volume medium: ", dialvol2 ? ' ' : '*' );
+ shods(dialvol2 ? dialvol2 : p->vol2_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Volume high: ", dialvol3 ? ' ' : '*' );
+ shods(dialvol3 ? dialvol3 : p->vol3_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(" %c Hangup-command: ", dialhcmd ? ' ' : '*' );
+ shods(dialhcmd ? dialhcmd : p->hup_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Hardware-flow: ", dialhwfc ? ' ' : '*' );
+ shods(dialhwfc ? dialhwfc : p->hwfc_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Software-flow: ", dialswfc ? ' ' : '*' );
+ shods(dialswfc ? dialswfc : p->swfc_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c No-flow-control: ", dialnofc ? ' ' : '*' );
+ shods(dialnofc ? dialnofc : p->nofc_str);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Pulse: ", dialpulse ? ' ' : '*');
+ shods(dialpulse ? dialpulse : p->pulse);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Tone: ", dialtone ? ' ' : '*');
+ shods(dialtone ? dialtone : p->tone);
+
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Ignore-dialtone: ", dialx3 ? ' ' : '*');
+ shods(dialx3 ? dialx3 : p->ignoredt);
+
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" %c Predial-init: ", dialini2 ? ' ' : '*');
+ shods(dialini2 ? dialini2 : p->ini2);
+
+ if (++n > cmd_rows - 4) if (!askmore()) return(0); else n = 0;
+ printf("\n For more info: SHOW DIAL and SHOW COMMUNICATIONS\n");
+
+ } else if (mdm > 0) {
+ printf("Modem info for \"%s\" not filled in yet\n", gmdmtyp());
+ } else printf(
+" No modem selected, so DIAL and most SET MODEM commands have no effect.\n\
+ Use SET MODEM TYPE to select a modem.\n");
+ return(success = 1);
+}
+#endif /* NOSHOW */
+#endif /* NODIAL */
+
+#ifdef CK_TAPI
+int /* TAPI action commands */
+dotapi() {
+ int x,y;
+ char *s;
+
+ if (!TAPIAvail) {
+ printf("\nTAPI is unavailable on this system.\n");
+ return(-9);
+ }
+ if ((y = cmkey(tapitab,ntapitab,"MS TAPI command","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case XYTAPI_CFG: { /* TAPI CONFIGURE-LINE */
+ extern struct keytab * tapilinetab;
+ extern struct keytab * _tapilinetab;
+ extern int ntapiline;
+ extern int LineDeviceId;
+ int lineID=LineDeviceId;
+ if (TAPIAvail)
+ cktapiBuildLineTable(&tapilinetab, &_tapilinetab, &ntapiline);
+ if (tapilinetab && _tapilinetab && ntapiline > 0) {
+ int i=0, j = 9999, k = -1;
+
+ if ( LineDeviceId == -1 ) {
+ /* Find out what the lowest numbered TAPI device is */
+ /* and use it as the default. */
+ for (i = 0; i < ntapiline; i++ ) {
+ if (tapilinetab[i].kwval < j) {
+ k = i;
+ }
+ }
+ } else {
+ /* Find the LineDeviceId in the table and use that entry */
+ for (i = 0; i < ntapiline; i++ ) {
+ if (tapilinetab[i].kwval == LineDeviceId) {
+ k = i;
+ break;
+ }
+ }
+ }
+ if (k >= 0)
+ s = _tapilinetab[k].kwd;
+ else
+ s = "";
+
+ if ((y = cmkey(_tapilinetab,ntapiline,
+ "TAPI device name",s,xxstring)) < 0)
+ return(y);
+ lineID = y;
+ }
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled\r\n");
+ return(success = 0);
+ }
+#endif /* ISKD */
+ cktapiConfigureLine(lineID);
+ break;
+ }
+ case XYTAPI_DIAL: /* TAPI DIALING-PROPERTIES */
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled\r\n");
+ return(success = 0);
+ }
+#endif /* ISKD */
+ cktapiDialingProp();
+ break;
+ }
+ return(success = 1);
+}
+
+static int /* SET TAPI command options */
+settapi() {
+ int x, y;
+ char *s;
+
+ if (!TAPIAvail) {
+ printf("\nTAPI is unavailable on this system.\n");
+ return(-9);
+ }
+ if ((y = cmkey(settapitab,nsettapitab,"MS TAPI option","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case XYTAPI_USE:
+ return (success = seton(&tapiusecfg));
+ case XYTAPI_LGHT:
+ return (success = seton(&tapilights));
+ case XYTAPI_PRE:
+ return (success = seton(&tapipreterm));
+ case XYTAPI_PST:
+ return (success = seton(&tapipostterm));
+ case XYTAPI_INA:
+ y = cmnum("seconds of inactivity before auto-disconnect",
+ "0",10,&x,xxstring);
+ return(setnum(&tapiinactivity,x,y,65535));
+ case XYTAPI_BNG:
+ y = cmnum("seconds to wait for credit card tone",
+ "8",10,&x,xxstring);
+ return(setnum(&tapibong,x,y,90));
+ case XYTAPI_MAN:
+ return (success = seton(&tapimanual));
+ case XYTAPI_CON: /* TAPI CONVERSIONS */
+ return (success = setonaut(&tapiconv));
+ case XYTAPI_LIN: /* TAPI LINE */
+ x = setlin(XYTAPI_LIN,1,0);
+ if (x > -1) didsetlin++;
+ return(x);
+ case XYTAPI_PASS: { /* TAPI PASSTHROUGH */
+#ifdef NODIAL
+ printf("\n?Modem-dialing not supported\n");
+ return(-9);
+#else /* NODIAL */
+ /* Passthrough became Modem-dialing which is an antonym */
+ success = seton(&tapipass);
+ tapipass = !tapipass;
+ return (success);
+#endif /* NODIAL */
+ }
+ case XYTAPI_LOC: { /* TAPI LOCATION */
+ extern char tapiloc[];
+ extern int tapilocid;
+ int i = 0, j = 9999, k = -1;
+
+ cktapiBuildLocationTable(&tapiloctab, &ntapiloc);
+ if (!tapiloctab || !ntapiloc) {
+ printf("\nNo TAPI Locations are configured for this system\n");
+ return(-9);
+ }
+ if (tapilocid == -1)
+ tapilocid = cktapiGetCurrentLocationID();
+
+ /* Find the current tapiloc entry */
+ /* and use it as the default. */
+ for (k = 0; k < ntapiloc; k++) {
+ if (tapiloctab[k].kwval == tapilocid)
+ break;
+ }
+ if (k >= 0 && k < ntapiloc)
+ s = tapiloctab[k].kwd;
+ else
+ s = "";
+
+ if ((y = cmkey(tapiloctab,ntapiloc, "TAPI location",s,xxstring)) < 0)
+ return(y);
+
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ cktapiFetchLocationInfoByID( y );
+#ifndef NODIAL
+ CopyTapiLocationInfoToKermitDialCmd();
+#endif /* NODIAL */
+ }
+ break;
+ }
+ return(success=1);
+}
+#endif /* CK_TAPI */
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+/* Method for evaluating \%x and \&x[] variables */
+
+static struct keytab varevaltab[] = {
+ { "recursive", 1, 0 },
+ { "simple", 0, 0 }
+};
+static int nvarevaltab = (sizeof(varevaltab) / sizeof(struct keytab));
+
+int
+setvareval() {
+ int x = 0, y = 0;
+ extern int vareval;
+#ifdef DCMDBUF
+ extern int * xvarev;
+#else
+ extern int xvarev[];
+#endif /* DCMDBUF */
+
+ if ((x = cmkey(varevaltab,
+ nvarevaltab,
+ "Method for evaluating \\%x and \\&x[] variables",
+ "",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ xvarev[cmdlvl] = x;
+ vareval = x;
+ return(success = 1);
+}
+
+#ifdef CK_ANSIC /* SET ALARM */
+int
+setalarm(long xx)
+#else
+int
+setalarm(xx) long xx;
+#endif /* CK_ANSIC */
+/* setalarm */ {
+#ifdef COMMENT
+ int yyyy, mm, dd, x;
+ char *s;
+ long zz;
+ char buf[6];
+#endif /* COMMENT */
+ long sec, jd;
+ char xbuf[20], * p;
+
+ debug(F101,"setalarm xx","",xx);
+ ck_alarm = 0L; /* 0 = no alarm (in case of error) */
+ if (xx < 0L) {
+ printf("%ld - illegal value, must be 0 or positive\n", xx);
+ return(-9);
+ }
+ if (xx == 0L) { /* CLEAR ALARM */
+ alrm_date[0] = NUL;
+ alrm_time[0] = NUL;
+ return(1);
+ }
+#ifdef COMMENT
+ x = 8; /* Get current date */
+ s = alrm_date;
+ if (zzstring("\\v(ndate)",&s,&x) < 0) {
+ printf("Internal date error, sorry.\n");
+ alrm_date[0] = SP;
+ return(-9);
+ }
+ x = 5; /* Get current time */
+ s = alrm_time;
+ if (zzstring("\\v(ntime)",&s,&x) < 0) {
+ printf("Internal time error, sorry.\n");
+ alrm_time[0] = SP;
+ return(-9);
+ }
+ sprintf(buf,"%05ld",atol(alrm_time)); /* SAFE (20) */
+ ckstrncpy(alrm_time,buf,8);
+ debug(F110,"SET ALARM date (1)",alrm_date,0);
+ debug(F110,"SET ALARM time (1)",alrm_time,0);
+
+ if ((zz = atol(alrm_time) + xx) < 0L) {
+ printf("Internal time conversion error, sorry.\n");
+ return(-9);
+ }
+ if (zz >= 86400L) { /* Alarm crosses midnight */
+ char d[10]; /* Local date buffer */
+ int lastday; /* Last day of this month */
+
+ ckstrncpy(d,alrm_date,8); /* We'll have to change the date */
+
+ x = (zz / 86400L); /* How many days after today */
+
+ dd = atoi((char *)(d+6)); /* Parse yyyymmdd */
+ d[6] = NUL; /* into yyyy, mm, dd ... */
+ mm = atoi((char *)(d+4));
+ d[4] = NUL;
+ yyyy = atoi((char *)d);
+
+ /* How many days in this month */
+
+ lastday = mdays[mm];
+ if (mm == 2 && yyyy % 4 == 0) /* Works thru 2099 AD... */
+ lastday++;
+
+ if (dd + x > lastday) { /* Dumb loop */
+ int y;
+
+ x -= (mdays[mm] - dd); /* Deduct rest of this month's days */
+
+ /* There's a more elegant way to do this... */
+
+ while (1) {
+ mm++; /* Next month */
+ if (mm > 12) { /* Wrap around */
+ mm = 1; /* Jan, next year */
+ yyyy++;
+ }
+ y = mdays[mm]; /* Days in new month */
+ if (mm == 2 && yyyy % 4 == 0) /* Feb in leap year */
+ y++; /* Works until 2100 AD */
+ if (x - y < 1)
+ break;
+ x -= y;
+ }
+ dd = x; /* Day of alarm month */
+ } else dd += x;
+
+ sprintf(alrm_date,"%04d%02d%02d",yyyy,mm,dd); /* SAFE (24) */
+ zz = zz % 86400L;
+ }
+ sprintf(alrm_time,"%ld",zz); /* SAFE (24) */
+ debug(F110,"SET ALARM date (2)",alrm_date,0);
+ debug(F110,"SET ALARM time (2)",alrm_time,0);
+ ck_alarm = xx;
+#else
+ /* Jul 1998 */
+ ckstrncpy(xbuf,ckcvtdate("",1),20); /* Get current date and time */
+ p = xbuf;
+ ckstrncpy(alrm_date,xbuf,10);
+ alrm_date[8] = NUL;
+ sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
+ debug(F110,"SET ALARM date (1)",alrm_date,0);
+ debug(F101,"SET ALARM time (1)","",sec);
+ if ((sec += xx) < 0L) {
+ printf("Internal time conversion error, sorry.\n");
+ return(-9);
+ }
+ if (sec >= 86400L) { /* Alarm crosses midnight */
+ long days;
+ days = sec / 86400L;
+ jd = mjd(p) + days; /* Get modified Julian date */
+ ckstrncpy(alrm_date,mjd2date(jd),10);
+ sec %= 86400L;
+ }
+ sprintf(alrm_time,"%05ld",sec); /* SAFE (24) */
+ debug(F110,"SET ALARM date (2)",alrm_date,0);
+ debug(F110,"SET ALARM time (2)",alrm_time,0);
+ ck_alarm = 1; /* Alarm is set */
+
+#endif /* COMMENT */
+ return(success = 1);
+}
+#endif /* NOSPL */
+
+#ifndef NOSETKEY
+int
+dosetkey() { /* SET KEY */
+ int x, y;
+ int flag = 0;
+ int kc; /* Key code */
+ char *s; /* Key binding */
+#ifndef NOKVERBS
+ char *p; /* Worker */
+#endif /* NOKVERBS */
+#ifdef OS2
+ extern int os2gks;
+ extern int mskkeys;
+ extern int initvik;
+#endif /* OS2 */
+
+ x_ifnum = 1;
+ y = cmnum("numeric key code, or the word CLEAR,","",10,&kc,xxstring);
+ x_ifnum = 0;
+ if (y < 0) {
+ debug(F111,"SET KEY",atmbuf,y);
+ if (y == -2) { /* Not a valid number */
+ if ((y = strlen(atmbuf)) < 0) /* Check for SET KEY CLEAR */
+ return(-2);
+ if (ckstrcmp(atmbuf,"clear",y,0))
+ return(-2);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ for (y = 0; y < KMSIZE; y++) {
+ keymap[y] = (KEY) y;
+ macrotab[y] = NULL;
+ }
+#ifdef OS2
+ keymapinit(); /* Special OS/2 initializations */
+ initvik = 1; /* Update the VIK table */
+#endif /* OS2 */
+ return(1);
+ } else if (y == -3) { /* SET KEY <Return> */
+ printf(" Press key to be defined: "); /* Prompt for a keystroke */
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+ conbin((char)escape); /* Put terminal in binary mode */
+#ifdef OS2
+ os2gks = 0; /* Turn off Kverb preprocessing */
+#endif /* OS2 */
+ kc = congks(0); /* Get character or scan code */
+#ifdef OS2
+ os2gks = 1; /* Turn on Kverb preprocessing */
+#endif /* OS2 */
+ concb((char)escape); /* Restore terminal to cbreak mode */
+ if (kc < 0) { /* Check for error */
+ printf("?Error reading key\n");
+ return(0);
+ }
+#ifdef OS2
+ shokeycode(kc,-1); /* Show current definition */
+#else
+ shokeycode(kc); /* Show current definition */
+#endif /* OS2 */
+ flag = 1; /* Remember it's a multiline command */
+ } else /* Error */
+ return(y);
+ }
+
+ /* Normal SET KEY <scancode> <value> command... */
+
+#ifdef OS2
+ if (mskkeys)
+ kc = msktock(kc);
+#endif /* OS2 */
+
+ if (kc < 0 || kc >= KMSIZE) {
+ printf("?key code must be between 0 and %d\n", KMSIZE - 1);
+ return(-9);
+ }
+ if (kc == escape) {
+ printf("Sorry, %d is the CONNECT-mode escape character\n",kc);
+ return(-9);
+ }
+#ifdef OS2
+ wideresult = -1;
+#endif /* OS2 */
+ if (flag) {
+ cmsavp(psave,PROMPTL);
+ cmsetp(" Enter new definition: ");
+ cmini(ckxech);
+ cmflgs = 0;
+ prompt(NULL);
+ }
+ def_again:
+ if (flag)
+ cmres();
+ if ((y = cmtxt("key definition,\n\
+or Ctrl-C to cancel this command,\n\
+or Enter to restore default definition",
+ "",&s,NULL)) < 0) {
+ if (flag) /* Handle parse errors */
+ goto def_again;
+ else
+ return(y);
+ }
+ s = brstrip(s);
+#ifndef NOKVERBS
+ p = s; /* Save this place */
+#endif /* NOKVERBS */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else.
+
+ We use this code active for all versions that support SET KEY, even if they
+ don't support \Kverbs, because otherwise \K would behave differently for
+ different versions.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ if (flag) cmsetp(psave);
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#endif /* NOKVERBS */
+
+ if (macrotab[kc]) { /* Possibly free old macro from key. */
+ free((char *)macrotab[kc]);
+ macrotab[kc] = NULL;
+ }
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Reset to default binding */
+ keymap[kc] = (KEY) kc;
+ break;
+ case 1: /* Single character */
+ keymap[kc] = (CHAR) *s;
+ break;
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ debug(F101,"set key kverb lookup",0,y); /* exact match required */
+ if (y > -1) {
+ keymap[kc] = F_KVERB | y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+ keymap[kc] = (KEY) kc;
+ macrotab[kc] = (MACRO) malloc(strlen(s)+1);
+ if (macrotab[kc])
+ strcpy((char *) macrotab[kc], s); /* safe */
+ break;
+ }
+ if (flag) cmsetp(psave);
+#ifdef OS2
+ initvik = 1; /* Update VIK table */
+#endif /* OS2 */
+ return(1);
+}
+#endif /* NOSETKEY */
+
+#ifdef STOPBITS
+struct keytab stoptbl[] = {
+ { "1", 1, 0 },
+ { "2", 2, 0 }
+};
+#endif /* STOPBITS */
+
+static struct keytab sertbl[] = {
+ { "7E1", 0, 0 },
+ { "7E2", 1, 0 },
+ { "7M1", 2, 0 },
+ { "7M2", 3, 0 },
+ { "7O1", 4, 0 },
+ { "7O2", 5, 0 },
+ { "7S1", 6, 0 },
+ { "7S2", 7, 0 },
+#ifdef HWPARITY
+ { "8E1", 9, 0 },
+ { "8E2", 10, 0 },
+#endif /* HWPARITY */
+ { "8N1", 8, 0 },
+#ifdef HWPARITY
+ { "8N2", 11, 0 },
+ { "8O1", 12, 0 },
+ { "8O2", 13, 0 },
+#endif /* HWPARITY */
+ { "", 0, 0 }
+};
+static int nsertbl = (sizeof(sertbl) / sizeof(struct keytab)) - 1;
+
+static char * sernam[] = { /* Keep this in sync with sertbl[] */
+ "7E1", "7E2", "7M1", "7M2", "7O1", "7O2", "7S1", "7S2",
+ "8N1", "8E1", "8E2", "8N2", "8O1", "8O2"
+};
+
+static struct keytab optstab[] = { /* SET OPTIONS table */
+#ifndef NOFRILLS
+ { "delete", XXDEL, 0}, /* DELETE */
+#endif /* NOFRILLS */
+ { "directory", XXDIR, 0}, /* DIRECTORY */
+#ifdef CKPURGE
+ { "purge", XXPURGE, 0}, /* PURGE */
+#endif /* CKPURGE */
+ { "type", XXTYP, 0}, /* TYPE */
+ { "", 0, 0}
+};
+static int noptstab = (sizeof(optstab) / sizeof(struct keytab)) - 1;
+
+#ifndef NOXFER
+/*
+ PROTOCOL SELECTION. Kermit is always available. If CK_XYZ is defined at
+ compile time, then the others become selections also. In OS/2 and
+ Windows, they are integrated and the various SET commands (e.g. "set file
+ type") affect them as they would Kermit. In other OS's (UNIX, VMS, etc),
+ they are external protocols which are run via Kermit's REDIRECT mechanism.
+ All we do is collect and verify the filenames and pass them along to the
+ external protocol.
+*/
+struct keytab protos[] = {
+#ifdef CK_XYZ
+ "g", PROTO_G, CM_INV,
+#endif /* CK_XYZ */
+ "kermit", PROTO_K, 0,
+#ifdef CK_XYZ
+ "other", PROTO_O, 0,
+ "x", PROTO_X, CM_INV|CM_ABR,
+ "xmodem", PROTO_X, 0,
+ "xmodem-crc", PROTO_XC, 0,
+ "y", PROTO_Y, CM_INV|CM_ABR,
+ "ymodem", PROTO_Y, 0,
+ "ymodem-g", PROTO_G, 0,
+ "zmodem", PROTO_Z, 0
+#endif /* CK_XYZ */
+};
+int nprotos = (sizeof(protos) / sizeof(struct keytab));
+
+#ifndef XYZ_INTERNAL
+#ifndef NOPUSH
+#define EXP_HANDLER 1
+#define EXP_STDERR 2
+#define EXP_TIMO 3
+
+static struct keytab extprotab[] = {
+ { "handler", EXP_HANDLER, 0 },
+ { "redirect-stderr", EXP_STDERR, 0 },
+ { "timeout", EXP_TIMO, 0 }
+};
+static int nxtprotab = (sizeof(extprotab) / sizeof(struct keytab));
+#endif /* NOPUSH */
+#endif /* XYZ_INTERNAL */
+
+#define XPCMDLEN 71
+
+_PROTOTYP(static int protofield, (char *, char *, char *));
+_PROTOTYP(static int setproto, (void));
+
+static int
+protofield(current, help, px) char * current, * help, * px; {
+
+ char *s, tmpbuf[XPCMDLEN+1];
+ int x;
+
+ if (current) /* Put braces around default */
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"{",current,"}",NULL);
+ else
+ tmpbuf[0] = NUL;
+
+ if ((x = cmfld(help, (char *)tmpbuf, &s, xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) > XPCMDLEN) {
+ printf("?Sorry - maximum length is %d\n", XPCMDLEN);
+ return(-9);
+ } else if (*s) {
+ strcpy(px,s); /* safe */
+ } else {
+ px = NULL;
+ }
+ return(x);
+}
+
+static int
+setproto() { /* Select a file transfer protocol */
+ /* char * s = NULL; */
+ int x = 0, y;
+ char s1[XPCMDLEN+1], s2[XPCMDLEN+1], s3[XPCMDLEN+1];
+ char s4[XPCMDLEN+1], s5[XPCMDLEN+1], s6[XPCMDLEN+1], s7[XPCMDLEN+1];
+ char * p1 = s1, * p2 = s2, *p3 = s3;
+ char * p4 = s4, * p5 = s5, *p6 = s6, *p7 = s7;
+
+#ifdef XYZ_INTERNAL
+ extern int p_avail;
+#else
+#ifndef CK_REDIR
+ x = 1;
+#endif /* CK_REDIR */
+#endif /* XYZ_INTERNAL */
+ s1[0] = NUL;
+ s2[0] = NUL;
+ s3[0] = NUL;
+ s4[0] = NUL;
+ s5[0] = NUL;
+ s6[0] = NUL;
+
+ if ((y = cmkey(protos,nprotos,"","kermit",xxstring)) < 0)
+ return(y);
+
+ if (x && y != PROTO_K) {
+ printf(
+ "?Sorry, REDIRECT capability required for external protocols.\n");
+ return(-9);
+ }
+ if ((x = protofield(ptab[y].h_b_init,
+ "Optional command to send to host prior to uploading in binary mode",
+ p1)) < 0) {
+ if (x == -3) {
+ protocol = y; /* Set protocol but don't change */
+ return(1); /* anything else */
+ } else
+ return(x);
+ }
+ if ((x = protofield(ptab[y].h_t_init,
+ "Optional command to send to host prior to uploading in text mode",
+ p2)) < 0) {
+ if (x == -3)
+ goto protoexit;
+ else
+ return(x);
+ }
+
+ if (y == PROTO_K) {
+ if ((x = protofield(ptab[y].h_x_init,
+ "Optional command to send to host to start Kermit server",
+ p3)) < 0) {
+ if (x == -3)
+ goto protoexit;
+ else
+ return(x);
+ }
+ }
+
+
+#ifndef XYZ_INTERNAL /* If XYZMODEM are external... */
+
+ if (y != PROTO_K) {
+ if ((x = protofield(ptab[y].p_b_scmd,
+ "External command to SEND in BINARY mode with this protocol",
+ p4)) < 0) {
+ if (x == -3)
+ goto protoexit;
+ else
+ return(x);
+ }
+ if ((x = protofield(ptab[y].p_t_scmd,
+ "External command to SEND in TEXT mode with this protocol",
+ p5)) < 0) {
+ if (x == -3)
+ goto protoexit;
+ else
+ return(x);
+ }
+ if ((x = protofield(ptab[y].p_b_rcmd,
+ "External command to RECEIVE in BINARY mode with this protocol",
+ p6)) < 0) {
+ if (x == -3)
+ goto protoexit;
+ else
+ return(x);
+ }
+ if ((x = protofield(ptab[y].p_t_rcmd,
+ "External command to RECEIVE in TEXT mode with this protocol",
+ p7)) < 0) {
+ if (x == -3)
+ goto protoexit;
+ else
+ return(x);
+ }
+ }
+#endif /* XYZ_INTERNAL */
+
+ if ((x = cmcfm()) < 0) /* Confirm the command */
+ return(x);
+
+protoexit: /* Common exit from this routine */
+
+#ifdef XYZ_INTERNAL
+ if (!p_avail) {
+ bleep(BP_WARN);
+ printf("\n?X,Y, and Zmodem are unavailable\n");
+ return(success = 0);
+ }
+#endif /* XYZ_INTERNAL */
+
+ p1 = brstrip(p1);
+ p2 = brstrip(p2);
+ p3 = brstrip(p3);
+ p4 = brstrip(p4);
+ p5 = brstrip(p5);
+ p6 = brstrip(p6);
+ p7 = brstrip(p7);
+ initproto(y,p1,p2,p3,p4,p5,p6,p7);
+ return(success = 1);
+}
+
+#ifndef NOPUSH
+#ifndef XYZ_INTERNAL
+
+#define DEF_EXP_TIMO 12 /* Default timeout for external protocol (seconds) */
+
+int exp_handler = 0; /* These are exported */
+int exp_timo = DEF_EXP_TIMO;
+int exp_stderr = SET_AUTO;
+
+VOID
+shoextern() { /* Invoked by SHOW PROTOCOL */
+ printf("\n External-protocol handler: %s\n",
+ exp_handler ? (exp_handler == 1 ? "pty" : "system") : "automatic");
+#ifdef COMMENT
+ printf(" External-protocol redirect-stderr: %s\n", showooa(exp_stderr));
+#endif /* COMMENT */
+ printf(" External-protocol timeout: %d (sec)\n", exp_timo);
+}
+
+static struct keytab setexternhandler[] = {
+ { "automatic", 0, 0 },
+ { "pty", 1, 0 },
+ { "system", 2, 0 }
+};
+
+int
+setextern() { /* SET EXTERNAL-PROTOCOL */
+ int x, y;
+ if ((x = cmkey(extprotab,nxtprotab,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case EXP_HANDLER:
+ if ((x = cmkey(setexternhandler,3,"","automatic",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ exp_handler = x;
+ break;
+
+#ifdef COMMENT
+ case EXP_STDERR:
+ if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ exp_stderr = x;
+ break;
+#endif /* COMMENT */
+
+ case EXP_TIMO:
+ y = cmnum("Inactivity timeout, seconds,",ckitoa(DEF_EXP_TIMO),
+ 10,&x,xxstring);
+ return(setnum(&exp_timo,x,y,-1));
+ }
+ return(success = 1);
+}
+#endif /* XYZ_INTERNAL */
+#endif /* NOPUSH */
+
+int
+setdest() {
+ int x, y;
+ if ((y = cmkey(desttab,ndests,"","disk",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ dest = y;
+ return(1);
+}
+#endif /* NOXFER */
+
+#ifdef DECNET
+struct keytab dnettab[] = {
+#ifndef OS2ONLY
+ "cterm", NP_CTERM, 0,
+#endif /* OS2ONLY */
+ "lat", NP_LAT, 0
+};
+int ndnet = (sizeof(dnettab) / sizeof(struct keytab));
+#endif /* DECNET */
+
+/* S E T P R I N T E R -- SET PRINTER command */
+
+#ifdef PRINTSWI
+static struct keytab prntab[] = { /* SET PRINTER switches */
+ "/bidirectional", PRN_BID, 0,
+#ifdef OS2
+ "/character-set", PRN_CS, CM_ARG,
+#endif /* OS2 */
+ "/command", PRN_PIP, CM_ARG,
+ "/dos-device", PRN_DOS, CM_ARG,
+ "/end-of-job-string",PRN_TRM, CM_ARG,
+ "/file", PRN_FIL, CM_ARG,
+#ifdef BPRINT
+ "/flow-control", PRN_FLO, CM_ARG,
+#endif /* BPRINT */
+ "/job-header-file", PRN_SEP, CM_ARG,
+#ifdef OS2
+ "/length", PRN_LEN, CM_ARG,
+#endif /* OS2 */
+ "/none", PRN_NON, 0,
+#ifdef OS2
+ "/nopostscript", PRN_RAW, 0,
+ "/nops", PRN_RAW, CM_INV,
+#endif /* OS2 */
+ "/output-only", PRN_OUT, 0,
+#ifdef BPRINT
+ "/parity", PRN_PAR, CM_ARG,
+#endif /* BPRINT */
+ "/pipe", PRN_PIP, CM_ARG|CM_INV,
+#ifdef OS2
+ "/postscript", PRN_PS, 0,
+ "/ps", PRN_PS, CM_INV,
+#endif /* OS2 */
+ "/separator", PRN_SEP, CM_ARG|CM_INV,
+#ifdef BPRINT
+ "/speed", PRN_SPD, CM_ARG,
+#endif /* BPRINT */
+ "/timeout", PRN_TMO, CM_ARG,
+ "/terminator", PRN_TRM, CM_ARG|CM_INV,
+#ifdef OS2
+#ifdef NT
+ "/w", PRN_WIN, CM_ARG|CM_ABR|CM_INV,
+ "/wi", PRN_WIN, CM_ARG|CM_ABR|CM_INV,
+#endif /* NT */
+ "/width", PRN_WID, CM_ARG,
+#endif /* OS2 */
+#ifdef NT
+ "/windows-queue", PRN_WIN, CM_ARG,
+#endif /* NT */
+ "", 0, 0
+};
+int nprnswi = (sizeof(prntab) / sizeof(struct keytab)) - 1;
+#endif /* PRINTSWI */
+
+static int
+setprinter(xx) int xx; {
+ int x, y;
+ char * s;
+ char * defname = NULL;
+#ifdef OS2
+ extern int prncs;
+#endif /* OS2 */
+
+#ifdef BPRINT
+ char portbuf[64];
+ long portspeed = 0L;
+ int portparity = 0;
+ int portflow = 0;
+#endif /* BPRINT */
+
+#ifdef PRINTSWI
+ int c, i, n, wild, confirmed = 0; /* Workers */
+ int getval = 0; /* Whether to get switch value */
+ struct stringint pv[PRN_MAX+1]; /* Temporary array for switch values */
+ struct FDB sw, of, cm; /* FDBs for each parse function */
+ int haveque = 0;
+ int typeset = 0;
+#endif /* PRINTSWI */
+
+#ifdef NT
+ struct keytab * printtab = NULL, * _printtab = NULL;
+ int nprint = 0, printdef=0;
+#endif /* NT */
+
+#ifdef OS2
+ defname = "PRN"; /* default */
+#else
+#ifdef VMS
+ defname = "LPT:";
+#else
+#ifdef UNIX
+ defname = "|lpr";
+#endif /* UNIX */
+#endif /* VMS */
+#endif /* OS2 */
+
+#ifdef PRINTSWI
+#ifdef NT
+ haveque = Win32EnumPrt(&printtab,&_printtab,&nprint,&printdef);
+ haveque = haveque && nprint;
+#endif /* NT */
+
+ for (i = 0; i <= PRN_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = -1; /* and -1 int values */
+ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
+ }
+ if (xx == XYBDCP) { /* SET BPRINTER == /BIDIRECTIONAL */
+ pv[PRN_BID].ival = 1;
+ pv[PRN_OUT].ival = 0;
+ }
+
+ /* Initialize defaults based upon current printer settings */
+ if (printername) {
+ defname = printername;
+ switch (printertype) {
+ case PRT_WIN: pv[PRN_WIN].ival = 1; break;
+ case PRT_DOS: pv[PRN_DOS].ival = 1; break;
+ case PRT_PIP: pv[PRN_PIP].ival = 1; break;
+ case PRT_FIL: pv[PRN_FIL].ival = 1; break;
+ case PRT_NON: pv[PRN_NON].ival = 1; break;
+ }
+ }
+#ifdef BPRINT
+ /* only set the BIDI flag if we are bidi */
+ if (printbidi)
+ pv[PRN_BID].ival = 1;
+
+ /* serial port parameters may be set for non-bidi devices */
+ pv[PRN_SPD].ival = pportspeed / 10L;
+ pv[PRN_PAR].ival = pportparity;
+ pv[PRN_FLO].ival = pportflow;
+#endif /* BPRINT */
+ if (printtimo)
+ pv[PRN_TMO].ival = printtimo;
+ if (printterm) {
+ pv[PRN_TRM].ival = 1;
+ makestr(&pv[PRN_TRM].sval,printterm);
+ }
+ if (printsep) {
+ pv[PRN_SEP].ival = 1;
+ makestr(&pv[PRN_SEP].sval,printsep);
+ }
+ if (txt2ps) {
+ pv[PRN_PS].ival = 1;
+ pv[PRN_WID].ival = ps_width;
+ pv[PRN_LEN].ival = ps_length;
+ } else {
+ pv[PRN_RAW].ival = 1;
+ }
+
+ /* Set up chained parse functions... */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nprnswi, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ prntab, /* Keyword table */
+ &cm /* Pointer to next FDB */
+ );
+ cmfdbi(&cm, /* Second fdb for confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ &of
+ );
+ cmfdbi(&of, /* Third FDB for printer name */
+ _CMOFI, /* fcode */
+ "Printer or file name", /* hlpmsg */
+ defname, /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ NULL, /* Nothing */
+ NULL
+ );
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse switch or other thing */
+ debug(F101,"setprinter cmfdb","",x);
+ if (x < 0) /* Error */
+ goto xsetprn; /* or reparse needed */
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ if (cmresult.fdbaddr != &sw) /* Advanced usage :-) */
+ break;
+ c = cmgbrk(); /* Get break character */
+ getval = (c == ':' || c == '='); /* to see how they ended the switch */
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"setprinter switch","",n);
+
+ switch (n) { /* Process the switch */
+ case PRN_PS: /* Text to Postscript */
+ pv[PRN_PS].ival = 1;
+ pv[PRN_BID].ival = 0;
+ pv[PRN_OUT].ival = 1;
+ pv[PRN_RAW].ival = 0;
+ break;
+
+ case PRN_RAW: /* Non-Postscript */
+ pv[PRN_PS].ival = 0;
+ pv[PRN_RAW].ival = 1;
+ break;
+
+ case PRN_BID: /* Bidirectional */
+ pv[PRN_BID].ival = 1;
+ pv[PRN_OUT].ival = 0;
+ pv[PRN_PS].ival = 0;
+ pv[PRN_RAW].ival = 1;
+ break;
+
+ case PRN_OUT: /* Output-only */
+ pv[PRN_OUT].ival = 1;
+ pv[PRN_BID].ival = 0;
+ pv[PRN_PS].ival = 0;
+ pv[PRN_RAW].ival = 1;
+ break;
+
+ case PRN_NON: /* NONE */
+ typeset++;
+ pv[n].ival = 1;
+ pv[PRN_SPD].ival = 0;
+ pv[PRN_PAR].ival = 0;
+ pv[PRN_FLO].ival = FLO_KEEP;
+ break;
+
+#ifdef UNIX
+ case PRN_WIN:
+#endif /* UNIX */
+ case PRN_DOS: /* DOS printer name */
+ case PRN_FIL: /* Or filename */
+ case PRN_PIP:
+ typeset++;
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = NULL;
+ pv[PRN_NON].ival = 0; /* Zero any previous selections */
+ pv[PRN_WIN].ival = 0;
+ pv[PRN_DOS].ival = 0;
+ pv[PRN_FIL].ival = 0;
+ pv[PRN_PIP].ival = 0;
+ pv[n].ival = 1; /* Flag this one */
+ if (!getval) break; /* No value wanted */
+
+ if (n == PRN_FIL) { /* File, check accessibility */
+ int wild = 0;
+ if ((x = cmiofi("Filename","kermit.prn",&s,&wild,xxstring))< 0)
+ if (x == -9) {
+ if (zchko(s) < 0) {
+ printf("Can't create \"%s\"\n",s);
+ return(x);
+ }
+ } else goto xsetprn;
+ if (iswild(s)) {
+ printf("?A single file please\n");
+ return(-9);
+ }
+ pv[PRN_SPD].ival = 0;
+ pv[PRN_PAR].ival = 0;
+ pv[PRN_FLO].ival = FLO_KEEP;
+ } else if ((x = cmfld(n == PRN_DOS ? /* Value wanted - parse it */
+ "DOS printer device name" : /* Help message */
+ (n == PRN_PIP ?
+ "Program name" :
+ "Filename"),
+ n == PRN_DOS ?
+ "PRN" : /* Default */
+ "",
+ &s,
+ xxstring
+ )) < 0)
+ goto xsetprn;
+ s = brstrip(s); /* Strip enclosing braces */
+ while (*s == SP) /* Strip leading blanks */
+ s++;
+ if (n == PRN_PIP) { /* If /PIPE: */
+ if (*s == '|') { /* strip any extraneous pipe sign */
+ s++;
+ while (*s == SP)
+ s++;
+ }
+ pv[PRN_SPD].ival = 0;
+ pv[PRN_PAR].ival = 0;
+ pv[PRN_FLO].ival = FLO_KEEP;
+ }
+ if ((y = strlen(s)) > 0) /* Anything left? */
+ if (pv[n].sval = (char *) malloc(y+1)) /* Yes, keep it */
+ strcpy(pv[n].sval,s); /* safe */
+ break;
+#ifdef NT
+ case PRN_WIN: /* Windows queue name */
+ typeset++;
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = NULL;
+ pv[PRN_NON].ival = 0;
+ pv[PRN_DOS].ival = 0;
+ pv[PRN_FIL].ival = 0;
+ pv[n].ival = 1;
+ pv[PRN_SPD].ival = 0;
+ pv[PRN_PAR].ival = 0;
+ pv[PRN_FLO].ival = FLO_KEEP;
+
+ if (!getval || !haveque)
+ break;
+ if ((x = cmkey(_printtab,nprint,"Print queue name",
+ _printtab[printdef].kwd,xxstring)) < 0) {
+ if (x != -2)
+ goto xsetprn;
+
+ if (pv[PRN_WIN].sval) free(pv[PRN_WIN].sval);
+ s = atmbuf;
+ if ((y = strlen(s)) > 0)
+ if (pv[n].sval = (char *)malloc(y+1))
+ strcpy(pv[n].sval,s); /* safe */
+ } else {
+ if (pv[PRN_WIN].sval) free(pv[PRN_WIN].sval);
+ for (i = 0; i < nprint; i++) {
+ if (x == printtab[i].kwval) {
+ s = printtab[i].kwd;
+ break;
+ }
+ }
+ if ((y = strlen(s)) > 0)
+ if (pv[n].sval = (char *)malloc(y+1))
+ strcpy(pv[n].sval,s); /* safe */
+ }
+ break;
+#endif /* NT */
+
+ case PRN_SEP: /* /JOB-HEADER (separator) */
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = NULL;
+ pv[n].ival = 1;
+ if (!getval) break;
+ if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0)
+ goto xsetprn;
+ if (y) {
+ printf("?Wildcards not allowed\n");
+ x = -9;
+ goto xsetprn;
+ }
+ if ((y = strlen(s)) > 0)
+ if (pv[n].sval = (char *) malloc(y+1))
+ strcpy(pv[n].sval,s); /* safe */
+ break;
+
+ case PRN_TMO: /* /TIMEOUT:number */
+ pv[n].ival = 0;
+ if (!getval) break;
+ if ((x = cmnum("Seconds","0",10,&y,xxstring)) < 0)
+ goto xsetprn;
+ if (y > 999) {
+ printf("?Sorry - 999 is the maximum\n");
+ x = -9;
+ goto xsetprn;
+ } else
+ pv[n].ival = y;
+ break;
+
+ case PRN_TRM: /* /END-OF-JOB:string */
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = NULL;
+ pv[n].ival = 1;
+ if (!getval) break;
+ if ((x = cmfld("String (enclose in braces if it contains spaces)",
+ "",&s,xxstring)) < 0)
+ goto xsetprn;
+ s = brstrip(s);
+ if ((y = strlen(s)) > 0)
+ if (pv[n].sval = (char *) malloc(y+1))
+ strcpy(pv[n].sval,s); /* safe */
+ break;
+
+#ifdef BPRINT
+ case PRN_FLO:
+ if (!getval) break;
+ if ((x = cmkey(flotab,nflo,
+ "Serial printer-port flow control",
+ "rts/cts",xxstring)) < 0)
+ goto xsetprn;
+ pv[n].ival = x;
+ break;
+
+#ifndef NOLOCAL
+ case PRN_SPD:
+ if (!getval) break;
+
+ /* TN_COMPORT here too? */
+
+ if ((x = cmkey(spdtab, /* Speed (no default) */
+ nspd,
+ "Serial printer-port interface speed",
+ "9600",
+ xxstring)
+ ) < 0)
+ goto xsetprn;
+ pv[n].ival = x;
+ break;
+#endif /* NOLOCAL */
+
+ case PRN_PAR:
+ pv[n].ival = 0;
+ if (!getval) break;
+ if ((x = cmkey(partbl,npar,"Serial printer-port parity",
+ "none",xxstring)) < 0)
+ goto xsetprn;
+ pv[n].ival = x;
+ break;
+#endif /* BPRINT */
+
+#ifdef OS2
+ case PRN_LEN:
+ if (!getval) break;
+ if ((x = cmnum("PS page length", "66",10,&y,xxstring)) < 0)
+ goto xsetprn;
+ pv[n].ival = y;
+ break;
+
+ case PRN_WID:
+ if (!getval) break;
+ if ((x = cmnum("PS page width", "80",10,&y,xxstring)) < 0)
+ goto xsetprn;
+ pv[n].ival = y;
+ break;
+
+ case PRN_CS:
+ pv[n].ival = 0;
+ if (!getval) break;
+ if ((y = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "auto-print/printscreen character-set",
+ "cp437",xxstring)) < 0)
+ goto xsetprn;
+ pv[n].ival = y;
+ break;
+#endif /* OS2 */
+
+ default:
+ printf("?Unexpected switch value - %d\n",cmresult.nresult);
+ x = -9;
+ goto xsetprn;
+ }
+ }
+ line[0] = NUL; /* Initialize printer name value */
+ switch (cmresult.fcode) { /* How did we get here? */
+ case _CMOFI: /* They typed a filename */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
+ wild = cmresult.nresult; /* Wild flag */
+ if (!typeset) { /* A printer name without a type */
+ pv[PRN_NON].ival = 0; /* is supposed to be treated as */
+ pv[PRN_WIN].ival = 0; /* a DOS or Pipe printer. We */
+ pv[PRN_FIL].ival = 0; /* clear all the flags and let */
+ pv[PRN_PIP].ival = 0; /* the code below dope out the */
+ pv[PRN_DOS].ival = 0; /* type. */
+ }
+#ifdef NT
+ else if (pv[PRN_WIN].ival && lookup(_printtab,line,nprint,&y)) {
+ /* invalid Window Queue name */
+ printf("?invalid Windows Printer Queue name: \"%s\"\r\n",line);
+ x = -9;
+ goto xsetprn;
+ }
+#endif /* NT */
+ if ((x = cmcfm()) < 0) /* Confirm the command */
+ goto xsetprn;
+ break;
+ case _CMCFM: /* They entered the command */
+ if (pv[PRN_DOS].ival > 0)
+ ckstrncpy(line,pv[PRN_DOS].sval ? pv[PRN_DOS].sval : "",LINBUFSIZ);
+ else if (pv[PRN_WIN].ival > 0)
+ ckstrncpy(line,pv[PRN_WIN].sval ? pv[PRN_WIN].sval : "",LINBUFSIZ);
+ else if (pv[PRN_FIL].ival > 0)
+ ckstrncpy(line,pv[PRN_FIL].sval ? pv[PRN_FIL].sval : "",LINBUFSIZ);
+ else if (pv[PRN_PIP].ival > 0)
+ ckstrncpy(line,pv[PRN_PIP].sval ? pv[PRN_PIP].sval : "",LINBUFSIZ);
+ break;
+ default: /* By mistake */
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ x = -9;
+ goto xsetprn;
+ }
+
+#else /* No PRINTSWI */
+
+ if ((x = cmofi("Printer or file name",defname,&s,xxstring)) < 0)
+ return(x);
+ if (x > 1) {
+ printf("?Directory names not allowed\n");
+ return(-9);
+ }
+ while (*s == SP || *s == HT) s++; /* Trim leading whitespace */
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a temporary safe copy */
+ if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
+#endif /* PRINTSWI */
+
+#ifdef IKSD
+ if (inserver && (isguest
+#ifndef NOSERVER
+ || !ENABLED(en_pri)
+#endif /* NOSERVER */
+ )) {
+ printf("Sorry, printing disabled\r\n");
+ return(success = 0);
+ }
+#endif /* ISKD */
+
+#ifdef PRINTSWI
+#ifdef BPRINT
+ if (printbidi) { /* If bidi printing active */
+#ifndef UNIX
+ bprtstop(); /* Stop it before proceeding */
+#endif /* UNIX */
+ printbidi = 0;
+ }
+ if (pv[PRN_SPD].ival > 0) {
+ portspeed = (long) pv[PRN_SPD].ival * 10L;
+ if (portspeed == 70L) portspeed = 75L;
+ }
+ if (pv[PRN_PAR].ival > 0)
+ portparity = pv[PRN_PAR].ival;
+ if (pv[PRN_FLO].ival > 0)
+ portflow = pv[PRN_FLO].ival;
+#endif /* BPRINT */
+#endif /* PRINTSWI */
+
+ s = line; /* Printer name, if given */
+
+#ifdef OS2ORUNIX
+#ifdef PRINTSWI
+ if (pv[PRN_PIP].ival > 0) { /* /PIPE was given? */
+ printpipe = 1;
+ noprinter = 0;
+ if (*s == '|') { /* It might still have a pipe sign */
+ s++; /* if name give later */
+ while (*s == SP) /* so remove it and spaces */
+ s++;
+ }
+ } else
+#endif /* PRINTSWI */
+ if (*s == '|') { /* Or pipe implied by name? */
+ s++; /* Point past pipe sign */
+ while (*s == SP) /* Gobble whitespace */
+ s++;
+ if (*s) {
+ printpipe = 1;
+ noprinter = 0;
+ }
+ } else {
+ printpipe = 0;
+ }
+
+#ifdef PRINTSWI
+#ifdef BPRINT
+ if (printpipe && pv[PRN_BID].ival > 0) {
+ printf("?Sorry, pipes not allowed for bidirectional printer\n");
+ return(-9);
+ }
+#endif /* BPRINT */
+#endif /* PRINTSWI */
+#endif /* OS2ORUNIX */
+
+#ifdef OS2
+ if ( pv[PRN_CS].ival > 0 )
+ prncs = pv[PRN_CS].ival;
+
+ if ( pv[PRN_PS].ival > 0 ) {
+ txt2ps = 1;
+ ps_width = pv[PRN_WID].ival <= 0 ? 80 : pv[PRN_WID].ival;
+ ps_length = pv[PRN_LEN].ival <= 0 ? 66 : pv[PRN_LEN].ival;
+ }
+#endif /* OS2 */
+
+ y = strlen(s); /* Length of name of new print file */
+ if (y > 0
+#ifdef OS2
+ && ((y != 3) || (ckstrcmp(s,"PRN",3,0) != 0))
+#endif /* OS2 */
+ ) {
+ if (printername) { /* Had a print file before? */
+ free(printername); /* Remove its name */
+ printername = NULL;
+ }
+ printername = (char *) malloc(y + 1); /* Allocate space for it */
+ if (!printername) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ strcpy(printername,s); /* (safe) Copy new name to new space */
+ debug(F110,"printername",printername,0);
+ }
+
+#ifdef PRINTSWI
+ /* Set printer type from switches that were given explicitly */
+
+ if (pv[PRN_NON].ival > 0) { /* No printer */
+ printertype = PRT_NON;
+ noprinter = 1;
+ printpipe = 0;
+ } else if (pv[PRN_FIL].ival > 0) { /* File */
+ printertype = PRT_FIL;
+ noprinter = 0;
+ printpipe = 0;
+ } else if (pv[PRN_PIP].ival > 0) { /* Pipe */
+ printertype = PRT_PIP;
+ noprinter = 0;
+ printpipe = 1;
+ } else if (pv[PRN_WIN].ival > 0) { /* Windows print queue */
+ printertype = PRT_WIN;
+ noprinter = 0;
+ printpipe = 0;
+ } else if (pv[PRN_DOS].ival > 0) { /* DOS device */
+ printertype = PRT_DOS;
+ noprinter = 0;
+ printpipe = 0;
+ } else if (line[0]) { /* Name given without switches */
+ noprinter = 0;
+ printertype = printpipe ? PRT_PIP : PRT_DOS;
+#ifdef NT
+ /* was the command SET PRINTER windows-queue ? */
+ y = lookup(_printtab,line,nprint,&x);
+ if (y >= 0) {
+ printertype = PRT_WIN;
+ if (pv[PRN_WIN].sval) free(pv[PRN_WIN].sval);
+ if (printername) { /* Had a print file before? */
+ free(printername); /* Remove its name */
+ printername = NULL;
+ }
+ pv[PRN_WIN].sval = NULL;
+ pv[PRN_WIN].ival = 1;
+ s = printtab[x].kwd; /* Get full new name */
+ if ((y = strlen(s)) > 0) {
+ makestr(&pv[PRN_WIN].sval,s);
+ makestr(&printername,s);
+ if (!printername) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ debug(F110,"printername",printername,0);
+ }
+ } else if ( y == -2 ) {
+ /* Ambiguous Print Queue Name */
+ printf("?Ambiguous printer name provided.\n");
+ return(-9);
+ }
+#endif /* NT */
+ }
+
+#ifdef BPRINT
+ /* Port parameters may be set for non-bidi mode */
+
+ pportspeed = portspeed; /* Set parameters */
+ pportparity = portparity;
+ pportflow = portflow;
+
+ if (pv[PRN_BID].ival > 0) { /* Bidirectional */
+#ifdef UNIX
+ printbidi = 1; /* (just to test parsing...) */
+#else
+ printbidi = bprtstart(); /* Start bidirectional printer */
+#endif /* UNIX */
+ return(success = printbidi);
+ } else
+ printbidi = 0; /* Not BPRINTER, unset flag */
+#endif /* BPRINT */
+
+ if (pv[PRN_TMO].ival > -1) { /* Take care of timeout */
+ printtimo = pv[PRN_TMO].ival;
+ }
+ if (pv[PRN_TRM].ival > 0) { /* Termination string */
+ if (printterm) {
+ free(printterm);
+ printterm = NULL;
+ }
+ if (pv[PRN_TRM].sval)
+ makestr(&printterm,pv[PRN_TRM].sval);
+ }
+ if (pv[PRN_SEP].ival > 0) { /* and separator file */
+ if (printsep) {
+ free(printsep);
+ printsep = NULL;
+ }
+ if (pv[PRN_SEP].sval)
+ makestr(&printsep,pv[PRN_SEP].sval);
+ }
+#endif /* PRINTSWI */
+
+#ifdef UNIXOROSK
+ if (!printpipe
+#ifdef PRINTSWI
+ && !noprinter
+#endif /* PRINTSWI */
+ ) { /* File - check access */
+ if (zchko(s) < 0) {
+ printf("?Access denied - %s\n",s);
+ x = -9;
+ goto xsetprn;
+ }
+ }
+#endif /* UNIXOROSK */
+
+ x = 1; /* Return code */
+
+ xsetprn: /* Common exit */
+#ifdef PRINTSWI
+ for (i = 0; i <= PRN_MAX; i++) { /* Free malloc'd memory */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ }
+#endif /* PRINTSWI */
+ success = (x > 0) ? 1 : 0;
+ return(x);
+}
+
+#ifdef ANYSSH
+/* The SET SSH command */
+
+#define SSH_CMD 1 /* SET SSH COMMAND */
+
+#ifdef SSHBUILTIN /* Built-in SET SSH options */
+#define SSH_ADD 2 /* Add */
+#define SSH_AFW 3 /* Agent-forwarding */
+#define SSH_CHI 4 /* Check Host IP */
+#define SSH_XFW 5 /* X11-forwarding */
+#define SSH_DYF 6 /* Dynamic forwarding */
+#define SSH_GWP 7 /* Gatewa portgs */
+#define SSH_GSS 8 /* GSSAPI */
+#define SSH_KBD 9 /* KBD Interactive Devices */
+#define SSH_K4 10 /* Kerberos 4 */
+#define SSH_K5 11 /* Kerberos 5 */
+#define SSH_SHK 12 /* Strict Host Key Check */
+#define SSH_V1 13 /* SSH V1 */
+#define SSH_V2 14 /* SSH V2 */
+#define SSH_PRP 15 /* Privd port */
+#define SSH_CMP 16 /* Compression */
+#define SSH_XAL 17 /* X Auth Location */
+#define SSH_SHH 18 /* Quiet */
+#define SSH_VER 19 /* Version */
+#define SSH_VRB 20 /* Verbosity level */
+#define SSH_IDF 21 /* Identity File */
+#define SSH_CFG 22 /* Use OpenSSH Config */
+#define SSH_HBT 23 /* Heartbeat Interval */
+#endif /* SSHBUILTIN */
+
+static struct keytab sshtab[] = { /* SET SSH command table */
+#ifdef SSHBUILTIN
+ { "agent-forwarding", SSH_AFW, 0 },
+ { "check-host-ip", SSH_CHI, 0 },
+ { "compression", SSH_CMP, 0 },
+ { "dynamic-forwarding", SSH_DYF, 0 },
+ { "gateway-ports", SSH_GWP, 0 },
+ { "gssapi", SSH_GSS, 0 },
+ { "heartbeat-interval", SSH_HBT, 0 },
+ { "identity-file", SSH_IDF, 0 },
+#ifdef COMMENT
+ { "kbd-interactive-devices", SSH_KBD, 0 },
+#endif /* COMMENT */
+ { "k4", SSH_K4, CM_INV },
+ { "k5", SSH_K5, CM_INV },
+ { "kerberos4", SSH_K4, 0 },
+ { "kerberos5", SSH_K5, 0 },
+ { "krb4", SSH_K4, CM_INV },
+ { "krb5", SSH_K5, CM_INV },
+ { "privileged-port", SSH_PRP, 0 },
+ { "quiet", SSH_SHH, 0 },
+ { "strict-host-key-check", SSH_SHK, 0 },
+ { "use-openssh-config", SSH_CFG, 0 },
+ { "v1", SSH_V1, 0 },
+ { "v2", SSH_V2, 0 },
+ { "verbose", SSH_VRB, 0 },
+ { "version", SSH_VER, 0 },
+ { "x11-forwarding", SSH_XFW, 0 },
+ { "xauth-location", SSH_XAL, 0 },
+#else
+#ifdef SSHCMD
+ { "command", SSH_CMD, 0 },
+#endif /* SSHCMD */
+#endif /* SSHBUILTIN */
+ { "", 0, 0 }
+};
+static int nsshtab = (sizeof(sshtab) / sizeof(struct keytab)) - 1;
+
+#ifdef SSHBUILTIN
+static struct keytab sshver[] = { /* SET SSH VERSION command table */
+ { "1", 1, 0 },
+ { "2", 2, 0 },
+ { "automatic", 0, 0 }
+};
+
+#define SSHA_CRS 1
+#define SSHA_DSA 2
+#define SSHA_GSS 3
+#define SSHA_HOS 4
+#define SSHA_KBD 5
+#define SSHA_K4 6
+#define SSHA_K5 7
+#define SSHA_PSW 8
+#define SSHA_PK 9
+#define SSHA_SKE 10
+#define SSHA_TIS 11
+#define SSHA_EXT 12
+#define SSHA_SRP 13
+
+static struct keytab ssh2aut[] = { /* SET SSH V2 AUTH command table */
+ { "external-keyx", SSHA_EXT, 0 },
+ { "gssapi", SSHA_GSS, 0 },
+ { "hostbased", SSHA_HOS, 0 },
+ { "keyboard-interactive", SSHA_KBD, 0 },
+ { "password", SSHA_PSW, 0 },
+ { "publickey", SSHA_PK, 0 },
+ { "srp-gex-sha1", SSHA_SRP, 0 },
+ { "", 0, 0 }
+};
+static int nssh2aut = (sizeof(ssh2aut) / sizeof(struct keytab)) - 1;
+
+#define SSHF_LCL 1
+#define SSHF_RMT 2
+
+static struct keytab addfwd[] = { /* SET SSH ADD command table */
+ { "local-port-forward", SSHF_LCL, 0 },
+ { "remote-port-forward", SSHF_RMT, 0 },
+ { "", 0, 0 }
+};
+static int naddfwd = (sizeof(addfwd) / sizeof(struct keytab)) - 1;
+
+#define SSH1_CIF 1
+#define SSH1_GNH 2
+#define SSH1_UNH 3
+#define SSH1_K54 4
+
+#define SSH2_CIF 1
+#define SSH2_GNH 2
+#define SSH2_UNH 3
+#define SSH2_ARK 4
+#define SSH2_HKA 5
+#define SSH2_MAC 6
+#define SSH2_AUT 7
+
+static struct keytab sshv1tab[] = { /* SET SSH V1 command table */
+ { "cipher", SSH1_CIF, 0 },
+ { "global-known-hosts-file", SSH1_GNH, 0 },
+ { "k5-reuse-k4-messages", SSH1_K54, CM_INV },
+ { "user-known-hosts-file", SSH1_UNH, 0 },
+ { "", 0, 0 }
+};
+static int nsshv1tab = (sizeof(sshv1tab) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshv2tab[] = { /* SET SSH V2 command table */
+ { "authentication", SSH2_AUT, 0 },
+ { "auto-rekey", SSH2_ARK, 0 },
+ { "ciphers", SSH2_CIF, 0 },
+ { "global-known-hosts-file", SSH2_GNH, 0 },
+ { "hostkey-algorithms", SSH2_HKA, 0 },
+ { "macs", SSH2_MAC, 0 },
+ { "user-known-hosts-file", SSH2_UNH, 0 },
+ { "", 0, 0 }
+};
+static int nsshv2tab = (sizeof(sshv2tab) / sizeof(struct keytab)) - 1;
+
+#define SSHC_3DES 1 /* 3DES */
+#define SSHC_3CBC 2 /* 3DES-CBC */
+#define SSHC_A128 3 /* AES128-CBC */
+#define SSHC_A192 4 /* AES192-CBC */
+#define SSHC_A256 5 /* AES256-CBC */
+#define SSHC_ARC4 6 /* ARCFOUR */
+#define SSHC_FISH 7 /* BLOWFISH */
+#define SSHC_BCBC 9 /* BLOWFISH-CBC */
+#define SSHC_C128 8 /* CAST128-CBC */
+#define SSHC_1DES 10 /* DES */
+
+static struct keytab ssh1ciphers[] = {
+ { "3des", SSHC_3DES, 0 },
+ { "blowfish", SSHC_FISH, 0 },
+ { "des", SSHC_1DES, 0 },
+ { "", 0, 0 }
+};
+static int nssh1ciphers = (sizeof(ssh1ciphers) / sizeof(struct keytab)) - 1;
+
+static struct keytab ssh2ciphers[] = { /* SET SSH V2 CIPHERS command table */
+ { "3des-cbc", SSHC_3DES, 0 },
+ { "aes128-cbc", SSHC_A128, 0 },
+ { "aes192-cbc", SSHC_A192, 0 },
+ { "aes256-cbc", SSHC_A256, 0 },
+ { "arcfour", SSHC_ARC4, 0 },
+ { "blowfish-cbc", SSHC_FISH, 0 },
+ { "cast128-cbc", SSHC_C128, 0 },
+ { "rijndael128-cbc", SSHC_A128, 0 },
+ { "rijndael192-cbc", SSHC_A192, 0 },
+ { "rijndael256-cbc", SSHC_A256, 0 },
+ { "", 0, 0 }
+};
+static int nssh2ciphers = (sizeof(ssh2ciphers) / sizeof(struct keytab)) - 1;
+
+#define SSHM_SHA 1 /* HMAC-SHA1 */
+#define SSHM_SHA_96 2 /* HMAC-SHA1-96 */
+#define SSHM_MD5 3 /* HMAC-MD5 */
+#define SSHM_MD5_96 4 /* HMAC-MD5-96 */
+#define SSHM_RIPE 5 /* HMAC-RIPEMD160 */
+
+static struct keytab ssh2macs[] = { /* SET SSH V2 MACS command table */
+ { "hmac-md5", SSHM_MD5, 0 },
+ { "hmac-md5-96", SSHM_MD5_96, 0 },
+ { "hmac-ripemd160", SSHM_RIPE, 0 },
+ { "hmac-sha1", SSHM_SHA, 0 },
+ { "hmac-sha1-96", SSHM_SHA_96, 0 },
+ { "", 0, 0 }
+};
+static int nssh2macs = (sizeof(ssh2macs) / sizeof(struct keytab)) - 1;
+
+static struct keytab tgtpass[] = {
+ { "tgt-passing", 1, 0, },
+ { "", 0, 0 }
+};
+static int ntgtpass = (sizeof(tgtpass) / sizeof(struct keytab)) - 1;
+
+static struct keytab gssapitab[] = {
+ { "delegate-credentials", 1, 0, },
+ { "key-exchange", 2, CM_INV, },
+ { "", 0, 0 }
+};
+static int ngssapitab = (sizeof(gssapitab) / sizeof(struct keytab)) - 1;
+
+#define HKA_RSA 1
+#define HKA_DSS 2
+
+static struct keytab hkatab[] = {
+ { "ssh-dss", HKA_DSS, 0, },
+ { "ssh-rsa", HKA_RSA, 0, },
+ { "", 0, 0 }
+};
+static int nhkatab = (sizeof(hkatab) / sizeof(struct keytab)) - 1;
+
+int /* SET SSH variables */
+ ssh_afw = 0, /* agent forwarding */
+ ssh_xfw = 0, /* x11 forwarding */
+ ssh_prp = SET_OFF, /* privileged ports */
+ ssh_cmp = 1, /* compression */
+ ssh_shh = 0, /* quiet */
+ ssh_ver = 0, /* protocol version (auto,1,2) */
+ ssh_vrb = 2, /* Report errors */
+ ssh_chkip = 0, /* SSH Check Host IP flag */
+ ssh_gwp = 0, /* gateway ports */
+ ssh_dyf = 0, /* dynamic forwarding */
+ ssh_gsd = 0, /* gssapi delegate credentials */
+ ssh_k4tgt = 0, /* k4 tgt passing */
+ ssh_k5tgt = 0, /* k5 tgt passing */
+ ssh_shk = 2, /* Strict host key (no, yes, ask) */
+ ssh2_ark = 1, /* Auto re-key */
+ ssh_cas = 0, /* command as subsys */
+ ssh_cfg = 0, /* use OpenSSH config? */
+ ssh_gkx = 1, /* gssapi key exchange */
+ ssh_k5_is_k4 = 1, /* some SSH v1 use same codes */
+ ssh_hbt = 0, /* heartbeat (seconds) */
+ ssh_dummy = 0; /* bottom of list */
+
+char /* The following are to be malloc'd */
+ * ssh1_cif = NULL, /* v1 cipher */
+ * ssh2_cif = NULL, /* v2 cipher list */
+ * ssh2_mac = NULL, /* v2 mac list */
+ * ssh2_auth = NULL, /* v2 authentication list */
+ * ssh_hst = NULL, /* hostname */
+ * ssh_prt = NULL, /* port/service */
+ * ssh_cmd = NULL, /* command to execute */
+ * ssh_xal = NULL, /* xauth-location */
+ * ssh1_gnh = NULL, /* v1 global known hosts file */
+ * ssh1_unh = NULL, /* v1 user known hosts file */
+ * ssh2_gnh = NULL, /* v2 global known hosts file */
+ * ssh2_unh = NULL, /* v2 user known hosts file */
+ * ssh2_hka = NULL, /* Host Key Algorithms */
+ * xxx_dummy = NULL;
+
+char * ssh_idf[32] = { /* Identity file list */
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
+};
+char * ssh_tmp[32] = { /* Temp identity file list */
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
+};
+int ssh_idf_n = 0;
+
+extern int ssh_pf_lcl_n,
+ ssh_pf_rmt_n;
+extern struct ssh_pf ssh_pf_lcl[32]; /* Port forwarding structs */
+extern struct ssh_pf ssh_pf_rmt[32]; /* (declared in ckuusr.c) */
+#endif /* SSHBUILTIN */
+
+#ifdef SFTP_BUILTIN
+static struct keytab sftptab[] = {
+ { "end-of-line", XY_SFTP_EOL, 0, },
+ { "remote-character-set", XY_SFTP_RCS, 0, },
+ { "", 0, 0 }
+};
+static int nsftptab = (sizeof(sftptab) / sizeof(struct keytab)) - 1;
+#endif /* SFTP_BUILTIN */
+
+VOID
+shossh() {
+#ifdef SSHBUILTIN
+ int i, n = 0; /* ADD askmore()! */
+
+ printf("\nSSH is built in:\n\n");
+
+ printf(" ssh host: %s\n",showstring(ssh_hst));
+ printf(" ssh port: %s\n",showstring(ssh_prt));
+ printf(" ssh command: %s\n",showstring(ssh_cmd));
+ printf(" ssh agent-forwarding: %s\n",showoff(ssh_afw));
+ printf(" ssh check-host-ip: %s\n",showoff(ssh_chkip));
+ printf(" ssh compression: %s\n",showoff(ssh_cmp));
+ printf(" ssh dynamic-forwarding: %s\n",showoff(ssh_dyf));
+ if (ssh_pf_lcl[0].p1 && ssh_pf_lcl[0].host && ssh_pf_lcl[0].p2) {
+ printf(" ssh forward-local-port: %d %s %d\n",
+ ssh_pf_lcl[0].p1, ssh_pf_lcl[0].host, ssh_pf_lcl[0].p2);
+ for ( n=1;n<ssh_pf_lcl_n;n++ )
+ printf(" : %d %s %d\n",
+ ssh_pf_lcl[n].p1, ssh_pf_lcl[n].host, ssh_pf_lcl[n].p2);
+ } else
+ printf(" ssh forward-local-port: (none)\n");
+ if (ssh_pf_rmt[0].p1 && ssh_pf_rmt[0].host && ssh_pf_rmt[0].p2) {
+ printf(" ssh forward-remote-port: %d %s %d\n",
+ ssh_pf_rmt[0].p1, ssh_pf_rmt[0].host, ssh_pf_rmt[0].p2);
+ for ( n=1;n<ssh_pf_rmt_n;n++ )
+ printf(" : %d %s %d\n",
+ ssh_pf_rmt[n].p1, ssh_pf_rmt[n].host, ssh_pf_rmt[n].p2);
+ } else
+ printf(" ssh forward-remote-port: (none)\n");
+ printf(" ssh gateway-ports: %s\n",showoff(ssh_gwp));
+ printf(" ssh gssapi delegate-credentials: %s\n",showoff(ssh_gsd));
+ printf(" ssh gssapi key-exchange : %s\n",showoff(ssh_gkx));
+ printf(" ssh identity-file: %d\n",ssh_idf_n);
+ for (i = 0; i < ssh_idf_n; i++)
+ printf(" %2d. %s\n",i+1,showstring(ssh_idf[i]));
+ printf(" ssh heartbeat interval: %d\n", ssh_hbt);
+ printf(" ssh k4 tgt-passing: %s\n",showoff(ssh_k4tgt));
+ printf(" ssh k5 tgt-passing: %s\n",showoff(ssh_k5tgt));
+
+ printf(" ssh privileged-port: %s\n",showooa(ssh_prp));
+ printf(" ssh quiet: %s\n",showoff(ssh_shh));
+ printf(" ssh strict-host-key-check: %d\n",ssh_shk);
+ printf(" ssh use-openssh-config: %s\n",showoff(ssh_cfg));
+ printf(" ssh verbose: %d\n",ssh_vrb);
+ printf(" ssh version: %s\n",
+ ssh_ver ? ckitoa(ssh_ver) : "automatic"
+ );
+ printf(" ssh x11-forwarding: %s\n",showooa(ssh_xfw));
+ printf(" ssh xauth-location: %s\n",showstring(ssh_xal));
+ printf("\n");
+ printf(" ssh v1 cipher: %s\n",showstring(ssh1_cif));
+ printf(" ssh v1 global-known-hosts-file: %s\n",showstring(ssh1_gnh));
+ printf(" ssh v1 user-known-hosts-file: %s\n",showstring(ssh1_unh));
+ printf("\n");
+ printf(" ssh v2 authentication: %s\n",showstring(ssh2_auth));
+ printf(" ssh v2 auto-rekey: %s\n",showoff(ssh2_ark));
+ printf(" ssh v2 ciphers: %s\n",showstring(ssh2_cif));
+ printf(" ssh v2 command-as-subsystem: %s\n",showoff(ssh_cas));
+ printf(" ssh v2 global-known-hosts-file: %s\n",showstring(ssh2_gnh));
+ printf(" ssh v2 hostkey-algorithms: %s\n",showstring(ssh2_hka));
+ printf(" ssh v2 mac: %s\n",showstring(ssh2_mac));
+ printf(" ssh v2 user-known-hosts-file: %s\n",showstring(ssh2_unh));
+#else
+#ifdef SSHCMD
+ extern char * sshcmd, * defsshcmd;
+ char * s;
+ s = sshcmd ? sshcmd : defsshcmd;
+ printf("\n SSH is external.\n\n");
+ printf(" ssh command: %s\n",showstring(s));
+#endif /* SSHCMD */
+#endif /* SSHBUILTIN */
+ printf("\n");
+}
+
+static int
+dosetssh() {
+#ifdef SSHCMD
+ extern char * sshcmd;
+#endif /* SSHCMD */
+#ifdef SSHBUILTIN
+#ifndef SSHTEST
+ extern int sl_ssh_xfw_saved, sl_ssh_ver_saved;
+#endif /* SSHTEST */
+#endif /* SSHBUILTIN */
+ int cx, x, y, z;
+ char * s;
+
+ if ((cx = cmkey(sshtab,nsshtab,"","command", xxstring)) < 0)
+ return(cx);
+ switch (cx) {
+#ifdef SSHCMD
+ case SSH_CMD: /* Command */
+ if ((x = cmtxt("Command to start ssh","ssh -e none",
+ &s,xxstring)) < 0)
+ return(x);
+ makestr(&sshcmd,s);
+ return(success = 1);
+#endif /* SSHCMD */
+
+#ifdef SSHBUILTIN
+ case SSH_AFW: /* Agent-forwarding */
+ return(success = seton(&ssh_afw));
+
+ case SSH_CHI: /* Check Host IP */
+ return(success = seton(&ssh_chkip));
+ break;
+
+ case SSH_CMP: /* Compression */
+ return(success = seton(&ssh_cmp));
+
+ case SSH_DYF: /* Dynamic Forwarding */
+ return(success = seton(&ssh_dyf));
+
+ case SSH_GWP: /* Gateway ports */
+ return(success = seton(&ssh_gwp));
+
+ case SSH_GSS: /* GSSAPI */
+ if ((y = cmkey(gssapitab,ngssapitab,"","", xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case 1: /* Delegate credentials */
+ return(success = seton(&ssh_gsd));
+ case 2: /* key-exchange */
+ return(success = seton(&ssh_gkx));
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ return(success = 0);
+
+#ifdef COMMENT
+ case SSH_KBD: /* Kbd Interactive Devices */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ /* TO BE FILLED IN */
+ return(-2);
+#endif /* COMMENT */
+
+ case SSH_K4: /* Kerberos IV */
+ case SSH_K5: /* Kerberos V */
+ if ((y = cmkey(tgtpass,1,"","tgt-passing", xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case 1:
+ return(success = (cx == SSH_K4) ?
+ seton(&ssh_k4tgt) : seton(&ssh_k5tgt));
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ return(success = 0);
+
+ case SSH_PRP: /* Privd port */
+ return(success = seton(&ssh_prp));
+
+ case SSH_SHH: /* Quiet */
+ return(success = seton(&ssh_shh));
+
+ case SSH_SHK: /* Strict Host Key Check */
+ if ((y = cmkey(ooktab,3,"","", xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ ssh_shk = y;
+ return(success = 1);
+
+ case SSH_HBT:
+ x = cmnum("Heartbeat interval, seconds","0",10,&z,xxstring);
+ if (x < 0) return(x);
+ if ((x = cmcfm()) < 0) return(x);
+ ssh_hbt = z;
+ return(success = 1);
+
+ case SSH_V1: /* SSH V1 */
+ if ((y = cmkey(sshv1tab,nsshv1tab,"","", xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case SSH1_K54:
+ return(success = seton(&ssh_k5_is_k4));
+ case SSH1_CIF: /* Not a list */
+ if ((y = cmkey(ssh1ciphers,nssh1ciphers,"","", xxstring)) < 0)
+ if (y != -3)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (y == -3) {
+ makestr(&ssh1_cif,NULL);
+ } else {
+ for (x = 0; x < nssh1ciphers; x++)
+ if (ssh1ciphers[x].kwval == y)
+ break;
+ makestr(&ssh1_cif,ssh1ciphers[x].kwd);
+ }
+ return(1);
+ case SSH1_GNH:
+ case SSH1_UNH:
+ if ((x = cmifi("Filename","",&s,&z,xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ } else {
+ ckstrncpy(line,s,LINBUFSIZ);
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ s = (x == -3) ? NULL : line;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ switch (y) {
+ case SSH1_GNH: makestr(&ssh1_gnh,s); break;
+ case SSH1_UNH: makestr(&ssh1_unh,s); break;
+ }
+ return(1);
+ }
+
+ case SSH_V2: /* SSH V2 */
+ if ((y = cmkey(sshv2tab,nsshv2tab,"","", xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case SSH2_ARK:
+ return(success = seton(&ssh2_ark));
+ case SSH2_AUT: { /* Authentication */
+#define TMPCNT 12
+ int i, j, tmp[TMPCNT];
+ for (i = 0; i < TMPCNT; i++)
+ tmp[i] = 0;
+ for (i = 0; i < TMPCNT; i++) {
+ if ((y = cmkey(ssh2aut,nssh2aut,
+ "Authentication method","",xxstring)) < 0) {
+ if (y == -3)
+ break;
+ return(y);
+ }
+ for (j = 0; j < i; j++) {
+ if (tmp[j] == y) {
+ printf("\r\n?Choice has already been used.\r\n");
+ return(-9);
+ }
+ }
+ tmp[i] = y;
+ }
+ if ((z = cmcfm()) < 0)
+ return(z);
+
+ if (ssh2_auth) {
+ free(ssh2_auth);
+ ssh2_auth = NULL;
+ }
+ if (i > 0) {
+ int len = 0;
+ for (j = 0; j < i; j++) {
+ for (x = 0; x < nssh2aut; x++)
+ if (ssh2aut[x].kwval == tmp[j] && !ssh2aut[x].flgs)
+ break;
+ len += strlen(ssh2aut[x].kwd) + 1;
+ }
+ ssh2_auth = malloc(len);
+ ssh2_auth[0] = '\0';
+ for (j = 0; j < i; j++) {
+ for (x = 0; x < nssh2aut; x++)
+ if (ssh2aut[x].kwval == tmp[j] && !ssh2aut[x].flgs)
+ break;
+ ckstrncat(ssh2_auth,ssh2aut[x].kwd,len);
+ if (j < i - 1)
+ ckstrncat(ssh2_auth,",",len);
+ }
+ }
+ return(success = 1);
+#undef TMPCNT
+ }
+ case SSH2_CIF: {
+#define TMPCNT 12
+ int i, j, tmp[TMPCNT];
+ for (i = 0; i < TMPCNT; i++)
+ tmp[i] = 0;
+
+ for (i = 0; i < TMPCNT; i++) {
+ if ((y = cmkey(ssh2ciphers,nssh2ciphers,
+ "","", xxstring)) < 0) {
+ if (y == -3)
+ break;
+ return(y);
+ }
+ for (j = 0; j < i; j++) {
+ if (tmp[j] == y) {
+ printf("\r\n?Choice has already been used.\r\n");
+ return(-9);
+ }
+ }
+ tmp[i] = y;
+ }
+ if ((z = cmcfm()) < 0)
+ return(z);
+
+ if (ssh2_cif) {
+ free(ssh2_cif);
+ ssh2_cif = NULL;
+ }
+ if (i > 0) {
+ int len = 0;
+ for (j=0; j < i; j++) {
+ for (x = 0; x < nssh2ciphers; x++)
+ if (ssh2ciphers[x].kwval == tmp[j] &&
+ !ssh2ciphers[x].flgs)
+ break;
+ len += strlen(ssh2ciphers[x].kwd) + 1;
+ }
+ ssh2_cif = malloc(len);
+ ssh2_cif[0] = '\0';
+ for (j = 0; j < i; j++) {
+ for (x = 0; x < nssh2ciphers; x++)
+ if (ssh2ciphers[x].kwval == tmp[j] && !ssh2ciphers[x].flgs)
+ break;
+ ckstrncat(ssh2_cif,ssh2ciphers[x].kwd,len);
+ if (j < i - 1)
+ ckstrncat(ssh2_cif,",",len);
+ }
+ }
+ return(success = 1);
+#undef TMPCNT
+ }
+ case SSH2_MAC: {
+#define TMPCNT 12
+ int i, j, tmp[TMPCNT];
+ for (i = 0; i < TMPCNT; i++)
+ tmp[i] = 0;
+
+ for (i = 0; i < TMPCNT; i++) {
+ if ((y = cmkey(ssh2macs,nssh2macs,"","", xxstring)) < 0) {
+ if (y == -3)
+ break;
+ return(y);
+ }
+ for (j = 0; j < i; j++) {
+ if (tmp[j] == y) {
+ printf("\r\n?Choice has already been used.\r\n");
+ return(-9);
+ }
+ }
+ tmp[i] = y;
+ }
+ if ((z = cmcfm()) < 0)
+ return(z);
+
+ if (ssh2_mac) {
+ free(ssh2_mac);
+ ssh2_mac = NULL;
+ }
+ if (i > 0) {
+ int len = 0;
+ for (j = 0; j < i; j++) {
+ for (x = 0; x < nssh2macs; x++)
+ if (ssh2macs[x].kwval == tmp[j] && !ssh2macs[x].flgs)
+ break;
+ len += strlen(ssh2macs[x].kwd) + 1;
+ }
+ ssh2_mac = malloc(len);
+ ssh2_mac[0] = '\0';
+ for (j=0; j < i; j++) {
+ for (x = 0; x < nssh2macs; x++)
+ if (ssh2macs[x].kwval == tmp[j] && !ssh2macs[x].flgs)
+ break;
+ ckstrncat(ssh2_mac,ssh2macs[x].kwd,len);
+ if (j < i - 1)
+ ckstrncat(ssh2_mac,",",len);
+ }
+ }
+ return(success = 1);
+#undef TMPCNT
+ }
+ case SSH2_HKA: {
+#define TMPCNT 12
+ int i, j, tmp[TMPCNT];
+ for (i = 0; i < TMPCNT; i++)
+ tmp[i] = 0;
+
+ for (i = 0; i < TMPCNT; i++) {
+ if ((y = cmkey(hkatab,nhkatab,
+ "","", xxstring)) < 0) {
+ if (y == -3)
+ break;
+ return(y);
+ }
+ for (j = 0; j < i; j++) {
+ if (tmp[j] == y) {
+ printf("\r\n?Choice has already been used.\r\n");
+ return(-9);
+ }
+ }
+ tmp[i] = y;
+ }
+ if ((z = cmcfm()) < 0)
+ return(z);
+
+ if (ssh2_hka) {
+ free(ssh2_hka);
+ ssh2_hka = NULL;
+ }
+ if (i > 0) {
+ int len = 0;
+ for (j=0; j < i; j++) {
+ for (x = 0; x < nhkatab; x++)
+ if (hkatab[x].kwval == tmp[j] &&
+ !hkatab[x].flgs)
+ break;
+ len += strlen(hkatab[x].kwd) + 1;
+ }
+ ssh2_hka = malloc(len);
+ ssh2_hka[0] = '\0';
+ for (j = 0; j < i; j++) {
+ for (x = 0; x < nhkatab; x++)
+ if (hkatab[x].kwval == tmp[j] && !hkatab[x].flgs)
+ break;
+ ckstrncat(ssh2_hka,hkatab[x].kwd,len);
+ if (j < i - 1)
+ ckstrncat(ssh2_hka,",",len);
+ }
+ }
+ return(success = 1);
+#undef TMPCNT
+ }
+ case SSH2_GNH:
+ case SSH2_UNH:
+ if ((x = cmifi("Filename","",&s,&z,xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ } else {
+ ckstrncpy(line,s,LINBUFSIZ);
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ s = (x == -3) ? NULL : line;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ switch (y) {
+ case SSH2_GNH: makestr(&ssh2_gnh,s); break;
+ case SSH2_UNH: makestr(&ssh2_unh,s); break;
+ default: return(success = 0);
+ }
+ return(success = 1);
+ }
+
+ case SSH_VRB: /* Verbosity level */
+ y = cmnum("SSH verbosity level, 0-7","2",10,&x,xxstring);
+ return(setnum(&ssh_vrb,x,y,7));
+
+ case SSH_VER: /* Version */
+ if ((y = cmkey(sshver,3,"","auto", xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ ssh_ver = y; /* 0 == AUTO */
+#ifndef SSHTEST
+ sl_ssh_ver_saved = 0;
+#endif /* SSHTEST */
+ return(success = 1);
+
+ case SSH_IDF: { /* Identity file */
+ int i, n;
+ for (i = 0; i < 32; i++) {
+ if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0) {
+ if (x == -3)
+ break;
+ return(x);
+ }
+ if (!zfnqfp(s,LINBUFSIZ,line))
+ ckstrncpy(line,s,LINBUFSIZ);
+ makestr(&ssh_tmp[i],line);
+ }
+ n = i;
+ if ((x = cmcfm()) < 0) {
+ for (i = 0; i < n; i++)
+ makestr(&(ssh_tmp[i]),NULL);
+ return(x);
+ }
+ for (i = 0; i < 32; i++) {
+ makestr(&(ssh_idf[i]),NULL);
+ if (i < n) {
+ ssh_idf[i] = ssh_tmp[i];
+ ssh_tmp[i] = NULL;
+ } else {
+ makestr(&(ssh_tmp[i]),NULL);
+ }
+ }
+ ssh_idf_n = n;
+ return(success = 1);
+ }
+ case SSH_XFW: /* X11-forwarding */
+ success = seton(&ssh_xfw);
+#ifndef SSHTEST
+ if (success)
+ sl_ssh_xfw_saved = 0;
+#endif /* SSHTEST */
+ return(success);
+
+ case SSH_XAL: /* SSH Xauth Location */
+ if ((x = cmifi("Path to executable", "",&s,&y,xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ } else {
+ ckstrncpy(line,s,LINBUFSIZ);
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ s = (x == -3) ? NULL : line;
+ if ((x = cmcfm()) < 0) return(x);
+ makestr(&ssh_xal,s);
+ return(success = 1);
+
+ case SSH_CFG: /* Use OpenSSH Config */
+ return(success = seton(&ssh_cfg));
+#endif /* SSHBUILTIN */
+
+ default:
+ return(-2);
+ }
+}
+#endif /* ANYSSH */
+
+#ifdef SFTP_BUILTIN
+static int
+dosetsftp() {
+ int cx, x, y, z;
+ char * s;
+
+ if ((cx = cmkey(sftptab,nsftptab,"","", xxstring)) < 0)
+ return(cx);
+ switch (cx) {
+ case XY_SFTP_EOL:
+ case XY_SFTP_RCS:
+ default:
+ return(-2);
+ }
+}
+#endif /* SFTP_BUILTIN */
+
+#ifdef KUI
+#include "ikui.h"
+extern ULONG RGBTable[16];
+
+#define GUI_RGB 1
+#define GUI_WIN 2
+#define GUI_FON 3
+#define GUI_DIA 4
+#define GUI_TLB 5
+#define GUI_MNB 6
+#define GUI_CLS 7
+
+#define GUIW_POS 1
+#define GUIW_RES 2
+#define GUIW_RUN 3
+#define GUIWR_NON 0
+#define GUIWR_FON 1
+#define GUIWR_DIM 2
+#define GUIWN_RES 1
+#define GUIWN_MIN 2
+#define GUIWN_MAX 3
+
+static struct keytab guitab[] = {
+ { "close", GUI_CLS, 0 },
+ { "dialogs", GUI_DIA, 0 },
+ { "font", GUI_FON, 0 },
+ { "menubar", GUI_MNB, 0 },
+ { "rgbcolor", GUI_RGB, 0 },
+ { "toolbar", GUI_TLB, 0 },
+ { "window", GUI_WIN, 0 },
+ { "", 0, 0}
+};
+static int nguitab = (sizeof(guitab) / sizeof(struct keytab));
+
+static struct keytab guiwtab[] = {
+ { "position", GUIW_POS, 0 },
+ { "resize-mode", GUIW_RES, 0 },
+ { "run-mode", GUIW_RUN, 0 },
+ { "", 0, 0}
+};
+static int nguiwtab = (sizeof(guiwtab) / sizeof(struct keytab));
+
+static struct keytab guiwrtab[] = {
+ { "change-dimensions", GUIWR_DIM, 0 },
+ { "none", GUIWR_NON, 0 },
+ { "scale-font", GUIWR_FON, 0 },
+ { "", 0, 0}
+};
+static int nguiwrtab = (sizeof(guiwrtab) / sizeof(struct keytab));
+
+static struct keytab guiwntab[] = {
+ { "maximize", GUIWN_MAX, 0 },
+ { "minimize", GUIWN_MIN, 0 },
+ { "restore", GUIWN_RES, 0 },
+ { "", 0, 0}
+};
+static int nguiwntab = (sizeof(guiwntab) / sizeof(struct keytab));
+
+static struct keytab rgbtab[] = {
+ { "black", 0, 0 },
+ { "blue", 1, 0 },
+ { "brown", 6, 0 },
+ { "cyan", 3, 0 },
+ { "darkgray", 8, 0 },
+ { "dgray", 8, CM_INV },
+ { "green", 2, 0 },
+ { "lblue", 9, CM_INV },
+ { "lcyan", 11, CM_INV },
+ { "lgreen", 10, CM_INV },
+ { "lgray", 7, CM_INV },
+ { "lightblue", 9, 0 },
+ { "lightcyan", 11, 0 },
+ { "lightgreen", 10, 0 },
+ { "lightgray", 7, 0 },
+ { "lightmagenta", 13, 0 },
+ { "lightred", 12, 0 },
+ { "lmagenta", 13, CM_INV },
+ { "lred", 12, CM_INV },
+ { "magenta", 5, 0 },
+ { "red", 4, 0 },
+ { "white", 15, 0 },
+ { "yellow", 14, 0 },
+
+};
+int nrgb = (sizeof(rgbtab) / sizeof(struct keytab));
+
+VOID
+shogui() {
+ extern gui_dialog;
+ extern HWND getHwndKUI();
+ unsigned char cmdsav = colorcmd;
+ int i, red, green, blue, lines=0;
+ char * s;
+
+
+ printf("GUI paramters:\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" Dialogs: %s\n",showoff(gui_dialog));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" Position: %d,%d\n",get_gui_window_pos_x(),
+ get_gui_window_pos_y());
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" Resolution: %d x %d\n",GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" Run-mode: %s\n",IsIconic(getHwndKUI()) ? "minimized" :
+ IsZoomed(getHwndKUI()) ? "maximized" : "restored");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ switch ( get_gui_resize_mode() ) {
+ case GUIWR_NON:
+ s = "none";
+ break;
+ case GUIWR_FON:
+ s = "scales font";
+ break;
+ case GUIWR_DIM:
+ s= "changes dimensions";
+ break;
+ }
+ printf(" Resize-mode: %s\n",s);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ printf("RGB Color Table:\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" Color Red Green Blue\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" ------------------------------------------\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ for (i = 0; i < nrgb; i++) {
+ if (!rgbtab[i].flgs) {
+ blue = (RGBTable[rgbtab[i].kwval] & 0x00FF0000)>>16;
+ green = (RGBTable[rgbtab[i].kwval] & 0x0000FF00)>>8;
+ red = (RGBTable[rgbtab[i].kwval] & 0x000000FF);
+ printf(" %-18s %3d %3d %3d ",rgbtab[i].kwd,red,green,blue);
+ colorcmd = rgbtab[i].kwval << 4;
+ printf("********");
+ colorcmd = cmdsav;
+ printf("\n");
+ if (++lines > cmd_rows - 3) {
+ if (!askmore())
+ return;
+ else
+ lines = 0;
+ }
+ }
+ }
+ printf("\n");
+}
+
+int
+setrgb() {
+ int cx, red = 0, blue = 0, green = 0, z, x;
+
+ if ((cx = cmkey(rgbtab,nrgb,"","",xxstring)) < 0)
+ return(cx);
+ if ((z = cmnum("Red value, 0-255","",10,&red,xxstring)) < 0)
+ return(z);
+ if ((z = cmnum("Green value, 0-255","",10,&green,xxstring)) < 0)
+ return(z);
+ if ((z = cmnum("Blue value, 0-255","",10,&blue,xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (cx > 15 || red > 255 || blue > 255 || green > 255)
+ return(-2);
+ RGBTable[cx] = (unsigned)(((unsigned)blue << 16) |
+ (unsigned)((unsigned)green << 8) |
+ (unsigned)red);
+ return(success = 1);
+}
+
+/*
+ Set GUI window position: XY coordinates of upper left corner,
+ expressed as pixel numbers in the current screen resolution.
+ (0,0) means put ourselves in the upper left corner.
+ Can we check for out of bounds?
+*/
+
+int
+setguiwin() {
+ int cx, x, y, z;
+ if ((cx = cmkey(guiwtab,nguiwtab,"","",xxstring)) < 0)
+ return(cx);
+ switch (cx) {
+ case GUIW_POS:
+ if ((z = cmnum("X coordinate (pixel number)","",10,&x,xxstring)) < 0)
+ return(z);
+ if ((z = cmnum("Y coordinate (pixel number)","",10,&y,xxstring)) < 0)
+ return(z);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ if (x < 0 || y < 0) {
+ printf("?Coordinates must be 0 or greater\n");
+ return(-9);
+ }
+ gui_position(x,y);
+ return(success = 1);
+ case GUIW_RES:
+ if ((x = cmkey(guiwrtab,nguiwrtab,"","",xxstring)) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ gui_resize_mode(x);
+ return(success = 1);
+ case GUIW_RUN:
+ if ((x = cmkey(guiwntab,nguiwntab,"","",xxstring)) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ gui_win_run_mode(x);
+ return(success = 1);
+ default:
+ return(-2);
+ }
+}
+
+int
+setguifont() { /* Assumes that CKFLOAT is defined! */
+
+ extern struct keytab * term_font;
+ extern struct keytab * _term_font;
+ extern int tt_font, tt_font_size, ntermfont;
+ int x, y, z;
+ char *s;
+
+ if (ntermfont == 0)
+ BuildFontTable(&term_font, &_term_font, &ntermfont);
+ if (!(term_font && _term_font && ntermfont > 0)) {
+ printf("?Internal error: Failure to enumerate fonts\n");
+ return(-9);
+ }
+ if ((x = cmkey(_term_font,ntermfont,"","",xxstring)) < 0)
+ return(x);
+ if ((z = cmfld("Height of font in points","12",&s,xxstring)) < 0)
+ return(z);
+ if (isfloat(s,0) < 1) { /* (sets floatval) */
+ printf("?Integer or floating-point number required\n");
+ return(-9);
+ }
+ if (floatval < 0.5) {
+ printf("?Positive number required\n");
+ return(-9);
+ }
+ if ((z = cmcfm()) < 0)
+ return(z);
+ tt_font = x; /* Font index */
+ tt_font_size = (int)(floatval * 2); /* Font size in half points */
+ KuiSetProperty(KUI_TERM_FONT, (long)tt_font, (long)tt_font_size);
+ return(success = 1);
+}
+
+VOID
+setguidialog(x) int x;
+{
+ extern int gui_dialog;
+ gui_dialog = x;
+ KuiSetProperty(KUI_GUI_DIALOGS, (long)x, 0L);
+}
+
+VOID
+setguimenubar(x) int x;
+{
+ KuiSetProperty(KUI_GUI_MENUBAR, (long)x, 0L);
+}
+
+VOID
+setguitoolbar(x) int x;
+{
+ KuiSetProperty(KUI_GUI_TOOLBAR, (long)x, 0L);
+}
+
+VOID
+setguiclose(x) int x;
+{
+ KuiSetProperty(KUI_GUI_CLOSE, (long)x, 0L);
+}
+
+int
+setgui() {
+ int cx, x, rc;
+ if ((cx = cmkey(guitab,nguitab,"","",xxstring)) < 0)
+ return(cx);
+ switch (cx) {
+ case GUI_DIA:
+ rc = seton(&x);
+ if (rc >= 0)
+ setguidialog(x);
+ return(rc);
+ case GUI_FON:
+ return(setguifont());
+ case GUI_RGB:
+ return(setrgb());
+ case GUI_WIN:
+ return(setguiwin());
+ case GUI_TLB:
+ rc = seton(&x);
+ if (rc >= 0)
+ setguitoolbar(x);
+ return(rc);
+ case GUI_MNB:
+ rc = seton(&x);
+ if (rc >= 0)
+ setguimenubar(x);
+ return(rc);
+ case GUI_CLS:
+ rc = seton(&x);
+ if (rc >= 0)
+ setguiclose(x);
+ return(rc);
+ default:
+ return(-2);
+ }
+}
+#endif /* KUI */
+
+VOID
+setexitwarn(x) int x;
+{
+ xitwarn = x;
+#ifdef KUI
+ KuiSetProperty(KUI_EXIT_WARNING, (long)x, 0L);
+#endif /* KUI */
+}
+
+#ifndef NOLOCAL
+VOID
+setdebses(x) int x; {
+#ifdef OS2
+ if ((debses != 0) && (x == 0)) /* It was on and we turned it off? */
+ os2debugoff(); /* Fix OS/2 coloration */
+#endif /* OS2 */
+ debses = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_DEBUG,x,0);
+#endif /* KUI */
+}
+#endif /* NOLOCAL */
+
+/* D O P R M -- Set a parameter. */
+/*
+ Returns:
+ -2: illegal input
+ -1: reparse needed
+ 0: success
+*/
+int
+doprm(xx,rmsflg) int xx, rmsflg; {
+ int i = 0, x = 0, y = 0, z = 0;
+ long zz = 0L;
+ char *s = NULL, *p = NULL;
+#ifdef OS2
+ char portbuf[64];
+ long portspeed = 0L;
+ int portparity = 0;
+ int portflow = 0;
+#endif /* OS2 */
+
+#ifndef NOSETKEY
+#ifdef OS2
+ if (xx == XYMSK)
+ return(setmsk());
+#endif /* OS2 */
+#endif /* NOSETKEY */
+
+ if (xx == XYFLAG) { /* SET FLAG */
+ extern int ooflag;
+ return(success = seton(&ooflag));
+ }
+ if (xx == XYPRTR /* SET PRINTER (or BPRINTER) */
+#ifdef BPRINT
+ || xx == XYBDCP
+#endif /* BPRINT */
+ )
+ return(setprinter(xx));
+
+ switch (xx) {
+
+#ifdef ANYX25 /* SET X25 ... */
+case XYX25:
+ return(setx25());
+
+#ifndef IBMX25
+case XYPAD: /* SET PAD ... */
+ return(setpadp());
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOXFER
+ case XYEOL: /* These have all been moved to set send/receive... */
+ case XYLEN: /* Let the user know what to do. */
+ case XYMARK:
+ case XYNPAD:
+ case XYPADC:
+ case XYTIMO:
+ printf("...Use SET SEND or SET RECEIVE instead.\n");
+ printf("Type HELP SET SEND or HELP SET RECEIVE for more info.\n");
+ return(success = 0);
+
+ case XYATTR: /* File Attribute packets */
+ return(setat(rmsflg));
+
+ case XYIFD: /* Incomplete file disposition */
+ if ((y = cmkey(ifdatab,3,"","auto",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S',
+ "310",
+ y == 0 ? "0" : (y == 1 ? "1" : "2"),
+ ""
+ );
+ return((int) sstate);
+ } else {
+ keep = y;
+ return(success = 1);
+ }
+#endif /* NOXFER */
+
+ case XYMATCH: /* [ REMOTE ] SET MATCH... */
+#ifndef NOXFER
+ if ((z = cmkey(matchtab,nmatchtab,"","",xxstring)) < 0)
+ return(z);
+ if (rmsflg) {
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ switch (z) {
+ case MCH_DOTF:
+ return(sstate = setgen('S',"330", y == 0 ? "0" : "1", ""));
+ case MCH_FIFO:
+ return(sstate = setgen('S',"331", y == 0 ? "0" : "1", ""));
+ default:
+ return(-2);
+ }
+ }
+#endif /* NOXFER */
+ switch (z) {
+ case MCH_FIFO:
+ return(success = seton(&matchfifo));
+ case MCH_DOTF:
+ x = seton(&matchdot);
+ if (x < 0) return(x);
+ dir_dots = -1;
+ return(success = x);
+ default:
+ return(-2);
+ }
+
+#ifndef NOSPL
+ case XYINPU: /* SET INPUT */
+ return(setinp());
+#endif /* NOSPL */
+
+#ifdef NETCONN
+ case XYNET: { /* SET NETWORK */
+
+ struct FDB k1, k2;
+
+ cmfdbi(&k1,_CMKEY,"","","",nnetkey, 0, xxstring, netkey, &k2);
+ cmfdbi(&k2,_CMKEY,"","","",nnets, 0, xxstring, netcmd, NULL);
+
+#ifdef OS2 /* Hide network-type keywords for networks not installed */
+ for (z = 0; z < nnets; z++) {
+ if (netcmd[z].kwval == NET_TCPB && tcp_avail == 0)
+ netcmd[z].flgs = CM_INV;
+#ifdef SSHBUILTIN
+ if (netcmd[z].kwval == NET_SSH &&
+ !ck_ssleay_is_installed())
+ netcmd[z].flgs = CM_INV;
+#endif /* SSHBUILTIN */
+#ifdef DECNET
+ else if (netcmd[z].kwval == NET_DEC && dnet_avail == 0)
+ netcmd[z].flgs = CM_INV;
+#endif /* DECNET */
+#ifdef CK_NETBIOS
+ else if (netcmd[z].kwval == NET_BIOS && netbiosAvail == 0)
+ netcmd[z].flgs = CM_INV;
+#endif /* CK_NETBIOS */
+#ifdef SUPERLAT
+ else if (netcmd[z].kwval == NET_SLAT && slat_avail == 0)
+ netcmd[z].flgs = CM_INV;
+#endif /* SUPERLAT */
+ }
+ if (tcp_avail) /* Default network type */
+ ckstrncpy(tmpbuf,"tcp/ip",TMPBUFSIZ);
+#ifdef SSHBUILTIN
+ else if ( ck_ssleay_is_installed() )
+ ckstrncpy(tmpbuf,"ssh",TMPBUFSIZ);
+#endif /* SSHBUILTIN */
+#ifdef DECNET
+ else if (dnet_avail)
+ ckstrncpy(tmpbuf,"decnet",TMPBUFSIZ);
+#endif /* DECNET */
+#ifdef SUPERLAT
+ else if (slat_avail)
+ ckstrncpy(tmpbuf,"superlat",TMPBUFSIZ);
+#endif /* SUPERLAT */
+#ifdef CK_NETBIOS
+ else if (netbiosAvail)
+ ckstrncpy(tmpbuf,"netbios",TMPBUFSIZ);
+#endif /* CK_NETBIOS */
+ else ckstrncpy(tmpbuf,"named-pipe",TMPBUFSIZ);
+#else /* OS2 */
+#ifdef TCPSOCKET
+ ckstrncpy(tmpbuf,"tcp/ip",TMPBUFSIZ);
+#else
+#ifdef ANYX25
+ ckstrncpy(tmpbuf,"x.25",TMPBUFSIZ);
+#else
+ ckstrncpy(tmpbuf,"",TMPBUFSIZ);
+#endif /* ANYX25 */
+#endif /* TCPSOCKET */
+#endif /* OS2 */
+
+ x = cmfdb(&k1);
+ if (x < 0) { /* Error */
+ if (x == -2 || x == -9)
+ printf("?No keywords match: \"%s\"\n",atmbuf);
+ return(x);
+ }
+ z = cmresult.nresult; /* Keyword value */
+ if (cmresult.fdbaddr == &k1) { /* Which table? */
+#ifndef NOSPL
+#ifndef NODIAL
+ if (z == XYNET_D)
+ return(parsdir(1));
+#endif /* NODIAL */
+#endif /* NOSPL */
+ if ((z = cmkey(netcmd,nnets,"",tmpbuf,xxstring)) < 0)
+ return(z);
+ }
+
+#ifdef NETCMD
+ if (z == NET_CMD && nopush) {
+ printf("\n?Sorry, access to external commands is disabled\n");
+ return(-9);
+ }
+#endif /* NETCMD */
+
+#ifndef NOPUSH
+#ifdef NETPTY
+ if (z == NET_PTY && nopush) {
+ printf("\n?Sorry, access to external commands is disabled\n");
+ return(-9);
+ }
+#endif /* NETPTY */
+#endif /* NOPUSH */
+
+#ifdef OS2
+ if (z == NET_TCPB && tcp_avail == 0) {
+ printf(
+"\n?Sorry, either TCP/IP is not available on this system or\n\
+necessary DLLs did not load. Use SHOW NETWORK to check network status.\n");
+ return(-9);
+#ifdef SSHBUILTIN
+ } else if (z == NET_SSH && !ck_ssleay_is_installed()) {
+ printf("\n?Sorry, SSH is not available on this system.\n") ;
+ return(-9);
+#endif /* SSHBUILTIN */
+#ifdef CK_NETBIOS
+ } else if (z == NET_BIOS && netbiosAvail == 0) {
+ printf("\n?Sorry, NETBIOS is not available on this system.\n") ;
+ return(-9);
+#endif /* CK_NETBIOS */
+#ifdef DECNET
+ } else if (z == NET_DEC && dnet_avail == 0) {
+ printf("\n?Sorry, DECnet is not available on this system.\n") ;
+ return(-9);
+#endif /* DECNET */
+#ifdef SUPERLAT
+ } else if (z == NET_SLAT && slat_avail == 0) {
+ printf("\n?Sorry, SuperLAT is not available on this system.\n") ;
+ return(-9);
+#endif /* SUPERLAT */
+ }
+#endif /* OS2 */
+
+#ifdef NPIPEORBIOS
+ if (z == NET_PIPE || /* Named pipe -- also get pipename */
+ z == NET_BIOS) { /* NETBIOS -- also get local name */
+ char *defnam;
+#ifdef CK_NETBIOS
+ char tmpnbnam[NETBIOS_NAME_LEN+1];
+#endif /* CK_NETBIOS */
+ /* Construct default name */
+ if (z == NET_PIPE) { /* Named pipe */
+ defnam = "kermit"; /* Default name is always "kermit" */
+ }
+#ifdef CK_NETBIOS
+ else { /* NetBIOS */
+ if (NetBiosName[0] != SP) { /* If there is already a name, */
+ char *p = NULL;
+ int n; /* use it as the default. */
+ ckstrncpy(tmpnbnam,NetBiosName,NETBIOS_NAME_LEN+1);
+ /* convert trailing spaces to NULs */
+ p = &tmpnbnam[NETBIOS_NAME_LEN-1];
+ while (*p == SP) {
+ *p = NUL;
+ p--;
+ }
+ defnam = tmpnbnam;
+ } else if (*myhost) /* Otherwise use this PC's host name */
+ defnam = (char *) myhost;
+ else /* Otherwise use "kermit" */
+ defnam = "kermit";
+ }
+#endif /* CK_NETBIOS */
+ if ((y = cmtxt((z == NET_PIPE) ? "name of named-pipe" :
+ "local NETBIOS name",
+ defnam, &s, xxstring)) < 0)
+ return(y);
+#ifdef NPIPE
+ pipename[0] = NUL;
+#endif /* NPIPE */
+ if ((y = (int) strlen(s)) < 1) {
+ printf("?You must also specify a %s name\n",
+ (z == NET_PIPE) ? "pipe" : "local NETBIOS" );
+ return(-9);
+ }
+#ifdef CK_NETBIOS
+ if (z == NET_BIOS) {
+ if (!netbiosAvail) {
+ printf("?NETBIOS is not available on this system.\n") ;
+ return(-9);
+ }
+ if (y - NETBIOS_NAME_LEN > 0) {
+ printf("?NETBIOS name too long, %ld maximum\n",
+ NETBIOS_NAME_LEN);
+ return(-9);
+ } else if ( !strcmp(s,tmpnbnam) ) {
+ nettype = z; /* Returning to old connection... */
+ return(success = 1); /* Done */
+ } else if (strcmp(" ",NetBiosName)) {
+ printf("?NETBIOS name already assigned to \"%s\"\n",
+ NetBiosName);
+ return(-9);
+ } else {
+ NCB ncb;
+ APIRET rc;
+ ckstrncpy(NetBiosName,s,16);
+ for (x = y; x < NETBIOS_NAME_LEN; x++)
+ NetBiosName[x] = SP;
+ NetBiosName[NETBIOS_NAME_LEN] = NUL;
+ printf("Checking \"%s\" as a unique NetBIOS name...\n",
+ NetBiosName);
+ rc = NCBAddName( NetbeuiAPI,
+ &ncb, NetBiosAdapter, NetBiosName );
+ if (rc) {
+ printf(
+ "?Sorry, \"%s\" is already in use by another NetBIOS node.\n",
+ NetBiosName);
+ for (x = 0; x < NETBIOS_NAME_LEN; x++)
+ NetBiosName[x] = SP;
+ return(-9);
+ }
+ }
+ }
+#endif /* CK_NETBIOS */
+#ifdef NPIPE
+ if (z == NET_PIPE)
+ ckstrncpy(pipename,s,PIPENAML);
+#endif /* NPIPE */
+ } else
+#endif /* NPIPEORBIOS */
+#ifdef DECNET
+ if (z == NET_DEC) {
+ /* Determine if we are using LAT or CTERM */
+ if ((y = cmkey(dnettab,
+ ndnet,"DECNET protocol","lat",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ ttnproto = y;
+ } else
+#endif /* DECNET */
+#ifdef NETDLL
+ if (z == NET_DLL) {
+ /* Find out which DLL they are using */
+ char dllname[256]="";
+ char * p=NULL;
+ if ((x = cmifi("Dynamic load library",
+ "",&p,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of DLL required\n");
+ return(-9);
+ }
+ return(x);
+ }
+ ckstrncpy(dllname,p,256);
+ if ((x = cmcfm()) < 0) return(x);
+
+ if (netdll_load(dllname) < 0) /* Try to load the dll */
+ return(success = 0);
+ else {
+ nettype = z;
+ return(success = 1);
+ }
+ } else
+#endif /* NETDLL */
+ if ((x = cmcfm()) < 0) return(x);
+ nettype = z;
+ if (
+#ifdef DECNET
+ (nettype != NET_DEC) &&
+#endif /* DECNET */
+#ifdef NPIPE
+ (nettype != NET_PIPE) &&
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+ (nettype != NET_BIOS) &&
+#endif /* CK_NETBIOS */
+#ifdef NETFILE
+ (nettype != NET_FILE) &&
+#endif /* NETFILE */
+#ifdef NETCMD
+ (nettype != NET_CMD) &&
+#endif /* NETCMD */
+#ifdef NETPTY
+ (nettype != NET_PTY) &&
+#endif /* NETPTY */
+#ifdef NETDLL
+ (nettype != NET_DLL) &&
+#endif /* NETDLL */
+#ifdef SUPERLAT
+ (nettype != NET_SLAT) &&
+#endif /* SUPERLAT */
+ (nettype != NET_SX25) &&
+ (nettype != NET_VX25) &&
+#ifdef IBMX25
+ (nettype != NET_IX25) &&
+#endif /* IBMX25 */
+#ifdef SSHBUILTIN
+ (nettype != NET_SSH) &&
+#endif /* SSHBUILTIN */
+ (nettype != NET_TCPB)) {
+ printf("?Network type not supported\n");
+ return(success = 0);
+ } else {
+ return(success = 1);
+ }
+ }
+
+#ifndef NOTCPOPTS
+#ifdef TCPSOCKET
+ case XYTCP: {
+ extern int ttyfd;
+
+ if ((z = cmkey(tcpopt,ntcpopt,"TCP option","nodelay",xxstring)) < 0)
+ return(z);
+
+ switch (z) {
+#ifndef NOHTTP
+ case XYTCP_HTTP_PROXY: {
+ struct FDB sw, tx;
+ int n, x;
+ char ubuf[LOGINLEN+1], pbuf[LOGINLEN+1], abuf[256];
+ ubuf[0] = pbuf[0] = abuf[0] = 0;
+
+ cmfdbi(&sw, /* First FDB - switches */
+ _CMKEY, /* fcode */
+ "HTTP proxy server host[:port] or switch",
+ "", /* default */
+ "", /* addtl string data */
+ nuserpass, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ userpass, /* Keyword table */
+ &tx /* Pointer to next FDB */
+ );
+ cmfdbi(&tx,
+ _CMTXT, /* fcode */
+ "HTTP proxy server host[:port]",
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ while (1) {
+ if ((x = cmfdb(&sw)) < 0) {
+ if (x == -3) {
+ x = -9;
+ printf("?Hostname required\n");
+ }
+ return(x);
+ }
+ if (cmresult.fcode != _CMKEY)
+ break;
+ n = cmresult.nresult;
+ switch (n) {
+ case UPW_USER:
+ case UPW_PASS:
+ case UPW_AGENT:
+ if ((x = cmfld((n == UPW_USER) ?
+ "Username" :
+ ((n == UPW_PASS) ? "Password" : "Agent"),
+ "", &s, xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ }
+ ckstrncpy((n == UPW_USER) ? ubuf :
+ ((n == UPW_PASS) ? pbuf : abuf), s,
+ (n == UPW_AGENT) ? 256 : (LOGINLEN+1));
+ }
+ }
+ if (cmresult.fcode != _CMTXT)
+ return(-2);
+ s = cmresult.sresult;
+ if (s) if (!*s) s = NULL;
+
+#ifdef IKSDCONF
+ if (iksdcf)
+ return(success = 0);
+#endif /* IKSDCONF */
+ makestr(&tcp_http_proxy_user,ubuf[0]?ubuf:NULL);
+ makestr(&tcp_http_proxy_pwd,pbuf[0]?pbuf:NULL);
+ makestr(&tcp_http_proxy_agent,abuf[0]?abuf:NULL);
+ makestr(&tcp_http_proxy,s);
+ memset(pbuf,0,sizeof(pbuf));
+ return(success = 1);
+ }
+#endif /* NOHTTP */
+/*
+ It would have been easy to combine XYTCP_SOCKS_SVR with the previous
+ one except for the #ifdefs...
+*/
+#ifdef NT
+#ifdef CK_SOCKS
+ case XYTCP_SOCKS_SVR: {
+ char ubuf[LOGINLEN+1], pbuf[LOGINLEN+1];
+ char * p = getenv("SOCKS_SERVER");
+ struct FDB sw, tx;
+ int n, x;
+
+ if (!p) p = "";
+
+ cmfdbi(&sw, /* First FDB - switches */
+ _CMKEY, /* fcode */
+ "SOCKS server host[:port] or switch",
+ "", /* default */
+ "", /* addtl string data */
+ nuserpass, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ userpass, /* Keyword table */
+ &tx /* Pointer to next FDB */
+ );
+ cmfdbi(&tx,
+ _CMTXT, /* fcode */
+ "SOCKS server host[:port]",
+ p, /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ while (1) {
+ if ((x = cmfdb(&sw)) < 0) {
+ if (x == -3) {
+ x = -9;
+ printf("?Hostname required\n");
+ }
+ return(x);
+ }
+ if (cmresult.fcode != _CMKEY)
+ break;
+ n = cmresult.nresult;
+ switch (n) {
+ case UPW_USER:
+ case UPW_PASS:
+ if ((x = cmfld((n == UPW_USER) ? "Username" : "Password",
+ "", &s, xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ }
+ ckstrncpy((n == UPW_USER) ? ubuf : pbuf, s, LOGINLEN+1);
+ }
+ }
+ if (cmresult.fcode != _CMTXT)
+ return(-2);
+ s = cmresult.sresult;
+ if (s) if (!*s) s = NULL;
+
+#ifdef IKSDCONF
+ if (iksdcf)
+ return(success = 0);
+#endif /* IKSDCONF */
+ makestr(&tcp_socks_user,ubuf);
+ memset(pbuf,0,sizeof(pbuf));
+ makestr(&tcp_socks_svr,s);
+ return(success = 1);
+ }
+
+#ifdef CK_SOCKS_NS
+ case XYTCP_SOCKS_NS: {
+ char * p = getenv("SOCKS_NS");
+ if (!p) p = "";
+ if ((y = cmtxt("hostname or IP of SOCKS Name Server",p,
+ &s,xxstring)) < 0)
+ return(y);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+ if (tcp_socks_ns) {
+ free(tcp_socks_ns); /* Free any previous storage */
+ tcp_socks_ns = NULL;
+ }
+ if (s == NULL || *s == NUL) { /* If none given */
+ tcp_socks_ns = NULL; /* remove the override string */
+ return(success = 1);
+ } else if ((tcp_socks_ns = malloc(strlen(s)+1))) {
+ strcpy(tcp_socks_ns,s);
+ return(success = 1);
+ } else
+ return(success = 0);
+ }
+#endif /* CK_SOCKS_NS */
+#endif /* CK_SOCKS */
+#endif /* NT */
+ case XYTCP_ADDRESS:
+ if ((y = cmtxt("preferred IP Address for TCP connections","",
+ &s,xxstring)) < 0)
+ return(y);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+ if (tcp_address) {
+ free(tcp_address); /* Free any previous storage */
+ tcp_address = NULL;
+ }
+ if (s == NULL || *s == NUL) { /* If none given */
+ tcp_address = NULL; /* remove the override string */
+ return(success = 1);
+ } else if ((tcp_address = malloc(strlen(s)+1))) {
+ strcpy(tcp_address,s);
+ return(success = 1);
+ } else
+ return(success = 0);
+#ifdef SO_KEEPALIVE
+ case XYTCP_KEEPALIVE:
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = keepalive(ssh_sock,z);
+ else
+#endif /* SSHBUILTIN */
+ success = keepalive(ttyfd,z);
+ return(success);
+#endif /* SO_KEEPALIVE */
+#ifdef SO_DONTROUTE
+ case XYTCP_DONTROUTE:
+ if ((z = cmkey(onoff,2,"","off",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = dontroute(ssh_sock,z);
+ else
+#endif /* SSHBUILTIN */
+ success = dontroute(ttyfd,z);
+ return(success);
+#endif /* SO_DONTROUTE */
+#ifdef TCP_NODELAY
+ case XYTCP_NODELAY:
+ if ((z = cmkey(onoff,2,"","off",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = no_delay(ssh_sock,z);
+ else
+#endif /* SSHBUILTIN */
+ success = no_delay(ttyfd,z);
+ return(success);
+ case XYTCP_NAGLE: /* The inverse of NODELAY */
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = no_delay(ssh_sock,z);
+ else
+#endif /* SSHBUILTIN */
+ success = no_delay(ttyfd,!z);
+ return(success);
+#endif /* TCP_NODELAY */
+#ifdef SO_LINGER
+ case XYTCP_LINGER:
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(z);
+ if (z) { /* if on, we need a timeout value */
+ if ((x = cmnum("Linger timeout in 10th of a millisecond",
+ "0",10,&y,xxstring)) < 0)
+ return(x);
+ } else
+ y = 0;
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = ck_linger(ssh_sock,z,y);
+ else
+#endif /* SSHBUILTIN */
+ success = ck_linger(ttyfd,z,y);
+ return(success);
+#endif /* SO_LINGER */
+#ifdef SO_SNDBUF
+ case XYTCP_SENDBUF:
+ x = cmnum("Send buffer size, bytes","8192",10,&z,xxstring);
+ if (x < 0) return(x);
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = sendbuf(ssh_sock,z);
+ else
+#endif /* SSHBUILTIN */
+ success = sendbuf(ttyfd,z);
+ return(success);
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ case XYTCP_RECVBUF:
+ x = cmnum("Receive buffer size, bytes","8192",10,&z,xxstring);
+ if (x < 0) return(x);
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef IKSDCONF
+ if (iksdcf) return(success = 0);
+#endif /* IKSDCONF */
+
+/* Note: The following is not 16-bit safe */
+
+#ifndef QNX16
+ if (x > 52248) {
+ printf("?Warning: receive buffers larger than 52248 bytes\n");
+ printf(" may not be understood by all hosts. Performance\n");
+ printf(" may suffer.\n");
+ return(-9);
+ }
+#endif /* QNX16 */
+#ifdef SSHBUILTIN
+ if (network && nettype == NET_SSH && ssh_sock != -1)
+ success = recvbuf(ssh_sock,z);
+ else
+#endif /* SSHBUILTIN */
+ success = recvbuf(ttyfd,z);
+ return(success);
+#endif /* SO_RCVBUF */
+
+#ifdef VMS
+#ifdef DEC_TCPIP
+ case XYTCP_UCX: { /* UCX 2.0 port swabbing bug */
+ extern int ucx_port_bug;
+ return(success = seton(&ucx_port_bug));
+ }
+#endif /* DEC_TCPIP */
+#endif /* VMS */
+
+ case XYTCP_RDNS: {
+ extern int tcp_rdns;
+ return(success = setonaut(&tcp_rdns));
+ }
+
+#ifdef CK_DNS_SRV
+ case XYTCP_DNS_SRV: {
+ extern int tcp_dns_srv;
+ return(success = seton(&tcp_dns_srv));
+ }
+#endif /* CK_DNS_SRV */
+
+ default:
+ return(0);
+ }
+ }
+#endif /* TCPSOCKET */
+#endif /* NOTCPOPTS */
+#endif /* NETCONN */
+ }
+
+ switch (xx) {
+
+#ifndef NOLOCAL
+#ifdef NETCONN
+ case XYHOST: { /* SET HOST */
+ z = ttnproto; /* Save protocol in case of failure */
+#ifdef DECNET
+ if (nettype != NET_DEC)
+#endif /* DECNET */
+ ttnproto = NP_NONE;
+ if ((y = setlin(XYHOST,1,0)) <= 0) { /* Sets success to 1 */
+ debug(F101,"SET HOST fail mdmtyp","",mdmtyp);
+ ttnproto = z; /* Failed, restore protocol */
+ success = 0;
+ }
+ didsetlin++;
+ debug(F101,"SET HOST OK mdmtyp","",mdmtyp);
+ debug(F101,"SET HOST reliable","",reliable);
+ return(y);
+ }
+#endif /* NETCONN */
+
+ case XYLINE: /* SET LINE (= SET PORT) */
+ debug(F101,"setlin flow 1","",flow);
+ x = setlin(xx,1,0);
+ if (x > -1) didsetlin++;
+ debug(F101,"SET LINE setlin","",x);
+ debug(F101,"SET LINE flow","",flow);
+ debug(F101,"SET LINE local","",local);
+ debug(F101,"SET LINE reliable","",reliable);
+ return(x);
+#endif /* NOLOCAL */
+
+#ifndef NOSETKEY
+ case XYKEY: /* SET KEY */
+ return(dosetkey());
+#endif /* NOSETKEY */
+
+#ifndef NOCSETS
+ case XYLANG: /* Language */
+ if ((y = cmkey(lngtab,nlng,"","none",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+
+ /* Look up language and get associated character sets */
+ for (i = 0; (i < nlangs) && (langs[i].id != y); i++) ;
+ if (i >= nlangs) {
+ printf("?internal error, sorry\n");
+ return(success = 0);
+ } /* */
+ language = i; /* All good, set the language, */
+ return(success = 1);
+#endif /* NOCSETS */
+
+#ifndef MAC
+ case XYBACK: /* BACKGROUND */
+ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef COMMENT
+ bgset = z; /* 0 = off (foreground) */
+#ifdef VMS /* 1 = on (background) */
+ if (batch && bgset == 0) /* To enable echoing of commands */
+ ckxech = 1; /* in VMS batch logs */
+#endif /* VMS */
+#else /* COMMENT */
+ if (z) { /* 1 = Background */
+ bgset = 1;
+ backgrd = 1;
+#ifdef VMS
+ batch = 1;
+#endif /* VMS */
+ } else { /* 0 = Foreground */
+ bgset = 0;
+ backgrd = 0;
+#ifdef VMS
+ batch = 0;
+#endif /* VMS */
+ }
+#endif /* COMMENT */
+ success = 1;
+ bgchk();
+ return(success);
+#endif /* MAC */
+
+ case XYQUIE: { /* QUIET */
+#ifdef DCMDBUF
+ extern int * xquiet;
+#else
+ extern int xquiet[];
+#endif /* DCMDBUF */
+ x = seton(&quiet);
+ if (x < 0) return(x);
+ xquiet[cmdlvl] = quiet;
+ return(success = x);
+ }
+
+#ifndef NOXFER
+ case XYBUF: { /* BUFFERS */
+#ifdef DYNAMIC
+ int sb, rb;
+ if ((y = cmnum("Send buffer size","",10,&sb,xxstring)) < 0) {
+ if (y == -3) printf("?Buffer size required\n");
+ return(y);
+ }
+ if (sb < 0) {
+ if (*atmbuf == '-')
+ printf("?Negative numbers can't be used here\n");
+ else printf("?Integer overflow, use a smaller number please\n");
+ return(-9);
+ } else if (sb < 80) {
+ printf("?Too small\n");
+ return(-9);
+ }
+ if ((y=cmnum("Receive buffer size",ckitoa(sb),10,&rb,xxstring)) < 0)
+ return(y);
+ if (rb < 0) {
+ if (*atmbuf == '-')
+ printf("?Negative numbers can't be used here\n");
+ else printf("?Integer overflow, use a smaller number please\n");
+ return(-9);
+ } else if (rb < 80) {
+ printf("?Too small\n");
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ if ((y = inibufs(sb,rb)) < 0) return(y);
+ y = adjpkl(urpsiz,wslotr,bigrbsiz); /* Maybe adjust packet sizes */
+ if (y != urpsiz) urpsiz = y;
+ y = adjpkl(spsiz,wslotr,bigsbsiz);
+ if (y != spsiz) spsiz = spmax = spsizr = y;
+ return(success = 1);
+#else
+ printf("?Sorry, not available\n");
+ return(success = 0);
+#endif /* DYNAMIC */
+ }
+
+ case XYCHKT: /* BLOCK-CHECK */
+ if ((x = cmkey(chktab,nchkt,"","3",xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (x == 5) {
+ bctf = 1;
+#ifdef COMMENT
+ printf("?5 - Not implemented yet\n");
+ return(success = 0);
+#endif /* COMMENT */
+ }
+ bctr = x; /* Set local too even if REMOTE SET */
+
+ if (rmsflg) {
+ if (x == 4) {
+ tmpbuf[0] = 'B';
+ tmpbuf[1] = '\0';
+ } else
+ ckstrncpy(tmpbuf,ckitoa(x),TMPBUFSIZ);
+ sstate = setgen('S', "400", tmpbuf, "");
+ return((int) sstate);
+ } else {
+ return(success = 1);
+ }
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+#ifndef MAC /* The Mac has no RS-232 */
+case XYCARR: /* CARRIER-WATCH */
+ return(setdcd());
+#endif /* MAC */
+#endif /* NOLOCAL */
+ }
+
+#ifdef TNCODE
+ switch (xx) { /* Avoid long switch statements... */
+ case XYTELOP: {
+ int c, n; /* Workers */
+ int getval = 0; /* Whether to get switch value */
+ int tnserver = 0; /* Client by default */
+ int opt = -1; /* Telnet Option */
+ struct FDB sw, op; /* FDBs for each parse function */
+#ifdef CK_AUTHENTICATION
+ extern int sl_topt_a_s_saved;
+ extern int sl_topt_a_c_saved;
+ extern int sl_topt_e_s_saved;
+ extern int sl_topt_e_c_saved;
+#endif /* CK_AUTHENTICATION */
+#ifdef IKSD
+ if (inserver) /* Server by default when IKSD */
+ tnserver = 1;
+#endif /* IKSD */
+
+ /* Set up chained parse functions... */
+
+ cmfdbi(&op, /* First fdb - telopts*/
+ _CMKEY, /* fcode */
+ "/client, /server or", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ ntnopt, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ tnopttab,
+ &sw
+ );
+ cmfdbi(&sw, /* Second FDB - command switches */
+ _CMKEY, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ ntnoptsw, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ tnoptsw, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+
+ while (opt < 0) { /* Parse 0 or more switches */
+ x = cmfdb(&op); /* Parse switch or other thing */
+ debug(F101,"XYTELOP cmfdb","",x);
+ if (x < 0) /* Error */
+ return(x); /* or reparse needed */
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk(); /* Get break character */
+ getval = (c == ':' || c == '='); /* see how switch ended */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9);
+ }
+ z = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"XYTELOP switch","",z);
+
+ switch (z) { /* Process the switch */
+ case CK_TN_CLIENT:
+ tnserver = 0;
+ break;
+ case CK_TN_SERVER:
+ tnserver = 1;
+ break;
+ case CK_TN_EC:
+ opt = TELOPT_ECHO;
+ break;
+ case CK_TN_TT:
+ opt = TELOPT_TTYPE;
+ break;
+ case CK_TN_BM:
+ opt = TELOPT_BINARY;
+ break;
+ case CK_TN_ENV:
+ opt = TELOPT_NEWENVIRON;
+ break;
+ case CK_TN_LOC:
+ opt = TELOPT_SNDLOC;
+ break;
+ case CK_TN_AU:
+ opt = TELOPT_AUTHENTICATION;
+ break;
+ case CK_TN_FX:
+ opt = TELOPT_FORWARD_X;
+ break;
+ case CK_TN_ENC:
+ opt = TELOPT_ENCRYPTION;
+ break;
+ case CK_TN_IKS:
+ opt = TELOPT_KERMIT;
+ break;
+ case CK_TN_TLS:
+ opt = TELOPT_START_TLS;
+ break;
+ case CK_TN_XD:
+ opt = TELOPT_XDISPLOC;
+ break;
+ case CK_TN_NAWS:
+ opt = TELOPT_NAWS;
+ break;
+ case CK_TN_SGA:
+ opt = TELOPT_SGA;
+ break;
+ case CK_TN_PHR:
+ opt = TELOPT_PRAGMA_HEARTBEAT;
+ break;
+ case CK_TN_PSP:
+ opt = TELOPT_SSPI_LOGON;
+ break;
+ case CK_TN_PLG:
+ opt = TELOPT_PRAGMA_LOGON;
+ break;
+ case CK_TN_SAK:
+ opt = TELOPT_IBM_SAK;
+ break;
+ case CK_TN_CPC:
+ opt = TELOPT_COMPORT;
+ break;
+ case CK_TN_LOG:
+ opt = TELOPT_LOGOUT;
+ break;
+ case CK_TN_FLW:
+ opt = TELOPT_LFLOW;
+ break;
+ default:
+ printf("?Unexpected value - %d\n",z);
+ return(-9);
+ }
+#ifdef COMMENT
+ if (cmresult.fdbaddr == &op)
+ break;
+#endif /* COMMENT */
+ }
+ switch (opt) {
+ case TELOPT_ECHO: /* Options only the Server WILL */
+ case TELOPT_FORWARD_X:
+ case TELOPT_SEND_URL:
+ case TELOPT_IBM_SAK:
+ case TELOPT_LOGOUT:
+ if ((x = cmkey(tnnegtab,
+ ntnnegtab,
+ "desired server state",
+ TELOPT_MODE(tnserver?TELOPT_DEF_S_ME_MODE(opt):TELOPT_DEF_C_U_MODE(opt)),
+ xxstring)
+ ) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ if (tnserver) {
+ TELOPT_DEF_S_ME_MODE(opt) = x;
+ TELOPT_ME_MODE(opt) = x;
+ } else {
+ TELOPT_DEF_C_U_MODE(opt) = x;
+ TELOPT_U_MODE(opt) = x;
+ }
+ break;
+
+ case TELOPT_TTYPE: /* Options only the Client WILL */
+ case TELOPT_NEWENVIRON:
+ case TELOPT_SNDLOC:
+ case TELOPT_AUTHENTICATION:
+ case TELOPT_START_TLS:
+ case TELOPT_XDISPLOC:
+ case TELOPT_NAWS:
+ case TELOPT_LFLOW:
+ case TELOPT_COMPORT:
+ if ((x = cmkey(tnnegtab,
+ ntnnegtab,
+ "desired client state",
+ TELOPT_MODE(!tnserver?TELOPT_DEF_S_U_MODE(opt):TELOPT_DEF_C_ME_MODE(opt)),
+ xxstring)
+ ) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ if (tnserver) {
+ TELOPT_DEF_S_U_MODE(opt) = x;
+ TELOPT_U_MODE(opt) = x;
+#ifdef CK_AUTHENTICATION
+ if (opt == TELOPT_AUTHENTICATION)
+ sl_topt_a_s_saved = 0;
+#endif /* CK_AUTHENTICATION */
+ } else {
+ TELOPT_DEF_C_ME_MODE(opt) = x;
+ TELOPT_ME_MODE(opt) = x;
+#ifdef CK_AUTHENTICATION
+ if (opt == TELOPT_AUTHENTICATION)
+ sl_topt_a_c_saved = 0;
+#endif /* CK_AUTHENTICATION */
+ }
+ break;
+
+ default:
+ if ((x = cmkey(tnnegtab,
+ ntnnegtab,
+ tnserver ?
+ "desired server state" :
+ "desired client state",
+ TELOPT_MODE(tnserver?TELOPT_DEF_S_ME_MODE(opt):TELOPT_DEF_C_ME_MODE(opt)),
+ xxstring
+ )
+ ) < 0)
+ return(x);
+ if ((y = cmkey(tnnegtab,
+ ntnnegtab,
+ !tnserver ? "desired server state" :
+ "desired client state",
+ TELOPT_MODE(!tnserver?TELOPT_DEF_S_U_MODE(opt):TELOPT_DEF_C_U_MODE(opt)),
+ xxstring
+ )
+ ) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ if (tnserver) {
+ TELOPT_DEF_S_ME_MODE(opt) = x;
+ TELOPT_ME_MODE(opt) = x;
+ TELOPT_DEF_S_U_MODE(opt) = y;
+ TELOPT_U_MODE(opt) = y;
+#ifdef CK_ENCRYPTION
+ if (opt == TELOPT_ENCRYPTION)
+ sl_topt_e_s_saved = 0;
+#endif /* CK_ENCRYPTION */
+ } else {
+ TELOPT_DEF_C_ME_MODE(opt) = x;
+ TELOPT_ME_MODE(opt) = x;
+ TELOPT_DEF_C_U_MODE(opt) = y;
+ TELOPT_U_MODE(opt) = y;
+#ifdef CK_ENCRYPTION
+ if (opt == TELOPT_ENCRYPTION)
+ sl_topt_e_c_saved = 0;
+#endif /* CK_ENCRYPTION */
+ }
+ }
+ return(success = 1);
+ }
+
+ case XYTEL: /* TELNET */
+ if ((z = cmkey(tntab,ntn,"parameter for TELNET negotiations", "",
+ xxstring)) < 0)
+ return(z);
+ switch (z) {
+ case CK_TN_EC: /* ECHO */
+ if ((x = cmkey(rltab,nrlt,
+ "initial TELNET echoing state",
+ "local",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tn_duplex = x;
+ return(success = 1);
+
+ case CK_TN_RE: /* REMOTE-ECHO */
+ return(success = seton(&tn_rem_echo));
+
+ case CK_TN_DB: /* DEBUG */
+ return(success = seton(&tn_deb));
+
+ case CK_TN_TT: /* TERMINAL TYPE */
+ if ((y = cmtxt("terminal type for TELNET connections","",
+ &s,xxstring)) < 0)
+ return(y);
+ if (tn_term) {
+ free(tn_term); /* Free any previous storage */
+ tn_term = NULL;
+ }
+ if (s == NULL || *s == NUL) { /* If none given */
+ tn_term = NULL; /* remove the override string */
+ return(success = 1);
+ } else if ((tn_term = malloc(strlen(s)+1))) {
+ strcpy(tn_term,s);
+ return(success = 1);
+ } else return(success = 0);
+
+#ifdef CK_FORWARD_X
+ case CK_TN_FX: /* FORWARD-X */
+ if ((x=cmkey(tnfwdxtab,ntnfwdx,"","xauthority-file",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case 0: { /* Xauthority-File */
+ x = cmifi("Full path of .Xauthority file","",&s,&y,xxstring);
+ if (x < 0 && x != -3)
+ return(x);
+ makestr(&tn_fwdx_xauthority,s);
+ return(success = 1);
+ }
+ case 1: { /* No-Encryption */
+ extern int fwdx_no_encrypt;
+ return(success = seton(&fwdx_no_encrypt));
+ }
+ }
+ return(success = 0);
+#endif /* CK_FORWARD_X */
+
+ case CK_TN_NL: /* TELNET NEWLINE-MODE */
+ if ((x = cmkey(tn_nlmtab,ntn_nlm,"","nvt",xxstring)) < 0)
+ return(x);
+ if (x == TN_NL_BIN) {
+ if ((x = cmkey(tnlmtab,ntnlm,"","raw",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tn_b_nlm = x;
+ return(success = 1);
+ } else if (x == TN_NL_NVT) {
+ if ((x = cmkey(tnlmtab,ntnlm,"","on",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tn_nlm = x;
+ return(success = 1);
+ } else {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tn_nlm = x;
+ return(success = 1);
+ }
+
+ case CK_TN_XF: /* BINARY-TRANSFER-MODE */
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ tn_b_xfer = z;
+ return(success = 1);
+
+ case CK_TN_NE: /* NO-ENCRYPT-DURING-XFER */
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+#endif /* CK_APC */
+ tn_no_encrypt_xfer = z;
+ return(success = 1);
+
+ case CK_TN_BM: /* BINARY-MODE */
+ if ((x = cmkey(tnnegtab,ntnnegtab,"","refused",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ TELOPT_DEF_S_ME_MODE(TELOPT_BINARY) = x;
+ TELOPT_DEF_S_U_MODE(TELOPT_BINARY) = x;
+ TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = x;
+ TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = x;
+ return(success = 1);
+
+#ifdef IKS_OPTION
+ case CK_TN_IKS: /* KERMIT */
+ if ((x = cmkey(tnnegtab,ntnnegtab,"DO","accept",xxstring)) < 0)
+ return(x);
+ if ((y = cmkey(tnnegtab,ntnnegtab,"WILL","accept",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = y;
+ TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = x;
+ TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = y;
+ TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = x;
+ return(success = 1);
+#endif /* IKS_OPTION */
+
+#ifdef CK_SSL
+ case CK_TN_TLS: /* START_TLS */
+ if ((x = cmkey(tnnegtab,ntnnegtab,"me","accept",xxstring)) < 0)
+ return(x);
+ if ((y = cmkey(tnnegtab,ntnnegtab,"u","accept",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = x;
+ TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = y;
+ TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = x;
+ TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = y;
+ return(success = 1);
+#endif /* CK_SSL */
+
+#ifdef CK_NAWS
+ case CK_TN_NAWS: /* NAWS */
+ if ((x = cmkey(tnnegtab,ntnnegtab,"me","accept",xxstring)) < 0)
+ return(x);
+ if ((y = cmkey(tnnegtab,ntnnegtab,"u","accept",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ TELOPT_DEF_S_ME_MODE(TELOPT_NAWS) = x;
+ TELOPT_DEF_S_U_MODE(TELOPT_NAWS) = y;
+ TELOPT_DEF_C_ME_MODE(TELOPT_NAWS) = x;
+ TELOPT_DEF_C_U_MODE(TELOPT_NAWS) = y;
+ return(success = 1);
+#endif /* CK_NAWS */
+
+#ifdef CK_AUTHENTICATION
+ case CK_TN_AU: /* AUTHENTICATION */
+ if ((x = cmkey(tnauthtab,ntnauth,"","",xxstring)) < 0)
+ return(x);
+ if (x == TN_AU_FWD) {
+ extern int forward_flag;
+ return(success = seton(&forward_flag));
+ } else if (x == TN_AU_TYP) {
+ extern int auth_type_user[];
+ extern int sl_auth_type_user[];
+ extern int sl_auth_saved;
+ int i, j, atypes[AUTHTYPLSTSZ];
+
+ for (i = 0; i < AUTHTYPLSTSZ; i++) {
+ if ((y = cmkey(autyptab,nautyp,"",
+ i == 0 ? "automatic" : "" ,
+ xxstring)) < 0) {
+ if (y == -3)
+ break;
+ return(y);
+ }
+ if (i > 0 && (y == AUTHTYPE_AUTO || y == AUTHTYPE_NULL)) {
+ printf(
+ "\r\n?Choice may only be used in first position.\r\n");
+ return(-9);
+ }
+ for (j = 0; j < i; j++) {
+ if (atypes[j] == y) {
+ printf("\r\n?Choice has already been used.\r\n");
+ return(-9);
+ }
+ }
+ atypes[i] = y;
+ if (y == AUTHTYPE_NULL || y == AUTHTYPE_AUTO) {
+ i++;
+ break;
+ }
+ }
+ if (i < AUTHTYPLSTSZ)
+ atypes[i] = AUTHTYPE_NULL;
+ if ((z = cmcfm()) < 0)
+ return(z);
+ sl_auth_saved = 0;
+ for (i = 0; i < AUTHTYPLSTSZ; i++) {
+ auth_type_user[i] = atypes[i];
+ sl_auth_type_user[i] = 0;
+ }
+ } else if (x == TN_AU_HOW) {
+ if ((y = cmkey(auhowtab,nauhow,"","any",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ tn_auth_how = y;
+ } else if (x == TN_AU_ENC) {
+ if ((y = cmkey(auenctab,nauenc,"","encrypt",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ tn_auth_enc = y;
+ } else {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = x;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = x;
+ }
+ return(success = 1);
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_ENCRYPTION
+ case CK_TN_ENC: { /* ENCRYPTION */
+ int c, tmp = -1;
+ int getval = 0;
+ static struct keytab * tnetbl = NULL;
+ static int ntnetbl = 0;
+
+ if ((y = cmkey(tnenctab,ntnenc,"","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TN_EN_TYP:
+ x = ck_get_crypt_table(&tnetbl,&ntnetbl);
+ debug(F101,"ck_get_crypt_table x","",x);
+ debug(F101,"ck_get_crypt_table n","",ntnetbl);
+ if (x < 1 || !tnetbl || ntnetbl < 1) /* Didn't get it */
+ x = 0;
+ if (!x) {
+ printf("?Oops, types not loaded\n");
+ return(-9);
+ }
+ if ((x = cmkey(tnetbl,ntnetbl,"type of encryption",
+ "automatic",xxstring)) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ cx_type = x;
+ sl_cx_type = 0;
+ break;
+ case TN_EN_START:
+ if ((z = cmcfm()) < 0)
+ return(z);
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))
+ return(success = 0);
+#endif /* CK_APC */
+ ck_tn_enc_start();
+ break;
+ case TN_EN_STOP:
+ if ((z = cmcfm()) < 0)
+ return(z);
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))
+ return(success = 0);
+#endif /* CK_APC */
+ ck_tn_enc_stop();
+ break;
+ default:
+ if ((z = cmcfm()) < 0)
+ return(z);
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = y;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = y;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = y;
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = y;
+ }
+ return(success = 1);
+ }
+#endif /* CK_ENCRYPTION */
+
+ case CK_TN_BUG: /* BUG */
+ if ((x = cmkey(tnbugtab,4,"",
+ "binary-me-means-u-too",xxstring)) < 0)
+ return(x);
+ if ((z = cmkey(onoff,2,"","off",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ switch (x) {
+ case 0:
+ tn_b_meu = z;
+ break;
+ case 1:
+ tn_b_ume = z;
+ break;
+ case 2:
+ tn_infinite = z;
+ break;
+ case 3:
+ tn_sb_bug = z;
+ break;
+ case 4:
+ tn_auth_krb5_des_bug = z;
+ break;
+ }
+ return(success = 1);
+
+#ifdef CK_ENVIRONMENT
+ case CK_TN_XD: /* XDISPLOC */
+ if ((x = cmkey(tnnegtab,ntnnegtab,"me","accept",xxstring)) < 0)
+ return(x);
+ if ((y = cmkey(tnnegtab,ntnnegtab,"u","accept",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ TELOPT_DEF_S_ME_MODE(TELOPT_XDISPLOC) = x;
+ TELOPT_DEF_S_U_MODE(TELOPT_XDISPLOC) = y;
+ TELOPT_DEF_C_ME_MODE(TELOPT_XDISPLOC) = x;
+ TELOPT_DEF_C_U_MODE(TELOPT_XDISPLOC) = y;
+ return(success = 1);
+
+ case CK_TN_ENV: {
+ char * msg = "value of telnet environment variable";
+ extern int tn_env_flg;
+ extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
+ tn_env_prnt[], tn_env_sys[];
+ extern char * tn_loc;
+ if ((x = cmkey(tnenvtab,ntnenv,"","",xxstring)) < 0)
+ return(x);
+ if (x == TN_ENV_UVAR) { /* User variables */
+ char * uvar=NULL;
+ char * uval=NULL;
+ char * env;
+ extern char * tn_env_uservar[8][2];
+
+ /* Get the user variable name */
+ if ((x = cmfld("Name of Environment Variable","",&s,
+ xxstring)) < 0)
+ return(x);
+ makestr(&uvar,s);
+
+ env = getenv(uvar);
+ if (!env) env = "";
+
+ if ((x = cmtxt("Value of Environment Variable",env,
+ &s,xxstring)) < 0)
+ return(x);
+ if (*s)
+ makestr(&uval,s);
+
+ /* Now that we have the variable and perhaps a value */
+ /* there are three possibilities: (1) new variable */
+ /* and associated value; (2) variable already exists */
+ /* but we have a new value; (3) variable already */
+ /* exists but no new value therefore the user wants */
+ /* to clear variable. */
+
+ /* Try to find an existing variable */
+ for (x = 0; x < 8; x++) {
+ if (!ckstrcmp(tn_env_uservar[x][0],uvar,-1,0)) {
+ if (uval) {
+ free(tn_env_uservar[x][1]);
+ tn_env_uservar[x][1] = uval;
+ free(uvar);
+ return(success = 1);
+ } else {
+ free(tn_env_uservar[x][0]);
+ tn_env_uservar[x][0] = NULL;
+ free(tn_env_uservar[x][1]);
+ tn_env_uservar[x][1] = NULL;
+ free(uvar);
+ return(success = 1);
+ }
+ }
+ }
+
+ /* Couldn't find one; look for empty location to insert */
+ for (x = 0; x < 8; x++) {
+ if (!tn_env_uservar[x][0]) {
+ tn_env_uservar[x][0] = uvar;
+ tn_env_uservar[x][1] = uval;
+ return(success = 1);
+ }
+ }
+ printf("?Sorry, no space for variable.\n");
+ return(success = 0);
+ }
+ if (x == TN_ENV_OFF || x == TN_ENV_ON) {
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ tn_env_flg = x == TN_ENV_OFF ? 0 : 1;
+ return(success = 1);
+ }
+
+ /* Not ON/OFF - Get the value */
+ z = cmdgquo();
+ cmdsquo(0);
+ if ((y = cmtxt(msg, "", &s, xxstring)) < 0) {
+ cmdsquo(z);
+ return(y);
+ }
+ cmdsquo(z);
+#ifdef IKSD
+ if (inserver)
+ return(success = 0);
+#endif /* IKSD */
+ if ((int)strlen(s) > 63) {
+ printf("Sorry, too long\n");
+ return(-9);
+ }
+ switch (x) {
+ case TN_ENV_USR:
+ ckstrncpy(uidbuf,s,UIDBUFLEN);
+ sl_uid_saved = 0;
+ break;
+ case TN_ENV_ACCT:
+ ckstrncpy(tn_env_acct,s,64);
+ break;
+ case TN_ENV_DISP:
+ ckstrncpy(tn_env_disp,s,64);
+ break;
+ case TN_ENV_JOB:
+ ckstrncpy(tn_env_job,s,64);
+ break;
+ case TN_ENV_PRNT:
+ ckstrncpy(tn_env_prnt,s,64);
+ break;
+ case TN_ENV_SYS:
+ ckstrncpy(tn_env_sys,s,64);
+ break;
+ case TN_ENV_LOC:
+ if (!*s) s = NULL;
+ makestr(&tn_loc,s);
+ break;
+ case TN_ENV_UVAR:
+ printf("\n?Not yet implemented\n");
+ break;
+ }
+ return(success = 1);
+ }
+#endif /* CK_ENVIRONMENT */
+
+#ifdef CK_SNDLOC
+ case CK_TN_LOC: { /* LOCATION */
+ extern char * tn_loc;
+ if ((y = cmtxt("Location string","",&s,xxstring)) < 0)
+ return(y);
+ if (!*s) s = NULL;
+ makestr(&tn_loc,s);
+ return(success = 1);
+ }
+#endif /* CK_SNDLOC */
+ case CK_TN_SFU: /* Microsoft SFU compatibility */
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ tn_sfu = z;
+ return(success = 1);
+ break;
+
+ case CK_TN_WAIT: /* WAIT-FOR-NEGOTIATIONS */
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+ ) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ tn_wait_flg = z;
+ sl_tn_saved = 0;
+ return(success = 1);
+
+ case CK_TN_DL: /* DELAY SUBNEGOTIATIONS */
+ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+ ) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ tn_delay_sb = z;
+ return(success = 1);
+
+ case CK_TN_PUID: { /* PROMPT-FOR-USERID */
+ int i,len;
+ if ((y = cmtxt("Prompt string","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ /* we must check to make sure there are no % fields */
+ len = strlen(s);
+ for (i = 0; i < len; i++) {
+ if (s[i] == '%') {
+ if (s[i+1] != '%') {
+ printf("%% fields are not used in this command.\n");
+ return(-9);
+ }
+ i++;
+ }
+ }
+ makestr(&tn_pr_uid,s);
+ return(success = 1);
+ }
+ default:
+ return(-2);
+ }
+ }
+#endif /* TNCODE */
+
+ switch (xx) {
+#ifndef NOSPL
+ case XYCOUN: /* SET COUNT */
+ x = cmnum("Positive number","0",10,&z,xxstring);
+ if (x < 0) return(x);
+ if ((x = cmcfm()) < 0) return(x);
+ if (z < 0) {
+ printf("?A positive number, please\n");
+ return(0);
+ }
+ debug(F101,"XYCOUN: z","",z);
+ return(success = setnum(&count[cmdlvl],z,0,10000));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+ case XYCASE:
+ return(success = seton(&inpcas[cmdlvl]));
+#endif /* NOSPL */
+
+ case XYCMD: /* COMMAND ... */
+ if ((y = cmkey(scmdtab,nbytt,"","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case SCMD_CBR:
+ if ((y = cmcfm()) < 0)
+ return(y);
+ concb((char)escape);
+ return(success = 1);
+
+ case SCMD_BSZ:
+ if ((y = cmnum("bytesize for command characters, 7 or 8","7",10,&x,
+ xxstring)) < 0)
+ return(y);
+ if (x != 7 && x != 8) {
+ printf("\n?The choices are 7 and 8\n");
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ if (x == 7) cmdmsk = 0177;
+ else if (x == 8) cmdmsk = 0377;
+ return(success = 1);
+#ifdef CK_RECALL
+ case SCMD_RCL:
+ if ((y = cmnum("maximum number of commands in recall buffer","10",
+ 10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+ return(success = cmrini(x));
+#endif /* CK_RECALL */
+#ifdef CK_RECALL
+ case SCMD_RTR:
+ return(success = seton(&cm_retry));
+#endif /* CK_RECALL */
+ case SCMD_MOR: /* More-prompting */
+ success = seton(&xaskmore);
+ if (success)
+ saveask = xaskmore;
+ return(success);
+ case SCMD_QUO:
+ if ((x = seton(&y)) < 0) return(x);
+ cmdsquo(y); /* Do it the right way */
+ cmd_quoting = y; /* Also keep a global copy */
+ /* Set string-processing function */
+#ifdef datageneral
+ xxstring = y ? zzstring : (xx_strp) NULL;
+#else
+#ifdef CK_ANSIC
+ xxstring = y ? zzstring : (xx_strp) NULL;
+#else
+ xxstring = y ? zzstring : (xx_strp) NULL;
+#endif /* CK_ANSIC */
+#endif /* datageneral */
+ return(success = 1);
+
+#ifdef OS2
+#ifndef NOLOCAL
+ case SCMD_COL: { /* Command-screen colors */
+ int fg, bg;
+ fg = cmkey(ttyclrtab, nclrs,
+ "foreground color and then background color",
+ "white",
+ xxstring);
+ if (fg < 0)
+ return(fg);
+ if ((bg = cmkey(ttyclrtab,nclrs,
+ "background color","black",xxstring)) < 0)
+ return(bg);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ colorcmd = fg | bg << 4;
+ return(success = 1);
+ }
+ case SCMD_SCR: /* Command Scrollback size */
+ if ((y = cmnum("COMMAND scrollback buffer size, lines","512",10,&x,
+ xxstring)) < 0)
+ return(y);
+ /* The max number of lines is the RAM */
+ /* we can actually dedicate to a */
+ /* scrollback buffer given the maximum */
+ /* process memory space of 512MB */
+ if (x < 256 || x > 2000000L) {
+ printf("\n?The size must be between 256 and 2,000,000.\n");
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ tt_scrsize[VCMD] = x;
+ VscrnInit( VCMD );
+ return(success = 1);
+
+ case SCMD_WID: {
+ if ((y = cmnum("Number of columns in display window",
+ "80",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+
+ os2_setcmdwidth(x);
+ return(success = 1);
+ }
+ case SCMD_HIG:
+ if ((y = cmnum("Number of rows in display window",
+ "24",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+ os2_setcmdheight(x);
+ return(success = 1);
+
+ case SCMD_STA: {
+ extern int marginbot;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (y != tt_status[VCMD]) {
+ /* Might need to fixup the margins */
+ tt_status[VCMD] = y;
+ if (y) {
+ tt_szchng[VCMD] = 2;
+ tt_rows[VCMD]--;
+ cmd_rows--;
+ VscrnInit(VCMD); /* Height set here */
+ printf("\n");
+ } else {
+ tt_szchng[VCMD] = 1;
+ tt_rows[VCMD]++;
+ cmd_rows++;
+ VscrnInit(VCMD); /* Height set here */
+ }
+ }
+ return(success = 1);
+ }
+
+ case SCMD_CUR: {
+ int row, col;
+ position * ppos;
+
+ ppos = VscrnGetCurPos(VCMD);
+#ifdef NT
+#define itoa _itoa
+#endif /* NT */
+ itoa(ppos->y+1, tmpbuf, 10);
+ if ((y = cmnum("row (1-based)",tmpbuf,10,&row,xxstring)) < 0)
+ return(y);
+
+ itoa(ppos->x+1, tmpbuf, 10);
+ if ((y = cmnum("col (1-based)",tmpbuf,10,&col,xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+
+ lgotoxy( VCMD, col, row ) ;
+ VscrnIsDirty( VCMD );
+ return(success=1);
+ }
+#endif /* NOLOCAL */
+#else
+ case SCMD_WID:
+ y = cmnum("Command screen width, characters","80",10,&x,xxstring);
+ return(setnum(&cmd_cols,x,y,1024));
+
+ case SCMD_HIG:
+ y = cmnum("Command screen height, rows","24",10,&x,xxstring);
+ return(setnum(&cmd_rows,x,y,1024));
+#endif /* OS2 */
+
+ case SCMD_INT:
+ return(seton(&cmdint));
+
+#ifdef CK_AUTODL
+ case SCMD_ADL:
+ return(seton(&cmdadl));
+#endif /* CK_AUTODL */
+
+#ifdef DOUBLEQUOTING
+ case SCMD_DBQ: {
+ extern int dblquo;
+ return(seton(&dblquo));
+ }
+#endif /* DOUBLEQUOTING */
+
+ case SCMD_ERR:
+ y = cmnum("Error message verbosity level, 0-3","1",10,&x,xxstring);
+ return(setnum(&cmd_err,x,y,3));
+
+ case SCMD_VAR:
+ return(setvareval());
+
+ default:
+ return(-2);
+ }
+ }
+
+ switch (xx) {
+
+ case XYDFLT: /* SET DEFAULT = CD */
+ return(success = docd(XXCWD));
+
+case XYDEBU: /* SET DEBUG { on, off, session } */
+ if ((y = cmkey(dbgtab,ndbg,"","",xxstring)) < 0)
+ return(y);
+ if (y == DEB_TIM)
+#ifdef COMMENT
+ return(seton(&debtim) < 0 ? x : (success = 1));
+#else
+ /* why this change? */
+ return(success = seton(&debtim));
+#endif /* COMMENT */
+
+#ifdef IKSD
+ if (inserver && isguest) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ switch (y) {
+ case DEB_LEN:
+ y = cmnum("Max length for debug log strings","",10,&x,xxstring);
+ if ((z = setnum(&debxlen,x,y,-1)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ return(success = 1);
+
+ case DEB_OFF:
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifndef NOLOCAL
+ setdebses(0);
+#endif /* NOLOCAL */
+#ifdef DEBUG
+ if (deblog) doclslog(LOGD);
+#endif /* DEBUG */
+ return(success = 1);
+
+ case DEB_ON:
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef DEBUG
+ deblog = debopn("debug.log", 0);
+ return(success = deblog ? 1 : 0);
+#else
+ printf("?Sorry, debug log feature not enabled\n");
+ return(success = 0);
+#endif /* DEBUG */
+ case DEB_SES:
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifndef NOLOCAL
+ setdebses(1);
+#endif /* NOLOCAL */
+ return(success = 1);
+
+ case DEB_MSG: /* Debug messages 2010/03/12 */
+ if ((y = cmkey(ooetab,nooetab,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ debmsg = y;
+ return(1);
+ }
+ break;
+
+#ifndef NOXFER
+ case XYDELA: /* SET DELAY */
+ y = cmnum("Number of seconds before starting to send",
+ "5",10,&x,xxstring);
+ if (x < 0) x = 0;
+ return(success = setnum(&ckdelay,x,y,999));
+#endif /* NOXFER */
+
+ default:
+ break;
+ }
+
+ switch (xx) {
+#ifdef CK_TAPI
+ case XYTAPI:
+ return(settapi());
+#endif /* CK_TAPI */
+#ifndef NODIAL
+ case XYDIAL: /* SET MODEM or SET DIAL */
+ return(setdial(-1));
+ case XYMODM:
+ return(setmodem());
+#ifdef COMMENT
+ /* not implemented yet */
+ case XYANSWER: /* SET ANSWER */
+ return(setanswer());
+#endif /* COMMENT */
+#endif /* NODIAL */
+
+#ifndef NOLOCAL
+ case XYDUPL: /* SET DUPLEX */
+ if ((y = cmkey(dpxtab,2,"","full",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ duplex = y;
+ return(success = 1);
+
+ case XYLCLE: /* LOCAL-ECHO (= DUPLEX) */
+ return(success = seton(&duplex));
+
+ case XYESC: /* SET ESCAPE */
+ return(success = setcc(ckitoa(DFESC),&escape));
+#endif /* NOLOCAL */
+
+ case XYEXIT: /* SET EXIT */
+ if ((z = cmkey(xittab,nexit,"","",xxstring)) < 0)
+ return(z);
+ switch (z) {
+ case 0: /* STATUS */
+ y = cmnum("EXIT status code","",10,&x,xxstring);
+ return(success = setnum(&xitsta,x,y,-1));
+ case 1: /* WARNING */
+ if ((z = cmkey(xitwtab,nexitw,"","",xxstring)) < 0)
+ return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ setexitwarn(z);
+ return(success = 1);
+ case 2:
+ success = seton(&exitonclose);
+#ifdef TCPSOCKET
+ if (success) tn_exit = exitonclose;
+#endif /* TCPSOCKET */
+ return(success);
+ case 3: {
+ extern int exithangup;
+ return((success = seton(&exithangup)));
+ }
+ default:
+ return(-2);
+ } /* End of SET EXIT switch() */
+ default:
+ break;
+ }
+
+ switch (xx) {
+
+ case XYFILE: /* SET FILE */
+ return(setfil(rmsflg));
+
+ case XYFLOW: { /* FLOW-CONTROL */
+ extern int cxflow[];
+ struct FDB k1, k2;
+ int tncomport = 0;
+ char * m;
+
+#ifdef TN_COMPORT
+ if (network && istncomport())
+ tncomport = 1;
+#endif /* TN_COMPORT */
+
+ if (tncomport) {
+ m = "Flow control type, one of the following:\n\
+ dtr/cd dtr/cts keep none rts/cts xon/xoff\n\
+ or connection type";
+ } else {
+ /* All this is because chained FDB's don't give chained help yet */
+ m =
+#ifdef Plan9
+#ifdef CK_RTSCTS
+ "Flow control type, one of the following:\n\
+ keep none rts/cts\n\
+ or connection type",
+#else
+ "Flow control type, one of the following:\n\
+ keep none\n\
+ or connection type";
+#endif /* CK_RTSCTS */
+#else
+#ifdef CK_RTSCTS
+#ifdef CK_DTRCD
+#ifdef CK_DTRCTS
+ "Flow control type, one of the following:\n\
+ dtr/cd dtr/cts keep none rts/cts xon/xoff\n\
+ or connection type";
+#else /* CK_DTRCTS */
+ "Flow control type, one of the following:\n\
+ dtr/cd keep none rts/cts xon/xoff\n\
+ or connection type";
+#endif /* CK_DTRCTS */
+#else /* CK_DTRCD */
+#ifdef CK_DTRCTS
+ "Flow control type, one of the following:\n\
+ dtr/cts keep none rts/cts xon/xoff\n\
+ or connection type";
+#else /* CK_DTRCTS */
+ "Flow control type, one of the following:\n\
+ keep none rts/cts xon/xoff\n\
+ or connection type";
+#endif /* CK_DTRCTS */
+#endif /* CK_DTRCD */
+#else
+ "Flow control type, one of the following:\n\
+ keep none xon/xoff\n\
+ or connection type";
+#endif /* CK_RTSCTS */
+#endif /* Plan9 */
+ }
+ cmfdbi(&k1,_CMKEY,m,"","",ncxtypesw, 4, xxstring, cxtypesw, &k2);
+ cmfdbi(&k2,
+ _CMKEY,
+ "",
+ "",
+ "",
+#ifdef TN_COMPORT
+ (tncomport ? ntnflo : nflo),
+#else
+ nflo,
+#endif /* TN_COMPORT */
+ 0,
+ xxstring,
+#ifdef TN_COMPORT
+ (tncomport ? tnflotab : flotab),
+#else
+ flotab,
+#endif /* TN_COMPORT */
+ NULL
+ );
+ x = cmfdb(&k1);
+ if (x < 0) { /* Error */
+ if (x == -2 || x == -9)
+ printf("?No keywords or switches match: \"%s\"\n",atmbuf);
+ return(x);
+ }
+ z = cmresult.nresult; /* Keyword value */
+ if (cmresult.fdbaddr == &k2) { /* Flow-control type keyword table */
+ if ((x = cmcfm()) < 0) /* Set it immediately */
+ return(x);
+ flow = z;
+ debug(F101,"set flow","",flow);
+#ifdef CK_SPEED
+ if (flow == FLO_XONX) /* Xon/Xoff forces prefixing */
+ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1;
+#endif /* CK_SPEED */
+ autoflow = (flow == FLO_AUTO);
+ return(success = 1); /* Done */
+ }
+ debug(F101,"set flow /blah 1","",z); /* SET FLOW /for-what */
+ if ((y = cmkey(flotab,nflo,"Flow control type","none",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ debug(F101,"set flow /blah 2","",y);
+ if (y == FLO_AUTO) {
+ printf(
+ "?Sorry, \"automatic\" can not be assigned to a connection type.\n");
+ return(-9);
+ } else if (z >= 0 && z <= CXT_MAX)
+ cxflow[z] = y;
+ debug(F101,"set flow","",flow);
+ debug(F101,"set flow autoflow","",autoflow);
+ return(success = 1);
+ }
+
+ case XYHAND: /* HANDSHAKE */
+ if ((y = cmkey(hshtab,nhsh,"","none",xxstring)) < 0) return(y);
+ if (y == 998) {
+ if ((x = cmnum("ASCII value","",10,&y,xxstring)) < 0)
+ return(x);
+ if ((y < 1) || ((y > 31) && (y != 127))) {
+ printf("?Character must be in ASCII control range\n");
+ return(-9);
+ }
+ }
+ if ((x = cmcfm()) < 0) return(x);
+ turn = (y > 0127) ? 0 : 1;
+ turnch = y;
+ return(success = 1);
+
+#ifndef NOSPL
+ case XYMACR: /* SET MACRO */
+ if ((y = cmkey(smactab,2,"","",xxstring)) < 0) return(y);
+ switch (y) {
+ case 0: return(success = seton(&mecho));
+ case 1: return(success = seton(&merror[cmdlvl]));
+ default: return(-2);
+ }
+#endif /* NOSPL */
+
+ case XYMSGS:
+#ifdef VMS
+ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ vms_msgs = z;
+ printf("Sorry, SET MESSAGES not implemented yet\n");
+ return(success = 0);
+#endif /* VMS */
+ default:
+ break;
+ }
+
+ switch (xx) {
+
+ case XYPARI: /* PARITY */
+ if ((y = cmkey(partbl,npar,"","none",xxstring)) < 0)
+ return(y);
+
+ /* If parity not none, then we also want 8th-bit prefixing */
+
+#ifdef HWPARITY
+ if (y == 'H') { /* Hardware */
+ if ((x = cmkey(hwpartbl,nhwpar,"","even",xxstring)) < 0)
+ return(x);
+ }
+#endif /* HWPARITY */
+
+ if ((z = cmcfm()) < 0)
+ return(z);
+
+#ifdef HWPARITY
+ if (y == 'H') { /* 8 data bits plus hardware parity */
+ parity = 0;
+#ifndef NOXFER
+ ebqflg = 0;
+#endif /* NOXFER */
+ hwparity = x;
+ } else { /* 7 data bits + software parity */
+ hwparity = 0;
+#endif /* HWPARITY */
+ parity = y;
+#ifndef NOXFER
+ ebqflg = (parity) ? 1 : 0;
+#endif /* NOXFER */
+#ifdef HWPARITY
+ }
+#endif /* HWPARITY */
+
+#ifdef TN_COMPORT
+ if (network && istncomport())
+ tnsettings(parity, 0);
+#endif /* TN_COMPORT */
+
+ return(success = 1);
+
+#ifndef NOFRILLS
+ case XYPROM: /* SET PROMPT */
+/*
+ Note: xxstring not invoked here. Instead, it is invoked every time the
+ prompt is issued. This allows the prompt string to contain variables
+ that can change, like \v(dir), \v(time), etc.
+*/
+ ckmakmsg(line, /* Default might have trailing space */
+ LINBUFSIZ,
+ "{",
+ inserver ? ikprompt : ckprompt,
+ "}",
+ NULL
+ );
+ if ((x = cmtxt("Program's command prompt",line,&s,NULL)) < 0)
+ return(x);
+ s = brstrip(s); /* Remove enclosing braces, if any */
+ cmsetp(s); /* Set the prompt */
+ return(success = 1);
+#endif /* NOFRILLS */
+
+#ifndef NOXFER
+ case XYRETR: /* RETRY: per-packet retry limit */
+ y = cmnum("Maximum retries per packet","10",10,&x,xxstring);
+ if (x < 0) x = 0;
+ if ((x = setnum(&maxtry,x,y,999)) < 0) return(x);
+#ifdef COMMENT
+ if (maxtry <= wslotr) {
+ printf("?Retry limit must be greater than window size\n");
+ return(success = 0);
+ }
+#endif /* COMMENT */
+ if (rmsflg) {
+ sstate = setgen('S', "403", ckitoa(maxtry), "");
+ return((int) sstate);
+ } else return(success = x);
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+ case XYSERV: /* SET SERVER items */
+ if ((y = cmkey(srvtab,nsrvt,"","",xxstring)) < 0) return(y);
+ switch (y) {
+ case XYSERI:
+ if ((y = cmnum("Number of seconds, or 0 for no idle timeout",
+ "0",10,&x,xxstring)) < 0)
+ return(y);
+ if (x < 0)
+ x = 0;
+ if ((y = cmcfm()) < 0)
+ return(y);
+#ifndef OS2
+ srvtim = 0;
+#endif /* OS2 */
+ srvidl = x;
+ return(success = 1);
+ case XYSERT:
+ if ((y = cmnum("Interval for server NAKs, 0 = none",
+ ckitoa(DSRVTIM),
+ 10,&x, xxstring)) < 0)
+ return(y);
+ if (x < 0) {
+ printf(
+ "\n?Specify a positive number, or 0 for no server NAKs\n");
+ return(0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "404", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+#ifndef OS2
+ srvidl = 0;
+#endif /* OS2 */
+ srvtim = x; /* Set the server timeout variable */
+ return(success = 1);
+ }
+ case XYSERD: /* SERVER DISPLAY */
+ return(success = seton(&srvdis)); /* ON or OFF... */
+
+#ifndef NOSPL
+ case XYSERP: /* SERVER GET-PATH */
+ return(parsdir(2));
+#endif /* NOSPL */
+
+ case XYSERL: /* SERVER LOGIN */
+ return(cklogin());
+
+ case XYSERC: /* SERVER CD-MESSAGE */
+ x = rmsflg ?
+ cmkey(onoff,2,"","",xxstring) :
+ cmkey(cdmsg,3,"","",xxstring);
+ if (x < 0)
+ return(x);
+ if (x == 2) { /* CD-MESSAGE FILE */
+ if ((x = cmtxt("Name of file","",&s,NULL)) < 0)
+ return(x);
+ if (!*s) {
+ s = NULL;
+ srvcdmsg = 0;
+ }
+ makestr(&cdmsgstr,s);
+ makelist(cdmsgstr,cdmsgfile,8);
+ return(success = 1);
+ }
+ if ((y = cmcfm()) < 0) /* CD-MESSAGE ON/OFF */
+ return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "420", x ? "1" : "0", "");
+ return((int) sstate);
+ } else {
+ if (x > 0)
+ srvcdmsg |= 1;
+ else
+ srvcdmsg &= 2;
+ return(success = 1);
+ }
+ case XYSERK: /* SERVER KEEPALIVE */
+ return(success = seton(&srvping)); /* ON or OFF... */
+
+ default:
+ return(-2);
+ }
+#endif /* NOSERVER */
+ }
+
+ switch (xx) {
+#ifdef UNIX
+#ifndef NOJC
+ case XYSUSP: /* SET SUSPEND */
+ seton(&xsuspend); /* on or off... */
+ return(success = 1);
+#endif /* NOJC */
+#endif /* UNIX */
+
+ case XYTAKE: /* SET TAKE */
+ if ((y = cmkey(taktab,4,"","",xxstring)) < 0) return(y);
+ switch (y) {
+ case 0: return(success = seton(&techo));
+#ifndef NOSPL
+ case 1: return(success = seton(&takerr[cmdlvl]));
+#else
+ case 1: return(success = seton(&takerr[tlevel]));
+#endif /* NOSPL */
+ case 2: techo = 0; return(success = 1); /* For compatibility with */
+ case 3: techo = 1; return(success = 1); /* MS-DOS Kermit */
+ default: return(-2);
+ }
+
+#ifndef NOSCRIPT
+ case XYSCRI: /* SET SCRIPT */
+ if ((y = cmkey(scrtab,1,"","echo",xxstring)) < 0) return(y);
+ switch (y) {
+ case 0: return(success = seton(&secho));
+ default: return(-2);
+ }
+#endif /* NOSCRIPT */
+
+ default:
+ break;
+ }
+
+#ifndef NOLOCAL
+ switch (xx) {
+ case XYTERM: /* SET TERMINAL */
+ x = settrm();
+ success = (x > 0) ? 1 : 0;
+ return(x);
+
+#ifdef NT
+ case XYWIN95: /* SET WIN95 workarounds */
+ x = setwin95();
+ success = (x > 0 ? 1 : 0);
+ return(x);
+#endif /* NT */
+
+#ifdef OS2
+ case XYDLR: /* SET DIALER workarounds */
+ x = setdialer();
+ success = (x > 0 ? 1 : 0);
+ return(x);
+
+ case XYTITLE: /* SET TITLE of window */
+ x = settitle();
+ success = (x > 0 ? 1 : 0);
+ return(x);
+#endif /* OS2 */
+
+#ifdef OS2MOUSE
+ case XYMOUSE: /* SET MOUSE */
+ return(success = setmou());
+#endif /* OS2MOUSE */
+
+ case XYBELL: /* SET BELL */
+ return(success = setbell());
+
+#ifdef OS2
+ case XYPRTY:
+ return(success = setprty() );
+#endif /* OS2 */
+
+ default:
+ break;
+ }
+#endif /* NOLOCAL */
+
+ switch (xx) {
+
+/* SET SEND/RECEIVE protocol parameters. */
+
+#ifndef NOXFER
+ case XYRECV:
+ case XYSEND:
+ return(setsr(xx,rmsflg));
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ case XYSESS: /* SESSION-LOG */
+ if ((x = cmkey(sfttab,nsfttab,"type of file",
+#ifdef OS2
+ "binary",
+#else /* OS2 */
+ "text",
+#endif /* OS2 */
+ xxstring
+ )
+ ) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if (x == 999) { /* TIMESTAMPED-TEXT */
+ sessft = XYFT_T; /* Implies text */
+ slogts = 1; /* and timestamps */
+ } else if (x == 998) { /* NULL-PADDED-LINES */
+ slognul = 1; /* adds NUL after ^J */
+ } else { /* A regular type */
+ sessft = x; /* The type */
+ slogts = 0; /* No timestampes */
+ }
+ return(success = 1);
+
+ case XYSPEE: /* SET SPEED */
+ lp = line;
+ if (local && !network) {
+ ckmakmsg(lp,
+ LINBUFSIZ,
+ "Transmission rate for ",
+ ttname,
+ " (bits per second)",
+ NULL
+ );
+ } else {
+ ckstrncpy(lp,
+ "Serial-port speed (bits per second)",
+ LINBUFSIZ
+ );
+ }
+ zz = -1L;
+
+#ifdef TN_COMPORT
+ if (network && istncomport())
+ x = cmkey(tnspdtab,ntnspd,line,"",xxstring);
+ else
+#endif /* TN_COMPORT */
+ x = cmkey(spdtab,nspd,line,"",xxstring);
+ if (x < 0) {
+ if (x == -3) printf("?value required\n");
+#ifdef USETCSETSPEED
+ /* In this case, any number can be tried */
+ /* There's a parse error message but the request still goes thru */
+ if (rdigits(atmbuf))
+ zz = atol(atmbuf);
+ else
+#endif /* USETCSETSPEED */
+ return(x);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ if (!local) {
+ printf("?SET SPEED has no effect without prior SET LINE\n");
+ return(success = 0);
+ } else if (network
+#ifdef TN_COMPORT
+ && !istncomport()
+#endif /* TN_COMPORT */
+ ) {
+ printf("\n?Speed cannot be set for network connections\n");
+ return(success = 0);
+ }
+
+/*
+ Note: This way of handling speeds is not 16-bit safe for speeds greater
+ than 230400. The argument to ttsspd() should have been a long.
+*/
+#ifdef USETCSETSPEED
+ if (zz > -1L)
+ x = zz / 10L;
+#endif /* USETCSETSPEED */
+ zz = (long) x * 10L;
+ if (zz == 130L) zz = 134L;
+ if (zz == 70L) zz = 75L; /* (see spdtab[] definition) */
+ if (ttsspd(x) < 0) { /* Call ttsspd with cps, not bps! */
+ printf("?Unsupported line speed - %ld\n",zz);
+ return(success = 0);
+ } else {
+#ifdef CK_TAPI
+ if (!tttapi || tapipass)
+ speed = ttgspd(); /* Read it back */
+ else
+ speed = zz;
+#else /* CK_TAPI */
+ speed = ttgspd(); /* Read it back */
+#endif /* CK_TAPI */
+ if (speed != zz) { /* Call ttsspd with cps, not bps! */
+ printf("?SET SPEED fails, speed is %ld\n",speed);
+ return(success = 0);
+ }
+ if (pflag && !xcmdsrc) {
+ if (speed == 8880)
+ printf("%s, 75/1200 bps\n",ttname);
+ else if (speed == 134)
+ printf("%s, 134.5 bps\n",ttname);
+ else
+ printf("%s, %ld bps\n",ttname,speed);
+ }
+ return(success = 1);
+ }
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+ case XYXFER: /* SET TRANSFER */
+ if ((y = cmkey(rmsflg ? rtstab : tstab, /* (or REMOTE SET TRANSFER) */
+ rmsflg ? nrts : nts,
+ "","character-set",xxstring)) < 0) return(y);
+ switch (y) {
+#ifdef XFRCAN
+ case XYX_CAN: /* CANCELLATION */
+ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z);
+ if (z == 0) { /* OFF */
+ if ((y = cmcfm()) < 0) return(y);
+ xfrcan = 0;
+ } else {
+ if ((y = cmnum("ASCII code for cancellation character",
+ "3",10,&x,
+ xxstring)) < 0)
+ return(y);
+ if (x > 31 && x != 127) {
+ printf("Cancel character must be 0-31 or 127\n");
+ return(-9);
+ }
+ if ((y = cmnum("How many required to cause cancellation",
+ "2",10,&z, xxstring)) < 0)
+ return(y);
+ if (z < 2) {
+ printf("Number must be 2 or greater\n");
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ xfrcan = 1; /* CANCELLATION ON */
+ xfrchr = x; /* Using this character */
+ xfrnum = z; /* Needing this many of them */
+ }
+ return(success = 1);
+#endif /* XFRCAN */
+
+#ifndef NOCSETS
+ case XYX_CSE: /* CHARACTER-SET */
+ if ((y = cmkey(tcstab,ntcs,"","transparent",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S', "405", tcsinfo[y].designator, "");
+ return((int) sstate);
+ } else {
+ extern int s_cset, fcharset, axcset[], tcs_save;
+ tslevel = (y == TC_TRANSP) ? 0 : 1; /* transfer syntax level */
+ xfrxla = tslevel;
+ tcharset = y; /* transfer character set */
+ /* SEND CHARACTER-SET AUTO */
+ if (tslevel > 0 && s_cset == XMODE_A)
+ if (y > -1 && y <= MAXTCSETS)
+ if (axcset[y] > -1 && axcset[y] > MAXFCSETS)
+ fcharset = axcset[y]; /* Auto-pick file charset */
+ setxlatype(tcharset,fcharset); /* Translation type */
+ tcs_save = -1;
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+ case XYX_LSH: /* LOCKING-SHIFT */
+ if ((y = cmkey(lstab,nls,"","on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ lscapr = (y == 1) ? 1 : 0; /* ON: requested = 1 */
+ lscapu = (y == 2) ? 2 : 0; /* FORCED: used = 1 */
+ return(success = 1);
+
+/* #ifdef CK_XYZ */
+ case XYX_PRO: /* Protocol */
+#ifndef OS2
+ if (inserver) {
+ printf("?Sorry, only Kermit protocol is available\n");
+ return(-9);
+ }
+#endif /* OS2 */
+ return(setproto());
+/* #endif */ /* CK_XYZ */
+
+ case XYX_MOD: /* Mode */
+ if ((y = cmkey(xfrmtab,2,"","automatic",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S', "410", y == XMODE_A ? "0" : "1", "");
+ return((int)sstate);
+ }
+ g_xfermode = y;
+ xfermode = y;
+#ifdef NEWFTP
+ if (ftpisopen()) { /* If an FTP connection is open */
+ extern int ftp_xfermode; /* change its transfer mode too */
+ ftp_xfermode = xfermode;
+ }
+#endif /* NEWFTP */
+ return(success = 1);
+
+#ifndef NOLOCAL
+ case XYX_DIS: /* Display */
+ return(doxdis(1)); /* 1 == Kermit */
+#endif /* NOLOCAL */
+
+ case XYX_SLO: /* Slow-start */
+ return(seton(&slostart));
+
+#ifndef NOSPL
+ case XYX_CRC: /* CRC */
+ return(seton(&docrc));
+#endif /* NOSPL */
+
+ case XYX_BEL: /* Bell */
+ return(seton(&xfrbel));
+
+#ifdef PIPESEND
+ case XYX_PIP: /* Pipes */
+#ifndef NOPUSH
+ if (nopush) {
+#endif /* NOPUSH */
+ printf("Sorry, access to pipes is disabled\n");
+ return(-9);
+#ifndef NOPUSH
+ } else
+#endif /* NOPUSH */
+ return(seton(&usepipes));
+#endif /* PIPESEND */
+
+ case XYX_INT: /* Interruption */
+ return(seton(&xfrint));
+
+ case XYX_XLA:
+ return(seton(&xfrxla)); /* Translation */
+
+ case XYX_MSG: {
+ extern char * xfrmsg;
+ if ((x = cmtxt("Prompt string","",&s,xxstring)) < 0)
+ return(x);
+ if (!*s) s = NULL;
+ makestr(&xfrmsg,s);
+ return(success = 1);
+
+ }
+ case XYX_RPT: {
+ extern int whereflg;
+ return(seton(&whereflg));
+ }
+ default:
+ return(-2);
+ }
+#endif /* NOXFER */
+ }
+
+ switch (xx) {
+
+#ifndef NOXMIT
+ case XYXMIT: /* SET TRANSMIT */
+ return(setxmit());
+#endif /* NOXMIT */
+
+#ifndef NOXFER
+#ifndef NOCSETS
+ case XYUNCS: /* UNKNOWN-CHARACTER-SET */
+ if ((y = cmkey(ifdtab,2,"","discard",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ unkcs = y;
+ return(success = 1);
+#endif /* NOCSETS */
+#endif /* NOXFER */
+
+#ifndef NOPUSH
+#ifdef UNIX
+ case XYWILD: /* WILDCARD-EXPANSION */
+ if ((y = cmkey(wildtab,nwild,
+ "Wildcard expansion option","on",xxstring)) < 0)
+ return(y);
+ if ((z = cmkey(wdottab,
+ 2,
+ "whether to match filenames that start with \".\"",
+ "/no-match-dot-files",
+ xxstring)
+ ) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (nopush) {
+ if (y > 0) {
+ printf("Shell expansion is disabled\n");
+ return(success = 0);
+ }
+ }
+ switch (y) {
+ case WILD_ON:
+ wildena = 1;
+ break;
+ case WILD_OFF:
+ wildena = 0;
+ break;
+ case WILD_KER:
+ wildxpand = 0; /* These are the previous */
+ break; /* hardwired values */
+ case WILD_SHE:
+ wildxpand = 1;
+ break;
+ }
+ matchdot = z;
+ return(success = 1);
+#endif /* UNIX */
+#endif /* NOPUSH */
+
+#ifndef NOXFER
+ case XYWIND: /* WINDOW-SLOTS */
+ if (protocol == PROTO_K) {
+ y = cmnum("Window size for Kermit protocol, 1 to 32",
+ "1", 10, &x, xxstring);
+ y = setnum(&z,x,y,MAXWS); /* == 32 */
+ }
+#ifdef CK_XYZ
+ else if (protocol == PROTO_Z) {
+ y = cmnum("Window size for ZMODEM protocol, 0 to 65535",
+ "0", 10, &x, xxstring);
+ y = setnum(&z,x,y,65535);
+ }
+#endif /* CK_XYZ */
+ else {
+ y = cmnum("Window size for current protocol",
+ "", 10, &x, xxstring);
+ y = setnum(&z,x,y,65472); /* Doesn't matter - we won't use it */
+ }
+ if (y < 0) return(y);
+ if (protocol == PROTO_K) {
+ if (z < 1)
+ z = 1;
+ }
+#ifdef CK_XYZ
+ else if (protocol == PROTO_Z) {
+ /* Zmodem windowing is closer to Kermit packet length */
+ /* than Kermit window size. If Window size is zero */
+ /* an end of frame and CRC is sent only at the end of */
+ /* the file (default). Otherwise, an End of Frame */
+ /* and CRC are sent after Window Size number of bytes */
+ if (z < 0) /* Disable windowing */
+ z = 0;
+ } else {
+ printf("?SET WINDOW does not apply to %s protocol\n",
+ ptab[protocol].p_name
+ );
+ }
+#endif /* CK_XYZ */
+
+#ifdef COMMENT
+ /* This is taken care of automatically now in protocol negotiation */
+ if (maxtry < z) {
+ printf("?Window slots must be less than retry limit\n");
+ return(success = 0);
+ }
+#endif /* COMMENT */
+ if (protocol == PROTO_K && rmsflg) { /* Set remote window size */
+ wslotr = z; /* Set local window size too */
+ ptab[protocol].winsize = wslotr;
+ sstate = setgen('S', "406", ckitoa(z), "");
+ return((int) sstate);
+ }
+ wslotr = z; /* Set requested window size here */
+ ptab[protocol].winsize = wslotr; /* and in protocol-specific table */
+ if (protocol == PROTO_K) { /* And for Kermit only... */
+ swcapr = (wslotr > 1) ? 1 : 0; /* set window bit in capas word */
+ if (wslotr > 1) { /* Window size > 1? */
+ /* Maybe adjust packet size */
+ y = adjpkl(urpsiz,wslotr,bigrbsiz);
+ if (y != urpsiz) { /* Did it change? */
+ urpsiz = y;
+ if (msgflg)
+ printf(
+" Adjusting receive packet-length to %d for %d window slots\n",
+ urpsiz,
+ wslotr
+ );
+ }
+ }
+ }
+ return(success = 1);
+#endif /* NOXFER */
+ }
+
+ switch (xx) {
+
+#ifndef NOSPL
+ case XYOUTP: /* OUTPUT command parameters */
+ if ((y = cmkey(outptab,noutptab,"OUTPUT command parameter","pacing",
+ xxstring)) < 0)
+ return(y);
+ switch(y) { /* Which parameter */
+ case OUT_PAC: /* PACING */
+ y = cmnum("Milliseconds to pause between each OUTPUT character",
+ "100", 10,&x,xxstring);
+ y = setnum(&z,x,y,16383); /* Verify and get confirmation */
+ if (y < 0) return(y);
+ if (z < 0) z = 0; /* (save some space) */
+ pacing = z;
+ return(success = 1);
+ case OUT_ESC: /* Special-escapes */
+ return(seton(&outesc));
+ default: /* (shouldn't happen) */
+ return(-2);
+ }
+#endif /* NOSPL */
+
+#ifdef CK_SPEED
+ case XYQCTL: {
+ short *p;
+ int zz;
+ if ((z = cmkey(ctltab,2, "control-character prefixing option",""
+ ,xxstring)) < 0)
+ return(z);
+ /* Make space for a temporary copy of the prefixing table */
+
+ p = (short *)malloc(256 * sizeof(short));
+ if (!p) {
+ printf("?Internal error - malloc failure\n");
+ return(-9);
+ }
+ for (i = 0; i < 256; i++) p[i] = ctlp[i]; /* Copy current table */
+
+ switch (z) {
+ case 0: /* UNPREFIXED control character */
+ case 1: /* PREFIXED control character */
+ while (1) { /* Collect a list of numbers */
+#ifndef NOSPL
+ x_ifnum = 1; /* Turn off complaints from eval() */
+#endif /* NOSPL */
+ if ((x = cmnum((z == 0) ?
+"\n Numeric ASCII value of control character that needs NO prefix,\n\
+ or the word \"all\", or carriage return to complete the list" :
+"\n Numeric ASCII value of control character that MUST BE prefixed,\n\
+ or the word \"all\", or carriage return to complete the list",
+ "",10,&y,xxstring
+ )) < 0) {
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) return(x);
+ break;
+ }
+ if (x == -2) {
+ if (p) { free((char *)p); p = NULL; }
+ debug(F110,"SET CONTROL atmbuf",atmbuf,0);
+ if (!ckstrcmp(atmbuf,"all",3,0) || /* "ALL" */
+ !ckstrcmp(atmbuf,"al",2,0) ||
+ !ckstrcmp(atmbuf,"a",1,0)) {
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ prefixing = z ? PX_ALL : PX_NON;
+ setprefix(prefixing);
+ return(success = 1);
+ } else { /* Not number, not ALL */
+ printf(
+ "?Please specify a number or the word ALL\n");
+ return(-9);
+ }
+ } else {
+ if (p) free((char *)p);
+ return(x);
+ }
+ }
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+#ifdef UNPREFIXZERO
+ zz = 0;
+#else
+#ifndef OS2
+ zz = 1 - z;
+#else
+ zz = 0; /* Allow 0 (but only for Zmodem) */
+#endif /* OS2 */
+#endif /* UNPREFIXZERO */
+
+ /* printf("x = %d, y = %d, z = %d, zz = %d\n", x,y,z,zz); */
+
+ if ((y > 31 && y < 127) || /* A specific numeric value */
+ (y > 159 && y < 255) || /* Check that it is a valid */
+ (y < zz) || /* control code. */
+ (y > 255)) {
+ printf("?Values allowed are: %d-31, 127-159, 255\n",zz);
+ if (p) free((char *)p);
+ return(-9);
+ }
+ x = y & 127; /* Get 7-bit value */
+ if (z == 0) { /* If they are saying it is safe... */
+ /* If flow control is Xon/Xoff */
+ if (((flow == FLO_XONX) &&
+ /* XON & XOFF chars not safe. */
+ (x == XON || x == XOFF))
+ ) {
+ if (msgflg)
+ printf(
+ "Sorry, not while Xon/Xoff is in effect.\n");
+ if (p) free((char *)p);
+ return(-9);
+ }
+#ifdef TNCODE
+ else if (network && IS_TELNET()
+ && (y == CR ||
+ (unsigned) y == (unsigned) 255)) {
+ if (msgflg)
+ printf("Sorry, not on a TELNET connection.\n");
+ if (p) free((char *)p);
+ return(-9);
+ }
+#endif /* TNCODE */
+ }
+ p[y] = (char) z; /* All OK, set flag */
+ } /* End of while loop */
+/*
+ Get here only if they have made no mistakes. Copy temporary table back to
+ permanent one, then free temporary table and return successfully.
+*/
+ for (i = 0; i < 256; i++) ctlp[i] = p[i];
+ if (p) free((char *)p);
+ if (z > 0) clearrq = 0; /* 199 (see SET PREFIXING) */
+ return(success = 1);
+ default:
+ return(-2);
+ }
+ }
+#endif /* CK_SPEED */
+ }
+
+ switch (xx) {
+
+#ifndef NOXFER
+ case XYREPT:
+ if ((y = cmkey(rpttab,2,
+ "repeat-count compression parameter","",xxstring)) < 0)
+ return(y);
+ switch(y) {
+ case 0:
+ return(success = seton(&rptena)); /* REPEAT COUNTS = ON, OFF */
+ case 1: /* REPEAT MININUM number */
+ printf("(not implemented yet, nothing happens)\n");
+ return(-9);
+ case 2: /* REPEAT PREFIX char */
+ if ((x = cmnum("ASCII value","",10,&z,xxstring)) < 0)
+ return(x);
+ if ((x = cmcfm()) < 0) return(x);
+ if ((z > 32 && z < 63) || (z > 95 && z < 127)) {
+ if (y == 1) rptmin = (CHAR) z; else myrptq = (CHAR) z;
+ return(success = 1);
+ } else {
+ printf("?Illegal value for prefix character\n");
+ return(-9);
+ }
+ }
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ case XYALRM: {
+#ifndef COMMENT
+ int yy;
+ long zz;
+ zz = -1L;
+ yy = x_ifnum;
+ x_ifnum = 1; /* Turn off internal complaints */
+ y = cmnum("Seconds from now, or time of day as hh:mm:ss",
+ "0" ,10, &x, xxstring);
+ x_ifnum = yy;
+ if (y < 0) {
+ if (y == -2) { /* Invalid number or expression */
+ zz = tod2sec(atmbuf); /* Convert to secs since midnight */
+ if (zz < 0L) {
+ printf("?Number, expression, or time of day required\n");
+ return(-9);
+ } else {
+ char now[32]; /* Current time */
+ char *p;
+ long tnow;
+ p = now;
+ ztime(&p);
+ tnow = atol(p+11) * 3600L +
+ atol(p+14) * 60L + atol(p+17);
+ if (zz < tnow) /* User's time before now */
+ zz += 86400L; /* So make it tomorrow */
+ zz -= tnow; /* Seconds from now. */
+ }
+ } else
+ return(y);
+ }
+ if (x < 0) {
+ printf("?Alarm time is in the past.\n");
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ if (zz > -1L) { /* Time of day given? */
+ x = zz;
+ if (zz != (long) x) {
+ printf(
+"Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
+ );
+ return(-9);
+ }
+ }
+ return(setalarm((long)x));
+ }
+#else
+/*
+ This is to allow long values where int and long are not the same, e.g.
+ on 16-bit systems. But something is wrong with it.
+*/
+ if ((y = cmtxt("seconds from now", "0", &s, xxstring)) < 0)
+ return(y);
+ if (rdigits(s)) {
+ return(setalarm(atol(s)));
+ } else {
+ printf("%s - not a number\n",s);
+ return(-9);
+ }
+#endif /* COMMENT */
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ case XYPROTO:
+ return(setproto());
+#endif /* NOXFER */
+
+/*
+ C-Kermit unprefixes control characters automatically on network connections
+ if CLEAR-CHANNEL is ON, which it is by default. But not all network
+ connections are transparent to all control characters. For example, the
+ DEC-20, even when you TELNET to it, is sensitive to Ctrl-O and Ctrl-T.
+ If you tell C-Kermit to SET CONTROL PREFIX 15 and/or 20, it doesn't help
+ because CLEAR-CHANNEL is still in effect. If the user goes to the trouble
+ to set up some prefixing, then Kermit should do what the user said. In
+ C-Kermit 7.1 Alpha.03 we change the code to set clearrq to 0 if the user
+ gives a SET PREFIXING or SET CONTROL PREFIX command.
+*/
+
+#ifdef CK_SPEED
+ case XYPREFIX: {
+#ifdef COMMENT
+ extern int clearrq;
+#endif /* COMMENT */
+ if ((z = cmkey(pfxtab, 4, "control-character prefixing option",
+ "", xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ clearrq = 0; /* 199 */
+ setprefix(z);
+#ifdef COMMENT
+ if (hints && (z == PX_ALL || z == PX_CAU) && clearrq) {
+ printf("Hint: Use SET CLEAR-CHANNEL OFF to disable negotiation of\n");
+ printf(" SET PREFIXING NONE during file transfers on reliable\n");
+ printf(" connections.\n");
+ }
+#endif /* COMMENT */
+ return(success = 1);
+ }
+#endif /* CK_SPEED */
+
+#ifndef NOSPL
+ case XYLOGIN:
+ if ((z = cmkey(logintab, 3, "value for login script","userid",
+ xxstring)) < 0)
+ return(z);
+ x = cmdgquo();
+ if (z == LOGI_PSW)
+ cmdsquo(0);
+ if ((y = cmtxt("text","", &s, NULL)) < 0) {
+ cmdsquo(x);
+ return(y);
+ }
+ cmdsquo(x);
+#ifdef IKSD
+ if (inserver)
+ return(success = 0);
+#endif /* IKSD */
+ s = brstrip(s);
+ if ((int)strlen(s) > 63) {
+ printf("Sorry, too long\n");
+ return(-9);
+ }
+ switch(z) {
+ case LOGI_UID:
+ ckstrncpy(uidbuf,s,UIDBUFLEN);
+ sl_uid_saved = 0;
+ break;
+ case LOGI_PSW:
+ ckstrncpy(pwbuf,s,PWBUFL);
+ if (pwbuf[0]) {
+ pwflg = 1;
+#ifdef OS2
+ pwcrypt = 1;
+#else /* OS2 */
+ pwcrypt = 0;
+#endif /* OS2 */
+ }
+ break;
+ case LOGI_PRM:
+ ckstrncpy(prmbuf,s,PWBUFL);
+ }
+ return(success = 1);
+#endif /* NOSPL */
+ }
+
+ switch (xx) {
+
+ case XYSTARTUP:
+ if ((y = cmkey(ifdtab,2,"","discard",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ DeleteStartupFile = (y != 0) ? 0 : 1;
+ return(success = 1);
+
+ case XYTMPDIR:
+ x = cmdir("Name of temporary directory","",&s,xxstring);
+ if (x == -3)
+ s = "";
+ else if (x < 0)
+ return(x);
+ if ((x = cmcfm()) < 0) return(x);
+ makestr(&tempdir,s);
+ return(tempdir ? 1 : 0);
+
+#ifndef NOXFER
+ case XYDEST: /* DESTINATION */
+ return(setdest());
+#endif /* NOXFER */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+
+/* Editor, Browser, and FTP Client */
+
+ case XYEDIT: /* EDITOR */
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+#endif /* CK_APC */
+
+#ifdef OS2ORUNIX
+ {
+ char *p = getenv("PATH");
+ char *e;
+ e = editor[0] ? (char *) editor : getenv("EDITOR");
+ if (!e) e = "";
+ if (p)
+ x = cmifip("Name of preferred editor",e,&s,&y,0,p,xxstring);
+ else
+ x = cmifi("Full path of preferred editor",e,&s,&y,xxstring);
+ if (x < 0 && x != -3)
+ return(x);
+ }
+#else
+#ifdef VMS
+ if ((y = cmtxt("DCL command for editing", "edit", &s, NULL)) < 0) {
+ if (x != -3)
+ return(x);
+ }
+#else
+ if ((x = cmifi("Full path of preferred editor","",&s,&y,xxstring))<0) {
+ if (x != -3)
+ return(x);
+ }
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#ifdef VMS
+ ckstrncpy(editor,s,CKMAXPATH);
+ editopts[0] = NUL;
+#else
+ if (y != 0) {
+ printf("?A single file please\n");
+ return(-2);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmtxt("editor command-line options","",&s,NULL)) < 0)
+ return(x);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((z = cmcfm()) < 0) return(z);
+ if (line[0]) {
+ zfnqfp(line,CKMAXPATH,editor);
+ ckstrncpy(editopts,tmpbuf,128);
+ } else {
+ editor[0] = NUL;
+ editopts[0] = NUL;
+ }
+#endif /* VMS */
+ return(success = 1);
+
+#ifndef NOFTP
+#ifndef SYSFTP
+#ifdef TCPSOCKET
+ case XYFTPX:
+ return(dosetftp()); /* SET FTP */
+#endif /* TCPSOCKET */
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+#ifdef BROWSER
+#ifndef NOFTP
+#ifdef SYSFTP
+ case XYFTP: /* SET FTP-CLIENT */
+#endif /* SYSFTP */
+#endif /* NOFTP */
+ case XYBROWSE: /* SET BROWSER */
+ {
+ char *p = getenv("PATH");
+ char *app = (char *) browser, *opts = (char *) browsopts;
+#ifndef NOFTP
+#ifdef SYSFTP
+ extern char ftpapp[], ftpopts[];
+ if (xx == XYFTP) {
+ app = (char *)ftpapp;
+ opts = (char *)ftpopts;
+ }
+#endif /* SYSFTP */
+#endif /* NOFTP */
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+#endif /* CK_APC */
+#ifdef OS2ORUNIX
+ if (p)
+ x = cmifip(xx == XYBROWSE ?
+ "Name of preferred browser" :
+ "Name of preferred ftp client",
+#ifdef OS2
+ xx == XYFTP ? "ftp.exe" : ""
+#else
+ xx == XYFTP ? "ftp" : ""
+#endif /* OS2 */
+ ,&s,&y,0,p,xxstring
+ );
+ else
+ x = cmifi(xx == XYBROWSE ?
+ "Full path of preferred browser" :
+ "Full path of preferred ftp client",
+ "",&s,&y,xxstring
+ );
+ if (x < 0 && x != -3)
+ return(x);
+#else
+#ifdef VMS
+ if ((x = cmtxt("DCL command to start your preferred Web browser",
+ "", &s, NULL)) < 0) {
+ if (x != -3)
+ return(x);
+ }
+#else
+ if ((x = cmifi("Full path of preferred browser","",&s,&y,xxstring)
+ ) < 0) {
+ if (x != -3)
+ return(x);
+ }
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#ifdef VMS
+ ckstrncpy(app,s,CKMAXPATH);
+ *opts = NUL;
+#else
+ if (y != 0) {
+ printf("?A single file please\n");
+ return(-2);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmtxt(xx == XYBROWSE ?
+ "browser command-line options" :
+ "ftp client command-line options",
+ "",&s,NULL)
+ ) < 0)
+ return(x);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((z = cmcfm()) < 0) return(z);
+ if (line[0]) {
+ zfnqfp(line,CKMAXPATH,app);
+ ckstrncpy(opts, tmpbuf, 128);
+ } else {
+ *app = NUL;
+ *opts = NUL;
+ }
+#endif /* VMS */
+ return(success = 1);
+ }
+#endif /* BROWSER */
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifdef CK_CTRLZ
+ case XYEOF: { /* SET EOF */
+ extern int eofmethod; extern struct keytab eoftab[];
+ if ((x = cmkey(eoftab,3,"end-of-file detection method","",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ eofmethod = x;
+ return(success = 1);
+ }
+#endif /* CK_CTRLZ */
+
+#ifdef SESLIMIT
+ case XYLIMIT: { /* Session-Limit (length of session in seconds) */
+ extern int seslimit;
+#ifdef OS2
+ extern int downloaded;
+#endif /* OS2 */
+ y = cmnum("Maximum length of session, seconds","0",10,&x,xxstring);
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+#ifdef OS2
+ || downloaded
+#endif /* OS2 */
+ ) {
+ if ((z = cmcfm()) < 0)
+ return(z);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+ return(setnum(&seslimit,x,y,86400));
+ }
+#endif /* SESLIMIT */
+
+ case XYRELY: { /* SET RELIABLE */
+ if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ reliable = x;
+ setreliable = (x != SET_AUTO);
+ debug(F101,"SET RELIABLE reliable","",reliable);
+ return(success = 1);
+ }
+
+#ifdef STREAMING
+ case XYSTREAM: { /* SET STREAMING */
+ extern int streamrq;
+ if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ streamrq = x;
+ return(success = 1);
+ }
+#endif /* STREAMING */
+
+#ifdef CKSYSLOG
+ case XYSYSL: {
+ if ((x = cmkey(syslogtab,nsyslog,"","",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+ ) {
+ printf("?Sorry, command disabled.\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+#endif /* CK_APC */
+ ckxsyslog = x;
+ return(success = 1);
+ }
+#endif /* CKSYSLOG */
+
+#ifdef TLOG
+ case XYTLOG: { /* SET TRANSACTION-LOG */
+ extern int tlogsep;
+ if ((x = cmkey(vbtab,nvb,"","verbose",xxstring)) < 0)
+ return(x);
+ if (x == 0) {
+ if ((y = cmtxt("field separator",",",&s,NULL)) < 0) return(y);
+ s = brstrip(s);
+ if (*s) {
+ if (s[1]) {
+ printf("?A single character, please.\n");
+ return(-9);
+ } else if ((*s >= '0' && *s <= '9') ||
+ (*s >= 'A' && *s <= 'Z') ||
+ (*s >= 'a' && *s <= 'z')) {
+ printf("?A non-alphanumeric character, please.\n");
+ return(-9);
+ } else
+ tlogsep = *s;
+ }
+ } else {
+ if ((y = cmcfm()) < 0) return(y);
+ }
+#ifdef IKSD
+ if (inserver && isguest) {
+ printf("?Sorry, command disabled.\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+#endif /* CK_APC */
+ tlogfmt = x;
+ return(success = 1);
+ }
+#endif /* TLOG */
+
+ case XYCLEAR: { /* SET CLEARCHANNEL */
+ if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ clearrq = x;
+ return(success = 1);
+ }
+
+#ifdef CK_AUTHENTICATION
+ case XYAUTH: { /* SET AUTHENTICATION */
+#ifdef CK_KERBEROS
+ int kv = 0;
+ extern struct krb_op_data krb_op;
+#endif /* CK_KERBEROS */
+ char * p = NULL;
+ if ((x =
+ cmkey(setauth,nsetauth,"authentication type","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+#ifdef CK_KERBEROS
+ case AUTH_KRB4: kv = 4; break; /* Don't assume values are same */
+ case AUTH_KRB5: kv = 5; break;
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+ case AUTH_SRP: break;
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ case AUTH_SSL:
+ case AUTH_TLS:
+ break;
+#endif /* CK_SSL */
+ default:
+ printf("?Authorization type not supported yet - \"%s\"\n",
+ atmbuf);
+ return(-9);
+ }
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+ ) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) {
+ if ((y = cmcfm()) < 0) return(y);
+ return(success = 0);
+ }
+#endif /* CK_APC */
+
+ switch(x) {
+#ifdef CK_KERBEROS
+ case AUTH_KRB4:
+ case AUTH_KRB5: {
+ if ((x = cmkey(kv == 4 ? k4tab : k5tab,
+ kv == 4 ? nk4tab : nk5tab,
+ "Kerberos parameter","",xxstring)) < 0) {
+ return(x);
+ }
+ s = "";
+ switch (x) {
+#ifdef KRB4
+ case XYKRBDBG:
+ if (kv == 4) {
+ if ((y = seton(&k4debug)) < 0)
+ return(y);
+#ifdef NT
+ ck_krb4_debug(k4debug);
+#endif /* NT */
+ } else {
+ return(-9);
+ }
+ break;
+#endif /* KRB4 */
+ case XYKRBLIF:
+ if ((y = cmnum("TGT lifetime","600",10,&z,xxstring)) < 0)
+ return(y);
+ break;
+ case XYKRBPRE:
+ if (kv == 4) {
+ if ((y = seton(&krb4_d_preauth)) < 0)
+ return(y);
+ } else {
+ return(-9);
+ }
+ break;
+ case XYKRBINS:
+ if ((y = cmtxt("Instance name","",&s,xxstring)) < 0)
+ return(y);
+ break;
+ case XYKRBFWD:
+ if (kv == 5) {
+ if ((y = seton(&krb5_d_forwardable)) < 0)
+ return(y);
+ } else {
+ return(-9);
+ }
+ break;
+ case XYKRBPRX:
+ if (kv == 5) {
+ if ((y = seton(&krb5_d_proxiable)) < 0)
+ return(y);
+ } else {
+ return(-9);
+ }
+ break;
+ case XYKRBRNW:
+ if ((y = cmnum("TGT renewable lifetime",
+ "0",10,&z,xxstring)) < 0)
+ return(y);
+ break;
+ case XYKRBADR:
+ if (kv == 5) {
+ if ((y = seton(&krb5_checkaddrs)) < 0)
+ return(y);
+ } else {
+ if ((y = seton(&krb4_checkaddrs)) < 0)
+ return(y);
+ }
+ break;
+ case XYKRBNAD:
+ if (kv == 5) {
+ if ((y = seton(&krb5_d_no_addresses)) < 0)
+ return(y);
+ }
+ break;
+ case XYKRBADD:
+ if (kv == 5) {
+ char * tmpaddrs[KRB5_NUM_OF_ADDRS];
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++)
+ tmpaddrs[i] = NULL;
+
+ if ((y =
+ cmfld("List of IP addresses","",&s,xxstring)) < 0)
+ return(y);
+ makelist(s,tmpaddrs,KRB5_NUM_OF_ADDRS);
+ if ((y = cmcfm()) < 0) {
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
+ if (tmpaddrs[i] != NULL)
+ free(tmpaddrs[i]);
+ }
+ return(y);
+ }
+ for (i = 0;
+ i < KRB5_NUM_OF_ADDRS && tmpaddrs[i];
+ i++) {
+ if (inet_addr(tmpaddrs[i]) == 0xffffffff) {
+ printf("invalid ip address: %s\n",
+ tmpaddrs[i]);
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
+ if (tmpaddrs[i] != NULL)
+ free(tmpaddrs[i]);
+ }
+ return(-9);
+ }
+ }
+ for (i = 0;
+ i < KRB5_NUM_OF_ADDRS && krb5_d_addrs[i];
+ i++) {
+ if (krb5_d_addrs[i])
+ free(krb5_d_addrs[i]);
+ krb5_d_addrs[i] = NULL;
+ }
+ for (i = 0;
+ i < KRB5_NUM_OF_ADDRS && tmpaddrs[i];
+ i++) {
+ krb5_d_addrs[i] = tmpaddrs[i];
+ tmpaddrs[i] = NULL;
+ }
+ krb5_d_addrs[i] = NULL;
+ return(success = 1);
+ }
+ break;
+
+ case XYKRBGET:
+ if (kv == 5) {
+ if ((y = seton(&krb5_autoget)) < 0)
+ return(y);
+ } else {
+ if ((y = seton(&krb4_autoget)) < 0)
+ return(y);
+ }
+ break;
+ case XYKRBDEL:
+ if ((z = cmkey(kdestab,nkdestab,
+ "Auto Destroy Tickets",
+ "never",xxstring)) < 0)
+ return(z);
+ break;
+ case XYKRBPR:
+ if ((y = cmtxt("User ID",uidbuf,&s,xxstring)) < 0)
+ return(y);
+ break;
+ case XYKRBRL:
+ if ((y = cmtxt("Name of realm","",&s,xxstring)) < 0)
+ return(y);
+ break;
+ case XYKRBKTB:
+ y = cmifi("Filename","",&s,&z,xxstring);
+ if (y != -3) {
+ if (y < 0)
+ return(y);
+ if (z) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ }
+ break;
+ case XYKRBCC:
+ if ((y = cmofi("Filename","",&s,xxstring)) < 0)
+ return(y);
+ break;
+ case XYKRBSRV:
+ if ((y = cmtxt("Name of service to use in ticket",
+ (kv == 4 ? "rcmd" : "host"),
+ &s,
+ xxstring
+ )) < 0)
+ return(y);
+ break;
+ case XYKRBK5K4:
+ if (kv == 5) {
+ if ((y = seton(&krb5_d_getk4)) < 0)
+ return(y);
+ } else {
+ return(-9);
+ }
+ break;
+ case XYKRBPRM: /* Prompt */
+ if ((z = cmkey(krbprmtab,2,"","",xxstring)) < 0)
+ return(z);
+ if ((y = cmtxt((z == KRB_PW_PRM) ?
+ "Text of prompt;\nmay contain \"%s\" to be replaced by principal name" :
+ "Text of prompt",
+ "",
+ &s,
+ xxstring
+ )
+ ) < 0)
+ return(y);
+ break;
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ if ((y = cmcfm()) < 0)
+ return(y);
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else /* IKSDCONF */
+ 1
+#endif /* IKSDCONF */
+ )
+ return(success = 0);
+#endif /* IKSD */
+
+ switch (x) { /* Copy value to right place */
+ case XYKRBLIF: /* Lifetime */
+ if (kv == 4)
+ krb4_d_lifetime = z;
+ else
+ krb5_d_lifetime = z;
+ break;
+ case XYKRBRNW:
+ if (kv == 5)
+ krb5_d_renewable = z;
+ break;
+ case XYKRBPR: /* Principal */
+ s = brstrip(s); /* Strip braces around. */
+ if (kv == 4)
+ makestr(&krb4_d_principal,s);
+ else
+ makestr(&krb5_d_principal,s);
+ break;
+ case XYKRBINS: /* Instance */
+ if (kv == 4)
+ makestr(&krb4_d_instance,s);
+ else
+ makestr(&krb5_d_instance,s);
+ break;
+ case XYKRBRL: /* Realm */
+ if (kv == 4)
+ makestr(&krb4_d_realm,s);
+ else
+ makestr(&krb5_d_realm,s);
+ break;
+ case XYKRBKTB: /* Key Table */
+ if (kv == 4)
+ makestr(&k4_keytab,s);
+ else
+ makestr(&k5_keytab,s);
+ break;
+ case XYKRBCC: /* Credentials cache */
+ makestr(&krb5_d_cc,s);
+ break;
+ case XYKRBSRV: /* Service Name */
+ if (kv == 4)
+ makestr(&krb4_d_srv,s);
+ else
+ makestr(&krb5_d_srv,s);
+ break;
+ case XYKRBDEL:
+ if (kv == 5)
+ krb5_autodel = z;
+ else
+ krb4_autodel = z;
+ break;
+ case XYKRBPRM: /* Prompt */
+ s = brstrip(s);
+ switch (z) {
+ case KRB_PW_PRM: { /* Password */
+ /* Check that there are no more than */
+ /* two % fields and % must followed by 's'. */
+ int i,n,len;
+ len = strlen(s);
+ for (i = 0, n = 0; i < len; i++) {
+ if (s[i] == '%') {
+ if (s[i+1] != '%') {
+ if (s[i+1] != 's') {
+ printf(
+ "Only %%s fields are permitted.\n"
+ );
+ return(-9);
+ }
+ if (++n > 2) {
+ printf(
+ "Only two %%s fields are permitted.\n");
+ return(-9);
+ }
+ }
+ i++;
+ }
+ }
+ if (kv == 5)
+ makestr(&k5pwprompt,s);
+ else
+ makestr(&k4pwprompt,s);
+ break;
+ }
+ case KRB_PR_PRM: { /* Principal */
+ /* Check to make sure there are no % fields */
+ int i,len;
+ len = strlen(s);
+ for (i = 0; i < len; i++) {
+ if (s[i] == '%') {
+ if (s[i+1] != '%') {
+ printf(
+ "%% fields are not used in this command.\n");
+ return(-9);
+ }
+ i++;
+ }
+ }
+ if (kv == 5)
+ makestr(&k5prprompt,s);
+ else
+ makestr(&k4prprompt,s);
+ break;
+ }
+ }
+ }
+ break;
+ }
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+ case AUTH_SRP: {
+ if ((x = cmkey(srptab, nsrptab,
+ "SRP parameter","",xxstring)) < 0) {
+ return(x);
+ }
+ s = "";
+ switch (x) {
+ case XYSRPPRM: /* Prompt */
+ if ((z = cmkey(srpprmtab,1,"","",xxstring)) < 0)
+ return(z);
+ if ((y = cmtxt(
+ "Text of prompt;\nmay contain one \"%s\" to be replaced by the username",
+ "",
+ &s,
+ xxstring
+ )
+ ) < 0)
+ return(y);
+ break;
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch (x) { /* Copy value to right place */
+ case XYSRPPRM: /* Prompt */
+ s = brstrip(s);
+ switch (z) {
+ case SRP_PW_PRM: { /* Password */
+ /* Check %s fields */
+ int i,n,len;
+ len = strlen(s);
+ for (i = 0, n = 0; i < len; i++) {
+ if (s[i] == '%') {
+ if (s[i+1] != '%') {
+ if (s[i+1] != 's') {
+ printf(
+ "Only %%s fields are permitted.\n");
+ return(-9);
+ }
+ if (++n > 1) {
+ printf(
+ "Only one %%s field is permitted.\n");
+ return(-9);
+ }
+ }
+ i++;
+ }
+ }
+ makestr(&srppwprompt,s);
+ break;
+ }
+ }
+ }
+ break;
+ }
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ case AUTH_SSL:
+ case AUTH_TLS: {
+ if ((z = cmkey(ssltab, nssltab,
+ (x == AUTH_SSL ? "SSL parameter" : "TLS parameter"),
+ "",xxstring)) < 0)
+ return(z);
+ s = "";
+ switch (z) {
+ case XYSSLRCFL: /* SSL/TLS RSA Certs file */
+ case XYSSLRCCF: /* SSL/TLS RSA Certs Chain file */
+ case XYSSLRKFL: /* SSL/TLS RSA Key File */
+ case XYSSLDCFL: /* SSL/TLS DSA Certs file */
+ case XYSSLDCCF: /* SSL/TLS DSA Certs Chain file */
+ case XYSSLDKFL: /* SSL/TLS DH Key File */
+ case XYSSLDPFL: /* SSL/TLS DH Param File */
+ case XYSSLCRL: /* SSL/TLS CRL File */
+ case XYSSLVRFF: /* SSL/TLS Verify File */
+ case XYSSLRND: /* SSL/TLS Random File */
+ y = cmifi("Filename","",&s,&x,xxstring);
+ if (y != -3) {
+ if (y < 0)
+ return(y);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ s = brstrip(s);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch (z) {
+ case XYSSLRCFL: /* SSL/TLS RSA Certs file */
+ if (!s[0] && ssl_rsa_cert_file) {
+ free(ssl_rsa_cert_file);
+ ssl_rsa_cert_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_rsa_cert_file,s);
+ if (!ssl_rsa_key_file)
+ makestr(&ssl_rsa_key_file,s);
+ }
+ break;
+ case XYSSLRCCF: /* SSL/TLS RSA Certs Chain file */
+ if (!s[0] && ssl_rsa_cert_chain_file) {
+ free(ssl_rsa_cert_chain_file);
+ ssl_rsa_cert_chain_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_rsa_cert_chain_file,s);
+ }
+ break;
+ case XYSSLRKFL: /* SSL/TLS RSA Key File */
+ if (!s[0] && ssl_rsa_key_file) {
+ free(ssl_rsa_key_file);
+ ssl_rsa_key_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_rsa_key_file,s);
+ }
+ break;
+ case XYSSLDCFL: /* SSL/TLS DSA Certs file */
+ if (!s[0] && ssl_dsa_cert_file) {
+ free(ssl_dsa_cert_file);
+ ssl_dsa_cert_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_dsa_cert_file,s);
+ if (!ssl_dh_key_file)
+ makestr(&ssl_dh_key_file,s);
+ }
+ break;
+ case XYSSLDCCF: /* SSL/TLS DSA Certs Chain file */
+ if (!s[0] && ssl_dsa_cert_chain_file) {
+ free(ssl_dsa_cert_chain_file);
+ ssl_dsa_cert_chain_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_dsa_cert_chain_file,s);
+ }
+ break;
+ case XYSSLDKFL: /* SSL/TLS DH Key File */
+ if (!s[0] && ssl_dh_key_file) {
+ free(ssl_dh_key_file);
+ ssl_dh_key_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_dh_key_file,s);
+ }
+ break;
+ case XYSSLDPFL: /* SSL/TLS DH Param File */
+ if (!s[0] && ssl_dh_param_file) {
+ free(ssl_dh_param_file);
+ ssl_dh_param_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_dh_param_file,s);
+ }
+ break;
+ case XYSSLCRL: /* SSL/TLS CRL File */
+ if (!s[0] && ssl_crl_file) {
+ free(ssl_crl_file);
+ ssl_crl_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_crl_file,s);
+ }
+ break;
+ case XYSSLVRFF: /* SSL/TLS Verify File */
+ if (!s[0] && ssl_verify_file) {
+ free(ssl_verify_file);
+ ssl_verify_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_verify_file,s);
+ }
+ break;
+ case XYSSLRND: /* SSL/TLS Random File */
+ if (!s[0] && ssl_rnd_file) {
+ free(ssl_rnd_file);
+ ssl_rnd_file = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_rnd_file,s);
+ }
+ break;
+ }
+ break;
+
+ case XYSSLCRLD:
+ case XYSSLVRFD: {
+ char * d = NULL;
+ if (z == XYSSLVRFD)
+ d= getenv("SSL_CERT_DIR");
+ if (d == NULL)
+ d = "";
+ if ((y = cmdir("Directory",d,&s,xxstring)) < 0)
+ if (y != -3)
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ s = brstrip(s);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch(z) {
+ case XYSSLCRLD:
+ if (!s[0] && ssl_crl_dir) {
+ free(ssl_crl_dir);
+ ssl_crl_dir = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_crl_dir,s);
+ }
+ break;
+ case XYSSLVRFD:
+ if (!s[0] && ssl_verify_dir) {
+ free(ssl_verify_dir);
+ ssl_verify_dir = NULL;
+ } else if (s[0]) {
+ makestr(&ssl_verify_dir,s);
+ }
+ break;
+ }
+ break;
+ }
+ case XYSSLCOK: /* SSL/TLS Certs-Ok flag */
+ if ((y = seton(&ssl_certsok_flag)) < 0)
+ return(y);
+ break;
+ case XYSSLDBG: /* SSL/TLS Debug flag */
+ if ((y = seton(&ssl_debug_flag)) < 0)
+ return(y);
+ break;
+ case XYSSLON: /* SSL/TLS Only flag */
+ switch (x) {
+ case AUTH_SSL:
+ if ((y = seton(&ssl_only_flag)) < 0)
+ return(y);
+ break;
+ case AUTH_TLS:
+ if ((y = seton(&tls_only_flag)) < 0)
+ return(y);
+ break;
+ }
+ break;
+ case XYSSLVRB: /* SSL/TLS Verbose flag */
+ if ((y = seton(&ssl_verbose_flag)) < 0)
+ return(y);
+ break;
+ case XYSSLVRF: /* SSL/TLS Verify flag */
+ if ((x = cmkey(sslvertab, nsslvertab,
+ "SSL/TLS verify mode",
+ "peer-cert",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ssl_verify_flag = x;
+ break;
+ case XYSSLDUM:
+ if ((y = seton(&ssl_dummy_flag)) < 0)
+ return(y);
+ break;
+ case XYSSLCL: { /* SSL/TLS Cipher List */
+#ifdef COMMENT
+ /* This code is used to generate a colon delimited */
+ /* list of the ciphers currently in use to be used */
+ /* as the default for cmtxt(). However, a better */
+ /* default is simply the magic keyword "ALL". */
+ CHAR def[1024] = "";
+ if (ssl_con != NULL) {
+ CHAR * p = NULL, *q = def;
+ int i, len;
+
+ for (i = 0; ; i++) {
+ p = (CHAR *) SSL_get_cipher_list(ssl_con,i);
+ if (p == NULL)
+ break;
+ len = strlen(p);
+ if (q+len+1 >= def+1024)
+ break;
+ if (i != 0)
+ *q++ = ':';
+ strcpy(q,p);
+ q += len;
+ }
+ }
+#endif /* COMMENT */
+ char * p = getenv("SSL_CIPHER");
+ if (!p)
+ p = "ALL";
+ if ((y = cmtxt(
+ "Colon-delimited list of ciphers or ALL (case-sensitive)",
+ p,
+ &s,
+ xxstring
+ )
+ ) < 0)
+ return(y);
+ makestr(&ssl_cipher_list,s);
+ if (ssl_con == NULL) {
+ SSL_library_init();
+ ssl_ctx = (SSL_CTX *)
+ SSL_CTX_new((SSL_METHOD *)TLSv1_method());
+ if (ssl_ctx != NULL)
+ ssl_con= (SSL *) SSL_new(ssl_ctx);
+ }
+ if (ssl_con) {
+ SSL_set_cipher_list(ssl_con,ssl_cipher_list);
+ }
+ break;
+ }
+ }
+ break;
+ }
+#endif /* CK_SSL */
+ default:
+ break;
+ }
+ return(success = 1);
+ }
+#endif /* CK_AUTHENTICATION */
+
+#ifndef NOSPL
+ case XYFUNC:
+ if ((x = cmkey(functab,nfunctab,"","diagnostics",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case FUNC_DI: return(seton(&fndiags));
+ case FUNC_ER: return(seton(&fnerror));
+ default: return(-2);
+ }
+#endif /* NOSPL */
+
+ case XYSLEEP: /* SET SLEEP / PAUSE */
+ if ((x = cmkey(sleeptab,1,"","cancellation",xxstring)) < 0)
+ return(x);
+ return(seton(&sleepcan));
+
+ case XYCD: /* SET CD */
+ if ((x = cmkey(cdtab,ncdtab,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case XYCD_H: { /* SET CD HOME */
+ extern char * myhome;
+ if ((y = cmdir("Directory name",zhome(),&s,xxstring)) < 0)
+ return(y);
+ makestr(&myhome,s);
+ return(success = 1);
+ }
+ case XYCD_M: /* SET CD MESSAGE */
+ if ((x = cmkey(cdmsg,ncdmsg,"","",xxstring)) < 0)
+ return(x);
+ if (x == 2) { /* CD MESSAGE FILE */
+ if ((x = cmtxt("Name of file","",&s,NULL)) < 0)
+ return(x);
+ if (!*s) {
+ s = NULL;
+#ifndef NOXFER
+ srvcdmsg = 0;
+#endif /* NOXFER */
+ }
+ makestr(&cdmsgstr,s);
+ makelist(cdmsgstr,cdmsgfile,8);
+ return(success = 1);
+ }
+
+ if ((y = cmcfm()) < 0) return(y); /* CD-MESSAGE ON/OFF */
+#ifndef NOXFER
+ if (x > 0)
+ srvcdmsg |= 2;
+ else
+ srvcdmsg &= 1;
+#endif /* NOXFER */
+ return(success = 1);
+
+ case XYCD_P: { /* SET CD PATH */
+ extern char * ckcdpath;
+ if ((x = cmtxt("CD PATH string","",&s,xxstring)) < 0)
+ return(x);
+ makestr(&ckcdpath,s);
+ return(success = 1);
+ }
+ }
+
+#ifndef NOLOCAL
+#ifdef STOPBITS
+ case XYSTOP: /* STOP-BITS */
+ if ((x = cmkey(stoptbl,2,"Stop bits for serial device","",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if (x > 0 && x < 3) {
+ stopbits = x;
+#ifdef TN_COMPORT
+ if (network && istncomport()) {
+ tnsettings(-1, x);
+ return(success = 1);
+ }
+#endif /* TN_COMPORT */
+#ifdef HWPARITY
+ return(success = 1);
+#else /* HWPARITY */
+ return(-2);
+#endif /* HWPARITY */
+ } else
+ return(-2);
+#endif /* STOPBITS */
+
+ case XYDISC: {
+ extern int clsondisc;
+ return(seton(&clsondisc));
+ }
+
+ case XYSERIAL: {
+ /* char c; */
+ extern int cmask;
+ if ((x = cmkey(sertbl,nsertbl,
+ "Serial device character size, parity, and stop bits",
+ "8N1", xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,atmbuf,LINBUFSIZ); /* Associated keyword string */
+ s = line;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ckstrncpy(line,sernam[x],LINBUFSIZ);
+ s = line;
+ if (s[0] != '8' && s[0] != '7') /* Char size */
+ return(-2);
+ else
+ z = s[0] - '0';
+ if (isupper(s[1])) /* Parity */
+ s[1] = tolower(s[1]);
+ if (s[2] != '1' && s[2] != '2') /* Stop bits */
+ return(-2);
+ else
+ stopbits = s[2] - '0';
+ if (z == 8) { /* 8 bits + parity (or not) */
+ parity = 0; /* Set parity */
+ hwparity = (s[1] == 'n') ? 0 : s[1];
+ setcmask(8); /* Also set TERM BYTESIZE to 8 */
+ } else { /* 7 bits plus parity */
+ parity = (s[1] == 'n') ? 0 : s[1];
+ hwparity = 0;
+ setcmask(7); /* Also set TERM BYTESIZE to 7 */
+ }
+#ifdef TN_COMPORT
+ if (network && !istncomport())
+ tnsettings(parity, stopbits);
+#endif /* TN_COMPORT */
+
+ return(success = 1); /* from SET SERIAL */
+ }
+
+ case XYOPTS: { /* SET OPTIONS */
+ extern int setdiropts();
+ extern int settypopts();
+#ifdef CKPURGE
+ extern int setpurgopts();
+#endif /* CKPURGE */
+ if ((x = cmkey(optstab,noptstab,"for command","", xxstring)) < 0)
+ return(x);
+ switch (x) {
+#ifndef NOFRILLS
+ case XXDEL:
+ return(setdelopts());
+#endif /* NOFRILLS */
+ case XXDIR:
+ return(setdiropts());
+ case XXTYP:
+ return(settypopts());
+#ifdef CKPURGE
+ case XXPURGE:
+ return(setpurgopts());
+#endif /* CKPURGE */
+ default:
+ return(-2);
+ }
+ }
+#endif /* NOLOCAL */
+#ifndef NOXFER
+ case XYQ8FLG: {
+ extern int q8flag;
+ return(seton(&q8flag));
+ }
+ case XYTIMER: {
+ extern int asktimer;
+ y = cmnum("Time limit for ASK command, seconds","0",10,&x,xxstring);
+#ifdef QNX16
+ return(setnum(&asktimer,x,y,32767));
+#else
+ return(setnum(&asktimer,x,y,86400));
+#endif /* QNX16 */
+ }
+ case XYFACKB: {
+ extern int fackbug;
+ return(seton(&fackbug));
+ }
+#endif /* NOXFER */
+
+ case XYHINTS:
+ return(seton(&hints));
+
+#ifndef NOSPL
+ case XYEVAL: {
+ extern int oldeval;
+ if ((x = cmkey(oldnew,2,"","", xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ oldeval = x;
+ return(success = 1);
+ }
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ case XYFACKP: {
+ extern int fackpath;
+ return(seton(&fackpath));
+ }
+#endif /* NOXFER */
+
+ case XYQNXPL: {
+ extern int qnxportlock;
+ return(seton(&qnxportlock));
+ }
+
+#ifndef NOCMDL
+#ifdef IKSD
+ case XYIKS: {
+ int setiks();
+ return(setiks());
+ }
+#endif /* IKSD */
+#endif /* NOCMDL */
+
+#ifdef CKROOT
+ case XYROOT:
+ return(dochroot());
+#endif /* CKROOT */
+
+#ifndef NOSPL
+#ifndef NOSEXP
+ case XYSEXP: {
+ if ((x = cmkey(sexptab,3,"","", xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case 0:
+ if ((x = cmkey(ooatab,3,"","automatic", xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ sexpecho = x;
+ break;
+ case 1: {
+ int i, xx;
+ xx = sexpmaxdep;
+ if ((y = cmnum("Maximum recursion depth",
+ "1000",10,&x,xxstring)) < 0)
+ return(y);
+ z = setnum(&sexpmaxdep,x,y,-1);
+ if (z < 0)
+ return(z);
+ if (sxresult) { /* Free old stack if allocated */
+ for (i = 0; i < xx; i++)
+ if (sxresult[i]) free(sxresult[i]);
+ free((char *)sxresult);
+ if (sxrlen) free((char *)sxrlen);
+ sxresult = NULL;
+ sxrlen = NULL;
+ }
+ break;
+ }
+ case 2:
+ return(seton(&sexptrunc));
+ }
+ return(success = 1);
+ }
+#endif /* NOSEXPL */
+#endif /* NOSPL */
+
+#ifdef NEWFTP
+ case XYGPR: {
+ extern struct keytab gprtab[];
+ extern int ftpget;
+ if ((x = cmkey(gprtab,3,"","kermit", xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ftpget = x;
+ return(success = 1);
+ }
+#endif /* NEWFTP */
+
+#ifdef ANYSSH
+ case XYSSH:
+ return(dosetssh());
+#endif /* ANYSHH */
+
+#ifdef SFTP_BUILTIN
+ case XYSFTP:
+ return(dosetsftp());
+#endif /* SFTP_BUILTIN */
+
+#ifdef LOCUS
+ case XYLOCUS:
+ if ((x = cmkey(locustab,nlocustab,"",
+#ifdef KUI
+ "ask"
+#else
+ "auto"
+#endif /* KUI */
+ ,xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if (x == 2 || x == 3) { /* AUTO or ASK */
+ setautolocus(x - 1); /* Two forms of automatic locusing */
+ /* setlocus(1,0); */ /* we're not changing the locus here */
+ } else { /* LOCAL or REMOTE */
+ setautolocus(0); /* No automatic Locus changing */
+ setlocus(x,0); /* Set Locus as requested */
+ }
+ return(success = 1);
+#endif /* LOCUS */
+
+#ifdef KUI
+ case XYGUI:
+ return(setgui());
+#endif /* KUI */
+
+#ifndef NOFRILLS
+#ifndef NORENAME
+ case XY_REN: /* SET RENAME */
+ return(setrename());
+#endif /* NORENAME */
+#endif /* NOFRILLS */
+
+#ifndef NOPUSH
+#ifdef CK_REDIR
+#ifndef NOXFER
+ case XYEXTRN: /* SET EXTERNAL-PROTOCOL */
+ return(setextern());
+#endif /* NOXFER */
+#endif /* CK_REDIR */
+#endif /* NOPUSH */
+
+#ifndef NOSPL
+ case XYVAREV: /* SET VARIABLE-EVALUATION */
+ return(setvareval());
+#endif /* NOSPL */
+
+ default:
+ if ((x = cmcfm()) < 0) return(x);
+ printf("Not implemented - %s\n",cmdbuf);
+ return(success = 0);
+ }
+}
+
+/*
+ H U P O K -- Is Hangup OK?
+
+ Issues a warning and gets OK from user depending on whether a connection
+ seems to be open and what the SET EXIT WARNING setting is. Returns:
+ 0 if not OK to hang up or exit (i.e. user said No);
+ nonzero if OK.
+ Argument x is used to differentiate the EXIT command from SET LINE / HOST.
+*/
+int
+hupok(x) int x; { /* Returns 1 if OK, 0 if not OK */
+ int y, z = 1;
+ extern int exithangup;
+#ifdef VMS
+ extern int batch;
+
+ if (batch) /* No warnings in batch */
+ return(1);
+#else
+#ifdef UNIX
+ if (backgrd) /* No warnings in background */
+ return(1);
+#endif /* UNIX */
+#endif /* VMS */
+
+#ifndef K95G
+ debug(F101,"hupok local","",local);
+
+ if (!local) /* No warnings in remote mode */
+ return(1);
+#endif /* K95G */
+
+ if (x == 0 && exithangup == 0) /* EXIT and EXIT HANGUP is OFF */
+ return(1);
+
+ debug(F101,"hupok x","",x);
+ debug(F101,"hupok xitwarn","",xitwarn);
+ debug(F101,"hupok network","",network);
+ debug(F101,"hupok haveline","",haveline);
+
+ if ((local && xitwarn) || /* Is a connection open? */
+ (!x && xitwarn == 2)) { /* Or Always give warning on EXIT */
+ int needwarn = 0;
+ char warning[256];
+
+ if (network) {
+ if (ttchk() >= 0)
+ needwarn = 1;
+ /* A connection seems to be open but it can't possibly be */
+ if (!haveline)
+ needwarn = 0;
+ if (needwarn) {
+ if (strcmp(ttname,"*"))
+ ckmakmsg(warning,256,
+ " A network connection to ",ttname,
+ " might still be active.\n",NULL);
+ else
+ ckstrncpy(warning,
+ " An incoming network connection might still be active.\n",
+ 256);
+ }
+ } else { /* Serial connection */
+ if (carrier == CAR_OFF) /* SET CARRIER OFF */
+ needwarn = 0; /* so we don't care about carrier. */
+ else if ((y = ttgmdm()) >= 0) /* else, get modem signals */
+ needwarn = (y & BM_DCD); /* Check for carrier */
+ else /* If we can't get modem signals... */
+ needwarn = (ttchk() >= 0);
+ /* A connection seems to be open but it can't possibly be */
+ if (!haveline || !exithangup)
+ needwarn = 0;
+ if (needwarn)
+ ckmakmsg(warning,256,
+ " A serial connection might still be active on ",
+ ttname,".\n",NULL);
+ }
+
+/* If a warning was issued, get user's permission to EXIT. */
+
+ if (needwarn || (!x && xitwarn == 2
+#ifndef K95G
+ && local
+#endif /* K95G */
+ )) {
+ if ( !needwarn )
+ ckstrncpy(warning, "No active connections", 256);
+
+#ifdef COMMENT
+ printf("%s",warning);
+ z = getyesno(x ? "OK to close? " : "OK to exit? ",0);
+ debug(F101,"hupok getyesno","",z);
+ if (z < -3) z = 0;
+#else
+ z = uq_ok(warning,
+ x ? "OK to close? " : "OK to exit? ",
+ 3,
+ NULL,
+ 0
+ );
+ debug(F101,"hupok uq_ok","",z);
+ if (z < 0) z = 0;
+#endif /* COMMENT */
+ }
+ }
+ return(z);
+}
+
+#ifndef NOSHOW
+VOID
+shoctl() { /* SHOW CONTROL-PREFIXING */
+#ifdef CK_SPEED
+ int i;
+#ifdef OS2
+ int zero;
+#endif /* OS2 */
+ printf(
+"\ncontrol quote = %d, applied to (0 = unprefixed, 1 = prefixed):\n\n",
+ myctlq);
+#ifdef OS2
+#ifndef UNPREFIXZERO
+ zero = ctlp[0];
+ if (protocol == PROTO_K) /* Zero can't be unprefixed */
+ ctlp[0] = 1; /* for Kermit */
+#endif /* UNPREFIXZERO */
+#endif /* OS2 */
+ for (i = 0; i < 16; i++) {
+ printf(" %3d: %d %3d: %d ",i,ctlp[i], i+16, ctlp[i+16]);
+ if (i == 15)
+ printf(" 127: %d",ctlp[127]);
+ else
+ printf(" ");
+ printf(" %3d: %d %3d: %d ",i+128,ctlp[i+128], i+144, ctlp[i+144]);
+ if (i == 15) printf(" 255: %d",ctlp[255]);
+ printf("\n");
+ }
+ printf("\n");
+#ifndef UNPREFIXZERO
+#ifdef OS2
+ ctlp[0] = zero;
+#endif /* OS2 */
+#endif /* UNPREFIXZERO */
+
+#endif /* CK_SPEED */
+}
+
+#ifndef NOXFER
+VOID
+shodbl() { /* SHOW DOUBLE/IGNORE */
+#ifdef CKXXCHAR
+ int i, n = 0;
+ printf("\nSET SEND DOUBLE characters:\n");
+ for (i = 0; i < 255; i++) {
+ if (dblt[i] & 2) {
+ n++;
+ printf(" %d", i);
+ }
+ }
+ if (n == 0)
+ printf(" (none)");
+ n = 0;
+ printf("\nSET RECEIVE IGNORE characters:\n");
+ for (i = 0; i < 255; i++) {
+ if (dblt[i] & 1) {
+ n++;
+ printf(" %d", i);
+ }
+ }
+ if (n == 0)
+ printf(" (none)");
+ printf("\n\n");
+#endif /* CKXXCHAR */
+}
+#endif /* NOXFER */
+#endif /* NOSHOW */
+
+#ifndef NOPUSH
+#ifdef CK_REXX
+/*
+ Rexx command. Note, this is not OS/2-specific, because Rexx also runs
+ on other systems where C-Kermit also runs, like the Amiga.
+*/
+#define REXBUFL 100 /* Change this if neccessary */
+char rexxbuf[REXBUFL] = { '\0' }; /* Rexx's return value (string) */
+
+int
+dorexx() {
+ int x, y;
+ char *rexxcmd;
+
+ if ((x = cmtxt("Rexx command","",&rexxcmd,xxstring)) < 0)
+ return(x);
+
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ /* Don't let this be set remotely */
+ if (apcactive == APC_LOCAL ||
+ apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))
+ return(success = 0);
+#endif /* CK_APC */
+
+ ckstrncpy(line,rexxcmd,LINBUFSIZ);
+ rexxcmd = line;
+#ifdef OS2
+ return(os2rexx(rexxcmd,rexxbuf,REXBUFL));
+#else /* !OS2 */
+ printf("Sorry, nothing happens.\n");
+ return(success = 0);
+#endif /* OS2 */
+}
+#endif /* CK_REXX */
+#endif /* NOPUSH */
+#else /* NOICP */
+VOID
+dologend() {
+ /* Dummy write record to connection log */
+}
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuus4.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus4.c
new file mode 100644
index 0000000..946603a
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus4.c
@@ -0,0 +1,15087 @@
+#include "ckcsym.h"
+
+/* C K U U S 4 -- "User Interface" for C-Kermit, part 4 */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ File ckuus4.c -- Functions moved from other ckuus*.c modules to even
+ out their sizes.
+*/
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckcnet.h" /* Network symbols */
+#include "ckuusr.h"
+#include "ckuver.h"
+#include "ckcxla.h" /* Character sets */
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifdef VMS
+#include <errno.h> /* For \v(errno) */
+extern char * ckvmserrstr(unsigned long);
+#ifndef OLD_VMS
+#include <lib$routines.h> /* Not for VAX C 2.4 */
+#else
+#include <libdef.h>
+#endif /* OLD_VMS */
+_PROTOTYP(int vmsttyfd, (void) );
+#endif /* VMS */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#define APIRET ULONG
+#endif /* NT */
+#include "ckocon.h"
+#include "ckoetc.h"
+int StartedFromDialer = 0;
+HWND hwndDialer = 0;
+LONG KermitDialerID = 0;
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef CK_PID
+#include <process.h>
+#endif /* CK_PID */
+#endif /* OS2 */
+
+#ifdef KUI
+extern struct keytab * term_font;
+extern int ntermfont, tt_font, tt_font_size;
+#endif /* KUI */
+
+extern xx_strp xxstring;
+
+#ifdef DEC_TCPIP
+#include <descrip>
+#include <dvidef>
+#include <dcdef>
+#endif /* DEC_TCPIP */
+
+#ifdef FNFLOAT
+#include <math.h> /* Floating-point functions */
+#endif /* FNFLOAT */
+
+extern int quiet, network, xitsta, escape, nopush, xferstat,
+ exitonclose, tn_exit, ttnproto, autodl, flow, byteorder, what, lastxfer;
+
+extern int filepeek, nscanfile, makestrlen;
+extern char * k_info_dir;
+
+#ifndef MAC
+#ifndef AMIGA
+extern int ttyfd;
+#endif /* MAC */
+#endif /* AMIGA */
+
+#ifdef TNCODE
+extern int tn_nlm, tn_b_nlm, tn_b_xfer, tn_sb_bug;
+extern int tn_rem_echo;
+extern int tn_b_meu, tn_b_ume, tn_auth_krb5_des_bug;
+#endif /* TNCODE */
+
+static char * lastkwval = NULL;
+
+char * xferfile = NULL;
+int xferlog = 0;
+
+extern int local, xargc, stayflg, rcflag, bgset, backgrd, cfilef,
+ inserver, srvcdmsg, success;
+
+#ifdef VMS
+extern int batch;
+#endif /* VMS */
+
+extern char cmdfil[], *versio, *ckxsys, **xargv;
+#ifdef DEBUG
+extern char debfil[]; /* Debug log file name */
+extern int debtim;
+#endif /* DEBUG */
+
+extern int noinit;
+
+static char ndatbuf[10];
+
+char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+char *
+zzndate() { /* Returns today's date as yyyymmdd */
+ char * p = NULL;
+ int x;
+
+/* WARNING - This will fail if asctime() returns non-English month names */
+
+ ztime(&p); /* Get "asctime" string */
+ if (p == NULL || *p == NUL) return("");
+ for (x = 20; x < 24; x++) /* yyyy */
+ ndatbuf[x - 20] = p[x];
+ ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]);
+ ndatbuf[7] = p[9]; /* dd */
+ for (x = 0; x < 12; x++) /* mm */
+ if (!strncmp(p+4,months[x],3)) break;
+ if (x == 12) {
+ ndatbuf[4] = ndatbuf[5] = '?';
+ } else {
+ x++;
+ ndatbuf[4] = (char) ((x < 10) ? '0' : '1');
+ ndatbuf[5] = (char) ((x % 10) + 48);
+ }
+ ndatbuf[8] = NUL;
+ debug(F110,"zzndate return",ndatbuf,0);
+ return((char *)ndatbuf);
+}
+
+#ifdef DCMDBUF
+extern struct cmdptr *cmdstk;
+extern char *line, *tmpbuf;
+#else
+extern struct cmdptr cmdstk[];
+extern char line[], tmpbuf[];
+#endif /* DCMDBUF */
+
+#ifdef OS2
+extern char exedir[];
+#else
+extern char * exedir;
+#endif /* OS2 */
+
+extern int nettype;
+
+#ifndef NOICP /* Most of this file... */
+#ifdef CKLOGDIAL
+extern char diafil[];
+#endif /* CKLOGDIAL */
+
+#ifndef AMIGA
+#ifndef MAC
+#include <signal.h>
+#endif /* MAC */
+#endif /* AMIGA */
+
+#ifdef SV68 /* July 2006 believe it or not */
+#ifndef SEEK_CUR
+#include <unistd.h>
+#endif /* SEEK_CUR */
+#endif /* SV68 */
+
+#ifdef SCO32 /* June 2011 believe it or not... */
+#ifdef XENIX
+#ifndef SEEK_CUR
+#include <unistd.h>
+#endif /* SEEK_CUR */
+#endif /* XENIX */
+#endif /* SCO32 */
+
+#ifdef STRATUS /* Stratus Computer, Inc. VOS */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef getchar
+#undef getchar
+#endif /* getchar */
+#define getchar(x) coninc(0)
+#endif /* STRATUS */
+
+
+#ifdef ANYX25
+extern int revcall, closgr, cudata;
+int x25ver;
+extern char udata[];
+#ifndef IBMX25
+extern int npadx3;
+extern CHAR padparms[];
+extern struct keytab padx3tab[];
+#endif /* !IBMX25 */
+#ifdef IBMX25
+/* global variables only available for IBM X.25 - possibly interesting for
+ * other implementations
+ */
+extern x25addr_t local_nua;
+extern x25addr_t remote_nua;
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifdef NETCONN
+#ifndef NODIAL
+extern int nnetdir;
+extern char *netdir[];
+#endif /* NODIAL */
+extern char ipaddr[];
+
+#ifdef CK_NETBIOS
+extern unsigned short netbiosAvail;
+extern unsigned long NetbeuiAPI;
+extern unsigned char NetBiosName[];
+extern unsigned char NetBiosAdapter;
+extern unsigned char NetBiosLSN;
+#endif /* CK_NETBIOS */
+
+#ifdef TCPSOCKET
+extern char myipaddr[];
+extern int tcp_rdns;
+#ifdef CK_DNS_SRV
+extern int tcp_dns_srv;
+#endif /* CK_DNS_SRV */
+extern char * tcp_address;
+#ifndef NOHTTP
+extern char * tcp_http_proxy;
+#endif /* NOHTTP */
+#ifdef NT
+#ifdef CK_SOCKS
+extern char * tcp_socks_svr;
+#ifdef CK_SOCKS_NS
+extern char * tcp_socks_ns;
+#endif /* CK_SOCKS_NS */
+#endif /* CK_SOCKS */
+#endif /* NT */
+
+#ifndef NOTCPOPTS
+#ifdef SOL_SOCKET
+#ifdef SO_LINGER
+extern int tcp_linger;
+extern int tcp_linger_tmo;
+#endif /* SO_LINGER */
+#ifdef SO_DONTROUTE
+extern int tcp_dontroute;
+#endif /* SO_DONTROUTE */
+#ifdef TCP_NODELAY
+extern int tcp_nodelay;
+#endif /* TCP_NODELAY */
+#ifdef SO_SNDBUF
+extern int tcp_sendbuf;
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+extern int tcp_recvbuf;
+#endif /* SO_RCVBUF */
+#ifdef SO_KEEPALIVE
+extern int tcp_keepalive;
+#endif /* SO_KEEPALIVE */
+#endif /* SOL_SOCKET */
+#endif /* NOTCPOPTS */
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+
+extern char * floname[];
+
+#ifndef NOSPL
+extern int vareval; /* Variable evaluation method */
+extern int fndiags; /* Function diagnostics on/off */
+extern int divbyzero;
+int itsapattern = 0;
+int isinbuflen = 0;
+int isjoin = 0;
+#ifdef CK_APC
+extern int apcactive; /* Nonzero = APC command was rec'd */
+extern int apcstatus; /* Are APC commands being processed? */
+#ifdef DCMDBUF
+extern char *apcbuf; /* APC command buffer */
+#else
+extern char apcbuf[];
+#endif /* DCMDBUF */
+#endif /* CK_APC */
+
+extern char evalbuf[]; /* EVALUATE result */
+extern char uidbuf[], pwbuf[], prmbuf[];
+_PROTOTYP( static char * fneval, (char *, char * [], int, char * ) );
+_PROTOTYP( static VOID myflsh, (void) );
+_PROTOTYP( static char * getip, (char *) );
+_PROTOTYP( int delta2sec, (char *, long *) );
+
+#ifdef NEWFTP
+_PROTOTYP( char * ftp_cpl_mode, (void) );
+_PROTOTYP( char * ftp_dpl_mode, (void) );
+_PROTOTYP( char * ftp_authtype, (void) );
+#endif /* NEWFTP */
+
+#ifndef NOHTTP
+_PROTOTYP( char * http_host, (void) );
+_PROTOTYP( int http_isconnected, (void) );
+_PROTOTYP( char * http_security, (void) );
+#endif /* NOHTTP */
+
+#ifndef NOSEXP
+_PROTOTYP( char * dosexp, (char *) );
+int fsexpflag = 0;
+#endif /* NOSEXP */
+
+static char hexdigits[16] = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+};
+extern char * tempdir;
+
+#ifdef CK_REXX
+extern char rexxbuf[];
+#endif /* CK_REXX */
+
+extern int tfline[];
+
+char *wkdays[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+#endif /* NOSPL */
+
+#ifdef OS2
+extern char startupdir[], inidir[];
+#else
+#ifdef VMSORUNIX
+extern char startupdir[];
+#endif /* VMSORUNIX */
+#endif /* OS2 */
+
+#ifdef OS2
+_PROTOTYP (int os2getcp, (void) );
+#ifdef TCPSOCKET
+extern char tcpname[];
+#endif /* TCPSOCKET */
+extern int tcp_avail;
+#ifdef DECNET
+extern int dnet_avail;
+#endif /* DECNET */
+#ifdef SUPERLAT
+extern int slat_avail;
+#endif /* SUPERLAT */
+
+#ifndef NOTERM
+extern int tt_type, max_tt;
+extern struct tt_info_rec tt_info[];
+#endif /* NOTERM */
+extern int tt_rows[], tt_cols[];
+#else /* OS2 */
+extern int tt_rows, tt_cols;
+#endif /* OS2 */
+
+#ifdef CK_TAPI
+extern int tttapi;
+extern int tapipass;
+extern struct keytab * tapilinetab;
+extern struct keytab * _tapilinetab;
+extern int ntapiline;
+#endif /* CK_TAPI */
+
+extern struct keytab colxtab[];
+extern int ncolx;
+
+extern char ttname[], *zinptr, *kermrc;
+extern char inidir[];
+
+extern int activecmd, remonly, cmd_rows, cmd_cols, parity, seslog,
+ sessft, sosi, hwparity, tsecs, xargs, zincnt, tlevel, insilence, cmdmsk,
+ timint, timef, inbufsize, dialog, binary, carrier, cdtimo, cmask, duplex,
+ fmask, inecho, nmac, turnch, turn, kbchar;
+
+#ifndef NOXFER
+extern CHAR eol, mypadc, mystch, padch, seol, stchr, * epktmsg, feol;
+extern char *cksysid;
+extern struct ck_p ptab[];
+extern int
+ protocol, prefixing, xfrbel, xfrcan, xfrint, xfrchr, xfrnum, pktpaus,
+ lscapr, lscapu, xfermode, dest, slostart, maxrps, maxsps, maxtry, mypadn,
+ npad, pkttim, bigrbsiz, bigsbsiz, keep, atcapr, autopar, bctr, bctu,
+ crunched, ckdelay, ebq, ebqflg, pktlog, retrans, rpackets, rptflg, rptq,
+ rtimo, spackets, spsiz, spsizf, spsizr, timeouts, fncact, fncnv, urpsiz,
+ wmax, wslotn, wslotr, fdispla, spmax, fnrpath, fnspath, crc16;
+#endif /* NOXFER */
+
+#ifdef OS2
+extern int zxpn;
+extern int viewonly;
+#endif /* OS2 */
+
+#ifndef NOXFER
+#ifdef GFTIMER
+extern CKFLOAT fptsecs, fpxfsecs;
+#endif /* GFTIMER */
+extern long xfsecs, tfcps;
+
+#ifdef CK_TMPDIR
+extern char *dldir;
+#endif /* CK_TMPDIR */
+#endif /* NOXFER */
+
+#ifdef RECURSIVE
+extern int recursive;
+#endif /* RECURSIVE */
+
+#ifdef VMS
+extern int frecl;
+#endif /* VMS */
+
+extern CK_OFF_T ffc, tfc, tlci, tlco;
+extern long filcnt, rptn, speed, ccu, ccp, vernum, xvernum;
+
+#ifndef NOSPL
+extern char fspec[], myhost[];
+#endif /* NOSPL */
+
+extern char *tfnam[]; /* Command file names */
+
+extern char pktfil[], /* Packet log file name */
+#ifdef TLOG
+ trafil[], /* Transaction log file name */
+#endif /* TLOG */
+ sesfil[]; /* Session log file name */
+
+#ifndef NOXMIT /* TRANSMIT command variables */
+extern char xmitbuf[];
+extern int xmitf, xmitl, xmitx, xmits, xmitw, xmitt;
+#endif /* NOXMIT */
+
+extern int cmdlvl;
+
+#ifndef NOSPL
+/* Script programming language items */
+extern char **a_ptr[]; /* Arrays */
+extern int a_dim[];
+static char * inpmatch = NULL;
+#ifdef CKFLOAT
+char * inpscale = NULL;
+#endif /* CKFLOAT */
+extern char * inpbuf, inchar[]; /* Buffers for INPUT and REINPUT */
+extern char *inpbp; /* And pointer to same */
+static char *r3 = (char *)0;
+extern int incount; /* INPUT character count */
+extern int m_found; /* MINPUT result */
+extern int maclvl; /* Macro invocation level */
+extern struct mtab *mactab; /* Macro table */
+extern char *mrval[];
+extern int macargc[], topargc;
+
+#ifdef COMMENT
+extern char *m_line[];
+extern char *topline;
+#endif /* COMMENT */
+
+extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
+extern char *g_var[GVARS]; /* for external 2-dimensional arrays. */
+#ifdef DCMDBUF
+extern int *count, *inpcas;
+#else
+extern int count[], inpcas[];
+#endif /* DCMDBUF */
+#endif /* NOSPL */
+
+#ifdef UNIX
+extern int haslock; /* For UUCP locks */
+extern char flfnam[];
+#ifndef USETTYLOCK
+extern char lock2[];
+#endif /* USETTYLOCK */
+#endif /* UNIX */
+
+#ifdef OS2ORUNIX
+extern int maxnam, maxpath; /* Longest name, path length */
+#endif /* OS2ORUNIX */
+
+extern int mdmtyp, mdmsav;
+
+#ifndef NODIAL
+/* DIAL-related variables */
+extern char modemmsg[];
+extern MDMINF *modemp[]; /* Pointers to modem info structs */
+extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialsta;
+extern int dialrtr, dialint, dialrstr, dialcon, dialcq, dialfld;
+extern int mdmspd, dialec, dialdc, dialmth, dialmauto, dialesc;
+extern char *dialnum, *dialini, *dialdir[], *dialcmd, *dialnpr,
+ *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac,
+ *dialhwfc, *dialswfc, *dialnofc, *dialpulse, *dialtone, *dialname,
+ *dialaaon, *dialaaoff, *dialmac;
+extern char *diallcc, *dialixp, *dialixs, *dialldp, *diallds,
+ *dialpxi, *dialpxo, *dialsfx, *dialtfp;
+extern char *diallcp, *diallcs;
+extern int ntollfree, ndialpxx, nlocalac;
+extern char *dialtfc[], *diallcac[], *dialpxx[], *matchpxx;
+extern int ndialpucc, ndialtocc;
+extern char *dialtocc[], *dialpucc[];
+extern int ndialdir, dialcnf, dialcvt, dialidt, dialpace;
+extern long dialmax, dialcapas;
+
+extern struct keytab mdmtab[];
+
+#ifdef BIGBUFOK
+#define ARGBUFSIZ 8191
+#else
+#define ARGBUFSIZ 1023
+#endif /* BIGBUFOK */
+
+#ifdef BIGBUFOK
+extern char * dialmsg[];
+#endif /* BIGBUFOK */
+
+#endif /* NODIAL */
+
+#ifndef NOCSETS
+/* Translation stuff */
+extern int nfilc;
+extern struct keytab fcstab[];
+extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
+extern int dcset7, dcset8;
+extern struct keytab lngtab[];
+extern struct csinfo fcsinfo[], tcsinfo[];
+extern struct langinfo langs[];
+#ifdef CK_ANSIC
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
+#else
+extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
+#endif /* CK_ANSIC */
+#ifdef UNICODE
+ extern int ucsbom, ucsorder;
+#endif /* UNICODE */
+#endif /* NOCSETS */
+
+#ifndef NOSPL
+/* Built-in variable names, maximum length VNAML (20 characters) */
+
+struct keytab vartab[] = {
+ { "_line", VN_TFLN, CM_INV}, /* 192 */
+#ifdef OS2
+ { "_regname", VN_REGN, CM_INV}, /* 1.1.12 */
+ { "_regorg", VN_REGO, CM_INV}, /* 1.1.12 */
+ { "_regnum", VN_REGS, CM_INV}, /* 1.1.12 */
+#endif /* OS2 */
+ { "apcactive", VN_APC, CM_INV}, /* 192 */
+#ifdef NT
+ { "appdata", VN_APPDATA, 0}, /* 201 */
+#endif /* NT */
+ { "argc", VN_ARGC, 0},
+ { "args", VN_ARGS, 0},
+ { "authname", VN_AUTHN, 0}, /* 196 */
+ { "authstate", VN_AUTHS, 0}, /* 195 */
+ { "authtype", VN_AUTHT, 0}, /* 195 */
+ { "bits", VN_BITS, 0}, /* 212 */
+ { "blockcheck",VN_BLK, 0}, /* 195 */
+#ifdef BROWSER
+ { "browser", VN_BROWSR,0}, /* 193 */
+ { "browsopts", VN_BROPT, 0}, /* 193 */
+ { "browsurl", VN_URL, 0}, /* 193 */
+ { "buildid", VN_BUILD, 0}, /* 199 */
+#endif /* BROWSER */
+ { "byteorder", VN_BYTE, 0}, /* 195 */
+#ifndef NOCSETS
+ { "charset", VN_CSET, 0}, /* 192 */
+#endif /* NOCSETS */
+ { "cmdbufsize",VN_CMDBL, 0}, /* 195 */
+ { "cmdfile", VN_CMDF, 0},
+ { "cmdlevel", VN_CMDL, 0},
+ { "cmdsource", VN_CMDS, 0},
+ { "cols", VN_COLS, 0}, /* 190 */
+#ifdef NT
+ { "common", VN_COMMON, 0}, /* 201 */
+#endif /* NT */
+ { "connection",VN_CONN, 0}, /* 190 */
+ { "count", VN_COUN, 0},
+#ifndef NOXFER
+ { "cps", VN_CPS, 0}, /* 190 */
+#endif /* NOXFER */
+ { "cpu", VN_CPU, 0},
+#ifndef NOXFER
+ { "crc16", VN_CRC16, 0}, /* 192 */
+ { "ctty", VN_TTYNAM,0}, /* 196 */
+#endif /* NOXFER */
+#ifndef NOLOGDIAL
+#ifndef NOLOCAL
+ { "cx_time", VN_CXTIME,0}, /* 195 */
+ { "cx_status", VN_CX_STA,0}, /* 199 */
+#endif /* NOLOCAL */
+#endif /* NOLOGDIAL */
+#ifndef NODIAL
+ { "d$ac", VN_D_AC, 0}, /* 192 */
+ { "d$cc", VN_D_CC, 0}, /* 192 */
+ { "d$ip", VN_D_IP, 0}, /* 192 */
+ { "d$lc", VN_D_LCP, 0}, /* 193 */
+ { "d$lcp", VN_D_LCP, CM_INV}, /* 193 */
+ { "d$lp", VN_D_LP, 0}, /* 192 */
+ { "d$px", VN_D_PXX, 0}, /* 195 */
+ { "d$pxx", VN_D_PXX, CM_INV}, /* 195 */
+#endif /* NODIAL */
+ { "date", VN_DATE, 0},
+ { "day", VN_DAY, 0},
+#ifdef NT
+ { "desktop", VN_DESKTOP, 0}, /* 201 */
+#endif /* NT */
+#ifndef NODIAL
+ { "dialcount", VN_DRTR, 0}, /* 195 */
+ { "dialmessage",VN_DMSG, 0}, /* 212 */
+ { "dialnumber",VN_DNUM, 0}, /* 192 */
+ { "dialresult",VN_MDMSG, 0}, /* 192 */
+ { "dialstatus",VN_DIAL, 0}, /* 190 */
+ { "dialsuffix",VN_PDSFX, 0}, /* 193 */
+ { "dialtype", VN_DTYPE, 0}, /* 193 */
+#endif /* NODIAL */
+ { "directory", VN_DIRE, 0},
+#ifndef NODIAL
+ { "dm_hf", VN_DM_HF, 0}, /* 199 */
+ { "dm_lp", VN_DM_LP, 0}, /* 195 */
+ { "dm_sp", VN_DM_SP, 0}, /* 195 */
+ { "dm_pd", VN_DM_PD, 0}, /* 195 */
+ { "dm_td", VN_DM_TD, 0}, /* 195 */
+ { "dm_wa", VN_DM_WA, 0}, /* 195 */
+ { "dm_wb", VN_DM_WB, 0}, /* 199 */
+ { "dm_wd", VN_DM_WD, 0}, /* 195 */
+ { "dm_rc", VN_DM_RC, 0}, /* 195 */
+#endif /* NODIAL */
+#ifndef NOXFER
+ { "download", VN_DLDIR, 0}, /* 192 */
+#endif /* NOXFER */
+ { "editor", VN_EDITOR,0},
+ { "editfile", VN_EDFILE,0},
+ { "editopts", VN_EDOPT, 0},
+ { "errno", VN_ERRNO, 0}, /* 192 */
+ { "errstring", VN_ERSTR, 0}, /* 192 */
+ { "escape", VN_ESC, 0}, /* 193 */
+ { "evaluate", VN_EVAL, 0}, /* 190 */
+#ifdef OS2ORUNIX
+ { "exedir", VN_EXEDIR,0}, /* 192 */
+#endif /* OS2ORUNIX */
+ { "exitstatus",VN_EXIT, 0},
+#ifdef CKCHANNELIO
+ { "f_count", VN_FCOU, 0}, /* 195 */
+ { "f_error", VN_FERR, 0}, /* 195 */
+ { "f_max", VN_FMAX, 0}, /* 195 */
+ { "fileerror", VN_FERR, CM_INV}, /* 195 */
+ { "filemax", VN_FERR, CM_INV}, /* 195 */
+#endif /* CKCHANNELIO */
+ { "filename", VN_FNAM, 0}, /* 193 */
+ { "filenumber",VN_FNUM, 0}, /* 193 */
+ { "filespec", VN_FILE, 0},
+ { "fsize", VN_FFC, 0}, /* 190 */
+#ifdef GFTIMER
+ { "ftime", VN_FTIME, 0}, /* 199 */
+#else
+ { "ftime", VN_NTIM, CM_INV},
+#endif /* GFTIMER */
+#ifndef NOFTP
+#ifndef SYSFTP
+ { "ftp_code", VN_FTP_C, 0}, /* 199 */
+ { "ftp_cpl", VN_FTP_B, 0}, /* 199 */
+ { "ftp_connected", VN_FTP_X, 0}, /* 199 */
+ { "ftp_dpl", VN_FTP_D, 0}, /* 199 */
+ { "ftp_getputremote", VN_FTP_G, 0}, /* 199 */
+ { "ftp_host", VN_FTP_H, 0}, /* 199 */
+ { "ftp_loggedin", VN_FTP_L, 0}, /* 199 */
+ { "ftp_message", VN_FTP_M, 0}, /* 199 */
+ { "ftp_msg", VN_FTP_M, CM_INV}, /* 199 */
+ { "ftp_security", VN_FTP_Z, 0}, /* 199 */
+ { "ftp_server", VN_FTP_S, 0}, /* 199 */
+#endif /* SYSFTP */
+#endif /* NOFTP */
+ { "ftype", VN_MODE, 0}, /* 190 */
+#ifdef KUI
+ { "gui_fontname", VN_GUI_FNM, 0}, /* 205 */
+ { "gui_fontsize", VN_GUI_FSZ, 0}, /* 205 */
+ { "gui_runmode", VN_GUI_RUN, 0}, /* 205 */
+ { "gui_xpos", VN_GUI_XP, 0}, /* 205 */
+ { "gui_xres", VN_GUI_XR, 0}, /* 205 */
+ { "gui_ypos", VN_GUI_YP, 0}, /* 205 */
+ { "gui_yres", VN_GUI_YR, 0}, /* 205 */
+#endif /* KUI */
+ { "herald", VN_HERALD, 0},
+ { "home", VN_HOME, 0},
+ { "host", VN_HOST, 0},
+ { "hour", VN_HOUR, 0}, /* 200 */
+#ifndef NOHTTP
+ { "http_code", VN_HTTP_C, 0}, /* 199 */
+ { "http_connected", VN_HTTP_N, 0}, /* 199 */
+ { "http_host", VN_HTTP_H, 0}, /* 199 */
+ { "http_message", VN_HTTP_M, 0}, /* 199 */
+ { "http_security", VN_HTTP_S, 0}, /* 199 */
+#endif /* NOHTTP */
+ { "hwparity", VN_HWPAR, 0}, /* 195 */
+ { "input", VN_IBUF, 0},
+ { "inchar", VN_ICHR, 0},
+ { "incount", VN_ICNT, 0},
+ { "inidir", VN_INI, 0}, /* 192 */
+ { "inmatch", VN_MATCH, 0}, /* 196 */
+ { "inmessage", VN_INPMSG,0}, /* 212 */
+ { "inscale", VN_ISCALE,0}, /* 210 */
+ { "instatus", VN_ISTAT, 0}, /* 192 */
+ { "intime", VN_INTIME,0}, /* 193 */
+ { "inwait", VN_INTMO, 0}, /* 195 */
+ { "ip", VN_IPADDR, CM_ABR|CM_INV},
+ { "ipaddress", VN_IPADDR,0}, /* 192 */
+ { "iprompt", VN_PROMPT,0}, /* 199 */
+ { "kbchar", VN_KBCHAR,0}, /* 196 */
+#ifndef NOLOCAL
+#ifdef OS2
+ { "keyboard", VN_KEYB, 0},
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CK_KERBEROS
+ { "krb4errmsg", VN_K4EMSG,0},
+ { "krb4errno", VN_K4ENO, 0},
+ { "krb4principal", VN_K4PRN, 0},
+ { "krb4realm", VN_K4RLM, 0},
+ { "krb4service", VN_K4SRV, 0},
+ { "krb5cc", VN_K5CC, 0},
+ { "krb5errmsg", VN_K5EMSG,0},
+ { "krb5errno", VN_K5ENO, 0},
+ { "krb5principal", VN_K5PRN, 0},
+ { "krb5realm", VN_K5RLM, 0},
+ { "krb5service", VN_K5SRV, 0},
+#endif /* CK_KERBEROS */
+ { "lastcommand", VN_PREVCMD, 0}, /* 299 */
+#ifndef NOLASTFILE
+ { "lastfilespec", VN_LASTFIL, 0}, /* 212 */
+#endif /* NOLASTFILE */
+ { "lastkeywordvalue", VN_LASTKWV, 0}, /* 212 */
+ { "lastkwvalue", VN_LASTKWV, CM_ABR|CM_INV}, /* 212 */
+ { "line", VN_LINE, 0},
+ { "local", VN_LCL, 0},
+#ifdef UNIX
+ { "lockdir", VN_LCKDIR,0}, /* 195 */
+ { "lockpid", VN_LCKPID,0}, /* 195 */
+#endif /* UNIX */
+ { "log_connection", VN_LOG_CON, 0}, /* 206 */
+ { "log_debug", VN_LOG_DEB, 0}, /* 206 */
+ { "log_packet", VN_LOG_PKT, 0}, /* 206 */
+ { "log_session", VN_LOG_SES, 0}, /* 206 */
+ { "log_transaction", VN_LOG_TRA, 0},/* 206 */
+ { "maclevel", VN_MACLVL,0}, /* 195 */
+ { "macro", VN_MAC, 0},
+#ifdef FNFLOAT
+ { "math_e", VN_MA_E, 0}, /* 195 */
+ { "math_pi", VN_MA_PI, 0}, /* 195 */
+ { "math_precision", VN_MA_PR, 0}, /* 195 */
+#endif /* FNFLOAT */
+ { "minput", VN_MINP, 0}, /* 192 */
+ { "model", VN_MODL, 0}, /* 193 */
+ { "modem", VN_MDM, 0},
+#ifndef NOLOCAL
+#ifdef OS2
+ { "mousecurx", VN_MOU_X, 0}, /* K95 1.1.14 */
+ { "mousecury", VN_MOU_Y, 0}, /* K95 1.1.14 */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifndef NODIAL
+ { "m_aa_off", VN_M_AAX, 0}, /* all 192... */
+ { "m_aa_on", VN_M_AAO, 0},
+ { "m_dc_off", VN_M_DCX, 0},
+ { "m_dc_on", VN_M_DCO, 0},
+ { "m_dial", VN_M_DCM, 0},
+ { "m_ec_off", VN_M_ECX, 0},
+ { "m_ec_on", VN_M_ECO, 0},
+ { "m_fc_hw", VN_M_HWF, 0},
+ { "m_fc_no", VN_M_NFC, 0},
+ { "m_fc_sw", VN_M_SWF, 0},
+ { "m_hup", VN_M_HUP, 0},
+ { "m_init", VN_M_INI, 0},
+ { "m_name", VN_M_NAM, 0}, /* 195 */
+ { "m_pulse", VN_M_PDM, 0},
+ { "m_sig_cd", VN_MS_CD, 0}, /* 195 */
+ { "m_sig_cts", VN_MS_CTS,0}, /* 195 */
+ { "m_sig_dsr", VN_MS_DSR,0}, /* 195 */
+ { "m_sig_dtr", VN_MS_DTR,0}, /* 195 */
+ { "m_sig_ri", VN_MS_RI, 0}, /* 195 */
+ { "m_sig_rts", VN_MS_RTS,0}, /* 195 */
+ { "m_tone", VN_M_TDM, 0},
+#endif /* NODIAL */
+ { "name", VN_NAME, 0},
+ { "ndate", VN_NDAT, 0},
+ { "nday", VN_NDAY, 0},
+ { "newline", VN_NEWL, 0},
+ { "ntime", VN_NTIM, 0},
+ { "osname", VN_OSNAM, 0}, /* 193 */
+ { "osrelease", VN_OSREL, 0}, /* 193 */
+ { "osversion", VN_OSVER, 0}, /* 193 */
+#ifndef NOXFER
+ { "packetlen", VN_RPSIZ, 0}, /* 192 */
+#endif /* NOXFER */
+ { "parity", VN_PRTY, 0}, /* 190 */
+ { "password", VN_PWD, CM_INV}, /* 192 */
+#ifdef NT
+ { "personal", VN_PERSONAL, 0}, /* 201 */
+#endif /* NT */
+#ifdef PEXITSTAT
+ { "pexitstat", VN_PEXIT, 0}, /* 193 */
+#endif /* PEXITSTAT */
+#ifdef CK_PID
+ { "pid", VN_PID, 0}, /* 193 */
+#endif /* CK_PID */
+ { "platform", VN_SYSV, 0},
+ { "printer", VN_PRINT, 0}, /* 193 */
+ { "program", VN_PROG, 0},
+ { "prompt", VN_PRM, CM_INV}, /* 192 */
+#ifndef NOXFER
+ { "protocol", VN_PROTO, 0}, /* 192 */
+ { "p_8bit", VN_P_8BIT,0}, /* 193 */
+ { "p_ctl", VN_P_CTL, 0}, /* 193 */
+ { "p_rpt", VN_P_RPT, 0}, /* 193 */
+ { "query", VN_QUE, 0}, /* 190 */
+#endif /* NOXFER */
+ { "remoteip", VN_HOSTIP,0}, /* 212 */
+ { "return", VN_RET, 0},
+#ifdef CK_REXX
+ { "rexx", VN_REXX, 0}, /* 190 */
+#endif /* CK_REXX */
+#ifdef TN_COMPORT
+ { "rfc2217_signature", VN_TNC_SIG, 0}, /* 201 */
+ { "rfc2717_signature", VN_TNC_SIG, CM_INV}, /* 202 */
+#endif /* TN_COMPORT */
+ { "rows", VN_ROWS, 0}, /* 190 */
+#ifndef NOSEXP
+ { "sdepth", VN_LSEXP,0}, /* 199 */
+#endif /* NOSEXP */
+ { "secure", VN_SECURE, 0}, /* 199 */
+#ifndef NOLOCAL
+#ifdef OS2
+ { "select", VN_SELCT, 0}, /* 192 */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ { "sendlist", VN_SNDL, 0},
+ { "serial", VN_SERIAL,0}, /* 195 */
+ { "setlinemsg",VN_SLMSG, 0}, /* 195 */
+#ifndef NOSEXP
+ { "sexpression",VN_SEXP, 0}, /* 199 */
+#endif /* NOSEXP */
+ { "speed", VN_SPEE, 0},
+#ifdef OS2
+ { "space", VN_SPA, 0},
+ { "startup", VN_STAR, 0}, /* 190 */
+#else
+#ifdef UNIX
+ { "startup", VN_STAR, 0}, /* 193 */
+#else
+#ifdef VMS
+ { "startup", VN_STAR, 0}, /* 193 */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OS2 */
+ { "status", VN_SUCC, 0},
+#ifndef NOSEXP
+ { "svalue", VN_VSEXP, 0}, /* 199 */
+#endif /* NOSEXP */
+#ifndef NOXFER
+ { "sysid", VN_SYSI, 0},
+#endif /* NOXFER */
+ { "system", VN_SYST, 0},
+ { "terminal", VN_TTYP, 0},
+#ifdef OS2
+#ifndef NOKVERBS
+ { "termkey", VN_TRMK, CM_INV}, /* 192 */
+#endif /* NOKVERBS */
+#endif /* OS2 */
+ { "test", VN_TEST, 0}, /* 193 */
+ { "textdir", VN_TXTDIR,0}, /* 195 */
+#ifndef NOXFER
+ { "tfsize", VN_TFC, 0},
+ { "tftime", VN_TFTIM, 0}, /* 195 */
+#endif /* NOXFER */
+ { "time", VN_TIME, 0},
+ { "timestamp", VN_NOW, 0}, /* 200 */
+ { "tmpdir", VN_TEMP, 0}, /* 192 */
+#ifdef CK_TRIGGER
+ { "trigger", VN_TRIG, 0}, /* 193 */
+#endif /* CK_TRIGGER */
+#ifdef CK_TTYFD
+ { "ttyfd", VN_TTYF, 0},
+#endif /* CK_TTYFD */
+ { "ty_ln", VN_TY_LN, 0}, /* 195 */
+ { "ty_lc", VN_TY_LC, 0}, /* 195 */
+ { "ty_lm", VN_TY_LM, 0}, /* 195 */
+#ifdef BROWSER
+ { "url", VN_URL, CM_INV}, /* 193 */
+#endif /* BROWSER */
+ { "userid", VN_UID, 0}, /* 192 */
+ { "vareval", VN_VAREVAL, 0}, /* 212 */
+ { "version", VN_VERS, 0},
+#ifndef NOXFER
+ { "window", VN_WINDO, 0}, /* 192 */
+#endif /* NOXFER */
+#ifdef IBMX25
+ { "x25local_nua", VN_X25LA, 0}, /* 193 */
+ { "x25remote_nua", VN_X25RA, 0}, /* 193 */
+#endif /* IBMX25 */
+#ifdef CK_SSL
+ { "x509_issuer", VN_X509_I, 0},
+ { "x509_subject", VN_X509_S, 0},
+#endif /* CK_SSL */
+#ifndef NOXFER
+ { "xferstatus",VN_XFSTAT,0}, /* 193 */
+ { "xfermsg", VN_XFMSG, 0}, /* 193 */
+ { "xfer_badpackets", VN_XF_BC, 0}, /* 195 */
+ { "xfer_timeouts", VN_XF_TM, 0}, /* 195 */
+ { "xfer_retransmits",VN_XF_RX, 0}, /* 195 */
+#endif /* NOXFER */
+ { "xprogram", VN_XPROG, 0}, /* 193 */
+ { "xversion", VN_XVNUM, 0} /* 192 */
+};
+int nvars = (sizeof(vartab) / sizeof(struct keytab));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+struct keytab fnctab[] = { /* Function names */
+#ifdef OS2
+ { ".oox", FN_OOX, CM_INV}, /* ... */
+#endif /* OS2 */
+
+#ifdef CKCHANNELIO
+ { "_eof", FN_FEOF, 0},
+ { "_errmsg", FN_FERMSG, 0},
+ { "_getblock", FN_FGBLK, 0},
+ { "_getchar", FN_FGCHAR, 0},
+ { "_getline", FN_FGLINE, 0},
+ { "_handle", FN_FILNO, 0},
+ { "_line", FN_NLINE, 0},
+ { "_pos", FN_FPOS, 0},
+ { "_putblock", FN_FPBLK, 0},
+ { "_putchar", FN_FPCHAR, 0},
+ { "_putline", FN_FPLINE, 0},
+ { "_status", FN_FSTAT, 0},
+#endif /* CKCHANNELIO */
+
+ { "aaconvert", FN_AADUMP, 0}, /* Associative Array conversion */
+ { "absolute", FN_ABS, 0}, /* Absolute value */
+#ifdef TCPSOCKET
+ { "addr2name", FN_HSTADD,CM_INV}, /* IP Address to Hostname */
+ { "addrtoname", FN_HSTADD,CM_INV}, /* IP Address to Hostname */
+#endif /* TCPSOCKET */
+ { "arraylook", FN_ALOOK,0}, /* Array lookup */
+ { "b64decode", FN_FMB64,0}, /* Base-64 conversion */
+ { "b64encode", FN_TOB64,0}, /* ... */
+ { "basename", FN_BSN, 0}, /* Basename */
+ { "break", FN_BRK, 0}, /* Break (as in Snobol) */
+ { "ca", FN_CAP, CM_INV|CM_ABR}, /* Abbreviation for capitablize */
+ { "cap", FN_CAP, CM_INV|CM_ABR}, /* Abbreviation for capitablize */
+ { "capitalize", FN_CAP, 0}, /* First Letter -> uppercase */
+ { "caps", FN_CAP, CM_INV}, /* ditto */
+ { "character", FN_CHR, 0}, /* Character from code */
+ { "checksum", FN_CHK, 0}, /* Checksum */
+ { "cmdstack", FN_CMDSTK,0}, /* Command stack */
+ { "cmpdates", FN_CMPDATE,0}, /* Compare dates */
+ { "code", FN_COD, 0}, /* Code from character */
+#ifndef NOPUSH
+ { "command", FN_CMD, 0}, /* Output from a command */
+#endif /* NOPUSH */
+ { "contents", FN_CON, 0}, /* Definition (contents) of variable */
+ { "count", FN_COUNT, 0}, /* Occurrences of string in string */
+ { "crc16", FN_CRC, 0}, /* CRC-16 */
+#ifdef OS2
+ { "crypt", FN_CRY, CM_INV},
+#endif /* OS2 */
+ { "cvtcset", FN_XLATE, 0}, /* Convert character set */
+ { "cvtdate", FN_DTIM, 0}, /* Convert free date/time to std */
+#ifdef ZFCDAT
+ { "date", FN_FD, 0}, /* File modification/creation date */
+#endif /* ZFCDAT */
+ { "day", FN_DAY, 0}, /* Day of week */
+ { "dayofyear", FN_JDATE,0}, /* Date to Day of Year */
+ { "decodehex", FN_UNPCT, 0}, /* Decode string with hex escapes */
+ { "definition", FN_DEF, 0}, /* Return definition of given macro */
+ { "delta2secs", FN_DELSEC, 0}, /* Delta time to seconds */
+ { "deltatosecs", FN_DELSEC, CM_INV}, /* Delta time to seconds */
+#ifndef NODIAL
+ { "dialconvert",FN_PNCVT,0}, /* Convert portable phone number */
+#endif /* NODIAL */
+ { "diffdates", FN_DIFDATE,0}, /* Difference of two date-times */
+ { "dimension", FN_DIM, 0}, /* Dimension of array */
+ { "dir", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
+ { "dire", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
+ { "direc", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
+ { "direct", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
+ { "directo", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
+ { "director", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
+ { "directories",FN_DIR, 0}, /* List of directories */
+ { "directory", FN_DIR, CM_INV}, /* List of directories */
+ { "dirname", FN_DNAM, 0}, /* Directory part of filename */
+ { "dos2unixpath",FN_PC_DU, }, /* DOS to UNIX path */
+ { "dostounixpath",FN_PC_DU, CM_INV}, /* DOS to UNIX path */
+ { "doy", FN_JDATE,CM_INV}, /* Date to Day of Year */
+ { "doy2date", FN_DATEJ,0}, /* Day of Year to date */
+ { "doytodate", FN_DATEJ,CM_INV}, /* Day of Year to date */
+ { "emailaddress",FN_EMAIL, 0}, /* Email address */
+#ifdef FN_ERRMSG
+ { "errstring", FN_ERRMSG,0}, /* Error code to message */
+#endif /* FN_ERRMSG */
+ { "evaluate", FN_EVA, 0}, /* Evaluate given arith expression */
+ { "execute", FN_EXE, 0}, /* Execute given macro */
+ { "files", FN_FC, 0}, /* File count */
+#ifdef FNFLOAT
+ { "fpabsolute", FN_FPABS, 0}, /* Floating-point absolute value */
+ { "fpadd", FN_FPADD, 0}, /* FP add */
+ { "fpcosine", FN_FPCOS, 0}, /* FP cosine */
+ { "fpdivide", FN_FPDIV, 0}, /* FP divide */
+ { "fpexp", FN_FPEXP, 0}, /* FP e to the x */
+ { "fpint", FN_FPINT, 0}, /* FP to integer */
+ { "fplog10", FN_FPLOG, 0}, /* FP base-10 logarithm */
+ { "fplogn", FN_FPLN, 0}, /* FP natural logarithm */
+ { "fpmaximum", FN_FPMAX, 0}, /* FP maxinum */
+ { "fpminimum", FN_FPMIN, 0}, /* FP mininum */
+ { "fpmodulus", FN_FPMOD, 0}, /* FP modulus */
+ { "fpmultiply", FN_FPMUL, 0}, /* FP multiply */
+ { "fpraise", FN_FPPOW, 0}, /* FP raise to a power */
+ { "fpround", FN_FPROU, 0}, /* FP round */
+ { "fpsine", FN_FPSIN, 0}, /* FP sine */
+ { "fpsqrt", FN_FPSQR, 0}, /* FP square root */
+ { "fpsubtract", FN_FPSUB, 0}, /* FP subtract */
+ { "fptangent", FN_FPTAN, 0}, /* FP tangent */
+#endif /* FNFLOAT */
+ { "function", FN_FUNC, 0 }, /* Test for existence of a function */
+ { "getpidinfo", FN_PID, 0 }, /* Get PID info */
+ { "hex2ip", FN_HEX2IP,0}, /* Hex to IP address */
+ { "hextoip", FN_HEX2IP,CM_INV}, /* Hex to IP address */
+ { "hex2n", FN_HEX2N, CM_INV}, /* Hex to decimal number */
+ { "hexify", FN_HEX, 0}, /* Hexify (string) */
+ { "index", FN_IND, 0}, /* Index (string search) */
+ { "ip2hex", FN_IP2HEX,0}, /* IP address to hex */
+ { "iptohex", FN_IP2HEX,CM_INV}, /* IP address to hex */
+ { "ipaddress", FN_IPA, 0}, /* Find and return IP address */
+ { "jdate", FN_JDATE, CM_INV}, /* Date to Day of Year */
+ { "join", FN_JOIN, 0}, /* Join array elements */
+ { "keywordvalue", FN_KWVAL, 0}, /* Keyword=Value */
+#ifdef CK_KERBEROS
+ { "krbflags", FN_KRB_FG, 0}, /* Kerberos functions */
+ { "krbisvalid", FN_KRB_IV, 0},
+ { "krbnextticket", FN_KRB_NX, 0},
+ { "krbtickets", FN_KRB_TK, 0},
+ { "krbtimeleft", FN_KRB_TT, 0},
+#endif /* CK_KERBEROS */
+ { "kwvalue", FN_KWVAL, CM_INV}, /* Keyword=Value */
+ { "left", FN_LEF, 0}, /* Leftmost n characters of string */
+ { "length", FN_LEN, 0}, /* Return length of argument */
+ { "literal", FN_LIT, 0}, /* Return argument literally */
+#ifdef NT
+ { "longpathname",FN_LNAME,0}, /* GetLongPathName() */
+#else
+ { "longpathname",FN_FFN,CM_INV},
+#endif /* NT */
+ { "lop", FN_STL, 0}, /* Lop */
+ { "lopx", FN_LOPX, 0}, /* Lopx */
+ { "lower", FN_LOW, 0}, /* Return lowercased argument */
+ { "lpad", FN_LPA, 0}, /* Return left-padded argument */
+ { "ltrim", FN_LTR, 0}, /* Left-Trim */
+ { "maximum", FN_MAX, 0}, /* Return maximum of two arguments */
+ { "minimum", FN_MIN, 0}, /* Return minimum of two arguments */
+ { "mjd", FN_MJD, 0}, /* Date to Modified Julian Date */
+ { "mjd2date", FN_MJD2, 0}, /* MJD to Date */
+ { "mjdtodate", FN_MJD2, CM_INV}, /* MJD to Date */
+ { "modulus", FN_MOD, 0}, /* Return modulus of two arguments */
+#ifdef COMMENT
+ { "msleep", FN_MSLEEP,0}, /* Sleep for n milliseconds */
+#endif /* COMMENT */
+ { "n2hex", FN_2HEX, CM_INV}, /* Number to hex */
+ { "n2octal", FN_2OCT, CM_INV}, /* Number to octal */
+ { "n2time", FN_N2TIM,0}, /* Number to hh:mm:ss */
+#ifdef TCPSOCKET
+ { "name2addr", FN_HSTNAM,CM_INV}, /* Hostname to IP Address */
+#endif /* TCPSOCKET */
+ { "nday", FN_NDAY, 0}, /* Numeric day of week */
+ { "nextfile", FN_FIL, 0}, /* Next file in list */
+ { "ntime", FN_NTIM, 0}, /* Time to seconds since midnight */
+ { "ntohex", FN_2HEX, CM_INV}, /* Number to hex */
+ { "ntooctal", FN_2OCT, CM_INV}, /* Number to octal */
+ { "ntotime", FN_N2TIM,CM_INV}, /* Number to hh:mm:ss */
+ { "oct2n", FN_OCT2N,CM_INV}, /* Octal to decimal number */
+ { "octton", FN_OCT2N,CM_INV}, /* Octal to decimal number */
+ { "pathname", FN_FFN, 0}, /* Full file name */
+ { "pattern", FN_PATTERN, 0}, /* Pattern (for INPUT) */
+#ifdef CK_PERMS
+ { "permissions",FN_PERM, 0}, /* Permissions of file */
+#else
+ { "permissions",FN_PERM, CM_INV}, /* Permissions of file */
+#endif /* CK_PERMS */
+#ifdef SEEK_CUR
+ { "pictureinfo",FN_PICTURE, 0 }, /* Picture orientation/dimensions */
+#endif /* SEEK_CUR */
+ { "radix", FN_RADIX, 0 }, /* Radix conversion */
+#ifndef NORANDOM
+ { "random", FN_RAND, 0}, /* Random number */
+#endif /* NORANDOM */
+#ifndef NOPUSH
+ { "rawcommand", FN_RAW, 0}, /* Output from a command (raw) */
+#endif /* NOPUSH */
+#ifdef RECURSIVE
+ { "rdirectories", FN_RDIR, 0}, /* Recursive directory list */
+#endif /* RECURSIVE */
+ { "recurse", FN_RECURSE, 0}, /* Recursive variable evaluation */
+#ifdef RECURSIVE
+ { "rfiles", FN_RFIL, 0}, /* Recursive file list */
+#endif /* RECURSIVE */
+ { "rep", FN_REP, CM_INV|CM_ABR},
+ { "repeat", FN_REP, 0}, /* Repeat argument given # of times */
+ { "replace", FN_RPL, 0}, /* Replace characters in string */
+ { "reverse", FN_REV, 0}, /* Reverse the argument string */
+ { "right", FN_RIG, 0}, /* Rightmost n characters of string */
+ { "rindex", FN_RIX, 0}, /* Right index */
+ { "rpad", FN_RPA, 0}, /* Right-pad the argument */
+ { "rsearch", FN_RSEARCH, 0}, /* R-L Search for pattern in string */
+#ifdef OS2
+ { "scrncurx", FN_SCRN_CX, 0}, /* Screen Cursor X Pos */
+ { "scrncury", FN_SCRN_CY, 0}, /* Screen Cursor Y Pos */
+ { "scrnstr", FN_SCRN_STR, 0}, /* Screen String */
+#endif /* OS2 */
+ { "search", FN_SEARCH, 0}, /* L-R Search for pattern in string */
+#ifndef NOSEXP
+ { "sexpression",FN_SEXP, 0}, /* S-Expression */
+#endif /* NOSEXP */
+#ifdef NT
+ { "shortpathname",FN_SNAME,0}, /* GetShortPathName() */
+#else
+ { "shortpathname",FN_FFN,CM_INV},
+#endif /* NT */
+ { "size", FN_FS, 0}, /* File size */
+#ifdef COMMENT
+ { "sleep", FN_SLEEP,0}, /* Sleep for n seconds */
+#endif /* COMMENT */
+ { "span", FN_SPN, 0}, /* Span - like Snobol */
+ { "split", FN_SPLIT,0}, /* Split string into words */
+ { "squeeze", FN_SQUEEZE,0}, /* Squeeze whitespace in string */
+ { "strcmp", FN_STRCMP,0}, /* String comparison */
+ { "stringtype", FN_STRINGT,0}, /* String type (7-bit, 8-bit, UTF-8) */
+ { "stripb", FN_STB, 0}, /* Strip enclosing braces/brackets */
+ { "stripn", FN_STN, 0}, /* Strip n chars */
+ { "stripx", FN_STX, 0}, /* Strip suffix */
+ { "su", FN_SUB, CM_INV|CM_ABR},
+ { "sub", FN_SUB, CM_INV|CM_ABR},
+ { "subs", FN_SUB, CM_INV|CM_ABR},
+ { "subst", FN_SUB, CM_INV|CM_ABR},
+ { "substitute", FN_SUBST,0}, /* Substitute chars */
+ { "substring", FN_SUB, 0}, /* Extract substring from argument */
+ { "tablelook", FN_TLOOK,0}, /* Table lookup */
+ { "time", FN_TIME, 0}, /* Free-format time to hh:mm:ss */
+ { "tod2secs", FN_NTIM, CM_INV}, /* Time-of-day-to-secs-since-midnite */
+ { "todtosecs", FN_NTIM, CM_INV}, /* Time-of-day-to-secs-since-midnite */
+ { "trim", FN_TRM, 0}, /* Trim */
+ { "unhexify", FN_UNH, 0}, /* Unhexify */
+ { "unix2dospath",FN_PC_UD, 0}, /* UNIX to DOS path */
+ { "unixtodospath",FN_PC_UD, CM_INV}, /* UNIX to DOS path */
+ { "untabify", FN_UNTAB,0}, /* Untabify */
+ { "upper", FN_UPP, 0}, /* Return uppercased argument */
+ { "utcdate", FN_TOGMT,0}, /* Date-time to UTC (GMT) */
+ { "verify", FN_VER, 0}, /* Verify */
+ { "word", FN_WORD, 0}, /* Extract a word */
+ { "", 0, 0}
+};
+int nfuncs = (sizeof(fnctab) / sizeof(struct keytab)) - 1;
+#endif /* NOSPL */
+
+#ifndef NOSPL /* Buffer for expansion of */
+#ifdef BIGBUFOK /* built-in variables. */
+#define VVBUFL 1024
+#else
+#define VVBUFL 256
+#endif /* BIGBUFOK */
+char vvbuf[VVBUFL+1];
+#endif /* NOSPL */
+
+struct keytab disptb[] = { /* Log file disposition */
+ { "append", 1, 0},
+ { "new", 0, 0}
+};
+
+#ifdef CKFLOAT
+
+/* I N I T F L O A T -- Deduce floating-point precision by inspection */
+
+int fp_rounding = 0; /* Nonzero if printf("%f") rounds */
+int fp_digits = 0; /* Digits of floating point precision */
+
+#ifdef COMMENT
+/* For looking at internal floating-point representations */
+static char fp_xbuf[128];
+static char *
+tohex(s, n) CHAR * s; int n; {
+ int x;
+ char * p = fp_xbuf;
+ while (n-- > 0) {
+ x = (*s >> 4) & 0x0f;
+ *p++ = hexdigits[x];
+ x = *s++ & 0x0f;
+ *p++ = hexdigits[x];
+ }
+ *p = NUL;
+ return((char *)fp_xbuf);
+}
+#endif /* COMMENT */
+
+char math_pi[] = "3.1415926535897932384626433832795";
+char math_e[] = "2.7182818284590452353602874713527";
+
+VOID
+initfloat() {
+ char * buf = NULL;
+ int i, x, y;
+/*
+ We malloc a big temporary buffer for sprintf() to minimize likelihood of
+ (and damage from) sprintf buffer overflows. In any case, the only way this
+ could happen would be if sprintf() itself had bugs, since the format
+ descriptor says to cut it off at 250 decimal places.
+*/
+ if ((buf = (char *)malloc(4096))) {
+ sprintf(buf,"%0.250f",(10.0 / 3.0));
+ for (i = 2; i < 250 && buf[i] == '3'; i++) ;
+ x = i - 1;
+ debug(F111,"initfloat 10.0/3.0",buf,x);
+ sprintf(buf,"%0.250f",(4.0 / 9.0));
+ for (i = 2; i < 250 && buf[i] == '4'; i++) ;
+ y = i - 1;
+ debug(F111,"initfloat 4.0/9.0",buf,y);
+ fp_digits = (x < y) ? x : y;
+ if (fp_digits < sizeof(math_pi) - 1) {
+ math_pi[fp_digits+1] = NUL;
+ math_e[fp_digits+1] = NUL;
+ }
+ sprintf(buf,"%0.6f",(7.0 / 9.0));
+ if (buf[7] == '8') fp_rounding = 1;
+ debug(F111,"initfloat 7.0/9.0",buf,fp_rounding);
+ debug(F101,"initfloat precision","",fp_digits);
+ free(buf);
+ }
+}
+#endif /* CKFLOAT */
+
+/*
+ P R E S C A N -- A quick look through the command-line options for
+ items that must be handled before the initialization file is executed.
+*/
+#ifdef NT
+extern int StartedFromDialer;
+#endif /* NT */
+#ifdef OS2
+extern int k95stdio;
+unsigned long startflags = 0L;
+#endif /* OS2 */
+
+static char *
+findinpath(arg) char * arg; {
+#ifdef OS2
+ char * scriptenv, * keymapenv;
+ int len;
+#endif /* OS2 */
+#ifdef DCMDBUF
+ extern char * cmdbuf;
+#else
+ extern char cmdbuf[];
+#endif /* DCMDBUF */
+ char takepath[4096];
+ char * s;
+ int x, z;
+
+ /* Set up search path... */
+#ifdef OS2
+ char * appdata0 = NULL, *appdata1 = NULL;
+#ifdef NT
+ scriptenv = getenv("K95SCRIPTS");
+ keymapenv = getenv("K95KEYMAPS");
+ makestr(&appdata0,(char *)GetAppData(0));
+ makestr(&appdata1,(char *)GetAppData(1));
+#else /* NT */
+ scriptenv = getenv("K2SCRIPTS");
+ keymapenv = getenv("K2KEYMAPS");
+#endif /* NT */
+ if (!scriptenv)
+ scriptenv = getenv("CK_SCRIPTS");
+ if (!scriptenv)
+ scriptenv = "";
+ if (!keymapenv)
+ keymapenv = getenv("CK_KEYMAPS");
+ if (!keymapenv)
+ keymapenv = "";
+
+ debug(F110,"startupdir",startupdir,0);
+ debug(F110,"common appdata directory",appdata1,0);
+ debug(F110,"appdata directory",appdata0,0);
+ debug(F110,"inidir",inidir,0);
+ debug(F110,"home",zhome(),0);
+ debug(F110,"exedir",exedir,0);
+
+ len = strlen(scriptenv) + strlen(keymapenv) + 3*strlen(startupdir)
+ + 3*strlen(inidir) + 3*strlen(zhome()) + 3*strlen(exedir)
+ + (appdata0 ? 3*strlen(appdata0) : 0)
+ + (appdata1 ? 3*strlen(appdata1) : 0)
+ + 6*strlen("SCRIPTS/") + 6*strlen("KEYMAPS/") + 16;
+
+ if (len >= 4096) { /* SAFE (length is checked) */
+ takepath[0] = '\0';
+ debug(F111,"findinpath error - path length too long","len",len);
+ } else
+ sprintf(takepath,
+ /* semicolon-separated path list */
+ "%s%s%s%s%s;%s%s;%s%s;%s%s%s%s%s%s%s%s%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s",
+ scriptenv,
+ (scriptenv[0] && scriptenv[strlen(scriptenv)-1]==';')?"":";",
+ keymapenv,
+ (keymapenv[0] && keymapenv[strlen(keymapenv)-1]==';')?"":";",
+ startupdir,
+ startupdir, "SCRIPTS/",
+ startupdir, "KEYMAPS/",
+ appdata1 ? appdata1 : "",
+ appdata1 ? "Kermit 95;" : "",
+ appdata1 ? appdata1 : "",
+ appdata1 ? "Kermit 95/SCRIPTS/;" : "",
+ appdata1 ? appdata1 : "",
+ appdata1 ? "Kermit 95/KEYMAPS/;" : "",
+ appdata0 ? appdata0 : "",
+ appdata0 ? "Kermit 95;" : "",
+ appdata0 ? appdata0 : "",
+ appdata0 ? "Kermit 95/SCRIPTS/;" : "",
+ appdata0 ? appdata0 : "",
+ appdata0 ? "Kermit 95/KEYMAPS/;" : "",
+ inidir,
+ inidir, "SCRIPTS/",
+ inidir, "KEYMAPS/",
+ zhome(),
+ zhome(), "SCRIPTS/",
+ zhome(), "KEYMAPS/",
+ exedir,
+ exedir, "SCRIPTS/",
+ exedir, "KEYMAPS/"
+ );
+ debug(F110,"findinpath takepath",takepath,0);
+#ifdef NT
+ makestr(&appdata0,NULL);
+ makestr(&appdata1,NULL);
+#endif /* NT */
+#else /* not OS2 */
+#ifndef NOSPL
+ z = 1024; /* Look in home directory */
+ s = takepath;
+ zzstring("\\v(home)",&s,&z);
+#else
+ takepath[0] = '\0';
+#endif /* NOSPL */
+#endif /* OS2 */
+/*
+ All the logic for searching the take path is in the command parser.
+ So even though we aren't parsing commands, we initialize and call the
+ parser from here, with the purported filename stuffed into the command
+ buffer, followed by some carriage returns to make the parser return.
+ If the file is not found, or otherwise not accessible, the parser prints
+ an appropriate message, and then we just exit.
+*/
+ cmdini(); /* Allocate command buffers etc */
+ cmini(0); /* Initialize them */
+ /* Stuff filename into command buf with braces in case of spaces */
+ ckmakmsg(cmdbuf,CMDBL,"{",arg,"}",NULL);
+ debug(F110,"findinpath cmdbuf",cmdbuf,0);
+ ckstrncat(cmdbuf,"\r\r",CMDBL); /* And some carriage returns */
+ if (cmifip("","",&s,&x,0,takepath,xxstring) < 0)
+ return(NULL);
+ cmres();
+ return(s);
+}
+
+static int tr_int; /* Flag if TRANSMIT interrupted */
+
+#ifndef MAC
+SIGTYP
+#ifdef CK_ANSIC
+trtrap(int foo) /* TRANSMIT interrupt trap */
+#else
+trtrap(foo) int foo; /* TRANSMIT interrupt trap */
+#endif /* CK_ANSIC */
+/* trtrap */ {
+#ifdef __EMX__
+ signal(SIGINT, SIG_ACK);
+#endif
+ tr_int = 1; /* (Need arg for ANSI C) */
+ SIGRETURN;
+}
+#endif /* MAC */
+#endif /* NOICP */
+
+#ifdef UNIX
+VOID
+getexedir() {
+ extern char * xarg0;
+ long xx;
+ /*
+ Unix provides no standard service for this. We look in argv[0], and if
+ we're lucky there's a full pathname. If not we do a PATH search.
+ */
+ if (ckstrchr(xarg0,'/')) { /* Global copy of argv[0] */
+ int i, k;
+ char * p = NULL;
+ if ((k = ckstrncpy(tmpbuf,xarg0,TMPBUFSIZ-2)) > 0) {
+ p = tmpbuf;
+ /* Convert to fully qualified pathname */
+ if (tmpbuf[0]) if (tmpbuf[0] != '/') {
+ line[0] = NUL;
+ zfnqfp(tmpbuf,LINBUFSIZ-2,(char *)line);
+ if (line[0])
+ p = line;
+ }
+ xx = zchki(p);
+ if (xx > -1) { /* Is the result an existing file? */
+ k = strlen(p);
+ for (i = k-1; i > 0; i--) { /* Yes, strip name part */
+ if (p[i] == '/') {
+ if (i < k-1)
+ p[i+1] = NUL;
+ break;
+ }
+ }
+ }
+ makestr(&exedir,p); /* Save the result */
+ }
+ }
+ if (!exedir && xarg0) { /* Not found? */
+ char * p;
+ p = getenv("PATH"); /* Search the PATH */
+ if (p) { /* If there is one... */
+ char * q, * PATH = NULL;
+ int k;
+ makestr(&PATH,p); /* Pokeable copy of PATH string */
+ if (PATH) { /* If malloc succeeded... */
+ p = PATH;
+ while (p && *p) { /* Loop through segments */
+ q = ckstrchr(p,':'); /* End of this segment */
+ if (q == p) { /* Null PATH segment */
+ p++; /* Skip over colon */
+ continue;
+ }
+ if (q) /* If not at end of PATH string */
+ *q++ = NUL; /* zero out the colon */
+ if ((k = ckstrncpy(tmpbuf,p,TMPBUFSIZ)) > 0) {
+ if (tmpbuf[k-1] != '/') { /* Copy this PATH segment */
+ tmpbuf[k++] = '/'; /* Append '/' if needed */
+ tmpbuf[k] = NUL;
+ }
+ /* Append the argv[0] value */
+ if (ckstrncpy(&tmpbuf[k],xarg0,TMPBUFSIZ) > 0) {
+ if (zchki(tmpbuf) > -1) { /* File exists? */
+ tmpbuf[k] = NUL; /* Yes, we're done */
+ zfnqfp(tmpbuf,LINBUFSIZ,(char *)line);
+ makestr(&exedir,line);
+ break;
+ }
+ } else break;
+ } else break;
+ p = q; /* Not found, go to next segment */
+ } /* while */
+ free(PATH); /* Free PATH copy */
+ }
+ }
+ if (!exedir) { /* Still nothing? */
+ if (zchki(xarg0) > -1) { /* Maybe it's in the current dir */
+ zfnqfp(zgtdir(),LINBUFSIZ,(char *)line);
+ makestr(&exedir,line);
+ }
+ }
+ }
+ if (!exedir) { /* Still nothing? */
+ makestr(&exedir,"/"); /* Fake it with with root. */
+ }
+}
+#endif /* UNIX */
+
+int arg_x = 0;
+static int x_prescan = 0;
+
+/*
+ The argument y once meant something but I can't imagine what so now
+ it's ignored. (Prior to 22 Aug 98, prescan() was called twice by main(),
+ and the arg differentiated the two calls. But this caused all sorts of
+ problems & confusion, so I commented out the second call. This issue might
+ need to be revisited.)
+*/
+VOID
+prescan(dummy) int dummy; { /* Arg is ignored. */
+ extern int howcalled;
+ int yargc; char **yargv;
+ char x;
+ char *yp, *yy;
+#ifdef DEBUG
+ int debcount = 0;
+#endif /* DEBUG */
+ int z;
+
+ if (x_prescan) /* Only run once */
+ return;
+ x_prescan = 1;
+
+ yargc = xargc; /* Make copy of arg vector */
+ yargv = xargv;
+
+#ifndef NOICP
+#ifdef DCMDBUF
+ if (!kermrc)
+ if (!(kermrc = (char *) malloc(KERMRCL+1)))
+ fatal("prescan: no memory for kermrc");
+#endif /* DCMDBUF */
+ ckstrncpy(kermrc,KERMRC,KERMRCL); /* Default init file name */
+#endif /* NOICP */
+
+#ifdef OS2
+ yp = getenv("K95STARTFLAGS");
+ if (yp) {
+ startflags = atoi(yp);
+ }
+#endif /* OS2 */
+
+#ifdef IKSD
+ if (howcalled == I_AM_IKSD) /* Internet Kermit Service daemon */
+ inserver = 1; /* (See inserver section of ckcmai) */
+#endif /* IKSD */
+
+/* Command line options for Kermit */
+
+#ifndef NOCMDL
+ if (yargc > 1
+ && *yargv[1] != '-'
+ && (yargv[1][0] != '=')
+#ifdef KERBANG
+ && (yargv[1][0] != '+')
+#endif /* KERBANG */
+#ifdef IKSD
+ && (howcalled != I_AM_IKSD)
+#endif /* IKSD */
+ ) { /* Filename as 1st argument */
+#ifndef NOICP
+ char *s;
+#endif /* NOICP */
+#ifndef NOURL
+ extern int haveurl;
+ extern struct urldata g_url;
+ if (urlparse(yargv[1],&g_url)) {
+ if (!ckstrcmp(g_url.svc,"ftp",-1,0) ||
+ !ckstrcmp(g_url.svc,"ftps",-1,0)) {
+ haveurl = 1;
+ howcalled = I_AM_FTP;
+ } else if (!ckstrcmp(g_url.svc,"telnet",-1,0) ||
+ !ckstrcmp(g_url.svc,"telnets",-1,0)) {
+ haveurl = 1;
+ howcalled = I_AM_TELNET;
+ } else if (!ckstrcmp(g_url.svc,"ssh",-1,0)) {
+ haveurl = 1;
+ howcalled = I_AM_SSH;
+ } else if (!ckstrcmp(g_url.svc,"iksd",-1,0) ||
+ !ckstrcmp(g_url.svc,"kermit",-1,0)) {
+ haveurl = 1;
+ howcalled = I_AM_KERMIT;
+ } else if (!ckstrcmp(g_url.svc,"http",-1,0) ||
+ !ckstrcmp(g_url.svc,"https",-1,0)) {
+ haveurl = 1;
+ howcalled = I_AM_HTTP;
+ }
+ if (haveurl) {
+ while (--yargc > 0) { /* Go through command-line args */
+ yargv++; /* looking for -Y and -d */
+ yp = *yargv+1;
+ if (**yargv == '-') {
+ x = *(*yargv+1);
+ while (x) {
+ switch (x) {
+#ifndef NOICP
+ case '+':
+ case '-':
+ if (doxarg(yargv,1) < 0) {
+ fatal("Extended argument error");
+ }
+ yp = "";
+ break;
+#endif /* NOICP */
+ case 'Y':
+ noinit++;
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'h':
+ noinit = 1;
+#ifdef OS2
+ startflags |= 2; /* No network DLLs */
+ startflags |= 4; /* No TAPI DLLs */
+ startflags |= 8; /* No Security DLLs */
+ startflags |= 16; /* No Zmodem DLLs */
+ startflags |= 32; /* Stdin */
+ startflags |= 64; /* Stdout */
+#endif /* OS2 */
+ break;
+ case 'd': /* = SET DEBUG ON */
+#ifdef DEBUG
+ if (debcount++ > 0)
+ debtim = 1;
+ if (!deblog)
+ deblog = debopn("debug.log",0);
+#endif /* DEBUG */
+ break;
+#ifdef OS2
+ case 'W':
+ if (*(yp+1))
+ fatal("invalid argument bundling after -W");
+ yargv++, yargc--;
+ if (yargc < 1)
+ fatal("Window handle missing");
+ hwndDialer = (HWND) atol(*yargv);
+ StartedFromDialer = 1;
+ yargv++, yargc--;
+ KermitDialerID = atol(*yargv) ;
+ break;
+ case '#': /* K95 initialization options */
+ if (*(yp+1)) {
+ fatal("invalid argument bundling");
+ }
+ yargv++, yargc--;
+ if (yargc < 1)
+ fatal("-# argument missing");
+ startflags |= atol(*yargv);
+ break;
+#endif /* OS2 */
+ }
+ if (!yp)
+ break;
+ x = *++yp;
+ }
+ }
+ }
+ return;
+ }
+ }
+ /* after this point non-Kermit personalities must return */
+ switch (howcalled) {
+ case I_AM_KERMIT:
+ case I_AM_IKSD:
+ case I_AM_SSHSUB:
+ break;
+ default:
+ return;
+ }
+#endif /* NOURL */
+
+#ifndef NOICP
+ /* If it is not a URL that we recognize, try to treat it as a file */
+
+ if (!isabsolute(yargv[1])) /* If not absolute */
+ s = findinpath(yargv[1]); /* Look in PATH */
+ else
+ s = yargv[1];
+ if (!s)
+ doexit(BAD_EXIT,xitsta);
+ zfnqfp(s,CKMAXPATH,cmdfil); /* In case of CD in file */
+ yargc -= 1; /* Skip past the filename */
+ yargv += 1; /* Otherwise we'll get an error */
+#endif /* NOICP */
+ }
+
+#ifndef NOCMDL
+#ifdef NEWFTP
+ if (howcalled == I_AM_FTP) { /* Kermit's FTP client personality */
+ while (--yargc > 0) { /* Go through command-line args */
+ yargv++; /* looking for -Y and -d */
+ yp = *yargv+1;
+ if (**yargv == '-') {
+ x = *(*yargv+1);
+ while (x) {
+ switch (x) {
+#ifndef NOICP
+ case '+':
+ case '-':
+ if (doxarg(yargv,1) < 0) {
+ fatal("Extended argument error");
+ }
+ yp = "";
+ break;
+#endif /* NOICP */
+ case 'Y':
+ noinit++;
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'h':
+ noinit = 1;
+#ifdef OS2
+ startflags |= 2; /* No network DLLs */
+ startflags |= 4; /* No TAPI DLLs */
+ startflags |= 8; /* No Security DLLs */
+ startflags |= 16; /* No Zmodem DLLs */
+ startflags |= 32; /* Stdin */
+ startflags |= 64; /* Stdout */
+#endif /* OS2 */
+ break;
+ case 'd': /* = SET DEBUG ON */
+#ifdef DEBUG
+ if (debcount++ > 0)
+ debtim = 1;
+ if (!deblog)
+ deblog = debopn("debug.log",0);
+#endif /* DEBUG */
+ break;
+#ifdef OS2
+ case 'W':
+ if (*(yp+1))
+ fatal("invalid argument bundling after -W");
+ yargv++, yargc--;
+ if (yargc < 1)
+ fatal("Window handle missing");
+ hwndDialer = (HWND) atol(*yargv);
+ StartedFromDialer = 1;
+ yargv++, yargc--;
+ KermitDialerID = atol(*yargv) ;
+ break;
+ case '#': /* K95 initialization options */
+ if (*(yp+1)) {
+ fatal("invalid argument bundling");
+ }
+ yargv++, yargc--;
+ if (yargc < 1)
+ fatal("-# argument missing");
+ startflags |= atol(*yargv);
+ break;
+#endif /* OS2 */
+ }
+ if (!yp)
+ break;
+ x = *++yp;
+ }
+ }
+ }
+ return;
+ }
+#endif /* NEWFTP */
+#endif /* NOCMDL */
+
+ while (--yargc > 0) { /* Go through command-line args */
+ yargv++;
+ yp = *yargv+1; /* Pointer for bundled args */
+ if (**yargv == '=') /* Same rules as cmdlin()... */
+ return;
+ debug(F110,"prescan *yargv",*yargv,0);
+
+#ifndef NOICP
+#ifdef KERBANG
+ yy = *yargv;
+ if (!strcmp(yy,"+") || (*yy == '+' && *(yy+1) < (char)33)) {
+ char * s;
+ yargv++;
+ noinit = 1;
+ if (!*yargv)
+ return;
+ cfilef = 1;
+ s = findinpath(*yargv);
+ if (s) {
+ zfnqfp(s,CKMAXPATH,cmdfil);
+ return;
+ } else
+ doexit(BAD_EXIT,xitsta);
+ }
+#endif /* KERBANG */
+#endif /* NOICP */
+ if (!strcmp(*yargv,"--")) /* getopt() conformance */
+ return;
+#ifdef VMS
+ else if (**yargv == '/')
+ continue;
+#endif /* VMS */
+ else if (**yargv == '-') { /* Got an option (begins with dash) */
+ x = *(*yargv+1); /* Get option letter */
+ while (x) { /* Allow for bundled options */
+ debug(F000,"prescan arg","",x);
+ switch (x) {
+#ifndef NOICP
+ case '+':
+ case '-':
+ if (doxarg(yargv,1) < 0) {
+ fatal("Extended argument error");
+ }
+#ifndef COMMENT /* Jeff 28 Apr 2003 */
+ yp = NULL; /* (not "") */
+#else
+ yargv++, yargc--;
+ yp = *yargv;
+#endif /* COMMENT */
+ break;
+#endif /* NOICP */
+
+ case '7': /* Undocumented... */
+ sstelnet = 1; /* (because it doesn't work) */
+ break;
+#ifdef IKSD
+ case 'A': {
+ char * p;
+ inserver = 1; /* Flag that we are doing this */
+ srvcdmsg = 2; /* Preset this */
+ /* See inserver section of ckcmai.c for more settings */
+#ifdef OS2
+ if (*(yp+1)) {
+ fatal("invalid argument bundling after -A");
+ }
+#ifdef NT
+ /* Support for Pragma Systems Telnet/Terminal Servers */
+ p = getenv("PRAGMASYS_INETD_SOCK");
+ if (p && atoi(p) != 0) {
+ ttname[0] = '$';
+ ckstrncpy(&ttname[1],p,TTNAMLEN-1);
+ break;
+ }
+#endif /* NT */
+ yargv++, yargc--;
+ if (yargc < 1 || **yargv == '-') {
+ fatal("-A argument missing");
+ } else {
+ ttname[0] = '$';
+ ckstrncpy(&ttname[1],*yargv,TTNAMLEN-1);
+ }
+#endif /* OS2 */
+ break;
+ }
+#endif /* IKSD */
+
+#ifdef OS2
+ case 'W':
+ if (*(yp+1))
+ fatal("invalid argument bundling after -W");
+ yargv++, yargc--;
+ if (yargc < 1)
+ fatal("Window handle missing");
+#ifdef COMMENT
+ if (dummy) {
+ yargv++, yargc--;
+ break;
+ } else {
+#endif /* COMMENT */
+ hwndDialer = (HWND) atol(*yargv);
+ StartedFromDialer = 1;
+ yargv++, yargc--;
+ KermitDialerID = atol(*yargv) ;
+#ifdef COMMENT
+ }
+#endif /* COMMENT */
+ break;
+
+ case '#': /* K95 initialization options */
+ if (*(yp+1)) {
+ fatal("invalid argument bundling");
+ }
+ yargv++, yargc--;
+ if (yargc < 1)
+ fatal("-# argument missing");
+ startflags |= atol(*yargv);
+ break;
+#endif /* OS2 */
+
+#ifndef NOSPL
+ case 'M': /* My User Name */
+ if (*(yp+1)) {
+ fatal("invalid argument bundling");
+ }
+ yargv++, yargc--;
+ if ((yargc < 1) || (**yargv == '-')) {
+ fatal("missing username");
+ }
+ if ((int)strlen(*yargv) > UIDBUFLEN) {
+ fatal("username too long");
+ }
+#ifdef COMMENT
+/*
+ This can't work. uidbuf is overwritten in sysinit() which has yet to be
+ called. This cannot be set in prescan().
+*/
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ ckstrncpy(uidbuf,*yargv,UIDBUFLEN);
+#endif /* COMMENT */
+ break;
+#endif /* NOSPL */
+ case 'R': /* Remote-only advisory */
+#ifdef CK_IFRO
+ remonly = 1;
+#endif /* CK_IFRO */
+ break;
+ case 'S': /* STAY */
+ stayflg = 1;
+ break;
+ case 'h':
+ noinit = 1;
+#ifdef OS2
+ startflags |= 2; /* No network DLLs */
+ startflags |= 4; /* No TAPI DLLs */
+ startflags |= 8; /* No Security DLLs */
+ startflags |= 16; /* No Zmodem DLLs */
+ startflags |= 32; /* Stdin */
+ startflags |= 64; /* Stdout */
+#endif /* OS2 */
+ break;
+#ifndef NOICP
+ case 'Y': /* No init file */
+ noinit = 1;
+ break;
+#endif /* NOICP */
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'd': /* = SET DEBUG ON */
+#ifdef DEBUG
+ if (debcount++ > 0)
+ debtim = 1;
+ if (!deblog)
+ deblog = debopn("debug.log",0);
+#endif /* DEBUG */
+ break;
+
+ case 'x': /* Server */
+ arg_x = 1; /* Note in advance */
+ break;
+#ifndef NOICP
+ case 'y': /* Alternative init file */
+ noinit = 0;
+ yargv++, yargc--;
+ if (yargc < 1) fatal("missing name in -y");
+ /* Replace init file name */
+ ckstrncpy(kermrc,*yargv,KERMRCL);
+ rcflag = 1; /* Flag that this has been done */
+ debug(F111,"prescan kermrc",kermrc,rcflag);
+ break;
+#endif /* NOICP */
+ case 'z': /* = SET BACKGROUND OFF */
+ bgset = 0;
+ backgrd = 0;
+#ifdef VMS
+ batch = 0;
+#endif /* VMS */
+ break;
+
+ case 'B': /* Force background (batch) */
+ bgset = 1;
+ backgrd = 1;
+#ifdef VMS
+ batch = 1;
+#endif /* VMS */
+ break;
+
+#ifdef CK_NETBIOS
+ case 'N':
+ {
+ int n ;
+ yargv++, yargc--;
+#ifdef COMMENT
+ if (y)
+ break;
+#endif /* COMMENT */
+ if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') {
+ NetBiosAdapter = -1;
+ } else {
+ n = atoi(*yargv);
+ if (n >= 0 && n <= 9)
+ NetBiosAdapter = n;
+ else
+ NetBiosAdapter = -1;
+ }
+ }
+ break;
+#endif /* CK_NETBIOS */
+ default:
+ break;
+ }
+ if (!yp)
+ break;
+ x = *++yp; /* See if options are bundled */
+ }
+ }
+ }
+#endif /* NOCMDL */
+}
+
+/* G E T T C S -- Get Transfer (Intermediate) Character Set */
+
+/*
+ Given two file character sets, this routine picks out the appropriate
+ "transfer" character set to use for translating between them.
+ The transfer character set number is returned.
+
+ Translation between two file character sets is done, for example,
+ by the CONNECT, TRANSMIT, and TRANSLATE commands.
+
+ Translation between Kanji character sets is not yet supported.
+*/
+int
+gettcs(cs1,cs2) int cs1, cs2; {
+#ifdef NOCSETS /* No character-set support */
+ return(0); /* so no translation */
+#else
+ int tcs = TC_TRANSP;
+#ifdef KANJI
+/* Kanji not supported yet */
+ if (fcsinfo[cs1].alphabet == AL_JAPAN ||
+ fcsinfo[cs2].alphabet == AL_JAPAN )
+ tcs = TC_TRANSP;
+ else
+#endif /* KANJI */
+#ifdef CYRILLIC
+/*
+ I can't remember why we don't test both sets here, but I think there
+ must have been a reason...
+*/
+ if (fcsinfo[cs2].alphabet == AL_CYRIL)
+ tcs = TC_CYRILL;
+ else
+#endif /* CYRILLIC */
+#ifdef HEBREW
+ if (fcsinfo[cs1].alphabet == AL_HEBREW ||
+ fcsinfo[cs2].alphabet == AL_HEBREW )
+ tcs = TC_HEBREW;
+ else
+#endif /* HEBREW */
+#ifdef GREEK
+ if (fcsinfo[cs1].alphabet == AL_GREEK ||
+ fcsinfo[cs2].alphabet == AL_GREEK )
+ tcs = TC_GREEK;
+ else
+#endif /* GREEK */
+
+ /* Roman sets ... */
+
+#ifdef LATIN2 /* East European */
+ if (cs1 == FC_2LATIN || cs2 == FC_2LATIN || /* Latin-2 */
+ cs1 == FC_CP852 || cs2 == FC_CP852 || /* CP852 */
+ cs1 == FC_CP1250 || cs2 == FC_CP1250 || /* Windows Latin-2 */
+ cs1 == FC_MAZOVIA || cs2 == FC_MAZOVIA) /* Polish Mazovia */
+ tcs = TC_2LATIN;
+ else
+#endif /* LATIN2 */
+ /* West European Euro-aware */
+ if (cs1 == FC_CP858 || cs1 == FC_9LATIN ||
+ cs2 == FC_CP858 || cs2 == FC_9LATIN)
+ tcs = TC_9LATIN;
+ else /* Traditional West European */
+ tcs = TC_1LATIN;
+ return(tcs);
+#endif /* NOCSETS */
+}
+
+#ifndef NOLOCAL
+/* D O C O N E C T -- Do the connect command */
+/*
+ q = 0 means issue normal informational message about how to get back, etc.
+ q != 0 means to skip the message.
+*/
+
+int
+doconect(q,async) int q, async; {
+ int x; /* Return code */
+#ifdef CK_AUTODL
+ extern CHAR ksbuf[];
+#endif /* CK_AUTODL */
+#ifndef NOKVERBS /* Keyboard macro material */
+ extern int keymac, keymacx;
+#endif /* NOKVERBS */
+ extern int justone, adl_err;
+ int qsave; /* For remembering "quiet" value */
+#ifdef OS2
+ extern int term_io;
+ extern int display_demo;
+ int term_io_save;
+#ifdef KUI
+ extern int kui_async;
+#endif /* KUI */
+#endif /* OS2 */
+ int is_tn = 0;
+
+#ifdef IKSD
+ if (inserver) {
+ if (!quiet)
+ printf("?Sorry, IKSD cannot CONNECT.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ is_tn =
+#ifdef TNCODE
+ (local && network && IS_TELNET()) || (!local && sstelnet)
+#else
+ 0
+#endif /* TNCODE */
+ ;
+/*
+ Saving, changing, and restoring the global "quiet" variable around calls
+ to conect() to control whether the verbose CONNECT message is printed is
+ obviously less elegant than passing a parameter to conect(), but we do it
+ this way to avoid the need to change all of the ck?con.c modules. NOTE:
+ it is important to restore the value immediately upon return in case there
+ is an autodownload or APC.
+*/
+ qsave = quiet; /* Save it */
+ if (!quiet && q > -1)
+ quiet = q; /* Use argument temporarily */
+ conres(); /* Put console back to normal */
+ debug(F101,"doconect justone 1","",justone);
+#ifdef CK_AUTODL
+ ksbuf[0] = NUL; /* Autodownload packet buffer */
+#endif /* CK_AUTODL */
+#ifdef OS2
+ display_demo = 1; /* Remember to display demo */
+#endif /* OS2 */
+
+#ifdef IKS_OPTION
+ if (is_tn && TELOPT_U(TELOPT_KERMIT) && ttchk() >= 0
+#ifdef OS2
+ && !viewonly
+#endif /* OS2 */
+ ) {
+ /* If the remote side is in a state of IKS START-SERVER */
+ /* we request that the state be changed. We will detect */
+ /* a failure to adhere to the request when we call ttinc() */
+ if (!iks_wait(KERMIT_REQ_STOP,0) && !tcp_incoming) {
+ if (!quiet) {
+ printf("\r\nEnter Client/Server Mode... Use:\r\n\r\n");
+ printf(
+" REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
+ printf(" SEND and GET for file transfer.\r\n");
+ printf(" REMOTE commands for file management.\r\n");
+ printf(" FINISH to terminate Client/Server mode.\r\n");
+ printf(" BYE to terminate and close connection.\r\n");
+ printf(" REMOTE HELP for additional information.\r\n\r\n");
+ }
+ quiet = qsave;
+ return(0); /* Failure */
+ }
+ }
+
+ /* Let our peer know our state. */
+#ifdef CK_AUTODL
+ if (is_tn && TELOPT_ME(TELOPT_KERMIT)
+#ifdef OS2
+ && !viewonly
+#endif /* OS2 */
+ ) {
+ if (autodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_START); /* Send Kermit-Server Start */
+ } else if (!autodl && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_STOP);
+ }
+ }
+#else /* CK_AUTODL */
+ if (is_tn && TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ tn_siks(KERMIT_STOP);
+#endif /* CK_AUTODL */
+#endif /* IKS_OPTION */
+
+ debug(F101,"doconect flow","",flow);
+#ifdef OS2
+ debug(F101,"doconect async","",async);
+#ifdef KUI
+ if (kui_async)
+ async = 1;;
+#endif /* KUI */
+ x = conect(async); /* Connect the first time */
+#else /* OS2 */
+ x = conect();
+#endif /* OS2 */
+ debok = 1;
+
+#ifdef IKS_OPTION
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
+ !tcp_incoming && !quiet && ttchk() >= 0
+ ) {
+ printf("\r\nEnter Client/Server Mode... Use:\r\n\r\n");
+ printf(
+" REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
+ printf(" SEND and GET for file transfer.\r\n");
+ printf(" REMOTE commands for file management.\r\n");
+ printf(" FINISH to terminate Client/Server mode.\r\n");
+ printf(" BYE to terminate and close connection.\r\n");
+ printf(" REMOTE HELP for additional information.\r\n\r\n");
+ }
+#endif /* IKS_OPTION */
+
+ quiet = qsave; /* Restore "quiet" value */
+ debug(F101,"doconect justone 2","",justone);
+
+#ifdef NETCONN
+ if (network && tn_exit && ttchk() < 0)
+ doexit(GOOD_EXIT,xitsta); /* Exit with good status */
+#endif /* NETCONN */
+
+#ifdef OS2ORUNIX
+ /* Exit on disconnect if the port is not open or carrier detect */
+ if (exitonclose && (ttchk() < 0))
+ doexit(GOOD_EXIT,xitsta);
+#endif /* OS2ORUNIX */
+
+#ifdef CKCONINTB4CB
+ /* The order makes a difference in HP-UX 8.00. */
+ /* The other order makes it think it's in the background when it */
+ /* returns from CONNECT (Apr 1999). */
+ setint();
+ concb((char)escape); /* Restore console for commands */
+#else
+ /* This is how it has always been so better leave it */
+ /* this way for all non-HP-UX-8.00 builds. */
+ concb((char)escape); /* Restore console for commands */
+ setint();
+#endif /* CKCONINTB4CB */
+
+#ifdef OS2
+ if (!async) {
+ term_io_save = term_io; /* Disable I/O by emulator */
+ term_io = 0;
+#endif /* OS2 */
+
+#ifdef CK_APC
+/*
+ If an APC command was received during CONNECT mode, we define it now
+ as a macro, execute the macro, and then return to CONNECT mode.
+ We do this in a WHILE loop in case additional APCs come during subsequent
+ CONNECT sessions.
+*/
+ debug(F101,"doconect apcactive","",apcactive);
+ debug(F101,"doconect success","",success);
+
+ while (x > 0 && (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && apcstatus != APC_OFF))) {
+ debug(F101,"doconect justone 3","",justone);
+ if (mlook(mactab,"_apc_commands",nmac) == -1) {
+ debug(F110,"doconect about to execute APC",apcbuf,0);
+ domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
+ delmac("_apc_commands",1);
+#ifdef DEBUG
+ } else {
+ debug(F100,"doconect APC in progress","",0);
+#endif /* DEBUG */
+ }
+ debug(F101,"doconect apcactive after domac","",apcactive);
+ if (!apcactive) { /* In case CLEAR APC was in APC */
+ debug(F101,"doconect quit APC loop: apcactive","",apcactive);
+ break;
+ }
+ /* Also don't reconnect if autodownload failed - very confusing! */
+ /* Let them view the local screen to see what happened. - fdc */
+
+ /* This should be conditional. If someone is relying on the */
+ /* connect mode autodownload for the kermit server to use with */
+ /* a remotely executed script we should be able to return to */
+ /* connect mode on the failure. What we really need to do is */
+ /* report the status of the transfer and then return to CONNECT. */
+ /* In unix this would simply be a printf(), but in K95 it could */
+ /* use a popup dialog to report the status. - Jeff */
+
+#ifndef NOXFER
+ debug(F101,"doconect xferstat","",xferstat);
+ if (apcactive == APC_LOCAL && !xferstat && adl_err != 0) {
+ debug(F101,"doconect quit APC loop: xferstat","",xferstat);
+ apcactive = APC_INACTIVE;
+ break;
+ }
+#endif /* NOXFER */
+#ifdef OS2
+ msleep(250);
+#endif /* OS2 */
+ debug(F101,"doconect justone 4","",justone);
+ qsave = quiet; /* Do this again... */
+ if (!quiet && q > -1)
+ quiet = q;
+#ifdef CK_AUTODL
+ ksbuf[0] = NUL;
+#endif /* CK_AUTODL */
+#ifdef IKS_OPTION
+#ifdef CK_AUTODL
+ if (is_tn &&
+ TELOPT_ME(TELOPT_KERMIT) &&
+ !TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
+ autodl
+#ifdef CK_APC
+ && !apcactive
+#endif /* CK_APC */
+#ifdef OS2
+ && !viewonly
+#endif /* OS2 */
+ ) {
+ tn_siks(KERMIT_START); /* Send Kermit-Server Start */
+ }
+#endif /* CK_AUTODL */
+#endif /* IKS_OPTION */
+#ifndef OS2
+ x = conect(); /* Re-CONNECT. */
+#else /* OS2 */
+ x = conect(0);
+ term_io = term_io_save;
+#endif /* OS2 */
+ debok = 1;
+ quiet = qsave;
+ debug(F101,"doconect justone 5","",justone);
+#ifdef NETCONN
+ if (network && ttchk() < 0) {
+ if (tn_exit || exitonclose)
+ doexit(GOOD_EXIT,xitsta);
+ else
+ break;
+ }
+#endif /* NETCONN */
+
+#ifdef OS2ORUNIX
+ /* If connection dropped */
+ if (ttchk() < 0) {
+ concb((char)escape); /* Restore console. */
+ if (exitonclose)
+ doexit(GOOD_EXIT,xitsta);
+ else
+ break;
+ }
+#endif /* OS2ORUNIX */
+ } /* Loop back for more. */
+#endif /* CK_APC */
+
+#ifndef NOKVERBS
+ if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
+ /* Set up the macro and return */
+ /* Do not clear the keymac flag */
+#ifdef OS2
+ term_io = term_io_save;
+#endif /* OS2 */
+ return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs));
+ }
+#endif /* NOKVERBS */
+#ifdef OS2
+ term_io = term_io_save;
+ } /* if (!async) */
+#endif /* OS2 */
+
+#ifdef CKCONINTB4CB
+ /* The order makes a difference in HP-UX 8.00. */
+ /* The other order makes it think it's in the background when it */
+ /* returns from CONNECT (Apr 1999). */
+ setint();
+ concb((char)escape); /* Restore console for commands */
+#else
+ /* This is how it has always been so better leave it */
+ /* this way for all non-HP-UX-8.00 builds. */
+ concb((char)escape); /* Restore console for commands */
+ setint();
+#endif /* CKCONINTB4CB */
+#ifdef OS2
+ if (!async)
+#endif /* OS2 */
+ what = W_COMMAND; /* Back in command mode. */
+ return(x); /* Done. */
+}
+#endif /* NOLOCAL */
+
+#ifndef NOICP
+#ifdef COMMENT
+/*
+ It seemed that this was needed for OS/2, in which \v(cmdfile) and other
+ file-oriented variables or functions can return filenames containing
+ backslashes, which are subsequently interpreted as quotes rather than
+ directory separators (e.g. see commented section for VN_CMDF below).
+ But the problem can't be cured at this level. Example:
+
+ type \v(cmdfile)
+
+ Without doubling, the filename is parsed correctly, but then when passed
+ to UNIX 'cat' through the shell, the backslash is removed, and then cat
+ can't open the file. With doubling, the filename is not parsed correctly
+ and the TYPE command fails immediately with a "file not found" error.
+*/
+/*
+ Utility routine to double all backslashes in a string.
+ s1 is pointer to source string, s2 is pointer to destination string,
+ n is length of destination string, both NUL-terminated.
+ Returns 0 if OK, -1 if not OK (destination string too short).
+*/
+int
+dblbs(s1,s2,n) char *s1, *s2; int n; {
+ int i = 0;
+ while (*s1) {
+ if (*s1 == '\\') {
+ if (++i > n) return(-1);
+ *s2++ = '\\';
+ }
+ if (++i > n) return(-1);
+ *s2++ = *s1++;
+ }
+ *s2 = NUL;
+ return(0);
+}
+#endif /* COMMENT */
+
+char *
+gmdmtyp() { /* Get modem type */
+#ifndef NODIAL
+ int i, x;
+
+ debug(F111,"gmdmtyp","mdmtyp",mdmtyp);
+ debug(F111,"gmdmtyp","mdmsav",mdmsav);
+
+ x = mdmtyp;
+ if (x < 0) /* In case of network dialing */
+ x = mdmsav;
+ if (x < 1)
+ return("none");
+ else
+ for (i = 0; i < nmdm; i++)
+ if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0))
+ return(mdmtab[i].kwd);
+#endif /* NODIAL */
+ return("none");
+}
+
+#ifndef NOXMIT
+#ifndef NOLOCAL
+/* T R A N S M I T -- Raw upload */
+
+/* Obey current line, duplex, parity, flow, text/binary settings. */
+/* Returns 0 upon apparent success, 1 on obvious failure. */
+
+/***
+ Things to add:
+ . Make both text and binary mode obey set file bytesize.
+ . Maybe allow user to specify terminators other than CR?
+ . Maybe allow user to specify prompts other than single characters?
+ . Make STATISTICS also work for TRANSMIT.
+ . If TRANSMIT is done without echo, make some kind of (optional) display.
+ . Make the same optimization for binary-mode transmit that was done for
+ text-mode (in the no-echo / no-prompt / no-pause case).
+***/
+
+/* T R A N S M I T -- Raw upload */
+
+/* s is the filename, t is the turnaround (prompt) character */
+
+/*
+ Maximum number of characters to buffer.
+ Must be less than LINBUFSIZ
+*/
+#ifdef OS2
+#define XMBUFS 4096 /* For compatibility with XYZmodem */
+#else /* OS2 */
+#define XMBUFS 1024
+#endif /* OS2 */
+
+#ifdef TNCODE
+#ifndef IAC
+#define IAC 255
+#endif /* IAC */
+#endif /* TNCODE */
+
+#define OUTXBUFSIZ 15
+static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */
+static int inxcount = 0; /* and count */
+static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */
+static int outxcount = 0; /* and count */
+
+/* T R A N S M I T -- Unguarded non-protocol file transmission */
+/*
+ Call with:
+ char * s: Name of file to transmit.
+ char t: Turnaround char for text-mode transmission (normally LF).
+ int xlate: nonzero = charset translation for text-mode xfer, 0 = skip.
+ int binary: nonzero = transmit in binary mode, 0 = in text mode.
+*/
+#define XBBUFSIZ 508 /* For binary blasting */
+static CHAR xbbuf[XBBUFSIZ+4];
+
+int
+#ifdef CK_ANSIC
+transmit(char * s, char t, int xlate, int binary, int xxecho)
+#else
+transmit(s,t,xlate,binary,xxecho) char *s; char t; int xlate, binary, xxecho;
+#endif /* CK_ANSIC */
+/* transmit */ {
+#ifdef MAC
+ extern char sstate;
+ int count = 100;
+#else
+ int count = 0;
+#ifdef OS2
+#ifdef NT
+ SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
+#else /* NT */
+ SIGTYP (* volatile oldsig)(int);
+#endif /* NT */
+
+#else /* OS2 */
+ SIGTYP (* oldsig)();
+#endif /* OS2 */
+#endif /* MAC */
+ int eof = 0; /* End of File flag */
+ int eol = 0; /* End of Line flag */
+ int rc = 1; /* Return code. 0=fail, 1=succeed. */
+ int myflow; /* Local copy of global flow... */
+ int is_tn = 0; /* Do Telnet negotiations */
+ int xbufsiz = XMBUFS; /* Size of TRANSMIT buffer */
+ int x, y, c, i; /* Int workers... */
+ int control = 0; /* Echo loop control */
+ long nbytes = 0; /* File byte count */
+ long zz; /* Long worker */
+ char *p; /* Char * worker */
+
+#ifdef PIPESEND
+ extern int pipesend;
+#endif /* PIPESEND */
+
+#ifndef NOCSETS
+ int tcs = TC_TRANSP; /* Intermediate (xfer) char set */
+ int langsv = L_USASCII; /* Save current language */
+ int unicode = 0;
+ int tcssize = 0;
+
+#ifdef CK_ANSIC /* ANSI C prototypes... */
+ CHAR (*sxo)(CHAR);
+ CHAR (*rxo)(CHAR);
+ CHAR (*sxi)(CHAR);
+ CHAR (*rxi)(CHAR);
+#else /* Not ANSI C... */
+ CHAR (*sxo)();
+ CHAR (*rxo)();
+ CHAR (*sxi)();
+ CHAR (*rxi)();
+#endif /* CK_ANSIC */
+#ifdef UNICODE
+ union ck_short uc;
+ int bomorder = 0;
+#ifdef CK_ANSIC
+ extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
+ extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
+ extern int (*xuf)(USHORT);
+ extern USHORT (*xfu)(CHAR);
+#else
+ extern int (*xl_ufc[MAXFCSETS+1])();
+ extern USHORT (*xl_fcu[MAXFCSETS+1])();
+ extern int (*xuf)();
+ extern USHORT (*xfu)();
+#endif /* CK_ANSIC */
+#endif /* UNICODE */
+#endif /* NOCSETS */
+
+ debug(F101,"xmit t","",t);
+ debug(F101,"xmit xlate","",xlate);
+ debug(F101,"xmit binary","",binary);
+
+#ifdef PIPESEND
+ if (pipesend) {
+ if (nopush) return(-2);
+ if (zxcmd(ZIFILE,s) < 1) {
+ printf("?Can't start command: %s\n",s);
+ return(0);
+ }
+ } else
+#endif /* PIPESEND */
+ if (zopeni(ZIFILE,s) == 0) { /* Open the file to be transmitted */
+ printf("?Can't open file %s\n",s);
+ return(0);
+ }
+ x = -1; /* Open the communication channel */
+ if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { /* (no harm if already open) */
+ printf("Can't open device %s\n",ttname);
+ return(0);
+ }
+ zz = x ? speed : -1L;
+ if (binary) { /* Binary file transmission */
+ myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
+
+ if (ttvt(zz,myflow) < 0) { /* So no Xon/Xoff! */
+ printf("Can't condition line\n");
+ return(0);
+ }
+ } else {
+ if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
+ printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
+ return(0);
+ }
+ }
+ is_tn =
+#ifdef TNCODE
+ (local && network && IS_TELNET()) || (!local && sstelnet)
+#else
+ 0
+#endif /* TNCODE */
+ ;
+
+#ifndef NOCSETS
+/* Set up character set translations */
+
+ tcs = 0; /* "Transfer" or "Other" charset */
+ sxo = rxo = NULL; /* Initialize byte-to-byte functions */
+ sxi = rxi = NULL;
+ unicode = 0; /* Assume Unicode won't be involved */
+ if (!binary && xlate) { /* Set up charset translations */
+/*
+ In the SENDING direction, we are converting from the local file's
+ character-set (fcharset) to the remote terminal charset (tcsr). In the
+ RECEIVING direction (echoing) we are converting from the remote end of the
+ terminal charset (tcsr) to its local end (tcsl), which is not necessarily
+ the same as the file character-set. Especially when the file character
+ set is UCS-2, which is not a valid terminal character set. The various
+ combinations are represented in this table:
+
+ FCS = File Character Set
+ RCS = Remote Terminal Character Set
+ CCS = Console (Local Terminal) Character Set
+
+ 8 4 2 1
+ FCS FCS RCS CCS
+ UCS UTF UTF UTF
+ 0 0 0 0 = 0 = No translation
+ 0 0 0 1 = 1 = FCS -> RCS, Echo RCS -> UTF
+ 0 0 1 0 = 2 = FCS -> UTF, Echo UTF -> CCS
+ 0 0 1 1 = 3 = FCS -> UTF, Echo no translation
+
+ 0 1 0 0 = 4 = UTF -> RCS, Echo RCS -> CCS
+ 0 1 0 1 = 5 = UTF -> RCS, Echo RCS -> UTF
+ 0 1 1 0 = 6 = UTF -> UTF, Echo UTF -> CCS
+ 0 1 1 1 = 7 = No translation
+
+ 1 0 0 0 = 8 = UCS -> RCS, Echo RCS -> CCS
+ 1 0 0 1 = 9 = UCS -> RCS, Echo RCS -> UTF
+ 1 0 1 0 = 10 = UCS -> UTF, Echo UTF -> CCS
+ 1 0 1 1 = 11 = UCS -> UTF, Echo no translation
+*/
+#ifdef UNICODE
+ xfu = NULL; /* Unicode translation functions */
+ xuf = NULL;
+ bomorder = ucsorder; /* UCS-2 byte order */
+
+ if (fcharset == FC_UCS2) /* File charset is UCS-2 */
+ unicode |= 8;
+ else if (fcharset == FC_UTF8) /* File charset is UTF-8 */
+ unicode |= 4;
+ if (tcsr == FC_UTF8) /* Remote term charset is UTF-8 */
+ unicode |= 2;
+ if (tcsl == FC_UTF8) /* Local term charset is UTF-8 */
+ unicode |= 1;
+#endif /* UNICODE */
+/*
+ When Unicode not involved -- TCS is the intermediate (xfer) set, and:
+ sxo = File-to-Intermediate charset function
+ rxo = Intermediate-to-Remote-Terminal charset function
+ sxi = Remote-Terminal-to-Intermediate
+ rxi = Intermediate-to-Local-Terminal
+*/
+ tcs = gettcs(tcsr,fcharset); /* Get intermediate set. */
+ sxo = xls[tcs][fcharset]; /* translation function */
+ rxo = xlr[tcs][tcsr]; /* pointers for output functions */
+ sxi = xls[tcs][tcsr]; /* and for input functions. */
+ rxi = xlr[tcs][tcsl];
+/*
+ At this point we have unicode nonzero if Unicode is involved in the
+ conversion, and to 0 if it is not.
+ The following is to prevent use of zmstuff() and zdstuff() by translation
+ functions (stuffing works with file i/o, not with communication i/o).
+*/
+ langsv = language; /* Save current SET LANGUAGE */
+ language = L_USASCII; /* No language-specific translations */
+ }
+#endif /* NOCSETS */
+
+ i = 0; /* Beginning of buffer. */
+#ifndef MAC
+#ifndef AMIGA
+ oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
+#endif /* AMIGA */
+#endif /* MAC */
+ tr_int = 0; /* Have not been interrupted (yet). */
+ rc = 1; /* Return code presumed good. */
+#ifdef VMS
+ conres();
+#endif /* VMS */
+
+#ifndef NOCSETS
+ debug(F101,"XMIT unicode","",unicode);
+#ifdef UNICODE
+ debug(F101,"XMIT bomorder","",bomorder);
+#endif /* UNICODE */
+#endif /* NOCSETS */
+
+ c = 0; /* Initial condition */
+ while (c > -1 && !eof) { /* Loop for all characters in file */
+ eol = 0;
+#ifdef MAC
+ /*
+ * It is expensive to run the miniparser so don't do it for
+ * every character.
+ */
+ if (--count < 0) {
+ count = 100;
+ miniparser(1);
+ if (sstate == 'a') {
+ sstate = '\0';
+ goto xmitfail;
+ }
+ }
+#else /* Not MAC */
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ goto xmitfail;
+ }
+#endif /* MAC */
+ c = zminchar(); /* Get a file character */
+#ifdef COMMENT
+/* too much */
+#ifdef DEBUG
+ if (deblog) {
+ if (c < 0)
+ debug(F101,"XMIT zminchar","",c);
+ else
+ debug(F000,"XMIT zminchar","",c);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ if (c < -1) { /* Other error */
+ printf("?TRANSMIT file read error: %s\n",ck_errstr());
+ goto xmitfail;
+ } else if (c > -1) {
+ nbytes++;
+ c &= fmask; /* Apply SET FILE BYTESIZE mask */
+ } else if (c == -1) {
+ eof = 1;
+ debug(F101,"XMIT eof","",eof);
+ }
+ if (binary) { /* Binary... */
+ if (c == -1) { /* If EOF */
+ rc = 1; /* Success */
+ eof = 1;
+ goto xmitexit; /* Done */
+ }
+ if (!xmitw && !xxecho) { /* Special "blast" mode */
+ if (count == XBBUFSIZ) { /* File input buffer full... */
+ while (count > 0) {
+ errno = 0;
+ y = ttol(xbbuf,count);
+ if (y < 0) { /* try to send it. */
+ printf("?TRANSMIT output error: %s\n",
+ ck_errstr());
+ debug(F111,"XMIT binary ttol error",
+ ck_errstr(),errno);
+ rc = 0;
+ break;
+ }
+ if (y < 0) break;
+ count -= y;
+ }
+ count = 0;
+ }
+ xbbuf[count++] = c;
+#ifdef TNCODE
+ if (c == IAC && is_tn) /* Telnet IAC */
+ xbbuf[count++] = IAC; /* must be doubled */
+#endif /* TNCODE */
+ continue;
+ }
+ if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
+ printf("?Can't transmit character\n");
+ goto xmitfail;
+ }
+#ifdef TNCODE
+ if (c == IAC && is_tn) /* Quote Telnet IAC */
+ ttoc((char)IAC);
+#endif /* TNCODE */
+
+ if (xmitw) /* Pause if requested */
+ msleep(xmitw);
+
+ if (xxecho) { /* SET TRANSMIT ECHO ON? */
+ if (duplex) { /* Yes, for half duplex */
+#ifndef NOLOCAL
+#ifdef OS2
+ /* Echo to emulator */
+ scriptwrtbuf((USHORT)(c & cmdmsk));
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ if (conoc((char)(c & cmdmsk)) < 0) /* echo locally. */
+ goto xmitfail;
+ } else { /* For full duplex, */
+ int i, n; /* display whatever is there. */
+ n = ttchk(); /* See how many chars are waiting */
+ if (n < 0) { /* Connection dropped? */
+ printf("?Connection lost\n");
+ goto xmitfail;
+ }
+ for (i = 0; i < n; i++) { /* Read and echo that many. */
+ x = ttinc(xmitt); /* Timed read just in case. */
+ if (x > -1) { /* If no timeout */
+ if (parity) x &= 0x7f; /* display the char, */
+#ifndef NOLOCAL
+#ifdef OS2
+ /* Echo to emulator */
+ scriptwrtbuf((USHORT)x);
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ if (conoc((char)(x & cmdmsk)) < 0) {
+ printf("?Output error\n");
+ goto xmitfail;
+ }
+ } else if (x == -2) {
+ printf("Connection closed.\n");
+ ttclos(1);
+ goto xmitfail;
+ } else if (x == -3) {
+ printf(
+ "Session Limit exceeded - closing connection.\n"
+ );
+ ttclos(1);
+ goto xmitfail;
+ } else {
+ printf("?Communications error\n");
+ goto xmitfail;
+ }
+ }
+ }
+ } else ttflui(); /* Not echoing, just flush input. */
+
+ } else { /* Text mode, line at a time. */
+#ifdef UNICODE
+ if (fcharset == FC_UCS2 && xlate) { /* Special for UCS-2 */
+ char xbuf[8];
+ x = 1 - (nbytes & 1); /* Odd or even byte */
+ if (x == 0) /* Note: 1 = the 1st, 0 = 2nd, etc */
+ uc.x_short = 0;
+ if (bomorder) /* Little Endian */
+ x = 1 - x; /* Save byte in appropriate half */
+ debug(F101,"XMIT UCS2 x","",x);
+ uc.x_char[x] = (CHAR) (c & 0xff);
+ if (nbytes & 1) /* First byte, go back for next */
+ continue;
+ if (nbytes == 2) { /* UCS-2 Byte Order Mark */
+ if (uc.x_short == (USHORT) 0xfeff) {
+ debug(F100,"XMIT UCS2 BOM FEFF","",bomorder);
+ continue;
+ } else if (uc.x_short == (USHORT) 0xfffe) {
+ bomorder = 1 - bomorder;
+ debug(F100,"XMIT UCS2 BOM FFFE (swap)","",bomorder);
+ continue;
+ }
+ }
+ sprintf(xbuf,"%04X",uc.x_short); /* SAFE */
+ debug(F111,"XMIT UCS2",xbuf,uc.x_short);
+ if (nbytes & 1) /* Special eol test for UCS-2 */
+ if (uc.x_short == '\n')
+ eol = 1;
+#ifdef COMMENT
+ if (uc.x_short == 0x2028 || uc.x_short == 0x2029)
+ eol = 1;
+#endif /* COMMENT */
+ } else
+#endif /* UNICODE */
+ if (c == '\n') { /* Normal eol test otherwise */
+ eol = 1;
+ }
+ if (eol) { /* End of line? */
+ int stuff = -1;
+ debug(F101,"XMIT eol length","",i);
+ if (i == 0) { /* Blank line? */
+ if (xmitf) /* Yes, insert fill if asked. */
+ line[i++] = dopar((char) xmitf);
+ }
+ if (i == 0 || ((char) line[i-1]) != ((char) dopar(CR)))
+ line[i++] = dopar(CR); /* Terminate it with CR */
+ if (xmitl) {
+ stuff = LF;
+#ifdef TNCODE
+ } else if (is_tn && (tn_nlm != TNL_CR)) {
+ /* TELNET NEWLINE ON/OFF/RAW */
+ stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
+#endif /* TNCODE */
+ }
+ if (stuff > -1)
+ line[i++] = dopar((char)stuff);
+ line[i] = NUL;
+ debug(F111,"XMIT eol line",line,i);
+
+ } else if (c != -1) { /* Not a newline, regular character */
+ int k, x;
+ outxbuf[0] = c; /* In case of no translation */
+ outxcount = 1; /* Assume result is one byte */
+#ifndef NOCSETS
+ switch (unicode) {
+ case 0: /* No Unicode involved */
+ case 1:
+ if (xlate) { /* If not /TRANSPARENT */
+ /* Local-to-intermediate */
+ if (sxo) c = (*sxo)((char)c);
+ /* Intermediate-to-remote */
+ if (rxo) c = (*rxo)((char)c);
+ outxbuf[0] = c;
+ }
+ break;
+#ifdef UNICODE
+ case 2: /* Local byte to UTF-8 */
+ case 3:
+ xfu = xl_fcu[fcharset];
+ tcssize = fcsinfo[fcharset].size;
+ outxcount =
+ b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
+ break;
+ case 4: /* Local UTF-8 to remote byte */
+ case 5:
+ xuf = xl_ufc[tcsr];
+ x = u_to_b((CHAR)c); /* Convert to byte */
+ if (x == -1) { /* If more input bytes needed */
+ continue; /* go back and get them */
+ } else if (x == -2) { /* LS or PS (shouldn't happen) */
+ outxbuf[0] = CR;
+ } else if (x == -9) { /* UTF-8 error */
+ outxbuf[0] = '?'; /* Insert error char */
+ outxbuf[1] = u_to_b2(); /* Insert next char */
+ outxcount = 2;
+ } else {
+ outxbuf[0] = /* Otherwise store result */
+ (unsigned)(x & 0xff);
+ }
+ break;
+ case 6: /* UTF-8 to UTF-8 */
+ case 7:
+ break;
+ case 8: /* UCS-2 to byte */
+ case 9:
+ xuf = xl_ufc[tcsr];
+ outxbuf[0] = (*xuf)(uc.x_short);
+ break;
+ case 10:
+ case 11: { /* UCS-2 to UTF-8 */
+ int j;
+ CHAR * buf = NULL;
+ x = ucs2_to_utf8(uc.x_short,&buf);
+ if (x < 0) {
+ outxbuf[0] = 0xff; /* (= U+FFFD) */
+ outxbuf[1] = 0xbd;
+ x = 2;
+ }
+ for (j = 0; j < x; j++)
+ outxbuf[j] = buf[j];
+ outxcount = x;
+ break;
+ }
+#endif /* UNICODE */
+ }
+#endif /* NOCSETS */
+ outxbuf[outxcount] = NUL;
+ debug(F111,"XMIT outxbuf",outxbuf,outxcount);
+/*
+ Now the input character (1 or more bytes) is translated into the output
+ expansion buffer (1 or more bytes); outxcount = number of bytes to add to
+ the TRANSMIT line buffer, which we do here, taking care of parity, SI/SO
+ processing, and quoting Telnet IACs.
+*/
+ for (k = 0; k < outxcount; k++) {
+ c = outxbuf[k];
+ if (xmits && parity && (c & 0200)) { /* If shifting */
+ line[i++] = dopar(SO); /* needs to be done, */
+ line[i++] = dopar((char)c); /* do it here, */
+ line[i++] = dopar(SI); /* crudely. */
+ } else {
+ line[i++] = dopar((char)c);
+#ifdef TNCODE
+ if (c == (CHAR)IAC && is_tn)
+ line[i++] = (CHAR)IAC;
+#endif /* TNCODE */
+ }
+ }
+ }
+/*
+ Send characters if buffer full, or at end of line, or at end of file.
+ (End of line only if echoing, waiting for a prompt, or pausing.)
+*/
+ debug(F000,"XMIT c",ckitoa(i),c);
+ if (i >= xbufsiz || eof || (eol && (xxecho || xmitw || t))) {
+ p = line;
+ line[i] = '\0';
+ debug(F111,"transmit buf",p,i);
+ if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
+ printf("?TRANSMIT output error: %s\n",ck_errstr());
+ rc = 0;
+ break;
+ }
+ i = 0; /* Reset buffer pointer. */
+/*
+ Now we handle the echo. If the user wants to see it, or if we have to
+ wait for the turnaround character, t. If the echo is being displayed,
+ and terminal character-set translation is required, we do it here.
+*/
+ if (duplex && xxecho) { /* If local echo, echo it */
+ if (parity || cmdmsk == 0x7f) { /* Strip hi bits */
+ char *ss = line; /* if necessary */
+ while (*ss) {
+ *ss &= 0x7f;
+ ss++;
+ }
+ }
+#ifndef NOLOCAL
+#ifdef OS2
+ { /* Echo to emulator */
+ char *ss = p;
+ while (*ss) {
+ scriptwrtbuf((USHORT)*ss);
+ ss++;
+ }
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ if (conoll(p) < 0)
+ goto xmitfail;
+ }
+ if (xmitw) /* Sleep TRANSMIT PAUSE interval */
+ msleep(xmitw);
+
+ control = 0; /* Readback loop control */
+ if (t != 0 && eol) /* TRANSMIT PROMPT given and at EOL */
+ control |= 1;
+ if (xxecho && !duplex) /* Echo desired and is remote */
+ control |= 2;
+
+ if (control) { /* Do this if reading back the echo */
+ int n;
+ x = 0;
+ while (1) {
+ if (control & 1) { /* Termination criterion */
+ if (x == t) /* for turnaround */
+ break;
+ } else if (control & 2) { /* And for echoing */
+ if ((n = ttchk()) < 1)
+ break;
+ }
+ if ((x = ttinc(xmitt)) < 0) { /* Read with timeout */
+ switch (x) {
+ case -2:
+ printf("Connection closed.\n");
+ ttclos(1);
+ goto xmitfail;
+ case -3:
+ printf(
+ "Session Limit exceeded - closing connection.\n"
+ );
+ ttclos(1); /* full thru... */
+ goto xmitfail;
+ default:
+ printf("?Timeout\n");
+ goto xmitfail;
+ }
+ }
+ if (x > -1 && (control & 2)) { /* Echo any echoes */
+ if (parity)
+ x &= 0x7f;
+ c = x;
+#ifndef NOLOCAL
+#ifdef OS2
+ scriptwrtbuf((USHORT)x);
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ inxbuf[0] = c;
+ inxcount = 1;
+#ifndef NOCSETS
+ switch (unicode & 3) { /* Remote bits */
+ case 0:
+ if (xlate) {
+ if (sxi) c = (*sxi)((CHAR)c);
+ if (rxi) c = (*rxi)((CHAR)c);
+ inxbuf[0] = c;
+ }
+ break;
+#ifdef UNICODE
+ case 1: /* Remote Byte to local UTF-8 */
+ xfu = xl_fcu[tcsr];
+ tcssize = fcsinfo[tcsr].size;
+ inxcount =
+ b_to_u((CHAR)c,
+ inxbuf,
+ OUTXBUFSIZ,
+ tcssize
+ );
+ break;
+ case 2: /* Remote UTF-8 to local Byte */
+ xuf = xl_ufc[tcsl];
+ x = u_to_b((CHAR)c);
+ if (x < 0)
+ continue;
+ inxbuf[0] = (unsigned)(x & 0xff);
+ break;
+ case 3: /* UTF-8 to UTF-8 */
+ break;
+#endif /* UNICODE */
+ }
+#endif /* NOCSETS */
+ inxbuf[inxcount] = NUL;
+ if (conxo(inxcount,(char *)inxbuf) < 0)
+ goto xmitfail;
+ }
+ }
+ } else /* Not echoing */
+ ttflui(); /* Just flush input buffer */
+ } /* End of buffer-dumping block */
+ } /* End of text mode */
+ if (eof) {
+ rc = 1;
+ goto xmitexit;
+ }
+ } /* End of character-reading loop */
+
+ xmitfail: /* Failure exit point */
+ rc = 0;
+
+ xmitexit: /* General exit point */
+ if (rc > 0) {
+ if (binary && !xmitw && !xxecho) { /* "blasting"? */
+ while (count > 0) { /* Partial buffer still to go? */
+ errno = 0;
+ y = ttol(xbbuf,count);
+ if (y < 0) {
+ printf("?TRANSMIT output error: %s\n",
+ ck_errstr());
+ debug(F111,"XMIT binary eof ttol error",
+ ck_errstr(),errno);
+ rc = 0;
+ break;
+ }
+ count -= y;
+ }
+ } else if (!binary && *xmitbuf) { /* Anything to send at EOF? */
+ p = xmitbuf; /* Yes, point to string. */
+ while (*p) /* Send it. */
+ ttoc(dopar(*p++)); /* Don't worry about echo here. */
+ }
+ }
+
+#ifndef AMIGA
+#ifndef MAC
+ signal(SIGINT,oldsig); /* Put old signal action back. */
+#endif /* MAC */
+#endif /* AMIGA */
+#ifdef VMS
+ concb(escape); /* Put terminal back, */
+#endif /* VMS */
+ zclose(ZIFILE); /* Close file, */
+#ifndef NOCSETS
+ language = langsv; /* restore language, */
+#endif /* NOCSETS */
+ ttres(); /* and terminal modes, */
+ return(rc); /* and return successfully. */
+}
+#endif /* NOLOCAL */
+#endif /* NOXMIT */
+
+#ifndef NOCSETS
+
+_PROTOTYP( CHAR (*sxx), (CHAR) ); /* Local translation function */
+_PROTOTYP( CHAR (*rxx), (CHAR) ); /* Local translation function */
+_PROTOTYP( CHAR zl1as, (CHAR) ); /* Latin-1 to ascii */
+_PROTOTYP( CHAR xl1as, (CHAR) ); /* ditto */
+
+/* X L A T E -- Translate a local file from one character set to another */
+
+/*
+ Translates input file (fin) from character set csin to character set csout
+ and puts the result in the output file (fout). The two character sets are
+ file character sets from fcstab.
+*/
+
+int
+xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
+
+#ifndef MAC
+#ifdef OS2
+ extern int k95stdout;
+ extern int wherex[], wherey[];
+ extern unsigned char colorcmd;
+#ifdef NT
+ SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
+#else /* NT */
+ SIGTYP (* volatile oldsig)(int); /* For saving old interrupt trap. */
+#endif /* NT */
+#else /* OS2 */
+ SIGTYP (* oldsig)();
+#endif /* OS2 */
+#endif /* MAC */
+#ifdef CK_ANSIC
+ int (*fn)(char); /* Output function pointer */
+#else
+ int (*fn)();
+#endif /* CK_ANSIC */
+ extern int xlatype;
+ int filecode; /* Code for output file */
+ int scrnflg = 0;
+
+ int z = 1; /* Return code. */
+ int x, c, c2; /* Workers */
+#ifndef UNICODE
+ int tcs;
+#endif /* UNICODE */
+
+ ffc = 0L;
+
+ if (zopeni(ZIFILE,fin) == 0) { /* Open the file to be translated */
+#ifdef COMMENT
+ /* An error message was already printed by zopeni() */
+ printf("?Can't open input file %s\n",fin);
+#endif /* COMMENT */
+ return(0);
+ }
+#ifdef MAC
+/*
+ If user specified no output file, it goes to the screen. For the Mac,
+ this must be done a special way (result goes to a new window); the Mac
+ doesn't have a "controlling terminal" device name.
+*/
+ filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
+#else
+#ifdef VMS
+ filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
+#else
+#ifdef OS2
+ filecode = (!stricmp(fout,"con") || !stricmp(fout,"con:")) ?
+ ZCTERM : ZMFILE;
+ if ((filecode == ZCTERM) && !k95stdout && !inserver)
+ csout = FC_UCS2;
+#else /* OS2 */
+ filecode = ZOFILE;
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* MAC */
+ if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
+ printf("?Can't open output file %s\n",fout);
+ return(0);
+ }
+#ifndef AMIGA
+#ifndef MAC
+ oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
+#endif /* MAC */
+#endif /* AMIGA */
+
+ scrnflg = (filecode == ZCTERM); /* Set output function */
+ if (scrnflg)
+ fn = NULL;
+ else if (filecode == ZMFILE)
+ fn = putmfil;
+ else
+ fn = putfil;
+
+ tr_int = 0; /* Have not been interrupted (yet). */
+ z = 1; /* Return code presumed good. */
+
+ if (!scrnflg && !quiet)
+ printf(" %s (%s) => %s (%s)\n", /* Say what we're doing. */
+ fin, fcsinfo[csin].keyword,
+ fout,fcsinfo[csout].keyword
+ );
+
+#ifndef UNICODE
+/*
+ Non-Unicode picks the "most appropriate" transfer character set as the
+ intermediate set, which results in loss of any characters that the source
+ and target sets have in common, but are lacking from the intermediate set.
+*/
+#ifdef KANJI
+ /* Special handling for Japanese... */
+
+ if (fcsinfo[csin].alphabet == AL_JAPAN ||
+ fcsinfo[csout].alphabet == AL_JAPAN) {
+ USHORT eu;
+ int c, x, y;
+
+ xpnbyte(-1,0,0,NULL); /* Reset output machine */
+ xlatype = XLA_JAPAN;
+
+ while ((c = xgnbyte(FC_JEUC,csin,NULL)) > -1) { /* Get an EUC byte */
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ z = 0;
+ break;
+ }
+ /* Send EUC byte to output machine */
+ if ((x = xpnbyte(c,TC_JEUC,csout,fn)) < 0) {
+ z = -1;
+ break;
+ }
+ }
+ goto xxlate;
+ }
+#endif /* KANJI */
+
+ /* Regular bytewise conversion... */
+
+ tcs = gettcs(csin,csout); /* Get intermediate set. */
+ if (csin == csout) { /* Input and output sets the same? */
+ sxx = rxx = NULL; /* If so, no translation. */
+ } else { /* Otherwise, set up */
+ if (tcs < 0 || tcs > MAXTCSETS ||
+ csin < 0 || csin > MAXFCSETS ||
+ csout < 0 || csout > MAXFCSETS) {
+ debug(F100,"XLATE csets out of range","",0);
+ sxx = rxx = NULL;
+ } else {
+ sxx = xls[tcs][csin]; /* translation function */
+ rxx = xlr[tcs][csout]; /* pointers. */
+ if (rxx == zl1as) rxx = xl1as;
+ }
+ }
+ while ((c = zminchar()) != -1) { /* Loop for all characters in file */
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ z = 0;
+ break;
+ }
+ if (sxx) c = (*sxx)((CHAR)c); /* From fcs1 to tcs */
+ if (rxx) c = (*rxx)((CHAR)c); /* from tcs to fcs2 */
+ if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
+ z = -1;
+ break;
+ }
+ }
+ goto xxlate; /* Done. */
+
+#else /* UNICODE */
+/*
+ Use Unicode as the intermediate character set. It's simple and gives
+ little or no loss, but the overhead is a bit higher.
+*/
+ initxlate(csin,csout); /* Set up translation functions */
+
+ if (xlatype == XLA_NONE) {
+ while ((c = zminchar()) != -1) { /* Loop for all characters in file */
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ z = 0;
+ break;
+ }
+ if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
+ z = -1;
+ break;
+ }
+ }
+ goto xxlate; /* Done. */
+ }
+
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (csout == FC_UCS2 && /* we're translating to UCS-2 */
+ filecode == ZCTERM && /* for the real screen... */
+ !k95stdout && !inserver
+ ) {
+ union {
+ USHORT ucs2;
+ UCHAR bytes[2];
+ } output;
+
+ while (1) { /* In this case we go two-by-two. */
+ if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
+ break;
+ output.bytes[0] = c;
+ if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
+ break;
+ output.bytes[1] = c;
+
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ z = 0;
+ break;
+ }
+
+ VscrnWrtUCS2StrAtt(VCMD,
+ &output.ucs2,
+ 1,
+ wherey[VCMD],
+ wherex[VCMD],
+ &colorcmd
+ );
+ }
+ } else
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ /* General case: Get next byte translated from fcs to UCS-2 */
+
+#ifdef COMMENT
+ while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1 &&
+ (c2 = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
+ extern int fileorder;
+
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ z = 0;
+ break;
+ }
+ debug(F001,"XLATE c","",c);
+ debug(F001,"XLATE c2","",c2);
+
+ /* And then send UCS-2 byte to translate-and-output machine */
+
+ if ((x = xpnbyte(fileorder?c2:c,TC_UCS2,csout,fn)) < 0) {
+ z = -1;
+ break;
+ }
+ if ((x = xpnbyte(fileorder?c:c2,TC_UCS2,csout,fn)) < 0) {
+ z = -1;
+ break;
+ }
+ }
+#else
+ while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
+ if (tr_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ z = 0;
+ break;
+ }
+ if ((x = xpnbyte(c,TC_UCS2,csout,fn)) < 0) {
+ z = -1;
+ break;
+ }
+ }
+#endif /* COMMENT */
+
+#endif /* UNICODE */
+
+ xxlate: /* Common exit point */
+
+#ifndef AMIGA
+#ifndef MAC
+ signal(SIGINT,oldsig); /* Put old signal action back. */
+#endif /* MAC */
+#endif /* AMIGA */
+ tr_int = 0;
+ if (z < 0) {
+ if (z == -1)
+ printf("?File output error: %s\n",ck_errstr());
+ z = 0;
+ }
+ zclose(ZIFILE); /* Close files */
+ zclose(filecode); /* ... */
+ return(success = z); /* and return status. */
+}
+
+int
+doxlate() {
+#ifdef OS2ONLY
+ extern int tt_font;
+#endif /* OS2ONLY */
+#ifdef UNIX
+ extern char ** mtchs; /* zxpand() file list */
+#endif /* UNIX */
+ int x, y, incs, outcs, multiple = 0, wild = 0, fc = 0, len = 0;
+ int ofisdir = 0;
+ char * s, * tocs = "";
+
+ if ((x = cmifi("File(s) to translate","",&s,&wild,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of an existing file\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Save copy of string just parsed. */
+
+ if ((incs = cmkey(fcstab,nfilc,"from character-set","",xxstring)) < 0)
+ return(incs);
+
+#ifdef OS2
+ if (isunicode())
+ tocs = "ucs2";
+ else
+#endif /* OS2 */
+ tocs = getdcset();
+
+ if ((outcs = cmkey(fcstab,nfilc,"to character-set",tocs,xxstring)) < 0)
+ return(outcs);
+ if ((x = cmofi("output file",CTTNAM,&s,xxstring)) < 0) return(x);
+ if (x > 1)
+ ofisdir = 1;
+
+ len = ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
+
+ if (len < 1)
+ return(-2);
+
+ if (ofisdir)
+ multiple = 2;
+ else if (wild) {
+ if (isdir(tmpbuf))
+ multiple = 2;
+ else if (!strcmp(tmpbuf,CTTNAM))
+ multiple = 1;
+#ifdef OS2
+ else if (!stricmp(tmpbuf,"con") || !stricmp(tmpbuf,"con:"))
+ multiple = 1;
+#else
+#ifdef UNIXOROSK
+ else if (!strncmp(tmpbuf,"/dev/",4))
+ multiple = 1;
+#endif /* UNIXOROSK */
+#endif /* OS2 */
+ if (!multiple) {
+ printf("?A single file please\n");
+ return(-9);
+ }
+ }
+ if (!multiple) { /* Just one file */
+ return(success = xlate(line,tmpbuf,incs,outcs));
+ } else { /* Translate multiple files */
+ char dirbuf[CKMAXPATH+4];
+ int k;
+#ifndef ZXREWIND
+ int flags = ZX_FILONLY;
+#endif /* ZXREWIND */
+
+ if (multiple == 2) { /* Target is a directory */
+ k = ckstrncpy(dirbuf,tmpbuf,CKMAXPATH+1) - 1;
+ if (k < 0)
+ return(-2);
+#ifdef OS2ORUNIX
+ if (dirbuf[k] != '/') {
+ dirbuf[k+1] = '/';
+ dirbuf[k+2] = NUL;
+ }
+#else
+#ifdef OSK
+ if (dirbuf[k] != '/') {
+ dirbuf[k+1] = '/';
+ dirbuf[k+2] = NUL;
+ }
+#else
+#ifdef VMS
+ if (ckmatch("*.DIR;1",s,0,0))
+ k = cvtdir(tmpbuf,dirbuf,TMPBUFSIZ);
+ if (dirbuf[k] != ']' &&
+ dirbuf[k] != '>' &&
+ dirbuf[k] != ':')
+ return(-2);
+#else
+#ifdef datageneral
+ if (dirbuf[k] != ':') {
+ dirbuf[k+1] = ':';
+ dirbuf[k+2] = NUL;
+ }
+#else
+#ifdef STRATUS
+ if (dirbuf[k] != '>') {
+ dirbuf[k+1] = '>';
+ dirbuf[k+2] = NUL;
+ }
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* OSK */
+#endif /* OS2ORUNIX */
+ }
+
+#ifdef ZXREWIND
+ fc = zxrewind(); /* Rewind the file list */
+#else
+ if (matchdot) flags |= ZX_MATCHDOT;
+ fc = nzxpand(line,flags);
+#endif /* ZXREWIND */
+
+ if (fc < 1) {
+ printf("?Wildcard expansion error\n");
+ return(-9);
+ }
+#ifdef UNIX
+ sh_sort(mtchs,NULL,fc,0,0,filecase); /* Sort the file list */
+#endif /* UNIX */
+
+ while (1) { /* Loop through the files */
+ znext(line);
+ if (!line[0])
+ break;
+ if (multiple == 2)
+ ckmakmsg(tmpbuf,TMPBUFSIZ,dirbuf,line,NULL,NULL);
+ if (xlate(line,tmpbuf,incs,outcs) < 1)
+ return(success = 0);
+ }
+ }
+ return(success = 1);
+}
+#endif /* NOCSETS */
+
+static char hompthbuf[CKMAXPATH+1];
+
+char *
+homepath() {
+ int x;
+ extern char * myhome;
+ char * h;
+
+ h = myhome ? myhome : zhome();
+ hompthbuf[0] = NUL;
+#ifdef UNIXOROSK
+ x = ckstrncpy(hompthbuf,h,CKMAXPATH+1);
+ if (x <= 0) {
+ hompthbuf[0] = '/';
+ hompthbuf[1] = NUL;
+ } else if (x < CKMAXPATH - 2 && hompthbuf[x-1] != '/') {
+ hompthbuf[x] = '/';
+ hompthbuf[x+1] = NUL;
+ }
+ return(hompthbuf);
+#else
+#ifdef STRATUS
+ if (strlen(h) < CKMAXPATH)
+ sprintf(hompthbuf,"%s>",h); /* SAFE */
+ return(hompthbuf);
+#else
+ return(h);
+#endif /* STRATUS */
+#endif /* UNIXOROSK */
+}
+
+/* D O L O G -- Do the log command */
+
+int
+dolog(x) int x; {
+ int y, disp; char *s = NULL, * p = NULL, * q = NULL;
+ extern int isguest;
+#ifdef ZFNQFP
+ struct zfnfp * fnp;
+#endif /* ZFNQFP */
+
+ if (isguest) {
+ printf("?Anonymous log creation not allowed\n");
+ return(-9);
+ }
+ switch (x) { /* Which log... */
+
+#ifdef DEBUG
+ case LOGD:
+ q = "debug.log";
+ y = cmofi("Name of debugging log file",q,&s,xxstring);
+ break;
+#endif /* DEBUG */
+
+ case LOGP:
+ q = "packet.log";
+ y = cmofi("Name of packet log file",q,&s,xxstring);
+ break;
+
+#ifndef NOLOCAL
+ case LOGS:
+ q = "session.log";
+ y = cmofi("Name of session log file",q,&s,xxstring);
+ break;
+#endif /* NOLOCAL */
+
+#ifdef TLOG
+ case LOGT:
+ q = "transact.log";
+ y = cmofi("Name of transaction log file",q,&s,xxstring);
+ break;
+#endif /* TLOG */
+
+#ifdef CKLOGDIAL
+ case LOGM: {
+ int m, n;
+ char mypath[CKMAXPATH+1];
+ q = CXLOGFILE;
+ m = ckstrncpy(mypath,homepath(),CKMAXPATH);
+ n = strlen(CXLOGFILE);
+ if (m + n < CKMAXPATH)
+ ckstrncat(mypath,CXLOGFILE,CKMAXPATH);
+ else
+ ckstrncpy(mypath,CXLOGFILE,CKMAXPATH);
+ y = cmofi("Name of connection log file",mypath,&s,xxstring);
+ break;
+ }
+#endif /* CKLOGDIAL */
+
+ default:
+ printf("\n?Unknown log designator - %d\n",x);
+ return(-2);
+ }
+ if (y < 0) return(y);
+ if (y == 2) { /* If they gave a directory name */
+ int k;
+ char * ds = "/";
+ k = strlen(s);
+ if (k > 0 && s[k-1] == '/') ds = "";
+ ckmakmsg(tmpbuf,TMPBUFSIZ,s,ds,q,NULL);
+ s = tmpbuf;
+ }
+#ifdef ZFNQFP
+#ifdef OS2ORUNIX
+ if (*s != '|') /* Allow for pipes */
+#else
+#ifdef OSK
+ if (*s != '|')
+#endif /* OSK */
+#endif /* OS2ORUNIX */
+ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
+ if (fnp->fpath)
+ if ((int) strlen(fnp->fpath) > 0)
+ s = fnp->fpath;
+ } /* else if error keep original string */
+#endif /* ZFNQFP */
+
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+#ifdef MAC
+ y = 0;
+#else
+
+ p = "new";
+#ifdef TLOG
+ if ((x == LOGT && tlogfmt == 2) || x == LOGM)
+ p = "append";
+#endif /* TLOG */
+
+ if ((y = cmkey(disptb,2,"Disposition",p,xxstring)) < 0)
+ return(y);
+#endif /* MAC */
+ disp = y;
+ if ((y = cmcfm()) < 0) return(y);
+
+ switch (x) {
+
+#ifdef DEBUG
+ case LOGD:
+ return(deblog = debopn(s,disp));
+#endif /* DEBUG */
+
+#ifndef NOXFER
+ case LOGP:
+ return(pktlog = pktopn(s,disp));
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ case LOGS:
+ setseslog(sesopn(s,disp));
+ return(seslog);
+#endif /* NOLOCAL */
+
+#ifdef TLOG
+ case LOGT:
+ return(tralog = traopn(s,disp));
+#endif /* TLOG */
+
+#ifdef CKLOGDIAL
+ case LOGM:
+ return(dialog = diaopn(s,disp,0));
+#endif /* CKLOGDIAL */
+
+ default:
+ return(-2);
+ }
+}
+
+#ifndef NOXFER
+int
+pktopn(s,disp) char *s; int disp; {
+ static struct filinfo xx;
+
+ if (!s)
+ s = "";
+ if (!*s)
+ return(0);
+
+ debug(F111,"pktopn",s,disp);
+
+ zclose(ZPFILE);
+
+#ifdef OS2ORUNIX
+ if (s[0] == '|') { /* Pipe */
+ char * p = s + 1;
+ debug(F110,"pktopn p",p,0);
+ while (*p) {
+ if (*p != ' ')
+ break;
+ else
+ p++;
+ }
+ debug(F110,"pktopn pipe",p,0);
+ pktlog = zxcmd(ZPFILE,p);
+ debug(F101,"pktopn seslog","",seslog);
+ } else { /* File */
+#endif /* OS2ORUNIX */
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ pktlog = zopeno(ZPFILE,s,NULL,&xx);
+ } else pktlog = zopeno(ZPFILE,s,NULL,NULL);
+ if (!pktlog && !quiet)
+ printf("?%s - %s\n",s,ck_errstr());
+#ifdef OS2ORUNIX
+ }
+#endif /* OS2ORUNIX */
+ if (pktlog > 0)
+ ckstrncpy(pktfil,s,CKMAXPATH+1);
+ else
+ *pktfil = '\0';
+ return(pktlog);
+}
+#endif /* NOXFER */
+
+int
+traopn(s,disp) char *s; int disp; {
+#ifdef TLOG
+ static struct filinfo xx;
+
+ if (!s)
+ s = "";
+ if (!*s)
+ return(0);
+
+ debug(F111,"traopn",s,disp);
+ debug(F101,"traopn tlogfmt","",tlogfmt);
+
+ zclose(ZTFILE);
+
+#ifdef OS2ORUNIX
+ if (tlogfmt == 2) { /* FTP format is special... */
+ VOID doiklog();
+ if (!disp) /* Append? */
+ if (zchki(s) > -1) /* No - does file exist? */
+ (VOID) zdelet(s); /* Yes - delete it. */
+ xferlog = 1;
+ ckstrncpy(trafil,s,CKMAXPATH);
+ makestr(&xferfile,s);
+ doiklog();
+ return(1);
+ }
+ if (s[0] == '|') { /* Pipe */
+ char * p = s + 1;
+ debug(F110,"traopn p",p,0);
+ while (*p) {
+ if (*p != ' ')
+ break;
+ else
+ p++;
+ }
+ debug(F110,"traopn pipe",p,0);
+ tralog = zxcmd(ZTFILE,p);
+ debug(F101,"traopn tralog","",tralog);
+ }
+#endif /* OS2ORUNIX */
+
+ if (s[0] != '|') { /* File */
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ tralog = zopeno(ZTFILE,s,NULL,&xx);
+ } else tralog = zopeno(ZTFILE,s,NULL,NULL);
+ }
+ if (!tralog && !quiet)
+ printf("?%s - %s\n",s,ck_errstr());
+ if (tralog > 0 && tlogfmt > 0) {
+ ckstrncpy(trafil,s,CKMAXPATH);
+ tlog(F110,"Transaction Log:",versio,0L);
+#ifndef MAC
+ tlog(F100,ckxsys,"",0L);
+#endif /* MAC */
+ ztime(&s);
+ tlog(F100,s,"",0L);
+ } else
+ *trafil = '\0';
+ return(tralog);
+#else
+ return(0);
+#endif /* TLOG */
+}
+
+#ifndef NOLOCAL
+int
+sesopn(s,disp) char * s; int disp; {
+ static struct filinfo xx;
+ extern int tsstate;
+
+ tsstate = 0; /* Session log timestamp state */
+
+ if (!s)
+ s = "";
+ if (!*s)
+ return(0);
+
+ debug(F111,"sesopn",s,disp);
+
+ zclose(ZSFILE);
+
+#ifdef OS2ORUNIX
+ if (s[0] == '|') { /* Pipe */
+ char * p = s + 1;
+ debug(F110,"sesopn p",p,0);
+ while (*p) {
+ if (*p != ' ')
+ break;
+ else
+ p++;
+ }
+ debug(F110,"sesopn pipe",p,0);
+ setseslog(zxcmd(ZSFILE,p));
+ debug(F101,"sesopn seslog","",seslog);
+ } else { /* File */
+#endif /* OS2ORUNIX */
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ setseslog(zopeno(ZSFILE,s,NULL,&xx));
+ } else
+ setseslog(zopeno(ZSFILE,s,NULL,NULL));
+ if (!seslog && !quiet)
+ printf("?%s - %s\n",s,ck_errstr());
+#ifdef OS2ORUNIX
+ }
+#endif /* OS2ORUNIX */
+ if (seslog > 0)
+ ckstrncpy(sesfil,s,CKMAXPATH+1);
+ else
+ *sesfil = '\0';
+ return(seslog);
+}
+#endif /* NOLOCAL */
+#endif /* NOICP */
+
+int
+debopn(s,disp) char *s; int disp; {
+#ifdef DEBUG
+#ifdef CK_UTSNAME
+ extern char unm_mch[], unm_nam[], unm_rel[], unm_ver[], unm_mod[];
+#endif /* CK_UTSNAME */
+#ifdef OS2
+ extern char ckxsystem[];
+#endif /* OS2 */
+ char *tp;
+ static struct filinfo xx;
+
+ if (!s)
+ s = "";
+ if (!*s)
+ return(0);
+
+ zclose(ZDFILE);
+
+#ifdef OS2ORUNIX
+ if (s[0] == '|') { /* Pipe */
+ char * p = s + 1;
+ debug(F110,"debopn p",p,0);
+ while (*p) {
+ if (*p != ' ')
+ break;
+ else
+ p++;
+ }
+ debug(F110,"debopn pipe",p,0);
+ deblog = zxcmd(ZDFILE,p);
+ debug(F101,"debopn deblog","",deblog);
+ } else { /* File */
+#endif /* OS2ORUNIX */
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ deblog = zopeno(ZDFILE,s,NULL,&xx);
+ } else
+ deblog = zopeno(ZDFILE,s,NULL,NULL);
+ if (!deblog && !quiet)
+ printf("?%s - %s\n",s,ck_errstr());
+#ifdef OS2ORUNIX
+ }
+#endif /* OS2ORUNIX */
+ if (deblog > 0) {
+ ckstrncpy(debfil,s,CKMAXPATH+1);
+ debug(F110,"Debug Log ",versio,0);
+#ifndef MAC
+#ifdef OS2
+ debug(F110,ckxsys,ckxsystem,0);
+#else /* OS2 */
+ debug(F100,ckxsys,"",0);
+#endif /* OS2 */
+#endif /* MAC */
+#ifdef CK_UTSNAME
+ if (unm_mch[0]) {
+ debug(F110,"uname machine",unm_mch,0);
+ if (unm_mod[0])
+ debug(F110,"uname model ",unm_mod,0);
+ debug(F110,"uname sysname",unm_nam,0);
+ debug(F110,"uname release",unm_rel,0);
+ debug(F110,"uname version",unm_ver,0);
+ }
+#ifdef KTARGET
+ {
+ char * s; /* Makefile target */
+ s = KTARGET;
+ if (!s) s = "";
+ if (!*s) s = "(unknown)";
+ debug(F110,"build target",s,0);
+ }
+#endif /* KTARGET */
+ deblog = 0;
+ ztime(&tp);
+ deblog = 1;
+ debug(F100,tp,"",0);
+#endif /* UTSNAME */
+ debug(F101,"byteorder","",byteorder);
+#ifndef NOICP
+#ifndef NOLOCAL
+ if (local) {
+ debug(F110,"Active connection: ",ttname,0);
+ if (!network) {
+ debug(F101,"Speed","",speed);
+ if (hwparity)
+ debug(F110,"Parity[hardware]",parnam((char)hwparity),0);
+ else
+ debug(F110,"Parity",parnam((char)parity),0);
+ deblog = 0;
+ debug(F110,"Modem",gmdmtyp(),0);
+ deblog = 1;
+ }
+ } else {
+ debug(F110,"Active connection: ","none",0);
+ }
+#endif /* NOLOCAL */
+#endif /* NOICP */
+ } else *debfil = '\0';
+ return(deblog);
+#else
+ return(0);
+#endif /* MAC */
+}
+
+
+/* C K D A T E -- Returns current date/time in standard format */
+
+static char nowbuf[18];
+
+char *
+ckdate() {
+ extern struct keytab cmonths[];
+ int x;
+ char * t; /* Substitute today's date */
+ char dbuf[32];
+ ztime(&t);
+
+/* 012345678901234567890123 */
+/* Sat Jul 4 12:16:43 1998 */
+
+ ckstrncpy(dbuf,t,32);
+ t = dbuf;
+ debug(F110,"ckdate dbuf",dbuf,0);
+ nowbuf[0] = t[20];
+ nowbuf[1] = t[21];
+ nowbuf[2] = t[22];
+ nowbuf[3] = t[23];
+
+ nowbuf[4] = NUL;
+ debug(F110,"ckdate nowbuf",nowbuf,0);
+
+ t[7] = NUL;
+ if ((x = lookup(cmonths,t+4,12,NULL)) < 0) {
+ debug(F110,"ckdate bad month",t,0);
+ return("<BAD_MONTH>");
+ }
+ sprintf(nowbuf+4,"%02d",x); /* SAFE */
+ nowbuf[6] = (t[8] == SP) ? '0' : t[8];
+ nowbuf[7] = t[9];
+ nowbuf[8] = ' ';
+
+ nowbuf[9] = NUL;
+ debug(F110,"ckdate nowbuf",nowbuf,0);
+
+ for (x = 11; x < 19; x++) nowbuf[x-2] = t[x];
+ nowbuf[17] = NUL;
+ debug(F110,"ckdate nowbuf",nowbuf,0);
+
+ return((char *)nowbuf);
+}
+
+#ifndef NOICP
+#ifdef CKLOGDIAL
+
+/*
+ fc = 0 for initial open, meaning open, then close immediately.
+ fc > 0 for subsequent opens, meaning open for use, leave open.
+*/
+int
+diaopn(s,disp,fc) char *s; int disp, fc; {
+ static struct filinfo xx;
+
+ if (!s)
+ s = "";
+ if (!*s)
+ return(0);
+
+ debug(F110,"diaopn log",s,0);
+ debug(F101,"diaopn fc",s,fc);
+ debug(F101,"diaopn disp 1",s,disp);
+ if (fc) disp = 1; /* Force append if open for use */
+ debug(F101,"diaopn disp 2",s,disp);
+
+ zclose(ZDIFIL); /* In case a log was already open */
+
+#ifdef OS2ORUNIX
+ if (s[0] == '|') { /* Pipe */
+ char * p = s + 1;
+ debug(F110,"diaopn p",p,0);
+ while (*p) {
+ if (*p != ' ')
+ break;
+ else
+ p++;
+ }
+ debug(F110,"diaopn pipe",p,0);
+ dialog = zxcmd(ZDIFIL,p);
+ debug(F101,"diaopn dialog","",dialog);
+ } else { /* File */
+#endif /* OS2ORUNIX */
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ dialog = zopeno(ZDIFIL,s,NULL,&xx);
+ } else dialog = zopeno(ZDIFIL,s,NULL,NULL);
+ if (!dialog)
+ printf("?%s - %s\n",s,ck_errstr());
+#ifdef OS2ORUNIX
+ }
+#endif /* OS2ORUNIX */
+ if (dialog > 0)
+ ckstrncpy(diafil,s,CKMAXPATH+1);
+ else
+ *diafil = '\0';
+ if (fc == 0) /* Initial open */
+ zclose(ZDIFIL); /* close it */
+ return(dialog);
+}
+#endif /* CKLOGDIAL */
+
+#ifndef NOSHOW
+
+/* SHOW command routines */
+
+char *
+shoxm() {
+ char * s;
+ switch (binary) {
+ case XYFT_T: s = "text"; break;
+#ifdef VMS
+ case XYFT_B: s = "binary fixed"; break;
+ case XYFT_I: s = "image"; break;
+ case XYFT_L: s = "labeled"; break;
+ case XYFT_U: s = "binary undef"; break;
+#else
+#ifdef MAC
+ case XYFT_B: s = "binary"; break;
+ case XYFT_M: s = "macbinary"; break;
+#else
+ case XYFT_B: s = "binary"; break;
+#ifdef CK_LABELED
+ case XYFT_L: s = "labeled"; break;
+#endif /* CK_LABELED */
+#endif /* MAC */
+#endif /* VMS */
+ default: s = "unknown"; break;
+ }
+ return(s);
+}
+
+#ifndef NOXFER
+VOID /* SHOW TRANSFER */
+shoxfer() {
+ extern int docrc, usepipes, xfrxla, whereflg;
+ extern char * xfrmsg;
+ printf("\n");
+ printf(" Transfer Bell: %s\n",showoff(xfrbel));
+ printf(" Transfer Interruption: %s\n",showoff(xfrint));
+ printf(" Transfer Cancellation: %s\n",showoff(xfrcan));
+#ifndef NOCSETS
+ printf(" Transfer Translation: %s\n",showoff(xfrxla));
+ printf(" Transfer Character-set: ");
+ if (tcharset == TC_TRANSP)
+ printf("Transparent\n");
+ else
+ printf("%s\n",tcsinfo[tcharset].keyword);
+#endif /* NOCSETS */
+ printf(" Transfer CRC-calculation: %s\n",showoff(docrc));
+ printf(" Transfer Display: ");
+ switch (fdispla) {
+ case XYFD_N: printf("%s\n","none"); break;
+ case XYFD_R: printf("%s\n","serial"); break;
+ case XYFD_C: printf("%s\n","fullscreen"); break;
+ case XYFD_S: printf("%s\n","crt"); break;
+ case XYFD_B: printf("%s\n","brief"); break;
+ case XYFD_G: printf("%s\n","gui"); break;
+ }
+ printf(" Transfer Message: %s\n", xfrmsg ? xfrmsg : "(none)");
+ printf(" Transfer Locking-shift: ");
+ if (lscapu == 2) {
+ printf("forced");
+ } else {
+ printf("%s", (lscapr ? "enabled" : "disabled"));
+ if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
+ }
+ printf("\n Transfer Mode: %s\n",
+ xfermode == XMODE_A ?
+ "automatic" :
+ "manual"
+ );
+ printf(" Transfer Pipes: %s\n", showoff(usepipes));
+ printf(" Transfer Protocol: %s\n",ptab[protocol].p_name);
+ printf(" Transfer Report: %s\n",showoff(whereflg));
+ printf(" Transfer Slow-start: %s\n",showoff(slostart));
+ printf("\n");
+}
+#endif /* NOXFER */
+
+VOID
+shoflow() {
+ int i, x;
+ extern int cxflow[], cxtype, ncxname, nfloname, autoflow;
+ extern char * cxname[];
+ printf("\nConnection type: %s\n",cxname[cxtype]);
+ if (autoflow) {
+ printf("Current flow-control: %s\n", floname[cxflow[cxtype]]);
+ printf("Switches automatically: yes\n");
+ } else {
+ printf("Current flow-control: %s\n", floname[flow]);
+ printf("Switches automatically: no\n");
+ }
+ printf("\nDefaults by connection type:\n");
+ debug(F111,"shoflow cxtype",cxname[cxtype],cxtype);
+ debug(F101,"shoflow flow","",flow);
+ for (i = 0; i < ncxname; i++) {
+#ifdef NOLOCAL
+ if (i > 0) break;
+#endif /* NOLOCAL */
+#ifndef NETCONN
+ if (i > 2) break;
+#endif /* NETCONN */
+#ifndef DECNET
+ if (i == CXT_DECNET) continue;
+#endif /* DECNET */
+#ifndef DECNET
+#ifndef SUPERLAT
+ if (i == CXT_LAT) continue;
+#endif /* SUPERLAT */
+#endif /* DECNET */
+#ifndef CK_NETBIOS
+ if (i == CXT_NETBIOS) continue;
+#endif /* CK_NETBIOS */
+#ifndef NPIPE
+ if (i == CXT_NPIPE) continue;
+#endif /* NPIPE */
+#ifndef NETCMD
+ if (i == CXT_PIPE) continue;
+#endif /* NETCMD */
+#ifndef ANYX25
+ if (i == CXT_X25) continue;
+#endif /* ANYX25 */
+ x = cxflow[i];
+ debug(F101,"shoflow x","",x);
+ if (x < nfloname)
+ printf(" %-14s: %s\n",cxname[i],floname[x]);
+ else
+ printf(" %-14s: (%d)\n",cxname[i],x);
+ }
+ printf("\n");
+}
+
+#ifndef NOLOCAL
+#ifdef ANYX25
+int
+shox25(n) int n; {
+ if (nettype == NET_SX25) {
+ printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
+ if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Reverse charge call %s",
+ revcall ? "selected" : "not selected");
+ printf (", Closed user group ");
+ if (closgr > -1)
+ printf ("%d",closgr);
+ else
+ printf ("not selected");
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Call user data %s.\n", cudata ? udata : "not selected");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ } else if (nettype == NET_VX25) {
+ if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Reverse charge call %s",
+ revcall ? "selected" : "not selected");
+ printf (", Closed user group [unsupported]");
+ if (closgr > -1)
+ printf ("%d",closgr);
+ else
+ printf ("not selected");
+ printf (",");
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Call user data %s.\n", cudata ? udata : "not selected");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ } else if (nettype == NET_IX25) {
+ printf("AIX NPI X.25\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf("\n Reverse charge call %s",
+ revcall ? "selected" : "not selected");
+ printf (", Closed user group [unsupported]");
+ if (closgr > -1)
+ printf ("%d",closgr);
+ else
+ printf ("not selected");
+ printf (",");
+ printf("\n Call user data %s.\n", cudata ? udata : "not selected");
+ }
+ return(n);
+}
+
+#ifndef IBMX25
+int
+shopad(n) int n; {
+ int i;
+ printf("\nX.3 PAD Parameters:\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ for (i = 0; i < npadx3; i++) {
+ printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
+ padparms[padx3tab[i].kwval]);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ }
+ return(n);
+}
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+VOID
+shoparc() {
+ extern int reliable, stopbits, clsondisc;
+ int i; char *s;
+ long zz;
+
+#ifdef NEWFTP
+ if (ftpisconnected()) {
+ shoftp(1);
+ printf("\n");
+ }
+#endif /* NEWFTP */
+
+ printf("Communications Parameters:\n");
+
+ if (network
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) {
+ printf(" Network Host: %s%s",ttname,
+ (reliable == SET_ON || (reliable == SET_AUTO && !local)
+#ifdef TN_COMPORT
+ && !istncomport()
+#endif /* TN_COMPORT */
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) ? " (reliable)" : "");
+#ifdef TN_COMPORT
+ if (istncomport()) {
+ int modemstate;
+ char * oflow, * iflow = "", * parity, * stopsize, * signature;
+ int baud = tnc_get_baud();
+
+ switch (tnc_get_oflow()) {
+ case TNC_CTL_OFLOW_NONE:
+ oflow = "none";
+ break;
+ case TNC_CTL_OFLOW_XON_XOFF:
+ oflow = "xon/xoff";
+ break;
+ case TNC_CTL_OFLOW_RTS_CTS:
+ oflow = "rts/cts";
+ break;
+ case TNC_CTL_OFLOW_DCD:
+ oflow = "dcd";
+ break;
+ case TNC_CTL_OFLOW_DSR:
+ oflow = "dsr";
+ break;
+ default:
+ oflow = "(unknown)";
+ }
+ switch (tnc_get_iflow()) {
+ case TNC_CTL_IFLOW_NONE:
+ iflow = "none";
+ break;
+ case TNC_CTL_IFLOW_XON_XOFF:
+ iflow = "xon/xoff";
+ break;
+ case TNC_CTL_IFLOW_RTS_CTS:
+ iflow = "rts/cts";
+ break;
+ case TNC_CTL_IFLOW_DTR:
+ break;
+ default:
+ iflow = oflow;
+ }
+ switch (tnc_get_parity()) {
+ case TNC_PAR_NONE:
+ parity = "none";
+ break;
+ case TNC_PAR_ODD:
+ parity = "odd";
+ break;
+ case TNC_PAR_EVEN:
+ parity = "even";
+ break;
+ case TNC_PAR_MARK:
+ parity = "mark";
+ break;
+ case TNC_PAR_SPACE:
+ parity = "space";
+ break;
+ default:
+ parity = "(unknown)";
+ }
+ switch (tnc_get_stopsize()) {
+ case TNC_SB_1:
+ stopsize = "1";
+ break;
+ case TNC_SB_1_5:
+ stopsize = "1.5";
+ break;
+ case TNC_SB_2:
+ stopsize = "2";
+ break;
+ default:
+ stopsize = "(unknown)";
+ }
+ signature = (char *)tnc_get_signature();
+ printf("\n Signature : %s\n",signature?signature:"");
+ if (baud <= 0)
+ printf(" Speed : (unknown)\n");
+ else
+ printf(" Speed : %d\n", baud);
+ printf(" Outbound Flow Control: %s\n", oflow);
+ printf(" Inbound Flow Control : %s\n", iflow);
+ printf(" Parity : %s\n", parity);
+ printf(" Data Size : %d\n", tnc_get_datasize());
+ printf(" Stop Bits : %s\n", stopsize);
+ printf(" DTR Signal : %d\n", tnc_get_dtr_state());
+ printf(" RTS Signal : %d\n", tnc_get_rts_state());
+ printf(" Modem State:\n");
+ modemstate = tnc_get_ms();
+ if (modemstate & TNC_MS_EDGE_RING)
+ printf(" Trailing Edge Ring Detector On\n");
+ else
+ printf(" Trailing Edge Ring Detector Off\n");
+ if (modemstate & TNC_MS_CTS_SIG)
+ printf(" CTS Signal On\n");
+ else
+ printf(" CTS Signal Off\n");
+ if (modemstate & TNC_MS_DSR_SIG)
+ printf(" DSR Signal On\n");
+ else
+ printf(" DSR Signal Off\n");
+ if (modemstate & TNC_MS_RI_SIG)
+ printf(" Ring Indicator On\n");
+ else
+ printf(" Ring Indicator Off\n");
+ if (modemstate & TNC_MS_RLSD_SIG)
+ printf(" RLSD (CD) Signal On\n");
+ else
+ printf(" RLSD (CD) Signal Off\n");
+ printf("\n");
+ }
+#endif /* TN_COMPORT */
+ } else {
+
+ printf(" %s: %s%s, speed: ",
+#ifdef OS2
+ "Port",
+#else
+ "Line",
+#endif /* OS2 */
+ ttname,
+#ifdef CK_TTYFD
+ (local &&
+#ifdef VMS
+ vmsttyfd() < 0
+#else
+ ttyfd == -1
+#endif /* VMS */
+ ) ?
+ " (closed)" :
+ (reliable == SET_ON ? " (reliable)" : "")
+#else
+ ""
+#endif /* CK_TTYFD */
+ );
+ if (
+#ifdef CK_TTYFD
+#ifdef VMS
+ vmsttyfd() < 0
+#else
+ ttyfd == -1
+#endif /* VMS */
+ ||
+#endif /* CK_TTYFD */
+ (zz = ttgspd()) < 0) {
+ printf("unknown");
+ } else {
+ if (speed == 8880) printf("75/1200");
+ else if (speed == 134) printf("134.5");
+ else printf("%ld",zz);
+ }
+ }
+ if (network
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ )
+ printf("\n Mode: ");
+ else
+ printf(", mode: ");
+ if (local) printf("local"); else printf("remote");
+ if (network == 0
+#ifdef IKSD
+ && !inserver
+#endif/* IKSD */
+ ) {
+#ifdef CK_TAPI
+ if (tttapi && !tapipass )
+ printf(", modem: %s","TAPI");
+ else
+#endif /* CK_TAPI */
+ printf(", modem: %s",gmdmtyp());
+ } else {
+#ifdef NETCONN
+ if (nettype == NET_TCPA) printf(", TCP/IP");
+ if (nettype == NET_TCPB) printf(", TCP/IP");
+ if (nettype == NET_DEC) {
+ if (ttnproto == NP_LAT) printf(", DECnet LAT");
+ else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
+ else printf(", DECnet");
+ }
+ if (nettype == NET_SLAT) printf(", Meridian Technologies' SuperLAT");
+#ifdef NETFILE
+ if (nettype == NET_FILE) printf(", local file");
+#endif /* NETFILE */
+#ifdef NETCMD
+ if (nettype == NET_CMD) printf(", pipe");
+#endif /* NETCMD */
+#ifdef NETPTY
+ if (nettype == NET_PTY) printf(", pseudoterminal");
+#endif /* NETPTY */
+#ifdef NETDLL
+ if (nettype == NET_DLL) printf(", dynamic load library");
+#endif /* NETDLL */
+ if (nettype == NET_PIPE) printf(", Named Pipes");
+#ifdef SSHBUILTIN
+ if (nettype == NET_SSH)
+ printf(", Secure Shell protocol (SECURE)");
+#endif /* SSHBUILTIN */
+#ifdef ANYX25
+ if (shox25(0) < 0) return;
+#endif /* ANYX25 */
+ if (IS_TELNET()) {
+ printf(", telnet protocol");
+ if (0
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+ )
+ printf(" (SECURE)");
+ }
+#ifdef RLOGCODE
+ else if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_K5LOGIN)
+ printf(", rlogin protocol");
+ else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)
+ printf(", rlogin protocol (SECURE)");
+#endif /* RLOGCODE */
+#ifdef CK_KERBEROS
+#ifdef KRB5
+ else if (ttnproto == NP_K5U2U)
+ printf(", Kerberos 5 User to User protocol (SECURE)");
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+#endif /* NETCONN */
+ }
+ printf("\n");
+ if (hwparity && local && !network)
+ s = parnam((char)hwparity);
+ else
+ s = parnam((char)parity);
+ printf(" Parity: %s%s",hwparity ? "hardware " : "", s);
+#ifndef NOLOCAL
+ if (local && !network) {
+ int sb;
+ char c;
+ c = s[0];
+ if (islower(c)) c = toupper(c);
+ sb = stopbits;
+ if (sb < 1) {
+ sb = (speed > 0 && speed <= 110L) ? 2 : 1;
+ printf(", stop-bits: (default)");
+ } else {
+ printf(", stop-bits: %d",sb);
+ }
+ if (hwparity)
+ printf(" (8%c%d)",c,sb);
+ else if (parity)
+ printf(" (7%c%d)",c,sb);
+ else
+ printf(" (8N%d)",sb);
+ printf("\n D");
+ } else
+ printf(", d");
+#endif /* NOLOCAL */
+
+ printf("uplex: %s, ", duplex ? "half" : "full");
+ debug(F101,"shoparp flow","",flow);
+ printf("flow: %s", floname[flow]);
+ printf(", handshake: ");
+ if (turn) printf("%d\n",turnch); else printf("none\n");
+#ifdef COMMENT
+ if (local && !network) { /* SET CARRIER-WATCH */
+#endif /* COMMENT */
+ if (carrier == CAR_OFF) s = "off";
+ else if (carrier == CAR_ON) s = "on";
+ else if (carrier == CAR_AUT) s = "auto";
+ else s = "unknown";
+ printf(" Carrier-watch: %s", s);
+ if (carrier == CAR_ON) {
+ if (cdtimo) printf(", timeout: %d sec", cdtimo);
+ else printf(", timeout: none");
+ }
+#ifdef COMMENT
+ }
+#endif /* COMMENT */
+ printf(", close-on-disconnect: %s\n",showoff(clsondisc));
+
+#ifdef UNIX /* UUCP lockfile, UNIX only */
+ if (local) {
+#ifndef NOUUCP
+ if (!network && haslock && *flfnam)
+ printf(" Lockfile: %s",flfnam);
+#ifndef USETTYLOCK
+ if (!network && haslock && lock2[0])
+ printf("\n Secondary lockfile: %s",lock2);
+#endif /* USETTYLOCK */
+#else
+#ifdef QNX
+ {
+ extern int qnxportlock, qnxopencount();
+ if (local)
+ printf(" Qnx-port-lock: %s, Open count: %d",
+ showoff(qnxportlock),
+ qnxopencount()
+ );
+ else
+ printf(" Qnx-port-lock: %s", showoff(qnxportlock));
+ }
+#endif /* QNX */
+#endif /* NOUUCP */
+ printf("\n");
+ } else {
+ char * s;
+ s = ttglckdir();
+ if (!s) s = "";
+ printf(" Lockfile directory: %s\n", *s ? s : "(none)");
+ }
+#endif /* UNIX */
+#ifndef MACOSX
+ if (!local) {
+ printf(" Typical port device name: %s\n",ttgtpn());
+ }
+#endif /* MACOSX */
+ if (local) {
+ int i;
+ i = parity ? 7 : 8;
+ if (i == 8) i = (cmask == 0177) ? 7 : 8;
+ printf(" Terminal bytesize: %d,",i);
+ printf(" escape character: %d (^%c)\n",escape,ctl(escape));
+ }
+}
+
+int
+shotcp(n) int n; {
+#ifdef TCPSOCKET
+ if (nettype == NET_TCPA || nettype == NET_TCPB) {
+ printf("SET TCP parameters:\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Reverse DNS lookup: %s\n", showooa(tcp_rdns));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+#ifdef CK_DNS_SRV
+ printf(" DNS Service Records lookup: %s\n", showooa(tcp_dns_srv));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* CK_DNS_SRV */
+
+#ifndef NOTCPOPTS
+#ifdef SOL_SOCKET
+#ifdef SO_KEEPALIVE
+ printf(" Keepalive: %s\n", showoff(tcp_keepalive));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SO_KEEPALIVE */
+
+#ifdef SO_LINGER
+ printf(" Linger: %s", tcp_linger ? "on, " : "off\n" );
+ if (tcp_linger) {
+ if (tcp_linger_tmo)
+ printf("%d x 10 milliseconds\n",tcp_linger_tmo);
+ else
+ printf("no timeout\n");
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SO_LINGER */
+
+#ifdef SO_DONTROUTE
+ printf(" DontRoute: %s\n", tcp_dontroute ? "on" : "off" );
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SO_DONTROUTE */
+
+#ifdef TCP_NODELAY
+ printf(" Nodelay: %s\n", showoff(tcp_nodelay));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* TCP_NODELAY */
+
+#ifdef SO_SNDBUF
+ if (tcp_sendbuf <= 0)
+ printf(" Send buffer: (default size)\n");
+ else
+ printf(" Send buffer: %d bytes\n", tcp_sendbuf);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ if (tcp_recvbuf <= 0)
+ printf(" Receive buffer: (default size)\n");
+ else
+ printf(" Receive buffer: %d bytes\n", tcp_recvbuf);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SO_RCVBUF */
+#endif /* SOL_SOCKET */
+#endif /* NOTCPOPTS */
+ printf(" address: %s\n",tcp_address ? tcp_address : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#ifndef NOHTTP
+ printf(" http-proxy: %s\n",tcp_http_proxy ? tcp_http_proxy : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#endif /* NOHTTP */
+#ifdef NT
+#ifdef CK_SOCKS
+ printf(" socks-server: %s\n",tcp_socks_svr ? tcp_socks_svr : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#ifdef CK_SOCKS_NS
+ printf(" socks-name-server: %s\n",
+ tcp_socks_ns ? tcp_socks_ns : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#endif /* CK_SOCKS_NS */
+#endif /* CK_SOCKS */
+#endif /* NT */
+ }
+#endif /* TCPSOCKET */
+ return(n);
+}
+
+#ifdef TNCODE
+int
+shotopt(n) int n; {
+ int opt;
+
+ printf("%-21s %12s %12s %12s %12s\n\n",
+ "Telnet Option","Me (client)","U (client)",
+ "Me (server)","U (server)");
+ n += 2;
+ if (n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+
+ for ( opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
+ switch (opt) {
+ case TELOPT_AUTHENTICATION:
+ case TELOPT_ENCRYPTION:
+ case TELOPT_TTYPE:
+ case TELOPT_NAWS:
+ case TELOPT_BINARY:
+ case TELOPT_NEWENVIRON:
+ case TELOPT_SNDLOC:
+ case TELOPT_XDISPLOC:
+ case TELOPT_SGA:
+ case TELOPT_ECHO:
+ case TELOPT_KERMIT:
+ case TELOPT_START_TLS:
+ case TELOPT_FORWARD_X:
+ case TELOPT_COMPORT:
+ break;
+ default:
+ continue;
+ }
+ printf("%03d %-17s ",
+ opt, TELOPT(opt)
+ );
+ printf("%12s %12s ",
+ TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)),
+ TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt))
+ );
+ printf("%12s %12s\n",
+ TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)),
+ TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt))
+ );
+
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ if (sstelnet)
+ printf("%21s %12s %12s %12s %12s\n",
+ "",
+ "",
+ "",
+ (TELOPT_ME(opt)?"WILL":"WONT"),
+ (TELOPT_U(opt)?"DO":"DONT")
+ );
+ else
+ printf("%21s %12s %12s %12s %12s\n",
+ "",
+ (TELOPT_ME(opt)?"WILL":"WONT"),
+ (TELOPT_U(opt)?"DO":"DONT"),
+ "",
+ ""
+ );
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ }
+ return(n);
+}
+
+int
+shotel(n) int n; {
+ extern int tn_duplex;
+#ifdef CK_ENVIRONMENT
+ extern int tn_env_flg;
+ extern char tn_env_acct[];
+ extern char tn_env_job[];
+ extern char tn_env_prnt[];
+ extern char tn_env_sys[];
+ extern char * tn_env_uservar[8][2];
+ int x;
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ extern char * tn_loc;
+#endif /* CK_SNDLOC */
+ printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ",
+ tn_duplex ? "local" : "remote");
+ switch (tn_nlm) {
+ case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
+ case TNL_CRLF: printf("%s\n","on (cr-lf)"); break;
+ case TNL_CR: printf("%s\n","raw (cr)"); break;
+ case TNL_LF: printf("%s\n","(lf)"); break;
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#ifdef CK_AUTHENTICATION
+ {
+ int type = ck_tn_authenticated();
+ printf(" authentication: ");
+ switch (sstelnet ?
+ TELOPT_U_MODE(TELOPT_AUTHENTICATION) :
+ TELOPT_ME_MODE(TELOPT_AUTHENTICATION)
+ ) {
+ case TN_NG_AC: printf( "accepted " ); break;
+ case TN_NG_RF: printf( "refused " ); break;
+ case TN_NG_RQ: printf( "requested"); break;
+ case TN_NG_MU: printf( "required "); break;
+ }
+
+#ifdef CK_SSL
+ if ((ssl_active_flag || tls_active_flag) &&
+ ck_tn_auth_valid() == AUTH_VALID &&
+ (!TELOPT_U(TELOPT_AUTHENTICATION) ||
+ type == AUTHTYPE_NULL ||
+ type == AUTHTYPE_AUTO))
+ printf(" in use: X.509 certificate\n");
+ else
+#endif /* CK_SSL */
+ printf(" in use: %s\n",AUTHTYPE_NAME(type));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ if (forward_flag)
+ printf(" credentials forwarding requested %s\n",
+ forwarded_tickets ? "and completed" :
+ "but not completed");
+ else
+ printf(" credentials forwarding disabled\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ {
+ int i,x;
+ int e_type = ck_tn_encrypting();
+ int d_type = ck_tn_decrypting();
+ char * e_str = NULL, * d_str = NULL;
+ static struct keytab * tnetbl = NULL;
+ static int ntnetbl = 0;
+
+ x = ck_get_crypt_table(&tnetbl,&ntnetbl);
+
+ for (i = 0; i < ntnetbl; i++) {
+ if (e_type == tnetbl[i].kwval)
+ e_str = tnetbl[i].kwd;
+ if (d_type == tnetbl[i].kwval)
+ d_str = tnetbl[i].kwd;
+ }
+ printf(" encryption: ");
+ switch (TELOPT_ME_MODE(TELOPT_ENCRYPTION)) {
+ /* This should be changed to report both ME and U modes */
+ case TN_NG_AC: printf( "accepted " ); break;
+ case TN_NG_RF: printf( "refused " ); break;
+ case TN_NG_RQ: printf( "requested"); break;
+ case TN_NG_MU: printf( "required "); break;
+ }
+ printf(" in use: ");
+ switch ((e_type ? 1 : 0) | (d_type ? 2 : 0)) {
+ case 0:
+ printf("plain text in both directions");
+ break;
+ case 1:
+ printf("%s output, plain text input",e_str);
+ break;
+ case 2:
+ printf("plain text output, %s input",d_str);
+ break;
+ case 3:
+ printf("%s output, %s input",e_str,d_str);
+ break;
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef IKS_OPTION
+ printf(" kermit: ");
+ switch (TELOPT_U_MODE(TELOPT_KERMIT)) {
+ case TN_NG_AC: printf( "u, accepted; " ); break;
+ case TN_NG_RF: printf( "u, refused; " ); break;
+ case TN_NG_RQ: printf( "u, requested; "); break;
+ case TN_NG_MU: printf( "u, required; "); break;
+ }
+ switch (TELOPT_ME_MODE(TELOPT_KERMIT)) {
+ case TN_NG_AC: printf( "me, accepted; " ); break;
+ case TN_NG_RF: printf( "me, refused; " ); break;
+ case TN_NG_RQ: printf( "me, requested; "); break;
+ case TN_NG_MU: printf( "me, required; "); break;
+ }
+ if (TELOPT_U(TELOPT_KERMIT))
+ printf(" u, %s",
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start ?
+ "started" :
+ "stopped"
+ );
+ else
+ printf(" u, n/a");
+ if (TELOPT_ME(TELOPT_KERMIT))
+ printf(" me, %s;",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start ?
+ "started" :
+ "stopped"
+ );
+ else
+ printf(" me, n/a;");
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#endif /* IKS_OPTION */
+ printf(" BINARY newline-mode: ");
+ switch (tn_b_nlm) {
+ case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
+ case TNL_CRLF: printf("%s\n","on (cr-lf)"); break;
+ case TNL_CR: printf("%s\n","raw (cr)"); break;
+ case TNL_LF: printf("%s\n","(lf)"); break;
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" binary-mode: ");
+ switch (TELOPT_U_MODE(TELOPT_BINARY)) {
+ case TN_NG_AC: printf( "u, accepted; " ); break;
+ case TN_NG_RF: printf( "u, refused; " ); break;
+ case TN_NG_RQ: printf( "u, requested; "); break;
+ case TN_NG_MU: printf( "u, required; "); break;
+ }
+ switch (TELOPT_ME_MODE(TELOPT_BINARY)) {
+ case TN_NG_AC: printf( "me, accepted; " ); break ;
+ case TN_NG_RF: printf( "me, refused; " ); break;
+ case TN_NG_RQ: printf( "me, requested; "); break;
+ case TN_NG_MU: printf( "me, required; "); break;
+ }
+ printf("u, %s; me, %s\n",
+ TELOPT_U(TELOPT_BINARY) ? "BINARY" : "NVT",
+ TELOPT_ME(TELOPT_BINARY) ? "BINARY" : "NVT"
+ );
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" binary-transfer-mode: %s\n",showoff(tn_b_xfer));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" bug sb-implies-will-do: %s\n",showoff(tn_sb_bug));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" bug auth-krb5-des: %s\n",showoff(tn_auth_krb5_des_bug));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" terminal-type: ");
+ if (tn_term) {
+ printf("%s\n",tn_term);
+ } else {
+ char *p;
+#ifdef OS2
+ p = (tt_type >= 0 && tt_type <= max_tt) ?
+ tt_info[tt_type].x_name :
+ "UNKNOWN";
+#else
+ p = getenv("TERM");
+#endif /* OS2 */
+ if (p)
+ printf("none (%s will be used)\n",p);
+ else printf("none\n");
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#ifdef CK_ENVIRONMENT
+ printf(" environment: %s\n", showoff(tn_env_flg));
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" ACCOUNT: %s\n",tn_env_acct);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" DISPLAY: %s\n",(char *)tn_get_display() ?
+ (char *)tn_get_display() : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" JOB : %s\n",tn_env_job);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" PRINTER: %s\n",tn_env_prnt);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#ifndef NOSPL
+ printf(" USER : %s\n",uidbuf);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#endif /* NOSPL */
+ printf(" SYSTEM : %s\n",tn_env_sys);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ for (x = 0; x < 8; x++) {
+ if (tn_env_uservar[x][0] && tn_env_uservar[x][1]) {
+ printf(" %-7s: %s\n",tn_env_uservar[x][0],
+ tn_env_uservar[x][1]);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ }
+ }
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_SNDLOC
+ printf(" LOCATION: %s\n", tn_loc ? tn_loc : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#endif /* CK_SNDLOC */
+#ifdef CK_FORWARD_X
+ printf(" .Xauthority-file: %s\n", (char *)XauFileName() ?
+ (char *)XauFileName() : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+#endif /* CK_FORWARD_X */
+ return(n);
+}
+#endif /* TNCODE */
+
+#ifdef CK_NETBIOS
+static int
+shonb(n) int n; {
+ printf("NETBIOS parameters:\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" API : %s\n",
+ NetbeuiAPI ?
+ "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
+ : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Local Name: [%s]\n", NetBiosName);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ printf(" Adapter : %d\n", NetBiosAdapter);
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ if (NetBiosLSN > 0xFF) {
+ printf(" Session : %d\n", NetBiosLSN);
+ } else {
+ printf(" Session : none active\n");
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
+ return(n);
+}
+#endif /* CK_NETBIOS */
+
+#ifndef NONET
+int
+shonet() {
+
+#ifndef NETCONN
+ printf("\nNo networks are supported in this version of C-Kermit\n");
+
+#else
+#ifdef NOLOCAL
+ printf("\nNo networks are supported in this version of C-Kermit\n");
+
+#else /* rest of this routine */
+
+ int i, n = 4;
+
+#ifndef NODIAL
+ if (nnetdir <= 1) {
+ printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)");
+ n++;
+ } else {
+ int i;
+ printf("\nNetwork directories:\n");
+ for (i = 0; i < nnetdir; i++) {
+ printf("%2d. %s\n",i,netdir[i]);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+ }
+#endif /* NODIAL */
+
+#ifdef SSHCMD
+ {
+ extern char * sshcmd;
+ printf("SSH COMMAND: %s\n",sshcmd ? sshcmd : "ssh -e none");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* SSHCMD */
+
+#ifdef OS2
+ printf("\nNetwork availability:\n");
+#else
+ printf("\nSupported networks:\n");
+#endif /* OS2 */
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+#ifdef VMS
+
+#ifdef TCPWARE
+ printf(" Process Software Corporation TCPware for OpenVMS");
+#else
+#ifdef MULTINET
+ printf(" TGV MultiNet TCP/IP");
+#else
+#ifdef WINTCP
+ printf(" WOLLONGONG WIN/TCP");
+#else
+#ifdef DEC_TCPIP
+ {
+ static $DESCRIPTOR(tcp_desc,"_TCP0:");
+ int status;
+ long devclass;
+ static int itmcod = DVI$_DEVCLASS;
+
+#ifdef COMMENT
+ status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
+#else
+ /* Martin Zinser 9/96 */
+ status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass);
+#endif /* COMMENT */
+ if ((status & 1) && (devclass == DC$_SCOM))
+ printf(" Process Software Corporation TCPware for OpenVMS");
+ else
+#ifdef UCX50
+ printf(" DEC TCP/IP Services for (Open)VMS 5.0");
+#else
+ printf(" DEC TCP/IP Services for (Open)VMS");
+#endif /* UCX50 */
+ }
+#else
+#ifdef CMU_TCPIP
+ printf(" CMU-OpenVMS/IP");
+#else
+ printf(" None");
+#endif /* CMU_TCPIP */
+#endif /* DEC_TCPIP */
+#endif /* WINTCP */
+#endif /* MULTINET */
+#endif /* TCPWARE */
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#ifdef TNCODE
+ printf(", TELNET protocol\n\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ n = shotel(n);
+ if (n < 0) return(0);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* TNCODE */
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf("\n");
+ n = shotcp(++n);
+ if (n < 0) return(0);
+#else /* Not VMS */
+
+#ifdef SUNX25
+ printf(" SunLink X.25\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SUNX25 */
+
+#ifdef STRATUSX25
+ printf(" Stratus VOS X.25\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* STRATUSX25 */
+
+#ifdef IBMX25
+ printf(" IBM AIX X.25\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* IBMX25 */
+
+#ifdef HPX25
+ printf(" HP-UX X.25\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* HPX25 */
+
+#ifdef SSHBUILTIN
+ if (ck_ssleay_is_installed())
+ printf(" SSH V1 and V2 protocols\n");
+ else
+ printf(" SSH V1 and V2 protocols - not available\n");
+#endif /* SSHBUILTIN */
+
+#ifdef DECNET
+#ifdef OS2
+#ifdef NT
+ if (dnet_avail)
+ printf(" DECnet, LAT and CTERM protocols\n");
+ else
+ printf(" DECnet, LAT and CTERM protocols - not available\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#else /* NT */
+ if (dnet_avail)
+ printf(" DECnet, LAT protocol\n");
+ else
+ printf(" DECnet, LAT protocol - not available\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* NT */
+#else
+ printf(" DECnet\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* OS2 */
+#endif /* DECNET */
+
+#ifdef NPIPE
+ printf(" Named Pipes\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* NPIPE */
+
+#ifdef CK_NETBIOS
+ if (netbiosAvail)
+ printf(" NETBIOS\n");
+ else
+ printf(" NETBIOS - not available\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* CK_NETBIOS */
+
+#ifdef SUPERLAT
+ if (slat_avail)
+ printf(" SuperLAT\n");
+ else
+ printf(" SuperLAT - not available\n") ;
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* SUPERLAT */
+
+#ifdef TCPSOCKET
+ if (
+#ifdef OS2
+ tcp_avail
+#else
+ 1
+#endif /* OS2 */
+ ) {
+ char ipaddr[16];
+
+ if (getlocalipaddrs(ipaddr,16,0) < 0) {
+#ifdef OS2ONLY
+ printf(" TCP/IP via %s\n", tcpname);
+#else
+ printf(" TCP/IP\n");
+#endif /* OS2ONLY */
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ int i = 1;
+#ifdef OS2ONLY
+ printf(" TCP/IP [%16s] via %s\n", ipaddr, tcpname);
+#else
+ printf(" TCP/IP [%16s]\n",ipaddr);
+#endif /* OS2ONLY */
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ while (getlocalipaddrs(ipaddr,16,i++) >= 0) {
+ printf(" [%16s]\n",ipaddr);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+ }
+ if (nettype == NET_TCPB) {
+ printf("\n");
+ n = shotcp(++n);
+ if (n < 0) return(0);
+#ifdef TNCODE
+ printf("\n");
+ n = shotel(++n);
+ if (n < 0) return(0);
+#endif /* TNCODE */
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#ifdef OS2
+ } else {
+ printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" );
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* OS2 */
+ }
+#endif /* TCPSOCKET */
+
+#ifdef CK_NETBIOS
+ if (netbiosAvail && nettype == NET_BIOS) {
+ printf("\n") ;
+ if ((n = shonb(++n)) < 0) return(0);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* CK_NETBIOS */
+
+#endif /* VMS */
+
+ printf("\nActive network connection:\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ if (network) {
+ printf(" Host: %s",ttname);
+ if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
+ printf(" [%s]",ipaddr);
+ } else
+ printf(" Host: none");
+ printf(", via: ");
+ if (nettype == NET_TCPA || nettype == NET_TCPB)
+ printf("tcp/ip\n");
+ else if (nettype == NET_SX25)
+ printf("SunLink X.25\n");
+ else if (nettype == NET_VX25)
+ printf("Stratus VOS X.25\n");
+ else if (nettype == NET_IX25)
+ printf("IBM AIX X.25\n");
+ else if (nettype == NET_HX25)
+ printf("HP-UX X.25\n");
+ else if (nettype == NET_DEC) {
+ if ( ttnproto == NP_LAT )
+ printf("DECnet LAT\n");
+ else if ( ttnproto == NP_CTERM )
+ printf("DECnet CTERM\n");
+ else
+ printf("DECnet\n");
+ } else if (nettype == NET_PIPE)
+ printf("Named Pipes\n");
+ else if (nettype == NET_BIOS)
+ printf("NetBIOS\n");
+ else if (nettype == NET_SLAT)
+ printf("SuperLAT\n");
+
+#ifdef NETFILE
+ else if ( nettype == NET_FILE )
+ printf("local file\n");
+#endif /* NETFILE */
+#ifdef NETCMD
+ else if ( nettype == NET_CMD )
+ printf("pipe\n");
+#endif /* NETCMD */
+#ifdef NETPTY
+ else if ( nettype == NET_PTY )
+ printf("pseudoterminal\n");
+#endif /* NETPTY */
+#ifdef NETDLL
+ else if ( nettype == NET_DLL )
+ printf("dynamic link library\n");
+#endif /* NETDLL */
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+#ifdef ANYX25
+ if ((nettype == NET_SX25) ||
+ (nettype == NET_VX25) ||
+ (nettype == NET_IX25))
+ if ((n = shox25(n)) < 0) return(0);
+#endif /* ANYX25 */
+
+#ifdef SSHBUILTIN
+ if (nettype == NET_SSH) {
+ printf("Secure Shell protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* SSHBUILTIN */
+
+ if (nettype == NET_TCPA || nettype == NET_TCPB) {
+#ifdef RLOGCODE
+ if (ttnproto == NP_RLOGIN) {
+ printf(" LOGIN (rlogin) protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#ifdef CK_KERBEROS
+ else if (ttnproto == NP_K4LOGIN) {
+ printf(" Kerberos 4 LOGIN (klogin) protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+ else if (ttnproto == NP_EK4LOGIN) {
+ printf(" Encrypted Kerberos 4 LOGIN (eklogin) protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+ else if (ttnproto == NP_K5LOGIN) {
+ printf(" Kerberos 5 LOGIN (klogin) protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+ else if (ttnproto == NP_EK5LOGIN) {
+ printf(" Encrypted Kerberos 5 LOGIN (eklogin) protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+#ifdef CK_KERBEROS
+ if (ttnproto == NP_K5U2U) {
+ printf(" Kerberos 5 User to User protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* CK_KERBEROS */
+
+#ifdef TNCODE
+ if (IS_TELNET()) {
+ printf(" TELNET protocol\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* TNCODE */
+ if (ttnproto == NP_TCPRAW) {
+ printf(" Raw TCP socket\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+ }
+ printf("\n");
+#endif /* NOLOCAL */
+#endif /* NETCONN */
+ return(0);
+}
+#endif /* NONET */
+
+#ifndef NODIAL
+VOID
+shodial() {
+ if (mdmtyp >= 0 || local != 0) doshodial();
+}
+
+VOID
+shods(s) char *s; { /* Show a dial-related string */
+ char c;
+ if (s == NULL || !(*s)) { /* Empty? */
+ printf("(none)\n");
+ } else { /* Not empty. */
+ while ((c = *s++)) /* Can contain controls */
+ if (c == '\\') /* a backslash */
+ printf("\\\\");
+ else if (c > 31 && c < 127) {
+ putchar(c);
+ } else
+ printf("\\{%d}",c);
+ printf("\n");
+ }
+}
+
+int
+doshodial() {
+
+ int i, n = 2;
+
+ printf(" Dial status: %d", dialsta);
+
+#ifdef BIGBUFOK
+ if (dialsta > 90)
+ printf(" = Unknown error");
+ else if (dialsta < 0)
+ printf(" = (none)");
+ else if (dialsta < 35 && dialmsg[dialsta])
+ printf(" = %s", dialmsg[dialsta]);
+#endif /* BIGBUFOK */
+ n++;
+ if (ndialdir <= 1) {
+ printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)");
+ } else {
+ int i;
+ printf("\n Dial directories:\n");
+ for (i = 0; i < ndialdir; i++)
+ printf("%2d. %s\n",i+1,dialdir[i]);
+ n += ndialdir;
+ }
+ printf(" Dial method: ");
+ if (dialmauto) printf("auto ");
+ else if (dialmth == XYDM_D) printf("default");
+ else if (dialmth == XYDM_P) printf("pulse ");
+ else if (dialmth == XYDM_T) printf("tone ");
+ printf(" Dial sort: %s\n",dialsrt ? "on" : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Dial hangup: %s Dial display: %s\n",
+ dialhng ? "on " : "off", dialdpy ? "on" : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (dialrtr > 0) {
+ printf(" Dial retries: %-12d Dial interval: %d\n",
+ dialrtr, dialint);
+ } else {
+ printf(" Dial retries: (auto) Dial interval: %d\n", dialint);
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Dial timeout: ");
+#ifdef CK_TAPI
+ if (tttapi && !tapipass)
+ printf("(tapi)");
+ else
+#endif /* CK_TAPI */
+ if (dialtmo > 0)
+ printf("%4d sec", dialtmo);
+ else
+ printf("0 (auto)");
+ printf(" Redial number: %s\n",dialnum ? dialnum : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Dial confirmation: %s Dial convert-directory: %s\n",
+ dialcnf ? "on " : "off",
+ dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Dial ignore-dialtone: %s", dialidt ? "on " : "off");
+ printf(" Dial pacing: %d\n",dialpace);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial prefix: %s\n", dialnpr ? dialnpr : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial suffix: %s\n", dialsfx ? dialsfx : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial country-code: %-12s", diallcc ? diallcc : "(none)");
+ printf("Dial connect: %s", dialcon ? ((dialcon == 1) ? "on" : "auto")
+ : "off");
+ if (dialcon != CAR_OFF)
+ printf(" %s", dialcq ? "quiet" : "verbose");
+ printf(
+"\n Dial area-code: %-12s", diallac ? diallac : "(none)");
+ n++;
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf("Dial restrict: ");
+ if (dialrstr == 5) printf("international\n");
+ else if (dialrstr == 4) printf("long-distance\n");
+ else if (dialrstr == 2) printf("local\n");
+ else if (dialrstr == 6) printf("none\n");
+ else printf("?\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Dial lc-area-codes: ");
+ if (nlocalac == 0)
+ printf("(none)");
+ else
+ for (i = 0; i < nlocalac; i++)
+ printf("%s ", diallcac[i]);
+ printf(
+"\n Dial lc-prefix: %s\n", diallcp ? diallcp : "(none)");
+ n++;
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial lc-suffix: %s\n", diallcs ? diallcs : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial ld-prefix: %s\n", dialldp ? dialldp : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial ld-suffix: %s\n", diallds ? diallds : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial force-long-distance %s\n", showoff(dialfld));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial intl-prefix: %s\n", dialixp ? dialixp : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial intl-suffix: %s\n", dialixs ? dialixs : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial toll-free-area-code: ");
+ if (ntollfree == 0)
+ printf("(none)");
+ else
+ for (i = 0; i < ntollfree; i++)
+ printf("%s ", dialtfc[i]);
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(
+" Dial pulse-countries: ");
+ if (ndialpucc == 0)
+ printf("(none)");
+ else
+ for (i = 0; i < ndialpucc; i++)
+ printf("%s ", dialpucc[i]);
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(
+" Dial tone-countries: ");
+ if (ndialtocc == 0)
+ printf("(none)");
+ else
+ for (i = 0; i < ndialtocc; i++)
+ printf("%s ", dialtocc[i]);
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(
+ " Dial toll-free-prefix: %s\n",
+ dialtfp ? dialtfp :
+ (dialldp ? dialldp : "(none)")
+ );
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Dial pbx-exchange: ");
+ if (ndialpxx == 0)
+ printf("(none)");
+ else
+ for (i = 0; i < ndialpxx; i++)
+ printf("%s ", dialpxx[i]);
+ printf("\n");
+
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial pbx-inside-prefix: %s\n", dialpxi ? dialpxi : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial pbx-outside-prefix: %s\n", dialpxo ? dialpxo : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(
+" Dial macro: %s\n", dialmac ? dialmac : "(none)");
+ return(0);
+}
+#endif /* NODIAL */
+#endif /* NOLOCAL */
+
+/* Show File Parameters */
+
+static char *
+pathval(x) int x; {
+ switch (x) {
+ case PATH_OFF: return("off");
+ case PATH_ABS: return("absolute");
+ case PATH_REL: return("relative");
+ case PATH_AUTO: return("auto");
+ default: return("unknown");
+ }
+}
+
+VOID
+shofil() {
+ char *s; int i = 0, n = 1;
+ extern char * ifdnam[];
+ extern int wildena;
+#ifdef UNIX
+ extern int wildxpand;
+#endif /* UNIX */
+ extern char * snd_move, * snd_rename, * rcv_move, * rcv_rename;
+#ifdef PATTERNS
+ extern int patterns;
+#endif /* PATTERNS */
+ extern char * rfspec, * sfspec;
+#ifdef UNIX
+ extern int zobufsize, zofbuffer, zofblock;
+#endif /* UNIX */
+#ifdef CK_CTRLZ
+ extern int eofmethod;
+#endif /* CK_CTRLZ */
+
+ printf("\n");
+
+#ifdef VMS
+ printf(" File record-Length: %5d\n",frecl);
+ n++;
+#endif /* VMS */
+
+#ifndef NOXFER
+ printf(" Transfer mode: %s\n",
+ xfermode == XMODE_A ?
+ "automatic" :
+ "manual"
+ );
+ n++;
+#ifdef PATTERNS
+ printf(" File patterns: %s", showooa(patterns));
+ if (xfermode == XMODE_M && patterns)
+ printf(" (but disabled by TRANSFER-MODE MANUAL)");
+ else if (patterns)
+ printf(" (SHOW PATTERNS for list)");
+ printf("\n");
+ n++;
+#endif /* PATTERNS */
+ if (filepeek)
+ printf(" File scan: on %d\n", nscanfile);
+ else
+ printf(" File scan: off\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ if (xfermode == XMODE_A)
+ printf(" Default file type: %s\n",shoxm());
+ else
+ printf(" File type: %s\n",shoxm());
+ n++;
+ if (fncnv == XYFN_L)
+ s = "literal";
+ else if (fncnv == XYFN_C)
+ s = "converted";
+ else
+ s = "(unknown)";
+ printf(" File names: %s\n",s);
+ n++;
+ printf(" Send pathnames: %s\n", pathval(fnspath));
+ n++;
+ printf(" Receive pathnames: %s\n", pathval(fnrpath));
+ n++;
+#ifdef UNIXOROSK
+ printf(" Match dot files: %s\n", matchdot ? "yes" : "no");
+ n++;
+#ifdef UNIX
+ printf(" Wildcard-expansion: %s (%s)\n", showoff(wildena),
+ wildxpand ? "shell" : "kermit");
+ n++;
+#endif /* UNIX */
+#endif /* UNIXOROSK */
+ printf(" File collision: ");
+ for (i = 0; i < ncolx; i++)
+ if (colxtab[i].kwval == fncact) break;
+ printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" File destination: %s\n",
+ (dest == DEST_D) ? "disk" :
+ ((dest == DEST_S) ? "screen" :
+ ((dest == DEST_N) ? "nowhere" :
+ "printer"))
+ );
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ s = (keep >= 0 && keep <= 2) ? ifdnam[keep] : "keep";
+ printf(" File incomplete: %s\n",s);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" File bytesize: %d\n",(fmask == 0177) ? 7 : 8);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#ifndef NOCSETS
+ printf(" File character-set: %s\n",fcsinfo[fcharset].keyword);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" File default 7-bit: %s\n",fcsinfo[dcset7].keyword);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" File default 8-bit: %s\n",fcsinfo[dcset8].keyword);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#ifdef UNICODE
+ printf(" File UCS bom: %s\n",showoff(ucsbom));
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" File UCS byte-order: %s-endian\n",
+ ucsorder ? "little" : "big");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Computer byteorder: %s-endian\n",
+ byteorder ? "little" : "big");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* UNICODE */
+#endif /* NOCSETS */
+
+ printf(" File end-of-line: ");
+ i = feol;
+ switch (feol) {
+ case XYFA_C: printf("%s\n","cr"); break;
+ case XYFA_L: printf("%s\n","lf"); break;
+ case XYFA_2: printf("%s\n","crlf"); break;
+ default: printf("%d\n",i);
+ }
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* NOXFER */
+
+#ifdef CK_CTRLZ
+ printf(" File eof: %s\n", eofmethod ? "ctrl-z" : "length");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* CK_CTRLZ */
+#ifndef NOXFER
+#ifdef CK_TMPDIR
+ printf(" File download-directory: %s\n", dldir ? dldir : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#ifdef COMMENT
+ i = 256;
+ s = line;
+ zzstring("\\v(tmpdir)",&s,&i);
+ printf(" Temporary directory: %s\n", line);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* COMMENT */
+#endif /* CK_TMPDIR */
+#ifdef VMS
+ {
+ extern int vmssversions, vmsrversions;
+ printf(" Send version-numbers: %s\n",showoff(vmssversions));
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Receive version-numbers: %s\n",showoff(vmsrversions));
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ }
+#endif /* VMS */
+ printf(" Send move-to: %s\n",
+ snd_move ? snd_move : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Send rename-to: %s\n",
+ snd_rename ? snd_rename : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Receive move-to: %s\n",
+ rcv_move ? rcv_move : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Receive rename-to: %s\n",
+ rcv_rename ? rcv_rename : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* NOXFER */
+#ifdef KERMRC
+ printf(" Initialization file: %s\n", noinit ? "(none)" :
+#ifdef CK_SYSINI
+ CK_SYSINI
+#else
+ kermrc
+#endif /* CK_SYSINI */
+ );
+#endif /* KERMRC */
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+
+ if (k_info_dir) {
+ printf(" Kermit doc files: %s\n", k_info_dir);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ }
+
+#ifdef CKROOT
+ s = zgetroot();
+ printf(" Root set: %s\n", s ? s : "(none)");
+#endif /* CKROOT */
+
+#ifdef UNIX
+ printf(" Disk output buffer: %d (writes are %s, %s)\n",
+ zobufsize,
+ zofbuffer ? "buffered" : "unbuffered",
+ zofblock ? "blocking" : "nonblocking"
+ );
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#ifdef DYNAMIC
+ printf(" Stringspace: %d\n", zsetfil(0,2));
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Listsize: %d\n", zsetfil(0,4));
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* DYNAMIC */
+#endif /* UNIX */
+#ifdef OS2ORUNIX
+ printf(" Longest filename: %d\n", maxnam);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Longest pathname: %d\n", maxpath);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* OS2ORUNIX */
+
+ printf(" Last file sent: %s\n", sfspec ? sfspec : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" Last file received: %s\n", rfspec ? rfspec : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf("\n Also see:\n");
+ n++;
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf(" SHOW PROTOCOL, SHOW XFER");
+#ifdef CK_LABELED
+ printf(", SHOW LABELED");
+#endif /* CK_LABELED */
+#ifdef PATTERNS
+ printf(", SHOW PATTERNS");
+#endif /* PATTERNS */
+#ifdef STREAMING
+ printf(", SHOW STREAMING");
+#endif /* STREAMING */
+#ifndef NOCSETS
+ printf(", SHOW CHARACTER-SETS");
+#endif /* NOCSETS */
+ printf("\n\n");
+}
+
+#ifndef NOXFER
+VOID
+shoparp() { /* Protocol */
+ extern int docrc, skipbup;
+ char *s;
+
+#ifdef CK_TIMERS
+ extern int rttflg;
+#endif /* CK_TIMERS */
+
+ printf("Protocol: %s\n",ptab[protocol].p_name);
+
+ if (protocol == PROTO_K) {
+ printf("\nProtocol Parameters: Send Receive");
+ if (timef)
+ printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
+ else
+ printf("\n Timeout (used=%2d):%7d%9d ", timint, rtimo, pkttim);
+#ifdef XFRCAN
+ printf(" Cancellation: %s",showoff(xfrcan));
+ if (xfrcan)
+ printf(" %d %d", xfrchr, xfrnum);
+#endif /* XFRCAN */
+ printf("\n Padding: %11d%9d", npad, mypadn);
+ if (bctr == 4)
+ printf(" Block Check: blank-free-2\n");
+ else
+ printf(" Block Check: %6d\n",bctr);
+ printf( " Pad Character:%11d%9d", padch, mypadc);
+ printf(" Delay: %6d\n",ckdelay);
+ printf( " Pause: %11d%9d", pktpaus, pktpaus);
+ printf(" Attributes: %s\n",showoff(atcapr));
+ printf( " Packet Start: %11d%9d", mystch, stchr);
+ printf(" Max Retries: %6d%s\n",
+ maxtry,
+ (maxtry == 0) ? " (unlimited)" : ""
+ );
+ printf( " Packet End: %11d%9d", seol, eol);
+ if (ebqflg)
+ printf(" 8th-Bit Prefix: '%c'",ebq);
+ else
+ printf(" 8th-Bit Prefix: ('%c' but not used)",ebq);
+ printf( "\n Packet Length:%11d ", spmax);
+ printf("%8d ", urpsiz);
+ if (rptflg)
+ printf(" Repeat Prefix: '%c'",rptq);
+ else
+ printf(" Repeat Prefix: ('%c' but not used)",rptq);
+ printf( "\n Maximum Length: %9d%9d", maxsps, maxrps);
+ printf(" Window Size:%7d set, %d used\n",wslotr,wmax);
+ printf( " Buffer Size: %11d%9d", bigsbsiz, bigrbsiz);
+ printf(" Locking-Shift: ");
+ if (lscapu == 2) {
+ printf("forced");
+ } else {
+ printf("%s", (lscapr ? "enabled" : "disabled"));
+ if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
+ }
+ printf("\n\n");
+
+ if (!(s = ptab[protocol].h_b_init)) s = "";
+ printf(" Auto-upload command (binary): ");
+ if (*s) {
+ shostrdef((CHAR *)s);
+ printf("\n");
+ } else {
+ printf("(none)\n");
+ }
+ if (!(s = ptab[protocol].h_t_init)) s = "";
+ printf(" Auto-upload command (text): ");
+ if (*s) {
+ shostrdef((CHAR *)s);
+ printf("\n");
+ } else {
+ printf("(none)\n");
+ }
+ if (!(s = ptab[protocol].h_x_init)) s = "";
+ printf(" Auto-server command: ");
+ if (*s) {
+ shostrdef((CHAR *)s);
+ printf("\n");
+ } else {
+ printf("(none)\n");
+ }
+ tmpbuf[0] = NUL;
+#ifdef CK_TIMERS
+ if (rttflg) {
+ extern int mintime, maxtime;
+ sprintf(tmpbuf," Packet timeouts: dynamic %d:%d", /* SAFE */
+ mintime,
+ maxtime);
+ } else {
+ sprintf(tmpbuf," Packet timeouts: fixed"); /* SAFE */
+ }
+#endif /* CK_TIMERS */
+ if (tmpbuf[0])
+ printf("%-31s",tmpbuf);
+ printf("Send backup: %s\n",showoff(!skipbup));
+
+ printf(" Transfer mode: %s", xfermode == XMODE_A ?
+ "automatic " :
+ "manual "
+ );
+ printf(" Transfer slow-start: %s, crc: %s\n",
+ showoff(slostart),
+ showoff(docrc)
+ );
+#ifdef PIPESEND
+ {
+ extern int usepipes;
+ printf(" Transfer pipes: %s ",usepipes ? "on " : "off");
+ }
+#endif /* PIPESEND */
+#ifndef NOCSETS
+ printf(" Transfer character-set: ");
+ if (tcharset == TC_TRANSP)
+ printf("transparent\n");
+ else
+ printf("%s\n", tcsinfo[tcharset].keyword );
+#endif /* NOCSETS */
+#ifdef PIPESEND
+ {
+ extern char * sndfilter, * rcvfilter;
+ printf(" Send filter: %s\n", sndfilter ? sndfilter : "(none)");
+ printf(" Receive filter: %s\n", rcvfilter ? rcvfilter : "(none)");
+ }
+#endif /* PIPESEND */
+ printf("\nAlso see:\n");
+ printf(" SHOW FILE, SHOW XFER");
+
+#ifdef CK_LABELED
+ printf(", SHOW LABELED");
+#endif /* CK_LABELED */
+#ifdef PATTERNS
+ printf(", SHOW PATTERNS");
+#endif /* PATTERNS */
+#ifdef STREAMING
+ printf(", SHOW STREAMING");
+#endif /* STREAMING */
+#ifndef NOCSETS
+ printf(", SHOW CHARACTER-SETS");
+#endif /* NOCSETS */
+ }
+
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+ if (protocol != PROTO_K) {
+ int i;
+ int x;
+ printf(" File type: %s\n", binary ? "binary" : "text");
+ if (protocol == PROTO_Z) { /* Zmodem */
+ printf(" Window size: ");
+ if (ptab[protocol].winsize < 1)
+ printf("none\n");
+ else
+ printf("%d\n",wslotr);
+#ifdef COMMENT
+ printf(" Packet (frame) length: ");
+ if (ptab[protocol].spktlen < 0)
+ printf("none\n");
+ else
+ printf("%d\n",spmax);
+#endif /* COMMENT */
+ } else {
+ if (ptab[protocol].spktlen >= 1000)
+ printf(" 1K packets\n");
+ else
+ printf(" 128-byte packets\n");
+ }
+ printf(" Pathname stripping when sending: %s\n",
+ showoff(ptab[protocol].fnsp)
+ );
+ printf(" Pathname stripping when receiving: %s\n",
+ showoff(ptab[protocol].fnrp)
+ );
+ printf(" Filename collision action: ");
+ for (i = 0; i < ncolx; i++)
+ if (colxtab[i].kwval == fncact) break;
+ printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
+
+ printf("\n Escape control characters: ");
+ x = ptab[protocol].prefix;
+ if (x == PX_ALL)
+ printf("all\n");
+ else if (x == PX_CAU || x==PX_WIL)
+ printf("minimal\n");
+ else
+ printf("none\n");
+ if (!(s = ptab[protocol].h_b_init))
+ s = "";
+ printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
+ if (!(s = ptab[protocol].h_t_init))
+ s = "";
+ printf(" Autoreceive command (text): %s\n", *s ? s : "(none)");
+ }
+#else
+#ifndef NOPUSH
+ if (protocol != PROTO_K) {
+ _PROTOTYP( VOID shoextern, (void) );
+ printf("\nExecuted by external commands:\n\n");
+ s = ptab[protocol].p_b_scmd;
+ if (!s) s = "";
+ printf(" SEND command (binary): %s\n", *s ? s : "(none)");
+ s = ptab[protocol].p_t_scmd;
+ if (!s) s = "";
+ printf(" SEND command (text): %s\n", *s ? s : "(none)");
+ s = ptab[protocol].p_b_rcmd;
+ if (!s) s = "";
+ printf(" RECEIVE command (binary): %s\n", *s ? s : "(none)");
+ s = ptab[protocol].p_t_rcmd;
+ if (!s) s = "";
+ printf(" RECEIVE command (text): %s\n", *s ? s : "(none)");
+ s = ptab[protocol].h_b_init;
+ if (!s) s = "";
+ printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
+ s = ptab[protocol].h_t_init;
+ if (!s) s = "";
+ printf(" Autoreceive command (text): %s\n", *s ? s : "(none)");
+ (VOID) shoextern();
+ }
+#endif /* NOPUSH */
+#endif /* XYZ_INTERNAL */
+#endif /* CK_XYZ */
+}
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+/* Character-set items */
+
+extern int s_cset, r_cset, axcset[], afcset[];
+extern struct keytab xfrmtab[];
+
+VOID
+shoparl() {
+#ifdef COMMENT
+ int i;
+/* Misleading... */
+ printf("\nAvailable Languages:\n");
+ for (i = 0; i < MAXLANG; i++) {
+ printf(" %s\n",langs[i].description);
+ }
+#else
+ printf("\nLanguage-specific translation rules: %s\n",
+ language == L_USASCII ? "none" : langs[language].description);
+ shocharset();
+ printf("\n\n");
+#endif /* COMMENT */
+}
+
+VOID
+shocharset() {
+ int x;
+#ifdef COMMENT
+ char * s = "Unknown";
+ extern int xlatype;
+#endif /* COMMENT */
+
+#ifndef NOXFER
+ extern int xfrxla;
+#endif /* NOXFER */
+
+ debug(F101,"SHOW FILE CHAR","",fcharset);
+ printf("\n");
+#ifndef NOXFER
+ printf(" Transfer Translation: %s\n", showoff(xfrxla));
+ if (!xfrxla) {
+ printf(
+ " Because transfer translation is off, the following are ignored:\n\n");
+ }
+#endif /* NOXFER */
+ printf(" File Character-Set: %s (%s), ",
+ fcsinfo[fcharset].keyword,
+ fcsinfo[fcharset].name
+ );
+ if ((x = fcsinfo[fcharset].size) == 128)
+ printf("7-bit");
+ else if (x == 256)
+ printf("8-bit");
+ else
+ printf("multibyte");
+ printf("\n");
+ printf(" File Scan: %s\n",showoff(filepeek));
+ printf(" Default 7bit-Character-Set: %s\n",fcsinfo[dcset7].keyword);
+ printf(" Default 8bit-Character-Set: %s\n",fcsinfo[dcset8].keyword);
+ printf(" Transfer Character-Set");
+#ifdef COMMENT
+ if (tslevel == TS_L2)
+ printf(": (international)");
+ else
+#endif /* COMMENT */
+ if (tcharset == TC_TRANSP)
+ printf(": Transparent");
+ else
+ printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name);
+ printf("\n");
+#ifdef COMMENT
+ switch (xlatype) {
+ case XLA_NONE: s = "None"; break;
+ case XLA_BYTE: s = "Byte"; break;
+ case XLA_JAPAN: s = "Japanese"; break;
+ case XLA_UNICODE: s = "Unicode"; break;
+ }
+ printf("\n Translation type: %s\n",s);
+#endif /* COMMENT */
+ printf(" SEND character-set-selection: %s\n",xfrmtab[s_cset].kwd);
+ printf(" RECEIVE character-set-selection: %s\n",xfrmtab[r_cset].kwd);
+ if (s_cset == XMODE_A || r_cset == XMODE_A)
+ printf(
+ " (Use SHOW ASSOCIATIONS to list automatic character-set selections.)\n"
+ );
+}
+
+VOID
+showassoc() {
+ int i, k, n = 4;
+ char * s;
+ printf("\nFor incoming files:\n\n");
+ printf("Transfer Character-Set File Character-Set\n");
+ for (i = 1; i <= MAXTCSETS; i++) {
+ k = axcset[i];
+ if (k < 0 || k > MAXFCSETS)
+ s = "(none)";
+ else
+ s = fcsinfo[k].keyword;
+ if (!s) s = "";
+ if (!*s) s = "(none)";
+ printf(" %-25s%s\n",tcsinfo[i].keyword,s);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ }
+ printf("\nFor outbound files:\n\n");
+ n += 2;
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ printf("File Character-Set Transfer Character-Set\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ for (i = 0; i <= MAXFCSETS; i++) {
+ k = afcset[i];
+ if (k < 0 || k > MAXTCSETS)
+ s = "(none)";
+ else
+ s = tcsinfo[k].keyword;
+ if (!s) s = "";
+ if (!*s) s = "(none)";
+ printf(" %-25s%s\n",fcsinfo[i].keyword,s);
+ if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+ }
+}
+#endif /* NOCSETS */
+
+VOID
+shopar() {
+ printf("Show what? (Type \"show ?\" for a list of possibilities.)\n");
+}
+#endif /* NOSHOW */
+
+#ifndef NOXFER
+/* D O S T A T -- Display file transfer statistics. */
+
+int
+dostat(brief) int brief; {
+ extern long filrej, peakcps;
+ extern int lastspmax, streamed, cleared, streamok;
+ extern char whoareu[];
+ int n = 0, ftp = 0;
+ extern int docrc, interrupted, fatalio;
+
+ ftp = lastxfer & W_FTP;
+
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
+ ttgwsiz();
+#else /* OS2 */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ debug(F101,"dostat xferstat","",xferstat);
+ if (xferstat < 0) {
+ printf(" No file transfers yet.\n");
+ return(1);
+ }
+ n = 0;
+ if (brief) { printf("\n"); n++; };
+ printf(" protocol : %s\n",
+ ftp ? "ftp" : ptab[protocol].p_name);
+ n++;
+ printf(" status : ");
+ if (xferstat) printf("SUCCESS\n");
+ else if (interrupted) printf("FAILURE (interrupted)\n");
+ else if (fatalio) printf("FAILURE (i/o error)\n");
+ else printf("FAILURE\n");
+#ifndef XYZ_INTERNAL
+ if (!ftp && protocol != PROTO_K) {
+ printf("\n external protocol statistics not available\n");
+ return(1);
+ }
+#endif /* XYZ_INTERNAL */
+ n++;
+ if (!ftp) {
+ if (!xferstat > 0) {
+ if (docrc)
+ printf(" crc-16 of file(s) : %ld\n", crc16);
+ else
+ printf(" crc-16 of file(s) : (disabled)\n");
+ n++;
+ }
+ if (!xferstat && *epktmsg) {
+ printf(" reason : %s\n", epktmsg);
+ n++;
+ }
+ }
+ if (!brief) {
+#ifdef NEWFTP
+ if (ftp) {
+ extern char ftp_srvtyp[];
+ printf(" remote system type : %s\n",ftp_srvtyp);
+ } else
+#endif /* NEWFTP */
+ if (whoareu[0]) {
+ printf(" remote system type : %s\n",
+ getsysid((char *)whoareu));
+ n++;
+ }
+ printf(" files transferred : %ld\n",filcnt - filrej);
+ if (!ftp)
+ printf(" files not transferred : %ld\n",filrej);
+ printf(" characters last file : %s\n",ckfstoa(ffc));
+ printf(" total file characters : %s\n",ckfstoa(tfc));
+ n += ftp ? 3 : 4;
+ if (!ftp) {
+ printf(" communication line in : %s\n",ckfstoa(tlci));
+ printf(" communication line out : %s\n",ckfstoa(tlco));
+ printf(" packets sent : %d\n", spackets);
+ printf(" packets received : %d\n", rpackets);
+ n += 4;
+ }
+ }
+ if (ftp) goto dotimes;
+
+ printf(" damaged packets rec'd : %d\n", crunched);
+ printf(" timeouts : %d\n", timeouts);
+ printf(" retransmissions : %d\n", retrans);
+ n += 3;
+
+ if (!brief) {
+ if (filcnt > 0) {
+ printf(" parity : %s",parnam((char)parity));
+ n++;
+ if (autopar) { printf(" (detected automatically)"); n++; }
+ printf(
+ "\n control characters : %ld prefixed, %ld unprefixed\n",
+ ccp, ccu);
+ n++;
+ printf(" 8th bit prefixing : ");
+ n++;
+ if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
+ n++;
+ printf(" locking shifts : %s\n", lscapu ? "yes" : "no");
+ n++;
+ }
+ }
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ if (streamed > 0)
+ printf(" window slots used : (streaming)\n");
+ else
+ printf(" window slots used : %d of %d\n", wmax, wslotr);
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ printf(" reliable: : %s%s\n",
+ streamok ? "" : "not ", "negotiated");
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ printf(" clearchannel: : %s%s\n",
+ cleared ? "" : "not ", "negotiated");
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+
+ if (!brief) {
+ printf(" packet length : %d (send), %d (receive)\n",
+ lastspmax, urpsiz);
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ printf(" compression : ");
+ if (rptflg)
+ printf("yes [%c] (%ld)\n",(char) rptq,rptn);
+ else
+ printf("no\n");
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ if (bctu == 4)
+ printf(" block check type used : blank-free-2\n");
+ else
+ printf(" block check type used : %d\n",bctu);
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ }
+
+ dotimes:
+
+#ifdef GFTIMER
+#ifdef COMMENT
+ printf(" elapsed time : %0.3f sec, %s\n", fptsecs,hhmmss(tsecs));
+#endif /* COMMENT */
+ printf(" elapsed time : %s (%0.3f sec)\n",
+ hhmmss((long)(fptsecs + 0.5)),fptsecs);
+#else
+#ifdef COMMENT
+ printf(" elapsed time : %s (%d sec)\n",hhmmss(tsecs),tsecs);
+#endif /* COMMENT */
+ printf(" elapsed time : %d sec, %s\n",tsecs,hhmmss(tsecs));
+#endif /* GFTIMER */
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ if (!ftp && local && !network && !brief) {
+ if (speed <= 0L) speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880)
+ printf(" transmission rate : 75/1200 bps\n");
+ else
+ printf(" transmission rate : %ld bps\n",speed);
+ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
+ }
+ }
+ if (!ftp && local && !network && /* Only makes sense for */
+ mdmtyp == 0 && /* direct serial connections */
+ speed > 99L && /* when we really know the speed */
+ speed != 8880L
+ ) {
+ int eff;
+ eff = (((tfcps * 100L) / (speed / 100L)) + 5L) / 10L;
+ printf(" effective data rate : %ld cps (%d%%)\n",tfcps,eff);
+ } else
+ printf(" effective data rate : %ld cps\n", tfcps);
+ if (!ftp && peakcps > 0L && peakcps > tfcps)
+ printf(" peak data rate : %ld cps\n", peakcps);
+ if (brief)
+ printf("\nUse STATISTICS /VERBOSE for greater detail.\n\n");
+ return(1);
+}
+#endif /* NOXFER */
+
+#ifndef NOSPL
+
+/* The INPUT command */
+
+/*
+ NOTE: An INPUT timeout of 0 means to perform a nonblocking read of the
+ material that has already arrived and is waiting to be read, and perform
+ matches against it, without doing any further reads. It should succeed
+ or fail instantaneously.
+*/
+
+/* Output buffering for "doinput" */
+
+#ifdef pdp11
+#define MAXBURST 16 /* Maximum size of input burst */
+#else
+#define MAXBURST 1024
+#endif /* pdp11 */
+#ifdef OSK
+static CHAR *conbuf; /* Buffer to hold output for console */
+#else
+static CHAR conbuf[MAXBURST]; /* Buffer to hold output for console */
+#endif /* OSK */
+static int concnt = 0; /* Number of characters buffered */
+#ifdef OSK
+static CHAR *sesbuf; /* Buffer to hold output for session log */
+#else
+static CHAR sesbuf[MAXBURST]; /* Buffer to hold output for session log */
+#endif /* OSK */
+static int sescnt = 0; /* Number of characters buffered */
+
+extern int debses; /* TERMINAL DEBUG ON/OFF */
+
+static VOID /* Flush INPUT echoing */
+myflsh() { /* and session log output. */
+ if (concnt > 0) {
+ if (debses) { /* Terminal debugging? */
+ int i;
+ for (i = 0; i < concnt; i++)
+ conol(dbchr(conbuf[i]));
+ } else
+ conxo(concnt, (char *) conbuf);
+ concnt = 0;
+ }
+ if (sescnt > 0) {
+ logstr((char *) sesbuf, sescnt);
+ sescnt = 0;
+ }
+}
+
+/* Execute the INPUT and MINPUT commands */
+
+int instatus = -1;
+long inetime = -1L;
+int inwait = 0;
+int nowrap = 0;
+
+/* For returning the input sequence that matched */
+
+#ifdef BIGBUFOK
+#define MATCHBUFSIZ 8191
+#else
+#define MATCHBUFSIZ 1023
+#endif /* BIGBUFOK */
+static char * matchbuf = NULL;
+static int matchindex = 0;
+static int burst = 0; /* Chars remaining in input burst */
+/*
+ timo = How long to wait:
+ < 0 = Wait forever
+ 0 = Don't wait at all - material must already have arrived
+ > 0 = Wait this many seconds
+ ms = Array of strings to wait for.
+ mp = Array of flags.
+ If mp[i] == 0, ms[i] is literal, else it's a pattern.
+ flags = bit mask
+ INPSW_NOM = /NOMATCH = 1
+ INPSW_CLR = /CLEAR = 2
+ INPSW_NOW = /NOWRAP = 4
+ INPSW_COU = /COUNT = 8
+ count = /COUNT: value if a /COUNT switch was given.
+
+ Returns:
+ 0 on failure, 1 on success.
+*/
+#ifndef ES_NORMAL
+#define ES_NORMAL 0
+#endif /* ES_NORMAL */
+extern int inesc[], oldesc[];
+
+int
+doinput(timo,ms,mp,flags,count)
+ int timo; char *ms[]; int mp[]; int flags; int count; {
+ extern int inintr;
+#ifdef CK_AUTODL
+ extern int inautodl;
+#endif /* CK_AUTODL */
+ int x, y, i, t, rt, icn, anychar = 0, mi[MINPMAX];
+#ifdef GFTIMER
+ CKFLOAT fpt = 0.0;
+#endif /* GFTIMER */
+ int savecount = 0;
+ int nomatch = 0;
+ int clearfirst = 0;
+ int lastchar = 0;
+ int waiting = 0;
+ int imask = 0;
+ char ch, *xp, *s;
+ CHAR c;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int term_io;
+ int term_io_save;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef TNCODE
+ static int cr = 0;
+#endif /* TNCODE */
+ int is_tn = 0;
+#ifdef SSHBUILTIN
+ extern int ssh_cas;
+ extern char * ssh_cmd;
+#endif /* SSHBUILTIN */
+ int noescseq = 0; /* Filter escape sequences */
+
+ debug(F101,"input count","",count);
+ debug(F101,"input flags","",flags);
+
+/*
+ CK_BURST enables the INPUT speedup code, which depends on ttchk() returning
+ accurate information. If INPUT fails with this code enabled, change the
+ above "#define" to "#undef".
+*/
+#define CK_BURST
+
+/***** CHANGE THIS TO A SET INPUT PARAMETER *****/
+
+ noescseq = (sessft == XYFT_T); /* Filter escape sequences */
+
+ imask = cmask;
+ if (parity) imask = 0x7f;
+ inwait = timo; /* For \v(inwait) */
+
+ /* Options from command switches */
+
+ nowrap = flags & INPSW_NOW; /* 4 = /NOWRAP */
+ nomatch = flags & INPSW_NOM; /* 1 = /NOMATCH */
+ clearfirst = flags & INPSW_CLR; /* 2 = /CLEAR */
+ savecount = count;
+
+ makestr(&inpmatch,NULL);
+ if (!matchbuf) {
+ matchbuf = malloc(MATCHBUFSIZ+1);
+ matchbuf[0] = NUL;
+ }
+ matchindex = 0;
+
+ /* If last time through we returned because of /NOWRAP and buffer full */
+ /* now we have to clear the buffer to make room for another load. */
+
+ if (nowrap && instatus == INP_BF)
+ clearfirst = 1;
+
+ if (clearfirst) { /* INPUT /CLEAR */
+ int i;
+ myflsh(); /* Flush screen and log buffers */
+ for (i = 0; i < inbufsize; i++)
+ inpbuf[i] = NUL;
+ inpbp = inpbuf;
+ }
+ is_tn =
+#ifdef TNCODE
+ (local && network && IS_TELNET()) || (!local && sstelnet)
+#else
+ 0
+#endif /* TNCODE */
+ ;
+
+#ifdef CK_SSL
+ if (is_tn) if (ssl_raw_flag || tls_raw_flag) is_tn = 0;
+#endif /* CK_SSL */
+
+ instatus = INP_IE; /* 3 = internal error */
+ kbchar = 0;
+
+#ifdef OSK
+ if (conbuf == NULL) {
+ if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) {
+ return(0);
+ }
+ sesbuf = conbuf + MAXBURST;
+ }
+#endif /* OSK */
+
+#ifndef NOLOCAL
+ if (local) { /* In local mode... */
+ if ((waiting = ttchk()) < 0) { /* check that connection is open */
+ if (!quiet) {
+ if ((!network
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) && carrier != CAR_OFF)
+ printf("?Carrier detect failure on %s.\n", ttname);
+ else
+ printf("?Connection %s %s is not open.\n",
+ network ? "to" : "on",
+ ttname
+ );
+ }
+ instatus = INP_IO;
+ return(0);
+ }
+ debug(F101,"doinput waiting","",waiting);
+ y = ttvt(speed,flow); /* Put line in "ttvt" mode */
+ if (y < 0) {
+ printf("?INPUT initialization error\n");
+ instatus = INP_IO;
+ return(0); /* Watch out for failure. */
+ }
+ }
+#endif /* NOLOCAL */
+
+#ifdef SSHBUILTIN
+ if ( network && nettype == NET_SSH && ssh_cas && ssh_cmd &&
+ !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) {
+ if (!quiet)
+ printf("?SSH Subsystem active: %s\n", ssh_cmd);
+ instatus = INP_IKS;
+ return(0);
+ }
+#endif /* SSHBUILTIN */
+
+ debug(F111,"doinput ms[0]",ms[0],waiting);
+
+ if (!ms[0] || isemptystring(ms[0])) { /* No search string was given nor */
+ if (count < 2) /* a /COUNT: switch so we just */
+ anychar = 1; /* wait for the first character */
+ }
+ if (nomatch) anychar = 0; /* Don't match anything */
+
+ if (!anychar && waiting == 0 && timo == 0)
+ return(0);
+
+#ifndef NODEBUG
+ if (deblog) {
+ char xbuf[24];
+ debug(F101,"doinput anychar","",anychar);
+ debug(F101,"doinput timo","",timo);
+ debug(F101,"doinput echo","",inecho);
+#ifdef CK_BURST
+ debug(F101,"doinput burst","",burst);
+#endif /* CK_BURST */
+ y = -1;
+ while (ms[++y]) {
+ sprintf(xbuf,"doinput string %2d",y); /* SAFE (24) */
+ debug(F111,xbuf,ms[y],mp[y]);
+ }
+ }
+#endif /* NODEBUG */
+
+#ifdef IKS_OPTION
+ if (is_tn) {
+ /* If the remote side is in a state of IKS START-SERVER */
+ /* we request that the state be changed. We will detect */
+ /* a failure to adhere to the request when we call ttinc() */
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
+ iks_wait(KERMIT_REQ_STOP,0); /* Send Request-Stop */
+#ifdef CK_AUTODL
+ /* If we are processing packets during INPUT and we have not */
+ /* sent a START message, do so now. */
+ if (inautodl && TELOPT_ME(TELOPT_KERMIT) &&
+ !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
+ tn_siks(KERMIT_START); /* Send Kermit-Server Start */
+ }
+#endif /* CK_AUTODL */
+ }
+#endif /* IKS_OPTION */
+ x = 0; /* Return code, assume failure */
+ instatus = INP_TO; /* Status, assume timeout */
+
+ for (y = 0; y < MINPMAX; y++) /* Initialize... */
+ mi[y] = 0; /* ..string pattern match position */
+
+ if (!inpcas[cmdlvl]) { /* INPUT CASE = IGNORE? */
+ y = -1;
+ while ((xp = ms[++y])) { /* Convert each target to lowercase */
+ while (*xp) {
+ if (isupper(*xp)) *xp = (char) tolower(*xp);
+ xp++;
+ }
+ }
+ }
+ rtimer(); /* Reset timer. */
+#ifdef GFTIMER
+ rftimer(); /* Floating-point timer too. */
+#endif /* GFTIMER */
+ inetime = -1L; /* Initialize elapsed time. */
+ t = 0; /* Time now is 0. */
+ m_found = 0; /* Default to timed-out */
+ incount = 0; /* Character counter */
+ rt = (timo == 0) ? 0 : 1; /* Character-read timeout interval */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io_save = term_io; /* Disable I/O by emulator */
+ term_io = 0;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ while (1) { /* Character-getting loop */
+#ifdef CK_APC
+ /* Check to see if there is an Autodown or other APC command */
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && apcstatus != APC_OFF)) {
+ if (mlook(mactab,"_apc_commands",nmac) == -1) {
+ debug(F110,"doinput about to execute APC",apcbuf,0);
+ domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
+ delmac("_apc_commands",1);
+ apcactive = APC_INACTIVE;
+#ifdef DEBUG
+ } else {
+ debug(F100,"doinput APC in progress","",0);
+#endif /* DEBUG */
+ }
+ }
+#endif /* CK_APC */
+
+ if (timo == 0 && waiting < 1) { /* Special exit criterion */
+ instatus = INP_TO; /* for timeout == 0 */
+ break;
+ }
+ if (local) { /* One case for local */
+ y = ttinc(rt); /* Get character from comm device */
+ debug(F101,"doinput ttinc(rt) returns","",y);
+ if (y < -1) { /* Connection failed. */
+ instatus = INP_IO; /* Status = i/o error */
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = term_io_save;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ switch (y) {
+ case -2: /* Connection lost */
+ if (local && !network && carrier != CAR_OFF) {
+ dologend();
+ printf("Connection closed.\n");
+ ttclos(1);
+ }
+ break;
+ case -3:
+ dologend();
+ printf("Session Limit exceeded - closing connection.\n");
+ ttclos(1);
+ default:
+ break;
+ }
+ debug(F111,"doinput Connection failed","returning 0",y);
+ return(0);
+ }
+ if (inintr) {
+ debug(F111,"doinput","inintr",inintr);
+ if ((icn = conchk()) > 0) { /* Interrupted from keyboard? */
+ debug(F101,"input interrupted from keyboard","",icn);
+ kbchar = coninc(0);
+ if (kbchar >= 0) {
+ while (--icn > 0) {
+ debug(F110,"doinput","absorbing",0);
+ coninc(0); /* Yes, absorb what was typed. */
+ }
+ instatus = INP_UI; /* Fail and remember why. */
+ break;
+ }
+ }
+ }
+ } else { /* Another for remote */
+ y = coninc(rt);
+ debug(F101,"doinput coninc(rt) returns","",y);
+ }
+ if (y > -1) { /* A character arrived */
+ debug(F111,"doinput","a character arrived",y);
+ if (timo == 0)
+ waiting--;
+#ifndef OS2
+#define TN_NOLO
+#endif /* OS2 */
+#ifdef NOLOCAL
+#define TN_NOLO
+#endif /* NOLOCAL */
+
+#ifdef TN_NOLO
+ debug(F100,"doinput TN_NOLO","",0);
+#ifdef TNCODE
+ /* Check for telnet protocol negotiation */
+ if (is_tn) {
+ switch (y & 0xff) {
+ case IAC:
+ cr = 0;
+ myflsh(); /* Break from input burst for tn_doop() */
+#ifdef CK_BURST
+ burst = 0;
+#endif /* CK_BURST */
+ waiting -= 2; /* (not necessarily...) */
+ switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
+ case 2: duplex = 0; continue;
+ case 1: duplex = 1; continue;
+#ifdef IKS_OPTION
+ case 4:
+ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
+ !tcp_incoming) {
+ instatus = INP_IKS;
+ printf(
+ " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
+ );
+ break;
+ }
+ continue;
+#endif /* IKS_OPTION */
+ case 6: /* TELNET DO LOGOUT received */
+ continue;
+ case 7:
+ case 3: /* A quoted IAC */
+ break;
+ default:
+ continue;
+ }
+ case CR:
+ cr = 1;
+ break;
+ case NUL:
+ if (!TELOPT_U(TELOPT_BINARY) && cr) {
+ cr = 0;
+ continue;
+ }
+ cr = 0;
+ break;
+ default:
+ cr = 0;
+ }
+ /* I'm echoing remote chars */
+ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
+ ttoc((char)y);
+ }
+#endif /* TNCODE */
+#ifdef CK_AUTODL
+ /* Check for file transfer packets */
+ if (inautodl) autodown(y);
+#endif /* CK_AUTODL */
+#else /* TN_NOLO */
+ debug(F100,"doinput !TN_NOLO","",0);
+#ifdef TNCODE
+ /* Check for telnet protocol negotiation */
+ if (is_tn) {
+ int tx;
+ switch (y & 0xff) {
+ case IAC:
+ myflsh(); /* Break from input burst for tn_doop() */
+#ifdef CK_BURST
+ burst = 0;
+#endif /* CK_BURST */
+#ifdef IKS_OPTION
+ tx = scriptwrtbuf((USHORT)y);
+ if (tx == 4) {
+ if (TELOPT_U(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
+ !tcp_incoming
+ ) {
+ instatus = INP_IKS;
+ printf(
+ " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
+ );
+ break;
+ }
+ } else if (tx == 6) {
+ /* TELNET DO LOGOUT received */
+
+ }
+#else /* IKS_OPTION */
+ /* Handles Telnet negotiations */
+ tx = scriptwrtbuf((USHORT)y);
+ if (tx == 6) {
+ /* TELNET DO LOGOUT received */
+ }
+#endif /* IKS_OPTION */
+ waiting -= 2; /* (not necessarily...) */
+ cr = 0;
+ continue; /* and autodownload check */
+ case CR:
+ cr = 1;
+ tx = scriptwrtbuf((USHORT)y);
+ if (tx == 6) {
+ /* TELNET DO LOGOUT received */
+ }
+ break;
+ case NUL:
+ cr = 0;
+ if (!TELOPT_U(TELOPT_BINARY) && cr)
+ continue;
+ tx = scriptwrtbuf((USHORT)y);
+ if (tx == 6) {
+ /* TELNET DO LOGOUT received */
+ }
+ break;
+ default:
+ cr = 0;
+ tx = scriptwrtbuf((USHORT)y);
+ if (tx == 6) {
+ /* TELNET DO LOGOUT received */
+ }
+ }
+ /* I'm echoing remote chars */
+ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
+ ttoc((CHAR)y);
+ } else
+#endif /* TNCODE */
+ /* Handles terminal emulation responses */
+ scriptwrtbuf((USHORT)y);
+#endif /* TN_NOLO */
+
+ /* Real input character to be checked */
+
+#ifdef CK_BURST
+ burst--; /* One less character waiting */
+ debug(F101,"doinput burst","",burst);
+#endif /* CK_BURST */
+ c = (CHAR) (imask & (CHAR) y); /* Mask off any parity */
+ inchar[0] = c; /* Remember character for \v(inchar) */
+#ifdef COMMENT
+#ifdef CK_BURST
+ /* Update "lastchar" time only once during input burst */
+ if (burst <= 0)
+#endif /* CK_BURST */
+#endif /* COMMENT */
+ lastchar = gtimer(); /* Remember when it came */
+
+ if (c == '\0') { /* NUL, we can't use it */
+ if (anychar) { /* Except if any character will do? */
+ x = 1; /* Yes, done. */
+ instatus = INP_OK;
+ incount = 1; /* This must be the first and only. */
+ break;
+ } else goto refill; /* Otherwise continue INPUTting */
+ }
+ *inpbp++ = c; /* Store char in circular buffer */
+ incount++; /* Count it for \v(incount) */
+
+ if (flags & INPSW_COU) { /* INPUT /COUNT */
+ if (--count < 1) {
+ x = 1;
+ instatus = INP_OK;
+ incount = savecount;
+ break;
+ }
+ }
+ if (matchbuf) {
+ if (matchindex < MATCHBUFSIZ) {
+ matchbuf[matchindex++] = c;
+ matchbuf[matchindex] = NUL;
+ }
+ }
+#ifdef MAC
+ {
+ extern char *ttermw; /* fake pointer cast */
+ if (inecho) {
+ outchar(ttermw, c); /* echo to terminal window */
+ /* this might be too much overhead to do here ? */
+ updatecommand(ttermw);
+ }
+ }
+#else /* Not MAC */
+ if (inecho) { /* Buffer console output */
+ conbuf[concnt++] = c;
+ }
+#endif /* MAC */
+#ifndef OS2
+ if (seslog) {
+ int dummy = 0, skip = 0;
+#ifndef NOLOCAL
+ if (noescseq) {
+ dummy = chkaes(c,0);
+ if (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL)
+ skip = 1;
+ }
+#endif /* NOLOCAL */
+#ifdef UNIXOROSK
+ if (sessft == XYFT_T) {
+#ifdef UNIX
+ if (c == '\r')
+#else
+#ifdef OSK
+ if (c == '\012')
+#endif /* OSK */
+#endif /* UNIX */
+ skip = 1;
+ }
+#endif /* UNIXOROSK */
+ if (!skip)
+ sesbuf[sescnt++] = c; /* Buffer session log output */
+ }
+#endif /* OS2 */
+ if (anychar) { /* Any character will do? */
+ x = 1;
+ instatus = INP_OK;
+ break;
+ }
+ if (!inpcas[cmdlvl]) { /* Ignore alphabetic case? */
+ if (isupper(c)) /* Yes, convert input char to lower */
+ c = (CHAR) tolower(c);
+ }
+ debug(F000,"doinput char","",c);
+
+ /* Here is the matching section */
+
+ y = -1; /* Loop thru search strings */
+ while (!nomatch && (s = ms[++y])) { /* ...as many as we have. */
+ if (mp[y]) { /* Pattern match? */
+#ifdef COMMENT
+ int j;
+ /* This is gross but it works... */
+ /* We could just as easily have prepended '*' to the */
+ /* pattern and skipped the loop, except then we would */
+ /* not have any way to identify the matching string. */
+ for (j = 0; j < matchindex; j++) {
+ if (ckmatch(s,&matchbuf[j],1,1)) {
+ matchindex = j;
+ instatus = INP_OK;
+ x = 1;
+ break;
+ }
+ }
+ if (x > 0)
+ break;
+#else
+ /* July 2001 - ckmatch() returns match position. */
+ /* It works and it's not gross. */
+ /* (4 = floating pattern) */
+ x = ckmatch(s,matchbuf,inpcas[cmdlvl],1+4);
+ if (x > 0) {
+ matchindex = x - 1;
+ instatus = INP_OK;
+ x = 1;
+ break;
+ }
+#endif /* COMMENT */
+ continue;
+ } /* Literal match. */
+ i = mi[y]; /* Match-position in search string. */
+ debug(F000,"compare char","",(CHAR)s[i]);
+ if (c == (CHAR) s[i]) { /* Check for match */
+ i++; /* Got one, go to next character */
+ } else { /* Don't have a match */
+ int j;
+ for (j = i; i > 0; ) { /* Back up in search string */
+ i--; /* (Do this here to prevent compiler foulup) */
+ /* j is the length of the substring that matched */
+ if (c == (CHAR) s[i]) {
+ if (!strncmp(s,&s[j-i],i)) {
+ i++; /* c actually matches -- cfk */
+ break;
+ }
+ }
+ }
+ }
+ if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
+ ckstrncpy(matchbuf,ms[y],MATCHBUFSIZ);
+ matchindex = 0;
+ instatus = INP_OK; /* Yes, */
+ x = 1;
+ break; /* done. */
+ }
+ mi[y] = i; /* No, remember match-position */
+ }
+ if (x == 1) { /* Set \v(minput) result */
+ instatus = INP_OK;
+ m_found = y + 1;
+ break;
+ }
+ if (inpbp >= inpbuf + inbufsize) { /* Reached end of buffer? */
+ if (nowrap) { /* If /NOWRAP...*/
+ instatus = INP_BF; /* ...return indicating buffer full. */
+ *inpbp = NUL;
+ goto xinput;
+ }
+ *inpbp = NUL; /* Make it null-terminated */
+ inpbp = inpbuf; /* Yes. */
+ }
+ }
+#ifdef CK_BURST
+ else if (y <= -1 && burst > 0) {
+ debug(F111,"doinput (y<=-1&&burst>0)","burst",burst);
+ /* A timeout occurred so there can't */
+ burst = 0; /* be data waiting; must check timo */
+ }
+ refill:
+ if (burst <= 0) { /* No buffered chars remaining... */
+ myflsh(); /* Flush buffered output */
+ if (local) { /* Get size of next input burst */
+ burst = ttchk();
+ if (burst < 0) { /* ttchk() says connection is closed */
+ instatus = INP_IO; /* Status = i/o error */
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = term_io_save;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ if ((!network
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) && carrier != CAR_OFF) {
+ /* The test is written this way because the Microsoft compiler
+ * is producing bad code if written:
+ *
+ * if (network && (!istncomport() || carrier == CAR_OFF) )
+ */
+ break;
+ } else {
+ printf("Fatal error - disconnected.\n");
+ ttclos(1);
+ break;
+ }
+ }
+ if (inintr) {
+ if ((icn = conchk()) > 0) { /* Interrupt from keyboard? */
+ kbchar = coninc(0);
+ debug(F101,"input interrupted from keyboard","",icn);
+ while (--icn > 0) coninc(0); /* Yes, absorb chars. */
+ break; /* And fail. */
+ }
+ }
+ } else {
+ burst = conchk();
+ }
+ debug(F101,"doinput burst","",burst);
+ /* Prevent overflow of "conbuf" and "sesbuf" */
+ if (burst > MAXBURST)
+ burst = MAXBURST;
+
+ /* Did not match, timer exceeded? */
+ t = gtimer();
+ debug(F111,"doinput gtimer","burst",t);
+ debug(F101,"doinput timo","",timo);
+ if ((t >= timo) && (timo > 0))
+ break;
+ else if (insilence > 0 && (t - lastchar) > insilence)
+ break;
+ } else {
+ debug(F111,"doinput (burst > 0)","burst",burst);
+ }
+#else /* CK_BURST */
+ refill:
+ myflsh(); /* Flush buffered output */
+ /* Did not match, timer exceeded? */
+ t = gtimer();
+ debug(F111,"doinput gtimer","no burst",t);
+ debug(F101,"doinput timo","",timo);
+ if ((t >= timo) && (timo > -1))
+ break;
+ else if (insilence > 0 && (t - lastchar) > insilence)
+ break;
+#endif /* CK_BURST */
+ } /* Still have time left, continue. */
+ xinput:
+ myflsh(); /* Flush buffered output */
+ if (instatus == INP_BF) { /* Buffer full and /NOWAIT */
+ x = 0; /* Must not succeed */
+ } else { /* Buffer full and /NOWAIT */
+ if (nomatch) x = 1; /* Succeed if nomatch and timed out */
+ if (x > 0 && !nomatch)
+ instatus = 0;
+ }
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = term_io_save;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef COMMENT
+#ifdef IKS_OPTION
+#ifdef CK_AUTODL
+ if (is_tn && TELOPT_ME(TELOPT_KERMIT) && inautodl) {
+ tn_siks(KERMIT_STOP); /* Send Kermit-Server Stop */
+ }
+#endif /* CK_AUTODL */
+#endif /* IKS_OPTION */
+#endif /* COMMENT */
+
+#ifdef GFTIMER
+ fpt = gftimer(); /* Get elapsed time */
+
+/* If a long is 32 bits, it would take about 50 days for this to overflow. */
+
+ inetime = (int)(fpt * (CKFLOAT)1000.0);
+#else
+ inetime = (int)(gtimer() * 1000);
+#endif /* GFTIMER */
+
+ if (x > 0)
+ makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
+ return(x); /* Return the return code. */
+}
+#endif /* NOSPL */
+
+#ifndef NOSPL
+/* REINPUT Command */
+
+/*
+ Note, the timeout parameter is required, but ignored. Syntax is compatible
+ with MS-DOS Kermit except timeout can't be omitted. This function only
+ looks at the characters already received and does not read any new
+ characters from the connection.
+*/
+int
+doreinp(timo,s,pat) int timo; char *s; int pat; {
+ int x, y, i;
+ char *xx, *xp, *xq = (char *)0;
+ CHAR c;
+
+ if (!s) s = "";
+ debug(F101,"doreinput pat","",pat);
+
+ y = (int)strlen(s);
+ debug(F111,"doreinput search",s,y);
+
+ if (y > inbufsize) { /* If search string longer than */
+ debug(F101,"doreinput inbufsize","",inbufsize);
+ return(0); /* input buffer, fail. */
+ }
+ makestr(&inpmatch,NULL);
+ if (!matchbuf)
+ matchbuf = malloc(MATCHBUFSIZ+1);
+ matchindex = 0;
+
+ x = 0; /* Return code, assume failure */
+ i = 0; /* String pattern match position */
+
+ if (!inpcas[cmdlvl]) { /* INPUT CASE = IGNORE? */
+ xp = malloc(y+2); /* Make a separate copy of the */
+ if (!xp) { /* search string. */
+ printf("?malloc error 6\n");
+ return(x);
+ } else xq = xp; /* Keep pointer to beginning. */
+ while (*s) { /* Yes, convert to lowercase */
+ *xp = *s;
+ if (isupper(*xp)) *xp = (char) tolower(*xp);
+ xp++; s++;
+ }
+ *xp = NUL; /* Terminate it! */
+ s = xq; /* Move search pointer to it. */
+ }
+ xx = *inpbp ? inpbp : inpbuf; /* Current INPUT buffer pointer */
+ do {
+ c = *xx++; /* Get next character */
+ if (!c) break;
+ if (xx >= inpbuf + inbufsize) /* Wrap around if necessary */
+ xx = inpbuf;
+ if (!inpcas[cmdlvl]) { /* Ignore alphabetic case? */
+ if (isupper(c)) c = (CHAR) tolower(c); /* Yes */
+ }
+ if (pat) {
+ int j;
+ if (matchbuf) {
+ if (matchindex < MATCHBUFSIZ) {
+ matchbuf[matchindex++] = c;
+ matchbuf[matchindex] = NUL;
+ }
+ for (j = 0; j < matchindex; j++) { /* Gross but effective */
+ if (ckmatch(s,&matchbuf[j],1,1)) {
+ debug(F101,"GOT IT","",j);
+ matchindex = j;
+ x = 1;
+ break;
+ }
+ }
+ }
+ if (x > 0)
+ break;
+ continue;
+ }
+ debug(F000,"doreinp char","",c);
+ debug(F000,"compare char","",(CHAR) s[i]);
+ if (((char) c) == ((char) s[i])) { /* Check for match */
+ i++; /* Got one, go to next character */
+ } else { /* Don't have a match */
+ int j;
+ for (j = i; i > 0; ) { /* [jrs] search backwards for it */
+ i--;
+ if (((char) c) == ((char) s[i])) {
+ if (!strncmp(s,&s[j-i],i)) {
+ i++;
+ break;
+ }
+ }
+ }
+ } /* [jrs] or return to zero from -1 */
+ if (s[i] == '\0') { /* Matched all the way to end? */
+ ckstrncpy(matchbuf,s,MATCHBUFSIZ);
+ matchindex = 0;
+ x = 1; /* Yes, */
+ break; /* done. */
+ }
+ } while (xx != inpbp && x < 1); /* Until back where we started. */
+
+ if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
+ makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
+ return(x); /* Return search result. */
+}
+
+/* X X S T R I N G -- Interpret strings containing backslash escapes */
+/* Z Z S T R I N G -- (new name...) */
+/*
+ Copies result to new string.
+ strips enclosing braces or doublequotes.
+ interprets backslash escapes.
+ returns 0 on success, nonzero on failure.
+ tries to be compatible with MS-DOS Kermit.
+
+ Syntax of input string:
+ string = chars | "chars" | {chars}
+ chars = (c*e*)*
+ where c = any printable character, ascii 32-126
+ and e = a backslash escape
+ and * means 0 or more repetitions of preceding quantity
+ backslash escape = \operand
+ operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
+ number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
+ radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
+*/
+
+#ifndef NOFRILLS
+int
+yystring(s,s2) char *s; char **s2; { /* Reverse a string */
+ int x;
+ static char *new;
+ new = *s2;
+ if (!s || !new) return(-1); /* Watch out for null pointers. */
+ if ((x = (int)strlen(s)) == 0) { /* Recursion done. */
+ *new = '\0';
+ return(0);
+ }
+ x--; /* Otherwise, call self */
+ *new++ = s[x]; /* to reverse rest of string. */
+ s[x] = 0;
+ return(yystring(s,&new));
+}
+#endif /* NOFRILLS */
+
+static char ipabuf[16] = { NUL }; /* IP address buffer */
+
+static char *
+getip(s) char *s; {
+ char c=NUL; /* Workers... */
+ int i=0, p=0, d=0;
+ int state = 0; /* State of 2-state FSA */
+
+ while ((c = *s++)) {
+ switch(state) {
+ case 0: /* Find first digit */
+ i = 0; /* Output buffer index */
+ ipabuf[i] = NUL; /* Initialize output buffer */
+ p = 0; /* Period counter */
+ d = 0; /* Digit counter */
+ if (isdigit(c)) { /* Have first digit */
+ d = 1; /* Count it */
+ ipabuf[i++] = c; /* Copy it */
+ state = 1; /* Change state */
+ }
+ break;
+
+ case 1: /* In numeric field */
+ if (isdigit(c)) { /* Have digit */
+ if (++d > 3) /* Too many */
+ state = 0; /* Start over */
+ else /* Not too many */
+ ipabuf[i++] = c; /* Keep it */
+ } else if (c == '.' && p < 3) { /* Have a period */
+ p++; /* Count it */
+ if (d == 0) /* Not preceded by a digit */
+ state = 0; /* Start over */
+ else /* OK */
+ ipabuf[i++] = c; /* Keep it */
+ d = 0; /* Reset digit counter */
+ } else if (p == 3 && d > 0) { /* Not part of address */
+ ipabuf[i] = NUL; /* If we have full IP address */
+ return((char *)ipabuf); /* Return it */
+ } else { /* Otherwise */
+ state = 0; /* Start over */
+ ipabuf[0] = NUL; /* (in case no more chars left) */
+ }
+ }
+ } /* Fall thru at end of string */
+ ipabuf[i] = NUL; /* Maybe we have one */
+ return((p == 3 && d > 0) ? (char *)ipabuf : "");
+}
+#endif /* NOSPL */
+
+/* Date Routines */
+
+/* Z J D A T E -- Convert yyyymmdd date to Day of Year */
+
+static int jdays[12] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
+static int ldays[12] = { 0,31,60,91,121,152,182,213,244,274,305,335 };
+static char zjdbuf[12] = { NUL, NUL };
+/*
+ Deinde, ne in posterum a XII kalendas aprilis aequinoctium recedat,
+ statuimus bissextum quarto quoque anno (uti mos est) continuari debere,
+ praeterquam in centesimis annis; qui, quamvis bissextiles antea semper
+ fuerint, qualem etiam esse volumus annum MDC, post eum tamen qui deinceps
+ consequentur centesimi non omnes bissextiles sint, sed in quadringentis
+ quibusque annis primi quique tres centesimi sine bissexto transigantur,
+ quartus vero quisque centesimus bissextilis sit, ita ut annus MDCC, MDCCC,
+ MDCCCC bissextiles non sint. Anno vero MM, more consueto dies bissextus
+ intercaletur, februario dies XXIX continente, idemque ordo intermittendi
+ intercalandique bissextum diem in quadringentis quibusque annis perpetuo
+ conservetur. - Gregorius XIII, Anno Domini MDLXXXII.
+*/
+char *
+zjdate(date) char * date; { /* date = yyyymmdd */
+ char year[5];
+ char month[3];
+ char day[3];
+ int d, m, x, y;
+ int leapday, j;
+ char * time = NULL;
+
+ if (!date) date = ""; /* Validate arg */
+ x = strlen(date);
+ if (x < 1) return("0");
+ if (x < 8) return("-1");
+ for (x = 0; x < 8; x++)
+ if (!isdigit(date[x]))
+ return("-1");
+
+ if (date[8]) if (date[9])
+ time = date + 9;
+
+ year[0] = date[0]; /* Isolate year */
+ year[1] = date[1];
+ year[2] = date[2];
+ year[3] = date[3];
+ year[4] = '\0';
+
+ month[0] = date[4]; /* Month */
+ month[1] = date[5];
+ month[2] = '\0';;
+
+ day[0] = date[6]; /* And day */
+ day[1] = date[7];
+ day[2] = '\0';
+
+ leapday = 0; /* Assume no leap day */
+ y = atoi(year);
+ m = atoi(month);
+ d = atoi(day);
+ if (m > 2) { /* No Leap day before March */
+ if (y % 4 == 0) { /* If year is divisible by 4 */
+ leapday = 1; /* It's a Leap year */
+ if (y % 100 == 0) { /* Except if divisible by 100 */
+ if (y % 400 != 0) /* but not by 400 */
+ leapday = 0;
+ }
+ }
+ }
+ j = jdays[m - 1] + d + leapday; /* Day of year */
+ if (time)
+ sprintf(zjdbuf,"%04d%03d %s",y,j,time); /* SAFE */
+ else
+ sprintf(zjdbuf,"%04d%03d",y,j); /* SAFE */
+ return((char *)zjdbuf);
+}
+
+static char jzdbuf[32];
+
+/* J Z D A T E -- Convert Day of Year to yyyyddmm date */
+
+char *
+jzdate(date) char * date; { /* date = yyyyddd */
+ char year[5]; /* with optional time */
+ char day[4];
+ char * time = NULL, * p;
+ int d, m, x, y;
+ int leapday, j;
+ int * zz;
+
+ if (!date) date = ""; /* Validate arg */
+ x = strlen(date);
+
+ debug(F111,"jzdate len",date,x);
+
+ if (x < 1) return("0");
+ if (x < 7) return("-1");
+ if (x > 8) time = date + 8;
+
+ for (x = 0; x < 7; x++)
+ if (!isdigit(date[x]))
+ return("-1");
+
+ year[0] = date[0]; /* Isolate year */
+ year[1] = date[1];
+ year[2] = date[2];
+ year[3] = date[3];
+ year[4] = '\0';
+
+ debug(F110,"jzdate year",year,0);
+
+ day[0] = date[4]; /* And day */
+ day[1] = date[5];
+ day[2] = date[6];
+ day[3] = '\0';
+
+ debug(F110,"jzdate day",day,0);
+
+ j = atoi(day);
+ if (j > 366)
+ return("-1");
+
+ leapday = 0; /* Assume no leap day */
+ y = atoi(year);
+ if (y % 4 == 0) { /* If year is divisible by 4 */
+ leapday = 1; /* It's a Leap year */
+ if (y % 100 == 0) { /* Except if divisible by 100 */
+ if (y % 400 != 0) /* but not by 400 */
+ leapday = 0;
+ }
+ }
+ debug(F101,"jzdate leapday","",leapday);
+ zz = leapday ? ldays : jdays;
+
+ for (x = 0; x < 11; x++)
+ if (j > zz[x] && j <= zz[x+1])
+ break;
+ m = x + 1;
+
+ debug(F101,"jzdate m","",m);
+
+ d = j - zz[x];
+
+ debug(F101,"jzdate d","",d);
+
+ if (time)
+ sprintf(jzdbuf,"%04d%02d%02d %s",y,m,d,time); /* SAFE */
+ else
+ sprintf(jzdbuf,"%04d%02d%02d",y,m,d); /* SAFE */
+
+ debug(F101,"jzdate jzdbuf",jzdbuf,0);
+
+ p = ckcvtdate((char *)jzdbuf, 0); /* Convert to standard form */
+ ckstrncpy(jzdbuf,p,32);
+ if (!time) jzdbuf[8] = NUL; /* Remove time if not wanted */
+ return((char *)jzdbuf);
+}
+
+/* M J D -- Modified Julian Date */
+/*
+ Call with:
+ Standard-format date-time string: yyyymmdd[ hh:mm:ss].
+ The time, if any, is ignored.
+
+ Returns:
+ -1L on error, otherwise:
+ The number of days since 17 Nov 1858 as a whole number:
+ 16 Nov 1858 = -1, 17 Nov 1858 = 0, 18 Nov 1858 = 1, 19 Nov 1858 = 2, ...
+
+ The Modified Julian Date is defined by the International Astronomical
+ Union as the true Julian date minus 2400000.5 days. The true Julian
+ date is the number days since since noon of 1 January 4713 BCE of the
+ Julian proleptic calendar. Conversions between calendar dates and
+ Julian dates, however, assume Gregorian dating.
+*/
+long
+mjd(date) char * date; {
+ char year[5];
+ char month[3];
+ char day[3];
+ int x, a, d, m, y;
+ long z;
+
+ if (!date) date = ""; /* Validate arg */
+ x = strlen(date);
+ if (x < 1) return(0L);
+ if (x < 8) return(-1L);
+ for (x = 0; x < 8; x++)
+ if (!isdigit(date[x]))
+ return(-1L);
+
+ year[0] = date[0]; /* Isolate year */
+ year[1] = date[1];
+ year[2] = date[2];
+ year[3] = date[3];
+ year[4] = '\0';
+
+ month[0] = date[4]; /* Month */
+ month[1] = date[5];
+ month[2] = '\0';;
+ m = atoi(month);
+
+ day[0] = date[6]; /* And day */
+ day[1] = date[7];
+ day[2] = '\0';
+ d = atoi(day);
+
+ a = (14-m)/12; /* Calculate true Julian date */
+ y = atoi(year) + 4800 - a;
+ m = m + 12 * a - 3;
+ z = d + (long)(306*m+5)/10 + (long)(y*365) + y/4 - y/100 + y/400 - 32045L;
+
+ z -= 2400001L; /* Convert JD to MJD */
+
+ return(z);
+}
+
+static char mjd2dbuf[32];
+
+/* M J D 2 D A T E -- Converts MJD to yyyymmdd */
+
+char *
+#ifdef CK_ANSIC
+mjd2date(long mjd)
+#else
+mjd2date(mjd) long mjd;
+#endif /* CK_ANSIC */
+/* mjd2date */ {
+ long jd, l, n;
+ int d, m, y;
+ jd = (long)(mjd + 2400001L);
+ l = jd + 68569;
+ n = 4 * l / 146097L;
+ l = l - (146097 * n + 3) / 4;
+ y = 4000 * (l + 1) / 1461001L;
+ l = l - 1461 * y / 4 + 31;
+ m = 80 * l / 2447;
+ d = l - 2447 * m / 80;
+ l = m / 11;
+ m = m + 2 - 12 * l;
+ y = 100 * (n - 49) + y + l;
+ sprintf(mjd2dbuf,"%04d%02d%02d",y,m,d); /* SAFE */
+ return((char *)mjd2dbuf);
+}
+
+#ifndef NOSPL
+static char ** flist = (char **) NULL; /* File list for \fnextfile() */
+static int flistn = 0; /* Number of items in file list */
+
+/*
+ The function return-value buffer must be global, since fneval() returns a
+ pointer to it. fneval() is called only by zzstring(), which always copies
+ the result out of this buffer to somewhere else, so it's OK to have only
+ one buffer for this in most cases. However, since function calls can be
+ nested -- e.g. functions whose arguments are functions, or recursive
+ functions, at some point we should convert this to an array of buffers,
+ indexed by function depth (which might or might not be the same as the
+ "depth" variable). Also, since function results are potentially quite big,
+ we'd need to allocate and deallocate dynamically as we descend and ascend
+ function depth. Left for a future release...
+*/
+char fnval[FNVALL+2]; /* Function return value */
+static int fndepth = 0; /* (we don't actually use this yet) */
+int fnsuccess = 1;
+extern int fnerror;
+
+/* f p f o r m a t -- Floating-point number nicely formatted. */
+/*
+ Returns results from a circular 1K buffer.
+ Don't count on too many results remaining available at once; it could
+ be anywhere from 5 to maybe 100, depending on the sizes of the results.
+*/
+#ifdef CKFLOAT
+#define FPFMTSIZ 1024
+static char fpfmtbuf[FPFMTSIZ] = { NUL, NUL };
+static int fpfbufpos = 0; /* (why was this char before?) */
+
+char *
+fpformat(fpresult,places,round) CKFLOAT fpresult; int places, round; {
+ char fbuf[16]; /* For creating printf format */
+ int nines = 0, sign = 0, x, y, i, j, size = 0;
+ char * buf;
+ CKFLOAT ftmp;
+
+ x = places ? places : (fp_digits ? fp_digits : 6);
+
+ debug(F101,"fpformat fpresult","",fpresult);
+ debug(F101,"fpformat places","",places);
+ debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
+
+ ftmp = fpresult;
+ if (ftmp < 0.0) ftmp = 0.0 - fpresult;
+
+#ifdef FNFLOAT
+ if (!fp_rounding && /* If printf doesn't round, */
+ (places > 0 || /* round result to decimal places. */
+ (places == 0 && round)))
+ fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
+ y = (ftmp == 0.0) ? 1 : (int)log10(ftmp);
+ size = y + x + 3; /* Estimated length of result */
+ if (fpresult < 0.0) size++;
+#else
+ size = 200; /* No way to estimate, be generous */
+#endif /* FNFLOAT */
+
+ debug(F101,"fpformat size","",size);
+
+ if (fpfbufpos > (FPFMTSIZ - size)) /* Wrap around if necessary */
+ fpfbufpos = 0;
+ debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
+
+ buf = &fpfmtbuf[fpfbufpos];
+
+ if (places > 0) { /* If places specified */
+ /* use specified places to write given number of digits */
+ sprintf(fbuf,"%%0.%df",places); /* SAFE */
+ sprintf(buf,fbuf,fpresult); /* SAFE */
+ } else { /* Otherwise... */
+ /* Go for max precision */
+ sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
+ sprintf(buf,fbuf,fpresult); /* SAFE */
+ }
+ if (buf[0] == '-') sign = 1;
+ debug(F111,"fpresult 1 errno",buf,errno); /* Check for over/underflow */
+ debug(F111,"fpresult 1 fpfbufpos",buf,fpfbufpos);
+ /* Give requested decimal places */
+ for (i = sign; i < FPFMTSIZ && buf[i]; i++) {
+ if (buf[i] == '.') /* First find the decimal point */
+ break;
+ else if (i > fp_digits + sign - 1) /* replacing garbage */
+ buf[i] = '0'; /* digits with 0... */
+ }
+ if (buf[i] == '.') { /* Have decimal point */
+ int gotend = 0;
+ /* places < 0 so truncate fraction */
+ if (places < 0 || (places == 0 && round)) {
+ buf[i] = NUL;
+ } else if (places > 0) { /* d > 0 so this many decimal places */
+ i++; /* First digit after decimal */
+ for (j = 0; j < places; j++) { /* Truncate after d decimal */
+ if (!buf[j+i]) /* places or extend to d */
+ gotend = 1; /* decimal places. */
+ if (gotend || j+i+sign > fp_digits)
+ buf[j+i] = '0';
+ }
+ buf[j+i] = NUL;
+ } else { /* places == 0 so Do The Right Thing */
+ for (j = (int)strlen(buf) - 1; j > i+1; j--) {
+ if ((j - sign) > fp_digits)
+ buf[j] = '0';
+ if (buf[j] == '0')
+ buf[j] = NUL; /* Strip useless trailing 0's. */
+ else
+ break;
+ }
+ }
+ }
+ fpfmtbuf[FPFMTSIZ-1] = NUL;
+ j = strlen(buf);
+ sign = 0;
+ for (i = j-1; i >= 0; i--) {
+ if (buf[i] == '9')
+ nines++;
+ else
+ break;
+ }
+ /* Do something about xx.xx99999999... */
+ if (nines > 5) {
+ if (isdigit(buf[i]) && i < FPFMTSIZ - 2) {
+ buf[i] = buf[i] + 1;
+ buf[i+1] = '0';
+ buf[i+2] = '\0';
+ }
+ }
+ if (!strncmp(buf,"-0.0",FPFMTSIZ))
+ ckstrncpy(buf,"0.0",FPFMTSIZ);
+ fpfbufpos += (int)strlen(buf) + 1;
+ return((char *)buf);
+}
+#endif /* CKFLOAT */
+
+static VOID
+evalerr(fn) char * fn; {
+ if (fndiags) {
+ if (divbyzero)
+ ckmakmsg(fnval,FNVALL,"<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
+ else
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ }
+}
+
+
+static int
+ckcindex(c,s) char c, *s; {
+ int rc;
+ if (!c || !s) return(0);
+ for (rc = 0; s[rc]; rc++) {
+ if (c == s[rc]) return(rc+1);
+ }
+ return(0);
+}
+
+static char *
+dokwval(s,sep) char * s, * sep; {
+ char c = '\0', * p, * kw = NULL, * vp = NULL;
+ char * rc = "0"; /* Return code */
+ int x = 0;
+ if (!s) return(rc);
+ if (!*s) return(rc);
+ debug(F110,"kwval arg",s,0);
+ debug(F110,"kwval sep",sep,0);
+ p = (char *)malloc((int)strlen(s)+1);
+ if (!p) goto xdokwval;
+ strcpy(p,s); /* SAFE */
+ s = p;
+ while (*s < '!' && *s > '\0') /* Get first nonblank */
+ s++;
+ if (!*s) goto xdokwval;
+ if (ckcindex(*s,sep)) /* Separator but no keyword */
+ goto xdokwval;
+ kw = s; /* Keyword */
+ while (*s > ' ') {
+ if (ckcindex(*s,sep)) { /* keyword=... */
+ c = *s;
+ break;
+ }
+ s++;
+ }
+ if (*kw) rc = "1"; /* Have keyword, promote return code */
+ *s++ = NUL; /* Terminate keyword */
+ while (*s < '!' && *s > '\0') /* Skip blanks */
+ s++;
+ if (!c && ckcindex(*s,sep)) {
+ c = *s++; /* Have separator */
+ while (*s < '!' && *s > '\0') /* Skip blanks */
+ s++;
+ }
+ if (c) {
+ vp = s;
+ if (*vp) rc = "2"; /* Have value, another promotion */
+#ifdef COMMENT
+ while (*s > ' ') /* Skip to end */
+ s++;
+ *s = NUL; /* Terminate value */
+#endif /* COMMENT */
+ }
+ debug(F110,"kwval c",ckctoa(c),0);
+ debug(F110,"kwval keyword",kw,0);
+ debug(F110,"kwval value",vp,0);
+ makestr(&lastkwval,kw);
+ vp = brstrip(vp);
+ debug(F110,"kwval value",vp,0);
+ x = addmac(kw,vp);
+ debug(F111,"kwval addmac",kw,x);
+ xdokwval:
+ if (p) free(p);
+ return((x < 0) ? "-1" : rc);
+}
+
+static int
+isaarray(s) char * s; { /* Is s an associative array element */
+ int state = 0;
+ CHAR c;
+ if (!s) return(0);
+ while ((c = *s++)) {
+ if (!isprint(c)) {
+ return(0);
+ } else if (c == '<') {
+ if (state != 0)
+ return(0);
+ state = 1;
+ } else if (c == '>') {
+ return((state != 1 || *s) ? 0 : 1);
+ }
+ }
+ return(0);
+}
+
+static char * /* Evaluate builtin functions */
+fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
+ int i=0, j=0, k=0, len1=0, len2=0, len3=0, n=0, t=0, x=0, y=0;
+ int cx, failed = 0; /* Return code, 0 = ok */
+ long z = 0L;
+ char *bp[FNARGS + 1]; /* Pointers to malloc'd strings */
+ char c = NUL;
+ char *p = NULL, *s = NULL;
+ char *val1 = NULL, *val2 = NULL; /* Pointers to numeric string values */
+
+#ifdef RECURSIVE
+ int rsave = recursive;
+#endif /* RECURSIVE */
+#ifdef OS2
+ int zsave = zxpn;
+#endif /* OS2 */
+
+ if (!fn) fn = ""; /* Protect against null pointers */
+ if (!*fn) return("");
+
+ for (i = 0; i < FNARGS; i++) /* Initialize argument pointers */
+ bp[i] = NULL;
+/*
+ IMPORTANT: Note that argn is not an accurate count of the number of
+ arguments. We can't really tell if an argument is null until after we
+ execute the code below. So argn is really the maximum number of arguments
+ we might have. Argn should always be at least 1, even if the function is
+ called with empty parentheses (but don't count on it).
+*/
+ debug(F111,"fneval",fn,argn);
+ debug(F110,"fneval",argp[0],0);
+ if (argn > FNARGS) /* Discard excess arguments */
+ argn = FNARGS;
+
+ fndepth++;
+ debug(F101,"fneval fndepth","",fndepth);
+ p = fnval;
+ fnval[0] = NUL;
+ y = lookup(fnctab,fn,nfuncs,&x); /* Look up the function name */
+ cx = y; /* Because y is too generic... */
+ if (cx < 0) { /* Not found */
+ failed = 1;
+ if (fndiags) { /* FUNCTION DIAGNOSTIC ON */
+ int x;
+ x = strlen(fn);
+ /* The following sprintf's are safe */
+ switch (cx) {
+ case -1:
+ if (x + 32 < FNVALL)
+ sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION:\\f%s()>",fn);
+ else
+ sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION>");
+ break;
+ case -2:
+ if (x + 26 < FNVALL)
+ sprintf(fnval,"<ERROR:NAME_AMBIGUOUS:\\f%s()>",fn);
+ else
+ sprintf(fnval,"<ERROR:NAME_AMBIGUOUS>");
+ break;
+ case -3:
+ sprintf(fnval,"<ERROR:FUNCTION_NAME_MISSING:\\f()>");
+ break;
+ default:
+ if (x + 26 < FNVALL)
+ sprintf(fnval,"<ERROR:LOOKUP_FAILURE:\\f%s()>",fn);
+ else
+ sprintf(fnval,"<ERROR:LOOKUP_FAILURE>");
+ break;
+ }
+ }
+ goto fnend; /* Always leave via common exit */
+ }
+ fn = fnctab[x].kwd; /* Full name of function */
+
+ if (argn < 0) {
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
+ goto fnend;
+ }
+ if (cx == FN_LIT) { /* literal(arg1) */
+ debug(F010,"flit",xp,0);
+ p = xp ? xp : ""; /* Return a pointer to arg itself */
+ goto fnend;
+ }
+
+#ifdef DEBUG
+ if (deblog) {
+ int j;
+ for (j = 0; j < argn; j++)
+ debug(F111,"fneval arg",argp[j],j);
+ }
+#endif /* DEBUG */
+ for (j = argn-1; j >= 0; j--) { /* Uncount empty trailing args */
+ if (!argp[j])
+ argn--;
+ else if (!*(argp[j]))
+ argn--;
+ else break;
+ }
+ debug(F111,"fneval argn",fn,argn);
+/*
+ \fliteral() and \fcontents() are special functions that do not evaluate
+ their arguments, and are treated specially here. After these come the
+ functions whose arguments are evaluated in the normal way.
+*/
+#ifdef COMMENT
+ /* (moved up) */
+ if (cx == FN_LIT) { /* literal(arg1) */
+ debug(F110,"flit",xp,0);
+ p = xp ? xp : ""; /* Return a pointer to arg itself */
+ goto fnend;
+ }
+#endif /* COMMENT */
+ if (cx == FN_CON) { /* Contents of variable, unexpanded. */
+ char c;
+ int subscript = 0;
+ if (!(p = argp[0]) || !*p) {
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ sprintf(fnval,"<ERROR:MISSING_ARG:\\fcontents()>");
+ goto fnend;
+ }
+ p = brstrip(p);
+ if (*p == CMDQ) p++;
+ if ((c = *p) == '%') { /* Scalar variable. */
+ c = *++p; /* Get ID character. */
+ p = ""; /* Assume definition is empty */
+ if (!c) { /* Double paranoia */
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ sprintf(fnval,"<ERROR:ARG_BAD_VARIABLE:\\fcontents()>");
+ goto fnend;
+ }
+ if (c >= '0' && c <= '9') { /* Digit for macro arg */
+ if (maclvl < 0) /* Digit variables are global */
+ p = g_var[c]; /* if no macro is active */
+ else /* otherwise */
+ p = m_arg[maclvl][c - '0']; /* they're on the stack */
+ } else if (c == '*') {
+#ifdef COMMENT
+ p = (maclvl > -1) ? m_line[maclvl] : topline;
+ if (!p) p = "";
+#else
+ int nx = FNVALL;
+ char * sx = fnval;
+ p = fnval;
+#ifdef COMMENT
+ if (cmdsrc() == 0 && topline)
+ p = topline;
+ else
+#endif /* COMMENT */
+ if (zzstring("\\fjoin(&_[],{ },1)",&sx,&nx) < 0) {
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ sprintf(fnval,"<ERROR:OVERFLOW:\\fcontents()>");
+ debug(F110,"zzstring fcontents(\\%*)",p,0);
+ }
+#endif /* COMMENT */
+ } else {
+ if (isupper(c)) c -= ('a'-'A');
+ p = g_var[c]; /* Letter for global variable */
+ }
+ if (!p) p = "";
+ goto fnend;
+ } else if (c == '&') { /* Array reference. */
+ int vbi, d;
+ if (arraynam(p,&vbi,&d) < 0) { /* Get name and subscript */
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\fcontents()>");
+ goto fnend;
+ }
+ subscript = chkarray(vbi,d); /* Check the array */
+ if (subscript >= 0) { /* Array is declared? */
+ vbi -= ARRAYBASE; /* Convert name to index */
+ if (a_dim[vbi] >= d) { /* If subscript in range */
+ char **ap;
+ ap = a_ptr[vbi]; /* get data pointer */
+ if (ap) { /* and if there is one */
+ p = ap[d]; /* return it */
+ goto fnend;
+ }
+ }
+ } else { /* Array not declared or element */
+ fnval[0] = NUL; /* out of range - return null string */
+ p = fnval; /* fdc 2010-12-30 */
+ goto fnend;
+ }
+ } else {
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ sprintf(fnval,"<ERROR:ARG_NOT_VARIABLE:\\fcontents()>");
+ goto fnend;
+ }
+ }
+ p = fnval; /* Default result pointer */
+ fnval[0] = NUL; /* Default result = empty string */
+
+ for (i = 0; i < argn; i++) { /* Loop to expand each argument */
+ n = MAXARGLEN; /* Allow plenty of space */
+ bp[i] = s = malloc(n+1); /* Allocate space for this argument */
+ if (bp[i] == NULL) { /* Handle failure to get space */
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ p = argp[i] ? argp[i] : ""; /* Point to this argument */
+
+/*
+ Trim leading and trailing spaces from the original argument, before
+ evaluation. This code new to edit 184. Fixed in edit 199 to trim
+ blanks BEFORE stripping braces.
+
+*/
+ {
+ int x, j;
+ x = strlen(p);
+ j = x - 1; /* Trim trailing whitespace */
+ while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
+ *(p + j--) = NUL;
+ while (*p == SP || *p == HT) /* Strip leading whitespace */
+ p++;
+ x = strlen(p);
+ if (*p == '{' && *(p+x-1) == '}') { /* NOW strip braces */
+ p[x-1] = NUL;
+ p++;
+ x -= 2;
+ }
+ }
+
+/* Now evaluate the argument */
+
+ debug(F111,"fneval calling zzstring",p,n);
+ t = zzstring(p,&s,&n); /* Expand arg into new space */
+ debug(F101,"fneval zzstring","",t);
+ debug(F101,"fneval zzstring","",n);
+ if (t < 0) {
+ debug(F101,"fneval zzstring fails, arg","",i);
+ failed = 1;
+ if (fndiags) {
+ if (n == 0)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_TOO_LONG:\\f",fn,"()>",NULL);
+ else
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_EVAL_FAILURE:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+ debug(F111,"fneval arg",bp[i],i);
+ }
+
+#ifdef DEBUG
+ if (deblog) {
+ int j;
+ for (j = 0; j < argn; j++) {
+ debug(F111,"fneval arg post eval",argp[j],j);
+ debug(F111,"fneval evaluated arg",bp[j],j);
+ }
+ }
+#endif /* DEBUG */
+ {
+ /* Adjust argn for empty trailing arguments. */
+ /* For example when an arg is a variable name but the */
+ /* variable has no value. July 2006. */
+ int j, old; char *p;
+ old = argn;
+ for (j = argn - 1; j >= 0; j--) {
+ p = bp[j];
+ if (!p)
+ argn--;
+ else if (!*p)
+ argn--;
+ else
+ break;
+ }
+#ifdef DEBUG
+ if (argn != old)
+ debug(F101,"fneval adjusted argn","",argn);
+#endif /* DEBUG */
+ }
+
+/*
+ From this point on, bp[0..argn-1] are not NULL and all must be freed
+ before returning.
+*/
+ if (argn < 1) { /* Catch required args missing */
+ switch (cx) {
+ case FN_DEF:
+ case FN_EVA:
+ case FN_EXE:
+ case FN_CHR:
+ case FN_COD:
+ case FN_MAX:
+ case FN_MIN:
+ case FN_MOD:
+ case FN_FD:
+ case FN_FS:
+ case FN_TOD:
+ case FN_FFN:
+ case FN_BSN:
+ case FN_RAW:
+ case FN_CMD:
+ case FN_2HEX:
+ case FN_2OCT:
+ case FN_DNAM:
+#ifdef FN_ERRMSG
+ case FN_ERRMSG:
+#endif /* FN_ERRMSG */
+#ifdef CK_KERBEROS
+ case FN_KRB_TK:
+ case FN_KRB_NX:
+ case FN_KRB_IV:
+ case FN_KRB_TT:
+ case FN_KRB_FG:
+#endif /* CK_KERBEROS */
+ case FN_MJD2:
+ case FN_N2TIM:
+ case FN_DIM:
+ case FN_DATEJ:
+ case FN_PNCVT:
+ case FN_PERM:
+ case FN_ALOOK:
+ case FN_TLOOK:
+ case FN_ABS:
+ case FN_AADUMP:
+ case FN_JOIN:
+#ifdef CKFLOAT
+ case FN_FPABS:
+ case FN_FPEXP:
+ case FN_FPLOG:
+ case FN_FPLN:
+ case FN_FPMOD:
+ case FN_FPSQR:
+ case FN_FPADD:
+ case FN_FPDIV:
+ case FN_FPMUL:
+ case FN_FPPOW:
+ case FN_FPSUB:
+ case FN_FPINT:
+ case FN_FPROU:
+ case FN_FPSIN:
+ case FN_FPCOS:
+ case FN_FPTAN:
+#endif /* CKFLOAT */
+#ifdef TCPSOCKET
+ case FN_HSTADD:
+ case FN_HSTNAM:
+#endif /* TCPSOCKET */
+ case FN_DELSEC:
+#ifdef COMMENT
+ case FN_KWVAL:
+ case FN_SLEEP:
+ case FN_MSLEEP:
+#endif /* COMMENT */
+#ifdef NT
+ case FN_SNAME:
+ case FN_LNAME:
+#endif /* NT */
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ p = fnval; /* Reset these again. */
+ fnval[0] = NUL;
+
+ switch (cx) { /* Do function on expanded args. */
+#ifdef TCPSOCKET
+ case FN_HSTADD:
+ p = ckaddr2name(bp[0]);
+ goto fnend;
+ case FN_HSTNAM:
+ p = ckname2addr(bp[0]);
+ goto fnend;
+#endif /* TCPSOCKET */
+
+ case FN_DEF: /* \fdefinition(arg1) */
+ k = isaarray(bp[0]) ?
+ mxxlook(mactab,bp[0],nmac) :
+ mxlook(mactab,bp[0],nmac);
+ p = (k > -1) ? mactab[k].mval : "";
+ goto fnend;
+
+ case FN_EVA: /* \fevaluate(arg1) */
+ p = *(bp[0]) ? evalx(bp[0]) : "";
+ if (!*p && fndiags) {
+ failed = 1;
+ p = fnval;
+ evalerr(fn);
+ }
+ goto fnend;
+
+ case FN_EXE: /* \fexecute(arg1) */
+ j = (int)strlen(s = bp[0]); /* Length of macro invocation */
+ p = ""; /* Initialize return value to null */
+ if (j) { /* If there is a macro to execute */
+ while (*s == SP) s++,j--; /* strip leading spaces */
+ p = s; /* remember beginning of macro name */
+ for (i = 0; i < j; i++) { /* find end of macro name */
+ if (*s == SP)
+ break;
+ s++;
+ }
+ if (*s == SP) { /* if there was a space after */
+ *s++ = NUL; /* terminate the macro name */
+ while (*s == SP) s++; /* skip past any extra spaces */
+ } else
+ s = ""; /* maybe there are no arguments */
+ if (p && *p) {
+ k = mlook(mactab,p,nmac); /* Look up the macro name */
+ debug(F111,"fexec mlook",p,k);
+ } else
+ k = -1;
+ if (k < 0) {
+ char * p2 = p;
+ failed = 1;
+ p = fnval;
+ if (fndiags)
+ ckmakxmsg(fnval,FNVALL,
+ "<ERROR:NO_SUCH_MACRO:\\f",fn,"(",p2,")>",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ goto fnend;
+ }
+/*
+ This is just a WEE bit dangerous because we are copying up to 9 arguments
+ into the space reserved for one. It won't overrun the buffer, but if there
+ are lots of long arguments we might lose some. The other problem is that if
+ the macro has more than 3 arguments, the 4th through last are all
+ concatenated onto the third. (The workaround is to use spaces rather than
+ commas to separate them.) Leaving it like this to avoid having to allocate
+ tons more buffers.
+*/
+ if (argn > 1) { /* Commas used instead of spaces */
+ int i;
+ char *p = bp[0]; /* Reuse this space */
+ *p = NUL; /* Make into dodo() arg list */
+ for (i = 1; i < argn; i++) {
+ ckstrncat(p,bp[i],MAXARGLEN);
+ ckstrncat(p," ",MAXARGLEN);
+ }
+ s = bp[0]; /* Point to new list */
+ }
+ p = ""; /* Initialize return value */
+ if (k >= 0) { /* If macro found in table */
+ /* Go set it up (like DO cmd) */
+ if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) {
+ if (cmpush() > -1) { /* Push command parser state */
+ extern int ifc;
+ int ifcsav = ifc; /* Push IF condition on stack */
+ k = parser(1); /* Call parser to execute the macro */
+ cmpop(); /* Pop command parser */
+ ifc = ifcsav; /* Restore IF condition */
+ if (k == 0) { /* No errors, ignore action cmds. */
+ p = mrval[maclvl+1]; /* If OK, set return value. */
+ if (p == NULL) p = "";
+ }
+ } else { /* Can't push any more */
+ debug(F100,"zzstring fneval fexec failure","",0);
+ printf("\n?\\fexec() too deeply nested\n");
+ while (cmpop() > -1) ;
+ p = "";
+ }
+ }
+ }
+ }
+ debug(F110,"zzstring fneval fexecute final p",p,0);
+ goto fnend;
+
+#ifdef RECURSIVE
+ case FN_RDIR: /* \frdir..() - Recursive dir count */
+ case FN_RFIL: /* \frfiles() - Recursive file count */
+ /* recursive = 2; */ /* fall thru... */
+#endif /* RECURSIVE */
+ case FN_FC: /* \ffiles() - File count. */
+ case FN_DIR: { /* \ffdir.() - Directory count. */
+ char abuf[16], *s;
+ char ** ap = NULL;
+ int x, xflags = 0;
+ if (matchdot)
+ xflags |= ZX_MATCHDOT;
+ if (cx == FN_RDIR || cx == FN_RFIL) {
+ xflags |= ZX_RECURSE;
+#ifdef CKSYMLINK
+ /* Recursive - don't follow symlinks */
+ xflags |= ZX_NOLINKS;
+#endif /* CKSYMLINK */
+ }
+ failed = 0;
+ if (argn < 1) {
+ p = "0";
+ goto fnend;
+ }
+ if (cx == FN_DIR || cx == FN_RDIR) { /* Only list directories */
+ debug(F100,"FN_DIR or FN_RDIR","",0);
+ xflags |= ZX_DIRONLY;
+#ifdef OS2
+ zxpn = 1; /* Use the alternate list */
+#endif /* OS2 */
+ } else { /* List only files */
+ debug(F100,"Not FN_DIR or FN_RDIR","",0);
+ xflags |= ZX_FILONLY;
+#ifdef OS2
+ zxpn = 1; /* Use the alternate list */
+#endif /* OS2 */
+ }
+ if (*(bp[0])) {
+ k = nzxpand(bp[0],xflags);
+ if (k < 0) k = 0;
+ sprintf(fnval,"%d",k); /* SAFE */
+ p = fnval;
+ } else
+ p = "0";
+
+ if (argn > 1) { /* Assign list to array */
+ fnval[0] = NUL; /* Initial return value */
+ ckstrncpy(abuf,bp[1],16); /* Get array reference */
+ s = abuf;
+ if (*s == CMDQ) s++;
+ failed = 1; /* Assume it's bad */
+ p = fnval; /* Point to result */
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ if (s[0] != '&') /* "Address" of array */
+ goto fnend;
+ if (s[2])
+ if (s[2] != '[' || s[3] != ']')
+ goto fnend;
+ if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
+ s[1] += 32;
+ if ((x = dclarray(s[1],k)) < 0) /* File list plus count */
+ goto fnend;
+ failed = 0; /* Unset failure flag */
+ ap = a_ptr[x]; /* Point to array we just declared */
+ sprintf(fnval,"%d",k); /* SAFE */
+ }
+#ifdef OS2
+ if (ap) { /* We are making an array */
+ int i;
+ char tmp[16];
+ ap[0] = NULL; /* Containing number of files */
+ makestr(&(ap[0]),ckitoa(k));
+
+ ckstrncpy(tmp,fnval,16); /* Save return value */
+
+ for (i = 1; i <= k; i++) { /* Fill it */
+ ap[i] = NULL;
+ znext(fnval); /* Next filename */
+ if (!*fnval) /* No more, done */
+ break; /* In case a premature end */
+ makestr(&(ap[i]),fnval);
+ }
+#ifdef ZXREWIND
+ k = zxrewind(); /* Reset the file expansion */
+#else
+ k = nzxpand(bp[0],xflags);
+#endif /* ZXREWIND */
+ ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
+ }
+#else /* OS2 */
+ { /* Make copies of the list */
+ int i; char tmp[16];
+ if (flist) { /* Free old file list, if any */
+ for (i = 0; flist[i]; i++) { /* and each string */
+ free(flist[i]);
+ flist[i] = NULL;
+ }
+ free((char *)flist);
+ }
+ ckstrncpy(tmp,fnval,16); /* Save our return value */
+ flist = (char **) malloc((k+1) * sizeof(char *)); /* New array */
+ if (flist) {
+ for (i = 0; i <= k; i++) { /* Fill it */
+ flist[i] = NULL;
+ znext(fnval); /* Next filename */
+ if (!*fnval) /* No more, done */
+ break;
+ makestr(&(flist[i]),fnval);
+ }
+ if (ap) { /* If array pointer given */
+ ap[0] = NULL;
+ makestr(&(ap[0]),ckitoa(k));
+ for (i = 0; i < k; i++) { /* Copy file list to array */
+ ap[i+1] = NULL;
+ makestr(&(ap[i+1]),flist[i]);
+ }
+ }
+ }
+ ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
+ flistn = 0; /* Reset global list pointer */
+ }
+#endif /* OS2 */
+#ifdef RECURSIVE
+ recursive = rsave;
+#endif /* RECURSIVE */
+#ifdef OS2
+ zxpn = zsave;
+#endif /* OS2 */
+ }
+ goto fnend;
+
+ case FN_FIL: /* \fnextfile() - Next file in list. */
+ p = fnval; /* (no args) */
+ *p = NUL;
+#ifdef OS2
+ zxpn = 1; /* OS/2 - use the alternate list */
+ znext(p); /* Call system-dependent function */
+ zxpn = zsave; /* Restore original list */
+#else
+ if (flist) /* Others, use our own list. */
+ if (flist[flistn])
+ p = flist[flistn++];
+#endif /* OS2 */
+ goto fnend;
+
+ } /* Break up big switch... */
+
+ switch (cx) {
+ case FN_IND: /* \findex(s1,s2,start,occurrence) */
+ case FN_RIX: /* \frindex(s1,s2,start,occurrence) */
+ case FN_SEARCH: /* \fsearch(pat,string,start,occ) */
+ case FN_RSEARCH: /* \frsearch(pat,string,start,occ) */
+ case FN_COUNT: { /* \fcount(s1,s2,start) */
+ int i = 0, right = 0, search = 0, count = 0;
+ int desired = 1;
+ right = (cx == FN_RIX || cx == FN_RSEARCH);
+ search = (cx == FN_SEARCH || cx == FN_RSEARCH);
+ count = (cx == FN_COUNT);
+ p = "0";
+ if (argn > 1) { /* Only works if we have 2 or 3 args */
+ int start = 0;
+ char * pat = NULL;
+ len1 = (int)strlen(pat = bp[0]); /* length of string to look for */
+ len2 = (int)strlen(s = bp[1]); /* length of string to look in */
+ if (len1 < 1 || len2 < 1) /* Watch out for empty strings */
+ goto fnend;
+ start = right ? -1 : 0; /* Default starting position */
+ if (argn > 2) {
+ val1 = *(bp[2]) ? evalx(bp[2]) : "1";
+ if (argn > 3) {
+ val2 = *(bp[3]) ? evalx(bp[3]) : "1";
+ if (chknum(val2)) desired = atoi(val2);
+ if (desired * len1 > len2) goto fnend;
+ }
+ if (chknum(val1)) {
+ int t;
+ t = atoi(val1);
+ if (!search) { /* Index or Rindex */
+ j = len2 - len1; /* Length difference */
+ t--; /* Convert position to 0-based */
+ if (t < 0) t = 0;
+ start = t;
+ if (!right && start < 0) start = 0;
+ } else { /* Search or Rsearch */
+ int x;
+ if (t < 0) t = 0;
+ if (right) { /* Right to left */
+ if (t > len2) t = len2;
+ start = len2 - t - 1;
+ if (start < 0)
+ goto fnend;
+ x = len2 - t;
+ s[x] = NUL;
+ } else { /* Left to right */
+ start = t - 1;
+ if (start < 0) start = 0;
+ if (start >= len2)
+ goto fnend;
+ }
+ }
+ } else {
+ failed = 1;
+ evalerr(fn);
+ p = fnval;
+ goto fnend;
+ }
+ }
+ if (count) { /* \fcount() */
+ int j;
+ for (i = 0; start < len2; i++) {
+ j = ckindex(pat,bp[1],start,0,inpcas[cmdlvl]);
+ if (j == 0) break;
+ start = j;
+ }
+
+ } else if (search) { /* \fsearch() or \frsearch() */
+
+ if (right && pat[0] == '^') {
+ right = 0;
+ start = 0;
+ }
+ if (right) { /* From right */
+ int k, j = 1;
+ if (start < 0)
+ start = len2 - 1;
+ i = 0;
+ while (start >= 0 && j <= desired) {
+ for (i = start;
+ (i >= 0) &&
+ !(k = ckmatch(pat,s+i,inpcas[cmdlvl],1+4));
+ i--) ;
+ if (k < 1) { /* No match */
+ i = 0;
+ break;
+ }
+ if (j == desired) { /* The match we want? */
+ i += k; /* Yes, return string index */
+ break;
+ }
+ j++; /* No, count this match */
+ s[i] = NUL; /* null it out */
+ start = i-1; /* move left and look again */
+ }
+
+ } else { /* From left */
+ int j;
+ i = 0;
+ for (j = 1; j <= desired && start < len2; j++) {
+ i = ckmatch(pat,&s[start],inpcas[cmdlvl],1+4);
+ if (i == 0 || j == desired) break;
+ start += i + 1;
+ }
+ if (j == desired && i != 0)
+ i += start;
+ else
+ i = 0;
+ }
+ } else { /* index or rindex */
+ int j = 0;
+ i = 0;
+ for (j = 1; j <= desired && start < len2; j++) {
+ i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]);
+ if (i == 0 || j == desired) break;
+ start = (right) ? len2 - i + 1 : i;
+ }
+ if (j != desired)
+ i = 0;
+ }
+ sprintf(fnval,"%d",i); /* SAFE */
+ p = fnval;
+ }
+ goto fnend;
+ }
+
+ case FN_RPL: /* \freplace(s1,s2,s3) */
+ /*
+ s = bp[0] = source string
+ bp[1] = match string
+ bp[2] = replacement string
+ bp[3] = which occurrence (default = all);
+ p = fnval = destination (result) string
+ */
+ if (argn < 1) /* Nothing */
+ goto fnend;
+ if (argn < 2) { /* Only works if we have 2 or 3 args */
+ ckstrncpy(p,bp[0],FNVALL);
+ } else {
+ int occur = 0, xx = 0, j2;
+ len1 = (int)strlen(bp[0]); /* length of string to look in */
+ len2 = (int)strlen(bp[1]); /* length of string to look for */
+ len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
+ j = len1 - len2 + 1;
+ j2 = j;
+ if (argn > 3) {
+ if (chknum(bp[3])) {
+ occur = atoi(bp[3]);
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ /* If args out of whack... */
+ if (j < 1 || len1 == 0 || len2 == 0) {
+ ckstrncpy(p,bp[0],FNVALL); /* just return original string */
+ p[FNVALL] = NUL;
+ } else {
+ ragain:
+ s = bp[0]; /* Point to beginning of string */
+ while (j-- > 0) { /* For each character */
+ if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl]) &&
+ (occur == 0 || occur == ++xx)) {
+ if (len3) {
+ ckstrncpy(p,bp[2],FNVALL);
+ p += len3;
+ }
+ s += len2; /* and skip past it. */
+ } else { /* No, */
+ *p++ = *s++; /* just copy this character */
+ }
+ }
+ *p = NUL;
+ while ((*p++ = *s++));
+ if (occur < 0) { /* cheap... */
+ occur = xx + occur + 1;
+ xx = 0;
+ p = fnval;
+ j = j2;
+ if (occur > 0)
+ goto ragain;
+ }
+ }
+ }
+ p = fnval;
+ goto fnend;
+
+ case FN_CHR: /* \fcharacter(arg1) */
+ val1 = *(bp[0]) ? evalx(bp[0]) : "";
+ if (chknum(val1)) { /* Must be numeric */
+ i = atoi(val1);
+ if (i >= 0 && i < 256) { /* Must be an 8-bit value */
+ p = fnval;
+ *p++ = (char) i;
+ *p = NUL;
+ p = fnval;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ }
+ } else {
+ failed = 1;
+ evalerr(fn);
+ }
+ goto fnend;
+
+ case FN_COD: /* \fcode(char) */
+ if ((int)strlen(bp[0]) > 0) {
+ p = fnval;
+ i = *bp[0];
+ sprintf(p,"%d",(i & 0xff)); /* SAFE */
+ } else p = "0"; /* Can't happen */
+ goto fnend;
+
+ case FN_LEN: /* \flength(arg1) */
+ if (argn > 0) {
+ p = fnval;
+ sprintf(p,"%d",(int)strlen(bp[0])); /* SAFE */
+ } else p = "0";
+ goto fnend;
+
+ case FN_LOW: /* \flower(arg1) */
+ s = bp[0] ? bp[0] : "";
+ p = fnval;
+ while (*s) {
+ if (isupper(*s))
+ *p = (char) tolower(*s);
+ else
+ *p = *s;
+ p++; s++;
+ }
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+
+ case FN_MAX: /* \fmax(arg1,arg2) */
+ case FN_MIN: /* \fmin(arg1,arg2) */
+ case FN_MOD: /* \fmod(arg1,arg2) */
+ val1 = *(bp[0]) ? evalx(bp[0]) : "";
+#ifdef COMMENT
+ /* No longer necessary because evalx() no longer overwrites its */
+ /* result every time it's called (2000/09/23). */
+ free(bp[0]);
+ bp[0] = NULL;
+#endif /* COMMENT */
+ if (argn > 1) {
+#ifdef COMMENT
+ /* Ditto... */
+ bp[0] = malloc((int)strlen(val1)+1);
+ if (bp[0])
+ strcpy(bp[0],val1); /* safe */
+ val1 = bp[0];
+#endif /* COMMENT */
+ val2 = *(bp[1]) ? evalx(bp[1]) : "";
+ if (chknum(val1) && chknum(val2)) {
+ i = atoi(val1);
+ j = atoi(val2);
+ switch (y) {
+ case FN_MAX:
+ if (j < i) j = i;
+ break;
+ case FN_MIN:
+ if (j > i) j = i;
+ break;
+ case FN_MOD:
+ if (j == 0) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
+ else
+ fnval[0] = NUL;
+ goto fnend;
+ } else
+ j = i % j;
+ }
+ p = fnval;
+ sprintf(p,"%d",j); /* SAFE */
+ } else {
+ failed = 1;
+ evalerr(fn);
+ }
+ } else p = val1;
+ goto fnend;
+ } /* Break up big switch... */
+
+ switch (y) {
+ case FN_SUB: /* \fsubstr(arg1,arg2,arg3) */
+ case FN_RIG: /* \fright(arg1,arg2) */
+ case FN_LEF: /* \fleft(arg1,arg2) */
+ if (argn < 1)
+ goto fnend;
+ val1 = "";
+ if (argn > 1)
+ if (*(bp[1]))
+ val1 = evalx(bp[1]);
+#ifdef COMMENT
+ if (bp[1]) free(bp[1]); /* Have to copy this */
+ bp[1] = malloc((int)strlen(val1)+1);
+ if (!bp[1]) {
+ failed = 1;
+ if (fndiags) {
+ p = fnval;
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+ strcpy(bp[1],val1); /* safe */
+ val1 = bp[1];
+#endif /* COMMENT */
+ val2 = "";
+ if (argn > 2)
+ if (*(bp[2]))
+ val2 = evalx(bp[2]);
+ if (
+ ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) ||
+ ((cx == FN_SUB) &&
+ ((argn > 2) && (int)strlen(val2) && !rdigits(val2)))
+ ) {
+ failed = 1;
+ evalerr(fn);
+ } else {
+ int lx;
+ p = fnval; /* pointer to result */
+ lx = strlen(bp[0]); /* length of arg1 */
+ if (cx == FN_SUB) { /* substring */
+ k = (argn > 2) ? atoi(val2) : MAXARGLEN; /* length */
+ j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */
+ } else if (cx == FN_LEF) { /* left */
+ k = (argn > 1) ? atoi(val1) : lx;
+ j = 1;
+ } else { /* right */
+ k = (argn > 1) ? atoi(val1) : lx; /* length */
+ j = lx - k + 1; /* start pos for right */
+ if (j < 1) j = 1;
+ }
+ if (k > 0 && j <= lx) { /* if start pos in range */
+ s = bp[0]+j-1; /* point to source string */
+ for (i = 0; (i < k) && (*p++ = *s++); i++) ; /* copy */
+ }
+ *p = NUL; /* terminate the result */
+ p = fnval; /* and point to it. */
+ }
+ goto fnend;
+
+ case FN_UPP: /* \fupper(arg1) */
+ s = bp[0] ? bp[0] : "";
+ p = fnval;
+ while (*s) {
+ if (islower(*s))
+ *p = (char) toupper(*s);
+ else
+ *p = *s;
+ p++; s++;
+ }
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+
+ case FN_REP: /* \frepeat(text,number) */
+ if (argn < 1)
+ goto fnend;
+ val1 = "1";
+ if (argn > 1)
+ if (*(bp[1]))
+ val1 = evalx(bp[1]);
+ if (chknum(val1)) { /* Repeat count */
+ n = atoi(val1);
+ debug(F111,"SUNDAY frepeat n",val1,n);
+ if (n > 0) { /* Make n copies */
+ p = fnval;
+ *p = '\0';
+ k = (int)strlen(bp[0]); /* Make sure string has some length */
+ debug(F111,"SUNDAY frepeat k","",k);
+ debug(F111,"SUNDAY frepeat FNVALL","",FNVALL);
+ if (k * n >= FNVALL) { /* But not too much... */
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
+ else
+ fnval[0] = NUL;
+ p = fnval;
+ goto fnend;
+ }
+ if (k > 0) { /* If there is something to copy */
+ for (i = 0; i < n; i++) { /* Copy loop */
+ s = bp[0];
+ for (j = 0; j < k; j++) {
+ if ((p - fnval) >= FNVALL)
+ break; /* shouldn't happen... */
+ else
+ *p++ = *s++;
+ }
+ }
+ *p = NUL;
+ }
+ }
+ } else {
+ failed = 1;
+ evalerr(fn);
+ }
+ p = fnval;
+ goto fnend;
+
+#ifndef NOFRILLS
+ case FN_REV: /* \freverse() */
+ if (argn < 1)
+ goto fnend;
+ yystring(bp[0],&p);
+ goto fnend;
+#endif /* NOFRILLS */
+
+ case FN_RPA: /* \frpad() and \flpad() */
+ case FN_LPA:
+ if (argn < 1)
+ goto fnend;
+ val1 = "";
+ if (argn > 1)
+ if (*(bp[1]))
+ val1 = evalx(bp[1]);
+ if (argn == 1) { /* If a number wasn't given */
+ p = fnval; /* just return the original string */
+ ckstrncpy(p,bp[0],FNVALL);
+ } else if (argn > 1 && !*val1) {
+ failed = 1;
+ evalerr(fn);
+ } else /* if (chknum(val1)) */ { /* Repeat count */
+ char pc;
+ n = atoi(val1);
+ if (n >= 0) {
+ p = fnval;
+ k = (int)strlen(bp[0]); /* Length of string to be padded */
+ if (k >= n) { /* It's already long enough */
+ ckstrncpy(p,bp[0],FNVALL);
+ } else {
+ if (n + k <= FNVALL) {
+ pc = (char) ((argn < 3) ? SP : *bp[2]);
+ if (!pc) pc = SP;
+ if (cx == FN_RPA) { /* RPAD */
+ strncpy(p,bp[0],k); /* (leave it like this) */
+ p[k] = NUL;
+ p += k;
+ for (i = k; i < n; i++)
+ *p++ = pc;
+ } else { /* LPAD */
+ n -= k;
+ for (i = 0; i < n; i++)
+ *p++ = pc;
+ strncpy(p,bp[0],k); /* (leave it like this) */
+ p[k] = NUL;
+ p += k;
+ }
+ }
+ *p = NUL;
+ }
+ }
+ }
+ p = fnval;
+ goto fnend;
+
+#ifdef ZFCDAT
+ case FN_FD: /* \fdate(filename) */
+ p = fnval;
+ s = zfcdat(bp[0]);
+ if (!s) s = "";
+ if (!*s) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ ckstrncpy(fnval,s,FNVALL);
+#endif /* ZFCDAT */
+ goto fnend;
+
+ } /* Break up big switch... */
+
+ switch (y) {
+ case FN_FS: { /* \fsize(filename) */
+ CK_OFF_T z;
+ p = fnval;
+ z = zchki(bp[0]);
+ if (z < (CK_OFF_T)0) {
+ failed = 1;
+ if (fndiags) {
+ if (z == (CK_OFF_T)-1)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
+ else if (z == (CK_OFF_T)-2)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
+ else if (z == (CK_OFF_T)-3)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
+ else
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+ ckstrncpy(fnval,ckfstoa(z),FNVALL);
+ goto fnend;
+ }
+ case FN_VER: /* \fverify() */
+ p = "-1";
+ if (argn == 1) /* No second arg */
+ goto fnend;
+ else if (!bp[1]) /* Or second arg null */
+ goto fnend;
+ else if (!*(bp[1])) /* or empty. */
+ goto fnend;
+ p = "0";
+ if (argn > 1) { /* Only works if we have 2 or 3 args */
+ int start;
+ char *s2, ch1, ch2;
+ start = 0;
+ if (argn > 2) { /* Starting position specified */
+ val1 = *(bp[2]) ? evalx(bp[2]) : "0";
+ if (chknum(val1)) {
+ start = atoi(val1) /* - 1 */;
+ if (start < 0) start = 0;
+ if (start > (int)strlen(bp[1]))
+ goto verfin;
+ } else {
+ failed = 1;
+ evalerr(fn);
+ goto fnend;
+ }
+ }
+ i = start;
+ p = "0";
+ for (s = bp[1] + start; *s; s++,i++) {
+ ch1 = *s;
+ if (!inpcas[cmdlvl]) if (islower(ch1)) ch1 = toupper(ch1);
+ j = 0;
+ for (s2 = bp[0]; *s2; s2++) {
+ ch2 = *s2;
+ if (!inpcas[cmdlvl]) if (islower(ch2)) ch2 = toupper(ch2);
+ if (ch1 == ch2) {
+ j = 1;
+ break;
+ }
+ }
+ if (j == 0) {
+ sprintf(fnval,"%d",i+1); /* SAFE */
+ p = fnval;
+ break;
+ }
+ }
+ }
+ verfin:
+ goto fnend;
+
+ case FN_IPA: /* Find and return IP address */
+ if (argn > 0) { /* in argument string. */
+ int start = 0;
+ if (argn > 1) { /* Starting position specified */
+ if (chknum(bp[1])) {
+ start = atoi(bp[1]) - 1;
+ if (start < 0) start = 0;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ p = getip(bp[0]+start);
+ } else p = "";
+ goto fnend;
+
+#ifdef OS2
+ case FN_CRY:
+ p = "";
+ if (argn > 0) {
+ p = fnval;
+ ckstrncpy(p,bp[0],FNVALL);
+ ck_encrypt(p);
+ }
+ goto fnend;
+
+ case FN_OOX:
+ p = "";
+ if (argn > 0)
+ p = (char *) ck_oox(bp[0], (argn > 1) ? bp[1] : "");
+ goto fnend;
+#endif /* OS2 */
+
+ case FN_HEX: /* \fhexify(arg1) */
+ if (argn < 1)
+ goto fnend;
+ if ((int)strlen(bp[0]) < (FNVALL / 2)) {
+ s = bp[0];
+ p = fnval;
+ while (*s) {
+ x = (*s >> 4) & 0x0f;
+ *p++ = hexdigits[x];
+ x = *s++ & 0x0f;
+ *p++ = hexdigits[x];
+ }
+ *p = NUL;
+ p = fnval;
+ }
+ goto fnend;
+
+ case FN_UNTAB: /* \funtab(arg1) */
+ if (argn < 1)
+ goto fnend;
+ if ((int)strlen(bp[0]) < (FNVALL * 2)) {
+ s = bp[0];
+ p = fnval;
+ if (untabify(bp[0],p,FNVALL) < 0) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:OVERFLOW:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+
+ case FN_UNH: { /* \funhex(arg1) */
+ int c[2], i;
+ if (argn < 1)
+ goto fnend;
+ if ((int)strlen(bp[0]) < (FNVALL * 2)) {
+ s = bp[0];
+ p = fnval;
+ while (*s) {
+ for (i = 0; i < 2; i++) {
+ c[i] = *s++;
+ if (!c[i]) { p = ""; goto unhexfin; }
+ if (islower(c[i])) c[i] = toupper(c[i]);
+ if (c[i] >= '0' && c[i] <= '9') {
+ c[i] -= 0x30;
+ } else if (c[i] >= 'A' && c[i] <= 'F') {
+ c[i] -= 0x37;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,
+ FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",
+ fn,
+ "()>",
+ NULL
+ );
+ goto fnend;
+ }
+ }
+ *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f);
+ }
+ *p = NUL;
+ p = fnval;
+ }
+ unhexfin:
+ goto fnend;
+ }
+
+ case FN_BRK: { /* \fbreak() */
+ char * c; /* Characters to break on */
+ char c2, s2;
+ int start = 0;
+ int done = 0;
+ if (argn < 1)
+ goto fnend;
+ if (argn > 2) {
+ s = bp[2] ? bp[2] : "0";
+ if (chknum(s)) {
+ start = atoi(s);
+ if (start < 0) start = 0;
+ if (start > (int)strlen(bp[0]))
+ goto brkfin;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ s = bp[0] + start; /* Source pointer */
+
+ while (*s && !done) {
+ s2 = *s;
+ if (!inpcas[cmdlvl] && islower(s2)) s2 = toupper(s2);
+ c = bp[1] ? bp[1] : ""; /* Character to break on */
+ while (*c) {
+ c2 = *c;
+ if (!inpcas[cmdlvl] && islower(c2)) c2 = toupper(c2);
+ if (c2 == s2) {
+ done = 1;
+ break;
+ }
+ c++;
+ }
+ if (done) break;
+ *p++ = *s++;
+ }
+ *p = NUL; /* terminate the result */
+ p = fnval; /* and point to it. */
+ brkfin:
+ goto fnend;
+ }
+
+ case FN_SPN: { /* \fspan() */
+ char *q;
+ char c1, c2;
+ int start = 0;
+ if (argn < 1)
+ goto fnend;
+ if (argn > 2) { /* Starting position */
+ s = bp[2] ? bp[2] : "0";
+ if (chknum(s)) {
+ start = atoi(s);
+ if (start < 0) start = 0;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ s = bp[0] + start; /* Source pointer */
+ if (argn > 1 &&
+ (int)strlen(bp[1]) > 0 &&
+ start <= (int)strlen(bp[0])) {
+ while (*s) { /* Loop thru source string */
+ q = bp[1]; /* Span string */
+ c1 = *s;
+ if (!inpcas[cmdlvl])
+ if (islower(c1)) c1 = toupper(c1);
+ x = 0;
+ while ((c2 = *q++)) {
+ if (!inpcas[cmdlvl])
+ if (islower(c2)) c2 = toupper(c2);
+ if (c1 == c2) { x = 1; break; }
+ }
+ if (!x) break;
+ *p++ = *s++;
+ }
+ *p = NUL; /* Terminate and return the result */
+ p = fnval;
+ }
+ goto fnend;
+ }
+ } /* Break up big switch... */
+
+ switch (y) {
+ case FN_TRM: /* \ftrim(s1[,s2]) */
+ case FN_LTR: /* \fltrim(s1[,s2]) */
+ if (argn < 1)
+ goto fnend;
+ if ((len1 = (int)strlen(bp[0])) > 0) {
+ if (len1 > FNVALL)
+ len1 = FNVALL;
+ s = " \t\r\n";
+ if (argn > 1) /* Trim list given */
+ s = bp[1];
+ len2 = (int)strlen(s);
+ if (len2 < 1) { /* or not... */
+ s = " \t\r\n"; /* Default is to trim whitespace */
+ len2 = 2;
+ }
+ if (cx == FN_TRM) { /* Trim from right */
+ char * q, p2, q2;
+ ckstrncpy(fnval,bp[0],FNVALL); /* Copy string to output */
+ p = fnval + len1 - 1; /* Point to last character */
+
+ while (p >= (char *)fnval) { /* Go backwards */
+ q = s; /* Point to trim list */
+ p2 = *p;
+ if (!inpcas[cmdlvl])
+ if (islower(p2)) p2 = toupper(p2);
+ while (*q) { /* Is this char in trim list? */
+ q2 = *q;
+ if (!inpcas[cmdlvl])
+ if (islower(q2)) q2 = toupper(q2);
+ if (p2 == q2) { /* Yes, null it out */
+ *p = NUL;
+ break;
+ }
+ q++;
+ }
+ if (!*q) /* Trim list exhausted */
+ break; /* So we're done. */
+ p--; /* Else keep trimming */
+ }
+ } else { /* Trim from left */
+ char * q, p2, q2;
+ p = bp[0]; /* Source */
+ while (*p) {
+ p2 = *p;
+ if (!inpcas[cmdlvl])
+ if (islower(p2)) p2 = toupper(p2);
+ q = s;
+ while (*q) { /* Is this char in trim list? */
+ q2 = *q;
+ if (!inpcas[cmdlvl])
+ if (islower(q2)) q2 = toupper(q2);
+ if (p2 == q2) { /* Yes, point past it */
+ p++; /* and try next source character */
+ break;
+ }
+ q++; /* No, try next trim character */
+ }
+ if (!*q) /* Trim list exhausted */
+ break; /* So we're done. */
+ }
+ ckstrncpy(fnval,p,FNVALL);
+ }
+ p = fnval;
+ } else p = "";
+ goto fnend;
+
+ case FN_CAP: /* \fcapitalize(arg1) */
+ if (argn < 1)
+ goto fnend;
+ s = bp[0];
+ p = fnval;
+ x = 0;
+ while ((c = *s++)) {
+ if (isalpha(c)) {
+ if (x == 0) {
+ x = 1;
+ if (islower(c))
+ c = toupper(c);
+ } else if (isupper(c))
+ c = tolower(c);
+ }
+ *p++ = c;
+ }
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+
+#ifdef COMMENT
+ case FN_TOD: /* Time of day to secs since midnite */
+ sprintf(fnval,"%ld",tod2sec(bp[0])); /* SAFE */
+ goto fnend;
+#endif /* COMMENT */
+
+ case FN_FFN: /* Full pathname of file */
+ zfnqfp(bp[0],FNVALL,p);
+ if (!p) p = "";
+ goto fnend;
+
+ case FN_CHK: { /* \fchecksum() */
+ long chk = 0;
+ p = (argn > 0) ? bp[0] : "";
+ while (*p) chk += *p++;
+ sprintf(fnval,"%lu",chk); /* SAFE */
+ p = fnval;
+ goto fnend;
+ }
+
+#ifndef NOXFER
+ case FN_CRC: /* \fcrc16() */
+ if (argn > 0)
+ sprintf(fnval,"%u", /* SAFE */
+ chk3((CHAR *)bp[0],(int)strlen(bp[0])));
+ else
+ p = "0";
+ goto fnend;
+#endif /* NOXFER */
+
+ case FN_BSN: /* \fbasename() */
+ zstrip(bp[0],&p);
+ goto fnend;
+
+#ifndef NOLOCAL
+#ifdef OS2
+ case FN_SCRN_CX: /* \fscrncurx() */
+ p = fnval;
+ sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->x); /* SAFE */
+ goto fnend;
+
+ case FN_SCRN_CY: /* \fscrncury() */
+ p = fnval;
+ sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->y); /* SAFE */
+ goto fnend;
+
+ case FN_SCRN_STR: { /* \fscrnstr() */
+ videoline * line = NULL;
+ viocell * cells = NULL;
+ int row = 0, col = 0, len = 0;
+ /* NOTE: On Unicode systems, the screen contents are stored in */
+ /* in Unicode. Therefore, we should really be performing a */
+ /* conversion to the local character set. */
+
+ /* 6/18/2000 - added the translation to lcs */
+
+ if (bp[0] == NULL || bp[0][0] == '\0') {
+ row = 0;
+ } else {
+ if (chknum(bp[0])) {
+ row = atoi(bp[0]);
+ if (row < 0)
+ row = 0;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ line = VscrnGetLineFromTop( VTERM, (USHORT) row );
+ if (line != NULL) {
+ if (bp[1] == NULL || bp[1][0] == '\0')
+ col = 0;
+ else {
+ if (chknum(bp[0])) {
+ col = atoi(bp[1]);
+ if (col < 0 || col >= line->width)
+ col = 0;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ if (bp[2] == NULL || bp[2][0] == '\0') {
+ len = line->width - (col+1);
+ } else {
+ if (!chknum(bp[2])) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ len = atoi(bp[2]);
+ if (len < 0 || len > line->width)
+ len = line->width;
+ }
+ cells = line->cells;
+ for (i = 0; i < len; i++) {
+ int pos = i + col;
+ if (pos < line->width) {
+ if (isunicode())
+ fnval[i] = (CHAR) utolxlat(cells[pos].c);
+ else
+ fnval[i] = (CHAR) (cells[pos].c & 0xFF);
+ if (fnval[i] == 0)
+ fnval[i] = SP;
+ } else
+ fnval[i] = SP;
+ }
+ fnval[i] = '\0';
+ } else {
+ fnval[0] = '\0';
+ }
+ p = fnval;
+ goto fnend;
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifndef NOPUSH
+ case FN_RAW: /* \frawcommand() */
+ case FN_CMD: { /* \fcommand() */
+ int x, c, n = FNVALL;
+ x = 0; /* Completion flag */
+/*
+ ZIFILE can be safely used because we can't possibly be transferring a file
+ while executing this function.
+*/
+ if (!nopush && zxcmd(ZIFILE,bp[0]) > 0) { /* Open the command */
+ while (n-- > -1) { /* Read from it */
+ if ((c = zminchar()) < 0) {
+ x = 1; /* EOF - set completion flag */
+ if (cx == FN_CMD) { /* If not "rawcommand" */
+ p--; /* remove trailing newlines */
+ while (*p == CR || *p == LF)
+ p--;
+ p++;
+ }
+ *p = NUL; /* Terminate the string */
+ break;
+ } else /* Command still running */
+ *p++ = c; /* Copy the bytes */
+ }
+ zclose(ZIFILE); /* Close the command */
+ }
+ /* Return null string if command's output was too long. */
+ p = fnval;
+ if (!x) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+#endif /* NOPUSH */
+ } /* Break up big switch... */
+
+ switch (y) {
+ case FN_STX: /* \fstripx(string,c) */
+ if (!(s = bp[0])) /* Make sure there is a string */
+ goto fnend;
+ c = '.'; /* Character to strip from */
+ if (argn > 1) if (*bp[1]) c = *bp[1];
+ n = ckstrncpy(fnval,bp[0],FNVALL);
+ while (--n >= 0) {
+ if (fnval[n] == c) {
+ fnval[n] = NUL;
+ break;
+ }
+ }
+ p = fnval;
+ goto fnend;
+
+ case FN_STL: /* \flop(string,c) */
+ case FN_LOPX: { /* \flopx(string,c) */
+ int n = 1;
+ if (!(s = bp[0])) /* Make sure there is a string */
+ goto fnend;
+ c = '.'; /* Character to strip to */
+ if (argn > 1) if (*bp[1]) c = *bp[1];
+ if (argn > 2) if (*bp[2]) {
+#ifndef NOFLOAT
+ n = 0;
+ if (isfloat(bp[2],0)) {
+ n = (int)floatval;
+ if (n < 0) n = 0;
+ } else
+#endif /* NOFLOAT */
+ n = atoi(bp[2]);
+ }
+ x = 0;
+ if (cx == FN_LOPX) { /* Lopx (from right) */
+ if (n == 0)
+ goto fnend;
+ s += strlen(s) - 1; /* We already know it's > 0 */
+ while (s-- >= bp[0]) {
+ if (*s == c) {
+ n--;
+ if (n == 0) {
+ s++;
+ x = 1;
+ break;
+ }
+ }
+ }
+ if (!x) s = "";
+ } else { /* Lop (from left) */
+ if (n == 0) {
+ p = bp[0];
+ goto fnend;
+ }
+ while (*s++) {
+ if (*(s-1) == c) {
+ if (--n == 0) {
+ x = 1;
+ break;
+ }
+ }
+ }
+ if (!x) s = bp[0];
+ }
+ ckstrncpy(fnval,s,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+ case FN_STN: /* \fstripn(string,n) */
+ if (argn < 1) /* Remove n chars from right */
+ goto fnend;
+ val1 = "0";
+ if (argn > 1)
+ if (*(bp[1]))
+ val1 = evalx(bp[1]);
+ if (!chknum(val1)) {
+ failed = 1;
+ evalerr(fn);
+ goto fnend;
+ }
+ n = atoi(val1);
+ if (n < 0) n = 0;
+ k = (int)strlen(s = bp[0]) - n;
+ if (k < 0) k = 0;
+ p = fnval;
+ while (k-- > 0)
+ *p++ = *s++;
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+
+ case FN_STB: { /* \fstripb(string,c) */
+ char c2 = NUL;
+ int i, k = 0;
+ char * gr_opn = "\"{'([<"; /* Group open brackets */
+ char * gr_cls = "\"}')]>"; /* Group close brackets */
+
+ p = fnval;
+ *p = NUL;
+ if (!(s = bp[0])) /* Make sure there is a string */
+ goto fnend;
+ if ((x = strlen(s)) < 1)
+ goto fnend;
+ c = NUL; /* Brace/bracket kind */
+ if (argn > 1) {
+ if (*bp[1]) {
+ if (chknum(bp[1])) {
+ k = atoi(bp[1]);
+ if (k < 0) k = 63;
+ for (i = 0; i < 6; i++) {
+ if (k & (1<<i)) {
+ if (s[0] == gr_opn[i] && s[x-1] == gr_cls[i]) {
+ ckstrncpy(fnval,s+1,FNVALL);
+ fnval[x-2] = NUL;
+ goto fnend;
+ }
+ }
+ }
+ ckstrncpy(fnval,s,FNVALL); /* No match */
+ goto fnend;
+ }
+ }
+ }
+ c = !bp[1] ? 0 : *bp[1];
+ if (!c) c = s[0];
+ if (argn > 2) if (*bp[2]) c2 = *bp[2];
+ if (*s == c) {
+ if (!c2) {
+ switch (c) {
+ case '(': c2 = ')'; break;
+ case '[': c2 = ']'; break;
+ case '{': c2 = '}'; break;
+ case '<': c2 = '>'; break;
+ case '"': c2 = '"'; break;
+ case 39: c2 = 39; break;
+ case 96: c2 = 39; break;
+ default:
+ if (argn == 2) {
+ c2 = c;
+ } else {
+ strncpy(fnval,s,x); /* Leave it like this */
+ fnval[x] = NUL;
+ goto fnend;
+ }
+ }
+ }
+ if (s[x-1] == c2) {
+ strncpy(fnval,s+1,x-2); /* Leave it like this */
+ fnval[x-2] = NUL;
+ goto fnend;
+ }
+ }
+ strncpy(fnval,s,x);
+ fnval[x] = NUL;
+ goto fnend;
+ }
+
+ case FN_2HEX: /* Number to hex */
+ case FN_2OCT: /* Number to octal */
+ val1 = evalx(bp[0]);
+ if (!*val1) {
+ failed = 1;
+ evalerr(fn);
+ goto fnend;
+ }
+ sprintf(fnval, cx == FN_2HEX ? "%lx" : "%lo", atol(val1)); /* SAFE */
+ if (cx == FN_2HEX && (int)(strlen(fnval)&1))
+ sprintf(fnval,"0%lx",atol(val1)); /* SAFE */
+ p = fnval;
+ goto fnend;
+
+ case FN_DNAM: { /* Directory part of file name */
+ char *s;
+ zfnqfp(bp[0],FNVALL,p); /* Get full name */
+ if (!isdir(p)) { /* Is it already a directory? */
+ zstrip(p,&s); /* No get basename */
+ if (*s) {
+ x = ckindex(s,p,0,0,0); /* Pos of latter in former */
+ if (x > 0) p[x-1] = NUL;
+ }
+ }
+ if (!p) p = "";
+ goto fnend;
+ }
+
+#ifndef NORANDOM
+ case FN_RAND: /* Random number */
+#ifdef CK_SSL
+ if (RAND_bytes((unsigned char *)&k,sizeof(k)) < 0)
+#endif /* CK_SSL */
+ k = rand();
+ x = 0;
+ if (argn > 0) {
+ if (!chknum(bp[0])) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ x = atoi(bp[0]);
+ }
+#ifdef COMMENT
+ sprintf(fnval,"%d", (x > 0 && k > 0) || (x < 0 && k < 0) ? k % x :
+ (x == 0 ? 0 : (0 - (k % (-x)))));
+#else
+ debug(F111,"rand",ckitoa(x),k);
+#ifdef SUNOS4
+/* This is really strange but on SunOS, if we are requesting random numbers */
+/* between 0 and 4 or less, they always come out in sequence: 0 1 2 3 0 1 2 */
+/* Shifting the result of rand() in this case gives a more random result. */
+ if (x < 5)
+ k = k >> 5;
+#endif /* SUNOS4 */
+ if ((x > 0 && k > 0) || (x < 0 && k < 0))
+ x = k % x;
+ else if (x == 0)
+ x = 0;
+ else
+ x = 0 - (k % (-x));
+ debug(F101,"rand x","",x);
+ sprintf(fnval,"%d", x); /* SAFE */
+#endif /* COMMENT */
+ p = fnval;
+ goto fnend;
+#endif /* NORANDOM */
+ } /* Break up big switch... */
+
+ switch (y) {
+ case FN_SPLIT: /* \fsplit(s1,a,s2,s3,mask) */
+ case FN_WORD: { /* \fword(s1,n,s2,s3,mask) */
+ int wordnum = 0;
+ int splitting = 0;
+ int x;
+ int array = 0;
+ int grouping = 0;
+ int nocollapse = 0;
+ char * sep = "";
+ char * notsep = "";
+ char * bp0 = NULL;
+ char * bp1 = NULL;
+ char abuf[16];
+ struct stringarray * q = NULL;
+
+ splitting = (cx == FN_SPLIT); /* Our job */
+ debug(F101,"FN_SPLIT splitting","",splitting);
+
+ fnval[0] = splitting ? '0' : NUL; /* Initial return value */
+ fnval[1] = NUL;
+ p = fnval;
+ bp0 = bp[0]; /* Source string */
+ if (!bp0) bp0 = "";
+ debug(F111,"fsplit bp[0]",bp0,argn);
+ if (argn < 1 || !*bp0) /* If none, return default value */
+ goto fnend;
+
+ bp1 = bp[1]; /* Function-dependent arg */
+ if (!bp1) bp1 = ""; /* (array or number) */
+ debug(F110,"fsplit bp[1]",bp1,0);
+ if (bp[5]) {
+ if (!chknum(bp[5])) {
+ failed = 1;
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ x = atoi(bp[5]);
+ nocollapse = x;
+ }
+ if (!splitting) { /* \fword(): n = desired word number */
+ val1 = "1"; /* Default is first word */
+ if (argn > 1) /* Word number supplied */
+ if (*bp1)
+ val1 = evalx(bp1);
+ if (!chknum(val1)) {
+ failed = 1;
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ n = atoi(val1);
+ } else if (argn > 1 && *bp1) { /* \fsplit(): n = word count */
+ ckstrncpy(abuf,bp1,16); /* Get array reference */
+ debug(F110,"fsplit abuf 1",abuf,0);
+ failed = 1; /* Assume it's bad */
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ if (abuf[0] != '&') /* "Address" of array */
+ goto fnend; /* It's bad */
+ if (abuf[2]) { /* Check for brackets */
+ if (abuf[2] != '[' || abuf[3] != ']') {
+ goto fnend; /* Bad */
+ }
+ }
+ debug(F110,"fsplit abuf 2",abuf,0);
+ if (abuf[1] > 64 && abuf[1] < 91) /* Convert upper to lower */
+ abuf[1] += 32;
+ if (abuf[1] < 97 || abuf[1] > 122) { /* Check for a-z */
+ goto fnend;
+ }
+ debug(F110,"fsplit abuf 3",abuf,0);
+ array = 1;
+ fnval[0] = NUL; /* No error, erase message */
+ failed = 0; /* Unset failure flag */
+ n = 0; /* Initialize word counter */
+ }
+ if (argn > 2) /* Have break set? */
+ sep = bp[2];
+ debug(F111,"fsplit sep",sep,argn);
+ if (argn > 3) /* Have include set? */
+ notsep = bp[3];
+ debug(F111,"fsplit notsep",notsep,argn);
+ if (argn > 4) { /* Have grouping set? */
+ char * bp4 = bp[4];
+ debug(F111,"fsplit bp4",bp4,argn);
+ if (!bp4) bp4 = "0";
+ if (!*bp4) bp4 = "0";
+ if (chknum(bp4)) {
+ grouping = atoi(bp4);
+ if (grouping == -1)
+ grouping = 127;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ /* Args parsed, now do the work */
+
+ debug(F111,"fsplit bp0",bp0,n);
+ q = cksplit(splitting,n,bp0,sep,notsep,grouping,0,nocollapse);
+
+ wordnum = q ? q->a_size : -1; /* Check result */
+ if (wordnum < 0) {
+ failed = 1; /* Failure */
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ (wordnum == -1) ?
+ "<ERROR:MALLOC_FAILURE:\\f" :
+ "<ERROR:TOO_MANY_WORDS:\\f",
+ fn,
+ "()>",
+ NULL
+ );
+ goto fnend;
+ }
+ if (splitting) { /* \fsplit() result */
+ ckstrncpy(fnval,ckitoa(wordnum),FNVALL);
+ if (array) { /* Array was not declared. */
+ int i;
+ if ((x = dclarray(abuf[1],wordnum)) < 0) { /* Declare it. */
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ for (i = 1; i <= wordnum; i++) { /* Copy results */
+ makestr(&(a_ptr[x][i]),q->a_head[i]);
+ }
+ a_ptr[x][0] = NULL; /* Array is 1-based */
+ makestr(&(a_ptr[x][0]),fnval); /* Element = size */
+ }
+ } else { /* \fword() result */
+ char * s;
+ s = q->a_head[1];
+ if (!s) s = "";
+ ckstrncpy(fnval,s,FNVALL);
+ }
+ goto fnend; /* Done */
+ }
+
+ } /* Break up big switch... */
+
+ switch (y) {
+
+#ifdef CK_KERBEROS
+ case FN_KRB_TK: /* Kerberos tickets */
+ case FN_KRB_NX: /* Kerberos next ticket */
+ case FN_KRB_IV: /* Kerberos ticket is valid */
+ case FN_KRB_FG: /* Kerberos Ticket flags */
+ case FN_KRB_TT: { /* Kerberos ticket time */
+ int kv = 0; /* Kerberos version */
+ int n = 0;
+ char * s = NULL;
+ if (rdigits(bp[0])) {
+ kv = atoi(bp[0]);
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (kv != 4 && kv != 5) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if ((cx == FN_KRB_IV || cx == FN_KRB_TT || cx == FN_KRB_FG) &&
+ argn < 2) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ switch (y) {
+ case FN_KRB_TK: /* Number of Kerberos tickets */
+#ifdef CK_AUTHENTICATION
+ switch (kv) {
+ case 4:
+ n = ck_krb4_get_tkts();
+ sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
+ goto fnend;
+ case 5: {
+ extern char * krb5_d_cc;
+ n = ck_krb5_get_tkts(krb5_d_cc);
+ sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
+ goto fnend;
+ }
+ }
+#else
+ sprintf(fnval,"%d",0); /* SAFE */
+#endif /* CK_AUTHENTICATION */
+ goto fnend;
+
+ case FN_KRB_NX: /* Kerberos next ticket */
+#ifdef CK_AUTHENTICATION
+ switch (kv) {
+ case 4:
+ s = ck_krb4_get_next_tkt();
+ ckstrncpy(fnval, s ? s : "",FNVALL);
+ goto fnend;
+ case 5:
+ s = ck_krb5_get_next_tkt();
+ ckstrncpy(fnval, s ? s : "",FNVALL);
+ goto fnend;
+ }
+#else
+ sprintf(fnval,"k%d next-ticket-string",kv); /* SAFE */
+#endif /* CK_AUTHENTICATION */
+ goto fnend;
+
+ case FN_KRB_IV: /* Kerberos ticket is valid */
+#ifdef CK_AUTHENTICATION
+ /* Return 1 if valid, 0 if not */
+ switch (kv) {
+ case 4:
+ n = ck_krb4_tkt_isvalid(bp[1]);
+ sprintf(fnval, "%d", n > 0 ? 1 : 0); /* SAVE */
+ goto fnend;
+ case 5: {
+ extern char * krb5_d_cc;
+ n = ck_krb5_tkt_isvalid(krb5_d_cc,bp[1]);
+ sprintf(fnval,"%d", n > 0 ? 1 : 0); /* SAFE */
+ goto fnend;
+ }
+ }
+#else
+ sprintf(fnval,"%d",0); /* SAFE */
+#endif /* CK_AUTHENTICATION */
+ goto fnend;
+
+ case FN_KRB_TT: /* Kerberos ticket time */
+#ifdef CK_AUTHENTICATION
+ switch (kv) {
+ case 4:
+ n = ck_krb4_tkt_time(bp[1]);
+ sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
+ goto fnend;
+ case 5: {
+ extern char * krb5_d_cc;
+ n = ck_krb5_tkt_time(krb5_d_cc,bp[1]);
+ sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
+ goto fnend;
+ }
+ }
+#else
+ ckstrncpy(fnval,"600",FNVALL); /* Some time */
+#endif /* CK_AUTHENTICATION */
+ goto fnend;
+
+ case FN_KRB_FG: /* Kerberos ticket flags */
+#ifdef CK_AUTHENTICATION
+ switch (kv) {
+ case 4:
+ fnval[0] = '\0';
+ goto fnend;
+ case 5: {
+ extern char * krb5_d_cc;
+ ckstrncpy(fnval,ck_krb5_tkt_flags(krb5_d_cc,bp[1]),FNVALL);
+ goto fnend;
+ }
+ }
+#else
+ fnval[0] = '\0';
+#endif /* CK_AUTHENTICATION */
+ goto fnend;
+ }
+ p = fnval;
+ goto fnend;
+ }
+#endif /* CK_KERBEROS */
+
+#ifdef FN_ERRMSG
+ case FN_ERRMSG:
+ if (rdigits(bp[0])) {
+ k = atoi(bp[0]);
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+#ifdef VMS
+ ckstrncpy(fnval,ckvmserrstr(k),FNVALL);
+#else
+ x = errno;
+ errno = k;
+ ckstrncpy(fnval,ck_errstr(),FNVALL);
+ errno = x;
+#endif /* VMS */
+ p = fnval;
+ goto fnend;
+#endif /* FN_ERRMSG */
+
+ case FN_DIM: {
+ int max;
+ char abuf[16], *s;
+ fnval[0] = NUL; /* Initial return value */
+ ckstrncpy(abuf,bp[0],16); /* Get array reference */
+ s = abuf;
+ if (*s == CMDQ) s++;
+ failed = 1; /* Assume it's bad */
+ p = fnval; /* Point to result */
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ if (s[0] != '&') { /* "Address" of array */
+ goto fnend;
+ }
+ if (s[2]) {
+ if (s[2] != '[' || s[3] != ']') {
+ goto fnend;
+ }
+ }
+ if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
+ s[1] += 32;
+ if (s[1] < 95 || s[1] > 122) { /* Check for a-z */
+ goto fnend; /* Bad */
+ }
+ if ((max = chkarray(s[1],1)) < 1) /* (second arg was 1) */
+ max = 0;
+ failed = 0; /* Unset failure flag */
+ sprintf(fnval,"%d",max); /* SAFE */
+ goto fnend;
+ }
+
+ } /* Break up big switch... */
+
+ switch (y) {
+ case FN_JDATE:
+ if (argn < 1) /* Check number of args */
+ p = ckdate(); /* None, get today's date-time */
+ else /* Some */
+ p = bp[0]; /* Use first */
+ p = ckcvtdate(p,0); /* Convert to standard form */
+ ckstrncpy(fnval,zjdate(p),FNVALL); /* Convert to Julian */
+ p = fnval; /* Point to result */
+ failed = 0;
+ if (*p == '-') {
+ failed = 1;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+
+ case FN_DATEJ:
+ ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy<dayofyear> */
+ p = fnval; /* Point to result */
+ failed = 0;
+ if (*p == '-') {
+ failed = 1;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+
+ case FN_DTIM: /* \fcvtdate() */
+ case FN_TIME: /* Free-format time to hh:mm:ss */
+ case FN_NTIM: /* Time to sec since midnight */
+ s = (argn > 0) ? bp[0] : "";
+ if (!s) s = "";
+ if (!*s)
+ p = ckdate(); /* None, get today's date */
+ else /* Some */
+ p = bp[0]; /* Use first */
+ {
+ char * s;
+ s = p;
+ while (*s) {
+ if (*s < 32) {
+ *s = NUL;
+ break;
+ }
+ s++;
+ }
+ /* do { if (*s < '!') *s = NUL; break; } while (*s++); */
+ }
+ p = ckcvtdate(p,2); /* Convert to standard form */
+ if (*p == '<') {
+ failed = 1;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_BAD_DATE_OR_TIME:\\f",fn,"()>",NULL);
+ p = fnval;
+ goto fnend;
+ }
+ if (argn > 1) { /* Format code */
+ s = bp[1];
+ if (!s) s = "";
+ if (!*s) s = "0";
+ if (!chknum(s)) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ p = fnval;
+ goto fnend;
+ }
+ x = atoi(s);
+ /* if (x) */ p = shuffledate(p,x);
+ }
+ if (cx == FN_TIME) {
+ p += 9;
+ } else if (cx == FN_NTIM) {
+ long sec = 0L;
+ p[11] = NUL;
+ p[14] = NUL;
+ sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
+ sprintf(fnval,"%ld",sec); /* SAFE */
+ p = fnval;
+ }
+ goto fnend;
+
+ case FN_MJD: /* Modified Julian Date */
+ if (argn < 1) /* Check number of args */
+ p = zzndate(); /* None, get today's date-time */
+ else /* Some */
+ p = bp[0]; /* Use first */
+ p = ckcvtdate(p,0); /* Convert to standard form */
+ if (*p == '-') {
+ failed = 1;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ /* Convert to modified Julian date */
+ sprintf(fnval,"%ld",mjd(p)); /* SAFE */
+ p = fnval; /* Point to result */
+ goto fnend;
+
+ case FN_MJD2: {
+ long k = 0L;
+ int n = 0;
+ p = evalx(bp[0]);
+ if (*p == '-') {
+ p++;
+ n = 1;
+ }
+ if (!rdigits(p)) {
+ failed = 1;
+ evalerr(fn);
+ p = fnval;
+ goto fnend;
+ } else {
+ k = atol(p);
+ if (n) k = -k;
+ }
+ ckstrncpy(fnval,mjd2date(k),FNVALL); /* Convert to Date */
+ p = fnval; /* Point to result */
+ failed = 0;
+ goto fnend;
+ }
+
+#ifndef NODIAL
+ case FN_PNCVT: { /* Convert phone number */
+ extern char * pncvt();
+ failed = 0;
+ p = pncvt(bp[0]);
+ if (!p) p = "";
+ if (!*p) {
+ failed = 1;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_BAD_PHONENUM:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+#endif /* NODIAL */
+
+ case FN_DAY:
+ case FN_NDAY:
+ if (argn < 1) /* Check number of args */
+ p = zzndate(); /* None, get today's date-time */
+ else /* Some */
+ p = bp[0]; /* Use first */
+ p = ckcvtdate(p,0); /* Convert to standard form */
+ if (*p == '-') {
+ failed = 1;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ failed = 0;
+ z = mjd(p); /* Convert to modified Julian date */
+ z = z % 7L;
+ if (z < 0) {
+ z = 0 - z;
+ k = 6 - ((int)z + 3) % 7;
+ } else {
+ k = ((int)z + 3) % 7; /* Day of week */
+ }
+ p = fnval; /* Point to result */
+ if (cx == FN_NDAY)
+ sprintf(fnval,"%d",k); /* SAFE */
+ else
+ ckstrncpy(fnval,wkdays[k],FNVALL);
+ goto fnend;
+
+ case FN_N2TIM: { /* Sec since midnight to hh:mm:ss */
+ long k = 0L;
+ int n = 0, hh, mm, ss;
+ char * s = bp[0];
+ if (argn < 1) /* If no arg substitute 0 */
+ s = "0";
+ p = evalx(s); /* Evaluate expression silently */
+ if (*p == '-') { /* Check result for minus sign */
+ p++;
+ n = 1;
+ }
+ if (!rdigits(p)) { /* Check for numeric */
+ failed = 1;
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ p = fnval;
+ goto fnend;
+ } else {
+ k = atol(p);
+ if (n) k = -k;
+ }
+ if (k < 0) { /* Check for negative */
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ p = fnval;
+ goto fnend;
+ }
+ hh = k / 3600L; /* Have positive number */
+ mm = (k % 3600L) / 60L; /* break it down... */
+ ss = ((k % 3600L) % 60L);
+
+ sprintf(fnval,"%02d:%02d:%02d",hh,mm,ss); /* SAFE */
+ p = fnval;
+ failed = 0;
+ goto fnend;
+ }
+
+ case FN_PERM: { /* File permissions */
+ p = fnval;
+ z = zchki(bp[0]);
+ if (z < 0) {
+ failed = 1;
+ if (fndiags) {
+ if (z == -1)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
+ else if (z == -2)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
+ else if (z == -3)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
+ else
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+#ifdef CK_PERMS
+ ckstrncpy(fnval,ziperm(bp[0]),FNVALL);
+#else
+ ckstrncpy(fnval,"(unknown)",FNVALL);
+#endif /* CK_PERMS */
+ goto fnend;
+ }
+ case FN_TLOOK: /* tablelook() */
+ case FN_ALOOK: { /* arraylook() */
+ int i, x, hi, lo, max, cmdlen;
+ char abuf[16], *s, *pat;
+ char kwbuf[256];
+ char delim = ':';
+ failed = 1; /* Assume failure */
+ ckstrncpy(fnval,"-1",FNVALL);
+ pat = bp[0]; /* Point to search pattern */
+ if (!pat) pat = ""; /* Watch out for NULL pointer */
+ cmdlen = strlen(pat); /* Get pattern length */
+ if (argn < 2 /* || cmdlen < 1 */ ) { /* Need two args */
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ ckstrncpy(abuf,bp[1],16); /* Get array reference */
+ if (argn > 2)
+ delim = *(bp[2]);
+ s = abuf;
+ if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ p = fnval; /* Point to result */
+ max = a_dim[x]; /* Size of array */
+ if (lo < 0) lo = 0; /* Use given range if any */
+ if (lo > max) lo = max;
+ if (hi < 0) hi = max;
+ if (hi > max) hi = max;
+ failed = 0; /* Unset failure flag */
+ if (max < 1)
+ goto fnend;
+ kwbuf[255] = NUL;
+ for (i = lo; i <= hi; i++) {
+ if (!a_ptr[x][i])
+ continue;
+ if (cx == FN_ALOOK) {
+ if (ckmatch(pat,a_ptr[x][i],inpcas[cmdlvl],1+4)) {
+ sprintf(fnval,"%d",i); /* SAFE */
+ goto fnend;
+ }
+ } else if (cx == FN_TLOOK) {
+ char * aa;
+ int j = 0, v = 0, len;
+ if (i == hi)
+ break;
+ aa = a_ptr[x][i]; /* Point to this array element */
+ if (!aa) aa = "";
+ while (j < 254 && *aa) { /* Isolate keyword */
+ if (*aa == delim)
+ break;
+ kwbuf[j++] = *aa++;
+ }
+ kwbuf[j] = NUL;
+ len = j;
+ v = 0;
+ if ((len == cmdlen && !ckstrcmp(kwbuf,pat,len,0)) ||
+ ((v = !ckstrcmp(kwbuf,pat,cmdlen,0)) &&
+ ckstrcmp(a_ptr[x][i+1],pat,cmdlen,0))) {
+ sprintf(fnval,"%d",i); /* SAFE */
+ goto fnend;
+ }
+ if (v) { /* Ambiguous */
+ ckstrncpy(fnval,"-2",FNVALL);
+ goto fnend;
+ }
+ }
+ }
+ if (cx == FN_TLOOK) { /* tablelook() last element */
+ ckstrncpy(fnval,"-1",FNVALL);
+ if (!ckstrcmp(a_ptr[x][hi],pat,cmdlen,0))
+ sprintf(fnval,"%d",hi); /* SAFE */
+ }
+ goto fnend;
+ }
+ case FN_TOB64: /* Base-64 conversion */
+ case FN_FMB64:
+ p = fnval;
+ *p = NUL;
+ if (argn < 1)
+ goto fnend;
+ if (cx == FN_TOB64) {
+ x = b8tob64(bp[0],-1,fnval,FNVALL);
+ } else {
+ x = strlen(bp[0]);
+ if (x % 4) { /* length must be multiple of 4 */
+ failed = 1;
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_INCOMPLETE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ b64tob8(NULL,0,NULL,0); /* Reset */
+ x = b64tob8(bp[0],-1,fnval,FNVALL);
+ b64tob8(NULL,0,NULL,0); /* Reset again */
+ }
+ if (x < 0) {
+ failed = 1;
+ if (fndiags) {
+ char * m = "INTERNAL_ERROR";
+ switch (x) {
+ case -1: m = "ARG_TOO_LONG"; break;
+ case -2: m = "ARG_OUT_OF_RANGE"; break;
+ }
+ if (ckmakmsg(fnval,FNVALL,"<ERROR:",m,"\\f",fn) > 0)
+ ckstrncat(fnval,"()>",FNVALL);
+ }
+ }
+ goto fnend;
+
+ case FN_ABS: {
+ char * s;
+ s = bp[0];
+ if (*s == '-' || *s == '+')
+ s++;
+ if (!rdigits(s)) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ ckstrncpy(fnval,s,FNVALL);
+ goto fnend;
+ }
+
+ case FN_AADUMP: {
+ char abuf[16], *s = NULL, **ap = NULL, **vp = NULL;
+ char pattern[VNAML];
+ int slen, i, j, k, first = -1;
+ extern int xdelmac();
+ p = fnval;
+ if (argn < 2) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG2:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ debug(F101,"aaconvert argn","",argn);
+ s = bp[0];
+ slen = strlen(s);
+
+ /* Count elements so we can create the array */
+
+ ckmakmsg(pattern,VNAML,s,"<*>",NULL,NULL);
+ for (k = 0, i = 0; i < nmac; i++) {
+ if (ckmatch(pattern,mactab[i].kwd,0,1)) {
+ if (first < 0) /* Remember location of first match */
+ first = i;
+ k++;
+ }
+ }
+ debug(F101,"aaconvert matches","",k);
+ debug(F101,"aaconvert first","",first);
+ fnval[0] = NUL; /* Initial return value */
+ ckstrncpy(abuf,bp[1],16); /* Get array reference */
+ s = abuf;
+ if (*s == CMDQ) s++;
+ p = fnval; /* Point to result */
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ if (s[0] != '&') /* Address of array */
+ goto fnend;
+ if (s[2])
+ if (s[2] != '[' || s[3] != ']')
+ goto fnend;
+ if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
+ s[1] += 32;
+ if ((x = dclarray(s[1],k)) < 0) /* Declare array to size */
+ goto fnend;
+ ap = a_ptr[x]; /* Point to array we just declared */
+ /* debug(F111,"aaconvert array 1",abuf,ap); */
+ abuf[0] = NUL;
+ if (argn > 2) {
+ ckstrncpy(abuf,bp[2],16); /* Get value array reference */
+ s = abuf;
+ if (*s == CMDQ) s++;
+ if (s[0] != '&') /* Address of array */
+ goto fnend;
+ if (s[2])
+ if (s[2] != '[' || s[3] != ']')
+ goto fnend;
+ if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
+ s[1] += 32;
+ if ((x = dclarray(s[1],k)) < 0)
+ goto fnend;
+ vp = a_ptr[x]; /* Point to array we just declared */
+ }
+ /* debug(F111,"aaconvert array 2",abuf,vp); */
+ makestr(&ap[0],ckitoa(k));
+ if (vp) makestr(&vp[0],ckitoa(k));
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:ASSOCIATIVE_ARRAY:\\f",fn,"()>",NULL);
+
+ /* Copy macro index & value to the arrays and then remove the */
+ /* macro, so the 'first' pointer keeps indicating the next one. */
+ /* We could combine the initial counting loop with this one but */
+ /* then it would be harder to create the array and anyway this */
+ /* function is plenty fast as it is. */
+
+ for (i = 1; i <= k; ) {
+ if (!ckmatch(pattern,mactab[first].kwd,0,1)) {
+ debug(F111,"aaconvert oddball",mactab[first].kwd,first);
+ first++;
+ continue;
+ }
+ ckstrncpy(tmpbuf,mactab[first].kwd,TMPBUFSIZ); /* Macro name */
+ s = tmpbuf; /* Make writeable copy */
+ s += slen; /* Isolate "index" */
+ j = strlen(s) - 1;
+ if (*s != '<' || *(s+j) != '>') { /* Check syntax */
+ /* This shouldn't happen */
+ debug(F111,"aaconvert ERROR",mactab[first].kwd,first);
+ goto fnend;
+ }
+ *(s+j) = NUL; /* Remove final '>' */
+ debug(F111,"aaconvert",s+1,i);
+ makestr(&(ap[i]),s+1); /* Set first array to index */
+ if (vp)
+ makestr(&(vp[i]),mactab[first].mval); /* 2nd to value */
+ if (xdelmac(first) < 0)
+ goto fnend;
+ i++;
+ }
+ sprintf(fnval,"%d",k); /* SAFE */
+ p = fnval; /* Return size of array */
+ debug(F110,"aaconvert return",p,0);
+ failed = 0; /* Unset failure flag */
+ goto fnend;
+ }
+
+ } /* End of switch() */
+
+#ifdef FNFLOAT
+/*
+ Floating-point functions. To be included only if FNFLOAT is defined, which
+ should happen only if CKFLOAT is also defined, and if the math library is
+ linked in. Even then, we might have float-vs-double confusion as well as
+ confusion about what the final "%f" format effector is supposed to reference
+ (32 bits, 64 bits, etc). Expect trouble if CKFLOAT does not match the data
+ type of math library functions or args.
+*/
+ if (cx == FN_FPABS || /* Floating-point functions */
+ cx == FN_FPADD ||
+ cx == FN_FPDIV ||
+ cx == FN_FPEXP ||
+ cx == FN_FPLOG ||
+ cx == FN_FPLN ||
+ cx == FN_FPMOD ||
+ cx == FN_FPMAX ||
+ cx == FN_FPMIN ||
+ cx == FN_FPMUL ||
+ cx == FN_FPPOW ||
+ cx == FN_FPSQR ||
+ cx == FN_FPINT ||
+ cx == FN_FPSUB ||
+ cx == FN_FPROU ||
+ cx == FN_FPSIN ||
+ cx == FN_FPCOS ||
+ cx == FN_FPTAN) {
+ CKFLOAT farg[2], fpresult = 0.0;
+ char fpbuf[64], * bp0;
+ double dummy;
+ /* int sign = 0; */
+ int i, j, places = 0;
+ int argcount = 1;
+
+ failed = 1;
+ p = fnval;
+ bp0 = bp[0];
+ if (!bp0)
+ bp0 = "0";
+ else if (!*bp0)
+ bp0 = "0";
+ if (!isfloat(bp0,0)) {
+ k = mxlook(mactab,bp0,nmac);
+ bp0 = (k > -1) ? mactab[k].mval : NULL;
+ if (bp0) {
+ if (!isfloat(bp0,0)) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ }
+ if (cx == FN_FPINT) { /* Float to int */
+ failed = 0;
+ ckstrncpy(fnval,bp0,FNVALL);
+ for (i = 0; fnval[i]; i++) {
+ if (fnval[i] == '.') {
+ fnval[i] = NUL;
+ break;
+ }
+ }
+ goto fnend;
+ }
+ switch (y) { /* These need 2 args */
+ case FN_FPADD:
+ case FN_FPDIV:
+ case FN_FPMOD:
+ case FN_FPMAX:
+ case FN_FPMIN:
+ case FN_FPMUL:
+ case FN_FPPOW:
+ case FN_FPSUB:
+ argcount = 2;
+ }
+ /* Missing arguments are supplied as 0.0 */
+
+ debug(F111,fn,"argcount",argcount);
+ for (i = 0; i < argcount; i++) { /* Get floating-point args */
+#ifdef DEBUG
+ if (deblog) {
+ ckmakmsg(fpbuf,
+ 64,
+ "bp[",
+ ckitoa(i),
+ bp[i] ? bp[i] : "(null)",
+ "]"
+ );
+ debug(F100,fpbuf,"",0);
+ }
+#endif /* DEBUG */
+ if (!bp[i]) {
+ farg[i] = 0.0;
+ } else if (!*(bp[i])) {
+ farg[i] = 0.0;
+ } else if (!isfloat(bp[i],0)) {
+ char * tmp;
+ k = mxlook(mactab,bp[i],nmac);
+ tmp = (k > -1) ? mactab[k].mval : NULL;
+ if (tmp) {
+ if (!isfloat(tmp,0)) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ }
+ farg[i] = floatval;
+
+#ifdef DEBUG
+ if (deblog) {
+ sprintf(fpbuf,"farg[%d]=%f",i,farg[i]); /* SAFE */
+ debug(F100,fpbuf,"",0);
+ }
+#endif /* DEBUG */
+ }
+ if (bp[argcount]) { /* Get decimal places */
+ char * s;
+ s = bp[argcount];
+ if (!s) s = "";
+ if (!*s) s = "0";
+ s = evalx(s);
+ if (!s) s = "";
+ if (!*s) {
+ evalerr(fn);
+ goto fnend;
+ }
+ places = atoi(s);
+ }
+ errno = 0;
+ failed = 0;
+ switch (y) { /* Now do the requested function */
+ case FN_FPABS: /* Floating-point absolute value */
+#ifndef COMMENT
+ fpresult = fabs(farg[0]);
+#else
+ if (farg[0] < 0.0)
+ fpresult = 0.0 - farg[0];
+#endif /* COMMENT */
+ break;
+ case FN_FPADD: /* FP add */
+ fpresult = farg[0] + farg[1];
+ break;
+ case FN_FPDIV: /* FP divide */
+ case FN_FPMOD: /* FP modulus */
+ if (!farg[1]) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
+ } else
+ fpresult = (cx == FN_FPDIV) ?
+ (farg[0] / farg[1]) :
+ fmod(farg[0],farg[1]);
+ break;
+ case FN_FPEXP: /* FP e to the x */
+ fpresult = (CKFLOAT) exp(farg[0]);
+ break;
+ case FN_FPLOG: /* FP base-10 logarithm */
+ case FN_FPLN: /* FP natural logarithm */
+ if (farg[0] < 0.0) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ } else
+ fpresult = (cx == FN_FPLOG) ? log10(farg[0]) : log(farg[0]);
+ break;
+ case FN_FPMUL: /* FP multiply */
+ fpresult = farg[0] * farg[1];
+ break;
+ case FN_FPPOW: /* FP raise to a power */
+ fpresult = modf(farg[1],&dummy);
+ if ((!farg[0] && farg[1] <= 0.0) ||
+ (farg[0] < 0.0 && fpresult)) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ } else
+ fpresult = pow(farg[0],farg[1]);
+ break;
+ case FN_FPSQR: /* FP square root */
+ if (farg[0] < 0.0) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ } else
+ fpresult = sqrt(farg[0]);
+ break;
+ case FN_FPSUB: /* FP subtract */
+ fpresult = farg[0] - farg[1];
+ break;
+ case FN_FPROU: /* FP round */
+ fpresult = farg[0];
+ break;
+ case FN_FPSIN: /* FP sine */
+ fpresult = (CKFLOAT) sin(farg[0]);
+ break;
+ case FN_FPCOS: /* FP cosine */
+ fpresult = (CKFLOAT) cos(farg[0]);
+ break;
+ case FN_FPTAN: /* FP tangent */
+ fpresult = (CKFLOAT) tan(farg[0]);
+ break;
+ case FN_FPMAX:
+ fpresult = (farg[0] > farg[1]) ? farg[0] : farg[1];
+ break;
+ case FN_FPMIN:
+ fpresult = (farg[0] < farg[1]) ? farg[0] : farg[1];
+ break;
+ }
+
+ /* Get here with fpresult = function result */
+
+ if (errno) { /* If range or domain error */
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FLOATING-POINT-OP:\\f",fn,"()>",NULL);
+ }
+ if (failed) /* and/or any other kind of error, */
+ goto fnend; /* fail. */
+#ifndef COMMENT
+ /* Call routine containing code that was formerly inline */
+ ckstrncpy(fnval,fpformat(fpresult,places,cx == FN_FPROU),FNVALL);
+#else
+ {
+ char fbuf[16]; /* For creating printf format */
+ if (!fp_rounding && /* If printf doesn't round, */
+ (places > 0 || /* round result to decimal places. */
+ (places == 0 && cx == FN_FPROU)))
+ fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
+ if (places > 0) { /* If places specified */
+ /* use specified places to write given number of digits */
+ sprintf(fbuf,"%%0.%df",places); /* SAFE */
+ sprintf(fnval,fbuf,fpresult); /* SAFE */
+ } else { /* Otherwise... */
+#ifdef COMMENT
+/*
+ Here we want to print exactly fp_digits significant digits, no matter which
+ side of the decimal point they are on. That is, we want want the default
+ format to show the maximum number of non-garbage digits, AND we want the last
+ such digit to be rounded. Of course there is no way to do that, since the
+ digit after the last non-garbage digit is, well, garbage. So the following
+ clever ruse does no good.
+*/
+ int sign = 0, m = 0;
+ sprintf(fnval,"%f",fpresult);
+ if (fnval[0] == '-') sign = 1;
+ for (i = sign; i < FNVALL; i++) {
+ if (isdigit(fnval[i]))
+ m++;
+ else
+ break;
+ }
+ if (m > 1) {
+ int d = fp_digits - m;
+ if (d < 1) d = 1;
+ sprintf(fbuf,"%%%d.%df",fp_digits+sign+1,d);
+ } else {
+ sprintf(fbuf,"%%0.%df",fp_digits);
+ }
+ sprintf(fnval,fbuf,fpresult);
+#else
+ /* Go for max precision */
+ sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
+ sprintf(fnval,fbuf,fpresult); /* SAFE */
+
+#endif /* COMMENT */
+ }
+ if (fnval[0] == '-') sign = 1;
+ }
+ debug(F111,"fpresult 1",fnval,errno); /* Check for over/underflow */
+ for (i = sign; fnval[i]; i++) { /* Give requested decimal places */
+ if (fnval[i] == '.') /* First find the decimal point */
+ break;
+ else if (i > fp_digits + sign - 1) /* replacing garbage */
+ fnval[i] = '0'; /* digits with 0... */
+ }
+ if (fnval[i] == '.') { /* Have decimal point */
+ int gotend = 0;
+ /* d < 0 so truncate fraction */
+ if (places < 0 || (places == 0 && cx == FN_FPROU)) {
+ fnval[i] = NUL;
+ } else if (places > 0) { /* d > 0 so this many decimal places */
+ i++; /* First digit after decimal */
+ for (j = 0; j < places; j++) { /* Truncate after d decimal */
+ if (!fnval[j+i]) /* places or extend to d */
+ gotend = 1; /* decimal places. */
+ if (gotend || j+i+sign > fp_digits)
+ fnval[j+i] = '0';
+ }
+ fnval[j+i] = NUL;
+ } else { /* d == 0 so Do The Right Thing */
+ for (j = (int)strlen(fnval) - 1; j > i+1; j--) {
+ if ((j - sign) > fp_digits)
+ fnval[j] = '0';
+ if (fnval[j] == '0')
+ fnval[j] = NUL; /* Strip useless trailing 0's. */
+ else
+ break;
+ }
+ }
+ }
+#endif /* COMMENT */
+ debug(F111,"fpresult 2",fnval,errno);
+ goto fnend;
+
+ }
+#endif /* FNFLOAT */
+
+#ifdef CKCHANNELIO
+ if (cx == FN_FSTAT || /* File functions */
+ cx == FN_FPOS ||
+ cx == FN_FEOF ||
+ cx == FN_FGCHAR ||
+ cx == FN_FGLINE ||
+ cx == FN_FGBLK ||
+ cx == FN_FPCHAR ||
+ cx == FN_FPLINE ||
+ cx == FN_FPBLK ||
+ cx == FN_NLINE ||
+ cx == FN_FERMSG ||
+ cx == FN_FILNO) {
+ int x = 0, t = 0, channel;
+ long z;
+ extern int z_maxchan;
+
+ failed = 1; /* Assume failure */
+ p = fnval; /* until we validate args */
+ if (cx == FN_FERMSG) {
+ extern int z_error;
+ if (argn < 1) {
+ x = z_error;
+ } else if (chknum(bp[0])) {
+ x = atoi(bp[0]);
+ } else if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ failed = 0;
+ ckstrncpy(fnval,ckferror(x),FNVALL);
+ goto fnend;
+ }
+ if (argn < 1) { /* All file functions need channel */
+ if (cx == FN_FSTAT) { /* Except f_status(), e.g. when */
+ fnval[0] = '0'; /* called with a variable that */
+ fnval[1] = NUL; /* hasn't been defined yet. */
+ failed = 0;
+ } else {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+ }
+ goto fnend;
+ }
+ if (rdigits(bp[0])) { /* Channel must be numeric */
+ channel = atoi(bp[0]);
+ } else { /* Fail if it isn't */
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (channel < 0 || channel > z_maxchan) { /* Check channel range */
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ x = z_getmode(channel); /* Find out about the channel */
+
+ failed = 0; /* Assume success from here down */
+ if (cx == FN_FSTAT) { /* Status / modes of channel */
+ if (x > -1)
+ x &= FM_RWB; /* Mask out irrelevant bits */
+ else /* In this case not open is OK */
+ x = 0; /* 0 if not open, 1-7 if open */
+ sprintf(fnval,"%d",x); /* SAFE */
+ goto fnend;
+ } else if (x < 1) { /* Not \f_status() so must be open */
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_OPEN:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ switch (y) { /* Do the requested function */
+ case FN_FPOS: /* Get position */
+ z = z_getpos(channel); /* FIX THIS */
+ sprintf(fnval,"%ld",z); /* SAFE */
+ goto fnend;
+
+ case FN_NLINE: /* Get line number */
+ z = z_getline(channel); /* FIX THIS */
+ sprintf(fnval,"%ld",z); /* SAFE */
+ goto fnend;
+
+ case FN_FEOF: /* Check EOF */
+ t = 0;
+ if (x & FM_EOF) t = 1;
+ sprintf(fnval,"%d",t); /* SAFE */
+ goto fnend;
+
+ case FN_FILNO: /* Get file handle */
+ x = z_getfnum(channel);
+ sprintf(fnval,"%d",x); /* SAFE */
+ goto fnend;
+
+ case FN_FPBLK: /* Read or write block */
+ case FN_FGBLK:
+ if (argn < 2) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (rdigits(bp[1])) {
+ t = atoi(bp[1]);
+ } else {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ case FN_FGCHAR: /* Read or write character or line */
+ case FN_FPCHAR:
+ case FN_FGLINE:
+ case FN_FPLINE:
+ fnval[0] = NUL;
+ switch (y) {
+ case FN_FGCHAR: t = z_in(channel,fnval,FNVALL,1,1); break;
+ case FN_FGLINE: t = z_in(channel,fnval,FNVALL,FNVALL-1,0); break;
+ case FN_FGBLK:
+ if (t >= FNVALL) t = FNVALL - 1;
+ t = z_in(channel,fnval,FNVALL,t,1);
+ break;
+ case FN_FPCHAR: t = z_out(channel,bp[1],1,1); break;
+ case FN_FPLINE: t = z_out(channel,bp[1],-1,0); break;
+ case FN_FPBLK: t = z_out(channel,bp[1],-1,1); break;
+ }
+ if (t < 0) { /* Handle read/write error */
+ failed = 1;
+ if (fndiags && t != FX_EOF)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:FILE_ERROR_%d:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (cx == FN_FGCHAR) /* Null terminate char */
+ fnval[1] = NUL;
+ /* Write (put) functions return numeric status code */
+ if (cx == FN_FPCHAR || cx == FN_FPLINE || cx == FN_FPBLK)
+ sprintf(fnval,"%d",t); /* SAFE */
+ goto fnend;
+ }
+ }
+#endif /* CKCHANNELIO */
+
+ if (cx == FN_SQUEEZE) { /* String function \fsqueeze() */
+ /* Squeeze out whitespace */
+ /* Add options later for whether to trim leading and trailing blanks */
+ /* and what to do about control characters, 8-bit whitespace, etc */
+ int started = 0; /* Flag for first non-whitespace */
+ int n = 0; /* Blank/Tab counter */
+ s = bp[0] ? bp[0] : "";
+ p = fnval; /* Result buffer */
+ while (*s) { /* While there is input */
+ if (!started && (*s == ' ' || *s == '\011')) {
+ s++; /* Skip past leading whitespace */
+ continue;
+ }
+ started++; /* Leading whitespace was skipped */
+ if (*s != ' ' && *s != '\011') { /* Have a nonspace char */
+ n = 0; /* reset space counter */
+ *p++ = *s++; /* copy char to destination */
+ continue;
+ }
+ if (n++ > 0) { /* Have blank or tab */
+ s++; /* don't copy more than one */
+ continue;
+ }
+ *p++ = ' '; /* Deposit one space */
+ s++; /* and go to next source char */
+ }
+ if (*(p-1) == ' ') p--; /* Remove trailing space */
+ *p = NUL; /* Terminate string */
+ p = fnval; /* point to beginning */
+ goto fnend; /* Done. */
+ }
+ if (cx == FN_PATTERN) { /* \fpattern() for INPUT */
+ itsapattern = 1;
+ if (argn > 0) {
+ p = fnval;
+ ckstrncpy(fnval,bp[0],FNVALL);
+ } else p = "";
+ goto fnend;
+ }
+ if (cx == FN_HEX2N || cx == FN_OCT2N) { /* \fhex2n(), \foct2n() */
+ p = "0";
+ if (argn < 1)
+ goto fnend;
+ p = ckradix(bp[0], ((cx == FN_HEX2N) ? 16 : 8), 10);
+ if (!p) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ failed = 0;
+ ckstrncpy(fnval,p,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+
+ if (cx == FN_HEX2IP) {
+ int c[2], ip[4], i, k;
+ p = "0";
+ if (argn < 1)
+ goto fnend;
+ s = bp[0];
+ if ((int)strlen(s) != 8) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ p = fnval;
+ for (k = 0; k < 8; k += 2) {
+ for (i = 0; i < 2; i++) {
+ c[i] = *s++;
+ if (islower(c[i])) c[i] = toupper(c[i]);
+ if (c[i] >= '0' && c[i] <= '9') {
+ c[i] -= 0x30;
+ } else if (c[i] >= 'A' && c[i] <= 'F') {
+ c[i] -= 0x37;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ ip[k/2] = c[0] << 4 | c[1];
+ }
+ sprintf(p,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
+ }
+ goto fnend;
+ }
+ if (cx == FN_IP2HEX) {
+ int ip[4], i;
+ char * q;
+ p = "00000000";
+ if (argn < 1)
+ goto fnend;
+ s = bp[0];
+ p = fnval;
+ for (i = 0; i < 3; i++) {
+ q = ckstrchr(s,'.');
+ if (q) {
+ *q++ = NUL;
+ ip[i] = atoi(s);
+ s = q;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ ip[3] = atoi(s);
+ sprintf(p,"%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
+ goto fnend;
+ }
+ if (cx == FN_RADIX) {
+ failed = 1;
+ p = fnval;
+ if (argn < 3) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (!rdigits(bp[1]) || !rdigits(bp[2])) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2]));
+ if (!p) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ failed = 0;
+ ckstrncpy(fnval,p,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+ if (cx == FN_JOIN) {
+ int i, x, y, z, flag, flag2, hi, lo, max, seplen, grouping = 0;
+ char abuf[16], c, *s, *q, *sep = NULL;
+ char * gr_opn = "\"{'([<"; /* Group open brackets */
+ char * gr_cls = "\"}')]>"; /* Group close brackets */
+ char lb[2], rb[2]; /* Selected left and right brackets */
+ int csv = 0, tsv = 0; /* Function flags */
+ char specialchar = 0; /* Field char that triggers grouping */
+ char *s2 = NULL; /* Address of malloc'd storage */
+
+ failed = 1; /* Assume failure */
+ fnval[0] = NUL;
+ debug(F101,"FNJOIN ARGN","",argn);
+
+ ckstrncpy(abuf,bp[0],16); /* Get array reference */
+ s = abuf;
+ if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ p = fnval; /* Point to result */
+ max = a_dim[x]; /* Size of array */
+ if (lo < 0) lo = 1; /* Use given range if any */
+ if (lo > max) lo = max;
+#ifdef COMMENT
+ hi = max;
+#else
+/*
+ This is a workaround for the problem in which the dimension of the \&_[]
+ array (but not its contents) grows upon entry to a SWITCH block. But this
+ code prevents the dimension from growing. Go figure.
+*/
+ if (hi < 0) { /* Bounds not given */
+ if (x) /* Regular array */
+ hi = max;
+ else /* Argument vector array */
+ for (hi = max; hi >= lo; hi--) { /* ignore any trailing */
+ if (!a_ptr[x][hi]) continue; /* empty elements */
+ if (!*(a_ptr[x][hi])) continue;
+ break;
+ }
+ }
+#endif /* COMMENT */
+ if (hi > max) hi = max;
+ failed = 0; /* Unset failure flag */
+ if (max < 1)
+ goto fnend;
+ sep = " "; /* Separator */
+ lb[0] = NUL; /* Group start char (as string) */
+ rb[0] = NUL;
+ lb[1] = NUL; /* Group end char as string */
+ rb[1] = NUL;
+
+ if (argn > 1) {
+ if (bp[1]) if (*bp[1]) { /* If arg1 given and not empty */
+ if (!strcmp(bp[1],"CSV")) { /* Special "CSV" symbolic arg */
+ csv++; /* Make a comma separated list */
+ sep = ","; /* Comma */
+ specialchar = *sep; /* Separator is special character */
+ grouping = 1; /* Group with doublequotes */
+ lb[0] = '"'; /* and here */
+ rb[0] = '"'; /* they are */
+ } else if (!strcmp(bp[1],"TSV")) { /* "TSV" symbolic arg */
+ tsv++; /* Make a Tab separated list */
+ sep = "\011"; /* Tab */
+ specialchar = *sep;
+ grouping = 0; /* No grouping */
+ } else /* Normal case */
+ sep = bp[1]; /* use the separator char specified */
+ }
+ }
+ if (argn > 2 && !csv && !tsv) { /* Grouping? */
+ char * bp2 = bp[2];
+ if (!bp2) bp2 = "0";
+ if (!*bp2) bp2 = "0";
+ if (chknum(bp2)) {
+ grouping = atoi(bp2);
+ if (grouping < 0 || grouping > 63)
+ grouping = 1;
+ } else {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (grouping) { /* Take lowest-order one */
+ int j, k; /* and set the others to 0 */
+ for (k = 0; k < 6; k++) {
+ j = 1 << k;
+ if (grouping & j) {
+ lb[0] = gr_opn[k];
+ rb[0] = gr_cls[k];
+ break;
+ }
+ }
+ }
+ }
+ if (!csv && !tsv) { /* Normal case, not CSV or TSV */
+ specialchar = SP; /* Special character is space */
+ if (argn > 3) /* Nonzero 4th arg for no separator */
+ if (chknum(bp[3]))
+ if (atoi(bp[3]) > 0)
+ sep = NULL;
+ if (!sep) {
+ sep = "";
+ seplen = 0;
+ } else
+ seplen = strlen(sep);
+ }
+ for (i = lo; i <= hi; i++) { /* Loop thru selected array elements */
+ s = a_ptr[x][i]; /* Get next element */
+ if (!s)
+ s = "";
+ flag = 0; /* Flag to indicate grouping needed */
+ flag2 = 0; /* Flag for internal doublequotes */
+ if (grouping) { /* Does this element need quoting? */
+ q = s; /* Look for special character */
+ while ((c = *q++)) { /* If found */
+ if (c == specialchar) /* grouping is required */
+ flag++;
+ if (csv && (c == '"')) /* Character that needs doubling */
+ flag2++; /* in comma-separated list */
+ if (flag && !csv) /* Exit early if no more to do */
+ break;
+ }
+ }
+ y = strlen(s); /* Get length of this element */
+ if ((y > 0) && csv && !flag) { /* CSV item needs grouping */
+ if (s[0] == SP || s[y-1] == SP || /* if it has leading */
+ s[0] == HT || s[y-1] == HT) /* or trailing whitespace */
+ flag++; /* then it needs grouping */
+ }
+ if (flag || flag2) { /* String needs grouping or quoting */
+ char *ss = s;
+ q = (char *)malloc(y + flag2 + 3); /* Make new buffer */
+ if (q) {
+ s2 = q; /* and this is what to free */
+ if (flag) /* If grouping */
+ *q++ = lb[0]; /* put opening group quote */
+ while (*ss) { /* Loop through string */
+ if (flag2 && (*ss == '"')) /* If CSV and this a '"' */
+ *q++ = *ss; /* double it. */
+ *q++ = *ss++; /* Copy the character */
+ }
+ if (flag) /* If grouping */
+ *q++ = rb[0]; /* add closing group quote */
+ *q = NUL; /* terminate the result. */
+ s = s2;
+ y = strlen(s);
+ }
+ }
+ z = 0; /* Number of chars copied */
+ flag = 0; /* flag is now buffer-overrun flag */
+ if (y > 0) /* If this string is not empty */
+ z = ckstrncat(fnval,s,FNVALL); /* copy it. */
+ if (s2) free(s2); /* Free temp storage */
+ if (z < y) /* Now check for buffer overrun. */
+ flag++;
+ if (!flag && *sep && i < hi) { /* If buffer still has room */
+ z = ckstrncat(fnval,sep,FNVALL); /* copy delimiter */
+ if (z < seplen)
+ flag++;
+ }
+ if (flag) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ }
+ isjoin = 1;
+ goto fnend;
+ }
+ if (cx == FN_SUBST) { /* \fsubstitute() */
+ CHAR c, * s, * r, * tp[2], buf1[256], buf2[256], buf3[256];
+ int len, i, j, state = 0, lo = 0, hi = 0;
+
+ failed = 0;
+ p = fnval; /* Result pointer */
+ *p = NUL;
+ if (!bp[0]) /* No target, no result*/
+ goto fnend;
+
+ len = strlen(bp[0]); /* Length of source */
+ if (len == 0)
+ goto fnend;
+ if (len > FNVALL) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (!bp[1]) {
+ ckstrncpy(bp[0],fnval,FNVALL);
+ goto fnend;
+ }
+ tp[0] = buf1; /* For s2-s3 interpretation loop */
+ tp[1] = buf2;
+
+ for (i = 0; i < 256; i++) { /* Initialize working buffers */
+ buf1[i] = 0; /* s2 expansion buffer */
+ buf2[i] = 0; /* s3 expansion buffer */
+ buf3[i] = i; /* Translation table */
+ }
+ for (i = 0; i < 2; i++) { /* Interpret s2 and s3 */
+ s = (CHAR *)bp[i+1]; /* Arg pointer */
+ if (!s) s = (CHAR *)"";
+ r = tp[i]; /* To construct interpreted arg */
+ j = 0; /* Output buf pointer */
+ state = 0; /* Initial state */
+ while (c = *s++) { /* Loop thru arg chars */
+ if (j > 255) /* Output buf full */
+ break;
+ switch (state) {
+ case 0: /* Normal state */
+ switch (c) {
+ case '\\': /* Have quote */
+ state = 1;
+ break;
+ case '[': /* Have range starter */
+ state = 2;
+ break;
+ default: /* Anything else */
+ r[j++] = c;
+ break;
+ }
+ continue;
+ case 1: /* Quoted char */
+ r[j++] = c;
+ state = 0;
+ continue;
+ case 2: /* Range bottom */
+ lo = c;
+ state++;
+ continue;
+ case 3: /* Range separater */
+ if (c != '-') {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ state++;
+ continue;
+ case 4: /* Range top */
+ hi = c;
+ state++;
+ continue;
+ case 5: /* Range end */
+ if (c != ']') {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ for (k = lo; k <= hi && j < 255; k++) /* Fill in */
+ r[j++] = k;
+ lo = 0; hi = 0; /* Reset */
+ state = 0;
+ continue;
+ }
+ }
+ }
+ for (i = 0; i < 256 && buf1[i]; i++) { /* Create translation table */
+ k = (unsigned)buf1[i];
+ buf3[k] = buf2[i];
+ }
+ s = (CHAR *)bp[0]; /* Point to source string */
+ for (i = 0; i < len; i++) { /* Translation loop */
+ k = (unsigned)s[i]; /* Get next char */
+ if (!buf3[k]) /* Remove this char */
+ continue;
+ *p++ = buf3[k]; /* Substitute this char */
+ }
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+ }
+
+#ifndef NOSEXP
+ if (cx == FN_SEXP) { /* \fsexpression(arg1) */
+ char * p2;
+ fsexpflag++;
+ p = (argn > 0) ? dosexp(bp[0]) : "";
+ fsexpflag--;
+ p2 = fnval;
+ while ((*p2++ = *p++)) ;
+ p = fnval;
+ goto fnend;
+ }
+#endif /* NOSEXP */
+
+ if (cx == FN_CMDSTK) { /* \fcmdstack(n1,n2) */
+ int i, j, k;
+ char * s;
+
+ if (bp[0])
+ val1 = *(bp[0]) ? evalx(bp[0]) : ckitoa(cmdlvl);
+ else
+ val1 = ckitoa(cmdlvl);
+#ifdef COMMENT
+ free(bp[0]); /* (evalx() always uses same buffer) */
+ bp[0] = NULL; /* (not any more!) */
+#endif /* COMMENT */
+ failed = 1;
+ if (argn > 1) {
+#ifdef COMMENT
+ makestr(&(bp[0]),val1);
+ val1 = bp[0];
+#endif /* COMMENT */
+ val2 = *(bp[1]) ? evalx(bp[1]) : "0";
+ if (!(chknum(val1) && chknum(val2))) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ } else {
+ val1 = ckitoa(cmdlvl);
+ val2 = "0";
+ }
+ i = atoi(val1); /* Level */
+ j = atoi(val2); /* Flags */
+ if (i < 0 || i > cmdlvl) {
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ failed = 0;
+ p = fnval;
+ k = cmdstk[i].src; /* What (prompt, file, macro) */
+ if (j) {
+ ckstrncpy(fnval,ckitoa(k),FNVALL);
+ goto fnend;
+ }
+ switch (k) {
+ case CMD_KB:
+ ckstrncpy(fnval,"(prompt)",FNVALL);
+ break;
+ case CMD_TF:
+ s = tfnam[cmdstk[i].lvl];
+ if (!zfnqfp(s,FNVALL,fnval))
+ ckstrncpy(fnval,s,FNVALL);
+ break;
+ case CMD_MD:
+ ckstrncpy(fnval,m_arg[cmdstk[i].lvl][0],FNVALL);
+ break;
+ }
+ goto fnend;
+ }
+#ifdef CKFLOAT
+ if (cx == FN_DIFDATE) { /* \fdiffdates(d1,d2) */
+ char * d1, * d2;
+ d1 = bp[0] ? bp[0] : ckdate();
+ d2 = bp[1] ? bp[1] : ckdate();
+ p = (char *)cmdiffdate(d1,d2);
+ if (!p) {
+ failed = 1;
+ if (fndiags) {
+ ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
+ p = fnval;
+ }
+ }
+ goto fnend;
+ }
+#endif /* CKFLOAT */
+ if (cx == FN_CMPDATE) { /* \fcmddates(d1,d2) */
+ int x = 0;
+ char d1[18], d2[18], * dp;
+ failed = 0;
+ d1[0] = NUL;
+ d2[0] = NUL;
+ p = fnval;
+ dp = cmcvtdate(bp[0],1);
+ if (dp) {
+ ckstrncpy(d1,dp,18);
+ if ((dp = cmcvtdate(bp[1],1))) {
+ ckstrncpy(d2,dp,18);
+ x = 1;
+ }
+ }
+ if (x == 0) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
+ } else {
+ x = strcmp(d1,d2);
+ if (x > 0)
+ x = 1;
+ else if (x < 0)
+ x = -1;
+ sprintf(fnval,"%d",x);
+ }
+ goto fnend;
+ }
+ if (cx == FN_TOGMT) { /* \futcdate(d1) */
+ char * d1, * dp;
+ char datebuf[32];
+ char d2[32];
+ p = fnval;
+ failed = 1;
+ if ((dp = cmcvtdate(bp[0],1))) { /* The given date */
+ ckstrncpy(datebuf,dp,18);
+ ckstrncpy(d2,dp,18); /* local time */
+ ckstrncat(datebuf,"Z",19); /* Same time GMT */
+ if ((dp = cmcvtdate(datebuf,1))) /* converted to local time */
+ ckstrncpy(datebuf,dp,18);
+ if ((p = (char *)cmdiffdate(d2,datebuf))) { /* Get offset */
+ ckstrncat(d2,p,32); /* Append offset to local time */
+ if ((dp = cmcvtdate(d2,1))) {
+ failed = 0;
+ ckstrncpy(fnval,dp,FNVALL);
+ p = fnval;
+ }
+ }
+ }
+ if (failed && fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ if (cx == FN_DELSEC) { /* \fdelta2secs(delta-time) */
+ long secs;
+ p = fnval;
+ if ((x = delta2sec(bp[0],&secs)) < 0) {
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,
+ (x == -1) ?
+ "<ERROR:BAD_DELTA_TIME:\\f" :
+ "<ERROR:OVERFLOW:\\f",
+ fn,
+ "()>",
+ NULL
+ );
+ goto fnend;
+ }
+ sprintf(p,"%ld",secs);
+ goto fnend;
+ }
+ if (cx == FN_PC_DU) {
+ char c, * s = bp[0];
+ if (!s) s = "";
+ p = fnval;
+ while ((c = *s++)) {
+ if (c == ':') {
+ if (*s != '\\')
+ *p++ = '/';
+ } else if (c == '\\') {
+ *p++ = '/';
+ } else {
+ *p++ = c;
+ }
+ }
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+ }
+ if (cx == FN_PC_UD) { /* Unix to DOS path */
+ char c, * s = bp[0];
+ if (!s) s = "";
+ if (*s == '~') { /* Skip leading tilde */
+ s++;
+ if (*s == '/')
+ s++;
+ }
+ p = fnval;
+ while ((c = *s++))
+ *p ++ = (c == '/') ? '\\' : c;
+ *p = NUL;
+ p = fnval;
+ goto fnend;
+ }
+ if (cx == FN_KWVAL) { /* Keyword=Value */
+ p = dokwval(bp[0],bp[1]?bp[1]:"=");
+ goto fnend;
+ }
+#ifdef COMMENT
+/* Cute idea but doesn't work */
+ if (cx == FN_SLEEP || cx == FN_MSLEEP) {
+ p = "";
+ if (chknum(bp[0])) {
+ x = atoi(bp[0]);
+ } else {
+ failed = 1;
+ if (fndiags) {
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+ p = fnval;
+ }
+ goto fnend;
+ }
+ if (cx == FN_SLEEP)
+ x *= 1000;
+ msleep(x);
+ goto fnend;
+ }
+#endif /* COMMENT */
+
+#ifdef NT
+ if (cx == FN_SNAME) {
+ GetShortPathName(bp[0],fnval,FNVALL);
+ goto fnend;
+ }
+ if (cx == FN_LNAME) {
+ ckGetLongPathName(bp[0],fnval,FNVALL);
+ goto fnend;
+ }
+#endif /* NT */
+
+/*
+ \femailaddress():
+ Picks the email address out of an RFC 2822 From: or Sender: header.
+ Added 26 Nov 2005. Handles all common, and some uncommon, cases but
+ doesn't totally bother about nested comments. Needed this for fetching
+ email from a POP server and then constructing the BSD "From " line.
+ Works with or without the "From: " or "Sender: " tag.
+*/
+ if (cx == FN_EMAIL) {
+ char c, * s = bp[0], * s2, * s3, * ap = "";
+ int k, state = 0, quote = 0, infield = 0;
+ int pc = 0; /* For nested comments */
+ if (!s) s = "";
+ if (!*s) goto xemail;
+
+ if (ckindex("From: ",s,0,0,0) == 1) s += 5;
+ if (ckindex("Sender: ",s,0,0,0) == 1) s += 7;
+
+ k = strlen(s); /* Strip junk from end */
+ if (k < 1) goto xemail;
+ k--;
+ while (k >= 0 && s[k] == CR || s[k] == LF)
+ s[k--] = NUL;
+ while (k >= 0 && s[k] == SP || s[k] == HT)
+ s[k--] = NUL;
+ if (k == 0)
+ goto xemail;
+
+#ifndef COMMENT /* Simple method if not 100% foolproof */
+ k = 0;
+ for (s2 = s; *s2; s2++) { /* Find at-sign */
+ if (*s2 == '@') {
+ k++; /* If more than one use rightmost */
+ s3 = s2;
+ }
+ }
+ if (k < 1) /* No at-sign */
+ goto xemail;
+
+ for (ap = s3-1; ap >= s; ap--) { /* Back up to beginning of address */
+ if (isspace(*ap) || *ap == '<') {
+ ap++;
+ break;
+ }
+ if (ap == s)
+ break;
+ }
+ for (s2 = s3+1; *s2; s2++) { /* Find end of address */
+ if (isspace(*s2) || *s2 == '>')
+ break;
+ }
+ *s2-- = NUL;
+ if (*ap == '[' && *s2 == ']') { /* Handle [blah@blah.blah] */
+ ap++;
+ *s2 = NUL;
+ }
+ if (!ckstrcmp(ap,"mailto:",7,0)) /* Handle mailto: URLs */
+ ap += 7;
+
+#else /* Too complicated and error-prone */
+
+ k = 0;
+ for (s2 = s; *s2; s2++) { /* Strip leading whitespace */
+ if (*s2 == SP || *s2 == HT) {
+ k = 1;
+ break;
+ }
+ }
+ if (!k) { /* Simple address */
+ ap = s;
+ goto xemail;
+ }
+ do { /* Not simple, have to extract it */
+ if (quote) {
+ quote = 0;
+ continue;
+ } else if (*s == '\\') {
+ quote = 1;
+ continue;
+ }
+ switch (state) {
+ case 0:
+ if (!infield && *s == '"') { /* Quoted string */
+ infield = 1;
+ c = '"';
+ state = 1;
+ } else if (!infield && *s == '(') { /* Comment in parens */
+ pc++;
+ infield = 1;
+ c = ')';
+ if (*ap) *s = NUL;
+ state = 1;
+ } else if (!infield && *s == '<') { /* Address */
+ infield = 1;
+ c = '>';
+ ap = s+1;
+ state = 2;
+ } else if (infield && (*s == SP || *s == HT)) {
+ infield = 0;
+ } else { /* One or more bare words */
+ infield = 1; /* Could be an address */
+ if (!*ap) ap = s; /* Could be comments */
+ }
+ continue;
+ case 1: /* In Quoted string or Comment */
+ if (infield && *s == c) { /* Look for end */
+ infield = 0;
+ *s++ = NUL;
+ while (*s == SP || *s == HT) s++;
+ if (!*ap)
+ ap = s;
+ state = 0;
+ }
+ continue;
+ case 2: /* In address */
+ if (infield && *s == c) { /* Looking for end */
+ infield = 0;
+ *s = NUL;
+ break;
+ }
+ }
+ } while (*s++);
+
+ xemail:
+ if (*ap) {
+ while (*ap == SP || *ap == HT) ap++;
+ }
+ k = strlen(ap) - 1;
+ while (k >= 0 && (ap[k] == SP || ap[k] == HT))
+ ap[k--] = NUL;
+ if (*ap) {
+ failed = 0;
+ if (*ap == '<') {
+ k = strlen(ap);
+ if (*(ap+k-1) == '>') {
+ ap[k-1] = NUL;
+ ap++;
+ }
+ }
+ } else
+ failed = 1;
+ /* Here we might also want check against "*@*.*" */
+#endif /* COMMENt */
+ xemail:
+ ckstrncpy(fnval,ap,FNVALL);
+ goto fnend;
+ }
+
+#ifdef SEEK_CUR
+/*
+ \fpicture(): Get dimensions of GIF or JPG image.
+ fdc June 2006
+*/
+ if (cx == FN_PICTURE) {
+ FILE *fp = NULL;
+ int c, x, w = 0, h = 0, eof = 0;
+ unsigned int i, j, k;
+ unsigned char buf[1024];
+ char abuf[16], * p, * s;
+ char ** ap = NULL;
+
+ p = fnval; /* Point to result */
+ failed = 1; /* Assume failure */
+ if (argn > 1) {
+ int xi;
+ ckstrncpy(abuf,bp[1],16); /* Get array reference */
+ s = abuf;
+ if (*s == CMDQ) s++;
+ if (fndiags) /* Default is this error message */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
+ if (s[0] != '&') /* "Address" of array */
+ goto fnend;
+ if (s[2])
+ if (s[2] != '[' || s[3] != ']')
+ goto fnend;
+ if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
+ s[1] += 32;
+ if ((xi = dclarray(s[1],2)) < 0) /* Two elements */
+ goto fnend;
+ ap = a_ptr[xi]; /* Point to array we just declared */
+ }
+ s = bp[0]; /* Filename */
+ failed = 0; /* From here on we don't fail */
+ p[0] = '0'; /* Default return value */
+ p[1] = NUL;
+ if (!ckmatch("*.{jpg,jpeg,gif}$",s,0,1+4)) /* Appropriate name? */
+ goto fnend; /* No, fail */
+ fp = fopen(s, "r"); /* Open it */
+ if (fp == NULL) { /* Can't, fail */
+ p[0] = '-';
+ p[1] = '1';
+ p[2] = NUL; /* Return -1 */
+ goto fnend;
+ }
+ k = strlen(s);
+ if (!ckstrcmp(&s[k-4],".gif",4,0)) { /* GIF file */
+ if (fread(buf,1,10,fp) != 10) {
+ fclose(fp);
+ goto fnend;
+ }
+ /* Check signature */
+ if (ckstrcmp((char *)buf,"GIF87a",6,0) &&
+ ckstrcmp((char *)buf,"GIF89a",6,0)) {
+ fclose(fp);
+ goto fnend;
+ }
+ w = buf[6] + 256 * buf[7];
+ h = buf[8] + 256 * buf[9];
+ goto picend;
+ } else if (!ckstrcmp(&s[k-4],".jpg",4,0) || /* JPEG file */
+ !ckstrcmp(&s[k-5],".jpeg",5,0)) {
+ if (fread(buf,1,2,fp) != 2) {
+ fclose(fp);
+ goto fnend;
+ }
+ if (buf[0] != 0xff || buf[1] != 0xd8) { /* Check signature */
+ fclose(fp);
+ goto fnend;
+ }
+ eof = 0;
+ while (!eof) { /* Loop for each marker */
+ while (!eof) { /* Find next marker */
+ c = getc(fp);
+ if (c == (unsigned int)EOF) {
+ eof++;
+ break;
+ }
+ if (c == 0xff) {
+ buf[0] = c;
+ c = getc(fp);
+ if (c == (unsigned int)EOF) {
+ eof++;
+ break;
+ }
+ buf[1] = c;
+ if (c == 0xd9)
+ eof++;
+ if (c >= 0xc0 && c <= 0xfe)
+ break;
+ }
+ }
+ if (eof) break;
+ x = buf[1];
+ if (x == 0xc0 || x == 0xc1 || x == 0xc2 || x == 0xc3 ||
+ x == 0xc9 || x == 0xca || x == 0xcb) {
+ if (fread(buf,1,7,fp) != 7) {
+ fclose(fp);
+ goto fnend;
+ }
+ h = buf[3] * 256 + buf[4];
+ w = buf[5] * 256 + buf[6];
+ goto picend;
+ } else { /* Not a desired field */
+ if (feof(fp)) {
+ eof++;
+ break;
+ }
+ if (fread(buf,1,2,fp) != 2) { /* Length of this field */
+ fclose(fp);
+ goto fnend;
+ }
+ j = 256 * buf[0] + buf[1] - 2; /* Skip next field */
+ if (CKFSEEK(fp,(CK_OFF_T)j,SEEK_CUR) != 0) {
+ fclose(fp);
+ goto fnend;
+ }
+ }
+ }
+ }
+ picend:
+ fclose(fp);
+ if (ap) {
+ makestr(&(ap[0]),"2");
+ makestr(&(ap[1]),ckitoa(w));
+ makestr(&(ap[2]),ckitoa(h));
+ }
+ if (w > 0 && h > 0) {
+ if (w > h) p[0] = '1';
+ if (h >= w) p[0] = '2';
+ }
+ goto fnend;
+ }
+#endif /* SEEK_CUR */
+
+ if (cx == FN_PID) {
+ int x = -1;
+ if (chknum(bp[0])) { /* Need numeric argument */
+ int pid;
+ pid = atoi(bp[0]); /* Convert to int */
+#ifdef UNIX
+ if (kill(pid,0) < 0) { /* Test it */
+ if (errno ==
+#ifdef ESRCH
+ ESRCH /* No such process */
+#else
+ 3
+#endif /* ESRCH */
+ )
+ x = 0;
+ } else /* Process exists */
+ x = 1;
+#endif /* UNIX */
+ }
+ sprintf(fnval,"%d",x); /* SAFE */
+ goto fnend;
+ }
+
+ if (cx == FN_FUNC) {
+ char * s = bp[0];
+ p = "0";
+ debug(F111,"ffunc",s,argn);
+ if (argn > 0) {
+ int x, y;
+ for (p = s; *p; p++) { /* Chop off trailing parens if any */
+ if (*p == '(') {
+ *p = NUL;
+ break;
+ }
+ }
+ /* Chop off leading "\\f" or "\f" or "f" */
+ p = s;
+ if (*p == CMDQ) /* Allow for \\f... */
+ p++;
+ if (*p == CMDQ && (*(p+1) == 'f' || *(p+1) == 'F')) { /* or \f */
+ p += 2;
+ } else if (*p == 'f' || *p == 'F') { /* or just f */
+ p++;
+ }
+ y = lookup(fnctab,p,nfuncs,&x); /* Look up the result */
+ debug(F111,"ffunc",p,y);
+ p = (y > -1) ? "1" : "0";
+ }
+ goto fnend;
+ }
+ if (cx == FN_RECURSE) {
+ int t, n;
+ char * s;
+ fnval[0] = NUL; /* Default result is empty string */
+ s = bp[0]; /* Check for null argument */
+ if (!s) s = ""; /* or empty argument */
+ if (!*s) goto fnend; /* in which case return empty string */
+ n = FNVALL; /* Not empty, max size for result */
+ s = fnval; /* Location of result */
+ {
+ /* Force VARIABLE-EVALUATION SIMPLE RECURSIVE */
+ /* NOTE: This is vulnerable to SIGINT and whatnot... */
+ int tmp = vareval; /* Save VARIABLE-EVALUATION setting */
+ vareval = 1; /* Force it to RECURSIVE */
+ zzstring(bp[0],&s,&n); /* Expand arg into result space */
+ vareval = tmp; /* Restore VARIABLE-EVALUATION */
+ }
+ goto fnend;
+ }
+
+ if (cx == FN_XLATE) { /* f_cvtcset() */
+#ifdef NOFRILLS
+ ckstrncpy(fnval,bp[0],FNVALL);
+#else
+#ifndef NOUNICODE
+ _PROTOTYP( char * cvtstring, (char *, int, int) );
+ char * string, * cset1, * cset2;
+ int id1, id2;
+#endif /* NOUNICODE */
+ fnval[0] = NUL;
+#ifdef NOUNICODE
+ ckstrncpy(fnval,bp[0],FNVALL);
+#else
+ string = bp[0] ? bp[0] : ""; /* String to convert */
+ if (!*string) goto fnend; /* It's empty */
+
+ cset1 = bp[1] ? bp[1] : "ascii"; /* Current charset of string */
+ cset2 = bp[2] ? bp[2] : "ascii"; /* Charset to convert to */
+
+ id1 = lookup(fcstab,cset1,nfilc,NULL); /* Lookup 'from' set */
+ if (id1 < 0) {
+ failed = 1;
+ ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_CHARSET:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ id2 = lookup(fcstab,cset2,nfilc,NULL); /* Lookup 'to' set */
+ if (id2 < 0) {
+ failed = 1;
+ ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_CHARSET:\\f",fn,"()>",NULL);
+ goto fnend;
+ }
+ string = cvtstring(string,id1,id2);
+ ckstrncpy(fnval,string,FNVALL);
+#endif /* NOUNICODE */
+#endif /* NOFRILLS */
+ goto fnend;
+ }
+
+/* Decode strings containing hex escapes */
+
+ if (cx == FN_UNPCT) { /* \fdecodehex() */
+ char *s1, *s2;
+ char *prefix; /* Can be 1 or 2 chars */
+ char buf[3];
+ int n = 0, k;
+
+ p = fnval;
+ *p = NUL;
+ if (argn < 1) goto fnend; /* Empty string */
+
+ s1 = bp[0] ? bp[0] : ""; /* Original string */
+ prefix = bp[1] ? bp[1] : "%%"; /* Hex byte prefix */
+ n = (int)strlen(prefix); /* Length of prefix */
+ if (n < 1 || n > 2) { /* must be 1 or 2 */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:INVALID_HEX_PREFIX:\\f",fn,"()>",NULL);
+ goto xunpct;
+ }
+ while (*s1) {
+ if (!ckstrcmp(s1,prefix,n,0)) { /* Case-independent */
+ if (!*(s1+n)) {
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:INCOMPLETE_SEQUENCE:\\f",fn,"()>",NULL);
+ goto xunpct;
+ }
+ buf[0] = *(s1+n); /* First hex character */
+ buf[1] = *(s1+n+1); /* Second hex character */
+ buf[2] = NUL;
+ if ((k = ckhexbytetoint((char *)buf)) > -1) {
+ *p++ = (char) k; /* Deposit decoded result */
+ s1 += 2+n; /* and advance the source pointer */
+ } else { /* Fail on conversion error */
+ ckmakmsg(fnval,FNVALL,
+ "<ERROR:NON_HEX_CHARS:\\f",fn,"()>",NULL);
+ goto xunpct;
+ }
+ } else { /* Not a hex escape sequence */
+ *p++ = *s1++; /* Just copy the character */
+ }
+ }
+ *p = NUL; /* Terminate the result string */
+ failed = 0; /* Say we didn't fail */
+ p = fnval; /* Set up result pointer */
+ goto fnend; /* and finish */
+
+ xunpct: /* Error exit */
+ p = fnval;
+ failed = 1;
+ goto fnend;
+ }
+
+/* Check a string for encoding family */
+
+ if (cx == FN_STRINGT) { /* \fstringtype() */
+ p = "UNK";
+ switch (scanstring(bp[0])) {
+ case FT_7BIT: p = "7BIT"; break;
+ case FT_8BIT: p = "8BIT"; break;
+ case FT_UTF8: p = "UTF8"; break;
+ case FT_UCS2: p = "UCS2"; break;
+ case FT_TEXT: p = "TEXT"; break;
+ case FT_BIN: p = "BINARY"; break;
+ }
+ ckstrncpy(fnval,p,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+
+/* String compare s1, s2, [ case ], [ start ] , [ len ] */
+
+ if (cx == FN_STRCMP) {
+ int docase = 0; /* Case matters or not */
+ int start = 0; /* Start of substring */
+ int len = -1; /* Length of substring to compare */
+ int x; char * s1, * s2; /* workers */
+
+ p = "0"; /* Return value */
+ if (argn == 0) { /* Two null strings are equal */
+ ckstrncpy(fnval,p,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+ if (argn == 1) { /* Non-null string > null string */
+ p = "1";
+ ckstrncpy(fnval,p,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+ if (argn > 2) {
+ s = *(bp[2]) ? evalx(bp[2]) : "0"; /* 0 = caseless */
+ if (chknum(s)) docase = atoi(s);
+ if (argn > 3) {
+ s = *(bp[3]) ? evalx(bp[3]) : "1"; /* start is 1-based */
+ if (chknum(s)) start = atoi(s);
+ if (argn > 4) {
+ s = *(bp[4]) ? evalx(bp[4]) : "-1"; /* -1 = whole thing */
+ if (chknum(s)) len = atoi(s);
+ }
+ }
+ }
+ if (start > 0) start--; /* start is 0-based internally */
+ s1 = bp[0]; /* Get length of first arg */
+ x = (int)strlen(s1);
+ if (x > start) /* Point to start position of s1 */
+ s1 += start;
+ else
+ s1 = "";
+ s2 = bp[1]; /* Get length of second arg */
+ x = (int)strlen(s2);
+ if (x > start) /* Point to start position of s2 */
+ s2 += start;
+ else
+ s2 = "";
+ x = ckstrcmp(s,s2,len,docase);
+ p = ckitoa(x);
+ ckstrncpy(fnval,p,FNVALL);
+ p = fnval;
+ goto fnend;
+ }
+
+/* Note: when adding new functions remember to update dohfunc in ckuus2.c. */
+
+ failed = 1;
+ if (fndiags)
+ ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_FUNCTION:\\f",fn,"()>",NULL);
+
+ fnend:
+ /* Free temporary storage for aguments */
+ for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
+ fndepth--;
+ if (failed) { /* Handle failure */
+ debug(F111,"fnend",fnval,errno);
+ if (!p) p = "";
+ if (p[0]) {
+ /* In case this wasn't caught above... */
+ k = strlen(p);
+ if (p[0] != '<' && p[k-1] != '>') {
+ ckmakmsg(fnval,FNVALL,"<ERROR:BAD_ARG:\\f",fn,"()>",NULL);
+ p = fnval;
+ }
+ } else {
+ ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN:\\f",fn,"()>",NULL);
+ p = fnval;
+ }
+ if (fnerror) /* SET FUNCTION ERROR ON */
+ fnsuccess = 0; /* Make command fail (see ckuus5.c) */
+ debug(F111,"fneval failed",p,fnsuccess);
+ if (fndiags) /* SET FUNCTION DIAGNOSTICS ON */
+ printf("?%s\n",p); /* Print error message now. */
+ else
+ return(""); /* Return nothing. */
+ }
+ return(p);
+}
+#endif /* NOSPL */
+
+static char ckpidbuf[32] = "????";
+
+#ifdef VMS
+_PROTOTYP(long zgpid,(void));
+#endif /* VMS */
+
+char *
+ckgetpid() { /* Return pid as string */
+#ifdef CK_PID
+#ifdef OS2
+#define getpid _getpid
+ unsigned long zz;
+#else
+ long zz;
+#endif /* OS2 */
+#ifdef VMS
+ zz = zgpid();
+#else
+ zz = getpid();
+#endif /* VMS */
+ sprintf(ckpidbuf,"%ld",zz); /* SAFE */
+#endif /* CK_PID */
+ return((char *)ckpidbuf);
+}
+
+#ifndef NOSPL
+#define EMBUFLEN 128 /* Error message buffer length */
+
+static char embuf[EMBUFLEN+1];
+
+char * /* Evaluate builtin variable */
+nvlook(s) char *s; {
+ int x, y, cx;
+ long z;
+ char *p;
+#ifndef NODIAL
+ MDMINF * m;
+#endif /* NODIAL */
+#ifndef NOKVERBS /* Keyboard macro material */
+ extern int keymac, keymacx;
+#endif /* NOKVERBS */
+#ifdef CK_LOGIN
+ extern int isguest;
+#endif /* CK_LOGIN */
+ if (!s) s = "";
+ x = strlen(s);
+ if (fndiags) { /* FUNCTION DIAGNOSTIC ON */
+ if (x + 32 < EMBUFLEN)
+ sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE:\\v(%s)>",s); /* SAFE */
+ else
+ sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE>"); /* SAFE */
+ } else /* FUNCTION DIAGNOSTIC OFF */
+ embuf[0] = NUL;
+ x = VVBUFL;
+ p = vvbuf;
+ if (zzstring(s,&p,&x) < 0) { /* e.g. for \v(\%a) */
+ y = -1;
+ } else {
+ s = vvbuf;
+ y = lookup(vartab,s,nvars,&x);
+ }
+ cx = y; /* y is too generic */
+#ifndef NODIAL
+ m = (mdmtyp > 0) ? modemp[mdmtyp] : NULL; /* For \v(m_xxx) variables */
+#endif /* NODIAL */
+
+ debug(F101,"nvlook y","",y);
+
+ switch (y) {
+ case VN_ARGC: /* ARGC */
+ sprintf(vvbuf,"%d",maclvl < 0 ? topargc : macargc[maclvl]); /* SAFE */
+ return(vvbuf);
+
+ case VN_ARGS: /* ARGS */
+ sprintf(vvbuf,"%d",xargs); /* SAFE */
+ return(vvbuf);
+
+ case VN_COUN: /* COUNT */
+ sprintf(vvbuf,"%d",count[cmdlvl]); /* SAFE */
+ return(vvbuf);
+
+ case VN_DATE: /* DATE */
+ ztime(&p); /* Get "asctime" string */
+ if (p == NULL || *p == NUL) return(NULL);
+ vvbuf[0] = p[8]; /* dd */
+ vvbuf[1] = p[9];
+ vvbuf[2] = SP;
+ vvbuf[3] = p[4]; /* mmm */
+ vvbuf[4] = p[5];
+ vvbuf[5] = p[6];
+ vvbuf[6] = SP;
+ for (x = 20; x < 24; x++) /* yyyy */
+ vvbuf[x - 13] = p[x];
+ vvbuf[11] = NUL;
+ return(vvbuf);
+
+ case VN_NDAT: /* Numeric date */
+ ckstrncpy(vvbuf,zzndate(),VVBUFL);
+ return(vvbuf);
+
+ case VN_DIRE: /* DIRECTORY */
+ s = zgtdir(); /* Get current directory */
+ if (!s)
+#ifdef UNIXOROSK
+ s = "./";
+#else
+#ifdef VMS
+ s = "[]";
+#else
+ s = "";
+#endif /* VMS */
+#endif /* UNIXOROSK */
+ ckstrncpy(vvbuf,s,VVBUFL);
+ s = vvbuf;
+#ifdef UNIXOROSK
+ x = strlen(s);
+ if (x < VVBUFL - 1) {
+ if (s[x-1] != '/') {
+ s[x] = '/';
+ s[x+1] = NUL;
+ }
+ }
+#endif /* UNIXOROSK */
+ return(s);
+
+ case VN_FILE: /* filespec */
+ return(fspec);
+
+ case VN_HOST: /* host name */
+ if (*myhost) { /* If known */
+ return(myhost); /* return it. */
+ } else { /* Otherwise */
+ ckstrncpy(vvbuf,"unknown",VVBUFL); /* just say "unknown" */
+ return(vvbuf);
+ }
+
+ case VN_SYST: /* System type */
+#ifdef UNIX
+ ckstrncpy(vvbuf,"UNIX",VVBUFL);
+#else
+#ifdef VMS
+ ckstrncpy(vvbuf,"VMS",VVBUFL);
+#else
+#ifdef OSK
+ ckstrncpy(vvbuf,"OS9/68K",VVBUFL);
+#else
+#ifdef AMIGA
+ ckstrncpy(vvbuf,"Amiga",VVBUFL);
+#else
+#ifdef MAC
+ ckstrncpy(vvbuf,"Macintosh",VVBUFL);
+#else
+#ifdef OS2
+#ifdef NT
+ ckstrncpy(vvbuf,"WIN32",VVBUFL) ;
+#else /* NT */
+ ckstrncpy(vvbuf,"OS/2",VVBUFL);
+#endif /* NT */
+#else
+#ifdef datageneral
+ ckstrncpy(vvbuf,"AOS/VS",VVBUFL);
+#else
+#ifdef GEMDOS
+ ckstrncpy(vvbuf,"Atari_ST",VVBUFL);
+#else
+#ifdef STRATUS
+ ckstrncpy(vvbuf,"Stratus_VOS",VVBUFL);
+#else
+ ckstrncpy(vvbuf,"unknown",VVBUFL);
+#endif /* STRATUS */
+#endif /* GEMDOS */
+#endif /* datageneral */
+#endif /* OS2 */
+#endif /* MAC */
+#endif /* AMIGA */
+#endif /* OSK */
+#endif /* VMS */
+#endif /* UNIX */
+ return(vvbuf);
+
+ case VN_SYSV: /* System herald */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ for (x = y = 0; x < VVBUFL; x++) {
+ if (ckxsys[x] == SP && y == 0) continue;
+ vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
+ }
+ vvbuf[y] = NUL;
+ return(vvbuf);
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_TIME: /* TIME. Assumes that ztime returns */
+ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
+ if (p == NULL || *p == NUL) /* like asctime()! */
+ return("");
+ for (x = 11; x < 19; x++) /* copy hh:mm:ss */
+ vvbuf[x - 11] = p[x]; /* to vvbuf */
+ vvbuf[8] = NUL; /* terminate */
+ return(vvbuf); /* and return it */
+
+ case VN_NTIM: /* Numeric time */
+ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
+ if (p == NULL || *p == NUL) /* like asctime()! */
+ return(NULL);
+ z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ sprintf(vvbuf,"%ld",z); /* SAFE */
+ return(vvbuf);
+
+#ifdef CK_TTYFD
+ case VN_TTYF: /* TTY file descriptor */
+ sprintf(vvbuf,"%d", /* SAFE */
+#ifdef VMS
+ vmsttyfd()
+#else
+ ttyfd
+#endif /* VMS */
+ );
+ return(vvbuf);
+#endif /* CK_TTYFD */
+
+ case VN_VERS: /* Numeric Kermit version number */
+ sprintf(vvbuf,"%ld",vernum); /* SAFE */
+ return(vvbuf);
+
+ case VN_XVNUM: /* Product-specific version number */
+ sprintf(vvbuf,"%ld",xvernum); /* SAFE */
+ return(vvbuf);
+
+ case VN_HOME: /* Home directory */
+ return(homepath());
+
+ case VN_IBUF: /* INPUT buffer */
+ return((char *)inpbuf);
+
+ case VN_ICHR: /* INPUT character */
+ inchar[1] = NUL;
+ return((char *)inchar);
+
+ case VN_ICNT: /* INPUT character count */
+ sprintf(vvbuf,"%d",incount); /* SAFE */
+ return(vvbuf);
+
+ case VN_SPEE: { /* Transmission SPEED */
+ long t;
+ t = ttgspd();
+ if (t < 0L)
+ sprintf(vvbuf,"unknown"); /* SAFE */
+ else
+ sprintf(vvbuf,"%ld",t); /* SAFE */
+ return(vvbuf);
+ }
+
+ case VN_SUCC: /* SUCCESS flag */
+ /* Note inverted sense */
+ sprintf(vvbuf,"%d",(success == 0) ? 1 : 0); /* SAFE */
+ return(vvbuf);
+
+ case VN_LINE: { /* LINE */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"\\v(line) local",ttname,local);
+ debug(F111,"\\v(line) inserver","",inserver);
+#ifdef TNCODE
+ debug(F111,"\\v(line) tcp_incoming","",tcp_incoming);
+#endif /* TNCODE */
+#ifdef CK_TAPI
+ debug(F111,"\\v(line) tttapi","",tttapi);
+#endif /* CK_TAPI */
+ }
+#endif /* DEBUG */
+
+#ifdef CK_TAPI
+ if (tttapi) { /* If I have made a TAPI connection */
+ int i; /* return the TAPI device name */
+ for (i = 0; i < ntapiline; i++) {
+ if (!strcmp(ttname,tapilinetab[i].kwd)) {
+ p = _tapilinetab[i].kwd;
+ return(p);
+ }
+ }
+ }
+#endif /* CK_TAPI */
+#ifndef NOXFER
+ if (inserver /* If I am a TCP server */
+#ifdef TNCODE
+ || tcp_incoming
+#endif /* TNCODE */
+ )
+#ifdef TCPSOCKET
+ p = ckgetpeer(); /* return peer name */
+ else
+#endif /* TCPSOCKET */
+#endif /* NOXFER */
+ if (local) /* Otherwise if in local mode */
+ p = (char *) ttname; /* return SET LINE / SET HOST name */
+ else /* Otherwise */
+ p = ""; /* return empty string */
+ if (!p) /* In case ckgetpeer() returns */
+ p = ""; /* null pointer... */
+ debug(F110,"\\v(line) p",p,0);
+ if (!*p)
+ p = (char *) ttname;
+ return(p);
+ }
+ case VN_PROG: /* Program name */
+ return("C-Kermit");
+
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_RET: /* Value of most recent RETURN */
+ debug(F111,"\\v(return)",mrval[maclvl+1],maclvl+1);
+ p = mrval[maclvl+1];
+ if (p == NULL) p = "";
+ return(p);
+
+ case VN_FFC: /* Size of most recent file */
+ sprintf(vvbuf, "%s", ckfstoa(ffc)); /* SAFE */
+ return(vvbuf);
+
+ case VN_TFC: /* Size of most recent file group */
+ sprintf(vvbuf, "%s", ckfstoa(tfc)); /* SAFE */
+ return(vvbuf);
+
+ case VN_CPU: /* CPU type */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+#ifdef OS2
+ {
+ char * getcpu(void) ;
+ return getcpu();
+ }
+#else /* OS2 */
+#ifdef CKCPU
+ return(CKCPU); /* Traditionally, compile-time value */
+#else
+#ifdef CK_UTSNAME
+ { /* But if none, try runtime value */
+ extern char unm_mch[];
+ return((char *)unm_mch);
+ }
+#else
+ p = getenv("HOSTTYPE"); /* 20091116 */
+ if (p) if (*p) return(p);
+ return("unknown");
+#endif /* CK_UTSNAME */
+#endif /* CKCPU */
+#endif /* OS2 */
+
+ case VN_CMDL: /* Command level */
+ sprintf(vvbuf, "%d", cmdlvl); /* SAFE */
+ return(vvbuf);
+
+ case VN_DAY: /* Day of week */
+ ztime(&p);
+ if (p != NULL && *p != NUL) /* ztime() succeeded. */
+ ckstrncpy(vvbuf,p,4);
+ else
+ vvbuf[0] = NUL; /* ztime() failed. */
+ return(vvbuf); /* Return what we got. */
+
+ case VN_NDAY: { /* Numeric day of week */
+ long k;
+ z = mjd(zzndate()); /* Get modified Julian date */
+ k = (((int)(z % 7L)) + 3) % 7; /* Get day number */
+ sprintf(vvbuf,"%ld",k); /* SAFE */
+ return(vvbuf);
+ }
+
+ case VN_LCL: /* Local (vs remote) mode */
+ ckstrncpy(vvbuf, local ? "1" : "0",VVBUFL);
+ return(vvbuf);
+
+ case VN_CMDS: /* Command source */
+ if (cmdstk[cmdlvl].src == CMD_KB)
+ ckstrncpy(vvbuf,"prompt",VVBUFL);
+ else if (cmdstk[cmdlvl].src == CMD_MD)
+ ckstrncpy(vvbuf,"macro",VVBUFL);
+ else if (cmdstk[cmdlvl].src == CMD_TF)
+ ckstrncpy(vvbuf,"file",VVBUFL);
+ else
+ ckstrncpy(vvbuf,"unknown",VVBUFL);
+ return(vvbuf);
+
+ case VN_CMDF: /* Current command file name */
+#ifdef COMMENT /* (see comments above) */
+ if (tfnam[tlevel]) { /* (near dblbs declaration) */
+ dblbs(tfnam[tlevel],vvbuf,VVBUFL);
+ return(vvbuf);
+ } else return("");
+#else
+ if (tlevel < 0)
+ return("");
+ else
+ return(tfnam[tlevel] ? tfnam[tlevel] : "");
+#endif /* COMMENT */
+
+ case VN_MAC: /* Current macro name */
+ return((maclvl > -1) ? m_arg[maclvl][0] : "");
+
+ case VN_EXIT:
+ sprintf(vvbuf,"%d",xitsta); /* SAFE */
+ return(vvbuf);
+
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_PRTY: { /* Parity */
+ char *ss;
+ switch (parity) {
+ case 0: ss = "none"; break;
+ case 'e': ss = "even"; break;
+ case 'm': ss = "mark"; break;
+ case 'o': ss = "odd"; break;
+ case 's': ss = "space"; break;
+ default: ss = "unknown"; break;
+ }
+ ckstrncpy(vvbuf,ss,VVBUFL);
+ return(vvbuf);
+ }
+
+ case VN_DIAL:
+ sprintf(vvbuf,"%d", /* SAFE */
+#ifndef NODIAL
+ dialsta
+#else
+ -1
+#endif /* NODIAL */
+ );
+ return(vvbuf);
+
+#ifndef NODIAL
+ case VN_DMSG:
+#ifdef BIGBUFOK
+ ckstrncpy(vvbuf,dialmsg[dialsta],VVBUFL); /* Safe if src == NULL */
+#endif /* BIGBUFOK */
+ return((char *)vvbuf);
+#endif /* NODIAL */
+
+#ifdef OS2
+ case VN_KEYB:
+ ckstrncpy(vvbuf,conkbg(),VVBUFL);
+ return(vvbuf);
+ case VN_SELCT: {
+#ifndef NOLOCAL
+ const char * selection = GetSelection();
+ return( (char *) (selection ? selection : "" )) ;
+#else
+ return("");
+#endif /* NOLOCAL */
+ }
+#endif /* OS2 */
+
+#ifndef NOXFER
+ case VN_CPS:
+ sprintf(vvbuf,"%ld",tfcps); /* SAFE */
+ return(vvbuf);
+#endif /* NOXFER */
+
+ case VN_MODE: /* File transfer mode */
+ switch (binary) {
+ case XYFT_T: ckstrncpy(vvbuf,"text",VVBUFL); break;
+ case XYFT_B:
+ case XYFT_U: ckstrncpy(vvbuf,"binary",VVBUFL); break;
+ case XYFT_I: ckstrncpy(vvbuf,"image",VVBUFL); break;
+ case XYFT_L: ckstrncpy(vvbuf,"labeled",VVBUFL); break;
+ case XYFT_M: ckstrncpy(vvbuf,"macbinary",VVBUFL); break;
+ default: ckstrncpy(vvbuf,"unknown",VVBUFL);
+ }
+ return(vvbuf);
+
+#ifdef CK_REXX
+ case VN_REXX:
+ return(rexxbuf);
+#endif /* CK_REXX */
+
+ case VN_NEWL: /* System newline char or sequence */
+#ifdef UNIX
+ ckstrncpy(vvbuf,"\n",VVBUFL);
+#else
+#ifdef datageneral
+ ckstrncpy(vvbuf,"\n",VVBUFL);
+#else
+#ifdef OSK
+ ckstrncpy(vvbuf,"\15",VVBUFL); /* Remember, these are octal... */
+#else
+#ifdef MAC
+ ckstrncpy(vvbuf,"\15",VVBUFL);
+#else
+#ifdef OS2
+ ckstrncpy(vvbuf,"\15\12",VVBUFL);
+#else
+#ifdef STRATUS
+ ckstrncpy(vvbuf,"\n",VVBUFL);
+#else
+#ifdef VMS
+ ckstrncpy(vvbuf,"\15\12",VVBUFL);
+#else
+#ifdef AMIGA
+ ckstrncpy(vvbuf,"\n",VVBUFL);
+#else
+#ifdef GEMDOS
+ ckstrncpy(vvbuf,"\n",VVBUFL);
+#else
+ ckstrncpy(vvbuf,"\n",VVBUFL);
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* MAC */
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* UNIX */
+ return(vvbuf);
+
+ case VN_ROWS: /* ROWS */
+ case VN_COLS: /* COLS */
+ ckstrncpy(vvbuf,(cx == VN_ROWS) ? "24" : "80",VVBUFL); /* Default */
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
+ ttgwsiz();
+ sprintf(vvbuf,"%d", /* SAFE */
+ (cx == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]);
+#else /* OS2 */
+ if (ttgwsiz() > 0) /* Get window size */
+ if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
+ sprintf(vvbuf,"%d", /* SAFE */
+ (cx == VN_ROWS) ? tt_rows : tt_cols);
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+ return(vvbuf);
+
+ case VN_TTYP:
+#ifdef NOTERM
+ ckstrncpy(vvbuf,"unknown",VVBUFL);
+#else
+#ifdef OS2
+ sprintf(vvbuf, "%s", /* SAFE */
+ (tt_type >= 0 && tt_type <= max_tt) ?
+ tt_info[tt_type].x_name :
+ "unknown"
+ );
+#else
+#ifdef MAC
+ ckstrncpy(vvbuf,"vt320",VVBUFL);
+#else
+ p = getenv("TERM");
+ ckstrncpy(vvbuf,p ? p : "unknown",VVBUFL+1);
+#endif /* MAC */
+#endif /* OS2 */
+#endif /* NOTERM */
+ return(vvbuf);
+
+ case VN_MINP: /* MINPUT */
+ sprintf(vvbuf, "%d", m_found); /* SAFE */
+ return(vvbuf);
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_CONN: /* CONNECTION */
+ if (!local) {
+ ckstrncpy(vvbuf,"remote",VVBUFL);
+ } else {
+ if (!network)
+ ckstrncpy(vvbuf,"serial",VVBUFL);
+#ifdef TCPSOCKET
+ else if (nettype == NET_TCPB || nettype == NET_TCPA) {
+ if (ttnproto == NP_TELNET)
+ ckstrncpy(vvbuf,"tcp/ip_telnet",VVBUFL);
+#ifdef CK_SSL
+ else if (ttnproto == NP_SSL || ttnproto == NP_SSL_RAW)
+ ckstrncpy(vvbuf,"tcp/ip_ssl",VVBUFL);
+ else if (ttnproto == NP_TLS || ttnproto == NP_SSL_RAW)
+ ckstrncpy(vvbuf,"tcp/ip_tls",VVBUFL);
+#endif /* CK_SSL */
+ else
+ ckstrncpy(vvbuf,"tcp/ip",VVBUFL);
+ }
+#endif /* TCPSOCKET */
+#ifdef SSHBUILTIN
+ else if (nettype == NET_SSH)
+ ckstrncpy(vvbuf,"tcp/ip_ssh",VVBUFL);
+#endif /* SSHBUILTIN */
+#ifdef ANYX25
+ else if (nettype == NET_SX25 ||
+ nettype == NET_VX25 ||
+ nettype == NET_IX25
+ )
+ ckstrncpy(vvbuf,"x.25",VVBUFL);
+#endif /* ANYX25 */
+#ifdef DECNET
+ else if (nettype == NET_DEC) {
+ if (ttnproto == NP_LAT)
+ ckstrncpy(vvbuf,"decnet_lat",VVBUFL);
+ else if ( ttnproto == NP_CTERM )
+ ckstrncpy(vvbuf,"decnet_cterm",VVBUFL);
+ else
+ ckstrncpy(vvbuf,"decnet",VVBUFL);
+ }
+#endif /* DECNET */
+#ifdef SUPERLAT
+ else if (nettype == NET_SLAT)
+ ckstrncpy(vvbuf,"superlat",VVBUFL);
+#endif /* SUPERLAT */
+#ifdef NETFILE
+ else if (nettype == NET_FILE)
+ ckstrncpy(vvbuf,"local_file",VVBUFL);
+#endif /* NETFILE */
+#ifdef NETCMD
+ else if (nettype == NET_CMD)
+ ckstrncpy(vvbuf,"pipe",VVBUFL);
+#endif /* NETCMD */
+#ifdef NETPTY
+ else if (nettype == NET_PTY)
+ ckstrncpy(vvbuf,"pseudoterminal",VVBUFL);
+#endif /* NETPTY */
+#ifdef NETDLL
+ else if (nettype == NET_DLL)
+ ckstrncpy(vvbuf,"dynamic_link_library",VVBUFL);
+#endif /* NETDLL */
+
+#ifdef NPIPE
+ else if (nettype == NET_PIPE)
+ ckstrncpy(vvbuf,"named_pipe",VVBUFL);
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+ else if (nettype == NET_BIOS)
+ ckstrncpy(vvbuf,"netbios",VVBUFL);
+#endif /* CK_NETBIOS */
+ else
+ ckstrncpy(vvbuf,"unknown",VVBUFL);
+ }
+ return(vvbuf);
+
+#ifndef NOXFER
+ case VN_SYSI: /* System ID, Kermit code */
+ return((char *)cksysid);
+#endif /* NOXFER */
+
+#ifdef OS2
+ case VN_SPA: {
+ unsigned long space = zdskspace(0);
+ if (space > 0 && space < 1024)
+ sprintf(vvbuf,"-1");
+ else
+ sprintf(vvbuf,"%lu",space); /* SAFE */
+ return(vvbuf);
+ }
+#endif /* OS2 */
+
+#ifndef NOXFER
+ case VN_QUE: {
+ extern char querybuf[];
+ return(querybuf);
+ }
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+ case VN_CSET:
+#ifdef OS2
+ sprintf(vvbuf,"cp%d",os2getcp()); /* SAFE */
+#else
+ ckstrncpy(vvbuf,fcsinfo[fcharset].keyword,VVBUFL+1);
+#endif /* OS2 */
+ return(vvbuf);
+#endif /* NOCSETS */
+
+#ifdef OS2
+ case VN_EXEDIR:
+ return(exedir);
+ case VN_STAR:
+ return(startupdir);
+#else
+ case VN_EXEDIR:
+ return(exedir ? exedir : "");
+#ifdef VMSORUNIX
+ case VN_STAR:
+ return(startupdir);
+#endif /* VMSORUNIX */
+#endif /* OS2 */
+
+ case VN_INI:
+ return(inidir);
+
+ case VN_MDM:
+ return(gmdmtyp());
+
+ case VN_EVAL:
+ return(evalbuf);
+
+#ifndef NODIAL
+ case VN_D_CC: /* DIAL COUNTRY-CODE */
+ return(diallcc ? diallcc : "");
+
+ case VN_D_AC: /* DIAL AREA-CODE */
+ return(diallac ? diallac : "");
+
+ case VN_D_IP: /* DIAL INTERNATIONAL-PREFIX */
+ return(dialixp ? dialixp : "");
+
+ case VN_D_LP: /* DIAL LD-PREFIX */
+ return(dialldp ? dialldp : "");
+
+ case VN_D_LCP: /* DIAL LOCAL-PREFIX */
+ return(diallcp ? diallcp : "");
+
+ case VN_D_PXX: /* DIAL PBX-EXCHANGE that matched */
+ return(matchpxx ? matchpxx : "");
+#else
+ case VN_D_CC: /* DIAL COUNTRY-CODE */
+ case VN_D_AC: /* DIAL AREA-CODE */
+ case VN_D_IP: /* DIAL INTERNATIONAL-PREFIX */
+ case VN_D_LP: /* DIAL LD-PREFIX */
+ case VN_D_LCP: /* DIAL LOCAL-PREFIX */
+ case VN_D_PXX: /* DIAL PBX-EXCHANGE */
+ return("");
+#endif /* NODIAL */
+ case VN_UID:
+#ifdef UNIX
+ {
+#ifdef IKSD
+ if (inserver)
+ return((char *)uidbuf);
+ else
+#endif /* IKSD */
+ if (uidbuf[0])
+ return((char *)uidbuf);
+ else
+ return(whoami());
+ }
+#else
+ return((char *)uidbuf);
+#endif /* UNIX */
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_PWD:
+#ifdef OS2
+ if (activecmd == XXOUT || activecmd == XXLNOUT) {
+ ckstrncpy(vvbuf,pwbuf,VVBUFL);
+ ck_encrypt((char *)vvbuf);
+ return((char *)vvbuf);
+ } else
+#endif /* OS2 */
+ return((char *)pwbuf);
+
+ case VN_PRM:
+ return((char *)prmbuf);
+
+ case VN_PROTO:
+#ifdef NOXFER
+ return("none");
+#else
+#ifdef CK_XYZ
+ return(ptab[protocol].p_name);
+#else
+ return("kermit");
+#endif /* CK_XYZ */
+#endif /* NOXFER */
+
+#ifndef NOXFER
+#ifdef CK_TMPDIR
+ case VN_DLDIR:
+ return(dldir ? dldir : "");
+#endif /* CK_TMPDIR */
+#endif /* NOXFER */
+
+#ifndef NODIAL
+ case VN_M_INI: /* Modem init string */
+ return(dialini ? dialini : (m ? m->wake_str : ""));
+
+ case VN_M_DCM: /* Modem dial command */
+ return(dialcmd ? dialcmd : (m ? m->dial_str : ""));
+
+ case VN_M_DCO: /* Modem data compression on */
+ return(dialdcon ? dialdcon : (m ? m->dc_on_str : ""));
+
+ case VN_M_DCX: /* Modem data compression off */
+ return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : ""));
+
+ case VN_M_ECO: /* Modem error correction on */
+ return(dialecon ? dialecon : (m ? m->ec_on_str : ""));
+
+ case VN_M_ECX: /* Modem error correction off */
+ return(dialecoff ? dialecoff : (m ? m->ec_off_str : ""));
+
+ case VN_M_AAO: /* Modem autoanswer on */
+ return(dialaaon ? dialaaon : (m ? m->aa_on_str : ""));
+
+ case VN_M_AAX: /* Modem autoanswer off */
+ return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : ""));
+
+ case VN_M_HUP: /* Modem hangup command */
+ return(dialhcmd ? dialhcmd : (m ? m->hup_str : ""));
+
+ case VN_M_HWF: /* Modem hardware flow command */
+ return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : ""));
+
+ case VN_M_SWF: /* Modem software flow command */
+ return(dialswfc ? dialswfc : (m ? m->swfc_str : ""));
+
+ case VN_M_NFC: /* Modem no flow-control command */
+ return(dialnofc ? dialnofc : (m ? m->nofc_str : ""));
+
+ case VN_M_PDM: /* Modem pulse dialing mode */
+ return(dialpulse ? dialpulse : (m ? m->pulse : ""));
+
+ case VN_M_TDM: /* Modem tone dialing mode */
+ return(dialtone ? dialtone : (m ? m->tone : ""));
+
+ case VN_M_NAM: /* Modem full name */
+ return(dialname ? dialname : (m ? m->name : ""));
+#else
+ case VN_M_INI: /* Modem init string */
+ case VN_M_DCM: /* Modem dial command */
+ case VN_M_DCO: /* Modem data compression on */
+ case VN_M_DCX: /* Modem data compression off */
+ case VN_M_ECO: /* Modem error correction on */
+ case VN_M_ECX: /* Modem error correction off */
+ case VN_M_AAO: /* Modem autoanswer on */
+ case VN_M_AAX: /* Modem autoanswer off */
+ case VN_M_HUP: /* Modem hangup command */
+ case VN_M_HWF: /* Modem hardware flow command */
+ case VN_M_SWF: /* Modem software flow command */
+ case VN_M_NFC: /* Modem no flow-control command */
+ case VN_M_PDM: /* Modem pulse dialing mode */
+ case VN_M_TDM: /* Modem tone dialing mode */
+ case VN_M_NAM:
+ return("");
+#endif /* NODIAL */
+
+ case VN_ISTAT: /* INPUT status */
+ sprintf(vvbuf, "%d", instatus); /* SAFE */
+ return(vvbuf);
+
+ case VN_TEMP: /* Temporary directory */
+ if (tempdir) {
+ p = tempdir;
+ } else {
+#ifdef OS2
+#ifdef NT
+ p = getenv("K95TMP");
+#else
+ p = getenv("K2TMP");
+#endif /* NT */
+ if ( !p )
+#endif /* OS2 */
+ p = getenv("CK_TMP");
+ if (!p) p = getenv("TMPDIR");
+ if (!p) p = getenv("TEMP");
+ if (!p) p = getenv("TMP");
+
+#ifdef OS2ORUNIX
+ if (p) {
+ int len = strlen(p);
+ if (p[len-1] != '/'
+#ifdef OS2
+ && p[len-1] != '\\'
+#endif /* OS2 */
+ ) {
+ static char foo[CKMAXPATH];
+ ckstrncpy(foo,p,CKMAXPATH);
+ ckstrncat(foo,"/",CKMAXPATH);
+ p = foo;
+ }
+ } else
+#else /* OS2ORUNIX */
+ if (!p)
+#endif /* OS2ORUNIX */
+#ifdef UNIX /* Systems that have a standard */
+ p = "/tmp/"; /* temporary directory... */
+#else
+#ifdef datageneral
+ p = ":TMP:";
+#else
+ p = "";
+#endif /* datageneral */
+#endif /* UNIX */
+ }
+ ckstrncpy(vvbuf,p,VVBUFL);
+ p = vvbuf;
+
+/* This needs generalizing for VOS, AOS/VS, etc... */
+
+ while (*p) {
+#ifdef OS2
+ if (*p == '\\') *p = '/';
+#endif /* OS2 */
+ p++;
+ }
+#ifndef VMS
+ if (p > vvbuf) {
+ char c = /* Directory termination character */
+#ifdef MAC
+ ':'
+#else
+#ifdef datageneral
+ ':'
+#else
+#ifdef STRATUS
+ '>'
+#else
+ '/'
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* MAC */
+ ;
+
+ if (*(p-1) != c) {
+ *p++ = c;
+ *p = NUL;
+ }
+ }
+#endif /* VMS */
+ return(vvbuf);
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_ERRNO: /* Error number */
+#ifdef VMS
+ {
+ extern int vms_lasterr;
+ sprintf(vvbuf, "%d", vms_lasterr); /* SAFE */
+ }
+#else
+ sprintf(vvbuf, "%d", errno); /* SAFE */
+#endif /* VMS */
+ return(vvbuf);
+
+ case VN_ERSTR: /* Error string */
+ ckstrncpy(vvbuf,ck_errstr(),VVBUFL);
+ return(vvbuf);
+
+#ifndef NOXFER
+ case VN_RPSIZ: /* RECEIVE packet-length */
+ sprintf(vvbuf,"%d",urpsiz); /* SAFE */
+ return(vvbuf);
+
+ case VN_WINDO: /* WINDOW slots */
+ sprintf(vvbuf,"%d",wslotr); /* SAFE */
+ return(vvbuf);
+#endif /* NOXFER */
+
+ case VN_TFLN: /* TAKE-file line number */
+ if (tlevel > -1) {
+ sprintf(vvbuf, "%d", tfline[tlevel]); /* SAFE */
+ return(vvbuf);
+ } else
+ return("0");
+
+ case VN_MDMSG: /* DIALRESULT */
+#ifndef NODIAL
+ return((char *)modemmsg);
+#else
+ return("");
+#endif /* NODIAL */
+
+ case VN_DNUM: /* DIALNUMBER */
+#ifndef NODIAL
+ return(dialnum ? (char *) dialnum : "");
+#else
+ return("");
+#endif /* NODIAL */
+
+ case VN_APC:
+ sprintf(vvbuf, "%d", /* SAFE */
+#ifdef CK_APC
+ apcactive
+#else
+ 0
+#endif /* CK_APC */
+ );
+ return((char *)vvbuf);
+
+#ifdef OS2
+#ifndef NOKVERBS
+ case VN_TRMK:
+ sprintf(vvbuf, "%d", keymac); /* SAFE */
+ return((char *)vvbuf);
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+ case VN_IPADDR:
+#ifdef TCPSOCKET
+#ifndef OSK
+ /* This dumps core on OS-9 for some reason, but only if executed */
+ /* before we have made a TCP connection. This is obviously not */
+ /* the ideal fix. */
+ if (!myipaddr[0])
+ getlocalipaddr();
+#endif /* OSK */
+#endif /* TCPSOCKET */
+ ckstrncpy(vvbuf,
+#ifdef TCPSOCKET
+ (char *)myipaddr,
+#else
+ "",
+#endif /* TCPSOCKET */
+ VVBUFL);
+ return((char *)vvbuf);
+
+#ifndef NOXFER
+ case VN_CRC16: /* CRC-16 of most recent transfer */
+ sprintf(vvbuf,"%d",crc16); /* SAFE */
+ return(vvbuf);
+#endif /* NOXFER */
+
+#ifdef CK_PID
+ case VN_PID:
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ return(ckgetpid());
+#endif /* CK_PID */
+
+#ifndef NOXFER
+ case VN_FNAM: { /* \v(filename) */
+ extern char filnam[], ofn1[], *sfspec, *rrfspec;
+ char * tmp;
+ switch (what) { /* File transfer is in progress */
+#ifdef NEWFTP
+ case (W_FTP|W_RECV):
+ case (W_FTP|W_SEND):
+ return((char *)filnam);
+#endif /* NEWFTP */
+ case W_RECV:
+ case W_REMO:
+ return((char *)ofn1);
+ default: /* Most recent file transferred */
+ if (filnam[0]) { /* (if any) */
+ return((char *)filnam);
+ } else if (lastxfer & W_SEND && sfspec) {
+ if (fnspath == PATH_OFF)
+ zstrip(sfspec,&tmp);
+ else
+ tmp = sfspec;
+ return(tmp);
+ } else if (lastxfer & W_RECV && rrfspec) {
+ if (fnrpath == PATH_OFF)
+ zstrip(rrfspec,&tmp);
+ else
+ tmp = rrfspec;
+ return(tmp);
+ } else
+ return("");
+ }
+ }
+ case VN_FNUM: /* \v(filenum) */
+ sprintf(vvbuf,"%ld",filcnt); /* SAFE */
+ return((char *)vvbuf);
+#endif /* NOXFER */
+
+#ifdef PEXITSTAT
+ case VN_PEXIT: {
+ extern int pexitstat;
+ sprintf(vvbuf,"%d",pexitstat); /* SAFE */
+ return((char *)vvbuf);
+ }
+#endif /* PEXITSTAT */
+
+#ifndef NOXFER
+ case VN_P_8BIT:
+ vvbuf[0] = parity ? ebq : NUL;
+ vvbuf[1] = NUL;
+ return((char *)vvbuf);
+
+ case VN_P_CTL: {
+ extern CHAR myctlq;
+ vvbuf[0] = myctlq;
+ vvbuf[1] = NUL;
+ return((char *)vvbuf);
+ }
+ case VN_P_RPT: {
+ extern int rptena;
+ vvbuf[0] = rptena ? rptq : NUL;
+ vvbuf[1] = NUL;
+ return((char *)vvbuf);
+ }
+#endif /* NOXFER */
+
+#ifdef OS2
+ case VN_REGN:
+ return(get_reg_name());
+ case VN_REGO:
+ return(get_reg_corp());
+ case VN_REGS:
+ return(get_reg_sn());
+#endif /* OS2 */
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_XPROG:
+#ifdef OS2
+#ifdef NT
+#ifdef KUI
+ return("K-95G");
+#else
+ return("K-95");
+#endif /* KUI */
+#else
+ return("K/2");
+#endif /* NT */
+#else
+ return("C-Kermit");
+#endif /* OS2 */
+
+ case VN_EDITOR:
+#ifdef NOFRILLS
+ return("");
+#else
+#ifdef NOPUSH
+ return("");
+#else
+ {
+ extern char editor[];
+ char *ss;
+ if (!editor[0]) {
+ ss = getenv("EDITOR");
+ if (ss) {
+ ckstrncpy(editor,ss,CKMAXPATH);
+ }
+ }
+ debug(F110,"\\v(editor)",editor,0);
+ return(editor[0] ? (char *)editor : "");
+ }
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+ case VN_EDOPT:
+#ifdef NOFRILLS
+ return("");
+#else
+#ifdef NOPUSH
+ return("");
+#else
+ {
+ extern char editopts[];
+ return(editopts[0] ? (char *)editopts : "");
+ }
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+ case VN_EDFILE:
+#ifdef NOFRILLS
+ return("");
+#else
+#ifdef NOPUSH
+ return("");
+#else
+ {
+ extern char editfile[];
+ return(editfile[0] ? (char *)editfile : "");
+ }
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+#ifdef BROWSER
+ case VN_BROWSR: {
+ extern char browser[];
+ if (!browser[0]) {
+ s = getenv("BROWSER");
+ if (s) ckstrncpy(browser,s,CKMAXPATH);
+ }
+ return(browser[0] ? (char *)browser : "");
+ }
+ case VN_BROPT: {
+ extern char browsopts[];
+ return(browsopts[0] ? (char *)browsopts : "");
+ }
+ case VN_URL: {
+ extern char browsurl[];
+ return(browsurl[0] ? (char *)browsurl : "");
+ }
+#endif /* BROWSER */
+ case VN_HERALD:
+ return((char *)versio);
+
+ case VN_TEST: { /* test */
+ extern char * ck_s_test, * ck_s_tver;
+ if (!ck_s_test) ck_s_test = "";
+ if (!ck_s_tver) ck_s_tver = "";
+ if (*ck_s_test) {
+ ckstrncpy(vvbuf,ck_s_test,VVBUFL);
+ if (*ck_s_tver) {
+ ckstrncat(vvbuf,".",VVBUFL);
+ ckstrncat(vvbuf,ck_s_tver,VVBUFL);
+ }
+ } else
+ ckstrncpy(vvbuf,"0",VVBUFL);
+ return((char *)vvbuf);
+ }
+
+#ifndef NOXFER
+ case VN_XFSTAT: /* xferstatus */
+ x = xferstat; /* Like success */
+ if (x > -1) x = (x == 0) ? 1 : 0; /* External value is reversed */
+ sprintf(vvbuf,"%d",x); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_XFMSG: /* xfermsg */
+ return((char *)epktmsg);
+
+#ifndef NOMSEND
+ case VN_SNDL: { /* sendlist */
+ extern int filesinlist;
+ sprintf(vvbuf,"%d",filesinlist); /* SAFE */
+ return((char *)vvbuf);
+ }
+#endif /* NOMSEND */
+#endif /* NOXFER */
+
+#ifdef CK_TRIGGER
+ case VN_TRIG: {
+ extern char * triggerval;
+ return(triggerval ? triggerval : "");
+ }
+#endif /* CK_TRIGGER */
+#ifdef OS2MOUSE
+#ifdef OS2
+ case VN_MOU_X: {
+ extern int MouseCurX;
+ sprintf(vvbuf,"%d",MouseCurX); /* SAFE */
+ return((char *)vvbuf);
+ }
+ case VN_MOU_Y: {
+ extern int MouseCurY;
+ sprintf(vvbuf,"%d",MouseCurY); /* SAFE */
+ return((char *)vvbuf);
+ }
+#endif /* OS2 */
+#endif /* OS2MOUSE */
+ case VN_PRINT: {
+ extern int printpipe;
+ extern char * printername;
+#ifdef PRINTSWI
+ extern int noprinter;
+ if (noprinter) return("");
+#endif /* PRINTSWI */
+ ckmakmsg(vvbuf,VVBUFL,
+ printpipe ? "|" : "",
+ printername ? printername :
+#ifdef OS2
+ "PRN",
+#else
+ "(default)",
+#endif /* OS2 */
+ NULL,
+ NULL
+ );
+ return((char *)vvbuf);
+ }
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_ESC: /* Escape character */
+ sprintf(vvbuf,"%d",escape); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_INTIME:
+ sprintf(vvbuf,"%ld",inetime); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_INTMO:
+ sprintf(vvbuf,"%d",inwait); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_SECURE:
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+ )
+ return("1");
+ else
+ return("0");
+
+ case VN_AUTHN:
+#ifdef CK_AUTHENTICATION
+ {
+ extern char szUserNameAuthenticated[];
+ return((char *)szUserNameAuthenticated);
+ }
+#else /* CK_AUTHENTICATION */
+ return((char *)"");
+#endif /* CK_AUTHENTICATION */
+
+ case VN_AUTHS:
+#ifdef CK_AUTHENTICATION
+ switch (ck_tn_auth_valid()) {
+ case AUTH_UNKNOWN:
+ return((char *)"unknown");
+ case AUTH_OTHER:
+ return((char *)"other");
+ case AUTH_USER:
+ return((char *)"user");
+ case AUTH_VALID:
+ return((char *)"valid");
+ case AUTH_REJECT:
+ default:
+ return((char *)"rejected");
+ }
+#else /* CK_AUTHENTICATION */
+ return((char *)"rejected");
+#endif /* CK_AUTHENTICATION */
+
+ case VN_AUTHT:
+#ifdef CK_AUTHENTICATION
+#ifdef CK_SSL
+ if ((ssl_active_flag || tls_active_flag) &&
+ ck_tn_auth_valid() == AUTH_VALID &&
+ (sstelnet ? (!TELOPT_U(TELOPT_AUTHENTICATION)) :
+ (!TELOPT_ME(TELOPT_AUTHENTICATION))) ||
+ ck_tn_authenticated() == AUTHTYPE_NULL ||
+ ck_tn_authenticated() == AUTHTYPE_AUTO)
+ return("X_509_CERTIFICATE");
+ else
+#endif /* CK_SSL */
+ return(AUTHTYPE_NAME(ck_tn_authenticated()));
+#else /* CK_AUTHENTICATION */
+ return((char *)"NULL");
+#endif /* CK_AUTHENTICATION */
+
+#ifdef CK_KERBEROS
+ case VN_K4PRN: {
+ extern char * krb4_d_principal;
+ if (krb4_d_principal)
+ ckstrncpy(vvbuf,krb4_d_principal,VVBUFL+1);
+ else
+ *vvbuf = NUL;
+ return((char *)vvbuf);
+ }
+ case VN_K5PRN: {
+ extern char * krb5_d_principal;
+ if (krb5_d_principal)
+ ckstrncpy(vvbuf,krb5_d_principal,VVBUFL+1);
+ else
+ *vvbuf = NUL;
+ return((char *)vvbuf);
+ }
+ case VN_K4RLM: {
+ extern char * krb4_d_realm;
+ if (krb4_d_realm) {
+ ckstrncpy(vvbuf,krb4_d_realm,VVBUFL+1);
+ } else {
+ char * s = ck_krb4_getrealm();
+ ckstrncpy(vvbuf,s ? s : "",VVBUFL+1);
+ }
+ return((char *)vvbuf);
+ }
+ case VN_K4SRV: {
+ extern char * krb4_d_srv;
+ if (krb4_d_srv)
+ ckstrncpy(vvbuf,krb4_d_srv,VVBUFL+1);
+ else
+ ckstrncpy(vvbuf,"rcmd",VVBUFL);
+ return((char *)vvbuf);
+ }
+ case VN_K5RLM: {
+ extern char * krb5_d_realm;
+ extern char * krb5_d_cc;
+ if (krb5_d_realm) {
+ ckstrncpy(vvbuf,krb5_d_realm,VVBUFL+1);
+ } else {
+ char * s = ck_krb5_getrealm(krb5_d_cc);
+ ckstrncpy(vvbuf,s,VVBUFL+1);
+ }
+ return((char *)vvbuf);
+ }
+ case VN_K5CC: {
+ extern char * krb5_d_cc;
+ if (krb5_d_cc)
+ ckstrncpy(vvbuf,krb5_d_cc,VVBUFL+1);
+ else
+ ckstrncpy(vvbuf,ck_krb5_get_cc_name(),VVBUFL+1);
+ return((char *)vvbuf);
+ }
+ case VN_K5SRV: {
+ extern char * krb5_d_srv;
+ if (krb5_d_srv)
+ ckstrncpy(vvbuf,krb5_d_srv,VVBUFL+1);
+ else
+ ckstrncpy(vvbuf,"host",VVBUFL);
+ return((char *)vvbuf);
+ }
+ case VN_K4ENO: {
+ extern int krb4_errno;
+ sprintf(vvbuf,"%d",krb4_errno); /* SAFE */
+ return((char *)vvbuf);
+ }
+ case VN_K5ENO: {
+ extern int krb5_errno;
+ sprintf(vvbuf,"%d",krb5_errno); /* SAFE */
+ return((char *)vvbuf);
+ }
+ case VN_K4EMSG: {
+ extern char * krb4_errmsg;
+ ckstrncpy(vvbuf,krb4_errmsg?krb4_errmsg:"",VVBUFL+1);
+ return((char *)vvbuf);
+ }
+ case VN_K5EMSG: {
+ extern char * krb5_errmsg;
+ ckstrncpy(vvbuf,krb5_errmsg,VVBUFL+1);
+ return((char *)vvbuf);
+ }
+#endif /* CK_KERBEROS */
+#ifdef CK_SSL
+ case VN_X509_S:
+ if (ssl_active_flag)
+ ckstrncpy(vvbuf,ssl_get_subject_name(ssl_con),VVBUFL+1);
+ else if (tls_active_flag)
+ ckstrncpy(vvbuf,ssl_get_subject_name(tls_con),VVBUFL+1);
+ else
+ ckstrncpy(vvbuf,"",VVBUFL+1);
+ return((char *)vvbuf);
+ case VN_X509_I:
+ if (ssl_active_flag)
+ ckstrncpy(vvbuf,ssl_get_issuer_name(ssl_con),VVBUFL+1);
+ else if (tls_active_flag)
+ ckstrncpy(vvbuf,ssl_get_issuer_name(tls_con),VVBUFL+1);
+ else
+ ckstrncpy(vvbuf,"",VVBUFL+1);
+ return((char *)vvbuf);
+#endif /* CK_SSL */
+
+ case VN_OSNAM:
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+#ifdef CK_UTSNAME
+ {
+ extern char unm_nam[];
+ return((char *)unm_nam);
+ }
+#else
+ for (x = y = 0; x < VVBUFL; x++) {
+ if (ckxsys[x] == SP && cx == 0) continue;
+ vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
+ }
+ vvbuf[y] = NUL;
+ return(vvbuf);
+#endif /* CK_UTSNAME */
+
+ case VN_OSVER: {
+#ifdef CK_UTSNAME
+ extern char unm_ver[];
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ return((char *)unm_ver);
+#else
+ return("");
+#endif /* CK_UTSNAME */
+ }
+
+ case VN_OSREL: {
+#ifdef CK_UTSNAME
+ extern char unm_rel[];
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ return((char *)unm_rel);
+#else
+ return("");
+#endif /* CK_UTSNAME */
+ }
+ } /* Break up long switch statements... */
+
+ switch(y) {
+ case VN_NAME: {
+ extern char * myname;
+ return(myname);
+ }
+
+ case VN_MODL: {
+#ifdef CK_UTSNAME
+ extern char unm_mod[], unm_mch[];
+ int y = VVBUFL - 1;
+ char * s = unm_mod;
+#endif /* CK_UTSNAME */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return("");
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+#ifdef COMMENT /* was HPUX */
+ if (!unm_mod[0] && !nopush)
+ zzstring("\\fcommand(model)",&s,&y);
+/*
+ Another possibility would be:
+ "\\fcommand(ksh -c 'whence model 1>&- && model || uname -m')"
+ But that would depend on having ksh.
+*/
+#else
+#ifdef OSF32 /* Digital UNIX 3.2 and higher... */
+/* Note: Ultrix has /etc/sizer, but it is not publicly executable. */
+/* sizer -c outputs 'cpu:<tab><tab>"DECxxxx"' */
+ if (!unm_mod[0]) {
+ char * p;
+ int flag = 0;
+ zzstring("\\fcommand(/usr/sbin/sizer -c)",&s,&y);
+ debug(F110,"DU model",unm_mod,0);
+ s = unm_mod;
+ p = unm_mod;
+ while (*p) { /* Extract the part in quotes */
+ if (*p == '"') {
+ if (flag)
+ break;
+ flag = 1;
+ p++;
+ continue;
+ }
+ if (flag)
+ *s++ = *p;
+ p++;
+ }
+ *s = NUL;
+ }
+#endif /* OSF32 */
+#endif /* COMMENT */
+
+#ifdef CK_UTSNAME
+ if (unm_mod[0])
+ return((char *)unm_mod);
+ else
+ return((char *)unm_mch);
+#else
+ return("");
+#endif /* CK_UTSNAME */
+ }
+
+#ifdef IBMX25
+ /* X.25 variables (local and remote address) */
+ case VN_X25LA:
+ if (!local_nua[0] && !x25local_nua(local_nua))
+ *vvbuf = NULL;
+ else
+ ckstrncpy(vvbuf,local_nua,VVBUFL+1);
+ return((char *)vvbuf);
+
+ case VN_X25RA:
+ if (!remote_nua[0])
+ *vvbuf = NULL;
+ else
+ ckstrncpy(vvbuf,remote_nua,VVBUFL+1);
+ return((char *)vvbuf);
+#endif /* IBMX25 */
+
+#ifndef NODIAL
+ case VN_PDSFX: {
+ extern char pdsfx[];
+ return((char *)pdsfx);
+ }
+ case VN_DTYPE: {
+ extern int dialtype;
+ sprintf(vvbuf,"%d",dialtype); /* SAFE */
+ return((char *)vvbuf);
+ }
+#endif /* NODIAL */
+
+#ifdef UNIX
+ case VN_LCKPID: {
+ extern char lockpid[];
+ return((char *)lockpid);
+ }
+#endif /* UNIX */
+
+#ifndef NOXFER
+ case VN_BLK:
+ sprintf(vvbuf,"%d",bctr); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_TFTIM:
+ sprintf(vvbuf, /* SAFE */
+#ifdef GFTIMER
+ "%ld", (long)(fptsecs + 0.5)
+#else
+ "%d", tsecs
+#endif /* GFTIMER */
+ );
+ return((char *)vvbuf);
+#endif /* NOXFER */
+
+ case VN_HWPAR:
+ case VN_SERIAL: {
+ int sb;
+ char c, * ss;
+ extern int stopbits;
+ vvbuf[0] = NUL;
+ if (hwparity && local && !network)
+ ss = parnam((char)hwparity);
+ else
+ ss = parnam((char)parity);
+ if (cx == VN_HWPAR) {
+ ckstrncpy(vvbuf,ss,VVBUFL);
+ return((char *)vvbuf);
+ }
+ c = ss[0];
+ if (islower(c)) c = toupper(c);
+ sb = stopbits;
+ if (sb < 1)
+ sb = (speed > 0 && speed <= 110L) ? 2 : 1;
+ if (hwparity)
+ sprintf(vvbuf," 8%c%d",c,sb); /* SAFE */
+ else if (parity)
+ sprintf(vvbuf," 7%c%d",c,sb); /* SAFE */
+ else
+ sprintf(vvbuf," 8N%d",sb); /* SAFE */
+ return((char *)vvbuf);
+ }
+
+#ifdef UNIX
+ case VN_LCKDIR: {
+#ifndef NOUUCP
+ extern char * uucplockdir;
+ ckstrncpy(vvbuf,uucplockdir,VVBUFL);
+ x = strlen(vvbuf);
+ if (x > 0) {
+ if (vvbuf[x-1] != '/') {
+ vvbuf[x] = '/';
+ vvbuf[x+1] = NUL;
+ }
+ }
+#else
+ vvbuf[0] = NUL;
+#endif /* NOUUCP */
+ return((char *)vvbuf);
+ }
+#endif /* UNIX */
+ } /* Break up long switch statements... */
+
+ switch(y) {
+#ifndef NODIAL
+ case VN_DM_LP:
+ case VN_DM_SP:
+ case VN_DM_PD:
+ case VN_DM_TD:
+ case VN_DM_WA:
+ case VN_DM_WD:
+ case VN_DM_HF:
+ case VN_DM_WB:
+ case VN_DM_RC: {
+ extern char * getdm();
+ ckstrncpy(vvbuf,getdm(y),VVBUFL);
+ return((char *)vvbuf);
+ }
+#endif /* NODIAL */
+
+ case VN_TY_LN:
+ case VN_TY_LC: {
+ extern int typ_lines;
+ sprintf(vvbuf,"%d",typ_lines); /* SAFE */
+ return((char *)vvbuf);
+ }
+ case VN_TY_LM: {
+ extern int typ_mtchs;
+ sprintf(vvbuf,"%d",typ_mtchs); /* SAFE */
+ return((char *)vvbuf);
+ }
+ case VN_MACLVL:
+ sprintf(vvbuf,"%d",maclvl); /* SAFE */
+ return((char *)vvbuf);
+ } /* Break up long switch statements... */
+
+ switch(y) {
+#ifndef NOLASTFILE
+ case VN_LASTFIL: {
+ extern char * lastfile;
+ return(lastfile ? lastfile : "");
+ }
+#endif /* NOLASTFILE */
+#ifndef NOXFER
+ case VN_XF_BC:
+ sprintf(vvbuf,"%d",crunched); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_XF_TM:
+ sprintf(vvbuf,"%d",timeouts); /* SAFE */
+ return((char *)vvbuf);
+
+ case VN_XF_RX:
+ sprintf(vvbuf,"%d",retrans); /* SAFE */
+ return((char *)vvbuf);
+#endif /* NOXFER */
+
+ case VN_MS_CD: /* Modem signals */
+ case VN_MS_CTS:
+ case VN_MS_DSR:
+ case VN_MS_DTR:
+ case VN_MS_RI:
+ case VN_MS_RTS: {
+ int x, z = -1;
+ x = ttgmdm(); /* Try to get them */
+ if (x > -1) {
+ switch (y) {
+ case VN_MS_CD: z = (x & BM_DCD) ? 1 : 0; break;
+ case VN_MS_DSR: z = (x & BM_DSR) ? 1 : 0; break;
+ case VN_MS_CTS: z = (x & BM_CTS) ? 1 : 0; break;
+#ifdef MAC
+ case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
+#else
+#ifndef STRATUS
+ case VN_MS_RI: z = (x & BM_RNG) ? 1 : 0; break;
+#ifndef NT
+ case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
+ case VN_MS_RTS: z = (x & BM_RTS) ? 1 : 0; break;
+#endif /* NT */
+#endif /* STRATUS */
+#endif /* MAC */
+ }
+ }
+ sprintf(vvbuf,"%d",z); /* SAFE */
+ return((char *)vvbuf);
+ }
+ case VN_MATCH: /* INPUT MATCH */
+ return(inpmatch ? inpmatch : "");
+
+#ifdef CKFLOAT
+ case VN_ISCALE: /* INPUT SCALE-FACTOR */
+ return(inpscale ? inpscale : "1.0");
+#endif /* CKFLOAT */
+
+ case VN_SLMSG: { /* SET LINE / HOST message */
+ extern char * slmsg;
+ vvbuf[0] = NUL;
+ if (slmsg)
+ ckstrncpy(vvbuf,slmsg,VVBUFL);
+ return(vvbuf);
+ }
+
+ case VN_TXTDIR: /* TEXTDIR */
+ return(k_info_dir ? k_info_dir : "");
+
+#ifdef FNFLOAT
+ case VN_MA_PI:
+ return(math_pi);
+
+ case VN_MA_E:
+ return(math_e);
+
+ case VN_MA_PR:
+ sprintf(vvbuf,"%d",fp_digits); /* SAFE */
+ return(vvbuf);
+#endif /* FNFLOAT */
+
+ case VN_CMDBL:
+ sprintf(vvbuf,"%d",CMDBL); /* SAFE */
+ return(vvbuf);
+
+#ifdef CKCHANNELIO
+ case VN_FERR: {
+ extern int z_error;
+ sprintf(vvbuf,"%d",z_error); /* SAFE */
+ return(vvbuf);
+ }
+ case VN_FMAX: {
+ extern int z_maxchan;
+ sprintf(vvbuf,"%d",z_maxchan); /* SAFE */
+ return(vvbuf);
+ }
+ case VN_FCOU: {
+ extern int z_filcount;
+ sprintf(vvbuf,"%d",z_filcount); /* SAFE */
+ return(vvbuf);
+ }
+#endif /* CKCHANNELIO */
+
+#ifndef NODIAL
+ case VN_DRTR: {
+ extern int dialcount;
+ sprintf(vvbuf,"%d",dialcount); /* SAFE */
+ return(vvbuf);
+ }
+#endif /* NODIAL */
+
+#ifndef NOLOGDIAL
+#ifndef NOLOCAL
+ case VN_CXTIME:
+ sprintf(vvbuf,"%ld",dologshow(0)); /* SAFE */
+ return(vvbuf);
+#endif /* NOLOCAL */
+#endif /* NOLOGDIAL */
+
+ case VN_BYTE:
+ sprintf(vvbuf,"%d",byteorder); /* SAFE */
+ return(vvbuf);
+
+ case VN_KBCHAR:
+ vvbuf[0] = NUL;
+ vvbuf[1] = NUL;
+ if (kbchar > 0)
+ vvbuf[0] = (kbchar & 0xff);
+ return(vvbuf);
+
+ case VN_TTYNAM: {
+#ifdef HAVECTTNAM
+ extern char cttnam[];
+ return((char *)cttnam);
+#else
+ return(CTTNAM);
+#endif /* HAVECTTNAM */
+ }
+
+ case VN_PROMPT:
+ return(cmgetp());
+
+ case VN_BUILD: {
+ extern char * buildid;
+ return(buildid);
+ }
+
+#ifndef NOSEXP
+ case VN_SEXP: {
+ extern char * lastsexp;
+ return(lastsexp ? lastsexp : "");
+ }
+ case VN_VSEXP: {
+ extern char * sexpval;
+ return(sexpval ? sexpval : "");
+ }
+ case VN_LSEXP: {
+ extern int sexpdep;
+ ckstrncpy(vvbuf,ckitoa(sexpdep),VVBUFL);
+ return(vvbuf);
+ }
+#endif /* NOSEXP */
+
+#ifdef GFTIMER
+ case VN_FTIME: {
+ CKFLOAT f;
+ ztime(&p);
+ if (p == NULL || *p == NUL)
+ return(NULL);
+ z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ f = (CKFLOAT)z + ((CKFLOAT)ztusec) / 1000000.0;
+ sprintf(vvbuf,"%f",f); /* SAFE */
+ return(vvbuf);
+ }
+#endif /* GFTIMER */
+
+#ifndef NOHTTP
+ case VN_HTTP_C: { /* HTTP Code */
+ extern int http_code;
+ return(ckitoa(http_code));
+ }
+ case VN_HTTP_N: /* HTTP Connected */
+ return( http_isconnected() ? "1" : "0");
+ case VN_HTTP_H: /* HTTP Host */
+ return( (char *)http_host() );
+ case VN_HTTP_M: { /* HTTP Message */
+ extern char http_reply_str[];
+ return((char *)http_reply_str);
+ }
+ case VN_HTTP_S: /* HTTP Security */
+ return((char *)http_security());
+#endif /* NOHTTP */
+
+#ifdef NEWFTP
+ case VN_FTP_B:
+ return((char *)ftp_cpl_mode());
+ case VN_FTP_D:
+ return((char *)ftp_dpl_mode());
+ case VN_FTP_Z:
+ return((char *)ftp_authtype());
+ case VN_FTP_C: {
+ extern int ftpcode;
+ return(ckitoa(ftpcode));
+ }
+ case VN_FTP_M: {
+ extern char ftp_reply_str[];
+ if (isdigit(ftp_reply_str[0]) &&
+ isdigit(ftp_reply_str[1]) &&
+ isdigit(ftp_reply_str[2]) &&
+ ftp_reply_str[3] == ' ')
+ return(&ftp_reply_str[4]);
+ else
+ return(ftp_reply_str);
+ }
+ case VN_FTP_S: {
+ extern char ftp_srvtyp[];
+ return((char *)ftp_srvtyp);
+ }
+ case VN_FTP_H: {
+ extern char * ftp_host;
+ return(ftp_host ? ftp_host : "");
+ }
+ case VN_FTP_X: { /* FTP Connected */
+ return(ftpisconnected() ? "1" : "0");
+ }
+ case VN_FTP_L: { /* FTP Logged in */
+ return(ftpisloggedin() ? "1" : "0");
+ }
+ case VN_FTP_G: { /* FTP GET-PUT-REMOTE */
+ extern int ftpget;
+ char * s = "";
+ switch (ftpget) {
+ case 0: s = "kermit"; break;
+ case 1: s = "ftp"; break;
+ case 2: s = "auto"; break;
+ }
+ return(s);
+ }
+#endif /* NEWFTP */
+
+#ifndef NOLOCAL
+ case VN_CX_STA: { /* CONNECT status */
+ extern int cx_status;
+ return(ckitoa(cx_status));
+ }
+#endif /* NOLOCAL */
+ case VN_NOW: /* Timestamp */
+ return(ckcvtdate(p,0));
+
+ case VN_HOUR: /* Hour of the day */
+ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
+ if (!p) p = "";
+ if (!*p) return(p);
+ vvbuf[0] = p[11];
+ vvbuf[1] = p[12];
+ vvbuf[2] = NUL;
+ return(vvbuf); /* and return it */
+
+ case VN_BITS: /* Bits (16, 32, 64) */
+ if (sizeof(long) > 4)
+ return(ckitoa(8*sizeof(long)));
+ else
+ return(ckitoa(8*sizeof(int)));
+
+ case VN_LASTKWV: /* 212 */
+ return(lastkwval ? lastkwval : "");
+
+ case VN_HOSTIP: { /* 212 */
+#ifdef TCPSOCKET
+ extern char hostipaddr[];
+ return((char *)hostipaddr);
+#else
+ return("");
+#endif /* TCPSOCKET */
+ }
+ case VN_INPMSG:
+ switch (instatus) {
+ case INP_OK: return("SUCCESS");
+ case INP_TO: return("Timed out");
+ case INP_UI: return("Keyboard interrupt");
+ case INP_IE: return("Internal error");
+ case INP_IO: return("I/O error or connection lost");
+ case INP_IKS: return("INPUT disabled");
+ case INP_BF: return("Buffer filled and /NOWRAP set");
+ default: return("Unknown");
+ }
+
+ case VN_VAREVAL: /* 212 */
+ return(vareval ? "recursive" : "simple");
+
+ case VN_LOG_CON: /* \v(...) for log files */
+#ifdef CKLOGDIAL
+ return(diafil);
+#else
+ return("");
+#endif
+ case VN_LOG_PKT:
+#ifndef NOXFER
+ return(pktfil);
+#else
+ return("");
+#endif
+ case VN_LOG_SES:
+#ifndef NOLOCAL
+ return(sesfil);
+#else
+ return("");
+#endif
+ case VN_LOG_TRA:
+#ifdef TLOG
+ return(trafil);
+#else
+ return("");
+#endif
+ case VN_LOG_DEB:
+#ifdef DEBUG
+ return(debfil);
+#else
+ return("");
+#endif
+ case VN_PREVCMD: {
+ extern char * prevcmd;
+ return(prevcmd ? prevcmd : "");
+ }
+ }
+
+#ifndef NODIAL
+ switch (y) { /* Caller ID values */
+ extern char
+ * callid_date, * callid_time, * callid_name,
+ * callid_nmbr, * callid_mesg;
+
+ case VN_CI_DA:
+ return(callid_date ? callid_date : "");
+
+ case VN_CI_TI:
+ return(callid_time ? callid_time : "");
+
+ case VN_CI_NA:
+ return(callid_name ? callid_name : "");
+
+ case VN_CI_NU:
+ return(callid_nmbr ? callid_nmbr : "");
+
+ case VN_CI_ME:
+ return(callid_mesg ? callid_mesg : "");
+
+ } /* End of variable-name switches */
+#endif /* NODIAL */
+
+#ifdef NT
+ switch (y) {
+ case VN_PERSONAL:
+ p = (char *)GetPersonal();
+ if (p) {
+ GetShortPathName(p,vvbuf,VVBUFL);
+ return(vvbuf);
+ }
+ return("");
+ case VN_DESKTOP:
+ p = (char *)GetDesktop();
+ if (p) {
+ GetShortPathName(p,vvbuf,VVBUFL);
+ return(vvbuf);
+ }
+ return("");
+ case VN_COMMON:
+ p = (char *)GetAppData(1);
+ if (p) {
+ ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
+ GetShortPathName(vvbuf,vvbuf,VVBUFL);
+ return(vvbuf);
+ }
+ return("");
+ case VN_APPDATA:
+ p = (char *)GetAppData(0);
+ if (p) {
+ ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
+ GetShortPathName(vvbuf,vvbuf,VVBUFL);
+ return(vvbuf);
+ }
+ return("");
+ }
+#endif /* NT */
+
+#ifdef TN_COMPORT
+ switch (y) {
+ case VN_TNC_SIG: {
+ p = (char *) tnc_get_signature();
+ ckstrncpy(vvbuf,p ? p : "",VVBUFL);
+ return(vvbuf);
+ }
+ }
+#endif /* TN_COMPORT */
+
+#ifdef KUI
+ switch (y) {
+ case VN_GUI_RUN: {
+ extern HWND getHwndKUI();
+ if ( IsIconic(getHwndKUI()) )
+ return("minimized");
+ if ( IsZoomed(getHwndKUI()) )
+ return("maximized");
+ return("restored");
+ }
+ case VN_GUI_XP:
+ sprintf(vvbuf,"%d",get_gui_window_pos_x()); /* SAFE */
+ return(vvbuf);
+ case VN_GUI_YP:
+ sprintf(vvbuf,"%d",get_gui_window_pos_y()); /* SAFE */
+ return(vvbuf);
+ case VN_GUI_XR:
+ sprintf(vvbuf,"%d",GetSystemMetrics(SM_CXSCREEN)); /* SAFE */
+ return(vvbuf);
+ case VN_GUI_YR:
+ sprintf(vvbuf,"%d",GetSystemMetrics(SM_CYSCREEN)); /* SAFE */
+ return(vvbuf);
+ case VN_GUI_FNM:
+ if ( ntermfont > 0 ) {
+ int i;
+ for (i = 0; i < ntermfont; i++) {
+ if (tt_font == term_font[i].kwval) {
+ ckstrncpy(vvbuf,term_font[i].kwd,VVBUFL);
+ return(vvbuf);
+ }
+ }
+ }
+ return("(unknown)");
+ case VN_GUI_FSZ:
+ ckstrncpy(vvbuf,ckitoa(tt_font_size/2),VVBUFL);
+ if ( tt_font_size % 2 )
+ ckstrncat(vvbuf,".5",VVBUFL);
+ return(vvbuf);
+ }
+#endif /* KUI */
+
+ fnsuccess = 0;
+ if (fnerror) {
+ fnsuccess = 0;
+ }
+ if (fndiags) {
+ if (!embuf[0])
+ ckstrncpy(embuf,"<ERROR:NO_SUCH_VARIABLE>",EMBUFLEN);
+ printf("?%s\n",embuf);
+ return((char *)embuf);
+ } else
+ return("");
+}
+#endif /* NOSPL */
+
+
+/*
+ X X S T R I N G -- Expand variables and backslash codes.
+
+ int xxtstring(s,&s2,&n);
+
+ Expands \ escapes via recursive descent.
+ Argument s is a pointer to string to expand (source).
+ Argument s2 is the address of where to put result (destination).
+ Argument n is the length of the destination string (to prevent overruns).
+ Returns -1 on failure, 0 on success,
+ with destination string null-terminated and s2 pointing to the
+ terminating null, so that subsequent characters can be added.
+ Failure reasons include destination buffer is filled up.
+*/
+
+#define XXDEPLIM 100 /* Recursion depth limit */
+/*
+ In Windows the stack is limited to 256K so big character arrays like
+ vnambuf can't be on the stack in recursive functions like zzstring().
+ But that's no reason use malloc() in Unix or VMS, which don't have
+ this kind of restriction.
+*/
+#ifdef DVNAMBUF /* Dynamic vnambuf[] */
+#undef DVNAMBUF /* Clean slate */
+#endif /* DVNAMBUF */
+
+#ifndef NOSPL /* Only if SPL included */
+#ifdef OS2 /* Only for K95 */
+#define DVNAMBUF
+#endif /* OS2 */
+#endif /* NOSPL */
+
+int
+zzstring(s,s2,n) char *s; char **s2; int *n; {
+ int x, /* Current character */
+ y, /* Worker */
+ pp, /* Paren level */
+ kp, /* Brace level */
+ argn, /* Function argument counter */
+ n2, /* Local copy of n */
+ d, /* Array dimension */
+ vbi, /* Variable id (integer form) */
+ argl, /* String argument length */
+ nx, /* Save original length */
+ quoting = 0; /* 299 */
+
+ char vb, /* Variable id (char form) */
+ *vp, /* Pointer to variable definition */
+ *new, /* Local pointer to target string */
+#ifdef COMMENT
+ *old, /* Save original target pointer */
+#endif /* COMMENT */
+ *p, /* Worker */
+ *q, /* Worker */
+ *s3; /* Worker */
+ int x3; /* Worker */
+ char *r = (char *)0; /* For holding function args */
+ char *r2 = (char *)0;
+ char *r3p;
+
+#ifndef NOSPL
+#ifdef DVNAMBUF
+ char * vnambuf = NULL; /* Buffer for variable/function name */
+#else /* DVNAMBUF */
+ char vnambuf[VNAML]; /* Buffer for variable/function name */
+#endif /* DVNAMBUF */
+ char *argp[FNARGS]; /* Pointers to function args */
+#endif /* NOSPL */
+
+ static int depth = 0; /* Call depth, avoid overflow */
+
+ n2 = *n; /* Make local copies of args */
+ nx = n2;
+
+#ifdef COMMENT
+ /* This is always 32K in BIGBUFOK builds */
+ if (depth == 0)
+ debug(F101,"zzstring top-level n","",n2);
+#endif /* COMMENT */
+
+ new = *s2; /* for one less level of indirection */
+#ifdef COMMENT
+ old = new;
+#endif /* COMMENT */
+
+#ifndef NOSPL
+ itsapattern = 0; /* For \fpattern() */
+ isjoin = 0; /* For \fjoin() */
+#endif /* NOSPL */
+ depth++; /* Sink to a new depth */
+ if (depth > XXDEPLIM) { /* Too deep? */
+ printf("?definition is circular or too deep\n");
+ debug(F101,"zzstring fail","",depth);
+ depth = 0;
+ *new = NUL;
+ return(-1);
+ }
+ if (!s || !new) { /* Watch out for null pointers */
+ debug(F101,"zzstring fail 2","",depth);
+ if (new)
+ *new = NUL;
+ depth = 0;
+ return(-1);
+ }
+ s3 = s;
+ argl = 0;
+ while (*s3++) argl++; /* Get length of source string */
+ debug(F010,"zzstring entry",s,0);
+ if (argl == 0) { /* Empty string */
+ debug(F111,"zzstring empty arg",s,argl);
+ depth = 0;
+ *new = NUL;
+ return(0);
+ }
+ if (argl < 0) { /* Watch out for garbage */
+ debug(F101,"zzstring fail 3","",depth);
+ *new = NUL;
+ depth = 0;
+ return(-1);
+ }
+#ifdef DVNAMBUF
+ debug(F100,"vnambuf malloc...","",0);
+ vnambuf = malloc(VNAML);
+ if (vnambuf == NULL) {
+ printf("?Out of memory");
+ return(-1);
+ }
+ debug(F100,"vnambuf malloc ok","",0);
+#endif /* DVNAMBUF */
+
+ while ((x = *s)) { /* Loop for all characters */
+ if (x != CMDQ) { /* Is it the command-quote char? */
+ *new++ = *s++; /* No, normal char, just copy */
+ if (--n2 < 0) { /* and count it, careful of overflow */
+ debug(F101,"zzstring overflow 1","",depth);
+ depth = 0;
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ continue;
+ }
+
+/* We have the command-quote character. */
+
+ x = *(s+1); /* Get the following character. */
+ if (isupper(x)) x = tolower(x);
+ switch (x) { /* Act according to variable type */
+#ifndef NOSPL
+ case 0: /* It's a lone backslash */
+ *new++ = *s++;
+ if (--n2 < 0) {
+ debug(F101,"zzstring overflow 2","",0);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ break;
+ case '%': /* Variable */
+ s += 2; /* Get the letter or digit */
+ vb = *s++; /* and move source pointer past it */
+ vp = NULL; /* Assume definition is empty */
+ if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
+ if (maclvl < 0) /* Digit variables are global */
+ vp = g_var[vb]; /* if no macro is active */
+ else /* otherwise */
+ vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
+ } else if (vb == '*') { /* Macro args string */
+#ifdef COMMENT
+ /* This doesn't take changes into account */
+ vp = (maclvl >= 0) ? m_line[maclvl] : topline;
+ if (!vp) vp = "";
+#else
+ char * ss = new;
+ if (zzstring("\\fjoin(&_[],,1)",&new,&n2) < 0) {
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ debug(F110,"zzstring \\%*",ss,0);
+ break;
+#endif /* COMMENT */
+ } else {
+ if (isupper(vb)) vb += ('a'-'A');
+ vp = g_var[vb]; /* Letter for global variable */
+ }
+ if (!vp) vp = "";
+#ifdef COMMENT
+ if (vp) { /* If definition not empty */
+#endif /* COMMENT */
+ if (vareval) {
+ debug(F010,"zzstring %n vp",vp,0);
+ /* call self to evaluate it */
+ if (zzstring(vp,&new,&n2) < 0) {
+ debug(F101,"zzstring fail 6","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1); /* Pass along failure */
+ }
+ } else {
+ while ((*new++ = *vp++)) /* copy it to output string. */
+ if (--n2 < 0) {
+ if (q) free(q);
+ debug(F101,"zzstring overflow 4.5","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ new--; /* Back up over terminating null */
+ n2++; /* to allow for further deposits. */
+ }
+#ifdef COMMENT
+ } else {
+ debug(F110,"zzstring %n vp","(NULL)",0);
+ n2 = nx;
+ new = old;
+ *new = NUL;
+ }
+#endif /* COMMENT */
+ break;
+ case '&': /* An array reference */
+ x = arraynam(s,&vbi,&d); /* Get name and subscript */
+ debug(F111,"zzstring arraynam",s,x);
+ if (x < 0) {
+ debug(F101,"zzstring fail 7","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ pp = 0; /* Bracket counter */
+ while (*s) { /* Advance source pointer... */
+ if (*s == '[') pp++;
+ if (*s == ']' && --pp == 0) break;
+ s++;
+ }
+ if (*s == ']') s++; /* ...past the closing bracket. */
+
+ x = chkarray(vbi,d); /* Array is declared? */
+ debug(F101,"zzstring chkarray","",x);
+ if (x > -1) {
+#ifdef COMMENT
+ char * s1 = NULL;
+#endif /* COMMENT */
+ vbi -= ARRAYBASE; /* Convert name to index */
+
+ if (a_dim[vbi] >= d) { /* If subscript in range */
+ char **ap;
+ ap = a_ptr[vbi]; /* get data pointer */
+ if (ap) { /* and if there is one */
+ if (ap[d]) { /* If definition not empty */
+ debug(F111,"zzstring ap[d]",ap[d],d);
+ if (vareval) {
+ if (zzstring(ap[d],&new,&n2) < 0) {
+ debug(F101,"zzstring fail 8","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1); /* Pass along failure */
+ }
+ } else {
+ vp = ap[d];
+ while ((*new++ = *vp++)) /* copy to result */
+ if (--n2 < 0) {
+ if (q) free(q);
+ debug(F101,
+ "zzstring overflow 8.5","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ new--; /* Back up over terminating null */
+ n2++; /* to allow for further deposits. */
+ }
+ }
+
+ } else {
+ /* old = new; */
+ n2 = nx;
+ }
+ }
+ }
+ break;
+
+ case 'f': /* A builtin function */
+ q = vnambuf; /* Copy the name */
+ y = 0; /* into a separate buffer */
+ s += 2; /* point past 'F' */
+ while (y++ < VNAML) {
+ if (*s == '(') { s++; break; } /* Look for open paren */
+ if ((*q = *s) == NUL) break; /* or end of string */
+ s++; q++;
+ }
+ *q = NUL; /* Terminate function name */
+ if (y >= VNAML) { /* Handle pathological case */
+ while (*s && (*s != '(')) /* of very long string entered */
+ s++; /* as function name. */
+ if (*s == ')') s++; /* Skip past it. */
+ }
+ r = r2 = malloc(argl+2); /* And make a place to copy args */
+ /* debug(F101,"zzstring r2","",r2); */
+ if (!r2) { /* Watch out for malloc failure */
+ debug(F101,"zzstring fail 9","",depth);
+ *new = NUL;
+ depth = 0;
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ if (r3) free(r3); /* And another to copy literal arg string */
+ r3 = malloc(argl+2);
+ /* debug(F101,"zzstring r3","",r3); */
+ if (!r3) {
+ debug(F101,"zzstring fail 10","",depth);
+ depth = 0;
+ *new = NUL;
+ if (r2) free(r2);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ } else
+ r3p = r3;
+ argn = 0; /* Argument counter */
+ argp[argn++] = r; /* Point to first argument */
+ y = 0; /* Completion flag */
+ pp = 1; /* Paren level (already have one). */
+ kp = 0;
+ while (1) { /* Copy each argument, char by char. */
+ *r3p++ = *s; /* This is a literal copy for \flit */
+ if (!*s) break;
+
+ if (*s == '{') { /* Left brace */
+ kp++;
+ }
+ if (*s == '}') { /* Right brace */
+ kp--;
+ }
+ if (*s == '(' && kp <= 0) { /* Open paren not in brace */
+ pp++; /* Count it */
+ }
+ *r = *s; /* Now copy resulting byte */
+ if (!*r) /* If NUL, done. */
+ break;
+ if (*r == ')' && kp <= 0) { /* Closing paren, count it. */
+ if (--pp == 0) { /* Final one? */
+ *r = NUL; /* Make it a terminating null */
+ *(r3p - 1) = NUL;
+ s++; /* Point past it in source string */
+ y = 1; /* Flag we've got all the args */
+ break; /* Done with while loop */
+ }
+ }
+ if (*r == ',' && kp <= 0) { /* Comma */
+ if (pp == 1) { /* If not within ()'s, */
+ if (argn >= FNARGS) { /* Too many args */
+ s++; r++; /* Keep collecting flit() string */
+ continue;
+ }
+ *r = NUL; /* New arg, skip past comma */
+ argp[argn++] = r+1; /* In range, point to new arg */
+ } /* Otherwise just skip past */
+ }
+ s++; r++; /* Advance pointers */
+ }
+ if (!y) /* If we didn't find closing paren */
+ argn = -1;
+#ifdef DEBUG
+ if (deblog) {
+ char buf[24];
+ debug(F111,"zzstring function name",vnambuf,y);
+ debug(F010,"zzstring function r3",r3,0);
+ for (y = 0; y < argn; y++) {
+ sprintf(buf,"arg %2d ",y);
+ debug(F010,buf,argp[y],0);
+ }
+ }
+#endif /* DEBUG */
+ {
+ /* In case the function name itself is constructed */
+ char buf[64]; char * p = buf; int n = 64;
+ if (zzstring(vnambuf,&p,&n) > -1)
+ ckstrncpy(vnambuf,buf,64);
+ }
+ vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */
+ if (vp) { /* If definition not empty */
+ while ((*new++ = *vp++)) { /* copy it to output string */
+ if (--n2 < 0) { /* watch out for overflow */
+ debug(F101,"zzstring fail 12","",depth);
+ if (r2) { free(r2); r2 = NULL; }
+ if (r3) { free(r3); r3 = NULL; }
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ }
+ new--; /* Back up over terminating null */
+ n2++; /* to allow for further deposits. */
+ }
+ if (r2) { free(r2); r2 = NULL; }
+ if (r3) { free(r3); r3 = NULL; }
+ break;
+ case 'q': /* 299 String to be take literally */
+ quoting = 1; /* 299 */
+ case '$': /* An environment variable */
+ case 'v': /* Or a named builtin variable. */
+ case 'm': /* Or a macro /long variable */
+ case 's': /* 196 Macro substring */
+ case ':': /* 196 \-variable substring */
+ pp = 0;
+ p = s+2; /* $/V/M must be followed by (name) */
+ if (*p != '(') { /* as in \$(HOME) or \V(count) */
+ *new++ = *s++; /* If not, just copy it */
+ if (--n2 < 0) {
+ debug(F101,"zzstring overflow 3","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ break;
+ }
+ pp++;
+ p++; /* Point to 1st char of name */
+ q = vnambuf; /* Copy the name */
+ y = 0; /* into a separate buffer */
+ debug(F110,">>>> \\q(ARG)",p,0);
+ while (y++ < VNAML) { /* Watch out for name too long */
+ if (*p == '(') { /* Parens can be nested... */
+ if (*(p-1) != CMDQ) /* 299 */
+ pp++;
+ } else if (*p == ')') { /* Name properly terminated with ')' */
+ if (*(p-1) != CMDQ) /* 299 */
+ pp--;
+ if (pp == 0) {
+ p++; /* Move source pointer past ')' */
+ break;
+ }
+ }
+ if ((*q = *p) == NUL) /* String ends before ')' */
+ break;
+ p++; q++; /* Advance pointers */
+ }
+ *q = NUL; /* Terminate the variable name */
+ if (y >= VNAML) { /* Handle pathological case */
+ while (*p && (*p != ')')) /* of very long string entered */
+ p++; /* as variable name. */
+ if (*p == ')') p++; /* Skip ahead to the end of it. */
+ }
+ s = p; /* Adjust global source pointer */
+ s3 = vnambuf;
+ x3 = 0;
+ while (*s3++) x3++;
+ p = malloc(x3 + 1); /* Make temporary space */
+ if (p && !quoting) { /* If we got the space */
+ vp = vnambuf; /* Point to original */
+ strcpy(p,vp); /* (safe) Make a copy of it */
+ y = VNAML; /* Length of name buffer */
+ zzstring(p,&vp,&y); /* Evaluate the copy */
+ free(p); /* Free the temporary space */
+ p = NULL;
+ }
+ debug(F110,"zzstring vname",vnambuf,0);
+ q = NULL;
+ if (x == 'q') { /* 299 Quoting this string */
+ vp = vnambuf; /* 299 */
+ debug(F110,">>> VP",vp,0);
+ } else if (x == '$') { /* Look up its value */
+ vp = getenv(vnambuf); /* This way for environment variable */
+ } else if (x == 'm' || x == 's' || x == ':') { /* Macro / substr */
+ int k, x1 = -1, x2 = -1;
+ char c = NUL;
+ k = strlen(vnambuf);
+ /* \s(name[n:m]) -- Compact substring notation */
+ if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */
+ int bprc;
+ if (vnambuf[k-1] == ']') {
+ int i;
+ for (i = 0; i < k-1; i++) {
+ if (vnambuf[i] == '[') {
+ bprc = boundspair(vnambuf,":_.",&x1,&x2,&c);
+ debug(F111,"zzstring boundspair",vnambuf,bprc);
+ debug(F000,"zzstring boundspair c","",c);
+ if (bprc > -1) {
+ vnambuf[i] = NUL;
+ if (x1 < 1)
+ x1 = 1;
+ x1--; /* Adjust to 0-base */
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (x == ':') { /* Variable type (s or :) */
+ vp = vnambuf;
+ } else {
+ y = isaarray(vnambuf) ?
+ mxxlook(mactab,vnambuf,nmac) :
+ mxlook(mactab,vnambuf,nmac);
+ if (y > -1) { /* Got definition */
+ vp = mactab[y].mval;
+ } else {
+ vp = NULL;
+ }
+ }
+ debug(F111,"zzstring vp",vp,(vp==NULL)?0:strlen(vp));
+
+ if (vp) {
+ if ((x == 's' || x == ':') && (k > 1)) {
+ /* Compact substring notation */
+ if (x2 == 0) { /* Length */
+ vp = NULL;
+ } else if (x1 > -1) { /* Start */
+ k = strlen(vp);
+ debug(F101,">>> k","",k);
+ /* If it's off the end, result is empty */
+ if (x1 > k) {
+ vp = NULL;
+ } else if (k > 0) {
+ /* Stay in bounds */
+ if (c == '_' && x2 > k) /* startpos_endpos */
+ x2 = k;
+ if (c == ':' && x1 + x2 > k) /* start:length */
+ x2 = -1;
+ debug(F101,">>> x2","",x2);
+ debug(F000,">>> c","",c);
+ if ((q = malloc(k+1))) {
+ strcpy(q,vp); /* safe */
+ if (c == '.') {
+ q[x1+1] = NUL;
+ debug(F000,"XXX. q",q,c);
+ }
+ if (c == ':') { /* start:length */
+ if ((x2 > -1) && ((x1 + x2) <= k)) {
+ q[x1+x2] = NUL;
+ }
+ debug(F000,"XXX: q",q,c);
+ } else if (c == '_') { /* start_endpos */
+ if (x1 >= x2) {
+ q[x1 = 0] = NUL;
+ } else if (x2 < k && x2 > -1) {
+ q[x2] = NUL;
+ }
+ debug(F000,"XXX_ q",q,c);
+ }
+ vp = q+x1;
+ } else vp = NULL;
+ } else vp = NULL;
+ }
+
+ debug(F110,"XXX vnambuf",vnambuf,0);
+ debug(F000,"XXX c","",c);
+ debug(F101,"XXX x1","",x1);
+ debug(F101,"XXX x2","",x2);
+ debug(F110,"XXX result",vp,0);
+#ifdef DEBUG
+ if (deblog) {
+ if (!vp) {
+ } else {
+ k = strlen(vp);
+ }
+ }
+#endif /* DEBUG */
+ }
+ }
+ } else { /* or */
+ vp = nvlook(vnambuf); /* this way for builtin variable */
+ }
+ if (vp) { /* If definition not empty */
+ while ((*new++ = *vp++)) /* copy it to output string. */
+ if (--n2 < 0) {
+ if (q) free(q);
+ debug(F101,"zzstring overflow 4","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ new--; /* Back up over terminating null */
+ n2++; /* to allow for further deposits. */
+ }
+ if (q) {
+ free(q);
+ q = NULL;
+ }
+ break;
+#endif /* NOSPL */ /* Handle \nnn even if NOSPL. */
+
+#ifndef NOKVERBS
+ case 'K':
+ case 'k': {
+ extern struct keytab kverbs[];
+ extern int nkverbs;
+#define K_BUFLEN 30
+ char kbuf[K_BUFLEN + 1]; /* Key verb name buffer */
+ int x, y, z, brace = 0;
+ s += 2;
+/*
+ We assume that the verb name is {braced}, or it extends to the end of the
+ string, s, or it ends with a space, control character, or backslash.
+*/
+ p = kbuf; /* Copy verb name into local buffer */
+ x = 0;
+ if (*s == '{') {
+ s++;
+ brace++;
+ }
+ while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
+ if (brace && *s == '}') {
+ s++;
+ break;
+ }
+ *p++ = *s++;
+ }
+ brace = 0;
+ *p = NUL; /* Terminate. */
+ p = kbuf; /* Point back to beginning */
+ debug(F110,"zzstring kverb",p,0);
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ debug(F101,"zzstring lookup",0,y);
+ if (y > -1) {
+ dokverb(VCMD,y);
+#ifndef NOSPL
+ } else { /* Is it a macro? */
+ y = mxlook(mactab,p,nmac);
+ if (y > -1) {
+ debug(F111,"zzstring mxlook",p,y);
+ if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
+ if (cmpush() > -1) { /* Push command parser state */
+ extern int ifc;
+ int ifcsav = ifc; /* Push IF condition on stack */
+ y = parser(1); /* New parser to execute macro */
+ cmpop(); /* Pop command parser */
+ ifc = ifcsav; /* Restore IF condition */
+ if (y == 0) { /* No errors, ignore actions */
+ p = mrval[maclvl+1]; /* If OK set return val */
+ if (p == NULL) p = "";
+ }
+ } else { /* Can't push any more */
+ debug(F101,"zzstring pushed too deep","",depth);
+ printf(
+ "\n?Internal error: zzstring stack overflow\n"
+ );
+ while (cmpop() > -1);
+ p = "";
+ }
+ }
+ }
+#endif /* NOSPL */
+ }
+ break;
+ }
+#endif /* NOKVERBS */
+
+ default: /* Maybe it's a backslash code */
+ y = xxesc(&s); /* Go interpret it */
+ if (y < 0) { /* Upon failure */
+ *new++ = (char) x; /* Just quote the next character */
+ s += 2; /* Move past the pair */
+ n2 -= 2;
+ if (n2 < 0) {
+ debug(F101,"zzstring overflow 5","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ continue; /* and go back for more */
+ } else {
+ *new++ = (char) y; /* else deposit interpreted value */
+ if (--n2 < 0) {
+ debug(F101,"zzstring overflow 6","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(-1);
+ }
+ }
+ }
+ }
+ *new = NUL; /* Terminate the new string */
+ debug(F010,"zzstring while exit",*s2,0);
+
+ depth--; /* Adjust stack depth gauge */
+ *s2 = new; /* Copy results back into */
+ *n = n2; /* the argument addresses */
+ debug(F101,"zzstring ok","",depth);
+#ifdef DVNAMBUF
+ if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+ return(0); /* and return. */
+}
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuus5.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus5.c
new file mode 100644
index 0000000..c4c8782
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus5.c
@@ -0,0 +1,12427 @@
+#include "ckcsym.h"
+
+int xcmdsrc = 0;
+
+#ifdef NOICP
+int cmdsrc() { return(0); }
+#endif /* NOICP */
+
+/* C K U U S 5 -- "User Interface" for C-Kermit, part 5 */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/* Includes */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+
+#ifdef DCMDBUF
+char *line; /* Character buffer for anything */
+char *tmpbuf;
+#else
+char line[LINBUFSIZ+1];
+char tmpbuf[TMPBUFSIZ+1]; /* Temporary buffer */
+#endif /* DCMDBUF */
+
+#ifndef NOICP
+
+#include "ckcnet.h"
+#ifndef NOCSETS
+#include "ckcxla.h"
+#endif /* NOCSETS */
+#ifdef MAC
+#include "ckmasm.h"
+#endif /* MAC */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+extern char * ck_cryear; /* (ckcmai.c) Latest C-Kermit copyright year */
+
+#ifdef OS2
+#include "ckoetc.h"
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else /* NT */
+#include <windows.h>
+#define TAPI_CURRENT_VERSION 0x00010004
+#include <tapi.h>
+#include <mcx.h>
+#include "ckntap.h"
+#define APIRET ULONG
+extern int DialerHandle;
+extern int StartedFromDialer;
+#endif /* NT */
+#include "ckocon.h"
+#include "ckokey.h"
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+extern int cursor_save ;
+extern bool cursorena[] ;
+#endif /* OS2 */
+
+/* 2010-03-09 SMS. VAX C V3.1-051 needs <stat.h> for off_t. */
+#ifdef VMS
+#include <stat.h>
+#endif /* def VMS */
+
+/* For formatted screens, "more?" prompting, etc. */
+
+#ifdef FT18
+#define isxdigit(c) isdigit(c)
+#endif /* FT18 */
+
+#ifdef STRATUS /* Stratus Computer, Inc. VOS */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef getchar
+#undef getchar
+#endif /* getchar */
+#define getchar(x) coninc(0)
+#endif /* STRATUS */
+
+/* External variables */
+
+extern int carrier, cdtimo, local, quiet, backgrd, bgset, sosi, xsuspend,
+ binary, escape, xargs, flow, cmdmsk, duplex, ckxech, seslog, what,
+ inserver, diractive, tlevel, cwdf, nfuncs, msgflg, remappd, hints, mdmtyp,
+ zincnt, cmask, rcflag, success, xitsta, pflag, tnlm, tn_nlm, xitwarn,
+ debses, xaskmore, parity, saveask, wasclosed, whyclosed, cdactive,
+ rcdactive, keepallchars, cmd_err;
+
+#ifdef LOCUS
+extern int locus, autolocus;
+#endif /* LOCUS */
+
+#ifndef NOMSEND
+extern int addlist;
+#endif /* NOMSEND */
+
+#ifdef CK_SPEED
+extern int prefixing;
+#endif /* CK_SPEED */
+
+extern int g_matchdot;
+
+#ifdef RECURSIVE
+extern int recursive;
+#endif /* RECURSIVE */
+extern int xfiletype;
+
+#ifdef IKSDCONF
+extern char * iksdconf;
+extern int iksdcf;
+#endif /* IKSDCONF */
+
+#ifdef CK_RECALL
+extern int on_recall;
+#endif /* CK_RECALL */
+
+extern int ngetpath, exitonclose;
+extern char * getpath[];
+extern CHAR * epktmsg;
+
+extern char * snd_move;
+extern char * snd_rename;
+extern char * rcv_move;
+extern char * rcv_rename;
+extern char * g_snd_move;
+extern char * g_snd_rename;
+extern char * g_rcv_move;
+extern char * g_rcv_rename;
+
+extern char * nm[];
+
+#ifdef CK_UTSNAME
+extern char unm_mch[];
+extern char unm_mod[];
+extern char unm_nam[];
+extern char unm_rel[];
+extern char unm_ver[];
+#endif /* CK_UTSNAME */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+extern char editor[];
+extern char editfile[];
+extern char editopts[];
+#ifdef BROWSER
+extern char browser[];
+extern char browsopts[];
+extern char browsurl[];
+#endif /* BROWSER */
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifndef NOFRILLS
+#ifndef NORENAME
+_PROTOTYP(VOID shorename, (void));
+#endif /* NORENAME */
+#endif /* NOFRILLS */
+
+#ifndef NOSERVER
+extern char * x_user, * x_passwd, * x_acct;
+#endif /* NOSERVER */
+
+#ifdef CKLOGDIAL
+extern int dialog;
+extern char diafil[];
+#endif /* CKLOGDIAL */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+#ifndef NOSPL
+extern int cfilef, xxdot, vareval;
+extern char cmdfil[];
+
+struct localvar * localhead[CMDSTKL];
+struct localvar * localtail = NULL;
+struct localvar * localnext = NULL;
+
+_PROTOTYP( VOID shosexp, (void) );
+_PROTOTYP( static VOID shoinput, (void) );
+_PROTOTYP( static char gettok, (void) );
+_PROTOTYP( static VOID factor, (void) );
+_PROTOTYP( static VOID term, (void) );
+_PROTOTYP( static VOID termp, (void) );
+_PROTOTYP( static VOID exprp, (void) );
+_PROTOTYP( static VOID expr, (void) );
+_PROTOTYP( static VOID simple, (void) );
+_PROTOTYP( static VOID simpler, (void) );
+_PROTOTYP( static VOID simplest, (void) );
+_PROTOTYP( static CK_OFF_T xparse, (void) );
+#endif /* NOSPL */
+#ifndef NOSHOW
+_PROTOTYP( int sho_iks, (void) );
+#endif /* NOSHOW */
+
+#ifdef MAC
+char * ckprompt = "Mac-Kermit>"; /* Default prompt for Macintosh */
+char * ikprompt = "IKSD>";
+#else /* Not MAC */
+#ifdef NOSPL
+#ifdef OS2
+char * ckprompt = "K-95> "; /* Default prompt for Win32 */
+char * ikprompt = "IKSD> ";
+#else
+char * ckprompt = "C-Kermit>";
+char * ikprompt = "IKSD>";
+#endif /* NT */
+#else /* NOSPL */
+#ifdef OS2
+/* Default prompt for OS/2 and Win32 */
+#ifdef NT
+char * ckprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] K-95> ";
+char * ikprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] IKSD> ";
+#else /* NT */
+char * ckprompt = "[\\freplace(\\v(dir),/,\\\\)] K-95> ";
+char * ikprompt = "[\\freplace(\\v(dir),/,\\\\)] IKSD> ";
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+char * ckprompt = "\\v(dir) C-Kermit>"; /* Default prompt VMS */
+char * ikprompt = "\\v(dir) IKSD>";
+#else
+char * ckprompt = "(\\v(dir)) C-Kermit>"; /* Default prompt for others */
+char * ikprompt = "(\\v(dir)) IKSD>";
+#endif /* VMS */
+#endif /* NT */
+#endif /* NOSPL */
+#endif /* MAC */
+
+#ifndef CCHMAXPATH
+#define CCHMAXPATH 257
+#endif /* CCHMAXPATH */
+char inidir[CCHMAXPATH] = { NUL, NUL }; /* Directory INI file executed from */
+
+#ifdef TNCODE
+extern int tn_b_nlm; /* TELNET BINARY newline mode */
+#endif /* TNCODE */
+
+#ifndef NOKVERBS
+extern struct keytab kverbs[]; /* Table of \Kverbs */
+extern int nkverbs; /* Number of \Kverbs */
+#endif /* NOKVERBS */
+
+#ifndef NOPUSH
+extern int nopush;
+#endif /* NOPUSH */
+
+#ifdef CK_RECALL
+extern int cm_recall;
+#endif /* CK_RECALL */
+
+extern char *ccntab[];
+
+/* Printer stuff */
+
+extern char *printername;
+extern int printpipe;
+#ifdef BPRINT
+extern int printbidi, pportparity, pportflow;
+extern long pportspeed;
+#endif /* BPRINT */
+
+#ifdef OS2
+_PROTOTYP (int os2getcp, (void) );
+_PROTOTYP (int os2getcplist, (int *, int) );
+#ifdef OS2MOUSE
+extern int tt_mouse;
+#endif /* OS2MOUSE */
+extern int tt_update, tt_updmode, updmode, tt_utf8;
+#ifndef IKSDONLY
+extern int tt_status[];
+#endif /* IKSDONLY */
+#ifdef PCFONTS
+extern struct keytab term_font[];
+#else
+#ifdef KUI
+extern struct keytab * term_font;
+#endif /* KUI */
+#endif /* PCFONTS */
+extern int ntermfont, tt_font, tt_font_size;
+extern unsigned char colornormal, colorunderline, colorstatus,
+ colorhelp, colorselect, colorborder, colorgraphic, colordebug,
+ colorreverse, colorcmd, coloritalic;
+extern int priority;
+extern struct keytab prtytab[];
+extern int nprty;
+char * cmdmac = NULL;
+#endif /* OS2 */
+
+#ifdef VMS
+_PROTOTYP (int zkermini, (char *, int, char *) );
+#endif /* VMS */
+
+extern long vernum;
+extern int inecho, insilence, inbufsize, nvars, inintr;
+extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav,
+ *cknetv, *clcmds;
+#ifdef OS2
+extern char *ckyv;
+#endif /* OS2 */
+#ifdef CK_AUTHENTICATION
+extern char * ckathv;
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+extern char * cksslv;
+#endif /* CK_SSL */
+#ifdef CK_ENCRYPTION
+#ifndef CRYPT_DLL
+extern char * ckcrpv;
+#endif /* CRYPT_DLL */
+#endif /* CK_ENCRYPTION */
+
+#ifdef SSHBUILTIN
+extern char *cksshv;
+#ifdef SFTP_BUILTIN
+extern char *cksftpv;
+#endif /* SFTP_BUILTIN */
+#endif /* SSHBUILTIN */
+
+#ifdef TNCODE
+extern char *cktelv;
+#endif /* TNCODE */
+#ifndef NOFTP
+#ifndef SYSFTP
+extern char * ckftpv;
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+extern int srvidl;
+
+#ifdef OS2
+extern char *ckonetv;
+extern int interm;
+#ifdef CK_NETBIOS
+extern char *ckonbiv;
+#endif /* CK_NETBIOS */
+#ifdef OS2MOUSE
+extern char *ckomouv;
+#endif /* OS2MOUSE */
+#endif /* OS2 */
+
+#ifndef NOLOCAL
+extern char *connv;
+#endif /* NOLOCAL */
+#ifndef NODIAL
+extern char *dialv;
+#endif /* NODIAL */
+#ifndef NOSCRIPT
+extern char *loginv;
+extern int secho;
+#endif /* NOSCRIPT */
+
+#ifndef NODIAL
+extern int nmdm, dirline;
+extern struct keytab mdmtab[];
+#endif /* NODIAL */
+
+extern int network, nettype, ttnproto;
+
+#ifdef OS2
+#ifndef NOTERM
+/* SET TERMINAL items... */
+extern int tt_type, tt_arrow, tt_keypad, tt_wrap, tt_answer, tt_scrsize[];
+extern int tt_bell, tt_roll[], tt_ctstmo, tt_cursor, tt_pacing, tt_type_mode;
+extern char answerback[];
+extern struct tt_info_rec tt_info[]; /* Indexed by terminal type */
+extern int max_tt;
+#endif /* NOTERM */
+#endif /* OS2 */
+
+_PROTOTYP( VOID shotrm, (void) );
+_PROTOTYP( int shofea, (void) );
+
+#ifdef OS2
+extern int tt_rows[], tt_cols[];
+#else /* OS2 */
+extern int tt_rows, tt_cols;
+#endif /* OS2 */
+extern int cmd_rows, cmd_cols;
+
+#ifdef CK_TMPDIR
+extern int f_tmpdir; /* Directory changed temporarily */
+extern char savdir[]; /* Temporary directory */
+#endif /* CK_TMPDIR */
+
+#ifndef NOLOCAL
+extern int tt_crd, tt_lfd, tt_escape;
+#endif /* NOLOCAL */
+
+#ifndef NOCSETS
+extern int language, nfilc, tcsr, tcsl, tcs_transp, fcharset;
+extern struct keytab fcstab[];
+extern struct csinfo fcsinfo[];
+#ifndef MAC
+extern struct keytab ttcstab[];
+#endif /* MAC */
+#endif /* NOCSETS */
+
+extern long speed;
+
+#ifndef NOXMIT
+extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt;
+extern char xmitbuf[];
+#endif /* NOXMIT */
+
+extern char **xargv, *versio, *ckxsys, *dftty, *lp;
+
+#ifdef DCMDBUF
+extern char *cmdbuf, *atmbuf; /* Command buffers */
+#ifndef NOSPL
+extern char *savbuf; /* Command buffers */
+#endif /* NOSPL */
+#else
+extern char cmdbuf[], atmbuf[]; /* Command buffers */
+#ifndef NOSPL
+extern char savbuf[]; /* Command buffers */
+#endif /* NOSPL */
+#endif /* DCMDBUF */
+
+extern char toktab[], ttname[], psave[];
+extern CHAR sstate, feol;
+extern int cmflgs, techo, repars, ncmd;
+extern struct keytab cmdtab[];
+
+#ifndef NOSETKEY
+KEY *keymap;
+#ifndef OS2
+#define mapkey(x) keymap[x]
+#endif /* OS2 */
+MACRO *macrotab;
+_PROTOTYP( VOID shostrdef, (CHAR *) );
+#endif /* NOSETKEY */
+
+extern int cmdlvl;
+
+#ifndef NOSPL
+extern struct mtab *mactab;
+extern struct keytab mackey[];
+extern struct keytab vartab[], fnctab[], iftab[];
+extern int maclvl, nmac, mecho, fndiags, fnerror, fnsuccess, nif;
+#endif /* NOSPL */
+
+FILE *tfile[MAXTAKE]; /* TAKE file stack */
+char *tfnam[MAXTAKE];
+int tfline[MAXTAKE];
+
+int topcmd = -1; /* cmdtab index of current command */
+int havetoken = 0;
+extern int dblquo; /* Doublequoting enabled */
+
+#ifdef DCMDBUF /* Initialization filespec */
+char *kermrc = NULL;
+#else
+char kermrcb[KERMRCL];
+char *kermrc = kermrcb;
+#endif /* DCMDBUF */
+
+int noherald = 0;
+int cm_retry = 1; /* Command retry enabled */
+xx_strp xxstring = zzstring;
+
+#ifndef NOXFER
+extern int displa, bye_active, protocol, pktlog, remfile, rempipe, unkcs,
+ keep, lf_opts, fncnv, pktpaus, autodl, xfrcan, xfrchr, xfrnum, srvtim,
+ srvdis, query, retrans, streamed, reliable, crunched, timeouts,
+ fnrpath, autopath, rpackets, spackets, epktrcvd, srvping;
+
+#ifdef CK_AUTODL
+extern int inautodl, cmdadl;
+#endif /* CK_AUTODL */
+
+#ifndef NOSERVER
+extern int en_asg, en_cwd, en_cpy, en_del, en_dir, en_fin, en_bye, en_ret,
+ en_get, en_hos, en_que, en_ren, en_sen, en_set, en_spa, en_typ, en_who,
+ en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
+#endif /* NOSERVER */
+
+extern int atcapr,
+ atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
+ attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
+
+#ifdef STRATUS
+extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
+#endif /* STRATUS */
+
+#ifdef CK_PERMS
+extern int atlpri, atlpro, atgpri, atgpro;
+#endif /* CK_PERMS */
+
+#ifdef CK_LOGIN
+extern char * anonfile; /* Anonymous login init file */
+extern char * anonroot; /* Anonymous file-system root */
+extern char * userfile; /* Forbidden user file */
+extern int isguest; /* Flag for anonymous user */
+#endif /* CK_LOGIN */
+#endif /* NOXFER */
+
+#ifdef DCMDBUF
+int *xquiet = NULL;
+int *xvarev = NULL;
+#else
+int xquiet[CMDSTKL];
+int xvarev[CMDSTKL];
+#endif /* DCMDBUF */
+
+char * prstring[CMDSTKL];
+
+#ifndef NOSPL
+
+extern long ck_alarm;
+extern char alrm_date[], alrm_time[];
+
+/* Local declarations */
+
+static int nulcmd = 0; /* Flag for next cmd to be ignored */
+
+/* Definitions for predefined macros */
+
+/* First, the single-line macros, installed with addmac()... */
+
+/* IBM-LINEMODE macro */
+char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none";
+
+/* FATAL macro */
+char *m_fat = "if def \\%1 echo \\%1, if not = \\v(local) 0 hangup, stop 1";
+
+#ifdef CK_SPEED
+#ifdef IRIX65
+char *m_fast = "set win 30, set rec pack 4000, set prefix cautious";
+#else
+#ifdef IRIX
+/* Because of bug in telnet server */
+char *m_fast = "set window 30, set rec pack 4000, set send pack 4000,\
+ set pref cautious";
+#else
+#ifdef pdp11
+char *m_fast = "set win 3, set rec pack 1024, set prefix cautious";
+#else
+#ifdef BIGBUFOK
+char *m_fast = "set win 30, set rec pack 4000, set prefix cautious";
+#else
+char *m_fast = "set win 4, set rec pack 2200, set prefix cautious";
+#endif /* BIGBUFOK */
+#endif /* IRIX */
+#endif /* IRIX65 */
+#endif /* pdp11 */
+#ifdef pdp11
+char *m_cautious = "set win 2, set rec pack 512, set prefixing cautious";
+#else
+char *m_cautious = "set win 4, set rec pack 1000, set prefixing cautious";
+#endif /* pdp11 */
+char *m_robust = "set win 1, set rec pack 90, set prefixing all, \
+set reliable off, set clearchannel off";
+#else
+#ifdef BIGBUFOK
+#ifdef IRIX65
+char *m_fast = "set win 30, set rec pack 4000";
+#else
+#ifdef IRIX
+char *m_fast = "set win 30, set rec pack 4000, set send pack 4000";
+#else
+char *m_fast = "set win 30, set rec pack 4000";
+#endif /* IRIX */
+#endif /* IRIX65 */
+#else /* Not BIGBUFOK */
+char *m_fast = "set win 4, set rec pack 2200";
+#endif /* BIGBUFOK */
+char *m_cautious = "set win 4, set rec pack 1000";
+char *m_robust = "set win 1, set rec pack 90, set reliable off";
+#endif /* CK_SPEED */
+
+#ifdef VMS
+char *m_purge = "run purge \\%*";
+#endif /* VMS */
+
+#ifdef OS2
+char *m_manual = "browse \\v(exedir)docs/manual/kermit95.htm";
+#endif /* OS2 */
+
+/* Now the multiline macros, defined with addmmac()... */
+
+/* FOR macro for \%i-style loop variables (see dofor()...) */
+
+char *for_def[] = { "_assign _for\\v(cmdlevel) { _getargs,",
+"def \\\\\\%1 \\feval(\\%2),:_..top,if \\%5 \\\\\\%1 \\%3 goto _..bot,",
+"\\%6,:_..inc,incr \\\\\\%1 \\%4,goto _..top,:_..bot,_putargs},",
+"def break goto _..bot, def continue goto _..inc,",
+"do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)",
+""};
+
+/* This is the FOR macro when the loop variable is itself a macro */
+
+char *foz_def[] = { "_assign _for\\v(cmdlevel) { _getargs,",
+"def \\%1 \\feval(\\%2),:_..top,if \\%5 \\%1 \\%3 goto _..bot,",
+"\\%6,:_..inc,incr \\%1 \\%4,goto _..top,:_..bot,_putargs},",
+"def break goto _..bot, def continue goto _..inc,",
+"do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)",
+""};
+
+/* WHILE macro */
+char *whil_def[] = { "_assign _whi\\v(cmdlevel) {_getargs,",
+":_..inc,\\%1,\\%2,goto _..inc,:_..bot,_putargs},",
+"_def break goto _..bot, _def continue goto _..inc,",
+"do _whi\\v(cmdlevel),_assign _whi\\v(cmdlevel)",
+""};
+
+/* SWITCH macro */
+char *sw_def[] = { "_assign _sw_\\v(cmdlevel) {_getargs,",
+"_forward {\\%1},\\%2,:default,:_..bot,_putargs},_def break goto _..bot,",
+"do _sw_\\v(cmdlevel),_assign _sw_\\v(cmdlevel)",
+""};
+
+/* XIF macro */
+char *xif_def[] = {
+"_assign _if\\v(cmdlevel) {_getargs,\\%1,_putargs},",
+"do _if\\v(cmdlevel),_assign _if\\v(cmdlevel)",
+""};
+
+/*
+ Variables declared here for use by other ckuus*.c modules.
+ Space is allocated here to save room in ckuusr.c.
+*/
+#ifdef DCMDBUF
+struct cmdptr *cmdstk;
+int
+ *ifcmd = NULL,
+ *count = NULL,
+ *iftest = NULL,
+ *intime = NULL,
+ *inpcas = NULL,
+ *takerr = NULL,
+ *merror = NULL;
+#else
+struct cmdptr cmdstk[CMDSTKL];
+int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL], intime[CMDSTKL],
+ inpcas[CMDSTKL], takerr[CMDSTKL], merror[CMDSTKL];
+#endif /* DCMDBUF */
+
+/* Macro stack */
+
+#ifdef COMMENT
+char *topline = NULL; /* Program invocation arg line */
+char *m_line[MACLEVEL] = { NULL, NULL }; /* Stack of macro invocation lines */
+#endif /* COMMENT */
+
+char **m_xarg[MACLEVEL]; /* Pointers to arg vector arrays */
+int n_xarg[MACLEVEL]; /* Sizes of arg vector arrays */
+char *m_arg[MACLEVEL][NARGS]; /* Args of each level */
+int macargc[MACLEVEL]; /* Argc of each level */
+char *macp[MACLEVEL]; /* Current position in each macro */
+char *macx[MACLEVEL]; /* Beginning of each macro def */
+char *mrval[MACLEVEL]; /* RETURN value at each level */
+int lastcmd[MACLEVEL]; /* Last command at each level */
+int topargc = 0; /* Argc at top level */
+char **topxarg = NULL; /* Argv at top level */
+char *toparg[MAXARGLIST+2];
+
+/* Global Variables */
+
+char *g_var[GVARS+1]; /* Global \%a..z pointers */
+extern char varnam[]; /* \%x variable name buffer */
+
+/* Arrays -- Dimension must be 'z' - ARRAYBASE + 1 */
+/* Note: a_link[x] < 0 means no link; >= 0 is a link */
+
+char **a_ptr[32]; /* Array pointers, for arrays a-z */
+int a_dim[32]; /* Dimensions for each array */
+int a_link[32]; /* Link (index of linked-to-array) */
+
+char **aa_ptr[CMDSTKL][32]; /* Array stack for automatic arrays */
+int aa_dim[CMDSTKL][32]; /* Dimensions for each array */
+
+/* INPUT command buffers and variables */
+
+char * inpbuf = NULL; /* Buffer for INPUT and REINPUT */
+extern char * inpbp; /* Global/static pointer to it */
+char inchar[2] = { NUL, NUL }; /* Last character that was INPUT */
+int incount = 0; /* INPUT character count */
+extern int instatus; /* INPUT status */
+static char * i_text[] = { /* INPUT status text */
+ "success", "timeout", "interrupted", "internal error", "i/o error"
+};
+
+char lblbuf[LBLSIZ]; /* Buffer for labels */
+
+#else /* NOSPL */
+
+int takerr[MAXTAKE];
+#endif /* NOSPL */
+
+static char *prevdir = NULL;
+
+int pacing = 0; /* OUTPUT pacing */
+
+char *tp; /* Temporary buffer pointer */
+
+int timelimit = 0, asktimer = 0; /* Timers for time-limited commands */
+
+#ifdef CK_APC /* Application Program Command (APC) */
+int apcactive = APC_INACTIVE;
+int apcstatus = APC_OFF; /* OFF by default everywhere */
+#ifdef DCMDBUF
+char *apcbuf;
+#else
+char apcbuf[APCBUFLEN];
+#endif /* DCMDBUF */
+#endif /* CK_APC */
+
+extern char pktfil[],
+#ifdef DEBUG
+ debfil[],
+#endif /* DEBUG */
+#ifdef TLOG
+ trafil[],
+#endif /* TLOG */
+ sesfil[];
+
+#ifndef NOFRILLS
+extern int rmailf, rprintf; /* REMOTE MAIL & PRINT items */
+extern char optbuf[];
+#endif /* NOFRILLS */
+
+extern int noinit; /* Flat to skip init file */
+
+#ifndef NOSPL
+static struct keytab kcdtab[] = { /* Symbolic directory names */
+#ifdef NT
+ { "appdata", VN_APPDATA, 0 },
+ { "common", VN_COMMON, 0 },
+ { "desktop", VN_DESKTOP, 0 },
+#endif /* NT */
+ { "download", VN_DLDIR, 0 },
+#ifdef OS2ORUNIX
+ { "exedir", VN_EXEDIR, 0 },
+#endif /* OS2ORUNIX */
+ { "home", VN_HOME, 0 },
+ { "inidir", VN_INI, 0 },
+#ifdef UNIX
+ { "lockdir", VN_LCKDIR, 0 },
+#endif /* UNIX */
+#ifdef NT
+ { "my_documents",VN_PERSONAL, 0 },
+ { "personal", VN_PERSONAL, CM_INV },
+#endif /* NT */
+ { "startup", VN_STAR, 0 },
+ { "textdir", VN_TXTDIR, 0 },
+ { "tmpdir", VN_TEMP, 0 }
+};
+static int nkcdtab = (sizeof(kcdtab) / sizeof(struct keytab));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+_PROTOTYP( VOID freelocal, (int) );
+_PROTOTYP( static CK_OFF_T expon, (CK_OFF_T, CK_OFF_T) );
+_PROTOTYP( static CK_OFF_T gcd, (CK_OFF_T, CK_OFF_T) );
+_PROTOTYP( static CK_OFF_T fact, (CK_OFF_T) );
+
+int /* Initialize macro data structures. */
+macini() { /* Allocate mactab and preset the first element. */
+ int i;
+ if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX)))
+ return(-1);
+ mactab[0].kwd = NULL;
+ mactab[0].mval = NULL;
+ mactab[0].flgs = 0;
+ for (i = 0; i < MACLEVEL; i++)
+ localhead[i] = NULL;
+ return(0);
+}
+#endif /* NOSPL */
+
+/* C M D S R C -- Returns current command source */
+
+/* 0 = top level, 1 = file, 2 = macro, -1 = error (shouldn't happen) */
+
+/*
+ As of 19 Aug 2000 this routine is obsolete. The scalar global variable
+ xcmdsrc can be checked instead to save the overhead of a function call.
+*/
+int
+cmdsrc() {
+#ifdef COMMENT
+ return(xcmdsrc);
+#else
+#ifndef NOSPL
+ if (cmdlvl == 0)
+ return(0);
+ else if (cmdstk[cmdlvl].src == CMD_MD)
+ return(2);
+ else if (cmdstk[cmdlvl].src == CMD_TF)
+ return(1);
+ else
+ return(-1);
+#else
+ if (tlevel < 0)
+ return(0);
+ else
+ return(1);
+#endif /* NOSPL */
+#endif /* COMMENT */
+}
+
+/* C M D I N I -- Initialize the interactive command parser */
+
+static int cmdinited = 0; /* Command parser initialized */
+extern int cmdint; /* Interrupts are allowed */
+#ifdef CK_AUTODL
+int cmdadl = 1; /* Autodownload */
+#else
+int cmdadl = 0;
+#endif /* CK_AUTODL */
+
+char * k_info_dir = NULL; /* Where to find text files */
+#ifdef UNIX
+static char * txtdir[] = {
+ "/usr/local/doc/", /* Linux, SunOS, ... */
+ "/usr/share/lib/", /* HP-UX 10.xx... */
+ "/usr/share/doc/", /* Other possibilities... */
+ "/usr/local/lib/", /* NOTE: Each of these is tried */
+ "/usr/local/share/", /* as is, and also with a kermit */
+ "/usr/local/share/doc/", /* subdirectory. */
+ "/usr/local/share/lib/",
+ "/opt/kermit/", /* Solaris */
+ "/opt/kermit/doc/",
+ "/opt/",
+ "/usr/doc/",
+ "/doc/",
+ ""
+};
+#endif /* UNIX */
+
+/*
+ lookup() cache to speed up script execution.
+
+ This is a static cache. Items are stored in decreasing frequency of
+ reference based on statistics from a range of scripts. This gives
+ better performance than a dynamic cache, which would require a lot more
+ code and also would require system-dependent elements including system
+ calls (e.g. to get subsecond times for entry aging).
+*/
+#ifdef USE_LUCACHE /* Set in ckuusr.h */
+#define LUCACHE 32 /* Change this to reduce cache size */
+int lusize = 0;
+char * lucmd[LUCACHE];
+int luval[LUCACHE];
+int luidx[LUCACHE];
+struct keytab * lutab[LUCACHE];
+#endif /* USE_LUCACHE */
+
+static VOID
+luinit() { /* Initialize lookup() cache */
+ int x, y;
+
+#ifdef USE_LUCACHE
+ x = lookup(cmdtab,"if",ncmd,&y);
+ lucmd[lusize] = "if";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(iftab,"not",nif,&y);
+ lucmd[lusize] = "not";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = iftab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(vartab,"cmdlevel",nvars,&y);
+ lucmd[lusize] = "cmdlevel";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = vartab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"goto",ncmd,&y);
+ lucmd[lusize] = "goto";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(iftab,">",nif,&y);
+ lucmd[lusize] = ">";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = iftab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"incr",ncmd,&y);
+ lucmd[lusize] = "incr";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"def",ncmd,&y);
+ lucmd[lusize] = "def";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"_assign",ncmd,&y);
+ lucmd[lusize] = "_assign";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"echo",ncmd,&y);
+ lucmd[lusize] = "echo";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(fnctab,"eval",nfuncs,&y);
+ lucmd[lusize] = "eval";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = fnctab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(fnctab,"lit",nfuncs,&y);
+ lucmd[lusize] = "lit";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = fnctab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"do",ncmd,&y);
+ lucmd[lusize] = "do";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"_getargs",ncmd,&y);
+ lucmd[lusize] = "_getargs";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(iftab,"<",nif,&y);
+ lucmd[lusize] = "<";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = iftab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"_putargs",ncmd,&y);
+ lucmd[lusize] = "_putargs";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"asg",ncmd,&y);
+ lucmd[lusize] = "asg";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+ if (++lusize > LUCACHE) return;
+
+ x = lookup(cmdtab,"else",ncmd,&y);
+ lucmd[lusize] = "else";
+ luval[lusize] = x;
+ luidx[lusize] = y;
+ lutab[lusize] = cmdtab;
+#endif /* USE_LUCACHE */
+}
+
+VOID
+cmdini() {
+ int i = 0, x = 0, y = 0, z = 0, skip = 0;
+ char * p;
+#ifdef TTSPDLIST
+ long * ss = NULL;
+ extern int nspd;
+ extern struct keytab * spdtab;
+#endif /* TTSPDLIST */
+
+#ifndef NOSPL
+/*
+ On stack to allow recursion!
+*/
+ char vnambuf[VNAML]; /* Buffer for variable names */
+#endif /* NOSPL */
+
+ if (cmdinited) /* Already initialized */
+ return; /* Don't do it again */
+
+ for (i = 0; i < CMDSTKL; i++) /* Prompt strings for each */
+ prstring[i] = NULL; /* command level */
+
+#ifndef NOCSETS
+ p = getenv("K_CHARSET"); /* Set default file character set */
+ if (p) { /* from environment */
+ x = lookup(fcstab,p,nfilc,&y);
+ if (x > -1)
+ fcharset = x;
+ }
+#endif /* NOCSETS */
+
+ p = getenv("K_INFO_DIRECTORY"); /* Find Kermit info directory */
+ if (p && *p && strlen(p) <= CKMAXPATH)
+ makestr(&k_info_dir,p);
+ if (!k_info_dir) {
+ p = getenv("K_INFO_DIR");
+ if (p && *p && strlen(p) <= CKMAXPATH)
+ makestr(&k_info_dir,p);
+ }
+#ifdef UNIX
+ if (k_info_dir) { /* Look for Kermit docs directory */
+ if (zchki(k_info_dir) == -2) {
+ char xbuf[CKMAXPATH+32], *s = "";
+ if (ckrchar(k_info_dir) != '/')
+ s = "/";
+ ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,s,"ckubwr.txt",NULL);
+ if (zchki(xbuf) < 0)
+ makestr(&k_info_dir,NULL);
+ }
+ }
+ if (!k_info_dir) {
+ char xbuf[CKMAXPATH+32];
+ int i;
+ for (i = 0; *(txtdir[i]); i++) {
+ ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckubwr.txt",NULL,NULL);
+ if (zchki(xbuf) > 0) {
+ makestr(&k_info_dir,txtdir[i]);
+ debug(F110,"k_info_dir 1",k_info_dir,0);
+ break;
+ }
+ ckmakmsg(xbuf,CKMAXPATH+32,
+ txtdir[i],"kermit/","ckubwr.txt",NULL);
+ if (zchki(xbuf) > 0) {
+ ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"kermit/",NULL,NULL);
+ makestr(&k_info_dir,xbuf);
+ debug(F110,"k_info_dir 2",k_info_dir,0);
+ break;
+ }
+ ckmakmsg(xbuf,CKMAXPATH+32,
+ txtdir[i],"ckermit/","ckubwr.txt",NULL);
+ if (zchki(xbuf) > 0) {
+ ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckermit/",NULL,NULL);
+ makestr(&k_info_dir,xbuf);
+ debug(F110,"k_info_dir 3",k_info_dir,0);
+ break;
+ }
+ }
+ if (k_info_dir) { /* Make sure it ends with "/" */
+ if (ckrchar(k_info_dir) != '/') {
+ char xbuf[CKMAXPATH+32];
+ ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,"/",NULL,NULL);
+ makestr(&k_info_dir,xbuf);
+ }
+ }
+ }
+#else
+#ifdef OS2
+ {
+ char xdir[CKMAXPATH+8], *s = "";
+ extern char startupdir[];
+ xdir[0] = NUL;
+ if (ckrchar(startupdir) != '/')
+ s = "/";
+ if (strlen(s) + strlen(startupdir) + 5 < CKMAXPATH + 8 )
+ ckmakmsg(xdir,CKMAXPATH+8,s,startupdir,"DOC/",NULL);
+ makestr(&k_info_dir,xdir);
+ }
+#endif /* OS2 */
+#endif /* UNIX */
+
+#ifdef TTSPDLIST
+ if (!spdtab && (ss = ttspdlist())) { /* Get speed list if necessary */
+ int j, k, m = 0, n; /* Create sorted keyword table */
+ char buf[16];
+ char * p;
+ if ((spdtab =
+ (struct keytab *) malloc(sizeof(struct keytab) * ss[0]))) {
+ for (i = 1; i <= ss[0]; i++) { /* ss[0] = number of elements */
+ if (ss[i] < 1L) break; /* Shouldn't happen */
+ buf[0] = NUL; /* Make string */
+ sprintf(buf,"%ld",ss[i]); /* SAFE */
+ if (ss[i] == 8880L)
+ ckstrncpy(buf,"75/1200",sizeof(buf));
+ if (ss[i] == 134L)
+ ckstrncat(buf,".5",16);
+ n = strlen(buf);
+ if ((n > 0) && (p = (char *)malloc(n+1))) {
+ if (m > 0) { /* Have at least one in list */
+ for (j = 0; /* Find slot */
+ j < m && strcmp(buf,spdtab[j].kwd) > 0;
+ j++
+ )
+ ;
+ if (j < m) { /* Must insert */
+ for (k = m-1; k >= j; k--) { /* Move others down */
+ spdtab[k+1].kwd = spdtab[k].kwd;
+ spdtab[k+1].flgs = spdtab[k].flgs;
+ spdtab[k+1].kwval = spdtab[k].kwval;
+ }
+ }
+ } else /* First one */
+ j = 0;
+ ckstrncpy(p,buf,n+1); /* Add new speed */
+ spdtab[j].kwd = p;
+ spdtab[j].flgs = 0;
+ spdtab[j].kwval = (int) ss[i] / 10;
+ m++; /* Count this one */
+ }
+ }
+ }
+ nspd = m;
+ }
+#endif /* TTSPDLIST */
+
+#ifndef NOSPL
+ /* Allocate INPUT command buffer */
+ if (!inpbuf) {
+ if (!(inpbuf = (char *) malloc(INPBUFSIZ+8)))
+ fatal("cmdini: no memory for INPUT buffer");
+ }
+ for (x = 0; x < INPBUFSIZ; x++) /* Initialize it */
+ inpbuf[x] = NUL;
+ inpbp = inpbuf; /* Initialize pointer */
+ inbufsize = INPBUFSIZ; /* and size. */
+#endif /* NOSPL */
+
+#ifdef DCMDBUF
+ if (cmsetup() < 0) fatal("Can't allocate command buffers!");
+
+#ifndef NOSPL
+ /* Allocate command stack allowing command parser to call itself */
+
+ if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL)))
+ fatal("cmdini: no memory for cmdstk");
+ if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for ifcmd");
+ if (!(count = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for count");
+ if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for iftest");
+ if (!(intime = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for intime");
+ if (!(inpcas = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for inpcas");
+ if (!(takerr = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for takerr");
+ if (!(merror = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for merror");
+ if (!(xquiet = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for xquiet");
+ if (!(xvarev = (int *) malloc(sizeof(int)*CMDSTKL)))
+ fatal("cmdini: no memory for xvarev");
+ if (!kermrc)
+ if (!(kermrc = (char *) malloc(KERMRCL+1)))
+ fatal("cmdini: no memory for kermrc");
+#ifdef CK_APC
+/* Application Program Command buffer */
+ if (!(apcbuf = malloc(APCBUFLEN + 1)))
+ fatal("cmdini: no memory for apcbuf");
+#endif /* CK_APC */
+#endif /* NOSPL */
+
+/* line[] and tmpbuf[] are the two string buffers used by the command parser */
+
+ if (!(line = malloc(LINBUFSIZ + 1)))
+ fatal("cmdini: no memory for line");
+ if (!(tmpbuf = malloc(LINBUFSIZ + 1)))
+ fatal("cmdini: no memory for tmpbuf");
+#endif /* DCMDBUF */
+
+#ifndef NOSPL
+#ifdef CK_MINPUT
+ { /* Initialize MINPUT pointers */
+ int i;
+ extern char *ms[];
+ for (i = 0; i < MINPMAX; i++)
+ ms[i] = NULL;
+ }
+#endif /* CK_MINPUT */
+
+ if (macini() < 0) /* Allocate macro buffers */
+ fatal("Can't allocate macro buffers!");
+
+ ifcmd[0] = 0; /* Command-level related variables. */
+ iftest[0] = 0; /* Initialize variables at top level */
+ count[0] = 0; /* of stack... */
+ intime[0] = 0;
+ inpcas[0] = 0;
+ takerr[0] = 0;
+ merror[0] = 0;
+ xquiet[0] = quiet;
+ xvarev[0] = vareval;
+#endif /* NOSPL */
+
+#ifndef NOSPL
+ cmdlvl = 0; /* Initialize the command stack */
+ xcmdsrc = CMD_KB;
+ cmdstk[cmdlvl].src = CMD_KB; /* Source is console */
+ cmdstk[cmdlvl].lvl = 0; /* Level is 0 */
+ cmdstk[cmdlvl].ccflgs = 0; /* No flags */
+#endif /* NOSPL */
+
+ tlevel = -1; /* Take file level = keyboard */
+ for (i = 0; i < MAXTAKE; i++) /* Initialize command file names */
+ tfnam[i] = NULL;
+
+ cmsetp(ckprompt); /* Set up C-Kermit's prompt */
+ /* Can't set IKSD prompt here since */
+ /* we do not yet know if we are IKSD */
+#ifndef NOSPL
+
+ initmac(); /* Initialize macro table */
+
+/* Predefine built-in one-line macros */
+
+ addmac("ibm-linemode",m_ibm); /* IBM-LINEMODE */
+ addmac("fatal",m_fat); /* FATAL macro */
+ y = addmac("fast",m_fast); /* FAST macro */
+ addmac("cautious",m_cautious); /* CAUTIOUS macro */
+ addmac("robust",m_robust); /* ROBUST macro */
+#ifdef OS2
+ addmac("manual",m_manual); /* MANUAL macro */
+#endif /* OS2 */
+#ifdef VMS
+ addmac("purge",m_purge); /* PURGE macro */
+#endif /* VMS */
+
+/*
+ Predefine built-in multiline macros; these are top-level commands
+ that are implemented internally as macros. NOTE: When adding a new
+ one of these, remember to update the END and RETURN commands to
+ account for it, or else END and RETURN from within it won't work right.
+*/
+ x = addmmac("_forx",for_def); /* FOR macro */
+ if (x > -1) mactab[x].flgs = CM_INV;
+ x = addmmac("_forz",foz_def); /* Other FOR macro */
+ if (x > -1) mactab[x].flgs = CM_INV;
+ x = addmmac("_xif",xif_def); /* XIF macro */
+ if (x > -1) mactab[x].flgs = CM_INV;
+ x = addmmac("_while",whil_def); /* WHILE macro */
+ if (x > -1) mactab[x].flgs = CM_INV;
+ x = addmmac("_switx",sw_def); /* SWITCH macro */
+ if (x > -1) mactab[x].flgs = CM_INV;
+
+/* Fill in command-line argument vector */
+
+ sprintf(vnambuf,"\\&@[%d]",xargs); /* SAFE */
+ if (inserver) { /* But hidden in IKSD */
+ y = -1;
+ xargs = 0;
+ } else
+ y = arraynam(vnambuf,&x,&z); /* goes in array \&@[] */
+
+ tmpbuf[0] = NUL;
+ if (y > -1) {
+ int j = -1;
+ int yy = 0;
+ dclarray((char)x,z); /* Declare the array */
+#ifndef NOTAKEARGS
+ /* Macro argument vector */
+ sprintf(vnambuf,"\\&_[%d]",z); /* SAFE */
+ yy = arraynam(vnambuf,&x,&z); /* goes in array \&_[] */
+ if (yy > -1) /* Name is OK */
+ dclarray((char)x,z); /* Declare the array */
+#endif /* NOTAKEARGS */
+ skip = 0;
+ for (i = 0; i < xargs; i++) { /* Fill the arrays */
+ sprintf(vnambuf,"\\&@[%d]",i); /* SAFE */
+ addmac(vnambuf,xargv[i]);
+ if (cfilef && i == 0)
+ continue;
+#ifdef KERBANG
+ if (skip) {
+ j = 0;
+ skip = 0;
+ continue;
+ }
+#endif /* KERBANG */
+ if (j < 0 && /* Assign items after "=" or "--"*/
+ (!strcmp(xargv[i],"=") || !strcmp(xargv[i],"--"))
+ ) {
+ j = 0; /* to \%1..\%9 */
+#ifdef KERBANG
+ } else if (j < 0 &&
+ (!strcmp(xargv[i],"+") ||
+ !strncmp(xargv[i],"+ ",2) ||
+ !strncmp(xargv[i],"+\t",2))
+ ) {
+ skip = 1;
+ continue;
+#endif /* KERBANG */
+ } else if (j > -1) {
+ j++;
+ if (j <= 9) {
+ vnambuf[0] = '\\';
+ vnambuf[1] = '%';
+ vnambuf[2] = (char)(j+'0');
+ vnambuf[3] = NUL;
+ addmac(vnambuf,xargv[i]);
+ }
+ if (yy > -1) {
+ char c, * p;
+ int flag = 0;
+ p = xargv[i];
+ makestr(&(toparg[j]),p);
+ while ((c = *p++)) { if (c == SP) { flag++; break; } }
+ if (flag)
+ ckstrncat(tmpbuf,"\"",TMPBUFSIZ);
+ ckstrncat(tmpbuf,xargv[i],TMPBUFSIZ);
+ if (flag)
+ ckstrncat(tmpbuf,"\"",TMPBUFSIZ);
+ ckstrncat(tmpbuf," ",TMPBUFSIZ);
+ }
+ }
+ }
+ if (cfilef) {
+ addmac("\\%0",cmdfil);
+ if (yy > -1)
+ makestr(&(toparg[0]),cmdfil);
+ } else {
+ addmac("\\%0",xargv[0]);
+ if (yy > -1)
+ makestr(&(toparg[0]),xargv[0]);
+ }
+ if (yy > -1) {
+ topargc = (j < 0) ? 1 : j + 1;
+ topxarg = toparg;
+#ifdef COMMENT
+ /* This needs work */
+ if (!cfilef)
+ makestr(&topline,tmpbuf);
+#endif /* COMMENT */
+ } else {
+ topargc = 0;
+ topxarg = NULL;
+ }
+ a_dim[0] = topargc - 1;
+ a_ptr[0] = topxarg;
+ debug(F111,"a_dim[0]","A",a_dim[0]);
+ }
+ *vnambuf = NUL;
+#endif /* NOSPL */
+
+ luinit(); /* Initialize lookup() cache */
+
+/* Get our home directory now. This needed in lots of places. */
+
+ cmdinited = 1;
+}
+
+#ifdef NT
+_PROTOTYP(char * GetAppData,(int));
+#endif /* NT */
+
+VOID
+doinit() {
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+ int x = 0, ok = 0;
+#ifdef OS2
+ char * ptr = 0;
+#endif /* OS2 */
+
+ if (!cmdinited)
+ cmdini();
+
+#ifdef MAC
+ return; /* Mac Kermit has no init file */
+
+#else /* !MAC */
+
+/* If skipping init file ('-Y' on Kermit command line), return now. */
+
+ if (noinit) {
+ kermrc[0] = '\0';
+ inidir[0] = '\0';
+/*
+ But returning from here results in inidir[] never being set to anything.
+ Instead it should be set to wherever the init file *would* have been
+ executed from. So this bit of code should be removed, and then we should
+ sprinkle "if (noinit)" tests throughout the following code until we have
+ set inidir[], and then return without actually taking the init file.
+*/
+ return;
+ }
+
+#ifdef OS2
+/*
+ The -y init file must be fully specified or in the current directory.
+ KERMRC is looked for via INIT, DPATH and PATH in that order. Finally, our
+ own executable file path is taken and the .EXE suffix is replaced by .INI
+ and this is tried as the initialization file.
+*/
+#ifdef CK_LOGIN
+ debug(F101,"doinit inserver","",inserver);
+ debug(F101,"doinit isguest","",isguest);
+ debug(F110,"doinit anonfile",anonfile,0);
+
+ if (isguest && anonfile) {
+ ckstrncpy(line, anonfile, LINBUFSIZ+1);
+ } else
+#endif /* CK_LOGIN */
+ if (rcflag) {
+ ckstrncpy(line,kermrc,LINBUFSIZ+1);
+#ifdef CK_LOGIN
+ } else if (inserver) {
+ char * appdata = NULL;
+#ifdef NT
+ appdata = GetAppData(1);
+ if ( appdata ) {
+ ckmakmsg(line,LINBUFSIZ+1,appdata,
+ "Kermit 95/k95.ini",NULL,NULL);
+ if ( zchki(line) < 0 )
+ line[0] = '\0';
+ }
+ if (line[0] == 0) {
+ appdata = GetAppData(0);
+ if ( appdata ) {
+ ckmakmsg(line,LINBUFSIZ+1,appdata,
+ "Kermit 95/k95.ini",NULL,NULL);
+ if ( zchki(line) < 0 )
+ line[0] = '\0';
+ }
+ }
+#endif /* NT */
+ if (line[0] == 0) {
+ appdata = zhome();
+ if ( appdata ) {
+ ckmakmsg(line,LINBUFSIZ+1,appdata,
+#ifdef NT
+ "k95.ini",
+#else /* NT */
+ "k2.ini",
+#endif /* NT */
+ NULL,NULL);
+ if ( zchki(line) < 0 )
+ line[0] = '\0';
+ }
+ }
+ debug(F110,"doinit inserver inifile",line,0);
+#endif /* CK_LOGIN */
+ } else {
+ char * env = 0;
+#ifdef NT
+ env = getenv("K95.KSC");
+#else
+ env = getenv("K2.KSC");
+#endif /* NT */
+ if (!env) {
+#ifdef NT
+ env = getenv("K95.INI");
+#else
+ env = getenv("K2.INI");
+#endif /* NT */
+ }
+ if (!env)
+ env = getenv("CKERMIT.INI");
+ if (!env)
+ env = getenv("CKERMIT_INI");
+ line[0] = '\0';
+
+ debug(F110,"doinit env",env,0);
+ if (env)
+ ckstrncpy(line,env,LINBUFSIZ+1);
+
+#ifdef NT
+ if (line[0] == 0) {
+ env = GetAppData(1);
+ if ( env ) {
+ ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL);
+ if ( zchki(line) < 0 )
+ line[0] = '\0';
+ }
+ }
+ if (line[0] == 0) {
+ env = GetAppData(0);
+ if ( env ) {
+ ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL);
+ if ( zchki(line) < 0 )
+ line[0] = '\0';
+ }
+ }
+#endif /* NT */
+
+ if (line[0] == 0) {
+ env = zhome();
+ if ( env ) {
+ ckmakmsg(line,LINBUFSIZ+1,env,
+#ifdef NT
+ "k95.ini",
+#else /* NT */
+ "k2.ini",
+#endif /* NT */
+ NULL,NULL);
+ if ( zchki(line) < 0 )
+ line[0] = '\0';
+ }
+ }
+
+ if (line[0] == 0)
+ _searchenv(kermrc,"INIT",line);
+ if (line[0] == 0)
+ _searchenv(kermrc,"DPATH",line);
+ if (line[0] == 0)
+ _searchenv(kermrc,"PATH",line);
+ if (line[0] == 0) {
+ char *pgmptr = GetLoadPath();
+ if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) {
+ lp = strrchr(pgmptr, '\\');
+ if (lp) {
+ strncpy(line, pgmptr, lp - pgmptr);
+#ifdef NT
+ strcpy(line + (lp - pgmptr), "/k95.ini");
+#else /* NT */
+ strcpy(line + (lp - pgmptr), "/k2.ini");
+#endif /* NT */
+ } else {
+ lp = strrchr(pgmptr, '.');
+ if (lp) {
+ strncpy(line, pgmptr, lp - pgmptr);
+ strcpy(line + (lp - pgmptr), ".ini");
+ }
+ }
+ }
+ }
+ }
+
+#ifdef CKROOT
+ if (!zinroot(line)) {
+ debug(F110,"doinit setroot violation",line,0);
+ return;
+ }
+#endif /* CKROOT */
+
+ debug(F110,"doinit fopen()",line,0);
+ if ((tfile[0] = fopen(line,"r")) != NULL) {
+ ok = 1;
+ tlevel = 0;
+ tfline[tlevel] = 0;
+ if (tfnam[tlevel] = malloc(strlen(line)+1))
+ strcpy(tfnam[tlevel],line); /* safe */
+#ifndef NOSPL
+ cmdlvl++;
+ xcmdsrc = CMD_TF;
+ cmdstk[cmdlvl].src = CMD_TF;
+ cmdstk[cmdlvl].lvl = tlevel;
+ cmdstk[cmdlvl].ccflgs = 0;
+ ifcmd[cmdlvl] = 0;
+ iftest[cmdlvl] = 0;
+ count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
+ intime[cmdlvl] = intime[cmdlvl-1];
+ inpcas[cmdlvl] = inpcas[cmdlvl-1];
+ takerr[cmdlvl] = takerr[cmdlvl-1];
+ merror[cmdlvl] = merror[cmdlvl-1];
+ xquiet[cmdlvl] = quiet;
+ xvarev[cmdlvl] = vareval;
+#endif /* NOSPL */
+ debug(F110,"doinit init file",line,0);
+ } else {
+ debug(F100,"doinit no init file","",0);
+ }
+ ckstrncpy(kermrc,line,KERMRCL);
+ for (ptr = kermrc; *ptr; ptr++) /* Convert backslashes to slashes */
+ if (*ptr == '\\')
+ *ptr = '/';
+#else /* not OS2 */
+ lp = line;
+ lp[0] = '\0';
+ debug(F101,"doinit rcflag","",rcflag);
+#ifdef GEMDOS
+ zkermini(line, rcflag, kermrc);
+#else
+#ifdef VMS
+ {
+ int x;
+ x = zkermini(line,LINBUFSIZ,kermrc);
+ debug(F111,"CUSTOM zkermini",line,x);
+ if (x == 0)
+ line[0] = NUL;
+ }
+#else /* not VMS */
+#ifdef CK_LOGIN
+ debug(F101,"doinit isguest","",isguest);
+ if (isguest)
+ ckstrncpy(lp, anonfile ? anonfile : kermrc, LINBUFSIZ);
+ else
+#endif /* CK_LOGIN */
+ if (rcflag) { /* If init file name from cmd line */
+ ckstrncpy(lp,kermrc,LINBUFSIZ); /* use it, */
+ } else { /* otherwise... */
+#ifdef CK_INI_A /* If we've a system-wide init file */
+ /* And it takes precedence over the user's... */
+ ckstrncpy(lp,CK_SYSINI,KERMRCL); /* Use it */
+ if (zchki(lp) < 0) { /* (if it exists...) */
+#endif /* CK_INI_A */
+ char * homdir;
+ char * env = 0;
+ line[0] = NUL;
+
+ /* Add support for environment variable */
+ env = getenv("CKERMIT.INI");
+ if (!env)
+ env = getenv("CKERMIT_INI");
+ if (env)
+ ckstrncpy(lp,env,KERMRCL);
+
+ if (lp[0] == 0) {
+ homdir = zhome();
+ if (homdir) { /* Home directory for init file. */
+ ckstrncpy(lp,homdir,KERMRCL);
+#ifdef STRATUS
+ ckstrncat(lp,">",KERMRCL);/* VOS dirsep */
+#else
+ if (lp[0] == '/') ckstrncat(lp,"/",KERMRCL);
+#endif /* STRATUS */
+ }
+ ckstrncat(lp,kermrc,KERMRCL);/* Append default file name */
+ }
+#ifdef CK_INI_A
+ }
+#endif /* CK_INI_A */
+#ifdef CK_INI_B /* System-wide init defined? */
+ /* But user's ini file takes precedence */
+ if (zchki(lp) < 0) /* If user doesn't have her own, */
+ ckstrncpy(lp,CK_SYSINI,KERMRCL); /* use system-wide one. */
+#endif /* CK_INI_B */
+ }
+#endif /* VMS */
+#endif /* GEMDOS */
+
+#ifdef AMIGA
+ reqoff(); /* Disable requestors */
+#endif /* AMIGA */
+
+#ifdef USE_CUSTOM
+ /* If no init file was found, execute the customization file */
+ debug(F111,"CUSTOM 1",line,rcflag);
+ if ((!line[0] || zchki(line) < 0) && !rcflag) {
+ int x;
+#ifdef OS2
+ x = ckmakestr(line,LINBUFSIZ,GetAppData(1),"/","K95CUSTOM.INI",NULL);
+ debug(F111,"CUSTOM 2",line,x);
+ if (zchki(line) < 0) {
+ x = ckmakestr(line,LINBUFSIZ,GetAppData(0),"/","K95USER.INI",NULL);
+ debug(F111,"CUSTOM 3",line,x);
+ }
+#else /* OS2 */
+ x = ckstrncpy(line,zhome(),LINBUFSIZ);
+#ifndef VMS
+ /* VMS zhome() returns "SYS$LOGIN:" */
+ if (line[x-1] != DIRSEP) {
+ line[x++] = DIRSEP;
+ line[x] = NUL;
+ }
+#endif /* VMS */
+ x = ckstrncat(line,MYCUSTOM,LINBUFSIZ);
+ debug(F111,"CUSTOM 4",line,x);
+#endif /* OS2 */
+ }
+ debug(F110,"CUSTOM 5",line,0);
+#endif /* USE_CUSTOM */
+
+#ifdef CKROOT
+ if (!zinroot(line)) {
+ debug(F110,"doinit setroot violation",line,0);
+ return;
+ }
+#endif /* CKROOT */
+
+ debug(F110,"doinit ini file is",line,0);
+ if ((tfile[0] = fopen(line,"r")) != NULL) { /* Try to open init file. */
+ ok = 1;
+ tlevel = 0;
+ tfline[tlevel] = 0;
+ if ((tfnam[tlevel] = malloc(strlen(line)+1)))
+ strcpy(tfnam[tlevel],line); /* safe */
+
+ ckstrncpy(kermrc,line,KERMRCL);
+
+#ifndef NOSPL
+ cmdlvl++;
+ ifcmd[cmdlvl] = 0;
+ iftest[cmdlvl] = 0;
+ count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
+ intime[cmdlvl] = intime[cmdlvl-1];
+ inpcas[cmdlvl] = inpcas[cmdlvl-1];
+ takerr[cmdlvl] = takerr[cmdlvl-1];
+ merror[cmdlvl] = merror[cmdlvl-1];
+ xquiet[cmdlvl] = quiet;
+ xvarev[cmdlvl] = vareval;
+ debug(F101,"doinit open ok","",cmdlvl);
+ xcmdsrc = CMD_TF;
+ cmdstk[cmdlvl].src = CMD_TF;
+ cmdstk[cmdlvl].lvl = tlevel;
+ cmdstk[cmdlvl].ccflgs = 0;
+#endif /* NOSPL */
+ } else if (rcflag) {
+ /* Print an error message only if a specific file was asked for. */
+ printf("?%s - %s\n", ck_errstr(), line);
+ }
+
+#ifdef datageneral
+/* If CKERMIT.INI not found in home directory, look in searchlist */
+ if (/* homdir && */ (tlevel < 0)) {
+ ckstrncpy(lp,kermrc,LINBUFSIZ);
+ if ((tfile[0] = fopen(line,"r")) != NULL) {
+ ok = 1;
+ tlevel = 0;
+ tfline[tlevel] = 0;
+ if (tfnam[tlevel] = malloc(strlen(line)+1))
+ strcpy(tfnam[tlevel],line); /* safe */
+#ifndef NOSPL
+ cmdlvl++;
+ xcmdsrc = CMD_TF;
+ cmdstk[cmdlvl].src = CMD_TF;
+ cmdstk[cmdlvl].lvl = tlevel;
+ cmdstk[cmdlvl].ccflgs = 0;
+ ifcmd[cmdlvl] = 0;
+ iftest[cmdlvl] = 0;
+ count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
+ intime[cmdlvl] = intime[cmdlvl-1];
+ inpcas[cmdlvl] = inpcas[cmdlvl-1];
+ takerr[cmdlvl] = takerr[cmdlvl-1];
+ merror[cmdlvl] = merror[cmdlvl-1];
+ xquiet[cmdlvl] = quiet;
+ xvarev[cmdlvl] = vareval;
+#endif /* NOSPL */
+ }
+ }
+#endif /* datageneral */
+
+#ifdef AMIGA /* Amiga... */
+ reqpop(); /* Restore requestors */
+#endif /* AMIGA */
+#endif /* OS2 */
+#endif /* MAC */
+
+ /* Assign value to inidir */
+
+ if (!ok) {
+ inidir[0] = NUL;
+ } else {
+ ckstrncpy(inidir, kermrc, CCHMAXPATH);
+ x = strlen(inidir);
+ if (x > 0) {
+ int i;
+ for (i = x - 1; i > 0; i-- ) {
+ if (ISDIRSEP(inidir[i])) {
+ inidir[i+1] = NUL;
+ break;
+ }
+ }
+ }
+#ifdef NT
+ GetShortPathName(inidir,inidir,CCHMAXPATH);
+#endif /* NT */
+ }
+}
+
+VOID
+doiksdinit() {
+#ifdef CK_SSL
+ /* IKSD doesn't request client certs */
+ ssl_verify_flag = SSL_VERIFY_NONE;
+#endif /* CK_SSL */
+
+ if (!cmdinited)
+ cmdini();
+
+#ifdef IKSDCONF
+#ifdef OS2
+ line[0] = '\0';
+ _searchenv(iksdconf,"INIT",line);
+ if (line[0] == 0)
+ _searchenv(iksdconf,"DPATH",line);
+ if (line[0] == 0)
+ _searchenv(iksdconf,"PATH",line);
+ if (line[0] == 0) {
+ char *pgmptr = GetLoadPath();
+ if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) {
+ lp = strrchr(pgmptr, '\\');
+ if (lp) {
+ strncpy(line, pgmptr, lp - pgmptr);
+ strcpy(line + (lp - pgmptr), "\\");
+ strcpy(line + (lp - pgmptr + 1), iksdconf);
+ } else {
+ lp = strrchr(pgmptr, '.');
+ if (lp) {
+ strncpy(line, pgmptr, lp - pgmptr);
+ strcpy(line + (lp - pgmptr), ".ksc");
+ }
+ }
+ }
+ }
+ debug(F110,"doiksdinit() line",line,0);
+ tfile[0] = fopen(line,"r");
+#else /* OS2 */
+ tfile[0] = fopen(iksdconf,"r");
+#endif /* OS2 */
+ if (tfile[0] != NULL) {
+ tlevel = 0;
+ tfline[tlevel] = 0;
+#ifdef OS2
+ if (tfnam[tlevel] = malloc(strlen(line)+1))
+ strcpy(tfnam[tlevel],line);
+#else /* OS2 */
+ if ((tfnam[tlevel] = malloc(strlen(iksdconf)+1)))
+ strcpy(tfnam[tlevel],iksdconf);
+#endif /* OS2 */
+#ifndef NOSPL
+ cmdlvl++;
+ xcmdsrc = CMD_TF;
+ cmdstk[cmdlvl].src = CMD_TF;
+ cmdstk[cmdlvl].lvl = tlevel;
+ cmdstk[cmdlvl].ccflgs = 0;
+ ifcmd[cmdlvl] = 0;
+ iftest[cmdlvl] = 0;
+ count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
+ intime[cmdlvl] = intime[cmdlvl-1];
+ inpcas[cmdlvl] = inpcas[cmdlvl-1];
+ takerr[cmdlvl] = takerr[cmdlvl-1];
+ merror[cmdlvl] = merror[cmdlvl-1];
+ xquiet[cmdlvl] = quiet;
+ xvarev[cmdlvl] = vareval;
+#endif /* NOSPL */
+ debug(F110,"doiksdinit file ok",tfnam[tlevel],0);
+ } else {
+ debug(F110,"doiksdinit open failed",tfnam[tlevel],0);
+ }
+#endif /* IKSDCONF */
+}
+
+#ifndef NOSPL
+/*
+ G E T N C M
+
+ Get next command from current macro definition. Command is copied
+ into string pointed to by argument s, max length n. Returns:
+ 0 if a string was copied;
+ -1 if there was no string to copy.
+*/
+int
+getncm(s,n) char *s; int n; {
+ int y = 0; /* Character counter */
+ int quote = 0;
+ int kp = 0; /* Brace up-down counter */
+ int pp = 0; /* Parenthesis up-down counter */
+#ifndef NODQMACRO
+ int dq = 0; /* Doublequote counter */
+#endif /* NODQMACRO */
+ char *s2; /* Copy of destination pointer */
+
+ s2 = s; /* Initialize string pointers */
+ *s = NUL; /* and destination buffer */
+
+ /* debug(F010,"getncm entry",macp[maclvl],0); */
+
+ for (y = 0; /* Loop for n bytes max */
+ macp[maclvl] && *macp[maclvl] && y < n;
+ y++, s++, macp[maclvl]++) {
+
+ *s = *macp[maclvl]; /* Get next char from macro def */
+
+#ifndef COMMENT
+/*
+ This is to allow quoting of parentheses, commas, etc, in function
+ arguments, but it breaks just about everything else. DON'T REMOVE THIS
+ COMMENT! (Otherwise you'll wind up adding the same code again and breaking
+ everything again.) <-- The preceding warning should be obsolete since the
+ statements below have been fixed, but in case of fire, remove the "n" from
+ the <#>ifndef above. NEW WARNING: code added 12 Apr 2002 to exempt the
+ opening brace in \{nnn} from being treated as a quoted brace.
+*/
+ if (!quote && *s == CMDQ) {
+ quote = 1;
+ continue;
+ }
+ if (quote) {
+ int notquote = 0;
+ quote = 0;
+ if (*s == '{') { /* Check for \{nnn} (8.0.203) */
+ char c, * p;
+ p = macp[maclvl] + 1;
+ while ((c = *p++)) {
+ if (isdigit(c))
+ continue;
+ else if (c == '}') {
+ notquote++;
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ if (notquote == 0)
+ continue;
+ }
+#endif /* COMMENT */
+
+/*
+ Allow braces around macro definition to prevent commas from being turned to
+ end-of-lines and also treat any commas within parens as text so that
+ multiple-argument functions won't cause the command to break prematurely.
+ 19 Oct 2001: Similar treatment was added for doublequotes, so
+
+ define foo { echo "one, two, three" }
+
+ would work as expected. This doesn't seem to have broken anything but
+ if something comes up later, rebuild with NODQMACRO defined.
+*/
+ if (*s == '{') kp++; /* Count braces */
+ if (*s == '}' && kp > 0) kp--;
+ if (*s == '(') pp++; /* Count parentheses. */
+ if (*s == ')' && pp > 0) pp--;
+#ifndef NODQMACRO
+#ifndef COMMENT
+ /* Too many false positives */
+ /* No, not really -- this is indeed the best we can do */
+ /* Reverted to this method Sun May 11 18:43:45 2003 */
+ if (*s == '"') dq = 1 - dq; /* Account for doublequotes */
+#else /* Fri Apr 4 13:21:29 2003 */
+ /* The code below breaks the SWITCH statement */
+ /* There is no way to make this work -- it would require */
+ /* building in all the knowledge of command parser. */
+ if (dblquo && (*s == '"')) { /* Have doublequote */
+ if (dq == 1) { /* Close quote only if... */
+ if ((*(macp[maclvl]+1) == SP) || /* followed by space or... */
+ (!*(macp[maclvl]+1)) || /* at end or ... */
+ /* Next char is command separator... */
+ /* Sun May 11 17:24:12 2003 */
+ (kp < 1 && pp < 1 && (*(macp[maclvl]+1) == ','))
+ )
+ dq = 0; /* Close the quote */
+ } else if (dq == 0) {
+ /* Open quote only if at beginning or preceded by space */
+ if (s > s2) {
+ if (*(s-1) == SP)
+ dq = 1;
+ } else if (s == s2) {
+ dq = 1;
+ }
+ }
+ }
+#endif /* COMMENT */
+#endif /* NODQMACRO */
+ if (*s == ',' && pp <= 0 && kp <= 0
+#ifndef NODQMACRO
+ && dq == 0
+#endif /* NODQMACRO */
+ ) {
+ macp[maclvl]++; /* Comma not in {} or () */
+ /* debug(F110,"next cmd",s,0); */
+ kp = pp = 0; /* so we have the next command */
+ break;
+ }
+ } /* Reached end. */
+#ifdef COMMENT
+ /* DON'T DO THIS - IT BREAKS EVERYTHING */
+ *s = NUL;
+#endif /* COMMENT */
+ if (*s2 == NUL) { /* If nothing was copied, */
+ /* debug(F100,"XXX getncm eom","",0); */
+ popclvl(); /* pop command level. */
+ return(-1);
+ } else { /* otherwise, tack CR onto end */
+ *s++ = CR;
+ *s = '\0';
+ /* debug(F110,"XXX getncm OK",s,0); */
+ if (mecho && pflag) /* If MACRO ECHO ON, echo the cmd */
+ printf("%s\n",s2);
+ }
+ return(0);
+}
+
+/* D O M A C -- Define and then execute a macro */
+
+int
+domac(name, def, flags) char *name, *def; int flags; {
+ int x, m;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int term_io;
+ int term_io_sav = term_io;
+ term_io = 0; /* Disable Terminal Emulator I/O */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ m = maclvl; /* Current macro stack level */
+ x = addmac(name, def); /* Define a new macro */
+ if (x > -1) { /* If successful, */
+ dodo(x,NULL,flags); /* start it (increments maclvl). */
+ while (maclvl > m) { /* Keep going till done with it, */
+ debug(F101,"domac loop maclvl 1","",maclvl);
+ sstate = (CHAR) parser(1); /* parsing & executing each command, */
+ debug(F101,"domac loop maclvl 2","",maclvl);
+ if (sstate) proto(); /* including protocol commands. */
+ }
+ debug(F101,"domac loop exit maclvl","",maclvl);
+ }
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = term_io_sav;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(success);
+}
+#endif /* NOSPL */
+
+/*
+ G E T N C T
+
+ Get next command from TAKE (command) file.
+
+ Call with:
+ s Pointer to buffer to read into
+ n Length of buffer
+ f File descriptor of file to read from
+ flag 0 == keep line terminator on and allow continuation
+ 1 == discard line terminator and don't allow continuation
+
+ Call with flag == 0 to read a command from a TAKE file;
+ Call with flag != 0 to read a line from a dialing or network directory.
+
+ In both cases, trailing comments and/or trailing whitespace is/are stripped.
+ If flag == 0, continued lines are combined into one line. A continued line
+ is one that ends in hypen, or any line in a "block", which starts with "{"
+ at the end of a line and ends with a matching "}" at the beginning of a
+ subsequent line; blocks may be nested.
+
+ Returns:
+ 0 if a string was copied,
+ -1 on EOF,
+ -2 on malloc failure
+ -3 if line is not properly terminated
+ -4 if (possibly continued) line is too long.
+*/
+static int lpxlen = 0;
+
+int
+getnct(s,n,f,flag) char *s; int n; FILE *f; int flag; {
+ int i = 0, len = 0, buflen = 0;
+ char c = NUL, cc = NUL, ccl = NUL, ccx = NUL, *s2 = NULL;
+ char *lp = NULL, *lpx = NULL, *lp2 = NULL, *lp3 = NULL, *lastcomma = NULL;
+ char * prev = NULL;
+ int bc = 0; /* Block counter */
+
+ s2 = s; /* Remember original pointer */
+ prev = s2; /* Here too */
+ buflen = n; /* Remember original buffer length */
+
+ if (n < 0)
+ return(-2);
+
+ /* Allocate a line buffer only if we don't have one that's big enough */
+
+ debug(F111,"getnct",ckitoa(lpxlen),n);
+
+ if (lpx && (n > lpxlen)) { /* Have one already */
+ debug(F101,"getnct new buffer","",lpxlen);
+ free(lpx); /* But it's not big enough */
+ lpx = NULL; /* Free current one */
+ lpxlen = 0;
+ }
+ if (!lpx) { /* Get new one */
+ if (!(lpx = (char *) malloc(n))) {
+ debug(F101,"getnct malloc failure","",0);
+ printf("?Memory allocation failure [getnct:%d]\n",n);
+ return(-2);
+ }
+ lpxlen = n;
+ }
+ lp2 = lpx;
+#ifdef KLUDGE
+ /* NOTE: No longer used as of 14 Aug 2000 */
+ lp2++;
+#endif /* KLUDGE */
+
+ while (1) { /* Loop to read lines from file */
+ debug(F101,"getnct while (1)","",n);
+ if (fgets(lp2,n,f) == NULL) { /* Read a line into lp2 */
+ debug(F110,"getnct EOF",s2,0); /* EOF */
+ free(lpx); /* Free temporary storage */
+ lpx = NULL;
+ *s = NUL; /* Make destination be empty */
+ return(-1); /* Return failure code */
+ }
+
+#ifndef NODIAL
+ if (flag) /* Count this line */
+ dirline++;
+ else
+#endif /* NODIAL */
+ tfline[tlevel]++;
+ len = strlen(lp2) - 1; /* Position of line terminator */
+ if (len == 0 && lp2[0] != '\n') { /* Last line in file has one char */
+ lp2[++len] = '\n'; /* that is not a newline */
+ lp2[len] = NUL;
+ }
+ debug(F010,"getnct",lp2,0);
+ if (len < 0)
+ len = 0;
+ if (techo && pflag) /* If TAKE ECHO ON, */
+ printf("%3d. %s", /* echo it this line. */
+#ifndef NODIAL
+ flag ? dirline :
+#endif /* NODIAL */
+ tfline[tlevel],
+ lp2
+ );
+ lp3 = lp2; /* Working pointer */
+ i = len; /* Get first nonwhitespace character */
+ while (i > 0 && (*lp3 == SP || *lp3 == HT)) {
+ i--;
+ lp3++;
+ }
+ if (i == 0 && bc > 0) /* Blank line in {...} block */
+ continue;
+
+ /* Isolate, remove, and check terminator */
+
+ c = lp2[len]; /* Value of line terminator */
+ /* debug(F101,"getnct terminator","",c); */
+ if (c < LF || c > CR) { /* It's not a terminator */
+ /* debug(F111,"getnct bad line",lp2,c); */
+ if (feof(f) && len > 0 && len < n) {
+ /* Kludge Alert... */
+ if (!quiet)
+ printf("WARNING: Last line of %s lacks terminator\n",
+ s2 == cmdbuf ? "command file" : "directory file");
+ c = lp2[++len] = '\n'; /* No big deal - supply one. */
+ } else { /* Something's wrong, fail. */
+ free(lpx);
+ lpx = NULL;
+ return(-3);
+ }
+ }
+ /* Trim trailing whitespace */
+
+ for (i = len - 1; i > -1 && lp2[i] <= SP; i--) /* Trim */
+ ;
+ /* debug(F101,"getnct i","",i); */
+ lp2[i+1] = NUL; /* Terminate the string */
+ /* debug(F110,"getnct lp2",lp2,0); */
+ lp = lp2; /* Make a working pointer */
+
+ /* Remove trailing or full-line comment */
+
+ while ((cc = *lp)) {
+ if (cc == ';' || cc == '#') { /* Comment introducer? */
+ if (lp == lp2) { /* First char on line */
+ *lp = NUL;
+ break;
+ } else if (*(lp - 1) == SP || *(lp - 1) == HT) {
+ lp--;
+ *lp = NUL; /* Or preceded by whitespace */
+ break;
+ }
+ }
+ lp++;
+ }
+ if (lp > lp2)
+ lp--; /* Back up over the NUL */
+
+ /* Now trim any space that preceded the comment */
+
+ while ((*lp == SP || *lp == HT) && lp >= lp2) {
+ *lp = NUL;
+ if (lp <= lp2)
+ break;
+ lp--;
+ }
+ /* debug(F110,"getnct comment trimmed",lp2,0); */
+
+ len = strlen(lp2); /* Length after trimming */
+
+ if (n - len < 2) { /* Check remaining space */
+ debug(F111,"getnct command too long",s2,buflen);
+ printf("?Line too long, maximum length: %d.\n",buflen);
+ free(lpx);
+ return(-4);
+ }
+ ccl = (len > 0) ? lp2[len-1] : 0; /* Last character in line */
+ ccx = (len > 1) ? lp2[len-2] : 0; /* Penultimate char in line */
+
+#ifdef COMMENT
+ /* Line containing only whitespace and ,- */
+ if ((len > 1) && (lp3 == lp2+len-2) && (ccl == '-') && (ccx == ','))
+ continue;
+#endif /* COMMENT */
+
+#ifdef KLUDGE
+/*
+ If it is a command and it begins with a token (like ! or .) that is not
+ followed by a space, insert a space now; otherwise cmkey() can get mighty
+ confused.
+*/
+ if (s == s2 && !flag) {
+ char *p = toktab;
+ while (*p) {
+ if (*p == *lp3 && *(p+1) != SP) {
+ debug(F110,"getnct token",p,0);
+ *lp3-- = SP;
+ *lp3 = *p;
+ if (lp3 < lp2) {
+ lp2--;
+ len++;
+ }
+ break;
+ } else
+ p++;
+ }
+ }
+#endif /* KLUDGE */
+ lp = lp2;
+
+ while ((*s++ = *lp++)) /* Copy result to target buffer */
+ n--; /* accounting for length */
+ s--; /* Back up over the NUL */
+
+ /* Check whether this line is continued */
+
+ if (flag) /* No line continuation when flag=1 */
+ break; /* So break out of read-lines loop */
+
+#ifdef COMMENT
+ debug(F000,"getnct first char","",*lp3);
+ debug(F000,"getnct last char","",ccl);
+ debug(F000,"getnct next-to-last char","",ccx);
+#endif /* COMMENT */
+
+ if (bc > 0 && *lp3 == '}') { /* First char on line is '}' */
+ bc--; /* Decrement block counter */
+ }
+
+ if (bc == 0 && /* Line is continued if bc > 0 */
+#ifdef COMMENT
+ /* Not supported as of C-Kermit 6.0 */
+ ccl != CMDQ && /* or line ends with CMDQ */
+#endif /* COMMENT */
+ ccl != '-' && /* or line ends with dash */
+ ccl != '{') /* or line ends with opening brace */
+ break; /* None of those, we're done. */
+
+ if (ccl == '-' || ccl == '{') /* Continuation character */
+ if (ccx == CMDQ) /* But it's quoted */
+ break; /* so ignore it */
+
+ if (ccl == '{') { /* Last char on line is '{'? */
+ bc++; /* Count the block opener. */
+ } else if (ccl == '-') { /* Explicit continue? */
+ char c, * ss;
+ int state = 0, nn;
+ s--; /* Yes, back up over terminators */
+ n++; /* and over continuation character */
+ nn = n; /* Save current count */
+ ss = s; /* and pointer */
+ s--; /* Back up over dash */
+ n++;
+ while (state < 2 && s >= prev) { /* Check for "{,-" */
+ n++;
+ c = *s--;
+ if (c <= SP)
+ continue;
+ if (c != ',' && c != '{')
+ break;
+ switch (state) {
+ case 0: /* Looking for comma */
+ if (c == ',')
+ state = 1;
+ break;
+ case 1: /* Looking for left brace */
+ if (c == '{') {
+ state = 2;
+ s += 2;
+ *s = NUL;
+ bc++;
+ }
+ break;
+ }
+ }
+ if (state != 2) { s = ss; n = nn; }
+ *s = NUL;
+ } else { /* None of those but (bc > 0) */
+ lastcomma = s;
+ *s++ = ','; /* and insert a comma */
+ n--;
+ }
+#ifdef COMMENT
+ debug(F101,"getnct bc","",bc);
+ debug(F100,"getnct continued","",0);
+#endif /* COMMENT */
+
+ *s = NUL;
+ prev = s;
+
+ } /* read-lines while loop */
+
+ if (lastcomma)
+ *lastcomma = SP;
+ if (!flag) /* Tack line terminator back on */
+ *s++ = c;
+ *s++ = NUL; /* Terminate the string */
+ untab(s2); /* Done, convert tabs to spaces */
+#ifdef DEBUG
+ if (!flag) {
+ debug(F010,"CMD(F)",s2,0);
+ }
+#endif /* DEBUG */
+ free(lpx); /* Free temporary storage */
+ return(0); /* Return success */
+}
+
+VOID
+shostack() { /* Dump the command stack */
+ int i;
+ char *p;
+#ifndef NOSPL
+ for (i = cmdlvl; i > 0; i--) {
+ if (cmdstk[i].src == CMD_TF) {
+ p = tfnam[cmdstk[i].lvl];
+ if (zfnqfp(p,TMPBUFSIZ,tmpbuf))
+ p = tmpbuf;
+ printf(" %2d. File : %s (line %d)\n",
+ i,
+ p,
+ tfline[cmdstk[i].lvl]
+ );
+ } else if (cmdstk[i].src == CMD_MD) {
+ char * m;
+ m = m_arg[cmdstk[i].lvl][0]; /* Name of this macro */
+ if (i > 0) { /* Special handling for 2-level */
+ char *s; /* built-in macros... */
+ s = m_arg[cmdstk[i-1].lvl][0]; /* Name next level up */
+ if (s && cmdstk[i-1].src == CMD_MD) {
+ if (!strcmp(s,"_forx"))
+ m = "FOR";
+ else if (!strcmp(s,"_xif"))
+ m = "XIF";
+ else if (!strcmp(s,"_while"))
+ m = "WHILE";
+ else if (!strcmp(s,"_switx"))
+ m = "SWITCH";
+ }
+ }
+ printf(" %2d. Macro : %s\n",i,m);
+ } else if (cmdstk[i].src == CMD_KB) {
+ printf(" %2d. Prompt:\n",i);
+ } else {
+ printf(" %2d. ERROR : Command source unknown\n",i);
+ }
+ }
+#else
+ for (i = tlevel; i > -1; i--) {
+ p = tfnam[i];
+ if (zfnqfp(p,TMPBUFSIZ,tmpbuf))
+ p = tmpbuf;
+ printf(" %2d. File : %s (line %d)\n",
+ i,
+ p,
+ tfline[i]
+ );
+ }
+#endif /* NOSPL */
+ if (i == 0)
+ printf(" %2d. Prompt: (top level)\n",0);
+}
+
+/* For command error messages - avoid dumping out the contents of some */
+/* some huge FOR loop if it contains a syntax error. */
+
+static char *
+cmddisplay(s, cx) char * s; int cx; {
+ static char buf[80];
+ if ((int)strlen(s) > 70) {
+ sprintf(buf,"%.64s...",s); /* SAFE */
+ s = buf;
+ }
+ return(s);
+}
+
+static VOID
+cmderr() {
+ if (xcmdsrc > 0) {
+ switch (cmd_err) { /* SET COMMAND ERROR-DISPLAY */
+ case 0:
+ break;
+ case 1:
+ case 2:
+ if (tlevel > -1) {
+#ifndef NOSPL
+ if (xcmdsrc == 2)
+ printf(
+"In macro or block defined in file: %s starting about line %d\n",
+ tfnam[tlevel] ? tfnam[tlevel] : "", tfline[tlevel]
+ );
+ else
+#endif /* NOSPL */
+ printf("File: %s, Line: %d\n",
+ tfnam[tlevel] ? tfnam[tlevel] : "", tfline[tlevel]
+ );
+ }
+#ifndef NOSPL
+ if (cmd_err == 2) {
+ if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
+ int m;
+ m = cmdstk[cmdlvl].lvl;
+ if (mlook(mactab,m_arg[m][0],nmac) >= 0)
+ printf("Macro name: %s\n", m_arg[m][0]);
+ }
+ }
+#endif /* NOSPL */
+ break;
+
+ case 3:
+ printf("Command stack:\n");
+ shostack();
+ }
+ }
+}
+
+/* P A R S E R -- Top-level interactive command parser. */
+
+/*
+ Call with:
+ m = 0 for normal behavior: keep parsing and executing commands
+ until an action command is parsed, then return with a
+ Kermit start-state as the value of this function.
+ m = 1 to parse only one command, can also be used to call parser()
+ recursively.
+ m = 2 to read but do not execute one command.
+ In all cases, parser() returns:
+ 0 if no Kermit protocol action required
+ > 0 with a Kermit protocol start-state.
+ < 0 upon error.
+*/
+int
+parser(m) int m; {
+ int tfcode, xx, yy, zz; /* Workers */
+ int is_tn = 0;
+ int cdlost = 0;
+
+#ifndef NOSPL
+ int inlevel; /* Level we were called at */
+ extern int askflag, echostars;
+#endif /* NOSPL */
+ char *cbp; /* Command buffer pointer */
+#ifdef MAC
+ extern char *lfiles; /* Fake extern cast */
+#endif /* MAC */
+ extern int interrupted;
+#ifndef NOXFER
+ extern int sndcmd, getcmd, fatalio, clearrq;
+#endif /* NOXFER */
+
+#ifdef AMIGA
+ reqres(); /* Restore AmigaDOS requestors */
+#endif /* AMIGA */
+
+#ifdef OS2
+ if (cursor_save > -1) { /* Restore cursor if it was */
+ cursorena[VCMD] = cursor_save; /* turned off during file transfer */
+ cursor_save = -1;
+ }
+#endif /* OS2 */
+
+#ifdef IKSDB
+ if (ikdbopen) slotstate(what,"COMMAND PROMPT","",""); /* IKSD database */
+#endif /* IKSDB */
+
+ is_tn = (local && network && IS_TELNET()) ||
+ (!local && sstelnet);
+
+ if (!xcmdsrc) /* If at top (interactive) level ... */
+ concb((char)escape); /* put console in 'cbreak' mode. */
+
+#ifdef CK_TMPDIR
+/* If we were cd'd temporarily to another device or directory ... */
+ if (f_tmpdir) {
+ int x;
+ x = zchdir((char *) savdir); /* ... restore previous directory */
+ f_tmpdir = 0; /* and remember we did it. */
+ debug(F111,"parser tmpdir restoring",savdir,x);
+ }
+#endif /* CK_TMPDIR */
+
+#ifndef NOSPL
+ inlevel = cmdlvl; /* Current macro level */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"&parser entry maclvl","",maclvl);
+ debug(F101,"&parser entry inlevel","",inlevel);
+ debug(F101,"&parser entry tlevel","",tlevel);
+ debug(F101,"&parser entry cmdlvl","",cmdlvl);
+ debug(F101,"&parser entry m","",m);
+ }
+#endif /* DEBUG */
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ ftreset(); /* Reset global file settings */
+#endif /* NOXFER */
+/*
+ sstate becomes nonzero when a command has been parsed that requires some
+ action from the protocol module. Any non-protocol actions, such as local
+ directory listing or terminal emulation, are invoked directly from below.
+*/
+ sstate = 0; /* Start with no start state. */
+
+#ifndef NOXFER
+#ifndef NOSPL
+ query = 0; /* QUERY not active */
+#endif /* NOSPL */
+#ifndef NOHINTS
+ if (!success) {
+ if (local && !network && carrier != CAR_OFF) {
+ int x; /* Serial connection */
+ x = ttgmdm(); /* with carrier checking */
+ if (x > -1) {
+ if (!(x & BM_DCD)) {
+ cdlost = 1;
+ fatalio = 1;
+ }
+ }
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"parser top what","",what);
+ debug(F101,"parser top interrupted","",interrupted);
+ debug(F101,"parser top cdlost","",cdlost);
+ debug(F101,"parser top sndcmd","",sndcmd);
+ debug(F101,"parser top getcmd","",getcmd);
+ }
+#endif /* DEBUG */
+ if (cdlost && !interrupted && (sndcmd || getcmd)) {
+ printf("?Connection broken (carrier signal lost)\n");
+ }
+ if (sndcmd && protocol == PROTO_K &&
+ !success && hints && !interrupted && !fatalio && !xcmdsrc) {
+ int x = 0, n = 0;
+ printf("\n*************************\n");
+ printf("SEND-class command failed.\n");
+ printf(" Packets sent: %d\n", spackets);
+ printf(" Retransmissions: %d\n",retrans);
+ printf(" Timeouts: %d\n", timeouts);
+ printf(" Damaged packets: %d\n", crunched);
+ if (epktrcvd) {
+ printf(" Transfer canceled by receiver.\n");
+ printf(" Receiver's message: \"%s\"\n",(char *)epktmsg);
+ n++;
+ } else {
+ if (epktmsg) if (*epktmsg) {
+ printf(" Fatal Kermit Protocol Error: %s\n",epktmsg);
+ n++;
+ }
+ }
+ if (local && !network && carrier != CAR_OFF) {
+ int xx; /* Serial connection */
+ xx = ttgmdm(); /* with carrier checking */
+ if (xx > -1) {
+ if (!(xx & BM_DCD))
+ cdlost = 1;
+ }
+ }
+
+#ifdef UNIX
+ if (errno != 0)
+#endif /* UNIX */
+ {
+ printf(" Most recent local OS error: \"%s\"\n",ck_errstr());
+ n++;
+ }
+ printf(
+ "\nHINTS... If the preceding error message%s not explain the failure:\n",
+ (n > 1) ? "s do" : " does"
+ );
+#ifndef NOLOCAL
+ if (local) {
+ if (rpackets == 0) {
+ printf(" . Did you start a Kermit receiver on the far end?\n");
+ } else {
+ printf(
+ " . Try changing the remote Kermit's FLOW-CONTROL setting.\n");
+ if (!network && mdmtyp > 0)
+ if ((3 * crunched) > spackets)
+ printf(
+ " . Try placing a new call to get a cleaner connection.\n");
+ }
+ } else if (rpackets > 0) {
+ if (flow == FLO_NONE)
+ printf(" . Give me a SET FLOW XON/XOFF command and try again.\n");
+ else
+ printf(" . Give me a SET FLOW NONE command and try again.\n");
+ }
+ x++;
+#endif /* NOLOCAL */
+
+ if ((3 * timeouts) > spackets)
+ printf(" . Adjust the timeout method (see HELP SET SEND).\n");
+ if ((3 * retrans) > spackets)
+ printf(" . Increase the retry limit (see HELP SET RETRY).\n");
+
+#ifdef CK_SPEED
+ if (prefixing != PX_ALL && rpackets > 2) {
+ printf(" . Try it again with: SET PREFIXING ALL\n");
+ x++;
+ }
+#endif /* CK_SPEED */
+#ifdef STREAMING
+ if (streamed) {
+ printf(" . Try it again with: SET STREAMING OFF\n");
+ x++;
+ } else if (reliable) {
+ printf(" . Try it again with: SET RELIABLE OFF\n");
+ x++;
+ }
+#endif /* STREAMING */
+
+#ifdef CK_SPEED
+ if (clearrq > 0 && prefixing == PX_NON) {
+ printf(" . Try it again with: SET CLEAR-CHANNEL OFF\n");
+ x++;
+ }
+#endif /* CK_SPEED */
+ if (!parity) {
+ printf(" . Try it again with: SET PARITY SPACE\n");
+ x++;
+ }
+ printf(" . %sive a ROBUST command and try again.\n",
+ (x > 0) ? "As a last resort, g" : "G"
+ );
+ printf("Also:\n");
+ printf(" . Be sure the source file has read permission.\n");
+ printf(" . Be sure the target directory has write permission.\n");
+/*
+ if the file was 2G or larger make sure other Kermit supports LFs...
+*/
+ printf(" . Be sure the target disk has sufficient space.\n");
+ printf("(Use SET HINTS OFF to suppress hints.)\n");
+ printf("*************************\n\n");
+ }
+ debug(F101,"topcmd","",topcmd);
+ if (getcmd && protocol == PROTO_K &&
+ !success && hints && !interrupted && !fatalio && !xcmdsrc) {
+ int x = 0;
+ extern int urpsiz, wslotr;
+ printf("\n*************************\n");
+ printf("RECEIVE- or GET-class command failed.\n");
+ printf(" Packets received: %d\n", rpackets);
+ printf(" Damaged packets: %d\n", crunched);
+ printf(" Timeouts: %d\n", timeouts);
+ if (rpackets > 0)
+ printf(" Packet length: %d\n", urpsiz);
+ if (epktrcvd) {
+ printf(" Transfer canceled by sender.\n");
+ printf(" Sender's message: \"%s\"\n",(char *)epktmsg);
+ }
+#ifdef UNIX
+ if (errno != 0)
+#endif /* UNIX */
+ printf(" Most recent local error: \"%s\"\n",ck_errstr());
+ printf(
+ "\nHINTS... If the preceding error message%s not explain the failure:\n",
+ epktrcvd ? "s do" : " does"
+ );
+#ifndef NOLOCAL
+ if (local) {
+ if (topcmd == XXGET)
+ printf(" . Did you start a Kermit SERVER on the far end?\n");
+ if (rpackets == 0) {
+ if (topcmd != XXGET)
+ printf(" . Did you start a Kermit SENDer on the far end?\n");
+ } else {
+ printf(
+ " . Choose a different FLOW-CONTROL setting and try again.\n");
+ }
+ } else if (topcmd == XXGET)
+ printf(" . Is the other Kermit in (or does it have) SERVER mode?\n");
+ if (rpackets > 0 && urpsiz > 90)
+ printf(" . Try smaller packets (SET RECEIVE PACKET-LENGTH).\n");
+ if (rpackets > 0 && wslotr > 1 && !streamed)
+ printf(" . Try a smaller window size (SET WINDOW).\n");
+ if (!local && rpackets > 0) {
+ if (flow == FLO_NONE)
+ printf(" . Give me a SET FLOW XON/XOFF command and try again.\n");
+ else
+ printf(" . Give me a SET FLOW NONE command and try again.\n");
+ }
+ x++;
+#endif /* NOLOCAL */
+#ifdef STREAMING
+ if (streamed) {
+ printf(" . Try it again with: SET STREAMING OFF\n");
+ x++;
+ } else if (reliable && local) {
+ printf(" . Try it again with: SET RELIABLE OFF\n");
+ x++;
+ } else
+#endif /* STREAMING */
+ if (!parity) {
+ printf(" . Try it again with: SET PARITY SPACE\n");
+ x++;
+ }
+ printf((x > 0) ?
+ " . As a last resort, give a ROBUST command and try again.\n" :
+ " . Give a ROBUST command and try again.\n"
+ );
+ printf("Also:\n");
+ printf(" . Be sure the target directory has write permission.\n");
+ printf(" . Be sure the target disk has sufficient space.\n");
+ printf(" . Try telling the %s to SET PREFIXING ALL.\n",
+ topcmd == XXGET ? "server" : "sender"
+ );
+ printf(" . Try giving a ROBUST command to the %s.\n",
+ topcmd == XXGET ? "server" : "sender"
+ );
+ printf("(Use SET HINTS OFF to suppress hints.)\n");
+ printf("*************************\n\n");
+ }
+#endif /* NOHINTS */
+ getcmd = 0;
+ sndcmd = 0;
+ interrupted = 0;
+#endif /* NOXFER */
+
+ while (sstate == 0) { /* Parse cmds until action requested */
+ debug(F100,"parse top","",0);
+ what = W_COMMAND; /* Now we're parsing commands. */
+ rcdactive = 0; /* REMOTE CD not active */
+ keepallchars = 0; /* MINPUT not active */
+
+#ifdef OS2
+ if (apcactive == APC_INACTIVE)
+ WaitCommandModeSem(-1);
+#endif /* OS2 */
+#ifdef IKS_OPTION
+ if ((local &&
+ !xcmdsrc &&
+ is_tn &&
+ TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start) ||
+ (!local &&
+ !cmdadl &&
+ TELOPT_ME(TELOPT_KERMIT) &&
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ ) {
+ tn_siks(KERMIT_STOP);
+ }
+#endif /* IKS_OPTION */
+
+#ifndef NOXFER
+ if (autopath) {
+ fnrpath = PATH_AUTO;
+ autopath = 0;
+ }
+ remfile = 0; /* Clear these in case REMOTE */
+ remappd = 0; /* command was interrupted... */
+ rempipe = 0;
+ makestr(&snd_move,g_snd_move); /* Restore these */
+ makestr(&rcv_move,g_rcv_move);
+ makestr(&snd_rename,g_snd_rename);
+ makestr(&rcv_rename,g_rcv_rename);
+#endif /* NOXFER */
+
+ /* Take requested action if there was an error in the previous command */
+
+ setint();
+ debug(F101,"parser tlevel","",tlevel);
+ debug(F101,"parser cmd_rows","",cmd_rows);
+
+#ifndef NOLOCAL
+ debug(F101,"parser wasclosed","",wasclosed);
+ if (wasclosed) { /* If connection was just closed */
+#ifndef NOSPL
+ int k;
+ k = mlook(mactab,"on_close",nmac); /* Look up "on_close" */
+ if (k >= 0) { /* If found, */
+ /* printf("ON_CLOSE CMD LOOP\n"); */
+ dodo(k,ckitoa(whyclosed),0); /* Set it up */
+ }
+#endif /* NOSPL */
+ whyclosed = WC_REMO;
+ wasclosed = 0;
+ }
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+ xxdot = 0; /* Clear this... */
+
+ debug(F101,"parser success","",success);
+ if (success == 0) {
+ if (cmdstk[cmdlvl].src == CMD_TF && takerr[cmdlvl]) {
+ printf("Command file terminated by error.\n");
+ popclvl();
+ if (cmdlvl == 0) return(0);
+ }
+ if (cmdstk[cmdlvl].src == CMD_MD && merror[cmdlvl]) {
+ printf("Command error: macro terminated.\n");
+ popclvl();
+ if (m && (cmdlvl < inlevel))
+ return((int) sstate);
+ }
+ }
+ nulcmd = (m == 2);
+ debug(F101,"parser nulcmd","",nulcmd);
+#else
+ if (success == 0 && tlevel > -1 && takerr[tlevel]) {
+ printf("Command file terminated by error.\n");
+ popclvl();
+ cmini(ckxech); /* Clear the cmd buffer. */
+ if (tlevel < 0) /* Just popped out of cmd files? */
+ return(0); /* End of init file or whatever. */
+ }
+#endif /* NOSPL */
+
+#ifdef MAC
+ /* Check for TAKE initiated by menu. */
+ if ((tlevel == -1) && lfiles)
+ startlfile();
+#endif /* MAC */
+
+ /* If in TAKE file, check for EOF */
+#ifndef NOSPL
+#ifdef MAC
+ if
+#else
+ while
+#endif /* MAC */
+ ((cmdstk[cmdlvl].src == CMD_TF) /* If end of take file */
+ && (tlevel > -1)
+ && feof(tfile[tlevel])) {
+ popclvl(); /* pop command level */
+ cmini(ckxech); /* and clear the cmd buffer. */
+ if (cmdlvl == 0) { /* Just popped out of all cmd files? */
+ return(0); /* End of init file or whatever. */
+ }
+ }
+#ifdef MAC
+ miniparser(1);
+ if (sstate == 'a') { /* if cmd-. cancel */
+ debug(F100, "parser: cancel take due to sstate", "", sstate);
+ sstate = '\0';
+ dostop();
+ return(0); /* End of init file or whatever. */
+ }
+#endif /* MAC */
+
+#else /* NOSPL */
+ if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */
+ popclvl(); /* Pop up one level. */
+ cmini(ckxech); /* and clear the cmd buffer. */
+ if (tlevel < 0) /* Just popped out of cmd files? */
+ return(0); /* End of init file or whatever. */
+ }
+#endif /* NOSPL */
+
+
+#ifndef NOSPL
+ debug(F101,"parser cmdlvl","",cmdlvl);
+ debug(F101,"parser cmdsrc","",cmdstk[cmdlvl].src);
+
+ if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
+ debug(F100,"parser macro","",0);
+ maclvl = cmdstk[cmdlvl].lvl; /* Get current level */
+ debug(F101,"parser maclvl","",maclvl);
+ cbp = cmdbuf; /* Copy next cmd to command buffer. */
+ *cbp = NUL;
+ if (*savbuf) { /* In case then-part of 'if' command */
+ ckstrncpy(cbp,savbuf,CMDBL); /* was saved, restore it. */
+ *savbuf = '\0';
+ } else { /* Else get next cmd from macro def */
+ if (getncm(cbp,CMDBL) < 0) {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"parser end of macro m","",m);
+ debug(F101,"parser end of macro cmdlvl","",cmdlvl);
+ debug(F101,"parser end of macro inlevel","",inlevel);
+ }
+#endif /* DEBUG */
+ if (m && (cmdlvl < inlevel))
+ return((int) sstate);
+ else /* if (!m) */ continue;
+ }
+ }
+ debug(F010,"CMD(M)",cmdbuf,0);
+
+ } else if (cmdstk[cmdlvl].src == CMD_TF)
+#else
+ if (tlevel > -1)
+#endif /* NOSPL */
+ {
+#ifndef NOSPL
+ debug(F111,"parser savbuf",savbuf,tlevel);
+ if (*savbuf) { /* In case THEN-part of IF command */
+ ckstrncpy(cmdbuf,savbuf,CMDBL); /* was saved, restore it. */
+ *savbuf = '\0';
+ } else
+#endif /* NOSPL */
+
+ /* Get next line from TAKE file */
+
+ if ((tfcode = getnct(cmdbuf,CMDBL,tfile[tlevel],0)) < 0) {
+ debug(F111,"parser tfcode",tfile[tlevel],tfcode);
+ if (tfcode < -1) { /* Error */
+ printf("?Error in TAKE command file: %s\n",
+ (tfcode == -2) ? "Memory allocation failure" :
+ "Line too long or contains NUL characters"
+ );
+ dostop();
+ }
+ continue; /* -1 means EOF */
+ }
+
+ /* If interactive, get next command from user. */
+
+ } else { /* User types it in. */
+ if (pflag) prompt(xxstring);
+ cmini(ckxech);
+ }
+
+ /* Now we know where next command is coming from. Parse and execute it. */
+
+ repars = 1; /* 1 = command needs parsing */
+#ifndef NOXFER
+ displa = 0; /* Assume no file transfer display */
+#endif /* NOXFER */
+
+ while (repars) { /* Parse this cmd until entered. */
+
+ debug(F101,"parser top of while loop","",0);
+ xaskmore = saveask; /* Restore global more-prompting */
+ diractive = 0; /* DIR command not active */
+ cdactive = 0; /* CD command not active */
+#ifndef NOSPL
+ askflag = 0; /* ASK command not active */
+ echostars = 0; /* Nor ASKQ */
+ debok = 1; /* Undisable debugging */
+#endif /* NOSPL */
+
+#ifdef RECURSIVE
+ /* In case of "send /recursive ./?<Ctrl-U>" etc */
+ recursive = 0; /* This is never sticky */
+#endif /* RECURSIVE */
+ xfiletype = -1; /* Reset this between each command */
+#ifndef NOMSEND
+ addlist = 0;
+#endif /* NOMSEND */
+#ifdef CK_RECALL
+ on_recall = 1;
+#endif /* CK_RECALL */
+ /* This might have been changed by a switch */
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot;
+ g_matchdot = -1;
+ }
+ cmres(); /* Reset buffer pointers. */
+
+#ifdef OS2
+#ifdef COMMENT
+ /* we check to see if a macro is waiting to be executed */
+ /* if so, we call domac on it */
+ if (cmdmac) {
+ ckstrncpy(cmdbuf, cmdmac, CMDBL);
+ free(cmdmac);
+ cmdmac = NULL;
+ }
+#endif /* COMMENT */
+#endif /* OS2 */
+#ifndef NOXFER
+ bye_active = 0;
+#endif /* NOXFER */
+ havetoken = 0;
+ xx = cmkey2(cmdtab,ncmd,"Command","",toktab,xxstring,1);
+ debug(F101,"top-level cmkey2","",xx);
+ if (xx == -5) {
+ yy = chktok(toktab);
+ debug(F101,"top-level cmkey token","",yy);
+#ifndef COMMENT
+ /* Either way makes absolutely no difference */
+ debug(F110,"NO UNGWORD",atmbuf,0);
+ /* ungword(); */
+#else
+ debug(F110,"TOKEN UNGWORD",atmbuf,0);
+ ungword();
+#endif /* COMMENT */
+ switch (yy) {
+ case '#': xx = XXCOM; break; /* Comment */
+ case ';': xx = XXCOM; break; /* Comment */
+#ifndef NOSPL
+ case '.': xx = XXDEF; xxdot = 1; break; /* Assignment */
+ case ':': xx = XXLBL; break; /* GOTO label */
+#endif /* NOSPL */
+
+#ifndef NOPUSH
+#ifdef CK_REDIR
+ case '<':
+#endif /* CK_REDIR */
+ case '@':
+ case '!':
+ if (nopush) {
+ char *s; int x;
+ if ((x = cmtxt("Text to be ignored","",&s,NULL)) < 0)
+ return(x);
+ success = 0;
+ xx = XXCOM;
+ } else {
+ switch(yy) {
+#ifdef CK_REDIR
+ case '<': xx = XXFUN; break; /* REDIRECT */
+#endif /* CK_REDIR */
+ case '@':
+ case '!': xx = XXSHE; break; /* Shell escape */
+ }
+ }
+ break;
+#endif /* NOPUSH */
+#ifdef CK_RECALL
+ case '^': xx = XXREDO; break;
+#endif /* CK_RECALL */
+#ifndef NOSPL
+ case '{': xx = XXMACRO; break;
+ case '(': xx = XXSEXP; break;
+#endif /* NOSPL */
+
+ default:
+ if (!quiet && !cmd_err) {
+ printf("\n?Invalid - \"%s\"\n",
+ cmddisplay((char *)cmdbuf,xx)
+ );
+ cmderr();
+ }
+ xx = -2;
+ }
+ havetoken = 1;
+ debug(F101,"HAVE TOKEN","",xx);
+ }
+ if (xx > -1) {
+ topcmd = xx; /* Top-level command index */
+#ifndef NOSPL
+ if (maclvl > -1)
+ lastcmd[maclvl] = xx;
+#endif /* NOSPL */
+ debug(F101,"topcmd","",topcmd);
+ debug(F101,"cmflgs","",cmflgs);
+ }
+
+#ifndef NOSPL
+ /* Special handling for IF..ELSE */
+
+ debug(F101,"cmdlvl","",cmdlvl);
+ debug(F101,"ifcmd[cmdlvl]","",ifcmd[cmdlvl]);
+
+ if (ifcmd[cmdlvl]) /* Count stmts after IF */
+ ifcmd[cmdlvl]++;
+ if (ifcmd[cmdlvl] > 2 && xx != XXELS && xx != XXCOM)
+ ifcmd[cmdlvl] = 0;
+
+ /* Execute the command and take action based on return code. */
+
+ if (nulcmd) { /* Ignoring this command? */
+ xx = XXCOM; /* Make this command a comment. */
+ }
+ fnsuccess = 1; /* For catching \function() errors */
+#endif /* NOSPL */
+
+ debug(F101,"calling docmd()","",xx);
+ zz = docmd(xx); /* Parse rest of command & execute. */
+
+#ifndef NOSPL
+ { /* For \v(lastcommand) */
+ extern char * prevcmd;
+ /* The exception list kind of a hack but let's try it... */
+ if (ckstrcmp(cmdbuf,"_getarg",7,0) &&
+ ckstrcmp(cmdbuf,"if ",3,0) &&
+ ckstrcmp(cmdbuf,"xif ",4,0) &&
+ ckstrcmp(cmdbuf,"do _if",6,0) &&
+ ckstrcmp(cmdbuf,"_assign _if",11,0))
+ ckstrncpy(prevcmd,cmdbuf,CMDBL);
+ }
+#endif /* NOSPL */
+
+#ifndef NOSPL
+ if (fnerror && !fnsuccess)
+ success = 0;
+#endif /* NOSPL */
+ debug(F101,"docmd returns","",zz);
+ /* debug(F011,"cmdbuf",cmdbuf,30); */
+ /* debug(F011,"atmbuf",atmbuf,30); */
+#ifdef MAC
+ if (tlevel > -1) {
+ if (sstate == 'a') { /* if cmd-. cancel */
+ debug(F110, "parser: cancel take, sstate:", "a", 0);
+ sstate = '\0';
+ dostop();
+ return(0); /* End of init file or whatever. */
+ }
+ }
+#endif /* MAC */
+ switch (zz) {
+ case -4: /* EOF (e.g. on redirected stdin) */
+ doexit(GOOD_EXIT,xitsta); /* ...exit successfully */
+ case -1: /* Reparse needed */
+ repars = 1; /* Just set reparse flag and... */
+ continue;
+#ifdef OS2
+ case -7: /* They typed a disk letter */
+ if (!zchdir((char *)cmdbuf)) {
+ perror((char *)cmdbuf);
+ success = 0;
+ } else success = 1;
+ repars = 0;
+ continue;
+
+#endif /* OS2 */
+ case -6: /* Invalid command given w/no args */
+ case -2: { /* Invalid command given w/args */
+ int x = 0;
+ char * eol = "";
+ x = strlen(cmdbuf); /* Avoid blank line */
+ if (x > 0) {
+ if (cmdbuf[x-1] != LF)
+ eol = "\n";
+ printf("?Invalid: %s%s",
+ cmddisplay(cmdbuf,xx),eol
+ );
+ } else
+ printf("?Invalid\n");
+ }
+ case -9: /* Bad, error message already done */
+ success = 0;
+ debug(F110,"top-level cmkey failed",cmdbuf,0);
+ /* If in background w/ commands coming stdin, terminate */
+ if (pflag == 0 && tlevel < 0)
+ fatal("Kermit command error in background execution");
+/*
+ Command retry feature, edit 190. If we're at interactive prompting level,
+ reprompt the user with as much of the command as didn't fail.
+*/
+#ifdef CK_RECALL
+ if (cm_retry && !xcmdsrc) { /* If at top level */
+ int len;
+ char *p, *s;
+ len = strlen(cmdbuf); /* Length of command buffer */
+ p = malloc(len + 1); /* Allocate space for copy */
+ if (p) { /* If we got the space copy */
+ strcpy(p,cmdbuf); /* the command buffer (SAFE). */
+ /* Chop off final field, the one that failed. */
+ s = p + len - 1; /* Point to end */
+ while (*s == SP && s > p) /* Trim blanks */
+ s--;
+ while (*s != SP && s > p) /* Trim last field */
+ s--;
+ if (s > p) /* Keep the space */
+ s++; /* after last good field */
+ if (s >= p) /* Cut off remainder */
+ *s = NUL;
+ cmini(ckxech); /* Reinitialize the parser */
+ ckstrncpy(cmdbuf,p,CMDBL); /* Copy result back */
+ free(p); /* Free temporary storage */
+ p = NULL;
+ prompt(xxstring); /* Reprint the prompt */
+ printf("%s",cmdbuf); /* Reprint partial command */
+ repars = 1; /* Force reparse */
+ continue;
+ }
+ } else
+#endif /* CK_RECALL */
+ cmderr();
+
+ cmini(ckxech); /* (fall thru) */
+
+ case -3: /* Empty command OK at top level */
+ repars = 0; /* Don't need to reparse. */
+ continue; /* Go back and get another command. */
+
+ default: /* Command was successful. */
+#ifndef NOSPL
+ debug(F101,"parser preparing to continue","",maclvl);
+#endif /* NOSPL */
+ debug(F101,"parser success","",success);
+ repars = 0; /* Don't need to reparse. */
+ continue; /* Go back and get another command. */
+ }
+ }
+#ifndef NOSPL
+ debug(F101,"parser breaks out of while loop","",maclvl);
+ if (m && (cmdlvl < inlevel)) return((int) sstate);
+#endif /* NOSPL */
+ }
+
+/* Got an action command, return start state. */
+
+ return((int) sstate);
+}
+
+#ifndef NOSPL
+/*
+ OUTPUT command.
+ Buffering and pacing added by L.I. Kirby, 5A(189), June 1993.
+*/
+#define OBSIZE 80 /* Size of local character buffer */
+
+static int obn; /* Buffer offset (high water mark) */
+static char obuf[OBSIZE+1]; /* OUTPUT buffer. */
+static char *obp; /* Pointer to output buffer. */
+_PROTOTYP( static int oboc, (char) );
+_PROTOTYP( static int xxout, (char *, int) );
+
+static int
+#ifdef CK_ANSIC
+xxout(char *obuf, int obsize)
+#else
+xxout(obuf, obsize) char *obuf; int obsize;
+#endif /* CK_ANSIC */
+/* xxout */ { /* OUTPUT command's output function */
+ int i, rc;
+
+ debug(F101,"xxout obsize","",obsize);
+ debug(F101,"xxout pacing","",pacing);
+ debug(F111,"xxout string",obuf,strlen(obuf));
+
+ rc = 0; /* Initial return code. */
+ if (!obuf || (obsize <= 0)) /* Nothing to output. */
+ goto xxout_x; /* Return successfully */
+
+ rc = -1; /* Now assume failure */
+ if (pacing == 0) { /* Is pacing enabled? */
+ if ((local ? /* No, write entire string at once */
+ ttol((CHAR *)obuf, obsize) : /* to communications device */
+ conxo(obsize, obuf)) /* or to console */
+ != obsize)
+ goto xxout_x;
+ } else {
+ for (i = 0; i < obsize; i++) { /* Write individual chars */
+ if ((local ? ttoc(obuf[i]) : conoc(obuf[i])) < 0)
+ goto xxout_x;
+ msleep(pacing);
+ }
+ }
+ if (duplex) {
+#ifdef OS2
+ if (inecho && local) {
+#ifndef NOLOCAL
+ for (i = 0; i < obsize; i++) { /* Write to emulator */
+ scriptwrtbuf((USHORT)obuf[i]); /* which also logs session */
+ }
+#endif /* NOLOCAL */
+ conxo(obsize,obuf);
+ } else if (seslog) { /* or log session here */
+ logstr((char *) obuf, obsize);
+ }
+#else /* OS2 */
+ if (seslog) {
+ logstr((char *) obuf, obsize);
+ }
+ if (inecho && local) {
+ conxo(obsize,obuf);
+ }
+#endif /* OS2 */
+ }
+ rc = 0; /* Success */
+ xxout_x:
+ obn = 0; /* Reset count */
+ obp = obuf; /* and pointers */
+ return(rc); /* return our return code */
+}
+
+#ifdef COMMENT
+/*
+ Macros for OUTPUT command execution, to make it go faster.
+*/
+#define obfls() ((xxout(obuf,obn)<0)?-1:0)
+#define oboc(c) ((*obp++=(char)(c)),*obp=0,(((++obn)>=OBSIZE)?obfls():0))
+
+#else /* The macros cause some compilers to generate bad code. */
+
+static int
+#ifdef CK_ANSIC
+oboc(char c)
+#else
+oboc(c) char c;
+#endif /* CK_ANSIC */
+/* oboc */ { /* OUTPUT command's output function */
+
+ *obp++ = c; /* Deposit character */
+ *obp = NUL; /* Flush buffer if it's now full */
+
+ return(((++obn) >= OBSIZE) ? xxout(obuf,obn) : 0);
+}
+#endif /* COMMENT */
+
+/* Routines for handling local variables -- also see popclvl(). */
+
+VOID
+freelocal(m) int m; { /* Free local variables */
+ struct localvar * v, * tv; /* at macro level m... */
+ debug(F101,"freelocal level","",m);
+ if (m < 0) return;
+ v = localhead[m]; /* List head for level m */
+ while (v) {
+ if (v->lv_name) /* Variable name */
+ free(v->lv_name);
+ if (v->lv_value) /* Value */
+ free(v->lv_value);
+ tv = v; /* Save pointer to this node */
+ v = v->lv_next; /* Get next one */
+ if (tv) /* Free this one */
+ free((char *)tv);
+ }
+ localhead[m] = (struct localvar *) NULL; /* Done, set list head to NULL */
+}
+
+#define MAXLOCALVAR 64
+
+/* Return a pointer to the definition of a user-defined variable */
+
+static char *
+vardef(s,isarray,x1,x2) char * s; int * isarray, * x1, * x2; {
+ char * p;
+ char c;
+ *isarray = 0;
+ if (!s) return(NULL);
+ if (!*s) return(NULL);
+ p = s;
+ if (*s == CMDQ) {
+ p++;
+ if (!*p)
+ return(NULL);
+ if ((c = *p) == '%') { /* Scalar variable. */
+ c = *++p; /* Get ID character. */
+ p = ""; /* Assume definition is empty */
+ if (!c)
+ return(NULL);
+ if (c >= '0' && c <= '9') { /* Digit for macro arg */
+ if (maclvl < 0) /* Digit variables are global */
+ return(g_var[c]); /* if no macro is active */
+ else /* otherwise */
+ return(m_arg[maclvl][c - '0']); /* they're on the stack */
+ } else if (isalpha(c)) {
+ if (isupper(c)) c -= ('a'-'A');
+ return(g_var[c]); /* Letter for global variable */
+ } else
+ return(NULL);
+ } else if (c == '&') { /* Array reference. */
+ int x, vbi, d;
+ x = arraynam(p,&vbi,&d); /* Get name and subscript */
+ if (x > -1 || d == -17) {
+ *isarray = 1;
+ *x1 = vbi;
+ *x2 = (d == -17) ? 0 : d;
+ }
+ if (x < 0)
+ return(NULL);
+ if (chkarray(vbi,d) >= 0) { /* Array is declared? */
+ vbi -= ARRAYBASE; /* Convert name to index */
+ if (a_dim[vbi] >= d) { /* If subscript in range */
+ char **ap;
+ ap = a_ptr[vbi];
+ return((ap) ? ap[d] : NULL);
+ }
+ }
+ }
+ return(NULL);
+ } else {
+ int k;
+ k = mxlook(mactab,s,nmac);
+ return((k > -1) ? mactab[k].mval : NULL);
+ }
+}
+
+
+int
+addlocal(p) char * p; {
+ int x, z, isarray = 0;
+ char * s;
+ struct localvar * v, *prev = (struct localvar *)NULL;
+ extern int tra_asg; int tra_tmp;
+
+ tra_tmp = tra_asg;
+
+ s = vardef(p,&isarray,&x,&z); /* Get definition of variable */
+ if (isarray) { /* Arrays are handled specially */
+ pusharray(x,z);
+ return(0);
+ }
+ if (!s) s = "";
+ if ((v = localhead[cmdlvl])) { /* Already have some at this level? */
+ while (v) { /* Find end of list */
+ prev = v;
+ v = v->lv_next;
+ }
+ }
+ v = (struct localvar *) malloc(sizeof(struct localvar));
+ if (!v) {
+ printf("?Failure to allocate storage for local variables");
+ return(-9);
+ }
+ if (!localhead[cmdlvl]) /* If first, set list head */
+ localhead[cmdlvl] = v;
+ else /* Otherwise link previous to this */
+ prev->lv_next = v;
+ prev = v; /* And make this previous */
+ v->lv_next = (struct localvar *) NULL; /* No next yet */
+
+ if (!(v->lv_name = (char *) malloc((int) strlen(p) + 1)))
+ return(-1);
+ strcpy(v->lv_name, p); /* Copy name into new node (SAFE) */
+
+ if (*s) {
+ if (!(v->lv_value = (char *) malloc((int) strlen(s) + 1)))
+ return(-1);
+ strcpy(v->lv_value, s); /* Copy value into new node (SAFE) */
+ } else
+ v->lv_value = NULL;
+
+ tra_asg = 0;
+ delmac(p,1); /* Delete the original macro */
+ tra_asg = tra_tmp;
+ return(0);
+}
+
+int
+dolocal() { /* Do the LOCAL command */
+ int i, x;
+ char * s;
+ char * list[MAXLOCALVAR+2]; /* Up to 64 variables per line */
+
+ if ((x = cmtxt("Variable name(s)","",&s,NULL)) < 0)
+ return(x);
+
+ xwords(s,MAXLOCALVAR,list,0); /* Break up line into "words" */
+
+ /* Note: Arrays do not use the localhead list, but have their own stack */
+
+ for (i = 1; i < MAXLOCALVAR && list[i]; i++) { /* Go through the list */
+ if (addlocal(list[i]) < 0)
+ goto localbad;
+ }
+ return(success = 1);
+
+ localbad:
+ printf("?Failure to allocate storage for local variables");
+ freelocal(cmdlvl);
+ return(-9);
+}
+
+/* D O O U T P U T -- Returns 0 on failure, 1 on success */
+
+#ifndef NOKVERBS
+#define K_BUFLEN 30
+#define SEND_BUFLEN 255
+#define sendbufd(x) { osendbuf[sendndx++] = x;\
+ if (sendndx == SEND_BUFLEN) {dooutput(s,cx); sendndx = 0;}}
+#endif /* NOKVERBS */
+
+int outesc = 1; /* Process special OUTPUT escapes */
+
+int
+dooutput(s, cx) char *s; int cx; {
+#ifdef SSHBUILTIN
+ extern int ssh_cas;
+ extern char * ssh_cmd;
+#endif /* SSHBUILTIN */
+ int x, xx, y, quote; /* Workers */
+ int is_tn = 0;
+
+ is_tn = (local && network && IS_TELNET()) ||
+ (!local && sstelnet);
+
+ debug(F111,"dooutput s",s,(int)strlen(s));
+
+ if (local) { /* Condition external line */
+#ifdef NOLOCAL
+ goto outerr;
+#else
+ if (ttchk() < 0) {
+ if (!network) {
+ if (carrier != CAR_OFF) {
+ int x;
+ x = ttgmdm();
+ if ((x > -1) && ((x & BM_DCD) == 0)) {
+ printf(
+"?Carrier signal required but not present - Try SET CARRIER-WATCH OFF.\n"
+ );
+ return(0);
+ }
+ } else {
+ printf(
+"?Problem with serial port or modem or cable - Try SHOW COMMUNICATIONS.\n"
+ );
+ return(0);
+ }
+ }
+ printf("?Connection %s %s is not open or not functioning.\n",
+ network ? "to" : "on",
+ ttname
+ );
+ return(0);
+ }
+ if (ttvt(speed,flow) < 0) {
+ printf("?OUTPUT initialization error\n");
+ return(0);
+ }
+#endif /* NOLOCAL */
+ }
+#ifdef SSHBUILTIN
+ if ( network && nettype == NET_SSH && ssh_cas && ssh_cmd &&
+ !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) {
+ if (!quiet)
+ printf("?SSH Subsystem active: %s\n", ssh_cmd);
+ return(0);
+ }
+#endif /* SSHBUILTIN */
+
+ if (!cmdgquo()) { /* COMMAND QUOTING OFF */
+ x = strlen(s); /* Just send the string literally */
+ xx = local ? ttol((CHAR *)s,x) : conxo(x,s);
+ return(success = (xx == x) ? 1 : 0);
+ }
+ quote = 0; /* Initialize backslash (\) quote */
+ obn = 0; /* Reset count */
+ obp = obuf; /* and pointers */
+
+ outagain:
+ while ((x = *s++)) { /* Loop through the string */
+ y = 0; /* Error code, 0 = no error. */
+ debug(F000,"dooutput","",x);
+ if (quote) { /* This character is quoted */
+#ifndef NOKVERBS
+ if (x == 'k' || x == 'K') { /* \k or \K */
+ extern struct keytab kverbs[];
+ extern int nkverbs;
+ extern char * keydefptr;
+ extern int keymac;
+ extern int keymacx;
+ int x, y, brace = 0;
+ int pause;
+ char * p, * b;
+ char kbuf[K_BUFLEN + 1]; /* Key verb name buffer */
+ char osendbuf[SEND_BUFLEN +1];
+ int sendndx = 0;
+
+ if (xxout(obuf,obn) < 0) /* Flush buffer */
+ goto outerr;
+ debug(F100,"OUTPUT KVERB","",0); /* Send a KVERB */
+ { /* Have K verb? */
+ if (!*s) {
+ break;
+ }
+/*
+ We assume that the verb name is {braced}, or it extends to the end of the
+ string, s, or it ends with a space, control character, or backslash.
+*/
+ p = kbuf; /* Copy verb name into local buffer */
+ x = 0;
+ while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
+ if (brace && *s == '}') {
+ break;
+ }
+ *p++ = *s++;
+ }
+ if (*s && !brace) /* If we broke because of \, etc, */
+ s--; /* back up so we get another look. */
+ brace = 0;
+ *p = NUL; /* Terminate. */
+ p = kbuf; /* Point back to beginning */
+ debug(F110,"dooutput kverb",p,0);
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ debug(F101,"dooutput lookup",0,y);
+ if (y > -1) {
+ if (sendndx) {
+ dooutput(osendbuf,cx);
+ sendndx = 0;
+ }
+ dokverb(VCMD,y);
+#ifndef NOSPL
+ } else { /* Is it a macro? */
+ y = mxlook(mactab,p,nmac);
+ if (y > -1) {
+ cmpush();
+ keymac = 1; /* Flag for key macro active */
+ keymacx = y; /* Key macro index */
+ keydefptr = s; /* Where to resume next time */
+ debug(F111,"dooutput mxlook",keydefptr,y);
+ parser(1);
+ cmpop();
+ }
+#endif /* NOSPL */
+ }
+ }
+ quote = 0;
+ continue;
+ } else
+#endif /* NOKVERBS */
+ if (outesc && (x == 'n' || x == 'N')) { /* \n or \N */
+ if (xxout(obuf,obn) < 0) /* Flush buffer */
+ goto outerr;
+ debug(F100,"OUTPUT NUL","",0); /* Send a NUL */
+ if (local)
+ ttoc(NUL);
+ else
+ conoc(NUL);
+ quote = 0;
+ continue;
+
+ } else if (outesc && (x == 'b' || x == 'B')) { /* \b or \B */
+
+ if (xxout(obuf,obn) < 0) /* Flush buffer first */
+ goto outerr;
+ debug(F100,"OUTPUT BREAK","",0);
+#ifndef NOLOCAL
+ ttsndb(); /* Send BREAK signal */
+#else
+ if (local)
+ ttoc(NUL);
+ else
+ conoc(NUL);
+#endif /* NOLOCAL */
+ quote = 0; /* Turn off quote flag */
+ continue; /* and not the b or B */
+#ifdef CK_LBRK
+ } else if (outesc && (x == 'l' || x == 'L')) { /* \l or \L */
+ if (xxout(obuf,obn) < 0) /* Flush buffer first */
+ goto outerr;
+ debug(F100,"OUTPUT Long BREAK","",0);
+#ifndef NOLOCAL
+ ttsndlb(); /* Send Long BREAK signal */
+#else
+ if (local)
+ ttoc(NUL);
+ else
+ conoc(NUL);
+#endif /* NOLOCAL */
+ quote = 0; /* Turn off quote flag */
+ continue; /* and not the l or L */
+#endif /* CK_LBRK */
+
+ } else if (x == CMDQ) { /* Backslash itself */
+ debug(F100,"OUTPUT CMDQ","",0);
+ xx = oboc(dopar(CMDQ)); /* Output the backslash. */
+ if (xx < 0)
+ goto outerr;
+ quote = 0;
+ continue;
+
+ } else { /* if \ not followed by special esc */
+ /* Note: Atari ST compiler won't allow macro call in "if ()" */
+ xx = oboc(dopar(CMDQ)); /* Output the backslash. */
+ if (xx < 0)
+ goto outerr;
+ quote = 0; /* Turn off quote flag */
+ }
+ } else if (x == CMDQ) { /* This is the quote character */
+ quote = 1; /* Go back and get next character */
+ continue; /* which is quoted */
+ }
+ xx = oboc(dopar((char)x)); /* Output this character */
+ debug(F111,"dooutput",obuf,obn);
+ if (xx < 0)
+ goto outerr;
+#ifdef COMMENT
+ if (seslog && duplex) { /* Log the character if log is on */
+ logchar((char)x);
+ }
+#endif /* COMMENT */
+ if (x == '\015') { /* String contains carriage return */
+ int stuff = -1, stuff2 = -1;
+ if (tnlm) { /* TERMINAL NEWLINE ON */
+ stuff = LF; /* Stuff LF */
+ }
+#ifdef TNCODE
+ /* TELNET NEWLINE ON/OFF/RAW */
+ if (is_tn) {
+ switch (TELOPT_ME(TELOPT_BINARY) ? /* NVT or BINARY */
+ tn_b_nlm :
+ tn_nlm
+ ) {
+ case TNL_CR:
+ break;
+ case TNL_CRNUL:
+ stuff2 = stuff;
+ stuff = NUL;
+ break;
+ case TNL_CRLF:
+ stuff2 = stuff;
+ stuff = LF;
+ break;
+ }
+ }
+#endif /* TNCODE */
+ if (stuff > -1) { /* Stuffing another character... */
+ xx = oboc(dopar((CHAR)stuff));
+ if (xx < 0)
+ goto outerr;
+#ifdef COMMENT
+ if (seslog && duplex) { /* Log stuffed char if appropriate */
+ logchar((char)stuff);
+ }
+#endif /* COMMENT */
+ }
+ if (stuff2 > -1) { /* Stuffing another character... */
+ xx = oboc(dopar((CHAR)stuff2));
+ if (xx < 0)
+ goto outerr;
+#ifdef COMMENT
+ if (seslog && duplex) { /* Log stuffed char if appropriate */
+ logchar((char)stuff2);
+ }
+#endif /* COMMENT */
+ }
+ if (xxout(obuf,obn) < 0) /* Flushing is required here! */
+ goto outerr;
+ }
+ }
+ if (cx == XXLNOUT) {
+ s = "\015";
+ cx = 0;
+ goto outagain;
+ }
+ if (quote == 1) /* String ended with backslash */
+ xx = oboc(dopar(CMDQ));
+
+ if (obn > 0) /* OUTPUT done */
+ if (xxout(obuf,obn) < 0) /* Flush the buffer if necessary. */
+ goto outerr;
+ return(1);
+
+outerr: /* OUTPUT command error handler */
+ if (msgflg) printf("?OUTPUT execution error\n");
+ return(0);
+
+/* Remove "local" OUTPUT macro defininitions */
+
+#ifdef COMMENT
+/* No more macros ... */
+#undef oboc
+#undef obfls
+#endif /* COMMENT */
+}
+#endif /* NOSPL */
+
+/* Display version herald and initial prompt */
+
+VOID
+herald() {
+ int x = 0, i;
+ extern int srvcdmsg;
+ extern char * cdmsgfile[];
+ char * ssl;
+ char * krb4;
+ char * krb5;
+
+#ifndef NOCMDL
+ extern char * bannerfile;
+ debug(F110,"herald bannerfile",bannerfile,0);
+ if (bannerfile) {
+ concb((char)escape);
+ if (dotype(bannerfile,1,0,0,NULL,0,NULL,0,0,NULL,0) > 0) {
+ debug(F111,"herald","srvcdmsg",srvcdmsg);
+ if (srvcdmsg) {
+ for (i = 0; i < 8; i++) {
+ debug(F111,"herald cdmsgfile[i]",cdmsgfile[i],i);
+ if (zchki(cdmsgfile[i]) > -1) {
+ printf("\n");
+ dotype(cdmsgfile[i],
+ xaskmore,0,0,NULL,0,NULL,0,0,NULL,0);
+ break;
+ }
+ }
+ }
+ return;
+ }
+ }
+#endif /* NOCMDL */
+
+#ifdef COMMENT
+ /* The following generates bad code in SCO compilers. */
+ /* Observed in both OSR5 and Unixware 2 -- after executing this */
+ /* statement when all conditions are false, x has a value of -32. */
+ if (noherald || quiet || bgset > 0 || (bgset != 0 && backgrd != 0))
+ x = 1;
+#else
+ x = 0;
+ if (noherald || quiet)
+ x = 1;
+ else if (bgset > 0)
+ x = 1;
+ else if (bgset < 0 && backgrd > 0)
+ x = 1;
+#endif /* COMMENT */
+
+ ssl = "";
+ krb4 = "";
+ krb5 = "";
+#ifdef CK_AUTHENTICATION
+#ifdef CK_SSL
+ ssl = "+SSL";
+#endif /* CK_SSL */
+#ifdef KRB4
+ krb4 = "+KRB4";
+#endif /* KRB4 */
+#ifdef KRB5
+ krb5 = "+KRB5";
+#endif /* KRB5 */
+#endif /* CK_AUTHENTICATION */
+
+ if (x == 0) {
+#ifdef datageneral
+ printf("%s, for%s\n",versio,ckxsys);
+#else
+#ifdef OSK
+ printf("%s, for%s\n",versio,ckxsys);
+#else
+#ifdef CK_64BIT
+ printf("%s, for%s%s%s%s (64-bit)\n\r",versio,ckxsys,ssl,krb4,krb5);
+#else
+ printf("%s, for%s%s%s%s\n\r",versio,ckxsys,ssl,krb4,krb5);
+#endif/* CK_64BIT */
+#endif /* OSK */
+#endif /* datageneral */
+ printf(" Copyright (C) 1985, %s,\n", ck_cryear);
+ printf(" Trustees of Columbia University in the City of New York.\n");
+#ifdef OS2
+ shoreg();
+#endif /* OS2 */
+
+ if (!quiet && !backgrd) {
+#ifdef COMMENT
+/* "Default file-transfer mode is AUTOMATIC" is useless information... */
+ char * s;
+ extern int xfermode;
+#ifdef VMS
+ s = "AUTOMATIC";
+#else
+ if (xfermode == XMODE_A) {
+ s = "AUTOMATIC";
+ } else {
+ s = gfmode(binary,1);
+ }
+ if (!s) s = "";
+#endif /* VMS */
+ if (*s)
+ printf("Default file-transfer mode is %s\n", s);
+#endif /* COMMENT */
+
+ debug(F111,"herald","srvcdmsg",srvcdmsg);
+ if (srvcdmsg) {
+ for (i = 0; i < 8; i++) {
+ debug(F111,"herald cdmsgfile[i]",cdmsgfile[i],i);
+ if (zchki(cdmsgfile[i]) > -1) {
+ printf("\n");
+ dotype(cdmsgfile[i],
+ xaskmore,0,0,NULL,0,NULL,0,0,NULL,0);
+ break;
+ }
+ }
+ }
+ printf("Type ? or HELP for help.\n");
+ }
+ }
+}
+
+/* G F M O D E -- Get File (transfer) Mode */
+
+char *
+gfmode(binary,upcase) int binary, upcase; {
+ char * s;
+ switch (binary) {
+ case XYFT_T: s = upcase ? "TEXT" : "text"; break;
+#ifdef VMS
+ case XYFT_B: s = upcase ? "BINARY FIXED" : "binary fixed"; break;
+ case XYFT_I: s = upcase ? "IMAGE" : "image"; break;
+ case XYFT_L: s = upcase ? "LABELED" : "labeled"; break;
+ case XYFT_U: s = upcase ? "BINARY UNDEF" : "binary undef"; break;
+#else
+#ifdef MAC
+ case XYFT_B: s = upcase ? "BINARY" : "binary"; break;
+ case XYFT_M: s = upcase ? "MACBINARY" : "macbinary"; break;
+#else
+ case XYFT_B: s = upcase ? "BINARY" : "binary"; break;
+#ifdef CK_LABELED
+ case XYFT_L: s = upcase ? "LABELED" : "labeled"; break;
+#endif /* CK_LABELED */
+#endif /* MAC */
+#endif /* VMS */
+ case XYFT_X: s = upcase ? "TENEX" : "tenex"; break;
+ default: s = "";
+ }
+ return(s);
+}
+
+#ifndef NOSPL
+static int
+isaa(s) char * s; { /* Is associative array */
+ char c;
+ int x;
+ if (!s) s = "";
+ if (!*s) return(0);
+ s++;
+ while ((c = *s++)) {
+ if (c == '<') {
+ x = strlen(s);
+ return ((*(s+x-1) == '>') ? 1 : 0);
+ }
+ }
+ return(0);
+}
+
+/* M L O O K -- Lookup the macro name in the macro table */
+
+/*
+ Call this way: v = mlook(table,word,n);
+
+ table - a 'struct mtab' table.
+ word - the target string to look up in the table.
+ n - the number of elements in the table.
+
+ The keyword table must be arranged in ascending alphabetical order, and
+ all letters must be lowercase.
+
+ Returns the table index, 0 or greater, if the name was found, or:
+
+ -3 if nothing to look up (target was null),
+ -2 if ambiguous,
+ -1 if not found.
+
+ A match is successful if the target matches a keyword exactly, or if
+ the target is a prefix of exactly one keyword. It is ambiguous if the
+ target matches two or more keywords from the table.
+*/
+int
+mlook(table,cmd,n) struct mtab table[]; char *cmd; int n; {
+ register int i;
+ int v, w, cmdlen = 0;
+ char c = 0, c1, * s;
+ if (!cmd) cmd = "";
+
+ for (s = cmd; *s; s++) cmdlen++; /* (instead of strlen) */
+ debug(F111,"MLOOK",cmd,cmdlen);
+
+ c1 = *cmd;
+ if (isupper(c1))
+ c1 = tolower(c1);
+ if (cmdlen < 1)
+ return(-3);
+
+/* Not null, look it up */
+
+ if (n < 12) { /* Not worth it for small tables */
+ i = 0;
+ } else { /* Binary search for where to start */
+ int lo = 0;
+ int hi = n;
+ int count = 0;
+ while (lo+2 < hi && ++count < 12) {
+ i = lo + ((hi - lo) / 2);
+ c = *(table[i].kwd);
+ if (isupper(c)) c = tolower(c);
+ if (c < c1) {
+ lo = i;
+ } else {
+ hi = i;
+ }
+ }
+ i = (c < c1) ? lo+1 : lo;
+ }
+ for ( ; i < n-1; i++) {
+ s = table[i].kwd;
+ if (!s) s = "";
+ if (!*s) continue; /* Empty table entry */
+ c = *s;
+ if (isupper(c)) c = tolower(c);
+ if (c1 != c) continue; /* First char doesn't match */
+ if (!ckstrcmp(s,cmd,-1,0)) /* Have exact match? */
+ return(i);
+ v = !ckstrcmp(s,cmd,cmdlen,0);
+ w = ckstrcmp(table[i+1].kwd,cmd,cmdlen,0);
+ if (v && w) /* Have abbreviated match? */
+ return(i);
+ if (v) /* Ambiguous? */
+ return(-2);
+ if (w > 0) /* Past our alphabetic area? */
+ return(-1);
+ }
+
+/* Last (or only) element */
+
+ if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0))
+ return(n-1);
+
+ return(-1);
+}
+
+/* mxlook is like mlook, but an exact full-length match is required */
+
+int
+mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
+ register int i;
+ int w, cmdlen = 0, one = 0;
+ register char c = 0, c1, * s;
+
+ if (!cmd) cmd = ""; /* Check args */
+
+ for (s = cmd; *s; s++) cmdlen++; /* (instead of strlen) */
+ debug(F111,"MXLOOK",cmd,cmdlen);
+
+ c1 = *cmd; /* First char of string to look up */
+ if (isupper(c1))
+ c1 = tolower(c1);
+ if (!*(cmd+1)) /* Special handling for 1-char names */
+ one = 1;
+
+ if (cmdlen < 1) /* Nothing to look up */
+ return(-3);
+
+ if (n < 12) { /* Not worth it for small tables */
+ i = 0;
+ } else { /* Binary search for where to start */
+ int lo = 0;
+ int hi = n;
+ int count = 0;
+ while (lo+2 < hi && ++count < 12) {
+ i = lo + ((hi - lo) / 2);
+ c = *(table[i].kwd);
+ if (isupper(c)) c = tolower(c);
+ if (c < c1) {
+ lo = i;
+ } else {
+ hi = i;
+ }
+ }
+ i = (c < c1) ? lo+1 : lo;
+ }
+ for ( ; i < n; i++) { /* Look thru table */
+ s = table[i].kwd; /* This entry */
+ if (!s) s = "";
+ if (!*s) continue; /* Empty table entry */
+ c = *s;
+ if (isupper(c)) c = tolower(c);
+ if (c1 != c) continue; /* First char doesn't match */
+ if (one) { /* Name is one char long */
+ if (!*(s+1))
+ return(i); /* So is table entry */
+ }
+#ifdef COMMENT
+ if (((int)strlen(s) == cmdlen) &&
+ (!ckstrcmp(s,cmd,cmdlen,0))) return(i);
+#else
+ w = ckstrcmp(s,cmd,-1,0);
+ if (!w) return(i);
+ if (w > 0) return(-1);
+#endif /* COMMENT */
+ }
+ return(-1);
+}
+
+/* mxxlook is like mxlook, but case-sensitive */
+
+int
+mxxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
+ int i, cmdlen;
+ if (!cmd) cmd = "";
+ if (((cmdlen = strlen(cmd)) < 1) || (n < 1)) return(-3);
+ /* debug(F111,"mxxlook target",cmd,n); */
+ for (i = 0; i < n; i++) {
+ if (((int)strlen(table[i].kwd) == cmdlen) &&
+ (!strncmp(table[i].kwd,cmd,cmdlen)))
+ return(i);
+ }
+ return(-1);
+}
+
+static int
+traceval(nam, val) char * nam, * val; { /* For TRACE command */
+ if (val)
+ printf(">>> %s: \"%s\"\n", nam, val);
+ else
+ printf(">>> %s: (undef)\n", nam);
+ return(0);
+}
+
+#ifdef USE_VARLEN /* Not used */
+
+/* V A R L E N -- Get length of variable's value.
+
+ Given a variable name, return the length of its definition or 0 if the
+ variable is not defined. If it is defined, set argument s to point to its
+ definition. Otherwise set s to NULL.
+*/
+int
+varlen(nam,s) char *nam; char **s; { /* Length of value of variable */
+ int x, z;
+ char *p = NULL, c;
+
+ *s = NULL;
+ if (!nam) return(0); /* Watch out for null pointer */
+ if (*nam == CMDQ) {
+ nam++;
+ if (*nam == '%') { /* If it's a variable name */
+ if (!(c = *(nam+1))) return(0); /* Get letter or digit */
+ p = (char *)0; /* Initialize value pointer */
+ if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */
+ p = m_arg[maclvl][c - '0']; /* Pointer from macro-arg table */
+ } else { /* It's a global variable */
+ if (c < 33 || c > GVARS) return(0);
+ p = g_var[c]; /* Get pointer from global-var table */
+ }
+ } else if (*nam == '&') { /* An array reference? */
+ char **q;
+ if (arraynam(nam,&x,&z) < 0) /* If syntax is bad */
+ return(-1); /* return -1. */
+ x -= ARRAYBASE; /* Convert name to number. */
+ if ((q = a_ptr[x]) == NULL) /* If array not declared, */
+ return(0); /* return -2. */
+ if (z > a_dim[x]) /* If subscript out of range, */
+ return(0); /* return -3. */
+ p = q[z];
+ }
+ } else { /* Macro */
+ z = isaa(nam);
+ x = z ? mxxlook(mactab,nam,nmac) : mlook(mactab,nam,nmac);
+ if (x < 0)
+ return(0);
+ p = mactab[x].mval;
+ }
+ if (p)
+ *s = p;
+ else
+ p = "";
+ return((int)strlen(p));
+}
+#endif /* USE_VARLEN */
+
+/*
+ This routine is for the benefit of those compilers that can't handle
+ long string constants or continued lines within them. Long predefined
+ macros like FOR, WHILE, and XIF have their contents broken up into
+ arrays of string pointers. This routine concatenates them back into a
+ single string again, and then calls the real addmac() routine to enter
+ the definition into the macro table.
+*/
+int
+addmmac(nam,s) char *nam, *s[]; { /* Add a multiline macro definition */
+ int i, x, y; char *p;
+ x = 0; /* Length counter */
+ for (i = 0; (y = (int)strlen(s[i])) > 0; i++) { /* Add up total length */
+ debug(F111,"addmmac line",s[i],y);
+ x += y;
+ }
+ debug(F101,"addmmac lines","",i);
+ debug(F101,"addmmac loop exit","",y);
+ debug(F111,"addmmac length",nam,x);
+ if (x < 0) return(-1);
+
+ p = malloc(x+1); /* Allocate space for all of it. */
+ if (!p) {
+ printf("?addmmac malloc error: %s\n",nam);
+ debug(F110,"addmmac malloc error",nam,0);
+ return(-1);
+ }
+ *p = '\0'; /* Start off with null string. */
+ for (i = 0; *s[i]; i++) /* Concatenate them all together. */
+ ckstrncat(p,s[i],x+1);
+ y = (int)strlen(p); /* Final precaution. */
+ debug(F111,"addmmac constructed string",p,y);
+ if (y == x) {
+ y = addmac(nam,p); /* Add result to the macro table. */
+ } else {
+ debug(F100,"addmmac length mismatch","",0);
+ printf("\n!addmmac internal error!\n");
+ y = -1;
+ }
+ free(p); /* Free the temporary copy. */
+ return(y);
+}
+
+/* Here is the real addmac routine. */
+
+/* Returns -1 on failure, macro table index >= 0 on success. */
+
+int mtchanged = 0;
+
+int
+addmac(nam,def) char *nam, *def; { /* Add a macro to the macro table */
+ int i, x, y, z, namlen, deflen, flag = 0;
+ int replacing = 0, deleting = 0;
+ char * p = NULL, c, *s;
+ extern int tra_asg; int tra_tmp;
+
+ if (!nam) return(-1);
+ if (!*nam) return(-1);
+
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else /* IKSDCONF */
+ 1
+#endif /* IKSDCONF */
+ ) {
+ if (!ckstrcmp("on_exit",nam,-1,0) ||
+ !ckstrcmp("on_logout",nam,-1,0))
+ return(-1);
+ }
+#endif /* IKSD */
+
+ namlen = 0;
+ p = nam;
+ while (*p++) namlen++; /* (instead of strlen) */
+
+ tra_tmp = tra_asg; /* trace... */
+ debug(F111,"addmac nam",nam,namlen);
+ if (!def) { /* Watch out for null pointer */
+ deflen = 0;
+ debug(F111,"addmac def","(null pointer)",deflen);
+ } else {
+ deflen = 0;
+ p = def;
+ while (*p++) deflen++; /* (instead of strlen) */
+ debug(F010,"addmac def",def,0);
+ }
+#ifdef USE_VARLEN /* NOT USED */
+ /* This does not boost performance much because varlen() does a lot */
+ x = varlen(nam,&s);
+ if (x > 0 && x >= deflen) {
+ strcpy(s,def); /* NOT USED */
+ flag = 1;
+ p = s;
+ }
+#endif /* USE_VARLEN */
+
+ if (*nam == CMDQ) nam++; /* Backslash quote? */
+ if (*nam == '%') { /* Yes, if it's a variable name, */
+ if (!(c = *(nam + 1))) return(-1); /* Variable name letter or digit */
+ if (!flag) {
+ tra_asg = 0;
+ delmac(nam,0); /* Delete any old value. */
+ tra_asg = tra_tmp;
+ }
+ if (deflen < 1) { /* Null definition */
+ p = NULL; /* Better not malloc or strcpy! */
+ } else if (!flag) { /* A substantial definition */
+ p = malloc(deflen + 1); /* Allocate space for it */
+ if (!p) {
+ printf("?addmac malloc error 2\n");
+ return(-1);
+ } else strcpy(p,def); /* Copy def into new space (SAFE) */
+ }
+
+ /* Now p points to the definition, or is a null pointer */
+
+ if (c >= '0' && c <= '9') { /* \%0-9 variable */
+ if (maclvl < 0) { /* Are we calling or in a macro? */
+ g_var[c] = p; /* No, it's top level one */
+ makestr(&(toparg[c - '0']),p); /* Take care \&_[] too */
+ } else { /* Yes, it's a macro argument */
+ m_arg[maclvl][c - '0'] = p; /* Assign the value */
+ makestr(&(m_xarg[maclvl][c - '0']),p); /* And a copy here */
+ }
+ } else { /* It's a \%a-z variable */
+ if (c < 33 || (unsigned int)c > GVARS) return(-1);
+ if (isupper(c)) c = (char) tolower(c);
+ g_var[c] = p; /* Put pointer in global-var table */
+ }
+ if (tra_asg) traceval(nam,p);
+ return(0);
+ } else if (*nam == '&') { /* An array reference? */
+ char **q = NULL;
+ int rc = 0;
+ if ((y = arraynam(nam,&x,&z)) < 0) /* If syntax is bad */
+ return(-1); /* return -1. */
+ if (chkarray(x,z) < 0) /* If array not declared or */
+ rc = -2; /* subscript out of range, ret -2 */
+ if (!flag) {
+ tra_asg = 0;
+ delmac(nam,0); /* Delete any old value. */
+ tra_asg = tra_tmp;
+ }
+ x -= ARRAYBASE; /* Convert name letter to index. */
+ if (x > 'z' - ARRAYBASE + 1)
+ rc = -1;
+ if (rc != -1) {
+ if ((q = a_ptr[x]) == NULL) /* If array not declared, */
+ return(-3); /* return -3. */
+ }
+ if (rc < 0)
+ return(rc);
+ if (!flag) {
+ if (deflen > 0) {
+ if ((p = malloc(deflen+1)) == NULL) { /* Allocate space */
+ printf("addmac macro error 7: %s\n",nam);
+ return(-4); /* for new def, return -4 on fail. */
+ }
+ strcpy(p,def); /* Copy def into new space (SAFE). */
+ } else p = NULL;
+ }
+ q[z] = p; /* Store pointer to it. */
+ if (x == 0) { /* Arg vector array */
+ if (z >= 0 && z <= 9) { /* Copy values to corresponding */
+ if (maclvl < 0) { /* \%1..9 variables. */
+ makestr(&(toparg[z]),p);
+ } else {
+ makestr(&(m_arg[maclvl][z]),p);
+ }
+ }
+ }
+ if (tra_asg) traceval(nam,p);
+ return(0); /* Done. */
+ }
+
+/* Not a macro argument or a variable, so it's a macro definition */
+
+#ifdef USE_VARLEN
+ if (flag) {
+ if (tra_asg) traceval(nam,p);
+ return(0);
+ }
+#endif /* USE_VARLEN */
+ x = isaa(nam) ? /* If it's an associative array */
+ mxxlook(mactab,nam,nmac) : /* look it up this way */
+ mxlook(mactab,nam,nmac); /* otherwise this way. */
+ if (x > -1) { /* If found... */
+ if (deflen > 0) /* and a new definition was given */
+ replacing = 1; /* we're replacing */
+ else /* otherwise */
+ deleting = 1; /* we're deleting */
+ }
+ if (deleting) { /* Deleting... */
+ if (delmac(nam,0) < 0)
+ return(-1);
+ mtchanged++;
+ if (tra_asg) traceval(nam,p);
+ return(0);
+ } else if (deflen < 1) /* New macro with no definition */
+ return(0); /* Nothing to do. */
+
+ if (replacing) { /* Replacing an existing macro */
+ if (mactab[x].mval) { /* If it currently has a definition, */
+ free(mactab[x].mval); /* free it. */
+ mactab[x].mval = NULL;
+ }
+ mtchanged++;
+ y = x; /* Replacement index. */
+
+ } else { /* Adding a new macro... */
+ char c1, c2; /* Use fast lookup to find the */
+ c1 = *nam; /* alphabetical slot. */
+ if (isupper(c1)) c1 = (char) tolower(c1);
+
+ if (nmac < 5) { /* Not worth it for small tables */
+ y = 0;
+ } else { /* First binary search to find */
+ int lo = 0; /* where to start */
+ int hi = nmac;
+ int count = 0;
+ char c = 0;
+ while (lo+2 < hi && ++count < 12) {
+ y = lo + ((hi - lo) / 2);
+ c = *(mactab[y].kwd);
+ if (isupper(c)) c = (char) tolower(c);
+ if (c < c1) {
+ lo = y;
+ } else {
+ hi = y;
+ }
+ }
+ y = (c < c1) ? lo+1 : lo;
+ }
+ /* Now search linearly from starting location */
+ for ( ; y < MAC_MAX && mactab[y].kwd != NULL; y++) {
+ c2 = *(mactab[y].kwd);
+ if (isupper(c2)) c2 = (char) tolower(c2);
+ if (c1 > c2)
+ continue;
+ if (c1 < c2)
+ break;
+ if (ckstrcmp(nam,mactab[y].kwd,-1,0) <= 0)
+ break;
+ }
+ if (y == MAC_MAX) { /* Macro table is full. */
+ debug(F101,"addmac table overflow","",y);
+ printf("?Macro table overflow\n");
+ return(-1);
+ }
+ if (mactab[y].kwd != NULL) { /* Must insert */
+ for (i = nmac; i > y; i--) { /* Move the rest down one slot */
+ mactab[i].kwd = mactab[i-1].kwd;
+ mactab[i].mval = mactab[i-1].mval;
+ mactab[i].flgs = mactab[i-1].flgs;
+ }
+ }
+ mtchanged++;
+ p = malloc(namlen + 1); /* Allocate space for name */
+ if (!p) {
+ printf("?Addmac: Out of memory - \"%s\"\n",nam);
+ return(-1);
+ }
+ strcpy(p,nam); /* Copy name into new space (SAFE) */
+ mactab[y].kwd = p; /* Add pointer to table */
+ }
+ if (deflen > 0) { /* If we have a definition */
+ p = malloc(deflen + 1); /* Get space */
+ if (p == NULL) {
+ printf("?Space exhausted - \"%s\"\n", nam);
+ if (mactab[y].kwd) {
+ free(mactab[y].kwd);
+ mactab[y].kwd = NULL;
+ }
+ return(-1);
+ } else {
+ strcpy(p,def); /* Copy the definition (SAFE) */
+ }
+ } else { /* definition is empty */
+ p = NULL;
+ }
+ mactab[y].mval = p; /* Macro points to definition */
+ mactab[y].flgs = 0; /* No flags */
+ if (!replacing) /* If new macro */
+ nmac++; /* count it */
+ if (tra_asg) traceval(nam,p);
+ return(y);
+}
+
+int
+xdelmac(x) int x; { /* Delete a macro given its index */
+ int i;
+ extern int tra_asg;
+ if (x < 0) return(x);
+ if (tra_asg)
+ traceval(mactab[x].kwd,NULL);
+
+ if (mactab[x].kwd) { /* Free the storage for the name */
+ free(mactab[x].kwd);
+ mactab[x].kwd = NULL;
+ }
+ if (mactab[x].mval) { /* and for the definition */
+ free(mactab[x].mval);
+ mactab[x].mval = NULL;
+ }
+ for (i = x; i < nmac; i++) { /* Now move up the others. */
+ mactab[i].kwd = mactab[i+1].kwd;
+ mactab[i].mval = mactab[i+1].mval;
+ mactab[i].flgs = mactab[i+1].flgs;
+ }
+ nmac--; /* One less macro */
+
+ mactab[nmac].kwd = NULL; /* Delete last item from table */
+ mactab[nmac].mval = NULL;
+ mactab[nmac].flgs = 0;
+ mtchanged++;
+ return(0);
+}
+
+int
+delmac(nam,exact) char *nam; int exact; { /* Delete the named macro */
+ int x, z;
+ char *p, c;
+ extern int tra_asg;
+
+ if (!nam) return(0); /* Watch out for null pointer */
+ debug(F110,"delmac nam",nam,0);
+#ifdef IKSD
+ if ( inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else /* IKSDCONF */
+ 1
+#endif /* IKSDCONF */
+ ) {
+ if (!ckstrcmp("on_exit",nam,-1,0) ||
+ !ckstrcmp("on_logout",nam,-1,0))
+ return(-1);
+ }
+#endif /* IKSD */
+
+ if (*nam == CMDQ) nam++;
+ if (*nam == '%') { /* If it's a variable name */
+ if (!(c = *(nam+1))) return(0); /* Get variable name letter or digit */
+ p = (char *)0; /* Initialize value pointer */
+ if (maclvl < 0 && c >= '0' && c <= '9') { /* Top-level digit? */
+ p = toparg[c - '0'];
+ if (p) if (p != g_var[c]) {
+ free(p);
+ toparg[c - '0'] = NULL;
+ }
+ p = g_var[c];
+ g_var[c] = NULL; /* Zero the table entry */
+ } else if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */
+ p = m_xarg[maclvl][c - '0'];
+ if (p) if (p != g_var[c]) {
+ free(p);
+ m_xarg[maclvl][c - '0'] = NULL;
+ }
+ p = m_arg[maclvl][c - '0']; /* Get pointer from macro-arg table */
+ m_arg[maclvl][c - '0'] = NULL; /* Zero the table pointer */
+ } else { /* It's a global variable */
+ if (c < 33 || (unsigned int)c > GVARS) return(0);
+ p = g_var[c]; /* Get pointer from global-var table */
+ g_var[c] = NULL; /* Zero the table entry */
+ }
+ if (p) {
+ debug(F010,"delmac def",p,0);
+ free(p); /* Free the storage */
+ p = NULL;
+ } else debug(F110,"delmac def","(null pointer)",0);
+ if (tra_asg) traceval(nam,NULL);
+ return(0);
+ }
+ if (*nam == '&') { /* An array reference? */
+ char **q;
+ if (arraynam(nam,&x,&z) < 0) /* If syntax is bad */
+ return(-1); /* return -1. */
+ x -= ARRAYBASE; /* Convert name to number. */
+ if ((q = a_ptr[x]) == NULL) /* If array not declared, */
+ return(-2); /* return -2. */
+ if (z > a_dim[x]) /* If subscript out of range, */
+ return(-3); /* return -3. */
+ if (q[z]) { /* If there is an old value, */
+ debug(F010,"delmac def",q[z],0);
+ if (x != 0) /* Macro arg vector is just a copy */
+ free(q[z]); /* Others are real so free them */
+ q[z] = NULL;
+ if (x == 0) { /* Arg vector array */
+ if (z >= 0 && z <= 9) { /* Copy values to corresponding */
+ if (maclvl < 0) { /* \%1..9 variables. */
+ makestr(&(toparg[z]),NULL);
+ } else {
+ makestr(&(m_arg[maclvl][z]),NULL);
+ }
+ }
+ }
+ if (tra_asg) traceval(nam,NULL);
+ } else debug(F010,"delmac def","(null pointer)",0);
+ }
+
+ /* Not a variable or an array, so it must be a macro. */
+
+ z = isaa(nam);
+ debug(F111,"delmac isaa",nam,z);
+ debug(F111,"delmac exact",nam,exact);
+ x = z ? mxxlook(mactab,nam,nmac) :
+ exact ? mxlook(mactab,nam,nmac) :
+ mlook(mactab,nam,nmac);
+ if (x < 0) {
+ debug(F111,"delmac mlook",nam,x);
+ return(x);
+ }
+ return(xdelmac(x));
+}
+
+VOID
+initmac() { /* Init macro & variable tables */
+ int i, j, x;
+
+ nmac = 0; /* No macros */
+ for (i = 0; i < MAC_MAX; i++) { /* Initialize the macro table */
+ mactab[i].kwd = NULL;
+ mactab[i].mval = NULL;
+ mactab[i].flgs = 0;
+ }
+ mtchanged++;
+ x = (MAXARGLIST + 1) * sizeof(char **);
+ for (i = 0; i < MACLEVEL; i++) { /* Init the macro argument tables */
+ m_xarg[i] = (char **) malloc(x);
+ mrval[i] = NULL; /* Macro return value */
+ /* Pointer to entire argument vector, level i, for \&_[] array */
+ for (j = 0; j <= MAXARGLIST; j++) { /* Macro argument list */
+ if (j < 10) /* For the \%0..\%9 variables */
+ m_arg[i][j] = NULL; /* Pointer to arg j, level i. */
+ if (m_xarg[i]) /* For \&_[] - all args. */
+ m_xarg[i][j] = NULL;
+ }
+ }
+ for (i = 0; i < GVARS; i++) { /* And the global variables table */
+ g_var[i] = NULL;
+ }
+ /* And the table of arrays */
+ for (i = 0; i < (int) 'z' - ARRAYBASE + 1; i++) {
+ a_ptr[i] = (char **) NULL; /* Null pointer for each */
+ a_dim[i] = 0; /* and a dimension of zero */
+ a_link[i] = -1;
+ for (j = 0; j < CMDSTKL; j++) {
+ aa_ptr[j][i] = (char **) NULL;
+ aa_dim[j][i] = 0;
+ }
+ }
+}
+
+int
+popclvl() { /* Pop command level, return cmdlvl */
+ extern int tra_cmd;
+ struct localvar * v;
+ int i, topcmd;
+ debug(F101,"popclvl cmdlvl","",cmdlvl);
+ if (cmdlvl > 0) {
+ if ((v = localhead[cmdlvl])) { /* Did we save any variables? */
+ while (v) { /* Yes */
+ if (v->lv_value) /* Copy old ones back */
+ addmac(v->lv_name,v->lv_value);
+ else
+ delmac(v->lv_name,1);
+ v = v->lv_next;
+ }
+ freelocal(cmdlvl); /* Free local storage */
+ }
+ /* Automatic arrays do not use the localhead list */
+
+ for (i = 0; i < 28; i++) { /* Free any local arrays */
+ if (aa_ptr[cmdlvl][i]) { /* Does this one exist? */
+ dclarray((char)(i+ARRAYBASE),-1); /* Destroy global one */
+ a_ptr[i] = aa_ptr[cmdlvl][i];
+ a_dim[i] = aa_dim[cmdlvl][i];
+ aa_ptr[cmdlvl][i] = (char **)NULL;
+ aa_dim[cmdlvl][i] = 0;
+ } else if (aa_dim[cmdlvl][i] == -23) { /* Secret code */
+ dclarray((char)(i+ARRAYBASE),-1); /* (see pusharray()) */
+ aa_ptr[cmdlvl][i] = (char **)NULL;
+ aa_dim[cmdlvl][i] = 0;
+ }
+
+ /* Otherwise do nothing - it is a local array that was declared */
+ /* at a level above this one so leave it alone. */
+ }
+ }
+ if (cmdlvl < 1) { /* If we're already at top level */
+ cmdlvl = 0; /* just make sure all the */
+ tlevel = -1; /* stack pointers are set right */
+ maclvl = -1; /* and return */
+ } else if (cmdstk[cmdlvl].src == CMD_TF) { /* Reading from TAKE file? */
+ debug(F101,"popclvl tlevel","",tlevel);
+ if (tlevel > -1) { /* Yes, */
+ fclose(tfile[tlevel]); /* close it */
+
+ if (tra_cmd)
+ printf("[%d] -F: \"%s\"\n",cmdlvl,tfnam[tlevel]);
+ debug(F111,"CMD -F",tfnam[tlevel],cmdlvl);
+ if (tfnam[tlevel]) { /* free storage for name */
+ free(tfnam[tlevel]);
+ tfnam[tlevel] = NULL;
+ }
+ tlevel--; /* and pop take level */
+ cmdlvl--; /* and command level */
+ quiet = xquiet[cmdlvl];
+ vareval = xvarev[cmdlvl];
+ } else
+ tlevel = -1;
+ } else if (cmdstk[cmdlvl].src == CMD_MD) { /* In a macro? */
+ topcmd = lastcmd[maclvl];
+ debug(F101,"popclvl maclvl","",maclvl);
+ if (maclvl > -1) { /* Yes, */
+#ifdef COMMENT
+ int i;
+ char **q;
+#endif /* COMMENT */
+ macp[maclvl] = ""; /* set macro pointer to null string */
+ *cmdbuf = '\0'; /* clear the command buffer */
+
+ if ((maclvl > 0) && /* 2 May 1999 */
+ (m_arg[maclvl-1][0]) &&
+ (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_for",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_whi",4)) &&
+ mrval[maclvl+1]) {
+ makestr(&(mrval[maclvl-1]),mrval[maclvl+1]);
+ }
+ if (maclvl+1 < MACLEVEL) {
+ if (mrval[maclvl+1]) { /* Free any deeper return values. */
+ free(mrval[maclvl+1]);
+ mrval[maclvl+1] = NULL;
+ }
+ }
+ if (tra_cmd)
+ printf("[%d] -M: \"%s\"\n",cmdlvl,m_arg[cmdstk[cmdlvl].lvl][0]);
+ debug(F111,"CMD -M",m_arg[cmdstk[cmdlvl].lvl][0],cmdlvl);
+
+ maclvl--; /* Pop macro level */
+ cmdlvl--; /* and command level */
+ debug(F101,"popclvl mac new maclvl","",maclvl);
+ debug(F010,"popclvl mac mrval[maclvl+1]",mrval[maclvl+2],0);
+
+ quiet = xquiet[cmdlvl];
+ vareval = xvarev[cmdlvl];
+ if (maclvl > -1) {
+ a_ptr[0] = m_xarg[maclvl];
+ a_dim[0] = n_xarg[maclvl] - 1;
+ debug(F111,"a_dim[0]","B",a_dim[0]);
+ } else {
+ a_ptr[0] = topxarg;
+ a_dim[0] = topargc - 1;
+ debug(F111,"a_dim[0]","C",a_dim[0]);
+ }
+ } else {
+ maclvl = -1;
+ }
+#ifndef NOSEXP
+ debug(F101,"popclvl topcmd","",topcmd);
+ if (topcmd == XXSEXP) {
+ extern char * sexpval;
+ makestr(&(mrval[maclvl+1]),sexpval);
+ }
+#endif /* NOSEXP */
+ } else {
+ cmdlvl--;
+ }
+ debug(F101,"popclvl cmdlvl","",cmdlvl);
+ if (prstring[cmdlvl]) {
+ cmsetp(prstring[cmdlvl]);
+ makestr(&(prstring[cmdlvl]),NULL);
+ }
+#ifndef MAC
+ if (cmdlvl < 1 || xcmdsrc == CMD_KB) { /* If at prompt */
+ setint();
+ concb((char)escape); /* Go into cbreak mode */
+ }
+#endif /* MAC */
+ xcmdsrc = cmdstk[cmdlvl].src;
+ debug(F101,"popclvl xcmdsrc","",xcmdsrc);
+ debug(F101,"popclvl tlevel","",tlevel);
+ return(cmdlvl < 1 ? 0 : cmdlvl); /* Return command level */
+}
+#else /* No script programming language */
+int popclvl() { /* Just close current take file. */
+ if (tlevel > -1) { /* if any... */
+ if (tfnam[tlevel]) {
+ free(tfnam[tlevel]);
+ tfnam[tlevel] = NULL;
+ }
+ fclose(tfile[tlevel--]);
+ }
+ if (tlevel == -1) { /* And if back at top level */
+ setint();
+ concb((char)escape); /* and go back into cbreak mode. */
+ }
+ xcmdsrc = tlevel > -1 ? CMD_TF : 0;
+ return(tlevel + 1);
+}
+#endif /* NOSPL */
+
+
+#ifndef NOSPL
+static int
+iseom(m) char * m; { /* Test if at end of macro def */
+ if (!m)
+ m = "";
+ debug(F111,"iseom",m,maclvl);
+ while (*m) {
+ /* Anything but Space and Comma means more macro is left */
+ if ((*m > SP) && (*m != ',')) {
+ debug(F111,"iseom return",m,0);
+ return(0);
+ }
+ m++;
+ }
+ debug(F111,"iseom return",m,1);
+ return(1); /* Nothing left */
+}
+#endif /* NOSPL */
+
+/* Pop all command levels that can be popped */
+
+int
+prepop() {
+ if (cmdlvl > 0) { /* If command level is > 0 and... */
+ while (
+#ifndef NOSPL
+ ((cmdstk[cmdlvl].src == CMD_TF) && /* Command source is file */
+#endif /* NOSPL */
+ (tlevel > -1) &&
+ feof(tfile[tlevel])) /* And at end of file... */
+#ifndef NOSPL
+ /* Or command source is macro... */
+ || ((cmdstk[cmdlvl].src == CMD_MD) &&
+ (maclvl > -1) &&
+ iseom(macp[maclvl]))) /* and at end of macro, then... */
+#endif /* NOSPL */
+ {
+ popclvl(); /* pop command level. */
+ }
+ }
+ return(cmdlvl < 1 ? 0 : cmdlvl); /* Return command level */
+}
+
+/* STOP - get back to C-Kermit prompt, no matter where from. */
+
+int
+dostop() {
+ extern int cmddep;
+ while (popclvl()) ; /* Pop all macros & take files */
+#ifndef NOSPL
+ if (cmddep > -1) /* And all recursive cmd pkg invocations */
+ while (cmpop() > -1) ;
+#endif /* NOSPL */
+ cmini(ckxech); /* Clear the command buffer. */
+ return(0);
+}
+
+/* Close the given log */
+
+int
+doclslog(x) int x; {
+ int y;
+ switch (x) {
+#ifdef DEBUG
+ case LOGD:
+ if (deblog <= 0) {
+ printf("?Debugging log wasn't open\n");
+ return(0);
+ }
+ debug(F100,"Debug Log Closed","",0L);
+ *debfil = '\0';
+ deblog = 0;
+ return(zclose(ZDFILE));
+#endif /* DEBUG */
+
+#ifndef NOXFER
+ case LOGP:
+ if (pktlog <= 0) {
+ printf("?Packet log wasn't open\n");
+ return(0);
+ }
+ *pktfil = '\0';
+ pktlog = 0;
+ return(zclose(ZPFILE));
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ case LOGS:
+ if (seslog <= 0) {
+ printf("?Session log wasn't open\n");
+ return(0);
+ }
+ *sesfil = '\0';
+ setseslog(0);
+ return(zclose(ZSFILE));
+#endif /* NOLOCAL */
+
+#ifdef TLOG
+ case LOGT: {
+#ifdef IKSD
+ extern int iklogopen, xferlog;
+#endif /* IKSD */
+ if (tralog <= 0
+#ifdef IKSD
+ && !iklogopen
+#endif /* IKSD */
+ ) {
+ if (msgflg)
+ printf("?Transaction log wasn't open\n");
+ return(0);
+ }
+#ifdef IKSD
+ if (iklogopen && !inserver) {
+ close(xferlog);
+ iklogopen = 0;
+ }
+#endif /* IKSD */
+ if (tralog) {
+ tlog(F100,"Transaction Log Closed","",0L);
+ zclose(ZTFILE);
+ }
+ *trafil = '\0';
+ tralog = 0;
+ return(1);
+ }
+#endif /* TLOG */
+
+#ifdef CKLOGDIAL
+ case LOGM:
+ if (dialog <= 0) {
+ if (msgflg) printf("?Connection log wasn't open\n");
+ return(0);
+ }
+ *diafil = '\0';
+ dialog = 0;
+ return(zclose(ZDIFIL));
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ case LOGW: /* WRITE file */
+ case LOGR: /* READ file */
+ y = (x == LOGR) ? ZRFILE : ZWFILE;
+ if (chkfn(y) < 1) /* If no file to close */
+ return(1); /* succeed silently. */
+ return(zclose(y)); /* Otherwise, close the file. */
+#endif /* NOSPL */
+
+ default:
+ printf("\n?Unexpected log designator - %d\n", x);
+ return(0);
+ }
+}
+
+static int slc = 0; /* Screen line count */
+
+char *
+showstring(s) char * s; {
+ return(s ? s : "(null)");
+}
+
+char *
+showoff(x) int x; {
+ return(x ? "on" : "off");
+}
+
+char *
+showooa(x) int x; {
+ switch (x) {
+ case SET_OFF: return("off");
+ case SET_ON: return("on");
+ case SET_AUTO: return("automatic");
+ default: return("(unknown)");
+ }
+}
+
+#ifdef GEMDOS
+isxdigit(c) int c; {
+ return(isdigit(c) ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F'));
+}
+#endif /* GEMDOS */
+
+#ifndef NOSETKEY
+#ifdef OS2
+static struct keytab shokeytab[] = { /* SHOW KEY modes */
+ "all", 1, 0,
+ "one", 0, 0
+};
+static int nshokey = (sizeof(shokeytab) / sizeof(struct keytab));
+
+#define SHKEYDEF TT_MAX+5
+struct keytab shokeymtab[] = {
+ "aaa", TT_AAA, CM_INV, /* AnnArbor */
+ "adm3a", TT_ADM3A, 0, /* LSI ADM-3A */
+ "adm5", TT_ADM5, 0, /* LSI ADM-5 */
+ "aixterm", TT_AIXTERM, 0, /* IBM AIXterm */
+ "annarbor", TT_AAA, 0, /* AnnArbor */
+ "ansi-bbs", TT_ANSI, 0, /* ANSI.SYS (BBS) */
+ "at386", TT_AT386, 0, /* Unixware ANSI */
+ "avatar/0+", TT_ANSI, 0, /* AVATAR/0+ */
+ "ba80", TT_BA80, 0, /* Nixdorf BA80 */
+ "be", TT_BEOS, CM_INV|CM_ABR,
+ "beos-ansi", TT_BEOS, CM_INV, /* BeOS ANSI */
+ "beterm", TT_BEOS, 0, /* BeOS Console */
+ "d200", TT_DG200, CM_INV|CM_ABR, /* Data General DASHER 200 */
+ "d210", TT_DG210, CM_INV|CM_ABR, /* Data General DASHER 210 */
+ "d217", TT_DG217, CM_INV|CM_ABR, /* Data General DASHER 217 */
+ "default", SHKEYDEF, 0,
+ "dg200", TT_DG200, 0, /* Data General DASHER 200 */
+ "dg210", TT_DG210, 0, /* Data General DASHER 210 */
+ "dg217", TT_DG217, 0, /* Data General DASHER 217 */
+ "emacs", TT_KBM_EMACS, 0, /* Emacs mode */
+ "h19", TT_H19, CM_INV, /* Heath-19 */
+ "heath19", TT_H19, 0, /* Heath-19 */
+ "hebrew", TT_KBM_HEBREW, 0, /* Hebrew mode */
+ "hft", TT_HFT, 0, /* IBM HFT */
+ "hp2621a", TT_HP2621, 0, /* HP 2621A */
+ "hpterm", TT_HPTERM, 0, /* HP TERM */
+ "hz1500", TT_HZL1500, 0, /* Hazeltine 1500 */
+ "ibm3151", TT_IBM31, 0, /* IBM 3101-xx,3161 */
+ "linux", TT_LINUX, 0, /* Linux */
+ "qansi", TT_QANSI, 0, /* QNX ANSI */
+ "qnx", TT_QNX, 0, /* QNX */
+ "russian", TT_KBM_RUSSIAN, 0, /* Russian mode */
+ "scoansi", TT_SCOANSI, 0, /* SCO ANSI */
+ "sni-97801", TT_97801, 0, /* Sinix 97801 */
+ "sun", TT_SUN, 0, /* Sun Console */
+#ifdef OS2PM
+#ifdef COMMENT
+ "tek4014", TT_TEK40, 0,
+#endif /* COMMENT */
+#endif /* OS2PM */
+ "tty", TT_NONE, 0,
+ "tvi910+", TT_TVI910, 0,
+ "tvi925", TT_TVI925, 0,
+ "tvi950", TT_TVI950, 0,
+ "vc404", TT_VC4404, 0,
+ "vc4404", TT_VC4404, CM_INV,
+ "vip7809", TT_VIP7809, 0,
+ "vt100", TT_VT100, 0,
+ "vt102", TT_VT102, 0,
+ "vt220", TT_VT220, 0,
+ "vt220pc", TT_VT220PC, 0,
+ "vt320", TT_VT320, 0,
+ "vt320pc", TT_VT320PC, 0,
+ "vt52", TT_VT52, 0,
+ "wp", TT_KBM_WP, 0,
+ "wy160", TT_WY160, 0,
+ "wy30", TT_WY30, 0,
+ "wy370", TT_WY370, 0,
+ "wy50", TT_WY50, 0,
+ "wy60", TT_WY60, 0,
+ "wyse30", TT_WY30, CM_INV,
+ "wyse370", TT_WY370, CM_INV,
+ "wyse50", TT_WY50, CM_INV,
+ "wyse60", TT_WY60, CM_INV
+};
+int nshokeym = (sizeof(shokeymtab) / sizeof(struct keytab));
+#endif /* OS2 */
+
+VOID
+#ifdef OS2
+shokeycode(c,m) int c, m;
+#else
+shokeycode(c) int c;
+#endif
+/* shokeycode */ {
+ KEY ch;
+ CHAR *s;
+#ifdef OS2
+ int i;
+ con_event km;
+#else /* OS2 */
+ int km;
+#endif /* OS2 */
+
+#ifdef OS2
+ extern int mskkeys;
+ char * mstr = "";
+
+ if (c >= KMSIZE) {
+ bleep(BP_FAIL);
+ return;
+ }
+#else /* OS2 */
+ printf(" Key code \\%d => ", c);
+#endif /* OS2 */
+
+#ifndef OS2
+ km = mapkey(c);
+
+#ifndef NOKVERBS
+ if (IS_KVERB(km)) { /* \Kverb? */
+ int i, kv;
+ kv = km & ~(F_KVERB);
+ printf("Verb: ");
+ for (i = 0; i < nkverbs; i++)
+ if (kverbs[i].kwval == kv) {
+ printf("\\K%s",kverbs[i].kwd);
+ break;
+ }
+ printf("\n");
+ } else
+#endif /* NOKVERBS */
+ if (IS_CSI(km)) {
+ int xkm = km & 0xFF;
+ if (xkm <= 32 || xkm >= 127)
+ printf("String: \\{27}[\\{%d}\n",xkm);
+ else
+ printf("String: \\{27}[%c\n",xkm);
+ } else if (IS_ESC(km)) {
+ int xkm = km & 0xFF;
+ if (xkm <= 32 || xkm >= 127)
+ printf("String: \\{27}\\{%d}\n",xkm);
+ else
+ printf("String: \\{27}%c\n",xkm);
+ } else if (macrotab[c]) { /* See if there's a macro */
+ printf("String: "); /* If so, display its definition */
+ s = macrotab[c];
+ shostrdef(s);
+ printf("\n");
+#ifndef NOKVERBS
+ } else if (km >= 0x100) { /* This means "undefined" */
+ printf("Undefined\n");
+#endif /* NOKVERBS */
+ } else { /* No macro, show single character */
+ printf("Character: ");
+ ch = km;
+ if (ch < 32 || ch == 127
+#ifdef OS2
+ || ch > 255
+#endif /* OS2 */
+#ifndef NEXT
+#ifndef AUX
+#ifndef XENIX
+#ifndef OS2
+ || (ch > 127 && ch < 160)
+#endif /* OS2 */
+#endif /* XENIX */
+#endif /* AUX */
+#endif /* NEXT */
+ )
+/*
+ These used to be %d, but gcc 1.93 & later complain about type mismatches.
+ %u is supposed to be totally portable.
+*/
+ printf("\\%u",(unsigned int) ch);
+ else printf("%c \\%u",(CHAR) (ch & 0xff),(unsigned int) ch);
+ if (ch == (KEY) c)
+ printf(" (self, no translation)\n");
+ else
+ printf("\n");
+ }
+#else /* OS2 */
+ if (m < 0) {
+ km = mapkey(c);
+ mstr = "default";
+ } else {
+ km = maptermkey(c,m);
+ for (i = 0; i < nshokeym; i++) {
+ if (m == shokeymtab[i].kwval) {
+ mstr = shokeymtab[i].kwd;
+ break;
+ }
+ }
+ }
+ s = keyname(c);
+ debug(F111,"shokeycode mstr",mstr,m);
+ debug(F111,"shokeycode keyname",s,c);
+ printf(" %sKey code \\%d %s (%s) => ",
+ mskkeys ? "mskermit " : "",
+ mskkeys ? cktomsk(c) : c,
+ s == NULL ? "" : s, mstr);
+
+ switch (km.type) {
+#ifndef NOKVERBS
+ case kverb: {
+ int i, kv;
+ kv = km.kverb.id & ~(F_KVERB);
+ printf("Verb: ");
+ for (i = 0; i < nkverbs; i++) {
+ if (kverbs[i].kwval == kv) {
+ printf("\\K%s",kverbs[i].kwd);
+ break;
+ }
+ }
+ printf("\n");
+ break;
+ }
+#endif /* NOKVERBS */
+ case csi: {
+ int xkm = km.csi.key & 0xFF;
+ if (xkm <= 32 || xkm >= 127)
+ printf("String: \\{27}[\\{%d}\n",xkm);
+ else
+ printf("String: \\{27}[%c\n",xkm);
+ break;
+ }
+ case esc: {
+ int xkm = km.esc.key & 0xFF;
+ if (xkm <= 32 || xkm >= 127)
+ printf("String: \\{%d}\\{%d}\n",ISDG200(tt_type)?30:27,xkm);
+ else
+ printf("String: \\{%d}%c\n",ISDG200(tt_type)?30:27,xkm);
+ break;
+ }
+ case macro: {
+ printf("String: "); /* Macro, display its definition */
+ shostrdef(km.macro.string);
+ printf("\n");
+ break;
+ }
+ case literal: {
+ printf("Literal string: "); /* Literal, display its definition */
+ shostrdef(km.literal.string);
+ printf("\n");
+ break;
+ }
+ case error: {
+ if (c >= 0x100) {
+ printf("Undefined\n");
+ } else {
+ printf("Character: ");
+ ch = c;
+ if (ch < 32 || ch == 127 || ch > 255
+#ifndef NEXT
+#ifndef AUX
+#ifndef XENIX
+#ifndef OS2
+ || (ch > 127 && ch < 160)
+#endif /* OS2 */
+#endif /* XENIX */
+#endif /* AUX */
+#endif /* NEXT */
+ )
+/*
+ These used to be %d, but gcc 1.93 & later complain about type mismatches.
+ %u is supposed to be totally portable.
+*/
+ printf("\\%u",(unsigned int) ch);
+ else printf("%c \\%u",(CHAR) (ch & 0xff),(unsigned int) ch);
+ printf(" (self, no translation)\n");
+ }
+ break;
+ }
+ case key: {
+ printf("Character: ");
+ ch = km.key.scancode;
+ if (ch < 32 || ch == 127 || ch > 255
+#ifndef NEXT
+#ifndef AUX
+#ifndef XENIX
+#ifndef OS2
+ || (ch > 127 && ch < 160)
+#else
+ || (ch > 127)
+#endif /* OS2 */
+#endif /* XENIX */
+#endif /* AUX */
+#endif /* NEXT */
+ )
+/*
+ These used to be %d, but gcc 1.93 & later complain about type mismatches.
+ %u is supposed to be totally portable.
+*/
+ printf("\\%u",(unsigned int) ch);
+ else printf("%c \\%u",(CHAR) (ch & 0xff),(unsigned int) ch);
+ if (ch == (KEY) c)
+ printf(" (self, no translation)\n");
+ else
+ printf("\n");
+ break;
+ }
+ }
+#endif /* OS2 */
+}
+#endif /* NOSETKEY */
+
+VOID
+shostrdef(s) CHAR * s; {
+ CHAR ch;
+ if (!s) s = (CHAR *)"";
+ while ((ch = *s++)) {
+ if (ch < 32 || ch == 127 || ch == 255
+/*
+ Systems whose native character sets have graphic characters in C1...
+*/
+#ifndef NEXT /* NeXT */
+#ifndef AUX /* Macintosh */
+#ifndef XENIX /* IBM PC */
+#ifdef OS2
+/*
+ It doesn't matter whether the local host can display 8-bit characters;
+ they are not portable among character-sets and fonts. Who knows what
+ would be displayed...
+*/
+ || (ch > 127)
+#else /* OS2 */
+ || (ch > 127 && ch < 160)
+#endif /* OS2 */
+#endif /* XENIX */
+#endif /* AUX */
+#endif /* NEXT */
+ )
+ printf("\\{%d}",ch); /* Display control characters */
+ else putchar((char) ch); /* in backslash notation */
+ }
+}
+
+#define xxdiff(v,sys) strncmp(v,sys,strlen(sys))
+
+#ifndef NOSHOW
+VOID
+shover() {
+#ifdef OS2
+ extern char ckxsystem[];
+#endif /* OS2 */
+ extern char *ck_patch, * cklibv;
+ printf("\nVersions:\n %s\n",versio);
+ printf(" Numeric: %ld\n",vernum);
+#ifdef OS2
+ printf(" Operating System: %s\n", ckxsystem);
+#else /* OS2 */
+ printf(" Built for: %s\n", ckxsys);
+#ifdef CK_UTSNAME
+ if (unm_nam[0])
+ printf(" Running on: %s %s %s %s\n", unm_nam,unm_ver,unm_rel,unm_mch);
+#endif /* CK_UTSNAME */
+ printf(" Patches: %s\n", *ck_patch ? ck_patch : "(none)");
+#endif /* OS2 */
+ if (xxdiff(ckxv,ckxsys))
+ printf(" %s for%s\n",ckxv,ckxsys);
+ else
+ printf(" %s\n",ckxv);
+ if (xxdiff(ckzv,ckzsys))
+ printf(" %s for%s\n",ckzv,ckzsys);
+ else
+ printf(" %s\n",ckzv);
+ printf(" %s\n",cklibv);
+ printf(" %s\n",protv);
+ printf(" %s\n",fnsv);
+ printf(" %s\n %s\n",cmdv,userv);
+#ifndef NOCSETS
+ printf(" %s\n",xlav);
+#endif /* NOCSETS */
+#ifndef MAC
+#ifndef NOLOCAL
+ printf(" %s\n",connv);
+#ifdef OS2
+ printf(" %s\n",ckyv);
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#endif /* MAC */
+#ifndef NODIAL
+ printf(" %s\n",dialv);
+#endif /* NODIAL */
+#ifndef NOSCRIPT
+ printf(" %s\n",loginv);
+#endif /* NOSCRIPT */
+#ifdef NETCONN
+ printf(" %s\n",cknetv);
+#ifdef OS2
+ printf(" %s\n",ckonetv);
+#ifdef CK_NETBIOS
+ printf(" %s\n",ckonbiv);
+#endif /* CK_NETBIOS */
+#endif /* OS2 */
+#endif /* NETCONN */
+#ifdef TNCODE
+ printf(" %s\n",cktelv);
+#endif /* TNCODE */
+#ifdef SSHBUILTIN
+ printf(" %s\n",cksshv);
+#ifdef SFTP_BUILTIN
+ printf(" %s\n",cksftpv);
+#endif /* SFTP_BUILTIN */
+#endif /* SSHBUILTIN */
+#ifdef OS2
+#ifdef OS2MOUSE
+ printf(" %s\n",ckomouv);
+#endif /* OS2MOUSE */
+#endif /* OS2 */
+#ifdef NEWFTP
+ printf(" %s\n",ckftpv);
+#endif /* NEWFTP */
+#ifdef CK_AUTHENTICATION
+ printf(" %s\n",ckathv);
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+#ifdef CRYPT_DLL
+ printf(" %s\n",ck_crypt_dll_version());
+#else /* CRYPT_DLL */
+ printf(" %s\n",ckcrpv);
+#endif /* CRYPT_DLL */
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ printf(" %s\n",cksslv);
+#endif /* CK_SSL */
+ printf("\n");
+}
+
+#ifdef CK_LABELED
+VOID
+sholbl() {
+#ifdef VMS
+ printf("VMS Labeled File Features:\n");
+ printf(" acl %s (ACL info %s)\n",
+ showoff(lf_opts & LBL_ACL),
+ lf_opts & LBL_ACL ? "preserved" : "discarded");
+ printf(" backup-date %s (backup date/time %s)\n",
+ showoff(lf_opts & LBL_BCK),
+ lf_opts & LBL_BCK ? "preserved" : "discarded");
+ printf(" name %s (original filename %s)\n",
+ showoff(lf_opts & LBL_NAM),
+ lf_opts & LBL_NAM ? "preserved" : "discarded");
+ printf(" owner %s (original file owner id %s)\n",
+ showoff(lf_opts & LBL_OWN),
+ lf_opts & LBL_OWN ? "preserved" : "discarded");
+ printf(" path %s (original file's disk:[directory] %s)\n",
+ showoff(lf_opts & LBL_PTH),
+ lf_opts & LBL_PTH ? "preserved" : "discarded");
+#else
+#ifdef OS2
+ printf("OS/2 Labeled File features (attributes):\n");
+ printf(" archive: %s\n", showoff(lf_opts & LBL_ARC));
+ printf(" extended: %s\n", showoff(lf_opts & LBL_EXT));
+ printf(" hidden: %s\n", showoff(lf_opts & LBL_HID));
+ printf(" read-only: %s\n", showoff(lf_opts & LBL_RO ));
+ printf(" system: %s\n", showoff(lf_opts & LBL_SYS));
+#endif /* OS2 */
+#endif /* VMS */
+}
+#endif /* CK_LABELED */
+
+VOID
+shotcs(csl,csr) int csl, csr; { /* Show terminal character set */
+#ifndef NOCSETS
+#ifdef OS2
+#ifndef NOTERM
+ extern struct _vtG G[4], *GL, *GR;
+ extern int decnrcm, sni_chcode;
+ extern int tt_utf8, dec_nrc, dec_kbd, dec_lang;
+ extern prncs;
+
+ printf(" Terminal character-sets:\n");
+ if (IS97801(tt_type_mode)) {
+ if (cmask == 0377)
+ printf(" Mode: 8-bit Mode\n");
+ else
+ printf(" Mode: 7-bit Mode\n");
+ printf(" CH.CODE is %s\n",sni_chcode?"On":"Off");
+ } else if (ISVT100(tt_type_mode)) {
+ if (decnrcm)
+ printf(" Mode: 7-bit National Mode\n");
+ else
+ printf(" Mode: 8-bit Multinational Mode\n");
+ }
+ if ( isunicode() )
+ printf(" Local: Unicode display / %s input\n",
+ csl == TX_TRANSP ? "transparent" :
+ csl == TX_UNDEF ? "undefined" : txrinfo[csl]->keywd);
+ else
+ printf(" Local: %s\n",
+ csl == TX_TRANSP ? "transparent" :
+ csl == TX_UNDEF ? "undefined" : txrinfo[csl]->keywd);
+
+ if ( tt_utf8 ) {
+ printf(" Remote: UTF-8\n");
+ } else {
+ printf(" Remote: %sG0: %s (%s)\n",
+ GL == &G[0] ? "GL->" : GR == &G[0] ? "GR->" : " ",
+ txrinfo[G[0].designation]->keywd,
+ G[0].designation == TX_TRANSP ? "" :
+ G[0].size == cs94 ? "94 chars" :
+ G[0].size == cs96 ? "96 chars" : "multi-byte");
+ printf(" %sG1: %s (%s)\n",
+ GL == &G[1] ? "GL->" : GR == &G[1] ? "GR->" : " ",
+ txrinfo[G[1].designation]->keywd,
+ G[1].designation == TX_TRANSP ? "" :
+ G[1].size == cs94 ? "94 chars" :
+ G[1].size == cs96 ? "96 chars" : "multi-byte");
+ printf(" %sG2: %s (%s)\n",
+ GL == &G[2] ? "GL->" : GR == &G[2] ? "GR->" : " ",
+ txrinfo[G[2].designation]->keywd,
+ G[2].designation == TX_TRANSP ? "" :
+ G[2].size == cs94 ? "94 chars" :
+ G[2].size == cs96 ? "96 chars" : "multi-byte");
+ printf(" %sG3: %s (%s)\n",
+ GL == &G[3] ? "GL->" : GR == &G[3] ? "GR->" : " ",
+ txrinfo[G[3].designation]->keywd,
+ G[3].designation == TX_TRANSP ? "" :
+ G[3].size == cs94 ? "94 chars" :
+ G[3].size == cs96 ? "96 chars" : "multi-byte");
+ }
+ printf("\n");
+ printf(" Keyboard character-sets:\n");
+ printf(" Multinational: %s\n",txrinfo[dec_kbd]->keywd);
+ printf(" National: %s\n",txrinfo[dec_nrc]->keywd);
+ printf("\n");
+ printf(" Printer character-set: %s\n",txrinfo[prncs]->keywd);
+#endif /* NOTERM */
+#else /* OS2 */
+#ifndef MAC
+ char *s;
+
+ debug(F101,"TERM LOCAL CSET","",csl);
+ debug(F101,"TERM REMOTE CSET","",csr);
+ printf(" Terminal character-set: ");
+ if (tcs_transp) { /* No translation */
+ printf("transparent\n");
+ } else { /* Translation */
+ printf("%s (remote) %s (local)\n",
+ fcsinfo[csr].keyword,fcsinfo[csl].keyword);
+ if (csr != csl) {
+ switch(gettcs(csr,csl)) {
+ case TC_USASCII: s = "ascii"; break;
+ case TC_1LATIN: s = "latin1-iso"; break;
+ case TC_2LATIN: s = "latin2-iso"; break;
+ case TC_CYRILL: s = "cyrillic-iso"; break;
+ case TC_JEUC: s = "japanese-euc"; break;
+ case TC_HEBREW: s = "hebrew-iso"; break;
+ case TC_GREEK: s = "greek-iso"; break;
+ case TC_9LATIN: s = "latin9-iso"; break;
+ default: s = "transparent"; break;
+ }
+ if (strcmp(s,fcsinfo[csl].keyword) &&
+ strcmp(s,fcsinfo[csr].keyword))
+ printf(" (via %s)\n",s);
+ }
+ }
+#endif /* MAC */
+#endif /* OS2 */
+#endif /* NOCSETS */
+}
+
+#ifndef NOLOCAL
+#ifdef OS2
+extern char htab[];
+VOID
+shotabs() {
+ int i,j,k,n;
+
+ printf("Tab Stops:\n\n");
+ for (i = 0, j = 1, k = VscrnGetWidth(VCMD); i < MAXTERMCOL; ) {
+ do {
+ printf("%c",htab[++i]=='T'?'T':'-');
+ } while (i % k && i < MAXTERMCOL);
+ printf("\n");
+ for ( ; j <= i; j++) {
+ switch ( j%10 ) {
+ case 1:
+ printf("%c",j == 1 ? '1' : '.');
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ printf("%c",'.');
+ break;
+ case 8:
+ n = (j+2)/100;
+ if (n)
+ printf("%d",n);
+ else
+ printf("%c",'.');
+ break;
+ case 9:
+ n = (j+1)%100/10;
+ if (n)
+ printf("%d",n);
+ else if (j>90)
+ printf("0");
+ else
+ printf("%c",'.');
+ break;
+ case 0:
+ printf("0");
+ break;
+ }
+ }
+ printf("\n");
+ }
+#ifdef COMMENT
+ for (i = 1; i <= 70; i++)
+ printf("%c",htab[i]=='T'?'T':'-');
+ printf("\n1.......10........20........30........40........50........60\
+........70\n\n");
+ for (; i <= 140; i++)
+ printf("%c",htab[i]=='T'?'T':'-');
+ printf("\n........80........90.......100.......110.......120.......130\
+.......140\n\n");
+ for (; i <= 210; i++)
+ printf("%c",htab[i]=='T'?'T':'-');
+ printf("\n.......150.......160.......170.......180.......190.......200\
+.......210\n\n");
+ for (; i <= 255; i++)
+ printf("%c",htab[i]=='T'?'T':'-');
+ printf("\n.......220.......230.......240.......250..255\n");
+#endif
+
+}
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef OS2MOUSE
+VOID
+shomou() {
+ int button, event, id, i;
+ char * name = "";
+
+ printf("Mouse settings:\n");
+ printf(" Button Count: %d\n",mousebuttoncount());
+ printf(" Active: %s\n\n",showoff(tt_mouse));
+
+ for (button = 0; button < MMBUTTONMAX; button++)
+ for (event = 0; event < MMEVENTSIZE; event++)
+ if (mousemap[button][event].type != error)
+ switch (mousemap[button][event].type) {
+ case key:
+ printf(" %s = Character: %c \\%d\n",
+ mousename(button,event),
+ mousemap[button][event].key.scancode,
+ mousemap[button][event].key.scancode );
+ break;
+ case kverb:
+ id = mousemap[button][event].kverb.id & ~(F_KVERB);
+ if (id != K_IGNORE) {
+ for (i = 0; i< nkverbs; i++)
+ if (id == kverbs[i].kwval) {
+ name = kverbs[i].kwd;
+ break;
+ }
+ printf(" %s = Kverb: \\K%s\n",
+ mousename(button,event),
+ name
+ );
+ }
+ break;
+ case macro:
+ printf(" %s = Macro: ",
+ mousename(button,event) );
+ shostrdef(mousemap[button][event].macro.string);
+ printf("\n");
+ break;
+ }
+}
+#endif /* OS2MOUSE */
+
+#ifndef NOLOCAL
+VOID
+shotrm() {
+ char *s;
+ extern char * getiact();
+ extern int tt_print, adl_err;
+#ifndef NOTRIGGER
+ extern char * tt_trigger[];
+#endif /* NOTRIGGER */
+#ifdef CKTIDLE
+ extern char * tt_idlesnd_str;
+ extern int tt_idlesnd_tmo;
+ extern int tt_idlelimit, tt_idleact;
+#endif /* CKTIDLE */
+#ifdef OS2
+ extern int wy_autopage, autoscroll, sgrcolors, colorreset, user_erasemode,
+ decscnm, decscnm_usr, tt_diff_upd, tt_senddata,
+ wy_blockend, marginbell, marginbellcol, tt_modechg, dgunix;
+ int lines = 0;
+#ifdef KUI
+ extern CKFLOAT tt_linespacing[];
+ extern tt_cursor_blink;
+#endif /* KUI */
+#ifdef PCFONTS
+ int i;
+ char *font;
+
+ if (IsOS2FullScreen()) { /* Determine the font name */
+ if (!os2LoadPCFonts()) {
+ for (i = 0; i < ntermfont; i++) {
+ if (tt_font == term_font[i].kwval) {
+ font = term_font[i].kwd;
+ break;
+ }
+ }
+ } else {
+ font = "(DLL not available)";
+ }
+ } else {
+ font = "(full screen only)";
+ }
+#endif /* PCFONTS */
+#ifdef KUI
+ char font[64] = "(unknown)";
+ if ( ntermfont > 0 ) {
+ int i;
+ for (i = 0; i < ntermfont; i++) {
+ if (tt_font == term_font[i].kwval) {
+ ckstrncpy(font,term_font[i].kwd,59);
+ ckstrncat(font," ",64);
+ ckstrncat(font,ckitoa(tt_font_size/2),64);
+ if ( tt_font_size % 2 )
+ ckstrncat(font,".5",64);
+ break;
+ }
+ }
+ }
+#endif /* KUI */
+
+ printf("Terminal parameters:\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %1d%-12s %13s: %1d%-14s\n",
+ "Bytesize: Command",
+ (cmdmsk == 0377) ? 8 : 7,
+ " bits","Terminal",
+ (cmask == 0377) ? 8 : 7," bits");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s","Type",
+ (tt_type >= 0 && tt_type <= max_tt) ?
+ tt_info[tt_type].x_name :
+ "unknown" );
+ if (tt_type >= 0 && tt_type <= max_tt)
+ if (strlen(tt_info[tt_type].x_id))
+ printf(" %13s: <ESC>%s","ID",tt_info[tt_type].x_id);
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Echo",
+ duplex ? "local" : "remote","Locking-shift",showoff(sosi));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Newline-mode", showoff(tnlm),
+ "Cr-display",tt_crd ? "crlf" : "normal");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Cursor",
+#ifdef KUI
+ (tt_cursor == 2) ? (tt_cursor_blink ?
+ "full (*)" : "full (.)") :
+ (tt_cursor == 1) ? (tt_cursor_blink ?
+ "half (*)" : "half (.)") :
+ (tt_cursor_blink ? "underline (*)" : "underline (.)"),
+#else /* KUI */
+ (tt_cursor == 2) ? "full" :
+ (tt_cursor == 1) ? "half" : "underline",
+#endif /* KUI */
+#ifdef CK_AUTODL
+ "autodownload",autodl == TAD_ON ?
+ (adl_err ? "on, error stop" : "on, error continue") :
+ autodl == TAD_ASK ?
+ (adl_err ? "ask, error stop" : "ask, error continue") :
+ "off"
+#else /* CK_AUTODL */
+ "", ""
+#endif /* CK_AUTODL */
+ );
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Arrow-keys",
+ tt_arrow ? "application" : "cursor",
+ "Keypad-mode", tt_keypad ? "application" : "numeric"
+ );
+
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ /* Just to make sure we are using current info */
+ updanswerbk();
+
+ /*
+ This line doesn't end with '\n' because the answerback string
+ is terminated with a newline
+ */
+ printf(" %19s: %-13s %13s: %-15s","Answerback",
+ showoff(tt_answer),"response",answerback);
+ switch (tt_bell) {
+ case XYB_NONE:
+ s = "none";
+ break;
+ case XYB_VIS:
+ s= "visible";
+ break;
+ case XYB_AUD | XYB_BEEP:
+ s="beep";
+ break;
+ case XYB_AUD | XYB_SYS:
+ s="system sounds";
+ break;
+ default:
+ s="(unknown)";
+ }
+ printf(" %19s: %-13s %13s: %-15s\n","Bell",s,
+ "Wrap",showoff(tt_wrap));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Autopage",showoff(wy_autopage),
+ "Autoscroll",showoff(autoscroll));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","SGR Colors",showoff(sgrcolors),
+ "ESC[0m color",colorreset?"default-color":"current-color");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n",
+ "Erase color",user_erasemode?"default-color":"current-color",
+ "Screen mode",decscnm?"reverse":"normal");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ printf(" %19s: %-13d %13s: %-15d\n","Transmit-timeout",tt_ctstmo,
+ "Output-pacing",tt_pacing);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ printf(" %19s: %-13d %13s: %s\n","Idle-timeout",tt_idlelimit,
+ "Idle-action", getiact());
+
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Send data",
+ showoff(tt_senddata),"End of Block", wy_blockend?"crlf/etx":"us/cr");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+#ifndef NOTRIGGER
+ printf(" %19s: %-13s %13s: %d seconds\n","Auto-exit trigger",
+ tt_trigger[0],"Output pacing",tt_pacing );
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+#endif /* NOTRIGGER */
+ printf(" %19s: %-13s %13s: %-15d\n","Margin bell",
+ showoff(marginbell),"at column", marginbellcol);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ switch (tt_modechg) {
+ case TVC_DIS: s = "disabled"; break;
+ case TVC_ENA: s = "enabled"; break;
+ case TVC_W95: s = "win95-restricted"; break;
+ default: s = "(unknown)";
+ }
+ printf(" %19s: %-13s %13s: %-15s\n","DG Unix mode",
+ showoff(dgunix),"Video change", s);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+#ifdef CK_APC
+ if (apcstatus == APC_ON) s = "on";
+ else if (apcstatus == APC_OFF) s = "off";
+ else if (apcstatus == APC_ON|APC_UNCH) s = "unchecked";
+ else if (apcstatus == APC_ON|APC_NOINP) s = "no-input";
+ else if (apcstatus == APC_ON|APC_UNCH|APC_NOINP) s = "unchecked-no-input";
+ printf(" %19s: %-13s %13s: %-15s\n",
+ "APC", s,
+#ifdef PCFONTS
+ "Font (VGA)",font
+#else /* PCFONTS */
+#ifdef KUI
+ "Font",font
+#else
+ "Font","(not supported)"
+#endif /* KUI */
+#endif /* PCFONTS */
+
+ );
+#endif /* CK_APC */
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+#ifdef CK_TTGWSIZ /* Console terminal screen size */
+ if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
+ ttgwsiz(); /* Try to get latest size */
+#endif /* CK_TTGWSIZ */
+ printf(" %19s: %-13d %13s: %-15d\n","Height",tt_rows[VTERM],
+ "Width",tt_cols[VTERM]);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+#ifdef KUI
+ printf(" %19s: %-12f %14s: %-15d\n","Line spacing",tt_linespacing[VTERM],
+ "Display Height",VscrnGetDisplayHeight(VTERM));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+#endif /* KUI */
+ printf(" %19s: %-13s %13s: %d lines\n","Roll-mode",
+ tt_roll[VTERM]?"insert":"overwrite","Scrollback", tt_scrsize[VTERM]);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ if (updmode == tt_updmode)
+ if (updmode == TTU_FAST)
+ s = "fast (fast)";
+ else
+ s = "smooth (smooth)";
+ else
+ if (updmode == TTU_FAST)
+ s = "fast (smooth)";
+ else
+ s = "smooth (fast)";
+
+ printf(" %19s: %-13s %13s: %d ms\n","Screen-update: mode",s,
+ "interval",tt_update);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n",
+ "Screen-optimization",showoff(tt_diff_upd),
+ "Status line",showoff(tt_status[VTERM]));
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" %19s: %-13s %13s: %-15s\n","Debug",
+ showoff(debses),"Session log", seslog? sesfil : "(none)" );
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ /* Display colors (should become SHOW COLORS) */
+ {
+ USHORT row, col;
+ char * colors[16] = {
+ "black","blue","green","cyan","red","magenta","brown","lgray",
+ "dgray","lblue","lgreen","lcyan","lred","lmagent","yellow","white"
+ };
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ printf(" Color:");
+#ifndef ONETERMUPD
+ GetCurPos(&row, &col);
+ WrtCharStrAtt("border", 6, row, 9, &colorborder );
+ WrtCharStrAtt("debug", 5, row, 17, &colordebug );
+ WrtCharStrAtt("helptext", 8, row, 25, &colorhelp );
+ WrtCharStrAtt("reverse", 7, row, 34, &colorreverse );
+ WrtCharStrAtt("select", 6, row, 42, &colorselect );
+ WrtCharStrAtt("status", 6, row, 50, &colorstatus );
+ WrtCharStrAtt("terminal", 8, row, 58, &colornormal );
+ WrtCharStrAtt("underline", 9, row, 67, &colorunderline );
+#endif /* ONETERMUPD */
+ row = VscrnGetCurPos(VCMD)->y+1;
+ VscrnWrtCharStrAtt(VCMD, "border", 6, row, 9, &colorborder );
+ VscrnWrtCharStrAtt(VCMD, "debug", 5, row, 17, &colordebug );
+ VscrnWrtCharStrAtt(VCMD, "helptext", 8, row, 25, &colorhelp );
+ VscrnWrtCharStrAtt(VCMD, "reverse", 7, row, 34, &colorreverse );
+ VscrnWrtCharStrAtt(VCMD, "select", 6, row, 42, &colorselect );
+ VscrnWrtCharStrAtt(VCMD, "status", 6, row, 50, &colorstatus );
+ VscrnWrtCharStrAtt(VCMD, "terminal", 8, row, 58, &colornormal );
+ VscrnWrtCharStrAtt(VCMD, "underline", 9, row, 67, &colorunderline );
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ /* Foreground color names */
+ printf("%6s: %-8s%-8s%-9s%-8s%-8s%-8s%-9s%-9s\n","fore",
+ "",
+ colors[colordebug&0x0F],
+ colors[colorhelp&0x0F],
+ colors[colorreverse&0x0F],
+ colors[colorselect&0x0F],
+ colors[colorstatus&0x0F],
+ colors[colornormal&0x0F],
+ colors[colorunderline&0x0F]);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ /* Background color names */
+ printf("%6s: %-8s%-8s%-9s%-8s%-8s%-8s%-9s%-9s\n","back",
+ colors[colorborder],
+ colors[colordebug>>4],
+ colors[colorhelp>>4],
+ colors[colorreverse>>4],
+ colors[colorselect>>4],
+ colors[colorstatus>>4],
+ colors[colornormal>>4],
+ colors[colorunderline>>4] );
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" Color:");
+#ifndef ONETERMUPD
+ GetCurPos(&row, &col);
+ WrtCharStrAtt("graphic", 7, row, 9, &colorgraphic );
+ WrtCharStrAtt("command", 7, row, 17, &colorcmd );
+ WrtCharStrAtt("italic", 6, row, 26, &coloritalic );
+#endif /* ONETERMUPD */
+ row = VscrnGetCurPos(VCMD)->y+1;
+ VscrnWrtCharStrAtt(VCMD, "graphic", 7, row, 9, &colorgraphic );
+ VscrnWrtCharStrAtt(VCMD, "command", 7, row, 17, &colorcmd );
+ VscrnWrtCharStrAtt(VCMD, "italic", 6, row, 26, &coloritalic );
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ /* Foreground color names */
+ printf("%6s: %-8s%-8s%-8s\n","fore",
+ colors[colorgraphic&0x0F],
+ colors[colorcmd&0x0F],
+ colors[coloritalic&0x0F]);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+ /* Background color names */
+ printf("%6s: %-8s%-8s%-8s\n","back",
+ colors[colorgraphic>>4],
+ colors[colorcmd>>4],
+ colors[coloritalic>>4]);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ }
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ {
+ extern int trueblink, truedim, truereverse, trueunderline, trueitalic;
+ printf(
+ " Attribute: \
+blink: %-3s dim: %-3s italic: %-3s reverse: %-3s underline: %-3s\n",
+ trueblink?"on":"off", truedim?"on":"off", trueitalic?"on":"off",
+ truereverse?"on":"off", trueunderline?"on":"off");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ }
+ {
+ extern vtattrib WPattrib;
+ printf(" ASCII Protected chars: %s%s%s%s%s%s%s\n",
+ WPattrib.blinking?"blink ":"",
+ WPattrib.italic?"italic ":"",
+ WPattrib.reversed?"reverse ":"",
+ WPattrib.underlined?"underline ":"",
+ WPattrib.bold?"bold ":"",
+ WPattrib.dim?"dim ":"",
+ WPattrib.invisible?"invisible ":"");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ }
+
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ (VOID) shoesc(escape);
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+ printf(" See SHOW CHARACTER-SETS for character-set info\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; }
+
+#else /* OS2 */ /* Beginning of new non-OS2 version */
+
+ printf("\n");
+ printf("Terminal parameters:\n");
+ printf(" %19s: %1d%-12s %13s: %1d%-14s\n",
+ "Bytesize: Command",
+ (cmdmsk == 0377) ? 8 : 7,
+ " bits","Terminal",
+ (cmask == 0377) ? 8 : 7," bits");
+ s = getenv("TERM");
+#ifdef XPRINT
+ printf(" %19s: %-13s %13s: %-15s\n",
+ "Type",
+ s ? s : "(unknown)",
+ "Print",
+ showoff(tt_print)
+ );
+#else
+ printf(" %19s: %-13s\n","Type", s ? s : "(unknown)");
+#endif /* XPRINT */
+ printf(" %19s: %-13s %13s: %-15s\n","Echo",
+ duplex ? "local" : "remote","Locking-shift",showoff(sosi));
+ printf(" %19s: %-13s %13s: %-15s\n","Newline-mode",
+ showoff(tnlm),"Cr-display",tt_crd ? "crlf" : "normal");
+
+#ifdef CK_APC
+ if (apcstatus == APC_ON) s = "on";
+ else if (apcstatus == APC_OFF) s = "off";
+ else if (apcstatus == (APC_ON|APC_UNCH)) s = "unchecked";
+ else if (apcstatus == (APC_ON|APC_NOINP)) s = "no-input";
+ else if (apcstatus == (APC_ON|APC_UNCH|APC_NOINP))
+ s = "unchecked-no-input";
+ printf(" %19s: %-13s %13s: %-15s\n",
+ "APC", s,
+#ifdef CK_AUTODL
+ "Autodownload", autodl ?
+ (adl_err ? "on, error stop" : "on, error continue") : "off"
+#else
+ "",""
+#endif /* CK_AUTODL */
+ );
+#endif /* CK_APC */
+
+#ifdef CK_TTGWSIZ /* Console terminal screen size */
+ ttgwsiz(); /* Try to get latest size */
+ printf(" %19s: %-13d %13s: %-15d\n","Height",tt_rows, "Width", tt_cols);
+#endif /* CK_TTGWSIZ */
+
+ printf(" %19s: %-13s %13s: %-15s\n","Debug",
+ showoff(debses),"Session log", seslog? sesfil : "(none)" );
+
+#ifdef CKTIDLE
+ printf(" %19s: %-13d %13s: %s\n","Idle-timeout",tt_idlelimit,
+ "Idle-action", getiact());
+#endif /* CKTIDLE */
+
+ printf(" %19s: %-13s ","Lf-display", tt_lfd ? "crlf" : "normal");
+#ifdef UNIX
+#ifndef NOJC
+ printf("%13s: %-15s","Suspend", showoff(xsuspend));
+#endif /* NOJC */
+#endif /* UNIX */
+ printf("\n");
+
+#ifndef NOTRIGGER
+ printf(" %19s: %-13s\n","Trigger",
+ tt_trigger[0] ? tt_trigger[0] : "(none)");
+#endif /* NOTRIGGER */
+ printf("\n");
+
+ (VOID) shoesc(escape);
+#ifndef NOCSETS
+ shotcs(tcsl,tcsr); /* Show terminal character sets */
+#endif /* NOCSETS */
+
+#endif /* OS2 */
+}
+
+VOID
+shmdmlin() { /* Briefly show modem & line */
+#ifndef NODIAL
+#ifndef MINIDIAL
+#ifdef OLDTBCODE
+ extern int tbmodel;
+ _PROTOTYP( char * gtbmodel, (void) );
+#endif /* OLDTBCODE */
+#endif /* MINIDIAL */
+#endif /* NODIAL */
+ if (local)
+#ifdef OS2
+ printf(" Port: %s, Modem type: ",ttname);
+#else
+ printf(" Line: %s, Modem type: ",ttname);
+#endif /* OS2 */
+ else
+ printf(
+#ifdef OS2
+" Communication device not yet selected with SET PORT\n Modem type: "
+#else
+" Communication device not yet selected with SET LINE\n Modem type: "
+#endif /* OS2 */
+ );
+#ifndef NODIAL
+ printf("%s",gmdmtyp());
+#ifndef MINIDIAL
+#ifdef OLDTBCODE
+ if (tbmodel) printf(" (%s)",gtbmodel()); /* Telebit model info */
+#endif /* OLDTBCODE */
+#endif /* MINIDIAL */
+#else
+ printf("(disabled)");
+#endif /* NODIAL */
+}
+
+#ifdef CK_TAPI
+void
+shotapi(int option) {
+ int rc=0,k ;
+ char *s=NULL;
+ LPDEVCFG lpDevCfg = NULL;
+ LPCOMMCONFIG lpCommConfig = NULL;
+ LPMODEMSETTINGS lpModemSettings = NULL;
+ DCB * lpDCB = NULL;
+ extern struct keytab * tapiloctab; /* Microsoft TAPI Locations */
+ extern int ntapiloc;
+ extern struct keytab * tapilinetab; /* Microsoft TAPI Line Devices */
+ extern int ntapiline;
+ extern int tttapi; /* TAPI in use */
+ extern int tapipass; /* TAPI Passthrough mode */
+ extern int tapiconv; /* TAPI Conversion mode */
+ extern int tapilights;
+ extern int tapipreterm;
+ extern int tapipostterm;
+ extern int tapimanual;
+ extern int tapiinactivity;
+ extern int tapibong;
+ extern int tapiusecfg;
+ extern char tapiloc[];
+ extern int tapilocid;
+ extern int TAPIAvail;
+
+ if (!TAPIAvail) {
+ printf("TAPI Support not enabled\r\n");
+ return;
+ }
+ switch (option) {
+ case 0:
+ printf("TAPI Settings:\n");
+ printf(" Line: %s\n",
+ tttapi ? ttname : "(none in use)");
+
+ cktapiBuildLocationTable(&tapiloctab, &ntapiloc);
+ if (tapilocid == -1)
+ tapilocid = cktapiGetCurrentLocationID();
+
+ /* Find the current tapiloc entry */
+ /* and use it as the default. */
+ for (k = 0; k < ntapiloc; k++) {
+ if (tapiloctab[k].kwval == tapilocid)
+ break;
+ }
+ if (k >= 0 && k < ntapiloc)
+ s = tapiloctab[k].kwd;
+ else
+ s = "(unknown)";
+ printf(" Location: %s\n",s);
+ printf(" Modem-dialing: %s\n",tapipass?"off":"on");
+ printf(" Phone-number-conversions: %s\n",
+ tapiconv==CK_ON?"on":tapiconv==CK_AUTO?"auto":"off");
+ printf(" Modem-lights: %s %s\n",tapilights?"on ":"off",
+ tapipass?"(n/a)":"");
+ printf(" Predial-terminal: %s %s\n",tapipreterm?"on ":"off",
+ tapipass?"(n/a)":"");
+ printf(" Postdial-terminal: %s %s\n",tapipostterm?"on ":"off",
+ tapipass?"(n/a)":"");
+ printf(" Manual-dial: %s %s\n",tapimanual?"on ":"off",
+ tapipass?"(n/a)":"");
+ printf(" Inactivity-timeout: %d seconds %s\n",tapiinactivity,
+ tapipass?"(n/a)":"");
+ printf(" Wait-for-bong: %d seconds %s\n",tapibong,
+ tapipass?"(n/a)":"");
+ printf(" Use-windows-configuration: %s %s\n",
+ tapiusecfg?"on ":"off", tapipass?"(n/a)":"");
+ printf("\n");
+
+#ifdef BETATEST
+ if (tapipass) {
+printf("K-95 uses the TAPI Line in an exclusive mode. Other applications\n");
+printf("may open the device but may not place calls nor answer calls.\n");
+printf("Dialing is performed using the K-95 dialing procedures. SET MODEM\n");
+printf("TYPE TAPI after the SET TAPI LINE command to activate the modem\n");
+printf("definition associated with the active TAPI LINE device.\n\n");
+
+ } else {
+
+printf("K-95 uses the TAPI Line in a cooperative mode. Other applications\n");
+printf("may open the device, place and answer calls. Dialing is performed\n");
+printf("by TAPI. K-95 SET MODEM commands are not used.\n\n");
+ }
+
+ if (tapiconv == CK_ON ||
+ tapiconv == CK_AUTO && !tapipass) {
+printf(
+"Phone numbers are converted from canonical to dialable form by TAPI\n");
+printf("using the dialing rules specified in the TAPI Dialing Properties\n");
+printf("dialog.\n\n");
+
+ } else {
+
+printf(
+"Phone numbers are converted from canonical to dialable form by K-95\n");
+printf(
+"using the dialing rules specified with the SET DIAL commands. TAPI\n");
+printf(
+"Dialing Properties are imported automaticly upon startup and whenever\n");
+printf("the TAPI Dialing Properties are altered or when the TAPI Location\n");
+printf("is changed.\n\n");
+ }
+#endif /* BETATEST */
+
+ if (tapipass) {
+ printf("Type SHOW MODEM to see MODEM configuration.\n");
+ if (tapiconv == CK_ON)
+ printf("Type SHOW DIAL to see DIAL-related items.\n");
+ } else {
+ if (tapiconv == CK_ON || tapiconv == CK_AUTO)
+ printf("Type SHOW DIAL to see DIAL-related items.\n");
+ }
+ break;
+ case 1:
+ cktapiDisplayTapiLocationInfo();
+ break;
+ case 2:
+ rc = cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
+ &lpCommConfig,&lpDCB);
+ if (rc) {
+ cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
+ lpCommConfig,lpDCB);
+ } else {
+ printf("?Unable to retrieve Modem Settings\n");
+ }
+ break;
+ case 3: {
+ HANDLE hModem = GetModemHandleFromLine((HLINE)0);
+ if (hModem)
+ DisplayCommProperties(hModem);
+ else
+ printf("?Unable to retrieve a valid Modem Handle\n");
+ CloseHandle(hModem);
+ break;
+ }
+ }
+ printf("\n");
+}
+#endif /* CK_TAPI */
+#endif /* NOLOCAL */
+
+#ifdef PATTERNS
+static VOID
+shopat() {
+ extern char * binpatterns[], * txtpatterns[];
+ extern int patterns, filepeek;
+ char **p, *s;
+ int i, j, k, n, flag, width;
+#ifdef CK_TTGWSIZ
+ ttgwsiz(); /* Try to get latest size */
+#ifdef OS2
+ width = tt_cols[VCMD];
+#else /* OS2 */
+ width = tt_cols;
+#endif /* OS2 */
+ if (width < 1)
+#endif /* CK_TTGWSIZ */
+ width = 80;
+ printf("\n");
+ printf(" Set file type: %s\n",gfmode(binary,1));
+ printf(" Set file patterns: %s", showooa(patterns));
+#ifdef CK_LABELED
+ if (binary == XYFT_L)
+ printf(" (but SET FILE TYPE LABELED overrides)\n");
+ else
+#endif /* CK_LABELED */
+#ifdef VMS
+ if (binary == XYFT_I)
+ printf(" (but SET FILE TYPE IMAGE overrides)\n");
+ else
+#endif /* VMS */
+ if (filepeek)
+ printf(" (but SET FILE SCAN ON overrides)\n");
+ else
+ printf("\n");
+ printf(" Maximum patterns allowed: %d\n", FTPATTERNS);
+ for (k = 0; k < 2; k++) { /* For each kind of patter */
+ printf("\n");
+ if (k == 0) { /* binary... */
+ printf(" File binary-patterns: ");
+ p = binpatterns;
+ } else { /* text... */
+ printf(" File text-patterns: ");
+ p = txtpatterns;
+ }
+ if (!p[0]) {
+ printf("(none)\n");
+ } else {
+ printf("\n ");
+ n = 2;
+ for (i = 0; i < FTPATTERNS; i++) { /* For each pattern */
+ if (!p[i]) /* Done */
+ break;
+ s = p[i]; /* Look for embedded space */
+ for (j = 0, flag = 1; *s; s++, j++) /* and also get length */
+ if (*s == SP)
+ flag = 3;
+ n += j + flag; /* Length of this line */
+ if (n >= width - 1) {
+ printf("\n ");
+ n = j+2;
+ }
+ printf(flag == 3 ? " {%s}" : " %s", p[i]);
+ }
+ if (n > 2)
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+#endif /* PATTERNS */
+
+#ifndef NOSPL
+static VOID
+shooutput() {
+ printf(" Output pacing: %d (milliseconds)\n",pacing);
+ printf(" Output special-escapes: %s\n", showoff(outesc));
+}
+
+static VOID
+shoinput() {
+#ifdef CKFLOAT
+ extern char * inpscale;
+#endif /* CKFLOAT */
+
+#ifdef CK_AUTODL
+ printf(" Input autodownload: %s\n", showoff(inautodl));
+#endif /* CK_AUTODL */
+ printf(" Input cancellation: %s\n", showoff(inintr));
+ printf(" Input case: %s\n", inpcas[cmdlvl] ?
+ "observe" : "ignore");
+ printf(" Input buffer-length: %d\n", inbufsize);
+ printf(" Input echo: %s\n", showoff(inecho));
+ printf(" Input silence: %d (seconds)\n", insilence);
+#ifdef OS2
+ printf(" Input terminal: %s\n", showoff(interm));
+#endif /* OS2 */
+ printf(" Input timeout: %s\n", intime[cmdlvl] ?
+ "quit" : "proceed");
+#ifdef CKFLOAT
+ printf(" Input scale-factor: %s\n", inpscale ? inpscale : "1.0");
+#endif /* CKFLOAT */
+
+ if (instatus < 0)
+ printf(" Last INPUT: -1 (INPUT command not yet given)\n");
+ else
+ printf(" Last INPUT: %d (%s)\n", instatus,i_text[instatus]);
+}
+#endif /* NOSPL */
+
+#ifndef NOSPL
+int
+showarray() {
+#ifdef COMMENT
+ char * p, * q, ** ap;
+ int i;
+#endif /* COMMENT */
+ char *s; int x = 0, y;
+ int range[2];
+
+ if ((y = cmfld("Array name","",&s,NULL)) < 0)
+ if (y != -3)
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if (*s) {
+ char ** ap;
+ if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
+ printf("?Bad array: %s\n",s);
+ return(-9);
+ }
+ ap = a_ptr[x];
+ if (!ap) {
+ printf("Array not declared: %s\n", s);
+ return(success = 1);
+ } else {
+ int i, n, max;
+ max = (range[1] > 0) ?
+ range[1] :
+ ((range[0] > 0) ? range[0] : a_dim[x]);
+ if (range[0] < 0)
+ range[0] = 0;
+ if (max > a_dim[x])
+ max = a_dim[x];
+ n = 1;
+ printf("\\&%c[]: Dimension = %d",arrayitoa(x),a_dim[x]);
+ if (a_link[x] > -1)
+ printf(" (Link to \\&%c[])",arrayitoa(a_link[x]));
+ printf("\n");
+ for (i = range[0]; i <= max; i++) {
+ if (ap[i]) {
+ printf("%3d. %s\n",i,ap[i]);
+ if (xaskmore) {
+ if (cmd_cols > 0) {
+ x = strlen(ap[i]) + 5;
+ y = (x % cmd_cols) ? 1 : 0;
+ n += (x / cmd_cols) + y;
+ } else {
+ n++;
+ }
+ if (n > (cmd_rows - 3)) {
+ if (!askmore())
+ break;
+ else
+ n = 0;
+ }
+ }
+ }
+ }
+ }
+ return(1);
+ }
+
+ /* All arrays - just show name and dimension */
+
+ for (y = 0; y < (int) 'z' - ARRAYBASE + 1; y++) {
+ if (a_ptr[y]) {
+ if (x == 0) printf("Declared arrays:\n");
+ x = 1;
+ printf(" \\&%c[%d]",
+ (y == 1) ? 64 : y + ARRAYBASE, a_dim[y]);
+ if (a_link[y] > -1)
+ printf(" => \\&%c[]",arrayitoa(a_link[y]));
+ printf("\n");
+ }
+ if (!x) printf(" No arrays declared\n");
+ }
+ return(1);
+}
+#endif /* NOSPL */
+
+int
+doshow(x) int x; {
+ int y, z, i; long zz;
+ extern int optlines;
+ char *s;
+#ifdef OS2
+ extern int os2gks;
+ extern int tt_kb_mode;
+#endif /* OS2 */
+ extern int srvcdmsg;
+ extern char * cdmsgstr, * ckcdpath;
+
+#ifndef NOSETKEY
+ if (x == SHKEY) { /* SHOW KEY */
+ int c;
+#ifdef OS2
+ if ((x = cmkey(shokeytab,nshokey,"How many keys should be shown?",
+ "one",xxstring)) < 0) return(x);
+ switch (tt_kb_mode) {
+ case KBM_EM:
+ s = "emacs";
+ break;
+ case KBM_HE:
+ s = "hebrew";
+ break;
+ case KBM_RU:
+ s = "russian";
+ break;
+ case KBM_EN:
+ default:
+ s = "default";
+ break;
+ }
+ if ((z = cmkey(shokeymtab,nshokeym,"Which definition should be shown?",
+ s,xxstring)) < 0) return(z);
+ if (z == SHKEYDEF)
+ z = -1;
+#endif /* OS2 */
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+#ifdef MAC
+ printf("Not implemented\n");
+ return(0);
+#else /* Not MAC */
+#ifdef OS2
+ if (x) {
+ con_event evt;
+ for (c = 0; c < KMSIZE; c++) {
+ evt = (z < 0) ? mapkey(c) : maptermkey(c,z);
+ if (evt.type != error) {
+ shokeycode(c,z);
+ }
+ }
+ } else {
+#endif /* OS2 */
+ printf(" Press key: ");
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+ conbin((char)escape); /* Put terminal in binary mode */
+#ifdef OS2
+ os2gks = 0; /* Raw scancode processing */
+#endif /* OS2 */
+ c = congks(0); /* Get character or scan code */
+#ifdef OS2
+ os2gks = 1; /* Cooked scancode processing */
+#endif /* OS2 */
+ concb((char)escape); /* Restore terminal to cbreak mode */
+ if (c < 0) { /* Check for error */
+ printf("?Error reading key\n");
+ return(0);
+ }
+#ifndef OS2
+/*
+ Do NOT mask when it can be a raw scan code, perhaps > 255
+*/
+ c &= cmdmsk; /* Apply command mask */
+#endif /* OS2 */
+ printf("\n");
+#ifdef OS2
+ shokeycode(c,z);
+#else /* OS2 */
+ shokeycode(c);
+#endif /* OS2 */
+#ifdef OS2
+ }
+#endif /* OS2 */
+ return(1);
+#endif /* MAC */
+ }
+#ifndef NOKVERBS
+ if (x == SHKVB) { /* SHOW KVERBS */
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ printf("\nThe following %d keyboard verbs are available:\n\n",nkverbs);
+ kwdhelp(kverbs,nkverbs,"","\\K","",3,0);
+ printf("\n");
+ return(1);
+ }
+#ifdef OS2
+ if (x == SHUDK) { /* SHOW UDKs */
+ extern void showudk(void);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ showudk();
+ return(1);
+ }
+#endif /* OS2 */
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+
+#ifndef NOSPL
+ if (x == SHMAC) { /* SHOW MACRO */
+ struct FDB kw, fl, cm;
+ int i, k, n = 0, left, flag, confirmed = 0;
+ char * p, *q[64];
+ for (i = 0; i < nmac; i++) { /* copy the macro table */
+ mackey[i].kwd = mactab[i].kwd; /* into a regular keyword table */
+ mackey[i].kwval = i; /* with value = pointer to macro tbl */
+ mackey[i].flgs = mactab[i].flgs;
+ }
+ p = line;
+ left = LINBUFSIZ;
+ while (!confirmed && n < 64) {
+ cmfdbi(&kw, /* First FDB - macro table */
+ _CMKEY, /* fcode */
+ "Macro name", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nmac, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ mackey, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 2nd FDB - something not in mactab */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* 3rd FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+ x = cmfdb(&kw); /* Parse something */
+ if (x < 0)
+ return(x);
+ s = atmbuf; /* What the user typed */
+ switch (cmresult.fcode) {
+ case _CMKEY: /* If it was a keyword */
+ y = mlook(mactab,atmbuf,nmac); /* get full name */
+ if (y > -1)
+ s = mactab[y].kwd; /* (fall thru on purpose...) */
+ case _CMFLD:
+ k = ckstrncpy(p,s,left) + 1; /* Copy result to list */
+ left -= k;
+ if (left <= 0) {
+ *p = NUL;
+ break;
+ }
+ q[n++] = p; /* Point to this item */
+ p += k; /* Move buffer pointer past it */
+ break;
+ case _CMCFM: /* End of command */
+ confirmed++;
+ default:
+ break;
+ }
+ }
+ if (n == 0) {
+ printf("Macros:\n");
+ slc = 1;
+ for (y = 0; y < nmac; y++)
+ if (shomac(mactab[y].kwd,mactab[y].mval) < 0) break;
+ return(1);
+ }
+ slc = 0;
+ for (i = 0; i < n; i++) {
+ flag = 0;
+ s = q[i];
+ if (!s) s = "";
+ if (!*s) continue;
+ if (iswild(s)) { /* Pattern match */
+ for (k = 0, x = 0; x < nmac; x++) {
+ if (ckmatch(s,mactab[x].kwd,0,1)) {
+ shomac(mactab[x].kwd,mactab[x].mval);
+ k++;
+ }
+ }
+ if (!k)
+ x = -1;
+ else
+ continue;
+ } else { /* Exact match */
+ x = mxlook(mactab,s,nmac);
+ flag = 1;
+ }
+ if (flag && x == -1)
+ x = mlook(mactab,s,nmac);
+ switch (x) {
+ case -3: /* Nothing to look up */
+ case -1: /* Not found */
+ printf("%s - (not defined)\n",s);
+ break;
+ case -2: /* Ambiguous, matches more than one */
+ printf("%s - ambiguous\n",s);
+ break;
+ default: /* Matches one exactly */
+ shomac(mactab[x].kwd,mactab[x].mval);
+ break;
+ }
+ }
+ return(1);
+ }
+#endif /* NOSPL */
+
+/*
+ Other SHOW commands only have two fields. Get command confirmation here,
+ then handle with big switch() statement.
+*/
+#ifndef NOSPL
+ if (x != SHBUI && x != SHARR)
+#endif /* NOSPL */
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+#ifdef COMMENT
+ /* This restriction is too general. */
+#ifdef IKSD
+ if (inserver &&
+#ifdef CK_LOGIN
+ isguest
+#else
+ 0
+#endif /* CK_LOGIN */
+ ) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#endif /* COMMENT */
+
+ switch (x) {
+
+#ifdef ANYX25
+#ifndef IBMX25
+ case SHPAD:
+ shopad(0);
+ break;
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+ case SHNET:
+#ifdef NOLOCAL
+ printf(" No network support in this version of C-Kermit.\n");
+#else
+#ifndef NETCONN
+ printf(" No network support in this version of C-Kermit.\n");
+#else
+ shonet();
+#endif /* NETCONN */
+#endif /* NOLOCAL */
+ break;
+
+ case SHPAR:
+ shopar();
+ break;
+
+#ifndef NOXFER
+ case SHATT:
+ shoatt();
+ break;
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ case SHCOU:
+ printf(" %d\n",count[cmdlvl]);
+ break;
+#endif /* NOSPL */
+
+#ifndef NOSERVER
+ case SHSER: /* Show Server */
+ i = 0;
+#ifndef NOFRILLS
+ printf("Function: Status:\n");
+ i++;
+ printf(" GET %s\n",nm[en_get]);
+ i++;
+ printf(" SEND %s\n",nm[en_sen]);
+ i++;
+ printf(" MAIL %s\n",nm[inserver ? 0 : en_mai]);
+ i++;
+ printf(" PRINT %s\n",nm[inserver ? 0 : en_pri]);
+ i++;
+#ifndef NOSPL
+ printf(" REMOTE ASSIGN %s\n",nm[en_asg]);
+ i++;
+#endif /* NOSPL */
+ printf(" REMOTE CD/CWD %s\n",nm[en_cwd]);
+ i++;
+#ifdef ZCOPY
+ printf(" REMOTE COPY %s\n",nm[en_cpy]);
+ i++;
+#endif /* ZCOPY */
+ printf(" REMOTE DELETE %s\n",nm[en_del]);
+ printf(" REMOTE DIRECTORY %s\n",nm[en_dir]);
+ printf(" REMOTE HOST %s\n",nm[inserver ? 0 : en_hos]);
+ i += 3;
+#ifndef NOSPL
+ printf(" REMOTE QUERY %s\n",nm[en_que]);
+ i++;
+#endif /* NOSPL */
+ printf(" REMOTE MKDIR %s\n",nm[en_mkd]);
+ printf(" REMOTE RMDIR %s\n",nm[en_rmd]);
+ printf(" REMOTE RENAME %s\n",nm[en_ren]);
+ printf(" REMOTE SET %s\n",nm[en_set]);
+ printf(" REMOTE SPACE %s\n",nm[en_spa]);
+ printf(" REMOTE TYPE %s\n",nm[en_typ]);
+ printf(" REMOTE WHO %s\n",nm[inserver ? 0 : en_who]);
+ printf(" BYE %s\n",nm[en_bye]);
+ printf(" FINISH %s\n",nm[en_fin]);
+ printf(" EXIT %s\n",nm[en_xit]);
+ printf(" ENABLE %s\n",nm[en_ena]);
+ i += 11;
+#endif /* NOFRILLS */
+ if (i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server timeout: %d\n",srvtim);
+ if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server idle-timeout: %d\n",srvidl);
+ if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server keepalive %s\n", showoff(srvping));
+ if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server cd-message %s\n", showoff(srvcdmsg));
+ if (srvcdmsg && cdmsgstr)
+ printf("Server cd-message %s\n", cdmsgstr);
+ if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server display: %s\n", showoff(srvdis));
+ if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server login: ");
+ if (!x_user) {
+ printf("(none)\n");
+ } else {
+ printf("\"%s\", \"%s\", \"%s\"\n",
+ x_user,
+ x_passwd ? x_passwd : "",
+ x_acct ? x_acct : ""
+ );
+ }
+ if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; }
+ printf("Server get-path: ");
+ if (ngetpath == 0) {
+ printf(" (none)\n");
+ } else {
+ printf("\n");
+ i += 3;
+ for (x = 0; x < ngetpath; x++) {
+ if (getpath[x]) printf(" %d. %s\n", x, getpath[x]);
+ if (++i > (cmd_rows - 3)) { /* More than a screenful... */
+ if (!askmore())
+ break;
+ else
+ i = 0;
+ }
+ }
+ }
+ break;
+#endif /* NOSERVER */
+
+ case SHSTA: /* Status of last command */
+ printf(" %s\n", success ? "SUCCESS" : "FAILURE");
+ return(0); /* Don't change it */
+
+ case SHSTK: { /* Stack for MAC debugging */
+#ifdef MAC
+ long sp;
+ sp = -1;
+ loadA0 ((char *)&sp); /* set destination address */
+ SPtoaA0(); /* move SP to destination */
+ printf("Stack at 0x%x\n", sp);
+ show_queue(); /* more debugging */
+ break;
+#else
+ shostack();
+#endif /* MAC */
+ break;
+ }
+
+
+#ifndef NOLOCAL
+#ifdef OS2
+ case SHTAB: /* SHOW TABS */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shotabs();
+ break;
+#endif /* OS2 */
+
+ case SHTER: /* SHOW TERMINAL */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shotrm();
+ break;
+
+#ifdef OS2
+ case SHVSCRN: /* SHOW Virtual Screen - for debug */
+ shovscrn();
+ break;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef OS2MOUSE
+ case SHMOU: /* SHOW MOUSE */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shomou();
+ break;
+#endif /* OS2MOUSE */
+
+#ifndef NOFRILLS
+ case SHVER:
+ shover();
+ break;
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+ case SHBUI: /* Built-in variables */
+ line[0] = NUL;
+ if ((y = cmtxt("Variable name or pattern","",&s,xxstring)) < 0)
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ /* if (line[0]) ckstrncat(line,"*",LINBUFSIZ); */
+
+ case SHFUN: /* or built-in functions */
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
+ ttgwsiz();
+#else /* OS2 */
+ if (ttgwsiz() > 0) { /* Get current screen size */
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ if (x == SHFUN) { /* Functions */
+ printf("\nThe following functions are available:\n\n");
+ kwdhelp(fnctab,nfuncs,"","\\F","()",3,0);
+ printf("\n");
+#ifndef NOHELP
+ printf(
+"HELP FUNCTION <name> gives the calling conventions of the given function.\n\n"
+ );
+#endif /* NOHELP */
+ break;
+ } else { /* Variables */
+ int j, flag = 0, havearg = 0;
+ struct stringarray * q = NULL;
+ char ** pp;
+ if (line[0]) { /* Have something to search for */
+ havearg = 1; /* Maybe a list of things */
+ q = cksplit(1,0,line,NULL,"_-^$*?[]{}",0,0,0);
+ if (!q) break;
+ pp = q->a_head;
+ }
+ i = 0;
+ for (y = 0; y < nvars; y++) {
+ if ((vartab[y].flgs & CM_INV))
+ continue;
+ if (havearg) { /* If I have something to match */
+ char * s2;
+ for (flag = 0, j = 1; j <= q->a_size && !flag; j++) {
+ s2 = pp[j] ? pp[j] : "";
+#ifdef COMMENT
+/* This is not needed because it's what the 4 arg does in ckmatch() */
+ len = strlen(s2);
+ if (len > 0) {
+ if (s2[len-1] != '$') {/* To allow anchors */
+ ckmakmsg(line,LINBUFSIZ,pp[j],"*",NULL,NULL);
+ s2 = line;
+ }
+ }
+#endif /* COMMENT */
+ if (ckmatch(s2,vartab[y].kwd,0,4) > 0) {
+ flag = 1; /* Matches */
+ break;
+ }
+ }
+ if (!flag) /* Doesn't match */
+ continue;
+ }
+ s = nvlook(vartab[y].kwd);
+ printf(" \\v(%s) = ",vartab[y].kwd);
+ if (vartab[y].kwval == VN_NEWL) { /* \v(newline) */
+ while (*s) /* Show control chars symbolically */
+ printf("\\{%d}",*s++);
+ printf("\n");
+ } else if (vartab[y].kwval == VN_IBUF || /* \v(input) */
+ vartab[y].kwval == VN_QUE || /* \v(query) */
+#ifdef OS2
+ vartab[y].kwval == VN_SELCT || /* \v(select) */
+#endif /* OS2 */
+ (vartab[y].kwval >= VN_M_AAA && /* modem ones */
+ vartab[y].kwval <= VN_M_ZZZ)
+ ) {
+ int r = 12; /* This one can wrap around */
+ char buf[10];
+ while (*s) {
+ if (isprint(*s)) {
+ buf[0] = *s;
+ buf[1] = NUL;
+ r++;
+ } else {
+ sprintf(buf,"\\{%d}",*s); /* SAFE */
+ r += (int) strlen(buf);
+ }
+ if (r >= cmd_cols - 1) {
+ printf("\n");
+ r = 0;
+ i++;
+ }
+ printf("%s",buf);
+ s++;
+ }
+ printf("\n");
+ } else
+ printf("%s\n",s);
+ if (++i > (cmd_rows - 3)) { /* More than a screenful... */
+ if ((y >= nvars - 1) || !askmore())
+ break;
+ else
+ i = 0;
+ }
+ }
+ }
+ break;
+
+ case SHVAR: /* Global variables */
+ x = 0; /* Variable count */
+ slc = 1; /* Screen line count for "more?" */
+ for (y = 33; y < GVARS; y++)
+ if (g_var[y]) {
+ if (x++ == 0) printf("Global variables:\n");
+ sprintf(line," \\%%%c",y); /* SAFE */
+ if (shomac(line,g_var[y]) < 0) break;
+ }
+ if (!x) printf(" No variables defined\n");
+ break;
+
+ case SHARG: { /* Args */
+ char * s1, * s2;
+ if (maclvl > -1) {
+ printf("Macro arguments at level %d (\\v(argc) = %d):\n",
+ maclvl,
+ macargc[maclvl]
+ );
+ for (y = 0; y < macargc[maclvl]; y++) {
+ s1 = m_arg[maclvl][y];
+ if (!s1) s1 = "(NULL)";
+ s2 = m_xarg[maclvl][y];
+ if (!s2) s2 = "(NULL)";
+ if (y < 10)
+ printf(" \\%%%d = %s\n",y,s1);
+ else
+ printf(" \\&_[%d] = %s\n",y,s2);
+ }
+ } else {
+ printf("Top-level arguments (\\v(argc) = %d):\n", topargc);
+ for (y = 0; y < topargc; y++) {
+ s1 = g_var[y + '0'];
+ if (!s1) s1 = "(NULL)";
+ s2 = toparg[y];
+ if (!s2) s2 = "(NULL)";
+ if (y < 10 && g_var[y])
+ printf(" \\%%%d = %s\n",y,s1);
+ if (toparg[y])
+ printf(" \\&_[%d] = %s\n",y,s2);
+ }
+ }
+ }
+ break;
+
+ case SHARR: /* Arrays */
+ return(showarray());
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ case SHPRO: /* Protocol parameters */
+ shoparp();
+ printf("\n");
+ break;
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ case SHCOM: /* Communication parameters */
+ printf("\n");
+ shoparc();
+#ifdef OS2
+ {
+ int i;
+ char *s = "(unknown)";
+ for (i = 0; i < nprty; i++)
+ if (prtytab[i].kwval == priority) {
+ s = prtytab[i].kwd;
+ break;
+ }
+ printf(" Priority: %s\n", s );
+ }
+#endif /* OS2 */
+
+ printf("\n");
+#ifdef NETCONN
+ if (!network
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) {
+#endif /* NETCONN */
+ shomdm();
+ printf("\n");
+#ifdef NETCONN
+ }
+#endif /* NETCONN */
+
+#ifndef NODIAL
+#ifdef IKSD
+ if ( !inserver )
+#endif /* IKSD */
+ {
+ printf("Type SHOW DIAL to see DIAL-related items.\n");
+ printf("Type SHOW MODEM to see modem-related items.\n");
+#ifdef CK_TAPI
+ printf("Type SHOW TAPI to see TAPI-related items.\n");
+#endif /* CK_TAPI */
+ printf("\n");
+ }
+#endif /* NODIAL */
+ break;
+#endif /* NOLOCAL */
+
+ case SHFIL: /* File parameters */
+ shofil();
+ /* printf("\n"); */ /* (out o' space) */
+ break;
+
+#ifndef NOCSETS
+ case SHLNG: /* Languages */
+ shoparl();
+ break;
+#endif /* NOCSETS */
+
+#ifndef NOSPL
+ case SHSCR: /* Scripts */
+ printf(" Command quoting: %s\n", showoff(cmdgquo()));
+ printf(" Take echo: %s\n", showoff(techo));
+ printf(" Take error: %s\n", showoff(takerr[cmdlvl]));
+ printf(" Macro echo: %s\n", showoff(mecho));
+ printf(" Macro error: %s\n", showoff(merror[cmdlvl]));
+ printf(" Quiet: %s\n", showoff(quiet));
+ printf(" Variable evaluation: %s [\\%%x and \\&x[] variables]\n",
+ vareval ? "recursive" : "simple");
+ printf(" Function diagnostics: %s\n", showoff(fndiags));
+ printf(" Function error: %s\n", showoff(fnerror));
+#ifdef CKLEARN
+ {
+ extern char * learnfile;
+ extern int learning;
+ if (learnfile) {
+ printf(" LEARN file: %s (%s)\n",
+ learnfile,
+ learning ? "ON" : "OFF"
+ );
+ } else
+ printf(" LEARN file: (none)\n");
+ }
+#endif /* CKLEARN */
+ shoinput();
+ shooutput();
+#ifndef NOSCRIPT
+ printf(" Script echo: %s\n", showoff(secho));
+#endif /* NOSCRIPT */
+ printf(" Command buffer length: %d\n", CMDBL);
+ printf(" Atom buffer length: %d\n", ATMBL);
+ break;
+#endif /* NOSPL */
+
+#ifndef NOXMIT
+ case SHXMI:
+ printf("\n");
+ printf(" File type: %s\n",
+ binary ? "binary" : "text");
+#ifndef NOCSETS
+ printf(" File character-set: %s\n",
+ fcsinfo[fcharset].keyword);
+#ifdef OS2
+ if ( isunicode() ) {
+ printf(" Terminal Character (remote): %s\n",
+ tt_utf8 ? "utf-8" : tcsr == TX_TRANSP ? "transparent" :
+ tcsr == TX_UNDEF ? "undefined" : txrinfo[tcsr]->keywd);
+ printf(" Terminal Character (local): %s\n",
+ tcsl == TX_TRANSP ? "transparent" :
+ tcsl == TX_UNDEF ? "undefined" : txrinfo[tcsl]->keywd);
+ } else {
+ printf(" Terminal Character (remote): %s\n",
+ tt_utf8 ? "utf-8" : tcsr == TX_TRANSP ? "transparent" :
+ tcsr == TX_UNDEF ? "undefined" : txrinfo[tcsr]->keywd);
+ printf(" Terminal Character (local): %s\n",
+ tcsl == TX_TRANSP ? "transparent" :
+ tcsl == TX_UNDEF ? "undefined" : txrinfo[tcsl]->keywd);
+ }
+#else /* OS2 */
+ printf(" Terminal character-set (remote): %s\n",
+ fcsinfo[tcsr].keyword);
+ printf(" Terminal character-set (local): %s\n",
+ fcsinfo[tcsl].keyword);
+#endif /* OS2 */
+#endif /* NOCSETS */
+ printf(" Terminal bytesize: %d\n",
+ (cmask == 0xff) ? 8 : 7);
+ printf(" Terminal echo: %s\n",
+ duplex ? "local" : "remote");
+ printf(" Transmit EOF: ");
+ if (*xmitbuf == NUL) {
+ printf("(none)\n");
+ } else {
+ char *p;
+ p = xmitbuf;
+ while (*p) {
+ if (*p < SP)
+ printf("^%c",ctl(*p));
+ else
+ printf("%c",*p);
+ p++;
+ }
+ printf("\n");
+ }
+ if (xmitf)
+ printf(" Transmit Fill: %d\n", xmitf);
+ else
+ printf(" Transmit Fill: (none)\n");
+ printf(" Transmit Linefeed: %s\n",showoff(xmitl));
+ if (xmitp)
+ printf(" Transmit Prompt: %d (%s)\n",
+ xmitp,
+ chartostr(xmitp)
+ );
+ else
+ printf(" Transmit Prompt: (none)\n");
+ printf(" Transmit Echo: %s\n", showoff(xmitx));
+ printf(" Transmit Locking-Shift: %s\n", showoff(xmits));
+ printf(" Transmit Pause: %d (millisecond%s)\n",
+ xmitw,
+ (xmitw == 1) ? "" : "s"
+ );
+ printf(" Transmit Timeout: %d (second%s)\n",
+ xmitt,
+ (xmitt == 1) ? "" : "s"
+ );
+ printf("\n");
+ break;
+#endif /* NOXMIT */
+
+#ifndef NODIAL
+ case SHMOD: /* SHOW MODEM */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shomodem(); /* Show SET MODEM items */
+ break;
+#endif /* NODIAL */
+
+#ifndef MAC
+ case SHDFLT:
+ printf("%s\n",zgtdir());
+ break;
+#endif /* MAC */
+
+#ifndef NOLOCAL
+ case SHESC:
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ return(shoesc(escape));
+
+#ifndef NODIAL
+ case SHDIA: /* SHOW DIAL */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shmdmlin();
+ printf(", speed: ");
+ if ((zz = ttgspd()) < 0) {
+ printf("unknown");
+ } else {
+ if (zz == 8880) printf("75/1200"); else printf("%ld",zz);
+ }
+ if (carrier == CAR_OFF) s = "off";
+ else if (carrier == CAR_ON) s = "on";
+ else if (carrier == CAR_AUT) s = "auto";
+ else s = "unknown";
+ printf(", carrier: %s", s);
+ if (carrier == CAR_ON) {
+ if (cdtimo) printf(", timeout: %d sec", cdtimo);
+ else printf(", timeout: none");
+ }
+ printf("\n");
+ doshodial();
+ if (local
+#ifdef NETCONN
+ && !network
+#endif /* NETCONN */
+ ) {
+ printf("Type SHOW MODEM to see modem settings.\n");
+#ifdef CK_TAPI
+ printf("Type SHOW TAPI to see TAPI-related items\n");
+#endif /* CK_TAPI */
+ printf("Type SHOW COMMUNICATIONS to see modem signals.\n");
+ }
+ break;
+#endif /* NODIAL */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+#ifdef CK_LABELED
+ case SHLBL: /* Labeled file info */
+ sholbl();
+ break;
+#endif /* CK_LABELED */
+#endif /* NOXFER */
+
+ case SHCSE: /* Character sets */
+#ifdef NOCSETS
+ printf(
+" Character set translation is not supported in this version of C-Kermit\n");
+#else
+ shocharset();
+#ifndef NOXFER
+ printf("\n Unknown-Char-Set: %s\n",
+ unkcs ? "Keep" : "Discard");
+#endif /* NOXFER */
+#ifdef OS2
+ printf("\n");
+#endif /* OS2 */
+ shotcs(tcsl,tcsr);
+ printf("\n");
+#ifdef OS2
+ /* PC Code Page information */
+ {
+ char cpbuf[128];
+ int cplist[16], cps;
+ int activecp;
+ cps = os2getcplist(cplist, sizeof(cplist));
+
+ sprintf(cpbuf, /* SAFE */
+ "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d",
+ cps > 1 ? cplist[1] : 0,
+ cps > 2 ? cplist[2] : 0, cps > 3 ? cplist[3] : 0,
+ cps > 4 ? cplist[4] : 0, cps > 5 ? cplist[5] : 0,
+ cps > 6 ? cplist[6] : 0, cps > 7 ? cplist[7] : 0,
+ cps > 8 ? cplist[8] : 0, cps > 9 ? cplist[9] : 0,
+ cps > 10 ? cplist[10] : 0, cps > 11 ? cplist[11] : 0,
+ cps > 12 ? cplist[12] : 0
+ );
+ printf(" Code Pages:\n");
+ activecp = os2getcp();
+ if ( activecp ) {
+ printf(" Active: %d\n",activecp);
+ if (!isWin95())
+ printf(" Available: %s\n",cpbuf);
+ } else
+ printf(" Active: n/a\n");
+ printf("\n");
+ }
+#endif /* OS2 */
+#endif /* NOCSETS */
+ break;
+
+ case SHFEA: /* Features */
+ shofea();
+ break;
+
+#ifdef CK_SPEED
+ case SHCTL: /* Control-Prefix table */
+ shoctl();
+ break;
+#endif /* CK_SPEED */
+
+ case SHEXI: {
+ extern int exithangup;
+ printf("\n Exit warning %s\n", xitwarn ?
+ (xitwarn == 1 ? "on" : "always") : "off");
+ printf(" Exit on-disconnect: %s\n", showoff(exitonclose));
+ printf(" Exit hangup: %s\n", showoff(exithangup));
+ printf(" Current exit status: %d\n\n", xitsta);
+ break;
+ }
+ case SHPRT: {
+#ifdef PRINTSWI
+ extern int printtimo, printertype, noprinter;
+ extern char * printterm, * printsep;
+ extern int prncs;
+#ifdef BPRINT
+ extern int printbidi;
+#endif /* BPRINT */
+#endif /* PRINTSWI */
+
+#ifdef IKSD
+ if (inserver &&
+#ifdef CK_LOGIN
+ isguest
+#else /* CK_LOGIN */
+ 0
+#endif /* CK_LOGIN */
+ ) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef PRINTSWI
+ if (noprinter) {
+ printf("Printer: (none)\n\n");
+ break;
+ }
+#endif /* PRINTSWI */
+
+ printf("Printer: %s%s\n",
+
+ printpipe ? "| " : "",
+ printername ? printername :
+#ifdef OS2
+ "PRN"
+#else
+ "(default)"
+#endif /* OS2 */
+ );
+#ifdef PRINTSWI
+#ifdef BPRINT
+ if (printbidi) {
+ printf(" /BIDIRECTIONAL\n");
+ if (pportspeed > 0)
+ printf(" /SPEED:%ld\n",pportspeed);
+ printf(" /PARITY:%s\n",parnam((char)pportparity));
+ printf(" /FLOW:%s\n",
+ pportflow == FLO_NONE ? "NONE" :
+ (pportflow == FLO_RTSC ? "RTS/CTS" : "XON/XOFF")
+ );
+ } else
+ printf(" /OUTPUT-ONLY\n");
+#endif /* BPRINT */
+ switch (printertype) {
+ case PRT_NON: printf(" /NONE\n"); break;
+ case PRT_FIL: printf(" /FILE\n"); break;
+ case PRT_PIP: printf(" /PIPE\n"); break;
+ case PRT_DOS: printf(" /DOS-DEVICE\n"); break;
+ case PRT_WIN: printf(" /WINDOWS-QUEUE\n"); break;
+ }
+ printf(" /TIMEOUT:%d\n",printtimo);
+ if (printterm) {
+ printf(" /END-OF-JOB-STRING:");
+ shostrdef(printterm);
+ printf("\n");
+ } else
+ printf(" /END-OF-JOB-STRING:(none)\n");
+ printf(" /JOB-HEADER-FILE:%s\n",printsep ? printsep : "(none)");
+ printf(" /CHARACTER-SET: %s\n",txrinfo[prncs]->keywd);
+#endif /* PRINTSWI */
+ printf("\n");
+ break;
+ }
+
+ case SHCMD: {
+#ifdef DOUBLEQUOTING
+ extern int dblquo;
+#endif /* DOUBLEQUOTING */
+#ifdef CK_AUTODL
+ printf(" Command autodownload: %s\n",showoff(cmdadl));
+#else
+ printf(" Command autodownload: (not available)\n");
+#endif /* CK_AUTODL */
+ printf(" Command bytesize: %d bits\n", (cmdmsk == 0377) ? 8 : 7);
+ printf(" Command error-display: %d\n", cmd_err);
+#ifdef CK_RECALL
+ printf(" Command recall-buffer-size: %d\n",cm_recall);
+#else
+ printf(" Command recall-buffer not available in this version\n");
+#endif /* CK_RECALL */
+#ifdef CK_RECALL
+ printf(" Command retry: %s\n",showoff(cm_retry));
+#else
+ printf(" Command retry not available in this version\n");
+#endif /* CK_RECALL */
+ printf(" Command interruption: %s\n", showoff(cmdint));
+ printf(" Command quoting: %s\n", showoff(cmdgquo()));
+#ifdef DOUBLEQUOTING
+ printf(" Command doublequoting: %s\n", showoff(dblquo));
+#endif /* DOUBLEQUOTING */
+ printf(" Command more-prompting: %s\n", showoff(xaskmore));
+ printf(" Command height: %d\n", cmd_rows);
+ printf(" Command width: %d\n", cmd_cols);
+#ifndef IKSDONLY
+#ifdef OS2
+ printf(" Command statusline: %s\n",showoff(tt_status[VCMD]));
+#endif /* OS2 */
+#endif /* IKSDONLY */
+#ifdef LOCUS
+ printf(" Locus: %s",
+ autolocus ? (autolocus == 2 ? "ask" : "auto") :
+ (locus ? "local" : "remote"));
+ if (autolocus)
+ printf(" (%s)", locus ? "local" : "remote");
+ printf("\n");
+#endif /* LOCUS */
+ printf(" Hints: %s\n", showoff(hints));
+ printf(" Quiet: %s\n", showoff(quiet));
+ printf(" Maximum command length: %d\n", CMDBL);
+#ifndef NOSPL
+ {
+ char * s;
+ int k;
+ printf(" Maximum number of macros: %d\n", MAC_MAX);
+ printf(" Macros defined: %d\n", nmac);
+ printf(" Maximum macro depth: %d\n", MACLEVEL);
+ printf(" Maximum TAKE depth: %d\n", MAXTAKE);
+ s = "(not defined)";
+ k = mlook(mactab,"on_unknown_command",nmac);
+ if (k > -1) if (mactab[k].mval) s = mactab[k].mval;
+ printf(" ON_UNKNOWN_COMMAND: %s\n",s);
+ }
+#endif /* NOSPL */
+#ifdef UNIX
+#ifndef NOJC
+ printf(" Suspend: %s\n", showoff(xsuspend));
+#endif /* NOJC */
+#endif /* UNIX */
+ printf(" Access to external commands and programs%s allowed\n",
+#ifndef NOPUSH
+ !nopush ? "" :
+#endif /* NOPUSH */
+ " not");
+ break;
+ }
+
+#ifndef NOSPL
+ case SHALRM:
+ if (ck_alarm)
+ printf("Alarm at %s %s\n",alrm_date,alrm_time);
+ else
+ printf("(no alarm set)\n");
+ break;
+#endif /* NOSPL */
+
+#ifndef NOMSEND
+ case SHSFL: {
+ extern struct filelist * filehead;
+ if (!filehead) {
+ printf("send-list is empty\n");
+ } else {
+ struct filelist * flp;
+ char * s;
+ flp = filehead;
+ while (flp) {
+ s = flp->fl_alias;
+ if (!s) s = "(none)";
+ printf("%s, mode: %s, alias: %s\n",
+ flp->fl_name,
+ gfmode(flp->fl_mode,0),
+ s
+ );
+ flp = flp->fl_next;
+ }
+ }
+ }
+ break;
+#endif /* NOMSEND */
+
+#ifdef CKXXCHAR
+ case SHDBL:
+ shodbl();
+ break;
+#endif /* CKXXCHAR */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+ case SHEDIT:
+ if (!editor[0]) {
+ s = getenv("EDITOR");
+ if (s) ckstrncpy(editor,s,CKMAXPATH);
+ }
+ printf("\n editor: %s\n", editor[0] ? editor : "(none)");
+ if (editor[0]) {
+ printf(" options: %s\n", editopts[0] ? editopts : "(none)");
+ printf(" file: %s\n", editfile[0] ? editfile : "(none)");
+ }
+ printf("\n");
+ break;
+
+#ifdef BROWSER
+ case SHBROWSE:
+ if (!browser[0]) {
+ s = getenv("BROWSER");
+ if (s) ckstrncpy(browser,s,CKMAXPATH);
+ }
+ printf("\n browser: %s\n", browser[0] ? browser : "(none)");
+ if (browser[0]) {
+ printf(" options: %s\n", browsopts[0] ? browsopts : "(none)");
+ printf(" url: %s\n", browsurl[0] ? browsurl : "(none)");
+ }
+ printf("\n");
+ break;
+#endif /* BROWSER */
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifndef NOLOCAL
+#ifdef CK_TAPI
+ case SHTAPI: /* TAPI options */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shotapi(0);
+ break;
+ case SHTAPI_L: /* TAPI Locations */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shotapi(1);
+ break;
+ case SHTAPI_M: /* TAPI Modem */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shotapi(2);
+ break;
+ case SHTAPI_C: /* TAPI Comm */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ shotapi(3);
+ break;
+#endif /* CK_TAPI */
+
+ case SHTCP: /* SHOTCP */
+ printf("\n");
+ shotcp(0);
+ printf("\n");
+ break;
+
+#ifdef TNCODE
+ case SHTEL: /* TELNET */
+ printf("\n");
+ shotel(0);
+ printf("\n");
+ break;
+
+ case SHTOPT: /* TELNET OPTIONS */
+ printf("\n");
+ shotopt(0);
+ printf("\n");
+ break;
+#endif /* TNCODE */
+
+#ifdef CK_TRIGGER
+ case SHTRIG: {
+ extern char * tt_trigger[], * triggerval;
+ int i;
+ if (!tt_trigger[0]) {
+ printf(" Triggers: (none)\n");
+ } else {
+ printf(" Triggers:\n");
+ for (i = 0; i < TRIGGERS; i++) {
+ if (!tt_trigger[i])
+ break;
+ printf(" \"%s\"\n",tt_trigger[i]);
+ }
+ printf(" Most recent trigger encountered: ");
+ if (triggerval)
+ printf("\"%s\"\n",triggerval);
+ else
+ printf("(none)\n");
+ }
+ break;
+ }
+#endif /* CK_TRIGGER */
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+ case SHINP:
+ shoinput();
+ break;
+#endif /* NOSPL */
+
+ case SHLOG: {
+#ifndef MAC
+#ifdef IKSD
+ if (inserver &&
+#ifdef CK_LOGIN
+ isguest
+#else /* CK_LOGIN */
+ 0
+#endif /* CK_LOGIN */
+ ) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef DEBUG
+ printf("\n Debug log: %s", deblog ? debfil : "(none)");
+ {
+ extern int debtim;
+ if (debtim) printf(" (timestamps)");
+ printf("\n");
+ }
+#endif /* DEBUG */
+#ifndef NOXFER
+ printf(" Packet log: %s\n", pktlog ? pktfil : "(none)");
+#endif /* NOXFER */
+#ifndef NOLOCAL
+ printf(" Session log: %s", seslog ? sesfil : "(none)");
+ {
+ extern int sessft, slogts, slognul;
+ switch (sessft) {
+ case XYFT_T: printf(" (text)"); break;
+ case XYFT_B: printf(" (binary)"); break;
+ case XYFT_D: printf(" (debug)"); break;
+ }
+ if (slogts) printf("(timestamped)");
+ if (slognul) printf("(null-padded)");
+ printf("\n");
+ }
+
+#endif /* NOLOCAL */
+#ifdef TLOG
+ printf(" Transaction log: %s (%s)\n",
+ (tralog ? (*trafil ? trafil : "(none)") : "(none)"),
+ (tlogfmt ? ((tlogfmt == 2) ? "ftp" : "verbose") : "brief")
+ );
+#endif /* TLOG */
+#ifdef CKLOGDIAL
+ printf(" Connection log: %s\n", dialog ? diafil : "(none)");
+#endif /* CKLOGDIAL */
+ printf("\n");
+#endif /* MAC */
+ break;
+ }
+
+#ifndef NOSPL
+ case SHOUTP: /* OUTPUT */
+ shooutput();
+ break;
+#endif /* NOSPL */
+
+#ifdef PATTERNS
+ case SHOPAT: /* PATTERNS */
+ shopat();
+ break;
+#endif /* PATTERNS */
+
+#ifdef STREAMING
+ case SHOSTR: { /* STREAMING */
+ extern int streamrq, clearrq, cleared;
+ extern long tfcps;
+ debug(F101,"SHOW RELIABLE reliable","",reliable);
+ printf("\n Reliable: %s\n",showooa(reliable));
+ printf(" Clearchannel: %s\n",showooa(clearrq));
+ printf(" Streaming: %s\n\n",showooa(streamrq));
+ if ((!local && (streamrq == SET_ON)) ||
+ (streamrq == SET_AUTO && reliable))
+ printf(" Streaming will be done if requested.\n");
+ else if ((streamrq == SET_OFF) ||
+ ((streamrq == SET_AUTO) && !reliable))
+ printf(" Streaming will not be requested and will not be done.\n");
+ else if ((streamrq == SET_ON) ||
+ ((streamrq == SET_AUTO) && reliable))
+ printf(
+" Streaming will be requested and will be done if the other Kermit agrees.\n");
+ printf(" Last transfer: %sstreaming%s, %ld cps.\n",
+ streamed > 0 ? "" : "no ",
+ cleared ? ", clearchannel" : "",
+ tfcps
+ );
+ printf("\n");
+ break;
+ }
+#endif /* STREAMING */
+
+ case SHOIKS:
+ return(sho_iks());
+ break;
+
+#ifdef CK_AUTHENTICATION
+ case SHOAUTH:
+ return(sho_auth(0));
+#endif /* CK_AUTHENTICATION */
+
+#ifndef NOFTP
+ case SHOFTP: {
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef SYSFTP
+ {
+ extern char ftpapp[], ftpopts[];
+ printf(" ftp-client: %s\n", ftpapp[0] ? ftpapp : "(none)");
+ if (ftpapp[0])
+ printf(" ftp options: %s\n", ftpopts[0] ? ftpopts : "(none)");
+ }
+#else
+#ifdef NEWFTP
+ shoftp(0);
+#else
+ printf("(No FTP client included in this version of Kermit.)\n");
+#endif /* NEWFTP */
+#endif /* SYSFTP */
+ break;
+ }
+#endif /* NOFTP */
+
+#ifndef NOCMDL
+ case SHXOPT: {
+#ifdef IKSDB
+ extern int dbenabled;
+ extern char * dbfile, * dbdir;
+#endif /* IKSDB */
+#ifdef CKWTMP
+ extern int ckxwtmp;
+ extern char * wtmpfile;
+#endif /* CKWTMP */
+#ifdef CK_LOGIN
+ extern int ckxanon, xferlog, logintimo;
+ extern char * xferfile;
+#ifdef UNIX
+ extern int ckxpriv;
+#endif /* UNIX */
+#ifdef CK_PERMS
+ extern int ckxperms;
+#endif /* CK_PERMS */
+#endif /* CK_LOGIN */
+ extern char * bannerfile, * helpfile;
+
+#ifdef IKSD
+ if (inserver &&
+#ifdef CK_LOGIN
+ isguest
+#else /* CK_LOGIN */
+ 0
+#endif /* CK_LOGIN */
+ ) {
+ printf("Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ printf("\n");
+ if (!cmdint)
+ printf(" --nointerrupts\n");
+ printf(" --bannerfile=%s\n",bannerfile ? bannerfile : "(null)");
+ printf(" --cdfile:%s\n",cdmsgstr ? cdmsgstr : "(null)");
+ printf(" --cdmessage:%d\n",srvcdmsg);
+ printf(" --helpfile:%d\n",helpfile);
+ if (inserver) {
+ printf("\n");
+ break;
+ }
+#ifdef CKSYSLOG
+#ifdef SYSLOGLEVEL
+ printf(" --syslog:%d (forced)\n",ckxsyslog);
+#else
+ printf(" --syslog:%d\n",ckxsyslog);
+#endif /* SYSLOGLEVEL */
+#endif /* CKSYSLOG */
+#ifdef CKWTMP
+ printf(" --wtmplog:%d\n",ckxwtmp);
+ printf(" --wtmpfile=%s\n",wtmpfile ? wtmpfile : "(null)");
+#endif /* CKWTMP */
+#ifdef IKSD
+#ifdef CK_LOGIN
+ printf(" --anonymous:%d\n",ckxanon);
+#ifdef UNIX
+ printf(" --privid:%d\n",ckxpriv);
+#endif /* UNIX */
+#ifdef CK_PERMS
+ printf(" --permission:%04o\n",ckxperms);
+#endif /* CK_PERMS */
+ printf(" --initfile:%s\n",anonfile ? anonfile : "(null)");
+ printf(" --userfile:%s\n",userfile ? userfile : "(null)");
+ printf(" --root:%s\n",anonroot ? anonroot : "(null)");
+ printf(" --xferlog=%d\n",xferlog);
+ printf(" --xferfile=%s\n",xferfile ? xferfile : "(null)");
+ printf(" --timeout=%d\n",logintimo);
+#endif /* CK_LOGIN */
+#ifdef IKSDB
+ printf(" --database=%d\n",dbenabled);
+ printf(" --dbfile=%s\n",dbfile ? dbfile : "(null)");
+ if (dbdir)
+ printf(" (db directory=[%s])\n",dbdir);
+#endif /* IKSDB */
+#ifdef IKSDCONF
+ printf(" IKSD conf=%s\n",iksdconf);
+#endif /* IKSDCONF */
+#endif /* IKSD */
+ printf("\n");
+ break;
+ }
+#endif /* NOCMDL */
+
+ case SHCD: {
+ extern char * myhome;
+ s = getenv("CDPATH");
+ if (!s) s = "(none)";
+ printf("\n current directory: %s\n", zgtdir());
+ printf(" previous directory: %s\n", prevdir ? prevdir : "(none)");
+ printf(" cd home: %s\n", homepath());
+ printf(" cd path: %s\n", ckcdpath ? ckcdpath : s);
+ printf(" cd message: %s\n", showoff(srvcdmsg & 2));
+ printf(" server cd-message: %s\n", showoff(srvcdmsg & 1));
+ printf(" cd message file: %s\n\n",cdmsgstr ? cdmsgstr : "(none)");
+ break;
+ }
+#ifndef NOCSETS
+ case SHASSOC:
+ (VOID) showassoc();
+ break;
+#endif /* NOCSETS */
+
+#ifdef CKLOGDIAL
+ case SHCONNX:
+#ifdef NEWFTP
+ if (ftpisconnected()) {
+ extern char cxlogbuf[];
+ dologshow(W_FTP | 1);
+ if (cxlogbuf[0])
+ dologshow(1);
+ } else {
+#endif /* NEWFTP */
+ dologshow(1);
+#ifdef NEWFTP
+ }
+#endif /* NEWFTP */
+ break;
+#endif /* CKLOGDIAL */
+
+ case SHOPTS:
+ optlines = 0;
+#ifndef NOFRILLS
+ (VOID) showdelopts();
+#endif /* NOFRILLS */
+#ifdef DOMYDIR
+ (VOID) showdiropts();
+#endif /* DOMYDIR */
+#ifdef CKPURGE
+ (VOID) showpurgopts();
+#endif /* CKPURGE */
+ (VOID) showtypopts();
+ break;
+
+#ifndef NOLOCAL
+ case SHOFLO:
+ (VOID) shoflow();
+ break;
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+ case SHOXFER:
+ (VOID) shoxfer();
+ break;
+#endif /* NOXFER */
+
+#ifdef CK_RECALL
+ case SHHISTORY:
+ (VOID) cmhistory();
+ break;
+#endif /* CK_RECALL */
+
+#ifndef NOSEXP
+#ifndef NOSPL
+ case SHSEXP:
+ (VOID) shosexp();
+ break;
+#endif /* NOSPL */
+#endif /* NOSEXP */
+
+#ifdef ANYSSH
+ case SHOSSH:
+ (VOID) shossh();
+ break;
+#endif /* ANYSSH */
+
+#ifdef KUI
+ case SHOGUI:
+ (VOID) shogui();
+ break;
+#endif /* KUI */
+
+#ifndef NOFRILLS
+#ifndef NORENAME
+ case SHOREN:
+ (VOID) shorename();
+ break;
+#endif /* NORENAME */
+#endif /* NOFRILLS */
+
+ default:
+ printf("\nNothing to show...\n");
+ return(-2);
+ }
+ return(success = 1);
+}
+
+#ifndef NOXFER
+int
+shoatt() {
+ printf("Attributes: %s\n", showoff(atcapr));
+ if (!atcapr) return(0);
+ printf(" Blocksize: %s\n", showoff(atblki));
+ printf(" Date: %s\n", showoff(atdati));
+ printf(" Disposition: %s\n", showoff(atdisi));
+ printf(" Encoding (Character Set): %s\n", showoff(atenci));
+ printf(" Length: %s\n", showoff(atleni));
+ printf(" Type (text/binary): %s\n", showoff(attypi));
+ printf(" System ID: %s\n", showoff(atsidi));
+ printf(" System Info: %s\n", showoff(atsysi));
+#ifdef CK_PERMS
+ printf(" Permissions In: %s\n", showoff(atlpri));
+ printf(" Permissions Out: %s\n", showoff(atlpro));
+#endif /* CK_PERMS */
+#ifdef STRATUS
+ printf(" Format: %s\n", showoff(atfrmi));
+ printf(" Creator: %s\n", showoff(atcrei));
+ printf(" Account: %s\n", showoff(atacti));
+#endif /* STRATUS */
+ return(0);
+}
+#endif /* NOXFER */
+
+#ifndef NOSPL
+int /* SHOW MACROS */
+shomac(s1, s2) char *s1, *s2; {
+ int x, n, pp;
+ pp = 0; /* Parenthesis counter */
+
+ debug(F110,"shomac s1",s1,0);
+ debug(F110,"shomac s2",s2,0);
+
+#ifdef IKSD
+ if ( inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else /* IKSDCONF */
+ 1
+#endif /* IKSDCONF */
+ ) {
+ if (!ckstrcmp("on_exit",s1,-1,0) ||
+ !ckstrcmp("on_logout",s1,-1,0))
+ return(0);
+ }
+#endif /* IKSD */
+
+ if (!s1)
+ return(0);
+ else
+ printf("%s = ",s1); /* Print blank line and macro name */
+ n = (int)strlen(s1) + 4; /* Width of current line */
+ if (!s2) s2 = "(not defined)";
+
+ while ((x = *s2++)) { /* Loop thru definition */
+ if (x == '(') pp++; /* Treat commas within parens */
+ if (x == ')') pp--; /* as ordinary text */
+ if (pp < 0) pp = 0; /* Outside parens, */
+ if (x == ',' && pp == 0) { /* comma becomes comma-dash-NL. */
+ putchar(',');
+ putchar('-');
+ x = '\n';
+ }
+ if (inserver && (x == '\n')) /* Send CR before LF */
+ putchar(CR);
+ putchar((CHAR)x); /* Output the character */
+ if (x == '\n') { /* If it was a newline */
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+ putchar(' '); /* Indent the next line 1 space */
+ while(*s2 == ' ') s2++; /* skip past leading blanks */
+ n = 2; /* restart the character counter */
+ slc++; /* and increment the line counter. */
+ } else if (++n > (cmd_cols - 1)) { /* If line is too wide */
+ putchar('-'); /* output a dash */
+ if (inserver)
+ putchar(CR); /* and a carriage return */
+ putchar(NL); /* and a newline */
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+ n = 1; /* and restart the char counter */
+ slc++; /* and increment the line counter */
+ }
+ if (n < 3 && slc > (cmd_rows - 3)) { /* If new line and screen full */
+ if (!askmore()) return(-1); /* ask if they want more. */
+ n = 1; /* They do, start a new line */
+ slc = 0; /* and restart line counter */
+ }
+ }
+ if (inserver)
+ putchar(CR);
+ putchar(NL); /* End of definition */
+ if (++slc > (cmd_rows - 3)) {
+ if (!askmore()) return(-1);
+ slc = 0;
+ }
+ return(0);
+}
+#endif /* NOSPL */
+#endif /* NOSHOW */
+
+int x_ifnum = 0; /* Flag for IF NUMERIC active */
+
+#ifndef NOSPL
+/* Evaluate an arithmetic expression. */
+/* Code adapted from ev, by Howie Kaye of Columbia U & others. */
+
+static int xerror = 0;
+int divbyzero = 0;
+static char *cp;
+static CK_OFF_T tokval;
+static char curtok;
+static CK_OFF_T expval;
+
+#define LONGBITS (8*sizeof (CK_OFF_T))
+#define NUMBER 'N'
+#define N_EOT 'E'
+
+/*
+ Replacement for strchr() and index(), neither of which seem to be universal.
+*/
+
+static char *
+#ifdef CK_ANSIC
+windex(char * s, char c)
+#else
+windex(s,c) char *s, c;
+#endif /* CK_ANSIC */
+/* windex */ {
+ while (*s != NUL && *s != c) s++;
+ if (*s == c) return(s); else return(NULL);
+}
+
+
+/*
+ g e t t o k
+
+ Returns the next token. If token is a NUMBER, sets tokval appropriately.
+*/
+static char
+gettok() {
+ char tbuf[80] /* ,*tp */ ; /* Buffer to accumulate number */
+
+ while (isspace(*cp)) /* Skip past leading spaces */
+ cp++;
+
+ debug(F110,"GETTOK",cp,0);
+
+ switch (*cp) {
+ case '$': /* ??? */
+ case '+': /* Add */
+ case '-': /* Subtract or Negate */
+ case '@': /* Greatest Common Divisor */
+ case '*': /* Multiply */
+ case '/': /* Divide */
+ case '%': /* Modulus */
+ case '<': /* Left shift */
+ case '>': /* Right shift */
+ case '&': /* And */
+ case '|': /* Or */
+ case '#': /* Exclusive Or */
+ case '~': /* Not */
+ case '^': /* Exponent */
+ case '!': /* Factorial */
+ case '(': /* Parens for grouping */
+ case ')': return(*cp++); /* operator, just return it */
+ case '\n':
+ case '\0': return(N_EOT); /* End of line, return that */
+ }
+#ifdef COMMENT
+/* This is the original code, which allows only integer numbers. */
+
+ if (isxdigit(*cp)) { /* Digit, must be a number */
+ int radix = 10; /* Default radix */
+ for (tp = tbuf; isxdigit(*cp); cp++)
+ *tp++ = (char) (isupper(*cp) ? tolower(*cp) : *cp);
+ *tp = '\0'; /* End number */
+ switch(isupper(*cp) ? tolower(*cp) : *cp) { /* Examine break char */
+ case 'h':
+ case 'x': radix = 16; cp++; break; /* if radix signifier... */
+ case 'o':
+ case 'q': radix = 8; cp++; break;
+ case 't': radix = 2; cp++; break;
+ }
+ for (tp = tbuf, tokval = 0; *tp != '\0'; tp++) {
+ int dig;
+ dig = *tp - '0'; /* Convert number */
+ if (dig > 10) dig -= 'a'-'0'-10;
+ if (dig >= radix) {
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("?Invalid digit '%c' in number\n",*tp);
+ xerror = 1;
+ return(NUMBER);
+ }
+ tokval = radix*tokval + dig;
+ }
+ return(NUMBER);
+ }
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("Invalid character '%c' in input\n",*cp);
+ xerror = 1;
+ cp++;
+ return(gettok());
+#else
+/* This code allows non-numbers to be treated as macro names */
+ {
+ int i, x;
+ char * s, * cp1;
+ cp1 = cp;
+ tp = tbuf;
+ for (i = 0; i < 80; i++) {
+ /* Look ahead to next break character */
+ /* pretty much anything that is not in the switch() above. */
+ if (isalpha(*cp) || isdigit(*cp) ||
+ *cp == '_' || *cp == ':' || *cp == '.' ||
+ *cp == '[' || *cp == ']' ||
+ *cp == '{' || *cp == '}'
+ )
+ tbuf[i] = *cp++;
+ else
+ break;
+ }
+ if (i >= 80) {
+ printf("Too long - \"%s\"\n", cp1);
+ xerror = 1;
+ cp++;
+ return(gettok());
+ }
+ if (xerror) return(NUMBER);
+
+ tbuf[i] = NUL;
+ s = tbuf;
+ if (!isdigit(tbuf[0])) {
+ char * s2 = NULL;
+ x = mxlook(mactab,tbuf,nmac);
+ debug(F111,"gettok mxlook",tbuf,x);
+ if (x < 0) {
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("Bad number - \"%s\"\n",tbuf);
+ xerror = 1;
+ cp++;
+ return(gettok());
+ }
+ s2 = mactab[x].mval;
+ if (!s2) s2 = "";
+ if (*s2) s = s2;
+ }
+#ifdef CKFLOAT
+ x = isfloat(s,0);
+#else
+ x = chknum(s);
+#endif /* CKFLOAT */
+ if (x > 0) {
+ tokval = ckatofs(s);
+ } else {
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("Bad number - \"%s\"\n",tbuf);
+ xerror = 1;
+ cp++;
+ return(gettok());
+ }
+ return(NUMBER);
+ }
+#endif /* COMMENT */
+}
+
+static CK_OFF_T
+#ifdef CK_ANSIC
+expon(CK_OFF_T x, CK_OFF_T y)
+#else
+expon(x,y) CK_OFF_T x,y;
+#endif /* CK_ANSIC */
+/* expon */ {
+ CK_OFF_T result = 1;
+ int sign = 1;
+ if (y < 0) return(0);
+ if (x < 0) {
+ x = -x;
+ if (y & 1) sign = -1;
+ }
+ while (y != 0) {
+ if (y & 1) result *= x;
+ y >>= 1;
+ if (y != 0) x *= x;
+ }
+ return(result * sign);
+}
+
+/*
+ * factor ::= simple | simple ^ factor
+ *
+ */
+static VOID
+factor() {
+ CK_OFF_T oldval;
+ simple();
+ if (curtok == '^') {
+ oldval = expval;
+ curtok = gettok();
+ factor();
+ expval = expon(oldval,expval);
+ }
+}
+
+/*
+ * termp ::= NULL | {*,/,%,&} factor termp
+ *
+ */
+static VOID
+termp() {
+ while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == '&') {
+ CK_OFF_T oldval;
+ char op;
+ op = curtok;
+ curtok = gettok(); /* skip past operator */
+ oldval = expval;
+ factor();
+ switch(op) {
+ case '*': expval = oldval * expval; break;
+ case '/':
+ case '%':
+ if (expval == 0) {
+ if (!x_ifnum)
+ printf("?Divide by zero\n");
+ xerror = 1;
+ divbyzero = 1;
+ expval = -1;
+ } else
+ expval = (op == '/') ? (oldval / expval) : (oldval % expval);
+ break;
+ case '&':
+ expval = oldval & expval; break;
+ }
+ }
+}
+
+static CK_OFF_T
+#ifdef CK_ANSIC
+fact(CK_OFF_T x)
+#else
+fact(x) CK_OFF_T x;
+#endif /* CK_ANSIC */
+/* fact */ { /* factorial */
+ CK_OFF_T result = 1;
+ while (x > 1)
+ result *= x--;
+ return(result);
+}
+
+/*
+ * term ::= factor termp
+ *
+ */
+static VOID
+term() {
+ factor();
+ termp();
+}
+
+static CK_OFF_T
+#ifdef CK_ANSIC
+gcd(CK_OFF_T x, CK_OFF_T y)
+#else
+gcd(x,y) CK_OFF_T x,y;
+#endif /* CK_ANSIC */
+/* gcd */ { /* Greatest Common Divisor */
+ int nshift = 0;
+ if (x < 0) x = -x;
+ if (y < 0) y = -y; /* validate arguments */
+ if (x == 0 || y == 0) return(x + y); /* this is bogus */
+
+ while (!((x & 1) | (y & 1))) { /* get rid of powers of 2 */
+ nshift++;
+ x >>= 1;
+ y >>= 1;
+ }
+ while (x != 1 && y != 1 && x != 0 && y != 0) {
+ while (!(x & 1)) x >>= 1; /* eliminate unnecessary */
+ while (!(y & 1)) y >>= 1; /* powers of 2 */
+ if (x < y) { /* force x to be larger */
+ CK_OFF_T t;
+ t = x;
+ x = y;
+ y = t;
+ }
+ x -= y;
+ }
+ if (x == 0 || y == 0) return((x + y) << nshift); /* gcd is non-zero one */
+ else return((CK_OFF_T) 1 << nshift); /* else gcd is 1 */
+}
+
+/*
+ * exprp ::= NULL | {+,-,|,...} term exprp
+ *
+ */
+static VOID
+exprp() {
+ while (windex("+-|<>#@",curtok) != NULL) {
+ CK_OFF_T oldval;
+ char op;
+ op = curtok;
+ curtok = gettok(); /* skip past operator */
+ oldval = expval;
+ term();
+ switch(op) {
+ case '+' : expval = oldval + expval; break;
+ case '-' : expval = oldval - expval; break;
+ case '|' : expval = oldval | expval; break;
+ case '#' : expval = oldval ^ expval; break;
+ case '@' : expval = gcd(oldval,expval); break;
+ case '<' : expval = oldval << expval; break;
+ case '>' : expval = oldval >> expval; break;
+ }
+ }
+}
+
+/*
+ * expr ::= term exprp
+ *
+ */
+static VOID
+expr() {
+ term();
+ exprp();
+}
+
+static CK_OFF_T
+xparse() {
+ curtok = gettok();
+ expr();
+#ifdef COMMENT
+ if (curtok == '$') {
+ curtok = gettok();
+ if (curtok != NUMBER) {
+ if (cmdlvl == 0 && !x_ifnum)
+ printf("?Illegal radix\n");
+ xerror = 1;
+ return(0);
+ }
+ curtok = gettok();
+ }
+#endif /* COMMENT */
+ if (curtok != N_EOT) {
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("?Extra characters after expression\n");
+ xerror = 1;
+ }
+ return(expval);
+}
+
+char * /* Silent front end for evala() */
+evalx(s) char *s; {
+ char * p;
+ int t;
+ t = x_ifnum;
+ x_ifnum = 1;
+ p = evala(s);
+ x_ifnum = t;
+ return(p);
+}
+
+char *
+evala(s) char *s; {
+ CK_OFF_T v; /* Numeric value */
+ if (!s) return("");
+ xerror = 0; /* Start out with no error */
+ divbyzero = 0;
+ cp = s; /* Make the argument global */
+ v = xparse(); /* Parse the string */
+ return(xerror ? "" : ckfstoa(v)); /* Return empty string on error */
+}
+
+/*
+ * simplest ::= NUMBER | ( expr )
+ *
+ */
+static VOID
+simplest() {
+ char * p;
+ p = cp;
+ if (curtok == NUMBER)
+ expval = tokval;
+ else if (curtok == '(') {
+ curtok = gettok(); /* skip over paren */
+ expr();
+ if (curtok != ')') {
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("?Missing right parenthesis\n");
+ xerror = 1;
+ }
+ debug(F110,"GETTOK SIMPLEST ()",p,0);
+
+ } else {
+ if (cmdlvl == 0 && !x_ifnum && !xerror)
+ printf("?Operator unexpected\n");
+ xerror = 1;
+ }
+ curtok = gettok();
+}
+
+/*
+ * simpler ::= simplest | simplest !
+ *
+ */
+static VOID
+simpler() {
+ simplest();
+ if (curtok == '!') {
+ curtok = gettok();
+ expval = fact(expval);
+ }
+}
+
+/*
+ * simple ::= {-,~,!} simpler | simpler
+ *
+ */
+
+static VOID
+simple() {
+ if (curtok == '-' || curtok == '~' || curtok == '!' || curtok == '+') {
+ int op = curtok;
+ curtok = gettok(); /* skip over - sign */
+ simpler(); /* parse the factor again */
+ if (op != '+')
+ expval = (op == '-') ? -expval : ((op == '!') ? !expval : ~expval);
+ } else simpler();
+}
+
+/* D C L A R R A Y -- Declare an array */
+/*
+ Call with:
+ char a = single character designator for the array, e.g. "a".
+ int n = size of array. -1 means to undeclare the array.
+ Returns:
+ 0 or greater on success, having created the requested array with
+ with n+1 elements, 0..n. If an array of the same name existed
+ previously, it is destroyed. The new array has all its elements
+ initialized to NULL pointers. When an array is successfully created,
+ the return value is its index (0 = 'a', 1 = 'b', and so on.)
+ -1 on failure (because 'a' out of range or malloc failure).
+*/
+int
+#ifdef CK_ANSIC
+dclarray(char a, int n)
+#else
+dclarray(a,n) char a; int n;
+#endif /* CK_ANSIC */
+/* dclarray */ {
+ char c, **p; int i, n2, rc;
+
+ if (a > 63 && a < 91) a += 32; /* Convert letters to lowercase */
+ if (a < ARRAYBASE || a > 122) /* Verify name */
+ return(-1);
+
+ if (n < 0) /* Check arg */
+ return(-1);
+ if (n+1 < 0) /* MAXINT+1 wraps around */
+ return(-1);
+
+ c = a;
+ a -= ARRAYBASE; /* Convert name to number */
+ rc = a; /* Array index will be return code */
+ if ((p = a_ptr[a]) != NULL) { /* Delete old array of same name */
+ if (a_link[a] > -1) { /* Is it a link? */
+ if (n == 0) { /* If we're just deleting it */
+ a_ptr[a] = (char **) NULL; /* clear all the info. */
+ a_dim[a] = 0;
+ a_link[a] = -1;
+ return(0);
+ } /* Not deleting */
+ a = a_link[a]; /* Switch to linked-to array */
+ }
+ n2 = a_dim[a]; /* Real array */
+ for (i = 0; i <= n2; i++) { /* First delete its elements */
+ if (p[i]) {
+ free(p[i]);
+ p[i] = NULL;
+ }
+ }
+ free((char *)a_ptr[a]); /* Then the element list */
+ if (n == 0) { /* If undeclaring this array... */
+ for (i = 0; i < 122 - ARRAYBASE; i++) { /* Any linked arrays? */
+ if (i != a && a_link[i] == a) { /* Find them */
+ a_ptr[i] = (char **) NULL; /* and remove them */
+ a_dim[i] = 0;
+ a_link[i] = -1;
+ }
+ }
+ }
+ a_ptr[a] = (char **) NULL; /* Remove pointer to element list */
+ a_dim[a] = 0; /* Set dimension at zero. */
+ a_link[a] = -1; /* Unset link word */
+ }
+ if (n < 0) /* If only undeclaring, */
+ return(0); /* we're done. */
+ p = (char **) malloc((n+1) * sizeof(char **)); /* Allocate for new array */
+ if (p == NULL) return(-1); /* Check */
+ a_ptr[a] = p; /* Save pointer to member list */
+ a_dim[a] = n; /* Save dimension */
+ for (i = 0; i <= n; i++) /* Initialize members to null */
+ p[i] = NULL;
+ for (i = 0; i < (int) 'z' - ARRAYBASE; i++) { /* Any linked arrays? */
+ if (i != a && a_link[i] == a) { /* Find and update them */
+ a_ptr[i] = p;
+ a_dim[i] = n;
+ }
+ }
+ return(rc);
+}
+
+/* X A R R A Y -- Convert array name to array index */
+
+int
+xarray(s) char * s; {
+ char buf[8];
+ int x;
+ char c;
+
+ if (!s) s = "";
+ debug(F110,"xarray",s,0);
+ if (!*s)
+ return(-1);
+ x = strlen(s);
+
+ buf[0] = NUL;
+ buf[1] = NUL;
+ buf[2] = s[0];
+ buf[3] = (x > 0) ? s[1] : NUL;
+ buf[4] = (x > 1) ? s[2] : NUL;
+ buf[5] = (x > 2) ? s[3] : NUL;
+ buf[6] = NUL;
+ debug(F110,"xarray buf[3]",&buf[3],0);
+ s = buf+2;
+ if (*s == '&') {
+ buf[1] = CMDQ;
+ s--;
+ } else if (*s != CMDQ) {
+ buf[0] = CMDQ;
+ buf[1] = '&';
+ s = buf;
+ }
+ debug(F110,"xarray s",s,0);
+ c = *(s+2);
+ if (isupper(c))
+ c = tolower(c);
+ if (c == '@')
+ c = 96;
+ x = (int)c - ARRAYBASE;
+ if (*(s+3) == '[')
+ *(s+3) = NUL;
+ if (x < 0) {
+ return(-1);
+ }
+ if (x > ('z' - ARRAYBASE)) {
+ debug(F101,"xarray x out of range","",x);
+ return(-1);
+ }
+ if (*(s+3)) {
+ debug(F110,"xarray syntax",s,0);
+ return(-1);
+ }
+ return(x);
+}
+
+/*
+ boundspair() -- parses blah[n:m]
+
+ For use with array segment specifiers and compact substring notation.
+ Ignores the "blah" part, gets the values of n and m, which can be
+ numbers, variables, or arithmetic expressions; anything that resolves
+ to a number.
+
+ Call with:
+ s - string to parse
+ sep - array of permissible bounds separator chars
+ lo - pointer to low-bound result (or -1)
+ hi - pointer to hi-bound result (or -1)
+ zz - pointer to separator char that was encountered (or NUL)
+ Returns:
+ -1 on failure
+ 0 on success
+*/
+
+int
+#ifdef CK_ANSIC
+boundspair(char *s, char *sep, int *lo, int *hi, char *zz)
+#else
+boundspair(s,sep,lo,hi,zz) char *s, *sep, *zz; int *lo, *hi;
+#endif /* CK_ANSIC */
+{
+ int i, x, y, range[2], bc = 0;
+ char c = NUL, *s2 = NULL, buf[256], *p, *q, *r, *e[2], *tmp = NULL;
+
+ debug(F110,"boundspair s",s,0);
+ debug(F110,"boundspair sep",sep,0);
+
+ *lo = -1; /* Default bounds */
+ *hi = -1;
+ *zz = 0; /* Default bounds separator */
+
+ range[0] = -1; /* It's OK -- get contents */
+ range[1] = -1; /* of subscript brackets */
+ if (!s) s = "";
+ if (!*s)
+ return(-1);
+ makestr(&tmp,s); /* Make a pokeable copy */
+ p = tmp;
+ q = NULL;
+ r = NULL;
+ for (p = s; *p; p++) { /* Get the two elements */
+ if (*p == '[') {
+ bc++; /* Bracket counter */
+ if (bc == 1 && !q) q = p+1;
+ } else if (*p == ']') {
+ bc--;
+ if (bc == 0 && q) *p = NUL;
+ } else if (bc == 1) { /* If within brackers */
+ s2 = ckstrchr(sep,*p); /* Check for separator */
+ if (s2) {
+ debug(F000,"boundspair *s2","",*s2);
+ if (c) {
+ debug(F000,"boundspair","Too many separators",*s2);
+ makestr(&tmp,NULL);
+ return(-1);
+ }
+ c = *s2; /* Separator character */
+ *p = NUL;
+ r = p+1;
+ }
+ }
+ }
+ if (bc == 0 && !q) {
+ /* This allows such constructions as "show array a" */
+ debug(F110,"boundspair","no brackets",0);
+ makestr(&tmp,NULL);
+ return(0);
+ }
+ if (bc != 0 || !q) {
+ debug(F110,"boundspair","unbalanced or missing brackets",0);
+ makestr(&tmp,NULL);
+ return(-1);
+ }
+ if (!q) q = "";
+ if (!*q) q = "-1";
+ if (!r) r = "";
+ if (!*r) r = "-1";
+
+ e[0] = q;
+ e[1] = r;
+
+ debug(F000,"boundspair c","",c);
+ debug(F110,"boundspair q",q,0);
+ debug(F110,"boundspair r",r,0);
+
+ for (i = 0; i < 2 && e[i]; i++) {
+ y = 255; /* Expand variables, etc. */
+ s = buf;
+ zzstring(e[i],&s,&y);
+ s = evalx(buf); /* Evaluate it arithmetically */
+ if (s) if (*s)
+ ckstrncpy(buf,s,256);
+ if (!chknum(buf)) { /* Did we get a number? */
+ debug(F110,"boundspair element not numeric",buf,0);
+ makestr(&tmp,NULL); /* No, fail. */
+ return(-1);
+ }
+ range[i] = atoi(buf);
+ }
+ makestr(&tmp,NULL); /* Free temporary poked string */
+ *lo = range[0]; /* Return what we got */
+ *hi = range[1];
+ *zz = c;
+ debug(F101,"boundspair lo","",*lo);
+ debug(F101,"boundspair hi","",*hi);
+ return(0);
+}
+
+/* A R R A Y B O U N D S -- Parse array segment notation \&a[n:m] */
+
+/*
+ Call with s = array reference, plus two pointers to ints.
+ Returns -1 on error, or array index, with the two ints set as follows:
+ \&a[] -1, -1
+ \&a[3] 3, -1
+ \&a[3:17] 3, 17
+ The array need not be declared -- this routine is just for parsing.
+*/
+int
+arraybounds(s,lo,hi) char * s; int * lo, * hi; {
+ int i, x, y, range[2];
+ char zz, buf[256], * p, * q;
+ char * tmp = NULL;
+
+ *lo = -1; /* Default bounds */
+ *hi = -1;
+
+ if (!s) s = ""; /* Defense de null args */
+ if (!*s)
+ return(-1);
+
+ x = xarray(s); /* Check basic structure */
+ debug(F111,"arraybounds xarray",s,x);
+ if (x < 0) /* Not OK, fail. */
+ return(-1);
+ y = boundspair(s,":",lo,hi,&zz);
+ debug(F111,"arraybounds boundspair",s,y);
+ debug(F101,"arraybounds lo","",*lo);
+ debug(F101,"arraybounds hi","",*hi);
+ if (y < 0) /* Get bounds */
+ return(-1);
+ return(x);
+}
+
+/* A R R A Y N A M -- Parse an array name */
+
+/*
+ Call with pointer to string that starts with the array reference.
+ String may begin with either \& or just &.
+ On success,
+ Returns letter ID (always lowercase) in argument c,
+ which can also be accent grave (` = 96; '@' is converted to grave);
+ Dimension or subscript in argument n;
+ IMPORTANT: These arguments must be provided by the caller as addresses
+ of ints (not chars), for example:
+ char *s; int x, y;
+ arraynam(s,&x,&y);
+ On failure, returns a negative number, with args n and c set to zero.
+*/
+int
+arraynam(ss,c,n) char *ss; int *c; int *n; {
+ int i, y, pp, len;
+ char x;
+ char *s, *p, *sx, *vnp;
+ /* On stack to allow for recursive calls... */
+ char vnbuf[ARRAYREFLEN+1]; /* Entire array reference */
+ char ssbuf[ARRAYREFLEN+1]; /* Subscript in "plain text" */
+ char sxbuf[16]; /* Evaluated subscript */
+
+ *c = *n = 0; /* Initialize return values */
+ len = strlen(ss);
+ for (pp = 0,i = 0; i < len; i++) { /* Check length */
+ if (ss[i] == '[') {
+ pp++;
+ } else if (ss[i] == ']') {
+ if (--pp == 0)
+ break;
+ }
+ }
+ if (i > ARRAYREFLEN) {
+ printf("?Array reference too long - %s\n",ss);
+ return(-9);
+ }
+ ckstrncpy(vnbuf,ss,ARRAYREFLEN);
+ vnp = vnbuf;
+ if (vnbuf[0] == CMDQ && vnbuf[1] == '&') vnp++;
+ if (*vnp != '&') {
+ printf("?Not an array - %s\n",vnbuf);
+ return(-9);
+ }
+ x = *(vnp + 1); /* Fold case of array name */
+
+ /* We don't use isupper & tolower here on purpose because these */
+ /* would produce undesired effects with accented letters. */
+ if (x > 63 && x < 91) x = *(vnp + 1) = (char) (x + 32);
+ if ((x < ARRAYBASE) || (x > 122) || (*(vnp+2) != '[')) {
+ if (msgflg) {
+ printf("?Invalid format for array name - %s\n",vnbuf);
+ return(-9);
+ } else
+ return(-2);
+ }
+ *c = x; /* Return the array name */
+ s = vnp+3; /* Get dimension */
+ p = ssbuf;
+ pp = 1; /* Bracket counter */
+ for (i = 0; i < ARRAYREFLEN && *s != NUL; i++) { /* Copy up to ] */
+ if (*s == '[') pp++;
+ if (*s == ']' && --pp == 0) break;
+ *p++ = *s++;
+ }
+ if (*s != ']') {
+ printf("?No closing bracket on array dimension - %s\n",vnbuf);
+ return(-9);
+ }
+ p--; /* Trim whitespace from end */
+ while (*p == SP || *p == HT)
+ p--;
+ p++;
+ *p = NUL; /* Terminate subscript with null */
+ p = ssbuf; /* Point to beginning of subscript */
+ while (*p == SP || *p == HT) /* Trim whitespace from beginning */
+ p++;
+ sx = sxbuf; /* Where to put expanded subscript */
+ y = 16;
+ {
+ /* Even if VARIABLE-EVALUATION SIMPLE use RECURSIVE for subscripts */
+ /* NOTE: This is vulnerable to SIGINT and whatnot... */
+ int tmp = vareval; /* Save VARIABLE-EVALUATION setting */
+ vareval = 1; /* Force it to RECURSIVE */
+ zzstring(p,&sx,&y); /* Convert variables, etc. */
+ vareval = tmp; /* Restore VARIABLE-EVALUATION */
+ }
+ sx = sxbuf;
+ while (*sx == SP) sx++;
+ /* debug(F110,"arraynam sx","",sx); */
+ if (!*sx) { /* Empty brackets... */
+ *n = -17; /* (Secret code :-) */
+ return(-2);
+ }
+ p = evala(sx); /* Run it thru \fneval()... */
+ if (p) if (*p) ckstrncpy(sxbuf,p,16); /* We know it has to be a number. */
+
+ if (!chknum(sxbuf)) { /* Make sure it's all digits */
+ if (msgflg) {
+ printf("?Array dimension or subscript missing or not numeric\n");
+ return(-9);
+ } else
+ return(-2);
+ }
+ if ((y = atoi(sxbuf)) < 0) {
+ if (cmflgs == 0) printf("\n");
+ if (msgflg) {
+ printf("?Array dimension or subscript not positive or zero\n");
+ return(-9);
+ } else
+ return(-2);
+ }
+ *n = y; /* Return the subscript or dimension */
+ return(0);
+}
+
+/* chkarray returns 0 or greater if array exists, negative otherwise */
+
+int
+chkarray(a,i) int a, i; { /* Check if array is declared */
+ int x; /* and if subscript is in range */
+ if (a == 64) a = 96; /* Convert atsign to grave accent */
+ x = a - ARRAYBASE; /* Values must be in range 95-122 */
+#ifdef COMMENT
+ if (x == 0 && maclvl < 0) /* Macro arg vector but no macro */
+ return(0);
+#endif /* COMMENT */
+ if (x < 0 || x > 'z' - ARRAYBASE) /* Not in range */
+ return(-2);
+ if (a_ptr[x] == NULL) return(-1); /* Not declared */
+ if (i > a_dim[x]) return(-2); /* Declared but out of range. */
+ return(a_dim[x]); /* All ok, return dimension */
+}
+
+#ifdef COMMENT /* This isn't used. */
+char *
+arrayval(a,i) int a, i; { /* Return value of \&a[i] */
+ int x; char **p; /* (possibly NULL) */
+ if (a == 64) a = 96; /* Convert atsign to grave accent */
+ x = a - ARRAYBASE; /* Values must be in range 95-122 */
+ if (x < 0 || x > 27) return(NULL); /* Not in range */
+ if ((x > 0) && (p = a_ptr[x]) == NULL) /* Array not declared */
+ return(NULL);
+ if (i > a_dim[x]) /* Subscript out of range. */
+ return(NULL);
+ return(p[i]); /* All ok, return pointer to value. */
+}
+#endif /* COMMENT */
+
+/*
+ pusharray() is called when an array name is included in a LOCAL statement.
+ It moves the pointers from the global definition to the stack, and removes
+ the global definition. Later, if the same array is declared in the local
+ context, it occupies the global definition in the normal way. But when
+ popclvl() is called, it replaces the global definition with the one saved
+ here. The "secret code" is used to indicate to popclv() that it should
+ remove the global array when popping through this level -- otherwise if a
+ local array were declared that had no counterpart at any higher level, it
+ would never be deleted. This allows Algol-like inheritance to work both
+ on the way down and on the way back up.
+*/
+int
+pusharray(x,z) int x, z; {
+ int y;
+ debug(F000,"pusharray x","",x);
+ debug(F101,"pusharray z","",z);
+ y = chkarray(x,z);
+ debug(F101,"pusharray y","",y);
+ x -= ARRAYBASE; /* Convert name letter to index. */
+ if (x < 0 || x > 27)
+ return(-1);
+ if (y < 0) {
+ aa_ptr[cmdlvl][x] = (char **) NULL;
+ aa_dim[cmdlvl][x] = -23; /* Secret code (see popclvl()) */
+ } else {
+ aa_ptr[cmdlvl][x] = a_ptr[x];
+ aa_dim[cmdlvl][x] = y;
+ }
+ a_ptr[x] = (char **) NULL;
+ a_dim[x] = 0;
+ return(0);
+}
+
+/* P A R S E V A R -- Parse a variable name or array reference. */
+/*
+ Call with:
+ s = pointer to candidate variable name or array reference.
+ *c = address of integer in which to return variable ID.
+ *i = address of integer in which to return array subscript.
+ Returns:
+ -2: syntax error in variable name or array reference.
+ 1: successful parse of a simple variable, with ID in c.
+ 2: successful parse of an array reference, w/ID in c and subscript in i.
+*/
+int
+parsevar(s,c,i) char *s; int *c, *i; {
+ char *p;
+ int x,y,z;
+
+ p = s;
+ if (*s == CMDQ) s++; /* Point after backslash */
+
+ if (*s != '%' && *s != '&') { /* Make sure it's % or & */
+ printf("?Not a variable name - %s\n",p);
+ return(-9);
+ }
+ if ((int)strlen(s) < 2) {
+ printf("?Incomplete variable name - %s\n",p);
+ return(-9);
+ }
+ if (*s == '%' && *(s+2) != '\0') {
+ printf("?Only one character after '%%' in variable name, please\n");
+ return(-9);
+ }
+ if (*s == '&' && *(s+2) != '[') {
+ printf("?Array subscript expected - %s\n",p);
+ return(-9);
+ }
+ if (*s == '%') { /* Simple variable. */
+ y = *(s+1); /* Get variable ID letter/char */
+ if (isupper(y)) y -= ('a'-'A'); /* Convert upper to lower case */
+ *c = y; /* Set the return values. */
+ *i = -1; /* No array subscript. */
+ return(1); /* Return 1 = simple variable */
+ }
+ if (*s == '&') { /* Array reference. */
+ y = arraynam(s,&x,&z); /* Go parse it. */
+ debug(F101,"parsevar arraynam","",y);
+ if ((y) < 0) {
+ if (y == -2)
+ return(pusharray(x,z));
+ if (y != -9)
+ printf("?Invalid array reference - %s\n",p);
+ return(-9);
+ }
+ if (chkarray(x,z) < 0) { /* Check if declared, etc. */
+ printf("?Array not declared or subscript out of range\n");
+ return(-9);
+ }
+ *c = x; /* Return array letter */
+ *i = z; /* and subscript. */
+ return(2);
+ }
+ return(-2); /* None of the above. */
+}
+
+
+#define VALN 32
+
+/* Get the numeric value of a variable */
+/*
+ Call with pointer to variable name, pointer to int for return value.
+ Returns:
+ 0 on success with second arg containing the value.
+ -1 on failure (bad variable syntax, variable not defined or not numeric).
+*/
+int
+varval(s,v) char *s; CK_OFF_T *v; {
+ char valbuf[VALN+1]; /* s is pointer to variable name */
+ char name[256];
+ char *p;
+ int y;
+
+ if (*s != CMDQ) { /* Handle macro names too */
+ ckmakmsg(name,256,"\\m(",s,")",NULL);
+ s = name;
+ }
+ p = valbuf; /* Expand variable into valbuf. */
+ y = VALN;
+ if (zzstring(s,&p,&y) < 0) return(-1);
+ p = valbuf; /* Make sure value is numeric */
+ if (!*p) { /* Be nice -- let an undefined */
+ valbuf[0] = '0'; /* variable be treated as 0. */
+ valbuf[1] = NUL;
+ }
+ if (chknum(p)) { /* Convert numeric string to int */
+ *v = ckatofs(p); /* OK */
+ } else { /* Not OK */
+ p = evala(p); /* Maybe it's an expression */
+ if (!chknum(p)) /* Did it evaluate? */
+ return(-1); /* No, failure. */
+ else /* Yes, */
+ *v = ckatofs(p); /* success */
+ }
+ return(0);
+}
+
+/* Increment or decrement a variable */
+/* Returns -1 on failure, 0 on success */
+
+int
+incvar(s,x,z) char *s; CK_OFF_T x; int z; { /* Increment a numeric variable */
+ CK_OFF_T n; /* s is pointer to variable name */
+ /* x is amount to increment by */
+ /* z != 0 means add */
+ /* z = 0 means subtract */
+ if (varval(s,&n) < 0) /* Convert numeric string to int */
+ return(-1);
+ if (z) /* Increment it by the given amount */
+ n += x;
+ else /* or decrement as requested. */
+ n -= x;
+ addmac(s,ckfstoa(n)); /* Replace old variable */
+ return(0);
+}
+
+/* D O D O -- Do a macro */
+
+/*
+ Call with x = macro table index, s = pointer to arguments.
+ Returns 0 on failure, 1 on success.
+*/
+
+int
+dodo(x,s,flags) int x; char *s; int flags; {
+ int y;
+ extern int tra_asg, tra_cmd; int tra_tmp;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int term_io;
+ int term_io_sav = term_io;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ if (x < 0) /* It can happen! */
+ return(-1);
+
+ tra_tmp = tra_asg;
+
+ if (++maclvl >= MACLEVEL) { /* Make sure we have storage */
+ debug(F101,"dodo maclvl too deep","",maclvl);
+ --maclvl;
+ printf("Macros nested too deeply\n");
+ return(0);
+ }
+ macp[maclvl] = mactab[x].mval; /* Point to the macro body */
+ macx[maclvl] = mactab[x].mval; /* Remember where the beginning is */
+
+#ifdef COMMENT
+ makestr(&(m_line[maclvl]),s); /* Entire arg string for "\%*" */
+#endif /* COMMENT */
+
+ cmdlvl++; /* Entering a new command level */
+ if (cmdlvl >= CMDSTKL) { /* Too many macros + TAKE files? */
+ debug(F101,"dodo cmdlvl too deep","",cmdlvl);
+ cmdlvl--;
+ printf("?TAKE files and DO commands nested too deeply\n");
+ return(0);
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"CMD +M",mactab[x].kwd,cmdlvl);
+ debug(F010,"CMD ->",s,0);
+ }
+#endif /* DEBUG */
+
+#ifdef VMS
+ conres(); /* So Ctrl-C, etc, will work. */
+#endif /* VMS */
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = 0; /* Disable terminal emulator I/O */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ ifcmd[cmdlvl] = 0;
+ iftest[cmdlvl] = 0;
+ count[cmdlvl] = count[cmdlvl-1]; /* Inherit COUNT from previous level */
+ intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit previous INPUT TIMEOUT */
+ inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* and INPUT CASE */
+ takerr[cmdlvl] = takerr[cmdlvl-1]; /* and TAKE ERROR */
+ merror[cmdlvl] = merror[cmdlvl-1]; /* and MACRO ERROR */
+ xquiet[cmdlvl] = quiet;
+ xvarev[cmdlvl] = vareval;
+ xcmdsrc = CMD_MD;
+ cmdstk[cmdlvl].src = CMD_MD; /* Say we're in a macro */
+ cmdstk[cmdlvl].lvl = maclvl; /* and remember the macro level */
+ cmdstk[cmdlvl].ccflgs = flags & ~CF_IMAC; /* Set flags */
+
+ /* Initialize return value except in FOR, WHILE, IF, and SWITCH macros */
+
+ if (!(flags & CF_IMAC) && mrval[maclvl]) {
+ free(mrval[maclvl]);
+ mrval[maclvl] = NULL;
+ }
+
+ /* Clear old %0..%9 arguments */
+
+ addmac("%0",mactab[x].kwd); /* Define %0 = name of macro */
+ makestr(&(m_xarg[maclvl][0]),mactab[x].kwd);
+ varnam[0] = '%';
+ varnam[2] = '\0';
+ tra_asg = 0;
+ for (y = 1; y < 10; y++) { /* Clear args %1..%9 */
+ if (m_arg[maclvl][y]) { /* Don't call delmac() unless */
+ varnam[1] = (char) (y + '0'); /* we have to... */
+ delmac(varnam,0);
+ }
+ }
+ tra_asg = tra_tmp;
+
+/* Assign the new args one word per arg, allowing braces to group words */
+
+ xwords(s,MAXARGLIST,NULL,0);
+
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = term_io_sav;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ if (tra_cmd)
+ printf("[%d] +M: \"%s\"\n",cmdlvl,mactab[x].kwd);
+ return(1);
+}
+
+/* Insert "literal" quote around each comma-separated command to prevent */
+/* its premature expansion. Only do this if object command is surrounded */
+/* by braces. */
+
+static char* flit = "\\flit(";
+
+int
+litcmd(src,dest,n) char **src, **dest; int n; {
+ int bc = 0, pp = 0;
+ char c, *s, *lp, *ss;
+
+ s = *src;
+ lp = *dest;
+
+ debug(F010,"litcmd",s,0);
+
+ while (*s == SP) s++; /* Strip extra leading spaces */
+
+ if (*s == '{') { /* Starts with brace */
+ pp = 0; /* Paren counter */
+ bc = 1; /* Count leading brace */
+ *lp++ = *s++; /* Copy it */
+ if (--n < 1) return(-1); /* Check space */
+ while (*s == SP) s++; /* Strip interior leading spaces */
+ ss = flit; /* Point to "\flit(" */
+ while ((*lp++ = *ss++)) /* Copy it */
+ if (--n < 1) /* and check space */
+ return(-1);
+ lp--; /* Back up over null */
+
+ while (*s) { /* Go thru rest of text */
+ c = *s;
+ if (c == '{') bc++; /* Count brackets */
+ if (c == '(') pp++; /* and parens */
+ if (c == ')') { /* Right parenthesis. */
+ pp--; /* Count it. */
+ if (pp < 0) { /* An unbalanced right paren... */
+#ifdef COMMENT
+/*
+ The problem here is that "\{" appears to be a quoted brace and therefore
+ isn't counted; then the "}" matches an earlier opening brace, causing
+ (e.g.) truncation of macros by getncm().
+*/
+ if (n < 5) /* Out of space in dest buffer? */
+ return(-1); /* If so, give up. */
+ *lp++ = CMDQ; /* Must be quoted to prevent */
+ *lp++ = '}'; /* premature termination of */
+ *lp++ = '4'; /* \flit(...) */
+ *lp++ = '1';
+ *lp++ = '}';
+ n -= 5;
+#else
+/* Here we rely on the fact the \nnn never takes more than 3 digits */
+ if (n < 4) /* Out of space in dest buffer? */
+ return(-1); /* If so, give up. */
+ *lp++ = CMDQ; /* Must be quoted to prevent */
+ *lp++ = '0'; /* premature termination of */
+ *lp++ = '4'; /* \flit(...) */
+ *lp++ = '1';
+ n -= 4;
+#endif /* COMMENT */
+ pp++; /* Uncount it. */
+ s++;
+ continue;
+ }
+ }
+ if (c == '}') { /* Closing brace. */
+ if (--bc == 0) { /* Final one? */
+ *lp++ = ')'; /* Add closing paren for "\flit()" */
+ if (--n < 1) return(-1);
+ *lp++ = c;
+ if (--n < 1) return(-1);
+ s++;
+ break;
+ }
+ }
+ *lp++ = c; /* General case */
+ if (--n < 1) return(-1);
+ s++;
+ }
+ *lp = NUL;
+ } else { /* No brackets around, */
+ while ((*lp++ = *s++)) /* just copy. */
+ if (--n < 1)
+ return(-1);
+ lp--;
+ }
+ *src = s; /* Return updated source */
+ *dest = lp; /* and destination pointers */
+ if (bc) /* Fail if braces unbalanced */
+ return(-1);
+ else /* Otherwise succeed. */
+ return(0);
+}
+#endif /* NOSPL */
+
+/* Functions moved here from ckuusr.c to even out the module sizes... */
+
+/*
+ Breaks up string s -- IN PLACE! -- into a list of up to max words.
+ Pointers to each word go into the array list[].
+ max is the maximum number of words (pointers).
+ If list is NULL, then they are added to the macro table.
+ flag = 0 means the last field is to be one word, like all the other fields,
+ so anything after it is discarded.
+ flag = 1 means the last field extends to the end of the string, even if
+ there are lots of words left, so the last field contains the
+ remainder of the string.
+*/
+VOID
+xwords(s,max,list,flag) char *s; int max; char *list[]; int flag; {
+ char *p;
+ int b, i, k, q, y, z;
+#ifndef NOSPL
+ int macro;
+ macro = (list == NULL);
+ debug(F010,"xwords",s,0);
+#endif /* NOSPL */
+
+#ifdef XWORDSDEBUG
+ printf("XWORDS string=%s\n",s);
+ printf("XWORDS max=%d\n",max);
+#endif /* XWORDSDEBUG */
+ p = s; /* Pointer to beginning of string */
+ q = 0; /* Flag for doublequote removal */
+ b = 0; /* Flag for outer brace removal */
+ k = 0; /* Flag for in-word */
+ y = 0; /* Brace nesting level */
+ z = 0; /* "Word" counter, 0 thru max */
+
+ if (list)
+ for (i = 0; i <= max; i++) /* Initialize pointers */
+ list[i] = NULL;
+
+ if (flag) max--;
+
+ while (1) { /* Go thru word list */
+ if (!s || (*s == '\0')) { /* No more characters? */
+ if (k != 0) { /* Was I in a word? */
+ if (z == max) break; /* Yes, only go up to max. */
+ z++; /* Count this word. */
+#ifdef XWORDSDEBUG
+ printf("1 z++ = %d\n", z);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+ if (macro) { /* Doing macro args */
+ if (z < 10) {
+ varnam[1] = (char) (z + '0'); /* Assign last arg */
+ addmac(varnam,p);
+ }
+ if (z <= max) {
+#ifdef COMMENT
+ if (maclvl < 0)
+ addmac(varnam,p);
+ else
+#endif /* COMMENT */
+ makestr(&(m_xarg[maclvl][z]),p);
+ }
+ } else { /* Not doing macro args */
+#endif /* NOSPL */
+ list[z] = p; /* Assign pointer. */
+#ifdef XWORDSDEBUG
+ printf("[1]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+ }
+#endif /* NOSPL */
+ break; /* And get out. */
+ } else break; /* Was not in a word */
+ }
+ if (k == 0 && (*s == SP || *s == HT)) { /* Eat leading blanks */
+ s++;
+ continue;
+ } else if (q == 0 && *s == '{') { /* An opening brace */
+ if (k == 0 && y == 0) { /* If leading brace */
+ p = s+1; /* point past it */
+ b = 1; /* and flag that we did this */
+ }
+ k = 1; /* Flag that we're in a word */
+ y++; /* Count the brace. */
+ } else if (q == 0 && *s == '}') { /* A closing brace. */
+ y--; /* Count it. */
+ if (y <= 0 && b != 0) { /* If it matches the leading brace */
+ char c;
+ c = *(s+1);
+ if (!c || c == SP || c == HT) { /* at EOL or followed by SP */
+ *s = SP; /* change it to a space */
+ b = 0; /* and we're not in braces any more */
+ }
+ }
+#ifdef DOUBLEQUOTING
+ /* Opening doublequote */
+ } else if (k == 0 && b == 0 && *s == '"' && dblquo) {
+ y++;
+ p = s+1; /* point past it */
+ q = 1; /* and flag that we did this */
+ k = 1; /* Flag that we're in a word */
+ /* Closing double quote */
+ } else if (q > 0 && k > 0 && b == 0 && *s == '"' && dblquo) {
+ char c;
+ c = *(s+1);
+ if (!c || c == SP || c == HT) { /* at EOL or followed by SP */
+ y--;
+ *s = SP; /* change it to a space */
+ q = 0; /* and we're not in quotes any more */
+ }
+#endif /* DOUBLEQUOTING */
+
+ } else if (*s != SP && *s != HT) { /* Nonspace means we're in a word */
+ if (k == 0) { /* If we weren't in a word before, */
+ p = s; /* Mark the beginning */
+ if (flag && z == max) { /* Want last word to be remainder? */
+ z++;
+#ifdef XWORDSDEBUG
+ printf("1 z++ = %d\n", z);
+#endif /* XWORDSDEBUG */
+ list[z] = p; /* Yes, point to it */
+#ifdef XWORDSDEBUG
+ printf("[4]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+ break; /* and quit */
+ }
+ k = 1; /* Set in-word flag */
+ }
+ }
+ /* If we're not inside a braced quantity, and we are in a word, and */
+ /* we have hit whitespace, then we have a word. */
+ if ((y < 1) && (k != 0) && (*s == SP || *s == HT) && !b) {
+ if (!flag || z < max) /* if we don't want to keep rest */
+ *s = '\0'; /* terminate the arg with null */
+ k = 0; /* say we're not in a word any more */
+ y = 0; /* start braces off clean again */
+ if (z == max) break; /* Only go up to max. */
+ z++; /* count this arg */
+#ifdef XWORDSDEBUG
+ printf("1 z++ = %d\n", z);
+#endif /* XWORDSDEBUG */
+
+#ifndef NOSPL
+ if (macro) {
+ if (z < 10) {
+ varnam[1] = (char) (z + '0'); /* compute its name */
+ addmac(varnam,p); /* add it to the macro table */
+ }
+ if (z <= max) {
+#ifdef COMMENT
+ if (maclvl < 0)
+ addmac(varnam,p);
+ else
+#endif /* COMMENT */
+ makestr(&(m_xarg[maclvl][z]),p);
+ }
+ } else {
+#endif /* NOSPL */
+ list[z] = p;
+#ifdef XWORDSDEBUG
+ printf("[2]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+ }
+#endif /* NOSPL */
+ p = s+1;
+ }
+ s++; /* Point past this character */
+ }
+ if ((z == 0) && (y > 1)) { /* Extra closing brace(s) at end */
+ z++;
+#ifndef NOSPL
+ if (macro) {
+ if (z < 10) {
+ varnam[1] = z + '0'; /* compute its name */
+ addmac(varnam,p); /* Add rest of line to last arg */
+ }
+ if (z <= max) {
+#ifdef COMMENT
+ if (maclvl < 0)
+ addmac(varnam,p);
+ else
+#endif /* COMMENT */
+ makestr(&(m_xarg[maclvl][z]),p);
+ }
+ } else {
+#endif /* NOSPL */
+ list[z] = p;
+#ifdef XWORDSDEBUG
+ printf("[3]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+ }
+#endif /* NOSPL */
+ }
+#ifndef NOSPL
+ if (macro) { /* Macro */
+ if (maclvl < 0) {
+ a_dim[0] = z; /* Array dimension is one less */
+ topargc = z + 1; /* than \v(argc) */
+ debug(F111,"a_dim[0]","D",a_dim[0]);
+ } else {
+ macargc[maclvl] = z + 1; /* Set \v(argc) variable */
+ n_xarg[maclvl] = z + 1; /* This is the actual number */
+ a_ptr[0] = m_xarg[maclvl]; /* Point \&_[] at the args */
+ a_dim[0] = z; /* And give it this dimension */
+ debug(F111,"a_dim[0]","E",a_dim[0]);
+ }
+ }
+#endif /* NOSPL */
+ return;
+}
+
+#ifndef NOSPL
+
+/* D O S H I F T -- Do the SHIFT Command; shift macro args left by n */
+
+/* Note: at some point let's consolidate m_arg[][] and m_xarg[][]. */
+
+int
+doshift(n) int n; { /* n = shift count */
+ int i, top, level;
+ char /* *s, *m, */ buf[6]; /* Buffer to build scalar names */
+ char * sx = tmpbuf;
+ int nx = TMPBUFSIZ;
+
+ debug(F101,"SHIFT count","",n);
+ debug(F101,"SHIFT topargc","",topargc);
+
+ if (n < 1) /* Stay in range */
+ return(n == 0 ? 1 : 0);
+
+ level = maclvl;
+ top = (level < 0) ? topargc : macargc[level];
+
+ if (n >= top)
+ n = top - 1;
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"SHIFT count 2","",n);
+ debug(F101,"SHIFT level","",level);
+ if (level > -1)
+ debug(F101,"SHIFT macargc[level]","",macargc[level]);
+ }
+#endif /* DEBUG */
+
+ buf[0] = '\\'; /* Initialize name template */
+ buf[1] = '%';
+ buf[2] = NUL;
+ buf[3] = NUL;
+
+ for (i = 1; i <= n; i++) { /* Free shifted-over args */
+ if (level < 0) {
+ makestr(&(toparg[i]),NULL);
+ } else {
+ makestr(&(m_xarg[level][i]),NULL);
+ }
+ if (i < 10) { /* Is this necessary? */
+ buf[2] = (char)(i+'0');
+ delmac(buf,0);
+ }
+ }
+ for (i = 1; i <= top-n; i++) { /* Shift remaining args */
+ if (level < 0) {
+#ifdef COMMENT
+ toparg[i] = toparg[i+n]; /* Full vector */
+#else
+ makestr(&(toparg[i]),toparg[i+n]); /* Full vector */
+#endif /* COMMENT */
+ if (i < 10) /* Scalars... */
+ makestr(&(g_var[i+'0']),toparg[i+n]);
+ } else {
+#ifdef COMMENT
+ m_xarg[level][i] = m_xarg[level][i+n];
+#else
+ makestr(&(m_xarg[level][i]),m_xarg[level][i+n]);
+#endif /* COMMENT */
+ if (i < 10) {
+ buf[2] = (char)(i+'0');
+ debug(F010,"SHIFT buf",buf,0);
+ addmac(buf,m_xarg[level][i+n]);
+ }
+ }
+ }
+ for (i = top-n; i <= top; i++) { /* Clear n args from the end */
+ if (level < 0) {
+#ifdef COMMENT
+ toparg[i] = NULL;
+#else
+ makestr(&(toparg[i]),NULL);
+#endif /* COMMENt */
+ if (i < 10)
+ makestr(&(g_var[i+'0']),NULL);
+ } else {
+#ifdef COMMENT
+ m_xarg[level][i] = NULL;
+#else
+ makestr(&(m_xarg[level][i]),NULL);
+#endif /* COMMENt */
+ if (i < 10) {
+ buf[2] = (char)(i+'0');
+ delmac(buf,0);
+ }
+ }
+ }
+ if (level > -1) { /* Macro args */
+ macargc[level] -= n; /* Adjust count */
+ n_xarg[maclvl] = macargc[level]; /* Here too */
+ a_dim[0] = macargc[level] - 1; /* Adjust array dimension */
+ debug(F111,"a_dim[0]","F",a_dim[0]);
+ zzstring("\\fjoin(&_[],{ },1)",&sx,&nx); /* Handle \%* */
+#ifdef COMMENT
+ makestr(&(m_line[level]),tmpbuf);
+#endif /* COMMENT */
+ } else { /* Ditto for top level */
+ topargc -= n;
+ a_dim[0] = topargc - 1;
+ debug(F111,"a_dim[0]","G",a_dim[0]);
+ zzstring("\\fjoin(&_[],{ },1)",&sx,&nx);
+#ifdef COMMENT
+ makestr(&topline,tmpbuf);
+#endif /* COMMENT */
+ }
+ return(1);
+}
+#endif /* NOSPL */
+
+int
+docd(cx) int cx; { /* Do the CD command */
+ int x;
+ extern int server, srvcdmsg, cdactive;
+ extern char * cdmsgfile[], * ckcdpath;
+ char *s, *p;
+#ifdef MAC
+ char temp[34];
+#endif /* MAC */
+#ifdef IKSDCONF
+extern int iksdcf;
+#endif /* IKSDCONF */
+
+#ifndef NOFRILLS
+ if (cx == XXBACK) {
+ if ((x = cmcfm()) < 0)
+ cwdf = 1;
+ if (prevdir) {
+ s = zgtdir();
+ if (!zchdir(prevdir)) {
+ cwdf = 0;
+ perror(s);
+ } else {
+ makestr(&prevdir,s);
+ }
+ }
+ return(cwdf);
+ }
+#endif /* NOFRILLS */
+
+ if (cx == XXCDUP) {
+#ifdef VMS
+ s = "[-]";
+#else
+#ifdef datageneral
+ s = "^";
+#else
+ s = "..";
+#endif /* datageneral */
+#endif /* VMS */
+ ckstrncpy(line,s,LINBUFSIZ);
+ goto gocd;
+ }
+#ifndef NOSPL
+ if (cx == XXKCD) { /* Symbolic (Kermit) CD */
+ char * p;
+ int n, k;
+ x = cmkey(kcdtab,nkcdtab,"Symbolic directory name","home",xxstring);
+ if (x < 0)
+ return(x);
+ x = lookup(kcdtab,atmbuf,nkcdtab,&k); /* Get complete keyword */
+ if (x < 0) {
+ printf("?Lookup error\n"); /* shouldn't happen */
+ return(-9);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (k == VN_HOME) { /* HOME: allow SET HOME to override */
+ ckstrncpy(line,homepath(),LINBUFSIZ);
+ } else { /* Other symbolic name */
+ /* Convert to variable syntax */
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"\\v(",kcdtab[k].kwd,")",NULL);
+ p = line; /* Expand the variable */
+ n = LINBUFSIZ;
+ zzstring(tmpbuf,&p,&n);
+ if (!line[0]) { /* Fail if variable not defined */
+ printf("?%s - not defined\n",tmpbuf);
+ return(success = 0);
+ }
+ }
+ s = line; /* All OK, go try to CD... */
+ goto gocd;
+ }
+#endif /* NOSPL */
+
+ cdactive = 1;
+#ifdef GEMDOS
+ if ((x = cmdir("Name of local directory, or carriage return",
+ homepath(),
+ &s,
+ NULL
+ )
+ ) < 0 )
+ return(x);
+#else
+#ifdef OS2
+ if ((x = cmdirp("Name of PC disk and/or directory,\n\
+ or press the Enter key for the default",
+ homepath(),
+ &s,
+ ckcdpath ? ckcdpath : getenv("CDPATH"),
+ xxstring
+ )
+ ) < 0 )
+ return(x);
+#else
+#ifdef MAC
+ x = ckstrncpy(temp,homepath(),32);
+ if (x > 0) if (temp[x-1] != ':') { temp[x] = ':'; temp[x+1] = NUL; }
+ if ((x = cmtxt("Name of Macintosh volume and/or folder,\n\
+ or press the Return key for the desktop on the boot disk",
+ temp,&s, xxstring)) < 0 )
+ return(x);
+#else
+ if ((x = cmdirp("Carriage return for home directory,\n\
+or name of directory on this computer",
+#ifdef VMS
+ "SYS$LOGIN", /* With no colon */
+#else
+ homepath(), /* In VMS this is "SYS$LOGIN:" */
+#endif /* VMS */
+ &s,
+ ckcdpath ? ckcdpath : getenv("CDPATH"),
+ xxstring
+ )) < 0)
+ return(x);
+#endif /* MAC */
+#endif /* OS2 */
+#endif /* GEMDOS */
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */
+ s = line;
+#ifdef VMS
+ if (ckmatch("*.DIR;1$",s,0,0))
+ if (cvtdir(s,tmpbuf,TMPBUFSIZ) > 0)
+ s = tmpbuf;
+#endif /* VMS */
+ debug(F110,"docd",s,0);
+#ifndef MAC
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+#endif /* MAC */
+
+ gocd:
+
+#ifdef datageneral
+ x = strlen(line); /* homdir ends in colon, */
+ if (x > 1 && line[x-1] == ':') /* and "dir" doesn't like that... */
+ line[x-1] = NUL;
+#endif /* datageneral */
+
+#ifdef MAC
+ cwdf = 1;
+ if (!zchdir(s)) {
+ cwdf = 0;
+ if (*s != ':') { /* If it failed, */
+ char *p; /* supply leading colon */
+ int len = (int)strlen(s) + 2;
+ p = malloc(len); /* and try again... */
+ if (p) {
+ strcpy(p,":"); /* safe */
+ strcat(p,s); /* safe */
+ if (zchdir(p))
+ cwdf = 1;
+ free(p);
+ p = NULL;
+ }
+ }
+ }
+ if (!cwdf)
+ perror(s);
+#else
+ p = zgtdir();
+ if (!zchdir(s)) {
+ cwdf = 0;
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off limits: \"%s\"\n",s);
+ else
+#endif /* CKROOT */
+ perror(s);
+ } else cwdf = 1;
+#endif /* MAC */
+
+ x = 0;
+ if (cwdf) {
+ makestr(&prevdir,p);
+ debug(F111,"docd","srvcdmsg",srvcdmsg);
+ if (srvcdmsg
+#ifdef IKSDCONF
+ && !(inserver && !iksdcf)
+#endif /* IKSDCONF */
+ ) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ debug(F111,"docd cdmsgfile[i]",cdmsgfile[i],i);
+ if (zchki(cdmsgfile[i]) > -1) {
+ x = 1;
+ dotype(cdmsgfile[i],xaskmore,0,0,NULL,0,NULL,0,0,NULL,0);
+ break;
+ }
+ }
+ }
+ }
+/* xdocd: */
+ if (!x && srvcdmsg && !server
+#ifdef IKSDCONF
+ && !(inserver && !iksdcf)
+#endif /* IKSDCONF */
+ && !quiet && !xcmdsrc)
+ printf("%s\n", zgtdir());
+
+ return(cwdf);
+}
+
+static int on_ctrlc = 0;
+
+VOID
+fixcmd() { /* Fix command parser after interruption */
+#ifndef NOSPL
+#ifndef NOONCTRLC
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * s = "on_ctrlc"; /* Name of Ctrl-C handling macro */
+ k = mlook(mactab,s,nmac); /* Look it up. */
+ if (k >= 0) { /* If found, */
+ if (on_ctrlc++ == 0) { /* if not already executing, */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* execute it, */
+ }
+ delmac(s,1); /* and undefine it. */
+ }
+ }
+ on_ctrlc = 0;
+#endif /* NOONCTRLC */
+#endif /* NOSPL */
+ dostop(); /* Back to top level (also calls conint()). */
+ bgchk(); /* Check background status */
+ if (*psave) { /* If old prompt saved, */
+ cmsetp(psave); /* restore it. */
+ *psave = NUL;
+ }
+ success = 0; /* Tell parser last command failed */
+}
+
+#ifndef NOSHOW /* SHOW FEATURES */
+/*
+ Note, presently optlist[] index overflow is not checked.
+ There is plenty of room (less than 360 entries for 1000 slots).
+ When space starts to get tight, check for noptlist >= NOPTLIST
+ every time noptlist is incremented.
+*/
+#define NOPTLIST 1024
+static int noptlist = 0;
+static char * optlist[NOPTLIST+1];
+static int hpos = 0;
+
+int
+prtopt(lines,s) int * lines; char *s; { /* Print an option */
+ int y, i; /* Does word wrap. */
+ if (!s) s = "";
+ i = *lines;
+ if (!*s) { /* Empty argument */
+ if (hpos > 0) { /* means to end this line. */
+ printf("\n"); /* Not needed if already at */
+ if (++i > (cmd_rows - 3)) { /* beginning of new line. */
+ if (!askmore())
+ return(0);
+ else
+ i = 0;
+ }
+ }
+ printf("\n"); /* And then make a blank line */
+ if (++i > (cmd_rows - 3)) {
+ if (!askmore())
+ return(0);
+ else
+ i = 0;
+ }
+ hpos = 0;
+ *lines = i;
+ return(1);
+ }
+ y = (int)strlen(s) + 1;
+ hpos += y;
+ debug(F101,"prtopt hpos","",hpos);
+ debug(F101,"prtopt cmd_cols","",cmd_cols);
+
+ if (
+#ifdef OS2
+ hpos > ((cmd_cols > 40) ? (cmd_cols - 1) : 79)
+#else /* OS2 */
+ hpos > ((tt_cols > 40) ? (tt_cols - 1) : 79)
+#endif /* OS2 */
+ ) {
+ printf("\n");
+ if (++i > (cmd_rows - 3)) {
+ if (!askmore())
+ return(0);
+ else
+ i = 0;
+ }
+ printf(" %s",s);
+ hpos = y;
+ } else
+ printf(" %s",s);
+ *lines = i;
+ return(1);
+}
+
+static VOID
+initoptlist() {
+ int i;
+ if (noptlist > 0)
+ return;
+ for (i = 0; i < NOPTLIST; i++)
+ optlist[i] = NULL;
+
+#ifdef MAC
+#ifdef MPW
+ makestr(&(optlist[noptlist++]),"MPW");
+#endif /* MPW */
+#endif /* MAC */
+
+#ifdef MAC
+#ifdef THINK_C
+ makestr(&(optlist[noptlist++]),"THINK_C");
+#endif /* THINK_C */
+#endif /* MAC */
+
+#ifdef __386__
+ makestr(&(optlist[noptlist++]),"__386__");
+#endif /* __386__ */
+
+/* Memory models... */
+
+#ifdef __FLAT__
+ makestr(&(optlist[noptlist++]),"__FLAT__");
+#endif /* __FLAT__ */
+#ifdef __SMALL__
+ makestr(&(optlist[noptlist++]),"__SMALL__");
+#endif /* __SMALL__ */
+#ifdef __MEDIUM__
+ makestr(&(optlist[noptlist++]),"__MEDIUM__");
+#endif /* __MEDIUM__ */
+#ifdef __COMPACT__
+ makestr(&(optlist[noptlist++]),"__COMPACT__");
+#endif /* __COMPACT__ */
+#ifdef __LARGE__
+ makestr(&(optlist[noptlist++]),"__LARGE__");
+#endif /* __LARGE__ */
+
+#ifdef DEBUG
+#ifdef IFDEBUG
+ makestr(&(optlist[noptlist++]),"IFDEBUG");
+#else
+ makestr(&(optlist[noptlist++]),"DEBUG");
+#endif /* IFDEBUG */
+#endif /* DEBUG */
+#ifdef TLOG
+ makestr(&(optlist[noptlist++]),"TLOG");
+#endif /* TLOG */
+#ifdef BIGBUFOK
+ makestr(&(optlist[noptlist++]),"BIGBUFOK");
+#endif /* BIGBUFOK */
+#ifdef INPBUFSIZ
+ sprintf(line,"INPBUFSIZ=%d",INPBUFSIZ); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* INPBUFSIZE */
+#ifdef LINBUFSIZ
+ sprintf(line,"LINBUFSIZ=%d",LINBUFSIZ); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* LINBUFSIZE */
+#ifdef INBUFSIZE
+ sprintf(line,"INBUFSIZE=%d",INBUFSIZE); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* INBUFSIZE */
+#ifdef OBUFSIZE
+ sprintf(line,"OBUFSIZE=%d",OBUFSIZE); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* OBUFSIZE */
+#ifdef FD_SETSIZE
+ sprintf(line,"FD_SETSIZE=%d",FD_SETSIZE); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* FD_SETSIZE */
+#ifdef XFRCAN
+ makestr(&(optlist[noptlist++]),"XFRCAN");
+#endif /* XFRCAN */
+#ifdef XPRINT
+ makestr(&(optlist[noptlist++]),"XPRINT");
+#endif /* XPRINT */
+#ifdef PIPESEND
+ makestr(&(optlist[noptlist++]),"PIPESEND");
+#endif /* PIPESEND */
+#ifdef CK_SPEED
+ makestr(&(optlist[noptlist++]),"CK_SPEED");
+#endif /* CK_SPEED */
+#ifdef CK_FAST
+ makestr(&(optlist[noptlist++]),"CK_FAST");
+#endif /* CK_FAST */
+#ifdef CK_APC
+ makestr(&(optlist[noptlist++]),"CK_APC");
+#endif /* CK_APC */
+#ifdef CK_AUTODL
+ makestr(&(optlist[noptlist++]),"CK_AUTODL");
+#endif /* CK_AUTODL */
+#ifdef CK_MKDIR
+ makestr(&(optlist[noptlist++]),"CK_MKDIR");
+#endif /* CK_MKDIR */
+#ifdef NOMKDIR
+ makestr(&(optlist[noptlist++]),"NOMKDIR");
+#endif /* NOMKDIR */
+#ifdef CK_LABELED
+ makestr(&(optlist[noptlist++]),"CK_LABELED");
+#endif /* CK_LABELED */
+#ifdef NODIAL
+ makestr(&(optlist[noptlist++]),"NODIAL");
+#endif /* NODIAL */
+#ifdef MINIDIAL
+ makestr(&(optlist[noptlist++]),"MINIDIAL");
+#endif /* MINIDIAL */
+#ifdef WHATAMI
+ makestr(&(optlist[noptlist++]),"WHATAMI");
+#endif /* WHATAMI */
+#ifdef DYNAMIC
+ makestr(&(optlist[noptlist++]),"DYNAMIC");
+#endif /* DYNAMIC */
+#ifndef NOSPL
+ sprintf(line,"CMDDEP=%d",CMDDEP); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* NOSPL */
+
+#ifdef MAXPATHLEN
+ sprintf(line,"MAXPATHLEN=%d",MAXPATHLEN); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXPATHLEN */
+
+#ifdef DEVNAMLEN
+ sprintf(line,"DEVNAMLEN=%d",DEVNAMLEN); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* DEVNAMLEN */
+
+#ifdef NO_PARAM_H
+ makestr(&(optlist[noptlist++]),"NO_PARAM_H");
+#endif /* NO_PARAM_H */
+
+#ifdef INCL_PARAM_H
+ makestr(&(optlist[noptlist++]),"INCL_PARAM_H");
+#endif /* INCL_PARAM_H */
+
+ sprintf(line,"CKMAXPATH=%d",CKMAXPATH); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+
+ sprintf(line,"CKMAXOPEN=%d",CKMAXOPEN); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+
+ sprintf(line,"Z_MAXCHAN=%d",Z_MAXCHAN); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+
+#ifdef OPEN_MAX
+ sprintf(line,"OPEN_MAX=%d",OPEN_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* OPEN_MAX */
+
+#ifdef _POSIX_OPEN_MAX
+ sprintf(line,"_POSIX_OPEN_MAX=%d",_POSIX_OPEN_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* _POSIX_OPEN_MAX */
+
+#ifdef CKCHANNELIO
+ {
+ extern int z_maxchan;
+#ifdef UNIX
+ extern int ckmaxfiles;
+ sprintf(line,"ckmaxfiles=%d",ckmaxfiles); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* UNIX */
+ sprintf(line,"z_maxchan=%d",z_maxchan); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+ }
+#endif /* CKCHANNELIO */
+
+#ifdef FOPEN_MAX
+ sprintf(line,"FOPEN_MAX=%d",FOPEN_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* FOPEN_MAX */
+
+#ifdef MAXGETPATH
+ sprintf(line,"MAXGETPATH=%d",MAXGETPATH); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXGETPATH */
+
+#ifdef CMDBL
+ sprintf(line,"CMDBL=%d",CMDBL); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* CMDBL */
+
+#ifdef VNAML
+ sprintf(line,"VNAML=%d",VNAML); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* VNAML */
+
+#ifdef ARRAYREFLEN
+ sprintf(line,"ARRAYREFLEN=%d",ARRAYREFLEN); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* ARRAYREFLEN */
+
+#ifdef UIDBUFLEN
+ sprintf(line,"UIDBUFLEN=%d",UIDBUFLEN); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* UIDBUFLEN */
+
+#ifdef FORDEPTH
+ sprintf(line,"FORDEPTH=%d",FORDEPTH); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* FORDEPTH */
+
+#ifdef MAXTAKE
+ sprintf(line,"MAXTAKE=%d",MAXTAKE); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXTAKE */
+
+#ifdef MACLEVEL
+ sprintf(line,"MACLEVEL=%d",MACLEVEL); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MACLEVEL */
+
+#ifdef MAC_MAX
+ sprintf(line,"MAC_MAX=%d",MAC_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAC_MAX */
+
+#ifdef _LARGEFILE_SOURCE
+ makestr(&(optlist[noptlist++]),"_LARGEFILE_SOURCE");
+#endif /* _LARGEFILE_SOURCE */
+
+#ifdef _FILE_OFFSET_BITS
+ sprintf(line,"_FILE_OFFSET_BITS=%d",_FILE_OFFSET_BITS); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* _FILE_OFFSET_BITS */
+
+#ifdef __USE_FILE_OFFSET64
+ makestr(&(optlist[noptlist++]),"__USE_FILE_OFFSET64");
+#endif /* __USE_FILE_OFFSET64 */
+
+#ifdef __USE_LARGEFILE64
+ makestr(&(optlist[noptlist++]),"__USE_LARGEFILE64");
+#endif /* __USE_LARGEFILE64 */
+
+#ifdef COMMENT
+#ifdef CHAR_MAX
+ sprintf(line,"CHAR_MAX=%llx",CHAR_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* CHAR_MAX */
+#ifdef UCHAR_MAX
+ sprintf(line,"UCHAR_MAX=%llx",UCHAR_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* UCHAR_MAX */
+#ifdef SHRT_MAX
+ sprintf(line,"SHRT_MAX=%llx",SHRT_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* SHRT_MAX */
+#ifdef USHRT_MAX
+ sprintf(line,"USHRT_MAX=%llx",USHRT_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* USHRT_MAX */
+#ifdef INT_MAX
+ sprintf(line,"INT_MAX=%llx",INT_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* INT_MAX */
+#ifdef UINT_MAX
+ sprintf(line,"UINT_MAX=%llx",UINT_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* UINT_MAX */
+#ifdef MAX_LONG
+ sprintf(line,"MAX_LONG=%llx",MAX_LONG); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAX_LONG */
+#ifdef LONG_MAX
+ sprintf(line,"LONG_MAX=%llx",LONG_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* LONG_MAX */
+#ifdef ULONG_MAX
+ sprintf(line,"ULONG_MAX=%llx",ULONG_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* ULONG_MAX */
+#ifdef MAXINT
+ sprintf(line,"MAXINT=%llx",MAXINT); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXINT */
+#ifdef MAXLONG
+ sprintf(line,"MAXLONG=%llx",MAXLONG); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXLONG */
+#ifdef NT
+#ifdef LLONG_MAX
+ sprintf(line,"LLONG_MAX=%I64x",LLONG_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* LLONG_MAX */
+#ifdef ULLONG_MAX
+ sprintf(line,"ULLONG_MAX=%I64x",ULLONG_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* ULLONG_MAX */
+#ifdef MAXLONGLONG
+ sprintf(line,"MAXLONGLONG=%I64x",MAXLONGLONG); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXLONGLONG */
+#else
+#ifdef LLONG_MAX
+ sprintf(line,"LLONG_MAX=%llx",LLONG_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* LLONG_MAX */
+#ifdef ULLONG_MAX
+ sprintf(line,"ULLONG_MAX=%llx",ULLONG_MAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* ULLONG_MAX */
+#ifdef MAXLONGLONG
+ sprintf(line,"MAXLONGLONG=%llx",MAXLONGLONG); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXLONGLONG */
+#endif
+#ifdef _INTEGRAL_MAX_BITS
+ sprintf(line,"_INTEGRAL_MAX_BITS=%d",_INTEGRAL_MAX_BITS); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* _INTEGRAL_MAX_BITS */
+#endif /* COMMENT */
+
+#ifdef MINPUTMAX
+ sprintf(line,"MINPUTMAX=%d",MINPUTMAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MINPUTMAX */
+
+#ifdef MAXWLD
+ sprintf(line,"MAXWLD=%d",MAXWLD); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#else
+#ifdef OS2
+ makestr(&(optlist[noptlist++]),"MAXWLD=unlimited");
+#endif /* OS2 */
+#endif /* MAXWLD */
+
+#ifdef MSENDMAX
+ sprintf(line,"MSENDMAX=%d",MSENDMAX); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MSENDMAX */
+
+#ifdef MAXDDIR
+ sprintf(line,"MAXDDIR=%d",MAXDDIR); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXDDIR */
+
+#ifdef MAXDNUMS
+ sprintf(line,"MAXDNUMS=%d",MAXDNUMS); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* MAXDNUMS */
+
+#ifdef UNIX
+ makestr(&(optlist[noptlist++]),"UNIX");
+#endif /* UNIX */
+
+#ifdef VMS
+ makestr(&(optlist[noptlist++]),"VMS");
+#ifdef __VMS_VER
+ sprintf(line,"__VMS_VER=%d",__VMS_VER); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* __VMS_VER */
+#ifdef VMSV70
+ makestr(&(optlist[noptlist++]),"VMSV70");
+#endif /* VMSV70 */
+#ifdef OLD_VMS
+ makestr(&(optlist[noptlist++]),"OLD_VMS");
+#endif /* OLD_VMS */
+#ifdef vms
+ makestr(&(optlist[noptlist++]),"vms");
+#endif /* vms */
+#ifdef VMSV60
+ makestr(&(optlist[noptlist++]),"VMSV60");
+#endif /* VMSV60 */
+#ifdef VMSV80
+ makestr(&(optlist[noptlist++]),"VMSV80");
+#endif /* VMSV80 */
+#ifdef VMSSHARE
+ makestr(&(optlist[noptlist++]),"VMSSHARE");
+#endif /* VMSSHARE */
+#ifdef NOVMSSHARE
+ makestr(&(optlist[noptlist++]),"NOVMSSHARE");
+#endif /* NOVMSSHARE */
+#endif /* VMS */
+
+#ifdef datageneral
+ makestr(&(optlist[noptlist++]),"datageneral");
+#endif /* datageneral */
+#ifdef apollo
+ makestr(&(optlist[noptlist++]),"apollo");
+#endif /* apollo */
+#ifdef aegis
+ makestr(&(optlist[noptlist++]),"aegis");
+#endif /* aegis */
+#ifdef A986
+ makestr(&(optlist[noptlist++]),"A986");
+#endif /* A986 */
+#ifdef AMIGA
+ makestr(&(optlist[noptlist++]),"AMIGA");
+#endif /* AMIGA */
+#ifdef CONVEX9
+ makestr(&(optlist[noptlist++]),"CONVEX9");
+#endif /* CONVEX9 */
+#ifdef CONVEX10
+ makestr(&(optlist[noptlist++]),"CONVEX10");
+#endif /* CONVEX9 */
+#ifdef MAC
+ makestr(&(optlist[noptlist++]),"MAC");
+#endif /* MAC */
+#ifdef AUX
+ makestr(&(optlist[noptlist++]),"AUX");
+#endif /* AUX */
+
+#ifdef OS2
+ makestr(&(optlist[noptlist++]),"OS2");
+#ifdef NT
+ makestr(&(optlist[noptlist++]),"NT");
+#endif /* NT */
+#endif /* OS2 */
+
+#ifdef OSK
+ makestr(&(optlist[noptlist++]),"OS9");
+#endif /* OSK */
+
+#ifdef MSDOS
+ makestr(&(optlist[noptlist++]),"MSDOS");
+#endif /* MSDOS */
+
+#ifdef DIRENT
+ makestr(&(optlist[noptlist++]),"DIRENT");
+#endif /* DIRENT */
+
+#ifdef SDIRENT
+ makestr(&(optlist[noptlist++]),"SDIRENT");
+#endif /* SDIRENT */
+
+#ifdef NDIR
+ makestr(&(optlist[noptlist++]),"NDIR");
+#endif /* NDIR */
+
+#ifdef XNDIR
+ makestr(&(optlist[noptlist++]),"XNDIR");
+#endif /* XNDIR */
+
+#ifdef SAVEDUID
+ makestr(&(optlist[noptlist++]),"SAVEDUID");
+#endif /* SAVEDUID */
+
+#ifdef RENAME
+ makestr(&(optlist[noptlist++]),"RENAME");
+#endif /* RENAME */
+
+#ifdef CK_TMPDIR
+ makestr(&(optlist[noptlist++]),"CK_TMPDIR");
+#endif /* CK_TMPDIR */
+
+#ifdef NOCCTRAP
+ makestr(&(optlist[noptlist++]),"NOCCTRAP");
+#endif /* NOCCTRAP */
+
+#ifdef NOCOTFMC
+ makestr(&(optlist[noptlist++]),"NOCOTFMC");
+#endif /* NOCOTFMC */
+
+#ifdef NOFRILLS
+ makestr(&(optlist[noptlist++]),"NOFRILLS");
+#endif /* NOFRILLS */
+
+#ifdef PARSENSE
+ makestr(&(optlist[noptlist++]),"PARSENSE");
+#endif /* PARSENSE */
+
+#ifdef TIMEH
+ makestr(&(optlist[noptlist++]),"TIMEH");
+#endif /* TIMEH */
+
+#ifdef NOTIMEH
+ makestr(&(optlist[noptlist++]),"TIMEH");
+#endif /* NOTIMEH */
+
+#ifdef SYSTIMEH
+ makestr(&(optlist[noptlist++]),"SYSTIMEH");
+#endif /* SYSTIMEH */
+
+#ifdef NOSYSTIMEH
+ makestr(&(optlist[noptlist++]),"SYSTIMEH");
+#endif /* NOSYSTIMEH */
+
+#ifdef SYSTIMEBH
+ makestr(&(optlist[noptlist++]),"SYSTIMEBH");
+#endif /* SYSTIMEBH */
+
+#ifdef NOSYSTIMEBH
+ makestr(&(optlist[noptlist++]),"SYSTIMEBH");
+#endif /* NOSYSTIMEBH */
+
+#ifdef UTIMEH
+ makestr(&(optlist[noptlist++]),"UTIMEH");
+#endif /* UTIMEH */
+
+#ifdef SYSUTIMEH
+ makestr(&(optlist[noptlist++]),"SYSUTIMEH");
+#endif /* SYSUTIMEH */
+
+#ifdef CK_NEED_SIG
+ makestr(&(optlist[noptlist++]),"CK_NEED_SIG");
+#endif /* CK_NEED_SIG */
+
+#ifdef CK_TTYFD
+ makestr(&(optlist[noptlist++]),"CK_TTYFD");
+#endif /* CK_TTYFD */
+
+#ifdef NETCONN
+ makestr(&(optlist[noptlist++]),"NETCONN");
+#endif /* NETCONN */
+
+#ifdef TCPSOCKET
+ makestr(&(optlist[noptlist++]),"TCPSOCKET");
+#ifdef NOTCPOPTS
+ makestr(&(optlist[noptlist++]),"NOTCPOPTS");
+#endif /* NOTCPOPTS */
+#ifdef CK_DNS_SRV
+ makestr(&(optlist[noptlist++]),"CK_DNS_SRV");
+#endif /* CK_DNS_SRV */
+#ifdef NO_DNS_SRV
+ makestr(&(optlist[noptlist++]),"NO_DNS_SRV");
+#endif /* NO_DNS_SRV */
+#ifdef CKGHNLHOST
+ makestr(&(optlist[noptlist++]),"CKGHNLHOST");
+#endif /* CKGHNLHOST */
+#ifdef NOLISTEN
+ makestr(&(optlist[noptlist++]),"NOLISTEN");
+#endif /* NOLISTEN */
+#ifdef SOL_SOCKET
+ makestr(&(optlist[noptlist++]),"SOL_SOCKET");
+#endif /* SOL_SOCKET */
+#ifdef SO_OOBINLINE
+ makestr(&(optlist[noptlist++]),"SO_OOBINLINE");
+#endif /* SO_OOBINLNE */
+#ifdef SO_DONTROUTE
+ makestr(&(optlist[noptlist++]),"SO_DONTROUTE");
+#endif /* SO_DONTROUTE */
+#ifdef SO_KEEPALIVE
+ makestr(&(optlist[noptlist++]),"SO_KEEPALIVE");
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ makestr(&(optlist[noptlist++]),"SO_LINGER");
+#endif /* SO_LINGER */
+#ifdef TCP_NODELAY
+ makestr(&(optlist[noptlist++]),"TCP_NODELAY");
+#endif /* TCP_NODELAY */
+#ifdef SO_SNDBUF
+ makestr(&(optlist[noptlist++]),"SO_SNDBUF");
+#endif /* SO_SNDBUF */
+#ifdef SO_RCVBUF
+ makestr(&(optlist[noptlist++]),"SO_RCVBUF");
+#endif /* SO_RCVBUF */
+#ifdef h_addr
+ makestr(&(optlist[noptlist++]),"h_addr");
+#endif /* h_addr */
+#ifdef HADDRLIST
+ makestr(&(optlist[noptlist++]),"HADDRLIST");
+#endif /* HADDRLIST */
+#ifdef CK_SOCKS
+ makestr(&(optlist[noptlist++]),"CK_SOCKS");
+#ifdef CK_SOCKS5
+ makestr(&(optlist[noptlist++]),"CK_SOCKS5");
+#endif /* CK_SOCKS5 */
+#ifdef CK_SOCKS_NS
+ makestr(&(optlist[noptlist++]),"CK_SOCKS_NS");
+#endif /* CK_SOCKS_NS */
+#endif /* CK_SOCKS */
+#ifdef RLOGCODE
+ makestr(&(optlist[noptlist++]),"RLOGCODE");
+#endif /* RLOGCODE */
+#ifdef NETCMD
+ makestr(&(optlist[noptlist++]),"NETCMD");
+#endif /* NETCMD */
+#ifdef NONETCMD
+ makestr(&(optlist[noptlist++]),"NONETCMD");
+#endif /* NONETCMD */
+#ifdef NETPTY
+ makestr(&(optlist[noptlist++]),"NETPTY");
+#endif /* NETPTY */
+#ifdef CK_ENVIRONMENT
+ makestr(&(optlist[noptlist++]),"CK_ENVIRONMENT");
+#endif /* CK_ENVIRONMENT */
+#endif /* TCPSOCKET */
+#ifdef TNCODE
+ makestr(&(optlist[noptlist++]),"TNCODE");
+#endif /* TNCODE */
+#ifdef CK_FORWARD_X
+ makestr(&(optlist[noptlist++]),"CK_FORWARD_X");
+#endif /* CK_FORWARD_X */
+#ifdef TN_COMPORT
+ makestr(&(optlist[noptlist++]),"TN_COMPORT");
+#endif /* TN_COMPORT */
+#ifdef MULTINET
+ makestr(&(optlist[noptlist++]),"MULTINET");
+#endif /* MULTINET */
+#ifdef DEC_TCPIP
+ makestr(&(optlist[noptlist++]),"DEC_TCPIP");
+#endif /* DEC_TCPIP */
+#ifdef TCPWARE
+ makestr(&(optlist[noptlist++]),"TCPWARE");
+#endif /* TCPWARE */
+#ifdef UCX50
+ makestr(&(optlist[noptlist++]),"UCX50");
+#endif /* UCX50 */
+#ifdef CMU_TCPIP
+ makestr(&(optlist[noptlist++]),"CMU_TCPIP");
+#endif /* CMU_TCPIP */
+#ifdef TTLEBUF
+ makestr(&(optlist[noptlist++]),"TTLEBUF");
+#endif /* TTLEBUF */
+#ifdef NETLEBUF
+ makestr(&(optlist[noptlist++]),"NETLEBUF");
+#endif /* NETLEBUF */
+#ifdef IKS_OPTION
+ makestr(&(optlist[noptlist++]),"IKS_OPTION");
+#endif /* IKS_OPTION */
+#ifdef IKSDB
+ makestr(&(optlist[noptlist++]),"IKSDB");
+#endif /* IKSDB */
+#ifdef IKSDCONF
+ makestr(&(optlist[noptlist++]),"IKSDCONF");
+#endif /* IKSDCONF */
+#ifdef CK_LOGIN
+ makestr(&(optlist[noptlist++]),"CK_LOGIN");
+#endif /* CK_LOGIN */
+#ifdef CK_PAM
+ makestr(&(optlist[noptlist++]),"CK_PAM");
+#endif /* CK_PAM */
+#ifdef CK_SHADOW
+ makestr(&(optlist[noptlist++]),"CK_SHADOW");
+#endif /* CK_SHADOW */
+#ifdef CONGSPD
+ makestr(&(optlist[noptlist++]),"CONGSPD");
+#endif /* CONGSPD */
+#ifdef SUNX25
+ makestr(&(optlist[noptlist++]),"SUNX25");
+#endif /* SUNX25 */
+#ifdef IBMX25
+ makestr(&(optlist[noptlist++]),"IBMX25");
+#endif /* IBMX25 */
+#ifdef HPX25
+ makestr(&(optlist[noptlist++]),"HPX25");
+#endif /* HPX25 */
+#ifdef DECNET
+ makestr(&(optlist[noptlist++]),"DECNET");
+#endif /* DECNET */
+#ifdef SUPERLAT
+ makestr(&(optlist[noptlist++]),"SUPERLAT");
+#endif /* SUPERLAT */
+#ifdef NPIPE
+ makestr(&(optlist[noptlist++]),"NPIPE");
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+ makestr(&(optlist[noptlist++]),"CK_NETBIOS");
+#endif /* CK_NETBIOS */
+#ifdef ATT7300
+ makestr(&(optlist[noptlist++]),"ATT7300");
+#endif /* ATT7300 */
+#ifdef ATT6300
+ makestr(&(optlist[noptlist++]),"ATT6300");
+#endif /* ATT6300 */
+#ifdef HDBUUCP
+ makestr(&(optlist[noptlist++]),"HDBUUCP");
+#endif /* HDBUUCP */
+#ifdef USETTYLOCK
+ makestr(&(optlist[noptlist++]),"USETTYLOCK");
+#endif /* USETTYLOCK */
+#ifdef USE_UU_LOCK
+ makestr(&(optlist[noptlist++]),"USE_UU_LOCK");
+#endif /* USE_UU_LOCK */
+#ifdef HAVE_LOCKDEV
+ makestr(&(optlist[noptlist++]),"HAVE_LOCKDEV");
+#endif /* HAVE_LOCKDEV */
+#ifdef HAVE_BAUDBOY
+ makestr(&(optlist[noptlist++]),"HAVE_BAUDBOY");
+#endif /* HAVE_BAUDBOY */
+#ifdef HAVE_OPENPTY
+ makestr(&(optlist[noptlist++]),"HAVE_OPENPTY");
+#endif /* HAVE_OPENPTY */
+#ifdef TTPTYCMD
+ makestr(&(optlist[noptlist++]),"TTPTYCMD");
+#endif /* TTPTYCMD */
+#ifdef NOUUCP
+ makestr(&(optlist[noptlist++]),"NOUUCP");
+#endif /* NOUUCP */
+#ifdef LONGFN
+ makestr(&(optlist[noptlist++]),"LONGFN");
+#endif /* LONGFN */
+#ifdef RDCHK
+ makestr(&(optlist[noptlist++]),"RDCHK");
+#endif /* RDCHK */
+#ifdef SELECT
+ makestr(&(optlist[noptlist++]),"SELECT");
+#endif /* SELECT */
+#ifdef USLEEP
+ makestr(&(optlist[noptlist++]),"USLEEP");
+#endif /* USLEEP */
+#ifdef NAP
+ makestr(&(optlist[noptlist++]),"NAP");
+#endif /* NAP */
+#ifdef NAPHACK
+ makestr(&(optlist[noptlist++]),"NAPHACK");
+#endif /* NAPHACK */
+#ifdef CK_POLL
+ makestr(&(optlist[noptlist++]),"CK_POLL");
+#endif /* CK_POLL */
+#ifdef NOIEXTEN
+ makestr(&(optlist[noptlist++]),"NOIEXTEN");
+#endif /* NOIEXTEN */
+#ifdef EXCELAN
+ makestr(&(optlist[noptlist++]),"EXCELAN");
+#endif /* EXCELAN */
+#ifdef INTERLAN
+ makestr(&(optlist[noptlist++]),"INTERLAN");
+#endif /* INTERLAN */
+#ifdef NOFILEH
+ makestr(&(optlist[noptlist++]),"NOFILEH");
+#endif /* NOFILEH */
+#ifdef NOSYSIOCTLH
+ makestr(&(optlist[noptlist++]),"NOSYSIOCTLH");
+#endif /* NOSYSIOCTLH */
+#ifdef DCLPOPEN
+ makestr(&(optlist[noptlist++]),"DCLPOPEN");
+#endif /* DCLPOPEN */
+#ifdef NOSETBUF
+ makestr(&(optlist[noptlist++]),"NOSETBUF");
+#endif /* NOSETBUF */
+#ifdef NOXFER
+ makestr(&(optlist[noptlist++]),"NOXFER");
+#endif /* NOXFER */
+#ifdef NOCURSES
+ makestr(&(optlist[noptlist++]),"NOCURSES");
+#endif /* NOCURSES */
+#ifdef NOSERVER
+ makestr(&(optlist[noptlist++]),"NOSERVER");
+#endif /* NOSERVER */
+#ifdef NOPATTERNS
+ makestr(&(optlist[noptlist++]),"NOPATTERNS");
+#else
+#ifdef PATTERNS
+ makestr(&(optlist[noptlist++]),"PATTERNS");
+#endif /* PATTERNS */
+#endif /* NOPATTERNS */
+#ifdef NOCKEXEC
+ makestr(&(optlist[noptlist++]),"NOCKEXEC");
+#else
+#ifdef CKEXEC
+ makestr(&(optlist[noptlist++]),"CKEXEC");
+#endif /* CKEXEC */
+#endif /* NOCKEXEC */
+#ifdef NOAUTODL
+ makestr(&(optlist[noptlist++]),"NOAUTODL");
+#endif /* NOAUTODL */
+#ifdef NOMSEND
+ makestr(&(optlist[noptlist++]),"NOMSEND");
+#endif /* NOMSEND */
+#ifdef NOFDZERO
+ makestr(&(optlist[noptlist++]),"NOFDZERO");
+#endif /* NOFDZERO */
+#ifdef NOPOPEN
+ makestr(&(optlist[noptlist++]),"NOPOPEN");
+#endif /* NOPOPEN */
+#ifdef NOPARTIAL
+ makestr(&(optlist[noptlist++]),"NOPARTIAL");
+#endif /* NOPARTIAL */
+#ifdef NOKVERBS
+ makestr(&(optlist[noptlist++]),"NOKVERBS");
+#endif /* NOKVERBS */
+#ifdef NOSETREU
+ makestr(&(optlist[noptlist++]),"NOSETREU");
+#endif /* NOSETREU */
+#ifdef LCKDIR
+ makestr(&(optlist[noptlist++]),"LCKDIR");
+#endif /* LCKDIR */
+#ifdef ACUCNTRL
+ makestr(&(optlist[noptlist++]),"ACUCNTRL");
+#endif /* ACUCNTRL */
+#ifdef BSD4
+ makestr(&(optlist[noptlist++]),"BSD4");
+#endif /* BSD4 */
+#ifdef BSD44
+ makestr(&(optlist[noptlist++]),"BSD44");
+#endif /* BSD44 */
+#ifdef BSD41
+ makestr(&(optlist[noptlist++]),"BSD41");
+#endif /* BSD41 */
+#ifdef BSD43
+ makestr(&(optlist[noptlist++]),"BSD43");
+#endif /* BSD43 */
+#ifdef BSD29
+ makestr(&(optlist[noptlist++]),"BSD29");
+#endif /* BSD29 */
+#ifdef BSDI
+ makestr(&(optlist[noptlist++]),"BSDI");
+#endif /* BSDI */
+#ifdef __bsdi__
+ makestr(&(optlist[noptlist++]),"__bsdi__");
+#endif /* __bsdi__ */
+#ifdef __NetBSD__
+ makestr(&(optlist[noptlist++]),"__NetBSD__");
+#endif /* __NetBSD__ */
+#ifdef __OpenBSD__
+ makestr(&(optlist[noptlist++]),"__OpenBSD__");
+#endif /* __OpenBSD__ */
+#ifdef __FreeBSD__
+ makestr(&(optlist[noptlist++]),"__FreeBSD__");
+#endif /* __FreeBSD__ */
+#ifdef FREEBSD4
+ makestr(&(optlist[noptlist++]),"FREEBSD4");
+#endif /* FREEBSD4 */
+#ifdef FREEBSD8
+ makestr(&(optlist[noptlist++]),"FREEBSD8");
+#endif /* FREEBSD8 */
+#ifdef FREEBSD9
+ makestr(&(optlist[noptlist++]),"FREEBSD9");
+#endif /* FREEBSD9 */
+#ifdef __linux__
+ makestr(&(optlist[noptlist++]),"__linux__");
+#endif /* __linux__ */
+#ifdef LINUX_HI_SPD
+ makestr(&(optlist[noptlist++]),"LINUX_HI_SPD");
+#endif /* LINUX_HI_SPD */
+#ifdef LYNXOS
+ makestr(&(optlist[noptlist++]),"LYNXOS");
+#endif /* LYNXOS */
+#ifdef V7
+ makestr(&(optlist[noptlist++]),"V7");
+#endif /* V7 */
+#ifdef AIX370
+ makestr(&(optlist[noptlist++]),"AIX370");
+#endif /* AIX370 */
+#ifdef RTAIX
+ makestr(&(optlist[noptlist++]),"RTAIX");
+#endif /* RTAIX */
+#ifdef HPUX
+ makestr(&(optlist[noptlist++]),"HPUX");
+#endif /* HPUX */
+#ifdef HPUX9
+ makestr(&(optlist[noptlist++]),"HPUX9");
+#endif /* HPUX9 */
+#ifdef HPUX10
+ makestr(&(optlist[noptlist++]),"HPUX10");
+#endif /* HPUX10 */
+#ifdef HPUX1000
+ makestr(&(optlist[noptlist++]),"HPUX1000");
+#endif /* HPUX1000 */
+#ifdef HPUX1100
+ makestr(&(optlist[noptlist++]),"HPUX1100");
+#endif /* HPUX1100 */
+#ifdef HPUXPRE65
+ makestr(&(optlist[noptlist++]),"HPUXPRE65");
+#endif /* HPUXPRE65 */
+#ifdef DGUX
+ makestr(&(optlist[noptlist++]),"DGUX");
+#endif /* DGUX */
+#ifdef DGUX430
+ makestr(&(optlist[noptlist++]),"DGUX430");
+#endif /* DGUX430 */
+#ifdef DGUX540
+ makestr(&(optlist[noptlist++]),"DGUX540");
+#endif /* DGUX540 */
+#ifdef DGUX543
+ makestr(&(optlist[noptlist++]),"DGUX543");
+#endif /* DGUX543 */
+#ifdef DGUX54410
+ makestr(&(optlist[noptlist++]),"DGUX54410");
+#endif /* DGUX54410 */
+#ifdef DGUX54411
+ makestr(&(optlist[noptlist++]),"DGUX54411");
+#endif /* DGUX54411 */
+#ifdef sony_news
+ makestr(&(optlist[noptlist++]),"sony_news");
+#endif /* sony_news */
+#ifdef CIE
+ makestr(&(optlist[noptlist++]),"CIE");
+#endif /* CIE */
+#ifdef XENIX
+ makestr(&(optlist[noptlist++]),"XENIX");
+#endif /* XENIX */
+#ifdef SCO_XENIX
+ makestr(&(optlist[noptlist++]),"SCO_XENIX");
+#endif /* SCO_XENIX */
+#ifdef ISIII
+ makestr(&(optlist[noptlist++]),"ISIII");
+#endif /* ISIII */
+#ifdef I386IX
+ makestr(&(optlist[noptlist++]),"I386IX");
+#endif /* I386IX */
+#ifdef RTU
+ makestr(&(optlist[noptlist++]),"RTU");
+#endif /* RTU */
+#ifdef PROVX1
+ makestr(&(optlist[noptlist++]),"PROVX1");
+#endif /* PROVX1 */
+#ifdef PYRAMID
+ makestr(&(optlist[noptlist++]),"PYRAMID");
+#endif /* PYRAMID */
+#ifdef TOWER1
+ makestr(&(optlist[noptlist++]),"TOWER1");
+#endif /* TOWER1 */
+#ifdef UTEK
+ makestr(&(optlist[noptlist++]),"UTEK");
+#endif /* UTEK */
+#ifdef ZILOG
+ makestr(&(optlist[noptlist++]),"ZILOG");
+#endif /* ZILOG */
+#ifdef TRS16
+ makestr(&(optlist[noptlist++]),"TRS16");
+#endif /* TRS16 */
+#ifdef MINIX
+ makestr(&(optlist[noptlist++]),"MINIX");
+#endif /* MINIX */
+#ifdef MINIX2
+ makestr(&(optlist[noptlist++]),"MINIX2");
+#endif /* MINIX2 */
+#ifdef MINIX3
+ makestr(&(optlist[noptlist++]),"MINIX3");
+#endif /* MINIX3 */
+#ifdef MINIX315
+ makestr(&(optlist[noptlist++]),"MINIX315");
+#endif /* MINIX315 */
+#ifdef C70
+ makestr(&(optlist[noptlist++]),"C70");
+#endif /* C70 */
+#ifdef AIXPS2
+ makestr(&(optlist[noptlist++]),"AIXPS2");
+#endif /* AIXPS2 */
+#ifdef AIXRS
+ makestr(&(optlist[noptlist++]),"AIXRS");
+#endif /* AIXRS */
+#ifdef UTSV
+ makestr(&(optlist[noptlist++]),"UTSV");
+#endif /* UTSV */
+#ifdef ATTSV
+ makestr(&(optlist[noptlist++]),"ATTSV");
+#endif /* ATTSV */
+#ifdef SVR3
+ makestr(&(optlist[noptlist++]),"SVR3");
+#endif /* SVR3 */
+#ifdef SVR4
+ makestr(&(optlist[noptlist++]),"SVR4");
+#endif /* SVR4 */
+#ifdef DELL_SVR4
+ makestr(&(optlist[noptlist++]),"DELL_SVR4");
+#endif /* DELL_SVR4 */
+#ifdef ICL_SVR4
+ makestr(&(optlist[noptlist++]),"ICL_SVR4");
+#endif /* ICL_SVR4 */
+#ifdef OSF
+ makestr(&(optlist[noptlist++]),"OSF");
+#endif /* OSF */
+#ifdef OSF1
+ makestr(&(optlist[noptlist++]),"OSF1");
+#endif /* OSF1 */
+#ifdef __OSF
+ makestr(&(optlist[noptlist++]),"__OSF");
+#endif /* __OSF */
+#ifdef __OSF__
+ makestr(&(optlist[noptlist++]),"__OSF__");
+#endif /* __OSF__ */
+#ifdef __osf__
+ makestr(&(optlist[noptlist++]),"__osf__");
+#endif /* __osf__ */
+#ifdef __OSF1
+ makestr(&(optlist[noptlist++]),"__OSF1");
+#endif /* __OSF1 */
+#ifdef __OSF1__
+ makestr(&(optlist[noptlist++]),"__OSF1__");
+#endif /* __OSF1__ */
+#ifdef PTX
+ makestr(&(optlist[noptlist++]),"PTX");
+#endif /* PTX */
+#ifdef POSIX
+ makestr(&(optlist[noptlist++]),"POSIX");
+#endif /* POSIX */
+#ifdef BSD44ORPOSIX
+ makestr(&(optlist[noptlist++]),"BSD44ORPOSIX");
+#endif /* BSD44ORPOSIX */
+#ifdef SVORPOSIX
+ makestr(&(optlist[noptlist++]),"SVORPOSIX");
+#endif /* SVORPOSIX */
+#ifdef SVR4ORPOSIX
+ makestr(&(optlist[noptlist++]),"SVR4ORPOSIX");
+#endif /* SVR4ORPOSIX */
+#ifdef OS2ORVMS
+ makestr(&(optlist[noptlist++]),"OS2ORVMS");
+#endif /* OS2ORVMS */
+#ifdef OS2ORUNIX
+ makestr(&(optlist[noptlist++]),"OS2ORUNIX");
+#endif /* OS2ORUNIX */
+#ifdef VMSORUNIX
+ makestr(&(optlist[noptlist++]),"VMSORUNIX");
+#endif /* VMSORUNIX */
+#ifdef VMS64BIT
+ makestr(&(optlist[noptlist++]),"VMS64BIT"); /* VMS on Alpha or IA64 */
+#endif /* VMS64BIT */
+#ifdef VMSI64
+ makestr(&(optlist[noptlist++]),"VMSI64"); /* VMS on IA64 */
+#endif /* VMSI64 */
+#ifdef _POSIX_SOURCE
+ makestr(&(optlist[noptlist++]),"_POSIX_SOURCE");
+#endif /* _POSIX_SOURCE */
+#ifdef _XOPEN_SOURCE
+ makestr(&(optlist[noptlist++]),"_XOPEN_SOURCE");
+#endif
+#ifdef _ALL_SOURCE
+ makestr(&(optlist[noptlist++]),"_ALL_SOURCE");
+#endif
+#ifdef _SVID3
+ makestr(&(optlist[noptlist++]),"_SVID3");
+#endif /* _SVID3 */
+#ifdef Plan9
+ makestr(&(optlist[noptlist++]),"Plan9");
+#endif /* Plan9 */
+#ifdef SOLARIS
+ makestr(&(optlist[noptlist++]),"SOLARIS");
+#ifdef SOLARIS24
+ makestr(&(optlist[noptlist++]),"SOLARIS24");
+#endif /* SOLARIS24 */
+#ifdef SOLARIS25
+ makestr(&(optlist[noptlist++]),"SOLARIS25");
+#endif /* SOLARIS25 */
+#ifdef SOLARIS26
+ makestr(&(optlist[noptlist++]),"SOLARIS26");
+#endif /* SOLARIS26 */
+#ifdef SOLARIS7
+ makestr(&(optlist[noptlist++]),"SOLARIS7");
+#endif /* SOLARIS7 */
+#ifdef SOLARIS8
+ makestr(&(optlist[noptlist++]),"SOLARIS8");
+#endif /* SOLARIS8 */
+#ifdef SOLARIS9
+ makestr(&(optlist[noptlist++]),"SOLARIS9");
+#endif /* SOLARIS9 */
+#ifdef SOLARIS10
+ makestr(&(optlist[noptlist++]),"SOLARIS10");
+#endif /* SOLARIS10 */
+#endif /* SOLARIS */
+
+#ifdef SUNOS4
+ makestr(&(optlist[noptlist++]),"SUNOS4");
+#endif /* SUNOS4 */
+#ifdef SUN4S5
+ makestr(&(optlist[noptlist++]),"SUN4S5");
+#endif /* SUN4S5 */
+#ifdef IRIX
+ makestr(&(optlist[noptlist++]),"IRIX");
+#endif /* IRIX */
+#ifdef ENCORE
+ makestr(&(optlist[noptlist++]),"ENCORE");
+#endif /* ENCORE */
+#ifdef ultrix
+ makestr(&(optlist[noptlist++]),"ultrix");
+#endif
+#ifdef sxaE50
+ makestr(&(optlist[noptlist++]),"sxaE50");
+#endif
+#ifdef mips
+ makestr(&(optlist[noptlist++]),"mips");
+#endif
+#ifdef MIPS
+ makestr(&(optlist[noptlist++]),"MIPS");
+#endif
+#ifdef vax
+ makestr(&(optlist[noptlist++]),"vax");
+#endif
+#ifdef VAX
+ makestr(&(optlist[noptlist++]),"VAX");
+#endif
+#ifdef alpha
+ makestr(&(optlist[noptlist++]),"alpha");
+#endif
+#ifdef ALPHA
+ makestr(&(optlist[noptlist++]),"ALPHA");
+#endif
+#ifdef __ALPHA
+ makestr(&(optlist[noptlist++]),"__ALPHA");
+#endif
+#ifdef __alpha
+ makestr(&(optlist[noptlist++]),"__alpha");
+#endif
+#ifdef __AXP
+ makestr(&(optlist[noptlist++]),"__AXP");
+#endif
+#ifdef AXP
+ makestr(&(optlist[noptlist++]),"AXP");
+#endif
+#ifdef axp
+ makestr(&(optlist[noptlist++]),"axp");
+#endif
+#ifdef __ALPHA__
+ makestr(&(optlist[noptlist++]),"__ALPHA__");
+#endif
+#ifdef __alpha__
+ makestr(&(optlist[noptlist++]),"__alpha__");
+#endif
+#ifdef sun
+ makestr(&(optlist[noptlist++]),"sun");
+#endif
+#ifdef sun3
+ makestr(&(optlist[noptlist++]),"sun3");
+#endif
+#ifdef sun386
+ makestr(&(optlist[noptlist++]),"sun386");
+#endif
+#ifdef _SUN
+ makestr(&(optlist[noptlist++]),"_SUN");
+#endif
+#ifdef sun4
+ makestr(&(optlist[noptlist++]),"sun4");
+#endif
+#ifdef sparc
+ makestr(&(optlist[noptlist++]),"sparc");
+#endif
+#ifdef _CRAY
+ makestr(&(optlist[noptlist++]),"_CRAY");
+#endif /* _CRAY */
+#ifdef NEXT33
+ makestr(&(optlist[noptlist++]),"NEXT33");
+#endif
+#ifdef NEXT
+ makestr(&(optlist[noptlist++]),"NEXT");
+#endif
+#ifdef NeXT
+ makestr(&(optlist[noptlist++]),"NeXT");
+#endif
+#ifdef MACH
+ makestr(&(optlist[noptlist++]),"MACH");
+#endif
+
+#ifdef MACOSX
+ makestr(&(optlist[noptlist++]),"MACOSX");
+#endif
+#ifdef MACOSX10
+ makestr(&(optlist[noptlist++]),"MACOSX10");
+#endif
+#ifdef MACOSX103
+ makestr(&(optlist[noptlist++]),"MACOSX10e");
+#endif
+#ifdef COMMENT
+/* not used */
+#ifdef MACOSX103
+ makestr(&(optlist[noptlist++]),"MACOSX103");
+#endif
+#endif /* COMMENT */
+
+#ifdef sgi
+ makestr(&(optlist[noptlist++]),"sgi");
+#endif
+#ifdef M_SYS5
+ makestr(&(optlist[noptlist++]),"M_SYS5");
+#endif
+#ifdef __SYSTEM_FIVE
+ makestr(&(optlist[noptlist++]),"__SYSTEM_FIVE");
+#endif
+#ifdef sysV
+ makestr(&(optlist[noptlist++]),"sysV");
+#endif
+#ifdef M_XENIX /* SCO Xenix V and UNIX/386 */
+ makestr(&(optlist[noptlist++]),"M_XENIX");
+#endif
+#ifdef M_UNIX /* SCO UNIX */
+ makestr(&(optlist[noptlist++]),"M_UNIX");
+#endif
+#ifdef _M_UNIX /* SCO UNIX 3.2v4 = ODT 2.0 */
+ makestr(&(optlist[noptlist++]),"_M_UNIX");
+#endif
+#ifdef CK_SCOV5
+ makestr(&(optlist[noptlist++]),"CK_SCOV5");
+#endif
+#ifdef SCO_OSR504
+ makestr(&(optlist[noptlist++]),"SCO_OSR504");
+#endif
+#ifdef M_IA64
+ makestr(&(optlist[noptlist++]),"M_IA64");
+#endif
+#ifdef _M_IA64
+ makestr(&(optlist[noptlist++]),"_M_IA64");
+#endif
+#ifdef ia64
+ makestr(&(optlist[noptlist++]),"ia64");
+#endif
+#ifdef _ia64
+ makestr(&(optlist[noptlist++]),"_ia64");
+#endif
+#ifdef _ia64_
+ makestr(&(optlist[noptlist++]),"_ia64_");
+#endif
+#ifdef __ia64
+ makestr(&(optlist[noptlist++]),"__ia64");
+#endif
+#ifdef M_I686
+ makestr(&(optlist[noptlist++]),"M_I686");
+#endif
+#ifdef _M_I686
+ makestr(&(optlist[noptlist++]),"_M_I686");
+#endif
+#ifdef i686
+ makestr(&(optlist[noptlist++]),"i686");
+#endif
+#ifdef M_I586
+ makestr(&(optlist[noptlist++]),"M_I586");
+#endif
+#ifdef _M_I586
+ makestr(&(optlist[noptlist++]),"_M_I586");
+#endif
+#ifdef i586
+ makestr(&(optlist[noptlist++]),"i586");
+#endif
+#ifdef M_I486
+ makestr(&(optlist[noptlist++]),"M_I486");
+#endif
+#ifdef _M_I486
+ makestr(&(optlist[noptlist++]),"_M_I486");
+#endif
+#ifdef i486
+ makestr(&(optlist[noptlist++]),"i486");
+#endif
+#ifdef M_I386
+ makestr(&(optlist[noptlist++]),"M_I386");
+#endif
+#ifdef _M_I386
+ makestr(&(optlist[noptlist++]),"_M_I386");
+#endif
+#ifdef i386
+ makestr(&(optlist[noptlist++]),"i386");
+#endif
+#ifdef __i386
+ makestr(&(optlist[noptlist++]),"__i386");
+#endif
+#ifdef __x86
+ makestr(&(optlist[noptlist++]),"__x86");
+#endif
+#ifdef __amd64
+ makestr(&(optlist[noptlist++]),"__amd64");
+#endif
+#ifdef _ILP32
+ makestr(&(optlist[noptlist++]),"_ILP32");
+#endif
+#ifdef _ILP64
+ makestr(&(optlist[noptlist++]),"_ILP64");
+#endif
+#ifdef _LP32
+ makestr(&(optlist[noptlist++]),"_LP32");
+#endif
+#ifdef _LP64
+ makestr(&(optlist[noptlist++]),"_LP64");
+#endif
+#ifdef __LP32__
+ makestr(&(optlist[noptlist++]),"__LP32__");
+#endif
+#ifdef __LP64__
+ makestr(&(optlist[noptlist++]),"__LP64__");
+#endif
+#ifdef _XGP4_2
+ makestr(&(optlist[noptlist++]),"_XGP4_2");
+#endif
+#ifdef __ppc__
+ makestr(&(optlist[noptlist++]),"__ppc__");
+#endif
+#ifdef __ppc32__
+ makestr(&(optlist[noptlist++]),"__ppc32__");
+#endif
+#ifdef __ppc64__
+ makestr(&(optlist[noptlist++]),"__ppc64__");
+#endif
+#ifdef CK_64BIT
+ makestr(&(optlist[noptlist++]),"CK_64BIT");
+#endif
+#ifdef i286
+ makestr(&(optlist[noptlist++]),"i286");
+#endif
+#ifdef M_I286
+ makestr(&(optlist[noptlist++]),"M_I286");
+#endif
+#ifdef __sparc
+ makestr(&(optlist[noptlist++]),"__sparc");
+#endif
+#ifdef __sparcv8
+ makestr(&(optlist[noptlist++]),"__sparcv8");
+#endif
+#ifdef __sparcv9
+ makestr(&(optlist[noptlist++]),"__sparcv9");
+#endif
+#ifdef mc68000
+ makestr(&(optlist[noptlist++]),"mc68000");
+#endif
+#ifdef mc68010
+ makestr(&(optlist[noptlist++]),"mc68010");
+#endif
+#ifdef mc68020
+ makestr(&(optlist[noptlist++]),"mc68020");
+#endif
+#ifdef mc68030
+ makestr(&(optlist[noptlist++]),"mc68030");
+#endif
+#ifdef mc68040
+ makestr(&(optlist[noptlist++]),"mc68040");
+#endif
+#ifdef M_68000
+ makestr(&(optlist[noptlist++]),"M_68000");
+#endif
+#ifdef M_68010
+ makestr(&(optlist[noptlist++]),"M_68010");
+#endif
+#ifdef M_68020
+ makestr(&(optlist[noptlist++]),"M_68020");
+#endif
+#ifdef M_68030
+ makestr(&(optlist[noptlist++]),"M_68030");
+#endif
+#ifdef M_68040
+ makestr(&(optlist[noptlist++]),"M_68040");
+#endif
+#ifdef m68k
+ makestr(&(optlist[noptlist++]),"m68k");
+#endif
+#ifdef m88k
+ makestr(&(optlist[noptlist++]),"m88k");
+#endif
+#ifdef pdp11
+ makestr(&(optlist[noptlist++]),"pdp11");
+#endif
+#ifdef iAPX
+ makestr(&(optlist[noptlist++]),"iAPX");
+#endif
+#ifdef hpux
+ makestr(&(optlist[noptlist++]),"hpux");
+#endif
+#ifdef __hpux
+ makestr(&(optlist[noptlist++]),"__hpux");
+#endif
+#ifdef __hp9000s800
+ makestr(&(optlist[noptlist++]),"__hp9000s800");
+#endif
+#ifdef __hp9000s700
+ makestr(&(optlist[noptlist++]),"__hp9000s700");
+#endif
+#ifdef __hp9000s500
+ makestr(&(optlist[noptlist++]),"__hp9000s500");
+#endif
+#ifdef __hp9000s300
+ makestr(&(optlist[noptlist++]),"__hp9000s300");
+#endif
+#ifdef __hp9000s200
+ makestr(&(optlist[noptlist++]),"__hp9000s200");
+#endif
+#ifdef AIX
+ makestr(&(optlist[noptlist++]),"AIX");
+#endif
+#ifdef _AIXFS
+ makestr(&(optlist[noptlist++]),"_AIXFS");
+#endif
+#ifdef u370
+ makestr(&(optlist[noptlist++]),"u370");
+#endif
+#ifdef u3b
+ makestr(&(optlist[noptlist++]),"u3b");
+#endif
+#ifdef u3b2
+ makestr(&(optlist[noptlist++]),"u3b2");
+#endif
+#ifdef multimax
+ makestr(&(optlist[noptlist++]),"multimax");
+#endif
+#ifdef balance
+ makestr(&(optlist[noptlist++]),"balance");
+#endif
+#ifdef ibmrt
+ makestr(&(optlist[noptlist++]),"ibmrt");
+#endif
+#ifdef _IBMRT
+ makestr(&(optlist[noptlist++]),"_IBMRT");
+#endif
+#ifdef ibmrs6000
+ makestr(&(optlist[noptlist++]),"ibmrs6000");
+#endif
+#ifdef _AIX
+ makestr(&(optlist[noptlist++]),"_AIX");
+#endif /* _AIX */
+#ifdef _IBMR2
+ makestr(&(optlist[noptlist++]),"_IBMR2");
+#endif
+#ifdef UNIXWARE
+ makestr(&(optlist[noptlist++]),"UNIXWARE");
+#endif
+#ifdef QNX
+ makestr(&(optlist[noptlist++]),"QNX");
+#ifdef __QNX__
+ makestr(&(optlist[noptlist++]),"__QNX__");
+#ifdef __16BIT__
+ makestr(&(optlist[noptlist++]),"__16BIT__");
+#endif
+#ifdef CK_QNX16
+ makestr(&(optlist[noptlist++]),"CK_QNX16");
+#endif
+#ifdef __32BIT__
+ makestr(&(optlist[noptlist++]),"__32BIT__");
+#endif
+#ifdef CK_QNX32
+ makestr(&(optlist[noptlist++]),"CK_QNX32");
+#endif
+#endif /* __QNX__ */
+#endif /* QNX */
+
+#ifdef QNX6
+ makestr(&(optlist[noptlist++]),"QNX6");
+#endif /* QNX6 */
+
+#ifdef NEUTRINO
+ makestr(&(optlist[noptlist++]),"NEUTRINO");
+#endif /* NEUTRINO */
+
+#ifdef __STRICT_BSD__
+ makestr(&(optlist[noptlist++]),"__STRICT_BSD__");
+#endif
+#ifdef __STRICT_ANSI__
+ makestr(&(optlist[noptlist++]),"__STRICT_ANSI__");
+#endif
+#ifdef _ANSI_C_SOURCE
+ makestr(&(optlist[noptlist++]),"_ANSI_C_SOURCE");
+#endif
+#ifdef __STDC__
+ makestr(&(optlist[noptlist++]),"__STDC__");
+#endif
+#ifdef cplusplus
+ makestr(&(optlist[noptlist++]),"cplusplus");
+#endif
+#ifdef __DECC
+ makestr(&(optlist[noptlist++]),"__DECC");
+#ifdef __DECC_VER
+ sprintf(line,"__DECC_VER=%d",__DECC_VER); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* __DECC_VER */
+#endif /* __DECC */
+#ifdef __CRTL_VER
+ sprintf(line,"__CRTL_VER=%d",__CRTL_VER); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* __CRTL_VER */
+#ifdef __GNUC__ /* gcc in ansi mode */
+ makestr(&(optlist[noptlist++]),"__GNUC__");
+#endif
+#ifdef GNUC /* gcc in traditional mode */
+ makestr(&(optlist[noptlist++]),"GNUC");
+#endif
+#ifdef __EGCS__ /* egcs in ansi mode */
+ makestr(&(optlist[noptlist++]),"__EGCS__");
+#endif
+#ifdef __egcs__ /* egcs in ansi mode */
+ makestr(&(optlist[noptlist++]),"__egcs__");
+#endif
+#ifdef __WATCOMC__
+ makestr(&(optlist[noptlist++]),"__WATCOMC__");
+#endif
+#ifdef CK_ANSIC
+ makestr(&(optlist[noptlist++]),"CK_ANSIC");
+#endif
+#ifdef CK_ANSILIBS
+ makestr(&(optlist[noptlist++]),"CK_ANSILIBS");
+#endif
+#ifdef CKCONINTB4CB
+ makestr(&(optlist[noptlist++]),"CKCONINTB4CB");
+#endif /* CKCONINTB4CB */
+#ifdef NOTERMCAP
+ makestr(&(optlist[noptlist++]),"NOTERMCAP");
+#endif /* NOTERMCAP */
+#ifdef __GLIBC__
+ makestr(&(optlist[noptlist++]),"__GLIBC__");
+#endif
+#ifdef _SC_JOB_CONTROL
+ makestr(&(optlist[noptlist++]),"_SC_JOB_CONTROL");
+#endif
+#ifdef _POSIX_JOB_CONTROL
+ makestr(&(optlist[noptlist++]),"_POSIX_JOB_CONTROL");
+#endif
+#ifdef SIG_I
+ makestr(&(optlist[noptlist++]),"SIG_I");
+#endif /* SIG_I */
+#ifdef SIG_V
+ makestr(&(optlist[noptlist++]),"SIG_V");
+#endif /* SIG_V */
+#ifdef CK_POSIX_SIG
+ makestr(&(optlist[noptlist++]),"CK_POSIX_SIG");
+#endif
+#ifdef SVR3JC
+ makestr(&(optlist[noptlist++]),"SVR3JC");
+#endif
+#ifdef _386BSD
+ makestr(&(optlist[noptlist++]),"_386BSD");
+#endif
+#ifdef _BSD
+ makestr(&(optlist[noptlist++]),"_BSD");
+#endif
+#ifdef USE_MEMCPY
+ makestr(&(optlist[noptlist++]),"USE_MEMCPY");
+#endif /* USE_MEMCPY */
+#ifdef USE_LSTAT
+ makestr(&(optlist[noptlist++]),"USE_LSTAT");
+#endif /* USE_LSTAT */
+#ifdef TERMIOX
+ makestr(&(optlist[noptlist++]),"TERMIOX");
+#endif /* TERMIOX */
+#ifdef STERMIOX
+ makestr(&(optlist[noptlist++]),"STERMIOX");
+#endif /* STERMIOX */
+#ifdef CK_CURSES
+ makestr(&(optlist[noptlist++]),"CK_CURSES");
+#endif /* CK_CURSES */
+#ifdef CK_NEWTERM
+ makestr(&(optlist[noptlist++]),"CK_NEWTERM");
+#endif /* CK_NEWTERM */
+#ifdef CK_WREFRESH
+ makestr(&(optlist[noptlist++]),"CK_WREFRESH");
+#endif /* CK_WREFRESH */
+#ifdef CK_PCT_BAR
+ makestr(&(optlist[noptlist++]),"CK_PCT_BAR");
+#endif /* CK_PCT_BAR */
+#ifdef CK_DTRCD
+ makestr(&(optlist[noptlist++]),"CK_DTRCD");
+#endif /* CK_DTRCD */
+#ifdef CK_DTRCTS
+ makestr(&(optlist[noptlist++]),"CK_DTRCTS");
+#endif /* CK_DTRCTS */
+#ifdef CK_RTSCTS
+ makestr(&(optlist[noptlist++]),"CK_RTSCTS");
+#endif /* CK_RTSCTS */
+#ifdef POSIX_CRTSCTS
+ makestr(&(optlist[noptlist++]),"POSIX_CRTSCTS");
+#endif /* POSIX_CRTSCTS */
+#ifdef FIXCRTSCTS
+ makestr(&(optlist[noptlist++]),"FIXCRTSCTS");
+#endif /* FIXCRTSCTS */
+#ifdef HWPARITY
+ makestr(&(optlist[noptlist++]),"HWPARITY");
+#endif /* HWPARITY */
+#ifdef CK_SYSINI
+#ifdef CK_INI_A
+ makestr(&(optlist[noptlist++]),"CK_INI_A");
+ ckmakmsg(line,LINBUFSIZ,"CK_SYSINI=\"",CK_SYSINI,"\"",NULL);
+ makestr(&(optlist[noptlist++]),line);
+#else
+#ifdef CK_INI_B
+ makestr(&(optlist[noptlist++]),"CK_INI_B");
+ ckmakmsg(line,LINBUFSIZ,"CK_SYSINI=\"",CK_SYSINI,"\"",NULL);
+ makestr(&(optlist[noptlist++]),line);
+#else
+ makestr(&(optlist[noptlist++]),"CK_SYSINI");
+#endif /* CK_INI_B */
+#endif /* CK_INI_A */
+#endif /* CK_DSYSINI */
+#ifdef CK_DSYSINI
+ makestr(&(optlist[noptlist++]),"CK_DSYSINI");
+#endif /* CK_DSYSINI */
+#ifdef CK_TTGWSIZ
+ makestr(&(optlist[noptlist++]),"CK_TTGWSIZ");
+#endif /* CK_TTGWSIZ */
+#ifdef CK_NAWS
+ makestr(&(optlist[noptlist++]),"CK_NAWS");
+#endif /* CK_NAWS */
+#ifdef MDMHUP
+ makestr(&(optlist[noptlist++]),"MDMHUP");
+#endif /* MDMHUP */
+#ifdef HUP_CLOSE_POSIX
+ makestr(&(optlist[noptlist++]),"HUP_CLOSE_POSIX");
+#endif /* HUP_CLOSE_POSIX */
+#ifdef NO_HUP_CLOSE_POSIX
+ makestr(&(optlist[noptlist++]),"NO_HUP_CLOSE_POSIX");
+#endif /* NO_HUP_CLOSE_POSIX */
+#ifdef DCMDBUF
+ makestr(&(optlist[noptlist++]),"DCMDBUF");
+#endif /* DCMDBUF */
+#ifdef CK_RECALL
+ makestr(&(optlist[noptlist++]),"CK_RECALL");
+#endif /* CK_RECALL */
+#ifdef BROWSER
+ makestr(&(optlist[noptlist++]),"BROWSER");
+#endif /* BROWSER */
+#ifdef CLSOPN
+ makestr(&(optlist[noptlist++]),"CLSOPN");
+#endif /* CLSOPN */
+#ifdef STRATUS
+ makestr(&(optlist[noptlist++]),"STRATUS");
+#endif /* STRATUS */
+#ifdef __VOS__
+ makestr(&(optlist[noptlist++]),"__VOS__");
+#endif /* __VOS__ */
+#ifdef STRATUSX25
+ makestr(&(optlist[noptlist++]),"STRATUSX25");
+#endif /* STRATUSX25 */
+#ifdef OS2MOUSE
+ makestr(&(optlist[noptlist++]),"OS2MOUSE");
+#endif /* OS2MOUSE */
+#ifdef CK_REXX
+ makestr(&(optlist[noptlist++]),"CK_REXX");
+#endif /* CK_REXX */
+#ifdef CK_TIMERS
+ makestr(&(optlist[noptlist++]),"CK_TIMERS");
+#endif /* CK_TIMERS */
+#ifdef TTSPDLIST
+ makestr(&(optlist[noptlist++]),"TTSPDLIST");
+#endif /* TTSPDLIST */
+#ifdef CK_PERMS
+ makestr(&(optlist[noptlist++]),"CK_PERMS");
+#endif /* CK_PERMS */
+#ifdef CKTUNING
+ makestr(&(optlist[noptlist++]),"CKTUNING");
+#endif /* CKTUNING */
+#ifdef NEWFTP
+ makestr(&(optlist[noptlist++]),"NEWFTP");
+#endif /* NEWFTP */
+#ifdef SYSFTP
+ makestr(&(optlist[noptlist++]),"SYSFTP");
+#endif /* SYSFTP */
+#ifdef NOFTP
+ makestr(&(optlist[noptlist++]),"NOFTP");
+#endif /* NOFTP */
+#ifdef CKHTTP
+ makestr(&(optlist[noptlist++]),"CKHTTP");
+#endif /* CKHTTP */
+#ifdef NOHTTP
+ makestr(&(optlist[noptlist++]),"NOHTTP");
+#endif /* NOHTTP */
+#ifdef CKROOT
+ makestr(&(optlist[noptlist++]),"CKROOT");
+#endif /* CKROOT */
+#ifdef CKREALPATH
+ makestr(&(optlist[noptlist++]),"CKREALPATH");
+#endif /* CKREALPATH */
+#ifdef STREAMING
+ makestr(&(optlist[noptlist++]),"STREAMING");
+#endif /* STREAMING */
+#ifdef UNPREFIXZERO
+ makestr(&(optlist[noptlist++]),"UNPREFIXZERO");
+#endif /* UNPREFIXZERO */
+#ifdef CKREGEX
+ makestr(&(optlist[noptlist++]),"CKREGEX");
+#endif /* CKREGEX */
+#ifdef ZXREWIND
+ makestr(&(optlist[noptlist++]),"ZXREWIND");
+#endif /* ZXREWIND */
+#ifdef CKSYSLOG
+ makestr(&(optlist[noptlist++]),"CKSYSLOG");
+#endif /* CKSYSLOG */
+#ifdef SYSLOGLEVEL
+ sprintf(line,"SYSLOGLEVEL=%d",SYSLOGLEVEL); /* SAFE */
+ makestr(&(optlist[noptlist++]),line);
+#endif /* SYSLOGLEVEL */
+#ifdef NOSEXP
+ makestr(&(optlist[noptlist++]),"NOSEXP");
+#endif /* NOSEXP */
+#ifdef CKLEARN
+ makestr(&(optlist[noptlist++]),"CKLEARN");
+#else
+#ifdef NOLOEARN
+ makestr(&(optlist[noptlist++]),"NOLOEARN");
+#endif /* NOLOEARN */
+#endif /* CKLEARN */
+
+#ifdef NOFLOAT
+ makestr(&(optlist[noptlist++]),"NOFLOAT");
+#else
+#ifdef FNFLOAT
+ makestr(&(optlist[noptlist++]),"FNFLOAT");
+#endif /* FNFLOAT */
+#ifdef CKFLOAT
+#ifdef GFTIMER
+ makestr(&(optlist[noptlist++]),"GFTIMER");
+#endif /* GFTIMER */
+#ifdef CKFLOAT_S
+ ckmakmsg(line,LINBUFSIZ,"CKFLOAT=",CKFLOAT_S,NULL,NULL);
+ makestr(&(optlist[noptlist++]),line);
+#else
+ makestr(&(optlist[noptlist++]),"CKFLOAT");
+#endif /* CKFLOAT_S */
+#endif /* CKFLOAT */
+#endif /* NOFLOAT */
+
+#ifdef SSH
+ makestr(&(optlist[noptlist++]),"SSH");
+#endif /* SSH */
+#ifdef NETDLL
+ makestr(&(optlist[noptlist++]),"NETDLL");
+#endif /* NETDLL */
+#ifdef NETFILE
+ makestr(&(optlist[noptlist++]),"NETFILE");
+#endif /* NETFILE */
+#ifdef CK_TAPI
+ makestr(&(optlist[noptlist++]),"CK_TAPI");
+#endif /* CK_TAPI */
+#ifdef CK_SSL
+ makestr(&(optlist[noptlist++]),"CK_SSL");
+#ifdef OPENSSL_VERSION_TEXT
+ ckmakmsg(line,LINBUFSIZ,
+ "OPENSSL_VERSION_TEXT=","\"",OPENSSL_VERSION_TEXT,"\"");
+ makestr(&(optlist[noptlist++]),line);
+#endif /* OPENSSL_VERSION_TEXT */
+#endif /* CK_SSL */
+ debug(F101,"initoptlist noptlist","",noptlist);
+ sh_sort(optlist,NULL,noptlist,0,0,0);
+}
+
+int
+shofea() {
+ int i;
+ int flag = 0;
+ int lines = 1;
+#ifdef FNFLOAT
+ extern int fp_digits, fp_rounding;
+#endif /* FNFLOAT */
+ extern int byteorder;
+ printf("%s\n",versio);
+ if (inserver)
+ return(1);
+
+ debug(F101,"shofea NOPTLIST","",NOPTLIST);
+ initoptlist();
+ debug(F101,"shofea noptlist","",noptlist);
+#ifdef OS2
+#ifdef NT
+#ifdef _M_ALPHA
+ printf("Microsoft Windows Operating Systems for Alpha CPUs.\n");
+#else /* _M_ALPHA */
+#ifdef _M_PPC
+ printf("Microsoft Windows Operating Systems for PowerPC CPUs.\n");
+#else /* _M_PPC */
+#ifdef _M_MRX000
+ printf("Microsoft Windows Operating Systems for MIPS CPUs.\n");
+#else /* _M_MRX000 */
+#ifdef _M_IX86
+ printf("Microsoft Windows Operating Systems for 32-bit Intel CPUs.\n");
+#else /* _M_IX86 */
+ UNKNOWN WINDOWS PLATFORM
+#endif /* _M_IX86 */
+#endif /* _M_MRX000 */
+#endif /* _M_PPC */
+#endif /* _M_ALPHA */
+#else /* NT */
+#ifdef M_I286
+ printf("IBM OS/2 16-bit.\n");
+#else
+ printf("IBM OS/2 32-bit.\n");
+#endif /* M_I286 */
+#endif /* NT */
+ lines++;
+#endif /* OS2 */
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf("Major optional features included:\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+
+ if (sizeof(CK_OFF_T) == 8) {
+ printf(" Large files and large integers (64 bits)\n");
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) return(1); else lines = 0;
+ }
+ }
+#ifdef NETCONN
+ printf(" Network support (type SHOW NET for further info)\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#ifdef IKS_OPTION
+ printf(" Telnet Kermit Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* IKS_OPTION */
+#ifdef CK_AUTHENTICATION
+ printf(" Telnet Authentication Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#ifdef CK_KERBEROS
+#ifdef KRB4
+#ifdef KRB5
+ printf(" Kerberos(TM) IV and Kerberos V authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#else /* KRB5 */
+ printf(" Kerberos(TM) IV authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* KRB5 */
+#else /* KRB4 */
+#ifdef KRB5
+ printf(" Kerberos(TM) V authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* KRB5 */
+#endif /* KRB4 */
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+ printf(" SRP(TM) (Secure Remote Password) authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ printf(" Secure Sockets Layer (SSL)\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" Transport Layer Security (TLS)\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_SSL */
+#ifdef SSHBUILTIN
+ printf(" Secure Shell (SSH) [internal]\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* SSHBUILTIN */
+#ifdef SSHCMD
+ printf(" Secure Shell (SSH) [external]\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* SSHCMD */
+#ifdef CK_ENCRYPTION
+ printf(" Telnet Encryption Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#ifdef CK_DES
+ printf(" Telnet DES Encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_DES */
+#ifdef CK_CAST
+ printf(" Telnet CAST Encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_CAST */
+
+#ifdef CK_KERBEROS
+#ifdef KRB5
+#ifdef ALLOW_KRB_3DES_ENCRYPT
+ printf(" Kerberos 3DES/AES Telnet Encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* ALLOW_KRB_3DES_ENCRYPT */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#endif /* CK_ENCRYPTION */
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_FORWARD_X
+ printf(" X Windows forwarding\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_FORWARD_X */
+#ifdef TN_COMPORT
+ printf(" Telnet Remote Com Port Control Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* TN_COMPORT */
+#ifdef CK_SOCKS
+#ifdef CK_SOCKS5
+ printf(" SOCKS 5\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#else /* CK_SOCKS5 */
+ printf(" SOCKS 4\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_SOCKS5 */
+#endif /* CK_SOCKS */
+#ifdef NEWFTP
+ printf(" Built-in FTP client\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* NEWFTP */
+#ifdef CKHTTP
+ printf(" Built-in HTTP client\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CKHTTP */
+#endif /* NETCONN */
+
+#ifdef CK_RTSCTS
+ printf(" Hardware flow control\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_RTSCTS */
+
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+ printf(" Built-in XYZMODEM protocols\n");
+#else
+ printf(" External XYZMODEM protocol support\n");
+#endif /* XYZ_INTERNAL */
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_XYZ */
+
+#ifndef NOCSETS
+ printf(" Latin-1 (West European) character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#ifdef LATIN2
+ printf(" Latin-2 (East European) character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ printf(" Cyrillic (Russian, Ukrainian, etc) character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CYRILLIC */
+#ifdef GREEK
+ printf(" Greek character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* GREEK */
+#ifdef HEBREW
+ printf(" Hebrew character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* HEBREW */
+#ifdef KANJI
+ printf(" Japanese character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* KANJI */
+#ifdef UNICODE
+ printf(" Unicode character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* UNICODE */
+#ifdef CKOUNI
+ if (isunicode())
+ printf(" Unicode support for ISO-2022 Terminal Emulation\n");
+ else
+ printf(" Unicode translation for Terminal Character-Sets\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CKOUNI */
+#endif /* NOCSETS */
+
+#ifdef NETPTY
+ printf(" Pseudoterminal control\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* NETPTY */
+
+#ifdef CK_REDIR
+ printf(" REDIRECT command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_REDIR */
+
+#ifdef CK_RESEND
+ printf(" RESEND command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_RESEND */
+
+#ifndef NOXFER
+#ifdef CK_CURSES
+ printf(" Fullscreen file transfer display\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_CURSES */
+#endif /* NOXFER */
+
+#ifdef CK_SPEED
+ printf(" Control-character unprefixing\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_SPEED */
+
+#ifdef STREAMING
+ printf(" Streaming\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* STREAMING */
+
+#ifdef CK_AUTODL
+ printf(" Autodownload\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_AUTODL */
+
+#ifdef OS2MOUSE
+ printf(" Mouse support\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* OS2MOUSE */
+
+#ifdef CK_REXX
+ printf(" REXX script language interface\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_REXX */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ printf(" Internet Kermit Service with user login support\n");
+#else /* CK_LOGIN */
+ printf(" Internet Kermit Service without user login support\n");
+#endif /* CK_LOGIN */
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* IKSD */
+
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf("Major optional features not included:\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+
+ if (sizeof(CK_OFF_T) <= 4) {
+ printf(" No large files or large integers\n");
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) return(1); else lines = 0;
+ }
+ }
+
+#ifdef NOXFER
+ printf(" No file-transfer protocols\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else
+#ifndef CK_CURSES
+#ifndef MAC
+ printf(" No fullscreen file transfer display\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* MAC */
+#endif /* CK_CURSES */
+
+#ifdef NOSERVER
+ printf(" No server mode\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOSERVER */
+
+#ifndef CK_SPEED
+ printf(" No control-character unprefixing\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_SPEED */
+
+#ifndef STREAMING
+ printf(" No streaming\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* STREAMING */
+
+#ifndef CK_AUTODL
+ printf(" No autodownload\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_AUTODL */
+
+#ifndef CK_XYZ
+ printf(" No built-in XYZMODEM protocols\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_XYZ */
+
+#ifdef NOFLOAT
+ printf(" No floating-point arithmetic\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+ printf(" No S-Expressions (LISP interpreter)\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else
+#ifdef NOSEXP
+ printf(" No S-Expressions (LISP interpreter)\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOSEXP */
+#endif /* NOFLOAT */
+
+#ifdef NOTLOG
+ printf(" No transaction log\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOTLOG */
+#endif /* NOXFER */
+
+#ifdef NODEBUG
+ printf(" No debugging\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NODEBUG */
+
+#ifdef NOHELP
+ printf(" No built-in help\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOHELP */
+
+#ifdef NOLOCAL
+ printf(" No making connections\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else
+#ifndef NETCONN
+ printf(" No network support\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else /* NETCONN */
+#ifndef IKS_OPTION
+ printf(" No Telnet Kermit Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* IKS_OPTION */
+#endif /* NETCONN */
+
+#ifdef NOSSH
+ printf(" No Secure Shell (SSH)\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* NOSSH */
+#ifndef CK_AUTHENTICATION
+ printf(" No Kerberos(TM) authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" No SRP(TM) (Secure Remote Password) protocol\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" No Secure Sockets Layer (SSL) protocol\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" No Transport Layer Security (TLS) protocol\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" No encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else /* CK_AUTHENTICATION */
+#ifndef CK_KERBEROS
+ printf(" No Kerberos(TM) authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else /* CK_KERBEROS */
+#ifndef KRB4
+ printf(" No Kerberos(TM) IV authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* KRB4 */
+#ifndef KRB5
+ printf(" No Kerberos(TM) V authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+#ifndef CK_SRP
+ printf(" No SRP(TM) (Secure Remote Password) authentication\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_SRP */
+#ifndef CK_SSL
+ printf(" No Secure Sockets Layer (SSL) protocol\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" No Transport Layer Security (TLS) protocol\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_SSL */
+#ifndef CK_ENCRYPTION
+ printf(" No Telnet Encryption Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else /* CK_ENCRYPTION */
+#ifndef OS2
+#ifndef CK_DES
+ printf(" No Telnet DES encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_DES */
+#ifndef CK_CAST
+ printf(" No Telnet CAST encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_CAST */
+
+#ifdef COMMENT
+#ifdef CK_KERBEROS
+#ifdef KRB5
+#ifndef ALLOW_KRB_3DES_ENCRYPT
+ printf(" No Kerberos 3DES/AES Telnet Encryption\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* ALLOW_KRB_3DES_ENCRYPT */
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+#endif /* COMMENT */
+
+#endif /* OS2 */
+#endif /* CK_ENCRYPTION */
+#endif /* CK_AUTHENTICATION */
+#ifndef CK_FORWARD_X
+ printf(" No X Windows forwarding\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_FORWARD_X */
+#ifndef TN_COMPORT
+ printf(" No Telnet Remote Com Port Control Option\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* TN_COMPORT */
+#ifndef CK_SOCKS
+ printf(" No SOCKS\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_SOCKS */
+#ifndef NEWFTP
+ printf(" No built-in FTP client\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* NEWFTP */
+#ifdef NOHTTP
+ printf(" No built-in HTTP client\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* NOHTTP */
+
+#ifdef NODIAL
+ printf(" No DIAL command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else
+#ifdef MINIDIAL
+ printf(" Support for most modem types excluded\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* MINIDIAL */
+#endif /* NODIAL */
+#endif /* NOLOCAL */
+
+#ifndef CK_RTSCTS
+#ifndef MAC
+ printf(" No hardware flow control\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* MAC */
+#endif /* CK_RTSCTS */
+
+#ifdef NOXMIT
+ printf(" No TRANSMIT command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOXMIT */
+
+#ifdef NOSCRIPT
+ printf(" No SCRIPT command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOSCRIPT */
+
+#ifdef NOSPL
+ printf(" No script programming features\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOSPL */
+
+#ifdef NOCSETS
+ printf(" No character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#else
+
+#ifndef LATIN2
+ printf(" No Latin-2 character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* LATIN2 */
+
+#ifdef NOGREEK
+ printf(" No Greek character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOGREEK */
+
+#ifdef NOHEBREW
+ printf(" No Hebrew character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOHEBREW */
+
+#ifdef NOUNICODE
+ printf(" No Unicode character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOUNICODE */
+
+#ifdef NOCYRIL
+ printf(" No Cyrillic character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOCYRIL */
+
+#ifndef KANJI
+ printf(" No Kanji character-set translation\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* KANJI */
+#endif /* NOCSETS */
+
+#ifdef NOCMDL
+ printf(" No command-line arguments\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOCMDL */
+
+#ifdef NOPUSH
+ printf(" No escape to system\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOPUSH */
+
+#ifdef NOJC
+#ifdef UNIX
+ printf(" No UNIX job control\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* UNIX */
+#endif /* NOJC */
+
+#ifdef NOSETKEY
+ printf(" No SET KEY command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NOSETKEY */
+
+#ifndef CK_REDIR
+ printf(" No REDIRECT or PIPE command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_REDIR */
+
+#ifdef UNIX
+#ifndef NETPTY
+ printf(" No pseudoterminal control\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* NETPTY */
+#endif /* UNIX */
+
+#ifndef CK_RESEND
+ printf(" No RESEND command\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_RESEND */
+
+#ifdef OS2
+#ifdef __32BIT__
+#ifndef OS2MOUSE
+ printf(" No Mouse support\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* __32BIT__ */
+#endif /* OS2 */
+#endif /* OS2MOUSE */
+
+#ifdef OS2
+#ifndef NT
+#ifndef CK_REXX
+ printf(" No REXX script language interface\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* CK_REXX */
+#endif /* NT */
+#endif /* OS2 */
+
+#ifndef IKSD
+ printf(" No Internet Kermit Service\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ flag = 1;
+#endif /* IKSD */
+
+ if (flag == 0) {
+ printf(" None\n");
+ if (++lines > cmd_rows - 3)
+ { if (!askmore()) return(1); else lines = 0; }
+ }
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+
+#ifdef CK_UTSNAME
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf("Host info:\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" Machine: %s\n",unm_mch[0] ? unm_mch : "(unknown)");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" Model: %s\n",unm_mod[0] ? unm_mod : "(unknown)");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" OS: %s\n",unm_nam[0] ? unm_nam : "(unknown)");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" OS Release: %s\n",unm_rel[0] ? unm_rel : "(unknown)");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf(" OS Version: %s\n",unm_ver[0] ? unm_ver : "(unknown)");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+ printf("\n");
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* CK_UTSNAME */
+
+/*
+ Print compile-time (-D) options, as well as C preprocessor
+ predefined symbols that might affect us...
+*/
+#ifdef KTARGET
+ {
+ char * s; /* Makefile target */
+ s = KTARGET;
+ if (!s) s = "";
+ if (!*s) s = "(unknown)";
+ printf("\n");
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) return(1); else lines = 0;
+ }
+ printf("Target: %s\n", s);
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) return(1); else lines = 0;
+ }
+ }
+#endif /* KTARGET */
+
+#ifdef __VERSION__
+#ifdef __GNUC__
+ printf("GCC version: %s\n", __VERSION__);
+#else
+ printf("Compiler version: %s\n", __VERSION__);
+#endif /* __GNUC__ */
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* __VERSION__ */
+
+#ifdef __DATE__ /* GNU and other ANSI */
+#ifdef __TIME__
+ printf("Compiled %s %s, options:\n", __DATE__, __TIME__);
+#else
+ printf("Compiled %s, options:\n", __DATE__);
+#endif /* __TIME__ */
+#else /* !__DATE__ */
+ printf("Compiler options:\n");
+#endif /* __DATE__ */
+ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+
+ for (i = 0; i < noptlist; i++) /* Print sorted option list */
+ if (!prtopt(&lines,optlist[i]))
+ return(0);
+
+ if (!prtopt(&lines,"")) return(0); /* Start a new section */
+
+/* Sizes of data types */
+
+ ckmakmsg(line,
+ LINBUFSIZ,
+ "byte order: ",
+ byteorder ? "little" : "big",
+ " endian",
+ NULL
+ );
+ {
+/* Whether to use %d or %ld with sizeof is a portability issue, so... */
+ int size = 0;
+
+ if (!prtopt(&lines,line)) return(0);
+ if (!prtopt(&lines,"")) return(0); /* Start a new section */
+
+ size = (int)sizeof(int);
+ sprintf(line,"sizeofs: int=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+ size = (int)sizeof(long);
+ sprintf(line,"long=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+#ifndef OS2
+ /* Windows doesn't have off_t */
+ size = (int)sizeof(off_t);
+ sprintf(line,"off_t=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+#endif /* OS2 */
+
+ size = (int)sizeof(CK_OFF_T);
+ sprintf(line,"CK_OFF_T=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+#ifdef BIGBUFOK
+ size = (int)sizeof(size_t);
+ sprintf(line,"size_t=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+#endif /* BIGBUFOK */
+
+ size = (int)sizeof(short);
+ sprintf(line,"short=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+ size = (int)sizeof(char);
+ sprintf(line,"char=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+ size = (int)sizeof(char *);
+ sprintf(line,"char*=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+ size = (int)sizeof(float);
+ sprintf(line,"float=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+
+ size = (int)sizeof(double);
+ sprintf(line,"double=%d",size); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+ }
+
+#ifdef FNFLOAT
+ if (!prtopt(&lines,"")) return(0); /* Start a new section */
+ if (!prtopt(&lines,"floating-point:")) return(0);
+ sprintf(line,"precision=%d",fp_digits); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+ sprintf(line,"rounding=%d",fp_rounding); /* SAFE */
+ if (!prtopt(&lines,line)) return(0);
+#endif /* FNFLOAT */
+
+ prtopt(&lines,"");
+ return(0);
+}
+#endif /* NOSHOW */
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuus6.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus6.c
new file mode 100644
index 0000000..a4990c6
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus6.c
@@ -0,0 +1,12009 @@
+#include "ckcsym.h"
+#ifndef NOICP
+
+/*
+ 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, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/* Includes */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+#include "ckcnet.h" /* Network symbols */
+#include <signal.h>
+
+#ifndef NOSTAT
+#ifdef VMS
+/* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
+#include <stat.h>
+#else /* def VMS */
+#include <sys/stat.h>
+#endif /* def VMS [else] */
+#endif /* NOSTAT */
+
+#ifdef VMS
+#ifndef TCPSOCKET
+#include <errno.h>
+#endif /* TCPSOCKET */
+#endif /* VMS */
+
+#ifdef datageneral
+#define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
+#endif /* datageneral */
+
+#ifdef QNX6
+#define readblock kreadblock
+#endif /* QNX6 */
+
+/* External Kermit Variables, see ckmain.c for description. */
+
+extern xx_strp xxstring;
+
+extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
+ turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
+ zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive;
+
+extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive,
+ xcmdsrc, nscanfile, reliable, nolinks, cmflgs;
+
+#ifdef VMSORUNIX
+extern int zgfs_dir, zgfs_link;
+#endif /* VMSORUNIX */
+
+#ifdef CK_IFRO
+ extern int remonly;
+#endif /* CK_IFRO */
+
+#ifdef OS2
+extern int StartedFromDialer ;
+extern int vmode;
+extern int k95stdout;
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#endif /* NT */
+#include "ckocon.h"
+#endif /* OS2 */
+
+extern long vernum, speed;
+extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
+extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
+extern char *foz_def[];
+extern char *ckxsys, *ckzsys;
+#ifndef OS2
+extern char *DIRCMD;
+#ifndef UNIX
+extern char *DELCMD;
+#endif /* UNIX */
+#endif /* OS2 */
+extern char ttname[], filnam[];
+extern CHAR sstate, feol;
+extern char *zinptr;
+
+#ifdef UNIX
+extern char ** mtchs; /* zxpand() file list */
+#endif /* UNIX */
+
+#ifndef NOXFER
+extern int oopts, omode, oname, opath; /* O-Packet options */
+
+extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
+ stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
+ atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
+ fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
+ g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
+ g_fnspath, g_fnrpath, xfrxla, g_xfrxla;
+
+extern char *cmarg, *cmarg2;
+
+#ifndef NOMSEND /* Multiple SEND */
+extern char *msfiles[];
+#endif /* NOMSEND */
+extern char fspec[]; /* Most recent filespec */
+extern int fspeclen;
+
+#ifdef CK_TMPDIR
+extern int f_tmpdir; /* Directory changed temporarily */
+extern char savdir[]; /* For saving current directory */
+#endif /* CK_TMPDIR */
+
+extern struct keytab protos[]; /* File transfer protocols */
+extern struct ck_p ptab[NPROTOS];
+#endif /* NOXFER */
+
+#ifdef DCMDBUF /* Declarations from cmd package */
+extern char *cmdbuf, *atmbuf; /* Command buffers */
+#else
+extern char cmdbuf[], atmbuf[]; /* Command buffers */
+#endif /* DCMDBUF */
+
+extern int nopush;
+
+#ifndef NOSPL
+int askflag = 0; /* ASK-class command active */
+int echostars = 0; /* ASKQ should echo asterisks */
+extern char **a_ptr[];
+extern int a_dim[];
+extern char **m_xarg[];
+extern int n_xarg[];
+extern struct mtab *mactab;
+extern int nmac;
+extern long ck_alarm;
+extern char alrm_date[], alrm_time[];
+extern int x_ifnum;
+#endif /* NOSPL */
+
+extern int inserver; /* I am IKSD */
+extern int backgrd; /* Kermit executing in background */
+extern char psave[]; /* For saving & restoring prompt */
+extern char *tp; /* Temporary buffer */
+
+int readblock = 4096; /* READ buffer size */
+CHAR * readbuf = NULL; /* Pointer to read buffer */
+int readsize = 0; /* Number of chars actually read */
+int getcmd = 0; /* GET-class command was given */
+
+extern int zchkod, zchkid;
+
+/* C K U U S 6 -- "User Interface" for Unix Kermit (Part 6) */
+
+struct keytab deltab[] = { /* DELETE Command Options */
+ { "/all", DEL_ALL, CM_INV },
+ { "/after", DEL_AFT, CM_ARG },
+ { "/ask", DEL_ASK, 0 },
+ { "/before", DEL_BEF, CM_ARG },
+ { "/directories", DEL_DIR, 0 },
+ { "/dotfiles", DEL_DOT, 0 },
+ { "/except", DEL_EXC, CM_ARG },
+ { "/heading", DEL_HDG, 0 },
+ { "/l", DEL_LIS, CM_INV|CM_ABR },
+ { "/larger-than", DEL_LAR, CM_ARG },
+ { "/list", DEL_LIS, 0 },
+ { "/log", DEL_LIS, CM_INV },
+ { "/noask", DEL_NAS, 0 },
+ { "/nodotfiles", DEL_NOD, 0 },
+ { "/noheading", DEL_NOH, 0 },
+ { "/nol", DEL_NOL, CM_INV|CM_ABR },
+ { "/nolist", DEL_NOL, 0 },
+ { "/nolog", DEL_NOL, CM_INV },
+ { "/nopage", DEL_NOP, 0 },
+ { "/not-after", DEL_NAF, CM_ARG },
+ { "/not-before", DEL_NBF, CM_ARG },
+ { "/not-since", DEL_NAF, CM_INV|CM_ARG },
+ { "/page", DEL_PAG, 0 },
+ { "/quiet", DEL_QUI, CM_INV },
+ { "/recursive", DEL_REC, 0 },
+ { "/simulate", DEL_SIM, 0 },
+ { "/since", DEL_AFT, CM_ARG|CM_INV },
+ { "/smaller-than", DEL_SMA, CM_ARG },
+ { "/summary", DEL_SUM, 0 },
+ { "/tree", DEL_ALL, 0 },
+ { "/type", DEL_TYP, CM_ARG },
+ { "/verbose", DEL_VRB, CM_INV }
+};
+int ndeltab = sizeof(deltab)/sizeof(struct keytab);
+
+/* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
+
+struct keytab qvswtab[] = {
+ { "/l", DEL_LIS, CM_INV|CM_ABR },
+ { "/list", DEL_LIS, 0 },
+ { "/log", DEL_LIS, CM_INV },
+ { "/nol", DEL_NOL, CM_INV|CM_ABR },
+ { "/nolist", DEL_NOL, 0 },
+ { "/nolog", DEL_NOL, CM_INV },
+ { "/quiet", DEL_QUI, CM_INV },
+ { "/verbose", DEL_VRB, CM_INV }
+};
+int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
+
+static struct keytab renamsw[] = {
+ { "/collision", REN_OVW, CM_ARG },
+#ifndef NOUNICODE
+ { "/convert", REN_XLA, CM_ARG },
+#endif /* NOUNICODE */
+ { "/fixspaces", REN_SPA, CM_ARG },
+ { "/l", DEL_LIS, CM_INV|CM_ABR },
+ { "/list", DEL_LIS, 0 },
+ { "/log", DEL_LIS, CM_INV },
+ { "/lower", REN_LOW, CM_ARG },
+ { "/nol", DEL_NOL, CM_INV|CM_ABR },
+ { "/nolist", DEL_NOL, 0 },
+ { "/nolog", DEL_NOL, CM_INV },
+ { "/quiet", DEL_QUI, CM_INV },
+ { "/replace", REN_RPL, CM_ARG },
+ { "/simulate", DEL_SIM, 0 },
+ { "/upper", REN_UPP, CM_ARG },
+ { "/verbose", DEL_VRB, CM_INV }
+};
+static int nrenamsw = sizeof(renamsw)/sizeof(struct keytab);
+
+static struct keytab renamset[] = {
+ { "collision", REN_OVW, 0 },
+ { "list", DEL_LIS, 0 }
+};
+static int nrenamset = sizeof(renamset)/sizeof(struct keytab);
+
+/* Args for RENAME /LOWER: and /UPPER: */
+
+static struct keytab r_upper[] = {
+ { "all", 1, 0 },
+ { "lower", 0, 0 }
+};
+
+static struct keytab r_lower[] = {
+ { "all", 1, 0 },
+ { "upper", 0, 0 }
+};
+
+/* Args for RENAME /COLLISION... */
+
+#define RENX_FAIL 0
+#define RENX_OVWR 1
+#define RENX_SKIP 2
+
+static struct keytab r_collision[] = {
+ { "fail", RENX_FAIL, 0 },
+ { "overwrite", RENX_OVWR, 0 },
+ { "proceed", RENX_SKIP, CM_INV },
+ { "skip", RENX_SKIP, 0 }
+};
+static int nr_collision = sizeof(r_collision)/sizeof(struct keytab);
+
+struct keytab copytab[] = {
+ { "/append", 998, 0 },
+#ifndef NOSPL
+ { "/fromb64", 997, 0 },
+#endif /* NOSPL */
+ { "/l", DEL_LIS, CM_INV|CM_ABR },
+ { "/list", DEL_LIS, 0 },
+ { "/log", DEL_LIS, CM_INV },
+ { "/nol", DEL_NOL, CM_INV|CM_ABR },
+ { "/nolist", DEL_NOL, 0 },
+ { "/nolog", DEL_NOL, CM_INV },
+ { "/overwrite", 994, CM_ARG },
+#ifndef NOXFER
+ { "/preserve", 995, 0 },
+#endif /* NOXFER */
+ { "/quiet", DEL_QUI, CM_INV },
+ { "/swap-bytes", 999, 0 },
+#ifndef NOSPL
+ { "/tob64", 996, 0 },
+#endif /* NOSPL */
+ { "/verbose", DEL_VRB, CM_INV }
+};
+int ncopytab = sizeof(copytab)/sizeof(struct keytab);
+
+#define OVW_ALWAYS 0
+#define OVW_NEVER 1
+#define OVW_OLDER 2
+#define OVW_NEWER 3
+
+static struct keytab ovwtab[] = {
+ { "always", OVW_ALWAYS, 0 },
+ { "never", OVW_NEVER, 0 },
+ { "newer", OVW_NEWER, 0 },
+ { "older", OVW_OLDER, 0 }
+};
+static int novwtab = 4;
+
+#ifndef NOXFER
+static struct keytab gettab[] = { /* GET options */
+ { "/as-name", SND_ASN, CM_ARG },
+ { "/binary", SND_BIN, 0 },
+#ifdef CALIBRATE
+ { "/calibrate", SND_CAL, CM_INV },
+#endif /* CALIBRATE */
+#ifdef PIPESEND
+ { "/command", SND_CMD, CM_PSH },
+#endif /* PIPESEND */
+ { "/delete", SND_DEL, 0 },
+ { "/except", SND_EXC, CM_ARG },
+ { "/filenames", SND_NAM, CM_ARG },
+#ifdef PIPESEND
+ { "/filter", SND_FLT, CM_ARG|CM_PSH },
+#endif /* PIPESEND */
+#ifdef VMS
+ { "/image", SND_IMG, 0 },
+ { "/labeled", SND_LBL, 0 },
+#else
+ { "/image", SND_BIN, CM_INV },
+#endif /* VMS */
+#ifdef CK_TMPDIR
+ { "/move-to", SND_MOV, CM_ARG },
+#endif /* CK_TMPDIR */
+ { "/pathnames", SND_PTH, CM_ARG },
+ { "/pipes", SND_PIP, CM_ARG|CM_PSH },
+ { "/quiet", SND_SHH, 0 },
+#ifdef CK_RESEND
+ { "/recover", SND_RES, 0 },
+#endif /* CK_RESEND */
+ { "/recursive", SND_REC, 0 },
+ { "/rename-to", SND_REN, CM_ARG },
+#ifdef COMMENT
+ { "/smaller-than", SND_SMA, CM_ARG },
+#endif /* COMMENT */
+ { "/subdirectories", SND_REC, CM_INV },
+ { "/text", SND_TXT, 0 },
+ { "/transparent", SND_XPA, 0 }
+};
+#define NGETTAB sizeof(gettab)/sizeof(struct keytab)
+static int ngettab = NGETTAB;
+
+static struct keytab rcvtab[] = { /* RECEIVE options */
+ { "/as-name", SND_ASN, CM_ARG },
+ { "/binary", SND_BIN, 0 },
+#ifdef CALIBRATE
+ { "/calibrate", SND_CAL, CM_INV },
+#endif /* CALIBRATE */
+#ifdef PIPESEND
+ { "/command", SND_CMD, CM_PSH },
+#endif /* PIPESEND */
+ { "/except", SND_EXC, CM_ARG },
+ { "/filenames", SND_NAM, CM_ARG },
+#ifdef PIPESEND
+ { "/filter", SND_FLT, CM_ARG|CM_PSH },
+#endif /* PIPESEND */
+#ifdef VMS
+ { "/image", SND_IMG, 0 },
+ { "/labeled", SND_LBL, 0 },
+#else
+ { "/image", SND_BIN, CM_INV },
+#endif /* VMS */
+#ifdef CK_TMPDIR
+ { "/move-to", SND_MOV, CM_ARG },
+#endif /* CK_TMPDIR */
+ { "/pathnames", SND_PTH, CM_ARG },
+ { "/pipes", SND_PIP, CM_ARG|CM_PSH },
+#ifdef CK_XYZ
+ { "/protocol", SND_PRO, CM_ARG },
+#else
+ { "/protocol", SND_PRO, CM_ARG|CM_INV },
+#endif /* CK_XYZ */
+ { "/quiet", SND_SHH, 0 },
+ { "/recursive", SND_REC, 0 },
+ { "/rename-to", SND_REN, CM_ARG },
+ { "/text", SND_TXT, 0 },
+ { "/transparent", SND_XPA, 0 }
+};
+#define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
+static int nrcvtab = NRCVTAB;
+#endif /* NOXFER */
+
+/* WAIT table */
+
+#define WAIT_FIL 997
+#define WAIT_MDM 998
+
+struct keytab waittab[] = {
+ { "cd", BM_DCD, CM_INV }, /* (Carrier Detect) */
+ { "cts", BM_CTS, CM_INV }, /* (Clear To Send) */
+ { "dsr", BM_DSR, CM_INV }, /* (Data Set Ready) */
+ { "file", WAIT_FIL, 0 }, /* New category selector keywords */
+ { "modem-signals", WAIT_MDM, 0 }, /* ... */
+ { "ri", BM_RNG, CM_INV } /* (Ring Indicator) */
+};
+int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
+
+/* Modem signal table */
+
+struct keytab mstab[] = {
+ { "cd", BM_DCD, 0 }, /* Carrier Detect */
+ { "cts", BM_CTS, 0 }, /* Clear To Send */
+ { "dsr", BM_DSR, 0 }, /* Data Set Ready */
+ { "ri", BM_RNG, 0 } /* Ring Indicator */
+};
+int nms = (sizeof(mstab) / sizeof(struct keytab));
+
+#define WF_MOD 1
+#define WF_DEL 2
+#define WF_CRE 3
+
+struct keytab wfswi[] = { /* WAIT FILE switches */
+ { "creation", WF_CRE, 0 }, /* Wait for file to be created */
+ { "deletion", WF_DEL, 0 }, /* Wait for file to be deleted */
+ { "modification", WF_MOD, 0 } /* Wait for file to be modified */
+};
+int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
+
+#ifndef NOSPL
+struct keytab asgtab[] = { /* Assignment operators for "." */
+ { "::=", 2, 0 }, /* ASSIGN and EVALUATE */
+ { ":=", 1, 0 }, /* ASSIGN */
+ { "=", 0, 0 } /* DEFINE */
+};
+int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
+
+struct keytab opntab[] = {
+#ifndef NOPUSH
+ { "!read", OPN_PI_R, CM_INV },
+ { "!write", OPN_PI_W, CM_INV },
+#endif /* NOPUSH */
+ { "append", OPN_FI_A, 0 },
+ { "host", OPN_NET, 0 },
+#ifdef OS2
+ { "line", OPN_SER, CM_INV },
+ { "port", OPN_SER, 0 },
+#else
+ { "line", OPN_SER, 0 },
+ { "port", OPN_SER, CM_INV },
+#endif /* OS2 */
+ { "read", OPN_FI_R, 0 },
+ { "write", OPN_FI_W, 0 }
+};
+int nopn = (sizeof(opntab) / sizeof(struct keytab));
+
+/* IF conditions */
+
+#define XXIFCO 0 /* IF COUNT */
+#define XXIFER 1 /* IF ERRORLEVEL */
+#define XXIFEX 2 /* IF EXIST */
+#define XXIFFA 3 /* IF FAILURE */
+#define XXIFSU 4 /* IF SUCCESS */
+#define XXIFNO 5 /* IF NOT */
+#define XXIFDE 6 /* IF DEFINED */
+#define XXIFEQ 7 /* IF EQUAL (strings) */
+#define XXIFAE 8 /* IF = (numbers) */
+#define XXIFLT 9 /* IF < (numbers) */
+#define XXIFGT 10 /* IF > (numbers) */
+#define XXIFLL 11 /* IF Lexically Less Than (strings) */
+#define XXIFLG 12 /* IF Lexically Greater Than (strings) */
+#define XXIFEO 13 /* IF EOF (READ file) */
+#define XXIFBG 14 /* IF BACKGROUND */
+#define XXIFNU 15 /* IF NUMERIC */
+#define XXIFFG 16 /* IF FOREGROUND */
+#define XXIFDI 17 /* IF DIRECTORY */
+#define XXIFNE 18 /* IF NEWER */
+#define XXIFRO 19 /* IF REMOTE-ONLY */
+#define XXIFAL 20 /* IF ALARM */
+#define XXIFSD 21 /* IF STARTED-FROM-DIALER */
+#define XXIFTR 22 /* IF TRUE */
+#define XXIFNT 23 /* IF FALSE */
+#define XXIFTM 24 /* IF TERMINAL-MACRO */
+#define XXIFEM 25 /* IF EMULATION */
+#define XXIFOP 26 /* IF OPEN */
+#define XXIFLE 27 /* IF <= */
+#define XXIFGE 28 /* IF >= */
+#define XXIFIP 29 /* IF INPATH */
+#define XXIFTA 30 /* IF TAPI */
+#define XXIFMA 31 /* IF MATCH */
+#define XXIFFL 32 /* IF FLAG */
+#define XXIFAB 33 /* IF ABSOLUTE */
+#define XXIFAV 34 /* IF AVAILABLE */
+#define XXIFAT 35 /* IF ASKTIMEOUT */
+#define XXIFRD 36 /* IF READABLE */
+#define XXIFWR 37 /* IF WRITEABLE */
+#define XXIFAN 38 /* IF ... AND ... */
+#define XXIFOR 39 /* IF ... OR ... */
+#define XXIFLP 40 /* IF left parenthesis */
+#define XXIFRP 41 /* IF right parenthesis */
+#define XXIFNQ 42 /* IF != (== "NOT =") */
+#define XXIFQU 43 /* IF QUIET */
+#define XXIFCK 44 /* IF C-KERMIT */
+#define XXIFK9 45 /* IF K-95 */
+#define XXIFMS 46 /* IF MS-KERMIT */
+#define XXIFWI 47 /* IF WILD */
+#define XXIFLO 48 /* IF LOCAL */
+#define XXIFCM 49 /* IF COMMAND */
+#define XXIFFP 50 /* IF FLOAT */
+#define XXIFIK 51 /* IF IKS */
+#define XXIFKB 52 /* IF KBHIT */
+#define XXIFKG 53 /* IF KERBANG */
+#define XXIFVE 54 /* IF VERSION */
+#define XXIFDC 55 /* IF DECLARED */
+#define XXIFGU 56 /* IF GUI */
+#define XXIFLN 57 /* IF LINK */
+#define XXIFDB 58 /* IF DEBUG */
+
+struct keytab iftab[] = { /* IF commands */
+ { "!", XXIFNO, 0 },
+ { "!=", XXIFNQ, 0 },
+ { "&&", XXIFAN, 0 },
+ { "(", XXIFLP, 0 },
+ { ")", XXIFRP, 0 },
+ { "<", XXIFLT, 0 },
+ { "<=", XXIFLE, 0 },
+ { "=", XXIFAE, 0 },
+ { "==", XXIFAE, CM_INV },
+ { ">", XXIFGT, 0 },
+ { ">=", XXIFGE, 0 },
+ { "absolute", XXIFAB, 0 },
+ { "alarm", XXIFAL, 0 },
+ { "and", XXIFAN, 0 },
+ { "asktimeout", XXIFAT, 0 },
+ { "available", XXIFAV, 0 },
+ { "background", XXIFBG, 0 },
+ { "c-kermit", XXIFCK, 0 },
+ { "command", XXIFCM, 0 },
+ { "count", XXIFCO, 0 },
+ { "dcl", XXIFDC, CM_INV },
+ { "debug", XXIFDB, 0 },
+ { "declared", XXIFDC, 0 },
+ { "defined", XXIFDE, 0 },
+#ifdef CK_TMPDIR
+ { "directory", XXIFDI, 0 },
+#endif /* CK_TMPDIR */
+ { "emulation", XXIFEM, 0 },
+#ifdef COMMENT
+ { "eof", XXIFEO, 0 },
+#endif /* COMMENT */
+ { "equal", XXIFEQ, 0 },
+ { "error", XXIFFA, CM_INV },
+ { "exist", XXIFEX, 0 },
+ { "failure", XXIFFA, 0 },
+ { "false", XXIFNT, 0 },
+ { "flag", XXIFFL, 0 },
+#ifdef CKFLOAT
+ { "float", XXIFFP, 0 },
+#endif /* CKFLOAT */
+ { "foreground", XXIFFG, 0 },
+#ifdef OS2
+ { "gui", XXIFGU, 0 },
+#else
+ { "gui", XXIFGU, CM_INV },
+#endif /* OS2 */
+#ifdef IKSD
+ { "iksd", XXIFIK, 0 },
+#else
+ { "iksd", XXIFIK, CM_INV },
+#endif /* IKSD */
+ { "integer", XXIFNU, CM_INV },
+ { "k-95", XXIFK9, 0 },
+ { "kbhit", XXIFKB, 0 },
+#ifdef UNIX
+ { "kerbang", XXIFKG, 0 },
+#else
+ { "kerbang", XXIFKG, CM_INV },
+#endif /* UNIX */
+ { "lgt", XXIFLG, 0 },
+#ifdef UNIX
+ { "link", XXIFLN, 0 },
+#endif /* UNIX */
+ { "llt", XXIFLL, 0 },
+ { "local", XXIFLO, 0 },
+ { "match", XXIFMA, 0 },
+ { "ms-kermit", XXIFMS, CM_INV },
+#ifdef ZFCDAT
+ { "newer", XXIFNE, 0 },
+#endif /* ZFCDAT */
+ { "not", XXIFNO, 0 },
+ { "numeric", XXIFNU, 0 },
+ { "ok", XXIFSU, CM_INV },
+ { "open", XXIFOP, 0 },
+ { "or", XXIFOR, 0 },
+ { "quiet", XXIFQU, 0 },
+ { "readable", XXIFRD, 0 },
+ { "remote-only",XXIFRO, 0 },
+ { "started-from-dialer",XXIFSD, CM_INV },
+ { "success", XXIFSU, 0 },
+ { "tapi", XXIFTA, 0 },
+#ifdef OS2
+ { "terminal-macro", XXIFTM, 0 },
+#else
+ { "terminal-macro", XXIFTM, CM_INV },
+#endif /* OS2 */
+ { "true", XXIFTR, 0 },
+ { "version", XXIFVE, 0 },
+ { "wild", XXIFWI, 0 },
+ { "writeable", XXIFWR, 0 },
+ { "||", XXIFOR, 0 },
+ { "", 0, 0 }
+};
+int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
+
+struct keytab iotab[] = { /* Keywords for IF OPEN */
+ { "!read-file", ZRFILE, CM_INV },
+ { "!write-file", ZWFILE, CM_INV },
+ { "append-file", ZWFILE, CM_INV },
+ { "connection", 8888, 0 },
+#ifdef CKLOGDIAL
+ { "cx-log", 7777, 0 },
+#endif /* CKLOGDIAL */
+ { "debug-log", ZDFILE, 0 },
+ { "error", 9999, 0 },
+ { "packet-log", ZPFILE, 0 },
+ { "read-file", ZRFILE, 0 },
+ { "screen", ZSTDIO, 0 },
+ { "session-log", ZSFILE, 0 },
+ { "transaction-log", ZTFILE, 0 },
+ { "write-file", ZWFILE, 0 }
+};
+int niot = (sizeof(iotab) / sizeof(struct keytab));
+#endif /* NOSPL */
+
+/* Variables and prototypes */
+
+_PROTOTYP(static int doymdir,(int));
+_PROTOTYP(static int renameone,(char *,char *,
+ int,int,int,int,int,int,int,int,int,int,int));
+
+#ifdef NETCONN
+extern int nnetdir; /* How many network directories */
+#endif /* NETCONN */
+#ifdef CK_SECURITY
+_PROTOTYP(int ck_krb4_is_installed,(void));
+_PROTOTYP(int ck_krb5_is_installed,(void));
+_PROTOTYP(int ck_ntlm_is_installed,(void));
+_PROTOTYP(int ck_srp_is_installed,(void));
+_PROTOTYP(int ck_ssleay_is_installed,(void));
+_PROTOTYP(int ck_ssh_is_installed,(void));
+_PROTOTYP(int ck_crypt_is_installed,(void));
+#else
+#define ck_krb4_is_installed() (0)
+#define ck_krb5_is_installed() (0)
+#define ck_ntlm_is_installed() (0)
+#define ck_srp_is_installed() (0)
+#define ck_ssleay_is_installed() (0)
+#define ck_ssh_is_installed() (0)
+#define ck_crypt_is_installed() (0)
+#endif /* CK_SECURITY */
+
+#define AV_KRB4 1
+#define AV_KRB5 2
+#define AV_NTLM 3
+#define AV_SRP 4
+#define AV_SSL 5
+#define AV_CRYPTO 6
+#define AV_SSH 7
+
+struct keytab availtab[] = { /* Available authentication types */
+ { "crypto", AV_CRYPTO, CM_INV }, /* and encryption */
+ { "encryption", AV_CRYPTO, 0 },
+ { "k4", AV_KRB4, CM_INV },
+ { "k5", AV_KRB5, CM_INV },
+ { "kerberos4", AV_KRB4, 0 },
+ { "kerberos5", AV_KRB5, 0 },
+ { "krb4", AV_KRB4, CM_INV },
+ { "krb5", AV_KRB5, CM_INV },
+ { "ntlm", AV_NTLM, 0 },
+ { "srp", AV_SRP, 0 },
+ { "ssh", AV_SSH, 0 },
+ { "ssl", AV_SSL, 0 },
+ { "tls", AV_SSL, 0 },
+ { "", 0, 0 }
+};
+int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
+
+#ifndef NODIAL
+_PROTOTYP(static int ddcvt, (char *, FILE *, int) );
+_PROTOTYP(static int dncvt, (int, int, int, int) );
+_PROTOTYP(char * getdname, (void) );
+
+static int partial = 0; /* For partial dial */
+static char *dscopy = NULL;
+int dialtype = -1;
+
+char *dialnum = (char *)0; /* Remember DIAL number for REDIAL */
+int dirline = 0; /* Dial directory line number */
+extern char * dialdir[]; /* Dial directory file names */
+extern int dialdpy; /* DIAL DISPLAY on/off */
+extern int ndialdir; /* How many dial directories */
+extern int ntollfree; /* Toll-free call info */
+extern int ndialpxx; /* List of PBX exchanges */
+extern char *dialtfc[];
+char * matchpxx = NULL; /* PBX exchange that matched */
+extern int nlocalac; /* Local area-code list */
+extern char * diallcac[];
+extern int tttapi;
+#ifdef CK_TAPI
+extern int tapiconv; /* TAPI Conversions */
+extern int tapipass; /* TAPI Passthrough */
+#endif /* CK_TAPI */
+extern int dialatmo;
+extern char * dialnpr, * dialsfx;
+extern char * dialixp, * dialixs, * dialmac;
+extern char * dialldp, * diallds, * dialtfp;
+extern char * dialpxi, * dialpxo, * diallac;
+extern char * diallcp, * diallcs, * diallcc;
+extern char * dialpxx[];
+
+extern int dialcnf; /* DIAL CONFIRMATION */
+int dialfld = 0; /* DIAL FORCE-LONG-DISTANCE */
+int dialsrt = 1; /* DIAL SORT ON */
+int dialrstr = 6; /* DIAL RESTRICTION */
+int dialtest = 0; /* DIAL TEST */
+int dialcount = 0; /* \v(dialcount) */
+
+extern int dialsta; /* Dial status */
+int dialrtr = -1, /* Dial retries */
+ dialint = 10; /* Dial retry interval */
+extern long dialcapas; /* Modem capabilities */
+extern int dialcvt; /* DIAL CONVERT-DIRECTORY */
+#endif /* NODIAL */
+
+#ifndef NOSPL
+#define IFCONDLEN 256
+int ifc, /* IF case */
+ not = 0, /* Flag for IF NOT */
+ ifargs = 0; /* Count of IF condition words */
+char ifcond[IFCONDLEN]; /* IF condition text */
+char *ifcp; /* Pointer to IF condition text */
+extern int vareval;
+#ifdef DCMDBUF
+extern int
+ *ifcmd, *count, *iftest, *intime,
+ *inpcas, *takerr, *merror, *xquiet, *xvarev;
+#else
+extern int ifcmd[]; /* Last command was IF */
+extern int iftest[]; /* Last IF was true */
+extern int count[]; /* For IF COUNT, one for each cmdlvl */
+extern int intime[]; /* Ditto for other stackables... */
+extern int inpcas[];
+extern int takerr[];
+extern int merror[];
+extern int xquiet[];
+extern int xvarev[];
+#endif /* DCMDBUF */
+#else
+extern int takerr[];
+#endif /* NOSPL */
+
+#ifdef DCMDBUF
+extern char *line; /* Character buffer for anything */
+extern char *tmpbuf;
+#else
+extern char line[], tmpbuf[];
+#endif /* DCMDBUF */
+extern char *lp; /* Pointer to line buffer */
+
+int cwdf = 0; /* CWD has been done */
+
+/* Flags for ENABLE/DISABLE */
+extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
+ en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
+ en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
+
+extern FILE *tfile[]; /* File pointers for TAKE command */
+extern char *tfnam[]; /* Names of TAKE files */
+extern int tfline[]; /* TAKE-file line number */
+
+extern int success; /* Command success/failure flag */
+extern int cmdlvl; /* Current position in command stack */
+
+#ifndef NOSPL
+extern int maclvl; /* Macro to execute */
+extern char *macx[]; /* Index of current macro */
+extern char *mrval[]; /* Macro return value */
+extern char *macp[]; /* Pointer to macro */
+extern int macargc[]; /* ARGC from macro invocation */
+
+#ifdef COMMENT
+extern char *m_line[];
+#endif /* COMMENT */
+
+extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */
+extern char *g_var[]; /* Global variables %a, %b, etc */
+
+#ifdef DCMDBUF
+extern struct cmdptr *cmdstk; /* The command stack itself */
+#else
+extern struct cmdptr cmdstk[]; /* The command stack itself */
+#endif /* DCMDBUF */
+#endif /* NOSPL */
+
+#define xsystem(s) zsyscmd(s)
+
+static int x, y, z = 0;
+static char *s, *p;
+
+#ifdef OS2
+_PROTOTYP( int os2settitle, (char *, int) );
+#endif /* OS2 */
+
+extern struct keytab yesno[], onoff[], fntab[];
+extern int nyesno, nfntab;
+
+#ifndef NOSPL
+
+/* Do the ASK, ASKQ, GETOK, and READ commands */
+
+int asktimedout = 0;
+
+#define ASK_PUP 1
+#define ASK_TMO 2
+#define ASK_GUI 3
+#define ASK_QUI 4
+#define ASK_DEF 5
+#define ASK_ECH 6
+
+static struct keytab asktab[] = {
+ { "/default", ASK_DEF, CM_ARG },
+ { "/gui", ASK_GUI,
+#ifdef KUI
+ 0
+#else /* KUI */
+ CM_INV
+#endif /* KUI */
+ },
+ { "/popup", ASK_PUP,
+#ifdef OS2
+ 0
+#else /* OS2 */
+ CM_INV
+#endif /* OS2 */
+ },
+ { "/quiet", ASK_QUI, 0 },
+ { "/timeout", ASK_TMO, CM_ARG },
+ { "", 0, 0 }
+};
+static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1;
+
+static struct keytab askqtab[] = {
+ { "/default", ASK_DEF, CM_ARG },
+ { "/echo", ASK_ECH, CM_ARG },
+ { "/gui", ASK_GUI,
+#ifdef KUI
+ 0
+#else /* KUI */
+ CM_INV
+#endif /* KUI */
+ },
+ { "/noecho", ASK_QUI, CM_INV },
+ { "/popup", ASK_PUP,
+#ifdef OS2
+ 0
+#else /* OS2 */
+ CM_INV
+#endif /* OS2 */
+ },
+ { "/quiet", ASK_QUI, 0 },
+ { "/timeout", ASK_TMO, CM_ARG },
+ { "", 0, 0 }
+};
+static int naskqtab = sizeof(askqtab)/sizeof(struct keytab)-1;
+
+int
+doask(cx) int cx; {
+ extern int asktimer, timelimit;
+#ifdef CK_RECALL
+ extern int on_recall;
+#endif /* CK_RECALL */
+ int echochar = 0;
+ int popupflg = 0;
+ int guiflg = 0;
+ int nomsg = 0;
+ int mytimer = 0;
+#ifdef CK_APC
+ extern int apcactive, apcstatus;
+#endif /* CK_APC */
+
+ char dfbuf[1024]; /* Buffer for default answer */
+ char * dfanswer = NULL; /* Pointer to it */
+
+ char vnambuf[VNAML+1]; /* Buffer for variable names */
+ char *vnp = NULL; /* Pointer to same */
+
+ dfbuf[0] = NUL;
+ vnambuf[0] = NUL;
+
+#ifdef CK_APC
+ if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
+ return(success = 0);
+ }
+#endif /* CK_APC */
+
+ mytimer = asktimer; /* Inherit global ASK timer */
+ echostars = 0; /* For ASKQ */
+
+ if (cx == XXASK || cx == XXASKQ) {
+ struct FDB sw, fl;
+ int getval;
+ char c;
+ if (cx == XXASKQ) /* Don't log ASKQ response */
+ debok = 0;
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Variable name or switch",
+ "", /* default */
+ "", /* addtl string data */
+ ((cx == XXASK) ? nasktab : naskqtab), /* Table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ ((cx == XXASK) ? asktab : askqtab), /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case ASK_QUI:
+ nomsg = 1;
+ if (cx == XXASKQ)
+ echostars = 0;
+ break;
+ case ASK_PUP:
+ popupflg = 1;
+ break;
+ case ASK_GUI:
+ guiflg = 1;
+ break;
+ case ASK_TMO: {
+ if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
+ return(y);
+ if (x < 0)
+ x = 0;
+ mytimer = x;
+ break;
+ }
+ case ASK_ECH: {
+ if ((y = cmfld("Character to echo","*",&s,xxstring)) < 0)
+ return(y);
+ echochar = *s;
+ break;
+ }
+ case ASK_DEF: {
+ if ((y = cmfld("Text to supply if reply is empty",
+ "",&s,xxstring)) < 0)
+ return(y);
+ ckstrncpy(dfbuf,s,1024);
+ dfanswer = dfbuf;
+ break;
+ }
+ default: return(-2);
+ }
+ }
+ /* Have variable name, make copy. */
+ ckstrncpy(vnambuf,cmresult.sresult,VNAML);
+ vnp = vnambuf;
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&z)) < 0)
+ return(y);
+ }
+ } else if (cx != XXGOK && cx != XXRDBL) { /* Get variable name */
+ if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
+ if (y == -3) {
+ printf("?Variable name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */
+ vnp = vnambuf;
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&z)) < 0)
+ return(y);
+ }
+ }
+ if (cx == XXREA || cx == XXRDBL) { /* READ or READBLOCK command */
+ if ((y = cmcfm()) < 0) /* Get confirmation */
+ return(y);
+ if (chkfn(ZRFILE) < 1) { /* File open? */
+ printf("?Read file not open\n");
+ return(success = 0);
+ }
+ if (!(s = (char *)readbuf)) { /* Where to read into. */
+ printf("?Oops, no READ buffer!\n");
+ return(success = 0);
+ }
+ y = zsinl(ZRFILE, s, readblock); /* Read a line. */
+ debug(F111,"read zsinl",s,y);
+ if (y < 0) { /* On EOF or other error, */
+ zclose(ZRFILE); /* close the file, */
+ delmac(vnp,0); /* delete the variable, */
+ return(success = 0); /* and return failure. */
+ } else { /* Read was OK. */
+ readsize = (int) strlen(s);
+ success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
+ debug(F111,"read addmac",vnp,success);
+ return(success); /* Return success. */
+ }
+ }
+
+ /* ASK, ASKQ, GETOK, or GETC */
+
+ if (cx == XXGOK) { /* GETOK can take switches */
+ struct FDB sw, fl;
+ int getval;
+ char c;
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Variable name or question prompt",
+ "", /* default */
+ "", /* addtl string data */
+ nasktab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ asktab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMTXT, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case ASK_PUP:
+ popupflg = 1;
+ break;
+ case ASK_GUI:
+ guiflg = 1;
+ break;
+ case ASK_TMO: {
+ if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
+ return(y);
+ if (x < 0)
+ x = 0;
+ mytimer = x;
+ break;
+ }
+ case ASK_DEF: {
+ if ((y = cmfld("Text to supply if reply is empty",
+ "",&s,xxstring)) < 0)
+ return(y);
+ ckstrncpy(dfbuf,s,1024);
+ dfanswer = dfbuf;
+ break;
+ }
+ case ASK_QUI:
+ nomsg = 1;
+ break;
+ default: return(-2);
+ }
+ }
+ p = cmresult.sresult;
+ } else
+ if ((y = cmtxt(
+"Prompt,\n\
+ enclose in { braces } or \" quotes \" to preserve leading and trailing\n\
+ spaces, precede question mark with backslash (\\).",
+ "",&p,xxstring)) < 0)
+ return(y);
+
+ if (!p) p = "";
+#ifndef NOLOCAL
+#ifdef OS2
+ if (popupflg) { /* Popup requested */
+ int len = -1;
+ ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
+ p = tmpbuf;
+ if (cx == XXASK || cx == XXASKQ) {
+ if (cx == XXASK)
+ len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer);
+ else
+ len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer);
+ asktimedout = ( len < 0 && mytimer );
+ } else if (cx == XXGOK) {
+ printf("?Sorry, GETOK /POPUP not implemented yet\n");
+ timelimit = 0;
+ return(-9);
+ }
+ if (len >= 0) {
+ y = addmac(vnp,(char *)line); /* Add it to the macro table. */
+ } else if ( asktimedout && dfanswer ) {
+ y = addmac(vnp,dfanswer); /* Add it to the macro table. */
+ asktimedout = 0;
+ len = 0;
+ }
+ timelimit = 0;
+ return(success = ((len >= 0) && (y >= 0)) && !asktimedout);
+ }
+#ifdef KUI
+ if (guiflg) { /* GUI requested */
+ int rc, n;
+ char * s1;
+ s1 = tmpbuf;
+ n = TMPBUFSIZ-1;
+ zzstring(brstrip(p),&s1,&n);
+ p = tmpbuf;
+ if (cx == XXASK || cx == XXASKQ) {
+ rc = gui_txt_dialog(NULL,p,(cx == XXASK),
+ line,LINBUFSIZ,dfanswer,mytimer);
+ asktimedout = (rc == -1 && mytimer);
+ if (rc == 1) {
+ y = addmac(vnp,(char *)line); /* Add it to the macro table. */
+ } else if ( asktimedout && dfanswer ) {
+ y = addmac(vnp,dfanswer); /* Add default to macro table. */
+ asktimedout = 0;
+ rc = 1;
+ }
+ timelimit = 0;
+ return(success = (rc == 1 && (y >= 0)) && !asktimedout);
+ } else if (cx == XXGOK) {
+ int x;
+ x = lookup(yesno,dfanswer,nyesno,NULL);
+ if (x != 1) x = 2;
+ rc = uq_ok(NULL, p, 3, NULL, x);
+ return(success = (rc == 1));
+ }
+ }
+#endif /* KUI */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+ concb((char)escape); /* Enter CBREAK mode */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(brstrip(p)); /* Make new prompt */
+
+reprompt:
+ if (cx == XXASKQ) { /* For ASKQ, */
+ cmini(0); /* no-echo mode. */
+ if (echochar)
+ echostars = echochar;
+ } else { /* For others, regular echoing. */
+ cmini(ckxech);
+ echostars = 0;
+ }
+ askflag = 1;
+ x = -1; /* This means to reparse. */
+ cmflgs = 0;
+ if (pflag)
+ prompt(xxstring); /* Issue prompt. */
+
+ asktimedout = 0; /* Handle timed responses. */
+ timelimit = mytimer;
+reparse:
+ cmres();
+ if (cx == XXGOK) { /* GETOK */
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ askflag = 0;
+ /* GETOK uses keyword table */
+ x = cmkey(yesno,nyesno,"",dfanswer,xxstring);
+ if (x < 0) { /* Parse error */
+ if (x == -10) {
+ char * ds;
+ ds = dfanswer ? dfanswer : "No";
+ if (!nomsg)
+ printf("?Timed out, assuming \"%s\"",ds);
+ printf("\n");
+ asktimedout = 1;
+ x = lookup(yesno,ds,nyesno,NULL);
+ if (x != 1) x = 0;
+ goto gokdone;
+ } else if (x == -3) { /* No answer? */
+ printf("Please respond Yes or No\n"); /* Make them answer */
+ cmini(ckxech);
+ goto reprompt;
+ } else if (x == -1) {
+ goto reparse;
+ } else
+ goto reprompt;
+ }
+ if (cmcfm() < 0) /* Get confirmation */
+ goto reparse;
+ gokdone:
+ askflag = 0;
+ cmsetp(psave); /* Restore prompt */
+#ifdef VMS
+ if (cmdlvl > 0) /* In VMS and not at top level, */
+ conres(); /* restore console again. */
+#endif /* VMS */
+ timelimit = 0;
+ return(x); /* Return success or failure */
+ } else if (cx == XXGETC /* GETC */
+#ifdef OS2
+ || cx == XXGETK /* or GETKEYCODE */
+#endif /* OS2 */
+ ) { /* GETC */
+ char tmp[16];
+ conbin((char)escape); /* Put keyboard in raw mode */
+#ifndef NOSETKEY
+#ifdef OS2
+ if (cx == XXGETK) { /* GETKEYCODE */
+ extern int os2gks;
+ int t;
+ t = os2gks; /* Turn off kverb recognition */
+ os2gks = 0;
+ x = congks(timelimit); /* Read a key event, blocking */
+ os2gks = t; /* Put back kverb recognition */
+ } else /* GETC */
+#endif /* OS2 */
+#endif /* NOSETKEY */
+ {
+ debug(F101,"GETC conchk","",conchk());
+ x = coninc(timelimit); /* Just read one character */
+ debug(F101,"GETC coninc","",x);
+ }
+ concb((char)escape); /* Put keyboard back in cbreak mode */
+ if (x > -1) {
+ if (xcmdsrc == 0)
+ printf("\r\n");
+#ifdef OS2
+ if (cx == XXGETK) { /* GETKEYCODE */
+ sprintf(tmp,"%d",x); /* SAFE */
+ } else {
+#endif /* OS2 */
+ tmp[0] = (char) (x & 0xff);
+ tmp[1] = NUL;
+#ifdef OS2
+ }
+#endif /* OS2 */
+ y = addmac(vnp,tmp); /* Add it to the macro table. */
+ debug(F111,"getc/getk addmac",vnp,y);
+ } else y = -1;
+ cmsetp(psave); /* Restore old prompt. */
+ if (x < -1) {
+ asktimedout = 1;
+ if (!quiet && !nomsg)
+ printf("?Timed out");
+ printf("\n");
+ }
+ timelimit = 0;
+ return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0)));
+ } else { /* ASK or ASKQ */
+#ifdef CK_RECALL
+ on_recall = 0; /* Don't put response in recall buf */
+#endif /* CK_RECALL */
+ askflag = 1; /* ASK[Q] always goes to terminal */
+ y = cmdgquo(); /* Get current quoting */
+ cmdsquo(0); /* Turn off quoting */
+ while (x == -1) { /* Prompt till they answer */
+ x = cmtxt("Please respond.",dfanswer,&s,NULL);
+ debug(F111,"ASK cmtxt",s,x);
+ cmres();
+ }
+ cmdsquo(y); /* Restore previous quoting */
+ if (cx == XXASKQ) /* ASKQ must echo CRLF here */
+ printf("\r\n");
+ if (x == -10 && dfanswer) { /* Don't fail on timeout if */
+ s = dfanswer; /* a default was specified */
+ asktimedout = 0; /* and don't fail */
+ x = 0;
+ }
+ if (x < 0) { /* If cmtxt parse error, */
+ cmsetp(psave); /* restore original prompt */
+#ifdef VMS
+ if (cmdlvl > 0) /* In VMS and not at top level, */
+ conres(); /* restore console again. */
+#endif /* VMS */
+ if (x == -10) { /* Timed out with no response */
+ if (!nomsg)
+ printf("?Timed out");
+ printf("\n");
+ asktimedout = 1;
+ if (dfanswer) /* Supply default answer if any */
+ s = dfanswer;
+ success = x = 0; /* (was "x = -9;") */
+ }
+ timelimit = 0;
+ return(x); /* and return cmtxt's error code. */
+ }
+ if (!s || *s == NUL) { /* If user typed a bare CR, */
+ cmsetp(psave); /* Restore old prompt, */
+ delmac(vnp,0); /* delete variable if it exists, */
+#ifdef VMS
+ if (cmdlvl > 0) /* In VMS and not at top level, */
+ conres(); /* restore console again. */
+#endif /* VMS */
+ timelimit = 0;
+ return(success = 1); /* and return. */
+ }
+ y = addmac(vnp,s); /* Add it to the macro table. */
+ debug(F111,"ask addmac",vnp,y);
+ cmsetp(psave); /* Restore old prompt. */
+#ifdef VMS
+ if (cmdlvl > 0) /* In VMS and not at top level, */
+ conres(); /* restore console again. */
+#endif /* VMS */
+ timelimit = 0;
+ return(success = (y < 0 ? 0 : 1) && (asktimedout == 0));
+ }
+}
+#endif /* NOSPL */
+
+#ifndef NOSPL
+int
+doincr(cx) int cx; { /* INCREMENT, DECREMENT */
+ char vnambuf[VNAML+1]; /* Buffer for variable names */
+ int eval = 0;
+ CK_OFF_T x;
+ eval = (cx == XX_DECR || cx == XX_INCR);
+
+ if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
+ if (y == -3) {
+ printf("?Variable name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(vnambuf,s,VNAML);
+ if ((y = cmnumw("by amount","1",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+ z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */
+
+ if (incvar(vnambuf,x,z) < 0) {
+ printf("?Variable %s not defined or not numeric\n",vnambuf);
+ return(success = 0);
+ }
+ return(success = 1);
+}
+
+/* Used by doundef() */
+static int
+xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
+ int rc = 0;
+ if (!s) return(0);
+ if (*s == CMDQ && *(s+1) == '%') {
+ char c = *(s+2), * p = NULL;
+ if (c >= '0' && c <= '9') {
+ if (maclvl < 0)
+ p = g_var[c];
+ else
+ p = m_arg[maclvl][c - '0'];
+ } else {
+ if (isupper(c)) c += ('a'-'A');
+ if (c >= 'a' && c <= 'z')
+ p = g_var[c];
+ }
+ if (!p) return(-1);
+ }
+ if (verbose)
+ printf(" %s ",s);
+ if (simulate) {
+ printf("(SELECTED)\n");
+ } else if ((x = delmac(s,1)) > -1) { /* Full name required */
+ rc = 1;
+ if (verbose) printf("(OK)\n");
+ } else if (verbose)
+ printf("(FAILED)\n");
+ return(rc);
+}
+
+/* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
+
+#define UND_MAT 1
+#define UND_VRB 2
+#define UND_EXC 3
+#define UND_SIM 3
+
+static struct keytab undefswi[] = {
+ { "/list", UND_VRB, 0 },
+#ifdef COMMENT
+ { "/except", UND_EXC, CM_ARG },
+#endif /* COMMENT */
+ { "/matching", UND_MAT, 0 },
+ { "/simulate", UND_SIM, 0 },
+ { "/verbose", UND_VRB, CM_INV }
+};
+static int nundefswi = sizeof(undefswi) / sizeof(struct keytab);
+
+#define UNDEFMAX 64
+static char ** undeflist = NULL;
+int
+doundef(cx) int cx; { /* UNDEF, _UNDEF */
+ int i, j, n, rc = 0, arraymsg = 0;
+ int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0;
+ char *vnp, vnbuf[4];
+#ifdef COMMENT
+ char *except = NULL;
+#endif /* COMMENT */
+ struct FDB sw, fl;
+ int getval;
+ char c;
+
+ if (!undeflist) { /* Allocate list if necessary */
+ undeflist = (char **)malloc(UNDEFMAX * sizeof(char *));
+ if (!undeflist) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ for (i = 0; i < UNDEFMAX; i++)
+ undeflist[i] = NULL;
+ }
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Variable name or switch",
+ "", /* default */
+ "", /* addtl string data */
+ nundefswi, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ undefswi, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ (cx == XXUNDEF) ? NULL : xxstring,
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case UND_MAT: domatch = 1; break;
+ case UND_SIM: simulate = 1; /* fall thru on purpose */
+ case UND_VRB: verbose = 1; break;
+
+#ifdef COMMENT
+ case UND_EXC:
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ x = -9;
+ }
+ goto xgetx;
+ }
+ makestr(&except,cmresult.sresult);
+ break;
+#endif /* COMMENT */
+
+ default:
+ return(-2);
+ }
+ }
+ n = 0;
+ makestr(&(undeflist[n++]),cmresult.sresult);
+ for (i = 1; i < UNDEFMAX; i++) {
+ x = cmfld("Macro or variable name","",&s,
+ ((cx == XXUNDEF) ? NULL : xxstring)
+ );
+ if (x == -3) {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ break;
+ } else if (y < 0) {
+ return(y);
+ }
+ makestr(&(undeflist[n++]),s);
+ }
+ /* Now we have a list of n variables or patterns to undefine */
+
+ for (i = 0; i < n; i++) {
+ flag = 0;
+ if (!(vnp = undeflist[i]))
+ continue;
+ if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) {
+ flag++;
+ vnp++;
+ }
+ if (!domatch) { /* Pattern match not requested */
+ if (flag) {
+ if ((y = parsevar(vnp,&x,&z)) < 0) {
+ vnp--;
+ if (verbose) printf(" %s...error\n",vnp);
+ continue;
+ }
+ vnp--;
+ }
+ x = xxundef(vnp,verbose,simulate);
+ if (x > -1) {
+ if (!x && !simulate) errors++;
+ rc += x;
+ }
+ continue;
+ }
+ /* Pattern match requested */
+
+ if (!flag) { /* It's a macro */
+ for (j = 0; j < nmac; j++) {
+ if (ckmatch(vnp,mactab[j].kwd,0,1)) {
+ x = xxundef(mactab[j].kwd,verbose,simulate);
+ if (x > -1) {
+ rc += x;
+ if (!x) errors++;
+ }
+ if (!simulate)
+ j--; /* Because mactab shifted up */
+ }
+ }
+ } else if (vnp[0] == '%') { /* It's a \%x variable */
+ vnbuf[0] = CMDQ;
+ vnbuf[1] = '%';
+ vnbuf[3] = NUL;
+ for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */
+ vnbuf[2] = j;
+ if (ckmatch(vnp,&vnbuf[1],0,1)) {
+ x = xxundef(vnbuf,verbose,simulate);
+ if (x > -1) {
+ if (!x) errors++;
+ rc += x;
+ }
+ }
+ if (j == '9') j = (int)'a' - 1; /* 9 -> a */
+ }
+ } else if (vnp[0] == '&') {
+ if (!arraymsg && !quiet) {
+ printf("?UNDEFINE /MATCH can't be used with arrays.\n");
+ printf("(Type HELP ARRAY to see other methods.)\n");
+ }
+ arraymsg++;
+ errors++;
+ }
+ }
+ if (verbose)
+ printf("undefined: %d, errors: %d\n",rc,errors);
+
+ for (i = 0; i < UNDEFMAX; i++) { /* Check them all */
+ if (undeflist[i]) { /* in case we were interrupted */
+ free(undeflist[i]); /* previously... */
+ undeflist[i] = NULL;
+ }
+ }
+ return(success = (errors == 0) ? 1 : 0);
+}
+
+int
+dodef(cx) int cx; {
+ extern int xxdot;
+ extern char ppvnambuf[];
+ int doeval = 0;
+ char vnambuf[VNAML+1]; /* Buffer for variable names */
+ char *vnp; /* Pointer to same */
+ int k, mydot;
+ mydot = xxdot; /* Copy */
+ xxdot = 0; /* and reset */
+/*
+ In case we got here from a command that begins like ".\%a", cmkey() has
+ already evaluated \%a, but we don't want that, so we retrieve the variable
+ name from a special pre-evaluation buffer in the command module, and we
+ undo the "unget word" that would be done because of the token, because if
+ the variable was defined, it will unget its value rather than its name.
+*/
+ s = NULL;
+
+ if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
+ s = ppvnambuf+1;
+ unungw();
+ }
+ if (!s) {
+ if (cx == XXDFX || cx == XXASX)
+ /* Evaluate variable name */
+ y = cmfld("Macro or variable name","",&s,xxstring);
+ else
+ /* Don't evaluate the variable name */
+ y = cmfld("Macro or variable name","",&s,NULL);
+ if (y < 0) {
+ if (y == -3) {
+ printf("?Variable name required\n");
+ return(-9);
+ } else return(y);
+ }
+ }
+ k = strlen(s);
+ if (k > VNAML) {
+ printf("?Name too long: \"%s\"\n",s);
+ return(-9);
+ }
+ ckstrncpy(vnambuf,s,VNAML);
+ vnambuf[VNAML] = NUL;
+ vnp = vnambuf;
+ if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
+#ifdef COMMENT
+ if (cx == XXUNDEF) { /* Undefine */
+ if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
+ delmac(vnp,0);
+ return(success = 1);
+ }
+#endif /* COMMENT */
+ debug(F101,"dodef parsevar x","",x);
+ if (mydot) {
+ if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
+ return(doeval);
+ if (doeval > 0) /* Type of assignment */
+ cx = XXASS;
+ }
+ if (y == 1) { /* Simple variable */
+ if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
+ return(y);
+ s = brstrip(s);
+ debug(F110,"xxdef var name",vnp,0);
+ debug(F110,"xxdef var def",s,0);
+ } else if (y == 2) { /* Array element */
+ if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
+ if (x == 96) {
+ printf("?Argument vector array is read-only\n");
+ return(-9);
+ }
+ if (chkarray(x,z) < 0) return(-2);
+ if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
+ return(y);
+ debug(F110,"xxdef array ref",vnp,0);
+ debug(F110,"xxdef array def",s,0);
+ }
+ } else { /* Macro */
+#ifdef COMMENT
+ if (cx == XXUNDEF) { /* Undefine */
+ if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
+ delmac(vnp,0);
+ return(success = 1);
+ }
+#endif /* COMMENT */
+ if (mydot) {
+ if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
+ return(doeval);
+ if (doeval > 0)
+ cx = XXASS;
+ }
+ if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F110,"xxdef macro name",vnp,0);
+ debug(F010,"xxdef macro def",s,0);
+ }
+#endif /* DEBUG */
+ s = brstrip(s);
+ }
+ if (*s == NUL) { /* No arg given, undefine */
+ delmac(vnp,1); /* silently... */
+ return(success = 1); /* even if it doesn't exist... */
+ }
+ /* Defining a new macro or variable */
+
+ if (cx == XXASS || cx == XXASX) { /* ASSIGN rather than DEFINE? */
+ int t;
+ t = LINBUFSIZ-1;
+ lp = line; /* If so, expand its value now */
+ zzstring(s,&lp,&t);
+ s = line;
+ }
+ if (doeval == 2) { /* Arithmetic evaluation wanted too? */
+ ckstrncpy(line,evala(s),LINBUFSIZ);
+ line[LINBUFSIZ] = NUL;
+ }
+ /* debug(F111,"calling addmac",s,(int)strlen(s)); */
+
+ y = addmac(vnp,s); /* Add it to the appropriate table. */
+ if (y < 0) {
+ printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
+ "ASSIGN" : "DEFINE");
+ return(success = 0);
+ } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
+ return(1); /* don't change success variable */
+ else
+ return(success = 1);
+}
+#endif /* NOSPL */
+
+
+#ifndef NODIAL
+/*
+ L U D I A L -- Lookup up dialing directory entry.
+
+ Call with string to look up and file descriptor of open dialing directory
+ file. On success, returns number of matches found, with numbers stored
+ in an array accessible via getdnum().
+*/
+static char *dn_p[MAXDNUMS + 1]; /* Dial Number pointers */
+static char *dn_p2[MAXDNUMS + 1]; /* Converted dial number pointers */
+static int dn_x[MAXDNUMS + 1]; /* Type of call */
+static int dncount = 0;
+char * d_name = NULL; /* Dial name pointer */
+
+char * /* Get dial directory entry name */
+getdname() {
+ return(d_name ? d_name : "");
+}
+
+char *
+getdnum(n) int n; { /* Get dial number n from directory */
+ if (n < 0 || n > dncount || n > MAXDNUMS)
+ return("");
+ else
+ return(dn_p[n]);
+}
+
+char * /* Check area code for spurious leading digit */
+chk_ac(i,buf) int i; char buf[]; {
+ char *p;
+ if (!buf)
+ return("");
+ p = (char *) buf; /* Country we are calling: */
+ if (i == 44 || /* UK */
+ i == 49 || /* Germany */
+ i == 39 || /* Italy */
+ i == 31 || /* Netherlands */
+ i == 351 || /* Portugal */
+ i == 55 || /* Brazil */
+ i == 972 || /* Israel */
+ i == 41 || /* Switzerland */
+ i == 43 || /* Austria */
+ i == 42 || /* Czech Republic */
+ i == 36 || /* Hungary */
+ i == 30 || /* Greece */
+ i == 352 || /* Luxembourg */
+ i == 48 || /* Poland */
+ i == 27 || /* South Africa */
+ i == 33 || /* France (as of 1997) */
+ i == 358 /* Finland (ditto) */
+ ) {
+ if (buf[0] == '0')
+ p++;
+ }
+ return(p);
+}
+
+/* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
+/*
+ src = area code of caller
+ dest = area code of callee
+ Returns:
+ 0 if call is local
+ 1 if call is long distance
+ 2 if call is local but area code must be dialed anyway
+*/
+static int
+callisld(src, dest) char * src, * dest; {
+ int i;
+ if (dialfld) /* Force long distance? */
+ return(1);
+ if (!strcmp(src,dest)) { /* Area codes are the same */
+ for (i = 0; i < nlocalac; i++) /* Is AC in the lc-area-codes list? */
+ if (!strcmp(src,diallcac[i]))
+ return(2); /* Yes so must be dialed */
+ return(0); /* No so don't dial it. */
+ }
+ for (i = 0; i < nlocalac; i++) /* ACs not the same so look in list */
+ if (!strcmp(dest,diallcac[i])) /* Match */
+ return(2); /* So local call with area code */
+ return(1); /* Not local so long-distance */
+}
+
+char pdsfx[64] = { NUL, NUL };
+
+#ifndef NOSPL
+static char *
+xdial(s) char *s; { /* Run dial string thru macro */
+ int x, m;
+ char * s2;
+ s2 = NULL;
+ makestr(&s2,s); /* Copy the argument */
+ if (!dialmac) /* Dial macro name given? */
+ return(NULL);
+ if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
+ return(NULL);
+ m = maclvl;
+ x = dodo(x,s2,0); /* Set up the macro */
+ if (s2) free(s2);
+ if (x > 0) {
+ while (maclvl > m) /* Execute the parser */
+ parser(1);
+ return(mrval[maclvl+1]); /* Return the result */
+ }
+ return(NULL);
+}
+#endif /* NOSPL */
+
+static int
+dncvt(k,cx, prefix, suffix)
+ int k, cx, prefix, suffix; { /* Dial Number Convert */
+ int i, j, n, what; /* cx is top-level command index */
+ char *ss; /* prefix - add prefixes? */
+ char *p, *p2, *pxo; /* suffix - add suffixes? */
+ char *lac;
+ char *npr;
+ char *sfx;
+ /* char *psfx; */
+ char ccbuf[128];
+ int cc;
+ char acbuf[24];
+ char *acptr;
+ char outbuf[256];
+/*
+ First pass for strict (punctuation-based) interpretation.
+ If it fails, we try the looser (length-based) one.
+*/
+ dialtype = -1;
+ what = 0; /* Type of call */
+ s = dn_p[k]; /* Number to be converted. */
+ debug(F111,"dncvt",s,k);
+ if (dn_p2[k]) {
+ free(dn_p2[k]);
+ dn_p2[k] = NULL;
+ }
+ if (!s) {
+ printf("Error - No phone number to convert\n");
+ return(-1);
+ }
+ if ((int)strlen(s) > 200) {
+ ckstrncpy(outbuf,s,40);
+ printf("?Too long: \"%s...\"\n",outbuf);
+ return(-1);
+ }
+ npr = (prefix && dialnpr) ? dialnpr : "";
+ sfx = (suffix && dialsfx) ? dialsfx : "";
+ /* if (partial) psfx = dialsfx ? dialsfx : ""; */
+ pxo = (prefix && dialpxo) ? dialpxo : "";
+ lac = diallac ? diallac : ""; /* Local area code */
+
+ outbuf[0] = NUL; /* Initialize conversion buffer */
+ ss = s; /* Remember original string */
+
+ if (*s != '+') { /* Literal number */
+ dn_x[k] = DN_UNK; /* Sort key is "unknown". */
+ ckmakmsg(outbuf,256, /* Sandwich it between */
+ pxo,npr,s,sfx /* DIAL PREFIX and SUFFIX */
+ );
+#ifdef CK_TAPI
+ if (tttapi && /* TAPI does its own conversions */
+ !tapipass && /* if not in passthru mode */
+ tapiconv == CK_AUTO || /* and TAPI conversions are AUTO */
+ tapiconv == CK_ON /* OR if TAPI conversions are ON */
+ ) {
+ char * p = NULL;
+ dialtype = -2;
+ if (!cktapiConvertPhoneNumber(dn_p[k], &p))
+ return(-1);
+ makestr(&dn_p2[k], p);
+ if (p) free(p);
+ return(0);
+ } else
+#endif /* CK_TAPI */
+ makestr(&dn_p2[k], outbuf); /* Not TAPI */
+ dialtype = what;
+ return(0); /* Done. */
+ }
+ i = 0; /* Portable number */
+ s++; /* Tiptoe past the plus sign */
+ ccbuf[0] = NUL; /* Do country code first */
+
+ if (!diallcc) { /* Do we know our own? */
+ if (cx != XXLOOK)
+ printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
+ return(-1);
+ }
+
+ /* Parse the number */
+
+ while (1) { /* Get the country code */
+ while (*s == HT || *s == SP)
+ s++;
+ if (!s) /* Not in standard format */
+ break;
+ if (*s == '(') { /* Beginning of area code */
+ s++; /* Skip past parenthesis */
+ ccbuf[i] = NUL; /* End of country code */
+ if (!s) { /* Check for end of string */
+ printf("Error - phone number ends prematurely: \"%s\"\n",ss);
+ return(-1);
+ }
+ break;
+ } else { /* Collect country code */
+ if (isdigit(*s))
+ ccbuf[i++] = *s; /* copy this character */
+ s++;
+ if (!*s || i > 127) /* watch out for memory leak */
+ break;
+ }
+ }
+ cc = atoi(ccbuf); /* Numeric version of country code */
+
+ i = 0; /* Now get area code */
+ acbuf[0] = NUL; /* Initialize area-code buffer */
+ acptr = acbuf; /* and pointer. */
+ while (1) {
+ while (*s == HT || *s == SP) /* Ignore whitespace */
+ s++;
+ if (!s) /* String finished */
+ break;
+ if (*s == ')') { /* End of area code */
+ s++; /* Skip past parenthesis */
+ acbuf[i] = NUL; /* Terminate area-code buffer */
+ break;
+ } else { /* Part of area code */
+ if (isdigit(*s)) /* If it's a digit, */
+ acbuf[i++] = *s; /* copy this character */
+ s++; /* Point to next */
+ if (!*s || i > 23) /* Watch out for overflow */
+ break;
+ }
+ }
+
+/*
+ Here we strip any leading 0 for countries that we know have
+ 0 as a long-distance prefix and do not have any area codes that
+ start with 0 (formerly also ditto for "9" in Finland...)
+*/
+ i = atoi(ccbuf);
+ acptr = chk_ac(i,acbuf);
+
+ while (*s == HT || *s == SP) /* Skip whitespace */
+ s++;
+
+/* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
+
+ if (*s && *acptr) { /* Area code was delimited */
+
+ while (*s == '-' || *s == '.') /* Skip past gratuitious punctuation */
+ s++;
+ if (!*s) s--; /* But not to end of string */
+
+ if (strcmp(diallcc,ccbuf)) { /* Out of country? */
+ if (!dialixp) { /* Need intl-prefix */
+ if (cx != XXLOOK)
+ printf("Error - No international dialing prefix defined\n");
+ return(-1);
+ }
+ what = dn_x[k] = DN_INTL;
+ p = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
+ p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
+
+ /* Form the final phone number */
+#ifdef COMMENT
+ sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */
+ sprintf(outbuf,
+ "%s%s%s%s%s%s%s%s",
+ pxo,npr,p,ccbuf,acptr,s,p2,sfx
+ );
+#else
+ ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
+ ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx,
+ NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+
+ } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
+ if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
+ if (cc == 1)
+ printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
+ }
+ if (x == 2) { /* Local call with area code */
+ what = dn_x[k] = DN_LOCAL; /* Local-call */
+ p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
+ p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
+ } else {
+ what = dn_x[k] = DN_LONG; /* Long-distance */
+ for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
+ if (!strcmp(acptr,dialtfc[i])) {
+ what = dn_x[k] = DN_FREE;
+ break;
+ }
+ }
+ if (what == DN_FREE) { /* Toll-free call */
+ p = (prefix && dialtfp) ? dialtfp :
+ ((prefix && dialldp) ? dialldp : "");
+ p2 = ""; /* no suffix */
+ } else { /* normal long distance */
+ p = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
+ p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
+ }
+ }
+ /* Form the number to be dialed */
+#ifdef COMMENT
+ sprintf(outbuf,"%s%s%s%s%s%s%s",
+ pxo,npr,p,acptr,s,p2,sfx
+ );
+ sprintf(pdsfx,"%s%s",p2,sfx);
+#else
+ ckmakxmsg(outbuf,256,
+ pxo,npr,p,acptr,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL);
+ ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
+#endif /* COMMENT */
+ } else { /* Same country, same area code */
+ what = dn_x[k] = DN_LOCAL; /* So it's a local call. */
+ if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
+ p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
+ p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
+#ifdef COMMENT
+ if (x == 2)
+ sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
+ else
+ sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
+ sprintf(pdsfx,"%s%s",p2,sfx);
+#else
+ if (x == 2)
+ ckmakxmsg(outbuf,256,
+ npr,p,acptr,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ else
+ ckmakxmsg(outbuf,256,
+ npr,p,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+ ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
+#endif /* COMMENT */
+
+ } else { /* Dialing from a PBX and not TAPI */
+ if (ndialpxx) { /* Is it internal? */
+#ifdef COMMENT
+ i = (int) strlen(dialpxx);
+ j = (int) strlen(s);
+ x = -1;
+ if (j > i)
+ x = ckstrcmp(dialpxx,s,i,0);
+#else
+ int kx;
+ x = -1;
+ j = (int) strlen(s);
+ for (kx = 0; kx < ndialpxx; kx++) {
+ i = (int) strlen(dialpxx[kx]);
+ if (j > i)
+ if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
+ break;
+ }
+#endif /* COMMENT */
+ if (!x) {
+ char * icp, buf[32];
+ makestr(&matchpxx,dialpxx[kx]);
+ debug(F111,"dncvt matchpxx",matchpxx,kx);
+ what = dn_x[kx] = DN_INTERN; /* Internal call. */
+ s += i;
+ /* Internal-call prefix */
+ icp = dialpxi;
+#ifndef NOSPL
+ if (icp) {
+ if (*icp == '\\') {
+ char c, *bp;
+ int n;
+ c = *(icp+1);
+ if (isupper(c)) c = tolower(c);
+ if (c == 'v' || c == 'f') {
+ n = 32;
+ bp = buf;
+ zzstring(icp,&bp,&n);
+ icp = buf;
+ }
+ }
+ }
+#endif /* NOSPL */
+ p = (prefix && icp) ? icp : "";
+#ifdef COMMENT
+ sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx);
+#else
+ ckmakmsg(outbuf,256,npr,p,s,sfx);
+#endif /* COMMENT */
+ } else { /* External local call */
+ /* local-prefix */
+ p = (prefix && diallcp) ? diallcp : "";
+ /* local-suffix */
+ p2 = (prefix && diallcs) ? diallcs : "";
+#ifdef COMMENT
+ if (x == 2)
+ sprintf(outbuf,"%s%s%s%s%s%s%s",
+ dialpxo ? dialpxo : "",
+ npr,p,acptr,s,p2,sfx);
+ else
+ sprintf(outbuf,
+ "%s%s%s%s%s%s",
+ dialpxo ? dialpxo : "",
+ npr,p,s,p2,sfx
+ );
+#else
+ if (x == 2)
+ ckmakxmsg(outbuf, 256,
+ dialpxo ? dialpxo : "",
+ npr,p,acptr,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL);
+ else
+ ckmakxmsg(outbuf, 256,
+ dialpxo ? dialpxo : "",
+ npr,p,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ }
+ }
+ }
+ }
+
+ } else { /* Area code was not delimited */
+
+ char xbuf[256]; /* Comparison based only on length */
+ char ybuf[256];
+ int x, j;
+
+ s = ss;
+
+ for (i = 0; i < 255; i++) {
+ if (!*s) break;
+ while (!isdigit(*s)) { /* Pay attention only to digits */
+ s++;
+ if (!*s) break;
+ }
+ xbuf[i] = *s++;
+ }
+ xbuf[i] = NUL;
+
+ x = 1; /* Assume LD */
+ n = 0;
+ if (!dialfld) { /* If LD not forced */
+ for (j = 0; j < nlocalac; j++) { /* check local AC list? */
+ ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL);
+ n = (int) strlen(ybuf);
+ if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
+ x = 2;
+ break;
+ }
+ }
+ if (x == 1) { /* Or exact match with local CC+AC? */
+ ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL);
+ n = (int) strlen(ybuf);
+ if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
+ x = 0;
+ }
+ }
+ if (x == 0 || x == 2) { /* Local call */
+ int xx,kx; /* Begin 1 Dec 2001... */
+ /* Account for PBX internal calls */
+ if (ndialpxx) {
+ xx = -1;
+ j = (int) strlen(ybuf);
+ for (kx = 0; kx < ndialpxx; kx++) {
+ i = (int) strlen(dialpxx[kx]);
+ if (j >= i)
+ if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0)))
+ break;
+ }
+ }
+ if (!xx) {
+ char * icp, buf[32];
+ makestr(&matchpxx,dialpxx[kx]);
+ debug(F111,"dncvt matchpxx",matchpxx,kx);
+ what = dn_x[kx] = DN_INTERN; /* Internal call. */
+ s = xbuf + j + i;
+ icp = dialpxi; /* Internal-call prefix */
+#ifndef NOSPL
+ if (icp) {
+ if (*icp == '\\') {
+ char c, *bp;
+ int n;
+ c = *(icp+1);
+ if (isupper(c)) c = tolower(c);
+ if (c == 'v' || c == 'f') {
+ n = 32;
+ bp = buf;
+ zzstring(icp,&bp,&n);
+ icp = buf;
+ }
+ }
+ }
+#endif /* NOSPL */
+ p = (prefix && icp) ? icp : "";
+ ckmakmsg(outbuf,256,npr,p,s,sfx);
+ /* End 1 Dec 2001... */
+
+ } else { /* Not PBX internal */
+
+ dn_x[k] = DN_LOCAL;
+ p = (prefix && diallcp) ? diallcp : "";
+ p2 = (suffix && diallcs) ? diallcs : "";
+ s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
+ ckmakxmsg(outbuf,256,
+ pxo,npr,p,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
+ }
+ } else { /* Not local */
+ n = ckstrncpy(ybuf,diallcc,256);
+ if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
+ dn_x[k] = DN_LONG;
+ p = (prefix && dialldp) ? dialldp : "";
+ p2 = (suffix && diallds) ? diallds : "";
+ s = xbuf + n;
+ while (*s == '-' || *s == '.')
+ s++;
+#ifdef COMMENT
+ sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
+ sprintf(pdsfx,"%s%s",p2,sfx);
+#else
+ ckmakxmsg(outbuf,256,
+ pxo,npr,p,s,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
+#endif /* COMMENT */
+ } else {
+ dn_x[k] = DN_INTL; /* International */
+ if (!dialixp) {
+ if (cx != XXLOOK) {
+ printf(
+ "Error - No international dialing prefix defined\n"
+ );
+ return(-1);
+ }
+ }
+ p = (prefix && dialixp) ? dialixp : "";
+ p2 = (suffix && dialixs) ? dialixs : "";
+#ifdef COMMENT
+ sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
+ sprintf(pdsfx,"%s%s",p2,sfx);
+#else
+ ckmakxmsg(outbuf,256,
+ pxo,npr,p,xbuf,p2,sfx,
+ NULL,NULL,NULL,NULL,NULL,NULL);
+ ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
+#endif /* COMMENT */
+ }
+ }
+ }
+#ifdef CK_TAPI
+ if (tttapi && /* TAPI performs the conversions */
+ !tapipass &&
+ tapiconv == CK_AUTO ||
+ tapiconv == CK_ON
+ ) {
+ p = NULL;
+ dialtype = -2;
+ if (!cktapiConvertPhoneNumber(dn_p[k],&p))
+ return(-1);
+ makestr(&dn_p2[k], p);
+ if (p) free(p);
+ return(0);
+ } else {
+#endif /* CK_TAPI */
+ makestr(&dn_p2[k], outbuf);
+#ifdef CK_TAPI
+ }
+#endif /* CK_TAPI */
+ dialtype = what;
+ return(0);
+}
+
+static int
+ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
+ char linebuf[1024], *s2; /* Buffers and pointers */
+#ifdef VMS
+ char * temp = NULL;
+#endif /* VMS */
+ char *info[8]; /* Pointers to words from entry */
+ FILE * f2 = NULL;
+ int x, rc;
+ rc = -1;
+
+ debug(F110,"ddcvt file",s,0);
+
+ if (!s || !f) /* No filename or file */
+ return(-1);
+ if (!*s)
+
+ fclose(f);
+ znewn(s,&s2); /* s2 = address of static buffer */
+ debug(F110,"ddcvt newname",s2,0);
+
+#ifdef VMS
+ /* In VMS, znewn() returns the same file name with a new version number */
+ makestr(&temp,s); /* Swap - otherwise the new */
+ s = s2; /* version has the older version */
+ s2 = temp; /* number... */
+ debug(F110,"ddcvt after swap s",s,0);
+ debug(F110,"ddcvt after swap s2",s2,0);
+ makestr(&(dialdir[n]),s); /* New file gets new version number */
+ debug(F110,"ddcvt after makestr s2",s2,0);
+ debug(F111,"ddcvt dialdir[n]",dialdir[n],n);
+#else
+ if (zrename(s,s2) < 0) { /* Not VMS - rename old file */
+ perror(s2); /* to new (wierd) name. */
+ goto ddexit;
+ }
+#endif /* VMS */
+ debug(F110,"ddcvt s2 (old)",s2,0);
+ if ((f = fopen(s2,"r")) == NULL) { /* Reopen old file with wierd name */
+ debug(F110,"ddcvt s2 open error",ck_errstr(),0);
+ dirline = 0; /* (or in VMS, old version) */
+ perror(s2);
+ goto ddexit;
+ }
+ debug(F110,"ddcvt fopen(s2) OK",s2,0);
+
+ debug(F110,"ddcvt s (new)",s,0);
+ if ((f2 = fopen(s,"w")) == NULL) { /* Create new file with old name */
+ debug(F110,"ddcvt s open error",ck_errstr(),0);
+ perror(s); /* (or in VMS, new version) */
+ goto ddexit;
+ }
+ debug(F110,"ddcvt fopen(s) OK",s,0);
+
+ printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
+ fprintf(f2,"; %s - Kermit dialing directory\n", s);
+ fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
+ "; Name","Number","Speed","Parity","Comment"
+ );
+
+ while (1) {
+ linebuf[0] = NUL; /* Read a line */
+ if (fgets(linebuf,1023,f) == NULL)
+ break;
+ debug(F110,"ddcvt linebuf",linebuf,0);
+ if (!linebuf[0]) { /* Empty line */
+ fprintf(f2,"\n");
+ continue;
+ }
+ x = (int) strlen(linebuf); /* Strip line terminator, */
+ while (x-- > 0) { /* if any. */
+ if (linebuf[x] <= SP)
+ linebuf[x] = NUL;
+ else
+ break;
+ }
+ xwords(linebuf,5,info,1); /* Parse it the old way */
+ for (x = 1; x < 6; x++)
+ if (!info[x]) info[x] = "";
+ fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
+ info[1],info[2],info[3],info[4],info[5]
+ );
+ }
+ printf(" OK\n\n");
+ rc = 0; /* Success */
+ ddexit:
+ if (f) fclose(f);
+ if (f2) fclose(f2);
+#ifdef VMS
+ if (temp) free(temp);
+#endif /* VMS */
+ return(rc);
+}
+
+int /* s = name to look up */
+#ifdef CK_ANSIC /* cx = index of command */
+ludial(char *s, int cx) /* (DIAL, LOOKUP, etc) */
+#else
+ludial(s, cx) char *s; int cx;
+#endif /* CK_ANSIC */
+/* ludial */ {
+
+ int dd, n1, n2, n3, i, j, t; /* Workers */
+ int olddir, newdir, oldentry, newentry;
+ int pass = 0;
+ int oldflg = 0;
+ int ambiguous = 0; /* Flag for lookup was ambiguous */
+ char *info[7]; /* Pointers to words from entry */
+ char *pp; /* Pointer to element of array */
+ FILE * f;
+ char *line; /* File input buffer */
+
+/* #define LUDEBUG */
+
+#ifdef LUDEBUG
+int zz = 1;
+#endif /* LUDEBUG */
+
+ if (!s || ndialdir < 1) /* Validate arguments */
+ return(-1);
+
+ if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */
+ return(-1);
+
+ if (!(line = malloc(1024))) /* Allocate input buffer */
+ return(-1);
+
+#ifdef LUDEBUG
+if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
+#endif /* LUDEBUG */
+
+ pass = 0;
+ lu_again:
+ f = NULL; /* Dial directory file descriptor */
+ t = dncount = 0; /* Dial-number match count */
+ dd = 0; /* Directory counter */
+ olddir = 0;
+ newdir = 0;
+/*
+ We need to recognize both old- and new-style directories.
+ But we can't allow old-style and new-style entries in the same
+ directory because there is no way to tell for sure the difference between
+ an old-style entry like this:
+
+ foo 5551212 9600
+
+ and a new-style literal entry like this:
+
+ foo 555 9600
+
+ I.e. is the "9600" a speed, or part of the phone number?
+*/
+ while (1) { /* We make one pass */
+ if (!f) { /* Directory not open */
+ if (dd >= ndialdir) /* No directories left? */
+ break; /* Done. */
+ debug(F111,"ludial dialdir[dd]",dialdir[dd],dd);
+ if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
+ perror(dialdir[dd]); /* Can't, print message saying why */
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ dd++; /* Go on to next one, if any... */
+ continue;
+ }
+ dirline = 0; /* Directory file line number */
+ if (dialdpy && !pass)
+ printf("Opening: %s...\n",dialdir[dd]);
+ dd++;
+ if (!oldflg) olddir = 0;
+ newdir = 0;
+ }
+ oldentry = 0;
+ newentry = 0;
+ line[0] = NUL;
+ if (getnct(line,1023,f,1) < 0) { /* Read a line */
+ if (f) { /* f can be clobbered! */
+ fclose(f); /* Close the file */
+ f = NULL; /* Indicate next one needs opening */
+ oldflg = 0;
+ }
+ continue;
+ }
+ if (!line[0]) /* Empty line */
+ continue;
+#ifdef LUDEBUG
+if (zz) printf("LUDIAL 2 s[%s]\n",s);
+#endif /* LUDEBUG */
+
+ /* Make a copy and parse it the old way */
+ /* A copy is needed because xwords() pokes NULs into the string */
+
+ if ((pp = malloc((int)strlen(line) + 1))) {
+ strcpy(pp,line); /* safe */
+ xwords(pp,5,info,0); /* Parse it the old way */
+
+#ifdef LUDEBUG
+if (zz) printf("LUDIAL 3 s[%s]\n",s);
+#endif /* LUDEBUG */
+
+ if (!info[1])
+ continue;
+ if (*info[1] == ';') { /* If full-line comment, */
+ newdir = 1; /* (only new directories have them) */
+ continue; /* keep reading. */
+ }
+ if (!info[2])
+ continue;
+ if (*info[2] == '+')
+ newentry = 1;
+ if (info[4]) {
+ if ((*info[4] == '=') ||
+ !ckstrcmp(info[4],"none", 4,0) ||
+ !ckstrcmp(info[4],"even", 4,0) ||
+ !ckstrcmp(info[4],"space",5,0) ||
+ !ckstrcmp(info[4],"mark", 4,0) ||
+ !ckstrcmp(info[4],"odd", 3,0)
+ )
+ oldentry = 1;
+ }
+ }
+ if (pp) {
+ free(pp);
+ pp = NULL;
+ }
+
+ /* Check consistency */
+
+ if ((oldentry || olddir) && (newentry || newdir)) {
+ printf(
+"\nERROR: You seem to have old- and new-format entries mixed in your\n");
+ printf(
+"dialing directory. You'll have to edit it by hand to convert it to the\n");
+#ifndef NOHELP
+ printf("new format. Type HELP DIAL for further information.\n\n");
+#else
+ printf("new format.\n\n");
+#endif /* NOHELP */
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ return(-1);
+ }
+ if (!olddir && oldentry) {
+ int convert = 0;
+ olddir = 1;
+ if (dialcvt == 2) { /* 2 == ASK */
+ sprintf(tmpbuf,
+"WARNING: Old-style dialing directory detected:\n%s", line);
+ convert = uq_ok(tmpbuf,
+ "Shall I convert it for you? ",3,NULL,0);
+ } else
+ convert = dialcvt;
+ if (convert) {
+ debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd);
+ if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
+ debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd);
+ oldflg = 1;
+ printf(
+" Sorry, can't convert.");
+ printf(
+" Will ignore speed and parity fields, continuing...\n\n");
+ } else {
+ olddir = newdir = 0;
+ debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd);
+ }
+ dd--;
+ f = NULL;
+ continue;
+ } else {
+ if (dialcvt == 2)
+ printf(
+" OK, will ignore speed and parity fields, continuing...\n\n");
+ olddir = 1;
+ }
+ }
+
+#ifdef LUDEBUG
+if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
+#endif /* LUDEBUG */
+
+ /* Now parse again for real */
+
+ if (oldentry) /* Parse it the old way */
+ xwords(line,5,info,0);
+ else /* Parse it the new way */
+ xwords(line,2,info,1);
+
+#ifdef LUDEBUG
+if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
+if (zz) printf("%s [%s]\n",info[1],info[2]);
+#endif /* LUDEBUG */
+
+ if (info[1]) { /* First word is entry name */
+ if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
+ continue; /* If no first word, keep reading. */
+ if (n3 < n1) /* Search name is longer */
+ continue; /* Can't possibly match */
+ if (ambiguous && n3 != n1)
+ continue;
+
+#ifdef LUDEBUG
+if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
+#endif /* LUDEBUG */
+
+ if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
+ continue;
+
+#ifdef LUDEBUG
+if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
+#endif /* LUDEBUG */
+
+ if (!info[2]) /* No phone number given */
+ continue;
+ if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
+ continue; /* Ignore empty phone numbers */
+
+ /* Got one */
+
+ if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
+ printf("?internal error - ludial malloc 1\n");
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ dncount = 0;
+ return(-1);
+ }
+ strcpy(pp,info[2]); /* safe */
+
+ if (dncount > MAXDNUMS) {
+ printf("Warning: %d matches found, %d max\n",
+ dncount,
+ MAXDNUMS
+ );
+ dncount = MAXDNUMS;
+ break;
+ }
+ dn_p[dncount++] = pp; /* Add pointer to array. */
+ if (dncount == 1) { /* First one... */
+ if (d_name) free(d_name);
+ if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
+ printf("?internal error - ludial malloc 2\n");
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ dncount = 0;
+ return(-1);
+ }
+ t = n3; /* And its length */
+ strcpy(d_name,info[1]); /* safe */
+ } else { /* Second or subsequent one */
+
+#ifdef LUDEBUG
+ if (zz)
+ printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
+#endif /* LUDEBUG */
+
+ if ((int) strlen(info[1]) == t) /* Lengths compare */
+ if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
+ continue;
+
+ /* Name given by user matches entries with different names */
+
+ if (ambiguous) /* Been here before */
+ break;
+
+ ambiguous = 1; /* Now an exact match is required */
+ for (j = 0; j < dncount; j++) { /* Clean out previous list */
+ if (dn_p[j]) {
+ free(dn_p[j]);
+ dn_p[j] = NULL;
+ }
+ }
+ pass++; /* Second pass... */
+ goto lu_again; /* Do it all over again. */
+ }
+ }
+ }
+ if (line) free(line);
+ if (dncount == 0 && ambiguous) {
+ printf(" Lookup: \"%s\" - ambiguous%s\n",
+ s,
+ cx == XXLOOK ? "" : " - dialing skipped"
+ );
+ return(-2);
+ }
+ return(dncount);
+}
+
+char *
+pncvt(s) char *s; { /* Phone number conversion */
+ char *p = NULL; /* (just a wrapper for dncvt() */
+ char *q = NULL;
+ static char pnbuf[128];
+ makestr(&p,dn_p[0]); /* Save these in case they are */
+ makestr(&q,dn_p2[0]); /* being used */
+ makestr(&dn_p[0],s); /* Copy the argument string to here */
+ dncvt(0,XXLOOK,1,1); /* Convert it */
+ if (!dn_p2[0]) /* Put result where can return it */
+ pnbuf[0] = NUL;
+ else
+ ckstrncpy(pnbuf,dn_p2[0],127);
+ makestr(&dn_p[0],p); /* Restore these */
+ makestr(&dn_p2[0],q);
+ makestr(&p,NULL); /* Free these */
+ makestr(&q,NULL);
+ return((char *)pnbuf);
+}
+
+int
+dodial(cx) int cx; { /* DIAL or REDIAL */
+ int i = 0, x = 0; /* Workers */
+ int sparity = -1; /* For saving global parity value */
+ int previous = 0;
+ int len = 0;
+ int literal = 0;
+ int flowsave;
+ int lufound = 0; /* Did any lookup succeed? */
+ int prefix = 1;
+ int postfix = 1;
+ int wasalpha = 0;
+ int xredial = 0;
+ int braces = 0;
+
+ char *p = NULL, *s3 = NULL, * sav = NULL;
+ int j = 0, t = 0, n = 0;
+ int xretries, xlcc;
+
+#ifdef COMMENT
+ debug(F101,"dodial cx","",cx);
+ debug(F111,"dodial diallcc",diallcc,diallcc);
+#endif /* COMMENT */
+
+ xretries = dialrtr; /* If retries not set, */
+ if (diallcc) { /* choose default based on */
+ xlcc = atoi(diallcc); /* local country code. */
+ if (xretries < 0) {
+ switch (xlcc) {
+ case 1: xretries = 10; break; /* No restrictions in NANP */
+ /* Add other country codes here */
+ /* that are known to have no restrictions on redialing. */
+ default: xretries = 1;
+ }
+ }
+ }
+ if (cx == XXPDIA) { /* Shortcut... */
+ cx = XXDIAL;
+ partial = 1;
+ debug(F100,"PDIAL sets partial=1","",0);
+ postfix = 0; /* Do not add postfix */
+ } else {
+ partial = 0;
+ debug(F100,"DIAL sets partial=0","",0);
+ }
+ previous = dialsta; /* Status of previous call, if any */
+ if (previous == DIA_PART) {
+ prefix = 0; /* do not add prefix */
+ }
+ s = NULL; /* Initialize user's dial string */
+ if (cx == XXRED) { /* REDIAL or... */
+ if ((y = cmcfm()) < 0)
+ return(y);
+ } else if (cx == XXANSW) { /* ANSWER or ... */
+ if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
+ return(y);
+ dialatmo = x;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ } else { /* DIAL or LOOKUP */
+ if (ndialdir > 0)
+ s3 = "Number to dial or entry from dial directory";
+ else
+ s3 = "Number to dial";
+ if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
+ return(x);
+ if (s) {
+ len = (int) strlen(s);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
+#ifdef COMMENT
+ if (len > 1) { /* Strip outer braces if given */
+ if (*s == '{') {
+ if (s[len-1] == '}') {
+ s[len-1] = NUL;
+ s++;
+ len -= 2;
+ }
+ }
+ }
+#else
+ s = brstrip(s); /* Strip outer braces or quotes */
+#endif /* COMMENT */
+ }
+ }
+
+ if (cx != XXLOOK) { /* Not LOOKUP */
+#ifdef IKSD
+ if (inserver) {
+ printf("Sorry, dialing is disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) {
+ ; /* Skip the modem test if TAPI */
+ } else
+#endif /* CK_TAPI */
+ if (mdmtyp < 1 && !dialtest) {
+ if (network
+#ifdef TN_COMPORT
+ && !istncomport()
+#endif /* TN_COMPORT */
+ )
+ printf("Please SET HOST first, and then SET MODEM TYPE\n");
+ else
+ printf("Sorry, you must SET MODEM TYPE first\n");
+ dialsta = DIA_NOMO;
+ return(success = 0);
+ }
+ if (!local && !dialtest) {
+ printf("Sorry, you must SET %s or SET HOST first\n",
+#ifdef OS2
+ "PORT"
+#else
+ "LINE"
+#endif /* OS2 */
+ );
+ dialsta = DIA_NOLI;
+ return(success = 0);
+ }
+ if ((!network
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) && !dialtest &&
+#ifdef CK_TAPI
+ !tttapi &&
+#endif /* CK_TAPI */
+ (speed < 0L)
+#ifdef UNIX
+ && (strcmp(ttname,"/dev/null"))
+#else
+#ifdef OSK
+ && (strcmp(ttname,"/nil"))
+#endif /* OSK */
+#endif /* UNIX */
+ ) {
+ printf("\nSorry, you must SET SPEED first\n");
+ dialsta = DIA_NOSP;
+ return(success = 0);
+ }
+ }
+ if (cx != XXANSW) {
+ for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
+ if (!dialnum) { /* First time dialing */
+ dn_p[j] = NULL; /* initialize all pointers. */
+ dn_p2[j] = NULL;
+ } else if (dn_p[j]) { /* Not the first time, */
+ free(dn_p[j]); /* free previous, if any, */
+ dn_p[j] = NULL; /* then set to NULL. */
+ if (dn_p2[j])
+ free(dn_p2[j]);
+ dn_p2[j] = NULL;
+ } else break; /* Already NULL */
+ }
+ if (len == 0)
+ s = NULL;
+ if (!s)
+ s = dialnum;
+ if (!s) {
+ if (cx == XXLOOK)
+ printf("?Lookup what?\n");
+ else
+ printf("%s\n", (cx == XXRED) ?
+ "?No DIAL command given yet" :
+ "?You must specify a number to dial"
+ );
+ return(-9);
+ }
+
+ /* Now we have the "raw" dial or lookup string and s is not NULL */
+
+ makestr(&dscopy,s); /* Put it in a safe place */
+ s = dscopy;
+ n = 0;
+
+ debug(F111,"dodial",s,ndialdir);
+
+ wasalpha = 0;
+ if (isalpha(*s)) {
+ wasalpha = 1;
+ if (ndialdir > 0) { /* Do we have a dialing directory? */
+ n = ludial(s,cx); /* Look up what the user typed */
+ if (n == 0)
+ printf(" Lookup: \"%s\" - not found%s\n",
+ s,
+ cx == XXLOOK ? "" : " - dialing as given\n"
+ );
+ }
+ debug(F101,"dodial",s,n);
+ if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
+ if (n == -1) /* -2 means ludial already gave msg */
+ printf(" Lookup: fatal error - dialing skipped\n");
+ dialsta = DIA_DIR;
+ return(-9);
+ }
+ if (n > 0) /* A successful lookup */
+ lufound = 1;
+ } else if (*s == '=') { /* If number starts with = sign */
+ s++; /* strip it */
+ literal = 1; /* remember this */
+ while (*s == SP) s++; /* and then also any leading spaces */
+ } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
+ makelist(tmpbuf,dn_p,MAXDNUMS);
+ makestr(&dscopy,tmpbuf);
+ s = tmpbuf;
+ for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
+ if (!dn_p[n]) break;
+ braces = 1;
+ }
+ if (cx == XXLOOK && !wasalpha && !braces) {
+ /* We've been told to lookup a number or a quoted name */
+ char *p;
+ n = 0;
+ p = literal ? s : pncvt(dscopy);
+ if (!p) p = "";
+ if (*p) {
+ printf("%s => %s\n", dscopy, p);
+ return(success = 1);
+ } else {
+ printf("?Bad phone number\n");
+ return(success = 0);
+ }
+ }
+ /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
+ /* But don't save pieces of partial dial ... */
+
+ debug(F101,"DIAL save dialnum partial","",partial);
+ debug(F101,"DIAL save dialnum previous","",previous);
+ if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
+ (cx == XXLOOK && n > 0)) {
+ makestr(&dialnum,dscopy);
+ if (!quiet && dscopy && !dialnum)
+ printf("WARNING - memory allocation failure: redial number\n");
+ }
+ if (n > 0) {
+ if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
+ if (!strcmp(d_name,s))
+ printf(" Lookup: \"%s\" - exact match\n",s);
+ else
+ printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
+ s,
+ d_name
+ );
+ }
+ if ((cx == XXLOOK) ||
+ ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
+ printf(" %d telephone number%sfound for \"%s\"%s\n",
+ n,
+ (n == 1) ? " " : "s ",
+ s,
+ (n > 0) ? ":" : "."
+ );
+ s3 = getdname();
+ }
+ for (i = 0; i < n; i++) { /* Convert */
+ dn_x[i] = -1;
+ if (dncvt(i,cx,prefix,postfix) < 0) {
+ if (cx != XXLOOK) {
+ dialsta = DIA_DIR;
+ return(-9);
+ }
+ }
+ }
+ if (dialsrt && n > 1) { /* Sort into optimal order */
+ for (i = 0; i < n-1; i++) {
+ for (j = i+1; j < n; j++) {
+ if (dn_x[j] < dn_x[i]) {
+ t = dn_x[j];
+ dn_x[j] = dn_x[i];
+ dn_x[i] = t;
+ p = dn_p[j];
+ dn_p[j] = dn_p[i];
+ dn_p[i] = p;
+ p = dn_p2[j];
+ dn_p2[j] = dn_p2[i];
+ dn_p2[i] = p;
+ }
+ }
+ }
+ }
+ if ((cx == XXLOOK) ||
+ ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
+ int nn = n;
+#ifndef NOSPL
+ char * p;
+#endif /* NOSPL */
+ if (cx != XXLOOK)
+ if (n > 12) nn = 12;
+ for (i = 0; i < nn; i++) {
+ printf("%3d. %-12s %-20s => %-20s (%d)\n",i+1,
+ s3, dn_p[i],
+ dn_p2[i] ? dn_p2[i] : "(processing failed)",
+ dn_x[i]
+ );
+ }
+ if (cx != XXLOOK && n != nn)
+ printf("And %d more...\n", n - nn);
+ }
+ } else if (n == 0) { /* Not found in directory */
+ makestr(&(dn_p[0]),literal ? s : dscopy);
+ makestr(&d_name,literal ? s : dscopy);
+ dncount = 1;
+ n = 1;
+ if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
+ dialsta = DIA_DIR; /* portable-format number ... */
+ return(-9);
+ }
+ }
+
+#ifndef NONET
+#ifdef NETCONN
+ /* It's not good that the networks directory depends on NOT-NODIAL.. */
+ if (cx == XXLOOK && dscopy) { /* Networks here too... */
+ extern char *nh_p[], *nh_p2[], *n_name;
+ extern char *nh_px[4][MAXDNUMS+1];
+ n = -1;
+ if (nnetdir > 0) { /* Do we have a network directory? */
+ dirline = 0;
+ n = lunet(dscopy); /* Look up what the user typed */
+ }
+ if (n > -1) {
+ int k;
+ if (n > 0) /* A successful lookup */
+ lufound = 1;
+ if (cx == XXLOOK && n == 0)
+ printf(" Lookup: \"%s\" - not found\n",dscopy);
+ else
+ printf("%s %d network entr%s found for \"%s\"%s\n",
+ cx == XXLOOK ? " Lookup:" : "",
+ n,
+ (n == 1) ? "y" : "ies",
+ dscopy,
+ (n > 0) ? ":" : "."
+ );
+
+ for (i = 0; i < n; i++) {
+
+ printf("%3d. %-12s => %-9s %s",
+ i+1,n_name,nh_p2[i],nh_p[i]);
+ for (k = 0; k < 4; k++) {
+ if (nh_px[k][i]) {
+ printf(" %s",nh_px[k][i]);
+ } else
+ break;
+ }
+ printf("\n");
+ }
+ }
+ }
+#endif /* NETCONN */
+#endif /* NONET */
+ if (cx == XXLOOK)
+ return(success = lufound);
+ } /* cx != XXANSW */
+
+#ifdef VMS
+ conres(); /* So Ctrl-C/Y will work */
+#endif /* VMS */
+/*
+ Some modems do not react well to parity. Also, if we are dialing through a
+ TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
+ negotiations.
+
+ This should work even if the user interrupts the DIAL command, because the
+ DIAL module has its own interrupt handler. BUT... if, for some reason, a
+ dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
+ parity should be used), this might prevent successful dialing. For that
+ reason, we don't do this for V.25bis modems.
+*/
+ sparity = parity; /* Save current parity */
+ if ((dialcapas & CKD_V25) == 0) /* If not V.25bis... */
+ parity = 0; /* Set parity to NONE */
+
+ flowsave = flow;
+/*
+ These modems use some kind of screwy flow control while in command mode,
+ and do not present CTS as they should. So if RTS/CTS is set (or even if
+ it isn't) disable flow control during dialing.
+*/
+#ifndef MINIDIAL
+ if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
+ flow = FLO_NONE; /* This is not enough */
+#ifdef CK_TTSETFLOW
+ ttsetflow(FLO_NONE); /* Really turn it off */
+#endif /* CK_TTSETFLOW */
+ }
+#endif /* MINIDIAL */
+ if (!network
+#ifdef TN_COMPORT
+ || istncomport()
+#endif /* TN_COMPORT */
+ ) {
+ int x;
+ if ((x = ttgmdm()) > -1) {
+ if (!x && msgflg) {
+ printf(
+"WARNING - No modem signals detected. Is your modem turned on? If not,\n\
+use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n",
+ cx == XXANSW ?
+ "ANSWER again" :
+ "REDIAL"
+ );
+ }
+ if (flow == FLO_RTSC) {
+ if (!(x & BM_CTS)) {
+ if (msgflg)
+ printf(
+"WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
+Disabling flow control temporarily %s...\n",
+ cx == XXANSW ?
+ "while waiting for call" :
+ "during dialing"
+ );
+ flow = FLO_NONE;
+ }
+ }
+ }
+ }
+ if (cx == XXANSW) { /* ANSWER */
+ success = ckdial("",0,0,1,0);
+ goto dialfin;
+ }
+
+/* Edit 192 adds the ability to dial repeatedly. */
+
+ i = 0;
+ dialcount = 0;
+ do {
+ if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
+ dialcount = i+1;
+ success = 0;
+ /* And the ability to dial alternate numbers. */
+ /* Loop to dial each in a list of numbers for the same name... */
+ for (j = 0; j < n && !success; j++) { /* until one answers. */
+ s = dn_p2[j]; /* Next number in list */
+ if (dn_x[j] >= dialrstr) { /* Dial restriction */
+ printf("Restricted: %s, skipping...\n",dn_p[j]);
+ continue;
+ }
+ xredial = (i == 0 && j == 0) ? 0 : 1;
+ if (!s) s = dn_p[j];
+
+#ifndef NOSPL
+ sav = s;
+ p = xdial(s); /* Apply DIAL macro now */
+ if (p) if (*p) s = p;
+#endif /* NOSPL */
+
+ /* Dial confirmation */
+ /* NOTE: the uq_xxx() calls allow for a GUI dialog */
+
+ if (i == 0 && dialcnf) {
+ char msgbuf[128];
+ ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL);
+ x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0);
+ if (!x) {
+
+#ifndef COMMENT
+ x = uq_txt( /* Allow GUI dialog */
+#ifdef OS2
+" Please enter the correct number,\r\n or press Enter to skip.",
+#else
+" Please enter the correct number,\r\n or press Return to skip.",
+#endif /* OS2 */
+ "Corrected phone number: ",
+ 1,
+ NULL,
+ atmbuf,
+ ATMBL,
+ s,
+ DEFAULT_UQ_TIMEOUT
+ );
+ if (x && atmbuf[0]) { /* They gave a new one */
+ s = atmbuf;
+ makestr(&(dn_p2[j]), s);
+ }
+
+#else /* COMMENT */
+
+#ifdef CK_RECALL
+ extern int on_recall;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL);
+ cmsetp(
+#ifdef OS2
+" Please enter the correct number,\r\n or press Enter to skip: "
+#else
+" Please enter the correct number,\r\n or press Return to skip: "
+#endif /* OS2 */
+ );
+ cmini(ckxech);
+ x = -1;
+ if (pflag) prompt(NULL);
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ y = cmdgquo();
+ cmdsquo(0);
+ while (x < 0) {
+ x = cmtxt("Corrected phone number","",&s,NULL);
+ cmres();
+ }
+ if ((int) strlen(s) < 1) {
+ cmsetp(psave);
+ continue;
+ }
+ makestr(&(dn_p2[j]), s);
+ cmdsquo(y);
+ cmsetp(psave);
+#endif /* COMMENT */
+ }
+ }
+ if (dialtest) { /* Just testing */
+ if (i + j == 0)
+ printf("\nTESTING...\n");
+ if (dialmac)
+ printf(" Number: \"%s\" => \"%s\"\n",sav,s);
+ else
+ printf(" Number: \"%s\"\n",s);
+ dialsta = DIA_BUSY;
+ success = 0;
+ } else {
+ what |= W_DIALING;
+ success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
+ what &= ~(W_DIALING);
+ if (!success) {
+ if (dialsta < 8 || /* Break out if unrecoverable error */
+ dialsta == DIA_INTR ||
+ dialsta == DIA_ERR ||
+ previous == DIA_PART
+ )
+ break;
+ }
+ }
+ }
+ if (success) /* Succeeded, leave the outer loop */
+ break;
+ if (dialsta < 8 || /* Break out if unrecoverable error */
+ dialsta == DIA_INTR || /* Interrupted */
+ dialsta == DIA_NODT || /* No dialtone */
+ dialsta == DIA_NOAC || /* Access forbidden */
+ dialsta == DIA_BLCK || /* Blacklisted */
+ dialsta == DIA_DIR || /* Dialing directory error */
+ dialsta == DIA_ERR || /* Modem command error */
+ previous == DIA_PART)
+ break;
+ if (++i >= xretries) /* Break out if too many tries */
+ break;
+ if (!backgrd && !quiet) {
+ if (dialint > 5)
+ printf(
+"\nWill redial in %d second%s- press any key to redial immediately.\n",
+ dialint,
+ dialint == 1 ? " " : "s "
+ );
+ printf("Ctrl-C to cancel...\n");
+ }
+ x = dialint; /* Redial interval */
+ while (x-- > 0) {
+ if ((y = conchk()) > 0) { /* Did they type something? */
+ while (y--) coninc(0); /* Yes, absorb it */
+ break; /* And wake up */
+ }
+ sleep(1); /* No interrupt, sleep a sec */
+ }
+ } while (!success);
+
+ dialfin:
+
+ if (cx != XXLOOK) {
+ if (!success)
+ bleep((short) BP_FAIL);
+ else if (!quiet)
+ bleep((short) BP_NOTE);
+#ifdef OS2
+ setint(); /* Fix OS/2 interrupts */
+#endif /* OS2 */
+ if (sparity > -1)
+ parity = sparity; /* Restore parity if we saved it */
+ flow = flowsave;
+#ifdef OS2
+ ttres(); /* Restore DIAL device */
+#endif /* OS2 */
+#ifdef VMS
+ concb((char)escape); /* Restore console */
+#endif /* VMS */
+#ifdef OS2
+ { /* Set session title */
+ char * p, name[72]; /* in window list. */
+ char * q;
+ if (cx == XXANSW) {
+ q = "Incoming call";
+ } else {
+ if (d_name)
+ q = d_name;
+ else if (dialnum)
+ q = dialnum;
+ else if (ttname[0])
+ q = ttname;
+ else q = "";
+ }
+ p = name;
+ if (success) {
+ strncpy(name,q,48);
+ while (*p) { /* Uppercase it for emphasis. */
+ if (islower(*p))
+ *p = toupper(*p);
+ p++;
+ }
+ } else
+ name[0] = NUL ;
+ os2settitle((char *) name, TRUE);
+ }
+#endif /* OS2 */
+ }
+ if (cx != XXLOOK) {
+ if (success) {
+ if (reliable == SET_AUTO) { /* It's not a reliable connection. */
+ reliable = SET_OFF;
+ debug(F101,"dodial reliable","",reliable);
+ }
+ } else {
+#ifndef NOHINTS
+ extern int hints;
+ if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */
+ extern int dialmhu, dialhng, dialdpy;
+ extern char * dialmsg[];
+ printf("\n*************************\n");
+ printf("DIAL-class command failed.\n");
+ printf("Modem type: %s\n", gmdmtyp());
+ printf("Device: %s\n", ttname);
+ printf("Speed: %ld\n", speed);
+ printf("Dial status: %d",dialsta);
+ if (dialsta < 35 && dialmsg[dialsta])
+ printf(" [%s]",dialmsg[dialsta]);
+ printf("\n");
+ if (dialsta == DIA_TIMO ||
+ dialsta == DIA_NRDY ||
+ (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN)
+ ) {
+ switch (dialsta) {
+ case DIA_TIMO:
+ printf(
+" . SET DIAL TIMEOUT to a greater value and try again.\n"
+ );
+ break;
+ case DIA_NRSP:
+ case DIA_NRDY:
+ case DIA_NOIN:
+ printf(
+" . Is the modem turned on?\n"
+ );
+ printf(
+" . Are you using the right communication port?\n"
+ );
+ break;
+ case DIA_NODT:
+ printf(
+" . Is the modem connected to the telephone line?\n"
+ );
+ }
+ if (mdmtyp == n_GENERIC) {
+ printf(
+" . Please choose a specific modem type with SET MODEM TYPE and try again.\n"
+ );
+ printf(
+" SET MODEM TYPE ? to see the list of known modem types.\n"
+ );
+ } else {
+ printf(
+" . Are you sure you have chosen the appropriate modem type?\n"
+ );
+ }
+ if (speed > 19200L) {
+ printf(
+" . Maybe the interface speed (%ld) is too fast:\n", speed
+ );
+ printf(
+" SET SPEED to a lower speed and try again.\n"
+ );
+ printf(
+" SET SPEED ? to see the list of valid speeds.\n"
+ );
+ }
+ if (dialhng) {
+ if (dialmhu)
+ printf(
+" . SET MODEM HANGUP-METHOD RS232 and try again.\n"
+ );
+ else
+ printf(
+" . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n"
+ );
+ printf(
+" . If that doesn't work, try again with SET DIAL HANGUP OFF.\n"
+ );
+ } else {
+ printf(
+" . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n"
+ );
+ }
+ if (!dialdpy)
+ printf(
+" . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n"
+ );
+ }
+#ifndef NOSHOW
+ printf(
+" . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n"
+ );
+#endif /* NOSHOW */
+
+#ifndef NOHELP
+ printf(
+" . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n"
+ );
+#endif /* NOHELP */
+ printf("(Use SET HINTS OFF to suppress future hints.)\n");
+ printf("*************************\n\n");
+ }
+#endif /* NOHINTS */
+ }
+ }
+ return(success);
+}
+#endif /* NODIAL */
+
+/* D O T Y P E -- Type (display) a file with various options... */
+
+#ifdef BIGBUFOK
+#define TYPBUFL 16384
+#else
+#define TYPBUFL 256
+#endif /* BIGBUFOK */
+
+int typ_lines = 0; /* \v(ty_ln) */
+int typ_mtchs = 0; /* \v(ty_lm) */
+static int typ_int = 0; /* Flag if TYPE interrupted */
+
+#ifdef UNICODE
+extern int fcharset, fileorder, byteorder, ucsorder;
+#define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4
+static char * mp = NULL;
+static char * mbuf = NULL;
+static long xn = 0L;
+
+static int
+#ifdef CK_ANSIC
+storechar(char c)
+#else
+storechar(c) char c;
+#endif /* CK_ANSIC */
+{
+ if (!mp) return(-1);
+ if (++xn > TYPXBUFL)
+ return(-1);
+ debug(F111,"storechar xn",ckitoa((int)c),xn);
+ *mp++ = c;
+ return(0);
+}
+#endif /* UNICODE */
+
+static FILE * ofp = NULL; /* For /OUTPUT: file */
+
+static int
+typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
+ register int i;
+
+ debug(F011,"typeline buf",buf,len);
+ /* debug(F101,"typeline outcs","",outcs); */
+
+#ifdef OS2
+#ifndef NOLOCAL
+#ifdef UNICODE
+ /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */
+ /* Len is its length in bytes. There is no line terminator. */
+ /* outcs is the file character-set number (FC_xxx) of the target set */
+ /* that was requested by the user. */
+ if (!inserver && !k95stdout) {
+ extern int wherex[], wherey[];
+ extern unsigned char colorcmd;
+
+ VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2,
+ wherey[VCMD], wherex[VCMD], &colorcmd);
+ printf("\r\n");
+ return(0);
+ }
+#endif /* UNICODE */
+#endif /* NOLOCAL */
+#endif /* OS2 */
+
+/* In Unix, VMS, etc, the line has already been converted to the desired */
+/* character-set, if one was given. OR... on all platforms, including in */
+/* K95, we don't know the character set. In either case we dump the line */
+/* byte by byte in case it contains NULs (printf() would truncate). */
+
+#ifdef COMMENT
+ for (i = 0; i < len; i++)
+ putchar(buf[i]);
+#else
+ for (i = 0; i < len; i++) {
+ if (ofp == stdout) {
+ putchar(buf[i]);
+ } else {
+ putc(buf[i],ofp);
+ }
+ }
+#endif /* COMMENT */
+
+#ifdef IKSD
+ if (inserver) {
+#ifdef UNICODE
+ if (outcs == FC_UCS2) {
+ if (ofp == stdout) {
+ putchar(NUL);
+ } else {
+ putc(NUL,ofp);
+ }
+ }
+#endif /* UNICODE */
+ if (ofp == stdout) {
+ putchar('\r');
+ } else {
+ putc('\r',ofp);
+ }
+ }
+#endif /* IKSD */
+#ifdef UNICODE
+ if (outcs == FC_UCS2) {
+ if (ofp == stdout) {
+ putchar(NUL);
+ } else {
+ putc(NUL,ofp);
+ }
+ }
+#endif /* UNICODE */
+ if (ofp == stdout) {
+ putchar('\n');
+ } else {
+ putc('\n',ofp);
+ }
+ fflush(stdout);
+ return(0);
+}
+
+static int /* Get translated line */
+typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
+ int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0;
+#ifdef UNICODE
+ int xxn = -1;
+ int yyn = -9;
+ xn = 0L;
+
+#ifdef DEBUG
+ if (deblog && typ_lines == 0) {
+ debug(F101,"typegetline incs","",incs);
+ debug(F101,"typegetline outcs","",outcs);
+ debug(F101,"typegetline feol","",feol);
+ debug(F101,"typegetline byteorder","",byteorder);
+ debug(F101,"typegetline ucsorder ","",ucsorder);
+ debug(F111,"typegetline fileorder","1",fileorder);
+ }
+#endif /* DEBUG */
+
+ if (incs < 0) /* Shouldn't happen */
+ return(-2);
+
+ if (outcs == -1) /* Can happen */
+ outcs = incs;
+
+ if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */
+ xlate = 1;
+ if (!mbuf) { /* Allocate buffer if not allocated */
+ mbuf = (char *)malloc(TYPXBUFL+1); /* yet */
+ if (!mbuf) {
+ printf("WARNING: Translation buffer allocation failure.\n");
+ printf("Translation will be skipped...\n");
+ xlate = 0;
+ }
+ }
+ }
+ if (xlate) { /* Translating... */
+ mp = mbuf; /* Reset working buffer pointer */
+/*
+ Here we call xgnbyte() in a loop, having it return UCS-2 bytes. In K95, we
+ use UCS-2 directly. Elsewhere, we feed the UCS-2 bytes into xpnbyte() to
+ convert them to the desired target character set. But since we are using
+ UCS-2, we have several sources for confusion: (1) xgnbyte() might return in
+ LE or BE byte order, with no explicit indication of what the order is; but
+ (2) xpnbyte() wants BE; but (3) Windows wants LE.
+*/
+ while (1) {
+ if (typ_int) /* Quit if interrupted */
+ return(0);
+ c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
+ debug(F000,"typegetline c0","",c0);
+ if (c0 < 0) { /* EOF */
+ eof++;
+ break;
+ }
+ c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
+ debug(F000,"typegetline c1","",c1);
+ if (c1 < 0) { /* EOF */
+ eof++;
+ break;
+ }
+#ifdef DEBUG
+ if (deblog && typ_lines == 0) {
+ if (count == 0) /* Check fileorder after BOM */
+ debug(F111,"typegetline fileorder","2",fileorder);
+ }
+#endif /* DEBUG */
+
+#ifdef COMMENT
+/* Now we have the two UCS-2 bytes. Which order are they in? */
+
+ if (fileorder > 0) { /* Little Endian */
+ int t; /* So swap them */
+ debug(F100,"typegetline swapping","",0);
+ t = c1;
+ c1 = c0;
+ c0 = t;
+ }
+#endif /* COMMENT */
+ if (c0 == 0 && c1 == 0x0D) /* Now see if we have EOL */
+ yyn = xn;
+
+ if (c0 == 0 && c1 == 0x0A) /* Now see if we have EOL */
+ xxn = xn;
+
+ count++; /* Count byte */
+
+/* Give the two bytes to xpnbyte() in BE order */
+
+ if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1);
+ if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1);
+
+ if (xxn > -1) { /* Have end of line? */
+ xn = xxn;
+ if (yyn == xxn - 2) /* Adjust for CRLF */
+ xn = yyn;
+ break; /* And break out of loop. */
+ }
+ }
+ mbuf[xn] = NUL;
+ if (xn > n) /* Can truncate here... */
+ xn = n;
+ memcpy(buf,mbuf,xn);
+ debug(F011,"typegetline xlate",buf,xn);
+ return((eof && (xn == 0)) ? -1 : xn);
+ }
+#endif /* UNICODE */
+#ifdef COMMENT
+ /* We can't use this because, stupidly, zsinl() doesn't return a length. */
+ /* It could be changed but then we'd have to change all ck?fio.c modules */
+ x = zsinl(ZIFILE,buf,n);
+#else
+ /* So instead, we copy zsinl() to here... */
+ /* But note: This does not necessarily handle UCS-2 alignment properly; */
+ /* that's what the code in the first section of this routine is for. */
+ /* But it does tolerate files that contain NULs. */
+ {
+ int a;
+ char *s;
+
+ s = buf;
+ a = -1; /* Current character, none yet. */
+ debug(F101,"typegetline zsinl simulation","",n);
+ while (n--) { /* Up to given length */
+#ifdef COMMENT
+ int old = 0;
+ if (feol) /* Previous character */
+ old = a;
+#endif /* COMMENT */
+ if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */
+ debug(F101,"typegetline zchin fail","",count);
+ if (count == 0)
+ x = -1; /* EOF or other error */
+ break;
+ } else
+ count++;
+ if (feol) { /* Single-character line terminator */
+ if (a == feol)
+ break;
+ } else { /* CRLF line terminator */
+#ifdef COMMENT
+/* Debug log shows that in Windows, <CR><LF> is returned as <LF>. */
+/* Apparently we're not reading the file in binary mode. */
+
+ if (a == '\015') /* CR, get next character */
+ continue;
+ if (old == '\015') { /* Previous character was CR */
+ if (a == '\012') { /* This one is LF, so we have a line */
+ break;
+ } else { /* Not LF, deposit CR */
+ *s++ = '\015';
+ n--;
+ len++;
+ }
+ }
+#else
+ if (a == LF) {
+ if (s[len] == CR) { /* This probably won't happen */
+ s[len] = NUL;
+ s--;
+ len--;
+ }
+ break;
+ }
+#endif /* COMMENT */
+ }
+ *s = a; /* Deposit character */
+ s++;
+ len++;
+ }
+ *s = '\0'; /* Terminate the string */
+ }
+#endif /* COMMENT */
+ return(x < 0 ? -1 : len);
+}
+
+
+#ifndef MAC
+SIGTYP
+#ifdef CK_ANSIC
+tytrap(int foo) /* TYPE interrupt trap */
+#else
+tytrap(foo) int foo;
+#endif /* CK_ANSIC */
+/* tytrap */ {
+#ifdef __EMX__
+ signal(SIGINT, SIG_ACK);
+#endif
+ debug(F100,"type tytrap SIGINT","",0);
+ typ_int = 1; /* (Need arg for ANSI C) */
+ SIGRETURN;
+}
+#endif /* MAC */
+
+int
+dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z)
+ char * file, * pat, * prefix; int paging, first, head, width, incs, outcs;
+ char * outfile; int z;
+/* dotype */ {
+ extern CK_OFF_T ffc;
+ char buf[TYPBUFL+2];
+ char * s = NULL;
+ int rc = 1, lines = 0, ucs2 = 0;
+ char ** tail = NULL;
+ int * tlen = NULL;
+ int tailing = 0, counting = 0;
+ int x, c, n, i, j, k = 0;
+ int number = 0, save, len, pfxlen = 0, evalpfx = 1;
+#ifdef UNICODE
+ int ucsbom_sav;
+ extern int ucsbom;
+#endif /* UNICODE */
+#ifdef NT
+ int gui = 0;
+#endif /* NT */
+
+#ifndef MAC
+#ifdef OS2
+#ifdef NT
+ SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
+#else /* NT */
+ SIGTYP (* volatile oldsig)(int);
+#endif /* NT */
+#else /* OS2 */
+ SIGTYP (* oldsig)();
+#endif /* OS2 */
+#endif /* MAC */
+
+#ifdef KUI
+ if (outfile == (char *)1) {
+ gui = 1;
+ outfile = "";
+ }
+#endif /* KUI */
+
+ if (!file) file = "";
+ if (!*file) return(-2);
+
+ if (ofp != stdout) { /* In case of previous interruption */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ if (!outfile) outfile = "";
+ if (outfile[0]) {
+ ofp = fopen(outfile,"w"); /* Open output file */
+ if (!ofp) {
+ printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
+ ofp = stdout;
+ return(-9);
+ }
+ }
+ number = z;
+ if (number && prefix) prefix = NULL;
+
+#ifdef UNICODE
+ ucsbom_sav = ucsbom; /* We are not creating a file */
+ ucsbom = 0; /* Do not use BOM bytes */
+#endif /* UNICODE */
+
+ typ_int = 0;
+
+ save = binary; /* Save file type */
+
+ debug(F101,"dotype incs","",incs);
+ debug(F101,"dotype outcs","",outcs);
+
+#ifdef UNICODE
+ debug(F111,"dotype fileorder","A",fileorder);
+#ifdef OS2
+ if (!inserver && !k95stdout)
+ outcs = FC_UCS2;
+#endif /* OS2 */
+
+ if (outcs == FC_UCS2) /* Output is UCS-2? */
+ ucs2 = 1;
+ if (fileorder < 0)
+ fileorder = ucsorder;
+ debug(F111,"dotype fileorder","B",fileorder);
+#endif /* UNICODE */
+
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ ttgcwsz();
+#else /* OS2 */
+ /* Check whether window size changed */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ debug(F101,"dotype cmd_rows","",cmd_rows);
+ debug(F101,"dotype cmd_cols","",cmd_cols);
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ if (prefix)
+ pfxlen = strlen(prefix);
+
+ if (paging < 0) { /* Count only, don't print */
+ counting = 1;
+ prefix = NULL;
+ width = 0;
+ paging = 0;
+ }
+ if (ucs2) /* Crude... */
+ width *= 2;
+
+#ifdef OS2
+ if (*file) {
+ ckstrncpy(buf, file, TYPBUFL); /* Change / to \. */
+ p = buf;
+ while (*p) {
+ if (*p == '/') *p = '\\';
+ p++;
+ }
+ file = buf;
+ } else {
+ rc = 0;
+ goto xdotype;
+ }
+#endif /* OS2 */
+
+ if (zchki(file) == -2) { /* It's a directory */
+ debug(F111,"dotype zchki failure",file,-2);
+ if (xcmdsrc == 0) {
+ printf("?Not a regular file: \"%s\"\n",file);
+ rc = -9;
+ } else
+ rc = 0;
+ goto xdotype;
+ }
+ if (!zopeni(ZIFILE, file)) { /* Not a directory, open it */
+ debug(F111,"dotype zopeni failure",file,0);
+ if (xcmdsrc == 0) {
+ printf("?Can't open file: \"%s\"\n",file);
+ rc = -9;
+ } else
+ rc = 0;
+ goto xdotype;
+ }
+
+#ifndef AMIGA
+#ifndef MAC
+ errno = 0;
+ oldsig = signal(SIGINT, tytrap); /* Save current interrupt trap. */
+ /* debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig); */
+#endif /* MAC */
+#endif /* AMIGA */
+
+ if (paging > -1) /* More-prompting */
+ xaskmore = paging;
+
+ binary = 0;
+
+ if (head < 0) { /* "tail" was requested */
+ tailing = 1; /* Set flag */
+ head = 0 - head; /* Get absolute number of lines */
+ if (!counting) {
+ tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
+ if (!tail) {
+ printf("?Memory allocation failure\n");
+ goto xdotype;
+
+ }
+ tlen = (int *) malloc(head * sizeof(int));
+ if (!tlen) {
+ printf("?Memory allocation failure\n");
+ goto xdotype;
+
+ }
+ for (i = 0; i < head; i++) { /* Initialize each pointer in list. */
+ tail[i] = NULL;
+ tlen[i] = 0;
+ }
+ }
+ }
+ typ_lines = 0;
+ typ_mtchs = 0;
+
+#ifdef UNICODE
+ if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */
+ ffc = (CK_OFF_T)0;
+ initxlate(incs,outcs); /* Set up translation functions */
+ } else
+#endif /* UNICODE */
+ outcs = -1; /* Means we don't know the charset */
+
+ debug(F101,"dotype ffc","",ffc);
+ debug(F101,"dotype outcs 2","",outcs);
+#ifdef UNICODE
+ debug(F111,"dotype fileorder","C",fileorder);
+#endif /* UNICODE */
+
+ /* Allow the buffer to contain NULs */
+
+ for (n = first;
+ (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1;
+ lines++
+ ) {
+ debug(F011,"dotype line",buf,len);
+#ifndef MAC
+ if (typ_int) { /* Interrupted? */
+ typ_int = 0;
+ debug(F101,"type interrupted line","",lines);
+ printf("^C...\n"); /* Print message */
+ if (ofp != stdout) { /* Close any output file */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ goto xxdotype;
+ }
+#endif /* MAC */
+ typ_lines++; /* For \v(ty_ln) */
+ if (pat) /* Matching? */
+ if (!ckmatch(pat,buf,1,1+4)) /* Line matches pattern? */
+ continue; /* No, skip it */
+ typ_mtchs++;
+
+ if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
+ break;
+
+ buf[TYPBUFL+1] = NUL; /* Just in case... */
+ if (prefix) { /* Add specified prefix to each line */
+ char pbuf[64];
+ char * pp;
+ pp = prefix;
+#ifndef NOSPL
+ if (evalpfx) { /* Prefix is a variable? */
+ int n = 63; /* Maybe - evaluate it and see */
+ char * p = pbuf;
+ zzstring(prefix,&p,&n); /* If there is no change */
+ if (!strcmp(prefix,pbuf)) { /* it's not a variable */
+ evalpfx = 0; /* So don't do this again. */
+ } else { /* It was a variable */
+ pp = pbuf; /* So substitute its value */
+ pfxlen = 63 - n; /* and get its new length */
+ }
+ }
+#endif /* NOSPL */
+ if (len + pfxlen + 2 < TYPBUFL) {
+ /* Shift right to make room for prefix */
+ memcpy((char *)line+pfxlen,(char *)buf,len);
+ lset((char *)line,pp,pfxlen,SP);
+ debug(F110,"dotype prefix",line,pfxlen);
+ len += pfxlen;
+ memcpy((char *)buf,(char *)line,len);
+ }
+ } else if (number) { /* Line numbers */
+ int x;
+ sprintf(line,"%4d. ",typ_lines);
+ x = strlen(line);
+ len += x;
+ if (len < LINBUFSIZ) {
+ memcpy((char *)&line[x],(char *)buf,len);
+ memcpy((char *)buf,(char *)line,len);
+ }
+ }
+ if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
+ char * obuf = line; /* But to do that first we must */
+ int i,k,z; /* expand tabs; assume every 8 cols. */
+ line[0] = NUL;
+ for (i = 0, k = 0; i < width; k++) { /* Character loop... */
+ if (!buf[k]) /* No more chars in this line, done. */
+ break;
+ if (buf[k] != '\t') { /* If it's not a tab */
+ if (i >= LINBUFSIZ) /* Check for overflow */
+ break;
+ obuf[i++] = buf[k]; /* and then deposit it. */
+ obuf[i] = NUL; /* Keep it null-terminated */
+ continue;
+ }
+ z = 8 - (i % 8); /* It's a tab, expand it. */
+ if (z == 0) z = 8;
+ for (j = 0; j < z && i < LINBUFSIZ; j++) {
+#ifdef UNICODE
+ if (ucs2 && !ucsorder)
+ obuf[i++] = NUL;
+#endif /* UNICODE */
+ obuf[i++] = ' ';
+#ifdef UNICODE
+ if (ucs2 && ucsorder)
+ obuf[i++] = NUL;
+#endif /* UNICODE */
+ }
+ obuf[i++] = NUL;
+ obuf[i] = NUL;
+ }
+ obuf[width] = NUL; /* Now truncate at given width. */
+#ifdef COMMENT
+ /* This doesn't work for UCS-2 because it contains NULs */
+ ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
+#else
+ memcpy((char *)buf,(char *)obuf,i); /* Copy it back */
+#endif /* COMMENT */
+ len = (i > width) ? width : i; /* Spare us another strlen()... */
+ }
+ if (tailing) { /* If /TAIL:n... */
+ k = lines % head; /* save this line in circular buffer */
+ if (!counting) {
+ if (tail[k]) free(tail[k]);
+ tail[k] = malloc(len+2);
+ if (!tail[k]) {
+ printf("?Memory allocation failure\n");
+ goto xdotype;
+ }
+ memcpy(tail[k],buf,len);
+ tlen[k] = len;
+ continue;
+ }
+ }
+ if (counting) /* If only counting */
+ continue; /* we're done with this line */
+
+ if (paging) { /* Displaying this line... */
+ int u;
+ u = len; /* Length in BYTES */
+ if (ucs2) /* If outputting in UCS-2 */
+ u /= 2; /* convert length to CHARACTERS */
+ x = (u / cmd_cols) + 1; /* Crudely allow for wrap */
+ if (cmd_rows > 0 && cmd_cols > 0)
+ n += x; /* This assumes terminal will wrap */
+ }
+#ifdef KUI
+ if ( gui ) {
+ int i;
+ unsigned short * uch = (unsigned short *)buf;
+ for ( i=0; i<len/2; i++)
+ gui_text_popup_append(uch[i]);
+ gui_text_popup_append(CR);
+ gui_text_popup_append(LF);
+ }
+ else
+#endif /* KUI */
+ typeline(buf,len,outcs,ofp); /* Print line, length based */
+#ifdef CK_TTGWSIZ
+ debug(F101,"dotype n","",n);
+ if (paging > 0 && ofp == stdout) { /* Pause at end of screen */
+ if (cmd_rows > 0 && cmd_cols > 0) {
+ if (n > cmd_rows - 3) {
+ if (!askmore())
+ goto xdotype;
+ else
+ n = 0;
+ }
+ }
+ }
+#endif /* CK_TTGWSIZ */
+ }
+
+ xdotype:
+ if (counting) {
+ fprintf(ofp,
+ "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
+ if (pat)
+ fprintf(ofp,
+ "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
+ goto xxdotype;
+ }
+ if (tailing && tail) { /* Typing tail of file? */
+ if (lines < head) { /* Yes, show the lines we saved */
+ k = 0; /* Show all lines */
+ } else { /* More lines than tail number */
+ lines = k; /* Last line to show */
+ k++; /* First line to show */
+ if (k >= head)
+ k = 0;
+ }
+ n = first; /* Output line counter */
+ for (i = k ;; i++) { /* Loop thru circular buffer */
+#ifndef MAC
+ if (typ_int) { /* Interrupted? */
+ printf("^C...\n"); /* Print message */
+ goto xxdotype;
+ }
+#endif /* MAC */
+ j = i % head; /* Index of this line */
+ s = tail[j]; /* Point to line to display */
+ if (!s) /* (shouldn't happen...) */
+ break;
+ if (paging) { /* Crudely allow for line wrap */
+ x = tlen[j];
+ if (ucs2) x /= 2;
+ x = x / cmd_cols + 1;
+ if (cmd_rows > 0 && cmd_cols > 0)
+ n += x;
+ }
+ typeline(s,tlen[j],outcs,ofp); /* Display this line */
+ if (paging && ofp == stdout) { /* Pause at end of screen */
+ if (cmd_rows > 0 && cmd_cols > 0) {
+ if (n > cmd_rows - 3) {
+ if (!askmore())
+ break;
+ else
+ n = 0;
+ }
+ }
+ }
+ tail[j] = NULL;
+ free(s); /* Free the line */
+ if (i % head == lines) /* When to stop */
+ break;
+ }
+ free((char *)tail); /* Free the list */
+ tail = NULL;
+ if (tlen) free((char *)tlen);
+ tlen = NULL;
+ }
+
+/* Come here when finished or on SIGINT */
+
+ xxdotype:
+#ifndef AMIGA
+#ifndef MAC
+ signal(SIGINT,oldsig); /* Put old signal action back. */
+#endif /* MAC */
+#endif /* AMIGA */
+ if (tailing && tail) {
+ for (i = 0; i < head; i++) { /* Free each line. */
+ if (tail[i])
+ free(tail[i]);
+ }
+ free((char *)tail); /* Free list pointer */
+ if (tlen)
+ free((char *)tlen);
+ }
+ x = zclose(ZIFILE); /* Done, close the input file */
+ if (ofp != stdout) { /* Close any output file */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ binary = save; /* Restore text/binary mode */
+#ifdef UNICODE
+ ucsbom = ucsbom_sav; /* Restore BOM usage */
+#endif /* UNICODE */
+
+#ifdef KUI
+ if ( gui )
+ gui_text_popup_wait(-1); /* Wait for user to close the dialog */
+#endif /* KUI */
+ return(rc);
+}
+
+/* GREP command */
+
+#define GREP_CASE 0 /* /CASE */
+#define GREP_COUN 1 /* /COUNT */
+#define GREP_DOTF 2 /* /DOTFILES */
+#define GREP_NAME 3 /* /NAMEONLY */
+#define GREP_NOBK 4 /* /NOBACKUP */
+#define GREP_NODO 5 /* /NODOTFILES */
+#define GREP_NOLI 6 /* /NOLIST */
+#define GREP_NOMA 7 /* /INVERT = /NOMATCH */
+#define GREP_NOPA 8 /* /NOPAGE */
+#define GREP_NUMS 9 /* /LINENUMBERS */
+#define GREP_PAGE 10 /* /PAGE */
+#define GREP_RECU 11 /* /RECURSIVE */
+#define GREP_TYPE 12 /* /TYPE: */
+#define GREP_OUTP 13 /* /OUTPUTFILE: */
+#define GREP_EXCP 14 /* /EXCEPT: */
+
+static struct keytab greptab[] = {
+ { "/count", GREP_COUN, CM_ARG },
+ { "/dotfiles", GREP_DOTF, 0 },
+ { "/except", GREP_EXCP, CM_ARG },
+ { "/linenumbers", GREP_NUMS, 0 },
+ { "/nameonly", GREP_NAME, 0 },
+ { "/nobackupfiles",GREP_NOBK, 0 },
+ { "/nocase", GREP_CASE, 0 },
+ { "/nodotfiles", GREP_NODO, 0 },
+ { "/nolist", GREP_NOLI, 0 },
+ { "/nomatch", GREP_NOMA, 0 },
+ { "/nopage", GREP_NOPA, 0 },
+ { "/output", GREP_OUTP, CM_ARG },
+ { "/page", GREP_PAGE, 0 },
+ { "/quiet", GREP_NOLI, CM_INV },
+#ifdef RECURSIVE
+ { "/recursive", GREP_RECU, 0 },
+#endif /* RECURSIVE */
+ { "/type", GREP_TYPE, CM_ARG },
+ { "", 0, 0 }
+};
+static int ngreptab = sizeof(greptab)/sizeof(struct keytab)-1;
+
+static char * grep_except = NULL;
+
+int
+dogrep() {
+ int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0;
+ int fline = 0, sline = 0, wild = 0, len = 0;
+ int xmode = -1, scan = 0;
+ char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
+ FILE * fp = NULL;
+
+ int /* Switch values and defaults */
+ gr_coun = 0,
+ gr_name = 0,
+ gr_nobk = 0,
+ gr_case = 1,
+ gr_noli = 0,
+ gr_noma = 0,
+ gr_nums = 0,
+ gr_excp = 0,
+ gr_page = xaskmore;
+
+ struct FDB sw, fl;
+
+ g_matchdot = matchdot; /* Save global matchdot setting */
+ outfile[0] = NUL;
+ makestr(&grep_except,NULL);
+
+ if (ofp != stdout) { /* In case of previous interruption */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "String or pattern to search for, or switch",
+ "", /* default */
+ "", /* addtl string data */
+ ngreptab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ greptab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring, /* xxstring */
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if ((cmresult.nresult != GREP_COUN) && !getval &&
+ (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case GREP_COUN: {
+ gr_coun++;
+ if (getval) {
+ if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
+ return(x);
+ makestr(&cv,s);
+ }
+ break;
+ }
+ case GREP_CASE: gr_case=0; break;
+ case GREP_NAME: gr_name++; gr_noli=0; break;
+ case GREP_NOBK: gr_nobk++; break;
+ case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break;
+ case GREP_NOMA: gr_noma++; break;
+ case GREP_NOPA: gr_page=0; break;
+ case GREP_NUMS: gr_nums++; gr_noli=0; break;
+ case GREP_PAGE: gr_page++; gr_noli=0; break;
+ case GREP_NODO:
+ matchdot = 0;
+ break;
+ case GREP_DOTF:
+ matchdot = 1;
+ break;
+#ifdef RECURSIVE
+ case GREP_RECU:
+ recursive = 1;
+ break;
+#endif /* RECURSIVE */
+ case GREP_TYPE: {
+ extern struct keytab txtbin[];
+ if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
+ return(x);
+ if (x == 2) { /* ALL */
+ xmode = -1;
+ } else { /* TEXT or BINARY only */
+ xmode = x;
+ scan = 1;
+ }
+ break;
+ }
+ case GREP_OUTP: /* Send output to file */
+ if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(outfile,s,CKMAXPATH);
+ break;
+ case GREP_EXCP: /* Exception pattern */
+ if (getval) {
+ if ((x = cmfld("Exception pattern",
+ "",
+ &s,
+ xxstring
+ )) < 0)
+ return(x);
+ gr_excp++;
+ makestr(&grep_except,s);
+ }
+ }
+ }
+ if (outfile[0]) {
+ ofp = fopen(outfile,"w"); /* Open output file */
+ if (!ofp) {
+ printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
+ ofp = stdout;
+ return(-9);
+ }
+ gr_page = 0;
+ }
+ s = cmresult.sresult;
+ s = brstrip(s); /* Strip braces from pattern */
+ if (!*s) {
+ printf("?Pattern required\n");
+ return(-9);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save pattern */
+ if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?File specification required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ s = brstrip(s); /* Strip braces from filename */
+#ifndef ZXREWIND
+ ckstrncpy(line,s,LINBUFSIZ);
+#endif /* ZXREWIND */
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+ if (gr_page > -1)
+ xaskmore = gr_page; /* Paging... */
+
+ p = tmpbuf; /* Point to pattern */
+#ifdef COMMENT
+/* Now this is done in ckmatch */
+ if (*p == '^') { /* '^' anchors pattern to beginning */
+ p++;
+ } else if (*p != '*') { /* Otherwise prepend implied '*' */
+ tmpbuf[0] = '*';
+ p = tmpbuf;
+ }
+ x = strlen(p); /* Get length of result */
+ if (x > 0 && x < TMPBUFSIZ) { /* '$' at end anchors pattern to end */
+ if (p[x-1] == '$') {
+ p[x-1] = NUL;
+ } else if (p[x-1] != '*') {
+ p[x] = '*';
+ p[x+1] = NUL;
+ }
+ }
+#endif /* COMMENT */
+ debug(F111,"grep pat",p,x);
+
+#ifdef ZXREWIND
+ fc = zxrewind(); /* Rewind the file list */
+#else
+ {
+ int flags = ZX_FILONLY; /* Expand file list */
+ if (matchdot) flags |= ZX_MATCHDOT;
+ if (recursive) flags |= ZX_RECURSE;
+ fc = nzxpand(line,flags);
+ }
+#endif /* ZXREWIND */
+#ifdef UNIX
+ sh_sort(mtchs,NULL,fc,0,0,filecase);
+#endif /* UNIX */
+
+ debug(F101,"grep cmd_rows","",cmd_rows);
+ debug(F101,"grep cmd_cols","",cmd_cols);
+
+ while (1) { /* Loop for each file */
+ znext(name); /* Get next file */
+ if (!name[0]) /* No more, done */
+ break;
+ if (gr_nobk) /* Skipping backup files? */
+ if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */
+ continue; /* Yes, skip */
+ if (scan) { /* /TYPE: given? */
+ switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */
+ case FT_BIN:
+ if (xmode != 1)
+ continue;
+ break;
+ case FT_TEXT:
+ case FT_7BIT:
+ case FT_8BIT:
+#ifdef UNICODE
+ case FT_UTF8:
+ case FT_UCS2:
+#endif /* UNICODE */
+ if (xmode != 0)
+ continue;
+ }
+ }
+ fp = fopen(name,"r"); /* Open */
+ if (!fp) /* Can't */
+ continue; /* Skip */
+ count = 0; /* Match count, this file */
+ fline = 0; /* Line count, this file */
+ while (1) { /* Loop for each line */
+ if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */
+ fclose(fp);
+ fp = NULL;
+ debug(F100,"GREP EOF","",0);
+ break;
+ }
+ fline++; /* Count this line */
+ line[LINBUFSIZ] = NUL; /* Make sure it's terminated */
+ debug(F111,"GREP",line,fline);
+ len = (int)strlen(line); /* Get length */
+ while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
+ line[--len] = NUL; /* Chop off terminators */
+ match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
+ if (match && gr_excp) {
+ if (ckmatch(grep_except,line,gr_case,1+4))
+ match = 0;
+ }
+ if (gr_noma) /* Invert match sense if requested */
+ match = !match;
+ if (match) { /* Have a matching line */
+ mc++; /* Total match count */
+ count++; /* Match count this file */
+ if (gr_name) { /* Don't care how many lines match */
+ fclose(fp); /* Close the file */
+ fp = NULL; /* and quit the line-reading loop. */
+ break;
+ }
+ if (gr_coun || gr_noli) /* Not listing each line */
+ continue; /* so don't print anything now. */
+ if (wild) { /* If searching multiple files */
+ fprintf(ofp,"%s:",name); /* print filename. */
+ len += (int)strlen(name) + 1;
+ }
+ if (gr_nums) { /* If line numbers wanted */
+ char nbuf[32];
+ len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
+ fprintf(ofp,"%s",nbuf);
+ }
+ if (cmd_rows > 0 && cmd_cols > 0)
+ sline += (len / cmd_cols) + 1;
+ fprintf(ofp,"%s\n",line); /* Print the line. */
+ if (sline > cmd_rows - 3) {
+ if (!askmore()) goto xgrep; else sline = 0;
+ }
+ }
+ }
+ if (!gr_noli) { /* If not not listing... */
+ x = 0;
+ if (gr_coun) { /* Show match count only */
+ fprintf(ofp,"%s:%d\n",name,count);
+ x++;
+ } else if (gr_name && count > 0) { /* Show name only */
+ fprintf(ofp,"%s\n",name);
+ x++;
+ }
+ if (x > 0) {
+ if (++sline > cmd_rows - 3) {
+ if (!askmore()) goto xgrep; else sline = 0;
+ }
+ }
+ }
+ bigcount += count; /* Overall count */
+ }
+ xgrep:
+#ifndef NOSPL
+ if (gr_coun && cv) { /* /COUNT:blah */
+ addmac(cv,ckitoa(bigcount)); /* set the variable */
+ makestr(&cv,NULL); /* free this */
+ }
+#endif /* NOSPL */
+ if (fp) fclose(fp); /* close input file if still open */
+ if (ofp != stdout) { /* Close any output file */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ return(success = mc ? 1 : 0);
+}
+
+/* System-independent directory */
+
+static char ** dirlist = NULL;
+static int ndirlist = 0;
+
+static VOID
+freedirlist() {
+ if (dirlist) {
+ int i;
+ for (i = 0; i < ndirlist; i++) {
+ if (dirlist[i])
+ free(dirlist[i]);
+ }
+ free((char *)dirlist);
+ dirlist = NULL;
+ }
+ ndirlist = 0;
+}
+
+static struct keytab dirswtab[] = { /* DIRECTORY command switches */
+ { "/after", DIR_AFT, CM_ARG },
+ { "/all", DIR_ALL, 0 },
+#ifndef NOSPL
+ { "/array", DIR_ARR, CM_ARG },
+#endif /* NOSPL */
+ { "/ascending", DIR_ASC, 0 },
+ { "/backup", DIR_BUP, 0 },
+ { "/before", DIR_BEF, CM_ARG },
+ { "/brief", DIR_BRF, 0 },
+ { "/count", DIR_COU, CM_ARG },
+ { "/descending", DIR_DSC, CM_INV },
+ { "/directories", DIR_DIR, 0 },
+ { "/dotfiles", DIR_DOT, 0 },
+ { "/englishdate", DIR_DAT, 0 },
+ { "/except", DIR_EXC, CM_ARG },
+ { "/files", DIR_FIL, 0 },
+ { "/heading", DIR_HDG, 0 },
+ { "/isodate", DIR_ISO, 0 },
+ { "/larger-than", DIR_LAR, CM_ARG },
+#ifdef CKSYMLINK
+ { "/followlinks", DIR_LNK, 0 },
+#endif /* CKSYMLINK */
+ { "/message", DIR_MSG, CM_ARG },
+ { "/nobackupfiles",DIR_NOB, 0 },
+ { "/nodotfiles", DIR_NOD, 0 },
+#ifdef CKSYMLINK
+ { "/nofollowlinks",DIR_NLK, 0 },
+#endif /* CKSYMLINK */
+ { "/noheading", DIR_NOH, 0 },
+#ifdef CKSYMLINK
+ { "/nolinks", DIR_NOL, 0 },
+#endif /* CKSYMLINK */
+ { "/nomessage", DIR_NOM, 0 },
+#ifdef CK_TTGWSIZ
+ { "/nopage", DIR_NOP, 0 },
+#endif /* CK_TTGWSIZ */
+#ifdef RECURSIVE
+ { "/norecursive", DIR_NOR, 0 },
+#else
+#ifdef VMS
+ { "/norecursive", DIR_NOR, 0 },
+#else
+#ifdef datageneral
+ { "/norecursive", DIR_NOR, 0 },
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* RECURSIVE */
+ { "/nosort", DIR_NOS, 0 },
+ { "/not-after", DIR_NAF, CM_ARG },
+ { "/not-before", DIR_NBF, CM_ARG },
+ { "/not-since", DIR_NAF, CM_INV|CM_ARG },
+ { "/noxfermode", DIR_NOT, 0 },
+ { "/output", DIR_OUT, CM_ARG },
+#ifdef CK_TTGWSIZ
+ { "/page", DIR_PAG, 0 },
+#endif /* CK_TTGWSIZ */
+#ifdef RECURSIVE
+ { "/recursive", DIR_REC, 0 },
+#else
+#ifdef VMS
+ { "/recursive", DIR_REC, 0 },
+#else
+#ifdef datageneral
+ { "/recursive", DIR_REC, 0 },
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* RECURSIVE */
+ { "/reverse", DIR_DSC, 0 },
+ { "/since", DIR_AFT, CM_ARG|CM_INV },
+ { "/smaller-than",DIR_SMA, CM_ARG },
+ { "/sort", DIR_SRT, CM_ARG },
+ { "/summary", DIR_SUM, 0 },
+ { "/top", DIR_TOP, CM_ARG },
+ { "/type", DIR_BIN, CM_ARG },
+ { "/xfermode", DIR_TYP, 0 },
+ { "/verbose", DIR_VRB, 0 },
+ { "",0,0 }
+};
+static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
+
+static struct keytab dirsort[] = { /* DIRECTORY /SORT: options */
+ { "date", DIRS_DT, 0 },
+ { "name", DIRS_NM, 0 },
+ { "size", DIRS_SZ, 0 }
+};
+static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
+
+static int dir_date = -1; /* Option defaults (-1 means none) */
+static int dir_page = -1;
+static int dir_verb = 1;
+static int dir_msg = -1;
+#ifdef VMS
+static int dir_sort = -1; /* Names are already sorted in VMS */
+static int dir_rvrs = -1;
+#else
+static int dir_sort = 1; /* Sort by default */
+static int dir_rvrs = 0; /* Not in reverse */
+#endif /* VMS */
+static int dir_skey = DIRS_NM; /* By name */
+#ifdef RECURSIVE
+static int dir_recu = -1;
+#endif /* RECURSIVE */
+static int dir_mode = -1;
+static int dir_show = -1; /* Show all files by default */
+int dir_dots = -1; /* Except dot files */
+int dir_back = 1;
+int dir_head = 0;
+static char * dirmsg = NULL;
+static int dirmsglen = 0;
+
+#ifndef NOSHOW
+VOID
+showdiropts() {
+ int x = 0;
+ extern int optlines;
+ prtopt(&optlines,"DIRECTORY");
+ if (dir_show > 0) {
+ prtopt(&optlines,(dir_show == 1) ? "/FILES" :
+ ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
+ x++;
+ } else {
+ prtopt(&optlines,"/ALL");
+ x++;
+ }
+ if (dir_verb > -1) {
+ prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
+ x++;
+ }
+ if (dir_page > -1) {
+ prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
+ x++;
+ }
+ if (dir_date > -1) {
+ prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
+ x++;
+ }
+ if (dir_dots > -1) {
+ prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
+ x++;
+ }
+ if (dir_back > -1) {
+ prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
+ x++;
+ }
+ if (dir_head > -1) {
+ prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
+ x++;
+ }
+#ifdef RECURSIVE
+ if (dir_recu > -1) {
+ prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
+ x++;
+ }
+#endif /* RECURSIVE */
+ if (dir_mode > -1) {
+ prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
+ x++;
+ }
+ if (dir_sort == 0) {
+ x++;
+ prtopt(&optlines,"/NOSORT ");
+ } else if (dir_sort > 0) {
+ x++;
+ if (dir_skey == DIRS_NM) s = "/SORT:NAME";
+ else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
+ else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
+ prtopt(&optlines,s);
+ }
+ if (dir_rvrs > -1) {
+ prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
+ x++;
+ }
+ if (dir_msg > -1) {
+ if (dir_msg == 0) {
+ prtopt(&optlines,"/NOMESSAGE");
+ } else {
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL);
+ prtopt(&optlines,tmpbuf);
+ }
+ x++;
+ }
+ if (!x) prtopt(&optlines,"(no options set)");
+ prtopt(&optlines,"");
+}
+#endif /* NOSHOW */
+
+int
+setdiropts() { /* Set DIRECTORY option defaults */
+ int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
+ int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
+ int getval;
+ char c;
+ while (1) {
+ if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
+ if (y == -3)
+ break;
+ else
+ return(y);
+ }
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (y) {
+ case DIR_BRF: xv = 0; break;
+ case DIR_VRB: xv = 1; break;
+ case DIR_PAG: xp = 1; break;
+ case DIR_NOP: xp = 0; break;
+ case DIR_ISO: xd = 0; break;
+ case DIR_DAT: xd = 1; break;
+ case DIR_HDG: xh = 1; break;
+ case DIR_NOH: xh = 0; break;
+ case DIR_DOT: xf = 1; break;
+ case DIR_NOD: xf = 0; break;
+ case DIR_ALL: xa = 3; break;
+ case DIR_DIR: xa = 2; break;
+ case DIR_FIL: xa = 1; break;
+ case DIR_SRT:
+ x = DIRS_NM;
+ if (getval)
+ if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
+ return(x);
+ xk = x;
+ xs = 1;
+ break;
+ case DIR_NOS: xs = 0; break;
+ case DIR_ASC: xx = 0; break;
+ case DIR_DSC: xx = 1; break;
+ case DIR_REC: xr = 1; break;
+ case DIR_NOR: xr = 0; break;
+ case DIR_TYP: xm = 1; break;
+ case DIR_NOT: xm = 0; break;
+ case DIR_BUP: xb = 1; break;
+ case DIR_NOB: xb = 0; break;
+ case DIR_NOM: xg = 0; break;
+ case DIR_MSG:
+ if (getval)
+ if ((x = cmfld("Message to append to each line",
+ "",
+ &s,
+ xxstring
+ )) < 0)
+ return(x);
+ xg = 1;
+ ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+ break;
+ default:
+ printf("?This option can not be set\n");
+ return(-9);
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (xv > -1) dir_verb = xv; /* Confirmed, save defaults */
+ if (xp > -1) dir_page = xp;
+ if (xd > -1) dir_date = xd;
+ if (xh > -1) dir_head = xh;
+ if (xs > -1) dir_sort = xs;
+ if (xk > -1) dir_skey = xk;
+ if (xx > -1) dir_rvrs = xx;
+ if (xf > -1) dir_dots = xf;
+ if (xa > -1) dir_show = xa;
+ if (xm > -1) dir_mode = xm;
+ if (xb > -1) dir_back = xb;
+#ifdef RECURSIVE
+ if (xr > -1) dir_recu = xr;
+#endif /* RECURSIVE */
+ if (xg > -1) dir_msg = xg;
+ if (xg > 0)
+ makestr(&dirmsg,tmpbuf);
+ return(success = 1);
+}
+
+int
+domydir(cx) int cx; { /* Internal DIRECTORY command */
+ extern char *months[];
+#ifdef VMS
+ _PROTOTYP( char * zrelname, (char *,char *) );
+ char * cdp = NULL;
+#endif /* VMS */
+
+ char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
+ char linebuf[CKMAXPATH+256];
+ char * mstr = NULL, * dstr = NULL, * s2 = NULL, * cv = NULL;
+ CK_OFF_T len = (CK_OFF_T)0, nbytes = (CK_OFF_T)0;
+ CK_OFF_T minsize = (CK_OFF_T)-1, maxsize = (CK_OFF_T)-1;
+ long ndirs = 0, nfiles = 0, nmatches = 0;
+ int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0;
+ int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
+ int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
+ int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
+ int touch = 0;
+ int fs = 0;
+ int multiple = 0;
+ int cmifn1 = 1, cmifn2 = 0;
+ int dir_top = 0, dir_cou = 0;
+ int dontshowlinks = 0;
+ int dontfollowlinks = 0;
+ int arrayindex = -1;
+ struct FDB sw, fi, fl;
+ char dbuf[32], xbuf[32];
+
+#ifndef NOSPL
+ char array = NUL;
+ char ** ap = NULL;
+#endif /* NOSPL */
+ char
+ * dir_aft = NULL,
+ * dir_bef = NULL,
+ * dir_naf = NULL,
+ * dir_nbf = NULL,
+ * dir_exc = NULL;
+ char * xlist[16];
+
+ debug(F101,"domydir cx","",cx);
+
+ g_matchdot = matchdot; /* Save global matchdot setting */
+#ifdef COMMENT
+ nolinks = 2; /* (it should already be 2) */
+#endif /* COMMENT */
+ outfile[0] = NUL; /* No output file yet */
+
+ if (ofp != stdout) { /* In case of previous interruption */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ for (i = 0; i < 16; i++) xlist[i] = NULL;
+
+ dir_top = 0;
+ name[0] = NUL;
+ freedirlist(); /* In case not freed last time */
+ page = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
+ engdate = dir_date > -1 ? dir_date : 0;
+ verbose = dir_verb > -1 ? dir_verb : 1;
+ heading = dir_head > -1 ? dir_head : 0;
+ xsort = dir_sort > -1 ? dir_sort : 0;
+ sortby = dir_skey > -1 ? dir_skey : 0;
+ reverse = dir_rvrs > -1 ? dir_rvrs : 0;
+ msg = dir_msg > -1 ? dir_msg : 0;
+#ifdef UNIXOROSK
+ if (dir_dots > -1) matchdot = dir_dots;
+#endif /* UNIXOROSK */
+ xfermod = dir_mode > -1 ? dir_mode : 0;
+ backup = dir_back > -1 ? dir_back : 1;
+#ifdef RECURSIVE
+ recursive = dir_recu > -1 ? dir_recu : 0;
+#endif /* RECURSIVE */
+ show = dir_show > -1 ? dir_show : 3;
+
+ if (cx == XXWDIR) { /* WDIRECTORY */
+ debug(F100,"domydir WDIRECTORY","",0);
+ reverse = 1; /* Reverse chronological order */
+ xsort = 1;
+ sortby = DIRS_DT;
+ } else if (cx == XXHDIR) { /* HDIRECTORY */
+ debug(F100,"domydir HDIRECTORY","",0);
+ reverse = 1; /* Reverse order by size */
+ xsort = 1;
+ sortby = DIRS_SZ;
+ } else if (cx == XXTOUC) {
+ touch = 1;
+ verbose = 0;
+ }
+
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ ttgcwsz(); /* Screen length for more-prompting */
+#else /* OS2 */
+ /* Check whether window size changed */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ diractive = 1;
+ cmifn1 = nolinks | 1; /* 1 = files or directories */
+ cmifn2 = 0; /* 0 = not directories only */
+
+ again:
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Enter or Return to confirm the command, or\n\
+ file specification, or switch",
+ "", /* default */
+ "", /* addtl string data */
+ ndirswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ dirswtab, /* Keyword table */
+ &fi /* Pointer to next FDB */
+ );
+ cmfdbi(&fi, /* 2nd FDB - filespec to match */
+ _CMIFI, /* fcode */
+ "File specification", /* hlpmsg */
+#ifdef datageneral
+ "+", /* Default filespec is wildcard */
+#else /* that matches all files... */
+#ifdef VMS
+ "*.*",
+#else
+ "*",
+#endif /* VMS */
+#endif /* datageneral */
+ "", /* addtl string data */
+ cmifn1,
+ cmifn2, /* 1 = only dirs; 0 files or dirs */
+ xxstring,
+ NULL,
+ &fl
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"domydir cmfdb","",x);
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ k = cmresult.nresult;
+ if (!getval &&
+ (cmgkwflgs() & CM_ARG) && k != DIR_TOP && k != DIR_COU) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (k) {
+ case DIR_COU: {
+ dir_cou++;
+ if (getval) {
+ if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
+ return(x);
+ makestr(&cv,s);
+ }
+ break;
+ }
+ case DIR_BRF: verbose = 0; break;
+ case DIR_VRB: verbose = 1; break;
+#ifdef CK_TTGWSIZ
+ case DIR_PAG: page = 1; break;
+ case DIR_NOP: page = 0; break;
+#endif /* CK_TTGWSIZ */
+ case DIR_ISO: engdate = 0; break;
+ case DIR_DAT: engdate = 1; break;
+ case DIR_HDG: heading = 1; break;
+ case DIR_NOH: heading = 0; break;
+#ifdef UNIXOROSK
+ case DIR_DOT: matchdot = 1; break;
+ case DIR_NOD: matchdot = 0; break;
+#endif /* UNIXOROSK */
+ case DIR_ALL:
+ show = 3;
+ cmifn1 |= 1;
+ cmifn2 = 0;
+ goto again;
+ case DIR_DIR:
+ show = 2;
+ cmifn1 |= 1;
+ cmifn2 = 1;
+ goto again;
+ case DIR_FIL:
+ show = 1;
+ cmifn1 &= ~(1);
+ cmifn2 = 0;
+ goto again;
+ case DIR_SRT:
+ x = DIRS_NM;
+ if (c == ':' || c == '=')
+ if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
+ return(x);
+ xsort = 1;
+ sortby = x;
+ break;
+
+ case DIR_BUP: backup = 1; fs++; break;
+ case DIR_NOB: backup = 0; fs++; break;
+
+ case DIR_NOS: xsort = 0; break;
+ case DIR_ASC: reverse = 0; break;
+ case DIR_DSC: reverse = 1; break;
+#ifdef RECURSIVE
+ case DIR_REC: recursive = 1; diractive = 1; break;
+ case DIR_NOR: recursive = 0; diractive = 0; break;
+#endif /* RECURSIVE */
+ case DIR_TYP: xfermod = 1; break;
+ case DIR_NOT: xfermod = 0; break;
+
+#ifdef CKSYMLINK
+ case DIR_LNK: /* Follow links */
+#ifdef COMMENT
+ /* A command switch shouldn't be setting a global value! */
+ nolinks = 0;
+#endif /* COMMENT */
+ cmifn1 &= ~(2);
+ dontfollowlinks = 0;
+ goto again;
+ case DIR_NLK: /* Don't follow links */
+#ifdef COMMENT
+ nolinks = 2;
+#endif /* COMMENT */
+ cmifn1 &= ~(2);
+ dontfollowlinks = 1;
+ goto again;
+ case DIR_NOL: /* Don't show links at all */
+ dontshowlinks = 1;
+ goto again;
+#endif /* CKSYMLINK */
+
+ case DIR_NOM: msg = 0; break;
+ case DIR_MSG:
+ if (c == ':' || c == '=')
+ if ((x = cmfld("Message to append to each line",
+ "",
+ &s,
+ xxstring
+ )) < 0)
+ return(x);
+ msg = 1;
+ ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+ break;
+
+ case DIR_SMA:
+ case DIR_LAR: {
+ CK_OFF_T y;
+ if (!getval) break;
+ if ((x = cmnumw("File size in bytes","0",10,&y,xxstring)) < 0)
+ return(x);
+ fs++;
+ show = 1;
+ switch (cmresult.nresult) {
+ case DIR_SMA: minsize = y; break;
+ case DIR_LAR: maxsize = y; break;
+ }
+ break;
+ }
+ case DIR_TOP:
+ dir_top = 10;
+ if (!getval) break;
+ if ((x = cmnum("How many lines to show","10",10,&y,xxstring))< 0)
+ return(x);
+ dir_top = y;
+ break;
+
+#ifndef NOSPL
+ case DIR_ARR:
+ if (c != ':' && c != '=') {
+ printf("?Array name required\n");
+ return(-9);
+ }
+ if ((x = cmfld("Array name (a single letter will do)",
+ "",
+ &s,
+ NULL
+ )) < 0) {
+ if (x == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ if (!*s) {
+ printf("?Array name required\n");
+ return(-9);
+ }
+ s2 = s;
+ if (*s == CMDQ) s++;
+ if (*s == '&') s++;
+ if (!isalpha(*s)) {
+ printf("?Bad array name - \"%s\"\n",s2);
+ return(-9);
+ }
+ array = *s++;
+ if (isupper(array)) array = tolower(array);
+ if (*s && (*s != '[' || *(s+1) != ']')) {
+ printf("?Bad array name - \"%s\"\n",s2);
+ return(-9);
+ }
+ break;
+#endif /* NOSPL */
+ case DIR_AFT:
+ case DIR_BEF:
+ case DIR_NAF:
+ case DIR_NBF:
+ if (!getval) break;
+ if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Date-time required\n");
+ rc = -9;
+ } else
+ rc = x;
+ goto xdomydir;
+ }
+ fs++;
+ switch (k) {
+ case DIR_AFT: makestr(&dir_aft,s); break;
+ case DIR_BEF: makestr(&dir_bef,s); break;
+ case DIR_NAF: makestr(&dir_naf,s); break;
+ case DIR_NBF: makestr(&dir_nbf,s); break;
+ }
+ break;
+ case DIR_EXC:
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ rc = -9;
+ } else
+ rc = x;
+ goto xdomydir;
+ }
+ fs++;
+ makestr(&dir_exc,s);
+ break;
+
+ case DIR_SUM:
+ summary = 1; break;
+
+ case DIR_BIN: {
+ extern struct keytab txtbin[];
+ extern int xfiletype;
+ if (!getval) break;
+ if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) {
+ rc = x;
+ goto xdomydir;
+ }
+ if (x == 2) {
+ xfiletype = -1;
+ } else {
+ xfiletype = x;
+ fs = 1;
+ }
+ break;
+ }
+ case DIR_OUT:
+ if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(outfile,s,CKMAXPATH+1);
+ break;
+
+ default:
+ printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
+ goto xdomydir;
+ }
+ }
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
+
+/* ^^^ START MULTIPLE */
+
+ while (!touch) {
+ x = cmfld("Another filespec or Enter","",&s,xxstring);
+ if (x == -3)
+ break;
+ if (x < 0)
+ return(x);
+ ckstrncat(line,",",LINBUFSIZ);
+ ckstrncat(line,s,LINBUFSIZ);
+ multiple++;
+ }
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL);
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ cmresult.nresult = 1;
+ cmresult.fcode = _CMIFI;
+
+/* ^^^ END MULTIPLE */
+
+ s = line;
+
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+
+/*
+ Command is TOUCH and file doesn't exist.
+*/
+ if (touch) { /* TOUCH */
+ if ((cmresult.fcode == _CMIFI && zchki(s) == (CK_OFF_T)-1)) {
+ FILE * fp;
+ s = brstrip(s);
+ if (!iswild(s)) {
+#ifdef UNIX
+ if (s[0] == '~')
+ s = tilde_expand(s);
+#endif /* UNIX */
+ fp = fopen(s,"w"); /* Create file */
+ if (!fp) {
+ printf("?TOUCH %s: %s\n",s,ck_errstr());
+ rc = -9;
+ goto xdomydir;
+ }
+ fclose(fp);
+ cx = XXDIR; /* Now maybe list it. */
+ multiple++; /* Force new directory scan */
+ }
+ }
+ } else
+
+ if (cmresult.fcode != _CMIFI) { /* Nothing matched */
+ /*
+ Note - this never gets executed because after the "begin
+ multiple" hack above, the result is always _CMIFI).
+ */
+ char * m;
+ if (*s == '/')
+#ifdef UNIXOROSK
+ m = "does not match switch or name of accessible file";
+#else
+#ifdef OS2
+ m = "does not match switch or name of accessible file";
+#else
+ m = "no switches match";
+#endif /* OS2 */
+#endif /* UNIXOROSX */
+ else
+ m = "not found or not accessible";
+ printf("\"%s\" - %s\n",s,m);
+ rc = -9;
+ goto xdomydir;
+ }
+#ifdef COMMENT
+ /* This can't be right because it's based on _CMCFM */
+ wild = cmresult.nresult; /* Wildcard was given? */
+ debug(F111,"domydir cmifi2",s,wild);
+#else
+ wild = 0;
+#endif /* COMMENT */
+
+ if (outfile[0]) { /* If an output file was specified */
+ ofp = fopen(outfile,"w"); /* open it */
+ if (!ofp) {
+ printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
+ ofp = stdout;
+ return(-9);
+ }
+ page = 0;
+ }
+
+#ifdef OS2
+ if (!wild) {
+ if (zchki(s) == -2) { /* Found a directory */
+ p = s + (int)strlen(s) - 1; /* Yes */
+ if (*p == '\\' || *p == '/')
+ strcat(s, "*");
+ else if (*p == ':')
+ strcat(s, "./*");
+ else
+ strcat(s, "/*");
+ wild = 1; /* Now it's wild */
+ }
+ }
+#else
+ if (!wild) if (isdir(s)) { /* Is it a directory? */
+ p = s + (int)strlen(s) - 1; /* Yes */
+#ifdef VMS
+ {
+ /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
+ char buf[CKMAXPATH+1];
+ debug(F000,"domydir directory 0",s,*p);
+ if (cvtdir(s,buf,CKMAXPATH) > 0)
+ ckstrncpy(line,buf,LINBUFSIZ);
+ }
+#endif /* VMS */
+ debug(F000,"domydir directory 1",s,*p);
+#ifdef VMS
+ if (*p == ']' || *p == '>' || *p == ':')
+ strcat(s, "*.*");
+#else
+#ifdef datageneral
+ if (*p == ':')
+ strcat(s, "+");
+ else
+ strcat(s, ":+");
+#else
+#ifdef STRATUS
+ if (*p == '>')
+ strcat(s, "*");
+ else
+ strcat(s, ">*");
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+ wild = 1; /* Now it's wild */
+ debug(F000,"domydir directory 2",s,*p);
+ }
+#endif /* OS2 */
+
+#ifdef ZXREWIND
+/* cmifi() already called nzxpand so we can just re-use the same list. */
+ if (!multiple) {
+ x = zxrewind(); /* Rewind the list */
+ debug(F111,"domydir zxrewind",s,x);
+ } else {
+#endif /* ZXREWIND */
+/*
+ In case we gave multiple filespecs they are now in {a,b,c} list format.
+ Which is a valid wildcard. We pass it to nzxpand() to get back the list
+ of files that match. This is fine for DIRECTORY but it's not find for
+ TOUCH because we want TOUCH to see those names so it can create the files.
+ So for now at least, if TOUCH is to be used to create files -- as opposed
+ to changing the timestamps of existing files -- it can only do one file
+ at a time.
+*/
+ nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
+ (show == ZX_FILONLY ? ZX_FILONLY : 0);
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ x = nzxpand(s,nzxopts); /* Expand file list */
+ debug(F111,"domydir nzxpand",s,x);
+#ifdef ZXREWIND
+ }
+#endif /* ZXREWIND */
+
+#ifndef NOSPL
+ if (array) {
+ int n, xx;
+ n = (x < 0) ? 0 : x;
+ if ((xx = dclarray(array,n)) < 0) {
+ printf("?Array declaration failure\n");
+ rc = -9;
+ goto xdomydir;
+ }
+ arrayindex = xx;
+ ap = a_ptr[xx]; /* Pointer to list of elements */
+ if (ap) /* Set element 0 to dimension */
+ makestr(&(ap[0]),"0"); /* which so far is zero */
+ if (n < 1) { /* No files matched, done. */
+ rc = 0;
+ goto xdomydir;
+ }
+ } else
+#endif /* NOSPL */
+ if (!touch && x < 1) {
+#ifdef CKROOT
+ extern int ckrooterr;
+ if (ckrooterr)
+ printf("?Off limits: %s\n",s);
+ else
+#endif /* CKROOT */
+ if (x == 0 && isdir(s))
+ printf("?Empty directory - \"%s\"\n", s);
+ else
+ printf("?%s %s match - \"%s\"\n",
+ (x == 0) ? "No" : "Too many",
+ (show == 2) ? "directories" : "files",
+ brstrip(s)
+ );
+ rc = -9;
+ goto xdomydir;
+ }
+ nx = x; /* Remember how many files */
+ if (nx < 2) xsort = 0; /* Skip sorting if none or one */
+
+ if (msg) {
+ makestr(&dirmsg,tmpbuf);
+ dirmsglen = strlen(tmpbuf);
+ }
+
+#ifdef VMS
+ cdp = zgtdir(); /* Get current directory */
+ debug(F110,"domydir VMS zgtdir",cdp,0);
+#endif /* VMS */
+
+ if (xsort && verbose) { /* If sorting, allocate space */
+ if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
+ if (!quiet) {
+ printf("* Warning: Failure to allocate memory for sorting.\n");
+ printf("* Will proceed without sorting...\n");
+ }
+ xsort = 0;
+ }
+ debug(F101,"domydir sort malloc","",xsort);
+ }
+
+ /* Display the listing */
+
+#ifndef NOSPL
+ if (array) /* Storing instead of printing */
+ heading = 0;
+#endif /* NOSPL */
+
+ if (heading) { /* If /HEADING print heading */
+ zfnqfp(s,TMPBUFSIZ,tmpbuf);
+ fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf);
+ n += 3;
+ }
+ if (page > -1) /* Paging */
+ xaskmore = page;
+
+ if (!verbose && !touch) { /* /BRIEF */
+ if (outfile[0]) { /* To file */
+ int k = 0;
+ znext(name);
+ while (name[0]) { /* One line per file */
+ k++;
+ if (fs) if (fileselect(name,
+ dir_aft,dir_bef,dir_naf,dir_nbf,
+ minsize,maxsize,!backup,16,xlist) < 1) {
+ znext(name);
+ continue;
+ }
+ fprintf(ofp,"%s\n",name);
+ znext(name);
+ }
+ if (heading)
+ fprintf(ofp,"Files: %d\n\n",k);
+ rc = 1;
+ goto xdomydir;
+ } else {
+ rc = xfilhelp(x,"","",n,0,1,
+ dir_aft,dir_bef,dir_naf,dir_nbf,
+ minsize,maxsize,!backup,16,xlist);
+ if (rc < 0)
+ goto xdomydir;
+ if (heading && rc > 0)
+ fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */
+ rc = 1;
+ goto xdomydir;
+ }
+ }
+ ndirs = nfiles = 0L; /* Initialize counters */
+ nbytes = (CK_OFF_T)0;
+
+ if (dir_exc) /* Have exception list? */
+ makelist(dir_exc,xlist,16); /* Yes, convert to array */
+
+ diractive = 1;
+ znext(name); /* Get next file */
+ while (name[0]) { /* Loop for each file */
+ if (fs) if (fileselect(name,
+ dir_aft,dir_bef,dir_naf,dir_nbf,
+ minsize,maxsize,!backup,16,xlist) < 1) {
+ znext(name);
+ continue;
+ }
+ len = zgetfs(name); /* Get file length */
+ debug(F111,"domydir zgetfs",name,len);
+#ifdef VMSORUNIX
+ itsadir = zgfs_dir; /* See if it's a directory */
+#else
+ itsadir = (len == (CK_OFF_T)-2 || isdir(name));
+#endif /* VMSOUNIX */
+ debug(F111,"domydir itsadir",name,itsadir);
+ if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
+ znext(name);
+ continue;
+ }
+ /* Get here when we know we have selected this file */
+
+ nmatches++;
+ if (itsadir) { /* Accumulate totals for summary */
+ ndirs++;
+ } else {
+ nfiles++;
+ nbytes += len;
+ }
+ dstr = NULL;
+ if (cx == XXTOUC) { /* Command was TOUCH, not DIRECTORY */
+ char * filename;
+ struct zattr xx;
+ dstr = ckcvtdate("",0);
+ xx.date.val = dstr;
+ xx.date.len = (int)strlen(xx.date.val);
+ xx.lprotect.len = 0;
+ debug(F110,"domydir touch",name,0);
+ debug(F110,"domydir touch",dstr,0);
+ if (zstime(name,&xx,0) < 0) {
+ printf("?TOUCH %s: %s\n",name,ck_errstr());
+ rc = -9;
+ goto xdomydir;
+ }
+ if (!verbose) { /* No listing so skip detail */
+ znext(name);
+ continue;
+ }
+ }
+ if (summary) { /* Summary only, no detail */
+ znext(name);
+ continue;
+ }
+
+#ifndef NOSPL
+ if (array) {
+ debug(F111,"domydir array",name,nfiles);
+ if (ap)
+ makestr(&(ap[nmatches]),name);
+ znext(name);
+ continue;
+ }
+#endif /* NOSPL */
+
+/*
+ NOTE: The sprintf's in this routine should be safe. They involve
+ permission strings, date/time strings, and filenames, all of which have
+ known maximum lengths; none of these items is input from users. The
+ destination buffers are large enough to hold maximum sizes for any and
+ all items. NOTE 2: If command was TOUCH, dstr was already set just
+ above.
+*/
+ if (!dstr) { /* Get file's modification date/time */
+ dstr = zfcdat(name);
+ debug(F111,"domydir zcfdat",dstr,0);
+ }
+ if (!dstr) dstr = "";
+ {
+/*
+ Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings
+ about possible out-of-bounds dstr[] array refs do not apply. This block of
+ code is to stifle the warnings and also allows for any out-of-spec
+ zfcdat() implementations.
+*/
+ int x;
+ char * p = "00000000 00:00:00";
+ x = ckstrncpy(xbuf,dstr,32);
+ if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x);
+ dstr = xbuf;
+ }
+ if (engdate) { /* English date requested? */
+ short month, day, year, hour, minute, seconds;
+ month = (dstr[4]-48)*10 + (dstr[5]-48);
+ mstr = (month > 0 && month <= 12) ? months[month-1] : "xxx";
+ day = (dstr[6]-48)*10 + (dstr[7]-48);
+ year = (((dstr[0]-48)*10 +
+ (dstr[1]-48))*10 +
+ (dstr[2]-48))*10 +
+ (dstr[3]-48);
+ hour = (dstr[9]-48)*10 + (dstr[10]-48);
+ minute = (dstr[12]-48)*10 + (dstr[13]-48);
+ seconds = (dstr[15]-48)*10 + (dstr[16]-48);
+ sprintf(dbuf, /* SAFE */
+ "%2d-%s-%4d %02d:%02d:%02d",
+ day,mstr,year,hour,minute,seconds
+ );
+ dstr = dbuf;
+ } else { /* ISO date */
+ dbuf[0] = dstr[0]; /* yyyy */
+ dbuf[1] = dstr[1];
+ dbuf[2] = dstr[2];
+ dbuf[3] = dstr[3];
+ dbuf[4] = '-';
+ dbuf[5] = dstr[4]; /* mm (numeric) */
+ dbuf[6] = dstr[5];
+ dbuf[7] = '-';
+ dbuf[8] = dstr[6]; /* dd */
+ dbuf[9] = dstr[7];
+ strcpy(dbuf+10,dstr+8); /* hh:mm:ss */
+ dstr = dbuf;
+ }
+ dlen = strlen(dbuf); /* Length of date */
+ name[CKMAXPATH] = NUL;
+#ifdef CK_PERMS
+#ifdef VMSORUNIX
+ p = ziperm(name); /* Get permissions */
+ debug(F110,"ziperm perms",p,0);
+#else
+ p = zgperm(name);
+ debug(F110,"zgperm perms",p,0);
+#endif /* VMSORUNIX */
+#else
+ p = NULL;
+ debug(F110,"NULL perms",p,0);
+#endif /* CK_PERMS */
+
+#ifdef VMS
+ /* Get relative name to save space -- VMS fullnames are long... */
+ ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
+#endif /* VMS */
+
+ if (itsadir && len < (CK_OFF_T)0) { /* Directory */
+#ifdef VMS
+ sprintf(linebuf,"%-22s%-10s %s %s",p,"<DIR>",dstr,name);
+#else
+ if (p)
+ sprintf(linebuf,"%10s%-10s %s %s",p,"<DIR>",dstr,name);
+ else
+ sprintf(linebuf,"%-10s %s %s", "<DIR>", dstr, name);
+#endif /* VMS */
+ } else { /* Regular file */
+#ifdef VMS
+ sprintf(linebuf,"%-22s%10s %s %s", p, ckfstoa(len), dstr, name);
+#else
+ if (p)
+ sprintf(linebuf,"%10s%10s %s %s", p, ckfstoa(len), dstr, name);
+ else
+ sprintf(linebuf,"%10s %s %s", ckfstoa(len), dstr, name);
+#endif /* VMS */
+ }
+#ifdef UNIX
+#ifdef CKSYMLINK
+ if (zgfs_link) { /* If it's a symlink */
+ if (dontshowlinks) { /* If /NOLINKS don't show it */
+ znext(name);
+ continue;
+ }
+ }
+ if (zgfs_link && !dontfollowlinks) { /* Symlink and following links */
+ int n, m; /* Show what the link points to */
+ extern char linkname[];
+ n = strlen(linebuf);
+ m = strlen(linkname) + n;
+ if (m < CKMAXPATH + 58)
+ strcpy(linebuf+n, " -> "); /* safe (checked) */
+ if (m + 4 < CKMAXPATH - 58)
+ strcpy(linebuf+n+4, linkname); /* safe (checked) */
+ } else
+#endif /* CKSYMLINK */
+#endif /* UNIX */
+ if (xfermod) { /* Show transfer mode */
+ int i, x, y;
+ char * s = "";
+ y = -1;
+ x = scanfile(name,&y,nscanfile);
+ switch (x) {
+ case FT_TEXT: s = " (T)"; break;
+ case FT_7BIT: s = " (T)(7BIT)"; break;
+ case FT_8BIT: s = " (T)(8BIT)"; break;
+#ifdef UNICODE
+ case FT_UTF8: s = " (T)(UTF8)"; break;
+ case FT_UCS2:
+ s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)";
+ break;
+#endif /* UNICODE */
+ case FT_BIN: s = " (B)"; break;
+ }
+ if (!*s) {
+ s = binary ? " (B)" : " (T)";
+ }
+ if (*s) {
+ int n;
+ n = strlen(linebuf);
+ if (n + 4 < CKMAXPATH - 58)
+ strcpy(linebuf+n, s); /* safe (checked) */
+ }
+ }
+ if (msg && dirmsg) {
+ int n;
+ n = strlen(linebuf);
+ if (n + dirmsglen + 2 < CKMAXPATH)
+ sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */
+ }
+ if (xsort) { /* Sorting - save line */
+ i = strlen(linebuf);
+ if ((ndirlist >= nx) ||
+ !(dirlist[ndirlist] = (char *)malloc(i+1))) {
+ printf("?Memory allocation error - try /NOSORT\n");
+ rc = -9;
+ goto xdomydir;
+ }
+ strcpy(dirlist[ndirlist],linebuf); /* safe */
+ ndirlist++;
+ }
+ znext(name); /* Peek ahead to next file */
+ if (!xsort) {
+ if (!touch || (touch && verbose))
+ fprintf(ofp,"%s\n",linebuf);
+ if (page && (name[0] || heading)) { /* If /PAGE */
+ if (cmd_cols > 0) {
+ int x = strlen(linebuf);
+ int y;
+ y = (x % cmd_cols) ? 1 : 0;
+ n += x / cmd_cols + y;
+ } else {
+ n++;
+ }
+#ifdef CK_TTGWSIZ
+ if (n > (cmd_rows - 3)) { /* Do more-prompting */
+ if (!askmore()) {
+ rc = 0;
+ goto xdomydir;
+ } else
+ n = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ }
+ }
+#ifndef NOSPL
+ if (array) {
+ if (ap)
+ makestr(&(ap[0]),ckitoa(nmatches));
+ rc = 1;
+ goto xdomydir;
+ }
+#endif /* NOSPL */
+ if (xsort) {
+ int namepos;
+ skey = 0;
+#ifdef VMS
+ namepos = dlen + 35;
+ switch (sortby) {
+ case DIRS_NM: skey = namepos; break;
+ case DIRS_DT: skey = 33; break;
+ case DIRS_SZ: skey = 21;
+ }
+#else
+ if (p) {
+ namepos = dlen + 24;
+ switch (sortby) {
+ case DIRS_NM: skey = namepos; break;
+ case DIRS_DT: skey = 22; break;
+ case DIRS_SZ: skey = 10;
+ }
+ } else {
+ namepos = dlen + 14;
+ switch (sortby) {
+ case DIRS_NM: skey = namepos; break;
+ case DIRS_DT: skey = 12; break;
+ case DIRS_SZ: skey = 0;
+ }
+ }
+#endif /* VMS */
+ sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
+ if (dir_top > 0 && dir_top < ndirlist)
+ ndirlist = dir_top;
+ for (i = 0; i < ndirlist; i++) {
+ fprintf(ofp,"%s\n",dirlist[i]);
+ if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */
+ if (cmd_cols > 0) {
+ int x = strlen(dirlist[i]);
+ int y;
+ y = (x % cmd_cols) ? 1 : 0;
+ n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
+ } else {
+ n++;
+ }
+#ifdef CK_TTGWSIZ
+ if (n > (cmd_rows - 3)) { /* Do more-prompting */
+ if (!askmore()) {
+ rc = 0;
+ goto xdomydir;
+ } else
+ n = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ }
+ }
+
+ if (heading || summary) {
+#ifdef CKFLOAT
+ CKFLOAT gm;
+#endif /* CKFLOAT */
+ fprintf(ofp,"\n%ld director%s, %ld file%s, %s byte%s",
+ ndirs,
+ (ndirs == 1) ? "y" : "ies",
+ nfiles,
+ (nfiles == 1) ? "" : "s",
+ ckfstoa(nbytes),
+ (nbytes == 1) ? "" : "s"
+ );
+#ifdef CKFLOAT
+ gm = ((CKFLOAT) nbytes ) / 1000000.0;
+ if (gm > 1000.0)
+ fprintf(ofp," (%0.2fGB)",(gm / 1000.0));
+ else if (gm >= 0.01)
+ fprintf(ofp," (%0.2fMB)",gm);
+#endif /* CKFLOAD */
+ fprintf(ofp,"\n\n");
+ } else if (dir_cou && !cv) {
+ fprintf(ofp,"\n Files: %ld\n\n",nfiles);
+ }
+ xdomydir:
+#ifndef NOSPL
+ if (dir_cou && cv) { /* /COUNT:var */
+ addmac(cv,ckitoa(nfiles)); /* set the variable */
+ makestr(&cv,NULL); /* free this */
+ }
+ if (ap) { /* If we have a result array */
+ if (a_dim[arrayindex] > nmatches) /* but it was not filled */
+ a_dim[arrayindex] = nmatches; /* adjust dimension */
+ }
+#endif /* NOSPL */
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot; /* Restore these... */
+ g_matchdot = -1;
+ }
+ freedirlist();
+ if (ofp != stdout) { /* Close any output file */
+ if (ofp) fclose(ofp);
+ ofp = stdout;
+ }
+ if (rc > 0)
+ success = 1;
+ return(rc);
+}
+
+int
+dodir(cx) int cx; { /* Do the DIRECTORY command */
+ char *dc , *msg;
+
+#ifdef OS2
+ return(domydir(cx));
+#else /* OS2 */
+ if (nopush
+#ifdef DOMYDIR /* Builds that domydir() by default */
+ || (cx == XXDIR || cx == XXLDIR || cx == XXWDIR ||
+ cx == XXHDIR || cx == XXTOUC)
+#endif /* DOMYDIR */
+ )
+ return(domydir(cx)); /* Built-in directory command */
+
+ /* Use the system's directory command. */
+
+ msg = (cx == XXLS) ?
+ "Arguments for ls" :
+ "Directory and/or file specification";
+ if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
+ return(x);
+
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy the filespec */
+ s = tmpbuf;
+
+ if ((y = cmcfm()) < 0) return(y);
+
+ lp = line;
+ if (!(dc = getenv("CK_DIR")))
+ dc = DIRCMD;
+ ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL);
+ debug(F110,"DIR",line,0);
+#ifdef VMS
+ conres();
+#endif /* VMS */
+ x = zshcmd(line);
+#ifdef VMS
+ concb((char)escape);
+#endif /* VMS */
+ return(success = (x < 1) ? 0 : 1);
+#endif /* OS2 */
+}
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+/* Do the ENABLE and DISABLE commands */
+
+int
+doenable(y,x) int y, x; {
+#ifdef CK_LOGIN
+ if (isguest) /* IKSD: Don't let guests */
+ return(0); /* enable anything that's disabled */
+#endif /* CK_LOGIN */
+ switch (x) {
+ case EN_ALL:
+ en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
+ en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
+ if (!inserver)
+ en_who = en_mai = en_pri = y;
+ en_mkd = en_rmd = y;
+ en_xit = y;
+#ifndef datageneral
+ en_bye = y;
+#endif /* datageneral */
+#ifndef NOPUSH
+ if (!nopush && !inserver)
+ en_hos = y;
+#endif /* NOPUSH */
+#ifndef NOSPL
+ en_asg = en_que = y;
+#endif /* NOSPL */
+ break;
+
+ case EN_BYE:
+#ifndef datageneral
+/*
+ In Data General AOS/VS Kermit can't log out its superior process.
+*/
+ en_bye = y;
+#endif /* datageneral */
+ break;
+ case EN_CPY:
+ en_cpy = y;
+ break;
+ case EN_CWD:
+ en_cwd = y;
+#ifdef IKSD
+ if (inserver && y == 0) {
+ fnrpath = PATH_OFF;
+ fnspath = PATH_OFF;
+ }
+#endif /* IKSD */
+ break;
+ case EN_DEL: /* Deleting of files */
+ en_del = y;
+ break;
+ case EN_DIR:
+ en_dir = y;
+ break;
+ case EN_FIN:
+ en_fin = y;
+ break;
+ case EN_GET:
+ en_get = y;
+ break;
+#ifndef NOPUSH
+ case EN_HOS:
+ if (!nopush)
+ en_hos = y;
+ break;
+#endif /* NOPUSH */
+ case EN_REN:
+ en_ren = y;
+ break;
+ case EN_SEN:
+ en_sen = y;
+ break;
+ case EN_SET:
+ en_set = y;
+ break;
+ case EN_SPA:
+ en_spa = y;
+ break;
+ case EN_TYP:
+ en_typ = y;
+ break;
+ case EN_WHO:
+ en_who = y;
+ break;
+#ifndef NOSPL
+ case EN_ASG:
+ en_asg = y;
+ break;
+ case EN_QUE:
+ en_que = y;
+ break;
+#endif /* NOSPL */
+ case EN_RET:
+ en_del = y;
+ break;
+ case EN_MAI:
+#ifdef CK_LOGIN
+ if (isguest && y) {
+ printf("?Sorry, not valid for guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+ en_mai = y;
+ break;
+ case EN_PRI:
+#ifdef CK_LOGIN
+ if (isguest && y) {
+ printf("?Sorry, not valid for guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+ en_pri = y;
+ break;
+ case EN_MKD:
+ en_mkd = y;
+ break;
+ case EN_RMD:
+ en_rmd = y;
+ break;
+ case EN_XIT:
+ en_xit = y;
+ break;
+ case EN_ENA:
+ if (((y & 1) && !(en_ena & 1)) ||
+ ((y & 2) && !(en_ena & 2))) {
+ printf("?Sorry, DISABLE ENABLE can not be undone\n");
+ return(-9);
+ } else {
+ en_ena = y;
+ break;
+ }
+ default:
+ return(-2);
+ }
+ return(1);
+}
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOFRILLS
+
+static int del_lis = 0;
+static int del_dot = 0;
+static int del_hdg = 0;
+static int del_pag = -1;
+static int del_ask = 0;
+
+#ifndef NOSHOW
+VOID
+showdelopts() {
+ int x = 0;
+ extern int optlines;
+ prtopt(&optlines,"");
+ prtopt(&optlines,"DELETE");
+ if (del_ask > -1) {
+ prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
+ x++;
+ }
+#ifdef UNIXOROSK
+ if (del_dot > -1) {
+ prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
+ x++;
+ }
+#endif /* UNIXOROSK */
+ if (del_lis > -1) {
+ prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
+ x++;
+ }
+ if (del_hdg > -1) {
+ prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
+ x++;
+ }
+#ifndef CK_TTGWSIZ
+ if (del_pag > -1) {
+ prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
+ x++;
+ }
+#endif /* CK_TTGWSIZ */
+ if (!x) prtopt(&optlines,"(no options set)");
+ prtopt(&optlines,"");
+}
+#endif /* NOSHOW */
+
+
+int
+setdelopts() {
+ int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
+ int getval = 0;
+ char c;
+ while (1) {
+ if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
+ if (y == -3)
+ break;
+ else
+ return(y);
+ }
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (y) {
+ case DEL_DOT:
+ x_dot = 1;
+ break;
+ case DEL_NOD:
+ x_dot = 0;
+ break;
+ case DEL_HDG:
+ x_hdg = 1;
+ break;
+ case DEL_LIS:
+ x_lis = 1;
+ break;
+ case DEL_NOL:
+ x_lis = 0;
+ break;
+#ifndef CK_TTGWSIZ
+ case DEL_PAG:
+ x_pag = 1;
+ break;
+ case DEL_NOP:
+ x_pag = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+ case DEL_QUI:
+ x_lis = 0;
+ break;
+ case DEL_VRB:
+ x_lis = 1;
+ break;
+ case DEL_ASK:
+ x_ask = 1;
+ break;
+ case DEL_NAS:
+ x_ask = 0;
+ break;
+ default:
+ printf("?Sorry, this option can not be set\n");
+ return(-9);
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (x_pag > -1) del_pag = x_pag;
+ if (x_dot > -1) del_dot = x_dot;
+ if (x_hdg > -1) del_hdg = x_hdg;
+ if (x_lis > -1) del_lis = x_lis;
+ if (x_ask > -1) del_ask = x_ask;
+ return(success = 1);
+}
+
+#ifdef OS2
+static char ** xmtchs = NULL;
+static int xmtchn = 0;
+#endif /* OS2 */
+
+int
+dodel() { /* DELETE */
+ int i, j, k, x;
+ int fs = 0; /* Need to call fileselect() */
+ int len = 0;
+ int bad = 0;
+ int getval = 0, asking = 0;
+ int simulate = 0, rc = 0;
+ CK_OFF_T minsize = -1L, maxsize = -1L;
+ int havename = 0, confirmed = 0;
+ int qflag = 0;
+ int summary = 0;
+ int deldirs = 0;
+ int deltree = 0;
+ int itsadir = 0;
+ int argisdir = 0;
+ int xmode = -1, scan = 0, skip = 0;
+#ifdef COMMENT
+ int pass = 0;
+#endif /* COMMENT */
+ char c;
+ char * deldef = "";
+ char safebuf[CKMAXPATH+1];
+ struct FDB sw, fi, fl;
+ char
+ * del_aft = NULL,
+ * del_bef = NULL,
+ * del_naf = NULL,
+ * del_nbf = NULL,
+ * del_exc = NULL;
+ int
+ x_lis = 0,
+ /* x_dot = -1, */
+ x_hdg = 0;
+
+ char * dxlist[8];
+
+ for (i = 0; i < 8; i++) dxlist[i] = NULL;
+
+ g_matchdot = matchdot;
+
+ if (del_lis > -1) x_lis = del_lis;
+ if (del_dot > -1) matchdot = del_dot;
+ if (del_hdg > -1) x_hdg = del_hdg;
+ if (del_pag > -1) xaskmore = del_pag;
+ if (del_ask > -1) asking = del_ask;
+
+ diractive = 1;
+ nolinks = 2; /* By default don't follow links */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "File specification;\n or switch",
+ "", /* default */
+ "", /* addtl string data */
+ ndeltab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ deltab, /* Keyword table */
+ &fi /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ again:
+ cmfdbi(&fi, /* 2nd FDB - file to delete */
+ _CMIFI, /* fcode */
+ "File(s) to delete", /* hlpmsg */
+ deldef, /* default */
+ "", /* addtl string data */
+ nolinks | deldirs, /* 0 = files, 1 = files or dirs */
+ 0, /* 1 = dirs only */
+ xxstring,
+ NULL,
+ &fl
+ );
+ while (!havename && !confirmed) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) { /* Error */
+ if (x == -3)
+ break;
+ if (x == -2 || x == -9)
+ printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
+ return(x);
+ }
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk(); /* Get break character */
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ rc = -9;
+ goto xdelete;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ rc = -9;
+ goto xdelete;
+ }
+ switch (k = cmresult.nresult) {
+ case DEL_AFT:
+ case DEL_BEF:
+ case DEL_NAF:
+ case DEL_NBF:
+ if (!getval) break;
+ if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Date-time required\n");
+ x = -9;
+ } else
+ rc = x;
+ goto xdelete;
+ }
+ fs++;
+ deltree = 0;
+ switch (k) {
+ case DEL_AFT: makestr(&del_aft,s); break;
+ case DEL_BEF: makestr(&del_bef,s); break;
+ case DEL_NAF: makestr(&del_naf,s); break;
+ case DEL_NBF: makestr(&del_nbf,s); break;
+ }
+ break;
+ case DEL_DOT:
+ matchdot = 1;
+ break;
+ case DEL_NOD:
+ matchdot = 0;
+ break;
+ case DEL_ALL:
+ fs = 0;
+#ifdef VMS
+ deldef = "*.*"; /* UNIX, Windows, OS/2 */
+#else
+#ifdef datageneral
+ deldef = "+"; /* AOS/VS */
+#else
+ deldef = "*"; /* UNIX, Windows, OS/2, VMS... */
+#endif /* datageneral */
+#endif /* VMS */
+ deltree = 1;
+ nolinks = 2;
+ matchdot = 1;
+ recursive = 1; /* Fall through purposely... */
+ case DEL_DIR:
+ deldirs = 1;
+ goto again;
+ case DEL_EXC:
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ x = -9;
+ } else
+ rc = x;
+ goto xdelete;
+ }
+ fs++;
+ deltree = 0;
+ makestr(&del_exc,s);
+ break;
+ case DEL_HDG:
+ x_hdg = 1;
+ break;
+#ifdef RECURSIVE
+ case DEL_REC:
+ recursive = 1;
+ break;
+#endif /* RECURSIVE */
+ case DEL_LIS:
+ x_lis = 1;
+ break;
+ case DEL_SUM:
+ summary = 1;
+ x_lis = 0;
+ x_hdg = 1;
+ break;
+ case DEL_NOL:
+ x_lis = 0;
+ break;
+#ifndef CK_TTGWSIZ
+ case DEL_PAG:
+ xaskmore = 1;
+ break;
+ case DEL_NOP:
+ xaskmore = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+ case DEL_QUI:
+ qflag = 1;
+ x_lis = 0;
+ break;
+ case DEL_VRB:
+ x_lis = 1;
+ break;
+
+ case DEL_SMA:
+ case DEL_LAR:
+ if (!getval) break;
+ if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
+ return(x);
+ fs++;
+ deltree = 0;
+ switch (cmresult.nresult) {
+ case DEL_SMA: minsize = y; break;
+ case DEL_LAR: maxsize = y; break;
+ }
+ break;
+
+ case DEL_SIM:
+ simulate = 1;
+ x_lis = 1;
+ break;
+ case DEL_ASK:
+ asking = 1;
+ break;
+ case DEL_NAS:
+ asking = 0;
+ break;
+ case DEL_TYP: {
+ extern struct keytab txtbin[];
+ if (!getval) break;
+ if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
+ return(x);
+ if (x == 2) { /* ALL */
+ xmode = -1;
+ } else { /* TEXT or BINARY only */
+ xmode = x;
+ scan = 1;
+ }
+ break;
+ }
+ default:
+ printf("?Not implemented yet - \"%s\"\n",atmbuf);
+ return(-9);
+ }
+ }
+ if (qflag && (cmresult.fcode == _CMFLD)) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ else
+ return(success = 0);
+ }
+ if (cmresult.fcode != _CMIFI) {
+ if (*atmbuf) {
+ int x;
+ if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
+ printf("?No files match: %s\n",brstrip(atmbuf));
+ else if ((x = zchki(atmbuf)) == -1)
+ printf("?File not found: %s\n",brstrip(atmbuf));
+ else if (x == -2)
+ printf("?Not a regular file: %s\n",atmbuf);
+ else
+ /* printf("?Not a deletable file: %s\n",atmbuf); */
+ goto tryanyway;
+ } else {
+ printf("?A file specification is required\n");
+ }
+ return(-9);
+ }
+ tryanyway:
+ ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
+ if (deldirs) {
+ ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH);
+#ifdef VMSORUNIX
+ len = zgetfs(tmpbuf); /* Is it a directory name? */
+ argisdir = zgfs_dir; /* Then because of how zxpand() */
+ if (argisdir && zgfs_link) /* works, we have to add it to */
+ argisdir = 0; /* the list. */
+ if (itsadir)
+ len = -2;
+#else
+ len = zchki(tmpbuf);
+ if (len < 0)
+ argisdir = isdir(tmpbuf);
+#endif /* VMSORUNIX */
+ }
+ debug(F110,"DELETE file",tmpbuf,0);
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest) {
+ printf("?Sorry, DELETE unavailable to guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+#ifndef OS2ORUNIX
+ if (simulate) {
+ printf("?Sorry, /SIMULATE not implemented on this platform\n");
+ return(-9);
+ }
+#endif /* OS2ORUNIX */
+
+#ifdef COMMENT
+ /* (not needed) */
+ if (!iswild(tmpbuf)) {
+ char *m;
+ errno = 0;
+ x = zchki(tmpbuf);
+ if (x < 0) {
+ switch (x) {
+ case -2: m = "Not a regular file"; break;
+ case -1: m = "File not found or not accessible"; break;
+ default: m = errno ? ck_errstr() : "Can't delete";
+ }
+ printf("?%s: \"%s\"\n",m,tmpbuf);
+ return(-9);
+ }
+ }
+#endif /* COMMENT */
+
+ makelist(del_exc,dxlist,8);
+
+/* tmpbuf[] has the name - now do any needed conversions on it */
+
+#ifdef OS2
+ { /* Lower level functions change / to \, not good for CMD.EXE. */
+ char *p = tmpbuf;
+ while (*p) { /* Change them back to \ */
+ if (*p == '/') *p = '\\';
+ p++;
+ }
+ }
+#endif /* OS2 */
+
+#ifdef VMS
+ if (iswild(tmpbuf)) {
+#ifdef COMMENT
+ /* Does not handle '.' as version separator */
+ char *p = tmpbuf;
+ x = 0;
+ while (*p) {
+ if (*p == ';') {
+ x = 1;
+ break;
+ } else
+ p++;
+ }
+ if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ);
+#else
+ j = 0; x = 0; /* for end_dot and number of dots */
+ i = strlen(tmpbuf);
+ if (tmpbuf[i] == ';') {
+ ckstrncat(tmpbuf,"0",TMPBUFSIZ);
+ } else {
+ if (tmpbuf[i--] == '.')
+ j++;
+ for (; i >= 0; i--) {
+ if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
+ tmpbuf[i] == ']' || tmpbuf[i] == '>')
+ break;
+ else if (tmpbuf[i] == '.')
+ x++;
+ }
+ if (tmpbuf[i] != ';') { /* dot may have been used */
+ if (j) { /* last char is dot */
+ if (x) /* second is version separator */
+ ckstrncat(tmpbuf,"0",TMPBUFSIZ);
+ else /* 'foo.' */
+ ckstrncat(tmpbuf,";0",TMPBUFSIZ);
+ } else if (x == 1) /* lacking a version separator */
+ ckstrncat(tmpbuf,";0",TMPBUFSIZ);
+ else if (x == 0) /* x == 2 has a version */
+ ckstrncat(tmpbuf,".*;0",TMPBUFSIZ);
+ }
+ }
+#endif /* COMMENT */
+ }
+#endif /* VMS */
+
+ debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
+
+#ifndef OS2ORUNIX /* No built-in DELETE code... */
+ /* Construct system command. */
+ ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL);
+#else
+#ifdef VMS
+ if (asking) { /* Maybe overwrite in VMS */
+ if (x_lis) /* if options are needed... */
+ ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL);
+ else
+ ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL);
+ } else if (x_lis)
+ ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL);
+ conres();
+#endif /* VMS */
+
+ debug(F110,"dodel line",line,0);
+#endif /* OS2ORUNIX */
+
+#ifdef MAC
+ success = (zdelet(tmpbuf) == 0);
+
+#else /* !MAC ... */
+
+#ifdef OS2ORUNIX
+ {
+ int filespace = 0;
+ int count = 0;
+ int lines = 0;
+ int n = 0;
+
+ s = tmpbuf;
+
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ ttgcwsz();
+#else /* OS2 */
+ /* Check whether window size changed */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ if (x_hdg > 0 && !summary) {
+ printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
+ n += 2;
+ }
+#ifdef ZXREWIND
+ z = zxrewind(); /* Rewind file list */
+#else
+ if (!deldirs)
+ nzxopts = ZX_FILONLY;
+ if (recursive) nzxopts |= ZX_RECURSE;
+ if (matchdot) nzxopts |= ZX_MATCHDOT;
+ errno = 0;
+ z = nzxpand(s,nzxopts); /* Expand file list */
+#endif /* ZXREWIND */
+ debug(F111,"dodel",s,z);
+
+ /* If deleting directories, sort in reverse order */
+ /* so we delete the files first, then the directory. */
+
+#ifdef OS2
+ /* In K95, we have no mtchs array, nor any control over */
+ /* the order in which znext() returns filenames, so we */
+ /* must copy the array and sort it. */
+ {
+ int i;
+ if (xmtchs) { /* Free previous list in case */
+ debug(F101,"dodel freeing previous list","",xmtchn);
+ for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */
+ if (xmtchs[i])
+ free(xmtchs[i]);
+ free(xmtchs);
+ }
+ xmtchn = 0;
+ xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */
+ if (!xmtchs) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ for (i = 0; i < z; i++) {
+ xmtchs[i] = NULL;
+ znext(tmpbuf);
+ if (!*tmpbuf)
+ break;
+ makestr(&(xmtchs[i]),tmpbuf);
+ if (!xmtchs[i]) {
+ printf("?Memory allocation failure\n");
+ xmtchn = i - 1;
+ rc = -9;
+ goto xdelete;
+ }
+ /* debug(F111,"dodel add",xmtchs[i],i); */
+ }
+ xmtchn = i;
+ debug(F101,"dodel xmtchn","",xmtchn);
+ sh_sort(xmtchs,NULL,z,0,deldirs,0);
+ }
+#else
+#ifdef UNIX
+ sh_sort(mtchs,NULL,z,0,deldirs,filecase);
+#endif /* UNIX */
+#endif /* OS2 */
+
+ if (z > 0) {
+ int i;
+#ifdef OS2
+ int ix = 0;
+#endif /* OS2 */
+ success = 1;
+ if (x_hdg > 0)
+ printf("\n");
+
+ while (
+#ifdef OS2
+ ix < xmtchn
+#else
+ 1
+#endif /* OS2 */
+ ) { /* Loop for all files */
+#ifdef OS2
+ ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ);
+#else
+ znext(tmpbuf); /* Get next file */
+#endif /* OS2 */
+ if (!*tmpbuf) { /* No more */
+ if (deldirs && recursive && argisdir) {
+ ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ);
+ argisdir = 0; /* (only do this once) */
+ } else
+ break;
+ }
+ skip = 0;
+ if (!deltree) {
+ if (fs)
+ if (fileselect(tmpbuf,
+ del_aft,del_bef,del_naf,del_nbf,
+ minsize,maxsize,0,8,dxlist) < 1) {
+ skip++;
+ }
+ }
+ if (!skip && scan && itsadir) {
+ skip++;
+ }
+ if (!skip && scan) {
+ switch (scanfile(tmpbuf,&y,nscanfile)) {
+ case FT_BIN:
+ if (xmode != 1)
+ skip++;
+ break;
+ case FT_TEXT:
+ case FT_7BIT:
+ case FT_8BIT:
+#ifdef UNICODE
+ case FT_UTF8:
+ case FT_UCS2:
+#endif /* UNICODE */
+ if (xmode != 0)
+ skip++;
+ }
+ }
+ if (!skip && asking) {
+ int x;
+ ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL);
+ x = getyesno(line,3);
+ switch (x) {
+ case 0: continue; /* no */
+ case 1: break; /* yes */
+ case 2: goto xdelete; /* quit */
+ case 3: asking = 0; break; /* go */
+ }
+ }
+#ifdef VMSORUNIX
+ len = zgetfs(tmpbuf); /* Get length and accessibility */
+ itsadir = zgfs_dir;
+ if (itsadir && zgfs_link) { /* Treat links to directories */
+ itsadir = 0; /* as regular files */
+ if (scan) /* But not if /TYPE: was given */
+ skip++;
+ }
+ if (itsadir) /* (emulate non-Unix code) */
+ len = -2;
+#else
+ len = zchki(tmpbuf); /* Get accessibility */
+ if (len < 0) /* See if it's a directory */
+ itsadir = isdir(tmpbuf);
+#endif /* VMSORUNIX */
+
+ if (skip) {
+#ifdef COMMENT /* Too verbose */
+ if (x_lis > 0) {
+ lines++;
+ printf(" %s (SKIPPED)\n",tmpbuf);
+#ifdef CK_TTGWSIZ
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+#endif /* CK_TTGWSIZ */
+ }
+#endif /* COMMENT */
+ continue;
+ }
+
+ debug(F111,"DELETE len",tmpbuf,len);
+ if (simulate) {
+ filespace += len;
+ count++;
+ if (x_lis > 0) {
+ lines++;
+ printf(" %s (SELECTED)\n",tmpbuf);
+ if (++n > cmd_rows - 3) {
+ int xx;
+ xx = askmore();
+ if (!xx) goto xdelete; else n = 0;
+ }
+ }
+ } else if (len >= 0 || !itsadir) { /* Regular file */
+ zdelet(tmpbuf); /* or symlink, etc... */
+ if (zchki(tmpbuf) < 0) {
+ filespace += len;
+ count++;
+ if (x_lis > 0) {
+ lines++;
+ printf(" %s (OK)\n",tmpbuf);
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+ }
+ } else {
+ bad++;
+ success = 0;
+ if (x_lis > 0) {
+ lines++;
+ printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr());
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+ }
+ }
+ } else if (/* pass > 0 && */ deldirs && itsadir) {
+ /* It's a directory */
+ if (zrmdir(tmpbuf) > -1) { /* Only works if empty */
+ count++;
+ if (x_lis > 0) {
+ lines++;
+ printf(" %s (OK)\n",tmpbuf);
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+ }
+ } else {
+ success = 0;
+ if (x_lis > 0) {
+ lines++;
+ printf(" %s (FAILED: %s)\n",
+ tmpbuf,
+ ck_errstr());
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+ }
+ }
+ } else if (x_lis > 0) {
+ lines++;
+ if (isdir(tmpbuf))
+ printf(" %s (FAILED: directory)\n",tmpbuf);
+ else
+ printf(" %s (FAILED: not a regular file)\n",tmpbuf);
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+ }
+ }
+ if (x_hdg > 0) {
+ if (lines > 0)
+ printf("\n");
+ if (++n > cmd_rows - 3)
+ if (!askmore()) goto xdelete; else n = 0;
+ printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
+ count,
+ count != 1 ? "s" : "",
+ simulate ? "would be " : "",
+ filespace,
+ filespace != 1 ? "s" : "",
+ simulate ? "would be " : "",
+ simulate ? " (maybe)" : ""
+ );
+ }
+ if (!x_lis && !success && !quiet) {
+ printf("?DELETE failed for %d file%s \
+(use DELETE /LIST to see details)\n",
+ bad, bad == 1 ? "" : "s"
+ );
+ }
+ } else if (x_lis > 0) {
+ if (errno)
+ printf("?%s: %s\n",ck_errstr(), tmpbuf);
+ else
+ printf("?Can't delete: %s\n",tmpbuf);
+ }
+ }
+#else /* OS2ORUNIX */
+#ifndef VMS /* Others - let the system do it. */
+ xsystem(line);
+ x = nzxpand(tmpbuf,nzxopts);
+ success = (x > 0) ? 0 : 1;
+ if (x_hdg > 0)
+ printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
+#else
+ if (asking)
+ printf("\n");
+ x = xsystem(line); /* zshcmd returns 1 for success */
+ success = (x > 0) ? 1 : 0;
+ if (x_hdg > 0 && !asking)
+ printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
+ concb((char)escape);
+#endif /* VMS */
+#endif /* OS2ORUNIX */
+#endif /* MAC */
+ xdelete:
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot; /* Restore these... */
+ g_matchdot = -1;
+ }
+#ifdef OS2
+ if (xmtchs) {
+ int i;
+ debug(F101,"dodel freeing list","",xmtchn);
+ for (i = 0; i < xmtchn; i++)
+ if (xmtchs[i]) free(xmtchs[i]);
+ free(xmtchs);
+ xmtchs = NULL;
+ xmtchn = 0;
+ }
+#endif /* OS2 */
+ debug(F101,"dodel result","",rc);
+ return((rc < 0) ? rc : success);
+}
+#endif /* NOFRILLS */
+
+#ifndef NOSPL /* The ELSE command */
+_PROTOTYP( VOID pushqcmd, (char *) );
+
+int
+doelse() {
+ if (!ifcmd[cmdlvl]) {
+ printf("?ELSE doesn't follow IF\n");
+ return(-2);
+ }
+#ifdef COMMENT
+/*
+ Wrong. This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
+ from working.
+*/
+ ifcmd[cmdlvl] = 0;
+#endif /* COMMENT */
+ if (!iftest[cmdlvl]) { /* If IF was false do ELSE part */
+ if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
+ debug(F100,"doelse pushing","",0);
+#ifndef COMMENT
+ pushcmd(NULL); /* save rest of command. */
+#else
+ /* This fixes certain obscure problems */
+ /* but breaks many other constructions that must work. */
+ pushqcmd(NULL);
+#endif /* COMMENT */
+ } else { /* If interactive, */
+ cmini(ckxech); /* just start a new command */
+ printf("\n"); /* (like in MS-DOS Kermit) */
+ if (pflag) prompt(xxstring);
+ }
+ } else { /* Condition is false */
+ if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
+ return(y); /* Gobble up rest of line */
+ }
+ return(0);
+}
+#endif /* NOSPL */
+
+#ifndef NOSPL
+int
+doswitch() {
+ char *lp, *ap; /* Macro argument pointer */
+ int len = 0, x, y, pp = 0;
+ char brbuf[3];
+
+ /* Get variable name */
+
+ tmpbuf[0] = NUL;
+ brbuf[0] = '{';
+ brbuf[1] = '}';
+ brbuf[2] = NUL;
+
+ y = cmfld("Variable name","",&s,xxstring);
+ debug(F111,"doswitch cmfld",s,y);
+ if (y < 0) {
+ if (y == -3) /* Because brstrip() writes */
+ s = brbuf; /* into its argument. */
+ else
+ return(y);
+ }
+ debug(F110,"doswitch A",s,0);
+ if (!strcmp(s,"(")) {
+ pp++;
+ if ((y = cmfld("Variable name","",&s,xxstring)) < 0) {
+ if (y == -3)
+ s = brbuf;
+ else
+ return(y);
+ debug(F110,"doswitch B",s,0);
+ }
+ }
+ len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+ if (tmpbuf[0] == CMDQ) {
+ if (chkvar(s) < 1) {
+ printf("?Variable name required\n");
+ return(-9);
+ }
+ }
+ if (pp > 0) { /* If open paren given parse closing */
+ if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
+ return(y);
+ if (strcmp(atmbuf,")")) {
+ printf("?Closing parenthesis required\n");
+ return(-9);
+ }
+ }
+ lp = line;
+ x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */
+ lp += x;
+ ap = lp;
+ debug(F010,"SWITCH a",line,0);
+
+#ifdef COMMENT
+ x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */
+#else
+ { /* variable name + SP */
+ char * p = tmpbuf;
+ if (len > 0) {
+ if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') {
+ tmpbuf[len-1] = NUL;
+ p++;
+ }
+ }
+ x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," ");
+ }
+#endif /* COMMENT */
+ debug(F010,"SWITCH b",line,0);
+ lp += x;
+
+ /* Get body */
+
+ if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
+ if ((y = (int)strlen(s)) < 1) return(-2);
+ if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
+ s = tmpbuf;
+ }
+ if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
+ printf("?Unbalanced braces\n");
+ return(0);
+ }
+ debug(F010,"SWITCH c",line,0);
+
+ x = mlook(mactab,"_switx",nmac); /* Look up SWITCH macro definition */
+ if (x < 0) { /* Not there? */
+ addmmac("_switx",sw_def); /* Put it back. */
+ if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
+ printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
+ return(success = 0);
+ }
+ }
+ debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */
+ success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC);
+ debug(F101,"SWITCH status","",success);
+ return(success);
+}
+
+int
+dofor() { /* The FOR command. */
+ int i, fx, fy, fz; /* loop variables */
+ char *ap, *di; /* macro argument pointer */
+ int pp = 0; /* Paren level */
+ int mustquote = 0;
+
+ for (i = 0; i < 2; i++) {
+ if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
+ if (y == -3) {
+ printf("?Variable name required\n");
+ return(-9);
+ } else
+ return(y);
+ }
+ if (strcmp(s,"("))
+ break;
+ pp++;
+ }
+#ifdef COMMENT
+ if ((y = parsevar(s,&x,&z)) < 0) /* Check variable. */
+ return(y);
+#else
+ if (*s == CMDQ) /* If loop variable starts with */
+ mustquote++; /* backslash, mustquote is > 0. */
+#endif /* COMMENT */
+
+ lp = line; /* Build a copy of the command */
+ ckstrncpy(lp,"_forx ",LINBUFSIZ);
+ lp += (int)strlen(line); /* "_for" macro. */
+ ap = lp; /* Save pointer to macro args. */
+
+ if (*s == CMDQ) s++; /* Skip past backslash if any. */
+ while ((*lp++ = *s++)) ; /* copy it */
+ lp--; *lp++ = SP; /* add a space */
+
+ if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
+ if (y == -3) return(-2);
+ else return(y);
+ }
+ debug(F101,"dofor fx","",fx);
+ s = atmbuf; /* Copy the atom buffer */
+
+ if ((int)strlen(s) < 1) goto badfor;
+/*
+ In edit 192, we change the loop variables to be evaluated at loop entry,
+ not each time through the loop. This was required in order to allow
+ \v(argc) to be used as a loop variable, or in a loop-variable expression.
+ Thus, we can't have FOR loops that modify their own exit conditions by
+ changing the final value or the increment. The problem with \v(argc) was
+ that it is on the macro stack; after entry into the _forx macro, it is at
+ the wrong place.
+*/
+ sprintf(tmpbuf,"%d",fx); /* (SAFE) Substitute actual value */
+ s = tmpbuf;
+ while ((*lp++ = *s++)) ; /* (what they actually typed) */
+ lp--; *lp++ = SP;
+#ifdef DEBUG
+ *lp = NUL;
+ debug(F110,"FOR A",line,0);
+#endif /* DEBUG */
+
+ if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
+ if (y == -3) return(-2);
+ else return(y);
+ }
+ debug(F101,"dofor fy","",fy);
+ s = atmbuf; /* Same deal */
+ if ((int)strlen(s) < 1)
+ goto badfor;
+
+ sprintf(tmpbuf,"%d",fy); /* SAFE */
+ s = tmpbuf;
+ while ((*lp++ = *s++)) ;
+ lp--;
+ *lp++ = SP;
+#ifdef DEBUG
+ *lp = NUL;
+ debug(F110,"FOR B",line,0);
+#endif /* DEBUG */
+
+ x_ifnum = 1; /* Increment or parenthesis */
+ di = (fx < fy) ? "1" : "-1"; /* Default increment */
+ if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
+ debug(F111,"dofor increment",atmbuf,y);
+ x_ifnum = 0;
+ if (y == -3) { /* Premature termination */
+ return(-2);
+ } else if (y == -2) { /* Maybe closing paren */
+ if (!strcmp(atmbuf,")")) {
+ pp--; /* Count it */
+ s = di; /* supply default interval */
+ fz = atoi(s);
+ } else /* Not closing paren, invalid */
+ return(y);
+ } else /* Other error */
+ return(y);
+ } else { /* Number */
+ x_ifnum = 0;
+ debug(F101,"dofor fz","",fz);
+ s = atmbuf; /* Use it */
+ }
+ if ((int)strlen(s) < 1)
+ goto badfor;
+
+ sprintf(tmpbuf,"%d",fz); /* (SAFE) Same deal */
+ s = tmpbuf;
+ while ((*lp++ = *s++)) ;
+ lp--; *lp++ = SP;
+
+#ifdef DEBUG
+ *lp = NUL;
+ debug(F110,"FOR C",line,0);
+#endif /* DEBUG */
+
+ /* Insert the appropriate comparison operator */
+ if (fz < 0)
+ *lp++ = '<';
+ else
+ *lp++ = '>';
+ *lp++ = SP;
+
+#ifdef DEBUG
+ *lp = NUL;
+ debug(F110,"FOR D",line,0);
+#endif /* DEBUG */
+
+ if (pp > 0) { /* If open paren given parse closing */
+ if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
+ return(y);
+ if (strcmp(atmbuf,")")) {
+ printf("?Closing parenthesis required\n");
+ return(-9);
+ }
+ }
+ if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
+ if ((y = (int)strlen(s)) < 1) return(-2);
+ if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
+ s = tmpbuf;
+ }
+ if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
+ printf("?Unbalanced braces\n");
+ return(0);
+ }
+#ifdef DEBUG
+ *lp = NUL;
+ debug(F110,"FOR E",line,0);
+#endif /* DEBUG */
+
+#ifdef COMMENT
+/* Too strict */
+ if (fz == 0) {
+ printf("?Zero increment not allowed\n");
+ return(0);
+ }
+#endif /* COMMENT */
+/*
+ In version 8.0 we decided to allow macro names anyplace a numeric-valed
+ variable could appear. But this caused trouble for the FOR loops because
+ the quoting in for_def[] assumed a \%i-style loop variable. We account
+ for this here in the if (mustquote)...else logic by invoking separate
+ FOR macro definitions in the two cases.
+*/
+ if (mustquote) { /* \%i-style loop variable */
+ x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */
+ if (x < 0) { /* Not there? */
+ addmmac("_forx",for_def); /* Put it back. */
+ if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
+ printf("?FOR macro definition gone!\n");
+ return(success = 0);
+ }
+ }
+ } else { /* Loop variable is a macro */
+ x = mlook(mactab,"_forz",nmac);
+ if (x < 0) {
+ addmmac("_forz",foz_def);
+ if ((x = mlook(mactab,"_forz",nmac)) < 0) {
+ printf("?FOR macro definition gone!\n");
+ return(success = 0);
+ }
+ }
+ }
+ debug(F010,"FOR command",line,0); /* Execute the FOR macro. */
+ return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
+
+badfor:
+ printf("?Incomplete FOR command\n");
+ return(-2);
+}
+#endif /* NOSPL */
+
+
+#ifndef NOSPL
+
+/* T O D 2 S E C -- Convert time of day as hh:mm:ss to secs since midnite */
+/*
+ Call with a string hh:mm or hh:mm:ss.
+ Returns a 0 to 86400 on success, or a negative number on failure.
+*/
+long
+tod2sec(t) char * t; {
+ long t2;
+ long hh = 0L, mm = 0L, ss = 0L;
+
+ if (!t) t = "";
+ if (!*t)
+ return(-3L);
+ debug(F110,"tod2sec",t,0);
+
+ if (isdigit(*t)) /* Get hours from argument */
+ hh = *t++ - '0';
+ else
+ return(-1L);
+ if (isdigit(*t))
+ hh = hh * 10 + *t++ - '0';
+#ifdef COMMENT
+ if (hh > 24L)
+ return(-1L);
+#endif /* COMMENT */
+ if (*t == ':')
+ t++;
+ else if (!*t)
+ goto xtod2sec;
+ else
+ return(-1L);
+
+ if (isdigit(*t)) /* Minutes */
+ mm = *t++ - '0';
+ else
+ return(-1L);
+ if (isdigit(*t))
+ mm = mm * 10 + *t++ - '0';
+ if (mm > 60L)
+ return(-1L);
+ if (*t == ':')
+ t++;
+ else if (!*t)
+ goto xtod2sec;
+ else
+ return(-1L);
+
+ if (isdigit(*t)) /* Seconds */
+ ss = *t++ - '0';
+ else
+ return(-1L);
+ if (isdigit(*t))
+ ss = ss * 10 + *t++ - '0';
+ if (ss > 60L)
+ return(-1L);
+
+ if (*t > 32) /* No trailing junk allowed */
+ return(-1L);
+
+ xtod2sec:
+
+ t2 = hh * 3600L + mm * 60L + ss; /* Seconds since midnight from arg */
+ debug(F101,"tod2sec t2","",t2);
+
+ return(t2);
+}
+
+int waitinterval = 1;
+
+#ifdef OLDWAIT
+#undef OLDWAIT
+#endif /* OLDWAIT */
+
+int kbchar = NUL;
+
+int
+dopaus(cx) int cx; {
+ long zz;
+ extern int sleepcan;
+
+#ifdef OLDWAIT
+ zz = -1L;
+ x_ifnum = 1; /* Turn off internal complaints */
+ if (cx == XXWAI)
+ y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
+ else if (cx == XXPAU)
+ y = cmnum("seconds to pause, or time of day hh:mm:ss",
+ "1",10,&x,xxstring);
+ else
+ y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
+ "100",10,&x,xxstring);
+ x_ifnum = 0;
+ if (y < 0) {
+ if (y == -2) { /* Invalid number or expression */
+ char *p = tmpbuf; /* Retrieve string from atmbuf */
+ int n = TMPBUFSIZ;
+ *p = NUL;
+ zzstring(atmbuf,&p,&n); /* Evaluate in case it's a variable */
+ zz = tod2sec(tmpbuf); /* Convert to secs since midnight */
+ if (zz < 0L) {
+ printf("?Number, expression, or time of day required\n");
+ return(-9);
+ } else {
+ char now[32]; /* Current time */
+ char *p;
+ long tnow;
+ p = now;
+ ztime(&p);
+ tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ if (zz < tnow) /* User's time before now */
+ zz += 86400L; /* So make it tomorrow */
+ zz -= tnow; /* Seconds from now. */
+ }
+ } else
+ return(y);
+ }
+ if (x < 0) x = 0;
+ switch (cx) {
+ case XXPAU: /* PAUSE */
+ case XXMSL: /* MSLEEP */
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case XXWAI: /* WAIT */
+ z = 0; /* Modem signal mask */
+ while (1) { /* Read zero or more signal names */
+ y = cmkey(mstab,nms,"modem signal","",xxstring);
+ if (y == -3) break; /* -3 means they typed CR */
+ if (y < 0) return(y); /* Other negatives are errors */
+ z |= y; /* OR the bit into the signal mask */
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ default: /* Shouldn't happen */
+ return(-2);
+ }
+
+/* Command is entered, now do it. */
+
+ if (zz > -1L) { /* Time of day given? */
+ x = zz;
+ if (zz != (long) x) {
+ printf(
+"Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
+ );
+ return(-9);
+ }
+ }
+ if (cx == XXMSL) { /* Millisecond sleep */
+ msleep(zz < 0 ? x : x * 1000);
+ return(success = 1);
+ }
+ if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
+ sleep(x);
+ return(success = 1);
+ }
+
+ /* WAIT, or else SLEEP with cancellation allowed... */
+
+ do { /* Sleep loop */
+ int mdmsig;
+ if (sleepcan) { /* Keyboard cancellation allowed? */
+ if (y = conchk()) { /* Did they type something? */
+#ifdef COMMENT
+ while (y--) coninc(0); /* Yes, gobble it all up */
+#else
+ /* There is a debate over whether PAUSE should absorb */
+ /* its cancelling character(s). There are several */
+ /* reasons why it should gobble at least one character: */
+ /* (1) MS-DOS Kermit does it */
+ /* (2) if not, subsequent PAUSE commands will terminate */
+ /* immediately */
+ /* (3) if not, subsequent ASK commands will use it as */
+ /* valid input. If \13, then it will get no input */
+ /* (4) if not, then the character appears on the command */
+ /* line after all enclosing macros are complete. */
+ kbchar = coninc(0); /* Gobble one up */
+#endif /* COMMENT */
+ break; /* And quit PAUSing or WAITing */
+ }
+ }
+ if (cx == XXWAI) { /* WAIT (z == modem signal mask) */
+ debug(F101,"WAIT x","",x);
+ if (z > 0) { /* Looking for any modem signals? */
+ mdmsig = ttgmdm(); /* Yes, get them */
+ if (mdmsig < 0) /* Failed */
+ return(success = 0);
+ if ((mdmsig & z) == z) /* Got what we wanted? */
+ return(success = 1); /* Succeed */
+ }
+ if (x == 0) /* WAIT 0 and didn't get our signals */
+ break;
+ }
+ sleep(1); /* No interrupt, sleep one second */
+ } while (--x > 0);
+
+ if (cx == XXWAI) /* If WAIT and loop exhausted */
+ success = (z == 0); /* Fail. */
+ else /* */
+ success = (x == 0); /* Set SUCCESS/FAILURE for PAUSE. */
+ return(success);
+
+#else /* New code uses chained FDBs and allows FILE waits... */
+
+ char * m = ""; /* Help message */
+ struct FDB nu, fl; /* Parse function descriptor blocks */
+ int filewait = 0;
+ int mdmsig = 0, fs = 0;
+ char filedate[32];
+
+ kbchar = 0;
+
+ switch (cx) {
+ case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
+ case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
+ case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
+ }
+ zz = -1L;
+ cmfdbi(&nu,
+ _CMNUM, /* Number */
+ m, /* Help message */
+ (cx == XXMSL) ? "100" : "1", /* Default */
+ "", /* N/A */
+ 0, /* N/A */
+ 0, /* N/A */
+ xxstring, /* Processing function */
+ NULL, /* N/A */
+ &fl /* Next */
+ );
+ cmfdbi(&fl, /* Time of day */
+ _CMFLD, /* Field */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring, /* processing func */
+ NULL, /* N/A */
+ NULL /* No next */
+ );
+ x = cmfdb(&nu); /* Parse a number or a field */
+ if (x < 0) {
+ if (x == -3)
+ x = -2;
+ return(x);
+ }
+ switch (cmresult.fcode) {
+ case _CMNUM: /* Number */
+ x = cmresult.nresult;
+ break;
+ case _CMFLD: /* Field */
+ zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */
+ if (zz < 0L) {
+ printf("?Number, expression, or time of day required\n");
+ return(-9);
+ } else {
+ char now[32]; /* Current time */
+ char *p;
+ long tnow;
+ p = now;
+ ztime(&p);
+ tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ if (zz < tnow) /* User's time before now */
+ zz += 86400L; /* So make it tomorrow */
+ zz -= tnow; /* Seconds from now. */
+ }
+ }
+ debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
+ switch (cx) {
+ case XXPAU: /* PAUSE */
+ case XXMSL: /* MSLEEP */
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case XXWAI: /* WAIT */
+ z = 0; /* Modem signal mask */
+ y = cmkey(waittab,nwaittab,"","",xxstring);
+ if (y < 0) {
+ if (y == -3) {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ break;
+ } else
+ return(y);
+ }
+ if (y == WAIT_FIL) { /* FILE */
+ int wild = 0;
+ if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
+ return(z);
+ filewait = z;
+ if (filewait == WF_MOD || filewait == WF_DEL)
+ z = cmifi("Filename","",&s,&wild,xxstring);
+ else
+ z = cmfld("Filename","",&s,xxstring);
+ if (z < 0)
+ return(z);
+ if (wild || ((filewait == WF_CRE) && iswild(s))) {
+ printf("?Wildcards not valid here\n");
+ return(-9);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ break;
+ } else if (y != WAIT_MDM) { /* A modem signal */
+ z |= y; /* OR the bit into the signal mask */
+ }
+ if (!filewait) { /* Modem signals... */
+ while (1) { /* Get zero or more signal names */
+ y = cmkey(mstab,nms,"modem signal","",xxstring);
+ if (y == -3) break; /* -3 means they typed CR */
+ if (y < 0) return(y); /* Other negatives are errors */
+ z |= y; /* OR the bit into the signal mask */
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ }
+
+ default: /* Shouldn't happen */
+ return(-2);
+ } /* switch (cx) */
+
+/* Command is entered, now do it. */
+
+ if (zz > -1L) { /* Time of day given? */
+ x = zz;
+ if (zz != (long) x) {
+ printf(
+"Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
+ );
+ return(-9);
+ }
+ }
+ if (sleepcan)
+ concb((char)escape); /* Ensure single-char wakeup */
+
+ if (cx == XXMSL) { /* Millisecond sleep */
+ msleep(zz < 0 ? x : x * 1000);
+ return(success = 1);
+ }
+ if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */
+ sleep(x);
+ return(success = 1);
+ }
+ if (filewait) { /* FILE... */
+ fs = zchki(tmpbuf); /* Check if file exists */
+ switch (filewait) {
+ case WF_DEL:
+ if (fs == -1)
+ return(success = 1);
+ break;
+ case WF_MOD:
+ if (fs == -1) {
+ printf("?File does not exit: %s\n",tmpbuf);
+ return(-9);
+ }
+ s = zfcdat(tmpbuf); /* Get current modification date */
+ if (!s) s = "";
+ if (ckstrncpy(filedate,s,32) != 17) {
+ printf("?Can't get modification time: %s\n",tmpbuf);
+ return(-9);
+ }
+ break;
+ case WF_CRE:
+ if (fs > -1)
+ return(success = 1);
+ break;
+ }
+ }
+ do { /* Polling loop */
+ if (sleepcan) { /* Keyboard cancellation allowed? */
+ if ((y = conchk()) > 0) { /* Did they type something? */
+ kbchar = coninc(0); /* Yes, get first char they typed */
+ debug(F000,"WAIT kbchar","",kbchar);
+#ifdef COMMENT
+ while (--y > 0) /* Gobble the rest up */
+ coninc(0);
+#endif /* COMMENT */
+ return(success = 0); /* And quit PAUSing or WAITing */
+ }
+ }
+ if (filewait == 0) {
+ if (cx == XXWAI) { /* WAIT for modem signals */
+ if (z != 0) {
+ mdmsig = ttgmdm(); /* Get them. */
+ debug(F101,"WAIT ttgmdm","",mdmsig);
+ if (mdmsig < 0) /* Failure to get them? */
+ return(success = 0); /* Fail. */
+ if ((mdmsig & z) == z) /* Got desired ones? */
+ return(success = 1); /* Succeed. */
+ } else if (x == 0)
+ return(success = 0);
+ }
+ } else { /* FILE... */
+ fs = zchki(tmpbuf); /* Get file status */
+ if (filewait == WF_MOD) { /* Wait for modification */
+ if (fs == -1) /* Failure to get status */
+ return(success = 0); /* so WAIT fails. */
+ s = zfcdat(tmpbuf); /* Get current modification time */
+ if (!s) s = ""; /* And compare with the time */
+ if (strcmp(s,filedate)) /* when the WAIT started */
+ return(success = 1);
+ } else if (filewait == WF_DEL) { /* Wait for deletion */
+ if (fs == -1) /* If file doesn't exist, */
+ return(success = 1); /* succeed. */
+ } else if (filewait == WF_CRE) { /* Wait for creation */
+ if (fs != -1) /* If file exists */
+ return(success = 1); /* succeed. */
+ }
+ }
+ if (x < 1) /* SLEEP/WAIT/PAUSE 0 */
+ break;
+ sleep(waitinterval); /* No interrupt, sleep */
+ x -= waitinterval; /* Deduct sleep time */
+ } while (x > 0);
+
+ if (cx == XXWAI) /* WAIT time expired */
+ success = (z == 0); /* Succeed if no modem signals */
+ else /* For SLEEP or PAUSE, success */
+ success = (x == 0); /* depends on whether it was */
+ return(success); /* interrupted from the keyboard. */
+#endif /* OLDWAIT */
+}
+#endif /* NOSPL */
+
+#ifdef OS2ORUNIX
+_PROTOTYP(int zcmpfn,(char *, char *));
+#endif /* OS2ORUNIX */
+
+#ifndef NOFRILLS
+#ifdef NT
+int
+dolink() {
+ /* Parse a file or a directory name */
+ int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
+ struct FDB sw, fi;
+
+ cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
+ _CMKEY, /* fcode */
+ "Filename or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nqvswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ qvswtab, /* Keyword table */
+ &fi /* Pointer to next FDB */
+ );
+
+ cmfdbi(&fi, /* 1st FDB - file to type */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 3, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ while (!havename) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) /* Error */
+ return(x);
+ switch (cmresult.fcode) {
+ case _CMKEY:
+ switch (cmresult.nresult) {
+ case DEL_LIS:
+ case DEL_VRB:
+ listing = 1;
+ break;
+ case DEL_NOL:
+ case DEL_QUI:
+ listing = 0;
+ break;
+ }
+ break;
+ case _CMIFI:
+ s = cmresult.sresult;
+ havename = 1;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ wild = cmresult.nresult; /* Source specification wild? */
+
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
+ s = line;
+
+ if (!wild)
+ wild = iswild(line);
+
+ p = tmpbuf; /* Place for new name */
+ if ((x = cmofi(wild ? "Target directory" : "New name",
+ "",&s,xxstring)) < 0) { /* Get new name */
+ if (x == -3) {
+ printf("?%s required\n", wild ? "Target directory" : "New name");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
+ if ((y = cmcfm()) < 0) return(y);
+
+ if (!wild) { /* Just one */
+ if (listing) printf("%s => %s ",line,p);
+ if (zlink(line,p) < 0) {
+ if (listing) printf("(FAILED: %s\n",ck_errstr());
+ rc = 0;
+ } else {
+ if (listing) printf("(OK)\n");
+ }
+ return(success = rc);
+ }
+ if (!isdir(p)) { /* Multiple */
+ printf( /* if target is not a directory */
+"?Multiple source files not allowed if target is not a directory.\n");
+ return(-9);
+ }
+#ifdef COMMENT
+ else { /* Show full path of target */
+ char buf[CKMAXPATH]; /* (too much) */
+ if (zfnqfp(p,CKMAXPATH,buf))
+ ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
+ }
+#endif /* COMMENT */
+
+#ifdef VMS
+ conres(); /* Let Ctrl-C work. */
+#endif /* VMS */
+ debug(F110,"dolink line",line,0);
+
+#ifdef ZXREWIND
+ z = zxrewind(); /* Rewind file list */
+#else
+ z = nzxpand(s,0); /* Expand file list */
+#endif /* ZXREWIND */
+ debug(F111,"dolink p",p,z);
+
+#ifdef UNIX
+ if (wild && z > 1)
+ sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
+#endif /* UNIX */
+
+ while (z-- > 0) {
+ if (!(z == 0 && !wild))
+ znext(line);
+ if (!line[0])
+ break;
+ if (listing) printf("%s => %s ",line,p);
+ if (zlink(line,p) < 0) {
+ if (listing) printf("(FAILED: %s\n",ck_errstr());
+ rc = 0;
+ } else {
+ if (listing) printf("(OK)\n");
+ }
+ }
+#ifdef VMS
+ concb((char)escape);
+#endif /* VMS */
+ return(success = rc);
+}
+#endif /* NT */
+
+#ifdef ZCOPY
+int
+docopy() {
+ int i, x, listing = 0, nolist = 0, havename = 0, getval;
+ char c;
+ struct FDB sw, fi;
+ int overwrite = OVW_ALWAYS;
+ int targetisdir = 0;
+ int targetlen = 0;
+ int appending = 0;
+ int preserve = 0;
+ int swapping = 0;
+ int fromb64 = 0;
+ int tob64 = 0;
+ int wild = 0;
+ int rc = 1;
+
+ char newname[CKMAXPATH], * nm;
+ nm = newname;
+
+ cmfdbi(&sw, /* 1st FDB - switches */
+ _CMKEY, /* fcode */
+ "Filename or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ ncopytab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ copytab, /* Keyword table */
+ &fi /* Pointer to next FDB */
+ );
+ cmfdbi(&fi, /* 2nd FDB - file to copy */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ while (!havename) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) /* Error */
+ return(x);
+ switch (cmresult.fcode) {
+ case _CMKEY:
+ c = cmgbrk(); /* Get break character */
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ rc = -9;
+ return(rc);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ rc = -9;
+ return(rc);
+ }
+ switch (cmresult.nresult) {
+ case DEL_LIS:
+ case DEL_VRB:
+ nolist = 0;
+ listing = 1;
+ break;
+ case DEL_NOL:
+ case DEL_QUI:
+ nolist = 1;
+ listing = 0;
+ break;
+ case 999:
+ swapping = 1;
+ break;
+ case 998:
+ appending = 1;
+ break;
+ case 995:
+ preserve = 1;
+ break;
+ case 994:
+ if ((x = cmkey(ovwtab,novwtab,
+ "When to overwrite existing destination file",
+ "",xxstring)) < 0)
+ return(x);
+ overwrite = x;
+ break;
+#ifndef NOSPL
+ case 997:
+ fromb64 = 1;
+ break;
+ case 996:
+ tob64 = 1;
+ break;
+#endif /* NOSPL */
+ }
+ break;
+ case _CMIFI:
+ s = cmresult.sresult;
+ havename = 1;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ wild = cmresult.nresult;
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
+ s = line;
+ p = tmpbuf; /* Place for new name */
+
+ /* Get destination name */
+ if ((x = cmofi("destination name and/or directory",
+#ifdef UNIX
+ "."
+#else
+ ""
+#endif /* UNIX */
+ ,&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name for destination file required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(p,s,TMPBUFSIZ); /* Safe copy of destination name */
+ if ((y = cmcfm()) < 0) return(y);
+ if (appending && swapping) {
+ printf("?Sorry, /APPEND and /SWAP conflict\n");
+ return(-9);
+ }
+#ifdef COMMENT
+/*
+ This unreasonably prevented "COPY /APPEND *.* bigfile" from concatenating
+ a bunch of files into one big file.
+*/
+ if (appending && wild) {
+ printf("?Sorry, /APPEND can be used only with single files\n");
+ return(-9);
+ }
+#endif /* COMMENT */
+ targetisdir = isdir(p);
+ x = strlen(p);
+ if (targetisdir) {
+#ifdef UNIXOROSK
+ if (p[x-1] != '/') {
+ ckstrncat(p,"/",TMPBUFSIZ);
+ x++;
+ }
+#else
+#ifdef OS2
+ if (p[x-1] != '/') {
+ ckstrncat(p,"/",TMPBUFSIZ);
+ x++;
+ }
+#else
+#ifdef STRATUS
+ if (p[x-1] != '>') {
+ ckstrncat(p,">",TMPBUFSIZ);
+ x++;
+ }
+#else
+#ifdef datageneral
+ if (p[x-1] != ':') {
+ ckstrncat(p,":",TMPBUFSIZ);
+ x++;
+ }
+#else
+ if (p[x-1] != '/') {
+ ckstrncat(p,"/",TMPBUFSIZ);
+ x++;
+ }
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* UNIXOROSK */
+ }
+ targetlen = x;
+
+ if (!appending) { /* If /APPEND not given */
+ if (wild && !targetisdir) { /* No wildcards allowed */
+ printf( /* if target is not a directory */
+"?Multiple source files not allowed if target is not a directory.\n");
+ return(-9);
+ }
+ }
+
+#ifdef VMS
+ conres(); /* Let Ctrl-C work. */
+#endif /* VMS */
+ debug(F110,"docopy line",line,0);
+ debug(F110,"docopy p",p,0);
+ debug(F110,"docopy nm",nm,0);
+
+#ifdef ZXREWIND
+ z = zxrewind(); /* Rewind file list */
+#else
+ z = nzxpand(s,0); /* Expand file list */
+#endif /* ZXREWIND */
+
+#ifdef UNIX
+ if (wild)
+ sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
+#endif /* UNIX */
+
+#ifdef IKSD
+ if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */
+ if (inserver && (!ENABLED(en_del)
+#ifdef CK_LOGIN
+ || isguest
+#endif /* CK_LOGIN */
+ )) {
+ printf("?Sorry, overwriting existing files is disabled\n");
+ return(-9);
+ }
+ }
+#endif /* IKSD */
+
+ if (tob64 && fromb64) { /* To and from B64 = no conversion */
+ tob64 = 0;
+ fromb64 = 0;
+ }
+ debug(F110,"COPY dest",p,0);
+
+ while (z > 0) {
+
+ znext(line);
+ if (!line[0])
+ break;
+
+ errno = 0; /* Reset errno */
+
+ if (targetisdir) {
+ zstrip(line,&nm);
+ ckmakmsg(newname,CKMAXPATH,p,nm,NULL,NULL);
+ nm = newname;
+ } else {
+ nm = p;
+ }
+ if (overwrite) { /* Overwrite checking? */
+ if (zchki(nm) >= (CK_OFF_T)0) { /* Destination file exists? */
+
+ char d1[20], * d2;
+ char * n1, * n2;
+ int i, skip = 0;
+
+ i = strlen(line); /* Isolate source filename */
+ for (; i >= 0; i--) {
+ if (ISDIRSEP(line[i])) {
+ n1 = &line[i+1];
+ break;
+ }
+ }
+ debug(F110,"COPY n1", n1, 0);
+ i = strlen(nm); /* And destination filename */
+ for (; i >= 0; i--) {
+ if (ISDIRSEP(nm[i])) {
+ n2 = &nm[i+1];
+ break;
+ }
+ }
+ debug(F110,"COPY n2", n2, 0);
+ if (!strcmp(n1,n2)) { /* Same name? */
+ if (overwrite == OVW_NEVER) { /* Never overwrite? */
+ if (listing) /* Skip */
+ if (listing) printf("%s => %s (SKIPPED)\n",line,nm);
+ continue;
+ }
+ ckstrncpy(d1,zfcdat(line),20); /* Source file timestamp */
+ d2 = zfcdat(nm); /* Timestamp of dest file */
+ x = strcmp(d1,d2); /* Compare them */
+ if (((overwrite == OVW_NEWER) && (x < 0)) ||
+ ((overwrite == OVW_OLDER) && (x > 0))) {
+ if (listing)
+ if (listing) printf("%s => %s (SKIPPED)\n",line,nm);
+ continue;
+ }
+ }
+ }
+ }
+ if (listing) printf("%s => %s ",line,nm);
+
+ /* Straight copy */
+ if (!swapping && !appending && !fromb64 && !tob64) {
+ debug(F110,"COPY zcopy",line,0);
+
+ if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
+ debug(F111,"COPY not OK",line,x);
+ switch (x) {
+ case -2:
+ if (listing)
+ printf("(FAILED: Not a regular file)\n");
+ else if (!nolist)
+ printf("?Not a regular file - %s\n",line);
+ rc = 0;
+ break;
+ case -3:
+ if (listing)
+ printf("(FAILED: Not found or not accessible)\n");
+ else if (!nolist)
+ printf("?Not found or not accessible - %s\n",line);
+ rc = 0;
+ break;
+ case -4:
+ if (listing)
+ printf("(FAILED: Permission denied)\n");
+ else if (!nolist)
+ printf("?Permission denied - %s\n",line);
+ rc = 0;
+ break;
+ case -5:
+ if (listing)
+ printf("(Source and destination are the same file)\n");
+ else if (!nolist)
+ printf(
+ "?Source and destination are the same file - %s\n",
+ line
+ );
+ break;
+ case -6:
+ if (listing)
+ printf("(FAILED: Input/Output error)\n");
+ else if (!nolist)
+ printf("?Input/Output error - %s\n",line);
+ rc = 0;
+ break;
+ case -7:
+ if (listing)
+ printf("(FAILED: %s - %s)\n",p,ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s\n",ck_errstr(),p);
+ rc = 0;
+ break;
+ default:
+ if (listing)
+ printf("(FAILED: %s)\n",ck_errstr());
+ else if (!nolist)
+ printf("?%s\n",ck_errstr());
+ rc = 0;
+ }
+ } else { /* Regular copy succeeded */
+ debug(F110,"COPY OK..",newname,0);
+#ifndef NOXFER
+ if (preserve) { /* Handle /PRESERVE */
+ char * pstr = ""; /* File permissions string */
+ struct zattr xx; /* File attribute structure */
+ extern char * cksysid;
+
+ initattr(&xx); /* Initialize the struct */
+
+ xx.systemid.val = cksysid; /* Set our system ID */
+ xx.systemid.len = (int)strlen(cksysid);
+#ifdef CK_PERMS
+ pstr = zgperm(line); /* Get source file's permissions */
+#endif /* CK_PERMS */
+ xx.lprotect.val = pstr;
+ xx.lprotect.len = (int)strlen(pstr);
+ xx.date.val = zfcdat(line); /* Source file's timestamp */
+ xx.date.len = (int)strlen(xx.date.val);
+ if (zstime(nm,&xx,0) < 0) {
+ printf("?COPY /PRESERVE %s: %s\n",nm,ck_errstr());
+ rc = -9;
+ }
+ }
+#endif /* NOXFER */
+ if (listing && rc > -1)
+ printf("(OK)\n");
+ }
+
+ } else { /* Special options */
+
+ int prev, y, x = 0; /* Variables needed for them */
+ int i, t;
+ char ibuf[100];
+ char obuf[200];
+ FILE * in = NULL;
+ FILE * out = NULL;
+
+ if ((in = fopen(line,"r")) == NULL) { /* Open input file */
+ if (listing)
+ printf("(FAILED: %s)\n",ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s)\n",ck_errstr(),line);
+ rc = 0;
+ continue;
+ }
+ if (targetisdir) { /* Target is directory */
+ char * buf = NULL; /* so append this filename to it */
+ zstrip(line,&buf);
+ p[targetlen] = NUL;
+ if (buf)
+ ckstrncat(p,buf,TMPBUFSIZ);
+ }
+#ifdef OS2ORUNIX
+ if (zcmpfn(line,p)) { /* Input and output are same file? */
+ if (listing)
+ printf("(FAILED: Source and destination identical)\n");
+ else if (!nolist)
+ printf("?Source and destination identical - %s\n", line);
+ rc = 0;
+ continue;
+ }
+#endif /* OS2ORUNIX */
+ if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
+ fclose(in);
+ if (listing)
+ printf("(FAILED: %s - %s)\n",p,ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s\n",p,ck_errstr());
+ rc = 0;
+ continue;
+ }
+#ifndef NOSPL
+ if (tob64) { /* Converting to Base-64 */
+
+ debug(F110,"COPY tob64",line,0);
+
+ while (1) { /* Loop... */
+ prev = x;
+ if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */
+ if (listing)
+ printf("(OK)\n");
+ break;
+ }
+ if (prev % 3) {
+ if (listing)
+ printf("(FAILED: Phase error at %d)\n",prev);
+ else if (!nolist)
+ printf("?Phase error at %d\n",prev);
+ rc = 0;
+ break;
+ }
+ if (swapping) {
+ if (x & 1) {
+ if (listing)
+ printf("(FAILED: Swap error)\n");
+ else if (!nolist)
+ printf("?Swap error\n");
+ rc = 0;
+ break;
+ }
+ for (i = 0; i < x; i+=2) {
+ t = ibuf[i];
+ ibuf[i] = ibuf[i+1];
+ ibuf[i+1] = t;
+ }
+ }
+ if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
+ if (listing)
+ printf("(FAILED: Encoding error)\n");
+ else if (!nolist)
+ printf("?Encoding error\n");
+ rc = 0;
+ break;
+ }
+ fprintf(out,"%s\n",obuf);
+ }
+
+ } else if (fromb64) { /* Converting from Base 64 */
+
+ debug(F110,"COPY fromb64",line,0);
+
+ if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
+ fclose(in);
+ if (listing)
+ printf("(FAILED: %s - %s)\n",p,ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s\n",p,ck_errstr());
+ rc = 0;
+ continue;
+ }
+ x = 1;
+ while (x) {
+ x = fread(ibuf,1,80,in);
+ if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
+ if (listing)
+ printf("(FAILED: Decoding error)\n");
+ else if (!nolist)
+ printf("?Decoding error\n");
+ rc = 0;
+ break;
+ }
+ if (swapping) {
+ if (x & 1) {
+ if (listing)
+ printf("(FAILED: Swap error)\n");
+ else if (!nolist)
+ printf("?Swap error\n");
+ rc = 0;
+ break;
+ }
+ for (i = 0; i < y; i+=2) {
+ t = obuf[i];
+ obuf[i] = obuf[i+1];
+ obuf[i+1] = t;
+ }
+ }
+ if (y > 0) {
+ if (fwrite(obuf,1,y,out) < 1) {
+ if (listing)
+ printf("(FAILED: %s - %s)\n",p,ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s\n",p,ck_errstr());
+ rc = 0;
+ break;
+ }
+ }
+ }
+
+ } else
+#endif /* NOSPL */
+
+ if (swapping) { /* Swapping bytes */
+
+ CHAR c[3];
+ c[2] = NUL;
+
+ debug(F110,"COPY swapping",line,0);
+
+ while (1) {
+ x = fread((char *)c,1,2,in);
+ if (x < 1) {
+ if (listing)
+ printf("(OK)\n");
+ break;
+ } else if (x == 1) {
+ c[1] = c[0];
+ c[0] = NUL;
+ printf(
+ "(WARNING: Odd byte count)");
+ if (!listing) printf("\n");
+ }
+ if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
+ if (listing)
+ printf("(FAILED: %s - %s)\n",p,ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s\n",p,ck_errstr());
+ rc = 0;
+ break;
+ }
+ }
+
+ } else if (appending) { /* Appending to target file */
+
+ char c;
+
+ debug(F110,"COPY appending",line,0);
+
+ while (1) {
+ x = fread(&c,1,1,in);
+ if (x < 1) {
+ if (listing)
+ printf("(OK)\n");
+ break;
+ }
+ if (fwrite(&c,1,1,out) < 1) {
+ if (listing)
+ printf("(FAILED: %s - %s)\n",p,ck_errstr());
+ else if (!nolist)
+ printf("?%s - %s\n",p,ck_errstr());
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (out) fclose(out);
+ if (in) fclose(in);
+ }
+#ifdef VMSORUNIX
+ concb((char)escape);
+#endif /* VMSORUNIX */
+ }
+ if (rc > -1) success = rc;
+ return(rc);
+}
+#endif /* ZCOPY */
+#endif /* NOFRILLS */
+
+#ifndef NOCSETS
+#ifndef NOUNICODE
+static struct keytab * xfcstab = NULL; /* For RENAME /CONVERT: */
+static char cvtbufin[CKMAXPATH+8] = { NUL, NUL };
+static char cvtbufout[CKMAXPATH+8] = { NUL, NUL };
+static char * pcvtbufin = NULL;
+static char * pcvtbufout = NULL;
+
+static int /* Input function xgnbyte() */
+cvtfnin() {
+ CHAR c;
+ c = *pcvtbufin++;
+ return(c ? c : -1);
+}
+
+_PROTOTYP(int cvtfnout,(char)); /* Output function for xpnbyte() */
+int
+#ifdef CK_ANSIC
+cvtfnout(char c)
+#else
+cvtfnout(c) char c;
+#endif /* CK_ANSIC */
+{
+ if (pcvtbufout - cvtbufout >= CKMAXPATH)
+ return(-1);
+ *pcvtbufout++ = c;
+ *pcvtbufout = NUL;
+ return(1);
+}
+
+/* Convert a string from any charset to any other charset */
+
+char *
+cvtstring(s,csin,csout) char * s; int csin, csout; {
+ int c;
+ extern CK_OFF_T ffc;
+
+ ckstrncpy(cvtbufin,s,CKMAXPATH); /* Put it in a public place */
+ pcvtbufin = cvtbufin; /* with public pointers */
+ pcvtbufout = cvtbufout;
+ *pcvtbufout = NUL;
+
+ if (csin == csout) /* If the two sets are the same */
+ return((char *)cvtbufin); /* don't bother converting */
+
+ initxlate(csin,csout); /* Initialize the translator */
+
+ while ((c = xgnbyte(FC_UCS2,csin,cvtfnin)) > -1) { /* Loop thru string */
+ if (xpnbyte(c,TC_UCS2,csout,cvtfnout) < 0) {
+ ffc = (CK_OFF_T)0;
+ return("");
+ }
+ }
+ /* ffc is touched by xgnbyte() but this is not file transfer */
+ /* so we have to undo it */
+ ffc = (CK_OFF_T)0;
+ return((char *)cvtbufout);
+}
+#endif /* NOUNICODE */
+#endif /* NOCSETS */
+
+#ifndef NORENAME
+#ifndef NOFRILLS
+#ifdef ZRENAME
+
+/* The RENAME command - expanded and improved in 8.0.212 April 2006 */
+
+static char * ren_sub[4] = { NULL,NULL,NULL,NULL }; /* For RENAME /REPLACE */
+
+int ren_list = 0; /* Default listing action for RENAME */
+int ren_coll = RENX_OVWR; /* Default collision action */
+
+int
+shorename() {
+ char * s;
+ switch (ren_coll) {
+ case RENX_FAIL: s = "fail"; break;
+ case RENX_OVWR: s = "overwrite"; break;
+ case RENX_SKIP: s = "proceed"; break;
+ }
+ printf(" rename collision: %s\n",s);
+ printf(" rename list: %s\n",showoff(ren_list));
+ return(1);
+}
+
+int
+setrename() { /* Parse SET RENAME options */
+ int x, y;
+ if ((x = cmkey(renamset,nrenamset,"","", xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case REN_OVW: /* COLLISION */
+ if ((x = cmkey(r_collision,nr_collision,"","", xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ ren_coll = x;
+ break;
+ case DEL_LIS: /* LIST */
+ return(seton(&ren_list));
+ }
+ return(success = 1);
+}
+
+/* Reverse a string - Assumes a single-byte character set */
+
+int
+gnirts(s1, s2, len) char * s1, * s2; int len; {
+ int n, m = 0;
+ if (!s1) /* Null source pointer, fail */
+ return(0);
+ n = (int) strlen(s1);
+ if (n > len-1) /* Source longer than dest, fail */
+ return(0);
+ s2[n--] = NUL; /* Deposit null byte at end of dest */
+ for (; n >= 0; n--) { /* Copy the rest backwards */
+ *s2++ = s1[n];
+ m++;
+ }
+ return(m);
+}
+
+/*
+ r e n a m e o n e
+
+ Worker function to rename one file for dorenam() (below).
+ old = name of file or directory to be renamed
+ new = new name (not required for /UPPER, /LOWER, and /REPLACE)
+ replacing = 1 if doing string replacement on the name
+ casing = 1 if converting name to lowercase, 2 if to uppercase
+ all = if doing case conversion on all names, not just monocase ones
+ converting = 1 if converting character sets
+ cset1 = character set to convert from (File Character Set index)
+ cset2 = character set to convert to (ditto, see ck?xla.h)
+ listing = 1 to show results of rename
+ nolist = 1 to be completely silent (don't even print error messages)
+ op = 1 means simulate, 2 means check for collision, 0 means rename
+ size = length of result buffer.
+ collision = action to take if destination file already exists:
+ 0 = fail
+ 1 = overwrite and succeed
+ 2 = skip and succeed
+ Returns:
+ 0: on failure to rename or when a forbidden collision would have occurred.
+ 1: on success (file was renamed or did not need to be renamed).
+ Note:
+ If this code is ever built on any platform that is not Unix, Windows,
+ VMS, or OS/2, this routine might need some adjustment.
+*/
+
+/* Opcodes for op... */
+#define REN_OP_SIM 1 /* Simulate */
+#define REN_OP_CHK 2 /* Check for collisions */
+
+static int
+renameone(old,new,
+ replacing,casing,all,converting,cset1,cset2,
+ listing,nolist,op,size,collision)
+ char * old, * new;
+ int replacing,casing,all,converting,cset1,cset2,
+ listing,nolist,op,size,collision;
+{
+ char buf[CKMAXPATH]; /* Temporary filename buffer */
+ char out[CKMAXPATH]; /* Buffer for new name */
+ char dir[CKMAXPATH]; /* Destination directory */
+ char pat[CKMAXPATH]; /* Path segment on old filename */
+
+ char * destdir; /* Destination directory, if any */
+ char * srcpath; /* Source path, if any */
+ int rc = 1, flag = 0, skip = 0; /* Control */
+ int honorcase = 0, replaced = 0;
+ int anchor = 0; /* 1 = beginning, 2 = end */
+ int occur = 0; /* Occurrence */
+ int minus = 0; /* Occurrence is negative */
+ int allbut = 0; /* Occurrence is "all but" */
+ int arg2isfile = 0; /* Arg2 ("new") is a filename */
+
+ debug(F110,"RENAMEONE old",old,0);
+ debug(F110,"RENAMEONE new",new,0);
+ debug(F110,"RENAMEONE ren_sub[0]",ren_sub[0],0);
+ debug(F110,"RENAMEONE ren_sub[1]",ren_sub[1],0);
+ debug(F110,"RENAMEONE ren_sub[2]",ren_sub[2],0);
+
+ if (op == REN_OP_SIM && !nolist) /* For convenience */
+ listing = 1;
+#ifndef NOSPL
+ honorcase = inpcas[cmdlvl]; /* Inherit SET CASE value */
+#else
+#ifdef UNIX
+ honorcase = 1;
+#else
+ honorcase = 0;
+#endif /* UNIX */
+#endif /* NOSPL */
+
+ if (!old) old = ""; /* In case of bad args */
+ if (!new) new = "";
+ if (!*old) return(success = 0);
+ ckstrncpy(out,new,CKMAXPATH); /* So we don't write into */
+ new = out; /* our argument... */
+ size = CKMAXPATH;
+
+ pat[0] = NUL; /* Assume no path in source file.. */
+ srcpath = pat;
+ {
+ int n; /* If the old name includes a path */
+ n = (int)strlen(old) - 1; /* put it in a separate place. */
+ for (; n >= 0; n--) { /* We are renaming the file only. */
+ if (ISDIRSEP(old[n])) {
+ ckstrncpy(pat,old,CKMAXPATH);
+ pat[n+1] = NUL;
+ old = old+n+1;
+ break;
+ }
+ }
+ }
+ debug(F110,"RENAMEONE old 2",old,0);
+ debug(F110,"RENAMEONE pat 2",pat,0);
+
+ dir[0] = NUL; /* Assume no destination directory */
+ destdir = dir;
+ if (*new) { /* If Arg2 given */
+ if (isdir(new)) { /* If it's a directory */
+ ckstrncpy(dir,new,CKMAXPATH); /* put it here */
+ } else { /* otherwise */
+ arg2isfile++; /* flag that it's a filename */
+ }
+ }
+ if (!casing && !replacing && !converting) {
+ if (!*new)
+ return(success = 0);
+ if (!arg2isfile) { /* Destination is a directory? */
+ if (!isdir(old)) { /* and source is not? */
+#ifndef VMS
+ int n, x = 0; /* Concatenate them */
+ if ((n = strlen(new)) > 0) /* so we can check for */
+ if (ISDIRSEP(new[n-1])) /* collisions. */
+ x++;
+ ckmakmsg(buf,size,new,x ? "" : "/", old, "");
+#else
+ ckmakmsg(buf,size,new, old, NULL, NULL);
+#endif /* VMS */
+ debug(F110,"RENAMEONE new new",new,0);
+ new = buf;
+ size = CKMAXPATH;
+ }
+ }
+ } else if (*new) { /* Directory to move file to */
+ int n, x = 0; /* after changing its name */
+ if (!isdir(new))
+ return(success = 0);
+#ifndef VMS
+ if ((n = strlen(new)) > 0)
+ if (ISDIRSEP(new[n-1]))
+ x++;
+ ckmakmsg(dir,CKMAXPATH,new,x ? "" : "/", "", "");
+#else
+ ckstrncpy(dir,new,CKMAXPATH);
+#endif /* VMS */
+ }
+
+#ifndef NOCSETS
+#ifndef NOUNICODE
+ if (converting) {
+ new = cvtstring(old,cset1,cset2);
+ }
+#endif /* NOUNICODE */
+#endif /* NOCSETS */
+
+ if (replacing) { /* Replacing strings */
+ int todo = 0;
+ int len0, len1, len2;
+ char c, *p, *s, *bp[3];
+
+ bp[0] = old; /* Original name */
+ bp[1] = ren_sub[0]; /* String to be replaced */
+ bp[2] = ren_sub[1]; /* What to replace it with */
+ if (!bp[2]) bp[2] = "";
+
+ len0 = (int)strlen(bp[0]); /* length of original filename */
+ len1 = (int)strlen(bp[1]); /* length of target substring */
+ len2 = (int)strlen(bp[2]); /* Length of replacement string */
+
+ if (ren_sub[2]) { /* Optional options */
+ p = ren_sub[2];
+ while ((c = *p++)) {
+ switch (c) {
+ case '^':
+ anchor = 1; occur = 0; minus = 0; allbut = 0; break;
+ case '$':
+ anchor = 2; occur = 0; minus = 0; allbut = 0; break;
+ case 'A': honorcase = 1; minus = 0; allbut = 0; break;
+ case 'a': honorcase = 0; minus = 0; allbut = 0; break;
+ case '-': minus = 1; break;
+ case '~': allbut = 1; break;
+ default:
+ if (isdigit(c)) {
+ occur = c - '0';
+ if (minus) occur = 0 - occur;
+ anchor = 0;
+ }
+ minus = 0;
+ }
+ }
+ }
+ if (anchor) { /* Anchored replacement... */
+ y = len0 - len1;
+ if (y > 0) {
+ int x;
+ switch (anchor) {
+ case 1: /* Anchored at beginning */
+ if (!ckstrcmp(bp[1],bp[0],len1,honorcase)) {
+ x = ckstrncpy(new,bp[2],size);
+ (VOID) ckstrncpy(new+x,bp[0]+len1,size-x);
+ replaced = 1;
+ }
+ break;
+ case 2: /* Anchored at end */
+ if (!ckstrcmp(bp[1],bp[0]+y,len1,honorcase)) {
+ x = ckstrncpy(new,bp[0],y+1);
+ (VOID) ckstrncpy(new+y,bp[2],size-x);
+ replaced = 1;
+ }
+ break;
+ }
+ }
+ if (!replaced) {
+ ckstrncpy(new,old,size); /* Keep old name */
+ replaced = 1;
+ }
+ } else { /* Replace all occurrences */
+ int j, n = 0; /* or a particular occurrence */
+ char c;
+ int x = 0;
+ char * s0 = NULL, * s1 = NULL, * s2 = NULL;
+ p = new; /* Pointer to new name */
+
+ if (occur < 0) { /* nth occurrence from the right */
+ occur = 0 - occur;
+ s0 = (char *)malloc(len0+1); /* Reverse original string */
+ if (s0) {
+ (VOID) gnirts(bp[0],s0,len0+1);
+ bp[0] = s0;
+ } else return(0);
+ s1 = (char *)malloc(len1+1); /* Reverse target string */
+ if (s1) {
+ (VOID) gnirts(bp[1],s1,len1+1);
+ bp[1] = s1;
+ } else return(0);
+ s2 = (char *)malloc(len2+1); /* Reverse replacement string */
+ if (s2) {
+ (VOID) gnirts(bp[2],s2,len2+1);
+ bp[2] = s2;
+ } else return(0);
+ debug(F111,"RENAMEONE s0",s0,len0);
+ debug(F111,"RENAMEONE s1",s1,len1);
+ debug(F111,"RENAMEONE s2",s2,len2);
+ }
+ s = bp[0]; /* Pointer to old name */
+ p = new; /* Pointer to new name */
+ j = len0 - len1 + 1; /* How much to scan */
+ while (j-- > 0) { /* For each character... */
+ if (!ckstrcmp(bp[1],s,len1,honorcase)) { /* Match? */
+ n++; /* Occurrence counter */
+ todo = (occur == 0) ||
+ (!allbut && n == occur) ||
+ (allbut && n != occur);
+ if (!todo) { /* Desired occurrence? */
+ size -= ckstrncpy(p,bp[1],size); /* No... */
+ p += len1; /* Copy target string */
+ s += len1; /* instead of replacement string */
+ continue;
+ }
+ if (len2) { /* If replacement string not empty */
+ size -= ckstrncpy(p,bp[2],size); /* Copy it */
+ p += len2;
+ }
+ s += len1; /* Advance source position */
+ } else { /* No match */
+ *p++ = *s++; /* just copy this character */
+ size--;
+ }
+ }
+ while ((*p++ = *s++)); /* Done copy the rest */
+ replaced = 1; /* Remember we changed the name */
+ if (s0) { /* Were we doing "all but"? */
+ debug(F110,"RENAMEONE new1",new,0);
+ x = (int)strlen(new); /* Unreverse the result */
+ if ((p = (char *)malloc(x+2))) {
+ (VOID) gnirts(new,p,x+2);
+ debug(F110,"RENAMEONE new2",new,0);
+ ckstrncpy(new,p,x+2);
+ free(p);
+ }
+ if (s0) free(s0); /* Free the temporary strings */
+ if (s1) free(s1);
+ if (s2) free(s2);
+ debug(F110,"RENAMEONE new3",new,0);
+ }
+ }
+ }
+ if (casing) { /* Changing case? */
+ char c, * t; /* See if mixed case. */
+ if (!replaced)
+ ckstrncpy(new,old,size); /* Copy old name to new name */
+ t = new;
+ while ((c = *t++)) {
+ if (islower(c)) flag |= 1; /* Have a lowercase letter */
+ else if (isupper(c)) flag |= 2; /* Have an uppercase letter */
+ if (flag == 3) break; /* Have a mixed-case name */
+ }
+ if (all || flag < 3) { /* Not skipping or not mixed case */
+ if (casing == 1 && flag != 1) /* Change case to lower */
+ (VOID) cklower(new);
+ else if (casing == 2 && flag != 2) /* Change case to upper */
+ (VOID) ckupper(new);
+ }
+ }
+ debug(F110,"XXX 1 new",new,0);
+ debug(F110,"XXX 1 old",old,0);
+ debug(F110,"XXX 1 srcpath",srcpath,0);
+ debug(F110,"XXX 1 destdir",destdir,0);
+
+ if (*destdir && !arg2isfile) { /* Moving without renaming */
+ ckstrncat(srcpath,old,CKMAXPATH);
+ old = srcpath;
+ new = destdir;
+ } else if (*destdir || *srcpath) { /* Were there any pathnames? */
+ char tmp[CKMAXPATH];
+ ckmakmsg(tmp,CKMAXPATH,srcpath,old,NULL,NULL);
+ ckstrncpy(old,tmp,CKMAXPATH);
+ if (*destdir) { /* Directory-to-move-to given? */
+ ckstrncat(destdir,new,CKMAXPATH);
+ new = destdir;
+ } else if (*srcpath && !arg2isfile) { /* Or was there a source path? */
+ ckstrncat(srcpath,new,CKMAXPATH);
+ new = srcpath;
+ }
+ }
+ debug(F110,"XXX 2",new,0);
+
+ skip = 0; /* Can we skip this one? */
+#ifdef COMMENT
+ if (casing && !replaced) {
+ skip = (((all == 0) && (flag == 3)) || (flag == casing)) ? 1 : 0;
+ if (!skip && destdir) skip = 0;
+ }
+#endif /* COMMENT */
+ if (!skip) {
+ if (!ckstrcmp(old,new,-1,1))
+ skip = 1;
+ }
+ if (op == 0 && !skip && (collision != RENX_OVWR)) {
+ if (zchki(new) > (CK_OFF_T)-1) { /* New file already exists? */
+ switch (collision) { /* Yes, take specified action */
+ case RENX_SKIP: /* Skip this one and proceed */
+ skip = 2;
+ break;
+ case RENX_FAIL: /* Or fail. */
+ skip = 3;
+ if (!listing && !nolist)
+ printf("?File already exists: %s\n",new);
+ }
+ }
+ }
+ debug(F110,"RENAMEONE new",new,0);
+ debug(F101,"RENAMEONE flag","",flag);
+ debug(F101,"RENAMEONE skip","",skip);
+ debug(F100,"RENAMEONE ----------------","",0);
+
+ if (skip == 3) {
+ if (listing) printf("%s => %s (SKIPPED: %s already exists)\n",
+ old,new,new);
+ rc = 0;
+ } else if (skip) { /* Skipping this one */
+ if (listing) printf("%s => %s (%s)\n",
+ old,new,
+ (skip == 2) ? "COLLISION: SKIPPED" : "SKIPPED");
+ } else { /* Have to rename this one */
+ if (op == REN_OP_CHK) { /* Checking for collisions */
+ return((zchki(new) > (CK_OFF_T)-1) ? 0 : 1 );
+ } else if (op == REN_OP_SIM) { /* Simulating */
+ if (listing) printf("%s => %s (SIMULATED)\n",old,new);
+ } else { /* Really renaming */
+ if (listing) printf("%s => %s ",old,new);
+ if (zrename(old,new) < 0) {
+ rc = 0;
+ if (listing)
+ printf("(FAILED: %s)\n",ck_errstr());
+ else if (!nolist)
+ printf("?%s\n",ck_errstr());
+ } else {
+ if (listing) printf("(OK)\n");
+ }
+ }
+ }
+ return(success = rc); /* Succeeds also if nothing needed to be renamed */
+}
+
+int
+dorenam() {
+#ifndef NOCSETS
+#ifndef NOUNICODE
+ extern int nfilc;
+ extern struct keytab fcstab[];
+ extern struct csinfo fcsinfo[];
+#endif /* NOUNICODE */
+#endif /* NOCSETS */
+ int cset1 = 0, cset2 = 0;
+
+ int i, x, z, fn, listing = 0, havename = 0, wild = 0, rc = 1, noarg = 0;
+ int nolist = 0, all = 0, casing = 0, replacing = 0, getval = 0, sim = 0;
+ int converting = 0, collision = 0;
+
+ char c;
+ struct FDB sw, fi;
+
+ collision = ren_coll; /* Inherit SET RENAME COLLISION */
+ listing = ren_list; /* Inhereit SET RENAME LIST */
+
+ if (ren_sub[0]) makestr(&(ren_sub[0]),NULL);
+ if (ren_sub[1]) makestr(&(ren_sub[1]),NULL);
+ if (ren_sub[2]) makestr(&(ren_sub[2]),NULL);
+ line[0] = NUL;
+ tmpbuf[0] = NUL;
+
+ cmfdbi(&sw, /* 1st FDB - switches */
+ _CMKEY, /* fcode */
+ "Filename or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nrenamsw, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ renamsw, /* Keyword table */
+ &fi /* Pointer to next FDB */
+ );
+
+ cmfdbi(&fi, /* 2nd FDB - file or directory name */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 3, /* Flags */
+ 0, /* 0 = Parse file or directory names */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ if (cmflgs == 1) {
+ printf("?File or directory name required\n");
+ return(-9);
+ }
+ while (!havename) {
+ noarg = 0;
+ x = cmfdb(&sw); /* Parse something */
+ if (x == -3) { /* They hit Enter prematurely */
+ printf("?Command incomplete\n");
+ return(-9);
+ } else if (x < 0) { /* Other error */
+ if (x == -1)
+ return(x);
+ if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
+ printf("?No files match: %s\n",brstrip(atmbuf));
+ else if (zchki(atmbuf) == -1)
+ printf("?File not found: %s\n",brstrip(atmbuf));
+ else
+ printf("?Error with switch or filename: %s\n",brstrip(atmbuf));
+ return(-9);
+ }
+ fn = cmresult.nresult; /* For brevity */
+ switch (cmresult.fcode) { /* Handle each kind of field */
+ case _CMKEY: /* Keyword (switch) */
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG))
+ noarg = 1; /* Remember arg is missing */
+ switch (cmresult.nresult) { /* Handle the switch */
+ case DEL_LIS: /* /LIST */
+ case DEL_VRB: /* /VERBOSE */
+ listing = 1;
+ break;
+ case DEL_NOL: /* /NOLIST */
+ case DEL_QUI: /* /QUIET */
+ nolist = 1;
+ listing = 0;
+ break;
+ case DEL_SIM: /* /SIMULATE */
+ sim = 1;
+ break;
+ case REN_UPP: /* /UPPER: */
+ case REN_LOW: /* /LOWER */
+ all = 1;
+ if (!noarg) {
+ if ((x = cmkey((fn == REN_UPP) ? r_upper : r_lower,
+ 2, "","all",xxstring)) < 0) {
+ if (x == -3)
+ x = 1;
+ else
+ return(x);
+ }
+ all = x;
+ }
+ /* 0 = don't convert; 1 = convert to lower; 2 = to upper */
+ casing = (fn == REN_UPP) ? 2 : 1;
+ converting = 0;
+ break;
+ case REN_OVW: /* /COLLISION */
+ if (!noarg) {
+ if ((x = cmkey(r_collision,
+ nr_collision,"","overwrite",xxstring))<0) {
+ if (x == -3)
+ x = RENX_OVWR;
+ else
+ return(x);
+ }
+ collision = x;
+ }
+ break;
+ case REN_RPL: /* /REPLACE: */
+ if (noarg) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((x = cmfld("String to remove, or {{String1}{String2}}",
+ "",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Target string required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (s[0]) {
+ if (s[0] == '{' && s[1] == '{') /* Get the list */
+ makelist(s,ren_sub,3);
+ else
+ makestr(&(ren_sub[0]),s);
+ }
+ converting = 0;
+ break;
+
+ case REN_SPA: /* /FIXSPACES: */
+ if (!noarg)
+ if ((x = cmfld("Character or string to replace spaces with",
+ "_",&s,xxstring)) < 0)
+ if (x == -3)
+ s = "_";
+ else
+ return(x);
+ makestr(&(ren_sub[0])," ");
+ makestr(&(ren_sub[1]),noarg ? "_" : brstrip(s));
+ makestr(&(ren_sub[3]),NULL);
+ converting = 0;
+ break;
+
+#ifndef NOCSETS
+#ifndef NOUNICODE
+ case REN_XLA: /* /CONVERT:cset1:cset2 */
+ if (!xfcstab) { /* Make a copy of the file charset */
+ int i, x; /* table with CM_ARG set for each */
+ x = (nfilc + 1) * sizeof(struct keytab);
+ xfcstab = (struct keytab *)malloc(x);
+ if (!xfcstab) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ for (i = 0; i < nfilc; i++) {
+ xfcstab[i].kwd = fcstab[i].kwd;
+ xfcstab[i].kwval = fcstab[i].kwval;
+ xfcstab[i].flgs = fcstab[i].flgs | CM_ARG;
+ }
+ }
+ if ((x = cmswi(xfcstab,nfilc,
+ "Character-set of old name","",xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pair of character-set names required\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ cset1 = x;
+ c = cmgbrk();
+ if (!getval) {
+ printf("?Secondcharacter-set name required\n");
+ return(-9);
+ }
+ if ((x = cmkey(fcstab,nfilc,
+ "Character-set of new name","",xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Second character-set name required\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ cset2 = x;
+ if (casing)
+ casing = 0;
+ if (ren_sub[0])
+ makestr(&(ren_sub[0]),NULL);
+ if (ren_sub[1])
+ makestr(&(ren_sub[1]),NULL);
+ if (ren_sub[2])
+ makestr(&(ren_sub[2]),NULL);
+ converting = 1;
+ break;
+#endif /* NOUNICODE */
+#endif /* NOCSETS */
+ }
+ break;
+ case _CMIFI: /* File or directory name */
+ s = cmresult.sresult;
+ havename = 1;
+ break;
+ default:
+ printf("?File or directory name required\n");
+ return(-9);
+ }
+ }
+ if (havename) {
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */
+ } else {
+ printf("?Internal error\n");
+ return(-9); /* Shouldn't happen */
+ }
+ wild = cmresult.nresult; /* Source specification wild? */
+ if (!wild)
+ wild = iswild(line);
+
+ debug(F111,"RENAME WILD",line,wild);
+
+ p = tmpbuf; /* Place for new name */
+ p[0] = NUL;
+ replacing = ren_sub[0] ? 1 : 0;
+
+#ifdef COMMENT
+ if (!(casing || replacing || converting)) {
+ if ((x = cmofi(wild ? "Target directory" : "New name",
+ "",&s,xxstring)) < 0) { /* Get new name */
+ if (x == -3) {
+ printf("?%s required\n",
+ wild ? "Target directory" : "New name");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
+ }
+#else
+ if ((x = cmofi(wild ? "Target directory" : "New name",
+ "",&s,xxstring)) < 0) { /* Get new name */
+ if (x == -3) {
+ if (casing || replacing || converting) {
+ s = "";
+ } else {
+ printf("?%s required\n",
+ wild ? "Target directory" : "New name");
+ return(-9);
+ }
+ } else return(x);
+ }
+ ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */
+#endif /* COMMENT */
+
+ if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
+
+#ifdef COMMENT
+#ifndef NOUNICODE
+ if (converting) {
+ printf(" From: %s\n",fcsinfo[cset1].keyword);
+ printf(" To: %s\n",fcsinfo[cset2].keyword);
+ }
+#endif /* NOUNICODE */
+ if (casing) {
+ printf("CASING: %s\n", (casing == 1) ? "LOWER" : "UPPER");
+ }
+ if (replacing) {
+ printf("REPLACING: '%s' with '%s'\n",
+ ren_sub[0],
+ ren_sub[1] ? ren_sub[1] : "");
+ }
+#endif /* COMMENT */
+
+ s = line;
+ if (!wild) /* Just one */
+ return(success =
+ renameone(s,p,
+ replacing,casing,all,converting,cset1,cset2,
+ listing,nolist,sim,TMPBUFSIZ,collision));
+
+ if (!casing && !replacing && !converting) { /* Multiple files */
+ if (!isdir(p)) {
+ printf( /* if target is not a directory */
+"?Multiple source files not allowed if target is not a directory.\n");
+ return(-9);
+ }
+ }
+#ifdef COMMENT
+ else { /* Show full path of target */
+ char buf[CKMAXPATH]; /* (too much) */
+ if (zfnqfp(p,CKMAXPATH,buf))
+ ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
+ }
+#endif /* COMMENT */
+
+#ifdef VMS
+ conres(); /* Let Ctrl-C work. */
+#endif /* VMS */
+ debug(F110,"dorename line",line,0);
+
+#ifdef ZXREWIND
+ z = zxrewind(); /* Rewind file list */
+#else
+ z = nzxpand(s,0); /* Expand file list */
+#endif /* ZXREWIND */
+ debug(F111,"dorename p",p,z);
+
+#ifdef UNIX
+ if (wild && z > 1)
+ sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
+#endif /* UNIX */
+
+ /* For /COLLISION:FAIL make a silent pass to see if there would be any */
+
+ if (collision == RENX_FAIL) {
+ int n = 0;
+ char line[CKMAXPATH+2];
+ while (z-- > 0) {
+ if (!(z == 0 && !wild))
+ znext(line);
+ if (!line[0])
+ break;
+ if (!renameone((char *)line,p,
+ replacing,casing,all,converting,cset1,cset2,
+ 0,1,REN_OP_CHK,TMPBUFSIZ,RENX_FAIL))
+ n++;
+ }
+ if (n > 0) {
+ printf("?Failed: %d file%s would be overwritten\n",
+ n, (n != 1) ? "s" : "");
+#ifdef VMS
+ concb((char)escape);
+#endif /* VMS */
+ return(success = 0);
+ }
+ /* Get the file list back. */
+#ifdef ZXREWIND
+ z = zxrewind();
+#else
+ z = nzxpand(s,0);
+#endif /* ZXREWIND */
+ }
+ while (z-- > 0 && rc > 0) {
+ char line[CKMAXPATH+2];
+ if (!(z == 0 && !wild))
+ znext(line);
+ if (!line[0])
+ break;
+ rc = renameone((char *)line,p,
+ replacing,casing,all,converting,cset1,cset2,
+ listing,nolist,sim,TMPBUFSIZ,collision);
+ }
+#ifdef VMS
+ concb((char)escape);
+#endif /* VMS */
+ return(success = rc);
+}
+#endif /* ZRENAME */
+#endif /* NOFRILLS */
+#endif /* NORENAME */
+
+#ifndef NOSPL
+
+/* Do the RETURN command */
+
+int
+doreturn(s) char *s; {
+ int x;
+ extern int tra_asg;
+ char * line, * lp;
+
+ if (cmdlvl < 1) {
+ printf("\n?Can't return from level %d\n",maclvl);
+ return(success = 0);
+ }
+ line = malloc(LINBUFSIZ);
+ if (line == NULL)
+ return(success = 0);
+ lp = line; /* Expand return value now */
+ x = LINBUFSIZ-1;
+ if (!s) s = "";
+ debug(F110,"RETURN s",s,0);
+ if (zzstring(s,&lp,&x) > -1) {
+ s = line;
+ debug(F110,"RETURN zzstring",s,0);
+ }
+
+ /* Pop from all FOR/WHILE/SWITCH/XIFs */
+ while ((maclvl > 0) &&
+ (m_arg[maclvl-1][0]) &&
+ (cmdstk[cmdlvl].src == CMD_MD) &&
+ (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_for",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
+ debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl);
+ dogta(XXPTA); /* Put args back */
+ popclvl(); /* Pop up two levels */
+ popclvl();
+ }
+ if (tra_asg) { /* If tracing show return value */
+ if (*s)
+ printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
+ else
+ printf("<<< %s: (null)\n", m_arg[maclvl][0]);
+ }
+ popclvl(); /* Pop from enclosing TAKE or macro */
+ debug(F111,"RETURN tolevel",s,maclvl);
+ if (!s) s = "";
+ if (!*s) s = NULL;
+ makestr(&(mrval[maclvl+1]),s); /* Set the RETURN value */
+ free(line);
+ return(success = 1); /* Macro succeeds if we RETURN */
+}
+#endif /* NOSPL */
+
+#ifndef NOSPL
+/* Do the OPEN command */
+
+int
+doopen() { /* OPEN { append, read, write } */
+ int x, y, z = 0; char *s;
+ static struct filinfo fcb; /* (must be static) */
+ if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Mode required\n");
+ return(-9);
+ } else return(x);
+ }
+ switch (x) {
+ case OPN_FI_R: /* Old file (READ) */
+ if (chkfn(ZRFILE) > 0) {
+ printf("?Read file already open\n");
+ return(-2);
+ }
+ if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
+ if (z == -3) {
+ printf("?Input filename required\n");
+ return(-9);
+ } else return(z);
+ }
+ if (y) { /* No wildcards allowed */
+ printf("\n?Please specify a single file\n");
+ return(-2);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((int)strlen(line) < 1) return(-2);
+ if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
+ return(z);
+ if (y < 1) {
+ printf("?Positive number required\n");
+ return(-9);
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ readblock = y;
+ if (readbuf)
+ free((char *)readbuf);
+ if (!(readbuf = (CHAR *) malloc(readblock+1))) {
+ printf("?Can't allocate read buffer\n");
+ return(-9);
+ }
+ return(success = zopeni(ZRFILE,line));
+
+#ifndef MAC
+#ifndef NOPUSH
+ case OPN_PI_R: /* Pipe/Process (!READ) */
+ if (nopush) {
+ printf("?Read from pipe disabled\n");
+ return(success=0);
+ }
+ if (chkfn(ZRFILE) > 0) {
+ printf("?Read file already open\n");
+ return(-2);
+ }
+ if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Command name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(line,brstrip(s),LINBUFSIZ);
+ if (!line[0]) return(-2);
+ if ((y = cmcfm()) < 0) return(y);
+ if (!readbuf) {
+ if (!(readbuf = (CHAR *) malloc(readblock+1))) {
+ printf("?Can't allocate read buffer\n");
+ return(-9);
+ }
+ }
+ return(success = zxcmd(ZRFILE,line));
+
+ case OPN_PI_W: /* Write to pipe */
+ if (nopush) {
+ printf("?Write to pipe disabled\n");
+ return(success=0);
+ }
+ if (chkfn(ZWFILE) > 0) {
+ printf("?Write file already open\n");
+ return(-2);
+ }
+ if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Command name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(line,brstrip(s),LINBUFSIZ);
+ if (!line[0]) return(-2);
+ if ((y = cmcfm()) < 0) return(y);
+ success = zxcmd(ZWFILE,line);
+ if (!success && msgflg)
+ printf("Can't open process for writing: %s\n",line);
+ return(success);
+#endif /* NOPUSH */
+#endif /* MAC */
+
+ case OPN_FI_W: /* New file (WRITE) */
+ case OPN_FI_A: /* (APPEND) */
+ if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
+ if (z == -3) {
+ printf("?Filename required\n");
+ return(-9);
+ } else return(z);
+ }
+ if (z == 2) {
+ printf("?Sorry, %s is a directory name\n",s);
+ return(-9);
+ }
+ if (chkfn(ZWFILE) > 0) {
+ printf("?Write/Append file already open\n");
+ return(-2);
+ }
+ fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
+ fcb.lblopts = 0;
+ fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((int)strlen(line) < 1) return(-2);
+ if ((y = cmcfm()) < 0) return(y);
+ return(success = zopeno(ZWFILE,line,NULL,&fcb));
+
+#ifndef NOLOCAL
+ case OPN_SER: /* OPEN PORT or LINE */
+ case OPN_NET: { /* OPEN HOST */
+ extern int didsetlin, ttnproto;
+ if (x == OPN_NET) {
+ z = ttnproto;
+ ttnproto = NP_NONE;
+ }
+ if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
+ if (x == OPN_NET)
+ ttnproto = z;
+ success = 0;
+ }
+ didsetlin++;
+ return(y);
+ }
+#endif /* NOLOCAL */
+
+ default:
+ printf("?Not implemented");
+ return(-2);
+ }
+}
+#endif /* NOSPL */
+
+#ifndef NOXFER
+/* D O X G E T -- GET command parser with switches */
+
+#ifdef CK_LABELED
+int g_lf_opts = -1;
+extern int lf_opts;
+#endif /* CK_LABELED */
+
+int
+doxget(cx) int cx; {
+ extern int /* External variables we need */
+#ifdef RECURSIVE
+ recursive,
+#endif /* RECURSIVE */
+ xfermode, fdispla, protocol, usepipes,
+ g_binary, g_xfermode, g_displa, g_rpath, g_usepipes;
+ extern char * rcv_move; /* Directory to move new files to */
+ extern char * rcv_rename; /* What to rename new files to */
+ extern char * rcvexcept[]; /* RECEIVE / GET exception list */
+ int opkt = 0; /* Flag for O-Packet needed */
+
+#ifdef PIPESEND
+ extern int pipesend;
+ extern char * rcvfilter;
+#endif /* PIPESEND */
+ extern struct keytab rpathtab[];
+ extern int nrpathtab;
+ extern CK_OFF_T calibrate;
+ int asname = 0; /* Flag for have as-name */
+ int konly = 0; /* Kermit-only function */
+ int c, i, n, confirmed = 0; /* Workers */
+ int getval = 0; /* Whether to get switch value */
+ int rcvcmd = 0; /* Whether it is the RECEIVE command */
+ int mget = 0; /* Whether it is the MGET command */
+ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
+ struct FDB sw, fl, cm; /* FDBs for each parse function */
+ char * cmdstr = "this command";
+
+#ifdef NEWFTP
+ if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) {
+ extern int ftpget;
+ extern int ftpisopen();
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) {
+ int x;
+ x = doftpget(cx,0);
+ debug(F101,"doftpget return","",x);
+ if (x > -1)
+ success = x;
+ debug(F101,"doftpget success","",success);
+ return(x);
+ }
+ }
+#endif /* NEWFTP */
+
+ debug(F101,"xget cx","",cx);
+
+ oopts = -1;
+ omode = -1;
+
+ for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL;
+ pv[i].ival = -1;
+ pv[i].wval = (CK_OFF_T)-1;
+ }
+ /* Preset switch values based on top-level command that called us */
+
+ switch (cx) {
+ case XXREC: /* RECEIVE */
+ cmdstr = "RECEIVE";
+ rcvcmd = 1; break;
+ case XXGET: /* GET */
+ cmdstr = "GET";
+ konly = 1;
+ break;
+#ifdef CK_RESEND
+ case XXREGET: /* REGET */
+ cmdstr = "REGET";
+ konly = 1;
+ pv[SND_BIN].ival = 1; /* Implies /BINARY */
+ pv[SND_RES].ival = 1; break;
+#endif /* CK_RESEND */
+ case XXRETR: /* RETRIEVE */
+ cmdstr = "RETRIEVE";
+ konly = 1;
+ pv[SND_DEL].ival = 1; break;
+#ifdef PIPESEND
+ case XXCREC: /* CRECEIVE */
+ cmdstr = "CRECEIVE";
+ konly = 1;
+ rcvcmd = 1;
+ pv[SND_CMD].ival = 1; break;
+ case XXCGET: /* CGET */
+ cmdstr = "CGET";
+ konly = 1;
+ pv[SND_CMD].ival = 1; break;
+#endif /* PIPESEND */
+#ifndef NOMGET
+ case XXMGET: /* MGET */
+ cmdstr = "MGET";
+ konly = 1;
+ mget = 1; break;
+#endif /* NOMGET */
+ }
+ debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
+ debug(F101,"xget konly","",konly);
+
+#ifdef CK_XYZ
+ if (!rcvcmd && protocol != PROTO_K) {
+ printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
+ return(-9);
+ }
+#endif /* CK_XYZ */
+
+ /* Set up chained parse functions... */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ rcvcmd ?
+ "Optional name/template to store incoming files under, or switch" :
+ "Remote filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ rcvcmd ? nrcvtab : ngettab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ rcvcmd ? rcvtab : gettab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ if (rcvcmd || mget) /* RECEIVE or MGET */
+ cmfdbi(&fl,
+ _CMTXT, /* fcode */
+ rcvcmd ? /* hlpmsg */
+ "Output filename or Command" : /* Output filename */
+ "File(s) to GET", /* Files we are asking for */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+#ifdef COMMENT
+#ifdef CK_XYZ
+ (protocol == PROTO_X || protocol == PROTO_XC) ?
+ xxstring :
+ (rcvcmd ? (xx_strp)0 : xxstring)
+#else
+ rcvcmd ? (xx_strp)0 : xxstring /* Processing function */
+#endif /* CK_XYZ */
+#else /* COMMENT */
+ xxstring /* Always evaluate - fdc 2006/02/01 */
+#endif /* COMMENT */
+ ,
+ NULL,
+ &cm
+ );
+ else
+ cmfdbi(&fl, /* Remote filename or command */
+ _CMFLD, /* fcode */
+ "Remote filename", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* Confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ /* (See doxsend() for fuller commentary) */
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"xget cmfdb","",x);
+ if (x < 0) /* Error */
+ goto xgetx; /* or reparse needed */
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk(); /* Get break character */
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ x = -9;
+ goto xgetx;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ x = -9;
+ goto xgetx;
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"xget switch","",n);
+
+ switch (n) { /* Process the switch */
+#ifdef PIPESEND
+ case SND_CMD: /* These take no args */
+ if (nopush) {
+ printf("?Sorry, system command access is disabled\n");
+ x = -9;
+ goto xgetx;
+ } else if (rcvfilter) {
+ printf(
+"?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
+ x = -9;
+ goto xgetx;
+ }
+ if (rcvcmd)
+ sw.hlpmsg = "Command, or switch"; /* Change help message */
+ /* Fall thru... */
+#endif /* PIPESEND */
+
+ case SND_REC: /* /RECURSIVE */
+ pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
+ pv[n].ival = 1; /* Set the recursive flag */
+ break;
+
+ case SND_RES: /* /RECOVER */
+ pv[SND_BIN].ival = 1; /* Implies /BINARY */
+ pv[n].ival = 1; /* Set the resend flag */
+ break;
+
+ case SND_DEL: /* /DELETE */
+ case SND_SHH: /* /QUIET */
+ case SND_CAL: /* /CALIBRATE */
+ case SND_XPA: /* /TRANSPARENT */
+ pv[n].ival = 1; /* Just set the appropriate flag */
+ break;
+
+ case SND_PIP: /* /PIPES:{ON,OFF} */
+ if (!getval) {
+ pv[n].ival = 1;
+ break;
+ }
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ goto xgetx;
+ if (!nopush)
+ pv[n].ival = x;
+ break;
+
+ /* File transfer modes - each undoes the others */
+
+ case SND_BIN: /* Binary */
+ case SND_TXT: /* Text */
+ case SND_IMG: /* Image */
+ case SND_LBL: /* Labeled */
+ pv[SND_BIN].ival = 0; /* Unset all */
+ pv[SND_TXT].ival = 0;
+ pv[SND_IMG].ival = 0;
+ pv[SND_LBL].ival = 0;
+ pv[n].ival = 1; /* Set the requested one */
+ break;
+
+ case SND_EXC: /* Excludes */
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ x = -9;
+ }
+ goto xgetx;
+ }
+ if (pv[n].sval) free(pv[n].sval);
+ y = strlen(s);
+ if (y > 256) {
+ printf("?Pattern too long - 256 max\n");
+ x = -9;
+ goto xgetx;
+ }
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ break;
+
+#ifdef COMMENT
+ /* Not implemented */
+ case SND_PRI: /* GET to printer */
+ pv[n].ival = 1;
+ if (!getval) break;
+ if ((x = cmfld("Print options","",&s,xxstring)) < 0)
+ goto xgetx;
+ pv[n].sval = malloc((int)strlen(s)+1);
+ if (pv[n].sval)
+ strcpy(pv[n].sval,s); /* safe */
+ break;
+#endif /* COMMENT */
+
+ case SND_MOV: /* MOVE after */
+ case SND_REN: /* RENAME after */
+ if (!getval) break;
+ if ((x = cmfld(n == SND_MOV ?
+ "device and/or directory for source file after sending" :
+ "new name for source file after sending",
+ "",
+ &s,
+ n == SND_MOV ? xxstring : NULL
+ )) < 0) {
+ if (x == -3) {
+ printf("%s\n", n == SND_MOV ?
+ "?Destination required" :
+ "?New name required"
+ );
+ x = -9;
+ }
+ goto xgetx;
+ }
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ s = brstrip(s);
+ y = strlen(s);
+ if (y > 0) {
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ }
+ break;
+
+ case SND_ASN: /* As-name */
+ if (!getval) break;
+ if (mget) {
+ printf("?Sorry, as-name not allowed with MGET\n");
+ x = -9;
+ goto xgetx;
+ }
+ if (
+#ifdef COMMENT
+ (x = cmfld("Name to store it under","",&s,NULL))
+#else
+ (x = cmfld("Name to store it under","",&s,xxstring))
+#endif /* COMMENT */
+ < 0)
+ goto xgetx;
+ s = brstrip(s);
+ if ((y = strlen(s)) > 0) {
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ }
+ break;
+
+#ifdef PIPESEND
+ case SND_FLT: /* Filter */
+ debug(F101,"xget /filter getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Filter program to receive through",
+ "",&s,NULL)) < 0) {
+ if (x == -3)
+ s = "";
+ else
+ goto xgetx;
+ }
+ if (*s) s = brstrip(s);
+ y = strlen(s);
+ for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
+ if (s[x] != '\\') continue;
+ if (s[x+1] == 'v') break;
+ }
+ if (x == y) {
+ printf(
+ "?Filter must contain a replacement variable for filename.\n"
+ );
+ x = -9;
+ goto xgetx;
+ }
+ pv[n].ival = 1;
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if ((y = strlen(s)) > 0) {
+ if ((pv[n].sval = malloc(y+1)))
+ strcpy(pv[n].sval,s); /* safe */
+ }
+ break;
+#endif /* PIPESEND */
+
+ case SND_PTH: /* Pathnames */
+ if (!getval) {
+ pv[n].ival = PATH_REL;
+ break;
+ }
+ if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
+ goto xgetx;
+ pv[n].ival = x; /* Ditto */
+ break;
+
+ case SND_NAM: /* Filenames */
+ if (!getval) break;
+ if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
+ goto xgetx;
+ pv[n].ival = x;
+ break;
+
+ case SND_PRO: /* Protocol to use */
+ if (!getval) break;
+ if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
+ xxstring)) < 0) {
+ if (x == -3)
+ x = 0;
+ else
+ goto xgetx;
+ }
+ debug(F111,"xget /proto",atmbuf,x);
+ pv[n].ival = x;
+ if (konly && x != PROTO_K) {
+ printf(
+"?Sorry, this command works only with Kermit protocol\n"
+ );
+ x = -9;
+ goto xgetx;
+ }
+ break;
+
+ default:
+ printf("?Unexpected switch value - %d\n",cmresult.nresult);
+ x = -9;
+ goto xgetx;
+ }
+ }
+ debug(F101,"xget cmresult fcode","",cmresult.fcode);
+
+ cmarg = line; /* Initialize string pointers */
+ cmarg2 = tmpbuf;
+ asname = 0;
+ line[0] = NUL; /* and buffers. */
+ tmpbuf[0] = NUL;
+
+ switch (cmresult.fcode) { /* How did we get out of switch loop */
+ case _CMFLD: /* (3) Remote filespec */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ break;
+ case _CMTXT: /* (4) As-name */
+ if (rcvcmd) {
+ ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
+ if ((int)strlen(tmpbuf) > 0)
+ asname = 1;
+ } else {
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ }
+ case _CMCFM: /* (6) Confirmation */
+ confirmed = 1;
+ break;
+ default:
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ x = -9;
+ goto xgetx;
+ }
+ debug(F110,"xget string",cmarg,0);
+ debug(F101,"xget confirmed","",confirmed);
+
+ cmarg = brstrip(cmarg); /* Strip any braces */
+
+ if (!confirmed) { /* CR not typed yet, get more fields */
+ if (pv[SND_CMD].ival > 0) {
+ debug(F100,"xget calling cmtxt","",0);
+ x = cmtxt("Local command to pipe into","",&s,NULL);
+ if (x < 0 && x != -3) goto xgetx;
+ if (x != -3) {
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ asname = 1;
+ }
+ } else if (!rcvcmd) {
+#ifdef VMS
+ /* cmofi() fails if you give it a directory name */
+ x = cmfld("Name or directory for incoming file","",&s,NULL);
+ debug(F111,"xget cmfld",s,x);
+#else
+ x = cmofi("Name or directory for incoming file","",&s,NULL);
+ debug(F111,"xget cmofi",s,x);
+#endif /* VMS */
+ if (x < 0 && x != -3) goto xgetx;
+ if (x != -3) {
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = cmcfm()) < 0) goto xgetx;
+ asname = 1;
+ }
+ }
+ }
+ /* Arrive here with cmarg and cmarg2 all set */
+
+ debug(F111,"xget asname",cmarg2,asname);
+ if (!asname) {
+ if (pv[SND_ASN].sval)
+ ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
+ else
+ tmpbuf[0] = NUL;
+ }
+ cmarg2 = brstrip(cmarg2); /* Strip outer braces if any. */
+ debug(F110,"xget cmarg",cmarg,0);
+ debug(F110,"xget cmarg2",cmarg2,0);
+
+ if (!*cmarg &&
+ (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
+ printf("?A remote file specification is required\n");
+ x = -9;
+ goto xgetx;
+ }
+#ifdef PIPESEND
+ if (pv[SND_CMD].ival > 0) { /* /COMMAND sets pipesend flag */
+ x = -9;
+ if (!*cmarg2) {
+ printf("?Command required\n");
+ goto xgetx;
+ } else if (nopush) {
+ printf("?Sorry, system command access is disabled\n");
+ goto xgetx;
+ } else if (rcvfilter) {
+ printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
+ goto xgetx;
+ } else
+ pipesend = 1;
+ }
+ debug(F101,"xget /COMMAND pipesend","",pipesend);
+#endif /* PIPESEND */
+
+#ifdef CK_RESEND
+ if (pv[SND_RES].ival > 0) { /* REGET or GET /RECOVER */
+#ifdef RECURSIVE
+ if (pv[SND_REC].ival > 0) { /* RECURSIVE */
+#ifdef COMMENT
+ printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
+ x = -9;
+ goto xgetx;
+#else
+ opkt = 1;
+#endif /* COMMENT */
+ }
+#endif /* RECURSIVE */
+ if (pv[SND_DEL].ival > 0) { /* /DELETE */
+#ifdef COMMENT
+ printf("?Unsupported option combination: /RECOVER /DELETE\n");
+ x = -9;
+ goto xgetx;
+#else
+ opkt = 1;
+#endif /* COMMENT */
+ }
+ }
+#endif /* CK_RESEND */
+
+ if (pv[SND_EXC].ival > 0) /* /EXCEPT */
+ makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
+
+#ifdef IKS_OPTION
+ if (!rcvcmd
+#ifdef CK_XYZ
+ && protocol == PROTO_K
+#endif /* CK_XYZ */
+ ) {
+ if (!iks_wait(KERMIT_REQ_START,1)) {
+ printf(
+ "?A Kermit Server is not available to process this command\n");
+ x = -9; /* correct the return code */
+ goto xgetx;
+ }
+ }
+#endif /* IKS_OPTION */
+
+#ifdef CK_XYZ
+ {
+ int po, pg; /* (for clarity) */
+ po = pv[SND_PRO].ival; /* /PROTOCOL option */
+ pg = protocol; /* Protocol global */
+ if ((rcvcmd && !*cmarg2) && /* If no as-name was given */
+ /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */
+ ((po < 0 && (pg == PROTO_X || pg == PROTO_XC)) ||
+ (po > -1 && (po == PROTO_X || po == PROTO_XC)))
+ ) {
+ printf(
+"Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
+ );
+ x = -9;
+ goto xgetx;
+ }
+ }
+#endif /* CK_XYZ */
+
+#ifdef RECURSIVE
+ if (pv[SND_REC].ival > 0) { /* RECURSIVE */
+ recursive = 1;
+ pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames too */
+ }
+#endif /* RECURSIVE */
+
+ if (pv[SND_PIP].ival > -1) {
+ g_usepipes = usepipes;
+ usepipes = pv[SND_PIP].ival;
+ }
+
+ /* Save global protocol parameters */
+
+ g_proto = protocol;
+#ifdef CK_LABELED
+ g_lf_opts = lf_opts; /* Save labeled transfer options */
+#endif /* CK_LABELED */
+ g_urpsiz = urpsiz; /* Receive packet length */
+ g_spsizf = spsizf; /* Send packet length flag */
+ g_spsiz = spsiz; /* Send packet length */
+ g_spsizr = spsizr; /* etc etc */
+ g_spmax = spmax;
+ g_wslotr = wslotr;
+ g_prefixing = prefixing;
+ g_fncact = fncact;
+ g_fncnv = fncnv;
+ g_fnspath = fnspath;
+ g_fnrpath = fnrpath;
+ g_xfrxla = xfrxla;
+
+ if (pv[SND_PRO].ival > -1) { /* Change according to switch */
+ protocol = pv[SND_PRO].ival;
+ if (ptab[protocol].rpktlen > -1) /* copied from initproto() */
+ urpsiz = ptab[protocol].rpktlen;
+ if (ptab[protocol].spktflg > -1)
+ spsizf = ptab[protocol].spktflg;
+ if (ptab[protocol].spktlen > -1) {
+ spsiz = ptab[protocol].spktlen;
+ if (spsizf)
+ spsizr = spmax = spsiz;
+ }
+ if (ptab[protocol].winsize > -1)
+ wslotr = ptab[protocol].winsize;
+ if (ptab[protocol].prefix > -1)
+ prefixing = ptab[protocol].prefix;
+ if (ptab[protocol].fnca > -1)
+ fncact = ptab[protocol].fnca;
+ if (ptab[protocol].fncn > -1)
+ fncnv = ptab[protocol].fncn;
+ if (ptab[protocol].fnsp > -1)
+ fnspath = ptab[protocol].fnsp;
+ if (ptab[protocol].fnrp > -1)
+ fnrpath = ptab[protocol].fnrp;
+ }
+ debug(F101,"xget protocol","",protocol);
+ debug(F111,"xget cmarg2",cmarg2,xfermode);
+
+ g_xfermode = xfermode;
+ g_binary = binary;
+ if (pv[SND_BIN].ival > 0) { /* Change according to switch */
+ xfermode = XMODE_M;
+ binary = XYFT_B; /* FILE TYPE BINARY */
+ omode = GMOD_BIN; /* O-Packet mode */
+ debug(F101,"doxget /BINARY xfermode","",xfermode);
+ } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */
+ xfermode = XMODE_M;
+ binary = XYFT_T;
+ omode = GMOD_TXT;
+ debug(F101,"doxget /TEXT xfermode","",xfermode);
+ } else if (pv[SND_IMG].ival > 0) {
+ xfermode = XMODE_M;
+#ifdef VMS
+ binary = XYFT_I;
+#else
+ binary = XYFT_B;
+#endif /* VMS */
+ omode = GMOD_TXT;
+ debug(F101,"doxget /IMAGE xfermode","",xfermode);
+ }
+#ifdef CK_LABELED
+ else if (pv[SND_LBL].ival > 0) {
+ xfermode = XMODE_M;
+ binary = XYFT_L;
+ omode = GMOD_LBL;
+ debug(F101,"doxget /LABELED xfermode","",xfermode);
+ }
+#endif /* CK_LABELED */
+ debug(F101,"xget binary","",binary);
+ debug(F101,"xget omode","",omode);
+
+ if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */
+ xfrxla = 0; /* Don't translate character sets */
+
+#ifdef PIPESEND
+ if (pv[SND_FLT].ival > 0)
+ makestr(&rcvfilter,pv[SND_FLT].sval);
+#endif /* PIPESEND */
+
+#ifdef CK_TMPDIR
+ if (pv[SND_MOV].ival > 0) {
+ int len;
+ char * p = pv[SND_MOV].sval;
+#ifdef CK_LOGIN
+ if (isguest) {
+ printf("?Sorry, /MOVE-TO not available to guests\n");
+ x = -9;
+ goto xgetx;
+ }
+#endif /* CK_LOGIN */
+ len = strlen(p);
+ if (!isdir(p)) { /* Check directory */
+#ifdef CK_MKDIR
+ char * s = NULL;
+ s = (char *)malloc(len + 4);
+ if (s) {
+ strcpy(s,p); /* safe */
+#ifdef datageneral
+ if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
+#else
+ if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
+#endif /* datageneral */
+ s[len++] = 'X';
+ s[len] = NUL;
+ x = zmkdir(s);
+ free(s);
+ if (x < 0) {
+ printf("?Can't create \"%s\"\n",p);
+ x = -9;
+ goto xgetx;
+ }
+ }
+#else
+ printf("?Directory \"%s\" not found\n",p);
+ x = -9;
+ goto xgetx;
+#endif /* CK_MKDIR */
+ }
+ zfnqfp(p,LINBUFSIZ,line);
+ makestr(&rcv_move,line);
+ }
+#endif /* CK_TMPDIR */
+
+ if (pv[SND_REN].ival > 0) { /* /RENAME-TO:name */
+ char * p = pv[SND_REN].sval;
+#ifdef CK_LOGIN
+ if (isguest) {
+ printf("?Sorry, /RENAME-TO not available to guests\n");
+ x = -9;
+ goto xgetx;
+ }
+#endif /* CK_LOGIN */
+ if (!p) p = "";
+ if (!*p) {
+ printf("?New name required for /RENAME\n");
+ x = -9;
+ goto xgetx;
+ }
+ p = brstrip(p);
+ makestr(&rcv_rename,p);
+ debug(F110,"xget rcv_rename","",0);
+ }
+
+#ifdef CALIBRATE
+ if (pv[SND_CAL].ival > 0)
+ calibrate = (CK_OFF_T)1;
+#endif /* CALIBRATE */
+ g_displa = fdispla;
+ if (pv[SND_SHH].ival > 0)
+ fdispla = 0;
+ debug(F101,"xget display","",fdispla);
+
+ if (pv[SND_NAM].ival > -1) { /* /FILENAMES */
+ g_fncnv = fncnv; /* Save global value */
+ fncnv = pv[SND_NAM].ival;
+ debug(F101,"xsend fncnv","",fncnv);
+ /* We should also handle O packet filename option here */
+ /* but we don't really need to since WHATAMI already handles it */
+ }
+ if (pv[SND_PTH].ival > -1) { /* PATHNAMES */
+ g_rpath = fnrpath; /* Save global values */
+ fnrpath = pv[SND_PTH].ival;
+ debug(F101,"xsend fnrpath","",fnrpath);
+#ifndef NZLTOR
+ if (fnrpath != PATH_OFF) {
+ g_fncnv = fncnv;
+ fncnv = XYFN_L;
+ debug(F101,"xsend fncnv","",fncnv);
+ }
+ /* We should also handle O packet pathname option here */
+ /* but we don't really need to since WHATAMI already handles it */
+#endif /* NZLTOR */
+ }
+
+ /* Set protocol start state */
+
+ if (opkt) { /* Extended GET Options*/
+ sstate = (CHAR) 'o';
+ oopts = 0;
+ if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
+ if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
+ if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
+ } else if (rcvcmd)
+ sstate = (CHAR) 'v'; /* RECEIVE or CRECEIVE */
+ else if (pv[SND_DEL].ival > 0)
+ sstate = (CHAR) 'h'; /* GET /DELETE (= RETRIEVE) */
+ else if (pv[SND_RES].ival > 0)
+ sstate = (CHAR) 'j'; /* GET /RECOVER (= REGET) */
+ else
+ sstate = (CHAR) 'r'; /* Regular GET */
+ getcmd = 1;
+ debug(F000,"xget sstate","",sstate);
+#ifdef MAC
+ what = W_RECV;
+ scrcreate();
+#endif /* MAC */
+ if (local) {
+ if (pv[SND_SHH].ival != 0)
+ displa = 1;
+ if (protocol == PROTO_K) /* fdc 20070108 */
+ ttflui();
+ }
+ x = 0;
+#ifdef PIPESEND
+ if (pipesend)
+ goto xgetx;
+#endif /* PIPESEND */
+
+#ifdef CK_TMPDIR
+/*
+ cmarg2 is also allowed to be a device or directory name;
+ even the name of a directory that doesn't exist.
+*/
+ y = strlen(cmarg2);
+ debug(F111,"xget strlen(cmarg2)",cmarg2,y);
+ if ((y > 0) &&
+#ifdef OS2
+ ((isalpha(cmarg2[0]) &&
+ cmarg2[1] == ':' &&
+ cmarg2[2] == NUL) ||
+ (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
+ isdir(cmarg2))
+#else
+#ifdef UNIXOROSK
+ (cmarg2[y-1] == '/' || isdir(cmarg2))
+#else
+#ifdef VMS
+ (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
+#else
+#ifdef STRATUS
+ (cmarg2[y-1] == '>' || isdir(cmarg2))
+#else
+#ifdef datageneral
+ (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
+#else
+ isdir(cmarg2)
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* UNIXOROSK */
+#endif /* OS2 */
+ ) {
+ debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
+ if (!f_tmpdir) {
+ int x;
+ s = zgtdir();
+ if (s) {
+ ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
+ f_tmpdir = 1; /* and that we did this */
+ } else {
+ printf("?Can't get current directory\n");
+ cmarg2 = "";
+ f_tmpdir = 0;
+ x = -9;
+ goto xgetx;
+ }
+#ifdef CK_MKDIR
+ x = zchki(cmarg2); /* Does as-name exist? */
+ if (x == -1) { /* Doesn't exist */
+ char * p = NULL; /* Try to create it */
+ x = strlen(cmarg2);
+ if ((p = (char *)malloc(x+4))) {
+ sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */
+ x = zmkdir(p);
+ free(p);
+ if (x < 0) {
+ printf("?Can't create %s\n",cmarg2);
+ x = -9;
+ goto xgetx;
+ }
+ }
+ }
+#endif /* CK_MKDIR */
+ if (!zchdir(cmarg2)) { /* change to given disk/directory, */
+ printf("?Can't access %s\n",cmarg2);
+ x = -9;
+ goto xgetx;
+ }
+ cmarg2 = "";
+ }
+ }
+#endif /* CK_TMPDIR */
+
+ ckstrncpy(fspec,cmarg,CKMAXPATH); /* Note - this is a REMOTE filespec */
+ debug(F111,"xget fspec",fspec,fspeclen);
+ debug(F110,"xget cmarg2",cmarg2,0);
+
+ xgetx:
+ for (i = 0; i < SND_MAX; i++)
+ if (pv[i].sval)
+ free(pv[i].sval);
+ return(x);
+}
+#endif /* NOXFER */
+
+#ifndef NOSPL
+
+/*
+ D O G T A -- Do _GETARGS or _PUTARGS Command.
+
+ Used by XIF, FOR, WHILE, and SWITCH, each of which are implemented as
+ 2-level macros; the first level defines the macro, the second runs it.
+ This routine hides the fact that they are macros by importing the
+ macro arguments (if any) from two levels up, to make them available
+ in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
+ loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
+ _PUTARGS is in case we changed any of these variables or used SHIFT
+ on them, so the new values won't be lost as we pop up the stack.
+*/
+int
+dogta(cx) int cx; {
+ int i, n;
+ char c, *p, mbuf[4];
+ extern int topargc, cmdint;
+ extern char ** topxarg;
+
+ if ((y = cmcfm()) < 0)
+ return(y);
+ debug(F101,"dogta cx","",cx);
+ debug(F101,"dogta maclvl","",maclvl);
+ if (cx == XXGTA) {
+ debug(F101,"dogta _GETARGS maclvl","",maclvl);
+ } else if (cx == XXPTA) {
+ debug(F101,"dogta _PUTARGS maclvl","",maclvl);
+ } else {
+ return(-2);
+ }
+ if (maclvl < 1)
+ return(success = 0);
+
+ /* Make new copies of macro arguments /%0..9 */
+
+ mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
+
+ if (cx == XXPTA) { /* Go NOINT because _PUTARGS */
+ if (cmdint) /* temporarily changes maclvl. */
+ connoi(); /* Interrupts OFF. */
+ }
+ for (i = 0; i < 10; i++) { /* For all args */
+ c = (char) (i + '0'); /* Make name */
+ mbuf[1] = (char) c; /* Insert digit */
+ if (cx == XXGTA) { /* Get arg from level-minus-2 */
+ if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
+ else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
+ addmac(mbuf,p);
+#ifdef COMMENT
+ if (maclvl > 1)
+ makestr(&(m_line[maclvl]),m_line[maclvl-2]);
+#endif /* COMMENT */
+ } else if (cx == XXPTA) { /* Put args level+2 */
+ maclvl -= 2; /* This is gross, it's because we're */
+ addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */
+ maclvl += 2; /* and addmac() uses maclvl. */
+ count[cmdlvl - 2] = count[cmdlvl];
+ intime[cmdlvl - 2] = intime[cmdlvl];
+ inpcas[cmdlvl - 2] = inpcas[cmdlvl];
+ takerr[cmdlvl - 2] = takerr[cmdlvl];
+ merror[cmdlvl - 2] = merror[cmdlvl];
+ xquiet[cmdlvl - 2] = xquiet[cmdlvl];
+ xvarev[cmdlvl - 2] = xvarev[cmdlvl];
+ } else return(success = 0); /* Bad call to this routine */
+ }
+ if (cx == XXPTA) { /* Restore interrupts if we */
+ if (cmdint) /* turned them off above. */
+ conint(trap,stptrap);
+ }
+ /* Now take care of the argument vector array \&_[], \v(return), */
+ /* and \v(argc) by just copying the pointers. */
+
+ if (cx == XXGTA) { /* GETARGS from 2 levels up */
+ if (maclvl == 1) {
+ a_ptr[0] = topxarg; /* \&_[] array */
+ a_dim[0] = topargc - 1; /* Dimension doesn't include [0] */
+ m_xarg[maclvl] = topxarg;
+ n_xarg[maclvl] = topargc; /* But \v(argc) does include \%0 */
+ macargc[maclvl] = topargc;
+ makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
+ } else {
+ a_ptr[0] = m_xarg[maclvl-2];
+ a_dim[0] = n_xarg[maclvl-2];
+ m_xarg[maclvl] = m_xarg[maclvl-2];
+ n_xarg[maclvl] = n_xarg[maclvl-2];
+ macargc[maclvl] = n_xarg[maclvl-2];
+ makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
+
+ }
+ } else { /* PUTARGS 2 levels up */
+ if (maclvl > 1) {
+ a_ptr[0] = m_xarg[maclvl];
+ m_xarg[maclvl-2] = m_xarg[maclvl];
+ a_dim[0] = n_xarg[maclvl];
+ n_xarg[maclvl-2] = n_xarg[maclvl];
+ macargc[maclvl-2] = n_xarg[maclvl];
+ }
+ }
+ return(1); /* Internal command - don't change success */
+}
+#endif /* NOSPL */
+
+#ifndef NOSPL
+/*
+ Do the GOTO and [_]FORWARD commands.
+ s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
+*/
+
+int
+dogoto(s, cx) char *s; int cx; {
+ int i, j, x, y, z, bc;
+ int empty = 0, stopflg = 0;
+ char * cmd; /* Name of this command */
+ char tmplbl[LBLSIZ+1], *lp; /* Current label from command stream */
+ char tmp2[LBLSIZ+1]; /* SWITCH label conversion buffer */
+ char tmp3[LBLSIZ+1]; /* Target label */
+
+ stopflg = (cx == XXXFWD); /* _FORWARD (used in SWITCH) */
+ bc = 0; /* Brace counter */
+
+ cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
+ if (!s) s = "";
+ if (!*s) empty = 1;
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"GOTO command",cmd,cx);
+ debug(F101,"GOTO cmdlvl","",cmdlvl);
+ debug(F101,"GOTO maclvl","",maclvl);
+ debug(F101,"GOTO tlevel","",tlevel);
+ debug(F111,"GOTO target",s,empty);
+ }
+#endif /* DEBUG */
+ debug(F110,cmd,s,0);
+ x = ckstrncpy(tmp3+1,s,LBLSIZ);
+ debug(F101,"GOTO target len","",x);
+ debug(F101,"GOTO target at x","",s[x]);
+ if (s[x]) {
+ debug(F100,"GOTO target overflow","",0);
+ printf("?GOTO target or SWITCH case label too long\n");
+ if (stopflg) dostop(); /* If in SWITCH return to prompt */
+ return(success = 0);
+ }
+ s = tmp3+1;
+ if (*s != ':') { /* Make copy of label */
+ tmp3[0] = ':'; /* guaranteed to start with ":" */
+ s--;
+ }
+ if (!stopflg && !empty) {
+ if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
+ printf("?Bad label syntax - '%s'\n",s);
+ if (stopflg) dostop(); /* If in SWITCH return to prompt */
+ return(success = 0);
+ }
+ }
+ if (cmdlvl == 0) {
+ printf("?Sorry, %s only works in a command file or macro\n",cmd);
+ return(success = 0);
+ }
+ y = strlen(s); /* y = length of target label */
+ debug(F111,cmd,s,y);
+
+ while (cmdlvl > 0) { /* As long as not at top level... */
+ if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
+ int i, m, flag;
+ char *xp, *tp;
+
+ /* GOTO: rewind the macro; FORWARD: start at current position */
+
+ lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
+ m = (int)strlen(lp);
+ debug(F111,"GOTO in macro",lp,m);
+
+ flag = 1; /* flag for valid label position */
+ for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
+ if (*lp == '{') /* But only at this level */
+ bc++; /* Anything inside braces is off */
+ else if (*lp == '}') /* limits. */
+ bc--;
+ if (stopflg && bc > 0) /* This is good for SWITCH */
+ continue; /* but interferes with WHILE, etc. */
+ if (*lp == ',') {
+ flag = 1;
+ continue;
+ }
+ if (flag) { /* If in valid label position */
+ if (*lp == SP) /* eat leading spaces */
+ continue;
+ if (*lp != ':') { /* Look for label introducer */
+ flag = 0; /* this isn't it */
+ continue; /* keep looking */
+ }
+ }
+ if (!flag) /* We don't have a label */
+ continue; /* so keep looking... */
+ xp = lp; tp = tmplbl; /* Copy the label from the macro */
+ j = 0; /* to make it null-terminated */
+ while ((*tp = *xp)) {
+ if (j++ > LBLSIZ-1) { /* j = length of word from macro */
+ printf("?GOTO target or SWITCH case label too long\n");
+ if (stopflg) dostop(); /* Return to prompt */
+ return(success = 0);
+ }
+ if (!*tp || *tp == ',') /* Look for end of word */
+ break;
+ else tp++, xp++; /* Next character */
+ }
+ *tp = NUL; /* In case we stopped early */
+ /* Now do caseless string comparison, using longest length */
+ debug(F111,"macro GOTO label",s,y);
+ debug(F111,"macro target label",tmplbl,j);
+ if (stopflg) { /* Allow variables as SWITCH labels */
+ int n = LBLSIZ - 1;
+ char * p = tmp2;
+ zzstring(tmplbl,&p,&n);
+ if (n < 0) {
+ printf("?GOTO target or SWITCH case label too long\n");
+ if (stopflg) dostop(); /* Return to prompt */
+ return(0);
+ }
+ ckstrncpy(tmplbl,tmp2,LBLSIZ);
+ }
+ debug(F111,"GOTO s",s,y);
+ debug(F111,"GOTO tmplbl",tmplbl,j);
+ debug(F111,"GOTO empty",ckitoa(stopflg),empty);
+
+ if (empty) { /* Empty target */
+ z = (!strcmp(s,":") && /* String is empty */
+ /* and Label is ":" or ":*"... */
+ (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*")))
+ ? 0 : 1;
+ debug(F111,"GOTO","A",z);
+ } else if (stopflg) {
+ z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
+ debug(F111,"GOTO","B",z);
+ } else {
+ z = (stopflg && inpcas[cmdlvl]) ?
+ strcmp(s,tmplbl) :
+ ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
+ debug(F111,"GOTO","C",z);
+ }
+ if (!z) {
+ break;
+ } else if (stopflg &&
+ !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) {
+ debug(F100,"GOTO DEFAULT","",0);
+ break;
+ } else {
+ flag = 0;
+ }
+ }
+ debug(F111,"GOTO macro i",cmd,i);
+ debug(F111,"GOTO macro m",cmd,m);
+ if (i >= m) { /* Didn't find the label */
+ debug(F101,"GOTO failed cmdlvl","",cmdlvl);
+#ifdef COMMENT
+ /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */
+ if (stopflg)
+ return(0);
+#endif /* COMMENT */
+ if ((maclvl > 0) &&
+ (m_arg[maclvl-1][0]) &&
+ (cmdstk[cmdlvl].src == CMD_MD) &&
+ (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_for",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
+ dogta(XXPTA); /* Restore args */
+ debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
+ popclvl(); /* Pop an extra level */
+ }
+ debug(F101,"GOTO popping","",cmdlvl);
+ if (!popclvl()) { /* pop up to next higher level */
+ printf("?Label '%s' not found\n",s); /* if none */
+ return(0); /* Quit */
+ } else if (stopflg) { /* SWITCH no case label match */
+ return(0); /* and no DEFAULT lable. */
+ } else {
+ continue; /* otherwise look again */
+ }
+ }
+ debug(F110,"GOTO found macro label",tmplbl,0);
+ macp[maclvl] = lp; /* set macro buffer pointer */
+ return(1);
+ } else if (cmdstk[cmdlvl].src == CMD_TF) {
+ x = 0; /* GOTO issued in take file */
+ debug(F111,"GOTO in TAKE file",cmd,cx);
+ if (cx == XXGOTO) { /* If GOTO, but not FORWARD, */
+ rewind(tfile[tlevel]); /* search file from beginning */
+ tfline[tlevel] = 0;
+ }
+ while (! feof(tfile[tlevel])) {
+#ifdef COMMENT
+/* This is wrong - it lets us jump to labels inside inferior blocks */
+ tfline[tlevel]++;
+ if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
+#else
+ if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0)
+#endif /* COMMENT */
+ break; /* If no more, done, label not found */
+ lp = line; /* Got line */
+ while (*lp == SP || *lp == HT)
+ lp++; /* Strip leading whitespace */
+ if (*lp != ':') continue; /* Check for label introducer */
+ while (*(lp+1) == SP) { /* Remove space between : and name */
+ *(lp+1) = ':';
+ lp++; /* Strip leading whitespace */
+ }
+ tp = lp; /* Get end of word */
+ j = 0;
+ while (*tp) { /* And null-terminate it */
+ if (*tp < 33) {
+ *tp = NUL;
+ break;
+ } else tp++, j++;
+ }
+ if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
+ x = 1; /* Got it */
+ break; /* done. */
+ } else if (stopflg &&
+ !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
+ x = 1;
+ break;
+ }
+ }
+ if (x == 0) { /* If not found, print message */
+ debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
+ if (stopflg)
+ return(0);
+ if (!popclvl()) { /* pop up to next higher level */
+ printf("?Label '%s' not found\n",s); /* if none */
+ return(0); /* quit */
+ } else continue; /* otherwise look again */
+ }
+ return(x); /* Send back return code */
+ }
+ }
+ printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
+ return(0);
+}
+#endif /* NOSPL */
+
+/* Finish parsing and do the IF, XIF, and WHILE commands */
+
+#ifndef NOSPL
+
+/* C H K V A R -- Check (if it's a) Variable */
+
+
+#ifdef OLDCHKVAR
+/*
+ Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
+ have backslashes in them. How do we know if a backslash in a filename is a
+ directory separator, or if it's a Kermit backslash? This routine does a
+ rough syntax check of the next few characters and if it looks like it MIGHT
+ be a variable, then it tries to evaluate it, and if the result is not empty,
+ we say it's a variable, although sometimes it might not be -- some cases are
+ truly ambiguous. For example there might a DOS directory called \%a, and
+ we also have a variable with the same name. This is all for the sake of not
+ having to tell PC users that they have to double all backslashes in file
+ and directory names.
+*/
+#else
+/*
+ Somewhat less crude & disgusting. The previous method was nondeterministic
+ and (worse) it interfered with macro argument passing. So now we only
+ check the syntax of backslash-items to see if they are variables, but we
+ do NOT check their values.
+*/
+#endif /* OLDCHKVAR */
+/*
+ Call with a string pointer pointing at the backslash of the purported
+ variable. Returns 1 if it has the syntax of a variable, 0 if not.
+*/
+int
+chkvar(s) char *s; {
+ int z = 0; /* Return code - assume failure. */
+ if (!s) s = ""; /* Watch our for null pointers. */
+ if (!*s) return(0); /* Empty arg so not a variable. */
+ if (*s == CMDQ) { /* Object begins with backslash. */
+ char c;
+ c = s[1]; /* Character following backslash. */
+ if (c) {
+ int t = 0;
+ if (c == CMDQ) /* Quoted backslash */
+ return(1);
+ c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
+ if (c == '%') { /* Simple variable */
+#ifdef OLDCHKVAR
+ t = 1;
+#else
+ return(1);
+#endif /* OLDCHKVAR */
+ } else if (c == '&') { /* Array */
+ if (!s[2]) return(0);
+ if (s[3] == '[')
+ t = ckindex("]",s,4,0,1);
+#ifndef OLDCHKVAR
+ return((t > 0) ? 1 : 0);
+#endif /* OLDCHKVAR */
+ } else if (c == '$' || /* Environment variable */
+ c == 'V' || /* Built-in variable */
+ c == 'M') { /* Macro name */
+ t = (s[2] == '(');
+#ifndef OLDCHKVAR
+ return((t > 0) ? 1 : 0);
+#endif /* OLDCHKVAR */
+ } else if (c == 'F') { /* Function reference */
+ /* Don't actually call it - it might have side effects */
+ int x;
+ if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */
+ if ((x = ckindex(")",s,x,0,1)))
+ z = 1;
+ /* Insert a better syntax check here if necessary */
+ }
+#ifdef OLDCHKVAR
+ if (t) {
+ t = 255; /* This lets us test \v(xxx) */
+ lp = line; /* and even \f...(xxx) */
+ zzstring(s,&lp,&t); /* Evaluate it, whatever it is. */
+ t = strlen(line); /* Get its length. */
+ debug(F111,"chkvar",line,t);
+ z = t > 0; /* If length > 0, it's defined */
+ }
+#endif /* OLDCHKVAR */
+ }
+ }
+ return(z);
+}
+
+/* B O O L E X P -- Evaluate a Boolean expression */
+
+#define BOOLLEN 1024
+static char boolval[BOOLLEN];
+
+int
+boolexp(cx) int cx; {
+ int x, y, z; char *s, *p;
+ int parens = 0, pcount = 0, ecount = 0;
+ char *q, *bx;
+ struct FDB kw, nu;
+#ifdef FNFLOAT
+ struct FDB fl;
+ CKFLOAT f1 = 0.0, f2 = 0.0;
+ int f1flag = 0, f2flag = 0;
+#endif /* FNFLOAT */
+#ifdef OS2
+ extern int keymac;
+#endif /* OS2 */
+
+ not = 0; /* Flag for whether "NOT" was seen */
+ z = 0; /* Initial IF condition */
+ ifargs = 0; /* Count of IF condition words */
+ bx = boolval; /* Initialize boolean value */
+ *bx = NUL;
+
+ ifagain:
+ cmfdbi(&kw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Number, numeric-valued variable, Boolean expression, or keyword",
+ "", /* default */
+ "", /* addtl string data */
+ nif, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = silent */
+ xxstring, /* Processing function */
+ iftab, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* 2nd FDB - An integer */
+ _CMNUM, /* fcode */
+ "", /* hlpmsg */
+ "", /* Default */
+ "", /* addtl string data */
+ 0,
+ 0,
+ xxstring,
+ NULL,
+#ifdef FNFLOAT
+ &fl
+#else
+ NULL
+#endif /* FNFLOAT */
+ );
+#ifdef FNFLOAT
+ cmfdbi(&fl, /* A floating-point number */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+#endif /* FNFLOAT */
+ x = cmfdb(&kw); /* Parse a keyword or a number */
+ debug(F111,"boolval cmfdb","",x);
+ if (x < 0) {
+ if (x == -3)
+ x = -2;
+ return(x);
+ }
+ debug(F111,"boolval switch","",cmresult.fcode);
+ switch (cmresult.fcode) { /* What did we get? */
+ case _CMFLD: { /* A "field" */
+ int i;
+ char * s;
+ s = cmresult.sresult;
+/*
+ C-Kermit 9.0: This allows a macro name to serve as an
+ IF condition without having to enclose it in \m(...).
+*/
+ if (
+#ifdef FNFLOAT
+ !isfloat(cmresult.sresult,0) /* Not a number */
+#else
+ !chknum(cmresult.sresult) /* Not a number */
+#endif /* FNFLOAT */
+ ) {
+ i = mlook(mactab,cmresult.sresult,nmac); /* Look it up */
+ if (i > -1) /* in the macro table */
+ s = mactab[x].mval; /* and get its value */
+ else /* Otherwise if no such macro */
+ s = "0"; /* evaluate as FALSE. */
+ }
+#ifdef FNFLOAT
+ if (isfloat(s,0)) { /* A floating-point number? */
+ f1 = floatval; /* Yes, get its value */
+ f1flag = 1; /* remember we did this */
+ ifc = 9999; /* Set special "if-code" */
+ }
+#else
+ if (chknum(s)) {
+ cmresult.nresult = atoi(s);
+ ifc = 9999;
+ break;
+ }
+#endif /* FNFLOAT */
+ else
+ return(-2);
+ }
+ case _CMNUM: /* A number... */
+ ifc = 9999; /* Set special "if-code" */
+ break;
+ case _CMKEY: /* A keyword */
+ ifc = cmresult.nresult; /* Get if-code */
+ break;
+ default:
+ return(-2);
+ }
+ switch (ifc) { /* set z = 1 for true, 0 for false */
+ case 9999: /* Number */
+#ifdef FNFLOAT
+ if (f1flag) {
+ z = (f1 == 0.0) ? 0 : 1;
+ } else
+#endif /* FNFLOAT */
+ z = (cmresult.nresult == 0) ? 0 : 1;
+ break;
+ case XXIFLP: /* Left paren */
+ if (pcount == 0 && ifargs > 0)
+ return(-2);
+ parens = 1;
+ pcount++;
+ ifargs++;
+ *bx++ = '(';
+ goto ifagain;
+ case XXIFRP: /* Right paren */
+ if (!parens)
+ return(-2);
+ if (--pcount < 0)
+ return(-2);
+ ifargs++;
+ *bx++ = ')';
+ *bx = NUL;
+ if (pcount == 0)
+ goto ifend;
+ goto ifagain;
+ case XXIFAN: /* AND (&&) */
+ ifargs++;
+ if (!ecount)
+ return(-2);
+ *bx++ = '&';
+ goto ifagain;
+ case XXIFOR: /* OR (||) */
+ ifargs++;
+ if (!ecount)
+ return(-2);
+ *bx++ = '|';
+ goto ifagain;
+ case XXIFNO: /* IF NOT [ NOT [ NOT ... ] ] */
+ if (bx > boolval) { /* evala() doesn't like cascaded */
+ if (*(bx-1) == '!') { /* unary operators... */
+ *(bx-1) = NUL; /* So here, two wrongs make a right. */
+ bx--;
+ } else {
+ *bx++ = '!';
+ }
+ } else {
+ *bx++ = '!';
+ }
+ ifargs++;
+ goto ifagain;
+ case XXIFTR: /* IF TRUE */
+ z = 1;
+ debug(F101,"if true","",z);
+ ifargs += 1;
+ break;
+ case XXIFNT: /* IF FALSE */
+ z = 0;
+ debug(F101,"if true","",z);
+ ifargs += 1;
+ break;
+ case XXIFSU: /* IF SUCCESS */
+ z = ( success != 0 ) ? 1 : 0;
+ debug(F101,"if success","",z);
+ ifargs += 1;
+ break;
+ case XXIFFA: /* IF FAILURE */
+ z = ( success == 0 ) ? 1 : 0;
+ debug(F101,"if failure","",z);
+ ifargs += 1;
+ break;
+
+ case XXIFDE: /* IF DEFINED */
+ if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
+ return((x == -3) ? -2 : x);
+
+ if (*s == CMDQ) {
+ char * lp;
+ char line[256];
+ int t, x;
+ if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */
+ extern struct keytab fnctab[];
+ extern int nfuncs;
+ ckstrncpy(line,s+2,256);
+ if (line[0]) {
+ lp = ckstrchr(line,'(');
+ if (lp) *lp = NUL;
+ x = lookup(fnctab,line,nfuncs,&t);
+ z = x > -1;
+ }
+ debug(F111,"if defined function",line,z);
+ } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */
+ extern struct keytab vartab[];
+ extern int nvars;
+ z = 0;
+ if (*(s+2) == '(') {
+ ckstrncpy(line,s+3,256);
+ if (line[0]) {
+ lp = ckstrchr(line,')');
+ if (lp) *lp = NUL;
+ x = lookup(vartab,line,nvars,&t);
+ z = x > -1;
+ if (z) { /* 8.0.203 */
+ int t; /* It must have a value to succeed */
+ t = 255; /* as in C-Kermit 6.0 and 7.0 */
+ lp = line; /* (this was broken in 8.0.200-201) */
+ zzstring(s,&lp,&t);
+ t = strlen(line);
+ z = line[0] ? 1 : 0;
+ }
+ }
+ }
+ debug(F111,"if defined variable",line,z);
+ } else {
+ z = chkvar(s); /* Starts with backslash */
+ if (z > 0) { /* Yes... */
+ t = 255; /* than buffer so if zzstring fails */
+ lp = line; /* check for that -- overflow means */
+ line[0] = NUL; /* the quantity is defined. */
+ x = zzstring(s,&lp,&t);
+ if ((x < 0 && t != 255) || !line[0])
+ z = 0;
+ debug(F111,"if defined zzstring",line,z);
+ debug(F101,"if defined zzstring t","",t);
+ }
+ }
+ } else {
+ z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
+ }
+ debug(F111,"if defined final",s,z);
+ ifargs += 2;
+ break;
+
+ case XXIFDC: { /* IF DECLARED */
+ char * lp;
+ char line[32];
+ int j, k, t, x;
+ if ((x = cmfld("Array name","",&s,NULL)) < 0)
+ return((x == -3) ? -2 : x);
+ if (*s == CMDQ) {
+ if (*(s+1) != '&') {
+ t = 31;
+ lp = line;
+ line[0] = NUL;
+ x = zzstring(s,&lp,&t);
+ s = line;
+ }
+ }
+ z = 0;
+ if ((x = arraybounds(s,&j,&k)) > -1) {
+ if (a_ptr[x]) {
+ if (j < 1)
+ z = 1;
+ else if (j <= a_dim[x])
+ z = 1;
+ if (z == 1 && k > a_dim[x])
+ z = 0;
+ }
+ }
+ break;
+ }
+ case XXIFBG: /* IF BACKGROUND */
+ case XXIFFG: /* IF FOREGROUND */
+ bgchk(); /* Check background status */
+ if (ifc == XXIFFG) /* Foreground */
+ z = pflag ? 1 : 0;
+ else z = pflag ? 0 : 1; /* Background */
+ ifargs += 1;
+ break;
+
+ case XXIFCO: /* IF COUNT */
+ z = ( --count[cmdlvl] > 0 );
+ if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
+ debug(F101,"if count","",z);
+ ifargs += 1;
+ break;
+
+ case XXIFEX: /* IF EXIST */
+#ifdef CK_TMPDIR
+ case XXIFDI: /* IF DIRECTORY */
+#endif /* CK_TMPDIR */
+ case XXIFAB: /* IF ABSOLUTE */
+ case XXIFLN: /* IF LINK */
+ if ((x = cmfld(
+ ((ifc == XXIFDI) ? "Directory name" : "File"),
+ "",&s,
+#ifdef OS2
+ NULL /* This allows \'s in filenames */
+#else
+ xxstring
+#endif /* OS2 */
+ )) < 0) {
+ if (x == -3) {
+ extern int cmflgs;
+ if (cmflgs == 1) {
+ printf("?File or directory name required\n");
+ return(-9);
+ }
+ } else return(x);
+ }
+ s = brstrip(s);
+#ifdef UNIX
+ if (ifc == XXIFLN) {
+ z = isalink(s);
+ } else
+#endif /* UNIX */
+ if (ifc == XXIFAB) {
+ z = isabsolute(s);
+ } else if (ifc == XXIFEX) {
+ z = (zgetfs(s) > -1L);
+ debug(F101,"if exist 1","",z);
+#ifdef OS2
+ if (!z) { /* File not found. */
+ int t; /* Try expanding variables */
+ t = LINBUFSIZ-1; /* and looking again. */
+ lp = line;
+ zzstring(s,&lp,&t);
+ s = line;
+ z = ( zchki(s) > -1L );
+ debug(F101,"if exist 2","",z);
+ }
+#endif /* OS2 */
+#ifdef CK_TMPDIR
+ } else {
+#ifdef VMS
+ z = (zchki(s) == -2)
+#else
+/* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
+ z = isdir(s)
+#ifdef OS2
+ || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
+#endif /* OS2 */
+#endif /* VMS */
+ ;
+ debug(F101,"if directory 1","",z);
+
+ if (!z) { /* File not found. */
+ int t; /* Try expanding variables */
+ t = LINBUFSIZ-1; /* and looking again. */
+ lp = line;
+ zzstring(s,&lp,&t);
+ s = line;
+ z = isdir(s)
+#ifdef OS2
+ || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
+#endif /* OS2 */
+ ;
+ debug(F101,"if directory 2","",z);
+ }
+#endif /* CK_TMPDIR */
+ }
+ ifargs += 2;
+ break;
+
+ case XXIFEQ: /* IF EQUAL (string comparison) */
+ case XXIFLL: /* IF Lexically Less Than */
+ case XXIFLG: /* If Lexically Greater Than */
+ if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Text required\n");
+ return(-9);
+ } else return(x);
+ }
+ s = brstrip(s); /* Strip braces */
+ x = (int)strlen(s);
+ if (x > LINBUFSIZ-1) {
+ printf("?IF: strings too long\n");
+ return(-2);
+ }
+ lp = line; /* lp points to first string */
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Text required\n");
+ return(-9);
+ } else return(y);
+ }
+ s = brstrip(s);
+ y = (int)strlen(s);
+ if (x + y + 2 > LINBUFSIZ) {
+ printf("?IF: strings too long\n");
+ return(-2);
+ }
+ tp = lp + x + 2; /* tp points to second string */
+ strcpy(tp,s); /* safe (checked) */
+ x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
+ switch (ifc) {
+ case XXIFEQ: /* IF EQUAL (string comparison) */
+ z = (x == 0);
+ break;
+ case XXIFLL: /* IF Lexically Less Than */
+ z = (x < 0);
+ break;
+ case XXIFLG: /* If Lexically Greater Than */
+ z = (x > 0);
+ break;
+ }
+ debug(F101,"IF EQ result","",z);
+ ifargs += 3;
+ break;
+
+ case XXIFVE: /* IF VERSION */
+ case XXIFAE: /* IF (arithmetically) = */
+ case XXIFNQ: /* IF != (not arithmetically equal) */
+ case XXIFLT: /* IF < */
+ case XXIFLE: /* IF <= */
+ case XXIFGE: /* IF >= */
+ case XXIFGT: { /* IF > */
+
+ /* July 2006 - converted to use CK_OFF_T rather than int to */
+ /* allow long integers on platforms that have ck_off_t > 32 bits */
+ int xx;
+ CK_OFF_T n1 = (CK_OFF_T)0, n2 = (CK_OFF_T)0;
+ if (ifc == XXIFVE) {
+ n1 = (CK_OFF_T) vernum;
+ } else {
+ x = cmfld("first number or variable name","",&s,xxstring);
+ if (x == -3) {
+ printf("?Quantity required\n");
+ return(-9);
+ }
+ if (x < 0) return(x);
+ debug(F101,"xxifgt cmfld","",x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ lp = brstrip(line);
+ debug(F110,"xxifgt exp1",lp,0);
+
+/* The following bit is for compatibility with old versions of MS-DOS Kermit */
+
+ if (!ckstrcmp(lp,"count",5,0)) {
+ n1 = (CK_OFF_T)count[cmdlvl];
+ } else if (!ckstrcmp(lp,"version",7,0)) {
+ n1 = (CK_OFF_T) vernum;
+ } else if (!ckstrcmp(lp,"argc",4,0)) {
+ n1 = (CK_OFF_T) macargc[maclvl];
+ } else {
+
+/* End of compatibility bit */
+
+#ifdef FNFLOAT
+ if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */
+ f1 = floatval;
+ f1flag = 1;
+ } else
+#endif /* FNFLOAT */
+ if (chknum(lp)) {
+ n1 = ckatofs(lp);
+ } else { /* Check for arithmetic expression */
+ q = evala(lp); /* cmnum() does this but ... */
+ if (chknum(q)) { /* we're not using cmnum(). */
+ n1 = ckatofs(q);
+ } else {
+ printf("?Value not numeric - %s", lp);
+ return(-9);
+ }
+ }
+ }
+ }
+ y = cmfld("number or variable name","",&s,xxstring);
+ if (y == -3) {
+ printf("?Quantity required\n");
+ return(-9);
+ }
+ if (y < 0) return(y);
+ s = brstrip(s);
+ if (!*s) return(-2);
+ if (ifc == XXIFVE) {
+ tp = line;
+ } else {
+ x = (int)strlen(lp);
+ tp = line + x + 2;
+ }
+ ckstrncpy(tp,s,LINBUFSIZ-x-2);
+ debug(F110,"xxifgt exp2",tp,0);
+ if (!ckstrcmp(tp,"count",5,0)) {
+ n2 = (CK_OFF_T) count[cmdlvl];
+ } else if (!ckstrcmp(tp,"version",7,0)) {
+ n2 = (CK_OFF_T) vernum;
+ } else if (!ckstrcmp(tp,"argc",4,0)) {
+ n2 = (CK_OFF_T) macargc[maclvl];
+ } else {
+#ifdef FNFLOAT
+ if (isfloat(tp,0) > 1) {
+ f2 = floatval;
+ f2flag = 1;
+ } else
+#endif /* FNFLOAT */
+ if (chknum(tp)) {
+ n2 = ckatofs(tp);
+ } else {
+ q = evala(tp);
+ if (chknum(q)) { /* we're not using cmnum(). */
+ n2 = ckatofs(q);
+ } else {
+ printf("?Value not numeric - %s", tp);
+ return(-9);
+ }
+ }
+ }
+ xx = (ifc == XXIFVE) ? XXIFGE : ifc;
+
+#ifdef FNFLOAT
+ if (f1flag && !f2flag) {
+ f2 = (CKFLOAT)n2;
+ f2flag = 1;
+ }
+ if (f2flag && !f1flag)
+ f1 = (CKFLOAT)n1;
+ if (f1flag)
+ z = ((f1 < f2 && xx == XXIFLT)
+ || (f1 != f2 && xx == XXIFNQ)
+ || (f1 <= f2 && xx == XXIFLE)
+ || (f1 == f2 && xx == XXIFAE)
+ || (f1 >= f2 && xx == XXIFGE)
+ || (f1 > f2 && xx == XXIFGT));
+ else
+#endif /* FNFLOAT */
+ z = ((n1 < n2 && xx == XXIFLT)
+ || (n1 != n2 && xx == XXIFNQ)
+ || (n1 <= n2 && xx == XXIFLE)
+ || (n1 == n2 && xx == XXIFAE)
+ || (n1 >= n2 && xx == XXIFGE)
+ || (n1 > n2 && xx == XXIFGT));
+ debug(F101,"xxifge z","",z);
+ if (ifc == XXIFVE)
+ ifargs += 2;
+ else
+ ifargs += 3;
+ break;
+ }
+
+ case XXIFNU: /* IF NUMERIC */
+ x = cmfld("variable name or constant","",&s,NULL);
+ if (x == -3) {
+ extern int cmflgs;
+ if (cmflgs == 1) {
+ printf("?Quantity required\n");
+ return(-9);
+ }
+ } else if (x < 0)
+ return(x);
+ x = LINBUFSIZ-1;
+ lp = line;
+ zzstring(s,&lp,&x);
+ lp = line;
+ debug(F110,"xxifnu quantity",lp,0);
+ z = chknum(lp);
+#ifdef COMMENT
+/*
+ This works, but it's not wise -- IF NUMERIC is mostly used to see if a
+ string really does contain only numeric characters. If they want to force
+ evaluation, they can use \feval() on the argument string.
+*/
+ if (!z) { /* Not a number */
+ x_ifnum = 1; /* Avoid "eval" error messages */
+ q = evala(lp); /* Maybe it's an expression */
+ z = chknum(q); /* that evaluates to a number */
+ x_ifnum = 0; /* Put eval messages back to normal */
+ if (z) debug(F110,"xxifnu exp",lp,0);
+ }
+#endif /* COMMENT */
+ debug(F101,"xxifnu chknum","",z);
+ ifargs += 2;
+ break;
+
+#ifdef ZFCDAT
+ case XXIFNE: { /* IF NEWER */
+ char d1[20], * d2; /* Buffers for 2 dates */
+ if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
+ return(z);
+ ckstrncpy(d1,zfcdat(s),20);
+ if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
+ return(z);
+ d2 = zfcdat(s);
+ if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
+ printf("?Failure to get file date\n");
+ return(-9);
+ }
+ debug(F110,"xxifnewer d1",d1,0);
+ debug(F110,"xxifnewer d2",d2,0);
+ z = (strcmp(d1,d2) > 0) ? 1 : 0;
+ debug(F101,"xxifnewer","",z);
+ ifargs += 2;
+ break;
+ }
+#endif /* ZFCDAT */
+
+#ifdef CK_IFRO
+ case XXIFRO: /* REMOTE-ONLY advisory */
+ ifargs++;
+#ifdef NOLOCAL
+ z = 1;
+#else
+ z = remonly;
+#endif /* NOLOCAL */
+ break;
+#endif /* CK_IFRO */
+
+ case XXIFAL: /* ALARM */
+ ifargs++;
+ debug(F101,"IF ALARM ck_alarm","",ck_alarm);
+ debug(F110,"IF ALARM alrm_date",alrm_date,0);
+ debug(F110,"IF ALARM alrm_time",alrm_time,0);
+
+ if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
+ z = 0; /* ALARM not SET */
+ break; /* so IF ALARM fails */
+ }
+ /* Get current date and time */
+ ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ);
+ s = tmpbuf;
+ s[8] = NUL;
+ z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
+ debug(F101,"IF ALARM date z","",z);
+ if (z == 0) { /* Dates are the same */
+ /* Compare times */
+ z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
+ debug(F101,"IF ALARM time z","",z);
+ }
+ tmpbuf[0] = NUL; /* z >= 0 if alarm is passed */
+ z = ((z >= 0) ? 1 : 0); /* z < 0 otherwise */
+ debug(F101,"IF ALARM final z","",z);
+ break;
+
+ case XXIFOP: /* IF OPEN */
+ if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
+ return(x);
+ if (x == 9999 || x == ZSTDIO) {
+ bgchk(); /* Check background status */
+ z = pflag ? 1 : 0;
+ } else if (x == 8888) {
+ z = local ? ttchk() > -1 : 0;
+#ifdef CKLOGDIAL
+ } else if (x == 7777) {
+ extern int dialog;
+ z = dialog ? 1 : 0;
+#endif /* CKLOGDIAL */
+ } else
+ z = (chkfn(x) > 0) ? 1 : 0;
+ ifargs += 1;
+ break;
+
+ case XXIFSD: /* Started-From-Dialer */
+#ifdef OS2
+ z = StartedFromDialer;
+#else
+ z = 0;
+#endif /* OS2 */
+ break;
+
+ case XXIFTM: /* Terminal-Macro */
+#ifdef OS2
+ z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
+#else
+ z = 0;
+#endif /* OS2 */
+ break;
+
+ case XXIFEM: /* Emulation is active */
+#ifdef OS2
+ z = 1;
+#else
+ z = 0;
+#endif /* OS2 */
+ break;
+
+ case XXIFIK: /* Running as IKSD? */
+ z = inserver;
+ break;
+
+ case XXIFTA: /* Connection is TAPI */
+ z = 0;
+#ifndef NODIAL
+#ifdef CK_TAPI
+ if (local && !network && tttapi)
+ z = 1;
+#endif /* CK_TAPI */
+#endif /* NODIAL */
+ break;
+
+ case XXIFMA: /* IF MATCH */
+ x = cmfld("String or variable","",&s,xxstring);
+ if (x == -3) {
+ extern int cmflgs;
+ if (cmflgs == 1) {
+ printf("?String required\n");
+ return(-9);
+ }
+ } else if (x < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+ debug(F110,"xxifma string",line,0);
+ x = cmfld("Pattern","",&p,xxstring);
+ if (x == -3) {
+ extern int cmflgs;
+ if (cmflgs == 1) {
+ printf("?Pattern required\n");
+ return(-9);
+ }
+ } else if (x < 0)
+ return(x);
+ ckstrncpy(tmpbuf,p,TMPBUFSIZ);
+ p = brstrip(tmpbuf);
+ debug(F110,"xxifma pattern",tmpbuf,0);
+ z = ckmatch(p,s,inpcas[cmdlvl],1);
+ break;
+
+ case XXIFFL: { /* IF FLAG */
+ extern int ooflag;
+ z = ooflag;
+ break;
+ }
+ case XXIFAV: { /* IF AVAILABLE */
+ if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case AV_KRB4:
+ z = ck_krb4_is_installed();
+ break;
+ case AV_KRB5:
+ z = ck_krb5_is_installed();
+ break;
+ case AV_SRP:
+ z = ck_srp_is_installed();
+ break;
+ case AV_SSL:
+ z = ck_ssleay_is_installed();
+ break;
+ case AV_NTLM:
+ z = ck_ntlm_is_installed();
+ break;
+ case AV_CRYPTO:
+ z = ck_crypt_is_installed();
+ break;
+ case AV_SSH:
+ z = ck_ssh_is_installed();
+ break;
+ default:
+ z = 0;
+ }
+ break;
+ }
+ case XXIFAT: /* IF ASKTIMEOUT */
+ z = asktimedout;
+ break;
+
+ case XXIFRD: /* IF READABLE */
+ case XXIFWR: /* IF WRITEABLE */
+ if ((x = cmfld("File or directory name",
+ "",
+ &s,
+#ifdef OS2
+ NULL /* This allows \'s in filenames */
+#else
+ xxstring
+#endif /* OS2 */
+ )) < 0) {
+ if (x == -3) {
+ extern int cmflgs;
+ if (cmflgs == 1) {
+ printf("?File or directory name required\n");
+ return(-9);
+ }
+ } else return(x);
+ }
+ s = brstrip(s);
+/*
+ zchk[io]() do not do what we want here for directories, so we set
+ a global flag telling it to behave specially in this case. Othewise
+ we'd have to change the API and change all ck?fio.c modules accordingly.
+*/
+ y = 0; /* Try-again control */
+#ifdef OS2
+ ifrdagain:
+#endif /* OS2 */
+ if (ifc == XXIFRD) { /* IF READABLE */
+ zchkid = 1;
+ z = zchki(s) > -1;
+ zchkid = 0;
+ } else if (ifc == XXIFWR) { /* IF WRITEABLE */
+ zchkod = 1;
+ z = zchko(s) > -1;
+ zchkod = 0;
+ }
+#ifdef OS2
+ if (!z && !y) { /* File not found. */
+ int t; /* Try expanding variables */
+ t = LINBUFSIZ-1; /* and looking again. */
+ lp = line;
+ zzstring(s,&lp,&t);
+ s = line;
+ z = zchko(s) > -1;
+ y++;
+ goto ifrdagain;
+ }
+#endif /* OS2 */
+ ifargs += 2;
+ break;
+ case XXIFQU: /* IF QUIET */
+ z = quiet ? 1 : 0;
+ debug(F101,"if quiet","",z);
+ ifargs += 1;
+ break;
+
+ case XXIFWI: /* WILD */
+ if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
+ z = iswild(s);
+ break;
+
+ case XXIFCK: /* C-KERMIT */
+#ifdef OS2
+ z = 0;
+#else
+ z = 1;
+#endif /* OS2 */
+ break;
+
+ case XXIFK9: /* K-95 */
+#ifdef OS2
+ z = 1;
+#else
+ z = 0;
+#endif /* OS2 */
+ break;
+
+ case XXIFGU: /* GUI */
+#ifdef KUI
+ z = 1;
+#else
+ z = 0;
+#endif /* KUI */
+ break;
+
+ case XXIFMS: /* MS-KERMIT */
+ z = 0;
+ break;
+
+ case XXIFLO: /* IF LOCAL */
+ z = local ? 1 : 0;
+ break;
+
+ case XXIFCM: { /* IF COMMAND */
+ extern struct keytab cmdtab[];
+ extern int ncmd;
+ if ((x = cmfld("Word","",&s,xxstring)) < 0)
+ return(x);
+ z = lookup(cmdtab,s,ncmd,&y);
+ z = (z == -2 || z > -1) ? 1 : 0;
+ break;
+ }
+#ifdef CKFLOAT
+ case XXIFFP: /* IF FLOAT */
+ if ((x = cmfld("Number","",&s,xxstring)) < 0)
+ if (x != -3) /* e.g. empty variable */
+ return(x);
+ z = isfloat(s,0);
+ break;
+#endif /* CKFLOAT */
+
+ case XXIFKB: /* KBHIT */
+ z = conchk();
+ if (z < 0) z = 0;
+ if (z > 1) z = 1;
+ break;
+
+ case XXIFKG: { /* KERBANG */
+ extern int cfilef;
+#ifdef COMMENT
+ z = (xcmdsrc == 0) ? 0 : (cfilef && cmdlvl == 1);
+#else
+ z = (xcmdsrc == 0) ? 0 : (cfilef && tlevel == 0);
+#endif /* COMMENT */
+ break;
+ }
+
+ case XXIFDB: { /* IF DEBUG - 2010/03/16 */
+ extern int debmsg;
+ z = debmsg;
+ break;
+ }
+
+ default: /* Shouldn't happen */
+ return(-2);
+ } /* end of switch */
+
+ if (z)
+ *bx++ = '1';
+ else
+ *bx++ = '0';
+ *bx = NUL;
+ if (bx > boolval + BOOLLEN - 2) {
+ printf("?Boolean expression too long");
+ return(-9);
+ }
+ ecount++; /* Expression counter */
+ debug(F101,"boolexp parens","",parens);
+ debug(F101,"boolexp pcount","",pcount);
+ if (parens && pcount > 0)
+ goto ifagain;
+
+ ifend: /* No more - done */
+ *bx = NUL;
+ z = atoi(evalx(boolval));
+ debug(F111,"boolexp boolval",boolval,z);
+ return(z);
+}
+
+/* D O I F -- Do the IF command */
+
+int
+doif(cx) int cx; {
+ int x, y, z; char *s, *p;
+ char *q;
+#ifdef OS2
+ extern int keymac;
+#endif /* OS2 */
+
+ debug(F101,"doif cx","",cx);
+
+ z = boolexp(cx); /* Evaluate the condition(s) */
+ debug(F010,"doif cmdbuf",cmdbuf,0);
+ debug(F101,"doif boolexp","",z);
+ if (z < 0)
+ return(z);
+
+ if (cx == XXIF) { /* Allow IF to have XIF semantics. */
+ char * p;
+ p = cmpeek();
+ if (!p) p = "";
+ while (*p) {
+ if (*p == SP || *p == HT)
+ p++;
+ else
+ break;
+ }
+ if (*p == '{')
+ cx = XXIFX;
+ }
+ switch (cx) { /* Separate handling for IF and XIF */
+
+ case XXASSER: /* And ASSERT */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ return(success = z);
+
+ case XXIF: /* This is IF... */
+ ifcmd[cmdlvl] = 1; /* We just completed an IF command */
+ debug(F101,"doif condition","",z);
+ if (z) { /* Condition is true */
+ iftest[cmdlvl] = 1; /* Remember that IF succeeded */
+ if (maclvl > -1) { /* In macro, */
+ pushcmd(NULL); /* save rest of command. */
+ } else if (tlevel > -1) { /* In take file, */
+ debug(F100, "doif: pushing command", "", 0);
+ pushcmd(NULL); /* save rest of command. */
+ } else { /* If interactive, */
+ cmini(ckxech); /* just start a new command */
+ printf("\n"); /* (like in MS-DOS Kermit) */
+ if (pflag) prompt(xxstring);
+ }
+ } else { /* Condition is false */
+ iftest[cmdlvl] = 0; /* Remember command failed. */
+ if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
+ return(y); /* Gobble up rest of line */
+ }
+ return(0);
+
+ case XXIFX: { /* This is XIF (Extended IF) */
+ char *p;
+ char e[5];
+ int i;
+ if ((y = cmtxt("Object command","",&s,NULL)) < 0)
+ return(y); /* Get object command. */
+ p = s;
+ lp = line;
+ debug(F110,"doif THEN part",s,-54);
+ if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
+ return(-2);
+ }
+ debug(F111,"doif THEN part 2",line,z);
+
+ while (*p == SP) p++; /* Strip trailing spaces */
+ ifcmd[cmdlvl] = 0; /* Assume ELSE part in same line */
+ iftest[cmdlvl] = z ? 1 : 0;
+ if (*p) { /* At end? */
+ if (!z) { /* No, use ELSE-part, if any */
+ for (i = 0; i < 4; i++) e[i] = *p++;
+ if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
+ return(-2); /* Something else - error. */
+ debug(F010,"doif ELSE line 1",p,0);
+ while (*p == SP) p++; /* Skip spaces */
+ if (*p != '{') { /* Brace ELSE part if necessary */
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL);
+ p = tmpbuf;
+ debug(F010,"doif ELSE line 2",p,0);
+ }
+ lp = line; /* Write over THEN part... */
+ *lp = NUL; /* with ELSE part. */
+ if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
+ return(-2);
+ }
+ while (*p == SP) p++; /* Strip trailing spaces */
+ if (*p) return(-2); /* Should be nothing here. */
+ debug(F010,"doif ELSE line 3",line,0);
+ }
+ } else { /* At end, treat like an IF command */
+ if (!z) line[0] = NUL; /* Condition not true and no ELSE */
+ ifcmd[cmdlvl] = 1; /* Allow ELSE on next line */
+ debug(F101,"IF condition","",z);
+ }
+ if (line[0]) {
+ x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
+ if (x < 0) { /* Not there? */
+ addmmac("_xif",xif_def); /* Put it back. */
+ if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
+ printf("?XIF macro gone!\n");
+ return(success = 0);
+ }
+ }
+ dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
+ }
+ return(0);
+ }
+ case XXWHI: { /* WHILE Command */
+ p = cmdbuf; /* Capture IF condition */
+ ifcond[0] = NUL; /* from command buffer */
+ while (*p == SP) p++;
+ while (*p != SP) p++;
+ ifcp = ifcond;
+ ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN);
+#ifdef COMMENT
+/*
+ This doesn't work because it breaks on the first left brace, which does
+ not necessarily start the command list, e.g. "while equal \%a {\35}".
+*/
+ while (*p != '{' && *p != NUL) *ifcp++ = *p++;
+ p = " ) goto _..bot) } ";
+ while (*ifcp++ = *p++) ;
+#else
+/*
+ The command parser sets cmbptr to the spot where it left off parsing in
+ the command buffer.
+*/
+ {
+ extern char * cmbptr;
+ if (cmbptr) {
+ while (p < cmbptr && *p != NUL)
+ *ifcp++ = *p++;
+ p = " ) goto _..bot) } ";
+ while ((*ifcp++ = *p++)) ;
+ } else {
+ printf("?Internal error parsing WHILE condition\n");
+ return(-9);
+ }
+ }
+#endif /* COMMENT */
+
+ debug(F110,"WHILE cmd",ifcond,0);
+
+ if ((y = cmtxt("Object command","",&s,NULL)) < 0)
+ return(y); /* Get object command. */
+ p = s;
+ lp = line;
+ if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
+ return(-2);
+ }
+ debug(F101,"WHILE body",line,-54);
+ if (line[0]) {
+ char *p;
+ x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
+ if (x < 0) { /* Not there? */
+ addmmac("_while",whil_def); /* Put it back. */
+ if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
+ printf("?WHILE macro definition gone!\n");
+ return(success = 0);
+ }
+ }
+ p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
+ if (p) {
+ strcpy(p,ifcond); /* safe (prechecked) */
+ strcat(p,line); /* safe (prechecked) */
+ debug(F010,"WHILE dodo",p,0);
+ dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
+ free(p);
+ p = NULL;
+ } else {
+ printf("?Can't allocate storage for WHILE command");
+ return(success = 0);
+ }
+ }
+ return(0);
+ }
+ default:
+ return(-2);
+ }
+}
+#endif /* NOSPL */
+
+/* Set up a TAKE command file */
+
+int
+dotake(s) char *s; {
+#ifndef NOSPL
+ extern int tra_cmd;
+#endif /* NOSPL */
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int term_io;
+ int term_io_sav = term_io;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ int slen;
+
+ debug(F110,"dotake",s,0);
+ if (!s) s = "";
+ if (!*s) return(success = 0);
+ slen = strlen(s);
+ debug(F101,"dotake len","",slen);
+
+ if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
+ perror(s);
+ debug(F110,"dotake fail",s,0);
+ tlevel--;
+ return(success = 0);
+ } else {
+ tfline[tlevel] = 0; /* Line counter */
+#ifdef VMS
+ conres(); /* So Ctrl-C will work */
+#endif /* VMS */
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = 0; /* Disable Terminal Emulator I/O */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifndef NOSPL
+ cmdlvl++; /* Entering a new command level */
+ debug(F111,"CMD +F",s,cmdlvl);
+ debug(F101,"dotake cmdlvl","",cmdlvl);
+ debug(F101,"dotake tlevel","",tlevel);
+ if (cmdlvl > CMDSTKL) {
+ debug(F100,"dotake stack overflow","",0);
+ cmdlvl--;
+ debug(F111,"CMD*-F",s,cmdlvl);
+ fclose(tfile[tlevel--]);
+ printf("?TAKE files and/or DO commands nested too deeply\n");
+ return(success = 0);
+ }
+ if (tfnam[tlevel]) { /* Copy the filename */
+ free(tfnam[tlevel]);
+ tfnam[tlevel] = NULL;
+ }
+ if ((tfnam[tlevel] = malloc(strlen(s) + 1))) {
+ strcpy(tfnam[tlevel],s); /* safe */
+ } else {
+ printf("?Memory allocation failure\n");
+ return(success = 0);
+ }
+ ifcmd[cmdlvl] = 0; /* Set variables for this cmd file */
+ iftest[cmdlvl] = 0;
+ count[cmdlvl] = count[cmdlvl-1]; /* Inherit this */
+ intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
+ inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
+ takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
+ merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
+ xquiet[cmdlvl] = quiet;
+ xvarev[cmdlvl] = vareval;
+ xcmdsrc = CMD_TF;
+ cmdstk[cmdlvl].src = CMD_TF; /* Say we're in a TAKE file */
+ cmdstk[cmdlvl].lvl = tlevel; /* nested at this level */
+ cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
+#else
+ takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
+#endif /* NOSPL */
+ }
+#ifndef NOSPL
+ if (tra_cmd)
+ printf("[%d] +F: \"%s\"\n",cmdlvl,s);
+#endif /* NOSPL */
+#ifndef NOLOCAL
+#ifdef OS2
+ term_io = term_io_sav;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(1);
+}
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuus7.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus7.c
new file mode 100644
index 0000000..1e74ab6
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuus7.c
@@ -0,0 +1,15323 @@
+#include "ckcsym.h"
+
+/* C K U U S 7 -- "User Interface" for C-Kermit, part 7 */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ This file created from parts of ckuus3.c, which became too big for
+ Mark Williams Coherent compiler to handle.
+*/
+
+/*
+ Definitions here supersede those from system include files.
+*/
+#include "ckcdeb.h" /* Debugging & compiler things */
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckcker.h" /* Kermit application definitions */
+#include "ckcxla.h" /* Character set translation */
+#include "ckcnet.h" /* Network symbols */
+#include "ckuusr.h" /* User interface symbols */
+#include "ckucmd.h"
+#include "ckclib.h"
+
+#ifdef VMS
+#ifndef TCPSOCKET
+#include <errno.h>
+#endif /* TCPSOCKET */
+#endif /* VMS */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#define INCL_DOSMODULEMGR
+#include <os2.h>
+#undef COMMENT
+#else /* NT */
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.h"
+#endif /* NT */
+#include "ckowin.h"
+#include "ckocon.h"
+#include "ckodir.h"
+#ifdef OS2MOUSE
+#include "ckokey.h"
+#endif /* OS2MOUSE */
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+extern int mskkeys;
+extern int mskrename;
+#endif /* OS2 */
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+#ifdef SSHBUILTIN
+#include "ckossh.h"
+#endif /* SSHBUILTIN */
+#ifdef STRATUS /* Stratus Computer, Inc. VOS */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef getchar
+#undef getchar
+#endif /* getchar */
+#define getchar(x) coninc(0)
+#endif /* STRATUS */
+
+char * slmsg = NULL;
+
+static int x, y = 0, z;
+static char *s;
+
+extern CHAR feol;
+extern int g_matchdot, hints, xcmdsrc, rcdactive;
+
+extern char * k_info_dir;
+
+#ifdef CK_LOGIN
+#ifdef CK_PAM
+int gotemptypasswd = 0; /* distinguish empty passwd from none given */
+#endif /* CK_PAM */
+#endif /* CK_LOGIN */
+
+#ifndef NOSPL
+extern int nmac;
+extern struct mtab *mactab;
+#endif /* NOSPL */
+
+#ifndef NOXFER
+#ifdef CK_SPEED
+extern short ctlp[]; /* Control-char prefixing table */
+#endif /* CK_SPEED */
+
+#ifdef PIPESEND
+extern char * sndfilter, * g_sfilter;
+extern char * rcvfilter, * g_rfilter;
+#endif /* PIPESEND */
+
+extern char * snd_move;
+extern char * snd_rename;
+extern char * g_snd_move;
+extern char * g_snd_rename;
+extern char * rcv_move;
+extern char * rcv_rename;
+extern char * g_rcv_move;
+extern char * g_rcv_rename;
+
+#ifdef PATTERNS
+extern char *binpatterns[], *txtpatterns[];
+extern int patterns;
+#endif /* PATTERNS */
+
+extern char * remdest;
+#ifdef CK_TMPDIR
+char * dldir = NULL;
+#endif /* CK_TMPDIR */
+
+extern struct ck_p ptab[];
+
+extern int protocol, remfile, rempipe, remappd, reliable, xreliable, fmask,
+ fncnv, frecl, maxrps, wslotr, bigsbsiz, bigrbsiz, urpsiz, rpsiz, spsiz,
+ bctr, npad, timef, timint, spsizr, spsizf, maxsps, spmax, nfils, displa,
+ atcapr, pkttim, rtimo, fncact, mypadn, fdispla, f_save, pktpaus, setreliable,
+ fnrpath, fnspath, atenci, atenco, atdati, atdato, atleni, atleno, atblki,
+ atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
+
+extern int stathack;
+
+extern int atfrmi, atfrmo;
+#ifdef STRATUS
+extern int atcrei, atcreo, atacti, atacto;
+#endif /* STRATUS */
+#ifdef CK_PERMS
+extern int atlpri, atlpro, atgpri, atgpro;
+#endif /* CK_PERMS */
+
+extern CHAR
+ sstate, eol, seol, stchr, mystch, mypadc, padch, ctlq, myctlq;
+
+#ifdef IKSD
+extern int inserver;
+#ifdef IKSDCONF
+extern int iksdcf;
+#endif /* IKSDCONF */
+#endif /* IKSD */
+
+extern char *cmarg, *cmarg2;
+
+#ifndef NOFRILLS
+extern char optbuf[]; /* Buffer for MAIL or PRINT options */
+extern int rprintf; /* REMOTE PRINT flag */
+#endif /* NOFRILLS */
+#endif /* NOXFER */
+
+#ifdef CK_TRIGGER
+extern char * tt_trigger[];
+#endif /* CK_TRIGGER */
+
+extern int tcs_transp;
+#ifdef PCTERM
+extern int tt_pcterm;
+#endif /* PCTERM */
+#ifdef NT
+extern int tt_vtnt;
+#endif /* NT */
+
+#ifdef SSHBUILTIN
+int sl_ssh_xfw = 0;
+int sl_ssh_xfw_saved = 0;
+int sl_ssh_ver = 0;
+int sl_ssh_ver_saved = 0;
+#endif /* SSHBUILTIN */
+
+#ifdef CK_AUTHENTICATION
+extern int auth_type_user[];
+int sl_auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_NULL, AUTHTYPE_NULL};
+int sl_auth_saved = 0;
+int sl_topt_a_su = 0;
+int sl_topt_a_s_saved = 0;
+int sl_topt_a_cm = 0;
+int sl_topt_a_c_saved = 0;
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+extern int cx_type;
+int sl_cx_type = 0;
+int sl_cx_saved = 0;
+int sl_topt_e_su = 0;
+int sl_topt_e_sm = 0;
+int sl_topt_e_s_saved = 0;
+int sl_topt_e_cu = 0;
+int sl_topt_e_cm = 0;
+int sl_topt_e_c_saved = 0;
+#endif /* CK_ENCRYPTION */
+extern char uidbuf[];
+static int uidflag = 0;
+char sl_uidbuf[UIDBUFLEN] = { NUL, NUL };
+int sl_uid_saved = 0;
+#ifdef TNCODE
+int sl_tn_wait = 0;
+int sl_tn_saved = 0;
+#endif /* TNCODE */
+
+#ifdef TNCODE
+extern int tn_wait_flg;
+#endif /* TNCODE */
+
+VOID
+slrestor() {
+#ifdef CK_AUTHENTICATION
+ int x;
+ if (sl_auth_saved) {
+ for (x = 0; x < AUTHTYPLSTSZ; x++)
+ auth_type_user[x] = sl_auth_type_user[x];
+ sl_auth_saved = 0;
+ }
+ if (sl_topt_a_s_saved) {
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_su;
+ sl_topt_a_s_saved = 0;
+ }
+ if (sl_topt_a_c_saved) {
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_cm;
+ sl_topt_a_c_saved = 0;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ if (sl_cx_saved) {
+ cx_type = sl_cx_type;
+ sl_cx_saved = 0;
+ }
+ if (sl_topt_e_s_saved) {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = sl_topt_e_su;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_sm;
+ sl_topt_e_s_saved = 0;
+ }
+ if (sl_topt_e_c_saved) {
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cu;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cm;
+ sl_topt_e_c_saved = 0;
+ }
+#endif /* CK_ENCRYPTION */
+ if (sl_uid_saved) {
+ ckstrncpy(uidbuf,sl_uidbuf,UIDBUFLEN);
+ sl_uid_saved = 0;
+ }
+#ifdef TNCODE
+ if (sl_tn_saved) {
+ tn_wait_flg = sl_tn_wait;
+ sl_tn_saved = 0;
+ }
+#endif /* TNCODE */
+#ifdef SSHBUILTIN
+ if (sl_ssh_xfw_saved) {
+ ssh_xfw = sl_ssh_xfw;
+ sl_ssh_xfw_saved = 0;
+ }
+ if (sl_ssh_ver_saved) {
+ ssh_ver = sl_ssh_ver;
+ sl_ssh_ver_saved = 0;
+ }
+#endif /* SSHBUILTIN */
+}
+
+int oldplex = -1; /* Duplex holder around network */
+
+#ifndef NOICP
+#ifdef LOCUS
+extern int locus, autolocus;
+#endif /* LOCUS */
+#ifndef NODIAL
+extern int dialsta;
+#endif /* NODIAL */
+
+/* Note: gcc -Wall wants braces around each keyword table entry. */
+
+static struct keytab psltab[] = { /* SET LINE/PORT command options */
+ { "/connect", SL_CNX, 0 },
+#ifdef OS2ORVMS
+ { "/noshare", SL_NSH, 0 },
+#endif /* OS2ORVMS */
+ { "/server", SL_SRV, 0 },
+#ifdef OS2ORVMS
+ { "/share", SL_SHR, 0 },
+#endif /* OS2ORVMS */
+ { "", 0, 0 }
+};
+static int npsltab = sizeof(psltab)/sizeof(struct keytab) - 1;
+
+#ifdef NETCONN
+static struct keytab shtab[] = { /* SET HOST command options */
+#ifdef NETCMD
+ /* (COMMAND is also a network type) */
+ { "/command", SL_CMD, CM_INV },
+#endif /* NETCMD */
+ { "/connect", SL_CNX, 0 },
+ { "/network-type", SL_NET, CM_ARG },
+ { "/nowait", SL_NOWAIT, 0 },
+#ifndef NOSPL
+#ifdef CK_AUTHENTICATION
+ { "/password", SL_PSW, CM_ARG },
+#endif /* CK_AUTHENTICATION */
+#endif /* NOSPL */
+#ifdef NETCMD
+ { "/pipe", SL_CMD, 0 },
+#endif /* NETCMD */
+#ifdef NETPTY
+ { "/pty", SL_PTY, 0 },
+#endif /* NETPTY */
+ { "/server", SL_SRV, 0 },
+ { "/timeout", SL_TMO, CM_ARG },
+ { "/userid", SL_UID, CM_ARG },
+ { "/wait", SL_WAIT, 0 },
+ { "", 0, 0 }
+};
+static int nshtab = sizeof(shtab)/sizeof(struct keytab) - 1;
+
+static struct keytab shteltab[] = { /* TELNET command options */
+#ifdef CK_AUTHENTICATION
+ { "/auth", SL_AUTH, CM_ARG },
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ { "/encrypt", SL_ENC, CM_ARG },
+#endif /* CK_ENCRYPTION */
+ { "/nowait", SL_NOWAIT, 0 },
+#ifndef NOSPL
+#ifdef CK_AUTHENTICATION
+ { "/password", SL_PSW, CM_ARG },
+#endif /* CK_AUTHENTICATION */
+#endif /* NOSPL */
+ { "/timeout", SL_TMO, CM_ARG },
+ { "/userid", SL_UID, CM_ARG },
+ { "/wait", SL_WAIT, 0 },
+ { "", 0 ,0 }
+};
+static int nshteltab = sizeof(shteltab)/sizeof(struct keytab) - 1;
+
+#ifdef RLOGCODE
+static struct keytab shrlgtab[] = { /* SET HOST RLOGIN command options */
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ { "/encrypt", SL_ENC, 0 },
+#endif /* CK_ENCRYPTION */
+ { "/k4", SL_KRB4, CM_INV },
+ { "/k5", SL_KRB5, CM_INV },
+ { "/kerberos4", SL_KRB4, 0 },
+ { "/kerberos5", SL_KRB5, 0 },
+ { "/kerberos_iv", SL_KRB4, CM_INV },
+ { "/kerberos_v", SL_KRB5, CM_INV },
+ { "/krb4", SL_KRB4, CM_INV },
+ { "/krb5", SL_KRB5, CM_INV },
+#endif /* CK_KERBEROS */
+ { "", 0 ,0 }
+};
+static int nshrlgtab = sizeof(shrlgtab)/sizeof(struct keytab)-1;
+#endif /* RLOGCODE */
+
+extern struct keytab netcmd[];
+extern int nnets;
+#ifndef NODIAL
+extern int dirline;
+extern int nnetdir; /* Network services directory */
+extern char *netdir[];
+_PROTOTYP( VOID ndreset, (void) );
+char *nh_p[MAXDNUMS + 1]; /* Network directory entry pointers */
+char *nh_p2[MAXDNUMS + 1]; /* Network directory entry nettype */
+char *nh_px[4][MAXDNUMS + 1]; /* Network-specific stuff... */
+#endif /* NODIAL */
+int nhcount = 0;
+int ndinited = 0;
+char * n_name = NULL; /* Network name pointer */
+#endif /* NETCONN */
+
+_PROTOTYP(int remtxt, (char **) );
+_PROTOTYP(VOID rmsg, (void) );
+_PROTOTYP(static int remcfm, (void) );
+
+extern int nopush;
+
+int mdmsav = -1; /* Save modem type around network */
+extern int isguest; /* Global flag for anonymous login */
+
+extern xx_strp xxstring;
+
+extern int success, binary, b_save, ckwarn, msgflg, quiet, cmask, pflag, local,
+ nettype, escape, mdmtyp, duplex, dfloc, network, cdtimo, autoflow, tnlm,
+ sosi, tlevel, lf_opts, backgrd, flow, debses, parity, ttnproto, ckxech,
+ x_ifnum, cmflgs, haveline, cxtype, cxflow[], maclvl;
+
+#ifdef DCMDBUF
+extern struct cmdptr *cmdstk; /* The command stack itself */
+#else
+extern struct cmdptr cmdstk[]; /* The command stack itself */
+#endif /* DCMDBUF */
+extern FILE * tfile[];
+extern char * macp[];
+
+extern char psave[]; /* For saving & restoring prompt */
+extern int sprmlen, rprmlen;
+
+#ifdef OS2
+static struct keytab strmkeytab[] = {
+ { "clear", 0, 0 },
+ { "default", 1, 0 }
+};
+static int nstrmkeytab = sizeof(strmkeytab)/sizeof(struct keytab);
+
+static struct keytab strmswitab[] = {
+ { "/literal", 0, 0 }
+};
+static int nstrmswitab = sizeof(strmswitab)/sizeof(struct keytab);
+
+static struct keytab normrev[] = {
+ { "dark-display", 0, 0 },
+ { "light-display", 1, 0 },
+ { "normal", 0, 0 },
+ { "reverse", 1, 0 }
+};
+
+static struct keytab prnmtab[] = {
+ { "auto", 1, 0 },
+ { "copy", 2, 0 },
+ { "off", 0, 0 },
+ { "on", 1, CM_INV }, /* Compatibility with XPRINT version */
+ { "user", 3, 0 },
+ { "transparent", 3, CM_INV } /* not really transparent */
+};
+static int nprnmtab = sizeof(prnmtab)/sizeof(struct keytab);
+
+extern int tt_diff_upd;
+
+#ifdef NT
+#define stricmp _stricmp
+extern int tt_attr_bug;
+#endif /* NT */
+extern int tt_rows[], tt_cols[];
+extern int tt_cols_usr;
+extern int tt_szchng[VNUM];
+int tt_modechg = TVC_ENA;
+extern int tt_url_hilite, tt_url_hilite_attr;
+extern struct _vtG G[4];
+extern int priority;
+extern bool send_c1;
+int send_c1_usr = FALSE;
+extern int sgrcolors;
+extern int marginbell, marginbellcol;
+extern int autoscroll, wy_autopage;
+extern int tt_sac;
+extern int dec_nrc, dec_lang, dec_kbd;
+#else /* OS2 */
+extern int tt_rows, tt_cols;
+#endif /* OS2 */
+
+extern int tt_escape;
+extern long speed;
+
+extern char *dftty;
+
+extern char *tp, *lp; /* Temporary buffer & pointers */
+extern char ttname[];
+
+#ifdef CK_TAPI
+int tttapi = 0; /* is Line TAPI? */
+struct keytab * tapilinetab = NULL;
+struct keytab * _tapilinetab = NULL;
+int ntapiline = 0;
+#endif /* CK_TAPI */
+
+#ifdef NETCONN /* Network items */
+
+#ifdef ANYX25
+extern int revcall, closgr, cudata, nx25;
+extern char udata[];
+extern struct keytab x25tab[];
+#ifndef IBMX25
+extern int npadx3;
+extern CHAR padparms[];
+extern struct keytab padx3tab[];
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifdef OS2
+extern bool ttshare;
+#ifndef NT
+extern bool ttslip,ttppp;
+#endif /* NT */
+#endif /* OS2 */
+#ifdef NPIPE
+extern char pipename[];
+#endif /* NPIPE */
+
+#ifdef TCPSOCKET
+static struct keytab tcprawtab[] = { /* SET HOST options */
+ { "/default", NP_DEFAULT, CM_INV },
+#ifdef CK_AUTHENTICATION
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+ { "/ek4login", NP_EK4LOGIN, 0 },
+ { "/ek5login", NP_EK5LOGIN, 0 },
+ { "/k4login", NP_K4LOGIN, 0 },
+ { "/k5login", NP_K5LOGIN, 0 },
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ { "/k5user2user", NP_K5U2U, 0 },
+#endif /* KRB5_U2U */
+#endif /* CK_KERBEROS */
+#endif /* CK_AUTHENTICATION */
+ { "/no-telnet-init", NP_NONE, 0 },
+ { "/none", NP_NONE, CM_INV },
+ { "/raw-socket", NP_TCPRAW, 0 },
+#ifdef RLOGCODE
+ { "/rlogin", NP_RLOGIN, 0 },
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ { "/ssl", NP_SSL, 0 },
+ { "/ssl-raw", NP_SSL_RAW, 0 },
+ { "/ssl-telnet", NP_SSL_TELNET, 0 },
+#endif /* CK_SSL */
+ { "/telnet", NP_TELNET, 0 },
+#ifdef CK_SSL
+ { "/tls", NP_TLS, 0 },
+ { "/tls-raw", NP_TLS_RAW, 0 },
+ { "/tls-telnet", NP_TLS_TELNET, 0 },
+#endif /* CK_SSL */
+ { "", 0, 0 }
+};
+static int ntcpraw = (sizeof(tcprawtab) / sizeof(struct keytab)) - 1;
+
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_naws, (void) );
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+
+#ifdef SUPERLAT
+extern char slat_pwd[18];
+#endif /* SUPERLAT */
+#endif /* NETCONN */
+
+#ifdef COMMENT
+#ifndef NOSETKEY
+extern KEY *keymap;
+#ifndef OS2
+#define mapkey(x) keymap[x]
+#endif /* OS2 */
+extern MACRO *macrotab;
+#ifndef NOKVERBS
+extern struct keytab kverbs[];
+extern int nkverbs;
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+#else
+#ifndef NOSETKEY
+extern KEY *keymap;
+extern MACRO *macrotab;
+#ifndef NOKVERBS
+extern struct keytab kverbs[];
+extern int nkverbs;
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+#endif /* COMMENT */
+
+#ifdef OS2 /* AUTODOWNLOAD parameters */
+extern int adl_kmode, adl_zmode; /* Match Packet to signal download */
+extern char * adl_kstr; /* KERMIT Download String */
+extern char * adl_zstr; /* ZMODEM Download String */
+extern int adl_kc0, adl_zc0; /* Process ADL C0s in emulation */
+#endif /* OS2 */
+
+/* Keyword tables ... */
+
+extern struct keytab onoff[], rltab[];
+extern int nrlt;
+
+#ifndef NOCSETS
+static struct keytab fdfltab[] = {
+ { "7bit-character-set", 7, 0 },
+ { "8bit-character-set", 8, 0 }
+};
+static int nfdflt = (sizeof(fdfltab) / sizeof(struct keytab));
+#endif /* NOCSETS */
+
+/* SET FILE parameters */
+
+static struct keytab filtab[] = {
+#ifndef NOXFER
+#ifdef PATTERNS
+ { "binary-patterns", XYFIBP, 0 },
+#endif /* PATTERNS */
+ { "bytesize", XYFILS, 0 },
+#ifndef NOCSETS
+ { "character-set", XYFILC, 0 },
+#endif /* NOCSETS */
+ { "collision", XYFILX, 0 },
+ { "default", XYF_DFLT, 0 },
+ { "destination", XYFILY, 0 },
+ { "display", XYFILD, CM_INV },
+#ifdef CK_TMPDIR
+ { "download-directory", XYFILG, 0 },
+#endif /* CK_TMPDIR */
+#endif /* NOXFER */
+ { "end-of-line", XYFILA, 0 },
+ { "eol", XYFILA, CM_INV },
+#ifdef CK_CTRLZ
+ { "eof", XYFILV, 0 },
+#endif /* CK_CTRLZ */
+#ifndef NOXFER
+ { "fastlookups", 9997, CM_INV },
+ { "incomplete", XYFILI, 0 },
+#ifndef datageneral
+ { "inspection", XYF_INSP, CM_INV },
+#endif /* datageneral */
+#ifdef CK_LABELED
+ { "label", XYFILL, 0 },
+#endif /* CK_LABELED */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+ { "listsize", XYF_LSIZ, 0 },
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+ { "names", XYFILN, 0 },
+#ifdef UNIX
+ { "output", XYFILH, 0 },
+#endif /* UNIX */
+#ifdef PATTERNS
+ { "patterns", XYFIPA, 0 },
+#endif /* PATTERNS */
+#ifdef COMMENT /* Not implemented (but see CHMOD) */
+ { "permissions", XYF_PRM, CM_INV },
+ { "protection", XYF_PRM, 0 },
+#endif /* COMMENt */
+#ifdef VMS
+ { "record-length", XYFILR, 0 },
+#endif /* VMS */
+#ifndef datageneral
+ { "scan", XYF_INSP, 0 },
+#endif /* datageneral */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+ { "stringspace", XYF_SSPA, 0 },
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+#ifdef PATTERNS
+ { "t", XYFILT, CM_INV|CM_ABR },
+ { "text-patterns", XYFITP, 0 },
+#endif /* PATTERNS */
+#endif /* NOXFER */
+ { "type", XYFILT, 0 },
+#ifdef UNICODE
+ { "ucs", XYFILU, 0 },
+#endif /* UNICODE */
+#ifndef NOXFER
+ { "warning", XYFILW, CM_INV }
+#endif /* NOXFER */
+};
+static int nfilp = (sizeof(filtab) / sizeof(struct keytab));
+
+struct keytab pathtab[] = {
+ { "absolute", PATH_ABS, 0 },
+ { "none", PATH_OFF, CM_INV },
+ { "off", PATH_OFF, 0 },
+ { "on", PATH_ABS, CM_INV },
+ { "relative", PATH_REL, 0 }
+};
+int npathtab = (sizeof(pathtab) / sizeof(struct keytab));
+
+struct keytab rpathtab[] = {
+ { "absolute", PATH_ABS, 0 },
+ { "auto", PATH_AUTO, 0 },
+ { "none", PATH_OFF, CM_INV },
+ { "off", PATH_OFF, 0 },
+ { "on", PATH_ABS, CM_INV },
+ { "relative", PATH_REL, 0 }
+};
+int nrpathtab = (sizeof(rpathtab) / sizeof(struct keytab));
+
+#ifdef CK_CTRLZ
+struct keytab eoftab[] = { /* EOF detection method */
+ { "ctrl-z", 1, 0 },
+ { "length", 0, 0 },
+ { "noctrl-z", 0, CM_INV }
+};
+#endif /* CK_CTRLZ */
+
+struct keytab fttab[] = { /* File types for SET FILE TYPE */
+ { "ascii", XYFT_T, CM_INV },
+#ifdef VMS
+ { "b", XYFT_B, CM_INV|CM_ABR },
+#endif /* VMS */
+ { "binary", XYFT_B, 0 },
+#ifdef VMS
+ { "block", XYFT_I, CM_INV },
+ { "image", XYFT_I, 0 },
+#endif /* VMS */
+#ifdef CK_LABELED
+ { "labeled", XYFT_L, 0 },
+#endif /* CK_LABELED */
+#ifdef MAC
+ { "macbinary", XYFT_M, 0 },
+#endif /* MAC */
+ { "text", XYFT_T, 0 }
+};
+int nfttyp = (sizeof(fttab) / sizeof(struct keytab));
+
+static struct keytab rfttab[] = { /* File types for REMOTE SET FILE */
+ { "ascii", XYFT_T, CM_INV },
+ { "binary", XYFT_B, 0 },
+#ifdef VMS
+ { "labeled", XYFT_L, 0 },
+#else
+#ifdef OS2
+ { "labeled", XYFT_L, 0 },
+#endif /* OS2 */
+#endif /* VMS */
+ { "text", XYFT_T, 0 }
+};
+static int nrfttyp = (sizeof(rfttab) / sizeof(struct keytab));
+
+#ifdef OS2ORUNIX
+#define ZOF_BLK 0
+#define ZOF_NBLK 1
+#define ZOF_BUF 2
+#define ZOF_NBUF 3
+static struct keytab zoftab[] = {
+ { "blocking", ZOF_BLK, 0 },
+ { "buffered", ZOF_BUF, 0 },
+ { "nonblocking", ZOF_NBLK, 0 },
+ { "unbuffered", ZOF_NBUF, 0 }
+};
+static int nzoftab = (sizeof(zoftab) / sizeof(struct keytab));
+#endif /* OS2ORUNIX */
+
+extern int query; /* Global flag for QUERY active */
+
+#ifndef NOSPL
+#ifndef NOXFER
+static struct keytab vartyp[] = { /* Variable types for REMOTE QUERY */
+ { "global", (int) 'G', CM_INV },
+ { "kermit", (int) 'K', 0 },
+ { "system", (int) 'S', 0 },
+ { "user", (int) 'G', 0 }
+};
+static int nvartyp = (sizeof(vartyp) / sizeof(struct keytab));
+#endif /* NOXFER */
+#endif /* NOSPL */
+
+#ifdef CK_TIMERS
+static struct keytab timotab[] = { /* Timer types */
+ { "dynamic", 1, 0 },
+ { "fixed", 0, 0 }
+};
+#endif /* CK_TIMERS */
+
+#ifdef DCMDBUF
+extern char *atxbuf, *atmbuf; /* Atom buffer */
+extern char *cmdbuf; /* Command buffer */
+extern char *line, *tmpbuf; /* Character buffers for anything */
+extern int *intime; /* INPUT TIMEOUT */
+
+#else /* Not DCMDBUF ... */
+
+extern char atxbuf[], atmbuf[]; /* Atom buffer */
+extern char cmdbuf[]; /* Command buffer */
+extern char line[], tmpbuf[]; /* Character buffer for anything */
+extern int intime[];
+
+#endif /* DCMDBUF */
+
+#ifndef NOCSETS
+extern struct keytab fcstab[]; /* For SET FILE CHARACTER-SET */
+extern struct csinfo fcsinfo[]; /* File character set info. */
+extern struct keytab ttcstab[];
+extern int nfilc, fcharset, tcharset, ntermc, tcsr, tcsl, dcset7, dcset8;
+#ifdef CKOUNI
+extern int tt_utf8;
+#endif /* CKOUNI */
+#ifdef OS2
+_PROTOTYP( int os2setcp, (int) );
+_PROTOTYP( int os2getcp, (void) );
+_PROTOTYP( void os2debugoff, (void) );
+#endif /* OS2 */
+#endif /* NOCSETS */
+
+extern int cmdlvl; /* Overall command level */
+
+#ifndef NOSPL
+#ifdef DCMDBUF
+extern int *inpcas; /* INPUT CASE setting on cmd stack */
+#else
+extern int inpcas[];
+#endif /* DCMDBUF */
+#endif /* NOSPL */
+
+#ifdef CK_CURSES
+#ifndef VMS
+_PROTOTYP(int tgetent,(char *, char *));
+#else
+#ifdef __DECC
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* __DECC */
+#endif /* VMS */
+#endif /* CK_CURSES */
+
+#ifndef NOXMIT
+#define XMITF 0 /* SET TRANSMIT values */
+#define XMITL 1 /* (Local to this module) */
+#define XMITP 2
+#define XMITE 3
+#define XMITX 4
+#define XMITS 5
+#define XMITW 6
+#define XMITT 7
+
+#define XMBUFL 50
+extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt;
+char xmitbuf[XMBUFL+1] = { NUL }; /* TRANSMIT eof string */
+
+struct keytab xmitab[] = { /* SET TRANSMIT */
+ { "echo", XMITX, 0 },
+ { "eof", XMITE, 0 },
+ { "fill", XMITF, 0 },
+ { "linefeed", XMITL, 0 },
+ { "locking-shift", XMITS, 0 },
+ { "pause", XMITW, 0 },
+ { "prompt", XMITP, 0 },
+ { "timeout", XMITT, 0 }
+};
+int nxmit = (sizeof(xmitab) / sizeof(struct keytab));
+#endif /* NOXMIT */
+
+/* For SET FILE COLLISION */
+/* Some of the following may be possible for some C-Kermit implementations */
+/* but not others. Those that are not possible for your implementation */
+/* should be ifdef'd out. */
+
+struct keytab colxtab[] = { /* SET FILE COLLISION options */
+#ifndef MAC
+ { "append", XYFX_A, 0 }, /* append to old file */
+#endif /* MAC */
+#ifdef COMMENT
+ { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
+#endif
+ { "backup", XYFX_B, 0 }, /* rename old file */
+#ifndef MAC
+ /* This crashes Mac Kermit. */
+ { "discard", XYFX_D, CM_INV }, /* don't accept new file */
+ { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
+#endif /* MAC */
+ { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
+ { "reject", XYFX_D, 0 }, /* (better word than discard) */
+ { "rename", XYFX_R, 0 }, /* rename the incoming file */
+#ifndef MAC /* This crashes Mac Kermit. */
+ { "update", XYFX_U, 0 }, /* replace if newer */
+#endif /* MAC */
+ { "", 0, 0 }
+};
+int ncolx = (sizeof(colxtab) / sizeof(struct keytab)) - 1;
+
+static struct keytab rfiltab[] = { /* for REMOTE SET FILE */
+#ifndef NOCSETS
+ { "character-set", XYFILC, 0 },
+#endif /* NOCSETS */
+ { "collision", XYFILX, 0 },
+ { "incomplete", XYFILI, 0 },
+ { "names", XYFILN, 0 },
+ { "record-length", XYFILR, 0 },
+ { "type", XYFILT, 0 }
+};
+int nrfilp = (sizeof(rfiltab) / sizeof(struct keytab));
+
+struct keytab eoltab[] = { /* File eof delimiters */
+ { "cr", XYFA_C, 0 },
+ { "crlf", XYFA_2, 0 },
+ { "lf", XYFA_L, 0 }
+};
+static int neoltab = (sizeof(eoltab) / sizeof(struct keytab));
+
+struct keytab fntab[] = { /* File naming */
+ { "converted", XYFN_C, 0 },
+ { "literal", XYFN_L, 0 },
+ { "standard", XYFN_C, CM_INV }
+};
+int nfntab = (sizeof(fntab) / sizeof(struct keytab));
+
+#ifndef NOLOCAL
+/* Terminal parameters table */
+static struct keytab trmtab[] = {
+#ifdef OS2
+ { "answerback", XYTANS, 0 },
+#endif /* OS2 */
+#ifdef CK_APC
+ { "apc", XYTAPC, 0 },
+#endif /* CK_APC */
+#ifdef OS2
+ { "arrow-keys", XYTARR, 0 },
+#endif /* OS2 */
+#ifdef NT
+ { "at", XYTATTR, CM_INV|CM_ABR },
+ { "att", XYTATTR, CM_INV|CM_ABR },
+ { "attr", XYTATTR, CM_INV|CM_ABR },
+ { "attr-bug", XYTATTBUG, CM_INV },
+#endif /* NT */
+#ifdef OS2
+ { "attribute", XYTATTR, 0 },
+#endif /* OS2 */
+#ifdef CK_APC
+#ifdef CK_AUTODL
+ { "autodownload", XYTAUTODL, 0, },
+#endif /* CK_AUTODL */
+#endif /* CK_APC */
+#ifdef OS2
+ { "autopage", XYTAPAGE, 0 },
+ { "autoscroll", XYTASCRL, 0 },
+ { "bell", XYTBEL, CM_INV },
+#endif /* OS2 */
+ { "bytesize", XYTBYT, 0 },
+#ifndef NOCSETS
+ { "character-set", XYTCS, 0 },
+#endif /* NOCSETS */
+#ifdef OS2
+ { "code-page", XYTCPG, 0 },
+ { "color", XYTCOL, 0 },
+ { "controls", XYTCTRL, 0 },
+#endif /* OS2 */
+ { "cr-display", XYTCRD, 0 },
+#ifdef OS2
+ { "cursor", XYTCUR, 0 },
+#endif /* OS2 */
+ { "debug", XYTDEB, 0 },
+#ifdef OS2
+ { "dg-unix-mode", XYTUNX, 0 },
+#endif /* OS2 */
+ { "echo", XYTEC, 0 },
+ { "escape-character", XYTESC, 0 },
+#ifdef OS2
+#ifdef PCFONTS
+ { "font", XYTFON, 0 },
+#else
+#ifdef KUI
+ { "font", XYTFON, 0 },
+#endif /* KUI */
+#endif /* PCFONTS */
+#endif /* OS2 */
+ { "height", XYTHIG, 0 },
+#ifdef CKTIDLE
+ { "idle-action", XYTIACT, 0 },
+ { "idle-limit", XYTITMO, CM_INV },
+ { "idle-send", XYTIDLE, CM_INV },
+ { "idle-timeout", XYTITMO, 0 },
+#endif /* CKTIDLE */
+#ifdef OS2
+#ifndef NOCSETS
+ { "kbd-follows-gl/gr", XYTKBDGL, 0 },
+#endif /* NOCSETS */
+ { "key", XYTKEY, 0 },
+ { "keyboard-mode", XYTKBMOD, 0 },
+ { "keypad-mode", XYTKPD, 0 },
+#endif /* OS2 */
+ { "lf-display", XYTLFD, 0 },
+#ifndef NOCSETS
+#ifdef OS2
+#ifndef KUI
+ { "line-spacing", XYTLSP, CM_INV },
+ { "local-character-set", XYTLCS, 0 },
+#else
+ { "line-spacing", XYTLSP, 0 },
+ { "local-character-set", XYTLCS, CM_INV },
+#endif /* KUI */
+#else
+ { "local-character-set", XYTLCS, CM_INV },
+#endif /* OS2 */
+#endif /* NOCSETS */
+ { "locking-shift", XYTSO, 0 },
+#ifdef OS2
+ { "margin-bell", XYTMBEL, 0 },
+#endif /* OS2 */
+#ifdef OS2MOUSE
+ { "mouse", XYTMOU, CM_INV },
+#endif /* OS2MOUSE */
+ { "newline-mode", XYTNL, 0 },
+#ifdef OS2
+ { "output-pacing", XYTPAC, 0 },
+#ifdef PCTERM
+ { "pcterm", XYTPCTERM, 0 },
+#endif /* PCTERM */
+#endif /* OS2 */
+#ifdef OS2ORUNIX
+ { "print", XYTPRN, 0 },
+#endif /* OS2ORUNIX */
+#ifndef NOCSETS
+#ifdef OS2
+ { "remote-character-set", XYTRCS, 0 },
+#else
+ { "remote-character-set", XYTRCS, CM_INV },
+#endif /* OS2 */
+#endif /* NOCSETS */
+#ifdef OS2
+ { "roll-mode", XYTROL, 0 },
+ { "s", XYTUPD, CM_ABR|CM_INV },
+ { "sc", XYTUPD, CM_ABR|CM_INV },
+ { "scr", XYTUPD, CM_ABR|CM_INV },
+ { "scree", XYTUPD, CM_ABR|CM_INV },
+ { "screen", XYTUPD, CM_ABR|CM_INV },
+ { "screen-", XYTUPD, CM_ABR|CM_INV },
+ { "screen-mode", XYTSCNM, 0 },
+ { "screen-optimize", XYTOPTI, 0 },
+ { "screen-update", XYTUPD, 0 },
+ { "scrollback", XYSCRS, 0 },
+ { "send-data", XYTSEND, 0 },
+ { "send-end-of-block", XYTSEOB, 0 },
+ { "sgr-colors", XYTSGRC, 0 },
+ { "sni-ch.code", XYTSNICC, 0 },
+ { "sni-firmware-versions", XYTSNIFV, 0 },
+ { "sni-language", XYTVTLNG, 0 },
+ { "sni-pagemode", XYTSNIPM, CM_INV },
+ { "sni-scrollmode", XYTSNISM, CM_INV },
+ { "spacing-attribute-character", XYTSAC, CM_INV },
+ { "statusline", XYTSTAT, 0 },
+ { "tra", XYTCTS, CM_INV|CM_ABR },
+ { "transmit-timeout", XYTCTS, 0 },
+#endif /* OS2 */
+
+#ifdef OS2ORUNIX
+ { "transparent-print", XYTPRN, CM_INV },
+#endif /* OS2ORUNIX */
+
+#ifdef CK_TRIGGER
+ { "trigger", XYTRIGGER,0 },
+#endif /* CK_TRIGGER */
+#ifdef OS2
+ { "type", XYTTYP, 0 },
+#else
+ { "type", XYTTYP, CM_INV },
+#endif /* OS2 */
+
+#ifndef NOCSETS
+#ifdef UNICODE
+#ifdef CKOUNI
+ { "unicode", XYTUNI, CM_INV },
+#endif /* CKOUNI */
+#endif /* UNICODE */
+#endif /* NOCSETS */
+#ifdef OS2
+ { "unix-mode", XYTUNX, CM_INV },
+ { "url-highlight", XYTURLHI, 0 },
+#ifdef NT
+ { "video-change", XYTVCH, 0 },
+#endif /* NT */
+ { "vt-language", XYTVTLNG, 0 },
+ { "vt-nrc-mode", XYTVTNRC, 0 },
+#endif /* OS2 */
+ { "width", XYTWID, 0 },
+#ifdef OS2
+ { "wrap", XYTWRP, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int ntrm = (sizeof(trmtab) / sizeof(struct keytab)) - 1;
+
+#ifdef OS2
+struct keytab termctrl[] = { /* SET TERM CONTROLS */
+ { "7", 7, 0 },
+ { "8", 8, 0 }
+};
+int ntermctrl = (sizeof(termctrl) / sizeof(struct keytab));
+
+struct keytab curontab[] = { /* SET TERM CURSOR */
+#ifdef KUI
+ { "noblink", 2, 0 },
+#else
+ { "noblink", 2, CM_INV },
+#endif /* KUI */
+ { "off", 0, 0 },
+ { "on", 1, 0 }
+};
+int ncuron = (sizeof(curontab) / sizeof(struct keytab));
+
+struct keytab rolltab[] = { /* Set TERM Roll Options */
+ { "insert", TTR_INSERT, 0 },
+ { "keystrokes",TTR_KEYS, 0 },
+ { "off", TTR_OVER, CM_INV },
+ { "on", TTR_INSERT, CM_INV },
+ { "overwrite", TTR_OVER, 0 }
+};
+int nroll = (sizeof(rolltab) / sizeof(struct keytab));
+
+struct keytab rollkeytab[] = { /* Set TERM ROLL KEYSTROKES */
+ { "ignore", TTRK_IGN, 0 },
+ { "restore-and-send", TTRK_RST, 0 },
+ { "send", TTRK_SND, 0 }
+};
+int nrollkey = (sizeof(rollkeytab) / sizeof(struct keytab));
+
+#define TT_GR_ALL 4
+#define TT_GR_G0 0
+#define TT_GR_G1 1
+#define TT_GR_G2 2
+#define TT_GR_G3 3
+#define TT_GR_KBD 4
+struct keytab graphsettab[] = { /* DEC VT Graphic Sets */
+ { "all", TT_GR_ALL, 0 },
+ { "g0", TT_GR_G0, 0 },
+ { "g1", TT_GR_G1, 0 },
+ { "g2", TT_GR_G2, 0 },
+ { "g3", TT_GR_G3, 0 },
+ { "keyboard", TT_GR_KBD, 0 }
+};
+int ngraphset = (sizeof(graphsettab) / sizeof(struct keytab));
+#endif /* OS2 */
+
+struct keytab adltab[] = { /* Autodownload Options */
+ { "ask", TAD_ASK, 0 },
+ { "error", TAD_ERR, 0 },
+#ifdef OS2
+ { "kermit", TAD_K, 0 },
+#endif /* OS2 */
+ { "off", TAD_OFF, 0 },
+ { "on", TAD_ON, 0 },
+#ifdef OS2
+ { "zmodem", TAD_Z, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int nadltab = (sizeof(adltab) / sizeof(struct keytab)) - 1;
+
+struct keytab adlerrtab[] = { /* Autodownload Error Options */
+ { "continue", 0, 0 },
+ { "go", 0, CM_INV },
+ { "stop", 1, 0 }
+};
+int nadlerrtab = (sizeof(adlerrtab) / sizeof(struct keytab));
+
+#ifdef OS2
+struct keytab adlxtab[] = { /* Autodownload Options */
+ { "c0-conflicts", TAD_X_C0, 0 },
+ { "detection-method", TAD_X_DETECT, 0 },
+ { "string", TAD_X_STR, 0 }
+};
+int nadlxtab = (sizeof(adlxtab) / sizeof(struct keytab));
+
+struct keytab adldtab[] = { /* Auto-dl Detection Methods */
+ { "packet", ADL_PACK, 0 },
+ { "string", ADL_STR, 0 }
+};
+int nadldtab = (sizeof(adldtab) / sizeof(struct keytab));
+
+struct keytab adlc0tab[] = { /* Auto-dl Detection Methods */
+ { "ignored-by-emulator", 0, 0 },
+ { "processed-by-emulator", 1, 0 }
+};
+int nadlc0tab = (sizeof(adlc0tab) / sizeof(struct keytab));
+
+#ifndef NOCSETS
+struct keytab vtlangtab[] = {
+ { "belgian", VTL_BELGIAN , 0 },
+ { "british", VTL_BRITISH , 0 },
+ { "canadian", VTL_CANADIAN, 0 },
+ { "czech", VTL_CZECH , 0 },
+ { "danish", VTL_DANISH , 0 },
+ { "dutch", VTL_DUTCH , 0 },
+ { "finnish", VTL_FINNISH , 0 },
+ { "french", VTL_FRENCH , 0 },
+ { "french-canadian",VTL_FR_CAN , 0 },
+ { "german", VTL_GERMAN , 0 },
+ { "greek", VTL_GREEK , 0 },
+ { "hebrew", VTL_HEBREW , 0 },
+ { "hungarian", VTL_HUNGARIA, 0 },
+ { "italian", VTL_ITALIAN , 0 },
+ { "latin-american", VTL_LATIN_AM, 0 },
+ { "north-american", VTL_NORTH_AM, 0 },
+ { "norwegian", VTL_NORWEGIA, 0 },
+ { "polish", VTL_POLISH , 0 },
+ { "portugese", VTL_PORTUGES, 0 },
+ { "romanian", VTL_ROMANIAN, 0 },
+ { "russian", VTL_RUSSIAN , 0 },
+ { "scs", VTL_SCS , CM_INV },
+ { "slovak", VTL_SLOVAK , 0 },
+ { "spanish", VTL_SPANISH , 0 },
+ { "swedish", VTL_SWEDISH , 0 },
+ { "swiss-french", VTL_SW_FR , 0 },
+ { "swiss-german", VTL_SW_GR , 0 },
+ { "turkish-f", VTL_TURK_F , CM_INV },
+ { "turkish-q", VTL_TURK_Q , CM_INV }
+};
+int nvtlangtab = (sizeof(vtlangtab) / sizeof(struct keytab));
+#endif /* NOCSETS */
+#endif /* OS2 */
+
+struct keytab crdtab[] = { /* Carriage-return display */
+ { "crlf", 1, 0 },
+ { "normal", 0, 0 }
+};
+extern int tt_crd; /* Carriage-return display variable */
+extern int tt_lfd; /* Linefeed display variable */
+
+#ifdef CK_APC
+extern int apcstatus, apcactive;
+static struct keytab apctab[] = { /* Terminal APC parameters */
+ { "no-input", APC_ON|APC_NOINP,0 },
+ { "off", APC_OFF, 0 },
+ { "on", APC_ON, 0 },
+ { "unchecked", APC_ON|APC_UNCH, 0 },
+ { "unchecked-no-input", APC_ON|APC_NOINP|APC_UNCH, 0 }
+};
+int napctab = (sizeof(apctab) / sizeof(struct keytab));
+#endif /* CK_APC */
+#endif /* NOLOCAL */
+
+extern int autodl, adl_err, adl_ask;
+
+struct keytab beltab[] = { /* Terminal bell mode */
+#ifdef OS2
+ { "audible", XYB_AUD, 0 },
+ { "none", XYB_NONE, 0 },
+#else
+ { "audible", XYB_AUD, CM_INV },
+ { "none", XYB_NONE, CM_INV },
+#endif /* OS2 */
+#ifdef OS2
+ { "off", XYB_NONE, CM_INV },
+ { "on", XYB_AUD, CM_INV },
+#else
+ { "off", XYB_NONE, 0 },
+ { "on", XYB_AUD, 0 },
+#endif /* OS2 */
+#ifdef OS2
+ { "visible", XYB_VIS, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int nbeltab = sizeof(beltab)/sizeof(struct keytab) - 1;
+
+int tt_unicode = 1; /* Use Unicode if possible */
+#ifdef CKTIDLE
+int tt_idlesnd_tmo = 0; /* Idle Send Timeout, disabled */
+char * tt_idlesnd_str = NULL; /* Idle Send String, none */
+char * tt_idlestr = NULL;
+extern int tt_idleact, tt_idlelimit;
+#endif /* CKTIDLE */
+
+#ifdef OS2
+#ifndef NOLOCAL
+/*
+ OS/2 serial communication devices.
+*/
+struct keytab os2devtab[] = {
+ { "1", 1, CM_INV }, /* Invisible synonyms, like */
+ { "2", 2, CM_INV }, /* "set port 1" */
+ { "3", 3, CM_INV },
+ { "4", 4, CM_INV },
+ { "5", 5, CM_INV },
+ { "6", 6, CM_INV },
+ { "7", 7, CM_INV },
+ { "8", 8, CM_INV },
+ { "com1", 1, 0 }, /* Real device names */
+ { "com2", 2, 0 },
+ { "com3", 3, 0 },
+ { "com4", 4, 0 },
+ { "com5", 5, 0 },
+ { "com6", 6, 0 },
+ { "com7", 7, 0 },
+ { "com8", 8, 0 },
+#ifdef OS2ONLY
+ { "slipcom1", 1, 0 }, /* For use with SLIP driver */
+ { "slipcom2", 2, 0 }, /* shared access */
+ { "slipcom3", 3, 0 },
+ { "slipcom4", 4, 0 },
+ { "slipcom5", 5, 0 },
+ { "slipcom6", 6, 0 },
+ { "slipcom7", 7, 0 },
+ { "slipcom8", 8, 0 },
+ { "pppcom1", 1, 0 }, /* For use with PPP driver */
+ { "pppcom2", 2, 0 }, /* shared access */
+ { "pppcom3", 3, 0 },
+ { "pppcom4", 4, 0 },
+ { "pppcom5", 5, 0 },
+ { "pppcom6", 6, 0 },
+ { "pppcom7", 7, 0 },
+ { "pppcom8", 8, 0 }
+#endif /* OS2ONLY */
+};
+int nos2dev = (sizeof(os2devtab) / sizeof(struct keytab)) - 1;
+
+#ifdef OS2ONLY
+struct keytab os2ppptab[] = {
+ { "0", 0, CM_INV },
+ { "1", 1, CM_INV }, /* Invisible synonyms, like */
+ { "2", 2, CM_INV }, /* "set port 1" */
+ { "3", 3, CM_INV },
+ { "4", 4, CM_INV },
+ { "5", 5, CM_INV },
+ { "6", 6, CM_INV },
+ { "7", 7, CM_INV },
+ { "8", 8, CM_INV },
+ { "9", 9, CM_INV },
+ { "ppp0", 0, 0 },
+ { "ppp1", 1, 0 }, /* For use with PPP driver */
+ { "ppp2", 2, 0 }, /* shared access */
+ { "ppp3", 3, 0 },
+ { "ppp4", 4, 0 },
+ { "ppp5", 5, 0 },
+ { "ppp6", 6, 0 },
+ { "ppp7", 7, 0 },
+ { "ppp8", 8, 0 },
+ { "ppp9", 9, 0 }
+};
+int nos2ppp = (sizeof(os2ppptab) / sizeof(struct keytab));
+#endif /* OS2ONLY */
+
+/*
+ Terminal parameters that can be set by SET commands.
+ Used by the ck?con.c terminal emulator code.
+ For now, only used for #ifdef OS2. Should add these for Macintosh.
+*/
+int tt_arrow = TTK_NORM; /* Arrow key mode: normal (cursor) */
+int tt_keypad = TTK_NORM; /* Keypad mode: normal (numeric) */
+int tt_shift_keypad = 0; /* Keypad Shift mode: Off */
+int tt_wrap = 1; /* Terminal wrap, 1 = On */
+int tt_type = TT_VT220; /* Terminal type, initially VT220 */
+int tt_type_mode = TT_VT220; /* Terminal type set by host command */
+int tt_cursor = 0; /* Terminal cursor, 0 = Underline */
+int tt_cursor_usr = 0; /* Users Terminal cursor type */
+int tt_cursorena_usr = 1; /* Users Terminal cursor enabled */
+int tt_cursor_blink = 1; /* Terminal Cursor Blink */
+int tt_answer = 0; /* Terminal answerback (disabled) */
+int tt_scrsize[VNUM] = {512,512,512,1}; /* Terminal scrollback buffer size */
+int tt_roll[VNUM] = {1,1,1,1}; /* Terminal roll (on) */
+int tt_rkeys[VNUM] = {1,1,1,1}; /* Terminal roll keys (send) */
+int tt_pacing = 0; /* Terminal output-pacing (none) */
+int tt_ctstmo = 15; /* Terminal transmit-timeout */
+int tt_codepage = -1; /* Terminal code-page */
+int tt_update = 100; /* Terminal screen-update interval */
+int tt_updmode = TTU_FAST; /* Terminal screen-update mode FAST */
+extern int updmode;
+#ifndef KUI
+int tt_status[VNUM] = {1,1,0,0}; /* Terminal status line displayed */
+int tt_status_usr[VNUM] = {1,1,0,0};
+#else /* KUI */
+extern CKFLOAT floatval;
+CKFLOAT tt_linespacing[VNUM] = {1.0,1.0,1.0,1.0};
+#ifdef K95G
+int tt_status[VNUM] = {1,1,0,0}; /* Terminal status line displayed */
+int tt_status_usr[VNUM] = {1,1,0,0};
+#else /* K95G */
+int tt_status[VNUM] = {0,0,0,0}; /* Terminal status line displayed */
+int tt_status_usr[VNUM] = {0,0,0,0};
+#endif /* K95G */
+#endif /* KUI */
+int tt_senddata = 0; /* Let host read terminal data */
+extern int wy_blockend; /* Terminal Send Data EOB type */
+int tt_hidattr = 1; /* Attributes are hidden */
+
+extern unsigned char colornormal, colorselect,
+colorunderline, colorstatus, colorhelp, colorborder,
+colorgraphic, colordebug, colorreverse, coloritalic;
+
+extern int trueblink, trueunderline, truereverse, trueitalic, truedim;
+
+extern int bgi, fgi;
+extern int scrninitialized[];
+
+struct keytab audibletab[] = { /* Terminal Bell Audible mode */
+ { "beep", XYB_BEEP, 0 }, /* Values ORd with bell mode */
+ { "system-sounds", XYB_SYS, 0 }
+};
+int naudibletab = sizeof(audibletab)/sizeof(struct keytab);
+
+struct keytab akmtab[] = { /* Arrow key mode */
+ { "application", TTK_APPL, 0 },
+ { "cursor", TTK_NORM, 0 }
+};
+struct keytab kpmtab[] = { /* Keypad mode */
+ { "application", TTK_APPL, 0 },
+ { "numeric", TTK_NORM, 0 }
+};
+
+struct keytab ttcolmodetab[] = {
+ { "current-color", 0, 0 },
+ { "default-color", 1, 0 }
+};
+int ncolmode = sizeof(ttcolmodetab)/sizeof(struct keytab);
+
+#define TTCOLNOR 0
+#define TTCOLREV 1
+#define TTCOLUND 2
+#define TTCOLSTA 3
+#define TTCOLHLP 4
+#define TTCOLBOR 5
+#define TTCOLSEL 6
+#define TTCOLDEB 7
+#define TTCOLGRP 8
+#define TTCOLITA 9
+#define TTCOLRES 10
+#define TTCOLERA 11
+
+struct keytab ttycoltab[] = { /* Terminal Screen coloring */
+ { "border", TTCOLBOR, 0 }, /* Screen border color */
+ { "debug-terminal", TTCOLDEB, 0 }, /* Debug color */
+ { "erase", TTCOLERA, 0 }, /* Erase mode */
+ { "graphic", TTCOLGRP, 0 }, /* Graphic Color */
+ { "help-text", TTCOLHLP, 0 }, /* Help screens */
+ { "italic", TTCOLITA, 0 }, /* Italic Color */
+ { "normal", TTCOLNOR, CM_INV }, /* Normal screen text */
+ { "reset-on-esc[0m", TTCOLRES, 0 }, /* Reset on ESC [ 0 m */
+ { "reverse-video", TTCOLREV, 0 }, /* Reverse video */
+ { "status-line", TTCOLSTA, 0 }, /* Status line */
+ { "selection", TTCOLSEL, 0 }, /* Selection color */
+ { "terminal-screen", TTCOLNOR, 0 }, /* Better name than "normal" */
+ { "underlined-text", TTCOLUND, 0 } /* Underlined text */
+};
+int ncolors = (sizeof(ttycoltab) / sizeof(struct keytab));
+
+#define TTATTNOR 0
+#define TTATTBLI 1
+#define TTATTREV 2
+#define TTATTUND 3
+#define TTATTPRO 4
+#define TTATTBLD 5
+#define TTATTDIM 6
+#define TTATTINV 7
+#define TTATTITA 8
+#define TTATTDONE 9
+
+struct keytab ttyattrtab[] = {
+ { "blink", TTATTBLI, 0 },
+ { "dim", TTATTDIM, 0 },
+ { "italic", TTATTITA, 0 },
+ { "protected", TTATTPRO, 0 },
+ { "reverse", TTATTREV, 0 },
+ { "underline", TTATTUND, 0 }
+};
+int nattrib = (sizeof(ttyattrtab) / sizeof(struct keytab));
+
+struct keytab ttyprotab[] = {
+ { "blink", TTATTBLI, 0 },
+ { "bold", TTATTBLD, 0 },
+ { "dim", TTATTDIM, 0 },
+ { "done", TTATTDONE, CM_INV },
+ { "invisible", TTATTINV, 0 },
+ { "italic", TTATTITA, 0 },
+ { "normal", TTATTNOR, 0 },
+ { "reverse", TTATTREV, 0 },
+ { "underlined", TTATTUND, 0 }
+
+};
+int nprotect = (sizeof(ttyprotab) / sizeof(struct keytab));
+
+struct keytab ttyseobtab[] = {
+ { "crlf_etx", 1, 0 },
+ { "us_cr", 0, 0 }
+};
+
+struct keytab ttyclrtab[] = { /* Colors */
+ { "black", 0, 0 },
+ { "blue", 1, 0 },
+ { "brown", 6, 0 },
+ { "cyan", 3, 0 },
+ { "darkgray", 8, CM_INV },
+ { "dgray", 8, 0 },
+ { "green", 2, 0 },
+ { "lblue", 9, CM_INV },
+ { "lcyan", 11, CM_INV },
+ { "lgray", 7, CM_INV },
+ { "lgreen", 10, CM_INV },
+ { "lightblue", 9, 0 },
+ { "lightcyan", 11, 0 },
+ { "lightgray", 7, 0 },
+ { "lightgreen", 10, 0 },
+ { "lightmagenta", 13, 0 },
+ { "lightred", 12, 0 },
+ { "lmagenta", 13, CM_INV },
+ { "lred", 12, CM_INV },
+ { "magenta", 5, 0 },
+ { "red", 4, 0 },
+ { "white", 15, 0 },
+ { "yellow", 14, 0 }
+};
+int nclrs = (sizeof (ttyclrtab) / sizeof (struct keytab));
+
+struct keytab ttycurtab[] = {
+ { "full", TTC_BLOCK, 0 },
+ { "half", TTC_HALF, 0 },
+ { "underline", TTC_ULINE, 0 }
+};
+int ncursors = 3;
+
+struct keytab ttyptab[] = {
+ { "aaa", TT_AAA, CM_INV }, /* AnnArbor */
+ { "adm3a", TT_ADM3A, 0 }, /* LSI ADM-3A */
+ { "adm5", TT_ADM5, 0 }, /* LSI ADM-5 */
+ { "aixterm", TT_AIXTERM, 0 }, /* IBM AIXterm */
+ { "annarbor", TT_AAA, 0 }, /* AnnArbor */
+ { "ansi-bbs", TT_ANSI, 0 }, /* ANSI.SYS (BBS) */
+ { "at386", TT_AT386, 0 }, /* Unixware ANSI */
+ { "avatar/0+",TT_ANSI, 0 }, /* AVATAR/0+ */
+ { "ba80", TT_BA80, 0 }, /* Nixdorf BA80 */
+ { "be", TT_BEOS, CM_INV|CM_ABR },
+ { "beos-ansi",TT_BEOS, CM_INV }, /* BeOS ANSI */
+ { "beterm", TT_BEOS, 0 }, /* BeOS Terminal (as of PR2 ) */
+ { "d200", TT_DG200, CM_INV|CM_ABR }, /* Data General DASHER 200 */
+ { "d210", TT_DG210, CM_INV|CM_ABR }, /* Data General DASHER 210 */
+ { "d217", TT_DG217, CM_INV|CM_ABR }, /* Data General DASHER 217 */
+ { "dg200", TT_DG200, 0 }, /* Data General DASHER 200 */
+ { "dg210", TT_DG210, 0 }, /* Data General DASHER 210 */
+ { "dg217", TT_DG217, 0 }, /* Data General DASHER 217 */
+ { "h1500", TT_HZL1500, CM_INV }, /* Hazeltine 1500 */
+ { "h19", TT_H19, CM_INV }, /* Heath-19 */
+ { "heath19", TT_H19, 0 }, /* Heath-19 */
+ { "hft", TT_HFT, 0 }, /* IBM High Function Terminal */
+ { "hp2621a", TT_HP2621, 0 }, /* HP 2621A */
+ { "hpterm", TT_HPTERM, 0 }, /* HP TERM */
+ { "hz1500", TT_HZL1500, 0 }, /* Hazeltine 1500 */
+ { "ibm3151", TT_IBM31, 0 }, /* IBM 3101-xx,3161 */
+ { "linux", TT_LINUX, 0 }, /* Linux */
+ { "qansi", TT_QANSI, 0 }, /* QNX ANSI */
+ { "qnx", TT_QNX, 0 }, /* QNX Console */
+ { "scoansi", TT_SCOANSI, 0 }, /* SCO ANSI */
+ { "sni-97801",TT_97801, 0 }, /* SNI 97801 */
+ { "sun", TT_SUN, 0 }, /* SUN Console */
+/*
+ The idea of NONE is to let the console driver handle the escape sequences,
+ which, in theory at least, would give not only ANSI emulation, but also any
+ other kind of emulation that might be provided by alternative console
+ drivers, if any existed.
+
+ For this to work, ckocon.c would need to be modified to make higher-level
+ calls, like VioWrtTTY(), DosWrite(), or (simply) write(), rather than
+ VioWrt*Cell() and similar, and it would also have to give up its rollback
+ feature, and its status line and help screens would also have to be
+ forgotten or else done in an ANSI way.
+
+ As matters stand, we already have perfectly good ANSI emulation built in,
+ and there are no alternative console drivers available, so there is no point
+ in having a terminal type of NONE, so it is commented out. However, should
+ you uncomment it, it will work like a "glass tty" -- no escape sequence
+ interpretation at all; somewhat similar to debug mode, except without the
+ debugging (no highlighting of control chars or escape sequences); help
+ screens, status line, and rollback will still work.
+*/
+#ifdef OS2PM
+#ifdef COMMENT
+ { "tek4014", TT_TEK40, 0 },
+#endif /* COMMENT */
+#endif /* OS2PM */
+ { "tty", TT_NONE, 0 },
+ { "tvi910+", TT_TVI910, 0 },
+ { "tvi925", TT_TVI925, 0 },
+ { "tvi950", TT_TVI950, 0 },
+ { "vc404", TT_VC4404, 0 },
+ { "vc4404", TT_VC4404, CM_INV },
+ { "vip7809", TT_VIP7809,0 },
+ { "vt100", TT_VT100, 0 },
+ { "vt102", TT_VT102, 0 },
+ { "vt220", TT_VT220, 0 },
+ { "vt220pc", TT_VT220PC,0 },
+ { "vt320", TT_VT320, 0 },
+ { "vt320pc", TT_VT320PC,0 },
+ { "vt52", TT_VT52, 0 },
+#ifdef NT
+ { "vtnt", TT_VTNT, 0 },
+#else /* NT */
+ { "vtnt", TT_VTNT, CM_INV },
+#endif /* NT */
+ { "wy160", TT_WY160, 0 },
+ { "wy30", TT_WY30, 0 },
+ { "wy370", TT_WY370, 0 },
+ { "wy50", TT_WY50, 0 },
+ { "wy60", TT_WY60, 0 },
+ { "wyse30", TT_WY30, CM_INV },
+ { "wyse370", TT_WY370, CM_INV },
+ { "wyse50", TT_WY50, CM_INV },
+ { "wyse60", TT_WY60, CM_INV }
+};
+int nttyp = (sizeof(ttyptab) / sizeof(struct keytab));
+
+struct keytab ttkeytab[] = {
+ { "aaa", TT_AAA, CM_INV }, /* AnnArbor */
+ { "adm3a", TT_ADM3A, 0 }, /* LSI ADM-3A */
+ { "adm5", TT_ADM5, 0 }, /* LSI ADM-5 */
+ { "aixterm", TT_AIXTERM, 0 }, /* IBM AIXterm */
+ { "annarbor", TT_AAA, 0 }, /* AnnArbor */
+ { "ansi-bbs", TT_ANSI, 0 }, /* ANSI.SYS (BBS) */
+ { "at386", TT_AT386, 0 }, /* Unixware ANSI */
+ { "avatar/0+", TT_ANSI, 0 }, /* AVATAR/0+ */
+ { "ba80", TT_BA80, 0 }, /* Nixdorf BA80 */
+ { "be", TT_BEOS, CM_INV|CM_ABR },
+ { "beos-ansi", TT_BEOS, CM_INV }, /* BeOS ANSI */
+ { "beterm", TT_BEOS, 0 }, /* BeOS Terminal (DR2) */
+ { "d200", TT_DG200, CM_INV|CM_ABR }, /* DG DASHER 200 */
+ { "d210", TT_DG210, CM_INV|CM_ABR }, /* DG DASHER 210 */
+ { "d217", TT_DG217, CM_INV|CM_ABR }, /* DG DASHER 217 */
+ { "dg200", TT_DG200, 0 }, /* DG DASHER 200 */
+ { "dg210", TT_DG210, 0 }, /* DG DASHER 210 */
+ { "dg217", TT_DG217, 0 }, /* DG DASHER 217 */
+ { "emacs", TT_KBM_EMACS, 0 }, /* Emacs mode */
+ { "h19", TT_H19, CM_INV }, /* Heath-19 */
+ { "heath19", TT_H19, 0 }, /* Heath-19 */
+ { "hebrew", TT_KBM_HEBREW, 0 }, /* Hebrew mode */
+ { "hft", TT_HFT, 0 }, /* IBM High Function Term */
+ { "hp2621a", TT_HP2621, 0 }, /* HP 2621A */
+ { "hpterm", TT_HPTERM, 0 }, /* HP TERM */
+ { "hz1500", TT_HZL1500, 0 }, /* Hazeltine 1500 */
+ { "ibm3151", TT_IBM31, 0 }, /* IBM 3101-xx,3161 */
+ { "linux", TT_LINUX, 0 }, /* Linux */
+ { "qansi", TT_QANSI, 0 }, /* QNX ANSI */
+ { "qnx", TT_QNX, 0 }, /* QNX */
+ { "russian", TT_KBM_RUSSIAN,0 }, /* Russian mode */
+ { "scoansi", TT_SCOANSI, 0 }, /* SCO ANSI */
+ { "sni-97801", TT_97801, 0 }, /* SNI 97801 */
+ { "sun", TT_SUN, 0 }, /* SUN Console */
+#ifdef OS2PM
+#ifdef COMMENT
+ { "tek4014", TT_TEK40, 0 },
+#endif /* COMMENT */
+#endif /* OS2PM */
+ { "tty", TT_NONE, 0 },
+ { "tvi910+", TT_TVI910, 0 },
+ { "tvi925", TT_TVI925, 0 },
+ { "tvi950", TT_TVI950, 0 },
+ { "vc404", TT_VC4404, 0 },
+ { "vc4404", TT_VC4404, CM_INV },
+ { "vip7809", TT_VIP7809, 0 },
+ { "vt100", TT_VT100, 0 },
+ { "vt102", TT_VT102, 0 },
+ { "vt220", TT_VT220, 0 },
+ { "vt220pc", TT_VT220PC, 0 },
+ { "vt320", TT_VT320, 0 },
+ { "vt320pc", TT_VT320PC, 0 },
+ { "vt52", TT_VT52, 0 },
+ { "vtnt", TT_VTNT, CM_INV },
+ { "wp", TT_KBM_WP, 0 }, /* Word Perfect mode */
+ { "wy160", TT_WY160, 0 },
+ { "wy30", TT_WY30, 0 },
+ { "wy370", TT_WY370, 0 },
+ { "wy50", TT_WY50, 0 },
+ { "wy60", TT_WY60, 0 },
+ { "wyse30", TT_WY30, CM_INV },
+ { "wyse370", TT_WY370, CM_INV },
+ { "wyse50", TT_WY50, CM_INV },
+ { "wyse60", TT_WY60, CM_INV }
+};
+int nttkey = (sizeof(ttkeytab) / sizeof(struct keytab));
+
+#ifndef NOSETKEY
+struct keytab kbmodtab[] = {
+ { "emacs", KBM_EM, 0 },
+ { "english", KBM_EN, CM_INV },
+ { "hebrew", KBM_HE, 0 },
+ { "normal", KBM_EN, 0 },
+ { "none", KBM_EN, CM_INV },
+ { "russian", KBM_RU, 0 },
+ { "wp", KBM_WP, 0 }
+};
+int nkbmodtab = (sizeof(kbmodtab) / sizeof(struct keytab));
+#endif /* NOSETKEY */
+#endif /* NOLOCAL */
+
+int tt_inpacing = 0; /* input-pacing (none) */
+
+struct keytab prtytab[] = { /* OS/2 Priority Levels */
+ { "foreground-server", XYP_SRV, 0 },
+ { "idle", XYP_IDLE, CM_INV },
+ { "regular", XYP_REG, 0 },
+ { "time-critical", XYP_RTP, 0 }
+};
+int nprty = (sizeof(prtytab) / sizeof(struct keytab));
+#endif /* OS2 */
+
+#ifdef NT
+struct keytab win95tab[] = { /* Win95 work-arounds */
+ { "8.3-filenames", XYW8_3, 0 },
+ { "alt-gr", XYWAGR, 0 },
+ { "horizontal-scan-line-substitutions", XYWHSL, 0 },
+ { "keyboard-translation", XYWKEY, 0 },
+ { "lucida-substitutions", XYWLUC, 0 },
+ { "overlapped-io", XYWOIO, 0 },
+ { "popups", XYWPOPUP, 0 },
+ { "select-bug", XYWSELECT, 0 }
+};
+int nwin95 = (sizeof(win95tab) / sizeof(struct keytab));
+#endif /* NT */
+
+#ifdef OS2MOUSE
+extern int wideresult;
+int tt_mouse = 1; /* Terminal mouse on/off */
+
+struct keytab mousetab[] = { /* Mouse items */
+ { "activate", XYM_ON, 0 },
+ { "button", XYM_BUTTON, 0 },
+ { "clear", XYM_CLEAR, 0 },
+ { "debug", XYM_DEBUG, 0 }
+};
+int nmtab = (sizeof(mousetab)/sizeof(struct keytab));
+
+struct keytab mousebuttontab[] = { /* event button */
+ { "1", XYM_B1, 0 },
+ { "2", XYM_B2, 0 },
+ { "3", XYM_B3, 0 },
+ { "one", XYM_B1, CM_INV },
+ { "three", XYM_B3, CM_INV },
+ { "two", XYM_B2, CM_INV }
+};
+int nmbtab = (sizeof(mousebuttontab) / sizeof(struct keytab));
+
+struct keytab mousemodtab[] = { /* event button key modifier */
+ { "alt", XYM_ALT, 0 },
+ { "alt-shift", XYM_SHIFT|XYM_ALT, 0 },
+ { "ctrl", XYM_CTRL, 0 },
+ { "ctrl-alt", XYM_CTRL|XYM_ALT, 0 },
+ { "ctrl-alt-shift", XYM_CTRL|XYM_SHIFT|XYM_ALT, 0 },
+ { "ctrl-shift", XYM_CTRL|XYM_SHIFT, 0 },
+ { "none", 0, 0 },
+ { "shift", XYM_SHIFT, 0 }
+};
+int nmmtab = (sizeof(mousemodtab) / sizeof(struct keytab));
+
+struct keytab mclicktab[] = { /* event button click modifier */
+ { "click", XYM_C1, 0 },
+ { "drag", XYM_DRAG, 0 },
+ { "double-click", XYM_C2, 0 }
+};
+int nmctab = (sizeof(mclicktab) / sizeof(struct keytab));
+
+#ifndef NOKVERBS
+extern int nkverbs;
+extern struct keytab kverbs[];
+#endif /* NOKVERBS */
+#endif /* OS2MOUSE */
+
+/* #ifdef VMS */
+struct keytab fbtab[] = { /* Binary record types for VMS */
+ { "fixed", XYFT_B, 0 }, /* Fixed is normal for binary */
+ { "undefined", XYFT_U, 0 } /* Undefined if they ask for it */
+};
+int nfbtyp = (sizeof(fbtab) / sizeof(struct keytab));
+/* #endif */
+
+#ifdef VMS
+struct keytab lbltab[] = { /* Labeled File info */
+ { "acl", LBL_ACL, 0 },
+ { "backup-date", LBL_BCK, 0 },
+ { "name", LBL_NAM, 0 },
+ { "owner", LBL_OWN, 0 },
+ { "path", LBL_PTH, 0 }
+};
+int nlblp = (sizeof(lbltab) / sizeof(struct keytab));
+#else
+#ifdef OS2
+struct keytab lbltab[] = { /* Labeled File info */
+ { "archive", LBL_ARC, 0 },
+ { "extended", LBL_EXT, 0 },
+ { "hidden", LBL_HID, 0 },
+ { "read-only", LBL_RO, 0 },
+ { "system", LBL_SYS, 0 }
+};
+int nlblp = (sizeof(lbltab) / sizeof(struct keytab));
+#endif /* OS2 */
+#endif /* VMS */
+
+#ifdef CK_CURSES
+#ifdef CK_PCT_BAR
+static struct keytab fdftab[] = { /* SET FILE DISPLAY FULL options */
+ { "thermometer", 1, 0, },
+ { "no-thermometer", 0, 0 }
+};
+extern int thermometer;
+#endif /* CK_PCT_BAR */
+#endif /* CK_CURSES */
+
+static struct keytab fdtab[] = { /* SET FILE DISPLAY options */
+#ifdef MAC /* Macintosh */
+ { "fullscreen", XYFD_R, 0 }, /* Full-screen but not curses */
+ { "none", XYFD_N, 0 },
+ { "off", XYFD_N, CM_INV },
+ { "on", XYFD_R, CM_INV },
+ { "quiet", XYFD_N, CM_INV },
+#else /* Not Mac */
+ { "brief", XYFD_B, 0 }, /* Brief */
+ { "crt", XYFD_S, 0 }, /* CRT display */
+#ifdef CK_CURSES
+#ifdef COMMENT
+ { "curses", XYFD_C, CM_INV }, /* Full-screen, curses */
+#endif /* COMMENT */
+ { "fullscreen", XYFD_C, 0 }, /* Full-screen, whatever the method */
+#endif /* CK_CURSES */
+#ifdef KUI
+ { "gui", XYFD_G, 0 }, /* GUI */
+#endif /* KUI */
+ { "none", XYFD_N, 0 }, /* No display */
+ { "off", XYFD_N, CM_INV }, /* Ditto */
+ { "on", XYFD_R, CM_INV }, /* On = Serial */
+ { "quiet", XYFD_N, CM_INV }, /* No display */
+ { "serial", XYFD_R, 0 }, /* Serial */
+#endif /* MAC */
+ { "", 0, 0 }
+};
+int nfdtab = (sizeof(fdtab) / sizeof(struct keytab)) - 1;
+
+struct keytab rsrtab[] = { /* For REMOTE SET RECEIVE */
+ { "packet-length", XYLEN, 0 },
+ { "timeout", XYTIMO, 0 }
+};
+int nrsrtab = (sizeof(rsrtab) / sizeof(struct keytab));
+
+/* Send/Receive Parameters */
+
+struct keytab srtab[] = {
+ { "backup", XYBUP, 0 },
+#ifndef NOCSETS
+ { "character-set-selection", XYCSET, 0 },
+#endif /* NOCSETS */
+ { "control-prefix", XYQCTL, 0 },
+#ifdef CKXXCHAR
+ { "double-character", XYDBL, 0 },
+#endif /* CKXXCHAR */
+ { "end-of-packet", XYEOL, 0 },
+#ifdef PIPESEND
+ { "filter", XYFLTR, 0 },
+#endif /* PIPESEND */
+#ifdef CKXXCHAR
+ { "ignore-character", XYIGN, 0 },
+#endif /* CKXXCHAR */
+ { "i-packets", 993, 0 },
+ { "move-to", XYMOVE, 0 },
+ { "negotiation-string-max-length", XYINIL, CM_INV },
+ { "packet-length", XYLEN, 0 },
+ { "pad-character", XYPADC, 0 },
+ { "padding", XYNPAD, 0 },
+ { "pathnames", XYFPATH, 0 },
+ { "pause", XYPAUS, 0 },
+#ifdef CK_PERMS
+ { "permissions", 994, 0}, /* 206 */
+#endif /* CK_PERMS */
+ { "quote", XYQCTL, CM_INV }, /* = CONTROL-PREFIX */
+ { "rename-to", XYRENAME, 0 },
+ { "start-of-packet", XYMARK, 0 },
+ { "timeout", XYTIMO, 0 },
+#ifdef VMS
+ { "version-numbers", 887, 0 }, /* VMS version numbers */
+#endif /* VMS */
+ { "", 0, 0 }
+};
+int nsrtab = (sizeof(srtab) / sizeof(struct keytab)) - 1;
+
+#ifdef UNICODE
+#define UCS_BOM 1
+#define UCS_BYT 2
+static struct keytab ucstab[] = {
+ { "bom", UCS_BOM, 0 },
+ { "byte-order", UCS_BYT, 0 },
+ { "", 0, 0 }
+};
+int nucstab = (sizeof(ucstab) / sizeof(struct keytab)) - 1;
+
+static struct keytab botab[] = {
+ { "big-endian", 0, 0 },
+ { "little-endian", 1, 0 }
+};
+static int nbotab = 2;
+#endif /* UNICODE */
+
+/* REMOTE SET */
+
+struct keytab rmstab[] = {
+ { "attributes", XYATTR, 0 },
+ { "block-check", XYCHKT, 0 },
+ { "file", XYFILE, 0 },
+ { "incomplete", XYIFD, CM_INV }, /* = REMOTE SET FILE INCOMPLETE */
+ { "match", XYMATCH,0 },
+ { "receive", XYRECV, 0 },
+ { "retry", XYRETR, 0 },
+ { "server", XYSERV, 0 },
+ { "transfer", XYXFER, 0 },
+ { "window", XYWIND, 0 },
+ { "xfer", XYXFER, CM_INV }
+};
+int nrms = (sizeof(rmstab) / sizeof(struct keytab));
+
+struct keytab attrtab[] = {
+#ifdef STRATUS
+ { "account", AT_ACCT, 0 },
+#endif /* STRATUS */
+ { "all", AT_XALL, 0 },
+#ifdef COMMENT
+ { "blocksize", AT_BLKS, 0 }, /* (not used) */
+#endif /* COMMENT */
+#ifndef NOCSETS
+ { "character-set", AT_ENCO, 0 },
+#endif /* NOCSETS */
+#ifdef STRATUS
+ { "creator", AT_CREA, 0 },
+#endif /* STRATUS */
+ { "date", AT_DATE, 0 },
+ { "disposition", AT_DISP, 0 },
+ { "encoding", AT_ENCO, CM_INV },
+ { "format", AT_RECF, CM_INV },
+ { "length", AT_LENK, 0 },
+ { "off", AT_ALLN, 0 },
+ { "on", AT_ALLY, 0 },
+#ifdef COMMENT
+ { "os-specific", AT_SYSP, 0 }, /* (not used by UNIX or VMS) */
+#endif /* COMMENT */
+#ifdef CK_PERMS
+ { "protection", AT_LPRO, 0 },
+ { "permissions", AT_LPRO, CM_INV },
+#endif /* CK_PERMS */
+ { "record-format", AT_RECF, 0 },
+ { "system-id", AT_SYSI, 0 },
+ { "type", AT_FTYP, 0 }
+};
+int natr = (sizeof(attrtab) / sizeof(struct keytab)); /* how many attributes */
+
+#ifdef CKTIDLE
+struct keytab idlacts[] = {
+ { "exit", IDLE_EXIT, 0 },
+ { "hangup", IDLE_HANG, 0 },
+ { "output", IDLE_OUT, 0 },
+ { "return", IDLE_RET, 0 },
+#ifdef TNCODE
+ { "telnet-nop", IDLE_TNOP, 0 },
+ { "telnet-ayt", IDLE_TAYT, 0 },
+#endif /* TNCODE */
+ { "", 0, 0 }
+};
+int nidlacts = (sizeof(idlacts) / sizeof(struct keytab)) - 1;
+#endif /* CKTIDLE */
+
+#ifndef NOSPL
+extern int indef, inecho, insilence, inbufsize, inautodl, inintr;
+#ifdef CKFLOAT
+extern CKFLOAT inscale;
+#endif /* CKFLOAT */
+extern char * inpbuf, * inpbp;
+#ifdef OS2
+extern int interm;
+#endif /* OS2 */
+struct keytab inptab[] = { /* SET INPUT parameters */
+#ifdef CK_AUTODL
+ { "autodownload", IN_ADL, 0 },
+#endif /* CK_AUTODL */
+ { "buffer-length", IN_BUF, 0 },
+ { "cancellation", IN_CAN, 0 },
+ { "case", IN_CAS, 0 },
+ { "default-timeout", IN_DEF, CM_INV }, /* There is no default timeout */
+ { "echo", IN_ECH, 0 },
+#ifdef OS2
+ { "pacing", IN_PAC, CM_INV },
+#endif /* OS2 */
+ { "scale-factor", IN_SCA, 0 },
+ { "silence", IN_SIL, 0 },
+#ifdef OS2
+ { "terminal", IN_TRM, 0 },
+#endif /* OS2 */
+ { "timeout-action", IN_TIM, 0 }
+};
+int ninp = (sizeof(inptab) / sizeof(struct keytab));
+
+struct keytab intimt[] = { /* SET INPUT TIMEOUT parameters */
+ { "proceed", 0, 0 }, /* 0 = proceed */
+ { "quit", 1, 0 } /* 1 = quit */
+};
+
+struct keytab incast[] = { /* SET INPUT CASE parameters */
+ { "ignore", 0, 0 }, /* 0 = ignore */
+ { "observe", 1, 0 } /* 1 = observe */
+};
+#endif /* NOSPL */
+
+struct keytab nabltab[] = { /* For any command that needs */
+ { "disabled", 0, 0 },
+ { "enabled", 1, 0 },
+ { "off", 0, CM_INV }, /* these keywords... */
+ { "on", 1, CM_INV }
+};
+int nnabltab = sizeof(nabltab) / sizeof(struct keytab);
+
+#ifdef OS2
+struct keytab tvctab[] = { /* SET TERM VIDEO-CHANGE */
+ { "disabled", TVC_DIS, 0 },
+ { "enabled", TVC_ENA, 0 },
+#ifdef NT
+ { "win95-safe", TVC_W95, 0 },
+#endif /* NT */
+ { "", 0, 0 }
+};
+int ntvctab = (sizeof(tvctab) / sizeof(struct keytab)) - 1;
+
+struct keytab msktab[] = { /* SET MS-DOS KERMIT compatibilities */
+#ifdef COMMENT
+ { "color", MSK_COLOR, 0 },
+#endif /* COMMENT */
+ { "file-renaming", MSK_REN, 0 },
+ { "keycodes", MSK_KEYS, 0 }
+};
+int nmsk = (sizeof(msktab) / sizeof(struct keytab));
+
+struct keytab scrnupd[] = { /* SET TERMINAL SCREEN-UPDATE */
+ { "fast", TTU_FAST, 0 },
+ { "smooth", TTU_SMOOTH, 0 }
+};
+int nscrnupd = (sizeof(scrnupd) / sizeof(struct keytab));
+
+#ifdef PCFONTS
+/* This definition of the term_font[] table is only for */
+/* the OS/2 Full Screen Session and is not used on Windows */
+struct keytab term_font[] = { /* SET TERMINAL FONT */
+#ifdef COMMENT
+ { "cp111", TTF_111, 0 },
+ { "cp112", TTF_112, 0 },
+ { "cp113", TTF_113, 0 },
+#endif /* COMMENT */
+ { "cp437", TTF_437, 0 },
+ { "cp850", TTF_850, 0 },
+#ifdef COMMENT
+ { "cp851", TTF_851, 0 },
+#endif /* COMMENT */
+ { "cp852", TTF_852, 0 },
+#ifdef COMMENT
+ { "cp853", TTF_853, 0 },
+ { "cp860", TTF_860, 0 },
+ { "cp861", TTF_861, 0 },
+#endif /* COMMENT */
+ { "cp862", TTF_862, 0 },
+#ifdef COMMENT
+ { "cp863", TTF_863, 0 },
+ { "cp864", TTF_864, 0 },
+ { "cp865", TTF_865, 0 },
+#endif /* COMMENT */
+ { "cp866", TTF_866, 0 },
+#ifdef COMMENT
+ { "cp880", TTF_880, 0 },
+ { "cp881", TTF_881, 0 },
+ { "cp882", TTF_882, 0 },
+ { "cp883", TTF_883, 0 },
+ { "cp884", TTF_884, 0 },
+ { "cp885", TTF_885, 0 },
+#endif /* COMMENT */
+ { "default",TTF_ROM,0 }
+};
+int ntermfont = (sizeof(term_font) / sizeof(struct keytab));
+int tt_font = TTF_ROM; /* Terminal screen font */
+#else /* PCFONTS */
+#ifdef NT
+#ifdef KUI
+struct keytab * term_font = NULL;
+struct keytab * _term_font = NULL;
+char * tt_facename = NULL;
+int ntermfont = 0;
+int tt_font = 0;
+int tt_font_size = 0;
+#endif /* KUI */
+#endif /* NT */
+#endif /* PCFONTS */
+
+struct keytab anbktab[] = { /* For any command that needs */
+ { "message", 2, 0 }, /* these keywords... */
+ { "off", 0, 0 },
+ { "on", 1, 0 },
+ { "unsafe-messag0", 99, CM_INV },
+ { "unsafe-message", 3, CM_INV }
+};
+int nansbk = (sizeof(anbktab) / sizeof(struct keytab));
+
+int win95_popup = 1;
+#ifdef NT
+#ifdef KUI
+int win95lucida = 0;
+int win95hsl = 1;
+#else /* KUI */
+int win95lucida = 1;
+int win95hsl = 1;
+#endif /* KUI */
+#else /* NT */
+int win95lucida = 0;
+int win95hsl = 1;
+#endif /* NT */
+#ifdef NT
+int win95altgr = 0;
+extern int win95selectbug;
+extern int win95_8_3;
+
+#ifdef COMMENT
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
+extern struct keytab tcstab[];
+extern int ntcs;
+#endif /* COMMENT */
+extern int maxow, maxow_usr; owwait; /* Overlapped I/O variables */
+#endif /* NT */
+#endif /* OS2 */
+
+
+/* The following routines broken out of doprm() to give compilers a break. */
+
+/* S E T O N -- Parse on/off (default on), set parameter to result */
+
+int
+seton(prm) int *prm; {
+ int x, y;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ *prm = y;
+ return(1);
+}
+
+/* S E T O N A U T O -- Parse on/off/auto (default auto) & set result */
+
+struct keytab onoffaut[] = {
+ { "auto", SET_AUTO, 0 }, /* 2 */
+ { "off", SET_OFF, 0 }, /* 0 */
+ { "on", SET_ON, 0 } /* 1 */
+};
+
+int
+setonaut(prm) int *prm; {
+ int x, y;
+ if ((y = cmkey(onoffaut,3,"","auto",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ *prm = y;
+ return(1);
+}
+
+/* S E T N U M -- Set parameter to result of cmnum() parse. */
+/*
+ Call with pointer to integer variable to be set,
+ x = number from cnum parse, y = return code from cmnum,
+ max = maximum value to accept, -1 if no maximum.
+ Returns -9 on failure, after printing a message, or 1 on success.
+*/
+int
+setnum(prm,x,y,max) int x, y, *prm, max; {
+ debug(F101,"setnum","",y);
+ if (y == -3) {
+ printf("\n?Value required\n");
+ return(-9);
+ }
+ if (y == -2) {
+ printf("%s?Not a number: %s\n",cmflgs == 1 ? "" : "\n", atxbuf);
+ return(-9);
+ }
+ if (y < 0) return(y);
+ if (max > -1 && x > max) {
+ printf("?Sorry, %d is the maximum\n",max);
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ *prm = x;
+ return(1);
+}
+
+/* S E T C C -- Set parameter var to an ASCII control character value. */
+/*
+ Parses a number, or a literal control character, or a caret (^) followed
+ by an ASCII character whose value is 63-95 or 97-122, then gets confirmation,
+ then sets the parameter to the code value of the character given. If there
+ are any parse errors, they are returned, otherwise on success 1 is returned.
+*/
+int
+setcc(dflt,var) char *dflt; int *var; {
+ int x, y;
+ unsigned int c;
+ char *hlpmsg = "Control character,\n\
+ numeric ASCII value,\n\
+ or in ^X notation,\n\
+ or preceded by a backslash and entered literally";
+
+ /* This is a hack to turn off complaints from expression evaluator. */
+ x_ifnum = 1;
+ y = cmnum(hlpmsg, dflt, 10, &x, xxstring); /* Parse a number */
+ x_ifnum = 0; /* Allow complaints again */
+ if (y < 0) { /* Parse failed */
+ if (y != -2) /* Reparse needed or somesuch */
+ return(y); /* Pass failure back up the chain */
+ }
+ /* Real control character or literal 8-bit character... */
+
+ for (c = strlen(atmbuf) - 1; c > 0; c--) /* Trim */
+ if (atmbuf[c] == SP) atmbuf[c] = NUL;
+
+ if (y < 0) { /* It was not a number */
+ if (((c = atmbuf[0])) && !atmbuf[1]) { /* Literal character? */
+ c &= 0xff;
+ if (((c > 31) && (c < 127)) || (c > 255)) {
+ printf("\n?%d: Out of range - must be 0-31 or 127-255\n",c);
+ return(-9);
+ } else {
+ if ((y = cmcfm()) < 0) /* Confirm */
+ return(y);
+ *var = c; /* Set the variable */
+ return(1);
+ }
+ } else if (atmbuf[0] == '^' && !atmbuf[2]) { /* Or ^X notation? */
+ c = atmbuf[1];
+ if (islower((char) c)) /* Uppercase lowercase letters */
+ c = toupper(c);
+ if (c > 62 && c < 96) { /* Check range */
+ if ((y = cmcfm()) < 0)
+ return(y);
+ *var = ctl(c); /* OK */
+ return(1);
+ } else {
+ printf("?Not a control character - %s\n", atmbuf);
+ return(-9);
+ }
+ } else { /* Something illegal was typed */
+ printf("?Invalid - %s\n", atmbuf);
+ return(-9);
+ }
+ }
+ if (((x > 31) && (x < 127)) || (x > 255)) { /* They typed a number */
+ printf("\n?%d: Out of range - must be 0-31 or 127-255\n",x);
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) /* In range, confirm */
+ return(y);
+ *var = x; /* Set variable */
+ return(1);
+}
+
+#ifndef NOSPL /* The SORT command... */
+
+static struct keytab srtswtab[] = { /* SORT command switches */
+ { "/case", SRT_CAS, CM_ARG },
+ { "/key", SRT_KEY, CM_ARG },
+ { "/numeric", SRT_NUM, 0 },
+ { "/range", SRT_RNG, CM_ARG },
+ { "/reverse", SRT_REV, 0 }
+};
+static int nsrtswtab = sizeof(srtswtab)/sizeof(struct keytab);
+
+extern char **a_ptr[]; /* Array pointers */
+extern int a_dim[]; /* Array dimensions */
+
+int
+dosort() { /* Do the SORT command */
+ char c, *p = NULL, ** ap, ** xp = NULL;
+ struct FDB sw, fl, cm;
+ int hi, lo;
+ int xn = 0, xr = -1, xk = -1, xc = -1, xs = 0;
+ int getval = 0, range[2], confirmed = 0;
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Array name or switch",
+ "", /* default */
+ "", /* addtl string data */
+ nsrtswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ NULL, /* Processing function */
+ srtswtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "Array name", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* Or premature confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ range[0] = -1;
+ range[1] = -1;
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw);
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case SRT_REV:
+ xr = 1;
+ break;
+ case SRT_KEY:
+ if (getval) {
+ if ((y = cmnum("Column for comparison (1-based)",
+ "1",10,&x,xxstring)) < 0)
+ return(y);
+ xk = x - 1;
+ } else
+ xk = 0;
+ break;
+ case SRT_CAS:
+ if (getval) {
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ xc = y;
+ } else
+ xc = 1;
+ break;
+ case SRT_RNG: /* /RANGE */
+ if (getval) {
+ char buf[32];
+ char buf2[16];
+ int i;
+ char * p, * q;
+ if ((y = cmfld("low:high element","1",&s,NULL)) < 0)
+ return(y);
+ s = brstrip(s);
+ ckstrncpy(buf,s,32);
+ p = buf;
+ for (i = 0; *p && i < 2; i++) { /* Get low and high */
+ q = p; /* Start of this piece */
+ while (*p) { /* Find end of this piece */
+ if (*p == ':') {
+ *p = NUL;
+ p++;
+ break;
+ }
+ p++;
+ }
+ y = 15; /* Evaluate this piece */
+ s = buf2;
+ zzstring(q,&s,&y);
+ s = evalx(buf2);
+ if (s) if (*s) ckstrncpy(buf2,s,16);
+ if (!rdigits(buf2)) {
+ printf("?Not numeric: %s\n",buf2);
+ return(-9);
+ }
+ range[i] = atoi(buf2);
+ }
+ }
+ break;
+ case SRT_NUM: /* /NUMERIC */
+ xn = 1;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ switch (cmresult.fcode) {
+ case _CMCFM:
+ confirmed = 1;
+ break;
+ case _CMFLD:
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of name */
+ s = line;
+ break;
+ default:
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ return(-9);
+ }
+ if (confirmed) {
+ printf("?Array name required\n");
+ return(-9);
+ }
+ ckmakmsg(tmpbuf,TMPBUFSIZ,
+ "Second array to sort according to ",s,NULL,NULL);
+ if ((x = cmfld(tmpbuf,"",&p,NULL)) < 0)
+ if (x != -3)
+ return(x);
+ tmpbuf[0] = NUL;
+ ckstrncpy(tmpbuf,p,TMPBUFSIZ);
+ p = tmpbuf;
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+
+ x = arraybounds(s,&lo,&hi); /* Get array index & bounds */
+ if (x < 0) { /* Check */
+ printf("?Bad array name: %s\n",s);
+ return(-9);
+ }
+ if (lo > -1) range[0] = lo; /* Set range */
+ if (hi > -1) range[1] = hi;
+ ap = a_ptr[x]; /* Get pointer to array element list */
+ if (!ap) { /* Check */
+ printf("?Array not declared: %s\n", s);
+ return(-9);
+ }
+ if (range[0] < 0) /* Starting element */
+ range[0] = 1;
+ if (range[1] < 0) /* Final element */
+ range[1] = a_dim[x];
+ if (range[1] > a_dim[x]) {
+ printf("?range %d:%d exceeds array dimension %d\n",
+ range[0],range[1],a_dim[x]
+ );
+ return(-9);
+ }
+ ap += range[0];
+ xs = range[1] - range[0] + 1; /* Number of elements to sort */
+ if (xs < 1) { /* Check */
+ printf("?Bad range: %d:%d\n",range[0],range[1]);
+ return(-9);
+ }
+ if (xk < 0) xk = 0; /* Key position */
+ if (xr < 0) xr = 0; /* Reverse flag */
+ if (xn) /* Numeric flag */
+ xc = 2;
+ else if (xc < 0) /* Not numeric */
+ xc = inpcas[cmdlvl]; /* so alpha case option */
+
+ if (*p) { /* Parallel array given? */
+ y = xarray(p); /* Yes, get its index. */
+ if (y < 0) {
+ printf("?Bad array name: %s\n", p);
+ return(-9);
+ }
+ if (y != x) { /* If the 2 arrays are different */
+ xp = a_ptr[y]; /* Pointer to 2nd array element list */
+ if (!xp) {
+ printf("?Array not declared: %s\n", p);
+ return(-9);
+ }
+ if (a_dim[y] < range[1]) {
+ printf("?Array %s smaller than %s\n", p, s);
+ return(-9);
+ }
+ xp += range[0]; /* Set base to same as 1st array */
+ }
+ }
+ sh_sort(ap,xp,xs,xk,xr,xc); /* Sort the array(s) */
+ return(success = 1); /* Always succeeds */
+}
+#endif /* NOSPL */
+
+static struct keytab purgtab[] = { /* PURGE command switches */
+ { "/after", PU_AFT, CM_ARG },
+ { "/ask", PU_ASK, 0 },
+ { "/before", PU_BEF, CM_ARG },
+ { "/delete", PU_DELE, CM_INV },
+#ifdef UNIXOROSK
+ { "/dotfiles", PU_DOT, 0 },
+#endif /* UNIXOROSK */
+ { "/except", PU_EXC, CM_ARG },
+ { "/heading", PU_HDG, 0 },
+ { "/keep", PU_KEEP, CM_ARG },
+ { "/larger-than", PU_LAR, CM_ARG },
+ { "/list", PU_LIST, 0 },
+ { "/log", PU_LIST, CM_INV },
+ { "/noask", PU_NASK, 0 },
+ { "/nodelete", PU_NODE, CM_INV },
+#ifdef UNIXOROSK
+ { "/nodotfiles", PU_NODOT,0 },
+#endif /* UNIXOROSK */
+ { "/noheading", PU_NOH, 0 },
+ { "/nol", PU_NOLI, CM_INV|CM_ABR },
+ { "/nolist", PU_NOLI, 0 },
+ { "/nolog", PU_NOLI, CM_INV },
+#ifdef CK_TTGWSIZ
+ { "/nopage", PU_NOPA, 0 },
+#endif /* CK_TTGWSIZ */
+ { "/not-after", PU_NAF, CM_ARG },
+ { "/not-before", PU_NBF, CM_ARG },
+ { "/not-since", PU_NAF, CM_INV|CM_ARG },
+#ifdef CK_TTGWSIZ
+ { "/page", PU_PAGE, 0 },
+#endif /* CK_TTGWSIZ */
+ { "/quiet", PU_QUIE, CM_INV },
+#ifdef RECURSIVE
+ { "/recursive", PU_RECU, 0 },
+#endif /* RECURSIVE */
+ { "/since", PU_AFT, CM_ARG|CM_INV },
+ { "/simulate", PU_NODE, 0 },
+ { "/smaller-than", PU_SMA, CM_ARG },
+ { "/verbose", PU_VERB, CM_INV }
+};
+static int npurgtab = sizeof(purgtab)/sizeof(struct keytab);
+
+
+
+
+
+int
+bkupnum(s,i) char * s; int *i; {
+ int k = 0, pos = 0;
+ char * p = NULL, *q;
+ *i = pos;
+ if (!s) s = "";
+ if (!*s)
+ return(-1);
+ if ((k = strlen(s)) < 5)
+ return(-1);
+
+ if (s[k-1] != '~')
+ return(-1);
+ pos = k - 2;
+ q = s + pos;
+ while (q >= s && isdigit(*q)) {
+ p = q--;
+ pos--;
+ }
+ if (!p)
+ return(-1);
+ if (q < s+2)
+ return(-1);
+ if (*q != '~' || *(q-1) != '.')
+ return(-1);
+ pos--;
+ *i = pos;
+ debug(F111,"bkupnum",s+pos,pos);
+ return(atoi(p));
+}
+
+#ifdef CKPURGE
+/* Presently only for UNIX because we need direct access to the file array. */
+/* Not needed for VMS anyway, because we don't make backup files there. */
+
+#define MAXKEEP 32 /* Biggest /KEEP: value */
+
+static int
+ pu_keep = 0, pu_list = 0, pu_dot = 0, pu_ask = 0, pu_hdg = 0;
+
+#ifdef CK_TTGWSIZ
+static int pu_page = -1;
+#else
+static int pu_page = 0;
+#endif /* CK_TTGWSIZ */
+
+#ifndef NOSHOW
+VOID
+showpurgopts() { /* SHOW PURGE command options */
+ int x = 0;
+ extern int optlines;
+ prtopt(&optlines,"PURGE");
+ if (pu_ask > -1) {
+ x++;
+ prtopt(&optlines, pu_ask ? "/ASK" : "/NOASK");
+ }
+#ifdef UNIXOROSK
+ if (pu_dot > -1) {
+ x++;
+ prtopt(&optlines, pu_dot ? "/DOTFILES" : "/NODOTFILES");
+ }
+#endif /* UNIXOROSK */
+ if (pu_keep > -1) {
+ x++;
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"/KEEP:",ckitoa(pu_keep),NULL,NULL);
+ prtopt(&optlines,tmpbuf);
+ }
+ if (pu_list > -1) {
+ x++;
+ prtopt(&optlines, pu_list ? "/LIST" : "/NOLIST");
+ }
+ if (pu_hdg > -1) {
+ x++;
+ prtopt(&optlines, pu_hdg ? "/HEADING" : "/NOHEADING");
+ }
+#ifdef CK_TTGWSIZ
+ if (pu_page > -1) {
+ x++;
+ prtopt(&optlines, pu_page ? "/PAGE" : "/NOPAGE");
+ }
+#endif /* CK_TTGWSIZ */
+ if (!x) prtopt(&optlines,"(no options set)");
+ prtopt(&optlines,"");
+}
+#endif /* NOSHOW */
+
+int
+setpurgopts() { /* Set PURGE command options */
+ int c, z, getval = 0;
+ int
+ x_keep = -1, x_list = -1, x_page = -1,
+ x_hdg = -1, x_ask = -1, x_dot = -1;
+
+ while (1) {
+ if ((y = cmswi(purgtab,npurgtab,"Switch","",xxstring)) < 0) {
+ if (y == -3)
+ break;
+ else
+ return(y);
+ }
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (y) {
+ case PU_KEEP:
+ z = 1;
+ if (c == ':' || c == '=')
+ if ((y = cmnum("How many backup files to keep",
+ "1",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > MAXKEEP) {
+ printf("?Please specify a number between 0 and %d\n",
+ MAXKEEP
+ );
+ return(-9);
+ }
+ x_keep = z;
+ break;
+ case PU_LIST:
+ case PU_VERB:
+ x_list = 1;
+ break;
+ case PU_QUIE:
+ case PU_NOLI:
+ x_list = 0;
+ break;
+#ifdef CK_TTGWSIZ
+ case PU_PAGE:
+ x_page = 1;
+ break;
+ case PU_NOPA:
+ x_page = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+ case PU_HDG:
+ x_hdg = 1;
+ break;
+ case PU_NOH:
+ x_hdg = 0;
+ break;
+ case PU_ASK:
+ x_ask = 1;
+ break;
+ case PU_NASK:
+ x_ask = 0;
+ break;
+#ifdef UNIXOROSK
+ case PU_DOT:
+ x_dot = 1;
+ break;
+ case PU_NODOT:
+ x_dot = 0;
+ break;
+#endif /* UNIXOROSK */
+ default:
+ printf("?This option can not be set\n");
+ return(-9);
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (x_keep > -1) /* Set PURGE defaults. */
+ pu_keep = x_keep;
+ if (x_list > -1)
+ pu_list = x_list;
+#ifdef CK_TTGWSIZ
+ if (x_page > -1)
+ pu_page = x_page;
+#endif /* CK_TTGWSIZ */
+ if (x_hdg > -1)
+ pu_hdg = x_hdg;
+ if (x_ask > -1)
+ pu_ask = x_ask;
+ if (x_dot > -1)
+ pu_dot = x_dot;
+ return(success = 1);
+}
+
+int
+dopurge() { /* Do the PURGE command */
+ extern char ** mtchs;
+ extern int xaskmore, cmd_rows, recursive;
+ int simulate = 0, asking = 0;
+ int listing = 0, paging = -1, lines = 0, deleting = 1, errors = 0;
+ struct FDB sw, sf, cm;
+ int g, i, j, k, m = 0, n, x, y, z, done = 0, count = 0, flags = 0;
+ int tokeep = 0, getval = 0, havename = 0, confirmed = 0;
+ int xx[MAXKEEP+1]; /* Array of numbers to keep */
+ int min = -1;
+ int x_hdg = 0, fs = 0, rc = 0;
+ CK_OFF_T minsize = -1L, maxsize = -1L;
+ char namebuf[CKMAXPATH+4];
+ char basebuf[CKMAXPATH+4];
+ char
+ * pu_aft = NULL,
+ * pu_bef = NULL,
+ * pu_naf = NULL,
+ * pu_nbf = NULL,
+ * pu_exc = NULL;
+ char * pxlist[8]; /* Exception list */
+
+ if (pu_keep > -1) /* Set PURGE defaults. */
+ tokeep = pu_keep;
+ if (pu_list > -1)
+ listing = pu_list;
+#ifdef CK_TTGWSIZ
+ if (pu_page > -1)
+ paging = pu_page;
+#endif /* CK_TTGWSIZ */
+
+ for (i = 0; i <= MAXKEEP; i++) /* Clear this number buffer */
+ xx[i] = 0;
+ for (i = 0; i < 8; i++) /* Initialize these... */
+ pxlist[i] = NULL;
+
+ g_matchdot = matchdot; /* Save these... */
+
+ cmfdbi(&sw, /* 1st FDB - PURGE switches */
+ _CMKEY, /* fcode */
+ "Filename or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ npurgtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ purgtab, /* Keyword table */
+ &sf /* Pointer to next FDB */
+ );
+ cmfdbi(&sf, /* 2nd FDB - filespec to purge */
+ _CMIFI, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* Or premature confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ while (!havename && !confirmed) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) { /* Error */
+ rc = x;
+ goto xpurge;
+ } else if (cmresult.fcode == _CMKEY) {
+ char c;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ rc = -9;
+ goto xpurge;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ rc = -9;
+ goto xpurge;
+ }
+ switch (k = cmresult.nresult) {
+ case PU_KEEP:
+ z = 1;
+ if (c == ':' || c == '=') {
+ if ((y = cmnum("How many backup files to keep",
+ "1",10,&z,xxstring)) < 0) {
+ rc = y;
+ goto xpurge;
+ }
+ }
+ if (z < 0 || z > MAXKEEP) {
+ printf("?Please specify a number between 0 and %d\n",
+ MAXKEEP
+ );
+ rc = -9;
+ goto xpurge;
+ }
+ tokeep = z;
+ break;
+ case PU_LIST:
+ listing = 1;
+ break;
+ case PU_NOLI:
+ listing = 0;
+ break;
+#ifdef CK_TTGWSIZ
+ case PU_PAGE:
+ paging = 1;
+ break;
+ case PU_NOPA:
+ paging = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+ case PU_DELE:
+ deleting = 1;
+ break;
+ case PU_NODE:
+ deleting = 0;
+ simulate = 1;
+ listing = 1;
+ break;
+ case PU_ASK:
+ asking = 1;
+ break;
+ case PU_NASK:
+ asking = 0;
+ break;
+ case PU_AFT:
+ case PU_BEF:
+ case PU_NAF:
+ case PU_NBF:
+ if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Date-time required\n");
+ rc = -9;
+ } else
+ rc = x;
+ goto xpurge;
+ }
+ fs++;
+ switch (k) {
+ case PU_AFT: makestr(&pu_aft,s); break;
+ case PU_BEF: makestr(&pu_bef,s); break;
+ case PU_NAF: makestr(&pu_naf,s); break;
+ case PU_NBF: makestr(&pu_nbf,s); break;
+ }
+ break;
+ case PU_SMA:
+ case PU_LAR:
+ if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0) {
+ rc = x;
+ goto xpurge;
+ }
+ fs++;
+ switch (cmresult.nresult) {
+ case PU_SMA: minsize = y; break;
+ case PU_LAR: maxsize = y; break;
+ }
+ break;
+ case PU_DOT:
+ matchdot = 1;
+ break;
+ case PU_NODOT:
+ matchdot = 0;
+ break;
+ case PU_EXC:
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ rc = -9;
+ } else
+ rc = x;
+ goto xpurge;
+ }
+ fs++;
+ makestr(&pu_exc,s);
+ break;
+ case PU_HDG:
+ x_hdg = 1;
+ break;
+#ifdef RECURSIVE
+ case PU_RECU: /* /RECURSIVE */
+ recursive = 2;
+ break;
+#endif /* RECURSIVE */
+ default:
+ printf("?Not implemented yet - \"%s\"\n",atmbuf);
+ rc = -9;
+ goto xpurge;
+ }
+ } else if (cmresult.fcode == _CMIFI) {
+ havename = 1;
+ } else if (cmresult.fcode == _CMCFM) {
+ confirmed = 1;
+ } else {
+ rc = -2;
+ goto xpurge;
+ }
+ }
+ if (havename) {
+#ifdef CKREGEX
+ ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~[1-9]*~",NULL,NULL);
+#else
+ ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~*~",NULL,NULL);
+#endif /* CKREGEX */
+ } else {
+#ifdef CKREGEX
+ ckstrncpy(line,"*.~[1-9]*~",LINBUFSIZ);
+#else
+ ckstrncpy(line,"*.~*~",LINBUFSIZ);
+#endif /* CKREGEX */
+ }
+ if (!confirmed) {
+ if ((x = cmcfm()) < 0) {
+ rc = x;
+ goto xpurge;
+ }
+ }
+ /* Parse finished - now action */
+
+#ifdef CK_LOGIN
+ if (isguest) {
+ printf("?File deletion by guests not permitted.\n");
+ rc = -9;
+ goto xpurge;
+ }
+#endif /* CK_LOGIN */
+
+#ifdef CK_TTGWSIZ
+ if (paging < 0) /* /[NO]PAGE not given */
+ paging = xaskmore; /* so use prevailing */
+#endif /* CK_TTGWSIZ */
+
+ lines = 0;
+ if (x_hdg > 0) {
+ printf("Purging %s, keeping %d...%s\n",
+ s,
+ tokeep,
+ simulate ? " (SIMULATION)" : "");
+ lines += 2;
+ }
+ flags = ZX_FILONLY;
+ if (recursive) flags |= ZX_RECURSE;
+ n = nzxpand(line,flags); /* Get list of backup files */
+ if (tokeep < 1) { /* Deleting all of them... */
+ for (i = 0; i < n; i++) {
+ if (fs) if (fileselect(mtchs[i],
+ pu_aft,pu_bef,pu_naf,pu_nbf,
+ minsize,maxsize,0,8,pxlist) < 1) {
+ if (listing > 0) {
+ printf(" %s (SKIPPED)\n",mtchs[i]);
+#ifdef CK_TTGWSIZ
+ if (paging)
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ continue;
+ }
+ if (asking) {
+ int x;
+ ckmakmsg(tmpbuf,TMPBUFSIZ," Delete ",mtchs[i],"?",NULL);
+ x = getyesno(tmpbuf,1);
+ switch (x) {
+ case 0: continue;
+ case 1: break;
+ case 2: goto xpurge;
+ }
+ }
+ x = deleting ? zdelet(mtchs[i]) : 0;
+ if (x > -1) {
+ if (listing)
+ printf(" %s (%s)\n", mtchs[i],deleting ? "OK" : "SELECTED");
+ count++;
+ } else {
+ errors++;
+ if (listing)
+ printf(" %s (FAILED)\n", mtchs[i]);
+ }
+#ifdef CK_TTGWSIZ
+ if (listing && paging)
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ goto xpurge;
+ }
+ if (n < tokeep) { /* Not deleting any */
+ count = 0;
+ if (listing)
+ printf(" Matches = %d: Not enough to purge.\n",n);
+ goto xpurge;
+ }
+
+ /* General case - delete some but not others */
+
+ sh_sort(mtchs,NULL,n,0,0,filecase); /* Alphabetize the list (ESSENTIAL) */
+
+ g = 0; /* Start of current group */
+ for (i = 0; i < n; i++) { /* Go thru sorted file list */
+ x = znext(namebuf); /* Get next file */
+ if (x < 1 || !namebuf[0] || i == n - 1) /* No more? */
+ done = 1; /* NOTE: 'done' must be 0 or 1 only */
+ if (fs) if (fileselect(namebuf,
+ pu_aft,pu_bef,pu_naf,pu_nbf,
+ minsize,maxsize,0,8,pxlist) < 1) {
+ if (listing > 0) {
+ printf(" %s (SKIPPED)\n",namebuf);
+ if (++lines > cmd_rows - 3)
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+ continue;
+ }
+ if (x > 0)
+ if ((m = bkupnum(namebuf,&z)) < 0) /* This file's backup number. */
+ continue;
+ for (j = 0; j < tokeep; j++) { /* Insert in list. */
+ if (m > xx[j]) {
+ for (k = tokeep - 1; k > j; k--)
+ xx[k] = xx[k-1];
+ xx[j] = m;
+ break;
+ }
+ }
+ /* New group? */
+ if (done || (i > 0 && ckstrcmp(namebuf,basebuf,z,1))) {
+ if (i + done - g > tokeep) { /* Do we have enough to purge? */
+ min = xx[tokeep-1]; /* Yes, lowest backup number to keep */
+ debug(F111,"dopurge group",basebuf,min);
+ for (j = g; j < i + done; j++) { /* Go through this group */
+ x = bkupnum(mtchs[j],&z); /* Get file backup number */
+ if (x > 0 && x < min) { /* Below minimum? */
+ x = deleting ? zdelet(mtchs[j]) : 0;
+ if (x < 0) errors++;
+ if (listing)
+ printf(" %s (%s)\n",
+ mtchs[j],
+ ((x < 0) ? "ERROR" :
+ (deleting ? "DELETED" : "SELECTED"))
+ );
+ count++;
+ } else if (listing) /* Not below minimum - keep this one */
+ printf(" %s (KEPT)\n",mtchs[j]);
+#ifdef CK_TTGWSIZ
+ if (listing && paging)
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ } else if (listing && paging) { /* Not enough to purge */
+ printf(" %s.~*~ (KEPT)\n",basebuf);
+#ifdef CK_TTGWSIZ
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ for (j = 0; j < tokeep; j++) /* Clear the backup number list */
+ xx[j] = 0;
+ g = i; /* Reset the group pointer */
+ }
+ if (done) /* No more files, done. */
+ break;
+ strncpy(basebuf,namebuf,z); /* Set basename of this file */
+ basebuf[z] = NUL;
+ }
+ xpurge: /* Common exit point */
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot; /* Restore these... */
+ g_matchdot = -1;
+ }
+ if (rc < 0) return(rc); /* Parse error */
+ if (x_hdg)
+ printf("Files purged: %d%s\n",
+ count,
+ deleting ? "" : " (not really)"
+ );
+ return(success = count > 0 ? 1 : (errors > 0) ? 0 : 1);
+}
+#endif /* CKPURGE */
+
+#ifndef NOXFER
+#ifndef NOLOCAL
+int
+doxdis(which) int which; { /* 1 = Kermit, 2 = FTP */
+ extern int nolocal;
+ int x, y = 0, z;
+#ifdef NEWFTP
+ extern int ftp_dis;
+#endif /* NEWFTP */
+
+#ifdef COMMENT
+ char *s;
+#endif /* COMMENT */
+
+ if ((x = cmkey(fdtab,nfdtab,"file transfer display style","",
+ xxstring)) < 0)
+ return(x);
+#ifdef CK_PCT_BAR
+ if ((y = cmkey(fdftab,2,"","thermometer",xxstring)) < 0)
+ return(y);
+#endif /* CK_PCT_BAR */
+ if ((z = cmcfm()) < 0) return(z);
+#ifdef CK_CURSES
+ if (x == XYFD_C) { /* FULLSCREEN */
+#ifdef COMMENT
+#ifndef MYCURSES
+ extern char * trmbuf; /* Real curses */
+ int z;
+#endif /* MYCURSES */
+#endif /* COMMENT */
+
+ if (nolocal) /* Nothing to do in this case */
+ return(success = 1);
+
+#ifdef COMMENT
+#ifndef MYCURSES
+#ifndef VMS
+ s = getenv("TERM");
+ debug(F110,"doxdis TERM",s,0);
+ if (!s) s = "";
+ fxdinit(x);
+ if (*s && trmbuf) { /* Don't call tgetent */
+ z = tgetent(trmbuf,s); /* if trmbuf not allocated */
+ debug(F111,"doxdis tgetent",s,z);
+ } else {
+ z = 0;
+ debug(F110,"doxdis tgetent skipped",s,0);
+ }
+ if (z < 1) {
+ printf("Sorry, terminal type unknown: \"%s\"\n",s);
+ return(success = 0);
+ }
+#endif /* VMS */
+#endif /* MYCURSES */
+#else
+ fxdinit(x);
+#endif /* COMMENT */
+
+#ifdef CK_PCT_BAR
+ thermometer = y;
+#endif /* CK_PCT_BAR */
+
+ line[0] = '\0'; /* (What's this for?) */
+ }
+#endif /* CK_CURSES */
+ if (which == 1) /* It's OK. */
+ fdispla = x;
+#ifdef NEWFTP
+ else if (which == 2)
+ ftp_dis = x;
+#endif /* NEWFTP */
+ return(success = 1);
+}
+#endif /* NOLOCAL */
+#endif /* NOXFER */
+
+int
+setfil(rmsflg) int rmsflg; {
+#ifdef COMMENT
+ extern int en_del;
+#endif /* COMMENT */
+#ifndef NOXFER
+ if (rmsflg) {
+ if ((y = cmkey(rfiltab,nrfilp,"Remote file parameter","",
+ xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Remote file parameter required\n");
+ return(-9);
+ } else return(y);
+ }
+ } else {
+#endif /* NOXFER */
+ if ((y = cmkey(filtab,nfilp,"File parameter","",xxstring)) < 0)
+ return(y);
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+ switch (y) {
+#ifdef COMMENT /* Not needed */
+ case XYFILB: /* Blocksize */
+ if ((y = cmnum("file block size",ckitoa(DBLKSIZ),10,&z,xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S', "311", ckitoa(z), "");
+ return((int) sstate);
+ } else {
+ fblksiz = z;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+
+#ifndef NOXFER
+ case XYFILS: /* Byte size */
+ if ((y = cmnum("file byte size (7 or 8)","8",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 7 && z != 8) {
+ printf("\n?The choices are 7 and 8\n");
+ return(0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ if (z == 7) fmask = 0177;
+ else if (z == 8) fmask = 0377;
+ return(success = 1);
+
+#ifndef NOCSETS
+ case XYFILC: { /* Character set */
+ char * csetname = NULL;
+ extern int
+ r_cset, s_cset, afcset[]; /* SEND CHARACTER-SET AUTO or MANUAL */
+
+ struct FDB kw, fl;
+ cmfdbi(&kw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ rmsflg ? "server character-set name" : "", /* help */
+ "", /* default */
+ "", /* addtl string data */
+ nfilc, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ fcstab, /* Keyword table */
+ rmsflg ? &fl : NULL /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ if ((x = cmfdb(&kw)) < 0)
+ return(x);
+ if (cmresult.fcode == _CMKEY) {
+ x = cmresult.nresult;
+ csetname = fcsinfo[x].keyword;
+ } else {
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ csetname = line;
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ if (rmsflg) {
+ sstate = setgen('S', "320", csetname, "");
+ return((int) sstate);
+ }
+ fcharset = x;
+ if (s_cset == XMODE_A) /* If SEND CHARACTER-SET is AUTO */
+ if (x > -1 && x <= MAXFCSETS)
+ if (afcset[x] > -1 && afcset[x] <= MAXTCSETS)
+ tcharset = afcset[x]; /* Pick corresponding xfer charset */
+ setxlatype(tcharset,fcharset); /* Translation type */
+ /* If I say SET FILE CHARACTER-SET blah, I want to be blah! */
+ r_cset = XMODE_M; /* Don't switch incoming set! */
+ x = fcsinfo[fcharset].size; /* Also set default x-bit charset */
+ if (x == 128) /* 7-bit... */
+ dcset7 = fcharset;
+ else if (x == 256) /* 8-bit... */
+ dcset8 = fcharset;
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+#ifndef NOLOCAL
+ case XYFILD: /* Display */
+ return(doxdis(1)); /* 1 == kermit */
+#endif /* NOLOCAL */
+#endif /* NOXFER */
+
+ case XYFILA: /* End-of-line */
+#ifdef NLCHAR
+ s = "";
+ if (NLCHAR == 015)
+ s = "cr";
+ else if (NLCHAR == 012)
+ s = "lf";
+ if ((x = cmkey(eoltab, neoltab,
+ "local text-file line terminator",s,xxstring)) < 0)
+ return(x);
+#else
+ if ((x = cmkey(eoltab, neoltab,
+ "local text-file line terminator","crlf",xxstring)) < 0)
+ return(x);
+#endif /* NLCHAR */
+ if ((z = cmcfm()) < 0) return(z);
+ feol = (CHAR) x;
+ return(success = 1);
+
+#ifndef NOXFER
+ case XYFILN: /* Names */
+ if ((x = cmkey(fntab,nfntab,"how to handle filenames","converted",
+ xxstring)) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0) return(z);
+ if (rmsflg) {
+ sstate = setgen('S', "301", ckitoa(1 - x), "");
+ return((int) sstate);
+ } else {
+ ptab[protocol].fncn = x; /* Set structure */
+ fncnv = x; /* Set variable */
+ f_save = x; /* And set "permanent" variable */
+ return(success = 1);
+ }
+
+ case XYFILR: /* Record length */
+ if ((y = cmnum("file record length",
+ ckitoa(DLRECL),10,&z,xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S', "312", ckitoa(z), "");
+ return((int) sstate);
+ } else {
+ frecl = z;
+ return(success = 1);
+ }
+
+#ifdef COMMENT
+ case XYFILO: /* Organization */
+ if ((x = cmkey(forgtab,nforg,"file organization","sequential",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "314", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+ forg = x;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT /* Not needed */
+ case XYFILF: /* Format */
+ if ((x = cmkey(frectab,nfrec,"file record format","stream",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "313", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+ frecfm = x;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+ case XYFILP: /* Printer carriage control */
+ if ((x = cmkey(fcctab,nfcc,"file carriage control","newline",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "315", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+ fcctrl = x;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+#endif /* NOXFER */
+
+ case XYFILT: /* Type */
+ if ((x = cmkey(rmsflg ? rfttab : fttab,
+ rmsflg ? nrfttyp : nfttyp,
+ "type of file transfer","text",xxstring)) < 0)
+ return(x);
+
+#ifdef VMS
+ /* Allow VMS users to choose record format for binary files */
+ if ((x == XYFT_B) && (rmsflg == 0)) {
+ if ((x = cmkey(fbtab,nfbtyp,"VMS record format","fixed",
+ xxstring)) < 0)
+ return(x);
+ }
+#endif /* VMS */
+ if ((y = cmcfm()) < 0) return(y);
+ binary = x;
+ b_save = x;
+#ifdef MAC
+ (void) mac_setfildflg(binary);
+#endif /* MAC */
+#ifndef NOXFER
+ if (rmsflg) {
+ /* Allow for LABELED in VMS & OS/2 */
+ sstate = setgen('S', "300", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+#endif /* NOXFER */
+ return(success = 1);
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+
+#ifndef NOXFER
+ case XYFILX: /* Collision Action */
+ if ((x = cmkey(colxtab,ncolx,"Filename collision action","backup",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef CK_LOGIN
+ if (isguest) {
+ /* Don't let guests change existing files */
+ printf("?This command not valid for guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+#ifdef COMMENT
+ /* Not appropriate - DISABLE DELETE only refers to server */
+ if ((x == XYFX_X || x == XYFX_B || x == XYFX_U || x == XYFX_A) &&
+ (!ENABLED(en_del))) {
+ printf("?Sorry, file deletion is disabled.\n");
+ return(-9);
+ }
+#endif /* COMMENT */
+ fncact = x;
+ ptab[protocol].fnca = x;
+ if (rmsflg) {
+ sstate = setgen('S', "302", ckitoa(fncact), "");
+ return((int) sstate);
+ } else {
+ if (fncact == XYFX_R) ckwarn = 1; /* FILE WARNING implications */
+ if (fncact == XYFX_X) ckwarn = 0; /* ... */
+ return(success = 1);
+ }
+
+ case XYFILW: /* Warning/Write-Protect */
+ if ((x = seton(&ckwarn)) < 0) return(x);
+ if (ckwarn)
+ fncact = XYFX_R;
+ else
+ fncact = XYFX_X;
+ return(success = 1);
+
+#ifdef CK_LABELED
+ case XYFILL: /* LABELED FILE parameters */
+ if ((x = cmkey(lbltab,nlblp,"Labeled file feature","",
+ xxstring)) < 0)
+ return(x);
+ if ((success = seton(&y)) < 0)
+ return(success);
+ if (y) /* Set or reset the selected bit */
+ lf_opts |= x; /* in the options bitmask. */
+ else
+ lf_opts &= ~x;
+ return(success);
+#endif /* CK_LABELED */
+
+ case XYFILI: { /* INCOMPLETE */
+ extern struct keytab ifdatab[];
+ extern int keep;
+ if ((y = cmkey(ifdatab,3,"","auto",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S',
+ "310",
+ y == 0 ? "0" : (y == 1 ? "1" : "2"),
+ ""
+ );
+ return((int) sstate);
+ } else {
+ keep = y;
+ return(success = 1);
+ }
+ }
+
+#ifdef CK_TMPDIR
+ case XYFILG: { /* Download directory */
+ int x;
+ char *s;
+#ifdef ZFNQFP
+ struct zfnfp * fnp;
+#endif /* ZFNQFP */
+#ifdef MAC
+ char temp[34];
+#endif /* MAC */
+
+#ifdef GEMDOS
+ if ((x = cmdir("Name of local directory, or carriage return",
+ "",&s,
+ NULL)) < 0 ) {
+ if (x != -3)
+ return(x);
+ }
+#else
+#ifdef OS2
+ if ((x = cmdir("Name of PC disk and/or directory,\n\
+ or press the Enter key to use current directory",
+ "",&s,xxstring)) < 0 ) {
+ if (x != -3)
+ return(x);
+ }
+#else
+#ifdef MAC
+ x = ckstrncpy(temp,zhome(),32);
+ if (x > 0) if (temp[x-1] != ':') { temp[x] = ':'; temp[x+1] = NUL; }
+ if ((x = cmtxt("Name of Macintosh volume and/or folder,\n\
+ or press the Return key for the desktop on the boot disk",
+ temp,&s, xxstring)) < 0 )
+ return(x);
+#else
+ if ((x = cmdir("Name of local directory, or carriage return",
+ "", &s, xxstring)) < 0 ) {
+ if (x != -3)
+ return(x);
+ }
+#endif /* MAC */
+#endif /* OS2 */
+#endif /* GEMDOS */
+ debug(F110,"download dir",s,0);
+
+#ifndef MAC
+ if (x == 2) {
+ printf("?Wildcards not allowed in directory name\n");
+ return(-9);
+ }
+#endif /* MAC */
+
+#ifdef ZFNQFP
+ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
+ if (fnp->fpath)
+ if ((int) strlen(fnp->fpath) > 0)
+ s = fnp->fpath;
+ }
+ debug(F110,"download zfnqfp",s,0);
+#endif /* ZFNQFP */
+
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */
+#ifndef MAC
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+#endif /* MAC */
+
+#ifdef CK_LOGIN
+ if (isguest) {
+ /* Don't let guests change existing files */
+ printf("?This command not valid for guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+ x = strlen(s);
+
+ if (x) {
+#ifdef datageneral /* AOS/VS */
+ if (s[x-1] == ':') /* homdir ends in colon, */
+ s[x-1] = NUL; /* and "dir" doesn't like that... */
+#else
+#ifdef OS2ORUNIX /* Unix or K-95... */
+ if ((x < (LINBUFSIZ - 2)) && /* Add trailing dirsep */
+ (s[x-1] != '/')) { /* if none present. */
+ s[x] = '/'; /* Note that Windows path has */
+ s[x+1] = NUL; /* been canonicalized to forward */
+ } /* slashes at this point. */
+#endif /* OS2ORUNIX */
+#endif /* datageneral */
+ makestr(&dldir,s);
+ } else
+ makestr(&dldir,NULL); /* dldir is NULL when not assigned */
+
+ return(success = 1);
+ }
+#endif /* CK_TMPDIR */
+ case XYFILY:
+ return(setdest());
+#endif /* NOXFER */
+
+#ifdef CK_CTRLZ
+ case XYFILV: { /* EOF */
+ extern int eofmethod;
+ if ((x = cmkey(eoftab,3,"end-of-file detection method","",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ eofmethod = x;
+ return(success = 1);
+ }
+#endif /* CK_CTRLZ */
+
+#ifndef NOXFER
+#ifdef UNIX
+ case XYFILH: { /* OUTPUT */
+ extern int zofbuffer, zobufsize, zofblock;
+#ifdef DYNAMIC
+ extern char * zoutbuffer;
+#endif /* DYNAMIC */
+
+ if ((x = cmkey(zoftab,nzoftab,"output file writing method","",
+ xxstring)) < 0)
+ return(x);
+ if (x == ZOF_BUF || x == ZOF_NBUF) {
+ if ((y = cmnum("output buffer size","32768",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 1) {
+ printf("?Bad size - %d\n", z);
+ return(-9);
+ }
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ switch (x) {
+ case ZOF_BUF:
+ case ZOF_NBUF:
+ zofbuffer = (x == ZOF_BUF);
+ zobufsize = z;
+ break;
+ case ZOF_BLK:
+ case ZOF_NBLK:
+ zofblock = (x == ZOF_BLK);
+ break;
+ }
+#ifdef DYNAMIC
+ if (zoutbuffer) free(zoutbuffer);
+ if (!(zoutbuffer = (char *)malloc(z))) {
+ printf("MEMORY ALLOCATION ERROR - FATAL\n");
+ doexit(BAD_EXIT,-1);
+ } else
+ zobufsize = z;
+#else
+ if (z <= OBUFSIZE) {
+ zobufsize = z;
+ } else {
+ printf("?Sorry, %d is too big - %d is the maximum\n",z,OBUFSIZE);
+ return(-9);
+ }
+#endif /* DYNAMIC */
+ return(success = 1);
+ }
+#endif /* UNIX */
+
+#ifdef PATTERNS
+ case XYFIBP: /* BINARY-PATTERN */
+ case XYFITP: { /* TEXT-PATTERN */
+ char * tmp[FTPATTERNS];
+ int i, n = 0;
+ while (n < FTPATTERNS) {
+ tmp[n] = NULL;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0)
+ break;
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+ makestr(&(tmp[n++]),s);
+ }
+ if (x == -3) x = cmcfm();
+ for (i = 0; i <= n; i++) {
+ if (x > -1) {
+ if (y == XYFIBP)
+ makestr(&(binpatterns[i]),tmp[i]);
+ else
+ makestr(&(txtpatterns[i]),tmp[i]);
+ }
+ free(tmp[i]);
+ }
+ if (y == XYFIBP) /* Null-terminate the list */
+ makestr(&(binpatterns[i]),NULL);
+ else
+ makestr(&(txtpatterns[i]),NULL);
+ return(x);
+ }
+
+ case XYFIPA: /* PATTERNS */
+ if ((x = setonaut(&patterns)) < 0)
+ return(x);
+ return(success = 1);
+#endif /* PATTERNS */
+#endif /* NOXFER */
+
+#ifdef UNICODE
+ case XYFILU: { /* UCS */
+ extern int ucsorder, ucsbom, byteorder;
+ if ((x = cmkey(ucstab,nucstab,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case UCS_BYT:
+ if ((y = cmkey(botab,nbotab,
+ "Byte order",
+ byteorder ? "little-endian" : "big-endian",
+ xxstring
+ )
+ ) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ ucsorder = y;
+ return(success = 1);
+ case UCS_BOM:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ ucsbom = y;
+ return(success = 1);
+ default:
+ return(-2);
+ }
+ }
+#endif /* UNICODE */
+
+#ifndef datageneral
+ case XYF_INSP: { /* SCAN (INSPECTION) */
+ extern int filepeek, nscanfile;
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(x);
+ if (y) {
+ if ((y = cmnum("How much to scan",ckitoa(SCANFILEBUF),
+ 10,&z,xxstring)) < 0)
+ return(y);
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+#ifdef VMS
+ filepeek = 0;
+ nscanfile = 0;
+ return(success = 0);
+#else
+ filepeek = x;
+ nscanfile = z;
+ return(success = 1);
+#endif /* VMS */
+ }
+#endif /* datageneral */
+
+ case XYF_DFLT:
+ y = 0;
+#ifndef NOCSETS
+ if ((y = cmkey(fdfltab,nfdflt,"","",xxstring)) < 0)
+ return(y);
+ if (y == 7 || y == 8) {
+ if (y == 7)
+ s = fcsinfo[dcset7].keyword;
+ else
+ s = fcsinfo[dcset8].keyword;
+ if ((x = cmkey(fcstab,nfilc,"character-set",s,xxstring)) < 0)
+ return(x);
+ }
+ ckstrncpy(line,fcsinfo[x].keyword,LINBUFSIZ);
+ s = line;
+#endif /* NOCSETS */
+ if ((z = cmcfm()) < 0)
+ return(z);
+ switch (y) {
+#ifndef NOCSETS
+ case 7:
+ if (fcsinfo[x].size != 128) {
+ printf("%s - Not a 7-bit set\n",s);
+ return(-9);
+ }
+ dcset7 = x;
+ break;
+ case 8:
+ if (fcsinfo[x].size != 256) {
+ printf("%s - Not an 8-bit set\n",s);
+ return(-9);
+ }
+ dcset8 = x;
+ break;
+#endif /* NOCSETS */
+ default:
+ return(-2);
+ }
+ return(success = 1);
+
+#ifndef NOXFER
+ case 9997: /* FASTLOOKUPS */
+ return(success = seton(&stathack));
+#endif /* NOXFER */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+ case XYF_LSIZ: { /* LISTSIZE */
+ int zz;
+ y = cmnum("Maximum number of filenames","",10,&x,xxstring);
+ if ((x = setnum(&zz,x,y,-1)) < 0)
+ return(x);
+ if (zsetfil(zz,3) < 0) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ return(success = 1);
+ }
+ case XYF_SSPA: { /* STRINGSPACE */
+ int zz;
+ y = cmnum("Number of characters for filename list",
+ "",10,&x,xxstring);
+ if ((x = setnum(&zz,x,y,-1)) < 0)
+ return(x);
+ if (zsetfil(zz,1) < 0) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ return(success = 1);
+ }
+
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+ default:
+ printf("?unexpected file parameter\n");
+ return(-2);
+ }
+}
+
+#ifdef UNIX
+#ifndef NOPUTENV
+#ifdef BIGBUFOK
+#define NPUTENVS 4096
+#else
+#define NPUTENVS 128
+#endif /* BIGBUFOK */
+/* environment variables must be static, not automatic */
+
+static char * putenvs[NPUTENVS]; /* Array of environment var strings */
+static int nputenvs = -1; /* Pointer into array */
+/*
+ If anyone ever notices the limitation on the number of PUTENVs, the list
+ can be made dynamic, we can recycle entries with the same name, etc.
+*/
+int
+doputenv(s1, s2) char * s1; char * s2; {
+ char * s, * t = tmpbuf; /* Create or alter environment var */
+
+ if (nputenvs == -1) { /* Table not used yet */
+ int i; /* Initialize the pointers */
+ for (i = 0; i < NPUTENVS; i++)
+ putenvs[i] = NULL;
+ nputenvs = 0;
+ }
+ if (!s1) return(1); /* Nothing to do */
+ if (!*s1) return(1); /* ditto */
+
+ if (ckindex("=",s1,0,0,0)) { /* Does the name contain an '='? */
+ printf( /* putenv() does not allow this. */
+ /* This also catches the 'putenv name=value' case */
+ "?PUTENV - Equal sign in variable name - 'help putenv' for info.\n");
+ return(-9);
+ }
+ nputenvs++; /* Point to next free string */
+
+ debug(F111,"doputenv s1",s1,nputenvs);
+ debug(F111,"doputenv s2",s2,nputenvs);
+
+ if (nputenvs > NPUTENVS - 1) { /* Notice the end */
+ printf("?PUTENV - static buffer space exhausted\n");
+ return(-9);
+ }
+ /* Quotes are not needed but we allow them for familiarity */
+ /* but then we strip them, so syntax is same as for Unix shell */
+
+ if (s2) {
+ s2 = brstrip(s2);
+ } else {
+ s2 = (char *)"";
+ }
+ ckmakmsg(t,TMPBUFSIZ,s1,"=",s2,NULL);
+ debug(F111,"doputenv",t,nputenvs);
+ (VOID) makestr(&(putenvs[nputenvs]),t); /* Make a safe permananent copy */
+ if (!putenvs[nputenvs]) {
+ printf("?PUTENV - memory allocation failure\n");
+ return(-9);
+ }
+ if (putenv(putenvs[nputenvs])) {
+ printf("?PUTENV - %s\n",ck_errstr());
+ return(-9);
+ } else return(success = 1);
+}
+#endif /* NOPUTENV */
+#endif /* UNIX */
+
+int
+settrmtyp() {
+#ifdef OS2
+#ifdef TNCODE
+ extern int ttnum; /* Last Telnet Terminal Type sent */
+ extern int ttnumend; /* Has end of list been found */
+#endif /* TNCODE */
+ if ((x = cmkey(ttyptab,nttyp,"","vt220",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ settermtype(x,1);
+#ifdef TNCODE
+ /* So we send the correct terminal name to the host if it asks for it */
+ ttnum = -1; /* Last Telnet Terminal Type sent */
+ ttnumend = 0; /* end of list not found */
+#endif /* TNCODE */
+ return(success = 1);
+#else /* Not OS2 */
+#ifdef UNIX
+ extern int fxd_inited;
+ x = cmtxt("Terminal type name, case sensitive","",&s,NULL);
+#ifdef NOPUTENV
+ success = 1;
+#else
+ success = doputenv("TERM",s); /* Set the TERM variable */
+#ifdef CK_CURSES
+ fxd_inited = 0; /* Force reinitialization of curses database */
+ (void)doxdis(0); /* Re-initialize file transfer display */
+ concb((char)escape); /* Fix command terminal */
+#endif /* CK_CURSES */
+#endif /* NOPUTENV */
+ return(success);
+#else
+ printf(
+"\n Sorry, this version of C-Kermit does not support the SET TERMINAL TYPE\n");
+ printf(
+" command. Type \"help set terminal\" for further information.\n");
+ return(success = 0);
+#endif /* UNIX */
+#endif /* OS2 */
+}
+
+#ifndef NOLOCAL
+#ifdef OS2
+/* MS-DOS KERMIT compatibility modes */
+int
+setmsk() {
+ if ((y = cmkey(msktab,nmsk,"MS-DOS Kermit compatibility mode",
+ "keycodes",xxstring)) < 0) return(y);
+
+ switch ( y ) {
+#ifdef COMMENT
+ case MSK_COLOR:
+ return(seton(&mskcolors));
+#endif /* COMMENT */
+ case MSK_KEYS:
+ return(seton(&mskkeys));
+ case MSK_REN:
+ return(seton(&mskrename));
+ default: /* Shouldn't get here. */
+ return(-2);
+ }
+}
+#endif /* OS2 */
+
+#ifdef CKTIDLE
+static char iactbuf[132];
+
+char *
+getiact() {
+ switch (tt_idleact) {
+ case IDLE_RET: return("return");
+ case IDLE_EXIT: return("exit");
+ case IDLE_HANG: return("hangup");
+#ifdef TNCODE
+ case IDLE_TNOP: return("Telnet NOP");
+ case IDLE_TAYT: return("Telnet AYT");
+#endif /* TNCODE */
+
+ case IDLE_OUT: {
+ int c, k, n;
+ char * p, * q, * t;
+ k = ckstrncpy(iactbuf,"output ",132);
+ n = k;
+ q = &iactbuf[k];
+ p = tt_idlestr;
+ if (!p) p = "";
+ if (!*p) return("output NUL");
+ while ((c = *p++) && n < 131) {
+ c &= 0xff;
+ if (c == '\\') {
+ if (n > 130) break;
+ *q++ = '\\';
+ *q++ = '\\';
+ *q = NUL;
+ n += 2;
+ } else if ((c > 32 && c < 127) || c > 159) {
+ *q++ = c;
+ *q = NUL;
+ n++;
+ } else {
+ if (n > (131 - 6))
+ break;
+ sprintf(q,"\\{%d}",c);
+ k = strlen(q);
+ q += k;
+ n += k;
+ *q = NUL;
+ }
+ }
+ *q = NUL;
+#ifdef OS2
+ k = tt_cols[VTERM];
+#else
+ k = tt_cols;
+#endif /* OS2 */
+ if (n > k - 52) {
+ n = k - 52;
+ iactbuf[n-2] = '.';
+ iactbuf[n-1] = '.';
+ iactbuf[n] = NUL;
+ }
+ return(iactbuf);
+ }
+ default: return("unknown");
+ }
+}
+#endif /* CKTIDLE */
+
+#ifndef NOCSETS
+VOID
+setlclcharset(x) int x; {
+ int i;
+ tcsl = y; /* Local character set */
+#ifdef OS2
+ for (i = 0; i < 4; i++) {
+ G[i].init = TRUE;
+ x = G[i].designation;
+ G[i].c1 = (x != tcsl) && cs_is_std(x);
+ x = G[i].def_designation;
+ G[i].def_c1 = (x != tcsl) && cs_is_std(x);
+ }
+#endif /* OS2 */
+}
+
+VOID
+setremcharset(x, z) int x, z; {
+ int i;
+
+#ifdef KUI
+ KuiSetProperty( KUI_TERM_REMCHARSET, (long) x, (long) z ) ;
+#endif /* KUI */
+#ifdef UNICODE
+ if (x == TX_TRANSP)
+#else /* UNICODE */
+ if (x == FC_TRANSP)
+#endif /* UNICODE */
+ { /* TRANSPARENT? */
+#ifndef OS2
+ tcsr = tcsl; /* Make both sets the same */
+#else /* OS2 */
+#ifdef CKOUNI
+ tt_utf8 = 0; /* Turn off UTF8 flag */
+ tcsr = tcsl = dec_kbd = TX_TRANSP; /* No translation */
+ tcs_transp = 1;
+
+ if (!cs_is_nrc(tcsl)) {
+ G[0].def_designation = G[0].designation = TX_ASCII;
+ G[0].init = TRUE;
+ G[0].def_c1 = G[0].c1 = FALSE;
+ G[0].size = cs94;
+ G[0].national = FALSE;
+ }
+ for (i = cs_is_nrc(tcsl) ? 0 : 1; i < 4; i++) {
+ G[i].def_designation = G[i].designation = tcsl;
+ G[i].init = TRUE;
+ G[i].def_c1 = G[i].c1 = FALSE;
+ switch (cs_size(G[i].designation)) { /* 94, 96, or 128 */
+ case 128:
+ case 96:
+ G[i].size = G[i].def_size = cs96;
+ break;
+ case 94:
+ G[i].size = G[i].def_size = cs94;
+ break;
+ default:
+ G[i].size = G[i].def_size = csmb;
+ break;
+ }
+ G[i].national = cs_is_nrc(x);
+ }
+#else /* CKOUNI */
+ tcsr = tcsl; /* Make both sets the same */
+ for (i = 0; i < 4; i++) {
+ G[i].def_designation = G[i].designation = FC_TRANSP;
+ G[i].init = FALSE;
+ G[i].size = G[i].def_size = cs96;
+ G[i].c1 = G[i].def_c1 = FALSE;
+ G[i].rtoi = NULL;
+ G[i].itol = NULL;
+ G[i].ltoi = NULL;
+ G[i].itor = NULL;
+ G[i].national = FALSE;
+ }
+#endif /* CKOUNI */
+#endif /* OS2 */
+ return;
+ }
+#ifdef OS2
+#ifdef CKOUNI
+ else if (x == TX_UTF8) {
+ tcs_transp = 0;
+ tt_utf8 = 1; /* Turn it on if we are UTF8 */
+ return;
+ }
+#endif /* CKOUNI */
+ else {
+ tcs_transp = 0;
+ tcsr = x; /* Remote character set */
+#ifdef CKOUNI
+ tt_utf8 = 0; /* Turn off UTF8 flag */
+#endif /* CKOUNI */
+
+ if (z == TT_GR_ALL) {
+ int i;
+#ifdef UNICODE
+ dec_kbd = x;
+#endif /* UNICODE */
+ for (i = 0; i < 4; i++) {
+ G[i].init = TRUE;
+ if ( i == 0 && !cs_is_nrc(x) ) {
+ G[0].designation = G[0].def_designation = FC_USASCII;
+ G[0].size = G[0].def_size = cs94;
+ G[0].national = 1;
+ } else {
+ G[i].def_designation = G[i].designation = x;
+ switch (cs_size(x)) { /* 94, 96, or 128 */
+ case 128:
+ case 96:
+ G[i].size = G[i].def_size = cs96;
+ break;
+ case 94:
+ G[i].size = G[i].def_size = cs94;
+ break;
+ default:
+ G[i].size = G[i].def_size = csmb;
+ break;
+ }
+ G[i].national = cs_is_nrc(x);
+ }
+ G[i].c1 = G[i].def_c1 = x != tcsl && cs_is_std(x);
+ }
+#ifdef UNICODE
+ } else if (z == TT_GR_KBD) { /* Keyboard only */
+ dec_kbd = x;
+#endif /* UNICODE */
+ } else { /* Specific Gn */
+ G[z].def_designation = G[z].designation = x;
+ G[z].init = TRUE;
+ switch (cs_size(x)) { /* 94, 96, or 128 */
+ case 128:
+ case 96:
+ G[z].size = G[z].def_size = cs96;
+ break;
+ case 94:
+ G[z].size = G[z].def_size = cs94;
+ break;
+ default:
+ G[z].size = G[z].def_size = csmb;
+ break;
+ }
+ G[z].c1 = G[z].def_c1 = x != tcsl && cs_is_std(x);
+ G[z].national = cs_is_nrc(x);
+ }
+ }
+#else /* not OS2 */
+ tcsr = x; /* Remote character set */
+#endif /* OS2 */
+}
+#endif /* NOCSETS */
+
+VOID
+setcmask(x) int x; {
+ if (x == 7) {
+ cmask = 0177;
+ } else if (x == 8) {
+ cmask = 0377;
+ parity = 0;
+ }
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_CMASK,x,0);
+#endif /* KUI */
+}
+
+#ifdef CK_AUTODL
+VOID
+setautodl(x,y) int x,y; {
+ autodl = x;
+ adl_ask = y;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_AUTODOWNLOAD,x?(y?2:1):0,0);
+#endif /* KUI */
+}
+#endif /* CK_AUTODL */
+
+#ifdef OS2
+VOID
+seturlhl(int x) {
+ tt_url_hilite = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_URL_HIGHLIGHT,x,0);
+#endif /* KUI */
+}
+
+VOID
+setaprint(int x) {
+ extern int aprint;
+ aprint = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_PRINTERCOPY,x,0);
+#endif /* KUI */
+}
+#endif /* OS2 */
+
+int
+settrm() {
+ int i = 0;
+#ifdef OS2
+ extern int colorreset, user_erasemode;
+#endif /* OS2 */
+ if ((y = cmkey(trmtab,ntrm,"", "",xxstring)) < 0) return(y);
+#ifdef MAC
+ printf("\n?Sorry, not implemented yet. Please use the Settings menu.\n");
+ return(-9);
+#else
+#ifdef IKSD
+ if (inserver) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ switch (y) {
+ case XYTBYT: /* SET TERMINAL BYTESIZE */
+ if ((y = cmnum("bytesize for terminal connection","8",10,&x,
+ xxstring)) < 0)
+ return(y);
+ if (x != 7 && x != 8) {
+ printf("\n?The choices are 7 and 8\n");
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ setcmask(x);
+#ifdef OS2
+ if (IS97801(tt_type_mode))
+ SNI_bitmode(x);
+#endif /* OS2 */
+ return(success = 1);
+
+ case XYTSO: /* SET TERMINAL LOCKING-SHIFT */
+ return(seton(&sosi));
+
+ case XYTNL: /* SET TERMINAL NEWLINE-MODE */
+ return(seton(&tnlm));
+
+#ifdef OS2
+ case XYTCOL:
+ if ((x = cmkey(ttycoltab,ncolors,"","terminal",xxstring)) < 0)
+ return(x);
+ else if (x == TTCOLRES) {
+ if ((y = cmkey(ttcolmodetab,ncolmode,
+ "","default-color",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ colorreset = y;
+ return(success = 1);
+ } else if (x == TTCOLERA) {
+ if ((y = cmkey(ttcolmodetab,ncolmode,"",
+ "current-color",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ user_erasemode = y;
+ return(success=1);
+ } else { /* No parse error */
+ int fg = 0, bg = 0;
+ fg = cmkey(ttyclrtab, nclrs,
+ (x == TTCOLBOR ?
+ "color for screen border" :
+ "foreground color and then background color"),
+ "lgray", xxstring);
+ if (fg < 0)
+ return(fg);
+ if (x != TTCOLBOR) {
+ if ((bg = cmkey(ttyclrtab,nclrs,
+ "background color","blue",xxstring)) < 0)
+ return(bg);
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch (x) {
+ case TTCOLNOR:
+ colornormal = fg | bg << 4;
+ fgi = fg & 0x08;
+ bgi = bg & 0x08;
+ break;
+ case TTCOLREV:
+ colorreverse = fg | bg << 4;
+ break;
+ case TTCOLITA:
+ coloritalic = fg | bg << 4;
+ break;
+ case TTCOLUND:
+ colorunderline = fg | bg << 4;
+ break;
+ case TTCOLGRP:
+ colorgraphic = fg | bg << 4;
+ break;
+ case TTCOLDEB:
+ colordebug = fg | bg << 4;
+ break;
+ case TTCOLSTA:
+ colorstatus = fg | bg << 4;
+ break;
+ case TTCOLHLP:
+ colorhelp = fg | bg << 4;
+ break;
+ case TTCOLBOR:
+ colorborder = fg;
+ break;
+ case TTCOLSEL:
+ colorselect = fg | bg << 4;
+ break;
+ default:
+ printf("%s - invalid\n",cmdbuf);
+ return(-9);
+ break;
+ }
+ scrninitialized[VTERM] = 0;
+ VscrnInit(VTERM);
+ }
+ return(success = 1);
+
+ case XYTCUR: { /* SET TERMINAL CURSOR */
+ extern int cursorena[];
+ extern int cursoron[] ; /* Cursor state on/off */
+ if ((x = cmkey(ttycurtab,ncursors,"","underline",xxstring)) < 0)
+ return(x);
+ if ((z = cmkey(curontab,ncuron,"","on",xxstring)) < 0)
+ return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_cursor = tt_cursor_usr = x;
+ if ( z == 2 ) {
+ cursorena[VTERM] = tt_cursorena_usr = 1;
+ tt_cursor_blink = 0;
+ } else {
+ cursorena[VTERM] = tt_cursorena_usr = z;/* turn cursor on/off */
+ tt_cursor_blink = 1;
+ }
+ cursoron[VTERM] = FALSE; /* Force newcursor to restore the cursor */
+ return(success = 1);
+ }
+#endif /* OS2 */
+
+ case XYTTYP: /* SET TERMINAL TYPE */
+ return(settrmtyp());
+
+#ifdef OS2
+ case XYTARR: /* SET TERMINAL ARROW-KEYS */
+ if ((x = cmkey(akmtab,2,"","",xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_arrow = x; /* TTK_NORM / TTK_APPL; see ckuusr.h */
+ return(success = 1);
+
+ case XYTKPD: /* SET TERMINAL KEYPAD-MODE */
+ if ((x = cmkey(kpmtab,2,"","",xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_keypad = x; /* TTK_NORM / TTK_APPL; see ckuusr.h */
+ return(success = 1);
+
+ case XYTUNX: { /* SET TERM UNIX-MODE (DG) */
+ extern int dgunix,dgunix_usr;
+ x = seton(&dgunix);
+ dgunix_usr = dgunix;
+ return(x);
+ }
+ case XYTKBMOD: { /* SET TERM KEYBOARD MODE */
+ extern int tt_kb_mode;
+ if ((x = cmkey(kbmodtab,
+ nkbmodtab,
+ "normal",
+ "special keyboard mode for terminal emulation",
+ xxstring)
+ ) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_kb_mode = x;
+ return(success = 1);
+ }
+
+ case XYTWRP: /* SET TERMINAL WRAP */
+ return(seton(&tt_wrap));
+
+ case XYSCRS:
+ if ((y = cmnum("CONNECT scrollback buffer size, lines","2000",10,&x,
+ xxstring)) < 0)
+ return(y);
+ /* The max number of lines is the RAM */
+ /* we can actually dedicate to a */
+ /* scrollback buffer given the maximum */
+ /* process memory space of 512MB */
+ if (x < 256 || x > 2000000L) {
+ printf("\n?The size must be between 256 and 2,000,000.\n");
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ tt_scrsize[VTERM] = x;
+ VscrnInit(VTERM);
+ return(success = 1);
+#endif /* OS2 */
+
+#ifndef NOCSETS
+ case XYTCS: { /* SET TERMINAL CHARACTER-SET */
+ int eol;
+ /* set terminal character-set <remote> <local> */
+ if ((x = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "remote terminal character-set","",xxstring)) < 0)
+ return(x);
+
+#ifdef UNICODE
+ if (x == TX_TRANSP
+#ifdef CKOUNI
+ || x == TX_UTF8
+#endif /* CKOUNI */
+ ) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+#ifdef OS2
+ if ( isunicode() && x == TX_TRANSP ) {
+ /* If we are in unicode display mode then transparent
+ * only affects the output direction. We need to know
+ * the actual remote character set in order to perform
+ * the tcsr -> ucs2 translation for display.
+ */
+ x = y = tcsl;
+ } else
+#endif /* OS2 */
+ y = x;
+ }
+#else /* UNICODE */
+ if (x == FC_TRANSP) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+ y = x;
+ }
+#endif /* UNICODE */
+
+ /* Not transparent or UTF8, so get local set to translate it into */
+ s = "";
+#ifdef OS2
+ y = os2getcp(); /* Default is current code page */
+ switch (y) {
+ case 437: s = "cp437"; break;
+ case 850: s = "cp850"; break;
+ case 852: s = "cp852"; break;
+ case 857: s = "cp857"; break;
+ case 858: s = "cp858"; break;
+ case 862: s = "cp862"; break;
+ case 866: s = "cp866"; break;
+ case 869: s = "cp869"; break;
+ case 1250: s = "cp1250"; break;
+ case 1251: s = "cp1251"; break;
+ case 1252: s = "cp1252"; break;
+ case 1253: s = "cp1253"; break;
+ case 1254: s = "cp1254"; break;
+ case 1255: s = "cp1255"; break;
+ case 1256: s = "cp1256"; break;
+ case 1257: s = "cp1257"; break;
+ case 1258: s = "cp1258"; break;
+ }
+#ifdef PCFONTS
+/*
+ If the user has loaded a font with SET TERMINAL FONT then we want
+ to change the default code page to the font that was loaded.
+*/
+ if (tt_font != TTF_ROM) {
+ for (y = 0; y < ntermfont; y++ ) {
+ if (term_font[y].kwval == tt_font) {
+ s = term_font[y].kwd;
+ break;
+ }
+ }
+ }
+#endif /* PCFONTS */
+#else /* Not K95... */
+ s = fcsinfo[fcharset].keyword;
+#endif /* OS2 */
+
+ if ((y = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "local character-set",s,xxstring)) < 0)
+ return(y);
+
+#ifdef UNICODE
+ if (y == TX_UTF8) {
+ printf("?UTF8 may not be used as a local character set.\r\n");
+ return(-9);
+ }
+#endif /* UNICODE */
+#ifdef OS2
+ if ((z = cmkey(graphsettab,ngraphset,
+ "DEC VT intermediate graphic set","all",xxstring)) < 0)
+ return(z);
+#endif /* OS2 */
+ if ((eol = cmcfm()) < 0)
+ return(eol); /* Confirm the command */
+
+ /* End of command parsing - actions begin */
+ setlclcharset(y);
+ setremcharset(x,z);
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+#ifndef NOCSETS
+ case XYTLCS: /* SET TERMINAL LOCAL-CHARACTER-SET */
+ /* set terminal character-set <local> */
+ s = getdcset(); /* Get display character-set name */
+ if ((y = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ fcstab,nfilc,
+#endif /* CKOUNI */
+ "local character-set",s,xxstring)) < 0)
+ return(y);
+
+#ifdef UNICODE
+ if (y == TX_UTF8) {
+ printf("?UTF8 may not be used as a local character set.\r\n");
+ return(-9);
+ }
+#endif /* UNICODE */
+ if ((z = cmcfm()) < 0) return(z); /* Confirm the command */
+
+ /* End of command parsing - action begins */
+
+ setlclcharset(y);
+ return(success = 1);
+#endif /* NOCSETS */
+
+#ifndef NOCSETS
+#ifdef UNICODE
+ case XYTUNI: /* SET TERMINAL UNICODE */
+ return(seton(&tt_unicode));
+#endif /* UNICODE */
+
+ case XYTRCS: /* SET TERMINAL REMOTE-CHARACTER-SET */
+ /* set terminal character-set <remote> <Graphic-set> */
+ if ((x = cmkey(
+#ifdef CKOUNI
+ txrtab, ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "remote terminal character-set","",xxstring)) < 0)
+ return(x);
+
+#ifdef UNICODE
+ if (x == TX_TRANSP
+#ifdef CKOUNI
+ || x == TX_UTF8
+#endif /* CKOUNI */
+ ) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+#ifdef OS2
+ if ( isunicode() && x == TX_TRANSP ) {
+ /* If we are in unicode display mode then transparent
+ * only affects the output direction. We need to know
+ * the actual remote character set in order to perform
+ * the tcsr -> ucs2 translation for display.
+ */
+ x = tcsl;
+ }
+#endif /* OS2 */
+ }
+#else /* UNICODE */
+ if (x == FC_TRANSP) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+ }
+#endif /* UNICODE */
+ else {
+#ifdef OS2
+ if ((z = cmkey(graphsettab,ngraphset,
+ "DEC VT intermediate graphic set","all",xxstring)) < 0)
+ return(z);
+#endif /* OS2 */
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+ }
+ /* Command parsing ends here */
+
+ setremcharset(x,z);
+ return(success = 1);
+#endif /* NOCSETS */
+
+ case XYTEC: /* SET TERMINAL ECHO */
+ if ((x = cmkey(rltab,nrlt,"which side echos during CONNECT",
+ "remote", xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef NETCONN
+ oldplex = x;
+#endif /* NETCONN */
+ duplex = x;
+ return(success = 1);
+
+ case XYTESC: /* SET TERM ESC */
+ if ((x = cmkey(nabltab,nnabltab,"","enabled",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_escape = x;
+ return(1);
+
+ case XYTCRD: /* SET TERMINAL CR-DISPLAY */
+ if ((x = cmkey(crdtab,2,"", "normal", xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_crd = x;
+ return(success = 1);
+
+ case XYTLFD: /* SET TERMINAL LF-DISPLAY */
+ if ((x = cmkey(crdtab,2,"", "normal", xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_lfd = x;
+ return(success = 1);
+
+#ifdef OS2
+ case XYTANS: { /* SET TERMINAL ANSWERBACK */
+/*
+ NOTE: We let them enable and disable the answerback sequence, but we
+ do NOT let them change it, and we definitely do not let the host set it.
+ This is a security feature.
+
+ As of 1.1.8 we allow the SET TERM ANSWERBACK MESSAGE <string> to be
+ used just as MS-DOS Kermit does. C0 and C1 controls as well as DEL
+ are not allowed to be used as characters. They are translated to
+ underscore. This may not be set by APC.
+*/
+ if ((x = cmkey(anbktab,nansbk,"", "off", xxstring)) < 0)
+ return(x);
+ if (x < 2) {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tt_answer = x;
+ return(success = 1);
+ } else if ( x == 2 || x == 3) {
+ int len = 0;
+ extern int safeanswerbk;
+ extern char useranswerbk[];
+ if ((y = cmtxt("Answerback extension","",&s,xxstring)) < 0)
+ return(y);
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+ len = strlen(s);
+ if (x == 2) {
+ /* Safe Answerback's don't have C0/C1 chars */
+ for (z = 0; z < len; z++) {
+ if ((s[z] & 0x7F) <= SP || (s[z] & 0x7F) == DEL)
+ useranswerbk[z] = '_';
+ else
+ useranswerbk[z] = s[z];
+ }
+ useranswerbk[z] = '\0';
+ safeanswerbk = 1 ; /* TRUE */
+ } else {
+ ckstrncpy(useranswerbk,s,60); /* (see ckocon.c) */
+ safeanswerbk = 0; /* FALSE */
+ }
+ updanswerbk();
+ return(success = 1);
+ } else
+ return(success = 0);
+ }
+#endif /* OS2 */
+
+#ifdef CK_APC
+ case XYTAPC:
+ if ((y = cmkey(apctab,napctab,
+ "application program command execution","",
+ xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+ apcstatus = y;
+ return(success = 1);
+
+#ifdef CK_AUTODL
+ case XYTAUTODL: /* AUTODOWNLOAD */
+ if ((y = cmkey(adltab,nadltab,"Auto-download options","",
+ xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TAD_ON:
+ case TAD_OFF:
+ if ((x = cmcfm()) < 0)
+ return(x);
+ setautodl(y,0);
+ break;
+ case TAD_ASK:
+ if ((x = cmcfm()) < 0)
+ return(x);
+ setautodl(TAD_ON,1);
+ break;
+ case TAD_ERR:
+ if ((y = cmkey(adlerrtab,nadlerrtab,"","", xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_err = y;
+ break;
+#ifdef OS2
+ case TAD_K:
+ if ((y = cmkey(adlxtab,nadlxtab,"","", xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TAD_X_C0:
+ if ((y = cmkey(adlc0tab,nadlc0tab,"",
+ "processed-by-emulator",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_kc0 = y;
+ break;
+ case TAD_X_DETECT:
+ if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_kmode = y;
+ break;
+ case TAD_X_STR:
+ if ((y = cmtxt("Kermit start string","KERMIT READY TO SEND...",
+ &s,xxstring)) < 0)
+ return(y);
+ free(adl_kstr);
+ adl_kstr = strdup(s);
+ break;
+ }
+ break;
+
+ case TAD_Z:
+ if ((y = cmkey(adlxtab,nadlxtab,"","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TAD_X_C0:
+ if ((y = cmkey(adlc0tab,nadlc0tab,"",
+ "processed-by-emulator",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_zc0 = y;
+ break;
+ case TAD_X_DETECT:
+ if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_zmode = y;
+ break;
+ case TAD_X_STR:
+ if ((y = cmtxt("","rz\\{13}",&s,xxstring)) < 0)
+ return(y);
+ free(adl_zstr);
+ adl_zstr = strdup(s);
+ break;
+ }
+ break;
+#endif /* OS2 */
+ }
+ return(success = 1);
+
+#endif /* CK_AUTODL */
+#endif /* CK_APC */
+
+#ifdef OS2
+ case XYTBEL:
+ return(success = setbell());
+
+ case XYTMBEL: /* MARGIN-BELL */
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if (y) { /* ON */
+ if ((z = cmnum("Column at which to set margin bell",
+ "72",10,&x,xxstring)) < 0)
+ return(z);
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ marginbell = y;
+ marginbellcol = x;
+ return(success = 1);
+#endif /* OS2 */
+
+#ifdef CKTIDLE
+ case XYTIDLE: /* IDLE-SEND */
+ case XYTITMO: /* IDLE-TIMEOUT */
+ if ((z = cmnum("seconds of idle time to wait, or 0 to disable",
+ "0",10,&x,xxstring)) < 0)
+ return(z);
+ if (y == XYTIDLE) {
+ if ((y = cmtxt("string to send, may contain kverbs and variables",
+ "\\v(newline)",&s,xxstring)) < 0)
+ return(y);
+ tt_idlesnd_tmo = x; /* (old) */
+ tt_idlelimit = x; /* (new) */
+ makestr(&tt_idlestr,brstrip(s)); /* (new) */
+ tt_idlesnd_str = tt_idlestr; /* (old) */
+ tt_idleact = IDLE_OUT; /* (new) */
+ } else {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tt_idlelimit = x;
+ }
+#ifdef OS2
+ puterror(VTERM);
+#endif /* OS2 */
+ return(success = 1);
+
+ case XYTIACT: { /* SET TERM IDLE-ACTION */
+ if ((y = cmkey(idlacts,nidlacts,"","",xxstring)) < 0)
+ return(y);
+ if (y == IDLE_OUT) {
+ if ((x = cmtxt("string to send, may contain kverbs and variables"
+ , "",&s,xxstring)) < 0)
+ return(x);
+ makestr(&tt_idlestr,brstrip(s)); /* (new) */
+ tt_idlesnd_str = tt_idlestr; /* (old) */
+ } else {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ }
+ tt_idleact = y;
+ return(success = 1);
+ }
+#endif /* CKTIDLE */
+
+ case XYTDEB: /* TERMINAL DEBUG */
+ y = seton(&x); /* Go parse ON or OFF */
+ if (y > 0) /* Command succeeded? */
+ setdebses(x);
+ return(y);
+
+#ifdef OS2
+ case XYTASCRL: /* SET TERMINAL AUTOSCROLL */
+ y = seton(&autoscroll);
+ return(y);
+
+ case XYTAPAGE: /* SET TERMINAL AUTOPAGE */
+ y = seton(&wy_autopage);
+ return(y);
+
+ case XYTROL: /* SET TERMINAL ROLL */
+ if ((y = cmkey(rolltab,nroll,"scrollback mode","insert",xxstring))<0)
+ return(y);
+ if (y == TTR_KEYS) {
+ if ((x = cmkey(rollkeytab,nrollkey,"","send",xxstring))<0)
+ return(x);
+ if ((z = cmcfm()) < 0) return(z);
+ tt_rkeys[VTERM] = x;
+ } else {
+ if ((x = cmcfm()) < 0) return(x);
+ tt_roll[VTERM] = y;
+ }
+ return(success = 1);
+
+ case XYTCTS: /* SET TERMINAL TRANSMIT-TIMEOUT */
+ y = cmnum("Maximum seconds to allow CTS off during CONNECT",
+ "5",10,&x,xxstring);
+ return(setnum(&tt_ctstmo,x,y,10000));
+
+ case XYTCPG: { /* SET TERMINAL CODE-PAGE */
+ int i;
+ int cp = -1;
+ y = cmnum("PC code page to use during terminal emulation",
+ ckitoa(os2getcp()),10,&x,xxstring);
+ if ((x = setnum(&cp,x,y,11000)) < 0) return(x);
+ if (os2setcp(cp) != 1) {
+#ifdef NT
+ if (isWin95())
+ printf(
+ "Sorry, Windows 95 does not support code page switching\n");
+ else
+#endif /* NT */
+ printf(
+ "Sorry, %d is not a valid code page for this system.\n",cp);
+ return(-9);
+ }
+ /* Force the terminal character-sets conversions to be updated */
+ for ( i = 0; i < 4; i++ )
+ G[i].init = TRUE;
+ return(1);
+ }
+
+ case XYTPAC: /* SET TERMINAL OUTPUT-PACING */
+ y = cmnum(
+ "Pause between sending each character during CONNECT, milliseconds",
+ "-1",10,&x,xxstring);
+ return(setnum(&tt_pacing,x,y,10000));
+
+#ifdef OS2MOUSE
+ case XYTMOU: { /* SET TERMINAL MOUSE */
+ int old_mou = tt_mouse;
+ if ((x = seton(&tt_mouse)) < 0)
+ return(x);
+ if (tt_mouse != old_mou)
+ if (tt_mouse)
+ os2_mouseon();
+ else
+ os2_mouseoff();
+ return(1);
+ }
+#endif /* OS2MOUSE */
+#endif /* OS2 */
+
+ case XYTWID: {
+ if ((y = cmnum(
+#ifdef OS2
+ "number of columns in display window during CONNECT",
+#else
+ "number of columns on your screen",
+#endif /* OS2 */
+ "80",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef OS2
+ return(success = os2_settermwidth(x));
+#else /* Not OS/2 */
+ tt_cols = x;
+ return(success = 1);
+#endif /* OS2 */
+ }
+
+ case XYTHIG:
+ if ((y = cmnum(
+#ifdef OS2
+ "number of rows in display window during CONNECT, not including status line",
+ tt_status[VTERM]?"24":"25",
+#else
+ "24","number of rows on your screen",
+#endif /* OS2 */
+ 10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+
+#ifdef OS2
+ return (success = os2_settermheight(x));
+#else /* Not OS/2 */
+ tt_rows = x;
+ return(success = 1);
+#endif /* OS2 */
+
+#ifdef OS2
+ case XYTPRN: { /* Print Mode */
+ extern bool xprint, aprint, cprint, uprint;
+ if ((y = cmkey(prnmtab,nprnmtab,"","off", xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ switch (y) {
+ case 0:
+ if (cprint || uprint || aprint || xprint)
+ printeroff();
+ cprint = xprint = uprint = 0;
+ setaprint(0);
+ break;
+ case 1:
+ if (!(cprint || uprint || aprint || xprint))
+ printeron();
+ setaprint(1);
+ cprint = xprint = uprint = 0;
+ break;
+ case 2:
+ if (!(cprint || uprint || aprint || xprint))
+ printeron();
+ cprint = 1;
+ setaprint(0);
+ xprint = uprint = 0;
+ break;
+ case 3:
+ if (!(cprint || uprint || aprint || xprint))
+ printeron();
+ uprint = 1;
+ setaprint(0);
+ xprint = cprint = 0;
+ break;
+ }
+ return(1);
+ }
+#else
+#ifdef XPRINT
+ case XYTPRN: {
+ extern int tt_print;
+ if ((x = seton(&tt_print)) < 0)
+ return(x);
+ return(success = 1);
+ }
+#endif /* XPRINT */
+#endif /* OS2 */
+
+#ifdef OS2
+ case XYTSCNM: {
+ extern int decscnm, decscnm_usr;
+ if ((y = cmkey(normrev,4,"",
+ decscnm_usr?"reverse":"normal",
+ xxstring)
+ ) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ decscnm_usr = y;
+ if (decscnm != decscnm_usr)
+ flipscreen(VTERM);
+ return(1);
+ }
+ case XYTOPTI:
+ if ((y = cmkey(onoff,2,"",tt_diff_upd?"on":"off",
+ xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ tt_diff_upd = y;
+ return(1);
+ case XYTUPD: {
+ int mode, delay;
+ if ((mode = cmkey(scrnupd,nscrnupd,"","fast",xxstring)) < 0) {
+ return(mode);
+ } else {
+ y = cmnum(
+ "Pause between FAST screen updates in CONNECT mode, milliseconds",
+ "100",10,&x,xxstring
+ );
+ if (x < 0 || x > 1000 ) {
+ printf(
+ "\n?The update rate must be between 0 and 1000 milliseconds.\n"
+ );
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+
+ updmode = tt_updmode = mode;
+ return(setnum(&tt_update,x,y,10000));
+ }
+ }
+ case XYTCTRL:
+ if ((x = cmkey(termctrl,ntermctrl,"","7",xxstring)) < 0) {
+ return(x);
+ } else {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch ( x ) {
+ case 8:
+ send_c1 = send_c1_usr = TRUE;
+ break;
+ case 7:
+ default:
+ send_c1 = send_c1_usr = FALSE;
+ break;
+ }
+ }
+ return(success = TRUE);
+ break;
+
+#ifdef PCFONTS
+ case XYTFON:
+ if ( !IsOS2FullScreen() ) {
+ printf(
+ "\n?SET TERMINAL FONT is only supported in Full Screen sessions.\n");
+ return(success = FALSE);
+ }
+
+ if ((x = cmkey(term_font,ntermfont,"","default",xxstring)) < 0) {
+ return(x);
+ } else {
+ if ((y = cmcfm()) < 0) return(y);
+ if ( !os2LoadPCFonts() ) {
+ tt_font = x;
+ return(success = TRUE);
+ } else {
+ printf(
+ "\n?PCFONTS.DLL is not available in CKERMIT executable directory.\n");
+ return(success = FALSE);
+ }
+ }
+ break;
+#else /* PCFONTS */
+#ifdef NT
+#ifdef KUI
+ case XYTFON:
+ return(setguifont()); /* ckuus3.c */
+#endif /* KUI */
+#endif /* NT */
+#endif /* PCFONTS */
+
+ case XYTVCH: {
+ extern int pheight, marginbot, cmd_rows, cmd_cols;
+ if ((x = cmkey(tvctab,ntvctab,"",isWin95()?"win95-safe":"enabled",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifndef KUI
+ if (x != tt_modechg) {
+ switch (x) {
+ case TVC_DIS:
+ /* When disabled the heights of all of the virtual screens */
+ /* must be equal to the physical height of the console */
+ /* window and may not be changed. */
+ /* The width of the window may not be altered. */
+ tt_modechg = TVC_ENA; /* Temporary */
+ if (marginbot > pheight-(tt_status[VTERM]?1:0))
+ marginbot = pheight-(tt_status[VTERM]?1:0);
+ tt_szchng[VCMD] = 1 ;
+ tt_rows[VCMD] = pheight;
+ VscrnInit(VCMD);
+ SetCols(VCMD);
+ cmd_rows = y;
+
+ tt_szchng[VTERM] = 2 ;
+ tt_rows[VTERM] = pheight - (tt_status[VTERM]?1:0);
+ VscrnInit(VTERM);
+
+ break;
+
+ case TVC_ENA:
+ /* When enabled the physical height of the console windows */
+ /* should be adjusted to the height of the virtual screen */
+ /* The width may be set to anything. */
+ /* nothing to do */
+ break;
+
+ case TVC_W95:
+ /* Win95-safe mode allows the physical height to change */
+ /* but restricts it to a width of 80 and a height equal to */
+ /* 25, 43, or 50. Must be adjusted now. */
+ /* The virtual heights must be equal to the above. */
+ if (pheight != 25 && pheight != 43 && pheight != 50) {
+ if (pheight < 25)
+ y = 25;
+ else if (pheight < 43)
+ y = 43;
+ else
+ y = 50;
+ } else
+ y = pheight;
+
+ tt_modechg = TVC_ENA; /* Temporary */
+
+ tt_szchng[VCMD] = 1;
+ tt_rows[VCMD] = y;
+ tt_cols[VCMD] = 80;
+ VscrnInit(VCMD);
+ SetCols(VCMD);
+ cmd_rows = y;
+ cmd_cols = 80;
+
+ marginbot = y-(tt_status[VTERM]?1:0);
+ tt_szchng[VTERM] = 2;
+ tt_rows[VTERM] = y - (tt_status[VTERM]?1:0);
+ tt_cols[VTERM] = 80;
+ VscrnInit(VTERM);
+ break;
+ }
+ tt_modechg = x;
+ }
+ return(success = 1);
+#else
+ return(success = 0);
+#endif /* KUI */
+ }
+ case XYTSTAT: {
+ extern int marginbot;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (y != tt_status[VTERM] || y != tt_status_usr[VTERM]) {
+ /* Might need to fixup the margins */
+ if ( marginbot == VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) )
+ if (y) {
+ marginbot--;
+ } else {
+ marginbot++;
+ }
+ tt_status_usr[VTERM] = tt_status[VTERM] = y;
+ if (y) {
+ tt_szchng[VTERM] = 2;
+ tt_rows[VTERM]--;
+ VscrnInit(VTERM); /* Height set here */
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ tn_snaws();
+#endif /* TNCODE */
+#ifdef RLOGCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ rlog_naws();
+#endif /* RLOGCODE */
+#ifdef SSHBUILTIN
+ if (TELOPT_ME(TELOPT_NAWS))
+ ssh_snaws();
+#endif /* SSHBUILTIN */
+ } else {
+ tt_szchng[VTERM] = 1;
+ tt_rows[VTERM]++;
+ VscrnInit(VTERM); /* Height set here */
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ tn_snaws();
+#endif /* TNCODE */
+#ifdef RLOGCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ rlog_naws();
+#endif /* RLOGCODE */
+#ifdef SSHBUILTIN
+ if (TELOPT_ME(TELOPT_NAWS))
+ ssh_snaws();
+#endif /* SSHBUILTIN */
+ }
+ }
+ return(1);
+ }
+#endif /* OS2 */
+
+#ifdef NT
+ case XYTATTBUG:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ tt_attr_bug = y;
+ return(1);
+#endif /* NT */
+
+#ifdef OS2
+ case XYTSGRC:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sgrcolors = y;
+ return(1);
+
+ case XYTSEND:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ tt_senddata = y;
+ return(1);
+
+ case XYTSEOB:
+ if ((y = cmkey(ttyseobtab,2,"","us_cr",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ wy_blockend = y;
+ return(1);
+
+ case XYTURLHI: {
+ int done = 0, attr = VT_CHAR_ATTR_NORMAL;
+
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(x);
+ if (x) {
+ z = 0;
+ while (!done) {
+ if ((y = cmkey(ttyprotab,nprotect,"",
+ z?"done":"reverse",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TTATTDONE:
+ done = TRUE;
+ break;
+ case TTATTBLI:
+ attr |= VT_CHAR_ATTR_BLINK;
+ break;
+ case TTATTREV:
+ attr |= VT_CHAR_ATTR_REVERSE;
+ break;
+ case TTATTITA:
+ attr |= VT_CHAR_ATTR_ITALIC;
+ break;
+ case TTATTUND:
+ attr |= VT_CHAR_ATTR_UNDERLINE;
+ break;
+ case TTATTBLD:
+ attr |= VT_CHAR_ATTR_BOLD;
+ break;
+ case TTATTDIM:
+ attr |= VT_CHAR_ATTR_DIM;
+ break;
+ case TTATTINV:
+ attr |= VT_CHAR_ATTR_INVISIBLE;
+ break;
+ case TTATTNOR:
+ break;
+ }
+ z = 1; /* One attribute has been chosen */
+ }
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ seturlhl(x);
+ if (x)
+ tt_url_hilite_attr = attr;
+ return(1);
+ }
+ case XYTATTR:
+ if ((x = cmkey(ttyattrtab,nattrib,"","underline",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case TTATTBLI:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ trueblink = y;
+#ifndef KUI
+ if ( !trueblink && trueunderline ) {
+ trueunderline = 0;
+ printf("Warning: Underline being simulated by color.\n");
+ }
+
+#endif /* KUI */
+ break;
+
+ case TTATTDIM:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ truedim = y;
+ break;
+
+ case TTATTREV:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ truereverse = y;
+ break;
+
+ case TTATTUND:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ trueunderline = y;
+#ifndef KUI
+ if (!trueblink && trueunderline) {
+ trueblink = 1;
+ printf("Warning: True blink mode is active.\n");
+ }
+#endif /* KUI */
+ break;
+
+ case TTATTITA:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ trueitalic = y;
+ break;
+
+ case TTATTPRO: { /* Set default Protected Character attribute */
+ extern vtattrib WPattrib; /* current WP Mode Attrib */
+ extern vtattrib defWPattrib; /* default WP Mode Attrib */
+ vtattrib wpa = {0,0,0,0,0,1,0,0,0,0,0}; /* Protected */
+ int done = 0;
+
+ x = 0;
+ while (!done) {
+ if ((y = cmkey(ttyprotab,nprotect,"",
+ x?"done":"dim",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TTATTNOR:
+ break;
+ case TTATTBLI: /* Blinking doesn't work */
+ wpa.blinking = TRUE;
+ break;
+ case TTATTREV:
+ wpa.reversed = TRUE;
+ break;
+ case TTATTITA:
+ wpa.italic = TRUE;
+ break;
+ case TTATTUND:
+ wpa.underlined = TRUE;
+ break;
+ case TTATTBLD:
+ wpa.bold = TRUE;
+ break;
+ case TTATTDIM:
+ wpa.dim = TRUE;
+ break;
+ case TTATTINV:
+ wpa.invisible = TRUE ;
+ break;
+ case TTATTDONE:
+ done = TRUE;
+ break;
+ }
+ x = 1; /* One attribute has been chosen */
+ }
+ if ((x = cmcfm()) < 0) return(x);
+ WPattrib = defWPattrib = wpa;
+ break;
+ }
+ }
+ return(1);
+
+ case XYTKEY: { /* SET TERMINAL KEY */
+ int t, x, y;
+ int clear = 0, deflt = 0;
+ int confirmed = 0;
+ int flag = 0;
+ int kc = -1; /* Key code */
+ int litstr = 0; /* Literal String? */
+ char *s = NULL; /* Key binding */
+#ifndef NOKVERBS
+ char *p = NULL; /* Worker */
+#endif /* NOKVERBS */
+ con_event defevt;
+ extern int os2gks;
+ extern int mskkeys;
+ extern int initvik;
+ struct FDB kw,sw,nu,cm;
+
+ defevt.type = error;
+
+ if ((t = cmkey(ttkeytab,nttkey,"","",xxstring)) < 0)
+ return(t);
+ cmfdbi(&nu, /* First FDB - command switches */
+ _CMNUM, /* fcode */
+ "/literal, keycode, or action",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ &sw /* Pointer to next FDB */
+ ); /* */
+ cmfdbi(&sw, /* Second FDB - switches */
+ _CMKEY, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ nstrmswitab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ strmswitab, /* Keyword table */
+ &kw /* Pointer to next FDB */
+ );
+ cmfdbi(&kw, /* Third FDB - command switches */
+ _CMKEY, /* fcode */
+ "/literal, keycode, or action",
+ "", /* default */
+ "", /* addtl string data */
+ nstrmkeytab, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2 */
+ xxstring, /* Processing function */
+ strmkeytab, /* Keyword table */
+ &cm /* Pointer to next FDB */
+ );
+ cmfdbi(&cm, /* Final FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ while (kc < 0) {
+ x = cmfdb(&nu); /* Parse something */
+ if (x < 0)
+ return(x);
+
+ switch (cmresult.fcode) {
+ case _CMCFM:
+ printf(" Press key to be defined: ");
+ conbin((char)escape); /* Put terminal in binary mode */
+ os2gks = 0; /* Turn off Kverb preprocessing */
+ kc = congks(0); /* Get character or scan code */
+ os2gks = 1; /* Turn on Kverb preprocessing */
+ concb((char)escape); /* Restore terminal to cbreak mode */
+ if (kc < 0) { /* Check for error */
+ printf("?Error reading key\n");
+ return(0);
+ }
+ shokeycode(kc,t); /* Show current definition */
+ flag = 1; /* Remember it's a multiline command */
+ break;
+ case _CMNUM:
+ kc = cmresult.nresult;
+ break;
+ case _CMKEY:
+ if (cmresult.fdbaddr == &sw) { /* Switch */
+ if (cmresult.nresult == 0)
+ litstr = 1;
+ } else if (cmresult.fdbaddr == &kw) { /* Keyword */
+ if (cmresult.nresult == 0)
+ clear = 1;
+ else
+ deflt = 1;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (clear)
+ clearkeymap(t);
+ else if (deflt)
+ defaultkeymap(t);
+ initvik = 1;
+ return(1);
+ }
+ }
+ }
+
+ /* Normal SET TERMINAL KEY <terminal> <scancode> <value> command... */
+
+ if (mskkeys)
+ kc = msktock(kc);
+
+ if (kc < 0 || kc >= KMSIZE) {
+ printf("?key code must be between 0 and %d\n", KMSIZE - 1);
+ return(-9);
+ }
+ if (kc == escape) {
+ printf("Sorry, %d is the CONNECT-mode escape character\n",kc);
+ return(-9);
+ }
+ wideresult = -1;
+ if (flag) {
+ cmsavp(psave,PROMPTL);
+ cmsetp(" Enter new definition: ");
+ cmini(ckxech);
+ }
+ def_again:
+ if (flag) prompt(NULL);
+ if ((y = cmtxt("key definition,\n\
+ or Ctrl-C to cancel this command,\n\
+ or Enter to restore default definition",
+ "",&s,NULL)) < 0) {
+ if (flag) /* Handle parse errors */
+ goto def_again;
+ else
+ return(y);
+ }
+ s = brstrip(s);
+#ifndef NOKVERBS
+ p = s; /* Save this place */
+#endif /* NOKVERBS */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else.
+
+ We use this code active for all versions that support SET KEY, even if they
+ don't support \Kverbs, because otherwise \K would behave differently for
+ different versions.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Get remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ if (flag) cmsetp(psave);
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#endif /* NOKVERBS */
+
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Clear individual key def */
+ deletekeymap(t,kc);
+ break;
+ case 1:
+ if (!litstr) {
+ defevt.type = key; /* Single character */
+ defevt.key.scancode = *s;
+ break;
+ }
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ /* Need exact match */
+ debug(F101,"set key kverb lookup",0,y);
+ if (y > -1) {
+ defevt.type = kverb;
+ defevt.kverb.id = y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+ if (litstr) {
+ defevt.type = literal;
+ defevt.literal.string = (char *) malloc(strlen(s)+1);
+ if (defevt.literal.string)
+ strcpy(defevt.literal.string, s); /* safe */
+ } else {
+ defevt.type = macro;
+ defevt.macro.string = (char *) malloc(strlen(s)+1);
+ if (defevt.macro.string)
+ strcpy(defevt.macro.string, s); /* safe */
+ }
+ break;
+ }
+ insertkeymap(t, kc, defevt);
+ if (flag)
+ cmsetp(psave);
+ initvik = 1; /* Update VIK table */
+ return(1);
+ }
+
+#ifdef PCTERM
+ case XYTPCTERM: /* PCTERM Keyboard Mode */
+ if ((x = seton(&tt_pcterm)) < 0) return(x);
+ return(success = 1);
+#endif /* PCTERM */
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+ case XYTRIGGER:
+ if ((y = cmtxt("String to trigger automatic return to command mode",
+ "",&s,xxstring)) < 0)
+ return(y);
+ makelist(s,tt_trigger,TRIGGERS);
+ return(1);
+#endif /* CK_TRIGGER */
+
+#ifdef OS2
+ case XYTSAC:
+ if ((y = cmnum("ASCII value to use for spacing attributes",
+ "32",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_sac = x;
+ return(success = 1);
+
+ case XYTKBDGL: { /* SET TERM KBD-FOLLOWS-GL/GR */
+ extern int tt_kb_glgr; /* from ckoco3.c */
+ if ((x = seton(&tt_kb_glgr)) < 0)
+ return(x);
+ return(success = 1);
+ }
+#ifndef NOCSETS
+ case XYTVTLNG: /* SET TERM DEC-LANGUAGE */
+ if ((y = cmkey(vtlangtab,nvtlangtab,"VT language",
+ IS97801(tt_type_mode)?"german":"north-american",
+ xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+
+ /* A real VT terminal would use the language to set the */
+ /* default keyboard language for both 8-bit multinational */
+ /* and 7-bit national modes. For 8-bit mode it would */
+ /* set the terminal character-set to the ISO set if it */
+ /* is not already set. */
+ /* Latin-1 can be replaced by DEC Multinational */
+ switch (y) {
+ case VTL_NORTH_AM: /* North American */
+ /* Multinational: Latin-1 */
+ /* National: US_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_ASCII;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_BRITISH :
+ /* Multinational: Latin-1 */
+ /* National: UK_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_BRITISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_FRENCH :
+ case VTL_BELGIAN :
+ case VTL_CANADIAN:
+ /* Multinational: Latin-1 */
+ /* National: FR_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_FRENCH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_FR_CAN :
+ /* Multinational: Latin-1 */
+ /* National: FC_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_CN_FRENCH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_DANISH :
+ case VTL_NORWEGIA:
+ /* Multinational: Latin-1 */
+ /* National: NO_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_NORWEGIAN;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_FINNISH :
+ /* Multinational: Latin-1 */
+ /* National: FI_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_FINNISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_GERMAN :
+ /* Multinational: Latin-1 */
+ /* National: GR_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_GERMAN;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_DUTCH :
+ /* Multinational: Latin-1 */
+ /* National: DU_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_DUTCH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_ITALIAN :
+ /* Multinational: Latin-1 */
+ /* National: IT_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_ITALIAN;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_SW_FR :
+ case VTL_SW_GR :
+ /* Multinational: Latin-1 */
+ /* National: CH_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_SWISS;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_SWEDISH :
+ /* Multinational: Latin-1 */
+ /* National: SW_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_SWEDISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_SPANISH :
+ /* Multinational: Latin-1 */
+ /* National: SP_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_SPANISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_PORTUGES:
+ /* Multinational: Latin-1 */
+ /* National: Portugese ASCII */
+ dec_lang = y;
+ dec_nrc = TX_PORTUGUESE;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_HEBREW :
+ /* Multinational: Latin-Hebrew / DEC-Hebrew */
+ /* National: DEC 7-bit Hebrew */
+ dec_lang = y;
+ dec_nrc = TX_HE7;
+ dec_kbd = TX_8859_8;
+ break;
+ case VTL_GREEK :
+ /* Multinational: Latin-Greek / DEC-Greek */
+ /* National: DEC Greek NRC */
+ /* is ELOT927 equivalent to DEC Greek???? */
+ dec_lang = y;
+ dec_nrc = TX_ELOT927;
+ dec_kbd = TX_8859_7;
+ break;
+#ifdef COMMENT
+ case VTL_TURK_Q :
+ case VTL_TURK_F :
+ /* Multinational: Latin-Turkish / DEC-Turkish */
+ /* National: DEC 7-bit Turkish */
+ break;
+#endif /* COMMENT */
+ case VTL_HUNGARIA:
+ /* Multinational: Latin-2 */
+ /* National: no national mode */
+ dec_lang = y;
+ dec_nrc = TX_HUNGARIAN;
+ dec_kbd = TX_8859_2;
+ break;
+ case VTL_SLOVAK :
+ case VTL_CZECH :
+ case VTL_POLISH :
+ case VTL_ROMANIAN:
+ /* Multinational: Latin-2 */
+ /* National: no national mode */
+ dec_lang = y;
+ dec_nrc = TX_ASCII;
+ dec_kbd = TX_8859_2;
+ break;
+ case VTL_RUSSIAN :
+ /* Multinational: Latin-Cyrillic / KOI-8 */
+ /* National: DEC Russian NRC */
+ dec_lang = y;
+ dec_nrc = TX_KOI7;
+ dec_kbd = TX_8859_5;
+ break;
+ case VTL_LATIN_AM:
+ /* Multinational: not listed in table */
+ /* National: not listed in table */
+ dec_lang = y;
+ dec_nrc = TX_ASCII;
+ dec_kbd = TX_8859_1;
+ break;
+#ifdef COMMENT
+ case VTL_SCS :
+ /* Multinational: Latin-2 */
+ /* National: SCS NRC */
+ break;
+#endif /* COMMENT */
+ default:
+ return(success = 0);
+ }
+ if (IS97801(tt_type_mode)) {
+ SNI_bitmode(cmask == 0377 ? 8 : 7);
+ }
+ return(success = 1);
+#endif /* NOCSETS */
+
+ case XYTVTNRC: { /* SET TERM DEC-NRC-MODE */
+ extern int decnrcm_usr, decnrcm; /* from ckoco3.c */
+ if ((x = seton(&decnrcm_usr)) < 0)
+ return(x);
+ decnrcm = decnrcm_usr;
+ return(success = 1);
+ }
+ case XYTSNIPM: { /* SET TERM SNI-PAGEMODE */
+ extern int sni_pagemode, sni_pagemode_usr;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sni_pagemode_usr = sni_pagemode = y;
+ return(success = 1);
+ }
+ case XYTSNISM: { /* SET TERM SNI-SCROLLMODE */
+ extern int sni_scroll_mode, sni_scroll_mode_usr;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sni_scroll_mode_usr = sni_scroll_mode = y;
+ return(success = 1);
+ }
+ case XYTSNICC: { /* SET TERM SNI-CH.CODE */
+ extern int sni_chcode_usr;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sni_chcode_usr = y;
+ SNI_chcode(y);
+ return(success = 1);
+ }
+ case XYTSNIFV: { /* SET TERM SNI-FIRMWARE-VERSIONS */
+ extern CHAR sni_kbd_firmware[], sni_term_firmware[];
+ CHAR kbd[7],term[7];
+
+ if ((x = cmfld("Keyboard Firmware Version",sni_kbd_firmware,
+ &s, xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) != 6) {
+ printf("?Sorry - the firmware version must be 6 digits long\n");
+ return(-9);
+ }
+ for (i = 0; i < 6; i++) {
+ if (!isdigit(s[i])) {
+ printf("?Sorry - the firmware version can only contain digits [0-9]\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(kbd,s,7);
+
+ if ((x = cmfld("Terminal Firmware Version",sni_term_firmware,
+ &s, xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) != 6) {
+ printf("?Sorry - the firmware version must be 6 digits long\n");
+ return(-9);
+ }
+ for (i = 0; i < 6; i++) {
+ if (!isdigit(s[i])) {
+ printf("?Sorry - the firmware version can only contain digits [0-9]\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(term,s,7);
+ if ((x = cmcfm()) < 0) return(x);
+
+ ckstrncpy(sni_kbd_firmware,kbd,7);
+ ckstrncpy(sni_term_firmware,term,7);
+ return(success = 1);
+ }
+
+ case XYTLSP: { /* SET TERM LINE-SPACING */
+ if ((x = cmfld("Line Spacing","1",&s, xxstring)) < 0)
+ return(x);
+ if (isfloat(s,0) < 1) { /* (sets floatval) */
+ printf("?Integer or floating-point number required\n");
+ return(-9);
+ }
+ if (floatval < 1.0 || floatval > 3.0) {
+ printf("?Value must within the range 1.0 and 3.0 (inclusive)\n");
+ return(-9);
+ }
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef KUI
+ tt_linespacing[VCMD] = tt_linespacing[VTERM] = floatval;
+ return(success = 1);
+#else /* KUI */
+ printf("?Sorry, Line-spacing is only supported in K95G.EXE.\n");
+ return(success = 0);
+#endif /* KUI */
+ }
+#endif /* OS2 */
+
+ default: /* Shouldn't get here. */
+ return(-2);
+ }
+#endif /* MAC */
+#ifdef COMMENT
+ /*
+ This was supposed to shut up picky compilers but instead it makes
+ most compilers complain about "statement not reached".
+ */
+ return(-2);
+#endif /* COMMENT */
+#ifdef OS2
+ return(-2);
+#endif /* OS2 */
+}
+
+#ifdef OS2
+int
+settitle(void) {
+ extern char usertitle[];
+ if ((y = cmtxt("title text","",&s,xxstring)) < 0)
+ return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ s = brstrip(s);
+ ckstrncpy(usertitle,s,64);
+ os2settitle("",1);
+ return(1);
+}
+
+static struct keytab dialertab[] = { /* K95 Dialer types */
+ "backspace", 0, 0,
+ "enter", 1, 0
+};
+static int ndialer = 2;
+
+int
+setdialer(void) {
+ int t, x, y;
+ int clear = 0, deflt = 0;
+ int kc; /* Key code */
+ char *s = NULL; /* Key binding */
+#ifndef NOKVERBS
+ char *p = NULL; /* Worker */
+#endif /* NOKVERBS */
+ con_event defevt;
+ extern int os2gks;
+ extern int mskkeys;
+ extern int initvik;
+
+ defevt.type = error;
+
+ if (( x = cmkey(dialertab, ndialer,
+ "Kermit-95 dialer work-arounds",
+ "", xxstring)) < 0 )
+ return(x);
+ switch (x) {
+ case 0: /* Backspace */
+ kc = 264;
+ break;
+ case 1: /* Enter */
+ kc = 269;
+ break;
+ default:
+ printf("Illegal value in setdialer()\n");
+ return(-9);
+ }
+ if ((y = cmtxt("Key definition","",&s,xxstring)) < 0)
+ return(y);
+
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ s = brstrip(s);
+#ifndef NOKVERBS
+ p = s; /* Save this place */
+#endif /* NOKVERBS */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else.
+
+ We use this code active for all versions that support SET KEY, even if they
+ don't support \Kverbs, because otherwise \K would behave differently for
+ different versions.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#endif /* NOKVERBS */
+
+ /* Clear the definition for SET KEY */
+ if (macrotab[kc]) { /* Possibly free old macro from key. */
+ free((char *)macrotab[kc]);
+ macrotab[kc] = NULL;
+ }
+ keymap[kc] = (KEY) kc;
+
+ /* Now reprogram the default value for all terminal types */
+ /* remember to treat Wyse and Televideo terminals special */
+ /* because of their use of Kverbs for Backspace and Enter */
+ for (t = 0; t <= TT_MAX; t++) {
+ if ( ISDG200(t) && kc == 264) {
+ extern char * udkfkeys[] ;
+ if (kc == 264) { /* \Kdgbs */
+ if (udkfkeys[83])
+ free(udkfkeys[83]);
+ udkfkeys[83] = strdup(s);
+ }
+ } else if (ISWYSE(t) || ISTVI(t)) {
+ extern char * udkfkeys[] ;
+ if (kc == 264) { /* \Kwybs or \Ktvibs */
+ if (udkfkeys[32])
+ free(udkfkeys[32]);
+ udkfkeys[32] = strdup(s);
+ }
+ if (kc == 269) { /* \Kwyenter and \Kwyreturn */
+ if (udkfkeys[39]) /* \Ktvienter and \Ktvireturn */
+ free(udkfkeys[39]);
+ udkfkeys[39] = strdup(s);
+ if (udkfkeys[49])
+ free(udkfkeys[49]);
+ udkfkeys[49] = strdup(s);
+ }
+ } else {
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Clear individual key def */
+ deletekeymap(t,kc);
+ break;
+ case 1:
+ defevt.type = key; /* Single character */
+ defevt.key.scancode = *s;
+ break;
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ /* Exact match req'd */
+ debug(F101,"set key kverb lookup",0,y);
+ if (y > -1) {
+ defevt.type = kverb;
+ defevt.kverb.id = y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+ defevt.type = macro;
+ defevt.macro.string = (char *) malloc(strlen(s)+1);
+ if (defevt.macro.string)
+ strcpy(defevt.macro.string, s); /* safe */
+ break;
+ }
+ insertkeymap( t, kc, defevt ) ;
+ initvik = 1; /* Update VIK table */
+ }
+ }
+ return(1);
+}
+#endif /* OS2 */
+
+#ifdef NT
+int
+setwin95( void ) {
+ int x, y, z;
+
+ if (( y = cmkey(win95tab, nwin95,
+ "Windows 95 specific work-arounds",
+ "keyboard-translation",
+ xxstring)) < 0 )
+ return (y);
+ switch (y) {
+ case XYWPOPUP:
+ if ((y = cmkey(onoff,2,"popups are used to prompt the user for data",
+ "on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95_popup = y;
+ return(1);
+
+ case XYW8_3:
+ if ((y = cmkey(onoff,2,"8.3 FAT file names","off",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95_8_3 = y;
+ return(1);
+
+ case XYWSELECT:
+ if ((y = cmkey(onoff,2,"\"select()\" fails on write","off",
+ xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95selectbug = y;
+ return(1);
+
+ case XYWAGR:
+ if ((y = cmkey(onoff,2,"Right-Alt is Alt-Gr","off",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95altgr = y;
+ return(1);
+
+ case XYWOIO:
+ if ((y = cmkey(onoff,2,"Use Overlapped I/O","on",xxstring)) < 0)
+ return(y);
+ if (y) {
+ if ((x = cmnum("Maximum number of outstanding I/O requests",
+ "10",10,&z,xxstring)) < 0)
+ return(x);
+ if (z < 1 || z > 7) {
+ printf(
+"?Maximum outstanding I/O requests must be between 1 and 7.\n");
+ return(-9);
+ }
+ } else
+ z = 1;
+ if ((x = cmcfm()) < 0) return(x);
+ owwait = !y;
+ maxow = maxow_usr = z;
+ return(1);
+
+ case XYWKEY:
+#ifndef COMMENT
+ printf("\n?\"Keyboard-Translation\" is no longer required.\n");
+ return(-9);
+#else /* COMMENT */
+ if (( z = cmkey(tcstab, ntcs,
+ "Keyboard Character Set",
+ "latin1-iso",
+ xxstring)) < 0)
+ return (z);
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ win95kcsi = z;
+ win95kl2 = (win95kcsi == TC_2LATIN);
+
+ if (win95kcsi == TC_TRANSP) {
+ win95kcs = NULL;
+ } else {
+#ifdef UNICODE
+ win95kcs = xlr[win95kcsi][tx2fc(tcsl)];
+#else /* UNICODE */
+ win95kcs = xlr[win95kcsi][tcsl];
+#endif /* UNICODE */
+ }
+ return(1);
+#endif /* COMMENT */
+
+ case XYWLUC:
+ if ((y = cmkey(onoff,2,"Unicode-to-Lucida-Console substitutions",
+ "on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95lucida = y;
+ return(1);
+
+ case XYWHSL:
+ if ((y = cmkey(onoff,2,"Horizontal Scan Line substitutions",
+ "on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95hsl = y;
+ return(1);
+
+ default:
+ printf("Illegal value in setwin95()\n");
+ return(-9);
+ }
+}
+#endif /* NT */
+
+#ifdef OS2
+int
+setprty (
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+/* setprty */ ) {
+ int x, y, z;
+
+ if (( y = cmkey(prtytab, nprty,
+ "priority level of terminal and communication threads",
+ "foreground-server",
+ xxstring)) < 0 )
+ return (y);
+
+ if ((x = cmcfm()) < 0)
+ return (x);
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+ ) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ priority = y;
+ return(TRUE);
+}
+#endif /* OS2 */
+
+int
+setbell() {
+ int y, x;
+#ifdef OS2
+ int z;
+#endif /* OS2 */
+
+ if ((y = cmkey(beltab,nbeltab,
+#ifdef OS2
+ "how console and terminal bells should\nbe generated", "audible",
+#else
+ "Whether Kermit should ring the terminal bell (beep)", "on",
+#endif /* OS2 */
+ xxstring)) < 0)
+ return(y);
+
+#ifdef IKSD
+ if (inserver) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ switch (y) { /* SET BELL */
+ case XYB_NONE:
+#ifdef OS2
+ case XYB_VIS:
+#endif /* OS2 */
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef OS2
+ tt_bell = y;
+#else
+ tt_bell = 0;
+#endif /* OS2 */
+ break;
+
+ case XYB_AUD:
+#ifdef OS2
+ if ((x = cmkey(audibletab, naudibletab,
+ "how audible console and terminal\nbells should be generated",
+ "beep",xxstring))<0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ tt_bell = y | x;
+#else
+ /* This lets C-Kermit accept but ignore trailing K95 keywords */
+ if ((x = cmtxt("Confirm with carriage return","",&s,xxstring)) < 0)
+ return(x);
+ tt_bell = 1;
+#endif /* OS2 */
+ break;
+ }
+ return(1);
+}
+
+#ifdef OS2MOUSE
+int
+setmou(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ /* setmou */ ) {
+ extern int initvik;
+ int button = 0, event = 0;
+ char * p;
+
+ if ((y = cmkey(mousetab,nmtab,"","",xxstring)) < 0)
+ return(y);
+
+#ifdef IKSD
+ if (inserver) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ if (y == XYM_ON) { /* MOUSE ACTIVATION */
+ int old_mou = tt_mouse;
+ if ((x = seton(&tt_mouse)) < 0)
+ return(x);
+ if (tt_mouse != old_mou)
+ if (tt_mouse)
+ os2_mouseon();
+ else
+ os2_mouseoff();
+ return(1);
+ }
+
+ if (y == XYM_DEBUG) { /* MOUSE DEBUG */
+ extern int MouseDebug;
+ if ((x = seton(&MouseDebug)) < 0)
+ return(x);
+ return(1);
+ }
+
+ if (y == XYM_CLEAR) { /* Reset Mouse Defaults */
+ if ((x = cmcfm()) < 0) return(x);
+ mousemapinit(-1,-1);
+ initvik = 1; /* Update VIK Table */
+ return 1;
+ }
+ if (y != XYM_BUTTON) { /* Shouldn't happen. */
+ printf("Internal parsing error\n");
+ return(-9);
+ }
+
+ /* MOUSE EVENT ... */
+
+ if ((button = cmkey(mousebuttontab,nmbtab,
+ "Button number","1",
+ xxstring)) < 0)
+ return(button);
+
+ if ((y = cmkey(mousemodtab,nmmtab,
+ "Keyboard modifier","none",
+ xxstring)) < 0)
+ return(y);
+
+ event |= y; /* OR in the bits */
+
+ if ((y = cmkey(mclicktab,nmctab,"","click",xxstring)) < 0)
+ return(y);
+
+ /* Two bits are assigned, if neither are set then it is button one */
+
+ event |= y; /* OR in the bit */
+
+ wideresult = -1;
+
+ if ((y = cmtxt("definition,\n\
+or Ctrl-C to cancel this command,\n\
+or Enter to restore default definition",
+ "",&s,NULL)) < 0) {
+ return(y);
+ }
+ s = brstrip(s);
+ p = s; /* Save this place */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else. This code copied from SET KEY, q.v. for addt'l commentary.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#else
+ p = NULL;
+#endif /* NOKVERBS */
+
+ /* free the old definition if necessary */
+ if (mousemap[button][event].type == macro) {
+ free( mousemap[button][event].macro.string);
+ mousemap[button][event].macro.string = NULL;
+ }
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Reset to default binding */
+ mousemapinit( button, event );
+ break;
+ case 1: /* Single character */
+ mousemap[button][event].type = key;
+ mousemap[button][event].key.scancode = *s;
+ break;
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ debug(F101,"set mouse kverb lookup",0,y); /* need exact match */
+ if (y > -1) {
+ /* Assign the kverb to the event */
+ mousemap[button][event].type = kverb;
+ mousemap[button][event].kverb.id = F_KVERB | y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+
+ /* Otherwise, it's a macro, so assign the macro to the event */
+ mousemap[button][event].type = macro;
+ mousemap[button][event].macro.string = (MACRO) malloc(strlen(s)+1);
+ if (mousemap[button][event].macro.string)
+ strcpy((char *) mousemap[button][event].macro.string, s); /* safe */
+ break;
+ }
+ initvik = 1; /* Update VIK Table */
+ if ( (button == XYM_B3) && (mousebuttoncount() < 3) && !quiet )
+ {
+ printf("?Warning: this machine does not have a three button mouse.\n");
+ return(0);
+ }
+ return(1);
+}
+#endif /* OS2MOUSE */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+int /* SET SEND/RECEIVE */
+setsr(xx, rmsflg) int xx; int rmsflg; {
+ if (xx == XYRECV)
+ ckstrncpy(line,"Parameter for inbound packets",LINBUFSIZ);
+ else
+ ckstrncpy(line,"Parameter for outbound packets",LINBUFSIZ);
+
+ if (rmsflg) {
+ if ((y = cmkey(rsrtab,nrsrtab,line,"",xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Remote receive parameter required\n");
+ return(-9);
+ } else return(y);
+ }
+ } else {
+ if ((y = cmkey(srtab,nsrtab,line,"",xxstring)) < 0) return(y);
+ }
+ switch (y) {
+ case XYQCTL: /* CONTROL-PREFIX */
+ if ((x = cmnum("ASCII value of control prefix","",10,&y,xxstring)) < 0)
+ return(x);
+ if ((x = cmcfm()) < 0) return(x);
+ if ((y > 32 && y < 63) || (y > 95 && y < 127)) {
+ if (xx == XYRECV)
+ ctlq = (CHAR) y; /* RECEIVE prefix, use with caution! */
+ else
+ myctlq = (CHAR) y; /* SEND prefix, OK to change */
+ return(success = 1);
+ } else {
+ printf("?Illegal value for prefix character\n");
+ return(-9);
+ }
+
+ case XYEOL:
+ if ((y = setcc("13",&z)) < 0)
+ return(y);
+ if (z > 31) {
+ printf("Sorry, the legal values are 0-31\n");
+ return(-9);
+ }
+ if (xx == XYRECV)
+ eol = (CHAR) z;
+ else
+ seol = (CHAR) z;
+ return(success = y);
+
+ case XYLEN:
+ y = cmnum("Maximum number of characters in a packet","90",10,&x,
+ xxstring);
+ if (xx == XYRECV) { /* Receive... */
+ if ((y = setnum(&z,x,y,maxrps)) < 0)
+ return(y);
+ if (protocol != PROTO_K) {
+ printf("?Sorry, this command does not apply to %s protocol.\n",
+ ptab[protocol].p_name
+ );
+ printf("Use SET SEND PACKET-LENGTH for XYZMODEM\n");
+ return(-9);
+ }
+ if (z < 10) {
+ printf("Sorry, 10 is the minimum\n");
+ return(-9);
+ }
+ if (rmsflg) {
+ sstate = setgen('S', "401", ckitoa(z), "");
+ return((int) sstate);
+ } else {
+ if (protocol == PROTO_K) {
+ if (z > MAXRP) z = MAXRP;
+ y = adjpkl(z,wslotr,bigrbsiz);
+ if (y != z) {
+ urpsiz = y;
+ if (!xcmdsrc)
+ if (msgflg) printf(
+" Adjusting receive packet-length to %d for %d window slots\n",
+ y, wslotr);
+ }
+ urpsiz = y;
+ ptab[protocol].rpktlen = urpsiz;
+ rpsiz = (y > 94) ? 94 : y;
+ } else {
+#ifdef CK_XYZ
+ if ((protocol == PROTO_X || protocol == PROTO_XC) &&
+ z != 128 && z != 1024) {
+ printf("Sorry, bad packet length for XMODEM.\n");
+ printf("Please use 128 or 1024.\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ urpsiz = rpsiz = z;
+ }
+ }
+ } else { /* Send... */
+ if ((y = setnum(&z,x,y,maxsps)) < 0)
+ return(y);
+ if (z < 10) {
+ printf("Sorry, 10 is the minimum\n");
+ return(-9);
+ }
+ if (protocol == PROTO_K) {
+ if (z > MAXSP) z = MAXSP;
+ spsiz = z; /* Set it */
+ y = adjpkl(spsiz,wslotr,bigsbsiz);
+ if (y != spsiz && !xcmdsrc)
+ if (msgflg)
+ printf("Adjusting packet size to %d for %d window slots\n",
+ y,wslotr);
+ } else
+ y = z;
+#ifdef CK_XYZ
+ if ((protocol == PROTO_X || protocol == PROTO_XC) &&
+ z != 128 && z != 1024) {
+ printf("Sorry, bad packet length for XMODEM.\n");
+ printf("Please use 128 or 1024.\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ spsiz = spmax = spsizr = y; /* Set it and flag that it was set */
+ spsizf = 1; /* to allow overriding Send-Init. */
+ ptab[protocol].spktflg = spsizf;
+ ptab[protocol].spktlen = spsiz;
+ }
+ if (pflag && protocol == PROTO_K && !xcmdsrc) {
+ if (z > 94 && !reliable && msgflg) {
+ /* printf("Extended-length packets requested.\n"); */
+ if (bctr < 2 && z > 200) printf("\
+Remember to SET BLOCK 2 or 3 for long packets.\n");
+ }
+ if (speed <= 0L) speed = ttgspd();
+#ifdef COMMENT
+/*
+ Kermit does this now itself.
+*/
+ if (speed <= 0L && z > 200 && msgflg) {
+ printf("\
+Make sure your timeout interval is long enough for %d-byte packets.\n",z);
+ }
+#endif /* COMMENT */
+ }
+ return(success = y);
+
+ case XYMARK:
+#ifdef DOOMSDAY
+/*
+ Printable start-of-packet works for UNIX and VMS only!
+*/
+ x_ifnum = 1;
+ y = cmnum("Code for packet-start character","1",10,&x,xxstring);
+ x_ifnum = 0;
+ if ((y = setnum(&z,x,y,126)) < 0) return(y);
+#else
+ if ((y = setcc("1",&z)) < 0)
+ return(y);
+#endif /* DOOMSDAY */
+ if (xx == XYRECV)
+ stchr = (CHAR) z;
+ else {
+ mystch = (CHAR) z;
+#ifdef IKS_OPTION
+ /* If IKS negotiation in use */
+ if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT))
+ tn_siks(KERMIT_SOP); /* Report change to other side */
+#endif /* IKS_OPTION */
+ }
+ return(success = y);
+
+ case XYNPAD: /* PADDING */
+ y = cmnum("How many padding characters for inbound packets","0",10,&x,
+ xxstring);
+ if ((y = setnum(&z,x,y,94)) < 0) return(y);
+ if (xx == XYRECV)
+ mypadn = (CHAR) z;
+ else
+ npad = (CHAR) z;
+ return(success = y);
+
+ case XYPADC: /* PAD-CHARACTER */
+ if ((y = setcc("0",&z)) < 0) return(y);
+ if (xx == XYRECV) mypadc = z; else padch = z;
+ return(success = y);
+
+ case XYTIMO: /* TIMEOUT */
+ if (xx == XYRECV) {
+ y = cmnum("Packet timeout interval",ckitoa(URTIME),10,&x,xxstring);
+ if ((y = setnum(&z,x,y,94)) < 0) return(y);
+
+ if (rmsflg) { /* REMOTE SET RECEIVE TIMEOUT */
+ sstate = setgen('S', "402", ckitoa(z), "");
+ return((int) sstate);
+ } else { /* SET RECEIVE TIMEOUT */
+ pkttim = z; /* Value to put in my negotiation */
+ } /* packet for other Kermit to use */
+
+ } else { /* SET SEND TIMEOUT */
+#ifdef CK_TIMERS
+ extern int rttflg, mintime, maxtime;
+ int tmin = 0, tmax = 0;
+#endif /* CK_TIMERS */
+ y = cmnum("Packet timeout interval",ckitoa(DMYTIM),10,&x,xxstring);
+ if (y == -3) { /* They cancelled a previous */
+ x = DMYTIM; /* SET SEND command, so restore */
+ timef = 0; /* and turn off the override flag */
+ y = cmcfm();
+ }
+#ifdef CK_TIMERS
+ if (y < 0) return(y);
+ if (x < 0) {
+ printf("?Out of range - %d\n",x);
+ return(-9);
+ }
+ if ((z = cmkey(timotab,2,"","dynamic",xxstring)) < 0) return(z);
+ if (z) {
+ if ((y = cmnum("Minimum timeout to allow",
+ "1",10,&tmin,xxstring)) < 0)
+ return(y);
+ if (tmin < 1) {
+ printf("?Out of range - %d\n",tmin);
+ return(-9);
+ }
+ if ((y = cmnum("Maximum timeout to allow",
+ "0",10,&tmax,xxstring)) < 0)
+ return(y);
+ /* 0 means let Kermit choose, < 0 means no maximum */
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+ rttflg = z; /* Round-trip timer flag */
+ z = x;
+#else
+ if ((y = setnum(&z,x,y,94)) < 0)
+ return(y);
+#endif /* CK_TIMERS */
+ timef = 1; /* Turn on the override flag */
+ timint = rtimo = z; /* Override value for me to use */
+#ifdef CK_TIMERS
+ if (rttflg) { /* Lower and upper bounds */
+ mintime = tmin;
+ maxtime = tmax;
+ }
+#endif /* CK_TIMERS */
+ }
+ return(success = 1);
+
+ case XYFPATH: /* PATHNAMES */
+ if (xx == XYRECV) {
+ y = cmkey(rpathtab,nrpathtab,"","auto",xxstring);
+ } else {
+ y = cmkey(pathtab,npathtab,"","off",xxstring);
+ }
+ if (y < 0) return(y);
+
+ if ((x = cmcfm()) < 0) return(x);
+ if (xx == XYRECV) { /* SET RECEIVE PATHNAMES */
+ fnrpath = y;
+ ptab[protocol].fnrp = fnrpath;
+ } else { /* SET SEND PATHNAMES */
+ fnspath = y;
+ ptab[protocol].fnsp = fnspath;
+ }
+ return(success = 1); /* Note: 0 = ON, 1 = OFF */
+ /* In other words, ON = leave pathnames ON, OFF = take them off. */
+
+ case XYPAUS: /* SET SEND/RECEIVE PAUSE */
+ y = cmnum("Milliseconds to pause between packets","0",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,15000)) < 0)
+ return(y);
+ pktpaus = z;
+ return(success = 1);
+
+#ifdef CKXXCHAR /* SET SEND/RECEIVE IGNORE/DOUBLE */
+ case XYIGN:
+ case XYDBL: {
+ int i, zz;
+ short *p;
+ extern short dblt[];
+ extern int dblflag, ignflag;
+
+ /* Make space for a temporary copy of the ignore/double table */
+
+ zz = y;
+#ifdef COMMENT
+ if (zz == XYIGN && xx == XYSEND) {
+ blah blah who cares
+ }
+ if (zz == XYDBL && xx == XYRECV) {
+ blah blah
+ }
+#endif /* COMMENT */
+ p = (short *)malloc(256 * sizeof(short));
+ if (!p) {
+ printf("?Internal error - malloc failure\n");
+ return(-9);
+ }
+ for (i = 0; i < 256; i++) p[i] = dblt[i]; /* Copy current table */
+
+ while (1) { /* Collect a list of numbers */
+#ifndef NOSPL
+ x_ifnum = 1; /* Turn off complaints from eval() */
+#endif /* NOSPL */
+ if ((x = cmnum(zz == XYDBL ?
+ "Character to double" :
+ "Character to ignore",
+ "",10,&y,xxstring
+ )) < 0) {
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ if (x == -3) /* Done */
+ break;
+ if (x == -2) {
+ if (p) { free(p); p = NULL; }
+ debug(F110,"SET S/R DOUBLE/IGNORE atmbuf",atmbuf,0);
+ if (!ckstrcmp(atmbuf,"none",4,0) ||
+ !ckstrcmp(atmbuf,"non",3,0) ||
+ !ckstrcmp(atmbuf,"no",2,0) ||
+ !ckstrcmp(atmbuf,"n",1,0)) {
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ for (y = 0; y < 256; y++)
+ dblt[y] &= (zz == XYDBL) ? 1 : 2;
+ if (zz == XYDBL) dblflag = 0;
+ if (zz == XYIGN) ignflag = 0;
+ return(success = 1);
+ } else {
+ printf(
+ "?Please specify a number or the word NONE\n");
+ return(-9);
+ }
+ } else {
+ free(p);
+ p = NULL;
+ return(x);
+ }
+ }
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ if (y < 0 || y > 255) {
+ printf("?Please enter a character code in range 0-255\n");
+ free(p);
+ p = NULL;
+ return(-9);
+ }
+ p[y] |= (zz == XYDBL) ? 2 : 1;
+ if (zz == XYDBL) dblflag = 1;
+ if (zz == XYIGN) ignflag = 1;
+ } /* End of while loop */
+
+ if ((x = cmcfm()) < 0) return(x);
+/*
+ Get here only if they have made no mistakes. Copy temporary table back to
+ permanent one, then free temporary table and return successfully.
+*/
+ if (p) {
+ for (i = 0; i < 256; i++) dblt[i] = p[i];
+ free(p);
+ p = NULL;
+ }
+ return(success = 1);
+ }
+#endif /* CKXXCHAR */
+
+#ifdef PIPESEND
+ case XYFLTR: { /* SET { SEND, RECEIVE } FILTER */
+ if ((y = cmtxt((xx == XYSEND) ?
+ "Filter program for sending files -\n\
+ use \\v(filename) to substitute filename" :
+ "Filter program for receiving files -\n\
+ use \\v(filename) to substitute filename",
+ "",&s,NULL)) < 0)
+ return(y);
+ if (!*s) { /* Removing a filter... */
+ if (xx == XYSEND && sndfilter) {
+ makestr(&g_sfilter,NULL);
+ makestr(&sndfilter,NULL);
+ } else if (rcvfilter) {
+ makestr(&g_rfilter,NULL);
+ makestr(&rcvfilter,NULL);
+ }
+ return(success = 1);
+ } /* Adding a filter... */
+ s = brstrip(s); /* Strip any braces */
+ y = strlen(s);
+ if (xx == XYSEND) { /* For SEND filter... */
+ for (x = 0; x < y; x++) { /* make sure they included "\v(...)" */
+ if (s[x] != '\\') continue;
+ if (s[x+1] == 'v') break;
+ }
+ if (x == y) {
+ printf(
+ "?Filter must contain a replacement variable for filename.\n"
+ );
+ return(-9);
+ }
+ }
+ if (xx == XYSEND) {
+ makestr(&sndfilter,s);
+ makestr(&g_sfilter,s);
+ } else {
+ makestr(&rcvfilter,s);
+ makestr(&g_rfilter,s);
+ }
+ return(success = 1);
+ }
+#endif /* PIPESEND */
+
+ case XYINIL:
+ y = cmnum("Max length for protocol init string","-1",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,-1)) < 0)
+ return(y);
+ if (xx == XYSEND)
+ sprmlen = z;
+ else
+ rprmlen = z;
+ return(success = 1);
+
+ case 993: {
+ extern int sendipkts;
+ if (xx == XYSEND) {
+ if ((x = seton(&sendipkts)) < 0)
+ return(x);
+ }
+ return(1);
+ }
+#ifdef CK_PERMS
+ case 994:
+ switch(xx) {
+ case XYSEND:
+ if ((x = seton(&atlpro)) < 0) return(x);
+ atgpro = atlpro;
+ return(1);
+ case XYRECV:
+ if ((x = seton(&atlpri)) < 0) return(x);
+ atgpri = atlpri;
+ return(1);
+ default:
+ return(-2);
+ }
+#endif /* CK_PERMS */
+
+#ifndef NOCSETS
+ case XYCSET: { /* CHARACTER-SET-SELECTION */
+ extern struct keytab xfrmtab[];
+ extern int r_cset, s_cset;
+ if ((y = cmkey(xfrmtab,2,"","automatic",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (xx == XYSEND)
+ s_cset = y;
+ else
+ r_cset = y;
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+ case XYBUP:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (xx == XYSEND) {
+ extern int skipbup;
+ skipbup = (y == 0) ? 1 : 0;
+ return(success = 1);
+ } else {
+ printf(
+"?Please use SET FILE COLLISION to choose the desired action\n");
+ return(-9);
+ }
+
+ case XYMOVE:
+#ifdef COMMENT
+ y = cmdir("Directory to move file(s) to after successful transfer",
+ "",&s,xxstring);
+#else
+ y = cmtxt("Directory to move file(s) to after successful transfer",
+ "",&s,xxstring);
+#endif /* COMMENT */
+
+ if (y < 0 && y != -3)
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+
+#ifdef COMMENT
+ /* Only needed for cmdir() */
+ if ((x = cmcfm()) < 0)
+ return(x);
+#endif /* COMMENT */
+
+ /* Check directory existence if absolute */
+ /* THIS MEANS IT CAN'T INCLUDE ANY DEFERRED VARIABLES! */
+ if (s) if (*s) {
+ if (isabsolute(s) && !isdir(s)) {
+ printf("?Directory does not exist - %s\n",s);
+ return(-9);
+ }
+ }
+ if (xx == XYSEND) {
+ if (*s) {
+#ifdef COMMENT
+ /* Allow it to be relative */
+ zfnqfp(s,LINBUFSIZ,line);
+#endif /* COMMENT */
+ makestr(&snd_move,line);
+ makestr(&g_snd_move,line);
+ } else {
+ makestr(&snd_move,NULL);
+ makestr(&g_snd_move,NULL);
+ }
+ } else {
+ if (*s) {
+#ifdef COMMENT
+ /* Allow it to be relative */
+ zfnqfp(s,LINBUFSIZ,line);
+#endif /* COMMENT */
+ makestr(&rcv_move,line);
+ makestr(&g_rcv_move,line);
+ } else {
+ makestr(&rcv_move,NULL);
+ makestr(&g_rcv_move,NULL);
+ }
+ }
+ return(success = 1);
+
+ case XYRENAME:
+ y = cmtxt("Template to rename file(s) to after successful transfer",
+ "",&s,NULL); /* NOTE: no xxstring */
+ if (y < 0 && y != -3) /* Evaluation is deferred */
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (xx == XYSEND) {
+ if (*s) {
+ makestr(&snd_rename,s);
+ makestr(&g_snd_rename,s);
+ } else {
+ makestr(&snd_rename,NULL);
+ makestr(&g_snd_rename,NULL);
+ }
+ } else {
+ if (*s) {
+ makestr(&rcv_rename,s);
+ makestr(&g_rcv_rename,s);
+ } else {
+ makestr(&rcv_rename,NULL);
+ makestr(&g_rcv_rename,NULL);
+ }
+ }
+ return(success = 1);
+
+#ifdef VMS
+ case 887: /* VERSION-NUMBERS */
+ if (xx == XYSEND) {
+ extern int vmssversions;
+ return(seton(&vmssversions));
+ } else {
+ extern int vmsrversions;
+ return(seton(&vmsrversions));
+ }
+#endif /* VMS */
+
+ default:
+ return(-2);
+ } /* End of SET SEND/RECEIVE... */
+}
+#endif /* NOXFER */
+
+#ifndef NOXMIT
+int
+setxmit() {
+ if ((y = cmkey(xmitab,nxmit,"","",xxstring)) < 0) return(y);
+ switch (y) {
+ case XMITE: /* EOF */
+ y = cmtxt("Characters to send at end of file,\n\
+ Use backslash codes for control characters","",&s,xxstring);
+ if (y < 0) return(y);
+ if ((int)strlen(s) > XMBUFL) {
+ printf("?Too many characters, %d maximum\n",XMBUFL);
+ return(-2);
+ }
+ ckstrncpy(xmitbuf,s,XMBUFL);
+ return(success = 1);
+
+ case XMITF: /* Fill */
+ y = cmnum("Numeric code for blank-line fill character","0",10,&x,
+ xxstring);
+ if ((y = setnum(&z,x,y,127)) < 0) return(y);
+ xmitf = z;
+ return(success = 1);
+ case XMITL: /* Linefeed */
+ return(seton(&xmitl));
+ case XMITS: /* Locking-Shift */
+ return(seton(&xmits));
+ case XMITP: /* Prompt */
+ y = cmnum("Numeric code for host's prompt character, 0 for none",
+ "10",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,127)) < 0) return(y);
+ xmitp = z;
+ return(success = 1);
+ case XMITX: /* Echo */
+ return(seton(&xmitx));
+ case XMITW: /* Pause */
+ y = cmnum("Number of milliseconds to pause between binary characters\n\
+or text lines during transmission","0",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,1000)) < 0) return(y);
+ xmitw = z;
+ return(success = 1);
+ case XMITT: /* Timeout */
+ y = cmnum("Seconds to wait for each character to echo",
+ "1",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,1000)) < 0) return(y);
+ xmitt = z;
+ return(success = 1);
+ default:
+ return(-2);
+ }
+}
+#endif /* NOXMIT */
+
+#ifndef NOXFER
+/* D O R M T -- Do a remote command */
+
+VOID
+rmsg() {
+ if (pflag && !quiet && fdispla != XYFD_N)
+ printf(
+#ifdef CK_NEED_SIG
+ " Type your escape character, %s, followed by X or E to cancel.\n",
+ dbchr(escape)
+#else
+ " Press the X or E key to cancel.\n"
+#endif /* CK_NEED_SIG */
+ );
+}
+
+static int xzcmd = 0; /* Global copy of REMOTE cmd index */
+
+/* R E M C F M -- Confirm a REMOTE command */
+/*
+ Like cmcfm(), but allows for a redirection indicator on the end,
+ like "> filename" or "| command". Returns what cmcfm() would have
+ returned: -1 if reparse needed, etc etc blah blah. On success,
+ returns 1 with:
+
+ char * remdest containing the name of the file or command.
+ int remfile set to 1 if there is to be any redirection.
+ int remappd set to 1 if output file is to be appended to.
+ int rempipe set to 1 if remdest is a command, 0 if it is a file.
+*/
+static int
+remcfm() {
+ int x;
+ char *s;
+ char c;
+
+ remfile = 0;
+ rempipe = 0;
+ remappd = 0;
+
+ if ((x = cmtxt(
+ "> filename, | command,\n\
+or type carriage return to confirm the command",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if (remdest) {
+ free(remdest);
+ remdest = NULL;
+ }
+ debug(F101,"remcfm local","",local);
+ debug(F110,"remcfm s",s,0);
+ debug(F101,"remcfm cmd","",xzcmd);
+/*
+ This check was added in C-Kermit 6.0 or 7.0 but it turns out to be
+ unhelpful in the situation where the remote is running a script that sends
+ REMOTE commands to the local workstation. What happens is, the local
+ server executes the command and sends the result back as screen text, which
+ is indicated by using an X packet instead of an F packet as the file
+ header. There are two parts to this: executing the command under control
+ of the remote Kermit, which is desirable (and in fact some big applications
+ depend on it, and therefore never installed any new C-Kermit versions after
+ 5A), and displaying the result. Commenting out the check allows the
+ command to be executed, but the result is still sent back to the remote in
+ a file transfer, where it vanishes into the ether. Actually it's on the
+ communication connection, mixed in with the packets. Pretty amazing that
+ the file transfer still works, right?
+*/
+#ifdef COMMENT
+ if (!*s) { /* No redirection indicator */
+ if (!local &&
+ (xzcmd == XZDIR || xzcmd == XZTYP ||
+ xzcmd == XZXIT || xzcmd == XZSPA ||
+ xzcmd == XZHLP || xzcmd == XZPWD ||
+ xzcmd == XZLGI || xzcmd == XZLGO ||
+ xzcmd == XZWHO || xzcmd == XZHOS)) {
+ printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
+ return(-9);
+ } else
+ return(1);
+ }
+#endif /* COMMENT */
+ c = *s; /* We have something */
+ if (c != '>' && c != '|') { /* Is it > or | ? */
+ printf("?Not confirmed\n"); /* No */
+ return(-9);
+ }
+ s++; /* See what follows */
+ if (c == '>' && *s == '>') { /* Allow for ">>" too */
+ s++;
+ remappd = 1; /* Append to output file */
+ }
+ while (*s == SP || *s == HT) s++; /* Strip intervening whitespace */
+ if (!*s) {
+ printf("?%s missing\n", c == '>' ? "Filename" : "Command");
+ return(-9);
+ }
+ if (c == '>' && zchko(s) < 0) { /* Check accessibility */
+ printf("?Access denied - %s\n", s);
+ return(-9);
+ }
+ remfile = 1; /* Set global results */
+ rempipe = (c == '|');
+ if (rempipe
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ ) {
+ printf("?Sorry, access to external commands is disabled.\n");
+ return(-9);
+ }
+ makestr(&remdest,s);
+#ifndef NODEBUG
+ if (deblog) {
+ debug(F101,"remcfm remfile","",remfile);
+ debug(F101,"remcfm remappd","",remappd);
+ debug(F101,"remcfm rempipe","",rempipe);
+ debug(F110,"remcfm remdest",remdest, 0);
+ }
+#endif /* NODEBUG */
+ return(1);
+}
+
+/* R E M T X T -- Like remcfm()... */
+/*
+ ... but for REMOTE commands that end with cmtxt().
+ Here we must decipher braces to discover whether the trailing
+ redirection indicator is intended for local use, or to be sent out
+ to the server, as in:
+
+ remote host blah blah > file This end
+ remote host { blah blah } > file This end
+ remote host { blah blah > file } That end
+ remote host { blah blah > file } > file Both ends
+
+ Pipes too:
+
+ remote host blah blah | cmd This end
+ remote host { blah blah } | cmd This end
+ remote host { blah blah | cmd } That end
+ remote host { blah blah | cmd } | cmd Both ends
+
+ Or both:
+
+ remote host blah blah | cmd > file This end, etc etc...
+
+ Note: this really only makes sense for REMOTE HOST, but why be picky?
+ Call after calling cmtxt(), with pointer to string that cmtxt() parsed,
+ as in "remtxt(&s);".
+
+ Returns:
+ 1 on success with braces & redirection things removed & pointer updated,
+ -9 on failure (bad indirection), after printing error message.
+*/
+int
+remtxt(p) char ** p; {
+ int i, x, bpos, ppos;
+ char c, *s, *q;
+
+ remfile = 0; /* Initialize global results */
+ rempipe = 0;
+ remappd = 0;
+ if (remdest) {
+ free(remdest);
+ remdest = NULL;
+ }
+ s = *p;
+ if (!s) /* No redirection indicator */
+ s = "";
+#ifdef COMMENT
+ if (!*s) { /* Ditto */
+ if (!local &&
+ (xzcmd == XZDIR || xzcmd == XZTYP ||
+ xzcmd == XZXIT || xzcmd == XZSPA ||
+ xzcmd == XZHLP || xzcmd == XZPWD ||
+ xzcmd == XZLGI || xzcmd == XZLGO ||
+ xzcmd == XZWHO || xzcmd == XZHOS)) {
+ printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
+ if (hints) {
+ printf("Hint: Try again with an output redirector.\n");
+ }
+ return(-9);
+ } else
+ return(1);
+ }
+#endif /* COMMENT */
+ bpos = -1; /* Position of > (bracket) */
+ ppos = -1; /* Position of | (pipe) */
+ x = strlen(s); /* Length of cmtxt() string */
+
+ for (i = x-1; i >= 0; i--) { /* Search right to left. */
+ c = s[i];
+ if (c == '}') /* Break on first right brace */
+ break; /* Don't look at contents of braces */
+ else if (c == '>') /* Record position of > */
+ bpos = i;
+ else if (c == '|') /* and of | */
+ ppos = i;
+ }
+ if (bpos < 0 && ppos < 0) { /* No redirectors. */
+#ifdef COMMENT
+ if (!local &&
+ (xzcmd == XZDIR || xzcmd == XZTYP ||
+ xzcmd == XZXIT || xzcmd == XZSPA ||
+ xzcmd == XZHLP || xzcmd == XZPWD ||
+ xzcmd == XZLGI || xzcmd == XZLGO ||
+ xzcmd == XZWHO || xzcmd == XZHOS)) {
+ printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
+ if (hints) {
+ printf("Hint: Try again with an output redirector.\n");
+ }
+ return(-9);
+ }
+#endif /* COMMENT */
+ s = brstrip(s); /* Remove outer braces if any. */
+ *p = s; /* Point to result */
+ return(1); /* and return. */
+ }
+ remfile = 1; /* It's | or > */
+ i = -1; /* Get leftmost symbol */
+ if (bpos > -1) /* Bracket */
+ i = bpos;
+ if (ppos > -1 && (ppos < bpos || bpos < 0)) { /* or pipe */
+ i = ppos;
+ rempipe = 1;
+ }
+ if (rempipe
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ ) {
+ printf("?Sorry, access to external commands is disabled.\n");
+ return(-9);
+ }
+ c = s[i]; /* Copy of symbol */
+
+ if (c == '>' && s[i+1] == '>') /* ">>" for append? */
+ remappd = 1; /* It's not just a flag it's a number */
+
+ q = s + i + 1 + remappd; /* Point past symbol in string */
+ while (*q == SP || *q == HT) q++; /* and any intervening whitespace */
+ if (!*q) {
+ printf("?%s missing\n", c == '>' ? "Filename" : "Command");
+ return(-9);
+ }
+ if (c == '>' && zchko(q) < 0) { /* (Doesn't work for | cmd > file) */
+ printf("?Access denied - %s\n", q);
+ return(-9);
+ }
+ makestr(&remdest,q); /* Create the destination string */
+ q = s + i - 1; /* Point before symbol */
+ while (q > s && (*q == SP || *q == HT)) /* Strip trailing whitespace */
+ q--;
+ *(q+1) = NUL; /* Terminate the string. */
+ s = brstrip(s); /* Remove any braces */
+ *p = s; /* Set return value */
+
+#ifndef NODEBUG
+ if (deblog) {
+ debug(F101,"remtxt remfile","",remfile);
+ debug(F101,"remtxt remappd","",remappd);
+ debug(F101,"remtxt rempipe","",rempipe);
+ debug(F110,"remtxt remdest",remdest, 0);
+ debug(F110,"remtxt command",s,0);
+ }
+#endif /* NODEBUG */
+
+ return(1);
+}
+
+int
+plogin(xx) int xx; {
+ char *p1 = NULL, *p2 = NULL, *p3 = NULL;
+ int psaved = 0, rc = 0;
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ debug(F101,"plogin local","",local);
+
+ if (!local || (network && ttchk() < 0)) {
+ printf("?No connection\n");
+ return(-9);
+ }
+ if ((x = cmfld("User ID","",&s,xxstring)) < 0) { /* Get User ID */
+ if (x != -3) return(x);
+ }
+ y = strlen(s);
+ if (y > 0) {
+ if ((p1 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ rc = -9;
+ goto XZXLGI;
+ } else
+ strcpy(p1,s); /* safe */
+ if ((rc = cmfld("Password","",&s,xxstring)) < 0)
+ if (rc != -3) goto XZXLGI;
+ y = strlen(s);
+ if (y > 0) {
+ if ((p2 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ rc = -9;
+ goto XZXLGI;
+ } else
+ strcpy(p2,s); /* safe */
+ if ((rc = cmfld("Account","",&s,xxstring)) < 0)
+ if (rc != -3) goto XZXLGI;
+ y = strlen(s);
+ if (y > 0) {
+ if ((p3 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ rc = -9;
+ goto XZXLGI;
+ } else
+ strcpy(p3,s); /* safe */
+ }
+ }
+ }
+ if ((rc = remtxt(&s)) < 0) /* Confirm & handle redirectors */
+ goto XZXLGI;
+
+ if (!p1) { /* No Userid specified... */
+ debok = 0; /* Don't log this */
+ /* Prompt for username, password, and account */
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ psaved = 1;
+ debug(F110,"REMOTE LOGIN saved",psave,0);
+
+ cmsetp("Username: "); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(1);
+ prompt(xxstring);
+ rc = -9;
+ for (x = -1; x < 0; ) { /* Prompt till they answer */
+ cmres(); /* Reset the parser */
+ x = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ }
+ y = strlen(s);
+ if (y < 1) {
+ printf("?Canceled\n");
+ goto XZXLGI;
+ }
+ if ((p1 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XZXLGI;
+ } else
+ strcpy(p1,s); /* safe */
+
+ cmsetp("Password: "); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(0); /* No echo */
+ prompt(xxstring);
+ debok = 0;
+ for (x = -1; x < 0 && x != -3; ) { /* Get answer */
+ cmres(); /* Reset the parser */
+ x = cmtxt("","",&s,NULL); /* Get literal line of text */
+ }
+ if ((p2 = malloc((int)strlen(s) + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XZXLGI;
+ } else
+ strcpy(p2,s); /* safe */
+ printf("\r\n");
+ if ((rc = cmcfm()) < 0)
+ goto XZXLGI;
+ }
+ sstate = setgen('I',p1,p2,p3); /* Get here with at least user ID */
+ rc = 0;
+
+ XZXLGI: /* Common exit point */
+ if (psaved)
+ cmsetp(psave); /* Restore original prompt */
+ if (p3) { free(p3); p3 = NULL; } /* Free malloc'd storage */
+ if (p2) { free(p2); p2 = NULL; }
+ if (p1) { free(p1); p1 = NULL; }
+ if (rc > -1) {
+ if (local && rc > -1) /* If local, flush tty input buffer */
+ ttflui();
+ }
+ return(rc);
+}
+
+#ifdef OS2
+#ifndef NOLOCAL
+int
+dormt(xx) int xx; {
+ int rc = 0;
+ extern int term_io;
+ int term_io_sav = term_io;
+#ifdef NEWFTP
+ extern int ftpget, ftpisopen();
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(doftprmt(xx,0));
+#endif /* NEWFTP */
+ term_io = 0;
+ rc = xxdormt(xx);
+ term_io = term_io_sav;
+ return rc;
+}
+
+
+int
+xxdormt(xx) int xx;
+#else /* NOLOCAL */
+int
+dormt(xx) int xx;
+#endif /* NOLOCAL */
+#else /* OS2 */
+int
+dormt(xx) int xx;
+#endif /* OS2 */
+{ /* REMOTE commands */
+ int x, y, retcode;
+ char *s, sbuf[50], *s2;
+
+#ifdef NEWFTP
+ extern int ftpget, ftpisopen();
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(doftprmt(xx,0));
+#endif /* NEWFTP */
+
+ remfile = 0; /* Clear these */
+ rempipe = 0;
+ remappd = 0;
+
+ if (xx < 0) return(xx); /* REMOTE what? */
+
+ xzcmd = xx; /* Make global copy of arg */
+
+ if (xx == XZSET) { /* REMOTE SET */
+ if ((y = cmkey(rmstab,nrms,"","",xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Parameter name required\n");
+ return(-9);
+ } else return(y);
+ }
+ return(doprm(y,1));
+ }
+
+ switch (xx) { /* Others... */
+
+ case XZCDU:
+ if ((x = cmcfm()) < 0) return(x);
+ printf("?Sorry, REMOTE CDUP not supported yet\n");
+ return(-9);
+
+ case XZCWD: /* CWD (CD) */
+ if ((x = cmtxt("Remote directory name","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ debug(F111,"XZCWD: ",s,x);
+ *sbuf = NUL;
+ s2 = sbuf;
+/*
+ The following is commented out because since the disappearance of the
+ DECSYSTEM-20 from the planet, no known computer requires a password for
+ changing directory.
+*/
+#ifdef DIRPWDPR
+ if (*s != NUL) { /* If directory name given, */
+ /* get password on separate line. */
+ if (tlevel > -1) { /* From take file... */
+
+ if (fgets(sbuf,50,tfile[tlevel]) == NULL)
+ fatal("take file ends prematurely in 'remote cwd'");
+ debug(F110," pswd from take file",s2,0);
+ for (x = (int)strlen(sbuf);
+ x > 0 && (sbuf[x-1] == NL || sbuf[x-1] == CR);
+ x--)
+ sbuf[x-1] = '\0';
+
+ } else { /* From terminal... */
+
+ printf(" Password: "); /* get a password */
+#ifdef IKSD
+ if (!local && inserver) {
+ x = coninc(0);
+ } else
+#endif /* IKSD */
+#ifdef OS2
+ x = is_a_tty(0) ? coninc(0) : /* with no echo ... */
+ getchar();
+#else /* OS2 */
+ x = getchar();
+#endif /* OS2 */
+ while ((x != NL) && (x != CR)) {
+ if ((x &= 0177) == '?') {
+ printf("? Password of remote directory\n Password: ");
+ s2 = sbuf;
+ *sbuf = NUL;
+ } else if (x == ESC) /* Mini command line editor... */
+ bleep(BP_WARN);
+ else if (x == BS || x == 0177)
+ s2--;
+ else if (x == 025) { /* Ctrl-U */
+ s2 = sbuf;
+ *sbuf = NUL;
+ } else
+ *s2++ = x;
+
+ /* Get the next character */
+#ifdef IKSD
+ if (!local && inserver) {
+ x = coninc(0);
+ } else
+#endif /* IKSD */
+#ifdef OS2
+ x = is_a_tty(0) ? coninc(0) : /* with no echo ... */
+ getchar();
+#else /* OS2 */
+ x = getchar();
+#endif /* OS2 */
+ }
+ *s2 = NUL;
+ putchar('\n');
+ }
+ s2 = sbuf;
+ } else s2 = "";
+#endif /* DIRPWDPR */
+
+ debug(F110," password",s2,0);
+ rcdactive = 1;
+ sstate = setgen('C',s,s2,"");
+ retcode = 0;
+ break;
+
+ case XZDEL: /* Delete */
+ if ((x = cmtxt("Name of remote file(s) to delete",
+ "",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file(s) required\n");
+ return(-9);
+ } else return(x);
+ }
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ retcode = sstate = rfilop(s,'E');
+ break;
+
+ case XZDIR: /* Directory */
+ if ((x = cmtxt("Remote directory or file specification","",&s,
+ xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ rmsg();
+ retcode = sstate = setgen('D',s,"","");
+ break;
+
+ case XZHLP: /* Help */
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('H',"","","");
+ retcode = 0;
+ break;
+
+ case XZHOS: /* Host */
+ if ((x = cmtxt("Command for remote system","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if ((y = (int)strlen(s)) < 1)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ cmarg = line;
+ rmsg();
+ retcode = sstate = 'c';
+ break;
+
+#ifndef NOFRILLS
+ case XZKER:
+ if ((x = cmtxt("Command for remote Kermit","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if ((int)strlen(s) < 1) {
+ if (x == -3) {
+ printf("?Remote Kermit command required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ cmarg = line;
+ retcode = sstate = 'k';
+ rmsg();
+ break;
+
+ case XZLGI: /* Login */
+ rcdactive = 1; /* Suppress "Logged in" msg if quiet */
+ return(plogin(XXREM));
+
+ case XZLGO: { /* Logout */
+ extern int bye_active;
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('I',"","","");
+ retcode = 0;
+ bye_active = 1; /* Close connection when done */
+ break;
+ }
+
+ case XZPRI: /* Print */
+ if (!atdiso || !atcapr) { /* Disposition attribute off? */
+ printf("?Disposition Attribute is Off\n");
+ return(-2);
+ }
+ cmarg = "";
+ cmarg2 = "";
+ if ((x = cmifi("Local file(s) to print on remote printer","",&s,&y,
+ xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of local file(s) required\n");
+ return(-9);
+ }
+ return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of filename */
+ *optbuf = NUL; /* Wipe out any old options */
+ if ((x = cmtxt("Options for remote print command","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if ((int)strlen(optbuf) > 94) { /* Make sure this is legal */
+ printf("?Option string too long\n");
+ return(-9);
+ }
+ ckstrncpy(optbuf,s,OPTBUFLEN); /* Make a safe copy of options */
+ nfils = -1; /* Expand file list internally */
+ cmarg = line; /* Point to file list. */
+ rprintf = 1; /* REMOTE PRINT modifier for SEND */
+ sstate = 's'; /* Set start state to SEND */
+ if (local) displa = 1;
+ retcode = 0;
+ break;
+#endif /* NOFRILLS */
+
+ case XZSPA: /* Space */
+ if ((x = cmtxt("Confirm, or remote directory name",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ retcode = sstate = setgen('U',s,"","");
+ break;
+
+ case XZMSG: /* Message */
+ if ((x = cmtxt("Short text message for server","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ retcode = sstate = setgen('M',s,"","");
+ break;
+
+#ifndef NOFRILLS
+ case XZTYP: /* Type */
+ if ((x = cmtxt("Remote file specification","",&s,xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) < 1) {
+ printf("?Remote filename required\n");
+ return(-9);
+ }
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ rmsg();
+ retcode = sstate = rfilop(s,'T');
+ break;
+#endif /* NOFRILLS */
+
+#ifndef NOFRILLS
+ case XZWHO:
+ if ((x = cmtxt("Remote user name, or carriage return",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ retcode = sstate = setgen('W',s,"","");
+ break;
+#endif /* NOFRILLS */
+
+ case XZPWD: /* PWD */
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('A',"","","");
+ retcode = 0;
+ break;
+
+#ifndef NOSPL
+ case XZQUE: { /* Query */
+ char buf[2];
+ extern char querybuf[], * qbufp;
+ extern int qbufn;
+ if ((y = cmkey(vartyp,nvartyp,"","",xxstring)) < 0)
+ return(y);
+ if ((x = cmtxt(y == 'F' ? "Remote function invocation" :
+ ('K' ? "Remote variable name or function":
+ "Remote variable name"),
+ "",
+ &s,
+ (y == 'K') ? xxstring : NULL
+ )) < 0) /* Don't evaluate */
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ query = 1; /* QUERY is active */
+ qbufp = querybuf; /* Initialize query response buffer */
+ qbufn = 0;
+ querybuf[0] = NUL;
+ buf[0] = (char) (y & 127);
+ buf[1] = NUL;
+ retcode = sstate = setgen('V',"Q",(char *)buf,s);
+ break;
+ }
+
+ case XZASG: { /* Assign */
+ char buf[VNAML];
+ if ((y = cmfld("Remote variable name","",&s,NULL)) < 0) /* No eval */
+ return(y);
+ if ((int)strlen(s) >= VNAML) {
+ printf("?Too long\n");
+ return(-9);
+ }
+ ckstrncpy(buf,s,VNAML);
+ if ((x = cmtxt("Assignment for remote variable",
+ "",&s,xxstring)) < 0) /* Evaluate this one */
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+#ifdef COMMENT
+/*
+ Server commands can't be long packets. In principle there's no reason
+ why they shouldn't be, except that we don't know at this point if the
+ server is capable of accepting long packets because we haven't started
+ the protocol yet. In practice, allowing a long packet here breaks a lot
+ of assumptions, causes buffer overruns and crashes, etc. To be fixed
+ later. (But since this is commented out, evidently I fixed it later...)
+*/
+ if ((int)strlen(s) > 85) { /* Allow for encoding expansion */
+ printf("?Sorry, value is too long - 85 characters max\n");
+ return(-9);
+ }
+#endif /* COMMENT */
+ retcode = sstate = setgen('V',"S",(char *)buf,s);
+ break;
+ }
+#endif /* NOSPL */
+
+ case XZCPY: { /* COPY */
+ char buf[TMPBUFSIZ];
+ buf[TMPBUFSIZ-1] = '\0';
+ if ((x = cmfld("Name of remote file to copy","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file required\n");
+ return(-9);
+ }
+ else
+ return(x);
+ }
+ ckstrncpy(buf,s,TMPBUFSIZ);
+ if ((x = cmfld("Name of remote destination file or directory",
+ "",&s, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file or directory required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = remcfm()) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ retcode = sstate = setgen('K',buf,tmpbuf,"");
+ break;
+ }
+ case XZREN: { /* Rename */
+ char buf[TMPBUFSIZ];
+ buf[TMPBUFSIZ-1] = '\0';
+ if ((x = cmfld("Name of remote file to rename",
+ "",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(buf,s,TMPBUFSIZ);
+ if ((x = cmfld("New name of remote file","",&s, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = remcfm()) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush device buffer */
+ retcode = sstate = setgen('R',buf,tmpbuf,"");
+ break;
+ }
+ case XZMKD: /* mkdir */
+ case XZRMD: /* rmdir */
+ if ((x = cmtxt((xx == XZMKD) ?
+ "Name of remote directory to create" :
+ "Name of remote directory to delete",
+ "",
+ &s,
+ xxstring
+ )) < 0) {
+ if (x == -3) {
+ printf("?Name required\n");
+ return(-9);
+ } else return(x);
+ }
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ retcode = sstate = rfilop(s, (char)(xx == XZMKD ? 'm' : 'd'));
+ break;
+
+ case XZXIT: /* Exit */
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('X',"","","");
+ retcode = 0;
+ break;
+
+ default:
+ if ((x = remcfm()) < 0) return(x);
+ printf("?Not implemented - %s\n",cmdbuf);
+ return(-2);
+ }
+ if (local && retcode > -1) /* If local, flush tty input buffer */
+ ttflui();
+ return(retcode);
+}
+
+
+/* R F I L O P -- Remote File Operation */
+
+CHAR
+#ifdef CK_ANSIC
+rfilop(char * s, char t)
+#else
+rfilop(s,t) char *s, t;
+#endif /* CK_ANSIC */
+/* rfilop */ {
+ if (*s == NUL) {
+ printf("?File specification required\n");
+ return((CHAR) 0);
+ }
+ debug(F111,"rfilop",s,t);
+ return(setgen(t,s,"",""));
+}
+#endif /* NOXFER */
+
+#ifdef ANYX25
+int
+setx25() {
+ if ((y = cmkey(x25tab,nx25,"X.25 call options","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case XYUDAT:
+ if ((z = cmkey(onoff,2,"X.25 call user data","",xxstring))
+ < 0) return(z);
+ if (z == 0) {
+ if ((z = cmcfm()) < 0) return(z);
+ cudata = 0; /* disable call user data */
+ return (success = 1);
+ }
+ if ((x = cmtxt("X.25 call user data string","",&s,xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) == 0) {
+ return (-3);
+ } else if ((int)strlen(s) > MAXCUDATA) {
+ printf("?The length must be > 0 and <= %d\n",MAXCUDATA);
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ ckstrncpy(udata,s,MAXCUDATA);
+ cudata = 1; /* X.25 call user data specified */
+ return (success = 1);
+ case XYCLOS:
+ if ((z = cmkey(onoff,2,"X.25 closed user group call","",xxstring))
+ < 0) return(z);
+ if (z == 0) {
+ if ((z = cmcfm()) < 0) return(z);
+ closgr = -1; /* disable closed user group */
+ return (success = 1);
+ }
+ if ((y = cmnum("0 <= cug index >= 99","",10,&x,xxstring)) < 0)
+ return(y);
+ if (x < 0 || x > 99) {
+ printf("?The choices are 0 <= cug index >= 99\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ closgr = x; /* closed user group selected */
+ return (success = 1);
+
+ case XYREVC:
+ if((z = cmkey(onoff,2,"X.25 reverse charge call","",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ revcall = z;
+ return (success = 1);
+ }
+}
+
+#ifndef IBMX25
+int
+setpadp() {
+ if ((y = cmkey(padx3tab,npadx3,"PAD X.3 parameter name","",xxstring)) < 0)
+ return(y);
+ x = y;
+ switch (x) {
+ case PAD_BREAK_CHARACTER:
+ if ((y = cmnum("PAD break character value","",10,&z,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_ESCAPE:
+ if ((y = cmnum("PAD escape","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_ECHO:
+ if ((y = cmnum("PAD echo","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_DATA_FORWARD_CHAR:
+ if ((y = cmnum("PAD data forward char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 0 && z != 2) {
+ printf("?The choices are 0 or 2\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_DATA_FORWARD_TIMEOUT:
+ if ((y = cmnum("PAD data forward timeout","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 255) {
+ printf("?The choices are 0 or 1 <= timeout <= 255\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_FLOW_CONTROL_BY_PAD:
+ if ((y = cmnum("PAD pad flow control","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_SUPPRESSION_OF_SIGNALS:
+ if ((y = cmnum("PAD service","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_BREAK_ACTION:
+ if ((y = cmnum("PAD break action","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1 && z != 2 && z != 5 && z != 8 && z != 21) {
+ printf("?The choices are 0, 1, 2, 5, 8 or 21\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_SUPPRESSION_OF_DATA:
+ if ((y = cmnum("PAD data delivery","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_PADDING_AFTER_CR:
+ if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 7) {
+ printf("?The choices are 0 or 1 <= crpad <= 7\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_LINE_FOLDING:
+ if ((y = cmnum("PAD linefold","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 255) {
+ printf("?The choices are 0 or 1 <= linefold <= 255\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_LINE_SPEED:
+ if ((y = cmnum("PAD baudrate","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 18) {
+ printf("?The choices are 0 <= baudrate <= 18\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_FLOW_CONTROL_BY_USER:
+ if ((y = cmnum("PAD terminal flow control","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_LF_AFTER_CR:
+ if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z == 3 || z > 7) {
+ printf("?The choices are 0, 1, 2, 4, 5, 6 or 7\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_PADDING_AFTER_LF:
+ if ((y = cmnum("PAD lfpad","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 7) {
+ printf("?The choices are 0 or 1 <= lfpad <= 7\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_EDITING:
+ if ((y = cmnum("PAD edit control","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_CHAR_DELETE_CHAR:
+ if ((y = cmnum("PAD char delete char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 127) {
+ printf("?The choices are 0 or 1 <= chardelete <= 127\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_BUFFER_DELETE_CHAR:
+ if ((y = cmnum("PAD buffer delete char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 127) {
+ printf("?The choices are 0 or 1 <= bufferdelete <= 127\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_BUFFER_DISPLAY_CHAR:
+ if ((y = cmnum("PAD display line char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 127) {
+ printf("?The choices are 0 or 1 <= displayline <= 127\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ }
+ padparms[x] = z;
+ return(success = 1);
+}
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOXFER
+int
+setat(rmsflg) int rmsflg; {
+ int xx;
+ if ((y = cmkey(attrtab,natr,"File Attribute packets","",xxstring)) < 0)
+ return(y);
+ if (y == AT_XALL) { /* ATTRIBUTES ALL ON or ALL OFF */
+ if ((z = seton(&xx)) < 0) return(z);
+ if (rmsflg) {
+ printf("Sorry, command not available\n");
+ return(-9);
+ } else {
+ atenci = xx; /* Encoding in */
+ atenco = xx; /* Encoding out */
+ atdati = xx; /* Date in */
+ atdato = xx; /* Date out */
+ atdisi = xx; /* Disposition in/out */
+ atdiso = xx;
+ atleni = xx; /* Length in/out (both kinds) */
+ atleno = xx;
+ atblki = xx; /* Blocksize in/out */
+ atblko = xx;
+ attypi = xx; /* File type in/out */
+ attypo = xx;
+ atsidi = xx; /* System ID in/out */
+ atsido = xx;
+ atsysi = xx; /* System-dependent params in/out */
+ atsyso = xx;
+#ifdef CK_PERMS /* Protection */
+ atlpri = xx; /* Local in */
+ atlpro = xx; /* Local out */
+ atgpri = xx; /* Generic in */
+ atgpro = xx; /* Generic out */
+#endif /* CK_PERMS */
+#ifdef STRATUS
+ atfrmi = xx; /* Format in/out */
+ atfrmo = xx;
+ atcrei = xx; /* Creator id in/out */
+ atcreo = xx;
+ atacti = xx; /* Account in/out */
+ atacto = xx;
+#endif /* STRATUS */
+ }
+ return(z);
+ } else if (y == AT_ALLY || y == AT_ALLN) { /* ATTRIBUTES ON or OFF */
+ if ((x = cmcfm()) < 0) return(x);
+ atcapr = (y == AT_ALLY) ? 1 : 0;
+ if (rmsflg) {
+ sstate = setgen('S', "132", atcapr ? "1" : "0", "");
+ return((int) sstate);
+ } else return(success = 1);
+ }
+ /* Otherwise, it's an individual attribute that wants turning off/on */
+
+ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+
+/* There are better ways to do this... */
+/* The real problem is that we're not separating the in and out cases */
+/* and so we have to arbitrarily pick the "in" case, i.e tell the remote */
+/* server to ignore incoming attributes of the specified type, rather */
+/* than telling it not to send them. The protocol does not (yet) define */
+/* codes for "in-and-out-at-the-same-time". */
+
+ switch (y) {
+#ifdef CK_PERMS
+/* We're lumping local and generic protection together for now... */
+ case AT_LPRO:
+ case AT_GPRO:
+ if (rmsflg) {
+ sstate = setgen('S', "143", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atlpri = atlpro = atgpri = atgpro = z; break;
+#endif /* CK_PERMS */
+ case AT_DISP:
+ if (rmsflg) {
+ sstate = setgen('S', "142", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atdisi = atdiso = z; break;
+ case AT_ENCO:
+ if (rmsflg) {
+ sstate = setgen('S', "141", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atenci = atenco = z; break;
+ case AT_DATE:
+ if (rmsflg) {
+ sstate = setgen('S', "135", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atdati = atdato = z; break;
+ case AT_LENB:
+ case AT_LENK:
+ if (rmsflg) {
+ sstate = setgen('S', "133", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atleni = atleno = z; break;
+ case AT_BLKS:
+ if (rmsflg) {
+ sstate = setgen('S', "139", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atblki = atblko = z; break;
+ case AT_FTYP:
+ if (rmsflg) {
+ sstate = setgen('S', "134", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ attypi = attypo = z; break;
+#ifdef STRATUS
+ case AT_CREA:
+ if (rmsflg) {
+ sstate = setgen('S', "136", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atcrei = atcreo = z; break;
+ case AT_ACCT:
+ if (rmsflg) {
+ sstate = setgen('S', "137", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atacti = atacto = z; break;
+#endif /* STRATUS */
+ case AT_SYSI:
+ if (rmsflg) {
+ sstate = setgen('S', "145", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atsidi = atsido = z; break;
+ case AT_RECF:
+ if (rmsflg) {
+ sstate = setgen('S', "146", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atfrmi = atfrmo = z; break;
+ case AT_SYSP:
+ if (rmsflg) {
+ sstate = setgen('S', "147", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atsysi = atsyso = z; break;
+ default:
+ printf("?Not available\n");
+ return(-2);
+ }
+ return(1);
+}
+#endif /* NOXFER */
+
+#ifndef NOSPL
+int
+setinp() {
+ if ((y = cmkey(inptab,ninp,"","",xxstring)) < 0) return(y);
+ switch (y) {
+#ifdef OS2
+ case IN_PAC: /* SET INPUT PACING */
+ z = cmnum("milliseconds","0",10,&x,xxstring);
+ return(setnum(&tt_inpacing,x,z,1000));
+ case IN_TRM: /* SET INPUT TERMINAL */
+ return(seton(&interm));
+#endif /* OS2 */
+ case IN_DEF: /* SET INPUT DEFAULT-TIMEOUT */
+ z = cmnum("Positive number","",10,&x,xxstring);
+ return(setnum(&indef,x,z,94));
+#ifdef CKFLOAT
+ case IN_SCA: /* SET INPUT SCALE-FACTOR */
+ if ((x = cmfld("Number such as 2 or 0.5","1.0",&s, xxstring)) < 0)
+ return(x);
+ if (isfloat(s,0)) { /* A floating-point number? */
+ extern char * inpscale;
+ inscale = floatval; /* Yes, get its value */
+ makestr(&inpscale,s); /* Save it as \v(inscale) */
+ return(success = 1);
+ } else {
+ return(-2);
+ }
+#endif /* CKFLOAT */
+ case IN_TIM: /* SET INPUT TIMEOUT-ACTION */
+ if ((z = cmkey(intimt,2,"","",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ intime[cmdlvl] = z;
+ return(success = 1);
+ case IN_CAS: /* SET INPUT CASE */
+ if ((z = cmkey(incast,2,"","",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ inpcas[cmdlvl] = z;
+ return(success = 1);
+ case IN_ECH: /* SET INPUT ECHO */
+ return(seton(&inecho));
+ case IN_SIL: /* SET INPUT SILENCE */
+ z = cmnum("Seconds of inactivity before INPUT fails","",10,&x,
+ xxstring);
+ return(setnum(&insilence,x,z,-1));
+
+ case IN_BUF: /* SET INPUT BUFFER-SIZE */
+ if ((z = cmnum("Number of bytes in INPUT buffer",
+ ckitoa(INPBUFSIZ),10,&x, xxstring)) < 0)
+ return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ inbufsize = 0;
+ if (inpbuf) {
+ free(inpbuf);
+ inpbuf = NULL;
+ inpbp = NULL;
+ }
+ if (!(s = (char *)malloc(x + 1)))
+ return(0);
+ inpbuf = s;
+ inpbp = s;
+ inbufsize = x;
+ for (x = 0; x <= inbufsize; x++)
+ inpbuf[x] = NUL;
+ return(success = 1);
+
+#ifdef CK_AUTODL
+ case IN_ADL: /* AUTODOWNLOAD */
+ return(seton(&inautodl));
+#endif /* CK_AUTODL */
+
+ case IN_CAN: /* SET INPUT INTERRUPTS */
+ return(seton(&inintr));
+ }
+ return(0);
+}
+#endif /* NOSPL */
+
+#ifdef NETCONN
+VOID
+ndreset() {
+#ifndef NODIAL /* This depends on DIAL... */
+ int i=0, j=0;
+ if (!ndinited) /* Don't free garbage... */
+ return;
+ for (i = 0; i < nhcount; i++) { /* Clean out previous list */
+ if (nh_p[i])
+ free(nh_p[i]);
+ nh_p[i] = NULL;
+ if (nh_p2[i])
+ free(nh_p2[i]);
+ nh_p2[i] = NULL;
+ for (j = 0; j < 4; j++) {
+ if (nh_px[j][i])
+ free(nh_px[j][i]);
+ nh_px[j][i] = NULL;
+ }
+ }
+#endif /* NODIAL */
+}
+
+VOID
+ndinit() { /* Net directory pointers */
+#ifndef NODIAL /* This depends on DIAL... */
+ int i, j;
+ if (ndinited++) /* Don't do this more than once. */
+ return;
+ for (i = 0; i < MAXDDIR; i++) { /* Init all pointers to NULL */
+ netdir[i] = NULL;
+ }
+ for (i = 0; i < MAXDNUMS; i++) {
+ nh_p[i] = NULL;
+ nh_p2[i] = NULL;
+ for (j = 0; j < 4; j++)
+ nh_px[j][i] = NULL;
+ }
+#endif /* NODIAL */
+}
+
+#ifndef NODIAL
+#ifdef NETCONN
+VOID /* Get net defaults from environment */
+getnetenv() {
+ char *p = NULL;
+
+ makestr(&p,getenv("K_NET_DIRECTORY")); /* Dialing directories */
+ if (p) {
+ int i;
+ xwords(p,MAXDDIR,netdir,0);
+ for (i = 0; i < MAXDDIR; i++) { /* Fill in any gaps... */
+ if (!netdir[i+1])
+ break;
+ else
+ netdir[i] = netdir[i+1];
+ debug(F111,"netdir[i]",netdir[i],i);
+ }
+ nnetdir = i;
+ }
+}
+#endif /* NETCONN */
+#endif /* NODIAL */
+
+int
+#ifdef CK_ANSIC
+lunet(char *s) /* s = name to look up */
+#else
+lunet(s) char *s;
+#endif /* CK_ANSIC */
+/* lunet */ {
+#ifndef NODIAL /* This depends on DIAL... */
+ int n, n1, t, dd = 0;
+ int ambiguous = 0;
+ FILE * f;
+ char *line = NULL;
+ extern int dialdpy;
+ int netdpy = dialdpy;
+ char *info[8];
+
+ nhcount = 0; /* Set this before returning */
+
+ if (!s || nnetdir < 1) /* Validate arguments */
+ return(-1);
+
+ if (isdigit(*s) || *s == '*' || *s == '.')
+ return(0);
+
+ if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */
+ return(-1);
+
+ if (!(line = malloc(1024))) /* Allocate input buffer */
+ return(-1);
+
+ lu_again:
+ f = NULL; /* Network directory file descriptor */
+ t = nhcount = 0; /* Match count */
+ dd = 0; /* Directory counter */
+
+ dirline = 0;
+ while (1) { /* We make one pass */
+ if (!f) { /* Directory not open */
+ if (dd >= nnetdir) /* No directories left? */
+ break; /* Done. */
+ if ((f = fopen(netdir[dd],"r")) == NULL) { /* Open it */
+ perror(netdir[dd]); /* Can't, print message saying why */
+ dd++;
+ continue; /* But go on to next one. */
+ }
+ if (netdpy)
+ printf("Opening %s...\n",netdir[dd]);
+ dd++;
+ }
+ line[0] = NUL;
+ if (getnct(line,1023,f,1) < 0) { /* Read a line */
+ if (f) { /* f can be clobbered! */
+ fclose(f); /* Close the file */
+ f = NULL; /* Indicate next one needs opening */
+ }
+ continue;
+ }
+ if (!line[0]) /* Empty line */
+ continue;
+
+ xwords(line,7,info,0); /* Parse it */
+
+ if (!info[1] || !info[2] || !info[3]) /* Required fields */
+ continue;
+ if (*info[1] == ';') /* Full-line comment */
+ continue;
+ if ((n = (int) strlen(info[1])) < 1) /* Length of name-tag */
+ continue;
+ if (n < n1) /* Search name is longer */
+ continue; /* Can't possibly match */
+ if (ambiguous && n != n1)
+ continue;
+ if (ckstrcmp(s,info[1],n1,0)) /* Compare using length of */
+ continue; /* search string s. */
+
+ /* Have a match */
+
+ makestr(&(nh_p[nhcount]), info[3]); /* address */
+ makestr(&(nh_p2[nhcount]),info[2]); /* net type */
+ makestr(&(nh_px[0][nhcount]),info[4]); /* net-specific stuff... */
+ makestr(&(nh_px[1][nhcount]),info[5]);
+ makestr(&(nh_px[2][nhcount]),info[6]);
+ makestr(&(nh_px[3][nhcount]),info[7]);
+
+ nhcount++; /* Count this match */
+ if (nhcount > MAXDNUMS) { /* Watch out for too many */
+ printf("Warning: %d matches found, %d max\n",
+ nhcount,
+ MAXDNUMS
+ );
+ nhcount = MAXDNUMS;
+ break;
+ }
+ if (nhcount == 1) { /* First one - save entry name */
+ if (n_name) { /* Free the one from before if any */
+ free(n_name);
+ n_name = NULL;
+ }
+ if (!(n_name = (char *)malloc(n + 1))) { /* Allocate new storage */
+ printf("?memory allocation error - lunet:3\n");
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ nhcount = 0;
+ return(-1);
+ }
+ t = n; /* Remember its length */
+ strcpy(n_name,info[1]); /* safe */
+ } else { /* Second or subsequent one */
+ if ((int) strlen(info[1]) == t) /* Lengths compare */
+ if (!ckstrcmp(n_name,info[1],t,0)) /* Caseless compare OK */
+ continue;
+
+ /* Name given by user matches entries with different names */
+
+ if (ambiguous) /* Been here before */
+ break;
+
+ ambiguous = 1; /* Now an exact match is required */
+ ndreset(); /* Clear out previous list */
+ goto lu_again; /* Do it all over again. */
+ }
+ }
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ if (nhcount == 0 && ambiguous)
+ printf("?\"%s\" - ambiguous in network directory\n",s);
+#else
+ nhcount = 0;
+#endif /* NODIAL */
+ return(nhcount);
+}
+#endif /* NETCONN */
+
+#ifndef NOLOCAL
+/* C L S C O N N X -- Close connection */
+
+int
+clsconnx(ask) int ask; {
+ int x, rc = 0;
+#ifdef NEWFTP
+ extern int ftpget, ftpisopen();
+ if ((ftpget == 1) || ((ftpget == 2) && !local && ftpisopen()))
+ return(success = ftpbye());
+#endif /* NEWFTP */
+ debug(F101,"clsconnx local","",local);
+ if (local) {
+ x = ask ? hupok(1) : 1; /* Make sure it's OK to close */
+ if (!x) {
+ rc = -1;
+ debug(F101,"clsconnx hupok says no","",rc);
+ return(rc);
+ }
+ ttflui(); /* Clear away buffered up junk */
+#ifndef NODIAL
+#ifdef OS2ONLY
+/* Don't hangup a line that is shared with the SLIP or PPP driver */
+ if (!ttslip && !ttppp)
+#endif /* OS2ONLY */
+ mdmhup();
+#endif /* NODIAL */
+ if (network && msgflg)
+ printf(" Closing connection\n");
+ ttclos(0); /* Close old connection, if any */
+ rc = 1;
+ {
+ extern int wasclosed, whyclosed;
+ if (wasclosed) {
+ whyclosed = WC_CLOS;
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ /* printf("ON_CLOSE CLSCONNX\n"); */
+ wasclosed = 0;
+ k = mlook(mactab,"on_close",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ whyclosed = WC_REMO;
+ wasclosed = 0;
+ }
+ }
+ }
+#ifdef VMS /* Or maybe #ifndef UNIX? */
+ else { /* Need to do this in VMS to */
+ ttclos(0); /* free the tty channel number */
+ rc = 1; /* obtained in ttopen() or else */
+ } /* subsequent ttopen's won't work */
+#endif /* VMS */
+ dologend();
+ haveline = 0;
+ if (mdmtyp < 0) { /* Switching from net to async? */
+ if (mdmsav > -1) /* Restore modem type from last */
+ mdmtyp = mdmsav; /* SET MODEM command, if any. */
+ else
+ mdmtyp = 0;
+ mdmsav = -1;
+ }
+ if (network)
+ network = 0;
+#ifdef NETCONN
+ if (oldplex > -1) { /* Restore previous duplex setting. */
+ duplex = oldplex;
+ oldplex = -1;
+ }
+#endif /* NETCONN */
+#ifndef MAC
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default communication */
+#endif /* MAC */
+ local = dfloc; /* device and local/remote status */
+ if (local) {
+ cxtype = CXT_DIRECT; /* Something reasonable */
+ speed = ttgspd(); /* Get the current speed */
+ } else {
+ cxtype = CXT_REMOTE;
+ speed = -1L;
+ }
+#ifndef NOXFER
+ if (xreliable > -1 && !setreliable) {
+ reliable = xreliable;
+ debug(F101,"clsconnx reliable A","",reliable);
+ } else if (!setreliable) {
+ reliable = SET_AUTO;
+ debug(F101,"clsconnx reliable B","",reliable);
+ }
+#endif /* NOXFER */
+ setflow(); /* Revert flow control */
+ return(rc);
+}
+
+int
+clskconnx(x) int x; { /* Close Kermit connection only */
+ int t, rc; /* (not FTP) */
+#ifdef NEWFTP
+ extern int ftpget;
+ t = ftpget;
+ ftpget = 0;
+#endif /* NEWFTP */
+ rc = clsconnx(x);
+#ifdef NEWFTP
+ ftpget = t;
+#endif /* NEWFTP */
+ return(rc);
+}
+
+/* May 2002: setlin() decomposition starts here ... */
+
+#ifdef OS2
+#define SRVBUFSIZ PIPENAML
+#else /* OS2 */
+#define SRVBUFSIZ 63
+#endif /* OS2 */
+#define HOSTNAMLEN 15*65
+
+int netsave = -1;
+static char * tmpstring = NULL;
+static char * tmpusrid = NULL;
+
+#ifdef SSHCMD
+char * sshcmd = NULL;
+char * defsshcmd = "ssh -e none";
+#else
+#ifdef SSHBUILTIN
+char * sshrcmd = NULL;
+char * sshtmpcmd = NULL;
+#endif /* SSHBUILTIN */
+#endif /* SSHCMD */
+
+/* c x _ f a i l -- Common error exit routine for cx_net, cx_line */
+
+int
+cx_fail(msg, text) int msg; char * text; {
+ makestr(&slmsg,text); /* For the record (or GUI) */
+ if (msg) /* Not GUI, not quiet, etc */
+ printf("?%s\n",text); /* Print error message */
+ slrestor(); /* Restore LINE/HOST to known state */
+ return(msg ? -9 : (success = 0)); /* Return appropriate code */
+}
+
+#ifdef NETCONN
+/* c x _ n e t -- Make a network connection */
+
+/*
+ Call with:
+ net = network type
+ protocol = protocol type
+ host = string pointer to host name.
+ svc = string pointer to service or port on host.
+ username = username for connection
+ password = password for connection
+ command = command to execute
+ param1 = Telnet: Authentication type
+ SSH: Version
+ param2 = Telnet: Encryption type
+ SSH: Command as Subsystem
+ param3 = Telnet: 1 to wait for negotiations, 0 otherwise
+ SSH: X11 Forwarding
+ cx = 1 to automatically enter Connect mode, 0 otherwise.
+ sx = 1 to automatically enter Server mode, 0 otherwise.
+ flag = if no host name given, 1 = close current connection, 0 = resume
+ gui = 1 if called from GUI dialog, 0 otherwise.
+ Returns:
+ 1 on success
+ 0 on failure and no message printed, slmsg set to failure message.
+ -9 on failure and message printed, ditto.
+*/
+int
+#ifdef CK_ANSIC
+cx_net( int net, int protocol, char * xhost, char * svc,
+ char * username, char * password, char * command,
+ int param1, int param2, int param3, int cx, int sx, int flag, int gui)
+#else /* CK_ANSIC */
+cx_net(net, protocol, xhost, svc,
+ username, password, command,
+ param1, param2, param3, cx, sx, flag, gui)
+ char * xhost, * svc, * username, *password, *command;
+ int net, protocol, cx, sx, flag, param1, param2, param3, gui;
+#endif /* CK_ANSIC */
+/* cx_net */ {
+
+ int i, n, x, msg;
+ int _local = -1;
+
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+
+ char srvbuf[SRVBUFSIZ+1]; /* Service */
+ char hostbuf[HOSTNAMLEN]; /* Host buffer to manipulate */
+ char hostname[HOSTNAMLEN]; /* Copy of host parameter */
+ char * host = hostbuf; /* Pointer to copy of host param */
+
+ if (!xhost) xhost = ""; /* Watch out for null pointers */
+ if (!svc) svc = "";
+ ckstrncpy(host,xhost,HOSTNAMLEN); /* Avoid buffer confusion */
+
+ debug(F110,"cx_net host",host,0);
+ debug(F111,"cx_net service",svc,SRVBUFSIZ);
+ debug(F101,"cx_net network type","",net);
+
+ msg = (gui == 0) && msgflg; /* Whether to print messages */
+
+#ifndef NODIAL
+ debug(F101,"cx_net nnetdir","",nnetdir);
+ x = 0; /* Look up in network directory */
+ if (*host == '=') { /* If number starts with = sign */
+ host++; /* strip it */
+ while (*host == SP) host++; /* and any leading spaces */
+ debug(F110,"cx_net host 2",host,0);
+ nhcount = 0;
+ } else if (*host) { /* We want to look it up. */
+ if (nnetdir > 0) /* If there is a directory... */
+ x = lunet(host); /* (sets nhcount) */
+ else /* otherwise */
+ nhcount = 0; /* we didn't find any there */
+ if (x < 0) /* Internal error? */
+ return(cx_fail(msg,"Network directory lookup error"));
+ debug(F111,"cx_net lunet nhcount",host,nhcount);
+ }
+#endif /* NODIAL */
+
+ /* New connection wanted. Make a copy of the host name/address... */
+
+ if (clskconnx(1) < 0) /* Close current Kermit connection */
+ return(cx_fail(msg,"Error closing previous connection"));
+
+ if (*host) { /* They gave a hostname */
+ _local = 1; /* Network connection always local */
+ if (mdmsav < 0)
+ mdmsav = mdmtyp; /* Remember old modem type */
+ mdmtyp = -net; /* Special code for network */
+ } else { /* They just said "set host" */
+ host = dftty; /* So go back to normal */
+ _local = dfloc; /* default tty, location, */
+ if (flag) { /* Close current connection */
+ setflow(); /* Maybe change flow control */
+ haveline = 1; /* (* is this right? *) */
+ dologend();
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ /* XXX - Is this right? */
+ /* Should we be returning without doing anything ? */
+ /* Yes it's right -- we closed the old connection just above. */
+ return(success = 1);
+ }
+ }
+ success = 0;
+ if (host != line) /* line[] is a global */
+ ckstrncpy(line,host,LINBUFSIZ);
+ ckstrncpy(hostname,host,HOSTNAMLEN);
+ ckstrncpy(srvbuf,svc,SRVBUFSIZ+1);
+
+#ifndef NODIAL
+ if ((nhcount > 1) && msg) {
+ int k;
+ printf("%d entr%s found for \"%s\"%s\n",
+ nhcount,
+ (nhcount == 1) ? "y" : "ies",
+ s,
+ (nhcount > 0) ? ":" : "."
+ );
+ for (i = 0; i < nhcount; i++) {
+ printf("%3d. %-12s => %-9s %s",
+ i+1,n_name,nh_p2[i],nh_p[i]);
+ for (k = 0; k < 4; k++) { /* Also list net-specific items */
+ if (nh_px[k][i]) /* free format... */
+ printf(" %s",nh_px[k][i]);
+ else
+ break;
+ }
+ printf("\n");
+ }
+ }
+ if (nhcount == 0)
+ n = 1;
+ else
+ n = nhcount;
+#else
+ n = 1;
+ nhcount = 0;
+#endif /* NODIAL */
+
+ for (i = 0; i < n; i++) { /* Loop for each entry found */
+ debug(F101,"cx_net loop i","",i);
+#ifndef NODIAL
+ if (nhcount > 0) { /* If we found at least one entry... */
+ ckstrncpy(line,nh_p[i],LINBUFSIZ); /* Copy current entry */
+ if (lookup(netcmd,nh_p2[i],nnets,&x) > -1) { /* Net type */
+ int xx;
+ xx = netcmd[x].kwval;
+ /* User specified SSH so don't let net directory override */
+ if (net != NET_SSH || xx != NET_TCPB) {
+ net = xx;
+ mdmtyp = 0 - net;
+ }
+ } else {
+ makestr(&slmsg,"Network type not supported");
+ if (msg)
+ printf("Error - network type \"%s\" not supported\n",
+ nh_p2[i]
+ );
+ continue;
+ }
+ switch (net) { /* Net-specific directory things */
+#ifdef SSHBUILTIN
+ case NET_SSH: /* SSH */
+ /* Any SSH specific network directory stuff? */
+ break; /* NET_SSH */
+#endif /* SSHBUILTIN */
+
+ case NET_TCPB: { /* TCP/IP TELNET,RLOGIN,... */
+#ifdef TCPSOCKET
+ char *q;
+ int flag = 0;
+
+ /* Extract ":service", if any, from host string */
+ debug(F110,"cx_net service 1",line,0);
+ for (q = line; (*q != '\0') && (*q != ':'); q++)
+ ;
+ if (*q == ':') { *q++ = NUL; flag = 1; }
+ debug(F111,"cx_net service 2",line,flag);
+
+ /* Get service, if any, from directory entry */
+
+ if (!*srvbuf) {
+ if (nh_px[0][i]) {
+ ckstrncpy(srvbuf,nh_px[0][i],SRVBUFSIZ);
+ debug(F110,"cx_net service 3",srvbuf,0);
+ }
+ if (flag) {
+ ckstrncpy(srvbuf,q,SRVBUFSIZ);
+ debug(F110,"cx_net service 4",srvbuf,0);
+ }
+ }
+ ckstrncpy(hostname,line,HOSTNAMLEN);
+
+ /* If we have a service, append to host name/address */
+ if (*srvbuf) {
+ ckstrncat(line, ":", LINBUFSIZ);
+ ckstrncat(line, srvbuf, LINBUFSIZ);
+ debug(F110,"cx_net service 5",line,0);
+ }
+#ifdef RLOGCODE
+ /* If no service given but command was RLOGIN */
+ else if (ttnproto == NP_RLOGIN) { /* add this... */
+ ckstrncat(line, ":login",LINBUFSIZ);
+ debug(F110,"cx_net service 6",line,0);
+ }
+#ifdef CK_AUTHENTICATION
+#ifdef CK_KERBEROS
+ else if (ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_K5LOGIN) { /* add this... */
+ ckstrncat(line, ":klogin",LINBUFSIZ);
+ debug(F110,"cx_net service 7",line,0);
+ }
+ else if (ttnproto == NP_EK4LOGIN ||
+ ttnproto == NP_EK5LOGIN) { /* add this... */
+ ckstrncat(line, ":eklogin",LINBUFSIZ);
+ debug(F110,"cx_net service 8",line,0);
+ }
+#endif /* CK_KERBEROS */
+#endif /* CK_AUTHENTICATION */
+#endif /* RLOGCODE */
+ else { /* Otherwise, add ":telnet". */
+ ckstrncat(line, ":telnet", LINBUFSIZ);
+ debug(F110,"cx_net service 9",line,0);
+ }
+ if (username) { /* This is a parameter... */
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+ uidflag = 1;
+ }
+ /* Fifth field, if any, is user ID (for rlogin) */
+
+ if (nh_px[1][i] && !uidflag)
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+#ifdef RLOGCODE
+ if (IS_RLOGIN() && !uidbuf[0])
+ return(cx_fail(msg,"Username required"));
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+ break;
+ }
+ case NET_PIPE: /* Pipe */
+#ifdef NPIPE
+ if (!pipename[0]) { /* User didn't give a pipename */
+ if (nh_px[0][i]) { /* But directory entry has one */
+ if (strcmp(pipename,"\\pipe\\")) {
+ ckstrncpy(pipename,"\\pipe\\",LINBUFSIZ);
+ ckstrncat(srvbuf,nh_px[0][i],PIPENAML-6);
+ } else {
+ ckstrncpy(pipename,nh_px[0][i],PIPENAML);
+ }
+ debug(F110,"cx_net pipeneme",pipename,0);
+ }
+ }
+#endif /* NPIPE */
+ break;
+
+ case NET_SLAT: /* LAT / CTERM */
+#ifdef SUPERLAT
+ if (!slat_pwd[0]) { /* User didn't give a password */
+ if (nh_px[0][i]) { /* But directory entry has one */
+ ckstrncpy(slat_pwd,nh_px[0][i],18);
+ debug(F110,"cx_net SuperLAT password",slat_pwd,0);
+ }
+ }
+#endif /* SUPERLAT */
+ break;
+
+ case NET_SX25: /* X.25 keyword parameters */
+ case NET_IX25:
+ case NET_VX25: {
+#ifdef ANYX25
+ int k; /* Cycle through the four fields */
+ for (k = 0; k < 4; k++) {
+ if (!nh_px[k][i]) /* Bail out if none left */
+ break;
+ if (!ckstrcmp(nh_px[k][i],"cug=",4,0)) {
+ closgr = atoi(nh_px[k][i]+4);
+ debug(F101,"X25 CUG","",closgr);
+ } else if (!ckstrcmp(nh_px[k][i],"cud=",4,0)) {
+ cudata = 1;
+ ckstrncpy(udata,nh_px[k][i]+4,MAXCUDATA);
+ debug(F110,"X25 CUD",cudata,0);
+ } else if (!ckstrcmp(nh_px[k][i],"rev=",4,0)) {
+ revcall = !ckstrcmp(nh_px[k][i]+4,"=on",3,0);
+ debug(F101,"X25 REV","",revcall);
+#ifndef IBMX25
+ } else if (!ckstrcmp(nh_px[k][i],"pad=",4,0)) {
+ int x3par, x3val;
+ char *s1, *s2;
+ s1 = s2 = nh_px[k][i]+4; /* PAD parameters */
+ while (*s2) { /* Pick them apart */
+ if (*s2 == ':') {
+ *s2 = NUL;
+ x3par = atoi(s1);
+ s1 = ++s2;
+ continue;
+ } else if (*s2 == ',') {
+ *s2 = NUL;
+ x3val = atoi(s1);
+ s1 = ++s2;
+ debug(F111,"X25 PAD",x3par,x3val);
+ if (x3par > -1 &&
+ x3par <= MAXPADPARMS)
+ padparms[x3par] = x3val;
+ continue;
+ } else
+ s2++;
+ }
+#endif /* IBMX25 */
+ }
+ }
+#endif /* ANYX25 */
+ break;
+ }
+ default: /* Nothing special for other nets */
+ break;
+ }
+ } else
+#endif /* NODIAL */
+ { /* No directory entries found. */
+ ckstrncpy(line,hostname,LINBUFSIZ); /* Put this back... */
+ /* If the user gave a TCP service */
+ if (net == NET_TCPB || net == NET_SSH)
+ if (*srvbuf) { /* Append it to host name/address */
+ ckstrncat(line, ":", LINBUFSIZ);
+ ckstrncat(line, srvbuf,LINBUFSIZ);
+ }
+ }
+ /*
+ Get here with host name/address and all net-specific
+ parameters set, ready to open the connection.
+ */
+ mdmtyp = -net; /* This should have been done */
+ /* already but just in case ... */
+
+ debug(F110,"cx_net net line[] before ttopen",line,0);
+ debug(F101,"cx_net net mdmtyp before ttopen","",mdmtyp);
+ debug(F101,"cx_net net ttnproto","",ttnproto);
+
+#ifdef SSHBUILTIN
+ if (net == NET_SSH) {
+ makestr(&ssh_hst,hostname); /* Stash everything */
+ if (username) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+ }
+ if (srvbuf[0]) {
+ makestr(&ssh_prt,srvbuf);
+ } else
+ makestr(&ssh_prt,NULL);
+
+ if (command) {
+ makestr(&ssh_cmd,brstrip(command));
+ ssh_cas = param2;
+ } else
+ makestr(&ssh_cmd,NULL);
+
+ if (param1 > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_ver_saved) {
+ sl_ssh_ver = ssh_ver;
+ sl_ssh_ver_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_ver = param1;
+ }
+ if (param3 > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_xfw_saved) {
+ sl_ssh_xfw = ssh_xfw;
+ sl_ssh_xfw_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_xfw = param3;
+ }
+ } else /* NET_SSH */
+#endif /* SSHBUILTIN */
+#ifdef TCPSOCKET
+ if (net == NET_TCPB) {
+ switch (protocol) {
+#ifdef CK_SSL
+#ifdef COMMENT
+/*
+ Jeff's version from 30 Dec 2006 - doesn't work - SSL/TLS_RAW still
+ start Telnet negotions if a 0xff byte comes in.
+*/
+ case NP_SSL_RAW:
+ ttnproto = NP_SSL_RAW;
+ debug(F101,"NP_SSL_RAW ttnproto","",ttnproto);
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS_RAW:
+ ttnproto = NP_TLS_RAW;
+ debug(F101,"NP_TLS_RAW ttnproto","",ttnproto);
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+
+ case NP_SSL:
+ ttnproto = NP_SSL;
+ debug(F101,"NP_SSL ttnproto","",ttnproto);
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS:
+ ttnproto = NP_TLS;
+ debug(F101,"NP_TLS ttnproto","",ttnproto);
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+
+ case NP_SSL_TELNET:
+ ttnproto = NP_TELNET;
+ debug(F101,"NP_SSL_TELNET ttnproto","",ttnproto);
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS_TELNET:
+ ttnproto = NP_TELNET;
+ debug(F101,"NP_TLS_TELNET ttnproto","",ttnproto);
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+#else
+/* fdc version of 4 Dec 2006 works OK */
+ case NP_SSL_RAW:
+ case NP_SSL:
+ ssl_raw_flag = (protocol == NP_SSL_RAW) ? 1 : 0;
+ ttnproto = protocol;
+ debug(F101,protocol==NP_SSL ?
+ "NP_SSL ttnproto" :
+ "NP_SSL_RAW ttnproto",
+ "",ttnproto);
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS:
+ case NP_TLS_RAW:
+ tls_raw_flag = (protocol == NP_SSL_RAW) ? 1 : 0;
+ ttnproto = protocol;
+ debug(F101,protocol==NP_TLS ?
+ "NP_TLS ttnproto" :
+ "NP_TLS_RAW ttnproto",
+ "",ttnproto);
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+
+ case NP_SSL_TELNET:
+ ssl_raw_flag = 0;
+ ttnproto = NP_TELNET;
+ debug(F101,"NP_SSL_TELNET ttnproto","",ttnproto);
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS_TELNET:
+ tls_raw_flag = 0;
+ ttnproto = NP_TELNET;
+ debug(F101,"NP_TLS_TELNET ttnproto","",ttnproto);
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+#endif /* COMMENT */
+#endif /* CK_SSL */
+
+ case NP_NONE:
+ case NP_TCPRAW:
+ case NP_RLOGIN:
+ case NP_K4LOGIN:
+ case NP_K5LOGIN:
+ case NP_EK4LOGIN:
+ case NP_EK5LOGIN:
+ case NP_TELNET:
+ case NP_KERMIT:
+ default:
+ ttnproto = protocol;
+#ifdef CK_SSL
+#ifdef COMMENT
+ /* Jeff version from 30 Dec 2006 */
+ ssl_only_flag = 0;
+ tls_only_flag = 0;
+#else
+ /* fdc version from 4 Dec 2006 */
+ ssl_raw_flag = 0;
+ tls_raw_flag = 0;
+ ssl_only_flag = 0;
+ tls_only_flag = 0;
+#endif /* COMMENT */
+#endif /* CK_SSL */
+ break;
+ }
+#ifdef CK_AUTHENTICATION
+ if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ param1 > -1) {
+ if (!sl_auth_saved) {
+ int x;
+ for (x = 0; x < AUTHTYPLSTSZ; x++)
+ sl_auth_type_user[x] = auth_type_user[x];
+ sl_auth_saved = 1;
+ }
+ if (!sl_topt_a_s_saved) {
+ sl_topt_a_su = TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION);
+ sl_topt_a_s_saved = 1;
+ }
+ if (!sl_topt_a_c_saved) {
+ sl_topt_a_cm = TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION);
+ sl_topt_a_c_saved = 1;
+ }
+ switch (param1) {
+ case AUTHTYPE_AUTO:
+ auth_type_user[0] = AUTHTYPE_AUTO;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
+ break;
+ case AUTHTYPE_NULL:
+ auth_type_user[0] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ break;
+#ifdef CK_SRP
+ case AUTHTYPE_SRP:
+ auth_type_user[0] = AUTHTYPE_SRP;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ case AUTHTYPE_SSL:
+ auth_type_user[0] = AUTHTYPE_SSL;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* CK_SSL */
+#ifdef NT
+ case AUTHTYPE_NTLM:
+ auth_type_user[0] = AUTHTYPE_NTLM;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* NT */
+#ifdef CK_KERBEROS
+ case AUTHTYPE_KERBEROS_V4:
+ auth_type_user[0] = AUTHTYPE_KERBEROS_V4;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+
+ case AUTHTYPE_KERBEROS_V5:
+ auth_type_user[0] = AUTHTYPE_KERBEROS_V5;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* CK_KERBEROS */
+ }
+ }
+ /*
+ If the user requires a particular type of Kerberos connection,
+ make sure we have a valid TGT.
+ */
+ makestr(&slmsg,"Authentication failure");
+ if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ (line[0] == '*' &&
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU ||
+ line[0] != '*' &&
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU)
+ ) {
+#ifdef CK_KERBEROS
+ if ( auth_type_user[0] == AUTHTYPE_KERBEROS_V4 ) {
+ extern int krb4_autoget;
+ if (!ck_krb4_is_installed())
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 4) is not installed"));
+#ifdef COMMENT
+ /* This code results in false failures when using */
+ /* kerberos to machines in realms other than the */
+ /* default since we don't know the realm of the */
+ /* other machine until perform the reverse DNS */
+ /* lookup. */
+ else if (line[0] != '*' && !ck_krb4_is_tgt_valid() &&
+ (!krb4_autoget ||
+ krb4_autoget && !ck_krb4_autoget_TGT(NULL))) {
+ return(cx_fail(msg,
+ "Kerberos 4: Ticket Getting Ticket not valid"));
+ }
+#endif /* COMMENT */
+ } else if (auth_type_user[0] == AUTHTYPE_KERBEROS_V5) {
+ extern int krb5_autoget;
+ if (!ck_krb5_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 5) is not installed"));
+ }
+#ifdef COMMENT
+ /* This code results in false failures when using */
+ /* kerberos to machines in realms other than the */
+ /* default since we don't know the realm of the */
+ /* other machine until perform the reverse DNS */
+ /* lookup. */
+ else if (line[0] != '*' && !ck_krb5_is_tgt_valid() &&
+ (!krb5_autoget ||
+ krb5_autoget && !ck_krb5_autoget_TGT(NULL))) {
+ return(cx_fail(msg,
+ "Kerberos 5: Ticket Getting Ticket not valid."));
+ }
+#endif /* COMMENT */
+ }
+#endif /* CK_KERBEROS */
+#ifdef NT
+ if (auth_type_user[0] == AUTHTYPE_NTLM) {
+ if (!ck_ntlm_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (NTLM) is not installed"));
+ } else if (line[0] != '*' && !ck_ntlm_is_valid(0)) {
+ return(cx_fail(msg,"NTLM: Credentials are unavailable."));
+ }
+ }
+#endif /* NT */
+#ifdef CK_SSL
+ if (auth_type_user[0] == AUTHTYPE_SSL) {
+ if (!ck_ssleay_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (SSL) is not installed"));
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_SRP
+ if (auth_type_user[0] == AUTHTYPE_SRP) {
+ if (!ck_srp_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (SRP) is not installed"));
+ }
+ }
+#endif /* CK_SRP */
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ param2 > -1) {
+ if (!sl_cx_saved) {
+ sl_cx_type = cx_type;
+ sl_cx_saved = 1;
+ }
+ if (!sl_topt_e_s_saved) {
+ sl_topt_e_su = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_sm = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_s_saved = 1;
+ }
+ if (!sl_topt_e_c_saved) {
+ sl_topt_e_cu = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_cm = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_c_saved = 1;
+ }
+ cx_type = param2;
+ if (cx_type == CX_AUTO) {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ } else if (cx_type == CX_NONE) {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ } else {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+ }
+ if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN ||
+ (ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ ((line[0] == '*' &&
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU &&
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU) ||
+ (line[0] != '*' &&
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU &&
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU))
+ ) {
+ if (!ck_crypt_is_installed()) {
+ return(cx_fail(msg,
+ "Required Encryption methods are not installed"));
+ }
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef KRB4
+ if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN) {
+ extern int krb4_autoget;
+ char tgt[256];
+ char * realm;
+
+ /* We don't have the full hostname at yet so */
+ /* we do a DNS lookup before calling ttopen() */
+
+ realm = ck_krb4_realmofhost(ckgetfqhostname(hostname));
+ ckmakmsg(tgt,256,"krbtgt.",realm,"@",realm);
+ if (!ck_krb4_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 4) is not installed"
+ ));
+ } else {
+ if ((ck_krb4_tkt_isvalid(tgt) <= 0) &&
+ (!krb4_autoget ||
+ krb4_autoget && !ck_krb4_autoget_TGT(realm))) {
+ return(cx_fail(msg,
+ "Kerberos 4: Ticket Getting Ticket not valid"));
+ }
+ }
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN ||
+ ttnproto == NP_K5U2U)
+ {
+ extern int krb5_autoget;
+ char tgt[256];
+ char * realm;
+
+ /* Must get full hostname before calling ttopen() */
+
+ realm = ck_krb5_realmofhost(ckgetfqhostname(hostname));
+ ckmakmsg(tgt,256,"krbtgt/",realm,"@",realm);
+
+ if (!ck_krb5_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 5) not installed"));
+ } else if (!((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
+ ck_krb5_is_tgt_valid()) &&
+ (!krb5_autoget ||
+ krb5_autoget && !ck_krb5_autoget_TGT(realm))) {
+ return(cx_fail(msg,
+ "Kerberos 5: Ticket Getting Ticket not valid."));
+ }
+ }
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+
+#ifndef NOSPL
+#ifdef RLOGCODE
+ if (username) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+ uidflag = 1;
+ }
+#endif /* RLOGCODE */
+#ifdef TNCODE
+ if (!sl_tn_saved) {
+ sl_tn_wait = tn_wait_flg;
+ sl_tn_saved = 1;
+ }
+ tn_wait_flg = param3;
+#endif /* TNCODE */
+#endif /* NOSPL */
+ } /* if (net == NET_TCPB) */
+#endif /* TCPSOCKET */
+
+#ifndef NOSPL
+#ifdef CK_SECURITY
+ if (password) {
+ if (password[0]) {
+ ckstrncpy(pwbuf,password,PWBUFL+1);
+ pwflg = 1;
+ pwcrypt = 0;
+ } else
+ pwflg = 0;
+ }
+#endif /* CK_SECURITY */
+#endif /* NOSPL */
+
+ /* Try to open - network */
+ ckstrncpy(ttname,line,TTNAMLEN);
+ y = ttopen(line, &_local, mdmtyp, 0 );
+
+#ifndef NOHTTP
+ /* If the connection failed and we are using an HTTP Proxy
+ * and the reason for the failure was an authentication
+ * error, then we need to give the user to ability to
+ * enter a username and password, just like a browser.
+ *
+ * I tried to do all of this within the netopen() call
+ * but it is much too much work.
+ */
+ while (y < 0 && tcp_http_proxy != NULL ) {
+
+ if (tcp_http_proxy_errno == 401 ||
+ tcp_http_proxy_errno == 407 ) {
+ char uid[UIDBUFLEN];
+ char pwd[256];
+ struct txtbox tb[2];
+ int ok;
+
+ tb[0].t_buf = uid;
+ tb[0].t_len = UIDBUFLEN;
+ tb[0].t_lbl = "Proxy Userid: ";
+ tb[0].t_dflt = NULL;
+ tb[0].t_echo = 1;
+ tb[1].t_buf = pwd;
+ tb[1].t_len = 256;
+ tb[1].t_lbl = "Proxy Passphrase: ";
+ tb[1].t_dflt = NULL;
+ tb[1].t_echo = 2;
+
+ ok = uq_mtxt("Proxy Server Authentication Required\n",
+ NULL, 2, tb);
+
+ if (ok && uid[0]) {
+ char * proxy_user, * proxy_pwd;
+
+ proxy_user = tcp_http_proxy_user;
+ proxy_pwd = tcp_http_proxy_pwd;
+
+ tcp_http_proxy_user = uid;
+ tcp_http_proxy_pwd = pwd;
+
+ ckstrncpy(ttname,line,TTNAMLEN);
+ y = ttopen(line, &_local, mdmtyp, 0);
+ memset(pwd,0,sizeof(pwd));
+ tcp_http_proxy_user = proxy_user;
+ tcp_http_proxy_pwd = proxy_pwd;
+ } else
+ break;
+ } else
+ break;
+ }
+#endif /* NOHTTP */
+ if (y < 0) {
+ slrestor();
+ makestr(&slmsg,"Network connection failure");
+#ifdef VMS
+ if (msg && hints && !xcmdsrc && IS_RLOGIN()) {
+ makestr(&slmsg,"RLOGIN failure");
+ if (socket_errno == EACCES) {
+ printf("*************************\n");
+ printf(
+ "Hint: RLOGIN requires privileges to open an outbound port.\n");
+ printf(
+ "(Use SET HINTS OFF to suppress future hints.)\n");
+ printf("*************************\n");
+ }
+ }
+#else /* Not VMS... */
+ if (errno) {
+ int x;
+ debug(F111,"set host line, errno","",errno);
+ makestr(&slmsg,ck_errstr());
+ if (msg) {
+#ifdef OS2
+ printf("Can't connect to %s\n",line);
+#else /* OS2 */
+#ifdef UNIX
+ if (hints && !xcmdsrc && IS_RLOGIN()) {
+ makestr(&slmsg,"RLOGIN failure");
+ printf("*************************\n");
+ printf(
+ "Hint: RLOGIN requires privileges to open an outbound port.\n");
+ printf(
+ "(Use SET HINTS OFF to suppress future hints.)\n");
+ printf("*************************\n");
+ }
+#endif /* UNIX */
+#endif /* OS2 */
+ } else printf("Can't connect to %s\n",line);
+ } else
+#endif /* VMS */
+ if (msg) printf("Can't open connection to %s\n",line);
+ continue;
+ } else {
+ success = 1;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ switch (net) {
+ case NET_TCPA:
+ case NET_TCPB:
+ cxtype = CXT_TCPIP;
+#ifdef COMMENT
+/* This works but it messes up interactive anonymous login */
+#ifndef NOXFER
+#ifdef IKS_OPTION
+ /* If we have connected to an Internet Kermit service */
+ /* and a /USER: switch was given, then log in. */
+
+ if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT)) {
+ debug(F111,"cx_net IKSD /USER:",uidbuf,haveuser);
+ if (haveuser /* && cx == 0 */ ) { /* /USER: given */
+ char * psw = pwbuf; /* Do we have a password? */
+ if (!*psw) { /* No... */
+ if (!strcmp(uidbuf,"anonymous") ||
+ !strcmp(uidbuf,"ftp")) {
+ extern char myhost[];
+ char * u = (char *)sl_uidbuf;
+ char * h = (char *)myhost;
+ if (!*u) u = "nobody";
+ if (!*h) h = "nowhere";
+ ckmakmsg(tmpbuf,TMPBUFSIZ,u,"@",h,NULL);
+ psw = tmpbuf;
+ debug(F110,"cx_net IKSD anon",psw,0);
+ } else {
+ readpass(" Password: ",pwbuf,PWBUFL);
+ }
+ }
+ sstate = setgen('I',uidbuf,psw,"");
+ }
+ }
+#endif /* IKS_OPTION */
+#endif /* NOXFER */
+#endif /* COMMENT */
+ break;
+ case NET_SSH:
+ cxtype = CXT_SSH;
+ duplex = 0; /* Remote echo */
+ break;
+ case NET_SLAT:
+ cxtype = CXT_LAT;
+ break;
+ case NET_SX25:
+ case NET_IX25:
+ case NET_HX25:
+ case NET_VX25:
+ cxtype = CXT_X25;
+ break;
+ case NET_BIOS:
+ cxtype = CXT_NETBIOS;
+ break;
+ case NET_FILE:
+ case NET_PIPE:
+ case NET_CMD:
+ case NET_DLL:
+ case NET_PTY:
+ cxtype = CXT_PIPE;
+ break;
+ default:
+ cxtype = CXT_PIPE;
+ break;
+ }
+ break;
+ }
+ } /* for-loop */
+ s = line;
+
+ debug(F101,"cx_net post ttopen success","",success);
+ if (!success) {
+ local = dfloc; /* Go back to normal */
+#ifndef MAC
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */
+#endif /* MAC */
+ speed = ttgspd();
+ network = 0; /* No network connection active */
+ haveline = 0;
+ if (mdmtyp < 0) { /* Switching from net to async? */
+ if (mdmsav > -1) /* Restore modem type from last */
+ mdmtyp = mdmsav; /* SET MODEM command, if any. */
+ else
+ mdmtyp = 0;
+ mdmsav = -1;
+ }
+ return(0); /* Return failure */
+ }
+ if (_local > -1) local = _local; /* Opened ok, set local/remote. */
+ makestr(&slmsg,NULL);
+ network = (mdmtyp < 0); /* Remember connection type. */
+ ckstrncpy(ttname,s,TTNAMLEN); /* Copy name into real place. */
+ debug(F110,"cx_net ok",ttname,0);
+ debug(F101,"cx_net network","",network);
+#ifndef NOXFER
+ if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */
+ reliable = SET_OFF;
+#endif /* NOXFER */
+ if (!network || istncomport())
+ speed = ttgspd(); /* Get the current speed. */
+ debug(F101,"cx_net local","",local);
+ if (network) {
+ debug(F101,"cx_net net","",net);
+#ifndef NOXFER
+ /* Force prefixing of 255 on TCP/IP connections... */
+ if (net == NET_TCPB
+#ifdef SSHBUILTIN
+ || net == NET_SSH
+#endif /* SSHBUILTIN */
+ ) {
+ debug(F101,"cx_net reliable A","",reliable);
+#ifdef CK_SPEED
+ ctlp[(unsigned)255] = 1;
+#endif /* CK_SPEED */
+ if ((reliable != SET_OFF || !setreliable)) {
+#ifdef TN_COMPORT
+ if (istncomport()) { /* Telnet communication port */
+ reliable = SET_OFF; /* Transport is not reliable */
+ debug(F101,"cx_net reliable istncomport()","",1);
+ } else {
+ reliable = SET_ON; /* Transport is reliable end to end */
+ debug(F101,"cx_net reliable istncomport()","",0);
+ }
+#else
+ reliable = SET_ON; /* Transport is reliable end to end */
+#endif /* ifdef TN_COMPORT */
+ }
+ debug(F101,"cx_net reliable B","",reliable);
+ } else if (net == NET_SX25 ||
+ net == NET_VX25 ||
+ net == NET_IX25 ||
+ net == NET_HX25) {
+ duplex = 1; /* Local echo for X.25 */
+ if (reliable != SET_OFF || !setreliable)
+ reliable = SET_ON; /* Transport is reliable end to end */
+ }
+#endif /* NOXFER */
+ }
+#ifndef NOXFER
+ debug(F101,"cx_net reliable","",reliable);
+#endif /* NOXFER */
+#ifdef OS2
+ if (mdmtyp <= 0) /* Network or Direct Connection */
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+#endif /* OS2 */
+
+ xcx_net:
+
+ setflow(); /* Set appropriate flow control */
+
+ haveline = 1;
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+
+ if (local && (cx || sx)) { /* /CONNECT or /SERVER switch given */
+ if (cx) { /* /CONNECT */
+ if (!gui) {
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+ if (cmdlvl > 0)
+ prepop();
+ }
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ success = doconect(0, cmdlvl == 0 ? 1 : 0);
+ if (ttchk() < 0)
+ dologend();
+ debug(F101,"cx_net post doconect success","",success);
+ return(success);
+#ifndef NOXFER
+ } else if (sx) { /* /SERVER */
+ sstate = 'x';
+#ifdef MAC
+ what = W_RECV;
+ scrcreate();
+#endif /* MAC */
+ if (local) displa = 1;
+#ifdef AMIGA
+ reqoff(); /* No DOS requestors while server */
+#endif /* AMIGA */
+#endif /* NOXFER */
+ }
+ }
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ return(success = 1);
+}
+#endif /* NETCONN */
+
+/* c x _ s e r i a l -- Make a serial connection */
+
+/*
+ Call with:
+ device = string pointer to device name.
+ cx = 1 to automatically enter Connect mode, 0 otherwise.
+ sx = 1 to automatically enter Server mode, 0 otherwise.
+ shr = 1 if device should be opened in shareable mode, 0 otherwise.
+ flag = if no dev name given: 1 = close current connection, 0 = resume.
+ gui = 1 if called from GUI dialog, 0 otherwise.
+ Returns:
+ 1 on success
+ 0 on failure and no message printed, slmsg set to failure message.
+ -9 on failure and message printed, ditto.
+*/
+
+/* these are bit flags */
+#define CX_TAPI 1
+#define CX_PPP 2
+#define CX_SLIP 4
+
+int
+#ifdef CK_ANSIC
+cx_serial(char *device,
+ int cx, int sx, int shr, int flag, int gui, int special)
+#else /* CK_ANSIC */
+cx_serial(device, cx, sx, shr, flag, gui, special)
+ char * device; int cx, sx, shr, flag, gui, special;
+#endif /* CK_ANSIC */
+/* cx_serial */ {
+ int i, n, x, y, msg;
+ int _local = -1;
+ char *s;
+
+ debug(F110,"cx_serial device",device,0);
+ s = device;
+ msg = (gui == 0) && msgflg; /* Whether to print messages */
+ success = 0;
+
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ debug(F101,"cx_serial mdmtyp","",mdmtyp);
+ if (clskconnx(1) < 0) /* Close the Kermit connection */
+ return(success = 0);
+ if (*s) { /* They gave a device name */
+ _local = -1; /* Let ttopen decide about it */
+ } else { /* They just said "set line" */
+ s = dftty; /* so go back to normal tty */
+ _local = dfloc; /* and mode. */
+ }
+#ifdef VMS
+ {
+ extern int ok_to_share;
+ ok_to_share = shr;
+ }
+#endif /* VMS */
+
+#ifdef OS2 /* Must wait until after ttclos() */
+#ifdef NT /* to change these settings */
+#ifdef CK_TAPI
+ tttapi = special & CX_TAPI;
+#endif /* CK_TAPI */
+#else
+ ttslip = special & CX_SLIP;
+ ttppp = special & CX_PPP;
+#endif /* NT */
+ ttshare = shr; /* Shareable device ? */
+ debug(F110,"OS2 SET PORT final s",s,"");
+#endif /* OS2 */
+
+ /* Open the new line */
+
+ ckstrncpy(ttname,s,TTNAMLEN);
+ if ((y = ttopen(s,&_local,mdmtyp,cdtimo)) > -1) {
+ cxtype = (mdmtyp > 0) ? CXT_MODEM : CXT_DIRECT;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#ifdef CK_TAPI
+ /* if the line is a tapi device, then we need to auto-execute */
+ /* SET MODEM TYPE TAPI - which we do the equivalent of here. */
+ if (tttapi) {
+ extern int usermdm;
+ usermdm = 0;
+ initmdm(38); /* From ckudia.c n_TAPI == 38 */
+ }
+#endif /* CK_TAPI */
+#endif /* NODIAL */
+ success = 1;
+ } else { /* Failed */
+#ifdef OS2ONLY
+ if (!strcmp(s,dftty)) /* Do not generate an error with dftty */
+ ;
+ else if (y == -6 && ttslip) {
+ makestr(&slmsg,"Can't access SLIP driver");
+ if (msg) printf("?%s\n",slmsg);
+ } else if (y == -6 && ttppp) {
+ makestr(&slmsg,"Can't access PPP driver");
+ if (msg) printf("?%s\n",slmsg);
+ } else
+#endif /* OS2ONLY */
+ if (y == -2) {
+ makestr(&slmsg,"Timed out - no carrier");
+ if (msg) {
+ printf("?%s\n",slmsg);
+ if (hints) {
+ printf("\n*************************\n");
+ printf(
+ "HINT (Use SET HINTS OFF to suppress future hints):\n");
+ printf(
+ "Try SET CARRIER OFF and SET LINE again, or else\n");
+ printf("SET MODEM, SET LINE, and then DIAL.\n");
+ printf("*************************\n\n");
+ }
+ }
+ } else if (y == -3) {
+ makestr(&slmsg,"Access to lock denied");
+ if (msg) {
+#ifdef UNIX
+ printf(
+ "Sorry, write access to UUCP lockfile directory denied.\n");
+#ifndef NOHINTS
+ if (hints) {
+ printf("\n*************************\n");
+ printf(
+ "HINT (Use SET HINTS OFF to suppress future hints):\n");
+ printf(
+ "Please read the installation instructions file, %sckuins.txt,\n",
+ k_info_dir ? k_info_dir : ""
+ );
+ printf(
+ "or the UNIX appendix of the manual, \"Using C-Kermit\"\n"
+ );
+ printf(
+ "or visit http://www.columbia.edu/kermit/ckuins.html \n"
+ );
+ printf("*************************\n\n");
+ }
+#endif /* NOHINTS */
+#else
+ printf("Sorry, access to lock denied: %s\n",s);
+#endif /* UNIX */
+ }
+ } else if (y == -4) {
+ makestr(&slmsg,"Access to device denied");
+ if (msg) {
+ printf("Sorry, access to device denied: %s\n",s);
+#ifdef UNIX
+#ifndef NOHINTS
+ if (hints) {
+ printf("\n*************************\n");
+ printf(
+ "HINT (Use SET HINTS OFF to suppress future hints):\n");
+ printf(
+ "Please read the installation instructions file, %sckuins.txt,\n",
+ k_info_dir ? k_info_dir : ""
+ );
+ printf(
+ "or the UNIX appendix of the manual, \"Using C-Kermit\".\n"
+ );
+ printf("*************************\n\n");
+ }
+#endif /* NOHINTS */
+#endif /* UNIX */
+ }
+ } else if (y == -5) {
+ makestr(&slmsg,"Device is in use or unavailable");
+ if (msg)
+#ifdef VMS
+ printf(
+ "Sorry, device is in use or otherwise unavailable: %s\n",s);
+#else
+ printf("Sorry, device is in use: %s\n",s);
+#endif /* VMS */
+ } else { /* Other error. */
+ makestr(&slmsg,"Device open failed");
+ if (
+#ifdef VMS
+ 1
+#else
+ errno
+#endif /* VMS */
+ ) {
+ int x; /* Find a safe, long buffer */
+ makestr(&slmsg,ck_errstr());
+#ifndef VMS
+ debug(F111,"cx_serial serial errno",slmsg,errno);
+#endif /* VMS */
+ if (msg)
+ printf("Connection to %s failed: %s\n",s,slmsg);
+ } else if (msg)
+ printf("Sorry, can't open connection: %s\n",s);
+ }
+ }
+ network = 0; /* No network connection active */
+ speed = ttgspd();
+ if (!success) {
+ local = dfloc; /* Go back to normal */
+#ifndef MAC
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */
+#endif /* MAC */
+ haveline = 0;
+ if (mdmtyp < 0) { /* Switching from net to async? */
+ if (mdmsav > -1) /* Restore modem type from last */
+ mdmtyp = mdmsav; /* SET MODEM command, if any. */
+ else
+ mdmtyp = 0;
+ mdmsav = -1;
+ }
+ return(msg ? -9 : 0); /* Return failure */
+ }
+ if (_local > -1)
+ local = _local; /* Opened ok, set local/remote. */
+ makestr(&slmsg,NULL); /* Erase SET LINE message */
+ ckstrncpy(ttname,s,TTNAMLEN); /* Copy name into real place. */
+ debug(F110,"cx_serial ok",ttname,0);
+#ifndef NOXFER
+ if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */
+ reliable = SET_OFF;
+#endif /* NOXFER */
+
+ xcx_serial:
+ setflow(); /* Set appropriate flow control */
+ haveline = 1;
+#ifdef CKLOGDIAL
+ dologline();
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+
+ if (local && (cx || sx)) { /* /CONNECT or /SERVER switch given */
+ extern int carrier;
+ if (carrier != CAR_OFF) { /* Looking for carrier? */
+ /* Open() turns on DTR -- wait up to a second for CD to come up */
+ int i, x;
+ for (i = 0; i < 10; i++) { /* WAIT 1 CD... */
+ x = ttgmdm();
+ if (x < 0 || x & BM_DCD)
+ break;
+ msleep(100);
+ }
+ }
+ if (cx) { /* /CONNECT */
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+
+ if (cmdlvl > 0)
+ prepop();
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ success = doconect(0, cmdlvl == 0 ? 1 : 0);
+ if (ttchk() < 0)
+ dologend();
+ return(success);
+#ifndef NOXFER
+ } else if (sx) { /* /SERVER */
+ sstate = 'x';
+#ifdef MAC
+ what = W_RECV;
+ scrcreate();
+#endif /* MAC */
+ if (local) displa = 1;
+#ifdef AMIGA
+ reqoff(); /* No DOS requestors while server */
+#endif /* AMIGA */
+#endif /* NOXFER */
+ }
+ }
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ return(success = 1);
+}
+
+
+/* S E T L I N -- parse name of and then open communication device. */
+/*
+ Call with:
+ xx == XYLINE for a serial (tty) line, XYHOST for a network host,
+ zz == 0 means if user doesn't give a device name, continue current
+ active connection (if any);
+ zz != 0 means if user doesn't give a device name, then close the
+ current connection and restore the default communication device.
+ fc == 0 to just make the connection, 1 to also CONNECT (e.g. "telnet").
+*/
+int
+setlin(xx, zz, fc)
+ int xx, zz, fc;
+{
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+ int wait;
+ /* int tn_wait_sv; */
+ int mynet;
+ int _local = -1;
+ int c, i, haveswitch = 0;
+ int haveuser = 0;
+ int getval = 0;
+ int wild = 0; /* Filespec has wildcards */
+ int cx = 0; /* Connect after */
+ int sx = 0; /* Become server after */
+ int a_type = -1; /* Authentication type */
+ int e_type = -1; /* Telnet /ENCRYPT type */
+#ifdef CK_ENCRYPTION
+ int encrypt = 0; /* Encrypted? */
+#endif /* CK_ENCRYPTION */
+ int shr = 0; /* Share serial device */
+ int confirmed = 0; /* Command has been entered */
+ struct FDB sw, tx, nx;
+#ifdef OS2
+ struct FDB fl;
+#endif /* OS2 */
+
+ char * ss;
+#ifdef TCPSOCKET
+ int rawflg = 0;
+#endif /* TCPSOCKET */
+
+ char srvbuf[SRVBUFSIZ+1];
+
+#ifdef OS2
+#ifdef NT
+ int xxtapi = 0;
+#else
+ int xxslip = 0, xxppp = 0;
+#endif /* NT */
+#endif /* OS2 */
+
+ int dossh = 0;
+
+ debug(F101,"setlin fc","",fc);
+ debug(F101,"setlin zz","",zz);
+ debug(F101,"setlin xx","",xx);
+
+#ifdef SSHCMD
+ if (xx == XXSSH) { /* SSH becomes PTY SSH ... */
+ dossh = 1;
+ xx = XYHOST;
+ } else if (!ckstrcmp("ssh ",line,4,0)) { /* 2010/03/01 */
+ dossh = 1;
+ xx = XYHOST;
+ }
+ debug(F101,"setlin dossh","",dossh);
+#endif /* SSHCMD */
+
+#ifdef TNCODE
+ /* tn_wait_sv = tn_wait_flg; */
+ wait = tn_wait_flg;
+#else
+ /* tn_wait_sv = 0; */
+ wait = 0;
+#endif /* TNCODE */
+
+ mynet = nettype;
+
+ if (nolocal) {
+ makestr(&slmsg,"Making connections is disabled");
+ printf("?Sorry, making connections is disabled\n");
+ return(-9);
+ }
+ if (netsave > -1)
+ nettype = netsave;
+
+ if (fc != 0 || zz == 0) /* Preset /CONNECT switch */
+ cx = 1;
+
+ debug(F101,"setlin cx","",cx);
+
+ *srvbuf = NUL;
+
+ line[0] = NUL;
+ s = line;
+
+#ifdef NETCONN
+#ifdef CK_SECURITY
+ if (tmpstring)
+ makestr(&tmpstring,NULL);
+#endif /* CK_SECURITY */
+ if (tmpusrid)
+ makestr(&tmpusrid,NULL);
+#endif /* NETCONN */
+
+ autoflow = 1; /* Enable automatic flow setting */
+
+ if (xx == XYHOST) { /* SET HOST <hostname> */
+#ifndef NETCONN
+ makestr(&slmsg,"Network connections not supported");
+ printf("?%s\n",slmsg);
+ return(-9);
+#else /* NETCONN */
+#ifndef NOPUSH
+ if ((mynet == NET_CMD || mynet == NET_PTY || dossh) && nopush) {
+ makestr(&slmsg,"Access to external commands is disabled");
+ printf("?Sorry, access to external commands is disabled\n");
+ return(-9);
+ }
+#endif /* NOPUSH */
+
+#ifdef SSHCMD
+ if (dossh) { /* SSH connection via pty */
+ int k;
+ extern int ttyfd; /* 2010/03/01 */
+ k = ckstrncpy(line, sshcmd ? sshcmd : defsshcmd, LINBUFSIZ);
+ debug(F111,"setlin sshcmd 1",line,k);
+ if ((x = cmtxt("Optional switches and hostname","",&s,xxstring))<0)
+ return(x);
+
+ /* 2010-03-30 */
+ if (!*s && ttyfd < 0 && !ckstrcmp("ssh ",ttname,4,0)) {
+ x = ckstrncpy(line,ttname,LINBUFSIZ);
+ } else {
+ if (!*s) {
+ printf("?SSH to where?\n");
+ return(-9);
+ }
+ if (k < LINBUFSIZ) {
+ line[k++] = SP;
+ line[k] = NUL;
+ debug(F111,"setlin sshcmd 2",line,k);
+ } if (k < LINBUFSIZ) {
+ ckstrncpy(&line[k],s,LINBUFSIZ-k);
+ debug(F111,"setlin sshcmd 3",line,k);
+ } else {
+ printf("?Too long\n");
+ return(-9);
+ }
+ }
+ x = cx_net( NET_PTY, /* network type */
+ 0, /* protocol (not used) */
+ line, /* host */
+ NULL, /* service (not used) */
+ NULL, /* username (not used) */
+ NULL, /* password (not used) */
+ NULL, /* command (not used) */
+ -1,-1,-1, /* params 1-3 (not used) */
+ 1, /* connect immediately */
+ sx, /* server? */
+ zz, /* close current? */
+ 0); /* not gui */
+ debug(F111,"setlin cx_net",line,x);
+ return(x);
+ }
+#endif /* SSHCMD */
+
+/*
+ Here we parse optional switches and then the hostname or whatever,
+ which depends on the network type. The tricky part is, the network type
+ can be set by a switch.
+*/
+#ifndef NOSPL
+ makestr(&g_pswd,pwbuf); /* Save global pwbuf */
+ g_pflg = pwflg; /* and flag */
+ g_pcpt = pwcrypt;
+#endif /* NOSPL */
+
+ confirmed = 0;
+ haveswitch = 0;
+#ifdef NETFILE
+ if (mynet != NET_FILE) {
+#endif /* NETFILE */
+ ss = (mynet == NET_CMD || mynet == NET_PTY) ?
+ "Command, or switch" :
+ (mynet == NET_TCPA || mynet == NET_TCPB
+ || mynet == NET_SSH) ?
+ "Hostname, ip-address, or switch" :
+ "Host or switch";
+ if (fc) {
+ if (mynet == NET_TCPB &&
+ (ttnproto == NP_TELNET || ttnproto == NP_KERMIT)) {
+ if (nshteltab) {
+ haveswitch++;
+ cmfdbi(&sw,_CMKEY,ss,"","",nshteltab,4,xxstring,
+ shteltab,&nx);
+ }
+ }
+#ifdef RLOGCODE
+ else if (mynet == NET_TCPB && ttnproto == NP_RLOGIN) {
+ if (nshrlgtab) {
+ haveswitch++;
+ cmfdbi(&sw,_CMKEY,ss,"","",nshrlgtab,4,xxstring,
+ shrlgtab,&nx);
+ }
+ }
+#endif /* RLOGCODE */
+ } else {
+ haveswitch++;
+ cmfdbi(&sw,_CMKEY,ss,"","",nshtab,4,xxstring,shtab,&nx);
+ }
+#ifdef NETFILE
+ }
+#endif /* NETFILE */
+ if (mynet == NET_TCPB || mynet == NET_SLAT ||
+ mynet == NET_SSH || mynet == NET_DEC) {
+ cmfdbi(&nx,_CMFLD,"Host","","",0,0,xxstring,NULL,NULL);
+#ifdef NETFILE
+ } else if (mynet == NET_FILE) {
+ cmfdbi(&nx,_CMIFI,"Filename","","",0,0,xxstring,NULL,NULL);
+#endif /* NETFILE */
+#ifdef PTYORPIPE
+ } else if (mynet == NET_CMD || mynet == NET_PTY) {
+ cmfdbi(&nx,_CMTXT,"Command","","",0,0,xxstring,NULL,NULL);
+#endif /* PTYORPIPE */
+ } else {
+ cmfdbi(&nx,_CMTXT,"Host","","",0,0,xxstring,NULL,NULL);
+ }
+ while (1) {
+ x = cmfdb(haveswitch ? &sw : &nx);
+ debug(F101,"setlin cmfdb","",x);
+ if (x < 0)
+ if (x != -3)
+ return(x);
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) {
+ return(x);
+ } else {
+ confirmed = 1;
+ break;
+ }
+ }
+ if (cmresult.fcode != _CMKEY) { /* Not a switch */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Save the data */
+ s = line; /* that was parsed... */
+ if (cmresult.fcode == _CMIFI) {
+ wild = cmresult.nresult;
+ } else if (cmresult.fcode == _CMTXT) {
+ confirmed = 1;
+ }
+ break; /* and break out of this loop */
+ }
+ c = cmgbrk(); /* Have switch - get break character */
+ getval = (c == ':' || c == '='); /* Must parse an agument? */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) { /* It's a switch.. */
+ case SL_CNX: /* /CONNECT */
+ cx = 1;
+ sx = 0;
+ break;
+ case SL_SRV: /* /SERVER */
+ cx = 0;
+ sx = 1;
+ break;
+#ifdef NETCMD
+ case SL_CMD: /* /COMMAND */
+ netsave = mynet;
+ mynet = NET_CMD;
+ break;
+#endif /* NETCMD */
+#ifdef NETPTY
+ case SL_PTY: /* /PTY */
+ netsave = mynet;
+ mynet = NET_PTY;
+ break;
+#endif /* NETPTY */
+ case SL_NET: /* /NETWORK-TYPE */
+ if ((x = cmkey(netcmd,nnets,"","",xxstring)) < 0)
+ return(x);
+ mynet = x;
+ break;
+
+#ifdef CK_SECURITY
+ case SL_PSW: /* /PASSWORD: */
+ if (!getval)
+ break;
+ debok = 0;
+ if ((x = cmfld("Password","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&tmpstring,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&tmpstring,s);
+ }
+ break;
+#endif /* CK_SECURITY */
+
+ case SL_UID: /* /USERID: */
+ if (!getval)
+ break;
+ if ((x = cmfld("Userid","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&tmpusrid,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > 63) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",63);
+ return(-9);
+ }
+ makestr(&tmpusrid,s);
+ haveuser = 1;
+ }
+ break;
+
+#ifdef CK_AUTHENTICATION
+#ifdef CK_SRP
+ case SL_SRP:
+ a_type = AUTHTYPE_SRP;
+ break;
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ case SL_SSL:
+ a_type = AUTHTYPE_SSL;
+ break;
+#endif /* CK_SSL */
+#ifdef NT
+ case SL_NTLM:
+ a_type = AUTHTYPE_NTLM;
+ break;
+#endif /* NT */
+#ifdef CK_KERBEROS
+ case SL_KRB4:
+ a_type = AUTHTYPE_KERBEROS_V4;
+ if (ttnproto == NP_RLOGIN)
+ ttnproto =
+#ifdef CK_ENCRYPTION
+ encrypt ? NP_EK4LOGIN :
+#endif /* CK_ENCRYPTION */
+ NP_K4LOGIN;
+ else if (ttnproto == NP_K5LOGIN)
+ ttnproto = NP_K4LOGIN;
+#ifdef CK_ENCRYPTION
+ else if (ttnproto == NP_EK5LOGIN)
+ ttnproto = NP_EK4LOGIN;
+#endif /* CK_ENCRYPTION */
+ break;
+ case SL_KRB5:
+ a_type = AUTHTYPE_KERBEROS_V5;
+ if (ttnproto == NP_RLOGIN)
+ ttnproto =
+#ifdef CK_ENCRYPTION
+ encrypt ? NP_EK5LOGIN :
+#endif /* CK_ENCRYPTION */
+ NP_K5LOGIN;
+ else if (ttnproto == NP_K4LOGIN)
+ ttnproto = NP_K5LOGIN;
+#ifdef CK_ENCRYPTION
+ else if (ttnproto == NP_EK4LOGIN)
+ ttnproto = NP_EK5LOGIN;
+#endif /* CK_ENCRYPTION */
+ break;
+#endif /* CK_KERBEROS */
+ case SL_AUTH: {
+ extern struct keytab autyptab[];
+ extern int nautyp;
+ if ((x = cmkey(autyptab,nautyp,"type of authentication",
+ "automatic",xxstring)) < 0)
+ return(x);
+ a_type = x;
+ break;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ case SL_ENC:
+ switch (ttnproto) {
+ case NP_K4LOGIN:
+ ttnproto = NP_EK4LOGIN;
+ encrypt = 1;
+ break;
+ case NP_K5LOGIN:
+ ttnproto = NP_EK5LOGIN;
+ encrypt = 1;
+ break;
+ case NP_KERMIT:
+ case NP_TELNET: {
+ static struct keytab * tnetbl = NULL;
+ static int ntnetbl = 0;
+ x = ck_get_crypt_table(&tnetbl,&ntnetbl);
+ debug(F101,"ck_get_crypt_table x","",x);
+ debug(F101,"ck_get_crypt_table n","",ntnetbl);
+ if (x < 1 || !tnetbl || ntnetbl < 1) /* Didn't get it */
+ x = 0;
+ if (!x) {
+ makestr(&slmsg,"Internal error");
+ printf("?Oops, types not loaded\n");
+ return(-9);
+ }
+ if ((x = cmkey(tnetbl,ntnetbl,"type of encryption",
+ "automatic",xxstring)) < 0)
+ return(x);
+ e_type = x;
+ break;
+ }
+ }
+ break;
+#endif /* CK_ENCRYPTION */
+ case SL_WAIT:
+ wait = 1;
+ break;
+ case SL_NOWAIT:
+ wait = 0;
+ break;
+ }
+ }
+
+#ifdef NETFILE
+ if (mynet == NET_FILE) { /* Parsed by cmifi() */
+ if ((x = cmcfm()) < 0) /* Needs confirmation */
+ return(x);
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* NETFILE */
+
+#ifdef NETCMD
+ if (mynet == NET_CMD || mynet == NET_PTY) {
+ char *p = NULL;
+ if (!confirmed) {
+ if ((x = cmtxt("Rest of command","",&s,xxstring)) < 0)
+ return(x);
+ if (*s) {
+ ckstrncat(line," ",LINBUFSIZ);
+ ckstrncat(line,s,LINBUFSIZ);
+ }
+ s = line;
+ }
+ /* s == line - so we must protect the line buffer */
+ s = brstrip(s);
+ makestr(&p,s);
+ ckstrncpy(line,p,LINBUFSIZ);
+ makestr(&p,NULL);
+
+ x = cx_net( mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* NETCMD */
+
+#ifdef NPIPE /* Named pipe */
+ if (mynet == NET_PIPE) { /* Needs backslash twiddling */
+ if (line[0]) {
+ if (strcmp(line,"*")) { /* If remote, begin with */
+ char * p = NULL;
+ makestr(&p,line);
+ ckstrncpy(line,"\\\\",LINBUFSIZ); /* server name */
+ ckstrncat(line,p,LINBUFSIZ);
+ makestr(&p,NULL);
+ } else {
+ line[0]='\0';
+ }
+ ckstrncat(line,"\\pipe\\", LINBUFSIZ); /* Make pipe name */
+ ckstrncat(line,pipename, LINBUFSIZ); /* Add name of pipe */
+
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+ }
+#endif /* NPIPE */
+
+#ifdef SUPERLAT
+ if (mynet == NET_SLAT) { /* Needs password, etc. */
+ slat_pwd[0] = NUL; /* Erase any previous password */
+ debok = 0;
+ if (*line) { /* If they gave a host name... */
+ if ((x = cmfld(
+ "password,\n or carriage return if no password required",
+ "",
+ &s,
+ xxstring
+ )) < 0 && x != -3)
+ return(x);
+ ckstrncpy(slat_pwd,s,18); /* Set the password, if any */
+ }
+ if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
+
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* SUPERLAT */
+
+#ifdef DECNET
+ if (mynet == NET_DEC) {
+ if (!line[0]) { /* If they gave a host name... */
+ printf("?hostname required\n");
+ return(-3);
+ }
+ if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
+
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* DECNET */
+
+#ifdef SSHBUILTIN
+ if (mynet == NET_SSH) { /* SSH connection */
+ int k, havehost = 0, trips = 0;
+ int tmpver = -1, tmpxfw = -1, tmpssh_cas;
+#ifndef SSHTEST
+ extern int sl_ssh_xfw, sl_ssh_xfw_saved;
+ extern int sl_ssh_ver, sl_ssh_ver_saved;
+#endif /* SSHTEST */
+ extern struct keytab sshopnsw[];
+ extern int nsshopnsw;
+ extern char *ssh_tmpcmd, *ssh_tmpport;
+ struct FDB sw, kw, fl;
+
+ debug(F110,"setlin SSH service 0",srvbuf,0);
+ debug(F110,"setlin SSH host s 2",s,0);
+ if (*s) { /* If they gave a host name... */
+ debug(F110,"setlin SSH host s 1",s,0);
+ if (*s == '*') {
+ makestr(&slmsg,"Incoming connections not supported");
+ printf(
+ "?Sorry, incoming connections not supported for SSH.\n"
+ );
+ return(-9);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ } else {
+ printf("?hostname required\n");
+ return(-3);
+ }
+
+ /* Parse [ port ] [ switches ] */
+ cmfdbi(&kw, /* Switches */
+ _CMKEY,
+ "Port number or service name,\nor switch",
+ "",
+ "",
+ nsshopnsw,
+ 4,
+ xxstring,
+ sshopnsw,
+ &fl
+ );
+ cmfdbi(&fl, /* Port number or service name */
+ _CMFLD,
+ "",
+ "",
+ "",
+ 0,
+ 0,
+ xxstring,
+ NULL,
+ NULL
+ );
+ trips = 0; /* Explained below */
+ while (1) { /* Parse port and switches */
+ y = cmfdb(&kw); /* Get a field */
+ if (y == -3) /* User typed CR so quit from loop */
+ break;
+ if (y < 0) /* Other parse error, pass it back */
+ return(y);
+ switch (cmresult.fcode) { /* Field or Keyword? */
+ case _CMFLD: /* Field */
+ ckstrncpy(srvbuf,cmresult.sresult,SRVBUFSIZ);
+ break;
+ case _CMKEY: /* Keyword */
+ switch (cmresult.nresult) { /* Which one? */
+ case SSHSW_PWD:
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ debok = 0;
+ if ((y = cmfld("Password","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ makestr(&tmpstring,"");
+ } else {
+ return(y);
+ }
+ } else {
+ s = brstrip(s);
+ if ((y = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&tmpstring,s);
+ }
+ break;
+ case SSHSW_USR: /* /USER: */
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((y = cmfld("Username","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ makestr(&tmpusrid,s);
+ break;
+ case SSHSW_VER:
+ if ((y = cmnum("Number","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 1 || z > 2) {
+ printf("?Out of range: %d\n",z);
+ return(-9);
+ }
+ tmpver = z;
+ break;
+ case SSHSW_CMD:
+ case SSHSW_SUB:
+ if ((y = cmfld("Text","",&s,xxstring)) < 0)
+ return(y);
+ makestr(&ssh_tmpcmd,s);
+ tmpssh_cas = (cmresult.nresult == SSHSW_SUB);
+ break;
+ case SSHSW_X11:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ tmpxfw = y;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ if (trips++ == 0) { /* After first time through */
+ cmfdbi(&kw, /* only parse switches, not port. */
+ _CMKEY,
+ "Switch",
+ "",
+ "",
+ nsshopnsw,
+ 4,
+ xxstring,
+ sshopnsw,
+ NULL
+ );
+ }
+ }
+ if ((y = cmcfm()) < 0) /* Get confirmation */
+ return(y);
+
+ debug(F110,"setlin pre-cx_net line",line,0);
+ debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0);
+ x = cx_net( mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ srvbuf, /* port */
+ tmpusrid, /* alternate username */
+ tmpstring, /* password */
+ ssh_tmpcmd, /* command to execute */
+ tmpver, /* param1 - ssh version */
+ tmpssh_cas, /* param2 - ssh cas */
+ tmpxfw, /* param3 - ssh x11fwd */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ if (tmpusrid)
+ makestr(&tmpusrid,NULL);
+ if (ssh_tmpcmd)
+ makestr(&ssh_tmpcmd,NULL);
+ }
+#endif /* SSHBUILTIN */
+
+#ifdef TCPSOCKET
+ if (mynet == NET_TCPB) { /* TCP/IP connection */
+ debug(F110,"setlin service 0",srvbuf,0);
+ debug(F110,"setlin host s 2",s,0);
+ if (*s) { /* If they gave a host name... */
+ debug(F110,"setlin host s 1",s,0);
+#ifdef NOLISTEN
+ if (*s == '*') {
+ makestr(&slmsg,"Incoming connections not supported");
+ printf(
+ "?Sorry, incoming connections not supported in this version of Kermit.\n"
+ );
+ return(-9);
+ }
+#endif /* NOLISTEN */
+#ifdef RLOGCODE
+ /* Allow a username if rlogin is requested */
+ if (mynet == NET_TCPB &&
+ (ttnproto == NP_RLOGIN || ttnproto == NP_K5LOGIN ||
+ ttnproto == NP_EK5LOGIN || ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_EK4LOGIN
+ )) {
+ int y;
+ uidflag = 0;
+ /* Check for "host:service" */
+ for ( ; (*s != '\0') && (*s != ':'); s++) ;
+ if (*s) { /* Service, save it */
+ *s = NUL;
+ ckstrncpy(srvbuf,++s,SRVBUFSIZ);
+ } else { /* No :service, then use default. */
+#ifdef VMS
+ switch (ttnproto) {
+ case NP_RLOGIN:
+ ckstrncpy(srvbuf,"513",SRVBUFSIZ); /* "login" */
+ break;
+ case NP_K4LOGIN:
+ case NP_K5LOGIN:
+ ckstrncpy(srvbuf,"543",SRVBUFSIZ); /* "klogin" */
+ break;
+ case NP_EK4LOGIN:
+ case NP_EK5LOGIN:
+ ckstrncpy(srvbuf,"2105",SRVBUFSIZ); /* "eklogin" */
+ break;
+ }
+#else /* VMS */
+ switch (ttnproto) {
+ case NP_RLOGIN:
+ ckstrncpy(srvbuf,"login",SRVBUFSIZ);
+ break;
+ case NP_K4LOGIN:
+ case NP_K5LOGIN:
+ ckstrncpy(srvbuf,"klogin",SRVBUFSIZ);
+ break;
+ case NP_EK4LOGIN:
+ case NP_EK5LOGIN:
+ ckstrncpy(srvbuf,"eklogin",SRVBUFSIZ);
+ break;
+ }
+#endif /* VMS */
+ }
+ if (!confirmed) {
+ y = cmfld("Userid on remote system",
+ uidbuf,&s,xxstring);
+ if (y < 0 && y != -3)
+ return(y);
+ if ((int)strlen(s) > 63) {
+ makestr(&slmsg,"Internal error");
+ printf("Sorry, too long\n");
+ return(-9);
+ }
+ makestr(&tmpusrid,s);
+ }
+ } else { /* TELNET or SET HOST */
+#endif /* RLOGCODE */
+ /* Check for "host:service" */
+ for ( ; (*s != '\0') && (*s != ':'); s++) ;
+ if (*s) { /* Service, save it */
+ *s = NUL;
+ ckstrncpy(srvbuf,++s,SRVBUFSIZ);
+ } else if (!confirmed) {
+ /* No :service, let them type one. */
+ if (*line != '*') { /* Not incoming */
+ if (mynet == NET_TCPB && ttnproto == NP_KERMIT) {
+ if ((x = cmfld(
+ "TCP service name or number",
+ "kermit",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+#ifdef RLOGCODE
+ } else if (mynet == NET_TCPB &&
+ ttnproto == NP_RLOGIN) {
+ if ((x = cmfld(
+ "TCP service name or number,\n or carriage return for rlogin (513)",
+ "login",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+#ifdef CK_AUTHENTICATION
+#ifdef CK_KERBEROS
+ } else if (mynet == NET_TCPB &&
+ (ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_K5LOGIN)) {
+ if ((x = cmfld(
+ "TCP service name or number,\n or carriage return for klogin (543)",
+ "klogin",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+ } else if (mynet == NET_TCPB &&
+ (ttnproto == NP_EK4LOGIN ||
+ ttnproto == NP_EK5LOGIN)) {
+ if ((x = cmfld(
+ "TCP service name or number,\n or carriage return for eklogin (2105)",
+ "eklogin",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+#endif /* CK_KERBEROS */
+#endif /* CK_AUTHENTICATION */
+#endif /* RLOGCODE */
+ } else {
+ /* Do not set a default value in this call */
+ /* If you do then it will prevent entries */
+ /* in the network directory from accessing */
+ /* alternate ports. */
+
+ if ((x = cmfld(
+ "TCP service name or number",
+ "",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+ }
+ } else { /* Incoming connection */
+ if ((x = cmfld("TCP service name or number",
+ "",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+ }
+ if (*s) /* If they gave a service, */
+ ckstrncpy(srvbuf,s,SRVBUFSIZ); /* copy it */
+ debug(F110,"setlin service 0.5",srvbuf,0);
+ }
+#ifdef RLOGCODE
+ }
+#endif /* RLOGCODE */
+ if (!confirmed) {
+ char * defproto;
+ switch (ttnproto) {
+ case NP_RLOGIN:
+ defproto = "/rlogin";
+ break;
+ case NP_K4LOGIN:
+ defproto = "/k4login";
+ break;
+ case NP_K5LOGIN:
+ defproto = "/k5login";
+ break;
+ case NP_EK4LOGIN:
+ defproto = "/ek4login";
+ break;
+ case NP_EK5LOGIN:
+ defproto = "/ek5login";
+ break;
+ case NP_KERMIT:
+ case NP_TELNET:
+ defproto = "/telnet";
+ break;
+ default:
+ defproto = "/default";
+ }
+ if ((x = cmkey(tcprawtab,ntcpraw,"Switch",defproto,
+ xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ else if ((x = cmcfm()) < 0)
+ return(x);
+ } else {
+ rawflg = x;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ }
+ }
+ }
+ debug(F110,"setlin pre-cx_net line",line,0);
+ debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0);
+ x = cx_net( mynet, /* nettype */
+ rawflg /* protocol */,
+ line, /* host */
+ srvbuf, /* port */
+ tmpusrid, /* alternate username */
+ tmpstring, /* password */
+ NULL, /* command to execute */
+ a_type, /* param1 - telnet authtype */
+ e_type, /* param2 - telnet enctype */
+ wait, /* param3 - telnet wait */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* TCPSOCKET */
+
+#ifdef CK_SECURITY
+ if (tmpstring)
+ makestr(&tmpstring,NULL);
+#endif /* CK_SECURITY */
+ if (tmpusrid)
+ makestr(&tmpusrid,NULL);
+ debug(F111,"setlin cx_net",line,x);
+ return(x);
+#endif /* NETCONN */
+ }
+
+/* Serial tty device, possibly modem, connection... */
+
+#ifdef OS2
+/*
+ User can type:
+ COM1..COM8 = Regular COM port
+ 1..8 = Synonym for COM1..COM8, is translated to COM1..COM8
+ _n = (n is a number) = open file handle
+ string = any text string = name of some other kind of device,
+ taken literally, as given.
+*/
+ s = "Communication device name";
+
+#ifdef CK_TAPI
+ if (TAPIAvail)
+ cktapiBuildLineTable(&tapilinetab, &_tapilinetab, &ntapiline);
+ if (!(tapilinetab && _tapilinetab && ntapiline > 0) &&
+ xx == XYTAPI_LIN ) {
+ makestr(&slmsg,"TAPI device not configured");
+ printf("\nNo TAPI Line Devices are configured for this system\n");
+ return(-9);
+ }
+ if (xx == XYTAPI_LIN) { /* Default (first) TAPI line */
+ s = "tapi"; /* (whatever it is) */
+ } else { /* Query the user */
+#endif /* CK_TAPI */
+
+/* Now parse optional switches and then device name */
+
+ confirmed = 0;
+ cmfdbi(&sw,_CMKEY,"Device name, or switch",
+ "","",npsltab,4,xxstring,psltab,&fl);
+ cmfdbi(&fl,_CMFLD,"",dftty,"",0,0,xxstring,NULL,NULL);
+ while (1) {
+ x = cmfdb(&sw);
+ debug(F101,"setlin cmfdb","",x);
+ if (x < 0)
+ if (x != -3)
+ return(x);
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) {
+ return(x);
+ } else {
+ confirmed = 1;
+ break;
+ }
+ }
+ if (cmresult.fcode == _CMFLD) {
+ s = cmresult.sresult;
+ break;
+ } else if (cmresult.fcode == _CMKEY) {
+ switch (cmresult.nresult) {
+ case SL_CNX: /* /CONNECT */
+ cx = 1;
+ sx = 0;
+ break;
+ case SL_SRV: /* /SERVER */
+ cx = 0;
+ sx = 1;
+ break;
+ case SL_SHR: /* /SHARE */
+ shr = 1;
+ break;
+ case SL_NSH: /* /NOSHARE */
+ shr = 0;
+ break;
+ }
+ }
+ }
+#ifdef CK_TAPI
+ }
+#endif /* CK_TAPI */
+
+ debug(F110,"OS2 SET PORT s",s,0);
+ y = lookup(os2devtab,s,nos2dev,&x); /* Look up in keyword table */
+ debug(F101,"OS2 SET PORT x","",x);
+ debug(F101,"OS2 SET PORT y","",y);
+ if ((y > -1) && (x >= 0 && x < 8)) { /* User typed a digit 1..8 */
+ s = os2devtab[x+8].kwd; /* Substitite its real name */
+#ifdef NT
+ xxtapi = 0;
+#else /* NT */
+ xxslip = xxppp = 0;
+#endif /* NT */
+ debug(F110,"OS2 SET PORT subst s",s,"");
+#ifndef NT
+ } else if ((y >-1) && (x >= 16 && x < 24)) { /* SLIP access */
+ s = os2devtab[x-8].kwd; /* Substitite its real name */
+ debug(F110,"OS2 SET PORT SLIP subst s",s,"");
+ xxslip = 1;
+ xxppp = 0;
+ } else if ((y >-1) && (x >= 24 && x < 32)) { /* PPP access */
+ s = os2devtab[x-16].kwd; /* Substitite its real name */
+ debug(F110,"OS2 SET PORT PPP subst s",s,"");
+ xxppp = 1;
+ xxslip = 0;
+ if ((y = cmkey(os2ppptab,
+ nos2ppp,
+ "PPP driver interface",
+ "ppp0",
+ xxstring)
+ ) < 0)
+ return(y);
+ debug(F101,"OS2 SET PORT PPP INTERFACE y","",y);
+ xxppp = (y % 10) + 1;
+#endif /* NT */
+ } else if (*s == '_') { /* User used "_" prefix */
+ s++; /* Remove it */
+ /* Rest must be numeric */
+ debug(F110,"OS2 SET PORT HANDLE _subst s",s,0);
+ if (!rdigits(s)) {
+ makestr(&slmsg,"Invalid file handle");
+ printf("?Invalid format for file handle\n");
+ return(-9);
+ }
+#ifdef NT
+ xxtapi = 0;
+#else /* NT */
+ xxslip = xxppp = 0;
+#endif /* NT */
+ } else { /* A normal COMx port or a string */
+ s = brstrip(s); /* Strip braces if any */
+#ifdef NT
+#ifdef CK_TAPI
+ /* Windows TAPI support - Look up in keyword table */
+ if (tapilinetab && _tapilinetab && ntapiline > 0) {
+ if (!ckstrcmp(s,"tapi",4,0)) {
+
+ /* Find out what the lowest numbered TAPI device is */
+ /* and use it as the default. */
+ int j = 9999, k = -1;
+ for (i = 0; i < ntapiline; i++) {
+ if (tapilinetab[i].kwval < j) {
+ j = tapilinetab[i].kwval;
+ k = i;
+ }
+ }
+ if (k >= 0)
+ s = _tapilinetab[k].kwd;
+ else
+ s = "";
+
+ if ((y = cmkey(_tapilinetab,ntapiline,
+ "TAPI device name",s,xxstring)) < 0)
+ return(y);
+
+ xxtapi = 1;
+
+ /* Get the non Underscored string */
+ for (i = 0; i < ntapiline; i++ ) {
+ if (tapilinetab[i].kwval == y) {
+ s = tapilinetab[i].kwd;
+ break;
+ }
+ }
+ } else
+ xxtapi = 0;
+ }
+#endif /* CK_TAPI */
+#else /* NT */
+ /* not OS/2 SLIP or PPP */
+ xxslip = xxppp = 0;
+#endif /* NT */
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy to a safe place */
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#else /* !OS2 */
+
+ cmfdbi(&sw,_CMKEY,"Device name, or switch",
+ "","",npsltab,4,xxstring,psltab,&tx);
+ cmfdbi(&tx,_CMTXT,"",dftty,"",0,0,xxstring,NULL,NULL);
+ while (!confirmed) {
+ x = cmfdb(&sw);
+ debug(F101,"setlin cmfdb","",x);
+ if (x < 0)
+ if (x != -3)
+ return(x);
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) {
+ return(x);
+ } else {
+ confirmed = 1;
+ break;
+ }
+ }
+ switch (cmresult.fcode) {
+ case _CMTXT:
+ ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
+ s = tmpbuf;
+ debug(F110,"setlin CMTXT",tmpbuf,0);
+ confirmed = 1;
+ break;
+ case _CMKEY: /* Switch */
+ debug(F101,"setlin CMKEY",tmpbuf,cmresult.nresult);
+ switch (cmresult.nresult) {
+ case SL_CNX: /* /CONNECT */
+ cx = 1;
+ sx = 0;
+ break;
+ case SL_SRV: /* /SERVER */
+ cx = 0;
+ sx = 1;
+ break;
+#ifdef VMS
+ case SL_SHR: /* /SHARE */
+ shr = 1;
+ break;
+ case SL_NSH: /* /NOSHARE */
+ shr = 0;
+ break;
+#endif /* VMS */
+ }
+ continue;
+ default:
+ debug(F101,"setlin bad cmfdb result","",cmresult.fcode);
+ makestr(&slmsg,"Internal error");
+ printf("?Internal parsing error\n");
+ return(-9);
+ }
+ }
+#endif /* OS2 */
+ if (!confirmed)
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ debug(F110,"setlin pre-cx_serial s",s,0);
+ debug(F110,"setlin pre-cx_serial line",line,0);
+ x = cx_serial(s,cx,sx,shr,zz,0,
+#ifdef OS2
+#ifdef NT
+ (xxtapi ? CX_TAPI : 0)
+#else
+ (xxslip ? CX_SLIP : 0) | (xxppp ? CX_PPP : 0)
+#endif /* NT */
+#else /* OS2 */
+ 0
+#endif /* OS2 */
+ );
+ debug(F111,"setlin cx_serial",line,x);
+ return(x);
+}
+#endif /* NOLOCAL */
+
+#ifdef CKCHANNELIO
+/*
+ C-Library based file-i/o package for scripts. This should be portable to
+ all C-Kermit versions since it uses the same APIs we have always used for
+ processing command files. The entire channel i/o package is contained
+ herein, apart from some keyword table entries in the main keyword table
+ and the help text in the HELP command module.
+
+ On platforms like VMS and VOS, this package handles only UNIX-style
+ stream files. If desired, it can be replaced for those platforms by
+ <#>ifdef'ing out this code and adding the equivalent replacement routines
+ to the ck?fio.c module, e.g. for RMS-based file i/o in ckvfio.c.
+*/
+#ifndef NOSTAT
+#ifdef VMS
+/* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
+#include <stat.h>
+#else /* def VMS */
+#include <sys/stat.h>
+#endif /* def VMS [else] */
+#endif /* NOSTAT */
+
+#ifdef NLCHAR
+static int z_lt = 1; /* Length of line terminator */
+#else
+static int z_lt = 2;
+#endif /* NLCHAR */
+
+struct ckz_file { /* C-Kermit file struct */
+ FILE * z_fp; /* Includes the C-Lib file struct */
+ unsigned int z_flags; /* Plus C-Kermit mode flags, */
+ CK_OFF_T z_nline; /* current line number if known, */
+ char z_name[CKMAXPATH+2]; /* and the file's name. */
+};
+static struct ckz_file ** z_file = NULL; /* Array of C-Kermit file structs */
+static int z_inited = 0; /* Flag for array initialized */
+int z_maxchan = Z_MAXCHAN; /* Max number of C-Kermit channels */
+int z_openmax = CKMAXOPEN; /* Max number of open files overall */
+int z_nopen = 0; /* How many channels presently open */
+int z_error = 0; /* Most recent error */
+int z_filcount = -1; /* Most recent FILE COUNT result */
+
+#define RD_LINE 0 /* FILE READ options */
+#define RD_CHAR 1
+#define RD_SIZE 2
+#define RD_TRIM 8 /* Like Snobol &TRIM = 1 */
+#define RD_UNTA 9 /* Untabify */
+
+#define WR_LINE RD_LINE /* FILE WRITE options */
+#define WR_CHAR RD_CHAR
+#define WR_SIZE RD_SIZE
+#define WR_STRI 3
+#define WR_LPAD 4
+#define WR_RPAD 5
+
+#ifdef UNIX
+extern int ckmaxfiles; /* Filled in by sysinit(). */
+#endif /* UNIX */
+
+/* See ckcker.h for error numbers */
+/* See ckcdeb.h for Z_MAXCHAN and CKMAXOPEN definitions */
+/* NOTE: For VMS we might be able to fill in ckmaxfiles */
+/* from FILLM and CHANNELCNT -- find out about these... */
+
+static char * fopnargs[] = { /* Mode combinations for fopen() */
+#ifdef COMMENT
+ /* All combinations of rwa */
+ "", "r", "w", "rw", "a", "ra", "wa", "rwa", /* Text mode */
+ "b", "rb", "wb", "rwb", "ab", "rab", "wab", "rwab" /* Binary mode */
+#else
+ /* Combinations and syntax permitted by C libraries... */
+ "", "r", "w", "r+", "a", "", "a", "", /* Text mode */
+#ifdef OS2
+ "", "rb", "wb", "r+b", "ab", "", "ab", "" /* Binary modes for K95 */
+#else
+#ifdef VMS
+ "", "rb", "wb", "r+b", "ab", "", "ab", "" /* Binary modes for VMS */
+#else
+ "", "r", "w", "r+", "a", "", "a", "" /* Binary modes for UNIX */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* COMMENT */
+};
+static int nfopnargs = sizeof(fopnargs) / sizeof(char *);
+
+char * /* Error messages */
+ckferror(n) int n; {
+ switch (n) {
+ case FX_NER: return("No error");
+ case FX_SYS: return(ck_errstr());
+ case FX_EOF: return("End of file");
+ case FX_NOP: return("File not open");
+ case FX_CHN: return("Channel out of range");
+ case FX_RNG: return("Parameter out of range");
+ case FX_NMF: return("Too many files open");
+ case FX_FOP: return("Operation conflicts with OPEN mode");
+ case FX_NYI: return("OPEN mode not supported");
+ case FX_BOM: return("Illegal combination of OPEN modes");
+ case FX_ACC: return("Access denied");
+ case FX_FNF: return("File not found");
+ case FX_OFL: return("Buffer overflow");
+ case FX_LNU: return("Current line number unknown");
+ case FX_ROO: return("Off limits");
+ case FX_UNK: return("Operation fails - reason unknown");
+ default: return("Error number out of range");
+ }
+}
+
+/*
+ Z _ O P E N -- Open a file for the requested type of access.
+
+ Call with:
+ name: Name of file to be opened.
+ flags: Any combination of FM_xxx values except FM_EOF (ckcker.h).
+ Returns:
+ >= 0 on success: The assigned channel number
+ < 0 on failure: A negative FX_xxx error code (ckcker.h).
+*/
+int
+z_open(name, flags) char * name; int flags; {
+ int i, n;
+ FILE * t;
+ char * mode;
+ debug(F111,"z_open",name,flags);
+ if (!name) name = ""; /* Check name argument */
+ if (!name[0])
+ return(z_error = FX_BFN);
+ if (flags & FM_CMD) /* Opening pipes not implemented yet */
+ return(z_error = FX_NYI); /* (and not portable either) */
+ debug(F101,"z_open nfopnargs","",nfopnargs);
+ if (flags < 0 || flags >= nfopnargs) /* Range check flags */
+ return(z_error = FX_RNG);
+ mode = fopnargs[flags]; /* Get fopen() arg */
+ debug(F111,"z_open fopen args",mode,flags);
+ if (!mode[0]) /* Check for illegal combinations */
+ return(z_error = FX_BOM);
+ if (!z_inited) { /* If file structs not inited */
+ debug(F101,"z_open z_maxchan 1","",z_maxchan);
+#ifdef UNIX
+ debug(F101,"z_open ckmaxfiles","",ckmaxfiles);
+ if (ckmaxfiles > 0) { /* Set in ck?tio.c: sysinit() */
+ int x;
+ x = ckmaxfiles - ZNFILS - 5;
+ if (x > z_maxchan) /* sysconf() value greater than */
+ z_maxchan = x; /* value from header files. */
+ debug(F101,"z_open z_maxchan 2","",z_maxchan);
+ }
+#endif /* UNIX */
+ if (z_maxchan < Z_MINCHAN) /* Allocate at least this many. */
+ z_maxchan = Z_MINCHAN;
+ debug(F101,"z_open z_maxchan 3","",z_maxchan);
+ /* Note: This could be a pretty big chunk of memory */
+ /* if z_maxchan is a big number. If this becomes a problem */
+ /* we'll need to malloc and free each element at open/close time */
+#ifdef COMMENT
+ /* May 2006 - it's time - in current Linux this about 3MB */
+ if (!(z_file = (struct ckz_file *)
+ malloc(sizeof(struct ckz_file) * (z_maxchan + 1))))
+ return(z_error = FX_NMF);
+ for (i = 0; i < z_maxchan; i++) {
+ z_file[i].z_fp = NULL;
+ z_file[i].z_flags = 0;
+ z_file[i].z_nline = 0;
+ *(z_file[i].z_name) = '\0';
+ }
+#else
+ /* New economical way, allocate storage for each channel as needed */
+ if (!z_file) {
+ z_file = (struct ckz_file **)malloc((z_maxchan + 1) *
+ sizeof(struct ckz_file *));
+ if (!z_file)
+ return(z_error = FX_NMF);
+ for (i = 0; i < z_maxchan; i++)
+ z_file[i] = NULL;
+ }
+#endif /* COMMENT */
+ z_inited = 1; /* Remember we initialized */
+ }
+ for (n = -1, i = 0; i < z_maxchan; i++) { /* Find a free channel */
+#ifdef COMMENT
+ if (!z_file[i].z_fp) {
+ n = i;
+ break;
+ }
+#else
+ if (!z_file[i]) {
+ z_file[i] = (struct ckz_file *) malloc(sizeof(struct ckz_file));
+ if (!z_file[i])
+ return(z_error = FX_NMF);
+ n = i;
+ break;
+ }
+#endif /* COMMENT */
+
+ }
+ if (n < 0 || n >= z_maxchan) /* Any free channels? */
+ return(z_error = FX_NMF); /* No, fail. */
+ errno = 0;
+
+ z_file[n]->z_flags = 0; /* In case of failure... */
+ z_file[n]->z_fp = NULL; /* Set file pointer to NULL */
+
+ t = fopen(name, mode); /* Try to open the file. */
+ if (!t) { /* Failed... */
+ debug(F111,"z_open error",name,errno);
+#ifdef EMFILE
+ if (errno == EMFILE)
+ return(z_error = FX_NMF);
+#endif /* EMFILE */
+ free(z_file[n]);
+ z_file[n] = NULL;
+ return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error code */
+ }
+#ifdef NT
+#ifdef O_SEQUENTIAL
+ if (t) /* Caching hint for NT */
+ _setmode(_fileno(t),O_SEQUENTIAL);
+#endif /* O_SEQUENTIAL */
+#endif /* NT */
+ z_nopen++; /* Open, count it. */
+ z_file[n]->z_fp = t; /* Stash the file pointer */
+ z_file[n]->z_flags = flags; /* and the flags */
+ z_file[n]->z_nline = 0; /* Current line number is 0 */
+ z_error = 0;
+ zfnqfp(name,CKMAXPATH,z_file[n]->z_name); /* and the file's full name */
+ return(n); /* Return the channel number */
+}
+
+int
+z_close(channel) int channel; { /* Close file on given channel */
+ int x;
+ FILE * t;
+ if (!z_inited) /* Called before any files are open? */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan) /* Channel out of range? */
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp)) /* Channel wasn't open? */
+ return(z_error = FX_NOP);
+ errno = 0; /* Set errno 0 to get a good reading */
+ x = fclose(t); /* Try to close */
+ if (x == EOF) /* On failure */
+ return(z_error = FX_SYS); /* indicate system error. */
+ z_nopen--; /* Closed OK, decrement open count */
+ z_file[channel]->z_fp = NULL; /* Set file pointer to NULL */
+ z_file[channel]->z_nline = 0; /* Current line number is 0 */
+ z_file[channel]->z_flags = 0; /* Set flags to 0 */
+ *(z_file[channel]->z_name) = '\0'; /* Clear name */
+ free(z_file[channel]);
+ z_file[channel] = NULL;
+ return(z_error = 0);
+}
+
+/*
+ Z _ O U T -- Output string to channel.
+
+ Call with:
+ channel: Channel number to write to.
+ s: String to write.
+ length > -1: How many characters of s to write.
+ length < 0: Write entire NUL-terminated string.
+ flags == 0: Supply line termination.
+ flags > 0: Don't supply line termination.
+ flags < 0: Write 'length' NUL characters.
+ Special case:
+ If flags > -1 and s is empty or NULL and length == 1, write 1 NUL.
+ Returns:
+ Number of characters written to channel on success, or
+ negative FX_xxx error code on failure.
+*/
+int
+z_out(channel,s,length,flags) int channel, flags, length; char * s; {
+ FILE * t;
+ int x, n;
+ char c = '\0';
+
+ if (!s) s = ""; /* Guard against null pointer */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"z_out",s,channel);
+ debug(F101,"z_out length","",length);
+ debug(F101,"z_out flags","",flags);
+ }
+#endif /* DEBUG */
+ if (!z_inited) /* File i/o inited? */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan) /* Channel in range? */
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp)) /* File open? */
+ return(z_error = FX_NOP);
+ if (!((z_file[channel]->z_flags) & (FM_WRI|FM_APP))) /* In write mode? */
+ return(z_error = FX_FOP);
+ n = length; /* Length of string to write */
+ if (n < 0) { /* Negative means get it ourselves */
+ if (flags < 0) /* Except when told to write NULs in */
+ return(z_error = FX_RNG); /* which case args are inconsistent */
+ n = strlen(s); /* Get length of string arg */
+ }
+ errno = 0; /* Reset errno */
+ debug(F101,"z_out n","",n);
+ if (flags < 0) { /* Writing NULs... */
+ int i;
+ for (i = 0; i < n; i++) {
+ x = fwrite(&c,1,1,t);
+ if (x < 1)
+ return(z_error = (errno ? FX_SYS : FX_UNK));
+ }
+ z_file[channel]->z_nline = -1; /* Current line no longer known */
+ z_error = 0;
+ return(i);
+ } else { /* Writing string arg */
+ if (n == 1 && !s[0]) /* Writing one char but it's NUL */
+ x = fwrite(&c,1,1,t);
+ else /* Writing non-NUL char or string */
+ x = fwrite(s,1,n,t);
+ debug(F101,"z_out fwrite",ckitoa(x),errno);
+ if (x < n) /* Failure to write requested amount */
+ return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error */
+ if (flags == 0) { /* If supplying line termination */
+ if (fwrite("\n",1,1,t)) /* do that */
+ x += z_lt; /* count the terminator */
+ if (z_file[channel]->z_nline > -1) /* count this line */
+ z_file[channel]->z_nline++;
+ } else {
+ z_file[channel]->z_nline = -1; /* Current line no longer known */
+ }
+ }
+ z_error = 0;
+ return(x);
+}
+
+#define Z_INBUFLEN 64
+
+/*
+ Z _ I N -- Multichannel i/o file input function.
+
+ Call with:
+ channel number to read from.
+ s = address of destination buffer.
+ buflen = destination buffer length.
+ length = Number of bytes to read, must be < buflen.
+ flags: 0 = read a line; nonzero = read the given number of bytes.
+ Returns:
+ Number of bytes read into buffer or a negative error code.
+ A terminating NUL is deposited after the last byte that was read.
+*/
+int
+z_in(channel,s,buflen,length,flags)
+ int channel, buflen, length, flags; char * s;
+/* z_in */ {
+ int i, j, x;
+ FILE * t;
+ char * p;
+
+ if (!z_inited) /* Check everything... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ if (!((z_file[channel]->z_flags) & FM_REA))
+ return(z_error = FX_FOP);
+ if (!s) /* Check destination */
+ return(z_error = FX_RNG);
+ s[0] = NUL;
+ if (length == 0) /* Read 0 bytes - easy. */
+ return(z_error = 0);
+ debug(F101,"z_in channel","",channel);
+ debug(F101,"z_in buflen","",buflen);
+ debug(F101,"z_in length","",length);
+ debug(F101,"z_in flags","",flags);
+ if (length < 0 || buflen < 0) /* Check length args */
+ return(z_error = FX_RNG);
+ if (buflen <= length)
+ return(z_error = FX_RNG);
+ errno = 0; /* Reset errno */
+ if (flags) { /* Read block or byte */
+ int n; /* 20050912 */
+ n = length; /* 20050912 */
+ i = 0; /* 20050912 */
+ while (n > 0) { /* 20050912 */
+ i = fread(s,1,n,t); /* 20050912 */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"z_in block",s,i);
+ debug(F101,"z_in block errno","",errno);
+ debug(F101,"z_in block ferror","",ferror(t));
+ debug(F101,"z_in block feof","",feof(t));
+ }
+#endif /* DEBUG */
+ if (i == 0) break; /* 20050912 */
+ s += i; /* 20050912 */
+ n -= i; /* 20050912 */
+ }
+ /* Current line no longer known */
+ z_file[channel]->z_nline = (CK_OFF_T)-1;
+ } else { /* Read line */
+#ifndef COMMENT
+ /* This method is used because it's simpler than the others */
+ /* and also marginally faster. */
+ debug(F101,"z_in getc loop","",CKFTELL(t));
+ for (i = 0; i < length; i++) {
+ if ((x = getc(t)) == EOF) {
+ debug(F101,"z_in getc error","",CKFTELL(t));
+ s[i] = '\0';
+ break;
+ }
+ s[i] = x;
+ if (s[i] == '\n') {
+ s[i] = '\0';
+ break;
+ }
+ }
+ debug(F111,"z_in line byte loop",ckitoa(errno),i);
+ debug(F111,"z_in line got",s,z_file[channel]->z_nline);
+ if (z_file[channel]->z_nline > -1)
+ z_file[channel]->z_nline++;
+#else
+#ifdef COMMENT2
+ /* Straightforward but strlen() slows it down. */
+ s[0] = '\0';
+ i = 0;
+ if (fgets(s,length,t)) {
+ i = strlen(s);
+ if (i > 0 && s[i-1] == '\n') i--;
+ }
+ debug(F111,"z_in line fgets",ckitoa(errno),i);
+ if (z_file[channel]->z_nline > -1)
+ z_file[channel]->z_nline++;
+#else
+ /* This is a do-it-yourself fgets() with its own readahead and */
+ /* putback. It's a bit faster than real fgets() but not enough */
+ /* to justify the added complexity or the risk of the ftell() and */
+ /* fseek() calls failing. */
+ int k, flag = 0;
+ CK_OFF_T pos;
+ for (i = 0; !flag && i <= (length - Z_INBUFLEN); i += Z_INBUFLEN) {
+ k = ((length - i) < Z_INBUFLEN) ? length - i : Z_INBUFLEN;
+ if ((x = fread(s+i,1,k,t)) < 1)
+ break;
+ s[i+x] = '\0';
+ for (j = 0; j < x; j++) {
+ if (s[i+j] == '\n') {
+ s[i+j] = '\0';
+ flag ++;
+ pos = CKFTELL(t);
+ if (pos > -1) {
+ pos -= (x - j - 1);
+ x = CKFSEEK(t, pos, 0);
+ i += j;
+ break;
+ } else
+ return(z_error = FX_SYS);
+ }
+ }
+ }
+ if (z_file[channel]->z_nline > -1)
+ z_file[channel]->z_nline++;
+ debug(F111,"z_in line chunk loop",ckitoa(errno),i);
+#endif /* COMMENT2 */
+#endif /* COMMENT */
+ }
+ debug(F111,"z_in i",ckitoa(errno),i);
+ if (i < 0) i = 0; /* NUL-terminate result */
+ s[i] = '\0';
+ if (i > 0) {
+ z_error = 0;
+ return(i);
+ }
+ if (i == 0 && feof(t)) /* EOF on reading? */
+ return(z_error = FX_EOF); /* Return EOF code */
+ return(errno ? (z_error = -1) : i); /* Return length or system error */
+}
+
+int
+z_flush(channel) int channel; { /* Flush output channel */
+ FILE * t;
+ int x;
+ if (!z_inited) /* Regular checks */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ if (!((z_file[channel]->z_flags) & (FM_WRI|FM_APP))) /* Write access? */
+ return(z_error = FX_FOP);
+ errno = 0; /* Reset errno */
+ x = fflush(t); /* Try to flush */
+ return(x ? (z_error = FX_SYS) : 0); /* Return system error or 0 if OK */
+}
+
+int
+#ifdef CK_ANSIC
+z_seek(int channel, CK_OFF_T pos) /* Move file pointer to byte */
+#else
+z_seek(channel,pos) int channel; CK_OFF_T pos; /* (seek to given position) */
+#endif /* CK_ANSIC */
+{
+ int i, x = 0, rc;
+ FILE * t;
+ if (!z_inited) /* Check... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ if (pos < 0L) {
+ x = 2;
+ pos = (pos == -2) ? -1L : 0L;
+ }
+ errno = 0;
+ rc = CKFSEEK(t,pos,x); /* Try to seek */
+ debug(F111,"z_seek",ckitoa(errno),rc);
+ if (rc < 0) /* OK? */
+ return(z_error = FX_SYS); /* No. */
+ z_file[channel]->z_nline = ((pos || x) ? -1 : 0);
+ return(z_error = 0);
+}
+
+int
+#ifdef CK_ANSIC
+z_line(int channel, CK_OFF_T pos) /* Move file pointer to line */
+#else
+z_line(channel,pos) int channel; CK_OFF_T pos; /* (seek to given position) */
+#endif /* CK_ANSIC */
+{
+ int i, len, x = 0;
+ CK_OFF_T current = (CK_OFF_T)0, prev = (CK_OFF_T)-1, old = (CK_OFF_T)-1;
+ FILE * t;
+ char tmpbuf[256];
+ if (!z_inited) /* Check... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ debug(F101,"z_line pos","",pos);
+ if (pos < 0L) { /* EOF wanted */
+ CK_OFF_T n;
+ n = z_file[channel]->z_nline;
+ debug(F101,"z_line n","",n);
+ if (n < 0 || pos < 0) {
+ rewind(t);
+ n = 0;
+ }
+ while (1) { /* This could take a while... */
+ if ((x = getc(t)) == EOF)
+ break;
+ if (x == '\n') {
+ n++;
+ if (pos == -2) {
+ old = prev;
+ prev = CKFTELL(t);
+ }
+ }
+ }
+ debug(F101,"z_line old","",old);
+ debug(F101,"z_line prev","",prev);
+ if (pos == -2) {
+ if ((x = z_seek(channel,old)) < 0)
+ return(z_error = x);
+ else
+ n--;
+ }
+ z_file[channel]->z_nline = n;
+ return(z_error = 0);
+ }
+ if (pos == 0L) { /* Rewind wanted */
+ z_file[channel]->z_nline = 0L;
+ rewind(t);
+ debug(F100,"z_line rewind","",0);
+ return(0L);
+ }
+ tmpbuf[255] = NUL; /* Make sure buf is NUL terminated */
+ current = z_file[channel]->z_nline; /* Current line */
+ /*
+ If necessary the following could be optimized, e.g. for positioning
+ to a previous line in a large file without starting over.
+ */
+ if (current < 0 || pos < current) { /* Not known or behind us... */
+ debug(F101,"z_line rewinding","",pos);
+ if ((x = z_seek(channel, 0L)) < 0) /* Rewind */
+ return(z_error = x);
+ if (pos == 0) /* If 0th line wanted we're done */
+ return(z_error = 0);
+ current = 0;
+ }
+ while (current < pos) { /* Search for specified line */
+ if (fgets(tmpbuf,255,t)) {
+ len = strlen(tmpbuf);
+ if (len > 0 && tmpbuf[len-1] == '\n') {
+ current++;
+ debug(F111,"z_line read",ckitoa(len),current);
+ } else if (len == 0) {
+ return(z_error = FX_UNK);
+ }
+ } else {
+ z_file[channel]->z_nline = -1L;
+ debug(F101,"z_line premature EOF","",current);
+ return(z_error = FX_EOF);
+ }
+ }
+ z_file[channel]->z_nline = current;
+ debug(F101,"z_line result","",current);
+ z_error = 0;
+ return(current);
+}
+
+char *
+z_getname(channel) int channel; { /* Return name of file on channel */
+ FILE * t;
+ if (!z_inited) {
+ z_error = FX_NOP;
+ return(NULL);
+ }
+ if (channel >= z_maxchan) {
+ z_error = FX_CHN;
+ return(NULL);
+ }
+ if (!z_file[channel]) {
+ z_error = FX_NOP;
+ return(NULL);
+ }
+ if (!(t = z_file[channel]->z_fp)) {
+ z_error = FX_NOP;
+ return(NULL);
+ }
+ return((char *)(z_file[channel]->z_name));
+}
+
+int
+z_getmode(channel) int channel; { /* Return OPEN modes of channel */
+ FILE * t; /* 0 if file not open */
+#ifndef NOSTAT
+#ifdef NT
+ struct _stat statbuf;
+#else /* NT */
+ struct stat statbuf;
+#endif /* NT */
+#endif /* NOSTAT */
+ int x;
+ if (!z_inited)
+ return(0);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(0);
+ if (!(t = z_file[channel]->z_fp))
+ return(0);
+ x = z_file[channel]->z_flags;
+ if (feof(t)) { /* This might not work for */
+ x |= FM_EOF; /* output files */
+#ifndef NOSTAT
+ /* But this does if we can use it. */
+ } else if (stat(z_file[channel]->z_name,&statbuf) > -1) {
+ if (CKFTELL(t) == statbuf.st_size)
+ x |= FM_EOF;
+#endif /* NOSTAT */
+ }
+ return(x);
+}
+
+CK_OFF_T
+z_getpos(channel) int channel; { /* Get file pointer position */
+ FILE * t; /* on this channel */
+ CK_OFF_T x;
+ if (!z_inited)
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ x = CKFTELL(t);
+ return((x < 0L) ? (z_error = FX_SYS) : x);
+}
+
+CK_OFF_T
+z_getline(channel) int channel; { /* Get current line number */
+ FILE * t; /* in file on this channel */
+ CK_OFF_T rc;
+ if (!z_inited)
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ debug(F101,"z_getline","",z_file[channel]->z_nline);
+ rc = z_file[channel]->z_nline;
+ return((rc < 0) ? (z_error = FX_LNU) : rc);
+}
+
+int
+z_getfnum(channel) int channel; { /* Get file number / handle */
+ FILE * t; /* for file on this channel */
+ if (!z_inited)
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ z_error = 0;
+ return(fileno(t));
+}
+
+/*
+ Line-oriented counts and seeks are as dumb as they can be at the moment.
+ Later we can speed them up by building little indexes.
+*/
+CK_OFF_T
+z_count(channel, what) int channel, what; { /* Count bytes or lines in file */
+ FILE * t;
+ int i, x;
+ CK_OFF_T pos, count = (CK_OFF_T)0;
+ if (!z_inited) /* Check stuff... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!z_file[channel])
+ return(z_error = FX_NOP);
+ if (!(t = z_file[channel]->z_fp))
+ return(z_error = FX_NOP);
+ pos = CKFTELL(t); /* Save current file pointer */
+ errno = 0;
+ z_error = 0;
+ if (what == RD_CHAR) { /* Size in bytes requested */
+#ifdef COMMENT
+ if (!CKFSEEK(t,0L,2)) { /* Seek to end */
+ count = CKFTELL(t); /* Get file pointer */
+ CKFSEEK(t,pos,0); /* Restore file file pointer */
+ return(count);
+ } else /* Fallback in case seek fails */
+#endif /* COMMENT */
+ return(zgetfs(z_file[channel]->z_name));
+ }
+ rewind(t); /* Line count requested - rewind. */
+ while (1) { /* Count lines. */
+ if ((x = getc(t)) == EOF) /* Stupid byte loop */
+ break; /* but it works as well as anything */
+ if (x == '\n') /* else... */
+ count++;
+ }
+ x = CKFSEEK(t,pos,0); /* Restore file pointer */
+ return(count);
+}
+
+/* User interface for generalized channel-oriented file i/o */
+
+struct keytab fctab[] = { /* FILE subcommands */
+ { "close", FIL_CLS, 0 },
+ { "count", FIL_COU, 0 },
+ { "flush", FIL_FLU, 0 },
+ { "list", FIL_LIS, 0 },
+ { "open", FIL_OPN, 0 },
+ { "read", FIL_REA, 0 },
+ { "rewind", FIL_REW, 0 },
+ { "seek", FIL_SEE, 0 },
+ { "status", FIL_STA, 0 },
+ { "write", FIL_WRI, 0 }
+};
+int nfctab = (sizeof (fctab) / sizeof (struct keytab));
+
+static struct keytab fcswtab[] = { /* OPEN modes */
+ { "/append", FM_APP, 0 },
+ { "/binary", FM_BIN, 0 },
+#ifdef COMMENT
+ { "/command", FM_CMD, 0 }, /* Not implemented */
+#endif /* COMMENT */
+ { "/read", FM_REA, 0 },
+ { "/write", FM_WRI, 0 }
+};
+static int nfcswtab = (sizeof (fcswtab) / sizeof (struct keytab));
+
+static struct keytab fclkwtab[] = { /* CLOSE options */
+ { "all", 1, 0 }
+};
+
+static struct keytab fsekwtab[] = { /* SEEK symbols */
+ { "eof", 1, 0 },
+ { "last", 2, 0 }
+};
+static int nfsekwtab = (sizeof (fsekwtab) / sizeof (struct keytab));
+
+#define SEE_LINE RD_LINE /* SEEK options */
+#define SEE_CHAR RD_CHAR
+#define SEE_REL 3
+#define SEE_ABS 4
+#define SEE_FIND 5
+
+static struct keytab fskswtab[] = {
+ { "/absolute", SEE_ABS, 0 },
+ { "/byte", SEE_CHAR, 0 },
+ { "/character", SEE_CHAR, CM_INV },
+ { "/find", SEE_FIND, CM_ARG },
+ { "/line", SEE_LINE, 0 },
+ { "/relative", SEE_REL, 0 }
+};
+static int nfskswtab = (sizeof (fskswtab) / sizeof (struct keytab));
+
+#define COU_LINE RD_LINE /* COUNT options */
+#define COU_CHAR RD_CHAR
+#define COU_LIS 3
+#define COU_NOL 4
+
+static struct keytab fcoswtab[] = {
+ { "/bytes", COU_CHAR, 0 },
+ { "/characters",COU_CHAR, CM_INV },
+ { "/lines", COU_LINE, 0 },
+ { "/list", COU_LIS, 0 },
+ { "/nolist", COU_NOL, 0 },
+ { "/quiet", COU_NOL, CM_INV }
+};
+static int nfcoswtab = (sizeof (fcoswtab) / sizeof (struct keytab));
+
+static struct keytab frdtab[] = { /* READ types */
+ { "/block", RD_SIZE, CM_INV|CM_ARG },
+ { "/byte", RD_CHAR, CM_INV },
+ { "/character", RD_CHAR, 0 },
+ { "/line", RD_LINE, 0 },
+ { "/size", RD_SIZE, CM_ARG },
+ { "/trim", RD_TRIM, 0 },
+ { "/untabify", RD_UNTA, 0 }
+};
+static int nfrdtab = (sizeof (frdtab) / sizeof (struct keytab));
+
+static struct keytab fwrtab[] = { /* WRITE types */
+ { "/block", WR_SIZE, CM_INV|CM_ARG },
+ { "/byte", WR_CHAR, CM_INV },
+ { "/character", WR_CHAR, 0 },
+ { "/line", WR_LINE, 0 },
+ { "/lpad", WR_LPAD, CM_ARG },
+ { "/rpad", WR_RPAD, CM_ARG },
+ { "/size", WR_SIZE, CM_ARG },
+ { "/string", WR_STRI, 0 }
+};
+static int nfwrtab = (sizeof (fwrtab) / sizeof (struct keytab));
+
+static char blanks[] = "\040\040\040\040"; /* Some blanks for formatting */
+static char * seek_target = NULL;
+
+int
+dofile(op) int op; { /* Do the FILE command */
+ char vnambuf[VNAML]; /* Buffer for variable names */
+ char *vnp = NULL; /* Pointer to same */
+ char zfilnam[CKMAXPATH+2];
+ char * p, * m;
+ struct FDB fl, sw, nu;
+ CK_OFF_T z;
+ int rsize, filmode = 0, relative = -1, eofflg = 0;
+ int rc, x, y, cx, n, getval, dummy, confirmed, listing = -1;
+ int charflag = 0, sizeflag = 0;
+ int pad = 32, wr_lpad = 0, wr_rpad = 0, rd_trim = 0, rd_untab = 0;
+
+ makestr(&seek_target,NULL);
+
+ if (op == XXFILE) { /* FILE command was given */
+ /* Get subcommand */
+ if ((cx = cmkey(fctab,nfctab,"Operation","",xxstring)) < 0) {
+ if (cx == -3) {
+ printf("?File operation required\n");
+ x = -9;
+ }
+ return(cx);
+ }
+ } else { /* Shorthand command was given */
+ switch (op) {
+ case XXF_CL: cx = FIL_CLS; break; /* FCLOSE */
+ case XXF_FL: cx = FIL_FLU; break; /* FFLUSH */
+ case XXF_LI: cx = FIL_LIS; break; /* FLIST */
+ case XXF_OP: cx = FIL_OPN; break; /* etc... */
+ case XXF_RE: cx = FIL_REA; break;
+ case XXF_RW: cx = FIL_REW; break;
+ case XXF_SE: cx = FIL_SEE; break;
+ case XXF_ST: cx = FIL_STA; break;
+ case XXF_WR: cx = FIL_WRI; break;
+ case XXF_CO: cx = FIL_COU; break;
+ default: return(-2);
+ }
+ }
+ switch (cx) { /* Do requested subcommand */
+ case FIL_OPN: /* OPEN */
+ cmfdbi(&sw, /* Switches */
+ _CMKEY, /* fcode */
+ "Variable or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nfcswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ fcswtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "Variable", /* hlpmsg */
+ "",
+ "",
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+ while (1) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Variable name and file name required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMFLD)
+ break;
+ else if (cmresult.fcode == _CMKEY) {
+ char c;
+ c = cmgbrk();
+ if ((getval =
+ (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+#ifdef COMMENT
+ /* Uncomment if we add any switches here that take args */
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9); /* (none do...) */
+ }
+#endif /* COMMENT */
+ filmode |= cmresult.nresult; /* OR in the file mode */
+ } else
+ return(-2);
+ }
+ /* Not a switch - get the string */
+ ckstrncpy(vnambuf,cmresult.sresult,VNAML);
+ if (!vnambuf[0] || chknum(vnambuf)) { /* (if there is one...) */
+ printf("?Variable name required\n");
+ return(-9);
+ }
+ vnp = vnambuf; /* Check variable-name syntax */
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&dummy)) < 0) {
+ printf("?Syntax error in variable name\n");
+ return(-9);
+ }
+ }
+ /* Assign a negative channel number in case we fail */
+ addmac(vnambuf,"-1");
+
+ if (!(filmode & FM_RWA)) /* If no access mode specified */
+ filmode |= FM_REA; /* default to /READ. */
+
+ y = 0; /* Now parse the filename */
+ if ((filmode & FM_RWA) == FM_WRI) {
+ x = cmofi("Name of new file","",&s,xxstring);
+ } else if ((filmode & FM_RWA) == FM_REA) {
+ x = cmifi("Name of existing file","",&s,&y,xxstring);
+ } else {
+ x = cmiofi("Filename","",&s,&y,xxstring);
+ debug(F111,"fopen /append x",s,x);
+ }
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Filename required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (y) { /* No wildcards */
+ printf("?Wildcards not allowed here\n");
+ return(-9);
+ }
+ if (filmode & (FM_APP|FM_WRI)) { /* Check output access */
+#ifndef VMS
+ if (zchko(s) < 0) { /* and set error code if denied */
+ z_error = FX_ACC;
+ printf("?Write access denied - \"%s\"\n",s);
+ return(-9);
+ }
+#endif /* VMS */
+ }
+ ckstrncpy(zfilnam,s,CKMAXPATH); /* Is OK - make safe copy */
+ if ((x = cmcfm()) < 0) /* Get confirmation of command */
+ return(x);
+ if ((n = z_open(zfilnam,filmode)) < 0) {
+ printf("?OPEN failed - %s: %s\n",zfilnam,ckferror(n));
+ return(-9);
+ }
+ addmac(vnambuf,ckitoa(n)); /* Assign channel number to variable */
+ return(success = 1);
+
+ case FIL_REW: /* REWIND */
+ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+
+ if ((rc = z_seek(n,0L)) < 0) {
+ printf("?REWIND failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ return(success = 1);
+
+ case FIL_CLS: /* CLOSE */
+#ifdef COMMENT /* fdc 20100804 - bad idea */
+ {
+ int i, j, k; /* Supply default if only one open */
+ s = "";
+ for (k = 0, j = 0, i = 0; i < z_maxchan; i++) {
+ if (z_file)
+ if (z_file[i])
+ if (z_file[i]->z_fp) { k++; j = i; }
+ }
+ if (k == 1) s = ckitoa(j);
+ }
+#endif /* COMMENT */
+ cmfdbi(&nu, /* Second FDB - channel number */
+ _CMNUM, /* fcode */
+ "Channel number or ALL", /* Help message */
+ s, /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ &sw /* Pointer to next FDB */
+ ); /* Pointer to next FDB */
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "", /* help message */
+ "", /* Default */
+ "", /* No addtl string data */
+ 1, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ fclkwtab, /* Keyword table */
+ NULL /* Last in chain */
+ );
+ x = cmfdb(&nu); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number or ALL required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM)
+ n = cmresult.nresult;
+ else if (cmresult.fcode == _CMKEY)
+ n = -1;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+
+ rc = 1;
+ if (n < 0) {
+ int count = 0;
+ int i;
+ for (i = 0; i < z_maxchan; i++) {
+ x = z_close(i);
+ if (x == FX_SYS) {
+ printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x));
+ rc = 0;
+ } else if (x > -1)
+ count++;
+ }
+ debug(F101,"FILE CLOSE ALL","",count);
+ } else if ((x = z_close(n)) < 0) {
+ printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x));
+ return(-9);
+ }
+ return(success = rc);
+
+ case FIL_REA: /* READ */
+ case FIL_WRI: /* WRITE */
+ rsize = 0;
+ cmfdbi(&sw, /* Switches */
+ _CMKEY, /* fcode */
+ "Channel or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ (cx == FIL_REA) ? nfrdtab : nfwrtab,
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ (cx == FIL_REA) ? frdtab : fwrtab, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* Channel number */
+ _CMNUM, /* fcode */
+ "Channel",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ do {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM) /* Channel number */
+ break;
+ else if (cmresult.fcode == _CMKEY) { /* Switch */
+ char c;
+ c = cmgbrk();
+ if ((getval =
+ (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case WR_LINE:
+ charflag = 0;
+ sizeflag = 0;
+ rsize = 0;
+ break;
+ case WR_CHAR:
+ rsize = 1;
+ charflag = 1;
+ sizeflag = 1;
+ break;
+ case WR_SIZE:
+ if ((x = cmnum("Bytes","",10,&rsize, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (rsize > LINBUFSIZ) {
+ printf("?Maximum FREAD/FWRITE size is %d\n",LINBUFSIZ);
+ rsize = 0;
+ return(-9);
+ }
+ charflag = 0;
+ sizeflag = 1;
+ break;
+ case WR_STRI:
+ rsize = 1;
+ charflag = 0;
+ sizeflag = 0;
+ break;
+ case WR_LPAD:
+ case WR_RPAD:
+ if ((x = cmnum("Numeric ASCII character value",
+ "32",10,&pad, xxstring)) < 0)
+ return(x);
+ if (cmresult.nresult == WR_LPAD)
+ wr_lpad = 1;
+ else
+ wr_rpad = 1;
+ break;
+ case RD_TRIM:
+ rd_trim = 1;
+ break;
+ case RD_UNTA:
+ rd_untab = 1;
+ break;
+ }
+ debug(F101,"FILE READ rsize 2","",rsize);
+ } else
+ return(-2);
+ } while
+ (cmresult.fcode == _CMKEY);
+
+ n = cmresult.nresult; /* Channel */
+ debug(F101,"FILE READ/WRITE channel","",n);
+
+ if (cx == FIL_WRI) { /* WRITE */
+ int len = 0;
+ if ((x = cmtxt("Text","",&s,xxstring)) < 0)
+ return(x);
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */
+ s = line;
+ s = brstrip(s); /* Strip braces */
+ if (charflag) { /* Write one char */
+ len = 1; /* So length = 1 */
+ rsize = 1; /* Don't supply terminator */
+ } else if (!sizeflag) { /* Write a string */
+ len = -1; /* So length is unspecified */
+ } else { /* Write a block of given size */
+ int i, k, xx;
+ if (rsize > TMPBUFSIZ) {
+ z_error = FX_OFL;
+ printf("?Buffer overflow\n");
+ return(-9);
+ }
+ len = rsize; /* rsize is really length */
+ rsize = 1; /* Don't supply a terminator */
+ xx = strlen(s); /* Size of given string */
+ if (xx >= len) { /* Bigger or equal */
+ s[len] = NUL;
+ } else if (wr_lpad) { /* Smaller, left-padding requested */
+ for (i = 0; i < len - xx; i++) /* Must make a copy */
+ tmpbuf[i] = pad;
+ ckstrncpy(tmpbuf+i,s,TMPBUFSIZ-i);
+ tmpbuf[len] = NUL;
+ s = tmpbuf; /* Redirect write source */
+ } else if (wr_rpad) { /* Smaller with right-padding */
+ for (i = xx; i < len; i++)
+ s[i] = pad;
+ s[len] = NUL;
+ }
+ }
+ if ((rc = z_out(n,s,len,rsize)) < 0) { /* Try to write */
+ printf("?Channel %d WRITE error: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ } else { /* FIL_REA READ */
+ confirmed = 0;
+ vnambuf[0] = NUL;
+ x = cmfld("Variable name","",&s,NULL);
+ debug(F111,"FILE READ cmfld",s,x);
+ if (x < 0) {
+ if (x == -3 || !*s) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ else
+ confirmed++;
+ } else
+ return(x);
+ }
+ ckstrncpy(vnambuf,s,VNAML);
+ debug(F111,"FILE READ vnambuf",vnambuf,confirmed);
+ if (vnambuf[0]) { /* Variable name given, check it */
+ if (!confirmed) {
+ x = cmcfm();
+ if (x < 0)
+ return(x);
+ else
+ confirmed++;
+ }
+ vnp = vnambuf;
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&dummy)) < 0) {
+ printf("?Syntax error in variable name\n");
+ return(-9);
+ }
+ }
+ }
+ debug(F111,"FILE READ variable",vnambuf,confirmed);
+
+ if (!confirmed)
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+
+ line[0] = NUL; /* Clear destination buffer */
+#ifdef COMMENT
+ if (rsize >= LINBUFSIZ) /* Don't overrun it */
+ rsize = LINBUFSIZ - 1;
+#endif /* COMMENT */
+
+ if (rsize == 0) { /* Read a line */
+ rc = z_in(n,line,LINBUFSIZ,LINBUFSIZ-1,0);
+ } else {
+ rc = z_in(n,line,LINBUFSIZ,rsize,1); /* Read a block */
+ }
+ if (rc < 0) { /* Error... */
+ debug(F101,"FILE READ error","",rc);
+ debug(F101,"FILE READ errno","",errno);
+ if (rc == FX_EOF) { /* EOF - fail but no error message */
+ return(success = 0);
+ } else { /* Other error - fail and print msg */
+ printf("?READ error: %s\n",ckferror(rc));
+ return(-9);
+ }
+ }
+ if (rsize == 0) { /* FREAD /LINE postprocessing */
+ if (rd_trim) { /* Trim */
+ int i, k;
+ k = strlen(line);
+ if (k > 0) {
+ for (i = k-1; i > 0; i--) {
+ if (line[i] == SP || line[i] == '\t')
+ line[i] = NUL;
+ else
+ break;
+ }
+ }
+ }
+ if (rd_untab) { /* Untabify */
+ if (untabify(line,tmpbuf,TMPBUFSIZ) > -1)
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ }
+ debug(F110,"FILE READ data",line,0);
+ if (vnambuf[0]) /* Read OK - If variable name given */
+ addmac(vnambuf,line); /* Assign result to variable */
+ else /* otherwise */
+ printf("%s\n",line); /* just print it */
+ }
+ return(success = 1);
+
+ case FIL_SEE: /* SEEK */
+ case FIL_COU: /* COUNT */
+ rsize = RD_CHAR; /* Defaults to /BYTE */
+ cmfdbi(&sw, /* Switches */
+ _CMKEY, /* fcode */
+ "Channel or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ ((cx == FIL_SEE) ? nfskswtab : nfcoswtab),
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ ((cx == FIL_SEE) ? fskswtab : fcoswtab),
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* Channel number */
+ _CMNUM, /* fcode */
+ "Channel",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ do {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM) /* Channel number */
+ break;
+ else if (cmresult.fcode == _CMKEY) { /* Switch */
+ char c;
+ c = cmgbrk();
+ if ((getval =
+ (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (cx == FIL_SEE) {
+ switch (cmresult.nresult) {
+ case SEE_REL: relative = 1; break;
+ case SEE_ABS: relative = 0; break;
+ case SEE_FIND: {
+ if (getval) {
+ y = cmfld("string or pattern","",&s,xxstring);
+ if (y < 0)
+ return(y);
+ makestr(&seek_target,brstrip(s));
+ break;
+ }
+ }
+ default: rsize = cmresult.nresult;
+ }
+ } else if (cx == FIL_COU) {
+ switch (cmresult.nresult) {
+ case COU_LIS: listing = 1; break;
+ case COU_NOL: listing = 0; break;
+ default: rsize = cmresult.nresult;
+ }
+ }
+ }
+ } while
+ (cmresult.fcode == _CMKEY);
+
+ n = cmresult.nresult; /* Channel */
+ debug(F101,"FILE SEEK/COUNT channel","",n);
+ if (cx == FIL_COU) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+
+ z_filcount = z_count(n,rsize);
+ if (z_filcount < 0) {
+ rc = z_filcount;
+ printf("?COUNT error: %s\n",ckferror(rc));
+ return(-9);
+ }
+ if (listing < 0)
+ listing = !xcmdsrc;
+ if (listing)
+ printf(" %ld %s%s\n",
+ z_filcount,
+ ((rsize == RD_CHAR) ? "byte" : "line"),
+ ((z_filcount == 1L) ? "" : "s")
+ );
+ return(success = (z_filcount > -1) ? 1 : 0);
+ }
+ m = (rsize == RD_CHAR) ?
+ "Number of bytes;\n or keyword" :
+ "Number of lines;\n or keyword";
+ cmfdbi(&sw, /* SEEK symbolic targets (EOF) */
+ _CMKEY, /* fcode */
+ m,
+ "",
+ "", /* addtl string data */
+ nfsekwtab, /* addtl numeric data 1: table size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ fsekwtab, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* Byte or line number */
+ _CMNUW, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number or EOF required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUW) {
+ z = cmresult.wresult;
+ debug(F110,"FILE SEEK atmbuf",atmbuf,0);
+ if (relative < 0) {
+ if (cx == FIL_SEE && (atmbuf[0] == '+' || atmbuf[0] == '-'))
+ relative = 1;
+ else
+ relative = 0;
+ }
+ } else if (cmresult.fcode == _CMKEY) {
+ eofflg = cmresult.nresult;
+ relative = 0;
+ y = 0 - eofflg;
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+ y = 1; /* Recycle this */
+ z_flush(n);
+ debug(F101,"FILE SEEK relative","",relative);
+ debug(F101,"FILE SEEK rsize","",rsize);
+
+ if (rsize == RD_CHAR) { /* Seek to byte position */
+ if (relative > 0) {
+ CK_OFF_T pos;
+ pos = z_getpos(n);
+ if (pos < (CK_OFF_T)0) {
+ rc = pos;
+ printf("?Relative SEEK failed: %s\n",ckferror(rc));
+ return(-9);
+ }
+ z += pos;
+ } else {
+ if (z < 0 && !eofflg) { /* Negative arg but not relative */
+ y = 0; /* Remember this was bad */
+ z = 0; /* but substitute 0 */
+ }
+ }
+ debug(F101,"FILE SEEK /CHAR z","",z);
+ if (z < 0 && !eofflg) {
+ z_error = FX_RNG;
+ return(success = 0);
+ }
+ if ((rc = z_seek(n,z)) < 0) {
+ if (rc == FX_EOF) return(success = 0);
+ printf("?SEEK /BYTE failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ } else { /* Seek to line */
+ if (relative > 0) {
+ CK_OFF_T pos;
+ pos = z_getline(n);
+ debug(F101,"FILE SEEK /LINE pos","",pos);
+ if (pos < 0) {
+ rc = pos;
+ printf("?Relative SEEK failed: %s\n",ckferror(rc));
+ return(-9);
+ }
+ z += pos;
+ }
+ debug(F101,"FILE SEEK /LINE z","",z);
+ debug(F101,"FILE SEEK /LINE eofflg","",eofflg);
+ if (z < 0 && !eofflg) {
+ z_error = FX_RNG;
+ return(success = 0);
+ }
+ if ((rc = z_line(n,z)) < 0) {
+ if (rc == FX_EOF) return(success = 0);
+ printf("?SEEK /LINE failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ }
+ /*
+ Now, having sought to the desired starting spot, if a /FIND:
+ target was specified, look for it now.
+ */
+ if (seek_target) {
+ int flag = 0, ispat = 0, matchresult = 0;
+ while (!flag) {
+ y = z_in(n,line,LINBUFSIZ,LINBUFSIZ-1,0);
+ if (y < 0) {
+ y = 0;
+ break;
+ }
+ if (ispattern(seek_target)) {
+ matchresult = ckmatch(seek_target,line,inpcas[cmdlvl],1+4);
+ } else {
+ /* This is faster */
+ matchresult = ckindex(seek_target,line,0,0,inpcas[cmdlvl]);
+ }
+ if (matchresult) {
+ flag = 1;
+ break;
+ }
+ }
+ if (flag) {
+ debug(F111,"FSEEK HAVE MATCH",seek_target,z_getline(n));
+ /* Back up to beginning of line where target found */
+ if ((y = z_line(n,z_getline(n)-1)) < 0) {
+ if (rc == FX_EOF) return(success = 0);
+ printf("?SEEK /LINE failed - Channel %d: %s\n",
+ n,ckferror(rc));
+ return(-9);
+ }
+ debug(F101,"FSEEK LINE","",y);
+ }
+ }
+ return(success = (y < 0) ? 0 : 1);
+
+ case FIL_LIS: { /* LIST open files */
+#ifdef CK_TTGWSIZ
+ extern int cmd_rows, cmd_cols;
+#endif /* CK_TTGWSIZ */
+ extern int xaskmore;
+ int i, x, n = 0, paging = 0;
+ char * s;
+
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#ifdef CK_TTGWSIZ
+ if (cmd_rows > 0 && cmd_cols > 0)
+#endif /* CK_TTGWSIZ */
+ paging = xaskmore;
+
+ printf("System open file limit:%5d\n", z_openmax);
+ printf("Maximum for FILE OPEN: %5d\n", z_maxchan);
+ printf("Files currently open: %5d\n\n", z_nopen);
+ n = 4;
+ for (i = 0; i < z_maxchan; i++) {
+ s = z_getname(i); /* Got one? */
+ if (s) { /* Yes */
+ char m[8];
+ m[0] = NUL;
+ printf("%2d. %s",i,s); /* Print name */
+ n++; /* Count it */
+ x = z_getmode(i); /* Get modes & print them */
+ if (x > 0) {
+ if (x & FM_REA) ckstrncat(m,"R",8);
+ if (x & FM_WRI) ckstrncat(m,"W",8);
+ if (x & FM_APP) ckstrncat(m,"A",8);
+ if (x & FM_BIN) ckstrncat(m,"B",8);
+ if (m[0])
+ printf(" (%s)",m);
+ if (x & FM_EOF)
+ printf(" [EOF]");
+ else /* And file position too */
+ printf(" %s",ckfstoa(z_getpos(i)));
+ }
+ printf("\n");
+#ifdef CK_TTGWSIZ
+ if (paging > 0) { /* Pause at end of screen */
+ if (n > cmd_rows - 3) {
+ if (!askmore())
+ break;
+ else
+ n = 0;
+ }
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ }
+ return(success = 1);
+ }
+
+ case FIL_FLU: /* FLUSH */
+ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (n == -9) return(success = 0);
+ if (n == -8) return(success = 1);
+ if ((rc = z_flush(n)) < 0) {
+ printf("?FLUSH failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ return(success = 1);
+
+ case FIL_STA: /* STATUS */
+ {
+ int i, j, k; /* Supply default if only one open */
+ s = "";
+ for (k = 0, j = 0, i = 0; i < z_maxchan; i++) {
+ if (z_file)
+ if (z_file[i])
+ if (z_file[i]->z_fp) { k++; j = i; }
+ }
+ if (k == 1) s = ckitoa(j);
+ }
+ if ((x = cmnum("Channel number",s,10,&n, xxstring)) < 0) {
+ if (x == -3) {
+ if (z_nopen > 1) {
+ printf("?%d files open - please supply channel number\n",
+ z_nopen);
+ return(-9);
+ }
+ } else
+ return(x);
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if ((!z_file || z_nopen == 0) && x == -3) {
+ printf("No files open\n");
+ return(success = 1);
+ }
+ p = blanks + 3; /* Tricky formatting... */
+ if (n < 1000) p--;
+ if (n < 100) p--;
+ if (n < 10) p--;
+ if ((rc = z_getmode(n)) < 0) {
+ printf("Channel %d:%s%s\n",n,p,ckferror(rc));
+ return(success = 0);
+ } else if (!rc) {
+ printf("Channel %d:%sNot open\n",n,p);
+ return(success = 0);
+ } else {
+ CK_OFF_T xx;
+ s = z_getname(n);
+ if (!s) s = "(name unknown)";
+ printf("Channel %d:%sOpen\n",n,p);
+ printf(" File: %s\n Modes: ",s);
+ if (rc & FM_REA) printf(" /READ");
+ if (rc & FM_WRI) printf(" /WRITE");
+ if (rc & FM_APP) printf(" /APPEND");
+ if (rc & FM_BIN) printf(" /BINARY");
+ if (rc & FM_CMD) printf(" /COMMAND");
+ if (rc & FM_EOF) printf(" [EOF]");
+ printf("\n Size: %s\n",ckfstoa(z_count(n,RD_CHAR)));
+ printf(" At byte: %s\n",ckfstoa(z_getpos(n)));
+ xx = z_getline(n);
+ if (xx > (CK_OFF_T)-1)
+ printf(" At line: %s\n",ckfstoa(xx));
+ return(success = 1);
+ }
+ default:
+ return(-2);
+ }
+}
+#endif /* CKCHANNELIO */
+
+#ifndef NOSETKEY
+/* Save Key maps and in OS/2 Mouse maps */
+int
+savkeys(name,disp) char * name; int disp; {
+ char *tp;
+ static struct filinfo xx;
+ int savfil, i, j, k;
+ char buf[1024];
+
+ zclose(ZMFILE);
+
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ savfil = zopeno(ZMFILE,name,NULL,&xx);
+ } else savfil = zopeno(ZMFILE,name,NULL,NULL);
+
+ if (savfil) {
+#ifdef OS2
+ ztime(&tp);
+ zsout(ZMFILE, "; Kermit 95 SAVE KEYMAP file: ");
+ zsoutl(ZMFILE,tp);
+ if (mskkeys) {
+ zsoutl(ZMFILE,
+ "if eq \"\\v(program)\" \"C-Kermit\" set mskermit keycodes on");
+ } else {
+ zsoutl(ZMFILE,
+ "if NOT eq \"\\v(program)\" \"C-Kermit\" stop 1 C-Kermit required.");
+ zsoutl(ZMFILE,"set mskermit keycodes off");
+ }
+ zsoutl(ZMFILE,"");
+#else /* OS2 */
+ ztime(&tp);
+ zsout(ZMFILE, "; C-Kermit SAVE KEYMAP file: ");
+ zsoutl(ZMFILE,tp);
+#endif /* OS2 */
+
+ zsoutl(ZMFILE,"; Clear previous keyboard mappings ");
+ zsoutl(ZMFILE,"set key clear");
+#ifdef OS2
+ for (k = 0; k < nttkey; k++) {
+ if (!ttkeytab[k].flgs) {
+ ckmakmsg(buf,1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " clear",
+ NULL
+ );
+ zsoutl(ZMFILE,buf);
+ }
+ }
+#endif /* OS2 */
+ zsoutl(ZMFILE,"");
+
+ for (i = 0; i < KMSIZE; i++) {
+ if (macrotab[i]) {
+ int len = strlen((char *)macrotab[i]);
+#ifdef OS2
+ ckmakmsg(buf,
+ 1024,
+ "set key \\",
+ ckitoa(mskkeys ? cktomsk(i) : i),
+ " ",
+ NULL
+ );
+#else /* OS2 */
+ ckmakmsg(buf,
+ 1024,
+ "set key \\",
+ ckitoa(i),
+ NULL,NULL
+ );
+#endif /* OS2 */
+ zsout(ZMFILE,buf);
+
+ for (j = 0; j < len; j++) {
+ char ch = macrotab[i][j];
+ if (ch <= SP || ch >= DEL ||
+ ch == '-' || ch == ',' ||
+ ch == '{' || ch == '}' ||
+ ch == ';' || ch == '?' ||
+ ch == '.' || ch == '\'' ||
+ ch == '\\' || ch == '/' ||
+ ch == '#') {
+ ckmakmsg(buf,1024,"\\{",ckitoa((int)ch),"}",NULL);
+ zsout(ZMFILE,buf);
+ } else {
+ ckmakmsg(buf,1024,ckctoa((char)ch),NULL,NULL,NULL);
+ zsout(ZMFILE,buf);
+ }
+ }
+#ifdef OS2
+ ckmakmsg(buf,1024,"\t; ",keyname(i),NULL,NULL);
+ zsoutl(ZMFILE,buf);
+#else
+ zsoutl(ZMFILE,"");
+#endif /* OS2 */
+ } else if ( keymap[i] != i ) {
+#ifndef NOKVERBS
+ if (IS_KVERB(keymap[i])) {
+ for (j = 0; j < nkverbs; j++)
+ if (kverbs[j].kwval == (keymap[i] & ~F_KVERB))
+ break;
+ if (j != nkverbs) {
+#ifdef OS2
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\K%s\t; %s",
+ mskkeys ? cktomsk(i) : i,
+ kverbs[j].kwd, keyname(i)
+ );
+#else
+ ckmakxmsg(buf, /* 12 string args */
+ 1024,
+ "set key \\",
+ ckitoa(mskkeys ? cktomsk(i) : i),
+ " \\K",
+ kverbs[j].kwd,
+ "\t; ",
+ keyname(i),
+ NULL, NULL, NULL, NULL, NULL, NULL);
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#else
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\K%s", i, kverbs[j].kwd);
+#else
+ ckmakmsg(buf,1024,
+ "set key \\",
+ ckitoa(i),
+ " \\K",
+ kverbs[j].kwd
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#endif
+ }
+ } else
+#endif /* NOKVERBS */
+ {
+#ifdef OS2
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\{%d}\t; %s",
+ mskkeys ? cktomsk(i) : i,
+ keymap[i],
+ keyname(i)
+ );
+#else
+ ckmakxmsg(buf, /* 8 string args */
+ 1024,
+ "set key \\",
+ ckitoa(mskkeys ? cktomsk(i) : i),
+ " \\{",
+ ckitoa(keymap[i]),
+ "}\t; ",
+ keyname(i),
+ NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#else
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\{%d}", i, keymap[i]);
+#else
+ ckmakxmsg(buf,1024,
+ "set key \\",
+ ckitoa(i),
+ " \\{",
+ ckitoa(keymap[i]),
+ "}",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#endif /* OS2 */
+ }
+ }
+ }
+#ifdef OS2
+ /* OS/2 also has the SET TERMINAL KEY <termtype> defines */
+ for (k = 0; k < nttkey; k++) {
+ extern struct keynode * ttkeymap[];
+ struct keynode * pnode = NULL;
+
+ if (ttkeytab[k].flgs) /* Don't process CM_INV or CM_ABR */
+ continue;
+
+ zsoutl(ZMFILE,"");
+ ckmakmsg(buf,1024,"; SET TERMINAL KEY ",ttkeytab[k].kwd,NULL,NULL);
+ zsoutl(ZMFILE,buf);
+
+ for (pnode = ttkeymap[ttkeytab[k].kwval];
+ pnode;
+ pnode = pnode->next
+ ) {
+ switch (pnode->def.type) {
+ case key:
+#ifdef COMMENT
+ sprintf(buf, "set terminal key %s \\%d \\{%d}\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ pnode->def.key.scancode,
+ keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\{",
+ ckitoa(pnode->def.key.scancode),
+ "}\t; ",
+ keyname(pnode->key),
+ NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ break;
+ case kverb:
+ for (j = 0; j < nkverbs; j++)
+ if (kverbs[j].kwval == (pnode->def.kverb.id & ~F_KVERB))
+ break;
+ if (j != nkverbs) {
+#ifdef COMMENT
+ sprintf(buf, "set terminal key %s \\%d \\K%s\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ kverbs[j].kwd, keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\K",
+ kverbs[j].kwd,
+ "\t; ",
+ keyname(pnode->key),
+ NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ }
+ break;
+ case macro: {
+ int len = strlen((char *)pnode->def.macro.string);
+#ifdef COMMENT
+ sprintf(buf,"set terminal key %s \\%d ",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key);
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsout(ZMFILE,buf);
+
+ for (j = 0; j < len; j++) {
+ char ch = pnode->def.macro.string[j];
+ if (ch <= SP || ch >= DEL ||
+ ch == '-' || ch == ',' ||
+ ch == '{' || ch == '}' ||
+ ch == ';' || ch == '?' ||
+ ch == '.' || ch == '\'' ||
+ ch == '\\' || ch == '/' ||
+ ch == '#') {
+ ckmakmsg(buf,1024,
+ "\\{",ckitoa((int)ch),"}",NULL);
+ zsout(ZMFILE,buf);
+ } else {
+ ckmakmsg(buf,1024,
+ ckctoa((char)ch),NULL,NULL,NULL);
+ zsout(ZMFILE,buf);
+ }
+ }
+ ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL);
+ zsoutl(ZMFILE,buf);
+ break;
+ }
+ case literal: {
+ int len = strlen((char *)pnode->def.literal.string);
+#ifdef COMMENT
+ sprintf(buf,"set terminal key %s /literal \\%d ",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key);
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " /literal \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ zsout(ZMFILE,buf);
+
+ for (j = 0; j < len; j++) {
+ char ch = pnode->def.literal.string[j];
+ if (ch <= SP || ch >= DEL ||
+ ch == '-' || ch == ',' ||
+ ch == '{' || ch == '}' ||
+ ch == ';' || ch == '?' ||
+ ch == '.' || ch == '\'' ||
+ ch == '\\' || ch == '/' ||
+ ch == '#') {
+ ckmakmsg(buf,1024,
+ "\\{",ckitoa((int)ch),"}",NULL);
+ zsout(ZMFILE,buf);
+ } else {
+ ckmakmsg(buf,1024,
+ ckctoa((char)ch),NULL,NULL,NULL);
+ zsout(ZMFILE,buf);
+ }
+ }
+ ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL);
+ zsoutl(ZMFILE,buf);
+ break;
+ }
+ case esc:
+#ifdef COMMENT
+ sprintf(buf,
+ "set terminal key %s /literal \\%d \\{%d}\\{%d}\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ ISDG200(ttkeytab[k].kwval) ? 30 : 27,
+ pnode->def.esc.key & ~F_ESC,
+ keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " /literal \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\{",
+ ckitoa(ISDG200(ttkeytab[k].kwval) ? 30 : 27),
+ "}\\{",
+ ckitoa(pnode->def.esc.key & ~F_ESC),
+ "}\t; ",
+ keyname(pnode->key),
+ NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ break;
+ case csi:
+#ifdef COMMENT
+ sprintf(buf,
+ "set terminal key %s /literal \\%d \\{27}[\\{%d}\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ pnode->def.csi.key & ~F_CSI,
+ keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " /literal \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\{27}[\\{",
+ ckitoa(pnode->def.csi.key & ~F_CSI),
+ "}\t; ",
+ keyname(pnode->key),
+ NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ break;
+ default:
+ continue;
+ }
+ }
+ }
+#endif /* OS2 */
+
+ zsoutl(ZMFILE,"");
+ zsoutl(ZMFILE,"; End");
+ zclose(ZMFILE);
+ return(success = 1);
+ } else {
+ return(success = 0);
+ }
+}
+#endif /* NOSETKEY */
+
+#define SV_SCRL 0
+#define SV_HIST 1
+
+#ifdef OS2
+#ifndef NOLOCAL
+static struct keytab trmtrmopt[] = {
+ { "scrollback", SV_SCRL, 0 }
+};
+#endif /* NOLOCAL */
+#endif /* OS2 */
+
+static struct keytab cmdtrmopt[] = {
+#ifdef CK_RECALL
+ { "history", SV_HIST, 0 },
+#endif /* CK_RECALL */
+#ifdef OS2
+#ifndef NOLOCAL
+ { "scrollback", SV_SCRL, 0 },
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+static int ncmdtrmopt = (sizeof (cmdtrmopt) / sizeof (struct keytab)) - 1;
+
+#ifdef OS2
+#ifndef NOLOCAL
+_PROTOTYP(int savscrbk, (int, char *, int));
+#endif /* NOLOCAL */
+#endif /* OS2 */
+
+#ifdef CK_RECALL
+_PROTOTYP(int savhistory, (char *, int));
+#endif /* CK_RECALL */
+
+int
+dosave(xx) int xx; {
+ int x, y = 0, disp;
+ char * s = NULL;
+ extern struct keytab disptb[];
+#ifdef ZFNQFP
+ struct zfnfp * fnp;
+#endif /* ZFNQFP */
+
+#ifndef NOSETKEY
+ if (xx == XSKEY) { /* SAVE KEYMAP.. */
+ z = cmofi("Name of Kermit command file","keymap.ksc",&s,xxstring);
+ } else {
+#endif /* NOSETKEY */
+ switch (xx) {
+ case XSCMD: /* SAVE COMMAND.. */
+ if ((y = cmkey(cmdtrmopt, ncmdtrmopt, "What to save",
+#ifdef OS2
+ "scrollback",
+#else
+ "history",
+#endif /* OS2 */
+ xxstring)) < 0)
+ return(y);
+ break;
+#ifdef OS2
+#ifndef NOLOCAL
+ case XSTERM: /* SAVE TERMINAL.. */
+ if ((y = cmkey(trmtrmopt,1,
+ "What to save","scrollback",xxstring)) < 0)
+ return(y);
+ break;
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ }
+ z = cmofi("Filename",
+ ((y == SV_SCRL) ? "scrollbk.txt" : "history.txt"),
+ &s,
+ xxstring
+ );
+#ifndef NOSETKEY
+ }
+#endif /* NOSETKEY */
+ if (z < 0) /* Check output-file parse results */
+ return(z);
+ if (z == 2) {
+ printf("?Sorry, %s is a directory name\n",s);
+ return(-9);
+ }
+#ifdef ZFNQFP
+ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {/* Convert to full pathname */
+ if (fnp->fpath)
+ if ((int) strlen(fnp->fpath) > 0)
+ s = fnp->fpath;
+ }
+#endif /* ZFNQFP */
+
+ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of pathname */
+ s = line;
+#ifdef MAC
+ z = 0;
+#else
+ /* Get NEW/APPEND disposition */
+ if ((z = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
+ return(z);
+#endif /* MAC */
+ disp = z;
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+
+ switch (xx) { /* Do action.. */
+#ifndef NOSETKEY
+ case XSKEY: /* SAVE KEYMAP */
+ return (savkeys(s,disp));
+#endif /* NOSETKEY */
+
+ case XSCMD: /* SAVE COMMAND.. */
+#ifdef OS2
+#ifndef NOLOCAL
+ if (y == SV_SCRL) /* .. SCROLLBACK */
+ return(success = savscrbk(VCMD,s,disp));
+#endif /* NOLOCAL */
+#endif /* OS2 */
+#ifndef NORECALL
+ if (y == SV_HIST) /* .. HISTORY */
+ return(success = savhistory(s,disp));
+#endif /* NORECALL */
+ break;
+
+#ifdef OS2
+#ifndef NOLOCAL
+ case XSTERM: /* SAVE TERMINAL SCROLLBACK */
+ return(success = savscrbk(VTERM,s,disp));
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ }
+ success = 0;
+ return(-2);
+}
+
+/*
+ R E A D T E X T
+
+ Read text with a custom prompt into given buffer using command parser but
+ with no echoing or entry into recall buffer.
+*/
+int
+readtext(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
+#ifdef CK_RECALL
+ extern int on_recall; /* Around Password prompting */
+#endif /* CK_RECALL */
+ int rc;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode;
+ extern int startflags;
+ int vmode_sav = vmode;
+
+ if (!prmpt) prmpt = "";
+
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ )
+ return(popup_readtext(vmode,NULL,prmpt,buffer,bufsiz,0));
+
+ if (vmode == VTERM) {
+ vmode = VCMD;
+ VscrnIsDirty(VTERM);
+ VscrnIsDirty(VCMD);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(1); /* and echo mode */
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (rc = -1; rc < 0; ) { /* Prompt till they answer */
+ rc = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ cmres(); /* Reset the parser again */
+ }
+ ckstrncpy(buffer,s,bufsiz);
+ cmsetp(psave); /* Restore original prompt */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode != vmode_sav) {
+ vmode = VTERM;
+ VscrnIsDirty(VCMD);
+ VscrnIsDirty(VTERM);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(0);
+}
+#endif /* NOICP */
+
+/* A general function to allow a Password or other information */
+/* to be read from the command prompt without it going into */
+/* the recall buffer or being echo'd. */
+
+int
+readpass(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
+ int x;
+#ifdef NOICP
+ if (!prmpt) prmpt = "";
+ printf("%s", prmpt);
+#ifdef COMMENT
+ /* Some linkers won't allow this because it's unsafe */
+ gets(buffer);
+#else /* COMMENT */
+ {
+ int c, i; char * p;
+ p = buffer;
+ for (i = 0; i < bufsiz-1; i++) {
+ if ((c = getchar()) == EOF)
+ break;
+ if (c < SP)
+ break;
+ buffer[i] = c;
+ }
+ buffer[i] = NUL;
+ }
+#endif /* COMMENT */
+ return(1);
+#else /* NOICP */
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ int rc;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode;
+ extern int startflags;
+ int vmode_sav = vmode;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CKSYSLOG
+ int savlog;
+#endif /* CKSYSLOG */
+ if (!prmpt) prmpt = "";
+#ifndef NOLOCAL
+ debok = 0; /* Don't log */
+#ifdef OS2
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) {
+ x = popup_readpass(vmode,NULL,prmpt,buffer,bufsiz,0);
+ debok = 1;
+ return(x);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef CKSYSLOG
+ savlog = ckxsyslog; /* Save and turn off syslogging */
+ ckxsyslog = 0;
+#endif /* CKSYSLOG */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode == VTERM) {
+ vmode = VCMD;
+ VscrnIsDirty(VTERM);
+ VscrnIsDirty(VCMD);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(0); /* and no-echo mode */
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (rc = -1; rc < 0; ) { /* Prompt till they answer */
+ rc = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ cmres(); /* Reset the parser again */
+ }
+ ckstrncpy(buffer,s,bufsiz);
+ printf("\r\n"); /* Echo a CRLF */
+ cmsetp(psave); /* Restore original prompt */
+ cmini(1); /* Restore echo mode */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode != vmode_sav) {
+ vmode = VTERM;
+ VscrnIsDirty(VCMD);
+ VscrnIsDirty(VTERM);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CKSYSLOG
+ ckxsyslog = savlog; /* Restore syslogging */
+#endif /* CKSYSLOG */
+ debok = 1;
+ return(0);
+#endif /* NOICP */
+}
+
+#ifndef NOICP
+struct keytab authtab[] = { /* Available authentication types */
+#ifdef CK_KERBEROS
+ { "k4", AUTH_KRB4, CM_INV },
+ { "k5", AUTH_KRB5, CM_INV },
+ { "kerberos4", AUTH_KRB4, 0 },
+ { "kerberos5", AUTH_KRB5, 0 },
+ { "krb4", AUTH_KRB4, CM_INV },
+ { "krb5", AUTH_KRB5, CM_INV },
+#endif /* CK_KERBEROS */
+#ifdef NT
+ { "ntlm", AUTH_NTLM, 0 },
+#endif /* NT */
+#ifdef CK_SRP
+ { "srp", AUTH_SRP, 0 },
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ { "ssl", AUTH_SSL, 0 },
+#endif /* CK_SSL */
+ { "", 0, 0 }
+};
+int authtabn = sizeof(authtab)/sizeof(struct keytab)-1;
+
+#ifdef CK_KERBEROS
+struct keytab kerbtab[] = { /* Kerberos authentication types */
+ { "k4", AUTH_KRB4, CM_INV },
+ { "k5", AUTH_KRB5, CM_INV },
+ { "kerberos4", AUTH_KRB4, 0 },
+ { "kerberos5", AUTH_KRB5, 0 },
+ { "krb4", AUTH_KRB4, CM_INV },
+ { "krb5", AUTH_KRB5, CM_INV }
+};
+int kerbtabn = sizeof(kerbtab)/sizeof(struct keytab);
+
+static struct keytab krb_s_tbl[] = { /* AUTHENTICATE command switches: */
+ { "/cache", KRB_S_CA, CM_ARG }
+};
+static int krb_s_n = sizeof(krb_s_tbl)/sizeof(struct keytab);
+
+static struct keytab krb_v_tbl[] = { /* KERBEROS version values: */
+ { "4", 4, 0 },
+ { "5", 5, 0 }, /* (add others as needed...) */
+ { "auto", 0, 0 } /* Note: 0 = auto */
+};
+static int krb_v_n = sizeof(krb_v_tbl)/sizeof(struct keytab);
+
+static struct keytab krb_a_tbl[] = { /* KERBEROS actions: */
+ { "destroy", KRB_A_DE, 0 },
+ { "initialize", KRB_A_IN, 0 },
+ { "list-credentials", KRB_A_LC, 0 }
+};
+static int krb_a_n = sizeof(krb_a_tbl)/sizeof(struct keytab);
+
+static struct keytab krb4_i_tbl[] = { /* KERBEROS 4 INITIALIZE switches: */
+ { "/brief", KRB_I_BR, 0 }, /* /BRIEF */
+ { "/instance", KRB_I_IN, CM_ARG }, /* /INSTANCE: */
+ { "/lifetime", KRB_I_LF, CM_ARG }, /* /LIFETIME: */
+ { "/not-preauth", KRB_I_NPA, 0 }, /* /NOT-PREAUTH */
+ { "/password", KRB_I_PW, CM_ARG }, /* /PASSWORD: */
+#ifdef OS2
+ { "/popup", KRB_I_POP, 0 }, /* /POPUP */
+#endif /* OS2 */
+ { "/preauth", KRB_I_PA, 0 }, /* /PREAUTH */
+ { "/realm", KRB_I_RL, CM_ARG }, /* /REALM: */
+ { "/verbose", KRB_I_VB, 0 }, /* /VERBOSE */
+ { "", 0, 0 }
+};
+static int krb4_i_n = sizeof(krb4_i_tbl)/sizeof(struct keytab) - 1;
+
+static struct keytab krb5_i_tbl[] = { /* KERBEROS 5 INITIALIZE switches: */
+ { "/addresses", KRB_I_ADR, CM_ARG },
+ { "/forwardable", KRB_I_FW, 0 }, /* /FORWARDABLE */
+ { "/instance", KRB_I_IN, CM_ARG }, /* /INSTANCE: */
+ { "/k4", KRB_I_K4, CM_INV }, /* /KERBEROS4 */
+ { "/kerberos4", KRB_I_K4, 0 }, /* /KERBEROS4 */
+ { "/krb4", KRB_I_K4, CM_INV }, /* /KERBEROS4 */
+ { "/lifetime", KRB_I_LF, CM_ARG }, /* /LIFETIME: */
+ { "/no-addresses", KRB_I_NAD, 0 }, /* /NO-ADDRESSES */
+ { "/no-k4", KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */
+ { "/no-kerberos4", KRB_I_NK4, 0 }, /* /NO-KERBEROS4 */
+ { "/no-krb4", KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */
+ { "/not-forwardable", KRB_I_NFW, 0 }, /* /NOT-FORWARDABLE */
+ { "/not-proxiable", KRB_I_NPR, 0 }, /* /NOT-PROXIABLE */
+ { "/password", KRB_I_PW, CM_ARG }, /* /PASSWORD: */
+#ifdef OS2
+ { "/popup", KRB_I_POP, 0 }, /* /POPUP */
+#endif /* OS2 */
+ { "/postdate", KRB_I_PD, CM_ARG }, /* /POSTDATE: */
+ { "/pr", KRB_I_PR, CM_INV|CM_ABR }, /* to allow for */
+ { "/pro", KRB_I_PR, CM_INV|CM_ABR }, /* different spellings */
+ { "/prox", KRB_I_PR, CM_INV|CM_ABR },
+ { "/proxiable", KRB_I_PR, 0 }, /* /PROXIABLE */
+ { "/proxyable", KRB_I_PR, CM_INV }, /* /PROXYABLE */
+ { "/realm", KRB_I_RL, CM_ARG }, /* /REALM: */
+ { "/renew", KRB_I_RN, 0 }, /* /RENEW */
+ { "/renewable", KRB_I_RB, CM_ARG }, /* /RENEWABLE: */
+ { "/service", KRB_I_SR, CM_ARG }, /* /SERVICE: */
+ { "/validate", KRB_I_VA, 0 }, /* /VALIDATE */
+ { "", 0, 0 }
+};
+static int krb5_i_n = sizeof(krb5_i_tbl)/sizeof(struct keytab) - 1;
+
+static struct keytab klctab[] = { /* List Credentials switches*/
+ { "/addresses", XYKLCAD, 0 },
+ { "/encryption", XYKLCEN, 0 },
+ { "/flags", XYKLCFL, 0 }
+};
+static int nklctab = sizeof(klctab)/sizeof(struct keytab);
+
+extern int krb_action;
+extern struct krb_op_data krb_op;
+
+extern struct krb5_list_cred_data krb5_lc;
+extern struct krb5_init_data krb5_init;
+extern char * krb5_d_principal; /* Default principal */
+extern char * krb5_d_instance;
+extern char * krb5_d_realm; /* Default realm */
+extern char * krb5_d_cc; /* Default credentials cache */
+extern char * krb5_d_srv; /* Default service name */
+extern int krb5_d_lifetime; /* Default lifetime */
+extern int krb5_d_forwardable;
+extern int krb5_d_proxiable;
+extern int krb5_d_renewable;
+extern int krb5_autoget;
+extern int krb5_autodel;
+extern int krb5_d_getk4;
+extern int krb5_d_no_addresses;
+extern int krb5_checkaddrs;
+extern char * krb5_d_addrs[];
+extern char * k5_keytab; /* Keytab file */
+
+extern struct krb4_init_data krb4_init;
+extern char * krb4_d_principal; /* Default principal */
+extern char * krb4_d_realm; /* Default realm */
+extern char * krb4_d_srv; /* Default service name */
+extern int krb4_d_lifetime; /* Default lifetime */
+extern int krb4_d_preauth;
+extern char * krb4_d_instance;
+extern int krb4_autoget;
+extern int krb4_autodel;
+extern int krb4_checkaddrs;
+extern char * k4_keytab; /* Keytab file */
+#endif /* CK_KERBEROS */
+
+#ifndef NOSHOW
+int
+sho_iks() {
+#ifdef IKSDCONF
+#ifdef CK_LOGIN
+ extern int ckxsyslog, ckxwtmp, ckxanon;
+#ifdef UNIX
+ extern int ckxpriv;
+#endif /* UNIX */
+#ifdef CK_PERMS
+ extern int ckxperms;
+#endif /* CK_PERMS */
+ extern char * anonfile, * userfile, * anonroot;
+#ifdef OS2
+ extern char * anonacct;
+#endif /* OS2 */
+#ifdef NT
+ extern char * iks_domain;
+#endif /* NT */
+#endif /* CK_LOGIN */
+#ifdef CKWTMP
+ extern char * wtmpfile;
+#endif /* CKWTMP */
+#ifdef IKSDB
+ extern char * dbfile;
+ extern int dbenabled;
+#endif /* IKSDB */
+#ifdef CK_LOGIN
+ extern int logintimo;
+#endif /* CK_LOGIN */
+ extern int srvcdmsg, success, iksdcf, noinit, arg_x;
+ extern char * cdmsgfile[], * cdmsgstr, *kermrc;
+ char * bannerfile = NULL;
+ char * helpfile = NULL;
+ extern int xferlog;
+ extern char * xferfile;
+ int i;
+
+ if (isguest) {
+ printf("?Command disabled\r\n");
+ return(success = 0);
+ }
+
+ printf("IKS Settings\r\n");
+#ifdef CK_LOGIN
+#ifdef OS2
+ printf(" Anonymous Account: %s\r\n",anonacct?anonacct:"<none>");
+#endif /* OS2 */
+ printf(" Anonymous Initfile: %s\r\n",anonfile?anonfile:"<none>");
+ printf(" Anonymous Login: %d\r\n",ckxanon);
+ printf(" Anonymous Root: %s\r\n",anonroot?anonroot:"<none>");
+#endif /* CK_LOGIN */
+ printf(" Bannerfile: %s\r\n",bannerfile?bannerfile:"<none>");
+ printf(" CDfile: %s\r\n",cdmsgfile[0]?cdmsgfile[0]:"<none>");
+ for ( i=1;i<16 && cdmsgfile[i];i++ )
+ printf(" CDfile: %s\r\n",cdmsgfile[i]);
+ printf(" CDMessage: %d\r\n",srvcdmsg);
+#ifdef IKSDB
+ printf(" DBfile: %s\r\n",dbfile?dbfile:"<none>");
+ printf(" DBenabled: %d\r\n",dbenabled);
+#endif /* IKSDB */
+#ifdef CK_LOGIN
+#ifdef NT
+ printf(" Default-domain: %s\r\n",iks_domain?iks_domain:".");
+#endif /* NT */
+#endif /* CK_LOGIN */
+ printf(" Helpfile: %s\r\n",helpfile?helpfile:"<none>");
+ printf(" Initfile: %s\r\n",kermrc?kermrc:"<none>");
+ printf(" No-Initfile: %d\r\n",noinit);
+#ifdef CK_LOGIN
+#ifdef CK_PERM
+ printf(" Permission code: %0d\r\n",ckxperms);
+#endif /* CK_PERM */
+#ifdef UNIX
+ printf(" Privileged Login: %d\r\n",ckxpriv);
+#endif /* UNIX */
+#endif /* CK_LOGIN */
+ printf(" Server-only: %d\r\n",arg_x);
+ printf(" Syslog: %d\r\n",ckxsyslog);
+ printf(" Timeout (seconds): %d\r\n",logintimo);
+ printf(" Userfile: %s\r\n",userfile?userfile:"<none>");
+#ifdef CK_LOGIN
+#ifdef CKWTMP
+ printf(" Wtmplog: %d\r\n",ckxwtmp);
+ printf(" Wtmpfile: %s\r\n",wtmpfile?wtmpfile:"<none>");
+#endif /* CKWTMP */
+#endif /* CK_LOGIN */
+ printf(" Xferfile: %s\r\n",xferfile?xferfile:"<none>");
+ printf(" Xferlog: %d\r\n",xferlog);
+#else /* IKSDCONF */
+ printf("?Nothing to show.\r\n");
+#endif /* IKSDCONF */
+ return(success = 1);
+}
+
+#ifdef CK_AUTHENTICATION
+int
+sho_auth(cx) int cx; {
+ extern int auth_type_user[], cmd_rows;
+ int i;
+ char * p;
+ int kv = 0, all = 0, n = 0;
+
+#ifdef IKSD
+ if (inserver && isguest) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ if (cx) {
+ kv = cx;
+ } else if (auth_type_user[0] != AUTHTYPE_AUTO) {
+ kv = auth_type_user[0];
+ } else {
+ all = 1;
+ kv = AUTHTYPE_KERBEROS_V4;
+ }
+ while (kv) {
+ switch (kv) {
+ case AUTHTYPE_KERBEROS_V4:
+ kv = all ? AUTHTYPE_KERBEROS_V5 : 0;
+ if (ck_krb4_is_installed()) {
+ printf(" Authentication: Kerberos 4\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: Kerberos 4 (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+#ifdef CK_KERBEROS
+ printf(" Keytab file: %s\n",
+ k4_keytab ? k4_keytab : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (krb_action < 0) {
+ p = "(none)";
+ } else {
+ for (p = "", i = 0; i < krb_a_n; i++) {
+ if (krb_action == krb_a_tbl[i].kwval) {
+ p = krb_a_tbl[i].kwd;
+ break;
+ }
+ }
+ }
+ printf(" Action: %s\n", p);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default lifetime %d\n",krb4_d_lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Lifetime: %d (minutes)\n",krb4_init.lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default preauth: %d\n",krb4_d_preauth);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Preauth: %d\n",krb4_init.preauth);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default principal: \"%s\"\n",
+ krb4_d_principal ? krb4_d_principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Principal: \"%s\"\n",
+ krb4_init.principal ? krb4_init.principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default realm: \"%s\"\n",
+ krb4_d_realm ? krb4_d_realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Realm: \"%s\"\n",
+ krb4_init.realm ? krb4_init.realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default instance: \"%s\"\n",
+ krb4_d_instance ? krb4_d_instance : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Instance: \"%s\"\n",
+ krb4_init.instance ? krb4_init.instance : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Get TGTs: %d\n",krb4_autoget);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Destroy TGTs: %s\n",
+ krb4_autodel==KRB_DEL_NO?"never":
+ krb4_autodel==KRB_DEL_CL?"on-close":"on-exit");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Check IP Addresses: %d\n",krb4_checkaddrs);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#ifdef COMMENT
+ printf(" Password: \"%s\"\n",
+ krb4_init.password ? krb4_init.password : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* COMMENT */
+#endif /* CK_KERBEROS */
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ kv = all ? AUTHTYPE_SSL : 0;
+ if (ck_krb5_is_installed()) {
+ if (ck_gssapi_is_installed())
+ printf(" Authentication: Kerberos 5 plus GSSAPI\n");
+ else
+ printf(" Authentication: Kerberos 5\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: Kerberos 5 (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+
+#ifdef CK_KERBEROS
+ printf(" Cache file: %s\n",
+ krb_op.cache ? krb_op.cache : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default cache: %s\n",
+ krb5_d_cc ? krb5_d_cc : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Keytab file: %s\n",
+ k5_keytab ? k5_keytab : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (krb_action < 0) {
+ p = "(none)";
+ } else {
+ for (p = "", i = 0; i < krb_a_n; i++) {
+ if (krb_action == krb_a_tbl[i].kwval) {
+ p = krb_a_tbl[i].kwd;
+ break;
+ }
+ }
+ }
+ printf(" Action: %s\n", p);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(" Default forwardable %d\n",krb5_d_forwardable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Forwardable: %d\n",krb5_init.forwardable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default lifetime %d\n",krb5_d_lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Lifetime: %d (minutes)\n",krb5_init.lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Postdate: \"%s\"\n",
+ krb5_init.postdate ? krb5_init.postdate: "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default proxiable: %d\n",krb5_d_proxiable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Proxiable: %d\n",krb5_init.proxiable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Renew: %d\n",krb5_init.renew);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default renewable: %d (minutes)\n",krb5_d_renewable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Renewable: %d (minutes)\n",krb5_init.renewable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Service: \"%s\"\n",
+ krb5_init.service ? krb5_init.service : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Validate: %d\n",krb5_init.validate);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default principal: \"%s\"\n",
+ krb5_d_principal ? krb5_d_principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Principal: \"%s\"\n",
+ krb5_init.principal ? krb5_init.principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default instance: \"%s\"\n",
+ krb5_d_instance ? krb5_d_instance : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default realm: \"%s\"\n",
+ krb5_d_realm ? krb5_d_realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Realm: \"%s\"\n",
+ krb5_init.realm ? krb5_init.realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Get TGTs: %d\n",krb5_autoget);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Destroy TGTs: %s\n",
+ krb5_autodel==KRB_DEL_NO?"never":
+ krb5_autodel==KRB_DEL_CL?"on-close":"on-exit");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default get K4 TGTs: %d\n",krb5_d_getk4);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Get K4 TGTs: %d\n",krb5_init.getk4);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Check IP Addresses: %d\n",krb5_checkaddrs);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" No IP Addresses: %d\n",krb5_d_no_addresses);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" IP-Addresses: ");
+ if (krb5_init.addrs && krb5_init.addrs[0]) {
+ for (i = 0; krb5_init.addrs[i]; i++) {
+ if (i)
+ printf(",");
+ printf("%s",krb5_init.addrs[i]);
+ }
+ } else if (krb5_d_addrs[0]) {
+ for (i = 0;i < KRB5_NUM_OF_ADDRS && krb5_d_addrs[i];i++) {
+ if (i)
+ printf(",");
+ printf("%s",krb5_d_addrs[i]);
+ }
+ } else {
+ printf("(use default)");
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#ifdef COMMENT
+ printf(" Password: \"%s\"\n",
+ krb5_init.password ? krb5_init.password : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* COMMENT */
+#endif /* CK_KERBEROS */
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+#ifdef CK_SSL
+ case AUTHTYPE_SSL:
+ kv = all ? AUTHTYPE_SRP : 0;
+ if (ck_ssleay_is_installed()) {
+ printf(" Authentication: SSL/TLS (%s)\n",
+ SSLeay_version(SSLEAY_VERSION));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: SSL/TLS (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+ printf(" RSA Certs file: %s\n",ssl_rsa_cert_file?
+ ssl_rsa_cert_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" RSA Certs Chain file: %s\n",ssl_rsa_cert_chain_file?
+ ssl_rsa_cert_chain_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" RSA Key file: %s\n",ssl_rsa_key_file?
+ ssl_rsa_key_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DSA Certs file: %s\n",ssl_dsa_cert_file?
+ ssl_dsa_cert_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DSA Certs Chain file: %s\n",ssl_dsa_cert_chain_file?
+ ssl_dsa_cert_chain_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DH Key file: %s\n",ssl_dh_key_file?
+ ssl_dh_key_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DH Param file: %s\n",ssl_dh_param_file?
+ ssl_dh_param_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" CRL file: %s\n",ssl_crl_file?
+ ssl_crl_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" CRL dir: %s\n",ssl_crl_dir?
+ ssl_crl_dir:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Random file: %s\n",ssl_rnd_file?
+ ssl_rnd_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verify file: %s\n",ssl_verify_file?
+ ssl_verify_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verify dir: %s\n",ssl_verify_dir?
+ ssl_verify_dir:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Cipher list: %s\n",ssl_cipher_list ? ssl_cipher_list :
+ DEFAULT_CIPHER_LIST);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (ssl_con == NULL) {
+ SSL_library_init();
+ ssl_ctx = (SSL_CTX *)
+ SSL_CTX_new((SSL_METHOD *)TLSv1_method());
+ if (ssl_ctx != NULL)
+ ssl_con= (SSL *) SSL_new(ssl_ctx);
+ }
+ if (ssl_con != NULL) {
+ CHAR * p = NULL;
+ int i;
+
+ for (i = 0; ; i++) {
+ p = (CHAR *) SSL_get_cipher_list(ssl_con,i);
+ if (p == NULL)
+ break;
+ printf(" %s\n",p);
+ if (++n > cmd_rows - 3)
+ if (!askmore()) return(0); else n = 0;
+ }
+ }
+ printf(" Certs OK? %s\n",ssl_certsok_flag? "yes" : "no");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Debug mode: %s\n", ssl_debug_flag ? "on" : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verbose mode: %s\n", ssl_verbose_flag ? "on" : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verify mode: %s\n",
+ ssl_verify_flag == SSL_VERIFY_NONE ? "none" :
+ ssl_verify_flag == SSL_VERIFY_PEER ? "peer-cert" :
+ "fail-if-no-peer-cert");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" SSL only? %s\n", ssl_only_flag ? "yes" : "no");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" TLS only? %s\n", tls_only_flag ? "yes" : "no");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* CK_SSL */
+ break;
+ case AUTHTYPE_NTLM:
+ kv = 0;
+ if (ck_ntlm_is_installed()) {
+ printf(" Authentication: NTLM\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" No options\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: NTLM (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ case AUTHTYPE_SRP:
+ kv = all ? AUTHTYPE_NTLM : 0;
+ if (ck_srp_is_installed()) {
+ if (ck_krypto_is_installed())
+ printf(" Authentication: SRP plus Krypto API\n");
+ else
+ printf(" Authentication: SRP\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" No options\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: SRP (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ }
+ }
+ return(success = 1);
+}
+#endif /* CK_AUTHENTICATION */
+#endif /* NOSHOW */
+
+#ifdef CK_KERBEROS
+
+/* C P _ A U T H -- AUTHENTICATE command parsing */
+
+int
+cp_auth() { /* Command_Parse AUTHENTICATE */
+ int c, i, n; /* Workers */
+ int rc = 0; /* Return code */
+ int getval; /* Parsing helpers */
+ int tmpauth = 0; /* Temporary authentication type */
+ int kv = 0; /* Temporary Kerberos version */
+ int tmp_action = -1; /* Temporary Kerberos action */
+ int tmp_klc = 0; /* Temporary list-credentials */
+ char tmphlp[256]; /* For building help message */
+ char * p;
+ char * tmppswd = NULL; /* Password */
+ char * tmpprinz = NULL; /* Principal */
+ char * tmprealm = NULL; /* Realm */
+ char * tmpcache = NULL; /* Cache file */
+ char * tmpinst = NULL; /* K4 Instance */
+ char * tmpaddrs[KRB5_NUM_OF_ADDRS];
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ struct stringint pv[KRB_I_MAX+1]; /* Temporary array for switch values */
+ struct FDB kw, sw, fl; /* FDBs for each parse function */
+
+ krb_action = -1; /* Initialize Kerberos action. */
+ tmp_action = -1; /* And our local copy. */
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++)
+ tmpaddrs[i] = NULL;
+
+ if ((y = cmkey(kerbtab,kerbtabn,"authentication type","",xxstring)) < 0)
+ {
+ if (y == -3)
+ printf("?Authentication type not specified - nothing happens\n");
+ return(y);
+ }
+ tmpauth = y;
+ debug(F101,"kerberos authentication","",tmpauth);
+ switch (tmpauth) {
+ case AUTH_KRB4: kv = 4; break; /* Don't assume values are the same */
+ case AUTH_KRB5: kv = 5; break;
+ default:
+ printf("?Authentication type not supported: \"%s\"\n",atmbuf);
+ return(-9);
+ }
+
+ /* From here down is Kerberos */
+ ini_kerb(); /* Reset Init data to defaults */
+
+ if (kv == 4) { /* Set K4 defaults */
+ if (krb4_d_realm)
+ makestr(&tmprealm,krb4_d_realm);
+ if (krb4_d_principal)
+ makestr(&tmpprinz,krb4_d_principal);
+ if (krb4_d_instance)
+ makestr(&tmpinst,krb4_d_instance);
+ } else if (kv == 5) { /* Set K5 defaults */
+ if (krb5_d_cc)
+ makestr(&tmpcache,krb5_d_cc);
+ if (krb5_d_realm)
+ makestr(&tmprealm,krb5_d_realm);
+ if (krb5_d_principal)
+ makestr(&tmpprinz,krb5_d_principal);
+ if (krb5_d_instance)
+ makestr(&tmpinst,krb5_d_instance);
+ }
+ for (i = 0; i <= KRB_I_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = 0; /* and 0 int values */
+ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
+ }
+ if (kv == 4) { /* Kerberos 4 */
+ pv[KRB_I_LF].ival = krb4_d_lifetime;
+ pv[KRB_I_PA].ival = krb4_d_preauth;
+
+ if ((n = cmkey(krb_a_tbl,krb_a_n,"Kerberos 4 action","",xxstring)) < 0)
+ {
+ if (n == -3)
+ printf("?Action not specified - nothing happens.\n");
+ return(n);
+ }
+ } else if (kv == 5) { /* Kerberos 5 */
+ pv[KRB_I_FW].ival = krb5_d_forwardable;
+ pv[KRB_I_PR].ival = krb5_d_proxiable;
+ pv[KRB_I_LF].ival = krb5_d_lifetime;
+ pv[KRB_I_RB].ival = krb5_d_renewable;
+ pv[KRB_I_K4].ival = krb5_d_getk4;
+ pv[KRB_I_NAD].ival = krb5_d_no_addresses;
+
+ /* Make help message that shows switches and action keywords */
+ ckstrncpy(tmphlp,"Kerberos 5 action, one of the following:\n ",256);
+ for (i = 0; i < krb_a_n; i++) {
+ ckstrncat(tmphlp,krb_a_tbl[i].kwd,sizeof(tmphlp));
+ if (i == krb_a_n - 1)
+ ckstrncat(tmphlp,"\nor switch",sizeof(tmphlp));
+ else
+ ckstrncat(tmphlp," ",sizeof(tmphlp));
+ }
+ /* Set up first set of chained FDB's */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ tmphlp, /* hlpmsg */
+ "", /* default (none) */
+ "", /* addtl string data */
+ krb_s_n, /* Switch table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ krb_s_tbl, /* Switch table */
+ &kw /* Pointer to next FDB */
+ );
+ cmfdbi(&kw, /* Second FDB - action keywords */
+ _CMKEY, /* fcode */
+ "Kerberos action", /* hlpmsg */
+ "", /* default (none) */
+ "", /* addtl string data */
+ krb_a_n, /* Switch table size */
+ 0, /* addtl num data (0 = NOT switch) */
+ xxstring, /* Processing function */
+ krb_a_tbl, /* Keyword table */
+ NULL /* Pointer to next FDB (none) */
+ );
+
+ /* Parse */
+
+ while (1) { /* Parse 0 or more switches */
+ rc = cmfdb(&sw); /* Parse something */
+ debug(F101,"kerberos cmfdb 1 rc","",rc);
+ if (rc < 0) { /* Error */
+ if (rc == -3)
+ printf("?Action not specified - nothing happens.\n");
+ return(rc); /* or reparse needed */
+ }
+ if (cmresult.fdbaddr != &sw) /* Break out if not a switch */
+ break;
+ c = cmgbrk(); /* Have switch - get break character */
+ getval = (c == ':' || c == '='); /* Must parse an agument? */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9); /* OK because nothing malloc'd yet */
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"kerberos command switch","",n);
+
+ switch (n) { /* Handle the switch */
+ case KRB_S_CA: /* /CACHE:<filename> */
+ p = krb5_d_cc ? krb5_d_cc : "";
+ if ((y = cmofi("Name of cache file",p,&s,xxstring)) < 0) {
+ if (y == -3)
+ s = NULL;
+ else
+ return(y);
+ }
+ makestr(&tmpcache,s);
+ break;
+ default:
+ printf("?Unexpected switch value - internal error\n");
+ return(-9); /* (if) nothing malloc'd yet. */
+ }
+ }
+ if (cmresult.fdbaddr != &kw) { /* Checking... */
+ printf("?Unexpected result - internal error\n");
+ return(-9); /* Nothing malloc'd yet. */
+ }
+ n = cmresult.nresult; /* Get keyword value */
+ } else {
+ printf("?Unexpected Kerberos version - Internal error\n");
+ return(-9);
+ }
+ debug(F101,"kerberos action","",n);
+ switch (n) {
+ case KRB_A_IN: /* INITIALIZE */
+ case KRB_A_DE: /* DESTROY */
+ case KRB_A_LC: /* LIST-CREDENTIALS */
+ tmp_action = n; /* OK, set */
+ break;
+ default: /* Not OK, punt. */
+ printf("?Unexpected action - internal error\n");
+ return(-9);
+ }
+ if (tmp_action == KRB_A_IN) { /* Action is INITIALIZE */
+ int x;
+ cmfdbi(&sw, /* INITIALIZE switches */
+ _CMKEY, /* fcode */
+ "Principal,\n or optional INITIALIZE switch(es)", /* hlpmsg */
+ "", /* default (none) */
+ "", /* addtl string data */
+ kv == 4 ? krb4_i_n : krb5_i_n, /* Switch table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ kv == 4 ? krb4_i_tbl : krb5_i_tbl, /* Switch table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 3rd FDB - command to send from */
+ _CMFLD, /* fcode */
+ "Principal", /* hlpmsg */
+ kv == 4 ? krb4_d_principal : krb5_d_principal, /* principal */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse INIT switches or principal */
+ rc = cmfdb(&sw);
+ debug(F101,"kerberos cmfdb 2 rc","",rc);
+ if (rc < 0) {
+ if (rc == -3)
+ printf("?Principal name required\n");
+ goto kerbx;
+ }
+ debug(F101,"kerberos cmfdb 2 fcode","",cmresult.fcode);
+ if (cmresult.fcode != _CMKEY) /* Not a switch, quit switch loop */
+ break;
+ c = cmgbrk(); /* Switch - get break character */
+ debug(F101,"kerberos cmfdb 2 cmgbrk","",c);
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9); /* OK because nothing malloc'd yet */
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ switch (n) {
+ /* These don't take args... */
+ case KRB_I_PA: /* /PREAUTH */
+ case KRB_I_FW: /* /FORWARDABLE */
+ case KRB_I_PR: /* /PROXIABLE */
+ case KRB_I_RN: /* /RENEW */
+ case KRB_I_VA: /* /VALIDATE */
+ case KRB_I_NPA: /* /NOT-PREAUTH */
+ case KRB_I_NFW: /* /NOT-FORWARDABLE */
+ case KRB_I_NPR: /* /NOT-PROXIABLE */
+ case KRB_I_VB: /* /VERBOSE */
+ case KRB_I_BR: /* /BRIEF */
+ case KRB_I_K4: /* /KERBEROS4 */
+ case KRB_I_NK4: /* /NO-KERBEROS4 */
+ case KRB_I_POP: /* /POPUP */
+ case KRB_I_NAD: /* /NO-ADDRESSES */
+ if (getval) {
+ printf("?This switch does not take a value\n");
+ rc = -9;
+ goto kerbx;
+ }
+ switch (n) {
+ case KRB_I_NPA:
+ pv[KRB_I_PA].ival = 0;
+ break;
+ case KRB_I_NFW:
+ pv[KRB_I_FW].ival = 0;
+ break;
+ case KRB_I_NPR:
+ pv[KRB_I_PR].ival = 0;
+ break;
+ case KRB_I_VB:
+ pv[KRB_I_BR].ival = 0;
+ break;
+ case KRB_I_NK4:
+ pv[KRB_I_K4].ival = 0;
+ break;
+ default:
+ pv[n].ival = 1;
+ }
+ break;
+
+ /* These do take arguments */
+
+ case KRB_I_RB: /* /RENEWABLE:<minutes> */
+ pv[n].ival = 0;
+ if (!getval) break;
+ if ((rc = cmnum("Minutes",ckitoa(krb5_init.renewable),
+ 10,&y, xxstring)) < 0)
+ goto kerbx;
+ pv[n].ival = y;
+ break;
+
+ case KRB_I_LF: /* /LIFETIME:<minutes> */
+ pv[n].ival = 0;
+ /* Default is previous value */
+ sprintf(tmpbuf,"%d", /* SAFE */
+ kv == 4 ?
+ krb4_init.lifetime :
+ krb5_init.lifetime
+ );
+ if (!getval) break;
+ if ((rc = cmnum("Minutes",tmpbuf,10,&y, xxstring)) < 0)
+ goto kerbx;
+ pv[n].ival = y;
+ break;
+
+ case KRB_I_PD: /* /POSTDATE:<timestamp> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmdate("date-time","",&s,0,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_SR: /* /SERVICE:<name> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmfld("Service-name","",&s,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_RL: /* /REALM:<name> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if (kv == 4)
+ p = krb4_d_realm ? krb4_d_realm : "";
+ else
+ p = krb5_d_realm ? krb5_d_realm : "";
+ if ((rc = cmfld("Realm",p,&s,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_IN: /* /INSTANCE:<name> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if (kv == 4)
+ p = krb4_d_instance ? krb4_d_instance : "";
+ else
+ p = krb5_d_instance ? krb5_d_instance : "";
+ if ((rc = cmfld("Instance",p,&s,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_PW: /* /PASSWORD:<password> */
+ debok = 0;
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmfld("Password","",&s,xxstring)) < 0)
+ if (rc != -3)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_ADR: /* /ADDRESSES:{<address-list>} */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmfld("List of IP addresses","",&s,xxstring)) < 0)
+ goto kerbx;
+ makelist(s,tmpaddrs,KRB5_NUM_OF_ADDRS);
+ for (i = 0; i < KRB5_NUM_OF_ADDRS && tmpaddrs[i]; i++) {
+ if (inet_addr(tmpaddrs[i]) == 0xffffffff) {
+ printf("invalid ip address: %s\n",tmpaddrs[i]);
+ rc = -9;
+ goto kerbx;
+ }
+ }
+ pv[KRB_I_NAD].ival = 0;
+ break;
+
+ default:
+ printf("?Unexpected switch value - internal error\n");
+ rc = -9;
+ goto kerbx;
+ }
+ }
+ if (cmresult.fcode != _CMFLD) {
+ printf("?Unexected result - internal error\n");
+ rc = -9;
+ goto kerbx;
+ }
+ /* cmresult.sresult may be of the form PRINCIPAL@REALM */
+ i = ckindex("@",cmresult.sresult,0,0,0);
+ if (i != 0) {
+ makestr(&tmprealm,&cmresult.sresult[i]);
+ cmresult.sresult[i-1] = '\0';
+ }
+ makestr(&tmpprinz,cmresult.sresult); /* Principal (user) */
+
+ if ((rc = cmcfm()) < 0) { /* Now get confirmation */
+ if (rc == -3) {
+ printf("?Principal name required\n");
+ }
+ goto kerbx;
+ }
+ if (!tmpprinz || !tmpprinz[0]) {
+ printf("?Principal name required\n");
+ goto kerbx;
+ }
+ if (!pv[KRB_I_RN].ival && !pv[KRB_I_VA].ival) {
+ /* Don't use a password if Validating or Renewing */
+ if (pv[KRB_I_PW].sval) { /* If they gave a /PASSWORD switch */
+ makestr(&tmppswd,pv[KRB_I_PW].sval); /* use this value */
+ }
+#ifdef COMMENT
+ /* Password prompting has been moved to ck_krb[45]_initTGT() */
+ else { /* Otherwise must prompt for it */
+ char prmpt[80];
+ if (pv[KRB_I_RL].sval)
+ sprintf(prmpt,"%s@%s's Password: ",
+ tmpprinz,pv[KRB_I_RL].sval);
+ else if (tmprealm)
+ sprintf(prmpt,"%s@%s's Password: ",
+ tmpprinz,tmprealm);
+ else
+ sprintf(prmpt,"%s's Password: ",tmpprinz);
+#ifdef OS2
+ if (pv[KRB_I_POP].ival) {
+ char passwd[80]="";
+ readpass(prmpt,passwd,80);
+ makestr(&tmppswd,passwd);
+ memset(passwd,0,80);
+ } else
+#endif /* OS2 */
+ {
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(0); /* and no-echo mode */
+ /* Issue prompt if at top level */
+ if (pflag) prompt(xxstring);
+ cmres(); /* Reset the parser */
+ for (rc = -1; rc < 0; ) { /* Prompt till they answer */
+ /* Get a literal line of text */
+ rc = cmtxt("","",&s,NULL);
+ cmres(); /* Reset the parser again */
+ }
+ makestr(&tmppswd,s);
+ printf("\n"); /* Echo a CRLF */
+ cmsetp(psave); /* Restore original prompt */
+ }
+ }
+ x = 0; /* Check for password */
+ if (tmppswd)
+ if (*tmppswd)
+ x = 1;
+ if (!x) {
+ printf("?Password required\n");
+ goto kerbx;
+ }
+#endif /* COMMENT */
+ }
+ } else if (kv == 5 && tmp_action == KRB_A_LC) { /* LIST-CREDENTIALS */
+ tmp_klc = 0;
+ while (1) {
+ if ((x = cmkey(klctab,nklctab,"Switch","",xxstring)) < 0) {
+ if (x == -3) {
+ if ((rc = cmcfm()) < 0)
+ goto kerbx;
+ else
+ break;
+ } else {
+ rc = x;
+ goto kerbx;
+ }
+ }
+ tmp_klc |= x;
+ }
+ } else if ((rc = cmcfm()) < 0) /* DESTROY, just confirm */
+ goto kerbx;
+
+/* Done - Move confirmed data to final locations */
+
+ krb_action = tmp_action; /* Action requested */
+ krb_op.version = kv; /* Kerberos version */
+ krb_op.cache = tmpcache; /* Cache file */
+ tmpcache = NULL; /* So we don't free it */
+
+ switch (krb_action) {
+ case KRB_A_IN: /* INITIALIZE */
+ if (kv == 5) {
+ krb5_init.forwardable = pv[KRB_I_FW].ival;
+ krb5_init.proxiable = pv[KRB_I_PR].ival;
+ krb5_init.lifetime = pv[KRB_I_LF].ival;
+ krb5_init.renew = pv[KRB_I_RN].ival;
+ krb5_init.renewable = pv[KRB_I_RB].ival;
+ krb5_init.validate = pv[KRB_I_VA].ival;
+
+ /* Here we just reassign the pointers and then set them to NULL */
+ /* so they won't be freed below. */
+
+ krb5_init.postdate = pv[KRB_I_PD].sval; pv[KRB_I_PD].sval = NULL;
+ krb5_init.service = pv[KRB_I_SR].sval; pv[KRB_I_SR].sval = NULL;
+ if (pv[KRB_I_RL].sval) {
+ krb5_init.realm = pv[KRB_I_RL].sval; pv[KRB_I_RL].sval = NULL;
+ } else if (tmprealm) {
+ krb5_init.realm = tmprealm; tmprealm = NULL;
+ }
+ if (pv[KRB_I_IN].sval) {
+ krb5_init.instance = pv[KRB_I_IN].sval;
+ pv[KRB_I_IN].sval = NULL;
+ } else if ( tmpinst ) {
+ krb5_init.instance = tmpinst;
+ tmpinst = NULL;
+ }
+ if (tmpprinz) {
+ krb5_init.principal = tmpprinz;
+ tmpprinz = NULL;
+ }
+ krb5_init.password = tmppswd;
+ tmppswd = NULL;
+
+ krb5_init.getk4 = pv[KRB_I_K4].ival;
+ if (krb5_init.getk4) {
+ krb4_init.lifetime = pv[KRB_I_LF].ival;
+ if (krb5_init.realm)
+ makestr(&krb4_init.realm,krb5_init.realm);
+ krb4_init.preauth = krb4_d_preauth;
+ krb4_init.verbose = pv[KRB_I_BR].ival ? 0 : 1;
+ if (krb5_init.principal)
+ makestr(&krb4_init.principal,krb5_init.principal);
+ if (krb5_init.principal)
+ makestr(&krb4_init.password,krb5_init.password);
+ }
+ krb5_init.no_addresses = pv[KRB_I_NAD].ival;
+ if (tmpaddrs[0]) {
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
+ if (krb5_init.addrs[i]) {
+ free(krb5_init.addrs[i]);
+ krb5_init.addrs[i] = NULL;
+ }
+ krb5_init.addrs[i] = tmpaddrs[i];
+ tmpaddrs[i] = NULL;
+ }
+ }
+ } else if (kv == 4) { /* Same deal for Kerberos 4 */
+ krb4_init.lifetime = pv[KRB_I_LF].ival;
+ if (pv[KRB_I_RL].sval) {
+ krb4_init.realm = pv[KRB_I_RL].sval;
+ pv[KRB_I_RL].sval = NULL;
+ } else if ( tmprealm ) {
+ krb4_init.realm = tmprealm;
+ tmprealm = NULL;
+ }
+ if (pv[KRB_I_IN].sval) {
+ krb4_init.instance = pv[KRB_I_IN].sval;
+ pv[KRB_I_IN].sval = NULL;
+ } else if ( tmpinst ) {
+ krb4_init.instance = tmpinst;
+ tmpinst = NULL;
+ }
+ krb4_init.preauth = pv[KRB_I_PA].ival;
+ krb4_init.verbose = pv[KRB_I_BR].ival ? 0 : 1;
+
+ if (tmpprinz) {
+ krb4_init.principal = tmpprinz;
+ tmpprinz = NULL;
+ }
+ krb4_init.password = tmppswd;
+ tmppswd = NULL;
+ }
+ break;
+ case KRB_A_LC: /* List Credentials */
+ krb5_lc.encryption = tmp_klc & XYKLCEN;
+ krb5_lc.flags = tmp_klc & XYKLCFL;
+ krb5_lc.addr = tmp_klc & XYKLCAD;
+ break;
+ }
+
+/* Common exit - Free temporary storage */
+
+ kerbx:
+ for (i = 0; i <= KRB_I_MAX; i++) { /* Free malloc'd switch data */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ }
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
+ if (tmpaddrs[i])
+ free(tmpaddrs[i]);
+ }
+ if (tmpprinz) free(tmpprinz); /* And these too. */
+ if (tmppswd) free(tmppswd);
+ if (tmpcache) free(tmpcache);
+ if (tmprealm) free(tmprealm);
+ if (tmpinst) free(tmpinst);
+
+ return(rc); /* Return the return code */
+}
+#endif /* CK_KERBEROS */
+
+#ifdef CK_LOGIN
+int
+#ifdef CK_ANSIC
+ckxlogin(CHAR * userid, CHAR * passwd, CHAR * acct, int promptok)
+#else /* CK_ANSIC */
+ckxlogin(userid, passwd, acct, promptok)
+ CHAR * userid; CHAR * passwd; CHAR * acct; int promptok;
+#endif /* CK_ANSIC */
+/* ckxlogin */ {
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+#ifdef COMMENT
+ extern int guest;
+#endif /* COMMENT */
+ int rprompt = 0; /* Restore prompt */
+#ifdef CKSYSLOG
+ int savlog;
+#endif /* CKSYSLOG */
+
+ extern int what, srvcdmsg;
+
+ int x = 0, ok = 0, rc = 0;
+ CHAR * _u = NULL, * _p = NULL, * _a = NULL;
+
+ debug(F111,"ckxlogin userid",userid,promptok);
+ debug(F110,"ckxlogin passwd",passwd,0);
+
+ isguest = 0; /* Global "anonymous" flag */
+
+ if (!userid) userid = (CHAR *)"";
+ if (!passwd) passwd = (CHAR *)"";
+
+ debug(F111,"ckxlogin userid",userid,what);
+
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+
+#ifdef CKSYSLOG
+ savlog = ckxsyslog; /* Save and turn off syslogging */
+#endif /* CKSYSLOG */
+
+ if ((!*userid || !*passwd) && /* Need to prompt for missing info */
+ promptok) {
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ debug(F110,"ckxlogin saved",psave,0);
+ rprompt = 1;
+ }
+ if (!*userid) {
+ if (!promptok)
+ return(0);
+ cmsetp("Username: "); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(1);
+
+/* Flush typeahead */
+
+#ifdef IKS_OPTION
+ debug(F101,
+ "ckxlogin TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ "",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+#endif /* IKS_OPTION */
+
+ while (ttchk() > 0) {
+ x = ttinc(0);
+ debug(F101,"ckxlogin flush user x","",x);
+ if (x < 0)
+ doexit(GOOD_EXIT,0); /* Connection lost */
+#ifdef TNCODE
+ if (sstelnet) {
+ if (x == IAC) {
+ x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc);
+ debug(F101,"ckxlogin user tn_doop","",x);
+#ifdef IKS_OPTION
+ debug(F101,
+ "ckxlogin user TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ "",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+#endif /* IKS_OPTION */
+
+ if (x < 0)
+ goto XCKXLOG;
+ switch (x) {
+ case 1: ckxech = 1; break; /* Turn on echoing */
+ case 2: ckxech = 0; break; /* Turn off echoing */
+#ifdef IKS_OPTION
+ case 4: /* IKS event */
+ if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ break; /* else fall thru... */
+#endif /* IKS_OPTION */
+ case 6: /* Logout */
+ goto XCKXLOG;
+ }
+ }
+ }
+#endif /* TNCODE */
+ }
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (x = -1; x < 0;) { /* Prompt till they answer */
+ /* Get a literal line of text */
+ x=cmtxt("Your username, or \"ftp\", or \"anonymous\"","",&s,NULL);
+ if (x == -4 || x == -10) {
+ printf("\r\n%sLogin cancelled\n",
+ x == -10 ? "Timed out: " : "");
+#ifdef CKSYSLOG
+ ckxsyslog = savlog;
+#endif /* CKSYSLOG */
+ doexit(GOOD_EXIT,0);
+ }
+ if (sstate) /* Did a packet come instead? */
+ goto XCKXLOG;
+ cmres(); /* Reset the parser again */
+ }
+ if ((_u = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XCKXLOG;
+ } else {
+ strcpy((char *)_u,s); /* safe */
+ userid = _u;
+ }
+ }
+ ok = zvuser((char *)userid); /* Verify username */
+ debug(F111,"ckxlogin zvuser",userid,ok);
+
+ if (!*passwd && promptok
+#ifdef COMMENT
+ && guest
+#endif /* COMMENT */
+ ) {
+ char prmpt[80];
+
+#ifdef CKSYSLOG
+ savlog = ckxsyslog; /* Save and turn off syslogging */
+ ckxsyslog = 0;
+#endif /* CKSYSLOG */
+
+/* Flush typeahead again */
+
+ while (ttchk() > 0) {
+ x = ttinc(0);
+ debug(F101,"ckxlogin flush user x","",x);
+#ifdef TNCODE
+ if (sstelnet) {
+ if (x == IAC) {
+ x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc);
+ debug(F101,"ckxlogin pass tn_doop","",x);
+#ifdef IKS_OPTION
+ debug(F101,
+ "ckxlogin pass TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ "",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+#endif /* IKS_OPTION */
+ if (x < 0)
+ goto XCKXLOG;
+ switch (x) {
+ case 1: ckxech = 1; break; /* Turn on echoing */
+ case 2: ckxech = 0; break; /* Turn off echoing */
+ case 4: /* IKS event */
+ if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ break; /* else fall thru... */
+ case 6: /* Logout */
+ goto XCKXLOG;
+ }
+ }
+ }
+#endif /* TNCODE */
+ }
+ if (!strcmp((char *)userid,"anonymous") ||
+ !strcmp((char *)userid,"ftp")) {
+ if (!ok)
+ goto XCKXLOG;
+ ckstrncpy(prmpt,"Enter e-mail address as Password: ",80);
+ } else if (*userid && strlen((char *)userid) < 60) {
+#ifdef NT
+ extern CHAR * pReferenceDomainName;
+ if (pReferenceDomainName)
+ ckmakxmsg(prmpt,
+ 80,
+ "Enter ",
+ pReferenceDomainName,
+ "\\\\",
+ userid,
+ "'s Password: ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ else
+#endif /* NT */
+ ckmakmsg(prmpt,80,"Enter ",(char *)userid,"'s Password: ",NULL);
+ } else
+ ckstrncpy(prmpt,"Enter Password: ",80);
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ if (strcmp((char *)userid,"anonymous") &&
+ strcmp((char *)userid,"ftp")) { /* and if not anonymous */
+ debok = 0;
+ cmini(0); /* and no-echo mode */
+ } else {
+ cmini(1);
+ }
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (x = -1; x < 0;) { /* Prompt till they answer */
+#ifdef CK_PAM
+ gotemptypasswd=0;
+#endif /* CK_PAM */
+ x = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ if (x == -4 || x == -10) {
+ printf("\r\n%sLogin cancelled\n",
+ x == -10 ? "Timed out: " : "");
+#ifdef CKSYSLOG
+ ckxsyslog = savlog;
+#endif /* CKSYSLOG */
+ doexit(GOOD_EXIT,0);
+ }
+#ifdef CK_PAM
+ if (!*s)
+ gotemptypasswd = 1;
+#endif /* CK_PAM */
+ if (sstate) /* In case of a Kermit packet */
+ goto XCKXLOG;
+ cmres(); /* Reset the parser again */
+ }
+ printf("\r\n"); /* Echo a CRLF */
+ if ((_p = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XCKXLOG;
+ } else {
+ strcpy((char *)_p,s); /* safe */
+ passwd = _p;
+ }
+ }
+#ifdef CK_PAM
+ else {
+ cmres(); /* Reset the parser */
+
+ /* We restore the prompt now because the PAM engine will call */
+ /* readpass() which will overwrite psave. */
+ if (rprompt) {
+ cmsetp(psave); /* Restore original prompt */
+ debug(F110,"ckxlogin restored",psave,0);
+ rprompt = 0;
+ }
+ }
+#endif /* CK_PAM */
+
+#ifdef CKSYSLOG
+ ckxsyslog = savlog;
+#endif /* CKSYSLOG */
+
+ if (ok) {
+ ok = zvpass((char *)passwd); /* Check password */
+ debug(F101,"ckxlogin zvpass","",ok);
+#ifdef CK_PAM
+ } else {
+ /* Fake pam password failure for nonexistent users */
+ sleep(1);
+ printf("Authentication failure\n");
+#endif /* CK_PAM */
+ }
+
+ if (ok > 0 && isguest) {
+#ifndef NOPUSH
+ nopush = 1;
+#endif /* NOPUSH */
+ srvcdmsg = 1;
+ }
+ rc = ok; /* Set the return code */
+ if ((char *)uidbuf != (char *)userid)
+ ckstrncpy(uidbuf,(char *)userid,UIDBUFLEN); /* Remember username */
+
+ XCKXLOG: /* Common exit */
+#ifdef CKSYSLOG
+ ckxsyslog = savlog; /* In case of GOTO above */
+#endif /* CKSYSLOG */
+ if (rprompt) {
+ cmsetp(psave); /* Restore original prompt */
+ debug(F110,"ckxlogin restored",psave,0);
+ }
+ if (_u || _p || _a) {
+ if (_u) free(_u);
+ if (_p) free(_p);
+ if (_a) free(_a);
+ }
+ return(rc);
+}
+
+int
+ckxlogout() {
+ doexit(GOOD_EXIT,0); /* doexit calls zvlogout */
+ return(0); /* not reached */
+}
+#endif /* CK_LOGIN */
+
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuusr.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusr.c
new file mode 100644
index 0000000..3b77fe6
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusr.c
@@ -0,0 +1,13376 @@
+#ifdef SSHTEST
+#define SSHBUILTIN
+#endif /* SSHTEST */
+
+#include "ckcsym.h"
+char *userv = "User Interface 9.0.299, 9 Jun 2011";
+
+/* C K U U S R -- "User Interface" for C-Kermit (Part 1) */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ Originally the entire user interface was in one module, ckuusr.c. Over
+ the years it has been split into many modules: ckuus2.c, ckuus3.c, ...,
+ ckuus7.c. ckuus2.c contains the HELP command parser and help-text strings;
+ ckuusy.c contains the UNIX-style command-line interface; ckuusx.c contains
+ routines needed by both the command-line interface and the interactive
+ command parser.
+*/
+
+/*
+ The ckuus*.c modules depend on the existence of C library features like
+ fopen, fgets, feof, (f)printf, argv/argc, etc. Other functions that are
+ likely to vary among different platforms -- like setting terminal modes or
+ interrupts -- are invoked via calls to functions that are defined in the
+ system- dependent modules, ck?[ft]io.c. The command line parser processes
+ any arguments found on the command line, as passed to main() via argv/argc.
+ The interactive parser uses the facilities of the cmd package (developed for
+ this program, but usable by any program). Any command parser may be
+ substituted for this one. The only requirements for the Kermit command
+ parser are these:
+
+ . Set parameters via global variables like duplex, speed, ttname, etc. See
+ ckcmai.c for the declarations and descriptions of these variables.
+
+ . If a command can be executed without the use of Kermit protocol, then
+ execute the command directly and set the variable sstate to 0. Examples
+ include 'set' commands, local directory listings, the 'connect' command.
+
+ . If a command requires the Kermit protocol, set the following variables:
+
+ sstate string data
+ 'x' (enter server mode) (none)
+ 'r' (send a 'get' command) cmarg, cmarg2
+ 'v' (enter receive mode) cmarg2
+ 'g' (send a generic command) cmarg
+ 's' (send files) nfils, cmarg & cmarg2 OR cmlist
+ 'c' (send a remote host command) cmarg
+
+ cmlist is an array of pointers to strings.
+ cmarg, cmarg2 are pointers to strings.
+ nfils is an integer.
+
+ cmarg can be a filename string (possibly wild), or
+ a pointer to a prefabricated generic command string, or
+ a pointer to a host command string.
+ cmarg2 is an "as-name" - the name to send file(s) under, or
+ the name under which to store incoming file(s); must not be wild.
+ A null or empty value means to use the file's own name.
+ cmlist is a list of filenames, such as passed via argv.
+ nfils is an integer, interpreted as follows:
+ -1: filespec (possibly wild) in cmarg, must be expanded internally.
+ 0: send from stdin (standard input).
+ >0: number of files to send, from cmlist.
+
+ The screen() function is used to update the screen during file transfer.
+ The tlog() function writes to a transaction log.
+ The debug() function writes to a debugging log.
+ The intmsg() and chkint() functions provide the user i/o for interrupting
+ file transfers.
+*/
+
+/* Includes */
+
+#ifdef MULTINET
+#define MULTINET_OLD_STYLE /* Leave select prototype undefined */
+#endif /* MULTINET */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckcnet.h" /* Network symbols */
+#include "ckuusr.h"
+#include "ckcxla.h"
+
+int g_fncact = -1; /* Needed for NOICP builds */
+int noinit = 0; /* Flag for skipping init file */
+int nscanfile = SCANFILEBUF;
+
+int rcdactive = 0; /* RCD active */
+int keepallchars = 0; /* See cmfld() */
+
+int locus = 1; /* Current LOCUS is LOCAL */
+#ifdef OS2
+int autolocus = 2; /* Automatic LOCUS switching: ASK */
+#else /* OS2 */
+int autolocus = 1; /* Automatic LOCUS switching enabled */
+#endif /* OS2 */
+
+#ifndef NOICP
+#ifdef CKLEARN
+#ifdef VMS
+#include <time.h> /* For CKLEARN */
+#endif /* VMS */
+#endif /* CKLEARN */
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.h" /* CK_TAPI definition */
+#endif /* NT */
+#include "ckowin.h"
+#include "ckocon.h"
+extern int tcp_avail;
+extern bool viewonly;
+extern int k95stdout;
+extern int tt_scroll;
+#ifndef NOTERM
+extern tt_status[VNUM];
+#endif /* NOTERM */
+int display_demo = 1;
+#include "ckossh.h"
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#endif /* OS2 */
+
+int optlines = 0;
+int didsetlin = 0;
+
+#ifdef NEWFTP
+extern int ftpget, ftpisopen(), doftpres();
+_PROTOTYP(int doftptyp,(int));
+_PROTOTYP(VOID doftpglobaltype,(int));
+#endif /* NEWFTP */
+
+#ifdef VMS
+extern int batch;
+#endif /* VMS */
+
+#ifdef datageneral
+#include <packets:common.h>
+#define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
+#endif /* datageneral */
+
+extern int xcmdsrc, hints, cmflgs, whyclosed;
+
+char * hlptok = NULL;
+
+#ifdef CK_TTGWSIZ /* Whether to use more-prompting */
+int xaskmore = 1; /* Momentary setting */
+int saveask = 1; /* Permanent setting */
+#else
+int xaskmore = 0;
+int saveask = 0;
+#endif /* CK_TTGWSIZ */
+
+#ifndef NOCSETS
+extern int nfilc;
+extern struct keytab fcstab[];
+extern int fcharset;
+#endif /* NOCSETS */
+
+char * g_pswd = NULL;
+int g_pcpt = -1;
+int g_pflg = -1;
+
+extern int cmd_rows, cmd_cols;
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+extern int inserver, filepeek;
+
+#ifdef CKLEARN
+FILE * learnfp = NULL;
+char * learnfile = NULL;
+int learning = 0;
+#endif /* CKLEARN */
+
+#ifndef NOXFER
+extern int atcapr, atdiso, nfils, moving, protocol, sendmode, epktflg, size,
+ sndsrc, server, displa, fncnv, fnspath, fnrpath, xfermode, urpsiz,
+ spsizf, spsiz, spsizr, spmax, wslotr, prefixing, fncact, reliable,
+ setreliable;
+
+#ifdef IKSDCONF
+extern int iksdcf;
+#endif /* IKSDCONF */
+
+#ifdef CK_LOGIN
+extern int isguest;
+#endif /* CK_LOGIN */
+
+extern CK_OFF_T sendstart;
+
+extern char *cmarg, *cmarg2, **cmlist, *dftty;
+
+extern struct keytab fntab[]; extern int nfntab;
+extern struct ck_p ptab[NPROTOS];
+
+int sndcmd = 0; /* Last command was a SEND-class command. */
+
+int g_xfermode = -1;
+int g_proto = -1;
+int g_urpsiz = -1;
+int g_spsizf = -1;
+int g_spsiz = -1;
+int g_spsizr = -1;
+int g_spmax = -1;
+int g_wslotr = -1;
+int g_prefixing = -1;
+int g_fncnv = -1;
+int g_fnspath = -1;
+int g_fnrpath = -1;
+int g_fnact = -1;
+int g_displa = -1;
+int g_spath = -1;
+int g_rpath = -1;
+char * g_sfilter = NULL;
+char * g_rfilter = NULL;
+
+extern int patterns;
+#ifdef PATTERNS
+extern char *txtpatterns[], *binpatterns[];
+int g_patterns = -1;
+#endif /* PATTERNS */
+int g_skipbup = -1;
+
+#ifdef PIPESEND
+extern int usepipes, pipesend;
+extern char * sndfilter;
+#endif /* PIPESEND */
+
+#ifndef NOSPL
+extern int sndxlo, sndxhi, sndxin;
+#endif /* NOSPL */
+
+extern char fspec[]; /* Most recent filespec */
+extern int fspeclen; /* Length of fspec[] buffer */
+
+#ifndef NOFRILLS
+extern int rmailf; /* MAIL command items */
+extern char optbuf[];
+#endif /* NOFRILLS */
+
+extern int
+ en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri,
+ en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit,
+ en_mkd, en_rmd, en_asg;
+
+#ifndef NOMSEND /* Multiple SEND */
+extern char *msfiles[];
+int filesinlist = 0; /* And ADD ... */
+extern struct filelist * filehead;
+extern struct filelist * filetail;
+extern struct filelist * filenext;
+extern int addlist;
+#endif /* NOMSEND */
+
+static struct keytab addtab[] = {
+#ifdef PATTERNS
+ { "binary-patterns", ADD_BIN, 0 },
+#endif /* PATTERNS */
+#ifndef NOMSEND
+ { "send-list", ADD_SND, 0 },
+#endif /* NOMSEND */
+#ifdef PATTERNS
+ { "text-patterns", ADD_TXT, 0 },
+#endif /* PATTERNS */
+ { "", 0, 0 }
+};
+static int naddtab = sizeof(addtab)/sizeof(struct keytab) - 1;
+
+#ifndef NOCSETS
+struct keytab assoctab[] = {
+ { "file-character-set", ASSOC_FC, 0 },
+ { "transfer-character-set", ASSOC_TC, 0 },
+ { "xfer-character-set", ASSOC_TC, CM_INV }
+};
+static int nassoc = sizeof(assoctab)/sizeof(struct keytab);
+extern int afcset[MAXFCSETS+1]; /* Character-set associations */
+extern int axcset[MAXTCSETS+1];
+#endif /* NOCSETS */
+
+#ifndef ADDCMD
+#ifndef NOMSEND
+#define ADDCMD
+#endif /* NOMSEND */
+#ifndef ADDCMD
+#ifdef PATTERNS
+#define ADDCMD
+#endif /* PATTERNS */
+#endif /* ADDCMD */
+#endif /* ADDCMD */
+#endif /* NOXFER */
+
+/* External Kermit Variables, see ckmain.c for description. */
+
+extern xx_strp xxstring;
+extern long xvernum;
+
+extern int local, xitsta, binary, msgflg, escape, duplex, quiet, tlevel,
+ pflag, zincnt, ckxech, carrier, what, nopush, haveline, bye_active;
+#ifdef TNCODE
+extern int debses;
+extern char tn_msg[];
+#endif /* TNCODE */
+
+int sleepcan = 1;
+int g_binary = -1;
+int g_recursive = -1;
+int g_matchdot = -1;
+extern int nolinks;
+
+extern long vernum;
+extern char *versio, *copyright[];
+extern char *ckxsys;
+#ifndef NOHELP
+extern char *introtxt[];
+extern char *newstxt[];
+#endif /* NOHELP */
+
+#ifndef OS2
+#ifndef UNIX
+extern char *PWDCMD;
+#endif /* UNIX */
+extern char *WHOCMD;
+#endif /* OS2 */
+
+extern char ttname[];
+
+extern CHAR sstate;
+
+extern int network; /* Have active network connection */
+extern int nettype; /* Type of network */
+extern int ttnproto; /* NET_TCPB protocol */
+
+#ifndef NODIAL
+extern int dialsta, dialatmo, dialcon, dialcq; /* DIAL status, etc. */
+#endif /* NODIAL */
+
+#ifdef CK_APC
+extern int apcactive, apcstatus;
+#endif /* CK_APC */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+extern char editor[];
+extern char editopts[];
+extern char editfile[];
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifdef BROWSER
+extern char browser[]; /* Web browser application */
+extern char browsopts[]; /* Web browser options */
+extern char browsurl[]; /* Most recent URL */
+#endif /* BROWSER */
+#ifndef NOFTP
+char ftpapp[CKMAXPATH+1] = { NUL, NUL }; /* ftp executable */
+char ftpopts[128] = { NUL, NUL }; /* ftp command-line options */
+#endif /* NOFTP */
+extern struct keytab onoff[]; /* On/Off keyword table */
+
+#ifdef CK_TMPDIR
+int f_tmpdir = 0; /* Directory changed temporarily */
+char savdir[TMPDIRLEN]; /* For saving current directory */
+#endif /* CK_TMPDIR */
+
+int activecmd = -1; /* Keyword index of active command */
+int doconx = -1; /* CONNECT-class command active */
+int ooflag = 0; /* User-settable on/off flag */
+
+int rcflag = 0; /* Pointer to home directory string */
+int repars, /* Reparse needed */
+ techo = 0; /* Take echo */
+int secho = 1; /* SCRIPT echo */
+
+int xitwarn = /* Warn about open connection on exit */
+#ifdef NOWARN
+0
+#else
+1
+#endif /* NOWARN */
+;
+
+struct keytab onoffsw[] = {
+ { "/off", 0, 0 },
+ { "/on", 1, 0 }
+};
+
+#ifdef CKEXEC
+struct keytab redirsw[] = {
+ { "/redirect", 1, 0 }
+};
+#endif /* CKEXEC */
+
+#ifndef NOXMIT
+/* Variables for TRANSMIT command */
+
+int xmitx = 1; /* Whether to echo during TRANSMIT */
+int xmitf = 0; /* Character to fill empty lines */
+int xmitl = 0; /* 0 = Don't send linefeed too */
+int xmitp = LF; /* Host line prompt */
+int xmits = 0; /* Use shift-in/shift-out, 0 = no */
+int xmitw = 0; /* Milliseconds to pause during TRANSMIT */
+int xmitt = 1; /* Seconds to wait for each char to echo */
+int xmita = 1; /* Action upon timeout */
+
+#define XMI_BIN 1
+#define XMI_TXT 2
+#define XMI_CMD 3
+#define XMI_TRA 4
+#define XMI_VRB 5
+#define XMI_QUI 6
+#define XMI_NOW 7
+#define XMI_NOE 8
+
+static struct keytab xmitsw[] = { /* TRANSMIT command options */
+ { "/binary", XMI_BIN, 0 },
+#ifdef PIPESEND
+ { "/command", XMI_CMD, CM_INV|CM_PSH },
+#endif /* PIPESEND */
+ { "/noecho", XMI_NOE, 0 },
+ { "/nowait", XMI_NOW, 0 },
+#ifdef PIPESEND
+ { "/pipe", XMI_CMD, 0 },
+#endif /* PIPESEND */
+#ifdef COMMENT
+ { "/quiet", XMI_QUI, 0 },
+#endif /* COMMENT */
+ { "/text", XMI_TXT, 0 },
+ { "/transparent", XMI_TRA, 0 },
+#ifdef COMMENT
+ { "/verbose", XMI_VRB, 0 },
+#endif /* COMMENT */
+ { "", 0, 0 }
+};
+#define NXMITSW sizeof(xmitsw)/sizeof(struct keytab) - 1
+static int nxmitsw = NXMITSW;
+
+#endif /* NOXMIT */
+
+/* Declarations from ck?fio.c module */
+
+extern char *SPACMD, *SPACM2; /* SPACE commands */
+
+/* Command-oriented items */
+
+#ifdef DCMDBUF
+extern char *cmdbuf; /* Command buffers */
+extern char *atmbuf;
+extern char *line; /* Character buffer for anything */
+extern char *tmpbuf; /* Short temporary string buffer */
+extern int *ifcmd;
+extern int *intime;
+extern int *inpcas;
+#else
+extern char cmdbuf[]; /* Command buffers */
+extern char atmbuf[];
+extern char line[]; /* Character buffer for anything */
+extern char tmpbuf[]; /* Temporary buffer */
+extern int ifcmd[];
+extern int intime[];
+extern int inpcas[];
+#endif /* DCMDBUF */
+
+#ifndef NOSPL
+extern char * prstring[];
+#endif /* NOSPL */
+
+char *lp; /* Pointer to line buffer */
+
+#ifndef NOSPL
+int vareval = 1; /* Evaluation method */
+int unkmacro = 0; /* Flag for in ON_UNKNOWN_COMMAND */
+int oldeval = 0;
+char evalbuf[33]; /* EVALUATE result */
+extern char * inpbuf; /* Buffer for INPUT and REINPUT */
+char *inpbp; /* And pointer to same */
+int m_found; /* MINPUT result */
+int i_active = 0; /* INPUT command is active */
+char *ms[MINPMAX]; /* Pointers to MINPUT strings */
+static int mpinited = 0; /* Flag they have been initialized */
+static int mp[MINPMAX]; /* and MINPUT flags */
+extern int fndiags, fnerror, fnsuccess; /* Function diagnostics */
+#ifndef NOSEXP
+char * lastsexp = NULL; /* S-Expressions */
+char * sexpval = NULL;
+int sexpecho = SET_AUTO;
+#endif /* NOSEXP */
+#endif /* NOSPL */
+
+char psave[PROMPTL] = { NUL }; /* For saving & restoring prompt */
+
+extern int success; /* Command success/failure flag */
+extern int cmdlvl; /* Current position in command stack */
+
+#ifndef NOSPL
+int /* SET INPUT parameters. */
+/* Note, INPUT TIMEOUT, intime[], is on the command-level stack. */
+ inbufsize = 0, /* INPUT buffer size */
+ indef = 1, /* default timeout, seconds */
+ inecho = 1, /* 1 = echo on */
+ inautodl = 0, /* INPUT autodownload */
+ inintr = 1, /* INPUT interrupion allowed */
+ insilence = 0; /* 0 = no silence constraint */
+
+#ifdef CKFLOAT
+CKFLOAT inscale = 1.0; /* Timeout scale factor */
+#endif /* CKFLOAT */
+
+#ifdef OS2
+int interm = 1; /* Terminal emulator displays input */
+#endif /* OS2 */
+int maclvl = -1; /* Macro nesting level */
+int mecho = 0; /* Macro echo, 0 = don't */
+char varnam[6]; /* For variable names */
+extern int macargc[]; /* ARGC from macro invocation */
+
+extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */
+extern char *mrval[];
+
+extern char **a_ptr[]; /* Array pointers */
+extern int a_dim[]; /* Array dimensions */
+extern int a_link[];
+
+#ifdef DCMDBUF
+extern struct cmdptr *cmdstk; /* The command stack itself */
+#else
+extern struct cmdptr cmdstk[]; /* The command stack itself */
+#endif /* DCMDBUF */
+
+long ck_alarm = 0; /* SET ALARM value */
+char alrm_date[24] = { ' ',' ',' ',' ',' ',' ',' ',' ',' ' };
+char alrm_time[24] = { ' ',' ',' ',' ',' ',' ',' ' };
+
+struct keytab inputsw[] = {
+ { "/clear", INPSW_CLR, 0 },
+ { "/count", INPSW_COU, CM_ARG },
+ { "/nomatch", INPSW_NOM, 0 },
+ { "/nowrap", INPSW_NOW, 0 }
+};
+static int ninputsw = sizeof(inputsw)/sizeof(struct keytab);
+
+/* The following should be reconciled with the above */
+
+#ifdef COMMENT /* INPUT switches not used yet... */
+static struct keytab inswtab[] = {
+#ifdef COMMENT
+ { "/assign", IN_ASG, CM_ARG },
+#endif /* COMMENT */
+ { "/autodownload", IN_ADL, CM_ARG },
+ { "/case", IN_CAS, CM_ARG },
+ { "/echo", IN_ECH, CM_ARG },
+ { "/interrupts", IN_NOI, CM_ARG },
+ { "/silence", IN_SIL, CM_ARG },
+#ifdef COMMENT
+ { "/pattern", IN_PAT, CM_ARG },
+#endif /* COMMENT */
+ { "", 0, 0 }
+};
+static int ninswtab = (sizeof(inswtab) / sizeof(struct keytab)) - 1;
+#endif /* COMMENT */
+
+
+#endif /* NOSPL */
+
+static int x, y, z = 0; /* Local workers */
+static char *s;
+
+#ifdef CK_MINPUT
+static char c1chars[] = { /* C1 control chars escept NUL */
+ 001,002,003,004,005,006,007,010,011,012,013,014,015,016,017,020,
+ 021,022,023,024,025,026,027,030,031,032,033,034,035,036,037
+};
+#endif /* CK_MINPUT */
+
+#define xsystem(s) zsyscmd(s)
+
+/* Top-Level Interactive Command Keyword Table */
+/* Keywords must be in lowercase and in alphabetical order. */
+
+struct keytab cmdtab[] = {
+#ifndef NOPUSH
+ { "!", XXSHE, CM_INV|CM_PSH }, /* Shell escape */
+#else
+ { "!", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOPUSH */
+ { "#", XXCOM, CM_INV }, /* Comment */
+#ifndef NOSPL
+ { "(", XXSEXP,CM_INV }, /* S-Expression */
+ { ".", XXDEF, CM_INV }, /* Assignment */
+ { ":", XXLBL, CM_INV }, /* Label */
+#endif /* NOSPL */
+#ifdef CK_REDIR
+#ifndef NOPUSH
+ { "<", XXFUN, CM_INV|CM_PSH }, /* REDIRECT */
+#else
+ { "<", XXNOTAV, CM_INV|CM_PSH }, /* REDIRECT */
+#endif /* NOPUSH */
+#endif /* CK_REDIR */
+#ifndef NOPUSH
+ { "@", XXSHE, CM_INV|CM_PSH }, /* DCL escape */
+#else
+ { "@", XXNOTAV, CM_INV|CM_PSH }, /* DCL escape */
+#endif /* NOPUSH */
+
+#ifdef CK_RECALL
+ { "^", XXREDO,CM_INV|CM_NOR }, /* Synonym for REDO */
+#endif /* CK_RECALL */
+#ifndef NOSPL
+ { "_asg", XXASX, CM_INV }, /* Used internally by FOR, etc */
+ { "_assign", XXASX, CM_INV }, /* Used internally by FOR, etc */
+ { "_decrement", XX_DECR, CM_INV },
+ { "_define", XXDFX, CM_INV }, /* Used internally by FOR, etc */
+ { "_evaluate", XX_EVAL, CM_INV },
+ { "_forward", XXXFWD, CM_INV }, /* Used internally by SWITCH */
+ { "_getargs", XXGTA, CM_INV }, /* Used internally by FOR, etc */
+ { "_increment", XX_INCR, CM_INV },
+ { "_putargs", XXPTA, CM_INV }, /* Used internally by FOR, etc */
+ { "_undefine", XXUNDFX, CM_INV },
+#endif /* NOSPL */
+
+ { "about", XXVER, CM_INV }, /* Synonym for VERSION */
+#ifndef NOSPL
+#ifdef NEWFTP
+ { "account", XXACCT, CM_INV }, /* (FTP) Account */
+#endif /* NEWFTP */
+#ifdef ADDCMD
+ { "add", XXADD, 0 }, /* ADD */
+#endif /* ADDCMD */
+#ifndef NODIAL
+ { "answer", XXANSW, CM_LOC }, /* ANSWER the phone */
+#else
+ { "answer", XXNOTAV, CM_INV|CM_LOC }, /* ANSWER the phone */
+#endif /* NODIAL */
+ { "apc", XXAPC, 0 }, /* Application Program Command */
+#ifndef NOSPL
+ { "array", XXARRAY, 0 }, /* Array operations */
+#endif /* NOSPL */
+ { "ascii", XXASC, CM_INV }, /* == SET FILE TYPE TEXT */
+ { "asg", XXASS, CM_INV }, /* Invisible synonym for ASSIGN */
+ { "ask", XXASK, 0 }, /* ASK for text, assign to variable */
+ { "askq", XXASKQ,0 }, /* ASK quietly (no echo) */
+#ifndef NOSPL
+ { "ass", XXASS, CM_INV|CM_ABR }, /* ASSIGN */
+ { "assert", XXASSER, CM_INV }, /* ASSERT */
+ { "assign", XXASS, 0 }, /* ASSIGN */
+#endif /* NOSPL */
+#ifndef NOXFER
+#ifndef NOCSETS
+ { "associate", XXASSOC, 0 }, /* ASSOCIATE */
+#else
+ { "associate", XXNOTAV, CM_INV }, /* ASSOCIATE */
+#endif /* NOCSETS */
+#endif /* NOXFER */
+#ifdef CK_KERBEROS
+#ifdef CK_AUTHENTICATION
+ { "authenticate",XXAUTH, 0 }, /* Authentication */
+#else
+ { "authenticate",XXAUTH, CM_INV },
+#endif /* CK_AUTHENTICATION */
+#endif /* CK_KERBEROS */
+#endif /* NOSPL */
+#ifndef NOFRILLS
+ { "back", XXBACK, 0 }, /* BACK to previous directory */
+#else
+ { "back", XXNOTAV,CM_INV },
+#endif /* NOFRILLS */
+ { "beep", XXBEEP,CM_INV }, /* BEEP */
+#ifndef NOXFER
+ { "binary", XXBIN, CM_INV }, /* == SET FILE TYPE BINARY */
+#endif /* NOXFER */
+#ifndef NOFRILLS
+ { "bug", XXBUG, CM_INV }, /* BUG report instructions */
+#else
+ { "bug", XXNOTAV, CM_INV },
+#endif /* NOFRILLS */
+#ifdef BROWSER
+ { "browse", XXBROWS, CM_PSH|CM_LOC }, /* BROWSE (start browser) */
+#else
+ { "browse", XXNOTAV, CM_INV|CM_PSH|CM_LOC },
+#endif /* BROWSER */
+#ifndef NOXFER
+ { "bye", XXBYE, 0 }, /* BYE to remote server */
+#endif /* NOXFER */
+#ifndef NOLOCAL
+ { "c", XXCON, CM_INV|CM_ABR|CM_LOC }, /* (CONNECT) */
+#endif /* NOLOCAL */
+#ifndef NOFRILLS
+ { "cat", XXCAT, CM_INV }, /* Invisible synonym for TYPE */
+#endif /* NOFRILLS */
+#ifndef NOSPL
+
+#ifndef NOXFER
+ { "cautious", XXCAU, CM_INV },
+#endif /* NOXFER */
+
+#endif /* NOSPL */
+
+ { "cd", XXCWD, 0 }, /* Change Directory */
+ { "cdup", XXCDUP, CM_INV }, /* Change Directory Up */
+
+#ifndef NOXFER
+#ifdef PIPESEND
+ { "cget", XXCGET, CM_INV|CM_PSH }, /* CGET */
+#else
+ { "cget", XXNOTAV, CM_INV|CM_PSH }, /* CGET */
+#endif /* PIPESEND */
+#endif /* NOXFER */
+ { "ch", XXCHK, CM_INV|CM_ABR },
+ { "check", XXCHK, 0 }, /* CHECK for a feature */
+#ifdef CK_PERMS
+#ifdef UNIX
+ { "chmod", XXCHMOD, 0 }, /* CHMOD */
+#else
+ { "chmod", XXNOTAV, CM_INV },
+#endif /* UNIX */
+#else
+ { "chmod", XXNOTAV, CM_INV },
+#endif /* CK_PERMS */
+#ifdef CKROOT
+ { "chroot", XXCHRT, CM_INV }, /* CHROOT */
+#endif /* CKROOT */
+ { "ckermit", XXKERMI, CM_INV }, /* CKERMIT (like KERMIT) */
+ { "cl", XXCLO, CM_ABR|CM_INV },
+#ifndef NOFRILLS
+ { "clear", XXCLE, 0 }, /* CLEAR input and/or device buffer */
+#else
+ { "clear", XXNOTAV, CM_INV },
+#endif /* NOFRILLS */
+ { "close", XXCLO, 0 }, /* CLOSE a log or other file */
+ { "cls", XXCLS, CM_INV }, /* Clear Screen (CLS) */
+ { "comment", XXCOM, CM_INV }, /* Introduce a comment */
+#ifndef NOLOCAL
+ { "connect", XXCON, CM_LOC }, /* Begin terminal connection */
+#else
+ { "connect", XXNOTAV, CM_LOC },
+#endif /* NOLOCAL */
+ { "continue", XXCONT, CM_INV }, /* CONTINUE */
+#ifndef NOFRILLS
+#ifdef ZCOPY
+ { "co", XXCPY, CM_INV|CM_ABR },
+ { "cop", XXCPY, CM_INV|CM_ABR },
+ { "copy", XXCPY, 0 }, /* COPY a file */
+#else
+ { "copy", XXNOTAV, CM_INV },
+#endif /* ZCOPY */
+ { "copyright", XXCPR, CM_INV }, /* COPYRIGHT */
+#ifdef ZCOPY
+ { "cp", XXCPY, CM_INV }, /* COPY a file */
+#endif /* ZCOPY */
+#ifndef NOLOCAL
+#ifndef OS2
+ { "cq", XXCQ, CM_INV|CM_LOC }, /* CQ (connect quietly) */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifndef NOXFER
+#ifdef PIPESEND
+ { "creceive", XXCREC,CM_INV|CM_PSH }, /* RECEIVE to a command */
+ { "csend", XXCSEN,CM_INV|CM_PSH }, /* SEND from command */
+#else
+ { "creceive", XXNOTAV,CM_INV|CM_PSH },
+ { "csend", XXNOTAV,CM_INV|CM_PSH },
+#endif /* PIPESEND */
+#endif /* NOXFER */
+#endif /* NOFRILLS */
+
+ { "cwd", XXCWD, CM_INV }, /* Traditional synonym for cd */
+
+#ifndef NOSPL
+ { "date", XXDATE, 0 }, /* DATE */
+ { "dcl", XXDCL, CM_INV }, /* DECLARE an array (see ARRAY) */
+ { "debug", XXDEBUG, 0 }, /* Print a debugging msg [9.0] */
+ { "declare", XXDCL, CM_INV }, /* DECLARE an array (see ARRAY) */
+ { "decrement", XXDEC, 0 }, /* DECREMENT a numeric variable */
+ { "define", XXDEF, 0 }, /* DEFINE a macro or variable */
+#else
+ { "date", XXNOTAV, CM_INV },
+ { "dcl", XXNOTAV, CM_INV },
+ { "declare", XXNOTAV, CM_INV },
+ { "decrement", XXNOTAV, CM_INV },
+ { "define", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+ { "delete", XXDEL, 0 }, /* DELETE a file */
+#else
+ { "delete", XXNOTAV, CM_INV },
+#endif /* NOFRILLS */
+
+#ifndef NODIAL
+ { "dial", XXDIAL, CM_LOC }, /* DIAL a phone number */
+#else
+ { "dial", XXNOTAV, CM_INV|CM_LOC },
+#endif /* NODIAL */
+
+#ifdef NT
+ { "dialer", XXDIALER, CM_INV }, /* K95 Dialer */
+#endif /* NT */
+
+ { "directory", XXDIR, 0 }, /* DIRECTORY of files */
+
+#ifndef NOFRILLS
+#ifndef NOSERVER
+ { "disable", XXDIS, 0 }, /* DISABLE a server function */
+#else
+ { "disable", XXNOTAV, CM_INV },
+#endif /* NOSERVER */
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+ { "do", XXDO, 0 }, /* DO (execute) a macro */
+#else
+ { "do", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+ { "e", XXEXI, CM_INV|CM_ABR },
+
+#ifndef NOFRILLS
+#ifndef NOXFER
+ { "e-packet", XXERR, CM_INV }, /* Send an Error-Packet */
+#endif /* NOXFER */
+#endif /* NOFRILLS */
+
+ { "echo", XXECH, 0 }, /* ECHO text */
+
+#ifndef NOFRILLS
+#ifndef NOPUSH
+ { "edit", XXEDIT, CM_PSH }, /* EDIT */
+#else
+ { "edit", XXNOTAV, CM_INV|CM_PSH }, /* EDIT */
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+ { "eightbit", XXEIGHT, CM_INV }, /* EIGHTBIT */
+
+#ifndef NOSPL
+ { "else", XXELS, CM_INV }, /* ELSE part of IF statement */
+#else
+ { "else", XXNOTAV, CM_INV }, /* ELSE part of IF statement */
+#endif /* NOSPL */
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+ { "enable", XXENA, 0 }, /* ENABLE a server function */
+#else
+ { "enable", XXNOTAV, CM_INV },
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+ { "end", XXEND, 0 }, /* END command file or macro */
+#else
+ { "end", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+ { "erase", XXDEL, CM_INV }, /* Synonym for DELETE */
+
+#ifndef NOSPL
+ { "evaluate", XXEVAL, 0 }, /* EVALUATE */
+#else
+ { "evaluate", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+ { "ex", XXEXI, CM_INV|CM_ABR }, /* Let "ex" still be EXIT */
+
+#ifdef CKEXEC
+ { "exec", XXEXEC, CM_INV|CM_LOC }, /* exec() */
+#else
+ { "exec", XXNOTAV, CM_INV|CM_LOC },
+#endif /* CKEXEC */
+
+ { "exit", XXEXI, 0 }, /* EXIT from C-Kermit */
+ { "extended-options", XXXOPTS,CM_INV|CM_HLP }, /* Extended-Options */
+
+#ifdef OS2
+ { "extproc", XXCOM, CM_INV }, /* Dummy command for OS/2 */
+#endif /* OS2 */
+
+#ifndef NOXFER
+ { "f", XXFIN, CM_INV|CM_ABR }, /* Invisible abbrev for FIN */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ { "fail", XXFAIL, CM_INV }, /* FAIL */
+
+#ifndef NOXFER
+ { "fast", XXFAST, CM_INV },
+#endif /* NOXFER */
+
+#ifdef CKCHANNELIO
+ { "fclose", XXF_CL, CM_INV }, /* FCLOSE */
+ { "fcount", XXF_CO, CM_INV }, /* FCOUNT */
+ { "fflush", XXF_FL, CM_INV }, /* FFLUSH */
+#endif /* CKCHANNELIO */
+
+#ifndef NOXFER
+ { "fi", XXFIN, CM_INV|CM_ABR }, /* FINISH */
+#endif /* NOXFER */
+
+#ifdef CKCHANNELIO
+ { "file", XXFILE, 0 }, /* FILE */
+#endif /* CKCHANNELIO */
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ { "fin", XXFIN, CM_INV|CM_ABR }, /* FINISH */
+#endif /* NOXFER */
+
+#ifndef UNIXOROSK
+ { "find", XXGREP, 0 }, /* FIND (grep) */
+#else
+ { "find", XXGREP,CM_INV },
+#endif /* UNIXOROSK */
+
+#ifndef NOXFER
+ { "finish", XXFIN, 0 }, /* FINISH */
+#endif /* NOXFER */
+
+#ifdef TCPSOCKET
+ { "firewall", XXFIREW, CM_INV|CM_HLP },
+#endif /* TCPSOCKET */
+
+#ifdef CKCHANNELIO
+ { "flist", XXF_LI, CM_INV }, /* FLIST */
+ { "fopen", XXF_OP, CM_INV }, /* FOPEN */
+#endif /* CKCHANNELIO */
+
+#ifndef NOSPL
+ { "fo", XXFOR, CM_INV|CM_ABR }, /* Invisible abbrev for... */
+ { "for", XXFOR, 0 }, /* FOR loop */
+ { "forward", XXFWD, CM_INV }, /* FORWARD */
+#endif /* NOSPL */
+#ifndef NOFRILLS
+ { "fot", XXDIR, CM_INV }, /* "fot" = "dir" (for Chris) */
+#endif /* NOFRILLS */
+
+#ifdef CKCHANNELIO
+ { "fread", XXF_RE, CM_INV }, /* FREAD */
+ { "frewind", XXF_RW, CM_INV }, /* FREWIND */
+ { "fseek", XXF_SE, CM_INV }, /* FSEEK */
+ { "fstatus", XXF_ST, CM_INV }, /* FSTATUS */
+#endif /* CKCHANNELIO */
+
+#ifdef TCPSOCKET
+#ifndef NOFTP
+#ifdef SYSFTP
+#ifndef NOPUSH
+ { "ftp", XXFTP, CM_INV|CM_PSH|CM_LOC }, /* System FTP */
+#else
+ { "ftp", XXNOTAV, CM_INV|CM_PSH|CM_LOC },
+#endif /* NOPUSH */
+#else /* SYSFTP */
+ { "ftp", XXFTP, 0 }, /* Built-in FTP */
+#endif /* SYSFTP */
+#else /* NOFTP */
+ { "ftp", XXNOTAV, CM_INV }, /* No FTP */
+#endif /* NOFTP */
+#endif /* TCPSOCKET */
+
+#ifndef NOSPL
+ { "function", XXFUNC, CM_INV|CM_HLP }, /* (for HELP FUNCTION) */
+#endif /* NOSPL */
+
+#ifdef CKCHANNELIO
+ { "fwrite", XXF_WR, CM_INV }, /* FWRITE */
+#endif /* CKCHANNELIO */
+
+#ifndef NOXFER
+ { "g", XXGET, CM_INV|CM_ABR }, /* Invisible abbrev for GET */
+#ifndef NOSPL
+ { "ge", XXGET, CM_INV|CM_ABR }, /* Ditto */
+#endif /* NOSPL */
+ { "get", XXGET, 0 }, /* GET */
+#endif /* NOXFER */
+#ifndef NOSPL
+ { "getc", XXGETC, 0 }, /* GETC */
+#ifdef OS2
+ { "getkeycode", XXGETK, 0 }, /* GETKEYCODE */
+#endif /* OS2 */
+#ifndef NOFRILLS
+ { "getok", XXGOK, 0 }, /* GETOK (ask for Yes/No/OK) */
+#endif /* NOFRILLS */
+#endif /* NOSPL */
+#ifndef NOSPL
+ { "goto", XXGOTO,0 }, /* GOTO label in take file or macro */
+#endif /* NOSPL */
+#ifdef UNIXOROSK
+ { "grep", XXGREP,0 }, /* GREP (find) */
+#else
+ { "grep", XXGREP,CM_INV }, /* GREP (find) */
+#endif /* UNIXOROSK */
+ { "h", XXHLP, CM_INV|CM_ABR }, /* Invisible synonym for HELP */
+ { "he", XXHLP, CM_INV|CM_ABR }, /* Invisible synonym for HELP */
+#ifndef NOFRILLS
+ { "head", XXHEAD, 0 },
+#endif /* NOFRILLS */
+#ifndef NOLOCAL
+ { "hangup", XXHAN, CM_LOC }, /* HANGUP the connection */
+#endif /* NOLOCAL */
+ { "hdirectory", XXHDIR, CM_INV }, /* DIR sorted by size biggest first */
+ { "HELP", XXHLP, 0 }, /* Display HELP text */
+#ifndef NOHTTP
+#ifdef TCPSOCKET
+ { "http", XXHTTP, 0 }, /* HTTP operations */
+#endif /* TCPSOCKET */
+#endif /* NOHTTP */
+#ifndef NOSPL
+ { "i", XXINP, CM_INV|CM_ABR }, /* Invisible synonym for INPUT */
+ { "if", XXIF, 0 }, /* IF ( condition ) command */
+#ifdef TCPSOCKET
+ { "iksd", XXIKSD, CM_INV }, /* Make connection to IKSD */
+#else
+ { "iksd", XXNOTAV, CM_INV },
+#endif /* TCPSOCKET */
+ { "in", XXINP, CM_INV|CM_ABR }, /* Invisible synonym for INPUT */
+ { "increment", XXINC, 0 }, /* Increment a numeric variable */
+ { "input", XXINP, 0 }, /* INPUT text from comm device */
+#endif /* NOSPL */
+
+#ifndef NOHELP
+ { "int", XXINT, CM_INV|CM_ABR },
+ { "intr", XXINT, CM_INV|CM_ABR },
+ { "INTRO", XXINT, 0 },
+ { "introduction",XXINT, CM_INV }, /* Print introductory text */
+#else
+ { "intro", XXNOTAV, CM_INV },
+ { "introduction",XXNOTAV, CM_INV },
+#endif /* NOHELP */
+
+#ifdef OS2
+ { "k95", XXKERMI, CM_INV }, /* Hmmm what's this... */
+#endif /* OS2 */
+
+#ifndef NOSPL
+ { "kcd", XXKCD, 0 },
+#endif /* NOSPL */
+
+ { "kermit", XXKERMI, CM_INV },
+
+#ifdef OS2
+#ifndef NOKVERBS
+ { "kverb", XXKVRB, CM_INV|CM_HLP }, /* Keyboard verb */
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+#ifndef NOFRILLS
+ { "l", XXLOG, CM_INV|CM_ABR }, /* Invisible synonym for log */
+#endif /* NOFRILLS */
+
+ { "lcd", XXLCWD, CM_INV },
+ { "lcdup", XXLCDU, CM_INV },
+ { "lcwd", XXLCWD, CM_INV },
+ { "ldelete", XXLDEL, CM_INV },
+ { "ldirectory", XXLDIR, CM_INV },
+
+#ifdef CKLEARN
+ { "learn", XXLEARN, 0 }, /* LEARN - automatic script writing */
+#else
+ { "learn", XXNOTAV, CM_INV },
+#endif /* CKLEARN */
+
+ { "li", XXLNOUT, CM_INV|CM_ABR },
+ { "LICENSE", XXCPR, 0 }, /* LICENSE */
+
+#ifndef NOSPL
+ { "lineout", XXLNOUT, 0 }, /* LINEOUT = OUTPUT + eol */
+#endif /* NOSPL */
+
+#ifdef NT
+ { "link", XXLINK, 0 }, /* LINK source destination */
+#endif /* NT */
+
+ { "lmkdir", XXLMKD, CM_INV },
+ { "lmv", XXLREN, CM_INV },
+
+#ifndef NOFRILLS
+ { "lo", XXLOG, CM_INV|CM_ABR }, /* Invisible synonym for log */
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+ { "local", XXLOCAL, CM_INV }, /* LOCAL variable declaration */
+#else
+ { "local", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+ { "locus", XXLOCU, CM_INV|CM_HLP }, /* "help locus" */
+
+ { "log", XXLOG, 0 }, /* Open a log file */
+
+ { "login", XXLOGIN, 0 }, /* (REMOTE) LOGIN to server or IKSD */
+ { "logout", XXLOGOUT, 0 }, /* LOGOUT from server or IKSD */
+
+#ifndef NOFRILLS
+#ifndef NODIAL
+ { "lookup", XXLOOK, 0 }, /* LOOKUP */
+#else
+ { "lookup", XXNOTAV, CM_INV },
+#endif /* NODIAL */
+
+ { "lpwd", XXLPWD, CM_INV },
+ { "lrename", XXLREN, CM_INV },
+ { "lrmdir", XXLRMD, CM_INV },
+
+#ifdef UNIXOROSK
+ { "ls", XXLS, CM_INV|CM_PSH }, /* UNIX ls command */
+#else
+ { "ls", XXDIR, CM_INV }, /* Invisible synonym for DIR */
+#endif /* UNIXOROSK */
+#ifndef NOXFER
+ { "mail", XXMAI, 0 }, /* Send a file as e-mail */
+#endif /* NOXFER */
+#ifndef NOHELP
+ { "manual", XXMAN, CM_PSH }, /* MAN(UAL) */
+#else
+ { "manual", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOHELP */
+#endif /* NOFRILLS */
+#ifdef CK_MKDIR
+ { "md", XXMKDIR, CM_INV }, /* Synonym for MKDIR */
+#endif /* CK_MKDIR */
+ { "message", XXMSG, 0 }, /* Print debugging message */
+#ifdef CK_MINPUT
+ { "minput", XXMINP, 0 }, /* MINPUT */
+#else
+ { "minput", XXNOTAV, CM_INV },
+#endif /* CK_MINPUT */
+#ifndef NOMSEND
+ { "mget", XXMGET, 0 }, /* MGET */
+#else
+ { "mget", XXNOTAV, CM_INV },
+#endif /* NOMSEND */
+#ifdef CK_MKDIR
+ { "mkdir", XXMKDIR, 0 }, /* MKDIR */
+#else
+ { "mkdir", XXNOTAV, CM_INV },
+#endif /* CK_MKDIR */
+
+#ifndef NOXFER
+#ifndef NOMSEND
+ { "mmove", XXMMOVE, 0 }, /* MMOVE */
+#else
+ { "mmove", XXNOTAV, CM_INV },
+#endif /* NOMSEND */
+#endif /* NOXFER */
+
+#ifndef NOFRILLS
+ { "more", XXMORE, CM_INV }, /* MORE */
+#endif /* NOFRILLS */
+
+#ifndef NOXFER
+ { "move", XXMOVE, 0 }, /* MOVE */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ { "mpause", XXMSL, CM_INV }, /* Millisecond sleep */
+#else
+ { "mpause", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOXFER
+#ifndef NOMSEND
+ { "mput", XXMSE, CM_INV }, /* MPUT = MSEND */
+ { "ms", XXMSE, CM_INV|CM_ABR },
+ { "msend", XXMSE, 0 }, /* Multiple SEND */
+#else
+ { "mput", XXNOTAV, CM_INV },
+ { "msend", XXNOTAV, CM_INV },
+#endif /* NOMSEND */
+#endif /* NOXFER */
+ { "msg", XXMSG, CM_INV }, /* Print debugging message */
+#ifndef NOSPL
+ { "msleep", XXMSL, 0 }, /* Millisecond sleep */
+#else
+ { "msleep", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+#ifndef NOFRILLS
+ { "mv", XXREN, CM_INV }, /* Synonym for rename */
+#endif /* NOFRILLS */
+#ifndef NOHELP
+ { "news", XXNEW, CM_INV }, /* Display NEWS of new features */
+#else
+ { "news", XXNOTAV, CM_INV },
+#endif /* NOHELP */
+ { "nolocal", XXNLCL, CM_INV }, /* Disable SET LINE / SET HOST */
+ { "nopush", XXNPSH, CM_INV }, /* Disable PUSH command/features */
+#ifdef OS2
+ { "noscroll", XXNSCR, CM_INV }, /* Disable scroll operations */
+#endif /* OS2 */
+#ifndef NOSPL
+ { "o", XXOUT, CM_INV|CM_ABR }, /* Invisible synonym for OUTPUT */
+ { "open", XXOPE, 0 }, /* OPEN file for reading or writing */
+#else
+ { "open", XXOPE, CM_INV }, /* OPEN */
+#endif /* NOSPL */
+#ifndef NOHELP
+ { "options", XXOPTS,CM_INV|CM_HLP }, /* Options */
+#endif /* NOHELP */
+ { "orientation", XXORIE, 0 },
+#ifndef NOSPL
+ { "output", XXOUT, 0 }, /* OUTPUT text to comm device */
+#else
+ { "output", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+#ifdef ANYX25
+#ifndef IBMX25
+ { "pad", XXPAD, CM_LOC }, /* X.3 PAD commands */
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifdef NEWFTP
+ { "passive", XXPASV, CM_INV }, /* (FTP) PASSIVE */
+#endif /* NEWFTP */
+
+#ifndef NOHELP
+ { "patterns", XXPAT,CM_INV|CM_HLP }, /* Pattern syntax */
+#endif /* NOHELP */
+
+#ifndef NOSPL
+ { "pause", XXPAU, 0 }, /* Sleep for specified interval */
+#else
+ { "pause", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+#ifndef NODIAL
+ { "pdial", XXPDIA, CM_LOC }, /* PDIAL (partial dial) */
+#else
+ { "pdial", XXNOTAV, CM_INV|CM_LOC },
+#endif /* NODIAL */
+#ifdef TCPSOCKET
+#ifndef NOPUSH
+ { "ping", XXPNG, CM_INV|CM_PSH|CM_LOC }, /* PING */
+#else
+ { "ping", XXNOTAV, CM_INV|CM_PSH|CM_LOC },
+#endif /* NOPUSH */
+#endif /* TCPSOCKET */
+#ifdef NETCMD
+#ifndef NOPUSH
+ { "pipe", XXPIPE, CM_PSH }, /* PIPE */
+#else
+ { "pipe", XXNOTAV, CM_INV|CM_PSH }, /* PIPE */
+#endif /* NOPUSH */
+#endif /* NETCMD */
+
+#ifndef NOSPL
+ { "pop", XXEND, CM_INV }, /* Invisible synonym for END */
+#endif /* NOSPL */
+#ifndef NOFRILLS
+ { "print", XXPRI, 0 }, /* PRINT a file locally */
+#endif /* NOFRILLS */
+
+ { "prompt", XXPROMP, CM_INV }, /* Go interactive (from script) */
+
+#ifndef NOXFER
+#ifdef CK_RESEND
+ { "psend", XXPSEN, CM_INV }, /* PSEND */
+#else
+ { "psend", XXNOTAV, CM_INV },
+#endif /* CK_RESEND */
+#endif /* NOXFER */
+
+#ifdef NETPTY
+ { "pty", XXPTY, CM_PSH }, /* PTY */
+#else
+ { "pty", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NETPTY */
+
+#ifndef NOPUSH
+ { "pu", XXSHE, CM_INV|CM_ABR|CM_PSH }, /* PU = PUSH */
+#endif /* NOPUSH */
+
+#ifdef CKPURGE
+ { "purge", XXPURGE, 0 }, /* PURGE (real) */
+#else
+#ifdef VMS
+ { "purge", XXPURGE, 0 }, /* PURGE (fake) */
+#else
+ { "purge", XXNOTAV, CM_INV },
+#endif /* VMS */
+#endif /* CKPURGE */
+
+#ifndef NOPUSH
+ { "push", XXSHE, CM_PSH }, /* PUSH command (like RUN, !) */
+#else
+ { "push", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOPUSH */
+
+#ifndef NOXFER
+ { "put", XXSEN, CM_INV }, /* PUT = SEND */
+#endif /* NOXFER */
+
+#ifdef UNIX
+#ifndef NOPUTENV
+ { "putenv", XXPUTE, CM_INV }, /* PUTENV */
+#endif /* NOPUTENV */
+#endif /* UNIX */
+
+ { "pwd", XXPWD, 0 }, /* Print Working Directory */
+ { "q", XXQUI, CM_INV|CM_ABR }, /* Invisible synonym for QUIT */
+
+#ifndef NOXFER
+ { "query", XXRQUE,CM_INV }, /* (= REMOTE QUERY) */
+#endif /* NOXFER */
+
+ { "quit", XXQUI, 0 }, /* QUIT from program = EXIT */
+
+#ifndef NOXFER
+ { "r", XXREC, CM_INV|CM_ABR }, /* Inv synonym for RECEIVE */
+#endif /* NOXFER */
+
+#ifndef NOXFER
+ { "rasg", XXRASG, CM_INV }, /* REMOTE ASSIGN */
+ { "rassign", XXRASG, CM_INV }, /* ditto */
+ { "rcd", XXRCWD, CM_INV }, /* REMOTE CD */
+ { "rcdup", XXRCDUP,CM_INV }, /* REMOTE CD */
+ { "rcopy", XXRCPY, CM_INV }, /* REMOTE COPY */
+ { "rcwd", XXRCWD, CM_INV }, /* REMOTE CWD */
+ { "rdelete", XXRDEL, CM_INV }, /* REMOTE DELETE */
+ { "rdirectory", XXRDIR, CM_INV }, /* REMODE DIRECTORY */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ { "read", XXREA, 0 }, /* READ a line from a file */
+#else
+ { "read", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ { "receive", XXREC, 0 }, /* RECEIVE files */
+#endif /* NOXFER */
+
+#ifndef NODIAL
+ { "red", XXRED, CM_INV|CM_ABR|CM_LOC }, /* Inv syn for REDIAL */
+ { "redi", XXRED, CM_INV|CM_ABR|CM_LOC }, /* ditto */
+ { "redial", XXRED, CM_LOC }, /* REDIAL last DIAL number */
+#else
+ { "red", XXNOTAV, CM_INV|CM_LOC },
+ { "redi", XXNOTAV, CM_INV|CM_LOC },
+ { "redial", XXNOTAV, CM_INV|CM_LOC },
+#endif /* NODIAL */
+
+#ifdef CK_REDIR
+#ifdef OS2
+#ifndef NOPUSH
+ { "redirect", XXFUN, CM_INV|CM_PSH }, /* REDIRECT */
+#else
+ { "redirect", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOPUSH */
+#else /* OS2 */
+#ifndef NOPUSH
+ { "redirect", XXFUN, CM_PSH }, /* REDIRECT */
+#else
+ { "redirect", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOPUSH */
+#endif /* OS2 */
+#endif /* CK_REDIR */
+
+#ifdef CK_RECALL
+ { "redo", XXREDO, CM_NOR }, /* REDO */
+#else
+ { "redo", XXNOTAV, CM_INV },
+#endif /* CK_RECALL */
+
+#ifndef NOXFER
+#ifdef CK_RESEND
+ { "reget", XXREGET, 0 }, /* REGET */
+#else
+ { "reget", XXNOTAV, CM_INV },
+#endif /* CK_RESEND */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ { "reinput", XXREI, CM_INV }, /* REINPUT (from INPUT buffer) */
+#else
+ { "reinput", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOXFER
+#ifdef ADDCMD
+ { "rem", XXREM, CM_INV|CM_ABR },
+ { "remo", XXREM, CM_INV|CM_ABR },
+#endif /* ADDCMD */
+ { "remote", XXREM, 0 }, /* Send REMOTE command to server */
+#endif /* NOXFER */
+
+#ifdef ADDCMD
+ { "remove", XXREMV,0 }, /* REMOVE (something from a list) */
+#else
+ { "remove", XXNOTAV, CM_INV },
+#endif /* ADDCMD */
+
+#ifndef NOFRILLS
+#ifndef NORENAME
+ { "rename", XXREN, 0 }, /* RENAME a local file */
+#else
+ { "rename", XXNOTAV, CM_INV },
+#endif /* NORENAME */
+ { "replay", XXTYP, CM_INV }, /* REPLAY (for now, just type) */
+#endif /* NOFRILLS */
+
+#ifndef NOXFER
+#ifdef CK_RESEND
+ { "rep", XXTYP, CM_INV|CM_ABR }, /* REPLAY abbreviation */
+ { "reput", XXRSEN, CM_INV }, /* REPUT = RESEND */
+ { "res", XXRSEN, CM_INV|CM_ABR }, /* RESEND */
+ { "rese", XXRSEN, CM_INV|CM_ABR }, /* RESEND */
+ { "resend", XXRSEN, 0 }, /* RESEND */
+#else
+ { "reput", XXNOTAV, CM_INV },
+ { "res", XXNOTAV, CM_INV },
+ { "rese", XXNOTAV, CM_INV },
+ { "resend", XXNOTAV, CM_INV },
+#endif /* CK_RESEND */
+#endif /* NOXFER */
+
+ { "reset", XXRESET, CM_INV }, /* RESET */
+
+#ifdef CK_RESEND
+#ifndef NOSPL
+ { "ret", XXRET, CM_INV|CM_ABR },
+#endif /* NOSPL */
+#endif /* CK_RESEND */
+
+#ifndef NOXFER
+ { "retrieve", XXRETR, CM_INV }, /* RETRIEVE */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ { "return", XXRET, 0 }, /* RETURN from a function */
+#else
+ { "return", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ { "rexit", XXRXIT, CM_INV }, /* REMOTE EXIT */
+#endif /* NOXFER */
+
+#ifdef CK_REXX
+#ifndef NOPUSH
+ { "rexx", XXREXX, CM_PSH }, /* Execute a Rexx command */
+#else
+ { "rexx", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOPUSH */
+#endif /* CK_REXX */
+
+#ifndef NOXFER
+ { "rhelp", XXRHLP, CM_INV }, /* REMOTE HELP */
+ { "rhost", XXRHOS, CM_INV }, /* REMOTE HOST */
+ { "rkermit", XXRKER, CM_INV }, /* REMOTE KERMIT */
+#endif /* NOXFER */
+
+#ifdef TCPSOCKET
+ { "rlogin", XXRLOG, CM_LOC }, /* Make an Rlogin connection */
+#else
+ { "rlogin", XXNOTAV, CM_INV|CM_LOC },
+#endif /* TCPSOCKET */
+
+#ifndef NOFRILLS
+ { "rm", XXDEL, CM_INV }, /* Invisible synonym for delete */
+#endif /* NOFRILLS */
+
+#ifdef CK_MKDIR
+ { "rmdir", XXRMDIR, 0 }, /* RMDIR */
+#else
+ { "rmdir", XXNOTAV, CM_INV },
+#endif /* CK_MKDIR */
+
+#ifndef NOXFER
+ { "rmessage", XXRMSG, CM_INV }, /* REMOTE MESSAGE */
+ { "rmkdir", XXRMKD, CM_INV }, /* REMOTE MKDIR */
+ { "rmsg", XXRMSG, CM_INV }, /* REMOTE MESSAGE */
+#ifndef NOSPL
+ { "robust", XXROB, CM_INV },
+#else
+ { "robust", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+ { "rprint", XXRPRI, CM_INV }, /* REMOTE PRINT */
+ { "rpwd", XXRPWD, CM_INV }, /* REMOTE PWD */
+ { "rquery", XXRQUE, CM_INV }, /* REMOTE QUERY */
+#endif /* NOXFER */
+
+#ifdef CK_RECALL
+ { "rr", XXREDO, CM_INV|CM_NOR },
+#endif /* CK_RECALL */
+
+#ifndef NOXFER
+ { "rrename", XXRREN, CM_INV }, /* REMOTE RENAME */
+ { "rrmdir", XXRRMD, CM_INV }, /* REMOTE REMDIR */
+ { "rset", XXRSET, CM_INV }, /* REMOTE SET */
+ { "rspace", XXRSPA, CM_INV }, /* REMOTE SPACE */
+ { "rtype", XXRTYP, CM_INV }, /* REMOTE TYPE */
+#endif /* NOXFER */
+
+#ifndef NOPUSH
+ { "run", XXSHE, CM_PSH }, /* RUN a program or command */
+#else
+ { "run", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOPUSH */
+
+#ifndef NOXFER
+ { "rwho", XXRWHO, CM_INV }, /* REMOTE WHO */
+ { "s", XXSEN, CM_INV|CM_ABR }, /* Invisible synonym for send */
+#endif /* NOXFER */
+
+#ifndef NOSETKEY
+#ifdef OS2
+ { "save", XXSAVE, 0 }, /* SAVE something */
+#else
+ { "save", XXSAVE, CM_INV },
+#endif /* OS2 */
+#else
+ { "save", XXNOTAV, CM_INV },
+#endif /* NOSETKEY */
+
+#ifndef NOSCRIPT
+ { "sc", XXLOGI, CM_INV|CM_ABR|CM_LOC },
+ { "scr", XXLOGI, CM_INV|CM_ABR|CM_LOC },
+#endif /* NOSCRIPT */
+ { "screen", XXSCRN, 0 }, /* SCREEN actions */
+#ifndef NOSCRIPT
+ { "script", XXLOGI, CM_LOC }, /* Expect-Send-style script line */
+#else
+ { "script", XXNOTAV, CM_INV|CM_LOC },
+#endif /* NOSCRIPT */
+
+ { "search", XXGREP,CM_INV }, /* Synonym for GREP and FIND */
+
+#ifndef NOXFER
+ { "send", XXSEN, 0 }, /* Send (a) file(s) */
+#ifndef NOSERVER
+ { "server", XXSER, 0 }, /* Be a SERVER */
+#else
+ { "server", XXNOTAV, CM_INV },
+#endif /* NOSERVER */
+#endif /* NOXFER */
+
+ { "set", XXSET, 0 }, /* SET parameters */
+
+#ifndef NOSPL
+#ifndef NOSEXP
+ { "sexpression", XXSEXP, CM_INV|CM_HLP }, /* SEXPR */
+#endif /* NOSEXP */
+
+#ifdef SFTP_BUILTIN
+ { "sftp", XXSFTP, 0 }, /* SFTP */
+#endif /* SFTP_BUILTIN */
+
+#ifndef NOSHOW
+ { "sh", XXSHO, CM_INV|CM_ABR }, /* SHOW parameters */
+#endif /* NOSHOW */
+ { "shift", XXSHIFT, 0 }, /* SHIFT args */
+#else
+ { "shift", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOSHOW
+ { "show", XXSHO, 0 }, /* SHOW parameters */
+#else
+ { "show", XXNOTAV, CM_INV },
+#endif /* NOSHOW */
+
+#ifdef NEWFTP
+ { "site", XXSITE, CM_INV }, /* (FTP) SITE */
+#endif /* NEWFTP */
+
+#ifdef SSHBUILTIN
+ { "skermit", XXSKRM, 0 }, /* SKERMIT */
+#endif /* SSHBUILTIN */
+
+#ifndef NOSPL
+#ifndef NOFRILLS
+ { "sleep", XXPAU, CM_INV }, /* SLEEP for specified interval */
+#endif /* NOFRILLS */
+#endif /* NOSPL */
+
+#ifndef NOSPL
+ { "sort", XXSORT, CM_INV }, /* (see ARRAY) */
+#else
+ { "sort", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef MAC
+#ifndef NOFRILLS
+ { "sp", XXSPA, CM_INV|CM_ABR },
+ { "spa", XXSPA, CM_INV|CM_ABR },
+#endif /* NOFRILLS */
+ { "space", XXSPA, 0 }, /* Show available disk SPACE */
+#endif /* MAC */
+
+#ifndef NOFRILLS
+#ifndef NOPUSH
+ { "spawn", XXSHE, CM_INV|CM_PSH }, /* Synonym for PUSH, RUN */
+#else
+ { "spawn", XXNOTAV, CM_INV|CM_PSH }, /* Synonym for PUSH, RUN */
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+#ifdef ANYSSH
+ { "ssh", XXSSH, 0 },
+#endif /* ANYSSH */
+
+#ifndef NOXFER
+ { "sta", XXSTA, CM_INV|CM_ABR },
+ { "stat", XXSTA, CM_INV|CM_ABR },
+ { "statistics", XXSTA, 0 }, /* Display file transfer stats */
+#endif /* NOXFER */
+
+ { "status", XXSTATUS,0 }, /* Show status of previous command */
+
+#ifndef NOSPL
+ { "stop", XXSTO, 0 }, /* STOP all take files and macros */
+ { "succeed", XXSUCC, CM_INV }, /* SUCCEED */
+#else
+ { "stop", XXNOTAV, CM_INV },
+ { "succeed", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+ { "SUPPORT", XXBUG, 0 }, /* Tech support instructions */
+#else
+ { "support", XXNOTAV, CM_INV },
+#endif /* NOFRILLS */
+
+#ifndef NOJC
+ { "suspend", XXSUS, CM_PSH }, /* SUSPEND C-Kermit (UNIX only) */
+#else
+ { "suspend", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOJC */
+
+#ifndef NOSPL
+ { "switch", XXSWIT, 0 }, /* SWITCH */
+#else
+ { "switch", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifdef CK_TAPI
+ { "ta", XXTAK, CM_INV|CM_ABR }, /* (because of TAPI) */
+#endif /* CK_TAPI */
+
+#ifndef NOFRILLS
+ { "tail", XXTAIL, 0 }, /* Display end of a local file */
+#endif /* NOFRILLS */
+
+ { "take", XXTAK, 0 }, /* TAKE commands from a file */
+
+#ifdef CK_TAPI
+ { "tapi", XXTAPI, CM_LOC }, /* Microsoft TAPI commands */
+#else
+ { "tapi", XXNOTAV, CM_INV|CM_LOC },
+#endif /* CK_TAPI */
+
+#ifndef NOFRILLS
+#ifdef TCPSOCKET
+ { "tel", XXTEL, CM_INV|CM_ABR|CM_LOC },
+ { "telnet", XXTEL, CM_LOC }, /* TELNET (TCP/IP only) */
+ { "telopt", XXTELOP, CM_INV }, /* TELOPT (ditto) */
+#else
+ { "tel", XXNOTAV, CM_INV|CM_LOC },
+ { "telnet", XXNOTAV, CM_INV|CM_LOC },
+ { "telopt", XXNOTAV, CM_INV },
+#endif /* TCPSOCKET */
+#ifdef OS2
+ { "terminal", XXTERM, CM_INV|CM_LOC }, /* == SET TERMINAL TYPE */
+#else
+ { "terminal", XXTERM, CM_INV },
+#endif /* OS2 */
+#endif /* NOFRILLS */
+#ifndef NOXFER
+ { "text", XXASC, CM_INV }, /* == SET FILE TYPE TEXT */
+#endif /* NOXFER */
+ { "touch", XXTOUC, 0 }, /* TOUCH */
+#ifndef NOSPL
+ { "trace", XXTRACE, 0 }, /* TRACE */
+#else
+ { "trace", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOCSETS
+ { "translate", XXXLA, 0 }, /* TRANSLATE local file char sets */
+#else
+ { "translate", XXNOTAV, CM_INV },
+#endif /* NOCSETS */
+
+#ifndef NOXMIT
+ { "transmit", XXTRA, 0 }, /* Send (upload) a file, no protocol */
+#else
+ { "transmit", XXNOTAV, CM_INV },
+#endif /* NOXMIT */
+
+#ifndef NOFRILLS
+ { "type", XXTYP, 0 }, /* Display a local file */
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+ { "undcl", XXUNDCL, CM_INV },
+ { "undeclare", XXUNDCL, 0 }, /* UNDECLARE an array */
+ { "undefine", XXUNDEF, 0 }, /* UNDEFINE a variable or macro */
+#else
+ { "undcl", XXNOTAV, CM_INV },
+ { "undeclare", XXNOTAV, CM_INV },
+ { "undefine", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifdef NEWFTP
+ { "user", XXUSER, CM_INV }, /* (FTP) USER */
+#endif /* NEWFTP */
+
+ { "version", XXVER, 0 }, /* VERSION-number display */
+
+#ifdef OS2
+ { "viewonly", XXVIEW, CM_LOC }, /* VIEWONLY Terminal Mode */
+#endif /* OS2 */
+
+ { "void", XXVOID, 0 }, /* VOID */
+
+#ifndef NOSPL
+ { "wait", XXWAI, 0 }, /* WAIT */
+#else
+ { "wait", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+ { "wdirectory", XXWDIR, CM_INV }, /* Like TOPS-20, reverse chron order */
+ { "wermit", XXKERMI, CM_INV },
+
+#ifndef NOXFER
+ { "where", XXWHERE, 0 }, /* WHERE (did my file go?) */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ { "while", XXWHI, 0 }, /* WHILE loop */
+#else
+ { "while", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef OS2
+#ifndef MAC
+#ifndef NOFRILLS
+ { "who", XXWHO, CM_PSH }, /* WHO's logged in? */
+#endif /* NOFRILLS */
+#endif /* MAC */
+#endif /* OS2 */
+
+#ifndef NOHELP
+ { "wildcards", XXWILD,CM_INV|CM_HLP }, /* Wildcard syntax */
+#endif /* NOHELP */
+
+#ifndef NOSPL
+ { "wr", XXWRI, CM_INV|CM_ABR },
+ { "wri", XXWRI, CM_INV|CM_ABR },
+ { "writ", XXWRI, CM_INV|CM_ABR },
+ { "write", XXWRI, 0 }, /* WRITE characters to a file */
+ { "write-line", XXWRL, CM_INV }, /* WRITE a line to a file */
+ { "writeln", XXWRL, CM_INV }, /* Pascalisch synonym for write-line */
+#else
+ { "wr", XXNOTAV, CM_INV },
+ { "wri", XXNOTAV, CM_INV },
+ { "writ", XXNOTAV, CM_INV },
+ { "write", XXNOTAV, CM_INV },
+ { "write-line", XXNOTAV, CM_INV },
+ { "writeln", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+ { "xecho", XXXECH,0 }, /* XECHO */
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+ { "xif", XXIFX, CM_INV }, /* Extended IF command (obsolete) */
+#else
+ { "xif", XXNOTAV, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOCSETS
+ { "xlate", XXXLA, CM_INV }, /* Synonym for TRANSLATE */
+#else
+ { "xlate", XXNOTAV, CM_INV },
+#endif /* NOCSETS */
+
+#ifndef NOXMIT
+ { "xm", XXTRA, CM_INV|CM_ABR }, /* Avoid conflict with XMESSAGE */
+#else
+ { "xm", XXNOTAV, CM_INV|CM_ABR }, /* Synonym for TRANSMIT */
+#endif /* NOXMIT */
+
+ { "xmessage", XXXMSG, 0 }, /* Print debugging message */
+
+#ifndef NOXMIT
+ { "xmit", XXTRA, CM_INV }, /* Synonym for TRANSMIT */
+#else
+ { "xmit", XXNOTAV, CM_INV },
+#endif /* NOXMIT */
+
+#ifndef OS2
+#ifndef NOJC
+ { "z", XXSUS, CM_INV|CM_PSH }, /* Synonym for SUSPEND */
+#else
+ { "z", XXNOTAV, CM_INV|CM_PSH },
+#endif /* NOJC */
+#endif /* OS2 */
+
+#ifndef NOSPL
+ { "{", XXMACRO, CM_INV }, /* Immediate macro */
+#endif /* NOSPL */
+ { "", 0, 0 }
+};
+int ncmd = (sizeof(cmdtab) / sizeof(struct keytab)) - 1;
+
+/* NOTE: Tokens must also be entered above into cmdtab[]. */
+
+char toktab[] = {
+#ifndef NOPUSH
+ '!', /* Shell escape */
+#endif /* NOPUSH */
+ '#', /* Comment */
+#ifndef NOSPL
+ '(', /* S-Expression */
+ '.', /* Assignment */
+#endif /* NOSPL */
+ ';', /* Comment */
+#ifndef NOSPL
+ ':', /* Label */
+#endif /* NOSPL */
+#ifndef NOPUSH
+#ifdef CK_REDIR
+ '<', /* REDIRECT */
+#endif /* CK_REDIR */
+ '@', /* DCL escape */
+#endif /* NOPUSH */
+#ifdef CK_RECALL
+ '^', /* Command recall */
+#endif /* CK_RECALL */
+#ifndef NOSPL
+ '{', /* Immediate macro */
+#endif /* NOSPL */
+ '\0' /* End of this string */
+};
+int xxdot = 0; /* Used with "." token */
+
+struct keytab yesno[] = { /* Yes/No keyword table */
+ { "no", 0, 0 },
+ { "ok", 1, 0 },
+ { "yes", 1, 0 }
+};
+int nyesno = (sizeof(yesno) / sizeof(struct keytab));
+
+/* Save keyword table */
+
+struct keytab savtab[] = {
+#ifdef OS2
+ { "command", XSCMD, 0 },
+#else
+#ifdef CK_RECALL
+ { "command", XSCMD, 0 },
+#endif /* CK_RECALL */
+#endif /* OS2 */
+#ifndef NOSETKEY
+ { "keymap", XSKEY, 0 },
+#endif /* NOSETKEY */
+#ifdef OS2
+ { "terminal", XSTERM, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int nsav = (sizeof(savtab) / sizeof(struct keytab)) - 1;
+
+/* Parameter keyword table */
+
+struct keytab prmtab[] = {
+ { "alarm", XYALRM, 0 },
+#ifdef COMMENT /* SET ANSWER not implemented yet */
+#ifndef NODIAL
+ { "answer", XYANSWER,0 },
+#endif /* NODIAL */
+#endif /* COMMENT */
+ { "ask-timer", XYTIMER, 0 },
+#ifndef NOXFER
+ { "attributes", XYATTR, 0 },
+#endif /* NOXFER */
+#ifdef CK_AUTHENTICATION
+ { "authentication", XYAUTH, 0 },
+#else /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+ { "authentication", XYAUTH, 0 },
+#endif /* CK_SSL */
+#endif /* CK_AUTHENTICATION */
+ { "b", XYBACK, CM_INV|CM_ABR|CM_PSH },
+ { "ba", XYBACK, CM_INV|CM_ABR|CM_PSH },
+#ifdef VMS
+ { "background", XYBACK, CM_INV|CM_PSH },
+ { "batch", XYBACK, CM_PSH },
+#else
+ { "background", XYBACK, CM_PSH },
+ { "batch", XYBACK, CM_INV|CM_PSH },
+#endif /* VMS */
+#ifndef NOLOCAL
+ { "baud", XYSPEE, CM_INV|CM_LOC },
+#endif /* NOLOCAL */
+ { "bell", XYBELL, 0 },
+#ifndef NOXFER
+ { "block-check", XYCHKT, 0 },
+#endif /* NOXFER */
+#ifdef OS2
+#ifdef BPRINT
+ { "bprinter", XYBDCP, CM_INV },
+#endif /* BPRINT */
+#endif /* OS2 */
+#ifdef BROWSER
+ { "browser", XYBROWSE,CM_PSH|CM_LOC },
+#endif /* BROWSER */
+#ifndef NOXFER
+#ifdef DYNAMIC
+ { "buffers", XYBUF, 0 },
+#endif /* DYNAMIC */
+#endif /* NOXFER */
+#ifndef NOLOCAL
+#ifndef MAC
+ { "carrier-watch", XYCARR, CM_LOC },
+#endif /* MAC */
+#endif /* NOLOCAL */
+#ifndef NOSPL
+ { "case", XYCASE, 0 },
+#endif /* NOSPL */
+ { "cd", XYCD, 0 },
+#ifndef NOXFER
+ { "cl", XYCLEAR, CM_INV|CM_ABR },
+ { "cle", XYCLEAR, CM_INV|CM_ABR },
+ { "clea", XYCLEAR, CM_INV|CM_ABR },
+ { "clear", XYCLEAR, CM_INV|CM_ABR },
+ { "clear-channel", XYCLEAR, 0 },
+ { "clearchannel", XYCLEAR, CM_INV },
+#endif /* NOXFER */
+#ifndef NOLOCAL
+ { "close-on-disconnect", XYDISC, CM_INV|CM_LOC },
+#endif /* NOLOCAL */
+ { "cmd", XYCMD, CM_INV },
+ { "command", XYCMD, 0 },
+#ifdef CK_SPEED
+ { "con", XYQCTL, CM_INV|CM_ABR },
+#endif /* CK_SPEED */
+ { "console", XYCMD, CM_INV },
+#ifdef CK_SPEED
+ { "control-character",XYQCTL, 0 },
+#endif /* CK_SPEED */
+#ifndef NOSPL
+ { "count", XYCOUN, 0 },
+#endif /* NOSPL */
+#ifndef NOXFER
+ { "d", XYDELA, CM_INV|CM_ABR },
+ { "de", XYDELA, CM_INV|CM_ABR },
+#endif /* NOXFER */
+ { "debug", XYDEBU, 0 },
+#ifdef VMS
+ { "default", XYDFLT, 0 },
+#else
+#ifndef MAC
+ { "default", XYDFLT, CM_INV },
+#endif /* MAC */
+#endif /* VMS */
+#ifndef NOXFER
+ { "delay", XYDELA, 0 },
+ { "destination", XYDEST, 0 },
+#endif /* NOXFER */
+#ifndef NODIAL
+ { "di", XYDIAL, CM_INV|CM_ABR|CM_LOC },
+ { "dia", XYDIAL, CM_INV|CM_ABR|CM_LOC },
+ { "dial", XYDIAL, CM_LOC },
+#endif /* NODIAL */
+#ifdef OS2
+ { "dialer", XYDLR, CM_INV },
+#endif /* OS2 */
+#ifndef NOLOCAL
+ { "disconnect", XYDISC, CM_LOC },
+ { "duplex", XYDUPL, CM_LOC },
+#endif /* NOLOCAL */
+#ifndef NOPUSH
+#ifndef NOFRILLS
+ { "editor", XYEDIT, CM_PSH },
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+#ifdef CK_CTRLZ
+ { "eof", XYEOF, CM_INV },
+#endif /* CK_CTRLZ */
+#ifndef NOLOCAL
+ { "escape-character", XYESC, CM_LOC },
+#endif /* NOLOCAL */
+#ifndef NOSPL
+ { "evaluate", XYEVAL, CM_INV },
+#endif /* NOSPL */
+ { "exit", XYEXIT, 0 },
+#ifndef NOXFER
+#ifdef CK_XYZ
+#ifndef NOPUSH
+#ifndef XYZ_INTERNAL
+ { "external-protocol",XYEXTRN, 0 },
+#endif /* XYZ_INTERNAL */
+#endif /* NOPUSH */
+#endif /* CK_XYZ */
+ { "f-ack-bug", XYFACKB, CM_INV },
+ { "f-ack-path", XYFACKP, CM_INV },
+#endif /* NOXFER */
+ { "file", XYFILE, 0 },
+ { "fl", XYFLOW, CM_INV|CM_ABR },
+#ifndef NOSPL
+ { "flag", XYFLAG, 0 },
+#endif /* NOSPL */
+#ifdef TCPSOCKET
+#ifndef SYSFTP
+#ifndef NOFTP
+ { "ft", XYFTPX, CM_INV|CM_ABR },
+ { "ftp", XYFTPX, 0 },
+#endif /* NOFTP */
+#endif /* SYSFTP */
+#endif /* TCPSOCKET */
+#ifdef BROWSER
+ { "ftp-client", XYFTP, CM_PSH },
+#endif /* BROWSER */
+ { "flow-control", XYFLOW, 0 },
+#ifndef NOSPL
+ { "function", XYFUNC, 0 },
+#endif /* NOSPL */
+#ifdef NEWFTP
+ { "get-put-remote", XYGPR, 0 },
+#endif /* NEWFTP */
+#ifdef KUI
+ { "gui", XYGUI, 0 },
+#endif /* KUI */
+ { "handshake", XYHAND, 0 },
+ { "hints", XYHINTS, 0 },
+#ifdef NETCONN
+ { "host", XYHOST, CM_LOC },
+#endif /* NETCONN */
+#ifndef NOSPL
+ { "i", XYINPU, CM_INV|CM_ABR },
+#endif /* NOSPL */
+#ifdef IKSD
+ { "iks", XYIKS, 0 },
+#else
+ { "iks", XYIKS, CM_INV },
+#endif /* IKSD */
+#ifndef NOSPL
+ { "in", XYINPU, CM_INV|CM_ABR },
+#endif /* NOSPL */
+#ifndef NOXFER
+ { "incomplete", XYIFD, CM_INV },
+#endif /* NOXFER */
+#ifndef NOSPL
+ { "input", XYINPU, 0 },
+#endif /* NOSPL */
+#ifndef NOSETKEY
+ { "key", XYKEY, 0 },
+#endif /* NOSETKEY */
+ { "l", XYLINE, CM_INV|CM_ABR },
+#ifndef NOCSETS
+ { "language", XYLANG, 0 },
+#endif /* NOCSETS */
+#ifndef NOLOCAL
+ { "line", XYLINE, CM_LOC },
+ { "local-echo", XYLCLE, CM_INV|CM_LOC },
+#endif /* NOLOCAL */
+#ifdef LOCUS
+ { "locus", XYLOCUS, 0 },
+#endif /* LOCUS */
+#ifndef NOSPL
+ { "login", XYLOGIN, CM_LOC },
+#endif /* NOSPL */
+#ifndef NOSPL
+ { "macro", XYMACR, 0 },
+#endif /* NOSPL */
+ { "match", XYMATCH, 0 },
+#ifdef COMMENT
+#ifdef VMS
+ { "messages", XYMSGS, 0 },
+#endif /* VMS */
+#endif /* COMMENT */
+#ifndef NODIAL
+ { "modem", XYMODM, CM_LOC },
+#endif /* NODIAL */
+#ifndef NOLOCAL
+#ifdef OS2MOUSE
+ { "mouse", XYMOUSE, 0 },
+#endif /* OS2MOUSE */
+#endif /* NOLOCAL */
+#ifdef OS2
+ { "mskermit", XYMSK, 0 },
+#endif /* OS2 */
+#ifdef NETCONN
+ { "network", XYNET, CM_LOC },
+#endif /* NETCONN */
+#ifndef NOSPL
+ { "output", XYOUTP, 0 },
+#endif /* NOSPL */
+ { "options", XYOPTS, 0 },
+ { "pause", XYSLEEP, CM_INV },
+#ifdef ANYX25
+#ifndef IBMX25
+ { "pad", XYPAD, CM_LOC },
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+ { "parity", XYPARI, 0 },
+#ifndef NOLOCAL
+#ifdef OS2
+ { "port", XYLINE, CM_LOC },
+#else
+ { "port", XYLINE, CM_INV|CM_LOC },
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifndef NOFRILLS
+ { "pr", XYPROM, CM_INV|CM_ABR },
+ { "printer", XYPRTR, 0 },
+#endif /* NOFRILLS */
+#ifdef OS2
+ { "priority", XYPRTY, 0 },
+#endif /* OS2 */
+#ifdef CK_SPEED
+ { "prefixing", XYPREFIX, 0 },
+#endif /* CK_SPEED */
+#ifndef NOFRILLS
+ { "prompt", XYPROM, 0 },
+#endif /* NOFRILLS */
+#ifndef NOXFER
+ { "protocol", XYPROTO, 0 },
+#endif /* NOXFER */
+ { "q", XYQUIE, CM_INV|CM_ABR },
+#ifndef NOXFER
+ { "q8flag", XYQ8FLG, CM_INV },
+#endif /* NOXFER */
+#ifdef QNX
+ { "qnx-port-lock", XYQNXPL, 0 },
+#else
+ { "qnx-port-lock", XYQNXPL, CM_INV },
+#endif /* QNX */
+ { "quiet", XYQUIE, 0 },
+#ifndef NOXFER
+ { "rec", XYRECV, CM_INV|CM_ABR },
+ { "receive", XYRECV, 0 },
+ { "recv", XYRECV, CM_INV },
+#endif /* NOXFER */
+ { "reliable", XYRELY, 0 },
+ { "rename", XY_REN, 0 },
+#ifndef NOXFER
+ { "repeat", XYREPT, 0 },
+ { "retry-limit", XYRETR, 0 },
+#endif /* NOXFER */
+#ifdef CKROOT
+ { "root", XYROOT, 0 },
+#endif /* CKROOT */
+#ifndef NOSCRIPT
+ { "script", XYSCRI, CM_LOC },
+#endif /* NOSCRIPT */
+#ifndef NOXFER
+ { "send", XYSEND, 0 },
+#ifndef NOLOCAL
+#ifndef NOSERVER
+ { "ser", XYSERV, CM_INV|CM_ABR },
+#endif /* NOSERVER */
+#endif /* NOXFER */
+ { "serial", XYSERIAL,CM_LOC },
+#endif /* NOLOCAL */
+#ifndef NOSERVER
+ { "server", XYSERV, 0 },
+#endif /* NOSERVER */
+#ifdef SESLIMIT
+#ifndef NOLOCAL
+ { "session-l", XYSESS, CM_INV|CM_ABR },
+#endif /* NOLOCAL */
+ { "session-limit", XYLIMIT, CM_INV|CM_LOC }, /* Session Limit */
+#endif /* SESLIMIT */
+
+#ifndef NOLOCAL
+ { "session-log", XYSESS, CM_LOC },
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+#ifndef NOSEXP
+ { "sexpression", XYSEXP, CM_INV },
+#endif /* NOSEXP */
+#endif /* NOSPL */
+
+ { "sleep", XYSLEEP, 0 },
+
+#ifndef NOLOCAL
+ { "speed", XYSPEE, CM_LOC },
+#endif /* NOLOCAL */
+
+#ifdef ANYSSH
+ { "ssh", XYSSH, 0 },
+#endif /* ANYSSH */
+
+#ifndef NOSPL
+ { "startup-file", XYSTARTUP, CM_INV },
+#endif /* NOSPL */
+
+#ifndef NOLOCAL
+#ifdef HWPARITY
+ { "stop-bits", XYSTOP, CM_LOC },
+#else
+#ifdef TN_COMPORT
+ { "stop-bits", XYSTOP, CM_LOC },
+#endif /* TN_COMPORT */
+#endif /* HWPARITY */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+#ifdef STREAMING
+ { "streaming", XYSTREAM, 0 },
+#endif /* STREAMING */
+#endif /* NOXFER */
+
+#ifndef NOJC
+ { "suspend", XYSUSP, CM_PSH },
+#endif /* NOJC */
+#ifdef CKSYSLOG
+ { "syslog", XYSYSL, CM_INV },
+#endif /* CKSYSLOG */
+ { "take", XYTAKE, 0 },
+
+#ifdef CK_TAPI
+ { "tapi", XYTAPI, CM_LOC },
+#endif /* CK_TAPI */
+
+#ifndef NOTCPOPTS
+#ifdef TCPSOCKET
+ { "tcp", XYTCP, CM_LOC },
+#endif /* TCPSOCKET */
+#endif /* NOTCPOPTS */
+
+#ifdef TNCODE
+ { "tel", XYTEL, CM_INV|CM_ABR },
+ { "telnet", XYTEL, 0 },
+ { "telopt", XYTELOP, 0 },
+#endif /* TNCODE */
+
+#ifndef NOSPL
+ { "temp-directory", XYTMPDIR,0 },
+#endif /* NOSPL */
+
+#ifndef NOLOCAL
+ { "terminal", XYTERM, CM_LOC },
+#endif /* NOLOCAL */
+
+#ifdef OS2
+ { "title", XYTITLE, CM_LOC },
+#endif /* OS2 */
+#ifdef TLOG
+ { "transaction-log", XYTLOG, 0 },
+#endif /* TLOG */
+#ifndef NOXFER
+ { "transfer", XYXFER, 0 },
+#endif /* NOXFER */
+#ifndef NOXMIT
+ { "transmit", XYXMIT, 0 },
+#endif /* NOXMIT */
+#ifndef NOXFER
+#ifndef NOCSETS
+ { "unknown-char-set", XYUNCS, 0 },
+#endif /* NOCSETS */
+#ifndef NOSPL
+ { "variable-evaluation", XYVAREV, CM_INV },
+#endif /* NOSPL */
+#endif /* NOXFER */
+ { "wait", XYSLEEP, CM_INV },
+#ifndef NOPUSH
+#ifdef UNIX
+ { "wildcard-expansion", XYWILD, 0 },
+#endif /* UNIX */
+#endif /* NOPUSH */
+#ifdef NT
+ { "w", XYWIND, CM_INV|CM_ABR },
+ { "wi", XYWIND, CM_INV|CM_ABR },
+ { "win", XYWIND, CM_INV|CM_ABR },
+#endif /* NT */
+ { "window-size", XYWIND, 0 },
+#ifdef NT
+ { "win95", XYWIN95, 0 },
+#endif /* NT */
+#ifdef ANYX25
+ { "x.25", XYX25, CM_LOC },
+ { "x25", XYX25, CM_INV|CM_LOC },
+#endif /* ANYX25 */
+ { "xfer", XYXFER, CM_INV },
+#ifndef NOXMIT
+ { "xmit", XYXMIT, CM_INV },
+#endif /* NOXMIT */
+ { "", 0, 0 }
+};
+int nprm = (sizeof(prmtab) / sizeof(struct keytab)) - 1; /* How many */
+
+struct keytab scntab[] = { /* Screen commands */
+ { "clear", SCN_CLR, 0 },
+ { "cleol", SCN_CLE, 0 },
+ { "move-to", SCN_MOV, 0 }
+};
+int nscntab = (sizeof(scntab) / sizeof(struct keytab)); /* How many */
+
+#ifdef ANYSSH /* SSH command table */
+#ifdef SSHBUILTIN
+int ssh_pf_lcl_n = 0,
+ ssh_pf_rmt_n = 0;
+struct ssh_pf ssh_pf_lcl[32] = { 0, NULL, 0 }; /* SSH Port Forwarding */
+struct ssh_pf ssh_pf_rmt[32] = { 0, NULL, 0 }; /* structs... */
+extern char * ssh_hst, * ssh_cmd, * ssh_prt;
+extern int ssh_ver, ssh_xfw;
+char * ssh_tmpuid = NULL, *ssh_tmpcmd = NULL, *ssh_tmpport = NULL,
+ * ssh_tmpstr = NULL;
+
+int
+ sshk_type = SSHKT_2D, /* SSH KEY CREATE /TYPE:x */
+ sshk_bits = 1024, /* SSH KEY CREATE /BITS:n */
+ sshk_din = SKDF_OSSH, /* SSH KEY DISPLAY /IN-FORMAT: */
+ sshk_dout = SKDF_OSSH; /* SSH KEY DISPLAY /OUT-FORMAT: */
+
+char
+ * sshk1_comment = NULL, /* SSH V1 COMMENT */
+ * sshkp_old = NULL, /* Old key passphrase */
+ * sshkp_new = NULL, /* New key passphrase */
+ * sshkc_pass = NULL, /* KEY CREATE /PASS:xxx */
+ * sshkc_comm = NULL, /* KEY CREATE /V1-RSA-COMMENT:xxx */
+ * sshd_file = NULL, /* DISPLAY file */
+ * sshk_file = NULL; /* SSH CREATE KEY file */
+
+static struct keytab sshclr[] = {
+ { "local-port-forward", SSHC_LPF, 0 },
+ { "remote-port-forward", SSHC_RPF, 0 },
+ { "", 0, 0 }
+};
+static int nsshclr = (sizeof(sshclr) / sizeof(struct keytab)) - 1;
+
+struct keytab sshopnsw[] = {
+ { "/command", SSHSW_CMD, CM_ARG },
+ { "/password", SSHSW_PWD, CM_ARG },
+ { "/subsystem", SSHSW_SUB, CM_ARG },
+ { "/user", SSHSW_USR, CM_ARG },
+ { "/version", SSHSW_VER, CM_ARG },
+ { "/x11-forwarding", SSHSW_X11, CM_ARG },
+ { "", 0, 0 }
+};
+int nsshopnsw = (sizeof(sshopnsw) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshkwtab[] = {
+ { "add", XSSH_ADD, 0 },
+ { "agent", XSSH_AGT, 0 },
+ { "clear", XSSH_CLR, 0 },
+ { "forward-local-port", XSSH_FLP, CM_INV },
+ { "forward-remote-port", XSSH_FRP, CM_INV },
+ { "key", XSSH_KEY, 0 },
+ { "open", XSSH_OPN, 0 },
+ { "v2", XSSH_V2, 0 },
+ { "", 0, 0 }
+};
+static int nsshcmd = (sizeof(sshkwtab) / sizeof(struct keytab)) - 1;
+
+static struct keytab ssh2tab[] = {
+ { "rekey", XSSH2_RKE, 0 },
+ { "", 0, 0 }
+};
+static int nssh2tab = (sizeof(ssh2tab) / sizeof(struct keytab));
+
+static struct keytab addfwd[] = { /* SET SSH ADD command table */
+ { "local-port-forward", SSHF_LCL, 0 },
+ { "remote-port-forward", SSHF_RMT, 0 },
+ { "", 0, 0 }
+};
+static int naddfwd = (sizeof(addfwd) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshagent[] = { /* SET SSH AGENT command table */
+ { "add", SSHA_ADD, 0 },
+ { "delete", SSHA_DEL, 0 },
+ { "list", SSHA_LST, 0 },
+ { "", 0, 0 }
+};
+static int nsshagent = (sizeof(sshagent) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshagtsw[] = { /* SET SSH AGENT LIST switch table */
+ { "/fingerprint", SSHASW_FP, 0 },
+ { "", 0, 0 }
+};
+static int nsshagtsw = (sizeof(sshagtsw) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshkey[] = { /* SET SSH KEY command table */
+ { "change-passphrase", SSHK_PASS, 0 },
+ { "create", SSHK_CREA, 0 },
+ { "display", SSHK_DISP, 0 },
+ { "v1", SSHK_V1, 0 },
+ { "", 0, 0 }
+};
+static int nsshkey = (sizeof(sshkey) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshkv1[] = { /* SET SSH KEY V1 command table */
+ { "set-comment", 1, 0 }
+};
+
+static struct keytab sshkpsw[] = { /* SET SSH KEY PASSPHRASE table */
+ { "/new-passphrase", 2, CM_ARG },
+ { "/old-passphrase", 1, CM_ARG }
+};
+
+static struct keytab sshkcrea[] = { /* SSH KEY CREATE table */
+ { "/bits", SSHKC_BI, CM_ARG },
+ { "/passphrase", SSHKC_PP, CM_ARG },
+ { "/type", SSHKC_TY, CM_ARG },
+ { "/v1-rsa-comment", SSHKC_1R, CM_ARG }
+};
+static int nsshkcrea = (sizeof(sshkcrea) / sizeof(struct keytab));
+
+static struct keytab sshkcty[] = { /* SSH KEY CREATE /TYPE:xxx */
+ { "srp", SSHKT_SRP, 0 },
+ { "v1-rsa", SSHKT_1R, 0 },
+ { "v2-dsa", SSHKT_2D, 0 },
+ { "v2-rsa", SSHKT_2R, 0 }
+};
+static int nsshkcty = (sizeof(sshkcty) / sizeof(struct keytab));
+
+static struct keytab sshdswi[] = { /* SET SSH KEY DISPLAY /switches */
+ { "/format", SSHKD_OUT, CM_ARG }
+};
+static int nsshdswi = (sizeof(sshdswi) / sizeof(struct keytab));
+
+#ifdef COMMENT
+static struct keytab sshdifmt[] = { /* SSH KEY DISPLAY /IN-FORMAT: */
+ { "openssh", SKDF_OSSH, 0 },
+ { "ssh.com", SKDF_SSHC, 0 }
+};
+static int nsshdifmt = (sizeof(sshdifmt) / sizeof(struct keytab));
+#endif /* COMMENT */
+
+static struct keytab sshdofmt[] = { /* SSH KEY DISPLAY /IN-FORMAT: */
+ { "fingerprint", SKDF_FING, 0 },
+ { "ietf", SKDF_IETF, 0 },
+ { "openssh", SKDF_OSSH, 0 },
+ { "ssh.com", SKDF_SSHC, 0 }
+};
+static int nsshdofmt = (sizeof(sshdofmt) / sizeof(struct keytab));
+
+static struct keytab sshkermit[] = { /* SKERMIT */
+ { "open", SKRM_OPN, 0 }
+};
+static int nsshkermit = (sizeof(sshkermit) / sizeof(struct keytab));
+
+struct keytab sshkrmopnsw[] = {
+ { "/password", SSHSW_PWD, CM_ARG },
+ { "/user", SSHSW_USR, CM_ARG },
+ { "/version", SSHSW_VER, CM_ARG },
+ { "", 0, 0 }
+};
+int nsshkrmopnsw = (sizeof(sshkrmopnsw) / sizeof(struct keytab)) - 1;
+#endif /* SSHBUILTIN */
+
+#ifdef SFTP_BUILTIN
+static struct keytab sftpkwtab[] = { /* SFTP */
+ { "cd", SFTP_CD, 0 },
+ { "chgrp", SFTP_CHGRP, 0 },
+ { "chmod", SFTP_CHMOD, 0 },
+ { "chown", SFTP_CHOWN, 0 },
+ { "delete", SFTP_RM, 0 },
+ { "dir", SFTP_DIR, 0 },
+ { "get", SFTP_GET, 0 },
+ { "mkdir", SFTP_MKDIR, 0 },
+ { "open", SFTP_OPN, 0 },
+ { "put", SFTP_PUT, 0 },
+ { "pwd", SFTP_PWD, 0 },
+ { "rename", SFTP_REN, 0 },
+ { "rm", SFTP_RM, CM_INV },
+ { "rmdir", SFTP_RMDIR, 0 },
+ { "symlink", SFTP_LINK, 0 },
+ { "version", SFTP_VER, 0 }
+};
+static int nsftpkwtab = (sizeof(sftpkwtab) / sizeof(struct keytab));
+#endif /* SFTP_BUILTIN */
+#endif /* ANYSSH */
+
+#ifdef NETCONN
+struct keytab netkey[] = { /* SET NETWORK table */
+ { "directory", XYNET_D, 0 },
+ { "type", XYNET_T, 0 }
+};
+int nnetkey = (sizeof(netkey) / sizeof(struct keytab));
+
+struct keytab netcmd[] = {
+/*
+ These are the network types.
+*/
+#ifdef NETCMD
+ { "command", NET_CMD, CM_INV }, /* Command */
+#endif /* NETCMD */
+
+#ifdef DECNET /* DECnet / PATHWORKS */
+ { "decnet", NET_DEC, 0 },
+#endif /* DECNET */
+
+#ifdef NETDLL
+ { "dll", NET_DLL, CM_INV }, /* DLL to be loaded */
+#endif /* NETDLL */
+
+#ifdef NETFILE
+ { "file", NET_FILE, CM_INV }, /* FILE (real crude) */
+#endif /* NETFILE */
+
+#ifdef NPIPE /* Named Pipes */
+ { "named-pipe", NET_PIPE, 0 },
+#endif /* NPIPE */
+
+#ifdef CK_NETBIOS
+ { "netbios", NET_BIOS, 0 }, /* NETBIOS */
+#endif /* CK_NETBIOS */
+
+#ifdef DECNET /* DECnet / PATHWORKS (alias) */
+ { "pathworks", NET_DEC, CM_INV },
+#endif /* DECNET */
+
+#ifdef NETCMD
+ { "pipe", NET_CMD, 0 }, /* Pipe */
+#endif /* NETCMD */
+
+#ifdef NETPTY
+ { "pseudoterminal",NET_PTY, 0 }, /* Pseudoterminal */
+#endif /* NETPTY */
+
+#ifdef NETPTY
+ { "pty", NET_PTY, CM_INV }, /* Inv syn for pseudoterm */
+#endif /* NETPTY */
+
+#ifdef SSHBUILTIN
+ { "ssh", NET_SSH, 0 },
+#endif /* SSHBUILTIN */
+
+#ifdef SUPERLAT
+ { "superlat", NET_SLAT, 0 }, /* Meridian Technologies' SuperLAT */
+#endif /* SUPERLAT */
+
+#ifdef TCPSOCKET /* TCP/IP sockets library */
+ { "tcp/ip", NET_TCPB, 0 },
+#endif /* TCPSOCKET */
+#ifdef SUPERLAT
+ { "tes32", NET_SLAT, 0 }, /* Emulux TES32 */
+#endif /* SUPERLAT */
+#ifdef ANYX25 /* X.25 */
+#ifdef SUNX25
+ { "x", NET_SX25, CM_INV|CM_ABR },
+ { "x.25", NET_SX25, 0 },
+ { "x25", NET_SX25, CM_INV },
+#else
+#ifdef STRATUSX25
+ { "x", NET_VX25, CM_INV|CM_ABR },
+ { "x.25", NET_VX25, 0 },
+ { "x25", NET_VX25, CM_INV },
+#endif /* STRATUSX25 */
+#endif /* SUNX25 */
+#ifdef IBMX25
+ { "x", NET_IX25, CM_INV|CM_ABR },
+ { "x.25", NET_IX25, CM_INV },
+ { "x25", NET_IX25, CM_INV },
+#endif /* IBMX25 */
+#ifdef HPX25
+ { "x", NET_IX25, CM_INV|CM_ABR },
+ { "x.25", NET_IX25, 0 },
+ { "x25", NET_IX25, CM_INV },
+#endif /* HPX25 */
+#endif /* ANYX25 */
+ { "", 0, 0 }
+};
+int nnets = (sizeof(netcmd) / sizeof(struct keytab));
+
+#ifndef NOTCPOPTS
+#ifdef TCPSOCKET
+
+/* TCP options */
+
+struct keytab tcpopt[] = {
+ { "address", XYTCP_ADDRESS, 0 },
+#ifdef CK_DNS_SRV
+ { "dns-service-records", XYTCP_DNS_SRV, 0 },
+#endif /* CK_DNS_SRV */
+#ifdef SO_DONTROUTE
+ { "dontroute", XYTCP_DONTROUTE, 0 },
+#endif /* SO_DONTROUTE */
+#ifndef NOHTTP
+ { "http-proxy", XYTCP_HTTP_PROXY, 0 },
+#endif /* NOHTTP */
+#ifdef SO_KEEPALIVE
+ { "keepalive", XYTCP_KEEPALIVE, 0 },
+#endif /* SO_KEEPALIVE */
+#ifdef SO_LINGER
+ { "linger", XYTCP_LINGER, 0 },
+#endif /* SO_LINGER */
+#ifdef TCP_NODELAY
+ { "nagle", XYTCP_NAGLE, CM_INV },
+ { "nodelay", XYTCP_NODELAY, 0 },
+#endif /* TCP_NODELAY */
+ { "reverse-dns-lookup", XYTCP_RDNS, 0 },
+#ifdef SO_RCVBUF
+ { "recvbuf", XYTCP_RECVBUF, 0 },
+#endif /* SO_RCVBUF */
+#ifdef SO_SNDBUF
+ { "sendbuf", XYTCP_SENDBUF, 0 },
+#endif /* SO_SNDBUF */
+#ifdef NT
+#ifdef CK_SOCKS
+ { "socks-server", XYTCP_SOCKS_SVR, 0 },
+#endif /* CK_SOCKS */
+#endif /* NT */
+#ifdef VMS
+#ifdef DEC_TCPIP
+ { "ucx-port-bug", XYTCP_UCX, 0 },
+#endif /* DEC_TCPIP */
+#endif /* VMS */
+ { "",0,0 }
+};
+int ntcpopt = (sizeof(tcpopt) / sizeof(struct keytab));
+#endif /* TCPSOCKET */
+#endif /* NOTCPOPTS */
+#endif /* NETCONN */
+
+#ifdef OS2
+/* K95 Manual Chapter Table -- Keep these two tables in sync! */
+
+static char * linktbl[] = { /* Internal links in k95.htm */
+ "#top", /* 00 */
+ "#what", /* 01 */
+ "#install", /* 02 */
+ "#start", /* 03 */
+ "#dialer", /* 04 */
+ "#entries", /* 05 */
+ "#command", /* 06 */
+ "#terminal", /* 07 */
+ "#transfer", /* 08 */
+ "#hostmode" /* 09 */
+};
+
+static struct keytab chaptbl[] = {
+ { "Command-Screen", 6, 0 },
+ { "Contents", 0, 0 },
+ { "Dialer-Entries", 5, 0 },
+ { "File-Transfer", 8, 0 },
+ { "Getting-Started", 3, 0 },
+ { "Host-Mode", 9, 0 },
+ { "Installation", 2, 0 },
+ { "Terminal-Emulation", 7, 0 },
+ { "Using-The-Dialer", 4, 0 },
+ { "What-Is-K95", 1, 0 },
+ { "", 0, 0 }
+};
+static int nchaptbl = (sizeof(chaptbl) / sizeof(struct keytab) - 1);
+#endif /* OS2 */
+
+#ifndef NOXFER
+/* Remote Command Table */
+
+struct keytab remcmd[] = {
+#ifndef NOSPL
+ { "as", XZASG, CM_INV|CM_ABR },
+ { "asg", XZASG, CM_INV },
+ { "assign", XZASG, 0 },
+#endif /* NOSPL */
+ { "cd", XZCWD, 0 },
+ { "cdup", XZCDU, CM_INV },
+ { "copy", XZCPY, 0 },
+ { "cwd", XZCWD, CM_INV },
+ { "delete", XZDEL, 0 },
+ { "directory", XZDIR, 0 },
+ { "e", XZXIT, CM_ABR|CM_INV },
+ { "erase", XZDEL, CM_INV },
+ { "exit", XZXIT, 0 },
+ { "help", XZHLP, 0 },
+#ifndef NOPUSH
+ { "host", XZHOS, 0 },
+#endif /* NOPUSH */
+#ifndef NOFRILLS
+ { "kermit", XZKER, 0 },
+ { "l", XZLGI, CM_ABR|CM_INV },
+ { "lo", XZLGI, CM_ABR|CM_INV },
+ { "log", XZLGI, CM_ABR|CM_INV },
+ { "login", XZLGI, 0 },
+ { "logout", XZLGO, 0 },
+ { "message", XZMSG, 0 },
+ { "mkdir", XZMKD, 0 },
+ { "print", XZPRI, 0 },
+#endif /* NOFRILLS */
+ { "pwd", XZPWD, 0 },
+#ifndef NOSPL
+ { "query", XZQUE, 0 },
+#endif /* NOSPL */
+ { "rename", XZREN, 0 },
+ { "rmdir", XZRMD, 0 },
+ { "set", XZSET, 0 },
+ { "space", XZSPA, 0 },
+#ifndef NOFRILLS
+ { "type", XZTYP, 0 },
+ { "who", XZWHO, 0 },
+#endif /* NOFRILLS */
+ { "", 0, 0}
+};
+int nrmt = (sizeof(remcmd) / sizeof(struct keytab)) - 1;
+#endif /* NOXFER */
+
+struct keytab logtab[] = {
+#ifdef CKLOGDIAL
+ { "connections", LOGM, CM_INV },
+ { "cx", LOGM, 0 },
+#endif /* CKLOGDIAL */
+#ifdef DEBUG
+ { "debugging", LOGD, 0 },
+#endif /* DEBUG */
+ { "packets", LOGP, 0 },
+#ifndef NOLOCAL
+ { "session", LOGS, 0 },
+#endif /* NOLOCAL */
+#ifdef TLOG
+ { "transactions", LOGT, 0 },
+#endif /* TLOG */
+ { "", 0, 0 }
+};
+int nlog = (sizeof(logtab) / sizeof(struct keytab)) - 1;
+
+struct keytab writab[] = {
+#ifndef NOSPL
+ { "append-file", LOGW, CM_INV },
+#endif /* NOSPL */
+ { "debug-log", LOGD, 0 },
+ { "error", LOGE, 0 },
+#ifndef NOSPL
+ { "file", LOGW, 0 },
+#endif /* NOSPL */
+ { "packet-log", LOGP, 0 },
+ { "screen", LOGX, 0 },
+#ifndef NOLOCAL
+ { "session-log", LOGS, 0 },
+#endif /* NOLOCAL */
+ { "sys$output", LOGX, CM_INV },
+ { "t", LOGT, CM_ABR|CM_INV }, /* Because of a typo in */
+ { "tr", LOGT, CM_ABR|CM_INV }, /* the book... */
+ { "tra", LOGT, CM_ABR|CM_INV },
+ { "tran", LOGT, CM_ABR|CM_INV },
+ { "trans", LOGT, CM_ABR|CM_INV },
+ { "transa", LOGT, CM_ABR|CM_INV },
+ { "transac", LOGT, CM_ABR|CM_INV },
+ { "transact", LOGT, CM_ABR|CM_INV },
+ { "transacti", LOGT, CM_ABR|CM_INV },
+ { "transactio", LOGT, CM_ABR|CM_INV },
+ { "transaction", LOGT, CM_ABR|CM_INV },
+ { "transaction-log", LOGT, 0 },
+ { "transactions", LOGT, CM_INV }
+};
+int nwri = (sizeof(writab) / sizeof(struct keytab));
+
+static struct keytab clrtab[] = { /* Keywords for CLEAR command */
+#ifndef NOSPL
+ { "alarm", CLR_ALR, 0 },
+#ifdef CK_APC
+ { "apc", CLR_APC, 0 },
+#endif /* CK_APC */
+#ifdef PATTERNS
+ { "binary-patterns", CLR_BIN, 0 },
+#endif /* PATTERNS */
+ { "both", CLR_DEV|CLR_INP, CM_INV },
+#endif /* NOSPL */
+#ifdef OS2
+ { "command-screen", CLR_CMD, 0 },
+#endif /* OS2 */
+#ifndef NOSPL
+ { "device", CLR_DEV, CM_INV|CM_ABR },
+ { "device-and-input", CLR_DEV|CLR_INP, 0 },
+#endif /* NOSPL */
+ { "device-buffer", CLR_DEV, 0 },
+#ifndef NODIAL
+ { "dial-status", CLR_DIA, 0 },
+#endif /* NODIAL */
+#ifndef NOSPL
+ { "input-buffer", CLR_INP, 0 },
+#endif /* NOSPL */
+ { "keyboard-buffer", CLR_KBD, 0 },
+ { "send-list", CLR_SFL, 0 },
+#ifdef OS2
+ { "scr", CLR_SCL, CM_INV|CM_ABR },
+#endif /* OS2 */
+ { "screen", CLR_SCR, 0 },
+#ifdef OS2
+ { "scrollback", CLR_SCL, CM_INV },
+ { "terminal-screen", CLR_TRM, 0 },
+#endif /* OS2 */
+#ifdef PATTERNS
+ { "text-patterns", CLR_TXT, 0 },
+#endif /* PATTERNS */
+ { "", 0, 0 }
+};
+int nclear = (sizeof(clrtab) / sizeof(struct keytab)) - 1;
+
+struct keytab clstab[] = { /* Keywords for CLOSE command */
+#ifndef NOSPL
+ { "!read", LOGR, CM_INV },
+ { "!write", LOGW, CM_INV },
+#ifndef NOPUSH
+#endif /* NOPUSH */
+#endif /* NOSPL */
+#ifndef NOSPL
+ { "append-file", LOGW, CM_INV },
+#endif /* NOSPL */
+#ifndef NOLOCAL
+ { "connection", 9999, 0 },
+#endif /* NOLOCAL */
+#ifdef CKLOGDIAL
+ { "cx-log", LOGM, 0 },
+#endif /* CKLOGDIAL */
+#ifdef DEBUG
+ { "debug-log", LOGD, 0 },
+#endif /* DEBUG */
+ { "host", 9999, CM_INV }, /* Synonym for CLOSE CONNECTION */
+ { "line", 9999, CM_INV }, /* Synonym for CLOSE CONNECTION */
+ { "p", LOGP, CM_INV|CM_ABR },
+ { "packet-log", LOGP, 0 },
+ { "port", 9999, CM_INV }, /* Synonym for CLOSE CONNECTION */
+#ifndef NOSPL
+ { "read-file", LOGR, 0 },
+#endif /* NOSPL */
+#ifndef NOLOCAL
+ { "session-log", LOGS, 0 },
+#endif /* NOLOCAL */
+#ifdef TLOG
+ { "t", LOGT, CM_ABR|CM_INV }, /* Because of a typo in */
+ { "tr", LOGT, CM_ABR|CM_INV }, /* the book... */
+ { "tra", LOGT, CM_ABR|CM_INV },
+ { "tran", LOGT, CM_ABR|CM_INV },
+ { "trans", LOGT, CM_ABR|CM_INV },
+ { "transa", LOGT, CM_ABR|CM_INV },
+ { "transac", LOGT, CM_ABR|CM_INV },
+ { "transact", LOGT, CM_ABR|CM_INV },
+ { "transacti", LOGT, CM_ABR|CM_INV },
+ { "transactio", LOGT, CM_ABR|CM_INV },
+ { "transaction", LOGT, CM_ABR|CM_INV },
+ { "transaction-log", LOGT, 0 },
+ { "transactions", LOGT, CM_INV },
+#endif /* TLOG */
+#ifndef NOSPL
+ { "write-file", LOGW, 0 },
+#endif /* NOSPL */
+ { "", 0, 0 }
+};
+int ncls = (sizeof(clstab) / sizeof(struct keytab)) - 1;
+
+/* SHOW command arguments */
+
+#ifndef NOSHOW
+struct keytab shotab[] = {
+#ifndef NOSPL
+ { "alarm", SHALRM, 0 },
+ { "arg", SHARG, CM_INV|CM_ABR },
+ { "arguments", SHARG, 0 },
+ { "args", SHARG, CM_INV },
+ { "arrays", SHARR, 0 },
+#endif /* NOSPL */
+
+#ifndef NOCSETS
+ { "associations", SHASSOC, 0 },
+#endif /* NOCSETS */
+
+#ifndef NOXFER
+ { "attributes", SHATT, 0 },
+#endif /* NOXFER */
+
+#ifdef CK_AUTHENTICATION
+ { "authentication", SHOAUTH, CM_INV },
+#endif /* CK_AUTHENTICATION */
+
+#ifndef NOPUSH
+#ifdef BROWSER
+ { "browser", SHBROWSE, CM_PSH|CM_LOC },
+#endif /* BROWSER */
+#endif /* NOPUSH */
+ { "cd", SHCD, 0 },
+ { "character-sets", SHCSE, 0 },
+ { "cmd", SHCMD, CM_INV },
+#ifndef NOLOCAL
+ { "com", SHCOM, CM_INV|CM_ABR },
+ { "comm", SHCOM, CM_INV|CM_ABR },
+ { "communications", SHCOM, 0 },
+#endif /* NOLOCAL */
+ { "command", SHCMD, 0 },
+ { "connection", SHCONNX, 0 },
+#ifdef CK_SPEED
+ { "control-prefixing", SHCTL, 0 },
+#endif /* CK_SPEED */
+#ifdef CKLOGDIAL
+ { "cx", SHCONNX, CM_INV },
+#endif /* CKLOGDIAL */
+#ifndef NOSPL
+ { "count", SHCOU, 0 },
+#endif /* NOSPL */
+ { "d", SHDIA, CM_INV|CM_ABR },
+#ifdef VMS
+ { "default", SHDFLT, 0 },
+#else
+ { "default", SHDFLT, CM_INV },
+#endif /* VMS */
+#ifndef NODIAL
+ { "dial", SHDIA, CM_LOC },
+#endif /* NODIAL */
+ { "double/ignore",SHDBL, 0 },
+#ifndef NOPUSH
+#ifndef NOFRILLS
+ { "editor", SHEDIT, CM_PSH },
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+#ifndef NOLOCAL
+ { "escape", SHESC, CM_LOC },
+#endif /* NOLOCAL */
+ { "exit", SHEXI, 0 },
+ { "extended-options", SHXOPT, CM_INV },
+ { "features", SHFEA, 0 },
+ { "file", SHFIL, 0 },
+#ifndef NOLOCAL
+ { "flow-control", SHOFLO, 0 },
+#endif /* NOLOCAL */
+#ifdef BROWSER
+ { "ftp", SHOFTP, CM_PSH|CM_LOC },
+#else
+#ifndef NOFTP
+#ifndef SYSFTP
+#ifdef TCPSOCKET
+ { "ftp", SHOFTP, 0 }, /* (built-in ftp) */
+#endif /* TCPSOCKET */
+#endif /* SYSFTP */
+#endif /* NOFTP */
+#endif /* BROWSER */
+#ifndef NOSPL
+ { "functions", SHFUN, 0 },
+ { "globals", SHVAR, 0 },
+#endif /* NOSPL */
+#ifdef KUI
+ { "gui", SHOGUI, 0 },
+#endif /* KUI */
+#ifdef CK_RECALL
+ { "history", SHHISTORY, 0 },
+#endif /* CK_RECALL */
+ { "ignore/double",SHDBL, CM_INV },
+ { "iksd", SHOIKS, CM_INV },
+#ifndef NOSPL
+ { "input", SHINP, 0 },
+#endif /* NOSPL */
+#ifndef NOSETKEY
+ { "k", SHKEY, CM_INV|CM_ABR },
+ { "key", SHKEY, 0 },
+#ifndef NOKVERBS
+ { "kverbs", SHKVB, 0 },
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+#ifdef CK_LABELED
+ { "labeled-file-info", SHLBL, 0 },
+#endif /* CK_LABELED */
+#ifndef NOCSETS
+ { "languages", SHLNG, 0 },
+#endif /* NOCSETS */
+ { "logs", SHLOG, 0 },
+#ifndef NOSPL
+ { "macros", SHMAC, 0 },
+#endif /* NOSPL */
+#ifndef NODIAL
+ { "modem", SHMOD, CM_LOC },
+#else
+ { "modem-signals",SHCOM, CM_INV|CM_LOC },
+#endif /* NODIAL */
+#ifndef NOLOCAL
+#ifdef OS2MOUSE
+ { "mouse", SHMOU, CM_LOC },
+#endif /* OS2MOUSE */
+#endif /* NOLOCAL */
+#ifdef NETCONN
+ { "network", SHNET, CM_LOC },
+#else
+ { "network", SHNET, CM_INV|CM_LOC },
+#endif /* NETCONN */
+ { "options", SHOPTS, 0 },
+#ifndef NOSPL
+ { "output", SHOUTP, CM_INV },
+#endif /* NOSPL */
+#ifdef ANYX25
+#ifndef IBMX25
+ { "pad", SHPAD, CM_LOC },
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+ { "parameters", SHPAR, CM_INV },
+#ifdef PATTERNS
+ { "patterns", SHOPAT, 0 },
+#endif /* PATTERNS */
+ { "printer", SHPRT, 0 },
+#ifdef CK_SPEED
+ { "prefixing", SHCTL, CM_INV },
+#endif /* CK_SPEED */
+#ifndef NOXFER
+ { "protocol", SHPRO, 0 },
+#endif /* NOXFER */
+ { "rename", SHOREN, 0 },
+#ifndef NOSPL
+ { "scripts", SHSCR, CM_LOC },
+#endif /* NOSPL */
+ { "send-list", SHSFL, 0 },
+#ifndef NOSERVER
+ { "server", SHSER, 0 },
+#endif /* NOSERVER */
+#ifndef NOSEXP
+ { "sexpression", SHSEXP, 0 },
+#endif /* NOSEXP */
+#ifdef ANYSSH
+ { "ssh", SHOSSH, 0 },
+#endif /* ANYSSH */
+ { "stack", SHSTK, 0 },
+ { "status", SHSTA, 0 },
+#ifdef STREAMING
+ { "streaming", SHOSTR, 0 },
+#endif /* STREAMING */
+#ifndef NOLOCAL
+#ifdef OS2
+ { "tabs", SHTAB, CM_INV|CM_LOC },
+#endif /* OS2 */
+#ifdef CK_TAPI
+ { "tapi", SHTAPI, CM_LOC },
+ { "tapi-comm", SHTAPI_C, CM_INV|CM_LOC },
+ { "tapi-location", SHTAPI_L, CM_INV|CM_LOC },
+ { "tapi-modem", SHTAPI_M, CM_INV|CM_LOC },
+#endif /* CK_TAPI */
+ { "tcp", SHTCP, CM_LOC },
+#ifdef TNCODE
+ { "tel", SHTEL, CM_INV|CM_ABR },
+ { "telnet", SHTEL, 0 },
+ { "telopt", SHTOPT, 0 },
+#endif /* TNCODE */
+ { "terminal", SHTER, CM_LOC },
+#endif /* NOLOCAL */
+#ifndef NOXMIT
+ { "tr", SHXMI, CM_INV|CM_ABR },
+ { "tra", SHXMI, CM_INV|CM_ABR },
+ { "tran", SHXMI, CM_INV|CM_ABR },
+ { "trans", SHXMI, CM_INV|CM_ABR },
+#endif /* NOXMIT */
+#ifndef NOXFER
+ { "transfer", SHOXFER, 0 },
+#endif /* NOXFER */
+#ifndef NOXMIT
+ { "transmit", SHXMI, 0 },
+#endif /* NOXMIT */
+#ifdef CK_TRIGGER
+ { "trigger", SHTRIG, CM_LOC },
+#endif /* CK_TRIGGER */
+#ifndef NOSETKEY
+#ifndef NOKVERBS
+#ifdef OS2
+ { "udk", SHUDK, CM_LOC },
+#endif /* OS2 */
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+#ifndef NOSPL
+ { "variables", SHBUI, 0 },
+#endif /* NOSPL */
+#ifndef NOFRILLS
+ { "versions", SHVER, 0 },
+#endif /* NOFRILLS */
+#ifdef OS2
+ { "vscrn", SHVSCRN, CM_INV|CM_LOC },
+#endif /* OS2 */
+ { "xfer", SHOXFER, CM_INV },
+#ifndef NOXMIT
+ { "xmit", SHXMI, CM_INV },
+#endif /* NOXMIT */
+ { "", 0, 0 }
+};
+int nsho = (sizeof(shotab) / sizeof(struct keytab)) - 1;
+#endif /* NOSHOW */
+
+#ifdef ANYX25
+#ifndef IBMX25
+struct keytab padtab[] = { /* PAD commands */
+ { "clear", XYPADL, 0 },
+ { "interrupt", XYPADI, 0 },
+ { "reset", XYPADR, 0 },
+ { "status", XYPADS, 0 }
+};
+int npadc = (sizeof(padtab) / sizeof(struct keytab));
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOSERVER
+static struct keytab kmstab[] = {
+ { "both", 3, 0 },
+ { "local", 1, 0 },
+ { "remote", 2, 0 }
+};
+
+static struct keytab enatab[] = { /* ENABLE commands */
+ { "all", EN_ALL, 0 },
+#ifndef NOSPL
+ { "as", EN_ASG, CM_INV|CM_ABR },
+ { "asg", EN_ASG, CM_INV },
+ { "assign", EN_ASG, 0 },
+#endif /* NOSPL */
+#ifndef datageneral
+ { "bye", EN_BYE, 0 },
+#endif /* datageneral */
+ { "cd", EN_CWD, 0 },
+#ifdef ZCOPY
+ { "copy", EN_CPY, 0 },
+#endif /* ZCOPY */
+ { "cwd", EN_CWD, CM_INV },
+ { "delete", EN_DEL, 0 },
+ { "directory", EN_DIR, 0 },
+ { "enable", EN_ENA, CM_INV },
+ { "exit", EN_XIT, 0 },
+ { "finish", EN_FIN, 0 },
+ { "get", EN_GET, 0 },
+ { "host", EN_HOS, 0 },
+ { "mail", EN_MAI, 0 },
+ { "mkdir", EN_MKD, 0 },
+ { "print", EN_PRI, 0 },
+#ifndef NOSPL
+ { "query", EN_QUE, 0 },
+#endif /* NOSPL */
+ { "rename", EN_REN, 0 },
+ { "retrieve", EN_RET, CM_INV },
+ { "rmdir", EN_RMD, 0 },
+ { "send", EN_SEN, 0 },
+ { "set", EN_SET, 0 },
+ { "space", EN_SPA, 0 },
+ { "type", EN_TYP, 0 },
+ { "who", EN_WHO, 0 }
+};
+static int nena = (sizeof(enatab) / sizeof(struct keytab));
+#endif /* NOSERVER */
+
+struct keytab txtbin[] = {
+ { "all", 2, 0 },
+ { "binary", 1, 0 },
+ { "text", 0, 0 }
+};
+
+#ifndef NOXFER
+static struct keytab sndtab[] = { /* SEND command options */
+ { "/after", SND_AFT, CM_ARG },
+#ifndef NOSPL
+ { "/array", SND_ARR, CM_ARG },
+#endif /* NOSPL */
+ { "/as-name", SND_ASN, CM_ARG },
+ { "/b", SND_BIN, CM_INV|CM_ABR },
+ { "/before", SND_BEF, CM_ARG },
+ { "/binary", SND_BIN, 0 },
+#ifdef CALIBRATE
+ { "/c", SND_CMD, CM_INV|CM_ABR },
+ { "/calibrate", SND_CAL, CM_INV|CM_ARG },
+#endif /* CALIBRATE */
+ { "/command", SND_CMD, CM_PSH },
+ { "/delete", SND_DEL, 0 },
+#ifdef UNIXOROSK
+ { "/dotfiles", SND_DOT, 0 },
+#endif /* UNIXOROSK */
+ { "/except", SND_EXC, CM_ARG },
+#ifdef PIPESEND
+ { "/filter", SND_FLT, CM_ARG|CM_PSH },
+#endif /* PIPESEND */
+ { "/filenames", SND_NAM, CM_ARG },
+#ifdef CKSYMLINK
+ { "/followlinks", SND_LNK, 0 },
+#endif /* CKSYMLINK */
+#ifdef VMS
+ { "/image", SND_IMG, 0 },
+#else
+ { "/image", SND_BIN, CM_INV },
+#endif /* VMS */
+#ifdef CK_LABELED
+ { "/labeled", SND_LBL, 0 },
+#endif /* CK_LABELED */
+ { "/larger-than", SND_LAR, CM_ARG },
+ { "/listfile", SND_FIL, CM_ARG },
+#ifndef NOFRILLS
+ { "/mail", SND_MAI, CM_ARG },
+#endif /* NOFRILLS */
+#ifdef CK_TMPDIR
+ { "/move-to", SND_MOV, CM_ARG },
+#endif /* CK_TMPDIR */
+ { "/nobackupfiles", SND_NOB, 0 },
+#ifdef UNIXOROSK
+ { "/nodotfiles", SND_NOD, 0 },
+#endif /* UNIXOROSK */
+#ifdef CKSYMLINK
+ { "/nofollowlinks", SND_NLK, 0 },
+#endif /* CKSYMLINK */
+ { "/not-after", SND_NAF, CM_ARG },
+ { "/not-before", SND_NBE, CM_ARG },
+ { "/pathnames", SND_PTH, CM_ARG },
+ { "/print", SND_PRI, CM_ARG },
+#ifdef CK_XYZ
+ { "/protocol", SND_PRO, CM_ARG },
+#else
+ { "/protocol", SND_PRO, CM_ARG|CM_INV },
+#endif /* CK_XYZ */
+ { "/quiet", SND_SHH, 0 },
+ { "/recover", SND_RES, 0 },
+#ifdef RECURSIVE
+/* Systems where we do recursion */
+ { "/recursive", SND_REC, 0 },
+#else
+#ifdef VMS
+/* Systems that do recursion themselves without our assistance */
+/* if we give them the right kind of wildcard */
+ { "/recursive", SND_REC, 0 },
+#else
+#ifdef datageneral
+ { "/recursive", SND_REC, 0 },
+#else
+ { "/recursive", SND_REC, CM_INV },
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* RECURSIVE */
+ { "/rename-to", SND_REN, CM_ARG },
+ { "/since", SND_AFT, CM_INV|CM_ARG },
+ { "/smaller-than", SND_SMA, CM_ARG },
+ { "/starting-at", SND_STA, CM_ARG },
+#ifndef NOFRILLS
+ { "/su", SND_ASN, CM_ARG|CM_INV|CM_ABR },
+ { "/sub", SND_ASN, CM_ARG|CM_INV|CM_ABR },
+ { "/subject", SND_ASN, CM_ARG },
+#endif /* NOFRILLS */
+#ifdef RECURSIVE
+ { "/subdirectories", SND_REC, CM_INV },
+#endif /* RECURSIVE */
+ { "/text", SND_TXT, 0 },
+ { "/transparent", SND_XPA, 0 },
+ { "/type", SND_TYP, CM_ARG }
+};
+#define NSNDTAB sizeof(sndtab)/sizeof(struct keytab)
+static int nsndtab = NSNDTAB;
+
+#ifndef NOMSEND
+static struct keytab msndtab[] = { /* MSEND options */
+ { "/after", SND_AFT, CM_ARG },
+ { "/before", SND_BEF, CM_ARG },
+ { "/binary", SND_BIN, 0 },
+ { "/delete", SND_DEL, 0 },
+ { "/except", SND_EXC, CM_ARG },
+ { "/filenames", SND_NAM, CM_ARG },
+#ifdef CKSYMLINK
+ { "/followlinks", SND_LNK, 0 },
+#endif /* CKSYMLINK */
+#ifdef VMS
+ { "/image", SND_IMG, 0 },
+#else
+ { "/image", SND_BIN, CM_INV },
+#endif /* VMS */
+#ifdef CK_LABELED
+ { "/labeled", SND_LBL, 0 },
+#endif /* CK_LABELED */
+ { "/larger-than", SND_LAR, CM_ARG },
+ { "/list", SND_FIL, CM_ARG },
+#ifndef NOFRILLS
+ { "/mail", SND_MAI, CM_ARG },
+#endif /* NOFRILLS */
+#ifdef CK_TMPDIR
+ { "/move-to", SND_MOV, CM_ARG },
+#endif /* CK_TMPDIR */
+#ifdef CKSYMLINK
+ { "/nofollowlinks", SND_NLK, 0 },
+#endif /* CKSYMLINK */
+ { "/not-after", SND_NAF, CM_ARG },
+ { "/not-before", SND_NBE, CM_ARG },
+ { "/pathnames", SND_PTH, CM_ARG },
+ { "/print", SND_PRI, CM_ARG },
+#ifdef CK_XYZ
+ { "/protocol", SND_PRO, CM_ARG },
+#endif /* CK_XYZ */
+ { "/quiet", SND_SHH, 0 },
+ { "/recover", SND_RES, 0 },
+ { "/rename-to", SND_REN, CM_ARG },
+ { "/since", SND_AFT, CM_INV|CM_ARG },
+ { "/smaller-than", SND_SMA, CM_ARG },
+ { "/starting-at", SND_STA, CM_ARG },
+#ifndef NOFRILLS
+ { "/subject", SND_ASN, CM_ARG },
+#endif /* NOFRILLS */
+ { "/text", SND_TXT, 0 },
+ { "/transparent", SND_XPA, 0 },
+ { "/type", SND_TYP, CM_ARG }
+};
+#define NMSNDTAB sizeof(msndtab)/sizeof(struct keytab)
+static int nmsndtab = NMSNDTAB;
+#endif /* NOMSEND */
+#endif /* NOXFER */
+
+/* CONNECT command switches */
+
+#define CONN_II 0 /* Idle interval */
+#define CONN_IS 1 /* Idle string */
+#define CONN_IL 2 /* Idle limit */
+#define CONN_NV 3 /* Non-Verbose */
+#define CONN_TL 4 /* Time limit */
+#define CONN_TS 5 /* Trigger string */
+#define CONN_AS 6 /* Asynchronous */
+#define CONN_SY 7 /* Synchronous */
+#define CONN_MAX 7 /* Number of CONNECT switches */
+
+#ifndef NOLOCAL
+static struct keytab conntab[] = {
+#ifdef OS2
+ { "/asynchronous", CONN_AS, CM_INV },
+#endif /* OS2 */
+#ifdef XLIMITS
+ { "/idle-interval", CONN_II, CM_ARG },
+ { "/idle-limit", CONN_IL, CM_ARG },
+ { "/idle-string", CONN_IS, CM_ARG },
+ { "/quietly", CONN_NV, CM_INV },
+#else
+ { "/quietly", CONN_NV, 0 },
+#endif /* XLIMITS */
+#ifdef OS2
+ { "/synchronous", CONN_SY, CM_INV },
+#endif /* OS2 */
+#ifdef XLIMITS
+ { "/time-limit", CONN_TL, CM_ARG },
+#endif /* XLIMITS */
+#ifdef CK_TRIGGER
+ { "/trigger", CONN_TS, CM_ARG },
+#endif /* CK_TRIGGER */
+ { "",0,0 }
+};
+#define NCONNTAB sizeof(conntab)/sizeof(struct keytab)
+static int nconntab = NCONNTAB;
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+static struct keytab stattab[] = { /* STATISTICS command switches */
+ { "/brief", 1, 0 },
+ { "/verbose", 0, 0 }
+};
+#endif /* NOXFER */
+
+#ifndef NOSPL
+#ifdef COMMENT
+struct mtab mactab[MAC_MAX] = { /* Preinitialized macro table */
+ { NULL, NULL, 0 }
+};
+#else
+struct mtab *mactab; /* Dynamically allocated macro table */
+#endif /* COMMENT */
+int nmac = 0;
+
+struct keytab mackey[MAC_MAX]; /* Macro names as command keywords */
+#endif /* NOSPL */
+
+#ifndef NOSPL
+#ifdef OS2
+struct keytab beeptab[] = { /* Beep options */
+ { "error", BP_FAIL, 0 },
+ { "information", BP_NOTE, 0 },
+ { "warning", BP_WARN, 0 }
+};
+int nbeeptab = sizeof(beeptab)/sizeof(struct keytab);
+
+/* CLEAR COMMMAND-SCREEN options */
+
+#define CLR_C_ALL 0
+#define CLR_C_BOL 1
+#define CLR_C_BOS 2
+#define CLR_C_EOL 3
+#define CLR_C_EOS 4
+#define CLR_C_LIN 5
+#define CLR_C_SCR 6
+
+struct keytab clrcmdtab[] = {
+ { "all", CLR_C_ALL, 0 },
+ { "bol", CLR_C_BOL, 0 },
+ { "bos", CLR_C_BOS, 0 },
+ { "eol", CLR_C_EOL, 0 },
+ { "eos", CLR_C_EOS, 0 },
+ { "line", CLR_C_LIN, 0 },
+ { "scrollback", CLR_C_SCR, 0 }
+};
+int nclrcmd = sizeof(clrcmdtab)/sizeof(struct keytab);
+#endif /* OS2 */
+#endif /* NOSPL */
+
+#ifdef COMMENT
+/* Not used at present */
+static struct keytab pagetab[] = {
+ { "/more", 1, CM_INV },
+ { "/nopage", 0, 0 },
+ { "/page", 1, 0 }
+};
+int npagetab = sizeof(pagetab)/sizeof(struct keytab);
+#endif /* COMMENT */
+
+#define TYP_NOP 0 /* /NOPAGE */
+#define TYP_PAG 1 /* /PAGE */
+#define TYP_HEA 2 /* /HEAD:n */
+#define TYP_TAI 3 /* /TAIL:n */
+#define TYP_PAT 4 /* /MATCH:pattern */
+#define TYP_WID 5 /* /WIDTH:cols */
+#define TYP_COU 6 /* /COUNT */
+#define TYP_OUT 7 /* /OUTPUT:file */
+#define TYP_PFX 8 /* /PREFIX:string */
+#ifdef UNICODE
+#define TYP_XIN 9 /* /TRANSLATE-FROM:charset */
+#define TYP_XUT 10 /* /TRANSLATE-TO:charset */
+#define TYP_XPA 11 /* /TRANSPARENT */
+#endif /* UNICODE */
+#ifdef KUI
+#define TYP_GUI 12 /* /GUI:title */
+#define TYP_HIG 13 /* /HEIGHT:rows */
+#endif /* KUI */
+#define TYP_NUM 14 /* /NUMBER */
+
+static struct keytab typetab[] = { /* TYPE command switches */
+ { "/count", TYP_COU, 0 },
+#ifdef UNICODE
+ { "/character-set", TYP_XIN, CM_ARG },
+#endif /* UNICODE */
+#ifdef KUI
+ { "/gui", TYP_GUI, CM_ARG },
+#endif /* KUI */
+ { "/head", TYP_HEA, CM_ARG },
+#ifdef KUI
+ { "/height", TYP_HIG, CM_ARG },
+#endif /* KUI */
+ { "/match", TYP_PAT, CM_ARG },
+#ifdef CK_TTGWSIZ
+ { "/more", TYP_PAG, CM_INV },
+ { "/nopage", TYP_NOP, 0 },
+ { "/number", TYP_NUM, 0 },
+ { "/output", TYP_OUT, CM_ARG },
+ { "/page", TYP_PAG, 0 },
+#endif /* CK_TTGWSIZ */
+ { "/prefix", TYP_PFX, CM_ARG },
+ { "/tail", TYP_TAI, CM_ARG },
+#ifdef UNICODE
+ { "/translate-to", TYP_XUT, CM_ARG },
+ { "/transparent", TYP_XPA, 0 },
+#endif /* UNICODE */
+ { "/width", TYP_WID, CM_ARG },
+#ifdef UNICODE
+ { "/xlate-to", TYP_XUT, CM_INV|CM_ARG },
+#endif /* UNICODE */
+ { "", 0, 0 }
+};
+int ntypetab = sizeof(typetab)/sizeof(struct keytab) - 1;
+
+int typ_page = -1; /* TYPE /[NO]PAGE default */
+int typ_wid = -1;
+
+#ifndef NOSPL
+#define TRA_ALL 999 /* TRACE command */
+#define TRA_ASG 0
+#define TRA_CMD 1
+
+int tra_asg = 0;
+int tra_cmd = 0;
+
+static struct keytab tracetab[] = { /* TRACE options */
+ { "all", TRA_ALL, 0 },
+ { "assignments", TRA_ASG, 0 },
+ { "command-level", TRA_CMD, 0 }
+};
+static int ntracetab = sizeof(tracetab)/sizeof(struct keytab);
+#endif /* NOSPL */
+
+#ifndef NOSHOW
+VOID
+showtypopts() {
+ printf(" TYPE ");
+ if (typ_page > -1) {
+ prtopt(&optlines,typ_page ? "/PAGE" : "/NOPAGE");
+ } else
+ prtopt(&optlines,"(no options set)");
+ if (typ_wid > -1) {
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"/WIDTH:",ckitoa(typ_wid),NULL,NULL);
+ prtopt(&optlines,tmpbuf);
+ }
+ prtopt(&optlines,"");
+}
+#endif /* NOSHOW */
+
+#ifdef LOCUS
+/* isauto == 1 if locus is being switched automatically */
+
+VOID
+setlocus(x, isauto) int x, isauto; {
+ extern int quitting;
+ if (x) x = 1;
+ if (x && locus) return;
+ if (!x && !locus) return;
+ /* Get here if it actually needs to be changed */
+#ifdef OS2
+ if (isauto && /* Automatically switching */
+ !quitting && /* not exiting */
+ autolocus == 2) { /* and AUTOLOCUS is set to ASK */
+ char locmsg[300];
+ ckmakmsg(locmsg,300,
+ "Switching Locus to ",
+ x ? "LOCAL" : "REMOTE",
+ " for file management commands\n"
+ "such as CD, DIRECTORY, DELETE, RENAME. Type HELP SET\n"
+ "LOCUS at the K-95> prompt for further info. Use the\n"
+#ifdef KUI
+ "Actions menu or SET LOCUS command to disable automatic\n"
+ "Locus switching or to disable these queries.",
+#else /* KUI */
+ "SET LOCUS command to disable automatic locus switching\n"
+ "or to disable these queries.",
+#endif /* KUI */
+ NULL);
+ if (uq_ok(locmsg,"OK to switch Locus?",3,NULL,1)) {
+ locus = x;
+#ifdef KUI
+ KuiSetProperty(KUI_LOCUS,x,0);
+#endif /* KUI */
+ return;
+ }
+ } else {
+#endif /* OS2 */
+ if (isauto && msgflg && !quitting)
+ printf("Switching LOCUS for file-management commands to %s %s.\n",
+ x ? "LOCAL" : "REMOTE",
+ "(HELP LOCUS for info)"
+ );
+ locus = x;
+#ifdef OS2
+#ifdef KUI
+ KuiSetProperty(KUI_LOCUS,x,0);
+#endif /* KUI */
+ }
+#endif /* OS2 */
+}
+
+VOID
+setautolocus(x) int x; {
+ autolocus = x;
+#ifdef KUI
+ KuiSetProperty(KUI_AUTO_LOCUS,x,0);
+#endif /* KUI */
+}
+#endif /* LOCUS */
+
+int
+settypopts() { /* Set TYPE option defaults */
+ int xp = -1;
+ int c, getval;
+ while (1) {
+ if ((y = cmswi(typetab,ntypetab,"Switch","",xxstring)) < 0) {
+ if (y == -3)
+ break;
+ else
+ return(y);
+ }
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ switch (y) {
+ case TYP_NOP: xp = 0; break;
+ case TYP_PAG: xp = 1; break;
+ case TYP_WID:
+ if (getval)
+ if ((x = cmnum("Column at which to truncate",
+ ckitoa(cmd_cols),10,&y,xxstring)) < 0)
+ return(x);
+ typ_wid = y;
+ break;
+
+ default:
+ printf("?Sorry, this option can not be set\n");
+ return(-9);
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (xp > -1) typ_page = xp; /* Confirmed, save defaults */
+ return(success = 1);
+}
+
+/* Forward declarations of functions local to this module */
+
+#ifdef UNIX
+_PROTOTYP (int douchmod, ( void ) );
+#endif /* UNIX */
+#ifdef CKPURGE
+_PROTOTYP (int dopurge, ( void ) );
+#endif /* CKPURGE */
+#ifndef NOSPL
+_PROTOTYP (int doundef, ( int ) );
+_PROTOTYP (int doask, ( int ) );
+_PROTOTYP (int dodef, ( int ) );
+_PROTOTYP (int doelse, ( void ) );
+_PROTOTYP (int dofor, ( void ) );
+#endif /* NOSPL */
+#ifndef NODIAL
+_PROTOTYP (int dodial, ( int ) );
+#endif /* NODIAL */
+_PROTOTYP (int dodel, ( void ) );
+_PROTOTYP (int dopaus, ( int ) );
+#ifndef NOPUSH
+#ifdef TCPSOCKET
+_PROTOTYP (int doping, ( void ) );
+_PROTOTYP (int doftp, ( void ) );
+#endif /* TCPSOCKET */
+#endif /* NOPUSH */
+#ifndef NORENAME
+#ifndef NOFRILLS
+_PROTOTYP (int dorenam, ( void ) );
+#endif /* NOFRILLS */
+#endif /* NORENAME */
+#ifdef ZCOPY
+_PROTOTYP (int docopy, ( void ) );
+#endif /* ZCOPY */
+#ifdef NT
+_PROTOTYP (int dolink, ( void ));
+#endif /* NT */
+#ifdef CK_REXX
+_PROTOTYP (int dorexx, ( void ) );
+#endif /* CK_REXX */
+
+#ifdef TNCODE
+static struct keytab telcmd[] = {
+ { "abort", TN_ABORT, CM_INV }, /* Emotionally toned - don't show */
+ { "ao", TN_AO, 0 },
+ { "ayt", TN_AYT, 0 },
+ { "break", BREAK, 0 },
+ { "cancel",TN_ABORT, 0 },
+ { "dmark", TN_DM, 0 },
+ { "do", DO, 0 },
+ { "dont", DONT, 0 },
+ { "ec", TN_EC, 0 },
+ { "el", TN_EL, 0 },
+ { "eof", TN_EOF, 0 },
+ { "eor", TN_EOR, 0 },
+#ifdef CK_KERBEROS
+#ifdef KRB5
+#define TN_FWD 1
+ { "forward", TN_FWD, CM_INV },
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+ { "ga", TN_GA, 0 },
+ { "ip", TN_IP, 0 },
+ { "nop", TN_NOP, 0 },
+ { "sak", TN_SAK, CM_INV },
+ { "sb", SB, 0 },
+ { "se", SE, 0 },
+ { "susp", TN_SUSP, 0 },
+ { "will", WILL, 0 },
+ { "wont", WONT, 0 }
+};
+static int ntelcmd = (sizeof(telcmd) / sizeof(struct keytab));
+
+static struct keytab tnopts[] = {
+#ifdef CK_AUTHENTICATION
+ { "auth", TELOPT_AUTHENTICATION, 0 },
+#else
+ { "auth", TELOPT_AUTHENTICATION, CM_INV },
+#endif /* CK_AUTHENTICATION */
+ { "binary", TELOPT_BINARY, 0 },
+#ifdef TN_COMPORT
+ { "c", TELOPT_COMPORT, CM_INV|CM_ABR},
+ { "co", TELOPT_COMPORT, CM_INV|CM_ABR},
+ { "com", TELOPT_COMPORT, CM_INV|CM_ABR},
+ { "com-port-control", TELOPT_COMPORT, 0 },
+ { "comport-control", TELOPT_COMPORT, CM_INV},
+#else /* TN_COMPORT */
+ { "com-port-control", TELOPT_COMPORT, CM_INV },
+ { "comport-control", TELOPT_COMPORT, CM_INV},
+#endif /* TN_COMPORT */
+ { "echo", TELOPT_ECHO, 0 },
+#ifdef CK_ENCRYPTION
+ { "encrypt", TELOPT_ENCRYPTION, 0 },
+#else
+ { "encrypt", TELOPT_ENCRYPTION, CM_INV },
+#endif /* CK_ENCRYPTION */
+#ifdef CK_FORWARD_X
+ { "forward-x", TELOPT_FORWARD_X, 0 },
+#else
+ { "forward-x", TELOPT_FORWARD_X, CM_INV },
+#endif /* CK_FORWARD_X */
+#ifdef IKS_OPTION
+ { "kermit", TELOPT_KERMIT, 0 },
+#else
+ { "kermit", TELOPT_KERMIT, CM_INV },
+#endif /* IKS_OPTION */
+ { "lflow", TELOPT_LFLOW, CM_INV },
+ { "logout", TELOPT_LOGOUT, CM_INV },
+#ifdef CK_NAWS
+ { "naws", TELOPT_NAWS, 0 },
+#else
+ { "naws", TELOPT_NAWS, CM_INV },
+#endif /* CK_NAWS */
+#ifdef CK_ENVIRONMENT
+ { "new-environment", TELOPT_NEWENVIRON, 0 },
+#else
+ { "new-environment", TELOPT_NEWENVIRON, CM_INV },
+#endif /* CK_ENVIRONMENT */
+ { "pragma-heartbeat",TELOPT_PRAGMA_HEARTBEAT, CM_INV },
+ { "pragma-logon", TELOPT_PRAGMA_LOGON, CM_INV },
+ { "pragma-sspi", TELOPT_SSPI_LOGON, CM_INV },
+ { "sak", TELOPT_IBM_SAK, CM_INV },
+#ifdef CK_SNDLOC
+ { "send-location", TELOPT_SNDLOC, 0 },
+#else
+ { "send-location", TELOPT_SNDLOC, CM_INV },
+#endif /* CK_SNDLOC */
+ { "sga", TELOPT_SGA, 0 },
+#ifdef CK_SSL
+ { "start-tls", TELOPT_START_TLS, 0 },
+#else
+ { "start-tls", TELOPT_START_TLS, CM_INV },
+#endif /* CK_SSL */
+ { "ttype", TELOPT_TTYPE, 0 },
+#ifdef CK_ENVIRONMENT
+ { "xdisplay-location", TELOPT_XDISPLOC, 0 },
+#else
+ { "xdisplay-location", TELOPT_XDISPLOC, CM_INV },
+#endif /* CK_ENVIRONMENT */
+ { "", 0, 0 }
+};
+static int ntnopts = (sizeof(tnopts) / sizeof(struct keytab)) - 1;
+
+static struct keytab tnsbopts[] = {
+#ifdef CK_NAWS
+ { "naws", TELOPT_NAWS, 0 },
+#endif /* CK_NAWS */
+ { "", 0, 0 }
+};
+static int ntnsbopts = (sizeof(tnsbopts) / sizeof(struct keytab)) - 1;
+#endif /* TNCODE */
+
+#ifdef TCPSOCKET
+#ifndef NOPUSH
+#ifdef SYSFTP
+int
+doftp() { /* (External) FTP command */
+ char *p, *f; /* (See doxftp() for internal one) */
+ int x;
+
+ if (network) /* If we have a current connection */
+ ckstrncpy(line,ttname,LINBUFSIZ); /* get the host name */
+ else *line = '\0'; /* as default host */
+ for (p = line; *p; p++) /* Remove ":service" from end. */
+ if (*p == ':') { *p = '\0'; break; }
+ if ((x = cmtxt("IP host name or number", line, &s, xxstring)) < 0)
+ return(x);
+ if (nopush) {
+ printf("?Sorry, FTP command disabled\n");
+ return(success = 0);
+ }
+/* Construct FTP command */
+#ifdef VMS
+#ifdef MULTINET /* TGV MultiNet */
+ ckmakmsg(line,LINBUFSIZ,"multinet ftp ",s,NULL,NULL);
+#else
+ ckmakmsg(line,LINBUFSIZ,"ftp ",s,NULL,NULL);
+#endif /* MULTINET */
+#else /* Not VMS */
+#ifdef OS2ORUNIX
+#ifndef NOFTP
+ f = ftpapp;
+ if (!f) f = "";
+ if (!f[0]) f = "ftp";
+ ckmakmsg(line,LINBUFSIZ,f," ",s,NULL);
+#ifdef OS2
+ p = line + strlen(ftpapp);
+ while (p != line) {
+ if (*p == '/') *p = '\\';
+ p--;
+ }
+#endif /* OS2 */
+#else /* NOFTP */
+ ckmakmsg(line,LINBUFSIZ,"ftp ",s,NULL,NULL);
+#endif /* NOFTP */
+#else /* OS2ORUNIX */
+ ckmakmsg(line,LINBUFSIZ,"ftp ",s,NULL,NULL);
+#endif /* OS2ORUNIX */
+#endif /* VMS */
+ conres(); /* Make console normal */
+#ifdef DEC_TCPIP
+ printf("\n"); /* Prevent prompt-stomping */
+#endif /* DEC_TCPIP */
+ x = zshcmd(line);
+ concb((char)escape);
+ return(success = x);
+}
+#endif /* SYSFTP */
+
+int
+doping() { /* PING command */
+ char *p; /* just runs ping program */
+ int x;
+
+ if (network) /* If we have a current connection */
+ ckstrncpy(line,ttname,LINBUFSIZ); /* get the host name */
+ else *line = '\0'; /* as default host to be pinged. */
+ for (p = line; *p; p++) /* Remove ":service" from end. */
+ if (*p == ':') { *p = '\0'; break; }
+ if ((x = cmtxt("IP host name or number", line, &s, xxstring)) < 0)
+ return(x);
+ if (nopush) {
+ printf("?Sorry, PING command disabled\n");
+ return(success = 0);
+ }
+
+ /* Construct PING command */
+#ifdef VMS
+#ifdef MULTINET /* TGV MultiNet */
+ ckmakmsg(line,LINBUFSIZ,"multinet ping ",s," /num=1",NULL);
+#else
+ ckmakmsg(line,LINBUFSIZ,"ping ",s," 56 1",NULL); /* Other VMS TCP/IP's */
+#endif /* MULTINET */
+#else /* Not VMS */
+ ckmakmsg(line,LINBUFSIZ,"ping ",s,NULL,NULL);
+#endif /* VMS */
+ conres(); /* Make console normal */
+#ifdef DEC_TCPIP
+ printf("\n"); /* Prevent prompt-stomping */
+#endif /* DEC_TCPIP */
+ x = zshcmd(line);
+ concb((char)escape);
+ return(success = x);
+}
+#endif /* NOPUSH */
+#endif /* TCPSOCKET */
+
+static VOID
+doend(x) int x; {
+#ifndef NOSPL
+ /* Pop from all FOR/WHILE/XIF/SWITCH's */
+ debug(F101,"doend maclvl 1","",maclvl);
+ while ((maclvl > 0) &&
+ (m_arg[maclvl-1][0]) &&
+ (cmdstk[cmdlvl].src == CMD_MD) &&
+ (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_for",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_whi",4) ||
+ !strncmp(m_arg[maclvl-1][0],"_swi",4))) {
+ debug(F110,"END popping",m_arg[maclvl-1][0],0);
+ dogta(XXPTA); /* Put args back */
+ popclvl(); /* Pop up two levels */
+ popclvl();
+ debug(F101,"doend maclvl 2","",maclvl);
+ }
+ if (maclvl > -1) {
+ if (mrval[maclvl]) /* Free previous retval if any */
+ free(mrval[maclvl]);
+ mrval[maclvl] = malloc(16); /* Room for up to 15 digits */
+ if (mrval[maclvl]) /* Record current retval */
+ ckmakmsg(mrval[maclvl],16,ckitoa(x),NULL,NULL,NULL);
+ }
+#endif /* NOSPL */
+ popclvl(); /* Now pop out of macro or TAKE file */
+#ifndef NOSPL
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"END maclvl 3","",maclvl);
+ debug(F111,"END mrval[maclvl]",mrval[maclvl],maclvl);
+ debug(F111,"END mrval[maclvl+1]",mrval[maclvl+1],maclvl+1);
+ }
+#endif /* DEBUG */
+#endif /* NOSPL */
+}
+
+#ifdef CKROOT
+int
+dochroot() {
+ if ((x = cmdir("Name of new root directory","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Directory name required\n");
+ return(-9);
+ }
+ return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ if ((x = cmcfm()) < 0) return(x);
+ s = brstrip(s);
+ x = zsetroot(s);
+ if (x < 0) {
+ char * m = NULL;
+ switch (x) {
+ case -1:
+ case -2: m = "Not a directory"; break;
+ case -3: m = "Internal error"; break;
+ case -4: m = "Access denied"; break;
+ case -5: m = "Off limits"; break;
+ }
+ if (m) printf("%s: \"%s\"\n", m, s);
+ return(m ? -9 : -2);
+ } else {
+ nopush = 1;
+ return(success = 1);
+ }
+}
+#endif /* CKROOT */
+
+#ifndef NOXFER
+static char * asnbuf = NULL; /* As-name buffer pointer */
+
+char sndxnam[] = { "_array_x_" }; /* (with replaceable x!) */
+
+/*
+ The new SEND command, replacing BSEND, CSEND, PSEND, etc etc.
+ Call with cx = top-level keyword value. Returns:
+ < 0 On parse error.
+ 0 On other type of failure (e.g. requested operation not allowed).
+ 1 On success with sstate set to 's' so protocol will begin.
+*/
+
+/* D O X S E N D -- Parse SEND and related commands with switches */
+
+int
+doxsend(cx) int cx; {
+ int c, i, n, wild, confirmed = 0; /* Workers */
+ int x, y; /* of the world... */
+ int getval = 0; /* Whether to get switch value */
+ extern char * snd_move; /* Directory to move sent files to */
+ extern char * snd_rename; /* What to rename sent files to */
+ extern char * filefile; /* File containing filenames to send */
+ extern int xfiletype; /* Send only text (or binary) files */
+ extern struct keytab pathtab[]; /* PATHNAMES option keywords */
+ extern int npathtab; /* How many of them */
+ extern int recursive; /* Recursive directory traversal */
+ extern int rprintf; /* REMOTE PRINT flag */
+ extern int fdispla; /* TRANSFER DISPLAY setting */
+ extern int skipbup; /* Skip backup files when sending */
+ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
+ struct FDB sf, sw, fl, cm; /* FDBs for each parse function */
+ int mlist = 0; /* Flag for MSEND or MMOVE */
+ char * m; /* For making help messages */
+ extern struct keytab protos[]; /* File transfer protocols */
+ extern int xfrxla, g_xfrxla, nprotos;
+ extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
+ extern char sndnbefore[], sndnafter[];
+ extern CK_OFF_T sndsmaller, sndlarger, calibrate;
+#ifndef NOSPL
+ int range[2]; /* Array range */
+ char ** ap = NULL; /* Array pointer */
+ int arrayx = -1; /* Array index */
+#endif /* NOSPL */
+
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) {
+ if (cx == XXMAI) {
+ printf("?Sorry, No MAIL with FTP\n");
+ return(-9);
+ }
+ return(doftpput(cx,0));
+ }
+#endif /* NEWFTP */
+
+ for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = -1; /* and -1 int values */
+ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
+ }
+#ifndef NOSPL
+ range[0] = -1;
+ range[1] = -1;
+ sndxin = -1; /* Array index */
+#endif /* NOSPL */
+ sndarray = NULL; /* Array pointer */
+
+#ifdef UNIXOROSK
+ g_matchdot = matchdot; /* Match dot files */
+#endif /* UNIXOROSK */
+ g_recursive = recursive; /* Recursive sending */
+ recursive = 0; /* Save global value, set local */
+ debug(F101,"xsend entry fncnv","",fncnv);
+
+ /* Preset switch values based on top-level command that called us */
+
+ switch (cx) {
+ case XXMSE: /* MSEND */
+ mlist = 1; break;
+ case XXCSEN: /* CSEND */
+ pv[SND_CMD].ival = 1; break;
+ case XXMMOVE: /* MMOVE */
+ mlist = 1;
+ case XXMOVE: /* MOVE */
+ pv[SND_DEL].ival = 1; break;
+ case XXRSEN: /* RESEND */
+ pv[SND_BIN].ival = 1; /* Implies /BINARY */
+ pv[SND_RES].ival = 1; break;
+ case XXMAI: /* MAIL */
+ pv[SND_MAI].ival = 1; break;
+ }
+
+ /* Set up chained parse functions... */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+#ifdef NOMSEND
+ nsndtab, /* addtl numeric data 1: tbl size */
+#else
+ mlist ? nmsndtab : nsndtab, /* addtl numeric data 1: tbl size */
+#endif /* NOMSEND */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+#ifdef NOMSEND
+ sndtab, /* Keyword table */
+#else
+ mlist ? msndtab : sndtab,
+#endif /* NOMSEND */
+ &sf /* Pointer to next FDB */
+ );
+ cmfdbi(&sf, /* 2nd FDB - file to send */
+ _CMIFI, /* fcode */
+ "File(s) to send", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nolinks, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ mlist ? &cm : &fl
+ );
+ cmfdbi(&fl, /* 3rd FDB - command to send from */
+ _CMFLD, /* fcode */
+ "Command", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* 4th FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"xsend cmfdb","",x);
+ if (x < 0) /* Error */
+ goto xsendx; /* or reparse needed */
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+/*
+ They gave a switch, but let's see how they terminated it.
+ If they ended it with : or =, then we must parse a value.
+ If they ended it with anything else, then we must NOT parse a value.
+*/
+ c = cmgbrk(); /* Get break character */
+ getval = (c == ':' || c == '='); /* to see how they ended the switch */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ x = -9;
+ goto xsendx;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ x = -9;
+ goto xsendx;
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"xsend switch","",n);
+
+ switch (n) { /* Process the switch */
+ case SND_CMD: /* These take no args */
+ if (nopush) {
+ printf("?Sorry, system command access is disabled\n");
+ x = -9;
+ goto xsendx;
+ }
+#ifdef PIPESEND
+ else if (sndfilter) {
+ printf(
+"?Sorry, no SEND /COMMAND or CSEND when SEND FILTER selected\n");
+ x = -9;
+ goto xsendx;
+ }
+#endif /* PIPESEND */
+ sw.hlpmsg = "Command, or switch"; /* Change help message */
+ pv[n].ival = 1; /* Just set the flag */
+ pv[SND_ARR].ival = 0;
+ break;
+
+ case SND_REC: /* /RECURSIVE */
+ recursive = 2; /* Set the real variable */
+ pv[SND_PTH].ival = PATH_REL; /* Give them relative pathnames */
+ pv[n].ival = 1; /* Just set the flag */
+ break;
+
+ case SND_RES: /* /RECOVER (resend) */
+ pv[SND_ARR].ival = 0;
+ pv[SND_BIN].ival = 1; /* Implies /BINARY */
+ case SND_NOB: /* /NOBACKUP */
+ case SND_DEL: /* /DELETE */
+ case SND_SHH: /* /QUIET */
+ pv[n].ival = 1; /* Just set the flag */
+ break;
+
+#ifdef UNIXOROSK
+/* Like recursive, these are set immediately because they affect cmifi() */
+ case SND_DOT: /* /DOTFILES */
+ matchdot = 1;
+ break;
+ case SND_NOD: /* /NODOTFILES */
+ matchdot = 0;
+ break;
+#endif /* UNIXOROSK */
+
+ /* File transfer modes - each undoes the others */
+
+ case SND_BIN: /* Binary */
+ case SND_TXT: /* Text */
+ case SND_IMG: /* Image */
+ case SND_LBL: /* Labeled */
+ pv[SND_BIN].ival = 0;
+ pv[SND_TXT].ival = 0;
+ pv[SND_IMG].ival = 0;
+ pv[SND_LBL].ival = 0;
+ pv[n].ival = 1;
+ break;
+
+#ifdef CKSYMLINK
+ case SND_LNK:
+ case SND_NLK:
+ nolinks = (n == SND_NLK) ? 2 : 0;
+ cmfdbi(&sf, /* Redo cmifi() */
+ _CMIFI, /* fcode */
+ "File(s) to send", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nolinks, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ mlist ? &cm : &fl
+ );
+ break;
+#endif /* CKSYMLINK */
+
+ case SND_EXC: /* Excludes */
+ if (!getval) break;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ x = -9;
+ }
+ goto xsendx;
+ }
+ if (pv[n].sval) free(pv[n].sval);
+ y = strlen(s);
+ if (y > 256) {
+ printf("?Pattern too long - 256 max\n");
+ x = -9;
+ goto xsendx;
+ }
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ break;
+
+ case SND_MOV: /* MOVE after */
+ case SND_REN: /* RENAME after */
+ if (!getval) break;
+ if ((x = cmfld(n == SND_MOV ?
+ "device and/or directory for source file after sending" :
+ "new name for source file after sending",
+ "",
+ &s,
+ n == SND_MOV ? xxstring : NULL
+ )) < 0) {
+ if (x == -3) {
+ printf("%s\n", n == SND_MOV ?
+ "?Destination required" :
+ "?New name required"
+ );
+ x = -9;
+ }
+ goto xsendx;
+ }
+ if (pv[n].sval) free(pv[n].sval);
+ s = brstrip(s);
+ y = strlen(s);
+ if (y > 0) {
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ }
+ break;
+
+ case SND_SMA: /* Smaller / larger than */
+ case SND_LAR: {
+ CK_OFF_T w;
+ if (!getval) break;
+ if ((x = cmnumw("Size in bytes","0",10,&w,xxstring)) < 0)
+ goto xsendx;
+ pv[n].wval = w;
+ break;
+ }
+ case SND_AFT: /* Send /AFTER:date-time */
+ case SND_BEF: /* Send /BEFORE:date-time */
+ case SND_NAF: /* Send /NOT-AFTER:date-time */
+ case SND_NBE: /* Send /NOT-BEFORE:date-time */
+ if (!getval) break;
+ if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Date-time required\n");
+ x = -9;
+ }
+ goto xsendx;
+ }
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = malloc((int)strlen(s)+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ break;
+
+ case SND_MAI: /* Send as mail (= MAIL) */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_mai)) {
+ printf("?Sorry, sending files as mail is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ pv[n].ival = 1;
+ if (!getval) break;
+ if ((x = cmfld("e-mail address","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?address required\n");
+ x = -9;
+ }
+ goto xsendx;
+ }
+ s = brstrip(s);
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = malloc((int)strlen(s)+1);
+ if (pv[n].sval)
+ strcpy(pv[n].sval,s); /* safe */
+ break;
+
+ case SND_PRI: /* Send to be printed (REMOTE PRINT) */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_mai)) {
+ printf("?Sorry, sending files for printing is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ pv[n].ival = 1;
+ if (!getval) break;
+ if ((x = cmfld("Print options","",&s,xxstring)) < 0)
+ if (x != -3) goto xsendx;
+ s = brstrip(s);
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = malloc((int)strlen(s)+1);
+ if (pv[n].sval)
+ strcpy(pv[n].sval,s); /* safe */
+ break;
+
+ case SND_ASN: /* As-name */
+ debug(F101,"xsend /as-name getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
+ if (x == -3) {
+ printf("?name required\n");
+ x = -9;
+ }
+ goto xsendx;
+ }
+ s = brstrip(s);
+ if ((y = strlen(s)) > 0) {
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ }
+ break;
+
+ case SND_STA: { /* Starting position (= PSEND) */
+ CK_OFF_T w;
+ if (!getval) break;
+ if ((x = cmnumw("0-based position","0",10,&w,xxstring)) < 0)
+ goto xsendx;
+ pv[n].wval = w;
+ break;
+ }
+ case SND_PRO: /* Protocol to use */
+ if (!getval) break;
+ if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
+ xxstring)) < 0) {
+ if (x == -3) {
+ printf("?name of protocol required\n");
+ x = -9;
+ }
+ goto xsendx;
+ }
+ pv[n].ival = x;
+ break;
+
+#ifdef PIPESEND
+ case SND_FLT: /* Filter */
+ debug(F101,"xsend /filter getval","",getval);
+ if (!getval) break;
+ if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
+ if (x == -3)
+ s = "";
+ else
+ goto xsendx;
+ }
+ if (*s) s = brstrip(s);
+ y = strlen(s);
+ for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
+ if (s[x] != '\\') continue;
+ if (s[x+1] == 'v') break;
+ }
+ if (x == y) {
+ printf(
+ "?Filter must contain a replacement variable for filename.\n"
+ );
+ x = -9;
+ goto xsendx;
+ }
+ pv[n].ival = 1;
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if ((y = strlen(s)) > 0) {
+ if ((pv[n].sval = malloc(y+1)))
+ strcpy(pv[n].sval,s); /* safe */
+ }
+ break;
+#endif /* PIPESEND */
+
+ case SND_PTH: /* Pathnames */
+ if (!getval) {
+ pv[n].ival = PATH_REL;
+ break;
+ }
+ if ((x = cmkey(pathtab,npathtab,"","absolute",xxstring)) < 0)
+ goto xsendx;
+ pv[n].ival = x;
+ break;
+
+ case SND_NAM: /* Filenames */
+ if (!getval) break;
+ if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
+ goto xsendx;
+ debug(F101,"xsend /filenames","",x);
+ pv[n].ival = x;
+ break;
+
+#ifdef CALIBRATE
+ case SND_CAL: { /* /CALIBRATE */
+ CK_OFF_T w;
+ if (getval) {
+ if ((x = cmnumw("number of Kbytes to send",
+ "1024",10,&w,xxstring)) < 0)
+ goto xsendx;
+ } else
+ w = (CK_OFF_T)1024;
+ pv[n].wval = w;
+ pv[SND_ARR].ival = 0;
+ break;
+ }
+#endif /* CALIBRATE */
+
+ case SND_FIL: /* Name of file containing filnames */
+ if (!getval) break;
+ if ((x = cmifi("Name of file containing list of filenames",
+ "",&s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Filename required\n");
+ x = -9;
+ }
+ goto xsendx;
+ } else if (y) {
+ printf("?Wildcards not allowed\n");
+ x = -9;
+ goto xsendx;
+ }
+ if (pv[n].sval)
+ free(pv[n].sval);
+ if (s) if (*s) {
+ if ((pv[n].sval = malloc((int)strlen(s)+1))) {
+ strcpy(pv[n].sval,s);
+ pv[n].ival = 1;
+ pv[SND_ARR].ival = 0;
+ }
+ }
+ break;
+
+#ifndef NOSPL
+ case SND_ARR: /* SEND /ARRAY: */
+ if (!getval) break;
+ ap = NULL;
+ if ((x = cmfld("Array name (a single letter will do)",
+ "",
+ &s,
+ NULL
+ )) < 0) {
+ if (x == -3)
+ break;
+ else
+ return(x);
+ }
+ if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
+ printf("?Bad array: %s\n",s);
+ return(-9);
+ }
+ if (!(ap = a_ptr[x])) {
+ printf("?No such array: %s\n",s);
+ return(-9);
+ }
+ pv[n].ival = 1;
+ pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
+ pv[SND_RES].ival = 0;
+ pv[SND_CAL].ival = 0;
+ pv[SND_FIL].ival = 0;
+ arrayx = x;
+ break;
+#endif /* NOSPL */
+
+ case SND_XPA: /* /TRANSPARENT */
+ pv[n].ival = 1;
+ break;
+
+ case SND_TYP: /* Only files of given type */
+ if (!getval) break;
+ if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
+ goto xsendx;
+ pv[n].ival = (x == 2) ? -1 : x;
+ break;
+
+ default:
+ printf("?Unexpected switch value - %d\n",cmresult.nresult);
+ x = -9;
+ goto xsendx;
+ }
+ }
+ debug(F101,"xsend cmresult fcode","",cmresult.fcode);
+
+#ifdef COMMENT
+ /* List switch parsing results in debug log */
+ for (i = 0; i <= SND_MAX; i++) {
+ ckmakmsg(line,LINBUFSIZ,"xsend switch ",ckitoa(i),NULL,NULL);
+ debug(F111,line, pv[i].sval, pv[i].ival);
+ }
+#endif /* COMMENT */
+
+/* Now we have all switches, plus maybe a filename or command, or nothing */
+
+#ifdef PIPESEND
+ if (protocol != PROTO_K && pv[SND_CMD].ival > 0) {
+ printf("?Sorry, %s works only with Kermit protocol\n",
+ (cx == XXCSEN) ? "CSEND" : "SEND /COMMAND");
+ x = -9;
+ goto xsendx;
+ }
+ if (pv[SND_RES].ival > 0 || /* /RECOVER */
+ pv[SND_STA].wval > 0) { /* or /STARTING */
+ if (sndfilter || pv[SND_FLT].ival > 0) {
+ printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
+ x = -9;
+ goto xsendx;
+ }
+ }
+#endif /* PIPESEND */
+
+ cmarg = "";
+ cmarg2 = "";
+ line[0] = NUL;
+ s = line;
+ wild = 0;
+
+ switch (cmresult.fcode) { /* How did we get out of switch loop */
+ case _CMIFI: /* Input filename */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
+ if (pv[SND_ARR].ival > 0)
+ cmarg2 = line;
+ else
+ wild = cmresult.nresult; /* Wild flag */
+ if (!recursive && !wild)
+ nolinks = 0;
+ break;
+ case _CMFLD: /* Field */
+ /* Only allowed with /COMMAND and /ARRAY */
+ if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
+#ifdef CKROOT
+ if (ckrooterr)
+ printf("?Off limits: %s\n",cmresult.sresult);
+ else
+#endif /* CKROOT */
+ printf("?%s - \"%s\"\n",
+ iswild(cmresult.sresult) ?
+ "No files match" : "File not found",
+ cmresult.sresult
+ );
+ x = -9;
+ goto xsendx;
+ }
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ if (pv[SND_ARR].ival > 0)
+ cmarg2 = line;
+ break;
+ case _CMCFM: /* Confirmation */
+ /* s = ""; */
+ confirmed = 1;
+ break;
+ default:
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ x = -9;
+ goto xsendx;
+ }
+ debug(F110,"xsend string",s,0);
+ debug(F101,"xsend confirmed","",confirmed);
+
+ /* Save and change protocol and transfer mode */
+ /* Global values are restored in main parse loop */
+
+ g_proto = protocol; /* Save current global protocol */
+ g_urpsiz = urpsiz;
+ g_spsizf = spsizf;
+ g_spsiz = spsiz;
+ g_spsizr = spsizr;
+ g_spmax = spmax;
+ g_wslotr = wslotr;
+ g_prefixing = prefixing;
+ g_fncact = fncact;
+ g_fncnv = fncnv;
+ g_fnspath = fnspath;
+ g_fnrpath = fnrpath;
+ g_xfrxla = xfrxla;
+
+ if (pv[SND_PRO].ival > -1) { /* Change according to switch */
+ protocol = pv[SND_PRO].ival;
+ if (ptab[protocol].rpktlen > -1) /* copied from initproto() */
+ urpsiz = ptab[protocol].rpktlen;
+ if (ptab[protocol].spktflg > -1)
+ spsizf = ptab[protocol].spktflg;
+ if (ptab[protocol].spktlen > -1) {
+ spsiz = ptab[protocol].spktlen;
+ if (spsizf)
+ spsizr = spmax = spsiz;
+ }
+ if (ptab[protocol].winsize > -1)
+ wslotr = ptab[protocol].winsize;
+ if (ptab[protocol].prefix > -1)
+ prefixing = ptab[protocol].prefix;
+ if (ptab[protocol].fnca > -1)
+ fncact = ptab[protocol].fnca;
+ if (ptab[protocol].fncn > -1)
+ fncnv = ptab[protocol].fncn;
+ if (ptab[protocol].fnsp > -1)
+ fnspath = ptab[protocol].fnsp;
+ if (ptab[protocol].fnrp > -1)
+ fnrpath = ptab[protocol].fnrp;
+ }
+ debug(F101,"xsend protocol","",protocol);
+
+ if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
+ g_skipbup = skipbup;
+ skipbup = 1;
+ }
+ if (pv[SND_REC].ival > 0) /* /RECURSIVE */
+ recursive = 2;
+
+ if (pv[SND_TYP].ival > -1) { /* /TYPE */
+ xfiletype = pv[SND_TYP].ival;
+ if (xfiletype == 2)
+ xfiletype = -1;
+ }
+ g_binary = binary; /* Save global transfer mode */
+#ifdef PATTERNS
+ g_patterns = patterns; /* Save FILE PATTERNS setting */
+#endif /* PATTERNS */
+ if (pv[SND_BIN].ival > 0) { /* Change according to switch */
+ /* If they said /BINARY they mean /BINARY */
+ patterns = 0; /* So no pattern-based switching */
+ g_xfermode = xfermode; /* or automatic transfer mode */
+ xfermode = XMODE_M;
+ binary = XYFT_B;
+ debug(F101,"doxsend /BINARY xfermode","",xfermode);
+ } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */
+ patterns = 0;
+ g_xfermode = xfermode;
+ xfermode = XMODE_M;
+ binary = XYFT_T;
+ debug(F101,"doxsend /TEXT xfermode","",xfermode);
+ } else if (pv[SND_IMG].ival > 0) {
+#ifdef VMS
+ binary = XYFT_I;
+#else
+ binary = XYFT_B;
+#endif /* VMS */
+ }
+#ifdef CK_LABELED
+ else if (pv[SND_LBL].ival > 0) {
+ binary = XYFT_L;
+ }
+#endif /* CK_LABELED */
+ debug(F101,"xsend binary","",binary);
+
+ if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */
+ xfrxla = 0; /* Don't translate character sets */
+
+ /* Check for legal combinations of switches, filenames, etc */
+
+#ifdef PIPESEND
+ if (pv[SND_CMD].ival > 0) { /* COMMAND - strip any braces */
+ debug(F110,"SEND /COMMAND before stripping",s,0);
+ s = brstrip(s);
+ debug(F110,"SEND /COMMAND after stripping",s,0);
+ if (!*s) {
+ printf("?Sorry, a command to send from is required\n");
+ x = -9;
+ goto xsendx;
+ }
+ cmarg = s;
+ }
+#endif /* PIPESEND */
+
+/* Set up /MOVE and /RENAME */
+
+ if (pv[SND_DEL].ival > 0 &&
+ (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
+ printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
+ x = -9;
+ goto xsendx;
+ }
+#ifdef CK_TMPDIR
+ if (pv[SND_MOV].ival > 0) {
+ int len;
+ char * p = pv[SND_MOV].sval;
+#ifdef CK_LOGIN
+ if (isguest) {
+ printf("?Sorry, /MOVE-TO not available to guests\n");
+ x = -9;
+ goto xsendx;
+ }
+#endif /* CK_LOGIN */
+ len = strlen(p);
+ if (!isdir(p)) { /* Check directory */
+#ifdef CK_MKDIR
+ char * s = NULL;
+ s = (char *)malloc(len + 4);
+ if (s) {
+ strcpy(s,p); /* safe */
+#ifdef datageneral
+ if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
+#else
+ if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
+#endif /* datageneral */
+ s[len++] = 'X';
+ s[len] = NUL;
+ x = zmkdir(s);
+ free(s);
+ if (x < 0) {
+ printf("?Can't create \"%s\"\n",p);
+ x = -9;
+ goto xsendx;
+ }
+ }
+#else
+ printf("?Directory \"%s\" not found\n",p);
+ x = -9;
+ goto xsendx;
+#endif /* CK_MKDIR */
+ }
+ zfnqfp(p,LINBUFSIZ,tmpbuf);
+ makestr(&snd_move,tmpbuf);
+ }
+#endif /* CK_TMPDIR */
+
+ if (pv[SND_REN].ival > 0) { /* /RENAME */
+ char * p = pv[SND_REN].sval;
+#ifdef CK_LOGIN
+ if (isguest) {
+ printf("?Sorry, /RENAME-TO not available to guests\n");
+ x = -9;
+ goto xsendx;
+ }
+#endif /* CK_LOGIN */
+ if (!p) p = "";
+ if (!*p) {
+ printf("?New name required for /RENAME\n");
+ x = -9;
+ goto xsendx;
+ }
+ p = brstrip(p);
+#ifndef NOSPL
+ /* If name given is wild, rename string must contain variables */
+ if (wild) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(p,&s,&x);
+ if (!strcmp(tmpbuf,p)) {
+ printf(
+ "?/RENAME for file group must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xsendx;
+ }
+ }
+#endif /* NOSPL */
+ makestr(&snd_rename,p);
+ }
+
+/* Handle /RECOVER and /START */
+
+#ifdef CK_RESEND
+ if (pv[SND_RES].ival > 0 && binary != XYFT_B && !filepeek
+#ifdef PATTERNS
+ && !patterns
+#else
+#ifdef VMS
+/* VMS sets text/binary automatically later when it opens the file */
+ && 0
+#endif /* VMS */
+#endif /* PATTERNS */
+ ) {
+ printf("?Sorry, /BINARY required\n");
+ x = -9;
+ goto xsendx;
+ }
+ if (pv[SND_STA].wval > 0) { /* /START */
+ if (wild) {
+ printf("?Sorry, wildcards not permitted with /START\n");
+ x = -9;
+ goto xsendx;
+ }
+ if (sizeof(int) < 4) {
+ printf("?Sorry, this command needs at least 32-bit integers\n");
+ x = -9;
+ goto xsendx;
+ }
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("?Sorry, SEND /START works only with Kermit protocol\n");
+ x = -9;
+ goto xsendx;
+ }
+#endif /* CK_XYZ */
+ }
+#ifdef CK_XYZ
+ if (pv[SND_RES].ival > 0) {
+ if (protocol != PROTO_K && protocol != PROTO_Z) {
+ printf(
+ "Sorry, /RECOVER is possible only with Kermit or ZMODEM protocol\n"
+ );
+ x = -9;
+ goto xsendx;
+ }
+ }
+#endif /* CK_XYZ */
+#endif /* CK_RESEND */
+
+ if (protocol == PROTO_K) {
+ if ((pv[SND_MAI].ival > 0 || /* MAIL */
+ pv[SND_PRI].ival > 0 || /* PRINT */
+ pv[SND_RES].ival > 0 /* RESEND */
+ ) &&
+ (!atdiso || !atcapr)) { /* Disposition attribute off? */
+ printf("?Sorry, ATTRIBUTE DISPOSITION must be ON\n");
+ x = -9;
+ goto xsendx;
+ }
+ }
+
+#ifdef CK_XYZ
+ if (wild && (protocol == PROTO_X || protocol == PROTO_XC)) {
+ printf(
+"Sorry, you can only send one file at a time with XMODEM protocol\n"
+ );
+ x = -9;
+ goto xsendx;
+ }
+#endif /* CK_XYZ */
+
+ if (!confirmed) { /* CR not typed yet, get more fields */
+ char *m;
+ if (mlist) { /* MSEND or MMOVE */
+ nfils = 0; /* We already have the first one */
+#ifndef NOMSEND
+ msfiles[nfils++] = line; /* Store pointer */
+ lp = line + (int)strlen(line) + 1; /* Point past it */
+ debug(F111,"xsend msend",msfiles[nfils-1],nfils-1);
+ while (1) { /* Get more filenames */
+ char *p;
+ if ((x = cmifi("Names of files to send, separated by spaces",
+ "", &s,&y,xxstring)) < 0) {
+ if (x != -3)
+ goto xsendx;
+ if ((x = cmcfm()) < 0)
+ goto xsendx;
+ break;
+ }
+ msfiles[nfils++] = lp; /* Got one, count it, point to it, */
+ p = lp; /* remember pointer, */
+ while ((*lp++ = *s++)) /* and copy it into buffer */
+ if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
+ printf("?MSEND list too long\n");
+ line[0] = NUL;
+ x = -9;
+ goto xsendx;
+ }
+ debug(F111,"xsend msend",msfiles[nfils-1],nfils-1);
+ if (nfils == 1) fspec[0] = NUL; /* Take care of \v(filespec) */
+#ifdef ZFNQFP
+ zfnqfp(p,TMPBUFSIZ,tmpbuf);
+ p = tmpbuf;
+#endif /* ZFNQFP */
+ if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
+ strcat(fspec,p); /* safe */
+ strcat(fspec," "); /* safe */
+ } else
+#ifdef COMMENT
+ printf("WARNING - \\v(filespec) buffer overflow\n");
+#else
+ debug(F101,"doxsend filespec buffer overflow","",0);
+#endif /* COMMENT */
+ }
+#endif /* NOMSEND */
+ } else { /* Regular SEND */
+ char *p; int y;
+ nfils = -1;
+ if (pv[SND_MAI].ival > 0)
+ m = (pv[SND_MAI].sval) ?
+ "e-mail address (optional)" :
+ "e-mail address (required)";
+ else if (pv[SND_PRI].ival > 0)
+ m = "printer options (optional)";
+ else if (wild)
+ m =
+"\nOptional as-name template containing replacement variables \
+like \\v(filename)";
+ else
+ m = "Optional name to send it with";
+ if ((x = cmtxt(m,"",&p,NULL)) < 0)
+ goto xsendx;
+ if (!p) p = "";
+ if (*p) { /* If some text was given... */
+ p = brstrip(p); /* Replace /AS-NAME: value if any */
+ if ((y = strlen(p)) > 0) {
+ if (pv[SND_MAI].ival > 0) {
+ makestr(&pv[SND_MAI].sval, p);
+ } else {
+ if (pv[SND_ASN].sval) free(pv[SND_ASN].sval);
+ pv[SND_ASN].sval = malloc(y+1);
+ if (pv[SND_ASN].sval) {
+ strcpy(pv[SND_ASN].sval,p); /* safe */
+ pv[SND_ASN].ival = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Set cmarg2 from as-name, however we got it. */
+
+ if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !*cmarg2) {
+ int x;
+ x = strlen(line);
+ ckstrncpy(line+x+2,pv[SND_ASN].sval,LINBUFSIZ-x-1);
+ cmarg2 = line+x+2;
+ debug(F110,"doxsend cmarg2",cmarg2,0);
+ }
+
+#ifndef NOFRILLS
+ if ((pv[SND_MAI].ival > 0) && (pv[SND_PRI].ival > 0)) {
+ printf("Sorry, /MAIL and /PRINT are conflicting options\n");
+ x = -9;
+ goto xsendx;
+ }
+ n = 0; /* /MAIL or /PRINT? */
+ if (pv[SND_MAI].ival > 0)
+ n = SND_MAI;
+ else if (pv[SND_PRI].ival > 0)
+ n = SND_PRI;
+ if (n) { /* Yes... */
+#ifdef DEBUG
+ char * p;
+ if (n == SND_MAI)
+ p = "/MAIL";
+ else
+ p = "/PRINT";
+ debug(F111,"xsend",p,n);
+#endif /* DEBUG */
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("Sorry, %s available only with Kermit protocol\n",
+ (n == SND_MAI) ? "/MAIL" : "/PRINT"
+ );
+ x = -9;
+ goto xsendx;
+ }
+#endif /* CK_XYZ */
+ debug(F101,"xsend print/mail wild","",wild);
+ *optbuf = NUL; /* Wipe out any old options */
+ s = pv[n].sval; /* mail address or print switch val */
+ if (!s) s = "";
+ debug(F110,"doxsend mail address or printer options",s,0);
+ if (n == SND_MAI && !*s) {
+ printf("?E-mail address required\n");
+ x = -9;
+ goto xsendx;
+ } else if ((int)strlen(s) > 94) { /* Ensure legal size */
+ printf("?%s too long\n",
+ (n == SND_MAI) ?
+ "E-mail address" :
+ "Print option string"
+ );
+ x = -9;
+ goto xsendx;
+ }
+ ckstrncpy(optbuf,s,OPTBUFLEN); /* OK, copy to option buffer */
+ cmarg = line; /* File to send */
+ if (n == SND_MAI) {
+ debug(F110,"xsend mailing",cmarg,0);
+ debug(F110,"xsend address:",optbuf,0);
+ rmailf = 1;
+ } else {
+ debug(F110,"xsend printing",cmarg,0);
+ debug(F110,"xsend options",optbuf,0);
+ rprintf = 1;
+ }
+ }
+#endif /* NOFRILLS */
+
+#ifdef CALIBRATE
+ if (pv[SND_CAL].wval > 0) { /* Handle /CALIBRATE */
+ if (confirmed) {
+ calibrate = pv[SND_CAL].wval * (CK_OFF_T)1024;
+ sndsrc = -9;
+ nfils = 1;
+ wild = 0;
+#ifndef NOMSEND
+ addlist = 0;
+#endif /* NOMSEND */
+ ckstrncpy(line,"CALIBRATION",LINBUFSIZ);
+ s = cmarg = line;
+ if (!cmarg2) cmarg2 = "";
+ debug(F110,"doxsend cmarg2 calibrate",cmarg2,0);
+ } else if (line[0]) {
+ calibrate = 0;
+ pv[SND_CAL].ival = 0;
+ pv[SND_CAL].wval = 0;
+ }
+ }
+#endif /* CALIBRATE */
+
+ if (pv[SND_FIL].ival > 0) {
+ if (confirmed && !calibrate) {
+ if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
+ debug(F110,"xsend can't open",pv[SND_FIL].sval,0);
+ printf("?Failure to open %s\n",filefile);
+ x = -9;
+ goto xsendx;
+ }
+ makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
+ debug(F110,"xsend opened",filefile,0);
+ wild = 1;
+ }
+ }
+
+ /* SEND alone... */
+
+#ifndef NOSPL
+ if (confirmed && pv[SND_ARR].ival > 0) {
+ if (!*cmarg2) {
+ sndxnam[7] = (char)((arrayx == 1) ? 64 : arrayx + ARRAYBASE);
+ cmarg2 = sndxnam;
+ }
+ cmarg = "";
+ goto sendend;
+ }
+#endif /* NOSPL */
+
+ if (confirmed && !line[0] && !filefile && !calibrate) {
+#ifndef NOMSEND
+ if (filehead) { /* OK if we have a SEND-LIST */
+ nfils = filesinlist;
+ sndsrc = nfils; /* Like MSEND */
+ addlist = 1; /* But using a different list... */
+ filenext = filehead;
+ goto sendend;
+ }
+#endif /* NOMSEND */
+ printf("?Filename required but not given\n");
+ x = -9;
+ goto xsendx;
+ }
+
+ /* Not send-list or array */
+
+#ifndef NOMSEND
+ addlist = 0; /* Don't use SEND-LIST. */
+ filenext = NULL;
+#endif /* NOMSEND */
+
+ if (mlist) { /* MSEND or MMOVE */
+#ifndef NOMSEND
+ cmlist = msfiles; /* List of files to send */
+ sndsrc = nfils;
+ cmarg2 = "";
+ sendstart = (CK_OFF_T)0;
+#endif /* NOMSEND */
+#ifdef PIPESEND
+ pipesend = 0;
+#endif /* PIPESEND */
+ } else if (filefile) { /* File contains list of filenames */
+ s = "";
+ cmarg = "";
+ cmarg2 = "";
+ line[0] = NUL;
+ nfils = 1;
+ sndsrc = 1;
+
+ } else if (!calibrate && pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
+
+ nfils = sndsrc = -1; /* Not MSEND, MMOVE, /LIST, or /ARRAY */
+ if ( /* or /COMMAND */
+
+#ifndef NOFRILLS
+ !rmailf && !rprintf /* Not MAIL or PRINT */
+#else
+ 1
+#endif /* NOFRILLS */
+ ) {
+ CK_OFF_T y = (CK_OFF_T)1;
+ if (!wild)
+ y = zchki(s);
+ if (y < (CK_OFF_T)0) {
+ printf("?Read access denied - \"%s\"\n", s);
+ x = -9;
+ goto xsendx;
+ }
+ if (s != line) /* We might already have done this. */
+ ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
+ else
+ debug(F110,"doxsend line=s",line,0);
+ cmarg = line; /* File to send */
+ }
+ zfnqfp(cmarg,fspeclen,fspec);
+ }
+ if (!mlist) { /* For all but MSEND... */
+#ifdef PIPESEND
+ if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
+ pipesend = 1;
+ debug(F101,"xsend /COMMAND pipesend","",pipesend);
+ if (pipesend && filefile) {
+ printf("?Invalid switch combination\n");
+ x = -9;
+ goto xsendx;
+ }
+#endif /* PIPESEND */
+
+#ifndef NOSPL
+ /* If as-name given and filespec is wild, as-name must contain variables */
+ debug(F111,"doxsend cmarg2 wild",cmarg2,wild);
+ if (wild && *cmarg2) {
+ char * s = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(cmarg2,&s,&x);
+ if (!strcmp(tmpbuf,cmarg2)) {
+ printf(
+ "?As-name for file group must contain variables such as \\v(filename)\n"
+ );
+ x = -9;
+ goto xsendx;
+ }
+ }
+#endif /* NOSPL */
+
+ /* Strip braces from as-name */
+ debug(F110,"xsend cmarg2 before stripping",cmarg2,0);
+ cmarg2 = brstrip(cmarg2);
+ debug(F110,"xsend filename",cmarg,0);
+ debug(F110,"xsend as-name",cmarg2,0);
+
+ /* Copy as-name to a safe place */
+
+ if (asnbuf) {
+ free(asnbuf);
+ asnbuf = NULL;
+ }
+ if ((y = strlen(cmarg2)) > 0) {
+ asnbuf = (char *) malloc(y + 1);
+ if (asnbuf) {
+ strcpy(asnbuf,cmarg2); /* safe */
+ cmarg2 = asnbuf;
+ } else cmarg2 = "";
+ }
+
+#ifdef CK_RESEND
+ debug(F111,"xsend pv[SND_STA].ival","",pv[SND_STA].ival);
+ if (pv[SND_STA].wval > (CK_OFF_T)-1) { /* /START position */
+ if (wild) {
+ printf("?/STARTING-AT may not be used with multiple files.\n");
+ x = -9;
+ goto xsendx;
+ } else
+ sendstart = pv[SND_STA].wval;
+ } else
+ sendstart = (CK_OFF_T)0;
+ debug(F101,"xsend /STARTING","",sendstart);
+#endif /* CK_RESEND */
+ }
+
+sendend: /* Common successful exit */
+ moving = 0;
+ if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
+ g_displa = fdispla;
+ fdispla = 0;
+ debug(F101,"xsend display","",fdispla);
+ }
+
+#ifndef NOSPL /* SEND /ARRAY... */
+ if (pv[SND_ARR].ival > 0) {
+ if (!ap) { x = -2; goto xsendx; } /* (shouldn't happen) */
+ if (range[0] == -1) /* If low end of range not specified */
+ range[0] = 1; /* default to 1 */
+ if (range[1] == -1) /* If high not specified */
+ range[1] = a_dim[arrayx]; /* default to size of array */
+ if ((range[0] < 0) || /* Check range */
+ (range[0] > a_dim[arrayx]) ||
+ (range[1] < range[0]) ||
+ (range[1] > a_dim[arrayx])) {
+ printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
+ x = -9;
+ goto xsendx;
+ }
+ sndarray = ap; /* Array pointer */
+ sndxin = arrayx; /* Array index */
+ sndxlo = range[0]; /* Array range */
+ sndxhi = range[1];
+ sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
+
+#ifdef COMMENT
+ printf("SENDING FROM ARRAY: &%c[]...\n", /* debugging */
+ (sndxin == 1) ? 64 : sndxin + ARRAYBASE);
+ printf("Lo=%d\nHi=%d\n", sndxlo, sndxhi);
+ printf("cmarg=[%s]\ncmarg2=[%s]\n", cmarg, cmarg2);
+ while ((x = agnbyte()) > -1) {
+ putchar((char)x);
+ }
+ return(1);
+#endif /* COMMENT */
+ }
+#endif /* NOSPL */
+
+ if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
+
+ if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
+ moving = 1;
+ debug(F101,"xsend /DELETE","",moving);
+ if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
+ ckstrncpy(sndafter,pv[SND_AFT].sval,19);
+ if (pv[SND_BEF].ival > 0)
+ ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
+ if (pv[SND_NAF].ival > 0)
+ ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
+ if (pv[SND_NBE].ival > 0)
+ ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
+ if (pv[SND_EXC].ival > 0)
+ makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
+ if (pv[SND_SMA].wval > (CK_OFF_T)-1)
+ sndsmaller = pv[SND_SMA].wval;
+ if (pv[SND_LAR].wval > (CK_OFF_T)-1)
+ sndlarger = pv[SND_LAR].wval;
+ if (pv[SND_NAM].ival > -1) {
+ g_fncnv = fncnv; /* Save global value */
+ fncnv = pv[SND_NAM].ival;
+ debug(F101,"xsend fncnv","",fncnv);
+ }
+ if (pv[SND_PTH].ival > -1) {
+ g_spath = fnspath; /* Save global values */
+ fnspath = pv[SND_PTH].ival;
+#ifndef NZLTOR
+ if (fnspath != PATH_OFF) {
+ g_fncnv = fncnv; /* Bad bad... */
+ fncnv = XYFN_C;
+ }
+#endif /* NZLTOR */
+ debug(F101,"xsend fnspath","",fnspath);
+ debug(F101,"xsend fncnv","",fncnv);
+ }
+ }
+
+#ifdef PIPESEND
+ if (pv[SND_FLT].ival > 0) {
+ makestr(&sndfilter,pv[SND_FLT].sval);
+ debug(F110,"xsend /FILTER", sndfilter, 0);
+ }
+#endif /* PIPESEND */
+
+#ifdef CK_APC
+/* MOVE not allowed in APCs */
+ if (moving &&
+ (apcactive == APC_LOCAL || apcactive == APC_REMOTE)
+ && !(apcstatus & APC_UNCH))
+ return(success = 0);
+#endif /* CK_APC */
+#ifdef IKS_OPTION
+ if (
+#ifdef CK_XYZ
+ protocol == PROTO_K &&
+#endif /* CK_XYZ */
+ !iks_wait(KERMIT_REQ_START,1)) {
+ printf("?A Kermit Server is not available to process this command.\n");
+ printf("?Start a RECEIVE command to complement this command.\n");
+ }
+#endif /* IKS_OPTION */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (moving && inserver && isguest) {
+ printf("?File deletion not allowed for guests.\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+ sstate = 's'; /* Set start state to SEND */
+ sndcmd = 1;
+#ifdef CK_RESEND
+ if (pv[SND_RES].ival > 0) /* Send sendmode appropriately */
+ sendmode = SM_RESEND;
+ else if (pv[SND_STA].ival > 0)
+ sendmode = SM_PSEND;
+ else
+#endif /* CK_RESEND */
+ if (mlist)
+ sendmode = SM_MSEND;
+ else
+ sendmode = SM_SEND;
+#ifdef MAC
+ what = W_SEND;
+ scrcreate();
+#endif /* MAC */
+ if (local && pv[SND_SHH].ival != 0) { /* If in local mode, */
+ displa = 1; /* turn on file transfer display */
+ }
+ x = 0;
+
+ xsendx: /* Common exit, including failure */
+ debug(F101,"doxsend sndsrc","",sndsrc);
+ for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ }
+ return(x);
+}
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+/* D O X C O N N -- CONNECT command parsing with switches */
+
+#ifdef XLIMITS
+#define XLIMORTRIGGER
+#else
+#ifdef CK_TRIGGER
+#define XLIMORTRIGGER
+#endif /* CK_TRIGGER */
+#endif /* XLIMITS */
+
+#ifdef CKTIDLE
+int tt_idlelimit = 0; /* Terminal idle limit */
+int tt_idleact = IDLE_RET; /* Terminal idle action */
+#endif /* CKTIDLE */
+
+#ifdef OS2 /* K95 only: */
+extern int
+ tt_idlesnd_tmo; /* Idle interval */
+int tt_timelimit = 0; /* Time limit, 0 = none */
+extern char * /* Parse results - strings: */
+ tt_idlesnd_str; /* Idle string */
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+extern char *tt_trigger[];
+extern CHAR *tt_trmatch[];
+extern char *triggerval;
+static char *g_tt_trigger[TRIGGERS];
+#endif /* CK_TRIGGER */
+
+#ifdef OS2
+static int g_tt_idlesnd_tmo, g_tt_timelimit; /* For saving and restoring */
+static int g_tt_idlelimit, g_tt_saved = 0;
+static char * g_tt_idlesnd_str; /* global settings */
+#endif /* OS2 */
+
+static struct stringint pv[CONN_MAX+1];
+
+VOID
+resconn() {
+ int i;
+
+#ifdef OS2
+ if ( g_tt_saved ) {
+ tt_idlelimit = g_tt_idlelimit;
+ tt_idlesnd_tmo = g_tt_idlesnd_tmo;
+ tt_timelimit = g_tt_timelimit;
+ tt_idlesnd_str = g_tt_idlesnd_str;
+ g_tt_saved = 0;
+ }
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+ for (i = 0; i < TRIGGERS; i++)
+ tt_trigger[i] = g_tt_trigger[i];
+#endif /* CK_TRIGGER */
+
+ for (i = 0; i <= CONN_MAX; i++) { /* Free malloc'd memory */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ pv[i].sval = NULL;
+ }
+}
+
+int
+doxconn(cx) int cx; {
+ int c, i, n; /* Workers */
+ int x, y;
+ int getval = 0; /* Whether to get switch value */
+ int async = 0; /* Make an async connect */
+ struct FDB sw, cm; /* FDBs for each parse function */
+ extern FILE * tfile[];
+ extern char * macp[];
+
+#ifdef OS2
+ g_tt_idlesnd_tmo = tt_idlesnd_tmo; /* Save global settings */
+ g_tt_timelimit = tt_timelimit;
+ g_tt_idlelimit = tt_idlelimit;
+ g_tt_idlesnd_str = tt_idlesnd_str;
+ g_tt_saved = 1;
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+ if (!tt_trigger[0]) { /* First initialization */
+ for (i = 1; i < TRIGGERS; i++)
+ tt_trigger[i] = NULL;
+ }
+ for (i = 0; i < TRIGGERS; i++)
+ g_tt_trigger[i] = tt_trigger[i];
+ if (triggerval) {
+ free(triggerval);
+ triggerval = NULL;
+ }
+#endif /* CK_TRIGGER */
+
+ for (i = 0; i <= CONN_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = -1; /* and -1 int values */
+ pv[i].wval = (CK_OFF_T)-1;
+ }
+ if (cx == XXCQ) /* CQ == CONNECT /QUIETLY */
+ pv[CONN_NV].ival = 1;
+
+ /* Set up chained parse functions... */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nconntab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ conntab, /* Keyword table */
+ &cm /* Pointer to next FDB */
+ );
+ cmfdbi(&cm, /* 2nd FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw); /* Parse switch or confirmation */
+ debug(F101,"doxconn cmfdb","",x);
+ if (x < 0) { /* Error */
+ if (x == -9 || x == -2)
+ printf("?No switches match - \"%s\"\n",atmbuf);
+ goto xconnx; /* or reparse needed */
+ }
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk(); /* Get break character */
+ getval = (c == ':' || c == '='); /* to see how they ended the switch */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ x = -9;
+ goto xconnx;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"doxconn switch","",n);
+
+ switch (n) { /* Process the switch */
+#ifdef OS2
+ case CONN_AS: /* Asynchronous */
+ pv[CONN_AS].ival = 1;
+ pv[CONN_SY].ival = 0;
+ break;
+ case CONN_SY: /* Synchronous */
+ pv[CONN_SY].ival = 1;
+ pv[CONN_AS].ival = 0;
+ break;
+#endif /* OS2 */
+ case CONN_NV: /* Non-verbal */
+ pv[n].ival = 1;
+ break;
+#ifdef XLIMITS
+ case CONN_II: /* Idle-interval */
+ case CONN_IL: /* Idle-limit */
+ case CONN_TL: /* Time-limit */
+ if (!getval) break;
+ if ((x = cmnum("Seconds","0",10,&y,xxstring)) < 0)
+ goto xconnx;
+ pv[n].ival = y;
+ break;
+ case CONN_IS: /* Idle-string */
+#endif /* XLIMITS */
+#ifdef CK_TRIGGER
+ case CONN_TS: /* Trigger-string */
+#endif /* CK_TRIGGER */
+#ifdef XLIMORTRIGGER
+ if (!getval) break;
+ if ((x = cmfld("String (enclose in braces if it contains spaces)",
+ "",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?String required\n");
+ x = -9;
+ }
+ goto xconnx;
+ }
+ if (n != CONN_TS)
+ s = brstrip(s);
+ if ((y = strlen(s)) > 0) {
+ if (pv[n].sval) free(pv[n].sval);
+ pv[n].sval = malloc(y+1);
+ if (pv[n].sval) {
+ strcpy(pv[n].sval,s); /* safe */
+ pv[n].ival = 1;
+ }
+ }
+ break;
+#endif /* XLIMORTRIGGER */
+ default:
+ printf("?Unexpected switch value - %d\n",cmresult.nresult);
+ x = -9;
+ goto xconnx;
+ }
+ }
+ debug(F101,"doxconn cmresult.fcode","",cmresult.fcode);
+ if (cmresult.fcode != _CMCFM) {
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ x = -9;
+ goto xconnx;
+ }
+
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a script */
+ /* if CONNECT was the final command in the script. */
+
+ if (cmdlvl > 0)
+ prepop();
+
+#ifdef OS2 /* Make results available globally */
+ if (pv[CONN_IL].ival > -1) /* Idle limit */
+ tt_idlelimit = pv[CONN_IL].ival;
+ if (pv[CONN_II].ival > -1) /* Idle limit */
+ tt_idlesnd_tmo = pv[CONN_II].ival;
+ if (pv[CONN_IS].sval) /* Idle string */
+ if (tt_idlesnd_str = (char *)malloc((int)strlen(pv[CONN_IS].sval)+1))
+ strcpy(tt_idlesnd_str,pv[CONN_IS].sval); /* safe */
+ if (pv[CONN_TL].ival > -1) /* Session limit */
+ tt_timelimit = pv[CONN_TL].ival;
+ async = (pv[CONN_AS].ival > 0 ||
+ pv[CONN_SY].ival <= 0 && cmdlvl == 0) ? 1 : 0;
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+ if (pv[CONN_TS].sval) /* Trigger strings */
+ makelist(pv[CONN_TS].sval,tt_trigger,TRIGGERS);
+ for (i = 0; i < TRIGGERS; i++) /* Trigger match pointers */
+ tt_trmatch[i] = NULL;
+ if (triggerval) { /* Reset trigger value */
+ free(triggerval);
+ triggerval = NULL;
+ }
+#endif /* CK_TRIGGER */
+
+#ifdef SSHCMD
+/*
+ 2010/03/01...
+ The previous connection was through the external ssh client and now, with
+ that connection closed, the user says "connect" and expects a new connection
+ to be made to the same host, because that's how all the other connection
+ methods work, so (and this is quite a hack)...
+*/
+ if (!ckstrcmp("ssh ",ttname,4,0)) { /* Previous "host" was "ssh blah" */
+ _PROTOTYP (int redossh, ( void ) );
+ extern int ttyfd;
+ if (ttyfd < 0) { /* And connection is no longer open */
+ int xx;
+ xx = redossh(); /* So redo the SSH connection */
+ if (xx < 0) return(xx);
+ goto xconnx;
+ }
+ }
+#endif /* SSHCMD */
+ x = doconect((pv[CONN_NV].ival > 0) ? 1 : 0, async);
+ {
+ int xx;
+ debug(F101,"doxconn doconect returns","",x);
+ if ((xx = ttchk()) < 0) dologend();
+ debug(F101,"doxconn ttchk returns","",xx);
+ }
+
+#ifdef CK_TRIGGER
+ debug(F111,"doxconn doconect triggerval",triggerval,x);
+#endif /* CK_TRIGGER */
+
+ xconnx:
+ /* Back from CONNECT -- Restore global settings */
+
+ if (!async)
+ resconn();
+
+ success = (x > 0) ? 1 : 0;
+ return(x);
+}
+#endif /* NOLOCAL */
+
+#ifdef ADDCMD
+/* cx == XXADD or XXREMV */
+/* fc == ADD_BIN or ADD_TXT */
+static int
+doadd(cx,fc) int cx, fc; {
+#ifdef PATTERNS
+ char * tmp[FTPATTERNS];
+ char **p = NULL;
+ int i, j, k, n = 0, x = 0, last;
+
+#endif /* PATTERNS */
+ if (cx != XXADD && cx != XXREMV) {
+ printf("?Unexpected function code: %d\n",cx);
+ return(-9);
+ }
+#ifdef PATTERNS
+ while (n < FTPATTERNS) { /* Collect new patterns */
+ tmp[n] = NULL;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0)
+ break;
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+ makestr(&(tmp[n++]),s);
+ }
+ if (x == -3)
+ x = cmcfm();
+ if (x < 0)
+ goto xdoadd;
+ p = (fc == ADD_BIN) ? binpatterns : txtpatterns; /* Which list */
+ last = 0;
+ for (i = 0; i < FTPATTERNS; i++) { /* Find last one in list */
+ if (!p[i]) {
+ last = i;
+ break;
+ }
+ }
+ if (cx == XXADD) { /* Adding */
+ if (last + n > FTPATTERNS) { /* Check if too many */
+ printf("?Too many patterns - %d is the maximum\n", FTPATTERNS);
+ goto xdoadd;
+ }
+ for (i = 0; i < n; i++) { /* Copy in the new ones. */
+ for (j = 0, x = 0; x == 0 && j < last ; j++ )
+ x = !ckstrcmp(tmp[i],p[j],-1,filecase); /* match */
+ if (x == 0)
+ makestr(&(p[last++]),tmp[i]);
+ }
+ makestr(&(p[last]),NULL); /* Null-terminate the list */
+ x = 1;
+ goto xdoadd; /* Done */
+ } else if (cx == XXREMV) { /* Remove something(s) */
+ int j, k;
+ if (last == 0) /* List is empty */
+ goto xdoadd; /* Nothing to remove */
+ for (i = 0; i < n; i++) { /* i = Patterns they typed */
+ for (j = 0; j < last; j++) { /* j = Patterns in list */
+ /* Change this to ckstrcmp()... */
+ if (filecase)
+ x = !ckstrcmp(tmp[i],p[j],-1,filecase); /* match */
+ else
+ x = ckstrcmp(tmp[i],p[j],-1,0); /* Case-independent match */
+ if (x) { /* This one matches */
+ makestr(&(p[j]),NULL); /* Free it */
+ for (k = j; k < last; k++) /* Move the rest up */
+ p[k] = p[k+1];
+ p[k] = NULL; /* Erase last one */
+ if (!p[k])
+ break;
+ }
+ }
+ }
+ }
+ xdoadd: /* Common exit */
+ for (i = 0; i < n; i++)
+ if (tmp[i])
+ free(tmp[i]);
+ return(x);
+#endif /* PATTERNS */
+}
+
+/* ADD SEND-LIST */
+
+static int
+addsend(cx) int cx; {
+#ifndef NOMSEND
+ extern struct keytab fttab[];
+ extern int nfttyp;
+ struct filelist * flp;
+ char * fmode = "";
+ int xmode = 0;
+ int xbinary = 0;
+#endif /* NOMSEND */
+
+#ifdef NOMSEND
+ printf("?Sorry, ADD/REMOVE SEND-LIST not available.\n");
+ return(-9);
+#endif /* NOMSEND */
+ if (cx == XXREMV) {
+ printf("?Sorry, REMOVE SEND-LIST not implemented yet.\n");
+ return(-9);
+ }
+#ifndef NOMSEND
+#ifndef XYZ_INTERNAL
+ if (protocol != PROTO_K) {
+ printf("?Sorry, ADD SEND-LIST does not work with external protocols\n");
+ return(-9);
+ }
+#endif /* XYZ_INTERNAL */
+
+ x = cmifi("File specification to add","", &s,&y,xxstring);
+ if (x < 0) {
+ if (x == -3) {
+ printf("?A file specification is required\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ s = tmpbuf;
+ if (filesinlist == 0) /* Take care of \v(filespec) */
+ fspec[0] = NUL;
+ zfnqfp(s,LINBUFSIZ,line);
+ s = line;
+ if (((int)strlen(fspec) + (int)strlen(s) + 1) < fspeclen) {
+ strcat(fspec,s); /* safe */
+ strcat(fspec," "); /* safe */
+ } else
+ printf("WARNING - \\v(filespec) buffer overflow\n");
+
+
+ xbinary = binary;
+ if ((patterns || filepeek) /* FILE PATTERNS or SCAN is ON */
+#ifdef CK_LABELED
+ && binary != XYFT_L /* And not if FILE TYPE LABELED */
+#endif /* CK_LABELED */
+#ifdef VMS
+ && binary != XYFT_I /* or FILE TYPE IMAGE */
+#endif /* VMS */
+ ) {
+ int k, x;
+ x = -1;
+ k = scanfile(line,&x,nscanfile);
+ if (k > 0) xbinary = (k == FT_BIN) ? XYFT_B : XYFT_T;
+ }
+ fmode = gfmode(xbinary,0);
+ if ((x = cmkey(fttab,nfttyp,
+ "type of file transfer", fmode, xxstring)) < 0)
+ return(x);
+ xmode = x;
+
+ cmarg2 = "";
+ if ((x = cmfld(y ?
+ "\nAs-name template containing replacement variables such as \\v(filename)" :
+ "Name to send it with", "",&s,NULL)) < 0)
+ if (x != -3)
+ return(x);
+#ifndef NOSPL
+ if (y && *s) {
+ char * p = tmpbuf;
+ x = TMPBUFSIZ;
+ zzstring(s,&p,&x);
+ if (!strcmp(tmpbuf,s)) {
+ printf(
+ "?As-name for file group must contain variables such as \\v(filename)\n"
+ );
+ return(-9);
+ }
+ }
+#endif /* NOSPL */
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ cmarg2 = tmpbuf;
+
+ if ((x = cmcfm()) < 0)
+ return(x);
+ flp = (struct filelist *) malloc(sizeof(struct filelist));
+ if (flp) {
+ if (filetail)
+ filetail->fl_next = flp;
+ filetail = flp;
+ if (!filehead)
+ filehead = flp;
+ x = (int) strlen(line); /* Length of filename */
+ s = (char *) malloc(x + 1);
+ if (s) {
+ strcpy(s,line); /* safe */
+ flp->fl_name = s;
+ flp->fl_mode = xmode;
+ x = (int) strlen(cmarg2); /* Length of as-name */
+ if (x < 1) {
+ flp->fl_alias = NULL;
+ } else {
+ s = (char *) malloc(x + 1);
+ if (s) {
+ strcpy(s,cmarg2); /* safe */
+ flp->fl_alias = s;
+ } else {
+ printf("Sorry, can't allocate space for as-name");
+ return(-9);
+ }
+ }
+ flp->fl_next = NULL;
+ filesinlist++; /* Count this node */
+ return(success = 1); /* Finished adding this node */
+ } else {
+ printf("Sorry, can't allocate space for name");
+ return(-9);
+ }
+ } else {
+ printf("Sorry, can't allocate file list node");
+ return(-9);
+ }
+#endif /* NOMSEND */
+}
+#endif /* ADDCMD */
+
+#ifndef NOHTTP /* HTTP ops... */
+#ifdef TCPSOCKET
+#define HTTP_GET 0 /* GET */
+#define HTTP_PUT 1 /* PUT */
+#define HTTP_POS 2 /* POST */
+#define HTTP_IDX 3 /* INDEX */
+#define HTTP_HED 4 /* HEAD */
+#define HTTP_DEL 5 /* DELETE */
+#define HTTP_CON 6 /* CONNECT */
+#define HTTP_OPN 7 /* OPEN */
+#define HTTP_CLS 8 /* CLOSE */
+
+static struct keytab httptab[] = {
+ { "close", HTTP_CLS, 0 },
+ { "connect", HTTP_CON, 0 },
+ { "delete", HTTP_DEL, 0 },
+ { "get", HTTP_GET, 0 },
+ { "head", HTTP_HED, 0 },
+ { "index", HTTP_IDX, 0 },
+ { "open", HTTP_OPN, 0 },
+ { "put", HTTP_PUT, 0 },
+ { "post", HTTP_POS, 0 }
+};
+static int nhttptab = sizeof(httptab)/sizeof(struct keytab);
+
+/* HTTP switches */
+#define HT_SW_AG 0 /* /AGENT */
+#define HT_SW_HD 1 /* /HEADER */
+#define HT_SW_US 2 /* /USER */
+#define HT_SW_PW 3 /* /PASSWORD */
+#define HT_SW_AR 4 /* /ARRAY */
+#define HT_SW_TP 5 /* /TOSCREEN */
+
+static struct keytab httpswtab[] = {
+ { "/agent", HT_SW_AG, CM_ARG },
+#ifndef NOSPL
+ { "/array", HT_SW_AR, CM_ARG },
+#endif /* NOSPL */
+ { "/header", HT_SW_HD, CM_ARG },
+ { "/password", HT_SW_PW, CM_ARG },
+ { "/toscreen", HT_SW_TP, 0 },
+ { "/user", HT_SW_US, CM_ARG },
+ { "", 0, 0 }
+};
+static int nhttpswtab = sizeof(httpswtab)/sizeof(struct keytab) - 1;
+
+/* HTTP PUT/POST switches */
+#define HT_PP_MT 0 /* /MIME-TYPE */
+
+static struct keytab httpptab[] = {
+ { "/mime-type", HT_PP_MT, CM_ARG },
+ { "", 0, 0 }
+};
+static int nhttpptab = sizeof(httpptab)/sizeof(struct keytab) - 1;
+
+#define HTTP_MAXHDR 8
+
+static int
+xdohttp(action, lfile, rf, dfile, agent, hdr, user, pass, mime, array, type)
+ int action;
+ char *lfile, *rf, *dfile, *agent, *hdr, *user, *pass, *mime, array;
+ int type;
+/* xdohttp */ {
+ int i, rc = 0;
+ char * hdrlist[HTTP_MAXHDR];
+ char rfile[CKMAXPATH+1];
+ extern int httpfd;
+
+ /* Check for a valid state to execute the command */
+ if (inserver) {
+ printf("?The HTTP command may not be used from the IKS\r\n");
+ } else if (httpfd == -1) {
+ if (http_reopen() < 0)
+ printf("?No connection\n");
+ else
+ rc = 1;
+ } else {
+ rc = 1;
+ }
+
+ /* If the command is not valid, exit with failure */
+ if (rc == 0)
+ return(success = 0);
+
+ if (action != HTTP_CON && rf[0] != '/') {
+ rfile[0] = '/';
+ ckstrncpy(&rfile[1],rf,CKMAXPATH);
+ } else {
+ ckstrncpy(rfile,rf,CKMAXPATH);
+ }
+ for (i = 0; i < HTTP_MAXHDR; i++) /* Initialize header list */
+ hdrlist[i] = NULL;
+ makelist(hdr,hdrlist,HTTP_MAXHDR); /* Make header list */
+
+#ifdef BETADEBUG
+ for (i = 0; i < nhttptab; i++) /* Find action keyword */
+ if (httptab[i].kwval == action)
+ break;
+ if (i == nhttptab) { /* Shouldn't happen... */
+ printf("?Invalid action - %d\n",action);
+ return(0); /* Failure */
+ }
+
+ printf("HTTP action: %s\n",httptab[i].kwd);
+ printf(" Agent: %s\n",agent ? agent : "(null)");
+
+ if (hdrlist[1]) {
+ printf(" Header list: 1. %s\n",hdrlist[0]);
+ for (i = 1; i < HTTP_MAXHDR && hdrlist[i]; i++)
+ printf("%15d. %s\n",i+1,hdrlist[i]);
+ } else
+ printf(" Header: %s\n",hdrlist[0] ? hdrlist[0] : "(null)");
+
+ printf(" User: %s\n",user ? user : "(null)");
+#ifdef COMMENT
+ printf(" Password: %s\n",pass ? pass : "(null)");
+#endif /* COMMENT */
+
+#ifndef NOSPL
+ if (array)
+ printf(" Array: \\%%%c[]\n", array);
+ else
+ printf(" Array: (none)\n");
+#endif /* NOSPL */
+
+ if (action == HTTP_PUT || action == HTTP_POS)
+ printf(" Mime-type: %s\n",mime ? mime : "(null)");
+
+ printf(" Local file: %s\n",lfile ? lfile : "(null)");
+ printf(" Remote file: %s\n",rfile ? rfile : "(null)");
+ printf(" Destination file: %s\n",dfile ? dfile : "(null)");
+#endif /* BETADEBUG */
+
+ /* The http_xxxx() functions return 0 on success, -1 on failure */
+ switch (action) {
+ case HTTP_CON: {
+ extern int ttyfd;
+ rc = http_connect(httpfd,agent,hdrlist,user,pass,array,rfile);
+ break;
+ }
+ case HTTP_DEL:
+ rc = http_delete(agent,hdrlist,user,pass,array,rfile);
+ break;
+ case HTTP_GET:
+ rc = http_get(agent,hdrlist,user,pass,array,lfile,rfile,type);
+ break;
+ case HTTP_HED:
+ rc = http_head(agent,hdrlist,user,pass,array,lfile,rfile,type);
+ break;
+ case HTTP_PUT:
+ rc = http_put(agent,hdrlist,mime,user,pass,array,lfile,rfile,dfile,
+ type);
+ break;
+ case HTTP_POS:
+ rc = http_post(agent,hdrlist,mime,user,pass,array,lfile,rfile,dfile,
+ type);
+ break;
+ case HTTP_IDX:
+ rc = http_index(agent,hdrlist,user,pass,array,lfile,rfile,type);
+ break;
+ default:
+ rc = -1;
+ }
+ return(rc == 0 ? 1 : 0); /* Success is set by caller */
+}
+#endif /* TCPSOCKET */
+#endif /* NOHTTP */
+
+#ifndef NOSPL /* ARRAY ops... */
+static struct keytab arraytab[] = {
+ { "clear", ARR_CLR, 0 },
+ { "copy", ARR_CPY, 0 },
+ { "dcl", ARR_DCL, CM_INV },
+ { "declare", ARR_DCL, 0 },
+ { "destroy", ARR_DST, CM_INV },
+ { "equate", ARR_EQU, CM_INV },
+ { "link", ARR_EQU, 0 },
+ { "resize", ARR_RSZ, 0 },
+ { "set", ARR_SET, 0 },
+#ifndef NOSHOW
+ { "show", ARR_SHO, 0 },
+#endif /* NOSHOW */
+ { "sort", ARR_SRT, 0 },
+ { "undeclare", ARR_DST, 0 },
+ { "", 0, 0 }
+};
+static int narraytab = sizeof(arraytab)/sizeof(struct keytab) - 1;
+
+#ifdef CKLEARN
+static struct keytab learnswi[] = {
+ { "/close", 2, 0 },
+ { "/off", 0, 0 },
+ { "/on", 1, 0 }
+};
+#endif /* CKLEARN */
+
+int
+arrayitoa(x) int x; { /* Array index to array letter */
+ if (x == 1)
+ return(64);
+ else if (x < 0 || x > (122 - ARRAYBASE))
+ return(-1);
+ else
+ return(x + ARRAYBASE);
+}
+
+int
+arrayatoi(c) int c; { /* Array letter to array index */
+ if (c == 64)
+ c = 96;
+ if (c > 63 && c < 91)
+ c += 32;
+ if (c < ARRAYBASE || c > 122)
+ return(-1);
+ return(c - ARRAYBASE);
+}
+
+static int /* Declare an array */
+dodcl(cx) int cx; {
+ int i, n, v, lo, hi, rc = 0;
+ int isdynamic = 0;
+ char tmpbuf[64];
+ char ** p = NULL;
+ char tmp[64]; /* Local temporary string buffer */
+ if ((y = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */
+ if (y == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ x = arraybounds(s,&lo,&hi); /* Check syntax and get bounds */
+ debug(F111,"dodcl arraybounds",s,x);
+ if (x < 0) { /* Error - Maybe it's a variable */
+ char * p; /* whose value is an array name */
+ int n;
+ p = tmpbuf;
+ n = 63;
+ p[0] = NUL;
+ if (s[0] == CMDQ && s[1] == '&')
+ s++;
+ if (zzstring(s,&p,&n) > -1) {
+ s = tmpbuf;
+ x = arraybounds(s,&lo,&hi);
+ debug(F111,"dodcl arraybounds 2",s,x);
+ }
+ if (x < 0) {
+ printf("?Bad array name - \"%s\"\n",s);
+ return(-9);
+ }
+ }
+ debug(F101,"dodcl hi","",hi);
+ debug(F101,"dodcl lo","",lo);
+ debug(F101,"dodcl lo+1","",lo+1);
+
+ if (lo == -1 && hi == -1) { /* Have good array name and bounds */
+ isdynamic = 1;
+ n = CMDBL / 5;
+ } else if (hi > -1) {
+ printf("?Segment notation not allowed in array declarations\n");
+ return(-9);
+ } else if ((lo+1) < 0) {
+ debug(F101,"dodcl underflow","",lo+1);
+ printf("?Dimension underflow\n");
+ return(-9);
+ } else
+ n = lo;
+ x = arrayitoa(x);
+ if (cx == XXUNDCL) {
+ n = 0;
+ v = 0;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ } else {
+ p = (char **)malloc(sizeof(char **)*(n+1));
+ if (!p) {
+ printf("?Memory allocation error\n");
+ return(-9);
+ }
+ v = 0; /* Highest initialized member */
+ p[0] = NULL; /* Element 0 */
+ keepallchars = 1;
+ while (n > 0 && v < n) { /* Parse initializers */
+ p[v+1] = NULL;
+ ckmakxmsg(tmp,
+ 64,
+ "Initial value for \\&",
+ ckctoa((char)x),
+ "[",
+ ckitoa(v+1),
+ "]",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+
+ rc = cmfld((char *)tmp,"",&s,xxstring); /* Get field */
+ if (rc < 0) { /* Error... */
+ if (rc == -3) { /* Empty element */
+ if (cmflgs == 1) /* because end of line? */
+ break; /* Yes, done initializing */
+ else /* No, it's just empty */
+ continue; /* Go on to next one. */
+ } else { /* Other parse error */
+ goto dclx; /* Go free temp pointers */
+ }
+ }
+ rc = 1;
+ if (v == 0 && !strcmp(s,"=")) /* Skip the = sign. */
+ continue;
+ s = brstrip(s); /* Strip any braces */
+ makestr(&(p[++v]),s);
+ }
+ keepallchars = 0;
+ if ((y = cmtxt("Carriage return to confirm","",&s,NULL)) < 0)
+ return(y);
+ if (isdynamic)
+ n = v;
+ }
+ if (dclarray((char)x,n) < 0) { /* Declare the array */
+ printf("?Declare failed\n");
+ goto dclx;
+ }
+ for (i = 1; i <= v; i++) { /* Add any initial values */
+ tmp[0] = '&';
+ ckmakmsg(&tmp[1],63,ckctoa((char)x),"[",ckitoa(i),"]");
+ if (addmac(tmp,p[i]) < 0) {
+ printf("Array initialization error: %s %s\n",tmp,p[i]);
+ rc = -9;
+ goto dclx;
+ }
+ }
+ dclx:
+ if (p) {
+ for (i = 1; i <= v; i++)
+ if (p[i]) free(p[i]);
+ free((char *)p);
+ }
+ debug(F101,"DCL rc","",rc);
+ return(success = rc);
+}
+
+static int
+rszarray() {
+ int i, x, y, n, lo, hi, islink = -1;
+ char c, * s, ** ap = NULL;
+ if ((x = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */
+ if (x == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of name */
+ s = line;
+ x = arraybounds(s,&lo,&hi);
+ if (x < 0) { /* Parse the name, get index */
+ printf("?Bad array reference - \"%s\"\n", s);
+ return(-9);
+ }
+ if (lo < 0 && hi < 0) {
+ y = cmnum("New size","",10,&lo,xxstring);
+ if (y < 0) {
+ if (y == -3)
+ printf("?New size required\n");
+ return(y);
+ }
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if (a_link[x] > -1) { /* Link? */
+ islink = x; /* Yes follow it */
+ x = a_link[x]; /* and remember */
+ }
+ if (!a_ptr[x]) {
+ printf("?Array not declared - \"%s\"\n", s);
+ return(-9);
+ }
+ if (lo < 0) {
+ printf("?New size required\n");
+ return(-9);
+ }
+ if (hi > -1) {
+ printf("?Array segments not allowed for this operation\n");
+ return(-9);
+ }
+ c = arrayitoa(x); /* Get array letter */
+ if (c == '@') { /* Argument vector array off limits */
+ printf("?Sorry, \\&@[] is read-only\n");
+ return(-9);
+ }
+ if (lo == 0) { /* If new size is 0... */
+ dclarray(c,0); /* Undeclare the array */
+ return(success = 1);
+ }
+ n = a_dim[x]; /* Current size */
+ ap = (char **) malloc((lo+1) * sizeof(char *)); /* New array */
+ y = (n < lo) ? n : lo;
+ for (i = 0; i <= y; i++) /* Copy the part that fits */
+ ap[i] = a_ptr[x][i];
+ if (n < lo) { /* If original array smaller */
+ for (; i <= lo; i++) /* initialize extra elements in */
+ ap[i] = NULL; /* new array to NULL. */
+ } else if (n > lo) { /* If new array smaller */
+ for (; i <= lo; i++) /* deallocate leftover elements */
+ makestr(&(a_ptr[x][i]),NULL); /* from original array. */
+ }
+ free((char *)a_ptr[x]); /* Free original array list */
+ a_ptr[x] = ap; /* Replace with new one */
+ a_dim[x] = lo; /* Record the new dimension */
+ if (islink > -1) { /* Was this a link? */
+ a_ptr[islink] = ap; /* If so point to the resized array */
+ a_dim[islink] = lo;
+ } else { /* If not are there links to here? */
+ for (i = 0; i < (int) 'z' - ARRAYBASE; i++) { /* Any linked arrays? */
+ if (i != x && a_link[i] == x) { /* Find and update them */
+ a_ptr[i] = ap;
+ a_dim[i] = lo;
+ }
+ }
+ }
+ return(success = 1);
+}
+
+static int
+copyarray() {
+ int i, j, x1, lo1, hi1, x2, lo2, hi2, whole = 0;
+ char c1, c2, * a1, * a2;
+ if ((y = cmfld("Name of source array","",&s,NULL)) < 0)
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ a1 = line;
+ if ((x1 = arraybounds(a1,&lo1,&hi1)) < 0) {
+ printf("?Bad array reference - \"%s\"\n", a1);
+ return(-9);
+ } else if (!a_ptr[x1]) {
+ printf("?Array not declared - \"%s\"\n", a1);
+ return(-9);
+ }
+ c1 = arrayitoa(x1);
+
+ if ((y = cmfld("Name of destination array","",&s,NULL)) < 0)
+ return(y);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ a2 = tmpbuf;
+ if ((x2 = arraybounds(a2,&lo2,&hi2)) < 0) {
+ printf("?Bad array reference - \"%s\"\n", a2);
+ return(-9);
+ }
+ c2 = arrayitoa(x2);
+
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ if (c2 == '@') { /* Argument vector array off limits */
+ printf("?Sorry, \\&@[] is read-only\n");
+ return(-9);
+ }
+ if (lo1 < 0 && lo2 < 0 && hi1 < 0 && hi2 < 0) /* Special case for */
+ whole = 1; /* whole array... */
+
+ if (lo1 < 0) lo1 = whole ? 0 : 1; /* Supply lower bound of source */
+ if (hi1 < 0) hi1 = a_dim[x1]; /* Supply upper bound of source */
+ if (lo2 < 0) lo2 = whole ? 0 : 1; /* Lower bound of target */
+ if (hi2 < 0) hi2 = lo2 + hi1 - lo1; /* Upper bound of target */
+ if (a_ptr[x2]) { /* Target array is already declared? */
+ if (hi2 > a_dim[x2]) /* If upper bound out of range */
+ hi2 = a_dim[x2]; /* shrink to fit */
+ } else { /* Otherwise... */
+ x2 = dclarray(c2, hi2); /* declare the target array */
+ }
+ for (i = lo1, j = lo2; i <= hi1 && j <= hi2; i++,j++) { /* Copy */
+ makestr(&(a_ptr[x2][j]),a_ptr[x1][i]);
+ }
+ return(success = 1);
+}
+
+static int /* Undeclare an array */
+unarray() {
+ int x, y, n, rc = 0;
+ char c, * s;
+
+ if ((y = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */
+ if (y == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of name */
+ s = line;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if ((x = arraybounds(s,&y,&n)) < 0) { /* Parse the name, get index */
+ printf("?Bad array reference - \"%s\"\n", s);
+ return(-9);
+ }
+ if (y > 0 || n > 0) {
+ printf("?Partial arrays can not be destroyed\n");
+ return(-9);
+ }
+ c = arrayitoa(x); /* Get array letter */
+ if (a_ptr[x]) { /* If array is declared */
+ if (c == '@') { /* Argument vector array off limits */
+ printf("?Sorry, \\&@[] is read-only\n");
+ return(-9);
+ }
+ rc = dclarray(c,-1); /* Undeclare the array */
+ } else /* It wasn't declared */
+ rc = 1;
+ if (rc > -1) { /* Set return code and success */
+ success = 1;
+ rc = 1;
+ } else {
+ success = 0;
+ printf("?Failed - destroy \"\\&%c[]\"\n", c);
+ rc = -9;
+ }
+ return(rc);
+}
+
+static int
+clrarray(cx) int cx; {
+ int i, x, lo, hi;
+ char c, * s, * val = NULL;
+
+ if ((x = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */
+ if (x == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of name */
+ s = line;
+ if (cx == ARR_SET) { /* SET */
+ if ((x = cmtxt("Value","",&val,xxstring)) < 0)
+ return(x);
+ ckstrncpy(tmpbuf,val,TMPBUFSIZ); /* Value to set */
+ val = tmpbuf;
+ if (!*val) val = NULL;
+ } else if ((x = cmcfm()) < 0) /* CLEAR */
+ return(x);
+
+ if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Parse the name */
+ printf("?Bad array reference - \"%s\"\n", s);
+ return(-9);
+ }
+ c = arrayitoa(x); /* Get array letter */
+ if (!a_ptr[x]) { /* If array is declared */
+ printf("?Array %s is not declared\n", s);
+ return(-9);
+ } else if (c == '@') { /* Argument vector array off limits */
+ printf("?Sorry, \\&@[] is read-only\n");
+ return(-9);
+ }
+ if (lo < 0) lo = 0;
+ if (hi < 0) hi = a_dim[x];
+ for (i = lo; i <= hi; i++) /* Clear/Set selected range */
+ makestr(&(a_ptr[x][i]),val);
+
+ return(success = 1);
+}
+
+extern char **aa_ptr[CMDSTKL][28];
+extern int aa_dim[CMDSTKL][28];
+
+static int /* Create symbolic link to an array */
+linkarray() {
+ int i = 0, x, y, lo, hi, flag = 0;
+ char c, * s, * p;
+
+ if ((x = cmfld("Array name not currently in use","",&s,NULL)) < 0) {
+ if (x == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of link name */
+ s = line;
+ if ((x = cmfld("Name of existing array","",&p,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Array name required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(tmpbuf,p,TMPBUFSIZ); /* Make safe copy of array name */
+ p = tmpbuf;
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Parse the link name */
+ printf("?Bad array reference - \"%s\"\n", s);
+ return(-9);
+ }
+ if (a_ptr[x]) { /* Must not already exist */
+ c = arrayitoa(x);
+ printf("?Array already exists: \\&%c[]\n", c);
+ return(-9);
+ }
+ if (lo > -1 || hi > -1) {
+ printf("?Sorry, whole arrays only: %s\n",s);
+ return(-9);
+ }
+ if ((y = arraybounds(p,&lo,&hi)) < 0) { /* Parse the array name */
+ printf("?Bad array reference - \"%s\"\n", s);
+ return(-9);
+ }
+ if (lo > -1 || hi > -1) {
+ printf("?Sorry, whole arrays only: %s\n",p);
+ return(-9);
+ }
+ if (x == y) {
+ for (i = cmdlvl; i >= 0; i--)
+ if (aa_ptr[i][x]) {
+ flag++;
+ break;
+ }
+ }
+ if (flag) {
+ a_ptr[x] = aa_ptr[i][y]; /* Link to saved copy */
+ a_dim[x] = aa_dim[i][y];
+ } else { /* Otherwise... */
+ c = arrayitoa(y); /* Check if it's declared */
+ if (!a_ptr[y]) {
+ printf("?Array is not declared: \\&%c[]\n", c);
+ return(-9);
+ }
+ if (a_link[y] > -1) { /* And if it's a link itself */
+ printf("?Links to links not allowed: \\&%c[]\n", c);
+ return(-9);
+ }
+ a_ptr[x] = a_ptr[y]; /* All OK, make the link */
+ a_dim[x] = a_dim[y];
+ }
+ a_link[x] = y;
+ return(success = 1);
+}
+#endif /* NOSPL */
+
+#ifndef NOCSETS
+static char * dcsetname = NULL;
+
+/* Get Display Character-Set Name */
+
+char *
+getdcset() {
+ char * s;
+ int y;
+#ifdef PCFONTS
+ extern int tt_font, ntermfont;
+ extern struct keytab term_font[];
+#endif /* PCFONTS */
+
+ s = "";
+#ifdef OS2
+ y = os2getcp(); /* Default is current code page */
+ switch (y) {
+ case 437: s = "cp437"; break;
+ case 850: s = "cp850"; break;
+ case 852: s = "cp852"; break;
+ case 857: s = "cp857"; break;
+ case 858: s = "cp858"; break;
+ case 862: s = "cp862"; break;
+ case 866: s = "cp866"; break;
+ case 869: s = "cp869"; break;
+ case 1250: s = "cp1250"; break;
+ case 1251: s = "cp1251"; break;
+ case 1252: s = "cp1252"; break;
+ case 1253: s = "cp1253"; break;
+ case 1254: s = "cp1254"; break;
+ case 1255: s = "cp1255"; break;
+ case 1256: s = "cp1256"; break;
+ case 1257: s = "cp1257"; break;
+ case 1258: s = "cp1258"; break;
+ }
+#ifdef PCFONTS
+/*
+ If the user has loaded a font with SET TERMINAL FONT then we want
+ to change the default code page to the font that was loaded.
+*/
+ if (tt_font != TTF_ROM) {
+ for (y = 0; y < ntermfont; y++ ) {
+ if (term_font[y].kwval == tt_font) {
+ s = term_font[y].kwd;
+ break;
+ }
+ }
+ }
+#endif /* PCFONTS */
+#else /* OS2 */
+#ifdef COMMENT
+ /* Hack not needed as of C-Kermit 7.1 */
+ if (fcharset == FC_1LATIN) {
+ s = "latin1-iso"; /* Hack to avoid reporting "cp1252" */
+ } else { /* Report current file character set */
+#endif /* COMMENT */
+ for (y = 0; y <= nfilc; y++)
+ if (fcstab[y].kwval == fcharset) {
+ s = fcstab[y].kwd;
+ break;
+ }
+#ifdef COMMENT
+ }
+#endif /* COMMENT */
+#endif /* OS2 */
+ makestr(&dcsetname,s); /* Return stable pointer */
+ return((char *)dcsetname);
+}
+#endif /* NOCSETS */
+
+#ifndef NOFRILLS
+static int
+doclear() {
+ if ((x = cmkey(clrtab,nclear,"item to clear",
+#ifdef NOSPL
+ "device-buffer"
+#else
+ "device-and-input"
+#endif /* NOSPL */
+ ,xxstring)) < 0) return(x);
+#ifndef NOSPL
+#ifdef OS2
+ if (x == CLR_CMD || x == CLR_TRM) {
+ if ((z = cmkey(clrcmdtab,nclrcmd,"how much screen to clear\n",
+ "all",xxstring)) < 0)
+ return(z);
+ }
+#endif /* OS2 */
+#endif /* NOSPL */
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+ /* Clear device input buffer if requested */
+ y = (x & CLR_DEV) ? ttflui() : 0;
+
+ if (x & CLR_SCR) /* CLEAR SCREEN */
+ y = ck_cls(); /* (= SCREEN CLEAR = CLS) */
+
+ if (x & CLR_KBD) { /* CLEAR KEYBOARD */
+ int n;
+ n = conchk();
+ y = 0;
+ while (n-- > 0 && (y = coninc(0) > -1))
+ ;
+ y = (y > -1) ? 0 : -1;
+ }
+
+#ifndef NOSPL
+ /* Clear INPUT command buffer if requested */
+ if (x & CLR_INP) {
+ for (z = 0; z < inbufsize; z++)
+ inpbuf[z] = NUL;
+ inpbp = inpbuf;
+ y = 0;
+ }
+#ifdef CK_APC
+ if (x & CLR_APC) {
+ debug(F101,"Executing CLEAR APC","",apcactive);
+ apcactive = 0;
+ y = 0;
+ }
+#endif /* CK_APC */
+ if (x & CLR_ALR) {
+ setalarm(0L);
+ y = 0;
+ }
+#endif /* NOSPL */
+
+#ifdef PATTERNS
+ if (x & (CLR_TXT|CLR_BIN)) {
+ int i;
+ for (i = 0; i < FTPATTERNS; i++) {
+ if (x & CLR_TXT)
+ makestr(&txtpatterns[i],NULL);
+ if (x & CLR_BIN)
+ makestr(&binpatterns[i],NULL);
+ }
+ y = 0;
+ }
+#endif /* PATTERNS */
+
+#ifndef NODIAL
+ if (x & CLR_DIA) {
+ dialsta = DIA_UNK;
+ y = 0;
+ }
+#endif /* NODIAL */
+
+#ifndef NOMSEND
+ if (x & CLR_SFL) { /* CLEAR SEND-LIST */
+ if (filehead) {
+ struct filelist * flp, * next;
+ flp = filehead;
+ while (flp) {
+ if (flp->fl_name)
+ free(flp->fl_name);
+ if (flp->fl_alias)
+ free(flp->fl_alias);
+ next = flp->fl_next;
+ free((char *)flp);
+ flp = next;
+ }
+ }
+ filesinlist = 0;
+ filehead = NULL;
+ filetail = NULL;
+ addlist = 0;
+ y = 0;
+ }
+#endif /* NOMSEND */
+
+#ifdef OS2
+#ifndef NOLOCAL
+ switch (x) {
+ case CLR_SCL:
+ clearscrollback(VTERM);
+ break;
+ case CLR_CMD:
+ switch ( z ) {
+ case CLR_C_ALL:
+ clear();
+ break;
+ case CLR_C_BOS:
+ clrboscr_escape(VCMD,SP);
+ break;
+ case CLR_C_BOL:
+ clrbol_escape(VCMD,SP);
+ break;
+ case CLR_C_EOL:
+ clrtoeoln(VCMD,SP);
+ break;
+ case CLR_C_EOS:
+ clreoscr_escape(VCMD,SP);
+ break;
+ case CLR_C_LIN:
+ clrline_escape(VCMD,SP);
+ break;
+ case CLR_C_SCR:
+ clearscrollback(VCMD);
+ break;
+ default:
+ printf("Not implemented yet, sorry.\n");
+ break;
+ }
+ break;
+
+#ifndef NOTERM
+ case CLR_TRM:
+ switch ( z ) {
+ case CLR_C_ALL:
+ if (VscrnGetBufferSize(VTERM) > 0 ) {
+ VscrnScroll(VTERM, UPWARD, 0,
+ VscrnGetHeight(VTERM)-(tt_status[VTERM]?2:1),
+ VscrnGetHeight(VTERM) -
+ (tt_status[VTERM]?1:0), TRUE, SP
+ );
+ cleartermscreen(VTERM);
+ }
+ break;
+ case CLR_C_BOS:
+ clrboscr_escape(VTERM,SP);
+ break;
+ case CLR_C_BOL:
+ clrbol_escape(VTERM,SP);
+ break;
+ case CLR_C_EOL:
+ clrtoeoln(VTERM,SP);
+ break;
+ case CLR_C_EOS:
+ clreoscr_escape(VTERM,SP);
+ break;
+ case CLR_C_LIN:
+ clrline_escape(VTERM,SP);
+ break;
+ case CLR_C_SCR:
+ clearscrollback(VTERM);
+ break;
+ default:
+ printf("Not implemented yet, sorry.\n");
+ break;
+ }
+ break;
+#endif /* NOTERM */
+ }
+ y = 0;
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ return(success = (y == 0));
+}
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+static int
+doeval(cx) int cx; {
+ char *p;
+ char vnambuf[VNAML], * vnp = NULL; /* These must be on the stack */
+ if (!oldeval) {
+ if ((y = cmfld("Variable name","",&s,
+ ((cx == XX_EVAL) ? xxstring : NULL))) < 0) {
+ if (y == -3) {
+ printf("?Variable name required\n");
+ return(-9);
+ } else return(y);
+ }
+ ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */
+ vnp = vnambuf;
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&z)) < 0)
+ return(y);
+ }
+ }
+ if ((x = cmtxt("Integer arithmetic expression","",&s,xxstring)) < 0)
+ return(x);
+ p = evala(s);
+ if (!p) p = "";
+ if (oldeval && *p)
+ printf("%s\n", p);
+ ckstrncpy(evalbuf,p,32);
+ if (!oldeval)
+ return(success = addmac(vnambuf,p));
+ else
+ return(success = *p ? 1 : 0);
+}
+#endif /* NOSPL */
+
+#ifdef TNCODE
+static int
+dotelopt() {
+ if ((x = cmkey(telcmd, ntelcmd, "TELNET command", "", xxstring)) < 0 )
+ return(x);
+ switch (x) {
+ case WILL:
+ case WONT:
+ case DO:
+ case DONT:
+ if ((y = cmkey(tnopts,ntnopts,"TELNET option","",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0) return(z);
+
+ switch (x) {
+ case WILL:
+ if (TELOPT_UNANSWERED_WILL(y))
+ return(success = 0);
+ break;
+ case WONT:
+ if (TELOPT_UNANSWERED_WONT(y))
+ return(success = 0);
+ break;
+ case DO:
+ if (TELOPT_UNANSWERED_DO(y))
+ return(success = 0);
+ break;
+ case DONT:
+ if (TELOPT_UNANSWERED_DONT(y))
+ return(success = 0);
+ break;
+ }
+ if (local) {
+ success = ((tn_sopt(x,y) > -1) ? 1 : 0);
+ } else {
+ printf("ff%02x%02x\n",x,y);
+ success = 1;
+ }
+ if (success) {
+ switch (x) {
+ case WILL:
+ TELOPT_UNANSWERED_WILL(y) = 1;
+ break;
+ case WONT:
+ if ( TELOPT_ME(y) )
+ TELOPT_UNANSWERED_WONT(y) = 1;
+ break;
+ case DO:
+ TELOPT_UNANSWERED_DO(y) = 1;
+ break;
+ case DONT:
+ if ( TELOPT_ME(y) )
+ TELOPT_UNANSWERED_DONT(y) = 1;
+ break;
+ }
+ if (tn_wait("XXTELOP") < 0) {
+ tn_push();
+ success = 0;
+ }
+ }
+ return(success);
+ case SB:
+ if ((y=cmkey(tnsbopts,ntnsbopts,"TELNET option","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TELOPT_NAWS:
+ /* Some compilers require switch() to have at least 1 case */
+#ifdef CK_NAWS
+ TELOPT_SB(TELOPT_NAWS).naws.x = 0;
+ TELOPT_SB(TELOPT_NAWS).naws.y = 0;
+ if (local)
+ return(success = ((tn_snaws() > -1) ? 1 : 0));
+ else
+ return(success = 0);
+#else
+ return(success = 0);
+#endif /* CK_NAWS */
+ }
+ return(success = 0);
+
+#ifdef CK_KERBEROS
+#ifdef KRB5
+ case TN_FWD:
+ success = (kerberos5_forward() == AUTH_SUCCESS);
+ return(success);
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+ default:
+ if ((z = cmcfm()) < 0) return(z);
+#ifndef NOLOCAL
+ if (local) {
+ CHAR temp[3];
+ if (network && IS_TELNET()) { /* TELNET */
+ temp[0] = (CHAR) IAC;
+ temp[1] = x;
+ temp[2] = NUL;
+ success = (ttol((CHAR *)temp,2) > -1 ? 1 : 0);
+ if (tn_deb || debses || deblog) {
+ /* TN_MSG_LEN is in ckctel.h */
+ ckmakmsg(tn_msg,256,"TELNET SENT ",TELCMD(x),NULL,NULL);
+ debug(F101,tn_msg,"",x);
+ if (debses || tn_deb) tn_debug(tn_msg);
+ }
+ return(success);
+ }
+ return(success = 0);
+ } else {
+#endif /* NOLOCAL */
+ printf("ff%02x\n",x);
+ return(success = 1);
+#ifndef NOLOCAL
+ }
+#endif /* NOLOCAL */
+ }
+}
+#endif /* TNCODE */
+
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+static int
+doedit() {
+#ifdef OS2
+ char * p = NULL;
+#endif /* OS2 */
+ if (!editor[0]) {
+ s = getenv("EDITOR");
+ if (s) ckstrncpy(editor,s,CKMAXPATH);
+ editor[CKMAXPATH] = NUL;
+ if (!editor[0]) {
+ printf("?Editor not defined - use SET EDITOR to define\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(tmpbuf,editfile,TMPBUFSIZ);
+/*
+ cmiofi() lets us parse the name of an existing file, or the name of
+ a nonexistent file to be created.
+*/
+ x = cmiofi("File to edit", (char *)tmpbuf, &s, &y, xxstring);
+ debug(F111,"edit",s,x);
+ if (x < 0 && x != -3)
+ return(x);
+ if (x == -3) {
+ tmpbuf[0] = NUL;
+ } else {
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ if (y) {
+ printf("?A single file please\n");
+ return(-9);
+ }
+ if (nopush) {
+ printf("?Sorry, editing not allowed\n");
+ return(success = 0);
+ }
+ if (tmpbuf[0]) {
+ /* Get full path in case we change directories between EDIT commands */
+ zfnqfp(tmpbuf, CKMAXPATH, editfile);
+ editfile[CKMAXPATH] = NUL;
+#ifdef OS2
+ p = editfile; /* Flip the stupid slashes */
+ while (*p) {
+ if (*p == '/') *p = '\\';
+ p++;
+ }
+#endif /* OS2 */
+ } else
+ editfile[0] = NUL;
+ if (editfile[0]) {
+ if (zchki(editfile) < (CK_OFF_T)0 && zchko(editfile) < 0) {
+ printf("?Access denied: %s\n",editfile);
+ return(-9);
+ }
+ }
+ x = 0;
+ if (editopts[0]) {
+#ifdef OS2
+ x = ckindex("%1",(char *)editopts,0,0,1);
+ if (x > 0)
+ editopts[x] = 's';
+ else
+#endif /* OS2 */
+ x = ckindex("%s",(char *)editopts,0,0,1);
+ }
+ if (((int)strlen(editopts) + (int)strlen(editfile) + 1) < TMPBUFSIZ) {
+ if (x)
+ sprintf(tmpbuf,editopts,editfile);
+ else
+ sprintf(tmpbuf,"%s %s",editopts,editfile);
+ }
+ s = line;
+ ckmakmsg(s,LINBUFSIZ,editor," ",tmpbuf,NULL);
+#ifdef OS2
+ p = s + strlen(editor); /* And again with the slashes */
+ while (p != s) {
+ if (*p == '/') *p = '\\';
+ p--;
+ }
+#endif /* OS2 */
+ conres();
+ x = zshcmd(s);
+ concb((char)escape);
+ return(x);
+}
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifdef BROWSER
+static int
+dobrowse() {
+#ifdef OS2
+ char * p = NULL;
+#endif /* OS2 */
+ if (nopush) {
+ printf("?Sorry, browsing not allowed\n");
+ return(success = 0);
+ }
+#ifndef NT
+ /* Windows lets the Shell Execute the URL if no Browser is defined */
+ if (!browser[0]) {
+ s = getenv("BROWSER");
+ if (s) ckstrncpy(browser,s,CKMAXPATH);
+ browser[CKMAXPATH] = NUL;
+ if (!browser[0]) {
+ printf("?Browser not defined - use SET BROWSER to define\n");
+ return(-9);
+ }
+ }
+#endif /* NT */
+ ckstrncpy(tmpbuf,browsurl,TMPBUFSIZ);
+ if ((x = cmtxt("URL",(char *)browsurl,&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(browsurl,s,4096);
+ x = 0;
+ if (browsopts[0]) {
+#ifdef OS2
+ x = ckindex("%1",(char *)browsopts,0,0,1);
+ if (x > 0)
+ browsopts[x] = 's';
+ else
+#endif /* OS2 */
+ x = ckindex("%s",(char *)browsopts,0,0,1);
+ }
+ if (((int)strlen(browsopts) + (int)strlen(browsurl) + 1) < TMPBUFSIZ) {
+ if (x)
+ sprintf(tmpbuf,browsopts,browsurl);
+ else
+ sprintf(tmpbuf,"%s %s",browsopts,browsurl);
+ }
+#ifdef NT
+ if (!browser[0])
+ return(success = Win32ShellExecute(browsurl));
+#endif /* NT */
+ s = line;
+ ckmakmsg(s,LINBUFSIZ,browser," ",tmpbuf,NULL);
+#ifdef OS2
+ p = line + strlen(browser); /* Flip slashes */
+ while (p != line) {
+ if (*p == '/') *p = '\\';
+ p--;
+ }
+#endif /* OS2 */
+ conres();
+ x = zshcmd(s);
+ concb((char)escape);
+ return(x);
+}
+#endif /* BROWSER */
+
+#ifdef CK_RECALL
+static int
+doredo() { /* Find a previous cmd and redo it */
+ extern int on_recall, in_recall;
+ int x;
+ char * p;
+
+ if ((x = cmtxt(
+"pattern, or first few characters of a previous command",
+ "*",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ x = strlen(s);
+ s = line;
+ if (*s == '{') { /* Braces disable adding * to end */
+ if (s[x-1] == '}') {
+ s[x-1] = NUL;
+ s++;
+ x--;
+ }
+ } else { /* No braces, add * to end. */
+ s[x] = '*';
+ s[x+1] = NUL;
+ }
+
+ while (x > 0 && s[x] == '*' && s[x-1] == '*') s[x--] = NUL;
+
+ if (!on_recall || !in_recall) {
+ printf("?Sorry, command recall can't be used now.\n");
+ return(-9);
+ }
+ if ((p = cmgetcmd(s))) { /* Look for it history buffer */
+ ckmakmsg(cmdbuf,CMDBL,p,"\r",NULL,NULL); /* Copy to command buffer */
+ if (!quiet) /* Echo it */
+ printf("%s\n",cmdbuf);
+ cmaddnext(); /* Force re-add to history buffer */
+ return(cmflgs = -1); /* Force reparse */
+ } else {
+ printf("?Sorry - \"%s\" not found\n", s);
+ return(-9);
+ }
+}
+#endif /* CK_RECALL */
+
+#ifndef NOXFER
+#ifndef NOCSETS
+static int
+doassoc() { /* ASSOCIATE */
+ extern struct keytab tcstab[];
+ extern int ntcs;
+ if ((x = cmkey(assoctab, nassoc, "", "", xxstring)) < 0 )
+ return(x);
+
+ switch (x) { /* Associate what? */
+
+ case ASSOC_TC: /* Transfer character-set... */
+ if ((x = cmkey(tcstab, ntcs,
+ "transfer character-set name","",xxstring)) < 0)
+ return(x);
+ if ((y = cmkey(fcstab, nfilc,
+ "with file character-set","", xxstring)) < 0)
+ if (y != -3)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ axcset[x] = y;
+ return(success = 1);
+
+ case ASSOC_FC: /* File character-set... */
+ if ((x = cmkey(fcstab, nfilc,
+ "file character-set name","",xxstring)) < 0)
+ return(x);
+ if ((y = cmkey(tcstab, ntcs,
+ "with transfer character-set","", xxstring)) < 0)
+ if (y != -3)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ afcset[x] = y;
+ return(success = 1);
+
+ default:
+ return(-2);
+ }
+}
+#endif /* NOCSETS */
+#endif /* NOXFER */
+
+#ifndef NOHELP
+static int
+domanual() {
+#ifdef OS2
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (nopush) {
+ printf("?Sorry, access to system commands is disabled.\n");
+ return(-9);
+ }
+ y = mxlook(mactab,"manual",nmac);
+ if (y > -1) {
+ z = maclvl; /* Save the current maclvl */
+ dodo(y,NULL,cmdstk[cmdlvl].ccflgs); /* Run the macro */
+ while (maclvl > z) {
+ debug(F101,"XXMAN loop maclvl 1","",maclvl);
+ sstate = (CHAR) parser(1);
+ debug(F101,"XXMAN loop maclvl 2","",maclvl);
+ if (sstate) proto();
+ }
+ debug(F101,"XXMAN loop exit maclvl","",maclvl);
+ return(success);
+ }
+ return(success = 0);
+#else
+ if ((x = cmtxt(
+#ifdef UNIX
+ "Carriage return to confirm the command, or manual topic",
+#else
+ "Carriage return to confirm the command, or help topic",
+#endif /* UNIX */
+ "kermit",
+ &s,
+ xxstring
+ )
+ ) < 0)
+ return(x);
+#endif /* OS2 */
+
+#ifdef UNIX
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"man ",s,NULL,NULL);
+#else
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"help ",s,NULL,NULL);
+#endif /* UNIX */
+ debug(F110,"MANUAL",tmpbuf,0);
+ if (nopush) {
+ printf("?Sorry, access to system commands is disabled.\n");
+ return(-9);
+ } else {
+ conres(); /* Restore the console */
+ success = zshcmd(tmpbuf);
+ concb((char)escape); /* Restore CBREAK mode */
+ return(success);
+ }
+}
+#endif /* NOHELP */
+
+#ifndef NOHTTP
+#ifdef TCPSOCKET
+static struct keytab sslswtab[] = {
+ { "/ssl", 1, 0 },
+ { "/tls", 1, 0 }
+};
+
+#ifndef NOURL
+struct urldata http_url = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+#endif /* NOURL */
+
+static int
+dohttp() { /* HTTP */
+ struct FDB sw, kw, fi;
+ int n, getval, allinone = 0;
+ char c, * p;
+ char rdns[128];
+
+ char * http_agent = NULL; /* Parse results */
+ char * http_hdr = NULL;
+ char * http_user = NULL;
+ char * http_pass = NULL;
+ char * http_mime = NULL;
+ char * http_lfile = NULL;
+ char * http_rfile = NULL;
+ char * http_dfile = NULL;
+ char http_array = NUL;
+ int http_action = -1;
+
+ char * http_host = NULL;
+ char * http_srv = NULL;
+ int http_ssl = 0;
+
+ static char * http_d_agent = NULL;
+ static char * http_d_user = NULL;
+ static char * http_d_pass = NULL;
+
+ static int http_d_type = 0;
+ int http_type = http_d_type;
+
+#ifdef OS2
+ p = "Kermit 95"; /* Default user agent */
+#else
+ p = "C-Kermit";
+#endif /* OS2 */
+ makestr(&http_agent,p);
+ makestr(&http_mime,"text/HTML"); /* MIME type default */
+ rdns[0] = '\0';
+
+ cmfdbi(&sw, /* 1st FDB - general switches */
+ _CMKEY, /* fcode */
+ "OPEN, CLOSE, GET, HEAD, PUT, INDEX, or POST,\n or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nhttpswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ httpswtab, /* Keyword table */
+ &kw /* Pointer to next FDB */
+ );
+ cmfdbi(&kw, /* 2nd FDB - commands */
+ _CMKEY, /* fcode */
+ "Command", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nhttptab, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ httptab, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+
+ while (1) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) /* Error */
+ goto xhttp;
+ n = cmresult.nresult;
+ if (cmresult.fdbaddr == &kw) /* Command - exit this loop */
+ break;
+ c = cmgbrk(); /* Switch... */
+ getval = (c == ':' || c == '=');
+ x = -9;
+ if (getval && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ goto xhttp;
+ }
+ switch (cmresult.nresult) { /* Handle each switch */
+ case HT_SW_TP: /* /TOSCREEN */
+ http_type = 1;
+ break;
+ case HT_SW_AG: /* /AGENT */
+ if (getval) {
+ if ((x = cmfld("User agent",p,&s,xxstring)) < 0)
+ goto xhttp;
+ } else {
+ s = p;
+ }
+ makestr(&http_agent,s);
+ break;
+ case HT_SW_HD: /* /HEADER */
+ s = NULL;
+ if (getval) {
+ if ((x = cmfld("Header line","",&s,xxstring)) < 0) {
+ if (x == -3)
+ s = NULL;
+ else
+ goto xhttp;
+ }
+ }
+ makestr(&http_hdr,s);
+ break;
+ case HT_SW_US: /* /USER */
+ s = NULL;
+ if (getval) {
+ if ((x = cmfld("User ID","",&s,xxstring)) < 0) {
+ if (x == -3)
+ s = "";
+ else
+ goto xhttp;
+ }
+ }
+ makestr(&http_user,s);
+ break;
+ case HT_SW_PW: /* /PASSWORD */
+ debok = 0;
+ s = NULL;
+ if (getval) {
+ if ((x = cmfld("Password","",&s,xxstring)) < 0)
+ goto xhttp;
+ }
+ makestr(&http_pass,s);
+ break;
+#ifndef NOSPL
+ case HT_SW_AR: { /* /ARRAY: */
+ char * s2, array = NUL;
+ if (!getval) {
+ printf("?This switch requires an argument\n");
+ x = -9;
+ goto xhttp;
+ }
+ if ((x = cmfld("Array name (a single letter will do)",
+ "",
+ &s,
+ NULL
+ )) < 0) {
+ if (x == -3) {
+ printf("?Array name required\n");
+ x = -9;
+ goto xhttp;
+ } else
+ goto xhttp;
+ }
+ if (!*s) {
+ printf("?Array name required\n");
+ x = -9;
+ goto xhttp;
+ }
+ s2 = s;
+ if (*s == CMDQ) s++;
+ if (*s == '&') s++;
+ if (!isalpha(*s)) {
+ printf("?Bad array name - \"%s\"\n",s2);
+ x = -9;
+ goto xhttp;
+ }
+ array = *s++;
+ if (isupper(array))
+ array = tolower(array);
+ if (*s && (*s != '[' || *(s+1) != ']')) {
+ printf("?Bad array name - \"%s\"\n",s2);
+ http_array = NUL;
+ x = -9;
+ goto xhttp;
+ }
+ http_array = array;
+ break;
+ }
+#endif /* NOSPL */
+ default:
+ x = -2;
+ goto xhttp;
+ }
+ }
+ http_action = n; /* Save the action */
+ if (http_action == HTTP_PUT || http_action == HTTP_POS) {
+ cmfdbi(&sw, /* 1st FDB - switch */
+ _CMKEY, /* fcode */
+ "Local filename\n Or switch", /* help */
+ "", /* default */
+ "", /* addtl string data */
+ nhttpptab, /* keyword table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ httpptab, /* Keyword table */
+ &fi /* Pointer to next FDB */
+ );
+ cmfdbi(&fi, /* 2nd FDB - filename */
+ _CMIFI, /* fcode */
+ "Local filename", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ while (1) {
+ x = cmfdb(&sw);
+ if (x < 0)
+ goto xhttp; /* Free any malloc'd temp strings */
+ n = cmresult.nresult;
+ if (cmresult.fcode != _CMKEY)
+ break;
+ c = cmgbrk(); /* Switch... */
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ x = -9;
+ goto xhttp;
+ }
+ switch (n) {
+ case HT_PP_MT:
+ s = "text/HTML";
+ if (getval) {
+ if ((x = cmfld("MIME type",
+ "text/HTML",&s,xxstring)) < 0)
+ goto xhttp;
+ }
+ makestr(&http_mime,s);
+ break;
+ default:
+ x = -2;
+ goto xhttp;
+ }
+ }
+ makestr(&http_lfile,cmresult.sresult);
+ n = ckindex("/",http_lfile,-1,1,0);
+ if (n)
+ p = &http_lfile[n];
+ else
+ p = http_lfile;
+ if ((x = cmfld("URL or remote filename",p,&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?%s what?\n",(http_action == HTTP_PUT) ? "Put" : "Post");
+ x = -9;
+ }
+ goto xhttp;
+ }
+ if (!*s) s = NULL;
+ makestr(&http_rfile,s);
+
+ if ((x = cmtxt("Response filename","",&s,xxstring)) < 0) {
+ if (x != -3)
+ goto xhttp;
+ }
+ if (*s)
+ makestr(&http_dfile,s);
+ }
+ switch (http_action) {
+ case HTTP_DEL: /* DELETE */
+ if ((x = cmfld("URL or remote source file","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Delete what?\n");
+ x = -9;
+ }
+ goto xhttp;
+ }
+ makestr(&http_rfile,s);
+ break;
+ case HTTP_CON: /* CONNECT */
+ if ((x = cmfld("Remote host[:port]","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Remote host[:port] is required\n");
+ x = -9;
+ }
+ goto xhttp;
+ }
+ makestr(&http_rfile,s);
+ break;
+ case HTTP_HED: { /* HEAD */
+ char buf[CKMAXPATH+1];
+ if ((x = cmfld("URL or remote source file","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Head of what?\n");
+ x = -9;
+ }
+ goto xhttp;
+ }
+ makestr(&http_rfile,s);
+
+ if (http_array || http_type) { /* Default result filename */
+ p = ""; /* None if /ARRAY or /TOSCREEN */
+ } else {
+ n = ckindex("/",http_rfile,-1,1,0); /* Otherwise strip path */
+ if (n) /* and add ".head" */
+ p = &http_rfile[n];
+ else
+ p = http_rfile;
+ ckmakmsg(buf,CKMAXPATH,p,".head",NULL,NULL);
+ p = buf;
+ }
+ if ((x = cmofi("Local filename",p,&s,xxstring)) < 0) {
+ if (x != -3)
+ goto xhttp;
+ }
+ makestr(&http_lfile,s);
+ break;
+ }
+ case HTTP_GET: /* GET */
+ case HTTP_IDX: { /* INDEX */
+ extern int wildena;
+ int tmp;
+ char * lfile = "";
+ if ((x = cmfld("URL or remote source file","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Get what?\n");
+ x = -9;
+ }
+ goto xhttp;
+ }
+ makestr(&http_rfile,s);
+ if (http_action == HTTP_GET && !http_type)
+ zstrip(http_rfile,&lfile);
+ /* URLs often contain question marks or other metacharacters */
+ /* cmofi() doesn't like them */
+ tmp = wildena;
+ wildena = 0;
+ if ((x = cmofi("Local filename",lfile,&s,xxstring)) < 0) {
+ wildena = tmp;
+ if (x != -3)
+ goto xhttp;
+ }
+ wildena = tmp;
+ makestr(&http_lfile,s);
+ break;
+ }
+ case HTTP_OPN: {
+ int sslswitch = 0;
+#ifdef CK_SSL
+ struct FDB sw, fl;
+ cmfdbi(&sw,
+ _CMKEY, /* fcode */
+ "IP host name or address, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 2, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ sslswtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 2nd FDB - host */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ x = cmfdb(&sw); /* Parse switch or host */
+ if (x < 0) /* Error */
+ goto xhttp;
+ if (cmresult.fcode == _CMFLD) { /* Host */
+ s = cmresult.sresult; /* Set up expected pointer */
+ goto havehost; /* Go parse rest of command */
+ }
+ sslswitch = 1; /* /SSL or /TLS switch - set flag */
+#endif /* CK_SSL */
+
+ /* Parse host */
+
+ if ((x = cmfld("URL, hostname, or ip-address","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Open what?\n");
+ x = -9;
+ }
+ goto xhttp;
+ }
+
+ havehost: /* Come here with s -> host */
+#ifdef CK_URL
+ x = urlparse(s,&http_url); /* Was a URL given? */
+ if (x < 1) { /* Not a URL */
+#endif /* CK_URL */
+ makestr(&http_host,s);
+ if ((x =
+ cmfld("Service name or port number",
+ sslswitch ? "https" : "http",&s,xxstring)) < 0)
+ goto xhttp;
+ else
+ makestr(&http_srv,s);
+#ifdef CK_URL
+ } else if (ckstrcmp(http_url.svc,"http",-1,0) && /* Non-HTTP URL */
+ ckstrcmp(http_url.svc,"https",-1,0)) {
+ printf("?Non-HTTP URL\n");
+ x = -9;
+ goto xhttp;
+ } else { /* Have HTTP URL */
+ makestr(&http_srv, http_url.svc);
+ makestr(&http_user,http_url.usr);
+ makestr(&http_pass,http_url.psw);
+ makestr(&http_host,http_url.hos);
+ if (http_url.por)
+ makestr(&http_srv,http_url.por);
+ makestr(&http_rfile,http_url.pth);
+ }
+ if (http_rfile) { /* Open, GET, and Close */
+ printf("?Directory/file path not allowed in HTTP OPEN URL\n");
+ x = -9;
+ goto xhttp;
+ }
+ if (!ckstrcmp("https",http_srv,-1,0) || sslswitch ||
+ !ckstrcmp("443",http_srv,-1,0))
+ http_ssl = 1;
+#endif /* CK_URL */
+ break;
+ }
+ case HTTP_CLS:
+ break;
+ }
+ if ((x = cmcfm()) < 0)
+ goto xhttp;
+
+ if (http_action == HTTP_OPN) {
+ x = (http_open(http_host,http_srv,http_ssl,rdns,128,http_agent) == 0);
+ if (x) {
+ if (!quiet) {
+ if (rdns[0])
+ printf("Connected to %s [%s]\r\n",http_host,rdns);
+ else
+ printf("Connected to %s\r\n",http_host);
+ }
+ if (http_agent) {
+ if (http_d_agent)
+ free(http_d_agent);
+ http_d_agent = http_agent;
+ http_agent = NULL;
+ }
+ if (http_user) {
+ if (http_d_user)
+ free(http_d_user);
+ http_d_user = http_user;
+ http_user = NULL;
+ }
+ if (http_pass) {
+ if (http_d_pass) {
+ memset(http_d_pass,0,strlen(http_d_pass));
+ free(http_d_pass);
+ }
+ http_d_pass = http_pass;
+ http_pass = NULL;
+ }
+ http_d_type = http_type;
+ } else {
+ if (!quiet)
+ printf("?HTTP Connection failed.\r\n");
+ }
+ } else if (http_action == HTTP_CLS) {
+ if (http_d_agent) {
+ free(http_d_agent);
+ http_d_agent = NULL;
+ }
+ if (http_d_user) {
+ free(http_d_user);
+ http_d_user = NULL;
+ }
+ if (http_d_pass) {
+ memset(http_d_pass,0,strlen(http_d_pass));
+ free(http_d_pass);
+ http_d_pass = NULL;
+ }
+ http_d_type = 0;
+ x = (http_close() == 0);
+ }
+ if ((http_action != HTTP_CLS) &&
+ (http_action != HTTP_CON) && http_rfile) { /* Remote file is URL? */
+
+ /* All-in-one actions when a URL is given... */
+
+#ifdef CK_URL
+ if (urlparse(http_rfile,&http_url) > 0) { /* Have URL? */
+ if (ckstrcmp(http_url.svc,"http",-1,0) && /* It's an HTTP URL? */
+ ckstrcmp(http_url.svc,"https",-1,0)) {
+ printf("?Non-HTTP URL\n");
+ x = -9;
+ goto xhttp;
+ } else { /* Yes, collect the pieces */
+ makestr(&http_srv, http_url.svc);
+ makestr(&http_user,http_url.usr);
+ makestr(&http_pass,http_url.psw);
+ makestr(&http_host,http_url.hos);
+ if (http_url.por)
+ makestr(&http_srv,http_url.por);
+ makestr(&http_rfile,http_url.pth);
+ }
+ if (!http_rfile) { /* Still have a path? */
+ makestr(&http_rfile,"/");
+ }
+ if (!ckstrcmp("https",http_srv,-1,0) || /* Check for SSL/TLS */
+ !ckstrcmp("443",http_srv,-1,0))
+ http_ssl = 1;
+ if (http_isconnected()) /* Close any open HTTP connection */
+ http_close();
+ if (http_pass == NULL && http_d_pass != NULL)
+ makestr(&http_pass,http_d_pass);
+ x = (http_open(http_host,
+ http_srv,http_ssl,rdns,128,http_d_agent) == 0);
+ if (x < 0) {
+ x = 0;
+ goto xhttp;
+ }
+ allinone = 1;
+ }
+#endif /* CK_URL */
+ if (http_pass == NULL && http_d_pass != NULL)
+ makestr(&http_pass,http_d_pass);
+
+ if (http_action == HTTP_OPN && allinone) {
+ http_action = HTTP_GET;
+ }
+ x = xdohttp(http_action,
+ http_lfile,
+ http_rfile,
+ http_dfile,
+ http_agent ? http_agent : http_d_agent,
+ http_hdr,
+ http_user ? http_user : http_d_user,
+ http_pass ? http_pass : http_d_pass,
+ http_mime,
+ http_array,
+ http_type
+ );
+ if (allinone)
+ x = (http_close() == 0);
+ }
+
+ xhttp:
+ if (http_agent) free(http_agent);
+ if (http_hdr) free(http_hdr);
+ if (http_user) free(http_user);
+ if (http_pass) {
+ memset(http_pass,0,strlen(http_pass));
+ free(http_pass);
+ }
+ if (http_mime) free(http_mime);
+ if (http_lfile) free(http_lfile);
+ if (http_rfile) free(http_rfile);
+ if (http_dfile) free(http_dfile);
+ if (http_host) free(http_host);
+ if (http_srv) free(http_srv);
+
+ if (x > -1)
+ success = x;
+ return(x);
+}
+#endif /* TCPSOCKET */
+#endif /* NOHTTP */
+
+
+#ifndef NOSPL
+static int
+dotrace() {
+ int on = 1;
+ struct FDB sw, kw;
+ cmfdbi(&sw, /* 1st FDB - switch */
+ _CMKEY, /* fcode */
+ "Trace object;\n Or switch", /* help */
+ "", /* default */
+ "", /* addtl string data */
+ 2, /* keyword table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ onoffsw, /* Keyword table */
+ &kw /* Pointer to next FDB */
+ );
+ cmfdbi(&kw, /* 2nd FDB - Trace object */
+ _CMKEY, /* fcode */
+ "Trace object", /* help */
+ "all", /* default */
+ "", /* addtl string data */
+ ntracetab, /* keyword table size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ tracetab, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ if ((x = cmfdb(&sw)) < 0)
+ return(x);
+ if (cmresult.fdbaddr == &sw) {
+ on = cmresult.nresult;
+ if ((x = cmkey(tracetab, ntracetab,"","all",xxstring)) < 0)
+ return(x);
+ } else {
+ x = cmresult.nresult;
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+ switch (x) {
+ case TRA_ASG:
+ tra_asg = on;
+ break;
+ case TRA_CMD:
+ tra_cmd = on;
+ break;
+ case TRA_ALL:
+ tra_asg = on;
+ tra_cmd = on;
+ break;
+ default:
+ return(-2);
+ }
+ printf("TRACE %s\n", on ? "ON" : "OFF");
+ return(success = 1);
+}
+#endif /* NOSPL */
+
+
+static int
+doprompt() {
+ extern int xcmdsrc;
+ if ((x = cmtxt("Optional message","",&s,xxstring)) < 0)
+ return(x);
+#ifdef NOSPL
+ printf("?Sorry, PROMPT requires script programming language\n");
+ return(-9);
+#else
+ debug(F101,"Prompt cmdlvl","",cmdlvl);
+ cmdlvl++;
+ if (cmdlvl > CMDSTKL) {
+ printf("?Command stack overflow: %d\n",cmdlvl);
+ cmdlvl--;
+ return(-9);
+ }
+ xcmdsrc = CMD_KB;
+ cmdstk[cmdlvl].src = CMD_KB; /* Say we're at the prompt */
+ cmdstk[cmdlvl].lvl = 0;
+ cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
+ if (tra_cmd)
+ printf("[%d] +P: \"(prompt)\"\n",cmdlvl);
+ concb((char)escape);
+ if (!quiet)
+ printf(
+"(Recursive command prompt: Resume script with CONTINUE, STOP to stop...)\n"
+ );
+ if (*s) { /* If prompt given */
+ makestr(&(prstring[cmdlvl-1]),cmgetp()); /* Save current prompt */
+ cmsetp(s); /* Set new one */
+ }
+ return(success = 1);
+#endif /* NOSPL */
+}
+
+#ifdef CKLEARN
+VOID
+learncmd(s) char *s; { /* Record commands in learned script */
+ char buf[64];
+ int i, k;
+ if (learnfp && learning) { /* Only if open and on */
+ k = ckstrncpy(buf,s,64);
+ for (i = 0; i < k; i++) { /* Get top-level command keyword */
+ if (buf[i] <= SP) {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ k = lookup(cmdtab,buf,ncmd,NULL); /* Look it up */
+ if (k == XXCON || k == XXLEARN) /* Don't record CONNECT or LEARN */
+ return;
+ if (k == XXTEL) {
+ fputs("SET HOST /NETWORK:TCP",learnfp);
+ fputs(&s[i],learnfp);
+ fputs(" TELNET /TELNET",learnfp);
+ fputs("\nIF FAIL STOP 1 Connection failed\n",learnfp);
+ } else {
+ fputs(s,learnfp);
+ fputs("\n",learnfp);
+ }
+ }
+}
+#endif /* CKLEARN */
+
+
+#ifdef SSHCMD
+/*
+ 2010/03/01...
+ Reopen a connection that was made with an external ssh client
+ after it has been closed.
+ */
+int
+redossh() {
+ int x, netsave;
+ x = nettype;
+ debug(F111,"redossh nettype",ttname,nettype);
+ if ((y = setlin(XXSSH,0,1)) < 0) {
+ if (errno)
+ printf("?%s\n",ck_errstr());
+ else
+ return(y);
+ nettype = x; /* Failed, restore net type. */
+ success = 0;
+ return(y);
+ }
+ netsave = x;
+ return(y);
+}
+#endif /* SSHCMD */
+
+/*
+ Like hmsga() in ckuus2.c but takes a single substitution parameter, s2,
+ which replaces every occurrence of "%s" in the first argument.
+ Added to print text containing the copyright year, so the year doesn't
+ have to be hardwired into lots of scattered text strings.
+*/
+int /* Print an array of lines, */
+#ifdef CK_ANSIC
+hmsgaa(char *s[], char *s2) /* pausing at end of each screen. */
+#else
+hmsgaa(s,s2) char *s[]; char *s2;
+#endif /* CK_ANSIC */
+{
+ extern int hmtopline;
+#ifdef OS2
+ extern int tt_rows[], tt_cols[];
+#else /* OS2 */
+ extern int tt_rows, tt_cols;
+#endif /* OS2 */
+ int x, y, i, j, k, n;
+ if ((x = cmcfm()) < 0) return(x);
+
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+ ttgcwsz();
+#else /* OS2 */
+ /* Check whether window size changed */
+ if (ttgwsiz() > 0) {
+ if (tt_rows > 0 && tt_cols > 0) {
+ cmd_rows = tt_rows;
+ cmd_cols = tt_cols;
+ }
+ }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+ printf("\n"); /* Start off with a blank line */
+ n = (hmtopline > 0) ? hmtopline : 1; /* Line counter */
+ for (i = 0; *s[i]; i++) {
+ printf((char *)s[i],s2); /* Print a line. */
+ printf("\n");
+ y = (int)strlen(s[i]);
+ k = 1;
+ for (j = 0; j < y; j++) /* See how many newlines were */
+ if (s[i][j] == '\n') k++; /* in the string... */
+ n += k;
+ if (n > (cmd_rows - 3) && *s[i+1]) /* After a screenful, give them */
+ if (!askmore()) return(0); /* a "more?" prompt. */
+ else n = 0;
+ }
+ printf("\n");
+ return(0);
+}
+
+/* D O C M D -- Do a command */
+
+/*
+ Returns:
+ -2: user typed an illegal command
+ -1: reparse needed
+ 0: parse was successful (even tho command may have failed).
+*/
+#ifdef DEBUG
+int cmdstats[256] = { -1, -1 };
+#endif /* DEBUG */
+
+int
+docmd(cx) int cx; {
+ extern int nolocal, cmkwflgs;
+
+ debug(F101,"docmd entry, cx","",cx);
+ activecmd = cx;
+ doconx = ((activecmd == XXCON) || (activecmd == XXTEL) ||
+ (activecmd == XXRLOG) || (activecmd == XXPIPE) ||
+ (activecmd == XXIKSD) || (activecmd == XXPTY));
+/*
+ Originally all commands were handled with a big switch() statement,
+ but eventually this started blowing up compilers. Now we have a series
+ of separate if statements and small switches, with the commands that are
+ most commonly executed in scipts and loops coming first, to speed up
+ compute-bound scripts.
+ */
+
+#ifdef DEBUG
+ if (cmdstats[0] == -1) { /* Count commands */
+ int i; /* for tuning... */
+ for (i = 0; i < 256; i++)
+ cmdstats[i] = 0;
+ }
+#endif /* DEBUG */
+
+ switch (cx) {
+ case -4: /* EOF */
+#ifdef OSK
+ if (msgflg) printf("\n");
+#else
+ if (msgflg) printf("\r\n");
+#endif /* OSK */
+ doexit(GOOD_EXIT,xitsta);
+ case -3: /* Null command */
+ return(0);
+ case -9: /* Like -2, but errmsg already done */
+ case -1: /* Reparse needed */
+ return(cx);
+ case -6: /* Special */
+ case -2: /* Error, maybe */
+
+#ifndef NOSPL
+/*
+ Maybe they typed a macro name. Let's look it up and see.
+*/
+ if (cx == -6) /* If they typed CR */
+ ckstrncat(cmdbuf,"\015",CMDBL); /* add it back to command buffer. */
+ if (ifcmd[cmdlvl] == 2) /* Watch out for IF commands. */
+ ifcmd[cmdlvl]--;
+ repars = 1; /* Force reparse */
+ cmres();
+ cx = XXDO; /* Try DO command */
+#else
+ return(cx);
+#endif /* NOSPL */
+ default:
+ if (cx < 0)
+ return(cx);
+ break;
+ }
+#ifdef DEBUG
+ if (cx < 256)
+ cmdstats[cx]++;
+#endif /* DEBUG */
+
+ if ((cmkwflgs & CM_PSH)
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ ) {
+ printf("?Access to system disabled\n");
+ return(-9);
+ }
+ if ((cmkwflgs & CM_LOC)
+#ifndef NOLOCAL
+ && nolocal
+#endif /* NOLOCAL */
+ ) {
+ printf("?Connections disabled\n");
+ return(-9);
+ }
+
+#ifndef NOSPL
+ /* Used in FOR loops */
+
+ if (cx == XX_INCR || cx == XXINC || /* _INCREMENT, INCREMENT */
+ cx == XX_DECR || cx == XXDEC) /* _DECREMENT, DECREMENT */
+ return(doincr(cx));
+
+ /* Define (or change the definition of) a macro or variable */
+
+ if (cx == XXUNDEF || cx == XXUNDFX) {
+#ifdef IKSD
+ if (inserver && !ENABLED(en_asg)) {
+ printf("?Sorry, DEFINE/ASSIGN disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ return(doundef(cx)); /* [_]UNDEFINE */
+ }
+ if (cx == XXDEF || cx == XXASS ||
+ cx == XXDFX || cx == XXASX) {
+#ifdef IKSD
+ if (inserver && !ENABLED(en_asg)) {
+ printf("?Sorry, DEFINE/ASSIGN disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ if (atmbuf[0] == '.' && !atmbuf[1]) /* "." entered as keyword */
+ xxdot = 1; /* i.e. with space after it... */
+ return(dodef(cx)); /* DEFINE, ASSIGN, etc... */
+ }
+
+ /* IF, WHILE, and friends */
+
+ if (cx == XXIF || cx == XXIFX || cx == XXWHI || cx == XXASSER) {
+ return(doif(cx));
+ }
+ if (cx == XXSWIT) { /* SWITCH */
+ return(doswitch());
+ }
+
+ /* GOTO, FORWARD, and _FORWARD (used internally by FOR, WHILE, etc) */
+
+ if (cx == XXGOTO || cx == XXFWD || cx == XXXFWD) { /* GOTO or FORWARD */
+ /* Note, here we don't set SUCCESS/FAILURE flag */
+#ifdef COMMENT
+ if ((y = cmfld("label","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ if (cx != XXXFWD) {
+ printf("?Label name required\n");
+ return(-9);
+ }
+ } else
+ return(y);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = cmcfm()) < 0) return(x);
+#else
+ if ((y = cmtxt("label","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ if (cx != XXXFWD) {
+ printf("?GOTO: Label name required: \"%s\" \"%s\"\n",
+ atmbuf,
+ cmdbuf);
+ return(-9);
+ }
+ } else
+ return(y);
+ }
+ ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+#endif /* COMMENT */
+ s = tmpbuf;
+ debug(F111,"GOTO target",s,cx);
+ return(dogoto(s,cx));
+ }
+ if (cx == XXDO || cx == XXMACRO) { /* DO (a macro) */
+ char mnamebuf[16]; /* (buffer for controlled temp name) */
+ struct FDB kw, fl;
+ int mx; /* Macro index (on stack!) */
+
+ debug(F101,"XXMACRO 0",line,cx);
+ if (cx == XXDO) {
+ if (nmac == 0) {
+ printf("\n?No macros defined\n");
+ return(-9);
+ }
+ for (y = 0; y < nmac; y++) { /* copy the macro table into a */
+ mackey[y].kwd = mactab[y].kwd; /* regular keyword table */
+ mackey[y].kwval = y; /* with value = pointer to macro tbl */
+ mackey[y].flgs = mactab[y].flgs;
+ }
+ cmfdbi(&kw, /* First FDB - macro name */
+ _CMKEY, /* fcode */
+ "Macro", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nmac, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = cmkey */
+ xxstring, /* Processing function */
+ mackey, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 2nd FDB - for "{" */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "",
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ x = cmfdb(&kw); /* Parse something */
+ if (x < 0) { /* Error */
+ if (x == -3) {
+ printf("?Macro name required\n");
+ return(-9);
+ } else
+ return(x);
+ }
+ if (cmresult.fcode == _CMKEY) {
+ extern int mtchanged;
+ char * macroname = NULL;
+
+ /* In case args include an \fexec() that changes the macro table */
+
+ mx = x; /* Save macro index on stack */
+ mtchanged = 0; /* Mark state of macro table */
+ makestr(¯oname,mactab[mx].kwd); /* Save name */
+
+ if ((y = cmtxt("optional arguments","",&s,xxstring)) < 0)
+ return(y); /* Get macro args */
+
+ if (mtchanged) { /* Macro table changed? */
+ mx = mlook(mactab,macroname,nmac); /* Look up name again */
+ }
+ if (macroname)
+ free(macroname);
+
+ return(dodo(mx,s,cmdstk[cmdlvl].ccflgs) < 1 ?
+ (success = 0) : 1);
+ }
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* _CMFLD */
+ if (atmbuf[0] == '{') {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ }
+ } else { /* XXMACRO ("immediate macro") */
+ int k = 0;
+ line[k++] = '{';
+ line[k++] = SP;
+ line[k] = NUL;
+ debug(F111,"XXMACRO A",line,k);
+ if ((y = cmtxt("Braced list of commands","",&s,xxstring)) < 0)
+ return(y);
+ k = ckstrncpy(line+k,s,LINBUFSIZ-k);
+ debug(F111,"XXMACRO B",line,k);
+ }
+ x = strlen(line);
+ if ((line[0] == '{' && line[x-1] != '}') || line[0] == '}')
+ return(-2);
+ if (line[0] != '{' && line[x-1] != '}') {
+ /* Unknown command. If ON_UNKNOWN_COMMAND macro is defined, */
+ /* parse args and then execute it, but only if it is not */
+ /* already active. */
+ int k = -1;
+ if (!unkmacro) {
+ k = mxlook(mactab,"on_unknown_command",nmac);
+ }
+ if (k > -1) {
+ ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
+ z = maclvl; /* Save the current maclvl */
+ if ((y = cmtxt("text","",&s,xxstring)) < 0)
+ return(y);
+ ckstrncat(tmpbuf," ",TMPBUFSIZ);
+ ckstrncat(tmpbuf,s,TMPBUFSIZ);
+ unkmacro = 1;
+ debug(F110,"ON_UNKNOWN_COMMAND",s,0);
+ dodo(k,tmpbuf,cmdstk[cmdlvl].ccflgs); /* Run the macro */
+ while (maclvl > z) {
+ sstate = (CHAR) parser(1);
+ if (sstate) proto();
+ }
+ debug(F101,"UNKMAC loop exit maclvl","",maclvl);
+ unkmacro = 0;
+ return(success);
+ }
+ if (x > 0)
+ printf("?Not a command or macro name: \"%s\"\n",line);
+ else
+ printf("?Not a command or macro name.\n");
+ return(-9);
+ }
+ s = brstrip(line);
+ sprintf(mnamebuf," ..tmp:%03d",cmdlvl); /* safe (16) */
+ x = addmac(mnamebuf,s);
+ return(dodo(x,NULL,cmdstk[cmdlvl].ccflgs) < 1 ? (success = 0) : 1);
+ }
+
+ if (cx == XXLBL) { /* LABEL */
+ if ((x = cmfld("label","",&s,xxstring)) < 0) {
+ if (x == -3) {
+#ifdef COMMENT
+ printf("?LABEL: Label name required: \"%s\"\n", cmdbuf);
+ return(-9);
+#else
+ s = "";
+#endif /* COMMENT */
+ } else return(x);
+
+ }
+ debug(F111,"LABEL",s,x);
+ if ((x = cmcfm()) < 0) return(x);
+ return(0);
+ }
+
+ if (cx == XXEVAL || cx == XX_EVAL) /* _EVALUATE, EVALUATE */
+ return(doeval(cx));
+
+#ifndef NOSEXP
+ if (cx == XXSEXP) { /* Lisp-like S-Expression */
+ struct stringarray * q;
+ char /* *p, *r, */ *tmp, *m;
+ int i, k, n, quote = 0, contd = 0, size = 0, len = 0;
+ extern int sexprc, sexppv;
+
+ tmp = tmpbuf; /* Buffer to collect SEXP */
+ tmpbuf[0] = NUL; /* Clear it */
+ size = TMPBUFSIZ; /* Capacity of buffer */
+ sexprc = -1; /* Assume bad input */
+ n = 0; /* Paren balance counter */
+
+ while (1) { /* Allow SEXP on multiple lines */
+ m = contd ?
+ "Continuation of S-Expression" :
+ "S-Expression (\"help sexp\" for details)";
+ x = cmtxt(m,"",&s,xxstring);
+ if (x < 0)
+ return(x);
+ if (!*s) /* Needed for (=) and (:) */
+ s = cmdbuf+1; /* I can't explain why. */
+ k = ckmakmsg(tmp, size, contd ? " " : "(", s, NULL, NULL);
+ if (k < 1) {
+ printf("?SEXP too long - %d max\n",TMPBUFSIZ);
+ return(-9);
+ }
+ debug(F111,contd ? "sexp contd" : "sexp",s,k);
+
+ for (i = len; i < len+k; i++) { /* Check balance */
+ if (!quote && tmpbuf[i] == CMDQ) {
+ quote = 1;
+ continue;
+ }
+ if (quote) {
+ quote = 0;
+ continue;
+ }
+ if (tmpbuf[i] == '(')
+ n++;
+ else if (tmpbuf[i] == ')')
+ n--;
+ }
+ if (n == 0) { /* Break when balanced */
+ break;
+ }
+ if (n < 0) { /* Too many right parens */
+ printf("?Unbalanced S-Expression: \"%s\"\n",tmpbuf);
+ return(-9);
+ }
+ contd++; /* Need more right parens */
+ cmini(ckxech); /* so keep parsing */
+ tmp += k; /* adjust buffer pointer */
+ size -= k; /* and capacity */
+ len += k; /* and length so far */
+ }
+ s = tmpbuf;
+ makestr(&lastsexp,s);
+ q = cksplit(1,SEXPMAX,s,NULL,NULL,8,0,0); /* Precheck for > 1 SEXP */
+ debug(F101,"sexp split","",q->a_size);
+
+ if (q->a_size == 1) { /* We should get exactly one back */
+ char * result, * dosexp();
+ sexprc = 0; /* Reset out-of-band return code */
+ result = dosexp(s); /* Get result */
+ debug(F111,"sexp result",result,sexprc);
+ if (sexprc == 0) { /* Success */
+ /* Echo the result if desired */
+ if ((!xcmdsrc && sexpecho != SET_OFF) || sexpecho == SET_ON)
+ printf(" %s\n",result ? result : "");
+ makestr(&sexpval,result);
+ success = sexppv > -1 ? sexppv : 1;
+ return(success);
+ }
+ }
+ if (sexprc < 0)
+ printf("?Invalid S-Expression: \"%s\"\n",lastsexp);
+ return(-9);
+ }
+#endif /* NOSEXP */
+
+#endif /* NOSPL */
+
+ if (cx == XXECH || cx == XXXECH || cx == XXVOID
+#ifndef NOSPL
+ || cx == XXAPC
+#endif /* NOSPL */
+ ) { /* ECHO or APC */
+ if ((x = cmtxt((cx == XXECH || cx == XXXECH) ?
+ "Text to be echoed" :
+ ((cx == XXVOID) ? "Text" :
+ "Application Program Command text"),
+ "",
+ &s,
+ xxstring
+ )
+ ) < 0)
+ return(x);
+ if (!s) s = "";
+#ifdef COMMENT
+/* This is to preserve the pre-8.0 behavior but it's too confusing */
+ x = strlen(s);
+ x = (x > 1) ? ((s[0] == '"' && s[x-1] == '"') ? 1 : 0) : 0;
+#endif /* COMMENT */
+ s = brstrip(s); /* Strip braces and doublequotes */
+ if (cx == XXECH) { /* ECHO */
+#ifndef NOSPL
+ if (!fndiags || fnsuccess) {
+#endif /* NOSPL */
+#ifdef COMMENT
+ /* The "if (x)" business preserves previous behavior */
+ /* by putting back the doublequotes if they were included. */
+ if (x)
+ printf("\"%s\"\n",s);
+ else
+#endif /* COMMENT */
+ printf("%s\n",s);
+#ifndef NOSPL
+ }
+#endif /* NOSPL */
+ } else if (cx == XXXECH) { /* XECHO */
+ if (x)
+ printf("\"%s\"",s);
+ else
+ printf("%s",s);
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ } else if (cx == XXAPC) { /* APC */
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+#endif /* CK_APC */
+ if (!local) {
+ printf("%c_%s%c\\",ESC,s,ESC);
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+
+ } else { /* Local mode - have connection */
+#ifndef NOSPL
+ if (ckmakxmsg(tmpbuf, /* Form APC string in buffer */
+ TMPBUFSIZ,
+ ckctoa((char)ESC),
+ ckctoa('_'),
+ s,
+ ckctoa((char)ESC),
+ ckctoa('\\'),
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ ) > 0)
+ return(success = dooutput(tmpbuf, XXOUT));
+ printf("?Too long\n");
+ return(-9);
+#else
+ printf("%c_%s%c\\",ESC,s,ESC);
+#endif /* NOSPL */
+ }
+ }
+ return(success = 1);
+ }
+
+#ifndef NOSPL
+/* Copy macro args from/to two levels up, used internally by _floop et al. */
+ if (cx == XXGTA || cx == XXPTA) { /* _GETARGS, _PUTARGS */
+ int x;
+ debug(F101,"docmd XXGTA","",XXGTA);
+ debug(F101,"docmd cx","",cx);
+ debug(F101,"docmd XXGTA maclvl","",maclvl);
+ x = dogta(cx);
+ debug(F101,"docmd dogta returns","",x);
+ debug(F101,"docmd dogta maclvl","",maclvl);
+ return(x);
+ }
+#endif /* NOSPL */
+
+#ifndef NOSPL
+#ifdef CKCHANNELIO
+ if (cx == XXFILE)
+ return(dofile(cx));
+ else if (cx == XXF_RE || cx == XXF_WR || cx == XXF_OP ||
+ cx == XXF_CL || cx == XXF_SE || cx == XXF_RW ||
+ cx == XXF_FL || cx == XXF_LI || cx == XXF_ST || cx == XXF_CO)
+ return(dofile(cx));
+#endif /* CKCHANNELIO */
+
+/* ASK, ASKQ, READ */
+ if (cx == XXASK || cx == XXASKQ || cx == XXREA ||
+ cx == XXRDBL || cx == XXGETC || cx == XXGETK) {
+ return(doask(cx));
+ }
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+#ifndef NOHELP
+ if (cx == XXBUG) { /* BUG */
+ if ((x = cmcfm()) < 0) return(x);
+ return(dobug());
+ }
+#endif /* NOHELP */
+#endif /* NOFRILLS */
+
+#ifndef NOXFER
+ if (cx == XXBYE) { /* BYE */
+ extern int ftp_cmdlin;
+ if ((x = cmcfm()) < 0) return(x);
+
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) {
+ extern int stayflg, ftp_fai;
+ success = ftpbye();
+ if (ftp_cmdlin && !stayflg && !local)
+ doexit(ftp_fai ? BAD_EXIT : GOOD_EXIT,-1);
+ else
+ return(success);
+ }
+#endif /* NEWFTP */
+
+ if (!local) {
+ printf("?No connection - use EXIT to quit.\n");
+ return(-9);
+ }
+
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("?Sorry, BYE only works with Kermit protocol\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+
+#ifdef IKS_OPTION
+ if (
+#ifdef CK_XYZ
+ protocol == PROTO_K &&
+#endif /* CK_XYZ */
+ !iks_wait(KERMIT_REQ_START,1)) {
+ printf(
+ "?A Kermit Server is not available to process this command\n");
+ return(-9); /* Correct the return code */
+ }
+#endif /* IKS_OPTION */
+
+ bye_active = 1;
+ sstate = setgen('L',"","","");
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ return(0);
+ }
+#endif /* NOXFER */
+
+ if (cx == XXBEEP) { /* BEEP */
+ int x;
+#ifdef OS2
+ int y;
+ if ((y = cmkey(beeptab, nbeeptab, "which kind of beep", "information",
+ xxstring)) < 0 )
+ return (y);
+ if ((x = cmcfm()) < 0) return(x);
+ bleep((short)y); /* y is one of the BP_ values */
+#else /* OS2 */
+ if ((x = cmcfm()) < 0) return(x);
+#ifndef NOSPL
+ bleep(BP_NOTE);
+#else
+ putchar('\07');
+#endif /* NOSPL */
+#endif /* OS2 */
+ return(0);
+ }
+
+#ifndef NOFRILLS
+ if (cx == XXCLE) /* CLEAR */
+ return(success = doclear());
+#endif /* NOFRILLS */
+
+ if (cx == XXCOM) { /* COMMENT */
+ if ((x = cmtxt("Text of comment line","",&s,NULL)) < 0)
+ return(x);
+ /* Don't change SUCCESS flag for this one */
+ return(0);
+ }
+
+#ifndef NOLOCAL
+ if (cx == XXCON || cx == XXCQ) /* CONNECT or CONNECT /QUIETLY */
+ return(doxconn(cx));
+#endif /* NOLOCAL */
+
+#ifndef NOFRILLS
+#ifdef ZCOPY
+ if (cx == XXCPY) { /* COPY a file */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_cpy)) {
+ printf("?Sorry, COPY is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))
+ )
+ return(success = 0);
+#endif /* CK_APC */
+ return(docopy());
+ }
+#endif /* ZCOPY */
+#ifdef NT
+ if ( cx == XXLINK ) {
+#ifdef IKSD
+ if (inserver && !ENABLED(en_cpy)) {
+ printf("?Sorry, LINK (COPY) is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))
+ )
+ return(success = 0);
+#endif /* CK_APC */
+ return(dolink());
+ }
+#endif /* NT */
+#endif /* NOFRILLS */
+
+ /* CD and friends */
+ if (cx == XXCWD || cx == XXCDUP || cx == XXBACK ||
+ cx == XXLCWD || cx == XXLCDU || cx == XXKCD) {
+#ifdef LOCUS
+ if (!locus) {
+ if (cx == XXCWD) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZCWD));
+#endif /* NOXFER */
+ } else if (cx == XXCDUP) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZCDU));
+#endif /* NOXFER */
+ }
+ }
+#endif /* LOCUS */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_cwd)) {
+ printf("?Sorry, changing directories is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ return(success = docd(cx));
+ }
+
+ if (cx == XXCHK) /* CHECK */
+ return(success = dochk());
+
+ if (cx == XXCLO) { /* CLOSE */
+ x = cmkey(clstab,ncls,"\"CONNECTION\", or log or file to close",
+ "connection",xxstring);
+ if (x == -3) {
+ printf("?You must say which file or log\n");
+ return(-9);
+ }
+ if (x < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifndef NOLOCAL
+ if (x == 9999) { /* CLOSE CONNECTION */
+ x = clsconnx(0);
+ switch (x) {
+ case 0:
+ if (msgflg) printf("?Connection was not open\n");
+ case -1:
+ return(0);
+ case 1:
+ whyclosed = WC_CLOS;
+ return(1);
+ }
+ return(0);
+ }
+#endif /* NOLOCAL */
+ y = doclslog(x);
+ success = (y == 1);
+ return(success);
+ }
+
+#ifndef NOSPL
+ if (cx == XXDCL || cx == XXUNDCL) { /* DECLARE an array */
+ return(dodcl(cx));
+ }
+#endif /* NOSPL */
+
+#ifndef NODIAL
+ if (cx == XXRED || cx == XXDIAL || cx == XXPDIA ||
+ cx == XXANSW || cx == XXLOOK) { /* DIAL, REDIAL etc */
+#ifdef VMS
+ extern int batch;
+#else
+#ifdef UNIXOROSK
+ extern int backgrd;
+#endif /* UNIXOROSK */
+#endif /* VMS */
+ x = dodial(cx);
+ debug(F101,"dodial returns","",x);
+ if ((cx == XXDIAL || cx == XXRED || cx == XXANSW) &&
+ (x > 0) && /* If DIAL or REDIAL succeeded */
+ (dialsta != DIA_PART) && /* and it wasn't partial */
+ (dialcon > 0)) {
+ if ((dialcon == 1 || /* And DIAL CONNECT is ON, */
+ ((dialcon == 2) && /* or DIAL CONNECT is AUTO */
+ !xcmdsrc /* and we're at top level... */
+#ifdef VMS
+ && !batch /* Not if running from batch */
+#else
+#ifdef UNIXOROSK
+ && !backgrd /* Not if running in background */
+#endif /* UNIXOROSK */
+#endif /* VMS */
+ ))) /* Or AUTO */
+ x = doconect(dialcq, /* Then also CONNECT */
+ cmdlvl == 0 ? 1 : 0
+ );
+ if (ttchk() < 0)
+ dologend();
+ }
+ return(success = x);
+ }
+#endif /* NODIAL */
+
+#ifndef NOPUSH
+#ifdef CK_REXX
+ if (cx == XXREXX) { /* REXX */
+ extern int nopush;
+ if ( nopush )
+ return(success=0);
+ return(dorexx());
+ }
+#endif /* CK_REXX */
+#endif /* NOPUSH */
+
+#ifndef NOFRILLS
+ if (cx == XXDEL || cx == XXLDEL) { /* DELETE */
+#ifdef LOCUS
+ if (!locus && cx != XXLDEL) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZDEL));
+#endif /* NOXFER */
+ }
+#endif /* LOCUS */
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_del)
+#ifdef CK_LOGIN
+ || isguest
+#endif /* CK_LOGIN */
+ )) {
+ printf("?Sorry, DELETE is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+ return(dodel());
+ }
+#endif /* NOFRILLS */
+
+ if (cx == XXTOUC) /* TOUCH */
+ return(dodir(cx));
+
+ /* DIRECTORY commands */
+
+ if (cx == XXDIR || cx == XXLS || cx == XXLDIR ||
+ cx == XXWDIR || cx == XXHDIR) {
+#ifdef LOCUS
+ if (!locus && cx != XXLDIR) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZDIR));
+#endif /* NOXFER */
+ }
+#endif /* LOCUS */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_dir)) {
+ printf("?Sorry, DIRECTORY is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ return(dodir(cx));
+ }
+
+#ifndef NOSPL
+ if (cx == XXELS) /* ELSE */
+ return(doelse());
+#endif /* NOSPL */
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+ if (cx == XXENA || cx == XXDIS) { /* ENABLE, DISABLE */
+ s = (cx == XXENA) ?
+ "Server function to enable" :
+ "Server function to disable";
+
+ if ((x = cmkey(enatab,nena,s,"",xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of server function required\n");
+ return(-9);
+ } else return(x);
+ }
+ if ((y = cmkey(kmstab,3,"mode","both",xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Please specify remote, local, or both\n");
+ return(-9);
+ } else return(y);
+ }
+ if (cx == XXDIS) /* Disabling, not enabling */
+ y = 3 - y;
+ if ((z = cmcfm()) < 0) return(z);
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+#ifdef IKSD
+ /* This may seem like it duplicates the work in doenable() */
+ /* but this code returns failure whereas doenable() returns */
+ /* success. */
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf &&
+#endif /* IKSDCONF */
+ (x == EN_HOS || x == EN_PRI || x == EN_MAI || x == EN_WHO ||
+ isguest))
+ return(success = 0);
+#endif /* IKSD */
+ return(doenable(y,x));
+ }
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+ if (cx == XXRET) { /* RETURN */
+ if ((x = cmtxt("Optional return value","",&s,NULL)) < 0)
+ return(x);
+ s = brstrip(s); /* Strip braces */
+ if (cmdlvl == 0) /* At top level, nothing happens... */
+ return(success = 1);
+ switch (cmdstk[cmdlvl].src) { /* Action depends on command source */
+ case CMD_TF: /* Command file */
+ popclvl(); /* Pop command level */
+ return(success = 1); /* always succeeds */
+ case CMD_MD: /* Macro */
+ case CMD_KB: /* Prompt */
+ return(doreturn(s)); /* Trailing text is return value. */
+ default: /* Shouldn't happen */
+ return(-2);
+ }
+ }
+#endif /* NOSPL */
+
+#ifndef NOSPL
+ if (cx == XXOPE) /* OPEN */
+ return(doopen());
+#endif /* NOSPL */
+
+#ifndef NOSPL
+ if (cx == XXOUT || cx == XXLNOUT) { /* OUTPUT or LINEOUT */
+ if ((x = cmtxt("Text to be output","",&s,NULL)) < 0)
+ return(x);
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+ debug(F110,"OUTPUT 1",s,0);
+ s = brstrip(s); /* Strip enclosing braces, */
+ debug(F110,"OUTPUT 2",s,0);
+/*
+ I don't think I could ever fully explain this in a million years...
+ We have read the user's string without calling the variable-expander
+ function. Now, before we call it, we have to double backslashes that
+ appear before \N, \B, \L, and \ itself, so the expander function will
+ reduce them back to single backslashes, so when we call dooutput()...
+ But it's more complicated than that.
+*/
+ if (cmdgquo()) { /* Only if COMMAND QUOTING ON ... */
+ for (x = 0, y = 0; s[x]; x++, y++) {
+ if (s[x] == CMDQ) {
+ char c = s[x+1];
+ if (c == 'n' || c == 'N' ||
+ c == 'b' || c == 'B' ||
+ c == 'l' || c == 'L' ||
+ c == CMDQ)
+ line[y++] = CMDQ;
+ }
+ line[y] = s[x];
+ }
+ line[y++] = '\0'; /* Now expand variables, etc. */
+ debug(F110,"OUTPUT 3",line,0);
+ s = line+y+1;
+ x = LINBUFSIZ - (int) strlen(line) - 1;
+ debug(F101,"OUTPUT size","",x);
+ if (zzstring(line,&s,&x) < 0)
+ return(success = 0);
+ s = line+y+1;
+ debug(F110,"OUTPUT 4",s,0);
+ }
+ success = dooutput(s,cx);
+ return(success);
+ }
+#endif /* NOSPL */
+
+#ifdef ANYX25
+#ifndef IBMX25
+ if (cx == XXPAD) { /* PAD commands */
+ x = cmkey(padtab,npadc,"PAD command","",xxstring);
+ if (x == -3) {
+ printf("?You must specify a PAD command to execute\n");
+ return(-9);
+ }
+ if (x < 0) return(x);
+
+ switch (x) {
+ case XYPADL:
+ if (x25stat() < 0)
+ printf("Sorry, you must 'set network' & 'set host' first\r\n");
+ else {
+ x25clear();
+ initpad();
+ }
+ break;
+ case XYPADS:
+ if (x25stat() < 0)
+ printf("Not connected\r\n");
+ else {
+ extern int linkid, lcn;
+ conol("Connected thru ");
+ conol(ttname);
+ printf(", Link id %d, Logical channel number %d\r\n",
+ linkid,lcn);
+ }
+ break;
+ case XYPADR:
+ if (x25stat() < 0)
+ printf("Sorry, you must 'set network' & 'set host' first\r\n");
+ else
+ x25reset(0,0);
+ break;
+ case XYPADI:
+ if (x25stat() < 0)
+ printf("Sorry, you must 'set network' & 'set host' first\r\n");
+ else
+ x25intr(0);
+ }
+ return(0);
+ }
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOSPL
+ if (cx == XXPAU || cx == XXWAI || cx == XXMSL) /* PAUSE, WAIT, etc */
+ return(dopaus(cx));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+ if (cx == XXPRI) {
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && (isguest || !ENABLED(en_pri))) {
+ printf("?Sorry, printing is disabled\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+ if ((x = cmifi("File to print","",&s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?A file specification is required\n");
+ return(-9);
+ } else return(x);
+ }
+ if (y != 0) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = "";
+#ifndef NT
+ if ((x = cmtxt("Local print command options, or carriage return","",&s,
+ xxstring)) < 0)
+ return(x);
+#endif /* NT */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ return(success = (zprint(s,line) == 0) ? 1 : 0);
+ }
+#endif /* NOFRILLS */
+
+#ifdef TCPSOCKET
+#ifndef NOPUSH
+ if (cx == XXPNG) /* PING an IP host */
+ return(doping());
+#endif /* NOPUSH */
+
+#ifndef NOFTP
+ if (cx == XXFTP) /* FTP */
+#ifdef SYSFTP
+#ifndef NOPUSH
+ return(doftp()); /* Just runs system's ftp program */
+#else
+ return(-2);
+#endif /* NOPUSH */
+#else
+ return(doxftp());
+#endif /* SYSFTP */
+#endif /* NOFTP */
+#endif /* TCPSOCKET */
+
+ if (cx == XXPWD || cx == XXLPWD) { /* PWD */
+#ifdef OS2
+ char *pwp;
+#endif /* OS2 */
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef LOCUS
+ if (!locus && cx != XXLPWD) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZPWD));
+#endif /* NOXFER */
+ }
+#endif /* LOCUS */
+
+#ifndef MAC
+#ifndef OS2
+#ifdef UNIX
+ printf("%s\n",zgtdir());
+#else
+ xsystem(PWDCMD);
+#endif /* UNIX */
+ return(success = 1); /* Blind faith */
+#else /* OS2 */
+ if (pwp = zgtdir()) {
+ if (*pwp) {
+#ifdef NT
+ line[0] = NUL;
+ ckGetLongPathName(pwp,line,LINBUFSIZ);
+ line[LINBUFSIZ-1] = NUL;
+ tmpbuf[0] = NUL;
+ GetShortPathName(pwp,tmpbuf,TMPBUFSIZ);
+ tmpbuf[TMPBUFSIZ-1] = NUL;
+ pwp = line;
+ if (!strcmp(line,tmpbuf)) {
+#endif /* NT */
+ printf("%s\n",pwp);
+#ifdef NT
+ } else {
+ printf(" Long name: %s\n",line);
+ printf(" Short name: %s\n",tmpbuf);
+ }
+#endif /* NT */
+ }
+ return(success = ((int)strlen(pwp) > 0));
+ } else return(success = 0);
+#endif /* OS2 */
+#else /* MAC */
+ if (pwp = zgtdir()) {
+ printf("%s\n",pwp);
+ return(success = ((int)strlen(pwp) > 0));
+ } else return(success = 0);
+#endif /* MAC */
+ }
+
+ if (cx == XXQUI || cx == XXEXI) { /* EXIT, QUIT */
+ extern int quitting;
+
+ if ((y = cmnum("exit status code",ckitoa(xitsta),10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmtxt("Optional EXIT message","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ ckstrncpy(line,s,LINBUFSIZ);
+
+ if (!hupok(0)) /* Check if connection still open */
+ return(success = 0);
+
+ if (line[0]) /* Print EXIT message if given */
+ printf("%s\n",(char *)line);
+
+ quitting = 1; /* Flag that we are quitting. */
+
+#ifdef VMS
+ doexit(GOOD_EXIT,x);
+#else
+#ifdef OSK
+/* Returning any codes here makes the OS-9 shell print an error message. */
+ doexit(GOOD_EXIT,-1);
+#else
+#ifdef datageneral
+ doexit(GOOD_EXIT,x);
+#else
+ doexit(x,-1);
+#endif /* datageneral */
+#endif /* OSK */
+#endif /* VMS */
+ }
+
+#ifndef NOXFER
+#ifndef NOFRILLS
+ if (cx == XXERR) { /* ERROR */
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("Sorry, E-PACKET only works with Kermit protocol\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ if ((x = cmcfm()) < 0) return(x);
+ ttflui();
+ epktflg = 1;
+ sstate = 'a';
+ return(0);
+ }
+#endif /* NOFRILLS */
+
+ if (cx == XXFIN) { /* FINISH */
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(ftpbye());
+#endif /* NEWFTP */
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("Sorry, FINISH only works with Kermit protocol\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ if ((x = cmcfm()) < 0) return(x);
+
+#ifdef IKS_OPTION
+ if (
+#ifdef CK_XYZ
+ protocol == PROTO_K &&
+#endif /* CK_XYZ */
+ !iks_wait(KERMIT_REQ_START,1)) {
+ printf(
+ "?A Kermit Server is not available to process this command\n");
+ return(-9); /* Correct the return code */
+ }
+#endif /* IKS_OPTION */
+
+ sstate = setgen('F',"","","");
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ return(0);
+ }
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ if (cx == XXFOR) /* FOR loop */
+ return(dofor());
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ /* GET MGET REGET RETRIEVE etc */
+ if (cx == XXGET || cx == XXMGET || cx == XXREGET || cx == XXRETR) {
+#ifdef IKSD
+ if (inserver && !ENABLED(en_sen)) {
+ printf("?Sorry, reception of files is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ return(doxget(cx));
+ }
+#endif /* NOXFER */
+
+#ifndef NOSPL
+#ifndef NOFRILLS
+ if (cx == XXGOK) { /* GETOK */
+ return(success = doask(cx));
+ }
+#endif /* NOFRILLS */
+#endif /* NOSPL */
+
+ if (cx == XXHLP) { /* HELP */
+#ifdef NOHELP
+ return(dohlp(XXHLP));
+#else
+ x = cmkey2(cmdtab,
+ ncmd,"\nCommand or topic","help",toktab,xxstring,1+2+8);
+ debug(F111,"HELP command x",cmdbuf,x);
+ if (x == -5) {
+ y = chktok(toktab);
+ debug(F101,"HELP cmkey token","",y);
+ /* ungword(); */
+ switch (y) {
+#ifndef NOPUSH
+ case '!':
+ case '@': x = XXSHE; break;
+ case '<': x = XXFUN; break;
+#endif /* NOPUSH */
+ case '#': x = XXCOM; break;
+ case ';': x = XXCOM; break;
+#ifndef NOSPL
+ case '.': x = XXDEF; break;
+ case ':': x = XXLBL; break;
+#ifndef NOSEXP
+ case '(': x = XXSEXP; break;
+#endif /* NOSEXP */
+#endif /* NOSPL */
+#ifdef CK_RECALL
+ case '^': x = XXREDO; break;
+#endif /* CK_RECALL */
+ case '&': x = XXECH; break; /* (what is this?) */
+ default:
+ printf("\n?Invalid - %s\n",cmdbuf);
+ x = -2;
+ }
+ }
+ makestr(&hlptok,atmbuf);
+ debug(F111,"HELP token",hlptok,x);
+ return(dohlp(x));
+#endif /* NOHELP */
+ }
+
+#ifndef NOHELP
+ if (cx == XXINT) /* INTRO */
+ return(hmsga(introtxt));
+ if (cx == XXNEW) { /* NEWS */
+ int x;
+ extern char * k_info_dir;
+ x = hmsga(newstxt);
+ return(x);
+ }
+
+#ifdef OS2ONLY
+ if (cx == XXUPD) { /* View UPDATE file */
+ extern char exedir[];
+ char * pTopic;
+ char updstr[2048];
+ if ((x = cmtxt("topic name","",&pTopic,xxstring)) < 0)
+ return x;
+#ifdef COMMENT
+ sprintf(updstr,
+ "start view %s\\docs\\k2.inf+%s\\docs\\using_ck.inf+\
+%s\\docs\\dialing.inf+%s\\docs\\modems.inf %s",
+ exedir,exedir,exedir,exedir,pTopic
+ );
+#else
+ if (ckmakxmsg(updstr,
+ 2048,
+ "start view ",
+ exedir,
+ "\\docs\\k2.inf+",
+ exedir,
+ "\\docs\\using_ck.inf+",
+ exedir,
+ "\\docs\\dialing.inf+",
+ exedir,
+ "\\docs\\modems.inf ",
+ pTopic,
+ NULL,
+ NULL
+ ) > 0)
+#endif /* COMMENT */
+ system(updstr);
+ return(success = 1);
+ }
+#endif /* OS2ONLY */
+#endif /* NOHELP */
+
+#ifndef NOLOCAL
+ if (cx == XXHAN) { /* HANGUP */
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && !local && ftpisopen()))
+ return(success = ftpbye());
+#endif /* NEWFTP */
+#ifndef NODIAL
+ if ((x = mdmhup()) < 1) {
+ debug(F101,"HANGUP mdmup","",x);
+#endif /* NODIAL */
+ x = tthang();
+ debug(F101,"HANGUP tthang","",x);
+ x = (x > -1);
+#ifndef NODIAL
+ }
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ whyclosed = WC_CLOS;
+ ttchk(); /* In case of CLOSE-ON-DISCONNECT */
+ dologend();
+#ifdef OS2
+ if (x)
+ DialerSend(OPT_KERMIT_HANGUP, 0);
+#endif /* OS2 */
+ if (x) haveline = 0;
+ return(success = x);
+ }
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+ /* INPUT, REINPUT, and MINPUT */
+
+ if (cx == XXINP || cx == XXREI || cx == XXMINP) {
+ long zz;
+ int flags = 0, incount = 0;
+ extern int itsapattern, isjoin, isinbuflen;
+ int c, getval;
+
+ struct FDB sw, nu, fl;
+ int fc, havetime = 0;
+ char * m;
+
+ if (cx == XXREI) {
+ m = "Timeout in seconds (ignored)";
+ } else {
+ m = "Seconds to wait for input,\n or time of day hh:mm:ss,\
+ or switch";
+ }
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ m, /* helpmsg */
+ ckitoa(indef), /* default */
+ "", /* addtl string data */
+ ninputsw, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ inputsw, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu,
+ _CMNUM, /* Number */
+ m, /* Help message */
+ ckitoa(indef), /* default */
+ "", /* N/A */
+ 10, /* Radix = 10 */
+ 0, /* N/A */
+ xxstring, /* Processing function */
+ NULL, /* N/A */
+ &fl /* Next */
+ );
+ cmfdbi(&fl, /* Time of day hh:mm:ss */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "",
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ fc = (cx == XXREI) ? cmfdb(&nu) : cmfdb(&sw); /* Parse something */
+
+ for (y = 0; y < MINPMAX; y++) { /* Initialize search strings */
+ mp[y] = 0; /* Assume it's not a pattern */
+ if (!mpinited) {
+ ms[y] = NULL;
+ }
+ if (ms[y]) {
+ free(ms[y]); /* Free old strings, if any */
+ ms[y] = NULL;
+ }
+ }
+ mpinited = 1;
+ while (!havetime) {
+ if (fc < 0) { /* Error */
+ if (fc == -3) {
+ printf("?Syntax error in INPUT-class command\n");
+ return(-9);
+ } else
+ return(fc);
+ }
+ switch (cmresult.fcode) {
+ case _CMKEY: /* Switch */
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) &&
+ !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (getval && cmresult.nresult == INPSW_COU) {
+ if ((y = cmnum("Number of bytes to read",
+ "",10,&x,xxstring)) < 0)
+ return(y);
+ incount = x;
+ }
+ flags |= cmresult.nresult;
+ fc = cmfdb(&sw); /* Maybe parse more switches */
+ continue;
+
+ case _CMNUM: /* Seconds to time out */
+ x = cmresult.nresult;
+#ifdef CKFLOAT
+ if (inscale != 1.0) /* Scale */
+ x *= inscale;
+#endif /* CKFLOAT */
+ havetime++;
+ break;
+
+ case _CMFLD:
+ zz = tod2sec(atmbuf); /* Convert to secs since midnight */
+ if (zz < 0L) {
+ printf("?Number, expression, or time of day required\n");
+ return(-9);
+ } else {
+ char now[32]; /* Current time */
+ char *p;
+ long tnow;
+ p = now;
+ ztime(&p);
+ tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ if (zz < tnow) /* User's time before now */
+ zz += 86400L; /* So make it tomorrow */
+ zz -= tnow; /* Seconds from now. */
+ if (zz > -1L) {
+ x = zz;
+ if (zz != (long) x) {
+ printf(
+"Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
+);
+ return(-9);
+ }
+ }
+ havetime++;
+ }
+ break;
+ default:
+ printf("?Internal error\n");
+ return(-9);
+ }
+ }
+ /* Now parse the search text */
+
+#ifdef CK_MINPUT
+ if (cx == XXMINP) { /* MINPUT */
+ int i, k = 0, n = 0;
+ struct stringarray * q;
+ keepallchars = 1;
+ while (k < MINPMAX) {
+ if ((y = cmfld("String or pattern","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ break;
+ } else {
+ return(y);
+ }
+ }
+ debug(F111,"MINPUT field",s,k);
+ if (isjoin) {
+ if ((q = cksplit(1,0,s," ",(char *)c1chars,3,0,0))) {
+ char ** ap = q->a_head;
+ n = q->a_size;
+ debug(F101,"minput cksplit size","",n);
+ for (i = 1; i <= n && k < MINPMAX; i++) {
+ if (!ap[i]) /* Add non-empty elements */
+ continue;
+ if (!*(ap[i]))
+ continue;
+ makestr(&(ms[k]),ap[i]);
+ debug(F111,"MINPUT JOIN",ms[k],k);
+ k++;
+ }
+ }
+ } else {
+ if (s) if (*s) {
+ makestr(&(ms[k]),brstrip(s));
+ if (itsapattern) mp[k] = 1;
+ debug(F111,"MINPUT",ms[k],itsapattern);
+ k++;
+ }
+ }
+ }
+ keepallchars = 0;
+ } else {
+#endif /* CK_MINPUT */
+
+ /* INPUT or REINPUT */
+
+ if (flags & INPSW_COU) {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ } else {
+ if ((y = cmtxt("Material to be input","",&s,xxstring)) < 0)
+ return(y);
+ }
+ mp[0] = itsapattern ? 1 : 0;
+ makestr(&(ms[0]),brstrip(s));
+ ms[1] = NULL;
+
+#ifdef CK_MINPUT
+ }
+#endif /* CK_MINPUT */
+
+ if (incount > 0) /* No searching if /COUNT: given */
+ makestr(&(ms[0]),NULL);
+
+ if (cx == XXINP || cx == XXMINP) { /* Not REINPUT... */
+ i_active = 1;
+ /* Go try to input the search string */
+ success = doinput(x,ms,mp,flags,incount);
+ i_active = 0;
+ } else { /* REINPUT */
+ success = doreinp(x,ms[0],itsapattern);
+ }
+ if (intime[cmdlvl] && !success) { /* TIMEOUT-ACTION = QUIT? */
+ popclvl(); /* If so, pop command level. */
+ if (pflag && cmdlvl == 0) {
+ if (cx == XXINP) printf("?INPUT timed out\n");
+ if (cx == XXMINP) printf("?MINPUT timed out\n");
+ if (cx == XXREI) printf("?REINPUT failed\n");
+ }
+ }
+ return(success); /* Return do(re)input's return code */
+ }
+
+#endif /* NOSPL */
+
+ if (cx == XXLOG) { /* LOG */
+ x = cmkey(logtab,nlog,"What to log","",xxstring);
+ if (x == -3) {
+ printf("?Type of log required\n");
+ return(-9);
+ }
+ if (x < 0) return(x);
+ x = dolog(x);
+ if (x < 0)
+ return(x);
+ else
+ return(success = x);
+ }
+
+ if (cx == XXLOGIN) { /* (REMOTE) LOGIN */
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(success = doftpusr());
+#endif /* NEWFTP */
+#ifdef IKSD
+ if (inserver) {
+ printf("?Already logged in\n");
+ return(-9);
+ } else
+#endif /* IKSD */
+ {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZLGI));
+#endif /* NOXFER */
+ }
+ }
+ if (cx == XXLOGOUT) { /* (REMOTE) LOGOUT */
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(success = doftpres());
+#endif /* NEWFTP */
+
+#ifdef IKSD
+ if (inserver) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ doexit(GOOD_EXIT,xitsta);
+ } else
+#endif /* IKSD */
+ if (!local || (network && ttchk() < 0)) {
+ printf("?No connection.\n");
+ return(-9);
+ } else {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZLGO));
+#endif /* NOXFER */
+ }
+ }
+
+#ifndef NOSCRIPT
+ if (cx == XXLOGI) { /* UUCP-style script */
+ if ((x = cmtxt("expect-send expect-send ...","",&s,xxstring)) < 0)
+ return(x);
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+#ifdef VMS
+ conres(); /* For Ctrl-C to work... */
+#endif /* VMS */
+ return(success = dologin(s)); /* Return 1=completed, 0=failed */
+ }
+#endif /* NOSCRIPT */
+
+#ifndef NOXFER
+#ifdef PIPESEND
+ if (cx == XXCREC) { /* CRECEIVE */
+ if (protocol != PROTO_K) {
+ printf("?Sorry, CRECEIVE works only with Kermit protocol\n");
+ return(-9);
+ } else
+ return(doxget(cx));
+ }
+ if (cx == XXCGET) { /* CGET */
+ return(doxget(cx));
+ }
+#endif /* PIPESEND */
+
+ if (cx == XXREC) /* RECEIVE */
+ return(doxget(cx));
+#endif /* NOXFER */
+
+#ifndef NOXFER
+ if (cx == XXREM) { /* REMOTE */
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(doftprmt(0,0));
+#endif /* NEWFTP */
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("Sorry, REMOTE commands only work with Kermit protocol\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ x = cmkey(remcmd,nrmt,"Remote Kermit server command","",xxstring);
+ if (x == -3) {
+ printf("?You must specify a command for the remote server\n");
+ return(-9);
+ }
+ return(dormt(x));
+ }
+#endif /* NOXFER */
+
+#ifndef NORENAME
+#ifndef NOFRILLS
+ if (cx == XXREN || cx == XXLREN) { /* RENAME */
+#ifdef LOCUS
+ if (!locus && cx != XXLREN) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZREN));
+#endif /* NOXFER */
+ }
+#endif /* LOCUS */
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_ren)
+#ifdef CK_LOGIN
+ || isguest
+#endif /* CK_LOGIN */
+ )) {
+ printf("?Sorry, renaming of files is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+ return(dorenam());
+ }
+#endif /* NOFRILLS */
+#endif /* NORENAME */
+
+ if (cx == XXEIGHT) { /* EIGHTBIT */
+ extern int parity, cmask, cmdmsk;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ parity = 0;
+ cmask = 0xff;
+ cmdmsk = 0xff;
+ return(success = 1);
+ }
+
+#ifndef NOXFER
+/* SEND, CSEND, MOVE, MAIL, and RESEND use the new common code */
+
+ if (cx == XXSEN /* SEND */
+#ifdef PIPESEND
+ || cx == XXCSEN /* CSEND */
+#endif /* PIPESEND */
+ || cx == XXMOVE /* MOVE */
+ || cx == XXMAI /* MAIL */
+#ifdef CK_RESEND
+ || cx == XXRSEN /* RESEND */
+#endif /* CK_RESEND */
+ ) {
+#ifdef IKSD
+ if (inserver && !ENABLED(en_get)) {
+ printf("?Sorry, sending files is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ return(doxsend(cx));
+ }
+
+/* PSEND, ADD, and REMOVE use special parsing */
+
+#ifdef ADDCMD
+ /* ADD and REMOVE */
+ if (cx == XXADD || cx == XXREMV) {
+ char * m;
+ m = (cx == XXADD) ? "Add to which list?" : "Remove from which list?";
+ x = cmkey(addtab,naddtab,m,"",xxstring);
+ if (x < 0)
+ return(x);
+#ifndef NOMSEND
+ if (x == ADD_SND)
+ return(addsend(cx));
+ else
+#endif /* NOMSEND */
+ return(doadd(cx,x));
+ }
+#endif /* ADDCMD */
+
+#ifdef CK_RESEND
+ if (cx == XXPSEN) { /* PSEND */
+ int seekto = 0; /* FIX THIS */
+
+ cmarg = cmarg2 = "";
+ x = cmifi("File to partially send", "", &s, &y, xxstring);
+ if (x < 0) {
+ if (x == -3) {
+ printf("?A file specification is required\n");
+ return(-9);
+ } else return(x);
+ }
+ nfils = -1; /* Files come from internal list. */
+#ifndef NOMSEND
+ addlist = 0; /* Don't use SEND-LIST. */
+ filenext = NULL;
+#endif /* NOMSEND */
+ ckstrncpy(line,s,LINBUFSIZ); /* Save copy of string just parsed. */
+ debug(F110,"PSEND line",line,0);
+ if (y != 0) {
+ printf("?Sorry, wildcards not permitted in this command\n");
+ return(-9);
+ }
+ if (sizeof(int) < 4) {
+ printf("?Sorry, this command needs 32-bit integers\n");
+ return(-9);
+ }
+ x = cmnum("starting position (byte number)",
+ "",10,&seekto,xxstring);
+ if (x < 0)
+ return(x);
+ zfnqfp(s,fspeclen,fspec); /* Get full path */
+ if ((x = cmtxt("Name to send it with","",&s,NULL)) < 0)
+ return(x);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+
+#ifdef IKSD
+ if (inserver && !ENABLED(en_get)) {
+ printf("?Sorry, sending files is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef PIPESEND
+ if (sndfilter) {
+ printf("?Sorry, no PSEND while SEND FILTER selected\n");
+ return(-9);
+ }
+#endif /* PIPESEND */
+#ifdef CK_XYZ
+ if ((protocol == PROTO_X || protocol == PROTO_XC)) {
+ printf("Sorry, PSEND works only with Kermit protocol\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+
+ cmarg2 = brstrip(tmpbuf); /* Strip braces */
+ cmarg = line; /* File to send */
+ debug(F110,"PSEND filename",cmarg,0);
+ debug(F110,"PSEND as-name",cmarg2,0);
+ sendstart = seekto;
+ sstate = 's'; /* Set start state to SEND */
+#ifndef NOMSEND
+ addlist = 0;
+ filenext = NULL;
+#endif /* NOMSEND */
+ sendmode = SM_PSEND;
+#ifdef MAC
+ what = W_SEND;
+ scrcreate();
+#endif /* MAC */
+ if (local) { /* If in local mode, */
+ displa = 1; /* enable file transfer display */
+ }
+ return(0);
+ }
+#endif /* CK_RESEND */
+#endif /* NOXFER */
+
+#ifndef NOXFER
+#ifndef NOMSEND
+ if (cx == XXMSE || cx == XXMMOVE) {
+#ifdef NEWFTP
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(doftpput(cx,0));
+#endif /* NEWFTP */
+#ifdef CK_XYZ
+ if (protocol == PROTO_X || protocol == PROTO_XC) {
+ printf(
+"Sorry, you can only send one file at a time with XMODEM protocol\n"
+ );
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ return(doxsend(cx));
+ }
+
+#ifdef COMMENT /* (moved to doxsend) */
+ if (cx == XXMSE || cx == XXMMOVE) { /* MSEND and MMOVE commands */
+ nfils = 0; /* Like getting a list of */
+ lp = line; /* files on the command line */
+ addlist = 0; /* Do not use SEND-LIST */
+ filenext = NULL; /* Ditto ! */
+
+ while (1) {
+ char *p;
+ if ((x = cmifi("Names of files to send, separated by spaces","",
+ &s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ if (nfils <= 0) {
+ printf("?A file specification is required\n");
+ return(-9);
+ } else break;
+ }
+ return(x);
+ }
+ msfiles[nfils++] = lp; /* Got one, count it, point to it, */
+ p = lp; /* remember pointer, */
+ while (*lp++ = *s++) /* and copy it into buffer */
+ if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
+ printf("?MSEND list too long\n");
+ line[0] = NUL;
+ return(-9);
+ }
+ debug(F111,"msfiles",msfiles[nfils-1],nfils-1);
+ if (nfils == 1) *fspec = NUL; /* Take care of \v(filespec) */
+#ifdef ZFNQFP
+ zfnqfp(p,TMPBUFSIZ,tmpbuf);
+ p = tmpbuf;
+#endif /* ZFNQFP */
+ if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
+ strcat(fspec,p); /* safe */
+ strcat(fspec," "); /* safe */
+ } else printf("WARNING - \\v(filespec) buffer overflow\n");
+ }
+ cmlist = msfiles; /* Point cmlist to pointer array */
+ cmarg2 = ""; /* No internal expansion list (yet) */
+ sndsrc = nfils; /* Filenames come from cmlist */
+ sendmode = SM_MSEND; /* Remember this kind of SENDing */
+ sstate = 's'; /* Set start state for SEND */
+ if (cx == XXMMOVE) /* If MMOVE'ing, */
+ moving = 1; /* set this flag. */
+#ifdef MAC
+ what = W_SEND;
+ scrcreate();
+#endif /* MAC */
+ if (local) { /* If in local mode, */
+ displa = 1; /* turn on file transfer display */
+ ttflui(); /* and flush tty input buffer. */
+ }
+ return(0);
+ }
+#endif /* COMMENT */
+#endif /* NOMSEND */
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+ if (cx == XXSER) { /* SERVER */
+#ifdef CK_XYZ
+ if (protocol != PROTO_K) {
+ printf("Sorry, SERVER only works with Kermit protocol\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+#ifdef COMMENT
+/*
+ Parse for time limit, but since we don't use it yet,
+ the parsing is commented out.
+*/
+ x_ifnum = 1; /* Turn off internal complaints */
+ y = cmnum("optional time limit, seconds, or time of day as hh:mm:ss",
+ "0", 10, &x, xxstring
+ );
+ x_ifnum = 0;
+ if (y < 0) {
+ if (y == -2) { /* Invalid number or expression */
+ zz = tod2sec(atmbuf); /* Convert to secs since midnight */
+ if (zz < 0L) {
+ printf("?Number, expression, or time of day required\n");
+ return(-9);
+ } else {
+ char now[32]; /* Current time */
+ char *p;
+ long tnow;
+ p = now;
+ ztime(&p);
+ tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
+ if (zz < tnow) /* User's time before now */
+ zz += 86400L; /* So make it tomorrow */
+ zz -= tnow; /* Seconds from now. */
+ }
+ } else
+ return(y);
+ }
+ if (zz > -1L) {
+ x = zz;
+ if (zz != (long) x) {
+ printf(
+"Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
+ );
+ return(-9);
+ }
+ }
+ if (x < 0)
+ x = 0;
+#endif /* COMMENT */
+
+ if ((x = cmcfm()) < 0) return(x);
+ sstate = 'x';
+#ifdef MAC
+ what = W_RECV;
+ scrcreate();
+#endif /* MAC */
+ if (local) displa = 1;
+#ifdef AMIGA
+ reqoff(); /* No DOS requestors while server */
+#endif /* AMIGA */
+ return(0);
+ }
+#endif /* NOSERVER */
+
+ if (cx == XXSAVE) { /* SAVE command */
+ x = cmkey(savtab,nsav,"option","keymap",xxstring);
+ if (x == -3) {
+ printf("?You must specify an option to save\n");
+ return(-9);
+ }
+ if (x < 0) return(x);
+ /* have to set success separately for each item in doprm()... */
+ /* actually not really, could have just had doprm return 0 or 1 */
+ /* and set success here... */
+ y = dosave(x);
+ if (y == -3) {
+ printf("?More fields required\n");
+ return(-9);
+ } else return(y);
+ }
+
+ if (cx == XXSET) { /* SET command */
+ x = cmkey(prmtab,nprm,"Parameter","",xxstring);
+ if (x == -3) {
+ printf("?You must specify a parameter to set\n");
+ return(-9);
+ }
+ if (x < 0) return(x);
+ /* have to set success separately for each item in doprm()... */
+ /* actually not really, could have just had doprm return 0 or 1 */
+ /* and set success here... */
+ y = doprm(x,0);
+ if (y == -3) {
+ printf("?More fields required\n");
+ return(-9);
+ } else return(y);
+ }
+
+#ifndef NOPUSH
+ if (cx == XXSHE /* SHELL (system) command */
+ || cx == XXEXEC /* exec() */
+ ) {
+ int rx = 0;
+ char * p = NULL;
+ int i /* ,n */ ;
+#ifdef UNIXOROSK
+ char * args[256];
+#endif /* UNIXOROSK */
+
+#ifdef IKSD
+ if (inserver && (nopush || !ENABLED(en_hos))) {
+ printf("?Sorry, host command access is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+
+#ifdef CKEXEC
+ if (cx == XXEXEC) { /* EXEC (overlay ourselves) */
+ struct FDB sw, fl;
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Command to overlay C-Kermit\n or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 1, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ redirsw, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 2nd FDB - command to exec */
+ _CMFLD, /* fcode */
+ "Command to overlay C-Kermit", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL /* No more after this */
+ );
+ while (1) {
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"exec cmfdb","",x);
+ if (x < 0)
+ return(x);
+ /* Generalize this if we add more switches */
+ if (cmresult.fcode == _CMKEY) {
+ rx = 1;
+ continue;
+ }
+ if (cmresult.fcode == _CMFLD)
+ break;
+ return(-2);
+ }
+ ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
+ if (!tmpbuf[0]) {
+ printf("?Command required\n");
+ return(-9);
+ }
+ p = brstrip(tmpbuf);
+ args[0] = NULL; /* Set argv[0] to it */
+ makestr(&args[0],p);
+ for (i = 1; i < 255; i++) { /* Get arguments for command */
+ if ((x = cmfld("Argument","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ break;
+ } else
+ return(x);
+ }
+ args[i] = NULL;
+ s = brstrip(s);
+ makestr(&args[i],s);
+ }
+ args[i] = NULL;
+ } else {
+#endif /* CKEXEC */
+ if ((x = cmtxt("System command to execute","",&s,xxstring)) < 0)
+ return(x);
+#ifdef CKEXEC
+ }
+#endif /* CKEXEC */
+ if (nopush)
+ return(success = 0);
+#ifdef CK_APC
+ if (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))
+ return(success = 0);
+#endif /* CK_APC */
+ conres(); /* Make console normal */
+#ifdef OS2
+ if (!(s && *s)) {
+ os2push();
+ return(success = 1);
+ } else
+#endif /* OS2 */
+ if (cx == XXSHE) {
+ x = zshcmd(s);
+ debug(F101,"RUN zshcmd code","",x);
+ concb((char)escape);
+ return(success = x);
+#ifdef CKEXEC
+ } else {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"EXEC cmd",p,0);
+ for (i = 0; i < 256 && args[i]; i++)
+ debug(F111,"EXEC arg",args[i],i);
+ }
+#endif /* DEBUG */
+ if (p) {
+ z_exec(p,args,rx); /* Overlay ourself */
+ debug(F100,"EXEC fails","",0);
+ concb((char)escape); /* In case it returns */
+ }
+ return(success = 0);
+#endif /* CKEXEC */
+ }
+ }
+
+#ifdef CK_REDIR
+ if (cx == XXFUN) { /* REDIRECT */
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+ ckmakmsg(tmpbuf,
+ TMPBUFSIZ,
+ "Local command to run,\n",
+ "with its standard input/output redirected to ",
+ local ? ttname : "the communications connection",
+ "\n"
+ );
+ if ((x = cmtxt(tmpbuf,"",&s,xxstring)) < 0)
+ return(x);
+ if (nopush) {
+ printf("?REDIRECT disabled\n");
+ return(success=0);
+ }
+ if (!local) {
+ printf("?SET LINE or SET HOST required first\n");
+ return(-9);
+ }
+ if (!*s) {
+ printf("?REDIRECT requires a command to redirect\n");
+ return(-9);
+ }
+ return(success = ttruncmd(s));
+ }
+#endif /* CK_REDIR */
+#endif /* NOPUSH */
+
+#ifndef NOSHOW
+ if (cx == XXSHO) { /* SHOW */
+ x = cmkey(shotab,nsho,"","parameters",xxstring);
+ if (x < 0) return(x);
+ return(doshow(x));
+ }
+#endif /* NOSHOW */
+
+#ifndef MAC
+ if (cx == XXSPA) { /* SPACE */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_spa)) {
+ printf("?Sorry, SPACE command disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef datageneral
+ /* AOS/VS can take an argument after its "space" command. */
+ if ((x = cmtxt("Confirm, or local directory name","",&s,xxstring)) < 0)
+ return(x);
+ if (nopush) {
+ printf("?Sorry, SPACE command disabled\n");
+ return(-9);
+ } else if (*s == NUL) {
+ xsystem(SPACMD);
+ } else {
+ ckmakmsg(line,LINBUFSIZ,"space ",s,NULL,NULL);
+ xsystem(line);
+ }
+#else
+#ifdef OS2
+ if ((x = cmtxt("Press Enter for current disk,\n\
+ or specify a disk letter like A:","",&s,xxstring)) < 0)
+ return(x);
+ if (*s == NUL) { /* Current disk */
+ unsigned long space = zdskspace(0);
+ if (space > 0 && space < 1024)
+ printf(" Free space: unknown\n");
+ else
+ printf(" Free space: %ldK\n", space/1024L);
+ } else {
+ int drive = toupper(*s);
+ unsigned long space = zdskspace(drive - 'A' + 1);
+ if (space > 0 && space < 1024)
+ printf(" Drive %c: unknown free\n");
+ else
+ printf(" Drive %c: %ldK free\n", drive,space / 1024L);
+ }
+#else
+#ifdef UNIXOROSK
+ x = cmdir("Confirm for current disk,\n\
+ or specify a disk device or directory","",&s,xxstring);
+ if (x == -3)
+ s = "";
+ else if (x < 0)
+ return(x);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0) return(x);
+ if (nopush) {
+ printf("?Sorry, SPACE command disabled\n");
+ return(-9);
+ }
+ if (!*s) { /* Current disk */
+ xsystem(SPACMD);
+ } else { /* Specified disk */
+ ckmakmsg(line,LINBUFSIZ,SPACM2," ",s,NULL);
+ xsystem(line);
+ }
+#else
+ if ((x = cmcfm()) < 0) return(x);
+ if (nopush) {
+ printf("?Sorry, SPACE command disabled\n");
+ return(-9);
+ }
+ xsystem(SPACMD);
+#endif /* UNIXOROSK */
+#endif /* OS2 */
+#endif /* datageneral */
+ return(success = 1); /* Pretend it worked */
+ }
+#endif /* MAC */
+
+#ifndef NOXFER
+ if (cx == XXSTA) { /* STATISTICS */
+ if ((x = cmkey(stattab,2,"Carriage return, or option",
+ "/brief",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ return(success = dostat(x));
+ }
+#endif /* NOXFER */
+
+ if (cx == XXSTO || cx == XXEND) { /* STOP, END, or POP */
+ if ((y = cmnum("exit status code","0",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmtxt("Message to print","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ if (*s) printf("%s\n",s);
+ if (cx == XXSTO) {
+ dostop();
+ } else {
+ doend(x);
+ }
+ return(success = (x == 0));
+ }
+ if (cx == XXSUS) { /* SUSPEND */
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef NOJC
+ printf("Sorry, this version of Kermit cannot be suspended\n");
+#else
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, IKSD can not be suspended\n");
+ return(-9);
+ } else
+#endif /* IKSD */
+ if (nopush) {
+ printf("?Sorry, access to system is disabled\n");
+ return(-9);
+ }
+ stptrap(0);
+#endif /* NOJC */
+ return(0);
+ }
+
+ if (cx == XXTAK) { /* TAKE */
+ char * scriptenv = NULL;
+#ifdef OS2
+ char * GetAppData(int);
+ extern char startupdir[],exedir[],inidir[];
+ char * keymapenv = NULL;
+ char * appdata0 = NULL, *appdata1 = NULL;
+ int xx;
+#define TAKEPATHLEN 4096
+#else /* OS2 */
+#define TAKEPATHLEN 1024
+#endif /* OS2 */
+ char takepath[TAKEPATHLEN];
+
+ if (tlevel >= MAXTAKE-1) {
+ printf("?Take files nested too deeply\n");
+ return(-9);
+ }
+#ifdef OS2
+#ifdef NT
+ scriptenv = getenv("K95SCRIPTS");
+ keymapenv = getenv("K95KEYMAPS");
+ makestr(&appdata0,(char *)GetAppData(0));
+ makestr(&appdata1,(char *)GetAppData(1));
+#else /* NT */
+ scriptenv = getenv("K2SCRIPTS");
+ keymapenv = getenv("K2KEYMAPS");
+#endif /* NT */
+#endif /* OS2 */
+
+ if (!scriptenv) /* Let this work for Unix etc too */
+ scriptenv = getenv("CK_SCRIPTS"); /* Use this if defined */
+#ifndef OS2
+ if (!scriptenv) /* Otherwise use home directory */
+ scriptenv = homepath();
+#endif /* OS2 */
+ if (!scriptenv)
+ scriptenv = "";
+ ckstrncpy(takepath,scriptenv,TAKEPATHLEN);
+ debug(F110,"TAKE initial takepath",takepath,0);
+
+#ifdef OS2
+ if (!keymapenv)
+ keymapenv = getenv("CK_KEYMAPS");
+ if (!keymapenv)
+ keymapenv = "";
+
+ ckstrncat(takepath,
+ (scriptenv && scriptenv[strlen(scriptenv)-1]==';')?"":";",
+ TAKEPATHLEN
+ );
+ ckstrncat(takepath,keymapenv?keymapenv:"",TAKEPATHLEN);
+ ckstrncat(takepath,
+ (keymapenv && keymapenv[strlen(keymapenv)-1]==';')?"":";",
+ TAKEPATHLEN
+ );
+ ckstrncat(takepath,startupdir,TAKEPATHLEN);
+ ckstrncat(takepath,";",TAKEPATHLEN);
+ ckstrncat(takepath,startupdir,TAKEPATHLEN);
+ ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN);
+ ckstrncat(takepath,startupdir,TAKEPATHLEN);
+ ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN);
+
+ ckstrncat(takepath,appdata1,TAKEPATHLEN);
+ ckstrncat(takepath,"Kermit 95/;",TAKEPATHLEN);
+ ckstrncat(takepath,appdata1,TAKEPATHLEN);
+ ckstrncat(takepath,"Kermit 95/SCRIPTS/;",TAKEPATHLEN);
+ ckstrncat(takepath,appdata1,TAKEPATHLEN);
+ ckstrncat(takepath,"Kermit 95/KEYMAPS/;",TAKEPATHLEN);
+
+ ckstrncat(takepath,appdata0,TAKEPATHLEN);
+ ckstrncat(takepath,"Kermit 95/;",TAKEPATHLEN);
+ ckstrncat(takepath,appdata0,TAKEPATHLEN);
+ ckstrncat(takepath,"Kermit 95/SCRIPTS/;",TAKEPATHLEN);
+ ckstrncat(takepath,appdata0,TAKEPATHLEN);
+ ckstrncat(takepath,"Kermit 95/KEYMAPS/;",TAKEPATHLEN);
+
+ ckstrncat(takepath,inidir,TAKEPATHLEN);
+ ckstrncat(takepath,";",TAKEPATHLEN);
+ ckstrncat(takepath,inidir,TAKEPATHLEN);
+ ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN);
+ ckstrncat(takepath,inidir,TAKEPATHLEN);
+ ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN);
+
+ ckstrncat(takepath,zhome(),TAKEPATHLEN);
+ ckstrncat(takepath,";",TAKEPATHLEN);
+ ckstrncat(takepath,zhome(),TAKEPATHLEN);
+ ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN);
+ ckstrncat(takepath,zhome(),TAKEPATHLEN);
+ ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN);
+
+ ckstrncat(takepath,exedir,TAKEPATHLEN);
+ ckstrncat(takepath,";",TAKEPATHLEN);
+ ckstrncat(takepath,exedir,TAKEPATHLEN);
+ ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN);
+ ckstrncat(takepath,exedir,TAKEPATHLEN);
+ ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN);
+#endif /* OS2 */
+ debug(F110,"TAKE final takepath",takepath,0);
+
+ if ((y = cmifip("Commands from file",
+ "",&s,&x,0,takepath,xxstring)) < 0) {
+ if (y == -3) {
+ printf("?A file name is required\n");
+ return(-9);
+ } else
+ return(y);
+ }
+ if (x != 0) {
+ printf("?Wildcards not allowed in command file name\n");
+ return(-9);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ debug(F110,"TAKE file",s,0);
+ if (isdir(s)) {
+ printf("?Can't execute a directory - \"%s\"\n", s);
+ return(-9);
+ }
+#ifndef NOTAKEARGS
+ {
+ char * p;
+ x = strlen(line);
+ debug(F111,"TAKE args",line,x);
+ p = line + x + 1;
+ if ((y = cmtxt("Optional arguments","",&s,xxstring)) < 0)
+ return(y);
+ if (*s) { /* Args given? */
+ ckstrncpy(p,s,LINBUFSIZ-x-1);
+#ifdef ZFNQFP
+ zfnqfp(line,TMPBUFSIZ,tmpbuf);
+ s = tmpbuf;
+#else
+ s = line;
+#endif /* ZFNQFP */
+ debug(F110,"TAKE filename",s,0);
+ x = strlen(s);
+ debug(F101,"TAKE new len",s,x);
+
+#ifdef COMMENT
+/*
+ This was added in C-Kermit 7.0 to allow args to be passed from the TAKE
+ command to the command file. But it overwrites the current argument vector,
+ which is at best surprising, and at worst unsafe.
+*/
+ addmac("%0",s); /* Define %0 = name of file */
+ varnam[0] = '%';
+ varnam[2] = '\0';
+ debug(F110,"take arg 0",s,0);
+ debug(F110,"take args",p,0);
+ for (y = 1; y < 10; y++) { /* Clear current args %1..%9 */
+ varnam[1] = (char) (y + '0');
+ delmac(varnam,0);
+ }
+ xwords(p,MAXARGLIST,NULL,0); /* Assign new args */
+ debug(F110,"take args",p,0);
+#else
+/*
+ This method is used in 8.0. If the TAKE command includes arguments, we
+ insert an intermediate temporary macro between the current level; we pass
+ the arguments to the macro and then the macro TAKEs the command file.
+ If the user Ctrl-C's out of the TAKE file, some temporary macro definitions
+ and other small malloc'd bits might be left behind.
+*/
+ {
+ char * q = NULL;
+ char * r = NULL;
+ int k, m;
+ m = maclvl;
+ q = (char *)malloc(x+24);
+ if (q) {
+ r = (char *)malloc(x+24);
+ if (r) {
+ sprintf(q,"_file[%s](%d)",s,cmdlvl); /* safe */
+ sprintf(r,"take %s",s); /* safe */
+ k = addmac(q,r);
+ if (k > -1) {
+ dodo(k,p,0);
+ while (maclvl > m) {
+ sstate = (CHAR) parser(1);
+ if (sstate) proto();
+ }
+ }
+ k = delmac(q,0);
+ free(q);
+ free(r);
+ return(success);
+ }
+ }
+ }
+ return(success = 0);
+#endif /* COMMENT */
+ }
+ }
+#else
+ if ((y = cmcfm()) < 0) return(y);
+#endif /* NOTAKEARGS */
+ return(success = dotake(line));
+ }
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (cx == XXVIEW) { /* VIEW Only Terminal mode */
+ viewonly = TRUE;
+ success = doconect(0, 0);
+ viewonly = FALSE;
+ return success;
+ }
+#endif /* OS2 */
+
+#ifdef NETCONN
+ if (cx == XXTEL || cx == XXIKSD) { /* TELNET */
+ int x,z;
+#ifdef OS2
+ if (!tcp_avail) {
+ printf("?Sorry, either TCP/IP is not available on this system or\n\
+necessary DLLs did not load. Use SHOW NETWORK to check network status.\n");
+ success = 0;
+ return(-9);
+ } else
+#endif /* OS2 */
+ {
+ x = nettype; /* Save net type in case of failure */
+ z = ttnproto; /* Save protocol in case of failure */
+ nettype = NET_TCPB;
+ ttnproto = (cx == XXTEL) ? NP_TELNET : NP_KERMIT;
+ if ((y = setlin(XYHOST,0,1)) <= 0) {
+ nettype = x; /* Failed, restore net type. */
+ ttnproto = z; /* and protocol */
+ success = 0;
+ }
+ didsetlin++;
+ }
+ return(y);
+ }
+
+#ifndef PTYORPIPE
+#ifdef NETCMD
+#define PTYORPIPE
+#else
+#ifdef NETPTY
+#define PTYORPIPE
+#endif /* NETPTY */
+#endif /* NETCMD */
+#endif /* PTYORPIPE */
+
+#ifdef PTYORPIPE
+ if (cx == XXPIPE || cx == XXPTY) { /* PIPE or PTY */
+ int x;
+ extern int netsave;
+ x = nettype; /* Save net type in case of failure */
+ nettype = (cx == XXPIPE) ? NET_CMD : NET_PTY;
+ if ((y = setlin(XYHOST,0,1)) < 0) {
+ nettype = x; /* Failed, restore net type. */
+ ttnproto = z; /* and protocol */
+ success = 0;
+ }
+ didsetlin++;
+ netsave = x;
+ return(y);
+ }
+#endif /* PTYORPIPE */
+
+#ifdef ANYSSH
+ if (cx == XXSSH) { /* SSH (Secure Shell) */
+ extern int netsave;
+#ifdef SSHBUILTIN
+ int k, x, havehost = 0, trips = 0;
+ int tmpver = -1, tmpxfw = -1;
+#ifndef SSHTEST
+ extern int sl_ssh_xfw, sl_ssh_xfw_saved;
+ extern int sl_ssh_ver, sl_ssh_ver_saved;
+#endif /* SSHTEST */
+ extern int mdmtyp, mdmsav, cxtype, sl_uid_saved;
+ extern char * slmsg;
+ extern char uidbuf[], sl_uidbuf[];
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+ struct FDB sw, kw, fl;
+
+ if (ssh_tmpstr)
+ memset(ssh_tmpstr,0,strlen(ssh_tmpstr));
+ makestr(&ssh_tmpstr,NULL);
+ makestr(&ssh_tmpuid,NULL);
+ makestr(&ssh_tmpcmd,NULL);
+ makestr(&ssh_tmpport,NULL);
+
+ cmfdbi(&kw, /* 1st FDB - commands */
+ _CMKEY, /* fcode */
+ "host [ port ],\n or action", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nsshcmd, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ sshkwtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Host */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ x = cmfdb(&kw);
+ if (x == -3) {
+ printf("?ssh what?\n");
+ return(-9);
+ }
+ if (x < 0)
+ return(x);
+ havehost = 0;
+ if (cmresult.fcode == _CMFLD) {
+ havehost = 1;
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Hostname */
+ cmresult.nresult = XSSH_OPN;
+ }
+ switch (cmresult.nresult) { /* SSH keyword */
+ case XSSH_OPN: /* SSH OPEN */
+ if (!havehost) {
+ if ((x = cmfld("Host","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ }
+ /* Parse [ port ] [ switches ] */
+ cmfdbi(&kw, /* Switches */
+ _CMKEY,
+ "Port number or service name,\nor switch",
+ "",
+ "",
+ nsshopnsw,
+ 4,
+ xxstring,
+ sshopnsw,
+ &fl
+ );
+ cmfdbi(&fl, /* Port number or service name */
+ _CMFLD,
+ "",
+ "",
+ "",
+ 0,
+ 0,
+ xxstring,
+ NULL,
+ NULL
+ );
+ trips = 0; /* Explained below */
+ while (1) { /* Parse port and switches */
+ x = cmfdb(&kw); /* Get a field */
+ if (x == -3) /* User typed CR so quit from loop */
+ break;
+ if (x < 0) /* Other parse error, pass it back */
+ return(x);
+ switch (cmresult.fcode) { /* Field or Keyword? */
+ case _CMFLD: /* Field */
+ makestr(&ssh_tmpport,cmresult.sresult);
+ break;
+ case _CMKEY: /* Keyword */
+ switch (cmresult.nresult) { /* Which one? */
+ case SSHSW_USR: /* /USER: */
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((y = cmfld("Username","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ makestr(&ssh_tmpuid,s);
+ break;
+ case SSHSW_PWD:
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ debok = 0;
+ if ((x = cmfld("Password","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&ssh_tmpstr,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&ssh_tmpstr,s);
+ }
+ break;
+
+ case SSHSW_VER:
+ if ((x = cmnum("Number","",10,&z,xxstring)) < 0)
+ return(x);
+ if (z < 1 || z > 2) {
+ printf("?Out of range: %d\n",z);
+ return(-9);
+ }
+ tmpver = z;
+ break;
+ case SSHSW_CMD:
+ case SSHSW_SUB:
+ if ((x = cmfld("Text","",&s,xxstring)) < 0)
+ return(x);
+ makestr(&ssh_tmpcmd,s);
+ ssh_cas = (cmresult.nresult == SSHSW_SUB);
+ break;
+ case SSHSW_X11:
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(x);
+ tmpxfw = x;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ if (trips++ == 0) { /* After first time through */
+ cmfdbi(&kw, /* only parse switches, not port. */
+ _CMKEY,
+ "Switch",
+ "",
+ "",
+ nsshopnsw,
+ 4,
+ xxstring,
+ sshopnsw,
+ NULL
+ );
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (clskconnx(1) < 0) { /* Close current Kermit connection */
+ if ( ssh_tmpstr ) {
+ memset(ssh_tmpstr,0,strlen(ssh_tmpstr));
+ makestr(&ssh_tmpstr,NULL);
+ }
+ return(success = 0);
+ }
+ makestr(&ssh_hst,line); /* Stash everything */
+ if (ssh_tmpuid) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,ssh_tmpuid,UIDBUFLEN);
+ makestr(&ssh_tmpuid,NULL);
+ }
+ if (ssh_tmpport) {
+ makestr(&ssh_prt,ssh_tmpport);
+ makestr(&ssh_tmpport,NULL);
+ } else
+ makestr(&ssh_prt,NULL);
+
+ if (ssh_tmpcmd) {
+ makestr(&ssh_cmd,brstrip(ssh_tmpcmd));
+ makestr(&ssh_tmpcmd,NULL);
+ } else
+ makestr(&ssh_cmd,NULL);
+
+ if (tmpver > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_ver_saved) {
+ sl_ssh_ver = ssh_ver;
+ sl_ssh_ver_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_ver = tmpver;
+ }
+ if (tmpxfw > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_xfw_saved) {
+ sl_ssh_xfw = ssh_xfw;
+ sl_ssh_xfw_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_xfw = tmpxfw;
+ }
+ if (ssh_tmpstr) {
+ if (ssh_tmpstr[0]) {
+ ckstrncpy(pwbuf,ssh_tmpstr,PWBUFL+1);
+ pwflg = 1;
+ pwcrypt = 0;
+ } else
+ pwflg = 0;
+ makestr(&ssh_tmpstr,NULL);
+ }
+ nettype = NET_SSH;
+ if (mdmsav < 0)
+ mdmsav = mdmtyp;
+ mdmtyp = -nettype;
+ x = 1;
+
+#ifndef NOSPL
+ makestr(&g_pswd,pwbuf); /* Save global pwbuf */
+ g_pflg = pwflg; /* and flag */
+ g_pcpt = pwcrypt;
+#endif /* NOSPL */
+
+ /* Line parameter to ttopen() is ignored */
+ debug(F110,"SSH line",line,0);
+ k = ttopen(line,&x,mdmtyp, 0);
+ if (k < 0) {
+ printf("?Unable to connect to %s\n",ssh_hst);
+ mdmtyp = mdmsav;
+ slrestor();
+ return(success = 0);
+ }
+ duplex = 0; /* Remote echo */
+ ckstrncpy(ttname,line,TTNAMLEN); /* Record the command */
+ debug(F110,"ssh ttname",ttname,0);
+ makestr(&slmsg,NULL); /* No SET LINE error message */
+ cxtype = CXT_SSH;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ success = 1; /* SET LINE succeeded */
+ network = 1; /* Network connection (not serial) */
+ local = 1; /* Local mode (not remote) */
+ if ((reliable != SET_OFF || !setreliable))
+ reliable = SET_ON; /* Transport is reliable end to end */
+#ifdef OS2
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+#endif /* OS2 */
+ setflow(); /* Set appropriate flow control */
+
+ haveline = 1;
+#ifdef CKLOGDIAL
+#ifdef NETCONN
+ dolognet();
+#endif /* NETCONN */
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ssh_hst,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+#ifdef LOCUS
+ if (autolocus)
+ setlocus(1,1);
+#endif /* LOCUS */
+
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+ if (cmdlvl > 0)
+ prepop();
+ success = doconect(0,cmdlvl == 0 ? 1 : 0);
+ if (ttchk() < 0)
+ dologend();
+ return(success);
+
+ case XSSH_CLR:
+ if ((y = cmkey(sshclr,nsshclr,"","", xxstring)) < 0) {
+ if (y == -3) {
+ printf("?clear what?\n");
+ return(-9);
+ }
+ return(y);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ switch (y) {
+ case SSHC_LPF:
+ ssh_pf_lcl_n = 0;
+ break;
+ case SSHC_RPF:
+ ssh_pf_rmt_n = 0;
+ break;
+ default:
+ return(-2);
+ }
+ return(success = 1); /* or whatever */
+
+ case XSSH_AGT: { /* SSH AGENT */
+ int doeach = 0;
+ if ((y = cmkey(sshagent,nsshagent,"","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case SSHA_ADD: /* SSH AGENT ADD ... */
+ if ((x = cmifi("Identity file","",&s,&y,xxstring)) < 0) {
+#ifndef SSHTEST
+ if (x == -3) /* No name given */
+ doeach = 1; /* so do them all */
+ else
+#endif /* SSHTEST */
+ return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef SSHTEST
+ x = 0;
+#else
+ if (doeach) {
+ int i;
+ x = 0;
+ for (i = 0; i < ssh_idf_n; i++)
+ x += ssh_agent_add_file(ssh_idf[i]);
+ } else
+ x = ssh_agent_add_file(line);
+#endif /* SSHTEST */
+ return(success = (x == 0));
+
+ case SSHA_DEL: { /* SSH AGENT DELETE ... */
+ int doall = 0;
+ if ((x = cmifi("Identity file","",&s,&y,xxstring)) < 0) {
+#ifndef SSHTEST
+ if (x == -3) /* No name given */
+ doall = 1; /* so do them all */
+ else
+#endif /* SSHTEST */
+ return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef SSHTEST
+ x = 0;
+#else
+ if (doall)
+ x = ssh_agent_delete_all();
+ else
+ x = ssh_agent_delete_file(line);
+#endif /* SSHTEST */
+ return(success = (x == 0));
+ }
+ case SSHA_LST: {
+ int fingerprint = 0;
+ if ((y = cmswi(sshagtsw,nsshagtsw,"","",xxstring)) < 0) {
+ if (y != -3)
+ return(y);
+ } else if (cmgbrk() > SP) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ } else if (y == SSHASW_FP) {
+ fingerprint = 1;
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef SSHTEST
+ return(success = 1);
+#else
+ return(success =
+ (ssh_agent_list_identities(fingerprint) == 0));
+#endif /* SSHTEST */
+ }
+ default:
+ return(-2);
+ }
+ }
+ case XSSH_ADD: { /* SSH ADD */
+ /* ssh add { local, remote } port host port */
+ int cx, i, j, k;
+ char * h;
+ if ((cx = cmkey(addfwd,naddfwd,"","", xxstring)) < 0)
+ return(cx);
+ if ((x = cmnum((cx == SSHF_LCL) ?
+ "Local port number" : "Remote port number",
+ "",10,&j,xxstring)) < 0)
+ return(x);
+ if ((x = cmfld("Host","",&s,xxstring)) < 0)
+ return(x);
+ makestr(&h,s);
+ if ((x = cmnum("Port","",10,&k,xxstring)) < 0)
+ return(x);
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ switch(cx) {
+ case SSHF_LCL:
+ if (ssh_pf_lcl_n == 32) {
+ printf(
+"?Maximum number of local port forwardings already specified\n"
+ );
+ free(h);
+ return(success = 0);
+ }
+ ssh_pf_lcl[ssh_pf_lcl_n].p1 = j;
+ makestr(&(ssh_pf_lcl[ssh_pf_lcl_n].host),h);
+ makestr(&h,NULL);
+ ssh_pf_lcl[ssh_pf_lcl_n].p2 = k;
+ ssh_pf_lcl_n++;
+ break;
+ case SSHF_RMT:
+ if (ssh_pf_rmt_n == 32) {
+ printf(
+"?Maximum number of remote port forwardings already specified\n"
+ );
+ free(h);
+ return(success = 0);
+ }
+ ssh_pf_rmt[ssh_pf_rmt_n].p1 = j;
+ makestr(&(ssh_pf_rmt[ssh_pf_rmt_n].host),h);
+ makestr(&h,NULL);
+ ssh_pf_rmt[ssh_pf_rmt_n].p2 = k;
+ ssh_pf_rmt_n++;
+ }
+ return(success = 1);
+ }
+ /* Not supporting arbitrary forwarding yet */
+ case XSSH_FLP: /* SSH FORWARD-LOCAL-PORT */
+ case XSSH_FRP: { /* SSH FORWARD-REMOTE-PORT */
+ int li_port = 0;
+ int to_port = 0;
+ char * fw_host = NULL;
+ int n;
+ if ((x = cmnum(cmresult.nresult == XSSH_FLP ?
+ "local-port":"remote-port",
+ "",10,&li_port,xxstring)) < 0)
+ return(x);
+ if (li_port < 1 || li_port > 65535) {
+ printf("?Out range - min: 1, max: 65535\n");
+ return(-9);
+ }
+ if ((x = cmfld("host",ssh_hst?ssh_hst:"",&s,xxstring)) < 0)
+ return(x);
+ n = ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ fw_host = tmpbuf;
+ if ((x = cmnum("host-port",ckuitoa(li_port),10,
+ &to_port,xxstring)) < 0)
+ return(x);
+ if (to_port < 1 || to_port > 65535) {
+ printf("?Out range - min: 1, max: 65535\n");
+ return(-9);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ switch (cmresult.nresult) {
+ case XSSH_FLP: /* SSH FORWARD-LOCAL-PORT */
+#ifndef SSHTEST
+ ssh_fwd_local_port(li_port,fw_host,to_port);
+#endif /* SSHTEST */
+ return(success = 1);
+ case XSSH_FRP: /* SSH FORWARD-REMOTE-PORT */
+#ifndef SSHTEST
+ ssh_fwd_remote_port(li_port,fw_host,to_port);
+#endif /* SSHTEST */
+ return(success = 1);
+ }
+ return(success = 1);
+ }
+ case XSSH_V2: /* SSH V2 */
+ if ((cx = cmkey(ssh2tab,nssh2tab,"","", xxstring)) < 0)
+ return(cx);
+ switch (cx) {
+ case XSSH2_RKE:
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifndef SSHTEST
+ ssh_v2_rekey();
+#endif /* SSHTEST */
+ return(success = 1);
+ default:
+ return(-2);
+ }
+ case XSSH_KEY:
+ if ((cx = cmkey(sshkey,nsshkey,"","", xxstring)) < 0)
+ return(cx);
+ switch (cx) {
+ case SSHK_PASS: { /* Change passphrase */
+ char * oldp = NULL, * newp = NULL;
+ struct FDB df, sw;
+ cmfdbi(&sw,
+ _CMKEY, /* fcode */
+ "Filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 2, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ sshkpsw, /* Keyword table */
+ &df /* Pointer to next FDB */
+ );
+ cmfdbi(&df, /* 2nd FDB - file for display */
+ _CMIFI, /* output file */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ line[0] = NUL;
+
+ while (1) {
+ x = cmfdb(&sw);
+ if (x == -3) break;
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY)
+ break;
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((y = cmfld("Passphrase","",&s,xxstring)) < 0)
+ return(y);
+ switch (cmresult.nresult) {
+ case 1: /* Old */
+ makestr(&oldp,s);
+ break;
+ case 2: /* New */
+ makestr(&newp,s);
+ }
+ }
+ if (cmresult.fcode == _CMIFI) { /* Filename */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ if ((x = cmcfm()) < 0) return(x);
+
+#ifndef SSHTEST
+ x = sshkey_change_passphrase(line[0] ? line : NULL,
+ oldp, newp);
+#endif /* SSHTEST */
+ makestr(&oldp,NULL);
+ makestr(&newp,NULL);
+ success = (x == 0);
+ return(success);
+ }
+ case SSHK_CREA: { /* SSH KEY CREATE /switches... */
+ int bits = 1024, keytype = SSHKT_2R;
+ char * pass = NULL, * comment = NULL;
+ struct FDB df, sw;
+
+ /*
+ * char * sshkey_default_file(int keytype)
+ * will provide the default filename for a given keytype
+ * is it possible to have the default value for the 2nd
+ * FDB set and changed when a /TYPE switch is provided?
+ * Would this allow for tab completion of the filename?
+ */
+ cmfdbi(&sw,
+ _CMKEY, /* fcode */
+ "Filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nsshkcrea, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ sshkcrea, /* Keyword table */
+ &df /* Pointer to next FDB */
+ );
+ cmfdbi(&df, /* 2nd FDB - file for display */
+ _CMOFI, /* output file */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ line[0] = NUL;
+
+ while (1) {
+ x = cmfdb(&sw);
+ if (x == -3) break;
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY)
+ break;
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case SSHKC_BI: /* /BITS:n */
+ if ((y = cmnum("","1024",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 512 || z > 4096) {
+ printf("?Out range - min: 512, max: 4096\n");
+ return(-9);
+ }
+ bits = z;
+ break;
+ case SSHKC_PP: /* /PASSPHRASE:blah */
+ if ((y = cmfld("Passphrase","",&s,xxstring)) < 0)
+ return(y);
+ makestr(&pass,s);
+ break;
+ case SSHKC_TY: /* /TYPE:keyword */
+ if ((y = cmkey(sshkcty,nsshkcty,"",
+ "v2-rsa",xxstring)) < 0)
+ return(y);
+ keytype = y;
+ break;
+ case SSHKC_1R: /* /COMMENT */
+ if ((y = cmfld("Text","",&s,xxstring)) < 0)
+ return(y);
+ makestr(&comment,s);
+ break;
+ }
+ }
+ if (cmresult.fcode == _CMOFI) { /* Filename */
+ if (cmresult.sresult) {
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ }
+ if ((y = cmcfm()) < 0) /* Confirm */
+ return(y);
+#ifndef SSHTEST
+ x = sshkey_create(line[0] ? line : NULL,
+ bits, pass, keytype, comment);
+ if (pass)
+ memset(pass,0,strlen(pass));
+#endif /* SSHTEST */
+ makestr(&pass,NULL);
+ makestr(&comment,NULL);
+ return(success = (x == 0));
+ }
+ case SSHK_DISP: { /* SSH KEY DISPLAY /switches... */
+ char c;
+ int infmt = 0, outfmt = 0;
+ struct FDB df, sw;
+ cmfdbi(&sw,
+ _CMKEY, /* fcode */
+ "Filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nsshdswi, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ sshdswi, /* Keyword table */
+ &df /* Pointer to next FDB */
+ );
+ cmfdbi(&df, /* 2nd FDB - file for display */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ line[0] = NUL;
+
+ while (1) {
+ x = cmfdb(&sw);
+ if (x == -3) break;
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY)
+ break;
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+#ifdef COMMENT
+ case SSHKD_IN: /* /IN-FORMAT: */
+ if ((y = cmkey(sshdifmt,nsshdifmt,
+ "","",xxstring)) < 0)
+ return(y);
+ infmt = y;
+ break;
+#endif /* COMMENT */
+ case SSHKD_OUT: /* /FORMAT: */
+ if ((y = cmkey(sshdofmt,nsshdofmt,
+ "","",xxstring)) < 0)
+ return(y);
+ outfmt = y;
+ break;
+ }
+ }
+ if (cmresult.fcode == _CMIFI) { /* Filename */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+#ifdef COMMENT
+ if (!line[0]) {
+ printf("?Key filename required\n");
+ return(-9);
+ }
+#endif /* COMMENT */
+ if ((y = cmcfm()) < 0) /* Confirm */
+ return(y);
+#ifndef SSHTEST
+ switch (outfmt) {
+ case SKDF_OSSH:
+ /* 2nd param is optional passphrase */
+ x = sshkey_display_public(line[0] ? line : NULL, NULL);
+ break;
+ case SKDF_SSHC:
+ /* 2nd param is optional passphrase */
+ x = sshkey_display_public_as_ssh2(line[0] ? line : NULL,
+ NULL);
+ break;
+ case SKDF_IETF:
+ x = sshkey_display_fingerprint(line[0] ? line : NULL, 1);
+ break;
+ case SKDF_FING:
+ x = sshkey_display_fingerprint(line[0] ? line : NULL, 0);
+ break;
+ }
+#endif /* SSHTEST */
+ return(success = (x == 0));
+ }
+ case SSHK_V1: /* SSH KEY V1 SET-COMMENT */
+ if ((x = cmkey(sshkv1,1,"","set-comment", xxstring)) < 0)
+ return(x);
+ if (x != 1) return(-2);
+ if ((x = cmifi("Key file name","",&s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of key file required\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ if ((x = cmtxt("Comment text","",&s,xxstring)) < 0)
+ return(x);
+#ifndef SSHTEST
+ x = sshkey_v1_change_comment(line, /* filename */
+ s, /* new comment */
+ NULL /* passphrase */
+ );
+#endif /* SSHTEST */
+ success = (x == 0);
+ return(success);
+ }
+ default:
+ return(-2);
+ }
+#else /* SSHBUILTIN */
+#ifdef SSHCMD
+ x = nettype;
+ if ((y = setlin(XXSSH,0,1)) < 0) {
+ if (errno)
+ printf("?%s\n",ck_errstr());
+ else
+#ifdef COMMENT
+ /* This isn't right either because it catches command editing */
+ printf("?Sorry, pseudoterminal open failed\n");
+ if (hints)
+ printf("Hint: Try \"ssh -t %s\"\n",line);
+#else
+ return(y);
+#endif /* COMMENT */
+ nettype = x; /* Failed, restore net type. */
+ ttnproto = z; /* and protocol */
+ success = 0;
+ }
+ didsetlin++;
+ netsave = x;
+ return(y);
+#endif /* SSHCMD */
+#endif /* SSHBUILTIN */
+ }
+#endif /* ANYSSH */
+
+#ifdef SSHBUILTIN
+ if (cx == XXSKRM) { /* SKERMIT (Secure Shell Kermit) */
+ extern int netsave;
+ int k, x, havehost = 0, trips = 0;
+ int tmpver = -1, tmpxfw = -1;
+#ifndef SSHTEST
+ extern int sl_ssh_xfw, sl_ssh_xfw_saved;
+ extern int sl_ssh_ver, sl_ssh_ver_saved;
+#endif /* SSHTEST */
+ extern int mdmtyp, mdmsav, cxtype, sl_uid_saved;
+ extern char * slmsg;
+ extern char uidbuf[], sl_uidbuf[];
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+ struct FDB sw, kw, fl;
+
+ if (ssh_tmpstr)
+ memset(ssh_tmpstr,0,strlen(ssh_tmpstr));
+ makestr(&ssh_tmpstr,NULL);
+ makestr(&ssh_tmpuid,NULL);
+ makestr(&ssh_tmpcmd,NULL);
+ makestr(&ssh_tmpport,NULL);
+
+ cmfdbi(&kw, /* 1st FDB - commands */
+ _CMKEY, /* fcode */
+ "host [ port ],\n or action", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nsshkermit, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ sshkermit, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Host */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ x = cmfdb(&kw);
+ if (x == -3) {
+ printf("?skermit what?\n");
+ return(-9);
+ }
+ if (x < 0)
+ return(x);
+ havehost = 0;
+ if (cmresult.fcode == _CMFLD) {
+ havehost = 1;
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Hostname */
+ cmresult.nresult = SKRM_OPN;
+ }
+ switch (cmresult.nresult) { /* SSH keyword */
+ case SKRM_OPN: /* SSH OPEN */
+ if (!havehost) {
+ if ((x = cmfld("Host","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ }
+ /* Parse [ port ] [ switches ] */
+ cmfdbi(&kw, /* Switches */
+ _CMKEY,
+ "Port number or service name,\nor switch",
+ "",
+ "",
+ nsshkrmopnsw,
+ 4,
+ xxstring,
+ sshkrmopnsw,
+ &fl
+ );
+ cmfdbi(&fl, /* Port number or service name */
+ _CMFLD,
+ "",
+ "",
+ "",
+ 0,
+ 0,
+ xxstring,
+ NULL,
+ NULL
+ );
+ trips = 0; /* Explained below */
+ while (1) { /* Parse port and switches */
+ x = cmfdb(&kw); /* Get a field */
+ if (x == -3) /* User typed CR so quit from loop */
+ break;
+ if (x < 0) /* Other parse error, pass it back */
+ return(x);
+ switch (cmresult.fcode) { /* Field or Keyword? */
+ case _CMFLD: /* Field */
+ makestr(&ssh_tmpport,cmresult.sresult);
+ break;
+ case _CMKEY: /* Keyword */
+ switch (cmresult.nresult) { /* Which one? */
+ case SSHSW_USR: /* /USER: */
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((y = cmfld("Username","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ makestr(&ssh_tmpuid,s);
+ break;
+ case SSHSW_PWD:
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ debok = 0;
+ if ((x = cmfld("Password","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&ssh_tmpstr,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&ssh_tmpstr,s);
+ }
+ break;
+
+ case SSHSW_VER:
+ if ((x = cmnum("Number","",10,&z,xxstring)) < 0)
+ return(x);
+ if (z < 1 || z > 2) {
+ printf("?Out of range: %d\n",z);
+ return(-9);
+ }
+ tmpver = z;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ if (trips++ == 0) { /* After first time through */
+ cmfdbi(&kw, /* only parse switches, not port. */
+ _CMKEY,
+ "Switch",
+ "",
+ "",
+ nsshkrmopnsw,
+ 4,
+ xxstring,
+ sshkrmopnsw,
+ NULL
+ );
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (clskconnx(1) < 0) { /* Close current Kermit connection */
+ if ( ssh_tmpstr ) {
+ memset(ssh_tmpstr,0,strlen(ssh_tmpstr));
+ makestr(&ssh_tmpstr,NULL);
+ }
+ return(success = 0);
+ }
+ makestr(&ssh_hst,line); /* Stash everything */
+ if (ssh_tmpuid) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,ssh_tmpuid,UIDBUFLEN);
+ makestr(&ssh_tmpuid,NULL);
+ }
+ if (ssh_tmpport) {
+ makestr(&ssh_prt,ssh_tmpport);
+ makestr(&ssh_tmpport,NULL);
+ } else
+ makestr(&ssh_prt,NULL);
+
+ /* Set the Subsystem to Kermit */
+ ssh_cas = 1;
+ makestr(&ssh_cmd,"kermit");
+
+ if (tmpver > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_ver_saved) {
+ sl_ssh_ver = ssh_ver;
+ sl_ssh_ver_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_ver = tmpver;
+ }
+ /* Disable X11 Forwarding */
+#ifndef SSHTEST
+ if (!sl_ssh_xfw_saved) {
+ sl_ssh_xfw = ssh_xfw;
+ sl_ssh_xfw_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_xfw = 0;
+
+ if (ssh_tmpstr) {
+ if (ssh_tmpstr[0]) {
+ ckstrncpy(pwbuf,ssh_tmpstr,PWBUFL+1);
+ pwflg = 1;
+ pwcrypt = 0;
+ } else
+ pwflg = 0;
+ makestr(&ssh_tmpstr,NULL);
+ }
+ nettype = NET_SSH;
+ if (mdmsav < 0)
+ mdmsav = mdmtyp;
+ mdmtyp = -nettype;
+ x = 1;
+
+#ifndef NOSPL
+ makestr(&g_pswd,pwbuf); /* Save global pwbuf */
+ g_pflg = pwflg; /* and flag */
+ g_pcpt = pwcrypt;
+#endif /* NOSPL */
+
+ /* Line parameter to ttopen() is ignored */
+ k = ttopen(line,&x,mdmtyp, 0);
+ if (k < 0) {
+ printf("?Unable to connect to %s\n",ssh_hst);
+ mdmtyp = mdmsav;
+ slrestor();
+ return(success = 0);
+ }
+ duplex = 0; /* Remote echo */
+ ckstrncpy(ttname,line,TTNAMLEN); /* Record the command */
+ debug(F110,"ssh ttname",ttname,0);
+ makestr(&slmsg,NULL); /* No SET LINE error message */
+ cxtype = CXT_SSH;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ success = 1; /* SET LINE succeeded */
+ network = 1; /* Network connection (not serial) */
+ local = 1; /* Local mode (not remote) */
+ if ((reliable != SET_OFF || !setreliable))
+ reliable = SET_ON; /* Transport is reliable end to end */
+#ifdef OS2
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+#endif /* OS2 */
+ setflow(); /* Set appropriate flow control */
+
+ haveline = 1;
+#ifdef CKLOGDIAL
+#ifdef NETCONN
+ dolognet();
+#endif /* NETCONN */
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ssh_hst,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+#ifdef LOCUS
+ if (autolocus)
+ setlocus(1,1);
+#endif /* LOCUS */
+
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+ if (cmdlvl > 0)
+ prepop();
+ return(success = 1);
+
+ default:
+ return(-2);
+ }
+ }
+#endif /* SSHBUILTIN */
+
+#ifdef SFTP_BUILTIN
+ if (cx == XXSFTP) { /* SFTP (Secure Shell File Transfer) */
+ extern int netsave;
+ int k, x, havehost = 0, trips = 0;
+ int tmpver = -1, tmpxfw = -1;
+#ifndef SSHTEST
+ extern int sl_ssh_xfw, sl_ssh_xfw_saved;
+ extern int sl_ssh_ver, sl_ssh_ver_saved;
+#endif /* SSHTEST */
+ extern int mdmtyp, mdmsav, cxtype, sl_uid_saved;
+ extern char * slmsg;
+ extern char uidbuf[], sl_uidbuf[];
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+ struct FDB sw, kw, fl;
+
+ if (ssh_tmpstr)
+ memset(ssh_tmpstr,0,strlen(ssh_tmpstr));
+ makestr(&ssh_tmpstr,NULL);
+ makestr(&ssh_tmpuid,NULL);
+ makestr(&ssh_tmpcmd,NULL);
+ makestr(&ssh_tmpport,NULL);
+
+ cmfdbi(&kw, /* 1st FDB - commands */
+ _CMKEY, /* fcode */
+ "host [ port ],\n or action", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nsftpkwtab, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ sftpkwtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Host */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ x = cmfdb(&kw);
+ if (x == -3) {
+ printf("?sftp what?\n");
+ return(-9);
+ }
+ if (x < 0)
+ return(x);
+ havehost = 0;
+ if (cmresult.fcode == _CMFLD) {
+ havehost = 1;
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Hostname */
+ cmresult.nresult = SFTP_OPN;
+ }
+ switch (cmresult.nresult) { /* SFTP keyword */
+ case SFTP_OPN: /* SFTP OPEN */
+ if (!havehost) {
+ if ((x = cmfld("Host","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ }
+ /* Parse [ port ] [ switches ] */
+ cmfdbi(&kw, /* Switches */
+ _CMKEY,
+ "Port number or service name,\nor switch",
+ "",
+ "",
+ nsshkrmopnsw,
+ 4,
+ xxstring,
+ sshkrmopnsw,
+ &fl
+ );
+ cmfdbi(&fl, /* Port number or service name */
+ _CMFLD,
+ "",
+ "",
+ "",
+ 0,
+ 0,
+ xxstring,
+ NULL,
+ NULL
+ );
+ trips = 0; /* Explained below */
+ while (1) { /* Parse port and switches */
+ x = cmfdb(&kw); /* Get a field */
+ if (x == -3) /* User typed CR so quit from loop */
+ break;
+ if (x < 0) /* Other parse error, pass it back */
+ return(x);
+ switch (cmresult.fcode) { /* Field or Keyword? */
+ case _CMFLD: /* Field */
+ makestr(&ssh_tmpport,cmresult.sresult);
+ break;
+ case _CMKEY: /* Keyword */
+ switch (cmresult.nresult) { /* Which one? */
+ case SSHSW_USR: /* /USER: */
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((y = cmfld("Username","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ makestr(&ssh_tmpuid,s);
+ break;
+ case SSHSW_PWD:
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ debok = 0;
+ if ((x = cmfld("Password","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&ssh_tmpstr,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&ssh_tmpstr,s);
+ }
+ break;
+
+ case SSHSW_VER:
+ if ((x = cmnum("Number","",10,&z,xxstring)) < 0)
+ return(x);
+ if (z < 1 || z > 2) {
+ printf("?Out of range: %d\n",z);
+ return(-9);
+ }
+ tmpver = z;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ if (trips++ == 0) { /* After first time through */
+ cmfdbi(&kw, /* only parse switches, not port. */
+ _CMKEY,
+ "Switch",
+ "",
+ "",
+ nsshkrmopnsw,
+ 4,
+ xxstring,
+ sshkrmopnsw,
+ NULL
+ );
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (clskconnx(1) < 0) { /* Close current Kermit connection */
+ if ( ssh_tmpstr ) {
+ memset(ssh_tmpstr,0,strlen(ssh_tmpstr));
+ makestr(&ssh_tmpstr,NULL);
+ }
+ return(success = 0);
+ }
+ makestr(&ssh_hst,line); /* Stash everything */
+ if (ssh_tmpuid) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,ssh_tmpuid,UIDBUFLEN);
+ makestr(&ssh_tmpuid,NULL);
+ }
+ if (ssh_tmpport) {
+ makestr(&ssh_prt,ssh_tmpport);
+ makestr(&ssh_tmpport,NULL);
+ } else
+ makestr(&ssh_prt,NULL);
+
+ /* Set the Subsystem to Kermit */
+ ssh_cas = 1;
+ makestr(&ssh_cmd,"sftp");
+
+ if (tmpver > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_ver_saved) {
+ sl_ssh_ver = ssh_ver;
+ sl_ssh_ver_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_ver = tmpver;
+ }
+ /* Disable X11 Forwarding */
+#ifndef SSHTEST
+ if (!sl_ssh_xfw_saved) {
+ sl_ssh_xfw = ssh_xfw;
+ sl_ssh_xfw_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_xfw = 0;
+
+ if (ssh_tmpstr) {
+ if (ssh_tmpstr[0]) {
+ ckstrncpy(pwbuf,ssh_tmpstr,PWBUFL+1);
+ pwflg = 1;
+ pwcrypt = 0;
+ } else
+ pwflg = 0;
+ makestr(&ssh_tmpstr,NULL);
+ }
+ nettype = NET_SSH;
+ if (mdmsav < 0)
+ mdmsav = mdmtyp;
+ mdmtyp = -nettype;
+ x = 1;
+
+#ifndef NOSPL
+ makestr(&g_pswd,pwbuf); /* Save global pwbuf */
+ g_pflg = pwflg; /* and flag */
+ g_pcpt = pwcrypt;
+#endif /* NOSPL */
+
+ /* Line parameter to ttopen() is ignored */
+ k = ttopen(line,&x,mdmtyp, 0);
+ if (k < 0) {
+ printf("?Unable to connect to %s\n",ssh_hst);
+ mdmtyp = mdmsav;
+ slrestor();
+ return(success = 0);
+ }
+ duplex = 0; /* Remote echo */
+ ckstrncpy(ttname,line,TTNAMLEN); /* Record the command */
+ debug(F110,"ssh ttname",ttname,0);
+ makestr(&slmsg,NULL); /* No SET LINE error message */
+ cxtype = CXT_SSH;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ success = 1; /* SET LINE succeeded */
+ network = 1; /* Network connection (not serial) */
+ local = 1; /* Local mode (not remote) */
+ if ((reliable != SET_OFF || !setreliable))
+ reliable = SET_ON; /* Transport is reliable end to end */
+#ifdef OS2
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+#endif /* OS2 */
+ setflow(); /* Set appropriate flow control */
+
+ haveline = 1;
+#ifdef CKLOGDIAL
+#ifdef NETCONN
+ dolognet();
+#endif /* NETCONN */
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ssh_hst,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+#ifdef LOCUS
+ if (autolocus)
+ setlocus(1,1);
+#endif /* LOCUS */
+
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+ if (cmdlvl > 0)
+ prepop();
+
+ success = sftp_do_init();
+ return(success = 1);
+
+ case SFTP_CD:
+ case SFTP_CHGRP:
+ case SFTP_CHMOD:
+ case SFTP_CHOWN:
+ case SFTP_RM:
+ case SFTP_DIR:
+ case SFTP_GET:
+ case SFTP_MKDIR:
+ case SFTP_PUT:
+ case SFTP_PWD:
+ case SFTP_REN:
+ case SFTP_RMDIR:
+ case SFTP_LINK:
+ case SFTP_VER:
+ if ((y = cmtxt("command parameters","",&s,xxstring)) < 0)
+ return(y);
+ if (ssh_tchk() < 0 || !ssh_cas || strcmp(ssh_cmd,"sftp")) {
+ printf("?Not connected to SFTP Service\n");
+ return(success = 0);
+ }
+ success = sftp_do_cmd(cmresult.nresult,s);
+ return(success);
+ default:
+ return(-2);
+ }
+ }
+#endif /* SFTP_BUILTIN */
+
+ if (cx == XXRLOG) { /* RLOGIN */
+#ifdef RLOGCODE
+ int x,z;
+#ifdef OS2
+ if (!tcp_avail) {
+ printf("?Sorry, either TCP/IP is not available on this system or\n\
+necessary DLLs did not load. Use SHOW NETWORK to check network status.\n"
+ );
+ success = 0;
+ return(-9);
+ } else {
+#endif /* OS2 */
+ x = nettype; /* Save net type in case of failure */
+ z = ttnproto; /* Save protocol in case of failure */
+ nettype = NET_TCPB;
+ ttnproto = NP_RLOGIN;
+ if ((y = setlin(XYHOST,0,1)) <= 0) {
+ nettype = x; /* Failed, restore net type. */
+ ttnproto = z; /* and protocol */
+ success = 0;
+ }
+ didsetlin++;
+#ifdef OS2
+ }
+#endif /* OS2 */
+ return(y);
+#else
+ printf("?Sorry, RLOGIN is not configured in this copy of C-Kermit.\n");
+ return(-9);
+#endif /* RLOGCODE */
+ }
+#endif /* NETCONN */
+#endif /* NOLOCAL */
+
+#ifndef NOXMIT
+ if (cx == XXTRA) { /* TRANSMIT */
+ extern int xfrxla;
+ int i, n, xpipe = 0, xbinary = 0, xxlate = 1, xxnowait = 0, getval;
+ int xxecho = 0;
+ int scan = 1;
+ char c;
+ struct FDB sf, sw, tx; /* FDBs for parse functions */
+#ifndef NOCSETS
+ extern int tcs_transp; /* Term charset is transparent */
+#else
+ int tcs_transp = 1;
+#endif /* NOCSETS */
+
+#ifdef COMMENT
+ xbinary = binary; /* Default text/binary mode */
+#else
+ xbinary = 0; /* Default is text */
+#endif /* COMMENT */
+ xxecho = xmitx;
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Filename, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nxmitsw, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ xmitsw, /* Keyword table */
+ &sf /* Pointer to next FDB */
+ );
+ cmfdbi(&sf, /* 2nd FDB - file to send */
+ _CMIFI, /* fcode */
+ "File to transmit", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+#ifdef PIPESEND
+ &tx
+#else
+ NULL
+#endif /* PIPESEND */
+ );
+#ifdef PIPESEND
+ cmfdbi(&tx,
+ _CMTXT, /* fcode */
+ "Command", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+#endif /* PIPESEND */
+
+ while (1) {
+ x = cmfdb(&sw);
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY)
+ break;
+ c = cmgbrk(); /* Have switch, get break character */
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ n = cmresult.nresult; /* Numeric result = switch ID */
+ switch (n) { /* Process the switch */
+#ifdef PIPESEND
+ case XMI_CMD: /* Transmit from a command */
+ if (nopush) {
+ printf("?Sorry, system command access is disabled\n");
+ return(-9);
+ }
+ sw.hlpmsg = "Command, or switch"; /* Change help message */
+ xpipe = 1; /* (No way to undo this one) */
+ break;
+#endif /* PIPESEND */
+
+ case XMI_BIN: /* Binary */
+ xbinary = 1;
+ xxlate = 0; /* Don't translate charsets */
+ scan = 0;
+ break;
+
+ case XMI_TXT: /* Text */
+ xbinary = 0;
+ xxlate = !tcs_transp; /* Translate if TERM CHAR not TRANSP */
+ scan = 0;
+ break;
+
+ case XMI_TRA: /* Transparent text */
+ xbinary = 0;
+ xxlate = 0; /* But don't translate charsets */
+ scan = 0;
+ break;
+
+#ifdef COMMENT
+ case XMI_VRB: /* /VERBOSE */
+ case XMI_QUI: /* /QUIET */
+ break; /* (not implemented yet) */
+#endif /* COMMENT */
+
+ case XMI_NOW: /* /NOWAIT */
+ xxnowait = 1;
+ break;
+
+ case XMI_NOE: /* /NOWAIT */
+ xxecho = 0;
+ break;
+
+ default:
+ return(-2);
+ }
+
+ }
+ if (cmresult.fcode != _CMIFI && cmresult.fcode != _CMTXT)
+ return(-2);
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Filename */
+ if (zfnqfp(line,TMPBUFSIZ,tmpbuf))
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ s = line;
+ if ((y = cmcfm()) < 0) /* Confirm */
+ return(y);
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+ if (cmresult.nresult != 0) {
+ printf("?Only a single file may be transmitted\n");
+ return(-9);
+ }
+#ifdef PIPESEND
+ if (xpipe) {
+ s = brstrip(s);
+ if (!*s) {
+ printf("?Sorry, a command to send from is required\n");
+ return(-9);
+ }
+ pipesend = 1;
+ }
+#endif /* PIPESEND */
+
+ if (scan && (filepeek
+#ifndef NOXFER
+ || patterns
+#endif /* NOXFER */
+ )) { /* If user didn't specify type */
+ int k, x; /* scan the file to see */
+ x = -1;
+ k = scanfile(s,&x,nscanfile);
+ if (k > 0) xbinary = (k == FT_BIN) ? XYFT_B : XYFT_T;
+ }
+ if (!xfrxla) xxlate = 0;
+ success = transmit(s,
+ (char) (xxnowait ? '\0' : (char)xmitp),
+ xxlate,
+ xbinary,
+ xxecho
+ );
+ return(success);
+ }
+#endif /* NOXMIT */
+
+#ifndef NOFRILLS
+ if (cx == XXTYP || cx == XXCAT || cx == XXMORE ||
+ cx == XXHEAD || cx == XXTAIL) {
+ int paging = 0, havename = 0, head = 0, width = 0;
+ int height = 0, count = 0;
+ char pfxbuf[64], * prefix = NULL;
+ char outfile[CKMAXPATH+1];
+ struct FDB sf, sw;
+ char * pat = NULL;
+ int incs = 0, outcs = 0, cset = -1, number = 0;
+#ifdef UNICODE
+ char * tocs = "";
+ extern int fileorder;
+#ifdef OS2
+#ifdef NT
+ char guibuf[128], * gui_title = NULL;
+ int gui = 0;
+#endif /* NT */
+#ifndef NOCSETS
+ extern int tcsr, tcsl;
+#endif /* NOCSETS */
+#endif /* OS2 */
+#endif /* UNICODE */
+
+ outfile[0] = NUL;
+
+ if (cx == XXMORE)
+ paging = 1;
+ else if (cx == XXCAT)
+ paging = 0;
+ else
+ paging = (typ_page < 0) ? xaskmore : typ_page;
+ if (paging < 0)
+ paging = saveask;
+
+ if (cx == XXHEAD) {
+ head = 10;
+ cx = XXTYP;
+ } else if (cx == XXTAIL) {
+ head = -10;
+ cx = XXTYP;
+ }
+
+#ifdef IKSD
+ if (inserver && !ENABLED(en_typ)) {
+ printf("?Sorry, TYPE command disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+
+ cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
+ _CMKEY, /* fcode */
+ "Filename or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ ntypetab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ typetab, /* Keyword table */
+ &sf /* Pointer to next FDB */
+ );
+ cmfdbi(&sf, /* 1st FDB - file to type */
+ _CMIFI, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+
+ while (!havename) {
+ x = cmfdb(&sw); /* Parse something */
+ debug(F101,"type cmfdb","",x);
+ debug(F101,"type cmresult.fcode","",cmresult.fcode);
+ debug(F101,"type cmresult.nresult","",cmresult.nresult);
+ if (x < 0) { /* Error */
+ if (x == -3) {
+ x = -9;
+ printf("?Filename required\n");
+ }
+ return(x);
+ } else if (cmresult.fcode == _CMKEY) {
+ char c; int getval;
+ c = cmgbrk();
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+#ifdef COMMENT
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ /* Not if it has a default! */
+ return(-9);
+ }
+#endif /* COMMENT */
+ switch (cmresult.nresult) {
+#ifdef CK_TTGWSIZ
+ case TYP_PAG:
+ paging = 1;
+ break;
+
+ case TYP_NOP:
+ paging = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+
+ case TYP_COU:
+ paging = 0;
+ count = 1;
+ break;
+
+ case TYP_HEA:
+ case TYP_TAI:
+ y = 10;
+ if (getval)
+ if ((x = cmnum("Number of lines",
+ "10",10,&y,xxstring)) < 0)
+ return(x);
+ head = (cmresult.nresult == TYP_TAI) ? -y : y;
+ break;
+
+ case TYP_WID:
+ y = typ_wid > -1 ? typ_wid : cmd_cols;
+ if (getval)
+ if ((x = cmnum("Column at which to truncate",
+ ckitoa(y),10,&y,xxstring)) < 0)
+ return(x);
+ width = y;
+ break;
+
+#ifdef KUI
+ case TYP_HIG:
+ if (getval)
+ if ((x = cmnum("Height of GUI dialog",
+ ckitoa(y),10,&y,xxstring)) < 0)
+ return(x);
+ height = y;
+ break;
+#endif /* KUI */
+
+ case TYP_PAT:
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((x = cmfld("pattern","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ pat = tmpbuf;
+ break;
+
+ case TYP_PFX:
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((x = cmfld("prefix for each line","",&s,xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) > 63) {
+ printf("?Too long - 63 max\n");
+ return(-9);
+ }
+ ckstrncpy(pfxbuf,s,64);
+ prefix = brstrip(pfxbuf);
+ number = 0;
+ break;
+
+#ifdef KUI
+ case TYP_GUI:
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((x = cmfld("Dialog box title","",&s,xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ } else {
+ if ((int)strlen(s) > 127) {
+ printf("?Too long - 127 max\n");
+ return(-9);
+ }
+ ckstrncpy(guibuf,s,128);
+ gui_title = brstrip(guibuf);
+ }
+ gui = 1;
+ break;
+#endif /* KUI */
+
+ case TYP_NUM: /* /NUMBER */
+ number = 1;
+ prefix = NULL;
+ break;
+
+#ifdef UNICODE
+ case TYP_XPA: /* /TRANSPARENT */
+ incs = 0;
+ cset = 0;
+ outcs = -1;
+ break;
+
+ case TYP_XIN: /* /CHARACTER-SET: */
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((incs = cmkey(fcstab,nfilc,
+ "character-set name","",xxstring)) < 0) {
+ if (incs == -3) /* Note: No default */
+ incs = -2;
+ return(incs);
+ }
+ cset = incs;
+ break;
+
+ case TYP_XUT: /* /TRANSLATE-TO: */
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+#ifdef OS2
+ if (!inserver && !k95stdout) {
+ tocs = "ucs2";
+ } else {
+#ifdef CKOUNI
+ tocs = rlookup(txrtab,ntxrtab,tcsl);
+#else /* CKOUNI */
+ extern struct keytab ttcstab[];
+ extern int ntxrtab;
+ tocs = rlookup(ttcstab,ntermc,tocs);
+ if (!tocs)
+ tocs = getdcset();
+#endif /* CKOUNI */
+ }
+#else /* OS2 */
+ tocs = getdcset();
+#endif /* OS2 */
+ if ((outcs = cmkey(fcstab,nfilc,
+ "character-set",tocs,xxstring)) < 0)
+ return(outcs);
+ break;
+#endif /* UNICODE */
+ case TYP_OUT:
+ if ((x = cmofi("File for result lines","",
+ &s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(outfile,s,CKMAXPATH);
+ break;
+ }
+ } else if (cmresult.fcode == _CMIFI)
+ havename = 1;
+ else
+ return(-2);
+ }
+ if (havename) {
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ y = cmresult.nresult;
+ } else {
+ if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of an existing file required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ }
+ if (y != 0) {
+ printf("?A single file please\n");
+ return(-9);
+ }
+#ifdef KUI
+ if ( outfile[0] && gui ) {
+ printf("?/GUI and /OUTPUT are incompatible\n");
+ return(-9);
+ }
+#endif /* KUI */
+
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+
+#ifdef UNICODE
+ fileorder = -1;
+ if (cset < 0 && filepeek) { /* If no charset switches given */
+ int k, x = -1;
+ k = scanfile(line,&x,nscanfile); /* Call file analyzer */
+ debug(F111,"type scanfile",line,k);
+ debug(F101,"type scanfile flag","",x);
+ switch(k) {
+ case FT_UTF8: /* which can detect UTF-8... */
+ cset = 0;
+ incs = FC_UTF8;
+ break;
+ case FT_UCS2: /* and UCS-2... */
+ cset = 0;
+ incs = FC_UCS2;
+ fileorder = x; /* even if there is no BOM. */
+ debug(F101,"type fileorder","",fileorder);
+ break;
+ }
+ }
+#ifdef OS2
+ if (cset < 0) { /* If input charset still not known */
+#ifdef CKOUNI
+ tocs = rlookup(txrtab,ntxrtab,tcsl);
+#else /* CKOUNI */
+ extern struct keytab ttcstab[];
+ extern int ntxrtab;
+ tocs = rlookup(ttcstab,ntermc,incs);
+ if (!tocs)
+ tocs = getdcset();
+#endif /* CKOUNI */
+ incs = lookup(fcstab,tocs,nfilc,&x);
+ }
+#endif /* OS2 */
+
+ if (outcs == 0 && incs != 0) { /* Supply default target charset */
+ int x = 0; /* if switch not given. */
+ tocs = getdcset();
+ outcs = lookup(fcstab,tocs,nfilc,&x);
+ }
+#else /* !UNICODE */
+ if (cset < 0) incs = outcs = 0;
+#endif /* UNICODE */
+
+ if (outfile[0] && paging) /* This combination makes no sense */
+ paging = 0; /* so turn off paging */
+
+#ifdef KUI
+ /* No paging when dialog is used */
+ if ( gui && paging )
+ paging = 0;
+
+ if ( !gui && height ) {
+ printf("?The /HEIGHT switch is not supported without /GUI\n");
+ return(-9);
+ }
+#endif /* KUI */
+
+ if (count) paging = -1;
+ debug(F111,"type",line,paging);
+#ifdef KUI
+ if ( gui ) {
+ s = (char *)1; /* ok, its an ugly hack */
+ if (gui_text_popup_create(gui_title ?
+ gui_title : line, height,width) < 0) {
+ printf("?/GUI not supported on this system\n");
+ gui = 0;
+ return(-9);
+ }
+ width = 0;
+ } else
+#endif /* KUI */
+ s = outfile;
+ success =
+ dotype(line,paging,0,head,pat,width,prefix,incs,outcs,s,number);
+ return(success);
+ }
+#endif /* NOFRILLS */
+
+#ifndef NOCSETS
+ if (cx == XXXLA) { /* TRANSLATE file's charset */
+ _PROTOTYP (int doxlate, ( void ) );
+ return(doxlate());
+ }
+#endif /* NOCSETS */
+
+ if (cx == XXVER) { /* VERSION */
+ int n = 0;
+ extern char * ck_patch, * ck_s_test;
+#ifdef COMMENT
+ extern int hmtopline;
+#endif /* COMMENT */
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+#ifdef CK_64BIT
+ printf("\n%s, for%s (64-bit)\n Numeric: %ld",versio,ckxsys,vernum);
+#else
+ printf("\n%s, for%s\n Numeric: %ld",versio,ckxsys,vernum);
+#endif /* CK_64BIT */
+ printf("\n\n");
+ printf("Authors:\n");
+ printf(" Frank da Cruz, Columbia University\n");
+ printf(" Jeffrey Eric Altman, Secure Endpoints, Inc. %s\n",
+ "<jaltman@secure-endpoints.com>"
+ );
+ printf(" Contributions from many others.\n");
+ n = 7;
+ if (*ck_s_test) {
+ printf("\nTHIS IS A TEST VERSION, NOT FOR PRODUCTION USE.\n");
+ n += 2;
+ }
+ if (*ck_patch) {
+ printf(" Patches: %s\n", ck_patch);
+ n++;
+ }
+ printf(" Type COPYRIGHT for copyright and license.\n\n");
+#ifdef OS2
+ shoreg();
+#else
+#ifdef COMMENT
+ hmtopline = n+1;
+ hmsga(copyright);
+ hmtopline = 0;
+#endif /* COMMENT */
+#endif /* OS2 */
+ return(success = 1);
+ }
+
+ if (cx == XXCPR) { /* COPYRIGHT or LICENSE */
+ _PROTOTYP( int hmsgaa, (char * [], char *) );
+ extern char * ck_cryear;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ hmsgaa(copyright,ck_cryear);
+ return(success = 1);
+ }
+
+#ifndef MAC /* Only for multiuser systems */
+#ifndef OS2
+#ifndef NOFRILLS
+ if (cx == XXWHO) { /* WHO */
+ char *wc;
+#ifdef IKSD
+ if (inserver && !ENABLED(en_who)) {
+ printf("?Sorry, WHO command disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef datageneral
+ if ((z = cmcfm()) < 0) return(z);
+ if (nopush) {
+ printf("?Sorry, who not allowed\n");
+ return(success = 0);
+ }
+ xsystem(WHOCMD);
+#else
+ if ((y = cmtxt("user name","",&s,xxstring)) < 0) return(y);
+ if (nopush) {
+ printf("?Sorry, WHO command disabled\n");
+ return(success = 0);
+ }
+ if (!(wc = getenv("CK_WHO"))) wc = WHOCMD;
+ if (wc)
+ if ((int) strlen(wc) > 0) {
+ ckmakmsg(line,LINBUFSIZ,wc," ",s,NULL);
+ xsystem(line);
+ }
+#endif /* datageneral */
+ return(success = 1);
+ }
+#endif /* NOFRILLS */
+#endif /* OS2 */
+#endif /* MAC */
+
+#ifndef NOFRILLS
+ if (cx == XXWRI || cx == XXWRL || cx == XXWRBL) { /* WRITE */
+ int x,y; /* On stack in case of \fexec() */
+ if ((x = cmkey(writab,nwri,"to file or log","",xxstring)) < 0) {
+ if (x == -3) printf("?Write to what?\n");
+ return(x);
+ }
+ if ((y = cmtxt("text","",&s,xxstring)) < 0) return(y);
+ s = brstrip(s);
+ switch (x) {
+ case LOGD: y = ZDFILE; break;
+ case LOGP: y = ZPFILE; break;
+#ifndef NOLOCAL
+ case LOGS: y = ZSFILE; break;
+#endif /* NOLOCAL */
+ case LOGT: y = ZTFILE; break;
+#ifndef NOSPL
+ case LOGW: y = ZWFILE; break;
+#endif /* NOSPL */
+ case LOGX: /* SCREEN (stdout) */
+ case LOGE: /* ERROR (stderr) */
+ if (x == LOGE) {
+ debug(F110,
+ (cx == XXWRL) ? "WRITELN ERROR" : "WRITE ERROR", s,0);
+ fprintf(stderr,"%s%s",s,(cx == XXWRL) ? "\n" : "");
+ } else {
+ debug(F110,
+ (cx == XXWRL) ? "WRITELN SCREEN" : "WRITE SCREEN", s,0);
+ printf("%s%s",s,(cx == XXWRL) ? "\n" : "");
+ }
+ return(success = 1);
+ default: return(-2);
+ }
+ if (chkfn(y) > 0) {
+ x = (cx == XXWRI) ? zsout(y,s) : zsoutl(y,s);
+ debug(F111,"WRITE",
+ (cx == XXWRI) ? "zsout" : "zsoutl",
+ x);
+ if (x < 0) printf("?Write error\n");
+ } else {
+ x = -1;
+ printf("?File or log not open\n");
+ }
+ debug(F101,"WRITE x","",x);
+ return(success = (x == 0) ? 1 : 0);
+ }
+#endif /* NOFRILLS */
+
+#ifndef NOXFER
+ if (cx == XXASC || cx == XXBIN) {
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef NEWFTP
+/*
+ Make C-Kermit work like other ftp clients, where
+ the ASCII (TEXT) and BINARY commands are global settings.
+*/
+ if (ftpisopen()) {
+ doftpglobaltype((cx == XXASC) ? XYFT_T : XYFT_B);
+ /* Fall thru--the command it should apply to both FTP and Kermit */
+ /* return(success = 1); */
+ }
+#endif /* NEWFTP */
+
+ xfermode = XMODE_M; /* Set manual Kermit transfer mode */
+ binary = (cx == XXASC) ? XYFT_T : XYFT_B;
+ return(success = 1);
+ }
+#endif /* NOXFER */
+
+ if (cx == XXCLS) {
+ if ((x = cmcfm()) < 0) return(x);
+ y = ck_cls();
+ return(success = (y > -1) ? 1 : 0);
+ }
+
+#ifdef CK_MKDIR
+ if (cx == XXMKDIR || cx == XXLMKD) {
+ char *p;
+#ifdef LOCUS
+ if (!locus && cx != XXLMKD) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZMKD));
+#endif /* NOXFER */
+ }
+#endif /* LOCUS */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_mkd)) {
+ printf("?Sorry, directory creation is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ if ((x = cmfld("Name for new directory","",&s,xxstring)) < 0) {
+ if (x != -3) {
+ return(x);
+ } else {
+ printf("?Directory name required\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ if ((x = cmcfm()) < 0) return(x);
+ s = brstrip(s);
+ bgchk(); /* Set msgflg */
+ x = ckmkdir(0,s,&p,msgflg,0);
+#ifdef COMMENT
+ if (msgflg && x == 0)
+ printf("?Directory already exists\n");
+#endif /* COMMENT */
+ return(success = (x < 0) ? 0 : 1);
+ }
+ if (cx == XXRMDIR || cx == XXLRMD) { /* RMDIR */
+ char *p;
+#ifdef LOCUS
+ if (!locus && cx != XXLRMD) {
+#ifdef NOXFER
+ return(-2);
+#else
+ return(dormt(XZRMD));
+#endif /* NOXFER */
+ }
+#endif /* LOCUS */
+#ifdef IKSD
+ if (inserver && !ENABLED(en_rmd)) {
+ printf("?Sorry, directory removal is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+ if ((x = cmdir("Name of directory to be removed","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ if ((x = cmcfm()) < 0) return(x);
+ s = brstrip(s);
+ x = ckmkdir(1,s,&p,msgflg,0);
+ return(success = (x < 0) ? 0 : 1);
+ }
+#endif /* CK_MKDIR */
+
+#ifdef TNCODE
+ if (cx == XXTELOP)
+ return(dotelopt());
+#endif /* TNCODE */
+
+#ifndef NOPUSH
+ if (cx == XXNPSH) {
+ if ((z = cmcfm()) < 0) return(z);
+ nopush = 1;
+#ifndef NOSERVER
+ en_hos = 0;
+#endif /* NOSERVER */
+#ifdef PIPESEND
+ usepipes = 0;
+#endif /* PIPESEND */
+ return(success = 1);
+ }
+#endif /* NOPUSH */
+
+#ifdef OS2
+ if (cx == XXNSCR) {
+ if ((z = cmcfm()) < 0) return(z);
+ tt_scroll = 0;
+ return(success = 1);
+ }
+#endif /* OS2 */
+
+#ifndef NOSPL
+ if (cx == XXLOCAL) /* LOCAL variable declarations */
+ return(success = dolocal());
+#endif /* NOSPL */
+
+ if (cx == XXKERMI) { /* The KERMIT command */
+ char * list[65];
+ extern char **xargv;
+ extern int xargc;
+ int i;
+ if ((y = cmtxt("kermit command-line arguments, -h for help",
+ "",&s,xxstring)) < 0)
+ return(y);
+ ckstrncpy(line,"kermit ",LINBUFSIZ);
+ ckstrncat(line,s,LINBUFSIZ-8);
+ xwords(line,64,list,0);
+ for (i = 1; i < 64; i++) {
+ if (!list[i])
+ break;
+ }
+ i--;
+ xargc = i;
+ xargv = list;
+ xargv++;
+ sstate = cmdlin();
+ if (sstate) {
+ extern int justone;
+ debug(F000,"KERMIT sstate","",sstate);
+ justone = 1; /* Force return to command mode */
+ proto(); /* after protocol */
+ return(success);
+ } else {
+ debug(F101,"KERMIT sstate","",sstate);
+ return(success = 1); /* Not exactly right, but... */
+ }
+ }
+ if (cx == XXDATE) { /* DATE command */
+ extern char cmdatebuf[], * cmdatemsg;
+
+#ifndef COMMENT
+ char * dp;
+ if ((y = cmtxt("date and/or time, or carriage return for current",
+ "",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ dp = cmcvtdate(s,1);
+ if (!dp) {
+ printf("?%s\n",cmdatemsg ? cmdatemsg : "Date conversion error");
+ success = 0;
+ } else {
+ printf("%s\n",dp);
+ success = 1;
+ }
+#else
+ /* This works fine but messes up my "dates" torture-test script */
+
+ if ((x = cmdate("Date and/or time, or carriage return for current",
+ "",&s,0,xxstring)) < 0) {
+ return(x);
+ } else {
+ printf("%s\n",cmdatebuf);
+ success = 1;
+ }
+#endif /* COMMENT */
+ return(success);
+ }
+#ifndef NOPUSH
+#ifndef NOFRILLS
+ if (cx == XXEDIT)
+ return(doedit());
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifdef BROWSER /* Defined only ifndef NOPUSH */
+ if (cx == XXBROWS)
+ return(dobrowse());
+#endif /* BROWSER */
+
+#ifdef CK_TAPI
+ if (cx == XXTAPI) { /* Microsoft TAPI */
+ return (success = dotapi());
+ }
+#endif /* CK_TAPI */
+
+#ifndef NOXFER
+ if (cx == XXWHERE) {
+ extern char * rfspec, * sfspec, * srfspec, * rrfspec;
+ if ((x = cmcfm()) < 0) return(x);
+ printf("\nFile most recently...\n\n");
+ printf(" Sent: %s\n", sfspec ? sfspec : "(none)");
+ if (sfspec && srfspec) {
+ printf(" Stored as: %s\n", srfspec);
+ printf("\n");
+ }
+ printf(" Received: %s\n", rrfspec ? rrfspec : "(none)");
+ if (rfspec && rrfspec)
+ printf(" Stored as: %s\n", rfspec);
+ printf(
+"\nIf the full path is not shown, then the file is probably in your current\n"
+ );
+ printf(
+"directory or your download directory (if any - SHOW FILE to find out).\n\n"
+ );
+ return(success = 1);
+ }
+#endif /* NOXFER */
+
+#ifdef CK_RECALL
+ if (cx == XXREDO)
+ return(doredo());
+#endif /* CK_RECALL */
+
+#ifdef CKROOT
+ if (cx == XXCHRT) /* Change Kermit's root directory */
+ return(dochroot());
+#endif /* CKROOT */
+
+#ifdef CK_KERBEROS
+ if (cx == XXAUTH) { /* KERBEROS */
+ x = cp_auth(); /* Parse it */
+#ifdef IKSD
+ if (inserver) {
+ printf("?Command disabled in IKSD.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ if (x < 0) /* Pass parse errors back */
+ return(x);
+ return(success = doauth(cx));
+ }
+#endif /* CK_KERBEROS */
+
+#ifndef NOLOCAL
+ if (cx == XXTERM) {
+ return(settrmtyp());
+ }
+#endif /* NOLOCAL */
+
+ if (cx == XXSTATUS) {
+ if ((x = cmcfm()) < 0) return(x);
+ printf( " %s\n", success ? "SUCCESS" : "FAILURE" );
+ return(0); /* Don't change it */
+ }
+
+ if (cx == XXFAIL) {
+ if ((x = cmcfm()) < 0) return(x);
+ return(success = 0);
+ }
+
+ if (cx == XXSUCC) {
+ if ((x = cmcfm()) < 0) return(x);
+ return(success = 1);
+ }
+
+ if (cx == XXNLCL) {
+ extern int nolocal;
+ if ((x = cmcfm()) < 0) return(x);
+ nolocal = 1;
+ return(success = 1);
+ }
+
+#ifndef NOXFER
+ if (cx == XXRASG) /* Shortcuts for REMOTE commands */
+ return(dormt(XZASG));
+ if (cx == XXRCWD)
+ return(dormt(XZCWD));
+ if (cx == XXRCPY)
+ return(dormt(XZCPY));
+ if (cx == XXRDEL)
+ return(dormt(XZDEL));
+ if (cx == XXRDIR)
+ return(dormt(XZDIR));
+ if (cx == XXRXIT)
+ return(dormt(XZXIT));
+ if (cx == XXRHLP)
+ return(dormt(XZHLP));
+ if (cx == XXRHOS)
+ return(dormt(XZHOS));
+ if (cx == XXRKER)
+ return(dormt(XZKER));
+ if (cx == XXRPWD)
+ return(dormt(XZPWD));
+ if (cx == XXRQUE)
+ return(dormt(XZQUE));
+ if (cx == XXRREN)
+ return(dormt(XZREN));
+ if (cx == XXRMKD)
+ return(dormt(XZMKD));
+ if (cx == XXRMSG)
+ return(dormt(XZMSG));
+ if (cx == XXRRMD)
+ return(dormt(XZRMD));
+ if (cx == XXRSET)
+ return(dormt(XZSET));
+ if (cx == XXRSPA)
+ return(dormt(XZSPA));
+ if (cx == XXRTYP)
+ return(dormt(XZTYP));
+ if (cx == XXRWHO)
+ return(dormt(XZWHO));
+ if (cx == XXRCDUP)
+ return(dormt(XZCDU));
+ if (cx == XXRPRI)
+ return(dormt(XZPRI));
+#endif /* NOXFER */
+
+ if (cx == XXRESET) { /* RESET */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ concb((char)escape); /* Make command echoing to normal */
+ doclean(0); /* Close all files */
+ return(success = 1);
+ }
+
+#ifndef NOXFER
+#ifndef NOCSETS
+ if (cx == XXASSOC) /* ASSOCIATE */
+ return(doassoc());
+#endif /* NOCSETS */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ if (cx == XXSHIFT) { /* SHIFT */
+ if ((y = cmnum("Number of arguments to shift","1",10,&x,xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ return(success = doshift(x));
+ }
+#endif /* NOSPL */
+
+#ifndef NOHELP
+ if (cx == XXMAN)
+ return(domanual());
+#endif /* NOHELP */
+
+#ifndef NOSPL
+ if (cx == XXSORT) /* SORT an array */
+ return(dosort());
+#endif /* NOSPL */
+
+ if (cx == XXPURGE) {
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_del)
+#ifdef CK_LOGIN
+ || isguest
+#endif /* CK_LOGIN */
+ )) {
+ printf("?Sorry, DELETE is disabled\n");
+ return(-9);
+ }
+#endif /* IKSD */
+#ifdef CK_APC
+ if ((apcactive == APC_LOCAL) ||
+ ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH))))
+ return(success = 0);
+#endif /* CK_APC */
+#ifdef CKPURGE
+ return(dopurge());
+#else
+#ifdef VMS
+ if ((x = cmtxt("optional switches followed by filespec",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if (nopush) {
+ printf("?Sorry, DCL access is disabled\n");
+ return(-9);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = line;
+ x = mlook(mactab,"purge",nmac);
+ return(success = dodo(x,s,cmdstk[cmdlvl].ccflgs));
+#else
+ return(-2);
+#endif /* VMS */
+#endif /* CKPURGE */
+ }
+
+#ifndef NOSPL
+ if (cx == XXFAST) {
+ if ((x = cmcfm()) < 0) return(x);
+ x = mlook(mactab,"fast",nmac);
+ return(success = dodo(x,NULL,cmdstk[cmdlvl].ccflgs));
+ }
+ if (cx == XXCAU) {
+ if ((x = cmcfm()) < 0) return(x);
+ x = mlook(mactab,"cautious",nmac);
+ return(success = dodo(x,NULL,cmdstk[cmdlvl].ccflgs));
+ }
+ if (cx == XXROB) {
+ if ((x = cmcfm()) < 0) return(x);
+ x = mlook(mactab,"robust",nmac);
+ return(success = dodo(x,NULL,cmdstk[cmdlvl].ccflgs));
+ }
+#endif /* NOSPL */
+
+ if (cx == XXSCRN) { /* SCREEN */
+ int row, col;
+ if ((x = cmkey(scntab, nscntab,"screen action","", xxstring)) < 0)
+ return(x);
+ switch (x) { /* MOVE-TO (cursor position) */
+ case SCN_MOV:
+ if ((y = cmnum("Row (1-based)","",10,&z,xxstring)) < 0)
+ return(y);
+ row = z;
+ y = cmnum("Column (1-based)","1",10,&z,xxstring);
+ if (y < 0)
+ return(y);
+ col = z;
+ if ((y = cmcfm()) < 0)
+ return(y);
+ if (row < 0 || col < 0) {
+ printf("?Row and Column must be 1 or greater\n");
+ return(-9);
+ }
+ if (cmd_rows > 0 && row > cmd_rows)
+ row = cmd_rows;
+ if (cmd_cols > 0 && col > cmd_cols)
+ col = cmd_cols;
+ y = ck_curpos(row,col);
+ return(success = (y > -1) ? 1 : 0);
+
+ case SCN_CLR: /* CLEAR */
+ if ((y = cmcfm()) < 0)
+ return(y);
+ debug(F100,"screen calling ck_cls()","",0);
+ y = ck_cls();
+ return(success = (y > -1) ? 1 : 0);
+
+ case SCN_CLE: /* CLEOL */
+ if ((y = cmcfm()) < 0)
+ return(y);
+ y = ck_cleol();
+ return(success = (y > -1) ? 1 : 0);
+ }
+ }
+
+#ifndef NOHTTP
+#ifdef TCPSOCKET
+ if (cx == XXHTTP)
+ return(dohttp());
+#endif /* TCPSOCKET */
+#endif /* NOHTTP */
+
+#ifndef NOSPL
+ if (cx == XXARRAY) { /* ARRAY */
+#ifndef NOSHOW
+ extern int showarray();
+#endif /* NOSHOW */
+ if ((x = cmkey(arraytab, narraytab,"Array operation","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case ARR_DCL:
+ return(dodcl(XXDCL));
+ case ARR_SRT:
+ return(dosort());
+#ifndef NOSHOW
+ case ARR_SHO:
+ return(showarray());
+#endif /* NOSHOW */
+ case ARR_CPY:
+ return(copyarray());
+ case ARR_SET:
+ case ARR_CLR:
+ return(clrarray(x));
+ case ARR_DST:
+ return(unarray());
+ case ARR_RSZ:
+ return(rszarray());
+ case ARR_EQU:
+ return(linkarray());
+
+ default:
+ printf("?Sorry, not implemented yet - \"%s\"\n",cmdbuf);
+ return(-9);
+ }
+ }
+ if (cx == XXTRACE) /* TRACE */
+ return(dotrace());
+#endif /* NOSPL */
+
+#ifdef CK_PERMS
+#ifdef UNIX
+ if (cx == XXCHMOD)
+ return(douchmod()); /* Do Unix chmod */
+#endif /* UNIX */
+#endif /* CK_PERMS */
+
+ if (cx == XXPROMP)
+ return(doprompt());
+
+ if (cx == XXGREP)
+ return(dogrep());
+
+ if (cx == XXDEBUG) { /* DEBUG */
+#ifndef DEBUG
+ int dummy = 0;
+ return(seton(&dummy));
+#else
+ return(seton(&deblog));
+#endif /* DEBUG */
+ }
+ if (cx == XXMSG || cx == XXXMSG) { /* MESSAGE */
+ extern int debmsg; /* Script debugging messages */
+ if ((x = cmtxt("Message to print if SET DEBUG MESSAGE is ON or STDERR",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if (!s) /* Watch out for null result */
+ s = ""; /* Make it an empty string */
+ else /* Not null */
+ s = brstrip(s); /* Strip braces and doublequotes */
+ switch (debmsg) { /* Not debugging - don't print */
+ case 0:
+ break;
+ case 1:
+ printf("%s",s); /* Print to stdout */
+ if (cx == XXMSG) printf("\n");
+ break;
+ case 2:
+ fprintf(stderr,"%s",s); /* Ditto but print to stderr */
+ if (cx == XXMSG) fprintf(stderr,"\n");
+ break;
+ }
+ return(0); /* Return without affecting SUCCESS */
+ }
+
+#ifdef CKLEARN
+ if (cx == XXLEARN) { /* LEARN */
+ struct FDB of, sw, cm;
+ int closing = 0, off = 0, on = 0, confirmed = 0;
+ char c;
+
+ cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */
+ _CMKEY, /* fcode */
+ "Script file name, or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 3, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ learnswi, /* Keyword table */
+ &of /* Pointer to next FDB */
+ );
+ cmfdbi(&of,_CMOFI,"","","",0,0,xxstring,NULL,&cm);
+ cmfdbi(&cm,_CMCFM,"","","",0,0,NULL,NULL,NULL);
+ line[0] = NUL;
+
+ while (!confirmed) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0)
+ return(x);
+ switch (cmresult.fcode) { /* What was it? */
+ case _CMOFI: /* Output file name */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ break;
+ case _CMKEY: /* Switch */
+ c = cmgbrk();
+ if ((c == ':' || c == '=') && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case 2: /* /CLOSE */
+ closing = 1; /* Fall thru on purpose */
+ case 0: /* /OFF */
+ off = 1;
+ on = 0;
+ break;
+ case 1: /* /ON */
+ on = 1;
+ off = 0;
+ break;
+ }
+ break;
+ case _CMCFM: /* Confirmation */
+ confirmed++;
+ break;
+ }
+ }
+ if (closing) {
+ if (learnfp) {
+ fclose(learnfp);
+ learnfp = NULL;
+ }
+ makestr(&learnfile,NULL);
+ }
+ if (line[0]) {
+ if (!on && !off)
+ on = 1;
+ if (learnfp) {
+ fclose(learnfp);
+ learnfp = NULL;
+ }
+ makestr(&learnfile,line);
+ if (learnfile) {
+ char * modes = "w";
+ learnfp = fopen(learnfile,modes);
+ if (!learnfp) {
+ debug(F110,"LEARN file open error",learnfile,0);
+ perror(learnfile);
+ return(-9);
+ } else {
+#ifdef ZFNQFP
+ if (zfnqfp(learnfile,TMPBUFSIZ,tmpbuf))
+ makestr(&learnfile,tmpbuf);
+#endif /* ZFNQFP */
+ debug(F110,"LEARN file open ok",learnfile,0);
+ if (!quiet) {
+ printf("Recording to %s...\n\n",learnfile);
+ printf(
+" WARNING: If you type your password during script recording, it will appear\n\
+ in the file. Be sure to edit it or take other appropriate precautions.\n\n"
+ );
+ }
+ fputs( "; Scriptfile: ",learnfp);
+ fputs(learnfile,learnfp);
+ fputs("\n; Directory: ",learnfp);
+ fputs(zgtdir(),learnfp);
+ fputs("\n; Recorded: ",learnfp);
+ fputs(ckdate(),learnfp);
+ fputs("\n",learnfp);
+ }
+ }
+ }
+ if (on) {
+ learning = 1;
+ } else if (off) {
+ learning = 0;
+ }
+ debug(F101,"LEARN learning","",learning);
+ return(success = 1);
+ }
+#endif /* CKLEARN */
+
+#ifdef NEWFTP
+ if (cx == XXUSER || cx == XXACCT) {
+ if (!ftpisopen()) {
+ printf("?FTP connection is not open\n");
+ return(-9);
+ }
+ return(success = (cx == XXUSER) ? doftpusr() : doftpacct());
+ }
+ if (cx == XXSITE || cx == XXPASV) {
+ if (!ftpisopen()) {
+ printf("?FTP connection is not open\n");
+ return(-9);
+ }
+ return(success = (cx == XXSITE) ? doftpsite() : dosetftppsv());
+ }
+#endif /* NEWFTP */
+
+ if (cx == XXORIE) { /* ORIENTATION */
+ extern char * myname;
+ int i, y, n = 0;
+ char * s, *p, vbuf[32];
+ char * vars[16]; char * legend[16];
+
+ if ((y = cmcfm()) < 0)
+ return(y);
+
+ printf("\nProgram name:\n %s\n\n",myname);
+ n += 4;
+
+#ifdef NT
+ vars[0] = "home"; legend[0] = "Your home directory";
+ vars[1] = "directory"; legend[1] = "K95's current directory";
+ vars[2] = "exedir"; legend[2] = "K95 Program directory";
+ vars[3] = "inidir"; legend[3] = "K95 Initialization file directory";
+ vars[4] = "startup"; legend[4] = "Current directory when started";
+
+ vars[5] = "common";
+ legend[5] = "K95 data for all users and K95SITE.INI file";
+
+ vars[6] = "personal"; legend[6] = "Your personal data directory tree";
+ vars[7] = "desktop"; legend[7] = "Your deskop directory tree";
+
+ vars[8] = "appdata";
+ legend[8] = "Your personal K95 data tree and K95CUSTOM.INI file";
+
+ vars[9] = "download"; legend[9] = "Your K95 download directory";
+ vars[10] = "tmpdir"; legend[10] = "Your TEMP directory";
+ vars[11] = NULL; legend[11] = NULL;
+
+ for (i = 0; i < 16 && vars[i]; i++) {
+ printf("%s:\n",legend[i]);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ ckmakmsg(vbuf,32,"\\v(",vars[i],")",NULL);
+ printf(" Variable: %s\n",vbuf);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ y = TMPBUFSIZ;
+ s = tmpbuf;
+ zzstring(vbuf,&s,&y);
+ line[0] = NUL;
+ ckGetLongPathName(tmpbuf,line,LINBUFSIZ);
+ printf(" Long name: %s\n",line);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ line[0] = NUL;
+ GetShortPathName(tmpbuf,line,LINBUFSIZ);
+ printf(" Short name: %s\n",line);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#else /* NT */
+
+ vars[0] = "home"; legend[0] = "Your home directory";
+ vars[1] = "directory"; legend[1] = "Kermit's current directory";
+ vars[2] = "exedir"; legend[2] = "Kermit's program directory";
+ vars[3] = "inidir"; legend[3] = "Initialization file directory";
+ vars[4] = "startup"; legend[4] = "Current directory when started";
+ vars[5] = "download"; legend[5] = "Kermit download directory";
+ vars[6] = NULL; legend[6] = NULL;
+
+ for (i = 0; i < 16 && vars[i]; i++) {
+ printf("%s:\n",legend[i]);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ ckmakmsg(vbuf,32,"\\v(",vars[i],")",NULL);
+ printf(" Variable: %s\n",vbuf);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ y = TMPBUFSIZ;
+ s = tmpbuf;
+ zzstring(vbuf,&s,&y);
+ printf(" Value: %s\n",tmpbuf);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ }
+#endif /* NT */
+ return(success = 1);
+ }
+
+#ifdef NT
+ if (cx == XXDIALER) {
+ StartDialer();
+ return(success = 1);
+ }
+#endif /* NT */
+
+ if (cx == XXCONT) { /* CONTINUE */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (!xcmdsrc) { /* At prompt: continue script */
+ if (cmdlvl > 0)
+ popclvl(); /* Pop command level */
+ return(success = 1); /* always succeeds */
+#ifndef NOSPL
+ } else { /* In script: whatever... */
+ x = mlook(mactab,"continue",nmac);
+ /* Don't set success */
+ return(dodo(x,NULL,cmdstk[cmdlvl].ccflgs));
+#endif /* NOSPL */
+ }
+ }
+#ifdef UNIX
+#ifndef NOPUTENV
+/*
+ NOTE: Syntax is PUTENV name value, not PUTENV name=value.
+ I could check for this but it would be too much magic.
+*/
+ if (cx == XXPUTE) { /* PUTENV */
+ char * t = tmpbuf; /* Create or alter environment var */
+ char * s1 = NULL, * s2 = NULL;
+ if ((x = cmfld("Variable name","",&s,xxstring)) < 0)
+ return(x);
+ if (s) if (s == "") s = NULL;
+ (VOID) makestr(&s1,s);
+ if (s && !s1) {
+ printf("?PUTENV - memory allocation failure\n");
+ return(-9);
+ }
+ if ((x = cmtxt("Value","",&s,xxstring)) < 0)
+ return(x);
+ if (s) if (s == "") s = NULL;
+ (VOID) makestr(&s2,s);
+ success = doputenv(s1,s2);
+ (VOID) makestr(&s1,NULL);
+ (VOID) makestr(&s2,NULL);
+ return(success);
+ }
+#endif /* NOPUTENV */
+#endif /* UNIX */
+
+ if (cx == XXNOTAV) { /* Command in table not available */
+ ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
+ if ((x = cmtxt("Rest of command","",&s,NULL)) < 0)
+ return(x);
+ printf("Sorry, \"%s\" not configured in this version of Kermit.\n",
+ tmpbuf
+ );
+ return(success = 0);
+ }
+ return(-2); /* None of the above */
+
+} /* end of docmd() */
+
+#endif /* NOICP */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuusr.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusr.h
new file mode 100644
index 0000000..83891fb
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusr.h
@@ -0,0 +1,3049 @@
+/* C K U U S R . H -- Symbol definitions for C-Kermit ckuus*.c modules */
+
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#ifndef CKUUSR_H
+#define CKUUSR_H
+
+#include "ckucmd.h" /* Get symbols from command package */
+
+#ifndef NOLUCACHE /* Use lookup() cache */
+#ifndef NOSPL /* To speed up script programs */
+#ifndef USE_LUCACHE
+#define USE_LUCACHE
+#endif /* USE_LUCACHE */
+#endif /* NOSPL */
+#endif /* NOLUCACHE */
+
+#ifndef NODOUBLEQUOTING /* New to 8.0 */
+#define DOUBLEQUOTING /* Allow fields to be enclosed in */
+#endif /* NODOUBLEQUOTING */ /* doublequotes. */
+
+#ifndef NOLOCUS /* SET LOCUS */
+#define LOCUS
+#endif /* NOLOCUS */
+
+/* Sizes of things - FNVALL and MAXARGLEN increased from 8K 20050912 */
+
+#ifdef BIGBUFOK
+#define FNVALL CMDBL /* Function return value length */
+#define MAXARGLEN CMDBL /* Max func arg length after eval */
+#define MAXARGLIST 1024 /* Max number of args for a macro */
+#define FSPECL CMDBL /* Max length for MSEND/GET string */
+#define MSENDMAX 1024 /* Number of filespecs for MSEND */
+#define MAC_MAX 16384 /* Maximum number of macros */
+
+#else /* Same as above but for smaller builds... */
+
+#define FNVALL 1022
+#define MAXARGLEN 1023
+#define MAXARGLIST 64
+#define FSPECL 300
+#define MSENDMAX 128
+#define MAC_MAX 1024
+#endif /* BIGBUFOK */
+
+#define GVARS 127 /* Highest global var allowed */
+#ifdef BIGBUFOK
+#define VNAML 4096 /* Max length for variable name */
+#define ARRAYREFLEN 1024 /* Max length for array reference */
+#define FORDEPTH 32 /* Maximum depth of nested FOR loops */
+#define MAXTAKE 54 /* Maximum nesting of TAKE files */
+#define MACLEVEL 128 /* Maximum nesting for macros */
+#define INPBUFSIZ 4096 /* Size of INPUT buffer */
+#define PROMPTL 1024 /* Max length for prompt */
+#define LBLSIZ 8192 /* Maximum length for a GOTO label */
+#else
+#define VNAML 256 /* Max length for variable name */
+#define ARRAYREFLEN 128 /* Max length for array reference */
+#define FORDEPTH 10 /* Maximum depth of nested FOR loops */
+#define MAXTAKE 32 /* Maximum nesting of TAKE files */
+#define MACLEVEL 64 /* Maximum nesting for macros */
+#define INPBUFSIZ 256
+#define PROMPTL 256 /* Max length for prompt */
+#define LBLSIZ 128 /* Maximum length for a GOTO label */
+#endif /* BIGBUFOK */
+#define NARGS 10 /* Max number of macro arguments */
+#define LINBUFSIZ (CMDBL + 10) /* Size of line[] buffer */
+#define TMPBUFSIZ (CMDBL + 10) /* Size of temporary buffer */
+
+#define CMDSTKL ( MACLEVEL + MAXTAKE + 2) /* Command stack depth */
+
+#ifndef NOPURGE /* PURGE command */
+#ifdef UNIX
+#define CKPURGE
+#endif /* UNIX */
+#endif /* NOPURGE */
+
+#ifndef NOMINPUT /* MINPUT command */
+#ifndef NOSPL
+#define CK_MINPUT
+#ifndef MINPMAX
+#ifdef BIGBUFOK
+#define MINPMAX 96 /* Max number of MINPUT strings */
+#else
+#define MINPMAX 16
+#endif /* BIGBUFOK */
+#endif /* MINPMAX */
+#define MINPBUFL 256 /* Size of MINPUT temp buffer */
+#endif /* NOSPL */
+#endif /* NOMINPUT */
+
+#define ARRAYBASE 95 /* Lowest array-name character */
+
+#ifndef NOKERBANG
+#ifndef KERBANG
+#define KERBANG
+#endif /* KERBANG */
+#endif /* NOKERBANG */
+
+/* Bit values (1, 2, 4, 8, ...) for the ccflgs field */
+
+#define CF_APC 1 /* Executing an APC command */
+#define CF_KMAC 2 /* Executing a \Kmacro */
+#define CF_CMDL 4 /* Macro from -C "blah" command line */
+#define CF_REXX 8 /* Macro from REXX interpreter */
+#define CF_IMAC 16 /* Internal macro like FOR, WHILE... */
+
+struct cmdptr { /* Command stack structure */
+ int src; /* Command Source */
+ int lvl; /* Current TAKE or DO level */
+ int ccflgs; /* Flags */
+};
+
+struct mtab { /* Macro table, like keyword table */
+ char *kwd; /* But with pointers for vals */
+ char *mval; /* instead of ints. */
+ short flgs;
+};
+
+struct localvar { /* Local variable structure. */
+ char * lv_name;
+ char * lv_value;
+ struct localvar * lv_next;
+};
+
+struct stringlist { /* General purpose string list */
+ char * sl_name;
+ struct stringlist * sl_next;
+};
+
+struct stringint { /* String and (wide) integer */
+ char * sval; /* used mainly with command switches */
+ int ival;
+ CK_OFF_T wval;
+};
+
+#ifndef NOICP
+/*
+ C-Kermit Initialization file...
+
+ System-dependent defaults are built into the program, see below.
+ These can be overridden in either of two ways:
+ 1. CK_DSYSINI is defined at compile time, in which case a default
+ system-wide initialization file name is chosen from below, or:
+ 2: CK_SYSINI is defined to be a string, which lets the program
+ builder choose the initialization filespec at compile time.
+ These can be given on the CC command line, so the source code need not be
+ changed.
+*/
+
+#ifndef CK_SYSINI /* If no initialization file given, */
+#ifdef CK_DSYSINI /* but CK_DSYSINI is defined... */
+
+/* Supply system-dependent "default default" initialization file */
+
+#ifdef UNIX /* For UNIX, system-wide */
+/* This allows one copy of the standard init file on the whole system, */
+/* rather than a separate copy in each user's home directory. */
+#ifdef HPUX10
+#define CK_SYSINI "/usr/share/lib/kermit/ckermit.ini"
+#else
+#ifdef CU_ACIS
+#define CK_SYSINI "/usr/share/lib/kermit/ckermit.ini"
+#else
+#ifdef __linux__
+#define CK_SYSINI "/usr/share/kermit/ckermit.ini"
+#else
+#define CK_SYSINI "/usr/local/bin/ckermit.ini"
+#endif /* linux */
+#endif /* CU_ACIS */
+#endif /* HPUX10 */
+/* Fill in #else..#ifdef's here for VMS, OS/2, etc. */
+/* Fill in matching #endif's here. */
+#endif /* UNIX */
+
+#endif /* CK_DSYSINI */
+#endif /* CK_SYSINI */
+
+#ifdef CK_SYSINI /* Init-file precedence */
+#ifndef CK_INI_A /* A means system-wide file first */
+#ifndef CK_INI_B /* B means user's first */
+#define CK_INI_A /* A is default */
+#endif /* CK_INI_B */
+#endif /* CK_INI_A */
+#else
+#ifdef CK_INI_A /* Otherwise */
+#undef CK_INI_A /* make sure these aren't defined */
+#endif /* CK_INI_A */
+#ifdef CK_INI_B
+#undef CK_INI_B
+#endif /* CK_INI_B */
+#endif /* CK_SYSINI */
+
+#ifdef CK_SYSINI /* One more check... */
+#ifdef CK_INI_A /* Make sure they're not both */
+#ifdef CK_INI_B /* defined. */
+#undef CK_INI_B
+#endif /* CK_INI_B */
+#endif /* CK_INI_A */
+#endif /* CK_SYSINI */
+/*
+ If neither CK_DSYSINI nor CK_SYSINI are defined, these are the
+ built-in defaults for each platform. USE_CUSTOM means to execute the
+ customization file automatically if the initialization file is not found.
+*/
+#ifndef NOCUSTOM
+#ifndef USE_CUSTOM
+#define USE_CUSTOM
+#endif /* USE_CUSTOM */
+#endif /* NOCUSTOM */
+
+#ifndef KERMRCL /* Path length for init file */
+#define KERMRCL CKMAXPATH
+#endif /* KERMRCL */
+
+#ifdef vms
+#define KERMRC "CKERMIT.INI" /* Init file name */
+#define MYCUSTOM "CKERMOD.INI" /* Customization file name */
+#else
+#ifdef OS2
+#ifdef NT
+#define KERMRC "k95.ini"
+#define MYCUSTOM "k95custom.ini"
+#else
+#define KERMRC "k2.ini"
+#define MYCUSTOM "k2custom.ini"
+#endif /* NT */
+#else
+#ifdef UNIXOROSK
+#define KERMRC ".kermrc"
+#define MYCUSTOM ".mykermrc"
+#else
+#ifdef STRATUS
+#define KERMRC "ckermit.ini"
+#define MYCUSTOM "ckermod.ini"
+#else
+#define KERMRC "CKERMIT.INI"
+#define MYCUSTOM "ckermod.ini"
+#endif /* STRATUS */
+#endif /* UNIXOROSK */
+#endif /* OS2 */
+#endif /* vms */
+
+#ifndef KERMRCL
+#define KERMRCL 256
+#endif /* KERMRCL */
+#endif /* NOICP */
+
+/* User interface features */
+
+#ifdef CK_CURSES /* Thermometer */
+#ifndef NO_PCT_BAR
+#ifndef CK_PCT_BAR
+#define CK_PCT_BAR
+#endif /* NO_PCT_BAR */
+#endif /* CK_PCT_BAR */
+#endif /* CK_CURSES */
+
+#ifdef KUI /* KUI requires the Thermometer code */
+#ifndef NO_PCT_BAR
+#ifndef CK_PCT_BAR
+#define CK_PCT_BAR
+#endif /* NO_PCT_BAR */
+#endif /* CK_PCT_BAR */
+#endif /* KUI */
+
+/* Includes */
+
+#ifdef MINIX
+/* why? */
+#include <sys/types.h>
+#endif /* MINIX */
+
+/* Symbols for command source */
+
+#define CMD_KB 0 /* KeyBoard or standard input */
+#define CMD_TF 1 /* TAKE command File */
+#define CMD_MD 2 /* Macro Definition */
+
+/*
+ SET TRANSFER CANCELLATION command should be available in all versions.
+ But for now...
+*/
+#ifdef UNIX /* UNIX has it */
+#ifndef XFRCAN
+#define XFRCAN
+#endif /* XFRCAN */
+#endif /* UNIX */
+#ifdef VMS /* VMS has it */
+#ifndef XFRCAN
+#define XFRCAN
+#endif /* XFRCAN */
+#endif /* VMS */
+#ifdef datageneral /* DG AOS/VS has it */
+#ifndef XFRCAN
+#define XFRCAN
+#endif /* XFRCAN */
+#endif /* datageneral */
+#ifdef STRATUS /* Stratus VOS has it */
+#ifndef XFRCAN
+#define XFRCAN
+#endif /* XFRCAN */
+#endif /* STRATUS */
+#ifdef OSK /* OS-9 */
+#ifndef XFRCAN
+#define XFRCAN
+#endif /* XFRCAN */
+#endif /* OSK */
+
+#ifndef NOCMDL
+/* Extended Command-Line Option Codes (keep alphabetical by keyword) */
+
+#define XA_ANON 0 /* --anonymous */
+#define XA_BAFI 1 /* --bannerfile */
+#define XA_CDFI 2 /* --cdfile */
+#define XA_CDMS 3 /* --cdmessage */
+#define XA_HELP 4 /* --help */
+#define XA_HEFI 5 /* --helpfile */
+#define XA_IKFI 6 /* --xferfile */
+#define XA_IKLG 7 /* --xferlog */
+#define XA_ANFI 8 /* --initfile */
+#define XA_PERM 9 /* --permissions */
+#define XA_ROOT 10 /* --root */
+#define XA_SYSL 11 /* --syslog */
+#define XA_USFI 12 /* --userfile */
+#define XA_WTFI 13 /* --wtmpfile */
+#define XA_WTMP 14 /* --wtmplog */
+#define XA_TIMO 15 /* --timeout */
+#define XA_NOIN 16 /* --nointerrupts */
+#define XA_DBAS 17 /* --database */
+#define XA_DBFI 18 /* --dbfile */
+#define XA_PRIV 19 /* --privid */
+#define XA_VERS 20 /* --version */
+#define XA_NPRM 21 /* --noperms */
+#define XA_XPOS 22 /* Window position X coordinate */
+#define XA_YPOS 23 /* Window position Y coordinate */
+#define XA_FNAM 24 /* Font Facename */
+#define XA_FSIZ 25 /* Font Size */
+#define XA_TERM 26 /* Terminal type */
+#define XA_CSET 27 /* Remote Character Set */
+#define XA_ROWS 28 /* Screen rows (height) */
+#define XA_COLS 29 /* Screen columns (width) */
+#define XA_TEL 30 /* Make a Telnet connection */
+#define XA_FTP 31 /* Make an FTP connection */
+#define XA_SSH 32 /* Make an SSH connection */
+#define XA_USER 33 /* Username for login */
+#define XA_PASS 34 /* Password for login */
+#define XA_TITL 35 /* Window Title */
+#define XA_NOMN 36 /* No GUI Menu Bar */
+#define XA_NOTB 37 /* No GUI Tool Bar */
+#define XA_NOSB 38 /* No GUI Status Bar */
+#define XA_NOPUSH 39 /* Disable external commands */
+#define XA_NOSCROLL 40 /* Disable scrollback operations */
+#define XA_NOESCAPE 41 /* Disable escape from connect mode */
+#define XA_LOCK 42 /* All lockdown options */
+#define XA_NOBAR 43 /* No GUI Bars */
+#define XA_WMAX 44
+#define XA_WMIN 45
+#define XA_SCALE 46 /* GUI Scale Font */
+#define XA_CHGD 47 /* GUI Change Dimensions */
+#define XA_NOCLOSE 48 /* GUI Disable Close Window */
+#define XA_UNBUF 49 /* UNIX unbuffered console */
+#define XA_MAX 49 /* Highest extended option number */
+#endif /* NOCMDL */
+
+#ifndef NOICP
+/* Top Level Commands */
+/* Values associated with top-level commands must be 0 or greater. */
+
+#define XXBYE 0 /* BYE */
+#define XXCLE 1 /* CLEAR */
+#define XXCLO 2 /* CLOSE */
+#define XXCON 3 /* CONNECT */
+#define XXCPY 4 /* COPY */
+#define XXCWD 5 /* CWD (Change Working Directory) */
+#define XXDEF 6 /* DEFINE (a macro or variable) */
+#define XXDEL 7 /* (Local) DELETE */
+#define XXDIR 8 /* (Local) DIRECTORY */
+
+/* DIRECTORY Command options... */
+#define DIR_BRF 1 /* BRIEF */
+#define DIR_VRB 2 /* VERBOSE */
+#define DIR_PAG 3 /* PAGE */
+#define DIR_NOP 4 /* NOPAGE */
+#define DIR_ISO 5 /* ISODATE */
+#define DIR_DAT 6 /* ENGLISHDATE */
+#define DIR_HDG 7 /* HEADINGS */
+#define DIR_NOH 8 /* NOHEADINGS */
+#define DIR_SRT 9 /* SORT */
+#define DIR_NOS 10 /* NOSORT */
+#define DIR_ASC 11 /* ASCENDING */
+#define DIR_DSC 12 /* DESCENDING */
+#define DIR_REC 13 /* RECURSIVE */
+#define DIR_NOR 14 /* NORECURIVE */
+#define DIR_DOT 15 /* DOTFILES */
+#define DIR_NOD 16 /* NODOTFILES */
+#define DIR_DIR 17 /* DIRECTORIES */
+#define DIR_FIL 18 /* FILES */
+#define DIR_ALL 19 /* ALL */
+#define DIR_NAM 20 /* NAMES: */
+#define DIR_TYP 21 /* FILETYPES */
+#define DIR_NOT 22 /* NOFILETYPES */
+#define DIR_BUP 23 /* BACKUP */
+#define DIR_NOB 24 /* NOBACKUP */
+#define DIR_MSG 25 /* MESSAGE */
+#define DIR_NOM 26 /* NOMESSAGE */
+#define DIR_ARR 27 /* ARRAY: */
+#define DIR_NAR 28 /* NOARRAY */
+#define DIR_EXC 29 /* EXCEPT: */
+#define DIR_LAR 30 /* LARGER-THAN: */
+#define DIR_SMA 31 /* SMALLER-THAN: */
+#define DIR_AFT 32 /* AFTER: */
+#define DIR_NAF 33 /* NOT-AFTER: */
+#define DIR_BEF 34 /* BEFORE: */
+#define DIR_NBF 35 /* NOT-BEFORE: */
+#define DIR_SUM 36 /* SUMMARY */
+#define DIR_BIN 37 /* TYPE (only show binary or text) */
+#define DIR_LNK 38 /* follow symlinks */
+#define DIR_NLK 39 /* don't follow symlinks */
+#define DIR_OUT 40 /* Output file for listing */
+#define DIR_TOP 41 /* Top n lines */
+#define DIR_COU 42 /* COUNT:var */
+#define DIR_NOL 43 /* NOLINKS (don't show symlinks at at all) */
+
+#define DIRS_NM 0 /* Sort directory by NAME */
+#define DIRS_DT 1 /* Sort directory by DATE */
+#define DIRS_SZ 2 /* Sort directory by SIZE */
+
+#define XXDIS 9 /* DISABLE */
+#define XXECH 10 /* ECHO */
+#define XXEXI 11 /* EXIT */
+#define XXFIN 12 /* FINISH */
+#define XXGET 13 /* GET */
+#define XXHLP 14 /* HELP */
+#define XXINP 15 /* INPUT */
+#define XXLOC 16 /* LOCAL */
+#define XXLOG 17 /* LOG */
+#define XXMAI 18 /* MAIL */
+#define XXMOU 19 /* (Local) MOUNT */
+#define XXMSG 20 /* (Local) MESSAGE */
+#define XXOUT 21 /* OUTPUT */
+#define XXPAU 22 /* PAUSE */
+#define XXPRI 23 /* (Local) PRINT */
+#define XXQUI 24 /* QUIT */
+#define XXREC 25 /* RECEIVE */
+#define XXREM 26 /* REMOTE */
+#define XXREN 27 /* (Local) RENAME */
+#define XXSEN 28 /* SEND */
+
+/* SEND switches */
+
+#define SND_BIN 0 /* Binary mode */
+#define SND_DEL 1 /* Delete after */
+#define SND_EXC 2 /* Except */
+#define SND_LAR 3 /* Larger than */
+#define SND_MAI 4 /* Mail */
+#define SND_BEF 5 /* Before */
+#define SND_AFT 6 /* After */
+#define SND_PRI 7 /* Print */
+#define SND_SHH 8 /* Quiet */
+#define SND_REC 9 /* Recursive */
+#define SND_SMA 10 /* Smaller than */
+#define SND_STA 11 /* Starting-from */
+#define SND_TXT 12 /* Text mode */
+#define SND_CMD 13 /* From command (pipe) */
+#define SND_RES 14 /* Resend/Recover */
+#define SND_PRO 15 /* Protocol */
+#define SND_ASN 16 /* As-name */
+#define SND_IMG 17 /* Image */
+#define SND_LBL 18 /* Labeled */
+#define SND_NAF 19 /* Not-After */
+#define SND_NBE 20 /* Not-Before */
+#define SND_FLT 21 /* Filter */
+#define SND_PTH 22 /* Pathnames */
+#define SND_NAM 23 /* Filenames */
+#define SND_MOV 24 /* MOVE to another directory */
+#define SND_REN 25 /* RENAME after sending */
+#define SND_CAL 26 /* Calibrate */
+#define SND_FIL 27 /* File containing list of files to send */
+#define SND_NOB 28 /* Skip backup files */
+#define SND_DOT 29 /* Include dot-files */
+#define SND_NOD 30 /* Exclude dot-files */
+#define SND_ARR 31 /* Send from array */
+#define SND_TYP 32 /* TYPE (only send text (or binary)) */
+#define SND_XPA 33 /* TRANSPARENT */
+#define SND_PIP 34 /* PIPES */
+#define SND_ERR 35 /* ERROR */
+#define SND_CSL 36 /* Local character set */
+#define SND_CSR 37 /* Remote character set */
+#define SND_UPD 38 /* Update */
+#define SND_COL 39 /* Collision */
+#define SND_NML 40 /* Namelist */
+#define SND_SRN 41 /* Server-Rename */
+#define SND_LNK 42 /* Follow links */
+#define SND_NLK 43 /* Don't follow links */
+#define SND_SIM 44 /* Simulate */
+#define SND_DIF 45 /* If dates Differ */
+#define SND_PAT 46 /* Pattern to use locally when GET'ing */
+#define SND_NLS 47 /* (FTP only) MGET forces NLST */
+#define SND_MLS 48 /* (FTP only) MGET forces MLSD */
+
+#define SND_MAX 48 /* Highest SEND switch */
+
+#define XXSER 29 /* SERVER */
+#define XXSET 30 /* SET */
+#define XXSHE 31 /* Command for SHELL */
+#define XXSHO 32 /* SHOW */
+#define XXSPA 33 /* (Local) SPACE */
+#define XXSTA 34 /* STATISTICS */
+#define XXSUB 35 /* (Local) SUBMIT */
+#define XXTAK 36 /* TAKE */
+#define XXTRA 37 /* TRANSMIT */
+#define XXTYP 38 /* (Local) TYPE */
+#define XXWHO 39 /* (Local) WHO */
+#define XXDIAL 40 /* (Local) DIAL */
+#define XXLOGI 41 /* (Local) SCRIPT */
+#define XXCOM 42 /* Comment */
+#define XXHAN 43 /* HANGUP */
+#define XXXLA 44 /* TRANSLATE */
+#define XXIF 45 /* IF */
+#define XXLBL 46 /* label */
+#define XXGOTO 47 /* GOTO */
+#define XXEND 48 /* END */
+#define XXSTO 49 /* STOP */
+#define XXDO 50 /* DO */
+#define XXPWD 51 /* PWD */
+#define XXTES 52 /* TEST */
+#define XXASK 53 /* ASK */
+#define XXASKQ 54 /* ASKQ */
+#define XXASS 55 /* ASSIGN */
+#define XXREI 56 /* REINPUT */
+#define XXINC 57 /* INCREMENT */
+#define XXDEC 59 /* DECREMENT */
+#define XXELS 60 /* ELSE */
+#define XXEXE 61 /* EXECUTE */
+#define XXWAI 62 /* WAIT */
+#define XXVER 63 /* VERSION */
+#define XXENA 64 /* ENABLE */
+#define XXWRI 65 /* WRITE */
+#define XXCLS 66 /* CLS (clear screen) */
+#define XXRET 67 /* RETURN */
+#define XXOPE 68 /* OPEN */
+#define XXREA 69 /* READ */
+#define XXON 70 /* ON */
+#define XXDCL 71 /* DECLARE */
+#define XXBEG 72 /* BEGIN (not used) */
+#define XXFOR 72 /* FOR */
+#define XXWHI 73 /* WHILE */
+#define XXIFX 74 /* Extended IF */
+#define XXCMS 75 /* SEND from command output (not yet) */
+#define XXCMR 76 /* RECEIVE to a command's input (not yet) */
+#define XXCMG 77 /* GET to a command's input (not yet) */
+#define XXSUS 78 /* SUSPEND */
+#define XXERR 79 /* ERROR */
+#define XXMSE 80 /* MSEND */
+#define XXBUG 81 /* BUG */
+#define XXPAD 82 /* PAD (as in X.25 PAD) ANYX25 */
+#define XXRED 83 /* REDIAL */
+#define XXGTA 84 /* _getargs (invisible internal) */
+#define XXPTA 85 /* _putargs (invisible internal) */
+#define XXGOK 86 /* GETOK - Ask for YES/NO */
+#define XXTEL 87 /* TELNET */
+#define XXASX 88 /* _ASSIGN (evaluates var name) */
+#define XXDFX 89 /* _DEFINE (evaluates var name) */
+#define XXPNG 90 /* PING (for TCP/IP) */
+#define XXINT 91 /* INTRODUCTION */
+#define XXCHK 92 /* CHECK (a feature) */
+#define XXMSL 93 /* MSLEEP, MPAUSE (millisecond sleep) */
+#define XXNEW 94 /* NEWS */
+#define XXAPC 95 /* APC */
+#define XXFUN 96 /* REDIRECT */
+#define XXWRL 97 /* WRITE-LINE */
+#define XXREXX 98 /* Rexx */
+#define XXMINP 100 /* MINPUT */
+#define XXRSEN 101 /* RESEND */
+#define XXPSEN 102 /* PSEND */
+#define XXGETC 103 /* GETC */
+#define XXEVAL 104 /* EVALUATE */
+#define XXFWD 105 /* FORWARD */
+#define XXUPD 106 /* UPDATES */
+#define XXBEEP 107 /* BEEP */
+#define XXMOVE 108 /* MOVE */
+#define XXMMOVE 109 /* MMOVE */
+#define XXREGET 110 /* REGET */
+#define XXLOOK 111 /* LOOKUP */
+#define XXVIEW 112 /* VIEW (terminal buffer) */
+#define XXANSW 113 /* ANSWER (the phone) */
+#define XXPDIA 114 /* PDIAL (partial dial) */
+#define XXASC 115 /* ASCII / TEXT */
+#define XXBIN 116 /* BINARY */
+#define XXFTP 117 /* FTP */
+#define XXMKDIR 118 /* MKDIR */
+#define XXRMDIR 119 /* RMDIR */
+#define XXTELOP 120 /* TELOPT */
+#define XXRLOG 121 /* RLOGIN */
+#define XXUNDEF 122 /* UNDEFINE */
+#define XXNPSH 123 /* NOPUSH */
+#define XXADD 124 /* ADD */
+#define ADD_SND 0 /* ADD SEND-LIST */
+#define ADD_BIN 1 /* ADD BINARY-PATTERNS */
+#define ADD_TXT 2 /* ADD TEXT-PATTERNS */
+#define XXLOCAL 125 /* LOCAL */
+#define XXKERMI 126 /* KERMIT */
+#define XXDATE 127 /* DATE */
+#define XXSWIT 128 /* SWITCH */
+#define XXXFWD 129 /* _FORWARD */
+#define XXSAVE 130 /* SAVE */
+#define XXXECH 131 /* XECHO */
+#define XXRDBL 132 /* READBLOCK */
+#define XXWRBL 133 /* WRITEBLOCK */
+#define XXRETR 134 /* RETRIEVE */
+#define XXEIGHT 135 /* EIGHTBIT */
+#define XXEDIT 136 /* EDIT */
+#define XXCSEN 137 /* CSEND */
+#define XXCREC 138 /* CRECEIVE */
+#define XXCQ 139 /* CQ */
+#define XXTAPI 140 /* TAPI actions such as dialogs */
+#define XXRES 141 /* RESET */
+#define XXCGET 142 /* CGET */
+#define XXFUNC 143 /* Function (help-only) */
+#define XXKVRB 144 /* Kverb (help-only) */
+#define XXBROWS 145 /* BROWSE */
+#define XXMGET 146 /* MGET */
+#define XXBACK 147 /* BACK */
+#define XXWHERE 148 /* WHERE */
+#define XXREDO 149 /* REDO */
+#define XXEXCH 150 /* EXCHANGE */
+#define XXREMV 151 /* REMOVE */
+#define XXCHRT 152 /* CHROOT */
+#define XXOPTS 153 /* Options (help-only) */
+#define XXAUTH 154 /* AUTHORIZE */
+#define XXPIPE 155 /* PIPE */
+#define XXSSH 156 /* SSH */
+#define XXTERM 157 /* TERMINAL */
+#define XXSTATUS 158 /* STATUS */
+#define XXCPR 159 /* COPYRIGHT */
+#define XXASSER 160 /* ASSERT */
+#define XXSUCC 161 /* SUCCEED */
+#define XXFAIL 162 /* FAIL */
+#define XXLOGIN 163 /* LOGIN */
+#define XXLOGOUT 164 /* LOGOUT */
+#define XXNLCL 165 /* NOLOCAL */
+#define XXWILD 166 /* WILDCARDS (help-only) */
+
+/* One-word synonyms for REMOTE commands */
+
+#define XXRCPY 167 /* REMOTE COPY */
+#define XXRCWD 168 /* Change Working Directory */
+#define XXRDEL 169 /* Delete */
+#define XXRDIR 170 /* Directory */
+#define XXRHLP 171 /* Help */
+#define XXRHOS 172 /* Host */
+#define XXRKER 173 /* Kermit */
+#define XXRMSG 174 /* Message */
+#define XXRPRI 175 /* Print */
+#define XXRREN 176 /* Rename */
+#define XXRSET 177 /* Set */
+#define XXRSPA 178 /* Space */
+#define XXRSUB 179 /* Submit */
+#define XXRTYP 180 /* Type */
+#define XXRWHO 181 /* Who */
+#define XXRPWD 182 /* Print Working Directory */
+#define XXRQUE 183 /* Query */
+#define XXRASG 184 /* Assign */
+#define XXRMKD 185 /* mkdir */
+#define XXRRMD 186 /* rmdir */
+#define XXRXIT 187 /* Exit */
+
+/* Top-Level commands, cont'd... */
+
+#define XXGETK 188 /* GETKEYCODE */
+#define XXMORE 189 /* MORE */
+#define XXXOPTS 190 /* Extended-Options (help-only) */
+#define XXIKSD 191 /* IKSD */
+#define XXRESET 192 /* RESET */
+#define XXASSOC 193 /* ASSOCIATE */
+
+#define ASSOC_FC 0 /* ASSOCIATE FILE-CHARACTER-SET */
+#define ASSOC_TC 1 /* ASSOCIATE TRANSFER-CHARACTER-SET */
+
+#define XXSHIFT 194 /* SHIFT */
+#define XXMAN 195 /* MANUAL */
+#define XXLS 196 /* LS */
+#define XXSORT 197 /* SORT */
+#define XXPURGE 198 /* PURGE */
+#define XXFAST 199 /* FAST */
+#define XXCAU 200 /* CAUTIOUS */
+#define XXROB 201 /* ROBUST */
+#define XXMACRO 202 /* Immediate macro */
+#define XXSCRN 203 /* SCREEN */
+#define XXLNOUT 204 /* LINEOUT */
+#define XX_INCR 205 /* _INCREMENT */
+#define XX_DECR 206 /* _DECREMENT */
+#define XX_EVAL 207 /* _EVALUATE */
+#define XXARRAY 208 /* ARRAY */
+#define XXPARSE 209 /* PARSE */
+#define XXHTTP 210 /* HTTP */
+
+#ifdef CKCHANNELIO
+#define XXFILE 211 /* FILE */
+#define XXF_CL 212 /* FCLOSE */
+#define XXF_FL 213 /* FFLUSH */
+#define XXF_LI 214 /* FLIST */
+#define XXF_OP 215 /* FOPEN */
+#define XXF_RE 216 /* FREAD */
+#define XXF_SE 217 /* FSEEK */
+#define XXF_ST 218 /* FSTATUS */
+#define XXF_WR 219 /* FWRITE */
+#define XXF_RW 220 /* FREWIND */
+#define XXF_CO 221 /* FCOUNT */
+#endif /* CKCHANNELIO */
+
+#define XXEXEC 222 /* exec() */
+#define XXTRACE 223 /* TRACE */
+#define XXNOTAV 224 /* The "not available" command */
+#define XXPTY 225 /* PTY (like PIPE) */
+#define XXCHMOD 226 /* CHMOD */
+#define XXPROMP 227 /* PROMPT */
+#define XXFEACH 228 /* FOREACH */
+#define XXGREP 229 /* GREP */
+#define XXSEXP 230 /* S-Expression */
+#define XXUNDCL 231 /* UNDECLARE */
+#define XXVOID 232 /* VOID */
+#define XXPUT 233 /* PUT */
+#define XXUNDFX 234 /* _UNDEFINE */
+#define XXHEAD 235 /* HEAD */
+#define XXTAIL 236 /* TAIL */
+#define XXDEBUG 237 /* DEBUG */
+#define XXLEARN 238 /* LEARN */
+#define XXPAT 239 /* PATTERNS (help only) */
+
+#define XXCDUP 240 /* CDUP (Change working directory upwards) */
+#define XXRCDUP 241 /* REMOTE CDUP */
+#define XXCAT 242 /* CAT (= TYPE /NOPAGE) */
+#define XXFIREW 243 /* FIREWALL (help only) */
+
+#define XXLCWD 244 /* Local C(W)D */
+#define XXLCDU 245 /* Local CDUP */
+#define XXLPWD 246 /* Local PWD */
+#define XXLDEL 247 /* Local DELETE */
+#define XXLDIR 248 /* Local DIRECTORY */
+#define XXLREN 249 /* Local RENAME */
+#define XXLMKD 250 /* Local MKDIR */
+#define XXLRMD 251 /* Local RMDIR */
+#define XXUSER 252 /* (FTP) USER */
+#define XXACCT 253 /* (FTP) ACCOUNT */
+#define XXLINK 254 /* LINK source destination */
+#define XXORIE 255 /* ORIENT(ATION) */
+#define XXDIALER 256 /* DIALER */
+#define XXKCD 257 /* KCD */
+#define XXSITE 258 /* (FTP) SITE */
+#define XXPASV 259 /* (FTP) PASSIVE */
+#define XXCONT 260 /* CONTINUE */
+#define XXNSCR 261 /* NOSCROLL */
+#define XXSFTP 262 /* SFTP */
+#define XXSKRM 263 /* SKERMIT */
+#define XXWDIR 264 /* WDIRECTORY */
+#define XXHDIR 265 /* HDIRECTORY */
+#define XXTOUC 266 /* TOUCH */
+#define XXLOCU 267 /* LOCUS (for HELP) */
+#define XXPUTE 268 /* PUTENV */
+#define XXXMSG 269 /* XMESSAGE */
+
+/* End of Top-Level Commands */
+
+#define SCN_CLR 0 /* SCREEN CLEAR */
+#define SCN_CLE 1 /* SCREEN CLEOL */
+#define SCN_MOV 2 /* SCREEN MOVE */
+
+/* ARRAY operations */
+
+#define ARR_DCL 0 /* Declare */
+#define ARR_CPY 1 /* Copy */
+#define ARR_RSZ 2 /* Resize */
+#define ARR_SRT 3 /* Sort */
+#define ARR_CLR 4 /* Clear */
+#define ARR_SEA 5 /* Search */
+#define ARR_DST 6 /* Destroy */
+#define ARR_SHO 7 /* Show */
+#define ARR_SET 8 /* Set */
+#define ARR_EQU 9 /* Equate */
+
+/* SORT options */
+
+#define SRT_CAS 0 /* /CASE */
+#define SRT_KEY 1 /* /KEY:n */
+#define SRT_REV 2 /* /REVERSE */
+#define SRT_RNG 3 /* /RANGE:n:m */
+#define SRT_NUM 4 /* /NUMERIC */
+
+/* PURGE command options */
+
+#define PU_KEEP 0 /* /KEEP: */
+#define PU_LIST 1 /* /LIST */
+#define PU_PAGE 2 /* /PAGE */
+#define PU_NOPA 3 /* /NOPAGE */
+#define PU_NODE 4 /* /SIMULATE */
+#define PU_DELE 5 /* /DELETE */
+#define PU_NOLI 6 /* /NOLIST */
+#define PU_QUIE 7 /* /QUIET (= NOLIST) */
+#define PU_VERB 8 /* /VERBOSE (= LIST) */
+#define PU_ASK 9 /* /ASK */
+#define PU_NASK 10 /* /NOASK */
+#define PU_LAR 11 /* /LARGER-THAN: */
+#define PU_SMA 12 /* /SMALLER-THAN: */
+#define PU_AFT 13 /* /AFTER: */
+#define PU_NAF 14 /* /NOT-AFTER: */
+#define PU_BEF 15 /* /BEFORE: */
+#define PU_NBF 16 /* /NOT-BEFORE: */
+#define PU_EXC 17 /* /EXCEPT: */
+#define PU_RECU 18 /* /RECURSIVE */
+#define PU_DOT 19 /* /DOTFILES */
+#define PU_NODOT 20 /* /NODOTFILES */
+#define PU_HDG 21 /* /HEADING */
+#define PU_NOH 22 /* /NOHEADING */
+
+/* DELETE command options */
+
+#define DEL_NOL 0 /* /NOLIST */
+#define DEL_LIS 1 /* /LIST */
+#define DEL_HDG 2 /* /HEADINGS */
+#define DEL_NOH 2 /* /NOHEADINGS */
+#define DEL_BEF 3 /* /BEFORE: */
+#define DEL_NBF 4 /* /NOT-BEFORE: */
+#define DEL_AFT 5 /* /AFTER: */
+#define DEL_NAF 6 /* /NOT-AFTER: */
+#define DEL_DOT 7 /* /DOTFILES */
+#define DEL_NOD 8 /* /NODOTFILES */
+#define DEL_EXC 9 /* /EXCEPT:*/
+#define DEL_PAG 10 /* /PAGE */
+#define DEL_NOP 11 /* /NOPAGE */
+#define DEL_REC 12 /* /RECURSIVE */
+#define DEL_NOR 13 /* /NORECURSIVE */
+#define DEL_VRB 14 /* /VERBOSE */
+#define DEL_QUI 15 /* /QUIET */
+#define DEL_SMA 16 /* /SMALLER-THAN: */
+#define DEL_LAR 17 /* /LARGER-THAN: */
+#define DEL_SIM 18 /* /SIMULATE */
+#define DEL_ASK 19 /* /ASK */
+#define DEL_NAS 20 /* /NOASK */
+#define DEL_SUM 21 /* /SUMMARY */
+#define DEL_DIR 22 /* /DIRECTORY */
+#define DEL_ALL 23 /* /ALL */
+#define DEL_TYP 24 /* /TYPE: */
+#define DEL_LNK 25 /* /FOLLOWLINKS */
+#define DEL_NLK 26 /* /NOFOLLOWLINKS */
+
+/* RENAME switches that can be used in the same table as the DEL switches */
+
+#define REN_LOW 100 /* Convert to lowercase */
+#define REN_UPP 101 /* Converto to uppercase */
+#define REN_RPL 102 /* String replacement */
+#define REN_OVW 103 /* Overwrite file with same name */
+#define REN_XLA 104 /* Translate character sets */
+#define REN_SPA 105 /* Fix spaces */
+
+/* FILE operations */
+
+#define FIL_OPN 0 /* OPEN */
+#define FIL_CLS 1 /* CLOSE */
+#define FIL_REA 2 /* READ */
+#define FIL_GET 3 /* GET */
+#define FIL_WRI 4 /* WRITE */
+#define FIL_REW 5 /* REWIND */
+#define FIL_LIS 6 /* LIST */
+#define FIL_FLU 7 /* FLUSH */
+#define FIL_SEE 8 /* SEEK */
+#define FIL_STA 9 /* STATUS */
+#define FIL_COU 10 /* COUNT */
+
+/* OPEN / CLOSE items */
+
+#define OPN_FI_R 1 /* FILE READ */
+#define OPN_FI_W 2 /* FILE WRITE */
+#define OPN_FI_A 3 /* FILE APPEND */
+#define OPN_PI_R 4 /* PIPE READ */
+#define OPN_PI_W 5 /* PIPE WRITE */
+#define OPN_PT_R 6 /* PTY READ */
+#define OPN_PT_W 7 /* PTY WRITE */
+#define OPN_SER 8 /* PORT or LINE */
+#define OPN_NET 9 /* HOST */
+
+/* KERBEROS command switches */
+
+#define KRB_S_VE 0 /* /VERSION */
+#define KRB_S_CA 1 /* /CACHE: */
+#define KRB_S_MAX 1 /* Highest KERBEROS switch number */
+
+#ifdef CK_KERBEROS
+
+/* KERBEROS actions */
+
+#define KRB_A_IN 0 /* INITIALIZE */
+#define KRB_A_DE 1 /* DESTROY */
+#define KRB_A_LC 2 /* LIST-CREDENTIALS */
+
+/* KERBEROS INIT switches */
+
+#define KRB_I_FW 0 /* /FORWARDABLE */
+#define KRB_I_LF 1 /* /LIFETIME: */
+#define KRB_I_PD 2 /* /POSTDATE: */
+#define KRB_I_PR 3 /* /PROXIABLE */
+#define KRB_I_RB 4 /* /RENEWABLE: */
+#define KRB_I_RN 5 /* /RENEW */
+#define KRB_I_SR 6 /* /SERVICE: */
+#define KRB_I_VA 7 /* /VALIDATE */
+#define KRB_I_RL 8 /* /REALM: */
+#define KRB_I_IN 9 /* /INSTANCE: */
+#define KRB_I_PW 10 /* /PASSWORD: */
+#define KRB_I_PA 11 /* /PREAUTH */
+#define KRB_I_VB 12 /* /VERBOSE */
+#define KRB_I_BR 13 /* /BRIEF */
+#define KRB_I_NFW 14 /* /NOT-FORWARDABLE */
+#define KRB_I_NPR 15 /* /NOT-PROXIABLE */
+#define KRB_I_NPA 16 /* /NOT-PREAUTH */
+#define KRB_I_K4 17 /* /KERBEROS4 (should k5 get k4 as well) */
+#define KRB_I_NK4 18 /* /NO-KERBEROS4 */
+#define KRB_I_POP 19 /* /POPUP */
+#define KRB_I_ADR 20 /* /ADDRESSES: */
+#define KRB_I_NAD 21 /* /NO-ADDRESSES */
+#define KRB_I_MAX 21 /* Highest KERBEROS INIT switch number */
+
+#endif /* CK_KERBEROS */
+
+/* SET parameters */
+
+#define XYBREA 0 /* BREAK simulation */
+#define XYCHKT 1 /* Block check type */
+#define XYDEBU 2 /* Debugging */
+#define XYDELA 3 /* Delay */
+#define XYDUPL 4 /* Duplex */
+#define XYEOL 5 /* End-Of-Line (packet terminator) */
+#define XYESC 6 /* Escape character */
+#define XYFILE 7 /* File Parameters (see ckcker.h for values) */
+ /* (this space available) */
+#define XYFLOW 9 /* Flow Control */
+#define XYHAND 10 /* Handshake */
+#define XYIFD 11 /* Incomplete File Disposition */
+#define XYIMAG 12 /* "Image Mode" */
+#define XYINPU 13 /* INPUT command parameters */
+#define XYLEN 14 /* Maximum packet length to send */
+#define XYLINE 15 /* Communication line to use */
+
+/* SET LINE / SET HOST command switches */
+
+#define SL_CNX 0 /* /CONNECT */
+#define SL_SRV 1 /* /SERVER */
+#define SL_SHR 2 /* /SHARE */
+#define SL_NSH 3 /* /NOSHARE */
+#define SL_BEE 4 /* /BEEP */
+#define SL_ANS 5 /* /ANSWER */
+#define SL_DIA 6 /* /DIAL:xxx */
+#define SL_SPD 7 /* /SPEED:xxx */
+#define SL_FLO 8 /* /FLOW:xxx */
+#define SL_TMO 9 /* /TIMEOUT:xxx */
+#define SL_CMD 10 /* /COMMAND */
+#define SL_PSW 11 /* /PASSWORD:xxx */
+#define SL_IKS 12 /* /KERMIT-SERVICE */
+#define SL_NET 13 /* /NETWORK-TYPE:xxx */
+#define SL_ENC 14 /* /ENCRYPT:type (telnet) /ENCRYPT (rlogin) */
+#define SL_KRB4 15 /* /KERBEROS 4 (rlogin/telnet) */
+#define SL_KRB5 16 /* /KERBEROS 5 (rlogin/telnet) */
+#define SL_SRP 17 /* /SRP (telnet) */
+#define SL_NTLM 18 /* /NTLM (telnet) */
+#define SL_SSL 19 /* /SSL (telnet) */
+#define SL_UID 20 /* /USERID:xxxx */
+#define SL_AUTH 21 /* /AUTH:type */
+#define SL_WAIT 22 /* /WAIT */
+#define SL_NOWAIT 23 /* /NOWAIT */
+#define SL_PTY 24 /* /PTY */
+
+#define XYLOG 16 /* Log file */
+#define XYMARK 17 /* Start of Packet mark */
+#define XYNPAD 18 /* Amount of padding */
+#define XYPADC 19 /* Pad character */
+#define XYPARI 20 /* Parity */
+#define XYPAUS 21 /* Interpacket pause */
+#define XYPROM 22 /* Program prompt string */
+#define XYQBIN 23 /* 8th-bit prefix */
+#define XYQCTL 24 /* Control character prefix */
+#define XYREPT 25 /* Repeat count prefix */
+#define XYRETR 26 /* Retry limit */
+#define XYSPEE 27 /* Line speed (baud rate) */
+#define XYTACH 28 /* Character to be doubled */
+#define XYTIMO 29 /* Timeout interval */
+#define XYMODM 30 /* Modem - also see XYDIAL */
+
+#define XYSEND 31 /* SET SEND parameters */
+#define XYRECV 32 /* SET RECEIVE parameters */
+#define XYTERM 33 /* SET TERMINAL parameters */
+#define XYTBYT 0 /* Terminal Bytesize (7 or 8) */
+#define XYTTYP 1 /* Terminal emulation Type */
+#define TT_NONE 0 /* NONE, no emulation */
+#ifdef OS2
+/*
+ Note, the symbols for VT and VT-like terminals should be in ascending
+ numerical order, so that higher ones can be treated as supersets of
+ lower ones with respect to capabilities.
+
+ This is no longer the case with the influx of new terminal types.
+ Just make sure that the ISXXXXX() macros include the proper family
+ groups.
+*/
+#define TT_DG200 1 /* Data General 200 */
+#define TT_DG210 2 /* Data General 210 */
+#define TT_DG217 3 /* Data General 217 */
+#define TT_HP2621 4 /* Hewlett-Packard 2621A */
+#define TT_HPTERM 5 /* Hewlett-Packard Console */
+#define TT_HZL1500 6 /* Hazeltine 1500 */
+#define TT_VC4404 7 /* Volker Craig VC4404/404 */
+#define TT_WY30 8 /* WYSE-30/30+ */
+#define TT_WY50 9 /* WYSE-50/50+ */
+#define TT_WY60 10 /* WYSE-60 */
+#define TT_WY160 11 /* WYSE-160 */
+#define TT_QNX 12 /* QNX */
+#define TT_QANSI 13 /* QNX Ansi emulation */
+#define TT_VT52 14 /* DEC VT-52 */
+#define TT_H19 15 /* Heath-19 */
+#define TT_IBM31 16 /* IBM 31xx */
+#define TT_SCOANSI 17 /* SCOANSI (Unix mode) */
+#define TT_AT386 18 /* Unixware AT386 (Unix mode) */
+#define TT_ANSI 19 /* IBM ANSI.SYS (BBS) */
+#define TT_VIP7809 20 /* Honeywell VIP7809 */
+#define TT_LINUX 21 /* Linux Console */
+#define TT_HFT 22 /* IBM High Function Terminal */
+#define TT_AIXTERM 23 /* IBM AIXterm */
+#define TT_SUN 24 /* SUN Console */
+#define TT_BA80 25 /* Nixdorf BA80 */
+#define TT_BEOS 26 /* BeOS Ansi */
+#define TT_VT100 27 /* DEC VT-100 */
+#define TT_VT102 28 /* DEC VT-102 */
+#define TT_VT220 29 /* DEC VT-220 */
+#define TT_VT220PC 30 /* DEC VT-220 with PC keyboard */
+#define TT_VT320 31 /* DEC VT-320 */
+#define TT_VT320PC 32 /* DEC VT-320 with PC keyboard */
+#define TT_WY370 33 /* WYSE 370 ANSI Terminal */
+#define TT_97801 34 /* Sinix 97801-5xx terminal */
+#define TT_AAA 35 /* Ann Arbor Ambassador */
+#define TT_TVI910 36 /* TVI 910+ */
+#define TT_TVI925 37 /* TVI 925 */
+#define TT_TVI950 38 /* TVI950 */
+#define TT_ADM3A 39 /* LSI ADM 3A */
+#define TT_ADM5 40 /* LSI ADM 5 */
+#define TT_VTNT 41 /* Microsoft NT Virtual Terminal */
+#define TT_MAX TT_VTNT
+#define TT_VT420 96 /* DEC VT-420 */
+#define TT_VT520 97 /* DEC VT-520/525 */
+#define TT_TEK40 99 /* Tektronix 401x */
+#define TT_KBM_EMACS TT_MAX+1
+#define TT_KBM_HEBREW TT_MAX+2
+#define TT_KBM_RUSSIAN TT_MAX+3
+#define TT_KBM_WP TT_MAX+4
+
+#define ISAAA(x) (x == TT_AAA)
+#define ISANSI(x) (x >= TT_SCOANSI && x <= TT_ANSI)
+#define ISBA80(x) (x == TT_BA80)
+#define ISBEOS(x) (x == TT_BEOS)
+#define ISQNX(x) (x == TT_QNX)
+#define ISQANSI(x) (x == TT_QANSI)
+#define ISLINUX(x) (x == TT_LINUX)
+#define ISSCO(x) (x == TT_SCOANSI)
+#define ISAT386(x) (x == TT_AT386)
+#define ISAVATAR(x) (x == TT_ANSI)
+#define ISSUN(x) (x == TT_SUN)
+#define ISUNIXCON(x) (x == TT_SCOANSI || x == TT_AT386 || \
+ x == TT_LINUX || x == TT_SUN)
+#define ISDG200(x) (x >= TT_DG200 && x <= TT_DG217)
+#define ISHZL(x) (x == TT_HZL1500)
+#define ISH19(x) (x == TT_H19)
+#define ISIBM31(x) (x == TT_IBM31)
+#define ISTVI(x) (x >= TT_TVI910 && x <= TT_TVI950)
+#define ISTVI910(x) (x == TT_TVI910)
+#define ISTVI925(x) (x == TT_TVI925)
+#define ISTVI950(x) (x == TT_TVI950)
+#define ISVT52(x) (x == TT_VT52 || x == TT_H19)
+#ifdef COMMENT
+#define ISVT520(x) (x == TT_VT520)
+#define ISVT420(x) (x >= TT_VT420 && x <= TT_VT520)
+#else /* COMMENT */
+/* Since we do not yet support 420/520 extend 320 */
+#define ISVT520(x) (ISVT320(x))
+#define ISVT420(x) (ISVT320(x))
+#endif /* COMMENT */
+#define ISVT320(x) (x >= TT_VT320 && x <= TT_AAA)
+#define ISVT220(x) (x >= TT_VT220 && x <= TT_AAA || \
+ ISBEOS(x) || ISQANSI(x) || \
+ ISLINUX(x) || ISSUN(x))
+#define ISVT102(x) (x >= TT_VIP7809 && x <= TT_BA80 || \
+ x == TT_VT102 || ISVT220(x))
+#define ISVT100(x) (x == TT_VT100 || ISVT102(x))
+#define ISWY30(x) (x == TT_WY30)
+#define ISWYSE(x) (x >= TT_WY30 && x <= TT_WY160)
+#define ISWY50(x) (x == TT_WY50)
+#define ISWY60(x) (x == TT_WY60 || x == TT_WY160)
+#define ISWY160(x) (x == TT_WY160)
+#define ISWY370(x) (x == TT_WY370)
+#define ISVC(x) (x == TT_VC4404)
+#define ISHP(x) (x == TT_HPTERM || x == TT_HP2621)
+#define ISHPTERM(x) (x == TT_HPTERM)
+#define ISVIP(x) (x == TT_VIP7809)
+#define IS97801(x) (x == TT_97801)
+#define ISHFT(x) (x == TT_HFT || x == TT_AIXTERM)
+#define ISAIXTERM(x) (x == TT_AIXTERM)
+#define ISTEK(x) (x == TT_TEK40)
+#define ISVTNT(x) (x == TT_VTNT)
+#define ISADM3A(x) (x == TT_ADM3A)
+#define ISADM5(x) (x == TT_ADM5)
+#endif /* OS2 */
+
+#define XYTCS 2 /* Terminal Character Set */
+#define XYTSO 3 /* Terminal Shift-In/Shift-Out */
+#define XYTNL 4 /* Terminal newline mode */
+#ifdef OS2
+#define XYTCOL 5 /* Terminal colors */
+#endif /* OS2 */
+#define XYTEC 6 /* Terminal echo = duplex = local-echo */
+#ifdef OS2
+#define XYTCUR 7 /* Terminal cursor */
+#define TTC_ULINE 0
+#define TTC_HALF 1
+#define TTC_BLOCK 2
+#define XYTARR 8 /* Terminal arrow-key mode */
+#define XYTKPD 9 /* Terminal keypad mode */
+#define TTK_NORM 0 /* Normal mode for arrow / keyad keys */
+#define TTK_APPL 1 /* Application mode for arrow / keyad keys */
+#define XYTWRP 10 /* Terminal wrap */
+#endif /* OS2 */
+#define XYTCRD 11 /* Terminal CR-display */
+#define XYTANS 12 /* Terminal answerback */
+#ifdef OS2
+#define XYSCRS 13 /* Terminal scrollback buffer size */
+#endif /* OS2 */
+#define XYTAPC 14 /* Terminal APC */
+#ifdef OS2
+#define XYTBEL 15 /* Terminal Bell */
+#endif /* OS2 */
+#define XYTDEB 16 /* Terminal Debug */
+#ifdef OS2
+#define XYTROL 17 /* Terminal Rollback */
+#define TTR_OVER 0 /* Rollback Overwrite */
+#define TTR_INSERT 1 /* Rollback Insert */
+#define TTR_KEYS 2 /* Keystrokes */
+#define TTRK_IGN 0 /* Ignore */
+#define TTRK_RST 2 /* Restore and Send */
+#define TTRK_SND 1 /* Send */
+#define XYTCTS 18 /* Terminal Transmit-Timeout */
+#define XYTCPG 19 /* Terminal Code Page */
+#ifdef COMMENT
+#define XYTHCU 20 /* Terminal Hide-Cursor */
+#endif /* COMMENT */
+#define XYTPAC 21 /* Terminal Output-Pacing */
+#define XYTMOU 22 /* Terminal Mouse */
+#endif /* OS2 */
+#define XYTHIG 23 /* Terminal Width */
+#define XYTWID 24 /* Terminal Height */
+#ifdef OS2
+#define XYTUPD 25 /* Terminal Screen-update */
+#define TTU_FAST 0 /* FAST but jerky */
+#define TTU_SMOOTH 1 /* SMOOTH but slow */
+#define XYTFON 26 /* Terminal Full screen Font */
+#define TTF_ROM 0 /* ROM font */
+#define TTF_CY1 1 /* CYRILL1 font */
+#define TTF_CY2 2 /* CYRILL2 font */
+#define TTF_CY3 3 /* CYRILL3 font */
+#define TTF_111 111 /* CP111 font */
+#define TTF_112 112 /* CP112 font */
+#define TTF_113 113 /* CP113 font */
+#define TTF_437 437 /* CP437 font */
+#define TTF_850 850 /* CP850 font */
+#define TTF_851 851 /* CP851 font */
+#define TTF_852 852 /* CP852 font */
+#define TTF_853 853 /* CP853 font */
+#define TTF_860 860 /* CP860 font */
+#define TTF_861 861 /* CP861 font */
+#define TTF_862 862 /* CP862 font */
+#define TTF_863 863 /* CP863 font */
+#define TTF_864 864 /* CP864 font */
+#define TTF_865 865 /* CP865 font */
+#define TTF_866 866 /* CP866 font */
+#define TTF_880 880 /* CP880 font */
+#define TTF_881 881 /* CP881 font */
+#define TTF_882 882 /* CP882 font */
+#define TTF_883 883 /* CP883 font */
+#define TTF_884 884 /* CP884 font */
+#define TTF_885 885 /* CP885 font */
+#define XYTVCH 27 /* SET TERMINAL VIDEO-CHANGE */
+#define TVC_DIS 0 /* DISABLED */
+#define TVC_ENA 1 /* ENABLED */
+#define TVC_W95 2 /* WIN95-SAFE */
+#endif /* OS2 */
+#define XYTAUTODL 28 /* SET TERMINAL AUTODOWNLOAD */
+#define TAD_OFF 0 /* OFF */
+#define TAD_ON 1 /* ON */
+#define TAD_K 2 /* KERMIT */
+#define TAD_Z 3 /* ZMODEM */
+#define TAD_X_STR 0 /* STRING */
+#define TAD_X_DETECT 1 /* DETECTION ( PACKET, STRING ) */
+#define TAD_X_C0 2 /* C0 CONFLICTS */
+#define TAD_ERR 4 /* ERROR { STOP, CONTINUE } */
+#define TAD_ASK 5 /* ASK (dialog) */
+#define XYTAUTOUL 29 /* SET TERMINAL AUTOUPLOAD */
+#ifdef OS2
+#define XYTATTBUG 30 /* SET TERM ATTR-BUG */
+#define XYTSTAT 31 /* SET TERM STATUSLINE */
+#endif /* OS2 */
+#define XYTESC 32 /* SET TERM ESCAPE-CHARACTER */
+#define XYTCTRL 33 /* SET TERM CONTROLS */
+#ifdef OS2
+#define XYTATTR 34 /* SET TERM ATTRIBUTE representation */
+#define XYTSGRC 35 /* SET TERM SGRCOLORS */
+#endif /* OS2 */
+#define XYTLCS 36 /* SET TERM LOCAL-CHARACTER-SET */
+#define XYTRCS 37 /* SET TERM REMOTE-CHARACTER-SET */
+#define XYTUNI 38 /* SET TERM UNICODE */
+#define XYTKEY 39 /* SET TERM KEY */
+#ifdef OS2
+#define XYTSEND 40 /* SET TERM SEND-DATA */
+#define XYTSEOB 41 /* SET TERM SEND-END-OF-BLOCK */
+#define XYTMBEL 42 /* SET TERM MARGIN-BELL */
+#endif /* OS2 */
+#define XYTIDLE 43 /* SET TERM IDLE-SEND */
+#ifdef OS2
+#define XYTKBMOD 44 /* SET TERM KEYBOARD-MODE */
+#define XYTUNX 45 /* SET TERM UNIX-MODE (DG) */
+#define XYTASCRL 46 /* SET TERM AUTOSCROLL */
+#define XYTAPAGE 47 /* SET TERM AUTOPAGE */
+#endif /* OS2 */
+#define XYTRIGGER 48 /* SET TERM TRIGGER */
+#ifdef OS2
+#define XYTPCTERM 49 /* SET TERM PCTERM */
+#define XYTOPTI 50 /* SET TERM SCREEN-OPTIMIZE */
+#define XYTSCNM 51 /* SET TERM SCREEN-MODE (DECSCNM) */
+#endif /* OS2 */
+#define XYTPRN 52 /* SET TERM PRINT {AUTO, COPY, OFF} */
+#ifdef OS2
+#define XYTSAC 53 /* SET TERM SPACING-ATTRIBUTE-CHARACTER (inv) */
+#define XYTSNIPM 54 /* SET TERM SNI-AUTOROLL */
+#define XYTSNISM 55 /* SET TERM SNI-SCROLLMODE */
+#define XYTKBDGL 56 /* SET TERM KBD-FOLLOWS-GL/GR */
+#define XYTVTLNG 57 /* SET TERM VT-LANGUAGE */
+#define VTL_NORTH_AM 1
+#define VTL_BRITISH 2
+#define VTL_BELGIAN 3
+#define VTL_FR_CAN 4
+#define VTL_DANISH 5
+#define VTL_FINNISH 6
+#define VTL_GERMAN 7
+#define VTL_DUTCH 8
+#define VTL_ITALIAN 9
+#define VTL_SW_FR 10
+#define VTL_SW_GR 11
+#define VTL_SWEDISH 12
+#define VTL_NORWEGIA 13
+#define VTL_FRENCH 14
+#define VTL_SPANISH 15
+#define VTL_PORTUGES 16
+#define VTL_HEBREW 19
+#define VTL_GREEK 22
+#define VTL_CANADIAN 28
+#define VTL_TURK_Q 29
+#define VTL_TURK_F 30
+#define VTL_HUNGARIA 31
+#define VTL_SLOVAK 33
+#define VTL_CZECH 34
+#define VTL_POLISH 35
+#define VTL_ROMANIAN 36
+#define VTL_SCS 38
+#define VTL_RUSSIAN 39
+#define VTL_LATIN_AM 40
+#define XYTVTNRC 58 /* SET TERM VT-NRC-MODE */
+#define XYTSNICC 59 /* SET TERM SNI-CH.CODE */
+#define XYTSNIFV 60 /* SET TERM SNI-FIRMWARE-VERSIONS */
+#define XYTURLHI 61 /* SET TERM URL-HIGHLIGHT */
+#endif /* OS2 */
+#define XYTITMO 62 /* SET TERM IDLE-TIMEOUT */
+#define XYTIACT 63 /* SET TERM IDLE-ACTION */
+#define XYTLSP 64 /* SET TERM LINE-SPACING */
+#define XYTLFD 65 /* SET TERM LF-DISPLAY */
+
+#define XYATTR 34 /* Attribute packets */
+#define XYSERV 35 /* Server parameters */
+#define XYSERT 0 /* Server timeout */
+#define XYSERD 1 /* Server display */
+#define XYSERI 2 /* Server idle */
+#define XYSERP 3 /* Server get-path */
+#define XYSERL 4 /* Server login */
+#define XYSERC 5 /* Server CD-Message */
+#define XYSERK 6 /* Server keepalive */
+#define XYWIND 36 /* Window size */
+#define XYXFER 37 /* Transfer */
+#define XYX_CAN 0 /* Cancellation */
+#define XYX_CSE 1 /* Character-Set */
+#define XYX_LSH 2 /* Locking-Shift */
+#define XYX_PRO 3 /* Protocol */
+#define XYX_MOD 4 /* Mode */
+#define XYX_DIS 5 /* Display */
+#define XYX_SLO 6 /* Slow-start */
+#define XYX_CRC 7 /* CRC calculation */
+#define XYX_BEL 8 /* Bell */
+#define XYX_PIP 9 /* Pipes */
+#define XYX_INT 10 /* Interruption */
+#define XYX_XLA 11 /* (character-set) Translation On/Off */
+#define XYX_MSG 12 /* Message */
+#define XYX_RPT 13 /* Report */
+#define XYLANG 38 /* Language */
+#define XYCOUN 39 /* Count */
+#define XYTAKE 40 /* Take */
+#define XYUNCS 41 /* Unknown-character-set */
+#define XYKEY 42 /* Key */
+#define XYMACR 43 /* Macro */
+#define XYHOST 44 /* Hostname on network */
+#define XYNET 45 /* SET NETWORK things */
+
+#define XYNET_D 99 /* NETWORK DIRECTORY */
+#define XYNET_T 100 /* NETWORK TYPE */
+
+#define XYCARR 46 /* Carrier */
+#define XYXMIT 47 /* Transmit */
+
+#define XYDIAL 48 /* Dial options */
+
+/* And now we interrupt the flow to bring you lots of stuff about dialing */
+
+#ifndef MAXTOLLFREE /* Maximum number of toll-free area codes */
+#define MAXTOLLFREE 8
+#endif /* MAXTOLLFREE */
+
+#ifndef MAXTPCC /* Maximum Tone or Pulse dialing countries */
+#define MAXTPCC 160
+#endif /* MAXTPCC */
+
+#ifndef MAXPBXEXCH /* Maximum number of PBX exchanges */
+#define MAXPBXEXCH 8
+#endif /* MAXPBXEXCH */
+
+#ifndef MAXLOCALAC
+#define MAXLOCALAC 32
+#endif /* MAXLOCALAC */
+
+#ifndef MAXDNUMS
+#ifdef BIGBUFOK
+#define MAXDDIR 32 /* Maximum number of dialing directories */
+#define MAXDNUMS 4095 /* Max numbers to fetch from dialing directories */
+#else
+#define MAXDDIR 12
+#define MAXDNUMS 1024
+#endif /* BIGBUFOK */
+#endif /* MAXDNUMS */
+/*
+ IMPORTANT: In 5A(192), the old SET DIAL command was split into two commands:
+ SET MODEM (for modem-related parameters) and SET DIAL (for dialing items).
+ To preserve the old formats, etc, invisibly we keep one symbol space for
+ both commands.
+*/
+#define XYDHUP 0 /* Dial Hangup */
+#define XYDINI 1 /* MODEM (dial) Initialization string */
+#define XYDKSP 2 /* MODEM (dial) Kermit-Spoof */
+#define XYDTMO 3 /* Dial Timeout */
+#define XYDDPY 4 /* Dial Display */
+#define XYDSPD 5 /* Dial Speed matching */
+#define XYDMNP 6 /* MODEM (dial) MNP negotiation enabled (obsolete) */
+#define XYDEC 7 /* MODEM (dial) error correction enabled */
+#define XYDDC 8 /* MODEM (dial) compression enabled */
+#define XYDHCM 9 /* MODEM (dial) hangup-string (moved elsewhere) */
+#define XYDDIR 10 /* Dial directory */
+#define XYDDIA 11 /* MODEM (dial) dial-command */
+#define XYDMHU 12 /* MODEM HANGUP (dial modem-hangup) */
+
+#ifndef DEFMDHUP /* Default MODEM HANGUP-METHOD */
+#define DEFMDMHUP 1 /* 0 = RS232, 1 = modem command */
+#endif /* DEFMDMHUP */
+
+#define XYDNPR 13 /* Dial PREFIX */
+#define XYDSTR 14 /* MODEM COMMAND (dial string) ... */
+
+#define XYDS_DC 0 /* Data compression */
+#define XYDS_EC 1 /* Error correction */
+#define XYDS_HU 2 /* Hangup command */
+#define XYDS_HW 3 /* Hardware flow control */
+#define XYDS_IN 4 /* Init-string */
+#define XYDS_NF 5 /* No flow control */
+#define XYDS_PX 6 /* Prefix (no, this goes in SET DIAL) */
+#define XYDS_SW 7 /* Software flow control */
+#define XYDS_DT 8 /* Tone dialing command */
+#define XYDS_DP 9 /* Pulse dialing command */
+#define XYDS_AN 10 /* Autoanswer */
+#define XYDS_RS 11 /* Reset */
+#define XYDS_MS 12 /* Dial mode string */
+#define XYDS_MP 13 /* Dial mode prompt */
+#define XYDS_SP 14 /* Modem speaker */
+#define XYDS_VO 15 /* Modem speaker volume */
+#define XYDS_ID 16 /* Ignore dialtone */
+#define XYDS_I2 17 /* Init string #2 */
+
+#define XYDM_A 9 /* Method: Auto */
+#define XYDM_D 0 /* Default */
+#define XYDM_T 2 /* Tone */
+#define XYDM_P 3 /* Pulse */
+
+#define XYDFC 15 /* MODEM (dial) flow-control */
+#define XYDMTH 16 /* Dial method */
+#define XYDESC 17 /* MODEM (dial) escape-character */
+#define XYDMAX 18 /* MODEM (dial) maximum interface speed */
+#define XYDCAP 19 /* MODEM (dial) capabilities */
+#define XYDTYP 20 /* MODEM TYPE */
+#define XYDINT 21 /* DIAL retries */
+#define XYDRTM 22 /* DIAL time between retries */
+#define XYDNAM 23 /* MODEM NAME */
+#define XYDLAC 24 /* DIAL (LOCAL-)AREA-CODE */
+#define XYDMCD 25 /* MODEM CARRIER */
+
+#define XYDCNF 26 /* DIAL CONFIRMATION */
+#define XYDCVT 27 /* DIAL CONVERT-DIRECTORY */
+#define XYDIXP 28 /* DIAL INTERNATIONAL-PREFIX */
+#define XYDIXS 29 /* DIAL INTERNATIONAL-SUFFIX */
+#define XYDLCC 30 /* DIAL LOCAL-COUNTRY-CODE */
+#define XYDLDP 31 /* DIAL LONG-DISTANCE-PREFIX */
+#define XYDLDS 32 /* DIAL LONG-DISTANCE-SUFFIX */
+#define XYDPXX 33 /* DIAL PBX-EXCHANGE */
+#define XYDPXI 34 /* DIAL PBX-INTERNAL-PREFIX */
+#define XYDPXO 35 /* DIAL PBX-OUTSIDE-PREFIX */
+#define XYDSFX 36 /* DIAL SUFFIX */
+#define XYDSRT 37 /* DIAL SORT */
+#define XYDTFC 38 /* DIAL TOLL-FREE-AREA-CODE */
+#define XYDTFP 39 /* DIAL TOLL-FREE-PREFIX */
+#define XYDTFS 40 /* DIAL TOLL-FREE-SUFFIX */
+#define XYDCON 41 /* DIAL CONNECT */
+#define XYDRSTR 42 /* DIAL RESTRICT */
+#define XYDRSET 43 /* MODEM RESET */
+#define XYDLCP 44 /* DIAL LOCAL-PREFIX */
+#define XYDLCS 45 /* DIAL LOCAL-SUFFIX */
+#define XYDLLAC 46 /* DIAL LC-AREA-CODES */
+#define XYDFLD 47 /* DIAL FORCE LONG-DISTANCE */
+#define XYDSPK 48 /* MODEM SPEAKER */
+#define XYDVOL 49 /* MODEM VOLUME */
+#define XYDIDT 50 /* IGNORE DIALTONE */
+#define XYDPAC 51 /* PACING */
+#define XYDMAC 52 /* MACRO */
+#define XYDPUCC 53 /* PULSE-COUNTRIES */
+#define XYDTOCC 54 /* TONE-COUNTRIES */
+#define XYDTEST 55 /* TEST */
+
+#define XYA_CID 1 /* SET ANSWER CALLER-ID */
+#define XYA_RNG 2 /* SET ANSWER RINGS */
+
+#define XYSESS 49 /* SET SESSION options */
+#define XYBUF 50 /* Buffer length */
+#define XYBACK 51 /* Background */
+#define XYDFLT 52 /* Default */
+#define XYDBL 53 /* Double */
+#define XYCMD 54 /* COMMAND */
+#define XYCASE 55 /* Case */
+#define XYCOMP 56 /* Compression */
+#define XYX25 57 /* X.25 parameter (ANYX25) */
+#define XYPAD 58 /* X.3 PAD parameter (ANYX25) */
+#define XYWILD 59 /* Wildcard expansion method */
+
+#define WILD_OFF 0 /* Wildcard expansion off */
+#define WILD_ON 1 /* Wildcard expansion on */
+#define WILD_KER 2 /* Wildcard expansion by Kermit */
+#define WILD_SHE 3 /* Wildcard expansion by Shell */
+
+#define XYSUSP 60 /* Suspend */
+#define XYMAIL 61 /* Mail-Command */
+#define XYPRIN 62 /* Print-Command */
+#define XYQUIE 63 /* Quiet */
+#define XYLCLE 64 /* Local-echo */
+#define XYSCRI 65 /* SCRIPT command parameters */
+#define XYMSGS 66 /* MESSAGEs ON/OFF */
+#ifdef TNCODE
+#define XYTEL 67 /* SET TELNET parameters */
+#define CK_TN_EC 0 /* TELNET ECHO */
+#define CK_TN_TT 1 /* TELNET TERMINAL-TYPE */
+#define CK_TN_NL 2 /* TELNET NEWLINE-MODE */
+#define CK_TN_BM 3 /* TELNET BINARY-MODE */
+#define CK_TN_BUG 4 /* TELNET BUG */
+#define CK_TN_ENV 5 /* TELNET ENVIRONMENT */
+#define TN_ENV_USR 0 /* VAR USER */
+#define TN_ENV_JOB 1 /* VAR JOB */
+#define TN_ENV_ACCT 2 /* VAR ACCT */
+#define TN_ENV_PRNT 3 /* VAR PRINTER */
+#define TN_ENV_SYS 4 /* VAR SYSTEMTYPE */
+#define TN_ENV_DISP 5 /* VAR DISPLAY */
+#define TN_ENV_UVAR 6 /* USERVAR */
+#define TN_ENV_LOC 7 /* USERVAR LOCATION */
+#define TN_ENV_ON 98 /* ON (enabled) */
+#define TN_ENV_OFF 99 /* OFF (disabled) */
+#define CK_TN_LOC 6 /* TELNET LOCATION */
+#define CK_TN_AU 7 /* TELNET AUTHENTICATION */
+#define TN_AU_FWD 4 /* AUTH FORWARD */
+#define TN_AU_TYP 5 /* AUTH TYPE */
+#define AUTH_NONE 0 /* AUTH NONE */
+#define AUTH_KRB4 1 /* AUTH Kerberos IV */
+#define AUTH_KRB5 2 /* AUTH Kerberos V */
+#define AUTH_SSL 7 /* AUTH Secure Sockets Layer */
+#define AUTH_TLS 98 /* AUTH Transport Layer Security */
+#define AUTH_SRP 5 /* AUTH Secure Remote Password */
+#define AUTH_NTLM 15 /* AUTH NT Lan Manager */
+#define AUTH_AUTO 99 /* AUTH AUTOMATIC */
+#define TN_AU_HOW 8 /* AUTH HOW FLAG */
+#define TN_AU_ENC 9 /* AUTH ENCRYPT FLAG */
+#define CK_TN_ENC 8 /* TELNET ENCRYPTION */
+#define TN_EN_TYP 4 /* ENCRYPT TYPE */
+#define TN_EN_START 5 /* ENCRYPT START */
+#define TN_EN_STOP 6 /* ENCRYPT STOP */
+#define CK_TN_IKS 9 /* TELNET KERMIT-SERVER */
+#define CK_TN_RE 10 /* TELNET REMOTE-ECHO */
+#define CK_TN_TLS 11 /* TELNET START_TLS */
+#define CK_TN_XD 12 /* TELNET XDISPLOC */
+#define CK_TN_NAWS 13 /* TELNET NAWS */
+#define CK_TN_WAIT 14 /* TELNET WAIT-FOR-NEGOTIATIONS */
+#define CK_TN_SGA 15 /* TELNET SGA */
+#define CK_TN_CLIENT 16 /* TELNET CLIENT */
+#define CK_TN_SERVER 17 /* TELNET SERVER */
+#define CK_TN_PHR 18 /* TELNET PRAGMA-HEARTBEAT */
+#define CK_TN_PLG 19 /* TELNET PRAGMA-LOGON */
+#define CK_TN_PSP 20 /* TELNET PRAGMA-SSPI */
+#define CK_TN_SAK 21 /* TELNET IBM SAK */
+#define CK_TN_FLW 22 /* TELNET LFLOW */
+#define CK_TN_XF 23 /* TELNET TRANSFER-MODE */
+#define CK_TN_PUID 24 /* TELNET PROMPT-FOR-USERID */
+#define CK_TN_NE 25 /* TELNET NO-ENCRYPT-DURING-XFER */
+#define CK_TN_CPC 26 /* TELNET COM-PORT-CONTROL */
+#define CK_TN_DB 27 /* TELNET DEBUG */
+#define CK_TN_FX 28 /* TELNET FORWARD_X */
+#define CK_TN_DL 29 /* TELNET DELAY-SB */
+#define CK_TN_SFU 30 /* TELNET SFU-COMPATIBILITY */
+#define CK_TN_LOG 31 /* TELNET LOGOUT */
+#endif /* TNCODE */
+#define XYOUTP 68 /* OUTPUT command parameters */
+#define OUT_PAC 0 /* OUTPUT PACING */
+#define OUT_ESC 1 /* OUTPUT SPECIAL-ESCAPES */
+#define XYEXIT 69 /* SET EXIT */
+#define XYPRTR 70 /* SET PRINTER */
+#define XYFPATH 71 /* PATHNAME */
+
+#ifdef OS2
+#define XYMOUSE 72 /* MOUSE SUPPORT */
+#define XYM_ON 0 /* Mouse ON/OFF */
+#define XYM_BUTTON 1 /* Define Mouse Events */
+#define XYM_CLEAR 2 /* Clear Mouse Events */
+#define XYM_DEBUG 3 /* Debug Mode ON/OFF */
+/* These must match similar definitions in ckokey.h */
+#define XYM_B1 0 /* Mouse Button One */
+#define XYM_B2 1 /* Mouse Button Two */
+#define XYM_B3 2 /* Mouse Button Three */
+#define XYM_ALT 1 /* Alt */
+#define XYM_CTRL 2 /* Ctrl */
+#define XYM_SHIFT 4 /* Shift */
+#define XYM_C1 0 /* Single Click */
+#define XYM_C2 8 /* Double Click */
+#define XYM_DRAG 16 /* Drag Event */
+#endif /* OS2 */
+
+#define XYBELL 73 /* BELL */
+
+#ifdef OS2
+#define XYPRTY 74 /* Thread Priority Level */
+#define XYP_IDLE 1
+#define XYP_REG 2
+#define XYP_SRV 4
+#define XYP_RTP 3
+#endif /* OS2 */
+
+#define XYALRM 75 /* SET ALARM */
+#define XYPROTO 76 /* SET PROTOCOL */
+#define XYPREFIX 77 /* SET PREFIXING */
+#define XYLOGIN 78 /* Login info for script programs... */
+
+#define LOGI_UID 0 /* User ID */
+#define LOGI_PSW 1 /* Password */
+#define LOGI_PRM 2 /* Prompt */
+
+#define XYSTARTUP 79 /* Startup file */
+#define XYTMPDIR 80 /* Temporary directory */
+
+#ifdef OS2
+#define XYTAPI 81 /* Microsoft Telephone API options */
+#define XYTAPI_CFG 1 /* TAPI Configure-Line Dialog */
+#define XYTAPI_DIAL 2 /* TAPI Dialing-Properties Dialog */
+#define XYTAPI_LIN 3 /* TAPI Line */
+#define XYTAPI_LOC 4 /* TAPI Location */
+#define XYTAPI_PASS 5 /* TAPI Passthrough */
+#define XYTAPI_CON 6 /* TAPI Conversions */
+#define XYTAPI_LGHT 7 /* TAPI Modem Lights */
+#define XYTAPI_PRE 8 /* TAPI Pre-dialing Terminal */
+#define XYTAPI_PST 9 /* TAPI Post-dialing Terminal */
+#define XYTAPI_INA 10 /* TAPI Inactivity Timeout */
+#define XYTAPI_BNG 11 /* TAPI Wait for Credit Card Tone */
+#define XYTAPI_MAN 12 /* TAPI Manual Dialing */
+#define XYTAPI_USE 13 /* TAPI Use Line Config settings */
+#endif /* OS2 */
+
+#ifdef TCPSOCKET
+#define XYTCP 82 /* TCP options */
+#define XYTCP_NODELAY 1 /* No Delay */
+#define XYTCP_SENDBUF 2 /* Send Buffer Size */
+#define XYTCP_LINGER 3 /* Linger */
+#define XYTCP_RECVBUF 4 /* Receive Buffer Size */
+#define XYTCP_KEEPALIVE 5 /* Keep Alive packets */
+#define XYTCP_UCX 6 /* UCX 2.0 port swabbing bug */
+#define XYTCP_NAGLE 7 /* Delay - inverse of 1 */
+#define XYTCP_RDNS 8 /* Reverse DNS lookup */
+#define XYTCP_ADDRESS 9 /* Set preferred IP Address */
+#define XYTCP_DNS_SRV 10 /* Use DNS Service Records */
+#define XYTCP_DONTROUTE 11 /* Dont Route */
+#define XYTCP_SOCKS_SVR 12 /* Name of Socks Server */
+#define XYTCP_HTTP_PROXY 13 /* Name/Port of HTTP Proxy Server */
+#define XYTCP_SOCKS_NS 14 /* Name of Socks Name Server */
+#endif /* TCPSOCKET */
+
+#ifdef OS2
+#define XYMSK 83 /* MS-DOS Kermit compatibility options */
+#define MSK_COLOR 0 /* Terminal color handling */
+#define MSK_KEYS 1 /* SET KEY uses MSK keycodes */
+#define MSK_REN 2 /* File renaming uses 8.3 notation always */
+#endif /* OS2 */
+
+#define XYDEST 84 /* SET DESTINATION as in MS-DOS Kermit */
+
+#ifdef OS2
+#define XYWIN95 85 /* SET WIN95 work arounds */
+#define XYWKEY 0 /* Keyboard translation */
+#define XYWAGR 1 /* Alt-Gr */
+#define XYWOIO 2 /* Overlapped I/O */
+#define XYWLUC 3 /* Lucida Console substitutions */
+#define XYWSELECT 4 /* Select on Write Bug */
+#define XYW8_3 5 /* Use 8.3 filenames? */
+#define XYWPOPUP 6 /* Use Popups? */
+#define XYWHSL 7 /* Horz Scan Line substitutions */
+#define XYDLR 86 /* SET K95 DIALER work arounds */
+#define XYTITLE 87 /* SET TITLE of window */
+#endif /* OS2 */
+
+#define XYIGN 88 /* SET IGNORE-CHARACTER */
+#define XYEDIT 89 /* SET EDITOR */
+#define XYFLTR 90 /* SET { SEND, RECEIVE } FILTER */
+#define XYBROWSE 91 /* SET BROWSER */
+#define XYEOF 92 /* EOF (= FILE EOF) */
+#ifdef OS2
+#define XYBDCP 93 /* BPRINTER */
+#endif /* OS2 */
+#define XYFLAG 94 /* FLAG */
+#define XYLIMIT 95 /* SESSION-LIMIT */
+#define XYINIL 96 /* Protocol negotiation string max length */
+#define XYRELY 97 /* RELIABLE */
+#define XYSTREAM 98 /* STREAMING */
+#define XYTLOG 99 /* TRANSACTION-LOG */
+#define XYCLEAR 100 /* CLEARCHANNEL */
+#define XYAUTH 101 /* AUTHENTICATION */
+
+#ifdef TNCODE
+#define XYKRBPR 0 /* Kerberos Principal */
+#define XYKRBRL 1 /* Kerberos Realm */
+#define XYKRBCC 2 /* Kerberos 5 Credentials-Cache */
+#define XYKRBSRV 3 /* Kerberos Service Name */
+#define XYKRBDBG 4 /* Kerberos Debugging */
+#define XYKRBLIF 5 /* Kerberos Lifetime */
+#define XYKRBPRE 6 /* Kerberos 4 Preauth */
+#define XYKRBINS 7 /* Kerberos 4 Instance */
+#define XYKRBFWD 8 /* Kerberos 5 Forwardable */
+#define XYKRBPRX 9 /* Kerberos 5 Proxiable */
+#define XYKRBRNW 10 /* Kerberos 5 Renewable lifetime */
+#define XYKRBGET 11 /* Kerberos Auto-Get-TGTs */
+#define XYKRBDEL 12 /* Kerberos Auto-Destroy-TGTs */
+#define KRB_DEL_NO 0 /* Kerberos No Auto Destroy */
+#define KRB_DEL_CL 1 /* Kerberos Auto Destory on Close */
+#define KRB_DEL_EX 2 /* Kerberos Auto Destroy on Exit */
+#define XYKRBK5K4 13 /* Kerberos 5 Get K4 Tickets */
+#define XYKRBPRM 14 /* Kerberos 4/5 Prompt */
+#define XYKRBADR 15 /* Kerberos 4/5 CheckAddrs */
+#define XYKRBNAD 16 /* Kerberos 5 No Addresses */
+#define XYKRBADD 17 /* Kerberos 5 Address List */
+#define XYKRBKTB 18 /* Kerberos 4/5 Key Table */
+#define XYSRPPRM 0 /* SRP Prompt */
+#define XYSSLRCFL 0 /* SSL/TLS RSA Certs file */
+#define XYSSLCOK 1 /* SSL/TLS Certs-Ok flag */
+#define XYSSLCRQ 2 /* SSL/TLS Certs-Required flag */
+#define XYSSLCL 3 /* SSL/TLS Cipher List */
+#define XYSSLDBG 4 /* SSL/TLS Debug flag */
+#define XYSSLRKFL 5 /* SSL/TLS RSA Key File */
+#define XYSSLLFL 6 /* SSL/TLS Log File */
+#define XYSSLON 7 /* SSL/TLS Only flag */
+#define XYSSLSEC 8 /* SSL/TLS Secure flag */
+#define XYSSLVRB 9 /* SSL/TLS Verbose flag */
+#define XYSSLVRF 10 /* SSL/TLS Verify flag */
+#define XYSSLDUM 11 /* SSL/TLS Dummy flag */
+#define XYSSLDCFL 12 /* SSL/TLS DSA Certs file */
+#define XYSSLDKFL 13 /* SSL/TLS DH Certs file */
+#define XYSSLDPFL 14 /* SSL/TLS DH Param file */
+#define XYSSLCRL 15 /* SSL/TLS CRL file */
+#define XYSSLCRLD 16 /* SSL/TLS CRL dir */
+#define XYSSLVRFF 17 /* SSL/TLS Verify file */
+#define XYSSLVRFD 18 /* SSL/TLS Verify dir */
+#define XYSSLRND 19 /* SSL/TLS Random file */
+#define XYSSLDCCF 20 /* SSL/TLS DSA Certs Chain File */
+#define XYSSLRCCF 21 /* SSL/TLS RSA Certs Chain File */
+
+/* The following must be powers of 2 for a bit mask */
+
+#define XYKLCEN 1 /* Kerberos List Credentials: Encryption */
+#define XYKLCFL 2 /* Kerberos List Credentials: Flags */
+#define XYKLCAD 4 /* Kerberos List Credentials: Addresses */
+#endif /* TNCODE */
+
+#define XYFUNC 102 /* SET FUNCTION */
+
+#define FUNC_DI 0 /* FUNCTION DIAGNOSTICS */
+#define FUNC_ER 1 /* FUNCTION ERROR */
+
+#define XYFTP 103 /* FTP application */
+#define XYSLEEP 104 /* SLEEP / PAUSE options */
+#define XYSSH 105 /* SSH options */
+#define XYTELOP 106 /* TELNET OPTIONS (TELOPT) */
+#define XYCD 107 /* SET CD */
+#define XYCSET 108 /* CHARACTER-SET */
+#define XYSTOP 109 /* STOP-BITS */
+#define XYSERIAL 110 /* SERIAL */
+#define XYDISC 111 /* CLOSE-ON-DISCONNECT */
+#define XYOPTS 112 /* OPTIONS */
+#define XYQ8FLG 113 /* Q8FLAG (invisible) */
+#define XYTIMER 114 /* TIMER */
+#define XYFACKB 115 /* F-ACK-BUG */
+#define XYBUP 116 /* SET SEND/RECEIVE BACKUP */
+#define XYMOVE 117 /* SET SEND/RECEIVE MOVE-TO */
+#define XYRENAME 118 /* SET SEND/RECEIVE RENAME-TO */
+#define XYHINTS 119 /* SET HINTS */
+#define XYEVAL 120 /* SET EVALUATE */
+#define XYFACKP 121 /* F-ACK-PATH */
+#define XYSYSL 122 /* SysLog */
+#define XYQNXPL 123 /* QNX Port Lock */
+#define XYIKS 124 /* SET IKS ... */
+#define XYROOT 125 /* SET ROOT */
+#define XYFTPX 126 /* SET FTP */
+#define XYSEXP 127 /* SET SEXP */
+#define XYGPR 128 /* SET GET-PUT-REMOTE */
+#define XYLOCUS 129 /* SET LOCUS */
+#define XYGUI 130 /* SET GUI */
+#define XYANSWER 131 /* SET ANSWER */
+#define XYMATCH 132 /* SET MATCHDOT */
+#define XYSFTP 133 /* SET SFTP */
+#define XY_REN 134 /* SET RENAME */
+#define XYEXTRN 135 /* SET EXTERNAL-PROTOCOL */
+#define XYVAREV 136 /* SET VARIABLE-EVALUATION */
+
+/* End of SET commands */
+
+/* S-Expressions -- floating-point support required */
+
+#ifndef CKFLOAT
+#ifndef NOSEXP
+#define NOSEXP
+#endif /* NOSEXP */
+#endif /* CKFLOAT */
+
+/* Maximum number of elements in an S-Expression */
+
+#ifndef NOSEXP
+#ifndef SEXPMAX
+#ifdef BIGBUFOK
+#define SEXPMAX 1024
+#else
+#define SEXPMAX 32
+#endif /* BIGBUFOK */
+#endif /* SEXPMAX */
+#endif /* NOSEXP */
+
+#ifdef ANYX25
+/* PAD command parameters */
+
+#define XYPADL 0 /* clear virtual call */
+#define XYPADS 1 /* status of virtual call */
+#define XYPADR 2 /* reset of virtual call */
+#define XYPADI 3 /* send an interrupt packet */
+
+/* Used with XYX25... */
+#define XYUDAT 0 /* X.25 call user data */
+#define XYCLOS 1 /* X.25 closed user group call */
+#define XYREVC 2 /* X.25 reverse charge call */
+#endif /* ANYX25 */
+
+#ifdef OS2
+/* SET PRINTER switches */
+
+#define PRN_OUT 0 /* Output only */
+#define PRN_BID 1 /* Bidirectional */
+#define PRN_DOS 2 /* DOS device */
+#define PRN_WIN 3 /* Windows queue */
+#define PRN_TMO 4 /* Timeout */
+#define PRN_TRM 5 /* Terminator */
+#define PRN_SEP 6 /* Separator */
+#define PRN_SPD 7 /* COM-port speed */
+#define PRN_FLO 8 /* COM-port flow control */
+#define PRN_PAR 9 /* COM-port parity */
+#define PRN_NON 10 /* No printer */
+#define PRN_FIL 11 /* Filename */
+#define PRN_PIP 12 /* Pipename */
+#define PRN_PS 13 /* Text to PS */
+#define PRN_WID 14 /* PS Width */
+#define PRN_LEN 15 /* PS Length */
+#define PRN_RAW 16 /* Non-PS */
+#define PRN_CS 17 /* Character Set */
+#define PRN_MAX 17 /* Number of switches defined */
+
+/* Printer types */
+
+#define PRT_DOS 0 /* DOS */
+#define PRT_WIN 1 /* Windows Queue */
+#define PRT_FIL 2 /* File */
+#define PRT_PIP 3 /* Pipe */
+#define PRT_NON 4 /* None */
+
+#define PRINTSWI
+#endif /* OS2 */
+#endif /* NOICP */
+
+#ifndef NODIAL
+/*
+ Symbols for modem types, moved here from ckudia.c, May 1997, because now
+ they are also used in some other modules. The numbers MUST correspond to
+ the ordering of entries within the modemp[] array.
+*/
+#ifdef MINIDIAL /* Minimum dialer support */
+
+#define n_DIRECT 0 /* Direct connection -- no modem */
+#define n_CCITT 1 /* CCITT/ITU-T V.25bis */
+#define n_HAYES 2 /* Hayes 2400 */
+#define n_UNKNOWN 3 /* Unknown */
+#define n_UDEF 4 /* User-Defined */
+#define n_GENERIC 5 /* Generic High Speed */
+#define n_ITUTV250 6 /* ITU-T V.250 */
+#define MAX_MDM 6 /* Number of modem types */
+
+#else /* Full-blown dialer support */
+
+#define n_DIRECT 0 /* Direct connection -- no modem */
+#define n_ATTDTDM 1
+#define n_ATTISN 2
+#define n_ATTMODEM 3
+#define n_CCITT 4
+#define n_CERMETEK 5
+#define n_DF03 6
+#define n_DF100 7
+#define n_DF200 8
+#define n_GDC 9
+#define n_HAYES 10
+#define n_PENRIL 11
+#define n_RACAL 12
+#define n_UNKNOWN 13
+#define n_VENTEL 14
+#define n_CONCORD 15
+#define n_ATTUPC 16 /* aka UNIX PC and ATT7300 */
+#define n_ROLM 17 /* Rolm CBX DCM */
+#define n_MICROCOM 18 /* Microcoms in SX command mode */
+#define n_USR 19 /* Modern USRs */
+#define n_TELEBIT 20 /* Telebits of all kinds */
+#define n_DIGITEL 21 /* Digitel DT-22 (CCITT variant) */
+#define n_H_1200 22 /* Hayes 1200 */
+#define n_H_ULTRA 23 /* Hayes Ultra and maybe Optima */
+#define n_H_ACCURA 24 /* Hayes Accura and maybe Optima */
+#define n_PPI 25 /* Practical Peripherals */
+#define n_DATAPORT 26 /* AT&T Dataport */
+#define n_BOCA 27 /* Boca */
+#define n_MOTOROLA 28 /* Motorola Fastalk or Lifestyle */
+#define n_DIGICOMM 29 /* Digicomm Connection */
+#define n_DYNALINK 30 /* Dynalink 1414VE */
+#define n_INTEL 31 /* Intel 14400 Faxmodem */
+#define n_UCOM_AT 32 /* Microcoms in AT mode */
+#define n_MULTI 33 /* Multitech MT1432 */
+#define n_SUPRA 34 /* SupraFAXmodem */
+#define n_ZOLTRIX 35 /* Zoltrix */
+#define n_ZOOM 36 /* Zoom */
+#define n_ZYXEL 37 /* ZyXEL */
+#define n_TAPI 38 /* TAPI Line modem - whatever it is */
+#define n_TBNEW 39 /* Newer Telebit models */
+#define n_MAXTECH 40 /* MaxTech XM288EA */
+#define n_UDEF 41 /* User-Defined */
+#define n_RWV32 42 /* Generic Rockwell V.32 */
+#define n_RWV32B 43 /* Generic Rockwell V.32bis */
+#define n_RWV34 44 /* Generic Rockwell V.34 */
+#define n_MWAVE 45 /* IBM Mwave Adapter */
+#define n_TELEPATH 46 /* Gateway Telepath */
+#define n_MICROLINK 47 /* MicroLink modems */
+#define n_CARDINAL 48 /* Cardinal modems */
+#define n_GENERIC 49 /* Generic high-speed */
+#define n_XJACK 50 /* Megahertz X-Jack */
+#define n_SPIRITII 51 /* Quickcomm Spirit II */
+#define n_MONTANA 52 /* Motorola Montana */
+#define n_COMPAQ 53 /* Compaq Data+Fax Modem */
+#define n_FUJITSU 54 /* Fujitsu Fax/Modem Adpater */
+#define n_MHZATT 55 /* Megahertz AT&T V.34 */
+#define n_SUPRASON 56 /* SupraSonic */
+#define n_BESTDATA 57 /* Best Data */
+#define n_ATT1900 58 /* AT&T STU III Model 1900 */
+#define n_ATT1910 59 /* AT&T STU III Model 1910 */
+#define n_KEEPINTOUCH 60 /* AT&T KeepinTouch */
+#define n_USRX2 61 /* USR XJ-1560 X2 56K */
+#define n_ROLMAT 62 /* Rolm with AT command set */
+#define n_ATLAS 63 /* Atlas / Newcom ixfC 33.6 */
+#define n_CODEX 64 /* Motorola Codex 326X Series */
+#define n_MT5634ZPX 65 /* Multitech MT5634ZPX */
+#define n_ULINKV250 66 /* Microlink ITU-T V.250 56K */
+#define n_ITUTV250 67 /* Generic ITU-T V.250 */
+#define n_RWV90 68 /* Generic Rockwell V.90 */
+#define n_SUPRAX 69 /* Diamond Supra Express V.90 */
+#define n_LUCENT 70 /* Lucent Venus chipset */
+#define n_PCTEL 71 /* PCTel chipset */
+#define n_CONEXANT 72 /* Conexant modem family */
+#define n_ZOOMV34 73 /* Zoom */
+#define n_ZOOMV90 74 /* Zoom */
+#define n_ZOOMV92 75 /* ZOOM V.92 */
+#define n_MOTSM56 76 /* Motorola SM56 chipset */
+#define MAX_MDM 76 /* Number of modem types */
+
+#endif /* MINIDIAL */
+#endif /* NODIAL */
+
+#ifndef NOICP
+/* SHOW command symbols */
+
+#define SHPAR 0 /* Parameters */
+#define SHVER 1 /* Versions */
+#define SHCOM 2 /* Communications */
+#define SHPRO 3 /* Protocol */
+#define SHFIL 4 /* File */
+#define SHLNG 5 /* Language */
+#define SHCOU 6 /* Count */
+#define SHMAC 7 /* Macros */
+#define SHKEY 8 /* Key */
+#define SHSCR 9 /* Scripts */
+#define SHSPD 10 /* Speed */
+#define SHSTA 11 /* Status */
+#define SHSER 12 /* Server */
+#define SHXMI 13 /* Transmit */
+#define SHATT 14 /* Attributes */
+#define SHMOD 15 /* Modem */
+#define SHDFLT 16 /* Default (as in VMS) */
+#define SHVAR 17 /* Show global variables */
+#define SHARG 18 /* Show macro arguments */
+#define SHARR 19 /* Show arrays */
+#define SHBUI 20 /* Show builtin variables */
+#define SHFUN 21 /* Show functions */
+#define SHPAD 22 /* Show (X.25) PAD */
+#define SHTER 23 /* Show terminal settings */
+#define SHESC 24 /* Show escape character */
+#define SHDIA 25 /* Show DIAL parameters */
+#define SHNET 26 /* Show network parameters */
+#define SHLBL 27 /* Show VMS labeled file parameters */
+#define SHSTK 28 /* Show stack, MAC debugging */
+#define SHCSE 29 /* Show character sets */
+#define SHFEA 30 /* Show features */
+#define SHCTL 31 /* Show control-prefix table */
+#define SHEXI 32 /* Show EXIT items */
+#define SHPRT 33 /* Show printer */
+#define SHCMD 34 /* Show command parameters */
+#define SHKVB 35 /* Show \Kverbs */
+#define SHMOU 36 /* Show Mouse (like Show Key) */
+#define SHTAB 37 /* Show Tabs (OS/2) */
+#define SHVSCRN 38 /* Show Virtual Screen (OS/2) */
+#define SHALRM 39 /* ALARM */
+#define SHSFL 40 /* SEND-LIST */
+#define SHUDK 41 /* DEC VT UDKs (OS/2) */
+#define SHDBL 42 /* DOUBLE/IGNORE characters */
+#define SHEDIT 43 /* EDITOR */
+#define SHBROWSE 44 /* BROWSER */
+#define SHTAPI 45 /* TAPI */
+#define SHTAPI_L 46 /* TAPI Location */
+#define SHTAPI_M 47 /* TAPI Modem Properties */
+#define SHTAPI_C 48 /* TAPI Comm Properties */
+#define SHTEL 49 /* SHOW TELNET */
+#define SHINP 50 /* SHOW INPUT */
+#define SHTRIG 51 /* SHOW TRIGGER */
+#define SHLOG 52 /* SHOW LOGS */
+#define SHOUTP 53 /* SHOW OUTPUT */
+#define SHOPAT 54 /* SHOW PATTERNS */
+#define SHOSTR 55 /* SHOW STREAMING */
+#define SHOAUTH 56 /* SHOW AUTHENTICATION */
+#define SHOFTP 57 /* SHOW FTP */
+#define SHTOPT 58 /* SHOW TELOPT */
+#define SHXOPT 59 /* SHOW EXTENDED-OPTIONS */
+#define SHCD 60 /* SHOW CD */
+#define SHASSOC 61 /* SHOW ASSOCIATIONS */
+#define SHCONNX 62 /* SHOW CONNECTION */
+#define SHOPTS 63 /* SHOW OPTIONS */
+#define SHOFLO 64 /* SHOW FLOW-CONTROL */
+#define SHOXFER 65 /* SHOW TRANSFER */
+#define SHTCP 66 /* SHOW TCP */
+#define SHHISTORY 67 /* SHOW (command) HISTORY */
+#define SHSEXP 68 /* SHOW SEXPRESSIONS */
+#define SHOSSH 69 /* SHOW SSH */
+#define SHOIKS 70 /* SHOW IKS */
+#define SHOGUI 71 /* SHOW GUI (K95) */
+#define SHOREN 72 /* SHOW RENAME */
+
+/* REMOTE command symbols */
+
+#define XZCPY 0 /* Copy */
+#define XZCWD 1 /* Change Working Directory */
+#define XZDEL 2 /* Delete */
+#define XZDIR 3 /* Directory */
+#define XZHLP 4 /* Help */
+#define XZHOS 5 /* Host */
+#define XZKER 6 /* Kermit */
+#define XZLGI 7 /* Login */
+#define XZLGO 8 /* Logout */
+#define XZMAI 9 /* Mail <-- wrong, this should be top-level */
+#define XZMOU 10 /* Mount */
+#define XZMSG 11 /* Message */
+#define XZPRI 12 /* Print */
+#define XZREN 13 /* Rename */
+#define XZSET 14 /* Set */
+#define XZSPA 15 /* Space */
+#define XZSUB 16 /* Submit */
+#define XZTYP 17 /* Type */
+#define XZWHO 18 /* Who */
+#define XZPWD 19 /* Print Working Directory */
+#define XZQUE 20 /* Query */
+#define XZASG 21 /* Assign */
+#define XZMKD 22 /* mkdir */
+#define XZRMD 23 /* rmdir */
+#define XZXIT 24 /* Exit */
+#define XZCDU 25 /* CDUP */
+
+/* SET INPUT command parameters */
+
+#define IN_DEF 0 /* Default timeout */
+#define IN_TIM 1 /* Timeout action */
+#define IN_CAS 2 /* Case (matching) */
+#define IN_ECH 3 /* Echo */
+#define IN_SIL 4 /* Silence */
+#define IN_BUF 5 /* Buffer size */
+#define IN_PAC 6 /* Input Pacing (debug) */
+#define IN_TRM 7 /* Input Terminal Display */
+#define IN_ADL 8 /* Input autodownload */
+#define IN_PAT 9 /* Pattern to match */
+#define IN_ASG 10 /* Assign matching text to variable */
+#define IN_CAN 11 /* Keyboard cancellation of INPUT */
+#define IN_SCA 12 /* Timeout scaling */
+
+/* ENABLE/DISABLE command parameters */
+
+#define EN_ALL 0 /* ALL */
+#define EN_CWD 1 /* CD/CWD */
+#define EN_DIR 2 /* DIRECTORY */
+#define EN_FIN 3 /* FINISH */
+#define EN_GET 4 /* GET */
+#define EN_HOS 5 /* HOST command */
+#define EN_KER 6 /* KERMIT command */
+#define EN_LOG 7 /* LOGIN */
+#define EN_SEN 8 /* SEND */
+#define EN_SET 9 /* SET */
+#define EN_SPA 10 /* SPACE */
+#define EN_TYP 11 /* TYPE */
+#define EN_WHO 12 /* WHO, finger */
+#define EN_DEL 13 /* Delete */
+#define EN_BYE 14 /* BYE (as opposed to FINISH) */
+#define EN_QUE 15 /* QUERY */
+#define EN_ASG 16 /* ASSIGN */
+#define EN_CPY 17 /* COPY */
+#define EN_REN 18 /* RENAME */
+#define EN_RET 19 /* RETRIEVE */
+#define EN_MAI 20 /* MAIL */
+#define EN_PRI 21 /* PRINT */
+#define EN_MKD 22 /* MKDIR */
+#define EN_RMD 23 /* RMDIR */
+#define EN_XIT 24 /* EXIT */
+#define EN_ENA 25 /* ENABLE */
+#endif /* NOICP */
+
+#ifndef NOICP
+/* CLEAR command symbols */
+#define CLR_DEV 1 /* Clear Device Buffers */
+#define CLR_INP 2 /* Clear Input Buffers */
+#define CLR_BTH CLR_DEV|CLR_INP /* Clear Device and Input */
+#define CLR_SCL 4 /* Clear Scrollback buffer */
+#define CLR_CMD 8 /* Clear Command Screen */
+#define CLR_TRM 16 /* Clear Terminal Screen */
+#define CLR_DIA 32 /* Clear Dial Status */
+#define CLR_SFL 64 /* Clear Send-File-List */
+#define CLR_APC 128 /* Clear APC */
+#define CLR_ALR 256 /* Clear Alarm */
+#define CLR_TXT 512 /* Clear text-patterns */
+#define CLR_BIN 1024 /* Clear binary-patterns */
+#define CLR_SCR 2048 /* Clear screen */
+#define CLR_KBD 4096 /* Clear keyboard buffer */
+#endif /* NOICP */
+
+/* Symbols for logs */
+
+#define LOGD 0 /* Debugging */
+#define LOGP 1 /* Packets */
+#define LOGS 2 /* Session */
+#define LOGT 3 /* Transaction */
+#define LOGX 4 /* Screen */
+#define LOGR 5 /* The "open read" file */
+#define LOGW 6 /* The "open write/append" file */
+#define LOGE 7 /* Error (e.g. stderr) */
+#define LOGM 8 /* The dialing log */
+
+#ifndef NOSPL
+/* Symbols for builtin variables */
+
+#define VN_ARGC 0 /* ARGC */
+#define VN_COUN 1 /* COUNT */
+#define VN_DATE 2 /* DATE */
+#define VN_DIRE 3 /* DIRECTORY */
+#define VN_ERRO 4 /* ERRORLEVEL */
+#define VN_TIME 5 /* TIME */
+#define VN_VERS 6 /* VERSION */
+#define VN_IBUF 7 /* INPUT buffer */
+#define VN_SUCC 8 /* SUCCESS flag */
+#define VN_LINE 9 /* LINE */
+#define VN_ARGS 10 /* Program command-line arg count */
+#define VN_SYST 11 /* System type */
+#define VN_SYSV 12 /* System version */
+#define VN_RET 13 /* RETURN value */
+#define VN_FILE 14 /* Most recent filespec */
+#define VN_NDAT 15 /* Numeric date yyyy/mm/dd */
+#define VN_HOME 16 /* Home directory */
+#define VN_SPEE 17 /* Transmission speed */
+#define VN_HOST 18 /* Host name */
+#define VN_TTYF 19 /* TTY file descriptor (UNIX only) */
+#define VN_PROG 20 /* Program name */
+#define VN_NTIM 21 /* NTIME */
+#define VN_FFC 22 /* Characters in last file xferred */
+#define VN_TFC 23 /* Chars in last file group xferred */
+#define VN_CPU 24 /* CPU type */
+#define VN_CMDL 25 /* Command level */
+#define VN_DAY 26 /* Day of week, string */
+#define VN_NDAY 27 /* Day of week, numeric */
+#define VN_LCL 28 /* Local (vs) remote mode */
+#define VN_CMDS 29 /* Command source */
+#define VN_CMDF 30 /* Command file name */
+#define VN_MAC 31 /* Macro name */
+#define VN_EXIT 32 /* Exit status */
+#define VN_ICHR 33 /* INPUT character */
+#define VN_ICNT 34 /* INPUT count */
+#define VN_PRTY 35 /* Current parity */
+#define VN_DIAL 36 /* DIAL status */
+#define VN_KEYB 37 /* Keyboard type */
+#define VN_CPS 38 /* Chars per second, last transfer */
+#define VN_RPL 39 /* Receive packet length */
+#define VN_SPL 40 /* Send packet length */
+#define VN_MODE 41 /* Transfer mode (text, binary) */
+#define VN_REXX 42 /* Rexx return value */
+#define VN_NEWL 43 /* Newline character or sequence */
+#define VN_COLS 44 /* Columns on console screen */
+#define VN_ROWS 45 /* Rows on console screen */
+#define VN_TTYP 46 /* Terminal type */
+#define VN_MINP 47 /* MINPUT result */
+#define VN_CONN 48 /* Connection type */
+#define VN_SYSI 49 /* System ID */
+#define VN_TZ 50 /* Timezone */
+#define VN_SPA 51 /* Space */
+#define VN_QUE 52 /* Query */
+#define VN_STAR 53 /* Startup directory */
+#define VN_CSET 54 /* Local character set */
+#define VN_MDM 55 /* Modem type */
+#define VN_EVAL 56 /* Most recent EVALUATE result */
+
+#define VN_D_CC 57 /* DIAL COUNTRY-CODE */
+#define VN_D_AC 58 /* DIAL AREA-CODE */
+#define VN_D_IP 59 /* DIAL INTERNATIONAL-PREFIX */
+#define VN_D_LP 60 /* DIAL LD-PREFIX */
+
+#define VN_UID 61
+#define VN_PWD 62
+#define VN_PRM 63
+
+#define VN_PROTO 64 /* Protocol */
+#define VN_DLDIR 65 /* Download directory */
+
+#define VN_M_AAA 66 /* First MODEM one */
+#define VN_M_INI 66 /* Modem init string */
+#define VN_M_DCM 67 /* Modem dial command */
+#define VN_M_DCO 68 /* Modem data compression on */
+#define VN_M_DCX 69 /* Modem data compression off */
+#define VN_M_ECO 70 /* Modem error correction on */
+#define VN_M_ECX 71 /* Modem error correction off */
+#define VN_M_AAO 72 /* Modem autoanswer on */
+#define VN_M_AAX 73 /* Modem autoanswer off */
+#define VN_M_HUP 74 /* Modem hangup command */
+#define VN_M_HWF 75 /* Modem hardware flow command */
+#define VN_M_SWF 76 /* Modem software flow command */
+#define VN_M_NFC 77 /* Modem no flow-control command */
+#define VN_M_PDM 78 /* Modem pulse dialing mode */
+#define VN_M_TDM 79 /* Modem tone dialing mode */
+#define VN_M_ZZZ 79 /* Last MODEM one */
+
+#define VN_SELCT 80 /* Selected Text from Mark Mode */
+#define VN_TEMP 81 /* Temporary directory */
+#define VN_ISTAT 82 /* INPUT command status */
+#define VN_INI 83 /* INI (kermrc) directory */
+#define VN_EXEDIR 84 /* EXE directory */
+#define VN_ERRNO 85 /* Value of errno */
+#define VN_ERSTR 86 /* Corresponding error message */
+#define VN_TFLN 87 /* TAKE file line number */
+#define VN_XVNUM 88 /* Product-specific version number */
+#define VN_RPSIZ 89 /* Receive packet length */
+#define VN_WINDO 90 /* Window size */
+#define VN_MDMSG 91 /* Modem message */
+#define VN_DNUM 92 /* Dial number */
+#define VN_APC 93 /* APC active */
+#define VN_IPADDR 94 /* My IP address */
+#define VN_CRC16 95 /* CRC-16 of most recent file group */
+#define VN_TRMK 96 /* Macro executed from Terminal Mode */
+#define VN_PID 97 /* Process ID */
+#define VN_FNAM 98 /* Name of file being transferred */
+#define VN_FNUM 99 /* Number of file being transferred */
+#define VN_PEXIT 100 /* Process exit status */
+#define VN_P_CTL 101 /* Control Prefix */
+#define VN_P_8BIT 102 /* 8-bit prefix */
+#define VN_P_RPT 103 /* Repeat count prefix */
+#define VN_D_LCP 104 /* DIAL LOCAL-PREFIX */
+#define VN_URL 105 /* Last URL selected */
+#define VN_REGN 106 /* Registration Name */
+#define VN_REGO 107 /* Registration Organization */
+#define VN_REGS 108 /* Registration Serial number */
+#define VN_XPROG 109 /* xprogram (like xversion) */
+#define VN_EDITOR 110 /* Editor */
+#define VN_EDOPT 111 /* Editor options */
+#define VN_EDFILE 112 /* Editor file */
+#define VN_BROWSR 113 /* Browser */
+#define VN_BROPT 114 /* Browser options */
+#define VN_HERALD 115 /* Program herald */
+#define VN_TEST 116 /* Program test level or "0" */
+#define VN_XFSTAT 117 /* File-Transfer status */
+#define VN_XFMSG 119 /* File-Transfer message */
+#define VN_SNDL 120 /* Send-list status */
+#define VN_TRIG 121 /* Trigger value */
+#define VN_MOU_X 122 /* OS/2 Mouse Cursor X */
+#define VN_MOU_Y 123 /* OS/2 Mouse Cursor Y */
+#define VN_PRINT 124 /* Printer */
+#define VN_ESC 125 /* Escape character */
+#define VN_INTIME 126 /* INPUT elapsed time */
+#define VN_K4RLM 127 /* Kerberos 4 Realm */
+#define VN_K5RLM 128 /* Kerberos 5 Realm */
+#define VN_K4PRN 129 /* Kerberos 4 Principal */
+#define VN_K5PRN 130 /* Kerberos 5 Principal */
+#define VN_K4CC 131 /* Kerberos 4 Credentials Cache */
+#define VN_K5CC 132 /* Kerberos 5 Credentials Cache */
+#define VN_OSNAM 133 /* OS name */
+#define VN_OSVER 134 /* OS version */
+#define VN_OSREL 135 /* OS release */
+#define VN_NAME 136 /* Name I was called by */
+#define VN_MODL 137 /* CPU model */
+#define VN_X25LA 138 /* X.25 local address */
+#define VN_X25RA 139 /* X.25 remote address */
+#define VN_K4SRV 140 /* Kerberos 4 Service Name */
+#define VN_K5SRV 141 /* Kerberos 5 Service Name */
+#define VN_PDSFX 142 /* PDIAL suffix */
+#define VN_DTYPE 143 /* DIAL type */
+#define VN_LCKPID 144 /* Lockfile PID (UNIX) */
+#define VN_BLK 145 /* Block check */
+#define VN_TFTIM 146 /* File transfer elapsed time */
+#define VN_D_PXX 147 /* DIAL PBX-EXCHANGE */
+#define VN_HWPAR 148 /* Hardware Parity */
+#define VN_SERIAL 149 /* SET SERIAL value */
+#define VN_LCKDIR 150 /* Lockfile directory (UNIX) */
+
+#define VN_K4ENO 151 /* Kerberos 4 Last Errno */
+#define VN_K4EMSG 152 /* Kerberos 4 Last Err Msg */
+#define VN_K5ENO 153 /* Kerberos 5 Last Errno */
+#define VN_K5EMSG 154 /* Kerberos 5 Last Err Msg */
+
+#define VN_INTMO 155 /* Input timeout */
+#define VN_AUTHS 156 /* Authentication State */
+
+#define VN_DM_LP 157 /* Dial Modifier: Long Pause */
+#define VN_DM_SP 158 /* Dial Modifier: Short Pause */
+#define VN_DM_PD 159 /* Dial Modifier: Pulse Dial */
+#define VN_DM_TD 160 /* Dial Modifier: Tone Dial */
+#define VN_DM_WA 161 /* Dial Modifier: Wait for Answer */
+#define VN_DM_WD 162 /* Dial Modifier: Wait for Dialtone */
+#define VN_DM_RC 163 /* Dial Modifier: Return to Command */
+
+/* (more below...) */
+
+#define VN_TY_LN 164 /* TYPE command line number */
+#define VN_TY_LC 165 /* TYPE command line count */
+#define VN_TY_LM 166 /* TYPE command match count */
+
+#define VN_MACLVL 167 /* \v(maclevel) */
+
+#define VN_XF_BC 168 /* Transfer blockcheck errors */
+#define VN_XF_TM 169 /* Transfer timeouts */
+#define VN_XF_RX 170 /* Transfer retransmissions */
+
+#define VN_M_NAM 171 /* Modem full name */
+#define VN_MS_CD 172 /* Modem signal CD */
+#define VN_MS_CTS 173 /* Modem signal CTS */
+#define VN_MS_DSR 174 /* Modem signal DSR */
+#define VN_MS_DTR 175 /* Modem signal DTR */
+#define VN_MS_RI 176 /* Modem signal RI */
+#define VN_MS_RTS 177 /* Modem signal RTS */
+
+#define VN_MATCH 178 /* Most recent pattern match */
+#define VN_SLMSG 179 /* SET LINE (error) message */
+#define VN_TXTDIR 180 /* Kermit text-file directory */
+#define VN_MA_PI 181 /* Math constant Pi */
+#define VN_MA_E 182 /* Math constant e */
+#define VN_MA_PR 183 /* Math precision (digits) */
+#define VN_CMDBL 184 /* Command buffer length */
+
+#define VN_AUTHT 185 /* Authentication Type */
+
+#ifdef CKCHANNELIO
+#define VN_FERR 186 /* FILE error */
+#define VN_FMAX 187 /* FILE max */
+#define VN_FCOU 188 /* Result of last FILE COUNT */
+#endif /* CKCHANNELIO */
+
+#define VN_DRTR 189 /* DIAL retry counter */
+#define VN_CXTIME 190 /* Elapsed time in session */
+#define VN_BYTE 191 /* Byte order */
+#define VN_AUTHN 192 /* Authentication Name */
+#define VN_KBCHAR 193 /* kbchar */
+#define VN_TTYNAM 194 /* Name of controlling terminal */
+
+#define VN_X509_S 195 /* X.509 Certificate Subject */
+#define VN_X509_I 196 /* X.509 Certificate Issuer */
+
+#define VN_PROMPT 197 /* C-Kermit's prompt */
+#define VN_BUILD 198 /* Build ID string */
+
+#define VN_SEXP 199 /* Last S-Expression */
+#define VN_VSEXP 200 /* Value of last S-Expression */
+#define VN_LSEXP 201 /* SEXP depth */
+
+#define VN_FTIME 202 /* Time as floating-poing number */
+
+#define VN_FTP_C 203 /* FTP Reply Code */
+#define VN_FTP_M 204 /* FTP Reply Message */
+#define VN_FTP_S 205 /* FTP Server type */
+#define VN_FTP_H 206 /* FTP Host */
+#define VN_FTP_X 207 /* FTP Connected */
+#define VN_FTP_L 208 /* FTP Logged in */
+#define VN_FTP_G 209 /* FTP GET-PUT-REMOTE setting */
+
+#define VN_SECURE 210 /* Encrypted connection 0 or 1 */
+
+#define VN_DM_HF 211 /* Dial Modifier: Hook Flash */
+#define VN_DM_WB 212 /* Dial Modifier: Wait for Bong */
+#define VN_CX_STA 213 /* CX_STATUS */
+
+#define VN_FTP_B 214 /* FTP CPL */
+#define VN_FTP_D 215 /* FTP DPL */
+#define VN_FTP_Z 216 /* FTP SECURITY */
+#define VN_HTTP_C 217 /* HTTP Code */
+#define VN_HTTP_N 218 /* HTTP Connected */
+#define VN_HTTP_H 219 /* HTTP Host */
+#define VN_HTTP_M 220 /* HTTP Message */
+#define VN_HTTP_S 221 /* HTTP Security */
+
+#define VN_NOW 222 /* Timestamp yyyymmdd hh:mm:ss */
+#define VN_HOUR 223 /* Current hour of the day 0-23 */
+
+#define VN_CI_DA 224 /* Caller ID date */
+#define VN_CI_TI 225 /* Caller ID time */
+#define VN_CI_NA 226 /* Caller ID name */
+#define VN_CI_NU 227 /* Caller ID number */
+#define VN_CI_ME 228 /* Caller ID message */
+#define VN_PERSONAL 229 /* Personal Directory on Windows */
+#define VN_APPDATA 230 /* User AppData directory */
+#define VN_COMMON 231 /* Common AppData directory */
+#define VN_DESKTOP 232 /* User Desktop directory */
+#define VN_TNC_SIG 233 /* RFC 2717 Signature */
+
+#ifdef KUI
+#define VN_GUI_XP 234 /* GUI Window X position */
+#define VN_GUI_YP 235 /* GUI Window Y position */
+#define VN_GUI_XR 236 /* GUI Window X resolution */
+#define VN_GUI_YR 237 /* GUI Window Y resolution */
+#define VN_GUI_RUN 238 /* GUI Window Run mode */
+#define VN_GUI_FNM 239 /* GUI Window Font Name */
+#define VN_GUI_FSZ 240 /* GUI Window Font Size */
+#endif /* KUI */
+
+#define VN_LOG_PKT 241 /* Packet Log Filename */
+#define VN_LOG_TRA 242 /* Transaction Log Filename */
+#define VN_LOG_SES 243 /* Session Log Filename */
+#define VN_LOG_DEB 244 /* Debug Log Filename */
+#define VN_LOG_CON 245 /* Connection Log Filename */
+
+#define VN_ISCALE 246 /* INPUT scale factor */
+#define VN_BITS 247 /* Bits of this build (16, 32, 64) */
+#define VN_LASTFIL 248 /* Last input filespec */
+#define VN_LASTKWV 249 /* Last \fkeywordvalue() keyword */
+#define VN_DMSG 250 /* Msg corresponding to dialstatus */
+#define VN_HOSTIP 251 /* IP address of remote host */
+#define VN_INPMSG 252 /* Msg corresponding to instatus */
+#define VN_VAREVAL 253 /* SET VARIABLE-EVALUATION setting */
+#define VN_PREVCMD 254 /* Previous command */
+#endif /* NOSPL */
+
+/* INPUT status values */
+
+#define INP_OK 0 /* Succeeded */
+#define INP_TO 1 /* Timed out */
+#define INP_UI 2 /* User interrupted */
+#define INP_IE 3 /* Internal error */
+#define INP_IO 4 /* I/O error or connection lost */
+#define INP_IKS 5 /* Kermit Server Active */
+#define INP_BF 6 /* Buffer full */
+
+/* INPUT switch values */
+
+#define INPSW_NOM 1 /* /NOMATCH */
+#define INPSW_CLR 2 /* /CLEAR */
+#define INPSW_NOW 4 /* /NOWRAP */
+#define INPSW_COU 8 /* /COUNT */
+
+#ifndef NOSPL
+/* Symbols for builtin functions */
+
+#define FNARGS 6 /* Maximum number of function args */
+
+#define FN_IND 0 /* Index (of string 1 in string 2) */
+#define FN_LEN 1 /* Length (of string) */
+#define FN_LIT 2 /* Literal (don't expand the string) */
+#define FN_LOW 3 /* Lower (convert to lowercase) */
+#define FN_MAX 4 /* Max (maximum) */
+#define FN_MIN 5 /* Min (minimum) */
+#define FN_MOD 6 /* Mod (modulus) */
+#define FN_EVA 7 /* Eval (evaluate arith expression) */
+#define FN_SUB 8 /* Substr (substring) */
+#define FN_UPP 9 /* Upper (convert to uppercase) */
+#define FN_REV 10 /* Reverse (a string) */
+#define FN_REP 11 /* Repeat (a string) */
+#define FN_EXE 12 /* Execute (a macro) */
+#define FN_VAL 13 /* Return value (of a macro) */
+#define FN_LPA 14 /* LPAD (left pad) */
+#define FN_RPA 15 /* RPAD (right pad) */
+#define FN_DEF 16 /* Definition of a macro, unexpanded */
+#define FN_CON 17 /* Contents of a variable, ditto */
+#define FN_FIL 18 /* File list */
+#define FN_FC 19 /* File count */
+#define FN_CHR 20 /* Character (like BASIC CHR$()) */
+#define FN_RIG 21 /* Right (like BASIC RIGHT$()) */
+#define FN_COD 22 /* Code value of character */
+#define FN_RPL 23 /* Replace */
+#define FN_FD 24 /* File date */
+#define FN_FS 25 /* File size */
+#define FN_RIX 26 /* Rindex (index from right) */
+#define FN_VER 27 /* Verify */
+#define FN_IPA 28 /* Find and return IP address */
+#define FN_CRY 39 /* ... */
+#define FN_OOX 40 /* ... */
+#define FN_HEX 41 /* Hexify */
+#define FN_UNH 42 /* Unhexify */
+#define FN_BRK 43 /* Break */
+#define FN_SPN 44 /* Span */
+#define FN_TRM 45 /* Trim */
+#define FN_LTR 46 /* Left-Trim */
+#define FN_CAP 47 /* Capitalize */
+#define FN_TOD 48 /* Time-of-day-to-secs-since-midnite */
+#define FN_SEC 49 /* Secs-since-midnite-to-time-of-day */
+#define FN_FFN 50 /* Full file name */
+#define FN_CHK 51 /* Checksum of text */
+#define FN_CRC 52 /* CRC-16 of text */
+#define FN_BSN 53 /* Basename of file */
+#define FN_CMD 54 /* Output of a command (cooked) */
+#define FN_RAW 55 /* Output of a command (raw) */
+#define FN_STX 56 /* Strip from right */
+#define FN_STL 57 /* Strip from left */
+#define FN_STN 58 /* Strip n chars */
+#define FN_SCRN_CX 59 /* Screen Cursor X Pos */
+#define FN_SCRN_CY 60 /* Screen Cursor Y Pos */
+#define FN_SCRN_STR 61 /* Screen String */
+#define FN_2HEX 62 /* Number (not string) to hex */
+#define FN_2OCT 63 /* Number (not string) to octal */
+#define FN_RFIL 64 /* Recursive file list */
+#define FN_DIR 65 /* Directory list */
+#define FN_RDIR 66 /* Recursive directory list */
+#define FN_DNAM 67 /* Directory part of filename */
+#define FN_RAND 68 /* Random number */
+#define FN_WORD 69 /* Word extraction */
+#define FN_SPLIT 70 /* Split string into words */
+#define FN_KRB_TK 71 /* Kerberos tickets */
+#define FN_KRB_NX 72 /* Kerberos next ticket */
+#define FN_KRB_IV 73 /* Kerberos ticket is valid */
+#define FN_KRB_TT 74 /* Kerberos ticket time */
+#define FN_ERRMSG 75 /* Error code to message */
+
+#ifndef UNIX
+#ifndef VMS
+#undef FN_ERRMSG
+#endif /* VMS */
+#endif /* UNIX */
+
+#define FN_DIM 76 /* Dimension of array */
+#define FN_DTIM 77 /* Convert to standard date/time */
+#define FN_JDATE 78 /* Regular date to day of year */
+#define FN_PNCVT 79 /* Convert phone number for dialing */
+#define FN_DATEJ 80 /* Day of year to date */
+#define FN_MJD 81 /* Date to modified Julian date */
+#define FN_MJD2 82 /* Modified Julian date to date */
+#define FN_DAY 83 /* Day of week of given date */
+#define FN_NDAY 84 /* Numeric day of week of given date */
+#define FN_TIME 85 /* Convert to hh:mm:ss */
+#define FN_NTIM 86 /* Convert to seconds since midnite */
+#define FN_N2TIM 87 /* Sec since midnite to hh:mm:ss */
+#define FN_PERM 88 /* Permissions of file */
+#define FN_KRB_FG 89 /* Kerberos Ticket Flags */
+#define FN_SEARCH 90 /* Search for pattern in string */
+#define FN_RSEARCH 91 /* Ditto, but right to left */
+#define FN_XLATE 92 /* Translate string charset */
+#define FN_ALOOK 93 /* Array lookup */
+#define FN_TLOOK 94 /* Table lookup */
+#define FN_TOB64 95 /* Encode into Base64 */
+#define FN_FMB64 96 /* Decode from Base64 */
+
+#define FN_ABS 97 /* Absolute value */
+
+#ifdef CKFLOAT
+#define FN_FPADD 98 /* Floating-point add */
+#define FN_FPSUB 99 /* Floating-point substract */
+#define FN_FPMUL 100 /* Floating-point multiply */
+#define FN_FPDIV 101 /* Floating-point divide */
+#define FN_FPEXP 102 /* Floating-point e to the x */
+#define FN_FPLN 103 /* Floating-point natural log */
+#define FN_FPLOG 104 /* Floating-point base-10 log */
+#define FN_FPPOW 105 /* Floating-point raise to power */
+#define FN_FPSQR 106 /* Floating-point square root */
+#define FN_FPABS 107 /* Floating-point absolute value */
+#define FN_FPMOD 108 /* Floating-point modulus */
+#define FN_FPMAX 109 /* Floating-point maximum */
+#define FN_FPMIN 110 /* Floating-point minimum*/
+#define FN_FPINT 111 /* Floating-point to integer */
+#define FN_FPROU 112 /* Floating-point round */
+#define FN_FPSIN 113 /* FP sine */
+#define FN_FPCOS 114 /* FP cosine */
+#define FN_FPTAN 115 /* FP tangent */
+#endif /* CKFLOAT */
+
+#ifdef CKCHANNELIO
+#define FN_FSTAT 116 /* File status */
+#define FN_FPOS 117 /* File position */
+#define FN_FEOF 118 /* File eof */
+#define FN_FILNO 119 /* File number / handle */
+#define FN_FGCHAR 120 /* File getchar */
+#define FN_FGLINE 121 /* File getline */
+#define FN_FGBLK 122 /* File getblock */
+#define FN_FPCHAR 123 /* File putchar */
+#define FN_FPLINE 124 /* File putline */
+#define FN_FPBLK 125 /* File putblock */
+#define FN_NLINE 126 /* File get current line number */
+#define FN_FERMSG 127 /* File error message */
+#endif /* CKCHANNELIO */
+
+#define FN_LEF 128 /* Left (= substr starting on left) */
+#define FN_AADUMP 129 /* Associative Array Dump */
+#define FN_STB 130 /* \fstripb() */
+#define FN_PATTERN 131 /* \fpattern() */
+#define FN_HEX2N 132 /* \fhexton() */
+#define FN_OCT2N 133 /* \foctton() */
+#define FN_HEX2IP 134 /* \fhextoip() */
+#define FN_IP2HEX 135 /* \fiptohex() */
+#define FN_RADIX 136 /* \fradix() */
+#define FN_JOIN 137 /* \fjoin() */
+#define FN_SUBST 138 /* \fsubstitute() */
+#define FN_SEXP 139 /* \fsexpression() */
+#define FN_CMDSTK 140 /* \fcmdstack() */
+#define FN_TOGMT 141 /* \ftogmt() */
+#define FN_CMPDATE 142 /* \fcmpdates() */
+#define FN_DIFDATE 143 /* \fdiffdates() */
+#ifdef TCPSOCKET
+#define FN_HSTADD 144 /* \faddr2name() */
+#define FN_HSTNAM 145 /* \fname2addr() */
+#endif /* TCPSOCKET */
+#define FN_DELSEC 146 /* \fdelta2sec() */
+#define FN_PC_DU 147 /* Path conversion DOS to Unix */
+#define FN_PC_VU 148 /* Path conversion VMS to Unix */
+#define FN_PC_UD 149 /* Path conversion Unix to DOS */
+#define FN_PC_UV 150 /* Path conversion Unix to VMS */
+#define FN_KWVAL 151 /* \fkeywordvalue() */
+#define FN_SLEEP 152 /* \fsleep() */
+#define FN_MSLEEP 153 /* \fmsleep() */
+#define FN_LNAME 154 /* \fLongPathName() (Windows) */
+#define FN_SNAME 155 /* \fShortPathName() (Windows) */
+#define FN_UNTAB 156 /* \funtabify() */
+#define FN_LOPX 157 /* \flopx() */
+#define FN_EMAIL 158 /* \femailaddress() */
+#define FN_PICTURE 159 /* \fpictureinfo() */
+#define FN_PID 160 /* \fpidinfo() */
+#define FN_COUNT 161 /* \fcount() */
+#define FN_FUNC 162 /* \ffunction() */
+#define FN_RECURSE 163 /* \frecurse() */
+#define FN_SQUEEZE 164 /* \fsqueeze() */
+#define FN_UNPCT 165 /* \fdecodehex() */
+#define FN_STRINGT 166 /* \fstringtype() */
+#define FN_STRCMP 167 /* \fstrcmp() */
+
+#endif /* NOSPL */
+
+/* Time Units */
+
+#define TU_DAYS 0
+#define TU_WEEKS 1
+#define TU_MONTHS 2
+#define TU_YEARS 3
+
+#ifdef CK_CURSES
+/* Screen line numbers for fullscreen file-transfer display */
+
+#define CW_BAN 0 /* Curses Window Banner */
+#define CW_DIR 2 /* Current directory */
+#define CW_LIN 3 /* Communication device */
+#define CW_SPD 4 /* Communication speed */
+#define CW_PAR 5 /* Parity */
+#define CW_TMO 6
+#define CW_NAM 7 /* Filename */
+#define CW_TYP 8 /* File type */
+#define CW_SIZ 9 /* File size */
+#define CW_PCD 10 /* Percent done */
+
+#ifndef CK_PCT_BAR
+#define CW_TR 11 /* Time remaining */
+#define CW_CP 12 /* Characters per second */
+#define CW_WS 13 /* Window slots */
+#define CW_PT 14 /* Packet type */
+#define CW_PC 15 /* Packet count */
+#define CW_PL 16 /* Packet length */
+#define CW_PR 17 /* Packet retry */
+#ifdef COMMENT
+#define CW_PB 17 /* Packet block check */
+#endif /* COMMENT */
+#else /* CK_PCT_BAR */
+#define CW_BAR 11 /* Percent Bar Scale */
+#define CW_TR 12 /* Time remaining */
+#define CW_CP 13 /* Chars per sec */
+#define CW_WS 14 /* Window slots */
+#define CW_PT 15 /* Packet type */
+#define CW_PC 16 /* Packet count */
+#define CW_PL 17 /* Packet length */
+#define CW_PR 18 /* Packet retry */
+#ifdef COMMENT
+#define CW_PB 18 /* Packet block check */
+#endif /* COMMENT */
+#endif /* CK_PCT_BAR */
+
+#define CW_ERR 19 /* Error message */
+#define CW_MSG 20 /* Info message */
+#define CW_INT 22 /* Instructions */
+#define CW_FFC 99 /* File Characters Sent/Received */
+#endif /* CK_CURSES */
+
+#ifndef NOICP
+/* Save Commands */
+#define XSKEY 0 /* Key map file */
+#define XSCMD 1 /* Command mode */
+#define XSTERM 2 /* Terminal mode */
+#endif /* NOICP */
+
+#ifndef NODIAL
+/* Dial routine sort priorities */
+#define DN_INTERN 0
+#define DN_FREE 1
+#define DN_LOCAL 2
+#define DN_UNK 3
+#define DN_LONG 4
+#define DN_INTL 5
+#endif /* NODIAL */
+
+#ifdef SSHBUILTIN
+#define XSSH_OPN 1
+#define XSSH_V2 2
+#define XSSH_FLP 3
+#define XSSH_FRP 4
+#define XSSH_ADD 5
+#define XSSH_KEY 6
+#define XSSH_CLR 7
+#define XSSH_AGT 8
+
+#define SSHKT_1R 0 /* SSH KEY TYPE symbols */
+#define SSHKT_2R 1 /* must match ssh/key.h values */
+#define SSHKT_2D 2
+#define SSHKT_SRP 3
+
+#define SSHKD_IN 1 /* SSH KEY DISPLAY /IN-FORMAT */
+#define SSHKD_OUT 2 /* SSH KEY DISPLAY /OUT-FORMAT */
+
+#define SKDF_OSSH 1 /* Key display format OpenSSH */
+#define SKDF_SSHC 2 /* Key display format SSH.COM */
+#define SKDF_IETF 3 /* Key display format IETF */
+#define SKDF_FING 4 /* Key display format FINGERPRINT */
+
+#define SSHSW_USR 1
+#define SSHSW_VER 2
+#define SSHSW_CMD 3
+#define SSHSW_X11 4
+#define SSHSW_PWD 5
+#define SSHSW_SUB 6
+
+#define SSHC_LPF 1
+#define SSHC_RPF 2
+
+#define XSSH2_RKE 1
+
+#define SSHF_LCL 1
+#define SSHF_RMT 2
+
+#define SSHA_ADD 1
+#define SSHA_DEL 2
+#define SSHA_LST 3
+
+#define SSHASW_FP 1
+
+#define SSHK_PASS 1
+#define SSHK_CREA 2
+#define SSHK_DISP 3
+#define SSHK_V1 4
+
+#define SSHKC_BI 1
+#define SSHKC_PP 2
+#define SSHKC_TY 3
+#define SSHKC_1R 4
+
+#define SKRM_OPN 1
+#endif /* SSHBUILTIN */
+
+#ifdef SFTP_BUILTIN
+#define SFTP_OPN 1
+#define SFTP_CD 2
+#define SFTP_CHGRP 3
+#define SFTP_CHMOD 4
+#define SFTP_CHOWN 5
+#define SFTP_DIR 6
+#define SFTP_GET 7
+#define SFTP_MKDIR 8
+#define SFTP_PWD 9
+#define SFTP_PUT 10
+#define SFTP_REN 11
+#define SFTP_RM 12
+#define SFTP_RMDIR 13
+#define SFTP_LINK 14
+#define SFTP_VER 15
+
+#define XY_SFTP_RCS 1
+#define XY_SFTP_EOL 2
+#endif /* SFTP_BUILTIN */
+
+/* ANSI-C prototypes for user interface functions */
+
+#ifdef UNIX
+_PROTOTYP( int doputenv, ( char *, char * ) );
+#endif /* UNIX */
+
+_PROTOTYP( int chkaes, ( char, int ) );
+
+#ifndef NOICP
+_PROTOTYP( int matchname, ( char *, int, int ) );
+_PROTOTYP( int ck_cls, ( void ) );
+_PROTOTYP( int ck_cleol, ( void ) );
+_PROTOTYP( int ck_curpos, ( int, int ) );
+_PROTOTYP( int cmdsrc, ( void ) );
+_PROTOTYP( int parser, ( int ) );
+_PROTOTYP( int chkvar, (char *) );
+_PROTOTYP( int zzstring, (char *, char **, int *) );
+#ifndef NOFRILLS
+_PROTOTYP( int yystring, (char *, char **) );
+#endif /* NOFRILLS */
+_PROTOTYP( int getncm, (char *, int) );
+_PROTOTYP( int getnct, (char *, int, FILE *, int) );
+#endif /* NOICP */
+_PROTOTYP( VOID bgchk, (void) );
+_PROTOTYP( char * nvlook, (char *) );
+_PROTOTYP( int xarray, (char *) );
+_PROTOTYP( int arraynam, (char *, int *, int *) );
+_PROTOTYP( int arraybounds, (char *, int *, int *) );
+_PROTOTYP( int boundspair, (char *, char *, int *, int *, char *) );
+_PROTOTYP( int arrayitoa, (int) );
+_PROTOTYP( int arrayatoi, (int) );
+_PROTOTYP( char * bldlen, (char *, char *) );
+_PROTOTYP( int chkarray, (int, int) );
+_PROTOTYP( int dclarray, (char, int) );
+_PROTOTYP( int pusharray, (int, int) );
+_PROTOTYP( int parsevar, (char *, int *, int *) );
+_PROTOTYP( int macini, (void) );
+_PROTOTYP( VOID initmac, (void) );
+_PROTOTYP( int delmac, (char *, int) );
+_PROTOTYP( int addmac, (char *, char *) );
+_PROTOTYP( int domac, (char *, char *, int) );
+_PROTOTYP( int addmmac, (char *, char *[]) );
+_PROTOTYP( int dobug, (void) );
+_PROTOTYP( int docd, (int) );
+_PROTOTYP( int doclslog, (int) );
+_PROTOTYP( int docmd, (int) );
+_PROTOTYP( int dodir, (int) );
+_PROTOTYP( int dodo, (int, char *, int) );
+_PROTOTYP( int doenable, (int, int) );
+_PROTOTYP( int dogoto, (char *, int) );
+_PROTOTYP( int dogta, (int) );
+_PROTOTYP( int dohlp, (int) );
+_PROTOTYP (int doincr, (int) );
+_PROTOTYP( int dohrmt, (int) );
+_PROTOTYP( int doif, (int) );
+_PROTOTYP( int doinput, (int, char *[], int[], int, int) );
+_PROTOTYP( int doreinp, (int, char *, int) );
+_PROTOTYP( int dolog, (int) );
+_PROTOTYP( int dologin, (char *) );
+_PROTOTYP( int doopen, (void) );
+_PROTOTYP( int doprm, (int, int) );
+_PROTOTYP( int doreturn, (char *) );
+_PROTOTYP( int dormt, (int) );
+_PROTOTYP( int dosort, (void) );
+_PROTOTYP( int dostat, (int) );
+_PROTOTYP( int dostop, (void) );
+_PROTOTYP( int dotype, (char *, int, int, int, char *, int, char *, int, int,
+ char *, int));
+_PROTOTYP( int transmit, (char *, char, int, int, int) );
+_PROTOTYP( int xlate, (char *, char *, int, int) );
+_PROTOTYP( int litcmd, (char **, char **, int) );
+_PROTOTYP( int incvar, (char *, CK_OFF_T, int) );
+_PROTOTYP( int ckdial, (char *, int, int, int, int) );
+_PROTOTYP( int hmsg, (char *) );
+_PROTOTYP( int hmsga, (char * []) );
+_PROTOTYP( int mlook, (struct mtab [], char *, int) );
+_PROTOTYP( int mxlook, (struct mtab [], char *, int) );
+_PROTOTYP( int mxxlook, (struct mtab [], char *, int) );
+_PROTOTYP( int prtopt, (int *, char *) );
+_PROTOTYP( CHAR rfilop, (char *, char) );
+_PROTOTYP( int setcc, (char *, int *) );
+_PROTOTYP( int setnum, (int *, int, int, int) );
+_PROTOTYP( int seton, (int *) );
+_PROTOTYP( int setonaut, (int *) );
+_PROTOTYP( VOID shmdmlin, (void) );
+_PROTOTYP( VOID initmdm, (int) );
+_PROTOTYP( char * showoff, (int) );
+_PROTOTYP( char * showooa, (int) );
+_PROTOTYP( char * showstring, (char *) );
+_PROTOTYP( int pktopn, (char *,int) );
+_PROTOTYP( int traopn, (char *,int) );
+_PROTOTYP( int sesopn, (char *,int) );
+_PROTOTYP( int debopn, (char *,int) );
+_PROTOTYP( int diaopn, (char *,int,int) );
+_PROTOTYP( int prepop, (void) );
+_PROTOTYP( int popclvl, (void) );
+_PROTOTYP( int varval, (char *, CK_OFF_T *) );
+_PROTOTYP( char * evala, (char *) );
+_PROTOTYP( char * evalx, (char *) );
+_PROTOTYP( int setalarm, (long) );
+_PROTOTYP( int setat, (int) );
+_PROTOTYP( int setinp, (void) );
+_PROTOTYP( VOID dolognet, (void) );
+_PROTOTYP( VOID dologline, (void) );
+_PROTOTYP( int setlin, (int, int, int) );
+_PROTOTYP( int setmodem, (void) );
+_PROTOTYP( int setfil, (int) );
+_PROTOTYP( char * homepath, (void) );
+#ifdef OS2
+_PROTOTYP( int settapi, (void) ) ;
+#ifdef OS2MOUSE
+_PROTOTYP( int setmou, (void) );
+#endif /* OS2MOUSE */
+#endif /* OS2 */
+#ifdef LOCUS
+_PROTOTYP( VOID setlocus, (int,int) );
+_PROTOTYP( VOID setautolocus, (int) );
+#endif /* LOCUS */
+_PROTOTYP( int setbell, (void) );
+_PROTOTYP( VOID setcmask, (int));
+_PROTOTYP( VOID setautodl, (int,int));
+_PROTOTYP( VOID setdebses, (int));
+_PROTOTYP( VOID setseslog, (int));
+_PROTOTYP( VOID setaprint, (int));
+_PROTOTYP( int settrm, (void) );
+_PROTOTYP( int settrmtyp, (void) );
+_PROTOTYP( int setsr, (int, int) );
+_PROTOTYP( int setxmit, (void) );
+_PROTOTYP( int dosetkey, (void) );
+_PROTOTYP( int dochk, (void) );
+_PROTOTYP( int ludial, (char *, int) );
+_PROTOTYP( char * getdnum, (int) );
+_PROTOTYP( VOID getnetenv, (void) );
+_PROTOTYP( int getyesno, (char *, int) );
+_PROTOTYP( VOID xwords, (char *, int, char *[], int) );
+#ifdef OS2
+_PROTOTYP( VOID keynaminit, (void) );
+#endif /* OS2 */
+_PROTOTYP( int xlookup, (struct keytab[], char *, int, int *) );
+_PROTOTYP( char * rlookup, (struct keytab[], int, int) );
+_PROTOTYP( int hupok, (int) );
+_PROTOTYP( char * zzndate, (void) );
+_PROTOTYP( char * zjdate, (char *) );
+_PROTOTYP( char * jzdate, (char *) );
+_PROTOTYP( char * ckdate, (void) );
+_PROTOTYP( char * chk_ac, (int, char[]) );
+_PROTOTYP( char * gmdmtyp, (void) );
+_PROTOTYP( char * gfmode, (int, int) );
+_PROTOTYP( int setdest, (void) );
+_PROTOTYP( VOID ndinit, (void) );
+_PROTOTYP( int doswitch, (void) );
+_PROTOTYP( int dolocal, (void) );
+_PROTOTYP( long tod2sec, (char *) );
+_PROTOTYP( int lunet, (char *) );
+_PROTOTYP( int doxdis, (int) );
+_PROTOTYP( int dosave, (int) );
+_PROTOTYP( int doxsend, (int) );
+_PROTOTYP( int doxget, (int) );
+_PROTOTYP( int doxconn, (int) );
+_PROTOTYP( int clsconnx, (int) );
+_PROTOTYP( VOID ftreset, (void) );
+#ifdef CK_KERBEROS
+_PROTOTYP (int cp_auth, ( void ) );
+#endif /* CK_KERBEROS */
+_PROTOTYP( long mjd, (char *) );
+_PROTOTYP( char * mjd2date, (long) );
+_PROTOTYP( char * ckgetpid, (void) );
+
+_PROTOTYP( int dogrep, (void) );
+
+#ifndef NOFTP
+#ifndef SYSFTP
+_PROTOTYP( int doxftp, (void) );
+_PROTOTYP( int doftphlp, (void) );
+_PROTOTYP( int dosetftp, (void) );
+_PROTOTYP( int dosetftphlp, (void) );
+_PROTOTYP( int shoftp, (int) );
+#endif /* SYSFTP */
+#endif /* NOFTP */
+
+_PROTOTYP( VOID cmhistory, (void) );
+_PROTOTYP( char * getdcset, (void) );
+_PROTOTYP( char * ttgtpn, (void) );
+
+#ifndef NOSHOW
+_PROTOTYP( int doshow, (int) );
+_PROTOTYP( int shotcp, (int) );
+_PROTOTYP( VOID shopar, (void) );
+_PROTOTYP( VOID shofil, (void) );
+_PROTOTYP( VOID shoparp, (void) );
+_PROTOTYP( int shoatt, (void) );
+_PROTOTYP( VOID shover, (void) );
+_PROTOTYP( VOID shoctl, (void) );
+_PROTOTYP( VOID shodbl, (void) );
+#ifndef NOSPL
+_PROTOTYP( int shomac, (char *, char *) );
+_PROTOTYP( int doshift, (int) );
+#endif /* NOSPL */
+#ifndef NOCSETS
+_PROTOTYP( VOID shocharset, (void) );
+_PROTOTYP( VOID shoparl, (void) );
+_PROTOTYP( VOID shotcs, (int, int) );
+#endif /* NOCSETS */
+#ifndef NOLOCAL
+_PROTOTYP( VOID shoparc, (void) );
+_PROTOTYP( int shomodem, (void) );
+#ifndef NODIAL
+_PROTOTYP( VOID shods, (char *) );
+_PROTOTYP( VOID shodial, (void) );
+_PROTOTYP( int doshodial, (void) );
+#endif /* NODIAL */
+#ifndef NONET
+_PROTOTYP( int shonet, (void) );
+_PROTOTYP( int shotopt, (int) );
+_PROTOTYP( int shotel, (int) );
+#ifdef CK_AUTHENTICATION
+_PROTOTYP (int sho_auth,( int ) );
+#endif /* CK_AUTHENTICATION */
+#endif /* NONET */
+_PROTOTYP( VOID shomdm, (void) );
+#endif /* NOLOCAL */
+#ifdef OS2
+_PROTOTYP( VOID shokeycode, (int,int) );
+#else
+_PROTOTYP( VOID shokeycode, (int) );
+#endif /* OS2 */
+_PROTOTYP( VOID showassoc, (void) );
+_PROTOTYP( VOID showdiropts, (void) );
+_PROTOTYP( VOID showdelopts, (void) );
+_PROTOTYP( VOID showtypopts, (void) );
+_PROTOTYP( VOID showpurgopts, (void) );
+_PROTOTYP( VOID shoflow, (void) );
+_PROTOTYP( VOID shoxfer, (void) );
+#ifdef ANYSSH
+_PROTOTYP( VOID shossh, (void) );
+#endif /* ANYSSH */
+#endif /* NOSHOW */
+
+_PROTOTYP( VOID shostrdef, (CHAR *) );
+
+#ifndef NOSPL
+_PROTOTYP( int addlocal, (char *) );
+#endif /* NOSPL */
+
+_PROTOTYP( int setdelopts, (void) );
+
+#ifdef VMS
+_PROTOTYP( int cvtdir, (char *, char *, int) );
+#endif /* VMS */
+
+#ifdef FNFLOAT
+_PROTOTYP( VOID initfloat, (void) );
+#endif /* FNFLOAT */
+
+#ifdef CKCHANNELIO
+_PROTOTYP( int dofile, (int) );
+#endif /* CKCHANNELIO */
+
+#ifdef CKROOT
+_PROTOTYP( int dochroot, (void) );
+#endif /* CKROOT */
+
+#ifdef NEWFTP
+_PROTOTYP( int doftpusr, (void) );
+_PROTOTYP( int doftpput, (int,int) );
+_PROTOTYP( int doftpget, (int,int) );
+_PROTOTYP( int doftprmt, (int,int) );
+_PROTOTYP( int ftpopen, (char *, char *, int) );
+_PROTOTYP( int cmdlinget, (int) );
+_PROTOTYP( int cmdlinput, (int) );
+_PROTOTYP( int doftparg, (char) );
+_PROTOTYP( int doftpacct, (void) );
+_PROTOTYP( int doftpsite, (void) );
+_PROTOTYP( int dosetftppsv, (void) );
+_PROTOTYP( int ftpbye, (void) );
+#endif /* NEWFTP */
+
+#ifdef COMMENT
+/* These prototypes are no longer used */
+_PROTOTYP( char * getdws, (int) );
+_PROTOTYP( char * getdcs, (int) );
+_PROTOTYP( int doget, (int) );
+_PROTOTYP( char * arrayval, (int, int) );
+#endif /* COMMENT */
+
+#ifdef KUI
+_PROTOTYP(int BuildFontTable,
+ (struct keytab ** pTable, struct keytab ** pTable2, int * pN));
+#endif /* KUI */
+
+_PROTOTYP(int cx_net, (int net, int protocol, char * xhost, char * svc,
+ char * username, char * password, char * command,
+ int param1, int param2, int param3,
+ int cx, int sx, int flag, int gui));
+_PROTOTYP(int cx_serial, (char *device,
+ int cx, int sx, int shr, int flag, int gui, int special));
+
+#endif /* CKUUSR_H */
+
+/* End of ckuusr.h */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c
new file mode 100644
index 0000000..4c464f7
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c
@@ -0,0 +1,9721 @@
+#include "ckcsym.h"
+
+/* C K U U S X -- "User Interface" common functions. */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ This module contains user interface functions needed by both the interactive
+ user interface and the command-line-only user interface, as well as the
+ screen-control routines (curses and equivalent).
+*/
+
+/* Includes */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+
+#ifndef NOHTERMCAP
+#ifdef NOTERMCAP
+#define NOHTERMCAP
+#else
+#ifndef BSD44
+#define NOHTERMCAP
+#else
+#ifdef __bsdi__
+#define NOHTERMCAP
+#else
+#ifdef OPENBSD
+#define NOHTERMCAP
+#else
+#ifdef MACOSX
+#define NOHTERMCAP
+#endif /* MACOSX */
+#endif /* OPENBSD */
+#endif /* __bsdi__ */
+#endif /* BSD44 */
+#endif /* NOTERMCAP */
+#endif /* NOHTERMCAP */
+
+#ifndef NOTERMCAP
+#ifdef BSD44
+#ifndef NOHTERMCAP
+#include <termcap.h>
+#endif /* NOHTERMCAP */
+#endif /* BSD44 */
+#else /* !BSD44 */
+#ifdef linux
+#include <term.h>
+#endif /* linux */
+#endif /* NOTERMCAP */
+
+#ifdef OS2
+#include <string.h>
+_PROTOTYP(char * os2_gethostname, (void));
+#define getpid _getpid
+#endif /* OS2 */
+#ifdef BSD44
+#include <errno.h>
+#endif /* BSD44 */
+
+extern xx_strp xxstring;
+
+#ifdef OS2
+#include "ckcnet.h"
+#else /* OS2 */
+_PROTOTYP( char * ckgetpeer, (VOID));
+_PROTOTYP(int getlocalipaddr, (void));
+_PROTOTYP(int istncomport, (void));
+#ifndef NOCKGETFQHOST
+_PROTOTYP( char * ckgetfqhostname,(char *));
+#endif /* NOCKGETFQHOST */
+#ifndef NETCONN
+/*
+ We should just pull in ckcnet.h here, but it causes a conflict with curses.h.
+*/
+#ifdef TCPSOCKET
+#define NETCONN
+#else
+#ifdef SUNX25
+#define NETCONN
+#else
+#ifdef STRATUSX25
+#define NETCONN
+#else
+#ifdef IBMX25
+#define NETCONN
+#else
+#ifdef HPX25
+#define NETCONN
+#else
+#ifdef DECNET
+#define NETCONN
+#else
+#ifdef NPIPE
+#define NETCONN
+#else
+#ifdef CK_NETBIOS
+#define NETCONN
+#ifdef SUPERLAT
+#define NETCONN
+#else
+#endif /* SUPERLAT */
+#endif /* TCPSOCKET */
+#endif /* SUNX25 */
+#endif /* STRATUSX25 */
+#endif /* IBMX25 */
+#endif /* HPX25 */
+#endif /* DECNET */
+#endif /* NPIPE */
+#endif /* CK_NETBIOS */
+#endif /* NETCONN */
+#endif /* OS2 */
+
+#ifndef TCPSOCKET
+#ifdef MULTINET
+#define TCPSOCKET
+#endif /* MULTINET */
+#ifdef DEC_TCPIP
+#define TCPSOCKET
+#endif /* DEC_TCPIP */
+#ifdef WINTCP
+#define TCPSOCKET
+#endif /* WINTCP */
+#ifdef TCPWARE
+#define TCPSOCKET
+#endif /* TCPWARE */
+#endif /* TCPSOCKET */
+
+#ifdef OS2
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#else /* NT */
+#define INCL_VIO
+#include <os2.h>
+#endif /* NT */
+#ifdef COMMENT /* Would you believe */
+#undef COMMENT /* <os2.h> defines this ? */
+#endif /* COMMENT */
+#ifdef CK_NETBIOS
+#include "ckonbi.h"
+#endif /* CK_NETBIOS */
+
+#include "ckocon.h"
+extern ascreen commandscreen;
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#endif /* OS2 */
+
+#ifdef NT
+#include "cknwin.h"
+#endif /* NT */
+#ifdef OS2
+#include "ckowin.h"
+#include "ckosyn.h"
+#endif /* OS2 */
+
+#ifdef CK_TAPI
+extern int tttapi;
+extern int tapipass;
+#endif /* CK_TAPI */
+
+#ifdef CK_KERBEROS
+#include "ckuath.h"
+#endif /* CK_KERBEROS */
+
+#ifndef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+
+#ifdef VMS
+#include <descrip.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#ifndef OLD_VMS
+#include <lib$routines.h> /* Not for VAX C 2.3 */
+#else
+#include <libdef.h>
+#endif /* OLD_VMS */
+#ifdef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+#endif /* VMS */
+
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * popen, (char *, char *) );
+#endif /* DCLPOPEN */
+
+int tt_crd = 0; /* Carriage return display */
+int tt_lfd = 0; /* Linefeed display */
+int interrupted = 0; /* Interrupted from keyboard flag */
+int fxd_inited = 0; /* Fullscreen stuff initialized */
+
+#ifdef DEBUG
+char debfil[CKMAXPATH+1]; /* Debugging log file name */
+#endif /* DEBUG */
+
+#ifdef TLOG
+char trafil[CKMAXPATH+1]; /* Transaction log file name */
+#endif /* TLOG */
+
+char sesfil[CKMAXPATH+1]; /* Session log file name */
+
+#ifdef CKLOGDIAL
+char diafil[CKMAXPATH+1]; /* Connection log file name */
+char cxlogbuf[CXLOGBUFL+1]; /* Connection log record buffer */
+int cx_active = 0; /* Connection is active */
+extern int dialog;
+#endif /* CKLOGDIAL */
+
+#ifdef DYNAMIC
+static char *cmdstr = NULL; /* Place to build generic command */
+#else
+#ifdef pdp11
+static char cmdstr[256];
+#else
+static char cmdstr[4096];
+#endif /* pdp11 */
+#endif /* DYNAMIC */
+
+#ifndef NOMSEND
+char fspec[CMDBL+4]; /* Filename string for \v(filespec) */
+int fspeclen = CMDBL;
+#else
+char fspec[CKMAXPATH+4];
+int fspeclen = CKMAXPATH;
+#endif /* NOMSEND */
+
+char * rfspec = NULL; /* Received filespec: local */
+char * prfspec = NULL; /* Preliminary rfspec */
+char * sfspec = NULL; /* Sent filespec: local */
+char * psfspec = NULL; /* Preliminary sfspec */
+char * srfspec = NULL; /* Received filespec: remote */
+char * psrfspec = NULL; /* Preliminary srfspec */
+char * rrfspec = NULL; /* Sent filespec: remote */
+char * prrfspec = NULL; /* Preliminary rrfspec */
+
+int success = 1, /* Command success/failure flag */
+ cmdlvl = 0, /* Command level */
+ action = 0, /* Action selected on command line */
+ slogts = 0, /* Session-log timestamps on/off */
+ slognul = 0, /* Session-log null-terminated lines */
+#ifdef UNIX
+ sessft = XYFT_T, /* Session log file type */
+#else
+ sessft = XYFT_B, /* (text for UNIX binary for others) */
+#endif /* UNIX */
+ pflag = 1, /* Print prompt */
+ msgflg = 1; /* Print informational messages */
+
+extern int xaskmore, saveask; /* More-prompting */
+
+#ifdef CK_APC
+extern int apcactive;
+#endif /* CK_APC */
+/* External variables */
+
+extern int local, quiet, binary, network, what, parity, xitsta, escape,
+ tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc;
+
+extern int cmd_rows, cmd_cols, xcmdsrc;
+
+extern char cmdfil[];
+
+#ifdef VMS
+extern int batch;
+#endif /* VMS */
+
+#ifdef datageneral /* 2/12/92 ENH */
+#include <sysid.h>
+extern int con_reads_mt, conint_ch, conint_avl;
+#endif /* datageneral */
+
+extern long speed;
+
+extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
+
+#ifndef NOCSETS
+extern int fcharset, tcharset, xfrxla;
+extern struct csinfo fcsinfo[], tcsinfo[];
+#endif /* NOCSETS */
+
+#ifdef OS2
+extern unsigned char colorcmd;
+#endif /* OS2 */
+
+#ifdef NOXFER
+
+int fdispla = XYFD_N;
+
+#else /* NOXFER is not defined */
+
+#ifdef OS2 /* File transfer display type */
+int fdispla = XYFD_C; /* Curses (fullscreen) if we have it */
+#else
+#ifdef CK_CURSES
+int fdispla = XYFD_C;
+#else
+int fdispla = XYFD_S; /* Otherwise CRT */
+#endif /* CK_CURSES */
+#endif /* OS2 */
+
+extern struct ck_p ptab[];
+extern int protocol, xfrbel, xfrint;
+
+#ifdef STREAMING
+extern int streaming, streamok;
+#endif /* STREAMING */
+
+/* Used internally */
+
+#ifdef KUI
+_PROTOTYP( VOID screeng, (int, char, long, char *) );
+#endif /* KUI */
+_PROTOTYP( VOID screenc, (int, char, CK_OFF_T, char *) );
+
+
+#ifdef CK_CURSES
+#ifndef DYNAMIC
+static char xtrmbuf[TRMBUFL]; /* tgetent() buffer */
+char * trmbuf = xtrmbuf;
+#else
+char * trmbuf = NULL;
+#endif /* DYNAMIC */
+_PROTOTYP( static VOID dpyinit, (void) );
+_PROTOTYP( static long shocps, (int, CK_OFF_T, CK_OFF_T) );
+_PROTOTYP( static CK_OFF_T shoetl, (CK_OFF_T, long, CK_OFF_T, CK_OFF_T) );
+#endif /* CK_CURSES */
+
+static int ft_win = 0; /* Fullscreen file transfer display window is active */
+
+/* Variables declared here */
+
+static char * skreason[] = {
+ "", /* 0 */
+ "Remote file not older", /* SKP_DAT */
+ "Identical modification times", /* SKP_EQU */
+ "Type", /* SKP_TYP */
+ "Size", /* SKP_SIZ */
+ "Name collision", /* SKP_NAM */
+ "Exception List", /* SKP_EXL */
+ "Dot file", /* SKP_DOT */
+ "Backup file", /* SKP_BKU */
+ "Recovery not needed", /* SKP_RES */
+ "Access denied", /* SKP_ACC */
+ "Not a regular file", /* SKP_NRF */
+ "Simulated", /* SKP_SIM */
+ "Simulated - Remote file older", /* SKP_XUP */
+ "Simulated - No remote file", /* SKP_XNX */
+};
+static int nskreason = (sizeof(skreason) / sizeof(char *));
+
+char *
+gskreason(n) int n; {
+ return((n > 0 && n < nskreason) ? skreason[n] : "");
+}
+
+char pktfil[CKMAXPATH+1]; /* Packet log file name */
+
+#ifndef NOMSEND /* Multiple SEND */
+char *msfiles[MSENDMAX];
+#endif /* NOMSEND */
+
+#ifdef CK_TIMERS
+extern long rttdelay;
+extern int rttflg;
+#endif /* CK_TIMERS */
+extern int rcvtimo;
+
+#ifdef CK_RESEND
+extern int sendmode;
+extern CK_OFF_T sendstart, rs_len;
+#endif /* CK_RESEND */
+
+#ifdef CK_PCT_BAR /* File transfer thermometer */
+int thermometer = 1; /* ON by default */
+#endif /* CK_PCT_BAR */
+
+#ifdef GFTIMER
+CKFLOAT gtv = -1.0, oldgtv = -1.0;
+#else
+#ifndef OS2
+static
+#endif /* OS2 */
+ long gtv = -1L, oldgtv = -1L;
+#endif /* GFTIMER */
+
+extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen,
+ winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu,
+ swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs,
+ pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl,
+ retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts,
+ rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive;
+
+extern long filcnt, filrej, rptn, filcps, tfcps, cps, peakcps;
+extern CK_OFF_T ffc, tfc, fsize;
+
+long oldcps = 0L;
+
+extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg;
+extern char *xfrmsg;
+
+#ifdef IKSDB
+FILE * dbfp = NULL; /* File pointer to database file */
+
+int dbenabled = 1; /* Flag for database is enabled */
+extern int ikdbopen; /* Flag for database is open */
+
+unsigned long mydbseek = 0L; /* Seek pointer to my record */
+int mydbslot = 0; /* My slot number */
+unsigned long myflags = 0L; /* My flags */
+unsigned long myatype = 0L; /* My authorization type */
+unsigned long myamode = 0L; /* My authorization mode */
+unsigned long mystate = 0L; /* My state (SEND, RECEIVE, etc) */
+unsigned long mypid = 0L; /* My PID */
+unsigned long myip = 0L; /* My IP address */
+unsigned long peerip = 0L; /* My peer's IP address */
+
+unsigned long dbip = 0L; /* IP address in db record */
+unsigned long dbpid = 0L; /* PID in db record */
+unsigned long dbflags = 0L; /* Flags field in db record */
+unsigned long dblastused = 0L; /* Last in-use record in db */
+char dbrec[DB_RECL]; /* Database record buffer */
+
+char * dbdir = NULL; /* Database directory */
+char * dbfile = NULL; /* Database file full pathname */
+char myhexip[33] = { NUL, NUL }; /* My IP address in hex */
+char peerhexip[33] = { NUL, NUL }; /* Client's IP address in hex */
+#endif /* IKSDB */
+
+#ifdef GFTIMER
+extern CKFLOAT fpfsecs, fptsecs, fpxfsecs;
+#else
+extern long xfsecs;
+#endif /* GFTIMER */
+#endif /* NOXFER */
+
+#ifdef TCPSOCKET
+#ifdef NEWFTP
+extern char * ftp_host, ftp_srvtyp[];
+extern int ftp_csx, ftp_csl, ftp_deb;
+#endif /* NEWFTP */
+extern char myipaddr[];
+#endif /* TCPSOCKET */
+
+#ifndef NOICP
+#ifndef NOSPL
+ extern struct mtab *mactab; /* For ON_EXIT macro. */
+ extern int nmac;
+#endif /* NOSPL */
+#ifdef DCMDBUF
+extern char *cmdbuf; /* Command buffer */
+#else
+extern char cmdbuf[]; /* Command buffer */
+#endif /* DCMDBUF */
+extern int cmd_quoting;
+#endif /* NOICP */
+
+#ifndef NOCCTRAP
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcsig.h"
+extern ckjmpbuf cmjbuf;
+#endif /* NOCCTRAP */
+
+extern int xfiletype, nscanfile;
+
+int
+shoesc(escape) int escape; {
+ extern char * ccntab[]; /* C0 control character name table */
+ extern int tt_escape;
+ if ((escape > 0 && escape < 32) || (escape == 127)) {
+ printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n",
+ ctl(escape),
+ escape,
+ (escape == 127 ? "DEL" : ccntab[escape]),
+ tt_escape ? "enabled" : "disabled"
+ );
+ } else {
+ printf(" Escape character: Code %d",escape);
+ if (escape > 160 && escape < 256)
+ printf(" (%c)",escape);
+ printf(": %s\r\n", tt_escape ? "enabled" : "disabled");
+ }
+ return(0);
+}
+
+#ifndef NOXFER
+/* P R E S E T -- Reset global protocol variables */
+
+extern int recursive;
+
+#ifdef PATTERNS
+int patterns = SET_AUTO; /* Whether to use filename patterns */
+extern int g_patterns; /* For saving and restoring */
+#else
+int patterns = SET_OFF;
+#endif /* PATTERNS */
+
+#ifndef NOICP
+#ifdef CK_LABELED
+extern int g_lf_opts, lf_opts;
+#endif /* CK_LABELED */
+extern int g_matchdot, g_usepipes, usepipes;
+extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv;
+extern int g_recursive;
+extern int g_xfermode, xfermode;
+extern int g_urpsiz, g_spsizf, g_spsiz;
+extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact;
+extern int g_fnspath, g_fnrpath, g_skipbup;
+extern int nolinks;
+#ifdef CKSYMLINK
+extern int zgfs_link;
+#endif /* CKSYMLINK */
+#ifndef NOSPL
+extern int g_pflg, pwflg, g_pcpt, pwcrypt;
+extern char * g_pswd, pwbuf[];
+#endif /* NOSPL */
+#endif /* NOICP */
+
+extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath;
+extern int moving; /* SEND criteria */
+extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[];
+extern CK_OFF_T sndlarger, sndsmaller, calibrate;
+extern int rmailf, rprintf, skipbup;
+extern char optbuf[];
+
+#ifdef PIPESEND
+extern char * g_sfilter, * g_rfilter;
+extern char * sndfilter, * rcvfilter;
+#endif /* PIPESEND */
+extern char ** sndarray;
+
+VOID
+ftreset() {
+#ifndef NOICP
+ int i;
+ extern char * filefile;
+ extern int reliable, xreliable, c_save, ss_save, slostart, urclear;
+ extern int oopts, omode, oname, opath, kactive, autopath;
+ extern char * snd_move; /* Directory to move sent files to */
+ extern char * snd_rename; /* What to rename sent files to */
+ extern char * rcv_move;
+ extern char * rcv_rename;
+ extern char * g_snd_move;
+ extern char * g_snd_rename;
+ extern char * g_rcv_move;
+ extern char * g_rcv_rename;
+
+#ifdef CK_TMPDIR
+ extern int f_tmpdir;
+ extern char savdir[];
+#endif /* CK_TMPDIR */
+
+#ifdef CK_SPEED
+#ifdef COMMENT
+ extern int f_ctlp;
+ extern short s_ctlp[], ctlp[];
+#endif /* COMMENT */
+#endif /* CK_SPEED */
+
+#ifndef NOCSETS
+ extern int fcs_save, tcs_save;
+ extern int g_xfrxla, xfrxla;
+#endif /* NOCSETS */
+
+/* Restore / reset per-command file-transfer switches */
+
+ makestr(&snd_move,g_snd_move);
+ makestr(&rcv_move,g_rcv_move);
+ makestr(&snd_rename,g_snd_rename);
+ makestr(&rcv_rename,g_rcv_rename);
+
+ kactive = 0; /* Kermit protocol no longer active */
+ oopts = -1; /* O-Packet Options */
+ omode = -1; /* O-Packet Transfer Mode */
+ oname = -1; /* O-Packet Filename Options */
+ opath = -1; /* O-Packet Pathname Options */
+
+#ifdef CK_RESEND
+ rs_len = 0L; /* REGET position */
+#endif /* CK_RESEND */
+
+#ifdef COMMENT
+#ifdef CK_SPEED
+ if (f_ctlp) {
+ for (i = 0; i < 256; i++)
+ ctlp[i] = s_ctlp[i];
+ f_ctlp = 0;
+ }
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+
+#ifdef CK_TMPDIR
+ if (f_tmpdir) { /* If we changed to download dir */
+ zchdir((char *) savdir); /* Go back where we came from */
+ f_tmpdir = 0;
+ }
+#endif /* CK_TMPDIR */
+
+ calibrate = 0L; /* Calibration run */
+ if (xreliable > -1) {
+ reliable = xreliable;
+ debug(F101,"ftreset reliable","",reliable);
+ }
+ urclear = 0;
+
+ if (autopath) { /* SET RECEIVE PATHNAMES AUTO */
+ fnrpath = PATH_AUTO;
+ autopath = 0;
+ }
+ if (filefile) { /* File list */
+ zclose(ZMFILE);
+ makestr(&filefile,NULL);
+ }
+ if (c_save > -1) { /* Block Check Type */
+ bctr = c_save;
+ c_save = -1;
+ }
+ if (ss_save > -1) { /* Slow Start */
+ slostart = ss_save;
+ ss_save = -1;
+ }
+#ifdef CK_LABELED
+ if (g_lf_opts > -1) {
+ lf_opts = g_lf_opts; /* Restore labeled transfer options */
+ g_lf_opts = -1;
+ }
+#endif /* CK_LABELED */
+
+#ifndef NOCSETS
+ if (tcs_save > -1) { /* Character sets */
+ tcharset = tcs_save;
+ tcs_save = -1;
+ }
+ if (fcs_save > -1) {
+ fcharset = fcs_save;
+ fcs_save = -1;
+ }
+ if (g_xfrxla > -1) {
+ xfrxla = g_xfrxla;
+ g_xfrxla = -1;
+ }
+ setxlatype(tcharset,fcharset); /* Translation type */
+#endif /* NOCSETS */
+
+#ifdef NETCONN
+#ifndef NOSPL
+ if (g_pswd) {
+ ckstrncpy(pwbuf,g_pswd,PWBUFL);
+ makestr(&g_pswd,NULL);
+ }
+ if (g_pflg > -1) {
+ pwflg = g_pflg;
+ g_pflg = -1;
+ }
+ if (g_pcpt > -1) {
+ pwcrypt = g_pcpt;
+ g_pcpt = -1;
+ }
+#endif /* NOSPL */
+#endif /* NETCONN */
+
+ if (g_binary > -1) { /* File type */
+ binary = g_binary;
+ g_binary = -1;
+ }
+ if (g_xfermode > -1) { /* Transfer mode */
+ xfermode = g_xfermode;
+ g_xfermode = -1;
+ }
+#ifdef PATTERNS
+ if (g_patterns > -1) { /* Filename patterns */
+ patterns = g_patterns;
+ g_patterns = -1;
+ }
+#endif /* PATTERNS */
+
+ if (g_usepipes > -1) {
+ usepipes = g_usepipes;
+ g_usepipes = -1;
+ }
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot;
+ g_matchdot = -1;
+ }
+ if (g_proto > -1) { /* Protocol */
+ protocol = g_proto;
+ g_proto = -1;
+ }
+ if (g_urpsiz > -1) {
+ urpsiz = g_urpsiz;
+ debug(F101,"ftreset restoring urpsiz","",urpsiz);
+ g_urpsiz = -1;
+ }
+ if (g_spsizf > -1) {
+ spsizf = g_spsizf;
+ debug(F101,"ftreset restoring spsizf","",spsizf);
+ g_spsizf = -1;
+ }
+ if (g_spsiz > -1) {
+ spsiz = g_spsiz;
+ debug(F101,"ftreset restoring spsiz","",spsiz);
+ g_spsiz = -1;
+ }
+ if (g_spsizr > -1) {
+ spsizr = g_spsizr;
+ debug(F101,"ftreset restoring spsizr","",spsizr);
+ g_spsizr = -1;
+ }
+ if (g_spmax > -1) {
+ spmax = g_spmax;
+ g_spmax = -1;
+ }
+ if (g_wslotr > -1) {
+ wslotr = g_wslotr;
+ g_wslotr = -1;
+ }
+ if (g_prefixing > -1) {
+ prefixing = g_prefixing;
+ g_prefixing = -1;
+ }
+ if (g_fncact > -1) {
+ fncact = g_fncact;
+ g_fncact = -1;
+ }
+ if (g_fncnv > -1) {
+ fncnv = g_fncnv;
+ g_fncnv = -1;
+ }
+ if (g_fnspath > -1) {
+ fnspath = g_fnspath;
+ g_fnspath = -1;
+ }
+ if (g_fnrpath > -1) {
+ fnrpath = g_fnrpath;
+ g_fnrpath = -1;
+ }
+ if (g_skipbup > -1) {
+ skipbup = g_skipbup;
+ g_skipbup = -1;
+ }
+ nolinks = 2; /* /FOLLOWLINKS is never global */
+ recursive = 0; /* /RECURSIVE can never be global */
+ xfiletype = -1;
+
+ if (g_displa > -1) { /* File transfer display */
+ fdispla = g_displa;
+ g_displa = -1;
+ }
+ if (g_spath > -1) { /* Send pathnames */
+ fnspath = g_spath;
+ g_spath = -1;
+ }
+ if (g_rpath > -1) { /* Receive pathnames */
+ fnrpath = g_rpath;
+ g_rpath = -1;
+ }
+ if (g_fncnv > -1) { /* Filename conversion */
+ fncnv = g_fncnv;
+ g_fncnv = -1;
+ }
+#ifdef PIPESEND
+ makestr(&sndfilter,g_sfilter); /* Send filter */
+ makestr(&rcvfilter,g_rfilter); /* Receive filter */
+#endif /* PIPESEND */
+
+#ifndef NOFRILLS
+ rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */
+ optbuf[0] = NUL; /* MAIL and PRINT options */
+#endif /* NOFRILLS */
+
+ moving = 0; /* Reset delete-after-send indicator */
+ sndafter[0] = NUL; /* Reset SEND selection switches */
+ sndbefore[0] = NUL;
+
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ if (sndexcept[i])
+ free(sndexcept[i]);
+ sndexcept[i] = NULL;
+ if (rcvexcept[i])
+ free(rcvexcept[i]);
+ rcvexcept[i] = NULL;
+ }
+ sndlarger = (CK_OFF_T)-1;
+ sndsmaller = (CK_OFF_T)-1;
+ debug(F101,"present sndsmaller","",sndsmaller);
+#ifdef GFTIMER
+ gtv = -1.0;
+ oldgtv = -1.0;
+#else
+ gtv = -1L;
+ oldgtv = -1L;
+#endif /* GFTIMER */
+#endif /* NOICP */
+}
+#endif /* NOXFER */
+
+char *
+ttgtpn() { /* Get typical port name */
+/*
+ Ideally this routine would be implemented in each of the cku?io.* modules,
+ but that requires changing the API definition.
+*/
+ return(
+#ifdef OS2
+#ifdef OS2ONLY
+"COM1"
+#else /* OS2ONLY */
+"TAPI [ name ] or COM1"
+#endif /* OS2ONLY */
+#else /* OS2 */
+#ifdef VMS
+"TXA0:, TTA0:, or LTA0:"
+#else /* VMS */
+#ifdef SOLARIS
+"/dev/cua/a"
+#else /* SOLARIS */
+#ifdef HPUX10
+"/dev/cua0p0"
+#else /* HPUX10 */
+#ifdef HPUX
+"/dev/cua00"
+#else /* HPUX */
+#ifdef __FreeBSD__
+"/dev/cuaa0"
+#else /* __FreeBSD__ */
+#ifdef __linux__
+"/dev/ttyS0"
+#else /* __linux__ */
+#ifdef BSD44
+"/dev/tty00"
+#else /* BSD44 */
+#ifdef OSK
+"/t1"
+#else /* OSK */
+#ifdef QNX
+"/dev/ser1"
+#else /* QNX */
+#ifdef QNX6
+"/dev/ser1"
+#else /* QNX6 */
+#ifdef UNIXWARE
+"/dev/term/00 or /dev/tty00"
+#else /* UNIXWARE */
+#ifdef CK_SCOV5
+"/dev/tty1A"
+#else /* CK_SCOV5 */
+#ifdef CK_SCO32V4
+"/dev/tty1A"
+#else /* CK_SCO32V4 */
+#ifdef M_XENIX
+"/dev/tty1A"
+#else /* M_XENIX */
+#ifdef AIXRS
+"/dev/tty0"
+#else /* AIXRS */
+#ifdef DGUX
+"/dev/tty00"
+#else /* DGUX */
+#ifdef datageneral
+"@con1"
+#else /* datageneral */
+#ifdef IRIX
+"/dev/ttym0"
+#else /* IRIX */
+#ifdef SUNOS4
+"/dev/ttyh0"
+#else /* SUNOS4 */
+#ifdef SV68R3V6
+"/dev/scc0"
+#else /* SV68R3V6 */
+#ifdef MOTSV88R4
+"/dev/contty00"
+#else /* MOTSV88R4 */
+#ifdef NEXT
+"/dev/cufa"
+#else
+#ifdef OSF
+"/dev/ttyd1"
+#else
+#ifdef SINIX
+"/dev/ttyc1"
+#else
+#ifdef UNIX
+"/dev/cua, /dev/acu, /dev/tty0, etc"
+#else /* UNIX */
+"(sorry no example available)"
+#endif /* UNIX */
+#endif /* SINIX */
+#endif /* OSF */
+#endif /* NEXT */
+#endif /* MOTSV88R4 */
+#endif /* SV68R3V6 */
+#endif /* SUNOS4 */
+#endif /* IRIX */
+#endif /* datageneral */
+#endif /* DGUX */
+#endif /* AIX */
+#endif /* M_XENIX */
+#endif /* CK_SCO32V4 */
+#endif /* CK_SCOV5 */
+#endif /* UNIXWARE */
+#endif /* QNX6 */
+#endif /* QNX */
+#endif /* OSK */
+#endif /* BSD44 */
+#endif /* __linux__ */
+#endif /* __FreeBSD__ */
+#endif /* HPUX */
+#endif /* HPUX10 */
+#endif /* SOLARIS */
+#endif /* VMS */
+#endif /* OS2 */
+ );
+}
+
+/* C K _ E R R S T R -- Return message from most recent system error */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+char *
+ck_errstr() {
+#ifdef USE_STRERROR
+#ifndef CK_ANSILIBS
+ /* Should have been declared in <string.h> */
+_PROTOTYP( char * strerror, (int) );
+#endif /* CK_ANSILIBS */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ return(strerror(errno));
+#else /* !USE_STRERROR */
+#ifdef VMS
+ extern char * ckvmserrstr(unsigned long);
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ return(ckvmserrstr(0L));
+#else /* !VMS */
+#ifdef BSD44
+#ifdef __386BSD__
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#else /* !__386BSD__ */
+#ifndef __bsdi__
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern const char *const sys_errlist[];
+#endif /* NDSYSERRLIST */
+#endif /* __bsdi__ */
+#endif /* __386BSD__ */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else /* !BSD44 */
+#ifdef ATTSV
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else /* !ATTSV */
+#ifdef BSD4
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else
+#ifdef OS2
+#ifndef NDSYSERRLIST
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef NT
+ extern int_sys_nerr;
+#endif /* NT */
+ char *e;
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ e = (errno > -1
+#ifdef NT
+ && errno <= _sys_nerr
+#endif /* NT */
+ ) ?
+#ifdef NT
+ (char *) sys_errlist[errno]
+#else /* NT */
+ /* I don't know how to get a CLIB error string in OS/2 */
+ strerror(errno)
+#endif /* NT */
+ : "";
+ return(e ? e : "");
+#else /* OS2 */
+ return("");
+#endif /* OS2 */
+#endif /* BSD4 */
+#endif /* ATTSV */
+#endif /* BSD44 */
+#endif /* VMS */
+#endif /* USE_STRERROR */
+}
+
+#ifdef PATTERNS
+/*
+ Filename pattern recognition lists for automatic text/binary switching.
+ These are somewhat passe after the addition of scanfile() (7.0).
+ But with the addition of FTP [M]GET, they're back in style (8.0).
+
+ Although, with FTP the lists need to be used in the reverse. With
+ Kermit the list is used to imply the types of the local system. Whereas
+ with FTP, the list must be used to imply the type of the remote system.
+ Therefore, all platforms must now support all of the lists.
+*/
+char *txtpatterns[FTPATTERNS+1] = { NULL, NULL };
+char *binpatterns[FTPATTERNS+1] = { NULL, NULL };
+/*
+ Default pattern lists for each platform...
+
+ NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they
+ are traditionally text types, they are binary in Windows. So they are
+ handled by the prevailing SET FILE TYPE, rather than automatically.
+ Similarly for ".dat", ".inf", and so on. Also ".ps" since PostScript files
+ are not always text. ".log" is omitted since logs can be text or binary,
+ except in VMS they are usually text, etc etc.
+
+ Later (Sep 2003): Add PostScript to binary patterns.
+*/
+static char *txtp[SYS_MAX][FTPATTERNS] = {
+ /* UNKNOWN */ {
+ NULL, NULL
+ },
+ { /* UNIX */
+ "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd",
+ "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx",
+ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh",
+ "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed",
+ "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac",
+ NULL
+ },
+ { /* WIN32 */
+ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
+ "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL
+ },
+ { /* VMS */
+ "*.com","*.txt","*.c", "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli",
+ "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log",
+ "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt",
+ "*.mem",NULL
+ },
+ { /* OS2 */
+ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
+ NULL
+ },
+ { /* DOS */
+ "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL
+ },
+ { /* TOPS-10 */
+ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
+ "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
+ "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
+ },
+ { /* TOPS-20 */
+ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
+ "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
+ "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
+ },
+ { /* STRATUS VOS */
+ "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex",
+ "*.hqx","*.c", "*.h", "*.w", "*.java","*.bwr","*.upd","*.ttp","*.cm",
+ "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL
+ },
+ { /* DG AOS/VS */
+ "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me",
+ "*.cli", "*.ksc", NULL
+ },
+ { /* OSK */
+ "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */
+ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp",
+ "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed",
+ "*.txt","*.w", /* general text */
+ "*.ksc","*.bwr","*.upd",
+ "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx",
+ "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*",
+ NULL
+ }
+};
+
+/* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */
+
+static char *binp[SYS_MAX][FTPATTERNS] = {
+ { /* UNKNOWN */
+ NULL, NULL
+ },
+ { /* UNIX */
+ "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out",
+ "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class",
+ "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx",
+ "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit",
+ "*.ps", NULL
+ },
+ { /* WIN32 */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg",
+ "*.ps", NULL
+ },
+ { /* VMS */
+ "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp",
+ "*.ps", "*.dat","*.par", NULL
+ },
+ { /* OS2 */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", NULL
+ },
+ { /* DOS */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", NULL
+ },
+ { /* TOPS10 */
+ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
+ "*.ps", NULL
+ },
+ { /* TOPS20 */
+ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
+ "*.ps", NULL
+ },
+ { /* STRATUS VOS */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", "*.pm", NULL
+ },
+ { /* DG */
+ "*.ob", "*.pr", "*.dmp", "*.ps", NULL
+ },
+ { /* OSK */
+ "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */
+ "*.zip","*.ar","*.zoo","*.rpm","*.lzh",
+ /* object files, libraries, executables */
+ "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class",
+ /* images */
+ "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps",
+ "*.bmp", "*.bz2", "*.BMP","*.pcx",
+ NULL
+ }
+};
+
+/*
+ Set up default pattern lists so they can be freed and re-malloc'd.
+ Each pattern list must terminated by a null element.
+*/
+VOID
+initpat() {
+ int i;
+ for (i = 0; i < FTPATTERNS; i++) {
+ txtpatterns[i] = NULL;
+ binpatterns[i] = NULL;
+ }
+ for (i = 0; i < FTPATTERNS; i++) {
+#ifdef UNIX
+ makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]);
+#else /* UNIX */
+#ifdef OS2
+#ifdef NT
+ makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]);
+#else /* NT */
+ makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]);
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+ makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]);
+#else /* VMS */
+#ifdef STRATUS
+ makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]);
+#else /* STRATUS */
+#ifdef datageneral
+ makestr(&(txtpatterns[i]),txtp[SYS_DG][i]);
+#else /* datageneral */
+#ifdef OSK
+ makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]);
+#else /* OSK */
+ makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]);
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+ if (!txtp[i])
+ break;
+ }
+ for (i = 0; i < FTPATTERNS; i++) {
+#ifdef UNIX
+ makestr(&(binpatterns[i]),binp[SYS_UNIX][i]);
+#else /* UNIX */
+#ifdef OS2
+#ifdef NT
+ makestr(&(binpatterns[i]),binp[SYS_WIN32][i]);
+#else /* NT */
+ makestr(&(binpatterns[i]),binp[SYS_OS2][i]);
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+ makestr(&(binpatterns[i]),binp[SYS_VMS][i]);
+#else /* VMS */
+#ifdef STRATUS
+ makestr(&(binpatterns[i]),binp[SYS_VOS][i]);
+#else /* STRATUS */
+#ifdef datageneral
+ makestr(&(binpatterns[i]),binp[SYS_DG][i]);
+#else /* datageneral */
+#ifdef OSK
+ makestr(&(binpatterns[i]),binp[SYS_OSK][i]);
+#else /* OSK */
+ makestr(&(binpatterns[i]),binp[SYS_UNK][i]);
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+ if (!binp[i])
+ break;
+ }
+}
+
+/*
+ m a t c h n a m e -- Compare filename with text & binary name patterns.
+
+ Returns:
+ 0 if name matches a text pattern but not a binary pattern.
+ 1 if name matches a binary pattern but not a text pattern.
+ -1 if name matches no patterns.
+ -2 if name matches a binary pattern and a text pattern.
+*/
+int
+matchname(filename, local, os) char * filename; int local; int os; {
+ int rc = -1; /* Return code */
+ char * name, * p;
+#ifdef OS2ORUNIX
+ char tmpbuf[CKMAXPATH+1];
+#endif /* OS2ORUNIX */
+
+ name = filename ? filename : ""; /* Copy of original arg */
+ if (patterns && *name) { /* If PATTERNS ON... */
+ int i;
+
+#ifdef OS2ORUNIX
+ if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */
+ int k;
+ k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */
+ for (i = k - 3; i > 4; i--) {
+ if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') {
+ tmpbuf[i-1] = NUL;
+ break;
+ }
+ }
+ name = tmpbuf; /* And point to stripped copy */
+ }
+#endif /* OS2ORUNIX */
+ zstrip(name,&p); /* Strip pathname too */
+ name = p;
+
+ if (local) {
+ if (txtpatterns[0]) { /* Search text patterns */
+ for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
+ if (ckmatch(txtpatterns[i],name,filecase,1)) {
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (binpatterns[0]) { /* And search binary patterns */
+ for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
+ if (ckmatch(binpatterns[i],name,filecase,1)) {
+ rc = (rc > -1) ? -2 : 1;
+ break;
+ }
+ }
+ }
+ } else {
+ if (os >= 0 && os < SYS_MAX) {
+ if (txtp[os][0]) {
+ for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) {
+ if (ckmatch(txtp[os][i],name,filecase,1)) {
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (binp[os][0]) {
+ for (i = 0; i < FTPATTERNS && binp[os][i]; i++) {
+ if (ckmatch(binp[os][i],name,filecase,1)) {
+ rc = (rc > -1) ? -2 : 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ debug(F111,"matchname",name,rc);
+ return(rc);
+}
+#endif /* PATTERNS */
+
+#ifdef UNICODE
+#ifndef NOEVENMAX
+#define EVENMAX
+#endif /* NOEVENMAX */
+#endif /* UNICODE */
+
+/* S C A N F I L E -- Analyze a file's contents */
+
+/*
+ Call with:
+ name: Pointer to name of existing file.
+ flag: Pointer to int in which to return additional numeric data.
+
+ Returns:
+ -1 on failure (to open file or to read from it).
+ Integer, 0..4, on success indicating file type:
+ 0 = 7-bit text (flag = -1)
+ 1 = UTF-8 text (flag = -1)
+ 2 = UCS-2 text (flag = 0: big-endian; flag = 1: little-endian)
+ 3 = 8-bit text (flag = 0: no C1 bytes; flag = 1: includes C1 bytes)
+ 4 = Text (type unknown)
+ 5 = binary (flag = -1)
+
+ If UNICODE is defined:
+
+ 1. If file begins with a valid BOM, it is believed. Otherwise we
+ read the first 4K of the file (since it might be email with verbose
+ headers) and analyze it:
+
+ 2. If file contains only valid UTF-8 sequences, we call it UTF-8;
+ otherwise:
+
+ 3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and
+ set the polarity according to whether the preponderance of them are in
+ even or odd positions; otherwise:
+
+ 4. If EVENMAX is defined and the file contains lots of alternate bytes that
+ are identical, even if they aren't zero, and the number of such bytes
+ is at least four times the length of the maximum run of alternating
+ identical bytes of the opposite polarity, we call it UCS-2; otherwise:
+
+ 5. If the file contained no bytes with their 8th bits on and no controls
+ other than CR, LF, HT, and FF, we call it ASCII; otherwise:
+
+ 6. If it contains C0 control characters other than CR, LF, HT, and FF, we
+ call it binary; otherwise:
+
+ 7. We call it 8-bit text, character set unknown (could be Latin-1 or
+ anything else).
+
+ Note that malformed UTF-8 is not diagnosed as UTF-8.
+
+ If UNICODE is not defined:
+
+ 1. If the file contains C0 control characters other than CR, LF, HT, and
+ FF, we call it binary; otherwise:
+
+ 2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise:
+
+ 3. We call it 7-bit text.
+
+ In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as
+ 8-bit text.
+
+ There is no significant speed difference between the Unicode and
+ non-Unicode cases.
+*/
+int
+scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
+ FILE * fp; /* File pointer */
+ unsigned char buf[SCANFILEBUF]; /* File data buffer for analysis */
+ int x, val = -1, count = 0; /* Workers */
+ int rc = -1; /* Return code */
+ int pv = -1; /* Pattern-match value */
+ int eof = 0; /* Flag for file EOF encountered */
+ int bytes = 0; /* Total byte count */
+#ifdef UNICODE
+ unsigned int c0, c1; /* First 2 file bytes (for BOM) */
+#endif /* UNICODE */
+ extern int pipesend, filepeek;
+
+ register int i; /* Loop control */
+ int readsize = 0; /* How much to read */
+ int eightbit = 0; /* Number of bytes with 8th bit on */
+ int c0controls = 0; /* C0 non-text control-char counter */
+ int c0noniso = 0; /* C0 non-ISO control-char counter */
+ int c1controls = 0; /* C1 control-character counter */
+ unsigned int c; /* Current character */
+ int runmax = 0; /* Longest run of 0 bytes */
+ int runzero = 0; /* Run of 0 bytes */
+ int pctzero = 0; /* Percentage of 0 bytes */
+ int txtcz = 0;
+#ifdef CK_CTRLZ
+ extern int eofmethod;
+#endif /* CK_CTRLZ */
+
+#ifdef UNICODE
+ int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
+ int utf8state = 0; /* UTF-8 recognizer state */
+ int oddzero = 0; /* Number of 0 bytes in odd postions */
+ int evenzero = 0; /* and in even positions */
+ int lfnul = 0; /* Number of <LF><NUL> sequences */
+ int crlf = 0; /* Number of <CRLF> sequences */
+#else
+ int notutf8 = 1;
+#endif /* UNICODE */
+
+#ifdef COMMENT
+#ifdef EVENMAX
+ int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0;
+ int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0;
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+#ifndef NOXFER
+ if (pipesend || calibrate || sndarray) /* Only for real files */
+ return(-1);
+#endif /* NOXFER */
+ debug(F111,"scanfile",name,nscanfile);
+#ifdef PATTERNS
+ if (!filepeek) {
+ pv = matchname(name,1,-1);
+ if (pv < 0)
+ rc = -1;
+ else
+ rc = (pv == 1) ? FT_BIN : FT_TEXT;
+ debug(F111,"scanfile !filepeek result",name,rc);
+ return(rc);
+ }
+#endif /* PATTERNS */
+
+#ifdef VMS
+/* We don't scan in VMS where text files have various record formats in */
+/* which record headers contain seemingly non-text bytes. So the best */
+/* we can do in VMS is tell whether the file is text or binary, period. */
+ {
+ int b, x;
+ b = binary; /* Save current binary setting */
+ if (zopeni(ZIFILE,name) > 0) { /* In VMS this sets binary */
+ x = binary; /* Get result */
+ zclose(ZIFILE); /* Close the file */
+ binary = b; /* Restore previous binary setting */
+ rc = x ? FT_BIN : FT_TEXT;
+ val = 0;
+ goto xscanfile;
+ }
+ }
+#endif /* VMS */
+
+ eof = 0; /* End-of-file reached indicator */
+#ifdef OS2
+ fp = fopen(name, "rb"); /* Open the file in binary mode */
+#else
+ fp = fopen(name, "r");
+#endif /* OS2 */
+
+ if (!fp) /* Failed? */
+ return(-1);
+
+ while (1) { /* One or more gulps from file */
+ if (eof) { /* EOF from last time? */
+ debug(F111,"scanfile at EOF",name,bytes);
+ if (runzero > runmax)
+ runmax = runzero;
+ break;
+ }
+ if (nscanfile < 0) { /* Reading whole file */
+ readsize = SCANFILEBUF;
+ } else { /* Reading first nscanfilee bytes */
+ readsize = nscanfile - bytes;
+ if (readsize < 1)
+ break;
+ if (readsize > SCANFILEBUF)
+ readsize = SCANFILEBUF;
+ }
+ debug(F101,"scanfile readsize","",readsize);
+ count = fread(buf,1,readsize,fp); /* Read a buffer */
+ if (count == EOF || count == 0) {
+ debug(F111,"scanfile EOF",name,count);
+ break;
+ }
+ debug(F111,"scanfile buffer ok",name,count);
+
+ if (bytes == 0 && count > 8) {
+ /* PDF files can look like text in the beginning. */
+ if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) {
+ if (isdigit(buf[7])) {
+ if (buf[8] == '\015' ||
+ count > 9 && buf[8] == SP && buf[9] == '\015') {
+#ifdef DEBUG
+ buf[8] = NUL;
+ debug(F110,"scanfile PDF",buf,0);
+#endif /* DEBUG */
+ binary = 1; /* But they are binary. */
+ break;
+ }
+ }
+ } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) {
+ /* Ditto for PostScript */
+#ifdef DEBUG
+ int i;
+ for (i = 8; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PostScript",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+#ifndef NOPCLSCAN
+ } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) {
+ /* HP PCL printer language */
+#ifdef DEBUG
+ int i;
+ for (i = 8; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PCL",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+ }
+#endif /* NOPCLSCAN */
+#ifndef NOPJLSCAN
+ else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) {
+ /* Ditto for PJL Job printer header */
+#ifdef DEBUG
+ int i;
+ for (i = 2; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PJL Job printer header",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+#endif /* NOPJLSCAN */
+ }
+ }
+
+#ifdef UNICODE
+ if (bytes == 0 && count > 1) {
+ int incl_cnt = 0;
+
+ /* First look for BOM */
+
+ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
+ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
+
+ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
+ rc = FT_UCS2;
+ val = 0;
+ debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
+ rc = FT_UCS2;
+ val = 1;
+ debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
+ (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
+ rc = FT_UTF8;
+ debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc);
+ incl_cnt++;
+ }
+ if (incl_cnt) { /* Have BOM */
+ bytes += count;
+ goto xscanfile;
+ }
+ }
+#endif /* UNICODE */
+
+ bytes += count; /* Count bytes read */
+ eof = feof(fp); /* Flag for at EOF */
+
+ for (i = 0; i < count; i++) { /* For each byte... */
+ c = (unsigned)buf[i]; /* For ease of reference */
+ if (!c) { /* Zero byte? */
+#ifdef EVENMAX
+ if (i&1) /* In odd position */
+ oddzero++;
+ else
+ evenzero++; /* In even position */
+#endif /* EVENMAX */
+ runzero++;
+ } else { /* Not a zero byte */
+ if (runzero > runmax)
+ runmax = runzero;
+ if (runmax > 2) /* That's all we need to be certain */
+ break; /* it's a binary file. */
+ runzero = 0;
+ }
+
+#ifdef COMMENT
+#ifdef EVENMAX
+
+/* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire */
+
+ if (i > 1) { /* Look for runs of alternating chars */
+ if (i&1) {
+ if (c == buf[i-2]) { /* In odd positions */
+ oddrun++;
+ oddbyte = c;
+ } else {
+ oddmax = oddrun;
+ oddmaxbyte = oddbyte;
+ }
+ } else { /* and even positions */
+ if (c == buf[i-2]) {
+ evenrun++;
+ evenbyte = c;
+ } else {
+ evenmax = evenrun;
+ evenmaxbyte = evenbyte;
+ }
+ }
+ }
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+ if ((c & 0x80) == 0) { /* We have a 7-bit byte */
+#ifdef UNICODE
+ if (i > 0 && c == 10) { /* Linefeed */
+ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
+ else if (buf[i-1] == 13) crlf++; /* or by CR... */
+ }
+#endif /* UNICODE */
+ if (c < ' ') { /* Check for CO controls */
+ if (c != LF && c != CR && c != HT && c != FF) {
+ c0controls++;
+ if (c != ESC && c != SO && c != SI)
+ c0noniso++;
+ }
+ if ((c == '\032') /* Ctrl-Z */
+#ifdef COMMENT
+ && eof && (i >= count - 2)
+#endif /* COMMENT */
+ ) {
+ c0controls--;
+ c0noniso--;
+#ifdef CK_CTRLZ
+ if (eofmethod == XYEOF_Z && txtcz == 0) {
+ if (c0controls == 0) /* All text prior to Ctrl-Z */
+ txtcz = 1;
+ }
+#endif /* CK_CTRLZ */
+ }
+ }
+#ifdef UNICODE
+ if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
+ utf8state = 0;
+ debug(F000,"scanfile","7-bit byte in UTF8 sequence",c);
+ notutf8++; /* Then it's not UTF-8 */
+ continue;
+ }
+#endif /* UNICODE */
+ } else { /* We have an 8-bit byte */
+ eightbit++; /* Count it */
+ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
+ c1controls++;
+#ifdef UNICODE
+ if (!notutf8) { /* If it might still be UTF8... */
+ switch (utf8state) { /* Enter the UTF-8 state machine */
+ case 0: /* First byte... */
+ if ((c & 0xE0) == 0xC0) { /* Tells number of */
+ utf8state = 1; /* subsequent bytes */
+ } else if ((c & 0xF0) == 0xE0) {
+ utf8state = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ utf8state = 3;
+ } else {
+ notutf8++;
+ }
+ break;
+ case 1: /* Subsequent byte */
+ case 2:
+ case 3:
+ if ((c & 0xC0) != 0x80) { /* Must start with 10 */
+ debug(F000,"scanfile",
+ "bad byte in UTF8 sequence",c);
+ notutf8++;
+ break;
+ }
+ utf8state--; /* Good, one less in this sequence */
+ break;
+ default: /* Shouldn't happen */
+ debug(F111,"scanfile","bad UTF8 state",utf8state);
+ notutf8++;
+ }
+ }
+#endif /* UNICODE */
+ }
+ }
+ }
+ fclose(fp); /* Close the file */
+ debug(F101,"scanfile bytes","",bytes);
+
+ if (bytes == 0) /* If nothing was read */
+ return(-1); /* we're done. */
+
+#ifdef EVENMAX
+ /* In case we had a run that never broke... */
+#ifdef COMMENT
+ if (oddmax == 0) {
+ oddmax = oddrun;
+ oddmaxbyte = oddbyte;
+ }
+ if (evenmax == 0) {
+ evenmax = evenrun;
+ evenmaxbyte = evenbyte;
+ }
+#endif /* COMMENT */
+ if (runmax == 0) {
+ runmax = runzero;
+ }
+#endif /* EVENMAX */
+
+#ifdef UNICODE
+ if (bytes > 100) /* Bytes is not 0 */
+ pctzero = (evenzero + oddzero) / (bytes / 100);
+ else
+ pctzero = ((evenzero + oddzero) * 100) / bytes;
+#endif /* UNICODE */
+
+#ifdef DEBUG
+ if (deblog) { /* If debugging, dump statistics */
+ debug(F101,"scanfile c0controls ","",c0controls);
+ debug(F101,"scanfile c0noniso ","",c0noniso);
+ debug(F101,"scanfile c1controls ","",c1controls);
+ debug(F101,"scanfile eightbit ","",eightbit);
+#ifdef UNICODE
+ debug(F101,"scanfile crlf ","",crlf);
+ debug(F101,"scanfile lfnul ","",lfnul);
+ debug(F101,"scanfile notutf8 ","",notutf8);
+ debug(F101,"scanfile evenzero ","",evenzero);
+ debug(F101,"scanfile oddzero ","",oddzero);
+ debug(F101,"scanfile even/odd ","",(evenzero / (oddzero + 1)));
+ debug(F101,"scanfile odd/even ","",(oddzero / (evenzero + 1)));
+ debug(F101,"scanfile pctzero ","",pctzero);
+#endif /* UNICODE */
+#ifdef COMMENT
+#ifdef EVENMAX
+ debug(F101,"scanfile oddmax ","",oddmax);
+ debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte);
+ debug(F101,"scanfile evenmax ","",evenmax);
+ debug(F101,"scanfile evenmaxbyte","",evenmaxbyte);
+#endif /* EVENMAX */
+#endif /* COMMENT */
+ debug(F101,"scanfile runmax ","",runmax);
+ }
+#endif /* DEBUG */
+
+#ifdef UNICODE
+ x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
+
+ if (runmax > 2) { /* File has run of more than 2 NULs */
+ debug(F100,"scanfile BIN runmax","",0);
+ rc = FT_BIN; /* so it can't be any kind of text. */
+ goto xscanfile;
+
+ } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
+ goto xscanfile; /* File starts with a BOM */
+
+ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
+ if (runmax > 0) { /* and runs of NULs */
+ debug(F100,"scanfile BIN (nnUTF8) runmax","",0);
+ rc = FT_BIN; /* UTF-8 doesn't have NULs */
+ } else { /* No NULs */
+ debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0);
+ rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
+ }
+ goto xscanfile;
+ }
+/*
+ For UCS-2 detection, see if the text contains lines delimited by
+ ASCII controls and containing spaces, ASCII digits, or other ASCII
+ characters, thus forcing the presence of a certain percentage of zero bytes.
+ For this purpose require 20% zero bytes, with at least six times as many
+ in even (odd) positions as in odd (even) positions.
+*/
+ if ((evenzero >= x && oddzero == 0) ||
+ ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) &&
+ (crlf == 0) &&
+ (lfnul > 1))
+ ) {
+ debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0);
+ rc = FT_UCS2;
+ val = 0;
+ } else if ((evenzero == 0 && oddzero >= x) ||
+ ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) &&
+ (crlf == 0) &&
+ (lfnul > 1))
+ ) {
+ debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0);
+ rc = FT_UCS2;
+ val = 1;
+
+#ifdef COMMENT
+#ifdef EVENMAX
+/*
+ If the tests above fail, we still might have UCS-2 if there are significant
+ runs of identical bytes in alternating positions, but only if it also has
+ unusual C0 controls (otherwise we'd pick up hex files here). NOTE: We
+ don't actually do this -- EVENMAX is not defined (see comments above at
+ first occurrence of EVENMAX).
+*/
+ } else if (c0noniso && evenmax > bytes / 4) {
+ debug(F100,"scanfile UCS2 BE (evenmax)","",0);
+ rc = FT_UCS2;
+ val = 0;
+ } else if (c0noniso && oddmax > bytes / 4) {
+ debug(F100,"scanfile UCS2 LE (evenmax)","",0);
+ rc = FT_UCS2;
+ val = 1;
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+ }
+/*
+ It seems to be UCS-2 but let's be more certain since there is no BOM...
+ If the number of 7- and 8-bit characters is approximately equal, it might
+ be a compressed file. In this case we decide based on the name.
+*/
+ if (rc == FT_UCS2) {
+ if (eightbit > 0) {
+ int j, k;
+ j = (c1controls * 100) / (c0controls + 1);
+ debug(F101,"scanfile c1/c0 ","",j);
+ k = (bytes * 100) / eightbit;
+ debug(F101,"scanfile pct 8bit ","",k);
+ if (k > 40 && k < 60 && j > 60) {
+ if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) {
+ debug(F110,"scanfile 8-bit BIN compressed",name,0);
+ rc = FT_BIN;
+ goto xscanfile;
+ }
+ }
+ }
+ /* Small file - not enough evidence unless ... */
+
+ if (bytes < 100) {
+ if (oddzero != 0 && evenzero != 0) {
+ debug(F100,"scanfile small UCS2 doubtful","",0);
+ rc = FT_BIN;
+ goto xscanfile;
+ } else if (oddzero == 0 && evenzero == 0) {
+ rc = eightbit ? FT_8BIT : FT_7BIT;
+ }
+ }
+ goto xscanfile; /* Seems to be UCS-2 */
+ }
+
+/* If none of the above, it's probably not Unicode. */
+
+ if (!eightbit) { /* It's 7-bit */
+ if (c0controls) { /* This would be strange */
+ if ((c0noniso > 0) && (txtcz == 0)) {
+ debug(F100,"scanfile 7-bit BIN (c0coniso)","",0);
+ rc = FT_BIN;
+ } else {
+ debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+ } else { /* 7-bit text */
+ debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0);
+ rc = FT_7BIT;
+ }
+ } else if (!c0noniso || txtcz) { /* 8-bit text */
+ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else { /* 8-bit binary */
+ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ }
+
+#else /* !UNICODE */
+
+ if (c0noniso) {
+ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ } else if (eightbit) {
+ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else {
+ debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+
+#endif /* UNICODE */
+
+ xscanfile:
+ if (flag) *flag = val;
+ debug(F101,"scanfile result ","",rc);
+ return(rc);
+}
+
+/*
+ scanstring - like scan file but for a string.
+ This is just a quick butchery of scanfile without thinking too much.
+*/
+int
+scanstring(s) char * s; {
+ int x, val = -1, count = 0; /* Workers */
+ int rc = -1; /* Return code */
+ int pv = -1; /* Pattern-match value */
+ int bytes = 0; /* Total byte count */
+#ifdef UNICODE
+ unsigned int c0, c1; /* First 2 file bytes (for BOM) */
+#endif /* UNICODE */
+ extern int pipesend, filepeek;
+
+ register int i; /* Loop control */
+ int readsize = 0; /* How much to read */
+ int eightbit = 0; /* Number of bytes with 8th bit on */
+ int c0controls = 0; /* C0 non-text control-char counter */
+ int c0noniso = 0; /* C0 non-ISO control-char counter */
+ int c1controls = 0; /* C1 control-character counter */
+ unsigned int c; /* Current character */
+ int runmax = 0; /* Longest run of 0 bytes */
+ int runzero = 0; /* Run of 0 bytes */
+ int pctzero = 0; /* Percentage of 0 bytes */
+ int txtcz = 0;
+
+#ifdef UNICODE
+ int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
+ int utf8state = 0; /* UTF-8 recognizer state */
+ int oddzero = 0; /* Number of 0 bytes in odd postions */
+ int evenzero = 0; /* and in even positions */
+ int lfnul = 0; /* Number of <LF><NUL> sequences */
+ int crlf = 0; /* Number of <CRLF> sequences */
+#else
+ int notutf8 = 1;
+#endif /* UNICODE */
+
+ char * buf = s;
+ if (!s) s = "";
+ count = strlen(s);
+
+#ifdef UNICODE
+ if (bytes == 0 && count > 1) {
+ int incl_cnt = 0;
+
+ /* First look for BOM */
+
+ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
+ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
+
+ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
+ rc = FT_UCS2;
+ val = 0;
+ debug(F111,"scanstring UCS2 BOM BE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
+ rc = FT_UCS2;
+ val = 1;
+ debug(F111,"scanstring UCS2 BOM LE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
+ (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
+ rc = FT_UTF8;
+ debug(F111,"scanstring UTF8 BOM",ckitoa(val),rc);
+ incl_cnt++;
+ }
+ if (incl_cnt) { /* Have BOM */
+ bytes += count;
+ goto xscanstring;
+ }
+ }
+#endif /* UNICODE */
+
+ bytes += count; /* Count bytes read */
+
+ for (i = 0; i < count; i++) { /* For each byte... */
+ c = (unsigned)buf[i]; /* For ease of reference */
+ if (!c) { /* Zero byte? */
+ goto xscanstring; /* Null terminated string */
+ }
+ if ((c & 0x80) == 0) { /* We have a 7-bit byte */
+#ifdef UNICODE
+ if (i > 0 && c == 10) { /* Linefeed */
+ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
+ else if (buf[i-1] == 13) crlf++; /* or by CR... */
+ }
+#endif /* UNICODE */
+ if (c < ' ') { /* Check for CO controls */
+ if (c != LF && c != CR && c != HT && c != FF) {
+ c0controls++;
+ if (c != ESC && c != SO && c != SI)
+ c0noniso++;
+ }
+ if ((c == '\032') /* Ctrl-Z */
+ ) {
+ c0controls--;
+ c0noniso--;
+ }
+ }
+#ifdef UNICODE
+ if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
+ utf8state = 0;
+ debug(F000,"scanstring","7-bit byte in UTF8 sequence",c);
+ notutf8++; /* Then it's not UTF-8 */
+ continue;
+ }
+#endif /* UNICODE */
+ } else { /* We have an 8-bit byte */
+ eightbit++; /* Count it */
+ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
+ c1controls++;
+#ifdef UNICODE
+ if (!notutf8) { /* If it might still be UTF8... */
+ switch (utf8state) { /* Enter the UTF-8 state machine */
+ case 0: /* First byte... */
+ if ((c & 0xE0) == 0xC0) { /* Tells number of */
+ utf8state = 1; /* subsequent bytes */
+ } else if ((c & 0xF0) == 0xE0) {
+ utf8state = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ utf8state = 3;
+ } else {
+ notutf8++;
+ }
+ break;
+ case 1: /* Subsequent byte */
+ case 2:
+ case 3:
+ if ((c & 0xC0) != 0x80) { /* Must start with 10 */
+ debug(F000,"scanstring",
+ "bad byte in UTF8 sequence",c);
+ notutf8++;
+ break;
+ }
+ utf8state--; /* Good, one less in this sequence */
+ break;
+ default: /* Shouldn't happen */
+ debug(F111,"scanstring","bad UTF8 state",utf8state);
+ notutf8++;
+ }
+ }
+#endif /* UNICODE */
+ }
+ }
+ if (bytes == 0) /* If nothing was read */
+ return(-1); /* we're done. */
+
+#ifdef UNICODE
+ if (bytes > 100) /* Bytes is not 0 */
+ pctzero = (evenzero + oddzero) / (bytes / 100);
+ else
+ pctzero = ((evenzero + oddzero) * 100) / bytes;
+#endif /* UNICODE */
+
+#ifdef UNICODE
+ x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
+
+ if (runmax > 2) { /* File has run of more than 2 NULs */
+ debug(F100,"scanstring BIN runmax","",0);
+ rc = FT_BIN; /* so it can't be any kind of text. */
+ goto xscanstring;
+
+ } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
+ goto xscanstring; /* File starts with a BOM */
+
+ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
+ if (runmax > 0) { /* and runs of NULs */
+ debug(F100,"scanstring BIN (nnUTF8) runmax","",0);
+ rc = FT_BIN; /* UTF-8 doesn't have NULs */
+ } else { /* No NULs */
+ debug(F100,"scanstring UTF8 (nnUTF8 + runmax == 0)","",0);
+ rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
+ }
+ goto xscanstring;
+ }
+/*
+ It seems to be UCS-2 but let's be more certain since there is no BOM...
+ If the number of 7- and 8-bit characters is approximately equal, it might
+ be a compressed file. In this case we decide based on the name.
+*/
+ if (rc == FT_UCS2) {
+ if (bytes < 100) {
+ if (oddzero != 0 && evenzero != 0) {
+ debug(F100,"scanstring small UCS2 doubtful","",0);
+ rc = FT_BIN;
+ goto xscanstring;
+ } else if (oddzero == 0 && evenzero == 0) {
+ rc = eightbit ? FT_8BIT : FT_7BIT;
+ }
+ }
+ goto xscanstring; /* Seems to be UCS-2 */
+ }
+
+/* If none of the above, it's probably not Unicode. */
+
+ if (!eightbit) { /* It's 7-bit */
+ if (c0controls) { /* This would be strange */
+ if ((c0noniso > 0) && (txtcz == 0)) {
+ debug(F100,"scanstring 7-bit BIN (c0coniso)","",0);
+ rc = FT_BIN;
+ } else {
+ debug(F100,"scanstring 7-bit ISO2022 TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+ } else { /* 7-bit text */
+ debug(F100,"scanstring 7-bit TEXT (no c0controls)","",0);
+ rc = FT_7BIT;
+ }
+ } else if (!c0noniso || txtcz) { /* 8-bit text */
+ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else { /* 8-bit binary */
+ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ }
+
+#else /* !UNICODE */
+
+ if (c0noniso) {
+ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ } else if (eightbit) {
+ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else {
+ debug(F100,"scanstring 7-bit TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+
+#endif /* UNICODE */
+
+ xscanstring:
+ debug(F101,"scanstring result ","",rc);
+ return(rc);
+}
+
+
+
+/* F I L E S E L E C T -- Select this file for sending */
+
+int
+#ifdef CK_ANSIC
+fileselect(
+ char *f, char *sa, char *sb, char *sna, char *snb,
+ CK_OFF_T minsiz, CK_OFF_T maxsiz,
+ int nbu, int nxlist,
+ char ** xlist
+)
+#else
+fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
+ char *f,*sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
+ int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+/* fileselect */ {
+ char *fdate;
+ int n;
+ CK_OFF_T z;
+
+ debug(F111,"fileselect minsiz",ckfstoa(minsiz),minsiz);
+ debug(F111,"fileselect maxsiz",ckfstoa(maxsiz),maxsiz);
+ debug(F111,"fileselect (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
+
+ if (!sa) sa = "";
+ if (!sb) sb = "";
+ if (!sna) sna = "";
+ if (!snb) snb = "";
+
+#ifdef CKSYMLINK
+#ifndef NOICP
+#ifndef NOXFER
+ if (nolinks) {
+ CK_OFF_T zz;
+ zz = zgetfs(f);
+ debug(F111,"fileselect NOLINKS zgetfs",f,zz);
+ if (zz < (CK_OFF_T)0)
+ return(0);
+ debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link);
+ if (zgfs_link)
+ return(0);
+ }
+#endif /* NOXFER */
+#endif /* NOICP */
+#endif /* CKSYMLINK */
+
+ debug(F110,"fileselect",f,0);
+ if (*sa || *sb || *sna || *snb) {
+ fdate = zfcdat(f); /* Date/time of this file */
+ if (!fdate) fdate = "";
+ n = strlen(fdate);
+ debug(F111,"fileselect fdate",fdate,n);
+ if (n != 17) /* Failed to get it */
+ return(1);
+ /* /AFTER: */
+ if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) {
+ debug(F110,"fileselect sa",sa,0);
+ /* tlog(F110,"Skipping (too old)",f,0); */
+ return(0);
+ }
+ /* /BEFORE: */
+ if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) {
+ debug(F110,"fileselect sb",sb,0);
+ /* tlog(F110,"Skipping (too new)",f,0); */
+ return(0);
+ }
+ /* /NOT-AFTER: */
+ if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) {
+ debug(F110,"fileselect sna",sna,0);
+ /* tlog(F110,"Skipping (too new)",f,0); */
+ return(0);
+ }
+ /* /NOT-BEFORE: */
+ if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) {
+ debug(F110,"fileselect snb",snb,0);
+ /* tlog(F110,"Skipping (too old)",f,0); */
+ return(0);
+ }
+ }
+ /* Smaller or larger */
+ if (minsiz > (CK_OFF_T)-1 || maxsiz > (CK_OFF_T)-1) {
+ z = zchki(f); /* Get size */
+ debug(F101,"fileselect filesize","",z);
+ if (z < (CK_OFF_T)0)
+ return(1);
+ if ((minsiz > (CK_OFF_T)-1) && (z >= minsiz)) {
+ debug(F111,"fileselect minsiz skipping",f,minsiz);
+ /* tlog(F111,"Skipping (too big)",f,z); */
+ return(0);
+ }
+ if ((maxsiz > (CK_OFF_T)-1) && (z <= maxsiz)) {
+ debug(F111,"fileselect maxsiz skipping",f,maxsiz);
+ /* tlog(F110,"Skipping (too small)",f,0); */
+ return(0);
+ }
+ }
+ if (nbu) { /* Skipping backup files? */
+ if (ckmatch(
+#ifdef CKREGEX
+ "*.~[0-9]*~" /* Not perfect but close enough. */
+#else
+ "*.~*~" /* Less close. */
+#endif /* CKREGEX */
+ ,f,filecase,1)) {
+ debug(F110,"fileselect skipping backup",f,0);
+ return(0);
+ }
+ }
+ for (n = 0; xlist && n < nxlist; n++) {
+ if (!xlist[n]) {
+ debug(F101,"fileselect xlist empty",0,n);
+ break;
+ }
+ if (ckmatch(xlist[n],f,filecase,1)) {
+ debug(F111,"fileselect xlist",xlist[n],n);
+ debug(F110,"fileselect skipping",f,0);
+ return(0);
+ }
+ }
+ if (xfiletype > -1) {
+ n = scanfile(f,NULL,nscanfile);
+ if (n < 0) {
+ n = binary ? 1 : 0;
+ } else {
+ n = (n == FT_BIN) ? 1 : 0;
+ }
+ if (n != xfiletype)
+ return(0);
+ }
+ debug(F110,"fileselect selecting",f,0);
+ return(1);
+}
+
+
+#ifdef TCPSOCKET
+#ifdef NT
+extern int WSASafeToCancel;
+#endif /* NT */
+#endif /* TCPSOCKET */
+
+VOID
+setflow() {
+ extern int flow, autoflow, mdmtyp, cxtype, cxflow[];
+#ifndef NODIAL
+ extern int dialcapas, dialfc;
+ extern MDMINF * modemp[];
+ MDMINF * p = NULL;
+ long bits = 0;
+#endif /* NODIAL */
+
+ debug(F101,"setflow autoflow","",autoflow);
+
+/* #ifdef COMMENT */
+/* WHY WAS THIS COMMENTED OUT? */
+ if (!autoflow) /* Only if FLOW is AUTO */
+ return;
+/* #endif */ /* COMMENT */
+
+ debug(F101,"setflow local","",local);
+ debug(F101,"setflow network","",network);
+ debug(F101,"setflow cxtype","",cxtype);
+
+#ifdef TN_COMPORT
+ if (network && istncomport()) {
+ flow = cxflow[CXT_MODEM];
+ debug(F101,"setflow TN_COMPORT flow","",flow);
+ return;
+ }
+#endif /* TN_COMPORT */
+
+ if (network || !local || cxtype == CXT_DIRECT) {
+ flow = cxflow[cxtype]; /* Set appropriate flow control */
+ debug(F101,"setflow flow","",flow);
+ return;
+ }
+ if (cxtype != CXT_MODEM) /* Connection type should be modem */
+ return;
+
+#ifndef NODIAL
+ bits = dialcapas; /* Capability bits */
+ if (!bits) { /* No bits? */
+ p = modemp[mdmtyp]; /* Look in modem info structure */
+ if (p)
+ bits = p->capas;
+ }
+ if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */
+#ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */
+ if (bits & CKD_HW) /* and modem can do it too */
+ flow = FLO_RTSC; /* then switch to RTS/CTS */
+ else /* otherwise */
+ flow = FLO_XONX; /* use Xon/Xoff. */
+#else
+#ifndef NEXT
+#ifndef IRIX
+ flow = FLO_XONX; /* Use Xon/Xoff. */
+#endif /* IRIX */
+#endif /* NEXT */
+#endif /* CK_RTSCTS */
+ }
+#endif /* NODIAL */
+ debug(F101,"setflow modem flow","",flow);
+ return;
+}
+
+#ifndef NOLOCAL
+#ifdef CK_TRIGGER
+
+/* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */
+/*
+ Returns -1 if trigger not found, or else the trigger index, 0 or greater.
+ (Replace with fancier and more efficient matcher later...)
+ NOTE: to prevent unnecessary function call overhead, call this way:
+
+ x = tt_trigger[0] ? autoexitchk(c) : -1;
+
+*/
+int
+#ifdef CK_ANSIC
+autoexitchk(CHAR c)
+#else
+autoexitchk(c) CHAR c;
+#endif /* CK_ANSIC */
+/* autoexitchk */ {
+ extern CHAR * tt_trmatch[];
+ extern char * tt_trigger[];
+ int i;
+ for (i = 0; i < TRIGGERS; i++) {
+ if (!tt_trigger[i]) { /* No more triggers in list */
+ break;
+ } else if (*tt_trigger[i]) {
+ if (!tt_trmatch[i]) /* Just starting? */
+ tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
+ if (c == *tt_trmatch[i]) { /* Compare this character */
+ tt_trmatch[i]++; /* It matches */
+ if (!*tt_trmatch[i]) { /* End of match string? */
+ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
+ debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
+ return(i); /* and return success */
+ }
+ } else /* No match */
+ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
+ } /* and go on the next match string */
+ }
+ return(-1); /* No match found */
+}
+#endif /* CK_TRIGGER */
+
+#ifndef NOSHOW
+/* S H O M D M -- Show modem signals */
+
+VOID
+shomdm() {
+/*
+ Note use of "\r\n" to make sure this report prints right, even when
+ called during CONNECT mode.
+*/
+ int y;
+ y = ttgmdm();
+ switch (y) {
+ case -3: printf(
+ "Modem signals unavailable in this version of Kermit\r\n");
+ break;
+ case -2: printf("No modem control for this device\r\n"); break;
+ case -1: printf("Modem signals unavailable\r\n"); break;
+ default:
+#ifndef MAC
+ printf(
+ " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off");
+ printf(
+ " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
+#endif /* MAC */
+ printf(
+ " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
+#ifndef STRATUS
+#ifndef MAC
+ printf(
+ " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off");
+#endif /* MAC */
+ printf(
+ " Data Terminal Ready (DTR): %s\r\n",
+#ifdef NT
+ "(unknown)"
+#else /* NT */
+ (y & BM_DTR) ? "On": "Off"
+#endif /* NT */
+ );
+#ifndef MAC
+ printf(
+ " Request To Send (RTS): %s\r\n",
+#ifdef NT
+ "(unknown)"
+#else /* NT */
+ (y & BM_RTS) ? "On": "Off"
+#endif /* NT */
+ );
+#endif /* MAC */
+#endif /* STRATUS */
+ }
+#ifdef BETADEBUG
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) {
+ LPDEVCFG lpDevCfg = NULL;
+ LPCOMMCONFIG lpCommConfig = NULL;
+ LPMODEMSETTINGS lpModemSettings = NULL;
+ DCB * lpDCB = NULL;
+
+ if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
+ &lpCommConfig,&lpDCB)) {
+ printf("\n");
+ cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
+ lpCommConfig,lpDCB);
+ }
+ }
+#endif /* CK_TAPI */
+#endif /* BETADEBUG */
+}
+#endif /* NOSHOW */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+/* S D E B U -- Record spar results in debugging log */
+
+VOID
+sdebu(len) int len; {
+ debug(F111,"spar: data",(char *) rdatap,len);
+ debug(F101," spsiz ","", spsiz);
+ debug(F101," timint","",timint);
+ debug(F101," npad ","", npad);
+ debug(F101," padch ","", padch);
+ debug(F101," seol ","", seol);
+ debug(F101," ctlq ","", ctlq);
+ debug(F101," ebq ","", ebq);
+ debug(F101," ebqflg","",ebqflg);
+ debug(F101," bctr ","", bctr);
+ debug(F101," rptq ","", rptq);
+ debug(F101," rptflg","",rptflg);
+ debug(F101," lscapu","",lscapu);
+ debug(F101," atcapu","",atcapu);
+ debug(F101," lpcapu","",lpcapu);
+ debug(F101," swcapu","",swcapu);
+ debug(F101," wslotn","", wslotn);
+ debug(F101," whatru","", whatru);
+}
+/* R D E B U -- Debugging display of rpar() values */
+
+VOID
+rdebu(d,len) CHAR *d; int len; {
+ debug(F111,"rpar: data",d,len);
+ debug(F101," rpsiz ","", xunchar(d[0]));
+ debug(F101," rtimo ","", rtimo);
+ debug(F101," mypadn","",mypadn);
+ debug(F101," mypadc","",mypadc);
+ debug(F101," eol ","", eol);
+ debug(F101," ctlq ","", ctlq);
+ debug(F101," sq ","", sq);
+ debug(F101," ebq ","", ebq);
+ debug(F101," ebqflg","",ebqflg);
+ debug(F101," bctr ","", bctr);
+ debug(F101," rptq ","", d[8]);
+ debug(F101," rptflg","",rptflg);
+ debug(F101," capas ","", capas);
+ debug(F101," bits ","",d[capas]);
+ debug(F101," lscapu","",lscapu);
+ debug(F101," atcapu","",atcapu);
+ debug(F101," lpcapu","",lpcapu);
+ debug(F101," swcapu","",swcapu);
+ debug(F101," wslotr","", wslotr);
+ debug(F101," rpsiz(extended)","",rpsiz);
+}
+
+#ifdef COMMENT
+/* C H K E R R -- Decide whether to exit upon a protocol error */
+
+VOID
+chkerr() {
+ if (backgrd && !server) fatal("Protocol error");
+}
+#endif /* COMMENT */
+#endif /* NOXFER */
+
+/* F A T A L -- Fatal error message */
+
+VOID
+fatal(msg) char *msg; {
+ extern int initflg;
+ static int initing = 0;
+ if (!msg) msg = "";
+ debug(F111,"fatal",msg,initflg);
+
+ if (!initflg) { /* If called from prescan */
+ if (initing) /* or called from sysinit() */
+ exit(253);
+ initing = 1;
+ sysinit();
+ }
+
+ debug(F111,"fatal",msg,xitsta);
+ tlog(F110,"Fatal:",msg,0L);
+#ifdef VMS
+ if (strncmp(msg,"%CKERMIT",8))
+ conol("%CKERMIT-E-FATAL, ");
+ conoll(msg);
+#else /* !VMS */
+ conoll(msg);
+#endif /* VMS */
+#ifdef OS2
+#ifndef NOXFER
+ if (xfrbel) {
+ bleep(BP_FAIL);
+ sleep(1);
+ bleep(BP_FAIL);
+ }
+#endif /* NOXFER */
+
+#endif /* OS2 */
+ doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */
+}
+
+#ifndef NOXFER
+/* B L D L E N -- Make length-encoded copy of string */
+
+char *
+bldlen(str,dest) char *str, *dest; {
+ int len;
+ len = (int)strlen(str);
+ if (len > 94)
+ *dest = SP;
+ else
+ *dest = (char) tochar(len);
+ strcpy(dest+1,str); /* Checked below in setgen() */
+ return(dest+len+1);
+}
+
+
+/* S E T G E N -- Construct a generic command */
+/*
+ Call with Generic command character followed by three string arguments.
+ Trailing strings are allowed to be empty (""). Each string except the last
+ non-empty string must be less than 95 characters long. The final nonempty
+ string is allowed to be longer.
+*/
+CHAR
+#ifdef CK_ANSIC
+setgen(char type, char * arg1, char * arg2, char * arg3)
+#else
+setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
+#endif /* CK_ANSIC */
+/* setgen */ {
+ char *upstr, *cp;
+#ifdef DYNAMIC
+ if (!cmdstr)
+ if (!(cmdstr = malloc(MAXSP + 1)))
+ fatal("setgen: can't allocate memory");
+#endif /* DYNAMIC */
+
+ cp = cmdstr;
+ *cp++ = type;
+ *cp = NUL;
+ if (!arg1) arg1 = "";
+ if (!arg2) arg2 = "";
+ if (!arg3) arg3 = "";
+ if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
+ if (*arg1 != NUL) {
+ upstr = bldlen(arg1,cp);
+ if (*arg2 != NUL) {
+ upstr = bldlen(arg2,upstr);
+ if (*arg3 != NUL) bldlen(arg3,upstr);
+ }
+ }
+ cmarg = cmdstr;
+ debug(F110,"setgen",cmarg,0);
+ return('g');
+ }
+ return('E');
+}
+#endif /* NOXFER */
+
+#ifndef NOMSEND
+static char *mgbufp = NULL;
+
+/* F N P A R S E -- */
+
+/*
+ Argument is a character string containing one or more filespecs.
+ This function breaks the string apart into an array of pointers, one
+ to each filespec, and returns the number of filespecs. Used by server
+ when it receives a GET command to allow it to process multiple file
+ specifications in one transaction. Sets cmlist to point to a list of
+ file pointers, exactly as if they were command line arguments.
+
+ This version of fnparse treats spaces as filename separators. If your
+ operating system allows spaces in filenames, you'll need a different
+ separator.
+
+ This version of fnparse mallocs a string buffer to contain the names. It
+ cannot assume that the string that is pointed to by the argument is safe.
+*/
+int
+fnparse(string) char *string; {
+ char *p, *s, *q;
+ int r = 0, x; /* Return code */
+#ifdef RECURSIVE
+ debug(F111,"fnparse",string,recursive);
+#endif /* RECURSIVE */
+
+ if (mgbufp) free(mgbufp); /* Free this from last time. */
+ mgbufp = malloc((int)strlen(string)+2);
+ if (!mgbufp) {
+ debug(F100,"fnparse malloc error","",0);
+ return(0);
+ }
+#ifndef NOICP
+#ifndef NOSPL
+ ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */
+#endif /* NOSPL */
+#endif /* NOICP */
+ s = string; /* Input string */
+ p = q = mgbufp; /* Point to the copy */
+ r = 0; /* Initialize our return code */
+ while (*s == SP || *s == HT) /* Skip leading spaces and tabs */
+ s++;
+ for (x = strlen(s); /* Strip trailing spaces */
+ (x > 1) && (s[x-1] == SP || s[x-1] == HT);
+ x--)
+ s[x-1] = NUL;
+ while (1) { /* Loop through rest of string */
+ if (*s == CMDQ) { /* Backslash (quote character)? */
+ if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
+ *q++ = (char) x; /* Numeric backslash code, ok */
+ } else { /* Just let it quote next char */
+ s++; /* get past the backslash */
+ *q++ = *s++; /* deposit next char */
+ }
+ continue;
+ } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
+ *q++ = NUL; /* End of output filename. */
+ msfiles[r] = p; /* Add this filename to the list */
+ debug(F111,"fnparse",msfiles[r],r);
+ r++; /* Count it */
+ if (*s == NUL) break; /* End of string? */
+ while (*s == SP) s++; /* Skip repeated spaces */
+ p = q; /* Start of next name */
+ continue;
+ } else *q++ = *s; /* Otherwise copy the character */
+ s++; /* Next input character */
+ }
+ debug(F101,"fnparse r","",r);
+ msfiles[r] = ""; /* Put empty string at end of list */
+ cmlist = msfiles;
+ return(r);
+}
+#endif /* NOMSEND */
+
+char * /* dbchr() for DEBUG SESSION */
+dbchr(c) int c; {
+ static char s[8];
+ char *cp = s;
+
+ c &= 0xff;
+ if (c & 0x80) { /* 8th bit on */
+ *cp++ = '~';
+ c &= 0x7f;
+ }
+ if (c < SP) { /* Control character */
+ *cp++ = '^';
+ *cp++ = (char) ctl(c);
+ } else if (c == DEL) {
+ *cp++ = '^';
+ *cp++ = '?';
+ } else { /* Printing character */
+ *cp++ = (char) c;
+ }
+ *cp = '\0'; /* Terminate string */
+ cp = s; /* Return pointer to it */
+ return(cp);
+}
+
+/* C K H O S T -- Get name of local host (where C-Kermit is running) */
+
+/*
+ Call with pointer to buffer to put hostname in, and length of buffer.
+ Copies hostname into buffer on success, puts null string in buffer on
+ failure.
+*/
+#ifdef BSD44
+#define BSD4
+#undef ATTSV
+#endif /* BSD44 */
+
+#ifdef SVORPOSIX
+#ifndef BSD44
+#ifndef apollo
+#include <sys/utsname.h>
+#endif /* apollo */
+#endif /* BSD44 */
+#else
+#ifdef BELLV10
+#include <utsname.h>
+#endif /* BELLV10 */
+#endif /* SVORPOSIX*/
+
+#ifdef CKSYSLOG
+extern char uidbuf[], * clienthost;
+#endif /* CKSYSLOG */
+
+VOID
+ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
+
+#ifndef NOPUSH
+ extern int nopush;
+#ifndef NOSERVER
+ extern int en_hos;
+#endif /* NOSERVER */
+#endif /* NOPUSH */
+
+#ifdef pdp11
+ *vvbuf = NUL;
+#else /* Everything else - rest of this routine */
+
+ char *g;
+ int havefull = 0;
+#ifdef VMS
+ int x;
+#endif /* VMS */
+
+#ifdef SVORPOSIX
+#ifndef BSD44
+#ifndef _386BSD
+#ifndef APOLLOSR10
+ struct utsname hname;
+#endif /* APOLLOSR10 */
+#endif /* _386BSD */
+#endif /* BSD44 */
+#endif /* SVORPOSIX */
+#ifdef datageneral
+ int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
+#endif /* datageneral */
+
+#ifndef NOPUSH
+ if (getenv("CK_NOPUSH")) { /* No shell access allowed */
+ nopush = 1; /* on this host... */
+#ifndef NOSERVER
+ en_hos = 0;
+#endif /* NOSERVER */
+ }
+#endif /* NOPUSH */
+
+ *vvbuf = NUL; /* How let's get our host name ... */
+
+#ifndef BELLV10 /* Does not have gethostname() */
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifdef APOLLOSR10
+ ckstrncpy(vvbuf,"Apollo",vvlen);
+#else
+#ifdef BSD44
+ if (gethostname(vvbuf,vvlen) < 0)
+ *vvbuf = NUL;
+#else
+#ifdef _386BSD
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else
+#ifdef QNX
+#ifdef TCPSOCKET
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else
+ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
+#endif /* TCPSOCKET */
+#else /* SVORPOSIX but not _386BSD or BSD44 */
+#ifdef __ia64__
+ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
+#else
+ if (uname(&hname) > -1) {
+ char * p;
+ p = hname.nodename;
+#ifdef TCPSOCKET
+#ifndef NOCKGETFQHOST
+ if (!ckstrchr(p,'.'))
+ p = (char *)ckgetfqhostname(p);
+#endif /* NOCKGETFQHOST */
+#endif /* TCPSOCKET */
+ if (!p) p = "";
+ if (!*p) p = "(unknown)";
+ ckstrncpy(vvbuf,p,vvlen);
+ }
+#endif /* __ia64__ */
+#endif /* QNX */
+#endif /* _386BSD */
+#endif /* BSD44 */
+#endif /* APOLLOSR10 */
+#else /* !SVORPOSIX */
+#ifdef BSD4
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else /* !BSD4 */
+#ifdef VMS
+ g = getenv("SYS$NODE");
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+ x = (int)strlen(vvbuf);
+ if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
+#else
+#ifdef datageneral
+ if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
+ vvlen = ac2 + 1; /* enh - have to add one */
+#else
+#ifdef OS2 /* OS/2 */
+ g = os2_gethostname();
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+#else /* OS2 */
+#ifdef OSK
+#ifdef TCPSOCKET
+ if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
+#endif /* TCPSOCKET */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* BSD4 */
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ /* If TCP/IP is not installed, gethostname() fails, use uname() */
+ if (gethostname(vvbuf,vvlen) < 0) {
+ if (uname(&hname) > -1)
+ ckstrncpy(vvbuf,hname.nodename,vvlen);
+ else
+ *vvbuf = NUL;
+ }
+#endif /* OXOS */
+#endif /* BELLV10 */
+ if (*vvbuf == NUL) { /* If it's still empty */
+ g = getenv("HOST"); /* try this */
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+ }
+ vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */
+#endif /* pdp11 */
+}
+#ifdef BSD44
+#undef BSD4
+#define ATTSV
+#endif /* BSD44 */
+
+/*
+ A S K M O R E -- Poor person's "more".
+ Returns 0 if no more, 1 if more wanted.
+*/
+int
+askmore() {
+ char c;
+ int rv, cx;
+#ifdef IKSD
+ extern int timelimit;
+#endif /* IKSD */
+#ifdef IKSDCONF
+ extern int iksdcf;
+#endif /* IKSDCONF */
+#ifdef CK_APC
+ extern int apcstatus, apcactive;
+#endif /* CK_APC */
+
+#ifdef NOICP
+ return(1);
+#else
+ if (!xaskmore)
+ return(1);
+#ifdef IKSDCONF
+ if (inserver && !iksdcf)
+ return(1);
+#endif /* IKSDCONF */
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
+ return(1);
+#endif /* CK_APC */
+#ifdef VMS
+ if (batch)
+ return(1);
+#else
+#ifdef UNIX
+ if (backgrd)
+ return(1);
+#endif /* UNIX */
+#endif /* VMS */
+
+#ifndef VMS
+ concb((char)escape); /* Force CBREAK mode. */
+#endif /* VMS */
+
+ rv = -1;
+ while (rv < 0) {
+#ifndef OS2
+ printf("more? ");
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+#else
+ printf("more? ");
+ fflush(stdout);
+#endif /* OS2 */
+
+#ifdef IKSD
+ if (inserver) {
+ cx = cmdgetc(timelimit);
+ if (cx < -1 && timelimit) {
+ printf("\n?IKS idle timeout - Goodbye.\n");
+ doexit(GOOD_EXIT,0);
+ } else if (cx == -1) { /* Connection lost */
+ doexit(BAD_EXIT,0);
+ }
+ c = (char) cx;
+ } else {
+#endif /* IKSD */
+#ifdef VMS
+ conbin((char)escape); /* Protect against Ctrl-Z */
+ cx = coninc(0);
+ concb((char)escape);
+#else
+ cx = cmdgetc(0);
+#endif /* VMS */
+ debug(F101,"askmore cmdgetc","",cx);
+ if (cx == EOF) {
+ debug(F100,"askmore EOF","",0);
+#ifdef VMS
+ c = '\032';
+#else
+ c = 'n';
+#endif /* VMS */
+ } else {
+ c = (char)cx;
+ }
+ debug(F101,"askmore c","",c);
+
+#ifdef IKSD
+ }
+#endif /* IKSD */
+ switch (c) {
+ /* Yes */
+ case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
+ xaskmore = 0;
+ /* fall thru on purpose */
+
+ case SP: case 'y': case 'Y': case 012: case 015:
+#ifdef OSK
+ write(1, "\015 \015", sizeof "\015 \015" - 1);
+#else
+ printf("\015 \015");
+#endif /* OSK */
+ rv = 1;
+ break;
+ /* No */
+ case 'n': case 'N': case 'q': case 'Q':
+#ifdef OSK
+ printf("\n");
+#else
+ printf("\015\012");
+#endif /* OSK */
+ rv = 0;
+ break;
+ case '\003':
+ case '\004':
+ case '\032':
+#ifdef OSK
+ printf("^%c...\n", (c + 0100));
+#else
+ printf("^%c...\015\012", (c + 0100));
+#endif /* OSK */
+ rv = 0;
+ break;
+ /* Invalid answer */
+ default:
+ debug(F111,"askmore","invalid answer",c);
+ printf("Y or space-bar for yes, N for no, G to show the rest\n");
+ continue;
+ }
+#ifdef OS2
+ printf("\r \r");
+ fflush(stdout);
+#endif /* OS2 */
+ }
+ return(rv);
+#endif /* NOICP */
+}
+
+/* T R A P -- Terminal interrupt handler */
+
+SIGTYP
+#ifdef CK_ANSIC
+trap(int sig)
+#else
+trap(sig) int sig;
+#endif /* CK_ANSIC */
+/* trap */ {
+ extern int b_save, f_save;
+#ifndef NOICP
+ extern int timelimit;
+#endif /* NOICP */
+#ifdef OS2
+ extern unsigned long startflags;
+#ifndef NOSETKEY
+ extern int os2gks;
+#endif /* NOSETKEY */
+ int i;
+#endif /* OS2 */
+#ifndef NOSPL
+ extern int i_active, instatus;
+#endif /* NOSPL */
+#ifdef VMS
+ int i; FILE *f;
+#endif /* VMS */
+ extern int zchkod, zchkid;
+#ifndef NOSPL
+ extern int unkmacro;
+#endif /* NOSPL */
+
+ debok = 1;
+#ifdef NTSIG
+ connoi();
+#endif /* NTSIG */
+#ifdef __EMX__
+ signal(SIGINT, SIG_ACK);
+#endif
+#ifdef GEMDOS
+/* GEM is not reentrant, no i/o from interrupt level */
+ cklongjmp(cmjbuf,1); /* Jump back to parser now! */
+#endif /* GEMDOS */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"*********************","",0);
+ if (sig == SIGINT)
+ debug(F101,"trap caught SIGINT","",sig);
+ else
+ debug(F101,"trap caught signal","",sig);
+ debug(F100,"*********************","",0);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ if ( sig == SIGBREAK && (startflags & 128) ) {
+ debug(F101,"trap ignoring SIGBREAK","",sig);
+ return;
+ }
+#endif /* OS2 */
+
+#ifndef NOICP
+ timelimit = 0; /* In case timed ASK interrupted */
+#ifndef NOSPL
+ unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */
+#endif /* NOSPL */
+#endif /* NOICP */
+ zchkod = 0; /* Or file expansion interrupted... */
+ zchkid = 0;
+ interrupted = 1;
+
+ if (what & W_CONNECT) { /* Are we in CONNECT mode? */
+/*
+ The HP workstation Reset key sends some kind of ueber-SIGINT that can not
+ be SIG_IGNored, so we wind up here somehow (even though this is *not* the
+ current SIGINT handler). Just return.
+*/
+ debug(F101,"trap: SIGINT caught during CONNECT","",sig);
+ SIGRETURN;
+ }
+#ifndef NOSPL
+ if (i_active) { /* INPUT command was active? */
+ i_active = 0; /* Not any more... */
+ instatus = INP_UI; /* INPUT status = User Interrupted */
+ }
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ ftreset(); /* Restore global protocol settings */
+ binary = b_save; /* Then restore these */
+ fncnv = f_save;
+ bye_active = 0;
+ diractive = 0;
+ cdactive = 0;
+#endif /* NOXFER */
+ zclose(ZIFILE); /* If we were transferring a file, */
+ zclose(ZOFILE); /* close it. */
+#ifndef NOICP
+ cmdsquo(cmd_quoting); /* If command quoting was turned off */
+#ifdef CKLEARN
+ {
+ extern FILE * learnfp;
+ extern int learning;
+ if (learnfp) {
+ fclose(learnfp);
+ learnfp = NULL;
+ learning = 0;
+ }
+ }
+#endif /* CKLEARN */
+#endif /* NOICP */
+#ifdef CK_APC
+ delmac("_apc_commands",1);
+ apcactive = APC_INACTIVE;
+#endif /* CK_APC */
+
+#ifdef VMS
+/*
+ Fix terminal.
+*/
+ if (ft_win) { /* If curses window open */
+ debug(F100,"^C trap() curses","",0);
+ xxscreen(SCR_CW,0,0L,""); /* Close it */
+ conres(); /* Restore terminal */
+ i = printf("^C..."); /* Echo ^C to standard output */
+ } else {
+ conres();
+ i = printf("^C...\n"); /* Echo ^C to standard output */
+ }
+ if (i < 1 && ferror(stdout)) { /* If there was an error */
+ debug(F100,"^C trap() error","",0);
+ fclose(stdout); /* close standard output */
+ f = fopen(dftty, "w"); /* open the controlling terminal */
+ if (f) stdout = f; /* and make it standard output */
+ printf("^C...\n"); /* and echo the ^C again. */
+ }
+#else /* Not VMS */
+#ifdef STRATUS
+ conres(); /* Set console back to normal mode */
+#endif /* STRATUS */
+#ifndef NOXFER
+ if (ft_win) { /* If curses window open, */
+ debug(F100,"^C trap() curses","",0);
+ xxscreen(SCR_CW,0,0L,""); /* close it. */
+ printf("^C..."); /* Echo ^C to standard output */
+ } else {
+#endif /* NOXFER */
+ printf("^C...\n");
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+#endif /* VMS */
+#ifdef datageneral
+ connoi_mt(); /* Kill asynch task that listens to */
+ ttimoff();
+ conres(); /* the keyboard */
+#endif /* datageneral */
+
+#ifndef NOCCTRAP
+/* This is stupid -- every version should have ttimoff()... */
+#ifdef UNIX
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef OSK
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef STRATUS
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef OS2
+#ifndef NOSETKEY
+ os2gks = 1; /* Turn back on keycode mapping */
+#endif /* NOSETKEY */
+#ifndef NOLOCAL
+ for (i = 0; i < VNUM; i++)
+ VscrnResetPopup(i);
+#endif /* NOLOCAL */
+#ifdef TCPSOCKET
+#ifdef NT
+ /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
+ if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
+ WSACancelBlockingCall();
+ }
+#endif /* NT */
+#endif /* TCPSOCKET */
+#ifdef CK_NETBIOS
+ NCBCancelOutstanding();
+#endif /* CK_NETBIOS */
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef VMS
+ ttimoff(); /* Turn off any timer interrupts */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* OSK */
+#endif /* UNIX */
+
+#ifdef NETPTY
+ /* Clean up Ctrl-C out of REDIRECT or external protocol */
+ {
+ extern PID_T pty_fork_pid;
+ extern int pty_master_fd, pty_slave_fd;
+ int x;
+
+ signal(SIGCHLD,SIG_IGN); /* We don't want this any more */
+
+ debug(F101,"trap pty_master_fd","",pty_master_fd);
+ if (pty_master_fd > 2) {
+ x = close(pty_master_fd);
+ debug(F101,"trap pty_master_fd close","",x);
+ }
+ pty_master_fd = -1;
+ debug(F101,"trap pty_slave_fd","",pty_slave_fd);
+ if (pty_slave_fd > 2) {
+ x = close(pty_slave_fd);
+ debug(F101,"trap pty_slave_fd close","",x);
+ }
+ pty_slave_fd = -1;
+ debug(F101,"trap pty_fork_pid","",pty_fork_pid);
+ if (pty_fork_pid > 0) {
+ x = kill(pty_fork_pid,0); /* See if the fork is really there */
+ debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno);
+ if (x == 0) { /* Seems to be active */
+ x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */
+ debug(F101,"trap pty_fork_pid kill SIGHUP","",x);
+ msleep(100);
+ errno = 0;
+ x = kill(pty_fork_pid,0); /* Is it still there? */
+ if (x == 0
+#ifdef ESRCH
+ /* This module is not always exposed to <errno.h> */
+ || errno != ESRCH
+#endif /* ESRCH */
+ ) {
+ x = kill(pty_fork_pid,SIGKILL);
+ debug(F101,"trap pty_fork_pid kill SIGKILL","",x);
+ }
+ }
+ pty_fork_pid = -1;
+ }
+ }
+#endif /* NETPTY */
+
+#ifdef OSK
+ sigmask(-1);
+/*
+ We are in an intercept routine but do not perform a F$RTE (done implicitly
+ by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump
+ only restores the cpu registers, NOT the fpu registers. So don't use fpu at
+ all or at least don't use common fpu (double or float) register variables.
+*/
+#endif /* OSK */
+
+#ifdef NTSIG
+ PostCtrlCSem();
+#else /* NTSIG */
+ debug(F100,"trap about to longjmp","",0);
+#ifdef NT
+ cklongjmp(ckjaddr(cmjbuf),1);
+#else /* NT */
+ cklongjmp(cmjbuf,1);
+#endif /* NT */
+#endif /* NTSIG */
+#else /* NOCCTRAP */
+/* No Ctrl-C trap, just exit. */
+#ifdef CK_CURSES /* Curses support? */
+ xxscreen(SCR_CW,0,0L,""); /* Close curses window */
+#endif /* CK_CURSES */
+ doexit(BAD_EXIT,what); /* Exit poorly */
+#endif /* NOCCTRAP */
+ SIGRETURN;
+}
+
+
+/* C K _ T I M E -- Returns pointer to current time. */
+
+char *
+ck_time() {
+ static char tbuf[10];
+ char *p;
+ int x;
+
+ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
+ if (!p) /* like asctime()! */
+ return("");
+ if (*p) {
+ for (x = 11; x < 19; x++) /* copy hh:mm:ss */
+ tbuf[x - 11] = p[x]; /* to tbuf */
+ tbuf[8] = NUL; /* terminate */
+ }
+ return(tbuf); /* and return it */
+}
+
+/* C C _ C L E A N -- Cleanup after terminal interrupt handler */
+
+#ifdef GEMDOS
+int
+cc_clean() {
+ zclose(ZIFILE); /* If we were transferring a file, */
+ zclose(ZOFILE); /* close it. */
+ printf("^C...\n"); /* Not VMS, no problem... */
+}
+#endif /* GEMDOS */
+
+
+/* S T P T R A P -- Handle SIGTSTP (suspend) signals */
+
+SIGTYP
+#ifdef CK_ANSIC
+stptrap(int sig)
+#else
+stptrap(sig) int sig;
+#endif /* CK_ANSIC */
+/* stptrap */ {
+
+#ifndef NOJC
+ int x; extern int cmflgs;
+ debug(F101,"stptrap() caught signal","",sig);
+ if (!xsuspend) {
+ printf("\r\nsuspend disabled\r\n");
+#ifndef NOICP
+ if (what & W_COMMAND) { /* If we were parsing commands */
+ prompt(xxstring); /* reissue the prompt and partial */
+ if (!cmflgs) /* command (if any) */
+ printf("%s",cmdbuf);
+ }
+#endif /* NOICP */
+ } else {
+ conres(); /* Reset the console */
+#ifndef OS2
+ /* Flush pending output first, in case we are continued */
+ /* in the background, which could make us block */
+ fflush(stdout);
+
+ x = psuspend(xsuspend); /* Try to suspend. */
+ if (x < 0)
+#endif /* OS2 */
+ printf("Job control not supported\r\n");
+ conint(trap,stptrap); /* Rearm the trap. */
+ debug(F100,"stptrap back from suspend","",0);
+ switch (what) {
+ case W_CONNECT: /* If suspended during CONNECT? */
+ conbin((char)escape); /* put console back in binary mode */
+ debug(F100,"stptrap W_CONNECT","",0);
+ break;
+#ifndef NOICP
+ case W_COMMAND: /* Suspended in command mode */
+ debug(F101,"stptrap W_COMMAND pflag","",pflag);
+ concb((char)escape); /* Put back CBREAK tty mode */
+ if (pflag) { /* If command parsing was */
+ prompt(xxstring); /* reissue the prompt and partial */
+ if (!cmflgs) /* command (if any) */
+ printf("%s",cmdbuf);
+ }
+ break;
+#endif /* NOICP */
+ default: /* All other cases... */
+ debug(F100,"stptrap default","",0);
+ concb((char)escape); /* Put it back in CBREAK mode */
+ break;
+ }
+ }
+#endif /* NOJC */
+ SIGRETURN;
+}
+
+#ifdef TLOG
+#define TBUFL 300
+
+/* T L O G -- Log a record in the transaction file */
+/*
+ Call with a format and 3 arguments: two strings and a number:
+ f - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
+ s1,s2 - String arguments 0 and 1.
+ n - Long, argument 2.
+*/
+VOID
+#ifdef CK_ANSIC
+dotlog(int f, char *s1, char *s2, CK_OFF_T n)
+#else
+dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2;
+#endif /* CK_ANSIC */
+/* dotlog */ {
+ static char s[TBUFL];
+ extern int tlogfmt;
+ char *sp = s; int x;
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+
+ if (!tralog) return; /* If no transaction log, don't */
+ if (tlogfmt != 1) return;
+ switch (f) {
+ case F000: /* 0 (special) "s1 n s2" */
+ if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
+ sprintf(sp,"?T-Log string too long");
+ else
+ sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F001: /* 1, " n" */
+ sprintf(sp," %s",ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F010: /* 2, "[s2]" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if (x + 6 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"[%s]",s2);
+ if (zsoutl(ZTFILE,"") < 0) tralog = 0;
+ break;
+ case F011: /* 3, "[s2] n" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if (x + 6 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"[%s] %s",s2,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F100: /* 4, "s1" */
+ if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
+ break;
+ case F101: /* 5, "s1: n" */
+ if ((int)strlen(s1) + 15 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"%s: %s",s1,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F110: /* 6, "s1 s2" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if ((int)strlen(s1) + x + 4 > TBUFL)
+ sprintf(sp,"?String too long");
+ else
+ sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F111: /* 7, "s1 s2: n" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if ((int)strlen(s1) + x + 15 > TBUFL)
+ sprintf(sp,"?String too long");
+ else
+ sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ default:
+ sprintf(sp,"?Invalid format for tlog() - %d",f);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ }
+}
+
+/*
+ D O X L O G
+
+ This is the transaction-log writer for BRIEF format.
+ The idea is produce one record (line) per file. Each record
+ has the following delimited fields:
+ Date (yyyymmdd)
+ Time (hh:mm:ss)
+ Action: SEND or RECV
+ File name
+ File size
+ Transfer mode (text, binary, image, labeled, etc).
+ Status: OK or FAILED
+ Free-form comments in doublequotes
+ The default separator is comma.
+ If a field contains the separator, it is enclosed in doublequotes.
+*/
+VOID
+#ifdef CK_ANSIC
+doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg)
+#else
+doxlog(x, fn, fs, fm, status, msg)
+ int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg;
+#endif /* CK_ANSIC */
+/* doxlog */ {
+ extern int tlogsep;
+ char sep[2];
+ char buf[CKMAXPATH+256], * bufp;
+ char tmpbuf[32];
+ char * s, * p;
+ int len, left, ftp = 0, k;
+
+ if (!tralog) return; /* If no transaction log, don't */
+
+ if (!fn) fn = ""; /* Protect against null pointers */
+ if (!msg) msg = "";
+ if (x & W_FTP)
+ ftp++;
+
+ sep[0] = (char) tlogsep;
+ sep[1] = NUL;
+ if (!sep[0]) sep[0] = ',';
+
+ bufp = buf;
+ left = sizeof(buf);
+ debug(F101,"XXX doxlog left 1","",left);
+
+ p = zzndate(); /* Date */
+ ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
+ bufp += 9;
+ left -= 9;
+ debug(F111,"XXX doxlog left 2",buf,left);
+
+ ztime(&p);
+ ckstrncpy(bufp,p+11,left);
+ bufp += 8;
+ left -= 8;
+ debug(F111,"XXX doxlog left 3",buf,left);
+
+ if (ftp) {
+ if (!(x & (W_SEND|W_RECV)))
+ return;
+ s = (x & W_SEND) ? "PUT" : "GET";
+ k = 3;
+ } else {
+ s = (x & W_SEND) ? "SEND" : "RECV";
+ k = 4;
+ }
+ ckmakmsg(bufp,left,sep,s,sep,NULL);
+ bufp += k + 2;
+ left -= (k + 2);
+ debug(F111,"XXX doxlog left 4",buf,left);
+
+ s = "";
+ if (ckstrchr(fn,sep[0])) /* Filename */
+ s = "\"";
+ ckmakmsg(bufp,left,s,fn,s,sep);
+ sprintf(tmpbuf,"%s",ckfstoa(fs)); /* Size */
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,sep,CKMAXPATH);
+ debug(F110,"doxlog 4",buf,0);
+
+#ifdef NOICP
+ /* Transfer mode */
+ ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
+#else
+ ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
+#endif /* NOICP */
+ if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */
+ ckstrncat(buf,"\"",CKMAXPATH);
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,"\"",CKMAXPATH);
+ } else
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,sep,CKMAXPATH);
+ debug(F110,"doxlog 5",buf,0);
+
+ ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
+ len = strlen(buf);
+ left = CKMAXPATH+256 - len;
+ if (left < 2) fatal("doxlog buffer overlow");
+
+ debug(F111,"XXX doxlog left 5",buf,left);
+
+ debug(F110,"doxlog buf 1", buf, len);
+ s = buf + len;
+ if (status == 0 && left > 32) {
+ long cps = 0L;
+#ifdef GFTIMER
+ debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
+ if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs);
+ sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
+#else
+ if (xfsecs) cps = fs / xfsecs;
+ sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
+#endif /* GFTIMER */
+ } else if ((int)strlen(msg) + 4 < left) {
+ sprintf(s,"%s\"%s\"",sep,msg);
+ }
+ debug(F111,"XXX doxlog left 5",buf,left);
+
+ debug(F110,"doxlog 5",buf,0);
+ x = zsoutl(ZTFILE,buf);
+ debug(F101,"doxlog zsoutl","",x);
+ if (x < 0) tralog = 0;
+}
+#endif /* TLOG */
+
+#ifndef MAC
+/*
+ The rest of this file is for all implementations but the Macintosh.
+*/
+
+#ifdef CK_CURSES
+static int repaint = 0; /* Transfer display needs repainting */
+#endif /* CK_CURSES */
+
+#ifndef NOXFER
+/* C H K I N T -- Check for console interrupts */
+
+/*
+ Used during file transfer in local mode only:
+ . If user has not touched the keyboard, returns 0 with no side effects.
+ . If user typed S or A (etc, see below) prints status message and returns 0.
+ . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
+ . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
+ . If user typed E or C (etc, see below) returns -1.
+*/
+int
+chkint() {
+ int ch, cn, ofd; long zz;
+ if (!xfrint)
+ return(0);
+ if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
+#ifdef datageneral
+ if (con_reads_mt) /* if conint_mt task is active */
+ if (conint_avl) { /* and there's an interrupt pending */
+ cn = 1; /* process it */
+ ch = conint_ch;
+ conint_avl = 0; /* turn off flag so conint_mt can */
+ } else /* proceed */
+ return(0);
+ else /* if conint_mt not active */
+ if ((ch = coninc(2)) < 0) /* try to get char manually */
+ return(0); /* I/O error, or no data */
+ else /* if successful, set cn so we */
+ cn = 1; /* know we got one */
+ debug(F101,"chkint got keyboard character",ch,cn);
+#else /* !datageneral */
+#ifdef NTSIG
+ {
+ extern int TlsIndex;
+ struct _threadinfo * threadinfo;
+ threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
+ if (threadinfo) {
+ if (!WaitSem(threadinfo->DieSem,0))
+ return -1; /* Cancel Immediately */
+ }
+ }
+#endif /* NTSIG */
+ cn = conchk(); /* Any input waiting? */
+ debug(F101,"conchk","",cn);
+ if (cn < 1) return(0);
+ ch = coninc(5) ;
+ debug(F101,"coninc","",ch);
+ if (ch < 0) return(0);
+#endif /* datageneral */
+
+ ch &= 0177;
+ switch (ch) {
+ case 'A': case 'a': case 0001: /* Status report */
+ case 'S': case 's':
+ if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
+ return(0); /* Only for serial, simple or none */
+ ofd = fdispla; /* [MF] Save file display type */
+ if (fdispla == XYFD_N)
+ fdispla = XYFD_R; /* [MF] Pretend serial if no display */
+ xxscreen(SCR_TN,0,0l,"Status report:");
+ xxscreen(SCR_TN,0,0l," file type: ");
+ if (binary) {
+ switch(binary) {
+ case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
+ case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
+ case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
+ default:
+ case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
+ }
+ } else {
+#ifdef NOCSETS
+ xxscreen(SCR_TZ,0,0l,"text");
+#else
+ xxscreen(SCR_TU,0,0l,"text, ");
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ xxscreen(SCR_TZ,0,0l,"transparent");
+ } else {
+ if (what & W_SEND) {
+ xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
+ xxscreen(SCR_TU,0,0l," => ");
+ xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
+ } else {
+ xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
+ xxscreen(SCR_TU,0,0l," => ");
+ xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
+ }
+ }
+#endif /* NOCSETS */
+ }
+ xxscreen(SCR_QE,0,filcnt," file number");
+ if (fsize) xxscreen(SCR_QE,0,fsize," size");
+ xxscreen(SCR_QE,0,ffc," characters so far");
+ if (fsize > 0L) {
+#ifdef CK_RESEND
+ zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
+ zz = ( (ffc + zz) * 100L ) / fsize;
+#else
+ zz = ( ffc * 100L ) / fsize;
+#endif /* CK_RESEND */
+ xxscreen(SCR_QE,0,zz, " percent done");
+ }
+ if (bctu == 4) { /* Block check */
+ xxscreen(SCR_TU,0,0L," block check: ");
+ xxscreen(SCR_TZ,0,0L,"blank-free-2");
+ } else xxscreen(SCR_QE,0,(long)bctu, " block check");
+ xxscreen(SCR_QE,0,(long)rptflg," compression");
+ xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
+ xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
+ if (!network)
+ xxscreen(SCR_QE,0, speed, " speed");
+ if (what & W_SEND)
+
+ xxscreen(SCR_QE,0,spsiz, " packet length");
+ else if (what & W_RECV || what & W_REMO)
+ xxscreen(SCR_QE,0,urpsiz," packet length");
+ xxscreen(SCR_QE,0,wslots, " window slots");
+ fdispla = ofd; /* [MF] Restore file display type */
+ return(0);
+
+ case 'B': case 'b': case 0002: /* Cancel batch */
+ case 'Z': case 'z': case 0032:
+ czseen = 1;
+ interrupted = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ (((what & W_RECV) && (wslots > 1)) ?
+ "Canceling batch, wait... " :
+ "Canceling batch... ")
+ );
+ return(0);
+
+ case 'F': case 'f': case 0006: /* Cancel file */
+ case 'X': case 'x': case 0030:
+ cxseen = 1;
+ interrupted = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ (((what & W_RECV) && (wslots > 1)) ?
+ "Canceling file, wait... " :
+ "Canceling file... ")
+ );
+ return(0);
+
+ case 'R': case 'r': case 0022: /* Resend packet */
+ case 0015: case 0012:
+#ifdef STREAMING
+ if (streaming)
+ return(0);
+#endif /* STREAMING */
+ xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
+ numerrs++;
+ resend(winlo);
+ return(0);
+
+#ifdef datageneral
+ case '\03': /* We're not trapping ^C's with */
+ trap(0); /* signals, so we check here */
+#endif /* datageneral */
+
+ case 'C': case 'c': /* Ctrl-C */
+#ifndef datageneral
+ case '\03':
+#endif /* datageneral */
+
+ case 'E': case 'e': /* Send error packet */
+ case 0005:
+ interrupted = 1;
+ return(-1);
+
+#ifdef CK_CURSES
+ case 0014: /* Ctrl-L to refresh screen */
+ case 'L': case 'l': /* Also accept L (upper, lower) */
+ case 0027: /* Ctrl-W synonym for VMS & Ingres */
+ repaint = 1;
+ return(0);
+#endif /* CK_CURSES */
+
+ case 'T':
+ case 't': /* Turn on debug-log timestamps */
+#ifdef DEBUG
+ {
+ extern int debtim;
+ if (ch == 'T') {
+ debtim = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ "Debug timestamps On... ");
+ } else {
+ debtim = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ "Debug timestamps Off... ");
+ }
+ }
+#endif /* DEBUG */
+ return(0);
+
+ case 'D':
+#ifdef DEBUG
+ if (!deblog) {
+ debopn("debug.log",0);
+ if (deblog) {
+ xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
+ } else {
+ xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
+ }
+ } else {
+ xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
+ }
+ if (deblog)
+ debok = 1;
+#endif /* DEBUG */
+ return(0);
+
+ case 'd': /* Turn off debugging */
+#ifdef DEBUG
+ if (deblog)
+ xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
+ debok = 0;
+#endif /* DEBUG */
+ return(0);
+
+ default: /* Anything else, print message */
+ intmsg(1L);
+ return(0);
+ }
+}
+
+/* I N T M S G -- Issue message about terminal interrupts */
+
+VOID
+#ifdef CK_ANSIC
+intmsg(long n)
+#else
+intmsg(n) long n;
+#endif /* CK_ANSIC */
+/* intmsg */ {
+#ifdef CK_NEED_SIG
+ char buf[80];
+#endif /* CK_NEED_SIG */
+
+ if (!displa || quiet) /* Not if we're being quiet */
+ return;
+ if (server && (!srvdis || n > -1L)) /* Special for server */
+ return;
+#ifdef CK_NEED_SIG
+ buf[0] = NUL; /* Keep compilers happy */
+#endif /* CK_NEED_SIG */
+#ifndef OXOS
+#ifdef SVORPOSIX
+ conchk(); /* Clear out pending escape-signals */
+#endif /* SVORPOSIX */
+#endif /* ! OXOS */
+#ifdef VMS
+ conres(); /* So Ctrl-C will work */
+#endif /* VMS */
+ if ((!server && n == 1L) || (server && n < 0L)) {
+
+#ifdef CK_NEED_SIG
+ if (xfrint) {
+ ckmakmsg(buf,
+ 80,
+ "Type escape character (",
+ dbchr(escape),
+ ") followed by:",
+ NULL
+ );
+ xxscreen(SCR_TN,0,0l,buf);
+ }
+#endif /* CK_NEED_SIG */
+
+ if (xfrint) {
+ if (protocol == PROTO_K) {
+ xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet");
+ xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
+ xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
+ } else {
+ xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
+ }
+ } else {
+ xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
+ }
+ }
+ else xxscreen(SCR_TU,0,0l," ");
+}
+
+#ifndef NODISPLAY
+static int newdpy = 0; /* New display flag */
+static char fbuf[80]; /* Filename buffer */
+static char abuf[80]; /* As-name buffer */
+static char a2buf[80]; /* Second As-name buffer */
+static CK_OFF_T oldffc = 0L;
+static CK_OFF_T dots = 0L;
+static int hpos = 0;
+
+static VOID /* Initialize Serial or CRT display */
+dpyinit() {
+ int m = 0, n = 0;
+ char * s = "";
+
+ newdpy = 0; /* Don't do this again */
+ oldffc = (CK_OFF_T)0; /* Reset this */
+ dots = (CK_OFF_T)0; /* and this.. */
+ oldcps = cps = 0L;
+
+ conoll(""); /* New line */
+ if (what & W_SEND) s = "Sending: "; /* Action */
+ else if (what & W_RECV) s = "Receiving: ";
+ n = (int)strlen(s) + (int)strlen(fbuf);
+ conol(fbuf);
+ m = (int)strlen(abuf) + 4;
+ if (n + m > cmd_cols) {
+ conoll("");
+ n = 0;
+ } else
+ n += m;
+ if (*abuf) {
+ conol(" => ");
+ conol(abuf);
+ }
+ m = (int)strlen(a2buf) + 4;
+ if (n + m > cmd_cols) {
+ conoll("");
+ n = 0;
+ } else
+ n += m;
+ if (*a2buf) {
+ conol(" => ");
+ conol(a2buf);
+ }
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ conoll("");
+ if (fsize > (CK_OFF_T)-1) { /* Size */
+ sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */
+ conol(fbuf); *fbuf = NUL;
+ } else conol("Size: unknown, Type: ");
+ if (binary) { /* Type */
+ switch(binary) {
+ case XYFT_L: conol("labeled"); break;
+ case XYFT_I: conol("image"); break;
+ case XYFT_U: conol("binary undefined"); break;
+ default:
+ case XYFT_B: conol("binary"); break;
+ }
+ } else {
+#ifdef NOCSETS
+ conol("text");
+#else
+ conol("text, ");
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ conol("transparent");
+ } else {
+ if (what & W_SEND) {
+ conol(fcsinfo[fcharset].keyword);
+ conol(" => ");
+ conol(tcsinfo[tcharset].keyword);
+ } else {
+ conol(tcsinfo[tcharset].keyword);
+ conol(" => ");
+ conol(fcsinfo[fcharset].keyword);
+ }
+ }
+#endif /* NOCSETS */
+ }
+#ifdef STREAMING
+ if (streaming)
+ conol(", STREAMING");
+#endif /* STREAMING */
+ conoll("");
+
+ if (fdispla == XYFD_S) { /* CRT field headings */
+/*
+ Define CK_CPS to show current transfer rate.
+ Leave it undefined to show estimated time remaining.
+ Estimated-time-remaining code from Andy Fyfe, not tested on
+ pathological cases.
+*/
+#define CK_CPS
+
+#ifdef CK_CPS
+ conoll(" File Percent Packet");
+ conoll(" Bytes Done CPS Length");
+#else
+ conoll(" File Percent Secs Packet");
+ conoll(" Bytes Done Left Length");
+#endif /* CK_CPS */
+ newdpy = 0;
+ }
+ hpos = 0;
+}
+
+/*
+ showpkt(c)
+ c = completion code: 0 means transfer in progress, nonzero means it's done.
+ Show the file transfer progress counter and perhaps verbose packet type.
+*/
+VOID
+#ifdef CK_ANSIC
+showpkt(char c)
+#else
+showpkt(c) char c;
+#endif /* CK_ANSIC */
+/* showpkt */ {
+
+#ifndef GFTIMER
+ long et; /* Elapsed time, entire batch */
+#endif /* GFTIMER */
+ CK_OFF_T howfar; /* How far into file */
+ long pd; /* Percent done, this file */
+ long tp; /* Transfer rate, entire batch */
+ long ps; /* Packet size, current packet */
+ CK_OFF_T mytfc; /* Local copy of byte counter */
+
+#ifdef GFTIMER
+ CKFLOAT tnow;
+#endif /* GFTIMER */
+
+ if (newdpy) /* Put up filenames, etc, */
+ dpyinit(); /* if they're not there already. */
+
+ howfar = ffc; /* How far */
+/*
+ Calculate CPS rate even if not displaying on screen for use in file
+ transfer statistics.
+*/
+#ifdef GFTIMER
+ tnow = gftimer(); /* Time since we started */
+ ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
+#ifdef CK_RESEND
+ if (what & W_SEND) /* In case we didn't start at */
+ howfar += sendstart; /* the beginning... */
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ pd = -1; /* Percent done. */
+ if (c == NUL) { /* Still going, figure % done */
+ if (!fsize) return; /* Empty file, don't bother */
+ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
+ if (pd > 100) pd = 100; /* Expansion */
+ }
+ if (c != NUL)
+ if (!cxseen && !discard && !czseen)
+ pd = 100; /* File complete, so 100%. */
+
+ mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */
+ tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
+ if (c && (tp == 0))
+ tp = ffc;
+
+ cps = tp; /* Set global variable */
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+
+#else /* Not GFTIMER */
+
+ et = gtimer(); /* Elapsed time */
+ ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
+#ifdef CK_RESEND
+ if (what & W_SEND) /* And if we didn't start at */
+ howfar += sendstart; /* the beginning... */
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ pd = -1; /* Percent done. */
+ if (c == NUL) { /* Still going, figure % done */
+ if (fsize == 0L) return; /* Empty file, don't bother */
+ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
+ if (pd > 100) pd = 100; /* Expansion */
+ }
+ if (c != NUL)
+ if (!cxseen && !discard && !czseen)
+ pd = 100; /* File complete, so 100%. */
+
+
+#ifndef CK_CPS
+/*
+ fsecs = time (from gtimer) that this file started (set in sfile()).
+ Rate so far is ffc / (et - fsecs), estimated time for remaining bytes
+ is (fsize - ffc) / (ffc / (et - fsecs)).
+*/
+ tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0;
+#endif /* CK_CPS */
+
+#ifdef CK_CPS
+ mytfc = (pd < 100) ? tfc + ffc : tfc;
+ tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
+ if (c && (tp == 0)) /* Watch out for subsecond times */
+ tp = ffc;
+
+ cps = tp; /* Set global variable */
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+#endif /* CK_CPS */
+
+#endif /* GFTIMER */
+
+ if (fdispla == XYFD_S) { /* CRT display */
+ char buffer[128];
+ /* These sprintfs should be safe until we have 32-digit numbers */
+
+ if (pd > -1L)
+ sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CR,ckfstoa(howfar),pd,tp,ps);
+ else
+ sprintf(buffer, "%c%9s %8ld%8ld ", CR,ckfstoa(howfar),tp,ps);
+ conol(buffer);
+ hpos = 31;
+ } else if (fdispla == XYFD_R) { /* SERIAL */
+ long i, k;
+ if (howfar - oldffc < 1024) /* Update display every 1K */
+ return;
+ oldffc = howfar; /* Time for new display */
+ k = (howfar / 1024L) - dots; /* How many K so far */
+ for (i = 0L; i < k; i++) {
+ if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
+ conoll("");
+ hpos = 0;
+ }
+ conoc('.'); /* Print a dot for this K */
+ dots++; /* Count it */
+ }
+ }
+}
+
+
+/* C K S C R E E N -- Screen display function */
+
+/*
+ ckscreen(f,c,n,s)
+ f - argument descriptor
+ c - a character or small integer
+ n - a long integer
+ s - a string.
+
+ and global fdispla = SET FILE DISPLAY value:
+
+ XYFD_N = NONE
+ XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy.
+ XYFD_S = CRT: Works on any CRT, writes over current line.
+ XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
+ XYFD_B = BRIEF: Like SERIAL but only filename & completion status.
+ XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN
+*/
+VOID
+#ifdef CK_ANSIC
+ckscreen(int f, char c,CK_OFF_T n,char *s)
+#else
+ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s;
+#endif /* CK_ANSIC */
+/* screen */ {
+ char buf[80];
+ int len; /* Length of string */
+#ifdef UNIX
+#ifndef NOJC
+ int obg;
+_PROTOTYP( VOID conbgt, (int) );
+#endif /* NOJC */
+#endif /* UNIX */
+ int ftp = 0;
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */
+
+ if (!local && !ftp) /* In remote mode - don't do this */
+ return;
+
+ if (!s) s = "";
+
+ if (!fxd_inited) /* Initialize if necessary */
+ fxdinit(fdispla);
+
+#ifdef UNIX
+#ifndef NOJC
+ obg = backgrd; /* Previous background status */
+ conbgt(1); /* See if running in background */
+ if (!backgrd && obg) { /* Just came into foreground? */
+ concb((char)escape); /* Put console back in CBREAK mode */
+ setint(); /* Restore interrupts */
+ }
+#endif /* NOJC */
+#endif /* UNIX */
+
+ if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
+ if (!displa ||
+ (backgrd && bgset) ||
+ fdispla == XYFD_N ||
+ (server && !srvdis)
+ )
+ return;
+
+#ifdef VMS
+ if (f == SCR_FN) /* VMS - shorten the name */
+ s = zrelname(s,zgtdir());
+#endif /* VMS */
+
+ if (dest == DEST_S) /* SET DESTINATION SCREEN */
+ return; /* would interfere... */
+
+#ifdef KUI
+ if (fdispla == XYFD_G) { /* If gui display selected */
+ screeng(f,c,n,s); /* call the gui version */
+ return;
+ }
+#endif /* KUI */
+#ifdef CK_CURSES
+ if (fdispla == XYFD_C) { /* If fullscreen display selected */
+ screenc(f,c,n,s); /* call the fullscreen version */
+ return;
+ }
+#endif /* CK_CURSES */
+
+ len = (int)strlen(s); /* Length of string */
+
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ if (fdispla == XYFD_B) {
+#ifdef NEWFTP
+ if (ftp)
+ printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
+ else
+#endif /* NEWFTP */
+ printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+ }
+#ifdef MAC
+ conoll(""); conol(s); conoc(SP); hpos = len + 1;
+#else
+ ckstrncpy(fbuf,s,80);
+ abuf[0] = a2buf[0] = NUL;
+ newdpy = 1; /* New file so refresh display */
+#endif /* MAC */
+ return;
+
+ case SCR_AN: /* As-name */
+ if (fdispla == XYFD_B) {
+#ifdef COMMENT
+ printf("(as %s) ",s);
+#endif /* COMMENT */
+ return;
+ }
+#ifdef MAC
+ if (hpos + len > 75) { conoll(""); hpos = 0; }
+ conol("=> "); conol(s);
+ if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
+#else
+ if (abuf[0]) {
+ ckstrncpy(a2buf,s,80);
+ } else {
+ ckstrncpy(abuf,s,80);
+ }
+#endif /* MAC */
+ return;
+
+ case SCR_FS: /* File-size */
+ if (fdispla == XYFD_B) {
+ printf(" (%s) (%s byte%s)",
+#ifdef NOICP
+ (binary ? "binary" : "text")
+#else
+ gfmode(binary,0)
+#endif /* NOICP */
+ , ckfstoa(n), n == 1 ? "" : "s");
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+ }
+#ifdef MAC
+ sprintf(buf,", Size: %s",ckfstoa(n)); conoll(buf); hpos = 0;
+#endif /* MAC */
+ return;
+
+ case SCR_XD: /* X-packet data */
+ if (fdispla == XYFD_B)
+ return;
+#ifdef MAC
+ conoll(""); conoll(s); hpos = 0;
+#else
+ ckstrncpy(fbuf,s,80);
+ abuf[0] = a2buf[0] = NUL;
+#endif /* MAC */
+ return;
+
+ case SCR_ST: /* File status */
+ switch (c) {
+ case ST_OK: /* Transferred OK */
+ showpkt('Z'); /* Update numbers one last time */
+ if (fdispla == XYFD_B) {
+#ifdef GFTIMER
+ if (fpxfsecs)
+ printf(": OK (%0.3f sec, %ld cps)",fpxfsecs,
+ (long)((CKFLOAT)ffc / fpxfsecs));
+#else
+ if (xfsecs)
+ printf(": OK (%d sec, %ld cps)",xfsecs,ffc/xfsecs);
+#endif /* GFTIMER */
+ printf("\n");
+ return;
+ }
+ if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
+ conoll(" [OK]"); hpos = 0; /* Print OK message. */
+ if (fdispla == XYFD_S) { /* We didn't show Z packet when */
+ conoc('Z'); /* it came, so show it now. */
+ hpos = 1;
+ }
+ return;
+
+ case ST_DISC: /* Discarded */
+ if (fdispla == XYFD_B) {
+ printf(": DISCARDED\n");
+ return;
+ }
+ if ((hpos += 12) > 78) conoll("");
+ conoll(" [discarded]"); hpos = 0;
+ return;
+
+ case ST_INT: /* Interrupted */
+ if (fdispla == XYFD_B) {
+ printf(": INTERRUPTED\n");
+ return;
+ }
+ if ((hpos += 14) > 78) conoll("");
+ conoll(" [interrupted]"); hpos = 0;
+ return;
+
+ case ST_SIM:
+ if (fdispla == XYFD_B) {
+ if (n == SKP_XNX)
+ printf(": WOULD BE TRANSFERRED (New file)\n");
+ else if (n == SKP_XUP)
+ printf(": WOULD BE TRANSFERRED (Remote file older)\n");
+ else if (n == SKP_SIM)
+ printf(": WOULD BE TRANSFERRED\n");
+ else if (n > 0 && n < nskreason)
+ printf(": SKIPPED (%s)\n",skreason[n]);
+ else
+ printf(": SKIPPED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Would Send: "); /* Action */
+ else if (what & W_RECV) conol("Would Receive: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ }
+ conoll(" [simulated]");
+ return;
+ }
+ if ((hpos += 10) > 78) conoll("");
+ conol(" [simulated]"); hpos = 0;
+ return;
+
+ case ST_SKIP: /* Skipped */
+ if (fdispla == XYFD_B) {
+ if (n == SKP_XNX)
+ printf(": WOULD BE TRANSFERRED (New file)\n");
+ else if (n == SKP_XUP)
+ printf(": WOULD BE TRANSFERRED (Remote file older)\n");
+ else if (n == SKP_SIM)
+ printf(": WOULD BE TRANSFERRED\n");
+ else if (n > 0 && n < nskreason)
+ printf(": SKIPPED (%s)\n",skreason[n]);
+ else
+ printf(": SKIPPED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Sending: "); /* Action */
+ else if (what & W_RECV) conol("Receiving: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ }
+ conoll(" [skipped]");
+ return;
+ }
+ if ((hpos += 10) > 78) conoll("");
+ conol(" "); conol(fbuf);
+ conoll(" [skipped]"); hpos = 0;
+ return;
+
+ case ST_ERR: /* Error */
+ if (fdispla == XYFD_B) {
+ printf(": ERROR: %s\n",s);
+ return;
+ }
+ conoll("");
+ conol("Error: "); conoll(s); hpos = 0;
+ return;
+
+ case ST_MSG: /* Message */
+#ifdef NEWFTP
+ if (fdispla == XYFD_B) {
+ if (ftp && ftp_deb)
+ printf(": MESSAGE: %s\n",s);
+ return;
+ }
+#endif /* NEWFTP */
+ conoll("");
+ conol("Message: ");
+ conoll(s);
+ hpos = 0;
+ return;
+
+ case ST_REFU: /* Refused */
+ if (fdispla == XYFD_B) {
+ printf(": REFUSED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Sending: "); /* Action */
+ else if (what & W_RECV) conol("Receiving: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ conoll("");
+ }
+ conol("Refused: "); conoll(s);
+ return;
+ }
+ conoll("");
+ conol("Refused: "); conoll(s); hpos = 0;
+ return;
+
+ case ST_INC: /* Incomplete */
+ if (fdispla == XYFD_B) {
+ printf(": INCOMPLETE\n");
+ return;
+ }
+ if ((hpos += 12) > 78) conoll("");
+ conoll(" [incomplete]"); hpos = 0;
+ return;
+
+ default:
+ conoll("*** screen() called with bad status ***");
+ hpos = 0;
+ return;
+ }
+
+#ifdef MAC
+ case SCR_PN: /* Packet number */
+ if (fdispla == XYFD_B) {
+ return;
+ }
+ ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
+ conol(buf); hpos += (int)strlen(buf); return;
+#endif /* MAC */
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (fdispla == XYFD_B)
+ return;
+ if (c == 'Y') return; /* Don't bother with ACKs */
+ if (c == 'D') { /* In data transfer phase, */
+ showpkt(NUL); /* show progress. */
+ return;
+ }
+#ifndef AMIGA
+ if (hpos++ > 77) { /* If near right margin, */
+ conoll(""); /* Start new line */
+ hpos = 0; /* and reset counter. */
+ }
+#endif /* AMIGA */
+ if (c == 'Z' && fdispla == XYFD_S)
+ return;
+ else
+ conoc(c); /* Display the packet type. */
+#ifdef AMIGA
+ if (c == 'G') conoll(""); /* New line after G packets */
+#endif /* AMIGA */
+ return;
+
+ case SCR_TC: /* Transaction complete */
+ if (xfrbel) bleep(BP_NOTE);
+ if (fdispla == XYFD_B) { /* Brief display... */
+ if (filcnt > 1) {
+ long fx;
+ fx = filcnt - filrej;
+ printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s"));
+ printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s"));
+#ifdef GFTIMER
+ printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
+#else
+ printf(", %ld sec, %ld cps", tsecs, tfcps);
+#endif /* GFTIMER */
+ printf(".\n");
+ }
+ } else {
+ conoll("");
+ }
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+
+ case SCR_EM: /* Error message */
+ if (fdispla == XYFD_B) {
+ printf(" ERROR: %s\n",s);
+ return;
+ }
+ conoll(""); conoc('?'); conoll(s); hpos = 0; return;
+
+ case SCR_WM: /* Warning message */
+ if (fdispla == XYFD_B) {
+ printf(" WARNING: %s\n",s);
+ return;
+ }
+ conoll(""); conoll(s); hpos = 0; return;
+
+ case SCR_MS: /* Message from other Kermit */
+ if (fdispla == XYFD_B) {
+ printf(" MESSAGE: %s\n",s);
+ return;
+ }
+ conoll(""); conoll(s); hpos = 0; return;
+
+ case SCR_TU: /* Undelimited text */
+ if (fdispla == XYFD_B)
+ return;
+ if ((hpos += len) > 77) { conoll(""); hpos = len; }
+ conol(s); return;
+
+ case SCR_TN: /* Text delimited at beginning */
+ if (fdispla == XYFD_B)
+ return;
+ conoll(""); conol(s); hpos = len; return;
+
+ case SCR_TZ: /* Text delimited at end */
+ if (fdispla == XYFD_B)
+ return;
+ if ((hpos += len) > 77) { conoll(""); hpos = len; }
+ conoll(s); return;
+
+ case SCR_QE: /* Quantity equals */
+ if (fdispla == XYFD_B)
+ return;
+ ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
+ conoll(buf); hpos = 0; return;
+
+ case SCR_CW: /* Close fullscreen window */
+ return; /* No window to close */
+
+ case SCR_CD:
+ return;
+
+ default:
+ conoll("*** screen() called with bad object ***");
+ hpos = 0;
+ return;
+ }
+}
+#endif /* NODISPLAY */
+
+/* E R M S G -- Nonfatal error message */
+
+/* Should be used only for printing the message text from an Error packet. */
+
+VOID
+ermsg(msg) char *msg; { /* Print error message */
+ debug(F110,"ermsg",msg,0);
+ if (local)
+ xxscreen(SCR_EM,0,0L,msg);
+ tlog(F110,"Protocol Error:",msg,0L);
+}
+#endif /* NOXFER */
+
+VOID
+setseslog(x) int x; {
+ seslog = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_CAPTURE,x,0);
+#endif /* KUI */
+}
+
+VOID
+doclean(fc) int fc; { /* General cleanup */
+#ifdef OS2ORUNIX
+ extern int ttyfd;
+#endif /* OS2ORUNIX */
+ extern int keep;
+ extern int exithangup;
+#ifndef NOXFER
+ extern char filnam[];
+#endif /* NOXFER */
+#ifndef NOICP
+ int x;
+
+ if (fc > 0)
+ dostop(); /* Stop all command files and end macros */
+#endif /* NOICP */
+
+#ifndef NOXFER
+ if (pktlog) {
+ *pktfil = '\0';
+ pktlog = 0;
+ zclose(ZPFILE);
+ }
+#endif /* NOXFER */
+ if (seslog) {
+ *sesfil = '\0';
+ setseslog(0);
+ zclose(ZSFILE);
+ }
+#ifdef TLOG
+ if (tralog) {
+ tlog(F100,"Transaction Log Closed","",0L);
+ *trafil = '\0';
+ tralog = 0;
+ zclose(ZTFILE);
+ }
+#endif /* TLOG */
+
+ debug(F100,"doclean calling dologend","",0);
+ dologend(); /* End current log record if any */
+#ifdef COMMENT
+ if (dialog) { /* If connection log open */
+ dialog = 0;
+ *diafil = '\0'; /* close it. */
+ zclose(ZDIFIL);
+ }
+#endif /* COMMENT */
+
+#ifndef NOICP
+#ifndef NOSPL
+ zclose(ZRFILE); /* READ and WRITE files, if any. */
+ zclose(ZWFILE);
+#ifndef NOXFER
+ zclose(ZIFILE); /* And other files too */
+ x = chkfn(ZOFILE); /* Download in progress? */
+ debug(F111,"doclean chkfn ZOFILE",filnam,x);
+ debug(F111,"doclean keep","",keep);
+ zclose(ZOFILE); /* Close output file */
+ if (x > 0 && !keep) { /* If it was being downloaded */
+ if (filnam[0])
+ x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */
+ debug(F111,"doclean download filename",filnam,x);
+ }
+#endif /* NOXFER */
+ zclose(ZSYSFN);
+ zclose(ZMFILE);
+
+ if (fc < 1) { /* RESETing, not EXITing */
+#ifdef DEBUG
+ if (deblog) { /* Close the debug log. */
+ *debfil = '\0';
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#endif /* DEBUG */
+ return;
+ }
+#endif /* NOSPL */
+#endif /* NOICP */
+
+#ifndef NOLOCAL
+ debug(F101,"doclean exithangup","",exithangup);
+ if (local && exithangup) { /* Close communication connection */
+ extern int haslock;
+ int x;
+
+ x = ttchk();
+ debug(F101,"doclean ttchk()","",x);
+#ifdef OS2ORUNIX
+ debug(F101,"doclean ttyfd","",ttyfd);
+#endif /* OS2ORUNIX */
+ if (x >= 0
+#ifdef OS2
+ || ttyfd != -1
+#else
+#ifdef UNIX
+ || haslock /* Make sure we get lockfile! */
+ || (!network && ttyfd > -1)
+#endif /* UNIX */
+#endif /* OS2 */
+ ) {
+ extern int wasclosed, whyclosed;
+ debug(F100,"doclean hanging up and closing","",0);
+ if (msgflg) {
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ printf("Closing %s...",ttname);
+ }
+#ifndef NODIAL
+ mdmhup(); /* Hangup the modem??? */
+#endif /* NODIAL */
+ ttclos(0); /* Close external line, if any */
+ if (msgflg) {
+ printf("OK\n");
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ }
+ if (wasclosed) {
+ whyclosed = WC_CLOS;
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_close",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ wasclosed = 0;
+ /* printf("ON_CLOSE DOCLEAN\n"); */
+ *(mactab[k].kwd) = NUL; /* See comment below */
+ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ wasclosed = 0;
+ }
+ }
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
+ local = dfloc; /* And default remote/local status */
+ }
+#ifdef DEBUG
+ else if (local) debug(F100,"doclean hangup/close skipped","",0);
+#endif /* DEBUG */
+#endif /* NOLOCAL */
+
+#ifdef NEWFTP
+ ftpbye(); /* If FTP connection open, close it */
+#endif /* NEWFTP */
+
+#ifdef IKSD
+ if (inserver)
+ ttclos(0); /* If IKSD, close socket */
+#endif /* IKSD */
+
+#ifndef NOSPL
+/*
+ If a macro named "on_exit" is defined, execute it. Also remove it from the
+ macro table, in case its definition includes an EXIT or QUIT command, which
+ would cause much recursion and would prevent the program from ever actually
+ EXITing.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_exit"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */
+ if (k >= 0) { /* If found, */
+#ifdef COMMENT
+ /* This makes a mess if ON_EXIT itself executes macros */
+ *(mactab[k].kwd) = NUL; /* poke its name from the table, */
+#else
+ /* Replace the keyword with something that doesn't wreck the */
+ /* order of the keyword table */
+ ckstrncpy(mactab[k].kwd,"on_exxx",8);
+#endif /* COMMENT */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+/*
+ Put console terminal back to normal. This is done here because the
+ ON_EXIT macro calls the parser, which meddles with console terminal modes.
+*/
+ conres(); /* Restore console terminal. */
+
+#ifdef COMMENT
+/* Should be no need for this, and maybe it's screwing things up? */
+ connoi(); /* Turn off console interrupt traps */
+#endif /* COMMENT */
+
+ /* Delete the Startup File if we are supposed to. */
+#ifndef NOICP
+ {
+ extern int DeleteStartupFile;
+ debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
+ if (DeleteStartupFile) {
+ int rc = zdelet(cmdfil);
+ debug(F111,"doclean zdelet",cmdfil,rc);
+ }
+ }
+#endif /* NOICP */
+ syscleanup(); /* System-dependent cleanup, last */
+}
+
+/* D O E X I T -- Exit from the program. */
+
+/*
+ First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
+ If second arg is -1, take 1st arg literally.
+ If second arg is not -1, work it into the exit code.
+*/
+VOID
+doexit(exitstat,code) int exitstat, code; {
+ extern int x_logged, quitting;
+#ifdef OS2
+ extern int display_demo;
+ extern int SysInited;
+#endif /* OS2 */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+ extern int krb4_autodel;
+#endif /* KRB4 */
+#ifdef KRB5
+ extern int krb5_autodel;
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef VMS
+ char envstr[64];
+ static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
+ static struct dsc$descriptor_s symval;
+#endif /* VMS */
+ int i;
+
+#ifdef DEBUG
+#ifdef USE_LUCACHE
+ extern long lucalls, luhits, xxhits, luloop;
+ extern int lusize;
+#endif /* USE_LUCACHE */
+#ifndef NOSPL
+ extern int cmdstats[];
+#endif /* NOSPL */
+
+ quitting++;
+
+#ifdef OS2
+ if ( !SysInited ) {
+ static int initing = 0;
+ if ( initing )
+ exit(253);
+ initing = 1;
+ sysinit();
+ }
+#endif /* OS2 */
+
+ if (deblog) {
+#ifdef USE_LUCACHE
+ debug(F101,"lookup cache size","",lusize);
+ debug(F101,"lookup calls ....","",lucalls);
+ debug(F101,"lookup cache hits","",luhits);
+ debug(F101,"lookup start hits","",xxhits);
+ debug(F101,"lookup loop iterations","",luloop);
+#endif /* USE_LUCACHE */
+#ifndef NOSPL
+ for (i = 0; i < 256; i++) {
+ if (cmdstats[i])
+ debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
+ }
+#endif /* NOSPL */
+ debug(F101,"doexit exitstat","",exitstat);
+ debug(F101,"doexit code","",code);
+ debug(F101,"doexit xitsta","",xitsta);
+ }
+#endif /* DEBUG */
+
+#ifdef CK_KERBEROS
+ /* If we are automatically destroying Kerberos credentials on Exit */
+ /* do it now. */
+#ifdef KRB4
+ if (krb4_autodel == KRB_DEL_EX) {
+ extern struct krb_op_data krb_op;
+ krb_op.version = 4;
+ krb_op.cache = NULL;
+ ck_krb4_destroy(&krb_op);
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (krb5_autodel == KRB_DEL_EX) {
+ extern struct krb_op_data krb_op;
+ extern char * krb5_d_cc;
+ krb_op.version = 5;
+ krb_op.cache = krb5_d_cc;
+ ck_krb5_destroy(&krb_op);
+ }
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (SysInited)
+ {
+#ifdef DCMDBUF
+ extern struct cmdptr *cmdstk;
+#else
+ extern struct cmdptr cmdstk[];
+#endif /* DCMDBUF */
+ extern int tt_status[];
+ extern int vmode;
+
+ /* If there is a demo screen to be displayed, display it */
+ if (display_demo) {
+ demoscrn(VCMD);
+ display_demo = 0;
+ }
+#ifndef KUI
+ /* This is going to be hideous. If we have a status line */
+ /* in the command window turn it off before we exit. */
+
+ if ( tt_status[VCMD] && vmode == VCMD ) {
+ domac("_clear_statusline","set command statusline off",
+ cmdstk[cmdlvl].ccflgs);
+ delmac("_clear_statusline",1);
+ RequestScreenMutex(-1);
+ VscrnIsDirty(vmode);
+ ReleaseScreenMutex();
+ while ( IsVscrnDirty(vmode) )
+ msleep(200);
+ RequestScreenMutex(-1);
+ ReleaseScreenMutex();
+ }
+#endif /* KUI */
+ DialerSend(OPT_KERMIT_EXIT,exitstat);
+#ifndef KUI
+ debug(F100,"doexit about to msleep","",0);
+
+ if ( isWin95() )
+ msleep(250);
+#endif /* KUI */
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && x_logged) {
+#ifndef NOSPL
+/*
+ If a macro named "on_logout" is defined, execute it. Also remove it from the
+ macro table, in case its definition includes an EXIT or QUIT command, which
+ would cause much recursion and would prevent the program from ever actually
+ EXITing.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_logout"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
+ if (k >= 0) { /* If found, */
+ *(mactab[k].kwd) = NUL; /* poke its name from the table, */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ zvlogout();
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+ debug(F100,"doexit about to doclean","",0);
+ doclean(1); /* Clean up most things */
+
+#ifdef VMS
+ if (code == -1)
+ code = 0; /* Since we set two different items */
+ sprintf(envstr,"%d", exitstat | code); /* SAFE */
+ symval.dsc$w_length = (int)strlen(envstr);
+ symval.dsc$a_pointer = envstr;
+ symval.dsc$b_class = DSC$K_CLASS_S;
+ symval.dsc$b_dtype = DSC$K_DTYPE_T;
+ i = 2; /* Store in global table */
+#ifdef COMMENT /* Martin Zinser */
+ LIB$SET_SYMBOL(&symnam, &symval, &i);
+#else
+ lib$set_symbol(&symnam, &symval, &i);
+#endif /* COMMENT */
+ if (exitstat == BAD_EXIT)
+ exitstat = SS$_ABORT | STS$M_INHIB_MSG;
+ if (exitstat == GOOD_EXIT)
+ exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
+#else /* Not VMS */
+ if (code != -1) /* Take 1st arg literally */
+ exitstat |= code;
+#endif /* VMS */
+
+#ifdef IKSD
+#ifdef IKSDB
+ debug(F101,"doexit ikdbopen","",ikdbopen);
+ if (ikdbopen && dbfp) { /* If IKSD database open */
+ int x;
+ x = freeslot(mydbslot); /* Free our slot... */
+ debug(F101,"doexit freeslot","",x);
+ fclose(dbfp); /* and close it. */
+ }
+#endif /* IKSDB */
+#endif /* IKSD */
+
+/* We have put this off till the very last moment... */
+
+#ifdef DEBUG
+ if (deblog) { /* Close the debug log. */
+ debug(F101,"C-Kermit EXIT status","",exitstat);
+ *debfil = '\0';
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ _exit(exitstat); /* Exit from C-Kermit (no matter what) */
+#else /* OS2 */
+ exit(exitstat); /* Exit from C-Kermit */
+#endif /* OS2 */
+}
+
+VOID
+bgchk() { /* Check background status */
+ if (bgset < 0) { /* They didn't type SET BACKGROUND */
+#ifdef VMS /* Set prompt flag based on */
+ pflag = !batch; /* what we detected at startup. */
+#else
+ pflag = !backgrd;
+#endif /* VMS */
+ } else { /* Otherwise SET BACKGROUND value */
+ pflag = (bgset == 0 ? 1 : 0);
+ }
+
+#ifndef NOICP
+ /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
+ if (!xcmdsrc)
+ msgflg = (pflag == 0) ? 0 : !quiet;
+ else msgflg = 0;
+#else
+ msgflg = 0;
+#endif /* NOICP */
+}
+
+/* Set console interrupts */
+
+VOID
+setint() { /* According to SET COMMAND INTERRUP */
+ int x = 0;
+ if (cmdint) x |= 1;
+ if (xsuspend) x |= 2;
+ debug(F101,"setint","",x);
+
+ switch (x) { /* Set the desired combination */
+ case 0: connoi(); break; /* No interrupts */
+ case 1: conint(trap,SIG_IGN); break;
+ case 2: conint(SIG_IGN,stptrap); break;
+ case 3: conint(trap,stptrap); break;
+ }
+ bgchk(); /* Check background status */
+}
+
+#ifdef DEBUG
+/* D E B U G -- Enter a record in the debugging log */
+
+/*
+ Call with a format, two strings, and a number:
+ f - Format, a bit string in range 0-7.
+ If bit x is on, then argument number x is printed.
+ s1 - String, argument number 1. If selected, printed as is.
+ s2 - String, argument number 2. If selected, printed in brackets.
+ n - Long int, argument 3. If selected, printed preceded by equals sign.
+
+ f=0 is special: print s1,s2, and interpret n as a char.
+
+ f=F011 (3) is also special; in this case s2 is interpeted as a counted
+ string that might contain NULs. n is the length. If n is negative, this
+ means the string has been truncated and ".." should be printed after the
+ first n bytes. NUL and LF bytes are printed as "<NUL>" and "<LF>".
+
+ Globals:
+ deblog: nonzero if debug log open.
+ debok: nonzero if ok to write entries.
+*/
+/*
+ WARNING: Don't change DEBUFL without changing sprintf() formats below,
+ accordingly.
+*/
+#define DBUFL 4000
+/*
+ WARNING: This routine is not thread-safe, especially when Kermit is
+ executing on multiple CPUs -- as different threads write to the same
+ static buffer, the debug statements are all interleaved. To be fixed
+ later...
+*/
+static char *dbptr = (char *)0;
+
+int
+#ifdef CK_ANSIC
+dodebug(int f, char *s1, char *s2, CK_OFF_T n)
+#else
+dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n;
+#endif /* CK_ANSIC */
+/* dodebug */ {
+ char *sp;
+ int len1, len2;
+ extern int debtim;
+#ifdef OS2
+ extern int SysInited;
+#endif /* OS2 */
+
+ if (!deblog || !debok)
+ return(0);
+
+#ifdef COMMENT
+ /* expensive... */
+ if (!chkfn(ZDFILE)) /* Debug log not open, don't. */
+ return(0);
+#endif /* COMMENT */
+ if (!dbptr) { /* Allocate memory buffer */
+ dbptr = malloc(DBUFL+4); /* This only happens once */
+ if (!dbptr) {
+ zclose(ZDFILE);
+ return(0);
+ }
+ }
+/*
+ This prevents infinite recursion in case we accidentally put a debug()
+ call in this routine, or call another routine that contains debug() calls.
+ From this point on, all returns from this return must be via goto xdebug,
+ which sets deblog back to 1.
+*/
+#ifdef OS2
+ if (SysInited) {
+ if (RequestDebugMutex(30000))
+ goto xdebug;
+ }
+#else /* OS2 */
+ deblog = 0; /* Prevent infinite recursion */
+#endif /* OS2 */
+
+ if (debtim) { /* Timestamp */
+ char *tb, tsbuf[48];
+ ztime(&tb);
+ ckstrncpy(tsbuf,tb,32);
+ if (ztmsec > -1L) {
+ sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
+ } else {
+ tsbuf[19] = ':';
+ tsbuf[20] = SP;
+ tsbuf[21] = NUL;
+ }
+ zsout(ZDFILE,tsbuf+11);
+ }
+ if (!s1) s1="(NULL)";
+ if (!s2) s2="(NULL)";
+
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+
+#ifdef COMMENT
+/*
+ This should work, but it doesn't.
+ So instead we'll cope with overflow via sprintf formats.
+ N.B.: UNFORTUNATELY, this means we have to put constants in the
+ sprintf formats.
+*/
+ if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
+ x = (int) strlen(s1) + (int) strlen(s2) + 18;
+ if (x > dbufl) { /* Longer than buffer? */
+ if (dbptr) /* Yes, free previous buffer */
+ free(dbptr);
+ dbptr = (char *) malloc(x + 2); /* Allocate a new one */
+ if (!dbptr) {
+ zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ } else {
+ dbufl = x;
+ sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
+ zsoutl(ZDFILE,dbptr);
+ }
+ }
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/* The aforementioned sprintf() formats were like this: */
+ if (n > 31 && n < 127)
+ sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
+ else if (n > 159 && n < 256)
+ sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
+ else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
+/*
+ But, naturally, it turns out these are not portable either, so now
+ we do the stupidest possible thing.
+*/
+#endif /* COMMENT */
+
+#ifdef BIGBUFOK
+/* Need to accept longer strings when debugging authenticated connections */
+ if (f == F010) {
+ if (len2 + 2 >= DBUFL) s2 = "(string too long)";
+ } else if (f != F011 && f != F100) {
+ if (len1 > 100) s1 = "(string too long)";
+ if (len2 + 101 >= DBUFL) s2 = "(string too long)";
+ }
+#else
+ if (f != F011) {
+ if (len1 > 100) s1 = "(string too long)";
+ if (len2 + 101 >= DBUFL) s2 = "(string too long)";
+ }
+#endif /* BIGBUFOK */
+
+ sp = dbptr;
+
+ switch (f) { /* Write log record according to format. */
+ case F000: /* 0 = print both strings, and n as a char. */
+ if (len2 > 0) {
+ if ((n > 31 && n < 127) || (n > 159 && n < 256))
+ sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
+ else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n);
+ } else {
+ if ((n > 31 && n < 127) || (n > 159 && n < 256))
+ sprintf(sp,"%s=%c\n",s1,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
+ else sprintf(sp,"%s=0x%lX\n",s1,(long)n);
+ }
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+
+ case F001: /* 1, "=n" */
+#ifdef COMMENT
+ /* This was never used */
+ sprintf(sp,"=%s\n",ckfstoa(n));
+#else
+ /* Like F111, but shows number n in hex */
+ ckmakxmsg(sp,DBUFL,
+ s1,
+ (*s1 ? ":" : ""),
+ s2,
+ (*s2 ? ":" : ""),
+ ckltox(n),
+ "\n",
+ NULL,NULL,NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+
+/*
+ This one was never used so (October 2000) we now use it like F011,
+ except in this case we treat s2 as NUL terminated.
+*/
+ case F010:
+ n = -debxlen;
+/*
+ This one treats n as the length of the string s2, which may contain NULs.
+ It's good for logging NUL-bearing data in the debug log.
+*/
+ case F011: {
+ int i, j, contd = 0;
+ char * p = s2, *pbuf = NULL; /* p = source pointer */
+ int m; /* pbuf = destination pointer */
+
+ if (f == F011) {
+ if (n < 0) { /* n = size of source */
+ n = 0 - n; /* Negative means to add "..." */
+ contd = 1;
+ }
+ } else {
+ int x, flag = 0;
+ x = strlen(s2);
+ if (n < 0) {
+ flag = 1;
+ n = 0 - n;
+ }
+ if (x < n)
+ n = x;
+ }
+ if (n == 0) /* 0 means do nothing */
+ goto xdebug;
+ m = DBUFL - 8; /* Get size for interpreted part */
+ if (n > m) /* Ensure requested size not too big */
+ n = m;
+ pbuf = dbptr; /* Construction pointer */
+ i = 0;
+ pbuf[i++] = '['; /* Interpret the string into it */
+ for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
+ if (*p == LF) {
+ if (i >= m-4)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'L';
+ pbuf[i++] = 'F';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p == CR) {
+ if (i >= m-4)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'C';
+ pbuf[i++] = 'R';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p == HT) {
+ if (i >= m-5)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'T';
+ pbuf[i++] = 'A';
+ pbuf[i++] = 'B';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p) {
+ pbuf[i++] = *p;
+ continue;
+ } else {
+ if (i >= m-5)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'N';
+ pbuf[i++] = 'U';
+ pbuf[i++] = 'L';
+ pbuf[i++] = '>';
+ continue;
+ }
+ }
+ if (i < m-2 && (*p || contd)) {
+ pbuf[i++] = '.';
+ pbuf[i++] = '.';
+ }
+ pbuf[i++] = ']';
+ pbuf[i] = NUL;
+ if (zsout(ZDFILE,s1) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+ if (zsoutl(ZDFILE,pbuf) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
+ }
+#endif /* CKSYSLOG */
+ }
+ break;
+
+ case F100: /* 4, "s1" */
+ if (zsoutl(ZDFILE,s1) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",s1,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F101: /* 5, "s1=n" */
+ sprintf(sp,"%s=%s\n",s1,ckfstoa(n));
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F110: /* 6, "s1[s2]" */
+ sprintf(sp,"%s[%s]\n",s1,s2);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F111: /* 7, "s1[s2]=n" */
+ sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n));
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ default:
+ sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ }
+ xdebug: /* Common exit point */
+#ifdef OS2
+ if (SysInited)
+ ReleaseDebugMutex();
+#else /* OS2 */
+ deblog = 1; /* Restore this */
+#endif /* OS2 */
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+dohexdump(CHAR *msg, CHAR *st, int cnt)
+#else
+dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
+#endif /* CK_ANSIC */
+/* dohexdump */ {
+ int i = 0, j = 0, k = 0;
+ char tmp[8];
+#ifdef OS2
+ extern int SysInited;
+#endif /* OS2 */
+
+ if (!deblog) return(0); /* If no debug log, don't. */
+ if (!dbptr) { /* Allocate memory buffer */
+ dbptr = malloc(DBUFL+1); /* This only happens once */
+ if (!dbptr) {
+ deblog = 0;
+ zclose(ZDFILE);
+ return(0);
+ }
+ }
+
+#ifdef OS2
+ if (SysInited) {
+ if (RequestDebugMutex(30000))
+ goto xdebug;
+ }
+#else /* OS2 */
+ deblog = 0; /* Prevent infinite recursion */
+#endif /* OS2 */
+
+ if (msg != NULL) {
+ ckmakxmsg(dbptr,
+ DBUFL,
+ "HEXDUMP: ",
+ (char *)msg,
+ " (",
+ ckitoa(cnt),
+ " bytes)\n",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ } else {
+ ckmakmsg(dbptr,
+ DBUFL,
+ "HEXDUMP: (",
+ ckitoa(cnt),
+ " bytes)\n",
+ NULL
+ );
+ zsout(ZDFILE,dbptr);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ }
+ for (i = 0; i < cnt; i++) {
+ dbptr[0] = '\0';
+ for (j = 0 ; (j < 16); j++) {
+ if ((i + j) < cnt)
+ sprintf(tmp,
+ "%s%02x ",
+ (j == 8 ? "| " : ""),
+ (CHAR) st[i + j]
+ );
+ else
+ sprintf(tmp,
+ "%s ",
+ (j == 8 ? "| " : "")
+ );
+ ckstrncat(dbptr,tmp,DBUFL+1);
+ }
+ ckstrncat(dbptr," ",DBUFL+1);
+ for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
+ sprintf(tmp,
+ "%s%c",
+ (k == 8 ? " " : ""),
+ isprint(st[i + k]) ? st[i + k] : '.'
+ );
+ ckstrncat(dbptr,tmp,DBUFL+1);
+ }
+ ckstrncat(dbptr,"\n",DBUFL+1);
+ i += j - 1;
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ } /* end for */
+
+
+ xdebug:
+#ifdef OS2
+ if (SysInited)
+ ReleaseDebugMutex();
+#else /* OS2 */
+ deblog = 1;
+#endif /* OS2 */
+ return(0);
+}
+#endif /* DEBUG */
+
+/* Session Log... */
+
+int tsstate = 0;
+
+VOID
+#ifdef OS2
+logchar(unsigned short c)
+#else /* OS2 */
+#ifdef CK_ANSIC
+logchar(char c)
+#else
+logchar(c) char c;
+#endif /* CK_ANSIC */
+#endif /* OS2 */
+/* logchar */ { /* Log character c to session log */
+ extern int slognul;
+ int oktolog = 0;
+#ifndef NOLOCAL
+ if (!seslog)
+ return;
+
+ if ((sessft != XYFT_T) || (
+#ifdef UNIX
+ c != '\r' &&
+#else
+#ifdef datageneral
+ c != '\r' &&
+#else
+#ifdef STRATUS
+ c != '\r' &&
+#else
+#ifdef AMIGA
+ c != '\r' &&
+#else
+#ifdef GEMDOS
+ c != '\r' &&
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* UNIX */
+#ifdef OSK
+ c != '\n' &&
+#else
+#ifdef MAC
+ c != '\n' &&
+#endif /* MAC */
+#endif /* OSK */
+ c != XON &&
+ c != XOFF))
+ oktolog = 1;
+ if (c == '\0' && !sessft) /* NUL in text mode */
+ if (slognul) oktolog = 1; /* only if padding (2009/10/22) */
+ if (!oktolog)
+ return;
+ if (slogts) { /* Log is timestamped */
+ if (tsstate == 0) { /* State = between-lines */
+ char * p; /* zstime() pointer */
+ char ts[48]; /* timestamp buffer */
+ ztime(&p); /* Get asctime() string */
+ ckstrncpy(ts,p,32); /* Make safe copy */
+ if (ztmsec > -1L) { /* Add msecs if we have them */
+ sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
+ } else {
+ ts[19] = ':';
+ ts[20] = SP;
+ ts[21] = NUL;
+ }
+ if (zsout(ZSFILE,&ts[11]) < 0)
+ goto xlogchar;
+ }
+ }
+ if (c == '\n') /* At end of line? */
+ tsstate = 0; /* yes */
+ else
+ tsstate = 1; /* no */
+ if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
+ goto xlogchar;
+ if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */
+ if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */
+ goto xlogchar;
+ }
+ return;
+
+ xlogchar:
+ conoll("");
+ conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
+ setseslog(0);
+ zclose(ZSFILE);
+#endif /* NOLOCAL */
+}
+
+VOID
+logstr(s, len) char * s; int len; { /* Log string to session log */
+#ifndef NOLOCAL
+ int n = 0;
+ if (!s)
+ return;
+ while (seslog && (n < len))
+ logchar(s[n++]);
+#endif /* NOLOCAL */
+}
+
+#ifdef CK_CURSES
+int
+ck_repaint() {
+ repaint = 1;
+ return(0);
+}
+
+#ifdef STRATUS
+/* VOS has curses but no tgetent() */
+int
+tgetent(s1, s2) char * s1, * s2; {
+ return(1);
+}
+#endif /* STRATUS */
+
+#ifdef VMS
+#ifdef __DECC
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* __DECC */
+#endif /* VMS */
+
+/*
+ There are three different ways to do fullscreen on VMS.
+ 1. Use the real curses library, VAXCCURSE.
+ 2. Use do-it-yourself code.
+ 3. Use the Screen Manager, SMG$.
+
+ Method 1 doesn't work quite right; you can't call endwin(), so once you've
+ started curses mode, you can never leave.
+
+ Method 2 doesn't optimize the screen, and so much more time is spent in
+ screen writes. This actually causes file transfers to fail because the
+ tty device input buffer can be overrun while the screen is being updated,
+ especially on a slow MicroVAX that has small typeahead buffers.
+
+ In the following #ifdef block, #define one of them and #undef the other 2.
+
+ So now let's try method 3...
+*/
+#ifdef VMS
+#define CK_SMG /* Screen Manager */
+#undef MYCURSES /* Do-it-yourself */
+#undef VMSCURSE /* VAXCCURSE library */
+#endif /* VMS */
+/*
+ But just before New Years, 2000, the SMG library seemed to break on
+ both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
+ So back to MYCURSES, which works fine.
+*/
+#ifdef VMS
+#undef CK_SMG
+#define MYCURSES
+#endif /* VMS */
+
+#ifdef MYCURSES
+#define stdscr 0
+#ifdef CK_WREFRESH
+#undef CK_WREFRESH
+#endif /* CK_WREFRESH */
+#endif /* MYCURSES */
+
+/* S C R E E N C -- Screen display function, uses curses */
+
+/* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
+
+/* Avoid conficts with curses.h */
+
+#ifdef QNX
+/* Same as ckcasc.h, but in a different radix... */
+#ifdef ESC
+#undef ESC
+#endif /* ESC */
+#endif /* QNX */
+
+#ifndef MYCURSES
+#undef VOID /* This was defined in ckcdeb.h */
+#endif /* MYCURSES */
+
+#undef BS /* These were defined in ckcasc.h */
+#undef CR
+#undef NL
+#undef SO
+#ifdef US
+#undef US
+#endif /* US */
+#undef SP /* Used in ncurses */
+#define CHR_SP 32 /* Use this instead */
+
+#ifdef VMS /* VMS fullscreen display */
+#ifdef MYCURSES /* Do-it-yourself method */
+extern int isvt52; /* From CKVTIO.C */
+#define printw printf
+#else
+#ifdef VMSCURSE /* VMS curses library VAXCCURSE */
+#include <curses.h>
+/* Note: Screen manager doesn't need a header file */
+#endif /* VMSCURSE */
+#endif /* MYCURSES */
+#else /* Not VMS */
+#ifdef MYCURSES /* Do-it-yourself method */
+#define isvt52 0 /* Used by OS/2, VT-100/ANSI always */
+#ifdef CKXPRINTF
+#define printw ckxprintf
+#else /* CKXPRINTF */
+#ifdef KUI
+#define printw Vscrnprintw
+#else /* KUI */
+#define printw printf
+#endif /* KUI */
+#endif /* CKXPRINTF */
+#else /* Use real curses */
+#ifdef CK_NCURSES /* or ncurses... */
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in ncurses.h */
+#endif /* CKXPRINTF */
+#include <ncurses.h>
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#else /* Not ncurses */
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in curses.h */
+#endif /* CKXPRINTF */
+#ifdef M_XENIX /* SCO XENIX... */
+#ifdef M_TERMCAP
+#undef M_TERMCAP
+#endif /* M_TERMCAP */
+#ifndef M_TERMINFO
+#define M_TERMINFO
+#endif /* M_TERMINFO */
+#endif /* M_XENIX */
+#ifdef RTAIX
+#undef NLS /* Avoid 'redeclaration of free'. */
+#endif /* RTAIX */
+#include <curses.h>
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#endif /* CK_NCURSES */
+#endif /* MYCURSES */
+#endif /* VMS */
+
+#ifdef BUG999
+_PROTOTYP(int tgetent,(char *, char *));
+_PROTOTYP(char *tgetstr,(char *, char **));
+_PROTOTYP(int tputs,(char *, int, int (*)()));
+_PROTOTYP(char *tgoto,(const char *, int, int));
+#endif /* BUG999 */
+#ifdef linux
+#include <term.h>
+#endif
+
+#endif /* CK_CURSES */
+
+/* F X D I N I T -- File Xfer Display Initialization */
+
+#ifdef CK_CURSES
+#ifndef MYCURSES
+#ifndef CK_SMG
+static
+#ifdef CK_ANSIC
+/* Can't use VOID because of curses.h */
+void
+ck_termset(int);
+#else
+ck_termset();
+#endif /* CK_ANSIC */
+#endif /* CK_SMG */
+#endif /* MYCURSES */
+#endif /* CK_CURSES */
+
+#ifdef NOTERMCAP
+static int notermcap = 1;
+#else
+static int notermcap = 0;
+#endif /* NOTERMCAP */
+
+#ifndef NODISPLAY
+CKVOID
+fxdinit(xdispla) int xdispla; {
+#ifndef COHERENT
+#ifndef OS2
+#ifndef STRATUS
+ char *s;
+ int x, dummy;
+
+ debug(F101,"fxdinit xdispla","",xdispla);
+ debug(F101,"fxdinit fxd_inited","",fxd_inited);
+
+#ifdef IKSD
+#ifndef NOXFER
+ /* No curses for IKSD */
+ if (inserver) {
+ fdispla = XYFD_N;
+ return;
+ }
+ if (fxd_inited) /* Only do this once */
+ return;
+#endif /* NOXFER */
+#endif /* IKSD */
+
+ if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
+ if (xfrmsg) {
+ printf("%s\n",xfrmsg);
+ makestr(&xfrmsg,NULL);
+ }
+ }
+
+#ifdef CK_CURSES
+#ifdef VMS
+ /* Force BRIEF in Batch logs */
+ if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
+ xdispla = XYFD_B;
+#else
+ if (xdispla == XYFD_C || xdispla == 9999) {
+
+#ifdef DYNAMIC
+ if (!trmbuf) {
+/*
+ Allocate tgetent() buffer. Make it big -- some termcaps can be huge;
+ tgetent() merrily writes past the end of the buffer, causing core dumps
+ or worse.
+*/
+ trmbuf = (char *)malloc(TRMBUFL);
+ if (!trmbuf) {
+ notermcap = 1;
+ debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
+ fdispla = XYFD_S;
+ return;
+ }
+#ifdef COMMENT
+ debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
+ debug(F001,"fxdinit trmbuf","",trmbuf);
+ memset(trmbuf,'\0',(size_t)TRMBUFL);
+ debug(F100,"fxdinit memset OK","",0);
+#endif /* COMMENT */
+ }
+#endif /* DYNAMIC */
+
+ debug(F100,"fxdinit before getenv(TERM)","",0);
+ s = getenv("TERM");
+ debug(F110,"fxdinit after getenv(TERM)",s,0);
+ if (!s) s = "";
+ if (*s) {
+ debug(F110,"fxdinit before tgetent()",s,0);
+ x = tgetent(trmbuf,s);
+ debug(F111,"fxdinit tgetent",s,x);
+ } else {
+ x = 0;
+ notermcap = 1;
+ debug(F110,"fxdinit TERM null - no tgetent",s,0);
+ }
+ if (x < 1 && !quiet && !backgrd
+#ifdef VMS
+ && !batch
+#endif /* VMS */
+ ) {
+ printf("Warning: terminal type unknown: \"%s\"\n",s);
+#ifdef COMMENT
+ /* Confusing - nobody knows what this means */
+ printf("SCREEN command will use ANSI sequences.\n");
+#endif /* COMMENT */
+ if (local)
+ printf("Fullscreen file transfer display disabled.\n");
+ fdispla = XYFD_S;
+ }
+#ifndef MYCURSES
+#ifndef CK_SMG
+ ck_termset(x);
+#endif /* CK_SMG */
+#endif /* MYCURSES */
+ fxd_inited = 1;
+ }
+#endif /* CK_CURSES */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* COHERENT */
+}
+#endif /* NODISPLAY */
+
+#ifdef CK_CURSES
+#ifdef CK_SMG
+/*
+ Long section for Screen Manager starts here...
+ By William Bader.
+*/
+#include "ckvvms.h"
+#ifdef OLD_VMS
+#include <smgdef.h> /* use this on VAX C 2.4 */
+/* #include <smgmsg.h> */
+#else
+#include <smg$routines.h> /* Martin Zinser */
+#endif /* OLD_VMS */
+
+extern unsigned int vms_status; /* Used for system service return status */
+
+static long smg_pasteboard_id = -1; /* pasteboard identifier */
+static long smg_display_id = -1; /* display identifier */
+static int smg_open = 0; /* flag if smg current open */
+static int smg_inited = 0; /* flag if smg initialized */
+
+#ifdef COMMENT
+#define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0)
+
+#define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
+
+#define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id)
+
+#else /* Not COMMENT */
+
+#define clrtoeol() smg$erase_line(&smg_display_id, 0, 0)
+
+#define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0)
+
+#define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id)
+#endif /* COMMENT */
+
+#define clearok(curscr,ok) /* Let wrefresh() do the work */
+
+#define wrefresh(cursrc) touchwin(scr)
+
+static void
+move(row, col) int row, col; {
+ /* Change from 0-based for curses to 1-based for SMG */
+ if (!smg_open)
+ return;
+ ++row; ++col;
+ debug(F111,"VMS smg move",ckitoa(row),col);
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("move: smg$set_cursor_abs",
+ SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
+#else
+ CHECK_ERR("move: smg$set_cursor_abs",
+ smg$set_cursor_abs(&smg_display_id, &row, &col));
+#endif /* COMMENT */
+ debug(F101,"VMS smg move vms_status","",vms_status);
+}
+
+#ifdef VMS_V40
+#define OLD_VMS
+#endif /* VMS_V40 */
+#ifdef VMS_V42
+#define OLD_VMS
+#endif /* VMS_V42 */
+#ifdef VMS_V44
+#define OLD_VMS
+#endif /* VMS_V44 */
+
+static int
+initscr() {
+ int rows = 24, cols = 80;
+ int row = 1, col = 1;
+
+ debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
+
+ if (smg_pasteboard_id == -1) { /* Open the screen */
+#ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */
+ CHECK_ERR("initscr: smg$create_pasteboard",
+ smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
+#else
+ /* For VMS V5, not tested */
+ CHECK_ERR("initscr: smg$create_pasteboard",
+ smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
+#endif /* OLD_VMS */
+ }
+ debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
+ if (smg_pasteboard_id == -1) {
+ printf("?Error initializing fullscreen display\n");
+ fdispla = XYFD_S;
+ dpyinit();
+ return(0);
+ }
+ debug(F101,"VMS initscr smg_display_id","",smg_display_id);
+ if (smg_display_id == -1) { /* Create a display window */
+
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("initscr: smg$create_virtual_display",
+ SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
+ 0, 0, 0));
+
+ /* Connect the display window to the screen */
+ CHECK_ERR("initscr: smg$paste_virtual_display",
+ SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
+ &row,&col));
+#else
+ CHECK_ERR("initscr: smg$create_virtual_display",
+ smg$create_virtual_display(&rows, &cols, &smg_display_id,
+ 0, 0, 0));
+
+ /* Connect the display window to the screen */
+ CHECK_ERR("initscr: smg$paste_virtual_display",
+ smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
+ &row,&col));
+#endif /* COMMENT */
+ }
+ debug(F101,"VMS initscr smg_open A","",smg_open);
+ if (!smg_open) { /* Start a batch update */
+ smg_open = 1;
+#ifdef COMMENT
+ CHECK_ERR("initscr: smg$begin_pasteboard_update",
+ SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("initscr: smg$begin_pasteboard_update",
+ smg$begin_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+ debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
+ }
+ debug(F101,"VMS initscr smg_open B","",smg_open);
+ smg_inited = 1;
+ return(1);
+}
+
+static void
+refresh() {
+ debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
+
+ if (smg_open == 0 || smg_pasteboard_id == -1)
+ return;
+
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("refresh: smg$end_pasteboard_update",
+ SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+ CHECK_ERR("refresh: smg$begin_pasteboard_update",
+ SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("refresh: smg$end_pasteboard_update",
+ smg$end_pasteboard_update(&smg_pasteboard_id));
+ CHECK_ERR("refresh: smg$begin_pasteboard_update",
+ smg$begin_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+}
+
+static void
+endwin() {
+ if (!smg_open)
+ return;
+
+ smg_open = 0;
+
+#ifdef COMMENT
+ CHECK_ERR("endwin: smg$end_pasteboard_update",
+ SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("endwin: smg$end_pasteboard_update",
+ smg$end_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+
+ move(22, 0);
+
+#ifdef COMMENT
+/*
+ These calls clear the screen.
+ (convert routine calls to lowercase - Martin Zinser)
+*/
+ CHECK_ERR("endwin: smg$delete_virtual_display",
+ SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
+ smg_display_id = -1;
+
+ CHECK_ERR("endwin: smg$delete_pasteboard",
+ SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
+ smg_pasteboard_id = -1;
+#endif /* COMMENT */
+}
+
+#ifdef COMMENT
+/* DECC 6.2 screams bloody murder about printw ("not enough args") */
+/* but adding the following prototype only makes it holler louder. */
+#ifdef __DECC
+/* "varargs" prototype for printw */
+_PROTOTYP(static int printw,(char *, ...));
+#endif /* __DECC */
+#endif /* COMMENT */
+
+#ifdef __DECC
+#include <stdarg.h>
+_PROTOTYP(static void printw,(char *, ...));
+static void
+printw(char *str,...) {
+ char buf[255];
+ va_list ap;
+ $DESCRIPTOR(text_dsc, 0);
+ text_dsc.dsc$a_pointer=buf;
+ if (!smg_open)
+ return;
+ va_start(ap,str);
+ text_dsc.dsc$w_length = vsprintf(buf, str, ap);
+ va_end(ap);
+ CHECK_ERR("printw: smg$put_chars",
+ smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
+}
+#else
+static void
+printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
+ char *str;
+ long a1, a2, a3, a4, a5, a6, a7, a8;
+/* printw */ {
+ char buf[255];
+ $DESCRIPTOR(text_dsc, 0);
+ if (!smg_open)
+ return;
+ text_dsc.dsc$a_pointer=buf;
+ text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
+ CHECK_ERR("printw: smg$put_chars",
+ smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
+}
+#endif /* __DECC */
+
+#define CK_CURPOS
+int
+ck_curpos(row, col) {
+ debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg curpos smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
+ move(row - 1, col - 1); /* SMG is 0-based */
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+
+int
+ck_cls() {
+ debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg ck_cls smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ clear();
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+
+int
+ck_cleol() {
+ debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ clrtoeol();
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+#endif /* CK_SMG */
+
+#ifdef MYCURSES
+/*
+ Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
+ Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
+ By Terry Kennedy, St Peters College.
+
+ First, some stuff we can just ignore:
+*/
+
+static int
+touchwin(x) int x; {
+ return(0);
+}
+static int
+initscr() {
+ return(0);
+}
+static int
+refresh() {
+ return(0);
+}
+static int
+endwin() {
+ return(0);
+}
+
+/*
+ * Now, some stuff we need to do:
+ */
+
+_PROTOTYP( int move, (int, int) );
+#ifndef OS2
+int
+move(row, col) int row, col; {
+ if (isvt52)
+ printf("\033Y%c%c", row + 037, col + 037);
+ else
+ printf("\033[%d;%dH", row + 1, col + 1);
+ return(0);
+}
+
+int
+clear() {
+ move(0,0);
+ if (isvt52)
+ printf("\033J");
+ else
+ printf("\033[J");
+ return(0);
+}
+
+int
+clrtoeol() {
+ if (isvt52)
+ printf("\033K");
+ else
+ printf("\033[K");
+ return(0);
+}
+
+#define CK_CURPOS
+int
+ck_cls() {
+ return(clear());
+}
+
+int
+ck_cleol() {
+ return(clrtoeol());
+}
+
+int
+ck_curpos(row, col) int row, col; {
+ move(row, col);
+ return(0);
+}
+
+#else /* OS2 */
+/* Windows NT and Windows 95 do not provide ANSI emulation */
+/* Therefore we might as well not use it for OS/2 either */
+
+int
+move(row, col) int row, col; {
+#ifndef ONETERMUPD
+ SetCurPos(row, col);
+#endif /* ONETERMUPD */
+ lgotoxy( VCMD, col+1, row+1);
+ VscrnIsDirty(VCMD);
+ return(0);
+}
+
+int
+clear() {
+ viocell cell;
+ move(0,0);
+#ifdef ONETERMUPD
+ if (VscrnGetBufferSize(VCMD) > 0) {
+ VscrnScroll(VCMD, UPWARD, 0,
+ VscrnGetHeight(VCMD)-(1),
+ VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
+ cleartermscreen(VCMD);
+ }
+#else
+ cell.c = ' ';
+ cell.a = colorcmd;
+ WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
+#endif /* ONETERMUPD */
+ return(0);
+}
+
+int
+clrtoeol() {
+ USHORT row, col;
+ viocell cell;
+
+ cell.c = ' ';
+ cell.a = colorcmd;
+#ifndef ONETERMUPD
+ GetCurPos(&row, &col );
+ WrtNCell(cell, cmd_cols - col -1, row, col);
+#endif /* ONETERMUPD */
+ clrtoeoln(VCMD,CHR_SP);
+ return(0);
+}
+
+#define CK_CURPOS
+int
+ck_curpos(row, col) int row, col; {
+ move(row, col);
+ return(0);
+}
+
+int
+ck_cls() {
+ return(clear());
+}
+
+int
+ck_cleol() {
+ return(clrtoeol());
+}
+
+#endif /* OS2 */
+#endif /* MYCURSES */
+
+#ifndef NOTERMCAP
+#ifndef CK_CURPOS
+#define CK_CURPOS
+
+/* Termcap/Terminfo section */
+
+static char cur_cls[32] = { NUL, NUL };
+static char cur_cleol[32] = { NUL, NUL };
+static char cur_cm[64] = { NUL, NUL };
+static char tgsbuf[128] = { NUL, NUL };
+
+static
+#ifdef CK_ANSIC
+void
+#endif /* CK_ANSIC */
+ck_termset(x) int x; {
+ cur_cls[0] = NUL;
+ cur_cleol[0] = NUL;
+ cur_cm[0] = NUL;
+#ifdef tgetent
+ debug(F100,"tgetent is a macro","",0);
+#endif /* tgetent */
+#ifdef tgetstr
+ debug(F100,"tgetstr is a macro","",0);
+#endif /* tgetstr */
+#ifdef tputs
+ debug(F100,"tputs is a macro","",0);
+#endif /* tputs */
+#ifdef tgoto
+ debug(F100,"tgoto is a macro","",0);
+#endif /* tgoto */
+#ifdef NOTERMCAP
+ /* tgetstr() gets a segmentation fault on OSF/1 */
+ debug(F100,"ck_termset NOTERMCAP","",0);
+#else
+ if (notermcap) {
+ debug(F100,"ck_termset notermcap","",0);
+ return;
+ }
+ debug(F101,"ck_termset x","",x);
+ if (x > 0) {
+ char * bp;
+ bp = tgsbuf;
+ *bp = NUL;
+ debug(F110,"ck_termset calling tgetstr","cl",0);
+ if (tgetstr("cl", &bp)) { /* Get clear-screen code */
+ debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 32)
+ ckstrncpy(cur_cls,tgsbuf,32);
+ } else
+ return;
+ bp = tgsbuf;
+ if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */
+ debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 32)
+ ckstrncpy(cur_cleol,tgsbuf,32);
+ } else
+ return;
+ bp = tgsbuf;
+ if (tgetstr("cm", &bp)) { /* Get cursor-movement code */
+ debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 64)
+ ckstrncpy(cur_cm,tgsbuf,64);
+ } else
+ return;
+ }
+#endif /* NOTERMCAP */
+}
+
+#ifndef TPUTSFNTYPE
+#ifdef TPUTSISVOID
+#define TPUTSFNTYPE void
+#else
+#define TPUTSFNTYPE int
+#endif /* TPUTSISVOID */
+#endif /* TPUTSFNTYPE */
+
+#ifndef TPUTSARGTYPE
+#ifdef HPUX9
+#define TPUTSARGTYPE char
+#else
+#ifdef HPUX10
+#define TPUTSARGTYPE char
+#else
+#define TPUTSARGTYPE int
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* TPUTSARGTYPE */
+
+static TPUTSFNTYPE
+#ifdef CK_ANSIC
+ck_outc(TPUTSARGTYPE x)
+#else
+ck_outc(x) TPUTSARGTYPE x;
+#endif /* CK_ANSIC */
+{ /* To satisfy tputs() arg3 prototype */
+ int rc;
+ char c;
+ c = (char) x;
+ rc = (inserver) ? ttoc(c) : conoc(c);
+#ifndef TPUTSISVOID
+ return(rc);
+#endif /* TPUTSISVOID */
+}
+
+int
+ck_curpos(row, col) int row, col; {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cm[0]) { /* We don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
+ printf("\033[%d;%dH", row, col); /* Or default to ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ /* termcap/terminfo is 0-based */
+ tputs(
+#ifdef TPUTSARG1CONST
+ (const char *)
+#endif /* TPUTSARG1CONST */
+ tgoto(cur_cm,col-1,row-1),1,fn);
+ }
+ return(0);
+}
+
+int
+ck_cls() {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cls[0]) { /* If we don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ printf("\033[;H\033[2J"); /* Or default to ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ debug(F111,"ck_cls 2",cur_cls,fxd_inited);
+ tputs(cur_cls,cmd_rows,fn);
+ }
+ return(0);
+}
+
+int
+ck_cleol() {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cleol[0]) { /* If we don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ printf("\033[K"); /* Or use ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ tputs(cur_cleol,1,fn);
+ }
+ return(0);
+}
+#endif /* CK_CURPOS */
+#else
+static void
+ck_termset(x) int x; {
+ if (x) return;
+}
+#endif /* NOTERMCAP */
+
+#ifndef CK_CURPOS
+#define CK_CURPOS
+int
+ck_cls() {
+ printf("\033[;H\033[2J");
+ return(0);
+}
+
+int
+ck_cleol() {
+ printf("\033[K");
+ return(0);
+}
+
+int
+ck_curpos(row, col) int row, col; {
+ printf("\033[%d;%dH", row, col);
+ return(0);
+}
+#endif /* CK_CURPOS */
+
+
+#ifndef NOXFER
+static int cinit = 0; /* Flag for curses init'd */
+static int cendw = 0; /* endwin() was called */
+
+static
+#ifdef CK_ANSIC /* Because VOID used by curses.h */
+void
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+#endif /* CK_ANSIC */
+#ifdef CK_ANSIC /* Update % transfered and % bar */
+updpct(long old, long new)
+#else /* CK_ANSIC */
+updpct(old, new) long old, new;
+#endif /* CK_ANSIC */
+/* updpct */ {
+#ifdef COMMENT
+ int m, n;
+ move(CW_PCD,22);
+ printw("%ld", new);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ if (old > new) {
+ old = 0;
+ move(CW_PCD, 26);
+ clrtoeol();
+ }
+ m = old/2;
+ move(CW_PCD, 26 + m);
+ n = new / 2 - m;
+#ifndef OS2
+ while (n > 0) {
+ if ((m + 1) % 5 == 0)
+ printw("*");
+ else
+ printw("=");
+ m++;
+ n--;
+ }
+ if (new % 2 != 0) printw("-");
+ /* move(CW_PCD, 22+53); */
+#else /* OS2 */
+ while (n > 0) {
+ printw("%c", '\333');
+ m++; n--;
+ }
+ if (new % 2 != 0)
+ printw("%c", '\261');
+#endif /* OS2 */
+ }
+#endif /* CK_PCT_BAR */
+ /* clrtoeol(); */
+#else /* !COMMENT */
+#ifdef OS2
+#define CHAR1 '\333' /* OS2 - CP437 */
+#define CHAR2 '\261'
+#else
+#define CHAR1 '/' /* Default */
+#define CHAR2 '-'
+#endif /* OS2 */
+ debug(F101,"updpct old","",old);
+ debug(F101,"updpct new","",new);
+ move(CW_PCD,22);
+ printw("%-3ld", new); /* (was) printw("%ld", new); */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ int m, n;
+
+ if (old > new) {
+ old = 0 ;
+ move(CW_PCD, 26);
+ clrtoeol();
+ }
+ if (new <= 100L) {
+ m = old / 2;
+ n = new / 2 - m;
+ move(CW_PCD, 26+m);
+ while (n-- > 0)
+ printw("%c", CHAR1);
+ if (new % 2 != 0)
+ printw("%c", CHAR2);
+ }
+ }
+#endif /* CK_PCT_BAR */
+#endif /* COMMENT */
+}
+
+static CK_OFF_T old_tr = (CK_OFF_T)-1; /* Time remaining previously */
+
+static CK_OFF_T
+#ifdef CK_ANSIC
+shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar)
+#else
+ shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shoetl */ { /* Estimated time left in transfer */
+ CK_OFF_T tr; /* Time remaining, seconds */
+
+#ifdef GFTIMER
+ if (fsiz > 0L && cps > 0L)
+ tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
+ else
+ tr = (CK_OFF_T)-1;
+#else
+ tr = (fsiz > 0L && cps > 0L) ?
+ ((fsiz - howfar) / cps) :
+ (CK_OFF_T)-1;
+#endif /* GFTIMER */
+ move(CW_TR,22);
+ if (tr > (CK_OFF_T)-1) {
+ if (tr != old_tr) {
+ printw("%s",hhmmss(tr));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ }
+ } else {
+ printw("(unknown)");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ }
+ return(tr);
+}
+
+static long
+#ifdef CK_ANSIC
+shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar)
+#else
+shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shocps */ {
+#ifdef CPS_WEIGHTED
+ static CK_OFF_T oldffc = 0L;
+#endif /* CPS_WEIGHTED */
+#ifdef GFTIMER
+ CKFLOAT secs, xx;
+#else
+ CK_OFF_T secs, xx;
+#endif /* GFTIMER */
+
+#ifdef GFTIMER
+ xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */
+ gtv = gftimer();
+ if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
+ return(oldcps);
+ oldgtv = xx;
+#else
+ xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */
+ gtv = gtimer();
+ if ((gtv - oldgtv) < 1)
+ return(oldcps);
+ oldgtv = xx;
+#endif /* GFTIMER */
+
+#ifdef CPS_WEIGHTED
+ /* debug(F100,"SHOCPS: WEIGHTED","",0); */
+ if (gtv != oldgtv) { /* The first packet is ignored */
+ if (ffc < oldffc)
+ oldffc = ffc;
+ oldcps = cps;
+ if (oldcps && oldgtv >
+#ifdef GFTIMER
+ 1.0
+#else
+ 1
+#endif /* GFTIMER */
+ ) { /* The first second is ignored */
+/*
+ This version of shocps() produces a weighted average that some
+ people like, but most people find it disconcerting and bombard us
+ with questions and complaints about why the CPS figure fluctuates so
+ wildly. So now you only get the weighted average if you build the
+ program yourself with CPS_WEIGHTED defined.
+*/
+#ifndef CPS_VINCE
+#ifdef GFTIMER
+ cps = (long)((((CKFLOAT)oldcps * 3.0) +
+ (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
+#else
+ cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
+#endif /* GFTIMER */
+#else
+/* And an alternate weighting scheme from Vincent Fatica... */
+ cps = (3 *
+ ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
+ / 4;
+#endif /* CPS_VINCE */
+ } else {
+ /* No weighted average since there is nothing to weigh */
+#ifdef GFTIMER
+ cps = (long)(gtv != 0.0 ?
+ (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
+ (ffc - oldffc)) ;
+#else
+ cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
+#endif /* GFTIMER */
+ }
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"SHOCPS: pct ","",pct);
+ debug(F101,"SHOCPS: gtv ","",gtv);
+ debug(F101,"SHOCPS: oldgtv","",oldgtv);
+ debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv));
+ debug(F101,"SHOCPS: ffc ","",ffc);
+ debug(F101,"SHOCPS: oldffc","",oldffc);
+ debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
+ debug(F101,"SHOCPS: cps ","",cps);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ move(CW_CP,22);
+ printw("%ld", cps);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldffc = ffc;
+ }
+#else /* !CPS_WEIGHTED */
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"SHOCPS: NOT WEIGHTED","",0);
+ debug(F101,"SHOCPS: pct ","",pct);
+ debug(F101,"SHOCPS: gtv ","",gtv);
+ debug(F101,"SHOCPS: oldgtv ","",oldgtv);
+ debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv);
+ debug(F101,"SHOCPS: ffc ","",ffc);
+ debug(F101,"SHOCPS: oldffc ","",oldffc);
+ debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
+ debug(F101,"SHOCPS: cps ","",cps);
+ debug(F101,"SHOCPS: filcnt ","",filcnt);
+#ifdef GFTIMER
+ debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
+#endif /* GFTIMER */
+ }
+ debug(F101,"shocps gtv","",gtv);
+#endif /* DEBUG */
+#ifdef GFTIMER
+#endif /* COMMENT */
+ /* debug(F101,"shocps fpfsecs","",fpfsecs); */
+ secs = gtv - fpfsecs;
+ /* debug(F101,"shocps secs","",(long)secs); */
+ if (secs > 0.0) {
+ cps = (long)((CKFLOAT) ffc / secs);
+ /* debug(F101,"shocps cps","",cps); */
+ move(CW_CP,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%ld", cps);
+ clrtoeol();
+ }
+#else /* Not GFTIMER */
+ if ((secs = gtv - fsecs) > 0) {
+ cps = (secs < 1L) ? ffc : ffc / secs;
+ move(CW_CP,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%ld", cps);
+ clrtoeol();
+ }
+#endif /* GFTIMER */
+#endif /* CPS_WEIGHTED */
+
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+ old_tr = shoetl(old_tr, cps, fsiz, howfar);
+ return(cps);
+}
+
+static
+#ifdef CK_ANSIC /* Because VOID used by curses.h */
+void
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+#endif /* CK_ANSIC */
+scrft() { /* Display file type */
+ char xferstr[256];
+ xferstr[0] = NUL;
+ debug(F101,"scrft binary","",binary);
+ if (binary) {
+ switch(binary) {
+ case XYFT_L:
+ ckstrncpy(xferstr,"LABELED",256);
+ break;
+ case XYFT_I:
+ ckstrncpy(xferstr,"IMAGE",256);
+ break;
+ case XYFT_U:
+ ckstrncpy(xferstr,"BINARY UNDEFINED",256);
+ break;
+ case XYFT_M:
+ ckstrncpy(xferstr,"MACBINARY",256);
+ break;
+ case XYFT_X:
+ ckstrncpy(xferstr,"TENEX",256);
+ break;
+ default:
+ case XYFT_B:
+ ckstrncpy(xferstr,"BINARY",256);
+ break;
+ }
+#ifdef CK_RESEND
+ if (what & W_SEND && sendstart > 0L) {
+ if (sendmode == SM_PSEND) {
+ ckstrncat(xferstr, " / partial", 256);
+ } else if (sendmode == SM_RESEND) {
+ ckstrncat(xferstr, " / resend", 256);
+ }
+ } else if (what & W_RECV && rs_len > 0L) {
+ ckstrncat(xferstr, " / resend", 256);
+ }
+#endif /* CK_RESEND */
+ } else {
+
+#ifndef NOCSETS
+ ckstrncpy(xferstr,"TEXT",256);
+#ifdef NEWFTP
+#ifndef NOUNICODE
+ if (what & W_FTP) {
+ if (ftp_csx < 0)
+ ckstrncat(xferstr," (no translation)", 256);
+ else
+ ckmakxmsg(&xferstr[4],252,
+ " (",
+ fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
+ " => ",
+ fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
+ ")",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ } else
+#endif /* NOUNICODE */
+#endif /* NEWFTP */
+ if (tcharset == TC_TRANSP) {
+ ckstrncat(xferstr, " (no translation)", 256);
+ } else {
+ if (what & W_SEND) {
+ sprintf( &xferstr[strlen(xferstr)], /* safe */
+ " (%s => %s)",
+ fcsinfo[fcharset].keyword, /* built-in keywords */
+ tcsinfo[tcharset].keyword /* lengths are controlled */
+ );
+ } else {
+ sprintf( &xferstr[strlen(xferstr)], /* safe */
+ " (%s => %s)",
+ tcsinfo[tcharset].keyword, /* built-in keywords */
+ fcsinfo[fcharset].keyword); /* lengths controlled */
+ }
+ }
+#endif /* NOCSETS */
+ }
+ move(CW_TYP,22);
+ printw("%s", xferstr);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
+#endif /* K95G */
+#endif /* KUI */
+ return;
+}
+
+#ifdef CK_NEWTERM
+static FILE *ck_stdout = NULL;
+static int ck_fd = -1;
+#endif /* CK_NEWTERM */
+
+static long pct = 0L, oldpct = 0L, oldrtt = -1L;
+static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
+
+#ifdef NETCONN
+static char *netname[] = {
+ "none", /* 00 */
+ "TCP/IP", /* 01 TCP (Sockets) */
+ "TCP/IP", /* 02 TCP (Streams) */
+ "X.25", /* 03 SunLink X.24 */
+ "DECnet", /* 04 DECnet */
+ "VAX PSI", /* 05 VAX PSI */
+ "Named Pipes", /* 06 LAN Manager Named Pipe */
+ "X.25", /* 07 Stratus VOS X.25 */
+ "NetBIOS", /* 08 IBM NETBIOS */
+ "SuperLAT", /* 07 Meridian SuperLAT */
+ "File", /* 10 File */
+ "Command", /* 11 Subprocess (pipe) */
+ "DLL", /* 12 DLL does i/o */
+ "X.25", /* 13 IBM AIXLink X.25 */
+ "X.25", /* 14 HP-UX X.25 */
+ "PTY", /* 15 Pseudoterminal */
+ "SSH", /* 16 SSH */
+ "<ERROR>", /* 17 In case new types are added */
+ "<ERROR>", /* 18 but nobody remembers to update */
+ "<ERROR>", /* 19 this table ... */
+ NULL /* 20 */
+};
+static int nnetname = (sizeof(netname) / sizeof(char *));
+
+#endif /* NETCONN */
+
+#ifdef CK_ANSIC
+void
+screenc(int f, char c,CK_OFF_T n,char *s)
+#else
+CKVOID
+screenc(f,c,n,s)
+int f; /* argument descriptor */
+char c; /* a character or small integer */
+CK_OFF_T n; /* a long integer */
+char *s; /* a string */
+#endif /* CK_ANSIC */
+/* screenc() */ {
+#ifdef CK_SSL
+ extern int tls_active_flag, ssl_active_flag;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+ extern int ttnproto;
+#endif /* RLOGCODE */
+ static int q = 0;
+ static long fcnt = 0L; /* Number of files transferred */
+ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
+ static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */
+ static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */
+ static int pctlbl = 0L; /* Percent done vs Bytes so far */
+ long cps = 0L;
+
+ int net = 0;
+ int xnet = 0;
+ int ftp = 0;
+ int len; /* Length of string */
+ int errors = 0; /* Error counter */
+ int x; /* Worker */
+
+ debug(F101,"screenc cinit","",cinit);
+ debug(F101,"screenc cendw","",cendw);
+
+ if (!s) s = ""; /* Always do this. */
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
+ net = network || ftp;
+ xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
+
+ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
+ if (f == SCR_CW) { /* Close window, but it's not open */
+ ft_win = 0;
+ return;
+ }
+ debug(F111,"screenc A",s,f);
+ if (f == SCR_EM ||
+ (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
+ conoll(""); conoc('?'); conoll(s); return; /* Regular display */
+ }
+ }
+ if (cinit == 0) { /* Only call initscr() once */
+ char * s;
+ /* Check these now -- if they are defined but not numeric */
+ /* they can crash curses */
+ s = getenv("LINES");
+ if (s) if (!rdigits(s)) {
+ printf("?LINES variable not numeric: \"%s\".\n",s);
+ printf("(Fullscreen display disabled)\n");
+ fdispla = XYFD_S;
+ return;
+ }
+ s = getenv("COLUMNS");
+ if (s) if (!rdigits(s)) {
+ printf("?COLUMNS variable not numeric: \"%s\".\n",s);
+ printf("(Fullscreen display disabled)\n");
+ fdispla = XYFD_S;
+ return;
+ }
+ cendw = 1; /* New window needs repainting */
+#ifdef COMMENT
+ if (!initscr()) { /* Oops, can't initialize window? */
+/*
+ In fact, this doesn't happen. "man curses" says initscr() halts the
+ entire program if it fails, which is true on the systems where I've
+ tested it. It will fail if your terminal type is not known to it.
+ That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
+ terminal type is known before allowing a curses display.
+*/
+ fprintf(stderr,"CURSES INITSCR ERROR\r\n");
+ fdispla = XYFD_S; /* Fall back to CRT display */
+ return;
+ } else {
+ cinit++; /* Window initialized ok */
+ debug(F100,"CURSES INITSCR OK","",0);
+ }
+#else /* Save some memory. */
+#ifdef CK_NEWTERM
+ /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
+ System V curses seems to reserve the right to alter the buffering
+ on the output FILE* without restoring it. Fortunately System V
+ curses provides newterm(), an alternative to initscr(), that
+ allows us to specify explicitly the terminal type and input and
+ output FILE pointers. Thus we duplicate stdout, and let curses
+ have the copy. The original remains unaltered. Unfortunately,
+ newterm() seems to be particular to System V.
+ */
+ s = getenv("TERM");
+ if (ck_fd < 0) {
+ ck_fd = dup(fileno(stdout));
+ ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
+ }
+ debug(F100,"screenc newterm...","",0);
+
+/* NOTE: It might be necessary to do this with stdin too! */
+/* This would have been the case in FreeBSD 4.1 but they fixed the */
+/* problem by restoring the buffering of stdin before the final release. */
+/* (But T.E. Dickey says stdin is not buffered?) */
+
+ if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
+ fprintf(stderr,
+ "Fullscreen display not supported for terminal type: %s\r\n",s);
+ fdispla = XYFD_S; /* Use CRT instead */
+ return;
+ }
+ debug(F100,"screenc newterm ok","",0);
+#else
+ debug(F100,"screen calling initscr","",0);
+ initscr(); /* Initialize curses. */
+ debug(F100,"screen initscr ok","",0);
+#endif /* CK_NEWTERM */
+ cinit++; /* Remember curses was initialized. */
+#endif /* COMMENT */
+ }
+ ft_win = 1; /* Window is open */
+ if (repaint) {
+#ifdef CK_WREFRESH
+/*
+ This totally repaints the screen, just what we want, but we can only
+ do this with real curses, and then only if clearok() and wrefresh() are
+ provided in the curses library.
+*/
+#ifdef OS2
+ RestoreCmdMode();
+#else
+#ifdef QNX
+#ifndef QNX16
+ clearok(stdscr, 1); /* QNX doesn't have curscr */
+#endif /* QNX16 */
+ wrefresh(stdscr);
+#else
+ wrefresh(curscr);
+#endif /* QNX */
+#endif /* OS2 */
+#else /* No CK_WREFRESH */
+/*
+ Kermit's do-it-yourself method, works with all types of fullscreen
+ support, but does not repaint all the fields. For example, the filename
+ is lost, because it arrives at a certain time and never comes again, and
+ Kermit presently does not save it anywhere. Making this method work for
+ all fields would be a rather major recoding task, duplicating what curses
+ already does, and would add a lot of complexity and storage space.
+*/
+ cendw = 1;
+#endif /* CK_WREFRESH */
+ repaint = 0;
+ }
+ if (cendw) { /* endwin() was called previously */
+#ifdef VMS
+ initscr(); /* (or should have been!) */
+ clear();
+ touchwin(stdscr);
+ refresh();
+#else
+#ifdef QNX
+/*
+ In QNX, if we don't call initscr() here we core dump.
+ I don't have any QNX curses documentation, but other curses manuals
+ say that initscr() should be called only once per application, and
+ experience shows that on other systems, calling initscr() here generally
+ results in a core dump.
+*/
+ debug(F100,"screenc re-calling initscr QNX","",0);
+ initscr();
+ clear();
+ refresh();
+#ifdef COMMENT
+/*
+ But even so, second and subsequent curses displays are messed up.
+ Calling touchwin, refresh, etc, doesn't make any difference.
+*/
+ debug(F100,"screenc calling touchwin QNX","",0);
+ touchwin(stdscr);
+ debug(F100,"screenc calling refresh QNX","",0);
+ refresh();
+#endif /* COMMENT */
+
+#else /* All others... */
+ debug(F100,"screenc calling clear","",0);
+ clear();
+ debug(F100,"screenc clear ok","",0);
+#endif /* QNX */
+#endif /* VMS */
+ debug(F100,"screenc setup ok","",0);
+ debug(F100,"screenc doing first move","",0);
+ move(CW_BAN,0); /* Display the banner */
+ debug(F110,"screenc myhost",myhost,0);
+#ifdef TCPSOCKET
+ debug(F110,"screenc myipaddr",myipaddr,0);
+#endif /* TCPSOCKET */
+#ifdef HPUX1010
+ debug(F100,"screenc calling first printw...","",0);
+/* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
+#endif /* HPUX1010 */
+ if (myhost[0]) {
+#ifdef TCPSOCKET
+ if (!myipaddr[0]
+#ifdef OS2
+ /* We need to perform this test because on non-TCP/IP */
+ /* systems the call to getlocalipaddr() results in a */
+ /* DNS Lookup which takes several minutes to time out */
+ && net &&
+ (xnet == NET_TCPA || xnet == NET_TCPB
+#ifdef SSHBUILTIN
+ || xnet == NET_SSH
+#endif /* SSHBUILTIN */
+ )
+#endif /* OS2 */
+ )
+ getlocalipaddr();
+ if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
+ printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
+ else
+#endif /* TCPSOCKET */
+ printw("%s, %s",versio,(char *)myhost);
+ } else {
+ printw("%s",versio);
+ }
+#ifdef HPUX1010
+ debug(F100,"screenc first printw returns","",0);
+#endif /* HPUX1010 */
+ move(CW_DIR,3);
+ printw("Current Directory: %s",zgtdir());
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
+#endif /* K95G */
+#endif /* KUI */
+ if (net) {
+ move(CW_LIN,8);
+ printw("Network Host: %s",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "(unknown)") :
+#endif /* NEWFTP */
+ ttname
+ );
+ } else {
+ move(CW_LIN,0);
+ printw("Communication Device: %s",ttname);
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
+#endif /* K95G */
+#endif /* KUI */
+
+ if (net) {
+ move(CW_SPD,8);
+ printw("Network Type: ");
+ } else {
+ move(CW_SPD,1);
+ printw("Communication Speed: ");
+ }
+ move(CW_SPD,22); /* Serial speed or network type */
+ if (net) {
+#ifdef NETCONN
+ int secure = 0;
+ char * xname;
+ if (xnet > nnetname)
+ xname = "[ERROR]";
+ else
+ xname = netname[xnet];
+#ifdef NEWFTP
+ if (ftp) {
+ if (ftpissecure())
+ secure = 1;
+ } else
+#endif /* NEWFTP */
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ secure = 1;
+ }
+ if (secure) {
+#ifdef KUI
+#ifndef K95G
+ char buf[30];
+ sprintf(buf,"%s (SECURE)",xname);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) buf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s (SECURE)",xname);
+ } else {
+ printw("%s",xname);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) xname
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+#else
+ printw("(network)");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(network)"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#endif /* NETCONN */
+ } else {
+ if (speed < 0L)
+ speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880) {
+ printw("75/1200");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "75/1200"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ } else {
+ char speedbuf[64] ;
+ sprintf(speedbuf, "%ld", speed);
+ printw("%s",speedbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) speedbuf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ } else {
+ printw("unknown");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(unknown)"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ }
+ move(CW_PAR,14);
+ printw("Parity: %s",ftp ? "none" : parnam((char)parity));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ move(CW_TMO, 9); printw("RTT/Timeout:"); }
+#endif /* CK_TIMERS */
+ move(CW_TYP,11); printw("File Type:");
+ move(CW_SIZ,11); printw("File Size:");
+ move(CW_PCD, 8);
+ clrtoeol();
+ pctlbl = (what & W_SEND);
+ printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
+
+#ifdef XYZ_INTERNAL
+ move(CW_BAR, 1);
+ printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
+#endif /* XYZ_INTERNAL */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ oldpct = pct = 0;
+ move(CW_BAR,22);
+ printw(" ...10...20...30...40...50...60...70...80...90..100");
+ move(CW_BAR,22+56);
+ }
+#endif /* CK_PCT_BAR */
+ move(CW_TR, 1); printw("Estimated Time Left:");
+ move(CW_CP, 2); printw("Transfer Rate, CPS:");
+ move(CW_WS, 8); printw("Window Slots:%s",
+ ((protocol == PROTO_K) && !ftp) ?
+ "" : " N/A"
+ );
+ move(CW_PT, 9); printw("Packet Type:");
+ if (ftp || protocol != PROTO_K) {
+ move(CW_PT,22);
+ printw("%s", "N/A");
+ move(CW_PC, 11); printw("I/O Count:");
+ move(CW_PL, 10); printw("I/O Length:");
+ } else {
+ move(CW_PC, 8); printw("Packet Count:");
+ move(CW_PL, 7); printw("Packet Length:");
+ }
+#ifndef COMMENT
+ move(CW_PR, 9); printw("Error Count:");
+#else
+ move(CW_PR, 2); printw("Packet Retry Count:");
+#endif
+#ifdef COMMENT
+ move(CW_PB, 2); printw("Packet Block Check:");
+#endif /* COMMENT */
+ move(CW_ERR,10); printw("Last Error:");
+ move(CW_MSG, 8); printw("Last Message:");
+ if (xfrmsg) {
+ move(CW_MSG, 22); printw("%s",xfrmsg);
+ makestr(&xfrmsg,NULL);
+ }
+ move(CW_INT, 0);
+ if (!xfrint) {
+ printw("(Transfer interruption is disabled)");
+ } else {
+#ifdef CK_NEED_SIG
+ printw(
+"<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
+ dbchr(escape), dbchr(escape), dbchr(escape)
+ );
+ move(CW_INT + 1, 0);
+ printw(
+"<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
+ dbchr(escape), dbchr(escape)
+ );
+#else /* !CK_NEED_SIG */
+ move(CW_INT, 0);
+#ifdef OS2
+ if (protocol == PROTO_K) {
+ printw(
+"X to cancel file, Z to cancel group, <Enter> to resend last packet,"
+ );
+ }
+#else /* !OS2 */
+#ifdef VMS /* In VMS avoid bottom line */
+ printw(
+"X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
+ );
+#else
+ printw(
+"X to cancel file, Z to cancel group, <CR> to resend last packet,"
+ );
+#endif /* VMS */
+#endif /* OS2 */
+
+#ifndef VMS
+ move(CW_INT + 1, 0);
+ if (protocol == PROTO_K) {
+ printw(
+"E to send Error packet, ^C to quit immediately, ^L to refresh screen."
+ );
+ } else {
+ printw("^C to cancel file transfer.");
+ }
+#endif /* VMS */
+#endif /* CK_NEED_SIG */
+ }
+ refresh();
+ cendw = 0;
+ }
+ debug(F101,"SCREENC switch","",f);
+ debug(F000,"SCREENC c","",c);
+ debug(F101,"SCREENC n","",n);
+
+ len = strlen(s); /* Length of argument string */
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ oldpct = pct = 0L; /* Reset percents */
+#ifdef GFTIMER
+ gtv = (CKFLOAT) -1.0;
+ /* oldgtv = (CKFLOAT) -1.0; */
+#else
+ gtv = -1L;
+ /* oldgtv = -1L; */
+#endif /* GFTIMER */
+ oldwin = -1;
+ fsiz = (CK_OFF_T)-1; /* Invalidate previous file size */
+ move(CW_PCD,22); /* Erase percent done from last time */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(CW_SIZ,22); /* Erase file size from last time */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(CW_ERR,22); /* And last error message */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+#ifdef COMMENT
+#ifdef STREAMING
+ if (protocol == PROTO_K && streamok) {
+ move(CW_BAR, 1);
+#ifdef XYZ_INTERNAL
+ printw(" Kermit STREAMING:");
+#else
+ printw(" STREAMING:");
+#endif /* XYZ_INTERNAL */
+ }
+#endif /* STREAMING */
+#endif /* COMMENT */
+
+ if (what & W_SEND) { /* If we're sending... */
+#ifdef NEWFTP
+ if (what & W_FTP) { /* FTP */
+ move(CW_NAM,10);
+ printw(" FTP PUT:");
+ } else
+#endif /* NEWFTP */
+#ifdef CK_RESEND
+ switch (sendmode) { /* Kermit */
+ case SM_RESEND:
+ move(CW_NAM,10);
+ printw(" RESENDING:");
+ break;
+ default:
+ move(CW_NAM,10);
+ printw(" SENDING:");
+ break;
+ }
+#else
+ move(CW_NAM,10);
+ printw(" SENDING:");
+#endif /* CK_RESEND */
+
+ } else if (what & W_RECV) { /* If we're receiving... */
+#ifdef NEWFTP
+ if (what & W_FTP) { /* FTP */
+ move(CW_NAM,10);
+ printw(" FTP GET:");
+ } else {
+#endif /* NEWFTP */
+ move(CW_NAM,10);
+ printw(" RECEIVING:");
+#ifdef NEWFTP
+ }
+ } else if (what == (W_FTP|W_FT_DELE)) {
+ move(CW_NAM,10);
+ printw("FTP DELETE:");
+#endif /* NEWFTP */
+ } else { /* If we don't know... */
+ move(CW_NAM,10); /* (should never see this) */
+ printw(" File Name:");
+ }
+ move(CW_NAM,22); /* Display the filename */
+ if (len > 57) {
+ printw("%.55s..",s);
+ len = 57;
+ } else printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ q = len; /* Remember name length for later */
+ clrtoeol();
+ scrft(); /* Display file type (can change) */
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_AN: /* File as-name */
+ if (q + len + 4 < 58) { /* Will fit */
+ move(CW_NAM, 22 + q);
+ printw(" => %s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ } else { /* Too long */
+ move(CW_NAM, 22); /* Overwrite previous name */
+ q = 0;
+ if (len + 4 > 57) { /* wg15 */
+ printw(" => %.51s..",s); /* wg15 */
+ len = 53; /* wg15 */
+ } else printw(" => %s",s); /* wg15 */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ q += len + 4; /* Remember horizontal position */
+ clrtoeol();
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_FS: /* File size */
+ fsiz = n;
+ move(CW_SIZ,22);
+ if (fsiz > (CK_OFF_T)-1) {
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s",ckfstoa(n));
+ }
+ if (fsiz == -2L) {
+ printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT");
+ }
+ clrtoeol();
+#ifdef COMMENT
+ move(CW_PCD, 8);
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ clrtoeol();
+ printw("Percent Done:");
+ }
+#else
+ move(CW_PCD, 8);
+ clrtoeol();
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ printw("Percent Done:");
+ } else {
+ pctlbl = 0;
+ printw("Bytes So Far:");
+ }
+#endif /* COMMENT */
+ clrtoeol();
+ scrft(); /* File type */
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (spackets < 5) {
+ extern int sysindex;
+ extern struct sysdata sysidlist[];
+ /* Things that won't change after the 4th packet */
+ move(CW_PAR,22);
+ printw("%s",parnam((char)parity));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+#ifdef COMMENT
+ move(CW_PB, 22); /* Block check on this packet */
+ if (bctu == 4)
+ printw("B");
+ else
+ printw("%d",bctu);
+ clrtoeol();
+#endif /* COMMENT */
+ if (
+#ifdef NEWFTP
+ (ftp && (spackets == 1 || rpackets == 1)) ||
+#endif /* NEWFTP */
+ spackets == 4
+ ) {
+ move(CW_LIN,8);
+ if (
+#ifdef NEWFTP
+ ftp ||
+#endif /* NEWFTP */
+ ((protocol == PROTO_K) && (sysindex > -1))
+ ) {
+ if (net) {
+ move(CW_LIN,8);
+ printw("Network Host: %s (%s)",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "") :
+#endif /* NEWFTP */
+ ttname,
+#ifdef NEWFTP
+ ftp ? ftp_srvtyp :
+#endif /* NEWFTP */
+ sysidlist[sysindex].sid_name
+ );
+ } else {
+ move(CW_LIN,0);
+ printw("Communication Device: %s (remote host is %s)",
+ ttname,
+ sysidlist[sysindex].sid_name
+ );
+ }
+ clrtoeol();
+ }
+ }
+ }
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ long xx;
+ if (
+#ifdef STREAMING
+ streaming && oldwin != -2
+#else
+ 0
+#endif /* STREAMING */
+ ) {
+ move(CW_TMO, 22);
+ printw("00 / 00");
+ clrtoeol();
+ } else {
+ xx = (rttdelay + 500) / 1000;
+ if (xx != oldrtt || rcvtimo != oldtim) {
+ move(CW_TMO, 22);
+ printw("%02ld / %02d", xx, rcvtimo);
+ oldrtt = xx;
+ oldtim = rcvtimo;
+ clrtoeol();
+ }
+ }
+ }
+#endif /* CK_TIMERS */
+
+ x = (what & W_RECV) ? /* Packet length */
+ rpktl+(protocol==PROTO_K?1:0) :
+ spktl;
+ if (x != oldlen) { /* But only if it changed. */
+ move(CW_PL, 22);
+ printw("%d",x);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldlen = x;
+ }
+ move(CW_PC, 22); /* Packet count (always). */
+
+ printw("%d", (what & W_RECV) ? rpackets : spackets);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+
+ if (protocol == PROTO_K && !ftp) { /* Window slots */
+ char ws[16];
+ int flag;
+ flag = 0;
+#ifdef STREAMING
+ if (streaming) {
+ if (oldwin != -2) {
+ sprintf(ws,"STREAMING");
+ flag = 1;
+ oldwin = -2;
+ }
+ } else
+#endif /* STREAMING */
+ if (wcur != oldwin) {
+ sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
+ flag = 1;
+ oldwin = wcur;
+ }
+ if (flag) {
+ move(CW_WS, 22);
+ printw("%s", ws);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ }
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Retry count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtry = errors;
+ }
+ /* Sender's packet type */
+ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
+ char type[2];
+ sprintf(type, "%c",c);
+ move(CW_PT,22);
+ printw("%s", type);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtyp = c;
+ }
+ switch (c) { /* Now handle specific packet types */
+ case 'S': /* Beginning of transfer */
+ fcnt = fbyt = 0L; /* Clear counters */
+#ifdef GFTIMER
+ gtv = -1.0;
+#else /* GFTIMER */
+ gtv = -1L; /* And old/new things... */
+#endif /* GFTIMER */
+ oldpct = pct = 0L;
+ break;
+
+ case 'Z': /* or EOF */
+ debug(F101,"screenc SCR_PT Z pktnum","",n);
+ debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
+ debug(F101,"screenc SCR_PT Z pct","",pct);
+ case 'D': /* Data packet */
+ if (fsiz > 0L) { /* Show percent done if known */
+ oldpct = pct; /* Remember previous percent */
+ howfar = ffc;
+#ifdef CK_RESEND
+ if (what & W_SEND) /* Account for PSEND or RESEND */
+ howfar += sendstart;
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ /* Percent done, to be displayed... */
+ if (c == 'Z') {
+ if (!discard && !cxseen && !czseen) pct = 100L;
+ } else
+ pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
+ if (pct > 100L || /* Allow for expansion and */
+ (oldpct == 99L && pct < 0L)) /* other boundary conditions */
+ pct = 100L;
+ if (pct != oldpct) /* Only do this 100 times per file */
+ updpct(oldpct, pct);
+ } else {
+ move(CW_PCD,22);
+ printw("%s", ckfstoa(ffc));
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
+#endif /* K95G */
+#endif /* KUI */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ break;
+
+ case '%': /* Timeouts, retransmissions */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ oldtry = errors;
+ if (s) if (*s) {
+ move(CW_ERR,22);
+ printw("%s",s);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+#endif /* K95G */
+#endif /* KUI */
+ }
+ break;
+
+ case 'E': /* Error packet */
+#ifdef COMMENT
+ move(CW_ERR,22); /* Print its data field */
+ if (*s) {
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ clrtoeol();
+#endif /* COMMENT */
+ fcnt = fbyt = 0L; /* So no bytes for this file */
+ break;
+ case 'Q': /* Crunched packet */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ move(CW_ERR,22);
+ printw("Damaged Packet");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Damaged Packet"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ break;
+ case 'q': /* Ctrl-C or connection lost */
+ move(CW_MSG,22);
+ clrtoeol();
+ if (!s) s = "";
+ printw("%s", *s ? s : "User interruption or connection lost");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) s
+ );
+#endif /* K95G */
+#endif /* KUI */
+ break;
+ case 'T': /* Timeout */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ move(CW_ERR,22);
+ printw("Timeout %d sec",rcvtimo);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Timeout"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtry = errors;
+ }
+ break;
+ default: /* Others, do nothing */
+ break;
+ }
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_ST: /* File transfer status */
+ debug(F101,"screenc SCR_ST c","",c);
+ debug(F101,"screenc SCR_ST success","",success);
+ debug(F101,"screenc SCR_ST cxseen","",cxseen);
+#ifdef COMMENT
+ move(CW_PCD,22); /* Update percent done */
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl)
+ updpct(oldpct,100);
+ else
+ printw("%s", ckfstoa(ffc));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#endif /* K95G */
+#endif /* KUI */
+ pct = 100;
+ oldpct = 0;
+ } else if (fsiz > 0L) /* Not OK, update final percent */
+/*
+ The else part writes all over the screen -- howfar and/or fsiz have
+ been reset as a consequence of the not-OKness of the transfer.
+*/
+ if (pctlbl)
+ updpct(oldpct, (howfar * 100L) / fsiz);
+ clrtoeol();
+#else
+ if (c == ST_OK) { /* OK, print 100 % */
+ move(CW_PCD,22); /* Update percent done */
+ if (pctlbl) {
+ if (oldpct == 0) /* Switching from "bytes so far" */
+ clrtoeol(); /* to "percent done"... */
+ updpct(oldpct,100);
+ } else
+ printw("%s", ckfstoa(ffc));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = 100;
+ oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol();
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/* No, leave it there so they can read it */
+ move(CW_MSG,22); /* Remove any previous message */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+#endif /* COMMENT */
+
+ move(CW_TR, 22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+
+ switch (c) { /* Print new status message */
+ case ST_OK: /* Transfer OK */
+ fcnt++; /* Count this file */
+ if (what == (W_FTP|W_FT_DELE)) {
+ move(CW_MSG,22);
+ clrtoeol();
+ printw("Delete OK");
+ } else {
+ fbyt += ffc;
+ move(CW_MSG,22);
+ clrtoeol();
+ printw("Transfer OK");
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Transfer OK"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_DISC: /* Discarded */
+ move(CW_ERR,22);
+ printw("File discarded");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File discarded"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_INT: /* Interrupted */
+ move(CW_ERR,22);
+ printw("Transfer interrupted");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Transfer interrupted"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_SKIP: /* Skipped */
+ move(CW_ERR,22);
+ if (n > 0 && n < nskreason)
+ printw("File skipped (%s)",skreason[n]);
+ else
+ printw("File skipped");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File skipped"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_ERR: /* Error message */
+ move(CW_ERR,22);
+ if (!s) s = (char *)epktmsg;
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_REFU: /* Refused */
+ move(CW_ERR,22);
+ if (*s) {
+ char errbuf[64] ;
+ sprintf( errbuf, "Refused, %s", s ) ;
+ printw("%s", errbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
+#endif /* K95G */
+#endif /* KUI */
+ } else {
+ printw("Refused");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+#endif /* K95G */
+#endif /* KUI */
+ }
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_INC:
+ move(CW_ERR,22);
+ printw("Incomplete");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_MSG:
+ move(CW_MSG,22);
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+ return;
+
+ default: /* Bad call */
+ move(CW_ERR,22);
+ printw("*** screen() called with bad status ***");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+ (long) "*** screen() called with bad status ***" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh(); return;
+ }
+
+ case SCR_TC: { /* Transaction complete */
+ char msgbuf[128];
+ move(CW_CP,22); /* Overall transfer rate */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s", ckfstoa(tfcps));
+ clrtoeol();
+ if (success) {
+ move(CW_MSG,22); /* Print statistics in message line */
+ clrtoeol();
+ }
+ if (success) {
+ sprintf(msgbuf,
+ "SUCCESS. Files: %ld, Bytes: %s, %ld CPS",
+ filcnt - filrej,
+ ckfstoa(fbyt),
+ tfcps
+ );
+ printw("%s", msgbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) msgbuf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+
+ }
+ move(CW_TR, 1);
+ printw(" Elapsed Time: %s",hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_TR,
+ (long) hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(23,0); clrtoeol(); /* Clear instructions lines */
+ move(22,0); clrtoeol(); /* to make room for prompt. */
+ refresh();
+
+#ifdef GFTIMER
+ oldgtv = (CKFLOAT) -1.0;
+#else
+ oldgtv = -1L;
+#endif /* GFTIMER */
+
+#ifndef VMSCURSE
+ debug(F100,"screenc endwin A","",0);
+ endwin();
+#ifdef COMMENT
+/*
+ Why and when was this call to conres() added? It makes no sense,
+ and it breaks echoing on Solaris 8.
+*/
+#ifdef SOLARIS
+ conres();
+#endif /* SOLARIS */
+#endif /* COMMENT */
+#endif /* VMSCURSE */
+
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+ cendw = 1;
+ if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ ft_win = 0; /* Window closed. */
+ return;
+ }
+ case SCR_EM: /* Error packet (fatal) */
+ move (CW_ERR,22);
+ printw("FAILURE: %s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ if (xfrbel) bleep(BP_FAIL);
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh(); return;
+
+ case SCR_QE: /* Quantity equals */
+ case SCR_TU: /* Undelimited text */
+ case SCR_TN: /* Text delimited at start */
+ case SCR_TZ: /* Text delimited at end */
+ return; /* (ignored in fullscreen display) */
+
+ case SCR_MS: /* Message from Kermit partner */
+ move(CW_MSG,22);
+ printw("%s",s);
+ clrtoeol(); refresh(); return;
+
+ case SCR_XD: /* X-packet data */
+ pct = oldpct = 0;
+ move(CW_NAM,22);
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh(); return;
+
+ case SCR_CW: /* Close Window */
+ clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
+ refresh();
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+
+#ifndef VMSCURSE
+ debug(F100,"screenc endwin B","",0);
+ endwin();
+#endif /* VMSCURSE */
+ ft_win = 0; /* Flag that window is closed. */
+ cendw = 1; return;
+
+ case SCR_CD: /* Display current directory */
+ move(CW_DIR,22);
+ printw("%s", s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ default: /* Bad call */
+ move (CW_ERR,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "*** screen() called with bad function code ***"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ printw("*** screen() called with bad function code ***");
+ clrtoeol(); refresh(); return;
+ }
+}
+#endif /* CK_CURSES */
+
+#ifdef KUI
+#ifdef CK_ANSIC
+void
+screeng(int f, char c,long n,char *s)
+#else
+CKVOID
+screeng(f,c,n,s)
+int f; /* argument descriptor */
+char c; /* a character or small integer */
+long n; /* a long integer */
+char *s; /* a string */
+#endif /* CK_ANSIC */
+/* screeng() */ {
+#ifdef CK_SSL
+ extern int tls_active_flag, ssl_active_flag;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+ extern int ttnproto;
+#endif /* RLOGCODE */
+ static int q = 0;
+ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
+ static long fcnt = 0L; /* Number of files transferred */
+ static long fbyt = 0L; /* Total file bytes of all files transferred */
+ static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */
+ static int pctlbl = 0L; /* Percent done vs Bytes so far */
+ long cps = 0L;
+
+ int net = 0;
+ int xnet = 0;
+ int ftp = 0;
+ int len; /* Length of string */
+ int errors = 0; /* Error counter */
+ int x; /* Worker */
+
+ debug(F101,"screeng cinit","",cinit);
+ debug(F101,"screeng cendw","",cendw);
+
+ if (!s) s = ""; /* Always do this. */
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
+ net = network || ftp;
+ xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
+
+ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
+ if (f == SCR_CW) { /* Close window, but it's not open */
+ ft_win = 0;
+ return;
+ }
+ debug(F111,"screeng A",s,f);
+ if (f == SCR_EM ||
+ (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
+ conoll(""); conoc('?'); conoll(s); return; /* Regular display */
+ }
+ }
+ if (cinit == 0) { /* Only call initscr() once */
+ /* Check these now -- if they are defined but not numeric */
+ /* they can crash curses */
+ cendw = 1; /* New window needs repainting */
+ debug(F100,"screeng calling initscr","",0);
+ initscr(); /* Initialize curses. */
+ debug(F100,"screeng initscr ok","",0);
+ cinit++; /* Remember curses was initialized. */
+ }
+ ft_win = 1; /* Window is open */
+ if (repaint) {
+#ifdef CK_WREFRESH
+/*
+ This totally repaints the screen, just what we want, but we can only
+ do this with real curses, and then only if clearok() and wrefresh() are
+ provided in the curses library.
+*/
+ RestoreCmdMode();
+#else /* No CK_WREFRESH */
+/*
+ Kermit's do-it-yourself method, works with all types of fullscreen
+ support, but does not repaint all the fields. For example, the filename
+ is lost, because it arrives at a certain time and never comes again, and
+ Kermit presently does not save it anywhere. Making this method work for
+ all fields would be a rather major recoding task, duplicating what curses
+ already does, and would add a lot of complexity and storage space.
+*/
+ cendw = 1;
+#endif /* CK_WREFRESH */
+ repaint = 0;
+ }
+ if (cendw) { /* endwin() was called previously */
+ debug(F100,"screeng setup ok","",0);
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
+ (long) (
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "(unknown)") :
+#endif /* NEWFTP */
+ ttname) );
+
+ if (net) {
+#ifdef NETCONN
+ int secure = 0;
+ char * xname;
+ if (xnet > nnetname)
+ xname = "[ERROR]";
+ else
+ xname = netname[xnet];
+#ifdef NEWFTP
+ if (ftp) {
+ if (ftpissecure())
+ secure = 1;
+ } else
+#endif /* NEWFTP */
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ secure = 1;
+ }
+ if (secure) {
+ char buf[30];
+ sprintf(buf,"%s (SECURE)",xname);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) buf
+ );
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) xname
+ );
+ }
+#else
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(network)"
+ );
+#endif /* NETCONN */
+ } else {
+ if (speed < 0L)
+ speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880) {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "75/1200"
+ );
+ } else {
+ char speedbuf[64] ;
+ sprintf(speedbuf, "%ld", speed);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) speedbuf
+ );
+ }
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(unknown)"
+ );
+ }
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+ pctlbl = (what & W_SEND);
+ cendw = 0;
+ }
+ debug(F101,"SCREENC switch","",f);
+ debug(F000,"SCREENC c","",c);
+ debug(F101,"SCREENC n","",n);
+
+ len = strlen(s); /* Length of argument string */
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ oldpct = pct = 0L; /* Reset percents */
+#ifdef GFTIMER
+ gtv = (CKFLOAT) -1.0;
+ /* oldgtv = (CKFLOAT) -1.0; */
+#else
+ gtv = -1L;
+ /* oldgtv = -1L; */
+#endif /* GFTIMER */
+ oldwin = -1;
+ fsiz = (CK_OFF_T)-1L; /* Invalidate previous file size */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+ q = len; /* Remember name length for later */
+ scrft(); /* Display file type (can change) */
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_AN: /* File as-name */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_FS: /* File size */
+ fsiz = n;
+ if (fsiz > (CK_OFF_T)-1) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+ }
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ } else {
+ pctlbl = 0;
+ }
+ scrft(); /* File type */
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (spackets < 5) {
+ extern int sysindex;
+ extern struct sysdata sysidlist[];
+ /* Things that won't change after the 4th packet */
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+ if (
+#ifdef NEWFTP
+ (ftp && (spackets == 1 || rpackets == 1)) ||
+#endif /* NEWFTP */
+ spackets == 4
+ ) {
+ if (
+#ifdef NEWFTP
+ ftp ||
+#endif /* NEWFTP */
+ ((protocol == PROTO_K) && (sysindex > -1))
+ ) {
+ char msgbuf[128];
+ if (net) {
+ sprintf(msgbuf,"Network Host: %s (%s)",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "") :
+#endif /* NEWFTP */
+ ttname,
+#ifdef NEWFTP
+ ftp ? ftp_srvtyp :
+#endif /* NEWFTP */
+ sysidlist[sysindex].sid_name
+ );
+ } else {
+ sprintf(msgbuf,
+ "Communication Device: %s (remote host is %s)",
+ ttname,
+ sysidlist[sysindex].sid_name
+ );
+ }
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_LIN,
+ (long) msgbuf
+ );
+ }
+ }
+ }
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ long xx;
+ if (
+#ifdef STREAMING
+ streaming && oldwin != -2
+#else
+ 0
+#endif /* STREAMING */
+ ) {
+ char msgbuf[64];
+ sprintf(msgbuf,"00 / 00");
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_TMO,
+ (long) msgbuf
+ );
+ } else {
+ xx = (rttdelay + 500) / 1000;
+ if (xx != oldrtt || rcvtimo != oldtim) {
+ char msgbuf[64];
+ sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_TMO,
+ (long) msgbuf
+ );
+ oldrtt = xx;
+ oldtim = rcvtimo;
+ clrtoeol();
+ }
+ }
+ }
+#endif /* CK_TIMERS */
+
+ x = (what & W_RECV) ? /* Packet length */
+ rpktl+(protocol==PROTO_K?1:0) :
+ spktl;
+ if (x != oldlen) { /* But only if it changed. */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
+ oldlen = x;
+ }
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
+
+ if (protocol == PROTO_K && !ftp) { /* Window slots */
+ char ws[16];
+ int flag;
+ flag = 0;
+#ifdef STREAMING
+ if (streaming) {
+ if (oldwin != -2) {
+ sprintf(ws,"STREAMING");
+ flag = 1;
+ oldwin = -2;
+ }
+ } else
+#endif /* STREAMING */
+ if (wcur != oldwin) {
+ sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
+ flag = 1;
+ oldwin = wcur;
+ }
+ if (flag) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
+ }
+ }
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Retry count, if changed */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
+ oldtry = errors;
+ }
+ /* Sender's packet type */
+ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
+ char type[2];
+ sprintf(type, "%c",c);
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
+ oldtyp = c;
+ }
+ switch (c) { /* Now handle specific packet types */
+ case 'S': /* Beginning of transfer */
+ fcnt = fbyt = 0L; /* Clear counters */
+#ifdef GFTIMER
+ gtv = -1.0;
+#else /* GFTIMER */
+ gtv = -1L; /* And old/new things... */
+#endif /* GFTIMER */
+ oldpct = pct = 0L;
+ break;
+
+ case 'Z': /* or EOF */
+ debug(F101,"screeng SCR_PT Z pktnum","",n);
+ debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
+ debug(F101,"screeng SCR_PT Z pct","",pct);
+ case 'D': /* Data packet */
+ if (fsiz > 0L) { /* Show percent done if known */
+ oldpct = pct; /* Remember previous percent */
+ howfar = ffc;
+#ifdef CK_RESEND
+ if (what & W_SEND) /* Account for PSEND or RESEND */
+ howfar += sendstart;
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ /* Percent done, to be displayed... */
+ if (c == 'Z') {
+ if (!discard && !cxseen && !czseen) pct = 100L;
+ } else
+ pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
+ if (pct > 100L || /* Allow for expansion and */
+ (oldpct == 99L && pct < 0L)) /* other boundary conditions */
+ pct = 100L;
+ if (pct != oldpct) /* Only do this 100 times per file */
+ updpct(oldpct, pct);
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ break;
+
+ case '%': /* Timeouts, retransmissions */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR,
+ (long) errors
+ );
+ }
+ oldtry = errors;
+ if (s) if (*s) {
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+ }
+ break;
+
+ case 'E': /* Error packet */
+ if (*s) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+ }
+ fcnt = fbyt = 0L; /* So no bytes for this file */
+ break;
+ case 'Q': /* Crunched packet */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Damaged Packet"
+ );
+ break;
+ case 'q': /* Ctrl-C or connection lost */
+ if (!s) s = "";
+ if (!*s) s = "User interruption or connection lost";
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) s
+ );
+ break;
+ case 'T': /* Timeout */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Timeout"
+ );
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+ oldtry = errors;
+ }
+ break;
+ default: /* Others, do nothing */
+ break;
+ }
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_ST: /* File transfer status */
+ debug(F101,"screeng SCR_ST c","",c);
+ debug(F101,"screeng SCR_ST success","",success);
+ debug(F101,"screeng SCR_ST cxseen","",cxseen);
+#ifdef COMMENT
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl)
+ updpct(oldpct,100);
+ else
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+ pct = 100;
+ oldpct = 0;
+ } else if (fsiz > 0L) /* Not OK, update final percent */
+/*
+ The else part writes all over the screen -- howfar and/or fsiz have
+ been reset as a consequence of the not-OKness of the transfer.
+*/
+ if (pctlbl)
+ updpct(oldpct, (howfar * 100L) / fsiz);
+#else
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl) {
+ updpct(oldpct,100);
+ } else
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#ifdef COMMENT
+ pct = 100;
+ oldpct = 0;
+#endif /* COMMENT */
+ }
+#endif /* COMMENT */
+
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+
+ switch (c) { /* Print new status message */
+ case ST_OK: /* Transfer OK */
+ fcnt++; /* Count this file */
+ if (what == (W_FTP|W_FT_DELE)) {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Delete OK"
+ );
+ } else {
+ fbyt += ffc;
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Transfer OK"
+ );
+ }
+ return;
+
+ case ST_DISC: /* Discarded */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File discarded"
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_INT: /* Interrupted */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Transfer interrupted"
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_SKIP: { /* Skipped */
+ char errbuf[64] ;
+ if (n > 0 && n < nskreason)
+ sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
+ else
+ sprintf( errbuf, "File skipped" ) ;
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) errbuf
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+ }
+ case ST_ERR: /* Error message */
+ if (!s) s = (char *)epktmsg;
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_REFU: /* Refused */
+ if (*s) {
+ char errbuf[64] ;
+ sprintf( errbuf, "Refused, %s", s ) ;
+ KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+ }
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_INC:
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_MSG:
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+ return;
+
+ default: /* Bad call */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+ (long) "*** screen() called with bad status ***" );
+ return;
+ }
+
+ case SCR_TC: { /* Transaction complete */
+ char msgbuf[128];
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+ if (success) {
+ sprintf(msgbuf,
+ "SUCCESS. Files: %s, Bytes: %ld, %ld CPS",
+ filcnt - filrej,
+ ckfstoa(fbyt),
+ tfcps
+ );
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) msgbuf
+ );
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_TR,
+ (long) hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+
+#ifdef GFTIMER
+ oldgtv = (CKFLOAT) -1.0;
+#else
+ oldgtv = -1L;
+#endif /* GFTIMER */
+
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+ cendw = 1;
+ if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
+ ft_win = 0; /* Window closed. */
+ return;
+ }
+ case SCR_EM: /* Error packet (fatal) */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+ if (xfrbel) bleep(BP_FAIL);
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case SCR_QE: /* Quantity equals */
+ case SCR_TU: /* Undelimited text */
+ case SCR_TN: /* Text delimited at start */
+ case SCR_TZ: /* Text delimited at end */
+ return; /* (ignored in fullscreen display) */
+
+ case SCR_XD: /* X-packet data */
+ pct = oldpct = 0;
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+ return;
+
+ case SCR_CW: /* Close Window */
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+
+ ft_win = 0; /* Flag that window is closed. */
+ cendw = 1; return;
+
+ case SCR_CD: /* Display current directory */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ default: /* Bad call */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "*** screen() called with bad function code ***"
+ );
+ return;
+ }
+}
+#endif /* KUI */
+#endif /* MAC */
+
+#endif /* NOXFER */
+
+#ifndef CK_CURPOS
+/* Dummies for when cursor control is not supported */
+int
+ck_curpos(row, col) {
+ return(-1);
+}
+
+int
+ck_cls() {
+ return(-1);
+}
+
+int
+ck_cleol() {
+ return(-1);
+}
+#endif /* CK_CURPOS */
+
+#ifndef NOIKSD
+#ifdef IKSDB
+
+struct iksdbfld dbfld[] = {
+ /* Offset Length Type */
+ { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */
+ { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */
+ { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */
+ { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */
+ { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */
+ { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */
+ { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */
+ { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */
+ { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */
+ { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */
+ { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */
+ { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */
+ { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */
+ { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */
+ { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */
+ { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */
+};
+
+static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */
+static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */
+
+static char * updmode = /* Update mode for fopen() */
+#ifdef OS2
+ "r+b"
+#else
+#ifdef VMS
+ "r+b"
+#else
+ "r+"
+#endif /* VMS */
+#endif /* OS2 */
+ ;
+
+/* D B I N I T -- Initialize the IKSD database... */
+
+int
+dbinit() {
+ extern int dbinited;
+ int x = 0;
+ debug(F110,"dbinit dbdir 1",dbdir,0);
+ debug(F110,"dbinit dbfile 1",dbfile,0);
+ if (dbinited)
+ return(0);
+#ifdef OS2
+ if (!dbdir) {
+#ifdef NT
+ char * p = NULL;
+ if (!isWin95()) {
+ p = getenv("SystemRoot");
+ } else {
+ p = getenv("winbootdir");
+ if (!p) p = getenv("windir");
+ }
+ if (!p) p = "C:/";
+ dbdir = malloc(strlen(p)+2);
+ strcpy(dbdir,p); /* safe */
+ p = dbdir;
+ while (*p) {
+ if (*p == '\\')
+ *p = '/';
+ p++;
+ }
+ if (*(p-1) != '/' ) {
+ *p++ = '/';
+ *p = '\0';
+ }
+#else /* NT */
+ makestr(&dbdir,"C:/");
+#endif /* NT */
+ }
+#else /* OS2 */
+ if (!dbdir)
+ makestr(&dbdir,IK_DBASEDIR);
+#endif /* OS2 */
+
+ if (!dbfile) {
+ char * s = "";
+ x = strlen(dbdir);
+ if (dbdir[x-1] != '/') {
+ s = "/";
+ x++;
+ }
+ x += (int)strlen(IK_DBASEFIL);
+ dbfile = (char *)malloc(x+1);
+ sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
+ }
+ debug(F110,"dbinit dbdir 2",dbdir,0);
+ debug(F110,"dbinit dbfile 2",dbfile,0);
+ mypid = getpid(); /* Get my pid */
+ debug(F101,"dbinit mypid","",mypid);
+
+ if (!myhexip[0]) { /* Set my hex IP address */
+#ifdef TCPSOCKET
+ extern unsigned long myxipaddr;
+ if (getlocalipaddr() > -1) {
+ myip = myxipaddr;
+ sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
+ } else
+#endif /* TCPSOCKET */
+ ckstrncpy(myhexip,"00000000",9);
+ }
+ debug(F111,"dbinit myip",myhexip,myip);
+ if (!peerhexip[0]) { /* Get peer's hex IP address */
+#ifdef TCPSOCKET
+ extern unsigned long peerxipaddr;
+ if (ckgetpeer()) {
+ peerip = peerxipaddr;
+ sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
+ debug(F111,"dbinit peerip",peerhexip,peerip);
+ } else {
+ debug(F101,"dbinit ckgetpeer failure","",errno);
+ ckstrncpy(peerhexip,"00000000",9);
+ }
+#else
+ ckstrncpy(peerhexip,"00000000",9);
+#endif /* TCPSOCKET */
+ }
+ debug(F111,"dbinit peerip",peerhexip,peerip);
+ debug(F101,"dbinit dbenabled","",dbenabled);
+ if (dbenabled && inserver) {
+ mydbslot = getslot();
+ debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
+ if (ikdbopen) dbinited = 1;
+ }
+ return(0);
+}
+
+/* U P D S L O T -- Update slot n */
+
+/*
+ Opens the database if necessary, seeks to slot n, writes current record
+ and adds current time to last-update field. n is the record sequence number
+ (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success.
+*/
+int
+updslot(n) int n; { /* Update our slot */
+ int rc = 0;
+ CK_OFF_T position;
+
+ debug(F111,"updslot","ikdbopen",ikdbopen);
+ if (!ikdbopen) /* Not if not ok */
+ return(0);
+ if (!dbfp) { /* Open database if not open */
+ dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */
+ if (!dbfp) {
+ debug(F110,"updslot fopen failed",dbfile,0);
+ ikdbopen = 0;
+ return(-1);
+ }
+ }
+ /* debug(F111,"updslot dbfile",dbfile,dbfp); */
+ position = n * DB_RECL;
+ if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */
+ debug(F111,"updslot fseek failed",dbfile,mydbseek);
+ ikdbopen = 0;
+ rc = -1;
+ } else {
+ /* Update the update time */
+ strncpy(&dbrec[dbfld[db_LASTU].off],
+ ckdate(),
+ dbfld[db_LASTU].len
+ );
+ if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
+ debug(F110,"updslot fwrite failed",dbfile,0);
+ ikdbopen = 0;
+ rc = -1;
+ } else { /* Flush the write */
+ fflush(dbfp);
+ }
+ }
+ return(rc);
+}
+
+/* I N I T S L O T -- Initialize slot n with my info */
+
+int
+initslot(n) int n; { /* Initialize slot */
+ int k;
+#ifdef TCPSOCKET
+ extern unsigned long peerxipaddr;
+#endif /* TCPSOCKET */
+
+ debug(F101,"initslot","",n);
+
+#ifdef USE_MEMCPY
+ memset(dbrec,32,DB_RECL);
+#else
+ for (k = 0; k < DB_RECL; k++)
+ dbrec[k] = '\040';
+#endif /* USE_MEMCPY */
+
+ myflags = DBF_INUSE; /* Set in-use flag */
+ mystate = W_NOTHING;
+ myatype = 0L;
+ myamode = 0L;
+
+ k = dbfld[db_FLAGS].len; /* Length of flags field */
+ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
+
+ k = dbfld[db_ATYPE].len;
+ strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
+
+ k = dbfld[db_AMODE].len;
+ strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
+
+ k = dbfld[db_STATE].len;
+ strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
+
+ k = dbfld[db_SADDR].len;
+ strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
+
+#ifdef TCPSOCKET
+ ckgetpeer();
+ k = dbfld[db_CADDR].len;
+ strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
+#else
+ k = dbfld[db_CADDR].len;
+ strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
+#endif /* TCPSOCKET */
+
+ k = dbfld[db_MYPID].len;
+ strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
+
+ k = dbfld[db_START].len;
+ strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
+
+ k = dbfld[db_ULEN].len;
+ strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
+
+ k = dbfld[db_DLEN].len;
+ strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
+
+ k = dbfld[db_ILEN].len;
+ strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
+
+ strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
+ return(updslot(n));
+}
+
+int
+slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
+ int k, l1, l2, l3, z;
+ mystate = x;
+ debug(F101,"slotstate ikdbopen","",ikdbopen);
+ if (!ikdbopen)
+ return(-1);
+ if (!s1) s1 = "";
+ l1 = strlen(s1);
+ if (!s2) s2 = "";
+ l2 = strlen(s2);
+ if (!s3) s3 = "";
+ l3 = strlen(s3);
+ strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
+ k = dbfld[db_ILEN].len;
+ z = l1 + l2 + l3 + 2;
+ if (z > dB_INFO)
+ z = dB_INFO;
+ strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
+ k = dbfld[db_INFO].len;
+ z = dbfld[db_INFO].off;
+ if (l1 <= k) {
+ lset(&dbrec[z],s1,l1+1,32);
+ z += l1+1;
+ k -= l1+1;
+ if (l2 <= k) {
+ lset(&dbrec[z],s2,l2+1,32);
+ z += l2+1;
+ k -= l2+1;
+ if (l3 <= k)
+ lset(&dbrec[z],s3,k,32);
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ char buf[128];
+ int i;
+ strncpy(buf,&dbrec[DB_INFO],127);
+ buf[127] = NUL;
+ for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
+ debug(F111,"slotstate",buf,mystate);
+ }
+#endif /* DEBUG */
+ z = updslot(mydbslot);
+ debug(F101,"slotstate updslot","",z);
+ return(z);
+}
+
+int
+slotdir(s1,s2) char * s1, * s2; { /* Update current directory */
+ int k, len1, len2;
+ if (!ikdbopen)
+ return(-1);
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+ k = dbfld[db_DLEN].len;
+ strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
+ k = dbfld[db_DIR].len;
+ if (len1 > 0) {
+ lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
+ lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
+ } else {
+ lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
+ }
+ return(updslot(mydbslot));
+}
+
+/* F R E E S L O T -- Free slot n */
+
+int
+freeslot(n) int n; {
+ int k;
+ if (!ikdbopen)
+ return(0);
+ dbflags = 0L;
+ if (n == mydbslot) {
+ dbflags = myflags & ~DBF_INUSE;
+ dbflags &= ~DBF_LOGGED;
+ }
+ k = dbfld[db_FLAGS].len;
+ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
+ return(updslot(n));
+}
+
+/* G E T S L O T -- Find a free database slot; returns slot number */
+
+#ifdef UNIX
+#include <fcntl.h> /* For creat() */
+#endif /* UNIX */
+
+int
+getslot() { /* Find a free slot for us */
+ FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */
+ char idstring[64]; /* PID string buffer (decimal) */
+ char pidbuf[64], * s;
+ int j, k, n, x, rc = -1;
+ int lockfd, tries, haveslot = 0;
+ long lockpid;
+ CK_OFF_T i;
+ /* char ipbuf[17]; */
+
+ if (!myhexip[0]) /* Set my hex IP address if not set */
+ ckstrncpy((char *)myhexip,"7F000001",33);
+ sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
+ debug(F110,"getslot idstring", idstring, 0);
+
+ /* Make temporary lockfile name IP.PID (hex.hex) */
+ /* This should fit in 14 chars -- huge PIDs are usually not possible */
+ /* on 14-char filename systems. */
+
+ sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
+ debug(F110,"getslot tempfile",tmplck,0);
+
+ /* Make a temporary file */
+
+ lockfd = creat(tmplck, 0600); /* BUT THIS ISN'T PORTABLE */
+ if (lockfd < 0) {
+ debug(F111,"getslock temp lockfile create failure", tmplck, errno);
+ return(-1);
+ }
+ /* Write my (decimal) PID into the temp file */
+
+ write(lockfd,idstring,(int)strlen(idstring));
+ if (close(lockfd) < 0) { /* Close lockfile */
+ debug(F101,"getslot error closing temp lockfile", "", errno);
+ return(-1);
+ }
+ sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
+ debug(F110,"getslot lockfile",lcknam,0);
+
+ rfp = fopen(lcknam,"r"); /* See if lockfile exists */
+ if (rfp) { /* If so... */
+ rset(pidbuf,"",64,0);
+ x = fread(pidbuf,1,63,rfp); /* Read ID string from it */
+ fclose(rfp); /* and close it quickly */
+ debug(F110,"getslot lock exists",pidbuf,0);
+ if (x > 0) { /* If we have a PID, check it */
+ char * s = pidbuf;
+ while (*s) {
+ if (islower(*s)) *s = toupper(*s);
+ if (*s == ':') {
+ *s = NUL;
+ debug(F110,"getslot lock IP",pidbuf,0);
+ debug(F110,"gteslot my IP",myhexip,0);
+ if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
+ lockpid = atol(s+1); /* Yes, now get PID */
+ debug(F101,"getslot lockpid","",lockpid);
+
+ /* Check if PID lockpid on this computer is alive */
+ x = zchkpid(lockpid);
+ if (!x) {
+ debug(F100,"getslot PID stale,removing lock","",0);
+ unlink(lcknam);
+ }
+ break;
+ }
+ }
+ s++;
+ }
+ } else {
+ debug(F111,"getslot lockfile open failure",lcknam,errno);
+ }
+ }
+ /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
+
+ for (tries = IK_LCKTRIES; tries > 0; tries--) {
+ if (zrename(tmplck,lcknam) == 0)
+ break;
+ debug(F101,"getslot database locked by pid", "", dbpid);
+ sleep(IK_LCKSLEEP);
+ }
+ if (tries < 1) { /* Couldn't */
+ debug(F110,"getslot create lock failure",lcknam,0);
+ return(-1);
+ }
+ /* Have lock, open database */
+
+ debug(F110,"getslot has lock",lcknam,0); /* Have lock */
+
+ if (!dbfile)
+ return(-1);
+
+ /* If database doesn't exist, create it. */
+
+ debug(F110,"getslot dbfile",dbfile,0);
+ if (zchki(dbfile) < 0) {
+ debug(F110,"getslot creating new database",dbfile,0);
+ x = creat(dbfile,0660);
+ if (x < 0) {
+ debug(F111,"getslot creat() failed", dbfile, errno);
+ goto xslot;
+ }
+ close(x);
+ }
+ dbfp = fopen(dbfile,updmode); /* Open it in update mode */
+ if (!dbfp) {
+ debug(F111,"getslot fopen failed",dbfile,errno);
+ goto xslot;
+ }
+ /* Now find a free (or new) slot... */
+
+ dblastused = 0L; /* Seek pointer to last record inuse */
+ mydbseek = 0L; /* Seek pointer for my record */
+
+ /* Quickly read the whole database; n = record counter, i = seek pointer */
+
+ for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
+ x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
+ if (x < 1) /* EOF not caught by feof() */
+ break;
+#ifndef NOFTRUNCATE
+ if (x != DB_RECL) { /* Watch out for trailing junk */
+ debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */
+#ifdef COHERENT
+ chsize(fileno(dbfp),i);
+#else
+ ftruncate(fileno(dbfp),(CK_OFF_T)i);
+#endif /* COHERENT */
+ x = 0;
+ CKFSEEK(dbfp,i,0);
+ break;
+ }
+#endif /* NOFTRUNCATE */
+ debug(F101,"getslot record","",n);
+ k = dbfld[db_FLAGS].off;
+ j = dbfld[db_FLAGS].len;
+ dbflags = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbflags","",dbflags);
+ k = dbfld[db_MYPID].off;
+ j = dbfld[db_MYPID].len;
+ dbpid = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbpid","",dbpid);
+ k = dbfld[db_SADDR].off;
+ j = dbfld[db_SADDR].len;
+ dbip = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbip","",dbip);
+
+ if (dbflags & DBF_INUSE) { /* Remember last slot in use */
+ x = 0; /* Make sure it's REALLY in use */
+ if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
+ x = 1;
+ debug(F101,"getslot record pid","",dbpid);
+ } else { /* Or for stale PID */
+ x = zchkpid(dbpid);
+ debug(F101,"getslot zchkpid()","",x);
+ }
+ if (!x) { /* Bogus record */
+ x = freeslot(n);
+ debug(F101,"getslot stale record pid: freeslot()","",x);
+ if (x > -1 && !haveslot)
+ dbflags = 0;
+ } else { /* It's really in use */
+ dblastused = i;
+ }
+ }
+ if (!haveslot) { /* If I don't have a slot yet */
+ if (!(dbflags & DBF_INUSE)) { /* Claim this one */
+ debug(F101,"getslot free slot", "", n);
+ haveslot = 1;
+ mydbseek = i;
+ mydbslot = n; /* But keep going... */
+ }
+ }
+ }
+ /* Come here with i == seek pointer to first record after eof */
+
+ if (!haveslot) { /* Found no free slot so add to end */
+ debug(F101,"getslot new slot","",n);
+ haveslot = 1;
+ mydbseek = i;
+ mydbslot = n;
+ }
+ ikdbopen = 1; /* OK to make database entries */
+ debug(F101,"getslot records","",n);
+ debug(F101,"getslot dblastused","",dblastused);
+ debug(F101,"getslot i","",i);
+
+ /* Trim stale records from end */
+
+#ifndef NOFTRUNCATE
+ if (i > dblastused+DB_RECL) {
+ debug(F101,"getslot truncating at","",dblastused+DB_RECL);
+#ifdef COHERENT
+ x = chsize(fileno(dbfp),dblastused+DB_RECL);
+#else
+ x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL));
+#endif /* COHERENT */
+ if (x < 0) /* (Not fatal) */
+ debug(F101,"getslot ftruncate failed", "", errno);
+ }
+#endif /* NOFTRUNCATE */
+
+ /* Initialize my record */
+
+ if (initslot(mydbslot) < 0) {
+ debug(F101,"getslot initslot() error","",n);
+ ikdbopen = 0;
+ goto xslot;
+ }
+ debug(F101,"getslot OK","",mydbslot);
+ rc = mydbslot; /* OK return code */
+
+ xslot: /* Unlock the database and return */
+ if (unlink(lcknam) < 0) {
+ debug(F111,"getslot lockfile removal failed",lcknam,errno);
+ rc = -1;
+ }
+ return(rc);
+}
+#endif /* IKSDB */
+#endif /* NOIKSD */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c.c99 b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c.c99
new file mode 100644
index 0000000..a8a857b
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c.c99
@@ -0,0 +1,9718 @@
+#include "ckcsym.h"
+
+/* C K U U S X -- "User Interface" common functions. */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ This module contains user interface functions needed by both the interactive
+ user interface and the command-line-only user interface, as well as the
+ screen-control routines (curses and equivalent).
+*/
+
+/* Includes */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+
+#ifndef NOHTERMCAP
+#ifdef NOTERMCAP
+#define NOHTERMCAP
+#else
+#ifndef BSD44
+#define NOHTERMCAP
+#else
+#ifdef __bsdi__
+#define NOHTERMCAP
+#else
+#ifdef OPENBSD
+#define NOHTERMCAP
+#else
+#ifdef MACOSX
+#define NOHTERMCAP
+#endif /* MACOSX */
+#endif /* OPENBSD */
+#endif /* __bsdi__ */
+#endif /* BSD44 */
+#endif /* NOTERMCAP */
+#endif /* NOHTERMCAP */
+
+#ifndef NOTERMCAP
+#ifdef BSD44
+#ifndef NOHTERMCAP
+#include <termcap.h>
+#endif /* NOHTERMCAP */
+#endif /* BSD44 */
+#else /* !BSD44 */
+#ifdef linux
+#include <term.h>
+#endif /* linux */
+#endif /* NOTERMCAP */
+
+#ifdef OS2
+#include <string.h>
+_PROTOTYP(char * os2_gethostname, (void));
+#define getpid _getpid
+#endif /* OS2 */
+#ifdef BSD44
+#include <errno.h>
+#endif /* BSD44 */
+
+extern xx_strp xxstring;
+
+#ifdef OS2
+#include "ckcnet.h"
+#else /* OS2 */
+_PROTOTYP( char * ckgetpeer, (VOID));
+_PROTOTYP(int getlocalipaddr, (void));
+_PROTOTYP(int istncomport, (void));
+#ifndef NOCKGETFQHOST
+_PROTOTYP( char * ckgetfqhostname,(char *));
+#endif /* NOCKGETFQHOST */
+#ifndef NETCONN
+/*
+ We should just pull in ckcnet.h here, but it causes a conflict with curses.h.
+*/
+#ifdef TCPSOCKET
+#define NETCONN
+#else
+#ifdef SUNX25
+#define NETCONN
+#else
+#ifdef STRATUSX25
+#define NETCONN
+#else
+#ifdef IBMX25
+#define NETCONN
+#else
+#ifdef HPX25
+#define NETCONN
+#else
+#ifdef DECNET
+#define NETCONN
+#else
+#ifdef NPIPE
+#define NETCONN
+#else
+#ifdef CK_NETBIOS
+#define NETCONN
+#ifdef SUPERLAT
+#define NETCONN
+#else
+#endif /* SUPERLAT */
+#endif /* TCPSOCKET */
+#endif /* SUNX25 */
+#endif /* STRATUSX25 */
+#endif /* IBMX25 */
+#endif /* HPX25 */
+#endif /* DECNET */
+#endif /* NPIPE */
+#endif /* CK_NETBIOS */
+#endif /* NETCONN */
+#endif /* OS2 */
+
+#ifndef TCPSOCKET
+#ifdef MULTINET
+#define TCPSOCKET
+#endif /* MULTINET */
+#ifdef DEC_TCPIP
+#define TCPSOCKET
+#endif /* DEC_TCPIP */
+#ifdef WINTCP
+#define TCPSOCKET
+#endif /* WINTCP */
+#ifdef TCPWARE
+#define TCPSOCKET
+#endif /* TCPWARE */
+#endif /* TCPSOCKET */
+
+#ifdef OS2
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#else /* NT */
+#define INCL_VIO
+#include <os2.h>
+#endif /* NT */
+#ifdef COMMENT /* Would you believe */
+#undef COMMENT /* <os2.h> defines this ? */
+#endif /* COMMENT */
+#ifdef CK_NETBIOS
+#include "ckonbi.h"
+#endif /* CK_NETBIOS */
+
+#include "ckocon.h"
+extern ascreen commandscreen;
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#endif /* OS2 */
+
+#ifdef NT
+#include "cknwin.h"
+#endif /* NT */
+#ifdef OS2
+#include "ckowin.h"
+#include "ckosyn.h"
+#endif /* OS2 */
+
+#ifdef CK_TAPI
+extern int tttapi;
+extern int tapipass;
+#endif /* CK_TAPI */
+
+#ifdef CK_KERBEROS
+#include "ckuath.h"
+#endif /* CK_KERBEROS */
+
+#ifndef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+
+#ifdef VMS
+#include <descrip.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#ifndef OLD_VMS
+#include <lib$routines.h> /* Not for VAX C 2.3 */
+#else
+#include <libdef.h>
+#endif /* OLD_VMS */
+#ifdef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+#endif /* VMS */
+
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * popen, (char *, char *) );
+#endif /* DCLPOPEN */
+
+int tt_crd = 0; /* Carriage return display */
+int tt_lfd = 0; /* Linefeed display */
+int interrupted = 0; /* Interrupted from keyboard flag */
+int fxd_inited = 0; /* Fullscreen stuff initialized */
+
+#ifdef DEBUG
+char debfil[CKMAXPATH+1]; /* Debugging log file name */
+#endif /* DEBUG */
+
+#ifdef TLOG
+char trafil[CKMAXPATH+1]; /* Transaction log file name */
+#endif /* TLOG */
+
+char sesfil[CKMAXPATH+1]; /* Session log file name */
+
+#ifdef CKLOGDIAL
+char diafil[CKMAXPATH+1]; /* Connection log file name */
+char cxlogbuf[CXLOGBUFL+1]; /* Connection log record buffer */
+int cx_active = 0; /* Connection is active */
+extern int dialog;
+#endif /* CKLOGDIAL */
+
+#ifdef DYNAMIC
+static char *cmdstr = NULL; /* Place to build generic command */
+#else
+#ifdef pdp11
+static char cmdstr[256];
+#else
+static char cmdstr[4096];
+#endif /* pdp11 */
+#endif /* DYNAMIC */
+
+#ifndef NOMSEND
+char fspec[CMDBL+4]; /* Filename string for \v(filespec) */
+int fspeclen = CMDBL;
+#else
+char fspec[CKMAXPATH+4];
+int fspeclen = CKMAXPATH;
+#endif /* NOMSEND */
+
+char * rfspec = NULL; /* Received filespec: local */
+char * prfspec = NULL; /* Preliminary rfspec */
+char * sfspec = NULL; /* Sent filespec: local */
+char * psfspec = NULL; /* Preliminary sfspec */
+char * srfspec = NULL; /* Received filespec: remote */
+char * psrfspec = NULL; /* Preliminary srfspec */
+char * rrfspec = NULL; /* Sent filespec: remote */
+char * prrfspec = NULL; /* Preliminary rrfspec */
+
+int success = 1, /* Command success/failure flag */
+ cmdlvl = 0, /* Command level */
+ action = 0, /* Action selected on command line */
+ slogts = 0, /* Session-log timestamps on/off */
+ slognul = 0, /* Session-log null-terminated lines */
+#ifdef UNIX
+ sessft = XYFT_T, /* Session log file type */
+#else
+ sessft = XYFT_B, /* (text for UNIX binary for others) */
+#endif /* UNIX */
+ pflag = 1, /* Print prompt */
+ msgflg = 1; /* Print informational messages */
+
+extern int xaskmore, saveask; /* More-prompting */
+
+#ifdef CK_APC
+extern int apcactive;
+#endif /* CK_APC */
+/* External variables */
+
+extern int local, quiet, binary, network, what, parity, xitsta, escape,
+ tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc;
+
+extern int cmd_rows, cmd_cols, xcmdsrc;
+
+extern char cmdfil[];
+
+#ifdef VMS
+extern int batch;
+#endif /* VMS */
+
+#ifdef datageneral /* 2/12/92 ENH */
+#include <sysid.h>
+extern int con_reads_mt, conint_ch, conint_avl;
+#endif /* datageneral */
+
+extern long speed;
+
+extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
+
+#ifndef NOCSETS
+extern int fcharset, tcharset, xfrxla;
+extern struct csinfo fcsinfo[], tcsinfo[];
+#endif /* NOCSETS */
+
+#ifdef OS2
+extern unsigned char colorcmd;
+#endif /* OS2 */
+
+#ifdef NOXFER
+
+int fdispla = XYFD_N;
+
+#else /* NOXFER is not defined */
+
+#ifdef OS2 /* File transfer display type */
+int fdispla = XYFD_C; /* Curses (fullscreen) if we have it */
+#else
+#ifdef CK_CURSES
+int fdispla = XYFD_C;
+#else
+int fdispla = XYFD_S; /* Otherwise CRT */
+#endif /* CK_CURSES */
+#endif /* OS2 */
+
+extern struct ck_p ptab[];
+extern int protocol, xfrbel, xfrint;
+
+#ifdef STREAMING
+extern int streaming, streamok;
+#endif /* STREAMING */
+
+/* Used internally */
+
+#ifdef KUI
+_PROTOTYP( VOID screeng, (int, char, long, char *) );
+#endif /* KUI */
+_PROTOTYP( VOID screenc, (int, char, CK_OFF_T, char *) );
+
+
+#ifdef CK_CURSES
+#ifndef DYNAMIC
+static char xtrmbuf[TRMBUFL]; /* tgetent() buffer */
+char * trmbuf = xtrmbuf;
+#else
+char * trmbuf = NULL;
+#endif /* DYNAMIC */
+_PROTOTYP( static VOID dpyinit, (void) );
+_PROTOTYP( static long shocps, (int, CK_OFF_T, CK_OFF_T) );
+_PROTOTYP( static CK_OFF_T shoetl, (CK_OFF_T, long, CK_OFF_T, CK_OFF_T) );
+#endif /* CK_CURSES */
+
+static int ft_win = 0; /* Fullscreen file transfer display window is active */
+
+/* Variables declared here */
+
+static char * skreason[] = {
+ "", /* 0 */
+ "Remote file not older", /* SKP_DAT */
+ "Identical modification times", /* SKP_EQU */
+ "Type", /* SKP_TYP */
+ "Size", /* SKP_SIZ */
+ "Name collision", /* SKP_NAM */
+ "Exception List", /* SKP_EXL */
+ "Dot file", /* SKP_DOT */
+ "Backup file", /* SKP_BKU */
+ "Recovery not needed", /* SKP_RES */
+ "Access denied", /* SKP_ACC */
+ "Not a regular file", /* SKP_NRF */
+ "Simulated", /* SKP_SIM */
+ "Simulated - Remote file older", /* SKP_XUP */
+ "Simulated - No remote file", /* SKP_XNX */
+};
+static int nskreason = (sizeof(skreason) / sizeof(char *));
+
+char *
+gskreason(n) int n; {
+ return((n > 0 && n < nskreason) ? skreason[n] : "");
+}
+
+char pktfil[CKMAXPATH+1]; /* Packet log file name */
+
+#ifndef NOMSEND /* Multiple SEND */
+char *msfiles[MSENDMAX];
+#endif /* NOMSEND */
+
+#ifdef CK_TIMERS
+extern long rttdelay;
+extern int rttflg;
+#endif /* CK_TIMERS */
+extern int rcvtimo;
+
+#ifdef CK_RESEND
+extern int sendmode;
+extern CK_OFF_T sendstart, rs_len;
+#endif /* CK_RESEND */
+
+#ifdef CK_PCT_BAR /* File transfer thermometer */
+int thermometer = 1; /* ON by default */
+#endif /* CK_PCT_BAR */
+
+#ifdef GFTIMER
+CKFLOAT gtv = -1.0, oldgtv = -1.0;
+#else
+#ifndef OS2
+static
+#endif /* OS2 */
+ long gtv = -1L, oldgtv = -1L;
+#endif /* GFTIMER */
+
+extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen,
+ winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu,
+ swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs,
+ pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl,
+ retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts,
+ rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive;
+
+extern long filcnt, filrej, rptn, filcps, tfcps, cps, peakcps;
+extern CK_OFF_T ffc, tfc, fsize;
+
+long oldcps = 0L;
+
+extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg;
+extern char *xfrmsg;
+
+#ifdef IKSDB
+FILE * dbfp = NULL; /* File pointer to database file */
+
+int dbenabled = 1; /* Flag for database is enabled */
+extern int ikdbopen; /* Flag for database is open */
+
+unsigned long mydbseek = 0L; /* Seek pointer to my record */
+int mydbslot = 0; /* My slot number */
+unsigned long myflags = 0L; /* My flags */
+unsigned long myatype = 0L; /* My authorization type */
+unsigned long myamode = 0L; /* My authorization mode */
+unsigned long mystate = 0L; /* My state (SEND, RECEIVE, etc) */
+unsigned long mypid = 0L; /* My PID */
+unsigned long myip = 0L; /* My IP address */
+unsigned long peerip = 0L; /* My peer's IP address */
+
+unsigned long dbip = 0L; /* IP address in db record */
+unsigned long dbpid = 0L; /* PID in db record */
+unsigned long dbflags = 0L; /* Flags field in db record */
+unsigned long dblastused = 0L; /* Last in-use record in db */
+char dbrec[DB_RECL]; /* Database record buffer */
+
+char * dbdir = NULL; /* Database directory */
+char * dbfile = NULL; /* Database file full pathname */
+char myhexip[33] = { NUL, NUL }; /* My IP address in hex */
+char peerhexip[33] = { NUL, NUL }; /* Client's IP address in hex */
+#endif /* IKSDB */
+
+#ifdef GFTIMER
+extern CKFLOAT fpfsecs, fptsecs, fpxfsecs;
+#else
+extern long xfsecs;
+#endif /* GFTIMER */
+#endif /* NOXFER */
+
+#ifdef TCPSOCKET
+#ifdef NEWFTP
+extern char * ftp_host, ftp_srvtyp[];
+extern int ftp_csx, ftp_csl, ftp_deb;
+#endif /* NEWFTP */
+extern char myipaddr[];
+#endif /* TCPSOCKET */
+
+#ifndef NOICP
+#ifndef NOSPL
+ extern struct mtab *mactab; /* For ON_EXIT macro. */
+ extern int nmac;
+#endif /* NOSPL */
+#ifdef DCMDBUF
+extern char *cmdbuf; /* Command buffer */
+#else
+extern char cmdbuf[]; /* Command buffer */
+#endif /* DCMDBUF */
+extern int cmd_quoting;
+#endif /* NOICP */
+
+#ifndef NOCCTRAP
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcsig.h"
+extern ckjmpbuf cmjbuf;
+#endif /* NOCCTRAP */
+
+extern int xfiletype, nscanfile;
+
+int
+shoesc(escape) int escape; {
+ extern char * ccntab[]; /* C0 control character name table */
+ extern int tt_escape;
+ if ((escape > 0 && escape < 32) || (escape == 127)) {
+ printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n",
+ ctl(escape),
+ escape,
+ (escape == 127 ? "DEL" : ccntab[escape]),
+ tt_escape ? "enabled" : "disabled"
+ );
+ } else {
+ printf(" Escape character: Code %d",escape);
+ if (escape > 160 && escape < 256)
+ printf(" (%c)",escape);
+ printf(": %s\r\n", tt_escape ? "enabled" : "disabled");
+ }
+ return(0);
+}
+
+#ifndef NOXFER
+/* P R E S E T -- Reset global protocol variables */
+
+extern int recursive;
+
+#ifdef PATTERNS
+int patterns = SET_AUTO; /* Whether to use filename patterns */
+extern int g_patterns; /* For saving and restoring */
+#else
+int patterns = SET_OFF;
+#endif /* PATTERNS */
+
+#ifndef NOICP
+#ifdef CK_LABELED
+extern int g_lf_opts, lf_opts;
+#endif /* CK_LABELED */
+extern int g_matchdot, g_usepipes, usepipes;
+extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv;
+extern int g_recursive;
+extern int g_xfermode, xfermode;
+extern int g_urpsiz, g_spsizf, g_spsiz;
+extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact;
+extern int g_fnspath, g_fnrpath, g_skipbup;
+extern int nolinks;
+#ifdef CKSYMLINK
+extern int zgfs_link;
+#endif /* CKSYMLINK */
+#ifndef NOSPL
+extern int g_pflg, pwflg, g_pcpt, pwcrypt;
+extern char * g_pswd, pwbuf[];
+#endif /* NOSPL */
+#endif /* NOICP */
+
+extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath;
+extern int moving; /* SEND criteria */
+extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[];
+extern CK_OFF_T sndlarger, sndsmaller, calibrate;
+extern int rmailf, rprintf, skipbup;
+extern char optbuf[];
+
+#ifdef PIPESEND
+extern char * g_sfilter, * g_rfilter;
+extern char * sndfilter, * rcvfilter;
+#endif /* PIPESEND */
+extern char ** sndarray;
+
+VOID
+ftreset() {
+#ifndef NOICP
+ int i;
+ extern char * filefile;
+ extern int reliable, xreliable, c_save, ss_save, slostart, urclear;
+ extern int oopts, omode, oname, opath, kactive, autopath;
+ extern char * snd_move; /* Directory to move sent files to */
+ extern char * snd_rename; /* What to rename sent files to */
+ extern char * rcv_move;
+ extern char * rcv_rename;
+ extern char * g_snd_move;
+ extern char * g_snd_rename;
+ extern char * g_rcv_move;
+ extern char * g_rcv_rename;
+
+#ifdef CK_TMPDIR
+ extern int f_tmpdir;
+ extern char savdir[];
+#endif /* CK_TMPDIR */
+
+#ifdef CK_SPEED
+#ifdef COMMENT
+ extern int f_ctlp;
+ extern short s_ctlp[], ctlp[];
+#endif /* COMMENT */
+#endif /* CK_SPEED */
+
+#ifndef NOCSETS
+ extern int fcs_save, tcs_save;
+ extern int g_xfrxla, xfrxla;
+#endif /* NOCSETS */
+
+/* Restore / reset per-command file-transfer switches */
+
+ makestr(&snd_move,g_snd_move);
+ makestr(&rcv_move,g_rcv_move);
+ makestr(&snd_rename,g_snd_rename);
+ makestr(&rcv_rename,g_rcv_rename);
+
+ kactive = 0; /* Kermit protocol no longer active */
+ oopts = -1; /* O-Packet Options */
+ omode = -1; /* O-Packet Transfer Mode */
+ oname = -1; /* O-Packet Filename Options */
+ opath = -1; /* O-Packet Pathname Options */
+
+#ifdef CK_RESEND
+ rs_len = 0L; /* REGET position */
+#endif /* CK_RESEND */
+
+#ifdef COMMENT
+#ifdef CK_SPEED
+ if (f_ctlp) {
+ for (i = 0; i < 256; i++)
+ ctlp[i] = s_ctlp[i];
+ f_ctlp = 0;
+ }
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+
+#ifdef CK_TMPDIR
+ if (f_tmpdir) { /* If we changed to download dir */
+ zchdir((char *) savdir); /* Go back where we came from */
+ f_tmpdir = 0;
+ }
+#endif /* CK_TMPDIR */
+
+ calibrate = 0L; /* Calibration run */
+ if (xreliable > -1) {
+ reliable = xreliable;
+ debug(F101,"ftreset reliable","",reliable);
+ }
+ urclear = 0;
+
+ if (autopath) { /* SET RECEIVE PATHNAMES AUTO */
+ fnrpath = PATH_AUTO;
+ autopath = 0;
+ }
+ if (filefile) { /* File list */
+ zclose(ZMFILE);
+ makestr(&filefile,NULL);
+ }
+ if (c_save > -1) { /* Block Check Type */
+ bctr = c_save;
+ c_save = -1;
+ }
+ if (ss_save > -1) { /* Slow Start */
+ slostart = ss_save;
+ ss_save = -1;
+ }
+#ifdef CK_LABELED
+ if (g_lf_opts > -1) {
+ lf_opts = g_lf_opts; /* Restore labeled transfer options */
+ g_lf_opts = -1;
+ }
+#endif /* CK_LABELED */
+
+#ifndef NOCSETS
+ if (tcs_save > -1) { /* Character sets */
+ tcharset = tcs_save;
+ tcs_save = -1;
+ }
+ if (fcs_save > -1) {
+ fcharset = fcs_save;
+ fcs_save = -1;
+ }
+ if (g_xfrxla > -1) {
+ xfrxla = g_xfrxla;
+ g_xfrxla = -1;
+ }
+ setxlatype(tcharset,fcharset); /* Translation type */
+#endif /* NOCSETS */
+
+#ifdef NETCONN
+#ifndef NOSPL
+ if (g_pswd) {
+ ckstrncpy(pwbuf,g_pswd,PWBUFL);
+ makestr(&g_pswd,NULL);
+ }
+ if (g_pflg > -1) {
+ pwflg = g_pflg;
+ g_pflg = -1;
+ }
+ if (g_pcpt > -1) {
+ pwcrypt = g_pcpt;
+ g_pcpt = -1;
+ }
+#endif /* NOSPL */
+#endif /* NETCONN */
+
+ if (g_binary > -1) { /* File type */
+ binary = g_binary;
+ g_binary = -1;
+ }
+ if (g_xfermode > -1) { /* Transfer mode */
+ xfermode = g_xfermode;
+ g_xfermode = -1;
+ }
+#ifdef PATTERNS
+ if (g_patterns > -1) { /* Filename patterns */
+ patterns = g_patterns;
+ g_patterns = -1;
+ }
+#endif /* PATTERNS */
+
+ if (g_usepipes > -1) {
+ usepipes = g_usepipes;
+ g_usepipes = -1;
+ }
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot;
+ g_matchdot = -1;
+ }
+ if (g_proto > -1) { /* Protocol */
+ protocol = g_proto;
+ g_proto = -1;
+ }
+ if (g_urpsiz > -1) {
+ urpsiz = g_urpsiz;
+ debug(F101,"ftreset restoring urpsiz","",urpsiz);
+ g_urpsiz = -1;
+ }
+ if (g_spsizf > -1) {
+ spsizf = g_spsizf;
+ debug(F101,"ftreset restoring spsizf","",spsizf);
+ g_spsizf = -1;
+ }
+ if (g_spsiz > -1) {
+ spsiz = g_spsiz;
+ debug(F101,"ftreset restoring spsiz","",spsiz);
+ g_spsiz = -1;
+ }
+ if (g_spsizr > -1) {
+ spsizr = g_spsizr;
+ debug(F101,"ftreset restoring spsizr","",spsizr);
+ g_spsizr = -1;
+ }
+ if (g_spmax > -1) {
+ spmax = g_spmax;
+ g_spmax = -1;
+ }
+ if (g_wslotr > -1) {
+ wslotr = g_wslotr;
+ g_wslotr = -1;
+ }
+ if (g_prefixing > -1) {
+ prefixing = g_prefixing;
+ g_prefixing = -1;
+ }
+ if (g_fncact > -1) {
+ fncact = g_fncact;
+ g_fncact = -1;
+ }
+ if (g_fncnv > -1) {
+ fncnv = g_fncnv;
+ g_fncnv = -1;
+ }
+ if (g_fnspath > -1) {
+ fnspath = g_fnspath;
+ g_fnspath = -1;
+ }
+ if (g_fnrpath > -1) {
+ fnrpath = g_fnrpath;
+ g_fnrpath = -1;
+ }
+ if (g_skipbup > -1) {
+ skipbup = g_skipbup;
+ g_skipbup = -1;
+ }
+ nolinks = 2; /* /FOLLOWLINKS is never global */
+ recursive = 0; /* /RECURSIVE can never be global */
+ xfiletype = -1;
+
+ if (g_displa > -1) { /* File transfer display */
+ fdispla = g_displa;
+ g_displa = -1;
+ }
+ if (g_spath > -1) { /* Send pathnames */
+ fnspath = g_spath;
+ g_spath = -1;
+ }
+ if (g_rpath > -1) { /* Receive pathnames */
+ fnrpath = g_rpath;
+ g_rpath = -1;
+ }
+ if (g_fncnv > -1) { /* Filename conversion */
+ fncnv = g_fncnv;
+ g_fncnv = -1;
+ }
+#ifdef PIPESEND
+ makestr(&sndfilter,g_sfilter); /* Send filter */
+ makestr(&rcvfilter,g_rfilter); /* Receive filter */
+#endif /* PIPESEND */
+
+#ifndef NOFRILLS
+ rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */
+ optbuf[0] = NUL; /* MAIL and PRINT options */
+#endif /* NOFRILLS */
+
+ moving = 0; /* Reset delete-after-send indicator */
+ sndafter[0] = NUL; /* Reset SEND selection switches */
+ sndbefore[0] = NUL;
+
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ if (sndexcept[i])
+ free(sndexcept[i]);
+ sndexcept[i] = NULL;
+ if (rcvexcept[i])
+ free(rcvexcept[i]);
+ rcvexcept[i] = NULL;
+ }
+ sndlarger = (CK_OFF_T)-1;
+ sndsmaller = (CK_OFF_T)-1;
+ debug(F101,"present sndsmaller","",sndsmaller);
+#ifdef GFTIMER
+ gtv = -1.0;
+ oldgtv = -1.0;
+#else
+ gtv = -1L;
+ oldgtv = -1L;
+#endif /* GFTIMER */
+#endif /* NOICP */
+}
+#endif /* NOXFER */
+
+char *
+ttgtpn() { /* Get typical port name */
+/*
+ Ideally this routine would be implemented in each of the cku?io.* modules,
+ but that requires changing the API definition.
+*/
+ return(
+#ifdef OS2
+#ifdef OS2ONLY
+"COM1"
+#else /* OS2ONLY */
+"TAPI [ name ] or COM1"
+#endif /* OS2ONLY */
+#else /* OS2 */
+#ifdef VMS
+"TXA0:, TTA0:, or LTA0:"
+#else /* VMS */
+#ifdef SOLARIS
+"/dev/cua/a"
+#else /* SOLARIS */
+#ifdef HPUX10
+"/dev/cua0p0"
+#else /* HPUX10 */
+#ifdef HPUX
+"/dev/cua00"
+#else /* HPUX */
+#ifdef __FreeBSD__
+"/dev/cuaa0"
+#else /* __FreeBSD__ */
+#ifdef __linux__
+"/dev/ttyS0"
+#else /* __linux__ */
+#ifdef BSD44
+"/dev/tty00"
+#else /* BSD44 */
+#ifdef OSK
+"/t1"
+#else /* OSK */
+#ifdef QNX
+"/dev/ser1"
+#else /* QNX */
+#ifdef QNX6
+"/dev/ser1"
+#else /* QNX6 */
+#ifdef UNIXWARE
+"/dev/term/00 or /dev/tty00"
+#else /* UNIXWARE */
+#ifdef CK_SCOV5
+"/dev/tty1A"
+#else /* CK_SCOV5 */
+#ifdef CK_SCO32V4
+"/dev/tty1A"
+#else /* CK_SCO32V4 */
+#ifdef M_XENIX
+"/dev/tty1A"
+#else /* M_XENIX */
+#ifdef AIXRS
+"/dev/tty0"
+#else /* AIXRS */
+#ifdef DGUX
+"/dev/tty00"
+#else /* DGUX */
+#ifdef datageneral
+"@con1"
+#else /* datageneral */
+#ifdef IRIX
+"/dev/ttym0"
+#else /* IRIX */
+#ifdef SUNOS4
+"/dev/ttyh0"
+#else /* SUNOS4 */
+#ifdef SV68R3V6
+"/dev/scc0"
+#else /* SV68R3V6 */
+#ifdef MOTSV88R4
+"/dev/contty00"
+#else /* MOTSV88R4 */
+#ifdef NEXT
+"/dev/cufa"
+#else
+#ifdef OSF
+"/dev/ttyd1"
+#else
+#ifdef SINIX
+"/dev/ttyc1"
+#else
+#ifdef UNIX
+"/dev/cua, /dev/acu, /dev/tty0, etc"
+#else /* UNIX */
+"(sorry no example available)"
+#endif /* UNIX */
+#endif /* SINIX */
+#endif /* OSF */
+#endif /* NEXT */
+#endif /* MOTSV88R4 */
+#endif /* SV68R3V6 */
+#endif /* SUNOS4 */
+#endif /* IRIX */
+#endif /* datageneral */
+#endif /* DGUX */
+#endif /* AIX */
+#endif /* M_XENIX */
+#endif /* CK_SCO32V4 */
+#endif /* CK_SCOV5 */
+#endif /* UNIXWARE */
+#endif /* QNX6 */
+#endif /* QNX */
+#endif /* OSK */
+#endif /* BSD44 */
+#endif /* __linux__ */
+#endif /* __FreeBSD__ */
+#endif /* HPUX */
+#endif /* HPUX10 */
+#endif /* SOLARIS */
+#endif /* VMS */
+#endif /* OS2 */
+ );
+}
+
+/* C K _ E R R S T R -- Return message from most recent system error */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+char *
+ck_errstr() {
+#ifdef USE_STRERROR
+#ifndef CK_ANSILIBS
+ /* Should have been declared in <string.h> */
+_PROTOTYP( char * strerror, (int) );
+#endif /* CK_ANSILIBS */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ return(strerror(errno));
+#else /* !USE_STRERROR */
+#ifdef VMS
+ extern char * ckvmserrstr(unsigned long);
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ return(ckvmserrstr(0L));
+#else /* !VMS */
+#ifdef BSD44
+#ifdef __386BSD__
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#else /* !__386BSD__ */
+#ifndef __bsdi__
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern const char *const sys_errlist[];
+#endif /* NDSYSERRLIST */
+#endif /* __bsdi__ */
+#endif /* __386BSD__ */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else /* !BSD44 */
+#ifdef ATTSV
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else /* !ATTSV */
+#ifdef BSD4
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else
+#ifdef OS2
+#ifndef NDSYSERRLIST
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef NT
+ extern int_sys_nerr;
+#endif /* NT */
+ char *e;
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ e = (errno > -1
+#ifdef NT
+ && errno <= _sys_nerr
+#endif /* NT */
+ ) ?
+#ifdef NT
+ (char *) sys_errlist[errno]
+#else /* NT */
+ /* I don't know how to get a CLIB error string in OS/2 */
+ strerror(errno)
+#endif /* NT */
+ : "";
+ return(e ? e : "");
+#else /* OS2 */
+ return("");
+#endif /* OS2 */
+#endif /* BSD4 */
+#endif /* ATTSV */
+#endif /* BSD44 */
+#endif /* VMS */
+#endif /* USE_STRERROR */
+}
+
+#ifdef PATTERNS
+/*
+ Filename pattern recognition lists for automatic text/binary switching.
+ These are somewhat passe after the addition of scanfile() (7.0).
+ But with the addition of FTP [M]GET, they're back in style (8.0).
+
+ Although, with FTP the lists need to be used in the reverse. With
+ Kermit the list is used to imply the types of the local system. Whereas
+ with FTP, the list must be used to imply the type of the remote system.
+ Therefore, all platforms must now support all of the lists.
+*/
+char *txtpatterns[FTPATTERNS+1] = { NULL, NULL };
+char *binpatterns[FTPATTERNS+1] = { NULL, NULL };
+/*
+ Default pattern lists for each platform...
+
+ NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they
+ are traditionally text types, they are binary in Windows. So they are
+ handled by the prevailing SET FILE TYPE, rather than automatically.
+ Similarly for ".dat", ".inf", and so on. Also ".ps" since PostScript files
+ are not always text. ".log" is omitted since logs can be text or binary,
+ except in VMS they are usually text, etc etc.
+
+ Later (Sep 2003): Add PostScript to binary patterns.
+*/
+static char *txtp[SYS_MAX][FTPATTERNS] = {
+ /* UNKNOWN */ {
+ NULL, NULL
+ },
+ { /* UNIX */
+ "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd",
+ "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx",
+ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh",
+ "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed",
+ "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac",
+ NULL
+ },
+ { /* WIN32 */
+ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
+ "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL
+ },
+ { /* VMS */
+ "*.com","*.txt","*.c", "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli",
+ "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log",
+ "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt",
+ "*.mem",NULL
+ },
+ { /* OS2 */
+ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
+ NULL
+ },
+ { /* DOS */
+ "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL
+ },
+ { /* TOPS-10 */
+ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
+ "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
+ "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
+ },
+ { /* TOPS-20 */
+ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
+ "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
+ "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
+ },
+ { /* STRATUS VOS */
+ "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex",
+ "*.hqx","*.c", "*.h", "*.w", "*.java","*.bwr","*.upd","*.ttp","*.cm",
+ "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL
+ },
+ { /* DG AOS/VS */
+ "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me",
+ "*.cli", "*.ksc", NULL
+ },
+ { /* OSK */
+ "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */
+ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp",
+ "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed",
+ "*.txt","*.w", /* general text */
+ "*.ksc","*.bwr","*.upd",
+ "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx",
+ "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*",
+ NULL
+ }
+};
+
+/* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */
+
+static char *binp[SYS_MAX][FTPATTERNS] = {
+ { /* UNKNOWN */
+ NULL, NULL
+ },
+ { /* UNIX */
+ "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out",
+ "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class",
+ "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx",
+ "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit",
+ "*.ps", NULL
+ },
+ { /* WIN32 */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg",
+ "*.ps", NULL
+ },
+ { /* VMS */
+ "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp",
+ "*.ps", "*.dat","*.par", NULL
+ },
+ { /* OS2 */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", NULL
+ },
+ { /* DOS */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", NULL
+ },
+ { /* TOPS10 */
+ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
+ "*.ps", NULL
+ },
+ { /* TOPS20 */
+ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
+ "*.ps", NULL
+ },
+ { /* STRATUS VOS */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", "*.pm", NULL
+ },
+ { /* DG */
+ "*.ob", "*.pr", "*.dmp", "*.ps", NULL
+ },
+ { /* OSK */
+ "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */
+ "*.zip","*.ar","*.zoo","*.rpm","*.lzh",
+ /* object files, libraries, executables */
+ "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class",
+ /* images */
+ "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps",
+ "*.bmp", "*.bz2", "*.BMP","*.pcx",
+ NULL
+ }
+};
+
+/*
+ Set up default pattern lists so they can be freed and re-malloc'd.
+ Each pattern list must terminated by a null element.
+*/
+VOID
+initpat() {
+ int i;
+ for (i = 0; i < FTPATTERNS; i++) {
+ txtpatterns[i] = NULL;
+ binpatterns[i] = NULL;
+ }
+ for (i = 0; i < FTPATTERNS; i++) {
+#ifdef UNIX
+ makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]);
+#else /* UNIX */
+#ifdef OS2
+#ifdef NT
+ makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]);
+#else /* NT */
+ makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]);
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+ makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]);
+#else /* VMS */
+#ifdef STRATUS
+ makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]);
+#else /* STRATUS */
+#ifdef datageneral
+ makestr(&(txtpatterns[i]),txtp[SYS_DG][i]);
+#else /* datageneral */
+#ifdef OSK
+ makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]);
+#else /* OSK */
+ makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]);
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+ if (!txtp[i])
+ break;
+ }
+ for (i = 0; i < FTPATTERNS; i++) {
+#ifdef UNIX
+ makestr(&(binpatterns[i]),binp[SYS_UNIX][i]);
+#else /* UNIX */
+#ifdef OS2
+#ifdef NT
+ makestr(&(binpatterns[i]),binp[SYS_WIN32][i]);
+#else /* NT */
+ makestr(&(binpatterns[i]),binp[SYS_OS2][i]);
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+ makestr(&(binpatterns[i]),binp[SYS_VMS][i]);
+#else /* VMS */
+#ifdef STRATUS
+ makestr(&(binpatterns[i]),binp[SYS_VOS][i]);
+#else /* STRATUS */
+#ifdef datageneral
+ makestr(&(binpatterns[i]),binp[SYS_DG][i]);
+#else /* datageneral */
+#ifdef OSK
+ makestr(&(binpatterns[i]),binp[SYS_OSK][i]);
+#else /* OSK */
+ makestr(&(binpatterns[i]),binp[SYS_UNK][i]);
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+ if (!binp[i])
+ break;
+ }
+}
+
+/*
+ m a t c h n a m e -- Compare filename with text & binary name patterns.
+
+ Returns:
+ 0 if name matches a text pattern but not a binary pattern.
+ 1 if name matches a binary pattern but not a text pattern.
+ -1 if name matches no patterns.
+ -2 if name matches a binary pattern and a text pattern.
+*/
+int
+matchname(filename, local, os) char * filename; int local; int os; {
+ int rc = -1; /* Return code */
+ char * name, * p;
+#ifdef OS2ORUNIX
+ char tmpbuf[CKMAXPATH+1];
+#endif /* OS2ORUNIX */
+
+ name = filename ? filename : ""; /* Copy of original arg */
+ if (patterns && *name) { /* If PATTERNS ON... */
+ int i;
+
+#ifdef OS2ORUNIX
+ if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */
+ int k;
+ k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */
+ for (i = k - 3; i > 4; i--) {
+ if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') {
+ tmpbuf[i-1] = NUL;
+ break;
+ }
+ }
+ name = tmpbuf; /* And point to stripped copy */
+ }
+#endif /* OS2ORUNIX */
+ zstrip(name,&p); /* Strip pathname too */
+ name = p;
+
+ if (local) {
+ if (txtpatterns[0]) { /* Search text patterns */
+ for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
+ if (ckmatch(txtpatterns[i],name,filecase,1)) {
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (binpatterns[0]) { /* And search binary patterns */
+ for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
+ if (ckmatch(binpatterns[i],name,filecase,1)) {
+ rc = (rc > -1) ? -2 : 1;
+ break;
+ }
+ }
+ }
+ } else {
+ if (os >= 0 && os < SYS_MAX) {
+ if (txtp[os][0]) {
+ for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) {
+ if (ckmatch(txtp[os][i],name,filecase,1)) {
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (binp[os][0]) {
+ for (i = 0; i < FTPATTERNS && binp[os][i]; i++) {
+ if (ckmatch(binp[os][i],name,filecase,1)) {
+ rc = (rc > -1) ? -2 : 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ debug(F111,"matchname",name,rc);
+ return(rc);
+}
+#endif /* PATTERNS */
+
+#ifdef UNICODE
+#ifndef NOEVENMAX
+#define EVENMAX
+#endif /* NOEVENMAX */
+#endif /* UNICODE */
+
+/* S C A N F I L E -- Analyze a file's contents */
+
+/*
+ Call with:
+ name: Pointer to name of existing file.
+ flag: Pointer to int in which to return additional numeric data.
+
+ Returns:
+ -1 on failure (to open file or to read from it).
+ Integer, 0..4, on success indicating file type:
+ 0 = 7-bit text (flag = -1)
+ 1 = UTF-8 text (flag = -1)
+ 2 = UCS-2 text (flag = 0: big-endian; flag = 1: little-endian)
+ 3 = 8-bit text (flag = 0: no C1 bytes; flag = 1: includes C1 bytes)
+ 4 = Text (type unknown)
+ 5 = binary (flag = -1)
+
+ If UNICODE is defined:
+
+ 1. If file begins with a valid BOM, it is believed. Otherwise we
+ read the first 4K of the file (since it might be email with verbose
+ headers) and analyze it:
+
+ 2. If file contains only valid UTF-8 sequences, we call it UTF-8;
+ otherwise:
+
+ 3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and
+ set the polarity according to whether the preponderance of them are in
+ even or odd positions; otherwise:
+
+ 4. If EVENMAX is defined and the file contains lots of alternate bytes that
+ are identical, even if they aren't zero, and the number of such bytes
+ is at least four times the length of the maximum run of alternating
+ identical bytes of the opposite polarity, we call it UCS-2; otherwise:
+
+ 5. If the file contained no bytes with their 8th bits on and no controls
+ other than CR, LF, HT, and FF, we call it ASCII; otherwise:
+
+ 6. If it contains C0 control characters other than CR, LF, HT, and FF, we
+ call it binary; otherwise:
+
+ 7. We call it 8-bit text, character set unknown (could be Latin-1 or
+ anything else).
+
+ Note that malformed UTF-8 is not diagnosed as UTF-8.
+
+ If UNICODE is not defined:
+
+ 1. If the file contains C0 control characters other than CR, LF, HT, and
+ FF, we call it binary; otherwise:
+
+ 2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise:
+
+ 3. We call it 7-bit text.
+
+ In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as
+ 8-bit text.
+
+ There is no significant speed difference between the Unicode and
+ non-Unicode cases.
+*/
+int
+scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
+ FILE * fp; /* File pointer */
+ unsigned char buf[SCANFILEBUF]; /* File data buffer for analysis */
+ int x, val = -1, count = 0; /* Workers */
+ int rc = -1; /* Return code */
+ int pv = -1; /* Pattern-match value */
+ int eof = 0; /* Flag for file EOF encountered */
+ int bytes = 0; /* Total byte count */
+#ifdef UNICODE
+ unsigned int c0, c1; /* First 2 file bytes (for BOM) */
+#endif /* UNICODE */
+ extern int pipesend, filepeek;
+
+ register int i; /* Loop control */
+ int readsize = 0; /* How much to read */
+ int eightbit = 0; /* Number of bytes with 8th bit on */
+ int c0controls = 0; /* C0 non-text control-char counter */
+ int c0noniso = 0; /* C0 non-ISO control-char counter */
+ int c1controls = 0; /* C1 control-character counter */
+ unsigned int c; /* Current character */
+ int runmax = 0; /* Longest run of 0 bytes */
+ int runzero = 0; /* Run of 0 bytes */
+ int pctzero = 0; /* Percentage of 0 bytes */
+ int txtcz = 0;
+#ifdef CK_CTRLZ
+ extern int eofmethod;
+#endif /* CK_CTRLZ */
+
+#ifdef UNICODE
+ int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
+ int utf8state = 0; /* UTF-8 recognizer state */
+ int oddzero = 0; /* Number of 0 bytes in odd postions */
+ int evenzero = 0; /* and in even positions */
+ int lfnul = 0; /* Number of <LF><NUL> sequences */
+ int crlf = 0; /* Number of <CRLF> sequences */
+#else
+ int notutf8 = 1;
+#endif /* UNICODE */
+
+#ifdef COMMENT
+#ifdef EVENMAX
+ int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0;
+ int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0;
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+#ifndef NOXFER
+ if (pipesend || calibrate || sndarray) /* Only for real files */
+ return(-1);
+#endif /* NOXFER */
+ debug(F111,"scanfile",name,nscanfile);
+#ifdef PATTERNS
+ if (!filepeek) {
+ pv = matchname(name,1,-1);
+ if (pv < 0)
+ rc = -1;
+ else
+ rc = (pv == 1) ? FT_BIN : FT_TEXT;
+ debug(F111,"scanfile !filepeek result",name,rc);
+ return(rc);
+ }
+#endif /* PATTERNS */
+
+#ifdef VMS
+/* We don't scan in VMS where text files have various record formats in */
+/* which record headers contain seemingly non-text bytes. So the best */
+/* we can do in VMS is tell whether the file is text or binary, period. */
+ {
+ int b, x;
+ b = binary; /* Save current binary setting */
+ if (zopeni(ZIFILE,name) > 0) { /* In VMS this sets binary */
+ x = binary; /* Get result */
+ zclose(ZIFILE); /* Close the file */
+ binary = b; /* Restore previous binary setting */
+ rc = x ? FT_BIN : FT_TEXT;
+ val = 0;
+ goto xscanfile;
+ }
+ }
+#endif /* VMS */
+
+ eof = 0; /* End-of-file reached indicator */
+#ifdef OS2
+ fp = fopen(name, "rb"); /* Open the file in binary mode */
+#else
+ fp = fopen(name, "r");
+#endif /* OS2 */
+
+ if (!fp) /* Failed? */
+ return(-1);
+
+ while (1) { /* One or more gulps from file */
+ if (eof) { /* EOF from last time? */
+ debug(F111,"scanfile at EOF",name,bytes);
+ if (runzero > runmax)
+ runmax = runzero;
+ break;
+ }
+ if (nscanfile < 0) { /* Reading whole file */
+ readsize = SCANFILEBUF;
+ } else { /* Reading first nscanfilee bytes */
+ readsize = nscanfile - bytes;
+ if (readsize < 1)
+ break;
+ if (readsize > SCANFILEBUF)
+ readsize = SCANFILEBUF;
+ }
+ debug(F101,"scanfile readsize","",readsize);
+ count = fread(buf,1,readsize,fp); /* Read a buffer */
+ if (count == EOF || count == 0) {
+ debug(F111,"scanfile EOF",name,count);
+ break;
+ }
+ debug(F111,"scanfile buffer ok",name,count);
+
+ if (bytes == 0 && count > 8) {
+ /* PDF files can look like text in the beginning. */
+ if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) {
+ if (isdigit(buf[7])) {
+ if (buf[8] == '\015' ||
+ count > 9 && buf[8] == SP && buf[9] == '\015') {
+#ifdef DEBUG
+ buf[8] = NUL;
+ debug(F110,"scanfile PDF",buf,0);
+#endif /* DEBUG */
+ binary = 1; /* But they are binary. */
+ break;
+ }
+ }
+ } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) {
+ /* Ditto for PostScript */
+#ifdef DEBUG
+ int i;
+ for (i = 8; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PostScript",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+#ifndef NOPCLSCAN
+ } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) {
+ /* HP PCL printer language */
+#ifdef DEBUG
+ int i;
+ for (i = 8; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PCL",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+ }
+#endif /* NOPCLSCAN */
+#ifndef NOPJLSCAN
+ else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) {
+ /* Ditto for PJL Job printer header */
+#ifdef DEBUG
+ int i;
+ for (i = 2; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PJL Job printer header",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+#endif /* NOPJLSCAN */
+ }
+ }
+
+#ifdef UNICODE
+ if (bytes == 0 && count > 1) {
+ int incl_cnt = 0;
+
+ /* First look for BOM */
+
+ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
+ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
+
+ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
+ rc = FT_UCS2;
+ val = 0;
+ debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
+ rc = FT_UCS2;
+ val = 1;
+ debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
+ (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
+ rc = FT_UTF8;
+ debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc);
+ incl_cnt++;
+ }
+ if (incl_cnt) { /* Have BOM */
+ bytes += count;
+ goto xscanfile;
+ }
+ }
+#endif /* UNICODE */
+
+ bytes += count; /* Count bytes read */
+ eof = feof(fp); /* Flag for at EOF */
+
+ for (i = 0; i < count; i++) { /* For each byte... */
+ c = (unsigned)buf[i]; /* For ease of reference */
+ if (!c) { /* Zero byte? */
+#ifdef EVENMAX
+ if (i&1) /* In odd position */
+ oddzero++;
+ else
+ evenzero++; /* In even position */
+#endif /* EVENMAX */
+ runzero++;
+ } else { /* Not a zero byte */
+ if (runzero > runmax)
+ runmax = runzero;
+ if (runmax > 2) /* That's all we need to be certain */
+ break; /* it's a binary file. */
+ runzero = 0;
+ }
+
+#ifdef COMMENT
+#ifdef EVENMAX
+
+/* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire */
+
+ if (i > 1) { /* Look for runs of alternating chars */
+ if (i&1) {
+ if (c == buf[i-2]) { /* In odd positions */
+ oddrun++;
+ oddbyte = c;
+ } else {
+ oddmax = oddrun;
+ oddmaxbyte = oddbyte;
+ }
+ } else { /* and even positions */
+ if (c == buf[i-2]) {
+ evenrun++;
+ evenbyte = c;
+ } else {
+ evenmax = evenrun;
+ evenmaxbyte = evenbyte;
+ }
+ }
+ }
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+ if ((c & 0x80) == 0) { /* We have a 7-bit byte */
+#ifdef UNICODE
+ if (i > 0 && c == 10) { /* Linefeed */
+ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
+ else if (buf[i-1] == 13) crlf++; /* or by CR... */
+ }
+#endif /* UNICODE */
+ if (c < ' ') { /* Check for CO controls */
+ if (c != LF && c != CR && c != HT && c != FF) {
+ c0controls++;
+ if (c != ESC && c != SO && c != SI)
+ c0noniso++;
+ }
+ if ((c == '\032') /* Ctrl-Z */
+#ifdef COMMENT
+ && eof && (i >= count - 2)
+#endif /* COMMENT */
+ ) {
+ c0controls--;
+ c0noniso--;
+#ifdef CK_CTRLZ
+ if (eofmethod == XYEOF_Z && txtcz == 0) {
+ if (c0controls == 0) /* All text prior to Ctrl-Z */
+ txtcz = 1;
+ }
+#endif /* CK_CTRLZ */
+ }
+ }
+#ifdef UNICODE
+ if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
+ utf8state = 0;
+ debug(F000,"scanfile","7-bit byte in UTF8 sequence",c);
+ notutf8++; /* Then it's not UTF-8 */
+ continue;
+ }
+#endif /* UNICODE */
+ } else { /* We have an 8-bit byte */
+ eightbit++; /* Count it */
+ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
+ c1controls++;
+#ifdef UNICODE
+ if (!notutf8) { /* If it might still be UTF8... */
+ switch (utf8state) { /* Enter the UTF-8 state machine */
+ case 0: /* First byte... */
+ if ((c & 0xE0) == 0xC0) { /* Tells number of */
+ utf8state = 1; /* subsequent bytes */
+ } else if ((c & 0xF0) == 0xE0) {
+ utf8state = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ utf8state = 3;
+ } else {
+ notutf8++;
+ }
+ break;
+ case 1: /* Subsequent byte */
+ case 2:
+ case 3:
+ if ((c & 0xC0) != 0x80) { /* Must start with 10 */
+ debug(F000,"scanfile",
+ "bad byte in UTF8 sequence",c);
+ notutf8++;
+ break;
+ }
+ utf8state--; /* Good, one less in this sequence */
+ break;
+ default: /* Shouldn't happen */
+ debug(F111,"scanfile","bad UTF8 state",utf8state);
+ notutf8++;
+ }
+ }
+#endif /* UNICODE */
+ }
+ }
+ }
+ fclose(fp); /* Close the file */
+ debug(F101,"scanfile bytes","",bytes);
+
+ if (bytes == 0) /* If nothing was read */
+ return(-1); /* we're done. */
+
+#ifdef EVENMAX
+ /* In case we had a run that never broke... */
+#ifdef COMMENT
+ if (oddmax == 0) {
+ oddmax = oddrun;
+ oddmaxbyte = oddbyte;
+ }
+ if (evenmax == 0) {
+ evenmax = evenrun;
+ evenmaxbyte = evenbyte;
+ }
+#endif /* COMMENT */
+ if (runmax == 0) {
+ runmax = runzero;
+ }
+#endif /* EVENMAX */
+
+#ifdef UNICODE
+ if (bytes > 100) /* Bytes is not 0 */
+ pctzero = (evenzero + oddzero) / (bytes / 100);
+ else
+ pctzero = ((evenzero + oddzero) * 100) / bytes;
+#endif /* UNICODE */
+
+#ifdef DEBUG
+ if (deblog) { /* If debugging, dump statistics */
+ debug(F101,"scanfile c0controls ","",c0controls);
+ debug(F101,"scanfile c0noniso ","",c0noniso);
+ debug(F101,"scanfile c1controls ","",c1controls);
+ debug(F101,"scanfile eightbit ","",eightbit);
+#ifdef UNICODE
+ debug(F101,"scanfile crlf ","",crlf);
+ debug(F101,"scanfile lfnul ","",lfnul);
+ debug(F101,"scanfile notutf8 ","",notutf8);
+ debug(F101,"scanfile evenzero ","",evenzero);
+ debug(F101,"scanfile oddzero ","",oddzero);
+ debug(F101,"scanfile even/odd ","",(evenzero / (oddzero + 1)));
+ debug(F101,"scanfile odd/even ","",(oddzero / (evenzero + 1)));
+ debug(F101,"scanfile pctzero ","",pctzero);
+#endif /* UNICODE */
+#ifdef COMMENT
+#ifdef EVENMAX
+ debug(F101,"scanfile oddmax ","",oddmax);
+ debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte);
+ debug(F101,"scanfile evenmax ","",evenmax);
+ debug(F101,"scanfile evenmaxbyte","",evenmaxbyte);
+#endif /* EVENMAX */
+#endif /* COMMENT */
+ debug(F101,"scanfile runmax ","",runmax);
+ }
+#endif /* DEBUG */
+
+#ifdef UNICODE
+ x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
+
+ if (runmax > 2) { /* File has run of more than 2 NULs */
+ debug(F100,"scanfile BIN runmax","",0);
+ rc = FT_BIN; /* so it can't be any kind of text. */
+ goto xscanfile;
+
+ } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
+ goto xscanfile; /* File starts with a BOM */
+
+ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
+ if (runmax > 0) { /* and runs of NULs */
+ debug(F100,"scanfile BIN (nnUTF8) runmax","",0);
+ rc = FT_BIN; /* UTF-8 doesn't have NULs */
+ } else { /* No NULs */
+ debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0);
+ rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
+ }
+ goto xscanfile;
+ }
+/*
+ For UCS-2 detection, see if the text contains lines delimited by
+ ASCII controls and containing spaces, ASCII digits, or other ASCII
+ characters, thus forcing the presence of a certain percentage of zero bytes.
+ For this purpose require 20% zero bytes, with at least six times as many
+ in even (odd) positions as in odd (even) positions.
+*/
+ if ((evenzero >= x && oddzero == 0) ||
+ ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) &&
+ (crlf == 0) &&
+ (lfnul > 1))
+ ) {
+ debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0);
+ rc = FT_UCS2;
+ val = 0;
+ } else if ((evenzero == 0 && oddzero >= x) ||
+ ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) &&
+ (crlf == 0) &&
+ (lfnul > 1))
+ ) {
+ debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0);
+ rc = FT_UCS2;
+ val = 1;
+
+#ifdef COMMENT
+#ifdef EVENMAX
+/*
+ If the tests above fail, we still might have UCS-2 if there are significant
+ runs of identical bytes in alternating positions, but only if it also has
+ unusual C0 controls (otherwise we'd pick up hex files here). NOTE: We
+ don't actually do this -- EVENMAX is not defined (see comments above at
+ first occurrence of EVENMAX).
+*/
+ } else if (c0noniso && evenmax > bytes / 4) {
+ debug(F100,"scanfile UCS2 BE (evenmax)","",0);
+ rc = FT_UCS2;
+ val = 0;
+ } else if (c0noniso && oddmax > bytes / 4) {
+ debug(F100,"scanfile UCS2 LE (evenmax)","",0);
+ rc = FT_UCS2;
+ val = 1;
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+ }
+/*
+ It seems to be UCS-2 but let's be more certain since there is no BOM...
+ If the number of 7- and 8-bit characters is approximately equal, it might
+ be a compressed file. In this case we decide based on the name.
+*/
+ if (rc == FT_UCS2) {
+ if (eightbit > 0) {
+ int j, k;
+ j = (c1controls * 100) / (c0controls + 1);
+ debug(F101,"scanfile c1/c0 ","",j);
+ k = (bytes * 100) / eightbit;
+ debug(F101,"scanfile pct 8bit ","",k);
+ if (k > 40 && k < 60 && j > 60) {
+ if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) {
+ debug(F110,"scanfile 8-bit BIN compressed",name,0);
+ rc = FT_BIN;
+ goto xscanfile;
+ }
+ }
+ }
+ /* Small file - not enough evidence unless ... */
+
+ if (bytes < 100) {
+ if (oddzero != 0 && evenzero != 0) {
+ debug(F100,"scanfile small UCS2 doubtful","",0);
+ rc = FT_BIN;
+ goto xscanfile;
+ } else if (oddzero == 0 && evenzero == 0) {
+ rc = eightbit ? FT_8BIT : FT_7BIT;
+ }
+ }
+ goto xscanfile; /* Seems to be UCS-2 */
+ }
+
+/* If none of the above, it's probably not Unicode. */
+
+ if (!eightbit) { /* It's 7-bit */
+ if (c0controls) { /* This would be strange */
+ if ((c0noniso > 0) && (txtcz == 0)) {
+ debug(F100,"scanfile 7-bit BIN (c0coniso)","",0);
+ rc = FT_BIN;
+ } else {
+ debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+ } else { /* 7-bit text */
+ debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0);
+ rc = FT_7BIT;
+ }
+ } else if (!c0noniso || txtcz) { /* 8-bit text */
+ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else { /* 8-bit binary */
+ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ }
+
+#else /* !UNICODE */
+
+ if (c0noniso) {
+ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ } else if (eightbit) {
+ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else {
+ debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+
+#endif /* UNICODE */
+
+ xscanfile:
+ if (flag) *flag = val;
+ debug(F101,"scanfile result ","",rc);
+ return(rc);
+}
+
+/*
+ scanstring - like scan file but for a string.
+ This is just a quick butchery of scanfile without thinking too much.
+*/
+int
+scanstring(s) char * s; {
+ int x, val = -1, count = 0; /* Workers */
+ int rc = -1; /* Return code */
+ int pv = -1; /* Pattern-match value */
+ int bytes = 0; /* Total byte count */
+#ifdef UNICODE
+ unsigned int c0, c1; /* First 2 file bytes (for BOM) */
+#endif /* UNICODE */
+ extern int pipesend, filepeek;
+
+ register int i; /* Loop control */
+ int readsize = 0; /* How much to read */
+ int eightbit = 0; /* Number of bytes with 8th bit on */
+ int c0controls = 0; /* C0 non-text control-char counter */
+ int c0noniso = 0; /* C0 non-ISO control-char counter */
+ int c1controls = 0; /* C1 control-character counter */
+ unsigned int c; /* Current character */
+ int runmax = 0; /* Longest run of 0 bytes */
+ int runzero = 0; /* Run of 0 bytes */
+ int pctzero = 0; /* Percentage of 0 bytes */
+ int txtcz = 0;
+
+#ifdef UNICODE
+ int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
+ int utf8state = 0; /* UTF-8 recognizer state */
+ int oddzero = 0; /* Number of 0 bytes in odd postions */
+ int evenzero = 0; /* and in even positions */
+ int lfnul = 0; /* Number of <LF><NUL> sequences */
+ int crlf = 0; /* Number of <CRLF> sequences */
+#else
+ int notutf8 = 1;
+#endif /* UNICODE */
+
+ char * buf = s;
+ if (!s) s = "";
+ count = strlen(s);
+
+#ifdef UNICODE
+ if (bytes == 0 && count > 1) {
+ int incl_cnt = 0;
+
+ /* First look for BOM */
+
+ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
+ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
+
+ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
+ rc = FT_UCS2;
+ val = 0;
+ debug(F111,"scanstring UCS2 BOM BE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
+ rc = FT_UCS2;
+ val = 1;
+ debug(F111,"scanstring UCS2 BOM LE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
+ (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
+ rc = FT_UTF8;
+ debug(F111,"scanstring UTF8 BOM",ckitoa(val),rc);
+ incl_cnt++;
+ }
+ if (incl_cnt) { /* Have BOM */
+ bytes += count;
+ goto xscanstring;
+ }
+ }
+#endif /* UNICODE */
+
+ bytes += count; /* Count bytes read */
+
+ for (i = 0; i < count; i++) { /* For each byte... */
+ c = (unsigned)buf[i]; /* For ease of reference */
+ if (!c) { /* Zero byte? */
+ goto xscanstring; /* Null terminated string */
+ }
+ if ((c & 0x80) == 0) { /* We have a 7-bit byte */
+#ifdef UNICODE
+ if (i > 0 && c == 10) { /* Linefeed */
+ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
+ else if (buf[i-1] == 13) crlf++; /* or by CR... */
+ }
+#endif /* UNICODE */
+ if (c < ' ') { /* Check for CO controls */
+ if (c != LF && c != CR && c != HT && c != FF) {
+ c0controls++;
+ if (c != ESC && c != SO && c != SI)
+ c0noniso++;
+ }
+ if ((c == '\032') /* Ctrl-Z */
+ ) {
+ c0controls--;
+ c0noniso--;
+ }
+ }
+#ifdef UNICODE
+ if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
+ utf8state = 0;
+ debug(F000,"scanstring","7-bit byte in UTF8 sequence",c);
+ notutf8++; /* Then it's not UTF-8 */
+ continue;
+ }
+#endif /* UNICODE */
+ } else { /* We have an 8-bit byte */
+ eightbit++; /* Count it */
+ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
+ c1controls++;
+#ifdef UNICODE
+ if (!notutf8) { /* If it might still be UTF8... */
+ switch (utf8state) { /* Enter the UTF-8 state machine */
+ case 0: /* First byte... */
+ if ((c & 0xE0) == 0xC0) { /* Tells number of */
+ utf8state = 1; /* subsequent bytes */
+ } else if ((c & 0xF0) == 0xE0) {
+ utf8state = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ utf8state = 3;
+ } else {
+ notutf8++;
+ }
+ break;
+ case 1: /* Subsequent byte */
+ case 2:
+ case 3:
+ if ((c & 0xC0) != 0x80) { /* Must start with 10 */
+ debug(F000,"scanstring",
+ "bad byte in UTF8 sequence",c);
+ notutf8++;
+ break;
+ }
+ utf8state--; /* Good, one less in this sequence */
+ break;
+ default: /* Shouldn't happen */
+ debug(F111,"scanstring","bad UTF8 state",utf8state);
+ notutf8++;
+ }
+ }
+#endif /* UNICODE */
+ }
+ }
+ if (bytes == 0) /* If nothing was read */
+ return(-1); /* we're done. */
+
+#ifdef UNICODE
+ if (bytes > 100) /* Bytes is not 0 */
+ pctzero = (evenzero + oddzero) / (bytes / 100);
+ else
+ pctzero = ((evenzero + oddzero) * 100) / bytes;
+#endif /* UNICODE */
+
+#ifdef UNICODE
+ x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
+
+ if (runmax > 2) { /* File has run of more than 2 NULs */
+ debug(F100,"scanstring BIN runmax","",0);
+ rc = FT_BIN; /* so it can't be any kind of text. */
+ goto xscanstring;
+
+ } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
+ goto xscanstring; /* File starts with a BOM */
+
+ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
+ if (runmax > 0) { /* and runs of NULs */
+ debug(F100,"scanstring BIN (nnUTF8) runmax","",0);
+ rc = FT_BIN; /* UTF-8 doesn't have NULs */
+ } else { /* No NULs */
+ debug(F100,"scanstring UTF8 (nnUTF8 + runmax == 0)","",0);
+ rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
+ }
+ goto xscanstring;
+ }
+/*
+ It seems to be UCS-2 but let's be more certain since there is no BOM...
+ If the number of 7- and 8-bit characters is approximately equal, it might
+ be a compressed file. In this case we decide based on the name.
+*/
+ if (rc == FT_UCS2) {
+ if (bytes < 100) {
+ if (oddzero != 0 && evenzero != 0) {
+ debug(F100,"scanstring small UCS2 doubtful","",0);
+ rc = FT_BIN;
+ goto xscanstring;
+ } else if (oddzero == 0 && evenzero == 0) {
+ rc = eightbit ? FT_8BIT : FT_7BIT;
+ }
+ }
+ goto xscanstring; /* Seems to be UCS-2 */
+ }
+
+/* If none of the above, it's probably not Unicode. */
+
+ if (!eightbit) { /* It's 7-bit */
+ if (c0controls) { /* This would be strange */
+ if ((c0noniso > 0) && (txtcz == 0)) {
+ debug(F100,"scanstring 7-bit BIN (c0coniso)","",0);
+ rc = FT_BIN;
+ } else {
+ debug(F100,"scanstring 7-bit ISO2022 TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+ } else { /* 7-bit text */
+ debug(F100,"scanstring 7-bit TEXT (no c0controls)","",0);
+ rc = FT_7BIT;
+ }
+ } else if (!c0noniso || txtcz) { /* 8-bit text */
+ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else { /* 8-bit binary */
+ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ }
+
+#else /* !UNICODE */
+
+ if (c0noniso) {
+ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ } else if (eightbit) {
+ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else {
+ debug(F100,"scanstring 7-bit TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+
+#endif /* UNICODE */
+
+ xscanstring:
+ debug(F101,"scanstring result ","",rc);
+ return(rc);
+}
+
+
+
+/* F I L E S E L E C T -- Select this file for sending */
+
+int
+#ifdef CK_ANSIC
+fileselect(
+ char *f, char *sa, char *sb, char *sna, char *snb,
+ CK_OFF_T minsiz, CK_OFF_T maxsiz,
+ int nbu, int nxlist,
+ char ** xlist
+)
+#else
+fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
+ char *f,*sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
+ int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+/* fileselect */ {
+ char *fdate;
+ int n;
+ CK_OFF_T z;
+
+ debug(F111,"fileselect minsiz",ckfstoa(minsiz),minsiz);
+ debug(F111,"fileselect maxsiz",ckfstoa(maxsiz),maxsiz);
+ debug(F111,"fileselect (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
+
+ if (!sa) sa = "";
+ if (!sb) sb = "";
+ if (!sna) sna = "";
+ if (!snb) snb = "";
+
+#ifdef CKSYMLINK
+#ifndef NOICP
+#ifndef NOXFER
+ if (nolinks) {
+ CK_OFF_T zz;
+ zz = zgetfs(f);
+ debug(F111,"fileselect NOLINKS zgetfs",f,zz);
+ if (zz < (CK_OFF_T)0)
+ return(0);
+ debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link);
+ if (zgfs_link)
+ return(0);
+ }
+#endif /* NOXFER */
+#endif /* NOICP */
+#endif /* CKSYMLINK */
+
+ debug(F110,"fileselect",f,0);
+ if (*sa || *sb || *sna || *snb) {
+ fdate = zfcdat(f); /* Date/time of this file */
+ if (!fdate) fdate = "";
+ n = strlen(fdate);
+ debug(F111,"fileselect fdate",fdate,n);
+ if (n != 17) /* Failed to get it */
+ return(1);
+ /* /AFTER: */
+ if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) {
+ debug(F110,"fileselect sa",sa,0);
+ /* tlog(F110,"Skipping (too old)",f,0); */
+ return(0);
+ }
+ /* /BEFORE: */
+ if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) {
+ debug(F110,"fileselect sb",sb,0);
+ /* tlog(F110,"Skipping (too new)",f,0); */
+ return(0);
+ }
+ /* /NOT-AFTER: */
+ if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) {
+ debug(F110,"fileselect sna",sna,0);
+ /* tlog(F110,"Skipping (too new)",f,0); */
+ return(0);
+ }
+ /* /NOT-BEFORE: */
+ if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) {
+ debug(F110,"fileselect snb",snb,0);
+ /* tlog(F110,"Skipping (too old)",f,0); */
+ return(0);
+ }
+ }
+ /* Smaller or larger */
+ if (minsiz > (CK_OFF_T)-1 || maxsiz > (CK_OFF_T)-1) {
+ z = zchki(f); /* Get size */
+ debug(F101,"fileselect filesize","",z);
+ if (z < (CK_OFF_T)0)
+ return(1);
+ if ((minsiz > (CK_OFF_T)-1) && (z >= minsiz)) {
+ debug(F111,"fileselect minsiz skipping",f,minsiz);
+ /* tlog(F111,"Skipping (too big)",f,z); */
+ return(0);
+ }
+ if ((maxsiz > (CK_OFF_T)-1) && (z <= maxsiz)) {
+ debug(F111,"fileselect maxsiz skipping",f,maxsiz);
+ /* tlog(F110,"Skipping (too small)",f,0); */
+ return(0);
+ }
+ }
+ if (nbu) { /* Skipping backup files? */
+ if (ckmatch(
+#ifdef CKREGEX
+ "*.~[0-9]*~" /* Not perfect but close enough. */
+#else
+ "*.~*~" /* Less close. */
+#endif /* CKREGEX */
+ ,f,filecase,1)) {
+ debug(F110,"fileselect skipping backup",f,0);
+ return(0);
+ }
+ }
+ for (n = 0; xlist && n < nxlist; n++) {
+ if (!xlist[n]) {
+ debug(F101,"fileselect xlist empty",0,n);
+ break;
+ }
+ if (ckmatch(xlist[n],f,filecase,1)) {
+ debug(F111,"fileselect xlist",xlist[n],n);
+ debug(F110,"fileselect skipping",f,0);
+ return(0);
+ }
+ }
+ if (xfiletype > -1) {
+ n = scanfile(f,NULL,nscanfile);
+ if (n < 0) {
+ n = binary ? 1 : 0;
+ } else {
+ n = (n == FT_BIN) ? 1 : 0;
+ }
+ if (n != xfiletype)
+ return(0);
+ }
+ debug(F110,"fileselect selecting",f,0);
+ return(1);
+}
+
+
+#ifdef TCPSOCKET
+#ifdef NT
+extern int WSASafeToCancel;
+#endif /* NT */
+#endif /* TCPSOCKET */
+
+VOID
+setflow() {
+ extern int flow, autoflow, mdmtyp, cxtype, cxflow[];
+#ifndef NODIAL
+ extern int dialcapas, dialfc;
+ extern MDMINF * modemp[];
+ MDMINF * p = NULL;
+ long bits = 0;
+#endif /* NODIAL */
+
+ debug(F101,"setflow autoflow","",autoflow);
+
+/* #ifdef COMMENT */
+/* WHY WAS THIS COMMENTED OUT? */
+ if (!autoflow) /* Only if FLOW is AUTO */
+ return;
+/* #endif */ /* COMMENT */
+
+ debug(F101,"setflow local","",local);
+ debug(F101,"setflow network","",network);
+ debug(F101,"setflow cxtype","",cxtype);
+
+#ifdef TN_COMPORT
+ if (network && istncomport()) {
+ flow = cxflow[CXT_MODEM];
+ debug(F101,"setflow TN_COMPORT flow","",flow);
+ return;
+ }
+#endif /* TN_COMPORT */
+
+ if (network || !local || cxtype == CXT_DIRECT) {
+ flow = cxflow[cxtype]; /* Set appropriate flow control */
+ debug(F101,"setflow flow","",flow);
+ return;
+ }
+ if (cxtype != CXT_MODEM) /* Connection type should be modem */
+ return;
+
+#ifndef NODIAL
+ bits = dialcapas; /* Capability bits */
+ if (!bits) { /* No bits? */
+ p = modemp[mdmtyp]; /* Look in modem info structure */
+ if (p)
+ bits = p->capas;
+ }
+ if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */
+#ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */
+ if (bits & CKD_HW) /* and modem can do it too */
+ flow = FLO_RTSC; /* then switch to RTS/CTS */
+ else /* otherwise */
+ flow = FLO_XONX; /* use Xon/Xoff. */
+#else
+#ifndef NEXT
+#ifndef IRIX
+ flow = FLO_XONX; /* Use Xon/Xoff. */
+#endif /* IRIX */
+#endif /* NEXT */
+#endif /* CK_RTSCTS */
+ }
+#endif /* NODIAL */
+ debug(F101,"setflow modem flow","",flow);
+ return;
+}
+
+#ifndef NOLOCAL
+#ifdef CK_TRIGGER
+
+/* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */
+/*
+ Returns -1 if trigger not found, or else the trigger index, 0 or greater.
+ (Replace with fancier and more efficient matcher later...)
+ NOTE: to prevent unnecessary function call overhead, call this way:
+
+ x = tt_trigger[0] ? autoexitchk(c) : -1;
+
+*/
+int
+#ifdef CK_ANSIC
+autoexitchk(CHAR c)
+#else
+autoexitchk(c) CHAR c;
+#endif /* CK_ANSIC */
+/* autoexitchk */ {
+ extern CHAR * tt_trmatch[];
+ extern char * tt_trigger[];
+ int i;
+ for (i = 0; i < TRIGGERS; i++) {
+ if (!tt_trigger[i]) { /* No more triggers in list */
+ break;
+ } else if (*tt_trigger[i]) {
+ if (!tt_trmatch[i]) /* Just starting? */
+ tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
+ if (c == *tt_trmatch[i]) { /* Compare this character */
+ tt_trmatch[i]++; /* It matches */
+ if (!*tt_trmatch[i]) { /* End of match string? */
+ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
+ debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
+ return(i); /* and return success */
+ }
+ } else /* No match */
+ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
+ } /* and go on the next match string */
+ }
+ return(-1); /* No match found */
+}
+#endif /* CK_TRIGGER */
+
+#ifndef NOSHOW
+/* S H O M D M -- Show modem signals */
+
+VOID
+shomdm() {
+/*
+ Note use of "\r\n" to make sure this report prints right, even when
+ called during CONNECT mode.
+*/
+ int y;
+ y = ttgmdm();
+ switch (y) {
+ case -3: printf(
+ "Modem signals unavailable in this version of Kermit\r\n");
+ break;
+ case -2: printf("No modem control for this device\r\n"); break;
+ case -1: printf("Modem signals unavailable\r\n"); break;
+ default:
+#ifndef MAC
+ printf(
+ " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off");
+ printf(
+ " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
+#endif /* MAC */
+ printf(
+ " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
+#ifndef STRATUS
+#ifndef MAC
+ printf(
+ " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off");
+#endif /* MAC */
+ printf(
+ " Data Terminal Ready (DTR): %s\r\n",
+#ifdef NT
+ "(unknown)"
+#else /* NT */
+ (y & BM_DTR) ? "On": "Off"
+#endif /* NT */
+ );
+#ifndef MAC
+ printf(
+ " Request To Send (RTS): %s\r\n",
+#ifdef NT
+ "(unknown)"
+#else /* NT */
+ (y & BM_RTS) ? "On": "Off"
+#endif /* NT */
+ );
+#endif /* MAC */
+#endif /* STRATUS */
+ }
+#ifdef BETADEBUG
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) {
+ LPDEVCFG lpDevCfg = NULL;
+ LPCOMMCONFIG lpCommConfig = NULL;
+ LPMODEMSETTINGS lpModemSettings = NULL;
+ DCB * lpDCB = NULL;
+
+ if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
+ &lpCommConfig,&lpDCB)) {
+ printf("\n");
+ cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
+ lpCommConfig,lpDCB);
+ }
+ }
+#endif /* CK_TAPI */
+#endif /* BETADEBUG */
+}
+#endif /* NOSHOW */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+/* S D E B U -- Record spar results in debugging log */
+
+VOID
+sdebu(len) int len; {
+ debug(F111,"spar: data",(char *) rdatap,len);
+ debug(F101," spsiz ","", spsiz);
+ debug(F101," timint","",timint);
+ debug(F101," npad ","", npad);
+ debug(F101," padch ","", padch);
+ debug(F101," seol ","", seol);
+ debug(F101," ctlq ","", ctlq);
+ debug(F101," ebq ","", ebq);
+ debug(F101," ebqflg","",ebqflg);
+ debug(F101," bctr ","", bctr);
+ debug(F101," rptq ","", rptq);
+ debug(F101," rptflg","",rptflg);
+ debug(F101," lscapu","",lscapu);
+ debug(F101," atcapu","",atcapu);
+ debug(F101," lpcapu","",lpcapu);
+ debug(F101," swcapu","",swcapu);
+ debug(F101," wslotn","", wslotn);
+ debug(F101," whatru","", whatru);
+}
+/* R D E B U -- Debugging display of rpar() values */
+
+VOID
+rdebu(d,len) CHAR *d; int len; {
+ debug(F111,"rpar: data",d,len);
+ debug(F101," rpsiz ","", xunchar(d[0]));
+ debug(F101," rtimo ","", rtimo);
+ debug(F101," mypadn","",mypadn);
+ debug(F101," mypadc","",mypadc);
+ debug(F101," eol ","", eol);
+ debug(F101," ctlq ","", ctlq);
+ debug(F101," sq ","", sq);
+ debug(F101," ebq ","", ebq);
+ debug(F101," ebqflg","",ebqflg);
+ debug(F101," bctr ","", bctr);
+ debug(F101," rptq ","", d[8]);
+ debug(F101," rptflg","",rptflg);
+ debug(F101," capas ","", capas);
+ debug(F101," bits ","",d[capas]);
+ debug(F101," lscapu","",lscapu);
+ debug(F101," atcapu","",atcapu);
+ debug(F101," lpcapu","",lpcapu);
+ debug(F101," swcapu","",swcapu);
+ debug(F101," wslotr","", wslotr);
+ debug(F101," rpsiz(extended)","",rpsiz);
+}
+
+#ifdef COMMENT
+/* C H K E R R -- Decide whether to exit upon a protocol error */
+
+VOID
+chkerr() {
+ if (backgrd && !server) fatal("Protocol error");
+}
+#endif /* COMMENT */
+#endif /* NOXFER */
+
+/* F A T A L -- Fatal error message */
+
+VOID
+fatal(msg) char *msg; {
+ extern int initflg;
+ static int initing = 0;
+ if (!msg) msg = "";
+ debug(F111,"fatal",msg,initflg);
+
+ if (!initflg) { /* If called from prescan */
+ if (initing) /* or called from sysinit() */
+ exit(253);
+ initing = 1;
+ sysinit();
+ }
+
+ debug(F111,"fatal",msg,xitsta);
+ tlog(F110,"Fatal:",msg,0L);
+#ifdef VMS
+ if (strncmp(msg,"%CKERMIT",8))
+ conol("%CKERMIT-E-FATAL, ");
+ conoll(msg);
+#else /* !VMS */
+ conoll(msg);
+#endif /* VMS */
+#ifdef OS2
+#ifndef NOXFER
+ if (xfrbel) {
+ bleep(BP_FAIL);
+ sleep(1);
+ bleep(BP_FAIL);
+ }
+#endif /* NOXFER */
+
+#endif /* OS2 */
+ doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */
+}
+
+#ifndef NOXFER
+/* B L D L E N -- Make length-encoded copy of string */
+
+char *
+bldlen(str,dest) char *str, *dest; {
+ int len;
+ len = (int)strlen(str);
+ if (len > 94)
+ *dest = SP;
+ else
+ *dest = (char) tochar(len);
+ strcpy(dest+1,str); /* Checked below in setgen() */
+ return(dest+len+1);
+}
+
+
+/* S E T G E N -- Construct a generic command */
+/*
+ Call with Generic command character followed by three string arguments.
+ Trailing strings are allowed to be empty (""). Each string except the last
+ non-empty string must be less than 95 characters long. The final nonempty
+ string is allowed to be longer.
+*/
+CHAR
+#ifdef CK_ANSIC
+setgen(char type, char * arg1, char * arg2, char * arg3)
+#else
+setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
+#endif /* CK_ANSIC */
+/* setgen */ {
+ char *upstr, *cp;
+#ifdef DYNAMIC
+ if (!cmdstr)
+ if (!(cmdstr = malloc(MAXSP + 1)))
+ fatal("setgen: can't allocate memory");
+#endif /* DYNAMIC */
+
+ cp = cmdstr;
+ *cp++ = type;
+ *cp = NUL;
+ if (!arg1) arg1 = "";
+ if (!arg2) arg2 = "";
+ if (!arg3) arg3 = "";
+ if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
+ if (*arg1 != NUL) {
+ upstr = bldlen(arg1,cp);
+ if (*arg2 != NUL) {
+ upstr = bldlen(arg2,upstr);
+ if (*arg3 != NUL) bldlen(arg3,upstr);
+ }
+ }
+ cmarg = cmdstr;
+ debug(F110,"setgen",cmarg,0);
+ return('g');
+ }
+ return('E');
+}
+#endif /* NOXFER */
+
+#ifndef NOMSEND
+static char *mgbufp = NULL;
+
+/* F N P A R S E -- */
+
+/*
+ Argument is a character string containing one or more filespecs.
+ This function breaks the string apart into an array of pointers, one
+ to each filespec, and returns the number of filespecs. Used by server
+ when it receives a GET command to allow it to process multiple file
+ specifications in one transaction. Sets cmlist to point to a list of
+ file pointers, exactly as if they were command line arguments.
+
+ This version of fnparse treats spaces as filename separators. If your
+ operating system allows spaces in filenames, you'll need a different
+ separator.
+
+ This version of fnparse mallocs a string buffer to contain the names. It
+ cannot assume that the string that is pointed to by the argument is safe.
+*/
+int
+fnparse(string) char *string; {
+ char *p, *s, *q;
+ int r = 0, x; /* Return code */
+#ifdef RECURSIVE
+ debug(F111,"fnparse",string,recursive);
+#endif /* RECURSIVE */
+
+ if (mgbufp) free(mgbufp); /* Free this from last time. */
+ mgbufp = malloc((int)strlen(string)+2);
+ if (!mgbufp) {
+ debug(F100,"fnparse malloc error","",0);
+ return(0);
+ }
+#ifndef NOICP
+#ifndef NOSPL
+ ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */
+#endif /* NOSPL */
+#endif /* NOICP */
+ s = string; /* Input string */
+ p = q = mgbufp; /* Point to the copy */
+ r = 0; /* Initialize our return code */
+ while (*s == SP || *s == HT) /* Skip leading spaces and tabs */
+ s++;
+ for (x = strlen(s); /* Strip trailing spaces */
+ (x > 1) && (s[x-1] == SP || s[x-1] == HT);
+ x--)
+ s[x-1] = NUL;
+ while (1) { /* Loop through rest of string */
+ if (*s == CMDQ) { /* Backslash (quote character)? */
+ if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
+ *q++ = (char) x; /* Numeric backslash code, ok */
+ } else { /* Just let it quote next char */
+ s++; /* get past the backslash */
+ *q++ = *s++; /* deposit next char */
+ }
+ continue;
+ } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
+ *q++ = NUL; /* End of output filename. */
+ msfiles[r] = p; /* Add this filename to the list */
+ debug(F111,"fnparse",msfiles[r],r);
+ r++; /* Count it */
+ if (*s == NUL) break; /* End of string? */
+ while (*s == SP) s++; /* Skip repeated spaces */
+ p = q; /* Start of next name */
+ continue;
+ } else *q++ = *s; /* Otherwise copy the character */
+ s++; /* Next input character */
+ }
+ debug(F101,"fnparse r","",r);
+ msfiles[r] = ""; /* Put empty string at end of list */
+ cmlist = msfiles;
+ return(r);
+}
+#endif /* NOMSEND */
+
+char * /* dbchr() for DEBUG SESSION */
+dbchr(c) int c; {
+ static char s[8];
+ char *cp = s;
+
+ c &= 0xff;
+ if (c & 0x80) { /* 8th bit on */
+ *cp++ = '~';
+ c &= 0x7f;
+ }
+ if (c < SP) { /* Control character */
+ *cp++ = '^';
+ *cp++ = (char) ctl(c);
+ } else if (c == DEL) {
+ *cp++ = '^';
+ *cp++ = '?';
+ } else { /* Printing character */
+ *cp++ = (char) c;
+ }
+ *cp = '\0'; /* Terminate string */
+ cp = s; /* Return pointer to it */
+ return(cp);
+}
+
+/* C K H O S T -- Get name of local host (where C-Kermit is running) */
+
+/*
+ Call with pointer to buffer to put hostname in, and length of buffer.
+ Copies hostname into buffer on success, puts null string in buffer on
+ failure.
+*/
+#ifdef BSD44
+#define BSD4
+#undef ATTSV
+#endif /* BSD44 */
+
+#ifdef SVORPOSIX
+#ifndef BSD44
+#ifndef apollo
+#include <sys/utsname.h>
+#endif /* apollo */
+#endif /* BSD44 */
+#else
+#ifdef BELLV10
+#include <utsname.h>
+#endif /* BELLV10 */
+#endif /* SVORPOSIX*/
+
+#ifdef CKSYSLOG
+extern char uidbuf[], * clienthost;
+#endif /* CKSYSLOG */
+
+VOID
+ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
+
+#ifndef NOPUSH
+ extern int nopush;
+#ifndef NOSERVER
+ extern int en_hos;
+#endif /* NOSERVER */
+#endif /* NOPUSH */
+
+#ifdef pdp11
+ *vvbuf = NUL;
+#else /* Everything else - rest of this routine */
+
+ char *g;
+ int havefull = 0;
+#ifdef VMS
+ int x;
+#endif /* VMS */
+
+#ifdef SVORPOSIX
+#ifndef BSD44
+#ifndef _386BSD
+#ifndef APOLLOSR10
+ struct utsname hname;
+#endif /* APOLLOSR10 */
+#endif /* _386BSD */
+#endif /* BSD44 */
+#endif /* SVORPOSIX */
+#ifdef datageneral
+ int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
+#endif /* datageneral */
+
+#ifndef NOPUSH
+ if (getenv("CK_NOPUSH")) { /* No shell access allowed */
+ nopush = 1; /* on this host... */
+#ifndef NOSERVER
+ en_hos = 0;
+#endif /* NOSERVER */
+ }
+#endif /* NOPUSH */
+
+ *vvbuf = NUL; /* How let's get our host name ... */
+
+#ifndef BELLV10 /* Does not have gethostname() */
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifdef APOLLOSR10
+ ckstrncpy(vvbuf,"Apollo",vvlen);
+#else
+#ifdef BSD44
+ if (gethostname(vvbuf,vvlen) < 0)
+ *vvbuf = NUL;
+#else
+#ifdef _386BSD
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else
+#ifdef QNX
+#ifdef TCPSOCKET
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else
+ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
+#endif /* TCPSOCKET */
+#else /* SVORPOSIX but not _386BSD or BSD44 */
+#ifdef __ia64__
+ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
+#else
+ if (uname(&hname) > -1) {
+ char * p;
+ p = hname.nodename;
+#ifdef TCPSOCKET
+#ifndef NOCKGETFQHOST
+ if (!ckstrchr(p,'.'))
+ p = (char *)ckgetfqhostname(p);
+#endif /* NOCKGETFQHOST */
+#endif /* TCPSOCKET */
+ if (!p) p = "";
+ if (!*p) p = "(unknown)";
+ ckstrncpy(vvbuf,p,vvlen);
+ }
+#endif /* __ia64__ */
+#endif /* QNX */
+#endif /* _386BSD */
+#endif /* BSD44 */
+#endif /* APOLLOSR10 */
+#else /* !SVORPOSIX */
+#ifdef BSD4
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else /* !BSD4 */
+#ifdef VMS
+ g = getenv("SYS$NODE");
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+ x = (int)strlen(vvbuf);
+ if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
+#else
+#ifdef datageneral
+ if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
+ vvlen = ac2 + 1; /* enh - have to add one */
+#else
+#ifdef OS2 /* OS/2 */
+ g = os2_gethostname();
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+#else /* OS2 */
+#ifdef OSK
+#ifdef TCPSOCKET
+ if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
+#endif /* TCPSOCKET */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* BSD4 */
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ /* If TCP/IP is not installed, gethostname() fails, use uname() */
+ if (gethostname(vvbuf,vvlen) < 0) {
+ if (uname(&hname) > -1)
+ ckstrncpy(vvbuf,hname.nodename,vvlen);
+ else
+ *vvbuf = NUL;
+ }
+#endif /* OXOS */
+#endif /* BELLV10 */
+ if (*vvbuf == NUL) { /* If it's still empty */
+ g = getenv("HOST"); /* try this */
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+ }
+ vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */
+#endif /* pdp11 */
+}
+#ifdef BSD44
+#undef BSD4
+#define ATTSV
+#endif /* BSD44 */
+
+/*
+ A S K M O R E -- Poor person's "more".
+ Returns 0 if no more, 1 if more wanted.
+*/
+int
+askmore() {
+ char c;
+ int rv, cx;
+#ifdef IKSD
+ extern int timelimit;
+#endif /* IKSD */
+#ifdef IKSDCONF
+ extern int iksdcf;
+#endif /* IKSDCONF */
+#ifdef CK_APC
+ extern int apcstatus, apcactive;
+#endif /* CK_APC */
+
+#ifdef NOICP
+ return(1);
+#else
+ if (!xaskmore)
+ return(1);
+#ifdef IKSDCONF
+ if (inserver && !iksdcf)
+ return(1);
+#endif /* IKSDCONF */
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
+ return(1);
+#endif /* CK_APC */
+#ifdef VMS
+ if (batch)
+ return(1);
+#else
+#ifdef UNIX
+ if (backgrd)
+ return(1);
+#endif /* UNIX */
+#endif /* VMS */
+
+#ifndef VMS
+ concb((char)escape); /* Force CBREAK mode. */
+#endif /* VMS */
+
+ rv = -1;
+ while (rv < 0) {
+#ifndef OS2
+ printf("more? ");
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+#else
+ printf("more? ");
+ fflush(stdout);
+#endif /* OS2 */
+
+#ifdef IKSD
+ if (inserver) {
+ cx = cmdgetc(timelimit);
+ if (cx < -1 && timelimit) {
+ printf("\n?IKS idle timeout - Goodbye.\n");
+ doexit(GOOD_EXIT,0);
+ } else if (cx == -1) { /* Connection lost */
+ doexit(BAD_EXIT,0);
+ }
+ c = (char) cx;
+ } else {
+#endif /* IKSD */
+#ifdef VMS
+ conbin((char)escape); /* Protect against Ctrl-Z */
+ cx = coninc(0);
+ concb((char)escape);
+#else
+ cx = cmdgetc(0);
+#endif /* VMS */
+ debug(F101,"askmore cmdgetc","",cx);
+ if (cx == EOF) {
+ debug(F100,"askmore EOF","",0);
+#ifdef VMS
+ c = '\032';
+#else
+ c = 'n';
+#endif /* VMS */
+ } else {
+ c = (char)cx;
+ }
+ debug(F101,"askmore c","",c);
+
+#ifdef IKSD
+ }
+#endif /* IKSD */
+ switch (c) {
+ /* Yes */
+ case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
+ xaskmore = 0;
+ /* fall thru on purpose */
+
+ case SP: case 'y': case 'Y': case 012: case 015:
+#ifdef OSK
+ write(1, "\015 \015", sizeof "\015 \015" - 1);
+#else
+ printf("\015 \015");
+#endif /* OSK */
+ rv = 1;
+ break;
+ /* No */
+ case 'n': case 'N': case 'q': case 'Q':
+#ifdef OSK
+ printf("\n");
+#else
+ printf("\015\012");
+#endif /* OSK */
+ rv = 0;
+ break;
+ case '\003':
+ case '\004':
+ case '\032':
+#ifdef OSK
+ printf("^%c...\n", (c + 0100));
+#else
+ printf("^%c...\015\012", (c + 0100));
+#endif /* OSK */
+ rv = 0;
+ break;
+ /* Invalid answer */
+ default:
+ debug(F111,"askmore","invalid answer",c);
+ printf("Y or space-bar for yes, N for no, G to show the rest\n");
+ continue;
+ }
+#ifdef OS2
+ printf("\r \r");
+ fflush(stdout);
+#endif /* OS2 */
+ }
+ return(rv);
+#endif /* NOICP */
+}
+
+/* T R A P -- Terminal interrupt handler */
+
+SIGTYP
+#ifdef CK_ANSIC
+trap(int sig)
+#else
+trap(sig) int sig;
+#endif /* CK_ANSIC */
+/* trap */ {
+ extern int b_save, f_save;
+#ifndef NOICP
+ extern int timelimit;
+#endif /* NOICP */
+#ifdef OS2
+ extern unsigned long startflags;
+#ifndef NOSETKEY
+ extern int os2gks;
+#endif /* NOSETKEY */
+ int i;
+#endif /* OS2 */
+#ifndef NOSPL
+ extern int i_active, instatus;
+#endif /* NOSPL */
+#ifdef VMS
+ int i; FILE *f;
+#endif /* VMS */
+ extern int zchkod, zchkid;
+#ifndef NOSPL
+ extern int unkmacro;
+#endif /* NOSPL */
+
+ debok = 1;
+#ifdef NTSIG
+ connoi();
+#endif /* NTSIG */
+#ifdef __EMX__
+ signal(SIGINT, SIG_ACK);
+#endif
+#ifdef GEMDOS
+/* GEM is not reentrant, no i/o from interrupt level */
+ cklongjmp(cmjbuf,1); /* Jump back to parser now! */
+#endif /* GEMDOS */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"*********************","",0);
+ if (sig == SIGINT)
+ debug(F101,"trap caught SIGINT","",sig);
+ else
+ debug(F101,"trap caught signal","",sig);
+ debug(F100,"*********************","",0);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ if ( sig == SIGBREAK && (startflags & 128) ) {
+ debug(F101,"trap ignoring SIGBREAK","",sig);
+ return;
+ }
+#endif /* OS2 */
+
+#ifndef NOICP
+ timelimit = 0; /* In case timed ASK interrupted */
+#ifndef NOSPL
+ unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */
+#endif /* NOSPL */
+#endif /* NOICP */
+ zchkod = 0; /* Or file expansion interrupted... */
+ zchkid = 0;
+ interrupted = 1;
+
+ if (what & W_CONNECT) { /* Are we in CONNECT mode? */
+/*
+ The HP workstation Reset key sends some kind of ueber-SIGINT that can not
+ be SIG_IGNored, so we wind up here somehow (even though this is *not* the
+ current SIGINT handler). Just return.
+*/
+ debug(F101,"trap: SIGINT caught during CONNECT","",sig);
+ SIGRETURN;
+ }
+#ifndef NOSPL
+ if (i_active) { /* INPUT command was active? */
+ i_active = 0; /* Not any more... */
+ instatus = INP_UI; /* INPUT status = User Interrupted */
+ }
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ ftreset(); /* Restore global protocol settings */
+ binary = b_save; /* Then restore these */
+ fncnv = f_save;
+ bye_active = 0;
+ diractive = 0;
+ cdactive = 0;
+#endif /* NOXFER */
+ zclose(ZIFILE); /* If we were transferring a file, */
+ zclose(ZOFILE); /* close it. */
+#ifndef NOICP
+ cmdsquo(cmd_quoting); /* If command quoting was turned off */
+#ifdef CKLEARN
+ {
+ extern FILE * learnfp;
+ extern int learning;
+ if (learnfp) {
+ fclose(learnfp);
+ learnfp = NULL;
+ learning = 0;
+ }
+ }
+#endif /* CKLEARN */
+#endif /* NOICP */
+#ifdef CK_APC
+ delmac("_apc_commands",1);
+ apcactive = APC_INACTIVE;
+#endif /* CK_APC */
+
+#ifdef VMS
+/*
+ Fix terminal.
+*/
+ if (ft_win) { /* If curses window open */
+ debug(F100,"^C trap() curses","",0);
+ xxscreen(SCR_CW,0,0L,""); /* Close it */
+ conres(); /* Restore terminal */
+ i = printf("^C..."); /* Echo ^C to standard output */
+ } else {
+ conres();
+ i = printf("^C...\n"); /* Echo ^C to standard output */
+ }
+ if (i < 1 && ferror(stdout)) { /* If there was an error */
+ debug(F100,"^C trap() error","",0);
+ fclose(stdout); /* close standard output */
+ f = fopen(dftty, "w"); /* open the controlling terminal */
+ if (f) stdout = f; /* and make it standard output */
+ printf("^C...\n"); /* and echo the ^C again. */
+ }
+#else /* Not VMS */
+#ifdef STRATUS
+ conres(); /* Set console back to normal mode */
+#endif /* STRATUS */
+#ifndef NOXFER
+ if (ft_win) { /* If curses window open, */
+ debug(F100,"^C trap() curses","",0);
+ xxscreen(SCR_CW,0,0L,""); /* close it. */
+ printf("^C..."); /* Echo ^C to standard output */
+ } else {
+#endif /* NOXFER */
+ printf("^C...\n");
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+#endif /* VMS */
+#ifdef datageneral
+ connoi_mt(); /* Kill asynch task that listens to */
+ ttimoff();
+ conres(); /* the keyboard */
+#endif /* datageneral */
+
+#ifndef NOCCTRAP
+/* This is stupid -- every version should have ttimoff()... */
+#ifdef UNIX
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef OSK
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef STRATUS
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef OS2
+#ifndef NOSETKEY
+ os2gks = 1; /* Turn back on keycode mapping */
+#endif /* NOSETKEY */
+#ifndef NOLOCAL
+ for (i = 0; i < VNUM; i++)
+ VscrnResetPopup(i);
+#endif /* NOLOCAL */
+#ifdef TCPSOCKET
+#ifdef NT
+ /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
+ if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
+ WSACancelBlockingCall();
+ }
+#endif /* NT */
+#endif /* TCPSOCKET */
+#ifdef CK_NETBIOS
+ NCBCancelOutstanding();
+#endif /* CK_NETBIOS */
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef VMS
+ ttimoff(); /* Turn off any timer interrupts */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* OSK */
+#endif /* UNIX */
+
+#ifdef NETPTY
+ /* Clean up Ctrl-C out of REDIRECT or external protocol */
+ {
+ extern PID_T pty_fork_pid;
+ extern int pty_master_fd, pty_slave_fd;
+ int x;
+
+ signal(SIGCHLD,SIG_IGN); /* We don't want this any more */
+
+ debug(F101,"trap pty_master_fd","",pty_master_fd);
+ if (pty_master_fd > 2) {
+ x = close(pty_master_fd);
+ debug(F101,"trap pty_master_fd close","",x);
+ }
+ pty_master_fd = -1;
+ debug(F101,"trap pty_slave_fd","",pty_slave_fd);
+ if (pty_slave_fd > 2) {
+ x = close(pty_slave_fd);
+ debug(F101,"trap pty_slave_fd close","",x);
+ }
+ pty_slave_fd = -1;
+ debug(F101,"trap pty_fork_pid","",pty_fork_pid);
+ if (pty_fork_pid > 0) {
+ x = kill(pty_fork_pid,0); /* See if the fork is really there */
+ debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno);
+ if (x == 0) { /* Seems to be active */
+ x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */
+ debug(F101,"trap pty_fork_pid kill SIGHUP","",x);
+ msleep(100);
+ errno = 0;
+ x = kill(pty_fork_pid,0); /* Is it still there? */
+ if (x == 0
+#ifdef ESRCH
+ /* This module is not always exposed to <errno.h> */
+ || errno != ESRCH
+#endif /* ESRCH */
+ ) {
+ x = kill(pty_fork_pid,SIGKILL);
+ debug(F101,"trap pty_fork_pid kill SIGKILL","",x);
+ }
+ }
+ pty_fork_pid = -1;
+ }
+ }
+#endif /* NETPTY */
+
+#ifdef OSK
+ sigmask(-1);
+/*
+ We are in an intercept routine but do not perform a F$RTE (done implicitly
+ by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump
+ only restores the cpu registers, NOT the fpu registers. So don't use fpu at
+ all or at least don't use common fpu (double or float) register variables.
+*/
+#endif /* OSK */
+
+#ifdef NTSIG
+ PostCtrlCSem();
+#else /* NTSIG */
+ debug(F100,"trap about to longjmp","",0);
+#ifdef NT
+ cklongjmp(ckjaddr(cmjbuf),1);
+#else /* NT */
+ cklongjmp(cmjbuf,1);
+#endif /* NT */
+#endif /* NTSIG */
+#else /* NOCCTRAP */
+/* No Ctrl-C trap, just exit. */
+#ifdef CK_CURSES /* Curses support? */
+ xxscreen(SCR_CW,0,0L,""); /* Close curses window */
+#endif /* CK_CURSES */
+ doexit(BAD_EXIT,what); /* Exit poorly */
+#endif /* NOCCTRAP */
+ SIGRETURN;
+}
+
+
+/* C K _ T I M E -- Returns pointer to current time. */
+
+char *
+ck_time() {
+ static char tbuf[10];
+ char *p;
+ int x;
+
+ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
+ if (!p) /* like asctime()! */
+ return("");
+ if (*p) {
+ for (x = 11; x < 19; x++) /* copy hh:mm:ss */
+ tbuf[x - 11] = p[x]; /* to tbuf */
+ tbuf[8] = NUL; /* terminate */
+ }
+ return(tbuf); /* and return it */
+}
+
+/* C C _ C L E A N -- Cleanup after terminal interrupt handler */
+
+#ifdef GEMDOS
+int
+cc_clean() {
+ zclose(ZIFILE); /* If we were transferring a file, */
+ zclose(ZOFILE); /* close it. */
+ printf("^C...\n"); /* Not VMS, no problem... */
+}
+#endif /* GEMDOS */
+
+
+/* S T P T R A P -- Handle SIGTSTP (suspend) signals */
+
+SIGTYP
+#ifdef CK_ANSIC
+stptrap(int sig)
+#else
+stptrap(sig) int sig;
+#endif /* CK_ANSIC */
+/* stptrap */ {
+
+#ifndef NOJC
+ int x; extern int cmflgs;
+ debug(F101,"stptrap() caught signal","",sig);
+ if (!xsuspend) {
+ printf("\r\nsuspend disabled\r\n");
+#ifndef NOICP
+ if (what & W_COMMAND) { /* If we were parsing commands */
+ prompt(xxstring); /* reissue the prompt and partial */
+ if (!cmflgs) /* command (if any) */
+ printf("%s",cmdbuf);
+ }
+#endif /* NOICP */
+ } else {
+ conres(); /* Reset the console */
+#ifndef OS2
+ /* Flush pending output first, in case we are continued */
+ /* in the background, which could make us block */
+ fflush(stdout);
+
+ x = psuspend(xsuspend); /* Try to suspend. */
+ if (x < 0)
+#endif /* OS2 */
+ printf("Job control not supported\r\n");
+ conint(trap,stptrap); /* Rearm the trap. */
+ debug(F100,"stptrap back from suspend","",0);
+ switch (what) {
+ case W_CONNECT: /* If suspended during CONNECT? */
+ conbin((char)escape); /* put console back in binary mode */
+ debug(F100,"stptrap W_CONNECT","",0);
+ break;
+#ifndef NOICP
+ case W_COMMAND: /* Suspended in command mode */
+ debug(F101,"stptrap W_COMMAND pflag","",pflag);
+ concb((char)escape); /* Put back CBREAK tty mode */
+ if (pflag) { /* If command parsing was */
+ prompt(xxstring); /* reissue the prompt and partial */
+ if (!cmflgs) /* command (if any) */
+ printf("%s",cmdbuf);
+ }
+ break;
+#endif /* NOICP */
+ default: /* All other cases... */
+ debug(F100,"stptrap default","",0);
+ concb((char)escape); /* Put it back in CBREAK mode */
+ break;
+ }
+ }
+#endif /* NOJC */
+ SIGRETURN;
+}
+
+#ifdef TLOG
+#define TBUFL 300
+
+/* T L O G -- Log a record in the transaction file */
+/*
+ Call with a format and 3 arguments: two strings and a number:
+ f - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
+ s1,s2 - String arguments 0 and 1.
+ n - Long, argument 2.
+*/
+VOID
+#ifdef CK_ANSIC
+dotlog(int f, char *s1, char *s2, CK_OFF_T n)
+#else
+dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2;
+#endif /* CK_ANSIC */
+/* dotlog */ {
+ static char s[TBUFL];
+ extern int tlogfmt;
+ char *sp = s; int x;
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+
+ if (!tralog) return; /* If no transaction log, don't */
+ if (tlogfmt != 1) return;
+ switch (f) {
+ case F000: /* 0 (special) "s1 n s2" */
+ if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
+ sprintf(sp,"?T-Log string too long");
+ else
+ sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F001: /* 1, " n" */
+ sprintf(sp," %s",ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F010: /* 2, "[s2]" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if (x + 6 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"[%s]",s2);
+ if (zsoutl(ZTFILE,"") < 0) tralog = 0;
+ break;
+ case F011: /* 3, "[s2] n" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if (x + 6 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"[%s] %s",s2,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F100: /* 4, "s1" */
+ if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
+ break;
+ case F101: /* 5, "s1: n" */
+ if ((int)strlen(s1) + 15 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"%s: %s",s1,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F110: /* 6, "s1 s2" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if ((int)strlen(s1) + x + 4 > TBUFL)
+ sprintf(sp,"?String too long");
+ else
+ sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F111: /* 7, "s1 s2: n" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if ((int)strlen(s1) + x + 15 > TBUFL)
+ sprintf(sp,"?String too long");
+ else
+ sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ default:
+ sprintf(sp,"?Invalid format for tlog() - %d",f);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ }
+}
+
+/*
+ D O X L O G
+
+ This is the transaction-log writer for BRIEF format.
+ The idea is produce one record (line) per file. Each record
+ has the following delimited fields:
+ Date (yyyymmdd)
+ Time (hh:mm:ss)
+ Action: SEND or RECV
+ File name
+ File size
+ Transfer mode (text, binary, image, labeled, etc).
+ Status: OK or FAILED
+ Free-form comments in doublequotes
+ The default separator is comma.
+ If a field contains the separator, it is enclosed in doublequotes.
+*/
+VOID
+#ifdef CK_ANSIC
+doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg)
+#else
+doxlog(x, fn, fs, fm, status, msg)
+ int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg;
+#endif /* CK_ANSIC */
+/* doxlog */ {
+ extern int tlogsep;
+ char sep[2];
+ char buf[CKMAXPATH+256], * bufp;
+ char tmpbuf[32];
+ char * s, * p;
+ int len, left, ftp = 0, k;
+
+ if (!tralog) return; /* If no transaction log, don't */
+
+ if (!fn) fn = ""; /* Protect against null pointers */
+ if (!msg) msg = "";
+ if (x & W_FTP)
+ ftp++;
+
+ sep[0] = (char) tlogsep;
+ sep[1] = NUL;
+ if (!sep[0]) sep[0] = ',';
+
+ bufp = buf;
+ left = sizeof(buf);
+ debug(F101,"XXX doxlog left 1","",left);
+
+ p = zzndate(); /* Date */
+ ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
+ bufp += 9;
+ left -= 9;
+ debug(F111,"XXX doxlog left 2",buf,left);
+
+ ztime(&p);
+ ckstrncpy(bufp,p+11,left);
+ bufp += 8;
+ left -= 8;
+ debug(F111,"XXX doxlog left 3",buf,left);
+
+ if (ftp) {
+ if (!(x & (W_SEND|W_RECV)))
+ return;
+ s = (x & W_SEND) ? "PUT" : "GET";
+ k = 3;
+ } else {
+ s = (x & W_SEND) ? "SEND" : "RECV";
+ k = 4;
+ }
+ ckmakmsg(bufp,left,sep,s,sep,NULL);
+ bufp += k + 2;
+ left -= (k + 2);
+ debug(F111,"XXX doxlog left 4",buf,left);
+
+ s = "";
+ if (ckstrchr(fn,sep[0])) /* Filename */
+ s = "\"";
+ ckmakmsg(bufp,left,s,fn,s,sep);
+ sprintf(tmpbuf,"%s",ckfstoa(fs)); /* Size */
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,sep,CKMAXPATH);
+ debug(F110,"doxlog 4",buf,0);
+
+#ifdef NOICP
+ /* Transfer mode */
+ ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
+#else
+ ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
+#endif /* NOICP */
+ if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */
+ ckstrncat(buf,"\"",CKMAXPATH);
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,"\"",CKMAXPATH);
+ } else
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,sep,CKMAXPATH);
+ debug(F110,"doxlog 5",buf,0);
+
+ ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
+ len = strlen(buf);
+ left = CKMAXPATH+256 - len;
+ if (left < 2) fatal("doxlog buffer overlow");
+
+ debug(F111,"XXX doxlog left 5",buf,left);
+
+ debug(F110,"doxlog buf 1", buf, len);
+ s = buf + len;
+ if (status == 0 && left > 32) {
+ long cps = 0L;
+#ifdef GFTIMER
+ debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
+ if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs);
+ sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
+#else
+ if (xfsecs) cps = fs / xfsecs;
+ sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
+#endif /* GFTIMER */
+ } else if ((int)strlen(msg) + 4 < left) {
+ sprintf(s,"%s\"%s\"",sep,msg);
+ }
+ debug(F111,"XXX doxlog left 5",buf,left);
+
+ debug(F110,"doxlog 5",buf,0);
+ x = zsoutl(ZTFILE,buf);
+ debug(F101,"doxlog zsoutl","",x);
+ if (x < 0) tralog = 0;
+}
+#endif /* TLOG */
+
+#ifndef MAC
+/*
+ The rest of this file is for all implementations but the Macintosh.
+*/
+
+#ifdef CK_CURSES
+static int repaint = 0; /* Transfer display needs repainting */
+#endif /* CK_CURSES */
+
+#ifndef NOXFER
+/* C H K I N T -- Check for console interrupts */
+
+/*
+ Used during file transfer in local mode only:
+ . If user has not touched the keyboard, returns 0 with no side effects.
+ . If user typed S or A (etc, see below) prints status message and returns 0.
+ . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
+ . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
+ . If user typed E or C (etc, see below) returns -1.
+*/
+int
+chkint() {
+ int ch, cn, ofd; long zz;
+ if (!xfrint)
+ return(0);
+ if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
+#ifdef datageneral
+ if (con_reads_mt) /* if conint_mt task is active */
+ if (conint_avl) { /* and there's an interrupt pending */
+ cn = 1; /* process it */
+ ch = conint_ch;
+ conint_avl = 0; /* turn off flag so conint_mt can */
+ } else /* proceed */
+ return(0);
+ else /* if conint_mt not active */
+ if ((ch = coninc(2)) < 0) /* try to get char manually */
+ return(0); /* I/O error, or no data */
+ else /* if successful, set cn so we */
+ cn = 1; /* know we got one */
+ debug(F101,"chkint got keyboard character",ch,cn);
+#else /* !datageneral */
+#ifdef NTSIG
+ {
+ extern int TlsIndex;
+ struct _threadinfo * threadinfo;
+ threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
+ if (threadinfo) {
+ if (!WaitSem(threadinfo->DieSem,0))
+ return -1; /* Cancel Immediately */
+ }
+ }
+#endif /* NTSIG */
+ cn = conchk(); /* Any input waiting? */
+ debug(F101,"conchk","",cn);
+ if (cn < 1) return(0);
+ ch = coninc(5) ;
+ debug(F101,"coninc","",ch);
+ if (ch < 0) return(0);
+#endif /* datageneral */
+
+ ch &= 0177;
+ switch (ch) {
+ case 'A': case 'a': case 0001: /* Status report */
+ case 'S': case 's':
+ if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
+ return(0); /* Only for serial, simple or none */
+ ofd = fdispla; /* [MF] Save file display type */
+ if (fdispla == XYFD_N)
+ fdispla = XYFD_R; /* [MF] Pretend serial if no display */
+ xxscreen(SCR_TN,0,0l,"Status report:");
+ xxscreen(SCR_TN,0,0l," file type: ");
+ if (binary) {
+ switch(binary) {
+ case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
+ case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
+ case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
+ default:
+ case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
+ }
+ } else {
+#ifdef NOCSETS
+ xxscreen(SCR_TZ,0,0l,"text");
+#else
+ xxscreen(SCR_TU,0,0l,"text, ");
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ xxscreen(SCR_TZ,0,0l,"transparent");
+ } else {
+ if (what & W_SEND) {
+ xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
+ xxscreen(SCR_TU,0,0l," => ");
+ xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
+ } else {
+ xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
+ xxscreen(SCR_TU,0,0l," => ");
+ xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
+ }
+ }
+#endif /* NOCSETS */
+ }
+ xxscreen(SCR_QE,0,filcnt," file number");
+ if (fsize) xxscreen(SCR_QE,0,fsize," size");
+ xxscreen(SCR_QE,0,ffc," characters so far");
+ if (fsize > 0L) {
+#ifdef CK_RESEND
+ zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
+ zz = ( (ffc + zz) * 100L ) / fsize;
+#else
+ zz = ( ffc * 100L ) / fsize;
+#endif /* CK_RESEND */
+ xxscreen(SCR_QE,0,zz, " percent done");
+ }
+ if (bctu == 4) { /* Block check */
+ xxscreen(SCR_TU,0,0L," block check: ");
+ xxscreen(SCR_TZ,0,0L,"blank-free-2");
+ } else xxscreen(SCR_QE,0,(long)bctu, " block check");
+ xxscreen(SCR_QE,0,(long)rptflg," compression");
+ xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
+ xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
+ if (!network)
+ xxscreen(SCR_QE,0, speed, " speed");
+ if (what & W_SEND)
+
+ xxscreen(SCR_QE,0,spsiz, " packet length");
+ else if (what & W_RECV || what & W_REMO)
+ xxscreen(SCR_QE,0,urpsiz," packet length");
+ xxscreen(SCR_QE,0,wslots, " window slots");
+ fdispla = ofd; /* [MF] Restore file display type */
+ return(0);
+
+ case 'B': case 'b': case 0002: /* Cancel batch */
+ case 'Z': case 'z': case 0032:
+ czseen = 1;
+ interrupted = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ (((what & W_RECV) && (wslots > 1)) ?
+ "Canceling batch, wait... " :
+ "Canceling batch... ")
+ );
+ return(0);
+
+ case 'F': case 'f': case 0006: /* Cancel file */
+ case 'X': case 'x': case 0030:
+ cxseen = 1;
+ interrupted = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ (((what & W_RECV) && (wslots > 1)) ?
+ "Canceling file, wait... " :
+ "Canceling file... ")
+ );
+ return(0);
+
+ case 'R': case 'r': case 0022: /* Resend packet */
+ case 0015: case 0012:
+#ifdef STREAMING
+ if (streaming)
+ return(0);
+#endif /* STREAMING */
+ xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
+ numerrs++;
+ resend(winlo);
+ return(0);
+
+#ifdef datageneral
+ case '\03': /* We're not trapping ^C's with */
+ trap(0); /* signals, so we check here */
+#endif /* datageneral */
+
+ case 'C': case 'c': /* Ctrl-C */
+#ifndef datageneral
+ case '\03':
+#endif /* datageneral */
+
+ case 'E': case 'e': /* Send error packet */
+ case 0005:
+ interrupted = 1;
+ return(-1);
+
+#ifdef CK_CURSES
+ case 0014: /* Ctrl-L to refresh screen */
+ case 'L': case 'l': /* Also accept L (upper, lower) */
+ case 0027: /* Ctrl-W synonym for VMS & Ingres */
+ repaint = 1;
+ return(0);
+#endif /* CK_CURSES */
+
+ case 'T':
+ case 't': /* Turn on debug-log timestamps */
+#ifdef DEBUG
+ {
+ extern int debtim;
+ if (ch == 'T') {
+ debtim = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ "Debug timestamps On... ");
+ } else {
+ debtim = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ "Debug timestamps Off... ");
+ }
+ }
+#endif /* DEBUG */
+ return(0);
+
+ case 'D':
+#ifdef DEBUG
+ if (!deblog) {
+ debopn("debug.log",0);
+ if (deblog) {
+ xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
+ } else {
+ xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
+ }
+ } else {
+ xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
+ }
+ if (deblog)
+ debok = 1;
+#endif /* DEBUG */
+ return(0);
+
+ case 'd': /* Turn off debugging */
+#ifdef DEBUG
+ if (deblog)
+ xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
+ debok = 0;
+#endif /* DEBUG */
+ return(0);
+
+ default: /* Anything else, print message */
+ intmsg(1L);
+ return(0);
+ }
+}
+
+/* I N T M S G -- Issue message about terminal interrupts */
+
+VOID
+#ifdef CK_ANSIC
+intmsg(long n)
+#else
+intmsg(n) long n;
+#endif /* CK_ANSIC */
+/* intmsg */ {
+#ifdef CK_NEED_SIG
+ char buf[80];
+#endif /* CK_NEED_SIG */
+
+ if (!displa || quiet) /* Not if we're being quiet */
+ return;
+ if (server && (!srvdis || n > -1L)) /* Special for server */
+ return;
+#ifdef CK_NEED_SIG
+ buf[0] = NUL; /* Keep compilers happy */
+#endif /* CK_NEED_SIG */
+#ifndef OXOS
+#ifdef SVORPOSIX
+ conchk(); /* Clear out pending escape-signals */
+#endif /* SVORPOSIX */
+#endif /* ! OXOS */
+#ifdef VMS
+ conres(); /* So Ctrl-C will work */
+#endif /* VMS */
+ if ((!server && n == 1L) || (server && n < 0L)) {
+
+#ifdef CK_NEED_SIG
+ if (xfrint) {
+ ckmakmsg(buf,
+ 80,
+ "Type escape character (",
+ dbchr(escape),
+ ") followed by:",
+ NULL
+ );
+ xxscreen(SCR_TN,0,0l,buf);
+ }
+#endif /* CK_NEED_SIG */
+
+ if (xfrint) {
+ if (protocol == PROTO_K) {
+ xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet");
+ xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
+ xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
+ } else {
+ xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
+ }
+ } else {
+ xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
+ }
+ }
+ else xxscreen(SCR_TU,0,0l," ");
+}
+
+#ifndef NODISPLAY
+static int newdpy = 0; /* New display flag */
+static char fbuf[80]; /* Filename buffer */
+static char abuf[80]; /* As-name buffer */
+static char a2buf[80]; /* Second As-name buffer */
+static CK_OFF_T oldffc = 0L;
+static CK_OFF_T dots = 0L;
+static int hpos = 0;
+
+static VOID /* Initialize Serial or CRT display */
+dpyinit() {
+ int m = 0, n = 0;
+ char * s = "";
+
+ newdpy = 0; /* Don't do this again */
+ oldffc = (CK_OFF_T)0; /* Reset this */
+ dots = (CK_OFF_T)0; /* and this.. */
+ oldcps = cps = 0L;
+
+ conoll(""); /* New line */
+ if (what & W_SEND) s = "Sending: "; /* Action */
+ else if (what & W_RECV) s = "Receiving: ";
+ n = (int)strlen(s) + (int)strlen(fbuf);
+ conol(fbuf);
+ m = (int)strlen(abuf) + 4;
+ if (n + m > cmd_cols) {
+ conoll("");
+ n = 0;
+ } else
+ n += m;
+ if (*abuf) {
+ conol(" => ");
+ conol(abuf);
+ }
+ m = (int)strlen(a2buf) + 4;
+ if (n + m > cmd_cols) {
+ conoll("");
+ n = 0;
+ } else
+ n += m;
+ if (*a2buf) {
+ conol(" => ");
+ conol(a2buf);
+ }
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ conoll("");
+ if (fsize > (CK_OFF_T)-1) { /* Size */
+ sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */
+ conol(fbuf); *fbuf = NUL;
+ } else conol("Size: unknown, Type: ");
+ if (binary) { /* Type */
+ switch(binary) {
+ case XYFT_L: conol("labeled"); break;
+ case XYFT_I: conol("image"); break;
+ case XYFT_U: conol("binary undefined"); break;
+ default:
+ case XYFT_B: conol("binary"); break;
+ }
+ } else {
+#ifdef NOCSETS
+ conol("text");
+#else
+ conol("text, ");
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ conol("transparent");
+ } else {
+ if (what & W_SEND) {
+ conol(fcsinfo[fcharset].keyword);
+ conol(" => ");
+ conol(tcsinfo[tcharset].keyword);
+ } else {
+ conol(tcsinfo[tcharset].keyword);
+ conol(" => ");
+ conol(fcsinfo[fcharset].keyword);
+ }
+ }
+#endif /* NOCSETS */
+ }
+#ifdef STREAMING
+ if (streaming)
+ conol(", STREAMING");
+#endif /* STREAMING */
+ conoll("");
+
+ if (fdispla == XYFD_S) { /* CRT field headings */
+/*
+ Define CK_CPS to show current transfer rate.
+ Leave it undefined to show estimated time remaining.
+ Estimated-time-remaining code from Andy Fyfe, not tested on
+ pathological cases.
+*/
+#define CK_CPS
+
+#ifdef CK_CPS
+ conoll(" File Percent Packet");
+ conoll(" Bytes Done CPS Length");
+#else
+ conoll(" File Percent Secs Packet");
+ conoll(" Bytes Done Left Length");
+#endif /* CK_CPS */
+ newdpy = 0;
+ }
+ hpos = 0;
+}
+
+/*
+ showpkt(c)
+ c = completion code: 0 means transfer in progress, nonzero means it's done.
+ Show the file transfer progress counter and perhaps verbose packet type.
+*/
+VOID
+#ifdef CK_ANSIC
+showpkt(char c)
+#else
+showpkt(c) char c;
+#endif /* CK_ANSIC */
+/* showpkt */ {
+
+#ifndef GFTIMER
+ long et; /* Elapsed time, entire batch */
+#endif /* GFTIMER */
+ CK_OFF_T howfar; /* How far into file */
+ long pd; /* Percent done, this file */
+ long tp; /* Transfer rate, entire batch */
+ long ps; /* Packet size, current packet */
+ CK_OFF_T mytfc; /* Local copy of byte counter */
+
+#ifdef GFTIMER
+ CKFLOAT tnow;
+#endif /* GFTIMER */
+
+ if (newdpy) /* Put up filenames, etc, */
+ dpyinit(); /* if they're not there already. */
+
+ howfar = ffc; /* How far */
+/*
+ Calculate CPS rate even if not displaying on screen for use in file
+ transfer statistics.
+*/
+#ifdef GFTIMER
+ tnow = gftimer(); /* Time since we started */
+ ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
+#ifdef CK_RESEND
+ if (what & W_SEND) /* In case we didn't start at */
+ howfar += sendstart; /* the beginning... */
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ pd = -1; /* Percent done. */
+ if (c == NUL) { /* Still going, figure % done */
+ if (!fsize) return; /* Empty file, don't bother */
+ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
+ if (pd > 100) pd = 100; /* Expansion */
+ }
+ if (c != NUL)
+ if (!cxseen && !discard && !czseen)
+ pd = 100; /* File complete, so 100%. */
+
+ mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */
+ tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
+ if (c && (tp == 0))
+ tp = ffc;
+
+ cps = tp; /* Set global variable */
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+
+#else /* Not GFTIMER */
+
+ et = gtimer(); /* Elapsed time */
+ ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
+#ifdef CK_RESEND
+ if (what & W_SEND) /* And if we didn't start at */
+ howfar += sendstart; /* the beginning... */
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ pd = -1; /* Percent done. */
+ if (c == NUL) { /* Still going, figure % done */
+ if (fsize == 0L) return; /* Empty file, don't bother */
+ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
+ if (pd > 100) pd = 100; /* Expansion */
+ }
+ if (c != NUL)
+ if (!cxseen && !discard && !czseen)
+ pd = 100; /* File complete, so 100%. */
+
+
+#ifndef CK_CPS
+/*
+ fsecs = time (from gtimer) that this file started (set in sfile()).
+ Rate so far is ffc / (et - fsecs), estimated time for remaining bytes
+ is (fsize - ffc) / (ffc / (et - fsecs)).
+*/
+ tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0;
+#endif /* CK_CPS */
+
+#ifdef CK_CPS
+ mytfc = (pd < 100) ? tfc + ffc : tfc;
+ tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
+ if (c && (tp == 0)) /* Watch out for subsecond times */
+ tp = ffc;
+
+ cps = tp; /* Set global variable */
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+#endif /* CK_CPS */
+
+#endif /* GFTIMER */
+
+ if (fdispla == XYFD_S) { /* CRT display */
+ char buffer[128];
+ /* These sprintfs should be safe until we have 32-digit numbers */
+
+ if (pd > -1L)
+ sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CR,ckfstoa(howfar),pd,tp,ps);
+ else
+ sprintf(buffer, "%c%9s %8ld%8ld ", CR,ckfstoa(howfar),tp,ps);
+ conol(buffer);
+ hpos = 31;
+ } else if (fdispla == XYFD_R) { /* SERIAL */
+ long i, k;
+ if (howfar - oldffc < 1024) /* Update display every 1K */
+ return;
+ oldffc = howfar; /* Time for new display */
+ k = (howfar / 1024L) - dots; /* How many K so far */
+ for (i = 0L; i < k; i++) {
+ if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
+ conoll("");
+ hpos = 0;
+ }
+ conoc('.'); /* Print a dot for this K */
+ dots++; /* Count it */
+ }
+ }
+}
+
+
+/* C K S C R E E N -- Screen display function */
+
+/*
+ ckscreen(f,c,n,s)
+ f - argument descriptor
+ c - a character or small integer
+ n - a long integer
+ s - a string.
+
+ and global fdispla = SET FILE DISPLAY value:
+
+ XYFD_N = NONE
+ XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy.
+ XYFD_S = CRT: Works on any CRT, writes over current line.
+ XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
+ XYFD_B = BRIEF: Like SERIAL but only filename & completion status.
+ XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN
+*/
+VOID
+#ifdef CK_ANSIC
+ckscreen(int f, char c,CK_OFF_T n,char *s)
+#else
+ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s;
+#endif /* CK_ANSIC */
+/* screen */ {
+ char buf[80];
+ int len; /* Length of string */
+#ifdef UNIX
+#ifndef NOJC
+ int obg;
+_PROTOTYP( VOID conbgt, (int) );
+#endif /* NOJC */
+#endif /* UNIX */
+ int ftp = 0;
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */
+
+ if (!local && !ftp) /* In remote mode - don't do this */
+ return;
+
+ if (!s) s = "";
+
+ if (!fxd_inited) /* Initialize if necessary */
+ fxdinit(fdispla);
+
+#ifdef UNIX
+#ifndef NOJC
+ obg = backgrd; /* Previous background status */
+ conbgt(1); /* See if running in background */
+ if (!backgrd && obg) { /* Just came into foreground? */
+ concb((char)escape); /* Put console back in CBREAK mode */
+ setint(); /* Restore interrupts */
+ }
+#endif /* NOJC */
+#endif /* UNIX */
+
+ if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
+ if (!displa ||
+ (backgrd && bgset) ||
+ fdispla == XYFD_N ||
+ (server && !srvdis)
+ )
+ return;
+
+#ifdef VMS
+ if (f == SCR_FN) /* VMS - shorten the name */
+ s = zrelname(s,zgtdir());
+#endif /* VMS */
+
+ if (dest == DEST_S) /* SET DESTINATION SCREEN */
+ return; /* would interfere... */
+
+#ifdef KUI
+ if (fdispla == XYFD_G) { /* If gui display selected */
+ screeng(f,c,n,s); /* call the gui version */
+ return;
+ }
+#endif /* KUI */
+#ifdef CK_CURSES
+ if (fdispla == XYFD_C) { /* If fullscreen display selected */
+ screenc(f,c,n,s); /* call the fullscreen version */
+ return;
+ }
+#endif /* CK_CURSES */
+
+ len = (int)strlen(s); /* Length of string */
+
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ if (fdispla == XYFD_B) {
+#ifdef NEWFTP
+ if (ftp)
+ printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
+ else
+#endif /* NEWFTP */
+ printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+ }
+#ifdef MAC
+ conoll(""); conol(s); conoc(SP); hpos = len + 1;
+#else
+ ckstrncpy(fbuf,s,80);
+ abuf[0] = a2buf[0] = NUL;
+ newdpy = 1; /* New file so refresh display */
+#endif /* MAC */
+ return;
+
+ case SCR_AN: /* As-name */
+ if (fdispla == XYFD_B) {
+#ifdef COMMENT
+ printf("(as %s) ",s);
+#endif /* COMMENT */
+ return;
+ }
+#ifdef MAC
+ if (hpos + len > 75) { conoll(""); hpos = 0; }
+ conol("=> "); conol(s);
+ if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
+#else
+ if (abuf[0]) {
+ ckstrncpy(a2buf,s,80);
+ } else {
+ ckstrncpy(abuf,s,80);
+ }
+#endif /* MAC */
+ return;
+
+ case SCR_FS: /* File-size */
+ if (fdispla == XYFD_B) {
+ printf(" (%s) (%s byte%s)",
+#ifdef NOICP
+ (binary ? "binary" : "text")
+#else
+ gfmode(binary,0)
+#endif /* NOICP */
+ , ckfstoa(n), n == 1 ? "" : "s");
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+ }
+#ifdef MAC
+ sprintf(buf,", Size: %s",ckfstoa(n)); conoll(buf); hpos = 0;
+#endif /* MAC */
+ return;
+
+ case SCR_XD: /* X-packet data */
+ if (fdispla == XYFD_B)
+ return;
+#ifdef MAC
+ conoll(""); conoll(s); hpos = 0;
+#else
+ ckstrncpy(fbuf,s,80);
+ abuf[0] = a2buf[0] = NUL;
+#endif /* MAC */
+ return;
+
+ case SCR_ST: /* File status */
+ switch (c) {
+ case ST_OK: /* Transferred OK */
+ showpkt('Z'); /* Update numbers one last time */
+ if (fdispla == XYFD_B) {
+#ifdef GFTIMER
+ if (fpxfsecs)
+ printf(": OK (%0.3f sec, %ld cps)",fpxfsecs,
+ (long)((CKFLOAT)ffc / fpxfsecs));
+#else
+ if (xfsecs)
+ printf(": OK (%d sec, %ld cps)",xfsecs,ffc/xfsecs);
+#endif /* GFTIMER */
+ printf("\n");
+ return;
+ }
+ if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
+ conoll(" [OK]"); hpos = 0; /* Print OK message. */
+ if (fdispla == XYFD_S) { /* We didn't show Z packet when */
+ conoc('Z'); /* it came, so show it now. */
+ hpos = 1;
+ }
+ return;
+
+ case ST_DISC: /* Discarded */
+ if (fdispla == XYFD_B) {
+ printf(": DISCARDED\n");
+ return;
+ }
+ if ((hpos += 12) > 78) conoll("");
+ conoll(" [discarded]"); hpos = 0;
+ return;
+
+ case ST_INT: /* Interrupted */
+ if (fdispla == XYFD_B) {
+ printf(": INTERRUPTED\n");
+ return;
+ }
+ if ((hpos += 14) > 78) conoll("");
+ conoll(" [interrupted]"); hpos = 0;
+ return;
+
+ case ST_SIM:
+ if (fdispla == XYFD_B) {
+ if (n == SKP_XNX)
+ printf(": WOULD BE TRANSFERRED (New file)\n");
+ else if (n == SKP_XUP)
+ printf(": WOULD BE TRANSFERRED (Remote file older)\n");
+ else if (n == SKP_SIM)
+ printf(": WOULD BE TRANSFERRED\n");
+ else if (n > 0 && n < nskreason)
+ printf(": SKIPPED (%s)\n",skreason[n]);
+ else
+ printf(": SKIPPED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Would Send: "); /* Action */
+ else if (what & W_RECV) conol("Would Receive: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ }
+ conoll(" [simulated]");
+ return;
+ }
+ if ((hpos += 10) > 78) conoll("");
+ conol(" [simulated]"); hpos = 0;
+ return;
+
+ case ST_SKIP: /* Skipped */
+ if (fdispla == XYFD_B) {
+ if (n == SKP_XNX)
+ printf(": WOULD BE TRANSFERRED (New file)\n");
+ else if (n == SKP_XUP)
+ printf(": WOULD BE TRANSFERRED (Remote file older)\n");
+ else if (n == SKP_SIM)
+ printf(": WOULD BE TRANSFERRED\n");
+ else if (n > 0 && n < nskreason)
+ printf(": SKIPPED (%s)\n",skreason[n]);
+ else
+ printf(": SKIPPED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Sending: "); /* Action */
+ else if (what & W_RECV) conol("Receiving: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ }
+ conoll(" [skipped]");
+ return;
+ }
+ if ((hpos += 10) > 78) conoll("");
+ conol(" "); conol(fbuf);
+ conoll(" [skipped]"); hpos = 0;
+ return;
+
+ case ST_ERR: /* Error */
+ if (fdispla == XYFD_B) {
+ printf(": ERROR: %s\n",s);
+ return;
+ }
+ conoll("");
+ conol("Error: "); conoll(s); hpos = 0;
+ return;
+
+ case ST_MSG: /* Message */
+#ifdef NEWFTP
+ if (fdispla == XYFD_B) {
+ if (ftp && ftp_deb)
+ printf(": MESSAGE: %s\n",s);
+ return;
+ }
+#endif /* NEWFTP */
+ conoll("");
+ conol("Message: ");
+ conoll(s);
+ hpos = 0;
+ return;
+
+ case ST_REFU: /* Refused */
+ if (fdispla == XYFD_B) {
+ printf(": REFUSED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Sending: "); /* Action */
+ else if (what & W_RECV) conol("Receiving: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ conoll("");
+ }
+ conol("Refused: "); conoll(s);
+ return;
+ }
+ conoll("");
+ conol("Refused: "); conoll(s); hpos = 0;
+ return;
+
+ case ST_INC: /* Incomplete */
+ if (fdispla == XYFD_B) {
+ printf(": INCOMPLETE\n");
+ return;
+ }
+ if ((hpos += 12) > 78) conoll("");
+ conoll(" [incomplete]"); hpos = 0;
+ return;
+
+ default:
+ conoll("*** screen() called with bad status ***");
+ hpos = 0;
+ return;
+ }
+
+#ifdef MAC
+ case SCR_PN: /* Packet number */
+ if (fdispla == XYFD_B) {
+ return;
+ }
+ ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
+ conol(buf); hpos += (int)strlen(buf); return;
+#endif /* MAC */
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (fdispla == XYFD_B)
+ return;
+ if (c == 'Y') return; /* Don't bother with ACKs */
+ if (c == 'D') { /* In data transfer phase, */
+ showpkt(NUL); /* show progress. */
+ return;
+ }
+#ifndef AMIGA
+ if (hpos++ > 77) { /* If near right margin, */
+ conoll(""); /* Start new line */
+ hpos = 0; /* and reset counter. */
+ }
+#endif /* AMIGA */
+ if (c == 'Z' && fdispla == XYFD_S)
+ return;
+ else
+ conoc(c); /* Display the packet type. */
+#ifdef AMIGA
+ if (c == 'G') conoll(""); /* New line after G packets */
+#endif /* AMIGA */
+ return;
+
+ case SCR_TC: /* Transaction complete */
+ if (xfrbel) bleep(BP_NOTE);
+ if (fdispla == XYFD_B) { /* Brief display... */
+ if (filcnt > 1) {
+ long fx;
+ fx = filcnt - filrej;
+ printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s"));
+ printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s"));
+#ifdef GFTIMER
+ printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
+#else
+ printf(", %ld sec, %ld cps", tsecs, tfcps);
+#endif /* GFTIMER */
+ printf(".\n");
+ }
+ } else {
+ conoll("");
+ }
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+
+ case SCR_EM: /* Error message */
+ if (fdispla == XYFD_B) {
+ printf(" ERROR: %s\n",s);
+ return;
+ }
+ conoll(""); conoc('?'); conoll(s); hpos = 0; return;
+
+ case SCR_WM: /* Warning message */
+ if (fdispla == XYFD_B) {
+ printf(" WARNING: %s\n",s);
+ return;
+ }
+ conoll(""); conoll(s); hpos = 0; return;
+
+ case SCR_MS: /* Message from other Kermit */
+ if (fdispla == XYFD_B) {
+ printf(" MESSAGE: %s\n",s);
+ return;
+ }
+ conoll(""); conoll(s); hpos = 0; return;
+
+ case SCR_TU: /* Undelimited text */
+ if (fdispla == XYFD_B)
+ return;
+ if ((hpos += len) > 77) { conoll(""); hpos = len; }
+ conol(s); return;
+
+ case SCR_TN: /* Text delimited at beginning */
+ if (fdispla == XYFD_B)
+ return;
+ conoll(""); conol(s); hpos = len; return;
+
+ case SCR_TZ: /* Text delimited at end */
+ if (fdispla == XYFD_B)
+ return;
+ if ((hpos += len) > 77) { conoll(""); hpos = len; }
+ conoll(s); return;
+
+ case SCR_QE: /* Quantity equals */
+ if (fdispla == XYFD_B)
+ return;
+ ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
+ conoll(buf); hpos = 0; return;
+
+ case SCR_CW: /* Close fullscreen window */
+ return; /* No window to close */
+
+ case SCR_CD:
+ return;
+
+ default:
+ conoll("*** screen() called with bad object ***");
+ hpos = 0;
+ return;
+ }
+}
+#endif /* NODISPLAY */
+
+/* E R M S G -- Nonfatal error message */
+
+/* Should be used only for printing the message text from an Error packet. */
+
+VOID
+ermsg(msg) char *msg; { /* Print error message */
+ debug(F110,"ermsg",msg,0);
+ if (local)
+ xxscreen(SCR_EM,0,0L,msg);
+ tlog(F110,"Protocol Error:",msg,0L);
+}
+#endif /* NOXFER */
+
+VOID
+setseslog(x) int x; {
+ seslog = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_CAPTURE,x,0);
+#endif /* KUI */
+}
+
+VOID
+doclean(fc) int fc; { /* General cleanup */
+#ifdef OS2ORUNIX
+ extern int ttyfd;
+#endif /* OS2ORUNIX */
+ extern int keep;
+ extern int exithangup;
+#ifndef NOXFER
+ extern char filnam[];
+#endif /* NOXFER */
+#ifndef NOICP
+ int x;
+
+ if (fc > 0)
+ dostop(); /* Stop all command files and end macros */
+#endif /* NOICP */
+
+#ifndef NOXFER
+ if (pktlog) {
+ *pktfil = '\0';
+ pktlog = 0;
+ zclose(ZPFILE);
+ }
+#endif /* NOXFER */
+ if (seslog) {
+ *sesfil = '\0';
+ setseslog(0);
+ zclose(ZSFILE);
+ }
+#ifdef TLOG
+ if (tralog) {
+ tlog(F100,"Transaction Log Closed","",0L);
+ *trafil = '\0';
+ tralog = 0;
+ zclose(ZTFILE);
+ }
+#endif /* TLOG */
+
+ debug(F100,"doclean calling dologend","",0);
+ dologend(); /* End current log record if any */
+#ifdef COMMENT
+ if (dialog) { /* If connection log open */
+ dialog = 0;
+ *diafil = '\0'; /* close it. */
+ zclose(ZDIFIL);
+ }
+#endif /* COMMENT */
+
+#ifndef NOICP
+#ifndef NOSPL
+ zclose(ZRFILE); /* READ and WRITE files, if any. */
+ zclose(ZWFILE);
+#ifndef NOXFER
+ zclose(ZIFILE); /* And other files too */
+ x = chkfn(ZOFILE); /* Download in progress? */
+ debug(F111,"doclean chkfn ZOFILE",filnam,x);
+ debug(F111,"doclean keep","",keep);
+ zclose(ZOFILE); /* Close output file */
+ if (x > 0 && !keep) { /* If it was being downloaded */
+ if (filnam[0])
+ x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */
+ debug(F111,"doclean download filename",filnam,x);
+ }
+#endif /* NOXFER */
+ zclose(ZSYSFN);
+ zclose(ZMFILE);
+
+ if (fc < 1) { /* RESETing, not EXITing */
+#ifdef DEBUG
+ if (deblog) { /* Close the debug log. */
+ *debfil = '\0';
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#endif /* DEBUG */
+ return;
+ }
+#endif /* NOSPL */
+#endif /* NOICP */
+
+#ifndef NOLOCAL
+ debug(F101,"doclean exithangup","",exithangup);
+ if (local && exithangup) { /* Close communication connection */
+ extern int haslock;
+ int x;
+
+ x = ttchk();
+ debug(F101,"doclean ttchk()","",x);
+#ifdef OS2ORUNIX
+ debug(F101,"doclean ttyfd","",ttyfd);
+#endif /* OS2ORUNIX */
+ if (x >= 0
+#ifdef OS2
+ || ttyfd != -1
+#else
+#ifdef UNIX
+ || haslock /* Make sure we get lockfile! */
+ || (!network && ttyfd > -1)
+#endif /* UNIX */
+#endif /* OS2 */
+ ) {
+ extern int wasclosed, whyclosed;
+ debug(F100,"doclean hanging up and closing","",0);
+ if (msgflg) {
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ printf("Closing %s...",ttname);
+ }
+#ifndef NODIAL
+ mdmhup(); /* Hangup the modem??? */
+#endif /* NODIAL */
+ ttclos(0); /* Close external line, if any */
+ if (msgflg) {
+ printf("OK\n");
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ }
+ if (wasclosed) {
+ whyclosed = WC_CLOS;
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_close",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ wasclosed = 0;
+ /* printf("ON_CLOSE DOCLEAN\n"); */
+ *(mactab[k].kwd) = NUL; /* See comment below */
+ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ wasclosed = 0;
+ }
+ }
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
+ local = dfloc; /* And default remote/local status */
+ }
+#ifdef DEBUG
+ else if (local) debug(F100,"doclean hangup/close skipped","",0);
+#endif /* DEBUG */
+#endif /* NOLOCAL */
+
+#ifdef NEWFTP
+ ftpbye(); /* If FTP connection open, close it */
+#endif /* NEWFTP */
+
+#ifdef IKSD
+ if (inserver)
+ ttclos(0); /* If IKSD, close socket */
+#endif /* IKSD */
+
+#ifndef NOSPL
+/*
+ If a macro named "on_exit" is defined, execute it. Also remove it from the
+ macro table, in case its definition includes an EXIT or QUIT command, which
+ would cause much recursion and would prevent the program from ever actually
+ EXITing.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_exit"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */
+ if (k >= 0) { /* If found, */
+#ifdef COMMENT
+ /* This makes a mess if ON_EXIT itself executes macros */
+ *(mactab[k].kwd) = NUL; /* poke its name from the table, */
+#else
+ /* Replace the keyword with something that doesn't wreck the */
+ /* order of the keyword table */
+ ckstrncpy(mactab[k].kwd,"on_exxx",8);
+#endif /* COMMENT */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+/*
+ Put console terminal back to normal. This is done here because the
+ ON_EXIT macro calls the parser, which meddles with console terminal modes.
+*/
+ conres(); /* Restore console terminal. */
+
+#ifdef COMMENT
+/* Should be no need for this, and maybe it's screwing things up? */
+ connoi(); /* Turn off console interrupt traps */
+#endif /* COMMENT */
+
+ /* Delete the Startup File if we are supposed to. */
+#ifndef NOICP
+ {
+ extern int DeleteStartupFile;
+ debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
+ if (DeleteStartupFile) {
+ int rc = zdelet(cmdfil);
+ debug(F111,"doclean zdelet",cmdfil,rc);
+ }
+ }
+#endif /* NOICP */
+ syscleanup(); /* System-dependent cleanup, last */
+}
+
+/* D O E X I T -- Exit from the program. */
+
+/*
+ First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
+ If second arg is -1, take 1st arg literally.
+ If second arg is not -1, work it into the exit code.
+*/
+VOID
+doexit(exitstat,code) int exitstat, code; {
+ extern int x_logged, quitting;
+#ifdef OS2
+ extern int display_demo;
+ extern int SysInited;
+#endif /* OS2 */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+ extern int krb4_autodel;
+#endif /* KRB4 */
+#ifdef KRB5
+ extern int krb5_autodel;
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef VMS
+ char envstr[64];
+ static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
+ static struct dsc$descriptor_s symval;
+#endif /* VMS */
+ int i;
+
+#ifdef DEBUG
+#ifdef USE_LUCACHE
+ extern long lucalls, luhits, xxhits, luloop;
+ extern int lusize;
+#endif /* USE_LUCACHE */
+#ifndef NOSPL
+ extern int cmdstats[];
+#endif /* NOSPL */
+
+ quitting++;
+
+#ifdef OS2
+ if ( !SysInited ) {
+ static int initing = 0;
+ if ( initing )
+ exit(253);
+ initing = 1;
+ sysinit();
+ }
+#endif /* OS2 */
+
+ if (deblog) {
+#ifdef USE_LUCACHE
+ debug(F101,"lookup cache size","",lusize);
+ debug(F101,"lookup calls ....","",lucalls);
+ debug(F101,"lookup cache hits","",luhits);
+ debug(F101,"lookup start hits","",xxhits);
+ debug(F101,"lookup loop iterations","",luloop);
+#endif /* USE_LUCACHE */
+#ifndef NOSPL
+ for (i = 0; i < 256; i++) {
+ if (cmdstats[i])
+ debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
+ }
+#endif /* NOSPL */
+ debug(F101,"doexit exitstat","",exitstat);
+ debug(F101,"doexit code","",code);
+ debug(F101,"doexit xitsta","",xitsta);
+ }
+#endif /* DEBUG */
+
+#ifdef CK_KERBEROS
+ /* If we are automatically destroying Kerberos credentials on Exit */
+ /* do it now. */
+#ifdef KRB4
+ if (krb4_autodel == KRB_DEL_EX) {
+ extern struct krb_op_data krb_op;
+ krb_op.version = 4;
+ krb_op.cache = NULL;
+ ck_krb4_destroy(&krb_op);
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (krb5_autodel == KRB_DEL_EX) {
+ extern struct krb_op_data krb_op;
+ extern char * krb5_d_cc;
+ krb_op.version = 5;
+ krb_op.cache = krb5_d_cc;
+ ck_krb5_destroy(&krb_op);
+ }
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (SysInited)
+ {
+#ifdef DCMDBUF
+ extern struct cmdptr *cmdstk;
+#else
+ extern struct cmdptr cmdstk[];
+#endif /* DCMDBUF */
+ extern int tt_status[];
+ extern int vmode;
+
+ /* If there is a demo screen to be displayed, display it */
+ if (display_demo) {
+ demoscrn(VCMD);
+ display_demo = 0;
+ }
+#ifndef KUI
+ /* This is going to be hideous. If we have a status line */
+ /* in the command window turn it off before we exit. */
+
+ if ( tt_status[VCMD] && vmode == VCMD ) {
+ domac("_clear_statusline","set command statusline off",
+ cmdstk[cmdlvl].ccflgs);
+ delmac("_clear_statusline",1);
+ RequestScreenMutex(-1);
+ VscrnIsDirty(vmode);
+ ReleaseScreenMutex();
+ while ( IsVscrnDirty(vmode) )
+ msleep(200);
+ RequestScreenMutex(-1);
+ ReleaseScreenMutex();
+ }
+#endif /* KUI */
+ DialerSend(OPT_KERMIT_EXIT,exitstat);
+#ifndef KUI
+ debug(F100,"doexit about to msleep","",0);
+
+ if ( isWin95() )
+ msleep(250);
+#endif /* KUI */
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && x_logged) {
+#ifndef NOSPL
+/*
+ If a macro named "on_logout" is defined, execute it. Also remove it from the
+ macro table, in case its definition includes an EXIT or QUIT command, which
+ would cause much recursion and would prevent the program from ever actually
+ EXITing.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_logout"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
+ if (k >= 0) { /* If found, */
+ *(mactab[k].kwd) = NUL; /* poke its name from the table, */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ zvlogout();
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+ debug(F100,"doexit about to doclean","",0);
+ doclean(1); /* Clean up most things */
+
+#ifdef VMS
+ if (code == -1)
+ code = 0; /* Since we set two different items */
+ sprintf(envstr,"%d", exitstat | code); /* SAFE */
+ symval.dsc$w_length = (int)strlen(envstr);
+ symval.dsc$a_pointer = envstr;
+ symval.dsc$b_class = DSC$K_CLASS_S;
+ symval.dsc$b_dtype = DSC$K_DTYPE_T;
+ i = 2; /* Store in global table */
+#ifdef COMMENT /* Martin Zinser */
+ LIB$SET_SYMBOL(&symnam, &symval, &i);
+#else
+ lib$set_symbol(&symnam, &symval, &i);
+#endif /* COMMENT */
+ if (exitstat == BAD_EXIT)
+ exitstat = SS$_ABORT | STS$M_INHIB_MSG;
+ if (exitstat == GOOD_EXIT)
+ exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
+#else /* Not VMS */
+ if (code != -1) /* Take 1st arg literally */
+ exitstat |= code;
+#endif /* VMS */
+
+#ifdef IKSD
+#ifdef IKSDB
+ debug(F101,"doexit ikdbopen","",ikdbopen);
+ if (ikdbopen && dbfp) { /* If IKSD database open */
+ int x;
+ x = freeslot(mydbslot); /* Free our slot... */
+ debug(F101,"doexit freeslot","",x);
+ fclose(dbfp); /* and close it. */
+ }
+#endif /* IKSDB */
+#endif /* IKSD */
+
+/* We have put this off till the very last moment... */
+
+#ifdef DEBUG
+ if (deblog) { /* Close the debug log. */
+ debug(F101,"C-Kermit EXIT status","",exitstat);
+ *debfil = '\0';
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ _exit(exitstat); /* Exit from C-Kermit (no matter what) */
+#else /* OS2 */
+ exit(exitstat); /* Exit from C-Kermit */
+#endif /* OS2 */
+}
+
+VOID
+bgchk() { /* Check background status */
+ if (bgset < 0) { /* They didn't type SET BACKGROUND */
+#ifdef VMS /* Set prompt flag based on */
+ pflag = !batch; /* what we detected at startup. */
+#else
+ pflag = !backgrd;
+#endif /* VMS */
+ } else { /* Otherwise SET BACKGROUND value */
+ pflag = (bgset == 0 ? 1 : 0);
+ }
+
+#ifndef NOICP
+ /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
+ if (!xcmdsrc)
+ msgflg = (pflag == 0) ? 0 : !quiet;
+ else msgflg = 0;
+#else
+ msgflg = 0;
+#endif /* NOICP */
+}
+
+/* Set console interrupts */
+
+VOID
+setint() { /* According to SET COMMAND INTERRUP */
+ int x = 0;
+ if (cmdint) x |= 1;
+ if (xsuspend) x |= 2;
+ debug(F101,"setint","",x);
+
+ switch (x) { /* Set the desired combination */
+ case 0: connoi(); break; /* No interrupts */
+ case 1: conint(trap,SIG_IGN); break;
+ case 2: conint(SIG_IGN,stptrap); break;
+ case 3: conint(trap,stptrap); break;
+ }
+ bgchk(); /* Check background status */
+}
+
+#ifdef DEBUG
+/* D E B U G -- Enter a record in the debugging log */
+
+/*
+ Call with a format, two strings, and a number:
+ f - Format, a bit string in range 0-7.
+ If bit x is on, then argument number x is printed.
+ s1 - String, argument number 1. If selected, printed as is.
+ s2 - String, argument number 2. If selected, printed in brackets.
+ n - Long int, argument 3. If selected, printed preceded by equals sign.
+
+ f=0 is special: print s1,s2, and interpret n as a char.
+
+ f=F011 (3) is also special; in this case s2 is interpeted as a counted
+ string that might contain NULs. n is the length. If n is negative, this
+ means the string has been truncated and ".." should be printed after the
+ first n bytes. NUL and LF bytes are printed as "<NUL>" and "<LF>".
+
+ Globals:
+ deblog: nonzero if debug log open.
+ debok: nonzero if ok to write entries.
+*/
+/*
+ WARNING: Don't change DEBUFL without changing sprintf() formats below,
+ accordingly.
+*/
+#define DBUFL 4000
+/*
+ WARNING: This routine is not thread-safe, especially when Kermit is
+ executing on multiple CPUs -- as different threads write to the same
+ static buffer, the debug statements are all interleaved. To be fixed
+ later...
+*/
+static char *dbptr = (char *)0;
+
+int
+#ifdef CK_ANSIC
+dodebug(int f, char *s1, char *s2, CK_OFF_T n)
+#else
+dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n;
+#endif /* CK_ANSIC */
+/* dodebug */ {
+ char *sp;
+ int len1, len2;
+ extern int debtim;
+#ifdef OS2
+ extern int SysInited;
+#endif /* OS2 */
+
+ if (!deblog || !debok)
+ return(0);
+
+#ifdef COMMENT
+ /* expensive... */
+ if (!chkfn(ZDFILE)) /* Debug log not open, don't. */
+ return(0);
+#endif /* COMMENT */
+ if (!dbptr) { /* Allocate memory buffer */
+ dbptr = malloc(DBUFL+4); /* This only happens once */
+ if (!dbptr) {
+ zclose(ZDFILE);
+ return(0);
+ }
+ }
+/*
+ This prevents infinite recursion in case we accidentally put a debug()
+ call in this routine, or call another routine that contains debug() calls.
+ From this point on, all returns from this return must be via goto xdebug,
+ which sets deblog back to 1.
+*/
+#ifdef OS2
+ if (SysInited) {
+ if (RequestDebugMutex(30000))
+ goto xdebug;
+ }
+#else /* OS2 */
+ deblog = 0; /* Prevent infinite recursion */
+#endif /* OS2 */
+
+ if (debtim) { /* Timestamp */
+ char *tb, tsbuf[48];
+ ztime(&tb);
+ ckstrncpy(tsbuf,tb,32);
+ if (ztmsec > -1L) {
+ sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
+ } else {
+ tsbuf[19] = ':';
+ tsbuf[20] = SP;
+ tsbuf[21] = NUL;
+ }
+ zsout(ZDFILE,tsbuf+11);
+ }
+ if (!s1) s1="(NULL)";
+ if (!s2) s2="(NULL)";
+
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+
+#ifdef COMMENT
+/*
+ This should work, but it doesn't.
+ So instead we'll cope with overflow via sprintf formats.
+ N.B.: UNFORTUNATELY, this means we have to put constants in the
+ sprintf formats.
+*/
+ if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
+ x = (int) strlen(s1) + (int) strlen(s2) + 18;
+ if (x > dbufl) { /* Longer than buffer? */
+ if (dbptr) /* Yes, free previous buffer */
+ free(dbptr);
+ dbptr = (char *) malloc(x + 2); /* Allocate a new one */
+ if (!dbptr) {
+ zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ } else {
+ dbufl = x;
+ sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
+ zsoutl(ZDFILE,dbptr);
+ }
+ }
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/* The aforementioned sprintf() formats were like this: */
+ if (n > 31 && n < 127)
+ sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
+ else if (n > 159 && n < 256)
+ sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
+ else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
+/*
+ But, naturally, it turns out these are not portable either, so now
+ we do the stupidest possible thing.
+*/
+#endif /* COMMENT */
+
+#ifdef BIGBUFOK
+/* Need to accept longer strings when debugging authenticated connections */
+ if (f == F010) {
+ if (len2 + 2 >= DBUFL) s2 = "(string too long)";
+ } else if (f != F011 && f != F100) {
+ if (len1 > 100) s1 = "(string too long)";
+ if (len2 + 101 >= DBUFL) s2 = "(string too long)";
+ }
+#else
+ if (f != F011) {
+ if (len1 > 100) s1 = "(string too long)";
+ if (len2 + 101 >= DBUFL) s2 = "(string too long)";
+ }
+#endif /* BIGBUFOK */
+
+ sp = dbptr;
+
+ switch (f) { /* Write log record according to format. */
+ case F000: /* 0 = print both strings, and n as a char. */
+ if (len2 > 0) {
+ if ((n > 31 && n < 127) || (n > 159 && n < 256))
+ sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
+ else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n);
+ } else {
+ if ((n > 31 && n < 127) || (n > 159 && n < 256))
+ sprintf(sp,"%s=%c\n",s1,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
+ else sprintf(sp,"%s=0x%lX\n",s1,(long)n);
+ }
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+
+ case F001: /* 1, "=n" */
+#ifdef COMMENT
+ /* This was never used */
+ sprintf(sp,"=%s\n",ckfstoa(n));
+#else
+ /* Like F111, but shows number n in hex */
+ ckmakxmsg(sp,DBUFL,
+ s1,
+ (*s1 ? ":" : ""),
+ s2,
+ (*s2 ? ":" : ""),
+ ckltox(n),
+ "\n",
+ NULL,NULL,NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+
+/*
+ This one was never used so (October 2000) we now use it like F011,
+ except in this case we treat s2 as NUL terminated.
+*/
+ case F010:
+ n = -debxlen;
+/*
+ This one treats n as the length of the string s2, which may contain NULs.
+ It's good for logging NUL-bearing data in the debug log.
+*/
+ case F011: {
+ int i, j, contd = 0;
+ char * p = s2, *pbuf = NULL; /* p = source pointer */
+ int m; /* pbuf = destination pointer */
+
+ if (f == F011) {
+ if (n < 0) { /* n = size of source */
+ n = 0 - n; /* Negative means to add "..." */
+ contd = 1;
+ }
+ } else {
+ int x, flag = 0;
+ x = strlen(s2);
+ if (n < 0) {
+ flag = 1;
+ n = 0 - n;
+ }
+ if (x < n)
+ n = x;
+ }
+ if (n == 0) /* 0 means do nothing */
+ goto xdebug;
+ m = DBUFL - 8; /* Get size for interpreted part */
+ if (n > m) /* Ensure requested size not too big */
+ n = m;
+ pbuf = dbptr; /* Construction pointer */
+ i = 0;
+ pbuf[i++] = '['; /* Interpret the string into it */
+ for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
+ if (*p == LF) {
+ if (i >= m-4)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'L';
+ pbuf[i++] = 'F';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p == CR) {
+ if (i >= m-4)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'C';
+ pbuf[i++] = 'R';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p == HT) {
+ if (i >= m-5)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'T';
+ pbuf[i++] = 'A';
+ pbuf[i++] = 'B';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p) {
+ pbuf[i++] = *p;
+ continue;
+ } else {
+ if (i >= m-5)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'N';
+ pbuf[i++] = 'U';
+ pbuf[i++] = 'L';
+ pbuf[i++] = '>';
+ continue;
+ }
+ }
+ if (i < m-2 && (*p || contd)) {
+ pbuf[i++] = '.';
+ pbuf[i++] = '.';
+ }
+ pbuf[i++] = ']';
+ pbuf[i] = NUL;
+ if (zsout(ZDFILE,s1) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+ if (zsoutl(ZDFILE,pbuf) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
+ }
+#endif /* CKSYSLOG */
+ }
+ break;
+
+ case F100: /* 4, "s1" */
+ if (zsoutl(ZDFILE,s1) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",s1,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F101: /* 5, "s1=n" */
+ sprintf(sp,"%s=%s\n",s1,ckfstoa(n));
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F110: /* 6, "s1[s2]" */
+ sprintf(sp,"%s[%s]\n",s1,s2);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F111: /* 7, "s1[s2]=n" */
+ sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n));
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ default:
+ sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ }
+ xdebug: /* Common exit point */
+#ifdef OS2
+ if (SysInited)
+ ReleaseDebugMutex();
+#else /* OS2 */
+ deblog = 1; /* Restore this */
+#endif /* OS2 */
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+dohexdump(CHAR *msg, CHAR *st, int cnt)
+#else
+dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
+#endif /* CK_ANSIC */
+/* dohexdump */ {
+ int i = 0, j = 0, k = 0;
+ char tmp[8];
+#ifdef OS2
+ extern int SysInited;
+#endif /* OS2 */
+
+ if (!deblog) return(0); /* If no debug log, don't. */
+ if (!dbptr) { /* Allocate memory buffer */
+ dbptr = malloc(DBUFL+1); /* This only happens once */
+ if (!dbptr) {
+ deblog = 0;
+ zclose(ZDFILE);
+ return(0);
+ }
+ }
+
+#ifdef OS2
+ if (SysInited) {
+ if (RequestDebugMutex(30000))
+ goto xdebug;
+ }
+#else /* OS2 */
+ deblog = 0; /* Prevent infinite recursion */
+#endif /* OS2 */
+
+ if (msg != NULL) {
+ ckmakxmsg(dbptr,
+ DBUFL,
+ "HEXDUMP: ",
+ (char *)msg,
+ " (",
+ ckitoa(cnt),
+ " bytes)\n",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ } else {
+ ckmakmsg(dbptr,
+ DBUFL,
+ "HEXDUMP: (",
+ ckitoa(cnt),
+ " bytes)\n",
+ NULL
+ );
+ zsout(ZDFILE,dbptr);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ }
+ for (i = 0; i < cnt; i++) {
+ dbptr[0] = '\0';
+ for (j = 0 ; (j < 16); j++) {
+ if ((i + j) < cnt)
+ sprintf(tmp,
+ "%s%02x ",
+ (j == 8 ? "| " : ""),
+ (CHAR) st[i + j]
+ );
+ else
+ sprintf(tmp,
+ "%s ",
+ (j == 8 ? "| " : "")
+ );
+ ckstrncat(dbptr,tmp,DBUFL+1);
+ }
+ ckstrncat(dbptr," ",DBUFL+1);
+ for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
+ sprintf(tmp,
+ "%s%c",
+ (k == 8 ? " " : ""),
+ isprint(st[i + k]) ? st[i + k] : '.'
+ );
+ ckstrncat(dbptr,tmp,DBUFL+1);
+ }
+ ckstrncat(dbptr,"\n",DBUFL+1);
+ i += j - 1;
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ } /* end for */
+
+
+ xdebug:
+#ifdef OS2
+ if (SysInited)
+ ReleaseDebugMutex();
+#else /* OS2 */
+ deblog = 1;
+#endif /* OS2 */
+ return(0);
+}
+#endif /* DEBUG */
+
+/* Session Log... */
+
+int tsstate = 0;
+
+VOID
+#ifdef OS2
+logchar(unsigned short c)
+#else /* OS2 */
+#ifdef CK_ANSIC
+logchar(char c)
+#else
+logchar(c) char c;
+#endif /* CK_ANSIC */
+#endif /* OS2 */
+/* logchar */ { /* Log character c to session log */
+ extern int slognul;
+ int oktolog = 0;
+#ifndef NOLOCAL
+ if (!seslog)
+ return;
+
+ if ((sessft != XYFT_T) || (
+#ifdef UNIX
+ c != '\r' &&
+#else
+#ifdef datageneral
+ c != '\r' &&
+#else
+#ifdef STRATUS
+ c != '\r' &&
+#else
+#ifdef AMIGA
+ c != '\r' &&
+#else
+#ifdef GEMDOS
+ c != '\r' &&
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* UNIX */
+#ifdef OSK
+ c != '\n' &&
+#else
+#ifdef MAC
+ c != '\n' &&
+#endif /* MAC */
+#endif /* OSK */
+ c != XON &&
+ c != XOFF))
+ oktolog = 1;
+ if (c == '\0' && !sessft) /* NUL in text mode */
+ if (slognul) oktolog = 1; /* only if padding (2009/10/22) */
+ if (!oktolog)
+ return;
+ if (slogts) { /* Log is timestamped */
+ if (tsstate == 0) { /* State = between-lines */
+ char * p; /* zstime() pointer */
+ char ts[48]; /* timestamp buffer */
+ ztime(&p); /* Get asctime() string */
+ ckstrncpy(ts,p,32); /* Make safe copy */
+ if (ztmsec > -1L) { /* Add msecs if we have them */
+ sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
+ } else {
+ ts[19] = ':';
+ ts[20] = SP;
+ ts[21] = NUL;
+ }
+ if (zsout(ZSFILE,&ts[11]) < 0)
+ goto xlogchar;
+ }
+ }
+ if (c == '\n') /* At end of line? */
+ tsstate = 0; /* yes */
+ else
+ tsstate = 1; /* no */
+ if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
+ goto xlogchar;
+ if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */
+ if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */
+ goto xlogchar;
+ }
+ return;
+
+ xlogchar:
+ conoll("");
+ conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
+ setseslog(0);
+ zclose(ZSFILE);
+#endif /* NOLOCAL */
+}
+
+VOID
+logstr(s, len) char * s; int len; { /* Log string to session log */
+#ifndef NOLOCAL
+ int n = 0;
+ if (!s)
+ return;
+ while (seslog && (n < len))
+ logchar(s[n++]);
+#endif /* NOLOCAL */
+}
+
+#ifdef CK_CURSES
+int
+ck_repaint() {
+ repaint = 1;
+ return(0);
+}
+
+#ifdef STRATUS
+/* VOS has curses but no tgetent() */
+int
+tgetent(s1, s2) char * s1, * s2; {
+ return(1);
+}
+#endif /* STRATUS */
+
+#ifdef VMS
+#ifdef __DECC
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* __DECC */
+#endif /* VMS */
+
+/*
+ There are three different ways to do fullscreen on VMS.
+ 1. Use the real curses library, VAXCCURSE.
+ 2. Use do-it-yourself code.
+ 3. Use the Screen Manager, SMG$.
+
+ Method 1 doesn't work quite right; you can't call endwin(), so once you've
+ started curses mode, you can never leave.
+
+ Method 2 doesn't optimize the screen, and so much more time is spent in
+ screen writes. This actually causes file transfers to fail because the
+ tty device input buffer can be overrun while the screen is being updated,
+ especially on a slow MicroVAX that has small typeahead buffers.
+
+ In the following #ifdef block, #define one of them and #undef the other 2.
+
+ So now let's try method 3...
+*/
+#ifdef VMS
+#define CK_SMG /* Screen Manager */
+#undef MYCURSES /* Do-it-yourself */
+#undef VMSCURSE /* VAXCCURSE library */
+#endif /* VMS */
+/*
+ But just before New Years, 2000, the SMG library seemed to break on
+ both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
+ So back to MYCURSES, which works fine.
+*/
+#ifdef VMS
+#undef CK_SMG
+#define MYCURSES
+#endif /* VMS */
+
+#ifdef MYCURSES
+#define stdscr 0
+#ifdef CK_WREFRESH
+#undef CK_WREFRESH
+#endif /* CK_WREFRESH */
+#endif /* MYCURSES */
+
+/* S C R E E N C -- Screen display function, uses curses */
+
+/* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
+
+/* Avoid conficts with curses.h */
+
+#ifdef QNX
+/* Same as ckcasc.h, but in a different radix... */
+#ifdef ESC
+#undef ESC
+#endif /* ESC */
+#endif /* QNX */
+
+#ifndef MYCURSES
+#undef VOID /* This was defined in ckcdeb.h */
+#endif /* MYCURSES */
+
+#undef BS /* These were defined in ckcasc.h */
+#undef CR
+#undef NL
+#undef SO
+#ifdef US
+#undef US
+#endif /* US */
+#undef SP /* Used in ncurses */
+#define CHR_SP 32 /* Use this instead */
+
+#ifdef VMS /* VMS fullscreen display */
+#ifdef MYCURSES /* Do-it-yourself method */
+extern int isvt52; /* From CKVTIO.C */
+#define printw printf
+#else
+#ifdef VMSCURSE /* VMS curses library VAXCCURSE */
+#include <curses.h>
+/* Note: Screen manager doesn't need a header file */
+#endif /* VMSCURSE */
+#endif /* MYCURSES */
+#else /* Not VMS */
+#ifdef MYCURSES /* Do-it-yourself method */
+#define isvt52 0 /* Used by OS/2, VT-100/ANSI always */
+#ifdef CKXPRINTF
+#define printw ckxprintf
+#else /* CKXPRINTF */
+#ifdef KUI
+#define printw Vscrnprintw
+#else /* KUI */
+#define printw printf
+#endif /* KUI */
+#endif /* CKXPRINTF */
+#else /* Use real curses */
+#ifdef CK_NCURSES /* or ncurses... */
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in ncurses.h */
+#endif /* CKXPRINTF */
+#include <ncurses.h>
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#else /* Not ncurses */
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in curses.h */
+#endif /* CKXPRINTF */
+#ifdef M_XENIX /* SCO XENIX... */
+#ifdef M_TERMCAP
+#undef M_TERMCAP
+#endif /* M_TERMCAP */
+#ifndef M_TERMINFO
+#define M_TERMINFO
+#endif /* M_TERMINFO */
+#endif /* M_XENIX */
+#ifdef RTAIX
+#undef NLS /* Avoid 'redeclaration of free'. */
+#endif /* RTAIX */
+#include <curses.h>
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#endif /* CK_NCURSES */
+#endif /* MYCURSES */
+#endif /* VMS */
+
+#ifdef BUG999
+_PROTOTYP(int tgetent,(char *, char *));
+_PROTOTYP(char *tgetstr,(char *, char **));
+_PROTOTYP(int tputs,(char *, int, int (*)()));
+_PROTOTYP(char *tgoto,(const char *, int, int));
+#endif /* BUG999 */
+
+#endif /* CK_CURSES */
+
+/* F X D I N I T -- File Xfer Display Initialization */
+
+#ifdef CK_CURSES
+#ifndef MYCURSES
+#ifndef CK_SMG
+static
+#ifdef CK_ANSIC
+/* Can't use VOID because of curses.h */
+void
+ck_termset(int);
+#else
+ck_termset();
+#endif /* CK_ANSIC */
+#endif /* CK_SMG */
+#endif /* MYCURSES */
+#endif /* CK_CURSES */
+
+#ifdef NOTERMCAP
+static int notermcap = 1;
+#else
+static int notermcap = 0;
+#endif /* NOTERMCAP */
+
+#ifndef NODISPLAY
+CKVOID
+fxdinit(xdispla) int xdispla; {
+#ifndef COHERENT
+#ifndef OS2
+#ifndef STRATUS
+ char *s;
+ int x, dummy;
+
+ debug(F101,"fxdinit xdispla","",xdispla);
+ debug(F101,"fxdinit fxd_inited","",fxd_inited);
+
+#ifdef IKSD
+#ifndef NOXFER
+ /* No curses for IKSD */
+ if (inserver) {
+ fdispla = XYFD_N;
+ return;
+ }
+ if (fxd_inited) /* Only do this once */
+ return;
+#endif /* NOXFER */
+#endif /* IKSD */
+
+ if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
+ if (xfrmsg) {
+ printf("%s\n",xfrmsg);
+ makestr(&xfrmsg,NULL);
+ }
+ }
+
+#ifdef CK_CURSES
+#ifdef VMS
+ /* Force BRIEF in Batch logs */
+ if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
+ xdispla = XYFD_B;
+#else
+ if (xdispla == XYFD_C || xdispla == 9999) {
+
+#ifdef DYNAMIC
+ if (!trmbuf) {
+/*
+ Allocate tgetent() buffer. Make it big -- some termcaps can be huge;
+ tgetent() merrily writes past the end of the buffer, causing core dumps
+ or worse.
+*/
+ trmbuf = (char *)malloc(TRMBUFL);
+ if (!trmbuf) {
+ notermcap = 1;
+ debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
+ fdispla = XYFD_S;
+ return;
+ }
+#ifdef COMMENT
+ debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
+ debug(F001,"fxdinit trmbuf","",trmbuf);
+ memset(trmbuf,'\0',(size_t)TRMBUFL);
+ debug(F100,"fxdinit memset OK","",0);
+#endif /* COMMENT */
+ }
+#endif /* DYNAMIC */
+
+ debug(F100,"fxdinit before getenv(TERM)","",0);
+ s = getenv("TERM");
+ debug(F110,"fxdinit after getenv(TERM)",s,0);
+ if (!s) s = "";
+ if (*s) {
+ debug(F110,"fxdinit before tgetent()",s,0);
+ x = tgetent(trmbuf,s);
+ debug(F111,"fxdinit tgetent",s,x);
+ } else {
+ x = 0;
+ notermcap = 1;
+ debug(F110,"fxdinit TERM null - no tgetent",s,0);
+ }
+ if (x < 1 && !quiet && !backgrd
+#ifdef VMS
+ && !batch
+#endif /* VMS */
+ ) {
+ printf("Warning: terminal type unknown: \"%s\"\n",s);
+#ifdef COMMENT
+ /* Confusing - nobody knows what this means */
+ printf("SCREEN command will use ANSI sequences.\n");
+#endif /* COMMENT */
+ if (local)
+ printf("Fullscreen file transfer display disabled.\n");
+ fdispla = XYFD_S;
+ }
+#ifndef MYCURSES
+#ifndef CK_SMG
+ ck_termset(x);
+#endif /* CK_SMG */
+#endif /* MYCURSES */
+ fxd_inited = 1;
+ }
+#endif /* CK_CURSES */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* COHERENT */
+}
+#endif /* NODISPLAY */
+
+#ifdef CK_CURSES
+#ifdef CK_SMG
+/*
+ Long section for Screen Manager starts here...
+ By William Bader.
+*/
+#include "ckvvms.h"
+#ifdef OLD_VMS
+#include <smgdef.h> /* use this on VAX C 2.4 */
+/* #include <smgmsg.h> */
+#else
+#include <smg$routines.h> /* Martin Zinser */
+#endif /* OLD_VMS */
+
+extern unsigned int vms_status; /* Used for system service return status */
+
+static long smg_pasteboard_id = -1; /* pasteboard identifier */
+static long smg_display_id = -1; /* display identifier */
+static int smg_open = 0; /* flag if smg current open */
+static int smg_inited = 0; /* flag if smg initialized */
+
+#ifdef COMMENT
+#define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0)
+
+#define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
+
+#define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id)
+
+#else /* Not COMMENT */
+
+#define clrtoeol() smg$erase_line(&smg_display_id, 0, 0)
+
+#define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0)
+
+#define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id)
+#endif /* COMMENT */
+
+#define clearok(curscr,ok) /* Let wrefresh() do the work */
+
+#define wrefresh(cursrc) touchwin(scr)
+
+static void
+move(row, col) int row, col; {
+ /* Change from 0-based for curses to 1-based for SMG */
+ if (!smg_open)
+ return;
+ ++row; ++col;
+ debug(F111,"VMS smg move",ckitoa(row),col);
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("move: smg$set_cursor_abs",
+ SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
+#else
+ CHECK_ERR("move: smg$set_cursor_abs",
+ smg$set_cursor_abs(&smg_display_id, &row, &col));
+#endif /* COMMENT */
+ debug(F101,"VMS smg move vms_status","",vms_status);
+}
+
+#ifdef VMS_V40
+#define OLD_VMS
+#endif /* VMS_V40 */
+#ifdef VMS_V42
+#define OLD_VMS
+#endif /* VMS_V42 */
+#ifdef VMS_V44
+#define OLD_VMS
+#endif /* VMS_V44 */
+
+static int
+initscr() {
+ int rows = 24, cols = 80;
+ int row = 1, col = 1;
+
+ debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
+
+ if (smg_pasteboard_id == -1) { /* Open the screen */
+#ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */
+ CHECK_ERR("initscr: smg$create_pasteboard",
+ smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
+#else
+ /* For VMS V5, not tested */
+ CHECK_ERR("initscr: smg$create_pasteboard",
+ smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
+#endif /* OLD_VMS */
+ }
+ debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
+ if (smg_pasteboard_id == -1) {
+ printf("?Error initializing fullscreen display\n");
+ fdispla = XYFD_S;
+ dpyinit();
+ return(0);
+ }
+ debug(F101,"VMS initscr smg_display_id","",smg_display_id);
+ if (smg_display_id == -1) { /* Create a display window */
+
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("initscr: smg$create_virtual_display",
+ SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
+ 0, 0, 0));
+
+ /* Connect the display window to the screen */
+ CHECK_ERR("initscr: smg$paste_virtual_display",
+ SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
+ &row,&col));
+#else
+ CHECK_ERR("initscr: smg$create_virtual_display",
+ smg$create_virtual_display(&rows, &cols, &smg_display_id,
+ 0, 0, 0));
+
+ /* Connect the display window to the screen */
+ CHECK_ERR("initscr: smg$paste_virtual_display",
+ smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
+ &row,&col));
+#endif /* COMMENT */
+ }
+ debug(F101,"VMS initscr smg_open A","",smg_open);
+ if (!smg_open) { /* Start a batch update */
+ smg_open = 1;
+#ifdef COMMENT
+ CHECK_ERR("initscr: smg$begin_pasteboard_update",
+ SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("initscr: smg$begin_pasteboard_update",
+ smg$begin_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+ debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
+ }
+ debug(F101,"VMS initscr smg_open B","",smg_open);
+ smg_inited = 1;
+ return(1);
+}
+
+static void
+refresh() {
+ debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
+
+ if (smg_open == 0 || smg_pasteboard_id == -1)
+ return;
+
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("refresh: smg$end_pasteboard_update",
+ SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+ CHECK_ERR("refresh: smg$begin_pasteboard_update",
+ SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("refresh: smg$end_pasteboard_update",
+ smg$end_pasteboard_update(&smg_pasteboard_id));
+ CHECK_ERR("refresh: smg$begin_pasteboard_update",
+ smg$begin_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+}
+
+static void
+endwin() {
+ if (!smg_open)
+ return;
+
+ smg_open = 0;
+
+#ifdef COMMENT
+ CHECK_ERR("endwin: smg$end_pasteboard_update",
+ SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("endwin: smg$end_pasteboard_update",
+ smg$end_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+
+ move(22, 0);
+
+#ifdef COMMENT
+/*
+ These calls clear the screen.
+ (convert routine calls to lowercase - Martin Zinser)
+*/
+ CHECK_ERR("endwin: smg$delete_virtual_display",
+ SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
+ smg_display_id = -1;
+
+ CHECK_ERR("endwin: smg$delete_pasteboard",
+ SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
+ smg_pasteboard_id = -1;
+#endif /* COMMENT */
+}
+
+#ifdef COMMENT
+/* DECC 6.2 screams bloody murder about printw ("not enough args") */
+/* but adding the following prototype only makes it holler louder. */
+#ifdef __DECC
+/* "varargs" prototype for printw */
+_PROTOTYP(static int printw,(char *, ...));
+#endif /* __DECC */
+#endif /* COMMENT */
+
+#ifdef __DECC
+#include <stdarg.h>
+_PROTOTYP(static void printw,(char *, ...));
+static void
+printw(char *str,...) {
+ char buf[255];
+ va_list ap;
+ $DESCRIPTOR(text_dsc, 0);
+ text_dsc.dsc$a_pointer=buf;
+ if (!smg_open)
+ return;
+ va_start(ap,str);
+ text_dsc.dsc$w_length = vsprintf(buf, str, ap);
+ va_end(ap);
+ CHECK_ERR("printw: smg$put_chars",
+ smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
+}
+#else
+static void
+printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
+ char *str;
+ long a1, a2, a3, a4, a5, a6, a7, a8;
+/* printw */ {
+ char buf[255];
+ $DESCRIPTOR(text_dsc, 0);
+ if (!smg_open)
+ return;
+ text_dsc.dsc$a_pointer=buf;
+ text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
+ CHECK_ERR("printw: smg$put_chars",
+ smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
+}
+#endif /* __DECC */
+
+#define CK_CURPOS
+int
+ck_curpos(row, col) {
+ debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg curpos smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
+ move(row - 1, col - 1); /* SMG is 0-based */
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+
+int
+ck_cls() {
+ debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg ck_cls smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ clear();
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+
+int
+ck_cleol() {
+ debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ clrtoeol();
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+#endif /* CK_SMG */
+
+#ifdef MYCURSES
+/*
+ Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
+ Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
+ By Terry Kennedy, St Peters College.
+
+ First, some stuff we can just ignore:
+*/
+
+static int
+touchwin(x) int x; {
+ return(0);
+}
+static int
+initscr() {
+ return(0);
+}
+static int
+refresh() {
+ return(0);
+}
+static int
+endwin() {
+ return(0);
+}
+
+/*
+ * Now, some stuff we need to do:
+ */
+
+_PROTOTYP( int move, (int, int) );
+#ifndef OS2
+int
+move(row, col) int row, col; {
+ if (isvt52)
+ printf("\033Y%c%c", row + 037, col + 037);
+ else
+ printf("\033[%d;%dH", row + 1, col + 1);
+ return(0);
+}
+
+int
+clear() {
+ move(0,0);
+ if (isvt52)
+ printf("\033J");
+ else
+ printf("\033[J");
+ return(0);
+}
+
+int
+clrtoeol() {
+ if (isvt52)
+ printf("\033K");
+ else
+ printf("\033[K");
+ return(0);
+}
+
+#define CK_CURPOS
+int
+ck_cls() {
+ return(clear());
+}
+
+int
+ck_cleol() {
+ return(clrtoeol());
+}
+
+int
+ck_curpos(row, col) int row, col; {
+ move(row, col);
+ return(0);
+}
+
+#else /* OS2 */
+/* Windows NT and Windows 95 do not provide ANSI emulation */
+/* Therefore we might as well not use it for OS/2 either */
+
+int
+move(row, col) int row, col; {
+#ifndef ONETERMUPD
+ SetCurPos(row, col);
+#endif /* ONETERMUPD */
+ lgotoxy( VCMD, col+1, row+1);
+ VscrnIsDirty(VCMD);
+ return(0);
+}
+
+int
+clear() {
+ viocell cell;
+ move(0,0);
+#ifdef ONETERMUPD
+ if (VscrnGetBufferSize(VCMD) > 0) {
+ VscrnScroll(VCMD, UPWARD, 0,
+ VscrnGetHeight(VCMD)-(1),
+ VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
+ cleartermscreen(VCMD);
+ }
+#else
+ cell.c = ' ';
+ cell.a = colorcmd;
+ WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
+#endif /* ONETERMUPD */
+ return(0);
+}
+
+int
+clrtoeol() {
+ USHORT row, col;
+ viocell cell;
+
+ cell.c = ' ';
+ cell.a = colorcmd;
+#ifndef ONETERMUPD
+ GetCurPos(&row, &col );
+ WrtNCell(cell, cmd_cols - col -1, row, col);
+#endif /* ONETERMUPD */
+ clrtoeoln(VCMD,CHR_SP);
+ return(0);
+}
+
+#define CK_CURPOS
+int
+ck_curpos(row, col) int row, col; {
+ move(row, col);
+ return(0);
+}
+
+int
+ck_cls() {
+ return(clear());
+}
+
+int
+ck_cleol() {
+ return(clrtoeol());
+}
+
+#endif /* OS2 */
+#endif /* MYCURSES */
+
+#ifndef NOTERMCAP
+#ifndef CK_CURPOS
+#define CK_CURPOS
+
+/* Termcap/Terminfo section */
+
+static char cur_cls[32] = { NUL, NUL };
+static char cur_cleol[32] = { NUL, NUL };
+static char cur_cm[64] = { NUL, NUL };
+static char tgsbuf[128] = { NUL, NUL };
+
+static
+#ifdef CK_ANSIC
+void
+#endif /* CK_ANSIC */
+ck_termset(x) int x; {
+ cur_cls[0] = NUL;
+ cur_cleol[0] = NUL;
+ cur_cm[0] = NUL;
+#ifdef tgetent
+ debug(F100,"tgetent is a macro","",0);
+#endif /* tgetent */
+#ifdef tgetstr
+ debug(F100,"tgetstr is a macro","",0);
+#endif /* tgetstr */
+#ifdef tputs
+ debug(F100,"tputs is a macro","",0);
+#endif /* tputs */
+#ifdef tgoto
+ debug(F100,"tgoto is a macro","",0);
+#endif /* tgoto */
+#ifdef NOTERMCAP
+ /* tgetstr() gets a segmentation fault on OSF/1 */
+ debug(F100,"ck_termset NOTERMCAP","",0);
+#else
+ if (notermcap) {
+ debug(F100,"ck_termset notermcap","",0);
+ return;
+ }
+ debug(F101,"ck_termset x","",x);
+ if (x > 0) {
+ char * bp;
+ bp = tgsbuf;
+ *bp = NUL;
+ debug(F110,"ck_termset calling tgetstr","cl",0);
+ if (tgetstr("cl", &bp)) { /* Get clear-screen code */
+ debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 32)
+ ckstrncpy(cur_cls,tgsbuf,32);
+ } else
+ return;
+ bp = tgsbuf;
+ if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */
+ debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 32)
+ ckstrncpy(cur_cleol,tgsbuf,32);
+ } else
+ return;
+ bp = tgsbuf;
+ if (tgetstr("cm", &bp)) { /* Get cursor-movement code */
+ debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 64)
+ ckstrncpy(cur_cm,tgsbuf,64);
+ } else
+ return;
+ }
+#endif /* NOTERMCAP */
+}
+
+#ifndef TPUTSFNTYPE
+#ifdef TPUTSISVOID
+#define TPUTSFNTYPE void
+#else
+#define TPUTSFNTYPE int
+#endif /* TPUTSISVOID */
+#endif /* TPUTSFNTYPE */
+
+#ifndef TPUTSARGTYPE
+#ifdef HPUX9
+#define TPUTSARGTYPE char
+#else
+#ifdef HPUX10
+#define TPUTSARGTYPE char
+#else
+#define TPUTSARGTYPE int
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* TPUTSARGTYPE */
+
+static TPUTSFNTYPE
+#ifdef CK_ANSIC
+ck_outc(TPUTSARGTYPE x)
+#else
+ck_outc(x) TPUTSARGTYPE x;
+#endif /* CK_ANSIC */
+{ /* To satisfy tputs() arg3 prototype */
+ int rc;
+ char c;
+ c = (char) x;
+ rc = (inserver) ? ttoc(c) : conoc(c);
+#ifndef TPUTSISVOID
+ return(rc);
+#endif /* TPUTSISVOID */
+}
+
+int
+ck_curpos(row, col) int row, col; {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cm[0]) { /* We don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
+ printf("\033[%d;%dH", row, col); /* Or default to ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ /* termcap/terminfo is 0-based */
+ tputs(
+#ifdef TPUTSARG1CONST
+ (const char *)
+#endif /* TPUTSARG1CONST */
+ tgoto(cur_cm,col-1,row-1),1,fn);
+ }
+ return(0);
+}
+
+int
+ck_cls() {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cls[0]) { /* If we don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ printf("\033[;H\033[2J"); /* Or default to ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ debug(F111,"ck_cls 2",cur_cls,fxd_inited);
+ tputs(cur_cls,cmd_rows,fn);
+ }
+ return(0);
+}
+
+int
+ck_cleol() {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cleol[0]) { /* If we don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ printf("\033[K"); /* Or use ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ tputs(cur_cleol,1,fn);
+ }
+ return(0);
+}
+#endif /* CK_CURPOS */
+#else
+static void
+ck_termset(x) int x; {
+ if (x) return;
+}
+#endif /* NOTERMCAP */
+
+#ifndef CK_CURPOS
+#define CK_CURPOS
+int
+ck_cls() {
+ printf("\033[;H\033[2J");
+ return(0);
+}
+
+int
+ck_cleol() {
+ printf("\033[K");
+ return(0);
+}
+
+int
+ck_curpos(row, col) int row, col; {
+ printf("\033[%d;%dH", row, col);
+ return(0);
+}
+#endif /* CK_CURPOS */
+
+
+#ifndef NOXFER
+static int cinit = 0; /* Flag for curses init'd */
+static int cendw = 0; /* endwin() was called */
+
+static
+#ifdef CK_ANSIC /* Because VOID used by curses.h */
+void
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+#endif /* CK_ANSIC */
+#ifdef CK_ANSIC /* Update % transfered and % bar */
+updpct(long old, long new)
+#else /* CK_ANSIC */
+updpct(old, new) long old, new;
+#endif /* CK_ANSIC */
+/* updpct */ {
+#ifdef COMMENT
+ int m, n;
+ move(CW_PCD,22);
+ printw("%ld", new);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ if (old > new) {
+ old = 0;
+ move(CW_PCD, 26);
+ clrtoeol();
+ }
+ m = old/2;
+ move(CW_PCD, 26 + m);
+ n = new / 2 - m;
+#ifndef OS2
+ while (n > 0) {
+ if ((m + 1) % 5 == 0)
+ printw("*");
+ else
+ printw("=");
+ m++;
+ n--;
+ }
+ if (new % 2 != 0) printw("-");
+ /* move(CW_PCD, 22+53); */
+#else /* OS2 */
+ while (n > 0) {
+ printw("%c", '\333');
+ m++; n--;
+ }
+ if (new % 2 != 0)
+ printw("%c", '\261');
+#endif /* OS2 */
+ }
+#endif /* CK_PCT_BAR */
+ /* clrtoeol(); */
+#else /* !COMMENT */
+#ifdef OS2
+#define CHAR1 '\333' /* OS2 - CP437 */
+#define CHAR2 '\261'
+#else
+#define CHAR1 '/' /* Default */
+#define CHAR2 '-'
+#endif /* OS2 */
+ debug(F101,"updpct old","",old);
+ debug(F101,"updpct new","",new);
+ move(CW_PCD,22);
+ printw("%-3ld", new); /* (was) printw("%ld", new); */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ int m, n;
+
+ if (old > new) {
+ old = 0 ;
+ move(CW_PCD, 26);
+ clrtoeol();
+ }
+ if (new <= 100L) {
+ m = old / 2;
+ n = new / 2 - m;
+ move(CW_PCD, 26+m);
+ while (n-- > 0)
+ printw("%c", CHAR1);
+ if (new % 2 != 0)
+ printw("%c", CHAR2);
+ }
+ }
+#endif /* CK_PCT_BAR */
+#endif /* COMMENT */
+}
+
+static CK_OFF_T old_tr = (CK_OFF_T)-1; /* Time remaining previously */
+
+static CK_OFF_T
+#ifdef CK_ANSIC
+shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar)
+#else
+ shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shoetl */ { /* Estimated time left in transfer */
+ CK_OFF_T tr; /* Time remaining, seconds */
+
+#ifdef GFTIMER
+ if (fsiz > 0L && cps > 0L)
+ tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
+ else
+ tr = (CK_OFF_T)-1;
+#else
+ tr = (fsiz > 0L && cps > 0L) ?
+ ((fsiz - howfar) / cps) :
+ (CK_OFF_T)-1;
+#endif /* GFTIMER */
+ move(CW_TR,22);
+ if (tr > (CK_OFF_T)-1) {
+ if (tr != old_tr) {
+ printw("%s",hhmmss(tr));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ }
+ } else {
+ printw("(unknown)");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ }
+ return(tr);
+}
+
+static long
+#ifdef CK_ANSIC
+shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar)
+#else
+shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shocps */ {
+#ifdef CPS_WEIGHTED
+ static CK_OFF_T oldffc = 0L;
+#endif /* CPS_WEIGHTED */
+#ifdef GFTIMER
+ CKFLOAT secs, xx;
+#else
+ CK_OFF_T secs, xx;
+#endif /* GFTIMER */
+
+#ifdef GFTIMER
+ xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */
+ gtv = gftimer();
+ if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
+ return(oldcps);
+ oldgtv = xx;
+#else
+ xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */
+ gtv = gtimer();
+ if ((gtv - oldgtv) < 1)
+ return(oldcps);
+ oldgtv = xx;
+#endif /* GFTIMER */
+
+#ifdef CPS_WEIGHTED
+ /* debug(F100,"SHOCPS: WEIGHTED","",0); */
+ if (gtv != oldgtv) { /* The first packet is ignored */
+ if (ffc < oldffc)
+ oldffc = ffc;
+ oldcps = cps;
+ if (oldcps && oldgtv >
+#ifdef GFTIMER
+ 1.0
+#else
+ 1
+#endif /* GFTIMER */
+ ) { /* The first second is ignored */
+/*
+ This version of shocps() produces a weighted average that some
+ people like, but most people find it disconcerting and bombard us
+ with questions and complaints about why the CPS figure fluctuates so
+ wildly. So now you only get the weighted average if you build the
+ program yourself with CPS_WEIGHTED defined.
+*/
+#ifndef CPS_VINCE
+#ifdef GFTIMER
+ cps = (long)((((CKFLOAT)oldcps * 3.0) +
+ (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
+#else
+ cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
+#endif /* GFTIMER */
+#else
+/* And an alternate weighting scheme from Vincent Fatica... */
+ cps = (3 *
+ ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
+ / 4;
+#endif /* CPS_VINCE */
+ } else {
+ /* No weighted average since there is nothing to weigh */
+#ifdef GFTIMER
+ cps = (long)(gtv != 0.0 ?
+ (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
+ (ffc - oldffc)) ;
+#else
+ cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
+#endif /* GFTIMER */
+ }
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"SHOCPS: pct ","",pct);
+ debug(F101,"SHOCPS: gtv ","",gtv);
+ debug(F101,"SHOCPS: oldgtv","",oldgtv);
+ debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv));
+ debug(F101,"SHOCPS: ffc ","",ffc);
+ debug(F101,"SHOCPS: oldffc","",oldffc);
+ debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
+ debug(F101,"SHOCPS: cps ","",cps);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ move(CW_CP,22);
+ printw("%ld", cps);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldffc = ffc;
+ }
+#else /* !CPS_WEIGHTED */
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"SHOCPS: NOT WEIGHTED","",0);
+ debug(F101,"SHOCPS: pct ","",pct);
+ debug(F101,"SHOCPS: gtv ","",gtv);
+ debug(F101,"SHOCPS: oldgtv ","",oldgtv);
+ debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv);
+ debug(F101,"SHOCPS: ffc ","",ffc);
+ debug(F101,"SHOCPS: oldffc ","",oldffc);
+ debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
+ debug(F101,"SHOCPS: cps ","",cps);
+ debug(F101,"SHOCPS: filcnt ","",filcnt);
+#ifdef GFTIMER
+ debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
+#endif /* GFTIMER */
+ }
+ debug(F101,"shocps gtv","",gtv);
+#endif /* DEBUG */
+#ifdef GFTIMER
+#endif /* COMMENT */
+ /* debug(F101,"shocps fpfsecs","",fpfsecs); */
+ secs = gtv - fpfsecs;
+ /* debug(F101,"shocps secs","",(long)secs); */
+ if (secs > 0.0) {
+ cps = (long)((CKFLOAT) ffc / secs);
+ /* debug(F101,"shocps cps","",cps); */
+ move(CW_CP,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%ld", cps);
+ clrtoeol();
+ }
+#else /* Not GFTIMER */
+ if ((secs = gtv - fsecs) > 0) {
+ cps = (secs < 1L) ? ffc : ffc / secs;
+ move(CW_CP,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%ld", cps);
+ clrtoeol();
+ }
+#endif /* GFTIMER */
+#endif /* CPS_WEIGHTED */
+
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+ old_tr = shoetl(old_tr, cps, fsiz, howfar);
+ return(cps);
+}
+
+static
+#ifdef CK_ANSIC /* Because VOID used by curses.h */
+void
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+#endif /* CK_ANSIC */
+scrft() { /* Display file type */
+ char xferstr[256];
+ xferstr[0] = NUL;
+ debug(F101,"scrft binary","",binary);
+ if (binary) {
+ switch(binary) {
+ case XYFT_L:
+ ckstrncpy(xferstr,"LABELED",256);
+ break;
+ case XYFT_I:
+ ckstrncpy(xferstr,"IMAGE",256);
+ break;
+ case XYFT_U:
+ ckstrncpy(xferstr,"BINARY UNDEFINED",256);
+ break;
+ case XYFT_M:
+ ckstrncpy(xferstr,"MACBINARY",256);
+ break;
+ case XYFT_X:
+ ckstrncpy(xferstr,"TENEX",256);
+ break;
+ default:
+ case XYFT_B:
+ ckstrncpy(xferstr,"BINARY",256);
+ break;
+ }
+#ifdef CK_RESEND
+ if (what & W_SEND && sendstart > 0L) {
+ if (sendmode == SM_PSEND) {
+ ckstrncat(xferstr, " / partial", 256);
+ } else if (sendmode == SM_RESEND) {
+ ckstrncat(xferstr, " / resend", 256);
+ }
+ } else if (what & W_RECV && rs_len > 0L) {
+ ckstrncat(xferstr, " / resend", 256);
+ }
+#endif /* CK_RESEND */
+ } else {
+
+#ifndef NOCSETS
+ ckstrncpy(xferstr,"TEXT",256);
+#ifdef NEWFTP
+#ifndef NOUNICODE
+ if (what & W_FTP) {
+ if (ftp_csx < 0)
+ ckstrncat(xferstr," (no translation)", 256);
+ else
+ ckmakxmsg(&xferstr[4],252,
+ " (",
+ fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
+ " => ",
+ fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
+ ")",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ } else
+#endif /* NOUNICODE */
+#endif /* NEWFTP */
+ if (tcharset == TC_TRANSP) {
+ ckstrncat(xferstr, " (no translation)", 256);
+ } else {
+ if (what & W_SEND) {
+ sprintf( &xferstr[strlen(xferstr)], /* safe */
+ " (%s => %s)",
+ fcsinfo[fcharset].keyword, /* built-in keywords */
+ tcsinfo[tcharset].keyword /* lengths are controlled */
+ );
+ } else {
+ sprintf( &xferstr[strlen(xferstr)], /* safe */
+ " (%s => %s)",
+ tcsinfo[tcharset].keyword, /* built-in keywords */
+ fcsinfo[fcharset].keyword); /* lengths controlled */
+ }
+ }
+#endif /* NOCSETS */
+ }
+ move(CW_TYP,22);
+ printw("%s", xferstr);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
+#endif /* K95G */
+#endif /* KUI */
+ return;
+}
+
+#ifdef CK_NEWTERM
+static FILE *ck_stdout = NULL;
+static int ck_fd = -1;
+#endif /* CK_NEWTERM */
+
+static long pct = 0L, oldpct = 0L, oldrtt = -1L;
+static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
+
+#ifdef NETCONN
+static char *netname[] = {
+ "none", /* 00 */
+ "TCP/IP", /* 01 TCP (Sockets) */
+ "TCP/IP", /* 02 TCP (Streams) */
+ "X.25", /* 03 SunLink X.24 */
+ "DECnet", /* 04 DECnet */
+ "VAX PSI", /* 05 VAX PSI */
+ "Named Pipes", /* 06 LAN Manager Named Pipe */
+ "X.25", /* 07 Stratus VOS X.25 */
+ "NetBIOS", /* 08 IBM NETBIOS */
+ "SuperLAT", /* 07 Meridian SuperLAT */
+ "File", /* 10 File */
+ "Command", /* 11 Subprocess (pipe) */
+ "DLL", /* 12 DLL does i/o */
+ "X.25", /* 13 IBM AIXLink X.25 */
+ "X.25", /* 14 HP-UX X.25 */
+ "PTY", /* 15 Pseudoterminal */
+ "SSH", /* 16 SSH */
+ "<ERROR>", /* 17 In case new types are added */
+ "<ERROR>", /* 18 but nobody remembers to update */
+ "<ERROR>", /* 19 this table ... */
+ NULL /* 20 */
+};
+static int nnetname = (sizeof(netname) / sizeof(char *));
+
+#endif /* NETCONN */
+
+#ifdef CK_ANSIC
+void
+screenc(int f, char c,CK_OFF_T n,char *s)
+#else
+CKVOID
+screenc(f,c,n,s)
+int f; /* argument descriptor */
+char c; /* a character or small integer */
+CK_OFF_T n; /* a long integer */
+char *s; /* a string */
+#endif /* CK_ANSIC */
+/* screenc() */ {
+#ifdef CK_SSL
+ extern int tls_active_flag, ssl_active_flag;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+ extern int ttnproto;
+#endif /* RLOGCODE */
+ static int q = 0;
+ static long fcnt = 0L; /* Number of files transferred */
+ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
+ static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */
+ static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */
+ static int pctlbl = 0L; /* Percent done vs Bytes so far */
+ long cps = 0L;
+
+ int net = 0;
+ int xnet = 0;
+ int ftp = 0;
+ int len; /* Length of string */
+ int errors = 0; /* Error counter */
+ int x; /* Worker */
+
+ debug(F101,"screenc cinit","",cinit);
+ debug(F101,"screenc cendw","",cendw);
+
+ if (!s) s = ""; /* Always do this. */
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
+ net = network || ftp;
+ xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
+
+ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
+ if (f == SCR_CW) { /* Close window, but it's not open */
+ ft_win = 0;
+ return;
+ }
+ debug(F111,"screenc A",s,f);
+ if (f == SCR_EM ||
+ (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
+ conoll(""); conoc('?'); conoll(s); return; /* Regular display */
+ }
+ }
+ if (cinit == 0) { /* Only call initscr() once */
+ char * s;
+ /* Check these now -- if they are defined but not numeric */
+ /* they can crash curses */
+ s = getenv("LINES");
+ if (s) if (!rdigits(s)) {
+ printf("?LINES variable not numeric: \"%s\".\n",s);
+ printf("(Fullscreen display disabled)\n");
+ fdispla = XYFD_S;
+ return;
+ }
+ s = getenv("COLUMNS");
+ if (s) if (!rdigits(s)) {
+ printf("?COLUMNS variable not numeric: \"%s\".\n",s);
+ printf("(Fullscreen display disabled)\n");
+ fdispla = XYFD_S;
+ return;
+ }
+ cendw = 1; /* New window needs repainting */
+#ifdef COMMENT
+ if (!initscr()) { /* Oops, can't initialize window? */
+/*
+ In fact, this doesn't happen. "man curses" says initscr() halts the
+ entire program if it fails, which is true on the systems where I've
+ tested it. It will fail if your terminal type is not known to it.
+ That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
+ terminal type is known before allowing a curses display.
+*/
+ fprintf(stderr,"CURSES INITSCR ERROR\r\n");
+ fdispla = XYFD_S; /* Fall back to CRT display */
+ return;
+ } else {
+ cinit++; /* Window initialized ok */
+ debug(F100,"CURSES INITSCR OK","",0);
+ }
+#else /* Save some memory. */
+#ifdef CK_NEWTERM
+ /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
+ System V curses seems to reserve the right to alter the buffering
+ on the output FILE* without restoring it. Fortunately System V
+ curses provides newterm(), an alternative to initscr(), that
+ allows us to specify explicitly the terminal type and input and
+ output FILE pointers. Thus we duplicate stdout, and let curses
+ have the copy. The original remains unaltered. Unfortunately,
+ newterm() seems to be particular to System V.
+ */
+ s = getenv("TERM");
+ if (ck_fd < 0) {
+ ck_fd = dup(fileno(stdout));
+ ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
+ }
+ debug(F100,"screenc newterm...","",0);
+
+/* NOTE: It might be necessary to do this with stdin too! */
+/* This would have been the case in FreeBSD 4.1 but they fixed the */
+/* problem by restoring the buffering of stdin before the final release. */
+/* (But T.E. Dickey says stdin is not buffered?) */
+
+ if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
+ fprintf(stderr,
+ "Fullscreen display not supported for terminal type: %s\r\n",s);
+ fdispla = XYFD_S; /* Use CRT instead */
+ return;
+ }
+ debug(F100,"screenc newterm ok","",0);
+#else
+ debug(F100,"screen calling initscr","",0);
+ initscr(); /* Initialize curses. */
+ debug(F100,"screen initscr ok","",0);
+#endif /* CK_NEWTERM */
+ cinit++; /* Remember curses was initialized. */
+#endif /* COMMENT */
+ }
+ ft_win = 1; /* Window is open */
+ if (repaint) {
+#ifdef CK_WREFRESH
+/*
+ This totally repaints the screen, just what we want, but we can only
+ do this with real curses, and then only if clearok() and wrefresh() are
+ provided in the curses library.
+*/
+#ifdef OS2
+ RestoreCmdMode();
+#else
+#ifdef QNX
+#ifndef QNX16
+ clearok(stdscr, 1); /* QNX doesn't have curscr */
+#endif /* QNX16 */
+ wrefresh(stdscr);
+#else
+ wrefresh(curscr);
+#endif /* QNX */
+#endif /* OS2 */
+#else /* No CK_WREFRESH */
+/*
+ Kermit's do-it-yourself method, works with all types of fullscreen
+ support, but does not repaint all the fields. For example, the filename
+ is lost, because it arrives at a certain time and never comes again, and
+ Kermit presently does not save it anywhere. Making this method work for
+ all fields would be a rather major recoding task, duplicating what curses
+ already does, and would add a lot of complexity and storage space.
+*/
+ cendw = 1;
+#endif /* CK_WREFRESH */
+ repaint = 0;
+ }
+ if (cendw) { /* endwin() was called previously */
+#ifdef VMS
+ initscr(); /* (or should have been!) */
+ clear();
+ touchwin(stdscr);
+ refresh();
+#else
+#ifdef QNX
+/*
+ In QNX, if we don't call initscr() here we core dump.
+ I don't have any QNX curses documentation, but other curses manuals
+ say that initscr() should be called only once per application, and
+ experience shows that on other systems, calling initscr() here generally
+ results in a core dump.
+*/
+ debug(F100,"screenc re-calling initscr QNX","",0);
+ initscr();
+ clear();
+ refresh();
+#ifdef COMMENT
+/*
+ But even so, second and subsequent curses displays are messed up.
+ Calling touchwin, refresh, etc, doesn't make any difference.
+*/
+ debug(F100,"screenc calling touchwin QNX","",0);
+ touchwin(stdscr);
+ debug(F100,"screenc calling refresh QNX","",0);
+ refresh();
+#endif /* COMMENT */
+
+#else /* All others... */
+ debug(F100,"screenc calling clear","",0);
+ clear();
+ debug(F100,"screenc clear ok","",0);
+#endif /* QNX */
+#endif /* VMS */
+ debug(F100,"screenc setup ok","",0);
+ debug(F100,"screenc doing first move","",0);
+ move(CW_BAN,0); /* Display the banner */
+ debug(F110,"screenc myhost",myhost,0);
+#ifdef TCPSOCKET
+ debug(F110,"screenc myipaddr",myipaddr,0);
+#endif /* TCPSOCKET */
+#ifdef HPUX1010
+ debug(F100,"screenc calling first printw...","",0);
+/* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
+#endif /* HPUX1010 */
+ if (myhost[0]) {
+#ifdef TCPSOCKET
+ if (!myipaddr[0]
+#ifdef OS2
+ /* We need to perform this test because on non-TCP/IP */
+ /* systems the call to getlocalipaddr() results in a */
+ /* DNS Lookup which takes several minutes to time out */
+ && net &&
+ (xnet == NET_TCPA || xnet == NET_TCPB
+#ifdef SSHBUILTIN
+ || xnet == NET_SSH
+#endif /* SSHBUILTIN */
+ )
+#endif /* OS2 */
+ )
+ getlocalipaddr();
+ if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
+ printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
+ else
+#endif /* TCPSOCKET */
+ printw("%s, %s",versio,(char *)myhost);
+ } else {
+ printw("%s",versio);
+ }
+#ifdef HPUX1010
+ debug(F100,"screenc first printw returns","",0);
+#endif /* HPUX1010 */
+ move(CW_DIR,3);
+ printw("Current Directory: %s",zgtdir());
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
+#endif /* K95G */
+#endif /* KUI */
+ if (net) {
+ move(CW_LIN,8);
+ printw("Network Host: %s",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "(unknown)") :
+#endif /* NEWFTP */
+ ttname
+ );
+ } else {
+ move(CW_LIN,0);
+ printw("Communication Device: %s",ttname);
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
+#endif /* K95G */
+#endif /* KUI */
+
+ if (net) {
+ move(CW_SPD,8);
+ printw("Network Type: ");
+ } else {
+ move(CW_SPD,1);
+ printw("Communication Speed: ");
+ }
+ move(CW_SPD,22); /* Serial speed or network type */
+ if (net) {
+#ifdef NETCONN
+ int secure = 0;
+ char * xname;
+ if (xnet > nnetname)
+ xname = "[ERROR]";
+ else
+ xname = netname[xnet];
+#ifdef NEWFTP
+ if (ftp) {
+ if (ftpissecure())
+ secure = 1;
+ } else
+#endif /* NEWFTP */
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ secure = 1;
+ }
+ if (secure) {
+#ifdef KUI
+#ifndef K95G
+ char buf[30];
+ sprintf(buf,"%s (SECURE)",xname);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) buf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s (SECURE)",xname);
+ } else {
+ printw("%s",xname);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) xname
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+#else
+ printw("(network)");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(network)"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#endif /* NETCONN */
+ } else {
+ if (speed < 0L)
+ speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880) {
+ printw("75/1200");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "75/1200"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ } else {
+ char speedbuf[64] ;
+ sprintf(speedbuf, "%ld", speed);
+ printw("%s",speedbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) speedbuf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ } else {
+ printw("unknown");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(unknown)"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ }
+ move(CW_PAR,14);
+ printw("Parity: %s",ftp ? "none" : parnam((char)parity));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ move(CW_TMO, 9); printw("RTT/Timeout:"); }
+#endif /* CK_TIMERS */
+ move(CW_TYP,11); printw("File Type:");
+ move(CW_SIZ,11); printw("File Size:");
+ move(CW_PCD, 8);
+ clrtoeol();
+ pctlbl = (what & W_SEND);
+ printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
+
+#ifdef XYZ_INTERNAL
+ move(CW_BAR, 1);
+ printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
+#endif /* XYZ_INTERNAL */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ oldpct = pct = 0;
+ move(CW_BAR,22);
+ printw(" ...10...20...30...40...50...60...70...80...90..100");
+ move(CW_BAR,22+56);
+ }
+#endif /* CK_PCT_BAR */
+ move(CW_TR, 1); printw("Estimated Time Left:");
+ move(CW_CP, 2); printw("Transfer Rate, CPS:");
+ move(CW_WS, 8); printw("Window Slots:%s",
+ ((protocol == PROTO_K) && !ftp) ?
+ "" : " N/A"
+ );
+ move(CW_PT, 9); printw("Packet Type:");
+ if (ftp || protocol != PROTO_K) {
+ move(CW_PT,22);
+ printw("%s", "N/A");
+ move(CW_PC, 11); printw("I/O Count:");
+ move(CW_PL, 10); printw("I/O Length:");
+ } else {
+ move(CW_PC, 8); printw("Packet Count:");
+ move(CW_PL, 7); printw("Packet Length:");
+ }
+#ifndef COMMENT
+ move(CW_PR, 9); printw("Error Count:");
+#else
+ move(CW_PR, 2); printw("Packet Retry Count:");
+#endif
+#ifdef COMMENT
+ move(CW_PB, 2); printw("Packet Block Check:");
+#endif /* COMMENT */
+ move(CW_ERR,10); printw("Last Error:");
+ move(CW_MSG, 8); printw("Last Message:");
+ if (xfrmsg) {
+ move(CW_MSG, 22); printw("%s",xfrmsg);
+ makestr(&xfrmsg,NULL);
+ }
+ move(CW_INT, 0);
+ if (!xfrint) {
+ printw("(Transfer interruption is disabled)");
+ } else {
+#ifdef CK_NEED_SIG
+ printw(
+"<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
+ dbchr(escape), dbchr(escape), dbchr(escape)
+ );
+ move(CW_INT + 1, 0);
+ printw(
+"<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
+ dbchr(escape), dbchr(escape)
+ );
+#else /* !CK_NEED_SIG */
+ move(CW_INT, 0);
+#ifdef OS2
+ if (protocol == PROTO_K) {
+ printw(
+"X to cancel file, Z to cancel group, <Enter> to resend last packet,"
+ );
+ }
+#else /* !OS2 */
+#ifdef VMS /* In VMS avoid bottom line */
+ printw(
+"X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
+ );
+#else
+ printw(
+"X to cancel file, Z to cancel group, <CR> to resend last packet,"
+ );
+#endif /* VMS */
+#endif /* OS2 */
+
+#ifndef VMS
+ move(CW_INT + 1, 0);
+ if (protocol == PROTO_K) {
+ printw(
+"E to send Error packet, ^C to quit immediately, ^L to refresh screen."
+ );
+ } else {
+ printw("^C to cancel file transfer.");
+ }
+#endif /* VMS */
+#endif /* CK_NEED_SIG */
+ }
+ refresh();
+ cendw = 0;
+ }
+ debug(F101,"SCREENC switch","",f);
+ debug(F000,"SCREENC c","",c);
+ debug(F101,"SCREENC n","",n);
+
+ len = strlen(s); /* Length of argument string */
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ oldpct = pct = 0L; /* Reset percents */
+#ifdef GFTIMER
+ gtv = (CKFLOAT) -1.0;
+ /* oldgtv = (CKFLOAT) -1.0; */
+#else
+ gtv = -1L;
+ /* oldgtv = -1L; */
+#endif /* GFTIMER */
+ oldwin = -1;
+ fsiz = (CK_OFF_T)-1; /* Invalidate previous file size */
+ move(CW_PCD,22); /* Erase percent done from last time */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(CW_SIZ,22); /* Erase file size from last time */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(CW_ERR,22); /* And last error message */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+#ifdef COMMENT
+#ifdef STREAMING
+ if (protocol == PROTO_K && streamok) {
+ move(CW_BAR, 1);
+#ifdef XYZ_INTERNAL
+ printw(" Kermit STREAMING:");
+#else
+ printw(" STREAMING:");
+#endif /* XYZ_INTERNAL */
+ }
+#endif /* STREAMING */
+#endif /* COMMENT */
+
+ if (what & W_SEND) { /* If we're sending... */
+#ifdef NEWFTP
+ if (what & W_FTP) { /* FTP */
+ move(CW_NAM,10);
+ printw(" FTP PUT:");
+ } else
+#endif /* NEWFTP */
+#ifdef CK_RESEND
+ switch (sendmode) { /* Kermit */
+ case SM_RESEND:
+ move(CW_NAM,10);
+ printw(" RESENDING:");
+ break;
+ default:
+ move(CW_NAM,10);
+ printw(" SENDING:");
+ break;
+ }
+#else
+ move(CW_NAM,10);
+ printw(" SENDING:");
+#endif /* CK_RESEND */
+
+ } else if (what & W_RECV) { /* If we're receiving... */
+#ifdef NEWFTP
+ if (what & W_FTP) { /* FTP */
+ move(CW_NAM,10);
+ printw(" FTP GET:");
+ } else {
+#endif /* NEWFTP */
+ move(CW_NAM,10);
+ printw(" RECEIVING:");
+#ifdef NEWFTP
+ }
+ } else if (what == (W_FTP|W_FT_DELE)) {
+ move(CW_NAM,10);
+ printw("FTP DELETE:");
+#endif /* NEWFTP */
+ } else { /* If we don't know... */
+ move(CW_NAM,10); /* (should never see this) */
+ printw(" File Name:");
+ }
+ move(CW_NAM,22); /* Display the filename */
+ if (len > 57) {
+ printw("%.55s..",s);
+ len = 57;
+ } else printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ q = len; /* Remember name length for later */
+ clrtoeol();
+ scrft(); /* Display file type (can change) */
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_AN: /* File as-name */
+ if (q + len + 4 < 58) { /* Will fit */
+ move(CW_NAM, 22 + q);
+ printw(" => %s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ } else { /* Too long */
+ move(CW_NAM, 22); /* Overwrite previous name */
+ q = 0;
+ if (len + 4 > 57) { /* wg15 */
+ printw(" => %.51s..",s); /* wg15 */
+ len = 53; /* wg15 */
+ } else printw(" => %s",s); /* wg15 */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ q += len + 4; /* Remember horizontal position */
+ clrtoeol();
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_FS: /* File size */
+ fsiz = n;
+ move(CW_SIZ,22);
+ if (fsiz > (CK_OFF_T)-1) {
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s",ckfstoa(n));
+ }
+ if (fsiz == -2L) {
+ printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT");
+ }
+ clrtoeol();
+#ifdef COMMENT
+ move(CW_PCD, 8);
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ clrtoeol();
+ printw("Percent Done:");
+ }
+#else
+ move(CW_PCD, 8);
+ clrtoeol();
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ printw("Percent Done:");
+ } else {
+ pctlbl = 0;
+ printw("Bytes So Far:");
+ }
+#endif /* COMMENT */
+ clrtoeol();
+ scrft(); /* File type */
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (spackets < 5) {
+ extern int sysindex;
+ extern struct sysdata sysidlist[];
+ /* Things that won't change after the 4th packet */
+ move(CW_PAR,22);
+ printw("%s",parnam((char)parity));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+#ifdef COMMENT
+ move(CW_PB, 22); /* Block check on this packet */
+ if (bctu == 4)
+ printw("B");
+ else
+ printw("%d",bctu);
+ clrtoeol();
+#endif /* COMMENT */
+ if (
+#ifdef NEWFTP
+ (ftp && (spackets == 1 || rpackets == 1)) ||
+#endif /* NEWFTP */
+ spackets == 4
+ ) {
+ move(CW_LIN,8);
+ if (
+#ifdef NEWFTP
+ ftp ||
+#endif /* NEWFTP */
+ ((protocol == PROTO_K) && (sysindex > -1))
+ ) {
+ if (net) {
+ move(CW_LIN,8);
+ printw("Network Host: %s (%s)",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "") :
+#endif /* NEWFTP */
+ ttname,
+#ifdef NEWFTP
+ ftp ? ftp_srvtyp :
+#endif /* NEWFTP */
+ sysidlist[sysindex].sid_name
+ );
+ } else {
+ move(CW_LIN,0);
+ printw("Communication Device: %s (remote host is %s)",
+ ttname,
+ sysidlist[sysindex].sid_name
+ );
+ }
+ clrtoeol();
+ }
+ }
+ }
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ long xx;
+ if (
+#ifdef STREAMING
+ streaming && oldwin != -2
+#else
+ 0
+#endif /* STREAMING */
+ ) {
+ move(CW_TMO, 22);
+ printw("00 / 00");
+ clrtoeol();
+ } else {
+ xx = (rttdelay + 500) / 1000;
+ if (xx != oldrtt || rcvtimo != oldtim) {
+ move(CW_TMO, 22);
+ printw("%02ld / %02d", xx, rcvtimo);
+ oldrtt = xx;
+ oldtim = rcvtimo;
+ clrtoeol();
+ }
+ }
+ }
+#endif /* CK_TIMERS */
+
+ x = (what & W_RECV) ? /* Packet length */
+ rpktl+(protocol==PROTO_K?1:0) :
+ spktl;
+ if (x != oldlen) { /* But only if it changed. */
+ move(CW_PL, 22);
+ printw("%d",x);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldlen = x;
+ }
+ move(CW_PC, 22); /* Packet count (always). */
+
+ printw("%d", (what & W_RECV) ? rpackets : spackets);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+
+ if (protocol == PROTO_K && !ftp) { /* Window slots */
+ char ws[16];
+ int flag;
+ flag = 0;
+#ifdef STREAMING
+ if (streaming) {
+ if (oldwin != -2) {
+ sprintf(ws,"STREAMING");
+ flag = 1;
+ oldwin = -2;
+ }
+ } else
+#endif /* STREAMING */
+ if (wcur != oldwin) {
+ sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
+ flag = 1;
+ oldwin = wcur;
+ }
+ if (flag) {
+ move(CW_WS, 22);
+ printw("%s", ws);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ }
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Retry count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtry = errors;
+ }
+ /* Sender's packet type */
+ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
+ char type[2];
+ sprintf(type, "%c",c);
+ move(CW_PT,22);
+ printw("%s", type);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtyp = c;
+ }
+ switch (c) { /* Now handle specific packet types */
+ case 'S': /* Beginning of transfer */
+ fcnt = fbyt = 0L; /* Clear counters */
+#ifdef GFTIMER
+ gtv = -1.0;
+#else /* GFTIMER */
+ gtv = -1L; /* And old/new things... */
+#endif /* GFTIMER */
+ oldpct = pct = 0L;
+ break;
+
+ case 'Z': /* or EOF */
+ debug(F101,"screenc SCR_PT Z pktnum","",n);
+ debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
+ debug(F101,"screenc SCR_PT Z pct","",pct);
+ case 'D': /* Data packet */
+ if (fsiz > 0L) { /* Show percent done if known */
+ oldpct = pct; /* Remember previous percent */
+ howfar = ffc;
+#ifdef CK_RESEND
+ if (what & W_SEND) /* Account for PSEND or RESEND */
+ howfar += sendstart;
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ /* Percent done, to be displayed... */
+ if (c == 'Z') {
+ if (!discard && !cxseen && !czseen) pct = 100L;
+ } else
+ pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
+ if (pct > 100L || /* Allow for expansion and */
+ (oldpct == 99L && pct < 0L)) /* other boundary conditions */
+ pct = 100L;
+ if (pct != oldpct) /* Only do this 100 times per file */
+ updpct(oldpct, pct);
+ } else {
+ move(CW_PCD,22);
+ printw("%s", ckfstoa(ffc));
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
+#endif /* K95G */
+#endif /* KUI */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ break;
+
+ case '%': /* Timeouts, retransmissions */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ oldtry = errors;
+ if (s) if (*s) {
+ move(CW_ERR,22);
+ printw("%s",s);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+#endif /* K95G */
+#endif /* KUI */
+ }
+ break;
+
+ case 'E': /* Error packet */
+#ifdef COMMENT
+ move(CW_ERR,22); /* Print its data field */
+ if (*s) {
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ clrtoeol();
+#endif /* COMMENT */
+ fcnt = fbyt = 0L; /* So no bytes for this file */
+ break;
+ case 'Q': /* Crunched packet */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ move(CW_ERR,22);
+ printw("Damaged Packet");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Damaged Packet"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ break;
+ case 'q': /* Ctrl-C or connection lost */
+ move(CW_MSG,22);
+ clrtoeol();
+ if (!s) s = "";
+ printw("%s", *s ? s : "User interruption or connection lost");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) s
+ );
+#endif /* K95G */
+#endif /* KUI */
+ break;
+ case 'T': /* Timeout */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ move(CW_ERR,22);
+ printw("Timeout %d sec",rcvtimo);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Timeout"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtry = errors;
+ }
+ break;
+ default: /* Others, do nothing */
+ break;
+ }
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_ST: /* File transfer status */
+ debug(F101,"screenc SCR_ST c","",c);
+ debug(F101,"screenc SCR_ST success","",success);
+ debug(F101,"screenc SCR_ST cxseen","",cxseen);
+#ifdef COMMENT
+ move(CW_PCD,22); /* Update percent done */
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl)
+ updpct(oldpct,100);
+ else
+ printw("%s", ckfstoa(ffc));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#endif /* K95G */
+#endif /* KUI */
+ pct = 100;
+ oldpct = 0;
+ } else if (fsiz > 0L) /* Not OK, update final percent */
+/*
+ The else part writes all over the screen -- howfar and/or fsiz have
+ been reset as a consequence of the not-OKness of the transfer.
+*/
+ if (pctlbl)
+ updpct(oldpct, (howfar * 100L) / fsiz);
+ clrtoeol();
+#else
+ if (c == ST_OK) { /* OK, print 100 % */
+ move(CW_PCD,22); /* Update percent done */
+ if (pctlbl) {
+ if (oldpct == 0) /* Switching from "bytes so far" */
+ clrtoeol(); /* to "percent done"... */
+ updpct(oldpct,100);
+ } else
+ printw("%s", ckfstoa(ffc));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = 100;
+ oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol();
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/* No, leave it there so they can read it */
+ move(CW_MSG,22); /* Remove any previous message */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+#endif /* COMMENT */
+
+ move(CW_TR, 22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+
+ switch (c) { /* Print new status message */
+ case ST_OK: /* Transfer OK */
+ fcnt++; /* Count this file */
+ if (what == (W_FTP|W_FT_DELE)) {
+ move(CW_MSG,22);
+ clrtoeol();
+ printw("Delete OK");
+ } else {
+ fbyt += ffc;
+ move(CW_MSG,22);
+ clrtoeol();
+ printw("Transfer OK");
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Transfer OK"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_DISC: /* Discarded */
+ move(CW_ERR,22);
+ printw("File discarded");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File discarded"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_INT: /* Interrupted */
+ move(CW_ERR,22);
+ printw("Transfer interrupted");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Transfer interrupted"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_SKIP: /* Skipped */
+ move(CW_ERR,22);
+ if (n > 0 && n < nskreason)
+ printw("File skipped (%s)",skreason[n]);
+ else
+ printw("File skipped");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File skipped"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_ERR: /* Error message */
+ move(CW_ERR,22);
+ if (!s) s = (char *)epktmsg;
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_REFU: /* Refused */
+ move(CW_ERR,22);
+ if (*s) {
+ char errbuf[64] ;
+ sprintf( errbuf, "Refused, %s", s ) ;
+ printw("%s", errbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
+#endif /* K95G */
+#endif /* KUI */
+ } else {
+ printw("Refused");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+#endif /* K95G */
+#endif /* KUI */
+ }
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_INC:
+ move(CW_ERR,22);
+ printw("Incomplete");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_MSG:
+ move(CW_MSG,22);
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+ return;
+
+ default: /* Bad call */
+ move(CW_ERR,22);
+ printw("*** screen() called with bad status ***");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+ (long) "*** screen() called with bad status ***" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh(); return;
+ }
+
+ case SCR_TC: { /* Transaction complete */
+ char msgbuf[128];
+ move(CW_CP,22); /* Overall transfer rate */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s", ckfstoa(tfcps));
+ clrtoeol();
+ if (success) {
+ move(CW_MSG,22); /* Print statistics in message line */
+ clrtoeol();
+ }
+ if (success) {
+ sprintf(msgbuf,
+ "SUCCESS. Files: %ld, Bytes: %s, %ld CPS",
+ filcnt - filrej,
+ ckfstoa(fbyt),
+ tfcps
+ );
+ printw("%s", msgbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) msgbuf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+
+ }
+ move(CW_TR, 1);
+ printw(" Elapsed Time: %s",hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_TR,
+ (long) hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(23,0); clrtoeol(); /* Clear instructions lines */
+ move(22,0); clrtoeol(); /* to make room for prompt. */
+ refresh();
+
+#ifdef GFTIMER
+ oldgtv = (CKFLOAT) -1.0;
+#else
+ oldgtv = -1L;
+#endif /* GFTIMER */
+
+#ifndef VMSCURSE
+ debug(F100,"screenc endwin A","",0);
+ endwin();
+#ifdef COMMENT
+/*
+ Why and when was this call to conres() added? It makes no sense,
+ and it breaks echoing on Solaris 8.
+*/
+#ifdef SOLARIS
+ conres();
+#endif /* SOLARIS */
+#endif /* COMMENT */
+#endif /* VMSCURSE */
+
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+ cendw = 1;
+ if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ ft_win = 0; /* Window closed. */
+ return;
+ }
+ case SCR_EM: /* Error packet (fatal) */
+ move (CW_ERR,22);
+ printw("FAILURE: %s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ if (xfrbel) bleep(BP_FAIL);
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh(); return;
+
+ case SCR_QE: /* Quantity equals */
+ case SCR_TU: /* Undelimited text */
+ case SCR_TN: /* Text delimited at start */
+ case SCR_TZ: /* Text delimited at end */
+ return; /* (ignored in fullscreen display) */
+
+ case SCR_MS: /* Message from Kermit partner */
+ move(CW_MSG,22);
+ printw("%s",s);
+ clrtoeol(); refresh(); return;
+
+ case SCR_XD: /* X-packet data */
+ pct = oldpct = 0;
+ move(CW_NAM,22);
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh(); return;
+
+ case SCR_CW: /* Close Window */
+ clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
+ refresh();
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+
+#ifndef VMSCURSE
+ debug(F100,"screenc endwin B","",0);
+ endwin();
+#endif /* VMSCURSE */
+ ft_win = 0; /* Flag that window is closed. */
+ cendw = 1; return;
+
+ case SCR_CD: /* Display current directory */
+ move(CW_DIR,22);
+ printw("%s", s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ default: /* Bad call */
+ move (CW_ERR,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "*** screen() called with bad function code ***"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ printw("*** screen() called with bad function code ***");
+ clrtoeol(); refresh(); return;
+ }
+}
+#endif /* CK_CURSES */
+
+#ifdef KUI
+#ifdef CK_ANSIC
+void
+screeng(int f, char c,long n,char *s)
+#else
+CKVOID
+screeng(f,c,n,s)
+int f; /* argument descriptor */
+char c; /* a character or small integer */
+long n; /* a long integer */
+char *s; /* a string */
+#endif /* CK_ANSIC */
+/* screeng() */ {
+#ifdef CK_SSL
+ extern int tls_active_flag, ssl_active_flag;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+ extern int ttnproto;
+#endif /* RLOGCODE */
+ static int q = 0;
+ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
+ static long fcnt = 0L; /* Number of files transferred */
+ static long fbyt = 0L; /* Total file bytes of all files transferred */
+ static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */
+ static int pctlbl = 0L; /* Percent done vs Bytes so far */
+ long cps = 0L;
+
+ int net = 0;
+ int xnet = 0;
+ int ftp = 0;
+ int len; /* Length of string */
+ int errors = 0; /* Error counter */
+ int x; /* Worker */
+
+ debug(F101,"screeng cinit","",cinit);
+ debug(F101,"screeng cendw","",cendw);
+
+ if (!s) s = ""; /* Always do this. */
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
+ net = network || ftp;
+ xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
+
+ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
+ if (f == SCR_CW) { /* Close window, but it's not open */
+ ft_win = 0;
+ return;
+ }
+ debug(F111,"screeng A",s,f);
+ if (f == SCR_EM ||
+ (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
+ conoll(""); conoc('?'); conoll(s); return; /* Regular display */
+ }
+ }
+ if (cinit == 0) { /* Only call initscr() once */
+ /* Check these now -- if they are defined but not numeric */
+ /* they can crash curses */
+ cendw = 1; /* New window needs repainting */
+ debug(F100,"screeng calling initscr","",0);
+ initscr(); /* Initialize curses. */
+ debug(F100,"screeng initscr ok","",0);
+ cinit++; /* Remember curses was initialized. */
+ }
+ ft_win = 1; /* Window is open */
+ if (repaint) {
+#ifdef CK_WREFRESH
+/*
+ This totally repaints the screen, just what we want, but we can only
+ do this with real curses, and then only if clearok() and wrefresh() are
+ provided in the curses library.
+*/
+ RestoreCmdMode();
+#else /* No CK_WREFRESH */
+/*
+ Kermit's do-it-yourself method, works with all types of fullscreen
+ support, but does not repaint all the fields. For example, the filename
+ is lost, because it arrives at a certain time and never comes again, and
+ Kermit presently does not save it anywhere. Making this method work for
+ all fields would be a rather major recoding task, duplicating what curses
+ already does, and would add a lot of complexity and storage space.
+*/
+ cendw = 1;
+#endif /* CK_WREFRESH */
+ repaint = 0;
+ }
+ if (cendw) { /* endwin() was called previously */
+ debug(F100,"screeng setup ok","",0);
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
+ (long) (
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "(unknown)") :
+#endif /* NEWFTP */
+ ttname) );
+
+ if (net) {
+#ifdef NETCONN
+ int secure = 0;
+ char * xname;
+ if (xnet > nnetname)
+ xname = "[ERROR]";
+ else
+ xname = netname[xnet];
+#ifdef NEWFTP
+ if (ftp) {
+ if (ftpissecure())
+ secure = 1;
+ } else
+#endif /* NEWFTP */
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ secure = 1;
+ }
+ if (secure) {
+ char buf[30];
+ sprintf(buf,"%s (SECURE)",xname);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) buf
+ );
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) xname
+ );
+ }
+#else
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(network)"
+ );
+#endif /* NETCONN */
+ } else {
+ if (speed < 0L)
+ speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880) {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "75/1200"
+ );
+ } else {
+ char speedbuf[64] ;
+ sprintf(speedbuf, "%ld", speed);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) speedbuf
+ );
+ }
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(unknown)"
+ );
+ }
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+ pctlbl = (what & W_SEND);
+ cendw = 0;
+ }
+ debug(F101,"SCREENC switch","",f);
+ debug(F000,"SCREENC c","",c);
+ debug(F101,"SCREENC n","",n);
+
+ len = strlen(s); /* Length of argument string */
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ oldpct = pct = 0L; /* Reset percents */
+#ifdef GFTIMER
+ gtv = (CKFLOAT) -1.0;
+ /* oldgtv = (CKFLOAT) -1.0; */
+#else
+ gtv = -1L;
+ /* oldgtv = -1L; */
+#endif /* GFTIMER */
+ oldwin = -1;
+ fsiz = (CK_OFF_T)-1L; /* Invalidate previous file size */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+ q = len; /* Remember name length for later */
+ scrft(); /* Display file type (can change) */
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_AN: /* File as-name */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_FS: /* File size */
+ fsiz = n;
+ if (fsiz > (CK_OFF_T)-1) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+ }
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ } else {
+ pctlbl = 0;
+ }
+ scrft(); /* File type */
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (spackets < 5) {
+ extern int sysindex;
+ extern struct sysdata sysidlist[];
+ /* Things that won't change after the 4th packet */
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+ if (
+#ifdef NEWFTP
+ (ftp && (spackets == 1 || rpackets == 1)) ||
+#endif /* NEWFTP */
+ spackets == 4
+ ) {
+ if (
+#ifdef NEWFTP
+ ftp ||
+#endif /* NEWFTP */
+ ((protocol == PROTO_K) && (sysindex > -1))
+ ) {
+ char msgbuf[128];
+ if (net) {
+ sprintf(msgbuf,"Network Host: %s (%s)",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "") :
+#endif /* NEWFTP */
+ ttname,
+#ifdef NEWFTP
+ ftp ? ftp_srvtyp :
+#endif /* NEWFTP */
+ sysidlist[sysindex].sid_name
+ );
+ } else {
+ sprintf(msgbuf,
+ "Communication Device: %s (remote host is %s)",
+ ttname,
+ sysidlist[sysindex].sid_name
+ );
+ }
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_LIN,
+ (long) msgbuf
+ );
+ }
+ }
+ }
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ long xx;
+ if (
+#ifdef STREAMING
+ streaming && oldwin != -2
+#else
+ 0
+#endif /* STREAMING */
+ ) {
+ char msgbuf[64];
+ sprintf(msgbuf,"00 / 00");
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_TMO,
+ (long) msgbuf
+ );
+ } else {
+ xx = (rttdelay + 500) / 1000;
+ if (xx != oldrtt || rcvtimo != oldtim) {
+ char msgbuf[64];
+ sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_TMO,
+ (long) msgbuf
+ );
+ oldrtt = xx;
+ oldtim = rcvtimo;
+ clrtoeol();
+ }
+ }
+ }
+#endif /* CK_TIMERS */
+
+ x = (what & W_RECV) ? /* Packet length */
+ rpktl+(protocol==PROTO_K?1:0) :
+ spktl;
+ if (x != oldlen) { /* But only if it changed. */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
+ oldlen = x;
+ }
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
+
+ if (protocol == PROTO_K && !ftp) { /* Window slots */
+ char ws[16];
+ int flag;
+ flag = 0;
+#ifdef STREAMING
+ if (streaming) {
+ if (oldwin != -2) {
+ sprintf(ws,"STREAMING");
+ flag = 1;
+ oldwin = -2;
+ }
+ } else
+#endif /* STREAMING */
+ if (wcur != oldwin) {
+ sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
+ flag = 1;
+ oldwin = wcur;
+ }
+ if (flag) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
+ }
+ }
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Retry count, if changed */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
+ oldtry = errors;
+ }
+ /* Sender's packet type */
+ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
+ char type[2];
+ sprintf(type, "%c",c);
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
+ oldtyp = c;
+ }
+ switch (c) { /* Now handle specific packet types */
+ case 'S': /* Beginning of transfer */
+ fcnt = fbyt = 0L; /* Clear counters */
+#ifdef GFTIMER
+ gtv = -1.0;
+#else /* GFTIMER */
+ gtv = -1L; /* And old/new things... */
+#endif /* GFTIMER */
+ oldpct = pct = 0L;
+ break;
+
+ case 'Z': /* or EOF */
+ debug(F101,"screeng SCR_PT Z pktnum","",n);
+ debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
+ debug(F101,"screeng SCR_PT Z pct","",pct);
+ case 'D': /* Data packet */
+ if (fsiz > 0L) { /* Show percent done if known */
+ oldpct = pct; /* Remember previous percent */
+ howfar = ffc;
+#ifdef CK_RESEND
+ if (what & W_SEND) /* Account for PSEND or RESEND */
+ howfar += sendstart;
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ /* Percent done, to be displayed... */
+ if (c == 'Z') {
+ if (!discard && !cxseen && !czseen) pct = 100L;
+ } else
+ pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
+ if (pct > 100L || /* Allow for expansion and */
+ (oldpct == 99L && pct < 0L)) /* other boundary conditions */
+ pct = 100L;
+ if (pct != oldpct) /* Only do this 100 times per file */
+ updpct(oldpct, pct);
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ break;
+
+ case '%': /* Timeouts, retransmissions */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR,
+ (long) errors
+ );
+ }
+ oldtry = errors;
+ if (s) if (*s) {
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+ }
+ break;
+
+ case 'E': /* Error packet */
+ if (*s) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+ }
+ fcnt = fbyt = 0L; /* So no bytes for this file */
+ break;
+ case 'Q': /* Crunched packet */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Damaged Packet"
+ );
+ break;
+ case 'q': /* Ctrl-C or connection lost */
+ if (!s) s = "";
+ if (!*s) s = "User interruption or connection lost";
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) s
+ );
+ break;
+ case 'T': /* Timeout */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Timeout"
+ );
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+ oldtry = errors;
+ }
+ break;
+ default: /* Others, do nothing */
+ break;
+ }
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_ST: /* File transfer status */
+ debug(F101,"screeng SCR_ST c","",c);
+ debug(F101,"screeng SCR_ST success","",success);
+ debug(F101,"screeng SCR_ST cxseen","",cxseen);
+#ifdef COMMENT
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl)
+ updpct(oldpct,100);
+ else
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+ pct = 100;
+ oldpct = 0;
+ } else if (fsiz > 0L) /* Not OK, update final percent */
+/*
+ The else part writes all over the screen -- howfar and/or fsiz have
+ been reset as a consequence of the not-OKness of the transfer.
+*/
+ if (pctlbl)
+ updpct(oldpct, (howfar * 100L) / fsiz);
+#else
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl) {
+ updpct(oldpct,100);
+ } else
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#ifdef COMMENT
+ pct = 100;
+ oldpct = 0;
+#endif /* COMMENT */
+ }
+#endif /* COMMENT */
+
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+
+ switch (c) { /* Print new status message */
+ case ST_OK: /* Transfer OK */
+ fcnt++; /* Count this file */
+ if (what == (W_FTP|W_FT_DELE)) {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Delete OK"
+ );
+ } else {
+ fbyt += ffc;
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Transfer OK"
+ );
+ }
+ return;
+
+ case ST_DISC: /* Discarded */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File discarded"
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_INT: /* Interrupted */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Transfer interrupted"
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_SKIP: { /* Skipped */
+ char errbuf[64] ;
+ if (n > 0 && n < nskreason)
+ sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
+ else
+ sprintf( errbuf, "File skipped" ) ;
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) errbuf
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+ }
+ case ST_ERR: /* Error message */
+ if (!s) s = (char *)epktmsg;
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_REFU: /* Refused */
+ if (*s) {
+ char errbuf[64] ;
+ sprintf( errbuf, "Refused, %s", s ) ;
+ KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+ }
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_INC:
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_MSG:
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+ return;
+
+ default: /* Bad call */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+ (long) "*** screen() called with bad status ***" );
+ return;
+ }
+
+ case SCR_TC: { /* Transaction complete */
+ char msgbuf[128];
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+ if (success) {
+ sprintf(msgbuf,
+ "SUCCESS. Files: %s, Bytes: %ld, %ld CPS",
+ filcnt - filrej,
+ ckfstoa(fbyt),
+ tfcps
+ );
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) msgbuf
+ );
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_TR,
+ (long) hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+
+#ifdef GFTIMER
+ oldgtv = (CKFLOAT) -1.0;
+#else
+ oldgtv = -1L;
+#endif /* GFTIMER */
+
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+ cendw = 1;
+ if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
+ ft_win = 0; /* Window closed. */
+ return;
+ }
+ case SCR_EM: /* Error packet (fatal) */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+ if (xfrbel) bleep(BP_FAIL);
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case SCR_QE: /* Quantity equals */
+ case SCR_TU: /* Undelimited text */
+ case SCR_TN: /* Text delimited at start */
+ case SCR_TZ: /* Text delimited at end */
+ return; /* (ignored in fullscreen display) */
+
+ case SCR_XD: /* X-packet data */
+ pct = oldpct = 0;
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+ return;
+
+ case SCR_CW: /* Close Window */
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+
+ ft_win = 0; /* Flag that window is closed. */
+ cendw = 1; return;
+
+ case SCR_CD: /* Display current directory */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ default: /* Bad call */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "*** screen() called with bad function code ***"
+ );
+ return;
+ }
+}
+#endif /* KUI */
+#endif /* MAC */
+
+#endif /* NOXFER */
+
+#ifndef CK_CURPOS
+/* Dummies for when cursor control is not supported */
+int
+ck_curpos(row, col) {
+ return(-1);
+}
+
+int
+ck_cls() {
+ return(-1);
+}
+
+int
+ck_cleol() {
+ return(-1);
+}
+#endif /* CK_CURPOS */
+
+#ifndef NOIKSD
+#ifdef IKSDB
+
+struct iksdbfld dbfld[] = {
+ /* Offset Length Type */
+ { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */
+ { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */
+ { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */
+ { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */
+ { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */
+ { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */
+ { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */
+ { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */
+ { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */
+ { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */
+ { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */
+ { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */
+ { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */
+ { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */
+ { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */
+ { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */
+};
+
+static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */
+static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */
+
+static char * updmode = /* Update mode for fopen() */
+#ifdef OS2
+ "r+b"
+#else
+#ifdef VMS
+ "r+b"
+#else
+ "r+"
+#endif /* VMS */
+#endif /* OS2 */
+ ;
+
+/* D B I N I T -- Initialize the IKSD database... */
+
+int
+dbinit() {
+ extern int dbinited;
+ int x = 0;
+ debug(F110,"dbinit dbdir 1",dbdir,0);
+ debug(F110,"dbinit dbfile 1",dbfile,0);
+ if (dbinited)
+ return(0);
+#ifdef OS2
+ if (!dbdir) {
+#ifdef NT
+ char * p = NULL;
+ if (!isWin95()) {
+ p = getenv("SystemRoot");
+ } else {
+ p = getenv("winbootdir");
+ if (!p) p = getenv("windir");
+ }
+ if (!p) p = "C:/";
+ dbdir = malloc(strlen(p)+2);
+ strcpy(dbdir,p); /* safe */
+ p = dbdir;
+ while (*p) {
+ if (*p == '\\')
+ *p = '/';
+ p++;
+ }
+ if (*(p-1) != '/' ) {
+ *p++ = '/';
+ *p = '\0';
+ }
+#else /* NT */
+ makestr(&dbdir,"C:/");
+#endif /* NT */
+ }
+#else /* OS2 */
+ if (!dbdir)
+ makestr(&dbdir,IK_DBASEDIR);
+#endif /* OS2 */
+
+ if (!dbfile) {
+ char * s = "";
+ x = strlen(dbdir);
+ if (dbdir[x-1] != '/') {
+ s = "/";
+ x++;
+ }
+ x += (int)strlen(IK_DBASEFIL);
+ dbfile = (char *)malloc(x+1);
+ sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
+ }
+ debug(F110,"dbinit dbdir 2",dbdir,0);
+ debug(F110,"dbinit dbfile 2",dbfile,0);
+ mypid = getpid(); /* Get my pid */
+ debug(F101,"dbinit mypid","",mypid);
+
+ if (!myhexip[0]) { /* Set my hex IP address */
+#ifdef TCPSOCKET
+ extern unsigned long myxipaddr;
+ if (getlocalipaddr() > -1) {
+ myip = myxipaddr;
+ sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
+ } else
+#endif /* TCPSOCKET */
+ ckstrncpy(myhexip,"00000000",9);
+ }
+ debug(F111,"dbinit myip",myhexip,myip);
+ if (!peerhexip[0]) { /* Get peer's hex IP address */
+#ifdef TCPSOCKET
+ extern unsigned long peerxipaddr;
+ if (ckgetpeer()) {
+ peerip = peerxipaddr;
+ sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
+ debug(F111,"dbinit peerip",peerhexip,peerip);
+ } else {
+ debug(F101,"dbinit ckgetpeer failure","",errno);
+ ckstrncpy(peerhexip,"00000000",9);
+ }
+#else
+ ckstrncpy(peerhexip,"00000000",9);
+#endif /* TCPSOCKET */
+ }
+ debug(F111,"dbinit peerip",peerhexip,peerip);
+ debug(F101,"dbinit dbenabled","",dbenabled);
+ if (dbenabled && inserver) {
+ mydbslot = getslot();
+ debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
+ if (ikdbopen) dbinited = 1;
+ }
+ return(0);
+}
+
+/* U P D S L O T -- Update slot n */
+
+/*
+ Opens the database if necessary, seeks to slot n, writes current record
+ and adds current time to last-update field. n is the record sequence number
+ (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success.
+*/
+int
+updslot(n) int n; { /* Update our slot */
+ int rc = 0;
+ CK_OFF_T position;
+
+ debug(F111,"updslot","ikdbopen",ikdbopen);
+ if (!ikdbopen) /* Not if not ok */
+ return(0);
+ if (!dbfp) { /* Open database if not open */
+ dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */
+ if (!dbfp) {
+ debug(F110,"updslot fopen failed",dbfile,0);
+ ikdbopen = 0;
+ return(-1);
+ }
+ }
+ /* debug(F111,"updslot dbfile",dbfile,dbfp); */
+ position = n * DB_RECL;
+ if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */
+ debug(F111,"updslot fseek failed",dbfile,mydbseek);
+ ikdbopen = 0;
+ rc = -1;
+ } else {
+ /* Update the update time */
+ strncpy(&dbrec[dbfld[db_LASTU].off],
+ ckdate(),
+ dbfld[db_LASTU].len
+ );
+ if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
+ debug(F110,"updslot fwrite failed",dbfile,0);
+ ikdbopen = 0;
+ rc = -1;
+ } else { /* Flush the write */
+ fflush(dbfp);
+ }
+ }
+ return(rc);
+}
+
+/* I N I T S L O T -- Initialize slot n with my info */
+
+int
+initslot(n) int n; { /* Initialize slot */
+ int k;
+#ifdef TCPSOCKET
+ extern unsigned long peerxipaddr;
+#endif /* TCPSOCKET */
+
+ debug(F101,"initslot","",n);
+
+#ifdef USE_MEMCPY
+ memset(dbrec,32,DB_RECL);
+#else
+ for (k = 0; k < DB_RECL; k++)
+ dbrec[k] = '\040';
+#endif /* USE_MEMCPY */
+
+ myflags = DBF_INUSE; /* Set in-use flag */
+ mystate = W_NOTHING;
+ myatype = 0L;
+ myamode = 0L;
+
+ k = dbfld[db_FLAGS].len; /* Length of flags field */
+ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
+
+ k = dbfld[db_ATYPE].len;
+ strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
+
+ k = dbfld[db_AMODE].len;
+ strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
+
+ k = dbfld[db_STATE].len;
+ strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
+
+ k = dbfld[db_SADDR].len;
+ strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
+
+#ifdef TCPSOCKET
+ ckgetpeer();
+ k = dbfld[db_CADDR].len;
+ strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
+#else
+ k = dbfld[db_CADDR].len;
+ strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
+#endif /* TCPSOCKET */
+
+ k = dbfld[db_MYPID].len;
+ strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
+
+ k = dbfld[db_START].len;
+ strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
+
+ k = dbfld[db_ULEN].len;
+ strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
+
+ k = dbfld[db_DLEN].len;
+ strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
+
+ k = dbfld[db_ILEN].len;
+ strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
+
+ strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
+ return(updslot(n));
+}
+
+int
+slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
+ int k, l1, l2, l3, z;
+ mystate = x;
+ debug(F101,"slotstate ikdbopen","",ikdbopen);
+ if (!ikdbopen)
+ return(-1);
+ if (!s1) s1 = "";
+ l1 = strlen(s1);
+ if (!s2) s2 = "";
+ l2 = strlen(s2);
+ if (!s3) s3 = "";
+ l3 = strlen(s3);
+ strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
+ k = dbfld[db_ILEN].len;
+ z = l1 + l2 + l3 + 2;
+ if (z > dB_INFO)
+ z = dB_INFO;
+ strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
+ k = dbfld[db_INFO].len;
+ z = dbfld[db_INFO].off;
+ if (l1 <= k) {
+ lset(&dbrec[z],s1,l1+1,32);
+ z += l1+1;
+ k -= l1+1;
+ if (l2 <= k) {
+ lset(&dbrec[z],s2,l2+1,32);
+ z += l2+1;
+ k -= l2+1;
+ if (l3 <= k)
+ lset(&dbrec[z],s3,k,32);
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ char buf[128];
+ int i;
+ strncpy(buf,&dbrec[DB_INFO],127);
+ buf[127] = NUL;
+ for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
+ debug(F111,"slotstate",buf,mystate);
+ }
+#endif /* DEBUG */
+ z = updslot(mydbslot);
+ debug(F101,"slotstate updslot","",z);
+ return(z);
+}
+
+int
+slotdir(s1,s2) char * s1, * s2; { /* Update current directory */
+ int k, len1, len2;
+ if (!ikdbopen)
+ return(-1);
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+ k = dbfld[db_DLEN].len;
+ strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
+ k = dbfld[db_DIR].len;
+ if (len1 > 0) {
+ lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
+ lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
+ } else {
+ lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
+ }
+ return(updslot(mydbslot));
+}
+
+/* F R E E S L O T -- Free slot n */
+
+int
+freeslot(n) int n; {
+ int k;
+ if (!ikdbopen)
+ return(0);
+ dbflags = 0L;
+ if (n == mydbslot) {
+ dbflags = myflags & ~DBF_INUSE;
+ dbflags &= ~DBF_LOGGED;
+ }
+ k = dbfld[db_FLAGS].len;
+ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
+ return(updslot(n));
+}
+
+/* G E T S L O T -- Find a free database slot; returns slot number */
+
+#ifdef UNIX
+#include <fcntl.h> /* For creat() */
+#endif /* UNIX */
+
+int
+getslot() { /* Find a free slot for us */
+ FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */
+ char idstring[64]; /* PID string buffer (decimal) */
+ char pidbuf[64], * s;
+ int j, k, n, x, rc = -1;
+ int lockfd, tries, haveslot = 0;
+ long lockpid;
+ CK_OFF_T i;
+ /* char ipbuf[17]; */
+
+ if (!myhexip[0]) /* Set my hex IP address if not set */
+ ckstrncpy((char *)myhexip,"7F000001",33);
+ sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
+ debug(F110,"getslot idstring", idstring, 0);
+
+ /* Make temporary lockfile name IP.PID (hex.hex) */
+ /* This should fit in 14 chars -- huge PIDs are usually not possible */
+ /* on 14-char filename systems. */
+
+ sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
+ debug(F110,"getslot tempfile",tmplck,0);
+
+ /* Make a temporary file */
+
+ lockfd = creat(tmplck, 0600); /* BUT THIS ISN'T PORTABLE */
+ if (lockfd < 0) {
+ debug(F111,"getslock temp lockfile create failure", tmplck, errno);
+ return(-1);
+ }
+ /* Write my (decimal) PID into the temp file */
+
+ write(lockfd,idstring,(int)strlen(idstring));
+ if (close(lockfd) < 0) { /* Close lockfile */
+ debug(F101,"getslot error closing temp lockfile", "", errno);
+ return(-1);
+ }
+ sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
+ debug(F110,"getslot lockfile",lcknam,0);
+
+ rfp = fopen(lcknam,"r"); /* See if lockfile exists */
+ if (rfp) { /* If so... */
+ rset(pidbuf,"",64,0);
+ x = fread(pidbuf,1,63,rfp); /* Read ID string from it */
+ fclose(rfp); /* and close it quickly */
+ debug(F110,"getslot lock exists",pidbuf,0);
+ if (x > 0) { /* If we have a PID, check it */
+ char * s = pidbuf;
+ while (*s) {
+ if (islower(*s)) *s = toupper(*s);
+ if (*s == ':') {
+ *s = NUL;
+ debug(F110,"getslot lock IP",pidbuf,0);
+ debug(F110,"gteslot my IP",myhexip,0);
+ if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
+ lockpid = atol(s+1); /* Yes, now get PID */
+ debug(F101,"getslot lockpid","",lockpid);
+
+ /* Check if PID lockpid on this computer is alive */
+ x = zchkpid(lockpid);
+ if (!x) {
+ debug(F100,"getslot PID stale,removing lock","",0);
+ unlink(lcknam);
+ }
+ break;
+ }
+ }
+ s++;
+ }
+ } else {
+ debug(F111,"getslot lockfile open failure",lcknam,errno);
+ }
+ }
+ /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
+
+ for (tries = IK_LCKTRIES; tries > 0; tries--) {
+ if (zrename(tmplck,lcknam) == 0)
+ break;
+ debug(F101,"getslot database locked by pid", "", dbpid);
+ sleep(IK_LCKSLEEP);
+ }
+ if (tries < 1) { /* Couldn't */
+ debug(F110,"getslot create lock failure",lcknam,0);
+ return(-1);
+ }
+ /* Have lock, open database */
+
+ debug(F110,"getslot has lock",lcknam,0); /* Have lock */
+
+ if (!dbfile)
+ return(-1);
+
+ /* If database doesn't exist, create it. */
+
+ debug(F110,"getslot dbfile",dbfile,0);
+ if (zchki(dbfile) < 0) {
+ debug(F110,"getslot creating new database",dbfile,0);
+ x = creat(dbfile,0660);
+ if (x < 0) {
+ debug(F111,"getslot creat() failed", dbfile, errno);
+ goto xslot;
+ }
+ close(x);
+ }
+ dbfp = fopen(dbfile,updmode); /* Open it in update mode */
+ if (!dbfp) {
+ debug(F111,"getslot fopen failed",dbfile,errno);
+ goto xslot;
+ }
+ /* Now find a free (or new) slot... */
+
+ dblastused = 0L; /* Seek pointer to last record inuse */
+ mydbseek = 0L; /* Seek pointer for my record */
+
+ /* Quickly read the whole database; n = record counter, i = seek pointer */
+
+ for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
+ x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
+ if (x < 1) /* EOF not caught by feof() */
+ break;
+#ifndef NOFTRUNCATE
+ if (x != DB_RECL) { /* Watch out for trailing junk */
+ debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */
+#ifdef COHERENT
+ chsize(fileno(dbfp),i);
+#else
+ ftruncate(fileno(dbfp),(CK_OFF_T)i);
+#endif /* COHERENT */
+ x = 0;
+ CKFSEEK(dbfp,i,0);
+ break;
+ }
+#endif /* NOFTRUNCATE */
+ debug(F101,"getslot record","",n);
+ k = dbfld[db_FLAGS].off;
+ j = dbfld[db_FLAGS].len;
+ dbflags = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbflags","",dbflags);
+ k = dbfld[db_MYPID].off;
+ j = dbfld[db_MYPID].len;
+ dbpid = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbpid","",dbpid);
+ k = dbfld[db_SADDR].off;
+ j = dbfld[db_SADDR].len;
+ dbip = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbip","",dbip);
+
+ if (dbflags & DBF_INUSE) { /* Remember last slot in use */
+ x = 0; /* Make sure it's REALLY in use */
+ if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
+ x = 1;
+ debug(F101,"getslot record pid","",dbpid);
+ } else { /* Or for stale PID */
+ x = zchkpid(dbpid);
+ debug(F101,"getslot zchkpid()","",x);
+ }
+ if (!x) { /* Bogus record */
+ x = freeslot(n);
+ debug(F101,"getslot stale record pid: freeslot()","",x);
+ if (x > -1 && !haveslot)
+ dbflags = 0;
+ } else { /* It's really in use */
+ dblastused = i;
+ }
+ }
+ if (!haveslot) { /* If I don't have a slot yet */
+ if (!(dbflags & DBF_INUSE)) { /* Claim this one */
+ debug(F101,"getslot free slot", "", n);
+ haveslot = 1;
+ mydbseek = i;
+ mydbslot = n; /* But keep going... */
+ }
+ }
+ }
+ /* Come here with i == seek pointer to first record after eof */
+
+ if (!haveslot) { /* Found no free slot so add to end */
+ debug(F101,"getslot new slot","",n);
+ haveslot = 1;
+ mydbseek = i;
+ mydbslot = n;
+ }
+ ikdbopen = 1; /* OK to make database entries */
+ debug(F101,"getslot records","",n);
+ debug(F101,"getslot dblastused","",dblastused);
+ debug(F101,"getslot i","",i);
+
+ /* Trim stale records from end */
+
+#ifndef NOFTRUNCATE
+ if (i > dblastused+DB_RECL) {
+ debug(F101,"getslot truncating at","",dblastused+DB_RECL);
+#ifdef COHERENT
+ x = chsize(fileno(dbfp),dblastused+DB_RECL);
+#else
+ x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL));
+#endif /* COHERENT */
+ if (x < 0) /* (Not fatal) */
+ debug(F101,"getslot ftruncate failed", "", errno);
+ }
+#endif /* NOFTRUNCATE */
+
+ /* Initialize my record */
+
+ if (initslot(mydbslot) < 0) {
+ debug(F101,"getslot initslot() error","",n);
+ ikdbopen = 0;
+ goto xslot;
+ }
+ debug(F101,"getslot OK","",mydbslot);
+ rc = mydbslot; /* OK return code */
+
+ xslot: /* Unlock the database and return */
+ if (unlink(lcknam) < 0) {
+ debug(F111,"getslot lockfile removal failed",lcknam,errno);
+ rc = -1;
+ }
+ return(rc);
+}
+#endif /* IKSDB */
+#endif /* NOIKSD */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c.printw b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c.printw
new file mode 100644
index 0000000..d332bed
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusx.c.printw
@@ -0,0 +1,9718 @@
+#include "ckcsym.h"
+
+/* C K U U S X -- "User Interface" common functions. */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ This module contains user interface functions needed by both the interactive
+ user interface and the command-line-only user interface, as well as the
+ screen-control routines (curses and equivalent).
+*/
+
+/* Includes */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+
+#ifndef NOHTERMCAP
+#ifdef NOTERMCAP
+#define NOHTERMCAP
+#else
+#ifndef BSD44
+#define NOHTERMCAP
+#else
+#ifdef __bsdi__
+#define NOHTERMCAP
+#else
+#ifdef OPENBSD
+#define NOHTERMCAP
+#else
+#ifdef MACOSX
+#define NOHTERMCAP
+#endif /* MACOSX */
+#endif /* OPENBSD */
+#endif /* __bsdi__ */
+#endif /* BSD44 */
+#endif /* NOTERMCAP */
+#endif /* NOHTERMCAP */
+
+#ifndef NOTERMCAP
+#ifdef BSD44
+#ifndef NOHTERMCAP
+#include <termcap.h>
+#endif /* NOHTERMCAP */
+#endif /* BSD44 */
+#else /* !BSD44 */
+#ifdef linux
+#include <term.h>
+#endif /* linux */
+#endif /* NOTERMCAP */
+
+#ifdef OS2
+#include <string.h>
+_PROTOTYP(char * os2_gethostname, (void));
+#define getpid _getpid
+#endif /* OS2 */
+#ifdef BSD44
+#include <errno.h>
+#endif /* BSD44 */
+
+extern xx_strp xxstring;
+
+#ifdef OS2
+#include "ckcnet.h"
+#else /* OS2 */
+_PROTOTYP( char * ckgetpeer, (VOID));
+_PROTOTYP(int getlocalipaddr, (void));
+_PROTOTYP(int istncomport, (void));
+#ifndef NOCKGETFQHOST
+_PROTOTYP( char * ckgetfqhostname,(char *));
+#endif /* NOCKGETFQHOST */
+#ifndef NETCONN
+/*
+ We should just pull in ckcnet.h here, but it causes a conflict with curses.h.
+*/
+#ifdef TCPSOCKET
+#define NETCONN
+#else
+#ifdef SUNX25
+#define NETCONN
+#else
+#ifdef STRATUSX25
+#define NETCONN
+#else
+#ifdef IBMX25
+#define NETCONN
+#else
+#ifdef HPX25
+#define NETCONN
+#else
+#ifdef DECNET
+#define NETCONN
+#else
+#ifdef NPIPE
+#define NETCONN
+#else
+#ifdef CK_NETBIOS
+#define NETCONN
+#ifdef SUPERLAT
+#define NETCONN
+#else
+#endif /* SUPERLAT */
+#endif /* TCPSOCKET */
+#endif /* SUNX25 */
+#endif /* STRATUSX25 */
+#endif /* IBMX25 */
+#endif /* HPX25 */
+#endif /* DECNET */
+#endif /* NPIPE */
+#endif /* CK_NETBIOS */
+#endif /* NETCONN */
+#endif /* OS2 */
+
+#ifndef TCPSOCKET
+#ifdef MULTINET
+#define TCPSOCKET
+#endif /* MULTINET */
+#ifdef DEC_TCPIP
+#define TCPSOCKET
+#endif /* DEC_TCPIP */
+#ifdef WINTCP
+#define TCPSOCKET
+#endif /* WINTCP */
+#ifdef TCPWARE
+#define TCPSOCKET
+#endif /* TCPWARE */
+#endif /* TCPSOCKET */
+
+#ifdef OS2
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#else /* NT */
+#define INCL_VIO
+#include <os2.h>
+#endif /* NT */
+#ifdef COMMENT /* Would you believe */
+#undef COMMENT /* <os2.h> defines this ? */
+#endif /* COMMENT */
+#ifdef CK_NETBIOS
+#include "ckonbi.h"
+#endif /* CK_NETBIOS */
+
+#include "ckocon.h"
+extern ascreen commandscreen;
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#endif /* OS2 */
+
+#ifdef NT
+#include "cknwin.h"
+#endif /* NT */
+#ifdef OS2
+#include "ckowin.h"
+#include "ckosyn.h"
+#endif /* OS2 */
+
+#ifdef CK_TAPI
+extern int tttapi;
+extern int tapipass;
+#endif /* CK_TAPI */
+
+#ifdef CK_KERBEROS
+#include "ckuath.h"
+#endif /* CK_KERBEROS */
+
+#ifndef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+
+#ifdef VMS
+#include <descrip.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#ifndef OLD_VMS
+#include <lib$routines.h> /* Not for VAX C 2.3 */
+#else
+#include <libdef.h>
+#endif /* OLD_VMS */
+#ifdef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+#endif /* VMS */
+
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * popen, (char *, char *) );
+#endif /* DCLPOPEN */
+
+int tt_crd = 0; /* Carriage return display */
+int tt_lfd = 0; /* Linefeed display */
+int interrupted = 0; /* Interrupted from keyboard flag */
+int fxd_inited = 0; /* Fullscreen stuff initialized */
+
+#ifdef DEBUG
+char debfil[CKMAXPATH+1]; /* Debugging log file name */
+#endif /* DEBUG */
+
+#ifdef TLOG
+char trafil[CKMAXPATH+1]; /* Transaction log file name */
+#endif /* TLOG */
+
+char sesfil[CKMAXPATH+1]; /* Session log file name */
+
+#ifdef CKLOGDIAL
+char diafil[CKMAXPATH+1]; /* Connection log file name */
+char cxlogbuf[CXLOGBUFL+1]; /* Connection log record buffer */
+int cx_active = 0; /* Connection is active */
+extern int dialog;
+#endif /* CKLOGDIAL */
+
+#ifdef DYNAMIC
+static char *cmdstr = NULL; /* Place to build generic command */
+#else
+#ifdef pdp11
+static char cmdstr[256];
+#else
+static char cmdstr[4096];
+#endif /* pdp11 */
+#endif /* DYNAMIC */
+
+#ifndef NOMSEND
+char fspec[CMDBL+4]; /* Filename string for \v(filespec) */
+int fspeclen = CMDBL;
+#else
+char fspec[CKMAXPATH+4];
+int fspeclen = CKMAXPATH;
+#endif /* NOMSEND */
+
+char * rfspec = NULL; /* Received filespec: local */
+char * prfspec = NULL; /* Preliminary rfspec */
+char * sfspec = NULL; /* Sent filespec: local */
+char * psfspec = NULL; /* Preliminary sfspec */
+char * srfspec = NULL; /* Received filespec: remote */
+char * psrfspec = NULL; /* Preliminary srfspec */
+char * rrfspec = NULL; /* Sent filespec: remote */
+char * prrfspec = NULL; /* Preliminary rrfspec */
+
+int success = 1, /* Command success/failure flag */
+ cmdlvl = 0, /* Command level */
+ action = 0, /* Action selected on command line */
+ slogts = 0, /* Session-log timestamps on/off */
+ slognul = 0, /* Session-log null-terminated lines */
+#ifdef UNIX
+ sessft = XYFT_T, /* Session log file type */
+#else
+ sessft = XYFT_B, /* (text for UNIX binary for others) */
+#endif /* UNIX */
+ pflag = 1, /* Print prompt */
+ msgflg = 1; /* Print informational messages */
+
+extern int xaskmore, saveask; /* More-prompting */
+
+#ifdef CK_APC
+extern int apcactive;
+#endif /* CK_APC */
+/* External variables */
+
+extern int local, quiet, binary, network, what, parity, xitsta, escape,
+ tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc;
+
+extern int cmd_rows, cmd_cols, xcmdsrc;
+
+extern char cmdfil[];
+
+#ifdef VMS
+extern int batch;
+#endif /* VMS */
+
+#ifdef datageneral /* 2/12/92 ENH */
+#include <sysid.h>
+extern int con_reads_mt, conint_ch, conint_avl;
+#endif /* datageneral */
+
+extern long speed;
+
+extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
+
+#ifndef NOCSETS
+extern int fcharset, tcharset, xfrxla;
+extern struct csinfo fcsinfo[], tcsinfo[];
+#endif /* NOCSETS */
+
+#ifdef OS2
+extern unsigned char colorcmd;
+#endif /* OS2 */
+
+#ifdef NOXFER
+
+int fdispla = XYFD_N;
+
+#else /* NOXFER is not defined */
+
+#ifdef OS2 /* File transfer display type */
+int fdispla = XYFD_C; /* Curses (fullscreen) if we have it */
+#else
+#ifdef CK_CURSES
+int fdispla = XYFD_C;
+#else
+int fdispla = XYFD_S; /* Otherwise CRT */
+#endif /* CK_CURSES */
+#endif /* OS2 */
+
+extern struct ck_p ptab[];
+extern int protocol, xfrbel, xfrint;
+
+#ifdef STREAMING
+extern int streaming, streamok;
+#endif /* STREAMING */
+
+/* Used internally */
+
+#ifdef KUI
+_PROTOTYP( VOID screeng, (int, char, long, char *) );
+#endif /* KUI */
+_PROTOTYP( VOID screenc, (int, char, CK_OFF_T, char *) );
+
+
+#ifdef CK_CURSES
+#ifndef DYNAMIC
+static char xtrmbuf[TRMBUFL]; /* tgetent() buffer */
+char * trmbuf = xtrmbuf;
+#else
+char * trmbuf = NULL;
+#endif /* DYNAMIC */
+_PROTOTYP( static VOID dpyinit, (void) );
+_PROTOTYP( static long shocps, (int, CK_OFF_T, CK_OFF_T) );
+_PROTOTYP( static CK_OFF_T shoetl, (CK_OFF_T, long, CK_OFF_T, CK_OFF_T) );
+#endif /* CK_CURSES */
+
+static int ft_win = 0; /* Fullscreen file transfer display window is active */
+
+/* Variables declared here */
+
+static char * skreason[] = {
+ "", /* 0 */
+ "Remote file not older", /* SKP_DAT */
+ "Identical modification times", /* SKP_EQU */
+ "Type", /* SKP_TYP */
+ "Size", /* SKP_SIZ */
+ "Name collision", /* SKP_NAM */
+ "Exception List", /* SKP_EXL */
+ "Dot file", /* SKP_DOT */
+ "Backup file", /* SKP_BKU */
+ "Recovery not needed", /* SKP_RES */
+ "Access denied", /* SKP_ACC */
+ "Not a regular file", /* SKP_NRF */
+ "Simulated", /* SKP_SIM */
+ "Simulated - Remote file older", /* SKP_XUP */
+ "Simulated - No remote file", /* SKP_XNX */
+};
+static int nskreason = (sizeof(skreason) / sizeof(char *));
+
+char *
+gskreason(n) int n; {
+ return((n > 0 && n < nskreason) ? skreason[n] : "");
+}
+
+char pktfil[CKMAXPATH+1]; /* Packet log file name */
+
+#ifndef NOMSEND /* Multiple SEND */
+char *msfiles[MSENDMAX];
+#endif /* NOMSEND */
+
+#ifdef CK_TIMERS
+extern long rttdelay;
+extern int rttflg;
+#endif /* CK_TIMERS */
+extern int rcvtimo;
+
+#ifdef CK_RESEND
+extern int sendmode;
+extern CK_OFF_T sendstart, rs_len;
+#endif /* CK_RESEND */
+
+#ifdef CK_PCT_BAR /* File transfer thermometer */
+int thermometer = 1; /* ON by default */
+#endif /* CK_PCT_BAR */
+
+#ifdef GFTIMER
+CKFLOAT gtv = -1.0, oldgtv = -1.0;
+#else
+#ifndef OS2
+static
+#endif /* OS2 */
+ long gtv = -1L, oldgtv = -1L;
+#endif /* GFTIMER */
+
+extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen,
+ winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu,
+ swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs,
+ pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl,
+ retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts,
+ rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive;
+
+extern long filcnt, filrej, rptn, filcps, tfcps, cps, peakcps;
+extern CK_OFF_T ffc, tfc, fsize;
+
+long oldcps = 0L;
+
+extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg;
+extern char *xfrmsg;
+
+#ifdef IKSDB
+FILE * dbfp = NULL; /* File pointer to database file */
+
+int dbenabled = 1; /* Flag for database is enabled */
+extern int ikdbopen; /* Flag for database is open */
+
+unsigned long mydbseek = 0L; /* Seek pointer to my record */
+int mydbslot = 0; /* My slot number */
+unsigned long myflags = 0L; /* My flags */
+unsigned long myatype = 0L; /* My authorization type */
+unsigned long myamode = 0L; /* My authorization mode */
+unsigned long mystate = 0L; /* My state (SEND, RECEIVE, etc) */
+unsigned long mypid = 0L; /* My PID */
+unsigned long myip = 0L; /* My IP address */
+unsigned long peerip = 0L; /* My peer's IP address */
+
+unsigned long dbip = 0L; /* IP address in db record */
+unsigned long dbpid = 0L; /* PID in db record */
+unsigned long dbflags = 0L; /* Flags field in db record */
+unsigned long dblastused = 0L; /* Last in-use record in db */
+char dbrec[DB_RECL]; /* Database record buffer */
+
+char * dbdir = NULL; /* Database directory */
+char * dbfile = NULL; /* Database file full pathname */
+char myhexip[33] = { NUL, NUL }; /* My IP address in hex */
+char peerhexip[33] = { NUL, NUL }; /* Client's IP address in hex */
+#endif /* IKSDB */
+
+#ifdef GFTIMER
+extern CKFLOAT fpfsecs, fptsecs, fpxfsecs;
+#else
+extern long xfsecs;
+#endif /* GFTIMER */
+#endif /* NOXFER */
+
+#ifdef TCPSOCKET
+#ifdef NEWFTP
+extern char * ftp_host, ftp_srvtyp[];
+extern int ftp_csx, ftp_csl, ftp_deb;
+#endif /* NEWFTP */
+extern char myipaddr[];
+#endif /* TCPSOCKET */
+
+#ifndef NOICP
+#ifndef NOSPL
+ extern struct mtab *mactab; /* For ON_EXIT macro. */
+ extern int nmac;
+#endif /* NOSPL */
+#ifdef DCMDBUF
+extern char *cmdbuf; /* Command buffer */
+#else
+extern char cmdbuf[]; /* Command buffer */
+#endif /* DCMDBUF */
+extern int cmd_quoting;
+#endif /* NOICP */
+
+#ifndef NOCCTRAP
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcsig.h"
+extern ckjmpbuf cmjbuf;
+#endif /* NOCCTRAP */
+
+extern int xfiletype, nscanfile;
+
+int
+shoesc(escape) int escape; {
+ extern char * ccntab[]; /* C0 control character name table */
+ extern int tt_escape;
+ if ((escape > 0 && escape < 32) || (escape == 127)) {
+ printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n",
+ ctl(escape),
+ escape,
+ (escape == 127 ? "DEL" : ccntab[escape]),
+ tt_escape ? "enabled" : "disabled"
+ );
+ } else {
+ printf(" Escape character: Code %d",escape);
+ if (escape > 160 && escape < 256)
+ printf(" (%c)",escape);
+ printf(": %s\r\n", tt_escape ? "enabled" : "disabled");
+ }
+ return(0);
+}
+
+#ifndef NOXFER
+/* P R E S E T -- Reset global protocol variables */
+
+extern int recursive;
+
+#ifdef PATTERNS
+int patterns = SET_AUTO; /* Whether to use filename patterns */
+extern int g_patterns; /* For saving and restoring */
+#else
+int patterns = SET_OFF;
+#endif /* PATTERNS */
+
+#ifndef NOICP
+#ifdef CK_LABELED
+extern int g_lf_opts, lf_opts;
+#endif /* CK_LABELED */
+extern int g_matchdot, g_usepipes, usepipes;
+extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv;
+extern int g_recursive;
+extern int g_xfermode, xfermode;
+extern int g_urpsiz, g_spsizf, g_spsiz;
+extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact;
+extern int g_fnspath, g_fnrpath, g_skipbup;
+extern int nolinks;
+#ifdef CKSYMLINK
+extern int zgfs_link;
+#endif /* CKSYMLINK */
+#ifndef NOSPL
+extern int g_pflg, pwflg, g_pcpt, pwcrypt;
+extern char * g_pswd, pwbuf[];
+#endif /* NOSPL */
+#endif /* NOICP */
+
+extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath;
+extern int moving; /* SEND criteria */
+extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[];
+extern CK_OFF_T sndlarger, sndsmaller, calibrate;
+extern int rmailf, rprintf, skipbup;
+extern char optbuf[];
+
+#ifdef PIPESEND
+extern char * g_sfilter, * g_rfilter;
+extern char * sndfilter, * rcvfilter;
+#endif /* PIPESEND */
+extern char ** sndarray;
+
+VOID
+ftreset() {
+#ifndef NOICP
+ int i;
+ extern char * filefile;
+ extern int reliable, xreliable, c_save, ss_save, slostart, urclear;
+ extern int oopts, omode, oname, opath, kactive, autopath;
+ extern char * snd_move; /* Directory to move sent files to */
+ extern char * snd_rename; /* What to rename sent files to */
+ extern char * rcv_move;
+ extern char * rcv_rename;
+ extern char * g_snd_move;
+ extern char * g_snd_rename;
+ extern char * g_rcv_move;
+ extern char * g_rcv_rename;
+
+#ifdef CK_TMPDIR
+ extern int f_tmpdir;
+ extern char savdir[];
+#endif /* CK_TMPDIR */
+
+#ifdef CK_SPEED
+#ifdef COMMENT
+ extern int f_ctlp;
+ extern short s_ctlp[], ctlp[];
+#endif /* COMMENT */
+#endif /* CK_SPEED */
+
+#ifndef NOCSETS
+ extern int fcs_save, tcs_save;
+ extern int g_xfrxla, xfrxla;
+#endif /* NOCSETS */
+
+/* Restore / reset per-command file-transfer switches */
+
+ makestr(&snd_move,g_snd_move);
+ makestr(&rcv_move,g_rcv_move);
+ makestr(&snd_rename,g_snd_rename);
+ makestr(&rcv_rename,g_rcv_rename);
+
+ kactive = 0; /* Kermit protocol no longer active */
+ oopts = -1; /* O-Packet Options */
+ omode = -1; /* O-Packet Transfer Mode */
+ oname = -1; /* O-Packet Filename Options */
+ opath = -1; /* O-Packet Pathname Options */
+
+#ifdef CK_RESEND
+ rs_len = 0L; /* REGET position */
+#endif /* CK_RESEND */
+
+#ifdef COMMENT
+#ifdef CK_SPEED
+ if (f_ctlp) {
+ for (i = 0; i < 256; i++)
+ ctlp[i] = s_ctlp[i];
+ f_ctlp = 0;
+ }
+#endif /* CK_SPEED */
+#endif /* COMMENT */
+
+#ifdef CK_TMPDIR
+ if (f_tmpdir) { /* If we changed to download dir */
+ zchdir((char *) savdir); /* Go back where we came from */
+ f_tmpdir = 0;
+ }
+#endif /* CK_TMPDIR */
+
+ calibrate = 0L; /* Calibration run */
+ if (xreliable > -1) {
+ reliable = xreliable;
+ debug(F101,"ftreset reliable","",reliable);
+ }
+ urclear = 0;
+
+ if (autopath) { /* SET RECEIVE PATHNAMES AUTO */
+ fnrpath = PATH_AUTO;
+ autopath = 0;
+ }
+ if (filefile) { /* File list */
+ zclose(ZMFILE);
+ makestr(&filefile,NULL);
+ }
+ if (c_save > -1) { /* Block Check Type */
+ bctr = c_save;
+ c_save = -1;
+ }
+ if (ss_save > -1) { /* Slow Start */
+ slostart = ss_save;
+ ss_save = -1;
+ }
+#ifdef CK_LABELED
+ if (g_lf_opts > -1) {
+ lf_opts = g_lf_opts; /* Restore labeled transfer options */
+ g_lf_opts = -1;
+ }
+#endif /* CK_LABELED */
+
+#ifndef NOCSETS
+ if (tcs_save > -1) { /* Character sets */
+ tcharset = tcs_save;
+ tcs_save = -1;
+ }
+ if (fcs_save > -1) {
+ fcharset = fcs_save;
+ fcs_save = -1;
+ }
+ if (g_xfrxla > -1) {
+ xfrxla = g_xfrxla;
+ g_xfrxla = -1;
+ }
+ setxlatype(tcharset,fcharset); /* Translation type */
+#endif /* NOCSETS */
+
+#ifdef NETCONN
+#ifndef NOSPL
+ if (g_pswd) {
+ ckstrncpy(pwbuf,g_pswd,PWBUFL);
+ makestr(&g_pswd,NULL);
+ }
+ if (g_pflg > -1) {
+ pwflg = g_pflg;
+ g_pflg = -1;
+ }
+ if (g_pcpt > -1) {
+ pwcrypt = g_pcpt;
+ g_pcpt = -1;
+ }
+#endif /* NOSPL */
+#endif /* NETCONN */
+
+ if (g_binary > -1) { /* File type */
+ binary = g_binary;
+ g_binary = -1;
+ }
+ if (g_xfermode > -1) { /* Transfer mode */
+ xfermode = g_xfermode;
+ g_xfermode = -1;
+ }
+#ifdef PATTERNS
+ if (g_patterns > -1) { /* Filename patterns */
+ patterns = g_patterns;
+ g_patterns = -1;
+ }
+#endif /* PATTERNS */
+
+ if (g_usepipes > -1) {
+ usepipes = g_usepipes;
+ g_usepipes = -1;
+ }
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot;
+ g_matchdot = -1;
+ }
+ if (g_proto > -1) { /* Protocol */
+ protocol = g_proto;
+ g_proto = -1;
+ }
+ if (g_urpsiz > -1) {
+ urpsiz = g_urpsiz;
+ debug(F101,"ftreset restoring urpsiz","",urpsiz);
+ g_urpsiz = -1;
+ }
+ if (g_spsizf > -1) {
+ spsizf = g_spsizf;
+ debug(F101,"ftreset restoring spsizf","",spsizf);
+ g_spsizf = -1;
+ }
+ if (g_spsiz > -1) {
+ spsiz = g_spsiz;
+ debug(F101,"ftreset restoring spsiz","",spsiz);
+ g_spsiz = -1;
+ }
+ if (g_spsizr > -1) {
+ spsizr = g_spsizr;
+ debug(F101,"ftreset restoring spsizr","",spsizr);
+ g_spsizr = -1;
+ }
+ if (g_spmax > -1) {
+ spmax = g_spmax;
+ g_spmax = -1;
+ }
+ if (g_wslotr > -1) {
+ wslotr = g_wslotr;
+ g_wslotr = -1;
+ }
+ if (g_prefixing > -1) {
+ prefixing = g_prefixing;
+ g_prefixing = -1;
+ }
+ if (g_fncact > -1) {
+ fncact = g_fncact;
+ g_fncact = -1;
+ }
+ if (g_fncnv > -1) {
+ fncnv = g_fncnv;
+ g_fncnv = -1;
+ }
+ if (g_fnspath > -1) {
+ fnspath = g_fnspath;
+ g_fnspath = -1;
+ }
+ if (g_fnrpath > -1) {
+ fnrpath = g_fnrpath;
+ g_fnrpath = -1;
+ }
+ if (g_skipbup > -1) {
+ skipbup = g_skipbup;
+ g_skipbup = -1;
+ }
+ nolinks = 2; /* /FOLLOWLINKS is never global */
+ recursive = 0; /* /RECURSIVE can never be global */
+ xfiletype = -1;
+
+ if (g_displa > -1) { /* File transfer display */
+ fdispla = g_displa;
+ g_displa = -1;
+ }
+ if (g_spath > -1) { /* Send pathnames */
+ fnspath = g_spath;
+ g_spath = -1;
+ }
+ if (g_rpath > -1) { /* Receive pathnames */
+ fnrpath = g_rpath;
+ g_rpath = -1;
+ }
+ if (g_fncnv > -1) { /* Filename conversion */
+ fncnv = g_fncnv;
+ g_fncnv = -1;
+ }
+#ifdef PIPESEND
+ makestr(&sndfilter,g_sfilter); /* Send filter */
+ makestr(&rcvfilter,g_rfilter); /* Receive filter */
+#endif /* PIPESEND */
+
+#ifndef NOFRILLS
+ rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */
+ optbuf[0] = NUL; /* MAIL and PRINT options */
+#endif /* NOFRILLS */
+
+ moving = 0; /* Reset delete-after-send indicator */
+ sndafter[0] = NUL; /* Reset SEND selection switches */
+ sndbefore[0] = NUL;
+
+ for (i = 0; i < NSNDEXCEPT; i++) {
+ if (sndexcept[i])
+ free(sndexcept[i]);
+ sndexcept[i] = NULL;
+ if (rcvexcept[i])
+ free(rcvexcept[i]);
+ rcvexcept[i] = NULL;
+ }
+ sndlarger = (CK_OFF_T)-1;
+ sndsmaller = (CK_OFF_T)-1;
+ debug(F101,"present sndsmaller","",sndsmaller);
+#ifdef GFTIMER
+ gtv = -1.0;
+ oldgtv = -1.0;
+#else
+ gtv = -1L;
+ oldgtv = -1L;
+#endif /* GFTIMER */
+#endif /* NOICP */
+}
+#endif /* NOXFER */
+
+char *
+ttgtpn() { /* Get typical port name */
+/*
+ Ideally this routine would be implemented in each of the cku?io.* modules,
+ but that requires changing the API definition.
+*/
+ return(
+#ifdef OS2
+#ifdef OS2ONLY
+"COM1"
+#else /* OS2ONLY */
+"TAPI [ name ] or COM1"
+#endif /* OS2ONLY */
+#else /* OS2 */
+#ifdef VMS
+"TXA0:, TTA0:, or LTA0:"
+#else /* VMS */
+#ifdef SOLARIS
+"/dev/cua/a"
+#else /* SOLARIS */
+#ifdef HPUX10
+"/dev/cua0p0"
+#else /* HPUX10 */
+#ifdef HPUX
+"/dev/cua00"
+#else /* HPUX */
+#ifdef __FreeBSD__
+"/dev/cuaa0"
+#else /* __FreeBSD__ */
+#ifdef __linux__
+"/dev/ttyS0"
+#else /* __linux__ */
+#ifdef BSD44
+"/dev/tty00"
+#else /* BSD44 */
+#ifdef OSK
+"/t1"
+#else /* OSK */
+#ifdef QNX
+"/dev/ser1"
+#else /* QNX */
+#ifdef QNX6
+"/dev/ser1"
+#else /* QNX6 */
+#ifdef UNIXWARE
+"/dev/term/00 or /dev/tty00"
+#else /* UNIXWARE */
+#ifdef CK_SCOV5
+"/dev/tty1A"
+#else /* CK_SCOV5 */
+#ifdef CK_SCO32V4
+"/dev/tty1A"
+#else /* CK_SCO32V4 */
+#ifdef M_XENIX
+"/dev/tty1A"
+#else /* M_XENIX */
+#ifdef AIXRS
+"/dev/tty0"
+#else /* AIXRS */
+#ifdef DGUX
+"/dev/tty00"
+#else /* DGUX */
+#ifdef datageneral
+"@con1"
+#else /* datageneral */
+#ifdef IRIX
+"/dev/ttym0"
+#else /* IRIX */
+#ifdef SUNOS4
+"/dev/ttyh0"
+#else /* SUNOS4 */
+#ifdef SV68R3V6
+"/dev/scc0"
+#else /* SV68R3V6 */
+#ifdef MOTSV88R4
+"/dev/contty00"
+#else /* MOTSV88R4 */
+#ifdef NEXT
+"/dev/cufa"
+#else
+#ifdef OSF
+"/dev/ttyd1"
+#else
+#ifdef SINIX
+"/dev/ttyc1"
+#else
+#ifdef UNIX
+"/dev/cua, /dev/acu, /dev/tty0, etc"
+#else /* UNIX */
+"(sorry no example available)"
+#endif /* UNIX */
+#endif /* SINIX */
+#endif /* OSF */
+#endif /* NEXT */
+#endif /* MOTSV88R4 */
+#endif /* SV68R3V6 */
+#endif /* SUNOS4 */
+#endif /* IRIX */
+#endif /* datageneral */
+#endif /* DGUX */
+#endif /* AIX */
+#endif /* M_XENIX */
+#endif /* CK_SCO32V4 */
+#endif /* CK_SCOV5 */
+#endif /* UNIXWARE */
+#endif /* QNX6 */
+#endif /* QNX */
+#endif /* OSK */
+#endif /* BSD44 */
+#endif /* __linux__ */
+#endif /* __FreeBSD__ */
+#endif /* HPUX */
+#endif /* HPUX10 */
+#endif /* SOLARIS */
+#endif /* VMS */
+#endif /* OS2 */
+ );
+}
+
+/* C K _ E R R S T R -- Return message from most recent system error */
+
+#ifdef CKROOT
+extern int ckrooterr;
+#endif /* CKROOT */
+
+char *
+ck_errstr() {
+#ifdef USE_STRERROR
+#ifndef CK_ANSILIBS
+ /* Should have been declared in <string.h> */
+_PROTOTYP( char * strerror, (int) );
+#endif /* CK_ANSILIBS */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ return(strerror(errno));
+#else /* !USE_STRERROR */
+#ifdef VMS
+ extern char * ckvmserrstr(unsigned long);
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ return(ckvmserrstr(0L));
+#else /* !VMS */
+#ifdef BSD44
+#ifdef __386BSD__
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#else /* !__386BSD__ */
+#ifndef __bsdi__
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern const char *const sys_errlist[];
+#endif /* NDSYSERRLIST */
+#endif /* __bsdi__ */
+#endif /* __386BSD__ */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else /* !BSD44 */
+#ifdef ATTSV
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else /* !ATTSV */
+#ifdef BSD4
+#ifndef NDSYSERRLIST
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+ else
+#endif /* CKROOT */
+ if (errno >= sys_nerr)
+ return("Error number out of range");
+ else
+ return((char *) sys_errlist[errno]);
+#else
+#ifdef OS2
+#ifndef NDSYSERRLIST
+ extern char *sys_errlist[];
+#endif /* NDSYSERRLIST */
+#ifdef NT
+ extern int_sys_nerr;
+#endif /* NT */
+ char *e;
+#ifdef CKROOT
+ if (ckrooterr)
+ return("Off limits");
+#endif /* CKROOT */
+ e = (errno > -1
+#ifdef NT
+ && errno <= _sys_nerr
+#endif /* NT */
+ ) ?
+#ifdef NT
+ (char *) sys_errlist[errno]
+#else /* NT */
+ /* I don't know how to get a CLIB error string in OS/2 */
+ strerror(errno)
+#endif /* NT */
+ : "";
+ return(e ? e : "");
+#else /* OS2 */
+ return("");
+#endif /* OS2 */
+#endif /* BSD4 */
+#endif /* ATTSV */
+#endif /* BSD44 */
+#endif /* VMS */
+#endif /* USE_STRERROR */
+}
+
+#ifdef PATTERNS
+/*
+ Filename pattern recognition lists for automatic text/binary switching.
+ These are somewhat passe after the addition of scanfile() (7.0).
+ But with the addition of FTP [M]GET, they're back in style (8.0).
+
+ Although, with FTP the lists need to be used in the reverse. With
+ Kermit the list is used to imply the types of the local system. Whereas
+ with FTP, the list must be used to imply the type of the remote system.
+ Therefore, all platforms must now support all of the lists.
+*/
+char *txtpatterns[FTPATTERNS+1] = { NULL, NULL };
+char *binpatterns[FTPATTERNS+1] = { NULL, NULL };
+/*
+ Default pattern lists for each platform...
+
+ NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they
+ are traditionally text types, they are binary in Windows. So they are
+ handled by the prevailing SET FILE TYPE, rather than automatically.
+ Similarly for ".dat", ".inf", and so on. Also ".ps" since PostScript files
+ are not always text. ".log" is omitted since logs can be text or binary,
+ except in VMS they are usually text, etc etc.
+
+ Later (Sep 2003): Add PostScript to binary patterns.
+*/
+static char *txtp[SYS_MAX][FTPATTERNS] = {
+ /* UNKNOWN */ {
+ NULL, NULL
+ },
+ { /* UNIX */
+ "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd",
+ "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx",
+ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh",
+ "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed",
+ "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac",
+ NULL
+ },
+ { /* WIN32 */
+ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
+ "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL
+ },
+ { /* VMS */
+ "*.com","*.txt","*.c", "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli",
+ "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log",
+ "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt",
+ "*.mem",NULL
+ },
+ { /* OS2 */
+ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
+ NULL
+ },
+ { /* DOS */
+ "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex",
+ "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
+ "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL
+ },
+ { /* TOPS-10 */
+ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
+ "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
+ "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
+ },
+ { /* TOPS-20 */
+ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
+ "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
+ "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
+ },
+ { /* STRATUS VOS */
+ "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex",
+ "*.hqx","*.c", "*.h", "*.w", "*.java","*.bwr","*.upd","*.ttp","*.cm",
+ "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL
+ },
+ { /* DG AOS/VS */
+ "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me",
+ "*.cli", "*.ksc", NULL
+ },
+ { /* OSK */
+ "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */
+ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp",
+ "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed",
+ "*.txt","*.w", /* general text */
+ "*.ksc","*.bwr","*.upd",
+ "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx",
+ "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*",
+ NULL
+ }
+};
+
+/* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */
+
+static char *binp[SYS_MAX][FTPATTERNS] = {
+ { /* UNKNOWN */
+ NULL, NULL
+ },
+ { /* UNIX */
+ "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out",
+ "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class",
+ "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx",
+ "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit",
+ "*.ps", NULL
+ },
+ { /* WIN32 */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg",
+ "*.ps", NULL
+ },
+ { /* VMS */
+ "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp",
+ "*.ps", "*.dat","*.par", NULL
+ },
+ { /* OS2 */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", NULL
+ },
+ { /* DOS */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", NULL
+ },
+ { /* TOPS10 */
+ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
+ "*.ps", NULL
+ },
+ { /* TOPS20 */
+ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
+ "*.ps", NULL
+ },
+ { /* STRATUS VOS */
+ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
+ "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
+ "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
+ "*.pdf", "*.ps", "*.lzh", "*.pm", NULL
+ },
+ { /* DG */
+ "*.ob", "*.pr", "*.dmp", "*.ps", NULL
+ },
+ { /* OSK */
+ "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */
+ "*.zip","*.ar","*.zoo","*.rpm","*.lzh",
+ /* object files, libraries, executables */
+ "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class",
+ /* images */
+ "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps",
+ "*.bmp", "*.bz2", "*.BMP","*.pcx",
+ NULL
+ }
+};
+
+/*
+ Set up default pattern lists so they can be freed and re-malloc'd.
+ Each pattern list must terminated by a null element.
+*/
+VOID
+initpat() {
+ int i;
+ for (i = 0; i < FTPATTERNS; i++) {
+ txtpatterns[i] = NULL;
+ binpatterns[i] = NULL;
+ }
+ for (i = 0; i < FTPATTERNS; i++) {
+#ifdef UNIX
+ makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]);
+#else /* UNIX */
+#ifdef OS2
+#ifdef NT
+ makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]);
+#else /* NT */
+ makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]);
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+ makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]);
+#else /* VMS */
+#ifdef STRATUS
+ makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]);
+#else /* STRATUS */
+#ifdef datageneral
+ makestr(&(txtpatterns[i]),txtp[SYS_DG][i]);
+#else /* datageneral */
+#ifdef OSK
+ makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]);
+#else /* OSK */
+ makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]);
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+ if (!txtp[i])
+ break;
+ }
+ for (i = 0; i < FTPATTERNS; i++) {
+#ifdef UNIX
+ makestr(&(binpatterns[i]),binp[SYS_UNIX][i]);
+#else /* UNIX */
+#ifdef OS2
+#ifdef NT
+ makestr(&(binpatterns[i]),binp[SYS_WIN32][i]);
+#else /* NT */
+ makestr(&(binpatterns[i]),binp[SYS_OS2][i]);
+#endif /* NT */
+#else /* OS2 */
+#ifdef VMS
+ makestr(&(binpatterns[i]),binp[SYS_VMS][i]);
+#else /* VMS */
+#ifdef STRATUS
+ makestr(&(binpatterns[i]),binp[SYS_VOS][i]);
+#else /* STRATUS */
+#ifdef datageneral
+ makestr(&(binpatterns[i]),binp[SYS_DG][i]);
+#else /* datageneral */
+#ifdef OSK
+ makestr(&(binpatterns[i]),binp[SYS_OSK][i]);
+#else /* OSK */
+ makestr(&(binpatterns[i]),binp[SYS_UNK][i]);
+#endif /* OSK */
+#endif /* datageneral */
+#endif /* STRATUS */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIX */
+ if (!binp[i])
+ break;
+ }
+}
+
+/*
+ m a t c h n a m e -- Compare filename with text & binary name patterns.
+
+ Returns:
+ 0 if name matches a text pattern but not a binary pattern.
+ 1 if name matches a binary pattern but not a text pattern.
+ -1 if name matches no patterns.
+ -2 if name matches a binary pattern and a text pattern.
+*/
+int
+matchname(filename, local, os) char * filename; int local; int os; {
+ int rc = -1; /* Return code */
+ char * name, * p;
+#ifdef OS2ORUNIX
+ char tmpbuf[CKMAXPATH+1];
+#endif /* OS2ORUNIX */
+
+ name = filename ? filename : ""; /* Copy of original arg */
+ if (patterns && *name) { /* If PATTERNS ON... */
+ int i;
+
+#ifdef OS2ORUNIX
+ if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */
+ int k;
+ k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */
+ for (i = k - 3; i > 4; i--) {
+ if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') {
+ tmpbuf[i-1] = NUL;
+ break;
+ }
+ }
+ name = tmpbuf; /* And point to stripped copy */
+ }
+#endif /* OS2ORUNIX */
+ zstrip(name,&p); /* Strip pathname too */
+ name = p;
+
+ if (local) {
+ if (txtpatterns[0]) { /* Search text patterns */
+ for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
+ if (ckmatch(txtpatterns[i],name,filecase,1)) {
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (binpatterns[0]) { /* And search binary patterns */
+ for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
+ if (ckmatch(binpatterns[i],name,filecase,1)) {
+ rc = (rc > -1) ? -2 : 1;
+ break;
+ }
+ }
+ }
+ } else {
+ if (os >= 0 && os < SYS_MAX) {
+ if (txtp[os][0]) {
+ for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) {
+ if (ckmatch(txtp[os][i],name,filecase,1)) {
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (binp[os][0]) {
+ for (i = 0; i < FTPATTERNS && binp[os][i]; i++) {
+ if (ckmatch(binp[os][i],name,filecase,1)) {
+ rc = (rc > -1) ? -2 : 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ debug(F111,"matchname",name,rc);
+ return(rc);
+}
+#endif /* PATTERNS */
+
+#ifdef UNICODE
+#ifndef NOEVENMAX
+#define EVENMAX
+#endif /* NOEVENMAX */
+#endif /* UNICODE */
+
+/* S C A N F I L E -- Analyze a file's contents */
+
+/*
+ Call with:
+ name: Pointer to name of existing file.
+ flag: Pointer to int in which to return additional numeric data.
+
+ Returns:
+ -1 on failure (to open file or to read from it).
+ Integer, 0..4, on success indicating file type:
+ 0 = 7-bit text (flag = -1)
+ 1 = UTF-8 text (flag = -1)
+ 2 = UCS-2 text (flag = 0: big-endian; flag = 1: little-endian)
+ 3 = 8-bit text (flag = 0: no C1 bytes; flag = 1: includes C1 bytes)
+ 4 = Text (type unknown)
+ 5 = binary (flag = -1)
+
+ If UNICODE is defined:
+
+ 1. If file begins with a valid BOM, it is believed. Otherwise we
+ read the first 4K of the file (since it might be email with verbose
+ headers) and analyze it:
+
+ 2. If file contains only valid UTF-8 sequences, we call it UTF-8;
+ otherwise:
+
+ 3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and
+ set the polarity according to whether the preponderance of them are in
+ even or odd positions; otherwise:
+
+ 4. If EVENMAX is defined and the file contains lots of alternate bytes that
+ are identical, even if they aren't zero, and the number of such bytes
+ is at least four times the length of the maximum run of alternating
+ identical bytes of the opposite polarity, we call it UCS-2; otherwise:
+
+ 5. If the file contained no bytes with their 8th bits on and no controls
+ other than CR, LF, HT, and FF, we call it ASCII; otherwise:
+
+ 6. If it contains C0 control characters other than CR, LF, HT, and FF, we
+ call it binary; otherwise:
+
+ 7. We call it 8-bit text, character set unknown (could be Latin-1 or
+ anything else).
+
+ Note that malformed UTF-8 is not diagnosed as UTF-8.
+
+ If UNICODE is not defined:
+
+ 1. If the file contains C0 control characters other than CR, LF, HT, and
+ FF, we call it binary; otherwise:
+
+ 2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise:
+
+ 3. We call it 7-bit text.
+
+ In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as
+ 8-bit text.
+
+ There is no significant speed difference between the Unicode and
+ non-Unicode cases.
+*/
+int
+scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
+ FILE * fp; /* File pointer */
+ unsigned char buf[SCANFILEBUF]; /* File data buffer for analysis */
+ int x, val = -1, count = 0; /* Workers */
+ int rc = -1; /* Return code */
+ int pv = -1; /* Pattern-match value */
+ int eof = 0; /* Flag for file EOF encountered */
+ int bytes = 0; /* Total byte count */
+#ifdef UNICODE
+ unsigned int c0, c1; /* First 2 file bytes (for BOM) */
+#endif /* UNICODE */
+ extern int pipesend, filepeek;
+
+ register int i; /* Loop control */
+ int readsize = 0; /* How much to read */
+ int eightbit = 0; /* Number of bytes with 8th bit on */
+ int c0controls = 0; /* C0 non-text control-char counter */
+ int c0noniso = 0; /* C0 non-ISO control-char counter */
+ int c1controls = 0; /* C1 control-character counter */
+ unsigned int c; /* Current character */
+ int runmax = 0; /* Longest run of 0 bytes */
+ int runzero = 0; /* Run of 0 bytes */
+ int pctzero = 0; /* Percentage of 0 bytes */
+ int txtcz = 0;
+#ifdef CK_CTRLZ
+ extern int eofmethod;
+#endif /* CK_CTRLZ */
+
+#ifdef UNICODE
+ int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
+ int utf8state = 0; /* UTF-8 recognizer state */
+ int oddzero = 0; /* Number of 0 bytes in odd postions */
+ int evenzero = 0; /* and in even positions */
+ int lfnul = 0; /* Number of <LF><NUL> sequences */
+ int crlf = 0; /* Number of <CRLF> sequences */
+#else
+ int notutf8 = 1;
+#endif /* UNICODE */
+
+#ifdef COMMENT
+#ifdef EVENMAX
+ int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0;
+ int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0;
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+#ifndef NOXFER
+ if (pipesend || calibrate || sndarray) /* Only for real files */
+ return(-1);
+#endif /* NOXFER */
+ debug(F111,"scanfile",name,nscanfile);
+#ifdef PATTERNS
+ if (!filepeek) {
+ pv = matchname(name,1,-1);
+ if (pv < 0)
+ rc = -1;
+ else
+ rc = (pv == 1) ? FT_BIN : FT_TEXT;
+ debug(F111,"scanfile !filepeek result",name,rc);
+ return(rc);
+ }
+#endif /* PATTERNS */
+
+#ifdef VMS
+/* We don't scan in VMS where text files have various record formats in */
+/* which record headers contain seemingly non-text bytes. So the best */
+/* we can do in VMS is tell whether the file is text or binary, period. */
+ {
+ int b, x;
+ b = binary; /* Save current binary setting */
+ if (zopeni(ZIFILE,name) > 0) { /* In VMS this sets binary */
+ x = binary; /* Get result */
+ zclose(ZIFILE); /* Close the file */
+ binary = b; /* Restore previous binary setting */
+ rc = x ? FT_BIN : FT_TEXT;
+ val = 0;
+ goto xscanfile;
+ }
+ }
+#endif /* VMS */
+
+ eof = 0; /* End-of-file reached indicator */
+#ifdef OS2
+ fp = fopen(name, "rb"); /* Open the file in binary mode */
+#else
+ fp = fopen(name, "r");
+#endif /* OS2 */
+
+ if (!fp) /* Failed? */
+ return(-1);
+
+ while (1) { /* One or more gulps from file */
+ if (eof) { /* EOF from last time? */
+ debug(F111,"scanfile at EOF",name,bytes);
+ if (runzero > runmax)
+ runmax = runzero;
+ break;
+ }
+ if (nscanfile < 0) { /* Reading whole file */
+ readsize = SCANFILEBUF;
+ } else { /* Reading first nscanfilee bytes */
+ readsize = nscanfile - bytes;
+ if (readsize < 1)
+ break;
+ if (readsize > SCANFILEBUF)
+ readsize = SCANFILEBUF;
+ }
+ debug(F101,"scanfile readsize","",readsize);
+ count = fread(buf,1,readsize,fp); /* Read a buffer */
+ if (count == EOF || count == 0) {
+ debug(F111,"scanfile EOF",name,count);
+ break;
+ }
+ debug(F111,"scanfile buffer ok",name,count);
+
+ if (bytes == 0 && count > 8) {
+ /* PDF files can look like text in the beginning. */
+ if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) {
+ if (isdigit(buf[7])) {
+ if (buf[8] == '\015' ||
+ count > 9 && buf[8] == SP && buf[9] == '\015') {
+#ifdef DEBUG
+ buf[8] = NUL;
+ debug(F110,"scanfile PDF",buf,0);
+#endif /* DEBUG */
+ binary = 1; /* But they are binary. */
+ break;
+ }
+ }
+ } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) {
+ /* Ditto for PostScript */
+#ifdef DEBUG
+ int i;
+ for (i = 8; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PostScript",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+#ifndef NOPCLSCAN
+ } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) {
+ /* HP PCL printer language */
+#ifdef DEBUG
+ int i;
+ for (i = 8; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PCL",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+ }
+#endif /* NOPCLSCAN */
+#ifndef NOPJLSCAN
+ else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) {
+ /* Ditto for PJL Job printer header */
+#ifdef DEBUG
+ int i;
+ for (i = 2; i < count; i++) {
+ if (buf[i] < '!') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ debug(F110,"scanfile PJL Job printer header",buf,0);
+#endif /* DEBUG */
+ binary = 1;
+ break;
+#endif /* NOPJLSCAN */
+ }
+ }
+
+#ifdef UNICODE
+ if (bytes == 0 && count > 1) {
+ int incl_cnt = 0;
+
+ /* First look for BOM */
+
+ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
+ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
+
+ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
+ rc = FT_UCS2;
+ val = 0;
+ debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
+ rc = FT_UCS2;
+ val = 1;
+ debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
+ (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
+ rc = FT_UTF8;
+ debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc);
+ incl_cnt++;
+ }
+ if (incl_cnt) { /* Have BOM */
+ bytes += count;
+ goto xscanfile;
+ }
+ }
+#endif /* UNICODE */
+
+ bytes += count; /* Count bytes read */
+ eof = feof(fp); /* Flag for at EOF */
+
+ for (i = 0; i < count; i++) { /* For each byte... */
+ c = (unsigned)buf[i]; /* For ease of reference */
+ if (!c) { /* Zero byte? */
+#ifdef EVENMAX
+ if (i&1) /* In odd position */
+ oddzero++;
+ else
+ evenzero++; /* In even position */
+#endif /* EVENMAX */
+ runzero++;
+ } else { /* Not a zero byte */
+ if (runzero > runmax)
+ runmax = runzero;
+ if (runmax > 2) /* That's all we need to be certain */
+ break; /* it's a binary file. */
+ runzero = 0;
+ }
+
+#ifdef COMMENT
+#ifdef EVENMAX
+
+/* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire */
+
+ if (i > 1) { /* Look for runs of alternating chars */
+ if (i&1) {
+ if (c == buf[i-2]) { /* In odd positions */
+ oddrun++;
+ oddbyte = c;
+ } else {
+ oddmax = oddrun;
+ oddmaxbyte = oddbyte;
+ }
+ } else { /* and even positions */
+ if (c == buf[i-2]) {
+ evenrun++;
+ evenbyte = c;
+ } else {
+ evenmax = evenrun;
+ evenmaxbyte = evenbyte;
+ }
+ }
+ }
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+ if ((c & 0x80) == 0) { /* We have a 7-bit byte */
+#ifdef UNICODE
+ if (i > 0 && c == 10) { /* Linefeed */
+ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
+ else if (buf[i-1] == 13) crlf++; /* or by CR... */
+ }
+#endif /* UNICODE */
+ if (c < ' ') { /* Check for CO controls */
+ if (c != LF && c != CR && c != HT && c != FF) {
+ c0controls++;
+ if (c != ESC && c != SO && c != SI)
+ c0noniso++;
+ }
+ if ((c == '\032') /* Ctrl-Z */
+#ifdef COMMENT
+ && eof && (i >= count - 2)
+#endif /* COMMENT */
+ ) {
+ c0controls--;
+ c0noniso--;
+#ifdef CK_CTRLZ
+ if (eofmethod == XYEOF_Z && txtcz == 0) {
+ if (c0controls == 0) /* All text prior to Ctrl-Z */
+ txtcz = 1;
+ }
+#endif /* CK_CTRLZ */
+ }
+ }
+#ifdef UNICODE
+ if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
+ utf8state = 0;
+ debug(F000,"scanfile","7-bit byte in UTF8 sequence",c);
+ notutf8++; /* Then it's not UTF-8 */
+ continue;
+ }
+#endif /* UNICODE */
+ } else { /* We have an 8-bit byte */
+ eightbit++; /* Count it */
+ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
+ c1controls++;
+#ifdef UNICODE
+ if (!notutf8) { /* If it might still be UTF8... */
+ switch (utf8state) { /* Enter the UTF-8 state machine */
+ case 0: /* First byte... */
+ if ((c & 0xE0) == 0xC0) { /* Tells number of */
+ utf8state = 1; /* subsequent bytes */
+ } else if ((c & 0xF0) == 0xE0) {
+ utf8state = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ utf8state = 3;
+ } else {
+ notutf8++;
+ }
+ break;
+ case 1: /* Subsequent byte */
+ case 2:
+ case 3:
+ if ((c & 0xC0) != 0x80) { /* Must start with 10 */
+ debug(F000,"scanfile",
+ "bad byte in UTF8 sequence",c);
+ notutf8++;
+ break;
+ }
+ utf8state--; /* Good, one less in this sequence */
+ break;
+ default: /* Shouldn't happen */
+ debug(F111,"scanfile","bad UTF8 state",utf8state);
+ notutf8++;
+ }
+ }
+#endif /* UNICODE */
+ }
+ }
+ }
+ fclose(fp); /* Close the file */
+ debug(F101,"scanfile bytes","",bytes);
+
+ if (bytes == 0) /* If nothing was read */
+ return(-1); /* we're done. */
+
+#ifdef EVENMAX
+ /* In case we had a run that never broke... */
+#ifdef COMMENT
+ if (oddmax == 0) {
+ oddmax = oddrun;
+ oddmaxbyte = oddbyte;
+ }
+ if (evenmax == 0) {
+ evenmax = evenrun;
+ evenmaxbyte = evenbyte;
+ }
+#endif /* COMMENT */
+ if (runmax == 0) {
+ runmax = runzero;
+ }
+#endif /* EVENMAX */
+
+#ifdef UNICODE
+ if (bytes > 100) /* Bytes is not 0 */
+ pctzero = (evenzero + oddzero) / (bytes / 100);
+ else
+ pctzero = ((evenzero + oddzero) * 100) / bytes;
+#endif /* UNICODE */
+
+#ifdef DEBUG
+ if (deblog) { /* If debugging, dump statistics */
+ debug(F101,"scanfile c0controls ","",c0controls);
+ debug(F101,"scanfile c0noniso ","",c0noniso);
+ debug(F101,"scanfile c1controls ","",c1controls);
+ debug(F101,"scanfile eightbit ","",eightbit);
+#ifdef UNICODE
+ debug(F101,"scanfile crlf ","",crlf);
+ debug(F101,"scanfile lfnul ","",lfnul);
+ debug(F101,"scanfile notutf8 ","",notutf8);
+ debug(F101,"scanfile evenzero ","",evenzero);
+ debug(F101,"scanfile oddzero ","",oddzero);
+ debug(F101,"scanfile even/odd ","",(evenzero / (oddzero + 1)));
+ debug(F101,"scanfile odd/even ","",(oddzero / (evenzero + 1)));
+ debug(F101,"scanfile pctzero ","",pctzero);
+#endif /* UNICODE */
+#ifdef COMMENT
+#ifdef EVENMAX
+ debug(F101,"scanfile oddmax ","",oddmax);
+ debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte);
+ debug(F101,"scanfile evenmax ","",evenmax);
+ debug(F101,"scanfile evenmaxbyte","",evenmaxbyte);
+#endif /* EVENMAX */
+#endif /* COMMENT */
+ debug(F101,"scanfile runmax ","",runmax);
+ }
+#endif /* DEBUG */
+
+#ifdef UNICODE
+ x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
+
+ if (runmax > 2) { /* File has run of more than 2 NULs */
+ debug(F100,"scanfile BIN runmax","",0);
+ rc = FT_BIN; /* so it can't be any kind of text. */
+ goto xscanfile;
+
+ } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
+ goto xscanfile; /* File starts with a BOM */
+
+ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
+ if (runmax > 0) { /* and runs of NULs */
+ debug(F100,"scanfile BIN (nnUTF8) runmax","",0);
+ rc = FT_BIN; /* UTF-8 doesn't have NULs */
+ } else { /* No NULs */
+ debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0);
+ rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
+ }
+ goto xscanfile;
+ }
+/*
+ For UCS-2 detection, see if the text contains lines delimited by
+ ASCII controls and containing spaces, ASCII digits, or other ASCII
+ characters, thus forcing the presence of a certain percentage of zero bytes.
+ For this purpose require 20% zero bytes, with at least six times as many
+ in even (odd) positions as in odd (even) positions.
+*/
+ if ((evenzero >= x && oddzero == 0) ||
+ ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) &&
+ (crlf == 0) &&
+ (lfnul > 1))
+ ) {
+ debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0);
+ rc = FT_UCS2;
+ val = 0;
+ } else if ((evenzero == 0 && oddzero >= x) ||
+ ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) &&
+ (crlf == 0) &&
+ (lfnul > 1))
+ ) {
+ debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0);
+ rc = FT_UCS2;
+ val = 1;
+
+#ifdef COMMENT
+#ifdef EVENMAX
+/*
+ If the tests above fail, we still might have UCS-2 if there are significant
+ runs of identical bytes in alternating positions, but only if it also has
+ unusual C0 controls (otherwise we'd pick up hex files here). NOTE: We
+ don't actually do this -- EVENMAX is not defined (see comments above at
+ first occurrence of EVENMAX).
+*/
+ } else if (c0noniso && evenmax > bytes / 4) {
+ debug(F100,"scanfile UCS2 BE (evenmax)","",0);
+ rc = FT_UCS2;
+ val = 0;
+ } else if (c0noniso && oddmax > bytes / 4) {
+ debug(F100,"scanfile UCS2 LE (evenmax)","",0);
+ rc = FT_UCS2;
+ val = 1;
+#endif /* EVENMAX */
+#endif /* COMMENT */
+
+ }
+/*
+ It seems to be UCS-2 but let's be more certain since there is no BOM...
+ If the number of 7- and 8-bit characters is approximately equal, it might
+ be a compressed file. In this case we decide based on the name.
+*/
+ if (rc == FT_UCS2) {
+ if (eightbit > 0) {
+ int j, k;
+ j = (c1controls * 100) / (c0controls + 1);
+ debug(F101,"scanfile c1/c0 ","",j);
+ k = (bytes * 100) / eightbit;
+ debug(F101,"scanfile pct 8bit ","",k);
+ if (k > 40 && k < 60 && j > 60) {
+ if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) {
+ debug(F110,"scanfile 8-bit BIN compressed",name,0);
+ rc = FT_BIN;
+ goto xscanfile;
+ }
+ }
+ }
+ /* Small file - not enough evidence unless ... */
+
+ if (bytes < 100) {
+ if (oddzero != 0 && evenzero != 0) {
+ debug(F100,"scanfile small UCS2 doubtful","",0);
+ rc = FT_BIN;
+ goto xscanfile;
+ } else if (oddzero == 0 && evenzero == 0) {
+ rc = eightbit ? FT_8BIT : FT_7BIT;
+ }
+ }
+ goto xscanfile; /* Seems to be UCS-2 */
+ }
+
+/* If none of the above, it's probably not Unicode. */
+
+ if (!eightbit) { /* It's 7-bit */
+ if (c0controls) { /* This would be strange */
+ if ((c0noniso > 0) && (txtcz == 0)) {
+ debug(F100,"scanfile 7-bit BIN (c0coniso)","",0);
+ rc = FT_BIN;
+ } else {
+ debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+ } else { /* 7-bit text */
+ debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0);
+ rc = FT_7BIT;
+ }
+ } else if (!c0noniso || txtcz) { /* 8-bit text */
+ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else { /* 8-bit binary */
+ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ }
+
+#else /* !UNICODE */
+
+ if (c0noniso) {
+ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ } else if (eightbit) {
+ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else {
+ debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+
+#endif /* UNICODE */
+
+ xscanfile:
+ if (flag) *flag = val;
+ debug(F101,"scanfile result ","",rc);
+ return(rc);
+}
+
+/*
+ scanstring - like scan file but for a string.
+ This is just a quick butchery of scanfile without thinking too much.
+*/
+int
+scanstring(s) char * s; {
+ int x, val = -1, count = 0; /* Workers */
+ int rc = -1; /* Return code */
+ int pv = -1; /* Pattern-match value */
+ int bytes = 0; /* Total byte count */
+#ifdef UNICODE
+ unsigned int c0, c1; /* First 2 file bytes (for BOM) */
+#endif /* UNICODE */
+ extern int pipesend, filepeek;
+
+ register int i; /* Loop control */
+ int readsize = 0; /* How much to read */
+ int eightbit = 0; /* Number of bytes with 8th bit on */
+ int c0controls = 0; /* C0 non-text control-char counter */
+ int c0noniso = 0; /* C0 non-ISO control-char counter */
+ int c1controls = 0; /* C1 control-character counter */
+ unsigned int c; /* Current character */
+ int runmax = 0; /* Longest run of 0 bytes */
+ int runzero = 0; /* Run of 0 bytes */
+ int pctzero = 0; /* Percentage of 0 bytes */
+ int txtcz = 0;
+
+#ifdef UNICODE
+ int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
+ int utf8state = 0; /* UTF-8 recognizer state */
+ int oddzero = 0; /* Number of 0 bytes in odd postions */
+ int evenzero = 0; /* and in even positions */
+ int lfnul = 0; /* Number of <LF><NUL> sequences */
+ int crlf = 0; /* Number of <CRLF> sequences */
+#else
+ int notutf8 = 1;
+#endif /* UNICODE */
+
+ char * buf = s;
+ if (!s) s = "";
+ count = strlen(s);
+
+#ifdef UNICODE
+ if (bytes == 0 && count > 1) {
+ int incl_cnt = 0;
+
+ /* First look for BOM */
+
+ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
+ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
+
+ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
+ rc = FT_UCS2;
+ val = 0;
+ debug(F111,"scanstring UCS2 BOM BE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
+ rc = FT_UCS2;
+ val = 1;
+ debug(F111,"scanstring UCS2 BOM LE",ckitoa(val),rc);
+ incl_cnt++;
+ } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
+ (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
+ rc = FT_UTF8;
+ debug(F111,"scanstring UTF8 BOM",ckitoa(val),rc);
+ incl_cnt++;
+ }
+ if (incl_cnt) { /* Have BOM */
+ bytes += count;
+ goto xscanstring;
+ }
+ }
+#endif /* UNICODE */
+
+ bytes += count; /* Count bytes read */
+
+ for (i = 0; i < count; i++) { /* For each byte... */
+ c = (unsigned)buf[i]; /* For ease of reference */
+ if (!c) { /* Zero byte? */
+ goto xscanstring; /* Null terminated string */
+ }
+ if ((c & 0x80) == 0) { /* We have a 7-bit byte */
+#ifdef UNICODE
+ if (i > 0 && c == 10) { /* Linefeed */
+ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
+ else if (buf[i-1] == 13) crlf++; /* or by CR... */
+ }
+#endif /* UNICODE */
+ if (c < ' ') { /* Check for CO controls */
+ if (c != LF && c != CR && c != HT && c != FF) {
+ c0controls++;
+ if (c != ESC && c != SO && c != SI)
+ c0noniso++;
+ }
+ if ((c == '\032') /* Ctrl-Z */
+ ) {
+ c0controls--;
+ c0noniso--;
+ }
+ }
+#ifdef UNICODE
+ if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
+ utf8state = 0;
+ debug(F000,"scanstring","7-bit byte in UTF8 sequence",c);
+ notutf8++; /* Then it's not UTF-8 */
+ continue;
+ }
+#endif /* UNICODE */
+ } else { /* We have an 8-bit byte */
+ eightbit++; /* Count it */
+ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
+ c1controls++;
+#ifdef UNICODE
+ if (!notutf8) { /* If it might still be UTF8... */
+ switch (utf8state) { /* Enter the UTF-8 state machine */
+ case 0: /* First byte... */
+ if ((c & 0xE0) == 0xC0) { /* Tells number of */
+ utf8state = 1; /* subsequent bytes */
+ } else if ((c & 0xF0) == 0xE0) {
+ utf8state = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ utf8state = 3;
+ } else {
+ notutf8++;
+ }
+ break;
+ case 1: /* Subsequent byte */
+ case 2:
+ case 3:
+ if ((c & 0xC0) != 0x80) { /* Must start with 10 */
+ debug(F000,"scanstring",
+ "bad byte in UTF8 sequence",c);
+ notutf8++;
+ break;
+ }
+ utf8state--; /* Good, one less in this sequence */
+ break;
+ default: /* Shouldn't happen */
+ debug(F111,"scanstring","bad UTF8 state",utf8state);
+ notutf8++;
+ }
+ }
+#endif /* UNICODE */
+ }
+ }
+ if (bytes == 0) /* If nothing was read */
+ return(-1); /* we're done. */
+
+#ifdef UNICODE
+ if (bytes > 100) /* Bytes is not 0 */
+ pctzero = (evenzero + oddzero) / (bytes / 100);
+ else
+ pctzero = ((evenzero + oddzero) * 100) / bytes;
+#endif /* UNICODE */
+
+#ifdef UNICODE
+ x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
+
+ if (runmax > 2) { /* File has run of more than 2 NULs */
+ debug(F100,"scanstring BIN runmax","",0);
+ rc = FT_BIN; /* so it can't be any kind of text. */
+ goto xscanstring;
+
+ } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
+ goto xscanstring; /* File starts with a BOM */
+
+ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
+ if (runmax > 0) { /* and runs of NULs */
+ debug(F100,"scanstring BIN (nnUTF8) runmax","",0);
+ rc = FT_BIN; /* UTF-8 doesn't have NULs */
+ } else { /* No NULs */
+ debug(F100,"scanstring UTF8 (nnUTF8 + runmax == 0)","",0);
+ rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
+ }
+ goto xscanstring;
+ }
+/*
+ It seems to be UCS-2 but let's be more certain since there is no BOM...
+ If the number of 7- and 8-bit characters is approximately equal, it might
+ be a compressed file. In this case we decide based on the name.
+*/
+ if (rc == FT_UCS2) {
+ if (bytes < 100) {
+ if (oddzero != 0 && evenzero != 0) {
+ debug(F100,"scanstring small UCS2 doubtful","",0);
+ rc = FT_BIN;
+ goto xscanstring;
+ } else if (oddzero == 0 && evenzero == 0) {
+ rc = eightbit ? FT_8BIT : FT_7BIT;
+ }
+ }
+ goto xscanstring; /* Seems to be UCS-2 */
+ }
+
+/* If none of the above, it's probably not Unicode. */
+
+ if (!eightbit) { /* It's 7-bit */
+ if (c0controls) { /* This would be strange */
+ if ((c0noniso > 0) && (txtcz == 0)) {
+ debug(F100,"scanstring 7-bit BIN (c0coniso)","",0);
+ rc = FT_BIN;
+ } else {
+ debug(F100,"scanstring 7-bit ISO2022 TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+ } else { /* 7-bit text */
+ debug(F100,"scanstring 7-bit TEXT (no c0controls)","",0);
+ rc = FT_7BIT;
+ }
+ } else if (!c0noniso || txtcz) { /* 8-bit text */
+ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else { /* 8-bit binary */
+ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ }
+
+#else /* !UNICODE */
+
+ if (c0noniso) {
+ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
+ rc = FT_BIN;
+ } else if (eightbit) {
+ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
+ rc = FT_8BIT;
+ val = c1controls ? 1 : 0;
+ } else {
+ debug(F100,"scanstring 7-bit TEXT (no c0noniso)","",0);
+ rc = FT_7BIT;
+ }
+
+#endif /* UNICODE */
+
+ xscanstring:
+ debug(F101,"scanstring result ","",rc);
+ return(rc);
+}
+
+
+
+/* F I L E S E L E C T -- Select this file for sending */
+
+int
+#ifdef CK_ANSIC
+fileselect(
+ char *f, char *sa, char *sb, char *sna, char *snb,
+ CK_OFF_T minsiz, CK_OFF_T maxsiz,
+ int nbu, int nxlist,
+ char ** xlist
+)
+#else
+fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
+ char *f,*sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
+ int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+/* fileselect */ {
+ char *fdate;
+ int n;
+ CK_OFF_T z;
+
+ debug(F111,"fileselect minsiz",ckfstoa(minsiz),minsiz);
+ debug(F111,"fileselect maxsiz",ckfstoa(maxsiz),maxsiz);
+ debug(F111,"fileselect (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
+
+ if (!sa) sa = "";
+ if (!sb) sb = "";
+ if (!sna) sna = "";
+ if (!snb) snb = "";
+
+#ifdef CKSYMLINK
+#ifndef NOICP
+#ifndef NOXFER
+ if (nolinks) {
+ CK_OFF_T zz;
+ zz = zgetfs(f);
+ debug(F111,"fileselect NOLINKS zgetfs",f,zz);
+ if (zz < (CK_OFF_T)0)
+ return(0);
+ debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link);
+ if (zgfs_link)
+ return(0);
+ }
+#endif /* NOXFER */
+#endif /* NOICP */
+#endif /* CKSYMLINK */
+
+ debug(F110,"fileselect",f,0);
+ if (*sa || *sb || *sna || *snb) {
+ fdate = zfcdat(f); /* Date/time of this file */
+ if (!fdate) fdate = "";
+ n = strlen(fdate);
+ debug(F111,"fileselect fdate",fdate,n);
+ if (n != 17) /* Failed to get it */
+ return(1);
+ /* /AFTER: */
+ if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) {
+ debug(F110,"fileselect sa",sa,0);
+ /* tlog(F110,"Skipping (too old)",f,0); */
+ return(0);
+ }
+ /* /BEFORE: */
+ if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) {
+ debug(F110,"fileselect sb",sb,0);
+ /* tlog(F110,"Skipping (too new)",f,0); */
+ return(0);
+ }
+ /* /NOT-AFTER: */
+ if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) {
+ debug(F110,"fileselect sna",sna,0);
+ /* tlog(F110,"Skipping (too new)",f,0); */
+ return(0);
+ }
+ /* /NOT-BEFORE: */
+ if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) {
+ debug(F110,"fileselect snb",snb,0);
+ /* tlog(F110,"Skipping (too old)",f,0); */
+ return(0);
+ }
+ }
+ /* Smaller or larger */
+ if (minsiz > (CK_OFF_T)-1 || maxsiz > (CK_OFF_T)-1) {
+ z = zchki(f); /* Get size */
+ debug(F101,"fileselect filesize","",z);
+ if (z < (CK_OFF_T)0)
+ return(1);
+ if ((minsiz > (CK_OFF_T)-1) && (z >= minsiz)) {
+ debug(F111,"fileselect minsiz skipping",f,minsiz);
+ /* tlog(F111,"Skipping (too big)",f,z); */
+ return(0);
+ }
+ if ((maxsiz > (CK_OFF_T)-1) && (z <= maxsiz)) {
+ debug(F111,"fileselect maxsiz skipping",f,maxsiz);
+ /* tlog(F110,"Skipping (too small)",f,0); */
+ return(0);
+ }
+ }
+ if (nbu) { /* Skipping backup files? */
+ if (ckmatch(
+#ifdef CKREGEX
+ "*.~[0-9]*~" /* Not perfect but close enough. */
+#else
+ "*.~*~" /* Less close. */
+#endif /* CKREGEX */
+ ,f,filecase,1)) {
+ debug(F110,"fileselect skipping backup",f,0);
+ return(0);
+ }
+ }
+ for (n = 0; xlist && n < nxlist; n++) {
+ if (!xlist[n]) {
+ debug(F101,"fileselect xlist empty",0,n);
+ break;
+ }
+ if (ckmatch(xlist[n],f,filecase,1)) {
+ debug(F111,"fileselect xlist",xlist[n],n);
+ debug(F110,"fileselect skipping",f,0);
+ return(0);
+ }
+ }
+ if (xfiletype > -1) {
+ n = scanfile(f,NULL,nscanfile);
+ if (n < 0) {
+ n = binary ? 1 : 0;
+ } else {
+ n = (n == FT_BIN) ? 1 : 0;
+ }
+ if (n != xfiletype)
+ return(0);
+ }
+ debug(F110,"fileselect selecting",f,0);
+ return(1);
+}
+
+
+#ifdef TCPSOCKET
+#ifdef NT
+extern int WSASafeToCancel;
+#endif /* NT */
+#endif /* TCPSOCKET */
+
+VOID
+setflow() {
+ extern int flow, autoflow, mdmtyp, cxtype, cxflow[];
+#ifndef NODIAL
+ extern int dialcapas, dialfc;
+ extern MDMINF * modemp[];
+ MDMINF * p = NULL;
+ long bits = 0;
+#endif /* NODIAL */
+
+ debug(F101,"setflow autoflow","",autoflow);
+
+/* #ifdef COMMENT */
+/* WHY WAS THIS COMMENTED OUT? */
+ if (!autoflow) /* Only if FLOW is AUTO */
+ return;
+/* #endif */ /* COMMENT */
+
+ debug(F101,"setflow local","",local);
+ debug(F101,"setflow network","",network);
+ debug(F101,"setflow cxtype","",cxtype);
+
+#ifdef TN_COMPORT
+ if (network && istncomport()) {
+ flow = cxflow[CXT_MODEM];
+ debug(F101,"setflow TN_COMPORT flow","",flow);
+ return;
+ }
+#endif /* TN_COMPORT */
+
+ if (network || !local || cxtype == CXT_DIRECT) {
+ flow = cxflow[cxtype]; /* Set appropriate flow control */
+ debug(F101,"setflow flow","",flow);
+ return;
+ }
+ if (cxtype != CXT_MODEM) /* Connection type should be modem */
+ return;
+
+#ifndef NODIAL
+ bits = dialcapas; /* Capability bits */
+ if (!bits) { /* No bits? */
+ p = modemp[mdmtyp]; /* Look in modem info structure */
+ if (p)
+ bits = p->capas;
+ }
+ if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */
+#ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */
+ if (bits & CKD_HW) /* and modem can do it too */
+ flow = FLO_RTSC; /* then switch to RTS/CTS */
+ else /* otherwise */
+ flow = FLO_XONX; /* use Xon/Xoff. */
+#else
+#ifndef NEXT
+#ifndef IRIX
+ flow = FLO_XONX; /* Use Xon/Xoff. */
+#endif /* IRIX */
+#endif /* NEXT */
+#endif /* CK_RTSCTS */
+ }
+#endif /* NODIAL */
+ debug(F101,"setflow modem flow","",flow);
+ return;
+}
+
+#ifndef NOLOCAL
+#ifdef CK_TRIGGER
+
+/* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */
+/*
+ Returns -1 if trigger not found, or else the trigger index, 0 or greater.
+ (Replace with fancier and more efficient matcher later...)
+ NOTE: to prevent unnecessary function call overhead, call this way:
+
+ x = tt_trigger[0] ? autoexitchk(c) : -1;
+
+*/
+int
+#ifdef CK_ANSIC
+autoexitchk(CHAR c)
+#else
+autoexitchk(c) CHAR c;
+#endif /* CK_ANSIC */
+/* autoexitchk */ {
+ extern CHAR * tt_trmatch[];
+ extern char * tt_trigger[];
+ int i;
+ for (i = 0; i < TRIGGERS; i++) {
+ if (!tt_trigger[i]) { /* No more triggers in list */
+ break;
+ } else if (*tt_trigger[i]) {
+ if (!tt_trmatch[i]) /* Just starting? */
+ tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
+ if (c == *tt_trmatch[i]) { /* Compare this character */
+ tt_trmatch[i]++; /* It matches */
+ if (!*tt_trmatch[i]) { /* End of match string? */
+ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
+ debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
+ return(i); /* and return success */
+ }
+ } else /* No match */
+ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
+ } /* and go on the next match string */
+ }
+ return(-1); /* No match found */
+}
+#endif /* CK_TRIGGER */
+
+#ifndef NOSHOW
+/* S H O M D M -- Show modem signals */
+
+VOID
+shomdm() {
+/*
+ Note use of "\r\n" to make sure this report prints right, even when
+ called during CONNECT mode.
+*/
+ int y;
+ y = ttgmdm();
+ switch (y) {
+ case -3: printf(
+ "Modem signals unavailable in this version of Kermit\r\n");
+ break;
+ case -2: printf("No modem control for this device\r\n"); break;
+ case -1: printf("Modem signals unavailable\r\n"); break;
+ default:
+#ifndef MAC
+ printf(
+ " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off");
+ printf(
+ " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
+#endif /* MAC */
+ printf(
+ " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
+#ifndef STRATUS
+#ifndef MAC
+ printf(
+ " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off");
+#endif /* MAC */
+ printf(
+ " Data Terminal Ready (DTR): %s\r\n",
+#ifdef NT
+ "(unknown)"
+#else /* NT */
+ (y & BM_DTR) ? "On": "Off"
+#endif /* NT */
+ );
+#ifndef MAC
+ printf(
+ " Request To Send (RTS): %s\r\n",
+#ifdef NT
+ "(unknown)"
+#else /* NT */
+ (y & BM_RTS) ? "On": "Off"
+#endif /* NT */
+ );
+#endif /* MAC */
+#endif /* STRATUS */
+ }
+#ifdef BETADEBUG
+#ifdef CK_TAPI
+ if (tttapi && !tapipass) {
+ LPDEVCFG lpDevCfg = NULL;
+ LPCOMMCONFIG lpCommConfig = NULL;
+ LPMODEMSETTINGS lpModemSettings = NULL;
+ DCB * lpDCB = NULL;
+
+ if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
+ &lpCommConfig,&lpDCB)) {
+ printf("\n");
+ cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
+ lpCommConfig,lpDCB);
+ }
+ }
+#endif /* CK_TAPI */
+#endif /* BETADEBUG */
+}
+#endif /* NOSHOW */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+/* S D E B U -- Record spar results in debugging log */
+
+VOID
+sdebu(len) int len; {
+ debug(F111,"spar: data",(char *) rdatap,len);
+ debug(F101," spsiz ","", spsiz);
+ debug(F101," timint","",timint);
+ debug(F101," npad ","", npad);
+ debug(F101," padch ","", padch);
+ debug(F101," seol ","", seol);
+ debug(F101," ctlq ","", ctlq);
+ debug(F101," ebq ","", ebq);
+ debug(F101," ebqflg","",ebqflg);
+ debug(F101," bctr ","", bctr);
+ debug(F101," rptq ","", rptq);
+ debug(F101," rptflg","",rptflg);
+ debug(F101," lscapu","",lscapu);
+ debug(F101," atcapu","",atcapu);
+ debug(F101," lpcapu","",lpcapu);
+ debug(F101," swcapu","",swcapu);
+ debug(F101," wslotn","", wslotn);
+ debug(F101," whatru","", whatru);
+}
+/* R D E B U -- Debugging display of rpar() values */
+
+VOID
+rdebu(d,len) CHAR *d; int len; {
+ debug(F111,"rpar: data",d,len);
+ debug(F101," rpsiz ","", xunchar(d[0]));
+ debug(F101," rtimo ","", rtimo);
+ debug(F101," mypadn","",mypadn);
+ debug(F101," mypadc","",mypadc);
+ debug(F101," eol ","", eol);
+ debug(F101," ctlq ","", ctlq);
+ debug(F101," sq ","", sq);
+ debug(F101," ebq ","", ebq);
+ debug(F101," ebqflg","",ebqflg);
+ debug(F101," bctr ","", bctr);
+ debug(F101," rptq ","", d[8]);
+ debug(F101," rptflg","",rptflg);
+ debug(F101," capas ","", capas);
+ debug(F101," bits ","",d[capas]);
+ debug(F101," lscapu","",lscapu);
+ debug(F101," atcapu","",atcapu);
+ debug(F101," lpcapu","",lpcapu);
+ debug(F101," swcapu","",swcapu);
+ debug(F101," wslotr","", wslotr);
+ debug(F101," rpsiz(extended)","",rpsiz);
+}
+
+#ifdef COMMENT
+/* C H K E R R -- Decide whether to exit upon a protocol error */
+
+VOID
+chkerr() {
+ if (backgrd && !server) fatal("Protocol error");
+}
+#endif /* COMMENT */
+#endif /* NOXFER */
+
+/* F A T A L -- Fatal error message */
+
+VOID
+fatal(msg) char *msg; {
+ extern int initflg;
+ static int initing = 0;
+ if (!msg) msg = "";
+ debug(F111,"fatal",msg,initflg);
+
+ if (!initflg) { /* If called from prescan */
+ if (initing) /* or called from sysinit() */
+ exit(253);
+ initing = 1;
+ sysinit();
+ }
+
+ debug(F111,"fatal",msg,xitsta);
+ tlog(F110,"Fatal:",msg,0L);
+#ifdef VMS
+ if (strncmp(msg,"%CKERMIT",8))
+ conol("%CKERMIT-E-FATAL, ");
+ conoll(msg);
+#else /* !VMS */
+ conoll(msg);
+#endif /* VMS */
+#ifdef OS2
+#ifndef NOXFER
+ if (xfrbel) {
+ bleep(BP_FAIL);
+ sleep(1);
+ bleep(BP_FAIL);
+ }
+#endif /* NOXFER */
+
+#endif /* OS2 */
+ doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */
+}
+
+#ifndef NOXFER
+/* B L D L E N -- Make length-encoded copy of string */
+
+char *
+bldlen(str,dest) char *str, *dest; {
+ int len;
+ len = (int)strlen(str);
+ if (len > 94)
+ *dest = SP;
+ else
+ *dest = (char) tochar(len);
+ strcpy(dest+1,str); /* Checked below in setgen() */
+ return(dest+len+1);
+}
+
+
+/* S E T G E N -- Construct a generic command */
+/*
+ Call with Generic command character followed by three string arguments.
+ Trailing strings are allowed to be empty (""). Each string except the last
+ non-empty string must be less than 95 characters long. The final nonempty
+ string is allowed to be longer.
+*/
+CHAR
+#ifdef CK_ANSIC
+setgen(char type, char * arg1, char * arg2, char * arg3)
+#else
+setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
+#endif /* CK_ANSIC */
+/* setgen */ {
+ char *upstr, *cp;
+#ifdef DYNAMIC
+ if (!cmdstr)
+ if (!(cmdstr = malloc(MAXSP + 1)))
+ fatal("setgen: can't allocate memory");
+#endif /* DYNAMIC */
+
+ cp = cmdstr;
+ *cp++ = type;
+ *cp = NUL;
+ if (!arg1) arg1 = "";
+ if (!arg2) arg2 = "";
+ if (!arg3) arg3 = "";
+ if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
+ if (*arg1 != NUL) {
+ upstr = bldlen(arg1,cp);
+ if (*arg2 != NUL) {
+ upstr = bldlen(arg2,upstr);
+ if (*arg3 != NUL) bldlen(arg3,upstr);
+ }
+ }
+ cmarg = cmdstr;
+ debug(F110,"setgen",cmarg,0);
+ return('g');
+ }
+ return('E');
+}
+#endif /* NOXFER */
+
+#ifndef NOMSEND
+static char *mgbufp = NULL;
+
+/* F N P A R S E -- */
+
+/*
+ Argument is a character string containing one or more filespecs.
+ This function breaks the string apart into an array of pointers, one
+ to each filespec, and returns the number of filespecs. Used by server
+ when it receives a GET command to allow it to process multiple file
+ specifications in one transaction. Sets cmlist to point to a list of
+ file pointers, exactly as if they were command line arguments.
+
+ This version of fnparse treats spaces as filename separators. If your
+ operating system allows spaces in filenames, you'll need a different
+ separator.
+
+ This version of fnparse mallocs a string buffer to contain the names. It
+ cannot assume that the string that is pointed to by the argument is safe.
+*/
+int
+fnparse(string) char *string; {
+ char *p, *s, *q;
+ int r = 0, x; /* Return code */
+#ifdef RECURSIVE
+ debug(F111,"fnparse",string,recursive);
+#endif /* RECURSIVE */
+
+ if (mgbufp) free(mgbufp); /* Free this from last time. */
+ mgbufp = malloc((int)strlen(string)+2);
+ if (!mgbufp) {
+ debug(F100,"fnparse malloc error","",0);
+ return(0);
+ }
+#ifndef NOICP
+#ifndef NOSPL
+ ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */
+#endif /* NOSPL */
+#endif /* NOICP */
+ s = string; /* Input string */
+ p = q = mgbufp; /* Point to the copy */
+ r = 0; /* Initialize our return code */
+ while (*s == SP || *s == HT) /* Skip leading spaces and tabs */
+ s++;
+ for (x = strlen(s); /* Strip trailing spaces */
+ (x > 1) && (s[x-1] == SP || s[x-1] == HT);
+ x--)
+ s[x-1] = NUL;
+ while (1) { /* Loop through rest of string */
+ if (*s == CMDQ) { /* Backslash (quote character)? */
+ if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
+ *q++ = (char) x; /* Numeric backslash code, ok */
+ } else { /* Just let it quote next char */
+ s++; /* get past the backslash */
+ *q++ = *s++; /* deposit next char */
+ }
+ continue;
+ } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
+ *q++ = NUL; /* End of output filename. */
+ msfiles[r] = p; /* Add this filename to the list */
+ debug(F111,"fnparse",msfiles[r],r);
+ r++; /* Count it */
+ if (*s == NUL) break; /* End of string? */
+ while (*s == SP) s++; /* Skip repeated spaces */
+ p = q; /* Start of next name */
+ continue;
+ } else *q++ = *s; /* Otherwise copy the character */
+ s++; /* Next input character */
+ }
+ debug(F101,"fnparse r","",r);
+ msfiles[r] = ""; /* Put empty string at end of list */
+ cmlist = msfiles;
+ return(r);
+}
+#endif /* NOMSEND */
+
+char * /* dbchr() for DEBUG SESSION */
+dbchr(c) int c; {
+ static char s[8];
+ char *cp = s;
+
+ c &= 0xff;
+ if (c & 0x80) { /* 8th bit on */
+ *cp++ = '~';
+ c &= 0x7f;
+ }
+ if (c < SP) { /* Control character */
+ *cp++ = '^';
+ *cp++ = (char) ctl(c);
+ } else if (c == DEL) {
+ *cp++ = '^';
+ *cp++ = '?';
+ } else { /* Printing character */
+ *cp++ = (char) c;
+ }
+ *cp = '\0'; /* Terminate string */
+ cp = s; /* Return pointer to it */
+ return(cp);
+}
+
+/* C K H O S T -- Get name of local host (where C-Kermit is running) */
+
+/*
+ Call with pointer to buffer to put hostname in, and length of buffer.
+ Copies hostname into buffer on success, puts null string in buffer on
+ failure.
+*/
+#ifdef BSD44
+#define BSD4
+#undef ATTSV
+#endif /* BSD44 */
+
+#ifdef SVORPOSIX
+#ifndef BSD44
+#ifndef apollo
+#include <sys/utsname.h>
+#endif /* apollo */
+#endif /* BSD44 */
+#else
+#ifdef BELLV10
+#include <utsname.h>
+#endif /* BELLV10 */
+#endif /* SVORPOSIX*/
+
+#ifdef CKSYSLOG
+extern char uidbuf[], * clienthost;
+#endif /* CKSYSLOG */
+
+VOID
+ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
+
+#ifndef NOPUSH
+ extern int nopush;
+#ifndef NOSERVER
+ extern int en_hos;
+#endif /* NOSERVER */
+#endif /* NOPUSH */
+
+#ifdef pdp11
+ *vvbuf = NUL;
+#else /* Everything else - rest of this routine */
+
+ char *g;
+ int havefull = 0;
+#ifdef VMS
+ int x;
+#endif /* VMS */
+
+#ifdef SVORPOSIX
+#ifndef BSD44
+#ifndef _386BSD
+#ifndef APOLLOSR10
+ struct utsname hname;
+#endif /* APOLLOSR10 */
+#endif /* _386BSD */
+#endif /* BSD44 */
+#endif /* SVORPOSIX */
+#ifdef datageneral
+ int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
+#endif /* datageneral */
+
+#ifndef NOPUSH
+ if (getenv("CK_NOPUSH")) { /* No shell access allowed */
+ nopush = 1; /* on this host... */
+#ifndef NOSERVER
+ en_hos = 0;
+#endif /* NOSERVER */
+ }
+#endif /* NOPUSH */
+
+ *vvbuf = NUL; /* How let's get our host name ... */
+
+#ifndef BELLV10 /* Does not have gethostname() */
+#ifndef OXOS
+#ifdef SVORPOSIX
+#ifdef APOLLOSR10
+ ckstrncpy(vvbuf,"Apollo",vvlen);
+#else
+#ifdef BSD44
+ if (gethostname(vvbuf,vvlen) < 0)
+ *vvbuf = NUL;
+#else
+#ifdef _386BSD
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else
+#ifdef QNX
+#ifdef TCPSOCKET
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else
+ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
+#endif /* TCPSOCKET */
+#else /* SVORPOSIX but not _386BSD or BSD44 */
+#ifdef __ia64__
+ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
+#else
+ if (uname(&hname) > -1) {
+ char * p;
+ p = hname.nodename;
+#ifdef TCPSOCKET
+#ifndef NOCKGETFQHOST
+ if (!ckstrchr(p,'.'))
+ p = (char *)ckgetfqhostname(p);
+#endif /* NOCKGETFQHOST */
+#endif /* TCPSOCKET */
+ if (!p) p = "";
+ if (!*p) p = "(unknown)";
+ ckstrncpy(vvbuf,p,vvlen);
+ }
+#endif /* __ia64__ */
+#endif /* QNX */
+#endif /* _386BSD */
+#endif /* BSD44 */
+#endif /* APOLLOSR10 */
+#else /* !SVORPOSIX */
+#ifdef BSD4
+ if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
+#else /* !BSD4 */
+#ifdef VMS
+ g = getenv("SYS$NODE");
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+ x = (int)strlen(vvbuf);
+ if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
+#else
+#ifdef datageneral
+ if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
+ vvlen = ac2 + 1; /* enh - have to add one */
+#else
+#ifdef OS2 /* OS/2 */
+ g = os2_gethostname();
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+#else /* OS2 */
+#ifdef OSK
+#ifdef TCPSOCKET
+ if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
+#endif /* TCPSOCKET */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* BSD4 */
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ /* If TCP/IP is not installed, gethostname() fails, use uname() */
+ if (gethostname(vvbuf,vvlen) < 0) {
+ if (uname(&hname) > -1)
+ ckstrncpy(vvbuf,hname.nodename,vvlen);
+ else
+ *vvbuf = NUL;
+ }
+#endif /* OXOS */
+#endif /* BELLV10 */
+ if (*vvbuf == NUL) { /* If it's still empty */
+ g = getenv("HOST"); /* try this */
+ if (g) ckstrncpy(vvbuf,g,vvlen);
+ }
+ vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */
+#endif /* pdp11 */
+}
+#ifdef BSD44
+#undef BSD4
+#define ATTSV
+#endif /* BSD44 */
+
+/*
+ A S K M O R E -- Poor person's "more".
+ Returns 0 if no more, 1 if more wanted.
+*/
+int
+askmore() {
+ char c;
+ int rv, cx;
+#ifdef IKSD
+ extern int timelimit;
+#endif /* IKSD */
+#ifdef IKSDCONF
+ extern int iksdcf;
+#endif /* IKSDCONF */
+#ifdef CK_APC
+ extern int apcstatus, apcactive;
+#endif /* CK_APC */
+
+#ifdef NOICP
+ return(1);
+#else
+ if (!xaskmore)
+ return(1);
+#ifdef IKSDCONF
+ if (inserver && !iksdcf)
+ return(1);
+#endif /* IKSDCONF */
+#ifdef CK_APC
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
+ return(1);
+#endif /* CK_APC */
+#ifdef VMS
+ if (batch)
+ return(1);
+#else
+#ifdef UNIX
+ if (backgrd)
+ return(1);
+#endif /* UNIX */
+#endif /* VMS */
+
+#ifndef VMS
+ concb((char)escape); /* Force CBREAK mode. */
+#endif /* VMS */
+
+ rv = -1;
+ while (rv < 0) {
+#ifndef OS2
+ printf("more? ");
+#ifdef UNIX
+#ifdef NOSETBUF
+ fflush(stdout);
+#endif /* NOSETBUF */
+#endif /* UNIX */
+#else
+ printf("more? ");
+ fflush(stdout);
+#endif /* OS2 */
+
+#ifdef IKSD
+ if (inserver) {
+ cx = cmdgetc(timelimit);
+ if (cx < -1 && timelimit) {
+ printf("\n?IKS idle timeout - Goodbye.\n");
+ doexit(GOOD_EXIT,0);
+ } else if (cx == -1) { /* Connection lost */
+ doexit(BAD_EXIT,0);
+ }
+ c = (char) cx;
+ } else {
+#endif /* IKSD */
+#ifdef VMS
+ conbin((char)escape); /* Protect against Ctrl-Z */
+ cx = coninc(0);
+ concb((char)escape);
+#else
+ cx = cmdgetc(0);
+#endif /* VMS */
+ debug(F101,"askmore cmdgetc","",cx);
+ if (cx == EOF) {
+ debug(F100,"askmore EOF","",0);
+#ifdef VMS
+ c = '\032';
+#else
+ c = 'n';
+#endif /* VMS */
+ } else {
+ c = (char)cx;
+ }
+ debug(F101,"askmore c","",c);
+
+#ifdef IKSD
+ }
+#endif /* IKSD */
+ switch (c) {
+ /* Yes */
+ case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
+ xaskmore = 0;
+ /* fall thru on purpose */
+
+ case SP: case 'y': case 'Y': case 012: case 015:
+#ifdef OSK
+ write(1, "\015 \015", sizeof "\015 \015" - 1);
+#else
+ printf("\015 \015");
+#endif /* OSK */
+ rv = 1;
+ break;
+ /* No */
+ case 'n': case 'N': case 'q': case 'Q':
+#ifdef OSK
+ printf("\n");
+#else
+ printf("\015\012");
+#endif /* OSK */
+ rv = 0;
+ break;
+ case '\003':
+ case '\004':
+ case '\032':
+#ifdef OSK
+ printf("^%c...\n", (c + 0100));
+#else
+ printf("^%c...\015\012", (c + 0100));
+#endif /* OSK */
+ rv = 0;
+ break;
+ /* Invalid answer */
+ default:
+ debug(F111,"askmore","invalid answer",c);
+ printf("Y or space-bar for yes, N for no, G to show the rest\n");
+ continue;
+ }
+#ifdef OS2
+ printf("\r \r");
+ fflush(stdout);
+#endif /* OS2 */
+ }
+ return(rv);
+#endif /* NOICP */
+}
+
+/* T R A P -- Terminal interrupt handler */
+
+SIGTYP
+#ifdef CK_ANSIC
+trap(int sig)
+#else
+trap(sig) int sig;
+#endif /* CK_ANSIC */
+/* trap */ {
+ extern int b_save, f_save;
+#ifndef NOICP
+ extern int timelimit;
+#endif /* NOICP */
+#ifdef OS2
+ extern unsigned long startflags;
+#ifndef NOSETKEY
+ extern int os2gks;
+#endif /* NOSETKEY */
+ int i;
+#endif /* OS2 */
+#ifndef NOSPL
+ extern int i_active, instatus;
+#endif /* NOSPL */
+#ifdef VMS
+ int i; FILE *f;
+#endif /* VMS */
+ extern int zchkod, zchkid;
+#ifndef NOSPL
+ extern int unkmacro;
+#endif /* NOSPL */
+
+ debok = 1;
+#ifdef NTSIG
+ connoi();
+#endif /* NTSIG */
+#ifdef __EMX__
+ signal(SIGINT, SIG_ACK);
+#endif
+#ifdef GEMDOS
+/* GEM is not reentrant, no i/o from interrupt level */
+ cklongjmp(cmjbuf,1); /* Jump back to parser now! */
+#endif /* GEMDOS */
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"*********************","",0);
+ if (sig == SIGINT)
+ debug(F101,"trap caught SIGINT","",sig);
+ else
+ debug(F101,"trap caught signal","",sig);
+ debug(F100,"*********************","",0);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ if ( sig == SIGBREAK && (startflags & 128) ) {
+ debug(F101,"trap ignoring SIGBREAK","",sig);
+ return;
+ }
+#endif /* OS2 */
+
+#ifndef NOICP
+ timelimit = 0; /* In case timed ASK interrupted */
+#ifndef NOSPL
+ unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */
+#endif /* NOSPL */
+#endif /* NOICP */
+ zchkod = 0; /* Or file expansion interrupted... */
+ zchkid = 0;
+ interrupted = 1;
+
+ if (what & W_CONNECT) { /* Are we in CONNECT mode? */
+/*
+ The HP workstation Reset key sends some kind of ueber-SIGINT that can not
+ be SIG_IGNored, so we wind up here somehow (even though this is *not* the
+ current SIGINT handler). Just return.
+*/
+ debug(F101,"trap: SIGINT caught during CONNECT","",sig);
+ SIGRETURN;
+ }
+#ifndef NOSPL
+ if (i_active) { /* INPUT command was active? */
+ i_active = 0; /* Not any more... */
+ instatus = INP_UI; /* INPUT status = User Interrupted */
+ }
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ ftreset(); /* Restore global protocol settings */
+ binary = b_save; /* Then restore these */
+ fncnv = f_save;
+ bye_active = 0;
+ diractive = 0;
+ cdactive = 0;
+#endif /* NOXFER */
+ zclose(ZIFILE); /* If we were transferring a file, */
+ zclose(ZOFILE); /* close it. */
+#ifndef NOICP
+ cmdsquo(cmd_quoting); /* If command quoting was turned off */
+#ifdef CKLEARN
+ {
+ extern FILE * learnfp;
+ extern int learning;
+ if (learnfp) {
+ fclose(learnfp);
+ learnfp = NULL;
+ learning = 0;
+ }
+ }
+#endif /* CKLEARN */
+#endif /* NOICP */
+#ifdef CK_APC
+ delmac("_apc_commands",1);
+ apcactive = APC_INACTIVE;
+#endif /* CK_APC */
+
+#ifdef VMS
+/*
+ Fix terminal.
+*/
+ if (ft_win) { /* If curses window open */
+ debug(F100,"^C trap() curses","",0);
+ xxscreen(SCR_CW,0,0L,""); /* Close it */
+ conres(); /* Restore terminal */
+ i = printf("^C..."); /* Echo ^C to standard output */
+ } else {
+ conres();
+ i = printf("^C...\n"); /* Echo ^C to standard output */
+ }
+ if (i < 1 && ferror(stdout)) { /* If there was an error */
+ debug(F100,"^C trap() error","",0);
+ fclose(stdout); /* close standard output */
+ f = fopen(dftty, "w"); /* open the controlling terminal */
+ if (f) stdout = f; /* and make it standard output */
+ printf("^C...\n"); /* and echo the ^C again. */
+ }
+#else /* Not VMS */
+#ifdef STRATUS
+ conres(); /* Set console back to normal mode */
+#endif /* STRATUS */
+#ifndef NOXFER
+ if (ft_win) { /* If curses window open, */
+ debug(F100,"^C trap() curses","",0);
+ xxscreen(SCR_CW,0,0L,""); /* close it. */
+ printf("^C..."); /* Echo ^C to standard output */
+ } else {
+#endif /* NOXFER */
+ printf("^C...\n");
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+#endif /* VMS */
+#ifdef datageneral
+ connoi_mt(); /* Kill asynch task that listens to */
+ ttimoff();
+ conres(); /* the keyboard */
+#endif /* datageneral */
+
+#ifndef NOCCTRAP
+/* This is stupid -- every version should have ttimoff()... */
+#ifdef UNIX
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef OSK
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef STRATUS
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef OS2
+#ifndef NOSETKEY
+ os2gks = 1; /* Turn back on keycode mapping */
+#endif /* NOSETKEY */
+#ifndef NOLOCAL
+ for (i = 0; i < VNUM; i++)
+ VscrnResetPopup(i);
+#endif /* NOLOCAL */
+#ifdef TCPSOCKET
+#ifdef NT
+ /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
+ if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
+ WSACancelBlockingCall();
+ }
+#endif /* NT */
+#endif /* TCPSOCKET */
+#ifdef CK_NETBIOS
+ NCBCancelOutstanding();
+#endif /* CK_NETBIOS */
+ ttimoff(); /* Turn off any timer interrupts */
+#else
+#ifdef VMS
+ ttimoff(); /* Turn off any timer interrupts */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* OSK */
+#endif /* UNIX */
+
+#ifdef NETPTY
+ /* Clean up Ctrl-C out of REDIRECT or external protocol */
+ {
+ extern PID_T pty_fork_pid;
+ extern int pty_master_fd, pty_slave_fd;
+ int x;
+
+ signal(SIGCHLD,SIG_IGN); /* We don't want this any more */
+
+ debug(F101,"trap pty_master_fd","",pty_master_fd);
+ if (pty_master_fd > 2) {
+ x = close(pty_master_fd);
+ debug(F101,"trap pty_master_fd close","",x);
+ }
+ pty_master_fd = -1;
+ debug(F101,"trap pty_slave_fd","",pty_slave_fd);
+ if (pty_slave_fd > 2) {
+ x = close(pty_slave_fd);
+ debug(F101,"trap pty_slave_fd close","",x);
+ }
+ pty_slave_fd = -1;
+ debug(F101,"trap pty_fork_pid","",pty_fork_pid);
+ if (pty_fork_pid > 0) {
+ x = kill(pty_fork_pid,0); /* See if the fork is really there */
+ debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno);
+ if (x == 0) { /* Seems to be active */
+ x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */
+ debug(F101,"trap pty_fork_pid kill SIGHUP","",x);
+ msleep(100);
+ errno = 0;
+ x = kill(pty_fork_pid,0); /* Is it still there? */
+ if (x == 0
+#ifdef ESRCH
+ /* This module is not always exposed to <errno.h> */
+ || errno != ESRCH
+#endif /* ESRCH */
+ ) {
+ x = kill(pty_fork_pid,SIGKILL);
+ debug(F101,"trap pty_fork_pid kill SIGKILL","",x);
+ }
+ }
+ pty_fork_pid = -1;
+ }
+ }
+#endif /* NETPTY */
+
+#ifdef OSK
+ sigmask(-1);
+/*
+ We are in an intercept routine but do not perform a F$RTE (done implicitly
+ by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump
+ only restores the cpu registers, NOT the fpu registers. So don't use fpu at
+ all or at least don't use common fpu (double or float) register variables.
+*/
+#endif /* OSK */
+
+#ifdef NTSIG
+ PostCtrlCSem();
+#else /* NTSIG */
+ debug(F100,"trap about to longjmp","",0);
+#ifdef NT
+ cklongjmp(ckjaddr(cmjbuf),1);
+#else /* NT */
+ cklongjmp(cmjbuf,1);
+#endif /* NT */
+#endif /* NTSIG */
+#else /* NOCCTRAP */
+/* No Ctrl-C trap, just exit. */
+#ifdef CK_CURSES /* Curses support? */
+ xxscreen(SCR_CW,0,0L,""); /* Close curses window */
+#endif /* CK_CURSES */
+ doexit(BAD_EXIT,what); /* Exit poorly */
+#endif /* NOCCTRAP */
+ SIGRETURN;
+}
+
+
+/* C K _ T I M E -- Returns pointer to current time. */
+
+char *
+ck_time() {
+ static char tbuf[10];
+ char *p;
+ int x;
+
+ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
+ if (!p) /* like asctime()! */
+ return("");
+ if (*p) {
+ for (x = 11; x < 19; x++) /* copy hh:mm:ss */
+ tbuf[x - 11] = p[x]; /* to tbuf */
+ tbuf[8] = NUL; /* terminate */
+ }
+ return(tbuf); /* and return it */
+}
+
+/* C C _ C L E A N -- Cleanup after terminal interrupt handler */
+
+#ifdef GEMDOS
+int
+cc_clean() {
+ zclose(ZIFILE); /* If we were transferring a file, */
+ zclose(ZOFILE); /* close it. */
+ printf("^C...\n"); /* Not VMS, no problem... */
+}
+#endif /* GEMDOS */
+
+
+/* S T P T R A P -- Handle SIGTSTP (suspend) signals */
+
+SIGTYP
+#ifdef CK_ANSIC
+stptrap(int sig)
+#else
+stptrap(sig) int sig;
+#endif /* CK_ANSIC */
+/* stptrap */ {
+
+#ifndef NOJC
+ int x; extern int cmflgs;
+ debug(F101,"stptrap() caught signal","",sig);
+ if (!xsuspend) {
+ printf("\r\nsuspend disabled\r\n");
+#ifndef NOICP
+ if (what & W_COMMAND) { /* If we were parsing commands */
+ prompt(xxstring); /* reissue the prompt and partial */
+ if (!cmflgs) /* command (if any) */
+ printf("%s",cmdbuf);
+ }
+#endif /* NOICP */
+ } else {
+ conres(); /* Reset the console */
+#ifndef OS2
+ /* Flush pending output first, in case we are continued */
+ /* in the background, which could make us block */
+ fflush(stdout);
+
+ x = psuspend(xsuspend); /* Try to suspend. */
+ if (x < 0)
+#endif /* OS2 */
+ printf("Job control not supported\r\n");
+ conint(trap,stptrap); /* Rearm the trap. */
+ debug(F100,"stptrap back from suspend","",0);
+ switch (what) {
+ case W_CONNECT: /* If suspended during CONNECT? */
+ conbin((char)escape); /* put console back in binary mode */
+ debug(F100,"stptrap W_CONNECT","",0);
+ break;
+#ifndef NOICP
+ case W_COMMAND: /* Suspended in command mode */
+ debug(F101,"stptrap W_COMMAND pflag","",pflag);
+ concb((char)escape); /* Put back CBREAK tty mode */
+ if (pflag) { /* If command parsing was */
+ prompt(xxstring); /* reissue the prompt and partial */
+ if (!cmflgs) /* command (if any) */
+ printf("%s",cmdbuf);
+ }
+ break;
+#endif /* NOICP */
+ default: /* All other cases... */
+ debug(F100,"stptrap default","",0);
+ concb((char)escape); /* Put it back in CBREAK mode */
+ break;
+ }
+ }
+#endif /* NOJC */
+ SIGRETURN;
+}
+
+#ifdef TLOG
+#define TBUFL 300
+
+/* T L O G -- Log a record in the transaction file */
+/*
+ Call with a format and 3 arguments: two strings and a number:
+ f - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
+ s1,s2 - String arguments 0 and 1.
+ n - Long, argument 2.
+*/
+VOID
+#ifdef CK_ANSIC
+dotlog(int f, char *s1, char *s2, CK_OFF_T n)
+#else
+dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2;
+#endif /* CK_ANSIC */
+/* dotlog */ {
+ static char s[TBUFL];
+ extern int tlogfmt;
+ char *sp = s; int x;
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+
+ if (!tralog) return; /* If no transaction log, don't */
+ if (tlogfmt != 1) return;
+ switch (f) {
+ case F000: /* 0 (special) "s1 n s2" */
+ if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
+ sprintf(sp,"?T-Log string too long");
+ else
+ sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F001: /* 1, " n" */
+ sprintf(sp," %s",ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F010: /* 2, "[s2]" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if (x + 6 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"[%s]",s2);
+ if (zsoutl(ZTFILE,"") < 0) tralog = 0;
+ break;
+ case F011: /* 3, "[s2] n" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if (x + 6 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"[%s] %s",s2,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F100: /* 4, "s1" */
+ if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
+ break;
+ case F101: /* 5, "s1: n" */
+ if ((int)strlen(s1) + 15 > TBUFL)
+ sprintf(sp,"?String too long");
+ else sprintf(sp,"%s: %s",s1,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F110: /* 6, "s1 s2" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if ((int)strlen(s1) + x + 4 > TBUFL)
+ sprintf(sp,"?String too long");
+ else
+ sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ case F111: /* 7, "s1 s2: n" */
+ x = (int)strlen(s2);
+ if (s2[x] == '\n') s2[x] = '\0';
+ if ((int)strlen(s1) + x + 15 > TBUFL)
+ sprintf(sp,"?String too long");
+ else
+ sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n));
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ break;
+ default:
+ sprintf(sp,"?Invalid format for tlog() - %d",f);
+ if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+ }
+}
+
+/*
+ D O X L O G
+
+ This is the transaction-log writer for BRIEF format.
+ The idea is produce one record (line) per file. Each record
+ has the following delimited fields:
+ Date (yyyymmdd)
+ Time (hh:mm:ss)
+ Action: SEND or RECV
+ File name
+ File size
+ Transfer mode (text, binary, image, labeled, etc).
+ Status: OK or FAILED
+ Free-form comments in doublequotes
+ The default separator is comma.
+ If a field contains the separator, it is enclosed in doublequotes.
+*/
+VOID
+#ifdef CK_ANSIC
+doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg)
+#else
+doxlog(x, fn, fs, fm, status, msg)
+ int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg;
+#endif /* CK_ANSIC */
+/* doxlog */ {
+ extern int tlogsep;
+ char sep[2];
+ char buf[CKMAXPATH+256], * bufp;
+ char tmpbuf[32];
+ char * s, * p;
+ int len, left, ftp = 0, k;
+
+ if (!tralog) return; /* If no transaction log, don't */
+
+ if (!fn) fn = ""; /* Protect against null pointers */
+ if (!msg) msg = "";
+ if (x & W_FTP)
+ ftp++;
+
+ sep[0] = (char) tlogsep;
+ sep[1] = NUL;
+ if (!sep[0]) sep[0] = ',';
+
+ bufp = buf;
+ left = sizeof(buf);
+ debug(F101,"XXX doxlog left 1","",left);
+
+ p = zzndate(); /* Date */
+ ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
+ bufp += 9;
+ left -= 9;
+ debug(F111,"XXX doxlog left 2",buf,left);
+
+ ztime(&p);
+ ckstrncpy(bufp,p+11,left);
+ bufp += 8;
+ left -= 8;
+ debug(F111,"XXX doxlog left 3",buf,left);
+
+ if (ftp) {
+ if (!(x & (W_SEND|W_RECV)))
+ return;
+ s = (x & W_SEND) ? "PUT" : "GET";
+ k = 3;
+ } else {
+ s = (x & W_SEND) ? "SEND" : "RECV";
+ k = 4;
+ }
+ ckmakmsg(bufp,left,sep,s,sep,NULL);
+ bufp += k + 2;
+ left -= (k + 2);
+ debug(F111,"XXX doxlog left 4",buf,left);
+
+ s = "";
+ if (ckstrchr(fn,sep[0])) /* Filename */
+ s = "\"";
+ ckmakmsg(bufp,left,s,fn,s,sep);
+ sprintf(tmpbuf,"%s",ckfstoa(fs)); /* Size */
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,sep,CKMAXPATH);
+ debug(F110,"doxlog 4",buf,0);
+
+#ifdef NOICP
+ /* Transfer mode */
+ ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
+#else
+ ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
+#endif /* NOICP */
+ if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */
+ ckstrncat(buf,"\"",CKMAXPATH);
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,"\"",CKMAXPATH);
+ } else
+ ckstrncat(buf,tmpbuf,CKMAXPATH);
+ ckstrncat(buf,sep,CKMAXPATH);
+ debug(F110,"doxlog 5",buf,0);
+
+ ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
+ len = strlen(buf);
+ left = CKMAXPATH+256 - len;
+ if (left < 2) fatal("doxlog buffer overlow");
+
+ debug(F111,"XXX doxlog left 5",buf,left);
+
+ debug(F110,"doxlog buf 1", buf, len);
+ s = buf + len;
+ if (status == 0 && left > 32) {
+ long cps = 0L;
+#ifdef GFTIMER
+ debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
+ if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs);
+ sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
+#else
+ if (xfsecs) cps = fs / xfsecs;
+ sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
+#endif /* GFTIMER */
+ } else if ((int)strlen(msg) + 4 < left) {
+ sprintf(s,"%s\"%s\"",sep,msg);
+ }
+ debug(F111,"XXX doxlog left 5",buf,left);
+
+ debug(F110,"doxlog 5",buf,0);
+ x = zsoutl(ZTFILE,buf);
+ debug(F101,"doxlog zsoutl","",x);
+ if (x < 0) tralog = 0;
+}
+#endif /* TLOG */
+
+#ifndef MAC
+/*
+ The rest of this file is for all implementations but the Macintosh.
+*/
+
+#ifdef CK_CURSES
+static int repaint = 0; /* Transfer display needs repainting */
+#endif /* CK_CURSES */
+
+#ifndef NOXFER
+/* C H K I N T -- Check for console interrupts */
+
+/*
+ Used during file transfer in local mode only:
+ . If user has not touched the keyboard, returns 0 with no side effects.
+ . If user typed S or A (etc, see below) prints status message and returns 0.
+ . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
+ . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
+ . If user typed E or C (etc, see below) returns -1.
+*/
+int
+chkint() {
+ int ch, cn, ofd; long zz;
+ if (!xfrint)
+ return(0);
+ if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
+#ifdef datageneral
+ if (con_reads_mt) /* if conint_mt task is active */
+ if (conint_avl) { /* and there's an interrupt pending */
+ cn = 1; /* process it */
+ ch = conint_ch;
+ conint_avl = 0; /* turn off flag so conint_mt can */
+ } else /* proceed */
+ return(0);
+ else /* if conint_mt not active */
+ if ((ch = coninc(2)) < 0) /* try to get char manually */
+ return(0); /* I/O error, or no data */
+ else /* if successful, set cn so we */
+ cn = 1; /* know we got one */
+ debug(F101,"chkint got keyboard character",ch,cn);
+#else /* !datageneral */
+#ifdef NTSIG
+ {
+ extern int TlsIndex;
+ struct _threadinfo * threadinfo;
+ threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
+ if (threadinfo) {
+ if (!WaitSem(threadinfo->DieSem,0))
+ return -1; /* Cancel Immediately */
+ }
+ }
+#endif /* NTSIG */
+ cn = conchk(); /* Any input waiting? */
+ debug(F101,"conchk","",cn);
+ if (cn < 1) return(0);
+ ch = coninc(5) ;
+ debug(F101,"coninc","",ch);
+ if (ch < 0) return(0);
+#endif /* datageneral */
+
+ ch &= 0177;
+ switch (ch) {
+ case 'A': case 'a': case 0001: /* Status report */
+ case 'S': case 's':
+ if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
+ return(0); /* Only for serial, simple or none */
+ ofd = fdispla; /* [MF] Save file display type */
+ if (fdispla == XYFD_N)
+ fdispla = XYFD_R; /* [MF] Pretend serial if no display */
+ xxscreen(SCR_TN,0,0l,"Status report:");
+ xxscreen(SCR_TN,0,0l," file type: ");
+ if (binary) {
+ switch(binary) {
+ case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
+ case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
+ case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
+ default:
+ case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
+ }
+ } else {
+#ifdef NOCSETS
+ xxscreen(SCR_TZ,0,0l,"text");
+#else
+ xxscreen(SCR_TU,0,0l,"text, ");
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ xxscreen(SCR_TZ,0,0l,"transparent");
+ } else {
+ if (what & W_SEND) {
+ xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
+ xxscreen(SCR_TU,0,0l," => ");
+ xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
+ } else {
+ xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
+ xxscreen(SCR_TU,0,0l," => ");
+ xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
+ }
+ }
+#endif /* NOCSETS */
+ }
+ xxscreen(SCR_QE,0,filcnt," file number");
+ if (fsize) xxscreen(SCR_QE,0,fsize," size");
+ xxscreen(SCR_QE,0,ffc," characters so far");
+ if (fsize > 0L) {
+#ifdef CK_RESEND
+ zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
+ zz = ( (ffc + zz) * 100L ) / fsize;
+#else
+ zz = ( ffc * 100L ) / fsize;
+#endif /* CK_RESEND */
+ xxscreen(SCR_QE,0,zz, " percent done");
+ }
+ if (bctu == 4) { /* Block check */
+ xxscreen(SCR_TU,0,0L," block check: ");
+ xxscreen(SCR_TZ,0,0L,"blank-free-2");
+ } else xxscreen(SCR_QE,0,(long)bctu, " block check");
+ xxscreen(SCR_QE,0,(long)rptflg," compression");
+ xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
+ xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
+ if (!network)
+ xxscreen(SCR_QE,0, speed, " speed");
+ if (what & W_SEND)
+
+ xxscreen(SCR_QE,0,spsiz, " packet length");
+ else if (what & W_RECV || what & W_REMO)
+ xxscreen(SCR_QE,0,urpsiz," packet length");
+ xxscreen(SCR_QE,0,wslots, " window slots");
+ fdispla = ofd; /* [MF] Restore file display type */
+ return(0);
+
+ case 'B': case 'b': case 0002: /* Cancel batch */
+ case 'Z': case 'z': case 0032:
+ czseen = 1;
+ interrupted = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ (((what & W_RECV) && (wslots > 1)) ?
+ "Canceling batch, wait... " :
+ "Canceling batch... ")
+ );
+ return(0);
+
+ case 'F': case 'f': case 0006: /* Cancel file */
+ case 'X': case 'x': case 0030:
+ cxseen = 1;
+ interrupted = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ (((what & W_RECV) && (wslots > 1)) ?
+ "Canceling file, wait... " :
+ "Canceling file... ")
+ );
+ return(0);
+
+ case 'R': case 'r': case 0022: /* Resend packet */
+ case 0015: case 0012:
+#ifdef STREAMING
+ if (streaming)
+ return(0);
+#endif /* STREAMING */
+ xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
+ numerrs++;
+ resend(winlo);
+ return(0);
+
+#ifdef datageneral
+ case '\03': /* We're not trapping ^C's with */
+ trap(0); /* signals, so we check here */
+#endif /* datageneral */
+
+ case 'C': case 'c': /* Ctrl-C */
+#ifndef datageneral
+ case '\03':
+#endif /* datageneral */
+
+ case 'E': case 'e': /* Send error packet */
+ case 0005:
+ interrupted = 1;
+ return(-1);
+
+#ifdef CK_CURSES
+ case 0014: /* Ctrl-L to refresh screen */
+ case 'L': case 'l': /* Also accept L (upper, lower) */
+ case 0027: /* Ctrl-W synonym for VMS & Ingres */
+ repaint = 1;
+ return(0);
+#endif /* CK_CURSES */
+
+ case 'T':
+ case 't': /* Turn on debug-log timestamps */
+#ifdef DEBUG
+ {
+ extern int debtim;
+ if (ch == 'T') {
+ debtim = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ "Debug timestamps On... ");
+ } else {
+ debtim = 1;
+ xxscreen(SCR_ST,ST_MSG,0l,
+ "Debug timestamps Off... ");
+ }
+ }
+#endif /* DEBUG */
+ return(0);
+
+ case 'D':
+#ifdef DEBUG
+ if (!deblog) {
+ debopn("debug.log",0);
+ if (deblog) {
+ xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
+ } else {
+ xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
+ }
+ } else {
+ xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
+ }
+ if (deblog)
+ debok = 1;
+#endif /* DEBUG */
+ return(0);
+
+ case 'd': /* Turn off debugging */
+#ifdef DEBUG
+ if (deblog)
+ xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
+ debok = 0;
+#endif /* DEBUG */
+ return(0);
+
+ default: /* Anything else, print message */
+ intmsg(1L);
+ return(0);
+ }
+}
+
+/* I N T M S G -- Issue message about terminal interrupts */
+
+VOID
+#ifdef CK_ANSIC
+intmsg(long n)
+#else
+intmsg(n) long n;
+#endif /* CK_ANSIC */
+/* intmsg */ {
+#ifdef CK_NEED_SIG
+ char buf[80];
+#endif /* CK_NEED_SIG */
+
+ if (!displa || quiet) /* Not if we're being quiet */
+ return;
+ if (server && (!srvdis || n > -1L)) /* Special for server */
+ return;
+#ifdef CK_NEED_SIG
+ buf[0] = NUL; /* Keep compilers happy */
+#endif /* CK_NEED_SIG */
+#ifndef OXOS
+#ifdef SVORPOSIX
+ conchk(); /* Clear out pending escape-signals */
+#endif /* SVORPOSIX */
+#endif /* ! OXOS */
+#ifdef VMS
+ conres(); /* So Ctrl-C will work */
+#endif /* VMS */
+ if ((!server && n == 1L) || (server && n < 0L)) {
+
+#ifdef CK_NEED_SIG
+ if (xfrint) {
+ ckmakmsg(buf,
+ 80,
+ "Type escape character (",
+ dbchr(escape),
+ ") followed by:",
+ NULL
+ );
+ xxscreen(SCR_TN,0,0l,buf);
+ }
+#endif /* CK_NEED_SIG */
+
+ if (xfrint) {
+ if (protocol == PROTO_K) {
+ xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet");
+ xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
+ xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
+ } else {
+ xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
+ }
+ } else {
+ xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
+ }
+ }
+ else xxscreen(SCR_TU,0,0l," ");
+}
+
+#ifndef NODISPLAY
+static int newdpy = 0; /* New display flag */
+static char fbuf[80]; /* Filename buffer */
+static char abuf[80]; /* As-name buffer */
+static char a2buf[80]; /* Second As-name buffer */
+static CK_OFF_T oldffc = 0L;
+static CK_OFF_T dots = 0L;
+static int hpos = 0;
+
+static VOID /* Initialize Serial or CRT display */
+dpyinit() {
+ int m = 0, n = 0;
+ char * s = "";
+
+ newdpy = 0; /* Don't do this again */
+ oldffc = (CK_OFF_T)0; /* Reset this */
+ dots = (CK_OFF_T)0; /* and this.. */
+ oldcps = cps = 0L;
+
+ conoll(""); /* New line */
+ if (what & W_SEND) s = "Sending: "; /* Action */
+ else if (what & W_RECV) s = "Receiving: ";
+ n = (int)strlen(s) + (int)strlen(fbuf);
+ conol(fbuf);
+ m = (int)strlen(abuf) + 4;
+ if (n + m > cmd_cols) {
+ conoll("");
+ n = 0;
+ } else
+ n += m;
+ if (*abuf) {
+ conol(" => ");
+ conol(abuf);
+ }
+ m = (int)strlen(a2buf) + 4;
+ if (n + m > cmd_cols) {
+ conoll("");
+ n = 0;
+ } else
+ n += m;
+ if (*a2buf) {
+ conol(" => ");
+ conol(a2buf);
+ }
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ conoll("");
+ if (fsize > (CK_OFF_T)-1) { /* Size */
+ sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */
+ conol(fbuf); *fbuf = NUL;
+ } else conol("Size: unknown, Type: ");
+ if (binary) { /* Type */
+ switch(binary) {
+ case XYFT_L: conol("labeled"); break;
+ case XYFT_I: conol("image"); break;
+ case XYFT_U: conol("binary undefined"); break;
+ default:
+ case XYFT_B: conol("binary"); break;
+ }
+ } else {
+#ifdef NOCSETS
+ conol("text");
+#else
+ conol("text, ");
+ if (tcharset == TC_TRANSP || xfrxla == 0) {
+ conol("transparent");
+ } else {
+ if (what & W_SEND) {
+ conol(fcsinfo[fcharset].keyword);
+ conol(" => ");
+ conol(tcsinfo[tcharset].keyword);
+ } else {
+ conol(tcsinfo[tcharset].keyword);
+ conol(" => ");
+ conol(fcsinfo[fcharset].keyword);
+ }
+ }
+#endif /* NOCSETS */
+ }
+#ifdef STREAMING
+ if (streaming)
+ conol(", STREAMING");
+#endif /* STREAMING */
+ conoll("");
+
+ if (fdispla == XYFD_S) { /* CRT field headings */
+/*
+ Define CK_CPS to show current transfer rate.
+ Leave it undefined to show estimated time remaining.
+ Estimated-time-remaining code from Andy Fyfe, not tested on
+ pathological cases.
+*/
+#define CK_CPS
+
+#ifdef CK_CPS
+ conoll(" File Percent Packet");
+ conoll(" Bytes Done CPS Length");
+#else
+ conoll(" File Percent Secs Packet");
+ conoll(" Bytes Done Left Length");
+#endif /* CK_CPS */
+ newdpy = 0;
+ }
+ hpos = 0;
+}
+
+/*
+ showpkt(c)
+ c = completion code: 0 means transfer in progress, nonzero means it's done.
+ Show the file transfer progress counter and perhaps verbose packet type.
+*/
+VOID
+#ifdef CK_ANSIC
+showpkt(char c)
+#else
+showpkt(c) char c;
+#endif /* CK_ANSIC */
+/* showpkt */ {
+
+#ifndef GFTIMER
+ long et; /* Elapsed time, entire batch */
+#endif /* GFTIMER */
+ CK_OFF_T howfar; /* How far into file */
+ long pd; /* Percent done, this file */
+ long tp; /* Transfer rate, entire batch */
+ long ps; /* Packet size, current packet */
+ CK_OFF_T mytfc; /* Local copy of byte counter */
+
+#ifdef GFTIMER
+ CKFLOAT tnow;
+#endif /* GFTIMER */
+
+ if (newdpy) /* Put up filenames, etc, */
+ dpyinit(); /* if they're not there already. */
+
+ howfar = ffc; /* How far */
+/*
+ Calculate CPS rate even if not displaying on screen for use in file
+ transfer statistics.
+*/
+#ifdef GFTIMER
+ tnow = gftimer(); /* Time since we started */
+ ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
+#ifdef CK_RESEND
+ if (what & W_SEND) /* In case we didn't start at */
+ howfar += sendstart; /* the beginning... */
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ pd = -1; /* Percent done. */
+ if (c == NUL) { /* Still going, figure % done */
+ if (!fsize) return; /* Empty file, don't bother */
+ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
+ if (pd > 100) pd = 100; /* Expansion */
+ }
+ if (c != NUL)
+ if (!cxseen && !discard && !czseen)
+ pd = 100; /* File complete, so 100%. */
+
+ mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */
+ tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
+ if (c && (tp == 0))
+ tp = ffc;
+
+ cps = tp; /* Set global variable */
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+
+#else /* Not GFTIMER */
+
+ et = gtimer(); /* Elapsed time */
+ ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
+#ifdef CK_RESEND
+ if (what & W_SEND) /* And if we didn't start at */
+ howfar += sendstart; /* the beginning... */
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ pd = -1; /* Percent done. */
+ if (c == NUL) { /* Still going, figure % done */
+ if (fsize == 0L) return; /* Empty file, don't bother */
+ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
+ if (pd > 100) pd = 100; /* Expansion */
+ }
+ if (c != NUL)
+ if (!cxseen && !discard && !czseen)
+ pd = 100; /* File complete, so 100%. */
+
+
+#ifndef CK_CPS
+/*
+ fsecs = time (from gtimer) that this file started (set in sfile()).
+ Rate so far is ffc / (et - fsecs), estimated time for remaining bytes
+ is (fsize - ffc) / (ffc / (et - fsecs)).
+*/
+ tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0;
+#endif /* CK_CPS */
+
+#ifdef CK_CPS
+ mytfc = (pd < 100) ? tfc + ffc : tfc;
+ tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
+ if (c && (tp == 0)) /* Watch out for subsecond times */
+ tp = ffc;
+
+ cps = tp; /* Set global variable */
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+#endif /* CK_CPS */
+
+#endif /* GFTIMER */
+
+ if (fdispla == XYFD_S) { /* CRT display */
+ char buffer[128];
+ /* These sprintfs should be safe until we have 32-digit numbers */
+
+ if (pd > -1L)
+ sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CR,ckfstoa(howfar),pd,tp,ps);
+ else
+ sprintf(buffer, "%c%9s %8ld%8ld ", CR,ckfstoa(howfar),tp,ps);
+ conol(buffer);
+ hpos = 31;
+ } else if (fdispla == XYFD_R) { /* SERIAL */
+ long i, k;
+ if (howfar - oldffc < 1024) /* Update display every 1K */
+ return;
+ oldffc = howfar; /* Time for new display */
+ k = (howfar / 1024L) - dots; /* How many K so far */
+ for (i = 0L; i < k; i++) {
+ if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
+ conoll("");
+ hpos = 0;
+ }
+ conoc('.'); /* Print a dot for this K */
+ dots++; /* Count it */
+ }
+ }
+}
+
+
+/* C K S C R E E N -- Screen display function */
+
+/*
+ ckscreen(f,c,n,s)
+ f - argument descriptor
+ c - a character or small integer
+ n - a long integer
+ s - a string.
+
+ and global fdispla = SET FILE DISPLAY value:
+
+ XYFD_N = NONE
+ XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy.
+ XYFD_S = CRT: Works on any CRT, writes over current line.
+ XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
+ XYFD_B = BRIEF: Like SERIAL but only filename & completion status.
+ XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN
+*/
+VOID
+#ifdef CK_ANSIC
+ckscreen(int f, char c,CK_OFF_T n,char *s)
+#else
+ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s;
+#endif /* CK_ANSIC */
+/* screen */ {
+ char buf[80];
+ int len; /* Length of string */
+#ifdef UNIX
+#ifndef NOJC
+ int obg;
+_PROTOTYP( VOID conbgt, (int) );
+#endif /* NOJC */
+#endif /* UNIX */
+ int ftp = 0;
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */
+
+ if (!local && !ftp) /* In remote mode - don't do this */
+ return;
+
+ if (!s) s = "";
+
+ if (!fxd_inited) /* Initialize if necessary */
+ fxdinit(fdispla);
+
+#ifdef UNIX
+#ifndef NOJC
+ obg = backgrd; /* Previous background status */
+ conbgt(1); /* See if running in background */
+ if (!backgrd && obg) { /* Just came into foreground? */
+ concb((char)escape); /* Put console back in CBREAK mode */
+ setint(); /* Restore interrupts */
+ }
+#endif /* NOJC */
+#endif /* UNIX */
+
+ if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
+ if (!displa ||
+ (backgrd && bgset) ||
+ fdispla == XYFD_N ||
+ (server && !srvdis)
+ )
+ return;
+
+#ifdef VMS
+ if (f == SCR_FN) /* VMS - shorten the name */
+ s = zrelname(s,zgtdir());
+#endif /* VMS */
+
+ if (dest == DEST_S) /* SET DESTINATION SCREEN */
+ return; /* would interfere... */
+
+#ifdef KUI
+ if (fdispla == XYFD_G) { /* If gui display selected */
+ screeng(f,c,n,s); /* call the gui version */
+ return;
+ }
+#endif /* KUI */
+#ifdef CK_CURSES
+ if (fdispla == XYFD_C) { /* If fullscreen display selected */
+ screenc(f,c,n,s); /* call the fullscreen version */
+ return;
+ }
+#endif /* CK_CURSES */
+
+ len = (int)strlen(s); /* Length of string */
+
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ if (fdispla == XYFD_B) {
+#ifdef NEWFTP
+ if (ftp)
+ printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
+ else
+#endif /* NEWFTP */
+ printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+ }
+#ifdef MAC
+ conoll(""); conol(s); conoc(SP); hpos = len + 1;
+#else
+ ckstrncpy(fbuf,s,80);
+ abuf[0] = a2buf[0] = NUL;
+ newdpy = 1; /* New file so refresh display */
+#endif /* MAC */
+ return;
+
+ case SCR_AN: /* As-name */
+ if (fdispla == XYFD_B) {
+#ifdef COMMENT
+ printf("(as %s) ",s);
+#endif /* COMMENT */
+ return;
+ }
+#ifdef MAC
+ if (hpos + len > 75) { conoll(""); hpos = 0; }
+ conol("=> "); conol(s);
+ if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
+#else
+ if (abuf[0]) {
+ ckstrncpy(a2buf,s,80);
+ } else {
+ ckstrncpy(abuf,s,80);
+ }
+#endif /* MAC */
+ return;
+
+ case SCR_FS: /* File-size */
+ if (fdispla == XYFD_B) {
+ printf(" (%s) (%s byte%s)",
+#ifdef NOICP
+ (binary ? "binary" : "text")
+#else
+ gfmode(binary,0)
+#endif /* NOICP */
+ , ckfstoa(n), n == 1 ? "" : "s");
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+ }
+#ifdef MAC
+ sprintf(buf,", Size: %s",ckfstoa(n)); conoll(buf); hpos = 0;
+#endif /* MAC */
+ return;
+
+ case SCR_XD: /* X-packet data */
+ if (fdispla == XYFD_B)
+ return;
+#ifdef MAC
+ conoll(""); conoll(s); hpos = 0;
+#else
+ ckstrncpy(fbuf,s,80);
+ abuf[0] = a2buf[0] = NUL;
+#endif /* MAC */
+ return;
+
+ case SCR_ST: /* File status */
+ switch (c) {
+ case ST_OK: /* Transferred OK */
+ showpkt('Z'); /* Update numbers one last time */
+ if (fdispla == XYFD_B) {
+#ifdef GFTIMER
+ if (fpxfsecs)
+ printf(": OK (%0.3f sec, %ld cps)",fpxfsecs,
+ (long)((CKFLOAT)ffc / fpxfsecs));
+#else
+ if (xfsecs)
+ printf(": OK (%d sec, %ld cps)",xfsecs,ffc/xfsecs);
+#endif /* GFTIMER */
+ printf("\n");
+ return;
+ }
+ if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
+ conoll(" [OK]"); hpos = 0; /* Print OK message. */
+ if (fdispla == XYFD_S) { /* We didn't show Z packet when */
+ conoc('Z'); /* it came, so show it now. */
+ hpos = 1;
+ }
+ return;
+
+ case ST_DISC: /* Discarded */
+ if (fdispla == XYFD_B) {
+ printf(": DISCARDED\n");
+ return;
+ }
+ if ((hpos += 12) > 78) conoll("");
+ conoll(" [discarded]"); hpos = 0;
+ return;
+
+ case ST_INT: /* Interrupted */
+ if (fdispla == XYFD_B) {
+ printf(": INTERRUPTED\n");
+ return;
+ }
+ if ((hpos += 14) > 78) conoll("");
+ conoll(" [interrupted]"); hpos = 0;
+ return;
+
+ case ST_SIM:
+ if (fdispla == XYFD_B) {
+ if (n == SKP_XNX)
+ printf(": WOULD BE TRANSFERRED (New file)\n");
+ else if (n == SKP_XUP)
+ printf(": WOULD BE TRANSFERRED (Remote file older)\n");
+ else if (n == SKP_SIM)
+ printf(": WOULD BE TRANSFERRED\n");
+ else if (n > 0 && n < nskreason)
+ printf(": SKIPPED (%s)\n",skreason[n]);
+ else
+ printf(": SKIPPED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Would Send: "); /* Action */
+ else if (what & W_RECV) conol("Would Receive: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ }
+ conoll(" [simulated]");
+ return;
+ }
+ if ((hpos += 10) > 78) conoll("");
+ conol(" [simulated]"); hpos = 0;
+ return;
+
+ case ST_SKIP: /* Skipped */
+ if (fdispla == XYFD_B) {
+ if (n == SKP_XNX)
+ printf(": WOULD BE TRANSFERRED (New file)\n");
+ else if (n == SKP_XUP)
+ printf(": WOULD BE TRANSFERRED (Remote file older)\n");
+ else if (n == SKP_SIM)
+ printf(": WOULD BE TRANSFERRED\n");
+ else if (n > 0 && n < nskreason)
+ printf(": SKIPPED (%s)\n",skreason[n]);
+ else
+ printf(": SKIPPED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Sending: "); /* Action */
+ else if (what & W_RECV) conol("Receiving: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ }
+ conoll(" [skipped]");
+ return;
+ }
+ if ((hpos += 10) > 78) conoll("");
+ conol(" "); conol(fbuf);
+ conoll(" [skipped]"); hpos = 0;
+ return;
+
+ case ST_ERR: /* Error */
+ if (fdispla == XYFD_B) {
+ printf(": ERROR: %s\n",s);
+ return;
+ }
+ conoll("");
+ conol("Error: "); conoll(s); hpos = 0;
+ return;
+
+ case ST_MSG: /* Message */
+#ifdef NEWFTP
+ if (fdispla == XYFD_B) {
+ if (ftp && ftp_deb)
+ printf(": MESSAGE: %s\n",s);
+ return;
+ }
+#endif /* NEWFTP */
+ conoll("");
+ conol("Message: ");
+ conoll(s);
+ hpos = 0;
+ return;
+
+ case ST_REFU: /* Refused */
+ if (fdispla == XYFD_B) {
+ printf(": REFUSED\n");
+ return;
+ } else if (fdispla == XYFD_S) {
+ if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
+ conoll(""); /* New line */
+ if (what & W_SEND) conol("Sending: "); /* Action */
+ else if (what & W_RECV) conol("Receiving: ");
+ conol(fbuf);
+ if (*abuf) conol(" => "); conol(abuf); /* Names */
+ if (*a2buf) conol(" => "); conol(a2buf); /* Names */
+ *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
+ conoll("");
+ }
+ conol("Refused: "); conoll(s);
+ return;
+ }
+ conoll("");
+ conol("Refused: "); conoll(s); hpos = 0;
+ return;
+
+ case ST_INC: /* Incomplete */
+ if (fdispla == XYFD_B) {
+ printf(": INCOMPLETE\n");
+ return;
+ }
+ if ((hpos += 12) > 78) conoll("");
+ conoll(" [incomplete]"); hpos = 0;
+ return;
+
+ default:
+ conoll("*** screen() called with bad status ***");
+ hpos = 0;
+ return;
+ }
+
+#ifdef MAC
+ case SCR_PN: /* Packet number */
+ if (fdispla == XYFD_B) {
+ return;
+ }
+ ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
+ conol(buf); hpos += (int)strlen(buf); return;
+#endif /* MAC */
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (fdispla == XYFD_B)
+ return;
+ if (c == 'Y') return; /* Don't bother with ACKs */
+ if (c == 'D') { /* In data transfer phase, */
+ showpkt(NUL); /* show progress. */
+ return;
+ }
+#ifndef AMIGA
+ if (hpos++ > 77) { /* If near right margin, */
+ conoll(""); /* Start new line */
+ hpos = 0; /* and reset counter. */
+ }
+#endif /* AMIGA */
+ if (c == 'Z' && fdispla == XYFD_S)
+ return;
+ else
+ conoc(c); /* Display the packet type. */
+#ifdef AMIGA
+ if (c == 'G') conoll(""); /* New line after G packets */
+#endif /* AMIGA */
+ return;
+
+ case SCR_TC: /* Transaction complete */
+ if (xfrbel) bleep(BP_NOTE);
+ if (fdispla == XYFD_B) { /* Brief display... */
+ if (filcnt > 1) {
+ long fx;
+ fx = filcnt - filrej;
+ printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s"));
+ printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s"));
+#ifdef GFTIMER
+ printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
+#else
+ printf(", %ld sec, %ld cps", tsecs, tfcps);
+#endif /* GFTIMER */
+ printf(".\n");
+ }
+ } else {
+ conoll("");
+ }
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ return;
+
+ case SCR_EM: /* Error message */
+ if (fdispla == XYFD_B) {
+ printf(" ERROR: %s\n",s);
+ return;
+ }
+ conoll(""); conoc('?'); conoll(s); hpos = 0; return;
+
+ case SCR_WM: /* Warning message */
+ if (fdispla == XYFD_B) {
+ printf(" WARNING: %s\n",s);
+ return;
+ }
+ conoll(""); conoll(s); hpos = 0; return;
+
+ case SCR_MS: /* Message from other Kermit */
+ if (fdispla == XYFD_B) {
+ printf(" MESSAGE: %s\n",s);
+ return;
+ }
+ conoll(""); conoll(s); hpos = 0; return;
+
+ case SCR_TU: /* Undelimited text */
+ if (fdispla == XYFD_B)
+ return;
+ if ((hpos += len) > 77) { conoll(""); hpos = len; }
+ conol(s); return;
+
+ case SCR_TN: /* Text delimited at beginning */
+ if (fdispla == XYFD_B)
+ return;
+ conoll(""); conol(s); hpos = len; return;
+
+ case SCR_TZ: /* Text delimited at end */
+ if (fdispla == XYFD_B)
+ return;
+ if ((hpos += len) > 77) { conoll(""); hpos = len; }
+ conoll(s); return;
+
+ case SCR_QE: /* Quantity equals */
+ if (fdispla == XYFD_B)
+ return;
+ ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
+ conoll(buf); hpos = 0; return;
+
+ case SCR_CW: /* Close fullscreen window */
+ return; /* No window to close */
+
+ case SCR_CD:
+ return;
+
+ default:
+ conoll("*** screen() called with bad object ***");
+ hpos = 0;
+ return;
+ }
+}
+#endif /* NODISPLAY */
+
+/* E R M S G -- Nonfatal error message */
+
+/* Should be used only for printing the message text from an Error packet. */
+
+VOID
+ermsg(msg) char *msg; { /* Print error message */
+ debug(F110,"ermsg",msg,0);
+ if (local)
+ xxscreen(SCR_EM,0,0L,msg);
+ tlog(F110,"Protocol Error:",msg,0L);
+}
+#endif /* NOXFER */
+
+VOID
+setseslog(x) int x; {
+ seslog = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_CAPTURE,x,0);
+#endif /* KUI */
+}
+
+VOID
+doclean(fc) int fc; { /* General cleanup */
+#ifdef OS2ORUNIX
+ extern int ttyfd;
+#endif /* OS2ORUNIX */
+ extern int keep;
+ extern int exithangup;
+#ifndef NOXFER
+ extern char filnam[];
+#endif /* NOXFER */
+#ifndef NOICP
+ int x;
+
+ if (fc > 0)
+ dostop(); /* Stop all command files and end macros */
+#endif /* NOICP */
+
+#ifndef NOXFER
+ if (pktlog) {
+ *pktfil = '\0';
+ pktlog = 0;
+ zclose(ZPFILE);
+ }
+#endif /* NOXFER */
+ if (seslog) {
+ *sesfil = '\0';
+ setseslog(0);
+ zclose(ZSFILE);
+ }
+#ifdef TLOG
+ if (tralog) {
+ tlog(F100,"Transaction Log Closed","",0L);
+ *trafil = '\0';
+ tralog = 0;
+ zclose(ZTFILE);
+ }
+#endif /* TLOG */
+
+ debug(F100,"doclean calling dologend","",0);
+ dologend(); /* End current log record if any */
+#ifdef COMMENT
+ if (dialog) { /* If connection log open */
+ dialog = 0;
+ *diafil = '\0'; /* close it. */
+ zclose(ZDIFIL);
+ }
+#endif /* COMMENT */
+
+#ifndef NOICP
+#ifndef NOSPL
+ zclose(ZRFILE); /* READ and WRITE files, if any. */
+ zclose(ZWFILE);
+#ifndef NOXFER
+ zclose(ZIFILE); /* And other files too */
+ x = chkfn(ZOFILE); /* Download in progress? */
+ debug(F111,"doclean chkfn ZOFILE",filnam,x);
+ debug(F111,"doclean keep","",keep);
+ zclose(ZOFILE); /* Close output file */
+ if (x > 0 && !keep) { /* If it was being downloaded */
+ if (filnam[0])
+ x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */
+ debug(F111,"doclean download filename",filnam,x);
+ }
+#endif /* NOXFER */
+ zclose(ZSYSFN);
+ zclose(ZMFILE);
+
+ if (fc < 1) { /* RESETing, not EXITing */
+#ifdef DEBUG
+ if (deblog) { /* Close the debug log. */
+ *debfil = '\0';
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#endif /* DEBUG */
+ return;
+ }
+#endif /* NOSPL */
+#endif /* NOICP */
+
+#ifndef NOLOCAL
+ debug(F101,"doclean exithangup","",exithangup);
+ if (local && exithangup) { /* Close communication connection */
+ extern int haslock;
+ int x;
+
+ x = ttchk();
+ debug(F101,"doclean ttchk()","",x);
+#ifdef OS2ORUNIX
+ debug(F101,"doclean ttyfd","",ttyfd);
+#endif /* OS2ORUNIX */
+ if (x >= 0
+#ifdef OS2
+ || ttyfd != -1
+#else
+#ifdef UNIX
+ || haslock /* Make sure we get lockfile! */
+ || (!network && ttyfd > -1)
+#endif /* UNIX */
+#endif /* OS2 */
+ ) {
+ extern int wasclosed, whyclosed;
+ debug(F100,"doclean hanging up and closing","",0);
+ if (msgflg) {
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ printf("Closing %s...",ttname);
+ }
+#ifndef NODIAL
+ mdmhup(); /* Hangup the modem??? */
+#endif /* NODIAL */
+ ttclos(0); /* Close external line, if any */
+ if (msgflg) {
+ printf("OK\n");
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ }
+ if (wasclosed) {
+ whyclosed = WC_CLOS;
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_close",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ wasclosed = 0;
+ /* printf("ON_CLOSE DOCLEAN\n"); */
+ *(mactab[k].kwd) = NUL; /* See comment below */
+ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ wasclosed = 0;
+ }
+ }
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
+ local = dfloc; /* And default remote/local status */
+ }
+#ifdef DEBUG
+ else if (local) debug(F100,"doclean hangup/close skipped","",0);
+#endif /* DEBUG */
+#endif /* NOLOCAL */
+
+#ifdef NEWFTP
+ ftpbye(); /* If FTP connection open, close it */
+#endif /* NEWFTP */
+
+#ifdef IKSD
+ if (inserver)
+ ttclos(0); /* If IKSD, close socket */
+#endif /* IKSD */
+
+#ifndef NOSPL
+/*
+ If a macro named "on_exit" is defined, execute it. Also remove it from the
+ macro table, in case its definition includes an EXIT or QUIT command, which
+ would cause much recursion and would prevent the program from ever actually
+ EXITing.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_exit"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */
+ if (k >= 0) { /* If found, */
+#ifdef COMMENT
+ /* This makes a mess if ON_EXIT itself executes macros */
+ *(mactab[k].kwd) = NUL; /* poke its name from the table, */
+#else
+ /* Replace the keyword with something that doesn't wreck the */
+ /* order of the keyword table */
+ ckstrncpy(mactab[k].kwd,"on_exxx",8);
+#endif /* COMMENT */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+/*
+ Put console terminal back to normal. This is done here because the
+ ON_EXIT macro calls the parser, which meddles with console terminal modes.
+*/
+ conres(); /* Restore console terminal. */
+
+#ifdef COMMENT
+/* Should be no need for this, and maybe it's screwing things up? */
+ connoi(); /* Turn off console interrupt traps */
+#endif /* COMMENT */
+
+ /* Delete the Startup File if we are supposed to. */
+#ifndef NOICP
+ {
+ extern int DeleteStartupFile;
+ debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
+ if (DeleteStartupFile) {
+ int rc = zdelet(cmdfil);
+ debug(F111,"doclean zdelet",cmdfil,rc);
+ }
+ }
+#endif /* NOICP */
+ syscleanup(); /* System-dependent cleanup, last */
+}
+
+/* D O E X I T -- Exit from the program. */
+
+/*
+ First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
+ If second arg is -1, take 1st arg literally.
+ If second arg is not -1, work it into the exit code.
+*/
+VOID
+doexit(exitstat,code) int exitstat, code; {
+ extern int x_logged, quitting;
+#ifdef OS2
+ extern int display_demo;
+ extern int SysInited;
+#endif /* OS2 */
+#ifdef CK_KERBEROS
+#ifdef KRB4
+ extern int krb4_autodel;
+#endif /* KRB4 */
+#ifdef KRB5
+ extern int krb5_autodel;
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifdef VMS
+ char envstr[64];
+ static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
+ static struct dsc$descriptor_s symval;
+#endif /* VMS */
+ int i;
+
+#ifdef DEBUG
+#ifdef USE_LUCACHE
+ extern long lucalls, luhits, xxhits, luloop;
+ extern int lusize;
+#endif /* USE_LUCACHE */
+#ifndef NOSPL
+ extern int cmdstats[];
+#endif /* NOSPL */
+
+ quitting++;
+
+#ifdef OS2
+ if ( !SysInited ) {
+ static int initing = 0;
+ if ( initing )
+ exit(253);
+ initing = 1;
+ sysinit();
+ }
+#endif /* OS2 */
+
+ if (deblog) {
+#ifdef USE_LUCACHE
+ debug(F101,"lookup cache size","",lusize);
+ debug(F101,"lookup calls ....","",lucalls);
+ debug(F101,"lookup cache hits","",luhits);
+ debug(F101,"lookup start hits","",xxhits);
+ debug(F101,"lookup loop iterations","",luloop);
+#endif /* USE_LUCACHE */
+#ifndef NOSPL
+ for (i = 0; i < 256; i++) {
+ if (cmdstats[i])
+ debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
+ }
+#endif /* NOSPL */
+ debug(F101,"doexit exitstat","",exitstat);
+ debug(F101,"doexit code","",code);
+ debug(F101,"doexit xitsta","",xitsta);
+ }
+#endif /* DEBUG */
+
+#ifdef CK_KERBEROS
+ /* If we are automatically destroying Kerberos credentials on Exit */
+ /* do it now. */
+#ifdef KRB4
+ if (krb4_autodel == KRB_DEL_EX) {
+ extern struct krb_op_data krb_op;
+ krb_op.version = 4;
+ krb_op.cache = NULL;
+ ck_krb4_destroy(&krb_op);
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (krb5_autodel == KRB_DEL_EX) {
+ extern struct krb_op_data krb_op;
+ extern char * krb5_d_cc;
+ krb_op.version = 5;
+ krb_op.cache = krb5_d_cc;
+ ck_krb5_destroy(&krb_op);
+ }
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (SysInited)
+ {
+#ifdef DCMDBUF
+ extern struct cmdptr *cmdstk;
+#else
+ extern struct cmdptr cmdstk[];
+#endif /* DCMDBUF */
+ extern int tt_status[];
+ extern int vmode;
+
+ /* If there is a demo screen to be displayed, display it */
+ if (display_demo) {
+ demoscrn(VCMD);
+ display_demo = 0;
+ }
+#ifndef KUI
+ /* This is going to be hideous. If we have a status line */
+ /* in the command window turn it off before we exit. */
+
+ if ( tt_status[VCMD] && vmode == VCMD ) {
+ domac("_clear_statusline","set command statusline off",
+ cmdstk[cmdlvl].ccflgs);
+ delmac("_clear_statusline",1);
+ RequestScreenMutex(-1);
+ VscrnIsDirty(vmode);
+ ReleaseScreenMutex();
+ while ( IsVscrnDirty(vmode) )
+ msleep(200);
+ RequestScreenMutex(-1);
+ ReleaseScreenMutex();
+ }
+#endif /* KUI */
+ DialerSend(OPT_KERMIT_EXIT,exitstat);
+#ifndef KUI
+ debug(F100,"doexit about to msleep","",0);
+
+ if ( isWin95() )
+ msleep(250);
+#endif /* KUI */
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && x_logged) {
+#ifndef NOSPL
+/*
+ If a macro named "on_logout" is defined, execute it. Also remove it from the
+ macro table, in case its definition includes an EXIT or QUIT command, which
+ would cause much recursion and would prevent the program from ever actually
+ EXITing.
+*/
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ char * cmd = "on_logout"; /* MSVC 2.x compiler error */
+ k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
+ if (k >= 0) { /* If found, */
+ *(mactab[k].kwd) = NUL; /* poke its name from the table, */
+ if (dodo(k,"",0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ zvlogout();
+ }
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+ debug(F100,"doexit about to doclean","",0);
+ doclean(1); /* Clean up most things */
+
+#ifdef VMS
+ if (code == -1)
+ code = 0; /* Since we set two different items */
+ sprintf(envstr,"%d", exitstat | code); /* SAFE */
+ symval.dsc$w_length = (int)strlen(envstr);
+ symval.dsc$a_pointer = envstr;
+ symval.dsc$b_class = DSC$K_CLASS_S;
+ symval.dsc$b_dtype = DSC$K_DTYPE_T;
+ i = 2; /* Store in global table */
+#ifdef COMMENT /* Martin Zinser */
+ LIB$SET_SYMBOL(&symnam, &symval, &i);
+#else
+ lib$set_symbol(&symnam, &symval, &i);
+#endif /* COMMENT */
+ if (exitstat == BAD_EXIT)
+ exitstat = SS$_ABORT | STS$M_INHIB_MSG;
+ if (exitstat == GOOD_EXIT)
+ exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
+#else /* Not VMS */
+ if (code != -1) /* Take 1st arg literally */
+ exitstat |= code;
+#endif /* VMS */
+
+#ifdef IKSD
+#ifdef IKSDB
+ debug(F101,"doexit ikdbopen","",ikdbopen);
+ if (ikdbopen && dbfp) { /* If IKSD database open */
+ int x;
+ x = freeslot(mydbslot); /* Free our slot... */
+ debug(F101,"doexit freeslot","",x);
+ fclose(dbfp); /* and close it. */
+ }
+#endif /* IKSDB */
+#endif /* IKSD */
+
+/* We have put this off till the very last moment... */
+
+#ifdef DEBUG
+ if (deblog) { /* Close the debug log. */
+ debug(F101,"C-Kermit EXIT status","",exitstat);
+ *debfil = '\0';
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#endif /* DEBUG */
+
+#ifdef OS2
+ _exit(exitstat); /* Exit from C-Kermit (no matter what) */
+#else /* OS2 */
+ exit(exitstat); /* Exit from C-Kermit */
+#endif /* OS2 */
+}
+
+VOID
+bgchk() { /* Check background status */
+ if (bgset < 0) { /* They didn't type SET BACKGROUND */
+#ifdef VMS /* Set prompt flag based on */
+ pflag = !batch; /* what we detected at startup. */
+#else
+ pflag = !backgrd;
+#endif /* VMS */
+ } else { /* Otherwise SET BACKGROUND value */
+ pflag = (bgset == 0 ? 1 : 0);
+ }
+
+#ifndef NOICP
+ /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
+ if (!xcmdsrc)
+ msgflg = (pflag == 0) ? 0 : !quiet;
+ else msgflg = 0;
+#else
+ msgflg = 0;
+#endif /* NOICP */
+}
+
+/* Set console interrupts */
+
+VOID
+setint() { /* According to SET COMMAND INTERRUP */
+ int x = 0;
+ if (cmdint) x |= 1;
+ if (xsuspend) x |= 2;
+ debug(F101,"setint","",x);
+
+ switch (x) { /* Set the desired combination */
+ case 0: connoi(); break; /* No interrupts */
+ case 1: conint(trap,SIG_IGN); break;
+ case 2: conint(SIG_IGN,stptrap); break;
+ case 3: conint(trap,stptrap); break;
+ }
+ bgchk(); /* Check background status */
+}
+
+#ifdef DEBUG
+/* D E B U G -- Enter a record in the debugging log */
+
+/*
+ Call with a format, two strings, and a number:
+ f - Format, a bit string in range 0-7.
+ If bit x is on, then argument number x is printed.
+ s1 - String, argument number 1. If selected, printed as is.
+ s2 - String, argument number 2. If selected, printed in brackets.
+ n - Long int, argument 3. If selected, printed preceded by equals sign.
+
+ f=0 is special: print s1,s2, and interpret n as a char.
+
+ f=F011 (3) is also special; in this case s2 is interpeted as a counted
+ string that might contain NULs. n is the length. If n is negative, this
+ means the string has been truncated and ".." should be printed after the
+ first n bytes. NUL and LF bytes are printed as "<NUL>" and "<LF>".
+
+ Globals:
+ deblog: nonzero if debug log open.
+ debok: nonzero if ok to write entries.
+*/
+/*
+ WARNING: Don't change DEBUFL without changing sprintf() formats below,
+ accordingly.
+*/
+#define DBUFL 4000
+/*
+ WARNING: This routine is not thread-safe, especially when Kermit is
+ executing on multiple CPUs -- as different threads write to the same
+ static buffer, the debug statements are all interleaved. To be fixed
+ later...
+*/
+static char *dbptr = (char *)0;
+
+int
+#ifdef CK_ANSIC
+dodebug(int f, char *s1, char *s2, CK_OFF_T n)
+#else
+dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n;
+#endif /* CK_ANSIC */
+/* dodebug */ {
+ char *sp;
+ int len1, len2;
+ extern int debtim;
+#ifdef OS2
+ extern int SysInited;
+#endif /* OS2 */
+
+ if (!deblog || !debok)
+ return(0);
+
+#ifdef COMMENT
+ /* expensive... */
+ if (!chkfn(ZDFILE)) /* Debug log not open, don't. */
+ return(0);
+#endif /* COMMENT */
+ if (!dbptr) { /* Allocate memory buffer */
+ dbptr = malloc(DBUFL+4); /* This only happens once */
+ if (!dbptr) {
+ zclose(ZDFILE);
+ return(0);
+ }
+ }
+/*
+ This prevents infinite recursion in case we accidentally put a debug()
+ call in this routine, or call another routine that contains debug() calls.
+ From this point on, all returns from this return must be via goto xdebug,
+ which sets deblog back to 1.
+*/
+#ifdef OS2
+ if (SysInited) {
+ if (RequestDebugMutex(30000))
+ goto xdebug;
+ }
+#else /* OS2 */
+ deblog = 0; /* Prevent infinite recursion */
+#endif /* OS2 */
+
+ if (debtim) { /* Timestamp */
+ char *tb, tsbuf[48];
+ ztime(&tb);
+ ckstrncpy(tsbuf,tb,32);
+ if (ztmsec > -1L) {
+ sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
+ } else {
+ tsbuf[19] = ':';
+ tsbuf[20] = SP;
+ tsbuf[21] = NUL;
+ }
+ zsout(ZDFILE,tsbuf+11);
+ }
+ if (!s1) s1="(NULL)";
+ if (!s2) s2="(NULL)";
+
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+
+#ifdef COMMENT
+/*
+ This should work, but it doesn't.
+ So instead we'll cope with overflow via sprintf formats.
+ N.B.: UNFORTUNATELY, this means we have to put constants in the
+ sprintf formats.
+*/
+ if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
+ x = (int) strlen(s1) + (int) strlen(s2) + 18;
+ if (x > dbufl) { /* Longer than buffer? */
+ if (dbptr) /* Yes, free previous buffer */
+ free(dbptr);
+ dbptr = (char *) malloc(x + 2); /* Allocate a new one */
+ if (!dbptr) {
+ zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ } else {
+ dbufl = x;
+ sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
+ zsoutl(ZDFILE,dbptr);
+ }
+ }
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/* The aforementioned sprintf() formats were like this: */
+ if (n > 31 && n < 127)
+ sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
+ else if (n > 159 && n < 256)
+ sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
+ else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
+/*
+ But, naturally, it turns out these are not portable either, so now
+ we do the stupidest possible thing.
+*/
+#endif /* COMMENT */
+
+#ifdef BIGBUFOK
+/* Need to accept longer strings when debugging authenticated connections */
+ if (f == F010) {
+ if (len2 + 2 >= DBUFL) s2 = "(string too long)";
+ } else if (f != F011 && f != F100) {
+ if (len1 > 100) s1 = "(string too long)";
+ if (len2 + 101 >= DBUFL) s2 = "(string too long)";
+ }
+#else
+ if (f != F011) {
+ if (len1 > 100) s1 = "(string too long)";
+ if (len2 + 101 >= DBUFL) s2 = "(string too long)";
+ }
+#endif /* BIGBUFOK */
+
+ sp = dbptr;
+
+ switch (f) { /* Write log record according to format. */
+ case F000: /* 0 = print both strings, and n as a char. */
+ if (len2 > 0) {
+ if ((n > 31 && n < 127) || (n > 159 && n < 256))
+ sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
+ else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n);
+ } else {
+ if ((n > 31 && n < 127) || (n > 159 && n < 256))
+ sprintf(sp,"%s=%c\n",s1,(CHAR) n);
+ else if (n < 32 || n == 127)
+ sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
+ else if (n > 127 && n < 160)
+ sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
+ else sprintf(sp,"%s=0x%lX\n",s1,(long)n);
+ }
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+
+ case F001: /* 1, "=n" */
+#ifdef COMMENT
+ /* This was never used */
+ sprintf(sp,"=%s\n",ckfstoa(n));
+#else
+ /* Like F111, but shows number n in hex */
+ ckmakxmsg(sp,DBUFL,
+ s1,
+ (*s1 ? ":" : ""),
+ s2,
+ (*s2 ? ":" : ""),
+ ckltox(n),
+ "\n",
+ NULL,NULL,NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+
+/*
+ This one was never used so (October 2000) we now use it like F011,
+ except in this case we treat s2 as NUL terminated.
+*/
+ case F010:
+ n = -debxlen;
+/*
+ This one treats n as the length of the string s2, which may contain NULs.
+ It's good for logging NUL-bearing data in the debug log.
+*/
+ case F011: {
+ int i, j, contd = 0;
+ char * p = s2, *pbuf = NULL; /* p = source pointer */
+ int m; /* pbuf = destination pointer */
+
+ if (f == F011) {
+ if (n < 0) { /* n = size of source */
+ n = 0 - n; /* Negative means to add "..." */
+ contd = 1;
+ }
+ } else {
+ int x, flag = 0;
+ x = strlen(s2);
+ if (n < 0) {
+ flag = 1;
+ n = 0 - n;
+ }
+ if (x < n)
+ n = x;
+ }
+ if (n == 0) /* 0 means do nothing */
+ goto xdebug;
+ m = DBUFL - 8; /* Get size for interpreted part */
+ if (n > m) /* Ensure requested size not too big */
+ n = m;
+ pbuf = dbptr; /* Construction pointer */
+ i = 0;
+ pbuf[i++] = '['; /* Interpret the string into it */
+ for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
+ if (*p == LF) {
+ if (i >= m-4)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'L';
+ pbuf[i++] = 'F';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p == CR) {
+ if (i >= m-4)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'C';
+ pbuf[i++] = 'R';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p == HT) {
+ if (i >= m-5)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'T';
+ pbuf[i++] = 'A';
+ pbuf[i++] = 'B';
+ pbuf[i++] = '>';
+ continue;
+ } else if (*p) {
+ pbuf[i++] = *p;
+ continue;
+ } else {
+ if (i >= m-5)
+ break;
+ pbuf[i++] = '<';
+ pbuf[i++] = 'N';
+ pbuf[i++] = 'U';
+ pbuf[i++] = 'L';
+ pbuf[i++] = '>';
+ continue;
+ }
+ }
+ if (i < m-2 && (*p || contd)) {
+ pbuf[i++] = '.';
+ pbuf[i++] = '.';
+ }
+ pbuf[i++] = ']';
+ pbuf[i] = NUL;
+ if (zsout(ZDFILE,s1) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+ if (zsoutl(ZDFILE,pbuf) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
+ }
+#endif /* CKSYSLOG */
+ }
+ break;
+
+ case F100: /* 4, "s1" */
+ if (zsoutl(ZDFILE,s1) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",s1,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F101: /* 5, "s1=n" */
+ sprintf(sp,"%s=%s\n",s1,ckfstoa(n));
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F110: /* 6, "s1[s2]" */
+ sprintf(sp,"%s[%s]\n",s1,s2);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ case F111: /* 7, "s1[s2]=n" */
+ sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n));
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ default:
+ sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ }
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_DB && ckxlogging) {
+ cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
+ }
+#endif /* CKSYSLOG */
+ break;
+ }
+ xdebug: /* Common exit point */
+#ifdef OS2
+ if (SysInited)
+ ReleaseDebugMutex();
+#else /* OS2 */
+ deblog = 1; /* Restore this */
+#endif /* OS2 */
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+dohexdump(CHAR *msg, CHAR *st, int cnt)
+#else
+dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
+#endif /* CK_ANSIC */
+/* dohexdump */ {
+ int i = 0, j = 0, k = 0;
+ char tmp[8];
+#ifdef OS2
+ extern int SysInited;
+#endif /* OS2 */
+
+ if (!deblog) return(0); /* If no debug log, don't. */
+ if (!dbptr) { /* Allocate memory buffer */
+ dbptr = malloc(DBUFL+1); /* This only happens once */
+ if (!dbptr) {
+ deblog = 0;
+ zclose(ZDFILE);
+ return(0);
+ }
+ }
+
+#ifdef OS2
+ if (SysInited) {
+ if (RequestDebugMutex(30000))
+ goto xdebug;
+ }
+#else /* OS2 */
+ deblog = 0; /* Prevent infinite recursion */
+#endif /* OS2 */
+
+ if (msg != NULL) {
+ ckmakxmsg(dbptr,
+ DBUFL,
+ "HEXDUMP: ",
+ (char *)msg,
+ " (",
+ ckitoa(cnt),
+ " bytes)\n",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ } else {
+ ckmakmsg(dbptr,
+ DBUFL,
+ "HEXDUMP: (",
+ ckitoa(cnt),
+ " bytes)\n",
+ NULL
+ );
+ zsout(ZDFILE,dbptr);
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ }
+ for (i = 0; i < cnt; i++) {
+ dbptr[0] = '\0';
+ for (j = 0 ; (j < 16); j++) {
+ if ((i + j) < cnt)
+ sprintf(tmp,
+ "%s%02x ",
+ (j == 8 ? "| " : ""),
+ (CHAR) st[i + j]
+ );
+ else
+ sprintf(tmp,
+ "%s ",
+ (j == 8 ? "| " : "")
+ );
+ ckstrncat(dbptr,tmp,DBUFL+1);
+ }
+ ckstrncat(dbptr," ",DBUFL+1);
+ for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
+ sprintf(tmp,
+ "%s%c",
+ (k == 8 ? " " : ""),
+ isprint(st[i + k]) ? st[i + k] : '.'
+ );
+ ckstrncat(dbptr,tmp,DBUFL+1);
+ }
+ ckstrncat(dbptr,"\n",DBUFL+1);
+ i += j - 1;
+ if (zsout(ZDFILE,dbptr) < 0) {
+ deblog = 0;
+ zclose(ZDFILE);
+ goto xdebug;
+ }
+ } /* end for */
+
+
+ xdebug:
+#ifdef OS2
+ if (SysInited)
+ ReleaseDebugMutex();
+#else /* OS2 */
+ deblog = 1;
+#endif /* OS2 */
+ return(0);
+}
+#endif /* DEBUG */
+
+/* Session Log... */
+
+int tsstate = 0;
+
+VOID
+#ifdef OS2
+logchar(unsigned short c)
+#else /* OS2 */
+#ifdef CK_ANSIC
+logchar(char c)
+#else
+logchar(c) char c;
+#endif /* CK_ANSIC */
+#endif /* OS2 */
+/* logchar */ { /* Log character c to session log */
+ extern int slognul;
+ int oktolog = 0;
+#ifndef NOLOCAL
+ if (!seslog)
+ return;
+
+ if ((sessft != XYFT_T) || (
+#ifdef UNIX
+ c != '\r' &&
+#else
+#ifdef datageneral
+ c != '\r' &&
+#else
+#ifdef STRATUS
+ c != '\r' &&
+#else
+#ifdef AMIGA
+ c != '\r' &&
+#else
+#ifdef GEMDOS
+ c != '\r' &&
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* UNIX */
+#ifdef OSK
+ c != '\n' &&
+#else
+#ifdef MAC
+ c != '\n' &&
+#endif /* MAC */
+#endif /* OSK */
+ c != XON &&
+ c != XOFF))
+ oktolog = 1;
+ if (c == '\0' && !sessft) /* NUL in text mode */
+ if (slognul) oktolog = 1; /* only if padding (2009/10/22) */
+ if (!oktolog)
+ return;
+ if (slogts) { /* Log is timestamped */
+ if (tsstate == 0) { /* State = between-lines */
+ char * p; /* zstime() pointer */
+ char ts[48]; /* timestamp buffer */
+ ztime(&p); /* Get asctime() string */
+ ckstrncpy(ts,p,32); /* Make safe copy */
+ if (ztmsec > -1L) { /* Add msecs if we have them */
+ sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
+ } else {
+ ts[19] = ':';
+ ts[20] = SP;
+ ts[21] = NUL;
+ }
+ if (zsout(ZSFILE,&ts[11]) < 0)
+ goto xlogchar;
+ }
+ }
+ if (c == '\n') /* At end of line? */
+ tsstate = 0; /* yes */
+ else
+ tsstate = 1; /* no */
+ if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
+ goto xlogchar;
+ if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */
+ if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */
+ goto xlogchar;
+ }
+ return;
+
+ xlogchar:
+ conoll("");
+ conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
+ setseslog(0);
+ zclose(ZSFILE);
+#endif /* NOLOCAL */
+}
+
+VOID
+logstr(s, len) char * s; int len; { /* Log string to session log */
+#ifndef NOLOCAL
+ int n = 0;
+ if (!s)
+ return;
+ while (seslog && (n < len))
+ logchar(s[n++]);
+#endif /* NOLOCAL */
+}
+
+#ifdef CK_CURSES
+int
+ck_repaint() {
+ repaint = 1;
+ return(0);
+}
+
+#ifdef STRATUS
+/* VOS has curses but no tgetent() */
+int
+tgetent(s1, s2) char * s1, * s2; {
+ return(1);
+}
+#endif /* STRATUS */
+
+#ifdef VMS
+#ifdef __DECC
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* __DECC */
+#endif /* VMS */
+
+/*
+ There are three different ways to do fullscreen on VMS.
+ 1. Use the real curses library, VAXCCURSE.
+ 2. Use do-it-yourself code.
+ 3. Use the Screen Manager, SMG$.
+
+ Method 1 doesn't work quite right; you can't call endwin(), so once you've
+ started curses mode, you can never leave.
+
+ Method 2 doesn't optimize the screen, and so much more time is spent in
+ screen writes. This actually causes file transfers to fail because the
+ tty device input buffer can be overrun while the screen is being updated,
+ especially on a slow MicroVAX that has small typeahead buffers.
+
+ In the following #ifdef block, #define one of them and #undef the other 2.
+
+ So now let's try method 3...
+*/
+#ifdef VMS
+#define CK_SMG /* Screen Manager */
+#undef MYCURSES /* Do-it-yourself */
+#undef VMSCURSE /* VAXCCURSE library */
+#endif /* VMS */
+/*
+ But just before New Years, 2000, the SMG library seemed to break on
+ both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
+ So back to MYCURSES, which works fine.
+*/
+#ifdef VMS
+#undef CK_SMG
+#define MYCURSES
+#endif /* VMS */
+
+#ifdef MYCURSES
+#define stdscr 0
+#ifdef CK_WREFRESH
+#undef CK_WREFRESH
+#endif /* CK_WREFRESH */
+#endif /* MYCURSES */
+
+/* S C R E E N C -- Screen display function, uses curses */
+
+/* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
+
+/* Avoid conficts with curses.h */
+
+#ifdef QNX
+/* Same as ckcasc.h, but in a different radix... */
+#ifdef ESC
+#undef ESC
+#endif /* ESC */
+#endif /* QNX */
+
+#ifndef MYCURSES
+#undef VOID /* This was defined in ckcdeb.h */
+#endif /* MYCURSES */
+
+#undef BS /* These were defined in ckcasc.h */
+#undef CR
+#undef NL
+#undef SO
+#ifdef US
+#undef US
+#endif /* US */
+#undef SP /* Used in ncurses */
+#define CHR_SP 32 /* Use this instead */
+
+#ifdef VMS /* VMS fullscreen display */
+#ifdef MYCURSES /* Do-it-yourself method */
+extern int isvt52; /* From CKVTIO.C */
+#define printw printf
+#else
+#ifdef VMSCURSE /* VMS curses library VAXCCURSE */
+#include <curses.h>
+/* Note: Screen manager doesn't need a header file */
+#endif /* VMSCURSE */
+#endif /* MYCURSES */
+#else /* Not VMS */
+#ifdef MYCURSES /* Do-it-yourself method */
+#define isvt52 0 /* Used by OS/2, VT-100/ANSI always */
+#ifdef CKXPRINTF
+#define printw ckxprintf
+#else /* CKXPRINTF */
+#ifdef KUI
+#define printw Vscrnprintw
+#else /* KUI */
+#define printw printf
+#endif /* KUI */
+#endif /* CKXPRINTF */
+#else /* Use real curses */
+#ifdef CK_NCURSES /* or ncurses... */
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in ncurses.h */
+#endif /* CKXPRINTF */
+#include <ncurses.h>
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#else /* Not ncurses */
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in curses.h */
+#endif /* CKXPRINTF */
+#ifdef M_XENIX /* SCO XENIX... */
+#ifdef M_TERMCAP
+#undef M_TERMCAP
+#endif /* M_TERMCAP */
+#ifndef M_TERMINFO
+#define M_TERMINFO
+#endif /* M_TERMINFO */
+#endif /* M_XENIX */
+#ifdef RTAIX
+#undef NLS /* Avoid 'redeclaration of free'. */
+#endif /* RTAIX */
+#include <curses.h>
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#endif /* CK_NCURSES */
+#endif /* MYCURSES */
+#endif /* VMS */
+
+#ifdef BUG999
+_PROTOTYP(int tgetent,(char *, char *));
+_PROTOTYP(char *tgetstr,(char *, char **));
+_PROTOTYP(int tputs,(char *, int, int (*)()));
+_PROTOTYP(char *tgoto,(const char *, int, int));
+#endif /* BUG999 */
+
+#endif /* CK_CURSES */
+
+/* F X D I N I T -- File Xfer Display Initialization */
+
+#ifdef CK_CURSES
+#ifndef MYCURSES
+#ifndef CK_SMG
+static
+#ifdef CK_ANSIC
+/* Can't use VOID because of curses.h */
+void
+ck_termset(int);
+#else
+ck_termset();
+#endif /* CK_ANSIC */
+#endif /* CK_SMG */
+#endif /* MYCURSES */
+#endif /* CK_CURSES */
+
+#ifdef NOTERMCAP
+static int notermcap = 1;
+#else
+static int notermcap = 0;
+#endif /* NOTERMCAP */
+
+#ifndef NODISPLAY
+CKVOID
+fxdinit(xdispla) int xdispla; {
+#ifndef COHERENT
+#ifndef OS2
+#ifndef STRATUS
+ char *s;
+ int x, dummy;
+
+ debug(F101,"fxdinit xdispla","",xdispla);
+ debug(F101,"fxdinit fxd_inited","",fxd_inited);
+
+#ifdef IKSD
+#ifndef NOXFER
+ /* No curses for IKSD */
+ if (inserver) {
+ fdispla = XYFD_N;
+ return;
+ }
+ if (fxd_inited) /* Only do this once */
+ return;
+#endif /* NOXFER */
+#endif /* IKSD */
+
+ if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
+ if (xfrmsg) {
+ printf("%s\n",xfrmsg);
+ makestr(&xfrmsg,NULL);
+ }
+ }
+
+#ifdef CK_CURSES
+#ifdef VMS
+ /* Force BRIEF in Batch logs */
+ if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
+ xdispla = XYFD_B;
+#else
+ if (xdispla == XYFD_C || xdispla == 9999) {
+
+#ifdef DYNAMIC
+ if (!trmbuf) {
+/*
+ Allocate tgetent() buffer. Make it big -- some termcaps can be huge;
+ tgetent() merrily writes past the end of the buffer, causing core dumps
+ or worse.
+*/
+ trmbuf = (char *)malloc(TRMBUFL);
+ if (!trmbuf) {
+ notermcap = 1;
+ debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
+ fdispla = XYFD_S;
+ return;
+ }
+#ifdef COMMENT
+ debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
+ debug(F001,"fxdinit trmbuf","",trmbuf);
+ memset(trmbuf,'\0',(size_t)TRMBUFL);
+ debug(F100,"fxdinit memset OK","",0);
+#endif /* COMMENT */
+ }
+#endif /* DYNAMIC */
+
+ debug(F100,"fxdinit before getenv(TERM)","",0);
+ s = getenv("TERM");
+ debug(F110,"fxdinit after getenv(TERM)",s,0);
+ if (!s) s = "";
+ if (*s) {
+ debug(F110,"fxdinit before tgetent()",s,0);
+ x = tgetent(trmbuf,s);
+ debug(F111,"fxdinit tgetent",s,x);
+ } else {
+ x = 0;
+ notermcap = 1;
+ debug(F110,"fxdinit TERM null - no tgetent",s,0);
+ }
+ if (x < 1 && !quiet && !backgrd
+#ifdef VMS
+ && !batch
+#endif /* VMS */
+ ) {
+ printf("Warning: terminal type unknown: \"%s\"\n",s);
+#ifdef COMMENT
+ /* Confusing - nobody knows what this means */
+ printf("SCREEN command will use ANSI sequences.\n");
+#endif /* COMMENT */
+ if (local)
+ printf("Fullscreen file transfer display disabled.\n");
+ fdispla = XYFD_S;
+ }
+#ifndef MYCURSES
+#ifndef CK_SMG
+ ck_termset(x);
+#endif /* CK_SMG */
+#endif /* MYCURSES */
+ fxd_inited = 1;
+ }
+#endif /* CK_CURSES */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* COHERENT */
+}
+#endif /* NODISPLAY */
+
+#ifdef CK_CURSES
+#ifdef CK_SMG
+/*
+ Long section for Screen Manager starts here...
+ By William Bader.
+*/
+#include "ckvvms.h"
+#ifdef OLD_VMS
+#include <smgdef.h> /* use this on VAX C 2.4 */
+/* #include <smgmsg.h> */
+#else
+#include <smg$routines.h> /* Martin Zinser */
+#endif /* OLD_VMS */
+
+extern unsigned int vms_status; /* Used for system service return status */
+
+static long smg_pasteboard_id = -1; /* pasteboard identifier */
+static long smg_display_id = -1; /* display identifier */
+static int smg_open = 0; /* flag if smg current open */
+static int smg_inited = 0; /* flag if smg initialized */
+
+#ifdef COMMENT
+#define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0)
+
+#define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
+
+#define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id)
+
+#else /* Not COMMENT */
+
+#define clrtoeol() smg$erase_line(&smg_display_id, 0, 0)
+
+#define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0)
+
+#define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id)
+#endif /* COMMENT */
+
+#define clearok(curscr,ok) /* Let wrefresh() do the work */
+
+#define wrefresh(cursrc) touchwin(scr)
+
+static void
+move(row, col) int row, col; {
+ /* Change from 0-based for curses to 1-based for SMG */
+ if (!smg_open)
+ return;
+ ++row; ++col;
+ debug(F111,"VMS smg move",ckitoa(row),col);
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("move: smg$set_cursor_abs",
+ SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
+#else
+ CHECK_ERR("move: smg$set_cursor_abs",
+ smg$set_cursor_abs(&smg_display_id, &row, &col));
+#endif /* COMMENT */
+ debug(F101,"VMS smg move vms_status","",vms_status);
+}
+
+#ifdef VMS_V40
+#define OLD_VMS
+#endif /* VMS_V40 */
+#ifdef VMS_V42
+#define OLD_VMS
+#endif /* VMS_V42 */
+#ifdef VMS_V44
+#define OLD_VMS
+#endif /* VMS_V44 */
+
+static int
+initscr() {
+ int rows = 24, cols = 80;
+ int row = 1, col = 1;
+
+ debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
+
+ if (smg_pasteboard_id == -1) { /* Open the screen */
+#ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */
+ CHECK_ERR("initscr: smg$create_pasteboard",
+ smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
+#else
+ /* For VMS V5, not tested */
+ CHECK_ERR("initscr: smg$create_pasteboard",
+ smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
+#endif /* OLD_VMS */
+ }
+ debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
+ if (smg_pasteboard_id == -1) {
+ printf("?Error initializing fullscreen display\n");
+ fdispla = XYFD_S;
+ dpyinit();
+ return(0);
+ }
+ debug(F101,"VMS initscr smg_display_id","",smg_display_id);
+ if (smg_display_id == -1) { /* Create a display window */
+
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("initscr: smg$create_virtual_display",
+ SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
+ 0, 0, 0));
+
+ /* Connect the display window to the screen */
+ CHECK_ERR("initscr: smg$paste_virtual_display",
+ SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
+ &row,&col));
+#else
+ CHECK_ERR("initscr: smg$create_virtual_display",
+ smg$create_virtual_display(&rows, &cols, &smg_display_id,
+ 0, 0, 0));
+
+ /* Connect the display window to the screen */
+ CHECK_ERR("initscr: smg$paste_virtual_display",
+ smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
+ &row,&col));
+#endif /* COMMENT */
+ }
+ debug(F101,"VMS initscr smg_open A","",smg_open);
+ if (!smg_open) { /* Start a batch update */
+ smg_open = 1;
+#ifdef COMMENT
+ CHECK_ERR("initscr: smg$begin_pasteboard_update",
+ SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("initscr: smg$begin_pasteboard_update",
+ smg$begin_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+ debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
+ }
+ debug(F101,"VMS initscr smg_open B","",smg_open);
+ smg_inited = 1;
+ return(1);
+}
+
+static void
+refresh() {
+ debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
+
+ if (smg_open == 0 || smg_pasteboard_id == -1)
+ return;
+
+#ifdef COMMENT /* Martin Zinser */
+ CHECK_ERR("refresh: smg$end_pasteboard_update",
+ SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+ CHECK_ERR("refresh: smg$begin_pasteboard_update",
+ SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("refresh: smg$end_pasteboard_update",
+ smg$end_pasteboard_update(&smg_pasteboard_id));
+ CHECK_ERR("refresh: smg$begin_pasteboard_update",
+ smg$begin_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+}
+
+static void
+endwin() {
+ if (!smg_open)
+ return;
+
+ smg_open = 0;
+
+#ifdef COMMENT
+ CHECK_ERR("endwin: smg$end_pasteboard_update",
+ SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
+#else
+ CHECK_ERR("endwin: smg$end_pasteboard_update",
+ smg$end_pasteboard_update(&smg_pasteboard_id));
+#endif /* COMMENT */
+
+ move(22, 0);
+
+#ifdef COMMENT
+/*
+ These calls clear the screen.
+ (convert routine calls to lowercase - Martin Zinser)
+*/
+ CHECK_ERR("endwin: smg$delete_virtual_display",
+ SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
+ smg_display_id = -1;
+
+ CHECK_ERR("endwin: smg$delete_pasteboard",
+ SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
+ smg_pasteboard_id = -1;
+#endif /* COMMENT */
+}
+
+#ifdef COMMENT
+/* DECC 6.2 screams bloody murder about printw ("not enough args") */
+/* but adding the following prototype only makes it holler louder. */
+#ifdef __DECC
+/* "varargs" prototype for printw */
+_PROTOTYP(static int printw,(char *, ...));
+#endif /* __DECC */
+#endif /* COMMENT */
+
+#ifdef __DECC
+#include <stdarg.h>
+_PROTOTYP(static void printw,(char *, ...));
+static void
+printw(char *str,...) {
+ char buf[255];
+ va_list ap;
+ $DESCRIPTOR(text_dsc, 0);
+ text_dsc.dsc$a_pointer=buf;
+ if (!smg_open)
+ return;
+ va_start(ap,str);
+ text_dsc.dsc$w_length = vsprintf(buf, str, ap);
+ va_end(ap);
+ CHECK_ERR("printw: smg$put_chars",
+ smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
+}
+#else
+static void
+printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
+ char *str;
+ long a1, a2, a3, a4, a5, a6, a7, a8;
+/* printw */ {
+ char buf[255];
+ $DESCRIPTOR(text_dsc, 0);
+ if (!smg_open)
+ return;
+ text_dsc.dsc$a_pointer=buf;
+ text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
+ CHECK_ERR("printw: smg$put_chars",
+ smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
+}
+#endif /* __DECC */
+
+#define CK_CURPOS
+int
+ck_curpos(row, col) {
+ debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg curpos smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
+ move(row - 1, col - 1); /* SMG is 0-based */
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+
+int
+ck_cls() {
+ debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg ck_cls smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ clear();
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+
+int
+ck_cleol() {
+ debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
+ if (!smg_inited || !smg_open) {
+ initscr();
+ }
+ debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
+ if (!smg_open)
+ return(0);
+ clrtoeol();
+ refresh();
+ /* endwin(); */
+ return(0);
+}
+#endif /* CK_SMG */
+
+#ifdef MYCURSES
+/*
+ Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
+ Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
+ By Terry Kennedy, St Peters College.
+
+ First, some stuff we can just ignore:
+*/
+
+static int
+touchwin(x) int x; {
+ return(0);
+}
+static int
+initscr() {
+ return(0);
+}
+static int
+refresh() {
+ return(0);
+}
+static int
+endwin() {
+ return(0);
+}
+
+/*
+ * Now, some stuff we need to do:
+ */
+
+_PROTOTYP( int move, (int, int) );
+#ifndef OS2
+int
+move(row, col) int row, col; {
+ if (isvt52)
+ printf("\033Y%c%c", row + 037, col + 037);
+ else
+ printf("\033[%d;%dH", row + 1, col + 1);
+ return(0);
+}
+
+int
+clear() {
+ move(0,0);
+ if (isvt52)
+ printf("\033J");
+ else
+ printf("\033[J");
+ return(0);
+}
+
+int
+clrtoeol() {
+ if (isvt52)
+ printf("\033K");
+ else
+ printf("\033[K");
+ return(0);
+}
+
+#define CK_CURPOS
+int
+ck_cls() {
+ return(clear());
+}
+
+int
+ck_cleol() {
+ return(clrtoeol());
+}
+
+int
+ck_curpos(row, col) int row, col; {
+ move(row, col);
+ return(0);
+}
+
+#else /* OS2 */
+/* Windows NT and Windows 95 do not provide ANSI emulation */
+/* Therefore we might as well not use it for OS/2 either */
+
+int
+move(row, col) int row, col; {
+#ifndef ONETERMUPD
+ SetCurPos(row, col);
+#endif /* ONETERMUPD */
+ lgotoxy( VCMD, col+1, row+1);
+ VscrnIsDirty(VCMD);
+ return(0);
+}
+
+int
+clear() {
+ viocell cell;
+ move(0,0);
+#ifdef ONETERMUPD
+ if (VscrnGetBufferSize(VCMD) > 0) {
+ VscrnScroll(VCMD, UPWARD, 0,
+ VscrnGetHeight(VCMD)-(1),
+ VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
+ cleartermscreen(VCMD);
+ }
+#else
+ cell.c = ' ';
+ cell.a = colorcmd;
+ WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
+#endif /* ONETERMUPD */
+ return(0);
+}
+
+int
+clrtoeol() {
+ USHORT row, col;
+ viocell cell;
+
+ cell.c = ' ';
+ cell.a = colorcmd;
+#ifndef ONETERMUPD
+ GetCurPos(&row, &col );
+ WrtNCell(cell, cmd_cols - col -1, row, col);
+#endif /* ONETERMUPD */
+ clrtoeoln(VCMD,CHR_SP);
+ return(0);
+}
+
+#define CK_CURPOS
+int
+ck_curpos(row, col) int row, col; {
+ move(row, col);
+ return(0);
+}
+
+int
+ck_cls() {
+ return(clear());
+}
+
+int
+ck_cleol() {
+ return(clrtoeol());
+}
+
+#endif /* OS2 */
+#endif /* MYCURSES */
+
+#ifndef NOTERMCAP
+#ifndef CK_CURPOS
+#define CK_CURPOS
+
+/* Termcap/Terminfo section */
+
+static char cur_cls[32] = { NUL, NUL };
+static char cur_cleol[32] = { NUL, NUL };
+static char cur_cm[64] = { NUL, NUL };
+static char tgsbuf[128] = { NUL, NUL };
+
+static
+#ifdef CK_ANSIC
+void
+#endif /* CK_ANSIC */
+ck_termset(x) int x; {
+ cur_cls[0] = NUL;
+ cur_cleol[0] = NUL;
+ cur_cm[0] = NUL;
+#ifdef tgetent
+ debug(F100,"tgetent is a macro","",0);
+#endif /* tgetent */
+#ifdef tgetstr
+ debug(F100,"tgetstr is a macro","",0);
+#endif /* tgetstr */
+#ifdef tputs
+ debug(F100,"tputs is a macro","",0);
+#endif /* tputs */
+#ifdef tgoto
+ debug(F100,"tgoto is a macro","",0);
+#endif /* tgoto */
+#ifdef NOTERMCAP
+ /* tgetstr() gets a segmentation fault on OSF/1 */
+ debug(F100,"ck_termset NOTERMCAP","",0);
+#else
+ if (notermcap) {
+ debug(F100,"ck_termset notermcap","",0);
+ return;
+ }
+ debug(F101,"ck_termset x","",x);
+ if (x > 0) {
+ char * bp;
+ bp = tgsbuf;
+ *bp = NUL;
+ debug(F110,"ck_termset calling tgetstr","cl",0);
+ if (tgetstr("cl", &bp)) { /* Get clear-screen code */
+ debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 32)
+ ckstrncpy(cur_cls,tgsbuf,32);
+ } else
+ return;
+ bp = tgsbuf;
+ if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */
+ debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 32)
+ ckstrncpy(cur_cleol,tgsbuf,32);
+ } else
+ return;
+ bp = tgsbuf;
+ if (tgetstr("cm", &bp)) { /* Get cursor-movement code */
+ debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
+ if ((int)strlen(tgsbuf) < 64)
+ ckstrncpy(cur_cm,tgsbuf,64);
+ } else
+ return;
+ }
+#endif /* NOTERMCAP */
+}
+
+#ifndef TPUTSFNTYPE
+#ifdef TPUTSISVOID
+#define TPUTSFNTYPE void
+#else
+#define TPUTSFNTYPE int
+#endif /* TPUTSISVOID */
+#endif /* TPUTSFNTYPE */
+
+#ifndef TPUTSARGTYPE
+#ifdef HPUX9
+#define TPUTSARGTYPE char
+#else
+#ifdef HPUX10
+#define TPUTSARGTYPE char
+#else
+#define TPUTSARGTYPE int
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* TPUTSARGTYPE */
+
+static TPUTSFNTYPE
+#ifdef CK_ANSIC
+ck_outc(TPUTSARGTYPE x)
+#else
+ck_outc(x) TPUTSARGTYPE x;
+#endif /* CK_ANSIC */
+{ /* To satisfy tputs() arg3 prototype */
+ int rc;
+ char c;
+ c = (char) x;
+ rc = (inserver) ? ttoc(c) : conoc(c);
+#ifndef TPUTSISVOID
+ return(rc);
+#endif /* TPUTSISVOID */
+}
+
+int
+ck_curpos(row, col) int row, col; {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cm[0]) { /* We don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
+ printf("\033[%d;%dH", row, col); /* Or default to ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ /* termcap/terminfo is 0-based */
+ tputs(
+#ifdef TPUTSARG1CONST
+ (const char *)
+#endif /* TPUTSARG1CONST */
+ tgoto(cur_cm,col-1,row-1),1,fn);
+ }
+ return(0);
+}
+
+int
+ck_cls() {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cls[0]) { /* If we don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ printf("\033[;H\033[2J"); /* Or default to ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ debug(F111,"ck_cls 2",cur_cls,fxd_inited);
+ tputs(cur_cls,cmd_rows,fn);
+ }
+ return(0);
+}
+
+int
+ck_cleol() {
+#ifdef CK_ANSIC
+ TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
+#else
+ TPUTSFNTYPE (*fn)();
+#endif /* CK_ANSIC */
+ if (!fxd_inited)
+ fxdinit(9999);
+ if (!cur_cleol[0]) { /* If we don't have escape sequences */
+#ifdef COMMENT
+ return(-1); /* Do nothing */
+#else
+ printf("\033[K"); /* Or use ANSI */
+#endif /* COMMENT */
+ } else {
+ fn = ck_outc;
+ tputs(cur_cleol,1,fn);
+ }
+ return(0);
+}
+#endif /* CK_CURPOS */
+#else
+static void
+ck_termset(x) int x; {
+ if (x) return;
+}
+#endif /* NOTERMCAP */
+
+#ifndef CK_CURPOS
+#define CK_CURPOS
+int
+ck_cls() {
+ printf("\033[;H\033[2J");
+ return(0);
+}
+
+int
+ck_cleol() {
+ printf("\033[K");
+ return(0);
+}
+
+int
+ck_curpos(row, col) int row, col; {
+ printf("\033[%d;%dH", row, col);
+ return(0);
+}
+#endif /* CK_CURPOS */
+
+
+#ifndef NOXFER
+static int cinit = 0; /* Flag for curses init'd */
+static int cendw = 0; /* endwin() was called */
+
+static
+#ifdef CK_ANSIC /* Because VOID used by curses.h */
+void
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+#endif /* CK_ANSIC */
+#ifdef CK_ANSIC /* Update % transfered and % bar */
+updpct(long old, long new)
+#else /* CK_ANSIC */
+updpct(old, new) long old, new;
+#endif /* CK_ANSIC */
+/* updpct */ {
+#ifdef COMMENT
+ int m, n;
+ move(CW_PCD,22);
+ printw("%ld", new);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ if (old > new) {
+ old = 0;
+ move(CW_PCD, 26);
+ clrtoeol();
+ }
+ m = old/2;
+ move(CW_PCD, 26 + m);
+ n = new / 2 - m;
+#ifndef OS2
+ while (n > 0) {
+ if ((m + 1) % 5 == 0)
+ printw("*");
+ else
+ printw("=");
+ m++;
+ n--;
+ }
+ if (new % 2 != 0) printw("-");
+ /* move(CW_PCD, 22+53); */
+#else /* OS2 */
+ while (n > 0) {
+ printw("%c", '\333');
+ m++; n--;
+ }
+ if (new % 2 != 0)
+ printw("%c", '\261');
+#endif /* OS2 */
+ }
+#endif /* CK_PCT_BAR */
+ /* clrtoeol(); */
+#else /* !COMMENT */
+#ifdef OS2
+#define CHAR1 '\333' /* OS2 - CP437 */
+#define CHAR2 '\261'
+#else
+#define CHAR1 '/' /* Default */
+#define CHAR2 '-'
+#endif /* OS2 */
+ debug(F101,"updpct old","",old);
+ debug(F101,"updpct new","",new);
+ move(CW_PCD,22);
+ printw("%-3ld", new); /* (was) printw("%ld", new); */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ int m, n;
+
+ if (old > new) {
+ old = 0 ;
+ move(CW_PCD, 26);
+ clrtoeol();
+ }
+ if (new <= 100L) {
+ m = old / 2;
+ n = new / 2 - m;
+ move(CW_PCD, 26+m);
+ while (n-- > 0)
+ printw("%c", CHAR1);
+ if (new % 2 != 0)
+ printw("%c", CHAR2);
+ }
+ }
+#endif /* CK_PCT_BAR */
+#endif /* COMMENT */
+}
+
+static CK_OFF_T old_tr = (CK_OFF_T)-1; /* Time remaining previously */
+
+static CK_OFF_T
+#ifdef CK_ANSIC
+shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar)
+#else
+ shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shoetl */ { /* Estimated time left in transfer */
+ CK_OFF_T tr; /* Time remaining, seconds */
+
+#ifdef GFTIMER
+ if (fsiz > 0L && cps > 0L)
+ tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
+ else
+ tr = (CK_OFF_T)-1;
+#else
+ tr = (fsiz > 0L && cps > 0L) ?
+ ((fsiz - howfar) / cps) :
+ (CK_OFF_T)-1;
+#endif /* GFTIMER */
+ move(CW_TR,22);
+ if (tr > (CK_OFF_T)-1) {
+ if (tr != old_tr) {
+ printw("%s",hhmmss(tr));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ }
+ } else {
+ printw("(unknown)");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ }
+ return(tr);
+}
+
+static long
+#ifdef CK_ANSIC
+shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar)
+#else
+shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shocps */ {
+#ifdef CPS_WEIGHTED
+ static CK_OFF_T oldffc = 0L;
+#endif /* CPS_WEIGHTED */
+#ifdef GFTIMER
+ CKFLOAT secs, xx;
+#else
+ CK_OFF_T secs, xx;
+#endif /* GFTIMER */
+
+#ifdef GFTIMER
+ xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */
+ gtv = gftimer();
+ if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
+ return(oldcps);
+ oldgtv = xx;
+#else
+ xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */
+ gtv = gtimer();
+ if ((gtv - oldgtv) < 1)
+ return(oldcps);
+ oldgtv = xx;
+#endif /* GFTIMER */
+
+#ifdef CPS_WEIGHTED
+ /* debug(F100,"SHOCPS: WEIGHTED","",0); */
+ if (gtv != oldgtv) { /* The first packet is ignored */
+ if (ffc < oldffc)
+ oldffc = ffc;
+ oldcps = cps;
+ if (oldcps && oldgtv >
+#ifdef GFTIMER
+ 1.0
+#else
+ 1
+#endif /* GFTIMER */
+ ) { /* The first second is ignored */
+/*
+ This version of shocps() produces a weighted average that some
+ people like, but most people find it disconcerting and bombard us
+ with questions and complaints about why the CPS figure fluctuates so
+ wildly. So now you only get the weighted average if you build the
+ program yourself with CPS_WEIGHTED defined.
+*/
+#ifndef CPS_VINCE
+#ifdef GFTIMER
+ cps = (long)((((CKFLOAT)oldcps * 3.0) +
+ (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
+#else
+ cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
+#endif /* GFTIMER */
+#else
+/* And an alternate weighting scheme from Vincent Fatica... */
+ cps = (3 *
+ ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
+ / 4;
+#endif /* CPS_VINCE */
+ } else {
+ /* No weighted average since there is nothing to weigh */
+#ifdef GFTIMER
+ cps = (long)(gtv != 0.0 ?
+ (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
+ (ffc - oldffc)) ;
+#else
+ cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
+#endif /* GFTIMER */
+ }
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"SHOCPS: pct ","",pct);
+ debug(F101,"SHOCPS: gtv ","",gtv);
+ debug(F101,"SHOCPS: oldgtv","",oldgtv);
+ debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv));
+ debug(F101,"SHOCPS: ffc ","",ffc);
+ debug(F101,"SHOCPS: oldffc","",oldffc);
+ debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
+ debug(F101,"SHOCPS: cps ","",cps);
+ }
+#endif /* DEBUG */
+#endif /* COMMENT */
+ move(CW_CP,22);
+ printw("%ld", cps);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldffc = ffc;
+ }
+#else /* !CPS_WEIGHTED */
+#ifdef COMMENT
+#ifdef DEBUG
+ if (deblog) {
+ debug(F100,"SHOCPS: NOT WEIGHTED","",0);
+ debug(F101,"SHOCPS: pct ","",pct);
+ debug(F101,"SHOCPS: gtv ","",gtv);
+ debug(F101,"SHOCPS: oldgtv ","",oldgtv);
+ debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv);
+ debug(F101,"SHOCPS: ffc ","",ffc);
+ debug(F101,"SHOCPS: oldffc ","",oldffc);
+ debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
+ debug(F101,"SHOCPS: cps ","",cps);
+ debug(F101,"SHOCPS: filcnt ","",filcnt);
+#ifdef GFTIMER
+ debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
+#endif /* GFTIMER */
+ }
+ debug(F101,"shocps gtv","",gtv);
+#endif /* DEBUG */
+#ifdef GFTIMER
+#endif /* COMMENT */
+ /* debug(F101,"shocps fpfsecs","",fpfsecs); */
+ secs = gtv - fpfsecs;
+ /* debug(F101,"shocps secs","",(long)secs); */
+ if (secs > 0.0) {
+ cps = (long)((CKFLOAT) ffc / secs);
+ /* debug(F101,"shocps cps","",cps); */
+ move(CW_CP,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%ld", cps);
+ clrtoeol();
+ }
+#else /* Not GFTIMER */
+ if ((secs = gtv - fsecs) > 0) {
+ cps = (secs < 1L) ? ffc : ffc / secs;
+ move(CW_CP,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%ld", cps);
+ clrtoeol();
+ }
+#endif /* GFTIMER */
+#endif /* CPS_WEIGHTED */
+
+ if (cps > peakcps && /* Peak transfer rate */
+ ((what & W_SEND && spackets > wslots + 4) ||
+ (!(what & W_SEND) && spackets > 10))) {
+ peakcps = cps;
+ }
+ old_tr = shoetl(old_tr, cps, fsiz, howfar);
+ return(cps);
+}
+
+static
+#ifdef CK_ANSIC /* Because VOID used by curses.h */
+void
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+#endif /* CK_ANSIC */
+scrft() { /* Display file type */
+ char xferstr[256];
+ xferstr[0] = NUL;
+ debug(F101,"scrft binary","",binary);
+ if (binary) {
+ switch(binary) {
+ case XYFT_L:
+ ckstrncpy(xferstr,"LABELED",256);
+ break;
+ case XYFT_I:
+ ckstrncpy(xferstr,"IMAGE",256);
+ break;
+ case XYFT_U:
+ ckstrncpy(xferstr,"BINARY UNDEFINED",256);
+ break;
+ case XYFT_M:
+ ckstrncpy(xferstr,"MACBINARY",256);
+ break;
+ case XYFT_X:
+ ckstrncpy(xferstr,"TENEX",256);
+ break;
+ default:
+ case XYFT_B:
+ ckstrncpy(xferstr,"BINARY",256);
+ break;
+ }
+#ifdef CK_RESEND
+ if (what & W_SEND && sendstart > 0L) {
+ if (sendmode == SM_PSEND) {
+ ckstrncat(xferstr, " / partial", 256);
+ } else if (sendmode == SM_RESEND) {
+ ckstrncat(xferstr, " / resend", 256);
+ }
+ } else if (what & W_RECV && rs_len > 0L) {
+ ckstrncat(xferstr, " / resend", 256);
+ }
+#endif /* CK_RESEND */
+ } else {
+
+#ifndef NOCSETS
+ ckstrncpy(xferstr,"TEXT",256);
+#ifdef NEWFTP
+#ifndef NOUNICODE
+ if (what & W_FTP) {
+ if (ftp_csx < 0)
+ ckstrncat(xferstr," (no translation)", 256);
+ else
+ ckmakxmsg(&xferstr[4],252,
+ " (",
+ fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
+ " => ",
+ fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
+ ")",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ } else
+#endif /* NOUNICODE */
+#endif /* NEWFTP */
+ if (tcharset == TC_TRANSP) {
+ ckstrncat(xferstr, " (no translation)", 256);
+ } else {
+ if (what & W_SEND) {
+ sprintf( &xferstr[strlen(xferstr)], /* safe */
+ " (%s => %s)",
+ fcsinfo[fcharset].keyword, /* built-in keywords */
+ tcsinfo[tcharset].keyword /* lengths are controlled */
+ );
+ } else {
+ sprintf( &xferstr[strlen(xferstr)], /* safe */
+ " (%s => %s)",
+ tcsinfo[tcharset].keyword, /* built-in keywords */
+ fcsinfo[fcharset].keyword); /* lengths controlled */
+ }
+ }
+#endif /* NOCSETS */
+ }
+ move(CW_TYP,22);
+ printw("%s", xferstr);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
+#endif /* K95G */
+#endif /* KUI */
+ return;
+}
+
+#ifdef CK_NEWTERM
+static FILE *ck_stdout = NULL;
+static int ck_fd = -1;
+#endif /* CK_NEWTERM */
+
+static long pct = 0L, oldpct = 0L, oldrtt = -1L;
+static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
+
+#ifdef NETCONN
+static char *netname[] = {
+ "none", /* 00 */
+ "TCP/IP", /* 01 TCP (Sockets) */
+ "TCP/IP", /* 02 TCP (Streams) */
+ "X.25", /* 03 SunLink X.24 */
+ "DECnet", /* 04 DECnet */
+ "VAX PSI", /* 05 VAX PSI */
+ "Named Pipes", /* 06 LAN Manager Named Pipe */
+ "X.25", /* 07 Stratus VOS X.25 */
+ "NetBIOS", /* 08 IBM NETBIOS */
+ "SuperLAT", /* 07 Meridian SuperLAT */
+ "File", /* 10 File */
+ "Command", /* 11 Subprocess (pipe) */
+ "DLL", /* 12 DLL does i/o */
+ "X.25", /* 13 IBM AIXLink X.25 */
+ "X.25", /* 14 HP-UX X.25 */
+ "PTY", /* 15 Pseudoterminal */
+ "SSH", /* 16 SSH */
+ "<ERROR>", /* 17 In case new types are added */
+ "<ERROR>", /* 18 but nobody remembers to update */
+ "<ERROR>", /* 19 this table ... */
+ NULL /* 20 */
+};
+static int nnetname = (sizeof(netname) / sizeof(char *));
+
+#endif /* NETCONN */
+
+#ifdef CK_ANSIC
+void
+screenc(int f, char c,CK_OFF_T n,char *s)
+#else
+CKVOID
+screenc(f,c,n,s)
+int f; /* argument descriptor */
+char c; /* a character or small integer */
+CK_OFF_T n; /* a long integer */
+char *s; /* a string */
+#endif /* CK_ANSIC */
+/* screenc() */ {
+#ifdef CK_SSL
+ extern int tls_active_flag, ssl_active_flag;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+ extern int ttnproto;
+#endif /* RLOGCODE */
+ static int q = 0;
+ static long fcnt = 0L; /* Number of files transferred */
+ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
+ static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */
+ static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */
+ static int pctlbl = 0L; /* Percent done vs Bytes so far */
+ long cps = 0L;
+
+ int net = 0;
+ int xnet = 0;
+ int ftp = 0;
+ int len; /* Length of string */
+ int errors = 0; /* Error counter */
+ int x; /* Worker */
+
+ debug(F101,"screenc cinit","",cinit);
+ debug(F101,"screenc cendw","",cendw);
+
+ if (!s) s = ""; /* Always do this. */
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
+ net = network || ftp;
+ xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
+
+ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
+ if (f == SCR_CW) { /* Close window, but it's not open */
+ ft_win = 0;
+ return;
+ }
+ debug(F111,"screenc A",s,f);
+ if (f == SCR_EM ||
+ (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
+ conoll(""); conoc('?'); conoll(s); return; /* Regular display */
+ }
+ }
+ if (cinit == 0) { /* Only call initscr() once */
+ char * s;
+ /* Check these now -- if they are defined but not numeric */
+ /* they can crash curses */
+ s = getenv("LINES");
+ if (s) if (!rdigits(s)) {
+ printf("?LINES variable not numeric: \"%s\".\n",s);
+ printf("(Fullscreen display disabled)\n");
+ fdispla = XYFD_S;
+ return;
+ }
+ s = getenv("COLUMNS");
+ if (s) if (!rdigits(s)) {
+ printf("?COLUMNS variable not numeric: \"%s\".\n",s);
+ printf("(Fullscreen display disabled)\n");
+ fdispla = XYFD_S;
+ return;
+ }
+ cendw = 1; /* New window needs repainting */
+#ifdef COMMENT
+ if (!initscr()) { /* Oops, can't initialize window? */
+/*
+ In fact, this doesn't happen. "man curses" says initscr() halts the
+ entire program if it fails, which is true on the systems where I've
+ tested it. It will fail if your terminal type is not known to it.
+ That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
+ terminal type is known before allowing a curses display.
+*/
+ fprintf(stderr,"CURSES INITSCR ERROR\r\n");
+ fdispla = XYFD_S; /* Fall back to CRT display */
+ return;
+ } else {
+ cinit++; /* Window initialized ok */
+ debug(F100,"CURSES INITSCR OK","",0);
+ }
+#else /* Save some memory. */
+#ifdef CK_NEWTERM
+ /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
+ System V curses seems to reserve the right to alter the buffering
+ on the output FILE* without restoring it. Fortunately System V
+ curses provides newterm(), an alternative to initscr(), that
+ allows us to specify explicitly the terminal type and input and
+ output FILE pointers. Thus we duplicate stdout, and let curses
+ have the copy. The original remains unaltered. Unfortunately,
+ newterm() seems to be particular to System V.
+ */
+ s = getenv("TERM");
+ if (ck_fd < 0) {
+ ck_fd = dup(fileno(stdout));
+ ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
+ }
+ debug(F100,"screenc newterm...","",0);
+
+/* NOTE: It might be necessary to do this with stdin too! */
+/* This would have been the case in FreeBSD 4.1 but they fixed the */
+/* problem by restoring the buffering of stdin before the final release. */
+/* (But T.E. Dickey says stdin is not buffered?) */
+
+ if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
+ fprintf(stderr,
+ "Fullscreen display not supported for terminal type: %s\r\n",s);
+ fdispla = XYFD_S; /* Use CRT instead */
+ return;
+ }
+ debug(F100,"screenc newterm ok","",0);
+#else
+ debug(F100,"screen calling initscr","",0);
+ initscr(); /* Initialize curses. */
+ debug(F100,"screen initscr ok","",0);
+#endif /* CK_NEWTERM */
+ cinit++; /* Remember curses was initialized. */
+#endif /* COMMENT */
+ }
+ ft_win = 1; /* Window is open */
+ if (repaint) {
+#ifdef CK_WREFRESH
+/*
+ This totally repaints the screen, just what we want, but we can only
+ do this with real curses, and then only if clearok() and wrefresh() are
+ provided in the curses library.
+*/
+#ifdef OS2
+ RestoreCmdMode();
+#else
+#ifdef QNX
+#ifndef QNX16
+ clearok(stdscr, 1); /* QNX doesn't have curscr */
+#endif /* QNX16 */
+ wrefresh(stdscr);
+#else
+ wrefresh(curscr);
+#endif /* QNX */
+#endif /* OS2 */
+#else /* No CK_WREFRESH */
+/*
+ Kermit's do-it-yourself method, works with all types of fullscreen
+ support, but does not repaint all the fields. For example, the filename
+ is lost, because it arrives at a certain time and never comes again, and
+ Kermit presently does not save it anywhere. Making this method work for
+ all fields would be a rather major recoding task, duplicating what curses
+ already does, and would add a lot of complexity and storage space.
+*/
+ cendw = 1;
+#endif /* CK_WREFRESH */
+ repaint = 0;
+ }
+ if (cendw) { /* endwin() was called previously */
+#ifdef VMS
+ initscr(); /* (or should have been!) */
+ clear();
+ touchwin(stdscr);
+ refresh();
+#else
+#ifdef QNX
+/*
+ In QNX, if we don't call initscr() here we core dump.
+ I don't have any QNX curses documentation, but other curses manuals
+ say that initscr() should be called only once per application, and
+ experience shows that on other systems, calling initscr() here generally
+ results in a core dump.
+*/
+ debug(F100,"screenc re-calling initscr QNX","",0);
+ initscr();
+ clear();
+ refresh();
+#ifdef COMMENT
+/*
+ But even so, second and subsequent curses displays are messed up.
+ Calling touchwin, refresh, etc, doesn't make any difference.
+*/
+ debug(F100,"screenc calling touchwin QNX","",0);
+ touchwin(stdscr);
+ debug(F100,"screenc calling refresh QNX","",0);
+ refresh();
+#endif /* COMMENT */
+
+#else /* All others... */
+ debug(F100,"screenc calling clear","",0);
+ clear();
+ debug(F100,"screenc clear ok","",0);
+#endif /* QNX */
+#endif /* VMS */
+ debug(F100,"screenc setup ok","",0);
+ debug(F100,"screenc doing first move","",0);
+ move(CW_BAN,0); /* Display the banner */
+ debug(F110,"screenc myhost",myhost,0);
+#ifdef TCPSOCKET
+ debug(F110,"screenc myipaddr",myipaddr,0);
+#endif /* TCPSOCKET */
+#ifdef HPUX1010
+ debug(F100,"screenc calling first printw...","",0);
+/* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
+#endif /* HPUX1010 */
+ if (myhost[0]) {
+#ifdef TCPSOCKET
+ if (!myipaddr[0]
+#ifdef OS2
+ /* We need to perform this test because on non-TCP/IP */
+ /* systems the call to getlocalipaddr() results in a */
+ /* DNS Lookup which takes several minutes to time out */
+ && net &&
+ (xnet == NET_TCPA || xnet == NET_TCPB
+#ifdef SSHBUILTIN
+ || xnet == NET_SSH
+#endif /* SSHBUILTIN */
+ )
+#endif /* OS2 */
+ )
+ getlocalipaddr();
+ if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
+ printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
+ else
+#endif /* TCPSOCKET */
+ printw("%s, %s",versio,(char *)myhost);
+ } else {
+ printw("%s",versio);
+ }
+#ifdef HPUX1010
+ debug(F100,"screenc first printw returns","",0);
+#endif /* HPUX1010 */
+ move(CW_DIR,3);
+ printw("Current Directory: %s",zgtdir());
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
+#endif /* K95G */
+#endif /* KUI */
+ if (net) {
+ move(CW_LIN,8);
+ printw("Network Host: %s",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "(unknown)") :
+#endif /* NEWFTP */
+ ttname
+ );
+ } else {
+ move(CW_LIN,0);
+ printw("Communication Device: %s",ttname);
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
+#endif /* K95G */
+#endif /* KUI */
+
+ if (net) {
+ move(CW_SPD,8);
+ printw("Network Type: ");
+ } else {
+ move(CW_SPD,1);
+ printw("Communication Speed: ");
+ }
+ move(CW_SPD,22); /* Serial speed or network type */
+ if (net) {
+#ifdef NETCONN
+ int secure = 0;
+ char * xname;
+ if (xnet > nnetname)
+ xname = "[ERROR]";
+ else
+ xname = netname[xnet];
+#ifdef NEWFTP
+ if (ftp) {
+ if (ftpissecure())
+ secure = 1;
+ } else
+#endif /* NEWFTP */
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ secure = 1;
+ }
+ if (secure) {
+#ifdef KUI
+#ifndef K95G
+ char buf[30];
+ sprintf(buf,"%s (SECURE)",xname);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) buf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s (SECURE)",xname);
+ } else {
+ printw("%s",xname);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) xname
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+#else
+ printw("(network)");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(network)"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#endif /* NETCONN */
+ } else {
+ if (speed < 0L)
+ speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880) {
+ printw("75/1200");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "75/1200"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ } else {
+ char speedbuf[64] ;
+ sprintf(speedbuf, "%ld", speed);
+ printw("%s",speedbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) speedbuf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ } else {
+ printw("unknown");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(unknown)"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ }
+ move(CW_PAR,14);
+ printw("Parity: %s",ftp ? "none" : parnam((char)parity));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ move(CW_TMO, 9); printw("RTT/Timeout:"); }
+#endif /* CK_TIMERS */
+ move(CW_TYP,11); printw("File Type:");
+ move(CW_SIZ,11); printw("File Size:");
+ move(CW_PCD, 8);
+ clrtoeol();
+ pctlbl = (what & W_SEND);
+ printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
+
+#ifdef XYZ_INTERNAL
+ move(CW_BAR, 1);
+ printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
+#endif /* XYZ_INTERNAL */
+#ifdef CK_PCT_BAR
+ if (thermometer) {
+ oldpct = pct = 0;
+ move(CW_BAR,22);
+ printw(" ...10...20...30...40...50...60...70...80...90..100");
+ move(CW_BAR,22+56);
+ }
+#endif /* CK_PCT_BAR */
+ move(CW_TR, 1); printw("Estimated Time Left:");
+ move(CW_CP, 2); printw("Transfer Rate, CPS:");
+ move(CW_WS, 8); printw("Window Slots:%s",
+ ((protocol == PROTO_K) && !ftp) ?
+ "" : " N/A"
+ );
+ move(CW_PT, 9); printw("Packet Type:");
+ if (ftp || protocol != PROTO_K) {
+ move(CW_PT,22);
+ printw("%s", "N/A");
+ move(CW_PC, 11); printw("I/O Count:");
+ move(CW_PL, 10); printw("I/O Length:");
+ } else {
+ move(CW_PC, 8); printw("Packet Count:");
+ move(CW_PL, 7); printw("Packet Length:");
+ }
+#ifndef COMMENT
+ move(CW_PR, 9); printw("Error Count:");
+#else
+ move(CW_PR, 2); printw("Packet Retry Count:");
+#endif
+#ifdef COMMENT
+ move(CW_PB, 2); printw("Packet Block Check:");
+#endif /* COMMENT */
+ move(CW_ERR,10); printw("Last Error:");
+ move(CW_MSG, 8); printw("Last Message:");
+ if (xfrmsg) {
+ move(CW_MSG, 22); printw("%s",xfrmsg);
+ makestr(&xfrmsg,NULL);
+ }
+ move(CW_INT, 0);
+ if (!xfrint) {
+ printw("(Transfer interruption is disabled)");
+ } else {
+#ifdef CK_NEED_SIG
+ printw(
+"<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
+ dbchr(escape), dbchr(escape), dbchr(escape)
+ );
+ move(CW_INT + 1, 0);
+ printw(
+"<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
+ dbchr(escape), dbchr(escape)
+ );
+#else /* !CK_NEED_SIG */
+ move(CW_INT, 0);
+#ifdef OS2
+ if (protocol == PROTO_K) {
+ printw(
+"X to cancel file, Z to cancel group, <Enter> to resend last packet,"
+ );
+ }
+#else /* !OS2 */
+#ifdef VMS /* In VMS avoid bottom line */
+ printw(
+"X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
+ );
+#else
+ printw(
+"X to cancel file, Z to cancel group, <CR> to resend last packet,"
+ );
+#endif /* VMS */
+#endif /* OS2 */
+
+#ifndef VMS
+ move(CW_INT + 1, 0);
+ if (protocol == PROTO_K) {
+ printw(
+"E to send Error packet, ^C to quit immediately, ^L to refresh screen."
+ );
+ } else {
+ printw("^C to cancel file transfer.");
+ }
+#endif /* VMS */
+#endif /* CK_NEED_SIG */
+ }
+ refresh();
+ cendw = 0;
+ }
+ debug(F101,"SCREENC switch","",f);
+ debug(F000,"SCREENC c","",c);
+ debug(F101,"SCREENC n","",n);
+
+ len = strlen(s); /* Length of argument string */
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ oldpct = pct = 0L; /* Reset percents */
+#ifdef GFTIMER
+ gtv = (CKFLOAT) -1.0;
+ /* oldgtv = (CKFLOAT) -1.0; */
+#else
+ gtv = -1L;
+ /* oldgtv = -1L; */
+#endif /* GFTIMER */
+ oldwin = -1;
+ fsiz = (CK_OFF_T)-1; /* Invalidate previous file size */
+ move(CW_PCD,22); /* Erase percent done from last time */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(CW_SIZ,22); /* Erase file size from last time */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(CW_ERR,22); /* And last error message */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+#ifdef COMMENT
+#ifdef STREAMING
+ if (protocol == PROTO_K && streamok) {
+ move(CW_BAR, 1);
+#ifdef XYZ_INTERNAL
+ printw(" Kermit STREAMING:");
+#else
+ printw(" STREAMING:");
+#endif /* XYZ_INTERNAL */
+ }
+#endif /* STREAMING */
+#endif /* COMMENT */
+
+ if (what & W_SEND) { /* If we're sending... */
+#ifdef NEWFTP
+ if (what & W_FTP) { /* FTP */
+ move(CW_NAM,10);
+ printw(" FTP PUT:");
+ } else
+#endif /* NEWFTP */
+#ifdef CK_RESEND
+ switch (sendmode) { /* Kermit */
+ case SM_RESEND:
+ move(CW_NAM,10);
+ printw(" RESENDING:");
+ break;
+ default:
+ move(CW_NAM,10);
+ printw(" SENDING:");
+ break;
+ }
+#else
+ move(CW_NAM,10);
+ printw(" SENDING:");
+#endif /* CK_RESEND */
+
+ } else if (what & W_RECV) { /* If we're receiving... */
+#ifdef NEWFTP
+ if (what & W_FTP) { /* FTP */
+ move(CW_NAM,10);
+ printw(" FTP GET:");
+ } else {
+#endif /* NEWFTP */
+ move(CW_NAM,10);
+ printw(" RECEIVING:");
+#ifdef NEWFTP
+ }
+ } else if (what == (W_FTP|W_FT_DELE)) {
+ move(CW_NAM,10);
+ printw("FTP DELETE:");
+#endif /* NEWFTP */
+ } else { /* If we don't know... */
+ move(CW_NAM,10); /* (should never see this) */
+ printw(" File Name:");
+ }
+ move(CW_NAM,22); /* Display the filename */
+ if (len > 57) {
+ printw("%.55s..",s);
+ len = 57;
+ } else printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ q = len; /* Remember name length for later */
+ clrtoeol();
+ scrft(); /* Display file type (can change) */
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_AN: /* File as-name */
+ if (q + len + 4 < 58) { /* Will fit */
+ move(CW_NAM, 22 + q);
+ printw(" => %s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ } else { /* Too long */
+ move(CW_NAM, 22); /* Overwrite previous name */
+ q = 0;
+ if (len + 4 > 57) { /* wg15 */
+ printw(" => %.51s..",s); /* wg15 */
+ len = 53; /* wg15 */
+ } else printw(" => %s",s); /* wg15 */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ q += len + 4; /* Remember horizontal position */
+ clrtoeol();
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_FS: /* File size */
+ fsiz = n;
+ move(CW_SIZ,22);
+ if (fsiz > (CK_OFF_T)-1) {
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s",ckfstoa(n));
+ }
+ if (fsiz == -2L) {
+ printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT");
+ }
+ clrtoeol();
+#ifdef COMMENT
+ move(CW_PCD, 8);
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ clrtoeol();
+ printw("Percent Done:");
+ }
+#else
+ move(CW_PCD, 8);
+ clrtoeol();
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ printw("Percent Done:");
+ } else {
+ pctlbl = 0;
+ printw("Bytes So Far:");
+ }
+#endif /* COMMENT */
+ clrtoeol();
+ scrft(); /* File type */
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (spackets < 5) {
+ extern int sysindex;
+ extern struct sysdata sysidlist[];
+ /* Things that won't change after the 4th packet */
+ move(CW_PAR,22);
+ printw("%s",parnam((char)parity));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+#ifdef COMMENT
+ move(CW_PB, 22); /* Block check on this packet */
+ if (bctu == 4)
+ printw("B");
+ else
+ printw("%d",bctu);
+ clrtoeol();
+#endif /* COMMENT */
+ if (
+#ifdef NEWFTP
+ (ftp && (spackets == 1 || rpackets == 1)) ||
+#endif /* NEWFTP */
+ spackets == 4
+ ) {
+ move(CW_LIN,8);
+ if (
+#ifdef NEWFTP
+ ftp ||
+#endif /* NEWFTP */
+ ((protocol == PROTO_K) && (sysindex > -1))
+ ) {
+ if (net) {
+ move(CW_LIN,8);
+ printw("Network Host: %s (%s)",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "") :
+#endif /* NEWFTP */
+ ttname,
+#ifdef NEWFTP
+ ftp ? ftp_srvtyp :
+#endif /* NEWFTP */
+ sysidlist[sysindex].sid_name
+ );
+ } else {
+ move(CW_LIN,0);
+ printw("Communication Device: %s (remote host is %s)",
+ ttname,
+ sysidlist[sysindex].sid_name
+ );
+ }
+ clrtoeol();
+ }
+ }
+ }
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ long xx;
+ if (
+#ifdef STREAMING
+ streaming && oldwin != -2
+#else
+ 0
+#endif /* STREAMING */
+ ) {
+ move(CW_TMO, 22);
+ printw("00 / 00");
+ clrtoeol();
+ } else {
+ xx = (rttdelay + 500) / 1000;
+ if (xx != oldrtt || rcvtimo != oldtim) {
+ move(CW_TMO, 22);
+ printw("%02ld / %02d", xx, rcvtimo);
+ oldrtt = xx;
+ oldtim = rcvtimo;
+ clrtoeol();
+ }
+ }
+ }
+#endif /* CK_TIMERS */
+
+ x = (what & W_RECV) ? /* Packet length */
+ rpktl+(protocol==PROTO_K?1:0) :
+ spktl;
+ if (x != oldlen) { /* But only if it changed. */
+ move(CW_PL, 22);
+ printw("%d",x);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldlen = x;
+ }
+ move(CW_PC, 22); /* Packet count (always). */
+
+ printw("%d", (what & W_RECV) ? rpackets : spackets);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+
+ if (protocol == PROTO_K && !ftp) { /* Window slots */
+ char ws[16];
+ int flag;
+ flag = 0;
+#ifdef STREAMING
+ if (streaming) {
+ if (oldwin != -2) {
+ sprintf(ws,"STREAMING");
+ flag = 1;
+ oldwin = -2;
+ }
+ } else
+#endif /* STREAMING */
+ if (wcur != oldwin) {
+ sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
+ flag = 1;
+ oldwin = wcur;
+ }
+ if (flag) {
+ move(CW_WS, 22);
+ printw("%s", ws);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ }
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Retry count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtry = errors;
+ }
+ /* Sender's packet type */
+ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
+ char type[2];
+ sprintf(type, "%c",c);
+ move(CW_PT,22);
+ printw("%s", type);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtyp = c;
+ }
+ switch (c) { /* Now handle specific packet types */
+ case 'S': /* Beginning of transfer */
+ fcnt = fbyt = 0L; /* Clear counters */
+#ifdef GFTIMER
+ gtv = -1.0;
+#else /* GFTIMER */
+ gtv = -1L; /* And old/new things... */
+#endif /* GFTIMER */
+ oldpct = pct = 0L;
+ break;
+
+ case 'Z': /* or EOF */
+ debug(F101,"screenc SCR_PT Z pktnum","",n);
+ debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
+ debug(F101,"screenc SCR_PT Z pct","",pct);
+ case 'D': /* Data packet */
+ if (fsiz > 0L) { /* Show percent done if known */
+ oldpct = pct; /* Remember previous percent */
+ howfar = ffc;
+#ifdef CK_RESEND
+ if (what & W_SEND) /* Account for PSEND or RESEND */
+ howfar += sendstart;
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ /* Percent done, to be displayed... */
+ if (c == 'Z') {
+ if (!discard && !cxseen && !czseen) pct = 100L;
+ } else
+ pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
+ if (pct > 100L || /* Allow for expansion and */
+ (oldpct == 99L && pct < 0L)) /* other boundary conditions */
+ pct = 100L;
+ if (pct != oldpct) /* Only do this 100 times per file */
+ updpct(oldpct, pct);
+ } else {
+ move(CW_PCD,22);
+ printw("%s", ckfstoa(ffc));
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
+#endif /* K95G */
+#endif /* KUI */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ break;
+
+ case '%': /* Timeouts, retransmissions */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ oldtry = errors;
+ if (s) if (*s) {
+ move(CW_ERR,22);
+ printw("%s",s);
+ clrtoeol();
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+#endif /* K95G */
+#endif /* KUI */
+ }
+ break;
+
+ case 'E': /* Error packet */
+#ifdef COMMENT
+ move(CW_ERR,22); /* Print its data field */
+ if (*s) {
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ }
+ clrtoeol();
+#endif /* COMMENT */
+ fcnt = fbyt = 0L; /* So no bytes for this file */
+ break;
+ case 'Q': /* Crunched packet */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ move(CW_ERR,22);
+ printw("Damaged Packet");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Damaged Packet"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ break;
+ case 'q': /* Ctrl-C or connection lost */
+ move(CW_MSG,22);
+ clrtoeol();
+ if (!s) s = "";
+ printw(*s ? s : "User interruption or connection lost");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) s
+ );
+#endif /* K95G */
+#endif /* KUI */
+ break;
+ case 'T': /* Timeout */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ move(CW_ERR,22);
+ printw("Timeout %d sec",rcvtimo);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Timeout"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ move(CW_PR, 22);
+ printw("%d",errors);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ oldtry = errors;
+ }
+ break;
+ default: /* Others, do nothing */
+ break;
+ }
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_ST: /* File transfer status */
+ debug(F101,"screenc SCR_ST c","",c);
+ debug(F101,"screenc SCR_ST success","",success);
+ debug(F101,"screenc SCR_ST cxseen","",cxseen);
+#ifdef COMMENT
+ move(CW_PCD,22); /* Update percent done */
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl)
+ updpct(oldpct,100);
+ else
+ printw("%s", ckfstoa(ffc));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#endif /* K95G */
+#endif /* KUI */
+ pct = 100;
+ oldpct = 0;
+ } else if (fsiz > 0L) /* Not OK, update final percent */
+/*
+ The else part writes all over the screen -- howfar and/or fsiz have
+ been reset as a consequence of the not-OKness of the transfer.
+*/
+ if (pctlbl)
+ updpct(oldpct, (howfar * 100L) / fsiz);
+ clrtoeol();
+#else
+ if (c == ST_OK) { /* OK, print 100 % */
+ move(CW_PCD,22); /* Update percent done */
+ if (pctlbl) {
+ if (oldpct == 0) /* Switching from "bytes so far" */
+ clrtoeol(); /* to "percent done"... */
+ updpct(oldpct,100);
+ } else
+ printw("%s", ckfstoa(ffc));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = 100;
+ oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol();
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+/* No, leave it there so they can read it */
+ move(CW_MSG,22); /* Remove any previous message */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+#endif /* COMMENT */
+
+ move(CW_TR, 22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+
+ switch (c) { /* Print new status message */
+ case ST_OK: /* Transfer OK */
+ fcnt++; /* Count this file */
+ if (what == (W_FTP|W_FT_DELE)) {
+ move(CW_MSG,22);
+ clrtoeol();
+ printw("Delete OK");
+ } else {
+ fbyt += ffc;
+ move(CW_MSG,22);
+ clrtoeol();
+ printw("Transfer OK");
+ }
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Transfer OK"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_DISC: /* Discarded */
+ move(CW_ERR,22);
+ printw("File discarded");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File discarded"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_INT: /* Interrupted */
+ move(CW_ERR,22);
+ printw("Transfer interrupted");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Transfer interrupted"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_SKIP: /* Skipped */
+ move(CW_ERR,22);
+ if (n > 0 && n < nskreason)
+ printw("File skipped (%s)",skreason[n]);
+ else
+ printw("File skipped");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File skipped"
+ );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_ERR: /* Error message */
+ move(CW_ERR,22);
+ if (!s) s = (char *)epktmsg;
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_REFU: /* Refused */
+ move(CW_ERR,22);
+ if (*s) {
+ char errbuf[64] ;
+ sprintf( errbuf, "Refused, %s", s ) ;
+ printw("%s", errbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
+#endif /* K95G */
+#endif /* KUI */
+ } else {
+ printw("Refused");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+#endif /* K95G */
+#endif /* KUI */
+ }
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_INC:
+ move(CW_ERR,22);
+ printw("Incomplete");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#endif /* K95G */
+#endif /* KUI */
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh();
+ return;
+
+ case ST_MSG:
+ move(CW_MSG,22);
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh();
+ return;
+
+ default: /* Bad call */
+ move(CW_ERR,22);
+ printw("*** screen() called with bad status ***");
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+ (long) "*** screen() called with bad status ***" );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh(); return;
+ }
+
+ case SCR_TC: { /* Transaction complete */
+ char msgbuf[128];
+ move(CW_CP,22); /* Overall transfer rate */
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+#endif /* K95G */
+#endif /* KUI */
+ printw("%s", ckfstoa(tfcps));
+ clrtoeol();
+ if (success) {
+ move(CW_MSG,22); /* Print statistics in message line */
+ clrtoeol();
+ }
+ if (success) {
+ sprintf(msgbuf,
+ "SUCCESS. Files: %ld, Bytes: %s, %ld CPS",
+ filcnt - filrej,
+ ckfstoa(fbyt),
+ tfcps
+ );
+ printw("%s", msgbuf);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) msgbuf
+ );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+
+ }
+ move(CW_TR, 1);
+ printw(" Elapsed Time: %s",hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_TR,
+ (long) hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ move(23,0); clrtoeol(); /* Clear instructions lines */
+ move(22,0); clrtoeol(); /* to make room for prompt. */
+ refresh();
+
+#ifdef GFTIMER
+ oldgtv = (CKFLOAT) -1.0;
+#else
+ oldgtv = -1L;
+#endif /* GFTIMER */
+
+#ifndef VMSCURSE
+ debug(F100,"screenc endwin A","",0);
+ endwin();
+#ifdef COMMENT
+/*
+ Why and when was this call to conres() added? It makes no sense,
+ and it breaks echoing on Solaris 8.
+*/
+#ifdef SOLARIS
+ conres();
+#endif /* SOLARIS */
+#endif /* COMMENT */
+#endif /* VMSCURSE */
+
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+ cendw = 1;
+ if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
+#ifdef UNIX
+ fflush(stdout);
+#endif /* UNIX */
+ ft_win = 0; /* Window closed. */
+ return;
+ }
+ case SCR_EM: /* Error packet (fatal) */
+ move (CW_ERR,22);
+ printw("FAILURE: %s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ if (xfrbel) bleep(BP_FAIL);
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ clrtoeol(); refresh(); return;
+
+ case SCR_QE: /* Quantity equals */
+ case SCR_TU: /* Undelimited text */
+ case SCR_TN: /* Text delimited at start */
+ case SCR_TZ: /* Text delimited at end */
+ return; /* (ignored in fullscreen display) */
+
+ case SCR_MS: /* Message from Kermit partner */
+ move(CW_MSG,22);
+ printw("%s",s);
+ clrtoeol(); refresh(); return;
+
+ case SCR_XD: /* X-packet data */
+ pct = oldpct = 0;
+ move(CW_NAM,22);
+ printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol(); refresh(); return;
+
+ case SCR_CW: /* Close Window */
+ clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
+ refresh();
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+
+#ifndef VMSCURSE
+ debug(F100,"screenc endwin B","",0);
+ endwin();
+#endif /* VMSCURSE */
+ ft_win = 0; /* Flag that window is closed. */
+ cendw = 1; return;
+
+ case SCR_CD: /* Display current directory */
+ move(CW_DIR,22);
+ printw("%s", s);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
+#endif /* K95G */
+#endif /* KUI */
+ clrtoeol();
+ refresh();
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ default: /* Bad call */
+ move (CW_ERR,22);
+#ifdef KUI
+#ifndef K95G
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "*** screen() called with bad function code ***"
+ );
+#endif /* K95G */
+#endif /* KUI */
+ printw("*** screen() called with bad function code ***");
+ clrtoeol(); refresh(); return;
+ }
+}
+#endif /* CK_CURSES */
+
+#ifdef KUI
+#ifdef CK_ANSIC
+void
+screeng(int f, char c,long n,char *s)
+#else
+CKVOID
+screeng(f,c,n,s)
+int f; /* argument descriptor */
+char c; /* a character or small integer */
+long n; /* a long integer */
+char *s; /* a string */
+#endif /* CK_ANSIC */
+/* screeng() */ {
+#ifdef CK_SSL
+ extern int tls_active_flag, ssl_active_flag;
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+ extern int ttnproto;
+#endif /* RLOGCODE */
+ static int q = 0;
+ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
+ static long fcnt = 0L; /* Number of files transferred */
+ static long fbyt = 0L; /* Total file bytes of all files transferred */
+ static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */
+ static int pctlbl = 0L; /* Percent done vs Bytes so far */
+ long cps = 0L;
+
+ int net = 0;
+ int xnet = 0;
+ int ftp = 0;
+ int len; /* Length of string */
+ int errors = 0; /* Error counter */
+ int x; /* Worker */
+
+ debug(F101,"screeng cinit","",cinit);
+ debug(F101,"screeng cendw","",cendw);
+
+ if (!s) s = ""; /* Always do this. */
+
+ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
+ net = network || ftp;
+ xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
+
+ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
+ if (f == SCR_CW) { /* Close window, but it's not open */
+ ft_win = 0;
+ return;
+ }
+ debug(F111,"screeng A",s,f);
+ if (f == SCR_EM ||
+ (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
+ conoll(""); conoc('?'); conoll(s); return; /* Regular display */
+ }
+ }
+ if (cinit == 0) { /* Only call initscr() once */
+ /* Check these now -- if they are defined but not numeric */
+ /* they can crash curses */
+ cendw = 1; /* New window needs repainting */
+ debug(F100,"screeng calling initscr","",0);
+ initscr(); /* Initialize curses. */
+ debug(F100,"screeng initscr ok","",0);
+ cinit++; /* Remember curses was initialized. */
+ }
+ ft_win = 1; /* Window is open */
+ if (repaint) {
+#ifdef CK_WREFRESH
+/*
+ This totally repaints the screen, just what we want, but we can only
+ do this with real curses, and then only if clearok() and wrefresh() are
+ provided in the curses library.
+*/
+ RestoreCmdMode();
+#else /* No CK_WREFRESH */
+/*
+ Kermit's do-it-yourself method, works with all types of fullscreen
+ support, but does not repaint all the fields. For example, the filename
+ is lost, because it arrives at a certain time and never comes again, and
+ Kermit presently does not save it anywhere. Making this method work for
+ all fields would be a rather major recoding task, duplicating what curses
+ already does, and would add a lot of complexity and storage space.
+*/
+ cendw = 1;
+#endif /* CK_WREFRESH */
+ repaint = 0;
+ }
+ if (cendw) { /* endwin() was called previously */
+ debug(F100,"screeng setup ok","",0);
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
+ (long) (
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "(unknown)") :
+#endif /* NEWFTP */
+ ttname) );
+
+ if (net) {
+#ifdef NETCONN
+ int secure = 0;
+ char * xname;
+ if (xnet > nnetname)
+ xname = "[ERROR]";
+ else
+ xname = netname[xnet];
+#ifdef NEWFTP
+ if (ftp) {
+ if (ftpissecure())
+ secure = 1;
+ } else
+#endif /* NEWFTP */
+ if (0
+#ifdef SSHBUILTIN
+ || IS_SSH()
+#endif /* SSHBUILTIN */
+#ifdef CK_ENCRYPTION
+ || ck_tn_encrypting() && ck_tn_decrypting()
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SSL
+ || tls_active_flag || ssl_active_flag
+#endif /* CK_SSL */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
+#endif /* CK_ENCRYPTION */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+ ) {
+ secure = 1;
+ }
+ if (secure) {
+ char buf[30];
+ sprintf(buf,"%s (SECURE)",xname);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) buf
+ );
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) xname
+ );
+ }
+#else
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(network)"
+ );
+#endif /* NETCONN */
+ } else {
+ if (speed < 0L)
+ speed = ttgspd();
+ if (speed > 0L) {
+ if (speed == 8880) {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "75/1200"
+ );
+ } else {
+ char speedbuf[64] ;
+ sprintf(speedbuf, "%ld", speed);
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) speedbuf
+ );
+ }
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_SPD,
+ (long) "(unknown)"
+ );
+ }
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+ pctlbl = (what & W_SEND);
+ cendw = 0;
+ }
+ debug(F101,"SCREENC switch","",f);
+ debug(F000,"SCREENC c","",c);
+ debug(F101,"SCREENC n","",n);
+
+ len = strlen(s); /* Length of argument string */
+ switch (f) { /* Handle our function code */
+ case SCR_FN: /* Filename */
+ oldpct = pct = 0L; /* Reset percents */
+#ifdef GFTIMER
+ gtv = (CKFLOAT) -1.0;
+ /* oldgtv = (CKFLOAT) -1.0; */
+#else
+ gtv = -1L;
+ /* oldgtv = -1L; */
+#endif /* GFTIMER */
+ oldwin = -1;
+ fsiz = (CK_OFF_T)-1L; /* Invalidate previous file size */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+ q = len; /* Remember name length for later */
+ scrft(); /* Display file type (can change) */
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_AN: /* File as-name */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_FS: /* File size */
+ fsiz = n;
+ if (fsiz > (CK_OFF_T)-1) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+ }
+ if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
+ pctlbl = 1;
+ } else {
+ pctlbl = 0;
+ }
+ scrft(); /* File type */
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_PT: /* Packet type or pseudotype */
+ if (spackets < 5) {
+ extern int sysindex;
+ extern struct sysdata sysidlist[];
+ /* Things that won't change after the 4th packet */
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_PAR,
+ (long) parnam((char)parity)
+ );
+ if (
+#ifdef NEWFTP
+ (ftp && (spackets == 1 || rpackets == 1)) ||
+#endif /* NEWFTP */
+ spackets == 4
+ ) {
+ if (
+#ifdef NEWFTP
+ ftp ||
+#endif /* NEWFTP */
+ ((protocol == PROTO_K) && (sysindex > -1))
+ ) {
+ char msgbuf[128];
+ if (net) {
+ sprintf(msgbuf,"Network Host: %s (%s)",
+#ifdef NEWFTP
+ ftp ? (ftp_host ? ftp_host : "") :
+#endif /* NEWFTP */
+ ttname,
+#ifdef NEWFTP
+ ftp ? ftp_srvtyp :
+#endif /* NEWFTP */
+ sysidlist[sysindex].sid_name
+ );
+ } else {
+ sprintf(msgbuf,
+ "Communication Device: %s (remote host is %s)",
+ ttname,
+ sysidlist[sysindex].sid_name
+ );
+ }
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_LIN,
+ (long) msgbuf
+ );
+ }
+ }
+ }
+#ifdef CK_TIMERS
+ if (/* rttflg && */ protocol == PROTO_K) {
+ long xx;
+ if (
+#ifdef STREAMING
+ streaming && oldwin != -2
+#else
+ 0
+#endif /* STREAMING */
+ ) {
+ char msgbuf[64];
+ sprintf(msgbuf,"00 / 00");
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_TMO,
+ (long) msgbuf
+ );
+ } else {
+ xx = (rttdelay + 500) / 1000;
+ if (xx != oldrtt || rcvtimo != oldtim) {
+ char msgbuf[64];
+ sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
+ KuiSetProperty( KUI_FILE_TRANSFER,
+ (long) CW_TMO,
+ (long) msgbuf
+ );
+ oldrtt = xx;
+ oldtim = rcvtimo;
+ clrtoeol();
+ }
+ }
+ }
+#endif /* CK_TIMERS */
+
+ x = (what & W_RECV) ? /* Packet length */
+ rpktl+(protocol==PROTO_K?1:0) :
+ spktl;
+ if (x != oldlen) { /* But only if it changed. */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
+ oldlen = x;
+ }
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
+
+ if (protocol == PROTO_K && !ftp) { /* Window slots */
+ char ws[16];
+ int flag;
+ flag = 0;
+#ifdef STREAMING
+ if (streaming) {
+ if (oldwin != -2) {
+ sprintf(ws,"STREAMING");
+ flag = 1;
+ oldwin = -2;
+ }
+ } else
+#endif /* STREAMING */
+ if (wcur != oldwin) {
+ sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
+ flag = 1;
+ oldwin = wcur;
+ }
+ if (flag) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
+ }
+ }
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Retry count, if changed */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
+ oldtry = errors;
+ }
+ /* Sender's packet type */
+ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
+ char type[2];
+ sprintf(type, "%c",c);
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
+ oldtyp = c;
+ }
+ switch (c) { /* Now handle specific packet types */
+ case 'S': /* Beginning of transfer */
+ fcnt = fbyt = 0L; /* Clear counters */
+#ifdef GFTIMER
+ gtv = -1.0;
+#else /* GFTIMER */
+ gtv = -1L; /* And old/new things... */
+#endif /* GFTIMER */
+ oldpct = pct = 0L;
+ break;
+
+ case 'Z': /* or EOF */
+ debug(F101,"screeng SCR_PT Z pktnum","",n);
+ debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
+ debug(F101,"screeng SCR_PT Z pct","",pct);
+ case 'D': /* Data packet */
+ if (fsiz > 0L) { /* Show percent done if known */
+ oldpct = pct; /* Remember previous percent */
+ howfar = ffc;
+#ifdef CK_RESEND
+ if (what & W_SEND) /* Account for PSEND or RESEND */
+ howfar += sendstart;
+ else if (what & W_RECV)
+ howfar += rs_len;
+#endif /* CK_RESEND */
+ /* Percent done, to be displayed... */
+ if (c == 'Z') {
+ if (!discard && !cxseen && !czseen) pct = 100L;
+ } else
+ pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
+ if (pct > 100L || /* Allow for expansion and */
+ (oldpct == 99L && pct < 0L)) /* other boundary conditions */
+ pct = 100L;
+ if (pct != oldpct) /* Only do this 100 times per file */
+ updpct(oldpct, pct);
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ break;
+
+ case '%': /* Timeouts, retransmissions */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR,
+ (long) errors
+ );
+ }
+ oldtry = errors;
+ if (s) if (*s) {
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+ }
+ break;
+
+ case 'E': /* Error packet */
+ if (*s) {
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+ }
+ fcnt = fbyt = 0L; /* So no bytes for this file */
+ break;
+ case 'Q': /* Crunched packet */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Damaged Packet"
+ );
+ break;
+ case 'q': /* Ctrl-C or connection lost */
+ if (!s) s = "";
+ if (!*s) s = "User interruption or connection lost";
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) s
+ );
+ break;
+ case 'T': /* Timeout */
+ cps = shocps((int) pct, fsiz, howfar);
+ /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Timeout"
+ );
+ errors = retrans + crunched + timeouts;
+ if (errors != oldtry) { /* Error count, if changed */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_PR, (long) errors
+ );
+ oldtry = errors;
+ }
+ break;
+ default: /* Others, do nothing */
+ break;
+ }
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ case SCR_ST: /* File transfer status */
+ debug(F101,"screeng SCR_ST c","",c);
+ debug(F101,"screeng SCR_ST success","",success);
+ debug(F101,"screeng SCR_ST cxseen","",cxseen);
+#ifdef COMMENT
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl)
+ updpct(oldpct,100);
+ else
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+ pct = 100;
+ oldpct = 0;
+ } else if (fsiz > 0L) /* Not OK, update final percent */
+/*
+ The else part writes all over the screen -- howfar and/or fsiz have
+ been reset as a consequence of the not-OKness of the transfer.
+*/
+ if (pctlbl)
+ updpct(oldpct, (howfar * 100L) / fsiz);
+#else
+ if (c == ST_OK) { /* OK, print 100 % */
+ if (pctlbl) {
+ updpct(oldpct,100);
+ } else
+ KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
+#ifdef COMMENT
+ pct = 100;
+ oldpct = 0;
+#endif /* COMMENT */
+ }
+#endif /* COMMENT */
+
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+
+ switch (c) { /* Print new status message */
+ case ST_OK: /* Transfer OK */
+ fcnt++; /* Count this file */
+ if (what == (W_FTP|W_FT_DELE)) {
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Delete OK"
+ );
+ } else {
+ fbyt += ffc;
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) "Transfer OK"
+ );
+ }
+ return;
+
+ case ST_DISC: /* Discarded */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "File discarded"
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_INT: /* Interrupted */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "Transfer interrupted"
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_SKIP: { /* Skipped */
+ char errbuf[64] ;
+ if (n > 0 && n < nskreason)
+ sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
+ else
+ sprintf( errbuf, "File skipped" ) ;
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) errbuf
+ );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+ }
+ case ST_ERR: /* Error message */
+ if (!s) s = (char *)epktmsg;
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_REFU: /* Refused */
+ if (*s) {
+ char errbuf[64] ;
+ sprintf( errbuf, "Refused, %s", s ) ;
+ KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
+ } else {
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+ }
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_INC:
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case ST_MSG:
+ KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+ return;
+
+ default: /* Bad call */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+ (long) "*** screen() called with bad status ***" );
+ return;
+ }
+
+ case SCR_TC: { /* Transaction complete */
+ char msgbuf[128];
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+ if (success) {
+ sprintf(msgbuf,
+ "SUCCESS. Files: %s, Bytes: %ld, %ld CPS",
+ filcnt - filrej,
+ ckfstoa(fbyt),
+ tfcps
+ );
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_MSG,
+ (long) msgbuf
+ );
+ }
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_TR,
+ (long) hhmmss((long)
+#ifdef GFTIMER
+ (fptsecs + 0.5)
+#else
+ tsecs
+#endif /* GFTIMER */
+ ));
+
+#ifdef GFTIMER
+ oldgtv = (CKFLOAT) -1.0;
+#else
+ oldgtv = -1L;
+#endif /* GFTIMER */
+
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+ cendw = 1;
+ if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
+ ft_win = 0; /* Window closed. */
+ return;
+ }
+ case SCR_EM: /* Error packet (fatal) */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
+ if (xfrbel) bleep(BP_FAIL);
+#ifdef COMMENT
+ pct = oldpct = 0;
+#endif /* COMMENT */
+ return;
+
+ case SCR_QE: /* Quantity equals */
+ case SCR_TU: /* Undelimited text */
+ case SCR_TN: /* Text delimited at start */
+ case SCR_TZ: /* Text delimited at end */
+ return; /* (ignored in fullscreen display) */
+
+ case SCR_XD: /* X-packet data */
+ pct = oldpct = 0;
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
+ return;
+
+ case SCR_CW: /* Close Window */
+#ifdef COMMENT
+ pct = 100; oldpct = 0; /* Reset these for next time. */
+#endif /* COMMENT */
+ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
+ oldtim = -1;
+
+ ft_win = 0; /* Flag that window is closed. */
+ cendw = 1; return;
+
+ case SCR_CD: /* Display current directory */
+ KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
+#ifdef OS2
+ SaveCmdMode(0, 0);
+#endif /* OS2 */
+ return;
+
+ default: /* Bad call */
+ KuiSetProperty(KUI_FILE_TRANSFER,
+ (long) CW_ERR,
+ (long) "*** screen() called with bad function code ***"
+ );
+ return;
+ }
+}
+#endif /* KUI */
+#endif /* MAC */
+
+#endif /* NOXFER */
+
+#ifndef CK_CURPOS
+/* Dummies for when cursor control is not supported */
+int
+ck_curpos(row, col) {
+ return(-1);
+}
+
+int
+ck_cls() {
+ return(-1);
+}
+
+int
+ck_cleol() {
+ return(-1);
+}
+#endif /* CK_CURPOS */
+
+#ifndef NOIKSD
+#ifdef IKSDB
+
+struct iksdbfld dbfld[] = {
+ /* Offset Length Type */
+ { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */
+ { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */
+ { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */
+ { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */
+ { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */
+ { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */
+ { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */
+ { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */
+ { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */
+ { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */
+ { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */
+ { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */
+ { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */
+ { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */
+ { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */
+ { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */
+};
+
+static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */
+static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */
+
+static char * updmode = /* Update mode for fopen() */
+#ifdef OS2
+ "r+b"
+#else
+#ifdef VMS
+ "r+b"
+#else
+ "r+"
+#endif /* VMS */
+#endif /* OS2 */
+ ;
+
+/* D B I N I T -- Initialize the IKSD database... */
+
+int
+dbinit() {
+ extern int dbinited;
+ int x = 0;
+ debug(F110,"dbinit dbdir 1",dbdir,0);
+ debug(F110,"dbinit dbfile 1",dbfile,0);
+ if (dbinited)
+ return(0);
+#ifdef OS2
+ if (!dbdir) {
+#ifdef NT
+ char * p = NULL;
+ if (!isWin95()) {
+ p = getenv("SystemRoot");
+ } else {
+ p = getenv("winbootdir");
+ if (!p) p = getenv("windir");
+ }
+ if (!p) p = "C:/";
+ dbdir = malloc(strlen(p)+2);
+ strcpy(dbdir,p); /* safe */
+ p = dbdir;
+ while (*p) {
+ if (*p == '\\')
+ *p = '/';
+ p++;
+ }
+ if (*(p-1) != '/' ) {
+ *p++ = '/';
+ *p = '\0';
+ }
+#else /* NT */
+ makestr(&dbdir,"C:/");
+#endif /* NT */
+ }
+#else /* OS2 */
+ if (!dbdir)
+ makestr(&dbdir,IK_DBASEDIR);
+#endif /* OS2 */
+
+ if (!dbfile) {
+ char * s = "";
+ x = strlen(dbdir);
+ if (dbdir[x-1] != '/') {
+ s = "/";
+ x++;
+ }
+ x += (int)strlen(IK_DBASEFIL);
+ dbfile = (char *)malloc(x+1);
+ sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
+ }
+ debug(F110,"dbinit dbdir 2",dbdir,0);
+ debug(F110,"dbinit dbfile 2",dbfile,0);
+ mypid = getpid(); /* Get my pid */
+ debug(F101,"dbinit mypid","",mypid);
+
+ if (!myhexip[0]) { /* Set my hex IP address */
+#ifdef TCPSOCKET
+ extern unsigned long myxipaddr;
+ if (getlocalipaddr() > -1) {
+ myip = myxipaddr;
+ sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
+ } else
+#endif /* TCPSOCKET */
+ ckstrncpy(myhexip,"00000000",9);
+ }
+ debug(F111,"dbinit myip",myhexip,myip);
+ if (!peerhexip[0]) { /* Get peer's hex IP address */
+#ifdef TCPSOCKET
+ extern unsigned long peerxipaddr;
+ if (ckgetpeer()) {
+ peerip = peerxipaddr;
+ sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
+ debug(F111,"dbinit peerip",peerhexip,peerip);
+ } else {
+ debug(F101,"dbinit ckgetpeer failure","",errno);
+ ckstrncpy(peerhexip,"00000000",9);
+ }
+#else
+ ckstrncpy(peerhexip,"00000000",9);
+#endif /* TCPSOCKET */
+ }
+ debug(F111,"dbinit peerip",peerhexip,peerip);
+ debug(F101,"dbinit dbenabled","",dbenabled);
+ if (dbenabled && inserver) {
+ mydbslot = getslot();
+ debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
+ if (ikdbopen) dbinited = 1;
+ }
+ return(0);
+}
+
+/* U P D S L O T -- Update slot n */
+
+/*
+ Opens the database if necessary, seeks to slot n, writes current record
+ and adds current time to last-update field. n is the record sequence number
+ (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success.
+*/
+int
+updslot(n) int n; { /* Update our slot */
+ int rc = 0;
+ CK_OFF_T position;
+
+ debug(F111,"updslot","ikdbopen",ikdbopen);
+ if (!ikdbopen) /* Not if not ok */
+ return(0);
+ if (!dbfp) { /* Open database if not open */
+ dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */
+ if (!dbfp) {
+ debug(F110,"updslot fopen failed",dbfile,0);
+ ikdbopen = 0;
+ return(-1);
+ }
+ }
+ /* debug(F111,"updslot dbfile",dbfile,dbfp); */
+ position = n * DB_RECL;
+ if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */
+ debug(F111,"updslot fseek failed",dbfile,mydbseek);
+ ikdbopen = 0;
+ rc = -1;
+ } else {
+ /* Update the update time */
+ strncpy(&dbrec[dbfld[db_LASTU].off],
+ ckdate(),
+ dbfld[db_LASTU].len
+ );
+ if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
+ debug(F110,"updslot fwrite failed",dbfile,0);
+ ikdbopen = 0;
+ rc = -1;
+ } else { /* Flush the write */
+ fflush(dbfp);
+ }
+ }
+ return(rc);
+}
+
+/* I N I T S L O T -- Initialize slot n with my info */
+
+int
+initslot(n) int n; { /* Initialize slot */
+ int k;
+#ifdef TCPSOCKET
+ extern unsigned long peerxipaddr;
+#endif /* TCPSOCKET */
+
+ debug(F101,"initslot","",n);
+
+#ifdef USE_MEMCPY
+ memset(dbrec,32,DB_RECL);
+#else
+ for (k = 0; k < DB_RECL; k++)
+ dbrec[k] = '\040';
+#endif /* USE_MEMCPY */
+
+ myflags = DBF_INUSE; /* Set in-use flag */
+ mystate = W_NOTHING;
+ myatype = 0L;
+ myamode = 0L;
+
+ k = dbfld[db_FLAGS].len; /* Length of flags field */
+ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
+
+ k = dbfld[db_ATYPE].len;
+ strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
+
+ k = dbfld[db_AMODE].len;
+ strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
+
+ k = dbfld[db_STATE].len;
+ strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
+
+ k = dbfld[db_SADDR].len;
+ strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
+
+#ifdef TCPSOCKET
+ ckgetpeer();
+ k = dbfld[db_CADDR].len;
+ strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
+#else
+ k = dbfld[db_CADDR].len;
+ strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
+#endif /* TCPSOCKET */
+
+ k = dbfld[db_MYPID].len;
+ strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
+
+ k = dbfld[db_START].len;
+ strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
+
+ k = dbfld[db_ULEN].len;
+ strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
+
+ k = dbfld[db_DLEN].len;
+ strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
+
+ k = dbfld[db_ILEN].len;
+ strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
+
+ strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
+ return(updslot(n));
+}
+
+int
+slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
+ int k, l1, l2, l3, z;
+ mystate = x;
+ debug(F101,"slotstate ikdbopen","",ikdbopen);
+ if (!ikdbopen)
+ return(-1);
+ if (!s1) s1 = "";
+ l1 = strlen(s1);
+ if (!s2) s2 = "";
+ l2 = strlen(s2);
+ if (!s3) s3 = "";
+ l3 = strlen(s3);
+ strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
+ k = dbfld[db_ILEN].len;
+ z = l1 + l2 + l3 + 2;
+ if (z > dB_INFO)
+ z = dB_INFO;
+ strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
+ k = dbfld[db_INFO].len;
+ z = dbfld[db_INFO].off;
+ if (l1 <= k) {
+ lset(&dbrec[z],s1,l1+1,32);
+ z += l1+1;
+ k -= l1+1;
+ if (l2 <= k) {
+ lset(&dbrec[z],s2,l2+1,32);
+ z += l2+1;
+ k -= l2+1;
+ if (l3 <= k)
+ lset(&dbrec[z],s3,k,32);
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+ char buf[128];
+ int i;
+ strncpy(buf,&dbrec[DB_INFO],127);
+ buf[127] = NUL;
+ for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
+ debug(F111,"slotstate",buf,mystate);
+ }
+#endif /* DEBUG */
+ z = updslot(mydbslot);
+ debug(F101,"slotstate updslot","",z);
+ return(z);
+}
+
+int
+slotdir(s1,s2) char * s1, * s2; { /* Update current directory */
+ int k, len1, len2;
+ if (!ikdbopen)
+ return(-1);
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+ k = dbfld[db_DLEN].len;
+ strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
+ k = dbfld[db_DIR].len;
+ if (len1 > 0) {
+ lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
+ lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
+ } else {
+ lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
+ }
+ return(updslot(mydbslot));
+}
+
+/* F R E E S L O T -- Free slot n */
+
+int
+freeslot(n) int n; {
+ int k;
+ if (!ikdbopen)
+ return(0);
+ dbflags = 0L;
+ if (n == mydbslot) {
+ dbflags = myflags & ~DBF_INUSE;
+ dbflags &= ~DBF_LOGGED;
+ }
+ k = dbfld[db_FLAGS].len;
+ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
+ return(updslot(n));
+}
+
+/* G E T S L O T -- Find a free database slot; returns slot number */
+
+#ifdef UNIX
+#include <fcntl.h> /* For creat() */
+#endif /* UNIX */
+
+int
+getslot() { /* Find a free slot for us */
+ FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */
+ char idstring[64]; /* PID string buffer (decimal) */
+ char pidbuf[64], * s;
+ int j, k, n, x, rc = -1;
+ int lockfd, tries, haveslot = 0;
+ long lockpid;
+ CK_OFF_T i;
+ /* char ipbuf[17]; */
+
+ if (!myhexip[0]) /* Set my hex IP address if not set */
+ ckstrncpy((char *)myhexip,"7F000001",33);
+ sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
+ debug(F110,"getslot idstring", idstring, 0);
+
+ /* Make temporary lockfile name IP.PID (hex.hex) */
+ /* This should fit in 14 chars -- huge PIDs are usually not possible */
+ /* on 14-char filename systems. */
+
+ sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
+ debug(F110,"getslot tempfile",tmplck,0);
+
+ /* Make a temporary file */
+
+ lockfd = creat(tmplck, 0600); /* BUT THIS ISN'T PORTABLE */
+ if (lockfd < 0) {
+ debug(F111,"getslock temp lockfile create failure", tmplck, errno);
+ return(-1);
+ }
+ /* Write my (decimal) PID into the temp file */
+
+ write(lockfd,idstring,(int)strlen(idstring));
+ if (close(lockfd) < 0) { /* Close lockfile */
+ debug(F101,"getslot error closing temp lockfile", "", errno);
+ return(-1);
+ }
+ sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
+ debug(F110,"getslot lockfile",lcknam,0);
+
+ rfp = fopen(lcknam,"r"); /* See if lockfile exists */
+ if (rfp) { /* If so... */
+ rset(pidbuf,"",64,0);
+ x = fread(pidbuf,1,63,rfp); /* Read ID string from it */
+ fclose(rfp); /* and close it quickly */
+ debug(F110,"getslot lock exists",pidbuf,0);
+ if (x > 0) { /* If we have a PID, check it */
+ char * s = pidbuf;
+ while (*s) {
+ if (islower(*s)) *s = toupper(*s);
+ if (*s == ':') {
+ *s = NUL;
+ debug(F110,"getslot lock IP",pidbuf,0);
+ debug(F110,"gteslot my IP",myhexip,0);
+ if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
+ lockpid = atol(s+1); /* Yes, now get PID */
+ debug(F101,"getslot lockpid","",lockpid);
+
+ /* Check if PID lockpid on this computer is alive */
+ x = zchkpid(lockpid);
+ if (!x) {
+ debug(F100,"getslot PID stale,removing lock","",0);
+ unlink(lcknam);
+ }
+ break;
+ }
+ }
+ s++;
+ }
+ } else {
+ debug(F111,"getslot lockfile open failure",lcknam,errno);
+ }
+ }
+ /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
+
+ for (tries = IK_LCKTRIES; tries > 0; tries--) {
+ if (zrename(tmplck,lcknam) == 0)
+ break;
+ debug(F101,"getslot database locked by pid", "", dbpid);
+ sleep(IK_LCKSLEEP);
+ }
+ if (tries < 1) { /* Couldn't */
+ debug(F110,"getslot create lock failure",lcknam,0);
+ return(-1);
+ }
+ /* Have lock, open database */
+
+ debug(F110,"getslot has lock",lcknam,0); /* Have lock */
+
+ if (!dbfile)
+ return(-1);
+
+ /* If database doesn't exist, create it. */
+
+ debug(F110,"getslot dbfile",dbfile,0);
+ if (zchki(dbfile) < 0) {
+ debug(F110,"getslot creating new database",dbfile,0);
+ x = creat(dbfile,0660);
+ if (x < 0) {
+ debug(F111,"getslot creat() failed", dbfile, errno);
+ goto xslot;
+ }
+ close(x);
+ }
+ dbfp = fopen(dbfile,updmode); /* Open it in update mode */
+ if (!dbfp) {
+ debug(F111,"getslot fopen failed",dbfile,errno);
+ goto xslot;
+ }
+ /* Now find a free (or new) slot... */
+
+ dblastused = 0L; /* Seek pointer to last record inuse */
+ mydbseek = 0L; /* Seek pointer for my record */
+
+ /* Quickly read the whole database; n = record counter, i = seek pointer */
+
+ for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
+ x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
+ if (x < 1) /* EOF not caught by feof() */
+ break;
+#ifndef NOFTRUNCATE
+ if (x != DB_RECL) { /* Watch out for trailing junk */
+ debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */
+#ifdef COHERENT
+ chsize(fileno(dbfp),i);
+#else
+ ftruncate(fileno(dbfp),(CK_OFF_T)i);
+#endif /* COHERENT */
+ x = 0;
+ CKFSEEK(dbfp,i,0);
+ break;
+ }
+#endif /* NOFTRUNCATE */
+ debug(F101,"getslot record","",n);
+ k = dbfld[db_FLAGS].off;
+ j = dbfld[db_FLAGS].len;
+ dbflags = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbflags","",dbflags);
+ k = dbfld[db_MYPID].off;
+ j = dbfld[db_MYPID].len;
+ dbpid = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbpid","",dbpid);
+ k = dbfld[db_SADDR].off;
+ j = dbfld[db_SADDR].len;
+ dbip = hextoulong(&dbrec[k],j);
+ debug(F001,"getslot dbip","",dbip);
+
+ if (dbflags & DBF_INUSE) { /* Remember last slot in use */
+ x = 0; /* Make sure it's REALLY in use */
+ if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
+ x = 1;
+ debug(F101,"getslot record pid","",dbpid);
+ } else { /* Or for stale PID */
+ x = zchkpid(dbpid);
+ debug(F101,"getslot zchkpid()","",x);
+ }
+ if (!x) { /* Bogus record */
+ x = freeslot(n);
+ debug(F101,"getslot stale record pid: freeslot()","",x);
+ if (x > -1 && !haveslot)
+ dbflags = 0;
+ } else { /* It's really in use */
+ dblastused = i;
+ }
+ }
+ if (!haveslot) { /* If I don't have a slot yet */
+ if (!(dbflags & DBF_INUSE)) { /* Claim this one */
+ debug(F101,"getslot free slot", "", n);
+ haveslot = 1;
+ mydbseek = i;
+ mydbslot = n; /* But keep going... */
+ }
+ }
+ }
+ /* Come here with i == seek pointer to first record after eof */
+
+ if (!haveslot) { /* Found no free slot so add to end */
+ debug(F101,"getslot new slot","",n);
+ haveslot = 1;
+ mydbseek = i;
+ mydbslot = n;
+ }
+ ikdbopen = 1; /* OK to make database entries */
+ debug(F101,"getslot records","",n);
+ debug(F101,"getslot dblastused","",dblastused);
+ debug(F101,"getslot i","",i);
+
+ /* Trim stale records from end */
+
+#ifndef NOFTRUNCATE
+ if (i > dblastused+DB_RECL) {
+ debug(F101,"getslot truncating at","",dblastused+DB_RECL);
+#ifdef COHERENT
+ x = chsize(fileno(dbfp),dblastused+DB_RECL);
+#else
+ x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL));
+#endif /* COHERENT */
+ if (x < 0) /* (Not fatal) */
+ debug(F101,"getslot ftruncate failed", "", errno);
+ }
+#endif /* NOFTRUNCATE */
+
+ /* Initialize my record */
+
+ if (initslot(mydbslot) < 0) {
+ debug(F101,"getslot initslot() error","",n);
+ ikdbopen = 0;
+ goto xslot;
+ }
+ debug(F101,"getslot OK","",mydbslot);
+ rc = mydbslot; /* OK return code */
+
+ xslot: /* Unlock the database and return */
+ if (unlink(lcknam) < 0) {
+ debug(F111,"getslot lockfile removal failed",lcknam,errno);
+ rc = -1;
+ }
+ return(rc);
+}
+#endif /* IKSDB */
+#endif /* NOIKSD */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuusy.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusy.c
new file mode 100644
index 0000000..1802b05
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuusy.c
@@ -0,0 +1,4744 @@
+#include "ckcsym.h"
+#define XFATAL fatal
+
+/* C K U U S Y -- "User Interface" for C-Kermit Kermit, part Y */
+
+/* Command-Line Argument Parser */
+
+/*
+ Authors:
+ Frank da Cruz <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, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+#include "ckcdeb.h"
+
+char * bannerfile = NULL;
+char * helpfile = NULL;
+extern int xferlog, filepeek, nolinks;
+extern char * xferfile;
+extern int debtim;
+
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckucmd.h"
+#include "ckcnet.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+#include <signal.h>
+
+#ifdef OS2
+#include <io.h>
+#ifdef KUI
+#include "ikui.h"
+extern struct _kui_init kui_init;
+#endif /* KUI */
+#endif /* OS2 */
+
+extern int inserver, fncnv, f_save, xfermode;
+#ifdef PATTERNS
+extern int patterns;
+#endif /* PATTERNS */
+
+#ifndef NOICP
+extern int cmdint;
+#endif /* NOICP */
+extern int xsuspend;
+
+#ifdef NETCONN
+#ifdef ANYX25
+extern int revcall, closgr, cudata;
+extern char udata[];
+extern int x25fd;
+#endif /* ANYX25 */
+#ifndef VMS
+#ifndef OS2
+#ifndef OSK
+extern
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* VMS */
+
+int telnetfd;
+extern struct keytab netcmd[];
+extern int tn_exit;
+#ifndef NOICP
+#ifndef NODIAL
+extern int nnets, nnetdir; /* Network services directory */
+extern char *netdir[];
+extern char *nh_p[]; /* Network directory entry pointers */
+extern char *nh_p2[]; /* Network directory entry nettype */
+extern char *nh_px[4][MAXDNUMS + 1];
+#endif /* NODIAL */
+extern int nhcount;
+extern char * n_name; /* Network name pointer */
+#endif /* NOICP */
+#endif /* NETCONN */
+
+#ifndef NOSPL
+extern int nmac;
+extern struct mtab *mactab;
+#endif /* NOSPL */
+extern char uidbuf[];
+
+#ifdef CK_LOGIN
+extern int logintimo;
+#endif /* CK_LOGIN */
+
+extern char * myname, * dftty;
+extern int howcalled;
+
+extern char *ckxsys, *ckzsys, **xargv, *xarg0, **cmlist, *clcmds;
+
+extern int action, cflg, xargc, cnflg, local, quiet, escape, network, mdmtyp,
+ bgset, backgrd, xargs, binary, parity, turn, turnch, duplex, flow, clfils,
+ noinit, stayflg, nettype, cfilef, noherald, cmask, cmdmsk, exitonclose,
+ haveline, justone, cxtype, xfinish, ttnproto;
+
+extern long speed;
+extern char ttname[];
+extern char * pipedata, * cmdfil;
+
+#ifndef NOXFER
+extern char *cmarg, *cmarg2;
+
+extern int nfils, stdouf, stdinf, displa, maxrps, rpsiz, ckwarn, urpsiz,
+ wslotr, swcapr, ckdelay, recursive, reliable, xreliable, fnspath, fncact,
+ clearrq, setreliable;
+
+#ifdef PIPESEND
+extern int usepipes, pipesend;
+#endif /* PIPESEND */
+extern int protocol;
+#endif /* NOXFER */
+
+#ifndef NOPUSH
+extern int nopush;
+#endif /* NOPUSH */
+
+#ifdef OS2
+extern struct keytab os2devtab[];
+extern int nos2dev;
+extern int ttslip;
+extern int tt_scroll, tt_escape;
+#ifdef OS2PM
+extern int os2pm;
+#endif /* OS2PM */
+#endif /* OS2 */
+
+#ifdef CK_NETBIOS
+extern unsigned char NetBiosAdapter;
+#endif /* CK_NETBIOS */
+
+#ifdef XFATAL
+#undef XFATAL
+#endif /* XFATAL */
+
+#ifdef TNCODE
+_PROTOTYP(static int dotnarg, (char x) );
+#endif /* TNCODE */
+#ifdef RLOGCODE
+_PROTOTYP(static int dorlgarg, (char x) );
+#endif /* RLOGCODE */
+#ifdef SSHBUILTIN
+_PROTOTYP(static int dossharg, (char x) );
+#endif /* SSHBUILTIN */
+
+int haveftpuid = 0; /* Have FTP user ID */
+static int have_cx = 0; /* Have connection */
+
+static char * failmsg = NULL; /* Failure message */
+
+#ifdef NEWFTP
+extern char * ftp_host;
+#endif /* NEWFTP */
+
+extern int what;
+
+#ifndef NOICP
+#ifndef NODIAL
+extern int nmdm, telephony;
+extern struct keytab mdmtab[];
+extern int usermdm, dialudt;
+#endif /* NODIAL */
+_PROTOTYP(static int pmsg, (char *) );
+_PROTOTYP(static int fmsg, (char *) );
+static int pmsg(s) char *s; { printf("%s\n", s); return(0); }
+static int fmsg(s) char *s; { fatal(s); return(0); }
+#define XFATAL(s) return(what==W_COMMAND?pmsg(s):fmsg(s))
+#else
+#define XFATAL fatal
+#endif /* NOICP */
+
+#ifndef NOHTTP
+#define HTTP_GET 1
+#define HTTP_PUT 2
+#define HTTP_HED 3
+#endif /* NOHTTP */
+
+#ifdef CK_URL
+/* URLs we recognize */
+
+#define URL_FTP 1
+#define URL_HTTP 2
+#define URL_HTTPS 3
+#define URL_IKSD 4
+#define URL_TELNET 5
+#define URL_LOGIN 6
+
+struct keytab urltab[] = {
+#ifdef NEWFTP
+ "ftp", URL_FTP, 0,
+#endif /* NEWFTP */
+#ifndef NOHTTP
+ "http", URL_HTTP, 0,
+ "https", URL_HTTPS, 0,
+#endif /* NOHTTP */
+ "iksd", URL_IKSD, 0,
+ "kermit", URL_IKSD, 0,
+ "telnet", URL_TELNET, 0,
+ "", 0, 0
+};
+int nurltab = sizeof(urltab)/sizeof(struct keytab) - 1;
+
+#ifndef URLBUFLEN
+#define URLBUFLEN 1024
+#endif /* URLBUFLEN */
+static char urlbuf[URLBUFLEN];
+struct urldata g_url = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+
+/* u r l p a r s e -- Parse a possible URL */
+
+/*
+ Returns 0 if the candidate does not seem to be a URL.
+ Returns 1 if it might be a URL, with the above pointers set to its pieces:
+ service : [ // ] [ user [ : password ] @ ] host [ : service ] [ / path ] -
+ [ ? name [ = value ]]
+
+ Example: ftp://ds.internic.net:21/rfc/rfc1234.txt
+ url.svc = [ftp]
+ url.usr = [(NULL)]
+ url.psw = [(NULL)]
+ url.hos = [ds.internic.net]
+ url.por = [21]
+ url.pth = [rfc/rfc1234.txt]
+
+ It might be a URL if it contains a possible service name followed by a
+ a colon (:). Thus "telnet:xyzcorp.com" is a minimal URL, whereas a
+ full-blown example would be:
+
+ ftp://olga:secret@ftp.xyzcorp.com/public/oofa.txt
+
+ The caller must verify the results, i.e. that the service string is a real
+ TCP service, etc. This routine just parses the fields.
+
+ struct urldata defined in ckcker.h
+*/
+
+int
+urlparse(s,url) char *s; struct urldata * url; {
+ char * p = NULL, * urlbuf = NULL;
+ int x;
+
+ if (!s || !url)
+ return(0);
+
+ if (!*s)
+ return(0);
+
+ makestr(&urlbuf,s);
+
+ if (url->sav) { /* In case we were called before... */
+ free(url->sav);
+ url->sav = NULL;
+ }
+ if (url->svc) {
+ free(url->svc);
+ url->svc = NULL;
+ }
+ if (url->hos) {
+ free(url->hos);
+ url->hos = NULL;
+ }
+ if (url->por) {
+ free(url->por);
+ url->por = NULL;
+ }
+ if (url->usr) {
+ free(url->usr);
+ url->usr = NULL;
+ }
+ if (url->psw) {
+ free(url->psw);
+ url->psw = NULL;
+ }
+ if (url->pth) {
+ free(url->pth);
+ url->pth = NULL;
+ }
+ if (url->nopts) {
+ int i;
+ for (i = 0; i < url->nopts && i < MAX_URL_OPTS; i++ ) {
+ if (url->opt[i].nam) {
+ free(url->opt[i].nam);
+ url->opt[i].nam = NULL;
+ }
+ if (url->opt[i].val) {
+ free(url->opt[i].val);
+ url->opt[i].val = NULL;
+ }
+ }
+ url->nopts = 0;
+ }
+ p = urlbuf; /* Was a service requested? */
+ while (*p && *p != ':') /* Look for colon */
+ p++;
+ if (*p == ':') { /* Have a colon */
+ *p++ = NUL; /* Get service name or number */
+ if (*p == ':') /* a second colon */
+ *p++ = NUL; /* get rid of that one too */
+ while (*p == '/') *p++ = NUL; /* and slashes */
+#ifdef COMMENT
+ /* Trailing slash is part of path - leave it - jaltman */
+ x = strlen(p); /* Length of remainder */
+ if (p[x-1] == '/') /* If there is a trailing slash */
+ p[x-1] = NUL; /* remove it. */
+#endif /* COMMENT */
+ if (urlbuf[0]) { /* Anything left? */
+ char *q = p, *r = p, *w = p;
+ makestr(&url->svc,urlbuf);
+
+ while (*p != NUL && *p != '@') /* look for @ */
+ p++;
+ if (*p == '@') { /* Signifies user ID, maybe password */
+ *p++ = NUL;
+ url->hos = p;
+ while (*w != NUL && *w != ':')
+ w++;
+ if (*w == ':')
+ *w++ = NUL;
+ url->usr = r; /* Username */
+ if (*w)
+ url->psw = w; /* Password */
+ q = p;
+ } else { /* No username or password */
+ p = q;
+ url->hos = p;
+ }
+#ifdef COMMENT
+ debug(F111,"urlparse url->usr",url->usr,url->usr);
+ debug(F111,"urlparse url->psw",url->usr,url->psw);
+ debug(F111,"urlparse url->hos",url->usr,url->hos);
+#endif /* COMMENT */
+
+ while (*p != NUL && *p != ':' && *p != '/') /* Port? */
+ p++;
+ if (*p == ':') { /* TCP port */
+ *p++ = NUL;
+ r = p;
+ url->por = r;
+ while (*p != NUL && *p != '/')
+ p++;
+ /* '/' is part of path, leave it until we can copy */
+ if (*p == '/') {
+ makestr(&url->pth,p); /* Path */
+ *p = NUL;
+ }
+ } else { /* No port */
+ /* '/' is part of path, leave it */
+ if (*p == '/') {
+ makestr(&url->pth,p); /* Path */
+ *p = NUL;
+ }
+ }
+ }
+ /* Copy non-NULL result strings */
+ if (url->svc) if (*url->svc) {
+ p = url->svc;
+ url->svc = NULL;
+ makestr(&url->svc,p);
+ }
+ if (url->hos) if (*url->hos) {
+ p = url->hos;
+ url->hos = NULL;
+ makestr(&url->hos,p);
+ }
+ if (url->por) if (*url->por) {
+ p = url->por;
+ url->por = NULL;
+ makestr(&url->por,p);
+ }
+/*
+ WARNING (Wed Oct 9 16:09:03 2002): We now allow the username and
+ password to be empty strings. These are treated differently from null
+ pointers: an empty string means the URL included username and/or password
+ fields that were empty, e.g. ftp://:@ftp.xyzcorp.com/somepath/somefile,
+ which causes the client to prompt for the username and/or password.
+*/
+ if (url->usr) /* if (*url->usr) */ {
+ p = url->usr;
+ url->usr = NULL;
+ makestr(&url->usr,p);
+ }
+ if (url->psw) /* if (*url->psw) */ {
+ p = url->psw;
+ url->psw = NULL;
+ makestr(&url->psw,p);
+ }
+ /* Save a copy of the full url if one was found. */
+ if (url->svc)
+ makestr(&url->sav,s);
+ free(urlbuf);
+ return(url->svc ? 1 : 0);
+ }
+ return(0);
+}
+#endif /* CK_URL */
+
+#ifndef NOCMDL
+
+char *hlp1[] = {
+#ifndef NOICP
+" [filename] [-x arg [-x arg]...[-yyy]..] [ = text ] ]\n",
+#else
+"[-x arg [-x arg]...[-yyy]..]\n",
+#endif /* NOICP */
+"\n",
+" -x is an option requiring an argument, -y an option with no argument.\n",
+" If the first command-line argument is the name of a file, interactive-\n",
+" mode commands are executed from the file. The '=' argument tells Kermit\n",
+" not to parse the remainder of the command line, but to make the words\n",
+" following '=' available as \\%1, \\%2, ... \\%9. The command file \
+(if any)\n",
+" is executed before the command-line options.\n",
+"\n",
+#ifndef NOICP
+"If no action command is included, or -S is, then after the command line is\n",
+"executed, Kermit issues its prompt and waits for you to type commands.\n",
+#else
+"Operation by command-line options only.\n",
+#endif /* NOICP */
+""
+};
+
+static
+char *hlp2[] = {
+" [option-list] host[:port] [port]\n",
+" The option-list consists of zero, one, or more of:\n",
+" -8 Negotiate Telnet Binary in both directions\n",
+" -a Require use of Telnet authentication\n",
+" -d Turn on debug mode\n",
+" -E No escape character\n",
+" -K Refuse use of authentication; do not send username\n",
+" -l user Set username and request Telnet authentication\n",
+" -L Negotiate Telnet Binary Output only\n",
+" -x Require Encryption\n",
+" -D Disable forward-X\n",
+" -T cert=file Use certificate in file\n",
+" -T key=file Use private key in file\n",
+" -T crlfile=file Use CRL in file\n",
+" -T crldir=dir Use CRLs in directory\n",
+" -T cipher=string Use only ciphers in string\n",
+" -f Forward credentials to host\n",
+" -k realm Set default Kerberos realm\n",
+""
+};
+
+static
+char *hlp3[] = { /* rlogin */
+" [option-list] host[:port] [port]\n",
+" The option-list consists of zero, one, or more of:\n",
+" -d Turn on debug mode\n",
+" -l user Set username\n",
+""
+};
+
+static
+char *hlp4[] = { /* ssh */
+" [option-list] host[:port] [port]\n",
+" The option-list consists of zero, one, or more of:\n",
+#ifdef OS2
+" -# flags Kermit 95 Startup Flags\n",
+" 1 turn off Win95 special fixes\n",
+" 2 do not load optional network dlls\n",
+" 4 do not load optional tapi dlls\n",
+" 8 do not load optional kerberos dlls\n",
+" 16 do not load optional zmodem dlls\n",
+" 32 use stdin for input instead of the console\n",
+" 64 use stdout for output instead of the console\n",
+" 128 do not terminate process in response to Session Logoff\n",
+#endif /* OS2 */
+" -d Turn on debug mode\n",
+" -Y Disable init file processing\n",
+" -l user Set username\n",
+""
+};
+
+/* Command-line option help lines. Update this when adding new options! */
+
+char * opthlp[128]; /* Option help */
+char * arghlp[128]; /* Argument for option */
+int optact[128]; /* Action-option flag */
+
+VOID
+fatal2(msg1,msg2) char *msg1, *msg2; {
+ char buf[256];
+ if (!msg1) msg1 = "";
+ if (!msg2) msg2 = "";
+ ckmakmsg(buf,256,"\"",msg1,"\" - ",msg2);
+#ifndef NOICP
+ if (what == W_COMMAND)
+ printf("%s\n",buf);
+ else
+#endif /* NOICP */
+ fatal((char *)buf);
+}
+
+static SIGTYP
+#ifdef CK_ANSI
+cl_int(int dummy)
+#else /* CK_ANSI */
+cl_int(dummy) int dummy;
+#endif /* CK_ANSI */
+{ /* Command-line interrupt handler */
+ doexit(BAD_EXIT,1);
+ SIGRETURN;
+}
+
+#ifdef NEWFTP
+extern int ftp_action, ftp_cmdlin;
+
+static int
+xx_ftp(host, port) char * host, * port; {
+#ifdef CK_URL
+ extern int haveurl;
+#endif /* CK_URL */
+ extern char * ftp_logname;
+ int use_tls = 0;
+ char * p;
+
+ if (port) if (!*port) port = NULL;
+
+ if (!host)
+ return(0);
+ if (!*host)
+ return(0);
+ debug(F111,"ftp xx_ftp host",ftp_host,haveftpuid);
+ debug(F111,"ftp xx_ftp uidbuf 1",uidbuf,haveftpuid);
+ ftp_cmdlin = 1; /* 1 = FTP started from command line */
+ if (nfils > 0)
+ ftp_cmdlin++; /* 2 = same plus file transfer */
+
+#ifndef NOURL
+ /* debug(F111,"ftp xx_ftp g_url.usr",g_url.usr,g_url.usr); */
+ if (haveurl && g_url.usr) { /* Wed Oct 9 15:15:22 2002 */
+ if (!*(g_url.usr)) { /* Force username prompt if */
+ haveftpuid = 0; /* "ftp://:@host" given. */
+ uidbuf[0] = NUL;
+ makestr(&ftp_logname,NULL);
+ }
+ debug(F111,"ftp xx_ftp uidbuf 2",uidbuf,haveftpuid);
+ }
+#endif /* NOURL */
+ debug(F111,"ftp xx_ftp uidbuf 3",uidbuf,haveftpuid);
+ if (haveftpuid) {
+ makestr(&ftp_logname,uidbuf);
+ debug(F111,"ftp_logname",ftp_logname,haveftpuid);
+ }
+ if (!port) {
+ if ((p = ckstrchr(ftp_host,':')))
+ *p++ = NUL;
+ port = p;
+ }
+ if (!port) {
+#ifdef CK_URL
+ if (haveurl) {
+ if (g_url.por)
+ port = g_url.por;
+ else if (g_url.svc)
+ port = g_url.svc;
+ else
+ port = "ftp";
+ } else
+#endif /* CK_URL */
+ port = "ftp";
+ }
+
+#ifdef CK_SSL
+ if (haveurl && g_url.svc)
+ use_tls = !ckstrcmp("ftps",g_url.svc,-1,0);
+#endif /* CK_SSL */
+
+ if (ftpopen(ftp_host,port,use_tls) < 1)
+ return(-1);
+ debug(F111,"ftp xx_ftp action",ckctoa((char)ftp_action),nfils);
+ if (nfils > 0) {
+ switch (ftp_action) {
+ case 'g':
+ return(cmdlinget(stayflg));
+ case 'p':
+ case 's':
+ return(cmdlinput(stayflg));
+ }
+ }
+ return(1);
+}
+#endif /* NEWFTP */
+
+
+#ifndef NOHTTP
+static
+char * http_hlp[] = {
+ " -h This message.\n",
+ " -d Debug to debug.log.\n",
+ " -S Stay (issue command prompt when done).\n",
+ " -Y Do not execute Kermit initialization file.\n",
+ " -q Quiet (suppress most messages).\n",
+ " -u name Username.\n",
+ " -P password Password.\n",
+ " -g pathname Get remote pathname.\n",
+ " -p pathname Put remote pathname.\n",
+ " -H pathname Head remote pathname.\n",
+ " -l pathname Local path for -g, -p, and -H.\n",
+#ifdef CK_SSL
+ " -z opt[=value] Security options...\n",
+ " cert=file Client certificate file\n",
+ " certsok Accept all certificates\n",
+ " key=file Client private key file\n",
+ " secure Use SSL\n",
+ " verify=n 0 = none, 1 = peer , 2 = certificate required\n",
+#endif /* CK_SSL */
+ ""
+};
+
+#define HT_CERTFI 0
+#define HT_OKCERT 1
+#define HT_KEY 2
+#define HT_SECURE 3
+#define HT_VERIFY 4
+
+static struct keytab httpztab[] = {
+ { "cert", HT_CERTFI, CM_ARG },
+ { "certsok", HT_OKCERT, 0 },
+ { "key", HT_KEY, CM_ARG },
+ { "secure", HT_SECURE, 0 },
+ { "verify", HT_VERIFY, CM_ARG },
+ { "", 0, 0 }
+};
+static int nhttpztab = sizeof(httpztab) / sizeof(struct keytab) - 1;
+#endif /* NOHTTP */
+
+/* U S A G E */
+
+VOID
+usage() {
+#ifdef MINIX
+ conol("Usage: ");
+ conol(xarg0);
+ conol(" [-x arg [-x arg]...[-yyy]..] ]\n");
+#else
+ conol("Usage: ");
+ conol(xarg0);
+ if (howcalled == I_AM_KERMIT || howcalled == I_AM_IKSD ||
+ howcalled == I_AM_SSHSUB)
+ conola(hlp1);
+ else if (howcalled == I_AM_TELNET)
+ conola(hlp2);
+ else if (howcalled == I_AM_RLOGIN)
+ conola(hlp3);
+ else if (howcalled == I_AM_SSH)
+ conola(hlp4);
+ if (howcalled == I_AM_KERMIT || howcalled == I_AM_IKSD ||
+ howcalled == I_AM_SSHSUB) {
+ int c;
+ conoll("");
+ conoll("Complete listing of command-line options:");
+ conoll("");
+ for (c = 31; c < 128; c++) {
+ if (!opthlp[c])
+ continue;
+ if (arghlp[c]) {
+ printf(" -%c <arg>%s\n",
+ (char)c,
+ (optact[c] ? " (action option)" : "")
+ );
+ printf(" %s\n",opthlp[c]);
+ printf(" Argument: %s\n\n",arghlp[c]);
+ } else { /* Option without arg */
+ printf(" -%c %s%s\n",
+ (char)c, opthlp[c],
+ (optact[c]?" (action option)":"")
+ );
+ printf(" Argument: (none)\n\n");
+ }
+ }
+#ifdef OS2ORUNIX
+ printf("To prevent this message from scrolling, use '%s -h | more'.\n",
+ xarg0);
+#endif /* OS2ORUNIX */
+ printf("For a list of extended options use '%s --help'.\n",
+ xarg0);
+ }
+#endif /* MINIX */
+}
+
+
+/* C M D L I N -- Get arguments from command line */
+
+int
+cmdlin() {
+ char x; /* Local general-purpose char */
+ extern int haveurl;
+
+#ifdef NEWFTP
+ char * port = NULL;
+#endif /* NEWFTP */
+
+#ifndef NOXFER
+ cmarg = ""; /* Initialize globals */
+ cmarg2 = "";
+#endif /* NOXFER */
+ action = 0;
+ cflg = 0;
+
+ signal(SIGINT,cl_int);
+
+/* Here we handle different "Command Line Personalities" */
+
+#ifdef TCPSOCKET
+#ifndef NOHTTP
+ if (howcalled == I_AM_HTTP) { /* If I was called as HTTP... */
+ char rdns[128];
+#ifdef OS2
+ char * agent = "Kermit 95";
+#else
+ char * agent = "C-Kermit";
+#endif /* OS2 */
+
+ debug(F100,"http personality","",0);
+#ifdef CK_URL
+ if (haveurl) {
+ int type;
+ char * lfile;
+
+ type = lookup(urltab,g_url.svc,nurltab,NULL);
+ if (!(type == URL_HTTP || type == URL_HTTPS)) {
+ printf("?Internal Error: HTTP command line processing\n");
+ debug(F100,"Error: HTTP command line processing","",0);
+ doexit(BAD_EXIT,1);
+ }
+ rdns[0] = '\0';
+ lfile = "";
+ x = (http_open(g_url.hos,g_url.por ? g_url.por : g_url.svc,
+ type == URL_HTTPS, rdns,128,NULL) == 0);
+ if (x) {
+#ifdef KUI
+ char asname[CKMAXPATH+1];
+#endif /* KUI */
+ if (!quiet) {
+ if (rdns[0])
+ printf("Connected to %s [%s]\r\n",g_url.hos,rdns);
+ else
+ printf("Connected to %s\r\n",g_url.hos);
+ }
+ if (g_url.pth)
+ zstrip(g_url.pth,&lfile);
+ else
+ g_url.pth = "/";
+
+ if (!*lfile)
+ lfile = "index.html";
+
+#ifdef KUI
+ if (uq_file(NULL, /* K95 GUI: Put up file box. */
+ NULL, /* (not tested...) */
+ 4,
+ NULL,
+ lfile,
+ asname,
+ CKMAXPATH+1
+ ) > 0)
+ lfile = asname;
+#endif /* KUI */
+
+ x = http_get(agent,
+ NULL, /* hdrlist */
+ g_url.usr,
+ g_url.psw,
+ 0,
+ lfile,
+ g_url.pth,
+ 0 /* stdio */
+ );
+ x = (http_close() == 0);
+ } else {
+ if (!quiet)
+ printf("?HTTP Connection failed.\r\n");
+ }
+ doexit(x ? GOOD_EXIT : BAD_EXIT, -1);
+ } else
+#endif /* CK_URL */
+ {
+ int http_action = 0;
+ char * host = NULL, * svc = NULL, * lpath = NULL;
+ char * user = NULL, * pswd = NULL, * path = NULL;
+ char * xp;
+
+ while (--xargc > 0) { /* Go through command line words */
+ xargv++;
+ debug(F111,"cmdlin http xargv",*xargv,xargc);
+ xp = *xargv+1;
+ if (**xargv == '-') { /* Got an option */
+ int xx;
+ x = *(*xargv+1); /* Get the option letter */
+ switch (x) {
+ case 'd': /* Debug */
+#ifdef DEBUG
+ if (deblog) {
+ debtim = 1;
+ } else {
+ deblog = debopn("debug.log",0);
+ }
+#endif /* DEBUG */
+ break;
+ case 'S': /* Stay */
+ case 'Y': /* No initialization file */
+ break; /* (already done in prescan) */
+ case 'q': /* Quiet */
+ quiet = 1;
+ break;
+ case 'u': /* Options that require arguments */
+ case 'P':
+ case 'g':
+ case 'p':
+ case 'H':
+ case 'l':
+ if (*(xp+1)) {
+ XFATAL("Invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("Missing argument");
+ }
+ switch (x) {
+ case 'u':
+ user = *xargv;
+ break;
+ case 'P':
+ pswd = *xargv;
+ break;
+ case 'l':
+ if (http_action != HTTP_PUT)
+ lpath = *xargv;
+ break;
+ case 'g':
+ http_action = HTTP_GET;
+ path = *xargv;
+ debug(F111,"cmdlin http GET",path,http_action);
+ break;
+ case 'p':
+ http_action = HTTP_PUT;
+ path = *xargv;
+ break;
+ case 'H':
+ http_action = HTTP_HED;
+ path = *xargv;
+ }
+ break;
+
+#ifdef CK_SSL
+ case 'z': {
+ /* *xargv contains a value of the form tag=value */
+ /* we need to lookup the tag and save the value */
+ int x,y,z;
+ char * p, * q;
+ makestr(&p,*xargv);
+ y = ckindex("=",p,0,0,1);
+ if (y > 0)
+ p[y-1] = '\0';
+ x = lookup(httpztab,p,nhttpztab,&z);
+ if (x < 0) {
+ printf("?Invalid security option: \"%s\"\n",p);
+ } else {
+ printf("Security option: \"%s",p);
+ if (httpztab[z].flgs & CM_ARG) {
+ q = &p[y];
+ if (!*q)
+ fatal("?Missing required value");
+ }
+ /* -z options w/args */
+ switch (httpztab[z].kwval) {
+ case HT_CERTFI:
+ makestr(&ssl_rsa_cert_file,q);
+ break;
+ case HT_OKCERT:
+ ssl_certsok_flag = 1;
+ break;
+ case HT_KEY:
+ makestr(&ssl_rsa_key_file,q);
+ break;
+ case HT_SECURE:
+ svc="https";
+ break;
+ case HT_VERIFY:
+ if (!rdigits(q))
+ printf("?Bad number: %s\n",q);
+ ssl_verify_flag = atoi(q);
+ break;
+ }
+ }
+ free(p);
+ break;
+ }
+#endif /* CK_SSL */
+
+ case 'h': /* Help */
+ default:
+ printf("Usage: %s host [ options... ]\n",xarg0);
+ conola(http_hlp);
+ doexit(GOOD_EXIT,-1);
+ }
+ } else { /* No dash - must be hostname */
+ host = *xargv;
+ if (xargc > 1) {
+ svc = *(xargv+1);
+ if (svc) if (*svc == '-' || !*svc)
+ svc = NULL;
+ if (svc) {
+ xargv++;
+ xargc--;
+ }
+ }
+ }
+ }
+ if (!svc) svc = "";
+ if (!*svc) svc = "http";
+ if (!host) XFATAL("No http host given");
+
+ /* Check action args before opening the connection */
+ if (http_action) {
+ if (http_action == HTTP_PUT) {
+ if (!lpath)
+ XFATAL("No local path for http PUT");
+ }
+ if (!path)
+ XFATAL("No remote path for http action");
+ }
+ /* Now it's OK to open the connection */
+ rdns[0] = NUL;
+ x = (http_open(host,
+ svc,!ckstrcmp("https",svc,-1,0),rdns,128,NULL
+ ) == 0);
+ if (!x) {
+ if (!quiet)
+ printf("?HTTP Connection failed.\r\n");
+ doexit(BAD_EXIT,-1);
+ }
+ if (!quiet) {
+ if (rdns[0])
+ printf("Connected to %s [%s]\r\n",host,rdns);
+ else
+ printf("Connected to %s\r\n",host);
+ }
+ if (http_action) {
+ int pcpy = 0;
+ if (http_action != HTTP_PUT) { /* Supply default */
+ if (!lpath) { /* local path... */
+ zstrip(path,&lpath);
+ if (!lpath)
+ lpath = "";
+ if (!*lpath)
+ lpath = "index.html";
+ }
+ }
+ if (*path != '/') {
+ char * p = (char *) malloc(strlen(path)+2);
+ if (!p) fatal("?Memory allocation error\n");
+ *p = '/';
+ strcpy(&p[1],path); /* safe */
+ path = p;
+ pcpy = 1;
+ }
+ switch (http_action) {
+ case HTTP_GET:
+ x = http_get(agent,NULL,user,pswd,0,lpath,path,0);
+ break;
+
+ case HTTP_PUT:
+ x = http_put(agent,NULL,"text/HTML",
+ user,pswd,0,lpath,path,NULL,0);
+ break;
+
+ case HTTP_HED:
+ x = http_head(agent,NULL,user,pswd,0,lpath,path,0);
+ break;
+ }
+ debug(F101,"cmdline http result","",x);
+ x = (http_close() == 0);
+ if (pcpy) free(path);
+ doexit(x ? GOOD_EXIT : BAD_EXIT, -1);
+ }
+ return(0);
+ }
+ } else
+#endif /* NOHTTP */
+#ifdef NEWFTP
+ if (howcalled == I_AM_FTP) { /* If I was called as FTP... */
+ debug(F100,"ftp personality","",0);
+#ifdef CK_URL
+ if (haveurl)
+ doftparg('U');
+ else
+#endif /* CK_URL */
+ {
+ while (--xargc > 0) { /* Go through command line words */
+ xargv++;
+ debug(F111,"cmdlin ftp xargv",*xargv,xargc);
+ if (**xargv == '-') { /* Got an option */
+ int xx;
+ x = *(*xargv+1); /* Get the option letter */
+ xx = doftparg(x);
+ if (xx < 0) {
+ if (what == W_COMMAND)
+ return(0);
+ else
+ doexit(BAD_EXIT,1);
+ }
+ } else { /* No dash - must be hostname */
+ makestr(&ftp_host,*xargv);
+ if (xargc > 1) {
+ port = *(xargv+1);
+ if (port) if (*port == '-' || !*port)
+ port = NULL;
+ if (port) {
+ xargv++;
+ xargc--;
+ }
+ }
+ debug(F110,"cmdlin ftp host",ftp_host,0);
+ debug(F110,"cmdlin ftp port",port,0);
+ }
+ } /* while */
+ } /* if (haveurl) */
+
+ if (ftp_host) {
+ int xx;
+#ifdef NODIAL
+ xx = xx_ftp(ftp_host,port);
+ if (xx < 0 && (haveurl || ftp_cmdlin > 1)) doexit(BAD_EXIT,-1);
+#else
+#ifdef NOICP
+ xx = xx_ftp(ftp_host,port);
+ if (xx < 0 && (haveurl || ftp_cmdlin > 1)) doexit(BAD_EXIT,-1);
+#else
+ if (*ftp_host == '=') { /* Skip directory lookup */
+ xx = xx_ftp(&ftp_host[1],port);
+ if (xx < 0 && (haveurl || ftp_cmdlin > 1))
+ doexit(BAD_EXIT,-1);
+ } else { /* Want lookup */
+ int i;
+ nhcount = 0; /* Check network directory */
+ debug(F101,"cmdlin nnetdir","",nnetdir);
+ if (nnetdir > 0) /* If there is a directory... */
+ lunet(ftp_host); /* Look up the name */
+ else /* If no directory */
+ nhcount = 0; /* we didn't find anything there */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmdlin lunet nhcount","",nhcount);
+ if (nhcount > 0) {
+ debug(F110,"cmdlin lunet nh_p[0]",nh_p[0],0);
+ debug(F110,"cmdlin lunet nh_p2[0]",nh_p2[0],0);
+ debug(F110,"cmdlin lunet nh_px[0][0]",
+ nh_px[0][0],0);
+ }
+ }
+#endif /* DEBUG */
+ if (nhcount == 0) {
+ xx = xx_ftp(ftp_host,port);
+ if (xx < 0 && (haveurl || ftp_cmdlin > 1))
+ doexit(BAD_EXIT,-1);
+ } else {
+ for (i = 0; i < nhcount; i++) {
+ if (ckstrcmp(nh_p2[i],"tcp/ip",6,0))
+ continue;
+ makestr(&ftp_host,nh_p[i]);
+ debug(F110,"cmdlin calling xx_ftp",ftp_host,0);
+ if (!quiet)
+ printf("Trying %s...\n",ftp_host);
+ if (xx_ftp(ftp_host,port) > -1)
+ break;
+ }
+ }
+ }
+#endif /* NODIAL */
+#endif /* NOICP */
+ if (!ftpisconnected())
+ doexit(BAD_EXIT,-1);
+ }
+ return(0);
+ }
+#endif /* NEWFTP */
+
+#ifdef TNCODE
+ if (howcalled == I_AM_TELNET) { /* If I was called as Telnet... */
+
+ while (--xargc > 0) { /* Go through command line words */
+ xargv++;
+ debug(F111,"cmdlin telnet xargv",*xargv,xargc);
+ if (**xargv == '=')
+ return(0);
+ if (!strcmp(*xargv,"--")) /* getopt() conformance */
+ return(0);
+#ifdef VMS
+ else if (**xargv == '/')
+ continue;
+#endif /* VMS */
+ else if (**xargv == '-') { /* Got an option (begins with dash) */
+ int xx;
+ x = *(*xargv+1); /* Get the option letter */
+ debug(F111,"cmdlin telnet args 1",*xargv,xargc);
+ xx = dotnarg(x);
+ debug(F101,"cmdlin telnet doarg","",xx);
+ debug(F111,"cmdlin telnet args 2",*xargv,xargc);
+ if (xx < 0) {
+#ifndef NOICP
+ if (what == W_COMMAND)
+ return(0);
+ else
+#endif /* NOICP */
+ {
+#ifdef OS2
+ sleep(1); /* Give it a chance... */
+#endif /* OS2 */
+ doexit(BAD_EXIT,1); /* Go handle option */
+ }
+ }
+ } else { /* No dash must be hostname */
+ ckstrncpy(ttname,*xargv,TTNAMLEN+1);
+ debug(F110,"cmdlin telnet host",ttname,0);
+
+#ifndef NOICP
+#ifndef NODIAL
+ nhcount = 0; /* Check network directory */
+ debug(F101,"cmdlin telnet nnetdir","",nnetdir);
+ if (nnetdir > 0) /* If there is a directory... */
+ lunet(*xargv); /* Look up the name */
+ else /* If no directory */
+ nhcount = 0; /* we didn't find anything there */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmdlin telnet lunet nhcount","",nhcount);
+ if (nhcount > 0) {
+ debug(F110,"cmdlin telnet lunet nh_p[0]",nh_p[0],0);
+ debug(F110,"cmdlin telnet lunet nh_p2[0]",nh_p2[0],0);
+ debug(F110,"cmdlin telnet lunet nh_px[0][0]",
+ nh_px[0][0],0);
+ }
+ }
+#endif /* DEBUG */
+ if (nhcount > 0 && nh_p2[0]) /* If network type specified */
+ if (ckstrcmp(nh_p2[0],"tcp/ip",6,0)) /* it must be TCP/IP */
+ nhcount = 0;
+ if (nhcount == 1) { /* Still OK, so make substitution */
+ ckstrncpy(ttname,nh_p[0],TTNAMLEN+1);
+ debug(F110,"cmdlin telnet lunet substitution",ttname,0);
+ }
+#endif /* NODIAL */
+#endif /* NOICP */
+
+ if (--xargc > 0 && !haveurl) { /* Service from command line? */
+ xargv++;
+ ckstrncat(ttname,":",TTNAMLEN+1);
+ ckstrncat(ttname,*xargv,TTNAMLEN+1);
+ debug(F110,"cmdlin telnet host2",ttname,0);
+ }
+#ifndef NOICP
+#ifndef NODIAL
+ else if (nhcount) { /* No - how about in net directory? */
+ if (nh_px[0][0]) {
+ ckstrncat(ttname,":",TTNAMLEN+1);
+ ckstrncat(ttname,nh_px[0][0],TTNAMLEN+1);
+ }
+ }
+#endif /* NODIAL */
+#endif /* NOICP */
+ local = 1; /* Try to open the connection */
+ nettype = NET_TCPB;
+ mdmtyp = -nettype;
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) {
+ XFATAL("can't open host connection");
+ }
+ network = 1; /* It's open */
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+#ifndef NOXFER
+ reliable = 1; /* It's reliable */
+ xreliable = 1; /* ... */
+ setreliable = 1;
+#endif /* NOXFER */
+ cflg = 1; /* Connect */
+ stayflg = 1; /* Stay */
+ tn_exit = 1; /* Telnet-like exit condition */
+ quiet = 1;
+ exitonclose = 1; /* Exit when connection closes */
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+ break;
+ }
+ }
+ return(0);
+ }
+#endif /* TNCODE */
+#ifdef RLOGCODE
+ else if (howcalled == I_AM_RLOGIN) { /* If I was called as Rlogin... */
+ while (--xargc > 0) { /* Go through command line words */
+ xargv++;
+ debug(F111,"cmdlin rlogin xargv",*xargv,xargc);
+ if (**xargv == '=')
+ return(0);
+ if (!strcmp(*xargv,"--")) /* getopt() conformance */
+ return(0);
+#ifdef VMS
+ else if (**xargv == '/')
+ continue;
+#endif /* VMS */
+ else if (**xargv == '-') { /* Got an option (begins with dash) */
+ int xx;
+ x = *(*xargv+1); /* Get the option letter */
+ debug(F111,"cmdlin rlogin args 1",*xargv,xargc);
+ xx = dorlgarg(x);
+ debug(F101,"cmdlin rlogin doarg","",xx);
+ debug(F111,"cmdlin rlogin args 2",*xargv,xargc);
+ if (xx < 0) {
+#ifndef NOICP
+ if (what == W_COMMAND)
+ return(0);
+ else
+#endif /* NOICP */
+ {
+#ifdef OS2
+ sleep(1); /* Give it a chance... */
+#endif /* OS2 */
+ doexit(BAD_EXIT,1); /* Go handle option */
+ }
+ }
+ } else { /* No dash must be hostname */
+ ckstrncpy(ttname,*xargv,TTNAMLEN+1);
+ debug(F110,"cmdlin rlogin host",ttname,0);
+
+#ifndef NOICP
+#ifndef NODIAL
+ nhcount = 0; /* Check network directory */
+ debug(F101,"cmdlin rlogin nnetdir","",nnetdir);
+ if (nnetdir > 0) /* If there is a directory... */
+ lunet(*xargv); /* Look up the name */
+ else /* If no directory */
+ nhcount = 0; /* we didn't find anything there */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmdlin rlogin lunet nhcount","",nhcount);
+ if (nhcount > 0) {
+ debug(F110,"cmdlin rlogin lunet nh_p[0]",nh_p[0],0);
+ debug(F110,"cmdlin rlogin lunet nh_p2[0]",nh_p2[0],0);
+ debug(F110,"cmdlin rlogin lunet nh_px[0][0]",
+ nh_px[0][0],0);
+ }
+ }
+#endif /* DEBUG */
+ if (nhcount > 0 && nh_p2[0]) /* If network type specified */
+ if (ckstrcmp(nh_p2[0],"tcp/ip",6,0)) /* it must be TCP/IP */
+ nhcount = 0;
+ if (nhcount == 1) { /* Still OK, so make substitution */
+ ckstrncpy(ttname,nh_p[0],TTNAMLEN+1);
+ debug(F110,"cmdlin rlogin lunet substitution",ttname,0);
+ }
+#endif /* NODIAL */
+#endif /* NOICP */
+
+ if (!haveurl) { /* Service from command line? */
+ ckstrncat(ttname,":login",TTNAMLEN+1);
+ debug(F110,"cmdlin rlogin host2",ttname,0);
+ }
+ local = 1; /* Try to open the connection */
+ nettype = NET_TCPB;
+ mdmtyp = -nettype;
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) {
+ XFATAL("can't open host connection");
+ }
+ network = 1; /* It's open */
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+#ifndef NOXFER
+ reliable = 1; /* It's reliable */
+ xreliable = 1; /* ... */
+ setreliable = 1;
+#endif /* NOXFER */
+ cflg = 1; /* Connect */
+ stayflg = 1; /* Stay */
+ tn_exit = 1; /* Telnet-like exit condition */
+ quiet = 1;
+ exitonclose = 1; /* Exit when connection closes */
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+ break;
+ }
+ }
+ return(0);
+ }
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+
+#ifdef SSHBUILTIN
+ if (howcalled == I_AM_SSH) { /* If I was called as SSH... */
+ extern char * ssh_hst, * ssh_cmd, * ssh_prt;
+ debug(F100,"ssh personality","",0);
+#ifdef CK_URL
+ if (haveurl) {
+ makestr(&ssh_hst,g_url.hos);
+ makestr(&ssh_prt,g_url.svc);
+ ckstrncpy(ttname,ssh_hst,TTNAMLEN+1);
+ ckstrncat(ttname,":",TTNAMLEN+1);
+ ckstrncat(ttname,ssh_prt,TTNAMLEN+1);
+ }
+ else
+#endif /* CK_URL */
+ {
+ while (--xargc > 0) { /* Go through command line words */
+ xargv++;
+ debug(F111,"cmdlin ssh xargv",*xargv,xargc);
+ if (**xargv == '=')
+ return(0);
+ if (!strcmp(*xargv,"--")) /* getopt() conformance */
+ return(0);
+#ifdef VMS
+ else if (**xargv == '/')
+ continue;
+#endif /* VMS */
+ /* Got an option (begins with dash) */
+ else if (**xargv == '-') {
+ int xx;
+ x = *(*xargv+1); /* Get the option letter */
+ debug(F111,"cmdlin args 1",*xargv,xargc);
+ xx = dossharg(x);
+ debug(F101,"cmdlin doarg","",xx);
+ debug(F111,"cmdlin args 2",*xargv,xargc);
+ if (xx < 0) {
+#ifndef NOICP
+ if (what == W_COMMAND)
+ return(0);
+ else
+#endif /* NOICP */
+ {
+#ifdef OS2
+ sleep(1); /* Give it a chance... */
+#endif /* OS2 */
+ doexit(BAD_EXIT,1); /* Go handle option */
+ }
+ }
+ } else { /* No dash must be hostname */
+ ckstrncpy(ttname,*xargv,TTNAMLEN+1);
+ makestr(&ssh_hst,ttname);
+ debug(F110,"cmdlin ssh host",ttname,0);
+#ifndef NOICP
+#ifndef NODIAL
+ nhcount = 0; /* Check network directory */
+ debug(F101,"cmdlin nnetdir","",nnetdir);
+ if (nnetdir > 0) /* If there is a directory... */
+ lunet(*xargv); /* Look up the name */
+ else /* If no directory */
+ nhcount = 0; /* we didn't find anything there */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"cmdlin lunet nhcount","",nhcount);
+ if (nhcount > 0) {
+ debug(F110,"cmdlin lunet nh_p[0]",nh_p[0],0);
+ debug(F110,"cmdlin lunet nh_p2[0]",nh_p2[0],0);
+ debug(F110,
+ "cmdlin lunet nh_px[0][0]",nh_px[0][0],0);
+ }
+ }
+#endif /* DEBUG */
+ /* If network type specified */
+ /* it must be TCP/IP */
+ if (nhcount > 0 && nh_p2[0])
+ if (ckstrcmp(nh_p2[0],"tcp/ip",6,0))
+ nhcount = 0;
+ if (nhcount == 1) { /* Still OK, so make substitution */
+ ckstrncpy(ttname,nh_p[0],TTNAMLEN+1);
+ makestr(&ssh_hst,ttname);
+ debug(F110,"cmdlin lunet substitution",ttname,0);
+ }
+#endif /* NODIAL */
+#endif /* NOICP */
+ /* Service from command line? */
+ if (--xargc > 0 && !haveurl) {
+ xargv++;
+ ckstrncat(ttname,":",TTNAMLEN+1);
+ ckstrncat(ttname,*xargv,TTNAMLEN+1);
+ makestr(&ssh_prt,*xargv);
+ debug(F110,"cmdlin telnet host2",ttname,0);
+ }
+#ifdef COMMENT
+ /* Do not substitute net dir service for ssh port */
+#ifndef NOICP
+#ifndef NODIAL
+ /* No - how about in net directory? */
+ else if (nhcount) {
+ if (nh_px[0][0]) {
+ ckstrncat(ttname,":",TTNAMLEN+1);
+ ckstrncat(ttname,nh_px[0][0],TTNAMLEN+1);
+ makestr(&ssh_prt,nh_px[0][0]);
+ }
+ }
+
+#endif /* NODIAL */
+#endif /* NOICP */
+#endif /* COMMENT */
+ break;
+ }
+ }
+ }
+ local = 1; /* Try to open the connection */
+ nettype = NET_SSH;
+ mdmtyp = -nettype;
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) {
+ XFATAL("can't open host connection");
+ }
+ network = 1; /* It's open */
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+#ifndef NOXFER
+ reliable = 1; /* It's reliable */
+ xreliable = 1; /* ... */
+ setreliable = 1;
+#endif /* NOXFER */
+ cflg = 1; /* Connect */
+ stayflg = 1; /* Stay */
+ tn_exit = 1; /* Telnet-like exit condition */
+ quiet = 1;
+ exitonclose = 1; /* Exit when connection closes */
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+ return(0);
+ }
+#endif /* SSHBUILTIN */
+
+ if (howcalled == I_AM_SSHSUB)
+ return(0);
+
+/*
+ From here down: We were called as "kermit" or "iksd".
+
+ If we were started directly from a Kermit script file,
+ the filename of the script is in argv[1], so skip past it.
+*/
+ if (xargc > 1) {
+ int n = 1;
+ if (*xargv[1] != '-') {
+
+#ifdef KERBANG
+ /* If we were started with a Kerbang script, the script */
+ /* arguments were already picked up in prescan / cmdini() */
+ /* and there is nothing here for us anyway. */
+ if (!strcmp(xargv[1],"+"))
+ return(0);
+#endif /* KERBANG */
+
+ if (cfilef) { /* Command file found in prescan() */
+ xargc -= n; /* Skip past it */
+ xargv += n;
+ cfilef = 0;
+ debug(F101,"cmdlin cfilef set to 0","",cfilef);
+ }
+ }
+ }
+/*
+ Regular Unix-style command line parser, mostly conforming with 'A Proposed
+ Command Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World,
+ Vol.1, No.3, 1984.
+*/
+ while (--xargc > 0) { /* Go through command line words */
+ xargv++;
+ debug(F111,"cmdlin xargv",*xargv,xargc);
+ if (**xargv == '=')
+ return(0);
+ if (!strcmp(*xargv,"--")) /* getopt() conformance */
+ return(0);
+#ifdef VMS
+ else if (**xargv == '/')
+ continue;
+#endif /* VMS */
+ else if (**xargv == '-') { /* Got an option (begins with dash) */
+ int xx;
+ x = *(*xargv+1); /* Get the option letter */
+ debug(F111,"cmdlin args 1",*xargv,xargc);
+ xx = doarg(x);
+ debug(F101,"cmdlin doarg","",xx);
+ debug(F111,"cmdlin args 2",*xargv,xargc);
+ if (xx < 0) {
+#ifndef NOICP
+ if (what == W_COMMAND)
+ return(0);
+ else
+#endif /* NOICP */
+ {
+#ifdef OS2
+ sleep(1); /* Give it a chance... */
+#endif /* OS2 */
+ doexit(BAD_EXIT,1); /* Go handle option */
+ }
+ }
+ } else if (!haveurl) { /* No dash where expected */
+ char xbuf[32];
+ char buf[128];
+ int k;
+ k = ckstrncpy(xbuf,*xargv,40);
+ if (k > 30) {
+ xbuf[30] = '.';
+ xbuf[29] = '.';
+ xbuf[28] = '.';
+ }
+ xbuf[31] = NUL;
+ ckmakmsg(buf,
+ 128,
+ "invalid command-line option, type \"",
+ myname,
+ " -h\" for help",
+ NULL
+ );
+ fatal2(xbuf,buf);
+ }
+ }
+#ifdef DEBUG
+ if (deblog) {
+#ifndef NOICP
+ debug(F101,"cmdlin what","",what);
+#endif /* NOICP */
+ debug(F101,"cmdlin action","",action);
+#ifndef NOXFER
+ debug(F101,"cmdlin stdouf","",stdouf);
+#endif /* NOXFER */
+ }
+#endif /* DEBUG */
+
+#ifdef NOICP
+ if (!action && !cflg && !cnflg) {
+ debug(F100,"cmdlin NOICP fatal no action","",0);
+ XFATAL("?No actions specified on command line");
+ }
+#else
+ if (inserver && what == 0) { /* Internet Kermit server checks */
+ if (local || (action != 0 && action != 'x')) {
+ if (local)
+ printf("local\r\n");
+ if (action)
+ printf("action=%c\r\n",action);
+ debug(F100,"cmdlin fatal 1","",0);
+ XFATAL("No actions or connections allowed with -A");
+ }
+ }
+#endif /* NOICP */
+
+#ifndef NOLOCAL
+ if (!local) {
+ if ((action == 'c') || (cflg != 0)) {
+ debug(F100,"cmdlin fatal 2","",0);
+ XFATAL("-l or -j or -X required");
+ }
+ }
+#endif /* NOLOCAL */
+#ifndef NOXFER
+ if (*cmarg2 != 0) {
+ if ((action != 's') && (action != 'r') && (action != 'v')) {
+ debug(F100,"cmdlin fatal 3","",0);
+ XFATAL("-a without -s, -r, or -g");
+ }
+ if (action == 'r' || action == 'v') {
+#ifdef CK_TMPDIR
+ if (isdir(cmarg2)) { /* -a is a directory */
+ if (!zchdir(cmarg2)) { /* try to change to it */
+ debug(F100,"cmdlin fatal 4","",0);
+ XFATAL("can't change to '-a' directory");
+ } else cmarg2 = "";
+ } else
+#endif /* CK_TMPDIR */
+ if (zchko(cmarg2) < 0) {
+ debug(F100,"cmdlin fatal 5","",0);
+ XFATAL("write access to -a file denied");
+ }
+ }
+ }
+ if ((action == 'v') && (stdouf) && (!local)) {
+ if (is_a_tty(1)) {
+ debug(F100,"cmdlin fatal 6","",0);
+ XFATAL("unredirected -k can only be used in local mode");
+ }
+ }
+ if ((action == 's') || (action == 'v') ||
+ (action == 'r') || (action == 'x')) {
+ if (local)
+ displa = 1;
+ if (stdouf) {
+ displa = 0;
+ quiet = 1;
+ }
+ }
+ if (quiet) displa = 0; /* No display if quiet requested */
+#endif /* NOXFER */
+#ifdef DEBUG
+ if (action)
+ debug(F000,"cmdlin returns action","",action);
+ else
+ debug(F101,"cmdlin returns action","",action);
+#endif /* DEBUG */
+
+ return(action); /* Then do any requested protocol */
+}
+
+/* Extended argument parsing: --keyword[:value] (or =value) */
+
+/*
+ XA_xxxx symbols are defined in ckuusr.h.
+ If you add a new one, also remember to update doshow(),
+ SHXOPT section, in ckuus5.c.
+*/
+struct keytab xargtab[] = {
+#ifdef CK_LOGIN
+ { "anonymous", XA_ANON, CM_ARG|CM_PRE },
+#endif /* CK_LOGIN */
+ { "bannerfile", XA_BAFI, CM_ARG },
+ { "cdfile", XA_CDFI, CM_ARG },
+ { "cdmessage", XA_CDMS, CM_ARG },
+ { "cdmsg", XA_CDMS, CM_ARG|CM_INV },
+#ifdef KUI
+ { "changedim", XA_CHGD, CM_PRE },
+#endif /* KUI */
+#ifndef NOCSETS
+ { "charset", XA_CSET, CM_ARG|CM_PRE },
+#endif /* NOCSETS */
+#ifdef IKSDB
+ { "database", XA_DBAS, CM_ARG|CM_PRE },
+ { "dbfile", XA_DBFI, CM_ARG|CM_PRE },
+#endif /* IKSDB */
+#ifdef KUI
+ { "facename", XA_FNAM, CM_ARG|CM_PRE|CM_INV },
+ { "fontname", XA_FNAM, CM_ARG|CM_PRE },
+ { "fontsize", XA_FSIZ, CM_ARG|CM_PRE },
+#endif /* KUI */
+#ifdef COMMENT
+#ifdef NEWFTP
+ { "ftp", XA_FTP, CM_ARG },
+#endif /* NEWFTP */
+#endif /* COMMENT */
+#ifndef NOLOCAL
+#ifdef OS2
+ { "height", XA_ROWS, CM_ARG|CM_PRE },
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ { "help", XA_HELP, 0 },
+#ifndef NOHELP
+ { "helpfile", XA_HEFI, CM_ARG },
+#endif /* NOHELP */
+#ifdef CK_LOGIN
+ { "initfile", XA_ANFI, CM_ARG|CM_PRE },
+#endif /* CK_LOGIN */
+#ifdef OS2
+ { "lockdown", XA_LOCK, CM_PRE },
+#ifdef KUI
+ { "maximize", XA_WMAX, CM_PRE },
+ { "minimize", XA_WMIN, CM_PRE },
+ { "nobars", XA_NOBAR, CM_PRE },
+ { "noclose" , XA_NOCLOSE, CM_PRE },
+#endif /* KUI */
+ { "noescape", XA_NOESCAPE, CM_PRE },
+#endif /* OS2 */
+ { "nointerrupts",XA_NOIN, CM_PRE },
+#ifdef KUI
+ { "nomenubar", XA_NOMN, CM_PRE },
+#endif /* KUI */
+ { "noperms", XA_NPRM, 0 },
+#ifndef NOPUSH
+ { "nopush", XA_NOPUSH, CM_PRE },
+#endif /* NOPUSH */
+#ifdef OS2
+ { "noscroll", XA_NOSCROLL, CM_PRE },
+#endif /* OS2 */
+#ifdef KUI
+ { "nostatusbar", XA_NOSB, CM_PRE },
+ { "notoolbar", XA_NOTB, CM_PRE },
+#endif /* KUI */
+#ifdef COMMENT
+ { "password", XA_PASS, CM_ARG|CM_INV },
+#endif /* COMMENT */
+#ifdef CK_LOGIN
+#ifndef NOXFER
+#ifdef CK_PERM
+ { "permissions", XA_PERM, CM_ARG|CM_PRE },
+ { "perms", XA_PERM, CM_ARG|CM_PRE|CM_INV },
+#endif /* CK_PERM */
+#endif /* NOXFER */
+#ifdef UNIX
+ { "privid", XA_PRIV, CM_ARG|CM_PRE },
+#endif /* UNIX */
+#ifndef NOLOCAL
+#ifndef NOCSETS
+ { "rcharset", XA_CSET, CM_ARG|CM_PRE|CM_INV },
+#endif /* NOCSETS */
+#endif /* NOLOCAL */
+#ifdef UNIX
+ { "root", XA_ROOT, CM_ARG|CM_PRE },
+#else /* UNIX */
+#ifdef CKROOT
+ { "root", XA_ROOT, CM_ARG|CM_PRE },
+#endif /* CKROOT */
+#endif /* UNIX */
+#ifdef KUI
+ { "scalefont", XA_SCALE, CM_PRE },
+#endif /* KUI */
+#ifdef COMMENT
+#ifdef SSHBUILTIN
+ { "ssh", XA_SSH, CM_ARG },
+#endif /* SSHBUILTIN */
+#endif /* COMMENT */
+#ifdef CKSYSLOG
+ { "syslog", XA_SYSL, CM_ARG|CM_PRE },
+#endif /* CKSYSLOG */
+#ifndef NOLOCAL
+#ifdef COMMENT
+#ifdef TNCODE
+ { "telnet", XA_TEL, CM_ARG },
+#endif /* TNCODE */
+#endif /* COMMENT */
+ { "termtype", XA_TERM, CM_ARG|CM_PRE },
+#endif /* NOLOCAL */
+ { "timeout", XA_TIMO, CM_ARG|CM_PRE },
+#ifndef NOLOCAL
+#ifdef OS2
+ { "title", XA_TITL, CM_ARG },
+#endif /* OS2 */
+#ifdef UNIX
+ { "unbuffered", XA_UNBUF, 0 },
+#endif /* UNIX */
+#ifndef NOSPL
+ { "user", XA_USER, CM_ARG },
+#endif /* NOSPL */
+#endif /* NOLOCAL */
+ { "userfile", XA_USFI, CM_ARG|CM_PRE },
+ { "version", XA_VERS, 0 },
+#ifndef NOLOCAL
+#ifdef OS2
+ { "width", XA_COLS, CM_ARG|CM_PRE },
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CKWTMP
+ { "wtmpfile", XA_WTFI, CM_ARG|CM_PRE },
+ { "wtmplog", XA_WTMP, CM_ARG|CM_PRE },
+#endif /* CKWTMP */
+#endif /* CK_LOGIN */
+ { "xferfile", XA_IKFI, CM_ARG|CM_PRE },
+ { "xferlog", XA_IKLG, CM_ARG|CM_PRE },
+#ifndef NOLOCAL
+#ifdef KUI
+ { "xpos", XA_XPOS, CM_ARG|CM_PRE },
+ { "ypos", XA_YPOS, CM_ARG|CM_PRE },
+#endif /* KUI */
+#endif /* NOLOCAL */
+ {"", 0, 0 }
+};
+int nxargs = sizeof(xargtab)/sizeof(struct keytab) - 1;
+
+static struct keytab oktab[] = {
+ { "0", 0, 0 },
+ { "1", 1, 0 },
+ { "2", 2, 0 },
+ { "3", 3, 0 },
+ { "4", 4, 0 },
+ { "5", 5, 0 },
+ { "6", 6, 0 },
+ { "7", 7, 0 },
+ { "8", 8, 0 },
+ { "9", 9, 0 },
+ { "false", 0, 0 },
+ { "no", 0, 0 },
+ { "off", 0, 0 },
+ { "ok", 1, 0 },
+ { "on", 1, 0 },
+ { "true", 1, 0 },
+ { "yes", 1, 0 }
+};
+static int noktab = sizeof(oktab)/sizeof(struct keytab);
+
+#define XARGBUFL 32
+
+char * xopthlp[XA_MAX+1]; /* Extended option help */
+char * xarghlp[XA_MAX+1]; /* Extended argument for option */
+
+static VOID
+inixopthlp() {
+ int i, j;
+ for (i = 0; i <= XA_MAX; i++) { /* Initialize all to null */
+ xopthlp[i] = NULL;
+ xarghlp[i] = NULL;
+ }
+ for (i = 0; i < nxargs; i++) { /* Then for each defined keyword */
+ j = xargtab[i].kwval; /* index by associated value */
+ if (j < 0 || j > XA_MAX)
+ continue;
+ switch (j) {
+#ifdef CK_LOGIN
+ case XA_ANON: /* "--anonymous" */
+ xopthlp[j] = "--anonymous:{on,off} [IKSD only]";
+ xarghlp[j] = "Whether to allow anonymous IKSD logins";
+ break;
+#ifdef UNIX
+ case XA_PRIV:
+ xopthlp[j] = "--privid:{on,off} [IKSD only]";
+ xarghlp[j] = "Whether to allow privileged IDs to login to IKSD";
+ break;
+#endif /* UNIX */
+#endif /* CK_LOGIN */
+ case XA_BAFI: /* "--bannerfile" */
+ xopthlp[j] = "--bannerfile:<filename>";
+ xarghlp[j] = "File to display upon startup or IKSD login";
+ break;
+ case XA_CDFI: /* "--cdfile" */
+ xopthlp[j] = "--cdfile:<filename>";
+ xarghlp[j] = "File to display when server changes directory";
+ break;
+ case XA_CDMS: /* "--cdmessage" */
+ xopthlp[j] = "--cdmessage:{on,off}";
+ xarghlp[j] = "Whether to display CD message file";
+ break;
+ case XA_HELP: /* "--help" */
+ xopthlp[j] = "--help";
+ xarghlp[j] = "Print this help text about extended options";
+ break;
+ case XA_HEFI: /* "--help" */
+ xopthlp[j] = "--helpfile:<filename>";
+ xarghlp[j] = "File containing custom info for HELP command";
+ break;
+ case XA_IKFI: /* "--xferfile" */
+ xopthlp[j] = "--xferfile:<filename> [IKSD only]";
+ xarghlp[j] = "Name of ftpd-like logfile.";
+ break;
+ case XA_IKLG: /* "--xferlog" */
+ xopthlp[j] = "--xferlog:{on,off} [IKSD only]";
+ xarghlp[j] = "Whether to keep an ftpd-like logfile.";
+ break;
+#ifdef CK_LOGIN
+ case XA_ANFI: /* "--initfile" */
+ xopthlp[j] = "--initfile:<filename> [IKSD only]";
+ xarghlp[j] = "Initialization file for anonymous users.";
+ break;
+#ifdef CK_PERM
+ case XA_PERM: /* "--permissions" */
+ xopthlp[j] = "--permissions:<octalnum> [IKSD only]";
+ xarghlp[j] = "Permissions for files uploaded by anonymous users.";
+ break;
+#endif /* CK_PERM */
+#ifdef UNIX
+ case XA_ROOT: /* "--root" */
+ xopthlp[j] = "--root:<directory> [IKSD only]";
+ xarghlp[j] = "File-system root for anonymous users.";
+ break;
+#else /* UNIX */
+#ifdef CKROOT
+ case XA_ROOT: /* "--root" */
+ xopthlp[j] = "--root:<directory> [IKSD only]";
+ xarghlp[j] = "File-system root for anonymous users.";
+ break;
+#endif /* CKROOT */
+#endif /* UNIX */
+#endif /* CK_LOGIN */
+#ifdef CKSYSLOG
+ case XA_SYSL: /* "--syslog" */
+ xopthlp[j] = "--syslog:<digit> [IKSD only]";
+ xarghlp[j] = "Syslog recording level, 0-6.";
+ break;
+#endif /* CKSYSLOG */
+ case XA_USFI: /* "--userfile" */
+ xopthlp[j] = "--userfile:<filename> [IKSD only]";
+ xarghlp[j] = "Forbidden user file.";
+ break;
+#ifdef CKWTMP
+ case XA_WTFI: /* "--wtmpfile" */
+ xopthlp[j] = "--wtmpfile:<filename> [IKSD only]";
+ xarghlp[j] = "Name of wtmp logfile.";
+ break;
+ case XA_WTMP: /* "--wtmplog" */
+ xopthlp[j] = "--wtmplog:{on,off} [IKSD only]";
+ xarghlp[j] = "Whether to keep a wtmp logfile.";
+ break;
+#endif /* CKWTMP */
+#ifdef CK_LOGIN
+ case XA_TIMO: /* "--timeout" */
+ xopthlp[j] = "--timeout:<seconds> [IKSD only]";
+ xarghlp[j] =
+ "How long to wait for login before closing the connection.";
+ break;
+#endif /* CK_LOGIN */
+ case XA_NOIN:
+ xopthlp[j] = "--nointerrupts";
+ xarghlp[j] = "Disable keyboard interrupts.";
+ break;
+#ifdef UNIX
+ case XA_UNBUF:
+ xopthlp[j] = "--unbuffered";
+ xarghlp[j] = "Force unbuffered console i/o.";
+ break;
+#endif /* UNIX */
+#ifdef IKSDB
+ case XA_DBAS:
+ xopthlp[j] = "--database:{on,off}";
+ xarghlp[j] = "Enable/Disable IKSD database (IKSD only)";
+ break;
+ case XA_DBFI:
+ xopthlp[j] = "--dbfile:<filename>";
+ xarghlp[j] = "Specify IKSD database file (IKSD only)";
+ break;
+#endif /* IKSDB */
+#ifdef CK_PERMS
+ case XA_NPRM:
+ xopthlp[j] = "--noperms";
+ xarghlp[j] = "Disable file-transfer Permissions attribute.";
+ break;
+#endif /* CK_PERMS */
+#ifdef KUI
+ case XA_CHGD:
+ xopthlp[j] = "--changedim";
+ xarghlp[j] = "Change Dimension on Window Resize";
+ case XA_SCALE:
+ xopthlp[j] = "--scalefont";
+ xarghlp[j] = "Scale Font on Window Resize";
+ case XA_WMAX:
+ xopthlp[j] = "--maximize";
+ xarghlp[j] = "start K95G window maximized.";
+ break;
+ case XA_WMIN:
+ xopthlp[j] = "--minimize";
+ xarghlp[j] = "start K95G window minimized.";
+ break;
+ case XA_XPOS:
+ xopthlp[j] = "--xpos:n";
+ xarghlp[j] = "X-coordinate of window position (number).";
+ break;
+ case XA_YPOS:
+ xopthlp[j] = "--ypos:n";
+ xarghlp[j] = "Y-coordinate of window position (number).";
+ break;
+ case XA_FNAM:
+ xopthlp[j] = "--fontname:s (or --facename:s)";
+ xarghlp[j] = "Font/typeface name: string with _ replacing blank.";
+ break;
+ case XA_FSIZ:
+ xopthlp[j] = "--fontsize:n";
+ xarghlp[j] = "Font point size (number).";
+ break;
+ case XA_NOMN:
+ xopthlp[j] = "--nomenubar";
+ xarghlp[j] = "No Menu Bar";
+ break;
+ case XA_NOTB:
+ xopthlp[j] = "--notoolbar";
+ xarghlp[j] = "No Tool Bar";
+ break;
+ case XA_NOSB:
+ xopthlp[j] = "--nostatusbar";
+ xarghlp[j] = "No Status Bar";
+ break;
+ case XA_NOBAR:
+ xopthlp[j] = "--nobars";
+ xarghlp[j] = "No Menu, Status, or Tool Bars";
+ break;
+#endif /* KUI */
+#ifndef NOPUSH
+ case XA_NOPUSH:
+ xopthlp[j] = "--nopush";
+ xarghlp[j] = "Disable external command execution.";
+ break;
+#endif /* NOPUSH */
+#ifdef OS2
+ case XA_LOCK:
+ xopthlp[j] = "--lockdown";
+ xarghlp[j] = "Enable all lockdown options.";
+ break;
+ case XA_NOCLOSE:
+ xopthlp[j] = "--noclose";
+ xarghlp[j] = "Disable Close Window and Menu Exit.";
+ break;
+ case XA_NOSCROLL:
+ xopthlp[j] = "--noscroll";
+ xarghlp[j] = "Disable scrollback operations.";
+ break;
+ case XA_NOESCAPE:
+ xopthlp[j] = "--noescape";
+ xarghlp[j] = "Disable escape from connect mode.";
+ break;
+ case XA_ROWS:
+ xopthlp[j] = "--height:n";
+ xarghlp[j] = "Screen height (number of rows).";
+ break;
+ case XA_COLS:
+ xopthlp[j] = "--width:n";
+ xarghlp[j] = "Screen width (number of columns).";
+ break;
+ case XA_TITL:
+ xopthlp[j] = "--title:string";
+ xarghlp[j] = "Window Title.";
+ break;
+#endif /* OS2 */
+ case XA_CSET:
+ xopthlp[j] = "--rcharset:name";
+ xarghlp[j] = "Name of remote terminal character set.";
+ break;
+ case XA_TERM:
+ xopthlp[j] = "--termtype:name";
+#ifdef OS2
+ xarghlp[j] = "Choose terminal emulation.";
+#else
+ xarghlp[j] = "Choose terminal type.";
+#endif /* OS2 */
+ break;
+ case XA_USER:
+ xopthlp[j] = "--user:name";
+#ifndef NETCONN
+ xarghlp[j] = "Username (for network login)";
+#else
+ xarghlp[j] = "Username.";
+#endif /* NETCONN */
+ break;
+ }
+ }
+}
+
+VOID
+iniopthlp() {
+ int i;
+ for (i = 0; i < 128; i++) {
+ optact[i] = 0;
+ switch(i) {
+#ifdef OS2
+ case '#': /* K95 Startup Flags */
+ opthlp[i] = "Kermit 95 Startup Flags";
+ arghlp[i] = "\n"\
+ " 1 - turn off Win95 special fixes\n"\
+ " 2 - do not load optional network dlls\n"\
+ " 4 - do not load optional tapi dlls\n"\
+ " 8 - do not load optional kerberos dlls\n"\
+ " 16 - do not load optional zmodem dlls\n"\
+ " 32 - use stdin for input instead of the console\n"\
+ " 64 - use stdout for output instead of the console\n"\
+ " 128 - do not terminate process in response to Session Logoff";
+ break;
+#endif /* OS2 */
+ case '0': /* In the middle */
+ opthlp[i] =
+ "100% transparent CONNECT mode for \"in-the-middle\" operation";
+ arghlp[i] = NULL;
+ break;
+
+ case '8':
+ opthlp[i] = "Connection is 8-bit clean";
+ arghlp[i] = NULL;
+ break;
+
+#ifdef NEWFTP
+ case '9':
+ opthlp[i] = "Make a connection to an FTP server";
+ arghlp[i] = "IP-address-or-hostname[:optional-TCP-port]";
+ break;
+#endif /* NEWFTP */
+
+#ifdef IKSD
+ case 'A':
+ opthlp[i] = "Kermit is to be started as an Internet service";
+#ifdef NT
+ arghlp[i] = " socket handle of incoming connection";
+#else /* NT */
+ arghlp[i] = NULL;
+#endif /* NT */
+ break;
+#endif /* IKSD */
+ case 'B': opthlp[i] =
+ "Kermit is running in Batch or Background (no controlling terminal)";
+ break;
+#ifndef NOSPL
+ case 'C':
+ opthlp[i] = "Interactive-mode Commands to be executed";
+ arghlp[i] = "Commands separated by commas, list in doublequotes";
+ break;
+#endif /* NOSPL */
+ case 'D':
+ opthlp[i] = "Delay before starting to send";
+ arghlp[i] = "Number of seconds";
+ break;
+ case 'E':
+ opthlp[i] = "Exit automatically when connection closes";
+ arghlp[i] = NULL;
+ break;
+#ifdef TCPSOCKET
+ case 'F':
+ opthlp[i] = "Use an existing TCP connection";
+ arghlp[i] = "Numeric file descriptor of open TCP connection";
+ break;
+#endif /* TCPSOCKET */
+ case 'G':
+ opthlp[i] = "GET from server, send to standard output";
+ arghlp[i] = "Remote file specification";
+ optact[i] = 1;
+ break;
+ case 'H':
+ opthlp[i] = "Suppress program startup Herald and greeting";
+ arghlp[i] = NULL;
+ break;
+ case 'I':
+ opthlp[i] = "Connection is reliable, streaming is allowed";
+ arghlp[i] = NULL;
+ break;
+#ifdef TCPSOCKET
+ case 'J':
+ opthlp[i] = "'Be like Telnet'";
+ arghlp[i] = "IP hostname/address optionally followed by service";
+ break;
+#endif /* TCPSOCKET */
+ case 'L':
+ opthlp[i] = "Recursive directory descent for files in -s option";
+ arghlp[i] = NULL;
+ break;
+ case 'M':
+ opthlp[i] = "My user name (for use with Telnet, Rlogin, etc)";
+ arghlp[i] = "Username string";
+ break;
+#ifdef NETBIOS
+ case 'N':
+ opthlp[i] = "NETBIOS adapter number";
+ arghlp[i] = "Number";
+ break;
+#endif /* NETBIOS */
+ case 'O': /* Be a server for One command only */
+ opthlp[i] = "Be a server for One command only";
+ arghlp[i] = NULL;
+ optact[i] = 1;
+ break;
+ case 'P':
+ opthlp[i] = "Don't convert file (Path) names";
+ arghlp[i] = NULL;
+ break;
+ case 'Q':
+ opthlp[i] = "Quick (FAST) Kermit protocol settings";
+ arghlp[i] = NULL;
+ break;
+ case 'R': /* Remote-Only */
+ opthlp[i] = "Remote-only (makes IF REMOTE true)";
+ arghlp[i] = NULL;
+ break;
+ case 'S': /* "Stay" - enter interactive */
+ opthlp[i] = "Stay (enter command parser after action options)";
+ arghlp[i] = NULL;
+ break;
+ case 'T': /* Text file transfer mode */
+ opthlp[i] = "Transfer files in Text mode";
+ arghlp[i] = NULL;
+ break;
+#ifdef ANYX25
+ case 'U': /* X.25 call user data */
+ opthlp[i] = "X.25 call User data";
+ arghlp[i] = "Call-user-data string";
+ break;
+#endif /* ANYX25 */
+ case 'V': /* No automatic filetype switching */
+ opthlp[i] = "Disable automatic per-file text/binary switching";
+ arghlp[i] = NULL;
+ break;
+#ifdef COMMENT
+#ifdef OS2
+ case 'W': /* Win32 Window Handle */
+ opthlp[i] = "";
+ arghlp[i] = NULL;
+ break;
+#endif /* OS2 */
+#endif /* COMMENT */
+#ifdef ANYX25
+ case 'X': /* SET HOST to X.25 address */
+ opthlp[i] = "Make an X.25 connection";
+ arghlp[i] = "X.25 or X.121 address";
+ break;
+#endif /* ANYX25 */
+ case 'Y': /* No initialization file */
+ opthlp[i] = "Skip initialization file";
+ arghlp[i] = NULL;
+ break;
+#ifdef ANYX25
+ case 'Z': /* SET HOST to X.25 file descriptor */
+ opthlp[i] = "Make an X.25 connection";
+ arghlp[i] = "Numeric file descriptor of open X.25 connection";
+ break;
+#endif /* ANYX25 */
+ case 'a': /* as-name */
+ opthlp[i] = "As-name for file(s) in -s, -r, or -g";
+ arghlp[i] = "As-name string (alternative filename)";
+ break;
+ case 'b': /* Set bits-per-second for serial */
+ opthlp[i] = "Speed for serial device";
+ arghlp[i] = "Numeric Bits per second";
+ break;
+ case 'c': /* Connect before */
+ optact[i] = 1;
+ opthlp[i] = "CONNECT before transferring files";
+ arghlp[i] = NULL;
+ break;
+ case 'd': /* DEBUG */
+ opthlp[i] = "Create debug.log file (a second -d adds timestamps)";
+ arghlp[i] = NULL;
+ break;
+ case 'e': /* Extended packet length */
+ opthlp[i] = "Maximum length for incoming file-transfer packets";
+ arghlp[i] = "Length in bytes";
+ break;
+ case 'f': /* finish */
+ optact[i] = 1;
+ opthlp[i] = "Send Finish command to a Kermit server";
+ arghlp[i] = NULL;
+ break;
+ case 'g': /* get */
+ optact[i] = 1;
+ opthlp[i] = "GET file(s) from a Kermit server";
+ arghlp[i] = "Remote file specification";
+ break;
+ case 'h': /* help */
+ optact[i] = 1;
+#ifdef OS2ORUNIX
+ opthlp[i] =
+ "Print this message (pipe thru 'more' to prevent scrolling)";
+#else
+ "Print this message";
+#endif /* OS2ORUNIX */
+ arghlp[i] = NULL;
+ break;
+ case 'i': /* Treat files as binary */
+ opthlp[i] ="Transfer files in binary mode";
+ arghlp[i] = NULL;
+ break;
+#ifdef TCPSOCKET
+ case 'j': /* SET HOST (TCP/IP socket) */
+ opthlp[i] = "Make a TCP connection";
+ arghlp[i] =
+ "TCP host name/address and optional service name or number";
+ break;
+#endif /* TCPSOCKET */
+ case 'k': /* receive to stdout */
+ optact[i] = 1;
+ opthlp[i] = "RECEIVE file(s) to standard output";
+ arghlp[i] = NULL;
+ break;
+ case 'l': /* SET LINE */
+ opthlp[i] = "Make connection on serial communications device";
+ arghlp[i] = "Serial device name";
+ break;
+ case 'm': /* Modem type */
+ opthlp[i] = "Modem type for use with -l device";
+ arghlp[i] = "Modem name as in SET MODEM TYPE command";
+ break;
+ case 'n': /* connect after */
+ optact[i] = 1;
+ opthlp[i] = "CONNECT after transferring files";
+ arghlp[i] = NULL;
+ break;
+#ifdef ANYX25
+ case 'o': /* X.25 closed user group */
+ opthlp[i] = "X.25 closed user group";
+ arghlp[i] = "User group string";
+ break;
+#endif /* ANYX25 */
+ case 'p': /* SET PARITY */
+ opthlp[i] = "Parity";
+ arghlp[i] = "One of the following: even, odd, mark, none, space";
+ break;
+ case 'q': /* Quiet */
+ opthlp[i] = "Quiet (suppress most messages)";
+ arghlp[i] = NULL;
+ break;
+ case 'r': /* receive */
+ optact[i] = 1;
+ opthlp[i] = "RECEIVE file(s)";
+ arghlp[i] = NULL;
+ break;
+ case 's': /* send */
+ optact[i] = 1;
+ opthlp[i] = "SEND file(s)";
+ arghlp[i] = "One or more file specifications";
+ break;
+ case 't': /* Line turnaround handshake */
+ opthlp[i] = "XON Turnaround character for half-duplex connections";
+ arghlp[i] = NULL;
+ break;
+#ifdef ANYX25
+ case 'u': /* X.25 reverse charge call */
+ opthlp[i] = "X.25 reverse charge call";
+ arghlp[i] = NULL;
+ break;
+#endif /* ANYX25 */
+ case 'v': /* Vindow size */
+ opthlp[i] = "Window size";
+ arghlp[i] = "Number, 1 to 32";
+ break;
+ case 'w': /* Writeover */
+ opthlp[i] = "Incoming files Write over existing files";
+ arghlp[i] = NULL;
+ break;
+ case 'x': /* Server */
+ optact[i] = 1;
+ opthlp[i] = "Be a Kermit SERVER";
+ arghlp[i] = NULL;
+ break;
+ case 'y': /* Alternate init-file name */
+ opthlp[i] = "Alternative initialization file";
+ arghlp[i] = "File specification";
+ break;
+ case 'z': /* Not background */
+ opthlp[i] = "Force foreground behavior";
+ arghlp[i] = NULL;
+ break;
+ default:
+ opthlp[i] = NULL;
+ arghlp[i] = NULL;
+ }
+ }
+ inixopthlp();
+}
+
+int
+doxarg(s,pre) char ** s; int pre; {
+#ifdef IKSD
+#ifdef CK_LOGIN
+ extern int ckxsyslog, ckxwtmp, ckxanon;
+#ifdef UNIX
+ extern int ckxpriv;
+#endif /* UNIX */
+#ifdef CK_PERMS
+ extern int ckxperms;
+#endif /* CK_PERMS */
+ extern char * anonfile, * userfile, * anonroot;
+#endif /* CK_LOGIN */
+#ifdef CKWTMP
+ extern char * wtmpfile;
+#endif /* CKWTMP */
+#endif /* IKSD */
+ extern int srvcdmsg;
+ extern char * cdmsgfile[], * cdmsgstr;
+ char tmpbuf[CKMAXPATH+1];
+
+ int i, x, y, z, havearg = 0;
+ char buf[XARGBUFL], c, * p;
+
+ if (nxargs < 1)
+ return(-1);
+
+ c = *(*s + 1); /* Hyphen or Plus sign */
+
+ p = *s + 2;
+ for (i = 0; *p && i < XARGBUFL; i++) {
+ buf[i] = *p++;
+ if (buf[i] == '=' || buf[i] == ':') {
+ havearg = 1;
+ buf[i] = NUL;
+ break;
+ } else if (buf[i] < ' ') {
+ buf[i] = NUL;
+ break;
+ }
+ }
+ if (i > XARGBUFL - 1)
+ return(-1);
+ buf[i] = NUL;
+
+ x = lookup(xargtab,buf,nxargs,&z); /* Lookup the option keyword */
+
+ if (x < 0) /* On any kind of error */
+ return(-1); /* fail. */
+
+ /* Handle prescan versus post-initialization file */
+
+ if (((xargtab[z].flgs & CM_PRE) || (c == '+')) && !pre)
+ return(0);
+ else if (pre && !(xargtab[z].flgs & CM_PRE) && (c != '+'))
+ return(0);
+
+ /* Ensure that argument is given if and only if required */
+
+ p = havearg ? *s + i + 3 : NULL;
+
+ if ((xargtab[z].flgs & CM_ARG) && !havearg)
+ return(-1);
+ else if ((!(xargtab[z].flgs & CM_ARG)) && havearg)
+ return(-1);
+
+ switch (x) { /* OK to process this option... */
+#ifdef CKSYSLOG
+ case XA_SYSL: /* IKS: Syslog level */
+ y = 0;
+ if (isdigit(*p)) {
+ while (*p) {
+ if (*p < '0' || *p > '9')
+ return(-1);
+ y = y * 10 + (*p++ - '0');
+ }
+ } else {
+ y = lookup(oktab,p,noktab,&z);
+ if (y > 0) y = SYSLG_DF; /* Yes = default logging level */
+ }
+#ifndef SYSLOGLEVEL
+ /* If specified on cc command line, user can't change it. */
+ if (!inserver) /* Don't allow voluminous syslogging */
+ if (y > SYSLG_FA) /* by ordinary users. */
+ y = SYSLG_FA;
+#endif /* SYSLOGLEVEL */
+ if (y < 0) return(-1);
+#ifdef DEBUG
+ if (y >= SYSLG_DB)
+ if (!deblog)
+ deblog = debopn("debug.log",0);
+#endif /* DEBUG */
+#ifdef SYSLOGLEVEL
+ /* If specified on cc command line, user can't change it. */
+ y = SYSLOGLEVEL;
+#endif /* SYSLOGLEVEL */
+ ckxsyslog = y;
+ /* printf("ckxsyslog=%d\n",ckxsyslog); */
+ break;
+#endif /* CKSYSLOG */
+
+#ifdef CK_LOGIN
+#ifdef CKWTMP
+ case XA_WTMP: /* IKS: wtmp log */
+ y = lookup(oktab,p,noktab,&z);
+ if (y < 0) return(-1);
+ ckxwtmp = y;
+ /* printf("ckxwtmp=%d\n",ckxwtmp); */
+ break;
+
+ case XA_WTFI: /* IKS: wtmp logfile */
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&wtmpfile,p);
+ /* printf("wtmpfile=%s\n",wtmpfile); */
+ break;
+#endif /* CKWTMP */
+
+ case XA_ANON: /* IKS: Anonymous login allowed */
+ y = lookup(oktab,p,noktab,&z);
+ if (y < 0) return(-1);
+ ckxanon = y;
+ /* printf("ckxanon=%d\n",ckxanon); */
+ break;
+
+#ifdef UNIX
+ case XA_PRIV: /* IKS: Priv'd login allowed */
+ y = lookup(oktab,p,noktab,&z);
+ if (y < 0) return(-1);
+ ckxpriv = y;
+ /* printf("ckxpriv=%d\n",ckxpriv); */
+ break;
+#endif /* UNIX */
+
+#ifdef CK_PERMS
+ case XA_PERM: /* IKS: Anonymous Upload Permissions */
+ y = 0;
+ while (*p) {
+ if (*p < '0' || *p > '7')
+ return(-1);
+ y = y * 8 + (*p++ - '0');
+ }
+ ckxperms = y;
+ /* printf("ckxperms=%04o\n",ckxperms); */
+ break;
+#endif /* CK_PERMS */
+
+ case XA_ANFI: /* Anonymous init file */
+ if (!isabsolute(p))
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&anonfile,p);
+ /* printf("anonfile=%s\n",anonfile); */
+ break;
+
+ case XA_USFI: /* IKS: Forbidden user file */
+ if (!isabsolute(p))
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&userfile,p);
+ /* printf("userfile=%s\n",userfile); */
+ break;
+
+ case XA_ROOT: /* IKS: Anonymous root */
+ if (!isabsolute(p))
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&anonroot,p);
+ /* printf("anonroot=%s\n",anonroot); */
+ break;
+#endif /* CK_LOGIN */
+
+ case XA_CDFI: /* CD filename */
+#ifdef COMMENT
+ /* Do NOT expand this one! */
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+#endif /* COMMENT */
+ makelist(p,cdmsgfile,16);
+ makestr(&cdmsgstr,p);
+ /* printf("cdmsgstr=%s\n",cdmsgstr); */
+ break;
+
+ case XA_CDMS: /* CD messages */
+ y = lookup(oktab,p,noktab,&z);
+ if (y < 0) return(-1);
+ srvcdmsg = y;
+ /* printf("srvcdmsg=%d\n",srvcdmsg); */
+ break;
+
+#ifndef NOXFER
+ case XA_IKLG: /* Transfer log on/off */
+ y = lookup(oktab,p,noktab,&z);
+ if (y < 0) return(-1);
+ xferlog = y;
+ /* printf("xferlog=%d\n",xferlog); */
+ break;
+
+ case XA_IKFI: /* Transfer log file */
+ if (!isabsolute(p))
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&xferfile,p);
+ xferlog = 1;
+ /* printf("xferfile=%s\n",xferfile); */
+ break;
+
+ case XA_BAFI: /* IKS: banner (greeting) file */
+ if (!isabsolute(p))
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&bannerfile,p);
+ /* printf("bannerfile=%s\n",bannerfile); */
+ break;
+#endif /* NOXFER */
+
+#ifndef NOHELP
+ case XA_HELP: /* Help */
+ /* printf("help\n"); */
+ for (i = 0; i <= XA_MAX; i++)
+ if (xopthlp[i])
+ printf("%s\n %s\n\n",xopthlp[i],xarghlp[i]);
+ if (stayflg || what == W_COMMAND)
+ break;
+ else
+ doexit(GOOD_EXIT,-1);
+#endif /* NOHELP */
+
+#ifndef NOHELP
+ case XA_HEFI: /* IKS: custom help file */
+ if (!isabsolute(p))
+ if (zfnqfp(p,CKMAXPATH,tmpbuf))
+ p = tmpbuf;
+ makestr(&helpfile,p);
+ /* printf("helpfile=%s\n",helpfile); */
+ break;
+#endif /* NOHELP */
+
+#ifdef CK_LOGIN
+ case XA_TIMO:
+ if (!rdigits(p))
+ return(-1);
+ logintimo = atoi(p);
+ /* printf("logintimo=%d\n",p); */
+ break;
+#endif /* CK_LOGIN */
+
+ case XA_NOIN: /* No interrupts */
+#ifndef NOICP
+ cmdint = 0;
+#endif /* NOICP */
+ xsuspend = 0;
+ break;
+
+#ifdef UNIX
+ case XA_UNBUF: /* Unbuffered console i/o*/
+ break; /* This one is handled in ckcmai.c */
+#endif /* UNIX */
+
+#ifdef IKSDB
+ case XA_DBFI: {
+ extern char * dbdir, * dbfile;
+ extern int dbenabled;
+ struct zfnfp * zz;
+ if ((zz = zfnqfp(p,CKMAXPATH,tmpbuf))) {
+ char *s, *s2 = NULL;
+ makestr(&dbdir,zz->fpath);
+ makestr(&dbfile,zz->fpath);
+ for (s = dbdir; *s; s++) {
+ if (ISDIRSEP(*s))
+ s2 = s+1;
+ }
+ if (s2) *s2 = NUL;
+ debug(F110,"XA_DBFI dbdir",dbdir,0);
+ debug(F110,"XA_DBFI dbfile",dbfile,0);
+ dbenabled = 1;
+ }
+ break;
+ }
+ case XA_DBAS: {
+ extern int dbenabled;
+ y = lookup(oktab,p,noktab,&z);
+ if (y < 0) return(-1);
+ dbenabled = y;
+ break;
+ }
+#endif /* IKSDB */
+
+ case XA_VERS: {
+ extern char * ck_s_ver, * ck_s_xver;
+ printf("%s",ck_s_ver);
+ if (*ck_s_xver)
+ printf(" [%s]\n",ck_s_xver);
+ printf("\n");
+ if (stayflg || what == W_COMMAND)
+ break;
+ else
+ doexit(GOOD_EXIT,-1);
+ }
+#ifndef NOXFER
+#ifdef CK_PERMS
+ case XA_NPRM: {
+ extern int atlpri, atlpro, atgpri, atgpro;
+ atlpri = 0;
+ atlpro = 0;
+ atgpri = 0;
+ atgpro = 0;
+ break;
+ }
+#endif /* CK_PERMS */
+#endif /* NOXFER */
+
+#ifdef KUI
+ case XA_SCALE:
+ kui_init.resizeMode = 1;
+ break;
+ case XA_CHGD:
+ kui_init.resizeMode = 2;
+ break;
+ case XA_WMAX:
+ kui_init.nCmdShow = SW_MAXIMIZE;
+ break;
+ case XA_WMIN:
+ kui_init.nCmdShow = SW_MINIMIZE;
+ break;
+
+ case XA_XPOS:
+ if (!rdigits(p))
+ return(-1);
+ kui_init.pos_init++;
+ kui_init.pos_x = atoi(p);
+ break;
+
+ case XA_YPOS:
+ if (!rdigits(p))
+ return(-1);
+ kui_init.pos_init++;
+ kui_init.pos_y = atoi(p);
+ break;
+
+ case XA_FNAM: {
+ extern struct _kui_init kui_init;
+ extern struct keytab * term_font;
+ extern struct keytab * _term_font;
+ extern int tt_font, ntermfont;
+ int x, z;
+ if (ntermfont == 0)
+ BuildFontTable(&term_font, &_term_font, &ntermfont);
+ if (!(term_font && _term_font && ntermfont > 0)) {
+ printf("?Unable to construct Font Facename Table\n");
+ return(0);
+ }
+ x = lookup(term_font,p,ntermfont,&z);
+ if (x < 0) {
+ x = lookup(_term_font,p,ntermfont,&z);
+ if (x < 0) {
+ printf("?Invalid Font Facename: %s\n",p);
+ return(0);
+ }
+ }
+ tt_font = x;
+ kui_init.face_init++;
+ makestr(&kui_init.facename,term_font[z].kwd);
+ break;
+ }
+ case XA_FSIZ: {
+ extern struct _kui_init kui_init;
+ extern int tt_font_size;
+ char * q;
+ int halfpoint = 0;
+
+ kui_init.font_init++;
+ for ( q=p ; *q ; q++ ) {
+ if ( *q == '.') {
+ *q++ = '\0';
+ if (!rdigits(q))
+ return(-1);
+ if (!*q || atoi(q) == 0)
+ break; /* no halfpoint */
+ halfpoint = 1;
+ if (atoi(q) != 5)
+ printf("? Font sizes are treated in half-point increments\n");
+ break;
+ }
+ }
+ if (!rdigits(p))
+ return(-1);
+ tt_font_size = kui_init.font_size = 2 * atoi(p) + halfpoint;
+ break;
+ }
+ case XA_NOMN:
+ kui_init.nomenubar = 1;
+ break;
+ case XA_NOTB:
+ kui_init.notoolbar = 1;
+ break;
+ case XA_NOSB:
+ kui_init.nostatusbar = 1;
+ break;
+ case XA_NOBAR:
+ kui_init.nomenubar = 1;
+ kui_init.notoolbar = 1;
+ kui_init.nostatusbar = 1;
+ break;
+#endif /* KUI */
+
+#ifndef NOPUSH
+ case XA_NOPUSH:
+ nopush = 1;
+ break;
+#endif /* NOPUSH */
+#ifdef OS2
+ case XA_LOCK:
+ tt_scroll = 0;
+ tt_escape = 0;
+#ifndef NOPUSH
+ nopush = 1;
+#endif
+#ifdef KUI
+ kui_init.nomenubar = 1;
+ kui_init.notoolbar = 1;
+ kui_init.nostatusbar = 1;
+#endif
+ break;
+#ifdef KUI
+ case XA_NOCLOSE:
+ kui_init.noclose = 1;
+ break;
+#endif /* KUI */
+ case XA_NOSCROLL:
+ tt_scroll = 0;
+ break;
+ case XA_NOESCAPE:
+ tt_escape = 0;
+ break;
+#endif /* OS2 */
+
+#ifndef NOLOCAL
+ case XA_TERM: { /* Terminal type */
+ extern struct keytab ttyptab[];
+ extern int nttyp;
+#ifdef TNCODE
+ extern char * tn_term;
+#endif /* TNCODE */
+#ifdef OS2
+ int x, z;
+ extern int tt_type, tt_type_mode;
+ x = lookup(ttyptab,p,nttyp,&z);
+ if (x < 0)
+ return(-1);
+ tt_type_mode = tt_type = x;
+#endif /* OS2 */
+#ifdef TNCODE
+ makestr(&tn_term,p);
+#endif /* TNCODE */
+ break;
+ }
+ case XA_CSET: { /* Remote Character Set */
+#ifndef NOCSETS
+#ifdef CKOUNI
+ extern struct keytab txrtab[];
+ extern int ntxrtab;
+ x = lookup(txrtab,p,ntxrtab,&z);
+#else /* CKOUNI */
+ extern struct keytab ttcstab[];
+ extern int ntermc;
+ x = lookup(ttcstab,p,ntermc,&z);
+#endif /* CKOUNI */
+ if (x < 0)
+ return(-1);
+ setremcharset(z,4 /* TT_GR_ALL (in ckuus7.c) */);
+#else /* NOCSETS */
+ return(-1);
+#endif /* NOCSETS */
+ break;
+ }
+ case XA_ROWS: { /* Screen rows (height) */
+#ifdef OS2
+ extern int row_init;
+#else /* OS2 */
+ extern int tt_rows;
+#endif /* OS2 */
+ if (!rdigits(p))
+ return(-1);
+#ifdef OS2
+ if (!os2_settermheight(atoi(p)))
+ return(-1);
+ row_init++;
+#else /* Not OS/2 */
+ tt_rows = atoi(p);
+#endif /* OS2 */
+ break;
+ }
+ case XA_COLS: { /* Screen columns (width) */
+#ifdef OS2
+ extern int col_init;
+#else /* OS2 */
+ extern int tt_cols;
+#endif /* OS2 */
+ if (!rdigits(p))
+ return(-1);
+#ifdef OS2
+ if (!os2_settermwidth(atoi(p)))
+ return(-1);
+ col_init++;
+#else /* Not OS/2 */
+ tt_cols = atoi(p);
+#endif /* OS2 */
+ break;
+ }
+#ifdef OS2
+ case XA_TITL: {
+ extern char usertitle[];
+ ckstrncpy(usertitle,p,64);
+ os2settitle("",1);
+ break;
+ }
+#endif /* OS2 */
+
+#ifdef COMMENT /* TO BE FILLED IN ... */
+ case XA_TEL: /* Make a Telnet connection */
+ case XA_FTP: /* Make an FTP connection */
+ case XA_SSH: /* Make an SSH connection */
+#endif /* COMMENT */
+
+#ifndef NOSPL
+ case XA_USER: /* Username for login */
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ {
+ ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
+ haveftpuid = 1;
+ }
+ break;
+#endif /* NOSPL */
+#endif /* NOLOCAL */
+
+ default:
+ return(-1);
+ }
+ return(0);
+}
+
+#ifdef IKSD
+#ifdef IKSDCONF
+#define IKS_ANON 0
+#define IKS_BAFI 1
+#define IKS_CDFI 2
+#define IKS_CDMS 3
+#define IKS_HEFI 4
+#define IKS_ANFI 5
+#define IKS_USFI 6
+#define IKS_IKLG 7
+#define IKS_IKFI 8
+#define IKS_DBAS 9
+#define IKS_DBFI 10
+#define IKS_PERM 11
+#define IKS_PRIV 12
+#define IKS_ROOT 13
+#define IKS_TIMO 14
+#define IKS_WTFI 15
+#define IKS_WTMP 16
+#define IKS_SRVR 17
+#define IKS_NOIN 18
+#define IKS_INIT 19
+#define IKS_ANLG 20
+#define IKS_ACCT 21
+#define IKS_NTDOM 22
+#define IKS_SYSL 23
+
+#ifdef CK_LOGIN
+static struct keytab iksantab[] = {
+#ifdef OS2
+ { "account", IKS_ACCT, 0 },
+#endif /* OS2 */
+ { "initfile", IKS_ANFI, 0 },
+ { "login", IKS_ANLG, 0 },
+#ifdef UNIX
+ { "root", IKS_ROOT, 0 },
+#else
+#ifdef CKROOT
+ { "root", IKS_ROOT, 0 },
+#endif /* CKROOT */
+#endif /* UNIX */
+ { "", 0, 0 }
+};
+static int niksantab = sizeof(iksantab) / sizeof(struct keytab) - 1;
+#endif /* CK_LOGIN */
+
+static struct keytab ikstab[] = {
+#ifdef CK_LOGIN
+ { "anonymous", IKS_ANON, 0 },
+#endif /* CK_LOGIN */
+ { "bannerfile", IKS_BAFI, 0 },
+ { "cdfile", IKS_CDFI, 0 },
+ { "cdmessage", IKS_CDMS, 0 },
+ { "cdmsg", IKS_CDMS, CM_INV },
+#ifdef IKSDB
+ { "database", IKS_DBAS, 0 },
+ { "dbfile", IKS_DBFI, 0 },
+#endif /* IKSDB */
+#ifdef CK_LOGIN
+#ifdef NT
+ { "default-domain", IKS_NTDOM, 0 },
+#endif /* NT */
+#endif /* CK_LOGIN */
+#ifndef NOHELP
+ { "helpfile", IKS_HEFI, 0 },
+#endif /* NOHELP */
+ { "initfile", IKS_INIT, 0 },
+ { "no-initfile", IKS_NOIN, 0 },
+#ifdef CK_LOGIN
+#ifdef CK_PERM
+ { "permissions", IKS_PERM, 0 },
+ { "perms", IKS_PERM, CM_INV },
+#endif /* CK_PERM */
+#ifdef UNIX
+ { "privid", IKS_PRIV, 0 },
+#endif /* UNIX */
+ { "server-only", IKS_SRVR, 0 },
+#ifdef CKSYSLOG
+ { "syslog", IKS_SYSL, 0 },
+#endif /* CKSYSLOG */
+ { "timeout", IKS_TIMO, 0 },
+ { "userfile", IKS_USFI, 0 },
+#ifdef CKWTMP
+ { "wtmpfile", IKS_WTFI, 0 },
+ { "wtmplog", IKS_WTMP, 0 },
+#endif /* CKWTMP */
+#endif /* CK_LOGIN */
+ { "xferfile", IKS_IKFI, 0 },
+ { "xferlog", IKS_IKLG, 0 }
+};
+static int nikstab = sizeof(ikstab) / sizeof(struct keytab);
+#endif /* IKSDCONF */
+
+#ifndef NOICP
+int
+setiks() { /* SET IKS */
+#ifdef IKSDCONF
+#ifdef CK_LOGIN
+ extern int ckxsyslog, ckxwtmp, ckxanon;
+#ifdef UNIX
+ extern int ckxpriv;
+#endif /* UNIX */
+#ifdef CK_PERMS
+ extern int ckxperms;
+#endif /* CK_PERMS */
+ extern char * anonfile, * userfile, * anonroot;
+#ifdef OS2
+ extern char * anonacct;
+#endif /* OS2 */
+#ifdef NT
+ extern char * iks_domain;
+#endif /* NT */
+#endif /* CK_LOGIN */
+#ifdef CKWTMP
+ extern char * wtmpfile;
+#endif /* CKWTMP */
+ extern int srvcdmsg, success, iksdcf, rcflag, noinit, arg_x;
+ extern char * cdmsgfile[], * cdmsgstr, *kermrc;
+ extern xx_strp xxstring;
+ int x, y, z;
+ char *s;
+ char tmpbuf[CKMAXPATH+1];
+
+ if ((y = cmkey(ikstab,nikstab,"","",xxstring)) < 0)
+ return(y);
+
+#ifdef CK_LOGIN
+ if (y == IKS_ANON) {
+ if ((y = cmkey(iksantab,niksantab,"","",xxstring)) < 0)
+ return(y);
+ }
+#endif /* CK_LOGIN */
+
+ switch (y) {
+#ifdef CKSYSLOG
+ case IKS_SYSL: /* IKS: Syslog level */
+ if ((z = cmkey(oktab,noktab,"","",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+#ifndef SYSLOGLEVEL
+ /* If specified on cc command line, user can't change it. */
+ if (!inserver) /* Don't allow voluminous syslogging */
+ if (y > SYSLG_FA) /* by ordinary users. */
+ y = SYSLG_FA;
+#endif /* SYSLOGLEVEL */
+ if (y < 0) return(-1);
+#ifdef DEBUG
+ if (y >= SYSLG_DB)
+ if (!deblog)
+ deblog = debopn("debug.log",0);
+#endif /* DEBUG */
+#ifdef SYSLOGLEVEL
+ /* If specified on cc command line, user can't change it. */
+ y = SYSLOGLEVEL;
+#endif /* SYSLOGLEVEL */
+ ckxsyslog = y;
+ /* printf("ckxsyslog=%d\n",ckxsyslog); */
+ break;
+#endif /* CKSYSLOG */
+
+#ifdef CK_LOGIN
+#ifdef NT
+ case IKS_NTDOM:
+ if ((z = cmtxt(
+ "DOMAIN to be used for user authentication when none is specified",
+ "", &s,xxstring)) < 0)
+ return(z);
+ if (iksdcf) return(success = 0);
+ if (!*s) s= NULL;
+ makestr(&iks_domain,s);
+ break;
+#endif /* NT */
+#ifdef OS2
+ case IKS_ACCT:
+ if ((z = cmtxt("Name of local account to use for anonymous logins",
+ "GUEST", &s,xxstring)) < 0)
+ return(z);
+ if (iksdcf) return(success = 0);
+ if (*s) {
+ makestr(&anonacct,s);
+ } else if ( anonacct ) {
+ free(anonacct);
+ anonacct = NULL;
+ }
+ break;
+#endif /* OS2 */
+ case IKS_ANLG:
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ ckxanon = z;
+#ifdef OS2
+ if (ckxanon && !anonacct)
+ makestr(&anonacct,"GUEST");
+#endif /* OS2 */
+ break;
+#endif /* CK_LOGIN */
+ case IKS_BAFI:
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ debug(F110,"bannerfile before zfnqfp()",s,0);
+ if (zfnqfp(s,CKMAXPATH,tmpbuf)) {
+ debug(F110,"bannerfile after zfnqfp()",tmpbuf,0);
+ s = tmpbuf;
+ }
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s)
+ makestr(&bannerfile,s);
+ break;
+ case IKS_CDFI:
+ if ((z = cmtxt("list of cd message file names","READ.ME",
+ &s,xxstring)) < 0)
+ return(z);
+ if (iksdcf) return(success = 0);
+ if (*s) {
+ makelist(s,cdmsgfile,16);
+ makestr(&cdmsgstr,s);
+ }
+ break;
+ case IKS_CDMS:
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ srvcdmsg = z;
+ break;
+ case IKS_HEFI:
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ if (zfnqfp(s,CKMAXPATH,tmpbuf))
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s)
+ makestr(&helpfile,s);
+ break;
+ case IKS_ANFI:
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ if (zfnqfp(s,CKMAXPATH,tmpbuf))
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s)
+ makestr(&anonfile,s);
+ break;
+ case IKS_USFI:
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ if (zfnqfp(s,CKMAXPATH,tmpbuf))
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s)
+ makestr(&userfile,s);
+ break;
+ case IKS_IKFI:
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ if (zfnqfp(s,CKMAXPATH,tmpbuf))
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s) {
+ makestr(&xferfile,s);
+ xferlog = 1;
+ }
+ break;
+ case IKS_IKLG:
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ xferlog = z;
+ break;
+
+#ifdef CK_LOGIN
+#ifdef CK_PERM
+ case IKS_PERM:
+ if ((z = cmtxt("Octal file permssion code","000",
+ &s,xxstring)) < 0)
+ return(z);
+ if (z < 0) return(z);
+ if (iksdcf) return(success = 0);
+ y = 0;
+ while (*s) {
+ if (*s < '0' || *s > '7')
+ return(-9);
+ y = y * 8 + (*s++ - '0');
+ }
+ ckxperms = y;
+ break;
+#endif /* CK_PERM */
+#ifdef UNIX
+ case IKS_PRIV: /* IKS: Priv'd login allowed */
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ ckxpriv = z;
+ break;
+#endif /* UNIX */
+
+ case IKS_ROOT: /* IKS: Anonymous root */
+ if ((z = cmdir("Name of disk and/or directory","",&s,
+ xxstring)) < 0 ) {
+ if (z != -3)
+ return(z);
+ }
+ if (*s) {
+ if (zfnqfp(s,CKMAXPATH,tmpbuf))
+ s = tmpbuf;
+ } else
+ s = "";
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s)
+ makestr(&anonroot,s);
+ /* printf("anonroot=%s\n",anonroot); */
+ break;
+
+ case IKS_TIMO:
+ z = cmnum("login timeout, seconds","0",10,&x,xxstring);
+ if (z < 0) return(z);
+ if (x < 0 || x > 7200) {
+ printf("?Value must be between 0 and 7200\r\n");
+ return(-9);
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ if (iksdcf) return(success = 0);
+ logintimo = x;
+ break;
+
+#ifdef CKWTMP
+ case IKS_WTMP: /* IKS: wtmp log */
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ ckxwtmp = z;
+ break;
+
+ case IKS_WTFI: /* IKS: wtmp logfile */
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ if (zfnqfp(s,CKMAXPATH,tmpbuf))
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (*s)
+ makestr(&wtmpfile,s);
+ break;
+#endif /* CKWTMP */
+#endif /* CK_LOGIN */
+#ifdef IKSDB
+ case IKS_DBFI: {
+ extern char * dbdir, * dbfile;
+ extern int dbenabled;
+ struct zfnfp * zz;
+ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0)
+ return(z);
+ if (x) {
+ printf("?Wildcards not allowed\n");
+ return(-9);
+ }
+ zz = zfnqfp(s,CKMAXPATH,tmpbuf);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ if (zz) {
+ makestr(&dbdir,zz->fpath);
+ makestr(&dbfile,(char *)tmpbuf);
+ dbenabled = 1;
+ } else
+ return(success = 0);
+ break;
+ }
+ case IKS_DBAS: {
+ extern int dbenabled;
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ dbenabled = z;
+ break;
+ }
+#endif /* IKSDB */
+
+ case IKS_INIT:
+ if ((z = cmtxt("Alternate init file specification","",
+ &s,xxstring)) < 0)
+ return(z);
+ if (z < 0) return(z);
+ if (iksdcf) return(success = 0);
+ ckstrncpy(kermrc,s,KERMRCL);
+ rcflag = 1; /* Flag that this has been done */
+ break;
+
+ case IKS_NOIN:
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ noinit = z;
+ break;
+
+ case IKS_SRVR:
+ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ if (iksdcf) return(success = 0);
+ arg_x = z;
+ break;
+
+ default:
+ return(-9);
+ }
+ return(success = (inserver ? 1 : 0));
+#else /* IKSDCONF */
+ if ((x = cmcfm()) < 0)
+ return(x);
+ return(success = 0);
+#endif /* IKSDCONF */
+}
+#endif /* NOICP */
+#endif /* IKSD */
+
+/* D O A R G -- Do a command-line argument. */
+
+int
+#ifdef CK_ANSIC
+doarg(char x)
+#else
+doarg(x) char x;
+#endif /* CK_ANSIC */
+/* doarg */ {
+ int i, n, y, z, xx; long zz; char *xp;
+
+#ifdef NETCONN
+extern char *line, *tmpbuf; /* Character buffers for anything */
+#endif /* NETCONN */
+
+#ifdef IKSD
+ /* Internet Kermit Server set some way besides -A... */
+ if (inserver)
+ dofast();
+#endif /* IKSD */
+
+ xp = *xargv+1; /* Pointer for bundled args */
+ debug(F111,"doarg entry",xp,xargc);
+ while (x) {
+ debug(F000,"doarg arg","",x);
+ switch (x) { /* Big switch on arg */
+
+#ifndef COMMENT
+ case '-': /* Extended commands... */
+ if (doxarg(xargv,0) < 0) {
+ XFATAL("Extended option error");
+ } /* Full thru... */
+ case '+': /* Extended command for prescan() */
+ return(0);
+#else /* NOICP */
+ case '-':
+ case '+':
+ XFATAL("Extended options not configured");
+#endif /* NOICP */
+
+#ifndef NOSPL
+ case 'C': { /* Commands for parser */
+ char * s;
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("No commands given for -C");
+ }
+ s = *xargv; /* Get the argument (must be quoted) */
+ if (!*s) /* If empty quotes */
+ s = NULL; /* ignore this option */
+ if (s) {
+ makestr(&clcmds,s); /* Make pokeable copy */
+ s = clcmds; /* Change tabs to spaces */
+ while (*s) {
+ if (*s == '\t') *s = ' ';
+ s++;
+ }
+ }
+ break;
+ }
+#endif /* NOSPL */
+
+#ifndef NOXFER
+ case 'D': /* Delay */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing delay value");
+ }
+ z = atoi(*xargv); /* Convert to number */
+ if (z > -1) /* If in range */
+ ckdelay = z; /* set it */
+ else {
+ XFATAL("bad delay value");
+ }
+ break;
+#endif /* NOXFER */
+
+ case 'E': /* Exit on close */
+#ifdef NETCONN
+ tn_exit = 1;
+#endif /* NETCONN */
+ exitonclose = 1;
+ break;
+
+#ifndef NOICP
+ case 'S': /* "Stay" - enter interactive */
+ stayflg = 1; /* command parser after executing */
+ xfinish = 0; /* command-line actions. */
+ break;
+#endif /* NOICP */
+
+ case 'T': /* File transfer mode = text */
+ binary = XYFT_T;
+ xfermode = XMODE_M; /* Transfer mode manual */
+ filepeek = 0;
+#ifdef PATTERNS
+ patterns = 0;
+#endif /* PATTERNS */
+ break;
+
+ case '7':
+ break;
+
+#ifdef IKSD
+ case 'A': { /* Internet server */
+ /* Already done in prescan() */
+ /* but implies 'x' && 'Q' */
+#ifdef OS2
+ char * p;
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+#ifdef NT
+ /* Support for Pragma Systems Telnet/Terminal Servers */
+ p = getenv("PRAGMASYS_INETD_SOCK");
+ if (!(p && atoi(p) != 0)) {
+ xargv++, xargc--;
+ if (xargc < 1 || **xargv == '-') {
+ XFATAL("missing socket handle");
+ }
+ }
+#else /* NT */
+ xargv++, xargc--;
+ if (xargc < 1 || **xargv == '-') {
+ XFATAL("missing socket handle");
+ }
+#endif /* NT */
+#endif /* OS2 */
+#ifdef NOICP /* If no Interactive Command Parser */
+ action = 'x'; /* -A implies -x. */
+#endif /* NOICP */
+#ifndef NOXFER
+ dofast();
+#endif /* NOXFER */
+ break;
+ }
+#endif /* IKSD */
+
+#ifndef NOXFER
+ case 'Q': /* Quick (i.e. FAST) */
+ dofast();
+ break;
+#endif /* NOXFER */
+
+ case 'R': /* Remote-Only */
+ break; /* This is handled in prescan(). */
+
+#ifndef NOSERVER
+ case 'x': /* server */
+ case 'O': /* (for One command only) */
+ if (action) {
+ XFATAL("conflicting actions");
+ }
+ if (x == 'O') justone = 1;
+ xfinish = 1;
+ action = 'x';
+ break;
+#endif /* NOSERVER */
+
+#ifndef NOXFER
+ case 'f': /* finish */
+ if (action) {
+ XFATAL("conflicting actions");
+ }
+ action = setgen('F',"","","");
+ break;
+#endif /* NOXFER */
+
+ case 'r': { /* receive */
+ if (action) {
+ XFATAL("conflicting actions");
+ }
+ action = 'v';
+ break;
+ }
+
+#ifndef NOXFER
+ case 'k': /* receive to stdout */
+ if (action) {
+ XFATAL("conflicting actions");
+ }
+ stdouf = 1;
+ action = 'v';
+ break;
+
+ case 's': { /* send */
+ int fil2snd, rc;
+ if (!recursive)
+ nolinks = 0; /* Follow links by default */
+
+ if (action) {
+ XFATAL("conflicting actions");
+ }
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -s");
+ }
+ nfils = 0; /* Initialize file counter */
+ fil2snd = 0; /* Assume nothing to send */
+ z = 0; /* Flag for stdin */
+ cmlist = xargv + 1; /* Remember this pointer */
+ while (++xargv, --xargc > 0) { /* Traverse the list */
+#ifdef PIPESEND
+ if (usepipes && protocol == PROTO_K && **xargv == '!') {
+ cmarg = *xargv;
+ cmarg++;
+ debug(F110,"doarg pipesend",cmarg,0);
+ nfils = -1;
+ z = 1;
+ pipesend = 1;
+ } else
+#endif /* PIPESEND */
+ if (**xargv == '-') { /* Check for sending stdin */
+ if (strcmp(*xargv,"-") != 0) /* next option? */
+ break;
+ z++; /* "-" alone means send from stdin. */
+#ifdef RECURSIVE
+ } else if (!strcmp(*xargv,".")) {
+ fil2snd = 1;
+ nfils++;
+ recursive = 1;
+ nolinks = 2;
+#endif /* RECURSIVE */
+ } else /* Check if file exists */
+ if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
+ if (rc != -2)
+ fil2snd = 1;
+ nfils++; /* Bump file counter */
+ } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
+ /* or contains wildcard characters matching real files */
+ fil2snd = 1;
+ nfils++;
+ } else {
+ if (!failmsg)
+ failmsg = (char *)malloc(2000);
+ if (failmsg) {
+ ckmakmsg(failmsg,2000,
+#ifdef VMS
+ "%CKERMIT-E-SEARCHFAIL "
+#else
+ "kermit -s "
+#endif /* VMS */
+ ,
+ *xargv,
+ ": ",
+ ck_errstr()
+ );
+ }
+ }
+ }
+ xargc++, xargv--; /* Adjust argv/argc */
+ if (!fil2snd && z == 0) {
+ if (!failmsg) {
+#ifdef VMS
+ failmsg = "%CKERMIT-E-SEARCHFAIL, no files for -s";
+#else
+ failmsg = "No files for -s";
+#endif /* VMS */
+ }
+ XFATAL(failmsg);
+ }
+ if (z > 1) {
+ XFATAL("kermit -s: too many -'s");
+ }
+ if (z == 1 && fil2snd) {
+ XFATAL("invalid mixture of filenames and '-' in -s");
+ }
+ debug(F101,"doarg s nfils","",nfils);
+ debug(F101,"doarg s z","",z);
+ if (nfils == 0) { /* no file parameters were specified */
+ if (is_a_tty(0)) { /* (used to be is_a_tty(1) - why?) */
+ XFATAL("sending from terminal not allowed");
+ } else stdinf = 1;
+ }
+ debug(F101,"doarg s stdinf","",stdinf);
+ debug(F111,"doarg",*xargv,nfils);
+ action = 's';
+ break;
+ }
+
+ case 'g': /* get */
+ case 'G': /* get to stdout */
+ if (action) {
+ XFATAL("conflicting actions");
+ }
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -g");
+ }
+ xargv++, xargc--;
+ if ((xargc == 0) || (**xargv == '-')) {
+ XFATAL("missing filename for -g");
+ }
+ if (x == 'G') stdouf = 1;
+ cmarg = *xargv;
+ action = 'r';
+ break;
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ case 'c': /* connect before */
+ cflg = 1;
+ break;
+
+ case 'n': /* connect after */
+ cnflg = 1;
+ break;
+#endif /* NOLOCAL */
+
+ case 'h': /* help */
+ usage();
+#ifndef NOICP
+ if (stayflg || what == W_COMMAND)
+ break;
+ else
+#endif /* NOICP */
+ doexit(GOOD_EXIT,-1);
+
+#ifndef NOXFER
+ case 'a': /* "as" */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -a");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing name in -a");
+ }
+ cmarg2 = *xargv;
+ debug(F111,"doarg a",cmarg2,xargc);
+ break;
+#endif /* NOXFER */
+
+#ifndef NOICP
+ case 'Y': /* No initialization file */
+ noinit = 1;
+ break;
+
+ case 'y': /* Alternate init-file name */
+ noinit = 0;
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -y");
+ }
+ xargv++, xargc--;
+ if (xargc < 1) {
+ XFATAL("missing filename in -y");
+ }
+ /* strcpy(kermrc,*xargv); ... already done in prescan()... */
+ break;
+#endif /* NOICP */
+
+#ifndef NOXFER
+ case 'I': /* Assume we have an "Internet" */
+ reliable = 1; /* or other reliable connection */
+ xreliable = 1;
+ setreliable = 1;
+
+ /* I'm not so sure about this -- what about VMS? (next comment) */
+ clearrq = 1; /* therefore the channel is clear */
+
+#ifndef VMS
+/*
+ Since this can trigger full control-character unprefixing, we need to
+ ensure that our terminal or pty driver is not doing Xon/Xoff; otherwise
+ we can become deadlocked the first time we receive a file that contains
+ Xoff.
+*/
+ flow = FLO_NONE;
+#endif /* VMS */
+ break;
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+ case 'l': /* SET LINE */
+#ifdef NETCONN
+#ifdef ANYX25
+ case 'X': /* SET HOST to X.25 address */
+#ifdef SUNX25
+ case 'Z': /* SET HOST to X.25 file descriptor */
+#endif /* SUNX25 */
+#endif /* ANYX25 */
+#ifdef TCPSOCKET
+ case 'J':
+ case 'j': /* SET HOST (TCP/IP socket) */
+#endif /* TCPSOCKET */
+#endif /* NETCONN */
+#ifndef NOXFER
+ if (x == 'j' || x == 'J' || x == 'X' || x == 'Z') {
+ reliable = 1; /* or other reliable connection */
+ xreliable = 1;
+ setreliable = 1;
+ }
+#endif /* NOXFER */
+ network = 0;
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -l or -j");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("communication line device name missing");
+ }
+
+#ifdef NETCONN
+ if (x == 'J') {
+ cflg = 1; /* Connect */
+ stayflg = 1; /* Stay */
+ tn_exit = 1; /* Telnet-like exit condition */
+ exitonclose = 1;
+ }
+#endif /* NETCONN */
+ ckstrncpy(ttname,*xargv,TTNAMLEN+1);
+ local = (strcmp(ttname,CTTNAM) != 0);
+ if (local && strcmp(ttname,"0") == 0)
+ local = 0;
+/*
+ NOTE: We really do not need to call ttopen here, since it should be called
+ again later, automatically, when we first try to condition the device via
+ ttpkt or ttvt. Calling ttopen here has the bad side effect of making the
+ order of the -b and -l options significant when the order of command-line
+ options should not matter. However, the network cases immediately below
+ complicate matters a bit, so we'll settle this in a future edit.
+*/
+ if (x == 'l') {
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) {
+ XFATAL("can't open device");
+ }
+#ifdef CKLOGDIAL
+ dologline();
+#endif /* CKLOGDIAL */
+ debug(F101,"doarg speed","",speed);
+ cxtype = (mdmtyp > 0) ? CXT_MODEM : CXT_DIRECT;
+ speed = ttgspd(); /* Get the speed. */
+ setflow(); /* Do something about flow control. */
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+
+#ifdef NETCONN
+ } else {
+ if (x == 'j' || x == 'J') { /* IP network host name */
+ char * s = line;
+ char * service = tmpbuf;
+ if (xargc > 0) { /* Check if it's followed by */
+ /* A service name or number */
+ if (*(xargv+1) && *(*(xargv+1)) != '-') {
+ xargv++, xargc--;
+ ckstrncat(ttname,":",TTNAMLEN+1);
+ ckstrncat(ttname,*xargv,TTNAMLEN+1);
+ }
+ }
+ nettype = NET_TCPB;
+ mdmtyp = -nettype; /* Perhaps already set in init file */
+ telnetfd = 1; /* Or maybe an open file descriptor */
+ ckstrncpy(line, ttname, LINBUFSIZ); /* Working copy */
+ for (s = line; *s != NUL && *s != ':'; s++);
+ if (*s) {
+ *s++ = NUL;
+ ckstrncpy(service, s, TMPBUFSIZ);
+ } else *service = NUL;
+ s = line;
+#ifndef NODIAL
+#ifndef NOICP
+ /* Look up in network directory */
+ x = 0;
+ if (*s == '=') { /* If number starts with = sign */
+ s++; /* strip it */
+ while (*s == SP) /* and also any leading spaces */
+ s++;
+ ckstrncpy(line,s,LINBUFSIZ); /* Do this again. */
+ nhcount = 0;
+ } else if (!isdigit(line[0])) {
+/*
+ nnetdir will be greater than 0 if the init file has been processed and it
+ contained a SET NETWORK DIRECTORY command.
+*/
+ xx = 0; /* Initialize this */
+ if (nnetdir > 0) /* If there is a directory... */
+ xx = lunet(line); /* Look up the name */
+ else /* If no directory */
+ nhcount = 0; /* we didn't find anything there */
+ if (xx < 0) { /* Lookup error: */
+ ckmakmsg(tmpbuf,
+ TMPBUFSIZ,
+ "?Fatal network directory lookup error - ",
+ line,
+ "\n",
+ NULL
+ );
+ XFATAL(tmpbuf);
+ }
+ }
+#endif /* NOICP */
+#endif /* NODIAL */
+ /* Add service to line specification for ttopen() */
+ if (*service) { /* There is a service specified */
+ ckstrncat(line, ":",LINBUFSIZ);
+ ckstrncat(line, service,LINBUFSIZ);
+ ttnproto = NP_DEFAULT;
+ } else {
+ ckstrncat(line, ":telnet",LINBUFSIZ);
+ ttnproto = NP_TELNET;
+ }
+
+#ifndef NOICP
+#ifndef NODIAL
+ if ((nhcount > 1) && !quiet && !backgrd) {
+ printf("%d entr%s found for \"%s\"%s\n",
+ nhcount,
+ (nhcount == 1) ? "y" : "ies",
+ s,
+ (nhcount > 0) ? ":" : "."
+ );
+ for (i = 0; i < nhcount; i++)
+ printf("%3d. %s %-12s => %s\n",
+ i+1, n_name, nh_p2[i], nh_p[i]
+ );
+ }
+ if (nhcount == 0)
+ n = 1;
+ else
+ n = nhcount;
+#else
+ n = 1;
+ nhcount = 0;
+#endif /* NODIAL */
+ for (i = 0; i < n; i++) {
+#ifndef NODIAL
+ if (nhcount >= 1) {
+ /* Copy the current entry to line */
+ ckstrncpy(line,nh_p[i],LINBUFSIZ);
+ /* Check to see if the network entry contains a service */
+ for (s = line ; (*s != NUL) && (*s != ':'); s++)
+ ;
+ /* If directory does not have a service ... */
+ /* and the user specified one */
+ if (!*s && *service) {
+ ckstrncat(line, ":",LINBUFSIZ);
+ ckstrncat(line, service,LINBUFSIZ);
+ }
+ if (lookup(netcmd,nh_p2[i],nnets,&z) > -1) {
+ mdmtyp = 0 - netcmd[z].kwval;
+ } else {
+ printf(
+ "Error - network type \"%s\" not supported\n",
+ nh_p2[i]
+ );
+ continue;
+ }
+ }
+#endif /* NODIAL */
+ }
+#endif /* NOICP */
+ ckstrncpy(ttname, line,TTNAMLEN+1);
+ cxtype = CXT_TCPIP; /* Set connection type */
+ setflow(); /* Set appropriate flow control. */
+#ifdef SUNX25
+ } else if (x == 'X') { /* X.25 address */
+ nettype = NET_SX25;
+ mdmtyp = -nettype;
+ } else if (x == 'Z') { /* Open X.25 file descriptor */
+ nettype = NET_SX25;
+ mdmtyp = -nettype;
+ x25fd = 1;
+#endif /* SUNX25 */
+#ifdef STRATUSX25
+ } else if (x == 'X') { /* X.25 address */
+ nettype = NET_VX25;
+ mdmtyp = -nettype;
+#endif /* STRATUSX25 */
+#ifdef IBMX25
+ } else if (x == 'X') { /* X.25 address */
+ nettype = NET_IX25;
+ mdmtyp = -nettype;
+#endif /* IBMX25 */
+#ifdef HPX25
+ } else if (x == 'X') { /* X.25 address */
+ nettype = NET_HX25;
+ mdmtyp = -nettype;
+#endif /* HPX25 */
+ }
+ if (ttopen(ttname,&local,mdmtyp,0) < 0) {
+ XFATAL("can't open host connection");
+ }
+ network = 1;
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+ cxtype = CXT_X25; /* Set connection type */
+ setflow(); /* Set appropriate flow control. */
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+#endif /* NETCONN */
+ }
+ /* add more here -- decnet, etc... */
+ haveline = 1;
+ break;
+
+#ifdef ANYX25
+ case 'U': /* X.25 call user data */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing call user data string");
+ }
+ ckstrncpy(udata,*xargv,MAXCUDATA);
+ if ((int)strlen(udata) <= MAXCUDATA) {
+ cudata = 1;
+ } else {
+ XFATAL("Invalid call user data");
+ }
+ break;
+
+ case 'o': /* X.25 closed user group */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing closed user group index");
+ }
+ z = atoi(*xargv); /* Convert to number */
+ if (z >= 0 && z <= 99) {
+ closgr = z;
+ } else {
+ XFATAL("Invalid closed user group index");
+ }
+ break;
+
+ case 'u': /* X.25 reverse charge call */
+ revcall = 1;
+ break;
+#endif /* ANYX25 */
+#endif /* NOLOCAL */
+
+ case 'b': /* Bits-per-second for serial device */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing bps");
+ }
+ zz = atol(*xargv); /* Convert to long int */
+ i = zz / 10L;
+#ifndef NOLOCAL
+ if (ttsspd(i) > -1) /* Check and set it */
+#endif /* NOLOCAL */
+ speed = ttgspd(); /* and read it back. */
+#ifndef NOLOCAL
+ else {
+ XFATAL("unsupported transmission rate");
+ }
+#endif /* NOLOCAL */
+ break;
+
+#ifndef NODIAL
+#ifndef NOICP
+ case 'm': /* Modem type */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -m");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("modem type missing");
+ }
+ y = lookup(mdmtab,*xargv,nmdm,&z);
+ if (y < 0) {
+ XFATAL("unknown modem type");
+ }
+ usermdm = 0;
+ usermdm = (y == dialudt) ? x : 0;
+ initmdm(y);
+ break;
+#endif /* NOICP */
+#endif /* NODIAL */
+
+#ifndef NOXFER
+ case 'e': /* Extended packet length */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -e");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing length");
+ }
+ z = atoi(*xargv); /* Convert to number */
+ if (z > 10 && z <= maxrps) {
+ rpsiz = urpsiz = z;
+ if (z > 94) rpsiz = 94; /* Fallback if other Kermit can't */
+ } else {
+ XFATAL("Unsupported packet length");
+ }
+ break;
+
+ case 'v': /* Vindow size */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing or bad window size");
+ }
+ z = atoi(*xargv); /* Convert to number */
+ if (z < 32) { /* If in range */
+ wslotr = z; /* set it */
+ if (z > 1) swcapr = 1; /* Set capas bit if windowing */
+ } else {
+ XFATAL("Unsupported packet length");
+ }
+ break;
+#endif /* NOXFER */
+
+ case 'i': /* Treat files as binary */
+ binary = XYFT_B;
+ xfermode = XMODE_M; /* Transfer mode manual */
+ filepeek = 0;
+#ifdef PATTERNS
+ patterns = 0;
+#endif /* PATTERNS */
+ break;
+
+#ifndef NOXFER
+ case 'w': /* Writeover */
+ ckwarn = 0;
+ fncact = XYFX_X;
+ break;
+#endif /* NOXFER */
+
+ case 'q': /* Quiet */
+ quiet = 1;
+ break;
+
+#ifdef DEBUG
+ case 'd': /* DEBUG */
+ break; /* Handled in prescan() */
+#endif /* DEBUG */
+
+ case '0': { /* In the middle */
+ extern int tt_escape, lscapr;
+ tt_escape = 0; /* No escape character */
+ flow = 0; /* No Xon/Xoff (what about hwfc?) */
+#ifndef NOXFER
+ lscapr = 0; /* No locking shifts */
+#endif /* NOXFER */
+#ifdef CK_APC
+ {
+ extern int apcstatus; /* No APCs */
+ apcstatus = APC_OFF;
+ }
+#endif /* CK_APC */
+#ifndef NOLOCAL
+#ifdef CK_AUTODL
+ setautodl(0,0); /* No autodownload */
+#endif /* CK_AUTODL */
+#endif /* NOLOCAL */
+#ifndef NOCSETS
+ {
+ extern int tcsr, tcsl; /* No character-set translation */
+ tcsr = 0;
+ tcsl = tcsr; /* Make these equal */
+ }
+#endif /* NOCSETS */
+#ifdef TNCODE
+ TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = TN_NG_RF;
+ TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = TN_NG_RF;
+ TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = TN_NG_RF;
+#endif /* TNCODE */
+ }
+/* Fall thru... */
+
+ case '8': /* 8-bit clean */
+ parity = 0;
+ cmdmsk = 0xff;
+ cmask = 0xff;
+ break;
+
+ case 'V': {
+ extern int xfermode;
+#ifdef PATTERNS
+ extern int patterns;
+ patterns = 0; /* No patterns */
+#endif /* PATTERNS */
+ xfermode = XMODE_M; /* Manual transfer mode */
+ filepeek = 0;
+ break;
+ }
+
+ case 'p': /* SET PARITY */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing parity");
+ }
+ switch(x = **xargv) {
+ case 'e':
+ case 'o':
+ case 'm':
+ case 's': parity = x; break;
+ case 'n': parity = 0; break;
+ default: { XFATAL("invalid parity"); }
+ }
+ break;
+
+ case 't': /* Line turnaround handshake */
+ turn = 1;
+ turnch = XON; /* XON is turnaround character */
+ duplex = 1; /* Half duplex */
+ flow = 0; /* No flow control */
+ break;
+
+ case 'B':
+ bgset = 1; /* Force background (batch) */
+ backgrd = 1;
+ break;
+
+ case 'z': /* Force foreground */
+ bgset = 0;
+ backgrd = 0;
+ break;
+
+#ifndef NOXFER
+#ifdef RECURSIVE
+ case 'L':
+ recursive = 2;
+ nolinks = 2;
+ fnspath = PATH_REL;
+ break;
+#endif /* RECURSIVE */
+#endif /* NOXFER */
+
+#ifndef NOSPL
+ case 'M': /* My User Name */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing username");
+ }
+ if ((int)strlen(*xargv) > 63) {
+ XFATAL("username too long");
+ }
+#ifdef IKSD
+ if (!inserver)
+#endif /* IKSD */
+ {
+ ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
+ haveftpuid = 1;
+ }
+ break;
+#endif /* NOSPL */
+
+#ifdef CK_NETBIOS
+ case 'N': /* NetBios Adapter Number follows */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -N");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing NetBios Adapter number");
+ }
+ if ((strlen(*xargv) != 1) ||
+ (*xargv)[0] != 'X' &&
+ (atoi(*xargv) < 0) &&
+ (atoi(*xargv) > 9)) {
+ XFATAL("Invalid NetBios Adapter - Adapters 0 to 9 are valid");
+ }
+ break;
+#endif /* CK_NETBIOS */
+
+#ifdef NETCONN
+ case 'F':
+ network = 1;
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -F");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("network file descriptor missing");
+ }
+ ckstrncpy(ttname,*xargv,TTNAMLEN+1);
+ nettype = NET_TCPB;
+ mdmtyp = -nettype;
+ telnetfd = 1;
+ local = 1;
+ break;
+#endif /* NETCONN */
+
+#ifdef COMMENT
+#ifdef OS2PM
+ case 'P': /* OS/2 Presentation Manager */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -P");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("pipe data missing");
+ }
+ pipedata = *xargv;
+ break;
+#endif /* OS2PM */
+#else
+ case 'P': /* Filenames literal */
+ fncnv = XYFN_L;
+ f_save = XYFN_L;
+ break;
+#endif /* COMMENT */
+
+#ifndef NOICP
+ case 'H':
+ noherald = 1;
+ break;
+#endif /* NOICP */
+
+#ifdef OS2
+ case 'W':
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -W");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1)) { /* could be negative */
+ XFATAL("Window handle missing");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("Kermit Instance missing");
+ }
+ /* Action done in prescan */
+ break;
+
+ case '#': /* K95 stdio threads */
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+#endif /* OS2 */
+
+#ifdef NEWFTP
+ case '9': /* FTP */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling after -9");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("FTP server address missing");
+ }
+ makestr(&ftp_host,*xargv);
+ break;
+#endif /* NEWFTP */
+
+ default:
+ fatal2(*xargv,
+#ifdef NT
+ "invalid command-line option, type \"k95 -h\" for help"
+#else
+#ifdef OS2
+ "invalid command-line option, type \"k2 -h\" for help"
+#else
+ "invalid command-line option, type \"kermit -h\" for help"
+#endif /* OS2 */
+#endif /* NT */
+ );
+ }
+ if (!xp) break;
+ x = *++xp; /* See if options are bundled */
+ }
+ return(0);
+}
+
+#ifdef TNCODE
+/* D O T N A R G -- Do a telnet command-line argument. */
+
+static int
+#ifdef CK_ANSIC
+dotnarg(char x)
+#else
+dotnarg(x) char x;
+#endif /* CK_ANSIC */
+/* dotnarg */ {
+ char *xp;
+
+ xp = *xargv+1; /* Pointer for bundled args */
+ debug(F111,"dotnarg entry",xp,xargc);
+ while (x) {
+ debug(F000,"dotnarg arg","",x);
+ switch (x) { /* Big switch on arg */
+
+#ifndef COMMENT
+ case '-': /* Extended commands... */
+ if (doxarg(xargv,0) < 0) {
+ XFATAL("Extended option error");
+ } /* Full thru... */
+ case '+': /* Extended command for prescan() */
+ return(0);
+#else /* COMMENT */
+ case '-':
+ case '+':
+ XFATAL("Extended options not configured");
+#endif /* COMMENT */
+
+/*
+ * -# Kermit 95 Startup Flags
+ * -8 Negotiate Telnet Binary in both directions
+ * -a Require use of Telnet authentication
+ * -c Do not read the .telnetrc file
+ * -d Turn on debug mode
+ * -E No escape character
+ * -f Forward credentials to host
+ * -K Refuse use of authentication; do not send username
+ * -k realm Set default realm
+ * -l user Set username and request Telnet authentication
+ * -L Negotiate Telnet Binary Output only
+ * -q Quiet mode (suppress messages)
+ * -S tos Use the IP type-of-service tos
+ * -x Require Encryption
+ * -D Disable forward-X
+ * -T cert=file Use certificate in file
+ * -T key=file Use private key in file
+ * -T crlfile=file Use CRL in file
+ * -T crldir=dir Use CRLs in directory
+ * -T cipher=string Use only ciphers in string
+ * -X atype Disable use of atype authentication
+ * -Y Disable init file processing
+ *
+ */
+ case 'h': /* help */
+ usage();
+ doexit(GOOD_EXIT,-1);
+ break;
+
+ case '8': /* Telnet Binary in both directions */
+ TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_MU;
+ parity = 0;
+ cmdmsk = 0xff;
+ cmask = 0xff;
+ break;
+
+ case 'a': /* Require Telnet Auth */
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+
+ case 'Y':
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+
+#ifdef OS2
+ case '#': /* K95 stdio threads */
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+#endif /* OS2 */
+
+ case 'q': /* Quiet */
+ quiet = 1;
+ break;
+
+ case 'd':
+#ifdef DEBUG
+ if (deblog) {
+ debtim = 1;
+ } else {
+ deblog = debopn("debug.log",0);
+ }
+#endif /* DEBUG */
+ break;
+
+ case 'E': { /* No Escape character */
+ extern int tt_escape;
+ tt_escape = 0;
+ }
+ break;
+
+ case 'K':
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ uidbuf[0] = NUL;
+ break;
+
+ case 'l': /* Set username and request telnet authentication */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing username");
+ }
+ if ((int)strlen(*xargv) > 63) {
+ XFATAL("username too long");
+ }
+ ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+
+ case 'L': /* Require BINARY mode outbound only */
+ TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_MU;
+ break;
+
+ case 'x': /* Require Encryption */
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ break;
+
+ case 'D': /* Disable use of Forward X */
+ TELOPT_DEF_C_U_MODE(TELOPT_FORWARD_X) = TN_NG_RF;
+ break;
+
+ case 'f': /* Forward credentials to host */
+ {
+#ifdef CK_AUTHENTICATION
+ extern int forward_flag;
+ forward_flag = 1;
+#endif
+ break;
+ }
+
+ case 'k': {
+#ifdef CK_KERBEROS
+ extern char * krb5_d_realm, * krb4_d_realm;
+#endif /* CK_KERBEROS */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing realm");
+ }
+#ifdef CK_KERBEROS
+ if ((int)strlen(*xargv) > 63) {
+ XFATAL("realm too long");
+ }
+ makestr(&krb5_d_realm,*xargv);
+ makestr(&krb4_d_realm,*xargv);
+#endif /* CK_KERBEROS */
+ break;
+ }
+
+ case 'T': {
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing cert=, key=, crlfile=, crldir=, or cipher=");
+ }
+#ifdef CK_SSL
+ if (!strncmp(*xargv,"cert=",5)) {
+ extern char * ssl_rsa_cert_file;
+ makestr(&ssl_rsa_cert_file,&(*xargv[5]));
+ } else if ( !strncmp(*xargv,"key=",4) ) {
+ extern char * ssl_rsa_key_file;
+ makestr(&ssl_rsa_key_file,&(*xargv[4]));
+ } else if ( !strncmp(*xargv,"crlfile=",8) ) {
+ extern char * ssl_crl_file;
+ makestr(&ssl_crl_file,&(*xargv[8]));
+ } else if ( !strncmp(*xargv,"crldir=",7) ) {
+ extern char * ssl_crl_dir;
+ makestr(&ssl_crl_dir,&(*xargv[7]));
+ } else if ( !strncmp(*xargv,"cipher=",7) ) {
+ extern char * ssl_cipher_list;
+ makestr(&ssl_cipher_list,&(*xargv[7]));
+ } else {
+ XFATAL("invalid parameter");
+ }
+#endif /* CK_SSL */
+ break;
+ }
+
+ default:
+ fatal2(*xargv,
+ "invalid command-line option, type \"telnet -h\" for help"
+ );
+ }
+
+ if (!xp) break;
+ x = *++xp; /* See if options are bundled */
+ }
+ return(0);
+}
+#endif /* TNCODE */
+
+#ifdef RLOGCODE
+
+/* D O R L G A R G -- Do a rlogin command-line argument. */
+
+static int
+#ifdef CK_ANSIC
+dorlgarg(char x)
+#else
+dorlgarg(x) char x;
+#endif /* CK_ANSIC */
+/* dorlgarg */ {
+ char *xp;
+
+ xp = *xargv+1; /* Pointer for bundled args */
+ debug(F111,"dorlgarg entry",xp,xargc);
+ while (x) {
+ debug(F000,"dorlgarg arg","",x);
+ switch (x) { /* Big switch on arg */
+
+#ifndef COMMENT
+ case '-': /* Extended commands... */
+ if (doxarg(xargv,0) < 0) {
+ XFATAL("Extended option error");
+ } /* Full thru... */
+ case '+': /* Extended command for prescan() */
+ return(0);
+#else /* COMMENT */
+ case '-':
+ case '+':
+ XFATAL("Extended options not configured");
+#endif /* COMMENT */
+
+/*
+ * -d Debug
+ * -l user Set username
+ *
+ */
+ case 'h': /* help */
+ usage();
+ doexit(GOOD_EXIT,-1);
+ break;
+
+ case 'Y':
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+#ifdef OS2
+ case '#': /* K95 stdio threads */
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+#endif /* OS2 */
+ case 'q': /* Quiet */
+ quiet = 1;
+ break;
+
+ case 'd':
+#ifdef DEBUG
+ if (deblog) {
+ debtim = 1;
+ } else {
+ deblog = debopn("debug.log",0);
+ }
+#endif /* DEBUG */
+ break;
+
+ case 'l': /* Set username and request telnet authentication */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing username");
+ }
+ if ((int)strlen(*xargv) > 63) {
+ XFATAL("username too long");
+ }
+ ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
+ break;
+
+ default:
+ fatal2(*xargv,
+ "invalid command-line option, type \"rlogin -h\" for help"
+ );
+ }
+
+ if (!xp) break;
+ x = *++xp; /* See if options are bundled */
+ }
+ return(0);
+}
+#endif /* RLOGCODE */
+
+#ifdef SSHBUILTIN
+
+/* D O S S H A R G -- Do a ssh command-line argument. */
+
+static int
+#ifdef CK_ANSIC
+dossharg(char x)
+#else
+dossharg(x) char x;
+#endif /* CK_ANSIC */
+/* dossharg */ {
+ char *xp;
+
+ xp = *xargv+1; /* Pointer for bundled args */
+ debug(F111,"dossharg entry",xp,xargc);
+ while (x) {
+ debug(F000,"dossharg arg","",x);
+ switch (x) { /* Big switch on arg */
+
+#ifndef COMMENT
+ case '-': /* Extended commands... */
+ if (doxarg(xargv,0) < 0) {
+ XFATAL("Extended option error");
+ } /* Full thru... */
+ case '+': /* Extended command for prescan() */
+ return(0);
+#else /* COMMENTP */
+ case '-':
+ case '+':
+ XFATAL("Extended options not configured");
+#endif /* COMMENT */
+
+/*
+ * -d Debug
+ * -# args Init
+ * -Y no init file
+ * -l user Set username
+ *
+ */
+ case 'h': /* help */
+ usage();
+ doexit(GOOD_EXIT,-1);
+ break;
+
+ case 'Y':
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+#ifdef OS2
+ case '#': /* K95 stdio threads */
+ xargv++, xargc--; /* Skip past argument */
+ break; /* Action done in prescan */
+#endif /* OS2 */
+ case 'q': /* Quiet */
+ quiet = 1;
+ break;
+
+ case 'd':
+#ifdef DEBUG
+ if (deblog) {
+ debtim = 1;
+ } else {
+ deblog = debopn("debug.log",0);
+ }
+#endif /* DEBUG */
+ break;
+
+ case 'l': /* Set username and request telnet authentication */
+ if (*(xp+1)) {
+ XFATAL("invalid argument bundling");
+ }
+ xargv++, xargc--;
+ if ((xargc < 1) || (**xargv == '-')) {
+ XFATAL("missing username");
+ }
+ if ((int)strlen(*xargv) > 63) {
+ XFATAL("username too long");
+ }
+ ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
+ break;
+
+ default:
+ fatal2(*xargv,
+ "invalid command-line option, type \"ssh -h\" for help"
+ );
+ }
+
+ if (!xp) break;
+ x = *++xp; /* See if options are bundled */
+ }
+ return(0);
+}
+#endif /* SSHBUILTIN */
+
+#else /* No command-line interface... */
+
+int
+cmdlin() {
+ extern int xargc;
+ if (xargc > 1) {
+ XFATAL("Sorry, command-line options disabled.");
+ }
+}
+#endif /* NOCMDL */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuver.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckuver.h
new file mode 100644
index 0000000..7a111fb
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuver.h
@@ -0,0 +1,1262 @@
+/* ckuver.h -- C-Kermit UNIX Version heralds */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2010,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+#ifndef CKUVER_H
+#define CKUVER_H
+
+/* Arranged more or less alphabetically by compiler symbol */
+/* Must be included AFTER ckcdeb.h. */
+
+#ifdef BEOS
+#ifdef BEOS45
+#define HERALD " BeOS 4.5"
+#else
+#define HERALD " BeOS"
+#endif /* BEOS45 */
+#else
+#ifdef BEBOX
+#ifdef BE_DR_7
+#define HERALD " BeBox DR7"
+#else
+#define HERALD " BeBox"
+#endif /* BE_DR_7 */
+#endif /* BEBOX */
+#endif /* BEOS */
+
+#ifdef BELLV10
+#define HERALD " Bell Labs Research UNIX V10"
+#endif /* BELLV10 */
+
+#ifdef APOLLOSR10
+#define HERALD " Apollo SR10"
+#endif /* APOLLOSR10 */
+
+#ifdef MAC
+#define HERALD " Apple Macintosh"
+#endif /* MAC */
+
+#ifdef A986
+#define HERALD " Altos 986 / Xenix 3.0"
+#endif /* A986 */
+
+#ifdef AS400
+#define HERALD " AS/400"
+#endif /* AS400 */
+
+#ifdef aegis
+#ifdef BSD4
+#define HERALD " Apollo DOMAIN/IX 4.2 BSD"
+#else
+#ifdef ATTSV
+#define HERALD " Apollo DOMAIN/IX System V"
+#else
+#define HERALD " Apollo Aegis"
+#endif /* BSD4 */
+#endif /* ATTSV */
+#endif /* aegis */
+
+#ifndef HERALD
+
+#ifdef AIXRS
+
+#ifdef AIX53
+#define HERALD " IBM AIX 5.3"
+#else
+#ifdef AIX52
+#define HERALD " IBM AIX 5.2"
+#else
+#ifdef AIX51
+#define HERALD " IBM AIX 5.1"
+#else
+#ifdef AIX45
+#define HERALD " IBM AIX 5.0"
+#else
+#ifdef AIX45
+#define HERALD " IBM AIX 4.5"
+#else
+#ifdef AIX44
+#define HERALD " IBM AIX 4.4"
+#else
+#ifdef AIX43
+#define HERALD " IBM AIX 4.3"
+#else
+#ifdef AIX42
+#define HERALD " IBM AIX 4.2"
+#else
+#ifdef SVR4
+#ifdef AIX41
+#define HERALD " IBM AIX 4.1"
+#else
+#define HERALD " IBM RS/6000 AIX 3.2"
+#endif /* AIX41 */
+#else
+#define HERALD " IBM RS/6000 AIX 3.0/3.1"
+#endif /* SVR4 */
+#endif /* AIX42 */
+#endif /* AIX43 */
+#endif /* AIX44 */
+#endif /* AIX45 */
+#endif /* AIX50 */
+#endif /* AIX51 */
+#endif /* AIX52 */
+#endif /* AIX53 */
+#endif /* AIXRS */
+
+#ifdef PS2AIX10
+#define HERALD " IBM PS/2 AIX 1.x"
+#endif /* PS2AIX10 */
+
+#ifdef AIXPS2
+#define HERALD " IBM PS/2 AIX 3.x"
+#endif /* AIXPS2 */
+
+#ifdef AIX370
+#ifndef HERALD
+#define HERALD " IBM System/370 AIX/370"
+#endif
+#endif /* AIX370 */
+
+#ifdef AIXESA
+#ifndef HERALD
+#define HERALD " IBM AIX/ESA version 2.1"
+#endif
+#endif /* AIXESA */
+
+#ifdef ATT6300
+#define HERALD " AT&T 6300"
+#endif /* ATT6300 */
+
+#ifdef ATT7300
+#ifdef UNIX351M
+#define HERALD " AT&T 7300 UNIX PC UNIX 3.51m"
+#else
+#define HERALD " AT&T 7300 UNIX PC"
+#endif /* UNIX351M */
+#endif /* ATT7300 */
+
+#ifdef AUX
+#define HERALD " Apple Macintosh AUX"
+#endif /* AUX */
+
+#ifdef BSD44
+#ifdef MACOSX
+#define HERALD " Mac OS X"
+#else
+#ifdef __OpenBSD__
+#define HERALD " OpenBSD"
+#else
+#ifdef __bsdi__
+#ifdef BSDI4
+#define HERALD " BSDI BSD/OS 4.0"
+#else
+#ifdef BSDI3
+#define HERALD " BSDI BSD/OS 3.0"
+#else
+#ifdef BSDI2
+#define HERALD " BSDI BSD/OS 2.0" /* 1.1++ name... */
+#else
+#define HERALD " BSDI BSD/386" /* Original 1.0 name */
+#endif /* BSDI2 */
+#endif /* BSDI3 */
+#endif /* BSDI4 */
+#else /* __bsdi__ */
+#ifdef __NetBSD__
+#ifndef HERALD
+#ifdef NETBSD16
+#define HERALD " NetBSD 1.6"
+#else
+#ifdef NETBSD15
+#define HERALD " NetBSD 1.5"
+#else
+#define HERALD " NetBSD"
+#endif /* NETBSD15 */
+#endif /* NETBSD16 */
+#endif /* HERALD */
+#else /* __NetBSD__ */
+#ifdef __FreeBSD__
+#ifdef FREEBSD51
+#define HERALD " FreeBSD 5.1"
+#else
+#ifdef FREEBSD50
+#define HERALD " FreeBSD 5.0"
+#else
+#ifdef FREEBSD49
+#define HERALD " FreeBSD 4.9"
+#else
+#ifdef FREEBSD48
+#define HERALD " FreeBSD 4.8"
+#else
+#ifdef FREEBSD47
+#define HERALD " FreeBSD 4.7"
+#else
+#ifdef FREEBSD46
+#define HERALD " FreeBSD 4.6"
+#else
+#ifdef FREEBSD45
+#define HERALD " FreeBSD 4.5"
+#else
+#ifdef FREEBSD44
+#define HERALD " FreeBSD 4.4"
+#else
+#ifdef FREEBSD43
+#define HERALD " FreeBSD 4.3"
+#else
+#ifdef FREEBSD42
+#define HERALD " FreeBSD 4.2"
+#else
+#ifdef FREEBSD41
+#define HERALD " FreeBSD 4.1"
+#else
+#ifdef FREEBSD4
+#define HERALD " FreeBSD 4.0"
+#else
+#ifdef FREEBSD3
+#define HERALD " FreeBSD 3.0"
+#else
+#ifdef FREEBSD2
+#define HERALD " FreeBSD 2.0"
+#else
+#define HERALD " FreeBSD"
+#endif /* FREEBSD2 */
+#endif /* FREEBSD3 */
+#endif /* FREEBSD4 */
+#endif /* FREEBSD41 */
+#endif /* FREEBSD42 */
+#endif /* FREEBSD43 */
+#endif /* FREEBSD44 */
+#endif /* FREEBSD45 */
+#endif /* FREEBSD46 */
+#endif /* FREEBSD47 */
+#endif /* FREEBSD48 */
+#endif /* FREEBSD49 */
+#endif /* FREEBSD50 */
+#endif /* FREEBSD51 */
+#else
+#ifdef __386BSD__
+#define HERALD " 386BSD"
+#else
+#define HERALD " 4.4BSD"
+#endif /* __386BSD__ */
+#endif /* __FreeBSD__ */
+#endif /* __NetBSD__ */
+#endif /* __bsdi__ */
+#endif /* __OpenBSD__ */
+#endif /* MACOSX */
+#endif /* BSD44 */
+
+#ifdef ENCORE
+#ifdef BSD43
+#define HERALD " Encore Multimax UMAX 4.3"
+#else
+#define HERALD " Encore Multimax UMAX 4.2"
+#endif
+#endif /* ENCORE */
+
+#ifdef BSD29
+#define HERALD " 2.9 BSD"
+#endif /* BSD29 */
+
+#ifdef BSD41
+#define HERALD " 4.1 BSD"
+#endif /* BSD41 */
+
+#ifdef C70
+#define HERALD " BBN C/70"
+#endif /* c70 */
+
+#ifdef CIE
+#define HERALD " CIE Systems 680/20 Regulus"
+#endif /* CIE */
+
+#ifdef COHERENT
+#ifdef _I386
+#define HERALD " MWC Coherent 386 4.x"
+#ifndef i386
+#define i386
+#endif /* i386 */
+#else
+#define HERALD " PC/AT MWC Coherent 286 3.x"
+#ifndef i286
+#define i286
+#endif /* i286 */
+#endif /* _I386 */
+#endif /* COHERENT */
+
+#ifdef CONVEX9
+#define HERALD " Convex/OS"
+#endif /* CONVEX9 */
+
+#ifdef CONVEX10
+#define HERALD " Convex/OS 10.1"
+#endif /* CONVEX10 */
+
+#ifdef _CRAY
+#ifdef _CRAYCOM
+#define HERALD " Cray CSOS"
+#else /* _CRAYCOM */
+#define HERALD " Cray UNICOS"
+#endif /* _CRAYCOM */
+#endif /* _CRAY */
+
+#ifdef DGUX
+#ifdef DGUX54420
+#define HERALD " Data General DG/UX R4.20"
+#else
+#ifdef DGUX54411
+#define HERALD " Data General DG/UX R4.11"
+#else
+#ifdef DGUX54410
+#define HERALD " Data General DG/UX R4.10"
+#else
+#ifdef DGUX54310
+#define HERALD " Data General DG/UX 5.4R3.10"
+#else
+#ifdef DGUX543
+#define HERALD " Data General DG/UX 5.4R3.00"
+#else
+#ifdef DGUX540
+#define HERALD " Data General DG/UX 5.4"
+#else
+#ifdef DGUX430
+#define HERALD " Data General DG/UX 4.30"
+#else
+#define HERALD " Data General DG/UX"
+#endif /* DGUX430 */
+#endif /* DGUX540 */
+#endif /* DGUX543 */
+#endif /* DGUX54310 */
+#endif /* DGUX54410 */
+#endif /* DGUX54411 */
+#endif /* DGUX54420 */
+#endif /* DGUX */
+
+#ifdef datageneral
+#ifndef HERALD
+#define HERALD " Data General AOS/VS"
+#endif /* HERALD */
+#endif /* datageneral */
+
+#ifdef SINIX
+#ifdef SNI544
+#define HERALD " Siemens Nixdorf Reliant UNIX V5.44"
+#else
+#ifdef SNI543
+#define HERALD " Siemens Nixdorf Reliant UNIX V5.43"
+#else
+#ifdef SNI541
+#define HERALD " Siemens Nixdorf SINIX V5.41"
+#else
+#define HERALD " Siemens Nixdorf SINIX V5.42"
+#endif /* SNI541 */
+#endif /* SNI543 */
+#endif /* SNI544 */
+#endif /* SINIX */
+
+#ifdef POWERMAX
+#define HERALD " Concurrent PowerMAX OS"
+#endif /* POWERMAX */
+
+#ifdef DELL_SVR4
+#define HERALD " Dell System V R4"
+#endif /* DELL_SVR4 */
+
+#ifdef NCRMPRAS
+#define HERALD " NCR MP-RAS"
+#endif /* NCRMPRAS */
+
+#ifdef UNIXWARE
+#define HERALD " UnixWare"
+#else
+#ifdef OLD_UNIXWARE
+#define HERALD " UnixWare"
+#endif /* OLD_UNIXWARE */
+#endif /* UNIXWARE */
+
+#ifdef ICL_SVR4
+#define HERALD " ICL System V R4 DRS N/X"
+#endif /* ICL_SVR4 */
+
+#ifdef FT18
+#ifdef FT21
+#define HERALD " Fortune For:Pro 2.1"
+#else
+#define HERALD " Fortune For:Pro 1.8"
+#endif /* FT21 */
+#endif /* FT18 */
+
+#ifdef GEMDOS
+#define HERALD " Atari ST GEM 1.0"
+#endif /* GEMDOS */
+
+#ifdef XF68R3V6
+#define HERALD " Motorola UNIX System V/68 R3V6"
+#endif /* XF68R3V6 */
+
+#ifdef XF88R32
+#define HERALD " Motorola UNIX System V/88 R32"
+#endif /* XF88R32 */
+
+#ifdef I386IX
+#ifdef SVR3JC
+#define HERALD " Interactive UNIX System V/386 R3.2"
+#else
+#define HERALD " Interactive Systems Corp 386/ix"
+#endif /* SVR3JC */
+#endif /* I386IX */
+
+#ifdef IRIX65
+#define HERALD " Silicon Graphics IRIX 6.5"
+#else
+#ifdef IRIX64
+#define HERALD " Silicon Graphics IRIX 6.4"
+#else
+#ifdef IRIX63
+#define HERALD " Silicon Graphics IRIX 6.3"
+#else
+#ifdef IRIX62
+#define HERALD " Silicon Graphics IRIX 6.2"
+#else
+#ifdef IRIX60
+#define HERALD " Silicon Graphics IRIX 6.0"
+#else
+#ifdef IRIX53
+#define HERALD " Silicon Graphics IRIX 5.3"
+#else
+#ifdef IRIX52
+#define HERALD " Silicon Graphics IRIX 5.2"
+#else
+#ifdef IRIX51
+#define HERALD " Silicon Graphics IRIX 5.1"
+#else
+#ifdef IRIX40
+#define HERALD " Silicon Graphics IRIX 4.0"
+#endif /* IRIX40 */
+#endif /* IRIX51 */
+#endif /* IRIX52 */
+#endif /* IRIX53 */
+#endif /* IRIX60 */
+#endif /* IRIX62 */
+#endif /* IRIX63 */
+#endif /* IRIX64 */
+#endif /* IRIX65 */
+
+#ifdef ISIII
+#define HERALD " Interactive Systems Corp System III"
+#endif /* ISIII */
+
+#ifdef IX370
+#define HERALD " IBM IX/370"
+#endif /* IX370 */
+
+#ifdef HPUX
+#ifdef HPUX5
+#define HERALD " HP-UX 5.00"
+#else
+#ifdef HPUX6
+#define HERALD " HP-UX 6.00"
+#else
+#ifdef HPUX7
+#define HERALD " HP-UX 7.00"
+#else
+#ifdef HPUX8
+#define HERALD " HP-UX 8.00"
+#else
+#ifdef HPUX9
+#define HERALD " HP-UX 9.00"
+#else
+#ifdef HPUX1100
+#define HERALD " HP-UX 11.00"
+#else
+#ifdef HPUX10
+#ifdef HPUX1030
+#define HERALD " HP-UX 10.30"
+#else
+#ifdef HPUX1020
+#define HERALD " HP-UX 10.20"
+#else
+#ifdef HPUX1010
+#define HERALD " HP-UX 10.10"
+#else
+#ifdef HPUX10xx
+#define HERALD " HP-UX 10.xx"
+#else
+#define HERALD " HP-UX 10.00"
+#endif /* HPUX10XX */
+#endif /* HPUX1010 */
+#endif /* HPUX1020 */
+#endif /* HPUX1030 */
+#else
+#define HERALD " HP-UX"
+#endif /* HPUX10 */
+#endif /* HPUX1100 */
+#endif /* HPUX9 */
+#endif /* HPUX8 */
+#endif /* HPUX7 */
+#endif /* HPUX6 */
+#endif /* HPUX5 */
+#endif /* HPUX */
+
+#ifndef MINIX
+#ifdef MINIX315
+#define MINIX
+#endif /* MINIX315 */
+#endif /* MINIX */
+
+#ifndef MINIX
+#ifdef MINIX3
+#define MINIX
+#endif /* MINIX3 */
+#endif /* MINIX */
+
+#ifdef MINIX
+#ifdef MINIX315
+#define HERALD " Minix 3.1.5"
+#ifndef MINIX3
+#define MINIX3
+#endif /* MINIX3 */
+#endif /* MINIX315 */
+#ifdef MINIX3
+#ifndef MINIX2
+#define MINIX2
+#endif /* MINIX2 */
+#ifndef HERALD
+#define HERALD " Minix 3.0"
+#endif /* HERALD */
+#else
+#ifdef MINIX2
+#define HERALD " Minix 2.0"
+#else
+#define HERALD " Minix 1.0"
+#endif /* MINIX3 */
+#endif /* MINIX2 */
+#endif /* MINIX */
+
+#ifdef MIPS
+#define HERALD " MIPS RISC/OS SVR3"
+#endif /* MIPS */
+
+#ifdef NEXT
+#ifdef OPENSTEP42
+#define HERALD " OPENSTEP 4.2"
+#else
+#ifdef NEXT33
+#define HERALD " NeXTSTEP 3.3"
+#else
+#define HERALD " NeXTSTEP"
+#endif /* NEXT33 */
+#endif /* OPENSTEP42 */
+#endif /* NEXT */
+
+#ifdef OSF
+#ifdef i386
+#define HERALD " DECpc OSF/1"
+#ifdef __GNUC
+#define OSFPC
+#endif /* __GNUC */
+#else /* Not i386 so Alpha */
+
+#ifdef TRU64
+
+#ifdef OSF51B
+#define HERALD " Compaq Tru64 UNIX 5.1B"
+#else
+#ifdef OSF51A
+#define HERALD " Compaq Tru64 UNIX 5.1A"
+#else
+#ifdef OSF50
+#define HERALD " Compaq Tru64 UNIX 5.0A"
+#else
+#ifdef OSF40G
+#define HERALD " Compaq Tru64 UNIX 4.0G"
+#else
+#ifdef OSF40F
+#define HERALD " Compaq Tru64 UNIX 4.0F"
+#else
+#ifdef OSF40E
+#define HERALD " Compaq Tru64 UNIX 4.0E"
+#endif /* OSF40E */
+#endif /* OSF40F */
+#endif /* OSF40G */
+#endif /* OSF50 */
+#endif /* OSF51A */
+#endif /* OSF51B */
+
+#else /* Not TRU64 */
+
+#ifdef OSF40
+#define HERALD " Digital UNIX 4.0"
+#else
+#ifdef OSF32
+#define HERALD " Digital UNIX 3.2"
+#else
+#define HERALD " DEC OSF/1 Alpha"
+#endif /* OSF40 */
+#endif /* OSF32 */
+
+#endif /* TRU64 */
+#endif /* i386 */
+#endif /* OSF */
+
+#ifdef PCIX
+#define HERALD " PC/IX"
+#endif /* PCIX */
+
+#ifdef sxaE50
+#define HERALD " PFU SX/A V10/L50"
+#endif /* sxaE50 */
+
+#ifdef PROVX1
+#define HERALD " DEC Professional 300 (Venix 1.0)"
+#endif /* PROVX1 */
+
+#ifdef PYRAMID
+#ifdef SVR4
+#define HERALD " Pyramid DC/OSx"
+#else
+#define HERALD " Pyramid Dual Port OSx"
+#endif /* SVR4 */
+#endif /* PYRAMID */
+
+#ifdef RTAIX
+#define HERALD " IBM RT PC (AIX 2.2)"
+#endif /* RTAIX */
+
+#ifdef RTU
+#define HERALD " Masscomp/Concurrent RTU"
+#endif /* RTU */
+
+#ifdef sony_news
+#define HERALD " SONY NEWS"
+#endif /* sony_news */
+
+#ifdef SOLARIS24
+#define HERALD " Solaris 2.4"
+#else
+#ifdef SOLARIS23
+#define HERALD " Solaris 2.3"
+#else
+#ifdef SOLARIS
+#define HERALD " Solaris 2.x"
+#endif /* SOLARIS */
+#endif /* SOLARIS23 */
+#endif /* SOLARIS24 */
+
+#ifdef SUNOS4
+#ifdef BSD4
+#ifdef SUNOS41
+#define HERALD " SunOS 4.1"
+#else
+#define HERALD " SunOS 4.0"
+#endif /* SUNOS41 */
+#endif /* BSD4 */
+#endif /* SUNOS4 */
+
+#ifdef SUN4S5
+#ifdef HDBUUCP
+#define HERALD " SunOS 4.1 (SVR3)"
+#else
+#define HERALD " SunOS 4.0 (SVR3)"
+#endif /* HDBUUCP */
+#endif /* SUN4S5 */
+
+#ifdef STRATUS
+#define HERALD " Stratus VOS"
+#endif /* STRATUS */
+
+#ifdef TOWER1
+#define HERALD " NCR Tower 1632 OS 1.02"
+#endif /* TOWER1 */
+
+#ifdef TRS16
+#define HERALD " Tandy 16/6000 Xenix 3.0"
+#ifndef CKCPU
+#define CKCPU "mc68000"
+#endif /* CKCPU */
+#endif /* TRS16 */
+
+#ifdef u3b2
+#ifndef HERALD
+#ifdef SVR3
+#define HERALD " AT&T 3B2 System V R3"
+#else
+#define HERALD " AT&T 3B2 System V"
+#endif /* SVR3 */
+#endif /* HERALD */
+#endif /* u3b2 */
+
+#ifdef ultrix
+#ifdef vax
+#ifdef ULTRIX3
+#define HERALD " VAX/ULTRIX 3.0"
+#else
+#define HERALD " VAX/ULTRIX"
+#endif /* ULTRIX3 */
+#else
+#ifdef mips
+#ifdef ULTRIX43
+#define HERALD " DECstation/ULTRIX 4.3"
+#else
+#ifdef ULTRIX44
+#define HERALD " DECstation/ULTRIX 4.4"
+#else
+#ifdef ULTRIX45
+#define HERALD " DECstation/ULTRIX 4.5"
+#else
+#define HERALD " DECstation/ULTRIX"
+#endif /* ULTRIX45 */
+#endif /* ULTRIX44 */
+#endif /* ULTRIX43 */
+#else
+#define HERALD " ULTRIX"
+#endif /* mips */
+#endif /* vax */
+#endif /* ultrix */
+
+#ifdef OXOS
+#define HERALD " Olivetti X/OS"
+#endif /* OXOS */
+
+#ifdef _386BSD
+#define HERALD " 386BSD"
+#endif /* _386BSD */
+
+#ifdef POSIX
+#ifdef PTX
+#ifdef PTX4
+#define HERALD " DYNIX/ptx V4"
+#else
+#define HERALD " DYNIX/ptx"
+#endif /* PTX4 */
+#else /* PTX */
+#ifndef OSF /* Let OSF -DPOSIX keep previously defined HERALD */
+#ifdef HERALD
+#undef HERALD
+#endif /* HERALD */
+#endif /* OSF */
+#ifdef OU8
+#define HERALD " OpenUNIX 8"
+#else
+#ifdef UW7
+#define HERALD " Unixware 7"
+#else
+#ifdef QNX
+#ifdef QNX16
+#define HERALD " QNX 16-bit"
+#else
+#define HERALD " QNX 32-bit"
+#endif /* QNX16 */
+#else
+#ifdef NEUTRINO
+#define HERALD " QNX Neutrino 2"
+#else /* NEUTRINO */
+#ifdef QNX6
+#define HERALD " QNX6"
+#else /* QNX6 */
+#ifdef __linux__
+#ifdef ZSL5500
+#define HERALD " Sharp Zaurus SL-5500"
+#else
+#ifdef RH90
+#define HERALD " Red Hat Linux 9.0"
+#else
+#ifdef RH80
+#define HERALD " Red Hat Linux 8.0"
+#else
+#ifdef RH73
+#define HERALD " Red Hat Linux 7.3"
+#else
+#ifdef RH72
+#define HERALD " Red Hat Linux 7.2"
+#else
+#ifdef RH71
+#define HERALD " Red Hat Linux 7.1"
+#else
+#define HERALD " Linux"
+#endif /* RH71 */
+#endif /* RH72 */
+#endif /* RH73 */
+#endif /* RH80 */
+#endif /* RH90 */
+#endif /* ZSL5500 */
+#else /* __linux__ */
+#ifdef _386BSD /* 386BSD Jolix */
+#define HERALD " 386BSD"
+#else
+#ifdef LYNXOS /* Lynx OS 2.2 */
+#define HERALD " Lynx OS"
+#else
+#ifdef Plan9
+#define HERALD " Plan 9 from Bell Labs"
+#else
+#ifdef SOLARIS11
+#define HERALD " Solaris 11"
+#else
+#ifdef SOLARIS10
+#define HERALD " Solaris 10"
+#else
+#ifdef SOLARIS9
+#define HERALD " Solaris 9"
+#else
+#ifdef SOLARIS8
+#define HERALD " Solaris 8"
+#else
+#ifdef SOLARIS7
+#define HERALD " Solaris 7"
+#else
+#ifdef SOLARIS26
+#define HERALD " Solaris 2.6"
+#else
+#ifdef SOLARIS25
+#define HERALD " Solaris 2.5"
+#else
+#ifdef SOLARIS24
+#define HERALD " Solaris 2.4"
+#else
+#ifdef SOLARIS
+#define HERALD " Solaris 2.x"
+#endif /* SOLARIS */
+#endif /* SOLARIS24 */
+#endif /* SOLARIS25 */
+#endif /* SOLARIS26 */
+#endif /* SOLARIS7 */
+#endif /* SOLARIS8 */
+#endif /* SOLARIS9 */
+#endif /* SOLARIS10 */
+#endif /* SOLARIS11 */
+#endif /* Plan9 */
+#endif /* LYNXOS */
+#endif /* _386BSD */
+#endif /* __linux__ */
+#endif /* QNX6 */
+#endif /* NEUTRINO */
+#endif /* QNX */
+#endif /* UW7 */
+#endif /* OU8 */
+#endif /* PTX */
+#endif /* POSIX */
+
+#ifdef UTS24
+#define HERALD " Amdahl UTS 2.4"
+#endif /* UTS24 */
+
+#ifdef UTSV
+#define HERALD " Amdahl UTS V"
+#endif /* UTSV */
+
+#ifdef VXVE
+#define HERALD " CDC VX/VE 5.2.1 System V"
+#endif /* VXVE */
+
+#ifdef SCO234
+#ifdef HERALD
+#undef HERALD
+#endif /* HERALD */
+#define HERALD " SCO XENIX 2.3.4"
+#else
+#ifdef CK_SCO32V4
+#ifdef HERALD
+#undef HERALD
+#endif /* HERALD */
+#ifdef ODT30
+#define HERALD " SCO ODT 3.0"
+#else
+#define HERALD " SCO UNIX/386 V4"
+#endif /* ODT30 */
+#else
+#ifdef CK_SCOV5
+#ifdef HERALD
+#undef HERALD
+#endif /* HERALD */
+#ifdef SCO_OSR507
+#define HERALD " SCO OpenServer R5.0.7"
+#else
+#ifdef SCO_OSR506A
+#define HERALD " SCO OpenServer R5.0.6a"
+#else
+#ifdef SCO_OSR506
+#define HERALD " SCO OpenServer R5.0.6"
+#else
+#ifdef SCO_OSR505
+#define HERALD " SCO OpenServer R5.0.5"
+#else
+#ifdef SCO_OSR504
+#define HERALD " SCO OpenServer R5.0.4"
+#else
+#ifdef SCO_OSR502
+#define HERALD " SCO OpenServer R5.0.2"
+#else
+#define HERALD " SCO OpenServer R5.0"
+#endif /* SCO_OSR502 */
+#endif /* SCO_OSR504 */
+#endif /* SCO_OSR505 */
+#endif /* SCO_OSR506 */
+#endif /* SCO_OSR506A */
+#endif /* SCO_OSR507 */
+#else
+#ifdef XENIX
+#ifdef HERALD
+#undef HERALD
+#endif /* HERALD */
+#ifdef M_UNIX
+#define HERALD " SCO UNIX/386"
+#else
+#ifdef M_I386
+#define HERALD " Xenix/386"
+#else
+#ifdef M_I286
+#define HERALD " Xenix/286"
+#else
+#define HERALD " Xenix"
+#endif /* M_I286 */
+#endif /* M_I386 */
+#endif /* M_UNIX */
+#endif /* XENIX */
+#endif /* CK_SCOV5 */
+#endif /* CK_SCOV32V4 */
+#endif /* SCO234 */
+
+#ifdef ZILOG
+#define HERALD " Zilog S8000 Zeus 3.21+"
+#endif /* ZILOG */
+
+#ifdef UTEK
+#define HERALD " UTek"
+#endif /* UTEK */
+
+/* Catch-alls for anything not defined explicitly above */
+
+#ifndef HERALD
+#ifdef SVR4
+#ifdef i386
+#define HERALD " AT&T System V/386 R4"
+#else
+#ifdef AMIX
+#define HERALD " Commodore Amiga System V/m68k R4"
+#else
+#define HERALD " AT&T System V R4"
+#endif /* AMIX */
+#endif /* i386 */
+#else
+#ifdef SVR3
+#define HERALD " AT&T System V R3"
+#else
+#ifdef ATTSV
+#define HERALD " AT&T System III / System V"
+#else
+#ifdef BSD43
+#ifdef pdp11
+#define HERALD " 2.10 BSD PDP-11"
+#else
+#ifdef vax
+#define HERALD " 4.3 BSD VAX"
+#else
+#define HERALD " 4.3 BSD"
+#endif /* vax */
+#endif /* pdp11 */
+#else
+#ifdef BSD4
+#ifdef vax
+#define HERALD " 4.2 BSD VAX"
+#else
+#define HERALD " 4.2 BSD"
+#endif /* vax */
+#else
+#ifdef V7
+#define HERALD " UNIX Version 7"
+#endif /* V7 */
+#endif /* BSD4 */
+#endif /* BSD43 */
+#endif /* ATTSV */
+#endif /* SVR3 */
+#endif /* SVR4 */
+#endif /* HERALD */
+#endif /* HERALD */
+
+#ifdef OS2
+#ifdef HERALD
+#undef HERALD
+#endif /* HERALD */
+#ifdef NT
+#define HERALD " 32-bit Windows"
+#else /* NT */
+#define HERALD " 32-bit OS/2"
+#endif /* NT */
+#endif /* OS/2 */
+
+#ifndef HERALD
+#define HERALD " Unknown Version"
+#endif /* HERALD */
+
+/* Hardware type */
+
+#ifdef vax /* DEC VAX */
+#ifndef CKCPU
+#define CKCPU "vax"
+#endif /* CKCPU */
+#endif /* vax */
+#ifdef pdp11 /* DEC PDP-11 */
+#ifndef CKCPU
+#define CKCPU "pdp11"
+#endif /* CKCPU */
+#endif /* pdp11 */
+
+#ifdef __ALPHA /* DEC Alpha */
+#ifndef CKCPU
+#define CKCPU "Alpha"
+#endif /* CKCPU */
+#endif /* __ALPHA */
+
+#ifdef __alpha /* OSF/1 uses lowercase... */
+#ifndef CKCPU
+#define CKCPU "Alpha"
+#endif /* CKCPU */
+#endif /* __alpha */
+
+#ifdef DGUX /* Override Motorola 88k assumption */
+#ifndef CKCPU /* New AViiONs are Intel based... */
+#ifdef i586
+#define CKCPU "i586"
+#else
+#ifdef i486
+#define CKCPU "i486"
+#else
+#ifdef i386
+#define CKCPU "i386"
+#endif /* i386 */
+#endif /* i486 */
+#endif /* i586 */
+#endif /* CKCPU */
+#endif /* DGUX */
+
+/* HP 9000 */
+
+#ifdef __hp9000s700
+#ifndef CKCPU
+#define CKCPU "hp9000s700"
+#endif /* CKCPU */
+#endif /* __hp9000s700 */
+
+#ifdef __hp9000s800
+#ifndef CKCPU
+#define CKCPU "hp9000s800"
+#endif /* CKCPU */
+#endif /* __hp9000s800 */
+
+#ifdef __hp9000s500
+#ifndef CKCPU
+#define CKCPU "hp9000s500"
+#endif /* CKCPU */
+#endif /* __hp9000s500 */
+
+#ifdef __hp9000s400
+#ifndef CKCPU
+#define CKCPU "hp9000s400"
+#endif /* CKCPU */
+#endif /* __hp9000s400 */
+
+#ifdef __hp9000s300
+#ifndef CKCPU
+#define CKCPU "hp9000s300"
+#endif /* CKCPU */
+#endif /* __hp9000s300 */
+
+#ifdef __hp9000s200
+#ifndef CKCPU
+#define CKCPU "hp9000s200"
+#endif /* CKCPU */
+#endif /* __hp9000s200 */
+
+#ifdef m88000 /* Motorola 88000 */
+#ifndef CKCPU
+#define CKCPU "mc88000"
+#endif /* CKCPU */
+#endif /* m88000 */
+#ifdef __using_M88KBCS /* DG symbol for Motorola 88000 */
+#ifndef CKCPU
+#define CKCPU "mc88000"
+#endif /* CKCPU */
+#endif /* __using_M88KBCS */
+#ifdef m88k /* Motorola symbol for 88000 */
+#ifndef CKCPU
+#define CKCPU "mc88000"
+#endif /* CKCPU */
+#endif /* m88k */
+#ifdef mc68040 /* Motorola 68040 */
+#ifndef CKCPU
+#define CKCPU "mc68040"
+#endif /* CKCPU */
+#endif /* mc68040 */
+#ifdef mc68030 /* Motorola 68030 */
+#ifndef CKCPU
+#define CKCPU "mc68030"
+#endif /* CKCPU */
+#endif /* mc68030 */
+#ifdef mc68020 /* Motorola 68020 */
+#ifndef CKCPU
+#define CKCPU "mc68020"
+#endif /* CKCPU */
+#endif /* mc68020 */
+#ifdef mc68010 /* Motorola 68010 */
+#ifndef CKCPU
+#define CKCPU "mc68010"
+#endif /* CKCPU */
+#endif /* mc68010 */
+#ifdef mc68000 /* Motorola 68000 */
+#ifndef CKCPU
+#define CKCPU "mc68000"
+#endif /* CKCPU */
+#endif /* mc68000 */
+#ifdef mc68k /* Ditto (used by DIAB DS90) */
+#ifndef CKCPU
+#define CKCPU "mc68000"
+#endif /* CKCPU */
+#endif /* mc68k */
+#ifdef m68 /* Ditto */
+#ifndef CKCPU
+#define CKCPU "mc68000"
+#endif /* CKCPU */
+#endif /* m68 */
+#ifdef m68k /* Ditto */
+#ifndef CKCPU
+#define CKCPU "mc68000"
+#endif /* CKCPU */
+#endif /* m68k */
+
+#ifdef ia64 /* IA64 / Itanium */
+#ifndef CKCPU
+#define CKCPU "ia64"
+#endif /* CKCPU */
+#endif /* i686 */
+
+#ifdef i686 /* Intel 80686 */
+#ifndef CKCPU
+#define CKCPU "i686"
+#endif /* CKCPU */
+#endif /* i686 */
+
+#ifdef i586 /* Intel 80586 */
+#ifndef CKCPU
+#define CKCPU "i586"
+#endif /* CKCPU */
+#endif /* i586 */
+
+#ifdef i486 /* Intel 80486 */
+#ifndef CKCPU
+#define CKCPU "i486"
+#endif /* CKCPU */
+#endif /* i80486 */
+#ifdef i386 /* Intel 80386 */
+#ifndef CKCPU
+#define CKCPU "i386"
+#endif /* CKCPU */
+#endif /* i80386 */
+#ifdef i286 /* Intel 80286 */
+#ifndef CKCPU
+#define CKCPU "i286"
+#endif /* CKCPU */
+#endif /* i286 */
+#ifdef i186 /* Intel 80186 */
+#ifndef CKCPU
+#define CKCPU "i186"
+#endif /* CKCPU */
+#endif /* i186 */
+#ifdef M_I586 /* Intel 80586 */
+#ifndef CKCPU
+#define CKCPU "i586"
+#endif /* CKCPU */
+#endif /* M_I586 */
+#ifdef M_I486 /* Intel 80486 */
+#ifndef CKCPU
+#define CKCPU "i486"
+#endif /* CKCPU */
+#endif /* M_I486 */
+#ifdef _M_I386 /* Intel 80386 */
+#ifndef CKCPU
+#define CKCPU "i386"
+#endif /* CKCPU */
+#endif /* _M_I386 */
+#ifdef M_I286 /* Intel 80286 */
+#ifndef CKCPU
+#define CKCPU "i286"
+#endif /* CKCPU */
+#endif /* M_I286 */
+#ifdef M_I86 /* Intel 80x86 */
+#ifndef CKCPU
+#define CKCPU "ix86"
+#endif /* CKCPU */
+#endif /* M_I86 */
+#ifdef sparc /* SUN SPARC */
+#ifndef CKCPU
+#define CKCPU "sparc"
+#endif /* CKCPU */
+#endif /* sparc */
+#ifdef mips /* MIPS RISC processor */
+#ifndef CKCPU
+#define CKCPU "mips"
+#endif /* CKCPU */
+#endif /* mips */
+#ifdef _IBMR2 /* IBM RS/6000 */
+#ifndef CKCPU /* (what do they call the chip?) */
+#define CKCPU "rs6000"
+#endif /* CKCPU */
+#endif /* rs6000 */
+#ifdef u3b5 /* WE32000 MAC-32, AT&T 3Bx */
+#ifndef CKCPU
+#define CKCPU "u3b5"
+#endif /* CKCPU */
+#endif /* u3b5 */
+#ifdef n3b
+#ifndef CKCPU
+#define CKCPU "n3b"
+#endif /* CKCPU */
+#endif /* n3b */
+#ifdef u3b
+#ifndef CKCPU
+#define CKCPU "u3b"
+#endif /* CKCPU */
+#endif /* u3b */
+#ifdef n16 /* Encore Multimax */
+#ifndef CKCPU
+#define CKCPU "n16"
+#endif /* CKCPU */
+#endif /* n16 */
+#ifdef u370 /* IBM 370 */
+#ifndef CKCPU
+#define CKCPU "u370"
+#endif /* CKCPU */
+#endif /* u370 */
+#ifdef MAC /* Macintosh catch-all */
+#ifndef CKCPU
+#define CKCPU "mc68000"
+#endif /* CKCPU */
+#endif /* MAC */
+
+#ifdef STRATUS
+#ifndef CKCPU
+#ifdef __I860__
+#define CKCPU "I860 Family"
+#else
+#ifdef __MC68K__
+#define CKCPU "MC680x0 Family"
+#else
+#define CKCPU "Stratus unknown processor"
+#endif /* __MC68K__ */
+#endif /* __I860__ */
+#endif /* CKCPU */
+#endif /* STRATUS */
+
+#ifdef COMMENT
+#ifndef CKCPU /* All others */
+#define CKCPU "unknown"
+#endif /* CKCPU */
+#endif /* COMMENT */
+
+#endif /* CKUVER_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuxla.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckuxla.c
new file mode 100644
index 0000000..d5566fa
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuxla.c
@@ -0,0 +1,7588 @@
+#include "ckcsym.h"
+
+#include "ckcdeb.h" /* Includes... */
+#include "ckcker.h"
+#include "ckucmd.h"
+#include "ckcxla.h"
+
+#ifdef NOXFER
+#define zdstuff(a)
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+char *xlav = "Character Set Translation 9.0.044, 2 Jun 2011";
+
+/* C K U X L A */
+
+/* C-Kermit tables and functions supporting character set translation. */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2011,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/* Character set translation data and functions */
+
+extern int zincnt; /* File i/o macros and variables */
+extern char *zinptr;
+extern int zoutcnt;
+extern char *zoutptr;
+extern int byteorder;
+extern int xfrxla;
+
+int tslevel = TS_L0; /* Transfer syntax level (0,1,2) */
+int tcharset = TC_TRANSP; /* Transfer syntax character set */
+int tcs_save = -1; /* For save/restore term charset */
+int tcs_transp = 0; /* Term charset is TRANSPARENT flag */
+
+#ifdef CKOUNI
+int tcsr = TX_8859_1; /* Remote terminal character set */
+#else /* CKOUNI */
+int tcsr = FC_USASCII;
+#endif /* CKOUNI */
+int language = L_USASCII; /* Language */
+
+#ifdef UNICODE
+int ucsbom = 1; /* Add BOM to new UCS files? */
+int ucsorder = -1; /* Default byte order for UCS files */
+int fileorder = -1; /* Byte order of current file */
+ /* 0 = BE, 1 = LE */
+#endif /* UNICODE */
+/*
+ Default local file and terminal character set.
+ Normally ASCII, but for some systems we know otherwise.
+*/
+int fcs_save = -1;
+#ifdef datageneral /* Data General AOS/VS */
+int fcharset = FC_DGMCS; /* uses the DG International set */
+int dcset8 = FC_DGMCS;
+int dcset7 = FC_USASCII;
+int tcsl = FC_DGMCS;
+#else
+#ifdef NEXT /* The NeXT workstation */
+int fcharset = FC_NEXT; /* uses its own 8-bit set */
+int dcset8 = FC_NEXT;
+int dcset7 = FC_USASCII;
+int tcsl = FC_NEXT;
+#else
+#ifdef MAC /* The Macintosh */
+int fcharset = FC_APPQD; /* uses an extended version of */
+int dcset8 = FC_APPQD;
+int dcset7 = FC_USASCII;
+int tcsl = FC_APPQD; /* Apple Quickdraw */
+#else
+#ifdef AUX
+int fcharset = FC_APPQD; /* Ditto for Apple A/UX */
+int dcset8 = FC_APPQD;
+int dcset7 = FC_USASCII;
+int tcsl = FC_APPQD;
+#else
+#ifdef AMIGA /* The Commodore Amiga */
+int fcharset = FC_1LATIN; /* uses Latin-1 */
+int dcset8 = FC_1LATIN;
+int dcset7 = FC_USASCII;
+int tcsl = FC_1LATIN;
+#else /* All others */
+#ifdef CKOUNI /* OS/2 Unicode */
+int fcharset = FC_1LATIN;
+int dcset8 = FC_1LATIN;
+int dcset7 = FC_USASCII;
+int tcsl = TX_8859_1;
+int prncs = TX_CP437;
+#else /* All others */
+int fcharset = FC_USASCII; /* use ASCII by default */
+int dcset8 = FC_1LATIN; /* But default 8-bit set is Latin-1 */
+int dcset7 = FC_USASCII;
+int tcsl = FC_USASCII;
+int prncs = FC_CP437;
+#endif /* CKOUNI */
+#endif /* AMIGA */
+#endif /* AUX */
+#endif /* MAC */
+#endif /* NEXT */
+#endif /* datageneral */
+
+int s_cset = XMODE_A; /* SEND charset selection = AUTO */
+int r_cset = XMODE_A; /* RECV charset selection = AUTO */
+int afcset[MAXFCSETS+1]; /* Character-set associations */
+int axcset[MAXTCSETS+1];
+int xlatype = XLA_NONE; /* Translation type */
+
+#ifdef UNICODE
+#ifdef CK_ANSIC
+extern int (*xl_utc[MAXTCSETS+1])(USHORT); /* Unicode to TCS */
+extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
+extern USHORT (*xl_tcu[MAXTCSETS+1])(CHAR); /* TCS to Unicode */
+extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
+#else
+extern int (*xl_utc[MAXTCSETS+1])();
+extern int (*xl_ufc[MAXFCSETS+1])();
+extern USHORT (*xl_tcu[MAXTCSETS+1])();
+extern USHORT (*xl_fcu[MAXFCSETS+1])();
+#endif /* CK_ANSIC */
+#endif /* UNICODE */
+
+/* Bureaucracy section */
+
+_PROTOTYP( CHAR xnel1, (CHAR c) ); /* NeXT to Latin-1 */
+_PROTOTYP( CHAR xl143, (CHAR c) ); /* Latin-1 to IBM CP437 */
+_PROTOTYP( CHAR xl1as, (CHAR c) ); /* Latin-1 to US ASCII */
+_PROTOTYP( CHAR zl1as, (CHAR c) ); /* Latin-1 to US ASCII */
+
+#ifdef CYRILLIC
+_PROTOTYP( CHAR xassk, (CHAR c) ); /* ASCII to Short KOI */
+_PROTOTYP( CHAR xskcy, (CHAR c) ); /* Short KOI to Latin/Cyrillic */
+#endif /* CYRILLIC */
+
+#ifdef LATIN2
+_PROTOTYP( CHAR xnel2, (CHAR c) ); /* NeXT to Latin-2 */
+_PROTOTYP( CHAR xl243, (CHAR c) ); /* Latin-2 to IBM CP437 */
+_PROTOTYP( CHAR xl2as, (CHAR c) ); /* Latin-2 to US ASCII */
+_PROTOTYP( CHAR zl2as, (CHAR c) ); /* Latin-2 to US ASCII */
+_PROTOTYP( CHAR xl2r8, (CHAR c) ); /* Latin-2 to HP */
+_PROTOTYP( CHAR xl2l9, (CHAR c) ); /* Latin-2 to Latin-9 */
+_PROTOTYP( CHAR xl9l2, (CHAR c) ); /* Latin-9 to Latin-2 */
+_PROTOTYP( CHAR xl2mz, (CHAR c) ); /* Latin-2 to Mazovia */
+_PROTOTYP( CHAR xmzl2, (CHAR c) ); /* Mazovia to Latin-2 */
+_PROTOTYP( CHAR xl1mz, (CHAR c) ); /* Latin-1 to Mazovia */
+_PROTOTYP( CHAR xmzl1, (CHAR c) ); /* Mazovia to Latin-1 */
+_PROTOTYP( CHAR xmzl9, (CHAR c) ); /* Latin-9 to Mazovia */
+_PROTOTYP( CHAR xl9mz, (CHAR c) ); /* Mazovia to Latin-9 */
+#endif /* LATIN2 */
+
+/* Transfer character-set info */
+
+struct csinfo tcsinfo[] = {
+/* Name size code designator alphabet keyword */
+ "TRANSPARENT", 256,TC_TRANSP, "", AL_UNK, "transparent", /* 0 */
+ "ASCII", 128,TC_USASCII,"", AL_ROMAN,"ascii", /* 1 */
+ "ISO 8859-1 Latin-1",256,TC_1LATIN, "I6/100",AL_ROMAN,"latin1-iso", /* 2 */
+#ifdef LATIN2
+ "ISO 8859-2 Latin-2",256,TC_2LATIN, "I6/101",AL_ROMAN,"latin2-iso", /* 3 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ /* 4 */
+ "ISO 8859-5 Latin/Cyrillic",256,TC_CYRILL,"I6/144",AL_CYRIL,"cyrillic-iso",
+#endif /* CYRILLIC */
+#ifdef KANJI
+ "Japanese EUC",16384,TC_JEUC, "I14/87/13", AL_JAPAN, "euc-jp", /* 5 */
+#endif /* KANJI */
+#ifdef HEBREW
+ /* 6 */
+ "ISO 8859-8 Latin/Hebrew",256,TC_HEBREW,"I6/138",AL_HEBREW,"hebrew-iso",
+#endif /* HEBREW */
+#ifdef GREEK
+ "ISO 8859-7 Latin/Greek",256,TC_GREEK,"I6/126",AL_GREEK,"greek-iso", /* 7 */
+#endif /* GREEK */
+ "ISO 8859-15 Latin-9",256,TC_9LATIN,"I6/203",AL_ROMAN,"latin9-iso", /* 8 */
+ "ISO 10646 / Unicode UCS-2",64000,TC_UCS2,"I162",AL_UNIV,"ucs2", /* 9 */
+ "ISO 10646 / Unicode UTF-8",64000,TC_UTF8,"I190",AL_UNIV,"utf8", /* 10 */
+ "",0,0,"",0,""
+};
+int ntcsets = (sizeof(tcsinfo) / sizeof(struct csinfo)) - 1;
+
+struct keytab tcstab[] = { /* Keyword table for */
+ "ascii", TC_USASCII, 0, /* SET TRANSFER CHARACTER-SET */
+#ifdef CYRILLIC
+ "cyrillic-iso", TC_CYRILL, 0,
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "elot928-greek", TC_GREEK, CM_INV,
+#endif /* GREEK */
+#ifdef KANJI
+ "euc-jp", TC_JEUC, 0,
+#endif /* KANJI */
+#ifdef GREEK
+ "greek-iso", TC_GREEK, 0,
+#endif /* GREEK */
+#ifdef HEBREW
+ "hebrew-iso", TC_HEBREW, 0,
+#endif /* HEBREW */
+
+#ifdef UNICODE
+ "iso-10646-ucs-2", TC_UCS2, CM_INV, /* ISO 10646 / Unicode UCS-2 */
+#endif /* UNICODE */
+ "iso-8859-1", TC_1LATIN, CM_INV, /* ISO Latin Alphabet 1 */
+ "iso-8859-15", TC_9LATIN, CM_INV, /* ISO Latin Alphabet 9 (yes) */
+ "iso-8859-2", TC_2LATIN, CM_INV, /* ISO Latin Alphabet 2 */
+#ifdef CYRILLIC
+ "iso-8859-5", TC_CYRILL, CM_INV, /* ISO Latin/Cyrillic Alphabet */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "iso-8859-7", TC_GREEK, CM_INV, /* ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+#ifdef HEBREW
+ "iso-8859-8", TC_HEBREW, CM_INV, /* ISO Latin/Hebrew */
+#endif /* HEBREW */
+
+#ifdef KANJI
+ "japanese-euc", TC_JEUC, CM_INV,
+#endif /* KANJI */
+ "l", TC_1LATIN, CM_ABR|CM_INV,
+ "la", TC_1LATIN, CM_ABR|CM_INV,
+ "lat", TC_1LATIN, CM_ABR|CM_INV,
+ "lati", TC_1LATIN, CM_ABR|CM_INV,
+ "latin", TC_1LATIN, CM_ABR|CM_INV,
+ "latin1-iso", TC_1LATIN, 0,
+#ifdef LATIN2
+ "latin2-iso", TC_2LATIN, 0,
+#endif /* LATIN2 */
+ "latin9-iso", TC_9LATIN, 0,
+ "transparent", TC_TRANSP, 0,
+#ifdef UNICODE
+ "ucs2", TC_UCS2, 0,
+#endif /* UNICODE */
+ "us-ascii", TC_USASCII, CM_INV,
+ "usascii", TC_USASCII, CM_INV,
+#ifdef UNICODE
+ "utf-8", TC_UTF8, CM_INV,
+ "utf8", TC_UTF8, 0,
+#endif /* UNICODE */
+ "", 0, 0
+};
+int ntcs = (sizeof(tcstab) / sizeof(struct keytab)) - 1;
+
+/* File character set information structure, indexed by character set code, */
+/* as defined in ckuxla.h. This table must be in order of file character */
+/* set number! */
+
+struct csinfo fcsinfo[] = { /* File character set information... */
+ /* Descriptive Name Size Designator */
+ "US ASCII", 128, FC_USASCII, NULL, AL_ROMAN, "ascii",
+ "British/UK ISO-646", 128, FC_UKASCII, NULL, AL_ROMAN, "british",
+ "Dutch ISO-646", 128, FC_DUASCII, NULL, AL_ROMAN, "dutch",
+ "Finnish ISO-646", 128, FC_FIASCII, NULL, AL_ROMAN, "finnish",
+ "French ISO-646", 128, FC_FRASCII, NULL, AL_ROMAN, "french",
+ "Canadian-French NRC", 128, FC_FCASCII, NULL, AL_ROMAN, "canadian-french",
+ "German ISO-646", 128, FC_GEASCII, NULL, AL_ROMAN, "german",
+ "Hungarian ISO-646", 128, FC_HUASCII, NULL, AL_ROMAN, "hungarian",
+ "Italian ISO-646", 128, FC_ITASCII, NULL, AL_ROMAN, "italian",
+ "Norwegian/Danish ISO-646",128,FC_NOASCII,NULL,AL_ROMAN,"norwegian/danish",
+ "Portuguese ISO-646", 128, FC_POASCII, NULL, AL_ROMAN,"portuguese",
+ "Spanish ISO-646", 128, FC_SPASCII, NULL, AL_ROMAN, "spanish",
+ "Swedish ISO-646", 128, FC_SWASCII, NULL, AL_ROMAN, "swedish",
+ "Swiss NRC", 128, FC_CHASCII, NULL, AL_ROMAN, "swiss",
+ "ISO 8859-1 Latin-1", 256, FC_1LATIN, NULL, AL_ROMAN,"latin1-iso",
+ "ISO 8859-2 Latin-2", 256, FC_2LATIN, NULL, AL_ROMAN,"latin2-iso",
+ "DEC Multinational", 256, FC_DECMCS, NULL,AL_ROMAN,"dec-multinational",
+ "NeXT Multinational", 256, FC_NEXT, NULL,AL_ROMAN,"next-multinational",
+ "PC Code Page 437", 256, FC_CP437, NULL, AL_ROMAN,"cp437",
+ "PC Code Page 850", 256, FC_CP850, NULL, AL_ROMAN,"cp850",
+ "PC Code Page 852", 256, FC_CP852, NULL, AL_ROMAN,"cp852",
+ "Apple Macintosh Latin", 256, FC_APPQD, NULL, AL_ROMAN,"macintosh-latin",
+ "Data General International",256,FC_DGMCS,NULL,AL_ROMAN,"dg-international",
+ "Hewlett Packard Roman8", 256, FC_HPR8, NULL, AL_ROMAN, "hp-roman8",
+ "ISO 8859-5 Latin/Cyrillic", 256, FC_CYRILL, NULL, AL_CYRIL,"cyrillic-iso",
+ "CP866 Cyrillic", 256, FC_CP866, NULL, AL_CYRIL,"cp866",
+ "Short KOI", 128, FC_KOI7, NULL, AL_CYRIL,"short-koi",
+ "Old KOI-8 Cyrillic", 256, FC_KOI8, NULL, AL_CYRIL,"koi8-cyrillic",
+ "Japanese JIS7", 16384, FC_JIS7, NULL, AL_JAPAN, "jis7-kanji",
+ "Japanese Shift JIS", 16384, FC_SHJIS, NULL, AL_JAPAN, "shift-jis-kanji",
+ "Japanese EUC", 16384, FC_JEUC, NULL, AL_JAPAN, "euc-jp",
+ "Japanese DEC Kanji", 16384, FC_JDEC, NULL, AL_JAPAN, "dec-kanji",
+ "Hebrew-7 DEC", 128, FC_HE7, NULL, AL_HEBREW, "hebrew-7",
+ "ISO 8859-8 Latin/Hebrew",256, FC_HEBREW, NULL, AL_HEBREW, "hebrew-iso",
+ "CP862 Hebrew", 256, FC_CP862, NULL, AL_HEBREW, "cp862-hebrew",
+ "ELOT 927 Greek", 128, FC_ELOT, NULL, AL_GREEK, "elot927-greek",
+ "ISO 8859-7 Latin/Greek", 256, FC_GREEK, NULL, AL_GREEK, "greek-iso",
+ "CP869 Greek", 256, FC_CP869, NULL, AL_GREEK, "cp869-greek",
+ "ISO 8859-15 Latin-9", 256, FC_9LATIN, NULL, AL_ROMAN, "latin9-iso",
+ "PC Code Page 858", 256, FC_CP850, NULL, AL_ROMAN, "cp858",
+ "PC Code Page 855", 256, FC_CP855, NULL, AL_CYRIL, "cp855-cyrillic",
+ "Windows Code Page 1251", 256, FC_CP1251, NULL, AL_CYRIL, "cp1251-cyrillic",
+ "Bulgarian PC Code Page", 256, FC_BULGAR, NULL, AL_CYRIL, "bulgaria-pc",
+ "Windows Code Page 1250", 256, FC_CP1250, NULL, AL_ROMAN, "cp1250",
+ "Polish Mazovia PC Code Page", 256, FC_MAZOVIA, NULL, AL_ROMAN, "mazovia-pc",
+ "ISO 10646 / Unicode UCS-2", 64000, FC_UCS2, NULL, AL_UNIV, "ucs2",
+ "ISO 10646 / Unicode UTF-8", 64000, FC_UCS2, NULL, AL_UNIV, "utf8",
+ "KOI8-R Russian+Boxdrawing",256, FC_KOI8R, NULL, AL_CYRIL,"koi8r",
+ "KOI8-U Ukrainian+Boxdrawing",256,FC_KOI8U, NULL, AL_CYRIL,"koi8u",
+ "Windows Code Page 1252", 256, FC_CP1252, NULL, AL_ROMAN, "cp1252",
+ "",0,0,NULL,0,NULL
+};
+
+/* Local file character sets */
+/* Includes 7-bit National Replacement Character Sets of ISO 646 */
+/* Plus ISO Latin-1, DEC Multinational Character Set (MCS), NeXT char set, */
+/* Various PC and Windows code pages, etc. */
+/* As of C-Kermit 9.0 MIME names are included as invisible synomyms for */
+/* those character sets that have MIME names. */
+
+struct keytab fcstab[] = { /* Keyword table for 'set file character-set' */
+/*
+ IMPORTANT: This table is replicated below as ttcstab (terminal character
+ set table). The only differences are the addition of TRANSPARENT
+ and the removal of the Kanji sets, which are not supported for terminal
+ emulation. If you make changes to this table, also change ttcstab.
+*/
+
+/* Keyword Value Flags */
+ "apple-quickdraw", FC_APPQD, CM_INV, /* Apple Quickdraw */
+ "ascii", FC_USASCII, 0, /* ASCII */
+ "british", FC_UKASCII, 0, /* British NRC */
+ "bulgaria-pc", FC_BULGAR, 0, /* Bulgarian PC Code Page */
+ "canadian-french", FC_FCASCII, 0, /* French Canadian NRC */
+#ifdef LATIN2
+ "cp1250", FC_CP1250, 0, /* Windows CP 1250 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "cp1251-cyrillic", FC_CP1251, 0, /* Windows CP 1251 */
+#endif /* CYRILLIC */
+ "cp1252", FC_CP1252, 0, /* Windows CP 1252 */
+ "cp437", FC_CP437, 0, /* PC CP437 */
+ "cp850", FC_CP850, 0, /* PC CP850 */
+#ifdef LATIN2
+ "cp852", FC_CP852, 0, /* PC CP852 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "cp855-cyrillic", FC_CP855, 0, /* PC CP855 */
+#endif /* CYRILLIC */
+ "cp858", FC_CP858, 0, /* PC CP858 */
+#ifdef HEBREW
+ "cp862-hebrew", FC_CP862, 0, /* PC CP862 */
+#endif /* HEBREW */
+#ifdef CYRILLIC
+ "cp866-cyrillic", FC_CP866, 0, /* CP866 Cyrillic */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "cp869-greek", FC_CP869, 0, /* CP869 Greek */
+#endif /* GREEK */
+#ifdef CYRILLIC
+ "cyrillic-iso", FC_CYRILL, 0, /* ISO Latin/Cyrillic Alphabet */
+#endif /* CYRILLIC */
+ "danish", FC_NOASCII, 0, /* Norwegian and Danish NRC */
+#ifdef KANJI
+ "dec-kanji", FC_JDEC, 0, /* Japanese DEC Kanji */
+#endif /* KANJI */
+ "dec-mcs", FC_DECMCS, CM_INV, /* DEC multinational char set */
+ "dec-multinational", FC_DECMCS, 0, /* DEC multinational character set */
+ "dg-international", FC_DGMCS, 0, /* Data General multinational */
+ "dutch", FC_DUASCII, 0, /* Dutch NRC */
+#ifdef GREEK
+ "elot927-greek", FC_ELOT, 0, /* ELOT 927 Greek */
+ "elot928-greek", FC_GREEK, 0, /* Same as ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+#ifdef KANJI
+ "euc-jp", FC_JEUC, 0, /* Japanese EUC */
+#endif /* KANJI */
+ "finnish", FC_FIASCII, 0, /* Finnish NRC */
+ "french", FC_FRASCII, 0, /* French NRC */
+ "fr-canadian", FC_FCASCII, CM_INV, /* French Canadian NRC */
+ "german", FC_GEASCII, 0, /* German NRC */
+#ifdef GREEK
+ "greek-iso", FC_GREEK, 0, /* ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+#ifdef HEBREW
+ "he", FC_HEBREW, CM_ABR|CM_INV,
+ "heb", FC_HEBREW, CM_ABR|CM_INV,
+ "hebr", FC_HEBREW, CM_ABR|CM_INV,
+ "hebre", FC_HEBREW, CM_ABR|CM_INV,
+ "hebrew", FC_HEBREW, CM_ABR|CM_INV,
+ "hebrew-7", FC_HE7, 0, /* DEC 7-Bit Hebrew */
+ "hebrew-iso", FC_HEBREW, 0, /* ISO Latin/Hebrew */
+#endif /* HEBREW */
+ "hp-roman8", FC_HPR8, 0, /* Hewlett Packard Roman8 */
+ "hungarian", FC_HUASCII, 0, /* Hungarian NRC */
+
+ "ibm437", FC_CP437, CM_INV, /* PC CP437 */
+ "ibm850", FC_CP850, CM_INV, /* PC CP850 (not in MIME) */
+#ifdef LATIN2
+ "ibm852", FC_CP852, CM_INV, /* PC CP852 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "ibm855", FC_CP855, CM_INV, /* PC CP855 */
+#endif /* CYRILLIC */
+ "ibm858", FC_CP858, CM_INV, /* PC CP858 (not in MIME) */
+#ifdef HEBREW
+ "ibm862", FC_CP862, CM_INV, /* PC CP862 (not in MIME) */
+#endif /* HEBREW */
+#ifdef CYRILLIC
+ "ibm866", FC_CP866, CM_INV, /* CP866 Cyrillic */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "ibm869", FC_CP869, CM_INV, /* CP869 Greek */
+#endif /* GREEK */
+
+#ifdef UNICODE
+ "iso-10646-ucs-2", FC_UCS2, CM_INV, /* ISO 10646 / Unicode UCS-2 */
+#endif /* UNICODE */
+ "iso-8859-1", FC_1LATIN, CM_INV, /* ISO Latin Alphabet 1 */
+ "iso-8859-15", FC_9LATIN, CM_INV, /* ISO Latin Alphabet 9 (yes) */
+ "iso-8859-2", FC_2LATIN, CM_INV, /* ISO Latin Alphabet 2 */
+#ifdef CYRILLIC
+ "iso-8859-5", FC_CYRILL, CM_INV, /* ISO Latin/Cyrillic Alphabet */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "iso-8859-7", FC_GREEK, CM_INV, /* ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+#ifdef HEBREW
+ "iso-8859-8", FC_HEBREW, CM_INV, /* ISO Latin/Hebrew */
+#endif /* HEBREW */
+#ifdef KANJI
+ "iso2022jp-kanji", FC_JIS7, CM_INV, /* Synonym for JIS-7 */
+#endif /* KANJI */
+
+ "iso646-gb", FC_UKASCII, CM_INV, /* British NRC */
+ "iso646-ca", FC_FCASCII, CM_INV, /* French Canadian NRC */
+ "iso646-de", FC_GEASCII, CM_INV, /* German NRC */
+ "iso646-dk", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */
+ "iso646-es", FC_SPASCII, CM_INV, /* Spanish NRC */
+ "iso646-fi", FC_FIASCII, CM_INV, /* Finnish NRC */
+ "iso646-fr", FC_FRASCII, CM_INV, /* French NRC */
+ "iso646-hu", FC_HUASCII, CM_INV, /* Hungarian NRC */
+ "iso646-it", FC_ITASCII, CM_INV, /* Italian NRC */
+ "iso646-no", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */
+ "iso646-po", FC_POASCII, CM_INV, /* Portuguese NRC */
+ "iso646-se", FC_SWASCII, CM_INV, /* Swedish NRC */
+
+ "italian", FC_ITASCII, CM_INV, /* Italian NRC */
+#ifdef KANJI
+ "japanese-euc", FC_JEUC, CM_INV, /* Japanese EUC */
+ "jis7-kanji", FC_JIS7, 0, /* Japanese JIS7 7bit code */
+#endif /* KANJI */
+#ifdef CYRILLIC
+ "k", FC_KOI8, CM_ABR|CM_INV,
+ "ko", FC_KOI8, CM_ABR|CM_INV,
+ "koi", FC_KOI8, CM_ABR|CM_INV,
+ "koi7", FC_KOI7, 0, /* Short KOI Cyrillic */
+ "koi8", FC_KOI8, 0, /* Old KOI-8 Cyrillic */
+ "koi8-e", FC_KOI8, CM_INV, /* Old KOI-8 Cyrillic */
+ "koi8-cyrillic", FC_KOI8, CM_INV,
+ "koi8-r", FC_KOI8R, CM_INV, /* KOI8-R RFC1489 */
+ "koi8-u", FC_KOI8U, CM_INV, /* KOI8-U RFC2319 */
+ "koi8r", FC_KOI8R, 0, /* KOI8-R RFC1489 */
+ "koi8u", FC_KOI8U, 0, /* KOI8-U RFC2319 */
+#endif /* CYRILLIC */
+ "l", FC_1LATIN, CM_ABR|CM_INV,
+ "la", FC_1LATIN, CM_ABR|CM_INV,
+ "lat", FC_1LATIN, CM_ABR|CM_INV,
+ "lati", FC_1LATIN, CM_ABR|CM_INV,
+ "latin", FC_1LATIN, CM_ABR|CM_INV,
+ "latin1-iso", FC_1LATIN, 0, /* ISO Latin Alphabet 1 */
+#ifdef LATIN2
+ "latin2-iso", FC_2LATIN, 0, /* ISO Latin Alphabet 2 */
+#endif /* LATIN2 */
+ "latin9-iso", FC_9LATIN, 0, /* ISO Latin Alphabet 9 */
+ "macintosh-latin", FC_APPQD, 0, /* "Extended Mac Latin" */
+#ifdef LATIN2
+ "mazovia-pc", FC_MAZOVIA, 0, /* Polish Mazovia PC code page */
+#endif /* LATIN2 */
+ "next-multinational", FC_NEXT, 0, /* NeXT workstation */
+ "norwegian", FC_NOASCII, 0, /* Norwegian and Danish NRC */
+ "portuguese", FC_POASCII, 0, /* Portuguese NRC */
+#ifdef KANJI
+ "shift-jis-kanji", FC_SHJIS, 0, /* Japanese Kanji Shift-JIS */
+ "shift_jis", FC_SHJIS, CM_INV, /* Japanese Kanji Shift-JIS */
+#endif /* KANJI */
+#ifdef CYRILLIC
+ "short-koi", FC_KOI7, 0, /* Short KOI Cyrillic */
+#endif /* CYRILLIC */
+ "spanish", FC_SPASCII, 0, /* Spanish NRC */
+ "swedish", FC_SWASCII, 0, /* Swedish NRC */
+ "swiss", FC_CHASCII, 0, /* Swiss NRC */
+#ifdef UNICODE
+ "ucs2", FC_UCS2, 0, /* ISO 10646 / Unicode UCS-2 */
+#endif /* UNICODE */
+ "us-ascii", FC_USASCII, CM_INV, /* MIME */
+ "usascii", FC_USASCII, CM_INV,
+#ifdef UNICODE
+ "utf-8", FC_UTF8, CM_INV, /* ISO 10646 / Unicode UTF-8 */
+ "utf8", FC_UTF8, 0, /* ISO 10646 / Unicode UTF-8 */
+#endif /* UNICODE */
+#ifdef LATIN2
+ "windows-1250", FC_CP1250, CM_INV, /* Windows CP 1250 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "windows-1251", FC_CP1251, CM_INV, /* Windows CP 1251 */
+#endif /* CYRILLIC */
+ "windows-1252", FC_CP1252, CM_INV, /* Windows CP 1252 */
+ "", 0, 0
+};
+int nfilc = (sizeof(fcstab) / sizeof(struct keytab)) - 1;
+
+struct keytab ttcstab[] = { /* Keyword table for SET TERMINAL CHARACTER-SET */
+/*
+ IMPORTANT: This table is a replica of fcstab, immediately above, with the
+ addition of TRANSPARENT and deletion of the Japanese sets. If you make
+ changes to this table, make the corresponding changes to fcstab.
+*/
+/* Keyword Value Flags */
+ "apple-quickdraw", FC_APPQD, CM_INV, /* Apple Quickdraw */
+ "ascii", FC_USASCII, 0, /* ASCII */
+ "british", FC_UKASCII, 0, /* British NRC */
+ "bulgaria-pc", FC_BULGAR, 0, /* Bulgarian PC Code Page */
+ "canadian-french", FC_FCASCII, 0, /* French Canadian NRC */
+#ifdef LATIN2
+ "cp1250", FC_CP1250, 0, /* Windows CP 1250 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "cp1251-cyrillic", FC_CP1251, 0, /* Windows CP 1251 */
+#endif /* CYRILLIC */
+ "cp1252", FC_CP1252, 0, /* Windows CP 1252 */
+ "cp437", FC_CP437, 0, /* PC CP437 */
+ "cp850", FC_CP850, 0, /* PC CP850 */
+#ifdef LATIN2
+ "cp852", FC_CP852, 0, /* PC CP852 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "cp855-cyrillic", FC_CP855, 0, /* PC CP855 */
+#endif /* CYRILLIC */
+ "cp858", FC_CP858, 0, /* PC CP858 */
+#ifdef HEBREW
+ "cp862-hebrew", FC_CP862, 0, /* PC CP862 */
+#endif /* HEBREW */
+#ifdef CYRILLIC
+ "cp866-cyrillic", FC_CP866, 0, /* CP866 Cyrillic */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "cp869-greek", FC_CP869, 0, /* CP869 Greek */
+#endif /* GREEK */
+#ifdef CYRILLIC
+ "cyrillic-iso", FC_CYRILL, 0, /* ISO Latin/Cyrillic Alphabet */
+#endif /* CYRILLIC */
+ "danish", FC_NOASCII, 0, /* Norwegian and Danish NRC */
+ "dec-mcs", FC_DECMCS, CM_INV, /* DEC multinational char set */
+ "dec-multinational", FC_DECMCS, 0, /* DEC multinational character set */
+ "dg-international", FC_DGMCS, 0, /* Data General multinational */
+ "dutch", FC_DUASCII, 0, /* Dutch NRC */
+#ifdef GREEK
+ "elot927-greek", FC_ELOT, 0, /* ELOT 927 Greek */
+ "elot928-greek", FC_GREEK, 0, /* Same as ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+ "finnish", FC_FIASCII, 0, /* Finnish NRC */
+ "french", FC_FRASCII, 0, /* French NRC */
+ "fr-canadian", FC_FCASCII, CM_INV, /* French Canadian NRC */
+ "german", FC_GEASCII, 0, /* German NRC */
+#ifdef GREEK
+ "greek-iso", FC_GREEK, 0, /* ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+#ifdef HEBREW
+ "he", FC_HEBREW, CM_ABR|CM_INV,
+ "heb", FC_HEBREW, CM_ABR|CM_INV,
+ "hebr", FC_HEBREW, CM_ABR|CM_INV,
+ "hebre", FC_HEBREW, CM_ABR|CM_INV,
+ "hebrew", FC_HEBREW, CM_ABR|CM_INV,
+ "hebrew-7", FC_HE7, 0, /* DEC 7-Bit Hebrew */
+ "hebrew-iso", FC_HEBREW, 0, /* ISO Latin/Hebrew */
+#endif /* HEBREW */
+ "hp-roman8", FC_HPR8, 0, /* Hewlett Packard Roman8 */
+ "hungarian", FC_HUASCII, 0, /* Hungarian NRC */
+
+ "ibm437", FC_CP437, CM_INV, /* PC CP437 */
+ "ibm850", FC_CP850, CM_INV, /* PC CP850 (not in MIME) */
+#ifdef LATIN2
+ "ibm852", FC_CP852, CM_INV, /* PC CP852 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "ibm855", FC_CP855, CM_INV, /* PC CP855 */
+#endif /* CYRILLIC */
+ "ibm858", FC_CP858, CM_INV, /* PC CP858 (not in MIME) */
+#ifdef HEBREW
+ "ibm862", FC_CP862, CM_INV, /* PC CP862 (not in MIME) */
+#endif /* HEBREW */
+#ifdef CYRILLIC
+ "ibm866", FC_CP866, CM_INV, /* CP866 Cyrillic */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "ibm869", FC_CP869, CM_INV, /* CP869 Greek */
+#endif /* GREEK */
+
+#ifdef UNICODE
+ "iso-10646-ucs-2", FC_UCS2, CM_INV, /* ISO 10646 / Unicode UCS-2 */
+#endif /* UNICODE */
+ "iso-8859-1", FC_1LATIN, CM_INV, /* ISO Latin Alphabet 1 */
+ "iso-8859-15", FC_9LATIN, CM_INV, /* ISO Latin Alphabet 9 (yes) */
+ "iso-8859-2", FC_2LATIN, CM_INV, /* ISO Latin Alphabet 2 */
+#ifdef CYRILLIC
+ "iso-8859-5", FC_CYRILL, CM_INV, /* ISO Latin/Cyrillic Alphabet */
+#endif /* CYRILLIC */
+#ifdef GREEK
+ "iso-8859-7", FC_GREEK, CM_INV, /* ISO 8859-7 Latin/Greek */
+#endif /* GREEK */
+#ifdef HEBREW
+ "iso-8859-8", FC_HEBREW, CM_INV, /* ISO Latin/Hebrew */
+#endif /* HEBREW */
+
+ "iso646-gb", FC_UKASCII, CM_INV, /* British NRC */
+ "iso646-ca", FC_FCASCII, CM_INV, /* French Canadian NRC */
+ "iso646-de", FC_GEASCII, CM_INV, /* German NRC */
+ "iso646-dk", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */
+ "iso646-es", FC_SPASCII, CM_INV, /* Spanish NRC */
+ "iso646-fi", FC_FIASCII, CM_INV, /* Finnish NRC */
+ "iso646-fr", FC_FRASCII, CM_INV, /* French NRC */
+ "iso646-hu", FC_HUASCII, CM_INV, /* Hungarian NRC */
+ "iso646-it", FC_ITASCII, CM_INV, /* Italian NRC */
+ "iso646-no", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */
+ "iso646-po", FC_POASCII, CM_INV, /* Portuguese NRC */
+ "iso646-se", FC_SWASCII, CM_INV, /* Swedish NRC */
+
+ "italian", FC_ITASCII, CM_INV, /* Italian NRC */
+
+#ifdef CYRILLIC
+ "k", FC_KOI8, CM_ABR|CM_INV,
+ "ko", FC_KOI8, CM_ABR|CM_INV,
+ "koi", FC_KOI8, CM_ABR|CM_INV,
+ "koi7", FC_KOI7, 0, /* Short KOI Cyrillic */
+ "koi8", FC_KOI8, 0, /* Old KOI-8 Cyrillic */
+ "koi8-e", FC_KOI8, CM_INV, /* Old KOI-8 Cyrillic */
+ "koi8-cyrillic", FC_KOI8, CM_INV,
+ "koi8-r", FC_KOI8R, CM_INV, /* KOI8-R RFC1489 */
+ "koi8-u", FC_KOI8U, CM_INV, /* KOI8-U RFC2319 */
+ "koi8r", FC_KOI8R, 0, /* KOI8-R RFC1489 */
+ "koi8u", FC_KOI8U, 0, /* KOI8-U RFC2319 */
+#endif /* CYRILLIC */
+ "l", FC_1LATIN, CM_ABR|CM_INV,
+ "la", FC_1LATIN, CM_ABR|CM_INV,
+ "lat", FC_1LATIN, CM_ABR|CM_INV,
+ "lati", FC_1LATIN, CM_ABR|CM_INV,
+ "latin", FC_1LATIN, CM_ABR|CM_INV,
+ "latin1-iso", FC_1LATIN, 0, /* ISO Latin Alphabet 1 */
+#ifdef LATIN2
+ "latin2-iso", FC_2LATIN, 0, /* ISO Latin Alphabet 2 */
+#endif /* LATIN2 */
+ "latin9-iso", FC_9LATIN, 0, /* ISO Latin Alphabet 9 */
+ "macintosh-latin", FC_APPQD, 0, /* "Extended Mac Latin" */
+#ifdef LATIN2
+ "mazovia-pc", FC_MAZOVIA, 0, /* Polish Mazovia PC code page */
+#endif /* LATIN2 */
+ "next-multinational", FC_NEXT, 0, /* NeXT workstation */
+ "norwegian", FC_NOASCII, 0, /* Norwegian and Danish NRC */
+ "portuguese", FC_POASCII, 0, /* Portuguese NRC */
+
+#ifdef CYRILLIC
+ "short-koi", FC_KOI7, 0, /* Short KOI Cyrillic */
+#endif /* CYRILLIC */
+ "spanish", FC_SPASCII, 0, /* Spanish NRC */
+ "swedish", FC_SWASCII, 0, /* Swedish NRC */
+ "swiss", FC_CHASCII, 0, /* Swiss NRC */
+ "transparent", FC_TRANSP, 0, /* Transparent */
+#ifdef UNICODE
+ "ucs2", FC_UCS2, 0, /* ISO 10646 / Unicode UCS-2 */
+#endif /* UNICODE */
+ "us-ascii", FC_USASCII, CM_INV, /* MIME */
+ "usascii", FC_USASCII, CM_INV,
+#ifdef UNICODE
+ "utf-8", FC_UTF8, CM_INV, /* ISO 10646 / Unicode UTF-8 */
+ "utf8", FC_UTF8, 0, /* ISO 10646 / Unicode UTF-8 */
+#endif /* UNICODE */
+#ifdef LATIN2
+ "windows-1250", FC_CP1250, CM_INV, /* Windows CP 1250 */
+#endif /* LATIN2 */
+#ifdef CYRILLIC
+ "windows-1251", FC_CP1251, CM_INV, /* Windows CP 1251 */
+#endif /* CYRILLIC */
+ "windows-1252", FC_CP1252, CM_INV, /* Windows CP 1252 */
+ "", 0, 0
+};
+int ntermc = (sizeof(ttcstab) / sizeof(struct keytab)) - 1;
+
+/* This table contains the equivalent FCS number for each TCS. */
+/* If the TC_xxx symbol definitions are ever changed, fix this table. */
+/* Ditto if another TCS is added. */
+
+int
+cseqtab[MAXTCSETS+1] = { /* TCS/FCS equivalency table */
+ -1, /* 0 = Transparent */
+ FC_USASCII, /* 1 = ASCII */
+ FC_1LATIN, /* 2 = Latin-1 */
+ FC_2LATIN, /* 3 = Latin-2 */
+ FC_CYRILL, /* 4 = Latin/Cyrillic */
+ FC_JEUC, /* 5 = Japanese EUC */
+ FC_HEBREW, /* 6 = Latin/Hebrew */
+ FC_GREEK, /* 7 = Latin/Greek */
+ FC_9LATIN, /* 8 = Latin-9 */
+ FC_UCS2, /* 9 = UCS-2 */
+ FC_UTF8 /* 10 = UTF-8 */
+};
+
+/*
+ Languages:
+
+ This table allows C-Kermit to have a SET LANGUAGE command to apply special
+ language-specific rules when translating from a character set that contains
+ national characters into plain ASCII, like German umlaut-a becomes ae.
+
+ Originally, I thought it would be a good idea to let SET LANGUAGE also select
+ an appropriate FILE CHARACTER-SET and TRANSFER CHARACTER-SET automatically,
+ and these are included in the langinfo structure. Later I realized that this
+ was a bad idea. Any particular language (e.g. Dutch) can be represented by
+ many different and incompatible character sets.
+
+ (But we could use the new (1998) ASSOCIATE command for this...)
+*/
+
+struct langinfo langs[] = {
+/* Language code File Charset Xfer Charset Name */
+ L_USASCII, FC_USASCII, TC_USASCII, "ASCII (American English)",
+ L_DANISH, FC_NOASCII, TC_1LATIN, "Danish",
+ L_DUTCH, FC_DUASCII, TC_1LATIN, "Dutch",
+ L_FINNISH, FC_FIASCII, TC_1LATIN, "Finnish",
+ L_FRENCH, FC_FRASCII, TC_1LATIN, "French",
+ L_GERMAN, FC_GEASCII, TC_1LATIN, "German",
+#ifdef GREEK
+ L_GREEK, FC_GREEK, TC_GREEK, "Greek",
+#endif /* GREEK */
+#ifdef HEBREW
+ L_HEBREW, FC_HEBREW, TC_HEBREW, "Hebrew",
+#endif /* HEBREW */
+ L_HUNGARIAN, FC_HUASCII, TC_2LATIN, "Hungarian",
+ L_ICELANDIC, FC_USASCII, TC_1LATIN, "Icelandic",
+ L_ITALIAN, FC_ITASCII, TC_1LATIN, "Italian",
+#ifdef KANJI
+ L_JAPANESE, FC_JEUC, TC_JEUC, "Japanese",
+#endif /* KANJI */
+ L_NORWEGIAN, FC_NOASCII, TC_1LATIN, "Norwegian",
+ L_PORTUGUESE, FC_POASCII, TC_1LATIN, "Portuguese",
+#ifdef CYRILLIC
+ L_RUSSIAN, FC_CP866, TC_CYRILL, "Russian",
+#endif /* CYRILLIC */
+ L_SPANISH, FC_SPASCII, TC_1LATIN, "Spanish",
+ L_SWEDISH, FC_SWASCII, TC_1LATIN, "Swedish",
+ L_SWISS, FC_CHASCII, TC_1LATIN, "Swiss"
+};
+int nlangs = (sizeof(langs) / sizeof(struct langinfo));
+
+/*
+ Keyword table for the SET LANGUAGE command.
+ Only a few of these (German, Scandinavian, etc) actually do anything.
+ The language is used to invoke special translation rules when converting
+ from an 8-bit character set to ASCII; for example, German u-diaeresis
+ becomes "ue", Dutch y-diaeresis becomes "ij". Languages without associated
+ rules are invisible (CM_INV).
+*/
+struct keytab lngtab[] = {
+ "ascii", L_USASCII, CM_INV,
+ "danish", L_DANISH, 0,
+ "dutch", L_DUTCH, 0,
+ "english", L_USASCII, CM_INV,
+ "finnish", L_FINNISH, 0,
+ "french", L_FRENCH, 0,
+ "german", L_GERMAN, 0,
+#ifdef GREEK
+ "greek", L_GREEK, CM_INV,
+#endif /* GREEK */
+#ifdef HEBREW
+ "hebrew", L_HEBREW, CM_INV,
+#endif /* HEBREW */
+ "hungarian", L_HUNGARIAN, CM_INV,
+ "icelandic", L_ICELANDIC, 0,
+ "italian", L_ITALIAN, CM_INV,
+#ifdef KANJI
+ "japanese", L_JAPANESE, CM_INV,
+#endif /* KANJI */
+ "norwegian", L_NORWEGIAN, 0,
+ "none", L_USASCII, 0,
+ "portuguese", L_PORTUGUESE, CM_INV,
+#ifdef CYRILLIC
+ "russian", L_RUSSIAN, 0,
+#endif /* CYRILLIC */
+ "spanish", L_SPANISH, CM_INV,
+ "swedish", L_SWEDISH, 0,
+#ifdef CYRILLIC
+ "ukrainian", L_RUSSIAN, 0,
+#endif /* CYRILLIC */
+ "", 0, 0
+};
+int nlng = (sizeof(lngtab) / sizeof(struct keytab)) - 1; /* how many */
+
+
+/* Translation tables ... */
+
+/*
+ For each pair of (transfer,file) character sets, we need two translation
+ functions, one for sending, one for receiving.
+*/
+
+/*
+ Here is the first table, Latin-1 to ASCII, fully annotated...
+ This one is absolutely NOT invertible, since we're going from an 8-bit
+ set to a 7-bit set. Accented letters are mapped to unaccented
+ equivalents, C1 control characters are all translated to "?", etc.
+*/
+CONST CHAR
+yl1as[] = { /* ISO 8859-1 Latin Alphabet 1 to US ASCII */
+ /* Source character Description => Translation */
+ /* Dec row/col Set */
+ 0, /* 000 00/00 C0 NUL Ctrl-@ => (self) */
+ 1, /* 001 00/01 C0 SOH Ctrl-A => (self) */
+ 2, /* 002 00/02 C0 STX Ctrl-B => (self) */
+ 3, /* 003 00/03 C0 ETX Ctrl-C => (self) */
+ 4, /* 004 00/04 C0 EOT Ctrl-D => (self) */
+ 5, /* 005 00/05 C0 ENQ Ctrl-E => (self) */
+ 6, /* 006 00/06 C0 ACK Ctrl-F => (self) */
+ 7, /* 007 00/07 C0 BEL Ctrl-G => (self) */
+ 8, /* 008 00/08 C0 BS Ctrl-H => (self) */
+ 9, /* 009 00/09 C0 HT Ctrl-I => (self) */
+ 10, /* 010 00/10 C0 LF Ctrl-J => (self) */
+ 11, /* 011 00/11 C0 VT Ctrl-K => (self) */
+ 12, /* 012 00/12 C0 FF Ctrl-L => (self) */
+ 13, /* 013 00/13 C0 CR Ctrl-M => (self) */
+ 14, /* 014 00/14 C0 SO Ctrl-N => (self) */
+ 15, /* 015 00/15 C0 SI Ctrl-O => (self) */
+ 16, /* 016 01/00 C0 DLE Ctrl-P => (self) */
+ 17, /* 017 01/01 C0 DC1 Ctrl-Q => (self) */
+ 18, /* 018 01/02 C0 DC2 Ctrl-R => (self) */
+ 19, /* 019 01/03 C0 DC3 Ctrl-S => (self) */
+ 20, /* 020 01/04 C0 DC4 Ctrl-T => (self) */
+ 21, /* 021 01/05 C0 NAK Ctrl-U => (self) */
+ 22, /* 022 01/06 C0 SYN Ctrl-V => (self) */
+ 23, /* 023 01/07 C0 ETB Ctrl-W => (self) */
+ 24, /* 024 01/08 C0 CAN Ctrl-X => (self) */
+ 25, /* 025 01/09 C0 EM Ctrl-Y => (self) */
+ 26, /* 026 01/10 C0 SUB Ctrl-Z => (self) */
+ 27, /* 027 01/11 C0 ESC Ctrl-[ => (self) */
+ 28, /* 028 01/12 C0 FS Ctrl-\ => (self) */
+ 29, /* 029 01/13 C0 GS Ctrl-] => (self) */
+ 30, /* 030 01/14 C0 RS Ctrl-^ => (self) */
+ 31, /* 031 01/15 C0 US Ctrl-_ => (self) */
+ 32, /* 032 02/00 SP Space => (self) */
+ 33, /* 033 02/01 G0 ! Exclamation mark => (self) */
+ 34, /* 034 02/02 G0 " Doublequote => (self) */
+ 35, /* 035 02/03 G0 # Number sign => (self) */
+ 36, /* 036 02/04 G0 $ Dollar sign => (self) */
+ 37, /* 037 02/05 G0 % Percent sign => (self) */
+ 38, /* 038 02/06 G0 & Ampersand => (self) */
+ 39, /* 039 02/07 G0 ' Apostrophe => (self) */
+ 40, /* 040 02/08 G0 ( Left parenthesis => (self) */
+ 41, /* 041 02/09 G0 ) Right parenthesis => (self) */
+ 42, /* 042 02/10 G0 * Asterisk => (self) */
+ 43, /* 043 02/11 G0 + Plus sign => (self) */
+ 44, /* 044 02/12 G0 , Comma => (self) */
+ 45, /* 045 02/13 G0 - Hyphen, minus sign => (self) */
+ 46, /* 046 02/14 G0 . Period, full stop => (self) */
+ 47, /* 047 02/15 G0 / Slash, solidus => (self) */
+ 48, /* 048 03/00 G0 0 Digit 0 => (self) */
+ 49, /* 049 03/01 G0 1 Digit 1 => (self) */
+ 50, /* 050 03/02 G0 2 Digit 2 => (self) */
+ 51, /* 051 03/03 G0 3 Digit 3 => (self) */
+ 52, /* 052 03/04 G0 4 Digit 4 => (self) */
+ 53, /* 053 03/05 G0 5 Digit 5 => (self) */
+ 54, /* 054 03/06 G0 6 Digit 6 => (self) */
+ 55, /* 055 03/07 G0 7 Digit 7 => (self) */
+ 56, /* 056 03/08 G0 8 Digit 8 => (self) */
+ 57, /* 057 03/09 G0 9 Digit 9 => (self) */
+ 58, /* 058 03/10 G0 : Colon => (self) */
+ 59, /* 059 03/11 G0 ; Semicolon => (self) */
+ 60, /* 060 03/12 G0 < Less-than sign => (self) */
+ 61, /* 061 03/13 G0 = Equals sign => (self) */
+ 62, /* 062 03/14 G0 > Greater-than sign => (self) */
+ 63, /* 063 03/15 G0 ? Question mark => (self) */
+ 64, /* 064 04/00 G0 @ Commercial at sign => (self) */
+ 65, /* 065 04/01 G0 A Letter A => (self) */
+ 66, /* 066 04/02 G0 B Letter B => (self) */
+ 67, /* 067 04/03 G0 C Letter C => (self) */
+ 68, /* 068 04/04 G0 D Letter D => (self) */
+ 69, /* 069 04/05 G0 E Letter E => (self) */
+ 70, /* 070 04/06 G0 F Letter F => (self) */
+ 71, /* 071 04/07 G0 G Letter G => (self) */
+ 72, /* 072 04/08 G0 H Letter H => (self) */
+ 73, /* 073 04/09 G0 I Letter I => (self) */
+ 74, /* 074 04/10 G0 J Letter J => (self) */
+ 75, /* 075 04/11 G0 K Letter K => (self) */
+ 76, /* 076 04/12 G0 L Letter L => (self) */
+ 77, /* 077 04/13 G0 M Letter M => (self) */
+ 78, /* 078 04/14 G0 N Letter N => (self) */
+ 79, /* 079 04/15 G0 O Letter O => (self) */
+ 80, /* 080 05/00 G0 P Letter P => (self) */
+ 81, /* 081 05/01 G0 Q Letter Q => (self) */
+ 82, /* 082 05/02 G0 R Letter R => (self) */
+ 83, /* 083 05/03 G0 S Letter S => (self) */
+ 84, /* 084 05/04 G0 T Letter T => (self) */
+ 85, /* 085 05/05 G0 U Letter U => (self) */
+ 86, /* 086 05/06 G0 V Letter V => (self) */
+ 87, /* 087 05/07 G0 W Letter W => (self) */
+ 88, /* 088 05/08 G0 X Letter X => (self) */
+ 89, /* 089 05/09 G0 Y Letter Y => (self) */
+ 90, /* 090 05/10 G0 Z Letter Z => (self) */
+ 91, /* 091 05/11 G0 [ Left square bracket => (self) */
+ 92, /* 092 05/12 G0 \ Reverse slash => (self) */
+ 93, /* 093 05/13 G0 ] Right square bracket => (self) */
+ 94, /* 094 05/14 G0 ^ Circumflex accent => (self) */
+ 95, /* 095 05/15 G0 _ Underline, low line => (self) */
+ 96, /* 096 06/00 G0 ` Grave accent => (self) */
+ 97, /* 097 06/01 G0 a Letter a => (self) */
+ 98, /* 098 06/02 G0 b Letter b => (self) */
+ 99, /* 099 06/03 G0 c Letter c => (self) */
+100, /* 100 06/04 G0 d Letter d => (self) */
+101, /* 101 06/05 G0 e Letter e => (self) */
+102, /* 102 06/06 G0 f Letter f => (self) */
+103, /* 103 06/07 G0 g Letter g => (self) */
+104, /* 104 06/08 G0 h Letter h => (self) */
+105, /* 105 06/09 G0 i Letter i => (self) */
+106, /* 106 06/10 G0 j Letter j => (self) */
+107, /* 107 06/11 G0 k Letter k => (self) */
+108, /* 108 06/12 G0 l Letter l => (self) */
+109, /* 109 06/13 G0 m Letter m => (self) */
+110, /* 110 06/14 G0 n Letter n => (self) */
+111, /* 111 06/15 G0 o Letter o => (self) */
+112, /* 112 07/00 G0 p Letter p => (self) */
+113, /* 113 07/01 G0 q Letter q => (self) */
+114, /* 114 07/02 G0 r Letter r => (self) */
+115, /* 115 07/03 G0 s Letter s => (self) */
+116, /* 116 07/04 G0 t Letter t => (self) */
+117, /* 117 07/05 G0 u Letter u => (self) */
+118, /* 118 07/06 G0 v Letter v => (self) */
+119, /* 119 07/07 G0 w Letter w => (self) */
+120, /* 120 07/08 G0 x Letter x => (self) */
+121, /* 121 07/09 G0 y Letter y => (self) */
+122, /* 122 07/10 G0 z Letter z => (self) */
+123, /* 123 07/11 G0 { Left curly bracket => (self) */
+124, /* 124 07/12 G0 | Vertical bar => (self) */
+125, /* 125 07/13 G0 } Right curly bracket => (self) */
+126, /* 126 07/14 G0 ~ Tilde => (self) */
+127, /* 127 07/15 DEL Delete, Rubout => (self) */
+UNK, /* 128 08/00 C1 => UNK */
+UNK, /* 129 08/01 C1 => UNK */
+UNK, /* 130 08/02 C1 => UNK */
+UNK, /* 131 08/03 C1 => UNK */
+UNK, /* 132 08/04 C1 IND => UNK */
+UNK, /* 133 08/05 C1 NEL => UNK */
+UNK, /* 134 08/06 C1 SSA => UNK */
+UNK, /* 135 08/07 C1 ESA => UNK */
+UNK, /* 136 08/08 C1 HTS => UNK */
+UNK, /* 137 08/09 C1 => UNK */
+UNK, /* 138 08/10 C1 => UNK */
+UNK, /* 139 08/11 C1 => UNK */
+UNK, /* 140 08/12 C1 => UNK */
+UNK, /* 141 08/13 C1 RI => UNK */
+UNK, /* 142 08/14 C1 SS2 => UNK */
+UNK, /* 143 08/15 C1 SS3 => UNK */
+UNK, /* 144 09/00 C1 DCS => UNK */
+UNK, /* 145 09/01 C1 => UNK */
+UNK, /* 146 09/02 C1 => UNK */
+UNK, /* 147 09/03 C1 STS => UNK */
+UNK, /* 148 09/04 C1 => UNK */
+UNK, /* 149 09/05 C1 => UNK */
+UNK, /* 150 09/06 C1 SPA => UNK */
+UNK, /* 151 09/07 C1 EPA => UNK */
+UNK, /* 152 09/08 C1 => UNK */
+UNK, /* 153 09/09 C1 => UNK */
+UNK, /* 154 09/10 C1 => UNK */
+UNK, /* 155 09/11 C1 CSI => UNK */
+UNK, /* 156 09/12 C1 ST => UNK */
+UNK, /* 157 09/13 C1 OSC => UNK */
+UNK, /* 158 09/14 C1 PM => UNK */
+UNK, /* 159 09/15 C1 APC => UNK */
+ 32, /* 160 10/00 G1 No-break space => SP */
+ 33, /* 161 10/01 G1 Inverted exclamation => ! */
+ 99, /* 162 10/02 G1 Cent sign => c */
+ 35, /* 163 10/03 G1 Pound sign => # */
+ 36, /* 164 10/04 G1 Currency sign => $ */
+ 89, /* 165 10/05 G1 Yen sign => Y */
+124, /* 166 10/06 G1 Broken bar => | */
+ 80, /* 167 10/07 G1 Paragraph sign => P */
+ 34, /* 168 10/08 G1 Diaeresis => " */
+ 67, /* 169 10/09 G1 Copyright sign => C */
+ 97, /* 170 10/10 G1 Feminine ordinal => a */
+ 34, /* 171 10/11 G1 Left angle quotation => " */
+126, /* 172 10/12 G1 Not sign => ~ */
+ 45, /* 173 10/13 G1 Soft hyphen => - */
+ 82, /* 174 10/14 G1 Registered trade mark => R */
+ 95, /* 175 10/15 G1 Macron => _ */
+111, /* 176 11/00 G1 Degree sign, ring above => o */
+UNK, /* 177 11/01 G1 Plus-minus sign => UNK */
+ 50, /* 178 11/02 G1 Superscript two => 2 */
+ 51, /* 179 11/03 G1 Superscript three => 3 */
+ 39, /* 180 11/04 G1 Acute accent => ' */
+117, /* 181 11/05 G1 Micro sign => u */
+ 45, /* 182 11/06 G1 Pilcrow sign => - */
+ 45, /* 183 11/07 G1 Middle dot => - */
+ 44, /* 184 11/08 G1 Cedilla => , */
+ 49, /* 185 11/09 G1 Superscript one => 1 */
+111, /* 186 11/10 G1 Masculine ordinal => o */
+ 34, /* 187 11/11 G1 Right angle quotation => " */
+UNK, /* 188 11/12 G1 One quarter => UNK */
+UNK, /* 189 11/13 G1 One half => UNK */
+UNK, /* 190 11/14 G1 Three quarters => UNK */
+ 63, /* 191 11/15 G1 Inverted question mark => ? */
+ 65, /* 192 12/00 G1 A grave => A */
+ 65, /* 193 12/01 G1 A acute => A */
+ 65, /* 194 12/02 G1 A circumflex => A */
+ 65, /* 195 12/03 G1 A tilde => A */
+ 65, /* 196 12/04 G1 A diaeresis => A */
+ 65, /* 197 12/05 G1 A ring above => A */
+ 65, /* 198 12/06 G1 A with E => A */
+ 67, /* 199 12/07 G1 C Cedilla => C */
+ 69, /* 200 12/08 G1 E grave => E */
+ 69, /* 201 12/09 G1 E acute => E */
+ 69, /* 202 12/10 G1 E circumflex => E */
+ 69, /* 203 12/11 G1 E diaeresis => E */
+ 73, /* 204 12/12 G1 I grave => I */
+ 73, /* 205 12/13 G1 I acute => I */
+ 73, /* 206 12/14 G1 I circumflex => I */
+ 73, /* 207 12/15 G1 I diaeresis => I */
+ 68, /* 208 13/00 G1 Icelandic Eth => D */
+ 78, /* 209 13/01 G1 N tilde => N */
+ 79, /* 210 13/02 G1 O grave => O */
+ 79, /* 211 13/03 G1 O acute => O */
+ 79, /* 212 13/04 G1 O circumflex => O */
+ 79, /* 213 13/05 G1 O tilde => O */
+ 79, /* 214 13/06 G1 O diaeresis => O */
+120, /* 215 13/07 G1 Multiplication sign => x */
+ 79, /* 216 13/08 G1 O oblique stroke => O */
+ 85, /* 217 13/09 G1 U grave => U */
+ 85, /* 218 13/10 G1 U acute => U */
+ 85, /* 219 13/11 G1 U circumflex => U */
+ 85, /* 220 13/12 G1 U diaeresis => U */
+ 89, /* 221 13/13 G1 Y acute => Y */
+ 84, /* 222 13/14 G1 Icelandic Thorn => T */
+115, /* 223 13/15 G1 German sharp s => s */
+ 97, /* 224 14/00 G1 a grave => a */
+ 97, /* 225 14/01 G1 a acute => a */
+ 97, /* 226 14/02 G1 a circumflex => a */
+ 97, /* 227 14/03 G1 a tilde => a */
+ 97, /* 228 14/04 G1 a diaeresis => a */
+ 97, /* 229 14/05 G1 a ring above => a */
+ 97, /* 230 14/06 G1 a with e => a */
+ 99, /* 231 14/07 G1 c cedilla => c */
+101, /* 232 14/08 G1 e grave => e */
+101, /* 233 14/09 G1 e acute => e */
+101, /* 234 14/10 G1 e circumflex => e */
+101, /* 235 14/11 G1 e diaeresis => e */
+105, /* 236 14/12 G1 i grave => i */
+105, /* 237 14/13 G1 i acute => i */
+105, /* 238 14/14 G1 i circumflex => i */
+105, /* 239 14/15 G1 i diaeresis => i */
+100, /* 240 15/00 G1 Icelandic eth => d */
+110, /* 241 15/01 G1 n tilde => n */
+111, /* 242 15/02 G1 o grave => o */
+111, /* 243 15/03 G1 o acute => o */
+111, /* 244 15/04 G1 o circumflex => o */
+111, /* 245 15/05 G1 o tilde => o */
+111, /* 246 15/06 G1 o diaeresis => o */
+ 47, /* 247 15/07 G1 Division sign => / */
+111, /* 248 15/08 G1 o oblique stroke => o */
+117, /* 249 15/09 G1 u grave => u */
+117, /* 250 15/10 G1 u acute => u */
+117, /* 251 15/11 G1 u circumflex => u */
+117, /* 252 15/12 G1 u diaeresis => u */
+121, /* 253 15/13 G1 y acute => y */
+116, /* 254 15/14 G1 Icelandic thorn => t */
+121 /* 255 15/15 G1 y diaeresis => y */
+};
+
+
+/* Translation tables for ISO Latin Alphabet 1 to local file character sets */
+
+/*
+ Most of the remaining tables are not annotated like the one above, because
+ the size of the resulting source file would be ridiculous. Each row in the
+ following tables corresponds to a column of ISO 8859-1.
+*/
+
+CONST CHAR
+yl185[] = { /* ISO 8859-1 Latin Alphabet 1 (Latin-1) to IBM Code Page 850 */
+/*
+ This is based on IBM's official invertible translation. Reference: IBM
+ Character Data Representation Architecture (CDRA), Level 1, Registry,
+ SC09-1291-00 (1990), p.152. (Note: Latin-1 is IBM Code Page 00819.) Note:
+ IBM's bizarre rearrangement of C0 controls and DEL has been undone in this
+ table.
+*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+186, 205, 201, 187, 200, 188, 204, 185, 203, 202, 206, 223, 220, 219, 254, 242,
+179, 196, 218, 191, 192, 217, 195, 180, 194, 193, 197, 176, 177, 178, 213, 159,
+255, 173, 189, 156, 207, 190, 221, 245, 249, 184, 166, 174, 170, 240, 169, 238,
+248, 241, 253, 252, 239, 230, 244, 250, 247, 251, 167, 175, 172, 171, 243, 168,
+183, 181, 182, 199, 142, 143, 146, 128, 212, 144, 210, 211, 222, 214, 215, 216,
+209, 165, 227, 224, 226, 229, 153, 158, 157, 235, 233, 234, 154, 237, 232, 225,
+133, 160, 131, 198, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, 140, 139,
+208, 164, 149, 162, 147, 228, 148, 246, 155, 151, 163, 150, 129, 236, 231, 152
+};
+
+CONST CHAR
+y85l1[] = { /* IBM Code Page 850 to Latin-1 */
+/*
+ This is from IBM CDRA page 153. It is the inverse of yl185[].
+ As of edit 183, this table is no longer pure CDRA. The translations
+ involving C0 controls and DEL have been removed.
+*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197,
+201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 248, 163, 216, 215, 159,
+225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187,
+155, 156, 157, 144, 151, 193, 194, 192, 169, 135, 128, 131, 133, 162, 165, 147,
+148, 153, 152, 150, 145, 154, 227, 195, 132, 130, 137, 136, 134, 129, 138, 164,
+240, 208, 202, 203, 200, 158, 205, 206, 207, 149, 146, 141, 140, 166, 204, 139,
+211, 223, 212, 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, 175, 180,
+173, 177, 143, 190, 182, 167, 247, 184, 176, 168, 183, 185, 179, 178, 142, 160
+};
+
+#ifdef COMMENT
+CONST CHAR
+yl1r8[] = { /* Latin-1 to Hewlett Packard Roman8 */
+/* This is HP's official translation, straight from iconv */
+/* It is NOT invertible. */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 184, 191, 187, 186, 188, 124, 189, 171, 99, 249, 251, 126, 45, 82, 176,
+179, 254, 50, 51, 168, 243, 244, 242, 44, 49, 250, 253, 247, 248, 245, 185,
+161, 224, 162, 225, 216, 208, 211, 180, 163, 220, 164, 165, 230, 229, 166, 167,
+227, 182, 232, 231, 223, 233, 218, 120, 210, 173, 237, 174, 219, 177, 240, 222,
+200, 196, 192, 226, 204, 212, 215, 181, 201, 197, 193, 205, 217, 213, 209, 221,
+228, 183, 202, 198, 194, 234, 206, 47, 214, 203, 199, 195, 207, 178, 241, 239
+};
+CONST CHAR
+yr8l1[] = { /* Hewlett Packard Roman8 to Latin-1 */
+/* This is HP's official translation, straight from iconv */
+/* It is NOT invertible. */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 192, 194, 200, 202, 203, 206, 207, 180, 96, 94, 168, 126, 217, 219, 163,
+175, 221, 253, 176, 199, 231, 209, 241, 161, 191, 164, 163, 165, 167, 102, 162,
+226, 234, 244, 251, 225, 233, 243, 250, 224, 232, 242, 249, 228, 235, 246, 252,
+197, 238, 216, 198, 229, 237, 248, 230, 196, 236, 214, 220, 201, 239, 223, 212,
+193, 195, 227, 208, 240, 205, 204, 211, 210, 213, 245, 83, 115, 218, 89, 255,
+222, 254, 183, 181, 182, 190, 45, 188, 189, 170, 186, 171, 42, 187, 177, 160
+};
+#else /* !COMMENT */
+/* This is an invertible mapping, approved by HP in January 1994. */
+CONST CHAR
+yl1r8[] = { /* ISO Latin-1 to HP Roman8, Invertible */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 184, 191, 187, 186, 188, 169, 189, 171, 170, 249, 251, 172, 175, 190, 176,
+179, 254, 235, 236, 168, 243, 244, 242, 238, 246, 250, 253, 247, 248, 245, 185,
+161, 224, 162, 225, 216, 208, 211, 180, 163, 220, 164, 165, 230, 229, 166, 167,
+227, 182, 232, 231, 223, 233, 218, 252, 210, 173, 237, 174, 219, 177, 240, 222,
+200, 196, 192, 226, 204, 212, 215, 181, 201, 197, 193, 205, 217, 213, 209, 221,
+228, 183, 202, 198, 194, 234, 206, 255, 214, 203, 199, 195, 207, 178, 241, 239
+};
+
+CONST CHAR
+yr8l1[] = { /* HP Roman8 to ISO Latin-1, Invertible */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 192, 194, 200, 202, 203, 206, 207, 180, 166, 169, 168, 172, 217, 219, 173,
+175, 221, 253, 176, 199, 231, 209, 241, 161, 191, 164, 163, 165, 167, 174, 162,
+226, 234, 244, 251, 225, 233, 243, 250, 224, 232, 242, 249, 228, 235, 246, 252,
+197, 238, 216, 198, 229, 237, 248, 230, 196, 236, 214, 220, 201, 239, 223, 212,
+193, 195, 227, 208, 240, 205, 204, 211, 210, 213, 245, 178, 179, 218, 184, 255,
+222, 254, 183, 181, 182, 190, 185, 188, 189, 170, 186, 171, 215, 187, 177, 247
+};
+#endif /* COMMENT */
+
+CONST CHAR
+yl143[] = { /* Latin-1 to IBM Code Page 437 */
+/*
+ Although the IBM CDRA does not include an official translation between CP437
+ and ISO Latin Alphabet 1, it does include an official, invertible
+ translation between CP437 and CP850 (page 196), and another from CP850 to
+ Latin-1 (CP819) (page 153). This translation was obtained with a two-step
+ process based on those tables.
+ As of edit 183, the translation is modified to leave C0 controls alone.
+*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+186, 205, 201, 187, 200, 188, 204, 185, 203, 202, 206, 223, 220, 219, 254, 242,
+179, 196, 218, 191, 192, 217, 195, 180, 194, 193, 197, 176, 177, 178, 213, 159,
+255, 173, 155, 156, 207, 157, 221, 245, 249, 184, 166, 174, 170, 240, 169, 238,
+248, 241, 253, 252, 239, 230, 244, 250, 247, 251, 167, 175, 172, 171, 243, 168,
+183, 181, 182, 199, 142, 143, 146, 128, 212, 144, 210, 211, 222, 214, 215, 216,
+209, 165, 227, 224, 226, 229, 153, 158, 190, 235, 233, 234, 154, 237, 232, 225,
+133, 160, 131, 198, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, 140, 139,
+208, 164, 149, 162, 147, 228, 148, 246, 189, 151, 163, 150, 129, 236, 231, 152
+};
+
+CONST CHAR
+y43l1[] = { /* IBM Code Page 437 to Latin-1 */
+/*
+ This table is the inverse of yl143[].
+*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197,
+201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 215, 159,
+225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187,
+155, 156, 157, 144, 151, 193, 194, 192, 169, 135, 128, 131, 133, 248, 216, 147,
+148, 153, 152, 150, 145, 154, 227, 195, 132, 130, 137, 136, 134, 129, 138, 164,
+240, 208, 202, 203, 200, 158, 205, 206, 207, 149, 146, 141, 140, 166, 204, 139,
+211, 223, 212, 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, 175, 180,
+173, 177, 143, 190, 182, 167, 247, 184, 176, 168, 183, 185, 179, 178, 142, 160
+};
+
+CONST CHAR
+yl1aq[] = { /* Latin-1 to Extended Mac Latin (based on Apple QuickDraw) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+182, 183, 184, 185, 189, 196, 197, 198, 206, 207, 210, 211, 217, 218, 195, 212,
+209, 215, 213, 226, 227, 228, 240, 245, 246, 247, 249, 250, 251, 253, 254, 255,
+202, 193, 162, 163, 219, 180, 201, 164, 172, 169, 187, 199, 194, 208, 168, 248,
+161, 177, 170, 173, 171, 181, 166, 225, 252, 176, 188, 200, 178, 179, 186, 192,
+203, 231, 229, 204, 128, 129, 174, 130, 233, 131, 230, 232, 237, 234, 235, 236,
+220, 132, 241, 238, 239, 205, 133, 165, 175, 244, 242, 243, 134, 160, 222, 167,
+136, 135, 137, 139, 138, 140, 190, 141, 143, 142, 144, 145, 147, 146, 148, 149,
+221, 150, 152, 151, 153, 155, 154, 214, 191, 157, 156, 158, 159, 224, 223, 216
+};
+
+CONST CHAR
+yl1du[] = { /* Latin-1 to Dutch ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, 39, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, 35, 124, UNK, UNK, 93, 123, 67, UNK, 34, UNK, 45, 82, UNK,
+ 91, UNK, UNK, UNK, 126, 117, UNK, UNK, 44, UNK, UNK, 34, 125, 92, 64, 63,
+ 65, 65, 65, 65, 91, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+ 97, 97, 97, 97, 97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, UNK, 91
+};
+
+CONST CHAR
+yl1fi[] = { /* Latin-1 to Finnish ISO NRC (*not* ISO 646) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, 95,
+UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 91, 93, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 94, 89, UNK, 115,
+ 97, 97, 97, 97, 123, 125, 97, 99, 101, 96, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 126, 121, UNK, 121
+};
+
+CONST CHAR
+yl1fr[] = { /* Latin-1 to French ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, 35, UNK, UNK, UNK, 93, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+ 91, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+ 64, 97, 97, 97, 97, 97, 97, 92, 125, 123, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 111, 47, 111, 124, 117, 117, 117, 121, UNK, 121
+};
+
+CONST CHAR
+yl1fc[] = { /* Latin-1 to French-Canadian ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, 95,
+UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+ 64, 97, 91, 97, 97, 97, 97, 92, 125, 123, 93, 101, 105, 105, 94, 105,
+UNK, 110, 111, 111, 96, 111, 111, 47, 111, 124, 117, 126, 117, 121, UNK, 121
+};
+
+CONST CHAR
+yl1ge[] = { /* Latin-1 to German ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, 64, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 91, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 93, 89, UNK, 126,
+ 97, 97, 97, 97, 123, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 125, 121, UNK, 121
+};
+
+CONST CHAR
+yl1hu[] = { /* Latin-1 to Hungarian ISO-646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, 36, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, 64, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 65, 65, 65, 67, 69, 91, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 93, 89, UNK, 115,
+ 97, 96, 97, 97, 97, 97, 97, 99, 101, 123, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 125, 121, UNK, 121
+};
+
+CONST CHAR
+yl1it[] = { /* Latin-1 to Italian ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, 35, UNK, UNK, UNK, 64, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+ 91, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+123, 97, 97, 97, 97, 97, 97, 92, 125, 93, 101, 101, 126, 105, 105, 105,
+UNK, 110, 124, 111, 111, 111, 111, 47, 111, 96, 117, 117, 117, 121, UNK, 121
+};
+
+CONST CHAR
+yl1ne[] = { /* Latin-1 to NeXT */
+/* NEED TO MAKE THIS ONE INVERTIBLE, LIKE CP850 */
+/*
+ Which means finding all the graphic characters in the NeXT set that have
+ no equivalent in Latin-1 and assigning them to the UNK positions (mostly
+ Latin-1 C1 controls). Then make the ynel1[] table be the inverse of this
+ one. But first we should try to get an official Latin-1/NeXT translation
+ table from NeXT, Inc.
+*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+ 32, 161, 162, 163, 168, 165, 181, 167, 200, 160, 227, 171, 190, UNK, 176, 197,
+202, 209, 201, 204, 194, 157, 182, 183, 203, 192, 235, 187, 210, 211, 212, 191,
+129, 130, 131, 132, 133, 134, 225, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 158, 233, 151, 152, 153, 154, 155, 156, 251,
+213, 214, 215, 216, 217, 218, 241, 219, 220, 221, 222, 223, 224, 226, 228, 229,
+230, 231, 236, 237, 238, 239, 240, 159, 249, 242, 243, 244, 246, 247, 252, 253
+};
+
+CONST CHAR
+yl1no[] = { /* Latin-1 to Norwegian/Danish ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 65, 93, 91, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 79, 120, 92, 85, 85, 85, 85, 89, UNK, 115,
+ 97, 97, 97, 97, 97, 125, 123, 99, 101, 101, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 111, 47, 124, 117, 117, 117, 117, 121, UNK, 121
+};
+
+CONST CHAR
+yl1po[] = { /* Latin-1 to Portuguese ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 91, 65, 65, 65, 92, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 93, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+ 97, 97, 97, 123, 97, 97, 97, 124, 101, 101, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 125, 111, 47, 111, 117, 117, 117, 117, 121, UNK, 121
+};
+
+CONST CHAR
+yl1sp[] = { /* Latin-1 to Spanish ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 96, UNK, UNK, 126, 127,
+126, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 91, UNK, 35, UNK, UNK, UNK, 64, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+123, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 93,
+ 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 92, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+124, 97, 97, 97, 97, 97, 97, 125, 101, 101, 101, 101, 105, 105, 105, 105,
+UNK, 124, 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, UNK, 121
+};
+
+CONST CHAR
+yl1sw[] = { /* Latin-1 to Swedish ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, 95,
+UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 91, 93, 65, 67, 69, 64, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 94, 89, UNK, 115,
+ 97, 97, 97, 97, 123, 125, 97, 99, 101, 96, 101, 101, 105, 105, 105, 105,
+UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 126, 121, UNK, 121
+};
+
+CONST CHAR
+yl1ch[] = { /* Latin-1 to Swiss ISO 646 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, UNK,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK,
+UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63,
+ 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115,
+ 64, 97, 97, 97, 123, 97, 97, 92, 95, 91, 93, 101, 105, 105, 94, 105,
+UNK, 110, 111, 111, 96, 111, 124, 47, 111, 35, 117, 126, 125, 121, UNK, 121
+};
+
+CONST CHAR
+yl1dm[] = { /* Latin-1 to DEC Multinational Character Set */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 32, 161, 162, 163, 168, 165, 124, 167, 34, 169, 170, 171, 126, UNK, 82, UNK,
+176, 177, 178, 179, 39, 181, 182, 183, 44, 185, 186, 187, 188, 189, UNK, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+UNK, 209, 210, 211, 212, 213, 214, 120, 216, 217, 218, 219, 220, 221, UNK, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+UNK, 241, 242, 243, 244, 245, 246, 47, 248, 249, 250, 251, 252, UNK, UNK, 253
+};
+
+CONST CHAR
+yl1dg[] = { /* Latin-1 to Data General International Character Set */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 171, 167, 168, 166, 181, 191, 187, 189, 173, 169, 177, 161, 255, 174, 175,
+188, 182, 164, 165, 190, 163, 178, 185, 186, 179, 170, 176, 223, 162, 220, 172,
+193, 192, 194, 196, 195, 197, 198, 199, 201, 200, 202, 203, 205, 204, 206, 207,
+184, 208, 210, 209, 211, 213, 212, 215, 214, 217, 216, 218, 219, 221, 222, 252,
+225, 224, 226, 228, 227, 229, 230, 231, 233, 232, 234, 235, 237, 236, 238, 239,
+183, 240, 242, 241, 243, 245, 244, 247, 246, 249, 248, 250, 251, 180, 254, 253
+};
+
+
+/* Local file character sets to ISO Latin Alphabet 1 */
+
+#ifdef NOTUSED
+CONST CHAR
+yasl1[] = { /* ASCII to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127
+};
+#endif /* NOTUSED */
+
+CONST CHAR
+yaql1[] = { /* Extended Mac Latin (based on Apple Quickdraw) to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232,
+234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 251, 252,
+221, 176, 162, 163, 167, 215, 182, 223, 174, 169, 178, 180, 168, 179, 198, 216,
+185, 177, 188, 189, 165, 181, 128, 129, 130, 131, 190, 170, 186, 132, 230, 248,
+191, 161, 172, 142, 133, 134, 135, 171, 187, 166, 160, 192, 195, 213, 136, 137,
+173, 144, 138, 139, 143, 146, 247, 145, 255, 140, 141, 164, 208, 240, 222, 254,
+253, 183, 147, 148, 149, 194, 202, 193, 203, 200, 205, 206, 207, 204, 211, 212,
+150, 210, 218, 219, 217, 151, 152, 153, 175, 154, 155, 156, 184, 157, 158, 159
+};
+
+CONST CHAR
+ydul1[] = { /* Dutch ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+190, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 255, 189, 124, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 168, 164, 188, 39, 127
+};
+
+CONST CHAR
+yfil1[] = { /* Finnish NRC (*not* ISO-646) to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 197, 220, 95,
+233, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 229, 252, 127
+};
+
+CONST CHAR
+yfrl1[] = { /* French ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+224, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 176, 231, 167, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 233, 249, 232, 168, 127
+};
+
+CONST CHAR
+yfcl1[] = { /* French-Canadian ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+224, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 226, 231, 234, 238, 95,
+244, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 233, 249, 232, 251, 127
+};
+
+CONST CHAR
+ygel1[] = { /* German ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+167, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 220, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 252, 223, 127
+};
+
+CONST CHAR
+yitl1[] = { /* Italian ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+167, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 176, 231, 233, 94, 95,
+249, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 224, 242, 232, 236, 127
+};
+
+CONST CHAR
+ynel1[] = { /* NeXT to Latin-1 */
+/* NEED TO MAKE THIS ONE INVERTIBLE */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+160, 192, 193, 194, 195, 196, 197, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 217, 218, 219, 220, 221, 222, 181, 215, 247,
+169, 161, 162, 163, UNK, 165, UNK, 167, 164, UNK, UNK, 171, UNK, UNK, UNK, UNK,
+174, UNK, UNK, UNK, 183, 166, 182, UNK, UNK, UNK, UNK, 187, UNK, UNK, 172, 191,
+185, 96, 180, 94, 126, 175, UNK, UNK, 168, 178, 176, 184, 179, UNK, UNK, UNK,
+UNK, 177, 188, 189, 190, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235,
+236, 198, 237, 170, 238, 239, 240, 241, UNK, 216, UNK, 186, 242, 243, 244, 245,
+246, 230, 249, 250, 251, UNK, 252, 253, UNK, 248, UNK, 223, 254, 255, UNK, UNK
+};
+
+CONST CHAR
+ynol1[] = { /* Norwegian/Danish ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 198, 216, 197, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 230, 248, 229, 126, 127
+};
+
+CONST CHAR
+ypol1[] = { /* Portuguese ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 195, 199, 213, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 227, 231, 245, 126, 127
+};
+
+CONST CHAR
+yspl1[] = { /* Spanish ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+167, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 161, 209, 191, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 176, 241, 231, 126, 127
+};
+
+CONST CHAR
+yswl1[] = { /* Swedish ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+201, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 197, 220, 95,
+233, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 229, 252, 127
+};
+
+CONST CHAR
+ychl1[] = { /* Swiss ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 249, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+224, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 233, 231, 234, 238, 232,
+244, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 252, 251, 127
+};
+
+CONST CHAR
+yhul1[] = { /* Hungarian ISO 646 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 164, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+193, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 201, 214, 220, 94, 95,
+225, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 233, 246, 252, 34, 127
+};
+
+CONST CHAR
+ydml1[] = { /* DEC Multinational Character Set to Latin-1 */
+/* Note: This is a null translation */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+CONST CHAR
+ydgl1[] = { /* Data General International to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 172, 189, 181, 178, 179, 164, 162, 163, 170, 186, 161, 191, 169, 174, 175,
+187, 171, 182, 185, 253, 165, 177, 240, 208, 183, 184, 167, 176, 168, 180, 166,
+193, 192, 194, 196, 195, 197, 198, 199, 201, 200, 202, 203, 205, 204, 206, 207,
+209, 211, 210, 212, 214, 213, 216, 215, 218, 217, 219, 220, 190, 221, 222, 188,
+225, 224, 226, 228, 227, 229, 230, 231, 233, 232, 234, 235, 237, 236, 238, 239,
+241, 243, 242, 244, 246, 245, 248, 247, 250, 249, 251, 252, 223, 255, 254, 173
+};
+
+
+/* Translation tables for Cyrillic character sets */
+
+#ifdef CYRILLIC
+CONST CHAR
+ylcac[] = { /* Latin/Cyrillic to CP866 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 208, 209, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+196, 179, 192, 217, 191, 218, 195, 193, 180, 194, 197, 176, 177, 178, 211, 216,
+205, 186, 200, 188, 187, 201, 204, 202, 185, 203, 206, 223, 220, 219, 254, UNK,
+255, 240, 132, 131, 242, 83, 73, 244, 74, 139, 141, 151, 138, 45, 246, 135,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+252, 241, 164, 163, 243, 115, 105, 245, 106, 171, 173, 231, 170, 21, 247, 167
+};
+
+CONST CHAR
+ylc55[] = { /* Latin/Cyrillic to CP855 (inverse of y55lc) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+174, 175, 176, 177, 178, 179, 180, 185, 186, 187, 188, 191, 192, 193, 194, 195,
+196, 197, 200, 201, 202, 203, 204, 205, 206, 207, 217, 218, 219, 220, 223, 254,
+255, 133, 129, 131, 135, 137, 139, 141, 143, 145, 147, 149, 151, 240, 153, 155,
+161, 163, 236, 173, 167, 169, 234, 244, 184, 190, 199, 209, 211, 213, 215, 221,
+226, 228, 230, 232, 171, 182, 165, 252, 246, 250, 159, 242, 238, 248, 157, 224,
+160, 162, 235, 172, 166, 168, 233, 243, 183, 189, 198, 208, 210, 212, 214, 216,
+225, 227, 229, 231, 170, 181, 164, 251, 245, 249, 158, 241, 237, 247, 156, 222,
+239, 132, 128, 130, 134, 136, 138, 140, 142, 144, 146, 148, 150, 253, 152, 154
+};
+
+CONST CHAR
+ylc1251[] = { /* Latin/Cyrillic to CP1251 (inverse of y1251lc) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+130, 132, 133, 134, 135, 136, 137, 139, 145, 146, 147, 148, 149, 150, 151, 152,
+153, 155, 164, 165, 166, 169, 171, 172, 174, 176, 177, 180, 181, 182, 183, 187,
+160, 168, 128, 129, 170, 189, 178, 175, 163, 138, 140, 142, 141, 173, 161, 143,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+185, 184, 144, 131, 186, 190, 179, 191, 188, 154, 156, 158, 157, 167, 162, 159
+};
+
+CONST CHAR
+ylcbu[] = { /* Latin/Cyrillic to Bulgarian PC Code Page */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+255, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+213, 207, 208, 209, 210, 211, 212, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 214, 253, 254
+};
+
+CONST CHAR
+ylck8[] = { /* Latin/Cyrillic to Old KOI-8 Cyrillic */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+UNK, 229, UNK, UNK, UNK, 83, 73, 73, 74, UNK, UNK, UNK, 235, UNK, 245, UNK,
+225, 226, 247, 231, 228, 229, 246, 250, 233, 234, 235, 236, 237, 238, 239, 240,
+242, 243, 244, 245, 230, 232, 227, 254, 251, 253, 255, 249, 248, 252, 224, 241,
+193, 194, 215, 199, 196, 197, 214, 218, 201, 202, 203, 204, 205, 206, 207, 208,
+210, 211, 212, 213, 198, 200, 195, 222, 219, 221, 223, 217, 216, 220, 192, 209,
+UNK, 197, UNK, UNK, UNK, 115, 105, 105, 106, UNK, UNK, UNK, 203, UNK, 213, UNK
+};
+
+CONST CHAR
+yaclc[] = { /* CP866 to Latin/Cyrillic */
+/* NEED TO MAKE THIS ONE INVERTIBLE */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+161, 241, 164, 244, 167, 247, 174, 254, UNK, UNK, UNK, UNK, 240, UNK, UNK, UNK
+};
+
+CONST CHAR
+y55lc[] = { /* CP855 to Latin/Cyrillic (inverse of ylc55) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+242, 162, 243, 163, 241, 161, 244, 164, 245, 165, 246, 166, 247, 167, 248, 168,
+249, 169, 250, 170, 251, 171, 252, 172, 254, 174, 255, 175, 238, 206, 234, 202,
+208, 176, 209, 177, 230, 198, 212, 180, 213, 181, 228, 196, 211, 179, 128, 129,
+130, 131, 132, 133, 134, 229, 197, 216, 184, 135, 136, 137, 138, 217, 185, 139,
+140, 141, 142, 143, 144, 145, 218, 186, 146, 147, 148, 149, 150, 151, 152, 153,
+219, 187, 220, 188, 221, 189, 222, 190, 223, 154, 155, 156, 157, 191, 239, 158,
+207, 224, 192, 225, 193, 226, 194, 227, 195, 214, 182, 210, 178, 236, 204, 240,
+173, 235, 203, 215, 183, 232, 200, 237, 205, 233, 201, 231, 199, 253, 159, 160
+};
+
+CONST CHAR
+y1251lc[] = { /* CP1251 to Latin/Cyrillic (inverse of ylc1251) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+162, 163, 128, 243, 129, 130, 131, 132, 133, 134, 169, 135, 170, 172, 171, 175,
+242, 136, 137, 138, 139, 140, 141, 142, 143, 144, 249, 145, 250, 252, 251, 255,
+160, 174, 254, 168, 146, 147, 148, 253, 161, 149, 164, 150, 151, 173, 152, 167,
+153, 154, 166, 246, 155, 156, 157, 158, 241, 240, 244, 159, 248, 165, 245, 247,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239
+};
+
+CONST CHAR
+ybulc[] = { /* Bulgarian PC Code Page to Latin/Cyrillic */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 209,
+210, 211, 212, 213, 214, 208, 253, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 254, 255, 128
+};
+
+CONST CHAR
+yk8lc[] = { /* Old KOI-8 Cyrillic to Latin/Cyrillic */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+238, 208, 209, 230, 212, 213, 228, 211, 229, 216, 217, 218, 219, 220, 221, 222,
+223, 239, 224, 225, 226, 227, 214, 210, 236, 235, 215, 232, 237, 233, 231, 234,
+206, 176, 177, 198, 180, 181, 196, 179, 197, 184, 185, 186, 187, 188, 189, 190,
+191, 207, 192, 193, 194, 195, 182, 178, 204, 203, 183, 200, 205, 201, 199, 127
+};
+
+CONST CHAR
+ylcsk[] = { /* Latin/Cyrillic to Short KOI */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 127,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 101, UNK, UNK, UNK, 83, 73, 73, 74, UNK, UNK, UNK, 107, 45, 117, UNK,
+ 97, 98, 119, 103, 100, 101, 118, 122, 105, 106, 107, 108, 109, 110, 111, 112,
+114, 115, 116, 117, 102, 104, 99, 126, 123, 125, 39, 121, 120, 124, 96, 113,
+ 97, 98, 119, 103, 100, 101, 118, 122, 105, 106, 107, 108, 109, 110, 111, 112,
+114, 115, 116, 117, 102, 104, 99, 126, 123, 125, 39, 121, 120, 124, 96, 113,
+UNK, 101, UNK, UNK, UNK, 83, 73, 73, 74, UNK, UNK, UNK, 107, UNK, 117, UNK
+};
+
+CONST CHAR yskcy[] = { /* Short KOI to Latin/Cyrillic */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+206, 176, 177, 198, 180, 181, 196, 179, 197, 184, 185, 186, 187, 188, 189, 190,
+191, 207, 192, 193, 194, 195, 182, 178, 204, 203, 183, 200, 205, 201, 199, 127
+};
+#endif /* CYRILLIC */
+
+#ifdef LATIN2
+
+/* Latin-2 tables */
+
+CONST CHAR
+yl252[] = { /* Latin-2 to Code Page 852 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+174, 175, 176, 177, 178, 179, 180, 185, 186, 187, 188, 191, 192, 193, 194, 195,
+196, 197, 200, 201, 202, 203, 204, 205, 206, 217, 218, 219, 220, 223, 240, 254,
+255, 164, 244, 157, 207, 149, 151, 245, 249, 230, 184, 155, 141, 170, 166, 189,
+248, 165, 242, 136, 239, 150, 152, 243, 247, 231, 173, 156, 171, 241, 167, 190,
+232, 181, 182, 198, 142, 145, 143, 128, 172, 144, 168, 211, 183, 214, 215, 210,
+209, 227, 213, 224, 226, 138, 153, 158, 252, 222, 233, 235, 154, 237, 221, 225,
+234, 160, 131, 199, 132, 146, 134, 135, 159, 130, 169, 137, 216, 161, 140, 212,
+208, 228, 229, 162, 147, 139, 148, 246, 253, 133, 163, 251, 129, 236, 238, 250
+};
+
+CONST CHAR
+y52l2[] = { /* Code Page 852 to Latin-2 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+199, 252, 233, 226, 228, 249, 230, 231, 179, 235, 213, 245, 238, 172, 196, 198,
+201, 197, 229, 244, 246, 165, 181, 166, 182, 214, 220, 171, 187, 163, 215, 232,
+225, 237, 243, 250, 161, 177, 174, 190, 202, 234, 173, 188, 200, 186, 128, 129,
+130, 131, 132, 133, 134, 193, 194, 204, 170, 135, 136, 137, 138, 175, 191, 139,
+140, 141, 142, 143, 144, 145, 195, 227, 146, 147, 148, 149, 150, 151, 152, 164,
+240, 208, 207, 203, 239, 210, 205, 206, 236, 153, 154, 155, 156, 222, 217, 157,
+211, 223, 212, 209, 241, 242, 169, 185, 192, 218, 224, 219, 253, 221, 254, 180,
+158, 189, 178, 183, 162, 167, 247, 184, 176, 168, 255, 251, 216, 248, 159, 160
+};
+
+CONST CHAR
+yl21250[] = { /* Latin-2 to Code Page 1250 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 139, 144, 145, 146, 147, 148,
+149, 150, 151, 152, 153, 155, 166, 169, 171, 172, 174, 177, 181, 182, 183, 187,
+160, 165, 162, 163, 164, 188, 140, 167, 168, 138, 170, 141, 143, 173, 142, 175,
+176, 185, 178, 179, 180, 190, 156, 161, 184, 154, 186, 157, 159, 189, 158, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+CONST CHAR
+y1250l2[] = { /* Code Page 1250 to Latin-2 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 169, 138, 166, 171, 174, 172,
+139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 185, 149, 182, 187, 190, 188,
+160, 183, 162, 163, 164, 161, 150, 167, 168, 151, 170, 152, 153, 173, 154, 175,
+176, 155, 178, 179, 180, 156, 157, 158, 184, 177, 186, 159, 165, 189, 181, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+CONST CHAR
+yl2mz[] = { /* Latin-2 to Mazovia (NOT invertible) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+255, 143, UNK, 156, 155, 76, 152, 21, 34, 83, 83, 84, 160, 45, 90, 161,
+248, 134, 44, 146, 39, 108, 158, UNK, 44, 115, 115, 116, 166, 34, 122, 167,
+ 82, 65, 65, 65, 142, 76, 149, 128, 67, 69, 144, 69, 69, 73, 73, 68,
+ 68, 165, 78, 163, 79, 153, 153, 250, 82, 85, 85, 154, 154, 89, 84, 225,
+114, 97, 131, 97, 132, 108, 141, 135, 99, 130, 145, 137, 101, 105, 140, 101,
+100, 164, 110, 162, 147, 148, 148, 246, 114, 117, 117, 129, 129, 121, 116, 249
+};
+
+CONST CHAR
+ymzl2[] = { /* Mazovia to Latin-2 (NOT INVERTIBLE) */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 252, 233, 226, 228, 97, 177, 231, 101, 235, 101, 105, 238, 230, 196, 161,
+202, 234, 179, 244, 246, 198, 117, 117, 166, 214, 220, 164, 163, 89, 182, 102,
+172, 175, 243, 211, 242, 210, 188, 191, 63, UNK, UNK, UNK, UNK, 33, 34, 34,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, 247, UNK, 176, 255, 215, UNK, UNK, UNK, UNK, 160
+};
+
+CONST CHAR
+yl2l1[] = { /* Latin-2 to Latin-1 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 'A', UNK, 'L', 164, 'L', 'S', 167, 168, 'S', 'S', 'T', 'Z', 173, 'Z', 'Z',
+176, 'a', UNK, 'l', 180, 'l', 's', UNK, 184, 's', 's', 't', 'z', UNK, 'z', 'z',
+'R', 193, 194, 'A', 196, 'L', 'C', 199, 'C', 201, 'E', 203, 'E', 205, 'I', 'D',
+208, 'N', 'N', 211, 212, 'O', 214, 215, 'R', 'U', 218, 'U', 220, 221, 'T', 223,
+'r', 225, 226, 'a', 228, 'l', 'c', 231, 'c', 233, 'e', 235, 'e', 237, 'i', 'd',
+240, 'n', 'n', 243, 244, 'o', 246, 247, 'r', 'u', 250, 'u', 252, 253, 't', '.'
+};
+
+CONST CHAR
+yl1l2[] = { /* Latin-1 to Latin-2 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 'A', UNK, 'L', 164, UNK, UNK, 167, 168, 'C', 'a', '<', '>', 173, 'R', UNK,
+176, UNK, UNK, UNK, 180, UNK, UNK, UNK, 184, UNK, 'o', '>', UNK, UNK, UNK, UNK,
+'A', 193, 194, 'A', 196, 'A', 'A', 199, 'E', 201, 'E', 203, 'I', 205, 'I', 'I',
+208, 'N', 'O', 211, 212, 'O', 214, 215, 'O', 'U', 218, 'U', 220, 221, UNK, 223,
+'a', 225, 226, 'a', 228, 'a', 'a', 231, 'e', 233, 'e', 235, 'i', 237, 'i', 'i',
+240, 'n', 'o', 243, 244, 'o', 246, 247, 'o', 'u', 250, 'u', 252, 253, UNK, 'y'
+};
+
+CONST CHAR
+yl2as[] = { /* Latin-2 to ASCII */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+ 32, 'A', UNK, 'L', UNK, 'L', 'S', UNK, 34, 'S', 'S', 'T', 'Z', '-', 'Z', 'Z',
+UNK, 'a', UNK, 'l', 39, 'l', 's', UNK, 44, 's', 's', 't', 'z', UNK, 'z', 'z',
+'R', 'A', 'A', 'A', 'A', 'L', 'C', 'C', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'D',
+'D', 'N', 'N', 'O', 'O', 'O', 'O', 'x', 'R', 'U', 'U', 'U', 'U', 'Y', 'T', 's',
+'r', 'a', 'a', 'a', 'a', 'l', 'c', 'c', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'd',
+'d', 'n', 'n', 'o', 'o', 'o', 'o', '/', 'r', 'u', 'u', 'u', 'u', 'y', 't', '.'
+};
+#endif /* LATIN2 */
+
+#ifdef HEBREW
+/*
+ 8-bit Tables providing invertible translation between Latin/Hebrew and CP862.
+*/
+CONST CHAR
+y62lh[] = { /* PC Code Page 862 to ISO 8859-8 Latin/Hebrew */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 162, 163, 165, 128, 129,
+130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 172, 189, 188, 140, 171, 187,
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
+157, 158, 159, 161, 164, 166, 167, 168, 169, 170, 173, 174, 175, 223, 179, 180,
+182, 184, 185, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+203, 204, 205, 206, 207, 208, 181, 209, 210, 211, 212, 213, 214, 215, 216, 217,
+218, 177, 219, 220, 221, 222, 186, 251, 176, 183, 252, 253, 254, 178, 255, 160
+};
+
+CONST CHAR
+ylh62[] = { /* ISO 8859-8 Latin/Hebrew to PC Code Page 862 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 173, 176, 177, 178,
+179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+255, 195, 155, 156, 196, 157, 197, 198, 199, 200, 201, 174, 170, 202, 203, 204,
+248, 241, 253, 206, 207, 230, 208, 249, 209, 210, 246, 175, 172, 171, 211, 212,
+213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
+229, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 205,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 247, 250, 251, 252, 254
+};
+/*
+ 7-bit table providing readable translation from DEC Hebrew-7 to CP862.
+*/
+CONST CHAR
+yh762[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127
+};
+/*
+ 8-bit table providing readable translation from CP862 to Hebrew-7.
+*/
+CONST CHAR
+y62h7[] = { /* PC Code Page 862 to Hebrew-7 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK
+};
+/*
+ 7-bit table providing readable translation from Hebrew-7 to ISO Latin/Hebrew.
+*/
+CONST CHAR
+yh7lh[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 123, 124, 125, 126, 127
+};
+/*
+ 8-bit table providing readable translation from ISO Latin/Hebrew to Hebrew-7.
+*/
+CONST CHAR
+ylhh7[] = { /* Latin/Hebrew to Hebrew-7 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, UNK
+};
+#endif /* HEBREW */
+
+#ifdef GREEK
+/*
+ 8-bit Tables providing invertible translation between Latin/Greek and CP869.
+*/
+CONST CHAR
+ylg69[] = { /* ISO 8859-7 Latin/Greek to PC Code Page 869 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+135, 147, 148, 176, 177, 178, 179, 180, 185, 186, 187, 188, 191, 192, 193, 194,
+195, 196, 197, 200, 201, 202, 203, 204, 205, 206, 217, 218, 219, 220, 223, 254,
+255, 139, 140, 156, 128, 129, 138, 245, 249, 151, 130, 174, 137, 240, 131, 142,
+248, 241, 153, 154, 239, 247, 134, 136, 141, 143, 144, 175, 146, 171, 149, 152,
+161, 164, 165, 166, 167, 168, 169, 170, 172, 173, 181, 182, 183, 184, 189, 190,
+198, 199, 132, 207, 208, 209, 210, 211, 212, 213, 145, 150, 155, 157, 158, 159,
+252, 214, 215, 216, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
+234, 235, 237, 236, 238, 242, 243, 244, 246, 250, 160, 251, 162, 163, 253, 133
+};
+
+CONST CHAR
+y69lg[] = { /* PC Code Page 869 to ISO 8859-7 Latin/Greek */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+164, 165, 170, 174, 210, 255, 182, 128, 183, 172, 166, 161, 162, 184, 175, 185,
+186, 218, 188, 129, 130, 190, 219, 169, 191, 178, 179, 220, 163, 221, 222, 223,
+250, 192, 252, 253, 193, 194, 195, 196, 197, 198, 199, 189, 200, 201, 171, 187,
+131, 132, 133, 134, 135, 202, 203, 204, 205, 136, 137, 138, 139, 206, 207, 140,
+141, 142, 143, 144, 145, 146, 208, 209, 147, 148, 149, 150, 151, 152, 153, 211,
+212, 213, 214, 215, 216, 217, 225, 226, 227, 154, 155, 156, 157, 228, 229, 158,
+230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 243, 242, 244, 180,
+173, 177, 245, 246, 247, 167, 248, 181, 176, 168, 249, 251, 224, 254, 159, 160
+};
+/*
+ 7-bit table providing readable translation from ELOT 927 to CP869.
+*/
+CONST CHAR
+yeg69[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 164, 165, 166, 167, 168, 169, 170, 172, 173, 181, 182, 183, 184, 189, 190,
+198, 199, 207, 208, 209, 210, 211, 212, 213, 32, 32, 23, 124, 125, 126, 127
+};
+/*
+ 8-bit table providing readable translation from CP869 to ELOT 927.
+*/
+CONST CHAR
+y69eg[] = { /* PC Code Page 869 to ELOT 927 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127,
+UNK, UNK, UNK, UNK, UNK, UNK, 97, UNK, 46, UNK, 124, 39, 39, 101, 45, 103,
+105, 105, 111, UNK, UNK, 116, 116, UNK, 120, 50, 51, 97, UNK, 101, 103, 105,
+105, 105, 111, 116, 97, 98, 99, 100, 101, 102, 103, UNK, 104, 105, 34, 34,
+UNK, UNK, UNK, UNK, UNK, 106, 107, 108, 109, UNK, UNK, UNK, UNK, 110, 111, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, 112, 113, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 114,
+115, 116, 117, 118, 119, 120, 97, 98, 99, UNK, UNK, UNK, UNK, 100, 101, UNK,
+102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 39,
+ 45, UNK, 116, 117, 118, UNK, 119, UNK, UNK, UNK, 120, 116, 116, 120, UNK, 32
+
+};
+/*
+ 7-bit table providing readable translation from ELOT 927 to ISO Latin/Greek.
+*/
+CONST CHAR
+yeglg[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 211, 212, 213, 214, 215, 216, 217, 32, 32, 123, 124, 125, 126, 127
+};
+/*
+ 8-bit table providing readable translation from ISO Latin/Greek to ELOT 927.
+*/
+CONST CHAR
+ylgeg[] = { /* Latin/Greek to ELOT 927 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
+ 32, 39, 39, UNK, UNK, UNK, 124, UNK, 34, UNK, UNK, 34, UNK, 45, UNK, 45,
+UNK, UNK, 50, 51, 39, UNK, 97, 46, 101, 103, 105, 34, 111, UNK, 116, 120,
+UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, UNK, 114, 115, 116, 117, 118, 119, 120, 105, 116, 97, 101, 103, 105,
+116, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 105, 116, 111, 116, 120, UNK
+};
+#endif /* GREEK */
+
+/* Translation functions ... */
+
+CHAR /* The identity function... */
+#ifdef CK_ANSIC
+ident(CHAR c) /* (no longer used) */
+#else
+ident(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* ident */
+ return(c); /* Instead, enter NULL in the */
+} /* table of functions to avoid */
+ /* needless function calls. */
+
+CHAR
+#ifdef CK_ANSIC
+xleft128(CHAR c)
+#else
+xleft128(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xleft128 */
+ return((c < 128) ? c : '?');
+}
+
+CHAR
+#ifdef CK_ANSIC
+xleft160(CHAR c)
+#else
+xleft160(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xleft160 */
+ return((c < 160) ? c : '?');
+}
+
+
+CHAR
+#ifdef CK_ANSIC
+xl1as(CHAR c)
+#else
+xl1as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1as */ /* Latin-1 to US ASCII... */
+ switch(langs[language].id) {
+
+ case L_DUTCH:
+ if (c == 255) { /* Dutch umlaut-y */
+ zmstuff('j'); /* becomes ij */
+ return('i');
+ } else return(yl1as[c]); /* all others by the book */
+
+ case L_GERMAN:
+ switch (c) { /* German, special rules. */
+ case 196: /* umlaut-A -> Ae */
+ zmstuff('e');
+ return('A');
+ case 214: /* umlaut-O -> Oe */
+ zmstuff('e');
+ return('O');
+ case 220: /* umlaut-U -> Ue */
+ zmstuff('e');
+ return('U');
+ case 228: /* umlaut-a -> ae */
+ zmstuff('e');
+ return('a');
+ case 246: /* umlaut-o -> oe */
+ zmstuff('e');
+ return('o');
+ case 252: /* umlaut-u -> ue */
+ zmstuff('e');
+ return('u');
+ case 223: /* ess-zet -> ss */
+ zmstuff('s');
+ return('s');
+ default: return(yl1as[c]); /* all others by the book */
+ }
+ case L_DANISH:
+ case L_FINNISH:
+ case L_NORWEGIAN:
+ case L_SWEDISH:
+ switch (c) { /* Scandanavian languages. */
+ case 196: /* umlaut-A -> Ae */
+ case 198: /* AE ligature also -> Ae */
+ zmstuff('e');
+ return('A');
+ case 214: /* umlaut-O -> Oe */
+ case 216: /* O-slash -> Oe */
+ zmstuff('e');
+ return('O');
+ case 220: /* umlaut-U -> Ue */
+ /* return('Y'); replaced by "Ue" by popular demand. */
+ /* Y for Umlaut-U is only used in German names. */
+ zmstuff('e');
+ return('U');
+ case 228: /* umlaut-a -> ae */
+ case 230: /* ditto for ae ligature */
+ zmstuff('e');
+ return('a');
+ case 246: /* umlaut-o -> oe */
+ case 248: /* o-slash -> oe */
+ zmstuff('e');
+ return('o');
+ case 252: /* umlaut-u -> ue */
+ /* return('y'); replaced by "ue" by popular demand. */
+ zmstuff('e');
+ return('u');
+ case 197: /* A-ring -> Aa */
+ zmstuff('a');
+ return('A');
+ case 229: /* a-ring -> aa */
+ zmstuff('a');
+ return('a');
+ default: return(yl1as[c]); /* All others by the book */
+ }
+ case L_ICELANDIC: /* Icelandic. */
+ switch (c) {
+ case 198: /* uppercase AE -> AE */
+ zmstuff('e');
+ return('A');
+ case 208: /* uppercase Eth -> D */
+ return('D');
+ case 214: /* uppercase O-diaeresis -> Oe */
+ zmstuff('e');
+ return('O');
+ case 222: /* uppercase Thorn -> Th */
+ zmstuff('h');
+ return('T');
+ case 230: /* lowercase ae -> ae */
+ zmstuff('e');
+ return('a');
+ case 240: /* lowercase Eth -> d */
+ return('d');
+ case 246: /* lowercase O-diaeresis -> oe */
+ zmstuff('e');
+ return('o');
+ case 254: /* lowercase Thorn -> th */
+ zmstuff('h');
+ return('t');
+ default: return(yl1as[c]); /* All others by the book */
+ }
+ default:
+ return(yl1as[c]); /* None of the above, by the table. */
+ }
+}
+
+CHAR /* CP1252 to ASCII */
+#ifdef CK_ANSIC
+xw1as(CHAR c)
+#else
+xw1as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1as */
+ switch(c) { /* Microsoft name... */
+ case 0x80: return('?'); /* Euro Sign */
+ case 0x82: return('\047'); /* Single Low-9 Quotation Mark */
+ case 0x83: return('f'); /* Latin Small Letter f with Hook */
+ case 0x84: return('"'); /* Double low-9 Quotation Mark */
+ case 0x85: return('-'); /* Horizontal Ellipsis */
+ case 0x86: return('+'); /* Dagger */
+ case 0x87: return('+'); /* Double Dagger */
+ case 0x88: return('^'); /* Modifier Letter Circumflex Accent */
+ case 0x89: return('?'); /* Per Mille Sign */
+ case 0x8A: return('S'); /* Latin Capital Letter S with Caron */
+ case 0x8B: return('<'); /* Single Left Angle Quotation Mark */
+ case 0x8C: return('O'); /* Latin Capital Ligature OE */
+ case 0x8E: return('Z'); /* Latin Capital Letter Z with Caron */
+ case 0x91: return('\047'); /* Left Single Quotation Mark */
+ case 0x92: return('\047'); /* Right Single Quotation Mark */
+ case 0x93: return('"'); /* Left Double Quotation Mark */
+ case 0x94: return('"'); /* Right Double Quotation Mark */
+ case 0x95: return('.'); /* Bullet */
+ case 0x96: return('-'); /* En Dash */
+ case 0x97: return('-'); /* Em Dash */
+ case 0x98: return('~'); /* Small Tilde */
+ case 0x99: return('T'); /* Trade Mark Sign */
+ case 0x9A: return('s'); /* Latin Small Letter s with Caron */
+ case 0x9B: return('>'); /* Single Right Angle Quotation Mark */
+ case 0x9C: return('o'); /* Latin Small Ligature OE */
+ case 0x9E: return('z'); /* Latin Small Letter z with Caron */
+ case 0x9F: return('Y'); /* Latin Capital Letter Y Diaeresis */
+ default:
+ if (c > 0x80 && c < 0xa0)
+ return('?');
+ else
+ return(yl1as[c]);
+ }
+}
+
+CHAR /* CP1252 to Latin-1 */
+#ifdef CK_ANSIC
+xw1l1(CHAR c)
+#else
+xw1l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1l1 */
+ if (c == 0x95) return(0xb7); /* Middle dot */
+ return((c < 160) ? xw1as(c) : c);
+}
+
+CHAR /* Latin-1 to German */
+#ifdef CK_ANSIC
+xl1ge(CHAR c)
+#else
+xl1ge(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1ge */
+ return(yl1ge[c]);
+}
+
+CHAR /* German to Latin-1 */
+#ifdef CK_ANSIC
+xgel1(CHAR c)
+#else
+xgel1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xgel1 */
+ if (c & 0x80)
+ return(UNK);
+ return(ygel1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xgeas(CHAR c)
+#else
+xgeas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xgeas */ /* German ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 91: /* umlaut-A -> Ae */
+ zmstuff('e');
+ return('A');
+ case 92: /* umlaut-O -> Oe */
+ zmstuff('e');
+ return('O');
+ case 93: /* umlaut-U -> Ue */
+ zmstuff('e');
+ return('U');
+ case 123: /* umlaut-a -> ae */
+ zmstuff('e');
+ return('a');
+ case 124: /* umlaut-o -> oe */
+ zmstuff('e');
+ return('o');
+ case 125: /* umlaut-u -> ue */
+ zmstuff('e');
+ return('u');
+ case 126: /* ess-zet -> ss */
+ zmstuff('s');
+ return('s');
+ default: return(c); /* all others stay the same */
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1w1(CHAR c)
+#else
+xl1w1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1w1 */ /* Latin-1 to CP1252 (Windows L1) */
+ if (c > 127 && c < 160)
+ return(UNK);
+ else
+ return(c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xduas(CHAR c)
+#else
+xduas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xduas */ /* Dutch ISO 646 to US ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 64: return(UNK); /* 3/4 */
+ case 91: /* y-diaeresis */
+ zmstuff('j');
+ return('i');
+ case 92: return(UNK); /* 1/2 */
+ case 93: return(124); /* vertical bar */
+ case 123: return(34); /* diaeresis */
+ case 124: return(UNK); /* Florin */
+ case 125: return(UNK); /* 1/4 */
+ case 126: return(39); /* Apostrophe */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xfias(CHAR c)
+#else
+xfias(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xfias */ /* Finnish ISO 646 to US ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 91: /* A-diaeresis */
+ zmstuff('e');
+ return('A');
+ case 92: /* O-diaeresis */
+ zmstuff('e');
+ return('O');
+ case 93: /* A-ring */
+ zmstuff('a');
+ return('A');
+ case 94: /* U-diaeresis */
+ /* return('Y'); */
+ zmstuff('e');
+ return('U');
+ case 96: /* e-acute */
+ return('e');
+ case 123: /* a-diaeresis */
+ zmstuff('e');
+ return('a');
+ case 124: /* o-diaeresis */
+ zmstuff('e');
+ return('o');
+ case 125: /* a-ring */
+ zmstuff('a');
+ return('a');
+ case 126: /* u-diaeresis */
+ /* return('y'); */
+ zmstuff('e');
+ return('U');
+ default:
+ return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xfras(CHAR c)
+#else
+xfras(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xfras */ /* French ISO 646 to US ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 64: return(97); /* a grave */
+ case 91: return(UNK); /* degree sign */
+ case 92: return(99); /* c cedilla */
+ case 93: return(UNK); /* paragraph sign */
+ case 123: return(101); /* e acute */
+ case 124: return(117); /* u grave */
+ case 125: return(101); /* e grave */
+ case 126: return(34); /* diaeresis */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xfcas(CHAR c)
+#else
+xfcas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xfcas */ /* French Canadian ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 64: return('a'); /* a grave */
+ case 91: return('a'); /* a circumflex */
+ case 92: return('c'); /* c cedilla */
+ case 93: return('e'); /* e circumflex */
+ case 94: return('i'); /* i circumflex */
+ case 96: return('o'); /* o circumflex */
+ case 123: return('e'); /* e acute */
+ case 124: return('u'); /* u grave */
+ case 125: return('e'); /* e grave */
+ case 126: return('u'); /* u circumflex */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xitas(CHAR c)
+#else
+xitas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xitas */ /* Italian ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 91: return(UNK); /* degree */
+ case 92: return('c'); /* c cedilla */
+ case 93: return('e'); /* e acute */
+ case 96: return('u'); /* u grave */
+ case 123: return('a'); /* a grave */
+ case 124: return('o'); /* o grave */
+ case 125: return('e'); /* e grave */
+ case 126: return('i'); /* i grave */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xneas(CHAR c)
+#else
+xneas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xneas */ /* NeXT to ASCII */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 234) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 250) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ c = xnel1(c); /* Convert to Latin-1 */
+ return(yl1as[c]); /* Convert Latin-1 to ASCII */
+}
+
+CHAR
+#ifdef CK_ANSIC
+xnoas(CHAR c)
+#else
+xnoas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xnoas */ /* Norge/Danish ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 91:
+ zmstuff('E'); /* AE digraph */
+ return('A');
+ case 92: return('O'); /* O slash */
+ case 93: /* A ring */
+ zmstuff('a');
+ return('A');
+ case 123: /* ae digraph */
+ zmstuff('e');
+ return('a');
+ case 124: return('o'); /* o slash */
+ case 125: /* a ring */
+ zmstuff('a');
+ return('a');
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xpoas(CHAR c)
+#else
+xpoas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xpoas */ /* Portuguese ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 91: return('A'); /* A tilde */
+ case 92: return('C'); /* C cedilla */
+ case 93: return('O'); /* O tilde */
+ case 123: return('a'); /* a tilde */
+ case 124: return('c'); /* c cedilla */
+ case 125: return('o'); /* o tilde */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xspas(CHAR c)
+#else
+xspas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xspas */ /* Spanish ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 91: return(33); /* Inverted exclamation */
+ case 92: return('N'); /* N tilde */
+ case 93: return(63); /* Inverted question mark */
+ case 123: return(UNK); /* degree */
+ case 124: return('n'); /* n tilde */
+ case 125: return('c'); /* c cedilla */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xswas(CHAR c)
+#else
+xswas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xswas */ /* Swedish ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 64: return('E'); /* E acute */
+ case 91: /* A diaeresis */
+ zmstuff('e');
+ return('A');
+ case 92: /* O diaeresis */
+ zmstuff('e');
+ return('O');
+ case 93: /* A ring */
+ zmstuff('a');
+ return('A');
+ case 94: /* U diaeresis */
+ /* return('Y'); */
+ zmstuff('e');
+ return('U');
+ case 96: return('e'); /* e acute */
+ case 123: /* a diaeresis */
+ zmstuff('e');
+ return('a');
+ case 124: /* o diaeresis */
+ zmstuff('e');
+ return('o');
+ case 125: /* a ring */
+ zmstuff('a');
+ return('a');
+ case 126: /* u diaeresis */
+ /* return('y'); */
+ zmstuff('e');
+ return('u');
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xchas(CHAR c)
+#else
+xchas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xchas */ /* Swiss ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 35: return('u'); /* u grave */
+ case 64: return('a'); /* a grave */
+ case 91: return('e'); /* e acute */
+ case 92: return('c'); /* c cedilla */
+ case 93: return('e'); /* e circumflex */
+ case 94: return('i'); /* i circumflex */
+ case 95: return('e'); /* e grave */
+ case 96: return('o'); /* o circumflex */
+ case 123: /* a diaeresis */
+ zmstuff('e');
+ return('a');
+ case 124: /* o diaeresis */
+ zmstuff('e');
+ return('o');
+ case 125: /* u diaeresis */
+ zmstuff('e');
+ return('u');
+ case 126: return('u'); /* u circumflex */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xhuas(CHAR c)
+#else
+xhuas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xhuas */ /* Hungarian ISO 646 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ switch (c) {
+ case 64: return('A'); /* A acute */
+ case 91: return('E'); /* E acute */
+ case 92: return('O'); /* O diaeresis */
+ case 93: return('U'); /* U diaeresis */
+ case 96: return('a'); /* a acute */
+ case 123: return('e'); /* e acute */
+ case 124: return('o'); /* o acute */
+ case 125: return('u'); /* u acute */
+ case 126: return(34); /* double acute accent */
+ default: return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xdmas(CHAR c)
+#else
+xdmas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xdmas */ /* DEC MCS to ASCII */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 215) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 247) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ return(yl1as[c]); /* Otherwise treat like Latin-1 */
+}
+
+CHAR
+#ifdef CK_ANSIC
+xdgas(CHAR c)
+#else
+xdgas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xdgas */ /* Data General to ASCII */
+ switch(c) {
+ case 180: return('f'); /* Florin */
+ case 183: return('<'); /* Less-equal */
+ case 184: return('>'); /* Greater-equal */
+ case 186: return(96); /* Grave accent */
+ case 191: return('^'); /* Uparrow */
+ case 215:
+ if (langs[language].id == L_FRENCH) { /* OE digraph */
+ zmstuff('E');
+ return('O');
+ } else return('O');
+ case 247:
+ if (langs[language].id == L_FRENCH) { /* oe digraph */
+ zmstuff('e');
+ return('o');
+ } else return('o');
+ case 175: case 179: case 220: case 222:
+ case 223: case 254: case 255:
+ return(UNK);
+ default: /* The rest, convert to Latin-1 */
+ return(yl1as[ydgl1[c]]); /* and from there to ASCII */
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xr8as(CHAR c)
+#else
+xr8as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xr8as */ /* Hewlett Packard Roman8 to ASCII */
+ switch(c) {
+ case 175: return('L'); /* Lira */
+ case 190: return('f'); /* Florin */
+ case 235: return('S'); /* S caron */
+ case 236: return('s'); /* s caron */
+ case 246: return('-'); /* Horizontal bar */
+ case 252: return('*'); /* Solid box */
+ default: /* The rest, convert to Latin-1 */
+ return(yl1as[yr8l1[c]]); /* and from there to ASCII */
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xukl1(CHAR c)
+#else
+xukl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xukl1 */ /* UK ASCII to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ if (c == 35)
+ return(163);
+ else return(c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1uk(CHAR c)
+#else
+xl1uk(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1uk */ /* Latin-1 to UK ASCII */
+ if (c == 163)
+ return(35);
+ else return(yl1as[c]);
+}
+
+CHAR /* Latin-1 to French ISO 646 */
+#ifdef CK_ANSIC
+xl1fr(CHAR c)
+#else
+xl1fr(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1fr */
+ return(yl1fr[c]);
+}
+
+
+CHAR /* French ISO 646 to Latin-1 */
+#ifdef CK_ANSIC
+xfrl1(CHAR c)
+#else
+xfrl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xfrl1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yfrl1[c]);
+}
+
+CHAR /* Latin-1 to Dutch ASCII */
+#ifdef CK_ANSIC
+xl1du(CHAR c)
+#else
+xl1du(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1du */
+ return(yl1du[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xdul1(CHAR c)
+#else
+xdul1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xdul1 */ /* Dutch ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(ydul1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xfil1(CHAR c)
+#else
+xfil1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xfil1 */ /* Finnish ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yfil1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1fi(CHAR c)
+#else
+xl1fi(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1fi */ /* Latin-1 to Finnish ISO 646 */
+ return(yl1fi[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xfcl1(CHAR c)
+#else
+xfcl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xfcl1 */ /* French Canadian ISO646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yfcl1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1fc(CHAR c)
+#else
+xl1fc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1fc */ /* Latin-1 to French Canadian ISO646 */
+ return(yl1fc[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xitl1(CHAR c)
+#else
+xitl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xitl1 */ /* Italian ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yitl1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1it(CHAR c)
+#else
+xl1it(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1it */ /* Latin-1 to Italian ISO 646 */
+ return(yl1it[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xnel1(CHAR c)
+#else
+xnel1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xnel1 */ /* NeXT to Latin-1 */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 234) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 250) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ return(ynel1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xnel9(CHAR c)
+#else
+xnel9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xnel9 */ /* NeXT to Latin-9 */
+ switch (c) {
+ case 234: return(188); /* OE */
+ case 250: return(189); /* oe */
+ case 188: return(234); /* keep it invertible... */
+ case 189: return(250); /* oe */
+ default:
+ return(ynel1[c]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1ne(CHAR c)
+#else
+xl1ne(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1ne */ /* Latin-1 to NeXT */
+ return(yl1ne[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl9ne(CHAR c)
+#else
+xl9ne(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl9ne */ /* Latin-9 to NeXT */
+ switch (c) {
+ case 188: return(234); /* OE */
+ case 189: return(250); /* oe */
+ case 234: return(188); /* OE */
+ case 250: return(189); /* oe */
+ default:
+ return(yl1ne[c]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xnol1(CHAR c)
+#else
+xnol1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xnol1 */ /* Norway/Denmark ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(ynol1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1no(CHAR c)
+#else
+xl1no(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1no */ /* Latin-1 to Norway/Denmark ISO 646 */
+ return(yl1no[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xpol1(CHAR c)
+#else
+xpol1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xpol1 */ /* Portuguese ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(ypol1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1po(CHAR c)
+#else
+xl1po(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1po */ /* Latin-1 to Portuguese ISO 646 */
+ return(yl1po[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xspl1(CHAR c)
+#else
+xspl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xspl1 */ /* Spanish ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yspl1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1sp(CHAR c)
+#else
+xl1sp(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1sp */ /* Latin-1 to Spanish ISO 646 */
+ return(yl1sp[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xswl1(CHAR c)
+#else
+xswl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xswl1 */ /* Swedish ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yswl1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1sw(CHAR c)
+#else
+xl1sw(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1sw */ /* Latin-1 to Swedish ISO 646 */
+ return(yl1sw[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xchl1(CHAR c)
+#else
+xchl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xchl1 */ /* Swiss ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(ychl1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1ch(CHAR c)
+#else
+xl1ch(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1ch */ /* Latin-1 to Swiss ISO 646 */
+ return(yl1ch[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xhul1(CHAR c)
+#else
+xhul1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xhul1 */ /* Hungarian ISO 646 to Latin-1 */
+ if (c & 0x80)
+ return(UNK);
+ return(yhul1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1hu(CHAR c)
+#else
+xl1hu(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1hu */ /* Latin-1 to Hungarian ISO 646 */
+ return(yl1hu[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1dm(CHAR c)
+#else
+xl1dm(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1dm */ /* Latin-1 to DEC MCS */
+ return(yl1dm[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl9dm(CHAR c)
+#else
+xl9dm(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl9dm */ /* Latin-9 to DEC MCS */
+ switch (c) {
+ case 188: return(215);
+ case 189: return(247);
+ case 215: return(188);
+ case 247: return(189);
+ default:
+ return(yl1dm[c]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl9w1(CHAR c)
+#else
+xl9w1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl9w1 */ /* Latin-9 to CP1252 */
+ if (c < 128)
+ return(c);
+ else if (c < 160)
+ return('?');
+ switch (c) {
+ case 0xa4: return(0x80); /* Euro */
+ case 0xa6: return(0x8a); /* S-caron */
+ case 0xa8: return(0x9a); /* s-caron */
+ case 0xb4: return(0x8e); /* Z-caron */
+ case 0xb8: return(0x9e); /* z-caron */
+ case 0xbc: return(0x8c); /* OE */
+ case 0xbd: return(0x9c); /* oe */
+ case 0xbe: return(0x9f); /* Y-diaeresis */
+ default:
+ return(c);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1dg(CHAR c)
+#else
+xl1dg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1dg */ /* Latin-1 to DG ICS */
+ return(yl1dg[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xdml1(CHAR c)
+#else
+xdml1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xdml1 */ /* DEC MCS to Latin-1 */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 215) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 247) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ return(ydml1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xdml9(CHAR c)
+#else
+xdml9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xdml9 */ /* DEC MCS to Latin-9 */
+ switch (c) {
+ case 215: return(188); /* OE */
+ case 247: return(189); /* oe */
+ case 188: return(215); /* and swap the other two... */
+ case 189: return(247); /* (1/4 and 1/2) */
+ default: /* to keep it invertible */
+ return(ydml1[c]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xdgl1(CHAR c)
+#else
+xdgl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xdgl1 */ /* DG International CS to Latin-1 */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 215) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 247) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ return(ydgl1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xr8l1(CHAR c)
+#else
+xr8l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xr8l1 */ /* Hewlett Packard Roman8 to Latin-1 */
+ return(yr8l1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1r8(CHAR c)
+#else
+xl1r8(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1r8 */ /* Latin-1 to Hewlett Packard Roman8 */
+ return(yl1r8[c]);
+}
+
+/* Translation functions for receiving files and translating them into ASCII */
+
+CHAR
+#ifdef CK_ANSIC
+zl1as(CHAR c)
+#else
+zl1as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* zl1as */
+ switch(langs[language].id) {
+
+ case L_DUTCH:
+ if (c == 255) { /* Dutch umlaut-y */
+ zdstuff('j'); /* becomes ij */
+ return('i');
+ } else return(yl1as[c]); /* all others by the book */
+
+ case L_GERMAN:
+ switch (c) { /* German, special rules. */
+ case 196: /* umlaut-A -> Ae */
+ zdstuff('e');
+ return('A');
+ case 214: /* umlaut-O -> Oe */
+ zdstuff('e');
+ return('O');
+ case 220: /* umlaut-U -> Ue */
+ zdstuff('e');
+ return('U');
+ case 228: /* umlaut-a -> ae */
+ zdstuff('e');
+ return('a');
+ case 246: /* umlaut-o -> oe */
+ zdstuff('e');
+ return('o');
+ case 252: /* umlaut-u -> ue */
+ zdstuff('e');
+ return('u');
+ case 223: /* ess-zet -> ss */
+ zdstuff('s');
+ return('s');
+ default: return(yl1as[c]); /* all others by the book */
+ }
+ case L_DANISH:
+ case L_FINNISH:
+ case L_NORWEGIAN:
+ case L_SWEDISH:
+ switch (c) { /* Scandanavian languages. */
+ case 196: /* umlaut-A -> Ae */
+ zdstuff('e');
+ return('A');
+ case 214: /* umlaut-O -> Oe */
+ case 216: /* O-slash -> Oe */
+ zdstuff('e');
+ return('O');
+ case 220: /* umlaut-U -> Y */
+ /* return('Y'); */
+ zdstuff('e');
+ return('U');
+ case 228: /* umlaut-a -> ae */
+ zdstuff('e');
+ return('a');
+ case 246: /* umlaut-o -> oe */
+ case 248: /* o-slash -> oe */
+ zdstuff('e');
+ return('o');
+ case 252: /* umlaut-u -> y */
+ /* return('y'); */
+ zdstuff('e');
+ return('u');
+ case 197: /* A-ring -> Aa */
+ zdstuff('a');
+ return('A');
+ case 229: /* a-ring -> aa */
+ zdstuff('a');
+ return('a');
+ default: return(yl1as[c]); /* All others by the book */
+ }
+ default:
+ return(yl1as[c]); /* No language, go by the table. */
+ }
+}
+
+CHAR /* IBM CP437 to Latin-1 */
+#ifdef CK_ANSIC
+x43l1(CHAR c)
+#else
+x43l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x43l1 */
+ return(y43l1[c]);
+}
+
+CHAR /* IBM CP850 to Latin-1 */
+#ifdef CK_ANSIC
+x85l1(CHAR c)
+#else
+x85l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x85l1 */
+ return(y85l1[c]);
+}
+
+CHAR /* Latin-1 to IBM CP437 */
+#ifdef CK_ANSIC
+xl143(CHAR c)
+#else
+xl143(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl143 */
+ return(yl143[c]);
+}
+
+CHAR /* Latin-1 to CP850 */
+#ifdef CK_ANSIC
+xl185(CHAR c)
+#else
+xl185(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl185 */
+ return(yl185[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+x43as(CHAR c)
+#else
+x43as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x43as */ /* CP437 to ASCII */
+ c = y43l1[c]; /* Translate to Latin-1 */
+ return(xl143(c)); /* and from Latin-1 to ASCII. */
+}
+
+CHAR
+#ifdef CK_ANSIC
+x85as(CHAR c)
+#else
+x85as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x85as */ /* CP850 to ASCII */
+ c = y85l1[c]; /* Translate to Latin-1 */
+ return(xl1as(c)); /* and from Latin-1 to ASCII. */
+}
+
+CHAR /* Macintosh Latin to Latin-1 */
+#ifdef CK_ANSIC
+xaql1(CHAR c)
+#else
+xaql1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xaql1 */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 206) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 207) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ return(yaql1[c]);
+}
+
+CHAR /* Macintosh Latin to ASCII */
+#ifdef CK_ANSIC
+xaqas(CHAR c)
+#else
+xaqas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xaqas */
+ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */
+ if (c == 206) { /* handle OE digraph. */
+ zmstuff('E');
+ return('O');
+ } else if (c == 207) { /* Also lowercase oe. */
+ zmstuff('e');
+ return('o');
+ }
+ }
+ c = yaql1[c]; /* Translate to Latin-1 */
+ return(xl1as(c)); /* then to ASCII. */
+}
+
+CHAR /* Latin-1 to Macintosh Latin */
+#ifdef CK_ANSIC
+xl1aq(CHAR c)
+#else
+xl1aq(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1aq */
+ return(yl1aq[c]);
+}
+
+#ifdef LATIN2
+
+/* Translation functions for Latin Alphabet 2 */
+
+CHAR /* Latin-2 to Latin-1 */
+#ifdef CK_ANSIC
+xl2l1(CHAR c)
+#else
+xl2l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2l1 */
+ return(yl2l1[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl2w1(CHAR c)
+#else
+xl2w1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2w1 */ /* Latin-2 to CP1252 (Windows L1) */
+ if (c > 127 && c < 160)
+ return(UNK);
+ else
+ return(yl2l1[c]);
+}
+
+CHAR /* Latin-1 to Latin-2 */
+#ifdef CK_ANSIC
+xl1l2(CHAR c)
+#else
+xl1l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll1l2 */
+ return(yl1l2[c]);
+}
+
+CHAR /* CP1252 to Latin-1 */
+#ifdef CK_ANSIC
+xw1l2(CHAR c)
+#else
+xw1l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1l2 */
+ switch (c) {
+ case 0x8a: return(0xa9); /* S caron */
+ case 0x8e: return(0xae); /* Z caron */
+ case 0x9a: return(0xb9); /* s caron */
+ case 0x9e: return(0xbe); /* z caron */
+ default:
+ return((c < 160) ? xw1as(c) : xl1l2(c));
+ }
+}
+
+
+CHAR /* Latin-2 to ASCII */
+#ifdef CK_ANSIC
+xl2as(CHAR c)
+#else
+xl2as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2as */
+ return(yl2as[c]);
+}
+
+CHAR /* Latin-2 to CP852 */
+#ifdef CK_ANSIC
+xl252(CHAR c)
+#else
+xl252(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll252 */
+ return(yl252[c]);
+}
+
+CHAR /* Latin-2 to Mazovia */
+#ifdef CK_ANSIC
+xl2mz(CHAR c)
+#else
+xl2mz(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2mz */
+ return(yl2mz[c]);
+}
+
+CHAR /* Latin-1 to Mazovia */
+#ifdef CK_ANSIC
+xl1mz(CHAR c)
+#else
+xl1mz(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll1mz */
+ return(yl2mz[yl1l2[c]]);
+}
+
+CHAR /* Mazovia to Latin-1 */
+#ifdef CK_ANSIC
+xmzl1(CHAR c)
+#else
+xmzl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xmzl1 */
+ return(yl2l1[ymzl2[c]]);
+}
+
+CHAR /* Mazovia to Latin-9 */
+#ifdef CK_ANSIC
+xmzl9(CHAR c)
+#else
+xmzl9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xmzl9 */
+ return(xl2l9(ymzl2[c]));
+}
+
+CHAR /* CP852 to Latin-2 */
+#ifdef CK_ANSIC
+x52l2(CHAR c)
+#else
+x52l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x52l2 */
+ return(y52l2[c]);
+}
+
+CHAR /* Mazovia to Latin-2 */
+#ifdef CK_ANSIC
+xmzl2(CHAR c)
+#else
+xmzl2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xmzl2 */
+ return(ymzl2[c]);
+}
+
+CHAR /* Latin-2 to CP1250 */
+#ifdef CK_ANSIC
+xl21250(CHAR c)
+#else
+xl21250(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll21250 */
+ return(yl21250[c]);
+}
+
+CHAR /* CP1250 to Latin-2 */
+#ifdef CK_ANSIC
+x1250l2(CHAR c)
+#else
+x1250l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x1250l2 */
+ return(y1250l2[c]);
+}
+
+CHAR /* CP852 to ASCII */
+#ifdef CK_ANSIC
+x52as(CHAR c)
+#else
+x52as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl52as */
+ return(yl2as[y52l2[c]]); /* CP852 -> Latin-2 -> ASCII */
+}
+
+CHAR /* CP1250 to ASCII */
+#ifdef CK_ANSIC
+x1250as(CHAR c)
+#else
+x1250as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1250as */
+ return(yl2as[y1250l2[c]]); /* CP81250 -> Latin-2 -> ASCII */
+}
+
+
+CHAR /* CP852 to Latin-1 */
+#ifdef CK_ANSIC
+x52l1(CHAR c)
+#else
+x52l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl52l1 */
+ return(yl2l1[y52l2[c]]); /* CP852 -> Latin-2 -> Latin-1 */
+}
+
+CHAR /* CP1250 to Latin-1 */
+#ifdef CK_ANSIC
+x1250l1(CHAR c)
+#else
+x1250l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1250l1 */
+ return(yl2l1[y1250l2[c]]); /* CP1250 -> Latin-2 -> Latin-1 */
+}
+
+CHAR /* CP1250 to Latin-9 */
+#ifdef CK_ANSIC
+x1250l9(CHAR c)
+#else
+x1250l9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x1250l9 */
+ if (c == (CHAR)128) /* Euro */
+ return((CHAR)164);
+ else
+ return(xl2l9(y1250l2[c])); /* CP1250 -> Latin-2 -> Latin-9 */
+}
+
+CHAR /* Latin-1 to CP852 */
+#ifdef CK_ANSIC
+xl152(CHAR c)
+#else
+xl152(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll152 */
+ return(yl252[yl1l2[c]]); /* Latin-1 -> Latin-2 -> CP852 */
+}
+
+CHAR /* Latin-1 to CP1250 */
+#ifdef CK_ANSIC
+xl11250(CHAR c)
+#else
+xl11250(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll11250 */
+ return(yl21250[yl1l2[c]]); /* Latin-1 -> Latin-2 -> CP1250 */
+}
+
+CHAR /* Latin-9 to CP1250 */
+#ifdef CK_ANSIC
+xl91250(CHAR c)
+#else
+xl91250(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll91250 */
+ if (c == (CHAR)164) /* Euro */
+ return((CHAR)128);
+ else
+ return(yl21250[xl9l2(c)]); /* Latin-9 -> Latin-2 -> CP1250 */
+}
+
+CHAR /* Latin-9 to Mazovia */
+#ifdef CK_ANSIC
+xl9mz(CHAR c)
+#else
+xl9mz(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll9mz */
+ return(yl2mz[xl9l2(c)]); /* Latin-9 -> Latin-2 -> Mazovia */
+}
+
+CHAR /* Latin-9 to Mazovia */
+#ifdef CK_ANSIC
+xmzas(CHAR c)
+#else
+xmzas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xmzas */
+ return(yl2as[xmzl2(c)]); /* Mazovia -> Latin-2 -> ASCII */
+}
+
+CHAR /* Latin-2 to NeXT */
+#ifdef CK_ANSIC
+xl2ne(CHAR c)
+#else
+xl2ne(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2ne */
+ switch(c) {
+ case 162: return(198); /* Breve */
+ case 163: return(232); /* L with stroke */
+ case 178: return(206); /* Ogonek */
+ case 179: return(248); /* l with stroke */
+ case 183: return(207); /* Caron */
+ case 189: return(205); /* Double acute */
+ case 208: return(144); /* D stroke = Eth */
+ case 240: return(230); /* d stroke = eth */
+ case 255: return(199); /* Dot above */
+ default: return(yl1ne[yl2l1[c]]);
+ }
+}
+
+CHAR /* Latin-2 to CP437 */
+#ifdef CK_ANSIC
+xl243(CHAR c)
+#else
+xl243(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll243 */
+ return(yl1l2[y43l1[c]]);
+}
+
+CHAR /* Latin-2 to CP850 */
+#ifdef CK_ANSIC
+xl285(CHAR c)
+#else
+xl285(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll285 */
+ return(yl1l2[y85l1[c]]);
+}
+
+CHAR /* Latin-2 to Apple */
+#ifdef CK_ANSIC
+xl2aq(CHAR c)
+#else
+xl2aq(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2aq */
+ return(yl1aq[yl2l1[c]]); /* Could do more... */
+}
+
+CHAR /* Latin-2 to DGI */
+#ifdef CK_ANSIC
+xl2dg(CHAR c)
+#else
+xl2dg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2dg */
+ return(ydgl1[yl1l2[c]]);
+}
+
+CHAR /* Latin-2 to Short KOI */
+#ifdef CK_ANSIC
+xl2sk(CHAR c)
+#else
+xl2sk(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2sk */
+ return(islower(c) ? toupper(c) : c);
+}
+
+CHAR /* NeXT to Latin-2 */
+#ifdef CK_ANSIC
+xnel2(CHAR c)
+#else
+xnel2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xnel2 */
+ switch (c) {
+ case 144: return(208); /* D stroke = Eth */
+ case 198: return(162); /* Breve */
+ case 199: return(255); /* Dot above */
+ case 205: return(189); /* Double acute */
+ case 206: return(178); /* Ogonek */
+ case 207: return(183); /* Caron */
+ case 230: return(240); /* d stroke = eth */
+ case 232: return(163); /* L with stroke */
+ case 248: return(179); /* l with stroke */
+ default: return(yl1l2[ynel1[c]]); /* Others, go thru Latin-1 */
+ }
+}
+
+CHAR /* CP437 to Latin-2 */
+#ifdef CK_ANSIC
+x43l2(CHAR c)
+#else
+x43l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl43l2 */
+ return(yl1l2[y43l1[c]]);
+}
+
+CHAR /* CP850 to Latin-2 */
+#ifdef CK_ANSIC
+x85l2(CHAR c)
+#else
+x85l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl85l2 */
+ return(yl1l2[y85l1[c]]);
+}
+
+CHAR /* Apple to Latin-2 */
+#ifdef CK_ANSIC
+xaql2(CHAR c)
+#else
+xaql2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlaql2 */
+ switch (c) {
+ case 249: return(162); /* Breve accent */
+ case 250: return(255); /* Dot accent */
+ case 253: return(189); /* Double acute */
+ default: return(yl1l2[yaql1[c]]);
+ }
+}
+
+CHAR /* DGI to Latin-2 */
+#ifdef CK_ANSIC
+xdgl2(CHAR c)
+#else
+xdgl2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xldgl2 */
+ return(yl1l2[ydgl1[c]]); /* (for now) */
+}
+
+CHAR /* Short KOI to Latin-2 */
+#ifdef CK_ANSIC
+xskl2(CHAR c)
+#else
+xskl2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlskl2 */
+ return(islower(c) ? toupper(c) : c);
+}
+
+CHAR /* Latin-2 to German */
+#ifdef CK_ANSIC
+xl2ge(CHAR c)
+#else
+xl2ge(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2ge */
+ switch(c) {
+ case 167: return(64); /* Paragraph sign */
+ case 196: return(91); /* A-diaeresis */
+ case 214: return(92); /* O-diaeresis */
+ case 220: return(93); /* U-diaeresis */
+ case 223: return(126); /* double-s */
+ case 228: return(123); /* a-diaeresis */
+ case 246: return(124); /* o-diaeresis */
+ case 252: return(125); /* u-diaeresis */
+ default: return(yl2as[c]); /* Others */
+ }
+}
+
+CHAR /* German to Latin-2 */
+#ifdef CK_ANSIC
+xgel2(CHAR c)
+#else
+xgel2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlgel2 */
+ if (c & 0x80)
+ return(UNK);
+ switch(c) {
+ case 64: return(167); /* Paragraph sign */
+ case 91: return(196); /* A-diaeresis */
+ case 92: return(214); /* O-diaeresis */
+ case 93: return(220); /* U-diaeresis */
+ case 123: return(228); /* a-diaeresis */
+ case 126: return(223); /* double-s */
+ case 124: return(246); /* o-diaeresis */
+ case 125: return(252); /* u-diaeresis */
+ default: return(c); /* Others */
+ }
+}
+
+CHAR /* Latin-2 to Hungarian */
+#ifdef CK_ANSIC
+xl2hu(CHAR c)
+#else
+xl2hu(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xll2hu */
+ switch(c) {
+ case 164: return(36); /* Currency symbol */
+ case 189: return(126); /* Double acute accent */
+ case 193: return(64); /* A-acute */
+ case 201: return(91); /* E-acute */
+ case 214: return(92); /* O-diaeresis */
+ case 220: return(93); /* U-diaeresis */
+ case 225: return(96); /* a-acute */
+ case 233: return(123); /* e-acute */
+ case 246: return(124); /* o-diaeresis */
+ case 252: return(125); /* u-diaeresis */
+ default: return(yl2as[c]); /* Others */
+ }
+}
+
+CHAR /* Hungarian to Latin-2 */
+#ifdef CK_ANSIC
+xhul2(CHAR c)
+#else
+xhul2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlhul2 */
+ if (c & 0x80)
+ return(UNK);
+ switch(c) {
+ case 36: return(164); /* Currency symbol */
+ case 64: return(193); /* A-acute */
+ case 91: return(201); /* E-acute */
+ case 92: return(214); /* O-diaeresis */
+ case 93: return(220); /* U-diaeresis */
+ case 96: return(225); /* a-acute */
+ case 123: return(233); /* e-acute */
+ case 124: return(246); /* o-diaeresis */
+ case 125: return(252); /* u-diaeresis */
+ case 126: return(189); /* Double acute accent */
+ default: return(c); /* Others */
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xr8l2(CHAR c)
+#else
+xr8l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xr8l2 */ /* Hewlett Packard Roman8 to Latin-2 */
+ switch (c) {
+ case 235: return(169); /* S caron */
+ case 236: return(185); /* s caron */
+ default: return(yl1l2[yr8l1[c]]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl2r8(CHAR c)
+#else
+xl2r8(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2r8 */ /* Latin-2 to Hewlett Packard Roman8 Character Set */
+ switch (c) {
+ case 169: return(235); /* S caron */
+ case 185: return(236); /* s caron */
+ default: return(yr8l1[yl1l2[c]]);
+ }
+}
+
+#else /* NOLATIN2 */
+
+#define xl1mz NULL
+#define xmzl1 NULL
+#define xl2mz NULL
+#define xmzl2 NULL
+#define xl9mz NULL
+#define xmzl9 NULL
+#define xmzas NULL
+
+#define xl11250 NULL
+#define xl21250 NULL
+#define xl91250 NULL
+
+#define x1250as NULL
+#define x1250l1 NULL
+#define x1250l2 NULL
+#define x1250l9 NULL
+
+#define xl2l1 NULL
+#define xl2w1 NULL
+#define xl1l2 NULL
+#define xw1l2 NULL
+#define xl2as NULL
+#define xl252 NULL
+#define x52l2 NULL
+#define x52as NULL
+#define x52l1 NULL
+#define xl152 NULL
+#define xl2ne NULL
+#define xl243 NULL
+#define xl285 NULL
+#define xl2aq NULL
+#define xl2dg NULL
+#define xl2sk NULL
+#define xnel2 NULL
+#define x43l2 NULL
+#define x85l2 NULL
+#define xaql2 NULL
+#define xdgl2 NULL
+#define xskl2 NULL
+#define xl2ge NULL
+#define xgel2 NULL
+#define xl2hu NULL
+#define xhul2 NULL
+#define xl2r8 NULL
+#define xr8l2 NULL
+#endif /* LATIN2 */
+
+/* This one can also be used for ELOT 927, Hebrew 7, etc */
+
+CHAR
+#ifdef CK_ANSIC
+xassk(CHAR c)
+#else
+xassk(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xassk */ /* ASCII to Short KOI */
+ if (c & 0x80)
+ return(UNK);
+ return((c > 95) ? (c - 32) : c); /* Fold columns 6-7 to 4-5 */
+}
+
+#ifdef CYRILLIC
+/* Translation functions for Cyrillic character sets */
+
+CHAR /* Latin/Cyrillic to CP866 */
+#ifdef CK_ANSIC
+xlcac(CHAR c)
+#else
+xlcac(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlcac */ /* PC Code Page 866 */
+ return(ylcac[c]);
+}
+
+CHAR /* Latin/Cyrillic to */
+#ifdef CK_ANSIC
+xlc55(CHAR c)
+#else
+xlc55(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlc55 */ /* PC Code Page 855 */
+ return(ylc55[c]);
+}
+
+CHAR /* Latin/Cyrillic to */
+#ifdef CK_ANSIC
+xlc1251(CHAR c)
+#else
+xlc1251(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlc1251 */ /* PC Code Page 1251 */
+ return(ylc1251[c]);
+}
+
+CHAR /* Latin/Cyrillic to... */
+#ifdef CK_ANSIC
+xlcbu(CHAR c)
+#else
+xlcbu(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlcbu */ /* Bulgarian PC Code Page */
+ return(ylcbu[c]);
+}
+
+CHAR /* Latin/Cyrillic to Old KOI-8 */
+#ifdef CK_ANSIC
+xlck8(CHAR c)
+#else
+xlck8(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlck8 */
+ return(ylck8[c]);
+}
+
+CHAR /* Latin/Cyrillic to KOI8-R */
+#ifdef CK_ANSIC
+xlckr(CHAR c)
+#else
+xlckr(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlckr */
+ switch(c) {
+ case 0xa1: return(0xb3); /* Io */
+ case 0xf1: return(0xa3); /* io */
+ default:
+ if (c > 0x7f && c < 0xc0)
+ return(UNK);
+ return(ylck8[c]);
+ }
+}
+
+CHAR /* Latin/Cyrillic to KOI8-U */
+#ifdef CK_ANSIC
+xlcku(CHAR c)
+#else
+xlcku(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlcku */
+ switch(c) {
+ case 0xa1: return(0xb3); /* Io */
+ case 0xf1: return(0xa3); /* io */
+ case 0xf4: return(0xa4); /* Ukrainian ie */
+ case 0xf6: return(0xa6); /* Ukrainian i */
+ case 0xf7: return(0xa7); /* Ukrainian yi */
+ case 0xf3: return(0xad); /* Ukrainian ghe with upturn */
+ case 0xa4: return(0xb4); /* Ukrainian Ie */
+ case 0xa6: return(0xb6); /* Ukrainian I */
+ case 0xa7: return(0xb7); /* Ukrainian Yi */
+ case 0xa3: return(0xbd); /* Ukrainian Ghe with upturn */
+ default:
+ if (c > 0x7f && c < 0xc0)
+ return(UNK);
+ return(ylck8[c]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlcsk(CHAR c)
+#else
+xlcsk(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlcsk */ /* Latin/Cyrillic to Short KOI */
+ return(ylcsk[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlcas(CHAR c)
+#else
+xlcas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlcas */ /* Latin/Cyrillic to ASCII */
+ if (langs[language].id == L_RUSSIAN)
+ return(ylcsk[c]);
+ else
+ return((c > 127) ? '?' : c);
+}
+
+CHAR /* CP866 */
+#ifdef CK_ANSIC
+xaclc(CHAR c)
+#else
+xaclc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xaclc */ /* to Latin/Cyrillic */
+ return(yaclc[c]);
+}
+
+CHAR /* CP855 */
+#ifdef CK_ANSIC
+x55lc(CHAR c)
+#else
+x55lc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x55lc */ /* to Latin/Cyrillic */
+ return(y55lc[c]);
+}
+
+CHAR /* Bulgarian PC Code Page ... */
+#ifdef CK_ANSIC
+xbulc(CHAR c)
+#else
+xbulc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xbulc */ /* to Latin/Cyrillic */
+ return(ybulc[c]);
+}
+
+CHAR /* CP1251 */
+#ifdef CK_ANSIC
+x1251lc(CHAR c)
+#else
+x1251lc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x1251lc */ /* to Latin/Cyrillic */
+ return(y1251lc[c]);
+}
+
+CHAR /* Old KOI-8 to Latin/Cyrillic */
+#ifdef CK_ANSIC
+xk8lc(CHAR c)
+#else
+xk8lc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xk8lc */
+ return(yk8lc[c]);
+}
+
+CHAR /* KOI8-R to Latin/Cyrillic */
+#ifdef CK_ANSIC
+xkrlc(CHAR c)
+#else
+xkrlc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xkrlc */
+ if (c == 0xb3) return(0xa1);
+ else if (c == 0xa3) return(0xf1);
+ else if (c > 0x7f && c < 0xc0)
+ return(UNK);
+ return(yk8lc[c]);
+}
+
+CHAR /* KOI8-U to Latin/Cyrillic */
+#ifdef CK_ANSIC
+xkulc(CHAR c)
+#else
+xkulc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xkulc */
+ switch (c) {
+ case 0xb3: return(0xa1); /* Io */
+ case 0xa3: return(0xf1); /* io */
+ case 0xa4: return(0xf4); /* Ukrainian ie */
+ case 0xa6: return(0xf6); /* Ukrainian i */
+ case 0xa7: return(0xf7); /* Ukrainian yi */
+ case 0xad: return(0xf3); /* Ukrainian ghe with upturn */
+ case 0xb4: return(0xa4); /* Ukrainian Ie */
+ case 0xb6: return(0xa6); /* Ukrainian I */
+ case 0xb7: return(0xa7); /* Ukrainian Yi */
+ case 0xbd: return(0xa3); /* Ukrainian Ghe with upturn */
+ /* Note substitution of Gje for Ghe-Upturn, which is not in 8859-5 */
+ default:
+ if (c > 0x7f && c < 0xc0)
+ return(UNK);
+ return(yk8lc[c]);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xskcy(CHAR c)
+#else
+xskcy(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xskcy */ /* Short KOI to Latin/Cyrillic */
+ return(yskcy[c & 0x7f]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xascy(CHAR c)
+#else
+xascy(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xascy */ /* ASCII to Latin/Cyrillic */
+ if (langs[language].id == L_RUSSIAN) { /* If LANGUAGE == RUSSIAN */
+ return(yskcy[c & 0x7f]); /* treat ASCII as Short KOI */
+ } else return((c > 127) ? '?' : c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xacas(CHAR c)
+#else
+xacas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xacas */ /* CP866 to ASCII */
+ if (langs[language].id == L_RUSSIAN) {
+ c = yaclc[c]; /* First to Latin/Cyrillic */
+ return(ylcsk[c]); /* Then to Short KOI */
+ } else return((c > 127) ? '?' : c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+x55as(CHAR c)
+#else
+x55as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x55as */ /* CP855 to ASCII */
+ if (langs[language].id == L_RUSSIAN) {
+ c = y55lc[c]; /* First to Latin/Cyrillic */
+ return(ylcsk[c]); /* Then to Short KOI */
+ } else return((c > 127) ? '?' : c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+x1251as(CHAR c)
+#else
+x1251as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x1251as */ /* CP81251 to ASCII */
+ if (langs[language].id == L_RUSSIAN) {
+ c = y1251lc[c]; /* First to Latin/Cyrillic */
+ return(ylcsk[c]); /* Then to Short KOI */
+ } else return((c > 127) ? '?' : c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xskas(CHAR c)
+#else
+xskas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xskas */ /* Short KOI to ASCII */
+ return((c > 95) ? '?' : c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xk8as(CHAR c)
+#else
+xk8as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xk8as */ /* Old KOI-8 Cyrillic to ASCII */
+ if (langs[language].id == L_RUSSIAN) {
+ c = yk8lc[c]; /* First to Latin/Cyrillic */
+ return(ylcsk[c]); /* Then to Short KOI */
+ } else return((c > 127) ? '?' : c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1sk(CHAR c)
+#else
+xl1sk(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1sk */ /* Latin-1 to Short KOI */
+ c = zl1as(c); /* Convert to ASCII */
+ return(c = xassk(c)); /* Convert ASCII to Short KOI */
+}
+
+CHAR
+#ifdef CK_ANSIC
+xw1lc(CHAR c)
+#else
+xw1lc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1lc */ /* CP1252 to Latin/Cyrillic */
+ return((c < 160) ? xw1as(c) : zl1as(c));
+}
+
+CHAR
+#ifdef CK_ANSIC
+xaslc(CHAR c)
+#else
+xaslc(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xaslc */ /* ASCII to Latin/Cyrillic */
+ if (langs[language].id == L_RUSSIAN)
+ return(yskcy[c & 0x7f]);
+ else return(c & 0x7f);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xasac(CHAR c)
+#else
+xasac(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xasac */ /* ASCII to CP866 */
+ if (c & 0x80)
+ return(UNK);
+ if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */
+ c = xskcy(c); /* Translate to Latin/Cyrillic */
+ return(ylcac[c]); /* Then to CP866 */
+ } else return(c & 0x7f);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xas55(CHAR c)
+#else
+xas55(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xas55 */ /* ASCII to CP855 */
+ if (c & 0x80)
+ return(UNK);
+ if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */
+ c = xskcy(c); /* Translate to Latin/Cyrillic */
+ return(ylc55[c]); /* Then to CP866 */
+ } else return(c & 0x7f);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xas1251(CHAR c)
+#else
+xas1251(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xas1251 */ /* ASCII to CP81251 */
+ if (c & 0x80)
+ return(UNK);
+ if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */
+ c = xskcy(c); /* Translate to Latin/Cyrillic */
+ return(ylc1251[c]); /* Then to CP866 */
+ } else return(c & 0x7f);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xask8(CHAR c)
+#else
+xask8(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xask8 */ /* ASCII to KOI-8 */
+ if (c & 0x80)
+ return(UNK);
+ if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */
+ c = xskcy(c); /* Translate to Latin/Cyrillic */
+ return(ylck8[c]); /* Then to KOI-8 */
+ } else return(c & 0x7f);
+}
+#else /* No Cyrillic */
+#define xacas NULL
+#define x55as NULL
+#define x1251as NULL
+#define xaclc NULL
+#define x55lc NULL
+#define x1251lc NULL
+#define xasac NULL
+#define xas55 NULL
+#define xas1251 NULL
+#define xascy NULL
+#define xask8 NULL
+#define xaslc NULL
+#define xassk NULL
+#define xk8as NULL
+#define xk8lc NULL
+#define xkrlc NULL
+#define xkulc NULL
+#define xl1sk NULL
+#define xw1lc NULL
+#define xlcac NULL
+#define xlc55 NULL
+#define xlc1251 NULL
+#define xlcas NULL
+#define xlck8 NULL
+#define xlckr NULL
+#define xlcku NULL
+#define xlch7 NULL
+#define xlcsk NULL
+#define xskas NULL
+#define xskcy NULL
+#define xbulc NULL
+#define xlcbu NULL
+#endif /* CYRILLIC */
+
+/* Translation functions for Hebrew character sets */
+
+#ifdef HEBREW
+
+CHAR
+#ifdef CK_ANSIC
+xash7(CHAR c)
+#else
+xash7(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xash7 */ /* ASCII to Hebrew-7 */
+ if (c & 0x80)
+ return(UNK);
+ if (c == 96) return('?');
+ if (c > 96 && c < 123) return(c - 32);
+ else return(c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1h7(CHAR c)
+#else
+xl1h7(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1h7 */ /* Latin-1 to Hebrew-7 */
+ return(xash7(xl1as(c)));
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1lh(CHAR c)
+#else
+xl1lh(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1lh */ /* Latin-1 to Latin/Hebrew */
+ switch(c) {
+ case 170: return('a'); /* Feminine ordinal */
+ case 186: return('o'); /* Masculine ordinal */
+ case 215: return(170); /* Times */
+ case 247: return(186); /* Divide */
+ default: return( (c > 190) ? xl1as(c) : c );
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xw1lh(CHAR c)
+#else
+xw1lh(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1lh */ /* CP1252 to Latin/Hebrew */
+ switch(c) {
+ case 170: return('a'); /* Feminine ordinal */
+ case 186: return('o'); /* Masculine ordinal */
+ case 215: return(170); /* Times */
+ case 247: return(186); /* Divide */
+ default:
+ if (c < 160)
+ return(xw1as(c));
+ else
+ return((c > 190) ? xl1as(c) : c);
+ }
+}
+
+#ifdef LATIN2
+CHAR
+#ifdef CK_ANSIC
+xl2h7(CHAR c)
+#else
+xl2h7(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2h7 */ /* Latin-2 to Hebrew-7 */
+ return(xash7(xl2as(c)));
+}
+#else
+#define xl2h7 NULL
+#endif /* LATIN2 */
+
+#ifndef NOCYRIL
+CHAR
+#ifdef CK_ANSIC
+xlch7(CHAR c)
+#else
+xlch7(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlch7 */ /* Latin/Cyrillic to Hebrew-7 */
+ return(xash7(xlcas(c)));
+}
+#endif /* NOCYRIL */
+
+CHAR
+#ifdef CK_ANSIC
+xlhas(CHAR c)
+#else
+xlhas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlhas */ /* Latin/Hebrew to ASCII */
+ return( (c > 127) ? '?' : c );
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlhl1(CHAR c)
+#else
+xlhl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlhl1 */ /* Latin/Hebrew to Latin-1 */
+ switch (c) {
+ case 170: return(215);
+ case 186: return(247);
+ default: return( (c > 190) ? '?' : c );
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlhw1(CHAR c)
+#else
+xlhw1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlhw1 */ /* Latin/Hebrew to CP1252 */
+ if (c > 127 && c < 160)
+ return('?');
+ switch (c) {
+ case 170: return(215);
+ case 186: return(247);
+ default: return( (c > 190) ? '?' : c );
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlh62(CHAR c)
+#else
+xlh62(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlh62 */ /* Latin/Hebrew to CP862 */
+ return(ylh62[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl162(CHAR c)
+#else
+xl162(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl162 */ /* Latin-1 to CP862 */
+ return(xlh62(xl1lh(c))); /* Via Latin/Hebrew */
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlhh7(CHAR c)
+#else
+xlhh7(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlhh7 */ /* Latin/Hebrew to Hebrew-7 */
+ return(ylhh7[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xh7as(CHAR c)
+#else
+xh7as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xh7as */ /* Hebrew-7 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ return( (c > 95 && c < 123) ? '?' : c );
+}
+
+CHAR
+#ifdef CK_ANSIC
+x62lh(CHAR c)
+#else
+x62lh(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x62lh */ /* CP862 to Latin/Hebrew */
+ return(y62lh[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+x62as(CHAR c)
+#else
+x62as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x62as */ /* CP862 to ASCII */
+ return( xlhas(x62lh(c)) );
+}
+
+CHAR
+#ifdef CK_ANSIC
+x62l1(CHAR c)
+#else
+x62l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x62l1 */ /* CP862 to Latin-1 */
+ return( xlhl1(x62lh(c)) );
+}
+
+CHAR
+#ifdef CK_ANSIC
+xh7lh(CHAR c)
+#else
+xh7lh(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xh7lh */ /* Hebrew-7 to Latin/Hebrew */
+ if (c & 0x80)
+ return(UNK);
+ return(yh7lh[c]);
+}
+
+#else /* No Hebrew */
+
+#define xash7 NULL
+#define xl1h7 NULL
+#define xl2h7 NULL
+#define xlch7 NULL
+#define xl1lh NULL
+#define xw1lh NULL
+#define xlhas NULL
+#define xlhl1 NULL
+#define xlhw1 NULL
+#define xl162 NULL
+#define xlhh7 NULL
+#define xlh62 NULL
+#define xh7as NULL
+#define x62as NULL
+#define x62l1 NULL
+#define xh7lh NULL
+#define x62lh NULL
+
+#endif /* HEBREW */
+
+/* Translation functions for Greek character sets */
+
+#ifdef GREEK
+
+CHAR
+#ifdef CK_ANSIC
+xaseg(CHAR c)
+#else
+xaseg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xaseg */ /* ASCII to ELOT 927 */
+ if (c & 0x80)
+ return(UNK);
+ if (c > 96 && c < 123) return(c - 32);
+ else return(c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1eg(CHAR c)
+#else
+xl1eg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1ge */ /* Latin-1 to ELOT 927 */
+ return(xaseg(xl1as(c)));
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl2lg(CHAR c)
+#else
+xl2lg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2lg */ /* Latin-1 to Latin/Greek */
+ if (c < 160) return(c);
+ else if (c == 160 || c == 168 || c == 173 || c == 174)
+ return(c);
+ else return('?');
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl1lg(CHAR c)
+#else
+xl1lg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl1lg */ /* Latin-1 to Latin/Greek */
+ if (c < 160) return(c);
+ switch(c) {
+ case 160: /* Themselves */
+ case 164:
+ case 166:
+ case 167:
+ case 168:
+ case 169:
+ case 171:
+ case 172:
+ case 173:
+ case 176:
+ case 177:
+ case 178:
+ case 179:
+ case 180:
+ case 187:
+ case 189:
+ return(c);
+ case 181: /* Lowercase mu */
+ return(236);
+ default:
+ return(UNK);
+ }
+}
+
+CHAR
+#ifdef CK_ANSIC
+xw1lg(CHAR c)
+#else
+xw1lg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1lg */ /* CP1252 to Latin/Greek */
+ return((c < 160) ? xw1as(c) : xl1lg(c));
+}
+
+
+#ifdef LATIN2
+CHAR
+#ifdef CK_ANSIC
+xl2eg(CHAR c)
+#else
+xl2eg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2eg */ /* Latin-2 to ELOT 927 */
+ return(xaseg(xl2as(c)));
+}
+#else
+#define xl2eg NULL
+#endif /* LATIN2 */
+
+#ifndef NOCYRIL
+CHAR
+#ifdef CK_ANSIC
+xlceg(CHAR c)
+#else
+xlceg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlceg */ /* Latin/Cyrillic to ELOT 927 */
+ return(xaseg(xlcas(c)));
+}
+#endif /* NOCYRIL */
+
+CHAR
+#ifdef CK_ANSIC
+xlgas(CHAR c)
+#else
+xlgas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlgas */ /* Latin/Greek to ASCII */
+ return( (c > 127) ? '?' : c );
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlgl1(CHAR c)
+#else
+xlgl1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlgl1 */ /* Latin/Greek to Latin-1 */
+ if (c == 236)
+ return(181);
+ else
+ return(xl1lg(c));
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlgw1(CHAR c)
+#else
+xlgw1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlgw1 */ /* Latin/Greek to Latin-1 */
+ if (c > 127 && c < 160)
+ return('?');
+ return(xlgl1(c));
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlg69(CHAR c)
+#else
+xlg69(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlg69 */ /* Latin/Greek to CP869 */
+ return(ylg69[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xl169(CHAR c)
+#else
+xl169(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl169 */ /* Latin-1 to CP869 */
+ return(xlg69(xl1lg(c))); /* Via Latin/Greek */
+}
+
+CHAR
+#ifdef CK_ANSIC
+xlgeg(CHAR c)
+#else
+xlgeg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xlgeg */ /* Latin/Greek to ELOT 927 */
+ return(ylgeg[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+xegas(CHAR c)
+#else
+xegas(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xegas */ /* ELOT 927 to ASCII */
+ if (c & 0x80)
+ return(UNK);
+ return( (c > 96 && c < 123) ? '?' : c );
+}
+
+CHAR
+#ifdef CK_ANSIC
+x69lg(CHAR c)
+#else
+x69lg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x69lg */ /* CP869 to Latin/Greek */
+ return(y69lg[c]);
+}
+
+CHAR
+#ifdef CK_ANSIC
+x69as(CHAR c)
+#else
+x69as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x69as */ /* CP869 to ASCII */
+ return( xlgas(x69lg(c)) );
+}
+
+CHAR
+#ifdef CK_ANSIC
+x69l1(CHAR c)
+#else
+x69l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x69l1 */ /* CP869 to Latin-1 */
+ return( xlgl1(x69lg(c)) );
+}
+
+CHAR
+#ifdef CK_ANSIC
+xeglg(CHAR c)
+#else
+xeglg(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xeglg */ /* ELOT 927 to Latin/Greek */
+ return(yeglg[c]);
+}
+
+#else /* No Greek */
+
+#define x69as NULL
+#define x69l1 NULL
+#define x69lg NULL
+#define xaseg NULL
+#define xegas NULL
+#define xeglg NULL
+#define xl169 NULL
+#define xl1eg NULL
+#define xl1lg NULL
+#define xw1lg NULL
+#define xl2ge NULL
+#define xl2lg NULL
+#define xlcge NULL
+#define xlg69 NULL
+#define xlgas NULL
+#define xlgeg NULL
+#define xlgge NULL
+#define xlgl1 NULL
+#define xlgw1 NULL
+
+#endif /* GREEK */
+
+
+/* Translation functions for Japanese Kanji character sets */
+
+#ifdef KANJI
+/*
+ Translate Kanji Transfer Character Set (EUC) to local file character set,
+ contributed by Dr. Hirofumi Fujii, Japan High Energy Research Laboratory
+ (KEK), Tokyo, Japan.
+
+ a is a byte to be translated, which may be a single-byte character,
+ the Katakana prefix, the first byte of a two-byte Kanji character, or the
+ second byte of 2-byte Kanji character.
+
+ fn is the output function.
+
+ Returns 0 on success, -1 on failure.
+*/
+
+_PROTOTYP(static int jpnxas, (int, int[]) );
+_PROTOTYP(static int jpnxkt, (int, int[]) );
+_PROTOTYP(static int jpnxkn, (int[], int[]) );
+
+static int jpncnt; /* Byte count for Japanese */
+static int jpnlst; /* Last status (for JIS7) */
+
+static int
+jpnxas(a, obuf) int a; int obuf[]; { /* Translate ASCII to local file code */
+ int r;
+
+ r = 0;
+ if (fcharset == FC_JIS7) {
+ switch (jpnlst) {
+ case 1:
+ obuf[0] = 0x0f;
+ obuf[1] = a;
+ r = 2;
+ break;
+ case 2:
+ obuf[0] = 0x1b;
+ obuf[1] = 0x28;
+ obuf[2] = 0x4a;
+ obuf[3] = a;
+ r = 4;
+ break;
+ default:
+ obuf[0] = a;
+ r = 1;
+ break;
+ }
+ } else {
+ obuf[0] = a;
+ r = 1;
+ }
+ return(r);
+}
+
+static int
+jpnxkt(a, obuf) int a; int obuf[]; {
+/* Translate JIS X 201 Katakana to local code */
+
+ int r;
+
+ r = 0;
+ if (fcharset == FC_JIS7) {
+ switch (jpnlst) {
+ case 2: /* from Kanji */
+ obuf[r++] = 0x1b;
+ obuf[r++] = 0x28;
+ obuf[r++] = 0x4a;
+ case 0: /* from Roman */
+ obuf[r++] = 0x0e;
+ default:
+ obuf[r++] = (a & 0x7f);
+ break;
+ }
+ } else {
+ if (fcharset == FC_JEUC)
+ obuf[r++] = 0x8e;
+ obuf[r++] = (a | 0x80);
+ }
+ return(r);
+}
+
+static int
+jpnxkn(ibuf, obuf) int ibuf[], obuf[]; {
+ /* Translate JIS X 0208 Kanji to local code */
+ int c1, c2;
+ int r;
+
+ c1 = ibuf[0] & 0x7f;
+ c2 = ibuf[1] & 0x7f;
+
+ if (fcharset == FC_SHJIS) {
+ if (c1 & 1)
+ c2 += 0x1f;
+ else
+ c2 += 0x7d;
+
+ if (c2 >= 0x7f) c2++;
+
+ c1 = ((c1 - 0x21) >> 1) + 0x81;
+ if (c1 > 0x9f) c1 += 0x40;
+
+ obuf[0] = c1;
+ obuf[1] = c2;
+ r = 2;
+ } else if (fcharset == FC_JIS7) {
+ r = 0;
+ switch (jpnlst) {
+ case 1:
+ obuf[r++] = 0x0f; /* From Katakana */
+ case 0:
+ obuf[r++] = 0x1b;
+ obuf[r++] = 0x24;
+ obuf[r++] = 0x42;
+ default:
+ obuf[r++] = c1;
+ obuf[r++] = c2;
+ break;
+ }
+ } else {
+ obuf[0] = (c1 | 0x80);
+ obuf[1] = (c2 | 0x80);
+ r = 2;
+ }
+ return(r);
+}
+
+int
+xkanjf() {
+/* Initialize parameters for xkanji */
+/* This function should be called when F/X-packet is received */
+ jpncnt = jpnlst = 0;
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+xkanjz(int (*fn)(char))
+#else
+xkanjz(fn) int (*fn)();
+#endif /* CK_ANSIC */
+{ /* xkanjz */
+/*
+ Terminate xkanji
+ This function must be called when Z-packet is received
+ (before closing the file).
+*/
+ static int obuf[6];
+ int r, i, c;
+
+ if (fcharset == FC_JIS7) {
+ c = 'A'; /* Dummy Roman character */
+ r = jpnxas(c, obuf) - 1; /* -1 removes Dummy character */
+ if (r > 0) {
+ for (i = 0; i < r; i++)
+ if (((*fn)((char) obuf[i])) < 0)
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+xkanji(int a, int (*fn)(char))
+#else
+xkanji(a, fn) int a; int (*fn)();
+#endif /* CK_ANSIC */
+{ /* xkanji */
+ static int xbuf[2];
+ static int obuf[8];
+
+ int i, r;
+ int c7;
+ int state=0;
+
+ r = 0;
+ if (jpncnt == 0) {
+ /* 1st byte */
+ if ((a & 0x80) == 0) {
+ /* 8th bit is 0, i.e., single-byte code */
+ r = jpnxas(a, obuf);
+ state = 0;
+ } else {
+ /* 8th bit is 1, check the range */
+ c7 = a & 0x7f;
+ if (((c7 > 0x20) && (c7 < 0x7f)) || (c7 == 0x0e)) {
+ /* double byte code */
+ xbuf[jpncnt++] = a;
+ } else {
+ /* single byte code */
+ r = jpnxas(a, obuf);
+ state = 0;
+ }
+ }
+ } else {
+ /* not the 1st byte */
+ xbuf[jpncnt++] = a;
+ if (xbuf[0] == 0x8e) {
+ r = jpnxkt(xbuf[1], obuf);
+ state = 1;
+ } else {
+ r = jpnxkn(xbuf, obuf);
+ state = 2;
+ }
+ }
+ if (r > 0) {
+ for (i = 0; i < r; i++ )
+ if (((*fn)((char) obuf[i])) < 0)
+ return(-1);
+ jpnlst = state;
+ jpncnt = 0;
+ }
+ return(0);
+}
+
+/*
+ Function for translating from Japanese file character set
+ to Japanese EUC transfer character set.
+ Returns a pointer to a string containing 0, 1, or 2 bytes.
+*/
+
+/* zkanji */
+static int jpnstz; /* status for JIS-7 */
+static int jpnpnd; /* number of pending bytes */
+static int jpnpnt; /* pending buffer index */
+static int jpnpbf[8]; /* pending buffer */
+
+/* There is some duplication here between the old and new JIS-7 parsers */
+/* to be cleaned up later... */
+
+VOID
+j7init() { /* Initialize JIS-7 parser */
+ jpnstz = 0;
+ jpnpnd = 0;
+ jpnpnt = 0;
+}
+
+int
+getj7() { /* Reads JIS-7 returns next EUC byte */
+ int x;
+
+ if (jpnpnd > 0) { /* If something is pending */
+ x = (unsigned) jpnpbf[jpnpnt++]; /* Get it */
+ jpnpnd--;
+ if (jpnpnd < 0) jpnpnd = 0;
+ return((unsigned)x);
+ }
+ jpnpnt = 0;
+
+ if ((x = zminchar()) < 0) return(x);
+ while (jpnpnd == 0) { /* While something is pending... */
+ if ((x > 0x20) && (x < 0x7f)) { /* 7-bit graphic character */
+ switch (jpnstz) {
+ case 1: /* Katakana */
+#ifdef COMMENT
+ /* This can't be right... */
+ jpnpbf[jpnpnd++] = 0x80; /* Insert flag (NOT SS2???) */
+#else
+ jpnpbf[jpnpnd++] = 0x8e; /* Insert SS2 */
+#endif /* COMMENT */
+ jpnpbf[jpnpnd++] = (x | 0x80); /* Insert Kana + 8th bit */
+ break;
+ case 2: /* Kanji */
+ jpnpbf[jpnpnd++] = (x | 0x80); /* Get another byte */
+ if ((x = zminchar()) < 0) return(x);
+ jpnpbf[jpnpnd++] = (x | 0x80);
+ break;
+ default: /* ASCII / JIS Roman */
+ jpnpbf[jpnpnd++] = x;
+ break;
+ }
+ } else if (x == 0x0e) { /* ^N = SO */
+ jpnstz = 1; /* Katakana */
+ if ((x = zminchar()) < 0) return(x);
+ } else if (x == 0x0f) { /* ^O = SI */
+ jpnstz = 0; /* ASCII / JIS Roman */
+ if ((x = zminchar()) < 0) return(x);
+ } else if (x == 0x1b) { /* Escape */
+ jpnpbf[jpnpnd++] = x; /* Save in buffer */
+ if ((x = zminchar()) < 0) return(x);
+ jpnpbf[jpnpnd++] = x; /* Save in buffer */
+ if (x == '$') { /* <ESC>$ */
+ if ((x = zminchar()) < 0) return(x);
+ jpnpbf[jpnpnd++] = x;
+ if ((x == '@') || (x == 'B')) { /* Kanji */
+ jpnstz = 2;
+ jpnpnt = jpnpnd = 0;
+ if ((x = zminchar()) < 0) return(x);
+ }
+ } else if (x == '(') { /* <ESC>( == 94-byte single-byte set */
+ if ((x = zminchar()) < 0) return(x);
+ jpnpbf[jpnpnd++] = x;
+ if ((x == 'B') || (x == 'J')) { /* ASCII or JIS Roman */
+ jpnstz = 0; /* Set state */
+ jpnpnt = jpnpnd = 0; /* Reset pointers */
+ if ((x = zminchar()) < 0) return(x);
+ }
+ } else if (x == 0x1b) { /* <ESC><ESC> */
+ jpnpnt = jpnpnd = 0; /* Reset pointers, stay in state */
+ if ((x = zminchar()) < 0) return(x);
+ }
+ } else { /* Not <ESC> - just save it */
+ jpnpbf[jpnpnd++] = x;
+ }
+ }
+ jpnpnt = 0;
+ x = (unsigned)jpnpbf[jpnpnt++];
+ jpnpnd--;
+ return((unsigned)x);
+}
+
+USHORT
+#ifdef CK_ANSIC
+eu_to_sj(USHORT eu) /* EUC-JP to Shift-JIS */
+#else
+eu_to_sj(eu) USHORT eu;
+#endif /* CK_ANSIC */
+{
+ int c1, c2;
+ union ck_short jcode,scode;
+
+ jcode.x_short = eu;
+ c1 = (jcode.x_char[byteorder] & 0x7f);
+ c2 = (jcode.x_char[1-byteorder] & 0x7f);
+
+ if (c1 & 1)
+ c2 += 0x1f;
+ else
+ c2 += 0x7d;
+ if (c2 >= 0x7f)
+ c2++;
+ c1 = ((c1 - 0x21) >> 1) + 0x81;
+ if (c1 > 0x9f)
+ c1 += 0x40;
+
+ scode.x_char[byteorder] = c1;
+ scode.x_char[1-byteorder] = c2;
+ return(scode.x_short);
+}
+
+
+USHORT
+#ifdef CK_ANSIC
+sj_to_eu(USHORT sj) /* Shift-JIS to EUC-JP */
+#else
+sj_to_eu(sj) USHORT sj;
+#endif /* CK_ANSIC */
+{
+ union ck_short jcode, scode;
+ int c0, c1;
+
+ scode.x_short = sj;
+ c0 = scode.x_char[byteorder]; /* Left (hi order) byte */
+ c1 = scode.x_char[1-byteorder]; /* Right (lo order) byte */
+
+ if (((c0 >= 0x81) && (c0 <= 0x9f)) || /* High order byte has 8th bit set */
+ ((c0 >= 0xe0) && (c0 <= 0xfc))) { /* Kanji */
+ if (c0 <= 0x9f) /* Two bytes in */
+ c0 -= 0x71; /* Do the shifting... */
+ else
+ c0 -= 0xb1;
+ c0 = c0 * 2 + 1;
+ if (c1 > 0x7f) c1 -= 1;
+ if (c1 >= 0x9e) {
+ c1 -= 0x7d;
+ c0 += 1;
+ } else {
+ c1 -= 0x1f;
+ }
+ jcode.x_char[byteorder] = (c0 | 0x80); /* Two bytes out */
+ jcode.x_char[1-byteorder] = (c1 | 0x80);
+
+ } else if (c0 == 0) { /* Single byte */
+ if (c1 >= 0xa1 && c1 <= 0xdf) { /* Katakana */
+ jcode.x_char[byteorder] = 0x8e; /* SS2 */
+ jcode.x_char[1-byteorder] = c1; /* Kana code */
+ } else { /* ASCII or C0 */
+ jcode.x_short = c1;
+ }
+ } else { /* Something bad */
+ debug(F001,"sj_to_eu bad sj","",sj);
+ jcode.x_short = 0xffff;
+ }
+ return(jcode.x_short);
+}
+
+int
+zkanjf() { /* Initialize */
+ jpnstz = jpnpnd = jpnpnt = 0;
+ return(0);
+}
+
+int
+zkanjz() {
+ return(0);
+}
+
+int
+#ifdef CK_ANSIC
+zkanji(int (*fn)(void))
+#else
+zkanji(fn) int (*fn)();
+#endif /* CK_ANSIC */
+{ /* zkanji */
+ /* Read Japanese local code and translate to Japanese EUC */
+ int a;
+ int sc[3];
+
+ /* No pending characters */
+ if (fcharset == FC_SHJIS) { /* Translating from Shift-JIS */
+ if (jpnpnd) {
+ jpnpnd--;
+ return(jpnpbf[jpnpnt++]);
+ }
+ a = (*fn)();
+ jpnpnd = jpnpnt = 0;
+ if (((a >= 0x81) && (a <= 0x9f)) ||
+ ((a >= 0xe0) && (a <= 0xfc))) { /* 2-byte Kanji code */
+ sc[0] = a;
+ if ((sc[1] = (*fn)()) < 0) /* Get second byte */
+ return(sc[1]);
+ if (sc[0] <= 0x9f)
+ sc[0] -= 0x71;
+ else
+ sc[0] -= 0xb1;
+ sc[0] = sc[0] * 2 + 1;
+ if (sc[1] > 0x7f)
+ sc[1]--;
+ if (sc[1] >= 0x9e) {
+ sc[1] -= 0x7d;
+ sc[0]++;
+ } else {
+ sc[1] -= 0x1f;
+ }
+ a = (sc[0] | 0x80);
+ jpnpbf[0] = (sc[1] | 0x80);
+ jpnpnd = 1;
+ jpnpnt = 0;
+ } else if ((a >= 0xa1) && (a <= 0xdf)) { /* Katakana */
+ jpnpbf[0] = a;
+ jpnpnd = 1;
+ jpnpnt = 0;
+ a = 0x8e;
+ }
+ return(a);
+ } else if (fcharset == FC_JIS7 ) { /* 7-bit JIS X 0208 */
+ if (jpnpnd) {
+ a = jpnpbf[jpnpnt++];
+ jpnpnd--;
+ return(a);
+ }
+ jpnpnt = 0;
+ if ((a = (*fn)()) < 0)
+ return(a);
+ while (jpnpnd == 0) {
+ if ((a > 0x20) && (a < 0x7f)) {
+ switch (jpnstz) {
+ case 1:
+ jpnpbf[jpnpnd++] = 0x80; /* Katakana */
+ jpnpbf[jpnpnd++] = (a | 0x80);
+ break;
+ case 2:
+ jpnpbf[jpnpnd++] = (a | 0x80); /* Kanji */
+ if ((a = (*fn)()) < 0)
+ return(a);
+ jpnpbf[jpnpnd++] = (a | 0x80);
+ break;
+ default:
+ jpnpbf[jpnpnd++] = a; /* Single byte */
+ break;
+ }
+ } else if (a == 0x0e) {
+ jpnstz = 1;
+ if ((a = (*fn)()) < 0)
+ return(a);
+ } else if (a == 0x0f) {
+ jpnstz = 0;
+ if ((a = (*fn)()) < 0)
+ return(a);
+ } else if (a == 0x1b) {
+ jpnpbf[jpnpnd++] = a; /* Escape */
+ if ((a = (*fn)()) < 0)
+ return(a);
+ jpnpbf[jpnpnd++] = a;
+ if (a == '$') {
+ if ((a = (*fn)()) < 0)
+ return(a);
+ jpnpbf[jpnpnd++] = a;
+ if ((a == '@') || (a == 'B')) {
+ jpnstz = 2;
+ jpnpnt = jpnpnd = 0;
+ if ((a = (*fn)()) < 0)
+ return(a);
+ }
+ } else if (a == '(') {
+ if ((a = (*fn)()) < 0)
+ return(a);
+ jpnpbf[jpnpnd++] = a;
+ if ((a == 'B') || (a == 'J')) {
+ jpnstz = 0;
+ jpnpnt = jpnpnd = 0;
+ if ((a = (*fn)()) < 0)
+ return(a);
+ }
+ } else if (a == 0x1b) {
+ jpnpnt = jpnpnd = 0;
+ if ((a = (*fn)()) < 0)
+ return(a);
+ }
+ } else {
+ jpnpbf[jpnpnd++] = a;
+ }
+ }
+ jpnpnt = 0;
+ a = jpnpbf[jpnpnt++];
+ jpnpnd--;
+ return(a);
+ } else {
+ a = (*fn)();
+ return(a);
+ }
+}
+#endif /* KANJI */
+
+/* Euro functions */
+
+#ifdef LATIN2
+CHAR
+#ifdef CK_ANSIC
+xl2l9(CHAR c)
+#else
+xl2l9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl2l9 */ /* Latin-2 to Latin-9... */
+ switch (c) {
+ case 169: return((CHAR)166); /* S caron */
+ case 185: return((CHAR)168); /* s caron */
+ case 174: return((CHAR)180); /* Z caron */
+ case 190: return((CHAR)184); /* z caron */
+ default:
+ return(yl2l1[c]);
+ }
+
+}
+
+_PROTOTYP( CHAR xl258, ( CHAR ) );
+CHAR
+#ifdef CK_ANSIC
+xl258(CHAR c)
+#else
+xl258(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl258 */ /* Latin-2 to CP858... */
+ return(c);
+}
+#else
+#define xl2l9 NULL
+#define xl258 NULL
+#endif /* LATIN2 */
+
+CHAR
+#ifdef CK_ANSIC
+zl9as(CHAR c)
+#else
+zl9as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* zl9as */ /* Latin-9 to US ASCII... */
+ if (c < (CHAR)0x80) return(c); /* Save a function call */
+ switch (c) {
+ case 0xa4: return(UNK); /* Euro */
+ case 0xa6: return('S'); /* S Caron */
+ case 0xa8: return('s'); /* s Caron */
+ case 0xb4: return('Z'); /* Z Caron */
+ case 0xbc: return('O'); /* OE digraph */
+ case 0xbd: return('o'); /* oe digraph */
+ case 0xbe: return('Y'); /* Y diaeresis */
+ default: return(zl1as(c)); /* The rest is like Latin-1 */
+ }
+}
+
+_PROTOTYP( CHAR xl9as, ( CHAR ) );
+CHAR
+#ifdef CK_ANSIC
+xl9as(CHAR c)
+#else
+xl9as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl9as */ /* Latin-9 to US ASCII... */
+ if (c < (CHAR)0x80) return(c); /* Save a function call */
+ switch (c) {
+ case 0xa4: return(UNK); /* Euro */
+ case 0xa6: return('S'); /* S Caron */
+ case 0xa8: return('s'); /* s Caron */
+ case 0xb4: return('Z'); /* Z Caron */
+ case 0xb8: return('z'); /* z Caron */
+ case 0xbc: return('O'); /* OE digraph */
+ case 0xbd: return('o'); /* oe digraph */
+ case 0xbe: return('Y'); /* Y diaeresis */
+ default: return(xl1as(c)); /* The rest is like Latin-1 */
+ }
+}
+
+CHAR /* CP1252 to Latin-9 */
+#ifdef CK_ANSIC
+xw1l9(CHAR c)
+#else
+xw1l9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xw1l9 */
+ switch (c) {
+ case 0x80: return(0xa4); /* Euro sign */
+ case 0x8a: return(0xa6); /* S caron */
+ case 0x8c: return(0xbc); /* OE */
+ case 0x8e: return(0xb4); /* Z caron */
+ case 0x9a: return(0xa8); /* s caron */
+ case 0x9c: return(0xbd); /* oe */
+ case 0x9e: return(0xb8); /* z caron */
+ case 0x9f: return(0xbe); /* Y diaeresis */
+ case 0xa4: /* Currency sign */
+ case 0xa6: /* Broken vertical bar */
+ case 0xa8: /* Diaeresis */
+ case 0xb4: /* Acute accent */
+ case 0xb8: /* Cedilla */
+ case 0xbc: /* 1/4 */
+ case 0xbd: /* 1/2 */
+ case 0xbe: return('?'); /* 3/4 */
+ default: return((c < 160) ? xw1as(c) : c);
+ }
+}
+
+#ifdef LATIN2
+CHAR
+#ifdef CK_ANSIC
+xl9l2(CHAR c)
+#else
+xl9l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl9l2 */ /* Latin-9 to Latin-2... */
+ if (c < (CHAR)0x80) return(c); /* Save a function call */
+ switch (c) {
+ case 0xa4: return(UNK); /* Euro */
+ case 0xa6: return((CHAR)0xa9); /* S Caron */
+ case 0xa8: return((CHAR)0xb9); /* s Caron */
+ case 0xb4: return((CHAR)0xae); /* Z Caron */
+ case 0xb8: return((CHAR)0xaf); /* z Caron */
+ case 0xbc: return('O'); /* OE digraph */
+ case 0xbd: return('o'); /* oe digraph */
+ case 0xbe: return('Y'); /* Y diaeresis */
+ default: return(xl1l2(c)); /* The rest is like Latin-1 */
+ }
+}
+#else
+#define xl9l2 NULL
+#endif /* LATIN2 */
+
+CHAR
+#ifdef CK_ANSIC
+xl958(CHAR c)
+#else
+xl958(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* xl958 */ /* Latin-9 to CP858... */
+ if (c == 0xa4) /* Euro Symbol */
+ return((CHAR)0xd5);
+ else if (c == 0x9e) /* This was currency symbol */
+ return((CHAR)0xcf);
+ c = yl185[c];
+ return(c);
+}
+
+CHAR
+#ifdef CK_ANSIC
+x58as(CHAR c)
+#else
+x58as(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x58as */ /* CP858 to US ASCII... */
+ if (c == 0xd5) /* Euro rather than dotless i */
+ return(UNK);
+ else
+ return(x85as(c)); /* The rest is like CP850 */
+}
+
+CHAR
+#ifdef CK_ANSIC
+x58l1(CHAR c)
+#else
+x58l1(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x58l1 */ /* CP858 to Latin-1... */
+ if (c == 0xd5) /* Euro rather than dotless i */
+ return((CHAR)0xa4); /* Return currency symbol */
+ else if (c == 0xcf) /* This keeps it invertible */
+ return((CHAR)0x9e);
+ else
+ return(x85l1(c));
+}
+
+#ifdef LATIN2
+CHAR
+#ifdef CK_ANSIC
+x58l2(CHAR c)
+#else
+x58l2(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x58l2 */ /* CP858 to Latin-2... */
+ if (c == 0xd5) /* Euro rather than dotless i */
+ return((CHAR)0xa4); /* Return currency symbol */
+ else if (c == 0xcf) /* This keeps it invertible */
+ return((CHAR)0x9e); /* (if it ever was...) */
+ else /* Otherwise like CP850 */
+ return(x85l2(c));
+}
+#else
+#define x58l2 NULL
+#endif /* LATIN2 */
+
+CHAR
+#ifdef CK_ANSIC
+x58l9(CHAR c)
+#else
+x58l9(c) CHAR c;
+#endif /* CK_ANSIC */
+{ /* x58l9 */ /* CP-858 to Latin-9... */
+ if (c == 0xd5) /* Euro rather than dotless i */
+ return((CHAR)0xa4); /* Return currency symbol */
+ else if (c == 0xcf) /* This keeps it invertible */
+ return((CHAR)0x9e); /* (if it ever was...) */
+ else /* Otherwise like CP850 */
+ return(x85l1(c)); /* to Latin-1 */
+}
+
+/* End Euro functions */
+
+
+/* TABLES OF TRANSLATION FUNCTIONS */
+
+/*
+ First, the table of translation functions for RECEIVING files. That is,
+ *from* the TRANSFER character set *to* the FILE character set, an array of
+ pointers to functions. The first index is the TRANSFER CHARACTER-SET
+ number, the second index is the FILE CHARACTER-SET number.
+
+ These arrays must be fully populated, even if (as is the case with Kanji
+ character sets), all the entries are NULL. Otherwise, subscript
+ calculations will be wrong and we'll use the wrong functions.
+*/
+
+/* Pointers to byte-for-byte translation functions */
+
+_PROTOTYP( CHAR (*rx), (CHAR) );
+_PROTOTYP( CHAR (*sx), (CHAR) );
+
+#ifdef UNICODE
+_PROTOTYP( int (*xut), (USHORT) ); /* Translation function UCS to TCS */
+_PROTOTYP( int (*xuf), (USHORT) ); /* Translation function UCS to FCS */
+_PROTOTYP( USHORT (*xtu), (CHAR) ); /* Translation function TCS to UCS */
+_PROTOTYP( USHORT (*xfu), (CHAR) ); /* Translation function FCS to UCS */
+#endif /* UNICODE */
+
+#ifdef CK_ANSIC
+CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR) =
+#else
+CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])() =
+#endif /* CK_ANSIC */
+{
+ NULL, /* 0,0 transparent to us ascii */
+ NULL, /* 0,1 transparent to uk ascii */
+ NULL, /* 0,2 transparent to dutch nrc */
+ NULL, /* 0,3 transparent to finnish nrc */
+ NULL, /* 0,4 transparent to french nrc */
+ NULL, /* 0,5 transparent to fr-canadian nrc */
+ NULL, /* 0,6 transparent to german nrc */
+ NULL, /* 0,7 transparent to hungarian nrc */
+ NULL, /* 0,8 transparent to italian nrc */
+ NULL, /* 0,9 transparent to norge/danish nrc */
+ NULL, /* 0,10 transparent to portuguese nrc */
+ NULL, /* 0,11 transparent to spanish nrc */
+ NULL, /* 0,12 transparent to swedish nrc */
+ NULL, /* 0,13 transparent to swiss nrc */
+ NULL, /* 0,14 transparent to latin-1 */
+ NULL, /* 0,15 transparent to latin-2 */
+ NULL, /* 0,16 transparent to DEC MCS */
+ NULL, /* 0,17 transparent to NeXT */
+ NULL, /* 0,18 transparent to CP437 */
+ NULL, /* 0,19 transparent to CP850 */
+ NULL, /* 0,20 transparent to CP852 */
+ NULL, /* 0,21 transparent to Macintosh Latin */
+ NULL, /* 0,22 transparent to DGI */
+ NULL, /* 0,23 transparent to HP */
+ NULL, /* 0,24 transparent to Latin/Cyrillic */
+ NULL, /* 0,25 transparent to CP866 */
+ NULL, /* 0,26 transparent to Short KOI-7 */
+ NULL, /* 0,27 transparent to Old KOI-8 Cyrillic */
+ NULL, /* 0,28 transparent to JIS-7 */
+ NULL, /* 0,29 transparent to Shift-JIS */
+ NULL, /* 0,30 transparent to J-EUC */
+ NULL, /* 0,31 transparent to DEC Kanji */
+ NULL, /* 0,32 transparent to Hebrew-7 */
+ NULL, /* 0,33 transparent to Latin/Hebrew */
+ NULL, /* 0,34 transparent to CP862 Hebrew */
+ NULL, /* 0,35 transparent to ELOT 927 Greek */
+ NULL, /* 0,36 transparent to Latin/Greek */
+ NULL, /* 0,37 transparent to CP869 */
+ NULL, /* 0,38 transparent to Latin-9 */
+ NULL, /* 0,39 transparent to CP858 */
+ NULL, /* 0,40 transparent to CP855 */
+ NULL, /* 0,41 transparent to CP1251 */
+ NULL, /* 0,42 transparent to Bulgarian */
+ NULL, /* 0,43 transparent to CP1250 */
+ NULL, /* 0,44 transparent to Mazovia */
+ NULL, /* 0,45 transparent to UCS-2 */
+ NULL, /* 0,46 transparent to UTF-8 */
+ NULL, /* 0,47 transparent to KOI8R */
+ NULL, /* 0,48 transparent to KOI8U */
+ NULL, /* 0,49 transparent to CP1252 */
+ NULL, /* 1,0 ascii to us ascii */
+ NULL, /* 1,1 ascii to uk ascii */
+ NULL, /* 1,2 ascii to dutch nrc */
+ NULL, /* 1,3 ascii to finnish nrc */
+ NULL, /* 1,4 ascii to french nrc */
+ NULL, /* 1,5 ascii to fr-canadian nrc */
+ NULL, /* 1,6 ascii to german nrc */
+ NULL, /* 1,7 ascii to hungarian nrc */
+ NULL, /* 1,8 ascii to italian nrc */
+ NULL, /* 1,9 ascii to norge/danish nrc */
+ NULL, /* 1,10 ascii to portuguese nrc */
+ NULL, /* 1,11 ascii to spanish nrc */
+ NULL, /* 1,12 ascii to swedish nrc */
+ NULL, /* 1,13 ascii to swiss nrc */
+ NULL, /* 1,14 ascii to latin-1 */
+ NULL, /* 1,15 ascii to latin-2 */
+ NULL, /* 1,16 ascii to DEC MCS */
+ NULL, /* 1,17 ascii to NeXT */
+ NULL, /* 1,18 ascii to CP437 */
+ NULL, /* 1,19 ascii to CP850 */
+ NULL, /* 1,20 ascii to CP852 */
+ NULL, /* 1,21 ascii to Macintosh Latin */
+ NULL, /* 1,22 ascii to DGI */
+ NULL, /* 1,23 ascii to HP */
+ xaslc, /* 1,24 ascii to Latin/Cyrillic */
+ xasac, /* 1,25 ascii to CP866 */
+ xassk, /* 1,26 ascii to Short KOI */
+ xask8, /* 1,27 ascii to Old KOI-8 Cyrillic */
+ NULL, /* 1,28 ascii to JIS-7 */
+ NULL, /* 1,29 ascii to Shift-JIS */
+ NULL, /* 1,30 ascii to J-EUC */
+ NULL, /* 1,31 ascii to DEC Kanji */
+ xash7, /* 1,32 ascii to Hebrew-7 */
+ NULL, /* 1,33 ascii to Latin/Hebrew */
+ NULL, /* 1,34 ascii to CP862 Hebrew */
+ xaseg, /* 1,35 ascii to ELOT 927 Greek */
+ NULL, /* 1,36 ascii to Latin/Greek */
+ NULL, /* 1,37 ascii to CP869 */
+ NULL, /* 1,38 ascii to Latin-9 */
+ NULL, /* 1,39 ascii to CP858 */
+ xas55, /* 1,40 ascii to CP855 */
+ xas1251, /* 1,41 ascii to CP1251 */
+ xleft128, /* 1,42 ascii to bulgarian */
+ xleft128, /* 1,43 ascii to CP1250 */
+ xleft128, /* 1,44 ascii to Mazovia */
+ NULL, /* 1,45 ascii to UCS-2 */
+ NULL, /* 1,46 ascii to UTF-8 */
+ NULL, /* 1,47 ascii to KOI8-R */
+ NULL, /* 1,48 ascii to KOI8-U */
+ NULL, /* 1,49 ascii to CP1252 */
+ zl1as, /* 2,0 latin-1 to us ascii */
+ xl1uk, /* 2,1 latin-1 to uk ascii */
+ xl1du, /* 2,2 latin-1 to dutch nrc */
+ xl1fi, /* 2,3 latin-1 to finnish nrc */
+ xl1fr, /* 2,4 latin-1 to french nrc */
+ xl1fc, /* 2,5 latin-1 to fr-canadian nrc */
+ xl1ge, /* 2,6 latin-1 to german nrc */
+ xl1it, /* 2,7 latin-1 to italian nrc */
+ xl1hu, /* 2,8 latin-1 to hungarian nrc */
+ xl1no, /* 2,9 latin-1 to norge/danish nrc */
+ xl1po, /* 2,10 latin-1 to portuguese nrc */
+ xl1sp, /* 2,11 latin-1 to spanish nrc */
+ xl1sw, /* 2,12 latin-1 to swedish nrc */
+ xl1ch, /* 2,13 latin-1 to swiss nrc */
+ NULL, /* 2,14 latin-1 to latin-1 */
+ xl1l2, /* 2,15 latin-1 to latin-2 */
+ xl1dm, /* 2,16 latin-1 to DEC MCS */
+ xl1ne, /* 2,17 latin-1 to NeXT */
+ xl143, /* 2,18 latin-1 to CP437 */
+ xl185, /* 2,19 latin-1 to CP850 */
+ xl152, /* 2,20 latin-1 to CP852 */
+ xl1aq, /* 2,21 latin-1 to Macintosh Latin */
+ xl1dg, /* 2,22 latin-1 to DGI */
+ xl1r8, /* 2,23 latin-1 to HP Roman8 */
+ zl1as, /* 2,24 latin-1 to Latin/Cyrillic */
+ zl1as, /* 2,25 latin-1 to CP866 */
+ xl1sk, /* 2,26 latin-1 to Short KOI */
+ zl1as, /* 2,27 latin-1 to Old KOI-8 Cyrillic */
+ NULL, /* 2,28 latin-1 to JIS-7 */
+ NULL, /* 2,29 latin-1 to Shift-JIS */
+ NULL, /* 2,30 latin-1 to J-EUC */
+ NULL, /* 2,31 latin-1 to DEC Kanji */
+ xl1h7, /* 2,32 latin-1 to Hebrew-7 */
+ xl1lh, /* 2,33 latin-1 to Latin/Hebrew */
+ xl162, /* 2,34 latin-1 to CP862 Hebrew */
+ xl1eg, /* 2,35 latin-1 to ELOT 927 Greek */
+ xl1lg, /* 2,36 latin-1 to Latin/Greek */
+ xl169, /* 2,37 latin-1 to CP869 */
+ NULL, /* 2,38 latin-1 to Latin9 */
+ xl185, /* 2,39 latin-1 to CP858 */
+ zl1as, /* 2,40 latin-1 to CP855 */
+ zl1as, /* 2,41 latin-1 to CP1251 */
+ zl1as, /* 2,42 latin-1 to Bulgarian */
+ xl11250, /* 2,43 latin-1 to CP1250 */
+ xl1mz, /* 2,44 latin-1 to Mazovia */
+ NULL, /* 2,45 latin-1 to UCS-2 */
+ NULL, /* 2,46 latin-1 to UTF-8 */
+ zl1as, /* 2,47 latin-1 to KOI8R */
+ zl1as, /* 2,48 latin-1 to KOI8U */
+ xl1w1, /* 2,49 latin-1 to CP1252 */
+ xl2as, /* 3,0 latin-2 to us ascii */
+ xl2as, /* 3,1 latin-2 to uk ascii */
+ xl2as, /* 3,2 latin-2 to dutch nrc */
+ xl2as, /* 3,3 latin-2 to finnish nrc */
+ xl2as, /* 3,4 latin-2 to french nrc */
+ xl2as, /* 3,5 latin-2 to fr-canadian nrc */
+ xl2as, /* 3,6 latin-2 to german nrc */
+ xl2as, /* 3,7 latin-2 to italian nrc */
+ xl2as, /* 3,8 latin-2 to hungarian nrc */
+ xl2as, /* 3,9 latin-2 to norge/danish nrc */
+ xl2as, /* 3,10 latin-2 to portuguese nrc */
+ xl2as, /* 3,11 latin-2 to spanish nrc */
+ xl2as, /* 3,12 latin-2 to swedish nrc */
+ xl2as, /* 3,13 latin-2 to swiss nrc */
+ xl2l1, /* 3,14 latin-2 to latin-1 */
+ NULL, /* 3,15 latin-2 to latin-2 */
+ xl2l1, /* 3,16 latin-2 to DEC MCS */
+ xl2ne, /* 3,17 latin-2 to NeXT */
+ xl243, /* 3,18 latin-2 to CP437 */
+ xl285, /* 3,19 latin-2 to CP850 */
+ xl252, /* 3,20 latin-2 to CP852 */
+ xl2aq, /* 3,21 latin-2 to Macintosh Latin */
+ xl2dg, /* 3,22 latin-2 to DGI */
+ xl2r8, /* 3,23 latin-2 to HP */
+ xl2as, /* 3,24 latin-2 to Latin/Cyrillic */
+ xl2as, /* 3,25 latin-2 to CP866 */
+ xl2sk, /* 3,26 latin-2 to Short KOI */
+ xl2as, /* 3,27 latin-2 to Old KOI-8 Cyrillic */
+ NULL, /* 3,28 latin-2 to JIS-7 */
+ NULL, /* 3,29 latin-2 to Shift-JIS */
+ NULL, /* 3,30 latin-2 to J-EUC */
+ NULL, /* 3,31 latin-2 to DEC Kanji */
+ xl2h7, /* 3,32 latin-2 to Hebrew-7 */
+ xl2as, /* 3,33 latin-2 to Latin/Hebrew */
+ xl2as, /* 3,34 latin-2 to CP862 Hebrew */
+ xassk, /* 3,35 latin-2 to ELOT 927 Greek */
+ xl2as, /* 3,36 latin-2 to Latin/Greek */
+ xl2as, /* 3,37 latin-2 to CP869 */
+ xl2l9, /* 3,38 latin-2 to Latin-9 */
+ xl258, /* 3,39 latin-2 to CP858 */
+ xl2as, /* 3,40 latin-2 to CP855 */
+ xl2as, /* 3,41 latin-2 to CP1251 */
+ xl2as, /* 3,42 latin-2 to Bulgarian */
+ xl21250, /* 3,43 latin-2 to CP1250 */
+ xl2mz, /* 3,44 latin-2 to Mazovia */
+ NULL, /* 3,45 latin-2 to UCS-2 */
+ NULL, /* 3,46 latin-2 to UTF-8 */
+ xl2as, /* 3,47 latin-2 to KOI8R */
+ xl2as, /* 3,48 latin-2 to KOI8U */
+ xl2w1, /* 3,49 latin-2 to CP1252 */
+ xlcas, /* 4,0 latin/cyrillic to us ascii */
+ xlcas, /* 4,1 latin/cyrillic to uk ascii */
+ xlcas, /* 4,2 latin/cyrillic to dutch nrc */
+ xlcas, /* 4,3 latin/cyrillic to finnish ascii */
+ xlcas, /* 4,4 latin/cyrillic to french nrc */
+ xlcas, /* 4,5 latin/cyrillic to fr-canadian nrc */
+ xlcas, /* 4,6 latin/cyrillic to german nrc */
+ xlcas, /* 4,7 latin/cyrillic to italian nrc */
+ xlcas, /* 4,8 latin/cyrillic to hungarian nrc */
+ xlcas, /* 4,9 latin/cyrillic to norge/danish nrc */
+ xlcas, /* 4,10 latin/cyrillic to portuguese nrc */
+ xlcas, /* 4,11 latin/cyrillic to spanish nrc */
+ xlcas, /* 4,12 latin/cyrillic to swedish nrc */
+ xlcas, /* 4,13 latin/cyrillic to swiss nrc */
+ xlcas, /* 4,14 latin/cyrillic to latin-1 */
+ xlcas, /* 4,15 latin/cyrillic to latin-2 */
+ xlcas, /* 4,16 latin/cyrillic to DEC MCS */
+ xlcas, /* 4,17 latin/cyrillic to NeXT */
+ xlcas, /* 4,18 latin/cyrillic to CP437 */
+ xlcas, /* 4,19 latin/cyrillic to CP850 */
+ xlcas, /* 4,20 latin/cyrillic to CP852 */
+ xlcas, /* 4,21 latin/cyrillic to Macintosh Latin */
+ xlcas, /* 4,22 latin/cyrillic to DGI */
+ xlcas, /* 4,23 latin/cyrillic to HP */
+ NULL, /* 4,24 latin/cyrillic to Latin/Cyrillic */
+ xlcac, /* 4,25 latin/cyrillic to CP866 */
+ xlcsk, /* 4,26 latin/cyrillic to Short KOI */
+ xlck8, /* 4,27 latin/cyrillic to Old KOI-8 Cyrillic */
+ NULL, /* 4,28 latin/cyril to JIS-7 */
+ NULL, /* 4,29 latin/cyril to Shift-JIS */
+ NULL, /* 4,30 latin/cyril to J-EUC */
+ NULL, /* 4,31 latin/cyril to DEC Kanji */
+ xlch7, /* 4,32 latin/cyril to Hebrew-7 */
+ xlcas, /* 4,33 latin/cyril to Latin/Hebrew */
+ xlcas, /* 4,34 latin/cyril to CP862 Hebrew */
+ xassk, /* 4,35 latin/cyril to ELOT 927 Greek */
+ xleft160, /* 4,36 latin/cyril to Latin/Greek */
+ xleft128, /* 4,37 latin/cyril to CP869 */
+ xlcas, /* 4,38 latin/cyril to latin-9 */
+ xlcas, /* 4,39 latin/cyril to CP858 */
+ xlc55, /* 4,40 latin/cyril to CP855 */
+ xlc1251, /* 4,41 latin/cyril to CP1251 */
+ xlcbu, /* 4,42 latin/cyril to Bulgarian */
+ xlcas, /* 4,43 latin/cyril to CP1250 */
+ xlcas, /* 4,44 latin/cyril to Mazovia */
+ NULL, /* 4,45 latin/cyril to UCS-2 */
+ NULL, /* 4,46 latin/cyril to UTF-8 */
+ xlckr, /* 4,47 latin/cyril to KOI8R */
+ xlcku, /* 4,48 latin/cyril to KOI8U */
+ xlcas, /* 4,49 latin/cyril to CP1252 */
+ NULL, /* 5,00 */
+ NULL, /* 5,01 */
+ NULL, /* 5,02 */
+ NULL, /* 5,03 */
+ NULL, /* 5,04 */
+ NULL, /* 5,05 */
+ NULL, /* 5,06 */
+ NULL, /* 5,07 */
+ NULL, /* 5,08 */
+ NULL, /* 5,09 */
+ NULL, /* 5,10 */
+ NULL, /* 5,11 */
+ NULL, /* 5,12 */
+ NULL, /* 5,13 */
+ NULL, /* 5,14 */
+ NULL, /* 5,15 */
+ NULL, /* 5,16 */
+ NULL, /* 5,17 */
+ NULL, /* 5,18 */
+ NULL, /* 5,19 */
+ NULL, /* 5,20 */
+ NULL, /* 5,21 */
+ NULL, /* 5,22 */
+ NULL, /* 5,23 */
+ NULL, /* 5,24 */
+ NULL, /* 5,25 */
+ NULL, /* 5,26 */
+ NULL, /* 5,27 */
+ NULL, /* 5,28 */
+ NULL, /* 5,29 */
+ NULL, /* 5,30 */
+ NULL, /* 5,31 */
+ NULL, /* 5,32 */
+ NULL, /* 5,33 */
+ NULL, /* 5,34 */
+ NULL, /* 5,35 */
+ NULL, /* 5,36 */
+ NULL, /* 5,37 */
+ NULL, /* 5,38 */
+ NULL, /* 5,39 */
+ NULL, /* 5,40 */
+ NULL, /* 5,41 */
+ NULL, /* 5,42 */
+ NULL, /* 5,43 */
+ NULL, /* 5,44 */
+ NULL, /* 5,45 */
+ NULL, /* 5,46 */
+ NULL, /* 5,47 */
+ NULL, /* 5,48 */
+ NULL, /* 5,49 */
+ xlhas, /* 6,0 latin/hebrew to us ascii */
+ xlhas, /* 6,1 latin/hebrew to uk ascii */
+ xlhas, /* 6,2 latin/hebrew to dutch nrc */
+ xlhas, /* 6,3 latin/hebrew to finnish ascii */
+ xlhas, /* 6,4 latin/hebrew to french nrc */
+ xlhas, /* 6,5 latin/hebrew to fr-canadian nrc */
+ xlhas, /* 6,6 latin/hebrew to german nrc */
+ xlhas, /* 6,7 latin/hebrew to italian nrc */
+ xlhas, /* 6,8 latin/hebrew to hungarian nrc */
+ xlhas, /* 6,9 latin/hebrew to norge/danish nrc */
+ xlhas, /* 6,10 latin/hebrew to portuguese nrc */
+ xlhas, /* 6,11 latin/hebrew to spanish nrc */
+ xlhas, /* 6,12 latin/hebrew to swedish nrc */
+ xlhas, /* 6,13 latin/hebrew to swiss nrc */
+ xlhl1, /* 6,14 latin/hebrew to latin-1 */
+ xlhas, /* 6,15 latin/hebrew to latin-2 */
+ xlhl1, /* 6,16 latin/hebrew to DEC MCS */
+ xlhas, /* 6,17 latin/hebrew to NeXT */
+ xlhas, /* 6,18 latin/hebrew to CP437 */
+ xlhas, /* 6,19 latin/hebrew to CP850 */
+ xlhas, /* 6,20 latin/hebrew to CP852 */
+ xlhas, /* 6,21 latin/hebrew to Macintosh Latin */
+ xlhas, /* 6,22 latin/hebrew to DGI */
+ xlhas, /* 6,23 latin/hebrew to HP */
+ xlhas, /* 6,24 latin/hebrew to Latin/Cyrillic */
+ xlhas, /* 6,25 latin/hebrew to CP866 */
+ NULL, /* 6,26 latin/hebrew to Short KOI */
+ xlhas, /* 6,27 latin/hebrew to Old KOI-8 Cyrillic */
+ NULL, /* 6,28 latin/hebrew to JIS-7 */
+ NULL, /* 6,29 latin/hebrew to Shift-JIS */
+ NULL, /* 6,30 latin/hebrew to J-EUC */
+ NULL, /* 6,31 latin/hebrew to DEC Kanji */
+ xlhh7, /* 6,32 latin/hebrew to Hebrew-7 */
+ NULL, /* 6,33 latin/hebrew to Latin/Hebrew */
+ xlh62, /* 6,34 latin/hebrew to CP862 Hebrew */
+ NULL, /* 6,35 latin/hebrew to ELOT 927 Greek */
+ xlhas, /* 6,36 latin/hebrew to Latin/Greek */
+ xlhas, /* 6,37 latin/hebrew to CP869 */
+ xlhas, /* 6,38 latin/hebrew to Latin-9 */
+ xlhas, /* 6,39 latin/hebrew to CP858 */
+ xlhas, /* 6,40 latin/hebrew to CP855 */
+ xlhas, /* 6,41 latin/hebrew to CP1251 */
+ xlhas, /* 6,42 latin/hebrew to Bulgarian */
+ xlhas, /* 6,43 latin/hebrew to CP1250 */
+ xlhas, /* 6,44 latin/hebrew to Mazovia */
+ NULL, /* 6,45 latin/hebrew to UCS-2 */
+ NULL, /* 6,46 latin/hebrew to UTF-8 */
+ NULL, /* 6,47 latin/hebrew to KOI8R */
+ NULL, /* 6,48 latin/hebrew to KOI8U */
+ xlhw1, /* 6,49 latin/hebrew to CP1252 */
+ xlgas, /* 7,0 latin/greek to us ascii */
+ xlgas, /* 7,1 latin/greek to uk ascii */
+ xlgas, /* 7,2 latin/greek to dutch nrc */
+ xlgas, /* 7,3 latin/greek to finnish ascii */
+ xlgas, /* 7,4 latin/greek to french nrc */
+ xlgas, /* 7,5 latin/greek to fr-canadian nrc */
+ xlgas, /* 7,6 latin/greek to german nrc */
+ xlgas, /* 7,7 latin/greek to italian nrc */
+ xlgas, /* 7,8 latin/greek to hungarian nrc */
+ xlgas, /* 7,9 latin/greek to norge/danish nrc */
+ xlgas, /* 7,10 latin/greek to portuguese nrc */
+ xlgas, /* 7,11 latin/greek to spanish nrc */
+ xlgas, /* 7,12 latin/greek to swedish nrc */
+ xlgas, /* 7,13 latin/greek to swiss nrc */
+ xlgas, /* 7,14 latin/greek to latin-1 */
+ xlgas, /* 7,15 latin/greek to latin-2 */
+ xlgas, /* 7,16 latin/greek to DEC MCS */
+ xlgas, /* 7,17 latin/greek to NeXT */
+ xlgas, /* 7,18 latin/greek to CP437 */
+ xlgas, /* 7,19 latin/greek to CP850 */
+ xlgas, /* 7,20 latin/greek to CP852 */
+ xlgas, /* 7,21 latin/greek to Macintosh Latin */
+ xlgas, /* 7,22 latin/greek to DGI */
+ xlgas, /* 7,23 latin/greek to HP */
+ xleft160, /* 7,24 latin/greek to Latin/Cyrillic */
+ xleft128, /* 7,25 latin/greek to CP866 */
+ xassk, /* 7,26 latin/greek to Short KOI */
+ xleft160, /* 7,27 latin/greek to Old KOI-8 Greek */
+ NULL, /* 7,28 latin/greek to JIS-7 */
+ NULL, /* 7,29 latin/greek to Shift-JIS */
+ NULL, /* 7,30 latin/greek to J-EUC */
+ NULL, /* 7,31 latin/greek to DEC Kanji */
+ NULL, /* 7,32 latin/greek to Hebrew-7 */
+ xlgas, /* 7,33 latin/greek to Latin/Hebrew */
+ xlgas, /* 7,34 latin/greek to CP862 Hebrew */
+ xlgeg, /* 7,35 latin/greek to ELOT 927 Greek */
+ NULL, /* 7,36 latin/greek to Latin/Greek */
+ xlg69, /* 7,37 latin/greek to CP869 */
+ xlgas, /* 7,38 latin/greek to Latin-9 */
+ xlgas, /* 7,39 latin/greek to CP858 */
+ xleft128, /* 7,40 latin/greek to CP855 */
+ xleft128, /* 7,41 latin/greek to CP1251 */
+ xleft128, /* 7,42 latin/greek to Bulgarian */
+ xleft128, /* 7,43 latin/greek to CP1250 */
+ xleft128, /* 7,44 latin/greek to Mazovia */
+ NULL, /* 7,45 latin/greek to UCS-2 */
+ NULL, /* 7,46 latin/greek to UTF-8 */
+ NULL, /* 7,47 latin/greek to KOI8R */
+ NULL, /* 7,48 latin/greek to KOI8U */
+ xlgw1, /* 7,49 latin/greek to CP1252 */
+ zl9as, /* 8,0 latin-9 to us ascii */
+ xl1uk, /* 8,1 latin-9 to uk ascii */
+ xl1du, /* 8,2 latin-9 to dutch nrc */
+ xl1fi, /* 8,3 latin-9 to finnish nrc */
+ xl1fr, /* 8,4 latin-9 to french nrc */
+ xl1fc, /* 8,5 latin-9 to fr-canadian nrc */
+ xl1ge, /* 8,6 latin-9 to german nrc */
+ xl1it, /* 8,7 latin-9 to italian nrc */
+ xl1hu, /* 8,8 latin-9 to hungarian nrc */
+ xl1no, /* 8,9 latin-9 to norge/danish nrc */
+ xl1po, /* 8,10 latin-9 to portuguese nrc */
+ xl1sp, /* 8,11 latin-9 to spanish nrc */
+ xl1sw, /* 8,12 latin-9 to swedish nrc */
+ xl1ch, /* 8,13 latin-9 to swiss nrc */
+ NULL, /* 8,14 latin-9 to latin-1 */
+ xl1l2, /* 8,15 latin-9 to latin-2 */
+ xl9dm, /* 8,16 latin-9 to DEC MCS */
+ xl9ne, /* 8,17 latin-9 to NeXT */
+ xl143, /* 8,18 latin-9 to CP437 */
+ xl185, /* 8,19 latin-9 to CP850 */
+ xl152, /* 8,20 latin-9 to CP852 */
+ xl1aq, /* 8,21 latin-9 to Macintosh Latin */
+ xl1dg, /* 8,22 latin-9 to DGI */
+ xl1r8, /* 8,23 latin-9 to HP Roman8 */
+ zl1as, /* 8,24 latin-9 to Latin/Cyrillic */
+ zl1as, /* 8,25 latin-9 to CP866 */
+ xl1sk, /* 8,26 latin-9 to Short KOI */
+ zl1as, /* 8,27 latin-9 to Old KOI-8 Cyrillic */
+ NULL, /* 8,28 latin-9 to JIS-7 */
+ NULL, /* 8,29 latin-9 to Shift-JIS */
+ NULL, /* 8,30 latin-9 to J-EUC */
+ NULL, /* 8,31 latin-9 to DEC Kanji */
+ xl1h7, /* 8,32 latin-9 to Hebrew-7 */
+ xl1lh, /* 8,33 latin-9 to Latin/Hebrew */
+ xl162, /* 8,34 latin-9 to CP862 Hebrew */
+ xl1eg, /* 8,35 latin-9 to ELOT 927 Greek */
+ xl1lg, /* 8,36 latin-9 to Latin/Greek */
+ xl169, /* 8,37 latin-9 to CP869 */
+ NULL, /* 8,38 latin-9 to Latin9 */
+ xl958, /* 8,39 latin-9 to CP858 */
+ zl1as, /* 8,40 latin-9 to CP855 */
+ zl1as, /* 8,41 latin-9 to CP1251 */
+ xl1as, /* 8,42 latin-9 to Bulgarian */
+ xl91250, /* 8,43 latin-9 to CP1250 */
+ xl9mz, /* 8,44 latin-9 to Mazovia */
+ NULL, /* 8,45 latin-9 to UCS-2 */
+ NULL, /* 8,46 latin-9 to UTF-8 */
+ zl1as, /* 8,47 latin-9 to KOI8-R */
+ zl1as, /* 8,48 latin-9 to KOI8-U */
+ xl9w1, /* 8,49 latin-9 to CP1252 */
+ NULL, /* 9,00 Unicode... */
+ NULL, /* 9,01 */
+ NULL, /* 9,02 */
+ NULL, /* 9,03 */
+ NULL, /* 9,04 */
+ NULL, /* 9,05 */
+ NULL, /* 9,06 */
+ NULL, /* 9,07 */
+ NULL, /* 9,08 */
+ NULL, /* 9,09 */
+ NULL, /* 9,10 */
+ NULL, /* 9,11 */
+ NULL, /* 9,12 */
+ NULL, /* 9,13 */
+ NULL, /* 9,14 */
+ NULL, /* 9,15 */
+ NULL, /* 9,16 */
+ NULL, /* 9,17 */
+ NULL, /* 9,18 */
+ NULL, /* 9,19 */
+ NULL, /* 9,20 */
+ NULL, /* 9,21 */
+ NULL, /* 9,22 */
+ NULL, /* 9,23 */
+ NULL, /* 9,24 */
+ NULL, /* 9,25 */
+ NULL, /* 9,26 */
+ NULL, /* 9,27 */
+ NULL, /* 9,28 */
+ NULL, /* 9,29 */
+ NULL, /* 9,30 */
+ NULL, /* 9,31 */
+ NULL, /* 9,32 */
+ NULL, /* 9,33 */
+ NULL, /* 9,34 */
+ NULL, /* 9,35 */
+ NULL, /* 9,36 */
+ NULL, /* 9,37 */
+ NULL, /* 9,38 */
+ NULL, /* 9,39 */
+ NULL, /* 9,40 */
+ NULL, /* 9,41 */
+ NULL, /* 9,42 */
+ NULL, /* 9,43 */
+ NULL, /* 9,44 */
+ NULL, /* 9,45 */
+ NULL, /* 9,46 */
+ NULL, /* 9,47 */
+ NULL, /* 9,48 */
+ NULL, /* 9,49 */
+ NULL, /* 10,00 */
+ NULL, /* 10,01 */
+ NULL, /* 10,02 */
+ NULL, /* 10,03 */
+ NULL, /* 10,04 */
+ NULL, /* 10,05 */
+ NULL, /* 10,06 */
+ NULL, /* 10,07 */
+ NULL, /* 10,08 */
+ NULL, /* 10,09 */
+ NULL, /* 10,10 */
+ NULL, /* 10,11 */
+ NULL, /* 10,12 */
+ NULL, /* 10,13 */
+ NULL, /* 10,14 */
+ NULL, /* 10,15 */
+ NULL, /* 10,16 */
+ NULL, /* 10,17 */
+ NULL, /* 10,18 */
+ NULL, /* 10,19 */
+ NULL, /* 10,20 */
+ NULL, /* 10,21 */
+ NULL, /* 10,22 */
+ NULL, /* 10,23 */
+ NULL, /* 10,24 */
+ NULL, /* 10,25 */
+ NULL, /* 10,26 */
+ NULL, /* 10,27 */
+ NULL, /* 10,28 */
+ NULL, /* 10,29 */
+ NULL, /* 10,30 */
+ NULL, /* 10,31 */
+ NULL, /* 10,32 */
+ NULL, /* 10,33 */
+ NULL, /* 10,34 */
+ NULL, /* 10,35 */
+ NULL, /* 10,36 */
+ NULL, /* 10,37 */
+ NULL, /* 10,38 */
+ NULL, /* 10,39 */
+ NULL, /* 10,40 */
+ NULL, /* 10,41 */
+ NULL, /* 10,42 */
+ NULL, /* 10,43 */
+ NULL, /* 10,44 */
+ NULL, /* 10,45 */
+ NULL, /* 10,46 */
+ NULL, /* 10,47 */
+ NULL, /* 10,48 */
+ NULL /* 10,49 */
+};
+int nxlr = (sizeof(xlr) / sizeof(CHAR *));
+
+/*
+ Translation function table for sending files.
+ Array of pointers to functions for translating from the local file
+ character set to the transfer character set. Indexed in the same
+ way as the xlr array above, but with the indices reversed.
+*/
+#ifdef CK_ANSIC
+CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR) =
+#else
+CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])() =
+#endif /* CK_ANSIC */
+{
+ NULL, /* 0,0 us ascii to transparent */
+ NULL, /* 0,1 uk ascii to transparent */
+ NULL, /* 0,2 dutch nrc to transparent */
+ NULL, /* 0,3 finnish nrc to transparent */
+ NULL, /* 0,4 french nrc to transparent */
+ NULL, /* 0,5 fr-canadian nrc to transparent */
+ NULL, /* 0,6 german nrc to transparent */
+ NULL, /* 0,7 hungarian nrc to transparent */
+ NULL, /* 0,8 italian nrc to transparent */
+ NULL, /* 0,9 norge/danish nrc to transparent */
+ NULL, /* 0,10 portuguese nrc to transparent */
+ NULL, /* 0,11 spanish nrc to transparent */
+ NULL, /* 0,12 swedish nrc to transparent */
+ NULL, /* 0,13 swiss nrc to transparent */
+ NULL, /* 0,14 latin-1 to transparent */
+ NULL, /* 0,15 latin-2 to transparent */
+ NULL, /* 0,16 DEC MCS to transparent */
+ NULL, /* 0,17 NeXT to transparent */
+ NULL, /* 0,18 CP437 to transparent */
+ NULL, /* 0,19 CP850 to transparent */
+ NULL, /* 0,20 CP852 to transparent */
+ NULL, /* 0,21 Macintosh Latin to transparent */
+ NULL, /* 0,22 DGI to transparent */
+ NULL, /* 0,23 HP to transparent */
+ NULL, /* 0,24 Latin/Cyrillic to transparent */
+ NULL, /* 0,25 CP866 to transparent */
+ NULL, /* 0,26 Short KOI to transparent */
+ NULL, /* 0,27 Old KOI-8 to transparent */
+ NULL, /* 0,28 JIS-7 to transparent */
+ NULL, /* 0,29 Shift JIS to transparent */
+ NULL, /* 0,30 Japanese EUC to transparent */
+ NULL, /* 0,31 DEC Kanji to transparent */
+ NULL, /* 0,32 Hebrew-7 to transparent */
+ NULL, /* 0,33 Latin/Hebrew to transparent */
+ NULL, /* 0,34 CP862 Hebrew to transparent */
+ NULL, /* 0,35 ELOT 927 Greek to transparent */
+ NULL, /* 0,36 Latin/Greek to transparent */
+ NULL, /* 0,37 CP869 to transparent */
+ NULL, /* 0,38 Latin-9 to transparent */
+ NULL, /* 0,39 CP858 to transparent */
+ NULL, /* 0,40 CP855 to transparent */
+ NULL, /* 0,41 CP1251 to transparent */
+ NULL, /* 0,42 Bulgarian to transparent */
+ NULL, /* 0,43 CP1250 to transparent */
+ NULL, /* 0,44 Mazovia to transparent */
+ NULL, /* 0,45 UCS-2 to transparent */
+ NULL, /* 0,46 UTF-8 to transparent */
+ NULL, /* 0,47 KOI8R to transparent */
+ NULL, /* 0,48 KOI8U to transparent */
+ NULL, /* 0,49 CP1252 to transparent */
+ NULL, /* 1,0 us ascii to ascii */
+ NULL, /* 1,1 uk ascii to ascii */
+ xduas, /* 1,2 dutch nrc to ascii */
+ xfias, /* 1,3 finnish nrc to ascii */
+ xfras, /* 1,4 french nrc to ascii */
+ xfcas, /* 1,5 french canadian nrc to ascii */
+ xgeas, /* 1,6 german nrc to ascii */
+ xhuas, /* 1,7 hungarian nrc to ascii */
+ xitas, /* 1,8 italian nrc to ascii */
+ xnoas, /* 1,9 norwegian/danish nrc to ascii */
+ xpoas, /* 1,10 portuguese nrc to ascii */
+ xspas, /* 1,11 spanish nrc to ascii */
+ xswas, /* 1,12 swedish nrc to ascii */
+ xchas, /* 1,13 swiss nrc to ascii */
+ xl1as, /* 1,14 latin-1 to ascii */
+ xl2as, /* 1,15 latin-2 to ascii */
+ xdmas, /* 1,16 dec mcs to ascii */
+ xneas, /* 1,17 NeXT to ascii */
+ x43as, /* 1,18 CP437 to ascii */
+ x85as, /* 1,19 CP850 to ascii */
+ x52as, /* 1,20 CP850 to ascii */
+ xaqas, /* 1,21 Macintosh Latin to ascii */
+ xdgas, /* 1,22 DGI to ascii */
+ xr8as, /* 1,23 HP to ASCII */
+ xlcas, /* 1,24 Latin/Cyrillic to ASCII */
+ xacas, /* 1,25 CP866 to ASCII */
+ xskas, /* 1,26 Short KOI to ASCII */
+ xk8as, /* 1,27 Old KOI-8 Cyrillic to ASCII */
+ NULL, /* 1,28 */
+ NULL, /* 1,29 */
+ NULL, /* 1,30 */
+ NULL, /* 1,31 */
+ xh7as, /* 1,32 Hebrew-7 to ASCII */
+ xlhas, /* 1,33 Latin/Hebrew to ASCII */
+ x62as, /* 1,34 CP862 Hebrew to ASCII */
+ xegas, /* 1,35 ELOT 927 Greek to ASCII */
+ xlgas, /* 1,36 Latin/Greek to ASCII */
+ x69as, /* 1,37 CP869 to ASCII */
+ xl9as, /* 1,38 Latin-9 to ASCII */
+ x58as, /* 1,39 CP858 to ASCII */
+ x55as, /* 1,40 CP855 to ASCII */
+ x1251as, /* 1,41 CP1251 to ASCII */
+ xleft128, /* 1,42 Bulgarian to ASCII */
+ x1250as, /* 1,43 CP1250 to ASCII */
+ xmzas, /* 1,44 Mazovia to ASCII */
+ NULL, /* 1,45 UCS-2 to ASCII */
+ NULL, /* 1,46 UTF-8 to ASCII */
+ xk8as, /* 1,47 KOI8R to ASCII */
+ xk8as, /* 1,48 KOI8U to ASCII */
+ xw1as, /* 1,49 CP1252 to ASCII */
+ NULL, /* 2,0 us ascii to latin-1 */
+ xukl1, /* 2,1 uk ascii to latin-1 */
+ xdul1, /* 2,2 dutch nrc to latin-1 */
+ xfil1, /* 2,3 finnish nrc to latin-1 */
+ xfrl1, /* 2,4 french nrc to latin-1 */
+ xfcl1, /* 2,5 french canadian nrc to latin-1 */
+ xgel1, /* 2,6 german nrc to latin-1 */
+ xhul1, /* 2,7 hungarian nrc to latin-1 */
+ xitl1, /* 2,8 italian nrc to latin-1 */
+ xnol1, /* 2,9 norwegian/danish nrc to latin-1 */
+ xpol1, /* 2,10 portuguese nrc to latin-1 */
+ xspl1, /* 2,11 spanish nrc to latin-1 */
+ xswl1, /* 2,12 swedish nrc to latin-1 */
+ xchl1, /* 2,13 swiss nrc to latin-1 */
+ NULL, /* 2,14 latin-1 to latin-1 */
+ xl2l1, /* 2,15 latin-2 to latin-1 */
+ xdml1, /* 2,16 dec mcs to latin-1 */
+ xnel1, /* 2,17 NeXT to Latin-1 */
+ x43l1, /* 2,18 CP437 to Latin-1 */
+ x85l1, /* 2,19 CP850 to Latin-1 */
+ x52l1, /* 2,20 CP852 to Latin-1 */
+ xaql1, /* 2,21 Macintosh Latin to Latin-1 */
+ xdgl1, /* 2,22 DGI to Latin-1 */
+ xr8l1, /* 2,23 HP to Latin-1 */
+ xlcas, /* 2,24 Latin/Cyrillic to Latin-1 */
+ xacas, /* 2,25 CP866 to Latin-1 */
+ xskas, /* 2,26 Short KOI to Latin-1 */
+ xk8as, /* 2,27 Old KOI-8 Cyrillic to Latin-1 */
+ NULL, /* 2,28 Kanji ... */
+ NULL, /* 2,29 */
+ NULL, /* 2,30 */
+ NULL, /* 2,31 */
+ xh7as, /* 2,32 Hebrew-7 to Latin-1 */
+ xlhl1, /* 2,33 Latin/Hebrew to Latin-1 */
+ x62l1, /* 2,34 CP862 Hebrew to Latin-1 */
+ xegas, /* 2,35 ELOT 927 Greek to Latin-1 */
+ xlgl1, /* 2,36 Latin/Greek to Latin-1 */
+ NULL, /* 2,37 CP869 to Latin-1 */
+ NULL, /* 2,38 Latin-9 to Latin-1 */
+ x58l1, /* 2,39 CP858 to Latin-1 */
+ x55as, /* 2,40 CP855 to Latin-1 */
+ x1251as, /* 2,41 CP1251 to Latin-1 */
+ xleft128, /* 2,42 Bulgarian to Latin-1 */
+ x1250l1, /* 2,43 CP1250 to Latin-1 */
+ xmzl1, /* 2,44 Mazovia to Latin-1 */
+ NULL, /* 2,45 UCS-2 to Latin-1 */
+ NULL, /* 2,46 UTF-8 to Latin-1 */
+ xk8as, /* 2,47 KOI8R to Latin-1 */
+ xk8as, /* 2,48 KOI8U to Latin-1 */
+ xw1l1, /* 2,49 CP1252 to Latin-1 */
+ NULL, /* 3,0 us ascii to latin-2 */
+ NULL, /* 3,1 uk ascii to latin-2 */
+ xduas, /* 3,2 dutch nrc to latin-2 */
+ xfias, /* 3,3 finnish nrc to latin-2 */
+ xfras, /* 3,4 french nrc to latin-2 */
+ xfcas, /* 3,5 french canadian nrc to latin-2 */
+ xgel2, /* 3,6 german nrc to latin-2 */
+ xhul2, /* 3,7 hungarian nrc to latin-2 */
+ xitas, /* 3,8 italian nrc to latin-2 */
+ xnoas, /* 3,9 norwegian/danish nrc to latin-2 */
+ xpoas, /* 3,10 portuguese nrc to latin-2 */
+ xspas, /* 3,11 spanish nrc to latin-2 */
+ xswas, /* 3,12 swedish nrc to latin-2 */
+ xchas, /* 3,13 swiss nrc to latin-2 */
+ xl1l2, /* 3,14 latin-1 to latin-2 */
+ NULL, /* 3,15 latin-2 to latin-2 */
+ xl1l2, /* 3,16 dec mcs to latin-2 */
+ xnel2, /* 3,17 NeXT to Latin-2 */
+ x43l2, /* 3,18 CP437 to Latin-2 */
+ x85l2, /* 3,19 CP850 to Latin-2 */
+ x52l2, /* 3,20 CP852 to Latin-2 */
+ xaql2, /* 3,21 Macintosh Latin to Latin-2 */
+ xdgl2, /* 3,22 DGI to Latin-2 */
+ xr8l2, /* 3,23 HP to Latin-2 */
+ xlcas, /* 3,24 Latin/Cyrillic to Latin-2 */
+ xacas, /* 3,25 CP866 to Latin-2 */
+ xskas, /* 3,26 Short KOI to Latin-2 */
+ xk8as, /* 3,27 Old KOI-8 Cyrillic to Latin-2 */
+ NULL, /* 3,28 Kanji ... */
+ NULL, /* 3,29 */
+ NULL, /* 3,30 */
+ NULL, /* 3,31 */
+ xh7as, /* 3,32 Hebrew-7 to Latin-2 */
+ xlhas, /* 3,33 Latin/Hebrew to Latin-2 */
+ x62as, /* 3,34 CP862 Hebrew to Latin-2 */
+ xegas, /* 3,35 ELOT 927 Greek to Latin-2 */
+ xl2lg, /* 3,36 Latin/Greek to Latin-2 */
+ xleft128, /* 3,37 CP869 to Latin-2 */
+ xl9l2, /* 3,38 Latin-9 to Latin-2 */
+ x58l2, /* 3,39 CP858 to Latin-2 */
+ x55as, /* 3,40 CP855 to Latin-2 */
+ x1251as, /* 3,41 CP1251 to Latin-2 */
+ xleft128, /* 3,42 Bulgarian to Latin-2 */
+ x1250l2, /* 3,43 CP1250 to Latin-2 */
+ xmzl2, /* 3,44 Mazovia to Latin-2 */
+ NULL, /* 3,45 UCS-2 to Latin-2 */
+ NULL, /* 3,46 UTF-8 to Latin-2 */
+ xk8as, /* 3,47 KOI8R to Latin-2 */
+ xk8as, /* 3,48 KOI8U to Latin-2 */
+ xw1l2, /* 3,49 CP1252 to latin-2 */
+ xaslc, /* 4,0 us ascii to latin/cyrillic */
+ xaslc, /* 4,1 uk ascii to latin/cyrillic */
+ xduas, /* 4,2 dutch nrc to latin/cyrillic */
+ xfias, /* 4,3 finnish nrc to latin/cyrillic */
+ xfras, /* 4,4 french nrc to latin/cyrillic */
+ xfcas, /* 4,5 french canadian nrc to latin/cyrillic */
+ xgeas, /* 4,6 german nrc to latin/cyrillic */
+ xhuas, /* 4,7 hungarian nrc to latin/cyrillic */
+ xitas, /* 4,8 italian nrc to latin/cyrillic */
+ xnoas, /* 4,9 norge/danish nrc to latin/cyrillic */
+ xpoas, /* 4,10 portuguese nrc to latin/cyrillic */
+ xspas, /* 4,11 spanish nrc to latin/cyrillic */
+ xswas, /* 4,12 swedish nrc to latin/cyrillic */
+ xchas, /* 4,13 swiss nrc to latin/cyrillic */
+ xl1as, /* 4,14 latin-1 to latin/cyrillic */
+ xl2as, /* 4,15 latin-2 to latin/cyrillic */
+ xdmas, /* 4,16 dec mcs to latin/cyrillic */
+ xneas, /* 4,17 NeXT to latin/cyrillic */
+ x43as, /* 4,18 CP437 to latin/cyrillic */
+ x85as, /* 4,19 CP850 to latin/cyrillic */
+ x52as, /* 4,20 CP852 to latin/cyrillic */
+ xaqas, /* 4,21 Macintosh Latin to latin/cyrillic */
+ xdgas, /* 4,22 DGI to Latin/Cyrillic */
+ xr8as, /* 4,23 HP to Latin/Cyrillic */
+ NULL, /* 4,24 Latin/Cyrillic to Latin/Cyrillic */
+ xaclc, /* 4,25 CP866 to Latin/Cyrillic */
+ xskcy, /* 4,26 Short KOI to Latin/Cyrillic */
+ xk8lc, /* 4,27 Old KOI-8 Cyrillic to Latin/Cyrillic */
+ NULL, /* 4,28 Kanji... */
+ NULL, /* 4,29 */
+ NULL, /* 4,30 */
+ NULL, /* 4,31 */
+ xh7as, /* 4,32 Hebrew-7 to Latin/Cyrillic */
+ xlhas, /* 4,33 Latin/Hebrew to Latin/Cyrillic */
+ x62as, /* 4,34 CP862 Hebrew to Latin/Cyrillic */
+ xegas, /* 4,35 ELOT 927 Greek to Latin/Cyrillic */
+ xleft160, /* 4,36 Latin/Greek to Latin/Cyrillic */
+ xleft128, /* 4,37 CP869 to Latin/Cyrillic */
+ xl1as, /* 4,38 latin-9 to latin/cyrillic */
+ xleft128, /* 4,39 CP858 to Latin/Cyrillic */
+ x55lc, /* 4,40 CP855 to Latin/Cyrillic */
+ x1251lc, /* 4,41 CP1251 to Latin/Cyrillic */
+ xbulc, /* 4,42 Bulgarian to Latin/Cyrillic */
+ x1250as, /* 4,43 CP1250 to Latin/Cyrillic */
+ xmzas, /* 4,44 Mazovia to Latin/Cyrillic */
+ NULL, /* 4,45 UCS-2 to Latin/Cyrillic */
+ NULL, /* 4,46 UTF-8 to Latin/Cyrillic */
+ xkrlc, /* 4,47 KOI8R to Latin/Cyrillic */
+ xkulc, /* 4,48 KOI8U to Latin/Cyrillic */
+ xw1lc, /* 4,49 CP1252 to Latin/Cyrillic */
+ NULL, /* 5,00 */
+ NULL, /* 5,01 */
+ NULL, /* 5,02 */
+ NULL, /* 5,03 */
+ NULL, /* 5,04 */
+ NULL, /* 5,05 */
+ NULL, /* 5,06 */
+ NULL, /* 4.07 */
+ NULL, /* 5,08 */
+ NULL, /* 5,09 */
+ NULL, /* 5,10 */
+ NULL, /* 5,11 */
+ NULL, /* 5,12 */
+ NULL, /* 5,13 */
+ NULL, /* 5,14 */
+ NULL, /* 5,15 */
+ NULL, /* 5,16 */
+ NULL, /* 5,17 */
+ NULL, /* 5,18 */
+ NULL, /* 5,19 */
+ NULL, /* 5,20 */
+ NULL, /* 5,21 */
+ NULL, /* 5,22 */
+ NULL, /* 5,23 */
+ NULL, /* 5,24 */
+ NULL, /* 5,25 */
+ NULL, /* 5,26 */
+ NULL, /* 5,27 */
+ NULL, /* 5,28 */
+ NULL, /* 5,29 */
+ NULL, /* 5,30 */
+ NULL, /* 5,31 */
+ NULL, /* 5,32 */
+ NULL, /* 5,33 */
+ NULL, /* 5,34 */
+ NULL, /* 5,35 */
+ NULL, /* 5,36 */
+ NULL, /* 5,37 */
+ NULL, /* 5,38 */
+ NULL, /* 5,39 */
+ NULL, /* 5,40 */
+ NULL, /* 5,41 */
+ NULL, /* 5,42 */
+ NULL, /* 5,43 */
+ NULL, /* 5,44 */
+ NULL, /* 5,45 */
+ NULL, /* 5,46 */
+ NULL, /* 5,47 */
+ NULL, /* 5,48 */
+ NULL, /* 5,49 */
+ NULL, /* 6,0 us ascii to Latin/Hebrew */
+ NULL, /* 6,1 uk ascii to Latin/Hebrew */
+ xduas, /* 6,2 dutch nrc to Latin/Hebrew */
+ xfias, /* 6,3 finnish nrc to Latin/Hebrew */
+ xfras, /* 6,4 french nrc to Latin/Hebrew */
+ xfcas, /* 6,5 french canadian nrc to Latin/Hebrew */
+ xgeas, /* 6,6 german nrc to Latin/Hebrew */
+ xhuas, /* 6,7 hungarian nrc to Latin/Hebrew */
+ xitas, /* 6,8 italian nrc to Latin/Hebrew */
+ xnoas, /* 6,9 norge/danish nrc to Latin/Hebrew */
+ xpoas, /* 6,10 portuguese nrc to Latin/Hebrew */
+ xspas, /* 6,11 spanish nrc to Latin/Hebrew */
+ xswas, /* 6,12 swedish nrc to Latin/Hebrew */
+ xchas, /* 6,13 swiss nrc to Latin/Hebrew */
+ xl1lh, /* 6,14 latin-1 to Latin/Hebrew */
+ xl2as, /* 6,15 latin-2 to Latin/Hebrew */
+ xdmas, /* 6,16 dec mcs to Latin/Hebrew */
+ xneas, /* 6,17 NeXT to Latin/Hebrew */
+ x43as, /* 6,18 CP437 to Latin/Hebrew */
+ x85as, /* 6,19 CP850 to Latin/Hebrew */
+ x52as, /* 6,20 CP852 to Latin/Hebrew */
+ xaqas, /* 6,21 Macintosh Latin to Latin/Hebrew */
+ xdgas, /* 6,22 DGI to Latin/Hebrew */
+ xr8as, /* 6,23 HP to Latin/Hebrew */
+ xlcas, /* 6,24 Latin/Cyrillic to Latin/Hebrew */
+ xacas, /* 6,25 CP866 to Latin/Hebrew */
+ xskas, /* 6,26 Short KOI to Latin/Hebrew */
+ xk8as, /* 6,27 Old KOI-8 Cyrillic to Latin/Hebrew */
+ NULL, /* 6,28 Kanji... */
+ NULL, /* 6,29 */
+ NULL, /* 6,30 */
+ NULL, /* 6,31 */
+ xh7lh, /* 6,32 Hebrew-7 to Latin/Hebrew */
+ NULL, /* 6,33 Latin/Hebrew to Latin/Hebrew */
+ x62lh, /* 6,34 CP862 Hebrew to Latin/Hebrew */
+ xegas, /* 6,35 ELOT 927 Greek to Latin/Hebrew */
+ xlgas, /* 6,36 Latin/Greek to Latin/Hebrew */
+ x69as, /* 6,37 CP869 to Latin/Hebrew */
+ xl1as, /* 6,38 latin-9 to Latin/Hebrew */
+ x58as, /* 6,39 CP858 to Latin/Hebrew */
+ x55as, /* 6,40 CP855 to Latin/Hebrew */
+ x1251as, /* 6,41 CP1251 to Latin/Hebrew */
+ xleft128, /* 6,42 Bulgarian to Latin/Hebrew */
+ x1250as, /* 6,43 CP1250 to Latin/Hebrew */
+ xmzas, /* 6,44 Mazovia to Latin/Hebrew */
+ NULL, /* 6,45 UCS-2 to Latin/Hebrew */
+ NULL, /* 6,46 UTF-8 to Latin/Hebrew */
+ NULL, /* 6,47 KOI8R to Latin/Hebrew */
+ NULL, /* 6,48 KOI8U to Latin/Hebrew */
+ xw1lh, /* 6,49 CP1252 to Latin/Hebrew */
+ NULL, /* 7,0 us ascii to Latin/Greek */
+ NULL, /* 7,1 uk ascii to Latin/Greek */
+ xduas, /* 7,2 dutch nrc to Latin/Greek */
+ xfias, /* 7,3 finnish nrc to Latin/Greek */
+ xfras, /* 7,4 french nrc to Latin/Greek */
+ xfcas, /* 7,5 french canadian nrc to Latin/Greek */
+ xgeas, /* 7,6 german nrc to Latin/Greek */
+ xhuas, /* 7,7 hungarian nrc to Latin/Greek */
+ xitas, /* 7,8 italian nrc to Latin/Greek */
+ xnoas, /* 7,9 norge/danish nrc to Latin/Greek */
+ xpoas, /* 7,10 portuguese nrc to Latin/Greek */
+ xspas, /* 7,11 spanish nrc to Latin/Greek */
+ xswas, /* 7,12 swedish nrc to Latin/Greek */
+ xchas, /* 7,13 swiss nrc to Latin/Greek */
+ xl1lg, /* 7,14 latin-1 to Latin/Greek */
+ xl2lg, /* 7,15 latin-2 to Latin/Greek */
+ xl1lg, /* 7,16 dec mcs to Latin/Greek */
+ xneas, /* 7,17 NeXT to Latin/Greek */
+ xleft128, /* 7,18 CP437 to Latin/Greek */
+ x85as, /* 7,19 CP850 to Latin/Greek */
+ x52as, /* 7,20 CP852 to Latin/Greek */
+ xaqas, /* 7,21 Macintosh Latin to Latin/Greek */
+ xdgas, /* 7,22 DGI to Latin/Greek */
+ xr8as, /* 7,23 HP to Latin/Greek */
+ xleft160, /* 7,24 Latin/Cyrillic to Latin/Greek */
+ xleft128, /* 7,25 CP866 to Latin/Greek */
+ xskas, /* 7,26 Short KOI to Latin/Greek */
+ xk8as, /* 7,27 Old KOI-8 Cyrillic to Latin/Greek */
+ NULL, /* 7,28 Kanji... */
+ NULL, /* 7,29 */
+ NULL, /* 7,30 */
+ NULL, /* 7,31 */
+ xh7as, /* 7,32 Hebrew-7 to Latin/Greek */
+ NULL, /* 7,33 Latin/Hebrew to Latin/Greek */
+ x62as, /* 7,34 CP862 Hebrew to Latin/Greek */
+ xeglg, /* 7,35 ELOT 927 Greek to Latin/Greek */
+ NULL, /* 7,36 Latin/Greek to Latin/Greek */
+ x69lg, /* 7,37 CP869 to Latin/Greek */
+ xl1as, /* 7,38 latin-9 to Latin/Greek */
+ xl1as, /* 7,39 latin-9 to Latin/Hebrew*/
+ xleft128, /* 7,40 CP855 to Latin/Greek */
+ xleft128, /* 7,41 CP1251 to Latin/Greek */
+ xleft128, /* 7,42 Bulgarian to Latin/Greek */
+ x1250as, /* 7,43 CP1250 to Latin/Greek */
+ xmzas, /* 7,44 Mazovia to Latin/Greek */
+ NULL, /* 7,45 UCS-2 to Latin/Greek */
+ NULL, /* 7,46 UTF-8 to Latin/Greek */
+ NULL, /* 7,47 KOI8R to Latin/Greek */
+ NULL, /* 7,48 KOI8U to Latin/Greek */
+ xw1lg, /* 7,49 CP1252 to Latin/Greek */
+ NULL, /* 8,0 us ascii to latin-9 */
+ xukl1, /* 8,1 uk ascii to latin-9 */
+ xdul1, /* 8,2 dutch nrc to latin-9 */
+ xfil1, /* 8,3 finnish nrc to latin-9 */
+ xfrl1, /* 8,4 french nrc to latin-9 */
+ xfcl1, /* 8,5 french canadian nrc to latin-9 */
+ xgel1, /* 8,6 german nrc to latin-9 */
+ xhul1, /* 8,7 hungarian nrc to latin-9 */
+ xitl1, /* 8,8 italian nrc to latin-9 */
+ xnol1, /* 8,9 norwegian/danish nrc to latin-9 */
+ xpol1, /* 8,10 portuguese nrc to latin-9 */
+ xspl1, /* 8,11 spanish nrc to latin-9 */
+ xswl1, /* 8,12 swedish nrc to latin-9 */
+ xchl1, /* 8,13 swiss nrc to latin-9 */
+ NULL, /* 8,14 latin-1 to latin-9 */
+ xl2l9, /* 8,15 latin-2 to latin-9 */
+ xdml9, /* 8,16 dec mcs to latin-9 */
+ xnel9, /* 8,17 NeXT To Latin-9 */
+ x43l1, /* 8,18 CP437 To Latin-9 */
+ x85l1, /* 8,19 CP850 To Latin-9 */
+ x52l1, /* 8,20 CP852 To Latin-9 */
+ xaql1, /* 8,21 Macintosh Latin To Latin-9 */
+ xdgl1, /* 8,22 DGI To Latin-9 */
+ xr8l1, /* 8,23 HP To Latin-9 */
+ xlcas, /* 8,24 Latin/Cyrillic To Latin-9 */
+ xacas, /* 8,25 CP866 To Latin-9 */
+ xskas, /* 8,26 Short KOI To Latin-9 */
+ xk8as, /* 8,27 Old KOI-8 Cyrillic To Latin-9 */
+ NULL, /* 8,28 Kanji ... */
+ NULL, /* 8,29 */
+ NULL, /* 8,30 */
+ NULL, /* 8,31 */
+ xh7as, /* 8,32 Hebrew-7 To Latin-9 */
+ xlhl1, /* 8,33 Latin/Hebrew To Latin-9 */
+ x62l1, /* 8,34 CP862 Hebrew To Latin-9 */
+ xegas, /* 8,35 ELOT 927 Greek To Latin-9 */
+ xlgl1, /* 8,36 Latin/Greek To Latin-9 */
+ xl169, /* 8,37 CP869 To Latin-9 */
+ NULL, /* 8,38 Latin-9 To Latin-9 */
+ x58l9, /* 8,39 cp858 To Latin-9 */
+ x55as, /* 8,40 cp855 To Latin-9 */
+ x55as, /* 8,41 cp1251 To Latin-9 */
+ xleft128, /* 8,42 Bulgarian To Latin-9 */
+ x1250l9, /* 8,43 CP1250 To Latin-9 */
+ xmzl9, /* 8,44 Mazovia To Latin-9 */
+ NULL, /* 8,45 UCS-2 to Latin-9 */
+ NULL, /* 8,46 UTF-8 to Latin-9 */
+ NULL, /* 8,47 KOI8R to Latin-9 */
+ NULL, /* 8,48 KOI8U to Latin-9 */
+ xw1l9, /* 8,49 CP1252 to Latin-9 */
+ NULL, /* 9,00 Unicode... */
+ NULL, /* 9,01 */
+ NULL, /* 9,02 */
+ NULL, /* 9,03 */
+ NULL, /* 9,04 */
+ NULL, /* 9,05 */
+ NULL, /* 9,06 */
+ NULL, /* 9,07 */
+ NULL, /* 9,08 */
+ NULL, /* 9,09 */
+ NULL, /* 9,10 */
+ NULL, /* 9,11 */
+ NULL, /* 9,12 */
+ NULL, /* 9,13 */
+ NULL, /* 9,14 */
+ NULL, /* 9,15 */
+ NULL, /* 9,16 */
+ NULL, /* 9,17 */
+ NULL, /* 9,18 */
+ NULL, /* 9,19 */
+ NULL, /* 9,20 */
+ NULL, /* 9,21 */
+ NULL, /* 9,22 */
+ NULL, /* 9,23 */
+ NULL, /* 9,24 */
+ NULL, /* 9,25 */
+ NULL, /* 9,26 */
+ NULL, /* 9,27 */
+ NULL, /* 9,28 */
+ NULL, /* 9,29 */
+ NULL, /* 9,30 */
+ NULL, /* 9,31 */
+ NULL, /* 9,32 */
+ NULL, /* 9,33 */
+ NULL, /* 9,34 */
+ NULL, /* 9,35 */
+ NULL, /* 9,36 */
+ NULL, /* 9,37 */
+ NULL, /* 9,38 */
+ NULL, /* 9,39 */
+ NULL, /* 9,40 */
+ NULL, /* 9,41 */
+ NULL, /* 9,42 */
+ NULL, /* 9,43 */
+ NULL, /* 9,44 */
+ NULL, /* 9,45 */
+ NULL, /* 9,46 */
+ NULL, /* 9,47 */
+ NULL, /* 9,48 */
+ NULL, /* 9,49 */
+ NULL, /* 10,00 */
+ NULL, /* 10,01 */
+ NULL, /* 10,02 */
+ NULL, /* 10,03 */
+ NULL, /* 10,04 */
+ NULL, /* 10,05 */
+ NULL, /* 10,06 */
+ NULL, /* 10,07 */
+ NULL, /* 10,08 */
+ NULL, /* 10,09 */
+ NULL, /* 10,10 */
+ NULL, /* 10,11 */
+ NULL, /* 10,12 */
+ NULL, /* 10,13 */
+ NULL, /* 10,14 */
+ NULL, /* 10,15 */
+ NULL, /* 10,16 */
+ NULL, /* 10,17 */
+ NULL, /* 10,18 */
+ NULL, /* 10,19 */
+ NULL, /* 10,20 */
+ NULL, /* 10,21 */
+ NULL, /* 10,22 */
+ NULL, /* 10,23 */
+ NULL, /* 10,24 */
+ NULL, /* 10,25 */
+ NULL, /* 10,26 */
+ NULL, /* 10,27 */
+ NULL, /* 10,28 */
+ NULL, /* 10,29 */
+ NULL, /* 10,30 */
+ NULL, /* 10,31 */
+ NULL, /* 10,32 */
+ NULL, /* 10,33 */
+ NULL, /* 10,34 */
+ NULL, /* 10,35 */
+ NULL, /* 10,36 */
+ NULL, /* 10,37 */
+ NULL, /* 10,38 */
+ NULL, /* 10,39 */
+ NULL, /* 10,40 */
+ NULL, /* 10,41 */
+ NULL, /* 10,42 */
+ NULL, /* 10,43 */
+ NULL, /* 10,44 */
+ NULL, /* 10,45 */
+ NULL, /* 10,46 */
+ NULL, /* 10,47 */
+ NULL, /* 10,48 */
+ NULL /* 10,49 */
+};
+int nxls = (sizeof(xls) / sizeof(CHAR *));
+
+#ifndef NOLOCAL
+/*
+ The following routines are useful only for terminal character sets, and so
+ ifdef'd out for NOLOCAL compilations.
+*/
+
+/*
+ C S _ I S _ N R C
+
+ Returns nonzero if argument indicates a 7-bit national character set,
+ zero otherwise.
+*/
+int
+cs_is_nrc(x) int x; {
+#ifdef UNICODE
+ if (x == TX_J201R || x == TX_DECSPEC || x == TX_DECTECH
+ || txrinfo[x] == NULL)
+ return(0);
+ else
+ return(txrinfo[x]->flags & X2U_STD && txrinfo[x]->size == 94);
+#else /* UNICODE */
+ if ((cs_size(x) == 94))
+ return(1);
+ else
+ return(0);
+#endif /* UNICODE */
+}
+
+/*
+ C S _ I S _ S T D
+
+ Returns nonzero if argument indicates an ISO 4873-standard-format
+ character set, i.e. one in which the control region is NOT used for
+ graphics; zero otherwise.
+*/
+int
+cs_is_std(x) int x; {
+#ifdef UNICODE
+ if (!txrinfo[x]) /* Even more safety */
+ return(0);
+ else if (txrinfo[x]->size == 128) /* Just for safety */
+ return(0);
+ else
+ return(txrinfo[x]->flags & X2U_STD); /* Only this should be needed */
+#else
+ switch (x) {
+ case FC_CP437: /* Code pages use C1 graphics */
+ case FC_CP850:
+ case FC_CP852:
+ case FC_CP862:
+ case FC_CP866:
+ case FC_CP869:
+ case FC_CP858:
+ case FC_APPQD: /* So do Apple and NeXTSTEP */
+ case FC_NEXT:
+ return(0);
+ default: /* Others behave */
+ return(1);
+ }
+#endif /* CKOUINI */
+}
+
+int
+cs_size(x) int x; {
+#ifdef UNICODE
+ if (!txrinfo[x])
+ return(128);
+ return(txrinfo[x]->size);
+#else
+ switch(x) {
+ case FC_USASCII:
+ case FC_UKASCII:
+ case FC_DUASCII:
+ case FC_FIASCII:
+ case FC_FRASCII:
+ case FC_FCASCII:
+ case FC_GEASCII:
+ case FC_HUASCII:
+ case FC_ITASCII:
+ case FC_NOASCII:
+ case FC_POASCII:
+ case FC_SPASCII:
+ case FC_SWASCII:
+ case FC_CHASCII:
+ case FC_KOI7:
+ case FC_HE7:
+ case FC_ELOT:
+ return(94);
+
+ case FC_1LATIN:
+ case FC_2LATIN:
+ case FC_DECMCS:
+ case FC_DGMCS:
+ case FC_HPR8:
+ case FC_CYRILL:
+ case FC_KOI8:
+ case FC_HEBREW:
+ case FC_GREEK:
+ case FC_9LATIN:
+ return(96);
+
+ case FC_NEXT:
+ case FC_CP437:
+ case FC_CP850:
+ case FC_CP852:
+ case FC_CP855:
+ case FC_CP862:
+ case FC_CP866:
+ case FC_CP1251:
+ case FC_APPQD:
+ return(128);
+#ifdef KANJI
+ case FC_JIS7:
+ return(-94);
+ case FC_SHJIS:
+ return(-128);
+ case FC_JEUC:
+ case FC_JDEC:
+ return(-96);
+#endif /* KANJI */
+ case FC_CP858:
+ default:
+ return(-1);
+ }
+#endif /* UNICODE */
+}
+#endif /* NOLOCAL */
+
+/*
+ S E T X L A T Y P E -- Set Translation Type
+
+ Sets global xlatype to indicate which kind of translation:
+
+ XLA_NONE No translation
+ XLA_BYTE Byte-for-Byte translation
+ XLA_JAPAN Japanese Kanji translation
+ XLA_UNICODE Unicode translations
+
+ And sets up the appropriate translation function pointers as follows:
+
+ For no translation:
+ All function pointers are NULL.
+
+ For Byte-for-Byte transation:
+ rx = TCS to FCS (these functions are in this module...)
+ sx = FCS to TCS
+
+ For Unicode translations:
+ xfu = FCS to UCS (these functions are in ckcuni.c...)
+ xtu = TCS to UCS
+ xuf = UCS to FCS
+ xut = UCS to TCS
+*/
+VOID
+setxlatype(tcs, fcs) int tcs, fcs; {
+#ifdef UNICODE
+ xfu = NULL; /* Unicode <-> TCS/FCS functions */
+ xtu = NULL;
+ xuf = NULL;
+ xut = NULL;
+#endif /* UNICODE */
+ rx = sx = NULL;
+ debug(F101,"setxlatype fcs","",fcs);
+ debug(F101,"setxlatype tcs","",tcs);
+
+ if (tcs < 0 || tcs > MAXTCSETS) {
+ debug(F101,"setxlatype bad tcs","",tcs);
+ return;
+ }
+ if (fcs < 0 || fcs > MAXFCSETS) {
+ debug(F101,"setxlatype bad fcs","",fcs);
+ return;
+ }
+ if (tcs == TC_TRANSP || xfrxla == 0) { /* Transfer charset TRANSPARENT */
+ debug(F101,"setxlatype transparent because TCS==Transparent","",tcs);
+ xlatype = XLA_NONE; /* Translation type is None */
+#ifdef UNICODE
+ /* If any of our charsets is Unicode we use Unicode functions */
+ /* even if TCS and FCS are the same because of BOM and byte swapping */
+ } else if (tcs == TC_UCS2 || tcs == TC_UTF8 ||
+ fcs == FC_UCS2 || fcs == FC_UTF8) {
+ debug(F101,"setxlatype Unicode tcs","",tcs);
+ debug(F101,"setxlatype Unicode fcs","",fcs);
+ /* Unicode <-> TCS/FCS functions */
+ xfu = xl_fcu[fcs]; /* FCS -> UCS */
+ xtu = xl_tcu[tcs]; /* TCS -> UCS */
+ xuf = xl_ufc[fcs]; /* UCS -> FCS */
+ xut = xl_utc[tcs]; /* UCS -> TCS */
+ xlatype = XLA_UNICODE; /* Translation type is Unicode */
+#ifdef COMMENT
+ /* These make trouble in 64-bit land */
+ debug(F001,"setxlatype Unicode xfu","",(unsigned)xfu);
+ debug(F001,"setxlatype Unicode xuf","",(unsigned)xuf);
+#endif /* COMMENT */
+#endif /* UNICODE */
+ } else if (cseqtab[tcs] == fcs) { /* Or if TCS == FCS */
+ debug(F101,"setxlatype transparent because TCS==FCS","",tcs);
+ xlatype = XLA_NONE; /* translation type is also None */
+#ifdef KANJI
+ /* Otherwise if any of them is Japanese, we use Kanji functions */
+ } else if (tcs == TC_JEUC || fcsinfo[fcs].alphabet == AL_JAPAN) {
+ debug(F101,"setxlatype Japanese tcs","",tcs);
+ debug(F101,"setxlatype Japanese fcs","",fcs);
+ xlatype = XLA_JAPAN; /* Translation type is Japanese */
+#endif /* KANJI */
+ /* Otherwise we use byte functions */
+ } else { /* Otherwise... */
+ rx = xlr[tcs][fcs]; /* Input translation function */
+ sx = xls[tcs][fcs]; /* Output translation function */
+ debug(F101,"setxlatype Byte tcs","",tcs);
+ debug(F101,"setxlatype Byte fcs","",fcs);
+ xlatype = XLA_BYTE; /* Translation type is Byte */
+ }
+ debug(F101,"setxlatype xlatype","",xlatype);
+}
+
+/* Set up translation between two file character sets with UCS intermediate */
+
+#ifdef UNICODE
+VOID
+initxlate(csin, csout) int csin, csout; {
+ xfu = NULL;
+ xtu = NULL;
+ xuf = NULL;
+ xut = NULL;
+
+ debug(F101,"initxlate csin","",csin);
+ debug(F101,"initxlate csout","",csout);
+
+ if (csin < 0 || csin > MAXFCSETS) {
+ debug(F101,"initxlate bad csin","",csin);
+ return;
+ }
+ if (csout < 0 || csout > MAXFCSETS) {
+ debug(F101,"initxlate bad csout","",csout);
+ return;
+ }
+ if (csin == csout && csin != FC_UCS2) {
+ xlatype = XLA_NONE; /* Translation type is None */
+ return;
+ }
+ xlatype = XLA_UNICODE; /* Translation type is Unicode */
+ xfu = xl_fcu[csin]; /* FCS -> UCS */
+ xuf = xl_ufc[csout]; /* UCS -> FCS */
+ xpnbyte(-1,0,0,NULL); /* Reset UCS-2 */
+#ifdef COMMENT
+ debug(F001,"initxlate Unicode xfu","",(unsigned)xfu);
+ debug(F001,"initxlate Unicode xuf","",(unsigned)xuf);
+#endif /* COMMENT */
+ debug(F101,"initxlate xlatype","",xlatype);
+}
+#endif /* UNICODE */
+
+int csetsinited = 0;
+
+VOID
+initcsets() { /* Routine to reset or initialize */
+ int i; /* character-set associations. */
+
+#ifdef UNICODE
+ if (ucsorder < 0) /* For creating UCS-2 files. */
+ ucsorder = byteorder;
+ if (ucsorder < 0)
+ ucsorder = 0;
+ if (fileorder < 0) /* For reading UCS-2 files. */
+ fileorder = ucsorder;
+#endif /* UNICODE */
+
+ debug(F101,"initcsets nxls","",nxls);
+ debug(F101,"initcsets nxlr","",nxlr);
+
+ debug(F101,"initcsets TERM LOCAL CSET","",tcsl);
+ debug(F101,"initcsets TERM REMOTE CSET","",tcsr);
+
+ for (i = 0; i <= MAXFCSETS; i++) /* First clear them all... */
+ afcset[i] = -1;
+ for (i = 0; i <= MAXTCSETS; i++)
+ axcset[i] = -1;
+
+ /* Now set specific defaults for incoming files */
+
+ xlatype = XLA_NONE;
+
+ axcset[TC_TRANSP] = FC_TRANSP;
+ axcset[TC_USASCII] = FC_USASCII;
+
+#ifdef OS2
+ switch (fcharset) {
+ case FC_CP850:
+ case FC_CP858:
+ case FC_CP437:
+ case FC_1LATIN:
+ axcset[TC_1LATIN] = fcharset;
+ break;
+ default:
+ axcset[TC_1LATIN] = FC_CP850;
+ }
+#else
+#ifdef HPUX
+ axcset[TC_1LATIN] = FC_HPR8;
+#else
+#ifdef VMS
+ axcset[TC_1LATIN] = FC_DECMCS;
+#else
+#ifdef NEXT
+ axcset[TC_1LATIN] = FC_NEXT;
+#else
+#ifdef datageneral
+ axcset[TC_1LATIN] = FC_DGMCS;
+#else
+ /* Should we use code pages on some PC based UNIXes? */
+ axcset[TC_1LATIN] = FC_1LATIN;
+#endif /* datageneral */
+#endif /* NEXT */
+#endif /* VMS */
+#endif /* HPUX */
+#endif /* OS2 */
+
+#ifdef OS2
+ axcset[TC_2LATIN] = FC_CP852;
+ axcset[TC_CYRILL] = FC_CP866;
+ axcset[TC_JEUC] = FC_SHJIS;
+ axcset[TC_HEBREW] = FC_CP862;
+ axcset[TC_GREEK] = FC_CP869;
+ axcset[TC_9LATIN] = FC_CP858;
+ axcset[TC_UCS2] = FC_UCS2;
+ axcset[TC_UTF8] = FC_UCS2;
+#else
+ axcset[TC_2LATIN] = FC_2LATIN;
+ axcset[TC_CYRILL] = FC_CYRILL;
+ axcset[TC_JEUC] = FC_JEUC;
+ axcset[TC_HEBREW] = FC_HEBREW;
+ axcset[TC_GREEK] = FC_GREEK;
+ axcset[TC_9LATIN] = FC_9LATIN;
+ axcset[TC_UCS2] = FC_UTF8;
+ axcset[TC_UTF8] = FC_UTF8;
+#endif /* OS2 */
+
+ /* And for outbound files */
+
+ afcset[FC_USASCII] = TC_USASCII;
+ afcset[FC_UKASCII] = TC_1LATIN;
+ afcset[FC_DUASCII] = TC_1LATIN;
+ afcset[FC_FIASCII] = TC_1LATIN;
+ afcset[FC_FRASCII] = TC_1LATIN;
+ afcset[FC_FCASCII] = TC_1LATIN;
+ afcset[FC_GEASCII] = TC_1LATIN;
+ afcset[FC_HUASCII] = TC_2LATIN;
+ afcset[FC_ITASCII] = TC_1LATIN;
+ afcset[FC_NOASCII] = TC_1LATIN;
+ afcset[FC_POASCII] = TC_1LATIN;
+ afcset[FC_SPASCII] = TC_1LATIN;
+ afcset[FC_SWASCII] = TC_1LATIN;
+ afcset[FC_CHASCII] = TC_1LATIN;
+ afcset[FC_1LATIN] = TC_1LATIN;
+ afcset[FC_2LATIN] = TC_2LATIN;
+ afcset[FC_DECMCS] = TC_1LATIN;
+ afcset[FC_NEXT] = TC_1LATIN;
+ afcset[FC_CP437] = TC_1LATIN;
+ afcset[FC_CP850] = TC_1LATIN;
+ afcset[FC_CP852] = TC_2LATIN;
+ afcset[FC_APPQD] = TC_1LATIN;
+ afcset[FC_DGMCS] = TC_1LATIN;
+ afcset[FC_HPR8] = TC_1LATIN;
+ afcset[FC_CYRILL] = TC_CYRILL;
+ afcset[FC_CP866] = TC_CYRILL;
+ afcset[FC_KOI7] = TC_CYRILL;
+ afcset[FC_KOI8] = TC_CYRILL;
+ afcset[FC_JIS7] = TC_JEUC;
+ afcset[FC_SHJIS] = TC_JEUC;
+ afcset[FC_JEUC] = TC_JEUC;
+ afcset[FC_JDEC] = TC_JEUC;
+ afcset[FC_HE7] = TC_HEBREW;
+ afcset[FC_HEBREW] = TC_HEBREW;
+ afcset[FC_CP862] = TC_HEBREW;
+ afcset[FC_ELOT] = TC_GREEK;
+ afcset[FC_GREEK] = TC_GREEK;
+ afcset[FC_CP869] = TC_GREEK;
+ afcset[FC_9LATIN] = TC_9LATIN;
+ afcset[FC_CP923] = TC_9LATIN;
+ afcset[FC_CP858] = TC_9LATIN;
+ afcset[FC_CP855] = TC_CYRILL;
+ afcset[FC_CP1251] = TC_CYRILL;
+ afcset[FC_BULGAR] = TC_CYRILL;
+ afcset[FC_CP1250] = TC_2LATIN;
+ afcset[FC_MAZOVIA] = TC_2LATIN;
+ afcset[FC_UCS2] = TC_UTF8;
+ afcset[FC_UTF8] = TC_UTF8;
+
+ afcset[FC_KOI8R] = TC_CYRILL;
+ afcset[FC_KOI8U] = TC_CYRILL;
+ afcset[FC_CP1252] = TC_1LATIN;
+
+ csetsinited++;
+ return;
+}
+#endif /* NOCSETS */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckuxla.h b/ckermit-9.0.302-build/ckermit-9.0.302/ckuxla.h
new file mode 100644
index 0000000..a3cd1a5
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckuxla.h
@@ -0,0 +1,118 @@
+/*
+ File CKUXLA.H
+
+ C-Kermit language and character-set support for UNIX, VMS, OS/2,
+ AOS/VS, and other systems.
+
+ This file should be used as a template for the language support files
+ for other C-Kermit implementations -- Macintosh, etc.
+*/
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City.
+
+ Copyright (C) 1985, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+
+*/
+
+#ifndef CKUXLA_H
+#define CKUXLA_H
+
+/* Codes for file character sets */
+
+/* ISO 646 and other ISO-646-like 7-bit sets */
+
+#define FC_USASCII 0 /* US ASCII */
+#define FC_UKASCII 1 /* United Kingdom ASCII */
+#define FC_DUASCII 2 /* Dutch ISO 646 NRC */
+#define FC_FIASCII 3 /* Finnish ISO 646 NRC */
+#define FC_FRASCII 4 /* French ISO 646 NRC */
+#define FC_FCASCII 5 /* French Canadian ISO 646 NRC */
+#define FC_GEASCII 6 /* German ISO 646 NRC */
+#define FC_HUASCII 7 /* Hungarian ISO 646 NRC */
+#define FC_ITASCII 8 /* Italian *ISO 646 NRC */
+#define FC_NOASCII 9 /* Norwegian and Danish ISO 646 NRC */
+#define FC_POASCII 10 /* Portuguese ISO 646 NRC */
+#define FC_SPASCII 11 /* Spanish ISO 646 NRC */
+#define FC_SWASCII 12 /* Swedish ISO 646 NRC */
+#define FC_CHASCII 13 /* Swiss ISO 646 NRC */
+
+/* 8-bit Roman character sets */
+
+#define FC_1LATIN 14 /* ISO 8859-1 Latin Alphabet 1 */
+#define FC_2LATIN 15 /* ISO 8859-2 Latin Alphabet 2 */
+#define FC_DECMCS 16 /* DEC Multinational Character Set */
+#define FC_NEXT 17 /* NeXT workstation character set */
+#define FC_CP437 18 /* IBM PC Code Page 437 */
+#define FC_CP850 19 /* IBM PC Code Page 850 */
+#define FC_CP852 20 /* IBM PC Code Page 852 */
+#define FC_APPQD 21 /* Apple Quickdraw */
+#define FC_DGMCS 22 /* Data General International Character Set */
+#define FC_HPR8 23 /* HP Roman8 */
+
+/* Cyrillic sets */
+
+#define FC_CYRILL 24 /* ISO 8859-5 Latin/Cyrillic */
+#define FC_CP866 25 /* PC Code Page 866 Cyrillic */
+#define FC_KOI7 26 /* KOI-7 = Short KOI */
+#define FC_KOI8 27 /* KOI-8 */
+
+/* Japanese sets */
+
+#define FC_JIS7 28 /* JIS-7 */
+#define FC_SHJIS 29 /* Shifted JIS = CP932 */
+#define FC_JEUC 30 /* Japanese EUC (JAE) */
+#define FC_JDEC 31 /* Japanese DEC Kanji */
+
+/* Hebrew sets */
+
+#define FC_HE7 32 /* 7-Bit DEC Hebrew */
+#define FC_HEBREW 33 /* 8-Bit ISO 8859-8 Latin/Hebrew */
+#define FC_CP862 34 /* Hebrew PC Code Page */
+
+/* Greek sets */
+
+#define FC_ELOT 35 /* 7-Bit ELOT 927 Greek */
+#define FC_GREEK 36 /* 8-Bit ISO 8859-7 Latin/Greek */
+#define FC_CP869 37 /* Greek PC Code Page */
+
+/* New Roman sets with Euro symbol */
+
+#define FC_9LATIN 38 /* ISO 8859-15 Latin Alphabet 9 */
+#define FC_CP923 38 /* Same as Latin-9 */
+#define FC_CP858 39 /* Western Europe with Euro */
+
+/* Other new additions */
+
+#define FC_CP855 40 /* Cyrillic PC Code Page */
+#define FC_CP1251 41 /* Cyrillic Windows */
+#define FC_BULGAR 42 /* Bulgarian PC code page */
+#define FC_CP1250 43 /* Latin 2 Windows (different from Latin-2)*/
+#define FC_MAZOVIA 44 /* Polish Mazovia PC code page */
+
+/* Unicode */
+
+#define FC_UCS2 45 /* ISO-10646 / Unicode UCS-2 */
+#define FC_UTF8 46 /* ISO-10646 / Unicode UTF-8 */
+
+/* Recent additions */
+
+#define FC_KOI8R 47 /* KOI8-R (RFC1489) - Russian + boxdrawing */
+#define FC_KOI8U 48 /* KOI8-U (RFC2319) - Ukrainian + boxdrawing */
+#define FC_CP1252 49 /* Latin 1 Windows */
+
+#define MAXFCSETS 49 /* Highest file character set number */
+
+#ifdef OS2
+#define FC_DECSPEC 253 /* Not real character-sets */
+#define FC_DECTECH 252
+#endif /* OS2 */
+
+#ifdef UNICODE
+_PROTOTYP( VOID initxlate, (int, int) );
+#endif /* UNICODE */
+
+#endif /* CKUXLA_H */
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ckwart.c b/ckermit-9.0.302-build/ckermit-9.0.302/ckwart.c
new file mode 100644
index 0000000..2f3bb75
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ckwart.c
@@ -0,0 +1,746 @@
+#include "ckcsym.h"
+char *wartv = "Wart Version 2.14, 10 Nov 1999";
+
+#define CKWART_C
+
+#ifdef MDEBUG
+/* Use the real ones in this module only */
+#ifdef malloc
+#undef malloc
+#endif /* malloc */
+#ifdef calloc
+#undef calloc
+#endif /* calloc */
+#ifdef realloc
+#undef realloc
+#endif /* realloc */
+#ifdef free
+#undef free
+#endif /* free */
+#endif /* MDEBUG */
+
+#ifdef MAC
+#define VOID void
+#endif /* MAC */
+
+/* W A R T */
+
+/*
+ A small subset of "lex".
+
+ Authors: Jeff Damens, Frank da Cruz
+ Columbia University Center for Computing Activites.
+ First released November 1984.
+ Copyright (C) 1984, 2009,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ * input format is:
+ * lines to be copied | %state <state names...>
+ * %%
+ * <state> | <state,state,...> CHAR { actions }
+ * ...
+ * %%
+ * more lines to be copied
+ */
+
+#include "ckcdeb.h" /* Includes */
+
+#ifdef STRATUS
+/* Actually call printf, not our printf-catcher for Kermit */
+#ifdef printf
+#undef printf
+#endif /* printf */
+#ifdef fprintf
+#undef fprintf
+#endif /* fprintf */
+#endif /* STRATUS */
+
+#ifdef MAC
+/* Same deal for Macintosh */
+#ifdef printf
+#undef printf
+#endif /* printf */
+#ifdef fprintf
+#undef fprintf
+#endif /* fprintf */
+#endif /* MAC */
+
+#ifdef UNIX
+/* And UNIX */
+#ifdef printf
+#undef printf
+#endif /* printf */
+#ifdef fprintf
+#undef fprintf
+#endif /* fprintf */
+#endif /* UNIX */
+/*
+ The following "char" should be changed to "short", "int", or "long" if your
+ wart program will generate more than 127 states. Since wart is used mainly
+ with C-Kermit, which has about 80 states, "char" is adequate. This keeps
+ the program about 3K-4K smaller, which can be critical on 16-bit
+ architectures.
+*/
+#ifdef IRIX60
+/*
+ Also use short or int if your compiler complains inordinately about
+ "integer conversion resulted in a change of sign"...
+*/
+#define TBL_TYPE "short" /* C data type of state table */
+#else
+#define TBL_TYPE "char" /* C data type of state table */
+#endif /* IRIX60 */
+
+#define C_L 014 /* Formfeed */
+
+#define SEP 1 /* Token types */
+#define LBRACK 2
+#define RBRACK 3
+#define WORD 4
+#define COMMA 5
+
+/* Storage sizes */
+
+#define MAXSTATES 50 /* max number of states */
+#define MAXWORD 50 /* max # of chars/word */
+#define SBYTES ((MAXSTATES+6)/8) /* # of bytes for state bitmask */
+
+/* Name of wart function in generated program */
+
+#ifndef FNAME
+#define FNAME "wart"
+#endif /* FNAME */
+
+/* Structure for state information */
+
+struct transx {
+ CHAR states[SBYTES]; /* included states */
+ int anyst; /* true if this good from any state */
+ CHAR inchr; /* input character */
+ int actno; /* associated action */
+ struct transx *nxt;
+}; /* next transition */
+typedef struct transx *trans;
+
+/* Function prototypes */
+
+_PROTOTYP( VOID setwstate, (int, trans) );
+_PROTOTYP( int teststate, (int, trans) );
+_PROTOTYP( trans rdinput, (FILE *, FILE *) );
+_PROTOTYP( VOID initial, (FILE *, FILE *) );
+_PROTOTYP( int isin, (char *, int) );
+_PROTOTYP( int isword, (int) );
+_PROTOTYP( VOID rdword, (FILE *, char *) );
+_PROTOTYP( VOID rdstates, (FILE *, FILE *) );
+_PROTOTYP( trans newtrans, (void) );
+_PROTOTYP( trans rdrules, (FILE *, FILE *) );
+_PROTOTYP( VOID statelist, (FILE *, trans) );
+_PROTOTYP( VOID copyact, (FILE *, FILE *, int) );
+_PROTOTYP( int faction, (trans, int, int) );
+_PROTOTYP( VOID emptytbl, (void) );
+_PROTOTYP( VOID addaction, (int, int, int) );
+_PROTOTYP( VOID writetbl, (FILE *) );
+_PROTOTYP( VOID warray, (FILE *, char *, int [], int, char *) );
+_PROTOTYP( VOID prolog, (FILE *) );
+_PROTOTYP( VOID epilogue, (FILE *) );
+_PROTOTYP( VOID copyrest, (FILE *, FILE *) );
+_PROTOTYP( int gettoken, (FILE *) );
+_PROTOTYP( VOID rdcmnt, (FILE *) );
+_PROTOTYP( VOID clrhash, (void) );
+_PROTOTYP( int hash, (char *) );
+_PROTOTYP( VOID enter, (char *, int) );
+_PROTOTYP( int lkup, (char *) );
+_PROTOTYP( static char* copy, (char *s) );
+
+/* Variables and tables */
+
+/* lt 1992-10-08 Begin
+ * provide definition for deblog variable
+ * ckcdeb.h declares as extern. DECC AXP is strict about ref/def model
+ * Variable is unused herein, to the best of my knowledge.
+ */
+#ifdef VMS
+int deblog;
+#endif /* VMS */
+/* lt 1992-10-08 End
+ */
+
+static int lines, nstates, nacts;
+
+static char tokval[MAXWORD];
+
+static int tbl[MAXSTATES*96];
+
+char *tbl_type = TBL_TYPE;
+
+char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\nint\n";
+
+char *fname = FNAME; /* Generated function name goes here */
+
+/* rest of program... */
+
+char *txt2 = "()\n\
+{\n\
+ int c,actno;\n\
+ extern ";
+
+/* Data type of state table is inserted here (short or int) */
+
+char *txt2a =
+" tbl[];\n\
+ while (1) {\n\
+ c = input() - 32;\n\
+ debug(F000,\"PROTO input\",ckitoa(state),c+32);\n\
+ if (c < 0 || c > 95) c = 0;\n";
+
+char *txt2b = " if ((actno = tbl[c + state*96]) != -1)\n\
+ switch(actno) {\n";
+
+/* this program's output goes here, followed by final text... */
+
+char *txt3 = "\n }\n }\n}\n\n";
+
+
+/*
+ * turn on the bit associated with the given state
+ *
+ */
+VOID
+setwstate(state,t) int state; trans t; {
+ int idx,msk;
+ idx = state/8; /* byte associated with state */
+ msk = 0x80 >> (state % 8); /* bit mask for state */
+ t->states[idx] |= msk;
+}
+
+/*
+ * see if the state is involved in the transition
+ *
+ */
+int
+teststate(state,t) int state; trans t; {
+ int idx,msk;
+ idx = state/8;
+ msk = 0x80 >> (state % 8);
+ return(t->states[idx] & msk);
+}
+
+
+/*
+ * read input from here...
+ *
+ */
+
+trans
+rdinput(infp,outfp) FILE *infp,*outfp; {
+ trans x;
+ lines = 1; /* line counter */
+ nstates = 0; /* no states */
+ nacts = 0; /* no actions yet */
+ fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/');
+ fprintf(outfp,"Wart preprocessor. */\n");
+ fprintf(outfp,"%c* Do not edit this file; edit the Wart-format ",'/');
+ fprintf(outfp,"source file instead, */\n");
+ fprintf(outfp,"%c* and then run it through Wart to produce a new ",'/');
+ fprintf(outfp,"C source file. */\n\n");
+ fprintf(outfp,"%c* Wart Version Info: */\n",'/');
+ fprintf(outfp,"char *wartv = \"%s\";\n\n",wartv);
+
+ initial(infp,outfp); /* read state names, initial defs */
+ prolog(outfp); /* write out our initial code */
+ x = rdrules(infp,outfp); /* read rules */
+ epilogue(outfp); /* write out epilogue code */
+ return(x);
+}
+
+
+/*
+ * initial - read initial definitions and state names. Returns
+ * on EOF or %%.
+ *
+ */
+VOID
+initial(infp,outfp) FILE *infp, *outfp; {
+ int c;
+ char wordbuf[MAXWORD];
+ while ((c = getc(infp)) != EOF) {
+ if (c == '%') {
+ rdword(infp,wordbuf);
+ if (strcmp(wordbuf,"states") == 0)
+ rdstates(infp,outfp);
+ else if (strcmp(wordbuf,"%") == 0) return;
+ else fprintf(outfp,"%%%s",wordbuf);
+ }
+ else putc(c,outfp);
+ if (c == '\n') lines++;
+ }
+}
+
+/*
+ * boolean function to tell if the given character can be part of
+ * a word.
+ *
+ */
+int
+isin(s,c) char *s; int c; {
+ for (; *s != '\0'; s++)
+ if (*s == (char) c) return(1);
+ return(0);
+}
+int
+isword(c) int c; {
+ static char special[] = ".%_-$@"; /* these are allowable */
+ return(isalnum(c) || isin(special,c));
+}
+
+/*
+ * read the next word into the given buffer.
+ *
+ */
+VOID
+rdword(fp,buf) FILE *fp; char *buf; {
+ int len = 0,c;
+ while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = (char) c;
+ *buf++ = '\0'; /* tie off word */
+ ungetc(c,fp); /* put break char back */
+}
+
+/*
+ * read state names, up to a newline.
+ *
+ */
+VOID
+rdstates(fp,ofp) FILE *fp,*ofp; {
+ int c;
+ char wordbuf[MAXWORD];
+ while ((c = getc(fp)) != EOF && c != '\n') {
+ if (isspace(c) || c == C_L) continue; /* skip whitespace */
+ ungetc(c,fp); /* put char back */
+ rdword(fp,wordbuf); /* read the whole word */
+ enter(wordbuf,++nstates); /* put into symbol tbl */
+ fprintf(ofp,"#define %s %d\n",wordbuf,nstates);
+ }
+ lines++;
+}
+
+/*
+ * allocate a new, empty transition node
+ *
+ */
+trans
+newtrans() {
+ trans new;
+ int i;
+ new = (trans) malloc(sizeof (struct transx));
+ for (i=0; i<SBYTES; i++) new->states[i] = 0;
+ new->anyst = 0;
+ new->nxt = NULL;
+ return(new);
+}
+
+
+/*
+ * read all the rules.
+ *
+ */
+
+trans
+rdrules(fp,out) FILE *fp,*out; {
+ trans head,cur,prev;
+ int curtok;
+ head = cur = prev = NULL;
+ while ((curtok = gettoken(fp)) != SEP)
+
+ switch(curtok) {
+ case LBRACK:
+ if (cur == NULL)
+ cur = newtrans();
+ else
+ fatal("duplicate state list");
+ statelist(fp,cur); /* set states */
+ continue; /* prepare to read char */
+
+ case WORD:
+ if ((int)strlen(tokval) != 1)
+ fatal("multiple chars in state");
+ if (cur == NULL) {
+ cur = newtrans();
+ cur->anyst = 1;
+ }
+ cur->actno = ++nacts;
+ cur->inchr = (char) (tokval[0] - 32);
+ if (head == NULL)
+ head = cur;
+ else
+ prev->nxt = cur;
+ prev = cur;
+ cur = NULL;
+ copyact(fp,out,nacts);
+ break;
+ default: fatal("bad input format");
+ }
+ return(head);
+}
+
+/*
+ * read a list of (comma-separated) states, set them in the
+ * given transition.
+ *
+ */
+VOID
+statelist(fp,t) FILE *fp; trans t; {
+ int curtok,sval;
+ curtok = COMMA;
+ while (curtok != RBRACK) {
+ if (curtok != COMMA) fatal("missing comma");
+ if ((curtok = gettoken(fp)) != WORD) fatal("missing state name");
+ if ((sval = lkup(tokval)) == -1) {
+ fprintf(stderr,"state %s undefined\n",tokval);
+ fatal("undefined state");
+ }
+ setwstate(sval,t);
+ curtok = gettoken(fp);
+ }
+}
+
+/*
+ * copy an action from the input to the output file
+ *
+ */
+VOID
+copyact(inp,outp,actno) FILE *inp,*outp; int actno; {
+ int c,bcnt;
+ fprintf(outp,"case %d:\n",actno);
+ while (c = getc(inp), (isspace(c) || c == C_L))
+ if (c == '\n') lines++;
+ if (c == '{') {
+ bcnt = 1;
+ fputs(" {",outp);
+ while (bcnt > 0 && (c = getc(inp)) != EOF) {
+ if (c == '{') bcnt++;
+ else if (c == '}') bcnt--;
+ else if (c == '\n') lines++;
+ putc(c,outp);
+ }
+ if (bcnt > 0) fatal("action doesn't end");
+ } else {
+ while (c != '\n' && c != EOF) {
+ putc(c,outp);
+ c = getc(inp);
+ }
+ lines++;
+ }
+ fprintf(outp,"\n break;\n");
+}
+
+/*
+ * find the action associated with a given character and state.
+ * returns -1 if one can't be found.
+ *
+ */
+int
+faction(hd,state,chr) trans hd; int state,chr; {
+ while (hd != NULL) {
+ if (hd->anyst || teststate(state,hd))
+ if (hd->inchr == ('.' - 32) || hd->inchr == (char) chr)
+ return(hd->actno);
+ hd = hd->nxt;
+ }
+ return(-1);
+}
+
+/*
+ * empty the table...
+ *
+ */
+VOID
+emptytbl() {
+ int i;
+ for (i=0; i<nstates*96; i++) tbl[i] = -1;
+}
+
+/*
+ * add the specified action to the output for the given state and chr.
+ *
+ */
+VOID
+addaction(act,state,chr) int act,state,chr; {
+ tbl[state*96 + chr] = act;
+}
+
+VOID
+writetbl(fp) FILE *fp; {
+ warray(fp,"tbl",tbl,96*(nstates+1),TBL_TYPE);
+}
+
+
+/*
+ * write an array to the output file, given its name and size.
+ *
+ */
+VOID
+warray(fp,nam,cont,siz,typ) FILE *fp; char *nam; int cont[],siz; char *typ; {
+ int i;
+ fprintf(fp,"%s %s[] = {\n",typ,nam);
+ for (i = 0; i < siz - 1; ) {
+ fprintf(fp," %2d,",cont[i]);
+ if ((++i % 16) == 0) putc('\n',fp);
+ }
+ fprintf(fp,"%2d\n};\n",cont[siz-1]);
+}
+
+#ifndef STRATUS
+#ifdef MAINTYPE
+/*
+ If you get complaints about "main: return type is not blah",
+ define MAINTYPE on the CC command line, e.g. "CFLAGS=-DMAINTYPE=int".
+*/
+MAINTYPE
+#else
+#ifdef CK_SCOV5
+int
+#else
+#ifdef __DECC
+#ifdef __ALPHA
+int
+#else
+VOID
+#endif /* __ALPHA */
+#else
+#ifdef STRATUS
+int
+#ifdef __GNUC__
+int
+#else
+/*
+ The default case should be int, not VOID, but it's been this way for
+ years (no doubt for a reason) and who knows how many builds would break
+ if I changed it.
+*/
+VOID
+#endif /* __GNUC__ */
+#endif /* STRATUS */
+#endif /* __DECC */
+#endif /* CK_SCOV5 */
+#endif /* MAINTYPE */
+#endif /* STRATUS */
+main(argc,argv) int argc; char **argv; {
+ trans head;
+ int state,c;
+ FILE *infile,*outfile;
+
+ if (argc > 1) {
+ if ((infile = fopen(argv[1],"r")) == NULL) {
+ fprintf(stderr,"Can't open %s\n",argv[1]);
+ fatal("unreadable input file");
+ }
+ } else infile = stdin;
+
+ if (argc > 2) {
+ if ((outfile = fopen(argv[2],"w")) == NULL) {
+ fprintf(stderr,"Can't write to %s\n",argv[2]);
+ fatal("bad output file");
+ }
+ } else outfile = stdout;
+
+ clrhash(); /* empty hash table */
+ head = rdinput(infile,outfile); /* read input file */
+ emptytbl(); /* empty our tables */
+ for (state = 0; state <= nstates; state++)
+ for (c = 1; c < 96; c++) /* find actions, */
+ addaction(faction(head,state,c),state,c); /* add to tbl */
+ writetbl(outfile);
+ copyrest(infile,outfile);
+ printf("%d states, %d actions\n",nstates,nacts);
+ exit(GOOD_EXIT);
+}
+
+
+/*
+ * fatal error handler
+ *
+ */
+
+VOID
+fatal(msg) char *msg; {
+ fprintf(stderr,"error in line %d: %s\n",lines,msg);
+ exit(BAD_EXIT);
+}
+
+VOID
+prolog(outfp) FILE *outfp; {
+ int c;
+ while ((c = *txt1++) != '\0') putc(c,outfp);
+ while ((c = *fname++) != '\0') putc(c,outfp);
+ while ((c = *txt2++) != '\0') putc(c,outfp);
+ while ((c = *tbl_type++) != '\0') putc(c,outfp);
+ while ((c = *txt2a++) != '\0') putc(c,outfp);
+ while ((c = *txt2b++) != '\0') putc(c,outfp);
+}
+
+VOID
+epilogue(outfp) FILE *outfp; {
+ int c;
+ while ((c = *txt3++) != '\0') putc(c,outfp);
+}
+
+VOID
+copyrest(in,out) FILE *in,*out; {
+ int c;
+ while ((c = getc(in)) != EOF) putc(c,out);
+}
+
+/*
+ * gettoken - returns token type of next token, sets tokval
+ * to the string value of the token if appropriate.
+ *
+ */
+
+int
+gettoken(fp) FILE *fp; {
+ int c;
+ while (1) { /* loop if reading comments... */
+ do {
+ c = getc(fp);
+ if (c == '\n') lines++;
+ } while ((isspace(c) || c == C_L)); /* skip whitespace */
+ switch(c) {
+ case EOF:
+ return(SEP);
+ case '%':
+ if ((c = getc(fp)) == '%') return(SEP);
+ tokval[0] = '%';
+ tokval[1] = (char) c;
+ rdword(fp,tokval+2);
+ return(WORD);
+ case '<':
+ return(LBRACK);
+ case '>':
+ return(RBRACK);
+ case ',':
+ return(COMMA);
+ case '/':
+ if ((c = getc(fp)) == '*') {
+ rdcmnt(fp); /* skip over the comment */
+ continue;
+ } else { /* and keep looping */
+ ungetc(c,fp); /* put this back into input */
+ c = '/'; /* put character back, fall thru */
+ }
+
+ default:
+ if (isword(c)) {
+ ungetc(c,fp);
+ rdword(fp,tokval);
+ return(WORD);
+ } else fatal("Invalid character in input");
+ }
+ }
+}
+
+/*
+ * skip over a comment
+ *
+ */
+
+VOID
+rdcmnt(fp) FILE *fp; {
+ int c,star,prcnt;
+ prcnt = star = 0; /* no star seen yet */
+ while (!((c = getc(fp)) == '/' && star)) {
+ if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment");
+ prcnt = (c == '%');
+ star = (c == '*');
+ if (c == '\n') lines++;
+ }
+}
+
+/*
+ * symbol table management for wart
+ *
+ * entry points:
+ * clrhash - empty hash table.
+ * enter - enter a name into the symbol table
+ * lkup - find a name's value in the symbol table.
+ *
+ */
+
+#define HASHSIZE 101 /* # of entries in hash table */
+
+struct sym {
+ char *name; /* symbol name */
+ int val; /* value */
+ struct sym *hnxt; /* next on collision chain */
+} *htab[HASHSIZE]; /* the hash table */
+
+/*
+ * empty the hash table before using it...
+ *
+ */
+VOID
+clrhash() {
+ int i;
+ for (i=0; i<HASHSIZE; i++) htab[i] = NULL;
+}
+
+/*
+ * compute the value of the hash for a symbol
+ *
+ */
+int
+hash(name) char *name; {
+ int sum;
+ for (sum = 0; *name != '\0'; name++) sum += (sum + *name);
+ sum %= HASHSIZE; /* take sum mod hashsize */
+ if (sum < 0) sum += HASHSIZE; /* disallow negative hash value */
+ return(sum);
+}
+
+/*
+ * make a private copy of a string...
+ *
+ */
+static char*
+copy(s) char *s; {
+ char *new;
+ new = (char *) malloc((int)strlen(s) + 1);
+ strcpy(new,s);
+ return(new);
+}
+
+/*
+ * enter state name into the hash table
+ *
+ */
+VOID
+enter(name,svalue) char *name; int svalue; {
+ int h;
+ struct sym *cur;
+ if (lkup(name) != -1) {
+ fprintf(stderr,"state \"%s\" appears twice...\n", name);
+ exit(BAD_EXIT);
+ }
+ h = hash(name);
+ cur = (struct sym *)malloc(sizeof (struct sym));
+ cur->name = copy(name);
+ cur->val = svalue;
+ cur->hnxt = htab[h];
+ htab[h] = cur;
+}
+
+/*
+ * find name in the symbol table, return its value. Returns -1
+ * if not found.
+ *
+ */
+int
+lkup(name) char *name; {
+ struct sym *cur;
+ for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt)
+ if (strcmp(cur->name,name) == 0) return(cur->val);
+ return(-1);
+}
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/makefile b/ckermit-9.0.302-build/ckermit-9.0.302/makefile
new file mode 100644
index 0000000..9efe262
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/makefile
@@ -0,0 +1,8626 @@
+# makefile / Makefile / ckuker.mak / CKUKER.MAK
+#
+# Sun Aug 21 10:33:08 2011
+BUILDID=20110821
+CKVER= "9.0.302"
+#
+# -- Makefile to build C-Kermit for UNIX and UNIX-like platforms --
+#
+# Copyright (C) 1985, 2011,
+# Trustees of Columbia University in the City of New York.
+# All rights reserved. See the C-Kermit COPYING.TXT file or the
+# copyright text in the ckcmai.c module for disclaimer and permissions.
+# In case you can't find the COPYING.TXT file, it contains the
+# Simplified 3-Clause BSD License, which is an Open Source license.
+#
+# Author: Frank da Cruz, Columbia University
+# 612 West 115th Street, New York NY 10025-7799, USA
+# Email: fdc@columbia.edu
+# Web: http://kermit.columbia.edu/
+# FTP: ftp://kermit.columbia.edu/kermit/
+#
+# Note: Author is no longer at Columbia University or at the 115th Street
+# address effective 1 July 2011. The email address should still work,
+# as well as the website and FTP addresses, for the foreseeable future.
+# For new developments, also check:
+#
+# http://www.columbia.edu/~fdc/kermit/
+#
+# Contributions from many others. Special thanks to Jeff Altman for the
+# secure-build targets, Peter Eichhorn, assyst GmbH, for the consolidated
+# HP-UX targets and the "uninstall" target, to Robert Lipe for the updated
+# and consolidated SCO UNIX / ODT / OSR5 targets, to Ric Anderson for the
+# IRIX 6.x targets, to Seth Theriault for major improvements to the
+# Mac OS X targets, and to Alexey Dokuchaev for FreeBSD 9.0.
+#
+# C-Kermit is written and produced by hand without any automated procedures
+# such as autoconf / automake / configure, although some of the targets below
+# (especially the linux target) inspect the environment and make some
+# decisions in the most portable way possible. The automated tools are not
+# used because (a) C-Kermit predates them, and (b) they are not portable to
+# all the platforms where C-Kermit must be (or once was) built, and (c) to
+# keep C-Kermit as independent as possible from external tools over which
+# we have no control.
+#
+# Most entries use the "xermit" target, which uses the select()-based CONNECT
+# module, ckucns.c. The "wermit" target uses the original fork()-based CONNECT
+# module, ckucon.c, which has some drawbacks but was portable to every Unix
+# variant whether it had TCP/IP or not (select() is part of the TCP/IP
+# library, which was not standard on older Unixes). If your target still uses
+# the "wermit" target, please try substituting the "xermit" one and if it
+# works, let us know (mailto:kermit-support@columbia.edu). When changing a
+# target over from wermit to xermit, also remove -DNOLOEARN.
+#
+# CAREFUL: Don't put the lowercase word "if", "define", or "end" as the first
+# word after the "#" comment introducer in the makefile, even if it is
+# separated by whitespace. Some versions of "make" understand these as
+# directives. Uppercase letters remove the danger, e.g. "# If you have..."
+#
+# WARNING: This is a huge makefile. Although this is less likely since the
+# turn of the century, some "make" programs might run out of memory. If this
+# happens to you, edit away the parts that do not apply to your platform and
+# try again.
+#
+# WARNING 2: In many cases this file invokes itself recursively, sometimes
+# several levels deep (as in the Linux targets); i.e. some targets are used
+# as 'subroutines' of other targets, with parameters passed by setting
+# environment variables. For that reason, don't use 'make -e'.
+#
+# Certain UNIX variations have their own separate makefiles:
+# . For 2.10 or 2.11 BSD on the DEC PDP-11, use ckubs2.mak.
+# . For Plan 9, use ckpker.mk.
+#
+# Separate build procedures are provided non-UNIX platforms: VMS, VOS,
+# AOS/VS, etc. See the ckaaaa.txt file or the Kermit website for details.
+#
+#
+# DIRECTIONS FOR UNIX
+#
+# Rename this file to "makefile" or "Makefile" if necessary. Pick out the
+# entry most appropriate for your UNIX version from the list below and then
+# give the appropriate "make" command, for example "make aix", "make macosx",
+# "make linux". If you experience any difficulties with the build procedure,
+# then please also read any comments that accompany the make entry itself
+# (search for the make entry name on the left margin).
+#
+# Other targets:
+# 'make install' is an installation script (read accompanying comments!).
+# 'make uninstall' undoes 'make install' (read accompanying comments!).
+# 'make clean' removes intermediate and object files.
+# 'make show' tells the default include and lib paths for secure builds.
+#
+# IMPORTANT:
+# For more detailed installation instructions, read the files ckuins.txt
+# and ckccfg.txt, also available at the Kermit website in HTML form:
+# http://www.columbia.edu/kermit/ckuins.html
+# http://www.columbia.edu/kermit/ckccfg.html
+#
+# For descriptions of known problems and limitations,
+# read the files ckcbwr.txt and ckubwr.txt (the "beware files") or:
+# http://www.columbia.edu/kermit/ckcbwr.html
+# http://www.columbia.edu/kermit/ckubwr.html
+#
+# Most targets build C-Kermit with its symbol table included. To reduce the
+# size of the executable program, add "LNKFLAGS=-s" to the end of your 'make'
+# command or to the makefile entry, or 'strip' the executable after
+# building. To further reduce the size after building, use 'mcs -d' if your
+# Unix version has such a command. For further details on size reduction, read
+# ckccfg.txt to find out how to remove features that you don't need.
+#
+# TCP/IP networking support: If your C-Kermit version does not include TCP/IP
+# networking, but your UNIX system does, try adding -DTCPSOCKET to the CFLAGS
+# of your makefile entry. If that doesn't work, look at some of the other
+# targets that include this flag for ideas about what libraries might need to
+# be included (typically -lsocket and/or -lBSD and/or -lnsl and/or -linet).
+# NOTE: In some cases (old versions of SCO or HP-UX), you might need not only
+# a C compiler, but also a "TCP/IP developers kit" for the required object
+# libraries and header files.
+#
+# Please report modifications, failures (preferably with fixes) or successes
+# to the author, fdc@columbia.edu.
+#
+# TARGETS FOR DIFFERENT UNIX PLATFORMS AND VERSIONS:
+#
+# + Marks those that have been built successfully for C-Kermit 9.0 or later.
+# - Those that once built OK but no longer do (e.g. too big).
+# ? Those that worked in a previous version but have not been tested recently.
+# --------------------------
+# Some commonly used targets:
+#
+# + "make linux" should work for any version of Linux on any hardware.
+# + "make linux+ssl" ditto, with OpenSSL security added.
+# + "make linux+krb5" ditto, with Kerberos 5 security added.
+# + "make linux+krb5+ssl" Linux with OpenSSL and Kerberos 5.
+# + "make netbsd", NetBSD, any version.
+# + "make netbsd+ssl", NetBSD with OpenSSL 0.9.7 or later.
+# + "make netbsd+krb5", NetBSD with Kerberos 5.
+# + "make netbsd+krb5+ssl", NetBSD with Kerberos 5 and OpenSSL 0.9.7 or later.
+# ? "make freebsd1" for FreeBSD 1.x
+# ? "make freebsd2" for FreeBSD 2.x
+# + "make freebsd3" for FreeBSD 3.x
+# ? "make freebsd4" for FreeBSD 4.0
+# + "make freebsd", FreeBSD 4.1 or later.
+# + "make freebsd+ssl", FreeBSD 5.0 or later with OpenSSL 0.9.7 or later.
+# + "make openbsd", OpenBSD 2.3 or later.
+# + "make openbsd+ssl", OpenBSD 2.3 or later with OpenSSL 0.9.7 or later.
+# + "make mirbsd", MirBSD.
+# + "make mirbsd+ssl", MirBSD with OpenSSL 0.9.7 or later.
+# + "make macosx" should work for any Mac OS X version 10.3.9 or later.
+# + "make macosx+krb5+openssl" Mac OS X 10.3.9 or later + Kerberos V + OpenSSL.
+# + "make aix" should work for any version of AIX 4.2 or later.
+# + "make aixg" should work for any version of AIX 4.2 or later, using gcc.
+# + "make aix+ssl" ditto, with OpenSSL (specifying SSLLIB and SSLINC)
+# + "make aix+ibmssl" ditto, with IBM OpenSSL
+# + "make solaris9", "make solaris10" for Solaris 9 or 10 with Sun cc.
+# + "make solaris9g", "make solaris10g" for Solaris 9 or 10 with gcc.
+# + "make solaris11" for Solaris 11 with Sun CC
+# + "make solaris11g" for Solaris 11 with gcc
+# + "make sco_osr600" for SCO OpenServer 6.0.0.
+#
+# For other current OSs such as Solaris, HP-UX, and SCO there are separate
+# targets for different combinations of OS version and compiler; see the
+# complete list. For older OS's see the complete list. If an old target
+# doesn't work in this release of C-Kermit you can get a previous release from
+# the Kermit FTP site: ftp://kermit.columbia.edu/kermit/
+#
+# SECURE TARGETS (versions that support authentication and encryption)
+# are described after the following list. Search for ******* below.
+#
+# --------------------------
+# Complete list (alphabetical):
+# ? for 386BSD (Jolix) 0.0, 0.1, "make 386bsd" (see comments in entry),
+# or (preferably, if it works) "make bsd44" or "make bsd44c".
+# ? for Acorn RISCiX, "make riscix" or "make riscix-gcc"
+# ? for Alliant FX/8 with Concentrix 4.1 or later, "make bsdlck"
+# ? for Altos 486, 586, 986 with Xenix 3.0, "make altos"
+# ? for Altos ACS68000, 8Mhz 68000, UNIX System 3 Rel 2, 512K, "make altos3"
+# ? for Amdahl UTS 2.4 on IBM 370 series & compatible mainframes, "make uts24"
+# ? for Amdahl UTSV IBM 370 series & compatible mainframes, "make utsv"
+# ? for Amdahl UTSV IBM 370 series mainframes with TCP/IP, "make utsvtcp"
+# ? for Amdahl mainframes with UNIX System V R 5.2.6b 580, "make sys3"
+# ? for Apollo Aegis 9.x, DOMAIN/IX 9.x, "make aegis"
+# (Last tested in C-Kermit 5A(189))
+# ? for Apollo DOMAIN/IX, if the above fails, try "make apollobsd"
+# ? for Apollo with SR10.0 or later, BSD environment, "make sr10-bsd"
+# ? for Apollo with SR10.0 or later, System V environment, "make sr10-s5r3"
+# ? for Apple Macintosh II with A/UX pre-3.0, "make aux", "auxgcc" or "auxufs"
+# ? for Apple Macintosh with A/UX 3.0 and gcc, "make aux3gcc" or aux3gccc
+# ? for Apple PowerMac with MkLinux, "make mklinux" (read Linux entry first)
+# ? for Apple PowerMac with LinuxPPC, "make linuxppc"
+# ? for Apple Macintosh with Minix 1.5.10, "make minix68k" or "make minixc68"
+# ? for Apple Macintosh with Mac OS X 1.0 (Rhapsody), "make macosx10"
+# (no curses), "make macosx10c" (curses), or "make macosx10nc" (ncurses).
+# Or "make macosx10ncx" (ncurses but "make macosx10nc" doesn't work).
+# ? for Apple Macintosh with Mac OS X 10.2, "make macosx102nc" (ncurses).
+# ? for Apple Macintosh with Mac OS X 10.3, "make macosx103"
+# ? for Apple Macintosh with Mac OS X 10.3.9 or later, "make macosx"
+# ? for Arix System 90 with AT&T SVR3, "make sys5r3na"
+# - for AT&T 6300 with IN/ix, "make sys5"
+# - for AT&T 6300 PLUS, "make att6300" or (with no debugging) "make att6300nd"
+# ? for AT&T 6386 WGS UNIX PC, "make sys5r3"
+# ? for AT&T 3B2, 3B20 systems, "make att3b2".
+# for AT&T 3B1, 7300 UNIX PC (see notes with the entries):
+# In C-Kermit 7.0, only the gcc entries work:
+# ? "make sys3upcg", "make sys3upcgc", "make att351gm"
+# The others fail with "too many defines" (usually in ckuusr.h):
+# - "make sys3upc", "make sys3upcold", "make sys3upcc", "make sys3upcx",
+# "make sys3upcm", "make att351m"
+# ? for AT&T System III/System V R2 or earlier, "make sys3" or "make sys3nid"
+# ? for AT&T System III/System V with Honey DanBer UUCP, "make sys3hdb"
+# ? for AT&T System V on DEC VAX, "make sys3" or "make sys5r3"
+# ? for AT&T System V R3, use "make sys5r3" or "make sys5r3c"
+# ? for AT&T System V/386 R3.2 built on Interactive 4.1.1, "make sys5r32is".
+# ? for AT&T System V/386 R320.0 Versyss Systems, use "make sys5r3"
+# or "make sys5r3c".
+# ? for AT&T System V R4, "make sys5r4", "make sys5r4sx", or "make sys5r4nx",
+# or if the ANSI C function prototyping makes trouble, add -DNOANSI,
+# as in "sys5r4sxna" entry
+# ? for AT&T (USL) System V R4.2 use the sys5r4* entries.
+# ? for Atari Falcon with MiNT, "make posix"
+# ? for Atari ST with Minix ST 1.5.10.3, "make minix68k" or "make minixc68"
+# ? for BBN C/70 with IOS 2.0, "make c70"
+# ? for BeBox with Be OS 1.x DR7, "make beboxdr7"
+# Compiles OK but doesn't link with default linker which is limited to 64K.
+# Links OK with "Code Warrior Gold". Many hacks in the source code need
+# to be removed when DR8 and later come out.
+# (Last tested in C-Kermit 6.0)
+# - for BeBox with Be OS 1.x DR8, "make bebox"
+# (Needed functions missing from operating system and/or not working.)
+# - for Bell Labs UNIX Version 6 (6th Edition), there is no makefile entry.
+# ? for Bell Labs UNIX Version 7 (7th Edition), "make v7" (but see notes below)
+# (last built successfully in C-Kermit 5A188)
+# ? for Bell Labs Research UNIX Version 10, "make bellv10"
+# (last built successfully in C-Kermit 6.0)
+# ? for Bell Labs / Lucent Plan 9, use separate makefile ckpker.mk:
+# can be built for Intel, MIPS, 680x0, and PowerPC (last built C-Kermit 7.0)
+# ? for BSDI BSD/386 1.x, "make bsdi"
+# ? for BSDI BSD/OS 2.x, "make bsdi2"
+# ? for BSDI BSD/OS 3.0 or 3.1, "make bsdi3"
+# ? for BSDI BSD/OS 4.x, "make bsdi4"
+# ? for BSDI BSD/OS 4.x, to build a binary that also works on FreeBSD,
+# "make bsdix".
+# ? for Berkeley Unix 2.4, "make v7" (but read v7 material below)
+# ? for Berkeley Unix 2.9 (DEC PDP-11 or Pro-3xx), "make bsd29"
+# - for Berkeley Unix 2.10, use ckubs2.mak (a separate makefile)
+# - for Berkeley Unix 2.11, use ckubs2.mak (a separate makefile)
+# This makefile is too big. Read the instructions in ckubs2.mak.
+# "make -f ckubs2.mak bsd210" or "make -f ckubs2.mak bsd211".
+# (last built successfully in C-Kermit 6.0 - later versions too big)
+# ? for Berkeley Unix 2.11 "make -f ckubs2.mak bsd210noicp" (no command parser)
+# ? for Berkeley Unix 4.1, "make bsd41"
+# ? for Berkeley Unix 4.2 on VAX, "make bsd42" or "make bsd42c"
+# ? for Berkeley Unix 4.2 or 4.3 with HoneyDanBer UUCP, "make bsdhdb"
+# ? for Berkeley Unix 4.3 on VAX, "make bsd43", "make bsd43nc".
+# ? for Berkeley Unix 4.3 on VAX, no networking "make bsd43nonet.
+# ? for Berkeley Unix 4.3 without acucntrl program, "make bsd42" or "bsd42c"
+# NOTE: all the C-Kermit 7.0 full builds for old BSDs fail with
+# "too many defines" in CPP, even on big architectures like VAX. This
+# can be worked around with a clever ruse. See comments at target.
+# ? for Berkeley Unix 4.3, command-line only, "make bsdm".
+# ? for Berkeley Unix 4.3-Tahoe, same as 4.3 BSD
+# ? for Berkeley Unix 4.3-Reno, "make bsd43" or "make bsd44" or "make bsd44c"
+# ? for Berkeley Unix 4.3-Carson City, "make bsd44" or "make bsd44c"
+# ? for Berkeley Unix 4.4-Networking/2 or -Alpha, "make bsd44" or "make bsd44c"
+# ? for Berkeley Unix 4.4, "make bsd44" or "make bsd44c"
+# ? for Berkeley Unix 4.4-Lite, "make bsd44" or "make bsd44c"
+# ? for Bull DPX/2 with BOS/X, "make bulldpx2"
+# ? for Cadmus, "make sys3"
+# for Caldera, see SCO, Linux.
+# ? for Callan Unistar, "make sys3"
+# ? for CDC VX/VE 5.2.1 System V emulation, "make vxve"
+# ? for Charles River Data Systems Universe 680x0 with UNOS 9.2, maybe
+# also other UNOS versions, "make crds"
+# ? for CIE Systems 680/20 with Regulus, "make cie"
+# ? for Commodore Amiga 3000UX Sys V R4, "make sys5r4sx"
+# ? for Commodore Amiga 3000UX Sys V R4 and TCP/IP, "make svr4amiganet"
+# ? for Commodore Amiga with Minix 1.5.10, "make minix68k" of "make minixc68"
+# ? for Concurrent/Masscomp with RTU 4.0 or later, BSD environment, "make
+# rtubsd", "make rtubsd2", "make rtubsd3" (depending on where ndir.h
+# is stored, see entries below).
+# ? for Concurrent/Masscomp with RTU 4.0 or later, System V R2, "make rtus5"
+# ? for Concurrent (Perkin-Elmer) 3200 series, "make sys5".
+# ? for Concurrent (Perkin-Elmer) 3200 series with <dirent.h>, "make ccop1"
+# ? for Concurrent PowerMAX OS SVR4, "make powermax"
+# ? for Consensys UNIX SV/386 R4V3, "make sys5r4sxtcpc" or "make sys5r4sx"
+# ? for Convergent with CTIX Sys V R2, "make sys5"
+# ? for Convergent with CTIX 6.4.1, "make ctix"
+# ? for Convex C1, "make convex"
+# ? for Convex C210 with Convex/OS 8, "make convex8"
+# ? for Convex C2 with Convex/OS 9.1, "make convex9"
+# ? for Convex C2 with Convex/OS 10.1 and gcc 2.x, "make convex10gcc"
+# ? for Cray Research X/MP or YMP or C90 with UNICOS 6.x (System V R3),
+# "make cray"
+# ? for Cray Research X/MP or YMP or C90 with UNICOS 7.x (System V R4),
+# "make cray"
+# ? for Cray Research X/MP or YMP or C90 with UNICOS 8.0 Alpha, "make cray8"
+# ? for Cray Research X/MP or Y-MP or C90 with UNICOS 9.0, "make cray9"
+# ? for Cray Computer Cray-2 or Cray3 with CSOS, "make craycsos"
+# ? for Cyber 910 (Silicon-Graphics Iris) with Irix 3.3, "irix33"
+# ? for Data General AViiON with DG/UX 5.4 before R3.00, "make dgux540"
+# or "make dgux540c" (compile ckwart separately if necessary)
+# ? for DG/UX 5.4 on AViiON Intel models, "make dgux540i" or dgux540ic.
+# ? for DG/UX 5.4R4.11 on AViiON, all models, "make dgux54411"
+# ? for DG/UX 5.4R4.20 on AViiON, all models, "make dgux54420"
+# ? for Data General AViiON with DG/UX 4.3x using Sys V-isms, "make dgux430"
+# ? for Data General AViiON with DG/UX 4.3x using BSD-isms, "make dgux430bsd"
+# ? for Data General AViiON, earlier UNIX versions,
+# "make sys5r3" (maybe compile ckwart separately, or "touch ckcpro.c")
+# ? for Data General MV systems with DG/UX, ???
+# ? for Data General MV systems with MV/UX, use AOS/VS C-Kermit (CKDKER.MAK)
+# ? for Data General MV systems with AOS/VS, use CKDKER.MAK (last = C-K 7.0)
+# ? for DEC PDP-11 with Berkeley UNIX 2.x, see Berkeley UNIX 2.x.
+# ? for DEC PDP-11 with Mini-UNIX (Bell 6th Edition for PDP-11 with no MMU),
+# probably no way to fit C-Kermit without I&D space.
+# ? for DEC PDP-11 with Ultrix-11 3.x, ??? (probably needs overlays)
+# ? for DEC VAX with Ultrix 1.x "make bsd"
+# ? for DEC VAX with Ultrix 2.x "make ultrix2x"
+# ? for DEC VAX or DECstation with Ultrix 3.0, 3.1, "make ultrix3x"
+# ? for DECstation or VAX with Ultrix 4.0 or 4.1, "make ultrix40"
+# ? for DECstation or VAX with Ultrix 4.2, "make ultrix42" or "make ultrix42c"
+# ? for DECstation or VAX with Ultrix 4.x, POSIX world, "make posix"
+# ? for DECstation or VAX with Ultrix 4.3, "make ultrix43".
+# ? for DECstation or VAX with Ultrix 4.4, "make ultrix44".
+# ? for DECstation 5000/50, /150 or /260 (R4x00 MIPS CPU), Ultrix 4.3A or later
+# "make ultrix43-mips3" or "make ultrix43c-mips3"
+# ? for DECstation (MIPS) with Berkeley Sprite, "make bsd44"?
+# ? for DECstation (MIPS) with OSF/1 V1.0 to 1.3, "make dec-osf"
+# ? for DEC Alpha with OSF/1 1.0 to 1.3, "make dec-osf"
+# ? for DEC PC 486 with OSF/1, "make dec-osf"
+# ? for DEC Alpha with OSF/1 2.x, "make dec-osf20"
+# ? for DEC Alpha with OSF/1 3.0, "make dec-osf30"
+# ? for DEC Alpha with Digital UNIX 3.2, "make du32"
+# ? for DEC Alpha with Digital UNIX 4.0-4.0D, "make du40" or "make du40gcc"
+# ? for DEC Alpha with Digital UNIX 4.0E or higher, see Tru64.
+# + for DEC Alpha with any version of DU or OSF/1, "make dec-osf1"
+# - for DEC Pro-350 with Pro/Venix V1.x, "make provx1" (version 5A is too big)
+# ? for DEC Pro-380 with Pro/Venix V2.0 (Sys V), "make sys3" or "make sys3nid"
+# ? for DEC Pro-380 with 2.9, 2.10, or 2.11 BSD, "make bsd29" or "make bsd210"
+# for DEC PDP-11 with 2.xBSD (use separate makefile ckubs2.mak)
+# ? for Dell UNIX Issue 2.x (= USL Sys V/386 R4.x + fixes), "make dellsys5r4"
+# or "make dellsys5r4c" (last tested in C-Kermit 5A).
+# ? for DIAB DS90 with DNIX (any version) create an empty <sys/file.h> if
+# this file does not already exist (or add -DNOFILEH to the make entry).
+# ? for DIAB DS90 with DNIX 5.2 (Sys V.2) or earlier, "make dnix",
+# "make dnixnd", or (to add curses and TCP/IP) "make dnixnetc",
+# ? for DIAB DS90 with DNIX 5.3 (Sys V.3), "make dnix5r3"
+# ? for DIAB DS90 with DNIX 5.3 (Sys V.3) and TCP/IP, "make dnix5r3net"
+# ? for DIAB DS90 with DNIX 5.3 2.2 (Sys V.3), ANSI C, "make dnix5r3ansi"
+# or, to include TCP/IP, "make dnix5r3ansinet",
+# but you have to fix a bug in /usr/include/stdlib.h first:
+# change "extern void free(char *str);" to "extern void free(void *str);"
+# ? for Dolphin Server Technology Triton 88/17 with SV/88 R3.2, "make sv88r32"
+# ? for Encore Multimax 310, 510 with Umax 4.2, "make umax42"
+# ? for Encore Multimax 310, 510 with Umax 4.3, "make umax43"
+# ? for Encore Multimax 310, 510 with Umax V 2.2, use Berkeley cc, "make bsd"
+# ? for Encore 88K with Umax V 5.2, "make encore88k"
+# ? for ESIX System V R4.0.3 or 4.04 with TCP/IP support, "make esixr4"
+# NOTE: You can also build on Unixware 2.x with "make esixr4", and run
+# on ESIX, but there you must first:
+# ln /usr/lib/libsocket.so /usr/lib/libsocket.so.1
+# ln /usr/lib/libnsl.so /usr/lib/libnsl.so.1
+# (This worked for C-Kermit 6.0 but does not work for 7.0)
+# (But you can probably still build a non-networking version this way)
+# ? for Everex STEP 386/25 Rev G with ESIX Sys V R3.2D, "make sys5r3"
+# ? for Fortune 32:16, For:Pro 1.8, "make ft18"
+# ? for Fortune 32:16, For:Pro 2.1, "make ft21"
+# ? for FPS 500 with FPX 4.1, "made bsd"
+# ? for FreeBSD 1.0, "make freebsd1"
+# ? for FreeBSD 2.x, "make freebsd2" (ncurses) or "make freebsd2c" (curses)
+# ? for FreeBSD 3.x, "make freebsd3" (ncurses) or "make freebsd3c" (curses)
+# ? for FreeBSD 4.0, "make freebsd40"
+# ? for FreeBSD 4.1 or later, "make freebsd"
+# + NOTE: Just use "make freebsd" for any reasonably recent FreeBSD version.
+# ? for Harris HCX-2900, "make sys5r3"
+# ? for Harris Night Hawk 88K or 68K with CX/UX pre-6.1, "make sys5r3"
+# ? for Harris Night Hawk 88K or 68K with CX/UX 6.1 or later, "make cx_ux"
+# ? for Heurikon, "make sys3"
+# ? for HP-3000, MPE/ix, "make posix"?
+# ? for HP-9000 Series 300 with 4.4BSD, "make bsd44"
+
+# NOTE: Most of the HP-UX targets were tested successfully in 2010.
+# Verification needed for C-Kermit 9.0 Beta.01...
+
+# ? for HP-9000 Series 500, HP-UX 5.21 and no networking "make hpux0500"
+# ? for HP-9000 Series 500, HP-UX 5.21 with WIN/TCP 1.2 "make hpux0500wintcp"
+# ? for HP-9000 Series, HP-UX 6.5, without long filenames,
+# "make hpux0650", "make hpux0650c" or "make hpux0650tcpc"
+# ? for HP-9000 Series, HP-UX 7.0 or later no long filenames, "make hpux0700sf"
+# or (to include tcp/ip, curses, etc) "make hpux0700sftcpc"
+# ? for HP-9000 Series with HP-UX 7.0, TCP/IP,long filenames,"make hpux0700lfn"
+# ? for HP-9000 300/400 Series (680x0) with HP-UX 8.0, TCP/IP, "make hpux0800"
+# or "make hpux0800c"
+# ? for HP-9000 700/800 Series (PA-RISC), HP-UX 8.0, TCP/IP, "make hpux0800pa"
+# or "make hpux0800pac"
+# ? for HP-9000 Series with HP-UX 8.0, no TCP/IP, long filenames,
+# "make hpux0800notcp"
+# ? for HP-9000 Series, HP-UX 9.0 - 9.10, TCP/IP, curses, restricted compiler
+# (no optimization, no ANSI), all models, "make hpux0900". Read the
+# hpux0900 entry below for more info.
+# ? for HP-9000 700 and 800 Series, HP-UX 9.x, TCP/IP, curses,
+# HP optimizing ANSI C compiler, "make hpux0900o700".
+# ? for HP-9000 with Motorola CPUs, HP-UX 9.x, TCP/IP, curses,
+# HP optimizing ANSI C compiler, "make hpux0900mot".
+# ? for HP-9000 on other CPUs, HP-UX 9.x, TCP/IP, curses,
+# HP optimizing ANSI C compiler, "make hpux0900o".
+# ? for HP-9000 series, HP-UX 9.x, TCP/IP, curses, gcc, all models,
+# "make hpux0900gcc"
+# ? for HP-9000 700/800 Series, HP-UX 10.00,10.01,10.10,10.20,10.30, TCP/IP,
+# curses, restricted compiler (no optimization, no ANSI) "make hpux1000".
+# ? for HP-9000 700/800 Series, HP-UX 10.00,10.01,10.10,10.20,10.30, TCP/IP,
+# curses, HP ANSI/optimizing compiler "make hpux1000o" or "make hpux1000o+"
+# ? for HP-9000 HP-UX 10.00 or later with gcc, "make hpux1000gcc"
+# ? for Trusted HP-UX 10.xx "make hpux1000t", "make hpux1000to",
+# or make hpux1000to+"
+# ? for HP-9000 700/800 Series, HP-UX 11.00,TCP/IP,curses, restricted compiler
+# (no optimization, no ANSI) "make hpux1100".
+# ? for HP-9000 700/800 Series, HP-UX 11.00,TCP/IP,curses, restricted compiler
+# HP ANSI/optimizing compiler "make hpux1100o" or "make hpux1100o+"
+# ? for Trusted HP-UX 11.xx "make hpux1100t", "make hpux1100to",
+# make hpux1100to+"
+# ? for HP-9000 PA-RISC models with NeXTSTEP 3.3, "make nextquadfat".
+# ? for HP-9000 PA-RISC models with OPENSTEP/Mach 4.1, "make nextquadfat".
+# ? for IBM 370 Series with IX/370, "make ix370"
+# ? for IBM 370 Series with AIX/370 1.2, "make aix370"
+# ? for IBM 370 Series with AIX/370 3.0, "make aix370"
+# ? for IBM 370 Series with AIX/ESA 2.1, "make aixesa"
+# - for IBM PC/AT 286 & compatibles with Mark Williams Coherent OS,
+# command-line-only version, "make coherent" (version 5A & later too big)
+# ? for IBM PC 386 & compatibles with Mark Williams Coherent OS,
+# minimum interactive version, "make coherentmi"
+# ? for IBM PC 386 & compatibles with Mark Williams Coherent OS,
+# full interactive version, prior to v4.2, "make coherentmax"
+# ? for IBM PC 386 & compatibles with Mark Williams Coherent OS 4.2,
+# "make coherent42"
+# ? for IBM PC 386 & compatibles with LynxOS 2.0 or 2.1, "make lynx21"
+# ? for IBM PC 386 & compatibles with LynxOS 2.2, "make lynx"
+# - for IBM PC/AT & compatibles with original MINIX, "make minix" (too big)
+# ? for IBM PC family, 386-based, with MINIX/386 1.5, "make minix386"
+# or if you have GNU CC, "make minix386gcc"
+# ? for IBM PC family, 386-based, with MINIX 2.0, "make minix20"
+# ? for IBM PC family, 386-based, with MINIX 3.0, "make minix3"
+# + for IBM PC family, 386-based, with MINIX 3.0, "make minix315"
+# ? for IBM PS/2 with PS/2 AIX 1.0, 1.1, or 1.2, "make ps2aix" or ps2aixnetc.
+# ? for IBM PS/2 with PS/2 AIX 1.3, "make ps2aix3"
+# ? for IBM RISC System/6000 with AIX 3.0, "make aix30"
+# ? for IBM RISC System/6000 with AIX 3.1.x, "make aix31"
+# ? for IBM RISC System/6000 with AIX 3.2.0 thru 3.2.5, "make aix32"
+# ? for IBM RS/6000 or Power Series with AIX 4.1.x, "make aix41"
+# ? for IBM RS/6000 or Power Series with AIX 4.1.x with gcc, "make aix41g"
+# ? for IBM RS/6000 or Power Series with AIX 4.1 with X.25, "make aix41x25"
+# ? for IBM RS/6000 or Power Series with AIX 4.2 or later: "make aix"
+# (the following "make aixnn" targets are no longer necessary except for gcc)
+# ? for IBM RS/6000 or Power Series with AIX 4.2, "make aix42"
+# ? for IBM RS/6000 or Power Series with AIX 4.3, "make aix43" (or aix43gcc)
+# ? for IBM RS/6000 or Power Series with AIX 4.4, "make aix44" (or aix44gcc)
+# ? for IBM RS/6000 or Power Series with AIX 4.5, "make aix45" (or aix45gcc)
+# ? for IBM RS/6000 or Power Series with AIX 5.0, "make aix50" (or aix50gcc)
+# ? for IBM RS/6000 or Power Series with AIX 5.1, "make aix51" (or aix51gcc)
+# ? for IBM RS/6000 or Power Series with AIX 5.2, "make aix52" (or aix52gcc)
+# ? for IBM RS/6000 or Power Series with AIX 5.3, "make aix53" (or aix53gcc)
+# ? for IBM RS/6000 or Power Series with AIX 6.1, "make aix61" (or aix53gcc)
+# ? for IBM RT PC with AIX 2.1, "make sys3"
+# ? for IBM RT PC with AIX 2.2.1, "make rtaix" or "make rtaixc"
+# ? for IBM RT PC with ACIS 4.2, "make bsd"
+# ? for IBM RT PC with ACIS 4.3, "make rtacis" or "make bsd KFLAGS=-DNOANSI"
+# ? for IBM RT PC with 4.3BSD/Reno, "make bsd44" or "make bsd44c"
+# ? for ICL DRS400 or 400E, "make iclsys5r3"
+# ? for ICL DRS3000 (80486) with DRS/NX, "make iclsys5r4_486"
+# ? for ICL DRS6000 (SPARC) with DRS/NX, "make iclsys5r4"
+# ? for ICL DRS6000 (SPARC) with DRS/NX 4.2MP 7MPlus, "make iclsys5r4m+"
+# ? Ditto but with IKSD support included, "make iclsys5r4m+iksd"
+# ? for Integrated Solutions Inc V8S VME 68020, "make isi"
+# ? for Intel 302 with Bell Tech Sys V/386 R3.2, "make sys5r3"
+# ? for Intel Xenix/286, "make sco286"
+# ? for Interactive System III (PC/IX), "make pcix" or "make is3"
+# ? for Interactive System III (PC/IX) with gcc, "make is3gcc"
+# ? for Interactive 386/ix 1.0.6 with TCP/IP networking, "make is5r3net2"
+# ? for Interactive 386/ix 2.0.x, "make is5r3" or (POSIX) "make is5r3p"
+# ? for Interactive 386/ix 2.0.x with TCP/IP networking, "make is5r3net"
+# or "make is5r3net2"
+# ? for Interactive 386/ix 2.2.1, job control, curses, no net, gcc,
+# "make is5r3gcc"
+# ? for Interactive UNIX Sys V R3.2 V2.2 - 4.0 without TCP/IP, "make is5r3jc"
+# ? for Interactive UNIX Sys V R3.2 V2.2 - 4.0 with TCP/IP, "make is5r3netjc"
+# ? for Intergraph Clipper, "make clix" or "make clixnet"
+# ? for Jolix (see 386BSD)
+# + for Linux 1.2 and later, "make linux". Uses ncurses. This version
+# handles serial speeds up to 460800 bps, Linux FSSTD 1.2, TCP/IP, and
+# should work on both libc and glibc systems. For static linking, use
+# "make linux LNKFLAGS=-static". Please read the comments that accompany
+# the linux entry. As of 8.0.212 Dev.10, this also includes Large File
+# Support (LFS).
+# + for Linux builds that fail with "sys/select.h: No such file or directory",
+# "make linuxns"
+# + for Linux 1.2 and later but with curses.h and libcurses (rather than
+# ncurses.h and libncurses), use "make linuxc".
+# + for Linux 1.2 and later with no curses support at all, "make linuxnc".
+# + for Linux with no TCP/IP, "make linuxnotcp"
+# (The following Linux targets are historic and might not work...)
+# ? for Red Hat Linux 7.1 through RH9, fully configured (krb5, SSL, etc):
+# "make redhat71", "make redhat72", "make redhat73", "make redhat80"
+# "make redhat9"
+# NOTE: You must use this target for Red Hat 7.1 since it
+# also includes a workaround for its broken curses library.
+# WARNING: These targets create binaries that include code for
+# strong encryption and are therefore not exportable. DO NOT PUT
+# THESE BINARIES ON US OR CANADIAN WEB OR FTP SITES.
+# ? for Linux on PowerMac (Mklinux DR3), "make mklinux".
+# ? for Linux 1.2 and later, to build with egcs, "make linuxegcs".
+# ? for Linux with lcc compiler, no TCP/IP, "make linuxnotcp-lcc"
+# ? for Linux 1.0 or earlier, "make linux10".
+# (End old linux targets)
+# ? for Mach 2.6 on (anything, e.g. DECstation), "make bsd42" or "make bsd43".
+# ? for MachTen (Tenon) 2.1.1.D on (e.g.) Apple Powerbook, "make machten".
+# ? for Masscomp RTU AT&T System III, "make rtu"
+# for other Masscomp, see Concurrent.
+# ? for Microport SV/AT (System V R2), "make mpsysv" (last edit tested: 144)
+# ? for Microport SVR4 2.2, 3.1, or 4.1 "make sys5r4sx"
+# ? for Microsoft,IBM Xenix (/286, PC/AT, etc), "make xenix" or "make sco286"
+# ? for MIPS System with RISC/os (UMIPS) 4.52 = AT&T SVR3, "make mips"
+# or "make mipstcpc"
+# ? for MkLinux on Power Macintosh, "make mklinux"
+# ? for Modcomp 9730, Real/IX, "make sys5r3" (or modify to use gcc = GLS cc)
+# ? for Modcomp Realstar 1000 with REAL/IX D.1, "make sv88r32"
+# ? for Motorola Four Phase, "make sys3" or "make sys3nid"
+# ? for Motorola Delta System V/68 R3, "make sv68r3"
+# ? for Motorola Delta System V/68 R3V5, "make sv68r3v5"
+# ? for Motorola Delta System V/68 R3V5.1, "make sv68r3v51"
+# ? for Motorola Delta System V/68 R3V6 with NSE TCP/IP, "make sv68r3v6"
+# ? for Motorola Delta System V/88 R32, "make sv88r32"
+# ? for Motorola Delta System V/88 R40, "make sv88r40"
+# ? for Mt Xinu Mach386 on 386/486-based PCs, "make bsd43"
+# ? for NCR Tower 1632, OS 1.02, "make tower1"
+# ? for NCR Tower 1632 or Minitower with System V R2, "make sys3"
+# or "make sys3nv"
+# ? for NCR Tower 32, OS Release 1.xx.xx, "make tower32-1"
+# ? for NCR Tower 32, OS Release 2.xx.xx, "make tower32-2"
+# ? for NCR Tower 32, OS Releases based on Sys V R3, "make tower32"
+# ? for NCR Tower 32, OS Releases based on Sys V R3 with gcc "make tower32g"
+# ? for NCR System 3000, AT&T UNIX System V R4 2.0, "make sys5r4sxna"
+# ? for NCR System 3000, AT&T UNIX System V R4 2.0 with Wollongong TCP/IP,
+# "make sys5r4net2" or "make sys5r4net2c".
+# Some header files might be misplaced; try this:
+# ln /usr/include/netinet/in.h /usr/include/sys/in.h
+# ln /usr/include/arpa/inet.h /usr/include/sys/inet.h
+# ln /usr/include/sys/termiox.h /usr/include/termiox.h
+# ? for NCR System 3000, NCR UNIX 02.02.01, same as above.
+# ? for NCR MP-RAS System V R4 V2.03 or 3.02, "make mpras" or "make mprastcpc"
+# + for NetBSD any version on any architecture, "make netbsd"
+# + for NetBSD with OpenSSL, "make netbsd+ssl"
+# ? for NetBSD with ncurses specified instead of curses, "make netbsdn"
+# ? for NetBSD with all curses support omitted, "make netbsdnc"
+# ? for NeXT with NeXTSTEP 1.0 through 3.2, "make next" (on a NeXT)
+# ? for NeXT with NeXTSTEP 3.3, "make next33"
+# ? for NeXT with OPENSTEP/Mach 4.1, "make nextquadfat".
+# ? for NeXT with OPENSTEP/Mach 4.2, "make openstep42".
+# ? for NeXTSTEP/486, "make next" (on a PC)
+# ? for NeXTSTEP portable binary (runs on Intel or Motorola), "make nextfat"
+# ? for NeXTSTEP portable binary (Intel, Motorola, HP PA-RISC, or SPARC),
+# "make nextquadfat"
+# ? for Nixdorf Targon/31, "make t31tos40x"
+# ? for Norsk Data Uniline 88/17 with SV/88 R3.2, "make sv88r32"
+# for Novell UnixWare - see UnixWare
+# ? for OSF/1 (vanilla, from OS/F), "make posix"
+# ? for OkiStation 7300 Series, "make sys5r4sxtcp"
+# ? for Olivetti LSX-3020 with X/OS R.2.3, "make xos23" or "make xos23c"
+# + for OpenBSD, "make openbsd" (also see secure targets listed below).
+# ? for OPENSTEP/Mach 4.1, "make nextquadfat" (NeXT, Intel, PA-RISC, SPARC)
+# ? for OPENSTEP/Mach 4.2, "make openstep42" (tested on NeXT)
+# ? for Perkin-Elmer (Concurrent) 3200 series, "make sys5".
+# ? for Perkin-Elmer (Concurrent) 3200 series with <dirent.h>, "make ccop1"
+# ? for Perkin-Elmer/Concurrent 3200 with Xelos R02, "make ccop1"
+# ? for PFU Compact A Series SX/A TISP V10/E50 (Japan), "make sxae50"
+# ? for Plexus, "make sys3"
+# ? for Pyramid 9XXX (e.g. 9845) or MIServer T series, OSx 4.4b thru 5.1,
+# "ucb make pyramid" or for HDB UUCP, "ucb make pyramid-hdb" or:
+# ? for Pyramid MIServer S or ES Series, DataCenter/OSx, "make pyrdcosx"
+# ? for Pyramid MIS-S MIPS R3000, DataCenter OSx System V R4, "make pyrdcosx"
+# ? for POSIX on anything, "make posix" (but adjustments might be necessary).
+# NOTE: this target is not very useful - many features are missing.
+# ? for Prime 8000 MIPS, SVR3, "make mips" or "make mipstcpc"
+# - for QNX 2.x (sorry we don't have a version of C-Kermit for QNX 2.x)
+# ? for QNX 4.0 or 4.1, 16-bit, on 286 PC, Watcom C 8.5, "make qnx16_41"
+# ? for QNX 4.21 - 4.22A (286+), and 4.23 (386+), or higher, 16-bit,
+# Watcom C 9.5x or higher, "make qnx16"
+# + for QNX 4.21-4.25, 32-bit, 386 or above, Watcom C 10.6, "make qnx32"
+# NOTE: ("make qnx" == "make qnx32")
+# ? for QNX Neutrino 2+, "make qnx_nto2+" (crosscompiled on QNX4 with Watcom C)
+# ? for QNX 6 = Neutrino 2.xx, "make qnx6"
+# ? for Ridge 32 (ROS3.2), "make ridge32"
+# ? for Samsung MagicStation, "make sys5r4"
+# ? for SCO Xenix 2.2.1 with development system 2.2 on 8086/8 "make sco86"
+# ? for SCO Xenix/286 2.2.1 with development system 2.2 on 80286, "make sco286"
+# NOTE: reportedly this makefile is too long for SCO Xenix/286 make, but it
+# works with "makeL", or if some of the other make entries are edited out.
+# ? for SCO Xenix/386 2.2.2, "make sco386"
+# ? for SCO Xenix/386 2.3.x, "make sco3r2"
+# ? for SCO Xenix/386 SCO 2.3.3 or 2.3.4 with gcc 1.37 or later,
+# "make sco386gcc" or (to add curses) "make sco386gccc".
+# ? for SCO Xenix/386 or UNIX/386 with Excelan TCP/IP, "make sco3r2net"
+# or (to add curses support) "make sco3r2netc" or "sco386netc"
+# + for SCO XENIX 2.3.4, "make sco234" or "make sco234c" to add curses.
+# ? for SCO XENIX 2.3.4 with SCO TCP/IP & curses, "make sco234netc".
+# ? for SCO Xenix 2.3.x with Racal-InterLan TCP/IP, "make sco3r2netri"
+# for other UNIX varieties with Racal Interlan TCP/IP, read sco3r2netri entry
+# ? for SCO Xenix 2.3.x with SCO (Lachman) TCP/IP, "make sco3r2lai"
+# or (to add curses) "make sco3r2laic"
+# for SCO UNIX... ALSO READ COMMENTS in the SCO UNIX entries for more info!
+# ? for SCO UNIX/386 3.2.0 or 3.2.1, "make sco3r2" or "make sco3r2x"
+# ? for SCO UNIX/386 3.2.2, "make sco3r22" or "make sco3r22gcc"
+# or "make sco3r22c"
+# ? for SCO UNIX/386 3.2.2 with SCO TCP/IP, "make sco3r22net"
+# or "make sco3r22netc" (curses)
+# ? for SCO ODT 1.1, "make sco3r22net" or "make sco3r22netc" (curses)
+# ? for SCO UNIX/386 3.2 V4.x, no network support, "make sco32v4"
+# ? or "make sco32v4ns" (this one uses no select() or sockets library)
+# ? for SCO UNIX/386 3.2 V4.x with TCP/IP, "make sco32v4net"
+# (also sco32v4gcc, sco32v4netgcc)
+# ? for SCO UNIX/386 3.2 V5.0 - see SCO OpenServer.
+# ? for SCO UNIX 3.2v4.x with TCP/IP, <dirent.h> for Extended Acer File
+# System (EAFS), curses, ANSI C compilation, "make sco32v4net"
+# ? or (to use select()-based CONNECT module) "make sco32v4netx".
+# ? for SCO UNIX 3.2v4.2, "make sco-odt30" (includes TCP/IP).
+# ? for SCO MPX 3.0 - The SCO UNIX binary runs on the corresponding MPX system.
+#
+# NOTE: Also see below for other entries that are variations on these.
+# Also be sure to read the comments accompanying each SCO entry.
+# Also see Unixware section.
+#
+# ? for SCO ODT 2.0, "make sco32v4net"
+# ? for SCO ODT 3.0, "make sco-odt30"
+# ? for SCO OpenServer 5.0 (OSR5), "make sco32v500"
+# ? for SCO OpenServer 5.0 (OSR5) with networking, "make sco32v500net"
+# ? for SCO OpenServer 5.0 (OSR5), gcc, "make sco32v500gcc"
+# ? for SCO OpenServer 5.0 (OSR5), gcc, with networking, "make sco32v500netgcc"
+# ? for SCO OpenServer 5.0 (OSR5), as above, ELF, "make sco32v500netgccelf"
+# ? for SCO OpenServer 5.0.2, use "make sco32v502xxx" entries as above.
+# ? for SCO OpenServer 5.0.4, use "make sco32v504xxx" entries as above.
+# ? for SCO OpenServer 5.0.5, use "make sco32v505xxx" entries as above.
+# Use the sco32v505udkxxx entries if you have the UDK rather than /bin/cc.
+# ? for SCO OpenServer 5.0.6, use "make sco32v506xxx" entries as above.
+# ? for SCO OpenServer 5.0.6a,use "make sco32v506axxx" entries as above.
+# ? for SCO OpenServer 5.0.7, use "make sco32v507", "make sco32v507net"
+# ? for SCO (Univel) UnixWare 1.x, "make unixware" or "make unixwarenetc".
+# If there are problems with this in C-K 7+ see notes at unixware entry.
+# + for SCO OpenServer 6.0.0, "make sco_osr600"
+# ? for SCO UnixWare 2.0.x, "make uw20"
+# ? for SCO UnixWare 2.1.0, "make uw21"
+# ? for SCO UnixWare 2.1.3, "make uw213"
+# + for SCO UnixWare 7, "make uw7" (includes large file support)
+# ? for SCO UnixWare 7 with IKSD support, "make uw7iksd" or "make uw7iksdudk"
+# ? for SCO UnixWare 7 with OpenSSL, "make uw7ssl"
+# ? for SCO (Caldera) Open UNIX 8, "make ou8"
+# ? for Sharp Zaurus SL5500 PDA, "make zsl5500".
+# ? for Sequent with DYNIX/ptx 1.2.1, "make dynixptx12"
+# ? for Sequent with DYNIX/ptx 1.3 or 1.4 with TCP/IP, "make dynixptx13"
+# ? for Sequent with DYNIX/ptx 2.0 or 2.1 with TCP/IP, "make dynixptx20"
+# or "dynixptx20c"
+# ? for Sequent with DYNIX/ptx 2.1.6 on i486, "dynixptx216c"
+# ? for Sequent with DYNIX/ptx V4.1.3 with TCP/IP, "make dynixptx41c"
+# ? for Sequent with DYNIX/ptx V4.4.2 with TCP/IP, "make dynixptx44"
+# ? for Sequent Balance 8000 or B8 with DYNIX 3.0.xx, "make dynix3"
+# or "make dynix3noacu"
+# ? for Sequent Symmetry S81 with DYNIX 3.0.xx, "make dynix3"
+# ? for Sequent DYNIX 3.1.xx, "make dynix31" or "make dynix31c"
+# ? for Siemens/Nixdorf SINIX-L Intel V5.41, "make sinix541i"
+# + for Siemens/Nixdorf SINIX-N MIPS V5.42, "make sinix542"
+# ? for Siemens/Nixdorf SINIX-P MIPS V5.42 with gcc, "make sinix542g"
+# ? for Siemens/Nixdorf SINIX-Z Intel V5.42, "make sinix542i"
+# ? for Siemens/Nixdorf Reliant UNIX V5.43, "make sni543"
+# ? for Siemens/Nixdorf Reliant UNIX V5.44, "make sni544"
+# ? for Silicon Graphics Iris System V IRIX 3.2 or earlier, "make iris"
+# ? for Silicon Graphics Sys V R3 with IRIX 3.3 or later, "make sys5r3"
+# ? for Silicon Graphics Iris Indigo with IRIX 4.0 or 5.0, "make irix40" or
+# (to include Yellow Pages and Curses) "make irix40ypc"
+# ? for Silicon Graphics Iris Indigo or Elan with IRIX 4.0.x with microcode
+# optimization and -O4, "make irix40u" or "irix40uc" (and read notes
+# accompanying these entries).
+# ? for Silicon Graphics IRIX 5.1, "make irix51" or "irix51x" (no optimize)
+# ? for Silicon Graphics IRIX 5.2, "make irix52"
+# ? for Silicon Graphics IRIX 5.3, "make irix53" or "irix53x" (no optimize)
+# ? for Silicon Graphics IRIX 6.0, "make irix60".
+# ? for Silicon Graphics IRIX 6.2, "make irix62".
+# ? for Silicon Graphics IRIX 6.3, "make irix63".
+# ? for Silicon Graphics IRIX 6.4, "make irix64" or "make irix64gcc".
+# + for Silicon Graphics (SGI) IRIX 6.5, "make irix65"
+# + or "make irix65mips2" to force MIPS2, or "make irix65gcc" for GCC.
+# + for Silicon Graphics (SGI) IRIX 6.5, "make irix65" or "make irix65mips2"
+# ? for SGI IRIX 6.5 with SSL/TLS, SRP, and ZLIB "make irix65+ssl+srp+zlib"
+# ? for Solaris 2.0-2.3 on SPARC or Intel, SunPro CC, "make solaris2x",
+# ? or to add SunLink X.25 8.0x support, "make solaris2x25".
+# ? for Solaris 2.4 built with gcc, "make solaris24g".
+# ? for Solaris 2.0-2.3 on SPARC or Intel, GNU CC, "make solaris2xg".
+# ? for Solaris 2.4 with X.25, "make solaris24x25".
+# ? for Solaris 2.5 on SPARC or Intel, SunPro CC, "make solaris25".
+# ? or to add SunLink X.25 8.0x support, "make solaris25x25".
+# ? for Solaris 2.5 on SPARC or Intel, GNU CC, "make solaris25g".
+# ? for Solaris 2.6 on SPARC or Intel, "make solaris26".
+# ? for Solaris 7 on SPARC or Intel, SunPro CC, "make solaris7".
+# ? for Solaris 7 on SPARC or Intel, GNU CC, "make solaris7g".
+# ? for Solaris 8 on SPARC or Intel, SunPro CC, "make solaris8".
+# ? for Solaris 8 on SPARC or Intel, GNU CC, "make solaris8g".
+# + for Solaris 9 on SPARC (or Intel?), 32-bit, SunPro CC, "make solaris9".
+# + for Solaris 9 on SPARC (or Intel?), 32-bit, GNU CC, "make solaris9g".
+# ? for Solaris 9 on SPARC (or Intel?), 64-bit, GNU CC, "make solaris9g64".
+# + for Solaris 10 on SPARC (or Intel?), 32-bit, SunPro CC, "make solaris10".
+# + for Solaris 10 on SPARC 64-bit, SunPro CC, "make solaris10_64".
+# + for Solaris 10 on SPARC (or Intel?), 32-bit, GNU CC, "make solaris10g".
+# ? for Solaris 10 on SPARC (or Intel?), 64-bit, GNU CC, "make solaris10g64".
+# ? for Solbourne 4/500 with OS/MP 4 "make sunos4"
+# ? for Solbourne 4/500 with OS/MP 4.1 "make sunos41" or "make sunos41c"
+# ? for SONY NEWS with NEWS-OS 4.0.1C, "make sonynews"
+# ? for SONY NEWS with NEWS-OS 4.1.2C, "make sonynews"
+# ? for Sperry/UNISYS 5000/20, UTS V 5.2 3R1, "make sys5"
+# ? for Sperry/UNISYS 5000/30/35/50/55, UTS V 5.2 2.01, "make unisys5r2"
+# ? for Sperry/UNISYS 5000/80 with System V R3, "make sys5r3"
+# ? for Sperry/UNISYS 5000/95 with System V R3, "make sys5r3"
+# For UNISYS SVR3 it might be necessary to "make sys5r3 KFLAGS=-UDYNAMIC"
+# ? for Stardent 1520, "make sys5r3"
+# ? for Stratus FTX 2.x, try "make ftx" or else "make sys5r4" or "sys5r4sx"
+# ? for Stratus FTX 3.x, PA-RISC 1.0 or 2.0, "make ftx" or "make ftxtcp"
+# ? for Sun with Sun UNIX 3.5 and gcc, "make sunos3gcc"
+# ? for Sun with pre-4.0 SunOS versions, "make bsd" (or appropriate variant)
+# ? for Sun with SunOS 4.0, BSD environment, "make sunos4"
+# ? for Sun with SunOS 4.0, BSD, with SunLink X.25, make sunos4x25
+# ? for Sun with SunOS 4.1 or 4.1.1, BSD environment, "make sunos41"
+# or "make sunos41c" (curses) or "make sunos41gcc" (compile with gcc)
+# ? for Sun with SunOS 4.1.x, BSD, with SunLink X.25 7.00 or earlier,
+# "make sunos41x25" or "make sunos41x25c" (curses)
+# ? for Sun with SunOS 4.1, 4.1.1, AT&T Sys V R3 environment, "make sunos41s5"
+# ? for Sun with SunOS 4.1.2, "make sunos41" or any of its variations.
+# NOTE: All SunOS 4.x systems -- Shared libraries are used by default.
+# If this causes problems, add -Bstatic to CFLAGS.
+# NOTE2: When building C-Kermit under SunOS for the BSD universe,
+# but /usr/5bin/cc is ahead of /usr/ucb/cc in your PATH, add
+# "CC=/usr/ucb/cc CC2=/usr/ucb/cc" to the make entry.
+# NOTE3: If an executable built on one type of Sun hardware does not work
+# on another type, rebuild the program from source on the target machine.
+# for Sun with Solaris 1.x use SunOS 4.1 entries.
+# for Sun with Solaris 2.0 and higher use Solaris entries.
+# + for Sun SPARC with Linux, "make linux"
+# ? for Sun SPARC with OPENSTEP/Mach 4.1, "make nextquadfat"
+# ? for Sun SPARC with OPENSTEP/Mach 4.2, "make openstep42"
+# - for Tandy 16/6000 with Xenix 3.0, "make trs16" (C-Kermit 7.0 is too big)
+# ? for Tektronix 6130/4132/43xx (e.g.4301) with UTek OS, "make utek"
+# or (for models without hardware flow control), "make uteknohwfc"
+# ? for Tektronix XD88 series with UTekV OS, "make utekvr3"
+# ? for Tri Star Flash Cache with Esix SVR3.2, "make sys5r3"
+# NOTE: The Tru64 builds have been failing since 2010, but "make dec-osf" is OK
+# ? for Tru64 UNIX 4.0E, "make tru64-40e"
+# ? for Tru64 UNIX 4.0F, "make tru64-40f"
+# ? for Tru64 UNIX 4.0G, "make tru64-40g"
+# ? for Tru64 UNIX 5.0A, "make tru64-50a"
+# ? for Tru64 UNIX 5.1A, "make tru64-51a"
+# ? for Tru64 UNIX 5.1B, "make tru64-51b"
+# ? for Unistar, "make sys5"
+# ? for Unisys S/4040 68040 CTIX SVR3.2 6.4.1, "make ctix" or "make sys5r3"
+# ? for Unisys U5000 UNIX SVR3 6.x, "make sys5r3" or "make sys5r3c"
+# ? for Unisys U6000 UNIX SVR4 1.x, "make sys5r4nx" or "make sys5r4nxnetc"
+# for Unisys ... (also see Sperry)
+# for Univel - see UnixWare
+# for Unixware - see SCO
+# ? for Valid Scaldstar, "make valid"
+# ? for Whitechapel MG01 Genix 1.3, "make white"
+# ? for Zilog ZEUS 3.21, "make zilog"
+#
+# The result should be a runnable program called "wermit" in the current
+# directory. After satisfactory testing, you can rename wermit to "kermit"
+# and put it in some directory that's in everybody's PATH, such as
+# /usr/local or /opt/local.
+#
+# To remove intermediate and object files, "make clean".
+# If your C compiler produces files with an extension other than "o",
+# then "make clean EXT=u", "make clean EXT=s", or whatever.
+#
+# To run lint on the source files, "make lintsun", "make lintbsd",
+# "make lints5", as appropriate.
+#
+# ******************************
+# SECURE TARGETS
+#
+# Beginning with C-Kermit 7.0, secure targets are included, as are the
+# source modules (ckuat*.[ch], ck_*.[ch]) needed to build them. Secure
+# target names are like the regular names, but with security features
+# indicated by plus (+) signs. The features are:
+#
+# krb4 MIT Kerberos IV
+# krb5 MIT Kerberos V
+# openssl OpenSSL (SSL/TLS)
+# zlib ZLIB compression for SSL/TLS
+# srp Stanford Secure Remote Password
+# pam PAM (pluggable authentication module)
+# shadow Shadow Password File
+#
+# You can build these targets if you have the Kermit source files and the
+# required libraries (Kerberos, OpenSSL, SRP, etc) and header files. See:
+# http://www.columbia.edu/kermit/security.html
+# for specific details regarding supported versions.
+#
+# NOTE: OpenSSL 0.9.6 and earlier are not compatible with 0.9.7 and later.
+# C-Kermit code was originally designed for 0.9.6. To build with 0.9.7 you
+# must add -DOPENSSL_097 to avoid missing symbols in the DES library and to
+# use the entry points that were renamed to avoid conflict with Kerberos 4.
+# If you have OpenSSL 0.9.8, add -DOPENSSL_098, which is a synonym for
+# -DOPENSSL_097. If you have 1.0.0 or later, add -DOPENSSL_100, which is
+# another synonym.
+
+# In OpenSSL builds add -ldl if you get unresolved references for
+# dlopen, dlclose, dlsym, and/or dlerror.
+#
+# In order to build a secure version of Kermit, you need to know the location
+# of the header (include) files and libraries for the desired form of
+# security. Unless you specify a location, this makefile looks in /usr/local
+# and if the required files are not found, the build fails.
+#
+# If the secure headers and libraries are not on your computer, you have
+# to download and install them, for example from http://www.openssl.org .
+#
+# The following symbols are used to specify library and header file locations:
+#
+prefix = /usr/local
+srproot = $(prefix)
+sslroot = $(prefix)
+manroot = $(prefix)
+
+K4LIB=-L/usr/kerberos/lib
+K4INC=-I/usr/kerberos/include
+K5LIB=-L/usr/kerberos/lib
+K5INC=-I/usr/kerberos/include
+SRPLIB=-L$(srproot)/lib
+SRPINC=-I$(srproot)/include
+SSLLIB=-L$(sslroot)/ssl/lib
+SSLINC=-I$(sslroot)/ssl/include
+
+# To override these assignments; for example, if your OpenSSL files are
+# not in /usr/local/ssl, invoke the desired target like this:
+#
+# make solaris9+openssl "SSLINC=-I/opt/openssl-0.9.8k/include" \
+# "SSLLIB=-L/opt/openssl-0.9.8k/lib"
+#
+# (don't set the variables and then do "make -e" because that breaks
+# chaining of makefile targets.)
+#
+# Here are some up-to-date secure targets as of Sep 2009:
+#
+# aix+openssl: IBM AIX 4.2 or later with OpenSSL
+# freebsd44+srp+openssl FreeBSD 4.4 with SRP and OpenSSL
+# freebsd50+openssl FreeBSD 5.0 with OpenSSL
+# hpux1100o+openssl: HP-UX 11.xx with OpenSSL
+# hpux1000gcc+openssl: HP-UX 10.xx with OpenSSL (build with gcc)
+# hpux1100gcc+openssl: HP-UX 11.xx with OpenSSL (build with gcc)
+# irix6x+krb5: IRIX 6.x with Kerberos V
+# irix65+krb5: etc etc...
+# solaris9+openssl Solaris 9,10, or 11 with Openssl (Sun cc)
+# solaris9g+openssl Solaris 9,10, or 11 with Openssl (gcc)
+# linux+ssl OpenSSL only
+# linux+krb5+ssl Linux with Kerberos 5 and OpenSSL
+# linux+krb5: Kerberos 5 only
+#
+# The following secure Linux targets have not been updated or tested recently.
+# linux+krb5+krb4:
+# linux+srp:
+# linux+srp+pam:
+# linux+srp+gmp:
+# linux+srp+gmp+no-des:
+# linux+srp+gmp-export:
+# linux+srp+gmp+pam:
+# linux+shadow+pam:
+# linux+openssl:
+# linux+openssl+shadow:
+# linux+openssl+zlib+shadow+pam:
+# linux+srp+openssl:
+# linux+krb5+krb4+srp:
+# linux+krb5+krb4+srp+openssl:
+# linux+krb5+krb4+openssl:
+# linux+krb5+krb4+openssl+shadow:
+# linux+krb5+krb4+openssl+zlib+shadow:
+# linux+krb5+krb4+srp-export:
+# linux+krb5+krb4+srp+pam:
+# linux+krb5+krb4+srp+openssl+pam-debug:
+# linux+krb5+krb4+srp+openssl+pam:
+# linux+krb5+krb4+srp+openssl+zlib+pam:
+# linux+krb5+krb4+openssl+shadow+pam:
+# linux+krb5+openssl+zlib+shadow+pam:
+#
+# The following have not been tested recently either and might
+# need adjustment.
+#
+# macosx+krb5+ssl: Mac OS X 10.3.9 or later + OpenSSL and Kerberos 5
+# macosx103+secure: This one is probably redundant
+# netbsd+openssl: NetBSD with OpenSSL
+# openbsd30+ssl: OpenBSD 3.0 with OpenSSL
+# redhat71,redhat72,redhat73,redhat80,redhat9 (Krb5,OpenSSL,Showdow,PAM,Zlib)
+# sco32v500net+ssl:
+# sco32v505net+ssl:
+# solaris2x+krb4:
+# solaris2xg+krb4:
+# solaris2xg+openssl+pam+shadow:
+# solaris2xg+openssl+zlib+pam+shadow:
+# solaris2xg+krb5+krb4+openssl+shadow:
+# solaris25+krb4:
+# solaris25g+krb4:
+# solaris26g+openssl:
+# solaris8g+openssl+zlib+pam+shadow:
+# solaris8g+krb4:
+# solaris9g+openssl+zlib+pam+shadow:
+# solaris9g+openssl+shadow+pam+zlib
+# sunos41gcc+krb4: SunOS 4.1 built with gcc with Kerberos IV
+# sunos41gcc+openssl: SunOS 4.1 built with gcc with OpenSSL
+# sunos41gcc+krb4+openssl: ...with Kerberos IV and OpenSSL
+# sunos41gcc+krb4+openssl+zlib: ditto, plus ZLIB compression
+# sunos41gcc+krb4+srp+openssl+zlib: ditto, plus SRP
+# sunos41gcc+srp+openssl+zlib:
+# tru64-51b-openssl: Tru64 (Digital) Unix 5.1B with OpenSSL
+# uw7ssl Unixware 7 with SSL
+#
+###########################################################################
+#
+# Compile and Link variables:
+#
+# EXT is the extension (file type) for object files, normally o.
+# See MINIX entry for what to do if another filetype must be used.
+#
+EXT=o
+#LNKFLAGS=
+SHAREDLIB=
+CC= cc
+CC2= cc
+MAKE= make
+SHELL=/bin/sh
+
+###########################################################################
+# (Ancient) UNIX V7-specific variables.
+# These are set up for Perkin-Elmer 3230 V7 Unix:
+#
+PROC=proc
+DIRECT=
+NPROC=nproc
+NPTYPE=int
+BOOTFILE=/edition7
+#
+# ( For old Tandy TRS-80 Model 16A or 6000 V7-based Xenix, use PROC=_proc,
+# DIRECT=-DDIRECT, NPROC=_Nproc, NPTYPE=short, BOOTFILE=/xenix )
+#
+
+###########################################################################
+# SAMPLE INSTALLATION SCRIPT
+#
+# Modify to suit your own computer's file organization and permissions. If
+# you don't have write access to the destination directories, "make install"
+# fails. In most cases, a real installation also requires you to chown /
+# chgrp the Kermit binary for the UUCP lockfile and/or tty devices, and
+# perhaps also to chmod +s the corresponding permission fields.
+#
+# Default binary, man, and doc directories are supplied below. You can
+# override them in your 'make' command. Examples:
+#
+# make install # Accept defaults.
+# make "INFODIR=/usr/share/lib/kermit" install # Override INFODIR default.
+#
+# You can also build and install in one step, e.g.:
+#
+# make linux install
+#
+# If you use the 'install' target to install C-Kermit, it creates an
+# UNINSTALL script that can be used to uninstall it.
+#
+WERMIT = makewhat
+BINARY = wermit
+DESTDIR =
+BINDIR = $(prefix)/bin
+MANDIR = $(manroot)/man/man1
+MANEXT = 1
+SRCDIR =
+INFODIR =
+CERTDIR =
+
+TEXTFILES = COPYING.TXT ckcbwr.txt ckubwr.txt ckuins.txt ckccfg.txt \
+ ckcplm.txt ckermit.ini ckermod.ini ckermit70.txt ckermit80.txt
+
+ALL = $(WERMIT)
+
+all: $(ALL)
+
+.c.o:
+ $(CC) $(CFLAGS) -DKTARGET=\"$(KTARGET)\" -c $<
+
+#Clean up intermediate and object files
+clean:
+ @echo 'Removing object files...'
+ -rm -f ckcmai.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckcpro.$(EXT) ckcfns.$(EXT) \
+ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) ckucon.$(EXT) ckutio.$(EXT) \
+ckufio.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) ckwart.$(EXT) ckuusx.$(EXT) \
+ckuusy.$(EXT) ckcnet.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) ckusig.$(EXT) \
+ckucns.$(EXT) ckcmdb.$(EXT) ckuath.$(EXT) ckctel.$(EXT) ckclib.$(EXT) \
+ckcuni.$(EXT) ck_crp.$(EXT) ck_ssl.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \
+ckcpro.c wart
+
+show:
+ @echo prefix=$(prefix)
+ @echo srproot=$(srproot)
+ @echo sslroot=$(sslroot)
+ @echo manroot=$(manroot)
+ @echo K4LIB=$(K4LIB)
+ @echo K4INC=$(K4INC)
+ @echo K5LIB=$(K5LIB)
+ @echo K5INC=$(K5INC)
+ @echo SRPLIB=$(SRPLIB)
+ @echo SRPINC=$(SRPINC)
+ @echo SSLLIB=$(SSLLIB)
+ @echo SSLINC=$(SSLINC)
+ @exit
+
+# Install C-Kermit after building -- IMPORTANT: Read the instructions above
+# (SAMPLE INSTALLATION SCRIPT). For SSL/TLS versions, ca_certs.pem file
+# should be installed in the appropriate place for your OpenSSL library, e.g.:
+#
+# cp ca_certs.pem /usr/local/ssl/
+# cp ca_certs.pem /usr/share/ssl/
+#
+# To make sure 'man' notices the new source file and doesn't keep
+# showing the old formatted version, remove the old formatted version,
+# something like this:
+# rm -f $(MANDIR)/../cat$(MANEXT)/kermit.$(MANEXT)
+# or this (which requires CATDIR to be defined):
+# rm -f $(CATDIR)/kermit.$(MANEXT)
+#
+# As of C-Kermit 8.0.205 this target also builds an UNINSTALL script, and
+# so it might be too long for some old Bourne shells, in which case you can
+# use a different shell:
+#
+# make SHELL=ksh install
+# make SHELL=/bin/posix/sh install
+#
+install:
+ @echo Installing C-Kermit version $(CKVER)...;\
+ rm -f UNINSTALL;\
+ exec 3>./UNINSTALL;\
+ echo "# C-Kermit UNINSTALL script" >&3;\
+ echo "# `date`\n" >&3;\
+ echo "CKVER=$(CKVER)" >&3;\
+ echo "PrN Uninstalling C-Kermit version $(CKVER)..." >&3;\
+ echo DESTDIR=$(DESTDIR);\
+ if test -n "$(DESTDIR)"; then\
+ if test -d $(DESTDIR); then\
+ echo "$(DESTDIR) exists...\n";\
+ else\
+ echo "Creating $(DESTDIR)...";\
+ DESTDIR=`echo $(DESTDIR) | sed 's!/*$$!!'`;\
+ mkdir $$DESTDIR || exit 1;\
+ fi;\
+ chmod 755 $(DESTDIR) || exit 1;\
+ fi;\
+ echo BINARY=$(BINARY);\
+ if test -f $(BINARY); then\
+ ls -l $(BINARY);\
+ else\
+ echo "?$(BINARY) not found";\
+ exit 1;\
+ fi;\
+ if test -z "$(DESTDIR)$(BINDIR)"; then\
+ echo "Binary directory not specified";\
+ exit 1;\
+ fi;\
+ if test -d $(DESTDIR)$(BINDIR); then\
+ echo "$(DESTDIR)$(BINDIR) exists...";\
+ else\
+ echo "Creating $(DESTDIR)$(BINDIR)/...";\
+ mkdir $(DESTDIR)$(BINDIR) || exit 1;\
+ chmod 755 $(DESTDIR)$(BINDIR);\
+ fi;\
+ rm -f $(DESTDIR)$(BINDIR)/kermit;\
+ cp $(BINARY) $(DESTDIR)$(BINDIR)/kermit || exit 1;\
+ chmod 755 $(DESTDIR)$(BINDIR)/kermit || exit 1;\
+ rm -f $(DESTDIR)$(BINDIR)/kermit-sshsub;\
+ ln -s $(DESTDIR)$(BINDIR)/kermit\
+ $(DESTDIR)$(BINDIR)/kermit-sshsub || exit 1;\
+ echo 'set flag=f\nPrC Removing binaries' >&3;\
+ echo "RmF $(DESTDIR)$(BINDIR)/kermit-sshsub" >&3;\
+ echo "RmF $(DESTDIR)$(BINDIR)/kermit" >&3;\
+ if test -f ckermit.ini; then\
+ echo "#!$(BINDIR)/kermit" >\
+ $(DESTDIR)$(BINDIR)/_tmp.ini;\
+ cat ckermit.ini >> $(DESTDIR)$(BINDIR)/_tmp.ini;\
+ mv $(DESTDIR)$(BINDIR)/_tmp.ini\
+ $(DESTDIR)$(BINDIR)/ckermit.ini;\
+ chmod 755 $(DESTDIR)$(BINDIR)/ckermit.ini;\
+ echo "RmF $(DESTDIR)$(BINDIR)/ckermit.ini" >&3;\
+ fi;\
+ echo;\
+ echo 'EfM' >&3;\
+ echo "Kermit binary installed:";\
+ ls -l $(DESTDIR)$(BINDIR)/kermit\
+ $(DESTDIR)$(BINDIR)/kermit-sshsub\
+ $(DESTDIR)$(BINDIR)/ckermit.ini;\
+ echo;\
+ echo " WARNING: If C-Kermit is to be used for dialing out,";\
+ echo " you must change its owner and group and permissions";\
+ echo " to match the 'cu' program. See the ckuins.txt file";\
+ echo " for details.";\
+ echo;\
+ echo MANDIR=$(MANDIR);\
+ if test -n "$(DESTDIR)$(MANDIR)"; then\
+ if test -d $(DESTDIR)$(MANDIR); then\
+ echo "$(DESTDIR)$(MANDIR) exists...";\
+ else\
+ echo "Creating $(MANDIR)...";\
+ mkdir $(MANDIR) || exit 1;\
+ chmod 755 $(MANDIR) || exit 1;\
+ fi;\
+ rm -f $(DESTDIR)$(MANDIR)/kermit.$(MANEXT);\
+ cp ckuker.nr $(DESTDIR)$(MANDIR)/kermit.$(MANEXT) || exit 1;\
+ chmod 644 $(DESTDIR)$(MANDIR)/kermit.$(MANEXT) || exit 1;\
+ echo 'set flag=f\nPrC Removing man pages' >&3;\
+ echo "RmF $(DESTDIR)$(MANDIR)/kermit.$(MANEXT)" >&3;\
+ echo 'EfM' >&3;\
+ echo;\
+ else\
+ echo "Not installing man page!\n";\
+ fi;\
+ echo CERTDIR=$(CERTDIR);\
+ if test -n "$(CERTDIR)"; then\
+ if test -f ca_certs.pem; then\
+ if test -d $(CERTDIR); then\
+ echo "$(CERTDIR) exists...";\
+ else\
+ echo "Creating $(CERTDIR)...";\
+ mkdir $(CERTDIR) || exit 1;\
+ chmod 755 $(CERTDIR) || exit 1;\
+ fi;\
+ echo "Installing certificates file...";\
+ cp ca_certs.pem $(CERTDIR) || exit 1;\
+ echo 'set flag=f' >&3;\
+ echo 'PrC Removing certificates file' >&3;\
+ echo "RmF $(CERTDIR)/ca_certs.pem" >&3;\
+ echo 'EfM' >&3;\
+ echo;\
+ fi;\
+ else\
+ echo "Not installing certificates file!\n";\
+ fi;\
+ echo SRCDIR=$(DESTDIR)$(SRCDIR);\
+ if test -n "$(SRCDIR)"; then\
+ echo "Installing source files...";\
+ if test -d $(DESTDIR)$(SRCDIR); then\
+ echo "$(DESTDIR)$(SRCDIR) exists...";\
+ else\
+ echo "Creating $(DESTDIR)$(SRCDIR)/...";\
+ mkdir $(DESTDIR)$(SRCDIR) || exit 1;\
+ chmod 755 $(DESTDIR)$(SRCDIR);\
+ fi;\
+ echo "Copying source files to $(DESTDIR)$(SRCDIR)...";\
+ echo 'set flag=f\nPrC Removing source files' >&3;\
+ for TextFile in COPYING.TXT ck[cuw_]*.[cwh] makefile; do\
+ cp $$TextFile $(DESTDIR)$(SRCDIR)/ && echo ".\c";\
+ echo "RmF $(DESTDIR)$(SRCDIR)/$$TextFile" >&3;\
+ done; echo;\
+ echo 'EfM' >&3;\
+ ( cd $(DESTDIR)$(SRCDIR)/ &&\
+ ls -l COPYING.TXT ck[cuw_]*.[cwh] makefile );echo;\
+ else\
+ echo "Not installing source code!\n";\
+ fi;\
+ echo INFODIR=$(DESTDIR)$(INFODIR);\
+ if test -n "$(INFODIR)"; then\
+ echo "Installing info files...";\
+ if test -d $(DESTDIR)$(INFODIR); then\
+ echo "$(DESTDIR)$(INFODIR) exists...";\
+ else\
+ echo "Creating $(DESTDIR)$(INFODIR)/...";\
+ mkdir $(DESTDIR)$(INFODIR) || exit 1;\
+ chmod 755 $(DESTDIR)$(INFODIR);\
+ fi;\
+ echo "Copying text files to $(DESTDIR)$(INFODIR)...";\
+ echo 'set flag=f\nPrC Removing text files' >&3;\
+ FileCopyList='';\
+ for TextFile in $(TEXTFILES); do\
+ test -f $$TextFile || continue;\
+ cp $$TextFile $(DESTDIR)$(INFODIR) && echo ".\c" &&\
+ FileCopyList="$$FileCopyList $$TextFile";\
+ echo "RmF $(DESTDIR)$(INFODIR)/$$TextFile" >&3;\
+ done; echo;\
+ echo 'EfM' >&3;\
+ ( cd $(DESTDIR)$(INFODIR)/ && chmod 644 $$FileCopyList );\
+ ( cd $(DESTDIR)$(INFODIR)/ && pwd && ls -l $$FileCopyList );\
+ else\
+ echo "Not installing text files!\n";\
+ fi;\
+ echo "set flag=d\nPrN Removing empty dirs..." >&3;\
+ echo "RmD $(DESTDIR)$(BINDIR)" >&3;\
+ echo "RmD $(DESTDIR)$(SRCDIR)" >&3;\
+ echo "RmD $(DESTDIR)$(INFODIR)" >&3;\
+ echo "RmD $(CERTDIR)" >&3;\
+ echo "RmD $(MANDIR)" >&3;\
+ echo "RmD $(DESTDIR)" >&3;\
+ echo "EfM" >&3;\
+ echo "PrN C-Kermit version $(CKVER) is uninstalled!" >&3;\
+ echo C-Kermit version $(CKVER) installed!
+
+# UN-Install C-Kermit after building
+# Please to not remove the extra blanks before and after '{}' within the
+# functions. You would get syntax errors for some older Bourne shells! Best is
+# you don't change or remove anything.
+#
+uninstall:
+ @if test ! -f UNINSTALL; then\
+ echo "?C-Kermit UNINSTALL data file not found!";\
+ exit 1;\
+ fi; \
+ X=`grep '^CKVER='$(CKVER)'$$' ./UNINSTALL || :`;\
+ if test -z "$$X"; then\
+ echo "?UNINSTALL file is not for C-Kermit version $(CKVER)";\
+ exit 2;\
+ fi;\
+ PrN () { echo "$$*"; };\
+ PrC () { echo "$$* \c"; };\
+ RmF () { test -f "$$1" && rm -f "$$1" && echo ".\c" && flag=F ; };\
+ RmD () { \
+ dir=$$1;\
+ while test -d "$$dir"; do\
+ rmdir "$$dir" 2>&- || return && echo "$$dir" && flag=D;\
+ dir=`echo "$$dir" | sed 's!/[^/]*/*$$!!'`;\
+ done; \
+ };\
+ EfM () { \
+ case "$$flag" in\
+ f) echo "- Nothing to remove!";;\
+ d) echo "Nothing to remove!";;\
+ F) echo " done";;\
+ D) echo "done";;\
+ esac; \
+ };\
+ while read Act Args; do\
+ case $$Act in\
+ EfM) EfM;;\
+ RmD) RmD $$Args;;\
+ RmF) RmF $$Args;;\
+ PrN) PrN $$Args;;\
+ PrC) PrC $$Args;;\
+ set) eval $$Args;;\
+ esac;\
+ done < ./UNINSTALL
+
+makewhat:
+ @echo 'make what? You must tell which platform to make C-Kermit for.'
+ @echo Examples: make linux, make aix, make solaris10, make hpux1100.
+ @echo Please read the comments at the beginning of the makefile.
+
+###########################################################################
+#
+# Dependencies Section:
+
+wermit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckucon.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT)
+ $(CC2) $(LNKFLAGS) -o wermit \
+ ckcmai.$(EXT) ckclib.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckcpro.$(EXT) ckucmd.$(EXT) ckuus2.$(EXT) ckuus3.$(EXT) \
+ ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) \
+ ckuusx.$(EXT) ckuusy.$(EXT) ckuusr.$(EXT) ckucon.$(EXT) \
+ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) \
+ ckusig.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \
+ $(LIBS)
+
+# Preferred configuration with select()-based CONNECT
+
+xermit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) ckuath.$(EXT) \
+ ck_crp.$(EXT) ck_ssl.$(EXT)
+ $(CC2) $(LNKFLAGS) -o wermit \
+ ckcmai.$(EXT) ckclib.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckcpro.$(EXT) ckucmd.$(EXT) ckuus2.$(EXT) ckuus3.$(EXT) \
+ ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) \
+ ckuusx.$(EXT) ckuusy.$(EXT) ckuusr.$(EXT) ckucns.$(EXT) \
+ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckusig.$(EXT) \
+ ckctel.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \
+ ckuath.$(EXT) ck_crp.$(EXT) ck_ssl.$(EXT) $(LIBS)
+
+# Malloc Debugging version
+
+mermit: ckcmdb.$(EXT) ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckcpro.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) \
+ ckuxla.$(EXT) ckucon.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \
+ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) \
+ ckusig.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT)
+ $(CC2) $(LNKFLAGS) -o mermit ckcmdb.$(EXT) ckclib.$(EXT) ckcmai.$(EXT)\
+ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \
+ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckuusr.$(EXT) ckucon.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \
+ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckcuni.$(EXT) \
+ ckupty.$(EXT) ckcftp.$(EXT) $(LIBS)
+
+# Kerberized Version - Subject to USA export restrictions.
+
+# NOTE: We don't use this any more -- As of 15 Feb 2003, the "xermit"
+# target is used for both secure and regular version.
+
+krbmit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) \
+ ckcftp.$(EXT) ck_ssl.$(EXT)
+ $(CC2) $(LNKFLAGS) -o krbmit ckcmai.$(EXT) ckclib.$(EXT) \
+ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \
+ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \
+ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \
+ ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \
+ ck_ssl.$(EXT) $(LIBS)
+
+krbmit-debug: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckcpro.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) \
+ ckuxla.$(EXT) ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \
+ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) \
+ ckusig.$(EXT) ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) \
+ ckupty.$(EXT) ck_ssl.$(EXT) ckcmdb.$(EXT) ckcftp.$(EXT)
+ $(CC2) $(LNKFLAGS) -o krbmit ckcmdb.$(EXT) ckcmai.$(EXT) \
+ ckclib.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) \
+ ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) \
+ ckucmd.$(EXT) ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) \
+ ckuus5.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) \
+ ckuusy.$(EXT) ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) \
+ ckcftp.$(EXT) ck_ssl.$(EXT) $(LIBS)
+
+# SRP(TM) Version - Subject to USA export restrictions.
+
+srpmit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) \
+ ckcftp.$(EXT) ck_ssl.$(EXT)
+ $(CC2) $(LNKFLAGS) -o srpmit ckcmai.$(EXT) ckclib.$(EXT) \
+ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \
+ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \
+ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \
+ ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ck_ssl.$(EXT) \
+ ckcftp.$(EXT) $(LIBS)
+
+# Kerberized Version - Not subject to USA export restrictions.
+
+krbmit-export: ckcmai.$(EXT) \
+ ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckuath.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT)
+ $(CC2) $(LNKFLAGS) -o krbmit-export ckcmai.$(EXT) ckclib.$(EXT) \
+ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \
+ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \
+ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \
+ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(LIBS)
+
+# SRP(TM) Version - Not subject to USA export restrictions.
+
+srpmit-export: ckcmai.$(EXT) \
+ ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \
+ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \
+ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \
+ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \
+ ckuath.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT)
+ $(CC2) $(LNKFLAGS) -o srpmit-export ckcmai.$(EXT) ckclib.$(EXT) \
+ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \
+ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \
+ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \
+ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \
+ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \
+ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(LIBS)
+
+###########################################################################
+# man page...
+#
+ckuker.nr:
+ @echo This target is obsolete.
+ @echo The ckuker.nr file no longer needs any preprocessing.
+
+###########################################################################
+# Dependencies for each module...
+#
+ckcmai.$(EXT): ckcmai.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcnet.h ckcsig.h \
+ ckuusr.h ckctel.h ckclib.h
+
+ckclib.$(EXT): ckclib.c ckclib.h ckcdeb.h ckcasc.h ckcsym.h
+
+ckcpro.$(EXT): ckcpro.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckclib.h
+
+ckcpro.c: ckcpro.w wart ckcdeb.h ckcsym.h ckcasc.h ckcker.h ckcnet.h ckctel.h \
+ ckclib.h
+ ./wart ckcpro.w ckcpro.c
+
+ckcfns.$(EXT): ckcfns.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h ckcuni.h \
+ ckuxla.h ckclib.h ckcnet.h
+
+ckcfn2.$(EXT): ckcfn2.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \
+ ckuxla.h ckctel.h ckclib.h ckcnet.h ckcuni.h
+
+ckcfn3.$(EXT): ckcfn3.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \
+ ckuxla.h ckclib.h ckcuni.h
+
+ckuxla.$(EXT): ckuxla.c ckcker.h ckcsym.h ckcdeb.h ckcxla.h ckuxla.h ckclib.h \
+ ckcuni.h
+
+ckcuni.$(EXT): ckcuni.c ckcdeb.h ckcker.h ckucmd.h ckcuni.h ckcxla.h ckuxla.h
+
+ckuusr.$(EXT): ckuusr.c ckucmd.h ckcker.h ckuusr.h ckcsym.h ckcdeb.h ckcxla.h \
+ ckuxla.h ckcasc.h ckcnet.h ckctel.h ckclib.h ckcuni.h
+
+ckuus2.$(EXT): ckuus2.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \
+ ckcasc.h ckcnet.h ckcsym.h ckctel.h ckclib.h ckcuni.h
+
+ckuus3.$(EXT): ckuus3.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \
+ ckcasc.h ckcnet.h ckcsym.h ckctel.h ckclib.h ckcuni.h
+
+ckuus4.$(EXT): ckuus4.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \
+ ckcasc.h ckcnet.h ckuver.h ckcsym.h ckctel.h ckclib.h ckcuni.h
+
+ckuus5.$(EXT): ckuus5.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcnet.h \
+ ckcsym.h ckctel.h ckclib.h ckcxla.h ckuxla.h ckcuni.h
+
+ckuus6.$(EXT): ckuus6.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcnet.h \
+ ckcsym.h ckctel.h ckclib.h
+
+ckuus7.$(EXT): ckuus7.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \
+ ckcasc.h ckcnet.h ckcsym.h ckctel.h ckclib.h ckcuni.h
+
+ckuusx.$(EXT): ckuusx.c ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcsym.h \
+ ckcsig.h ckcnet.h ckctel.h ckclib.h ckcxla.h ckuxla.h ckcuni.h
+
+ckuusy.$(EXT): ckuusy.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \
+ ckclib.h
+
+ckucmd.$(EXT): ckucmd.c ckcasc.h ckucmd.h ckcdeb.h ckcsym.h ckctel.h ckclib.h
+
+ckufio.$(EXT): ckufio.c ckcdeb.h ckuver.h ckcsym.h ckclib.h \
+ ckcxla.h ckuxla.h ckcuni.h
+
+ckutio.$(EXT): ckutio.c ckcdeb.h ckcnet.h ckuver.h ckcsym.h ckctel.h ckclib.h
+
+ckucon.$(EXT): ckucon.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \
+ ckclib.h
+
+ckucns.$(EXT): ckucns.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \
+ ckclib.h ckcxla.h ckuxla.h ckcuni.h
+
+ckcnet.$(EXT): ckcnet.c ckcdeb.h ckcker.h ckcnet.h ckcsym.h ckcsig.h ckctel.h \
+ ckclib.h
+
+ckctel.$(EXT): ckcsym.h ckcdeb.h ckcker.h ckcnet.h ckctel.h ckclib.h
+
+# ck_off_t: ck_off_t.$(EXT)
+# $(CC) -o ck_off_t ck_off_t.$(EXT)
+
+wart: ckwart.$(EXT)
+ $(CC) $(LNKFLAGS) -o wart ckwart.$(EXT) $(LIBS)
+
+ckcmdb.$(EXT): ckcmdb.c ckcdeb.h ckcsym.h ckclib.h
+
+ckwart.$(EXT): ckwart.c
+
+ckudia.$(EXT): ckudia.c ckcker.h ckcdeb.h ckucmd.h ckcasc.h ckcsym.h ckcsig.h \
+ ckcnet.h ckctel.h ckclib.h
+
+ckuscr.$(EXT): ckuscr.c ckcker.h ckcdeb.h ckcasc.h ckcsym.h ckcsig.h \
+ ckcnet.h ckctel.h ckclib.h
+
+ckusig.$(EXT): ckusig.c ckcasc.h ckcdeb.h ckcker.h ckcnet.h ckuusr.h \
+ ckcsig.h ckctel.h ckclib.h
+
+ckcftp.$(EXT): ckcftp.c ckcdeb.h ckcasc.h ckcker.h ckucmd.h ckuusr.h \
+ ckcnet.h ckctel.h ckcxla.h ckuxla.h ckcuni.h
+
+ckupty.$(EXT): ckupty.c ckupty.h ckcdeb.h
+
+ckuath.$(EXT): ckuath.c ckcdeb.h ckucmd.h ckuath.h ckuat2.h ckctel.h \
+ ckclib.h ckcnet.h
+
+ck_crp.$(EXT): ck_crp.c ckcdeb.h ckcnet.h ckuath.h ckclib.h
+
+ck_ssl.$(EXT): ck_ssl.c ckcdeb.h ckucmd.h ckuath.h ckuat2.h ckctel.h \
+ ckclib.h ck_ssl.h
+
+###########################################################################
+#
+# Entries to make C-Kermit for specific systems.
+#
+# Put the ones that need short makefiles first.
+
+#Apollo Aegis 9.x. Includes TCP/IP support.
+#You can also add processor-dependent optimization switches like -M570.
+aegis:
+ @echo Making C-Kermit $(CKVER) for Apollo Aegis 9.x...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DNOCSETS -DCK_CURSES -O $(KFLAGS)" \
+ "LIBS = -lcurses -ltermcap"
+
+#Apple Mac II, A/UX pre-3.0
+#Warning, if "send *" doesn't work, try the auxufs makefile entry below.
+aux:
+ @echo Making C-Kermit $(CKVER) for Macintosh A/UX...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DAUX -DTCPSOCKET $(KFLAGS) -i -O" "LNKFLAGS = -i"
+
+#Apple Mac II, A/UX pre-3.0, compiled with gcc
+auxgcc:
+ @echo Making C-Kermit $(CKVER) for Macintosh A/UX...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DAUX -DTCPSOCKET -traditional $(KFLAGS) -i -O" \
+ "LNKFLAGS = " "CC = gcc" "CC2 = gcc"
+
+#Apple Mac II, A/UX, pre-3.0, but with ufs file volumes, uses <dirent.h>.
+auxufs:
+ @echo Making C-Kermit $(CKVER) for Macintosh A/UX...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DAUX -DTCPSOCKET -DDIRENT $(KFLAGS) -i -O" "LNKFLAGS = -i"
+
+#Apple Mac II, A/UX 3.0, compiled with gcc
+aux3gcc:
+ @echo Making C-Kermit $(CKVER) for Macintosh A/UX 3.0...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DAUX -DHDBUUCP -DLFDEVNO -DTCPSOCKET -DDIRENT $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = $(LIBS)" \
+ "CC=gcc -pipe -traditional" "CC2=gcc -pipe -traditional"
+
+#Apple Mac II, A/UX 3.0, compiled with gcc, uses curses
+aux3cgcc:
+ @echo Making C-Kermit $(CKVER) for Macintosh A/UX 3.0...
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) aux3gcc \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DCK_CURSES" "LIBS = -lcurses $(LIBS)"
+
+# Tenon MachTen, tested on Apple Powerbook with MachTen 2.1.1.D.
+# NOTE: This doesn't do anything about UUCP. It only works if /usr/spool/uucp
+# has permission of 777, and dialout device is world read/writeable.
+machten:
+ @echo Making C-Kermit $(CKVER) for MachTen...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD43 -DTCPSOCKET -DSIG_V -DNDGPWNAM -DCK_CURSES -O \
+ $(KFLAGS)" "LIBS=-lcurses -ltermcap"
+
+#Bell Labs Research UNIX V10
+#Can't add TCP/IP because there is no sockets library. It would have to
+#be done using streams, but there is no code in C-Kermit for that.
+#Remove -DNOJC if desired (if your system has csh, ksh, or bash).
+bellv10:
+ @echo Making C-Kermit $(CKVER) for Bell Labs Research UNIX V10...
+ $(MAKE) wermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBELLV10 -DBSD4 -DNDIR -DNOJC -DNOSYSIOCTLH -DNOSETREU \
+ -DNOCSETS -MINIDIAL $(KFLAGS)"
+
+# WARNING: The early BSD entries do not build in version 7.0 with the stock
+# BSD compiler: "Too many defines". Unless you can rebuild cpp to have more
+# space for defines, these builds must be accomplished by:
+# copying the /usr/include tree to someplace else, preprocessing there with cc
+# -E -I./include or whatever (plus all the same -D's, adding any necessary
+# -U/-D to override the architecture)), renaming the the resulting files back
+# to their original names, bringing them back to the original BSD system, and
+# running the make target there. This technique was used for 4.2 and 4.3 BSD
+# on a VAX in C-Kermit 7.0 (later, cpp on that machine was rebuilt to allow
+# more symbols, so the C-Kermit 8.0 build proceeds normally).
+
+#Berkeley Unix 4.1
+bsd41:
+ @echo Making C-Kermit $(CKVER) for 4.1BSD...
+ $(MAKE) wermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD41" "LIBS = -ljobs"
+
+#Berkeley 4.2, 4.3, also Ultrix-32 1.x, 2.x, 3.x, many others
+# Add -O, -s, etc, if they work.
+# If you have a version of BSD but signal() is void rather than int,
+# "make bsd KFLAGS=-DSIG_V".
+bsd42:
+ @echo Making C-Kermit $(CKVER) for 4.2BSD...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DNOREALPATH -DNOTIMEH -DNOIKSD \
+ -DCK_CURSES -DSYSTIMEBH -DNOPUTENV -DNOANSI -DBIGBUFOK -DBSD42HACK \
+ $(KFLAGS)" "LIBS=-lcurses -ltermcap $(LIBS)"
+
+bsd:
+ $(MAKE) CC=$(CC) CC2=$(CC2) bsd42 KTARGET=$${KTARGET-$(@)}
+
+#Berkeley Unix 4.2 or 4.3 with HoneyDanBer UUCP
+bsdhdb:
+ @echo Making C-Kermit $(CKVER) for 4.2BSD with HDB UUCP...
+ $(MAKE) CC=$(CC) CC2=$(CC2) bsd KTARGET=$${KTARGET-$(@)} \
+ "KFLAGS= -DHDBUUCP $(KFLAGS)"
+
+#Berkeley Unix 4.3 with acucntrl program, curses, TCP/IP included.
+bsd43:
+ @echo Making C-Kermit $(CKVER) for 4.3BSD...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DBSD43 -DTCPSOCKET -DNOREALPATH -DNOTIMEH -DNOIKSD \
+ -DCK_CURSES -DACUCNTRL -DSYSTIMEBH -DNOPUTENV -DNOANSI -DBIGBUFOK \
+ -DBSD42HACK $(KFLAGS)" "LIBS=-lcurses -ltermcap $(LIBS)"
+
+#4.3BSD, curses excluded
+bsd43nc:
+ @echo Making C-Kermit $(CKVER) for 4.3BSD...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DBSD43 -DTCPSOCKET -DNOREALPATH -DNOTIMEH \
+ -DACUCNTRL -DSYSTIMEBH -DNOIKSD -DNOPUTENV -DNOANSI -DBIGBUFOK \
+ -DBSD42HACK $(KFLAGS)" "LIBS=$(LIBS)"
+
+#4.3BSD, TCP/IP excluded.
+bsd43nonet:
+ @echo Making C-Kermit $(CKVER) for 4.3BSD + curses...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DBSD43 -DTCPSOCKET -DNOREALPATH -DNOTIMEH -DNOIKSD \
+ -DCK_CURSES -DACUCNTRL -DSYSTIMEBH -DNOPUTENV -DNOANSI -DBIGBUFOK \
+ -DBSD42HACK -DNONET $(KFLAGS)" "LIBS=-lcurses -ltermcap $(LIBS)"
+
+#Berkeley Unix 4.2 or 4.3 with lock directory /usr/spool/uucp/LCK/LCK..ttyxx,
+#but without acucntrl program
+bsdlck:
+ @echo Making C-Kermit $(CKVER) for 4.2BSD, /usr/spool/uucp/LCK/...
+ $(MAKE) CC=$(CC) CC2=$(CC2) bsd KTARGET=$${KTARGET-$(@)} \
+ "KFLAGS= -DLCKDIR $(KFLAGS)"
+
+#Berkeley UNIX 4.4-Lite, 4.4-Encumbered, Net/2, etc (Post-Reno),
+#with TCP/IP networking. This was the basis for FreeBSD, NetBSD, OpenBSD,
+#BSDI, BSD/OS, and Mac OS X (each of which has its own set of targets that
+#are newer than this one).
+#
+#NOTE: This is not a pure POSIX configuration. Using -DPOSIX instead of
+# -DBSD44 prevents any kind of directory-reading (for wildcard expansion),
+#and disallows use of ENOTCONN symbol for detecting broken network
+#connections, and disallows RTS/CTS flow control, and would also require
+#definition of the appropriate UUCP lockfile convention.
+#Do not add -DCK_POSIX_SIG without reading <signal.h> first! For example,
+#sigsetjmp(), etc, tend to be defined but not implemented.
+#
+#NOTE: originally crypt was in libc - later it was unbundled.
+#Remove the LIBS clause to build on an early 4.4BSD platform.
+#
+bsd44:
+ @echo Making C-Kermit $(CKVER) for 4.4BSD...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DTCPSOCKET $(KFLAGS) -O" "LIBS=-lcrypt"
+
+#Berkeley UNIX 4.4, as above, but with curses for fullscreen display
+#Please read notes for bsd44 entry just above.
+# NOTE: This one dumped core on the real 4.4BSD development system at
+# UC Berkeley (an HP-9000/300), so the no-curses version was used
+# for that one, which was unplugged years ago.
+bsd44c:
+ @echo Making C-Kermit $(CKVER) for 4.4BSD with curses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET $(KFLAGS) -O" \
+ "LIBS= -lcurses -ltermcap -lcrypt $(LIBS)"
+
+#For FreeBSD 1.x.
+freebsd1:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -funsigned-char \
+ -DFNFLOAT -DNOHTERMCAP -DNOREALPATH -DNOSYSCONF $(KFLAGS) -O -pipe" \
+ "LIBS= -lcurses -ltermcap -lm $(LIBS)"
+
+#FreeBSD 2.x with ncurses
+freebsd2:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD 2.x with ncurses...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_NCURSES -DTCPSOCKET -DNOCOTFMC -DUSE_STRERROR \
+ -DTPUTSARGTYPE=int -DTPUTSARG1CONST -DFREEBSD2 -funsigned-char \
+ -DFNFLOAT $(KFLAGS) -O -pipe" \
+ "LIBS= -lncurses -ltermlib -lcrypt -lm $(LIBS)"
+
+#For FreeBSD 2.x -- Uses curses rather than ncurses
+freebsd2c:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD 2.x with curses...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -DUSE_STRERROR \
+ -DTPUTSARGTYPE=int -DTPUTSARG1CONST -DFREEBSD2 -DFNFLOAT \
+ -funsigned-char $(KFLAGS) -O -pipe" \
+ "LIBS= -lcurses -ltermlib -lcrypt -lm $(LIBS)"
+
+#FreeBSD 3.x with ncurses and uu_lock()
+#(Note: uu_lock() goes back to 2.2.2, but not necessarily 2.0)
+#OK 2011/08/20 FreeBSD 3.3
+freebsd3:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD 3.x with ncurses...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_NCURSES -DTCPSOCKET -DNOCOTFMC -funsigned-char \
+ -DTPUTSARGTYPE=int -DUSE_STRERROR -DFREEBSD3 -DUSE_UU_LOCK -DFNFLOAT \
+ $(KFLAGS) -O -pipe" \
+ "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#As above but with curses rather than ncurses.
+freebsd3c:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD 3.x with curses...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -DUSE_UU_LOCK \
+ -DTPUTSARGTYPE=int -DUSE_STRERROR -DFREEBSD3 $(KFLAGS) -DFNFLOAT \
+ -funsigned-char -pipe -O" \
+ "LIBS= -lcurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.0 with ncurses and uu_lock(). Note - there is no curses in 4.0.
+#ncurses 5.0 is broken requiring us to work around with setbuf().
+freebsd40:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD 4.x with ncurses...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_NCURSES -DTCPSOCKET -DNOCOTFMC -DFNFLOAT \
+ -funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR -DFREEBSD4 \
+ -DNONOSETBUF -DUSE_UU_LOCK $(KFLAGS) -O -pipe" \
+ "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.1 and above
+#Like FreeBSD 4.0 but without the NONOSETBUF hack and with CK_NEWTERM.
+#NOTE: This target definitely does not work for FreeBSD 3.3 in 9.0.302.
+#and it has not been tested on 4 or 5.
+#OK 2011/06/xx FreeBSD 3.3, 4,4, 4.7, and 8.2
+#OK 2011/08/21 FreeBSD 3.3, 4.4, 6.4, 9.0
+freebsd freebsd41 freebsd72 freebsd5 freebsd6 freebsd7 freebsd8 freebsd9:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD 4.1 or later...'
+ @if test `uname -r | cut -d . -f 1` -ge 8; then \
+ HAVE_FBSD8='-DFREEBSD8'; \
+ else HAVE_FBSD8=''; fi; \
+ if test `uname -r | cut -d . -f 1` -ge 9; then \
+ HAVE_FBSD9='-DFREEBSD9'; \
+ else HAVE_FBSD9=''; fi; \
+ if test -f /usr/include/utmpx.h ; \
+ then HAVE_UTMPX='-DHAVEUTMPX' ; \
+ else HAVE_UTMPX='' ; fi; \
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+ -DFREEBSD4 $$HAVE_FBSD8 $$HAVE_FBSD9 -DUSE_UU_LOCK -DFNFLOAT \
+ $$HAVE_UTMPX -DHERALD=\"\\\" `uname -rs`\\\"\" \
+ -funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR $(KFLAGS) \
+ -O2 -pipe"\
+ "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 5.0 or later with OpenSSL.
+#OK 2011/06/15 FreeBSD 4.7 and 8.2
+#OK 2011/08/20 FreeBSD 9.0-CURRENT
+freebsd+ssl freebsd+openssl freebsd50+openssl:
+ @echo 'Making C-Kermit $(CKVER) for FreeBSD with Kerberos 5...'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) freebsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \
+ KFLAGS="-DCK_AUTHENTICATION -DCK_SSL $(SSLINC) -DZLIB $$OPENSSLOPTION \
+ $$HAVE_DES $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS= -lncurses -lcrypt -lssl -lcrypto -lutil -lm \
+ $(SSLLIB) $$DES_LIB $(LIBS)"; \
+ if [ ! -f ./wermit ] || [ ./ckcmai.o -nt ./wermit ] ; then \
+ echo ""; \
+ echo "If build failed try:"; \
+ echo ""; \
+ echo " make clean ; make $${KTARGET:-$(@)} KFLAGS=-UCK_DES"; \
+ echo ""; \
+ fi
+
+#NetBSD 1.4.1 or later with vanity banner automated with uname
+#and automatic inclusion of large file support if it is available.
+#This target tested successfully on NetBSD 1.4.1, 1.5.2, and 2.0.3 (Jan 2006).
+#Fails on NetBSD 2.0 on Sun/3 mc68030 with gcc 3.3.3 unless optimization is
+#disabled on ckcfn2.c ("KFLAGS=-O0") (Letter O Digit Zero).
+#(This could be automated by testing `uname -m` for "sun3".)
+#OK: 2011/06/15 on NetBSD 1.5.2 and 5.1.
+#OK: 2011/08/21 on 5.1.
+netbsd netbsd2 netbsd15 netbsd16 old-netbsd:
+ @echo Making C-Kermit $(CKVER) for NetBSD with curses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS=`grep fseeko /usr/include/stdio.h > /dev/null && \
+ echo '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'` \
+ -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR -DHAVE_OPENPTY \
+ -funsigned-char -DHERALD=\"\\\" NetBSD `uname -r`\\\"\" \
+ -DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DFNFLOAT $(KFLAGS) -O" \
+ "LIBS= -lcurses -lcrypt -lm -lutil $(LIBS)"
+
+#NetBSD 1.4.1 or later with OpenSSL
+#OK: 2011/06/15 on NetBSD 5.1 (but not 1.5.2 with OpenSSL 0.9.5a)
+#OK: 2011/08/21 on 5.1.
+netbsd+ssl netbsd+openssl:
+ @echo 'Making C-Kermit $(CKVER) for NetBSD+OpenSSL SSLLIB=$(SSLLIB)'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \
+ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \
+ -DCK_SSL -DCK_PAM -DZLIB -DNO_DCL_INET_ATON $$OPENSSLOPTION \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS= -L/usr/pkg/lib -R/usr/pkg/lib -lssl $$DES_LIB -lcurses \
+ -lcrypto -lcrypt -lz -lm -lpam -lutil $(LIBS)"
+
+#NetBSD with MIT Kerberos 5:
+# OK 2011/06/15 (once K5INC and K5LIB were set right).
+# NOT OK for Heimdal - Heimdal Kerberos support in C-Kermit needs work.
+# OK: 2011/08/21 on 5.1.
+netbsd+krb5:
+ @echo 'Making C-Kermit $(CKVER) for NetBSD with Kerberos 5...'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \
+ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_KERBEROS -DKRB5 \
+ -DCK_CAST $$HAVE_DES -DNOFTP_GSSAPI $(K5INC) $(K5INC)/krb5 \
+ $(KFLAGS)" \
+ "LIBS= $(K5LIB) -L/usr/pkg/lib -R/usr/pkg/lib -lcurses $$DES_LIB \
+ -lcrypto -lgssapi -lkrb5 -lm -lutil $(LIBS)"
+
+# NetBSD - With Kerberos 5 and SSL and Zlib.
+# OK: 2011/08/21 on 5.1 with MIT Kerberos.
+netbsd+krb5+ssl netbsd+krb5+openssl+zlib:
+ @echo 'Making C-Kermit $(CKVER) for NetBSD+OpenSSL+Kerberos5...'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \
+ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \
+ -DCK_KERBEROS -DKRB5 -DNOFTP_GSSAPI $(K5INC) $(K5INC)/krb5 \
+ -DCK_SSL -DCK_PAM -DZLIB -DNO_DCL_INET_ATON $$OPENSSLOPTION \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS= $(K5LIB) -L/usr/pkg/lib -R/usr/pkg/lib -lssl $$DES_LIB \
+ -lcrypto -lcrypt -lgssapi -lkrb5 -lz -lm -lpam -lutil -lcurses $(LIBS)"
+
+#Special Security Enhanced NetBSD target with SRP, SSL, and zlib support.
+#To build this, you need to BUILD the pkgsrc srp_client package. After
+#you build it, you must go into work/srp-x.y.z/libkrypto and "bmake install"
+#then go to work/srp-x.y.z/libsrp and "bmake install". As of 2005Q3, the
+#pkgsrc install only installed the statically linked client applications. You
+#need to manually install the libraries to build your own applications.
+#NOT TESTED RECENTLY - probably needs work.
+netbsd+ssl+srp+zlib:
+ @echo Making C-Kermit $(CKVER) for NetBSD with curses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR -DNETBSD15 \
+ -DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DHAVE_OPENPTY \
+ -I/usr/include/openssl -I/usr/pkg/include \
+ -DCK_AUTHENTICATION -DCK_SRP -DPRE_SRP_1_4_5 -DCK_ENCRYPTION \
+ -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DZLIB -DFNFLOAT $(KFLAGS) -O" \
+ "LIBS= -L/usr/pkg/lib -R/usr/pkg/lib -lcurses -lsrp -lgmp -ldes \
+ -lssl -lkrypto -lcrypto -lcrypt -lz -lm -lutil $(LIBS)"
+
+#NetBSD with curses left out (e.g. for use as IKSD).
+netbsdnc:
+ @echo Making C-Kermit $(CKVER) for NetBSD with no curses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) netbsd KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOCURSES"
+
+#NetBSD with ncurses requested explicitly rather than curses-which-is-ncurses
+netbsdn:
+ @echo Making C-Kermit $(CKVER) for NetBSD with curses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS=`grep fseeko /usr/include/stdio.h > /dev/null && \
+ echo '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'` \
+ -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR -DHAVE_OPENPTY \
+ -DHERALD=\"\\\" NetBSD `uname -r`\\\"\" \
+ -DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DFNFLOAT $(KFLAGS) -O" \
+ "LIBS= -L/usr/pkg/lib -lncurses -lcrypt -lm -lutil $(LIBS)"
+
+#OpenBSD before 2.3.
+#Uses ncurses as its curses so use -ltermlib, not -ltermcap
+#But it doesn't use uu_lock() which was introduced in OpenBSD 2.3.
+#For that use the next entry.
+#Add -DMAINTYPE=int if you get complaints about main: return type is not int.
+openbsdold:
+ @echo Making C-Kermit $(CKVER) for OpenBSD...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \
+ -DFNFLOAT -DNDSYSERRLIST $(KFLAGS) -O" "LIBS= -lcurses -ltermlib -lm"
+
+#OpenBSD 2.3 or later
+#Add -DMAINTYPE=int if you get complaints about main: return type is not int.
+#For C-Kermit 8.0 (Christian Weisgerber):
+# -ltermlib removed (presumably because -lcurses==ncurses already includes it)
+# -DUSE_UU_LOCK and -lutil added for uu_lock()
+# -DNDSYSERRLIST changed to -DUSE_STRERROR
+#If this gives you trouble use the previous entry.
+#NOTE: The openbsd and openbsd+ssl should be reworked to be like the
+#corresponding FreeBSD and NetBSD targets. The mirbsd targets should
+openbsd:
+ @echo Making C-Kermit $(CKVER) for OpenBSD 2.3 or later...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \
+ -DHERALD=\"\\\" OpenBSD `uname -r`\\\"\" \
+ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR $(KFLAGS) -O" \
+ "LIBS= -lcurses -lutil -lm"
+
+#Better to chain to the openbsd target but...
+mirbsd:
+ @echo Making C-Kermit $(CKVER) for OpenBSD 2.3 or later...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \
+ -DHERALD=\"\\\" MirBSD `uname -r`\\\"\" \
+ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR $(KFLAGS) -O" \
+ "LIBS= -lcurses -lutil -lm"
+
+#OpenBSD 3.0 or later includes OpenSSL
+#Add -DMAINTYPE=int if you get complaints about main: return type is not int.
+#For C-Kermit 8.0 (Christian Weisgerber):
+# -ltermlib removed (presumably because -lcurses==ncurses already includes it)
+# -DUSE_UU_LOCK and -lutil added for uu_lock()
+# -DNDSYSERRLIST changed to -DUSE_STRERROR
+#If this gives you trouble use the previous entry.
+openbsd+ssl:
+ @echo Making C-Kermit $(CKVER) for OpenBSD 3.0 or later...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \
+ -DHERALD=\"\\\" OpenBSD `uname -r`\\\"\" \
+ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR -DCK_AUTHENTICATION \
+ -DCK_SSL $(KFLAGS) -O" \
+ "LIBS= -lcurses -lutil -lm -lssl -lcrypto"
+
+mirbsd+ssl:
+ @echo Making C-Kermit $(CKVER) for OpenBSD 3.0 or later...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \
+ -DHERALD=\"\\\" MirBSD `uname -r`\\\"\" \
+ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR -DCK_AUTHENTICATION \
+ -DCK_SSL -DNO_DCL_INET_ATON $(KFLAGS) -O" \
+ "LIBS= -lcurses -lutil -lm -lssl -lcrypto"
+
+# make 386bsd 0.0new, posix
+# for 386bsd 0.1.24, change /usr/include/termios.h to #define NCCS if
+# _POSIX_SOURCE is #defined. (source: lewine, posix prgmrs guide, o`reilly)
+#NOTE: Lock directory is /var/spool/lock. Formerly, it was /var/spool/uucp,
+#but reportedly <wjones@halcyon.com> that was due to a typo in 'man tip'.
+386bsd:
+ @echo 'Making C-Kermit $(CKVER) for jolix 386BSD 0.0new and 0.1.24...'
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DSETREUID -DPIDSTRING -DUSLEEP \
+ -D_386BSD -DCK_CURSES -DTCPSOCKET \
+ -DLOCK_DIR=\\\"/var/spool/lock\\\" \
+ $(KFLAGS) -O" "LNKFLAGS = -s" "LIBS = -lcurses -ltermcap"
+
+# Mac OS X 10 early versions.
+# For 10.3.9 and later, use the macosx target below.
+
+#Mac OS X 1.0 (Rhapsody, Darwin) -- TCP/IP but no curses.
+oldmacosx10:
+ @echo Making C-Kermit $(CKVER) for `uname -s`...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DTCPSOCKET -DUSE_STRERROR -O $(KFLAGS)"
+
+#Mac OS X 1.0 (Rhapsody, Darwin) -- TCP/IP and curses.
+#Note: curses must be obtained separately. See next entry for ncurses.
+#Add "LIBS = -lcurses -ltermcap" if necessary (but reportedly it is not).
+oldmacosx10c:
+ @echo Making C-Kermit $(CKVER) for `uname -s` + curses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DCK_CURSES -DTPUTSFNTYPE=void -DTPUTSISVOID \
+ -DTCPSOCKET -DUSE_STRERROR -O $(KFLAGS)"
+
+#Mac OS X 1.0 (Rhapsody, Darwin) -- TCP/IP and ncurses.
+#Note: ncurses must be obtained separately.
+#In the event of trouble with this one try the next one.
+oldmacosx10nc:
+ @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DCK_NCURSES -DTCPSOCKET -DUSE_STRERROR -O \
+ $(KFLAGS)" "LIBS= -lncurses $(LIBS)"
+
+#Mac OS X 10.2 (Jaguar) ncurses.
+oldmacosx102nc:
+ @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DCK_NCURSES -DTCPSOCKET -DUSE_STRERROR -O \
+ $(KFLAGS) " "LIBS= -lncurses $(LIBS)"
+
+#The problem here is that if curses.h also exists, it conflicts with
+#ncurses.h and and we have fatal errors. If this happens to you, then
+#try this target.
+oldmacosx10ncx:
+ @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses...
+ @rm -f ./curses.h; touch ./curses.h
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DCK_NCURSES -DTCPSOCKET -DUSE_STRERROR \
+ -I. -O $(KFLAGS) " \
+ "LIBS= -lncurses $(LIBS)"
+ @rm -f ./curses.h
+
+#Mac OS X 10.3 (Panther) - Assumes ncurses is installed.
+oldmacosx103:
+ @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET -DCKHTTP \
+ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -O \
+ $(KFLAGS) " "LIBS= -lncurses -lresolv $(LIBS)"
+
+#Mac OS X 10.3 (Panther) with Kerberos 5 and SSL, assumes ncurses is installed.
+oldmacosx103+secure:
+ @echo Making Secure C-Kermit $(CKVER) for `uname -s` + ncurses...
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET \
+ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -O -DCK_PAM \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DZLIB \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \
+ $(KFLAGS) " "LIBS= -lssl -lcrypto -lkrb5 -lcom_err \
+ -lk5crypto -lgssapi_krb5 -lpam -lncurses -lresolv $(LIBS)"
+
+# THIS IS THE MAIN MAC OS X TARGET (the next one is for Kerberos/SSL builds).
+# Use this target for 10.3.9 (or maybe earlier) through 10.6 (maybe later)
+# on both Power and Intel architectures. This one uses utmp.h on 10.4 and
+# earlier and utmpx.h on 10.5 onwards.
+# Note: Mac OS X 10.5 and earlier are 32-bit; 10.6 and later 64-bit.
+# Note 2: As of C-Kermit 9.0 -NOUUCP is included by default because
+# Mac OS X doesn't support UUCP. To undo this, use KFLAGS=-UNOUUCP.
+#OK: 2011/06/14 (for 10.4.11, 10.5.8, 10.6.7)
+macosx macosx10 macosx10.3.9 macosx10.4 macosx10.5 macosx10.6:
+ @MACOSNAME=`/usr/bin/sw_vers -productName`; \
+ MACOSV=`/usr/bin/sw_vers -productVersion`; \
+ echo Making C-Kermit $(CKVER) for $$MACOSNAME $$MACOSV... ; \
+ MACCPU=$$HOSTTYPE; \
+ if test `uname -r | cut -d . -f 1` -gt 8; \
+ then if test -f /usr/include/utmpx.h ; \
+ then HAVE_UTMPX='-DHAVEUTMPX -D_UTMPX_COMPAT' ; \
+ else HAVE_UTMPX='' ; fi ; fi; \
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET -DCKHTTP \
+ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -DNOCHECKOVERFLOW -DFNFLOAT \
+ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $$HAVE_UTMPX \
+ -funsigned-char -DNODCLINITGROUPS \
+ -DNOUUCP -O -DHERALD=\"\\\" $${MACOSNAME} $${MACOSV}\\\"\" \
+ -DCKCPU=\"\\\"$${MACCPU}\\\"\" \
+ $(KFLAGS)" "LIBS= -lncurses -lresolv $(LIBS)"
+
+# Mac OS X 10.3.9 or later with Kerberos 5 and OpenSSL...
+# NOTE: Apple has removed all support for DES in OpenSSL and Kerberos
+# in Mac OS X 10.6 and later. The DES flags are included or left out
+# automatically based on the Mac OS X version number.
+# See note about UUCP in previous target.
+#OK: 2009/11/16 (for 10.3.9, 10.4.11, 10.5.8, 10.6.1)
+#OK: 2011/06/14 (for 10.4.11, 10.5.8, 10.6.7)
+macosx+krb5+ssl macosx10.5+krb5+ssl macosx10.6+krb5+ssl \
+macosx+krb5+openssl macosx10.5+krb5+openssl macosx10.6+krb5+openssl:
+ @MACOSNAME=`/usr/bin/sw_vers -productName`; \
+ MACOSV=`/usr/bin/sw_vers -productVersion`; \
+ echo Making C-Kermit $(CKVER) for $$MACOSNAME $$MACOSV... ; \
+ MACCPU=$$HOSTTYPE; \
+ if test `uname -r | cut -d . -f 1` -gt 8; \
+ then if test -f /usr/include/utmpx.h ; \
+ then HAVE_UTMPX='-DHAVEUTMPX -D_UTMPX_COMPAT' ; \
+ else HAVE_UTMPX='' ; fi ; fi; \
+ if test `uname -r | cut -d . -f 1` -eq 7; \
+ then IS_MACOSX103='-DMACOSX103' ; \
+ else IS_MACOSX103='' ; fi; \
+ case $$MACOSV in \
+ 10.[012345].*) HAVE_DES='-DCK_DES -DLIBDES' ;; \
+ *.*) HAVE_DES='' ;; \
+ esac ; \
+ if test -x /usr/bin/krb5-config ; \
+ then HAVE_KRB5CONFIG=`/usr/bin/krb5-config --libs krb5 gssapi` ; \
+ else HAVE_KRB5CONFIG='-lgssapi_krb5 -lkrb5 -lk5crypto \
+ -lcom_err -lresolv' ; fi; \
+ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMACOSX10 $$IS_MACOSX103 -DCK_NCURSES -DTCPSOCKET \
+ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -DNOCHECKOVERFLOW -DFNFLOAT \
+ -DCKHTTP -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $$HAVE_UTMPX \
+ -DNODCLINITGROUPS -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DZLIB \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_SSL -DOPENSSL_098 $$HAVE_DES \
+ -DNOUUCP -DHERALD=\"\\\" $${MACOSNAME} $${MACOSV}\\\"\" \
+ -DCKCPU=\"\\\"$${MACCPU}\\\"\" \
+ -funsigned-char -O $(KFLAGS)" \
+ "LIBS= $$HAVE_KRB5CONFIG -lssl -lcrypto -lpam -lncurses $(LIBS)"
+
+# End of Mac OS X Section
+
+#Acorn RISCiX, based on ...
+#Berkeley Unix 4.2 or 4.3 with lock directory /usr/spool/uucp/LCK/LCK..ttyxx,
+#but without acucntrl program
+riscix:
+ @echo Making C-Kermit $(CKVER) for RISCiX, /usr/spool/uucp/LCK..ttyxx
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD42 -DBSD4 -DRISCIX -DNOCSETS \
+ -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DDIRENT -DCK_CURSES \
+ -DMAXSP=9024 -DMAXRD=9024 -DSBSIZ=9050 -DRBSIZ=9050 \
+ -DDFTTY=\\\"/dev/serial\\\" -DNOCSETS -DNOCYRIL \
+ -DNOANSI -w -O2 -fomit-frame-pointer" \
+ "LIBS= -lcurses -ltermcap " \
+ "CC= /usr/ucb/cc" \
+ "CC2= /usr/ucb/cc"
+
+#Acorn RISCiX, as above, but using gcc
+riscix-gcc:
+ @echo Making C-Kermit $(CKVER) for RISCiX, /usr/spool/uucp/LCK..ttyxx
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD42 -DBSD4 -DRISCIX -DNOCSETS \
+ -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DDIRENT -DCK_CURSES \
+ -DMAXSP=9024 -DMAXRD=9024 -DSBSIZ=9050 -DRBSIZ=9050 \
+ -DDFTTY=\\\"/dev/serial\\\" -DNOCSETS -DNOCYRIL \
+ -DNOANSI -w -O2 -fomit-frame-pointer" \
+ "LIBS= -lcurses -ltermcap " \
+ "CC= gcc -mbsd" \
+ "CC2= gcc -mbsd"
+
+#Convergent CTIX 6.4.1
+ctix:
+ @echo 'Making C-Kermit $(CKVER) for Convergent CTIX 6.4.1'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSVR3 -DDIRENT -DTCPSOCKET -DHDBUUCP -DCK_CURSES \
+ -DNONAWS -DNOLEARN -DNOLONGLONG $(KFLAGS) -XO" \
+ "LNKFLAGS=-s" "LIBS=-lsocket -lcurses -lc_s"
+ mcs -d wermit
+
+# The following makefile entry should work for any Harris Night Hawk system
+# (either 88k or 68k based) running release 6.1 or later of the CX/UX
+# operating system. This is a POSIX and ANSI-C compliant system which also
+# supports BSD networking. (Earlier CX/UX releases will probably work with
+# sys5r3, but this has not been verified).
+#
+cx_ux:
+ @echo Making C-Kermit $(CKVER) for Harris Night Hawk CX/UX 6.1 or later
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS=-DPOSIX -DTCPSOCKET -DHDBUUCP -DPID_T=pid_t -DWAIT_T=int \
+ -Dd_ino=d_fileno -DUID_T=uid_t -DGID_T=gid_t -DNOLONGLONG \
+ $(KFLAGS) -Xa -O3 -g" "LNKFLAGS=-O3"
+
+#Intergraph Clipper, CLIX, job control, HDB UUCP.
+clix:
+ @echo 'Making C-Kermit $(CKVER) for Intergraph CLIX...'
+ $(MAKE) wermit "CC=acc" "CC2=acc" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -w -DSVR3 -DCLIX -DDIRENT -DHDBUUCP -DNOSYSLOG -DUSE_MEMCPY \
+ -DNOGETUSERSHELL -DNOREALPATH -DNOLEARN $(KFLAGS) -O" \
+ "LNKFLAGS=" "LIBS= -lbsd"
+
+#As above + TCP/IP...
+clixnet:
+ @echo 'Making networked C-Kermit $(CKVER) for Intergraph CLIX...'
+ $(MAKE) wermit "CC=acc" "CC2=acc" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -w -DSVR3 -DCLIX -DDIRENT -DHDBUUCP -DNOSYSLOG -DUSE_MEMCPY \
+ -DTCPSOCKET -DNOGETUSERSHELL -DNOLEARN -DNOREALPATH $(KFLAGS) -O" \
+ "LNKFLAGS=" "LIBS= -lbsd"
+
+#Mark Williams Coherent 286 or 386 on IBM PC family.
+#There is a 64K limit on program size, so this is a command-line only version.
+coherent:
+ $(MAKE) "CFLAGS = -O -DCOHERENT -DNOANSI -DNOICP -DNOSETKEY -DNOLEARN \
+ -DNOCSETS -DNOHELP -DNODIAL -DNOSCRIPT -DNODEBUG -DNOTLOG -DNOXMIT \
+ -DNOMSEND -DNOFRILLS -DNOSYSIOCTLH -DSELECT_H $(KFLAGS) -VSUVAR" \
+ -DNOFLOAT KTARGET=$${KTARGET:-$(@)} wermit
+
+#Mark Williams Coherent 386 on IBM PC family.
+#This will make a "minimum interactive" version - no scripts,
+#no character sets, no help, no dial, no debug/transaction logging, no
+#transmit, msend, mail, type, etc.
+coherentmi:
+ $(MAKE) "CFLAGS = -O -DCOHERENT -DNOANSI -DNOSETKEY -DNOLEARN \
+ -DNOSHOW -DNOCSETS -DNOHELP -DNODIAL -DNOSCRIPT -DNODEBUG -DNOTLOG \
+ -DNOXMIT -DNOMSEND -DNOFRILLS -DNOSYSIOCTLH -DNOSERVER -DNOUUCP \
+ -DNOSPL -DNOPUSH -DNOMDMHUP -DNOJC -DNOFDZERO -DNOESCSEQ -DNOFLOAT \
+ -DNOCMDL $(KFLAGS) -VSUVAR -DSELECT_H" KTARGET=$${KTARGET:-$(@)} \
+ wermit
+
+#Mark Williams Coherent 386 on IBM PC/AT family.
+coherentmax:
+ $(MAKE) "CFLAGS = -O -DCOHERENT -DNOANSI -DSELECT_H -DNOLEARN \
+ -DNOFLOAT -DNOSYSIOCTLH $(KFLAGS) -VSUVAR" "LNKFLAGS = -O -s" \
+ KTARGET=$${KTARGET:-$(@)} wermit
+
+#Mark Williams Coherent 386 4.2. Includes curses but not TCP/IP.
+#Requires updates to the 4.2.10 compiler; the regular compiler fails to
+#to handle "complex expressions". NOFLOAT is so it can work on old PCs
+#without floating-point hardware.
+coherent42:
+ $(MAKE) "CFLAGS = -T500000 -DNOFLOAT -DCOHERENT -DNOANSI -DSELECT \
+ -DNOSYSLOG -DDIRENT -DCK_CURSES -DCK_NEWTERM -DCK_WREFRESH -VSUVAR \
+ -DDCLGETCWD -DNOSYSIOCTLH -DNOINITGROUPS -DNOSYMLINK -DSELECT_H \
+ -DDCLGETCWD -O $(KFLAGS)" \
+ "LNKFLAGS = -O -s" KTARGET=$${KTARGET:-$(@)} \
+ "LIBS = -lsocket -lcurses" wermit
+
+#DEC Ultrix 2.x
+# Add -O, -DDYNAMIC, -s, etc, if they work.
+ultrix2x:
+ @echo Making C-Kermit $(CKVER) for Ultrix 2.x ...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DDU2 -DNOGETUSERSHELL $(KFLAGS)"
+
+du2:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix2x
+
+#DEC Ultrix 3.0 and 3.1
+ultrix30:
+ @echo Making C-Kermit $(CKVER) for Ultrix 3.0...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DDIRENT -DSIG_V -DNOGETUSERSHELL \
+ -DULTRIX3 -DCK_CURSES $(KFLAGS) -O" "LIBS= -lcurses -ltermcap"
+
+du3:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix30
+
+ultrix3x:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix30
+
+#DEC Ultrix 4.0 or 4.1 on DECstation, VAXstation, VAX, etc.
+ultrix40:
+ @echo Making C-Kermit $(CKVER) for Ultrix 4.0 or 4.1...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DDU4 -DNOGETUSERSHELL \
+ $(KFLAGS) -Olimit 1450" "LNKFLAGS = -s"
+
+#DEC Ultrix 4.2-4.5 on DECstation, DECsystem, VAXstation, VAX, etc.
+#Like ultrix40, except now C compiler supports -O2 optimization.
+ultrix42:
+ @echo Making C-Kermit $(CKVER) for Ultrix 4.2 or later...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL $(KFLAGS) \
+ -O2 -Olimit 1750" "LNKFLAGS = -s"
+
+du42:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix42
+
+#DEC Ultrix 4.2-4.5 on DECstation, DECsystem, VAXstation, VAX, etc.
+#Like du42, but with curses support added and a couple features.
+ultrix42c:
+ @echo Making C-Kermit $(CKVER) for Ultrix 4.2 or later...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL \
+ -DCK_CURSES -DNOIKSD $(KFLAGS)-G6 -O2 -Olimit 3000 " \
+ "LNKFLAGS = -s" "LIBS= -lcurses -ltermcap"
+
+ultrix43:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ "KFLAGS=-DULTRIX43 $(KFLAGS)" KTARGET=$${KTARGET-$(@)} ultrix42c
+
+ultrix43notcp:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ "KFLAGS=-DULTRIX43 -DNONET $(KFLAGS)" \
+ KTARGET=$${KTARGET-$(@)} ultrix42c
+
+# NOTE: need -DNODEBUG on MIPS to avoid relocation errors at link time.
+# Actually now (8.0) that we have discovered the -G option maybe debugging
+# can be put back.
+ultrix44:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ "KFLAGS=-DULTRIX44 -G7 -DNODEBUG -DNETPTY -DNO_DEVTTY $(KFLAGS)" \
+ KTARGET=$${KTARGET-$(@)} ultrix42c
+
+ultrix45:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ "KFLAGS=-DULTRIX45 $(KFLAGS)-DNETPTY -DNO_DEVTTY $(KFLAGS)" \
+ KTARGET=$${KTARGET-$(@)} ultrix42c
+
+du42c:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ KTARGET=$${KTARGET-$(@)} ultrix42c
+
+#DEC Ultrix 4.3A or later on DECsystem and DECstation 5000/50, /150 or /260
+#with MIPS R4x00 processor. The "-mips3" switch generates R4000-specific
+#code, which is faster and more compact, but *won't* run on earlier
+#DECsystems and DECstations.
+ultrix43-mips3:
+ @echo Making C-Kermit $(CKVER) for Ultrix 4.3A or later, R4000 cpu...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL \
+ $(KFLAGS) -O2 -Olimit 1750 -mips3" "LNKFLAGS = -s -mips3"
+
+du43-mips3:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) ultrix43-mips3
+
+#DEC Ultrix 4.3A or later on MIPS R4x000 based systems.
+#Like ultrix43-mips3 but with curses support added
+ultrix43c-mips3:
+ @echo Making C-Kermit $(CKVER) for Ultrix 4.3A or later, R4000 cpu...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL -DCK_CURSES \
+ $(KFLAGS) -O2 -Olimit 3000 -mips3" "LNKFLAGS = -s -mips3" \
+ "LIBS= -lcurses -ltermcap"
+
+du43c-mips3:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ KTARGET=$${KTARGET-$(@)} ultrix43c-mips3
+
+#DEC Ultrix 4.4 on DECstation 5000/50 or /150 with R4000 MIPS processor,
+#or 5000/260 with R4400. The "-mips3" switch generates R4000-specific code,
+#which is faster and more compact but *won't* run on earlier DECstations.
+ultrix44-mips3:
+ @echo Making C-Kermit $(CKVER) for Ultrix 4.4, R4000 cpu ...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL \
+ $(KFLAGS) -O2 -Olimit 1450 -mips3" "LNKFLAGS = -s -mips3"
+
+du44-mips3:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ KTARGET=$${KTARGET-$(@)} ultrix44c-mips3
+
+#DEC Ultrix 4.2 on DECstation, VAXstation, VAX, etc, System V R4 environment
+ultrix42s5r4:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4 on Ultrix...'
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS = -O2 -Olimit 1500 -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DTCPSOCKET $(KFLAGS)" "LNKFLAGS = -s"
+
+#OSF/1
+osf osf1:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \
+ -DCK_CURSES -DCK_RTSCTS -DFNFLOAT $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = $(LIBS) -lbsd -lcurses -ltermcap -lm"
+
+#DEC OSF/1 V1.0-1.3 on DECstation, VAX, Alpha, or PC.
+dec-osf dec-osf1:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD4 -DOSF -DOSF13 -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \
+ -DNOREALPATH -DNOIKSD -DCK_CURSES -DCK_RTSCTS -DFNFLOAT -DNODEBUG \
+ -DNOUNICODE $(KFLAGS)" \
+ "LNKFLAGS = -non_shared" "LIBS = -lbsd -lcurses -ltermcap -lm"
+
+# This one causes "relocation out-of-range" errors in the linker.
+old-dec-osf:
+ @echo Making C-Kermit $(CKVER) for DEC OSF/1 V1.x...
+ @echo If you are building for DEC OSF/1 2.0, please use dec-osf20.
+ @echo Remove or adjust -O2 and/or -Olimit if they cause trouble.
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -O2 -Olimit 2400 $(KFLAGS)"
+
+#DEC OSF/1 2.0 on Alpha and probably nowhere else.
+#The only difference from OSF/1 is that optimization is omitted.
+#The optimized version gets strange runtime errors, like the PAUSE command
+#not working. Add "-unsigned" to make all chars unsigned.
+dec-osf20:
+ @echo Making C-Kermit $(CKVER) for DEC OSF/1 V2.0...
+ @echo Optimization omitted because it causes runtime errors.
+ @echo See comments in makefile.
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF20 $(KFLAGS)"
+
+dec-osf30:
+ @echo Making C-Kermit $(CKVER) for DEC OSF/1 V3.0...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF30 -O2 -Olimit 2400 $(KFLAGS)"
+
+#Digital UNIX 3.2
+# Must compile ckuus[6x].c separately without optimization otherwise
+# the optimizer dumps core - keep CFLAGS here in sync with those from osf.
+du32:
+ @echo Making C-Kermit $(CKVER) for Digital UNIX 3.2...
+ $(MAKE) CC=$(CC) CC2=$(CC2) ckuus6.$(EXT) \
+ "CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \
+ -DCK_CURSES -DCK_RTSCTS -DFNFLOAT -DOSF32 -DHDBUUCP $(KFLAGS)"
+ $(MAKE) CC=$(CC) CC2=$(CC2) ckuusx.$(EXT) \
+ "CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \
+ -DCK_CURSES -DCK_RTSCTS -DFNFLOAT -DOSF32 -DHDBUUCP $(KFLAGS)"
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf \
+ "KFLAGS= -DOSF32 -DHDBUUCP -O2 -Olimit 3200 $(KFLAGS)"
+
+dec-osf32:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) du32 \
+ KTARGET=$${KTARGET:-$(@)}
+
+#Digital UNIX 4.0 through 4.0D (use tru64 targets for 4.0E and above)...
+du40:
+ @echo Making C-Kermit $(CKVER) for Digital UNIX 4.0...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF40 -DHDBUUCP -DFNFLOAT \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm"
+
+du40gcc:
+ @echo Making C-Kermit $(CKVER) for Digital UNIX 4.0 with gcc ...
+ $(MAKE) osf CC=gcc CC2=gcc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF40 -DHDBUUCP $(KFLAGS)"
+
+#Tru64 Unix 4.0E
+tru64-40e:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 4.0E...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF40 -DOSF40E -DTRU64 -DHDBUUCP -DFNFLOAT -DNOCOTFMC \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm"
+
+tru64-40f:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 4.0F...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF40 -DOSF40F -DTRU64 -DHDBUUCP -DFNFLOAT -DNOCOTFMC \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm"
+
+tru64-40g:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 4.0G...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF40 -DOSF40G -DTRU64 -DHDBUUCP -DFNFLOAT -DNOCOTFMC \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm"
+
+tru64-50a:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.0A...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DTRU64 -DOSF50 -DHDBUUCP \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)"
+
+tru64-51a:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.1A...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DHDBUUCP \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)"
+
+tru64-51b:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.1B...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DOSF51B -DHDBUUCP \
+ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)"
+
+# Added 5.1b version with OpenSSL - CDW 6-13-2005...
+tru64-51b+openssl:
+ @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.1b
+ @echo including OpenSSL...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DOSF51B -DHDBUUCP \
+ -unsigned -std1 -O3 -Olimit 2400 \
+ -DCK_AUTHENTICATION -DCK_SSL $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -rpath $(sslroot)/ssl/lib -lssl -lcrypto"
+
+du50:
+ $(MAKE) CC=$(CC) CC2=$(CC2) tru64-50a KTARGET=$${KTARGET:-$(@)}
+
+du40-ridiculous-checking:
+ @echo Making C-Kermit $(CKVER) for Digital UNIX 4.0.
+ @echo Checking everything - assumes DECC...
+ $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= -DOSF40 -DHDBUUCP -w0 -warnprotos -check -portable \
+ -unsigned -std1 -O3 -Olimit 1760 $(KFLAGS)"
+
+#Sequent DYNIX/ptx 1.2.1
+dynixptx12:
+ @echo Making C-Kermit $(CKVER) for Sequent DYNIX/ptx 1.2.1...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DPTX -DNOGETUSERSHELL -DNOLEARN \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i"
+
+#Sequent DYNIX/ptx 1.3 or 1.4
+dynixptx13:
+ @echo Making C-Kermit $(CKVER) for Sequent DYNIX/ptx 1.3 TCP/IP...
+ $(MAKE) xermit "CFLAGS= -O KTARGET=$${KTARGET:-$(@)} \
+ -DSVR3 -DDIRENT -DHDBUUCP -DPTX -DCK_POLL -DNOGETUSERSHELL \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DTCPSOCKET $(KFLAGS) -i" \
+ "LNKFLAGS = -i" "LIBS = -lsocket -linet -lnsl"
+
+#Sequent DYNIX/ptx 2.0, ANSI C compilation
+#Should work on any hardware platform when DYNIX/ptx runs, including
+#386, 486, Pentium.
+dynixptx20:
+ @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.0...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DHDBUUCP -DTCPSOCKET \
+ -DWAIT_T=int -DPTX -DNOGETUSERSHELL $(KFLAGS) -O" \
+ "LIBS = -lsocket -linet -lnsl"
+
+#Sequent DYNIX/ptx 2.0, ANSI C compilation, with curses
+dynixptx20c:
+ @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.0...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DHDBUUCP -DTCPSOCKET -DWAIT_T=int -DPTX -DCK_CURSES \
+ -DCK_NEWTERM -DNOGETUSERSHELL $(KFLAGS) -O" \
+ "LIBS = -lsocket -linet -lnsl -lcurses -ltermcap"
+
+#Sequent DYNIX/ptx 2.1.6, 80486, ANSI C compilation, with curses:
+# -Xa -- use ANSI compiler.
+# -Wc,-pw -- suppress portability warnings.
+# -Wc,-i386 -- 80386 cpu.
+# -Wc,-i486 -- 80486 cpu.
+# -Wc,-P5 -- Pentium (default).
+# -Wc,-O3 -- highest optimization.
+# -Wa,-N17061 -- increase symbol table from default of 15013 for ckcuni.c.
+# Early versions of DYNIX/ptx 2.1.x may need -DCK_POLL instead of -DSELECT.
+# Add "$&" after the colon in the "xermit" target for parallel makes.
+dynixptx216c:
+ @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.1.6'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DHDBUUCP -DDYNAMIC -DTCPSOCKET \
+ -DSELECT -DCK_REDIR -DCK_NAWS -DCK_WREFRESH -DSW_ACC_ID \
+ -DTCP_NODELAY=1 -DTRMBUFL=2048 -DBIGBUFOK -DHADDRLIST \
+ -DPTX -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL -DNOREALPATH \
+ $(KFLAGS) -Xa -Wc,-pw -Wc,-i486 -Wc,-O3 -Wa,-N17061" \
+ "LIBS = -lXbsd -lseq -lsocket -linet -lnsl -lmalloc -lm -lcurses" \
+ "LNKFLAGS = -s"
+
+#Sequent DYNIX/ptx 2.1.6, gcc 2.7.2.2, with curses:
+dynixptx216cgcc:
+ @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.1.6 gcc'
+ $(MAKE) xermit "CC = gcc" "CC2 = gcc" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DHDBUUCP -DDYNAMIC -DTCPSOCKET \
+ -DSELECT -DCK_REDIR -DCK_NAWS -DCK_WREFRESH -DSW_ACC_ID \
+ -DTCP_NODELAY=1 -DTRMBUFL=2048 -DBIGBUFOK -DHADDRLIST \
+ -DPTX -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL -DNOREALPATH \
+ $(KFLAGS) -O3 -pipe -funsigned-char" \
+ "LIBS = -lXbsd -lseq -lsocket -linet -lnsl -lmalloc -lm -lcurses" \
+ "LNKFLAGS = -s"
+
+#Sequent DYNIX/ptx 4.0, ANSI C compilation, with curses
+dynixptx41c:
+ @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 4.0...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DHDBUUCP -DTCPSOCKET \
+ -DWAIT_T=int -DPTX -DPTX4 -DCK_CURSES -DCK_NEWTERM \
+ -DNOGETUSERSHELL $(KFLAGS) -O" \
+ "LIBS = -lsocket -lnsl -lcurses -ltermcap"
+
+#Sequent DYNIX/ptx 4.4, ANSI C compilation, with curses
+dynixptx44:
+ @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 4.4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPTX -DPTX4 -DPOSIX -DHDBUUCP -DTCPSOCKET -DWAIT_T=int \
+ -DCK_CURSES -DCK_NEWTERM -DBIGBUFOK -DSELECT -DNOGETUSERSHELL \
+ $(KFLAGS) -O" "LIBS = -lsocket -lnsl -lcurses -ltermcap"
+
+#Sequent DYNIX 3.0.x
+dynix3:
+ @echo Making C-Kermit $(CKVER) for Sequent DYNIX 3.0.x...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD43 -DACUCNTRL -DTCPSOCKET -O \
+ -DPWUID_T=int -DGID_T=int $(KFLAGS)"
+
+#Sequent DYNIX 3.0.x, no ACUCNTRL
+dynix3noacu:
+ @echo Making C-Kermit $(CKVER) for Sequent DYNIX 3.0.x...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD43 -DLCKDIR -DTCPSOCKET -O \
+ -DUID_T=int -DGID_T=int $(KFLAGS)"
+
+#Sequent DYNIX 3.1.x
+dynix31:
+ @echo Making C-Kermit $(CKVER) for Sequent DYNIX 3.1.x...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DDCLPOPEN -DLCKDIR -DBSD4 -DTCPSOCKET $(KFLAGS)"
+
+#Sequent DYNIX 3.1.2, as above but with curses, to be compiled by gcc 2.3.3.
+dynix31c:
+ @echo 'Making C-Kermit $(CKVER) for Sequent DYNIX 3.1.2, curses...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O2 -DDCLPOPEN -DACUCNTRL \
+ -DBSD43 -DTCPSOCKET -DCK_CURSES -DUID_T=int \
+ $(KFLAGS)" "LIBS= -lcurses -ltermcap"
+
+#Convex C1 with Berkeley Unix
+convex:
+ @echo Making C-Kermit $(CKVER) for Convex C1 / BSD...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD4 -DNOLEARN $(KFLAGS) -Dmsleep=mnap"
+
+#Convex C210 with Convex/OS 8
+convex8:
+ @echo Making C-Kermit $(CKVER) for Convex C210 with OS 8
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DNODEBUG -DDIRENT -DNOFILEH \
+ $(KFLAGS) -DSIG_V -Dmsleep=mnap"
+
+#Convex C2 with Convex OS 9.1 (should also work with 8.1 or later)
+#with ANSI C compiler, uses BSD 4.3 uucp lockfile convention.
+convex9:
+ @echo Making C-Kermit $(CKVER) for Convex C210 with OS 9.1
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DCONVEX9 -DNOIEXTEN -DDIRENT -DNOFILEH -DTCPSOCKET \
+ -D__STDC__ -DLCKDIR -Dmsleep=mnap -O -ext -tm c1 $(KFLAGS)" \
+ "LNKFLAGS = -ext"
+
+#Convex C2 with Convex OS 10.1 or later
+#with gcc 2.x C compiler
+convex10gcc:
+ @echo Making C-Kermit $(CKVER) for Convex C2 with OS 10.1 using gcc
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DCONVEX9 -DNOIEXTEN -DDIRENT -DNOFILEH -DTCPSOCKET \
+ -D__STDC__ -Dmsleep=mnap -O2 $(KFLAGS)" CC=gcc CC2=gcc
+
+#Cray X-MP or Y-MP UNICOS 6.x or 7.x.
+#NOTE: NPROC tells how many parallel makes to run. If your Cray has multiple
+#processors, you can set NPROC up to the number of CPUs, e.g. NPROC=16.
+cray:
+ @echo 'Making C-Kermit $(CKVER) for Cray X/Y-MP UNICOS 6.x or 7.0...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS) -O1"
+
+#Cray X-MP or Y-MP UNICOS 8.0 Alpha.
+cray8:
+ @echo 'Making C-Kermit $(CKVER) for Cray X/Y-MP UNICOS 8.0 Alpha...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \
+ "CFLAGS= -DSVR4 -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS) -O1"
+
+#Cray X-MP or Y-MP UNICOS 9.0.
+#This one was executed successfully for C-Kermit 8.0.209.
+#Earlier versions of Unicos will probably need the same flags.
+cray9:
+ @echo 'Making C-Kermit $(CKVER) for Cray X/Y-MP UNICOS 9.0...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \
+ "CFLAGS= -DSVR4 -DDIRENT -DHDBUUCP -DNOLFDEVNO \
+ -DTCPSOCKET $(KFLAGS) -O1"
+
+#Cray-2 or Cray 3-CSOS
+#NOTE: NPROC tells how many parallel makes to run. If your Cray has multiple
+#processors, you can set NPROC up to the number of CPUs, e.g. NPROC=16.
+craycsos:
+ @echo 'Making C-Kermit $(CKVER) for Cray-2/3 CSOS
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ $(KFLAGS) -DCK_ANSIC -DCK_CURSES" "LIBS=-lnet"
+
+#NeXTSTEP 1.0 through 3.2.
+#Includes fullscreen file transfer display (curses) and TCP/IP support.
+#Uses shared library to make executable program about 80K smaller.
+#Remove "LIBS = -lsys_s" if this causes trouble.
+next:
+ @echo Making C-Kermit $(CKVER) for NeXTSTEP...
+ @echo 'If you get errors in ckutio.c about w_S, w_T, etc,'
+ @echo 'add KFGLAGS=-DNOREDIRECT to your make command.'
+ $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNEXT -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \
+ -pipe -DCK_CURSES $(KFLAGS) -O -w" "LIBS = -lsys_s -lcurses -ltermcap"
+
+nextc:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \
+ KTARGET=$${KTARGET:-$(@)}
+
+nextg:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \
+ KFLAGS=-Wall KTARGET=$${KTARGET:-$(@)}
+
+nextgc:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \
+ KFLAGS=-Wall KTARGET=$${KTARGET:-$(@)}
+
+#NeXTSTEP 3.3.
+#Includes fullscreen file transfer display and TCP/IP.
+# You might have to add 1 line to 1 NeXT header file <ip.h>
+# to declare n_long as u_long by adding #include <bsd/netinet/in_systm.h>
+
+next33:
+ @echo Making C-Kermit $(CKVER) for NeXTSTEP 3.3...
+ $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNEXT33 -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \
+ -pipe -DCK_CURSES $(KFLAGS) -O -w" "LIBS = -lsys_s -lcurses -ltermcap"
+
+#OPENSTEP 4.2 for Sparc, m680x0, HP PA-RISC, and Intel.
+#Includes fullscreen file transfer display and TCP/IP.
+#ckcpro.c compiled without optimization because it crashes the compiler.
+openstep42:
+ @echo Making C-Kermit $(CKVER) for OPENSTEP 4.2...
+ $(MAKE) ckcpro.$(EXT) \
+ "CFLAGS= -DOPENSTEP42 -DNEXT33 -DTCPSOCKET -DLCKDIR -DNOPUTENV \
+ -DFNFLOAT -pipe -DCK_CURSES $(KFLAGS) -w"
+ $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DOPENSTEP42 -DNEXT33 -DTCPSOCKET -DLCKDIR -DNOPUTENV \
+ -DFNFLOAT -pipe -DCK_CURSES $(KFLAGS) -O -w" \
+ "LIBS = -lsys_s -lcurses -ltermcap"
+
+#NeXT with malloc debugger
+nextmd:
+ @echo Making C-Kermit $(CKVER) for NeXT with malloc debugging...
+ $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNEXT -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \
+ -DCK_CURSES $(KFLAGS) -O -w -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG" \
+ "LIBS = -lsys_s -lcurses -ltermcap"
+
+#Build for NeXTSTEP with "fat" binaries (MABs) that run on both Motorola
+#and Intel platforms.
+nextfat:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+ next KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-Wall -arch m68k -arch i386" "LNKFLAGS = -arch m68k -arch i386"
+
+#NeXTSTEP on Intel Platforms.
+next486:
+ @echo Making C-Kermit $(CKVER) for NeXTSTEP on Intel Platforms...
+ @echo 'If you get errors in ckutio.c about w_S, w_T, etc,'
+ @echo 'add KFGLAGS=D-DNOREDIRECT to your make command.'
+ $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNEXT -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \
+ -DNODEBUG -O3 -fno-omit-frame-pointer -fschedule-insns2 -pipe \
+ -DCK_CURSES $(KFLAGS) -w" "LIBS = -lsys_s -lcurses -ltermcap"
+
+#Single binary that runs on NeXT 68030 and 68040, Intel, HP, and Sparc,
+#as well as on OpenStep/Mach.
+nextquadfat:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-Wall -arch m68k -arch i386 -arch hppa -arch sparc" \
+ "LNKFLAGS = -arch m68k -arch i386 -arch hppa -arch sparc"
+
+#BeBox
+beboxdr7:
+ @echo 'Making C-Kermit $(CKVER) for the BeBox...'
+ @echo 'Link step will fail with default Metroworks linker 64K limit.'
+ @echo 'Code Warrior Gold required to link big programs.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CC=/boot/develop/tools/mwcc" "CC2=/boot/develop/tools/mwld" \
+ "CFLAGS= -DBEBOX -DBE_DR_7 -DPOSIX -DNOUUCP -DNOLEARN $(KFLAGS) -O"
+
+#BeBox BeOS DR7 only
+bebox:
+ @echo 'Making C-Kermit $(CKVER) for BeBox...'
+ @echo 'Link step will fail with default Metroworks linker 64K limit.'
+ @echo 'Code Warrior Pro 3.0 for BeBox required to link big programs.'
+ $(MAKE) wermit "CC=mwcc" "CC2=mwld" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBEBOX -DPOSIX -DNOLEARN -DNOUUCP $(KFLAGS) -O"
+
+#BeOS 4.5
+#We have to use the wermit target because 'fd_set' is unknown.
+beos45:
+ $(MAKE) wermit "CC=$(CC)" "CC2=$(CC2)" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBEOS -DBEOS45 -DPOSIX -DNOIKSD -DNOREALPATH -DSYSTIMEH \
+ -DNOCOTFMC -DNOUUCP -DNOLEARN $(KFLAGS) -O" \
+ "LIBS = $(LIBS)"
+
+#BeOS 4.5
+beos45net:
+ $(MAKE) CC=$(CC) CC2=$(CC2) beos45 \
+ "KFLAGS=-DTCPSOCKET -DNO_DNS_SRV $(KFLAGS)" "LIBS=-lnet -lnetapi"
+
+#Plan 9 from Bell Labs
+plan9:
+ @echo 'C-Kermit for Plan 9 from Bell Labs - calling ckpker.mk...'
+ make -f ckpker.mk
+
+#POSIX
+posix:
+ @echo 'Making C-Kermit $(CKVER) for pure POSIX...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DNOUUCP -DNOLEARN $(KFLAGS) -O"
+
+# PowerMAX OS (SVR4) from Concurrent (tested on PowerMAX 5.1)
+powermax:
+ @echo 'Making C-Kermit $(CKVER) for Concurrent PowerMAX OS...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DPOWERMAX \
+ -DNETPTY -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \
+ -DPUSH_LDTERM -DPUSH_TTCOMPAT \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lresolv -lcurses -lgen -lc -lucbc"
+
+#Berkeley Software Design Inc. BSDI
+# Substitute "LIBS= -lnewcurses -ltermcap" if desired.
+bsdi:
+ @echo 'Making C-Kermit $(CKVER) for BSDI ...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD44 -DSETREUID -DSW_ACC_ID -DBIGBUFOK -DFIXCRTSCTS \
+ -DTCPSOCKET -DCK_CURSES -DFNFLOAT $(KFLAGS) -O" \
+ "LIBS= -lcurses -ltermcap -lm"
+
+#Berkeley Software Design Inc. BSDI - has higher serial speeds than 1.x.
+bsdi2:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DBSDI2 $(KFLAGS)"
+
+bsdi3:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DBSDI2 -DBSDI3 $(KFLAGS)"
+
+bsdi4:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DBSDI2 -DBSDI3 -DBSDI4 -DTPUTSFNTYPE=void -DTPUTSISVOID \
+ -DCKHTTP -m486 $(KFLAGS)"
+
+# (old name for the above)
+bsdiposix:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi
+
+
+#Build a BSDI 4.x binary that also runs under FreeBSD (Terry Kennedy).
+#But watch out for details like serial-port locking.
+bsdix:
+ $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DBSDI2 -DBSDI3 -DBSDI4 -DTPUTSFNTYPE=void -DTPUTSISVOID \
+ -m486 $(KFLAGS)" "LNKFLAGS=-static -Wl,-m,i386bsdi -Wl,-e,_start"
+
+#Pyramid 9XXX (e.g. 9845) or MIServer T series, OSx 4.4b thru 5.1
+pyramid:
+ @echo Making C-Kermit $(CKVER) for Pyramid Dual Port OSx
+ ucb $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD43 -DTCPSOCKET -DPYRAMID -O $(KFLAGS)" "LNKFLAGS = -s"
+
+#Pyramid Dual Port OSx using HoneyDanBer UUCP, curses and TCP
+pyramid-hdb:
+ @echo Making C-Kermit $(CKVER) for Pyramid Dual Port OSx
+ ucb $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DBSD43 -DTCPSOCKET -DHBDUUCP -DCK_CURSES -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lcurses -ltermcap"
+
+#Pyramid DC/OSx (UNIX System V R4).
+#Has <sys/termiox.h>, regular Berkeley sockets library, i.e. in.h and inet.h
+#are not misplaced in sys (rather than netinet and arpa, respectively).
+#Uses ANSI C.
+#NOTE: Remove -O and Olimit:2500 from CFLAGS if TELNET connections do not work.
+pyrdcosx:
+ @echo 'Making C-Kermit $(CKVER) for Pyramid DC/OSx...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -Xa -O -DSVR4 -DDIRENT -DHDBUUCP -DSELECT -DNOGETUSERSHELL \
+ -DCK_CURSES -DSTERMIOX -DTCPSOCKET -DPYRAMID -K Olimit:3100 \
+ -DNO_DNS_SRV $(KFLAGS)" "LIBS= -lcurses -lsocket -lnsl" "LNKFLAGS = -s"
+
+#IBM's AIX 3.0 on IBM 370 mainframe, tested on AIX F44 thru F50.
+aix370:
+ @echo Making C-Kermit $(CKVER) for IBM System/370 AIX 3.0...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIX370 -DTCPSOCKET -DLCKDIR -DDIRENT $(KFLAGS)" \
+ "LIBS = -lbsd"
+
+#IBM's AIX/ESA 2.1 (OSF/1) on IBM mainframe
+aixesa:
+ @echo Making C-Kermit $(CKVER) for IBM AIX/ESA...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXESA -DTCPSOCKET $(KFLAGS) -O"
+
+#IBM PS/2 with AIX 1.0 thru 1.3.
+# Reports indicate that -O switch must be omitted.
+# It is also possible that "make bsd" will work (reports welcome).
+# One report said "make LIBS=-lbsd bsd" did the trick.
+# NOTLOG is to get around a 'tlog' symbol defined in one of the headers.
+ps2aix:
+ @echo 'Making C-Kermit $(CKVER) for IBM AIX 1.x PS/2...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DNOREALPATH -DPS2AIX10 -DSIG_V \
+ -DNOUNICODE -DNOTLOG -DNOLEARN $(KFLAGS) -i" \
+ "LNKFLAGS = -i"
+
+ps2aixnetc:
+ @echo 'Making C-Kermit $(CKVER) for IBM AIX 1.x PS/2...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DNOREALPATH -DPS2AIX10 -DTCPSOCKET -DCK_CURSES \
+ -DSIG_V -DNOUNICODE -DNOTLOG -DNOLEARN $(KFLAGS) -i" \
+ "LIBS = -lcurses" "LNKFLAGS = -i"
+
+ps2aix3:
+ $(MAKE) ps2aix KTARGET=$${KTARGET:-$(@)}
+
+#IBM RT PC with AIX 2.2.1, valid as of C-Kermit 8.0.
+#NOTLOG because of a conflict in <sys/termio.h>.
+#This one has unique and strange lockfiles.
+# -O removed on purpose (8.0).
+# In case of "compiler error: symbol table full", increase the -Nn number.
+# In case of "compiler error: Constant pool too big", boost the -Np number.
+# Add -DNOPUTENV if putenv() causes trouble.
+# Put -DNOIKSD back if IKSD-related problems occur.
+rtaix:
+ @echo 'Making C-Kermit $(CKVER) for IBM RT PC, AIX 2.2.1...'
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS = -DATTSV -DRTAIX -DHDBUUCP -DDIRENT -DNOTLOG -DTCPSOCKET \
+ -DNOGETUSERSHELL -DCLSOPN -DNOREALPATH -DNOUNICODE -DBSD_INCLUDES \
+ -DUSE_LSTAT -DFNFLOAT -Nn2500 -Np1000 -Wq,-SJ2 -a -w $(KFLAGS)" \
+ "LIBS = -lm $(LIBS)" "LNKFLAGS = -s"
+
+#### IBM RT PC - these targets were last verified in C-Kermit 8.0.211.
+
+#IBM RT PC with AIX 2.2.1 + curses
+rtaixc:
+ $(MAKE) rtaix CC=$(CC) CC2=$(CC2) "KFLAGS=-DCK_CURSES" "LIBS=-lcurses"
+
+#IBM RT PC with AIX (ACIS) 2.2.1 (BSD 4.3)
+# Add -O, -DDYNAMIC, -s, etc, if they work.
+rtacis:
+ @echo Making C-Kermit $(CKVER) for RT PC with ACIS 2.2.1 = BSD 4.3...
+ $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DNOREALPATH -DNOIKSD -DNOPUTENV \
+ $(KFLAGS) -U__STDC__" "LNKFLAGS = -s"
+
+#### IBM AIX. The first two targets should work for any version of AIX
+#### from 4.2 onwards. The ones after that are for older versions or
+#### specific configurations, and/or with gcc.
+
+# This one should work for any AIX 4.2 or later: "make aix".
+# Other tags are for compatibility with old makefile targets.
+#OK: 2011/06/11
+aix aix42 aix43 aix44 aix45 aix50 aix51 aix52 aix53 aix54 aix61:
+ @echo Making C-Kermit $(CKVER) for IBM AIX...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \
+ -DSELECT -DSELECT_H -DNOGETUSERSHELL -qmaxmem=16000 -O \
+ -DCKCPU=\\\"`uname -p`\\\" \
+ -DHERALD=\"\\\" IBM AIX `uname -v`.`uname -r`\\\"\" \
+ -D_LARGE_FILES $(KFLAGS)" "LNKFLAGS = -s" "LIBS=-lcurses -lm"
+
+# Same but using gcc instead of cc
+# This works but we get "gcc: unrecognized option '-qmaxmem-..'" each module.
+aixg:
+ @echo "Using gcc..."
+ $(MAKE) aix KTARGET=$${KTARGET:-$(@)} \
+ CC=gcc CC2=gcc "KFLAGS=-pipe -funsigned-char"
+
+# AIX 4.2 or later with OpenSSL 0.9.7 or later: "make aix+ssl"
+# For earlier OpenSSL remove -DOPENSSL_097 or add "KFLAGS=-UOPENSSL_097".
+# Synonym target names added to cover old redundant targets that were removed.
+# If SSL is not installed in the /usr/local tree (see SSLINC and SSLLIB
+# definitions near the top), you can specify the locations in your make
+# command as in this example:
+#
+# SSLINC=-I/opt/ssl/include SSLLIB=-L/opt/ssl/lib make -e aix+ssl
+#
+# To build with gcc use "make aix CC=gcc CC2=gcc", or "make aixg"
+#
+#OK: 2011/06/15
+aix+ssl aix51+openssl aix52+openssl aix53+openssl:
+ @echo "Making C-Kermit $(CKVER) for IBM AIX with OpenSSL..."
+ @echo "SSLINC=$(SSLINC) SSLLIB=$(SSLLIB)"
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ CC=$(CC) CC2=$(CC2) \
+ "CFLAGS=-DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \
+ -D_LARGE_FILES -DSELECT -DSELECT_H -DNOGETUSERSHELL \
+ -DCKCPU=\\\"`uname -p`\\\" \
+ -DHERALD=\"\\\" IBM AIX `uname -v`.`uname -r`\\\"\" \
+ -DCK_AUTHENTICATION -DCK_SSL -DOPENSSL_097 $(SSLINC) $(KFLAGS)" \
+ "LNKFLAGS=-s" "LIBS=$(SSLLIB) -lssl -lcrypto -lcurses -lm -lcrypt"
+
+# AIX 5.3 or 6.1 or later with IBM OpenSSL, which is always in the directories
+# shown below so you don't have to set SSLINC and SSLLIB. If for some reason
+# the SSL include files and libraries are not in the places assumed, then use
+# "make aix+ssl" (just above) and set SSLINC and SSLLIB to indicate where the
+# SSL files are. To build with gcc use "make aix+ibmssl CC=gcc CC2=gcc".
+aix+ibmssl:
+ @echo "Making C-Kermit $(CKVER) for IBM AIX 6.1 with OpenSSL..."
+ @echo "If this fails use 'make aix+ss' and specify SSLINC and SSLLIB"
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ CC=$(CC) CC2=$(CC2) \
+ "CFLAGS=-DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \
+ -D_LARGE_FILES -DSELECT -DSELECT_H -DNOGETUSERSHELL \
+ -DCKCPU=\\\"`uname -p`\\\" \
+ -DHERALD=\"\\\" IBM AIX `uname -v`.`uname -r`\\\"\" \
+ -DCK_AUTHENTICATION -DCK_SSL -DOPENSSL_098 \
+ -I/usr/include/openssl $(KFLAGS)" \
+ "LNKFLAGS=-s" \
+ "LIBS=-L/usr/lib/openssl -lssl -lcrypto -lcurses -lm -lcrypt"
+
+# Old AIX versions...
+
+#IBM AIX 3.0, 3.1, or 3.2 for RISC System/6000.
+rs6000:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 3.0 or 3.1, RS/6000...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR3 -DDIRENT -DCK_ANSIC \
+ -DCK_POLL -DCLSOPN -DSELECT_H -DNOTTYLOCK -O $(KFLAGS)" \
+ "LNKFLAGS = -s"
+
+#IBM AIX 3.0, 3.1, or 3.2 for RISC System/6000, with curses.
+rs6000c:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 3.0 or 3.1, RS/6000...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR3 -DDIRENT -DCK_ANSIC \
+ -DCK_POLL -DCLSOPN -DCK_CURSES -DSELECT_H -DNOTTYLOCK -DNOREALPATH \
+ -O $(KFLAGS)" "LIBS= -lcurses -ltermcap" "LNKFLAGS = -s"
+
+aix30:
+ $(MAKE) rs6000 CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)}
+
+aix31:
+ $(MAKE) rs6000 CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)}
+
+#IBM AIX 3.2 for RISC System/6000.
+#In case of "subprogram too complex" warnings, add "-qmaxmem=16000" to CFLAGS.
+rs6aix32:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 3.2, RS/6000...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR4 -DDIRENT -DCK_ANSIC -DNOREALPATH \
+ -DSELECT_H -DCLSOPN -DNOTTYLOCK -O $(KFLAGS)" "LNKFLAGS = -s"
+
+#IBM AIX 3.2 for RISC System/6000.
+rs6aix32c:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 3.2, RS/6000, TCP+curses...
+ @echo In case of Subprogram Too Complex warnings,
+ @echo add -qmaxmem=16000 to CFLAGS.
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR4 -DDIRENT -DCK_ANSIC -DNOREALPATH \
+ -DCLSOPN -DCK_CURSES -DSELECT_H -DNOTTYLOCK -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS=-lcurses"
+
+aix32:
+ $(MAKE) rs6aix32c KTARGET=$${KTARGET:-$(@)}
+
+#IBM AIX 4.1, 4.1.x on RISC System/6000 or Power Series.
+#Generates common binary for all platforms if using xlc (IBM C compiler).
+#When using gcc, add -mcpu=common to generate common binary.
+#Note that this one needs CK_NEWTERM.
+# Add -bbigtoc in case ld fails with TOC overflow.
+aix41:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \
+ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -qmaxmem=16000 -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS=-lcurses"
+
+#Ditto but with gcc.
+#Remove "CC=gcc CC2=gcc" if you have gcc installed as cc.
+aix41g:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=gcc" "CC2=gcc" \
+ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \
+ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -O $(KFLAGS)" \
+ "LNKFLAGS = -s -Xlinker -bbigtoc" "LIBS=-lcurses"
+
+# Add -bbigtoc in case ld fails with TOC overflow.
+aix41+krb5+krb4:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \
+ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_DES $(K5INC) $(K5INC)/krb5 \
+ -DNOGETUSERSHELL -qmaxmem=16000 -O $(KFLAGS)" \
+ "LNKFLAGS = -s" \
+ "LIBS = $(K5LIB) -lcurses -lkrb4 -ldes425 -lkrb5 \
+ -lcom_err -lk5crypto -lgssapi_krb5"
+
+#Old name for "aix41".
+rs6aix41c:
+ $(MAKE) aix41 KTARGET=$${KTARGET:-$(@)}
+
+#IBM AIX 4.1, 4.1.x, or 4.2 on RISC System/6000 or Power Series,
+# with X.25 support
+#Generates common binary for all platforms if using xlc (IBM C compiler).
+#When using gcc, add -mcpu=common to generate common binary.
+# Add -bbigtoc in case ld fails with TOC overflow.
+aix41x25:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \
+ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DIBMX25 -DDEBUG -DNOGETUSERSHELL -qmaxmem=16000 -g $(KFLAGS)" \
+ "LNKFLAGS = -g -bI:/lib/pse.exp" "LIBS=-lcurses -lodm -lcfg"
+ -@echo "^[]0;kermit done\a\c"
+
+#As above but without -g in LNKFLAGS.
+# Add -bbigtoc in case ld fails with TOC overflow.
+aix41x25o:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \
+ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DIBMX25 -DNODEBUG -DNOGETUSERSHELL -qmaxmem=16000 $(KFLAGS)" \
+ "LNKFLAGS = -bI:/lib/pse.exp" "LIBS=-lcurses -lodm -lcfg"
+ -@echo "^[]0;kermit done\a\c"
+
+#AIX 4.2 -- Use this target if the regular "make aix" doesn't work.
+# Must have CK_NEWTERM or echoing is lost after curses.
+# Add -bbigtoc in case ld fails with TOC overflow. As of C-Kermit 8.0.212,
+# all AIX builds 4.2 and later include large file support.
+oldaix42:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.2 or higher...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \
+ -DSELECT -DSELECT_H -DNOGETUSERSHELL -qmaxmem=16000 -O \
+ -DCKCPU=\\\"`uname -p`\\\" \
+ -DHERALD=\\\"\ IBM\ AIX\ `uname -v`.`uname -r`\\\" \
+ -D_LARGE_FILES $(KFLAGS)" "LNKFLAGS = -s" "LIBS=-lcurses -lm"
+
+#AIX 4.3 - Use this target if the regular "make aix" doesn't work.
+# Must NOT have CK_NEWTERM or else C-Kermit hangs after curses.
+# -bbigtoc needed on some systems but not others to avoid TOC overflow.
+# "man ld" says -bbigtoc makes program run slower.
+oldaix43:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DAIX43 -DSVR4 -DSTERMIOX -DTCPSOCKET \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DFNFLOAT -DNOGETUSERSHELL -qmaxmem=16000 -bbigtoc -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS=-lcurses -lm"
+
+#AIX 4.3 with IBM X.25.
+aix43x25:
+ @echo "Making C-Kermit $(CKVER) for IBM AIX 4.3 with X.25..."
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DAIXRS -DAIX41 -DAIX43 -DSVR4 -DSTERMIOX -DTCPSOCKET \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DFNFLOAT -DNOGETUSERSHELL -DIBMX25 \
+ -qmaxmem=16000 -bbigtoc -O $(KFLAGS)" \
+ "LNKFLAGS = -bI:/lib/pse.exp" "LIBS=-lcurses -lodm -lcfg -lm"
+
+#AIX 4.3 -- Must NOT have CK_NEWTERM or else C-Kermit hangs after curses.
+# -mminimal-toc needed on some systems but not others to avoid TOC overflow.
+# "man ld" says -bbigtoc makes program run slower.
+aix43g:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \
+ "LIBS=-lcurses -lm"
+
+aix43gcc:
+ $(MAKE) aix43g
+
+# None of the following aix43gcc attempts work on a gcc-only AIX 4.3.3 box.
+# It just plain can't find the math routines (fmod, pow, exp, sqrt, log10,...)
+# Which is odd because nm /usr/lib/libC.a finds them...
+
+#in case aix43gcc can't find its math library...
+aix43gccx:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \
+ "LIBS= -L/usr/local/lib/gcc-lib/powerpc-ibm-aix4.3.1.0/2.95.2 \
+ -lcurses -bloadmap -bnoquiet"
+
+#in case aix43gccx can't find its math library...
+aix43gccy:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \
+ "LIBS= -lcurses -bloadmap -bnoquiet"
+
+#in case aix43gccx can't find its math library...
+aix43gccz:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \
+ "LIBS= -L. -lcurses -bloadmap -bnoquiet"
+
+#AIX 4.3 with MIT Kerberos 5 and Kerberos 4 compatibility mode
+# Must NOT have CK_NEWTERM or else C-Kermit hangs after curses.
+# -mminimal-toc needed on some systems but not others to avoid TOC overflow.
+# "man ld" says -bbigtoc makes program run slower.
+aix43gcc+krb5+krb4:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher w/Kerberos...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_DES -funsigned-char $(K5INC) $(K5INC)/krb5 \
+ $(KFLAGS)" \
+ "LIBS=$(K5LIB) -lcurses -lm -lkrb4 -ldes425 -lkrb5 \
+ -lcom_err -lk5crypto -lcrypt -lgssapi_krb5"
+
+#AIX 4.3 with MIT Kerberos 5, Kerberos 4 compatibility mode and OpenSSL
+# Must NOT have CK_NEWTERM or else C-Kermit hangs after curses.
+# -mminimal-toc needed on some systems but not others to avoid TOC overflow.
+# "man ld" says -bbigtoc makes program run slower.
+aix43gcc+krb5+krb4+openssl:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher w/Kerberos...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_DES -DCK_CAST -DLIBDES -DCK_SSL \
+ -funsigned-char $(K5INC) $(K5INC)/krb5 $(SSLINC) $(KFLAGS)" \
+ "LIBS=$(K5LIB) $(SSLLIB) -lssl -lcrypto \
+ -lcurses -lm -lkrb4 -ldes425 -lkrb5 -lcom_err -lk5crypto -lcrypt \
+ -lgssapi_krb5"
+
+aix43gcc+openssl:
+ @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher w/OpenSSL...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \
+ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \
+ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL \
+ -DCK_AUTHENTICATION -DCK_SSL -funsigned-char $(SSLINC) $(KFLAGS)" \
+ "LIBS=$(SSLLIB) -lssl -lcrypto -lcurses -lm -lcrypt"
+
+aix44gcc:
+ $(MAKE) aix43g "KFLAGS=-DAIX44 $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)}
+
+aix45gcc:
+ $(MAKE) aix43g "KFLAGS=-DAIX45 $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)}
+
+aix50gcc:
+ $(MAKE) aix43g "KFLAGS=-DAIX50 $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)}
+
+aix51gcc:
+ $(MAKE) aix43g "KFLAGS=-DAIX51 $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)}
+
+aix52gcc:
+ $(MAKE) aix43g "KFLAGS=-DAIX52 $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)}
+
+aix53gcc:
+ $(MAKE) aix43g "KFLAGS=-DAIX53 $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)}
+
+#Bull DPX/2 with BOS/X, like AIX/RS6000
+bulldpx2:
+ @echo Making C-Kermit $(CKVER) for Bull DPX/2 with BOS/X...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSVR3 -DDIRENT -DCK_ANSIC -DCKTYP_H=<sys/types.h> \
+ -DCK_POLL -DNOGETUSERSHELL -DCLSOPN -DNOLEARN -O $(KFLAGS)" \
+ "LNKFLAGS = -s"
+
+#Sun UNIX 3.5 with gcc 2.3.3.
+sunos3gcc:
+ @echo Making C-Kermit $(CKVER) for Sun UNIX 3.5 and gcc...
+ $(MAKE) xermit CC=gcc CC2=gcc KTARGET=$${KTARGET:-$(@)} \
+ CFLAGS="-g -O -DBSD4 -DTCPSOCKET $(KFLAGS)"
+
+#SunOS version 4.0, BSD environment, has saved original euid feature.
+# Add "CC=/usr/ucb/cc CC2=/usr/ucb/cc" if necessary.
+# Note: Including Unicode crashes the assembler in ckcuni.c.
+sunos4:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.0, BSD environment...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DSUNOS4 -DFNFLOAT -DNOUNICODE $(KFLAGS)" \
+ "LIBS=-lm"
+
+#As above, but with SunLink X.25 support
+sunos4x25:
+ @echo SunLink X.25 support
+ $(MAKE) "MAKE=$(MAKE)" sunos4 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DFNFLOAT -DSUNX25" \
+ "LIBS=-lm"
+
+#SUN OS version 4.1 - 4.1.3, BSD environment, has saved original euid feature.
+#Uses Honey DanBer UUCP. Requires presence of /usr/spool/locks directory.
+# /var/spool/ should be a symbolic link to /usr/spool/.
+# ... or 'make xermit "CC= /usr/ucb/cc " \'
+# Note: "xermit" means use the select() version of the CONNECT module.
+# Note for C-Kermit 9.0: Reportedly 'you need to modify the sys/ioctl.h
+# include file, i.e. comment out the "struct winsize" and "struct
+# ttysize". Otherwise there will be a conflict with sys/ttycom.h (included by
+# termios.h) which also declares these structs. But you need both includes.'
+sunos41:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 / BSD...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNOUNICODE $(KFLAGS)" \
+ "LIBS= $(LIBS) -lresolv -lm"
+
+#As above, but compiled with gcc. Gives 24-32K size reduction
+#with gcc 2.1 or 2.2.2. CAUTION: make sure "fixincludes" has been run on
+#the include files, so gcc's are in sync with the regular Sun ones.
+#This includes the curses library for fullscreen file transfer display.
+#NDGPWNAM needed for GCC 2.5.6, not needed for 2.4.0, but it's uncertain
+#whether it will do any harm for 2.4.0 compilation -- if so, remove it.
+sunos41gcc:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -funsigned-char $(KFLAGS)" "LIBS= -lcurses -ltermcap -lresolv -lm"
+
+# As above, but without -funsigned-char so I can see the warnings that
+# everybody else will get when they use ANSI compilers that don't have this
+# option (gsc = gcc signed char).
+sunos41gsc:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ $(KFLAGS)" "LIBS= -lcurses -ltermcap -lresolv -lm"
+
+#As above but with ckucon.c rather than ckucns.c (for testing only)
+sunos41gccfork:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DNOLEARN -funsigned-char $(KFLAGS)" \
+ "LIBS= -lcurses -ltermcap -lresolv -lm"
+
+#as above but configured for Kerberos IV
+sunos41gcc+krb4:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, krb4...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DTCPSOCKET -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 \
+ -DCK_ENCRYPTION -DCK_DES -DCK_CAST -DBIGBUFOK -funsigned-char \
+ $(K4INC) $(KFLAGS)" \
+ "LIBS= $(K4LIB) -lcurses -ltermcap -lresolv -lm -lkrb -ldes"
+
+#as above but configured for SSL/TLS
+sunos41gcc+openssl:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, ssl...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DCK_AUTHENTICATION -funsigned-char \
+ -DCK_SSL -DTCPSOCKET -DBIGBUFOK $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -lcurses -ltermcap -lresolv -lm -lssl -lcrypto"
+
+#as above but configured for Kerberos IV and SSL/TLS
+sunos41gcc+krb4+openssl:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, krb4...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION -DCK_DES \
+ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \
+ $(K4INC) $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(K4LIB) $(SSLLIB) \
+ -lcurses -ltermcap -lresolv -lm -lkrb -lssl -lcrypto"
+
+#as above but configured for Kerberos IV and ZLIB enabled SSL/TLS
+sunos41gcc+krb4+openssl+zlib:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, krb4...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION -DCK_DES \
+ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \
+ -DZLIB $(K4INC) $(SSLINC) \
+ $(KFLAGS)" \
+ "LIBS= $(K4LIB) $(SSLLIB) \
+ -lcurses -ltermcap -lresolv -lm -lkrb -lssl -lcrypto -lz"
+
+#as above but configured for Kerberos IV and SRP and ZLIB enabled SSL/TLS
+sunos41gcc+krb4+srp+openssl+zlib:
+ @echo "C-Kermit $(CKVER) SunOS 4.1: gcc,curses,krb4,srp,ssl,zlib..."
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION -DCK_DES \
+ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \
+ -DZLIB -DCK_SRP $(K4INC) $(SRPINC) $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(K4LIB) $(SRPLIB) $(SSLLIB) \
+ -lcurses -ltermcap -lresolv -lm -lkrb -lkrypto \
+ -lsrp -lssl -lcrypto -lz"
+
+#as above but configured for Kerberos IV and SRP and ZLIB enabled SSL/TLS
+sunos41gcc+srp+openssl+zlib:
+ @echo "C-Kermit $(CKVER) SunOS 4.1: gcc,curses,srp,ssl,zlib..."
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \
+ -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_DES \
+ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \
+ -DZLIB -DCK_SRP $(SRPINC) $(SSLINC) \
+ $(KFLAGS)" \
+ "LIBS= $(SRPLIB) $(SSLLIB) \
+ -lcurses -ltermcap -lresolv -lm -lkrypto -lsrp -lssl -lcrypto -lz "
+
+#SUNOS 4.1 as sunos41 above, but also with curses support
+sunos41c:
+ @echo Curses support
+ $(MAKE) "MAKE=$(MAKE)" sunos41 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DCK_CURSES -DFNFLOAT " \
+ "LIBS= -lcurses -ltermcap"
+
+#As SunOS 4.1.x, gcc, configured as Internet Kermit Server.
+# . NOLOCAL removes capability to make connections
+# . TNCODE allows server-side Telnet negotiation.
+# . used to include -lpwent, why?
+# . used to include -L/usr/local/lib -lm, why?
+sunos41giks:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc for IKS...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \
+ "CFLAGS= -O -DSUNOS41 -DNDGPWNAM -DFNFLOAT \
+ -DNOLOCAL -DTCPSOCKET -DTNCODE -DNOPUSH $(KFLAGS)" \
+ "LIBS= -lm -lresolv"
+
+#SUNOS 4.1 with SunLink X.25 support
+sunos41x25:
+ @echo SunLink X.25 support
+ $(MAKE) "MAKE=$(MAKE)" wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNOUNICODE -DFNFLOAT -DSUNX25 \
+ -DNOLEARN $(KFLAGS)" "LIBS= $(LIBS) -lresolv -lm"
+
+#SUNOS 4.1 with SunLink X.25 support and curses
+sunos41x25c:
+ @echo SunLink X.25 support + curses
+ $(MAKE) "MAKE=$(MAKE)" wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNOUNICODE -DFNFLOAT -DSUNX25 \
+ -DCK_CURSES -DNOLEARN $(KFLAGS)" \
+ "LIBS= $(LIBS) -lcurses -ltermcap -lresolv -lm"
+
+#SUN with Solaris 2.0 = SunOS 5.0.
+#Mostly the same as System V R4. Don't use this with later Solaris versions.
+solaris20:
+ @echo 'Making C-Kermit $(CKVER) for Sun with Solaris 2.0 and curses...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DSOLARIS -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DTCPSOCKET -DCK_CURSES -DFNFLOAT -DCK_POLL $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermlib -lm" "LNKFLAGS = -s"
+
+#SUN with Solaris 2.0.
+#As above, but built with the gcc compiler from the Cygnus CD-ROM.
+solaris20g:
+ @echo 'Making C-Kermit $(CKVER) for Sun Solaris 2.0, gcc, and curses..'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DSOLARIS -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DTCPSOCKET -DCK_CURSES -DCK_POLL -DFNFLOAT $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermlib -lm" "LNKFLAGS = -s" \
+ CC=/opt/cygnus-sol2-1.1/bin/gcc CC2=/opt/cygnus-sol2-1.1/bin/gcc
+
+#SunOS 5.1 = Solaris 2.1.
+#NOTE: A C compiler is no longer bundled with SunOS 5.1, so to compile C
+#programs, you might have to change your PATH to include the directory
+#/usr/ccs/bin AFTER the directory containing the compiler. SunPRO C is
+#installed by default in /opt/SUNWspro/bin. So a sample PATH might be:
+#
+# /usr/local/bin:/usr/bin:/opt/SUNWspro/bin:/usr/ccs/bin:\
+# /usr/ucb:/usr/sbin:/sbin:.
+#
+# or:
+#
+# /usr/openwin/bin:/export/home/SUNWspro/bin:/usr/ccs/bin:/usr/sbin:/usr/bin.
+#
+#NOTE 2: Compilation with the Apogee C compiler (apcc) might not work,
+#because it refuses to allow "-Usun". Reportedly, newer releases of apcc
+#(such as 1.2.17) work OK, use: "make -e sunos51 CC=apcc CC2=apcc".
+solaris21:
+ @echo 'Making C-Kermit $(CKVER) for SunOS 5.x....'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS -DDIRENT -DHDBUUCP -DFNFLOAT \
+ -DSELECT -DNODEBUG -DSTERMIOX $(KFLAGS)" "LIBS = -lm" "LNKFLAGS = -s"
+
+#Solaris 2.0 - 2.4, SunPro compiler, includes curses and TCP/IP.
+#When using SUNWspro CC 2.0.1 under Solaris 2.3, be sure all cc patches
+#are applied, otherwise corrupt or truncated object files can result.
+#To build, set your PATH as follows:
+# /usr/local/bin:/usr/bin:/opt/SUNWspro/bin:/usr/ccs/bin:\
+# /usr/ucb:/usr/sbin:/sbin:.
+# or (depending on where the compiler has been installed):
+# /usr/openwin/bin:/export/home/SUNWspro/bin:/usr/ccs/bin:/usr/sbin:/usr/bin.
+#For additional optimization try using "-fast -xO4 -xdepend".
+solaris2x:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with SunPro cc...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -Usun -i -DSVR4 -DDIRENT -DSOLARIS -DHDBUUCP -DFNFLOAT \
+ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv"
+
+#as above but configured for Kerberos IV
+solaris2x+krb4:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x, SunPro cc, krb4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -Usun -i -DSVR4 -DDIRENT -DSOLARIS -DHDBUUCP -DFNFLOAT \
+ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 \
+ -DCK_ENCRYPTION -DCK_DES -DCK_CAST $(K4INC) $(KFLAGS)" \
+ "LNKFLAGS = -s" \
+ "LIBS= $(K4LIB) -ltermlib -lsocket -lnsl -lm -lresolv -lkrb -ldes"
+
+#C-Kermit for Solaris 2.0-2.4 compiled with gcc, includes curses and TCP/IP.
+#Change -O2 to -O if -O2 gives trouble.
+#Remove -Usun if it causes trouble.
+#Your PATH should start with something like:
+# /usr/local/gnu/bin:/usr/ccs/bin:
+#Produces a huge executable -- strip with /usr/ccs/bin/strip (not Gnu strip).
+#Also don't add "LNKFLAGS = -s" -- strip manually instead.
+#Also note: this can NOT be linked statically - Sun makes it impossible.
+#And for Solaris 2.4, you might have to replace:
+# /usr/local/lib/gcc-lib/i486-sun-solaris2/2.4.5/include/sys/stat.h
+#with /usr/include/sys/stat.h.
+solaris2xg:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with GNU cc...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv $(LIBS)"
+
+#ditto but no curses.
+solaris2xgnc:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with GNU cc...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lm -lresolv $(LIBS)"
+
+#and with Kerberos IV
+solaris2xg+krb4:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with GNU cc, krb4...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION \
+ -DCK_DES -DCK_CAST -DBIGBUFOK $(K4INC) $(KFLAGS)" \
+ "LIBS= $(K4LIB) -ltermlib -lsocket -lnsl -lm -lresolv -lkrb -ldes \
+ $(LIBS)"
+
+#and with OpenSSL,ZLIB,PAM,SHADOW
+solaris2xg+openssl+zlib+pam+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB \
+ -DBIGBUFOK $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -ltermlib \
+ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam -lz"
+
+#Ditto but with GCC 3.1 in which you have to specify 32-bit with -m32.
+#In Solaris 9 (and maybe 8) you'll also need specifiy the Library path.
+#Reportedly this can be done here, but only with:
+# crle -l /usr/lib:/usr/local/ssl/lib
+#prior to building. Note: 64-bit not tested with SSL.
+#For no-crypto 64-bit builds see the solaris9g64 target.
+solaris2xg32+openssl+zlib+pam+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC="gcc -m32" CC2="gcc -m32" \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB \
+ -DBIGBUFOK $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -ltermlib \
+ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam -lz"
+
+#and with Krb5,Krb4,OpenSSL,SHADOW
+solaris2xg+krb5+krb4+openssl+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc,k5,k4,ssl...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_SSL -DCK_DES -DCK_CAST -DBIGBUFOK \
+ $(K5INC) $(K5INC)/krb5 $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(K5LIB) $(SSLLIB) -ltermlib -lsocket -lnsl -lm -lresolv \
+ -lkrb4 -lssl -lcrypto -lgssapi_krb5 -lkrb5 -lcom_err -lk5crypto \
+ -ldes $(LIBS)"
+
+#and with OpenSSL
+solaris2xg+openssl+pam+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW \
+ -DBIGBUFOK $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -ltermlib \
+ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam"
+
+solaris2xg+openssl+zlib+srp+pam+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...'
+ @echo 'Please read the comments that accompany the solaris2xg target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET -DBIGBUFOK \
+ -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_DES -DLIBDES -DCK_CAST \
+ -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB -DCK_SRP $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -ltermlib -lsocket -lnsl -lm -lresolv -lsrp -lssl \
+ -ldes -lkrypto -lcrypto -lpam -lz"
+
+solaris22g:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DPOSIX_CRTSCTS $(KFLAGS)" solaris2xg \
+ KTARGET=$${KTARGET:-$(@)}
+
+solaris23g:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DPOSIX_CRTSCTS $(KFLAGS)" solaris2xg \
+ KTARGET=$${KTARGET:-$(@)}
+
+#Solaris 2.4 built with gcc
+solaris24g:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} \
+ solaris2xg "KFLAGS=-DSOLARIS24 -DPOSIX_CRTSCTS $(KFLAGS)"
+
+#Solaris 2.0-2.3, SunPro compiler, with SunLink X.25 support.
+#This will only run if user has /opt/SUNWconn/lib/libsockx25.so.1
+#exists and can be dynamically linked.
+#NOTE: Do not change target to xermit -- it doesn't support X.25.
+solaris2x25:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x+X.25 with SunPro cc...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS -DDIRENT \
+ -DSUNX25 -DTCPSOCKET -DHDBUUCP -DFNFLOAT -DNOLEARN \
+ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX $(KFLAGS)" \
+ "LNKFLAGS = -s" \
+ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \
+ -lsockx25 -lsocket -lnsl -lm -lresolv"
+
+#Solaris 2.0-2.4, gcc, SunLink X.25 added.
+#NOTE: Can't use xermit target with X.25.
+solaris2xgx25:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x + X.25 with GNU cc...'
+ @echo 'Please read the comments that accompany the solaris2xg entry.'
+ $(MAKE) wermit CC=gcc CC2=gcc KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DSUNX25 \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET -DFNFLOAT \
+ -DNOLEARN $(KFLAGS)" \
+ "LIBS= -ltermlib -lm -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \
+ -lsockx25 -lsocket -lnsl"
+
+#Solaris 2.4, SunPro compiler, with SunLink X.25 support.
+#This will only run if user has /opt/SUNWconn/lib/libsockx25.so.1
+#exists and can be dynamically linked.
+solaris24x25:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.4+X.25 with SunPro cc...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS -DSOLARIS24 -DDIRENT -DNOLEARN \
+ -DSUNX25 -DTCPSOCKET -DHDBUUCP -DFNFLOAT -DPOSIX_CRTSCTS \
+ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX $(KFLAGS)" \
+ "LNKFLAGS = -s" \
+ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \
+ -lsockx25 -lsocket -lnsl -lm -lresolv"
+
+#Solaris 2.5, SunPro compiler, with SunLink X.25 support.
+solaris25x25:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.5+X.25 with SunPro cc...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS25 -DDIRENT -DSUNX25 \
+ -DTCPSOCKET -DHDBUUCP -DSELECT -DCK_CURSES \
+ -DCK_NEWTERM -DSTERMIOX -DFNFLOAT -DPOSIX_CRTSCTS -DNOLEARN \
+ -I/opt/SUNWconn/include $(KFLAGS)" \
+ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \
+ -lsockx25 -lsocket -lnsl -lm -lresolv"
+
+solaris23:
+ $(MAKE) "MAKE=$(MAKE)" solaris2x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS)"
+
+solaris24:
+ $(MAKE) "MAKE=$(MAKE)" solaris2x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS24 -DPOSIX_CRTSCTS $(KFLAGS)"
+
+# template for Solaris 2.5 and above.
+solaris25x:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with SunPro cc...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DFNFLOAT -O -Usun -i $(KFLAGS)" \
+ "LNKFLAGS = -s" \
+ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv $(LIBS)"
+
+#Solaris 2.5, SunPro compiler, curses, TCP/IP
+solaris25:
+ $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS25 $(KFLAGS)"
+
+#Solaris 2.5, SunPro compiler, curses, TCP/IP, Kerberos IV
+solaris25+krb4:
+ $(MAKE) "MAKE=$(MAKE)" solaris25x+krb4 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS25 $(KFLAGS)"
+
+#Solaris 2.5 built with gcc
+solaris25g:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-funsigned-char -DSOLARIS25 $(KFLAGS)"
+
+#Solaris 2.5 built with gcc and Kerberos IV
+solaris25g+krb4:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb4 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-funsigned-char -DSOLARIS25 $(KFLAGS)"
+
+#Solaris 2.5 built with gcc and Kerberos V/IV, SSL, ...
+solaris25g+krb5+krb4+openssl+shadow:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb5+krb4+openssl+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-funsigned-char -DSOLARIS25 $(KFLAGS)"
+
+#Solaris 2.5, gcc, SunLink X.25 added.
+solaris25gx25:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xgx25 \
+ "KFLAGS=-DSOLARIS25 $(KFLAGS)"
+
+#Solaris 2.6, gcc, SunLink X.25 added.
+solaris26gx25:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xgx25 \
+ "KFLAGS=-DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 2.6, SunPro compiler, curses, TCP/IP
+solaris26:
+ $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 2.6 with gcc
+solaris26g:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xg \
+ "KFLAGS= -DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS = -lpam"
+
+#Solaris 2.6 with gcc and SSL
+solaris26g+openssl:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS= -DSOLARIS26 $(KFLAGS)"
+
+#Solaris 2.6 with gcc, no curses (e.g. because libtermlib is missing).
+solaris26gnc:
+ $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xgnc \
+ "KFLAGS= -DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 2.6, SunPro compiler, with SunLink X.25 support.
+solaris26x25:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 2.6+X.25 with SunPro cc...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS26 -DDIRENT -DSUNX25 \
+ -DTCPSOCKET -DHDBUUCP -DSELECT -DCK_CURSES -DCK_PAM -DCK_SHADOW \
+ -DCK_NEWTERM -DSTERMIOX -DFNFLOAT -DPOSIX_CRTSCTS -DNOLEARN \
+ -I/opt/SUNWconn/include $(KFLAGS)" \
+ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \
+ -lsockx25 -lsocket -lnsl -lm -lresolv -lpam"
+
+#Solaris 7 (2.7) with Sun CC
+solaris7:
+ $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 7 with gcc (32-bit)
+solaris7g:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 7 with gcc + Kerberos IV (32-bit)
+solaris7g+krb4:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb4 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+solaris7g+openssl+zlib+pam+shadow:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)"
+
+#Solaris 7 with gcc + OpenSSL (32-bit)
+solaris7g+openssl+zlib+srp+pam+shadow:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+srp+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)"
+
+#Solaris 8
+solaris8:
+ $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 8 with gcc (32-bit)
+solaris8g:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+# In OpenSSL builds add -ldl if you get unresolved references for
+# dlclose, dlsym, dlopen, dlerror.
+
+#Solaris 8 with gcc + OpenSSL (32-bit)
+solaris8g+openssl+zlib+pam+shadow:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DSOLARIS8 $(KFLAGS)"
+
+#Solaris 8 with gcc + Kerberos IV (32-bit)
+solaris8g+krb4:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb4 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+ "LIBS= -lpam"
+
+solaris9nolfs:
+ $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS9 -DCK_PAM -DCK_SHADOW -DUSE_STRERROR $(KFLAGS)" \
+ "LIBS= -lpam"
+
+#Solaris 9 with malloc debugging
+solaris9md:
+ $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DFNFLOAT -O -Usun -i -D_FILE_OFFSET_BITS=64 \
+ -DSOLARIS9 -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG \
+ -DCK_PAM -DCK_SHADOW -DUSE_STRERROR $(KFLAGS)" \
+ "LIBS= -lpam -ltermlib -lsocket -lnsl -lm -lresolv"
+
+#Solaris 9 with gcc + OpenSSL + Shadow (32-bit)
+#Add -DOPENSSL_097 for OpenSSL 0.9.7 or later.
+solaris9g+openssl+shadow+pam+zlib:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS9 -DHDBUUCP -DDIRENT -D_FILE_OFFSET_BITS=64 \
+ -DNO_DCL_INET_ATON -DZLIB -DCK_PAM -DCK_SHADOW -DLIBDES $(KFLAGS)" \
+ "LIBS= -lpam -ldes425 -lz $(LIBS)"
+
+#Solaris 9 with gcc + OpenSSL + Kerberos 5 + Krb4 + Shadow (32-bit)
+#Add -DOPENSSL_097 for OpenSSL 0.9.7 or later.
+solaris9g+krb5+krb4+openssl+shadow+pam+zlib:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb5+krb4+openssl+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS9 -DHDBUUCP -DDIRENT -D_FILE_OFFSET_BITS=64 \
+ -DNO_DCL_INET_ATON -DZLIB -DCK_PAM -DCK_SHADOW -DLIBDES $(KFLAGS)" \
+ "LIBS= -lpam -ldes -lz $(LIBS)"
+
+#Solaris 9 with gcc + Kerberos 4 and 5:
+solaris9g+krb5+krb4:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS9 -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -D_FILE_OFFSET_BITS=64 \
+ -DCK_ENCRYPTION -DCK_DES -DCK_CAST -DBIGBUFOK \
+ $(K5INC) $(K5INC)/krb5 $(KFLAGS)" \
+ "LIBS= $(K5LIB) -ltermlib -lsocket -lnsl -lm -lresolv \
+ -lkrb4 -lcrypto -lgssapi_krb5 -lkrb5 -lcom_err -lk5crypto \
+ -ldes $(LIBS)"
+
+#Solaris 9, 10, or 11 with gcc...
+#Uses streams PTYs rather than BSD ptys as in C-Kermit 8.0 and earlier.
+#This target is chained to be the secure solaris9g+xxx targets below.
+solaris9g solaris10g solaris11g:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 9 or later with gcc'
+ @case `uname -r` in \
+ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \
+ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \
+ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \
+ *) SOLARISVERSION="-DSOLARIS" ;; \
+ esac ; \
+ $(MAKE) "MAKE=$(MAKE)" CC="gcc -m32" CC2="gcc -m32" xermit \
+ KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -g -O -Usun -DSVR4 $$SOLARISVERSION -DUSE_STRERROR \
+ -DSTERMIOX -DSELECT -DFNFLOAT -DCK_PAM -DCK_SHADOW -funsigned-char \
+ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \
+ -DPUSH_LDTERM -DPUSH_TTCOMPAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -D_FILE_OFFSET_BITS=64 $(KFLAGS)" \
+ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv -lpam $(LIBS)"
+
+#Solaris 9, 10, or 11 with gcc + Kerberos 5 + OpenSSL.
+#OK C-Kermit 9.0.301.
+solaris9g+krb5+ssl solaris10g+krb5+ssl solaris11g+krb5+ssl:
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac ; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes425'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ GSSAPILIB=''; \
+ K5DIR=`echo $(K5LIB) | sed 's|-L||'`; \
+ echo K5DIR=$$K5DIR; \
+ if ls $$K5DIR/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ else GSSAPILIB='-lgssapi'; \
+ fi; \
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS9 -DSTERMIOX -DSELECT -DFNFLOAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET -DBIGBUFOK \
+ -DCK_AUTHENTICATION -DCK_SSL -DZLIB -DCK_KERBEROS -DKRB5 \
+ -DCK_ENCRYPTION -DCK_CAST $$OPENSSLOPTION \
+ $$HAVE_DES $(SSLINC) $(K5INC) $(K5INC)/krb5 $(KFLAGS)" \
+ "LIBS= $(SSLLIB) $(K5LIB) -lz -lssl -ltermlib -lsocket -lnsl -lm \
+ -lresolv -lcrypto \
+ $$GSSAPILIB -lkrb5 -lcom_err -lk5crypto $$DES_LIB $(LIBS)"
+
+#Solaris 9, 10, or 11 with gcc, 64 bit build.
+#Peeking inside FILE struct not allowed in 64-bit world.
+#DON'T USE THIS ONE ON PC ARCHITECTURE - It compiles and links but won't run.
+#OK: 2009/09/25 (but not tested on Solaris 11)
+solaris9g64 solaris10g64 solaris11g64:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 9++ with gcc 64-bit'
+ @case `uname -r` in \
+ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \
+ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \
+ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \
+ *) SOLARISVERSION="-DSOLARIS" ;; \
+ esac ; \
+ $(MAKE) "MAKE=$(MAKE)" CC="gcc -m64" CC2="gcc -m64" xermit \
+ KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -g -O -Usun -funsigned-char \
+ -DSVR4 $$SOLARISVERSION -DNOARROWKEYS \
+ -DSTERMIOX -DSELECT -DFNFLOAT -DUSE_STRERROR -DCK_PAM -DCK_SHADOW \
+ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \
+ -DPUSH_LDTERM -DPUSH_TTCOMPAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv -lpam $(LIBS)"
+
+#Solaris 9, 10, or 11 with SunPro CC
+#Uses streams PTYs rather than BSD ptys as in C-Kermit 8.0 and earlier.
+#This target is chained to by the secure targets below.
+#OK C-Kermit 9.0
+solaris9 solaris10 solaris11:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 9 or later with Sun CC'
+ @case `uname -r` in \
+ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \
+ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \
+ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \
+ *) SOLARISVERSION="-DSOLARIS" ;; \
+ esac ; \
+ $(MAKE) "MAKE=$(MAKE)" xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -Usun -DSVR4 $$SOLARISVERSION -DUSE_STRERROR \
+ -DSTERMIOX -DSELECT -DFNFLOAT -DCK_PAM -DCK_SHADOW \
+ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \
+ -DPUSH_LDTERM -DPUSH_TTCOMPAT \
+ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -D_FILE_OFFSET_BITS=64 $(KFLAGS)" \
+ "LIBS= $(LIBS) -ltermlib -lsocket -lnsl -lm -lresolv -lpam"
+
+# Solaris 9, 10, or 11 with OpenSSL built with Sun CC.
+# Here's an example of how to invoke this target in case your OpenSSL
+# headers and libraries are not in /usr/local:
+#
+# make solaris9+openssl "SSLINC=" "SSLLIB=" \
+# "KFLAGS= -I/opt/openssl-0.9.8k/include -L/opt/openssl-0.9.8k/lib"
+#
+# Don't use 'make -e' because that inhibits passing of KFLAGS to
+# the base (solaris9) target.
+#
+#OK C-Kermit 9.0
+solaris9+ssl solaris10+ssl solaris11+ssl \
+solaris9+openssl solaris10+openssl solaris11+openssl:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 9/10/11 with OpenSSL: cc'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac ; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes425'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) "MAKE=$(MAKE)" solaris9 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DCK_AUTHENTICATION -DCK_SSL -DZLIB $$HAVE_DES \
+ -DNO_DCL_INET_ATON $$OPENSSLOPTION $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -lz -lssl $$DES_LIB -lcrypto $(LIBS)"
+
+# Solaris 9 or later with OpenSSL, built with gcc.
+# Remove -DNO_DCL_INET_ATON if inet_aton comes up missing. This target nicely
+# chains to the solaris{9,10,11}g target but for some reason it doesn't work if
+# you add the -DFORWARD_X option, thus the solaris9g+openssl+forward_x target.
+#
+#OK: 2011/06/14
+solaris9g+ssl solaris10g+ssl solaris11g+ssl \
+solaris9g+openssl solaris10g+openssl solaris11g+openssl:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 9/10/11 with OpenSSL: gcc'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac ; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes425'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) "MAKE=$(MAKE)" solaris9g KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DCK_AUTHENTICATION -DCK_SSL -DZLIB $$HAVE_DES \
+ -DNO_DCL_INET_ATON $$OPENSSLOPTION $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -lz -lssl $$DES_LIB -lcrypto $(LIBS)"
+
+# Solaris 9 or later with gcc + OpenSSL + Shadow (32-bit).
+# Remove -DNO_DCL_INET_ATON if inet_aton comes up missing.
+# Includes long file support - not sure if this was available before Solaris 9.
+# Detects Solaris version automatically.
+#
+solaris9g+openssl+forward_x:
+ @echo 'Making C-Kermit $(CKVER) for Solaris 9 or later with OpenSSL...'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac ; case `uname -r` in \
+ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \
+ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \
+ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \
+ *) SOLARISVERSION="-DSOLARIS" ;; \
+ esac ; \
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "CFLAGS = -g -O -Usun -DSVR4 $$SOLARISVERSION \
+ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \
+ -DPUSH_LDTERM -DPUSH_TTCOMPAT \
+ -DSTERMIOX -DSELECT -DFNFLOAT -DBIGBUFOK -D_FILE_OFFSET_BITS=64 \
+ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB -DLIBDES \
+ -DFORWARD_X $$OPENSSLOPTION $(SSLINC) $(KFLAGS)" \
+ "LIBS= $(SSLLIB) -lpam -ldes425 -lz -ltermlib \
+ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam -lz $(LIBS)"
+
+# These two should be folded in with the ones just above.
+
+#Solaris 9 with gcc 3.1 + OpenSSL (32-bit)
+solaris9g+openssl+zlib+pam+shadow:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg32+openssl+zlib+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS9 -DUSE_STRERROR $(KFLAGS)"
+
+#Solaris 10 with gcc 3.1 + OpenSSL (32-bit)
+solaris10g+openssl+zlib+pam+shadow:
+ $(MAKE) "MAKE=$(MAKE)" solaris2xg32+openssl+zlib+pam+shadow \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSOLARIS10 -DUSE_STRERROR $(KFLAGS)"
+
+#The following (old, old) sunosxxx entries are for debugging and testing only.
+
+sunos41x:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DSUNOS41 -DDIRENT -DNOTLOG -DNOMSEND \
+ -DNOUUCP -DNOSIGWINCH -DNOREDIRECT -DNOPUSH -DNOCCTRAP \
+ -DNOICP -DNOLOCAL $(KFLAGS)"
+
+#SunOS 4.1.x, debugging with Pure Software, Inc., Purify 2 (commercial runtime
+#error-detection software for catching wild array references, etc).
+#Before running the resulting wermit, you'll also need to define and export
+#the following environment variables (as in this example):
+#PURIFYHOME=/usr/local/purify ; export PURIFYHOME
+#PURIFYCACHEDIR=/tmp ; export PURIFYCACHEDIR
+sunos41cp:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 / BSD / Curses / Purify...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CC2= purify -cache_dir=/usr/tmp cc" \
+ "CFLAGS= -g -DSUNOS41 -DHDBUUCP -DDIRENT -DTCPSOCKET \
+ -DSAVEDUID -DCK_CURSES $(KFLAGS)" \
+ "LIBS= -lcurses -ltermcap"
+
+#SunOS 4.1 with malloc debugger
+sunos41md:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 malloc debug...
+ $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DDIRENT -DTCPSOCKET \
+ -DSAVEDUID $(KFLAGS) -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG"
+
+sunos41gmd:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses...
+ $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} "CC= gcc " "CC2= gcc" \
+ "CFLAGS= -g -DSUNOS41 -DHDBUUCP -DDIRENT -DTCPSOCKET \
+ -DNDGPWNAM -DSAVEDUID -DCK_CURSES -DRLOGCODE \
+ $(KFLAGS) -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG" \
+ "LIBS= -lcurses -ltermcap"
+
+#SunOS version 4.1, gcc, profiling with gprof, no debugging.
+#To get profile, "make sunos41p" (on Sun), then "./wermit". After running
+#wermit, "gprof ./wermit | lpr" (or whatever) to get execution profile.
+sunos41p:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.x with profiling...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc " "CC2= gcc" \
+ "CFLAGS= -DSUNOS41 -DNODEBUG -DSAVEDUID -DDIRENT -DTCPSOCKET \
+ -DNDGPWNAM $(KFLAGS) -pg" "LNKFLAGS = -pg"
+
+#SunOS version 4.1 or later, BSD environment, minimum features.
+sunos41min:
+ @echo Minimum interactive
+ $(MAKE) "MAKE=$(MAKE)" sunos41 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOSPL -DNOXMIT -DNOMSEND -DNOFRILLS -DNORETRY \
+ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG -DNOSCRIPT -DNOCSETS \
+ -DNOSHOW -DNOSETKEY -DNOUUCP -DNORECALL -DNOREDIRECT \
+ -DNOPUSH -DNOMDMHUP -DNOJC -DNOFDZERO -DNOESCSEQ \
+ -DNONET -DCK_SMALL -DNOCKSPEED -DNOCKTIMERS -DNOLOGIN \
+ -DNOCKXYZ -DNOKERBEROS -DNOMKDIR -DNOPATTERNS -DNOPERMS -DNOPIPESEND \
+ -DNORECURSIVE -DNORENAME -DNORESEND -DNOSETKEY \
+ -DNOTRIGGER -DNOTUNING $(KFLAGS)" "LNKFLAGS = -s"
+
+#SunOS version 4.1, BSD environment, min size, command-line only...
+sunos41m:
+ @echo Minimum size
+ $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOICP $(KFLAGS)"
+
+#SunOS version 4.1, BSD environment, min size, cmd-line only, remote only...
+#
+sunos41mr:
+ @echo Minimum size
+ $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOICP -DNOLOCAL $(KFLAGS)"
+
+#SunOS version 4.1, BSD environment, min size, interactive...
+sunos41mi:
+ @echo Minimum size
+ $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOCMDL $(KFLAGS)"
+
+#SunOS version 4.1, BSD environment, min size, interactive, remote only...
+sunos41mir:
+ @echo Minimum size
+ $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOCMDL -DNOLOCAL $(KFLAGS)"
+
+#SunOS 4.1, System V R3 environment (-i option omitted).
+sunos41s5:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 System V R3...
+ @echo For testing purposes only - NOT for production use.
+ @echo For a useable version, make sunos41 instead.
+ $(MAKE) wermit "CC= /usr/5bin/cc " "CC2=/usr/5bin/cc " \
+ KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSUN4S5 -DDIRENT -DHDBUUCP -DNOLEARN -DCK_POLL $(KFLAGS) -O"
+
+#As above, but with curses support
+sunos41s5c:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 System V R3...
+ @echo Curses included.
+ @echo For testing purposes only - NOT for production use.
+ @echo For a useable version, make sunos41 instead.
+ $(MAKE) wermit "CC= /usr/5bin/cc " "CC2=/usr/5bin/cc " \
+ KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSUN4S5 -DDIRENT -DHDBUUCP -DNOLEARN \
+ -DCK_POLL -DCK_CURSES -DCK_NEWTERM $(KFLAGS) -O" "LIBS= -lcurses"
+
+#As above, but with curses support AND net support
+sunos41s5tcpc:
+ @echo Making C-Kermit $(CKVER) for SunOS 4.1 System V R3...
+ @echo TCP/IP and curses included. No debug log.
+ @echo For testing purposes only - NOT for production use.
+ @echo For a useable version, make sunos41 instead.
+ $(MAKE) xermit "CC= /usr/5bin/cc " "CC2=/usr/5bin/cc " \
+ KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSUN4S5 -DDIRENT -DHDBUUCP -DCK_POLL \
+ -DNODEBUG -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET $(KFLAGS) -O" \
+ "LIBS= -lcurses -lresolv"
+
+# (End of SunOS test entries...)
+
+#Apollo with Domain SR10.0 or later, BSD environment
+#Reportedly, it might also help to add '-A,systype=bsd4.3' to CFLAGS.
+#Reportedly, there is also a problem with getc & putc macros that can
+#be handled by using '#ifdef apollo' somewhere to redefine them???
+#On the other hand, other reports indicate that it works fine as-is.
+#NOTE: This entry was previously like this:
+# $(MAKE) wermit "CFLAGS= -DNOFILEH -DBSD4 $(KFLAGS) -Uaegis \
+# -DTCPSOCKET -U__STDC__"
+#Reports (Dec 91) indicate SR10 has an ANSI-compliant C compiler,
+#in addition to an older one that claimed to be ANSI-compliant but wasn't.
+#The following make entry (plus checks that are made in ckcdeb.h) detect
+#which compiler is used and define the CK_ANSIC or NOANSI flags accordingly.
+sr10-bsd:
+ @echo Making C-Kermit $(CKVER) for Apollo SR10.0 / BSD ...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DAPOLLOSR10 -DBSD43 -DTCPSOCKET -DCK_CURSES -DNOLEARN \
+ -Uaegis $(KFLAGS)" "LIBS= -lcurses -ltermcap"
+
+#Apollo with Domain SR10.0 or later, System V R3 environment.
+#Don't use the optimizer (-O), it causes problems at runtime.
+sr10-s5r3:
+ @echo Making C-Kermit $(CKVER) for Apollo SR10.0 / Sys V R3 ...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNOFILEH -DSVR3 -DAPOLLOSR10 -DNOLEARN $(KFLAGS) \
+ -Uaegis -U__STDC__"
+
+#Apollo Domain/IX (untested, try this if sr10-bsd doesn't work)
+# -DTCPSOCKET can probably be added here.
+apollobsd:
+ @echo Making C-Kermit $(CKVER) for Apollo Domain/IX...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CC= /bin/cc " "CC2= /bin/cc " \
+ "CFLAGS= -DNOFILEH -DBSD4 -DAPOLLOBSD -DNOLEARN $(KFLAGS) -Uaegis"
+
+#Version 7 Unix (see comments near top of makefile)
+v7:
+ @echo Making C-Kermit $(CKVER) for UNIX Version 7.
+ @echo Read the makefile if you have trouble with this...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS=-DV7 -DPROCNAME=\\\"$(PROC)\\\" \
+ -DBOOTNAME=\\\"$(BOOTFILE)\\\" -DNPROCNAME=\\\"$(NPROC)\\\" \
+ -DNPTYPE=$(NPTYPE) $(DIRECT) -DO_RDWR=2 -DO_NDELAY=0 -DO_SCCS_ID \
+ -DNOLEARN $(KFLAGS)"
+
+#AT&T UNIX System V R3, signal() is void rather than int.
+#Uses dirent.h and Honey DanBer UUCP.
+#Add the -i link option if necessary.
+#If you get errors like "ws_row undefined" in ckutio.c, add -DNONAWS.
+sys5r3:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DNOLEARN $(KFLAGS) -O" \
+ "LNKFLAGS="
+
+#As above, plus curses.
+sys5r3c:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3 + curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DCK_CURSES -DNONAWS -DNOLEARN \
+ $(KFLAGS) -O" "LNKFLAGS=" "LIBS = -ltermlib"
+
+#System V R3.2 for PCs built on Interactive UNIX SV/386 R4.x
+#but with all calls to dup2() disabled because generic SVR3 does not have dup2.
+# (The -linet library might not need to be in this one.)
+sys5r32is:
+ @echo 'Making C-Kermit $(CKVER) for System V/386 R32
+ $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \
+ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES -DNONAWS \
+ -DPOSIX_JC -DCK_REDIR -DCK_POLL -DDCLGETCWD -DNOFDZERO -DNOREDIRECT \
+ -DNOZEXEC -DNOLEARN $(KFLAGS)" "LIBS=-lcurses -lc_s -linet"
+
+#System V R3.2 for PCs built on Interactive UNIX SV/386 R4.x
+#but with all calls to dup2() disabled because generic SVR3 does not have dup2.
+#With TCP/IP added.
+sys5r32isnet:
+ @echo 'Making C-Kermit $(CKVER) for System V/386 R32 + TCP/IP
+ $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \
+ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES -DNONAWS \
+ -DPOSIX_JC -DCK_REDIR -DCK_POLL -DDCLGETCWD -DNOFDZERO -DNOREDIRECT \
+ -DNOLEARN -DNOZEXEC -DTCPSOCKET $(KFLAGS)" "LIBS=-lcurses -lc_s -linet"
+
+iclsys5r3:
+ make sys5r3 KTARGET=$${KTARGET:-$(@)} KFLAGS=-DICLSVR3
+
+#AT&T UNIX System V R3. As above, but no ANSI prototyping.
+sys5r3na:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DNOANSI -DNOLEARN $(KFLAGS) -O" \
+ "LNKFLAGS="
+
+#AT&T UNIX System V R3, for 3B computers with Wollongong TCP/IP.
+sys5r3net3b:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX SVR3/3B/Wollongong...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DWOLLONGONG -DNOLEARN $(KFLAGS) \
+ -O" "LIBS= -lnet -lnsl_s" "LNKFLAGS ="
+
+#AT&T UNIX System V R3, signal() is void rather than int.
+#Uses dirent.h and Honey DanBer uucp, has <termiox.h>.
+#Has <termiox.h> for RTS/CTS flow control.
+sys5r3tx:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DTERMIOX -DNOLEARN \
+ $(KFLAGS) -i -O" "LNKFLAGS ="
+
+#AT&T UNIX System V R3, signal() is void rather than int.
+#Uses dirent.h and Honey DanBer uucp, has <termiox.h>.
+#Has <sys/termiox.h> for RTS/CTS flow control.
+sys5r3sx:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DSTERMIOX -DNOLEARN \
+ $(KFLAGS) -i -O" "LNKFLAGS ="
+
+#AT&T UNIX System V R4.
+#Has <termiox.h>.
+sys5r4:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DTERMIOX -DNOLEARN $(KFLAGS)" \
+ "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4 with Wollongong TCP/IP.
+#Has <termiox.h>.
+sys5r4net:
+ @echo 'Making C-Kermit $(CKVER) for System V R4 + Wollongong TCP/IP...'
+ @echo ' If sockets-library routines are missing at link time, then'
+ @echo ' try the sys5r4net2 entry.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOLEARN \
+ -DTERMIOX -DWOLLONGONG $(KFLAGS)" "LNKFLAGS = -s"
+
+#As above, but needs libs included.
+sys5r4net2:
+ @echo ' PLEASE READ ckuins.txt IF YOU GET MISSING HEADER FILES.'
+ @echo ' (Search for WOLLONGONG...)'
+ $(MAKE) sys5r4net KTARGET=$${KTARGET:-$(@)} "LIBS= -lsocket -lnsl"
+
+#As above plus curses.
+sys5r4net2c:
+ echo 'Making C-Kermit $(CKVER) for System V R4 + Wollongong TCP/IP...'
+ @echo ' PLEASE READ ckuins.txt IF YOU GET MISSING HEADER FILES.'
+ @echo ' (Search for WOLLONGONG...)'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOLEARN \
+ -DTERMIOX -DWOLLONGONG -DCK_CURSES $(KFLAGS)" "LNKFLAGS = -s" \
+ "LIBS= -lsocket -lnsl -lcurses"
+
+#DELL UNIX System V R4.
+#Has <sys/termiox.h>, regular Berkeley sockets library, i.e. in.h and inet.h
+#are not misplaced in sys (rather than netinet and arpa, respectively).
+#Uses ANSI C constructs, advisory file locking on devices, etc.
+#Warning: -DSTERMIOX enables hardware flow control (RTS/CTS), but reportedly
+#this does not work with the normal drivers. However, it might still work
+#on non-Dell systems, or even Dell systems with different drivers installed.
+dellsys5r4:
+ @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT -DHDBUUCP \
+ -DTCPSOCKET -DSTERMIOX -DCK_POLL $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl" "LNKFLAGS = -s"
+
+#As above, curses support added...
+dellsys5r4c:
+ @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT -DHDBUUCP \
+ -DTCPSOCKET -DSTERMIOX -DCK_CURSES -DCK_POLL \
+ $(KFLAGS)" "LIBS= -lsocket -lnsl -lcurses -ltermcap" "LNKFLAGS = -s"
+
+#Minimum interactive: As above, but with every conceivable option removed.
+dellsys5r4mi:
+ @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...'
+ @echo 'Minimum-size interactive'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT \
+ -UTCPSOCKET -DNOCMDL -DNOSPL -DNOXMIT -DCK_POLL \
+ -DNOMSEND -DNOFRILLS -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \
+ -DNOSCRIPT -DNOCSETS -DNOSHOW -DNOSETKEY -DNOSERVER -DNOUUCP \
+ -DNOPUSH -DNOMDMHUP -DNOJC -DNOFDZERO -DNOESCSEQ \
+ $(KFLAGS)" "LNKFLAGS = -s"
+
+#Command-line only version.
+dellsys5r4m:
+ @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...'
+ @echo 'Command-line only'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT \
+ -UTCPSOCKET -DNOICP -DNOFRILLS -DNODIAL -DNODEBUG -DNOTLOG -DNOCSETS \
+ -DNOSETKEY -DNOESCSEQ -DNOJC -DNOFDZERO -DCK_POLL \
+ $(KFLAGS)" "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4.
+#Has <sys/termiox.h>.
+sys5r4sx:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DSTERMIOX -DNOLEARN \
+ $(KFLAGS)" "LNKFLAGS = -s" "LIBS=$(LIBS)"
+
+#AT&T UNIX System V R4.
+#Has <sys/termiox.h>, regular Berkeley sockets library, i.e. in.h and inet.h
+#are not misplaced in sys (rather than netinet and arpa, respectively).
+#Uses ANSI C constructs, <sys/termiox.h>, etc etc.
+sys5r4sxtcp:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl $(LIBS)" "LNKFLAGS= -s"
+
+#AT&T UNIX System V R4.
+#As above + curses.
+sys5r4sxtcpc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DCK_CURSES -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap $(LIBS)" "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4. CONSENSYS SVR4.2-1.
+#Has <sys/termiox.h>, regular Berkeley sockets library, i.e. in.h and inet.h
+#are not misplaced in sys (rather than netinet and arpa, respectively).
+#Uses ANSI C constructs, <sys/termiox.h>, etc.
+# Fullscreen -DCK_CURSES added (with curses & termcap libs)
+# Submission by Robert Weiner/Programming Plus, rweiner@watsun.cc.columbia.edu
+sys5r4sxtcpf:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -L/usr/ccs/lib -lcurses -ltermcap" \
+ "LIBS=$(LIBS)" "LNKFLAGS = -s"
+
+#Smallest possible version for System V R4
+s5r4m:
+ @echo Minimum size
+ $(MAKE) "MAKE=$(MAKE)" sys5r4sx KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \
+ -DNOSCRIPT -DNOCSETS -DNOICP -DNOMSEND -UTCPSOCKET" "LNKFLAGS = -s"
+
+#Smallest possible interactive version of above
+s5r4mi:
+ @echo Minimum interactive
+ $(MAKE) "MAKE=$(MAKE)" sys5r4sx \
+ "KFLAGS=-DNOSPL -DNOXMIT -DNOMSEND -DNOFRILLS -DNOSHOW \
+ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG -DNOSCRIPT -DNOCSETS -DNOSETKEY \
+ -UTCPSOCKET $(KFLAGS)" "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4, has <sys/termiox.h>
+#ANSI C function prototyping disabled.
+sys5r4sxna:
+ @echo No ANSI C prototyping...
+ $(MAKE) "MAKE=$(MAKE)" sys5r4sx KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DNOANSI"
+
+#Stratus FTX.
+ftx:
+ @echo 'Making C-Kermit $(CKVER) for Stratus FTX 3.x...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DFTX -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DNOGETUSERSHELL -DNOLEARN +DA1.1 $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS=$(LIBS)"
+
+#Stratus FTX + TCP/IP.
+ftxtcp:
+ @echo 'Making C-Kermit $(CKVER) for Stratus FTX 3.x...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DFTX -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DSTERMIOX -DTCPSOCKET -DNO_DNS_SRV +DA1.1 $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl $(LIBS)" "LNKFLAGS= -s"
+
+#NCR MP-RAS 2.03 or 3.02
+mpras:
+ @echo 'Making C-Kermit $(CKVER) for NCR MP-RAS...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DNCRMPRAS -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DNOGETUSERSHELL -DUSE_FILE__CNT -DNOLEARN -DNO_DNS_SRV $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS=$(LIBS)"
+
+#NCR MP-RAS 2.03 or 3.02 with TCP/IP and curses
+mprastcpc:
+ @echo 'Making C-Kermit $(CKVER) for NCR MP-RAS + TCP/IP + curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CFLAGS=-DTCPSOCKET \
+ -DCK_CURSES -DSVR4 -DNCRMPRAS -DDIRENT -DHDBUUCP -DSTERMIOX -DNOLEARN \
+ -DNOGETUSERSHELL -DNO_DNS_SRV DUSE_FILE__CNT -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS= -lsocket -lnsl -lcurses -ltermcap $(LIBS)"
+
+#SINIX-L V5.41 - includes curses, tcp/ip - Use this one for i386.
+#This version of SINIX doesn't like fdopen() or popen().
+sinix541:
+ @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf SINIX V5.41/i386'
+ $(MAKE) ckcpro.$(EXT) "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DNO_DNS_SRV \
+ -DSNI541 -DNOGETUSERSHELL -DNONETCMD -DNOPOPEN -kansi -W0 $(KFLAGS)"
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DNO_DNS_SRV -DNOPOPEN \
+ -DFNFLOAT -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC \
+ -DSNI541 -DNOGETUSERSHELL -DNONETCMD -kansi -W0 -O $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" "LNKFLAGS = -s"
+
+sinix541i:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sinix541
+
+#SINIX V5.42 - includes curses, tcp/ip, everything - Use this one for MIPS.
+# As of C-Kermit 7.1, optimization removed -- takes (literally) forever.
+sinix542:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DNO_DNS_SRV \
+ -DFNFLOAT -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC \
+ -DSNI542 -DNOGETUSERSHELL -kansi -W0 $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" "LNKFLAGS = -s"
+
+#SINIX V5.42 gcc - includes curses, tcp/ip, everything.
+#This one was used to build the Pyramid-architecture RM600 version
+#on SINIX-P 5.42 A10 with gcc but should work for SINIX 5.42 on any other
+#architecture with gcc.
+sinix542g:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=gcc" "CC2=gcc" \
+ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DNO_DNS_SRV \
+ -DFNFLOAT -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC \
+ -DSNI542 -DNOGETUSERSHELL $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" \
+ "LNKFLAGS = -s"
+
+#SINIX V5.42 - includes curses, tcp/ip, everything - Use this one for Intel.
+# (Note: SNI discontinued Intel support after 5.42.)
+sinix542i:
+ @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf SINIX-Z V5.42...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DFNFLOAT -DSTERMIOX \
+ -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DNO_DNS_SRV -kansi \
+ -DSNI542 $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" \
+ "LNKFLAGS = -s"
+
+#Siemens Nixdorf Reliant UNIX V5.43 - includes curses, tcp/ip, everything:
+# . gettimeofday() suddenly has only one arg instead of two (GTODONEARG).
+# . The syntax of the Olimit specifier changed.
+# . The name was changed from SINIX to Reliant UNIX in version 5.43C.
+sni543:
+ @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf Reliant UNIX V5.43'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSINIX -DSNI543 -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DGTODONEARG \
+ -DNO_DNS_SRV -kansi -W0 -O -F Olimit,3100 $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap" "LNKFLAGS = -s"
+
+#Siemens Nixdorf Reliant UNIX V5.44 - Like 5.43 but with different banner.
+sni544:
+ @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf Reliant UNIX V5.44'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSINIX -DSNI544 -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DGTODONEARG \
+ -DNO_DNS_SRV -kansi -W0 -O -K Olimit,3100 $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap" "LNKFLAGS = -s"
+
+#Commodore Amiga with AT&T UNIX System V R4 and TCP/IP support.
+#Has <sys/termiox.h>.
+svr4amiganet:
+ @echo 'Making C-Kermit $(CKVER) for Amiga SVR4 + TCP/IP...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=gcc" "CC2=gcc" \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DTCPSOCKET -DCK_CURSES $(KFLAGS)" "LNKFLAGS = -s" \
+ "LIBS = -lsocket -lnsl -ltermlib"
+
+#SCO (Novell (Univel)) UnixWare 1.x or 2.0, no TCP/IP.
+#This assumes the Novell SDK 1.0, which has <sys/termiox.h>.
+#UnixWare users with the "Prime Time Freeware" CD-ROM SDK will probably have
+#to use the sys5r4 entry (no termiox.h file, so no hardware flow control).
+#Change -DSELECT to -DCK_POLL if -DSELECT causes problems.
+# NOTE: Unixware 1.x builds have not been tried in C-Kermit 7.0.
+unixware:
+ $(MAKE) "MAKE=$(MAKE)" sys5r4sx KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DOLD_UNIXWARE -DCK_NEWTERM -DSELECT -DNOGETUSERSHELL \
+ -DNOSYSLOG $(KFLAGS)" "LIBS=-lcrypt"
+
+#UnixWare 1.x or 2.0 with TCP/IP and curses.
+#fork()-based CONNECT - no high serial speeds.
+unixwarenetc:
+ $(MAKE) "MAKE=$(MAKE)" sys5r4sxtcpc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DOLD_UNIXWARE -DCK_NEWTERM -DSELECT -DNOGETUSERSHELL \
+ -DNOSYSLOG $(KFLAGS)" "LIBS=-lcrypt -lresolv"
+
+uw10:
+ $(MAKE) unixwarenetc KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)"
+
+#This is for Unixware 2.0.x only - use unixware21 for UW 2.1.x.
+#Has special library search and enables special kludge around library
+#foulup regarding vfork() (which Kermit doesn't use). Forces POSIX-style
+#hangup.
+unixware20:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 2.0.x...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DOLD_UNIXWARE -DUNIXWARE2 -DSELECT -DSVR4 -DDIRENT \
+ -DHDBUUCP -DBIGBUFOK -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES \
+ -DTCPSOCKET -DUW200 -DFNFLOAT -DCK_NEWTERM -DNOSYSLOG $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lcrypt -lgen -lm -lresolv" \
+ "LNKFLAGS = -s"
+
+uw20:
+ $(MAKE) unixware20 KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)"
+
+#Adds big buffers ("large memory model") - otherwise the same as UnixWare 1.x.
+unixware21:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 2.1.x...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \
+ -DNOSYSLOG -DSTERMIOX -DCK_CURSES -DTCPSOCKET \
+ -DCK_NEWTERM -DFNFLOAT -DUNIXWARE2 $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv \
+ $(LIBS)" "LNKFLAGS = -s"
+
+#Unixware 2.1.0
+uw21:
+ $(MAKE) unixware21 KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)"
+
+#Unixware 2.1.3
+uw213:
+ $(MAKE) unixware21 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DUSE_FILE__CNT $(KFLAGS)"
+
+#Unixware 2.1 with IKSD support
+uw21iksd:
+ $(MAKE) unixware21 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DCK_SHADOW $(KFLAGS)" "LIBS= -lgen"
+
+#UnixWare 7 with tc[gs]etspeed() high serial speeds & select()-based CONNECT
+#and as of C-Kermit 8.0.212, large file support (LFS).
+#NOTE: This is the one we use.
+unixware7t:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 7 with POSIX i/o...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \
+ -DFNFLOAT -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DPOSIX \
+ -DUW7 -DUSETCSETSPEED -DCK_NEWTERM -DNOLSTAT -DDCLTIMEVAL \
+ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DNEEDMDMDEFS $(KFLAGS)" \
+ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \
+ "LNKFLAGS = -s"
+
+#UnixWare 7 - select()-based CONNECT - no POSIX i/o - no high serial speeds.
+#In other words, just like the UnixWare 1 and 2 builds.
+unixware7x:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 7...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \
+ -DUW7 -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DNOLSTAT \
+ -DFNFLOAT -DCK_NEWTERM $(KFLAGS)" \
+ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \
+ "LNKFLAGS = -s"
+
+#UnixWare 7 with POSIX cfset[oi]speed() to allow high serial speeds.
+#(but the high speeds don't work)
+unixware7p:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 7 with POSIX i/o...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \
+ -DUW7 -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DPOSIX \
+ -DFNFLOAT -DCK_NEWTERM -DNOLSTAT $(KFLAGS)" \
+ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \
+ "LNKFLAGS = -s"
+
+# UnixWare 7 built with gcc - This does not work at all...
+# Reportedly gcc 2.8.1 is broken on Unixware 7. Try egcs?
+unixware7g:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 7 with gcc...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s -shlib"
+ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \
+ -DUW7 -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DNOLSTAT \
+ -DFNFLOAT -DCK_NEWTERM $(KFLAGS)" \
+ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \
+ "LNKFLAGS = -s"
+
+unixware7:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" unixware7t \
+ KTARGET=$${KTARGET:-$(@)}
+
+uw7:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" unixware7t \
+ KTARGET=$${KTARGET:-$(@)}
+
+#SCO OpenUNIX 8.0
+ou8:
+ @echo 'Making C-Kermit $(CKVER) for Open UNIX 8...'
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DOU8 $(KFLAGS)" unixware7t \
+ KTARGET=$${KTARGET:-$(@)}
+
+#UnixWare 7 with OpenSSL
+uw7ssl uw7+ssl:
+ @echo 'Making C-Kermit $(CKVER) for UnixWare 7 and OpenSSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DCK_AUTHENTICATION -DCK_SSL -DCK_SHADOW \
+ -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \
+ -DFNFLOAT -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DPOSIX \
+ -DUW7 -DUSETCSETSPEED -DCK_NEWTERM -DNOLSTAT -DDCLTIMEVAL \
+ $(SSLINC) $(KFLAGS)" \
+ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv \
+ -lgen -lcudk70 $(SSLLIB) -lssl -lcrypto $(LIBS)" \
+ "LNKFLAGS = -s"
+
+#As above but includes Shadow password support needed for IKSD.
+uw7iksd:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DCK_SHADOW $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)} "LIBS= -lgen" unixware7t
+
+#As above but links with static API for realpath() so a binary built
+#with this target on UW7.1 will also work on 7.0. Requires SCO UDK
+#rather than the stock compiler.
+uw7iksdudk:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DCK_SHADOW $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)} "LIBS= -lgen -lcudk70" unixware7t
+
+#ESIX SVR4.0.3 or 4.04 with TCP/IP support.
+#Has <sys/termiox.h>, ANSI C function prototyping disabled.
+#Add -m486 to CFLAGS if desired.
+esixr4:
+ @echo 'Making C-Kermit $(CKVER) for ESIX SVR4 + TCP/IP...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOANSI \
+ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" "LNKFLAGS = -s" \
+ "LIBS = -lsocket -lnsl"
+
+#AT&T UNIX System V R4.
+#Has <sys/termiox.h>, Wollongong WIN/TCP TCP/IP.
+sys5r4sxnet:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \
+ -DSTERMIOX -DWOLLONGONG $(KFLAGS)" "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4, no <termio.x> or <sys/termio.x>.
+sys5r4nx:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOLEARN $(KFLAGS)" \
+ "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4, no <termio.x> or <sys/termio.x>, curses, TCP/IP.
+sys5r4nxnetc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \
+ -DCK_CURSES -DTCPSOCKET $(KFLAGS)" \
+ "LIBS = -lcurses -lsocket -lnsl -ltcpip" \
+ "LNKFLAGS = -s"
+
+#AT&T UNIX System V R4, no <termio.x> or <sys/termio.x>, Wollongong TCP/IP.
+sys5r4nxtwg:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DWOLLONGONG $(KFLAGS)"
+ "LNKFLAGS = -s"
+
+#ICL UNIX System V R4.(DRS N/X) version :-
+#UNIX System V Release 4.0 ICL DRS 6000 (SPARC)
+#DRS/NX 6000 SVR4 Version 5 Level 1 Increment 4
+#Has <sys/termiox.h>, regular Berkeley sockets library, i.e. in.h and inet.h
+#are not misplaced in sys (rather than netinet and arpa, respectively).
+#Uses ANSI C constructs, advisory file locking on devices, etc.
+#Remove -lnsl if it causes trouble.
+iclsys5r4:
+ @echo 'Making C-Kermit $(CKVER) for ICL UNIX System V R4 (DRS N/X)'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DICL_SVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lresolv " "LNKFLAGS = -s"
+
+#As above but for DRS/NX 4.2MP 7MPlus.
+iclsys5r4m+:
+ @echo 'Making C-Kermit $(CKVER) for ICL UNIX System V R4 DRS/NX 4.2MP+'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DICL_SVR4 -DDIRENT -DHDBUUCP -DNOIKSD \
+ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lm -lc -g -lgen " "LNKFLAGS = -s"
+
+#As above but for DRS/NX 4.2MP 7MPlus with IKSD support.
+iclsys5r4m+iksd:
+ @echo 'Making C-Kermit $(CKVER) for ICL UNIX System V R4 DRS/NX 4.2MP+'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DICL_SVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lm -lc -g -lgen -lresolv " "LNKFLAGS = -s"
+
+iclsys5r4_486:
+ $(MAKE) "MAKE=$(MAKE)" iclsys5r4 KTARGET=$${KTARGET:-$(@)}
+
+#Data General DG/UX 4.30 (System V R3) for DG AViiON, with TCP/IP support.
+dgux430:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 4.30...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX430 -DSVR3 -DDIRENT -DTCPSOCKET \
+ -DNOINADDRX -DNOGETUSERSHELL $(KFLAGS)"
+
+#Data General DG/UX 4.30 for DG AViiON, with TCP/IP support with BSDisms.
+dgux430bsd:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 4.30...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX430 -D_BSD_SOURCE -DBSD4 \
+ -DNOINADDRX -DTCPSOCKET -DNOGETUSERSHELL $(KFLAGS)"
+
+#Data General DG/UX 5.4 (System V R4) for DG AViiON, with TCP/IP support.
+#Add -lsocket -lnsl if inet_addr comes up missing...
+#Hmmm - I really think CK_POLL can be removed from this one in which case
+#there is no difference between dgux540 and dgux540i.
+dgux540:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.40...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \
+ -DSTERMIOX -DTCPSOCKET -DCK_POLL -DNOGETUSERSHELL $(KFLAGS)"
+
+#Data General DG/UX 5.40 (System V R4) for Intel AViiON, with TCP/IP support.
+dgux540i:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.40...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \
+ -DSTERMIOX -DTCPSOCKET -DNOGETUSERSHELL $(KFLAGS)" \
+ "LIBS = -lsocket -lnsl"
+
+dgux54:
+ make dgux540 KTARGET=$${KTARGET:-$(@)}
+
+#Data General DG/UX 5.4 (= System V R4) for DG AViiON, with TCP/IP support.
+# And curses.
+dgux540c:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.4...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \
+ $(KFLAGS)" "LIBS= -lcurses8 -ltermcap" "LNKFLAGS = -s"
+
+#As above but for Intel - only difference is name library names.
+dgux540ic:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.40...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \
+ $(KFLAGS)" "LIBS = -lsocket -lnsl -lcurses -ltermcap"
+
+dgux54c:
+ make dgux540c KTARGET=$${KTARGET:-$(@)}
+
+#DG/UX 5.4R3.10
+dgux54310:
+ @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.4R3...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DDGUX540 -DDGUX54310 -DDIRENT -DHDBUUCP -DSELECT \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \
+ -DNOINADDRX $(KFLAGS)" "LIBS= -lcurses8 -ltermcap" "LNKFLAGS = -s"
+
+#DG/UX 5.4R4.10 - Includes everything.
+dgux54410:
+ @echo 'Making C-Kermit $(CKVER) for DG/UX 5.4R4.10...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDGUX54410 -DDIRENT -DHDBUUCP -DSELECT \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \
+ -DNOINADDRX $(KFLAGS)" "LIBS = -lsocket -lnsl -lcurses -ltermcap"
+
+#DG/UX 5.4R4.11 - Includes everything.
+dgux54411:
+ @echo 'Making C-Kermit $(CKVER) for DG/UX 5.4R4.11...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDGUX54411 -DDIRENT -DHDBUUCP -DSELECT \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \
+ -DNOINADDRX $(KFLAGS)" "LIBS = -lsocket -lnsl -lcurses -ltermcap"
+
+#DG/UX 5.4R4.20 - Includes everything.
+dgux54420:
+ @echo 'Making C-Kermit $(CKVER) for DG/UX 5.4R4.20...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DDGUX540 -DDGUX54420 -DDIRENT -DHDBUUCP -DSELECT \
+ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \
+ -DNOINADDRX $(KFLAGS)" \
+ "LIBS = -lsocket -lresolv -lnsl -lcurses -ltermcap"
+
+#Silicon Graphics System V R3 with BSD file system (IRIS)
+iris:
+ @echo Making C-Kermit $(CKVER) for Silicon Graphics IRIX pre-3.3...
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR3 -DLONGFN -DNOLEARN $(KFLAGS) -I/usr/include/bsd" \
+ "LIBS = -lbsd"
+
+#Silicon Graphics IRIS System V R3
+irix33:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 3.3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNOLEARN $(KFLAGS) -O" \
+ "LNKFLAGS = -s"
+
+#Silicon Graphics Iris Indigo with IRIX 4.0.0 or 5.0...
+#Strict ANSI C compilation, TCP/IP support included
+irix40:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DPWID_T=uid_t \
+ -DCK_ANSIC -DTCPSOCKET $(KFLAGS) -O -Olimit 1600 -I/usr/include/bsd" \
+ "LNKFLAGS = -s"
+
+#As above, but with fullscreen display (curses) and Sun Yellow Pages support.
+#NOTE: IRIX versions prior to 5 run COFF binaries.
+irix40ypc:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0.'
+ @echo 'Includes fullscreen file display and Sun Yellow Pages...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DCK_CURSES \
+ -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET $(KFLAGS) \
+ -O -Olimit 1600 -I/usr/include/bsd" \
+ "LIBS = -lcurses -lsun" "LNKFLAGS = -s"
+
+# Silicon Graphics Iris Series 4D/*, IRIX 4.0.x, -O4 ucode optimized.
+# Huge temporary file space needed for ucode optimizer. If you get an error
+# like "ugen: internal error writing to /tmp/ctmca08777: Error 0", define the
+# the TMPDIR environment variable to point to a file system that has more
+# space available, e.g. "setenv TMPDIR /usr/tmp".
+irix40u:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DPWID_T=uid_t \
+ -DCK_ANSIC -DTCPSOCKET $(KFLAGS) -O4 -Olimit 1600" \
+ "LNKFLAGS=-O4 -Olimit 1600 -s" "EXT=u"
+
+# As above, with Curses Support added
+irix40uc:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DPWID_T=uid_t \
+ -DCK_ANSIC -DCK_CURSES -DTCPSOCKET $(KFLAGS) -O4 -Olimit 1600" \
+ "LNKFLAGS=-O4 -Olimit 1600 -s" "EXT=u" "LIBS= -lcurses -ltermcap"
+
+#Silicon Graphics IRIX 5.x.
+#Yellow Pages and Curses support included.
+#IRIX version 5.x can run COFF or ELF binaries.
+irix51:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 5.x'
+ @echo 'Includes fullscreen file display and Yellow Pages...'
+ @echo 'Add -mips<n> to CFLAGS specify a particular hardware target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DIRIX51 -DSVR4 -DDIRENT -DHDBUUCP -DCK_CURSES -DCK_NEWTERM \
+ -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET -DSELECT -DNOGETUSERSHELL \
+ -DSYSTIMEH -DDCLPOPEN -DDCLFDOPEN $(KFLAGS) -ansi -O -Olimit 3000" \
+ "LIBS = -lcurses" "LNKFLAGS = -s"
+
+#Use this one if irix51 blows up due to lack of swap space or whatever.
+irix51x:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 5.x'
+ @echo 'Includes fullscreen file display and Yellow Pages...'
+ @echo 'Add -mips<n> to CFLAGS specify a particular hardware target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DIRIX51 -DSVR4 -DDIRENT -DHDBUUCP -DCK_CURSES -DCK_NEWTERM \
+ -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET -DSELECT -DNOGETUSERSHELL \
+ -DSYSTIMEH -DDCLPOPEN -DDCLFDOPEN $(KFLAGS)" \
+ "LIBS = -lcurses" "LNKFLAGS = -s"
+
+irix51ypc:
+ $(MAKE) "MAKE=$(MAKE)" irix51 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS= $(KFLAGS)"
+
+#IRIX 5.2 adds RTS/CTS
+irix52:
+ $(MAKE) "MAKE=$(MAKE)" irix51 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DIRIX52 -DCK_RTSCTS $(KFLAGS)"
+
+irix53:
+ $(MAKE) "MAKE=$(MAKE)" irix51 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DIRIX52 -DIRIX53 -DCK_RTSCTS $(KFLAGS)"
+
+irix53x:
+ $(MAKE) "MAKE=$(MAKE)" irix51x KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DIRIX52 -DIRIX53 -DCK_RTSCTS $(KFLAGS)"
+
+#Silicon Graphics IRIX 6.[024] common stuff.
+#Yellow Pages and Curses support included.
+#IRIX version 6.0 and later runs only ELF binaries.
+#Depends on code changes in ckcdeb.h that make -DIRIX6x define all
+#lower IRIX6x values and IRIX51.
+irix6x:
+ @echo 'Includes fullscreen file display and Yellow Pages...'
+ @echo 'Add -mips<n> to specify a particular hardware target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DCK_CURSES -DCK_NEWTERM -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET \
+ -DSELECT -DCK_RTSCTS -O $(KFLAGS)" \
+ "LIBS = -lcurses" "LNKFLAGS = -s $(LNKFLAGS)"
+
+#Silicon Graphics IRIX 6.0.
+irix60:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.0'
+ @$(MAKE) "MAKE=$(MAKE)" \
+ "KFLAGS=-DIRIX60 -Olimit 2138 $(KFLAGS)" \
+ irix6x KTARGET=$${KTARGET:-$(@)}
+
+#Silicon Graphics IRIX 6.2.
+#Serial speeds > 38400 are available in IRIX 6.2 on O-class machines only.
+#Note: Olimit must be a number > 0.
+irix62:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.2'
+ @$(MAKE) "MAKE=$(MAKE)" \
+ LNKFLAGS="-Wl,-woff,84" \
+ "KFLAGS=-DIRIX62 -Olimit 4700 $(KFLAGS)" \
+ irix6x KTARGET=$${KTARGET:-$(@)}
+
+#Silicon Graphics IRIX 6.3.
+irix63:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.3'
+ @$(MAKE) "MAKE=$(MAKE)" irix62 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DIRIX63"
+
+#Silicon Graphics IRIX 6.4.
+# -woff,84 to linker stops complaints about no symbols loaded from
+# curses, and -woff 1110 stops complaints about unreachable "break;"
+# statements in ckcpro.c among others.
+# tested on SGI Octane, running IRIX 6.4 up to 115200 bps.
+# -Olimit 0 means infinite.
+irix64:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.4'
+ @$(MAKE) "MAKE=$(MAKE)" \
+ LNKFLAGS="-Wl,-woff,84" \
+ "KFLAGS=-DIRIX64 -DCK_RTSCTS -Olimit 3000 -woff 1110 $(KFLAGS)" \
+ irix6x KTARGET=$${KTARGET:-$(@)}
+
+irix64gcc:
+ @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.4 gcc'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -DSVR4 -DIRIX64 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DSELECT -DPWID_T=uid_t -DTCPSOCKET -DNOCOTFMC \
+ -DCK_ANSIC -DCK_RTSCTS -DCK_NEWTERM -DCK_CURSES \
+ $(KFLAGS) -O" "LIBS= -lcurses -ltermcap -lcrypt"
+
+#Note the new Optimization option syntax for MIPSpro CC 7.2.1.2m.
+#See note on irix65gcc target about Large File Support (LFS).
+irix65:
+ @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5'
+ @$(MAKE) "MAKE=$(MAKE)" LNKFLAGS="-Wl,-woff,84" \
+ "KFLAGS=-DIRIX65 -D_LARGEFILE_SOURCE -DCK_RTSCTS -OPT:Olimit=0 \
+ -woff 1110,1552,1174 $(KFLAGS)" \
+ irix6x KTARGET=$${KTARGET:-$(@)}
+
+#Build for those that have GCC instead of MIPSpro.
+#
+# Large File Support note: use the define _LARGEFILE_SOURCE to enable support
+# for files larger than 2GB. This may work on releases of Irix prior to
+# 6.5.xx. To verify, check the man page for fstat and verify that off_t is a
+# 64 bit value for an -n32 build. Also check the manpage for fseek and ftell
+# to verify that the fseek64 and ftell64 functions are provided. If so, then
+# LFS support should work and you can try adding -D_LARGEFILE_SOURCE to CFLAGS
+# for your selected Irix target.
+#
+irix65gcc:
+ @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5 with gcc'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -DSVR4 -DIRIX65 -D_LARGEFILE_SOURCE -DDIRENT -DHDBUUCP \
+ -DNOGETUSERSHELL -DSELECT -DPWID_T=uid_t -DTCPSOCKET -DNOCOTFMC \
+ -DCK_ANSIC -DCK_RTSCTS -DCK_NEWTERM -DCK_CURSES \
+ $(KFLAGS) -O" "LIBS= -lcurses"
+
+# The 64-bit IRIX target works but presumably is no longer needed given the
+# large file support in the more portable and compact 32-bit version.
+irix65_64:
+ @echo 'Making C-Kermit $(CKVER) 64-bit for SGI IRIX 6.5'
+ @$(MAKE) "MAKE=$(MAKE)" LNKFLAGS="-Wl,-woff,84" \
+ "KFLAGS=-DIRIX65 -64 -DCK_RTSCTS -OPT:Olimit=0 -woff 1110,1552,1174 \
+ -DCK_64BIT $(KFLAGS)" \
+ irix6x KTARGET=$${KTARGET:-$(@)}
+
+#Dumb down to MIPS-2 if building on R5000 or higher...
+irix65mips2:
+ @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5 MIPS-2'
+ @$(MAKE) "MAKE=$(MAKE)" LNKFLAGS="-o32 -mips2 -Wl,-woff,84" \
+ "KFLAGS=-DIRIX65 -DCK_RTSCTS -OPT:Olimit=0 -o32 -mips2 \
+ -woff 1110,1552,1174 $(KFLAGS)" \
+ irix6x KTARGET=$${KTARGET:-$(@)}
+
+#Special target that adds srp, ssl, and zlib support. This requires
+#that you have pkgsrc installed instead of Irix Freeware. See
+#NetBSD.org for pkgsrc for Irix. You will need to BUILD the srp_client
+#package yourself. Install it manually using the directions found
+#in the netbsds+ssl+srp+zlib target comments.
+irix65+ssl+srp+zlib:
+ @echo 'Making C-Kermit $(CKVER) for IRIX 6.5 with gcc and SSL SRP ZLIB'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -DIRIX65 -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL -DSELECT \
+ -DTCPSOCKET -DNOCOTFMC -DCK_NEWTERM -DPWID_T=uid_t -DCK_ANSIC \
+ -I/usr/pkg/include -DCK_AUTHENTICATION -DCK_SRP -DPRE_SRP_1_4_5 \
+ -DCK_RTSCTS -DCK_NCURSES -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DCK_SSL \
+ -DLIBDES -DZLIB -DFNFLOAT -I/usr/pkg/include/openssl $(KFLAGS) -O" \
+ "LIBS= -L/usr/pkg/lib -rpath /usr/pkg/lib -lncurses -lsrp -lgmp -ldes \
+ -lssl -lkrypto -lcrypto -lcrypt -lz -lm"
+
+irix6x+krb5:
+ @echo 'Includes fullscreen file display and Yellow Pages...'
+ @echo 'Add -mips<n> to specify a particular hardware target.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \
+ -DCK_CURSES -DCK_NEWTERM -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET\
+ -DSELECT -DCK_RTSCTS -O \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DCK_ENCRYPTION -DCK_DES \
+ $(K5INC) $(K5INC)/krb5 $(KFLAGS)" \
+ "LIBS = -lcurses $(K5LIB) -ldes425 -lkrb5 \
+ -lcom_err -lcrypto -lcrypt -lgssapi_krb5" \
+ "LNKFLAGS = -s $(LNKFLAGS)"
+
+irix65+krb5:
+ @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5'
+ @$(MAKE) "MAKE=$(MAKE)" \
+ LNKFLAGS="-Wl,-woff,84" \
+ "KFLAGS=-DIRIX65 -DCK_RTSCTS -OPT:Olimit=0 -woff 1110,1552,1174 \
+ $(KFLAGS)" \
+ irix6x+krb5 KTARGET=$${KTARGET:-$(@)}
+
+#In case they type "make sys5"...
+sys5:
+ $(MAKE) "MAKE=$(MAKE)" sys3 KTARGET=$${KTARGET:-$(@)}
+
+#Generic ATT System III or System V (with I&D space)
+sys3:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III'
+ @echo 'or System V R2 or earlier...'
+ @echo 'add -DNOMKDIR if mkdir is an undefined symbol.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DNOUNICODE -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL \
+ -DNOINITGROUPS -DNOFTRUNCATE -DNOREALPATH -DNOLEARN $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i"
+
+#Generic ATT System III or System V (no I&D space)
+sys3nid:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III'
+ @echo 'or System V R2 or earlier, no I&D space...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DNOREALPATH -DNOUNICODE -DNOSYSLOG -DNOSYMLINK \
+ -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE -DNOLEARN $(KFLAGS) -O" \
+ "LNKFLAGS ="
+
+#Generic ATT System III or System V R2 or earlier, "no void":
+#special entry to remove "Illegal pointer combination" warnings.
+sys3nv:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III'
+ @echo 'or System V R2 or earlier...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DATTSV -DNOREALPATH -DNOUNICODE -DNOSYSLOG -DNOGETUSERSHELL \
+ -DNOSYMLINK -DNOFTRUNCATE -DNOINITGROUPS -DNOLEARN \
+ -Dvoid=int $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i"
+
+# AT&T 7300 UNIX PC. As of C-Kermit 6.1, many of these entries don't work
+# any more due to "Out of memory" or "Too many defines" errors during
+# compilation, at least not on systems without lots of memory. The sys3upcgc
+# entry works (using gcc) with optimization removed, and might also work
+# with optimization enabled on machines with larger memories.
+
+#AT&T 7300/UNIX PC (3B1) systems, sys3 but special handling for internal modem.
+#Link with the shared library -- the conflict with openi in shared library
+#is solved with -Dopeni=xopeni. Note that the xermit target can't be used
+#for the Unix PC; there is no select().
+sys3upc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, shared lib...'
+ @echo 'If shared lib causes trouble, use make sys3upcold.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DATT7300 -DNOMKDIR -DUSE_MEMCPY -DNOREALPATH -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOREDIRECT -DNOGFTIMER -DNOUNICODE $(KFLAGS) -Dopeni=xopeni" \
+ "CC2 = ld /lib/crt0s.o /lib/shlib.ifile" "LNKFLAGS = -s"
+
+#AT&T 7300/Unix PC systems, minimum kermit for those with smaller amounts
+#of memory.
+sys3upcm:
+ @echo Minimum interactive
+ $(MAKE) "MAKE=$(MAKE)" sys3upc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOSPL -DNOFRILLS -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS \
+ -DNOSYSLOG -DNOSETKEY -DNOREALPATH"
+
+#AT&T 7300/UNIX PC (3B1) systems, with curses support.
+#Curses and the shared library don't get along, so we don't use the
+#shared library. We need to include CK_NEWTERM to avoid a conflict
+#with curses and buffering on stdout. Merged with submission by
+#Robert Weiner/Programming Plus, rweiner@watsun.cc.columbia.edu.
+#We don't need -Dopeni=xopeni since we're not using the shared library,
+#but we keep it to be consistent with the other entries.
+sys3upcc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DATT7300 -DNOREALPATH \
+ -DCK_CURSES -DCK_NEWTERM -DNOMKDIR -DNOREDIRECT -DNOGFTIMER -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DUSE_MEMCPY -DNOUNICODE $(KFLAGS) -Dopeni=xopeni" \
+ "LIBS = -lcurses" "LNKFLAGS = -s"
+
+#Like sys3upcc but for AT&T UNIX 3.51m (released as a patch on Fix Disk 2),
+#adds hardware flow control.
+att351m:
+ $(MAKE) "MAKE=$(MAKE)" sys3upcc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DCK_RTSCTS -DUNIX351M"
+
+#As above but with gcc.
+att351gm:
+ $(MAKE) "MAKE=$(MAKE)" sys3upcgc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DCK_RTSCTS -DUNIX351M"
+
+#AT&T 7300 UNIX PC (3B1), as above, but no newterm().
+sys3upcx:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DATT7300 -DNOREALPATH -DNOUNICODE -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DCK_CURSES -DNOMKDIR -DNOREDIRECT -DNOGFTIMER -DUSE_MEMCPY $(KFLAGS) \
+ -Dopeni=xopeni" "LIBS = -lcurses -ltermcap" "LNKFLAGS = -s"
+
+#AT&T 7300/UNIX PC (3B1) systems, with curses and shared library support.
+sys3upcshcc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, shared lib...'
+ @echo 'With curses. Requires shcc.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DATT7300 -DNOMKDIR -DNOREALPATH -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DCK_NEWTERM -DCK_CURSES -DNOREDIRECT -DNOGFTIMER \
+ -DUSE_MEMCPY -DNOUNICODE $(KFLAGS) -Dopeni=xopeni" \
+ "LNKFLAGS = -i -s" "CC = shcc" "CC2 = shcc" "LIBS = -lcurses"
+
+#AT&T 7300/UNIX PC (3B1) systems, as above, no curses, but use gcc.
+sys3upcg:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT7300 -DNOREDIRECT -DUSE_MEMCPY -DNOUNICODE -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOGFTIMER -DNOMKDIR -DNOREALPATH $(KFLAGS) -Dopeni=xopeni" \
+ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s -shlib"
+
+#AT&T 7300/UNIX PC (3B1) systems, curses and gcc.
+#Optimization omitted -- add it back in if your machine has lots of memory.
+sys3upcgc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT7300 -DNOREDIRECT -DUSE_MEMCPY -DNOGFTIMER -DNOUNICODE \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DCK_CURSES -DCK_NEWTERM -DNOMKDIR -DNOREALPATH -DNOLEARN $(KFLAGS)" \
+ "CC = gcc" "CC2 = gcc" "LIBS = -lcurses" "LNKFLAGS = -s"
+
+#AT&T 7300/UNIX PC (3B1) systems, special handling for internal modem.
+#No FULLSCREEN file transfer display (curses).
+sys3upcold:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT7300 -DNOMKDIR -DUSE_MEMCPY -DNOUNICODE -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOGFTIMER -DNOREDIRECT -DNOREALPATH $(KFLAGS) -O" "LNKFLAGS = -i"
+
+#As above, but with gcc. mininum features - fits on a 400K UNIX PC floppy
+#after compression with room to spare; add -DNOSHOW or other -DNOxxxx items
+#to reduce size even further.
+sys3upcgm:
+ @echo Minimum interactive
+ $(MAKE) "MAKE=$(MAKE)" sys3upcg KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DNOSPL -DNOFRILLS -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS \
+ -DNOSETKEY $(KFLAGS)"
+
+#This target is designed to create a version with the most features possible
+#that, after compression, still fits on a 400K UNIX PC floppy.
+sys3upcgfd:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC floppy...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT7300 -DNOREDIRECT -DUSE_MEMCPY -DNOSPL -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOGFTIMER -DNOREALPATH -Dopeni=xopeni \
+ -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS -DNOSETKEY -DNOMKDIR $(KFLAGS)" \
+ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s"
+
+#AT&T 6300 PLUS (warning, -O might make it run out of space).
+#NOTE: Remove -DHDBUUCP if not using Honey DanBer UUCP.
+att6300:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 6300 PLUS...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT6300 -DHDBUUCP -DNOFILEH -DNOREALPATH -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOUNICODE $(KFLAGS) -O -Ml -i" "LNKFLAGS = -i -Ml"
+
+#As above, but with curses support. Debugging disabled to prevent thrashing.
+att6300c:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 6300 PLUS...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT6300 -DHDBUUCP -DNOFILEH -DNOCSETS -DNOREALPATH \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DCK_CURSES -DNODEBUG -DNOUNICODE -DNOLEARN $(KFLAGS) -O -Ml -i" \
+ "LNKFLAGS = -i -Ml" "LIBS = -lcurses"
+
+#AT&T 6300 PLUS with no curses, no debugging (about 34K smaller)
+# -Optimization saves about 20K too.
+att6300nd:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 6300 PLUS, no debugging...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATT6300 -DHDBUUCP -DNODEBUG -DNOFILEH -DNOREALPATH \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOUNICODE -DNOLEARN $(KFLAGS) -O -i -Ml" "LNKFLAGS = -i -Ml"
+
+#AT&T 3B2 and maybe 3B20-series computers running AT&T UNIX System V R3.
+#This one was actually used to build C-Kermit 7.0 successfully on a 3B2/300.
+att3b2:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 3B2'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DNOREDIRECT -DUSE_MEMCPY \
+ -DNOTIMEVAL -DNOTIMEZONE -DMINIDIAL -DNOCHANNELIO -DNOBIGBUF \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOGFTIMER -DNOREALPATH -Dopeni=xopeni -DNOFRILLS -DNOLEARN \
+ -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS -DNOSETKEY -DNOMKDIR $(KFLAGS)" \
+ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s"
+
+# The next two are likely not to work as-is.
+
+#AT&T 3B2, 3B20-series computers running AT&T UNIX System V.
+#This is just generic System V with Honey DanBer UUCP, so refer to sys3hdb.
+#Remove -DNONAWS if you can get away with it.
+att3bx:
+ $(MAKE) "MAKE=$(MAKE)" sys3hdb KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DNONAWS -DNOTIMEVAL"
+
+# 3Bx with charsets (except Unicode) but no curses.
+att3bx1:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 3B2 or 3B20'
+ @echo 'with Honey DanBer UUCP no curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DHDBUUCP $(KFLAGS) -DNOREDIRECT \
+ -DNOTIMEVAL -DNOTIMEZONE -DMINIDIAL -DNOCHANNELIO -DNOBIGBUF \
+ -DNOHELP -DNODEBUG -DNOGFTIMER -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOREALPATH -DNOUNICODE -i" \
+ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -i -s"
+
+#AT&T 3B2, 3B20-series computers running AT&T UNIX System V,
+#with fullscreen file transfer display.
+att3bxc:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 3B2 or 3B20'
+ @echo 'with Honey DanBer UUCP and curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DHDBUUCP -DNONAWS -DNOTIMEVAL $(KFLAGS) \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOREALPATH -DCK_CURSES -DCK_NEWTERM -DNOUNICODE -DNOLEARN -i -O" \
+ "LNKFLAGS = -i" "LIBS=-lcurses"
+
+#3bx with curses but no charsets
+att3bxc3:
+ @echo 'Making C-Kermit $(CKVER) for AT&T 3B2 or 3B20'
+ @echo 'with Honey DanBer UUCP with curses... no CSETS'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DHDBUUCP $(KFLAGS) -DNOREDIRECT \
+ -DNOTIMEVAL -DNOTIMEZONE -DMINIDIAL -DNOCHANNELIO -DNOBIGBUF \
+ -DNOHELP -DNODEBUG -DNOGFTIMER -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOREALPATH -DNOCSETS -DCK_CURSES -DCK_NEWTERM -i" \
+ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -i -s" "LIBS = -lcurses"
+
+#Any System V R2 or earlier with Honey DanBer UUCP (same as above)
+sys3hdb:
+ @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III'
+ @echo 'or System V R2 or earlier with Honey DanBer UUCP...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DHDBUUCP -DNOREALPATH -DNOUNICODE -DNOLEARN \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ $(KFLAGS) -i -O" "LNKFLAGS = -i"
+
+#Sperry/UNISYS 5000 UTS V 5.2 (System V R2), Honey DanBer UUCP
+unisys5r2:
+ @echo 'Making C-Kermit $(CKVER) for Sperry/UNISYS 5000 UTS V 5.2...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DUNISYS52 -DHDBUUCP -DNOREALPATH -DNOUNICODE \
+ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \
+ -DNOLEARN $(KFLAGS) -i -O" "LNKFLAGS = -i"
+
+#In case they say "make sys5hdb" instead of "make sys3hdb"...
+sys5hdb:
+ $(MAKE) "MAKE=$(MAKE)" sys3hdb
+
+#Create the common header line for all hpux[5-11]* entries and above. This
+#extra entry is here because our header message length may differ for each
+#C-Kermit version. Don't use 'fold -s' for HP-UX 5.x - 7.x! This option is
+#available only for HP-UX 8.0 and above!
+hpux-header:
+ @HPUX=`uname -r | sed -e 's/^[^1-9]*//' -e 's/\.00$$/.0/'` ; \
+ [ "$(MESSAGE0)" ] && MESSAGE1="$(MESSAGE0)" ; \
+ Message0='Making C-Kermit $(CKVER) for HP9000 HP-UX' ; \
+ Message1=$${MESSAGE1:='without any extra compiler optimization'} ; \
+ MessageH="$$Message0 $$HPUX" ; \
+ case $$HPUX in \
+ [567].*) echo "$$MessageH\n$$Message1" ;; \
+ *.*) echo "$$MessageH $${Message1}$(MESSAGE1A)" | fold -s ;; \
+ esac | sed -e 's/^ //' -e 's/ *$$//'
+
+# Peter E's updated HP-UX 5.xx entries Oct 2001.
+
+#HP-9000 500 HP-UX 5.xx, no TCP/IP.
+# Last known successful build: C-Kermit 8.0.206 2002/20/27.
+hpux0500:
+ @MESSAGE0="no TCP/IP and no compiler optimization";\
+ MESSAGE0=$${MESSAGE1:-$$MESSAGE0} \
+ $(MAKE) hpux-header
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUX -DHPUX5 -DHPUXPRE65 -DNOREDIRECT -DDCLGETCWD \
+ -DNOGETUSERSHELL -DNOGFTIMER -DNOSYSLOG -DNOTOMACROS -DNOLSTAT \
+ -DNOSYMLINK -DNOINITGROUPS -DNOUNICODE -DNOLEARN -DNOLONGLONG \
+ -DVOID=int -DCKVOID=int $(KFLAGS)" "LIBS = $(LIBS)" "LNKFLAGS = "
+
+#HP-9000 500 HP-UX 5.21 with Wollongong WIN/TCP 1.2 TCP/IP.
+#Requires /usr/wins/usr/include and /usr/lib/libnet.a from Wollongong.
+#Optimization skipped - takes forever. Really.
+# WARNING: this doesn't work if a file called "hpux0500" is on the disk.
+# Last known successful build: C-Kermit 8.0.206 2002/20/27.
+hpux0500wintcp:
+ @MESSAGE1="with WIN/TCP but without any extra compiler optimization" \
+ $(MAKE) hpux0500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = -DTCPSOCKET -DHPUX5WINTCP -DINADDRX -DNO_DNS_SRV \
+ -DNOMHHOST -DVOID=int -DCKVOID=int -DNOHADDRLIST -DNOLONGLONG \
+ -I/usr/wins/usr/include $(KFLAGS)" "LIBS = /usr/lib/libnet.a"
+
+#HP-UX 6.5, short filenames, no network and no curses support.
+#ckcpro, ckuusr, ckuus3 and others are broken out because they make the
+#optimizer run away. Note that the XERMIT target does not work with HP-UX 6.5!
+#
+#If you get compiler warnings like:
+#'Switch table overflow. Try the -Wc,-Nw option.' (for ckcuni.c, or
+#other files) increase the '...' value in '-Wc,-Nw...'! The default maximum
+#switch table stack (-Nw) is 250 table entries. ckcuni.c from Oct 16 2009
+#needs 257 table entries (C-Kermit Version "9.0.299").
+#OK: 2010/03/26
+hpux0650:
+ @$(MAKE) hpux-header
+ @MESSAGE2=$${MESSAGE2:-'and NO network'}; \
+ echo "supporting: NO long filenames $$MESSAGE2."
+
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \
+ ckuusr.$(EXT) ckuxla.$(EXT) ckcftp.$(EXT) ckcpro.$(EXT) \
+ "CFLAGS = -DHPUX -DHPUX6 -DSIG_V -DNOSYSLOG -DNOSELECT -DFNFLOAT \
+ -DDCLGETCWD -DNOGETUSERSHELL -DNO_DNS_SRV -DNOLEARN -DNOLONGLONG \
+ $(KFLAGS)"
+
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUX -DHPUX6 -DSIG_V -DNOSYSLOG -DNOSELECT -DFNFLOAT \
+ -DDCLGETCWD -DNOGETUSERSHELL -DNO_DNS_SRV -DNOLEARN -DNOLONGLONG \
+ $(KFLAGS) -Wc,-Nw260 $(OFLAGS)" "LNKFLAGS = -s" "LIBS = -lm $(LIBS)"
+
+#Exactly as above, plus curses:
+#OK: 2009/10/06
+hpux0650c:
+ @MESSAGE2="and NO network but with curses" \
+ $(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = -DCK_CURSES $(KFLAGS)" \
+ "LIBS = -lcurses"
+
+#Exactly as above, plus curses + network:
+#OK: 2009/10/02
+hpux0650tcpc:
+ @MESSAGE2="but with curses and with TCP/IP" \
+ $(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DCK_CURSES -DTCPSOCKET -DNOHADDRLIST \
+ -DINTSELECT -DNOCKGETFQHOST $(KFLAGS)" \
+ "LIBS=-lcurses"
+
+#Exactly as hpux0650 but with compiler optimization:
+#OK: 2009/10/06
+hpux0650o:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as hpux0650c but with compiler optimization:
+#OK: 2009/10/06
+hpux0650oc:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0650c KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as hpux0650tcpc but with compiler optimization:
+#OK: 2009/10/06
+hpux0650otcpc:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0650tcpc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#Take this as startup entry for all 'non-optimized' files under HP-UX 7.x!
+#Make sure we don't call it with the '-O' option because this will blow up
+#the compiler!
+#OK: 2009/09/30
+hpux0700noopt:
+ @case "$(CFLAGS)" in \
+ *-O*) echo "Don't use CFLAGS= -O here!" ;; \
+ *) $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ ckuusr.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+ ckuus6.$(EXT) ckuus7.$(EXT) ckuxla.$(EXT) \
+ ckcuni.$(EXT) ckcftp.$(EXT) ckcpro.$(EXT) \
+ ;; \
+ esac
+
+#HP-UX 7.0, no long filenames, no network support, no curses.
+#If you get compiler warnings like:
+#'Switch table overflow. Try the -Wc,-Nw option.' (for ckcuni.c, or
+#other files) increase the '...' value in '-Wc,-Nw...'! The default maximum
+#switch table stack (-Nw) is 250 table entries. ckcuni.c from Oct 16 2009
+#needs 257 table entries (C-Kermit Version "9.0.299").
+#OK: 2010/10/26
+hpux0700sf:
+ @$(MAKE) hpux-header
+ @echo 'supporting: NO long filenames, NO network, NO curses.'
+ $(MAKE) hpux0700noopt KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUX -DHPUX7 -DSIG_V -DNOGETUSERSHELL -DFNFLOAT \
+ -DNO_DNS_SRV $(KFLAGS) -Wc,-Nw260"
+
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUX -DHPUX7 -DSIG_V -DNOGETUSERSHELL -DFNFLOAT \
+ -DNO_DNS_SRV $(KFLAGS) -Wc,-Nw260 $(OFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lm $(LIBS)"
+
+#Exactly as hpux0700sf but with compiler optimization:
+#OK: 2009/09/30
+hpux0700osf:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0700sf KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#HP-UX 7.0, short filenames, but with tcp/ip and curses.
+#To use this, you must have bought the ARPA Services Product from HP, and you
+#must have /usr/lib/libBSD.a.
+#
+#If you get compiler warnings like:
+#'Symbol table overflow. Try the -Wc,-Ns option.' (as for ckuus4.c or
+#other files) increase the '...' value in '-Wc,-Ns...'! The default maximum
+#symbol table size (-Ns) is 2000 table entries. ckuus4.c from Mar 12 2010
+#needs 2031 table entries (C-Kermit Version "9.0.299").
+#OK: 2010/03/24
+hpux0700sftcpc:
+ @$(MAKE) hpux-header
+ @echo 'supporting: NO long filenames, \c'
+ @echo 'but with networking, curses, HDB uucp...'
+ $(MAKE) hpux0700noopt KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V \
+ -DCK_REDIR -DCK_RTSCTS -DCK_CURSES -DNOGETUSERSHELL -DFNFLOAT \
+ -DNO_DNS_SRV -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \
+ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040"
+
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V \
+ -DCK_REDIR -DCK_RTSCTS -DCK_CURSES -DNOGETUSERSHELL -DFNFLOAT \
+ -DNO_DNS_SRV -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \
+ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040 $(OFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lm -lBSD -lcurses"
+
+#Exactly as above but with compiler optimization:
+#OK: 2009/09/30
+hpux0700osftcpc:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0700sftcpc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#HP 9000 series 300/800 HP-UX 7.0, long filenames, network support, HDB uucp,
+#but NO curses. See comments in hpux0700sftcpc about TCP/IP support.
+#
+#If you get compiler warnings like:
+#'Symbol table overflow. Try the -Wc,-Ns option.' (as for ckuus4.c or
+#other files) increase the '...' value in '-Wc,-Ns...'! The default maximum
+#symbol table size (-Ns) is 2000 table entries. ckuus4.c from Mar 12 2010
+#needs 2031 table entries (C-Kermit Version "9.0.299").
+#OK: 2010/03/24
+hpux0700lfn:
+ @$(MAKE) hpux-header
+ @echo 'supporting: long filenames, networking, HDB uucp$(MESSAGE2)...'
+ $(MAKE) hpux0700noopt KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V -DFNFLOAT \
+ -DNOGETUSERSHELL -DNOSETBUF -DCK_REDIR -DCK_RTSCTS -DLONGFN \
+ -DNO_DNS_SRV -DDIRENT -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \
+ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040"
+
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V -DFNFLOAT \
+ -DNOGETUSERSHELL -DNOSETBUF -DCK_REDIR -DCK_RTSCTS -DLONGFN \
+ -DNO_DNS_SRV -DDIRENT -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \
+ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040 $(OFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lm -lBSD $(LIBS)"
+
+#Exactly as above + curses.
+#OK: 2009/09/30
+hpux0700lfnc:
+ @MESSAGE2=', curses' \
+ $(MAKE) hpux0700lfn KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = -DCK_CURSES $(KFLAGS)" \
+ "LIBS = -lcurses"
+
+#Exactly as above hpux0700lfn but with compiler optimization:
+#OK: 2009/09/30
+hpux0700olfn:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0700lfn KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as above hpux0700lfnc but with compiler optimization:
+#OK: 2009/09/30
+hpux0700olfnc:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0700lfnc KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#HP 9000 Series 300 or 400, HP-UX 8.0, long filenames and TCP/IP support.
+#This one should also work on 700/800, but without PA-specific optimization.
+#In case -DCK_RTSCTS and -DCK_REDIR make trouble, remove them.
+#NOTE: ckcpro.c, ckuusr.c and ckuus3.c blow up the optimizer, so don't optimize
+#them.
+#For HP-UX 8.0 on Motorola CPUs, you might have to reinstall your kernel with
+#maxdsiz >= 0x03000000. But if physical memory is small, that still will not
+#help much.
+#OK: 2009/10/01
+hpux0800:
+ @$(MAKE) hpux-header
+ @MESSAGE3=$${MESSAGE3:='TCP/IP'}; \
+ echo "supporting: long filenames, $$MESSAGE3, HDB UUCP$(MESSAGE2)..."
+ $(MAKE) -B "CC=$(CC)" "CC2=$(CC2)" KTARGET=$${KTARGET:-$(@)} \
+ ckcpro.$(EXT) ckuusr.$(EXT) ckuus3.$(EXT) \
+ "CFLAGS = -DCK_REDIR -DHPUXDEBUG -DHPUX -DHPUX8 -DRENAME -DSIG_V \
+ -DNOSETBUF -DDIRENT -DCK_RTSCTS -DSTERMIOX -DLONGFN -DTCPSOCKET \
+ -DHDBUUCP -DNO_DNS_SRV -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT \
+ -DNOLONGLONG $(KFLAGS)"
+
+ $(MAKE) -B "CC=$(CC)" "CC2=$(CC2)" xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DCK_REDIR -DHPUXDEBUG -DHPUX -DHPUX8 -DRENAME -DSIG_V \
+ -DNOSETBUF -DDIRENT -DCK_RTSCTS -DSTERMIOX -DLONGFN -DTCPSOCKET \
+ -DHDBUUCP -DNO_DNS_SRV -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT \
+ -DNOLONGLONG -DNODCLENDUSERSHELL $(KFLAGS) $(OFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lm -lBSD $(LIBS)"
+
+#Exactly as above hpux0800 + curses.
+#OK: 2009/10/01
+hpux0800c:
+ @MESSAGE2=', curses' \
+ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) -DCK_CURSES" "LIBS = -lcurses"
+
+#HP 9000 HP-UX 8.0, no TCP/IP because /usr/lib/libBSD.a can't be found,
+#or TCP/IP header files missing.
+#OK: 2009/10/01
+hpux0800notcp:
+ @MESSAGE3='NO network, NO curses' \
+ $(MAKE) "MAKE=$(MAKE)" hpux0800 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) -UTCPSOCKET"
+
+#Now the same as above hpux0800 but with compiler optimization
+#OK: 2009/10/01
+hpux0800o:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as above hpux0800 + curses and with compiler optimization.
+#OK: 2009/10/01
+hpux0800oc:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) hpux0800c KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" "LIBS = -lcurses"
+
+#Exactly as above hpux0800notcp but with compiler optimization
+#OK: 2009/10/01
+hpux0800onotcp:
+ @MESSAGE1="with compiler optimization" \
+ $(MAKE) "MAKE=$(MAKE)" hpux0800notcp KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#HP 9000 Series 700 or 800, HP-UX 8.0, long filenames and TCP/IP support.
+# Like the previous entries, but with PA-RISC-specific optimization.
+#OK: 2009/10/01
+hpux0800pa:
+ @MESSAGE1="with PA-RISC-specific optimization" \
+ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) +Obb1100"
+
+#As above, but with curses.
+#OK: 2009/10/01
+hpux0800pac:
+ @MESSAGE1="with PA-RISC-specific optimization" \
+ $(MAKE) hpux0800c KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) +Obb1100"
+
+#As above, but compiled with GCC 2.3.3.
+#OK: 2009/10/01
+hpux0800pagcc:
+ @MESSAGE1='using the gcc compiler' \
+ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \
+ "CC=gcc" "CC2=gcc" "KFLAGS = -funsigned-char $(KFLAGS)"
+
+#HP-UX 9.0, 9.01, 9.03, 9.04, 9.05, 9.07, 9.10 ..., + TCP/IP + curses, fully
+#configured. Use this entry with the restricted compiler: no optimization, no
+#ANSI support. If you get unresolved sockets library references at link time,
+#then try adding -lBSD to LIBS, or else remove -DTCPSOCKET to build a version
+#without TCP/IP support.
+#
+#Please note that we have to add the compiler option +DA1.0/+DA1.1 to avoid
+#core-dumps for large arguments in IF MATCH. The man page says these options
+#are default but C-Kermit dumps core without them! Therefore keep them
+#untouched. If you want to overwrite or disable the +DA1.0/+DA1.1 option use
+#'make hpux0900 OFLAGS=...'. An other possibility would be to create a new
+#kernel with maxssiz >= 0x01185000 (default maxssiz=0x00800000).
+#OK: 2009/09/24
+hpux0900:
+ @MESSAGE1A='. Read hpux0900 entry comments if you have trouble.' \
+ $(MAKE) hpux-header
+ @case `uname -m` in \
+ */[34]*) KFLAGS='-DNOLONGLONG $(KFLAGS)' ;; \
+ */7*) AFLAGS='+DA1.1' ;; \
+ */8*) AFLAGS='+DA1.0' ;; \
+ esac ; \
+ OFLAGS=$${OFLAGS:-$$AFLAGS} ; \
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DHPUXDEBUG -DHPUX9 -DSTERMIOX -DDIRENT -DUTIMEH \
+ -DNOSETBUF -DCK_CURSES -DTCPSOCKET -DRENAME -DCK_REDIR -DLONGFN \
+ -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT \
+ -DNODCLENDUSERSHELL $$KFLAGS $$OFLAGS" \
+ "LNKFLAGS = -s" "LIBS = -lm -lcurses" "CC=$(CC)" "CC2=$(CC2)"
+
+#Like hpux0900, but for the "value-added" compiler on all HP 9000 models.
+#Adds optimization and ANSI compilation:
+# +O2 makes smaller executable (= -O = Level-1 and global optimization)
+# +O3 adds interprocedural global optimization, makes bigger executable.
+# Please note: To support long-long we would need compiler switch '-Ae' but
+# this one works only on Risc systems. But the equivalant compiler flags
+# '-Aa -D_HPUX_SOURCE +e' works for Motorola and Risc.
+# If optimization fails on some modules, you can add:
+# +Obb<n>, +Olimit <n>, or +Onolimit, depending on your cc version,
+# where <n> is a number, e.g. +Obb1200. In other words, if you get optimizer
+# warnings, add (for example) +Obb1200; if you still get optimizer warnings,
+# increase the number. Repeat until warnings go away. If your compiler
+# permits it, use +Onolimit. If optimizer blows up on ckcpro.c, see next entry.
+# Reportedly, on some configurations, such as HP9000/425e or /340, perhaps
+# depending on the amount of main memory, this entry might fail no matter what
+# you do ("Out of Memory", "cc: Fatal error in /lib/c.c1", etc). In that case
+# use "make hpux0900" (no "o").
+#OK: 2009/09/24
+hpux0900o:
+ @MESSAGE1=$${MESSAGE1:-"with compiler optimization"} \
+ $(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) -Aa -DCK_ANSIC -D_HPUX_SOURCE +O2 +e"
+
+# For HP-UX 9.0 on Motorola CPUs, optimization of ckcpro.c tends to blow up
+# the compiler. You might have to reinstall your kernel with maxdsiz >=
+# 0x03000000. But if physical memory is small, that still will not help much.
+# In that case, use this entry to skip optimization of ckcpro.c. But for
+# C-Kermit 8.0.208 you need a kernel with maxdsiz >= 0x02000000 to compile an
+# optimized ckcftp.c.
+# Please note: To support long-long we would need compiler switch '-Ae' but
+# this one works only on Risc systems. But the equivalant compiler flags
+# '-Aa -D_HPUX_SOURCE +e' works for Motorola and Risc.
+hpux0900m68ko:
+ @MESSAGE1='without compiler optimization for ckcpro.$(EXT) ...' \
+ $(MAKE) hpux-header
+ $(MAKE) ckuusr.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) \
+ ckcftp.$(EXT) ckcpro.$(EXT) \
+ "CFLAGS = -DHPUXDEBUG -DHPUX9 -DSTERMIOX -DDIRENT \
+ -DNOSETBUF -DCK_CURSES -DTCPSOCKET -DRENAME -DCK_REDIR -DLONGFN \
+ -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT $(KFLAGS)"
+ @echo
+ @MESSAGE1="with compiler optimization for the rest" \
+ $(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) -Aa -DCK_ANSIC -D_HPUX_SOURCE +O2 +e"
+
+# Old name for hpux0900m68ko.
+hpux0900mot:
+ $(MAKE) hpux0900m68ko KTARGET=$${KTARGET:-$(@)} "KFLAGS = $(KFLAGS)"
+
+#Like hpux0900o but with additional model-700/800-specific optimizations.
+# +ESlit = consolidate strings in read-only memory.
+# +ESfsc = inline millicode calls when comparing pointers.
+hpux0900o700:
+ @echo 'If you get optimizer warnings \c'
+ @echo 'try "make hpux0900o700 KFLAGS=+Obb1200"'
+ @MESSAGE1="with PA-RISC-specific optimizations" \
+ $(MAKE) hpux0900o KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) +ESlit +ESsfc"
+
+#HP-UX 9.0, 9.01, 9.03, 9.04, 9.05, 9.07, 9.10 ..., + TCP/IP + curses, fully
+#configured, built with gcc, all models except 800 series.
+#You might need to add the include path for gcc headers, for example:
+# 'KFLAGS=-I/usr/gnu/lib/gcc-lib/hppa1.1-hp-hpux/2.4.5/include/'
+hpux0900gcc:
+ @MESSAGE1='using the gcc compiler' \
+ $(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "KFLAGS = -DCK_ANSIC $(KFLAGS)" \
+ "OFLAGS = -funsigned-char -O2 $(OFLAGS)"
+
+#HP-9000 HP-UX 10.0 + TCP/IP + curses, fully configured.
+#Use with restricted (bundled) compiler: no optimization, no ANSI support.
+#libcurses needed for fullscreen file xfer display in HP-UX 10.00 and 10.01.
+#libHcurses (NOT libcurses!) for fullscreen display, to work around fatal bugs
+#in HP-UX 10.10 and 10.20 curses. Maybe we could use lcurses for 10.30, since
+#the 10.10 curses problem is supposedly fixed in 10.30.
+# +DA1.0 = Generate PA-RISC 1.0 code that runs on both 700 and 800 models.
+# +DA1.1 = Generate PA-RISC 1.1 code that runs on both 700 and 800 models.
+# Note that HP-UX 10.20 and upwards do not support PA-RISC 1.0 systems.
+# And that as of Dec 2001, 11.00 and 11.11 are PA-only and 11.20 is IA64-only.
+# Later 11.2x releases are expected to be for both. Architecture can be
+# determined with the model command, at least in 10.20 and later...
+#For future releases, we need to include +DA1.1 for PA builds, so that a
+#binary built on PA 2.0 will still work on PA 1.1 machines, whereas +DA1.1
+#must NOT be included for IA64 builds.
+#4 Jan 2006 - Added Large File Support (LFS). Large files (>2GB) are
+#possible in HP-UX 10.20 and later. The only change is to add:
+# -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+#to KFLAGS. These should be harmless in 10.00 and 10.10, if any of examples
+#of those still exist, but I have no way to test this hypothesis.
+#OK: 2009/11/16
+hpux1000:
+ @$(MAKE) hpux-header
+ @LIBS='-lHcurses' ; \
+ AFLAGS='+DA1.1' ; \
+ case `uname -r` in \
+ [AB].10.0*) KFLAGS='-DHPUX1000 $(KFLAGS)' ; \
+ AFLAGS='+DA1.0' ; LIBS='-lcurses' ;; \
+ [AB].10.1*) KFLAGS='-DHPUX1010 -D__HP_CURSES $(KFLAGS)' ; \
+ ;; \
+ [AB].10.2*) KFLAGS='-DHPUX1020 -D__HP_CURSES $(KFLAGS)' ; \
+ ;; \
+ [AB].10.3*) KFLAGS='-DHPUX1030 -D__HP_CURSES $(KFLAGS)' ; \
+ ;; \
+ [AB].10.?*) KFLAGS='-DHPUX10XX -D__HP_CURSES $(KFLAGS)' ; \
+ ;; \
+ [AB].11.0*) KFLAGS='-DHPUX1100 -D__HP_CURSES $(KFLAGS)' ; \
+ ;; \
+ [AB].11.1*) KFLAGS='-DHPUX1100 -D__HP_CURSES $(KFLAGS)' ; \
+ ;; \
+ [AB].11.?*) KFLAGS='-DHPUX1100 -D__HP_CURSES $(KFLAGS)' ; \
+ AFLAGS='' ; LIBS='-lcurses' ;; \
+ esac ; \
+ OFLAGS=$${OFLAGS:-$$AFLAGS} ; \
+ $(MAKE) "SHELL=/usr/bin/sh" xermit KTARGET=$${KTARGET:-$(@)} \
+ "CC=$(CC)" "CC2=$(CC2)" \
+ "CFLAGS = -DHPUX10 -DDIRENT -DSTERMIOX -DCK_DSYSINI -DHDBUUCP \
+ -DCK_CURSES -DCK_WREFRESH -DTCPSOCKET -DCK_REDIR -DRENAME -DFNFLOAT \
+ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \
+ $$KFLAGS $$OFLAGS" \
+ "LNKFLAGS=-s $(LNKFLAGS)" "LIBS = -lm $$LIBS $(KLIBS)"
+
+# This is a kludge, copying hpux0900gcc and adapting hpux1000
+# (add CC and CC2, drop the A1.[0||1])
+# Builds w/ no compiler warnings but minimally tested.
+#
+#OK: 2009/09/21
+hpux1000gcc:
+ @MESSAGE1="using the gcc compiler $(MESSAGE1)" \
+ $(MAKE) hpux1000 KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \
+ "KFLAGS = $(KFLAGS)" "OFLAGS = -DCK_ANSIC -funsigned-char -O2"
+
+# Trusted HP-UX 10
+# echo KFLAGS=$(KFLAGS) YTARGET YTARGET=$(YTARGET) $(XTARGET) ;
+hpux1000t:
+ @case "$(KTARGET)" in \
+ *+openssl | *+ssl) \
+ KENTRY=hpux1000o+openssl ;; \
+ *gcc) \
+ KENTRY=hpux1000gcc ;; \
+ *o+) KENTRY=hpux1000o+ ;; \
+ *o) KENTRY=hpux1000o ;; \
+ *) KENTRY=hpux1000 ;; \
+ esac ; \
+ MESSAGE1="and support for 'Trusted HP-UX'" \
+ $(MAKE) $$KENTRY KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS = $(KFLAGS) -DHPUX10_TRUSTED" "KLIBS=-lsec"
+
+hpux1000to:
+ $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+hpux1000to+:
+ $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+hpux1000tgcc:
+ $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+hpux1000to+ssl hpux1000to+openssl:
+ $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+hpux1000tgcc+ssl hpux1000tgcc+openssl:
+ $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+#HP-9000 HP-UX 10.00 and higher with ANSI prototyping and optimization.
+#PA-RISC only, no Motorola or other hardware is support in HP-UX 10.00++.
+#The unbundled optional compiler is required.
+#Your path should start with /opt/ansic/bin.
+# -Wl,-Fw = Remove stack unwind table (info used by debuggers).
+# +O2 makes a smaller executable (= -O = Level-1 and global optimization).
+# +O3 adds interprocedural global optimization, makes a bigger executable.
+# +Onolimit allows all modules to be optimized, no matter how complex. But:
+# (a) +Onolimit does not seem to always be there in HP-UX 10.00, and:
+# (b) some modules might take hours on low-memory and/or slow systems.
+# The following are PA-RISC-specific optimizations:
+# +ESlit = Consolidate strings in read-only memory.
+# +ESfsc = Inline millicode calls when comparing pointers.
+# You might need to configure your kernel for a maxdsiz of 0x0B000000 (176MB)
+# or greater to prevent the optimizer from running out of space.
+# December 2001: +ESlit +ESsfc removed because not supported on IA64.
+# Somebody who cares can use 'model' to see whether it's PA-RISC or IA64
+# and include the architecture-specific optimization flags. Also note:
+# +DA1.1 is PA-only. If this is included in in HP-UX 11.00 or later,
+# then +DS2.0 should be included too (but don't use +DS2.0 without +DA1.1,
+# or else the binary won't run on older PA hardware).
+#OK: 2009/09/21
+hpux1000o:
+ @case `uname -m` in \
+ ia64) ;; \
+ *) MFLAGS='+ESlit +ESsfc' ;; \
+ esac ; \
+ MESSAGE1="with PA-RISC-specific optimizations $(MESSAGE1)" \
+ $(MAKE) "SHELL=/usr/bin/sh" "PATH=/opt/ansic/bin:$$PATH" hpux1000 \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = $(KFLAGS) \
+ -Ae -D_HPUX_SOURCE -DCK_ANSIC -DUTIMEH \
+ +O2 -Wl,-Fw $$MFLAGS"
+
+#Like hpux1000o but with "+Onolimit".
+#On 700 series set kernel parameter maxdsiz >= 0x0D000000 (=208MB).
+#Takes a long time.
+hpux1000o+:
+ @MESSAGE1="and +Onolimit $(MESSAGE1)" KTARGET=$${KTARGET:-$(@)} \
+ $(MAKE) hpux1000o \
+ "KFLAGS = $(KFLAGS) +Onolimit"
+
+#HP-UX 10.xx + 11.xx with optimizing ANSI compiler and OpenSSL.
+#Define SSLLIB and SSLINC appropriately for your OpenSSL installation.
+#To overwrite the default SSLLIB and SSLINC settings you can also use the
+#command-line variable KSSLLIB and KSSLINC like:
+#make hpux1000o+openssl KSSLLIB=-L/opt/openssl/lib KSSLINC=-I/...
+#Ditto for the Zlib location.
+#This entry works for C-Kermit 8.0.206 on HP-UX 10.20 + 11.11
+#with OpenSSL 0.9.6 + 0.9.7
+#NOTE: an ANSI C compiler is required for the SSL interface. If you don't
+#have the HP Optimizing ANSI compiler, see the hpux1000gcc+openssl target
+#below.
+hpux1000o+ssl hpux1000o+openssl:
+ @case "$(KTARGET)" in \
+ *gcc+*) \
+ KENTRY=hpux1000gcc ;; \
+ *) KENTRY=hpux1000o ;; \
+ esac ; \
+ case "$(KTARGET)" in \
+ *-zlib*) \
+ DZLIB= LZLIB= ;; \
+ *) DZLIB=-DZLIB LZLIB='-L/opt/zlib/lib -lz' ;; \
+ esac ; \
+ SSLINC=$${KSSLINC:-$(SSLINC)}; \
+ SSLLIB=$${KSSLLIB:-$(SSLLIB)}; \
+ MESSAGE1="and with OpenSSL $(MESSAGE1)" \
+ $(MAKE) $$KENTRY KTARGET=$${KTARGET:-$(@)} \
+ KFLAGS="-DCK_AUTHENTICATION -DCK_SSL -DOPENSSL_097 $$DZLIB \
+ $$SSLINC $(KFLAGS)" \
+ KLIBS="$(KLIBS) \
+ $$SSLLIB -lssl -lcrypto \
+ $$LZLIB \
+ "
+
+# Ditto but without Zlib:
+hpux1000o+ssl-zlib hpux1000o+openssl-zlib:
+ @MESSAGE1="but without Zlib $(MESSAGE1)" \
+ $(MAKE) hpux1000o+ssl KTARGET=$${KTARGET:-$(@)}
+
+#HP-UX 10.00 or higher with OpenSSL 0.9.7. Compiled with gcc.
+#From Chris Chaney, NEC America Inc. His instructions:
+# (1) Install gcc version 3.2.3 & binutils version 2.13.2
+# (used binary depot from http://hpux.cs.utah.edu/)
+# (2) Install gcc make version 3.80 from http://hpux.cs.utah.edu/
+#
+# or: gcc 2.9.2000-12-1 from "Linux to hp-ux 11.0/11i porting kit version 1.0
+# (2CD)" free from: http://www.software.hp.com
+#
+# (3) Install openSSL version 0.9.7b from http://www.software.hp.com
+# (4) Install flex version 2.5.4 from http://hpux.cs.utah.edu/
+# (5) Install gmp version 3.1.1 from http://hpux.cs.utah.edu/
+#
+#Note from Peter Eichhorn, assyst Munich. It works also without gcc make!
+hpux1000gcc+ssl hpux1000gcc+openssl:
+ $(MAKE) hpux1000o+openssl KTARGET=$${KTARGET:-$(@)}
+
+# Ditto but without Zlib:
+hpux1000gcc+ssl-zlib hpux1000gcc+openssl-zlib:
+ $(MAKE) hpux1000o+openssl-zlib KTARGET=$${KTARGET:-$(@)}
+
+# Same for HP-UX 11
+hpux1100o+ssl hpux1100o+openssl:
+ $(MAKE) hpux1000o+openssl KTARGET=$${KTARGET:-$(@)}
+
+#OK: 2009/09/26
+hpux1100gcc+ssl hpux1100gcc+openssl:
+ $(MAKE) hpux1000gcc+openssl KTARGET=$${KTARGET:-$(@)}
+
+hpux1100o+ssl-zlib hpux1100o+openssl-zlib:
+ $(MAKE) hpux1000o+openssl-zlib KTARGET=$${KTARGET:-$(@)}
+
+hpux1100gcc+ssl-zlib hpux1100gcc+openssl-zlib:
+ $(MAKE) hpux1000gcc+openssl-zlib KTARGET=$${KTARGET:-$(@)}
+
+# HP-UX 11
+# Note: these are 32-bit builds even on IA64.
+# Adding +DD64 to CFLAGS produces 64-bit object files,
+# but the linker fails to find the needed 64-bit libs.
+#OK: 2009/09/26
+hpux1100:
+ $(MAKE) hpux1000 KTARGET=$${KTARGET:-$(@)}
+
+#OK: 2009/09/26
+hpux1100o:
+ $(MAKE) hpux1000o KTARGET=$${KTARGET:-$(@)}
+
+hpux1100o+:
+ $(MAKE) hpux1000o+ KTARGET=$${KTARGET:-$(@)}
+
+#OK: 2009/09/26
+hpux1100gcc:
+ $(MAKE) hpux1000gcc KTARGET=$${KTARGET:-$(@)}
+
+# Trusted HP-UX 11
+hpux1100t:
+ $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+hpux1100to:
+ $(MAKE) hpux1000to KTARGET=$${KTARGET:-$(@)}
+
+hpux1100to+:
+ $(MAKE) hpux1000to+ KTARGET=$${KTARGET:-$(@)}
+
+hpux1100tgcc:
+ $(MAKE) hpux1000tgcc KTARGET=$${KTARGET:-$(@)}
+
+hpux1100to+ssl hpux1100to+openssl:
+ $(MAKE) hpux1000to+openssl KTARGET=$${KTARGET:-$(@)}
+
+hpux1100tgcc+ssl hpux1100tgcc+openssl:
+ $(MAKE) hpux1000tgcc+openssl KTARGET=$${KTARGET:-$(@)}
+
+#Regulus on CIE Systems 680/20
+cie:
+ @echo 'Making C-Kermit $(CKVER) for CIE Systems 680/20 Regulus...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DATTSV -DNOFILEH -DCIE -DNOLEARN $(KFLAGS) -O" "LNKFLAGS ="
+
+# Linux 1.2 or later with gcc, dynamic libraries, ncurses, TCP/IP.
+#
+# If your Linux system has curses rather than ncurses, use the linuxc
+# entry, or if that doesn't work, linuxnc.
+#
+# The Kermit "large memory model" is used by default to configure big packet
+# and script buffers, etc. For small-memory or limited-resource systems,
+# "make linux KFLAGS=-DNOBIGBUF".
+#
+# -DLINUXFSSTND (Linux File System Standard 1.2) gives UUCP lockfile /var/lock
+# with string pid. Remove this to get /usr/spool/uucp with int pid, used in
+# very early Linux versions. FSSTND 1.2 also says that the PID string in the
+# UUCP lock file has leading spaces. This is a change from FSSTND 1.0, which
+# used leading zeros. Add -DFSSTND10 to support FSSTND 1.0 instead of 1.2.
+# I hope subsequent editions of the file-system standard did not change these
+# again.
+#
+# Add -DOLINUXHISPEED (Old Linux High Speed support) to turn on an ugly kludge
+# in Linux 1.0 and earlier to support speeds of 57600 and 115200. Extremely
+# old Linux systems (pre-0.99pl15) will not support this. If OLINUXHISPEED is
+# not defined, then only the standard POSIX termios methods of setting the port
+# speed will be used, and in this case speeds can be as high as 460800 in most
+# modern Linux versions.
+#
+# -DCK_POSIX_SIG (POSIX signal handling) is good for Linux releases back to at
+# least 0.99.14; if it causes trouble for you, remove it from the CFLAGS.
+#
+# -pipe removes the need for temp files - remove it if it causes trouble.
+#
+# -funsigned-char makes all characters unsigned, as they should have been
+# in the first place.
+#
+# Add -DCK_DSYSINI if you want a shared system-wide init file.
+#
+# See http://www.columbia.edu/kermit/ckubwr.html about -DNOCOTFMC.
+# Better still, should read the entire Linux section of that document.
+#
+# The "linuxa" entry can be referenced directly on LIBC systems, but not
+# GLIBC, where -lcrypt is required. The "make linux" entry should normally
+# be used for all builds on all Linux distributions unless you have special
+# requirements, in which case keep reading. CK_NEWTERM added after 7.0b04
+# due to new complaints about ncurses changing buffering of tty.
+
+linuxa:
+ @echo 'Making C-Kermit $(CKVER) for Linux 1.2 or later...'
+ @echo 'IMPORTANT: Read the comments in the linux section of the'
+ @echo 'makefile if you have trouble.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -DLINUX -pipe -funsigned-char -DFNFLOAT -DCK_POSIX_SIG \
+ -DCK_NEWTERM -DTCPSOCKET -DLINUXFSSTND -DNOCOTFMC -DPOSIX \
+ -DUSE_STRERROR $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(LIBS) -lm"
+
+# As above but with profiling
+linuxp:
+ $(MAKE) linuxa KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS) -pg" \
+ "LIBS=-pg -lcrypt -lresolv"
+
+#Linux. This entry should work for any Linux distribution on any platform,
+#32-bit or 64-bit, except for extremely ancient ones. Automatically detects:
+# . curses, ncurses, or no curses
+# . Old versus new pty handling (new == glibc 2.1++)
+# . Presence or absence of libcrypt.a and <crypt.h>
+# . Presence or absence of libresolv.a
+# . Transitional Long File API for 32-bit platforms (SUS V2 UNIX 98 LFS).
+#Note: The HAVE_PTMX test was previously "if test -c /dev/ptmx" but this was
+#not sufficient for Debian 2.1, because although it had /dev/ptmx, it did not
+#have grantpt(), unlockpt(), or ptsname(), so has been changed to look for a
+#grantpt() prototype in the header files. Modified in 8.0.206 to allow for
+#libraries that contain .so's but no .a's, e.g. Mandrake 9.0.
+#HAVE_BAUDBOY added in 8.0.210 for Red Hat -- it's like AIX ttylock().
+#Modified 17 Aug 2005 to use openpty() if available because the other stuff
+#dumps core in 64-bit ia64 and x86_64 builds.
+#Long file support for 32-bit builds added in 8.0.212 - if features.h contains
+#__USE_LARGEFILE64 then we set the flags that must be set before reading any
+#header files; on 32-bit platforms such as i386, this produces a 32-bit build
+#capable of accessing, sending, receiving, and managing long (> 2GB) files.
+#On 64-bit platforms, it does no harm.
+#As of 3 March 2009 we detect automatically if we have curses, ncurses,
+#or no curses at all.
+#Added HAVE_LOCKDEV as openSuSE >= 11.3 uses ttylock directly instead of
+#baudboy 2010/08/23
+#OK: 2011/06/18
+linux:
+ @if test \
+ `grep grantpt /usr/include/*.h /usr/include/sys/*.h | wc -l` -gt 0; \
+ then if test -c /dev/ptmx; then HAVE_PTMX='-DHAVE_PTMX'; \
+ else HAVE_PTMX=''; fi; fi ; \
+ if test `grep openpty /usr/include/pty.h | wc -l` -gt 0; \
+ then HAVE_OPENPTY='-DHAVE_OPENPTY'; \
+ else HAVE_OPENPTY=''; fi ; \
+ HAVE_LIBCURSES=''; \
+ if test -f /usr/lib64/libncurses.so || \
+ test -f /usr/lib/libncurses.a || \
+ test -f /usr/lib/libncurses.so; then \
+ HAVE_LIBCURSES='-lncurses'; \
+ else if test -f /usr/lib64/libcurses.so || \
+ test -f /usr/lib/libcurses.a || \
+ test -f /usr/lib/libcurses.so; then \
+ HAVE_LIBCURSES='-lcurses'; fi; fi; \
+ HAVE_CURSES=''; \
+ if test -n '$$HAVE_LIBCURSES'; then \
+ if test -f /usr/include/ncurses.h; then \
+ HAVE_CURSES='-DCK_NCURSES -I/usr/include/ncurses'; \
+ else if test -f /usr/include/curses.h; then \
+ HAVE_CURSES='-DCK_CURSES'; \
+ fi; fi; fi; \
+ if test -f /usr/include/baudboy.h || test -f /usr/include/ttylock.h; \
+ then HAVE_LOCKDEV='-DHAVE_LOCKDEV' ; \
+ else HAVE_LOCKDEV='' ; fi ; \
+ if test -f /usr/include/baudboy.h ; \
+ then HAVE_BAUDBOY='-DHAVE_BAUDBOY' ; \
+ else HAVE_BAUDBOY='' ; fi ; \
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$$HAVE_CURSES $$HAVE_PTMX $$HAVE_LOCKDEV \
+ $$HAVE_BAUDBOY $$HAVE_OPENPTY \
+ `grep __USE_LARGEFILE64 /usr/include/features.h > /dev/null && \
+ echo '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'` \
+ `if test -f /usr/include/crypt.h; then echo -DHAVE_CRYPT_H; fi` \
+ $(KFLAGS)" \
+ "LIBS=$(LIBS) $$HAVE_LIBCURSES \
+ `if test -n '$$HAVE_OPENPTY'; then echo -lutil; fi` \
+ `if test -f /usr/lib64/libresolv.a || test -f /usr/lib64/libresolv.so \
+ || test -f /usr/lib/libresolv.a || test -f /usr/lib/libresolv.so \
+ || test -f /usr/lib/i386-linux-gnu/libresolv.a \
+ || test -f /usr/lib/i386-linux-gnu/libresolv.so \
+ || ls /lib/x86_64-linux-gnu/libresolv.* > /dev/null 2> /dev/null; \
+ then echo -lresolv; fi` \
+ `if test -f /usr/lib64/libcrypt.a || test -f /usr/lib64/libcrypt.so \
+ || test -f /usr/lib/libcrypt.a || test -f /usr/lib/libcrypt.so \
+ || ls /lib/x86_64-linux-gnu/libcrypt.* > /dev/null 2> /dev/null; \
+ then echo -lcrypt; fi` \
+ `if test -f /usr/lib64/liblockdev.a || \
+ test -f /usr/lib64/liblockdev.so || \
+ test -f /usr/lib/liblockdev.a || \
+ test -f /usr/lib/liblockdev.so; \
+ then echo -llockdev; fi`" \
+ linuxa
+
+# Linux + Shadow passwords + PAM
+# OK 2011/06/18
+linux+shadow+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux+Shadow+PAM...'
+ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \
+ KFLAGS="-DCK_SHADOW -DCK_PAM $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = -lpam"
+
+# Linux systems that have no <sys/select.h>.
+# (not tested in recent years, perhaps no longer needed)
+linuxns:
+ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} KFLAGS=-DNO_SYS_SELECT_H
+
+# Linux-script-only:
+# A minimum-size version for Linux that does only scripting and
+# serial communication -- no networks, no file transfer, no security.
+# OK 2011/06/18
+linuxso:
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -DLINUX -pipe -funsigned-char -DPOSIX -DCK_POSIX_SIG \
+ -DLINUXFSSTND -DNOCOTFMC -DNOXFER -DNODEBUG -DNOCSETS -DNOHELP \
+ -DNONET -DMINIDIAL -DNOSCRIPT -DNOIKSD -DNOPUSH $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS)" "LIBS = "
+
+# Secure targets for Linux. These work on RHAS4, RHEL4, and RHEL5,
+# unlike some of the older targets that follow. They hook into the main Linux
+# target so we pick up all the other new stuff - large files, baudboy.h, the
+# appropriate pty interface, etc.
+
+# Linux with Kerberos 5.
+# Use "make linux+krb5 KFLAGS=-DNO_KRB5_INIT_ETS" if necessary.
+#OK 2011/06/16 on Fedora 14 with:
+# make linux+krb5 "LIBS=$LIBS /lib/libk5crypto.so.3 /lib/libcom_err.so.2"
+# On RHEL5: make linux+krb5 -UCK_DES
+linux+krb5:
+ @echo 'Making C-Kermit $(CKVER) for Linux with Kerberos 5...'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes425'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ K5CRYPTO=''; \
+ if ls /lib/libk5crypto* > /dev/null 2> /dev/null; then \
+ K5CRYPTO='-lk5crypto'; \
+ else if ls /usr/lib/libk5crypto* > /dev/null 2> /dev/null; then \
+ K5CRYPTO='-lk5crypto'; \
+ else if ls /usr/lib64/libk5crypto* > /dev/null 2> /dev/null; then \
+ K5CRYPTO='-lk5crypto'; \
+ fi; fi; fi; \
+ COM_ERR=''; \
+ if ls /lib/libcom_err* > /dev/null 2> /dev/null; then \
+ COM_ERR='-lcom_err'; \
+ fi; \
+ GSSAPILIB='-lgssapi'; \
+ if ls /lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ else if ls /usr/lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ else K5DIR=`echo $(K5LIB) | sed 's|-L||'`; \
+ if ls $$K5DIR/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ fi; fi; fi; \
+ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "KFLAGS= -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 $$OPENSSLOPTION \
+ -DCK_ENCRYPTION $$HAVE_DES $(K5INC) $(K5INC)/krb5 \
+ -I/usr/include/et $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $$DES_LIB -lcrypto $$GSSAPILIB -lkrb5 \
+ $$K5CRYPTO $$COM_ERR $(LIBS)" ; \
+ if [ ! -f ./wermit ] || [ ./ckcmai.o -nt ./wermit ] ; then \
+ echo ""; \
+ echo "If build failed try:"; \
+ echo ""; \
+ echo " make clean ; make $${KTARGET:-$(@)} KFLAGS=-UCK_DES"; \
+ echo ""; \
+ fi
+
+# Linux with Kerberos 5 and Kerberos 4.
+# Use "make linux+krb5 KFLAGS=-DNO_KRB5_INIT_ETS" if necessary.
+# Add "KFLAGS=-UCK_DES" if failure messages look DES-related.
+# UNTESTED (because I can't find a box with Krb4 and Krb5 installed)
+linux+krb5+krb4:
+ @echo 'Making C-Kermit for Linux with Kerberos 4 and Kerberos 5'
+ $(MAKE) linux+krb5 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DKRB4 -DKRB524 $(KFLAGS)" "LIBS=$(LIBS) -lkrb4"
+
+# Linux with OpenSSL
+# In Linux, SSL libs are often in /lib or /usr/lib and so found by default.
+# This targets takes into account the DES library might or might not
+# exist. If it does exist, however, the target will require some editing
+# if its basename is not libdes425. - fdc Tue Sep 21 14:28:00 2010
+# IMPORTANT: Some Linux platforms have DES libraries but they are missing
+# functions used by Kermit. In that case you will get fatal errors at
+# link time involving routines such as des_ecb3_encrypt, des_random_seed,
+# and des_set_odd_parity. In that case, "make linux KFLAGS=-UCK_DES"
+# There's a new warning at the end that should come out if this happens,
+# and that should not come out if it didn't.
+#
+linux+ssl linux+openssl linux+openssl+zlib+shadow+pam linux+openssl+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Linux+OpenSSL SSLLIB=$(SSLLIB)'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes425'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \
+ -DCK_SSL -DCK_PAM -DZLIB -DCK_SHADOW $$OPENSSLOPTION $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SSLLIB) -lssl $$DES_LIB -lcrypto -lpam -ldl -lz $(LIBS)" ; \
+ if [ ! -f ./wermit ] || [ ./ckcmai.o -nt ./wermit ] ; then \
+ echo ""; \
+ echo "If build failed try:"; \
+ echo ""; \
+ echo " make clean ; make $${KTARGET:-$(@)} KFLAGS=-UCK_DES"; \
+ echo ""; \
+ fi
+
+# Linux with Kerberos 5 and OpenSSL
+# OK 2011/05/16
+# Add -UCK_DES if functions like des_ecb3_encrypt, es_random_seed,
+# come up missing at link time.
+linux+krb5+ssl linux+krb5+openssl:
+ @echo 'Making C-Kermit $(CKVER) for Linux with Krb5 and OpenSSL...'
+ @case `openssl version` in \
+ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \
+ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \
+ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \
+ *) OPENSSLOPTION="" ;; \
+ esac; \
+ HAVE_DES=''; \
+ DES_LIB=''; \
+ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \
+ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \
+ DES_LIB='-ldes425'; \
+ HAVE_DES='-DCK_DES -DLIBDES'; \
+ echo "HAVE DES"; \
+ else echo "NO DES"; \
+ fi; \
+ K5CRYPTO=''; \
+ if ls /lib/libk5crypto* > /dev/null 2> /dev/null; then \
+ K5CRYPTO='-lk5crypto'; \
+ else if ls /usr/lib/libk5crypto* > /dev/null 2> /dev/null; then \
+ K5CRYPTO='-lk5crypto'; \
+ else if ls /usr/lib64/libk5crypto* > /dev/null 2> /dev/null; then \
+ K5CRYPTO='-lk5crypto'; \
+ fi; fi; fi; \
+ COM_ERR=''; \
+ if ls /lib/libcom_err* > /dev/null 2> /dev/null; then \
+ COM_ERR='-lcom_err'; \
+ fi; \
+ GSSAPILIB='-lgssapi'; \
+ if ls /lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ else if ls /usr/lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ else K5DIR=`echo $(K5LIB) | sed 's|-L||'`; \
+ if ls $$K5DIR/libgssapi_krb5* > /dev/null 2> /dev/null; then \
+ GSSAPILIB='-lgssapi_krb5'; \
+ fi; fi; fi; \
+ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "KFLAGS= -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 \
+ -DCK_SSL -DCK_PAM -DZLIB -DCK_SHADOW $$OPENSSLOPTION $(SSLINC) \
+ -DCK_ENCRYPTION $$HAVE_DES $(K5INC) $(K5INC)/krb5 \
+ -I/usr/include/et $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) -lssl $$DES_LIB -lpam -lz \
+ -lcrypto $$GSSAPILIB -lkrb5 $$K5CRYPTO $$COM_ERR $(LIBS)" ; \
+ if [ ! -f ./wermit ] || [ ./ckcmai.o -nt ./wermit ] ; then \
+ echo ""; \
+ echo "If build failed try:"; \
+ echo ""; \
+ echo " make clean ; make $${KTARGET:-$(@)} KFLAGS=-UCK_DES"; \
+ echo ""; \
+ fi
+
+# ::BEGIN_OLD_LINUX_TARGETS::
+
+# The remaining Linux entries are for special or customized builds. They have
+# not been generalized ("subroutinized") like the ones above. Ideally, we
+# should allow for every combination of libc vs glibc, gcc vs egcs, curses vs
+# ncurses, Kerberos IV vs Kerberos V vs SRP (in any combination), and so on.
+# The best way to do this is to set KFLAGS and LIBS values and then chain to
+# the main "linux" target, as in the examples just above. To skip past all of
+# these old targets (and there are many) search for ::END_OLD_LINUX_TARGETS::
+# (after this line).
+
+#Sharp Zaurus SL-5500 - Linux based
+zsl5500:
+ @echo 'Making C-Kermit $(CKVER) for Sharp Zaurus SL-5500...'
+ @touch ckcpro.c
+ @touch wart
+ $(MAKE) linuxnc KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DZSL5500" \
+ "CC = gcc" "CC2 = gcc"
+
+#Mklinux DR3 has horrible bug in <utmpbits.h> - see ckufio.c.
+mklinux:
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DUTMPBUG" \
+ "LIBS=-lcrypt -lresolv" linuxa
+
+#LinuxPPC 1999
+linuxppc:
+ @echo 'Making C-Kermit $(CKVER) for LinuxPPC 1999...'
+ @if test -f /usr/lib/libcrypt.a; then \
+ if test -f /usr/lib/libresolv.a; then \
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(NCURSES_CPP) -DHAVE_CRYPT_H \
+ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \
+ "LIBS=-lncurses -lresolv -lcrypt" linuxa ; \
+ else \
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(NCURSES_CPP) -DHAVE_CRYPT_H \
+ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \
+ "LIBS=-lncurses -lcrypt" linuxa ; \
+ fi \
+ else \
+ if test -f /usr/lib/libresolv.a; then \
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(NCURSES_CPP) \
+ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \
+ "LIBS=-lncurses -lresolv" linuxa ; \
+ else \
+ $(MAKE) KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(NCURSES_CPP) \
+ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \
+ "LIBS=-lncurses" linuxa ; \
+ fi \
+ fi
+
+
+# Like "make linux" but built with egcs rather than gcc.
+# If you get "Internal compiler error xxx, output pipe has been closed",
+# try removing -pipe.
+linuxegcs:
+ @echo 'Making C-Kermit $(CKVER) for Linux 1.2 or later with egcs...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = egcs" "CC2 = egcs" \
+ "CFLAGS = -O -DLINUX -pipe -funsigned-char \
+ -DPOSIX -DCK_POSIX_SIG -DCK_NCURSES -DNOCOTFMC \
+ -DTCPSOCKET -DLINUXFSSTND $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lncurses -lcrypt -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.1 (no K4 compatibility).
+linux+krb5-old:
+ @echo 'Making C-Kermit $(CKVER) for Linux on Intel with Kerberos...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 \
+ -DCK_ENCRYPTION -DCK_DES -DCK_CURSES -DCK_POSIX_SIG \
+ -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H $(K5INC) $(K5INC)/krb5 \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) -lncurses -ltermcap -ldes425 -lkrb5 \
+ -lcom_err -lk5crypto -lgssapi_krb5 -lcrypt -lresolv"
+
+# Linux on Intel PC with SRP 1.7.4 using GNU MP, Krypto, and Eric Young's
+# DES library. Remove the -DCK_DES, -DLIBDES and -ldes if you do not have
+# Eric Young's# libdes.a installed.
+#
+linux+srp+gmp:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) \
+ -lncurses -ltermcap -lsrp -lgmp -ldes -lkrypto -lcrypt -lresolv"
+
+linux+srp+gmp+no-des:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP ...'
+ $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP \
+ -DCK_ENCRYPTION -DCK_CAST \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) \
+ -lncurses -ltermcap -lsrp -lgmp -lkrypto -lcrypt -lresolv"
+
+linux+srp+gmp-export:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) srpmit-export KTARGET=$${KTARGET:-$(@)} \
+ "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DFNFLOAT \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) \
+ -lncurses -ltermcap -lsrp -lgmp -lkrypto -lcrypt -lm -lresolv"
+
+linux+srp+gmp+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -DCK_PAM -DFNFLOAT $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) -lncurses -ltermcap -lsrp -lgmp -ldes -lkrypto \
+ -lcrypt -lpam -ldl -lm -lresolv"
+
+#Linux on Intel PC with SRP 1.7.4 built with OpenSSL for Big Number Math
+#and Cryptographic functionality.
+#
+linux+srp:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(SSLLIB) \
+ -lncurses -ltermcap -lsrp -lkrypto -lcrypto -lcrypt -lresolv"
+
+linux+srp+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -DCK_PAM -DFNFLOAT $(SRPINC) $(SSLINC) $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(SSLLIB) -lncurses -ltermcap -lsrp -lkrypto \
+ -lcrypto -lcrypt -lpam -ldl -lm -lresolv"
+
+#Linux on Intel PC with SRP and SSL/TLS.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 or higher to be compiled with KRB4 compatibility.
+#Remove -ltermcap if it causes trouble e.g. in Debian 2.2.
+#If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+srp+openssl:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(SSLLIB) \
+ -lncurses -ltermcap -lsrp -lssl -lkrypto -lcrypto \
+ -lcrypt -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2 and SRP.
+#
+# libsrp.a should be build with GNU MP (libgmp.a)
+# instead of AT&T CryptoLib (libcrypt.a) due to naming conflicts with
+# standard distribution Linux libraries.
+# Requires the Kerberos 1.2.2 or higher to be compiled with KRB4 compatibility.
+linux+krb5+krb4+srp:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB54+SRP...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SRPINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SRPLIB) \
+ -lncurses -ltermcap -lsrp -lgmp -lgssapi_krb5 -lkrypto \
+ -ldes -lkrb4 -ldes425 -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP and SSL/TLS.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 or higher to be compiled with KRB4 compatibility.
+# Requires OpenSSL 0.9.6a or higher
+#If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+srp+openssl:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SRPLIB) $(SSLLIB) \
+ -lncurses -ltermcap -lsrp \
+ -lkrb4 -lssl -lkrypto -lcrypto \
+ -lkrb5 -lcom_err -lk5crypto -lgssapi_krb5 -lcrypt -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SSL/TLS.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+#If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+openssl:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) \
+ -lncurses -ltermcap \
+ -lkrb4 -lssl -lcrypto -lkrb5 -lcom_err \
+ -lk5crypto -lgssapi_krb5 -lcrypt -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.1, SSL/TLS.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+openssl+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_SHADOW \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) \
+ -lncurses -ltermcap \
+ -lkrb4 -lssl -lcrypto -lkrb5 -lcom_err \
+ -lk5crypto -lgssapi_krb5 -lcrypt -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2, SSL/TLS.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+openssl+zlib+shadow:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 -DZLIB \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_SHADOW \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) \
+ -lncurses -ltermcap \
+ -lkrb4 -lssl -lcrypto -lkrb5 -lcom_err \
+ -lk5crypto -lgssapi_krb5 -lcrypt -lresolv -lz"
+
+linux+krb5+krb4+srp-export:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) xermit-export KTARGET=$${KTARGET:-$(@)} \
+ "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SRPINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(K5LIB) \
+ -lncurses -ltermcap -lsrp -lgmp -lkrb4 -ldes425 -lkrb5 -lgssapi_krb5 \
+ -lcom_err -lk5crypto -lkrypto -lcrypt -lresolv"
+
+linux+krb5+krb4+srp+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -DCK_PAM $(K5INC) $(K5INC)/krb5 $(SRPINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(K5LIB) \
+ -lncurses -ltermcap -lsrp -lgmp -ldes -lkrb4 -ldes425 -lkrb5 \
+ -lcom_err -lk5crypto -lgssapi_krb5 -lkrypto -lcrypt -lpam -ldl \
+ -lresolv"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP and SSL/TLS.
+# and PAM.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+srp+openssl+pam-debug:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit-debug KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -w -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG $(K5INC) $(K5INC)/krb5 \
+ $(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \
+ -lncurses -ltermcap -lsrp -lkrb4 -lssl -lkrypto -lcrypto \
+ -lkrb5 -lcom_err -lk5crypto -lgssapi_krb5 -lcrypt -lresolv -lpam -ldl"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.1, SRP and SSL/TLS.
+# and PAM.
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+srp+openssl+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \
+ -lm -lncurses -ltermcap -lsrp \
+ -lkrb4 -lssl -lkrypto -lcrypto -lgssapi_krb5 \
+ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP, OpenSSL
+# with ZLIB and PAM
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+srp+openssl+zlib+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \
+ -lm -lncurses -ltermcap -lsrp \
+ -lkrb4 -lssl -lkrypto -lcrypto -lgssapi_krb5 \
+ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP, OpenSSL
+# with ZLIB, Shadow Passwords, and PAM
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+srp+openssl+zlib+shadow+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -DCK_SHADOW $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \
+ -lm -lncurses -ltermcap -lsrp -lkrypto \
+ -lkrb4 -lssl -lcrypto -lgssapi_krb5 \
+ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, OpenSSL
+# with Shadow Passwords, PAM
+#
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+linux+krb5+krb4+openssl+shadow+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL,...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -DCK_SHADOW $(K5INC) $(K5INC)/krb5 $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) \
+ -lm -lncurses -ltermcap \
+ -lkrb4 -lssl -lcrypto -lgssapi_krb5 \
+ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, OpenSSL
+# with ZLIB, Shadow Passwords, PAM
+#
+# libsrp.a should be build with OpenSSL
+# Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility.
+# If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS.
+linux+krb5+krb4+openssl+zlib+shadow+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ -DCK_SHADOW $(K5INC) $(K5INC)/krb5 $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) \
+ -lm -lncurses -ltermcap \
+ -lkrb4 -lssl -lcrypto -lgssapi_krb5 \
+ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz"
+
+#Red Hat 9 - full install includes Kerberos 5 (4 compat), PAM, SSL.
+#Also works around bug in curses in which terminal goes dead after
+#returning from file-transfer display. Assumes OpenSSL 0.9.7 or later.
+redhat9:
+ @echo "Building SECURE Kermit for Red Hat 9.0..."
+ $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH90 -DOPENSSL_097 $(KFLAGS)"
+
+#Ditto plus SRP (which is not normally included with RH Linux).
+redhat9+srp:
+ @echo "Building SECURE Kermit for Red Hat 9.0..."
+ $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH90 -DOPENSSL_097 $(KFLAGS)"
+
+#For Red Hat AS 2.1 with OpenSSL
+redhat21+ssl:
+ @echo "Building SECURE Kermit for Red Hat 2.1..."
+ $(MAKE) linux+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = $(KFLAGS)"
+
+#Red Hat Linux 8.0 - full install includes Kerberos 5 (4 compat), PAM, SSL.
+#Also works around bug in curses in which terminal goes dead after
+#returning from file-transfer display.
+redhat80:
+ @echo "Building SECURE Kermit for Red Hat 8.0..."
+ $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH80 $(KFLAGS)"
+
+redhat80+srp:
+ @echo "Building SECURE Kermit for Red Hat 8.0..."
+ $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH80 $(KFLAGS)"
+
+#Red Hat Linux 7.3 - full install includes Kerberos 5 (4 compat), PAM, SSL.
+#Also works around bug in curses in which terminal goes dead after
+#returning from file-transfer display.
+redhat73:
+ @echo "Building SECURE Kermit for Red Hat 7.3..."
+ $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH73 $(KFLAGS)"
+
+redhat73+srp:
+ @echo "Building SECURE Kermit for Red Hat 7.3..."
+ $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH73 $(KFLAGS)"
+
+#Red Hat Linux 7.2 - full install includes Kerberos 5 (4 compat), PAM, SSL.
+#Also works around bug in curses in which terminal goes dead after
+#returning from file-transfer display.
+redhat72:
+ @echo "Building SECURE Kermit for Red Hat 7.2..."
+ $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH72 $(KFLAGS)"
+
+redhat72+srp:
+ @echo "Building SECURE Kermit for Red Hat 7.2..."
+ $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH72 $(KFLAGS)"
+
+#Red Hat Linux 7.1 - full install includes Kerberos 5 (4 compat), PAM, SSL.
+#Also works around bug in curses in which terminal goes dead after
+#returning from file-transfer display.
+redhat71:
+ @echo "Building SECURE Kermit for Red Hat 7.1..."
+ $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH71 $(KFLAGS)"
+
+redhat71+srp:
+ @echo "Building SECURE Kermit for Red Hat 7.1..."
+ $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH71 $(KFLAGS)"
+
+#Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, OpenSSL
+# with ZLIB and PAM and Shadow passwords
+linux+krb5+openssl+zlib+shadow+pam:
+ @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB5,SSL...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DCK_SHADOW -DHAVE_PTMX \
+ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \
+ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+ $(K5INC) $(K5INC)/krb5 $(SSLINC) \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+ "LIBS = $(K5LIB) $(SSLLIB) \
+ -lm -lncurses -ltermcap -lssl -lcrypto -lgssapi_krb5 \
+ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz"
+
+linuxnotcp:
+ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DNONET $(KFLAGS)"
+
+# "make linuxnotcp" with lcc (see http://www.cs.princeton.edu/software/lcc)
+# lcc does not understand various gcc extensions:
+# "__inline__" -- can be eliminated by adding "-D__inline__="
+# "__asm__ and "long long" -- in header files, should be surrounded by
+# "#ifndef(__STRICT_ANSI__)"/"#endif"
+# however, TCP requires some __asm__ functions, so cannot be compiled
+linuxnotcp-lcc:
+ @echo 'Making C-Kermit $(CKVER) for Linux with lcc ...'
+ @echo 'Read comments in makefile for additional information.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = lcc" "CC2 = lcc" \
+ "CFLAGS = -DLINUX -DPOSIX -DCK_CURSES -DCK_POSIX_SIG \
+ -UTCPSOCKET -DLINUXFSSTND -DNOLEARN $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lcurses -ltermcap"
+
+# Linux 0.99.14 thru 1.0 with gcc, dynamic libraries, curses, TCP/IP.
+# For Linux 1.2 or later, use "make linux" (above).
+#
+# -DLINUXFSSTND (Linux File System Standard) gives UUCP lockfile /var/lock with
+# string pid. Remove this and get /usr/spool/uucp with int pid, which was used
+# in early Linux versions.
+#
+# If you get compiler errors regarding <linux/serial.h>, add -DNOHISPEED.
+#
+# -DCK_POSIX_SIG (POSIX signal handling) is good for Linux releases back to at
+# least 0.99.14; if it causes trouble for you, just remove it.
+#
+# -DCK_CURSES: Here we link with the regular curses library. But you should
+# be using ncurses. Internally, the ckuusx.c module includes <curses.h>, but
+# this really should be <ncurses.h>. Thus if you have the new curses
+# material, you should either install it with the standard names, or else
+# create symbolic links from the standard names to the new ones. If you get
+# compile-time errors complaining about data definitions in termcap.h, it
+# means you have new kernel material mixed with older libc header files. To
+# fix, add "#include <termios.h>" to the <termcap.h> file. Or if all this is
+# too confusing, create a new makefile entry based on this one, but with
+# -DCK_CURSES removed from CFLAGS and the entire LIBS= clause removed.
+#
+# But wait, there's more. On most Linux systems, -ltermcap must be included
+# in LIBS. But on others, the linker complains that libtermcap can't be
+# found. In that case, try removing -ltermcap from LIBS=.
+#
+# But wait, there's more. The format of the PID string in the UUCP lockfile
+# changed between Linux FSSTND 1.0 and 1.2. In the earlier standard, it had
+# leading zeros; in the second, it has leading spaces. By default this entry
+# uses the newer standard. To force the older one, add -DFSSTND10.
+#
+# "The nice thing about the Linux standard is there are so many to choose from"
+#
+# NOTE: Remove -DBIGBUFOK for small-memory or limited-resource systems.
+linux10:
+ @echo 'Making C-Kermit $(CKVER) for Linux 1.0 or earlier...'
+ @echo 'IMPORTANT: Read the comments in the linux section of the'
+ @echo 'makefile if you get compilation or link errors.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -DPOSIX -DCK_CURSES -DCK_POSIX_SIG -DLINUX \
+ -DTCPSOCKET -DLINUXFSSTND -DOLINUXHISPEED -DNOLEARN $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lcurses -ltermcap"
+
+#This version was used for Linux prior to C-Kermit 6.0.192.
+#Now the "Linux File System Standard" is considered standard, ditto TCP/IP.
+linuxold:
+ @echo 'Making C-Kermit $(CKVER) for Linux...'
+ @echo 'For FSSTND-recommended UUCP lockfiles, use:'
+ @echo ' make linux "KFLAGS=-DLINUXFSSTND".'
+ @echo 'Read comments in makefile for additional options.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS = -O -DLINUX -DPOSIX -DCK_CURSES -DCK_POSIX_SIG -DNOLEARN \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lcurses -ltermcap"
+
+# ::END_OLD_LINUX_TARGETS::
+
+# LynxOS 2.2 with GCC compiler, TCP/IP and fullscreen display.
+# Probably also works with Lynx 2.1, and maybe even Lynx 2.0.
+# -X means use termios serial drivers rather than BSD4.3-style sgtty drivers.
+# If you have trouble with this, try "make bsd KFLAGS=-DNOFDZERO".
+lynx:
+ @echo 'Making C-Kermit $(CKVER) for LynxOS 2.2 with TCP/IP'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -O -DPOSIX -DDIRENT -DSETREUID -DCK_CURSES -DTCPSOCKET \
+ -DCK_ANSIC -DLYNXOS -DNOLEARN" "LNKFLAGS = -X" "LIBS = -lcurses -lbsd"
+
+lynx22:
+ $(MAKE) lynx KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)"
+
+# LynxOS 2.1 with GCC compiler 1.40 and TCP/IP.
+lynx21:
+ @echo 'Making C-Kermit $(CKVER) for LynxOS 2.1 with TCP/IP'
+ $(MAKE) kermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -O -DSETREUID -DTCPSOCKET -DCK_ANSIC -DBSD4 -DLYNXOS" \
+ "LIBS = -lbsd"
+
+#SCO Xenix 2.2.1 for IBM PC, XT, PS2/30, or other 8088 or 8086 machine
+#Should this not work, try some of the tricks from sco286.
+#NOTE: -DRENAME is omitted for early SCO Xenix releases because it didn't
+#exist, or its semantics were different from the later POSIX-compliant
+#version of rename().
+sco86:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/86...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DXENIX -DNOFILEH -DNOIKSD -DNOUNICODE -DNOLEARN \
+ $(KFLAGS) -Dunix -F 3000 -i -M0me" \
+ "LNKFLAGS = -F 3000 -i -s -M0me" "LIBS = -lx"
+
+#SCO Xenix/286 2.2.1, e.g. for IBM PC/AT, PS/2 Model 50, etc.
+#Reportedly, this "make" can fail simply because of the size of this
+#makefile. If that happens, use "makeL", or edit out some of the
+#other entries. No debugging or character-set translation.
+sco286:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/286...'
+ @echo 'If make fails, try using makeL.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -xenix -s -O -LARGE -DXENIX -DNOFILEH -Dunix -DRDCHK -DNAP \
+ -DNOIKSD -DNODEBUG -DNOTLOG -DNOCSETS -DNOLEARN \
+ $(KFLAGS) -F 3000 -i -M2let16" \
+ "LIBS = -lx" "LNKFLAGS = -xenix -s -O -LARGE -F 3000 -i -M2let16"
+
+#SCO Xenix/286 2.2.1, e.g. for IBM PC/AT, PS/2 Model 50, etc.
+#As above, but with HDBUUCP (This one might need fixing -- see sco286).
+sco286hdb:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/286 with HDB UUCP...'
+ @echo 'If make fails, try using makeL.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -s -O -LARGE -DXENIX -DNOFILEH -Dunix -DRDCHK -DNAP \
+ -DHDBUUCP -DNOIKSD -DNOUNICODE -DNOLEARN \
+ $(KFLAGS) -F 3000 -i -M2let32" \
+ "LIBS = -lx" "LNKFLAGS = -s -O -LARGE -F 3000 -i -M2let32"
+
+#SCO Xenix/386 2.2.2 and 2.2.3
+sco386:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.2.2...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DXENIX -DNOFILEH -DNOIKSD -DNOREDIRECT -DNOLEARN \
+ -Dunix -DRDCHK -DNAP -DNOUNICODE $(KFLAGS) -Otcl -M3e" \
+ "LNKFLAGS = -s" "LIBS = -lx"
+
+#SCO XENIX/386 2.2.3 with Excelan TCP/IP + curses.
+# NOTE: This one might need some work in C-Kermit 6.0.
+# You might need to include /usr/include/sys/types.h
+# containing "typedef char *caddr_t;". Then at least it compiles.
+sco386netc:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.2.3 + Excelan TCP'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -I/usr/include/exos -DXENIX -DCK_CURSES -DNOUNICODE \
+ -Dunix -DRDCHK -DNAP -DTCPSOCKET -DEXCELAN -DNOJC -DNOMKDIR -DNOFILEH \
+ -DNOLEARN -DNOREDIRECT -DNOIKSD -DNO_DNS_SRV $(KFLAGS) -Otcl -M3e" \
+ "LNKFLAGS = -s" "LIBS = -lc -lx -lsocket -lcurses -ltermcap"
+
+#SCO XENIX/386 2.3.3 with gcc 1.37 or later...
+sco386gcc:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.3.3, gcc...'
+ @echo 'Add -D_NO_PROTOTYPE if you have trouble with Xenix header files'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -O -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP \
+ -DNOJC -DNODEBUG -DNOUNICODE -DNOLEARN $(KFLAGS) \
+ -traditional -fpcc-struct-return -fstrength-reduce \
+ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM \
+ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \
+ -DM_SYSIII -DM_SYSV -DM_WORDSWAP -DM_XENIX -DNOIKSD -DNOREDIRECT \
+ -DPWID_T=int " "LNKFLAGS = -s" "LIBS = -lx"
+
+#As above, but with curses...
+sco386gccc:
+ @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.3.3, gcc...'
+ @echo 'Add -D_NO_PROTOTYPE if you have trouble with Xenix header files'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+ "CFLAGS= -O -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP \
+ -DNOJC -DNODEBUG -DCK_CURSES -DNOUNICODE -DNOLEARN $(KFLAGS) \
+ -traditional -fpcc-struct-return -fstrength-reduce \
+ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DNOREDIRECT \
+ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \
+ -DM_SYSIII -DM_SYSV -DM_WORDSWAP -DM_XENIX -DNOIKSD \
+ -DPWID_T=int " "LNKFLAGS = -s" "LIBS = -lx -lcurses -ltermlib"
+
+#SCO UNIX (and ODT) entries...
+#
+#NOTE: All SCO UNIX entry LIBS should have "-lc_s -lc -lx" IN THAT ORDER (if
+#shared C library is desired), or else "-lc -lx" IN THAT ORDER. Use shared C
+#libraries to save memory, but then don't expect to run the resulting binary
+#on a different machine. When using -lc_s, you must also use -lc, because the
+#shared C library does not contain all of libc.a. And in all cases, -lc must
+#ALWAYS precede -lx.
+#
+#ANOTHER NOTE: -DRENAME is included in all SCO UNIX entries. Remove it if it
+#causes trouble. No harm is done by removing it (see ckuins.txt).
+#
+#AND ANOTHER: In theory, it should be possible to run SCO UNIX binaries on
+#SCO Xenix 2.3 and later. In practice, this might not work because of the
+#libraries, etc. Also, don't add the -link -z switch (which is supposed to
+#root out references to null pointers) because it makes UNIX binaries core
+#dump when they are run under Xenix.
+
+#NOTE: -Otcl removed and replaced by -O, since -Otcl produced incorrect code.
+#SCO UNIX/386 3.2.0, 3.2.1, and SCO Xenix 2.3.x
+sco3r2:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2.0 or 3.2.1 ...'
+ @echo 'Warning: If make blows up, edit the makefile to join'
+ @echo 'the following three continued lines into one line.'
+ @echo 'Also, remove -DRENAME if _rename unresolved at link time.'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DNOLEARN \
+ -DRENAME -DNOIKSD -DNOJC $(KFLAGS) -O" \
+ "LNKFLAGS = -s" "LIBS = -lc -lx"
+
+#SCO UNIX/386 3.2.0 and SCO Xenix 2.3.x with Excelan TCP/IP support.
+#In case of compilation or runtime problems, try adding
+#"-DUID_T=int -DGID_T=int" to the CFLAGS. If that doesn't work, try
+#"-DUID_T=uid_t -DGID_T=gid_t".
+sco3r2net:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 / Excelan...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -I/usr/include/exos -DXENIX -DSVR3 -DNOFILEH -DNOLEARN \
+ -DHDBUUCP -DRDCHK -DNAP -DRENAME -DTCPSOCKET -DEXCELAN -DNOJC \
+ -DNOIKSD -DNOREDIRECT $(KFLAGS) -O" \
+ "LNKFLAGS = -s" "LIBS = -lc -lx -lsocket"
+
+#SCO UNIX/386 3.2.0 and SCO Xenix 2.3.x with Excelan TCP/IP support.
+#As above, with curses added.
+sco3r2netc:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 / Excelan / curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -I/usr/include/exos -DXENIX -DSVR3 -DNOFILEH -DNOLEARN \
+ -DHDBUUCP -DRDCHK -DNAP -DTCPSOCKET -DEXCELAN -DNOJC $(KFLAGS) \
+ -DRENAME -DCK_CURSES -DNOREDIRECT -DNOIKSD -O" "LNKFLAGS = -s" \
+ "LIBS = -lc -lx -lsocket -lcurses -ltermcap"
+
+#SCO UNIX 3.2.x or SCO Xenix 2.3.x with Racal InterLan TCP/IP support
+# Extra compile flags for other version of Racal InterLan TCP/IP:
+# Xenix286/NP621-286, use -Ml -DPARAMH -DINTERLAN -Di286 -DSYSV
+# Xenix386/NP621-386, use -DPARAMH -DINTERLAN -Di386 -DSYSV
+# ISC386ix/NP622I, use -DSYSV -Di386
+# SCO Unix3.2/NP622S, use -DSYSV -Di386 -DSCO_UNIX
+# AT&T SVR3.2/NP622A, use -DSYSV -Di386 -DATT
+sco3r2netri:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 / Racal InterLan...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -I/usr/include/interlan -DXENIX -DNOFILEH -DHDBUUCP \
+ -DSVR3 -DRDCHK -DNAP -DTCPSOCKET -DPARAMH -DINTERLAN -Di386 -DSYSV \
+ -DRENAME -DNOREDIRECT -DNOIKSD -DNOJC -DNOLEARN $(KFLAGS) -Otcl -M3e" \
+ "LNKFLAGS = -s" "LIBS = -lc -lx -ltcp"
+
+# SCO XENIX/386 2.3.3 SysV with SCO TCP/IP
+# System V STREAMS TCP developed by Lachman Associates Inc and
+# Convergent Technologies.
+# -DRENAME removed since some reports indicate it is not supported
+# (whereas others say it is.)
+sco3r2lai:
+ @echo 'Making C-Kermit $(CKVER) for SCO XENIX/386 2.3.3 + TCP/IP...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DLAI_TCP -Di386 -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK \
+ -DNAP -DTCPSOCKET -DPWID_T=int -DNOREDIRECT -DNOIKSD -DNOLEARN \
+ $(KFLAGS) -Otcl -i -M3e" \
+ "LNKFLAGS = -i -s" "LIBS = -lc -lx -lsocket"
+
+sco3r2laic:
+ @echo 'Making C-Kermit $(CKVER) for SCO XENIX/386 2.3.3 + TCP/IP...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DLAI_TCP -Di386 -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK \
+ -DNAP -DTCPSOCKET -DCK_ANSIC -DCK_CURSES -DM_TERMINFO -DNOLEARN \
+ -DPWID_T=int -DNOREDIRECT -DNOIKSD $(KFLAGS) -Otcl -i -M3e" \
+ "LNKFLAGS = -i -s" "LIBS = -ltinfo -lc -lx -lsocket"
+
+#SCO UNIX/386 3.2v2 (POSIX job control), shared libraries.
+sco3r22:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2 ...'
+ make wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \
+ -DNAP -DRENAME -DPID_T=pid_t -DPWID_T=int -DDIRENT -DNOIKSD \
+ -DNOREDIRECT $(KFLAGS) -O" \
+ "LNKFLAGS = -s" "LIBS = -lc_s -lc -lx"
+
+#SCO UNIX/386 3.2v2, POSIX job control, fullscreen file transfer display,
+#dynamic memory allocation, shared C library
+sco3r22c:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2 ...'
+ @echo 'Warning: If make blows up, edit the makefile to join'
+ @echo 'the following four continued lines into one line.'
+ make wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DNOLEARN \
+ -DCK_CURSES -DDIRENT -DRENAME -DNOREDIRECT -DNOIKSD \
+ -DPID_T=pid_t -DPWID_T=int $(KFLAGS) -O" \
+ "LNKFLAGS = -s" "LIBS = -lcurses -lc_s -lc -lx"
+
+#SCO UNIX/386 3.2v2 with gcc 1.40 or later (POSIX job control)
+sco3r22gcc:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2, gcc'
+ @echo 'Warning: If make blows up, edit the makefile to join'
+ @echo 'the following seven continued lines into one line.'
+ make wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" \
+ "CFLAGS= -O -DPOSIX -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP \
+ -DNOLEARN -DRENAME -traditional -fpcc-struct-return -fstrength-reduce \
+ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM \
+ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \
+ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \
+ -DPID_T=pid_t -DPWID_T=int -DNOREDIRECT -DNOIKSD $(KFLAGS) " \
+ "LNKFLAGS = -s" "LIBS = -lc_s -lc -lx"
+
+#SCO UNIX/386 3.2v2 (ODT 1.1) (POSIX job control) with SCO TCP/IP, shared libs
+#Requires SCO TCP/IP or ODT development system for telnet.h, etc.
+sco3r22net:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2.2 + TCP/IP...'
+ @echo 'Warning: If make blows up, edit the makefile to join'
+ @echo 'the following three continued lines into one line.'
+ make xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DTCPSOCKET \
+ -DRENAME -DPID_T=pid_t -DPWID_T=int -DDIRENT -DNOREDIRECT -DNOIKSD \
+ $(KFLAGS) -O" "LNKFLAGS = -s" "LIBS = -lsocket -lc_s -lc -lx"
+
+#As above, but with curses for fullscreen file transfer display.
+#Requires SCO TCP/IP or ODT development system for telnet.h, etc.
+sco3r22netc:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2 + TCP/IP...'
+ @echo 'Warning: If make blows up, edit the makefile to join'
+ @echo 'the following three continued lines into one line.'
+ make xermit KTARGET=$${KTARGET:-$(@)} "CFLAGS= \
+ -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DTCPSOCKET -DRENAME \
+ -DCK_CURSES -DDIRENT -DNOIKSD -DNOREDIRECT \
+ -DPID_T=pid_t -DPWID_T=int -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lcurses -lsocket -lc_s -lc -lx"
+
+#SCO XENIX 2.3.4, no curses, no TCP/IP, no IKSD.
+#This one built and tested in C-Kermit 7.0.
+#lcfp is C library floating-point support.
+#Use -M3 to generate 32-bit i386 code instead of 16-bit segmented i286 code.
+#Use -Me to enable MS nonstandard keywords in system headers.
+#Use -W2 or W3 to increase the warning level.
+#OK: 2011/06/15
+sco234:
+ @echo 'Making C-Kermit $(CKVER) for SCO XENIX 2.3.4...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSCO32 -DXENIX -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \
+ -DNAP -DNOJC -DNOCOTFMC -DNOIKSD -DNOREDIRECT -DNOTNCODE -DNOGFTIMER \
+ -DNOTIMEVAL -DNOTIMEZONE -DNOSYMLINK -DSCO234 -DDCLGETCWD $(KFLAGS) \
+ -Otcl" "LNKFLAGS = -s" "LIBS = -lcfp -lc -lx"
+
+#SCO XENIX 2.3.4, no TCP/IP, no IKSD, but with curses.
+# Built and tested in C-Kermit 7.0.
+# Note: XENIX 2.3.4 does not have newterm() so no point in adding -DCK_NEWTERM.
+sco234c:
+ @echo 'Making C-Kermit $(CKVER) for SCO XENIX 2.3.4 + curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSCO32 -DXENIX -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \
+ -DNAP -DNOJC -DNOCOTFMC -DNOIKSD -DNOREDIRECT -DNOTNCODE -DNOGFTIMER \
+ -DNOTIMEVAL -DNOTIMEZONE -DNOSYMLINK -DCK_CURSES -DSCO234 \
+ -DDCLGETCWD $(KFLAGS) -Otcl" \
+ "LNKFLAGS = -s" "LIBS = -lcfp -lc -ltinfo -lx"
+
+#SCO XENIX 2.3.4 with SCO TCP/IP and curses, no IKSD.
+# Built and tested in C-Kermit 7.0. TCP/IP works and curses works.
+# Previous versions of this target included -lmalloc, but this caused "error:
+# " _calloc : symbol defined more than once" at link time so I removed it.
+# Results are likely to vary depending on exactly which version of the SDK
+# and TCP/IP SDK you have.
+sco234netc:
+ @echo 'Making C-Kermit $(CKVER) for SCO XENIX 2.3.4 + TCP + curses...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DSCO32 -DXENIX -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \
+ -DNAP -DNOJC -DNOCOTFMC -DNOIKSD -DNOREDIRECT -DNOTNCODE -DNOGFTIMER \
+ -DNOTIMEVAL -DNOTIMEZONE -DNOSYMLINK -DCK_CURSES -DSCO234 \
+ -DDCLGETCWD -DTCPSOCKET -DNO_DNS_SRV $(KFLAGS) -Otcl" \
+ "LNKFLAGS = -s" "LIBS = -ltinfo -lsocket -lcfp -lc -lx"
+
+# SCO 3.2v4.x targets...
+
+# NOTE: Add -DDCLPOPEN and/or -DDCLFDOPEN to anySCO 3.2v4.x non-gcc entries
+# that complain about fdopen() or popen() at compile time. They compile OK
+# without these flags as of July 1999. However, the gcc entries seem to
+# need them, at least for gcc 2.7.2.2.
+
+# NOTE 2: To enable IKSD support, add:
+# -DCK_LOGIN -DNOGETUSERSHELL -DNOINITGROUPS
+# to CFLAGS (not tested).
+
+#SCO UNIX/386 3.2v4 (POSIX job control), curses, ANSI C compilation,
+#<dirent.h> (EAFS) file system. Remove -lmalloc if it causes trouble. It was
+#put there to avoid core dumps caused by regular libc.a malloc. Add -J to make
+#all chars unsigned. This version uses select() for CONNECT and also has
+#high-precision timers and so might not work on non-TCP systems, in which case
+#sco32v4ns should be used instead.
+# If you get _ftime redefinition_ complaint, try adding -DODT30 to CFLAGS.
+sco32v4:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...'
+ make xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DCK_SCO32V4 -DNOFILEH -DHDBUUCP -DCK_CURSES -DM_TERMINFO \
+ -DNOANSI -DSELECT -DNOIKSD -DDCLGETCWD -NOLSTAT \
+ -DNOLINKBITS -DDCLGETCWD $(KFLAGS) -O" \
+ "LNKFLAGS = -s" "LIBS = -lcurses -lmalloc -lsocket -lc_s -lc -lx"
+
+# As above, but with no dependence on sockets library or select().
+sco32v4ns:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...'
+ @echo 'No select() and no sockets library.'
+ make wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DCK_SCO32V4 -DNOFILEH -DHDBUUCP -DCK_CURSES -DM_TERMINFO \
+ -DNOANSI -DNOIKSD -DNOGFTIMER -DCK_POLL -DNAP -DDCLGETCWD -DNOLSTAT \
+ -DNOLINKBITS -DDCLGETCWD -DNOLEARN -O $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lcurses -lmalloc -lc_s -lc -lx"
+
+#SCO UNIX/386 3.2v4 (POSIX job control), TCP/IP, curses, ANSI C compilation,
+#<dirent.h> (EAFS) file system. With DIRENT, -lc must come before -lx.
+#Reportedly it's OK to add -DCK_REDIR and -DCK_WREFRESH, and to remove -lc_s.
+#Requires SCO TCP/IP development system or ODT for telnet.h, etc.
+#See sco32v4 above for additional comments.
+#NOTE: No more room for -Dxxx -- 25 seems to be the limit. Move some to
+#ckcdeb.h or somewhere...
+sco32v4net:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...'
+ @echo 'If you get _ftime redefinition_ complaint,'
+ @echo 'use make sco-odt30.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNOFILEH -DHDBUUCP -DTCPSOCKET -DCK_ANSIC -DCK_CURSES \
+ -DNAP -DCK_WREFRESH -DNOLINKBITS -D_IBCS2 -DSELECT -DNOLSTAT \
+ -DDCLGETCWD -DCK_SCO32V4 -DNOIKSD -O \
+ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS) -s" \
+ "LIBS = $(LIBS) -lcurses -lsocket -lmalloc -lsocket -lc_s -lc -lx"
+
+#SCO UNIX/386 3.2v4 with gcc 1.40 or later, POSIX job control.
+#Also see comments in sco32r4 entry.
+sco32v4gcc:
+ make xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" \
+ "CFLAGS= -O -DNOFILEH -DHDBUUCP -DNOANSI -DCK_CURSES -DM_TERMINFO \
+ -traditional -fpcc-struct-return -fstrength-reduce -funsigned-char \
+ -D_KR -D_NO_PROTOTYPE -D_SVID -DNOIKSD -DCK_SCO32V4 -DNOLINKBITS \
+ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DSELECT -DNOLSTAT \
+ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 -DDCLGETCWD \
+ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \
+ -DDCLPOPEN -DDCLFDOPEN $(KFLAGS) " \
+ "LNKFLAGS = -s" "LIBS = -lcurses -lsocket -lc_s -lc -lx"
+
+#SCO UNIX/386 3.2v4 (POSIX job control), TCP/IP, curses, ANSI C compilation,
+#Requires SCO TCP/IP or ODT development system for telnet.h, etc.
+#<dirent.h> (EAFS) file system. With DIRENT, -lc must come before -lx.
+#gcc 1.40 or later. Also see comments in sco32r4 entry.
+sco32v4netgcc:
+ make xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2=gcc" \
+ "CFLAGS= -O2 -DNOFILEH -DHDBUUCP -DSELECT -DNOLSTAT \
+ -DNOANSI -DTCPSOCKET -DCK_CURSES -DM_TERMINFO \
+ -D_KR -D_NO_PROTOTYPE -D_SVID -DNOIKSD -DCK_SCO32V4 -DNOLINKBITS \
+ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DDCLGETCWD \
+ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \
+ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \
+ -DDCLPOPEN -DDCLFDOPEN $(KFLAGS)" \
+ "LNKFLAGS = -s" "LIBS = -lcurses -lsocket -lc_s -lc -lx"
+
+#As above but with bgcc BOUNDS CHECKING (for developers only). -lcheck has
+#bounds-checking replacements for malloc, memcpy, bcopy, etc, so must come
+#before -lsocket and -lc.
+sco32v4netbgcc:
+ make xermit KTARGET=$${KTARGET:-$(@)} \
+ "CC = bgcc -pipe -m386" "CC2=bgcc -pipe -m386" \
+ "CFLAGS= -O1 -g -DNOFILEH -DHDBUUCP -DSELECT \
+ -DNOANSI -DTCPSOCKET -DCK_CURSES -DM_TERMINFO \
+ -D_KR -D_NO_PROTOTYPE -D_SVID -DNOIKSD -DCK_SCO32V4 -DNOLSTAT \
+ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DNOLINKBITS \
+ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 -DDCLGETCWD \
+ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \
+ -DDCLPOPEN -DDCLFDOPEN $(KFLAGS) " \
+ "LNKFLAGS = -g" "LIBS = -lcurses -lcheck -lsocket -lx"
+
+sco32v4netnd:
+ @echo sco32v4net with no debug
+ $(MAKE) "MAKE=$(MAKE)" sco32v4net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DNODEBUG -DNOTLOG" "LIBS=$(LIBS)"
+
+sco3r2netnd:
+ @echo sco32v4netnd built for SCO XENIX 2.3 under SCO UNIX...
+ @echo requires copying /lib/386/Slibc.a to /lib/386/Slibc_s.a and
+ @echo getting /lib/386/Slibsocket.a from a XENIX devkit.
+ @echo WARNING: poll/CK_POLL supported only on XENIX 2.3.4
+ echo For earlier XENIX systems, replace CK_POLL with RDCHK.
+ $(MAKE) "MAKE=$(MAKE)" sco32v4netnd KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -x2.3 -DNORENAME -DNOSYMLINK" \
+ "LNKFLAGS = $(LNKFLAGS) -x2.3" \
+ "LIBS=-ldir -lcfp $(LIBS)"
+
+#SCO UNIX/386 3.2v4 (POSIX job control), TCP/IP, curses, ANSI C compilation,
+#<dirent.h> (EAFS) file system. With DIRENT, -lc must come before -lx.
+#Reportedly it's OK to add -DCK_REDIR and -DCK_WREFRESH, and to remove -lc_s.
+#Requires SCO TCP/IP development system or ODT for telnet.h, etc.
+#See sco32v4 above for additional comments.
+# Note: "xermit" means use the select() version of the CONNECT module.
+sco32v4netx:
+ @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...'
+ @echo 'If you get _ftime redefinition_ complaint,'
+ @echo 'use make sco-odt30.'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DNOFILEH -DHDBUUCP -DTCPSOCKET -DCK_ANSIC -DCK_CURSES -DNAP \
+ -DCK_WREFRESH -DNOLINKBITS -D_IBCS2 -DSELECT -DDCLGETCWD \
+ -DCK_SCO32V4 -DNOIKSD -DNOLSTAT -O $(KFLAGS)" \
+ "LNKFLAGS = $(LNKFLAGS) -s" \
+ "LIBS = $(LIBS) -lcurses -lsocket -lmalloc -lsocket -lc_s -lc -lx"
+
+sco32v4netndx:
+ @echo sco32v4netx with no debug
+ $(MAKE) "MAKE=$(MAKE)" sco32v4netx KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DNODEBUG -DNOTLOG" "LIBS=$(LIBS)"
+
+sco3r2netndx:
+ @echo sco32v4netndx built for SCO XENIX 2.3 under SCO UNIX...
+ @echo requires copying /lib/386/Slibc.a to /lib/386/Slibc_s.a and
+ @echo getting /lib/386/Slibsocket.a from a XENIX devkit.
+ @echo WARNING: poll/CK_POLL supported only on XENIX 2.3.4
+ echo For earlier XENIX systems, replace CK_POLL with RDCHK.
+ $(MAKE) "MAKE=$(MAKE)" sco32v4netndx KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -x2.3 -DNORENAME -DNOSYMLINK" \
+ "LNKFLAGS = $(LNKFLAGS) -x2.3" \
+ "LIBS=-ldir -lcfp $(LIBS)"
+
+sco-odt30:
+ @echo SCO ODT 3.0
+ $(MAKE) "MAKE=$(MAKE)" sco32v4net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=$(KFLAGS) -DODT30"
+
+#SCO OpenServer 5.0 (SCO UNIX 3.2v5.0) with SCO development tools, no TCP/IP.
+#SCO OSR5 is much more like standard System V than previous SCO releases.
+#The SCO development tools include TCP/IP, so this target is only for creating
+#artificially limited versions of kermit required by site policy rather than
+#the operating system. NOSYSLOG is included because syslog() requires the
+#sockets library.
+sco32v500:
+ @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DNOSYSLOG \
+ $(KFLAGS)" \
+ "LIBS=-lcurses $(LIBS)" "LNKFLAGS=$(LNKFLAGS)"
+
+sco32v5:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sco32v500
+
+
+#SCO OpenServer 5.0 with networking, SCO development tools.
+#Networking libraries are now provided with the OS.
+sco32v500net:
+ @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \
+ -DNO_DNS_SRV $(KFLAGS)" \
+ "LIBS=-lcurses -lsocket $(LIBS)" "LNKFLAGS=$(LNKFLAGS)"
+
+sco32v5net:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sco32v500net
+
+#SCO OpenServer 5.0 with networking and OpenSSL, SCO development tools.
+#Networking libraries are now provided with the OS.
+sco32v500net+ssl:
+ @echo Making C-Kermit $(CKVER) for SCO OSR5 with OpenSSL...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \
+ -DNO_DNS_SRV -DCK_AUTHENTICATION -DCK_SSL -DCK_TRIGGER \
+ $(SSLINC) $(SSLLIB) $(KFLAGS)" \
+ "LIBS=$(SSLLIB) -lcurses -lsocket -lssl -lcrypto $(LIBS)" \
+ "LNKFLAGS=$(LNKFLAGS)"
+
+#SCO OpenServer 5.0 with gcc, no networking.
+#Note: NOSYSLOG required for non-net entries because it requires <socket.h>
+sco32v500gcc:
+ @echo Using gcc...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500CC=gcc CC2=gcc \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS= $(KFLAGS)"
+
+#SCO OpenServer 5.0 with networking, gcc.
+sco32v500netgcc:
+ @echo TCP/IP networking added - using gcc...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net CC=gcc CC2=gcc \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)"
+
+#SCO OpenServer 5.0 with networking, gcc, elf.
+sco32v500netgccelf:
+ @echo TCP/IP networking added - using gcc, dynamic elf library
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-O3 -belf" "LNKFLAGS=-belf"
+
+sco32v502:
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR502 $(KFLAGS)"
+
+#SCO OpenServer 5.0.2 with networking, SCO development tools.
+sco32v502net:
+ @echo TCP/IP networking added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-b elf -DSCO_OSR502 $(KFLAGS)"
+
+#SCO OpenServer 5.0.4 (SCO UNIX 3.2v5.0.4) with SCO development tools.
+#Like 5.0, but adds high serial speeds. First POSIX-based SCO version.
+#Note: the -O flag is deliberately omitted for /bin/cc (= /usr/ccs/bin/cc).
+sco32v504:
+ @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5.0.4...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \
+ -DSCO_OSR504 -b elf -DPOSIX \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DNOSYSLOG $(KFLAGS)" \
+ "LIBS=-lcurses $(LIBS)" "LNKFLAGS=$(LNKFLAGS)"
+
+#SCO OpenServer 5.0.4 with gcc, no networking.
+sco32v504gcc:
+ @echo Using gcc...
+ $(MAKE) "MAKE=$(MAKE)" sco32v504 "CC=gcc" "CC2=gcc" \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS= $(KFLAGS)"
+
+#SCO OpenServer 5.0.4 with networking.
+#SCO development tools (/bin/cc = /usr/ccs/bin/cc).
+#Optimization deliberately suppressed.
+sco32v504net:
+ @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5.0.4...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \
+ -b elf -DSCO_OSR504 -DPOSIX -DNO_DNS_SRV $(KFLAGS)" \
+ "LIBS=-lcurses -lsocket $(LIBS)" "LNKFLAGS=$(LNKFLAGS)"
+
+#SCO OpenServer 5.0.4 with networking, gcc.
+sco32v504netgcc:
+ @echo TCP/IP networking added - using gcc...
+ @echo If gcc crashes on ckwart.c then build it by hand:
+ @echo " gcc -o wart -DCK_SCOV5 ckwart.c"
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \
+ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DSCO_OSR504 -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.4 with networking, gcc, elf.
+sco32v504netgccelf:
+ @echo TCP/IP networking added - using gcc, dynamic elf library
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc"
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR504 -DPOSIX -O3 -belf $(KFLAGS)" \
+ LNKFLAGS="-belf"
+
+#SCO OpenServer 5.0.5 (SCO UNIX 3.2v5.0.5) with SCO /bin/cc.
+#Like 5.0, but adds high serial speeds. First POSIX-based SCO version.
+#You might have to add "LIBS=-ltinfo" (some do, some don't).
+sco32v505:
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.5 (SCO UNIX 3.2v5.0.5) with SCO UDK.
+#This one can't see the high serial speeds and anything to do with modem
+#signals doesn't work because UKD cc has its own alternative universe of
+#header files.
+sco32v505udk:
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DDCLTIMEVAL -DNOSHADOW -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.5 with networking, SCO /bin/cc.
+#See comments with sco32v505 targets.
+sco32v505net:
+ @echo TCP/IP networking added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.5 with networking and OpenSSL, SCO /bin/cc.
+#See comments with sco32v505 targets.
+sco32v505net+ssl:
+ @echo TCP/IP networking and OpenSSL added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net+ssl KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -b elf -DPOSIX $(KFLAGS) " \
+ "LIBS=$(SSLLIB) -lcurses -lsocket -lssl -lcrypto $(LIBS)" \
+ "LNKFLAGS=$(LNKFLAGS)"
+
+#SCO OpenServer 5.0.5 with networking, SCO UDK.
+#See comments with above sco32v505 targets.
+sco32v505udknet:
+ @echo TCP/IP networking added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DDCLTIMEVAL -DNOSHADOW -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.5 with gcc, no networking.
+sco32v505gcc:
+ @echo Using gcc...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 "CC=gcc" "CC2=gcc" \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DPOSIX -funsigned-char $(KFLAGS)"
+
+#SCO OpenServer 5.0.5 with gcc, no networking, no shadow passwords.
+sco32v505xgcc:
+ @echo Using gcc...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 "CC=gcc" "CC2=gcc" \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -DPOSIX -funsigned-char $(KFLAGS)"
+
+#SCO OpenServer 5.0.5 with networking, gcc.
+sco32v505netgcc:
+ @echo TCP/IP networking added - using gcc...
+ @echo If gcc crashes on ckwart.c then build it by hand:
+ @echo " gcc -o wart -DCK_SCOV5 ckwart.c"
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \
+ KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -DPOSIX -funsigned-char $(KFLAGS)"
+
+#egcs is just like gcc but generates ELF by default.
+#Or you can include -melf (not -belf) to force it.
+sco32v505netegcs:
+ $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sco32v505netgcc \
+ KTARGET=$${KTARGET:-$(@)}
+
+#SCO OpenServer 5.0.5 with networking, gcc, elf.
+sco32v505netgccelf:
+ @echo TCP/IP networking added - using gcc, dynamic elf library
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \
+ "KFLAGS=-DSCO_OSR505 -DPOSIX -funsigned-char -O3 -belf $(KFLAGS)" \
+ KTARGET=$${KTARGET:-$(@)} LNKFLAGS="-belf"
+
+#SCO OpenServer 5.0.6 with SCO /bin/cc.
+# Add -DDCLTIMEVAL when building with UDK.
+#Like 5.0.5. IMPORTANT: Use sco32v506a target for 5.0.6a.
+sco32v506:
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.6 with networking, SCO /bin/cc.
+# Add -DDCLTIMEVAL when building with UDK.
+# IMPORTANT: Use sco32v506a target for 5.0.6a.
+sco32v506net:
+ @echo TCP/IP networking added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.6a, no networking, SCO development tools.
+#This one has patched sio drivers that, for the first time,
+#actually handle modem signals correctly.
+# Add -DDCLTIMEVAL when building with UDK.
+sco32v506a:
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR506A -DNEEDMDMDEFS \
+ -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.6a with networking, SCO development tools.
+# Add -DDCLTIMEVAL when building with UDK.
+sco32v506anet:
+ @echo TCP/IP networking added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR506A -DNEEDMDMDEFS \
+ -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.7, no networking, SCO development tools.
+#Adds flags to make PTY and SSH commands work. These have been tested
+#only in 5.0.7 but probably they can also be added to earlier OSR5 targets.
+sco32v507:
+ $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR507 -DNEEDMDMDEFS \
+ -DHAVE_PTSNAME -DHAVE_PTMX -DHAVE_GRANTPT \
+ -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 5.0.7 as above but with networking.
+sco32v507net:
+ @echo TCP/IP networking added...
+ $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \
+ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR507 -DNEEDMDMDEFS \
+ -DHAVE_PTSNAME -DHAVE_PTMX -DHAVE_GRANTPT \
+ -b elf -DPOSIX $(KFLAGS)"
+
+#SCO OpenServer 6 (new target 30 Jan 2006)
+sco_osr600 sco600:
+ @echo Making C-Kermit $(CKVER) for SCO OpenServer 6.0.0...
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \
+ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \
+ -DNO_DNS_SRV -DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR507 -DNEEDMDMDEFS \
+ -DHAVE_PTSNAME -DHAVE_PTMX -DHAVE_GRANTPT -DDCLTIMEVAL \
+ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \
+ -DSOCKOPT_T=socklen_t -DGSOCKNAME_T=size_t -DGPEERNAME_T=size_t \
+ -DHERALD=\"\\\" SCO OpenServer `uname -v`\\\"\" \
+ -b elf -DPOSIX $(KFLAGS)" \
+ "LIBS=-lcurses -lsocket $(LIBS)" "LNKFLAGS=$(LNKFLAGS)"
+
+#Tandy 16/6000 with Xenix 3.0 (16 bits)
+#C-Kermit 7.0 (and later) do not build here; "too many defines".
+#Add more -DNOxxx options to remove features if program won't load.
+#Successful operation is a function of program size, physical memory,
+#available swap space, etc. The following stripped-down configuration
+#seems to work on most Tandy 6000s. NOTE: "-+" means allow long variable
+#names, needed for C-Kermit 6.0 because some identifiers are not unique
+#within the first six characters.
+trs16:
+ @echo 'Making C-Kermit $(CKVER) for Tandy 16/6000, Xenix 3.0...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -+ -DATTSV -DTRS16 -DNOMKDIR -DDCLPOPEN -DCK_CURSES \
+ -DNODEBUG -DNOTLOG -DNOHELP -DNOSCRIPT -DNOCSETS -DNOIKSD \
+ -DNOREDIRECT -DNOSYSLOG -DNOPUTENV -DNOREALPATH -DNOLEARN \
+ $(KFLAGS) -O" "LIBS= -lcurses -ltermcap" "LNKFLAGS = -+ -n -s"
+
+# QNX 4.21 and above, 32-bit version, Watcom C32 10.6, fully configured,
+# except no job control because QNX 4.x does not support it. New NCURSES
+# library used instead of CURSES.
+#
+# -Oatx optimizes to favor speed over size: loop optimization, inline fn's.
+# -Os favors size over speed. Saves 30-40K out of about 1.75M.
+# -3r = generate 386 code with register-based arg passing.
+# -3s = generate 386 code with stack-based arg passing.
+# -ms = separate code & data 4GB segments (32-bit builds only).
+# -mf = flat memory model code+data in one 4GB segment (ditto).
+# -zc = place literal strings in code segment.
+# -N4M = Big stack (increase the digit upon SIGSEGVs at runtime).
+# chars are unsigned by default (-j makes them signed by default).
+# -NOUUCP is included because QNX doesn't use it.
+# Add these to the end if you like but they dump core on my QNX 4.25 system:
+#
+# @wermit -h >use.qnx
+# @usemsg wermit use.qnx
+# @rm use.qnx
+#
+# If you get warnings about HEADER or C_IN add -DNO_DNS_SRV.
+# OK 2011/06/14
+qnx32:
+ @echo 'Making C-Kermit $(CKVER) for QNX 4.2x, 32-bit...'
+ $(MAKE) xermit \
+ "LNKFLAGS = -N4M -3r" \
+ "CFLAGS = -ms -3r -DQNX -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL \
+ -DCK_WREFRESH -DCK_REDIR -DSELECT -DSELECT_H -DCK_RTSCTS -DNOJC \
+ -DNOINITGROUPS -DNOUUCP -DCK_ANSIC -DPID_T=pid_t -Oatx -zc $(KFLAGS)" \
+ "LIBS= -lsocket -lncurses -ltermcap"
+
+# As above but no networking since some QNX systems do not have TCP/IP
+# installed, or the TCP/IP developers kit, which includes all the needed
+# header files. This entry has not been tested on a QNX system that, in
+# fact, does not have TCP/IP installed; some adjustments might be necessary,
+# in particular regarding the use of select(): is -lsocket needed, can we
+# get the needed definitions from non-TCP/IP header files (FD_SET, etc)?
+qnx32nonet:
+ @echo 'Making C-Kermit $(CKVER) for QNX 4.2x, 32-bit, no net...'
+ $(MAKE) xermit \
+ "LNKFLAGS = -N4M -3r" \
+ "CFLAGS = -3r -ms -DQNX -DNONET -DNOIKSD -DCK_CURSES \
+ -DCK_WREFRESH -DCK_REDIR -DSELECT -DSELECT_H -DCK_RTSCTS -DNOJC \
+ -DNOUUCP -DCK_ANSIC -DPID_T=pid_t -Oatx -zc $(KFLAGS)" \
+ "LIBS= -lsocket -lncurses -ltermcap"
+ @wermit -h >use.qnx
+ @usemsg wermit use.qnx
+ @rm use.qnx
+
+# Synonym for qnx32.
+qnx:
+ $(MAKE) qnx32 "KFLAGS=$(KFLAGS)"
+
+# QNX 4.21 and above, 16-bit version, Watcom C 8.5 - and higher on i286 PCs
+# and above.
+#
+# IMPORTANT: Do not use Watcom C 10.6!!!
+# If you have it installed, add "-v9.52 to CFLAGS"
+#
+# NOTE: QNX 4.23 onward does not work on 286's anyway.
+# Stacksize 26000, objects larger than 100 bytes in their own segments,
+# string constants to the codesegment, etc. Fully configured except job ctrl.
+# This entry works for building a 16-bit executable on a 32-bit system, but
+# has not been tested on a 16-bit system. Uses large memory model, links
+# explicitly with large-model sockets library. Correct-model curses library
+# is chosen automatically. See comment in qnx32 entry about -DNOUUCP.
+#
+# WARNING:
+#
+# Watcom C prior to 10.6 never had released curses library. To link against it,
+# you must obtain ported free curses source from ftp://ftp.qnx.com/usr/free,
+# then compile and build library (cursesl.lib) and place it in /usr/lib. You
+# must also copy curses.h to /usr/include. Be aware that if you have Watcom
+# 10.6 installed, you should already have curses.h, which is the new ncurses
+# library. You must back it up and use free curses.h instead, since ncurses is
+# only for 32-bit applications and some definitions in these files are
+# different (e.g., clearok()). For safety, curses is not defined in build.
+#
+# In 7.0 -DNOHELP added to keep ckuus2.c from blowing up; NOCSETS and NOSPL
+# added because ckuus4 was blowing up, and NOFLOAT just because it seemed
+# dangerous (remove -DNOFLOAT if you want to try it), The result works OK
+# except for some mysterious beeps upon termination of the top-level keyword.
+#
+# Things to try next time we get in trouble:
+# . Change -zt100 to something smaller like -zt25
+# . Change -Oatx to -Omilerat (enable stack checking)
+# . Maybe get rid of -v9.52 -- it's only there because we were warned.
+#
+qnx16:
+ @echo 'Making C-Kermit $(CKVER) for QNX 4.21, 16-bit...'
+ $(MAKE) xermit \
+ "LNKFLAGS = -2 -ml -N 26000" \
+ "CFLAGS = -2 -Oatx -zc -zt100 -ml -DQNX -DQNX16 -DNOUUCP -DNOHELP \
+ -DCK_REDIR -DSELECT -DSELECT_H -DNOJC -DNOGETUSERSHELL -DNOCSETS \
+ -v9.52 -DTCPSOCKET -DCK_RTSCTS -DCK_ANSIC -DNOINITGROUPS -DNOKVERBS \
+ -DNORANDOM -DNOCSETS -DNOSPL -DNOFLOAT -DPID_T=pid_t $(KFLAGS)"
+
+# QNX 4.1, 16-bit version, with Watcom C 8.5 on i286 PCs and above.
+# stacksize 26000, objects larger than 100 bytes in their own segments,
+# string constants to the codesegment, etc. Add -DNOUUCP if desired.
+qnx16_41:
+ @echo 'Making C-Kermit $(CKVER) for QNX 4.1, 16-bit...'
+ $(MAKE) xermit \
+ "LNKFLAGS = -mh -N 26000" "CFLAGS = -Wc,-fpc -Wc,-j -DNOGETUSERSHELL \
+ -Wc,-Ols -Wc,-zdf -Wc,-zc -Wc,-zt100 -mh -DPOSIX -DQNX -DDIRENT \
+ -DNOCYRIL -DNODEBUG -DNOMSEND -DMINIDIAL -DNOXMIT -DNOSCRIPT -DNOSPL \
+ -DNOSETKEY -DNOINITGROUPS -DQNX16 -DPID_T=pid_t $(KFLAGS)"
+
+# QNX Neutrino 2 (pwaechtler@qnx.de) crosscompiled on QNX 4.25.
+# Gets lots of compiler warnings.
+qnx_nto2+:
+ @echo 'Making C-Kermit $(CKVER) for QNX Neutrino 2+ '
+ cc -o wart ckwart.c
+ $(MAKE) xermit \
+ "CC = qcc -Vgcc_ntox86" \
+ "CC2 = qcc -Vgcc_ntox86" \
+ "LNKFLAGS = " \
+ "CFLAGS = -DNEUTRINO -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL \
+ -DNOUUCP -DCK_WREFRESH -DCK_REDIR -DSELECT -DSELECT_H -DCK_RTSCTS \
+ -DNOJC -DNOINITGROUPS -DCK_ANSIC -DPID_T=pid_t -DUNIX -DDIRENT \
+ -DMYREAD -DBSD44ORPOSIX -DSVORPOSIX -DNDGPWNAM $(KFLAGS)" \
+ "LIBS= -lsocket -lncurses "
+
+# QNX 6 (= Neutrino 2.xx) native build (kirussel@cisco.com).
+qnx6:
+ @echo 'Making C-Kermit $(CKVER) for QNX6'
+ $(MAKE) xermit KTARGET=QNX6 \
+ "CFLAGS = -DPOSIX -DCK_POSIX_SIG -DNETPTY -DNOARROWKEYS \
+ -DUSE_TIOCSDTR -DBIGBUFOK -DCKMAXOPEN=100 -DRLOGCODE -DNOREALPATH \
+ -DMAXNAMLEN=48 -DQNX6 -DUSE_TERMIO -DINIT_SPTY \
+ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DDYNAMIC \
+ -DTCPSOCKET -DNOGETUSERSHELL -DCK_REDIR -DSELECT -DSELECT_H \
+ -DCK_RTSCTS -DNOJC -DSVORPOSIX -DBSD44ORPOSIX -DNOUUCP -DCK_ANSIC \
+ $(KFLAGS) -O" \
+ "LIBS= -lsocket -lncurses"
+
+#MINIX/2.0 32 Bit version for intel 386+ running the POSIX-compliant MINIX
+# version 2.0 (The definition of fatal avoids a conflict with a symbol by
+# the same name in the curses library.) It is impossible to compile with
+# network support since Minix does not support Berkeley sockets.
+# Note: use chmem liberally on the compiler passes, make, and the final
+# kermit executable. (3 megabytes of memory for each is sufficient.)
+# From Terry McConnell, Syracuse U, and Will Rose. Will says:
+# The stacks for make and some compiler passes needed to be increased
+# with chmem as follows:
+# make 1MB
+# /usr/lib/em_cemcom.ansi 3MB
+# /usr/lib/em_opt 1MB
+# /usr/lib/i386/cg 1MB
+# /usr/lib/i386/as 1MB
+# The compiler temporary directory was set to /usr/tmp via the TMPDIR
+# environment variable; more than 1MB of temporary space was needed.
+# Kermit itself needs at least 1MB of stack.
+minix20:
+ @echo 'Making C-Kermit $(CKVER) for MINIX 2.0/386...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} EXT=o \
+ "CFLAGS= -wo -DV7 -DMINIX2 -DMINIX -DSIG_V -D_POSIX_SOURCE \
+ -DCKCPU=\\\"i-386\\\" -DNOIKSD -Dfatal=myfatal -DCK_CURSES -DNOLEARN \
+ -DNOSYSLOG -DUSE_MEMCPY -DNOREALPATH $(KFLAGS)" "LIBS= -lcurses"
+
+#MINIX/386 (PC Minix modified by Bruce Evans in Australia for 386 addressing)
+# For MINIX 1.5+ (but < 2.0)
+minix386:
+ @echo 'Making C-Kermit $(CKVER) for MINIX/386...'
+ @echo 'TOTALLY UNTESTED!'
+ $(MAKE) wermit EXT=s KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DV7 -DMINIX -D_POSIX_SOURCE -DNOLEARN $(KFLAGS)"
+
+#MINIX/386 Minix modified by Bruce Evans in Australia to use 386 addressing
+minix386gcc:
+ @echo 'Making C-Kermit $(CKVER) for MINIX/386 with gcc...'
+ @echo 'TOTALLY UNTESTED!'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC=gcc -g -O" "CC2=gcc -g" \
+ "CFLAGS= -DV7 -DMINIX -D_POSIX_SOURCE -DNOLEARN $(KFLAGS)"
+
+#MINIX - 68k version with ACK compiler.
+# If you have trouble compiling or running wart, "touch wart".
+# If it still doesn't work, "touch ckcpro.c".
+# The version configured below has many features removed, including
+# the TRANSMIT, MSEND, HELP, and SCRIPT commands, international
+# character set support, and the entire script programming language.
+# But it does have an interactive command parser.
+# Make sure make(1) has (at least) 100000 chmemory!
+# If you are using the Amsterdam C compiler, you might have to add "-D__ACK__".
+minix68k:
+ @echo 'Making C-Kermit $(CKVER) for MINIX 68k with ACK...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DV7 -DMINIX -D_MINIX -D_POSIX_SOURCE -DNOLEARN \
+ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \
+ -DNOSCRIPT -DNOCSETS -DNOSPL $(KFLAGS) \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V"
+
+#MINIX - 68k version with c68 compiler.
+# If you have trouble compiling or running wart, "touch wart" or
+# "touch ckcpro.c". Compiling ckudia.c (no -DNODIAL!) might fail. :-(
+# Give c68 250000 bytes of stack+heap; make sure make(1) has at least
+# 100000 chmemory. On a 1MB Atari ST this means that the recursive
+# call of make fails due to memory shortage. Try "make -n minixc68 >makeit",
+# followed by ". makeit". Otherwise, as above.
+minixc68:
+ @echo 'Making C-Kermit $(CKVER) for MINIX 68k with c68...'
+ $(MAKE) wermit "CC= cc -c68" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DV7 -DMINIX -D_MINIX -D_POSIX_SOURCE -DNOLEARN \
+ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \
+ -DNOSCRIPT -DNOCSETS -DNOSPL $(KFLAGS) \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V"
+
+#MINIX - 68k version with c68 compiler.
+#A variation on the above that was recently (Sep 95) reported to work.
+minixc68a:
+ @echo 'Making C-Kermit $(CKVER) for MINIX 68k with c68...'
+ $(MAKE) wermit "CC= cc -c68" KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DV7 -DMINIX -D_MINIX -D_POSIX_SOURCE \
+ -DCK_ANSIC -DNODEBUG -DNOTLOG -DMINIDIAL -DEXTEN -DMYCURSES \
+ -DNOSCRIPT -DNOCSETS -DNOSPL -DNOJC -DDIRENT -DNOLEARN \
+ -DNOSETKEY -DNOESCSEQ $(KFLAGS) \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V"
+
+#MIPS Computer Systems with UMIPS RISC/OS 4.52 = AT&T UNIX System V R3.0.
+#Remove -DNOJC if job control can be safely used.
+mips:
+ @echo 'Making C-Kermit $(CKVER) for MIPS RISC/OS...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DMIPS -DDIRENT -DCK_POLL -DNOJC -DNOLEARN -DPID_T=int \
+ -DGID_T=gid_t -DUID_T=uid_t -i -O1500 $(KFLAGS)"
+
+#As above, but with TCP/IP and fullscreen support.
+mipstcpc:
+ @echo 'Making C-Kermit $(CKVER) for MIPS RISC/OS...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DMIPS -DDIRENT -DCK_POLL -DNOJC \
+ -DTCPSOCKET -DCK_CURSES -I/usr/include/bsd \
+ -DPID_T=int -DGID_T=gid_t -DUID_T=uid_t -i -O1500 $(KFLAGS)" \
+ "LIBS = -lcurses -lbsd"
+
+#Motorola Delta System V/68 R3, signal() is void rather than int.
+#Uses dirent.h and Honey DanBer uucp. Supports TCP/IP.
+#After building, use "mcs -d" to reduce size of the executable program.
+sv68r3:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DSV68 -DDIRENT -DHDBUUCP -DNO_DNS_SRV -DTCPSOCKET \
+ -DNOUNICODE -DNOLEARN -DUSE_MEMCPY $(KFLAGS) -O" "LNKFLAGS ="
+
+#Motorola Delta System V/68 R3V5, signal() is void rather than int.
+#Uses dirent.h and Honey DanBer UUCP. Supports TCP/IP.
+#After building, use "mcs -d" to reduce size of the executable program.
+sv68r3v5:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3V5'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DSV68 -DDIRENT -DHDBUUCP -DNO_DNS_SRV -DUSE_MEMCPY \
+ -DTCPSOCKET -DINADDRX -DNOUNICODE -DFNFLOAT -DNOLEARN $(KFLAGS) -O" \
+ "LNKFLAGS =" "LIBS = -linet -lm"
+
+#Motorola MVME147 System V/68 R3 V5.1. Requires gcc 2.1 to compile.
+#After building, use "mcs -d" to reduce size of the executable program.
+sv68r3v51:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3V5.1'
+ $(MAKE) wermit "CC=gcc-delta" "CC2=gcc-delta" \
+ KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNODEBUG -DNO_DNS_SRV -DNOLEARN \
+ -DNOUNICODE -DFNFLOAT -DSV68 -DUSE_MEMCPY $(KFLAGS) \
+ -O2 -v -ftraditional" \
+ "LNKFLAGS = -s -v" "LIBS = -lm881 -lm"
+
+#Motorola MVME147 System V/68 R3V6. derived from Motorola Delta System R3V5.
+#Checked on larger Motorola System V/68 R3V6 (with NSE Network Services Ext.)
+#After building, use "strip" to reduce size of the executable program.
+# "LIBS = -lnsl" removed in C-Kermit 6.1 - put back if needed.
+# "LIBS = lm" added in 7.1/8.0 for floating-point math.
+# ckuusr.c clobbers the optimizer.
+sv68r3v6:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3V6'
+ $(MAKE) ckuusr.$(EXT) KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSV68R3V6 -DDIRENT -DHDBUUCP -DNOLOGIN -DNOINITGROUPS \
+ -DNOSYMLINK -DNOREDIRECT -DNOGFTIMER -DTCPSOCKET -DDCLGETCWD -DSV68 \
+ -DNO_DNS_SRV -DNOUNICODE -DFNFLOAT -DSELECT -DUSE_MEMCPY $(KFLAGS)"
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSV68R3V6 -DDIRENT -DHDBUUCP -DNOLOGIN -DNOINITGROUPS \
+ -DNOSYMLINK -DNOREDIRECT -DNOGFTIMER -DTCPSOCKET -DDCLGETCWD -DSV68 \
+ -DNO_DNS_SRV -DNOUNICODE -DFNFLOAT -DSELECT -DUSE_MEMCPY $(KFLAGS)" \
+ "LNKFLAGS =" "LIBS = -lm"
+
+#Motorola Delta System V/88 R32, signal() is void rather than int.
+#Uses dirent.h and Honey DanBer uucp. Needs <sys/utime.h> for setting
+#file dates. Supports TCP/IP.
+#After building, use "mcs -d" to reduce size of the executable program.
+sv88r32:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/88 R32...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -DSV88R32 -DDIRENT -DHDBUUCP -DTCPSOCKET \
+ -DSYSUTIMEH -DCK_CURSES -DNOGETUSERSHELL -DGTODONEARG $(KFLAGS) -O" \
+ "LIBS= -lcurses -lresolv" "LNKFLAGS = -s"
+
+#Motorola Delta System V/88 R40. Has <sys/termiox.h>, regular Berkeley
+#sockets library, i.e. in.h and inet.h are not misplaced in sys (rather than
+#netinet and arpa, respectively). Uses ANSI C constructs, advisory file
+#locking on devices, etc. curses support added. Reportedly, the
+#/usr/include/sys/vnode.h file has a bug which must be fixed before this
+#makefile entry can work correctly. The "if DEBUG" directive at about line
+#320 must be changed to "ifdef DEBUG" (Reportedly, this was fixed in
+#in System V/88 R4.3).
+#After building, use "mcs -d" to reduce size of the executable program.
+sv88r40:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/88 R40...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DMOTSV88R4 -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL -DGTODONEARG -DFNFLOAT \
+ $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -lresolv -lm" "LNKFLAGS = -s"
+
+#As above but without the floating-point math library.
+sv88r40nm:
+ @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/88 R40...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS = -O -DSVR4 -DMOTSV88R4 -DDIRENT -DHDBUUCP -DSTERMIOX \
+ -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL -DGTODONEARG $(KFLAGS)" \
+ "LIBS= -lsocket -lnsl -lcurses -lresolv" "LNKFLAGS = -s"
+
+#As above but with floating-point math library support \ffp...() functions
+#and S-Expressions.
+
+#Olivetti X/OS R2.3, 3.x.
+#NOTES:
+# . If you build the executable on 2.x X/OS, it will also run on 3.x.
+# . If you build it on 3.x X/OS, it will NOT run on 2.x.
+# . Kermit can run with no privileges unless the uucp lines are protected,
+# in which case kermit must be owned by uucp with suid bit set:
+# chown uucp kermit ; chmod 4111 kermit.
+xos23:
+ @echo 'Making C-Kermit $(CKVER) for Olivetti X/OS...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ 'CFLAGS=-OLM -DOXOS -DTCPSOCKET -DHDBUUCP $(KFLAGS)' \
+ "LIBS=" "LNKFLAGS="
+
+#As above, but with curses.
+xos23c:
+ @echo 'Making C-Kermit $(CKVER) for Olivetti X/OS with curses...'
+ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+ 'CFLAGS=-OLM -DOXOS -DTCPSOCKET -DHDBUUCP -DCK_CURSES $(KFLAGS)' \
+ "LIBS=-lcurses" "LNKFLAGS="
+
+ckuuid:
+ @echo 'building C-Kermit $(CKVER) set-UID/set-GID test programs'
+ $(CC) -DANYBSD -DSAVEDUID -o ckuuid1 ckuuid.c
+ $(CC) -DANYBSD -o ckuuid2 ckuuid.c
+ $(CC) -DANYBSD -DNOSETREU -o ckuuid3 ckuuid.c
+ $(CC) -DANYBSD -DSETEUID -DNOSETREU -o ckuuid4 ckuuid.c
+ $(CC) -o ckuuid5 ckuuid.c
+ @echo 'Read the top of ckuuid.c for directions...for testing'
+ @echo 'you must make these programs setuid and setgid'
+
+############################################################################
+# A N T I Q U I T I E S
+#
+# The following are antique targets from C-Kermit 5A or earlier. They have
+# not been updated or tested in years. Most of them will need recent features
+# disabled, usually with some combination of -DNOUNICODE, -DNOIKSD, -DNOANSI,
+# -DNOCKGHNLHOST, -DNO_DNS_SRV, -DNOREDIRECT, -DNOREALPATH, -DNOCURSES, etc.
+# They are also missing the KTARGET=$${KTARGET:-$(@)} business.
+# For details see ckuins.txt and ckccfg.txt.
+#
+############################################################################
+
+#Berkeley Unix 2.8, 2.9 for PDP-11s with I&D space, maybe also Ultrix-11???
+#C-Kermit(5A) is simply too large (even turning off almost every feature
+#available) to run without both I&D space plus overlays. The old comment
+#suggested running 'pcc' but that won't help. Changing 'cc' to 'ckustr.sed'
+#will cause a string extraction to be done, saving D space by moving strings
+#to a file.
+bsd29:
+ @echo Making C-Kermit $(CKVER) for 2.8 or 2.9BSD.
+ @echo Read the makefile if you have trouble with this...
+ $(MAKE) ovwermit \
+ "CFLAGS= -DBSD29 -DNODEBUG -DNOTLOG -DNOCSETS -DNOHELP \
+ -DNOSCRIPT -DNOSPL -DNOXMIT -DNODIAL $(KFLAGS)" \
+ "LNKFLAGS= -i -lndir" "CC= cc " "CC2= cc"
+
+bsd210:
+ @echo Please use ckubs2.mak to build C-Kermit $(CKVER) for 2.10BSD.
+
+bsd211:
+ @echo Please use ckubs2.mak to build C-Kermit $(CKVER) for 2.11BSD.
+
+#Charles River Data Systems Universe with UNOS Version 9.2
+crds:
+ @echo 'Making C-Kermit $(CKVER) for Charles River Data Systems...'
+ make xermit \
+ "CFLAGS = -DATTSV -DNOANSI -DDIRENT -DLONGFN -DTCPSOCKET \
+ -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DNOSETREU \
+ -Dsuspend=ksuspend $(KFLAGS) -O" "LNKFLAGS ="
+
+#Microport SV/AT for IBM PC/AT 286 and clones, System V R2.
+#The -O flag may fail on some modules (like ckuus2.c), in which case you
+#should compile them by hand, omitting the -O. If you get "hash table
+#overflow", try adding -DNODEBUG.
+#Also, reportedly this compiles better with gcc than with cc.
+mpsysv:
+ @echo 'Making C-Kermit $(CKVER) for Microport SV/AT 286...'
+ $(MAKE) wermit \
+ "CFLAGS= -DATTSV -DNOLEARN $(KFLAGS) -O -Ml" "LNKFLAGS = -Ml"
+
+#Microsoft "Xenix/286" e.g. for IBM PC/AT
+xenix:
+ @echo 'Making C-Kermit $(CKVER) for Xenix/286'
+ $(MAKE) wermit \
+ "CFLAGS= -DXENIX -DNOFILEH -DNOLEARN $(KFLAGS) -Dunix -F 3000 -i" \
+ "LNKFLAGS = -F 3000 -i"
+
+#PC/IX, Interactive Corp System III for IBM PC/XT
+pcix:
+ @echo 'Making C-Kermit $(CKVER) for PC/IX...'
+ $(MAKE) wermit \
+ "CFLAGS= -DPCIX -DISIII -DNOLEARN $(KFLAGS) \
+ -Dsdata=sdatax -O -i" "LNKFLAGS = -i"
+
+#Integrated Solutions Inc V8S VME 68020
+isi:
+ @echo Making C-Kermit $(CKVER) for 4.2BSD on ISI...
+ $(MAKE) wermit "CC = cc" \
+ "CFLAGS= -DBSD4 -DTCPSOCKET -DINADDRX -DDCLPOPEN -DDEBUG -DNOSETREU \
+ -DCK_CURSES -DNOLEARN $(KFLAGS)" "LIBS = -lcurses -ltermcap"
+
+#Interactive Corp version of AT&T System III
+#is3: (very old, probably not sufficient for 5A or later)
+# @echo 'Making C-Kermit $(CKVER) for Interactive System III...'
+# make wermit "CFLAGS = -DISIII -Ddata=datax -O -i" "LNKFLAGS = -i"
+#The following should work, use it if you don't have gcc.
+#Use is3gcc if you have gcc.
+is3:
+ @echo 'Making C-Kermit $(CKVER) for Interactive System III...'
+ $(MAKE) wermit \
+ "CFLAGS= -DISIII $(KFLAGS) -Ddata=datax -DNAP -DHDBUUCP
+ -DLOCK_DIR=\"/usr/spool/uucp\" -DSIGTYP=void -O -i" "LNKFLAGS = -i"
+
+#Interactive UNIX System V R3, no network support. Uses <dirent.h> and Honey
+#DanBer UUCP. If this entry does not compile correctly, try any or all of the
+#following. These suggestions also apply more or less to the other is5r3xxx
+#entries that follow this one.
+# . Remove the UID_T and GID_T definitions, or change them as required.
+# . Change -DDIRENT to -DSDIRENT.
+# . Add -DSIGTYP=void.
+# . Remove -g from LNKFLAGS.
+# . Add -DNOANSI to remove compiler complaints about ANSI C constructions
+# . Add other -DNOxxx's to save space (e.g. -DNOCSETS)
+# See the next few makefile entries for related examples.
+# Also see sys5r32is for making a portable i386 SVR3 binary.
+is5r3:
+ @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix or later...'
+ @echo 'If this does not work please read the makefile entry.'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -g -DNOCSETS -DNOREALPATH \
+ -DUID_T=ushort -DGID_T=ushort -DI386IX $(KFLAGS)" \
+ "LNKFLAGS = -g"
+
+#Interactive Corp System System V R3 with gcc
+is3gcc:
+ @echo 'Making C-Kermit $(CKVER) for Interactive System V R3 / gcc...'
+ $(MAKE) wermit CC=gcc CC2=gcc \
+ 'CFLAGS = -D_SYSV3 -DISIII -Ddata=datax -DNAP -DHDBUUCP -DNOREALPATH \
+ -DLOCK_DIR=\"/usr/spool/uucp\" -DSIGTYP=void -O' "LNKFLAGS ="
+
+#Interactive UNIX System V R3, POSIX variant. Untested.
+#Uses dirent.h and Honey DanBer uucp. Read comments in is5r3 entry.
+is5r3p:
+ @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix or later...'
+ $(MAKE) wermit \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -g -DNOCSETS -DNOREALPATH \
+ -DI386IX -DPOSIX $(KFLAGS)" "LNKFLAGS=" "LIBS=-lcposix"
+
+#Interactive UNIX SVR3 2.2.1, job control, curses, no net, gcc.
+is5r3gcc:
+ $(MAKE) wermit CC=gcc CC2=gcc \
+ "CFLAGS=-g -posix -DSVR3 -DDIRENT -DNOREALPATH \
+ -DHDBUUCP -O -DNOCSETS -DI386IX -DSVR3JC -DCK_CURSES \
+ $(KFLAGS)" LNKFLAGS="-posix" LIBS="-lcurses -lc_s"
+
+#Interactive UNIX System V R3 with TCP/IP network support.
+#Needs -linet for net functions. signal() is void rather than int.
+#Uses dirent.h and Honey DanBer uucp. Read comments in is5r3 entry.
+#Also see is5r3net2 if you have trouble with this entry.
+is5r3net:
+ @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix...'
+ @echo 'If this does not work please read the makefile entry.'
+ $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET -DNOREALPATH \
+ -DI386IX $(KFLAGS) -O" "LIBS = -linet"
+
+is5r3netgcc:
+ $(MAKE) is5r3net CC=gcc CC2=gcc
+
+#Interactive UNIX System V R3, no job control, signal() void rather than int.
+#Uses dirent.h and Honey DanBer uucp. Needs -linet for net functions.
+#Read comments in is5r3 entry. Use this entry if is5r3net fails.
+#Saves some space by stripping (-s) and using shared library (-lc_s).
+is5r3net2:
+ @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix...'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET -DNOJC -DNOREALPATH \
+ -DSIGTYP=void -DNOANSI -DI386IX $(KFLAGS) -O" \
+ "LNKFLAGS= -s" "LIBS = -linet -lc_s"
+
+#Interactive UNIX System V R3 (version 2.2 or later) with job control & curses.
+#Uses dirent.h and Honey DanBer UUCP.
+is5r3jc:
+ @echo 'Making C-Kermit $(CKVER) for Interactive Unix 2.2 or later...'
+ $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \
+ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES \
+ -DPOSIX_JC -DCK_REDIR -DCK_POLL -DDCLGETCWD \
+ $(KFLAGS)" "LIBS=-lcurses -lc_s -linet"
+
+is5r3jcgcc:
+ $(MAKE) is5r3jc CC="gcc -DCK_ANSILIBS -DDCGPWNAM -O4" CC2=gcc \
+ KFLAGS="$(KFLAGS)" LNKFLAGS="$(LNKFLAGS)"
+
+#Sunsoft/Interactive UNIX System V R3 (version 2.2 or later)
+#with job control, curses, and TCP/IP networking.
+#Uses dirent.h and Honey DanBer UUCP.
+is5r3netjc:
+ @echo 'Making C-Kermit $(CKVER) for Interactive Unix 2.2 or later...'
+ $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \
+ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES \
+ -DPOSIX_JC -DCK_REDIR -DTCPSOCKET -DSELECT \
+ $(KFLAGS)" "LIBS=-linet -lcurses -lc_s"
+
+is5r3netjcgcc:
+ $(MAKE) is5r3netjc CC="gcc -DCK_ANSILIBS -DDCGPWNAM -O4" CC2=gcc \
+ KFLAGS="$(KFLAGS)" LNKFLAGS="$(LNKFLAGS)"
+
+#Masscomp System III
+rtu:
+ @echo 'Making C-Kermit $(CKVER) for Masscomp RTU System III...'
+ $(MAKE) wermit \
+ "CFLAGS= -UFIONREAD -DATTSV $(KFLAGS) -O" "LNKFLAGS =" "LIBS= -ljobs"
+
+#Masscomp/Concurrent RTU 4.0 or later, Berkeley environment.
+#Includes <ndir.h> = /usr/include/ndir.h
+#Note "LIBS = -lndir" might not be necessary because of "ucb make".
+rtubsd:
+ @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.1A...'
+ ucb make wermit \
+ "CFLAGS= -DBSD4 -DRTU -DNDIR -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \
+ "LIBS = -lndir"
+
+#Masscomp/Concurrent RTU 4.0 or later, same as above,
+#Includes "usr/lib/ndir.h"
+#Note "LIBS = -lndir" might not be necessary because of "ucb make".
+rtubsd2:
+ @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.1A...'
+ ucb make wermit \
+ "CFLAGS= -DBSD4 -DRTU -DXNDIR -DHDBUUCP $(KFLAGS)" \
+ "LIBS = -lndir"
+
+#Masscomp/Concurrent RTU 4.0 or later, same as above,
+#Includes <sys/ndir.h>
+#Note "LIBS = -lndir" might not be necessary because of "ucb make".
+rtubsd3:
+ @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.x BSD...'
+ ucb make wermit "CFLAGS= -DBSD4 -DRTU -DHDBUUCP $(KFLAGS)" \
+ "LIBS = -lndir"
+
+#Masscomp/Concurrent RTU 4.0 or later, System V R2, using <dirent.h>.
+#In case of problems, add back the -DRTU switch.
+#In case -DTCPSOCKET gives trouble, remove it.
+rtus5:
+ @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.x...'
+ $(MAKE) wermit \
+ "CFLAGS= -DATTSV -DHDBUUCP -DDIRENT -DTCPSOCKET $(KFLAGS)"
+
+#Masscomp/Concurrent RTU 4.x, System V R3, using <dirent.h>.
+#Use this one if rtus5 gives warnings about pointer type mismatches.
+#In case of problems, add back the -DRTU switch.
+rtus5r3:
+ @echo 'Making C-Kermit $(CKVER) for Masscomp RTU Sys V R3...'
+ $(MAKE) wermit "CFLAGS= -DSVR3 -DHDBUUCP -DDIRENT $(KFLAGS)"
+
+#DEC Pro-3xx with Pro/Venix V1.0 or V1.1
+# Requires code-mapping on non-I&D-space 11/23 processor, plus some
+# fiddling to get interrupt targets into resident code section.
+# This almost certainly doesn't work any more.
+provx1:
+ @echo 'Making C-Kermit $(CKVER) for DEC Pro-3xx, Pro/Venix 1.x...'
+ $(MAKE) wart "CFLAGS= -DPROVX1 $(KFLAGS)" "LNKFLAGS= "
+ $(MAKE) wermit "CFLAGS = -DPROVX1 -DNOFILEH -md780" \
+ "LNKFLAGS= -u _sleep -lc -md780"
+
+#Nixdorf Targon/31.
+#AT&T UNIX System V R3, signal() is void rather than int.
+#Uses dirent.h without Honey DanBer uucp.
+t31tos40x:
+ @echo 'Making C-Kermit $(CKVER) for Targon/31 with TOS 4.0.xx...'
+ $(MAKE) wermit \
+ "CFLAGS= -DSVR3 -DDIRENT $(KFLAGS) -O" \
+ "LNKFLAGS="
+
+#NCR Tower 1632, OS 1.02
+tower1:
+ @echo 'Making C-Kermit $(CKVER) for NCR Tower 1632, OS 1.02...'
+ $(MAKE) wermit "CFLAGS= -DTOWER1 $(KFLAGS)"
+
+#NCR Tower 32, OS Release 1.xx.xx
+tower32-1:
+ @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 Rel 1 System V R2...'
+ @echo 'Add KFLAGS=-DISDIRBUG if you get errors about S_ISREG/S_ISDIR.'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV $(KFLAGS) -O" "LNKFLAGS = -n"
+
+#NCR Tower 32, OS Release 2.xx.xx
+tower32-2:
+ @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 Rel 2 System V R2...'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DHDBUUCP $(KFLAGS) -O2" \
+ "LNKFLAGS = -n"
+
+#NCR Tower 32, OS Releases based on System V R3
+#Don't add -DNAP (doesn't work right) or -DRDCHK (not available in libc).
+tower32:
+ @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 System V R3...'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNOSYSIOCTLH $(KFLAGS) \
+ -DUID_T=ushort -DGID_T=ushort -O1"
+
+#NCR Tower 32, OS Releases based on System V R3
+tower32g:
+ @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 System V R3, gcc...'
+ $(MAKE) wermit "CC = gcc" \
+ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNOSYSIOCTLH $(KFLAGS) \
+ DUID_T=ushort -DGID_T=ushort -O -fstrength-reduce -fomit-frame-pointer"
+
+#Fortune 32:16, For:Pro 1.8 (mostly like 4.1bsd)
+ft18:
+ @echo 'Making C-Kermit $(CKVER) for Fortune 32:16 For:Pro 1.8...'
+ $(MAKE) wermit \
+ "CFLAGS= -DNODEBUG -DBSD4 -DFT18 -DNOFILEH $(KFLAGS) \
+ -DPID_T=short"
+
+#Fortune 32:16, For:Pro 2.1 (mostly like 4.1bsd).
+#The modules that break the optimizer are compiled separately.
+ft21:
+ @echo 'Making C-Kermit $(CKVER) for Fortune 32:16 For:Pro 2.1...'
+ $(MAKE) ckuusx.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+ -SYM 800 -DCK_CURSES $(KFLAGS) -DPID_T=short" \
+ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet"
+ $(MAKE) ckuxla.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+ -SYM 800 -DCK_CURSES $(KFLAGS) -DPID_T=short" \
+ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet"
+ $(MAKE) ckudia.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+ -SYM 800 -DCK_CURSES $(KFLAGS) -DPID_T=short" \
+ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet"
+ $(MAKE) wermit \
+ "CFLAGS= -O -DNODEBUG -DBSD4 -DFT21 -DNOFILEH -SYM 800 \
+ -DCK_CURSES $(KFLAGS) -DPID_T=short" \
+ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet"
+
+#Valid Scaldstar
+#Berkeleyish, but need to change some variable names.
+valid:
+ @echo 'Making C-Kermit $(CKVER) for Valid Scaldstar...'
+ $(MAKE) wermit \
+ "CFLAGS= -DBSD4 -DNODEBUG -DNOTLOG -Dcc=ccx -DFREAD=1 $(KFLAGS)"
+
+#IBM IX/370 on IBM 370 Series mainframes
+#Mostly like sys3, but should buffer packets.
+ix370:
+ @echo 'Making C-Kermit $(CKVER) for IBM IX/370...'
+ $(MAKE) wermit "CFLAGS = -DIX370 -DATTSV $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i"
+
+#Amdahl UTS 2.4 on IBM 370 series compatible mainframes.
+#Mostly like V7, but can't do initrawq() buffer peeking.
+uts24:
+ @echo 'Making C-Kermit $(CKVER) for Amdahl UTS 2.4...'
+ $(MAKE) wermit "CFLAGS=-DV7 -DPROCNAME=\\\"$(PROC)\\\" \
+ -DUTS24 -DBOOTNAME=\\\"$(BOOTFILE)\\\" -DNPROCNAME=\\\"$(NPROC)\\\" \
+ -DNPTYPE=$(NPTYPE) $(DIRECT) $(KFLAGS)"
+
+#Amdahl UTSV UNIX System V = System V R2 or earlier.
+utsv:
+ @echo 'Making C-Kermit $(CKVER) for Amdahl UTSV...'
+ $(MAKE) wermit \
+ "CFLAGS = -DUTSV $(KFLAGS) -i -O" "LNKFLAGS = -i"
+
+#Amdahl UTSV UNIX System V = System V R2 or earlier, with TCP sockets library.
+utsvtcp:
+ @echo 'Making C-Kermit $(CKVER) for Amdahl UTSV w/tcp...'
+ $(MAKE) wermit "CFLAGS = \
+ -DTCPSOCKET -DUTSV $(KFLAGS) -i -O" "LNKFLAGS = -i" \
+ "LIBS = -lsocket"
+
+#BBN C/70 with IOS 2.0
+#Mostly Berkeley-like, but with some ATTisms
+c70:
+ @echo 'Making C-Kermit $(CKVER) for BBN C/70 IOS 2.0...'
+ $(MAKE) wermit "CFLAGS= -DBSD4 -DC70 $(KFLAGS)"
+
+#Zilog ZEUS 3.21
+zilog:
+ @echo 'Making C-Kermit $(CKVER) for Zilog Zeus 3.21...'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DZILOG -DNODEBUG $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i -lpw"
+
+#Whitechapel MG-1 Genix 1.3
+white:
+ @echo 'Making C-Kermit $(CKVER) for Whitechapel MG-1 Genix 1.3...'
+ @touch ckcpro.c
+ $(MAKE) wermit "CFLAGS= -DBSD4 -Dzkself()=0 $(KFLAGS)"
+
+#Pixel 1000
+pixel:
+ @echo 'Making C-Kermit $(CKVER) for Pixel 1000...'
+ $(MAKE) wermit "CFLAGS= -DBSD4 -Dzkself()=0 $(KFLAGS)"
+
+ptx:
+ $(MAKE) "MAKE=$(MAKE)" dynixptx12
+
+#CDC VX/VE 5.2.1
+vxve:
+ @echo 'Making C-Kermit $(CKVER) for CDC VX/VE 5.2.1...'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DVXVE -DNODEBUG -DNOTLOG $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i"
+
+#DIAB DS90 or LUXOR ABC-9000 with pre-5.2 DNIX. Sys V with nap() and rdchk().
+# nd = no opendir(), readdir(), closedir(), etc.
+# Some of the modules fail to compile with -O.
+dnixnd:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with very old DNIX 5.2.'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DNAP -DRDCHK -DDCLPOPEN \
+ -U__STDC__ $(KFLAGS)"
+
+#DIAB DS90 with DNIX 5.2. Sys V with nap() and rdchk().
+# This one has opendir(), readdir(), closedir(), etc.
+# Some of the modules fail to compile with -O.
+dnix:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with old DNIX 5.2...'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DNAP -DRDCHK -DDIRENT \
+ -U__STDC__ $(KFLAGS)"
+
+#DIAB DS90 with DNIX 5.2. Sys V with nap() and rdchk().
+# As above, but with curses and TCP/IP.
+# You might get complaints about redefinition of O_RDONLY, etc, because
+# of bugs in the DNIX header files, which can be fixed by adding #ifndef...
+# around the offending definitions in the header files.
+dnixnetc:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with old DNIX 5.2...'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DNAP -DRDCHK -DDIRENT \
+ -DTCPSOCKET -DCK_CURSES -I/usr/include/bsd -U__STDC__ $(KFLAGS)" \
+ "LIBS = -ln -lcurses"
+
+#DIAB DS90 with DNIX 5.3 or later, with HDB UUCP, nap() and rdchk().
+dnix5r3:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...'
+ @echo 'with Honey DanBer UUCP'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DHDBUUCP -DNAP -DRDCHK -DDIRENT \
+ -DCK_CURSES -DRENAME $(KFLAGS) -O" "LIBS= -lcurses"
+
+#DIAB DS90 with DNIX 5.3 or later, with HDB UUCP, nap() and rdchk() + TCP/IP
+dnix5r3net:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...'
+ @echo 'with Honey DanBer UUCP and TCP/IP'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DHDBUUCP -DNAP -DRDCHK -DDIRENT \
+ -DTCPSOCKET -DCK_CURSES -DRENAME $(KFLAGS) -O \
+ -I/usr/include/bsd" "LIBS = -ln -lcurses"
+
+#DIAB DS90 with DNIX 5.3 2.2 or later, with HDB UUCP, nap() and rdchk(),
+#ANSI C compilation and libraries.
+#Note that for DNIX 5.3 2.2 you have to correct a bug in /usr/include/stdlib.h:
+#change "extern void free(char *str);"
+#to "extern void free(void *str);"
+#NOTE: This bug is reportedly fixed in DNIX 5.3 2.2.1.
+#Should you get fatal errors caused by harmless pointer-type mismatches,
+#like between signed and unsigned char, just remove -X7.
+dnix5r3ansi:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...'
+ @echo 'with ANSI C Honey DanBer UUCP'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DDIAB -DHDBUUCP -DNAP -DRDCHK -DDIRENT \
+ -DCK_ANSILIBS -DCK_CURSES -DRENAME -O -X7 -X9 $(KFLAGS)" \
+ "LIBS= -lcurses"
+
+#DIAB DS90 with DNIX 5.3 2.2 or later, with HDB UUCP, nap() and rdchk(),
+# + TCP/IP, ANSI C compilation and libraries.
+#Should you get fatal errors caused by harmless pointer-type mismatches,
+#like between signed and unsigned char, just remove -X7.
+dnix5r3ansinet:
+ @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...'
+ @echo 'with ANSI C Honey DanBer UUCP'
+ $(MAKE) wermit \
+ "CFLAGS = -DSVR3 -DDIAB -DHDBUUCP -DNAP -DRDCHK -DDIRENT \
+ -DTCPSOCKET -DCK_ANSILIBS -DCK_CURSES -DRENAME -O -X7 -X9 $(KFLAGS) \
+ -I/usr/include/bsd" "LIBS= -ln -lcurses"
+
+#Ridge 32 with ROS 3.2
+ridge32:
+ @echo 'Making C-Kermit $(CKVER) Ridge 32 ROS 3.2'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DNOFILEH -DNODEBUG -DNOTLOG $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i"
+
+#Altos 486, 586, or 986 with Xenix 3.0
+altos:
+ @echo 'Making C-Kermit $(CKVER) for Altos x86 with Xenix 3.0...'
+ $(MAKE) wermit \
+ "CFLAGS= -DATTSV -DA986 -DNODEBUG -DNOTLOG $(KFLAGS) -i -O" \
+ "LNKFLAGS= -i"
+
+#Altos 986 with Xenix 3.0, as above, but command-line only, minimal size.
+#For systems with small memories. It might also be necessary to chop certain
+#modules up into smaller pieces, e.g. ckuus3-6, because of symbol table
+#overflow. If this makefile is too big or complex for the Altos, compile
+#and link by hand or write shell scripts.
+altosc:
+ @echo 'Making C-Kermit $(CKVER) for Altos x86 Xenix 3.0, remote...'
+ $(MAKE) wermit \
+ "CFLAGS= -DATTSV -DA986 -DNODEBUG -DNOTLOG -DNOSCRIPT -DNODIAL \
+ -DNOCSETS -DNOANSI -DNOMSEND -DNOSPL -DNOICP $(KFLAGS) -Mm -O" \
+ "LNKFLAGS= -Mm -s"
+
+#Altos 986 with Xenix 3.0, as above, but interactive only, minimal size.
+altosi:
+ @echo 'Making C-Kermit $(CKVER) for Altos x86 Xenix 3.0, local...'
+ $(MAKE) wermit \
+ "CFLAGS= -DATTSV -DA986 -DNODEBUG -DNOTLOG -DNOSCRIPT -DNODIAL \
+ -DNOCSETS -DNOANSI -DNOMSEND -DNOSPL -DNOCMDL -DNOFRILLS -DNOHELP \
+ -DNOSETKEY $(KFLAGS) -Mm -O" "LNKFLAGS= -Mm -s"
+
+# Altos ACS68000 68000 System, UNIX System 3 Release 2, 512k memory.
+# also needs getcwd() external function; see ckuins.txt file.
+# also, sys/types.h needed modifying:
+# #ifdef __SYS_TYPES_H__, #define ..., #endif
+# also, ckuus2.c MUST be compiled NOOPT else symbol table is destroyed!
+# Submission by Robert Weiner/Programming Plus, rweiner@progplus.com.
+#
+altos3:
+ @echo 'Making C-Kermit $(CKVER) for Altos ACS68k UNIX System III'
+ $(MAKE) ckuus2.$(EXT) "CFLAGS = -DATTSV -DNOCSETS -DNOSETKEY -DNOJC \
+ -DNODIAL -DDCLPOPEN -DNOSCRIPT -DNOHELP $(KFLAGS) -i"
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -DNOCSETS -DNOSETKEY -DNOJC \
+ -DNODIAL -DDCLPOPEN -DNOSCRIPT -DNOHELP $(KFLAGS) -i -O" \
+ "LNKFLAGS = -i" "LIBS = getcwd.$(EXT)"
+
+#MINIX - Original PC version with 64K+64K limit.
+# Reportedly, the linker (asld) can run out of space while linking. The only
+# way around this is to make a copy of libc.a from which all modules that are
+# not used by Kermit are removed. If you have trouble compiling or running
+# wart, "touch wart". If that doesn't help, "touch ckcpro.c".
+# The version configured below has no interactive command parser.
+# If you can build this version successfully, maybe there will be room for
+# a minimal interactive command parser too; try replacing -DNOICP with
+# -DNOSPL, plus every other -DNOxxx flag there is, except for -DNOICP
+# (see ckccfg.txt).
+minix:
+ @echo 'Making C-Kermit $(CKVER) for MINIX, no command parser...'
+ @echo 'TOTALLY UNTESTED!'
+ $(MAKE) wermit EXT=s \
+ "CFLAGS= -DV7 -DMINIX -i -D_MINIX -D_POSIX_SOURCE \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V \
+ -DNOXMIT -DNOMSEND -DNOFRILLS -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \
+ -DNOSCRIPT -DNOCSETS -DNOICP -DNOSETKEY $(KFLAGS)" \
+ "LNKFLAGS= -i -T"
+
+#MINIX - PC version with 64K+64K limit, new (as yet unreleased) ACK 2.0 beta C
+#compiler, which outputs .o object files, rather than .s. But 'make' still
+#expects .s files, so must be patched to use .o. Tested on Minix 1.5.10.
+minix15:
+ @echo 'Making C-Kermit $(CKVER) for MINIX (new ACK 2.0 compiler),'
+ @echo 'no command parser... TOTALLY UNTESTED!'
+ $(MAKE) wermit \
+ "CFLAGS= -DV7 -DMINIX -i -D_MINIX -D_POSIX_SOURCE \
+ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V -DNODIAL \
+ -DNOHELP -DNODEBUG -DNOTLOG -DNOSCRIPT -DNOCSETS -DNOICP $(KFLAGS)" \
+ "LNKFLAGS= -i -T"
+
+#MINIX3 - MINIX 3.0 (no VM) - May-Aug 2005 (not sure if this ever worked...)
+minix3:
+ @echo 'Making C-Kermit $(CKVER) for MINIX3...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DPOSIX -DNOUUCP -DNOLEARN $(KFLAGS) -DMINIX2 \
+ -DMINIX3 -DNO_PARAM_H -DNOSYSLOG -DNOGETUSERSHELL \
+ -DNOINITGROUPS -DNOFTRUNCATE -DNOARROWKEYS -DDNOREALPATH \
+ -DTCPSOCKET -DNOTIMEZONE -DNOFTP -DNO_DNS_SRV -O"
+
+#MINIX315 - MINIX 3 1.5 - January 2010
+minix315:
+ @echo 'Making C-Kermit $(CKVER) for Minix 3 1.5...'
+ $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+ "CFLAGS= -DMINIX315 -DPOSIX -DNOUUCP -DNOJC -DNOLEARN $(KFLAGS) \
+ -DHAVE_OPENPTY -DNO_PARAM_H -DNOSYSLOG -DNOGETUSERSHELL \
+ -DSYSTIMEH -DNOINITGROUPS -DNOFTRUNCATE -DNOARROWKEYS -DNOREALPATH \
+ -DTCPSOCKET -DNOTIMEZONE -DNO_DNS_SRV -DNOFTP -O"
+
+#PFU Compact A Series UNIX System V R3, SX/A TISP V10/L50 (Japan)
+#Maybe the -i link option should be removed?
+sxae50:
+ @echo 'Making C-Kermit $(CKVER) for PFU SX/A V10/L50...'
+ $(MAKE) xermit \
+ "CFLAGS= -DSVR3 -DDIRENT -DsxaE50 -DTCPSOCKET $(KFLAGS) -i -O" \
+ "LNKFLAGS= "
+
+#Tektronix 6130, 4319, 4301, etc, with UTek OS, /usr/spool/uucp/LCK./...
+#The models that support hardware flow control.
+utek:
+ @echo 'Making C-Kermit $(CKVER) for 4.2BSD/UTek, hardware flow control'
+ $(MAKE) wermit \
+ "CFLAGS= -O -DLCKDIR -DBSD4 -DTCPSOCKET \
+ -DUTEK -DDCLPOPEN -DLOCK_DIR=\\\"/usr/spool/uucp/LCK.\\\" \
+ -DTRMBUFL=2048 -DCK_DTRCTS $(KFLAGS)"
+
+#Tektronix 4315, 4316, 4317 with UTek OS, /usr/spool/uucp/LCK./...
+#The models that do not fully support hardware flow control.
+uteknohwfc:
+ @echo 'Making C-Kermit $(CKVER) for 4.2BSD/UTek, no h/w flow control'
+ $(MAKE) wermit \
+ "CFLAGS= -O -DLCKDIR -DBSD4 -DTCPSOCKET \
+ -DUTEK -DDCLPOPEN -DLOCK_DIR=\\\"/usr/spool/uucp/LCK.\\\" \
+ -DTRMBUFL=2048 $(KFLAGS)"
+
+#Tektronix XD88 with UTekV OS
+utekvr3:
+ @echo 'Making C-Kermit $(CKVER) for Tektronix XD88 UTekV R3...'
+ $(MAKE) wermit \
+ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP \
+ -DTCPSOCKET -DSYSUTIMEH -DCK_CURSES $(KFLAGS) -O" \
+ "LIBS= -lcurses" "LNKFLAGS= -s"
+
+#Perkin-Elmer 3200 Xelos R02 or earlier
+ccop1:
+ @echo 'Making C-Kermit $(CKVER) for Xelos & Public Domain Dirent calls'
+ @echo 'or System V R2 or earlier...'
+ $(MAKE) wermit \
+ "CFLAGS = -DATTSV -Dvoid=int -DDIRENT -DCK_CURSES \
+ $(KFLAGS) -O" "LNKFLAGS =" "LIBS= -lcurses -ltermlib"
+
+#Encore, UMAX 4.3 (BSD) but without acucntrl program.
+encore:
+ $(MAKE) "MAKE=$(MAKE)" umax43 "KFLAGS=$(KFLAGS)"
+
+#Encore, as above, but with curses file transfer display included.
+encorec:
+ $(MAKE) "MAKE=$(MAKE)" umax43 "KFLAGS=-DCK_CURSES $(KFLAGS)" \
+ "LIBS= -lcurses -ltermcap"
+
+#Encore, UMAX 4.3 (BSD) but without acucntrl program.
+umax43:
+ @echo Making C-Kermit $(CKVER) for Encore UMAX 4.3...
+ $(MAKE) "MAKE=$(MAKE)" PARALLEL=4 xermit \
+ "CFLAGS= -DBSD43 -DENCORE -DTCPSOCKET $(KFLAGS) -O"
+
+#Encore, UMAX 4.2 (BSD)
+umax42:
+ @echo Making C-Kermit $(CKVER) for Encore UMAX 4.2...
+ $(MAKE) "MAKE=$(MAKE)" PARALLEL=4 xermit \
+ "CFLAGS= -DBSD4 -DENCORE -DTCPSOCKET $(KFLAGS) -O"
+
+#Encore 88K UMAX 5.3 with TCP/IP support
+encore88k:
+ @echo 'Making C-Kermit $(CKVER) for Encore 88K UMAX V, TCP/IP...'
+ $(MAKE) xermit \
+ "CFLAGS = -q ext=pcc -DSVR3 -DTCPSOCKET -DDIRENT \
+ -DNOGETID_PROTOS -DHDBUUCP $(KFLAGS) -O" "LNKFLAGS ="
+
+#Encore 88K UMAX 5.3 with TCP/IP support
+encore88kgcc:
+ @echo 'Making C-Kermit $(CKVER) for Encore 88K UMAX V, TCP/IP, gcc...'
+ $(MAKE) xermit CC=gcc CC2=gcc \
+ "CFLAGS = -DSVR3 -DTCPSOCKET -DDIRENT \
+ -DNOGETID_PROTOS -DHDBUUCP $(KFLAGS) -O" "LNKFLAGS ="
+
+#SONY NEWS, NEWS-OS 4.01C
+sonynews:
+ @echo Making C-Kermit $(CKVER) for SONY NEWS-OS 4.01C...
+ $(MAKE) xermit "CFLAGS= -DBSD43 -DACUCNTRL -DTCPSOCKET -O"
+
+#Run Lint on this mess for selected versions.
+#These are pretty much obsolete since ANSI C / gcc.
+lintsun:
+ @echo 'Running Lint on C-Kermit $(CKVER) sources for SunOS version...'
+ lint -x -DSUNOS4 -DDIRENT -DTCPSOCKET -DSAVEDUID \
+ ck[cu]*.c > ckuker.lint.sun
+
+lintbsd:
+ @echo 'Running Lint on C-Kermit $(CKVER) sources for BSD 4.2 version..'
+ lint -x -DBSD4 -DTCPSOCKET ck[cu]*.c > ckuker.lint.bsd42
+
+lints5:
+ @echo 'Running Lint on C-Kermit $(CKVER) sources for Sys V version...'
+ lint -x -DATTSV ck[cu]*.c > ckuker.lint.s5
+
+#Who remembers TECO?
+love:
+ @echo 'Not war?'
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ockermit.ini b/ckermit-9.0.302-build/ckermit-9.0.302/ockermit.ini
new file mode 100644
index 0000000..f007561
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ockermit.ini
@@ -0,0 +1,618 @@
+COMMENT - Standard C-Kermit initialization file
+;
+; For C-Kermit Version: 8.0
+;
+; Filename:
+; .kermrc (UNIX, OS-9, Aegis)
+; CKERMIT.INI (OS/2, VMS, OpenVMS, AOS/VS, Atari ST, Commodore Amiga)
+; ckermit.ini (Stratus VOS)
+; K95.INI (Kermit 95 -- but this big version is not used there)
+; K2.INI (Kermit/2 -- but ditto)
+;
+; Authors:
+; Frank da Cruz, Christine M. Gianone, Jeffrey Altman
+; Columbia University, New York, NY 10025-7799, USA
+;
+; This is the standard and recommended C-Kermit 8.0 initialization file. To
+; override settings or definitions made in this file, to add new settings or
+; definitions, or to make any other desired customizations, create a separate,
+; personal customization file called:
+;
+; .mykermrc (UNIX, OS-9, Aegis, BeBox, Plan 9)
+; CKERMOD.INI (OS/2, VMS, OpenVMS, AOS/VS, Atari ST, Commodore Amiga)
+; ckermod.ini (VOS)
+;
+; You can also define the customization filename in an environment
+; variable (logical name in VMS), CKERMOD, which takes precedence over
+; the names shown above.
+;
+; WHAT THIS FILE DOES:
+;
+; . Defines your default dialing directory name:
+; .kdd for UNIX, OS-9 and Aegis; CKERMIT.KDD for other operating systems.
+; You can override this with the environment variable K_DIAL_DIRECTORY
+; . Defines your default network directory name:
+; .knd for UNIX, OS-9 and Aegis; CKERMIT.KND for other operating systems.
+; You can override this with the environment variable K_NET_DIRECTORY
+; . Defines your default services directory name:
+; .ksd for UNIX, OS-9 and Aegis; CKERMIT.KSD for other operating systems.
+; You can override this with environment variable K_SERVICE_DIRECTORY.
+; . Defines your customization file name (name given above)
+; . Performs system-dependent setups for UNIX, VMS, OS/2, etc.
+; . Defines VTPRINT macros for use with K95, MS-DOS Kermit, etc.
+; . If you have a services directory, all the macros needed to use it are
+; defined. If you don't have a services directory, the macros are not
+; defined and Kermit starts faster.
+; . Executes your personal customization file, if you have one.
+; NOTE: Your customization file is NOT executed by Kermit itself; it is
+; executed by this file.
+;
+; In UNIX, with C-Kermit 7.0 and later, you can store this file with a name
+; other than .kermrc, and it will not be executed automatically, but, if you
+; give this file execute permission, you can execute directly because of the
+; "kerbang line" at the top, whenever you want all of the above actions to
+; occur. The kerbang line must reflect the actual full path of the Kermit
+; 7.0-or-later executable.
+;
+; C-Kermit 6.0 is documented in the book "Using C-Kermit", 2nd Edition,
+; by Frank da Cruz and Christine M. Gianone, 1997, Digital Press /
+; Butterworth-Heinemann, ISBN 1-55558-164-1. New features of subsequent
+; versions are documented at the Kermit website:
+; http://www.columbia.edu/kermit/
+;
+; Everything after this point depends on the script programming language.
+; The CHECK command terminates this command file immediately if the script
+; programming language (IF command) is not configured.
+;
+set take error on ; This makes CHECK quit if no script language.
+check if ; Do we have an IF command? If not, quit now.
+set take error off ; Back to normal.
+
+local _sd _servicedir _xp ; Declare local variables.
+
+COMMENT - C-Kermit version 6.0 or later required.
+;
+
+asg _xp \v(xprogram)
+if not def _xp asg _xp \v(program)
+if not equal "\m(_xp)" "C-Kermit" -
+ stop 1 \v(cmdfile): This initialization file is only for C-Kermit.
+echo Executing \v(cmdfile) for \v(system)...
+if < \v(version) 60000 -
+ stop 1 \v(cmdfile): C-Kermit 6.0 or later required.
+
+forward \v(system) ; First do system-dependent items...
+
+:unknown ; Should not happen
+Stop 1 Error: System type unknown!
+
+:Aegis ; Apollo Aegis and
+:UNIX ; UNIX, all versions
+asg _myinit -
+ \v(home).mykermrc ; Customization filename
+if remote forward COMMON ; Skip local-mode items if "-R"
+asg _dialdir -
+ \v(home).kdd ; C-Kermit dialing directory
+asg _netdir -
+ \v(home).knd ; C-Kermit network directory
+asg _servicedir -
+ \v(home).ksd ; C-Kermit services directory
+forward COMMON ; End of UNIX section
+
+:OS9/68K ; OS-9
+asg _myinit -
+ \v(home).mykermrc ; Customization filename
+if remote forward COMMON
+asg _dialdir -
+ \v(home).kdd ; C-Kermit dialing directory
+asg _netdir -
+ \v(home).knd ; C-Kermit network directory
+asg _servicedir -
+ \v(home).ksd ; C-Kermit services directory
+else set file display crt
+forward COMMON ; End of OS-9 section
+
+:VMS ; VMS and OpenVMS
+forward COMMON
+
+:OS/2 ; Kermit 95
+:WIN32
+echo This initialization file is not for use with K95.
+forward COMMON ; End of OS/2 section
+
+:AOS/VS ; Data General AOS/VS
+set window 1 ; Sliding windows don't work
+set file char dg-international ; File character-set
+set xfer char latin1 ; Transfer character-set
+set file display crt ; File transfer fisplay
+def cli push ; Escape to CLI
+def reset - ; Macro to reset DG DASHER terminal
+ run write [!ascii 236 306 301]
+forward COMMON ; End of AOS/VS section
+
+:Amiga ; Commodore Amiga
+def cls echo \27[H\27[2J ; CLS command to clear the screen
+set file char latin1 ; Use Latin Alphabet 1 for file transfer
+set xfer char latin1 ; ...
+forward COMMON ; End of Amiga section
+
+:Atari_ST ; Atari ST
+def cls echo \27H\27J ; Clear screen a`la VT52
+set server display on ; Show file xfer display in server mode too
+set server timeout 15 ; Nonzero required for ^C interruption!
+forward COMMON ; End of Atari ST section
+
+:Macintosh ; Apple Macintosh
+set server display on ; Show file xfer display in server mode too.
+forward COMMON
+
+:Stratus_VOS ; Stratus VOS
+asg _myinit \v(home)ckermod.ini
+if remote forward COMMON
+asg _dialdir \v(home)ckermit.kdd
+asg _netdir \v(home)ckermit.knd
+asg _servicedir \v(home)ckermit.ksd
+forward COMMON ; End of Stratus VOS section
+
+:COMMON ; For all systems
+
+; Define macros that are useful when running C-Kermit in remote mode.
+; These macros serve no purpose on local-mode-only versions such as
+; OS/2, Macintosh, Amiga, and Atari ST Kermit, so we skip defining them
+; for those systems.
+;
+if not = 0 \findex(\v(system),WIN32:OS/2:Macintosh:Amiga:Atari_ST) -
+ forward files
+
+; VTPRINT macro. Print a file on your PC's local printer.
+
+def VTPRINT echo \27[5i, type \%1, echo \27[4i
+; or if your printer needs a formfeed to force the page out:
+; def VTPRINT def echo \27[5i, type \%1, echo \12\27[4i
+
+; Macros for host-initiated file transfer using APC:
+; NOT NEEDED ANY MORE because of autodownload/autoupload.
+; Remove the following FORWARD command to reinstate these definitions:
+
+:FILES
+
+; Get customization and directory file names. Environment variables take
+; precedence, so you do not have to edit this file to change these filenames.
+;
+if def \$(CKERMOD) assign _myinit \$(CKERMOD)
+if not def _myinit assign _myinit \v(home)CKERMOD.INI
+
+if remote forward CUSTOM ; Skip all this if -R given on command line
+
+if def \$(K_NET_DIRECTORY) assign _netdir \$(K_NET_DIRECTORY)
+if not def _netdir assign _netdir \v(home)CKERMIT.KND
+
+if def \$(K_DIAL_DIRECTORY) assign _dialdir \$(K_DIAL_DIRECTORY)
+if not def _dialdir assign _dialdir \v(home)CKERMIT.KDD
+
+CHECK DIAL ; Is there a DIAL command?
+xif fail { ; No.
+ echo DIAL disabled
+ forward CUSTOM
+}
+
+CHECK NETWORK
+xif success {
+ xif exist \m(_netdir) {
+ set net directory \m(_netdir)
+ echo { Network directory is \m(_netdir) }
+ }
+}
+
+if eq "\v(name)" "telnet" forward CUSTOM
+
+xif exist \m(_dialdir) {
+ set dial directory \m(_dialdir)
+ echo { Dial directory is \m(_dialdir) }
+}
+
+COMMENT - Services directory
+
+if def \$(K_SERVICE_DIRECTORY) assign _servicedir \$(K_SERVICE_DIRECTORY)
+if not def _servicedir assign _servicedir \v(home)CKERMIT.KSD
+
+; If no services directory is found skip all the big macro definitions and
+; go straight to the bottom, where we execute the customization file.
+
+if not exist \m(_servicedir) forward custom
+
+echo { Services directory is \m(_servicedir)}
+
+def MAX_SVCS 200 ; Adjust this if you have more entries
+define _sd 0 ; Assume no services directory
+open read \m(_servicedir) ; Try to open services directory file
+xif success {
+ declare \&d[\m(MAX_SVCS)] ; It's open, declare directory array
+ for \%i 1 \m(MAX_SVCS) 1 { ; Read the lines into the array
+ read \&d[\%i]
+ if fail break
+ }
+ close read
+ xif > \%i \m(MAX_SVCS) {
+ echo Too many entries in services directory
+ echo { Maximum is \m(MAX_SVCS).}
+ echo { Change definition of MAX_SVCS in \v(cmdfile) to allow more. }
+ echo { Services directory disabled.}
+ } else {
+ asg \&d[0] \feval(\%i - 1)
+ define _sd 1
+ }
+}
+
+xif not \m(_sd) {
+ def access echo { Services directory not available.}
+ asg list \m(access)
+} else {
+ def FIND {
+ set case off
+ for \%i 1 \&d[0] 1 {
+ if eq {\%1} {\fsubstr(\&d[\%i],1,\flen(\%1))} break
+ }
+ if not > \%i \&d[0] return \&d[\%i]
+ }
+ def LIST {
+ xif > \v(argc) 1 {
+ do find \%1
+ if def \v(return) echo \v(return)
+ else echo \%1: Not found
+ } else {
+ echo \&d[0] items in services directory:
+ for \%i 1 \&d[0] 1 { echo \fcont(\&d[\%i]) }
+ }
+ }
+ def SPLIT { asg _word1 \%1, asg _word2 \%2 }
+ def DOACCESS { ; (Used internally by ACCESS macro)
+ do \%5 \%6 \%7 \%8 \%9 ; Do the connection macro
+ if fail end 1
+ split \%3 ; Get words from \%3
+ asg \%3 \m(_word1)
+ asg \%2 \m(_word2)
+ do \%3 \%4 {\%1} \%2 ; Login macro, userid, password, prompt
+ }
+ def ACCESS {
+ if not defined \%1 end 1 access what? ; Check service
+ do find \%1 ; Look it up
+ if success doaccess {\%2} \v(return) ; OK, try it
+ else end 1 "\%1" not in services directory ; Not found
+ if fail end 1 ; DOACCESS failed?
+ xif eq \v(cmdlevel) 1 {
+ echo
+ echo ACCESS: Login succeeded - CONNECTing...
+ show escape
+ output \13
+ connect /quietly
+ }
+ }
+}
+
+:CONNECTION ; Macros for making connections
+
+COMMENT - SERIAL macro. Arguments:
+; \%1 = device name
+; \%2 = speed
+;
+def SERIAL {
+ if < \v(argc) 3 ; All arguments given?
+ end 1 Usage: SERIAL device speed ; No.
+ set line \%1 ; OK, try to SET LINE.
+ if failure - ; If this failed,
+ end 1 Can't open device: \%1 ; print message and quit.
+ set speed \%2 ; Try to set the speed.
+ if fail end 1 Unsupported speed: \%2 ; Failed.
+ echo Connection successful. ; Succeeded.
+}
+
+COMMENT - NET macro. Arguments:
+; \%1 = network type
+; \%2 = host name or address
+;
+def NET {
+ if < \v(argc) 3 end 1 Usage: NET network host
+ set network type \%1
+ if fail end 1 unsupported network: \%1
+ set login user ; Don't send user ID.
+ set host \%2
+ if fail end 1 Can't reach host: \%2
+ echo Connection successful.
+}
+
+COMMENT - CALL macro. Arguments:
+;
+; \%1 = modem type
+; \%2 = device name
+; \%3 = speed
+; \%4 = phone number
+;
+def CALL {
+ if < \v(argc) 5 - ; All arguments present?
+ end 1 Usage: CALL modem device speed number
+ xif not equal {\v(modem)} {\%1} { ; Set modem type
+ set modem \%1
+ if fail end 1 unknown modem type: \%1
+ }
+ xif not equal {\v(line)} {\%2} { ; Communication device
+ set line \%2
+ if fail end 1 can't open device: \%2
+ }
+ xif not equal {\v(speed)} {\%3} { ; Communication speed
+ set speed \%3
+ if fail end 1 unsupported speed: \%3
+ }
+ dial \%4 ; Dial the number
+ if fail end 1 Can't place call: \%4
+ end 0 Connection successful.
+}
+
+COMMENT - TCPCALL macro. Arguments:
+;
+; \%1 = server name:port
+; \%2 = modem type
+; \%3 = phone number
+;
+def TCPCALL {
+ if < \v(argc) 4 - ; All arguments present?
+ end 1 Usage: TCPCALL server[:port] modem number
+ set net type tcp/ip ; Which network to use
+ if fail end 1 unsupported network: tcp/ip
+ set host \%1 ; Access server and port
+ if fail end 1 can't access server \%1
+ set modem \%2 ; Set modem type
+ if fail end 1 unknown modem type: \%2
+ dial \%3 ; Dial the number
+ if fail end 1 Can't place call: \%3
+ end 0 Connection successful.
+}
+
+COMMENT - SPRINT macro. Arguments:
+; \%1 = Service name or address
+;
+def SPRINT {
+ if < \v(argc) 2 end 1 Usage: \%0 service
+ set input timeout proceed
+ output @D\13
+ input 10 TERMINAL=
+ if fail end 1 No terminal prompt
+ out D1\13
+ inp 10 @
+ if fail end 1 No atsign prompt
+ output c \%1\13
+ input 10 CONNECTED
+ if fail end 1 Can't access \%1 from SprintNet
+}
+
+COMMENT - ULOGIN macro. For logging into systems where user ID is required
+; but there is no password. Arguments:
+; \%1 = UNIX user ID
+;
+define ULOGIN {
+ if < \v(argc) 2 end 1 Usage: \%0 userid
+ set input timeout proceed ; Handle timeouts ourselves
+ set case on ; Case is important in UNIX
+ minput 5 login: Username: {User ID:} {User Name:}
+ out \%1\13 ; Send username, carriage return
+ end 0
+}
+
+COMMENT - VMSLOGIN macro. Arguments:
+; \%1 = VMS user ID
+; \%2 = Password. If password not supplied, it is prompted for.
+; \%3 = System prompt. If omitted a default is supplied.
+;
+define VMSLOGIN {
+ if < \v(argc) 2 end 1 Usage: \%0 userid [ password [ prompt ] ]
+ while not defined \%2 {
+ askq \%2 { \%1's password: }
+ }
+ set parity none ; Set communication parameters
+ set duplex full
+ set handshake none
+ set input timeout proceed ; Handle timeouts ourselves
+ in 5 Username: ; Is prompt already there?
+ xif fail { ; No.
+ for \%i 1 3 1 { ; Try 3 times to get it.
+ out \13 ; Send carriage return
+ in 5 Username: ; Look for prompt
+ if success break ; Success, go log in
+ }
+ if > \%i 3 end 1 No Username prompt
+ }
+ out \%1\13 ; Send username, carriage return
+ inp 5 Password: ; Wait 5 sec for this prompt
+ if fail end 1 No password prompt
+ pause ; Wait a sec
+ out \%2\13 ; Send password
+ xif not emulation { ; No emulator built in?
+ set input echo off ; Protect terminal from this
+ minput 10 {\27Z} {\27[c} {\27[0c} ; Get terminal ID query
+ xif success { ; Got one
+ output \27[\?1c ; Send VT100 terminal ID
+ in 2 \27[6n ; Screen dimension query?
+ if succ out \27[\v(rows);\v(cols)R ; Send dimensions
+ }
+ set input echo on ; Echo input again
+ }
+ if not def \%3 - ; If we were not given a prompt
+ asg \%3 {\v(prompt)} ; use the SET LOGIN PROMPT value
+ if not def \%3 - ; If we still don't have a prompt
+ asg \%3 {\13$\32} ; use this one as the default
+ reinp 0 \%3 ; Did we INPUT the prompt already?
+ if fail inp 60 \%3 ; No, look now.
+ if fail end 1
+}
+
+COMMENT - UNIXLOGIN macro. Arguments:
+; \%1 = UNIX user ID
+; \%2 = Password. If password not supplied, it is prompted for.
+; \%3 = System prompt. If omitted a default is supplied.
+;
+define UNIXLOGIN {
+ local \%m \%i
+ if < \v(argc) 2 -
+ end 1 Usage: \%0 userid [ password [ prompt ] ]
+ while not defined \%2 {
+ askq \%2 { \%1's password: }
+ }
+ set input echo on
+ set parity none ; Set communication parameters.
+ set duplex full
+ set handshake none
+ set input timeout proceed ; Handle timeouts ourselves
+ set case on ; Case is important in UNIX
+ def \%m 10 ; Waiting time for INPUT
+ for \%i 1 5 1 {
+ minput \%m login: {ssword:} {Password for \%1:}
+ if success break
+ output \B\13
+ \%m ::= 6-\%1
+ }
+ if > \%i 5 end 1 {No response from host}
+ xif = \v(minput) 1 { ; Have username prompt
+ output \%1\13 ; Send username
+ minput 5 {ssword:} {ssword for \%1:} ; Wait for password prompt
+ if fail end 1 {No password prompt}
+ }
+ pause ; Wait a sec
+ out \%2\13 ; Send password
+ if not def \%3 - ; If we were not given a prompt
+ asg \%3 {\v(prompt)} ; use the SET LOGIN PROMPT value
+ if not def \%3 - ; If we still don't have a prompt
+ asg \%3 {\10$ } ; use this one as the default
+ reinp 0 \%3 ; Did we INPUT the prompt already?
+ if fail inp 60 \%3 ; No, look now.
+ if fail end 1
+}
+
+COMMENT - VMLINELOGIN macro. Arguments:
+; \%1 = User ID
+; \%2 = Password
+;
+define VMLINELOGIN {
+ if < \v(argc) 2 -
+ end 1 Usage: \%0 userid [ password ]
+ while not defined \%2 {
+ askq \%2 { \%1's password: }
+ }
+ set parity mark ; Set communication parameters
+ set flow none
+ set handshake xon
+ set duplex half
+ set input timeout quit ; Don't bother with IF FAILURE
+ input 10 BREAK KEY ; Look for BREAK KEY prompt
+ pause 1 ; Wait a second
+ output \B ; Send BREAK
+ input 10 .\17, output logon \%1\13 ; Now log in
+ input 10 .\17, output \%2\13 ; Send password
+ input 10 .\17, output \13 ; Send carriage return
+ input 10 .\17, output \13 ; Send another one
+ end 0
+}
+
+COMMENT - VMFULLOGIN macro. Arguments:
+; \%1 = User ID
+; \%2 = Password
+;
+define VMFULLOGIN {
+ if < \v(argc) 2 -
+ end 1 Usage: \%0 userid [ password ]
+ while not defined \%2 {
+ askq \%2 { \%1's password: }
+ }
+ set input timeout quit ; Quit if INPUT fails
+ set parity even ; Set communication parameters
+ set duplex full
+ set handshake none
+ set flow xon/xoff
+ out \13 ; Send carriage return
+ inp 5 TERMINAL TYPE: ; Get terminal-type prompt
+ out vt-100\13 ; Just send "vt-100"
+ inp 20 RUNNING ; Get RUNNING message
+ pau 1 ; Wait one second
+ out \%1\9\%2\13 ; Send user ID, tab, password
+ out \13\13 ; Two more carriage returns
+ end 0
+}
+
+COMMENT - CISLOGIN macro. Arguments:
+; \%1 = CompuServe User ID
+; \%2 = Password
+; \%3 = Prompt
+;
+define CISLOGIN {
+ if < \v(argc) 2 -
+ end 1 Usage: \%0 userid [ password [ prompt ] ]
+ while not defined \%2 {
+ askq \%2 { \%1's password: }
+ }
+ set terminal bytesize 7 ; No 8-bit characters
+ set input timeout quit ; Skip the IF FAILURE's
+ output \13 ; Send initial carriage return
+ input 5 Host Name: ; Look for Host Name prompt
+ output cis\13 ; Send "cis" and carriage return
+ input 5 User ID: ; Look for User ID prompt
+ output \%1\13 ; Send ID and carriage return
+ input Password: ; Look for Password prompt
+ output \%2\13 ; Send password and CR
+ if not def \%3 asg \%3 \v(prompt)
+ if not def \%3 asg \%3 {CompuServe Information Service}
+ input 30 \%3
+ end 0
+}
+
+COMMENT - DOWLOGIN macro. Arguments:
+; \%1 = Dow Jones Password
+;
+define DOWLOGIN {
+ while not defined \%1 { ; Get password
+ askq \%1 { Dow Jones password: }
+ }
+ set input timeout proceed
+ input 20 SERVICE PLEASE\?\?\?\? ; Look for Dow prompt
+ if fail end 1 No service prompt
+ out djnr\13 ; Select DJNR
+ input 10 @@@@@@@@ ; Get password prompt
+ if fail end 1 No password prompt
+ pause 1 ; Wait a second, then...
+ output \%1\13 ; send password and CR
+ input 30 ENTER QUERY ; Get DJNR query prompt
+ if fail end 1 No main query prompt
+ pause 1
+}
+
+COMMENT - DJNRSPRINT macro: Log in to Dow Jones via SprintNet.
+;
+def djnrsprint sprint dow, if success dowlogin
+
+COMMENT - NOLOGIN macro. Does nothing. Use when login not required.
+;
+def nologin comment
+
+:CUSTOM ; Customization file
+
+; In VMS and OpenVMS, allow for system-wide site customizations
+
+xif equal "\v(system)" "VMS" {
+ xif exist CKERMIT_INI:CKERMIT.SYS {
+ echo Executing CKERMIT_INI:CKERMIT.SYS
+ take CKERMIT_INI:CKERMIT.SYS
+ }
+}
+
+; Execute user's personal customization file
+
+xif exist \m(_myinit) { ; If it exists,
+ echo Executing \m(_myinit)... ; print message,
+ take \m(_myinit) ; and TAKE the file.
+}
+
+; Finish up with traditional greeting.
+
+if < \v(ntime) 43200 echo Good Morning!
+ else if < \v(ntime) 61200 echo Good Afternoon!
+ else echo Good Evening.
+
+End ; of C-Kermit 8.0 initialization file.
diff --git a/ckermit-9.0.302-build/ckermit-9.0.302/ockermod.ini b/ckermit-9.0.302-build/ckermit-9.0.302/ockermod.ini
new file mode 100644
index 0000000..5848c3f
--- /dev/null
+++ b/ckermit-9.0.302-build/ckermit-9.0.302/ockermod.ini
@@ -0,0 +1,144 @@
+; File CKERMOD.INI, Sample C-Kermit 7.0 customization file.
+;
+; This file, which is ONLY A SAMPLE, should be called:
+;
+; .mykermrc (UNIX, OS-9, Aegis, BeBox, Plan 9)
+; CKERMOD.INI (VMS, OpenVMS, AOS/VS, OS/2, Amiga, Atari ST)
+; ckermod.ini (Stratus VOS)
+;
+; This file is executed automatically by the standard C-Kermit initialization
+; file, CKERMIT.INI (or .kermrc). This file is not executed by C-Kermit itself
+; unless the initialization file is not found.
+;
+; MODify this file to suit your needs and preferences, and install it in your
+; home directory. Or replace it entirely with a new file.
+;
+; The design of this sample customization file lets you fill in a section for
+; each different operating system where you run C-Kermit.
+;
+; In UNIX, if you give this file execute permission and make sure the top
+; line indicates the full path of the C-Kermit 7.0-or-later executable, you
+; can execute this file directly, as if it was a shell script, except it is
+; interpreted by Kermit rather than the shell. This lets you have as many
+; different startup files as you like, each suited to a particular purpose.
+;
+; Authors: Christine Gianone, Frank da Cruz, Jeffrey Altman,
+; The Kermit Project, Columbia University.
+; Creation: 23 November 1992 for C-Kermit 5A(188).
+; Modified: 30 June 1993 for edit 189.
+; 04 October 1994 for edit 190.
+; 17 April 1995 for edit 191.
+; 6 September 1996 for version 6.0, edit 192.
+; 1 January 2000 for version 7.0, edit 196.
+; 14 October 2001 for version 8.0, edit 200.
+
+ECHO
+ECHO Executing SAMPLE C-Kermit customization file \v(cmdfile) for \v(system)...
+ECHO { Please edit this file to reflect your needs and preferences.}
+ECHO
+;
+; ... and then remove the ECHO commands above.
+
+COMMENT - Settings that apply to all the systems I use:
+;
+set delay 1 ; I escape back quickly
+set dial display on ; I like to watch C-Kermit dial
+
+; Dialing locale and method
+;
+; SET DIAL COUNTRY-CODE 1 ; Uncomment and replace with yours
+; SET DIAL AREA-CODE 000 ; Uncomment and replace with yours
+; SET DIAL LD-PREFIX 1 ; Uncomment and replace with yours
+; SET DIAL INTL-PREFIX 011 ; Uncomment and replace with yours
+; SET DIAL METHOD TONE ; Uncomment and replace with PULSE if necessary
+; SET DIAL DIRECTORY ... ... ; List dialing directory files here
+
+if < \v(version) 600192 -
+ stop 1 \v(cmdfile): C-Kermit 6.0.192 or later required.
+
+set take error on ; Make errors fatal temporarily
+check if ; Do we have an IF command?
+set take error off ; Yes we do, back to normal
+
+; The ON_EXIT macro is executed automatically when C-Kermit exits.
+; Define as desired.
+;
+define ON_EXIT echo Returning you to \v(system) now.
+
+; System-independent quick dialing macro. Depends on having the
+; macros MYMODEM, MYPORT, and (optionally) MYSPEED defined in the
+; system-dependent sections below.
+;
+define MYDIAL {
+ if not defined MYMODEM end 1 {\%0: Modem type not defined.}
+ set modem type \m(MYMODEM)
+ if fail end 1 {\%0: \m(MYMODEM): Unsupported modem type.}
+ if not defined MYPORT end 1 {\%0: Communication port not defined.}
+ set port \m(MYPORT)
+ if fail end 1 {\%0: SET PORT \m(MYPORT) failed.}
+ if defined MYFLOW set flow \m(MYFLOW)
+ if fail end 1 {\%0: SET FLOW \m(MYFLOW) failed.}
+ if defined MYSPEED set speed \m(MYSPEED)
+ if fail end 1 {\%0: SET SPEED \m(MYSPEED) failed.}
+ dial \%1\%2\%3\%4\%5\%6\%7\%8\%9
+ end \v(status)
+}
+
+forward \v(system) ; Go execute system-dependent commands
+
+:UNIX ; UNIX, all versions...
+define MYPORT /dev/cua ; My dialing environment
+define MYMODEM usr ; Replace these by what you actually have
+define MYSPEED 57600
+;
+; If you want all your downloads to go to the same directory, no matter
+; what your current directory is, uncomment and edit the following command:
+;
+; set file download-directory ~/download ; Download directory for UNIX
+
+; Put other UNIX-specific commands here...
+end ; End of UNIX section
+
+:VMS ; VMS and OpenVMS
+define MYPORT TXA0: ; My dialing environment
+define MYMODEM usr ; Replace these by what you actually have
+define MYSPEED 57600
+; set file download-directory [\$(USER).DOWNLOAD] ; Download directory for VMS
+; Put other VMS-specific commands here...
+end ; End of VMS section
+
+:WIN32 ; Windows and OS/2 customizations...
+:OS/2
+define MYPORT COM1 ; My dialing environment
+define MYMODEM usr ; Replace these by what you actually have
+define MYSPEED 57600
+set command byte 8 ; Use 8 bits between Kermit and console
+set xfer char latin1 ; Use Latin-1 for text file transfer
+set term char latin1 ; And use Latin-1 during CONNECT mode
+; set file download-directory C:\DOWNLOADS
+end
+
+:OS9/68K ; OS-9/68000
+define MYPORT /t3 ; My dialing environment
+define MYMODEM usr ; Replace these by what you actually have
+define MYSPEED 9600
+; set file download-directory ~/downloads
+end ; End of OS-9 section
+
+:AOS/VS ; Data General AOS/VS
+define MYPORT @con3 ; My dialing environment
+define MYMODEM usr ; Replace these by what you actually have
+define MYSPEED 9600
+; set file download-directory \v(home)DOWNLOADS
+end
+
+; And so on, you get the idea...
+; Fill in the sections that apply to you.
+
+:Stratus_VOS ; Stratus VOS
+:Amiga ; Commodore Amiga
+:Atari_ST ; Atari ST
+:Macintosh ; Apple Macintosh
+:unknown ; Others
+
+; (End of CKERMOD.INI)
diff --git a/ckermit.spec b/ckermit.spec
index 6e85311..5fb221b 100644
--- a/ckermit.spec
+++ b/ckermit.spec
@@ -3,7 +3,7 @@
Summary: The quintessential all-purpose communications program
Name: ckermit
Version: 9.0.%{patchlevel}
-Release: 36%{?dist}
+Release: 37%{?dist}
# Most of the package is under a three-clause BSD license, but the file
# ckaut2.h appears to be covered by three licenses:
# The blanket license in COPYING.TXT and ckcmai.c, which is BSD three-clause
@@ -53,7 +53,7 @@ cp %{SOURCE6} .
%build
%make_build linux \
- KFLAGS="-O0 $RPM_OPT_FLAGS -Wall -DOPENSSL_097 -Dsdata=s_data -DHAVE_OPENPTY -D'krb5_init_ets(__ctx)=' -DMAINTYPE=int" \
+ KFLAGS="-O0 $RPM_OPT_FLAGS -Wall -ansi -D_DEFAULT_SOURCE -DOPENSSL_097 -Dsdata=s_data -DHAVE_OPENPTY -D'krb5_init_ets(__ctx)=' -DMAINTYPE=int" \
LNKFLAGS="%{?optflags} %{?__global_ldflags}" \
K4LIB= \
K4INC= \
@@ -89,6 +89,9 @@ install -D -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/kermit/ckermit.phone
%{_mandir}/man1/kermit.1*
%changelog
+* Wed Jan 22 2025 David Cantrell <dcantrell@redhat.com> - 9.0.302-37
+- Add '-ansi -D_DEFAULT_SOURCE' to KFLAG variable to fix FTBFS (#2339971)
+
* Thu Jan 16 2025 Fedora Release Engineering <releng@fedoraproject.org> - 9.0.302-36
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
diff --git a/log b/log
new file mode 100644
index 0000000..9296d6d
--- /dev/null
+++ b/log
@@ -0,0 +1,42 @@
+Uploading srpm: ckermit-9.0.302-37.fc42.src.rpm
+[ ] 00% 00:00:00 0.00 B - B/sec\r[=========== ] 33% 00:00:00 1.00 MiB 10.10 MiB/sec\r[======================= ] 66% 00:00:00 2.00 MiB 31.79 MiB/sec\r[=================================== ] 99% 00:00:00 3.00 MiB 31.90 MiB/sec\r[====================================] 100% 00:00:00 3.01 MiB 16.40 MiB/sec
+Created task: 128323648
+Task info: https://koji.fedoraproject.org/koji/taskinfo?taskID=128323648
+Watching tasks (this may be safely interrupted)...
+128323648 build (rawhide, ckermit-9.0.302-37.fc42.src.rpm): free
+128323648 build (rawhide, ckermit-9.0.302-37.fc42.src.rpm): free -> assigned (buildhw-x86-10.iad2.fedoraproject.org)
+128323648 build (rawhide, ckermit-9.0.302-37.fc42.src.rpm): assigned (buildhw-x86-10.iad2.fedoraproject.org) -> open (buildhw-x86-10.iad2.fedoraproject.org)
+ 128323694 rebuildSRPM (s390x): free
+ 128323694 rebuildSRPM (s390x): free -> assigned (buildvm-s390x-02.s390.fedoraproject.org)
+ 128323694 rebuildSRPM (s390x): assigned (buildvm-s390x-02.s390.fedoraproject.org) -> open (buildvm-s390x-02.s390.fedoraproject.org)
+ 128323694 rebuildSRPM (s390x): open (buildvm-s390x-02.s390.fedoraproject.org) -> closed
+ 0 free 1 open 1 done 0 failed
+ 128323748 buildArch (ckermit-9.0.302-37.fc42.src.rpm, i686): free
+ 128323752 buildArch (ckermit-9.0.302-37.fc42.src.rpm, s390x): free
+ 128323749 buildArch (ckermit-9.0.302-37.fc42.src.rpm, x86_64): free
+ 128323750 buildArch (ckermit-9.0.302-37.fc42.src.rpm, aarch64): free
+ 128323751 buildArch (ckermit-9.0.302-37.fc42.src.rpm, ppc64le): free
+ 128323748 buildArch (ckermit-9.0.302-37.fc42.src.rpm, i686): free -> assigned (buildhw-x86-01.iad2.fedoraproject.org)
+ 128323752 buildArch (ckermit-9.0.302-37.fc42.src.rpm, s390x): free -> assigned (buildvm-s390x-03.s390.fedoraproject.org)
+ 128323749 buildArch (ckermit-9.0.302-37.fc42.src.rpm, x86_64): free -> assigned (buildhw-x86-02.iad2.fedoraproject.org)
+ 128323750 buildArch (ckermit-9.0.302-37.fc42.src.rpm, aarch64): free -> assigned (buildvm-a64-09.iad2.fedoraproject.org)
+ 128323751 buildArch (ckermit-9.0.302-37.fc42.src.rpm, ppc64le): free -> assigned (buildvm-ppc64le-20.iad2.fedoraproject.org)
+ 128323752 buildArch (ckermit-9.0.302-37.fc42.src.rpm, s390x): assigned (buildvm-s390x-03.s390.fedoraproject.org) -> open (buildvm-s390x-03.s390.fedoraproject.org)
+ 128323749 buildArch (ckermit-9.0.302-37.fc42.src.rpm, x86_64): assigned (buildhw-x86-02.iad2.fedoraproject.org) -> open (buildhw-x86-02.iad2.fedoraproject.org)
+ 128323750 buildArch (ckermit-9.0.302-37.fc42.src.rpm, aarch64): assigned (buildvm-a64-09.iad2.fedoraproject.org) -> open (buildvm-a64-09.iad2.fedoraproject.org)
+ 128323748 buildArch (ckermit-9.0.302-37.fc42.src.rpm, i686): assigned (buildhw-x86-01.iad2.fedoraproject.org) -> open (buildhw-x86-01.iad2.fedoraproject.org)
+ 128323751 buildArch (ckermit-9.0.302-37.fc42.src.rpm, ppc64le): assigned (buildvm-ppc64le-20.iad2.fedoraproject.org) -> open (buildvm-ppc64le-20.iad2.fedoraproject.org)
+ 128323749 buildArch (ckermit-9.0.302-37.fc42.src.rpm, x86_64): open (buildhw-x86-02.iad2.fedoraproject.org) -> closed
+ 0 free 5 open 2 done 0 failed
+ 128323748 buildArch (ckermit-9.0.302-37.fc42.src.rpm, i686): open (buildhw-x86-01.iad2.fedoraproject.org) -> closed
+ 0 free 4 open 3 done 0 failed
+ 128323752 buildArch (ckermit-9.0.302-37.fc42.src.rpm, s390x): open (buildvm-s390x-03.s390.fedoraproject.org) -> closed
+ 0 free 3 open 4 done 0 failed
+ 128323750 buildArch (ckermit-9.0.302-37.fc42.src.rpm, aarch64): open (buildvm-a64-09.iad2.fedoraproject.org) -> closed
+ 0 free 2 open 5 done 0 failed
+ 128323751 buildArch (ckermit-9.0.302-37.fc42.src.rpm, ppc64le): open (buildvm-ppc64le-20.iad2.fedoraproject.org) -> closed
+ 0 free 1 open 6 done 0 failed
+128323648 build (rawhide, ckermit-9.0.302-37.fc42.src.rpm): open (buildhw-x86-10.iad2.fedoraproject.org) -> closed
+ 0 free 0 open 7 done 0 failed
+
+128323648 build (rawhide, ckermit-9.0.302-37.fc42.src.rpm) completed successfully
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-18 13:52 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 13:52 [rpms/ckermit] epel9: Add '-ansi -D_DEFAULT_SOURCE' to KFLAG variable to fix FTBFS (#2339971) David Cantrell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox